[med-svn] [gatk] 01/02: Imported Upstream version 3.3
Andreas Tille
tille at debian.org
Thu Mar 26 12:39:07 UTC 2015
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository gatk.
commit a61d1aa040794805beba16bfb288a4d27a82a393
Author: Andreas Tille <tille at debian.org>
Date: Thu Mar 26 13:34:37 2015 +0100
Imported Upstream version 3.3
---
.gitignore | 29 +
README.md | 3 +
ant-bridge.sh | 173 +
intellij_example.tar.bz2 | Bin 0 -> 7520 bytes
licensing/private_license.txt | 48 +
licensing/protected_license.txt | 48 +
licensing/public_license.txt | 22 +
pom.xml | 756 +
public/VectorPairHMM/README.md | 72 +
public/VectorPairHMM/pom.xml | 122 +
public/VectorPairHMM/src/main/c++/.gitignore | 16 +
.../src/main/c++/LoadTimeInitializer.cc | 205 +
.../src/main/c++/LoadTimeInitializer.h | 86 +
public/VectorPairHMM/src/main/c++/Makefile | 126 +
public/VectorPairHMM/src/main/c++/Sandbox.cc | 106 +
public/VectorPairHMM/src/main/c++/Sandbox.h | 96 +
public/VectorPairHMM/src/main/c++/Sandbox.java | 306 +
.../main/c++/Sandbox_JNIHaplotypeDataHolderClass.h | 13 +
.../src/main/c++/Sandbox_JNIReadDataHolderClass.h | 13 +
.../src/main/c++/avx_function_instantiations.cc | 45 +
public/VectorPairHMM/src/main/c++/baseline.cc | 157 +
.../src/main/c++/common_data_structure.h | 215 +
public/VectorPairHMM/src/main/c++/define-double.h | 205 +
public/VectorPairHMM/src/main/c++/define-float.h | 206 +
.../VectorPairHMM/src/main/c++/define-sse-double.h | 173 +
.../VectorPairHMM/src/main/c++/define-sse-float.h | 173 +
public/VectorPairHMM/src/main/c++/headers.h | 71 +
public/VectorPairHMM/src/main/c++/jni_common.h | 60 +
public/VectorPairHMM/src/main/c++/jnidebug.h | 191 +
...te_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc | 175 +
...ute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.h | 86 +
...tute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc | 416 +
...itute_gatk_utils_pairhmm_VectorLoglessPairHMM.h | 96 +
.../VectorPairHMM/src/main/c++/pairhmm-1-base.cc | 65 +
.../src/main/c++/pairhmm-template-kernel.cc | 380 +
.../src/main/c++/pairhmm-template-main.cc | 113 +
public/VectorPairHMM/src/main/c++/run.sh | 32 +
public/VectorPairHMM/src/main/c++/shift_template.c | 113 +
.../src/main/c++/sse_function_instantiations.cc | 44 +
public/VectorPairHMM/src/main/c++/template.h | 119 +
public/VectorPairHMM/src/main/c++/utils.cc | 567 +
public/VectorPairHMM/src/main/c++/utils.h | 85 +
public/c/SeparateQltout.cc | 70 +
public/c/libenvironhack/Makefile | 10 +
public/c/libenvironhack/libenvironhack.c | 37 +
public/c/libenvironhack/libenvironhack.dylib | Bin 0 -> 28904 bytes
public/chainFiles/b36tob37.chain | 30854 ++++++++++++
public/chainFiles/b37tob36.chain | 12268 +++++
public/chainFiles/b37tohg18.chain | 49040 +++++++++++++++++++
public/chainFiles/b37tohg19.chain | 75 +
public/chainFiles/hg18tob37.chain | 30854 ++++++++++++
public/chainFiles/hg19toHg18.chain | 49040 +++++++++++++++++++
public/chainFiles/makeChains.py | 50 +
public/doc/Ant_Help.tex | 9 +
public/doc/GATK_Coding_Standards.pdf | Bin 0 -> 133046 bytes
public/doc/GATK_Coding_Standards.tex | 288 +
public/doc/README | 86 +
public/external-example/pom.xml | 272 +
.../java/org/mycompany/app/MyExampleWalker.java | 56 +
.../app/MyExampleWalkerIntegrationTest.java | 54 +
.../org/mycompany/app/MyExampleWalkerUnitTest.java | 41 +
public/gatk-engine/pom.xml | 94 +
.../src/main/assembly/example-resources.xml | 37 +
.../broadinstitute/gatk/engine/ReadMetrics.java | 121 +
.../broadinstitute/gatk/engine/package-info.java | 26 +
.../gatk-engine/src/test/resources/exampleBAM.bam | Bin 0 -> 3635 bytes
.../src/test/resources/exampleBAM.bam.bai | Bin 0 -> 232 bytes
.../src/test/resources/exampleBAM.simple.bai | Bin 0 -> 232 bytes
.../src/test/resources/exampleBAM.simple.bam | Bin 0 -> 3595 bytes
.../src/test/resources/exampleDBSNP.vcf | 282 +
.../src/test/resources/exampleDBSNP.vcf.idx | Bin 0 -> 330 bytes
.../src/test/resources/exampleFASTA-3contigs.fasta | 24 +
.../src/test/resources/exampleFASTA-combined.fasta | 1675 +
.../src/test/resources/exampleFASTA-windows.fasta | 7 +
.../src/test/resources/exampleFASTA.dict | 2 +
.../src/test/resources/exampleFASTA.fasta | 1668 +
.../src/test/resources/exampleFASTA.fasta.amb | 1 +
.../src/test/resources/exampleFASTA.fasta.ann | 3 +
.../src/test/resources/exampleFASTA.fasta.bwt | Bin 0 -> 37548 bytes
.../src/test/resources/exampleFASTA.fasta.fai | 1 +
.../src/test/resources/exampleFASTA.fasta.pac | Bin 0 -> 25002 bytes
.../src/test/resources/exampleFASTA.fasta.rbwt | Bin 0 -> 37548 bytes
.../src/test/resources/exampleFASTA.fasta.rpac | Bin 0 -> 25002 bytes
.../src/test/resources/exampleFASTA.fasta.rsa | Bin 0 -> 12528 bytes
.../src/test/resources/exampleFASTA.fasta.sa | Bin 0 -> 12528 bytes
.../src/test/resources/exampleGATKReport.eval | 36 +
.../src/test/resources/exampleGATKReportv1.tbl | 36 +
.../src/test/resources/exampleGATKReportv2.tbl | 36 +
.../gatk-engine/src/test/resources/exampleGRP.grp | 1118 +
.../src/test/resources/exampleINTERVAL.intervals | 3 +
.../gatk-engine/src/test/resources/exampleNORG.bam | Bin 0 -> 3586 bytes
.../src/test/resources/exampleNORG.bam.bai | Bin 0 -> 232 bytes
.../test/resources/forAlleleFractionSimulation.vcf | 29 +
.../resources/forAlleleFractionSimulation.vcf.idx | Bin 0 -> 2074 bytes
.../src/test/resources/forLongInsert.vcf | 16 +
.../src/test/resources/forLongInsert.vcf.idx | Bin 0 -> 2019 bytes
.../src/test/resources/forSimulation.vcf | 8 +
.../src/test/resources/forSimulation.vcf.idx | Bin 0 -> 2067 bytes
public/gatk-engine/src/test/resources/testfile.sam | 450 +
public/gatk-queue-extensions-generator/pom.xml | 29 +
.../extensions/gatk/ArgumentDefinitionField.java | 558 +
.../gatk/queue/extensions/gatk/ArgumentField.java | 250 +
.../extensions/gatk/GATKExtensionsGenerator.java | 399 +
.../queue/extensions/gatk/ReadFilterField.java | 48 +
public/gatk-queue-extensions-public/pom.xml | 168 +
.../src/main/assembly/example-resources.xml | 20 +
.../gatk/queue/qscripts/CNV/xhmmCNVpipeline.scala | 615 +
.../gatk/queue/qscripts/GATKResourcesBundle.scala | 426 +
.../queue/qscripts/examples/ExampleCountLoci.scala | 56 +
.../qscripts/examples/ExampleCountReads.scala | 87 +
.../qscripts/examples/ExampleCustomWalker.scala | 73 +
.../qscripts/examples/ExamplePrintReads.scala | 53 +
.../qscripts/examples/ExampleReadFilter.scala | 48 +
.../examples/ExampleRetryMemoryLimit.scala | 53 +
.../gatk/queue/qscripts/examples/HelloWorld.scala | 36 +
.../gatk/queue/qscripts/lib/ChunkVCF.scala | 115 +
.../gatk/queue/qscripts/lib/Vcf2Table.scala | 55 +
.../gatk/queue/qscripts/lib/VcfToPed.scala | 225 +
.../gatk/queue/extensions/cancer/MuTect.scala | 420 +
.../queue/extensions/gatk/BamGatherFunction.scala | 57 +
.../extensions/gatk/CatVariantsGatherer.scala | 59 +
.../extensions/gatk/ContigScatterFunction.scala | 50 +
.../gatk/DistributedScatterFunction.scala | 52 +
.../gatk/queue/extensions/gatk/DoC/package.scala | 242 +
.../gatk/queue/extensions/gatk/GATKIntervals.scala | 98 +
.../extensions/gatk/GATKScatterFunction.scala | 111 +
.../extensions/gatk/IntervalScatterFunction.scala | 46 +
.../extensions/gatk/LocusScatterFunction.scala | 43 +
.../extensions/gatk/ReadScatterFunction.scala | 57 +
.../gatk/queue/extensions/gatk/TaggedFile.scala | 58 +
.../queue/extensions/gatk/VcfGatherFunction.scala | 53 +
.../gatk/WriteFlankingIntervalsFunction.scala | 49 +
.../extensions/picard/AddOrReplaceReadGroups.scala | 90 +
.../extensions/picard/CalculateHsMetrics.scala | 68 +
.../extensions/picard/CollectGcBiasMetrics.scala | 57 +
.../extensions/picard/CollectMultipleMetrics.scala | 61 +
.../gatk/queue/extensions/picard/FastqToSam.scala | 104 +
.../queue/extensions/picard/MarkDuplicates.scala | 79 +
.../queue/extensions/picard/MergeSamFiles.scala | 74 +
.../extensions/picard/PicardBamFunction.scala | 63 +
.../extensions/picard/PicardMetricsFunction.scala | 54 +
.../gatk/queue/extensions/picard/ReorderSam.scala | 73 +
.../gatk/queue/extensions/picard/RevertSam.scala | 86 +
.../gatk/queue/extensions/picard/SamToFastq.scala | 107 +
.../gatk/queue/extensions/picard/SortSam.scala | 63 +
.../queue/extensions/picard/ValidateSamFile.scala | 85 +
.../samtools/SamtoolsCommandLineFunction.scala | 37 +
.../samtools/SamtoolsIndexFunction.scala | 56 +
.../samtools/SamtoolsMergeFunction.scala | 64 +
.../gatk/queue/extensions/snpeff/SnpEff.scala | 68 +
.../extensions/gatk/GATKIntervalsUnitTest.scala | 154 +
.../examples/ExampleCountLociQueueTest.scala | 46 +
.../examples/ExampleCountReadsQueueTest.scala | 43 +
.../examples/ExamplePrintReadsQueueTest.scala | 83 +
.../examples/ExampleReadFilterQueueTest.scala | 91 +
.../ExampleRetryMemoryLimitQueueTest.scala | 47 +
.../pipeline/examples/HelloWorldQueueTest.scala | 152 +
public/gatk-queue/pom.xml | 107 +
.../broadinstitute/gatk/queue/QueueVersion.java | 32 +
.../broadinstitute/gatk/queue/package-info.java | 26 +
.../gatk/queue/util/queueJobReport.R | 240 +
.../broadinstitute/gatk/queue/QCommandLine.scala | 295 +
.../broadinstitute/gatk/queue/QCommandPlugin.scala | 36 +
.../org/broadinstitute/gatk/queue/QException.scala | 31 +
.../org/broadinstitute/gatk/queue/QScript.scala | 184 +
.../broadinstitute/gatk/queue/QScriptManager.scala | 168 +
.../org/broadinstitute/gatk/queue/QSettings.scala | 101 +
.../gatk/queue/engine/CommandLineJobManager.scala | 35 +
.../gatk/queue/engine/CommandLineJobRunner.scala | 107 +
.../queue/engine/CommandLinePluginManager.scala | 33 +
.../gatk/queue/engine/FunctionEdge.scala | 211 +
.../gatk/queue/engine/InProcessJobManager.scala | 34 +
.../gatk/queue/engine/InProcessRunner.scala | 66 +
.../gatk/queue/engine/JobManager.scala | 60 +
.../gatk/queue/engine/JobRunInfo.scala | 79 +
.../gatk/queue/engine/JobRunner.scala | 89 +
.../gatk/queue/engine/MappingEdge.scala | 39 +
.../broadinstitute/gatk/queue/engine/QEdge.scala | 57 +
.../broadinstitute/gatk/queue/engine/QGraph.scala | 1228 +
.../gatk/queue/engine/QGraphSettings.scala | 85 +
.../broadinstitute/gatk/queue/engine/QNode.scala | 45 +
.../gatk/queue/engine/QStatusMessenger.scala | 41 +
.../gatk/queue/engine/RunnerStatus.scala | 34 +
.../gatk/queue/engine/drmaa/DrmaaJobManager.scala | 62 +
.../gatk/queue/engine/drmaa/DrmaaJobRunner.scala | 169 +
.../engine/gridengine/GridEngineJobManager.scala | 33 +
.../engine/gridengine/GridEngineJobRunner.scala | 88 +
.../gatk/queue/engine/lsf/Lsf706JobManager.scala | 40 +
.../gatk/queue/engine/lsf/Lsf706JobRunner.scala | 421 +
.../engine/pbsengine/PbsEngineJobManager.scala | 33 +
.../engine/pbsengine/PbsEngineJobRunner.scala | 98 +
.../gatk/queue/engine/shell/ShellJobManager.scala | 35 +
.../gatk/queue/engine/shell/ShellJobRunner.scala | 91 +
.../gatk/queue/function/CommandLineFunction.scala | 341 +
.../gatk/queue/function/InProcessFunction.scala | 48 +
.../queue/function/JavaCommandLineFunction.scala | 139 +
.../gatk/queue/function/ListWriterFunction.scala | 60 +
.../gatk/queue/function/QFunction.scala | 517 +
.../gatk/queue/function/RetryMemoryLimit.scala | 103 +
.../function/scattergather/CloneFunction.scala | 111 +
.../scattergather/ConcatenateLogsFunction.scala | 56 +
.../function/scattergather/GatherFunction.scala | 72 +
.../function/scattergather/GathererFunction.scala | 44 +
.../function/scattergather/ScatterFunction.scala | 78 +
.../scattergather/ScatterGatherableFunction.scala | 376 +
.../scattergather/SimpleTextGatherFunction.scala | 89 +
.../library/clf/vcf/VCFExtractIntervals.scala | 46 +
.../queue/library/clf/vcf/VCFExtractSamples.scala | 58 +
.../gatk/queue/library/ipf/SortByRef.scala | 82 +
.../library/ipf/vcf/VCFExtractIntervals.scala | 85 +
.../queue/library/ipf/vcf/VCFExtractSamples.scala | 62 +
.../queue/library/ipf/vcf/VCFExtractSites.scala | 99 +
.../queue/library/ipf/vcf/VCFSimpleMerge.scala | 107 +
.../gatk/queue/util/ClassFieldCache.scala | 219 +
.../gatk/queue/util/CollectionUtils.scala | 116 +
.../gatk/queue/util/EmailMessage.scala | 140 +
.../gatk/queue/util/EmailSettings.scala | 55 +
.../broadinstitute/gatk/queue/util/Logging.scala | 62 +
.../queue/util/PrimitiveOptionConversions.scala | 142 +
.../gatk/queue/util/QJobReport.scala | 110 +
.../gatk/queue/util/QJobsReporter.scala | 122 +
.../gatk/queue/util/QScriptUtils.scala | 101 +
.../gatk/queue/util/ReflectionUtils.scala | 170 +
.../gatk/queue/util/RemoteFile.scala | 42 +
.../gatk/queue/util/RemoteFileConverter.scala | 46 +
.../org/broadinstitute/gatk/queue/util/Retry.scala | 70 +
.../gatk/queue/util/RetryException.scala | 34 +
.../util/ScalaCompoundArgumentTypeDescriptor.scala | 114 +
.../gatk/queue/util/ShellUtils.scala | 61 +
.../gatk/queue/util/StringFileConversions.scala | 113 +
.../gatk/queue/util/SystemUtils.scala | 67 +
.../gatk/queue/util/TextFormatUtils.scala | 56 +
.../gatk/queue/util/VCF_BAM_utilities.scala | 79 +
.../function/CommandLineFunctionUnitTest.scala | 196 +
.../gatk/queue/pipeline/QueueTest.scala | 265 +
.../gatk/queue/pipeline/QueueTestEvalSpec.scala | 59 +
.../gatk/queue/pipeline/QueueTestSpec.scala | 68 +
.../gatk/queue/util/ShellUtilsUnitTest.scala | 82 +
.../queue/util/StringFileConversionsUnitTest.scala | 128 +
.../gatk/queue/util/SystemUtilsUnitTest.scala | 44 +
public/gatk-root/pom.xml | 717 +
public/gatk-tools-public/pom.xml | 81 +
.../main/java/htsjdk/samtools/GATKBAMFileSpan.java | 308 +
.../src/main/java/htsjdk/samtools/GATKBin.java | 135 +
.../src/main/java/htsjdk/samtools/GATKChunk.java | 116 +
.../java/htsjdk/samtools/PicardNamespaceUtils.java | 40 +
.../gatk/engine/CommandLineExecutable.java | 229 +
.../gatk/engine/CommandLineGATK.java | 385 +
.../gatk/engine/GenomeAnalysisEngine.java | 1280 +
.../broadinstitute/gatk/engine/ReadProperties.java | 198 +
.../broadinstitute/gatk/engine/WalkerManager.java | 431 +
.../gatk/engine/alignment/Aligner.java | 74 +
.../gatk/engine/alignment/Alignment.java | 246 +
.../gatk/engine/alignment/bwa/BWAAligner.java | 63 +
.../engine/alignment/bwa/BWAConfiguration.java | 79 +
.../gatk/engine/alignment/bwa/BWTFiles.java | 259 +
.../alignment/bwa/java/AlignerTestHarness.java | 189 +
.../alignment/bwa/java/AlignmentMatchSequence.java | 175 +
.../engine/alignment/bwa/java/AlignmentState.java | 38 +
.../engine/alignment/bwa/java/BWAAlignment.java | 215 +
.../engine/alignment/bwa/java/BWAJavaAligner.java | 418 +
.../gatk/engine/alignment/bwa/java/LowerBound.java | 113 +
.../gatk/engine/alignment/package-info.java | 26 +
.../engine/alignment/reference/bwt/AMBWriter.java | 93 +
.../engine/alignment/reference/bwt/ANNWriter.java | 120 +
.../gatk/engine/alignment/reference/bwt/BWT.java | 197 +
.../engine/alignment/reference/bwt/BWTReader.java | 114 +
.../bwt/BWTSupplementaryFileGenerator.java | 85 +
.../engine/alignment/reference/bwt/BWTWriter.java | 96 +
.../gatk/engine/alignment/reference/bwt/Bases.java | 133 +
.../engine/alignment/reference/bwt/Counts.java | 176 +
.../reference/bwt/CreateBWTFromReference.java | 200 +
.../alignment/reference/bwt/SequenceBlock.java | 66 +
.../alignment/reference/bwt/SuffixArray.java | 183 +
.../alignment/reference/bwt/SuffixArrayReader.java | 110 +
.../alignment/reference/bwt/SuffixArrayWriter.java | 92 +
.../reference/packing/BasePackedInputStream.java | 120 +
.../reference/packing/BasePackedOutputStream.java | 165 +
.../reference/packing/CreatePACFromReference.java | 64 +
.../alignment/reference/packing/PackUtils.java | 160 +
.../packing/UnsignedIntPackedInputStream.java | 129 +
.../packing/UnsignedIntPackedOutputStream.java | 121 +
.../engine/arguments/DbsnpArgumentCollection.java | 46 +
.../engine/arguments/GATKArgumentCollection.java | 628 +
...ndardVariantContextInputArgumentCollection.java | 48 +
.../gatk/engine/arguments/ValidationExclusion.java | 67 +
.../gatk/engine/contexts/AlignmentContext.java | 154 +
.../engine/contexts/AlignmentContextUtils.java | 150 +
.../gatk/engine/contexts/ReferenceContext.java | 217 +
.../gatk/engine/datasources/package-info.java | 26 +
.../engine/datasources/providers/AllLocusView.java | 169 +
.../datasources/providers/CoveredLocusView.java | 63 +
.../IntervalOverlappingRODsFromStream.java | 168 +
.../providers/IntervalReferenceOrderedView.java | 184 +
.../providers/InvalidPositionException.java | 46 +
.../datasources/providers/LocusReferenceView.java | 236 +
.../providers/LocusShardDataProvider.java | 100 +
.../engine/datasources/providers/LocusView.java | 220 +
.../providers/ManagingReferenceOrderedView.java | 117 +
.../providers/RODMetaDataContainer.java | 83 +
.../providers/ReadBasedReferenceOrderedView.java | 69 +
.../datasources/providers/ReadReferenceView.java | 102 +
.../providers/ReadShardDataProvider.java | 82 +
.../engine/datasources/providers/ReadView.java | 88 +
.../providers/ReferenceOrderedView.java | 33 +
.../datasources/providers/ReferenceView.java | 131 +
.../engine/datasources/providers/RodLocusView.java | 197 +
.../datasources/providers/ShardDataProvider.java | 197 +
.../gatk/engine/datasources/providers/View.java | 55 +
.../engine/datasources/providers/package-info.java | 26 +
.../reads/ActiveRegionShardBalancer.java | 85 +
.../engine/datasources/reads/BAMAccessPlan.java | 170 +
.../gatk/engine/datasources/reads/BAMSchedule.java | 530 +
.../engine/datasources/reads/BAMScheduler.java | 320 +
.../reads/BGZFBlockLoadingDispatcher.java | 86 +
.../engine/datasources/reads/BlockInputStream.java | 450 +
.../gatk/engine/datasources/reads/BlockLoader.java | 189 +
.../engine/datasources/reads/FileHandleCache.java | 232 +
.../gatk/engine/datasources/reads/FilePointer.java | 436 +
.../engine/datasources/reads/GATKBAMIndex.java | 468 +
.../engine/datasources/reads/GATKBAMIndexData.java | 121 +
.../reads/IntervalOverlapFilteringIterator.java | 205 +
.../engine/datasources/reads/IntervalSharder.java | 93 +
.../gatk/engine/datasources/reads/LocusShard.java | 60 +
.../datasources/reads/LocusShardBalancer.java | 58 +
.../gatk/engine/datasources/reads/ReadShard.java | 271 +
.../datasources/reads/ReadShardBalancer.java | 231 +
.../engine/datasources/reads/SAMDataSource.java | 1179 +
.../gatk/engine/datasources/reads/SAMReaderID.java | 125 +
.../gatk/engine/datasources/reads/Shard.java | 253 +
.../engine/datasources/reads/ShardBalancer.java | 49 +
.../engine/datasources/reads/package-info.java | 26 +
.../datasources/reads/utilities/BAMFileStat.java | 185 +
.../datasources/reads/utilities/BAMTagRenamer.java | 100 +
.../reads/utilities/FindLargeShards.java | 192 +
.../reads/utilities/PrintBAMRegion.java | 113 +
.../reads/utilities/PrintBGZFBounds.java | 137 +
.../reads/utilities/UnzipSingleBlock.java | 89 +
.../datasources/reads/utilities/package-info.java | 26 +
.../datasources/reference/ReferenceDataSource.java | 199 +
.../engine/datasources/reference/package-info.java | 26 +
.../engine/datasources/rmd/DataStreamSegment.java | 32 +
.../gatk/engine/datasources/rmd/EntireStream.java | 32 +
.../datasources/rmd/MappedStreamSegment.java | 48 +
.../datasources/rmd/ReferenceOrderedDataPool.java | 153 +
.../rmd/ReferenceOrderedDataSource.java | 256 +
.../gatk/engine/datasources/rmd/ResourcePool.java | 188 +
.../gatk/engine/datasources/rmd/package-info.java | 26 +
.../AlleleBiasedDownsamplingUtils.java | 369 +
.../gatk/engine/downsampling/DownsampleType.java | 39 +
.../gatk/engine/downsampling/Downsampler.java | 161 +
.../engine/downsampling/DownsamplingMethod.java | 142 +
.../downsampling/DownsamplingReadsIterator.java | 116 +
.../engine/downsampling/DownsamplingUtils.java | 107 +
.../engine/downsampling/FractionalDownsampler.java | 129 +
.../downsampling/FractionalDownsamplerFactory.java | 46 +
.../engine/downsampling/LevelingDownsampler.java | 242 +
.../downsampling/PassThroughDownsampler.java | 111 +
.../PerSampleDownsamplingReadsIterator.java | 207 +
.../gatk/engine/downsampling/ReadsDownsampler.java | 56 +
.../downsampling/ReadsDownsamplerFactory.java | 38 +
.../engine/downsampling/ReservoirDownsampler.java | 219 +
.../downsampling/ReservoirDownsamplerFactory.java | 46 +
.../downsampling/SimplePositionalDownsampler.java | 171 +
.../SimplePositionalDownsamplerFactory.java | 46 +
.../gatk/engine/executive/Accumulator.java | 211 +
.../executive/HierarchicalMicroScheduler.java | 495 +
.../executive/HierarchicalMicroSchedulerMBean.java | 86 +
.../engine/executive/LinearMicroScheduler.java | 130 +
.../gatk/engine/executive/MicroScheduler.java | 463 +
.../gatk/engine/executive/MicroSchedulerMBean.java | 37 +
.../gatk/engine/executive/OutputMergeTask.java | 102 +
.../gatk/engine/executive/ReduceTree.java | 187 +
.../gatk/engine/executive/ShardTraverser.java | 163 +
.../gatk/engine/executive/TreeReducer.java | 127 +
.../gatk/engine/executive/WindowMaker.java | 217 +
.../gatk/engine/executive/package-info.java | 26 +
.../gatk/engine/filters/BadCigarFilter.java | 122 +
.../gatk/engine/filters/BadMateFilter.java | 47 +
.../engine/filters/CountingFilteringIterator.java | 150 +
.../gatk/engine/filters/DuplicateReadFilter.java | 66 +
.../filters/FailsVendorQualityCheckFilter.java | 41 +
.../gatk/engine/filters/FilterManager.java | 95 +
.../gatk/engine/filters/LibraryReadFilter.java | 49 +
.../gatk/engine/filters/MalformedReadFilter.java | 260 +
.../gatk/engine/filters/MappingQualityFilter.java | 46 +
.../filters/MappingQualityUnavailableFilter.java | 43 +
.../engine/filters/MappingQualityZeroFilter.java | 42 +
.../gatk/engine/filters/MateSameStrandFilter.java | 42 +
.../gatk/engine/filters/MaxInsertSizeFilter.java | 44 +
.../engine/filters/MissingReadGroupFilter.java | 41 +
.../engine/filters/NDNCigarReadTransformer.java | 118 +
.../filters/NoOriginalQualityScoresFilter.java | 65 +
.../engine/filters/NotPrimaryAlignmentFilter.java | 41 +
.../gatk/engine/filters/Platform454Filter.java | 43 +
.../gatk/engine/filters/PlatformFilter.java | 49 +
.../gatk/engine/filters/PlatformUnitFilter.java | 86 +
.../engine/filters/PlatformUnitFilterHelper.java | 87 +
.../gatk/engine/filters/ReadFilter.java | 60 +
.../engine/filters/ReadGroupBlackListFilter.java | 120 +
.../gatk/engine/filters/ReadLengthFilter.java | 48 +
.../gatk/engine/filters/ReadNameFilter.java | 44 +
.../gatk/engine/filters/ReadStrandFilter.java | 46 +
.../filters/ReassignMappingQualityFilter.java | 86 +
.../filters/ReassignOneMappingQualityFilter.java | 87 +
.../gatk/engine/filters/SampleFilter.java | 45 +
.../gatk/engine/filters/SingleReadGroupFilter.java | 48 +
.../gatk/engine/filters/UnmappedReadFilter.java | 41 +
.../gatk/engine/filters/package-info.java | 26 +
.../gatk/engine/io/DirectOutputTracker.java | 48 +
.../gatk/engine/io/FastqFileWriter.java | 77 +
.../gatk/engine/io/GATKSAMFileWriter.java | 56 +
.../gatk/engine/io/OutputTracker.java | 178 +
.../gatk/engine/io/ThreadGroupOutputTracker.java | 170 +
.../engine/io/storage/OutputStreamStorage.java | 144 +
.../engine/io/storage/SAMFileWriterStorage.java | 157 +
.../gatk/engine/io/storage/Storage.java | 45 +
.../gatk/engine/io/storage/StorageFactory.java | 92 +
.../io/storage/VariantContextWriterStorage.java | 228 +
.../stubs/OutputStreamArgumentTypeDescriptor.java | 134 +
.../gatk/engine/io/stubs/OutputStreamStub.java | 142 +
.../stubs/SAMFileReaderArgumentTypeDescriptor.java | 77 +
.../stubs/SAMFileWriterArgumentTypeDescriptor.java | 106 +
.../gatk/engine/io/stubs/SAMFileWriterStub.java | 336 +
.../broadinstitute/gatk/engine/io/stubs/Stub.java | 69 +
.../io/stubs/VCFWriterArgumentTypeDescriptor.java | 148 +
.../engine/io/stubs/VariantContextWriterStub.java | 301 +
.../gatk/engine/iterators/BoundedReadIterator.java | 159 +
.../gatk/engine/iterators/GATKSAMIterator.java | 56 +
.../engine/iterators/GATKSAMIteratorAdapter.java | 136 +
.../engine/iterators/GATKSAMRecordIterator.java | 57 +
.../gatk/engine/iterators/GenomeLocusIterator.java | 100 +
.../gatk/engine/iterators/IterableIterator.java | 40 +
.../MalformedBAMErrorReformatingIterator.java | 69 +
.../gatk/engine/iterators/NullSAMIterator.java | 57 +
.../gatk/engine/iterators/PeekingIterator.java | 65 +
.../engine/iterators/PositionTrackingIterator.java | 105 +
.../gatk/engine/iterators/PushbackIterator.java | 82 +
.../gatk/engine/iterators/RNAReadTransformer.java | 37 +
.../engine/iterators/ReadFormattingIterator.java | 140 +
.../gatk/engine/iterators/ReadTransformer.java | 205 +
.../engine/iterators/ReadTransformersMode.java | 53 +
.../engine/iterators/VerifyingSamIterator.java | 90 +
.../gatk/engine/iterators/package-info.java | 26 +
.../gatk/engine/phonehome/GATKRunReport.java | 786 +
.../engine/phonehome/GATKRunReportException.java | 99 +
.../gatk/engine/refdata/RODRecordListImpl.java | 129 +
.../gatk/engine/refdata/RefMetaDataTracker.java | 497 +
.../refdata/ReferenceDependentFeatureCodec.java | 43 +
.../gatk/engine/refdata/ReferenceOrderedDatum.java | 66 +
.../gatk/engine/refdata/SeekableRODIterator.java | 412 +
.../engine/refdata/VariantContextAdaptors.java | 399 +
.../gatk/engine/refdata/package-info.java | 26 +
.../gatk/engine/refdata/tracks/FeatureManager.java | 280 +
.../refdata/tracks/IndexDictionaryUtils.java | 114 +
.../gatk/engine/refdata/tracks/RMDTrack.java | 147 +
.../engine/refdata/tracks/RMDTrackBuilder.java | 430 +
.../utils/FeatureToGATKFeatureIterator.java | 74 +
.../engine/refdata/utils/FlashBackIterator.java | 221 +
.../gatk/engine/refdata/utils/GATKFeature.java | 109 +
.../utils/LocationAwareSeekableRODIterator.java | 49 +
.../gatk/engine/refdata/utils/RMDTriplet.java | 92 +
.../gatk/engine/refdata/utils/RODRecordList.java | 45 +
.../gatk/engine/report/GATKReport.java | 376 +
.../gatk/engine/report/GATKReportColumn.java | 147 +
.../gatk/engine/report/GATKReportColumnFormat.java | 63 +
.../gatk/engine/report/GATKReportDataType.java | 236 +
.../gatk/engine/report/GATKReportGatherer.java | 62 +
.../gatk/engine/report/GATKReportTable.java | 779 +
.../gatk/engine/report/GATKReportVersion.java | 101 +
.../resourcemanagement/ThreadAllocation.java | 116 +
.../gatk/engine/samples/Affection.java | 47 +
.../broadinstitute/gatk/engine/samples/Gender.java | 35 +
.../gatk/engine/samples/PedReader.java | 311 +
.../engine/samples/PedigreeValidationType.java | 42 +
.../broadinstitute/gatk/engine/samples/Sample.java | 259 +
.../gatk/engine/samples/SampleDB.java | 338 +
.../gatk/engine/samples/SampleDBBuilder.java | 161 +
.../broadinstitute/gatk/engine/samples/Trio.java | 70 +
.../engine/traversals/TAROrderedReadCache.java | 168 +
.../gatk/engine/traversals/TraversalEngine.java | 124 +
.../engine/traversals/TraverseActiveRegions.java | 719 +
.../gatk/engine/traversals/TraverseDuplicates.java | 205 +
.../gatk/engine/traversals/TraverseLociNano.java | 304 +
.../gatk/engine/traversals/TraverseReadPairs.java | 129 +
.../gatk/engine/traversals/TraverseReadsNano.java | 256 +
.../gatk/engine/traversals/package-info.java | 26 +
.../walkers/ActiveRegionTraversalParameters.java | 97 +
.../gatk/engine/walkers/ActiveRegionWalker.java | 196 +
.../broadinstitute/gatk/engine/walkers/Allows.java | 51 +
.../gatk/engine/walkers/Attribution.java | 39 +
.../gatk/engine/walkers/BAQMode.java | 56 +
.../org/broadinstitute/gatk/engine/walkers/By.java | 53 +
.../gatk/engine/walkers/DataSource.java | 58 +
.../gatk/engine/walkers/Downsample.java | 47 +
.../gatk/engine/walkers/DuplicateWalker.java | 57 +
.../gatk/engine/walkers/LocusWalker.java | 58 +
.../gatk/engine/walkers/Multiplex.java | 44 +
.../gatk/engine/walkers/Multiplexer.java | 52 +
.../gatk/engine/walkers/NanoSchedulable.java | 34 +
.../gatk/engine/walkers/PartitionBy.java | 39 +
.../gatk/engine/walkers/PartitionType.java | 61 +
.../broadinstitute/gatk/engine/walkers/RMD.java | 56 +
.../gatk/engine/walkers/ReadFilters.java | 45 +
.../gatk/engine/walkers/ReadPairWalker.java | 63 +
.../gatk/engine/walkers/ReadWalker.java | 55 +
.../gatk/engine/walkers/RefWalker.java | 39 +
.../gatk/engine/walkers/Reference.java | 47 +
.../gatk/engine/walkers/RemoveProgramRecords.java | 46 +
.../gatk/engine/walkers/Requires.java | 52 +
.../gatk/engine/walkers/RodWalker.java | 39 +
.../gatk/engine/walkers/TreeReducible.java | 49 +
.../broadinstitute/gatk/engine/walkers/Walker.java | 177 +
.../gatk/engine/walkers/WalkerName.java | 42 +
.../broadinstitute/gatk/engine/walkers/Window.java | 57 +
.../walkers/diffengine/BAMDiffableReader.java | 119 +
.../engine/walkers/diffengine/DiffElement.java | 125 +
.../gatk/engine/walkers/diffengine/DiffEngine.java | 437 +
.../gatk/engine/walkers/diffengine/DiffNode.java | 249 +
.../engine/walkers/diffengine/DiffObjects.java | 276 +
.../gatk/engine/walkers/diffengine/DiffValue.java | 90 +
.../engine/walkers/diffengine/DiffableReader.java | 66 +
.../gatk/engine/walkers/diffengine/Difference.java | 137 +
.../diffengine/GATKReportDiffableReader.java | 104 +
.../walkers/diffengine/VCFDiffableReader.java | 145 +
.../org/broadinstitute/gatk/tools/CatVariants.java | 338 +
.../broadinstitute/gatk/tools/ListAnnotations.java | 85 +
.../tools/walkers/annotator/AlleleBalance.java | 218 +
.../walkers/annotator/AlleleBalanceBySample.java | 181 +
.../gatk/tools/walkers/annotator/BaseCounts.java | 91 +
.../annotator/ChromosomeCountConstants.java | 44 +
.../gatk/tools/walkers/annotator/LowMQ.java | 91 +
.../annotator/MappingQualityZeroBySample.java | 86 +
.../gatk/tools/walkers/annotator/NBaseCount.java | 89 +
.../gatk/tools/walkers/annotator/SnpEff.java | 586 +
.../gatk/tools/walkers/annotator/SnpEffUtil.java | 154 +
.../tools/walkers/annotator/VariantAnnotator.java | 336 +
.../walkers/annotator/VariantAnnotatorEngine.java | 304 +
.../walkers/annotator/VariantOverlapAnnotator.java | 224 +
.../interfaces/ActiveRegionBasedAnnotation.java | 42 +
.../interfaces/AnnotationInterfaceManager.java | 140 +
.../annotator/interfaces/AnnotationType.java | 28 +
.../annotator/interfaces/AnnotatorCompatible.java | 41 +
.../interfaces/ExperimentalAnnotation.java | 28 +
.../annotator/interfaces/GenotypeAnnotation.java | 54 +
.../annotator/interfaces/InfoFieldAnnotation.java | 62 +
.../interfaces/RodRequiringAnnotation.java | 28 +
.../annotator/interfaces/StandardAnnotation.java | 28 +
.../interfaces/VariantAnnotatorAnnotation.java | 43 +
.../interfaces/WorkInProgressAnnotation.java | 28 +
.../tools/walkers/beagle/BeagleOutputToVCF.java | 392 +
.../tools/walkers/beagle/ProduceBeagleInput.java | 463 +
.../walkers/beagle/VariantsToBeagleUnphased.java | 184 +
.../gatk/tools/walkers/coverage/CallableLoci.java | 396 +
.../walkers/coverage/CompareCallableLoci.java | 143 +
.../gatk/tools/walkers/coverage/CoverageUtils.java | 241 +
.../tools/walkers/coverage/DepthOfCoverage.java | 1110 +
.../walkers/coverage/DepthOfCoverageStats.java | 352 +
.../gatk/tools/walkers/coverage/DoCOutputType.java | 89 +
.../walkers/coverage/GCContentByInterval.java | 106 +
.../diagnostics/CoveredByNSamplesSites.java | 154 +
.../walkers/diagnostics/ErrorRatePerCycle.java | 215 +
.../walkers/diagnostics/ReadGroupProperties.java | 229 +
.../diagnostics/ReadLengthDistribution.java | 180 +
.../tools/walkers/examples/GATKDocsExample.java | 83 +
.../tools/walkers/examples/GATKPaperGenotyper.java | 273 +
.../fasta/FastaAlternateReferenceMaker.java | 187 +
.../tools/walkers/fasta/FastaReferenceMaker.java | 127 +
.../gatk/tools/walkers/fasta/FastaSequence.java | 101 +
.../gatk/tools/walkers/fasta/FastaStats.java | 93 +
.../gatk/tools/walkers/filters/ClusteredSnps.java | 81 +
.../tools/walkers/filters/FiltrationContext.java | 47 +
.../walkers/filters/FiltrationContextWindow.java | 104 +
.../tools/walkers/filters/VariantFiltration.java | 400 +
.../gatk/tools/walkers/genotyper/AlleleList.java | 41 +
.../walkers/genotyper/AlleleListPermutation.java | 35 +
.../tools/walkers/genotyper/AlleleListUtils.java | 334 +
.../tools/walkers/genotyper/IndexedAlleleList.java | 95 +
.../tools/walkers/genotyper/IndexedSampleList.java | 96 +
.../gatk/tools/walkers/genotyper/SampleList.java | 42 +
.../tools/walkers/genotyper/SampleListUtils.java | 224 +
.../haplotypecaller/HCMappingQualityFilter.java | 54 +
.../gatk/tools/walkers/package-info.java | 26 +
.../gatk/tools/walkers/qc/CheckPileup.java | 258 +
.../gatk/tools/walkers/qc/CountBases.java | 74 +
.../gatk/tools/walkers/qc/CountIntervals.java | 128 +
.../gatk/tools/walkers/qc/CountLoci.java | 96 +
.../gatk/tools/walkers/qc/CountMales.java | 85 +
.../gatk/tools/walkers/qc/CountRODs.java | 214 +
.../gatk/tools/walkers/qc/CountRODsByRef.java | 112 +
.../gatk/tools/walkers/qc/CountReadEvents.java | 121 +
.../gatk/tools/walkers/qc/CountReads.java | 81 +
.../gatk/tools/walkers/qc/CountTerminusEvent.java | 104 +
.../gatk/tools/walkers/qc/DocumentationTest.java | 117 +
.../gatk/tools/walkers/qc/ErrorThrowing.java | 110 +
.../gatk/tools/walkers/qc/FlagStat.java | 225 +
.../gatk/tools/walkers/qc/Pileup.java | 217 +
.../gatk/tools/walkers/qc/PrintRODs.java | 91 +
.../gatk/tools/walkers/qc/QCRef.java | 142 +
.../gatk/tools/walkers/qc/ReadClippingStats.java | 157 +
.../gatk/tools/walkers/qc/RodSystemValidation.java | 182 +
.../gatk/tools/walkers/readutils/ClipReads.java | 607 +
.../gatk/tools/walkers/readutils/PrintReads.java | 316 +
.../walkers/readutils/ReadAdaptorTrimmer.java | 395 +
.../gatk/tools/walkers/readutils/SplitSamFile.java | 151 +
.../tools/walkers/varianteval/VariantEval.java | 666 +
.../varianteval/VariantEvalReportWriter.java | 203 +
.../varianteval/evaluators/CompOverlap.java | 109 +
.../varianteval/evaluators/CountVariants.java | 219 +
.../evaluators/IndelLengthHistogram.java | 123 +
.../varianteval/evaluators/IndelSummary.java | 259 +
.../evaluators/MendelianViolationEvaluator.java | 187 +
.../evaluators/MultiallelicSummary.java | 164 +
.../varianteval/evaluators/PrintMissingComp.java | 57 +
.../varianteval/evaluators/StandardEval.java | 28 +
.../evaluators/ThetaVariantEvaluator.java | 143 +
.../evaluators/TiTvVariantEvaluator.java | 100 +
.../varianteval/evaluators/ValidationReport.java | 183 +
.../varianteval/evaluators/VariantEvaluator.java | 133 +
.../varianteval/evaluators/VariantSummary.java | 277 +
.../varianteval/stratifications/AlleleCount.java | 114 +
.../stratifications/AlleleFrequency.java | 61 +
.../varianteval/stratifications/CompRod.java | 51 +
.../varianteval/stratifications/Contig.java | 54 +
.../walkers/varianteval/stratifications/CpG.java | 76 +
.../varianteval/stratifications/Degeneracy.java | 158 +
.../stratifications/DynamicStratification.java | 66 +
.../varianteval/stratifications/EvalRod.java | 52 +
.../varianteval/stratifications/Filter.java | 56 +
.../stratifications/FunctionalClass.java | 110 +
.../varianteval/stratifications/IndelSize.java | 78 +
.../stratifications/IntervalStratification.java | 92 +
.../stratifications/JexlExpression.java | 69 +
.../varianteval/stratifications/Novelty.java | 64 +
.../varianteval/stratifications/OneBPIndel.java | 59 +
.../stratifications/RequiredStratification.java | 28 +
.../varianteval/stratifications/Sample.java | 57 +
.../stratifications/SnpEffPositionModifier.java | 86 +
.../stratifications/StandardStratification.java | 29 +
.../varianteval/stratifications/TandemRepeat.java | 67 +
.../stratifications/VariantStratifier.java | 110 +
.../varianteval/stratifications/VariantType.java | 49 +
.../stratifications/manager/StratNode.java | 166 +
.../stratifications/manager/StratNodeIterator.java | 69 +
.../manager/StratificationManager.java | 426 +
.../stratifications/manager/Stratifier.java | 41 +
.../tools/walkers/varianteval/util/Analysis.java | 36 +
.../varianteval/util/AnalysisModuleScanner.java | 154 +
.../tools/walkers/varianteval/util/DataPoint.java | 35 +
.../varianteval/util/EvaluationContext.java | 115 +
.../tools/walkers/varianteval/util/Molten.java | 64 +
.../varianteval/util/SortableJexlVCMatchExp.java | 45 +
.../walkers/varianteval/util/VariantEvalUtils.java | 311 +
.../variantrecalibration/VQSRCalibrationCurve.java | 160 +
.../walkers/variantutils/CombineVariants.java | 371 +
.../walkers/variantutils/ConcordanceMetrics.java | 369 +
.../walkers/variantutils/FilterLiftedVariants.java | 136 +
.../walkers/variantutils/GenotypeConcordance.java | 675 +
.../variantutils/LeftAlignAndTrimVariants.java | 303 +
.../walkers/variantutils/LiftoverVariants.java | 179 +
.../variantutils/RandomlySplitVariants.java | 165 +
.../tools/walkers/variantutils/SelectHeaders.java | 278 +
.../tools/walkers/variantutils/SelectVariants.java | 801 +
.../walkers/variantutils/ValidateVariants.java | 301 +
.../variantutils/VariantValidationAssessor.java | 304 +
.../variantutils/VariantsToAllelicPrimitives.java | 140 +
.../walkers/variantutils/VariantsToBinaryPed.java | 550 +
.../walkers/variantutils/VariantsToTable.java | 460 +
.../tools/walkers/variantutils/VariantsToVCF.java | 271 +
.../gatk/utils/AutoFormattingTime.java | 185 +
.../org/broadinstitute/gatk/utils/BaseUtils.java | 672 +
.../org/broadinstitute/gatk/utils/BitSetUtils.java | 134 +
.../gatk/utils/ContigComparator.java | 80 +
.../gatk/utils/DeprecatedToolChecks.java | 96 +
.../broadinstitute/gatk/utils/GenomeLocParser.java | 622 +
.../gatk/utils/GenomeLocSortedSet.java | 476 +
.../broadinstitute/gatk/utils/HeapSizeMonitor.java | 107 +
.../org/broadinstitute/gatk/utils/IndelUtils.java | 262 +
.../org/broadinstitute/gatk/utils/LRUCache.java | 45 +
.../utils/MRUCachingSAMSequenceDictionary.java | 186 +
.../broadinstitute/gatk/utils/MannWhitneyU.java | 508 +
.../org/broadinstitute/gatk/utils/MathUtils.java | 1690 +
.../java/org/broadinstitute/gatk/utils/Median.java | 94 +
.../gatk/utils/MendelianViolation.java | 460 +
.../gatk/utils/MultiThreadedErrorTracker.java | 105 +
.../org/broadinstitute/gatk/utils/NGSPlatform.java | 136 +
.../org/broadinstitute/gatk/utils/PathUtils.java | 195 +
.../broadinstitute/gatk/utils/QualityUtils.java | 397 +
.../gatk/utils/R/RScriptExecutor.java | 191 +
.../gatk/utils/R/RScriptExecutorException.java | 34 +
.../gatk/utils/R/RScriptLibrary.java | 66 +
.../org/broadinstitute/gatk/utils/R/RUtils.java | 91 +
.../org/broadinstitute/gatk/utils/SampleUtils.java | 290 +
.../gatk/utils/SequenceDictionaryUtils.java | 527 +
.../gatk/utils/UnvalidatingGenomeLoc.java | 50 +
.../java/org/broadinstitute/gatk/utils/Utils.java | 1186 +
.../gatk/utils/activeregion/ActiveRegion.java | 500 +
.../utils/activeregion/ActiveRegionReadState.java | 40 +
.../gatk/utils/activeregion/ActivityProfile.java | 520 +
.../utils/activeregion/ActivityProfileState.java | 112 +
.../activeregion/BandPassActivityProfile.java | 194 +
.../gatk/utils/analysis/AminoAcid.java | 114 +
.../gatk/utils/analysis/AminoAcidTable.java | 94 +
.../gatk/utils/analysis/AminoAcidUtils.java | 77 +
.../org/broadinstitute/gatk/utils/baq/BAQ.java | 713 +
.../gatk/utils/baq/BAQReadTransformer.java | 74 +
.../gatk/utils/baq/ReadTransformingIterator.java | 69 +
.../gatk/utils/classloader/JVMUtils.java | 309 +
.../gatk/utils/classloader/PluginManager.java | 355 +
.../utils/classloader/ProtectedPackageSource.java | 28 +
.../utils/classloader/PublicPackageSource.java | 28 +
.../gatk/utils/clipping/ClippingOp.java | 617 +
.../utils/clipping/ClippingRepresentation.java | 63 +
.../gatk/utils/clipping/ReadClipper.java | 568 +
.../gatk/utils/codecs/beagle/BeagleCodec.java | 276 +
.../gatk/utils/codecs/beagle/BeagleFeature.java | 111 +
.../gatk/utils/codecs/hapmap/RawHapMapCodec.java | 125 +
.../gatk/utils/codecs/hapmap/RawHapMapFeature.java | 196 +
.../gatk/utils/codecs/refseq/RefSeqCodec.java | 171 +
.../gatk/utils/codecs/refseq/RefSeqFeature.java | 323 +
.../gatk/utils/codecs/refseq/Transcript.java | 78 +
.../utils/codecs/sampileup/SAMPileupCodec.java | 354 +
.../utils/codecs/sampileup/SAMPileupFeature.java | 276 +
.../gatk/utils/codecs/samread/SAMReadCodec.java | 123 +
.../gatk/utils/codecs/samread/SAMReadFeature.java | 199 +
.../gatk/utils/codecs/table/BedTableCodec.java | 59 +
.../gatk/utils/codecs/table/TableCodec.java | 126 +
.../gatk/utils/codecs/table/TableFeature.java | 99 +
.../gatk/utils/collections/DefaultHashMap.java | 56 +
.../gatk/utils/collections/ExpandingArrayList.java | 69 +
.../gatk/utils/collections/IndexedSet.java | 342 +
.../collections/LoggingNestedIntegerArray.java | 120 +
.../gatk/utils/collections/NestedIntegerArray.java | 221 +
.../gatk/utils/collections/Pair.java | 93 +
.../gatk/utils/collections/Permutation.java | 103 +
.../gatk/utils/collections/PrimitivePair.java | 200 +
.../gatk/utils/collections/RODMergingIterator.java | 160 +
.../gatk/utils/commandline/Advanced.java | 41 +
.../gatk/utils/commandline/Argument.java | 125 +
.../gatk/utils/commandline/ArgumentCollection.java | 45 +
.../gatk/utils/commandline/ArgumentDefinition.java | 297 +
.../utils/commandline/ArgumentDefinitionGroup.java | 99 +
.../utils/commandline/ArgumentDefinitions.java | 195 +
.../gatk/utils/commandline/ArgumentException.java | 38 +
.../gatk/utils/commandline/ArgumentIOType.java | 52 +
.../gatk/utils/commandline/ArgumentMatch.java | 294 +
.../utils/commandline/ArgumentMatchFileValue.java | 52 +
.../gatk/utils/commandline/ArgumentMatchSite.java | 77 +
.../utils/commandline/ArgumentMatchSource.java | 97 +
.../utils/commandline/ArgumentMatchSourceType.java | 33 +
.../commandline/ArgumentMatchStringValue.java | 49 +
.../gatk/utils/commandline/ArgumentMatchValue.java | 43 +
.../gatk/utils/commandline/ArgumentMatches.java | 211 +
.../gatk/utils/commandline/ArgumentSource.java | 243 +
.../utils/commandline/ArgumentTypeDescriptor.java | 1030 +
.../gatk/utils/commandline/ClassType.java | 40 +
.../gatk/utils/commandline/CommandLineProgram.java | 447 +
.../gatk/utils/commandline/CommandLineUtils.java | 192 +
.../commandline/EnumerationArgumentDefault.java | 65 +
.../gatk/utils/commandline/Gather.java | 41 +
.../gatk/utils/commandline/Gatherer.java | 47 +
.../gatk/utils/commandline/Hidden.java | 41 +
.../gatk/utils/commandline/Input.java | 83 +
.../commandline/IntervalArgumentCollection.java | 88 +
.../gatk/utils/commandline/IntervalBinding.java | 106 +
.../commandline/MissingArgumentValueException.java | 50 +
.../gatk/utils/commandline/Output.java | 90 +
.../gatk/utils/commandline/ParsedArgs.java | 38 +
.../gatk/utils/commandline/ParsedListArgs.java | 55 +
.../gatk/utils/commandline/ParsingEngine.java | 829 +
.../commandline/ParsingEngineArgumentFiles.java | 55 +
.../commandline/ParsingEngineArgumentProvider.java | 37 +
.../gatk/utils/commandline/ParsingMethod.java | 127 +
.../gatk/utils/commandline/RodBinding.java | 197 +
.../utils/commandline/RodBindingCollection.java | 89 +
.../gatk/utils/commandline/Tags.java | 112 +
.../gatk/utils/commandline/package-info.java | 26 +
.../gatk/utils/crypt/CryptUtils.java | 391 +
.../broadinstitute/gatk/utils/crypt/GATKKey.java | 350 +
.../gatk/utils/duplicates/DupUtils.java | 142 +
.../gatk/utils/duplicates/DuplicateComp.java | 66 +
.../DynamicClassResolutionException.java | 54 +
.../gatk/utils/exceptions/UserException.java | 485 +
.../gatk/utils/fasta/ArtificialFastaUtils.java | 154 +
.../fasta/CachingIndexedFastaSequenceFile.java | 311 +
.../gatk/utils/fasta/package-info.java | 26 +
.../gatk/utils/file/FSLockWithShared.java | 293 +
.../gatk/utils/fragments/FragmentCollection.java | 67 +
.../gatk/utils/fragments/FragmentUtils.java | 377 +
.../gatk/utils/genotyper/DiploidGenotype.java | 125 +
.../gatk/utils/genotyper/MostLikelyAllele.java | 134 +
.../genotyper/PerReadAlleleLikelihoodMap.java | 413 +
.../gatk/utils/genotyper/ReadLikelihoods.java | 1587 +
.../gatk/utils/haplotype/EventMap.java | 423 +
.../gatk/utils/haplotype/Haplotype.java | 343 +
.../utils/haplotype/HaplotypeBaseComparator.java | 42 +
.../utils/haplotype/HaplotypeScoreComparator.java | 39 +
.../haplotype/HaplotypeSizeAndBaseComparator.java | 47 +
.../gatk/utils/help/ApplicationDetails.java | 95 +
.../gatk/utils/help/DocletUtils.java | 76 +
.../gatk/utils/help/DocumentedGATKFeature.java | 50 +
.../utils/help/DocumentedGATKFeatureHandler.java | 99 +
.../utils/help/DocumentedGATKFeatureObject.java | 61 +
.../gatk/utils/help/ForumAPIUtils.java | 173 +
.../gatk/utils/help/ForumDiscussion.java | 84 +
.../gatk/utils/help/GATKDocUtils.java | 71 +
.../gatk/utils/help/GATKDocWorkUnit.java | 127 +
.../broadinstitute/gatk/utils/help/GATKDoclet.java | 576 +
.../gatk/utils/help/GSONArgument.java | 83 +
.../gatk/utils/help/GSONWorkUnit.java | 86 +
.../utils/help/GenericDocumentationHandler.java | 1008 +
.../gatk/utils/help/HelpConstants.java | 83 +
.../gatk/utils/help/HelpFormatter.java | 336 +
.../broadinstitute/gatk/utils/help/HelpUtils.java | 64 +
.../utils/help/ResourceBundleExtractorDoclet.java | 228 +
.../gatk/utils/instrumentation/Sizeof.java | 146 +
.../gatk/utils/interval/IntervalMergingRule.java | 35 +
.../gatk/utils/interval/IntervalSetRule.java | 36 +
.../gatk/utils/interval/IntervalUtils.java | 890 +
.../gatk/utils/io/FileExtension.java | 37 +
.../utils/io/HardThresholdingOutputStream.java | 56 +
.../org/broadinstitute/gatk/utils/io/IOUtils.java | 575 +
.../org/broadinstitute/gatk/utils/io/Resource.java | 91 +
.../gatk/utils/jna/clibrary/JNAUtils.java | 59 +
.../gatk/utils/jna/clibrary/LibC.java | 200 +
.../gatk/utils/jna/drmaa/v1_0/JnaJobInfo.java | 101 +
.../gatk/utils/jna/drmaa/v1_0/JnaJobTemplate.java | 316 +
.../gatk/utils/jna/drmaa/v1_0/JnaSession.java | 461 +
.../utils/jna/drmaa/v1_0/JnaSessionFactory.java | 40 +
.../gatk/utils/jna/drmaa/v1_0/LibDrmaa.java | 723 +
.../gatk/utils/jna/lsf/v7_0_6/LibBat.java | 20014 ++++++++
.../gatk/utils/jna/lsf/v7_0_6/LibLsf.java | 1780 +
.../utils/locusiterator/AlignmentStateMachine.java | 370 +
.../utils/locusiterator/LIBSDownsamplingInfo.java | 51 +
.../gatk/utils/locusiterator/LIBSPerformance.java | 198 +
.../gatk/utils/locusiterator/LocusIterator.java | 62 +
.../utils/locusiterator/LocusIteratorByState.java | 454 +
.../locusiterator/PerSampleReadStateManager.java | 261 +
.../gatk/utils/locusiterator/ReadStateManager.java | 289 +
.../utils/locusiterator/SamplePartitioner.java | 172 +
.../gatk/utils/nanoScheduler/EOFMarkedValue.java | 105 +
.../gatk/utils/nanoScheduler/InputProducer.java | 217 +
.../gatk/utils/nanoScheduler/MapResult.java | 75 +
.../gatk/utils/nanoScheduler/MapResultsQueue.java | 116 +
.../gatk/utils/nanoScheduler/NSMapFunction.java | 44 +
.../utils/nanoScheduler/NSProgressFunction.java | 37 +
.../gatk/utils/nanoScheduler/NSReduceFunction.java | 43 +
.../gatk/utils/nanoScheduler/NanoScheduler.java | 494 +
.../gatk/utils/nanoScheduler/Reducer.java | 169 +
.../gatk/utils/pairhmm/BatchPairHMM.java | 41 +
.../gatk/utils/pairhmm/Log10PairHMM.java | 220 +
.../gatk/utils/pairhmm/N2MemoryPairHMM.java | 98 +
.../broadinstitute/gatk/utils/pairhmm/PairHMM.java | 357 +
.../gatk/utils/pairhmm/PairHMMModel.java | 435 +
.../gatk/utils/pairhmm/PairHMMReadyHaplotypes.java | 182 +
.../utils/pileup/MergingPileupElementIterator.java | 76 +
.../gatk/utils/pileup/PileupElement.java | 539 +
.../gatk/utils/pileup/PileupElementFilter.java | 36 +
.../gatk/utils/pileup/PileupElementTracker.java | 154 +
.../gatk/utils/pileup/ReadBackedPileup.java | 295 +
.../gatk/utils/pileup/ReadBackedPileupImpl.java | 1040 +
.../org/broadinstitute/gatk/utils/pileup2/Notes | 34 +
.../gatk/utils/progressmeter/ProgressMeter.java | 465 +
.../utils/progressmeter/ProgressMeterDaemon.java | 111 +
.../utils/progressmeter/ProgressMeterData.java | 79 +
.../gatk/utils/recalibration/BQSRArgumentSet.java | 85 +
.../gatk/utils/recalibration/BQSRMode.java | 55 +
.../gatk/utils/recalibration/EventType.java | 72 +
.../gatk/utils/runtime/CapturedStreamOutput.java | 134 +
.../gatk/utils/runtime/InputStreamSettings.java | 116 +
.../gatk/utils/runtime/OutputStreamSettings.java | 127 +
.../gatk/utils/runtime/ProcessController.java | 387 +
.../gatk/utils/runtime/ProcessOutput.java | 57 +
.../gatk/utils/runtime/ProcessSettings.java | 140 +
.../gatk/utils/runtime/RuntimeUtils.java | 77 +
.../gatk/utils/runtime/StreamLocation.java | 33 +
.../gatk/utils/runtime/StreamOutput.java | 69 +
.../gatk/utils/sam/AlignmentStartComparator.java | 50 +
.../sam/AlignmentStartWithNoTiesComparator.java | 73 +
.../gatk/utils/sam/AlignmentUtils.java | 1337 +
.../gatk/utils/sam/ArtificialBAMBuilder.java | 242 +
.../utils/sam/ArtificialGATKSAMFileWriter.java | 130 +
.../utils/sam/ArtificialMultiSampleReadStream.java | 87 +
.../utils/sam/ArtificialPatternedSAMIterator.java | 172 +
.../gatk/utils/sam/ArtificialReadsTraversal.java | 140 +
.../gatk/utils/sam/ArtificialSAMFileReader.java | 156 +
.../gatk/utils/sam/ArtificialSAMIterator.java | 212 +
.../gatk/utils/sam/ArtificialSAMQueryIterator.java | 259 +
.../gatk/utils/sam/ArtificialSAMUtils.java | 484 +
.../sam/ArtificialSingleSampleReadStream.java | 213 +
.../ArtificialSingleSampleReadStreamAnalyzer.java | 282 +
.../gatk/utils/sam/BySampleSAMFileWriter.java | 70 +
.../broadinstitute/gatk/utils/sam/CigarUtils.java | 273 +
.../gatk/utils/sam/GATKSAMReadGroupRecord.java | 116 +
.../gatk/utils/sam/GATKSAMRecord.java | 631 +
.../gatk/utils/sam/GATKSamRecordFactory.java | 75 +
.../sam/MisencodedBaseQualityReadTransformer.java | 94 +
.../gatk/utils/sam/NWaySAMFileWriter.java | 185 +
.../ReadUnclippedStartWithNoTiesComparator.java | 73 +
.../broadinstitute/gatk/utils/sam/ReadUtils.java | 964 +
.../gatk/utils/sam/SAMFileReaderBuilder.java | 84 +
.../gatk/utils/sam/SimplifyingSAMFileWriter.java | 86 +
.../gatk/utils/sam/package-info.java | 26 +
.../GlobalEdgeGreedySWPairwiseAlignment.java | 208 +
.../gatk/utils/smithwaterman/Parameters.java | 62 +
.../utils/smithwaterman/SWPairwiseAlignment.java | 599 +
.../smithwaterman/SWPairwiseAlignmentMain.java | 221 +
.../gatk/utils/smithwaterman/SWParameterSet.java | 51 +
.../gatk/utils/smithwaterman/SmithWaterman.java | 57 +
.../gatk/utils/text/ListFileUtils.java | 344 +
.../gatk/utils/text/TextFormattingUtils.java | 172 +
.../broadinstitute/gatk/utils/text/XReadLines.java | 208 +
.../EfficiencyMonitoringThreadFactory.java | 160 +
.../gatk/utils/threading/NamedThreadFactory.java | 51 +
.../utils/threading/ThreadEfficiencyMonitor.java | 232 +
.../gatk/utils/threading/ThreadLocalArray.java | 65 +
.../gatk/utils/threading/ThreadPoolMonitor.java | 77 +
.../gatk/utils/threading/package-info.java | 26 +
.../gatk/utils/variant/GATKVCFIndexType.java | 39 +
.../gatk/utils/variant/GATKVCFUtils.java | 316 +
.../utils/variant/GATKVariantContextUtils.java | 1960 +
.../gatk/utils/variant/HomoSapiensConstants.java | 51 +
.../gatk/utils/wiggle/WiggleHeader.java | 56 +
.../gatk/utils/wiggle/WiggleWriter.java | 117 +
.../src/main/resources/GATK_public.key | Bin 0 -> 294 bytes
.../engine/phonehome/resources/GATK_AWS_access.key | Bin 0 -> 256 bytes
.../engine/phonehome/resources/GATK_AWS_secret.key | Bin 0 -> 256 bytes
.../walkers/variantrecalibration/plot_Tranches.R | 93 +
.../broadinstitute/gatk/utils/recalibration/BQSR.R | 159 +
.../htsjdk/samtools/GATKBAMFileSpanUnitTest.java | 254 +
.../java/htsjdk/samtools/GATKChunkUnitTest.java | 71 +
.../gatk/engine/CommandLineGATKUnitTest.java | 68 +
.../gatk/engine/EngineFeaturesIntegrationTest.java | 736 +
.../gatk/engine/GenomeAnalysisEngineUnitTest.java | 273 +
.../gatk/engine/MaxRuntimeIntegrationTest.java | 151 +
.../gatk/engine/ReadMetricsUnitTest.java | 371 +
.../gatk/engine/WalkerManagerUnitTest.java | 71 +
.../providers/AllLocusViewUnitTest.java | 90 +
.../providers/CoveredLocusViewUnitTest.java | 103 +
.../IntervalReferenceOrderedViewUnitTest.java | 366 +
.../providers/LocusReferenceViewUnitTest.java | 143 +
.../datasources/providers/LocusViewTemplate.java | 405 +
.../providers/ReadReferenceViewUnitTest.java | 160 +
.../providers/ReferenceOrderedViewUnitTest.java | 157 +
.../providers/ReferenceViewTemplate.java | 122 +
.../providers/ShardDataProviderUnitTest.java | 152 +
.../reads/ActiveRegionShardBalancerUnitTest.java | 102 +
.../datasources/reads/DownsamplerBenchmark.java | 94 +
.../datasources/reads/FilePointerUnitTest.java | 129 +
.../datasources/reads/GATKBAMIndexUnitTest.java | 108 +
.../datasources/reads/GATKWalkerBenchmark.java | 141 +
.../IntervalOverlapFilteringIteratorUnitTest.java | 150 +
.../engine/datasources/reads/MockLocusShard.java | 51 +
.../datasources/reads/PicardBaselineBenchmark.java | 101 +
.../datasources/reads/ReadProcessingBenchmark.java | 83 +
.../reads/ReadShardBalancerUnitTest.java | 195 +
.../datasources/reads/SAMDataSourceUnitTest.java | 253 +
.../datasources/reads/SAMReaderIDUnitTest.java | 49 +
.../reads/SeekableBufferedStreamUnitTest.java | 101 +
.../reads/TheoreticalMinimaBenchmark.java | 114 +
.../ReferenceDataSourceIntegrationTest.java | 75 +
.../rmd/ReferenceOrderedDataPoolUnitTest.java | 208 +
.../rmd/ReferenceOrderedQueryDataPoolUnitTest.java | 89 +
.../AlleleBiasedDownsamplingUtilsUnitTest.java | 219 +
.../downsampling/DownsamplingIntegrationTest.java | 44 +
.../DownsamplingReadsIteratorUnitTest.java | 139 +
.../FractionalDownsamplerUnitTest.java | 158 +
.../downsampling/LevelingDownsamplerUnitTest.java | 163 +
...PerSampleDownsamplingReadsIteratorUnitTest.java | 299 +
...edArtificialSingleSampleReadStreamAnalyzer.java | 127 +
.../downsampling/ReservoirDownsamplerUnitTest.java | 131 +
.../SimplePositionalDownsamplerUnitTest.java | 331 +
.../gatk/engine/executive/ReduceTreeUnitTest.java | 254 +
.../AllowNCigarMalformedReadFilterUnitTest.java | 77 +
.../engine/filters/BadCigarFilterUnitTest.java | 91 +
.../filters/BadReadGroupsIntegrationTest.java | 52 +
.../filters/MalformedReadFilterUnitTest.java | 246 +
.../filters/NDNCigarReadTransformerUnitTest.java | 70 +
.../gatk/engine/filters/ReadFilterTest.java | 370 +
.../filters/ReadGroupBlackListFilterUnitTest.java | 247 +
.../filters/UnsafeMalformedReadFilterUnitTest.java | 50 +
.../gatk/engine/io/OutputTrackerUnitTest.java | 84 +
.../iterators/BoundedReadIteratorUnitTest.java | 145 +
.../iterators/GATKSAMIteratorAdapterUnitTest.java | 176 +
.../iterators/ReadFormattingIteratorUnitTest.java | 50 +
.../iterators/VerifyingSamIteratorUnitTest.java | 128 +
.../engine/phonehome/GATKRunReportUnitTest.java | 310 +
.../engine/refdata/RefMetaDataTrackerUnitTest.java | 290 +
.../refdata/tracks/FeatureManagerUnitTest.java | 163 +
.../refdata/tracks/RMDTrackBuilderUnitTest.java | 190 +
.../utils/CheckableCloseableTribbleIterator.java | 90 +
.../FeatureToGATKFeatureIteratorUnitTest.java | 61 +
.../refdata/utils/FlashBackIteratorUnitTest.java | 364 +
.../engine/refdata/utils/TestFeatureReader.java | 53 +
.../engine/refdata/utils/TestRMDTrackBuilder.java | 71 +
.../gatk/engine/report/GATKReportUnitTest.java | 285 +
.../gatk/engine/samples/PedReaderUnitTest.java | 354 +
.../gatk/engine/samples/SampleDBUnitTest.java | 251 +
.../gatk/engine/samples/SampleUnitTest.java | 89 +
.../engine/traversals/DummyActiveRegionWalker.java | 116 +
.../traversals/TAROrderedReadCacheUnitTest.java | 111 +
.../traversals/TraverseActiveRegionsUnitTest.java | 679 +
.../traversals/TraverseDuplicatesUnitTest.java | 162 +
.../engine/traversals/TraverseReadsUnitTest.java | 166 +
.../gatk/engine/walkers/WalkerTest.java | 455 +
.../gatk/tools/CatVariantsIntegrationTest.java | 145 +
.../gatk/tools/walkers/BAQIntegrationTest.java | 55 +
.../CNV/SymbolicAllelesIntegrationTest.java | 63 +
.../walkers/annotator/SnpEffUtilUnitTest.java | 111 +
.../coverage/CallableLociIntegrationTest.java | 69 +
.../CompareCallableLociWalkerIntegrationTest.java | 42 +
.../DepthOfCoverageB36IntegrationTest.java | 111 +
.../coverage/DepthOfCoverageIntegrationTest.java | 181 +
.../walkers/qc/CheckPileupIntegrationTest.java | 70 +
.../gatk/tools/walkers/qc/CountReadsUnitTest.java | 51 +
.../qc/DictionaryConsistencyIntegrationTest.java | 82 +
.../tools/walkers/qc/FlagStatIntegrationTest.java | 45 +
.../walkers/qc/PileupWalkerIntegrationTest.java | 123 +
.../readutils/ClipReadsWalkersIntegrationTest.java | 80 +
.../readutils/PrintReadsIntegrationTest.java | 136 +
.../readutils/PrintReadsLargeScaleTest.java | 45 +
.../walkers/readutils/PrintReadsUnitTest.java | 123 +
.../ReadAdaptorTrimmerIntegrationTest.java | 60 +
.../variantutils/FilterLiftedVariantsUnitTest.java | 54 +
.../variantutils/SelectVariantsUnitTest.java | 88 +
.../gatk/utils/AutoFormattingTimeUnitTest.java | 118 +
.../org/broadinstitute/gatk/utils/BaseTest.java | 568 +
.../gatk/utils/BaseUtilsUnitTest.java | 179 +
.../gatk/utils/BitSetUtilsUnitTest.java | 85 +
.../gatk/utils/ExampleToCopyUnitTest.java | 241 +
.../gatk/utils/GATKTextReporter.java | 41 +
.../gatk/utils/GenomeLocParserBenchmark.java | 81 +
.../gatk/utils/GenomeLocParserUnitTest.java | 509 +
.../gatk/utils/GenomeLocSortedSetUnitTest.java | 405 +
.../gatk/utils/GenomeLocUnitTest.java | 386 +
.../java/org/broadinstitute/gatk/utils/MD5DB.java | 312 +
.../org/broadinstitute/gatk/utils/MD5Mismatch.java | 67 +
.../MRUCachingSAMSequencingDictionaryUnitTest.java | 97 +
.../org/broadinstitute/gatk/utils/MWUnitTest.java | 131 +
.../gatk/utils/MathUtilsUnitTest.java | 913 +
.../broadinstitute/gatk/utils/MedianUnitTest.java | 115 +
.../gatk/utils/NGSPlatformUnitTest.java | 167 +
.../gatk/utils/PathUtilsUnitTest.java | 65 +
.../gatk/utils/QualityUtilsUnitTest.java | 189 +
.../gatk/utils/R/RScriptExecutorUnitTest.java | 110 +
.../gatk/utils/R/RScriptLibraryUnitTest.java | 47 +
.../gatk/utils/R/RUtilsUnitTest.java | 65 +
.../gatk/utils/SampleUtilsUnitTest.java | 52 +
.../utils/SequenceDictionaryUtilsUnitTest.java | 241 +
.../gatk/utils/SimpleTimerUnitTest.java | 179 +
.../gatk/utils/TestNGTestTransformer.java | 62 +
.../broadinstitute/gatk/utils/UtilsUnitTest.java | 363 +
.../utils/activeregion/ActiveRegionUnitTest.java | 395 +
.../activeregion/ActivityProfileStateUnitTest.java | 92 +
.../activeregion/ActivityProfileUnitTest.java | 491 +
.../BandPassActivityProfileUnitTest.java | 339 +
.../broadinstitute/gatk/utils/baq/BAQUnitTest.java | 257 +
.../gatk/utils/classloader/JVMUtilsUnitTest.java | 75 +
.../gatk/utils/clipping/ReadClipperTestUtils.java | 144 +
.../gatk/utils/clipping/ReadClipperUnitTest.java | 421 +
.../gatk/utils/codecs/hapmap/HapMapUnitTest.java | 164 +
.../utils/collections/DefaultHashMapUnitTest.java | 159 +
.../collections/ExpandingArrayListUnitTest.java | 177 +
.../commandline/ArgumentMatchSiteUnitTest.java | 80 +
.../commandline/ArgumentMatchSourceUnitTest.java | 99 +
.../ArgumentTypeDescriptorUnitTest.java | 233 +
.../InvalidArgumentIntegrationTest.java | 66 +
.../utils/commandline/LoggingIntegrationTest.java | 117 +
.../utils/commandline/ParsingEngineUnitTest.java | 1140 +
.../commandline/RodBindingCollectionUnitTest.java | 133 +
.../gatk/utils/commandline/RodBindingUnitTest.java | 82 +
.../gatk/utils/crypt/CryptUtilsUnitTest.java | 199 +
.../gatk/utils/crypt/GATKKeyIntegrationTest.java | 157 +
.../gatk/utils/crypt/GATKKeyUnitTest.java | 129 +
.../CachingIndexedFastaSequenceFileUnitTest.java | 264 +
.../gatk/utils/file/FSLockWithSharedUnitTest.java | 60 +
.../utils/fragments/FragmentUtilsBenchmark.java | 81 +
.../utils/fragments/FragmentUtilsUnitTest.java | 390 +
.../gatk/utils/haplotype/EventMapUnitTest.java | 203 +
.../gatk/utils/haplotype/HaplotypeUnitTest.java | 249 +
.../utils/interval/IntervalIntegrationTest.java | 304 +
.../gatk/utils/interval/IntervalUtilsUnitTest.java | 1110 +
.../gatk/utils/io/IOUtilsUnitTest.java | 326 +
.../gatk/utils/jna/clibrary/LibCUnitTest.java | 70 +
.../utils/jna/drmaa/v1_0/JnaSessionQueueTest.java | 165 +
.../utils/jna/drmaa/v1_0/LibDrmaaQueueTest.java | 257 +
.../gatk/utils/jna/lsf/v7_0_6/LibBatQueueTest.java | 162 +
.../AlignmentStateMachineUnitTest.java | 110 +
.../gatk/utils/locusiterator/LIBS_position.java | 155 +
.../locusiterator/LocusIteratorBenchmark.java | 142 +
.../LocusIteratorByStateBaseTest.java | 252 +
.../LocusIteratorByStateUnitTest.java | 753 +
.../PerSampleReadStateManagerUnitTest.java | 188 +
.../utils/nanoScheduler/InputProducerUnitTest.java | 94 +
.../utils/nanoScheduler/MapResultUnitTest.java | 65 +
.../utils/nanoScheduler/NanoSchedulerUnitTest.java | 343 +
.../gatk/utils/nanoScheduler/ReducerUnitTest.java | 236 +
.../gatk/utils/pileup/PileupElementUnitTest.java | 189 +
.../utils/pileup/ReadBackedPileupUnitTest.java | 328 +
.../progressmeter/ProgressMeterDaemonUnitTest.java | 121 +
.../progressmeter/ProgressMeterDataUnitTest.java | 86 +
.../utils/recalibration/EventTypeUnitTest.java | 61 +
.../utils/report/ReportMarshallerUnitTest.java | 64 +
.../utils/runtime/ProcessControllerUnitTest.java | 518 +
.../gatk/utils/runtime/RuntimeUtilsUnitTest.java | 42 +
.../gatk/utils/sam/AlignmentUtilsUnitTest.java | 1044 +
.../utils/sam/ArtificialBAMBuilderUnitTest.java | 121 +
.../ArtificialPatternedSAMIteratorUnitTest.java | 122 +
.../utils/sam/ArtificialSAMFileWriterUnitTest.java | 120 +
.../sam/ArtificialSAMQueryIteratorUnitTest.java | 138 +
.../gatk/utils/sam/ArtificialSAMUtilsUnitTest.java | 108 +
.../ArtificialSingleSampleReadStreamUnitTest.java | 186 +
.../gatk/utils/sam/GATKSAMRecordUnitTest.java | 78 +
.../utils/sam/MisencodedBaseQualityUnitTest.java | 96 +
.../gatk/utils/sam/ReadUtilsUnitTest.java | 340 +
.../smithwaterman/SmithWatermanBenchmark.java | 87 +
.../gatk/utils/text/ListFileUtilsUnitTest.java | 159 +
.../utils/text/TextFormattingUtilsUnitTest.java | 89 +
.../EfficiencyMonitoringThreadFactoryUnitTest.java | 189 +
.../utils/threading/ThreadPoolMonitorUnitTest.java | 64 +
.../gatk/utils/variant/GATKVCFUtilsUnitTest.java | 138 +
.../variant/GATKVariantContextUtilsUnitTest.java | 1612 +
.../gatk/utils/variant/VCFIntegrationTest.java | 377 +
.../utils/variant/VariantContextBenchmark.java | 377 +
.../src/test/resources/testProperties.properties | 2 +
public/gatk-utils/pom.xml | 192 +
.../gatk/utils/help/log4j.properties | 7 +
.../org/broadinstitute/gatk/utils/GenomeLoc.java | 657 +
.../gatk/utils/HasGenomeLocation.java | 36 +
.../org/broadinstitute/gatk/utils/SimpleTimer.java | 261 +
.../gatk/utils/exceptions/GATKException.java | 64 +
.../utils/exceptions/ReviewedGATKException.java | 42 +
.../broadinstitute/gatk/utils/package-info.java | 26 +
.../gatk/utils/pairhmm/libVectorLoglessPairHMM.so | Bin 0 -> 479380 bytes
public/gsalib/pom.xml | 45 +
public/gsalib/src/R/DESCRIPTION | 13 +
public/gsalib/src/R/LICENSE | 2 +
public/gsalib/src/R/NAMESPACE | 1 +
public/gsalib/src/R/R/gsa.error.R | 12 +
public/gsalib/src/R/R/gsa.getargs.R | 116 +
public/gsalib/src/R/R/gsa.message.R | 3 +
public/gsalib/src/R/R/gsa.plot.venn.R | 50 +
public/gsalib/src/R/R/gsa.read.eval.R | 83 +
public/gsalib/src/R/R/gsa.read.gatkreport.R | 196 +
public/gsalib/src/R/R/gsa.read.squidmetrics.R | 28 +
public/gsalib/src/R/R/gsa.read.vcf.R | 23 +
public/gsalib/src/R/R/gsa.variantqc.utils.R | 246 +
public/gsalib/src/R/R/gsa.warn.R | 3 +
public/gsalib/src/R/Read-and-delete-me | 9 +
public/gsalib/src/R/man/gsa.error.Rd | 49 +
public/gsalib/src/R/man/gsa.getargs.Rd | 57 +
public/gsalib/src/R/man/gsa.message.Rd | 44 +
public/gsalib/src/R/man/gsa.plot.venn.Rd | 75 +
public/gsalib/src/R/man/gsa.read.eval.Rd | 111 +
public/gsalib/src/R/man/gsa.read.gatkreport.Rd | 55 +
public/gsalib/src/R/man/gsa.read.squidmetrics.Rd | 48 +
public/gsalib/src/R/man/gsa.read.vcf.Rd | 53 +
public/gsalib/src/R/man/gsa.warn.Rd | 46 +
public/gsalib/src/R/man/gsalib-package.Rd | 70 +
public/gsalib/src/assembly/gsalib.xml | 13 +
public/java/config/log4j.properties | 10 +
public/package-tests/pom.xml | 199 +
public/perl/liftOverVCF.pl | 83 +
public/perl/sortByRef.pl | 127 +
public/pom.xml | 47 +
.../cofoja/cofoja/1.0-r139/cofoja-1.0-r139.jar | Bin 0 -> 378205 bytes
.../cofoja/cofoja/1.0-r139/cofoja-1.0-r139.pom | 9 +
.../net/sf/snpeff/snpeff/2.0.5/snpeff-2.0.5.jar | Bin 0 -> 4178339 bytes
.../net/sf/snpeff/snpeff/2.0.5/snpeff-2.0.5.pom | 9 +
.../picard/picard/1.120.1579/picard-1.120.1579.jar | Bin 0 -> 1380569 bytes
.../picard/picard/1.120.1579/picard-1.120.1579.pom | 34 +
.../htsjdk/1.120.1620/htsjdk-1.120.1620.jar | Bin 0 -> 2185840 bytes
.../htsjdk/1.120.1620/htsjdk-1.120.1620.pom | 27 +
.../sysinternals/junction/1.04/junction-1.04.exe | Bin 0 -> 40960 bytes
.../junction/1.04/junction-1.04.exe.md5 | 1 +
.../sysinternals/junction/1.04/junction-1.04.pom | 15 +
.../junction/1.04/junction-1.04.pom.md5 | 1 +
.../src/main/scripts/shell/delete_maven_links.sh | 13 +
settings/helpTemplates/common.html | 88 +
settings/helpTemplates/generic.index.template.html | 93 +
settings/helpTemplates/generic.template.html | 327 +
1181 files changed, 390633 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..819c120
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,29 @@
+/*.bam
+/*.bai
+/*.bed
+*~
+/*.vcf
+/*.txt
+/*.csh
+/.*
+/*.pdf
+/*.eval
+*.ipr
+*.iws
+*.iml
+*.pyc
+.DS_Store
+queueScatterGather
+/foo*
+/bar*
+integrationtests/
+public/testdata/onTheFlyOutputTest.vcf
+build/
+dist/
+dump/
+lib/
+out/
+/atlassian-ide-plugin.xml
+maven-metadata-local.xml
+dependency-reduced-pom.xml
+public/external-example/target/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2c245a2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+The Genome Analysis Toolkit
+============
+See http://www.broadinstitute.org/gatk/
diff --git a/ant-bridge.sh b/ant-bridge.sh
new file mode 100755
index 0000000..a2f6865
--- /dev/null
+++ b/ant-bridge.sh
@@ -0,0 +1,173 @@
+#!/bin/sh
+
+mvn_args="verify"
+mvn_properties=
+mvn_clean=
+unknown_args=
+property_regex='-D(.*)=(.*)'
+unit_test_regex='.*UnitTest'
+post_script=
+run_type="run"
+
+for arg in "${@}" ; do
+ if [[ "${arg}" == "dry" ]] ; then
+ run_type="dry"
+
+ elif [[ "${arg}" == "clean" ]] ; then
+ mvn_clean="clean"
+ mvn_args=
+
+ elif [[ "${arg}" =~ ${property_regex} ]] ; then
+ property_name=${BASH_REMATCH[1]}
+ property_value=${BASH_REMATCH[2]}
+
+ if [[ "${property_name}" == "single" ]] ; then
+ test_property="test"
+ test_disabled="it.test"
+ if [[ ! "${property_value}" =~ ${unit_test_regex} ]] ; then
+ test_property="it.test"
+ test_disabled="test"
+ fi
+
+ mvn_properties="${mvn_properties} -D${test_disabled}=disabled -D${test_property}=${property_value}"
+
+ elif [[ "${property_name}" == "test.debug.port" ]] ; then
+ mvn_properties="${mvn_properties} -Dmaven.surefire.debug=\"-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${property_value}\""
+ mvn_properties="${mvn_properties} -Dmaven.failsafe.debug=\"-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${property_value}\""
+
+ elif [[ "${property_name}" == "test.default.maxmemory" ]] ; then
+ mvn_properties="${mvn_properties} -Dtest.maxmemory=${property_value}"
+
+ else
+ unknown_args="${unknown_args} \"${arg}\""
+
+ fi
+
+ else
+ if [[ "${arg}" != "dist" && "${mvn_args}" != "" && "${mvn_args}" != "verify" ]] ; then
+ echo "Sorry, this script does not currently support mixing targets." >&2
+ exit 1
+
+ elif [[ "${arg}" == "dist" ]] ; then
+ mvn_args="verify"
+
+ elif [[ "${arg}" == "gatk" ]] ; then
+ mvn_args="verify '-P!queue'"
+
+ elif [[ "${arg}" == "test.compile" ]] ; then
+ mvn_args="test-compile"
+
+ elif [[ "${arg}" == "gatkdocs" ]] ; then
+ local_repo="sitetemprepo"
+ mvn_args="install -Dmaven.repo.local=${local_repo} -Ddisable.queue && mvn site -Dmaven.repo.local=${local_repo} -Ddisable.queue"
+
+ elif [[ "${arg}" == "package.gatk.full" ]] ; then
+ mvn_args="package '-P!private,!queue'"
+
+ elif [[ "${arg}" == "package.gatk.all" ]] ; then
+ mvn_args="package '-P!queue'"
+
+ elif [[ "${arg}" == "package.queue.full" ]] ; then
+ mvn_args="package '-P!private'"
+
+ elif [[ "${arg}" == "package.queue.all" ]] ; then
+ mvn_args="package"
+
+# elif [[ "${arg}" == "release.gatk.full" ]] ; then
+# mvn_args="package '-P!private,!queue'"
+# post_script=" && private/src/main/scripts/shell/copy_release.sh public/gatk-package/target/GenomeAnalysisTK-*.tar.bz2"
+
+# elif [[ "${arg}" == "release.queue.full" ]] ; then
+# mvn_args="package '-P!private'"
+# post_script=" && private/src/main/scripts/shell/copy_release.sh public/queue-package/target/Queue-*.tar.bz2"
+
+ elif [[ "${arg}" == "build-picard-private" ]] ; then
+ mvn_args="mvn install -f private/picard-maven/pom.xml"
+
+ # TODO: clover support
+ # see ant and maven docs for clover:
+ # https://confluence.atlassian.com/display/CLOVER/1.+QuickStart+Guide
+ # https://confluence.atlassian.com/display/CLOVER/Clover-for-Maven+2+and+3+User%27s+Guide
+ #
+ #elif [[ "${arg}" == "clover.report" ]] ; then
+ # mvn_args=...
+ #
+ #elif [[ "${arg}" == "with.clover" ]] ; then
+ # mvn_args=...
+
+ # TODO: This runs *all* commit tests, including the few on Queue.
+ elif [[ "${arg}" == "gatkfull.binary.release.tests" ]] ; then
+ local_repo="sitetemprepo"
+ mvn_args="install -Dmaven.repo.local=${local_repo} && mvn verify"
+ mvn_args="${mvn_args} -Dmaven.repo.local=${local_repo}"
+ mvn_args="${mvn_args} -Dgatk.packagetests.enabled=true"
+ mvn_args="${mvn_args} -Dgatk.packagecommittests.skipped=false"
+
+ # TODO: This runs only the queue tests (full, non-dry run), but not the commit tests for Queue.
+ elif [[ "${arg}" == "queuefull.binary.release.tests" ]] ; then
+ local_repo="sitetemprepo"
+ mvn_args="install -Dmaven.repo.local=${local_repo} && mvn verify"
+ mvn_args="${mvn_args} -Dmaven.repo.local=${local_repo}"
+ mvn_args="${mvn_args} -Dgatk.packagetests.enabled=true"
+ mvn_args="${mvn_args} -Dgatk.packagequeuetests.skipped=false"
+ mvn_args="${mvn_args} -Dgatk.queuetests.run=true"
+
+ elif [[ "${arg}" == "committests" ]] ; then
+ mvn_args="verify -Dgatk.committests.skipped=false"
+
+ elif [[ "${arg}" == "test" ]] ; then
+ mvn_args="test -Dgatk.unittests.skipped=false"
+
+ elif [[ "${arg}" == "unittest" ]] ; then
+ mvn_args="test -Dgatk.unittests.skipped=false"
+
+ elif [[ "${arg}" == "integrationtest" ]] ; then
+ mvn_args="verify -Dgatk.integrationtests.skipped=false"
+
+ elif [[ "${arg}" == "largescaletest" ]] ; then
+ mvn_args="verify -Dgatk.largescaletests.skipped=false"
+
+ elif [[ "${arg}" == "knowledgebasetest" ]] ; then
+ mvn_args="verify -Dgatk.knowledgebasetests.skipped=false"
+
+ elif [[ "${arg}" == "queuetest" ]] ; then
+ mvn_args="verify -Dgatk.queuetests.skipped=false"
+
+ elif [[ "${arg}" == "queuetestrun" ]] ; then
+ mvn_args="verify -Dgatk.queuetests.skipped=false -Dgatk.queuetests.run=true"
+
+ elif [[ "${arg}" == "fasttest" ]] ; then
+ mvn_args="verify -Dgatk.committests.skipped=false -pl private/gatk-tools-private -am -Dresource.bundle.skip=true"
+
+ else
+ unknown_args="${unknown_args} \"${arg}\""
+
+ fi
+
+ fi
+
+done
+
+mvn_cmd=
+if [[ "${mvn_clean}" != "" ]] ; then
+ if [[ "${mvn_args}" != "" ]] ; then
+ mvn_cmd="mvn ${mvn_clean} && mvn ${mvn_args}"
+ else
+ mvn_cmd="mvn ${mvn_clean}"
+ fi
+else
+ mvn_cmd="mvn ${mvn_args}"
+fi
+
+if [[ "${unknown_args}" != "" ]] ; then
+ echo "Unrecognized arguments:${unknown_args}" >&2
+
+else
+ echo "Equivalent maven command"
+ echo "${mvn_cmd}${mvn_properties}${post_script}"
+
+ if [[ "${run_type}" != "dry" ]] ; then
+ sh -c "${mvn_cmd}${mvn_properties}${post_script}"
+ fi
+
+fi
diff --git a/intellij_example.tar.bz2 b/intellij_example.tar.bz2
new file mode 100644
index 0000000..bce1604
Binary files /dev/null and b/intellij_example.tar.bz2 differ
diff --git a/licensing/private_license.txt b/licensing/private_license.txt
new file mode 100644
index 0000000..a9d3904
--- /dev/null
+++ b/licensing/private_license.txt
@@ -0,0 +1,48 @@
+By downloading the PROGRAM you agree to the following terms of use:
+
+BROAD INSTITUTE
+SOFTWARE LICENSE AGREEMENT
+FOR ACADEMIC NON-COMMERCIAL RESEARCH PURPOSES ONLY
+
+This Agreement is made between the Broad Institute, Inc. with a principal address at 415 Main Street, Cambridge, MA 02142 (“BROAD”) and the LICENSEE and is effective at the date the downloading is completed (“EFFECTIVE DATE”).
+
+WHEREAS, LICENSEE desires to license the PROGRAM, as defined hereinafter, and BROAD wishes to have this PROGRAM utilized in the public interest, subject only to the royalty-free, nonexclusive, nontransferable license rights of the United States Government pursuant to 48 CFR 52.227-14; and
+WHEREAS, LICENSEE desires to license the PROGRAM and BROAD desires to grant a license on the following terms and conditions.
+NOW, THEREFORE, in consideration of the promises and covenants made herein, the parties hereto agree as follows:
+
+1. DEFINITIONS
+1.1 PROGRAM shall mean copyright in the object code and source code known as GATK3 and related documentation, if any, as they exist on the EFFECTIVE DATE and can be downloaded from http://www.broadinstitute.org/gatk on the EFFECTIVE DATE.
+
+2. LICENSE
+2.1 Grant. Subject to the terms of this Agreement, BROAD hereby grants to LICENSEE, solely for academic non-commercial research purposes, a non-exclusive, non-transferable license to: (a) download, execute and display the PROGRAM and (b) create bug fixes and modify the PROGRAM. LICENSEE hereby automatically grants to BROAD a non-exclusive, royalty-free, irrevocable license to any LICENSEE bug fixes or modifications to the PROGRAM with unlimited rights to sublicense and/or distribute. LI [...]
+The LICENSEE may apply the PROGRAM in a pipeline to data owned by users other than the LICENSEE and provide these users the results of the PROGRAM provided LICENSEE does so for academic non-commercial purposes only. For clarification purposes, academic sponsored research is not a commercial use under the terms of this Agreement.
+2.2 No Sublicensing or Additional Rights. LICENSEE shall not sublicense or distribute the PROGRAM, in whole or in part, without prior written permission from BROAD. LICENSEE shall ensure that all of its users agree to the terms of this Agreement. LICENSEE further agrees that it shall not put the PROGRAM on a network, server, or other similar technology that may be accessed by anyone other than the LICENSEE and its employees and users who have agreed to the terms of this agreement.
+2.3 License Limitations. Nothing in this Agreement shall be construed to confer any rights upon LICENSEE by implication, estoppel, or otherwise to any computer software, trademark, intellectual property, or patent rights of BROAD, or of any other entity, except as expressly granted herein. LICENSEE agrees that the PROGRAM, in whole or part, shall not be used for any commercial purpose, including without limitation, as the basis of a commercial software or hardware product or to provide s [...]
+
+3. PHONE-HOME FEATURE
+LICENSEE expressly acknowledges that the PROGRAM contains an embedded automatic reporting system (“PHONE-HOME”) which is enabled by default upon download. Unless LICENSEE requests disablement of PHONE-HOME, LICENSEE agrees that BROAD may collect limited information transmitted by PHONE-HOME regarding LICENSEE and its use of the PROGRAM. Such information shall include LICENSEE’S user identification, version number of the PROGRAM and tools being run, mode of analysis employed, and any err [...]
+
+4. OWNERSHIP OF INTELLECTUAL PROPERTY
+LICENSEE acknowledges that title to the PROGRAM shall remain with BROAD. The PROGRAM is marked with the following BROAD copyright notice and notice of attribution to contributors. LICENSEE shall retain such notice on all copies. LICENSEE agrees to include appropriate attribution if any results obtained from use of the PROGRAM are included in any publication.
+Copyright 2012-2014 Broad Institute, Inc.
+Notice of attribution: The GATK3 program was made available through the generosity of Medical and Population Genetics program at the Broad Institute, Inc.
+LICENSEE shall not use any trademark or trade name of BROAD, or any variation, adaptation, or abbreviation, of such marks or trade names, or any names of officers, faculty, students, employees, or agents of BROAD except as states above for attribution purposes.
+
+5. INDEMNIFICATION
+LICENSEE shall indemnify, defend, and hold harmless BROAD, and their respective officers, faculty, students, employees, associated investigators and agents, and their respective successors, heirs and assigns, (Indemnitees), against any liability, damage, loss, or expense (including reasonable attorneys fees and expenses) incurred by or imposed upon any of the Indemnitees in connection with any claims, suits, actions, demands or judgments arising out of any theory of liability (including, [...]
+
+6. NO REPRESENTATIONS OR WARRANTIES
+THE PROGRAM IS DELIVERED AS IS. BROAD MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE PROGRAM OR THE COPYRIGHT, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, WHETHER OR NOT DISCOVERABLE. BROAD EXTENDS NO WARRANTIES OF ANY KIND AS TO PROGRAM CONFORMITY WITH WHATEVER USER MANUALS OR OTHER LITERATURE MAY BE ISSUED FROM TIME TO TIME.
+IN NO EVENT SHALL BROAD OR ITS RESPECTIVE DIRECTORS, OFFICERS, EMPLOYEES, AFFILIATED INVESTIGATORS AND AFFILIATES BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING, WITHOUT LIMITATION, ECONOMIC DAMAGES OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER BROAD SHALL BE ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE POSSIBILITY OF THE FOREGOING.
+
+7. ASSIGNMENT
+This Agreement is personal to LICENSEE and any rights or obligations assigned by LICENSEE without the prior written consent of BROAD shall be null and void.
+
+8. MISCELLANEOUS
+8.1 Export Control. LICENSEE gives assurance that it will comply with all United States export control laws and regulations controlling the export of the PROGRAM, including, without limitation, all Export Administration Regulations of the United States Department of Commerce. Among other things, these laws and regulations prohibit, or require a license for, the export of certain types of software to specified countries.
+8.2 Termination. LICENSEE shall have the right to terminate this Agreement for any reason upon prior written notice to BROAD. If LICENSEE breaches any provision hereunder, and fails to cure such breach within thirty (30) days, BROAD may terminate this Agreement immediately. Upon termination, LICENSEE shall provide BROAD with written assurance that the original and all copies of the PROGRAM have been destroyed, except that, upon prior written authorization from BROAD, LICENSEE may retain [...]
+8.3 Survival. The following provisions shall survive the expiration or termination of this Agreement: Articles 1, 3, 4, 5 and Sections 2.2, 2.3, 7.3, and 7.4.
+8.4 Notice. Any notices under this Agreement shall be in writing, shall specifically refer to this Agreement, and shall be sent by hand, recognized national overnight courier, confirmed facsimile transmission, confirmed electronic mail, or registered or certified mail, postage prepaid, return receipt requested. All notices under this Agreement shall be deemed effective upon receipt.
+8.5 Amendment and Waiver; Entire Agreement. This Agreement may be amended, supplemented, or otherwise modified only by means of a written instrument signed by all parties. Any waiver of any rights or failure to act in a specific instance shall relate only to such instance and shall not be construed as an agreement to waive any rights or fail to act in any other instance, whether or not similar. This Agreement constitutes the entire agreement among the parties with respect to its subject [...]
+8.6 Binding Effect; Headings. This Agreement shall be binding upon and inure to the benefit of the parties and their respective permitted successors and assigns. All headings are for convenience only and shall not affect the meaning of any provision of this Agreement.
+8.7 Governing Law. This Agreement shall be construed, governed, interpreted and applied in accordance with the internal laws of the Commonwealth of Massachusetts, U.S.A., without regard to conflict of laws principles.
diff --git a/licensing/protected_license.txt b/licensing/protected_license.txt
new file mode 100644
index 0000000..a9d3904
--- /dev/null
+++ b/licensing/protected_license.txt
@@ -0,0 +1,48 @@
+By downloading the PROGRAM you agree to the following terms of use:
+
+BROAD INSTITUTE
+SOFTWARE LICENSE AGREEMENT
+FOR ACADEMIC NON-COMMERCIAL RESEARCH PURPOSES ONLY
+
+This Agreement is made between the Broad Institute, Inc. with a principal address at 415 Main Street, Cambridge, MA 02142 (“BROAD”) and the LICENSEE and is effective at the date the downloading is completed (“EFFECTIVE DATE”).
+
+WHEREAS, LICENSEE desires to license the PROGRAM, as defined hereinafter, and BROAD wishes to have this PROGRAM utilized in the public interest, subject only to the royalty-free, nonexclusive, nontransferable license rights of the United States Government pursuant to 48 CFR 52.227-14; and
+WHEREAS, LICENSEE desires to license the PROGRAM and BROAD desires to grant a license on the following terms and conditions.
+NOW, THEREFORE, in consideration of the promises and covenants made herein, the parties hereto agree as follows:
+
+1. DEFINITIONS
+1.1 PROGRAM shall mean copyright in the object code and source code known as GATK3 and related documentation, if any, as they exist on the EFFECTIVE DATE and can be downloaded from http://www.broadinstitute.org/gatk on the EFFECTIVE DATE.
+
+2. LICENSE
+2.1 Grant. Subject to the terms of this Agreement, BROAD hereby grants to LICENSEE, solely for academic non-commercial research purposes, a non-exclusive, non-transferable license to: (a) download, execute and display the PROGRAM and (b) create bug fixes and modify the PROGRAM. LICENSEE hereby automatically grants to BROAD a non-exclusive, royalty-free, irrevocable license to any LICENSEE bug fixes or modifications to the PROGRAM with unlimited rights to sublicense and/or distribute. LI [...]
+The LICENSEE may apply the PROGRAM in a pipeline to data owned by users other than the LICENSEE and provide these users the results of the PROGRAM provided LICENSEE does so for academic non-commercial purposes only. For clarification purposes, academic sponsored research is not a commercial use under the terms of this Agreement.
+2.2 No Sublicensing or Additional Rights. LICENSEE shall not sublicense or distribute the PROGRAM, in whole or in part, without prior written permission from BROAD. LICENSEE shall ensure that all of its users agree to the terms of this Agreement. LICENSEE further agrees that it shall not put the PROGRAM on a network, server, or other similar technology that may be accessed by anyone other than the LICENSEE and its employees and users who have agreed to the terms of this agreement.
+2.3 License Limitations. Nothing in this Agreement shall be construed to confer any rights upon LICENSEE by implication, estoppel, or otherwise to any computer software, trademark, intellectual property, or patent rights of BROAD, or of any other entity, except as expressly granted herein. LICENSEE agrees that the PROGRAM, in whole or part, shall not be used for any commercial purpose, including without limitation, as the basis of a commercial software or hardware product or to provide s [...]
+
+3. PHONE-HOME FEATURE
+LICENSEE expressly acknowledges that the PROGRAM contains an embedded automatic reporting system (“PHONE-HOME”) which is enabled by default upon download. Unless LICENSEE requests disablement of PHONE-HOME, LICENSEE agrees that BROAD may collect limited information transmitted by PHONE-HOME regarding LICENSEE and its use of the PROGRAM. Such information shall include LICENSEE’S user identification, version number of the PROGRAM and tools being run, mode of analysis employed, and any err [...]
+
+4. OWNERSHIP OF INTELLECTUAL PROPERTY
+LICENSEE acknowledges that title to the PROGRAM shall remain with BROAD. The PROGRAM is marked with the following BROAD copyright notice and notice of attribution to contributors. LICENSEE shall retain such notice on all copies. LICENSEE agrees to include appropriate attribution if any results obtained from use of the PROGRAM are included in any publication.
+Copyright 2012-2014 Broad Institute, Inc.
+Notice of attribution: The GATK3 program was made available through the generosity of Medical and Population Genetics program at the Broad Institute, Inc.
+LICENSEE shall not use any trademark or trade name of BROAD, or any variation, adaptation, or abbreviation, of such marks or trade names, or any names of officers, faculty, students, employees, or agents of BROAD except as states above for attribution purposes.
+
+5. INDEMNIFICATION
+LICENSEE shall indemnify, defend, and hold harmless BROAD, and their respective officers, faculty, students, employees, associated investigators and agents, and their respective successors, heirs and assigns, (Indemnitees), against any liability, damage, loss, or expense (including reasonable attorneys fees and expenses) incurred by or imposed upon any of the Indemnitees in connection with any claims, suits, actions, demands or judgments arising out of any theory of liability (including, [...]
+
+6. NO REPRESENTATIONS OR WARRANTIES
+THE PROGRAM IS DELIVERED AS IS. BROAD MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE PROGRAM OR THE COPYRIGHT, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, WHETHER OR NOT DISCOVERABLE. BROAD EXTENDS NO WARRANTIES OF ANY KIND AS TO PROGRAM CONFORMITY WITH WHATEVER USER MANUALS OR OTHER LITERATURE MAY BE ISSUED FROM TIME TO TIME.
+IN NO EVENT SHALL BROAD OR ITS RESPECTIVE DIRECTORS, OFFICERS, EMPLOYEES, AFFILIATED INVESTIGATORS AND AFFILIATES BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING, WITHOUT LIMITATION, ECONOMIC DAMAGES OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER BROAD SHALL BE ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE POSSIBILITY OF THE FOREGOING.
+
+7. ASSIGNMENT
+This Agreement is personal to LICENSEE and any rights or obligations assigned by LICENSEE without the prior written consent of BROAD shall be null and void.
+
+8. MISCELLANEOUS
+8.1 Export Control. LICENSEE gives assurance that it will comply with all United States export control laws and regulations controlling the export of the PROGRAM, including, without limitation, all Export Administration Regulations of the United States Department of Commerce. Among other things, these laws and regulations prohibit, or require a license for, the export of certain types of software to specified countries.
+8.2 Termination. LICENSEE shall have the right to terminate this Agreement for any reason upon prior written notice to BROAD. If LICENSEE breaches any provision hereunder, and fails to cure such breach within thirty (30) days, BROAD may terminate this Agreement immediately. Upon termination, LICENSEE shall provide BROAD with written assurance that the original and all copies of the PROGRAM have been destroyed, except that, upon prior written authorization from BROAD, LICENSEE may retain [...]
+8.3 Survival. The following provisions shall survive the expiration or termination of this Agreement: Articles 1, 3, 4, 5 and Sections 2.2, 2.3, 7.3, and 7.4.
+8.4 Notice. Any notices under this Agreement shall be in writing, shall specifically refer to this Agreement, and shall be sent by hand, recognized national overnight courier, confirmed facsimile transmission, confirmed electronic mail, or registered or certified mail, postage prepaid, return receipt requested. All notices under this Agreement shall be deemed effective upon receipt.
+8.5 Amendment and Waiver; Entire Agreement. This Agreement may be amended, supplemented, or otherwise modified only by means of a written instrument signed by all parties. Any waiver of any rights or failure to act in a specific instance shall relate only to such instance and shall not be construed as an agreement to waive any rights or fail to act in any other instance, whether or not similar. This Agreement constitutes the entire agreement among the parties with respect to its subject [...]
+8.6 Binding Effect; Headings. This Agreement shall be binding upon and inure to the benefit of the parties and their respective permitted successors and assigns. All headings are for convenience only and shall not affect the meaning of any provision of this Agreement.
+8.7 Governing Law. This Agreement shall be construed, governed, interpreted and applied in accordance with the internal laws of the Commonwealth of Massachusetts, U.S.A., without regard to conflict of laws principles.
diff --git a/licensing/public_license.txt b/licensing/public_license.txt
new file mode 100644
index 0000000..648ec8f
--- /dev/null
+++ b/licensing/public_license.txt
@@ -0,0 +1,22 @@
+Copyright (c) 2012 The Broad Institute
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..8488cf8
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,756 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!--
+ This pom is the aggregator for all gatk poms
+ See also:
+ http://maven.apache.org/pom.html#Inheritance_v
+ http://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Project_Inheritance_vs_Project_Aggregation
+ http://stackoverflow.com/questions/1992213/maven-parent-pom-vs-modules-pom
+ -->
+
+ <parent>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-root</artifactId>
+ <version>3.3</version>
+ <relativePath>public/gatk-root</relativePath>
+ </parent>
+
+ <artifactId>gatk-aggregator</artifactId>
+ <packaging>pom</packaging>
+ <name>GATK Aggregator</name>
+
+ <modules>
+ <module>public</module>
+ <!-- private & protected optionally enabled as profiles -->
+ </modules>
+
+ <properties>
+ <gatk.basedir>${project.basedir}</gatk.basedir>
+ <resource.bundle.path>GATKText.properties</resource.bundle.path>
+ <resource.bundle.skip>false</resource.bundle.skip>
+ <!-- TODO: Need a better a way to say "don't include hidden" by default -->
+ <gatkdocs.include.hidden>-build-timestamp "${maven.build.timestamp}"</gatkdocs.include.hidden>
+
+ <!--
+ Phases of the build that may be disabled to speed up compilation.
+ -->
+ <gatk.jar.phase>package</gatk.jar.phase>
+ <gatk.generate-resources.phase>generate-resources</gatk.generate-resources.phase>
+ <gatk.process-resources.phase>process-resources</gatk.process-resources.phase>
+ <gatk.process-test-resources.phase>process-test-resources</gatk.process-test-resources.phase>
+
+ <!--
+ Package tests ensure the consistency of the packaged / shaded jars.
+ It runs the tests where the monolithic jar is the only dependency on the classpath.
+ -->
+ <gatk.packagecommittests.skipped>true</gatk.packagecommittests.skipped>
+ <gatk.packageunittests.skipped>${gatk.packagecommittests.skipped}</gatk.packageunittests.skipped>
+ <gatk.packageintegrationtests.skipped>${gatk.packagecommittests.skipped}</gatk.packageintegrationtests.skipped>
+ <gatk.packagequeuetests.skipped>${gatk.packagecommittests.skipped}</gatk.packagequeuetests.skipped>
+ <gatk.packagelargescaletests.skipped>true</gatk.packagelargescaletests.skipped>
+ <gatk.packageknowledgebasetests.skipped>true</gatk.packageknowledgebasetests.skipped>
+
+ <!--
+ Serial tests use the test jars to run tests, such that all tests are run from a single TestNG invocation.
+ This is different that the invoker, that runs the test classes from the filesystem, but pointing at the packaged JAR files.
+ TODO: Currently, all tests run within each package, since packages already collect dependencies for shading an uber jar.
+ TODO: Should there be another level up of tests, possibly running "all tests" via this aggregator level?
+ TODO: If that require the aggregator to be dependent on the child dependencies, perhaps a better approach might be another monolithic test project.
+ -->
+ <gatk.serialcommittests.skipped>true</gatk.serialcommittests.skipped>
+ <gatk.serialunittests.skipped>${gatk.serialcommittests.skipped}</gatk.serialunittests.skipped>
+ <gatk.serialintegrationtests.skipped>${gatk.serialcommittests.skipped}</gatk.serialintegrationtests.skipped>
+ <gatk.serialqueuetests.skipped>${gatk.serialcommittests.skipped}</gatk.serialqueuetests.skipped>
+ <gatk.seriallargescaletests.skipped>true</gatk.seriallargescaletests.skipped>
+ <gatk.serialknowledgebasetests.skipped>true</gatk.serialknowledgebasetests.skipped>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.sun</groupId>
+ <artifactId>tools</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <!-- Plugin configuration -->
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-clean-plugin</artifactId>
+ <configuration>
+ <filesets>
+ <!--
+ TODO: Once GATKDoclet stops hard coding paths, we remove this and leave
+ TODO: it to the standard maven conventions to clean up for us
+ -->
+ <fileset>
+ <directory>gatkdocs</directory>
+ </fileset>
+ <fileset>
+ <directory>${basedir}</directory>
+ <includes>
+ <include>javadoc.sh</include>
+ <include>options</include>
+ <include>packages</include>
+ </includes>
+ </fileset>
+ <!--
+ Shade dumps this temp file in basedir, with no good way to reconfigure.
+ https://jira.codehaus.org/browse/MSHADE-145
+ -->
+ <fileset>
+ <directory>${basedir}</directory>
+ <includes>
+ <include>dependency-reduced-pom.xml</include>
+ </includes>
+ </fileset>
+ </filesets>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-direct-dependencies</id>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <phase>none</phase>
+ <!--
+ NOTE: Shade include filters do NOT include transient dependencies, only the class directly listed.
+
+ Thus to fully include all the classes in packages, we must:
+ 1) List the artifacts we want shaded as direct dependencies
+ 2) Run the unpack direct dependencies into the classes directory
+ 3) Shade the classes directory as we normally would.
+ -->
+ <configuration>
+ <excludeTransitive>true</excludeTransitive>
+ <outputDirectory>${project.build.outputDirectory}</outputDirectory>
+ <includeTypes>jar</includeTypes>
+ <includeScope>runtime</includeScope>
+ <!-- Don't unjar the resource bundle, so that shade's AppendingTransformer can merge -->
+ <excludes>${resource.bundle.path}</excludes>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- TODO: Change the ResourceBundleExtractorDoclet to not require log4j.properties file -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-resources</id>
+ <goals>
+ <goal>resources</goal>
+ </goals>
+ <phase>${gatk.process-resources.phase}</phase>
+ </execution>
+ <execution>
+ <id>default-testResources</id>
+ <goals>
+ <goal>testResources</goal>
+ </goals>
+ <phase>${gatk.process-test-resources.phase}</phase>
+ </execution>
+ <execution>
+ <id>copy-resource-bundle-log4j</id>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <phase>none</phase>
+ <configuration>
+ <!--
+ Just before running the resource bundle generation, copy a simple log4j
+ config file to the apidocs execution directory, so that logging prints out.
+ -->
+ <outputDirectory>${project.reporting.outputDirectory}/apidocs</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${gatk.basedir}/gatk-utils/src/main/config/org/broadinstitute/gatk/utils/help</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>extract-resource-bundle</id>
+ <goals>
+ <goal>javadoc</goal>
+ </goals>
+ <phase>none</phase>
+ <configuration>
+ <!-- Allow skipping for "fasttest" -->
+ <skip>${resource.bundle.skip}</skip>
+ <doclet>org.broadinstitute.gatk.utils.help.ResourceBundleExtractorDoclet</doclet>
+ <!-- Required as doclet uses reflection to access classes for documentation, instead of source java-->
+ <docletPath>${project.build.outputDirectory}</docletPath>
+ <docletArtifact>
+ <groupId>${project.groupId}</groupId>
+ <!-- TODO: THIS IS SUPPOSED TO BE GATK-UTILS! -->
+ <artifactId>gatk-tools-public</artifactId>
+ <version>${project.version}</version>
+ </docletArtifact>
+ <maxmemory>2g</maxmemory>
+ <useStandardDocletOptions>false</useStandardDocletOptions>
+ <quiet>true</quiet>
+ <additionalparam>-build-timestamp "${maven.build.timestamp}" -absolute-version ${build.version} -out "${project.build.outputDirectory}/${resource.bundle.path}"</additionalparam>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <proc>none</proc>
+ <annotationProcessors>
+ <annotationProcessor>com.google.java.contract.core.apt.AnnotationProcessor</annotationProcessor>
+ </annotationProcessors>
+ </configuration>
+ <executions>
+ <execution>
+ <id>default-compile</id>
+ <phase>none</phase>
+ </execution>
+ <execution>
+ <id>default-testCompile</id>
+ <phase>none</phase>
+ </execution>
+ <!--
+ Explicit package-info creation to match existing ant output.
+ -->
+ <execution>
+ <id>compile-package-info</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <compilerArgs>
+ <arg>-Xpkginfo:always</arg>
+ </compilerArgs>
+ <includes>
+ <include>**/package-info.java</include>
+ </includes>
+ </configuration>
+ </execution>
+ <!--
+ TODO: Currently disabled in build.xml. Here as well.
+ <execution>
+ <id>compile-annotations</id>
+ <phase>compile</phase>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <proc>only</proc>
+ </configuration>
+ </execution>
+ -->
+ <execution>
+ <id>compile-java</id>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <!--
+ Package info is supposed to be in source:
+ http://maven.apache.org/plugins/maven-javadoc-plugin/examples/javadoc-resources.html
+ But maven-compile-plugin doesn't auto exclude these:
+ https://jira.codehaus.org/browse/MCOMPILER-205?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=326505#comment-326505
+ So, explicitly exclude them
+ -->
+ <excludes>
+ <exclude>**/package-info.java</exclude>
+ </excludes>
+ </configuration>
+ </execution>
+ <!--
+ TODO: Currently disabled in build.xml. Here as well.
+ <execution>
+ <id>testCompile-annotations</id>
+ <phase>test-compile</phase>
+ <goals>
+ <goal>testCompile</goal>
+ </goals>
+ <configuration>
+ <proc>only</proc>
+ </configuration>
+ </execution>
+ -->
+ <execution>
+ <id>testCompile-java</id>
+ <goals>
+ <goal>testCompile</goal>
+ </goals>
+ <phase>test-compile</phase>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.scala-tools</groupId>
+ <artifactId>maven-scala-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>compile</goal>
+ <goal>testCompile</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-jar</id>
+ <phase>${gatk.jar.phase}</phase>
+ </execution>
+ <execution>
+ <id>test-jar</id>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ <phase>${gatk.jar.phase}</phase>
+ <configuration>
+ <skipIfEmpty>true</skipIfEmpty>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>gatk-executable</id>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <phase>none</phase>
+ <configuration>
+ <minimizeJar>true</minimizeJar>
+ <artifactSet>
+ <excludes>
+ <exclude>org.broadinstitute.gatk:gsalib:tar.gz:*</exclude>
+ <exclude>org.broadinstitute.gatk:*:tar.bz2:example-resources</exclude>
+ </excludes>
+ </artifactSet>
+ <filters>
+ <!--
+ NOTE: Removing cofoja's annotation service to allow "javac -cp GenomeAnalysisTK.jar ..." without
+ needing an additional -proc:none argument. Using *:* to catch shaded GATK in Queue package.
+ -->
+ <filter>
+ <artifact>*:*</artifact>
+ <excludes>
+ <exclude>META-INF/services/javax.annotation.processing.Processor</exclude>
+ </excludes>
+ </filter>
+ </filters>
+ <transformers>
+ <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+ <manifestEntries>
+ <Main-Class>${app.main.class}</Main-Class>
+ </manifestEntries>
+ </transformer>
+ <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+ <resource>${resource.bundle.path}</resource>
+ </transformer>
+ </transformers>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>example-resources</id>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <phase>none</phase>
+ <configuration>
+ <descriptors>
+ <descriptor>src/main/assembly/example-resources.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ <execution>
+ <id>binary-dist</id>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <phase>none</phase>
+ <configuration>
+ <descriptors>
+ <descriptor>src/main/assembly/binary-dist.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>com.pyx4j</groupId>
+ <artifactId>maven-junction-plugin</artifactId>
+ <executions>
+ <!--
+ HACK: Adding the source directory via build-helper-maven-plugin doesn't work with IntelliJ.
+ Add compatibility link from public's extensions source code to target/generated-sources.
+ see: http://wiki.jetbrains.net/intellij/Maven_FAQ
+ -->
+ <execution>
+ <id>link-extensions-sources</id>
+ <goals>
+ <goal>link</goal>
+ </goals>
+ <phase>none</phase>
+ <configuration>
+ <links>
+ <link>
+ <dst>${project.build.directory}/generated-sources/gatk-queue-extensions-public-src-main-scala</dst>
+ <src>${gatk.basedir}/public/gatk-queue-extensions-public/src/main/scala</src>
+ </link>
+ </links>
+ </configuration>
+ </execution>
+ <execution>
+ <id>link-binary-jar</id>
+ <goals>
+ <goal>link</goal>
+ </goals>
+ <phase>none</phase>
+ <configuration>
+ <links>
+ <link>
+ <dst>${gatk.basedir}/target/${gatk.binary-dist.name}.${project.packaging}</dst>
+ <src>${project.build.directory}/${project.build.finalName}.${project.packaging}</src>
+ </link>
+ </links>
+ </configuration>
+ </execution>
+ <execution>
+ <id>link-git-release</id>
+ <goals>
+ <goal>link</goal>
+ </goals>
+ <phase>none</phase>
+ <configuration>
+ <links>
+ <link>
+ <dst>${project.build.directory}/${gatk.binary-dist.name}-${build.version}.tar.bz2</dst>
+ <src>${project.build.directory}/${project.build.finalName}-binary-dist.tar.bz2</src>
+ </link>
+ </links>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <configuration>
+ <skipInvocation>true</skipInvocation>
+ <debug>false</debug>
+ <pom>${gatk.basedir}/public/package-tests/pom.xml</pom>
+ <noLog>true</noLog>
+ <streamLogs>true</streamLogs>
+ <localRepositoryPath>${gatk.basedir}/${maven.repo.local}</localRepositoryPath>
+ <properties>
+ <test>${test}</test>
+ <it.test>${it.test}</it.test>
+ <skip>false</skip>
+ <maven.test.skip>false</maven.test.skip>
+ <gatk.packagetests.artifactId>${gatk.packagetests.artifactId}</gatk.packagetests.artifactId>
+ <gatk.packagetests.testClasses>${project.build.testOutputDirectory}</gatk.packagetests.testClasses>
+ <gatk.packagetests.basedir>${project.basedir}</gatk.packagetests.basedir>
+ <gatk.queuetests.run>${gatk.queuetests.run}</gatk.queuetests.run>
+ <maven.surefire.debug>${maven.surefire.debug}</maven.surefire.debug>
+ <maven.failsafe.debug>${maven.failsafe.debug}</maven.failsafe.debug>
+ </properties>
+ <!--
+ To allow using separated integration-test and verify, each execution must use a separate reportsDirectory.
+
+ Otherwise, when an empty "pipeline test" later runs on an IntegrationTest class,
+ it overwrites the results of the previous invocation always with a zero exit status.
+
+ Mixing in the test name into the reportsDirectory also avoids collisions, when different maven jobs run tests in parallel.
+
+ Similarly generating unique failsafe summary reports to avoid collisions.
+ -->
+ </configuration>
+ <executions>
+ <execution>
+ <id>package-unittests</id>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <reportsDirectory>${project.build.directory}/invoker-reports/unit/${test}</reportsDirectory>
+ <skipInvocation>${gatk.packageunittests.skipped}</skipInvocation>
+ <properties>
+ <unittests.profile.enabled>true</unittests.profile.enabled>
+ <gatk.packageunittests.skipped>${gatk.packageunittests.skipped}</gatk.packageunittests.skipped>
+ </properties>
+ </configuration>
+ </execution>
+ <execution>
+ <id>package-integrationtests</id>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ <reportsDirectory>${project.build.directory}/invoker-reports/integration/${it.test}</reportsDirectory>
+ <skipInvocation>${gatk.packageintegrationtests.skipped}</skipInvocation>
+ <properties>
+ <integrationtests.profile.enabled>true</integrationtests.profile.enabled>
+ <gatk.packageintegrationtests.skipped>${gatk.packageintegrationtests.skipped}</gatk.packageintegrationtests.skipped>
+ </properties>
+ </configuration>
+ </execution>
+ <execution>
+ <id>package-queuetests</id>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ <reportsDirectory>${project.build.directory}/invoker-reports/queuetest/${it.test}</reportsDirectory>
+ <skipInvocation>${gatk.packagequeuetests.skipped}</skipInvocation>
+ <properties>
+ <integrationtests.profile.enabled>true</integrationtests.profile.enabled>
+ <gatk.packagequeuetests.skipped>${gatk.packagequeuetests.skipped}</gatk.packagequeuetests.skipped>
+ </properties>
+ </configuration>
+ </execution>
+ <execution>
+ <id>package-largescaletests</id>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ <reportsDirectory>${project.build.directory}/invoker-reports/largescale/${it.test}</reportsDirectory>
+ <skipInvocation>${gatk.packagelargescaletests.skipped}</skipInvocation>
+ <properties>
+ <integrationtests.profile.enabled>true</integrationtests.profile.enabled>
+ <gatk.packagelargescaletests.skipped>${gatk.packagelargescaletests.skipped}</gatk.packagelargescaletests.skipped>
+ </properties>
+ </configuration>
+ </execution>
+ <execution>
+ <id>package-knowledgebasetests</id>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ <reportsDirectory>${project.build.directory}/invoker-reports/knowledgebase/${it.test}</reportsDirectory>
+ <skipInvocation>${gatk.packageknowledgebasetests.skipped}</skipInvocation>
+ <properties>
+ <integrationtests.profile.enabled>true</integrationtests.profile.enabled>
+ <gatk.packageknowledgebasetests.skipped>${gatk.packageknowledgebasetests.skipped}</gatk.packageknowledgebasetests.skipped>
+ </properties>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <version>2.5</version>
+ <executions>
+ <execution>
+ <id>install-package</id>
+ <goals>
+ <goal>install-file</goal>
+ </goals>
+ <phase>none</phase>
+ <configuration>
+ <generatePom>true</generatePom>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${project.artifactId}</artifactId>
+ <version>${project.version}</version>
+ <packaging>${project.packaging}</packaging>
+ <file>${project.build.directory}/${project.build.finalName}.${project.packaging}</file>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+
+ <!-- Invoke plugins that always run -->
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <!--
+ TODO: Remove after 3.3+ release.
+ Until then, will clean out symbolic links from users who download public/protected.
+ Perhaps leave the script even longer.
+ -->
+ <id>delete-mavens-links</id>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <phase>process-test-resources</phase>
+ <inherited>false</inherited>
+ <configuration>
+ <executable>${gatk.basedir}/public/src/main/scripts/shell/delete_maven_links.sh</executable>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-clean-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>com.google.code.sortpom</groupId>
+ <artifactId>maven-sortpom-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>package-tests</id>
+ <goals>
+ <goal>sort</goal>
+ </goals>
+ <phase>verify</phase>
+ <inherited>false</inherited>
+ <configuration>
+ <pomFile>public/package-tests/pom.xml</pomFile>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.9.1</version>
+ <reportSets>
+ <!-- By not specifying an id, shut off all default javadocs from mvn site -->
+ <reportSet>
+ <reports />
+ </reportSet>
+ <reportSet>
+ <id>generate-gatk-docs</id>
+ <reports>
+ <report>aggregate</report>
+ </reports>
+ <!-- Only generate the GATK Docs across the parent aggregation, not the children too. -->
+ <inherited>false</inherited>
+ <configuration>
+ <doclet>org.broadinstitute.gatk.utils.help.GATKDoclet</doclet>
+ <docletArtifact>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-package-distribution</artifactId>
+ <version>${project.version}</version>
+ </docletArtifact>
+ <useStandardDocletOptions>false</useStandardDocletOptions>
+ <quiet>true</quiet>
+ <show>private</show>
+ <additionalparam>-build-timestamp "${maven.build.timestamp}" -absolute-version ${build.version} ${gatkdocs.include.hidden} -settings-dir ${gatk.basedir}/settings/helpTemplates -destination-dir ${project.build.directory}/gatkdocs</additionalparam>
+ </configuration>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <profiles>
+ <!-- Optionally include protected -->
+ <profile>
+ <id>protected</id>
+ <activation>
+ <file>
+ <exists>${basedir}/protected/pom.xml</exists>
+ </file>
+ </activation>
+ <modules>
+ <module>protected</module>
+ </modules>
+ </profile>
+
+ <!-- Optionally include private -->
+ <profile>
+ <id>private</id>
+ <activation>
+ <file>
+ <exists>${basedir}/private/pom.xml</exists>
+ </file>
+ </activation>
+ <modules>
+ <module>private</module>
+ </modules>
+ </profile>
+
+ <!-- Collection of properties for use during package testing -->
+ <profile>
+ <id>packagetests-enabled</id>
+ <activation>
+ <property>
+ <name>gatk.packagetests.enabled</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <properties>
+ <maven.javadoc.skip>true</maven.javadoc.skip>
+ <gatk.generate-gatk-extensions.skipped>true</gatk.generate-gatk-extensions.skipped>
+ <gatk.jar.phase>none</gatk.jar.phase>
+ <gatk.generate-resources.phase>none</gatk.generate-resources.phase>
+ <gatk.process-resources.phase>none</gatk.process-resources.phase>
+ <gatk.process-test-resources.phase>none</gatk.process-test-resources.phase>
+ </properties>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/public/VectorPairHMM/README.md b/public/VectorPairHMM/README.md
new file mode 100644
index 0000000..ad40055
--- /dev/null
+++ b/public/VectorPairHMM/README.md
@@ -0,0 +1,72 @@
+Implementation overview:
+Created a new Java class called VectorLoglessPairHMM which extends LoglessPairHMM and
+overrides functions from both LoglessPairHMM and PairHMM.
+1. Constructor: Call base class constructors. Then, load the native library located in this
+directory and call an init function (with suffix 'jniInitializeClassFieldsAndMachineMask') in the
+library to determine fields ids for the members of classes JNIReadDataHolder and
+JNIHaplotypeDataHolders. The native code stores the field ids (struct offsets) for the classes and
+re-uses them for subsequent computations. Optionally, the user can disable the vector
+implementation, by using the 'mask' argument (see comments for a more detailed explanation).
+2. When the library is loaded, it invokes the constructor of the class LoadTimeInitializer (because
+a global variable g_load_time_initializer is declared in the library). This constructor
+(LoadTimeInitializer.cc) can be used to perform various initializations. Currently, it initializes
+two global function pointers to point to the function implementation that is supported on the
+machine (AVX/SSE/un-vectorized) on which the program is being run. The two pointers are for float
+and double respectively. The global function pointers are declared in utils.cc and are assigned in
+the function initialize_function_pointers() defined in utils.cc and invoked from the constructor of
+LoadTimeInitializer.
+Other initializations in LoadTimeInitializer:
+* ConvertChar::init - sets some masks for the vector implementation
+* FTZ for performance
+* stat counters = 0
+* debug structs (which are never used in non-debug mode)
+This initialization is done only once for the whole program.
+3. initialize(): To initialize the region for PairHMM. Pass haplotype bases to native code through
+the JNIHaplotypeDataHolder class. Since the haplotype list is common across multiple samples in
+computeReadLikelihoods(), we can pass the haplotype bases to the native code once and re-use across
+multiple samples.
+4. computeLikelihoods(): Copies array references for readBases/quals etc to array of
+JNIReadDataHolder objects. Invokes the JNI function to perform the computation and updates the
+likelihoodMap.
+The JNI function copies the byte array references into an array of testcase structs and invokes the
+compute_full_prob function through the function pointers initialized earlier.
+The primary native function called is
+Java_org_broadinstitute_sting_utils_pairhmm_VectorLoglessPairHMM_jniComputeLikelihoods. It uses
+standard JNI calls to get and return data from/to the Java class VectorLoglessPairHMM. The last
+argument to the function is the maximum number of OpenMP threads to use while computing PairHMM in
+C++. This option is set when the native function call is made from JNILoglessPairHMM
+computeLikelihoods - currently it is set to 12 (no logical reason).
+Note: OpenMP has been disabled for now - insufficient #testcases per call to computeLikelihoods() to
+justify multi-threading.
+5. finalizeRegion(): Releases the haplotype arrays initialized in step 3 - should be called at the
+end of every region (line 351 in PairHMMLikelihoodCalculationEngine).
+
+Note: Debug code has been moved to a separate class DebugJNILoglessPairHMM.java.
+
+Compiling:
+The native library (called libVectorLoglessPairHMM.so) can be compiled with icc (Intel C compiler)
+or gcc versions >= 4.8.1 that support AVX intrinsics. By default, the make process tries to invoke
+icc. To use gcc, edit the file 'pom.xml' (in this directory) and enable the environment variables
+USE_GCC,C_COMPILER and CPP_COMPILER (edit and uncomment lines 60-62).
+Using Maven:
+Type 'mvn install' in this directory - this will build the library (by invoking 'make') and copy the
+native library to the directory
+${sting-utils.basedir}/src/main/resources/org/broadinstitute/sting/utils/pairhmm
+The GATK maven build process (when run) will bundle the library into the StingUtils jar file from
+the copied directory.
+Simple build:
+cd src/main/c++
+make
+
+Running:
+The default implementation of PairHMM is now VECTOR_LOGLESS_CACHING in HaplotypeCaller.java. To use
+the Java version, use the command line argument "--pair_hmm_implementation LOGLESS_CACHING". (see
+run.sh in src/main/c++).
+The native library is bundled with the StingUtils jar file. When HaplotypeCaller is invoked, then
+the library is unpacked from the jar file, copied to the /tmp directory (with a unique id) and
+loaded by the Java class VectorLoglessPairHMM in the constructor (if it has not been loaded
+already).
+The default library can be overridden by using the -Djava.library.path argument (see
+src/main/c++/run.sh for an example) for the JVM to pass the path to the library. If the library
+libVectorLoglessPairHMM.so can be found in java.library.path, then it is loaded and the 'packed'
+library is not used.
diff --git a/public/VectorPairHMM/pom.xml b/public/VectorPairHMM/pom.xml
new file mode 100644
index 0000000..ca08087
--- /dev/null
+++ b/public/VectorPairHMM/pom.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-root</artifactId>
+ <version>3.3</version>
+ <relativePath>../../public/gatk-root</relativePath>
+ </parent>
+
+ <artifactId>VectorPairHMM</artifactId>
+ <packaging>pom</packaging>
+ <name>Vectorized PairHMM native libraries</name>
+
+ <description>Builds a GNU/Linux x86_64 library of VectorPairHMM using icc (Intel C++ compiler). During install, copies it into gatk-utils. Neither tested nor expected to work on any other platform.</description>
+
+ <properties>
+ <sourceEncoding>UTF-8</sourceEncoding>
+ <project.build.sourceEncoding>${sourceEncoding}</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>${sourceEncoding}</project.reporting.outputEncoding>
+ <gatk.basedir>${project.basedir}/../..</gatk.basedir>
+ <gatk-utils.basedir>${gatk.basedir}/public/gatk-utils</gatk-utils.basedir>
+ <!-- Where to place the library in gatk-utils -->
+ <pairhmm.resources.directory>${gatk-utils.basedir}/src/main/resources/org/broadinstitute/gatk/utils/pairhmm</pairhmm.resources.directory>
+ </properties>
+ <build>
+ <plugins>
+ <!-- Print out the architecture - works only on GNU/Linux x86_64 systems -->
+ <!-- Neither tested nor expected to work on any other platform. -->
+ <!-- Requires icc (Intel C++ compiler) to be in your PATH. -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>display-info</goal>
+ </goals>
+ <phase>validate</phase>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Run make -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <phase>compile</phase>
+ <configuration>
+ <executable>make</executable>
+ <workingDirectory>src/main/c++</workingDirectory>
+ <environmentVariables>
+ <JRE_HOME>${java.home}</JRE_HOME>
+ <!--<USE_GCC>1</USE_GCC>-->
+ <!--<C_COMPILER>/opt/gcc-4.8.2/bin/gcc</C_COMPILER>-->
+ <!--<CPP_COMPILER>/opt/gcc-4.8.2/bin/g++</CPP_COMPILER>-->
+ <OUTPUT_DIR>${project.build.directory}</OUTPUT_DIR>
+ </environmentVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Don't actually install this artifact into the user's repo -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+
+ <!-- Copy the built library into gatk-utils -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default-install</id>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <phase>install</phase>
+ <configuration>
+ <outputDirectory>${pairhmm.resources.directory}</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${project.build.directory}</directory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- pom.xml cleanup, always sort according to the definitions in gatk-root -->
+ <plugin>
+ <groupId>com.google.code.sortpom</groupId>
+ <artifactId>maven-sortpom-plugin</artifactId>
+ <configuration>
+ <createBackupFile>false</createBackupFile>
+ <predefinedSortOrder>custom_1</predefinedSortOrder>
+ <lineSeparator>\n</lineSeparator>
+ <encoding>${sourceEncoding}</encoding>
+ <keepBlankLines>true</keepBlankLines>
+ <sortDependencies>scope</sortDependencies>
+ <nrOfIndentSpace>4</nrOfIndentSpace>
+ <expandEmptyElements>false</expandEmptyElements>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/public/VectorPairHMM/src/main/c++/.gitignore b/public/VectorPairHMM/src/main/c++/.gitignore
new file mode 100644
index 0000000..d791ffd
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/.gitignore
@@ -0,0 +1,16 @@
+.svn
+*.o
+*.so
+tests
+.deps
+hmm_Mohammad
+pairhmm-template-main
+*.swp
+*.class
+checker
+reformat
+subdir_checkout.sh
+avx/
+sse/
+triplicate.sh
+
diff --git a/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.cc b/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.cc
new file mode 100644
index 0000000..f6cdbab
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.cc
@@ -0,0 +1,205 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include "utils.h"
+#include "LoadTimeInitializer.h"
+using namespace std;
+char* LoadTimeInitializerStatsNames[] =
+{
+ "num_regions",
+ "num_reads",
+ "num_haplotypes",
+ "num_testcases",
+ "num_double_invocations",
+ "haplotype_length",
+ "readlength",
+ "product_read_length_haplotype_length",
+ "dummy"
+};
+
+LoadTimeInitializer g_load_time_initializer;
+
+LoadTimeInitializer::LoadTimeInitializer() //will be called when library is loaded
+{
+#if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__INTEL_COMPILER)
+ //compiles only with gcc >= 4.8
+ __builtin_cpu_init();
+#endif
+ ConvertChar::init();
+#ifndef DISABLE_FTZ
+ //Very important to get good performance on Intel processors
+ //Function: enabling FTZ converts denormals to 0 in hardware
+ //Denormals cause microcode to insert uops into the core causing big slowdown
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
+ //cout << "FTZ enabled - may decrease accuracy if denormal numbers encountered\n";
+#else
+ cout << "FTZ is not set - may slow down performance if denormal numbers encountered\n";
+#endif
+ //Profiling: times for compute and transfer (either bytes copied or pointers copied)
+ m_compute_time = 0;
+ m_data_transfer_time = 0;
+ m_bytes_copied = 0;
+
+ //Initialize profiling counters
+ for(unsigned i=0;i<TOTAL_NUMBER_STATS;++i)
+ {
+ m_sum_stats[i] = 0;
+ m_sum_square_stats[i] = 0;
+ m_max_stats[i] = 0;
+ m_min_stats[i] = 0xFFFFFFFFFFFFFFFFull;
+ }
+
+ //for debug dump
+ m_filename_to_fptr.clear();
+ m_written_files_set.clear();
+
+ initialize_function_pointers();
+
+ //Initialize static members of class
+ Context<float>::initializeStaticMembers();
+ Context<double>::initializeStaticMembers();
+
+ cout.flush();
+}
+
+void LoadTimeInitializer::print_profiling()
+{
+ double mean = 0;
+ double variance = 0;
+ uint64_t denominator = 1;
+ cout << "Time spent in compute_testcases "<<m_compute_time*1e-9<<"\n";
+ cout << "Time spent in data transfer (Java <--> C++) "<<m_data_transfer_time*1e-9<<"\n";
+
+ cout << "\nHC input stats\nstat_name,sum,sum_square,mean,variance,min,max\n";
+ for(unsigned i=0;i<TOTAL_NUMBER_STATS;++i)
+ {
+ cout << LoadTimeInitializerStatsNames[i];
+ cout << "," << m_sum_stats[i];
+ cout << "," << std::scientific << m_sum_square_stats[i];
+ denominator = 1;
+ switch(i)
+ {
+ case NUM_READS_IDX:
+ case NUM_HAPLOTYPES_IDX:
+ case NUM_TESTCASES_IDX:
+ denominator = m_sum_stats[NUM_REGIONS_IDX];
+ break;
+ case HAPLOTYPE_LENGTH_IDX:
+ denominator = m_sum_stats[NUM_HAPLOTYPES_IDX];
+ break;
+ case READ_LENGTH_IDX:
+ denominator = m_sum_stats[NUM_READS_IDX];
+ break;
+ case PRODUCT_READ_LENGTH_HAPLOTYPE_LENGTH_IDX:
+ denominator = m_sum_stats[NUM_TESTCASES_IDX];
+ break;
+ default:
+ denominator = 1;
+ break;
+ }
+ mean = ((double)m_sum_stats[i])/denominator;
+ cout << "," << std::scientific << mean;
+ variance = (m_sum_square_stats[i]/denominator) - (mean*mean); //E(X^2)-(E(X))^2
+ cout << "," << std::scientific << variance;
+ cout << "," << m_min_stats[i];
+ cout << "," << m_max_stats[i];
+ cout << "\n";
+ }
+ cout << "\n";
+ cout.flush();
+}
+
+void LoadTimeInitializer::debug_dump(string filename, string s, bool to_append, bool add_newline)
+{
+ map<string, ofstream*>::iterator mI = m_filename_to_fptr.find(filename);
+ ofstream* fptr = 0;
+ if(mI == m_filename_to_fptr.end())
+ {
+ m_filename_to_fptr[filename] = new ofstream();
+ fptr = m_filename_to_fptr[filename];
+ //File never seen before
+ if(m_written_files_set.find(filename) == m_written_files_set.end())
+ {
+ to_append = false;
+ m_written_files_set.insert(filename);
+ }
+ fptr->open(filename.c_str(), to_append ? ios::app : ios::out);
+ assert(fptr->is_open());
+ }
+ else
+ fptr = (*mI).second;
+ //ofstream fptr;
+ //fptr.open(filename.c_str(), to_append ? ofstream::app : ofstream::out);
+ (*fptr) << s;
+ if(add_newline)
+ (*fptr) << "\n";
+ //fptr.close();
+}
+void LoadTimeInitializer::debug_close()
+{
+ for(map<string,ofstream*>::iterator mB = m_filename_to_fptr.begin(), mE = m_filename_to_fptr.end();
+ mB != mE;mB++)
+ {
+ (*mB).second->close();
+ delete (*mB).second;
+ }
+ m_filename_to_fptr.clear();
+}
+
+void LoadTimeInitializer::dump_sandbox(testcase& tc, unsigned tc_idx, unsigned numReads, unsigned numHaplotypes)
+{
+ unsigned haplotypeLength = tc.haplen;
+ unsigned readLength = tc.rslen;
+ ofstream& dumpFptr = m_sandbox_fptr;
+ for(unsigned k=0;k<haplotypeLength;++k)
+ dumpFptr<<(char)(tc.hap[k]);
+ dumpFptr<<" ";
+ for(unsigned k=0;k<readLength;++k)
+ dumpFptr<<(char)(tc.rs[k]);
+ dumpFptr<<" ";
+ for(unsigned k=0;k<readLength;++k)
+ dumpFptr<<(char)(tc.q[k]+33);
+ dumpFptr<<" ";
+ for(unsigned k=0;k<readLength;++k)
+ dumpFptr<<(char)(tc.i[k]+33);
+ dumpFptr<<" ";
+ for(unsigned k=0;k<readLength;++k)
+ dumpFptr<<(char)(tc.d[k]+33);
+ dumpFptr<<" ";
+ for(unsigned k=0;k<readLength;++k)
+ dumpFptr<<(char)(tc.c[k]+33);
+ if(tc_idx == 0) //new region
+ dumpFptr << " "<< numReads << " "<<numHaplotypes;
+ dumpFptr<<"\n";
+}
+
+void LoadTimeInitializer::update_stat(LoadTimeInitializerStatsEnum stat_idx, uint64_t value)
+{
+ m_sum_stats[stat_idx] += value;
+ double v = value;
+ m_sum_square_stats[stat_idx] += (v*v);
+ m_max_stats[stat_idx] = std::max(m_max_stats[stat_idx], value);
+ m_min_stats[stat_idx] = std::min(m_min_stats[stat_idx], value);
+}
diff --git a/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.h b/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.h
new file mode 100644
index 0000000..d8e9aee
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.h
@@ -0,0 +1,86 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef LOAD_TIME_INITIALIZER_H
+#define LOAD_TIME_INITIALIZER_H
+#include "headers.h"
+#include <jni.h>
+/*#include "template.h"*/
+
+enum LoadTimeInitializerStatsEnum
+{
+ NUM_REGIONS_IDX=0,
+ NUM_READS_IDX,
+ NUM_HAPLOTYPES_IDX,
+ NUM_TESTCASES_IDX,
+ NUM_DOUBLE_INVOCATIONS_IDX,
+ HAPLOTYPE_LENGTH_IDX,
+ READ_LENGTH_IDX,
+ PRODUCT_READ_LENGTH_HAPLOTYPE_LENGTH_IDX,
+ TOTAL_NUMBER_STATS
+};
+extern char* LoadTimeInitializerStatsNames[];
+
+class LoadTimeInitializer
+{
+ public:
+ LoadTimeInitializer(); //will be called when library is loaded
+ void print_profiling();
+ void debug_dump(std::string filename, std::string s, bool to_append, bool add_newline=true);
+ void debug_close();
+
+ void dump_sandbox(testcase& tc, unsigned tc_idx, unsigned numReads, unsigned numHaplotypes);
+ void open_sandbox() { m_sandbox_fptr.open("sandbox.txt", std::ios::app); }
+ void close_sandbox() { m_sandbox_fptr.close(); }
+
+ jfieldID m_readBasesFID;
+ jfieldID m_readQualsFID;
+ jfieldID m_insertionGOPFID;
+ jfieldID m_deletionGOPFID;
+ jfieldID m_overallGCPFID;
+ jfieldID m_haplotypeBasesFID;
+ //profiling - update stats
+ void update_stat(LoadTimeInitializerStatsEnum stat_idx, uint64_t value);
+ //timing in nanoseconds
+ uint64_t m_compute_time;
+ uint64_t m_data_transfer_time;
+ //bytes copied
+ uint64_t m_bytes_copied;
+ private:
+ std::map<std::string, std::ofstream*> m_filename_to_fptr;
+ std::set<std::string> m_written_files_set;
+ std::ofstream m_sandbox_fptr;
+ //used to compute various stats
+ uint64_t m_sum_stats[TOTAL_NUMBER_STATS];
+ double m_sum_square_stats[TOTAL_NUMBER_STATS];
+ uint64_t m_min_stats[TOTAL_NUMBER_STATS];
+ uint64_t m_max_stats[TOTAL_NUMBER_STATS];
+};
+extern LoadTimeInitializer g_load_time_initializer;
+
+#define SIZE_PER_TESTCASE 6*10000
+#define SIZE_PER_BUFFER 10000
+
+#endif
diff --git a/public/VectorPairHMM/src/main/c++/Makefile b/public/VectorPairHMM/src/main/c++/Makefile
new file mode 100644
index 0000000..0fae1e8
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/Makefile
@@ -0,0 +1,126 @@
+#Copyright (c) 2012 The Broad Institute
+
+#Permission is hereby granted, free of charge, to any person
+#obtaining a copy of this software and associated documentation
+#files (the "Software"), to deal in the Software without
+#restriction, including without limitation the rights to use,
+#copy, modify, merge, publish, distribute, sublicense, and/or sell
+#copies of the Software, and to permit persons to whom the
+#Software is furnished to do so, subject to the following
+#conditions:
+
+#The above copyright notice and this permission notice shall be
+#included in all copies or substantial portions of the Software.
+
+#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+#OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+#NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+#HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+#WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+#FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+#THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+
+#OMPCFLAGS=-fopenmp
+#OMPLFLAGS=-fopenmp #-openmp-link static
+
+#CFLAGS=-O2 -std=c++11 -W -Wall -march=corei7-avx -Wa,-q -pedantic $(OMPCFLAGS) -Wno-unknown-pragmas
+#CFLAGS=-O2 -W -Wall -march=corei7 -mfpmath=sse -msse4.2 -pedantic $(OMPCFLAGS) -Wno-unknown-pragmas
+
+JRE_HOME?=/opt/jdk1.7.0_25/jre
+JNI_COMPILATION_FLAGS=-D_REENTRANT -fPIC -I${JRE_HOME}/../include -I${JRE_HOME}/../include/linux
+
+#COMMON_COMPILATION_FLAGS=$(JNI_COMPILATION_FLAGS) -O3 -W -Wall -pedantic $(OMPCFLAGS) -Wno-unknown-pragmas
+COMMON_COMPILATION_FLAGS=$(JNI_COMPILATION_FLAGS) -O3 -Wall $(OMPCFLAGS) -Wno-unknown-pragmas -Wno-write-strings -Wno-unused-variable -Wno-unused-but-set-variable
+ifdef DISABLE_FTZ
+ COMMON_COMPILATION_FLAGS+=-DDISABLE_FTZ
+endif
+
+ifdef USE_GCC
+ C_COMPILER?=gcc
+ CPP_COMPILER?=g++
+ AVX_FLAGS=-mavx
+ SSE41_FLAGS=-msse4.1
+ COMMON_COMPILATION_FLAGS+=-Wno-char-subscripts
+else
+ C_COMPILER?=icc
+ CPP_COMPILER?=icc
+ AVX_FLAGS=-xAVX
+ SSE41_FLAGS=-xSSE4.1
+ LIBFLAGS=-static-intel
+ ifdef DISABLE_FTZ
+ COMMON_COMPILATION_FLAGS+=-no-ftz
+ endif
+endif
+
+LDFLAGS=-lm -lrt $(OMPLDFLAGS)
+
+PAPI_DIR=/home/karthikg/softwares/papi-5.3.0
+ifdef USE_PAPI
+ ifeq ($(USE_PAPI),1)
+ COMMON_COMPILATION_FLAGS+=-I$(PAPI_DIR)/include -DUSE_PAPI
+ LDFLAGS+=-L$(PAPI_DIR)/lib -lpapi
+ endif
+endif
+
+BIN=libVectorLoglessPairHMM.so pairhmm-template-main checker
+#BIN=checker
+
+DEPDIR=.deps
+DF=$(DEPDIR)/$(*).d
+
+#Common across libJNI and sandbox
+COMMON_SOURCES=utils.cc avx_function_instantiations.cc baseline.cc sse_function_instantiations.cc LoadTimeInitializer.cc
+#Part of libJNI
+LIBSOURCES=org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc Sandbox.cc $(COMMON_SOURCES)
+SOURCES=$(LIBSOURCES) pairhmm-template-main.cc pairhmm-1-base.cc
+LIBOBJECTS=$(LIBSOURCES:.cc=.o)
+COMMON_OBJECTS=$(COMMON_SOURCES:.cc=.o)
+
+
+#No vectorization for these files
+NO_VECTOR_SOURCES=org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc pairhmm-template-main.cc pairhmm-1-base.cc utils.cc baseline.cc LoadTimeInitializer.cc Sandbox.cc
+#Use -xAVX for these files
+AVX_SOURCES=avx_function_instantiations.cc
+#Use -xSSE4.2 for these files
+SSE_SOURCES=sse_function_instantiations.cc
+
+NO_VECTOR_OBJECTS=$(NO_VECTOR_SOURCES:.cc=.o)
+AVX_OBJECTS=$(AVX_SOURCES:.cc=.o)
+SSE_OBJECTS=$(SSE_SOURCES:.cc=.o)
+$(NO_VECTOR_OBJECTS): CXXFLAGS=$(COMMON_COMPILATION_FLAGS)
+$(AVX_OBJECTS): CXXFLAGS=$(COMMON_COMPILATION_FLAGS) $(AVX_FLAGS)
+$(SSE_OBJECTS): CXXFLAGS=$(COMMON_COMPILATION_FLAGS) $(SSE41_FLAGS)
+OBJECTS=$(NO_VECTOR_OBJECTS) $(AVX_OBJECTS) $(SSE_OBJECTS)
+
+all: $(BIN) Sandbox.class copied_lib
+
+-include $(addprefix $(DEPDIR)/,$(SOURCES:.cc=.d))
+
+checker: pairhmm-1-base.o $(COMMON_OBJECTS)
+ $(CPP_COMPILER) $(OMPLFLAGS) -o $@ $^ $(LDFLAGS)
+
+pairhmm-template-main: pairhmm-template-main.o $(COMMON_OBJECTS)
+ $(CPP_COMPILER) $(OMPLFLAGS) -o $@ $^ $(LDFLAGS)
+
+libVectorLoglessPairHMM.so: $(LIBOBJECTS)
+ $(CPP_COMPILER) $(OMPLFLAGS) -shared $(LIBFLAGS) -o $@ $(LIBOBJECTS) ${LDFLAGS}
+
+
+$(OBJECTS): %.o: %.cc
+ @mkdir -p $(DEPDIR)
+ $(CPP_COMPILER) -c -MMD -MF $(DF) $(CXXFLAGS) $(OUTPUT_OPTION) $<
+
+Sandbox.class: Sandbox.java
+ javac Sandbox.java
+
+copied_lib: libVectorLoglessPairHMM.so
+ifdef OUTPUT_DIR
+ mkdir -p $(OUTPUT_DIR)
+ rsync -a libVectorLoglessPairHMM.so $(OUTPUT_DIR)/
+endif
+
+clean:
+ rm -rf $(BIN) *.o $(DEPDIR) *.class
diff --git a/public/VectorPairHMM/src/main/c++/Sandbox.cc b/public/VectorPairHMM/src/main/c++/Sandbox.cc
new file mode 100644
index 0000000..a4c2b73
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/Sandbox.cc
@@ -0,0 +1,106 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include "Sandbox.h"
+#include "org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.h"
+#include "utils.h"
+#include "jni_common.h"
+/*
+ * Class: Sandbox
+ * Method: jniGetMachineType
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_Sandbox_jniGetMachineType
+ (JNIEnv * env, jobject thisObj)
+{
+ return 0;
+}
+
+/*
+ * Class: Sandbox
+ * Method: jniInitializeClassFieldsAndMachineMask
+ * Signature: (Ljava/lang/Class;Ljava/lang/Class;J)V
+ */
+JNIEXPORT void JNICALL Java_Sandbox_jniInitializeClassFieldsAndMachineMask
+ (JNIEnv* env, jobject thisObject, jclass readDataHolderClass, jclass haplotypeDataHolderClass, jlong mask)
+{
+ Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeClassFieldsAndMachineMask(env, thisObject, readDataHolderClass,
+ haplotypeDataHolderClass, mask);
+}
+
+/*
+ * Class: Sandbox
+ * Method: jniInitializeHaplotypes
+ * Signature: (I[LSandbox/JNIHaplotypeDataHolderClass;)V
+ */
+JNIEXPORT void JNICALL Java_Sandbox_jniInitializeHaplotypes
+ (JNIEnv * env, jobject thisObject, jint numHaplotypes, jobjectArray haplotypeDataArray)
+{
+ Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeHaplotypes(env, thisObject, numHaplotypes, haplotypeDataArray);
+}
+
+/*
+ * Class: Sandbox
+ * Method: jniFinalizeRegion
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_Sandbox_jniFinalizeRegion
+ (JNIEnv * env, jobject thisObject)
+{
+ Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniFinalizeRegion(env, thisObject);
+}
+
+
+/*
+ * Class: Sandbox
+ * Method: jniComputeLikelihoods
+ * Signature: (II[LSandbox/JNIReadDataHolderClass;[LSandbox/JNIHaplotypeDataHolderClass;[DI)V
+ */
+JNIEXPORT void JNICALL Java_Sandbox_jniComputeLikelihoods
+ (JNIEnv* env, jobject thisObject, jint numReads, jint numHaplotypes,
+ jobjectArray readDataArray, jobjectArray haplotypeDataArray, jdoubleArray likelihoodArray, jint maxNumThreadsToUse)
+{
+ Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniComputeLikelihoods(env, thisObject,
+ numReads, numHaplotypes, readDataArray, haplotypeDataArray, likelihoodArray, maxNumThreadsToUse);
+}
+/*
+ * Class: Sandbox
+ * Method: jniClose
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_Sandbox_jniClose
+ (JNIEnv* env, jobject thisObject)
+{ Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniClose(env, thisObject); }
+
+JNIEXPORT void JNICALL Java_Sandbox_doEverythingNative
+ (JNIEnv* env, jobject thisObject, jstring fileNameString)
+{
+ const char* fileName = env->GetStringUTFChars(fileNameString, 0);
+ char local_array[800];
+ strncpy(local_array, fileName, 200);
+ env->ReleaseStringUTFChars(fileNameString, fileName);
+ do_compute(local_array, true, 10000, false);
+}
+
diff --git a/public/VectorPairHMM/src/main/c++/Sandbox.h b/public/VectorPairHMM/src/main/c++/Sandbox.h
new file mode 100644
index 0000000..486a1c0
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/Sandbox.h
@@ -0,0 +1,96 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class Sandbox */
+
+#ifndef _Included_Sandbox
+#define _Included_Sandbox
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef Sandbox_enableAll
+#define Sandbox_enableAll -1LL
+/*
+ * Class: Sandbox
+ * Method: jniGetMachineType
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_Sandbox_jniGetMachineType
+ (JNIEnv *, jobject);
+
+/*
+ * Class: Sandbox
+ * Method: jniInitializeClassFieldsAndMachineMask
+ * Signature: (Ljava/lang/Class;Ljava/lang/Class;J)V
+ */
+JNIEXPORT void JNICALL Java_Sandbox_jniInitializeClassFieldsAndMachineMask
+ (JNIEnv *, jobject, jclass, jclass, jlong);
+
+/*
+ * Class: Sandbox
+ * Method: jniInitializeHaplotypes
+ * Signature: (I[LSandbox/JNIHaplotypeDataHolderClass;)V
+ */
+JNIEXPORT void JNICALL Java_Sandbox_jniInitializeHaplotypes
+ (JNIEnv *, jobject, jint, jobjectArray);
+
+/*
+ * Class: Sandbox
+ * Method: jniFinalizeRegion
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_Sandbox_jniFinalizeRegion
+ (JNIEnv *, jobject);
+
+/*
+ * Class: Sandbox
+ * Method: jniComputeLikelihoods
+ * Signature: (II[LSandbox/JNIReadDataHolderClass;[LSandbox/JNIHaplotypeDataHolderClass;[DI)V
+ */
+JNIEXPORT void JNICALL Java_Sandbox_jniComputeLikelihoods
+ (JNIEnv *, jobject, jint, jint, jobjectArray, jobjectArray, jdoubleArray, jint);
+
+/*
+ * Class: Sandbox
+ * Method: jniClose
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_Sandbox_jniClose
+ (JNIEnv *, jobject);
+
+/*
+ * Class: Sandbox
+ * Method: doEverythingNative
+ * Signature: ([B)V
+ */
+JNIEXPORT void JNICALL Java_Sandbox_doEverythingNative
+ (JNIEnv *, jobject, jstring);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/public/VectorPairHMM/src/main/c++/Sandbox.java b/public/VectorPairHMM/src/main/c++/Sandbox.java
new file mode 100644
index 0000000..605c5f5
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/Sandbox.java
@@ -0,0 +1,306 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.vectorpairhmm;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.HashMap;
+import java.io.File;
+import java.util.Scanner;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.io.InputStreamReader;
+
+public class Sandbox {
+
+ private long setupTime = 0;
+ private long computeTime = 0;
+ //Used to copy references to byteArrays to JNI from reads
+ protected class JNIReadDataHolderClass {
+ public byte[] readBases = null;
+ public byte[] readQuals = null;
+ public byte[] insertionGOP = null;
+ public byte[] deletionGOP = null;
+ public byte[] overallGCP = null;
+ }
+
+ //Used to copy references to byteArrays to JNI from haplotypes
+ protected class JNIHaplotypeDataHolderClass {
+ public byte[] haplotypeBases = null;
+ }
+
+ /**
+ * Return 64-bit mask representing machine capabilities
+ * Bit 0 is LSB, bit 63 MSB
+ * Bit 0 represents sse4.2 availability
+ * Bit 1 represents AVX availability
+ */
+ public native long jniGetMachineType();
+ public static final long enableAll = 0xFFFFFFFFFFFFFFFFl;
+
+
+ /**
+ * Function to initialize the fields of JNIReadDataHolderClass and JNIHaplotypeDataHolderClass from JVM.
+ * C++ codegets FieldIDs for these classes once and re-uses these IDs for the remainder of the program. Field IDs do not
+ * change per JVM session
+ * @param readDataHolderClass class type of JNIReadDataHolderClass
+ * @param haplotypeDataHolderClass class type of JNIHaplotypeDataHolderClass
+ * @param mask mask is a 64 bit integer identical to the one received from jniGetMachineType(). Users can disable usage of some hardware features by zeroing some bits in the mask
+ * */
+ private native void jniInitializeClassFieldsAndMachineMask(Class<?> readDataHolderClass, Class<?> haplotypeDataHolderClass, long mask);
+
+ private static Boolean isVectorLoglessPairHMMLibraryLoaded = false;
+ //The constructor is called only once inside PairHMMLikelihoodCalculationEngine
+ public Sandbox() {
+ synchronized(isVectorLoglessPairHMMLibraryLoaded) {
+ //Load the library and initialize the FieldIDs
+ if(!isVectorLoglessPairHMMLibraryLoaded) {
+ System.loadLibrary("VectorLoglessPairHMM");
+ isVectorLoglessPairHMMLibraryLoaded = true;
+ jniInitializeClassFieldsAndMachineMask(JNIReadDataHolderClass.class, JNIHaplotypeDataHolderClass.class, enableAll); //need to do this only once
+ }
+ }
+ }
+
+ private native void jniInitializeHaplotypes(final int numHaplotypes, JNIHaplotypeDataHolderClass[] haplotypeDataArray);
+ private JNIHaplotypeDataHolderClass[] mHaplotypeDataArray = null;
+
+ //Used to transfer data to JNI
+ //Since the haplotypes are the same for all calls to computeLikelihoods within a region, transfer the haplotypes only once to the JNI per region
+ public void initialize(final List<JNIHaplotypeDataHolderClass> haplotypes) {
+ int numHaplotypes = haplotypes.size();
+ mHaplotypeDataArray = new JNIHaplotypeDataHolderClass[numHaplotypes];
+ int idx = 0;
+ for(final JNIHaplotypeDataHolderClass currHaplotype : haplotypes)
+ {
+ mHaplotypeDataArray[idx] = new JNIHaplotypeDataHolderClass();
+ mHaplotypeDataArray[idx].haplotypeBases = currHaplotype.haplotypeBases;
+ ++idx;
+ }
+ jniInitializeHaplotypes(numHaplotypes, mHaplotypeDataArray);
+ }
+ /**
+ * Tell JNI to release arrays - really important if native code is directly accessing Java memory, if not
+ * accessing Java memory directly, still important to release memory from C++
+ */
+ private native void jniFinalizeRegion();
+
+
+ public void finalizeRegion()
+ {
+ jniFinalizeRegion();
+ }
+
+ /**
+ * Real compute kernel
+ */
+ private native void jniComputeLikelihoods(int numReads, int numHaplotypes, JNIReadDataHolderClass[] readDataArray,
+ JNIHaplotypeDataHolderClass[] haplotypeDataArray, double[] likelihoodArray, int maxNumThreadsToUse);
+
+ public void computeLikelihoods(final List<JNIReadDataHolderClass> reads, final List<JNIHaplotypeDataHolderClass> haplotypes) {
+ //System.out.println("Region : "+reads.size()+" x "+haplotypes.size());
+ long startTime = System.nanoTime();
+ int readListSize = reads.size();
+ int numHaplotypes = haplotypes.size();
+ int numTestcases = readListSize*numHaplotypes;
+ JNIReadDataHolderClass[] readDataArray = new JNIReadDataHolderClass[readListSize];
+ int idx = 0;
+ for(JNIReadDataHolderClass read : reads)
+ {
+ readDataArray[idx] = new JNIReadDataHolderClass();
+ readDataArray[idx].readBases = read.readBases;
+ readDataArray[idx].readQuals = read.readQuals;
+ readDataArray[idx].insertionGOP = read.insertionGOP;
+ readDataArray[idx].deletionGOP = read.deletionGOP;
+ readDataArray[idx].overallGCP = read.overallGCP;
+ ++idx;
+ }
+
+ double[] mLikelihoodArray = new double[readListSize*numHaplotypes]; //to store results
+ setupTime += (System.nanoTime() - startTime);
+ //for(reads)
+ // for(haplotypes)
+ // compute_full_prob()
+ jniComputeLikelihoods(readListSize, numHaplotypes, readDataArray, mHaplotypeDataArray, mLikelihoodArray, 12);
+
+ computeTime += (System.nanoTime() - startTime);
+ }
+
+ /**
+ * Print final profiling information from native code
+ */
+ public native void jniClose();
+ public void close()
+ {
+ System.out.println("Time spent in setup for JNI call : "+(setupTime*1e-9)+" compute time : "+(computeTime*1e-9));
+ jniClose();
+ }
+
+ public void parseSandboxFile(String filename)
+ {
+ File file = new File(filename);
+ Scanner input = null;
+ try
+ {
+ input = new Scanner(file);
+ }
+ catch(FileNotFoundException e)
+ {
+ System.err.println("File "+filename+" cannot be found/read");
+ return;
+ }
+ int idx = 0;
+ int numReads = 0;
+ int numHaplotypes = 0;
+ int readIdx = 0, testCaseIdx = 0, haplotypeIdx = 0;
+ LinkedList<JNIHaplotypeDataHolderClass> haplotypeList = new LinkedList<JNIHaplotypeDataHolderClass>();
+ LinkedList<JNIReadDataHolderClass> readList = new LinkedList<JNIReadDataHolderClass>();
+
+ byte[][] byteArray = new byte[6][];
+ boolean firstLine = true;
+ String[] currTokens = new String[8];
+ while(input.hasNextLine())
+ {
+ String line = input.nextLine();
+ Scanner lineScanner = new Scanner(line);
+ idx = 0;
+ while(lineScanner.hasNext())
+ currTokens[idx++] = lineScanner.next();
+ if(idx == 0)
+ break;
+ assert(idx >= 6);
+ //start of new region
+ if(idx == 8)
+ {
+ if(!firstLine)
+ {
+ initialize(haplotypeList);
+ computeLikelihoods(readList, haplotypeList);
+ finalizeRegion();
+ }
+ try
+ {
+ numReads = Integer.parseInt(currTokens[6]);
+ }
+ catch(NumberFormatException e)
+ {
+ numReads = 1;
+ }
+ try
+ {
+ numHaplotypes = Integer.parseInt(currTokens[7]);
+ }
+ catch(NumberFormatException e)
+ {
+ numHaplotypes = 1;
+ }
+ haplotypeIdx = readIdx = testCaseIdx = 0;
+ readList.clear();
+ haplotypeList.clear();
+ }
+ if(haplotypeIdx < numHaplotypes)
+ {
+ JNIHaplotypeDataHolderClass X = new JNIHaplotypeDataHolderClass();
+ X.haplotypeBases = currTokens[0].getBytes();
+ haplotypeList.add(X);
+ }
+ if(testCaseIdx%numHaplotypes == 0)
+ {
+ JNIReadDataHolderClass X = new JNIReadDataHolderClass();
+ X.readBases = currTokens[1].getBytes();
+ for(int i=2;i<6;++i)
+ {
+ byteArray[i] = currTokens[i].getBytes();
+ for(int j=0;j<byteArray[i].length;++j)
+ byteArray[i][j] -= 33; //normalize
+ }
+ X.readQuals = byteArray[2];
+ X.insertionGOP = byteArray[3];
+ X.deletionGOP = byteArray[4];
+ X.overallGCP = byteArray[5];
+ readList.add(X);
+ }
+ ++testCaseIdx;
+ ++haplotypeIdx;
+
+ lineScanner.close();
+ firstLine = false;
+ }
+ if(haplotypeList.size() > 0 && readList.size() > 0)
+ {
+ initialize(haplotypeList);
+ computeLikelihoods(readList, haplotypeList);
+ finalizeRegion();
+ }
+
+ close();
+ input.close();
+ }
+
+ private native void doEverythingNative(String filename);
+
+ public static void main(String[] args)
+ {
+ if(args.length <= 0)
+ {
+ System.err.println("Needs 1 argument - <filename>");
+ System.exit(-1);
+ }
+ //// Get runtime
+ //java.lang.Runtime rt = java.lang.Runtime.getRuntime();
+ //// Start a new process: UNIX command ls
+ //String cmd = "/home/karthikg/broad/gsa-unstable/public/c++/VectorPairHMM/checker "+args[0];
+ //try
+ //{
+ //System.out.println(cmd);
+ //java.lang.Process p = rt.exec(cmd);
+ //try
+ //{
+ //p.waitFor();
+ //java.io.InputStream is = p.getInputStream();
+ //java.io.BufferedReader reader = new java.io.BufferedReader(new InputStreamReader(is));
+ //// And print each line
+ //String s = null;
+ //while ((s = reader.readLine()) != null) {
+ //System.out.println(s);
+ //}
+ //is.close();
+ //}
+ //catch(InterruptedException e)
+ //{
+ //System.err.println(e);
+ //}
+ //}
+ //catch(IOException e)
+ //{
+ //System.err.println(e);
+ //}
+ Sandbox t = new Sandbox();
+ //t.doEverythingNative(args[0]);
+ t.parseSandboxFile(args[0]);
+ }
+}
diff --git a/public/VectorPairHMM/src/main/c++/Sandbox_JNIHaplotypeDataHolderClass.h b/public/VectorPairHMM/src/main/c++/Sandbox_JNIHaplotypeDataHolderClass.h
new file mode 100644
index 0000000..7f78f01
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/Sandbox_JNIHaplotypeDataHolderClass.h
@@ -0,0 +1,13 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class Sandbox_JNIHaplotypeDataHolderClass */
+
+#ifndef _Included_Sandbox_JNIHaplotypeDataHolderClass
+#define _Included_Sandbox_JNIHaplotypeDataHolderClass
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/public/VectorPairHMM/src/main/c++/Sandbox_JNIReadDataHolderClass.h b/public/VectorPairHMM/src/main/c++/Sandbox_JNIReadDataHolderClass.h
new file mode 100644
index 0000000..a9312ff
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/Sandbox_JNIReadDataHolderClass.h
@@ -0,0 +1,13 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class Sandbox_JNIReadDataHolderClass */
+
+#ifndef _Included_Sandbox_JNIReadDataHolderClass
+#define _Included_Sandbox_JNIReadDataHolderClass
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/public/VectorPairHMM/src/main/c++/avx_function_instantiations.cc b/public/VectorPairHMM/src/main/c++/avx_function_instantiations.cc
new file mode 100644
index 0000000..1a6b593
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/avx_function_instantiations.cc
@@ -0,0 +1,45 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+
+#undef SIMD_ENGINE
+#undef SIMD_ENGINE_SSE
+
+#define SIMD_ENGINE avx
+#define SIMD_ENGINE_AVX
+
+#include "template.h"
+
+#include "define-float.h"
+#include "shift_template.c"
+#include "pairhmm-template-kernel.cc"
+
+#include "define-double.h"
+#include "shift_template.c"
+#include "pairhmm-template-kernel.cc"
+
+template double compute_full_prob_avxd<double>(testcase* tc, double* nextlog);
+template float compute_full_prob_avxs<float>(testcase* tc, float* nextlog);
+
diff --git a/public/VectorPairHMM/src/main/c++/baseline.cc b/public/VectorPairHMM/src/main/c++/baseline.cc
new file mode 100644
index 0000000..17d2c27
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/baseline.cc
@@ -0,0 +1,157 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include "headers.h"
+#include "common_data_structure.h"
+#include "utils.h"
+#include "LoadTimeInitializer.h"
+using namespace std;
+
+template<class NUMBER>
+NUMBER compute_full_prob(testcase *tc, NUMBER *before_last_log)
+{
+ int r, c;
+ int ROWS = tc->rslen + 1;
+ int COLS = tc->haplen + 1;
+
+ Context<NUMBER> ctx;
+ //#define USE_STACK_ALLOCATION 1
+#ifdef USE_STACK_ALLOCATION
+ NUMBER M[ROWS][COLS];
+ NUMBER X[ROWS][COLS];
+ NUMBER Y[ROWS][COLS];
+ NUMBER p[ROWS][6];
+#else
+ //allocate on heap in way that simulates a 2D array. Having a 2D array instead of
+ //a straightforward array of pointers ensures that all data lies 'close' in memory, increasing
+ //the chance of being stored together in the cache. Also, prefetchers can learn memory access
+ //patterns for 2D arrays, not possible for array of pointers
+ //NUMBER* common_buffer = 0;
+ NUMBER* common_buffer = new NUMBER[3*ROWS*COLS + ROWS*6];
+ //pointers to within the allocated buffer
+ NUMBER** common_pointer_buffer = new NUMBER*[4*ROWS];
+ NUMBER* ptr = common_buffer;
+ unsigned i = 0;
+ for(i=0;i<3*ROWS;++i, ptr+=COLS)
+ common_pointer_buffer[i] = ptr;
+ for(;i<4*ROWS;++i, ptr+=6)
+ common_pointer_buffer[i] = ptr;
+
+ NUMBER** M = common_pointer_buffer;
+ NUMBER** X = M + ROWS;
+ NUMBER** Y = X + ROWS;
+ NUMBER** p = Y + ROWS;
+#endif
+
+
+ p[0][MM] = ctx._(0.0);
+ p[0][GapM] = ctx._(0.0);
+ p[0][MX] = ctx._(0.0);
+ p[0][XX] = ctx._(0.0);
+ p[0][MY] = ctx._(0.0);
+ p[0][YY] = ctx._(0.0);
+
+ for (r = 1; r < ROWS; r++)
+ {
+ int _i = tc->i[r-1] & 127;
+ int _d = tc->d[r-1] & 127;
+ int _c = tc->c[r-1] & 127;
+ //p[r][MM] = ctx._(1.0) - ctx.ph2pr[(_i + _d) & 127];
+ SET_MATCH_TO_MATCH_PROB(p[r][MM], _i, _d);
+ p[r][GapM] = ctx._(1.0) - ctx.ph2pr[_c];
+ p[r][MX] = ctx.ph2pr[_i];
+ p[r][XX] = ctx.ph2pr[_c];
+ p[r][MY] = ctx.ph2pr[_d];
+ p[r][YY] = ctx.ph2pr[_c];
+ //p[r][MY] = (r == ROWS - 1) ? ctx._(1.0) : ctx.ph2pr[_d];
+ //p[r][YY] = (r == ROWS - 1) ? ctx._(1.0) : ctx.ph2pr[_c];
+ }
+ for (c = 0; c < COLS; c++)
+ {
+ M[0][c] = ctx._(0.0);
+ X[0][c] = ctx._(0.0);
+ Y[0][c] = ctx.INITIAL_CONSTANT / (tc->haplen);
+ }
+
+ for (r = 1; r < ROWS; r++)
+ {
+ M[r][0] = ctx._(0.0);
+ X[r][0] = X[r-1][0] * p[r][XX];
+ Y[r][0] = ctx._(0.0);
+ }
+
+ NUMBER result = ctx._(0.0);
+
+ for (r = 1; r < ROWS; r++)
+ for (c = 1; c < COLS; c++)
+ {
+ fexcept_t flagp;
+ char _rs = tc->rs[r-1];
+ char _hap = tc->hap[c-1];
+ int _q = tc->q[r-1] & 127;
+ NUMBER distm = ctx.ph2pr[_q];
+ if (_rs == _hap || _rs == 'N' || _hap == 'N')
+ distm = ctx._(1.0) - distm;
+ else
+ distm = distm/3;
+
+
+ //feclearexcept(FE_ALL_EXCEPT);
+ M[r][c] = distm * (M[r-1][c-1] * p[r][MM] + X[r-1][c-1] * p[r][GapM] + Y[r-1][c-1] * p[r][GapM]);
+ //STORE_FP_EXCEPTIONS(flagp, exceptions_array);
+
+ //feclearexcept(FE_ALL_EXCEPT);
+ X[r][c] = M[r-1][c] * p[r][MX] + X[r-1][c] * p[r][XX];
+ //STORE_FP_EXCEPTIONS(flagp, exceptions_array);
+
+ //feclearexcept(FE_ALL_EXCEPT);
+ Y[r][c] = M[r][c-1] * p[r][MY] + Y[r][c-1] * p[r][YY];
+ //STORE_FP_EXCEPTIONS(flagp, exceptions_array);
+
+ //CONVERT_AND_PRINT(M[r][c]);
+ //CONVERT_AND_PRINT(X[r][c]);
+ //CONVERT_AND_PRINT(Y[r][c]);
+
+ }
+ for (c = 0; c < COLS; c++)
+ {
+ result += M[ROWS-1][c] + X[ROWS-1][c];
+ }
+
+ if (before_last_log != NULL)
+ *before_last_log = result;
+
+#ifndef USE_STACK_ALLOCATION
+ delete[] common_pointer_buffer;
+ delete[] common_buffer;
+#endif
+
+ return result;
+ //return ctx.LOG10(result) - ctx.LOG10_INITIAL_CONSTANT;
+}
+
+template double compute_full_prob<double>(testcase* tc, double* nextbuf);
+template float compute_full_prob<float>(testcase* tc, float* nextbuf);
+
diff --git a/public/VectorPairHMM/src/main/c++/common_data_structure.h b/public/VectorPairHMM/src/main/c++/common_data_structure.h
new file mode 100644
index 0000000..4b5f034
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/common_data_structure.h
@@ -0,0 +1,215 @@
+#ifndef COMMON_DATA_STRUCTURE_H
+#define COMMON_DATA_STRUCTURE_H
+
+#include "headers.h"
+
+#define CAT(X,Y) X####Y
+#define CONCAT(X,Y) CAT(X,Y)
+
+#define MM 0
+#define GapM 1
+#define MX 2
+#define XX 3
+#define MY 4
+#define YY 5
+
+//#define MROWS 500
+//#define MCOLS 1000
+
+
+#define MAX_QUAL 254
+#define MAX_JACOBIAN_TOLERANCE 8.0
+#define JACOBIAN_LOG_TABLE_STEP 0.0001
+#define JACOBIAN_LOG_TABLE_INV_STEP (1.0 / JACOBIAN_LOG_TABLE_STEP)
+#define MAXN 70000
+#define LOG10_CACHE_SIZE (4*MAXN) // we need to be able to go up to 2*(2N) when calculating some of the coefficients
+#define JACOBIAN_LOG_TABLE_SIZE ((int) (MAX_JACOBIAN_TOLERANCE / JACOBIAN_LOG_TABLE_STEP) + 1)
+
+template<class NUMBER>
+struct ContextBase
+{
+ public:
+ NUMBER ph2pr[128];
+ NUMBER INITIAL_CONSTANT;
+ NUMBER LOG10_INITIAL_CONSTANT;
+ NUMBER RESULT_THRESHOLD;
+
+ static bool staticMembersInitializedFlag;
+ static NUMBER jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE];
+ static NUMBER matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1];
+
+ static void initializeStaticMembers()
+ {
+ if(!staticMembersInitializedFlag)
+ {
+ //Order of calls important - Jacobian first, then MatchToMatch
+ initializeJacobianLogTable();
+ initializeMatchToMatchProb();
+ staticMembersInitializedFlag = true;
+ }
+ }
+
+ static void deleteStaticMembers()
+ {
+ if(staticMembersInitializedFlag)
+ {
+ staticMembersInitializedFlag = false;
+ }
+ }
+
+ //Called only once during library load - don't bother to optimize with single precision fp
+ static void initializeJacobianLogTable()
+ {
+ for (int k = 0; k < JACOBIAN_LOG_TABLE_SIZE; k++) {
+ jacobianLogTable[k] = (NUMBER)(log10(1.0 + pow(10.0, -((double) k) * JACOBIAN_LOG_TABLE_STEP)));
+ }
+ }
+
+ //Called only once per library load - don't bother optimizing with single fp
+ static void initializeMatchToMatchProb()
+ {
+ double LN10 = log(10);
+ double INV_LN10 = 1.0/LN10;
+ for (int i = 0, offset = 0; i <= MAX_QUAL; offset += ++i)
+ for (int j = 0; j <= i; j++) {
+ double log10Sum = approximateLog10SumLog10(-0.1*i, -0.1*j);
+ double matchToMatchLog10 =
+ log1p(-std::min(1.0,pow(10,log10Sum))) * INV_LN10;
+ matchToMatchProb[offset + j] = (NUMBER)(pow(10,matchToMatchLog10));
+ }
+ }
+ //Called during computation - use single precision where possible
+ static int fastRound(NUMBER d) {
+ return (d > ((NUMBER)0.0)) ? (int) (d + ((NUMBER)0.5)) : (int) (d - ((NUMBER)0.5));
+ }
+ //Called during computation - use single precision where possible
+ static NUMBER approximateLog10SumLog10(NUMBER small, NUMBER big) {
+ // make sure small is really the smaller value
+ if (small > big) {
+ NUMBER t = big;
+ big = small;
+ small = t;
+ }
+
+ if (isinf(small) == -1 || isinf(big) == -1)
+ return big;
+
+ NUMBER diff = big - small;
+ if (diff >= ((NUMBER)MAX_JACOBIAN_TOLERANCE))
+ return big;
+
+ // OK, so |y-x| < tol: we use the following identity then:
+ // we need to compute log10(10^x + 10^y)
+ // By Jacobian logarithm identity, this is equal to
+ // max(x,y) + log10(1+10^-abs(x-y))
+ // we compute the second term as a table lookup with integer quantization
+ // we have pre-stored correction for 0,0.1,0.2,... 10.0
+ int ind = fastRound((NUMBER)(diff * ((NUMBER)JACOBIAN_LOG_TABLE_INV_STEP))); // hard rounding
+ return big + jacobianLogTable[ind];
+ }
+};
+
+template<class NUMBER>
+struct Context : public ContextBase<NUMBER>
+{};
+
+template<>
+struct Context<double> : public ContextBase<double>
+{
+ Context():ContextBase<double>()
+ {
+ for (int x = 0; x < 128; x++)
+ ph2pr[x] = pow(10.0, -((double)x) / 10.0);
+
+ INITIAL_CONSTANT = ldexp(1.0, 1020.0);
+ LOG10_INITIAL_CONSTANT = log10(INITIAL_CONSTANT);
+ RESULT_THRESHOLD = 0.0;
+ }
+
+ double LOG10(double v){ return log10(v); }
+ inline double POW(double b, double e) { return pow(b,e); }
+
+ static double _(double n){ return n; }
+ static double _(float n){ return ((double) n); }
+};
+
+template<>
+struct Context<float> : public ContextBase<float>
+{
+ Context() : ContextBase<float>()
+ {
+ for (int x = 0; x < 128; x++)
+ {
+ ph2pr[x] = powf(10.f, -((float)x) / 10.f);
+ }
+
+ INITIAL_CONSTANT = ldexpf(1.f, 120.f);
+ LOG10_INITIAL_CONSTANT = log10f(INITIAL_CONSTANT);
+ RESULT_THRESHOLD = ldexpf(1.f, -110.f);
+ }
+
+ float LOG10(float v){ return log10f(v); }
+ inline float POW(float b, float e) { return powf(b,e); }
+
+ static float _(double n){ return ((float) n); }
+ static float _(float n){ return n; }
+};
+
+#define SET_MATCH_TO_MATCH_PROB(output, insQual, delQual) \
+{ \
+ int minQual = delQual; \
+ int maxQual = insQual; \
+ if (insQual <= delQual) \
+ { \
+ minQual = insQual; \
+ maxQual = delQual; \
+ } \
+ (output) = (MAX_QUAL < maxQual) ? \
+ ((NUMBER)1.0) - ctx.POW(((NUMBER)10), ctx.approximateLog10SumLog10(((NUMBER)-0.1)*minQual, ((NUMBER)-0.1)*maxQual)) \
+ : ctx.matchToMatchProb[((maxQual * (maxQual + 1)) >> 1) + minQual]; \
+}
+
+
+
+typedef struct
+{
+ int rslen, haplen;
+ /*int *q, *i, *d, *c;*/
+ /*int q[MROWS], i[MROWS], d[MROWS], c[MROWS];*/
+ char *q, *i, *d, *c;
+ char *hap, *rs;
+ int *ihap;
+ int *irs;
+} testcase;
+
+#define MIN_ACCEPTED 1e-28f
+#define NUM_DISTINCT_CHARS 5
+#define AMBIG_CHAR 4
+
+class ConvertChar {
+
+ static uint8_t conversionTable[255] ;
+
+public:
+
+ static void init() {
+ assert (NUM_DISTINCT_CHARS == 5) ;
+ assert (AMBIG_CHAR == 4) ;
+
+ conversionTable['A'] = 0 ;
+ conversionTable['C'] = 1 ;
+ conversionTable['T'] = 2 ;
+ conversionTable['G'] = 3 ;
+ conversionTable['N'] = 4 ;
+ }
+
+ static inline uint8_t get(uint8_t input) {
+ return conversionTable[input] ;
+ }
+
+};
+
+int normalize(char c);
+int read_testcase(testcase *tc, FILE* ifp=0);
+
+#endif
diff --git a/public/VectorPairHMM/src/main/c++/define-double.h b/public/VectorPairHMM/src/main/c++/define-double.h
new file mode 100644
index 0000000..96fc274
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/define-double.h
@@ -0,0 +1,205 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include <iostream>
+
+#ifdef PRECISION
+#undef PRECISION
+#undef MAIN_TYPE
+#undef MAIN_TYPE_SIZE
+#undef UNION_TYPE
+#undef IF_128
+#undef IF_MAIN_TYPE
+#undef SHIFT_CONST1
+#undef SHIFT_CONST2
+#undef SHIFT_CONST3
+#undef _128_TYPE
+#undef SIMD_TYPE
+#undef AVX_LENGTH
+#undef HAP_TYPE
+#undef MASK_TYPE
+#undef MASK_ALL_ONES
+
+#undef SET_VEC_ZERO
+#undef VEC_OR
+#undef VEC_ADD
+#undef VEC_SUB
+#undef VEC_MUL
+#undef VEC_DIV
+#undef VEC_BLEND
+#undef VEC_BLENDV
+#undef VEC_CAST_256_128
+#undef VEC_EXTRACT_128
+#undef VEC_EXTRACT_UNIT
+#undef VEC_SET1_VAL128
+#undef VEC_MOVE
+#undef VEC_CAST_128_256
+#undef VEC_INSERT_VAL
+#undef VEC_CVT_128_256
+#undef VEC_SET1_VAL
+#undef VEC_POPCVT_CHAR
+#undef VEC_LDPOPCVT_CHAR
+#undef VEC_CMP_EQ
+#undef VEC_SET_LSE
+#undef SHIFT_HAP
+#undef MASK_VEC
+#undef VEC_SSE_TO_AVX
+#undef VEC_SHIFT_LEFT_1BIT
+#undef MASK_ALL_ONES
+#undef COMPARE_VECS
+#undef _256_INT_TYPE
+#undef BITMASK_VEC
+#endif
+
+#define PRECISION d
+#define MAIN_TYPE double
+#define MAIN_TYPE_SIZE 64
+#define UNION_TYPE mix_D
+#define IF_128 IF_128d
+#define IF_MAIN_TYPE IF_64
+#define SHIFT_CONST1 8
+#define SHIFT_CONST2 1
+#define SHIFT_CONST3 8
+#define _128_TYPE __m128d
+#define SIMD_TYPE __m256d
+#define _256_INT_TYPE __m256i
+#define AVX_LENGTH 4
+#define HAP_TYPE __m128i
+#define MASK_TYPE uint64_t
+#define MASK_ALL_ONES 0xFFFFFFFFFFFFFFFF
+#define MASK_VEC MaskVec_D
+
+#define SET_VEC_ZERO(__vec) \
+ __vec= _mm256_setzero_pd()
+
+#define VEC_OR(__v1, __v2) \
+ _mm256_or_pd(__v1, __v2)
+
+#define VEC_ADD(__v1, __v2) \
+ _mm256_add_pd(__v1, __v2)
+
+#define VEC_SUB(__v1, __v2) \
+ _mm256_sub_pd(__v1, __v2)
+
+#define VEC_MUL(__v1, __v2) \
+ _mm256_mul_pd(__v1, __v2)
+
+#define VEC_DIV(__v1, __v2) \
+ _mm256_div_pd(__v1, __v2)
+
+#define VEC_BLEND(__v1, __v2, __mask) \
+ _mm256_blend_pd(__v1, __v2, __mask)
+
+#define VEC_BLENDV(__v1, __v2, __maskV) \
+ _mm256_blendv_pd(__v1, __v2, __maskV)
+
+#define VEC_CAST_256_128(__v1) \
+ _mm256_castpd256_pd128 (__v1)
+
+#define VEC_EXTRACT_128(__v1, __im) \
+ _mm256_extractf128_pd (__v1, __im)
+
+#define VEC_EXTRACT_UNIT(__v1, __im) \
+ _mm_extract_epi64(__v1, __im)
+
+#define VEC_SET1_VAL128(__val) \
+ _mm_set1_pd(__val)
+
+#define VEC_MOVE(__v1, __val) \
+ _mm_move_sd(__v1, __val)
+
+#define VEC_CAST_128_256(__v1) \
+ _mm256_castpd128_pd256(__v1)
+
+#define VEC_INSERT_VAL(__v1, __val, __pos) \
+ _mm256_insertf128_pd(__v1, __val, __pos)
+
+#define VEC_CVT_128_256(__v1) \
+ _mm256_cvtepi32_pd(__v1)
+
+#define VEC_SET1_VAL(__val) \
+ _mm256_set1_pd(__val)
+
+#define VEC_POPCVT_CHAR(__ch) \
+ _mm256_cvtepi32_pd(_mm_set1_epi32(__ch))
+
+#define VEC_LDPOPCVT_CHAR(__addr) \
+ _mm256_cvtepi32_pd(_mm_load_si128((__m128i const *)__addr))
+
+#define VEC_CMP_EQ(__v1, __v2) \
+ _mm256_cmp_pd(__v1, __v2, _CMP_EQ_OQ)
+
+#define VEC_SET_LSE(__val) \
+ _mm256_set_pd(zero, zero, zero, __val);
+
+#define SHIFT_HAP(__v1, __val) \
+ __v1 = _mm_insert_epi32(_mm_slli_si128(__v1, 4), __val.i, 0)
+
+#define VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) \
+ __vdst = _mm256_castpd128_pd256(__vsLow) ; \
+__vdst = _mm256_insertf128_pd(__vdst, __vsHigh, 1) ;
+
+#define VEC_SHIFT_LEFT_1BIT(__vs) \
+ __vs = _mm_slli_epi64(__vs, 1)
+
+
+#define COMPARE_VECS(__v1, __v2, __first, __last) { \
+ double* ptr1 = (double*) (&__v1) ; \
+ double* ptr2 = (double*) (&__v2) ; \
+ for (int ei=__first; ei <= __last; ++ei) { \
+ if (ptr1[ei] != ptr2[ei]) { \
+ std::cout << "Double Mismatch at " << ei << ": " \
+ << ptr1[ei] << " vs. " << ptr2[ei] << std::endl ; \
+ exit(0) ; \
+ } \
+ } \
+}
+
+class BitMaskVec_double {
+
+ MASK_VEC low_, high_ ;
+ SIMD_TYPE combined_ ;
+
+ public:
+ inline MASK_TYPE& getLowEntry(int index) {
+ return low_.masks[index] ;
+ }
+ inline MASK_TYPE& getHighEntry(int index) {
+ return high_.masks[index] ;
+ }
+
+ inline const SIMD_TYPE& getCombinedMask() {
+ VEC_SSE_TO_AVX(low_.vecf, high_.vecf, combined_) ;
+ return combined_ ;
+ }
+
+ inline void shift_left_1bit() {
+ VEC_SHIFT_LEFT_1BIT(low_.vec) ;
+ VEC_SHIFT_LEFT_1BIT(high_.vec) ;
+ }
+
+} ;
+
+#define BITMASK_VEC BitMaskVec_double
diff --git a/public/VectorPairHMM/src/main/c++/define-float.h b/public/VectorPairHMM/src/main/c++/define-float.h
new file mode 100644
index 0000000..056bd53
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/define-float.h
@@ -0,0 +1,206 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include <iostream>
+
+#ifdef PRECISION
+#undef PRECISION
+#undef MAIN_TYPE
+#undef MAIN_TYPE_SIZE
+#undef UNION_TYPE
+#undef IF_128
+#undef IF_MAIN_TYPE
+#undef SHIFT_CONST1
+#undef SHIFT_CONST2
+#undef SHIFT_CONST3
+#undef _128_TYPE
+#undef SIMD_TYPE
+#undef AVX_LENGTH
+#undef HAP_TYPE
+#undef MASK_TYPE
+#undef MASK_ALL_ONES
+
+#undef SET_VEC_ZERO
+#undef VEC_OR
+#undef VEC_ADD
+#undef VEC_SUB
+#undef VEC_MUL
+#undef VEC_DIV
+#undef VEC_BLEND
+#undef VEC_BLENDV
+#undef VEC_CAST_256_128
+#undef VEC_EXTRACT_128
+#undef VEC_EXTRACT_UNIT
+#undef VEC_SET1_VAL128
+#undef VEC_MOVE
+#undef VEC_CAST_128_256
+#undef VEC_INSERT_VAL
+#undef VEC_CVT_128_256
+#undef VEC_SET1_VAL
+#undef VEC_POPCVT_CHAR
+#undef VEC_LDPOPCVT_CHAR
+#undef VEC_CMP_EQ
+#undef VEC_SET_LSE
+#undef SHIFT_HAP
+#undef MASK_VEC
+#undef VEC_SSE_TO_AVX
+#undef VEC_SHIFT_LEFT_1BIT
+#undef MASK_ALL_ONES
+#undef COMPARE_VECS
+#undef _256_INT_TYPE
+#undef BITMASK_VEC
+#endif
+
+#define PRECISION s
+
+#define MAIN_TYPE float
+#define MAIN_TYPE_SIZE 32
+#define UNION_TYPE mix_F
+#define IF_128 IF_128f
+#define IF_MAIN_TYPE IF_32
+#define SHIFT_CONST1 12
+#define SHIFT_CONST2 3
+#define SHIFT_CONST3 4
+#define _128_TYPE __m128
+#define SIMD_TYPE __m256
+#define _256_INT_TYPE __m256i
+#define AVX_LENGTH 8
+#define HAP_TYPE UNION_TYPE
+#define MASK_TYPE uint32_t
+#define MASK_ALL_ONES 0xFFFFFFFF
+#define MASK_VEC MaskVec_F
+
+#define SET_VEC_ZERO(__vec) \
+ __vec= _mm256_setzero_ps()
+
+#define VEC_OR(__v1, __v2) \
+ _mm256_or_ps(__v1, __v2)
+
+#define VEC_ADD(__v1, __v2) \
+ _mm256_add_ps(__v1, __v2)
+
+#define VEC_SUB(__v1, __v2) \
+ _mm256_sub_ps(__v1, __v2)
+
+#define VEC_MUL(__v1, __v2) \
+ _mm256_mul_ps(__v1, __v2)
+
+#define VEC_DIV(__v1, __v2) \
+ _mm256_div_ps(__v1, __v2)
+
+#define VEC_BLEND(__v1, __v2, __mask) \
+ _mm256_blend_ps(__v1, __v2, __mask)
+
+#define VEC_BLENDV(__v1, __v2, __maskV) \
+ _mm256_blendv_ps(__v1, __v2, __maskV)
+
+#define VEC_CAST_256_128(__v1) \
+ _mm256_castps256_ps128 (__v1)
+
+#define VEC_EXTRACT_128(__v1, __im) \
+ _mm256_extractf128_ps (__v1, __im)
+
+#define VEC_EXTRACT_UNIT(__v1, __im) \
+ _mm_extract_epi32(__v1, __im)
+
+#define VEC_SET1_VAL128(__val) \
+ _mm_set1_ps(__val)
+
+#define VEC_MOVE(__v1, __val) \
+ _mm_move_ss(__v1, __val)
+
+#define VEC_CAST_128_256(__v1) \
+ _mm256_castps128_ps256(__v1)
+
+#define VEC_INSERT_VAL(__v1, __val, __pos) \
+ _mm256_insertf128_ps(__v1, __val, __pos)
+
+#define VEC_CVT_128_256(__v1) \
+ _mm256_cvtepi32_ps(__v1.i)
+
+#define VEC_SET1_VAL(__val) \
+ _mm256_set1_ps(__val)
+
+#define VEC_POPCVT_CHAR(__ch) \
+ _mm256_cvtepi32_ps(_mm256_set1_epi32(__ch))
+
+#define VEC_LDPOPCVT_CHAR(__addr) \
+ _mm256_cvtepi32_ps(_mm256_loadu_si256((__m256i const *)__addr))
+
+#define VEC_CMP_EQ(__v1, __v2) \
+ _mm256_cmp_ps(__v1, __v2, _CMP_EQ_OQ)
+
+#define VEC_SET_LSE(__val) \
+ _mm256_set_ps(zero, zero, zero, zero, zero, zero, zero, __val);
+
+#define SHIFT_HAP(__v1, __val) \
+ _vector_shift_lastavxs(__v1, __val.f);
+
+#define VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) \
+ __vdst = _mm256_castps128_ps256(__vsLow) ; \
+__vdst = _mm256_insertf128_ps(__vdst, __vsHigh, 1) ;
+
+#define VEC_SHIFT_LEFT_1BIT(__vs) \
+ __vs = _mm_slli_epi32(__vs, 1)
+
+#define COMPARE_VECS(__v1, __v2, __first, __last) { \
+ float* ptr1 = (float*) (&__v1) ; \
+ float* ptr2 = (float*) (&__v2) ; \
+ for (int ei=__first; ei <= __last; ++ei) { \
+ if (ptr1[ei] != ptr2[ei]) { \
+ std::cout << "Float Mismatch at " << ei << ": " \
+ << ptr1[ei] << " vs. " << ptr2[ei] << std::endl ; \
+ exit(0) ; \
+ } \
+ } \
+}
+
+class BitMaskVec_float {
+
+ MASK_VEC low_, high_ ;
+ SIMD_TYPE combined_ ;
+
+ public:
+
+ inline MASK_TYPE& getLowEntry(int index) {
+ return low_.masks[index] ;
+ }
+ inline MASK_TYPE& getHighEntry(int index) {
+ return high_.masks[index] ;
+ }
+
+ inline const SIMD_TYPE& getCombinedMask() {
+ VEC_SSE_TO_AVX(low_.vecf, high_.vecf, combined_) ;
+ return combined_ ;
+ }
+
+ inline void shift_left_1bit() {
+ VEC_SHIFT_LEFT_1BIT(low_.vec) ;
+ VEC_SHIFT_LEFT_1BIT(high_.vec) ;
+ }
+
+} ;
+
+#define BITMASK_VEC BitMaskVec_float
diff --git a/public/VectorPairHMM/src/main/c++/define-sse-double.h b/public/VectorPairHMM/src/main/c++/define-sse-double.h
new file mode 100644
index 0000000..9456e14
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/define-sse-double.h
@@ -0,0 +1,173 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifdef PRECISION
+#undef PRECISION
+#undef MAIN_TYPE
+#undef MAIN_TYPE_SIZE
+#undef UNION_TYPE
+#undef IF_128
+#undef IF_MAIN_TYPE
+#undef SHIFT_CONST1
+#undef SHIFT_CONST2
+#undef SHIFT_CONST3
+#undef _128_TYPE
+#undef SIMD_TYPE
+#undef AVX_LENGTH
+#undef HAP_TYPE
+#undef MASK_TYPE
+#undef MASK_ALL_ONES
+
+#undef VEC_EXTRACT_UNIT
+#undef VEC_INSERT_UNIT
+#undef SET_VEC_ZERO
+#undef VEC_OR
+#undef VEC_ADD
+#undef VEC_SUB
+#undef VEC_MUL
+#undef VEC_DIV
+#undef VEC_BLEND
+#undef VEC_BLENDV
+#undef VEC_CAST_256_128
+#undef VEC_EXTRACT_128
+#undef VEC_EXTRACT_UNIT
+#undef VEC_SET1_VAL128
+#undef VEC_MOVE
+#undef VEC_CAST_128_256
+#undef VEC_INSERT_VAL
+#undef VEC_CVT_128_256
+#undef VEC_SET1_VAL
+#undef VEC_POPCVT_CHAR
+#undef VEC_LDPOPCVT_CHAR
+#undef VEC_CMP_EQ
+#undef VEC_SET_LSE
+#undef SHIFT_HAP
+#undef MASK_VEC
+#undef VEC_SSE_TO_AVX
+#undef VEC_SHIFT_LEFT_1BIT
+#undef MASK_ALL_ONES
+#undef COMPARE_VECS
+#undef _256_INT_TYPE
+#undef BITMASK_VEC
+#endif
+
+#define SSE
+#define PRECISION d
+
+#define MAIN_TYPE double
+#define MAIN_TYPE_SIZE 64
+#define UNION_TYPE mix_D128
+#define IF_128 IF_128d
+#define IF_MAIN_TYPE IF_64
+#define SHIFT_CONST1 1
+#define SHIFT_CONST2 8
+#define SHIFT_CONST3 0
+#define _128_TYPE __m128d
+#define SIMD_TYPE __m128d
+#define _256_INT_TYPE __m128i
+#define AVX_LENGTH 2
+#define HAP_TYPE __m128i
+#define MASK_TYPE uint64_t
+#define MASK_ALL_ONES 0xFFFFFFFFFFFFFFFFL
+#define MASK_VEC MaskVec_D
+
+#define VEC_EXTRACT_UNIT(__v1, __im) \
+ _mm_extract_epi64(__v1, __im)
+
+#define VEC_INSERT_UNIT(__v1,__ins,__im) \
+ _mm_insert_epi64(__v1,__ins,__im)
+
+#define VEC_OR(__v1, __v2) \
+ _mm_or_pd(__v1, __v2)
+
+#define VEC_ADD(__v1, __v2) \
+ _mm_add_pd(__v1, __v2)
+
+#define VEC_SUB(__v1, __v2) \
+ _mm_sub_pd(__v1, __v2)
+
+#define VEC_MUL(__v1, __v2) \
+ _mm_mul_pd(__v1, __v2)
+
+#define VEC_DIV(__v1, __v2) \
+ _mm_div_pd(__v1, __v2)
+
+#define VEC_CMP_EQ(__v1, __v2) \
+ _mm_cmpeq_pd(__v1, __v2)
+
+#define VEC_BLEND(__v1, __v2, __mask) \
+ _mm_blend_pd(__v1, __v2, __mask)
+
+#define VEC_BLENDV(__v1, __v2, __maskV) \
+ _mm_blendv_pd(__v1, __v2, __maskV)
+
+#define SHIFT_HAP(__v1, __val) \
+ __v1 = _mm_insert_epi32(_mm_slli_si128(__v1, 4), __val.i, 0)
+
+#define VEC_CVT_128_256(__v1) \
+ _mm_cvtepi32_pd(__v1)
+
+#define VEC_SET1_VAL(__val) \
+ _mm_set1_pd(__val)
+
+#define VEC_POPCVT_CHAR(__ch) \
+ _mm_cvtepi32_pd(_mm_set1_epi32(__ch))
+
+#define VEC_SET_LSE(__val) \
+ _mm_set_pd(zero, __val);
+
+#define VEC_LDPOPCVT_CHAR(__addr) \
+ _mm_cvtepi32_pd(_mm_loadu_si128((__m128i const *)__addr))
+
+#define VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) \
+ __vdst = _mm_castsi128_pd(_mm_set_epi64(__vsHigh, __vsLow))
+
+#define VEC_SHIFT_LEFT_1BIT(__vs) \
+ __vs = _mm_slli_epi64(__vs, 1)
+
+
+class BitMaskVec_sse_double {
+
+ MASK_VEC combined_ ;
+ public:
+ inline MASK_TYPE& getLowEntry(int index) {
+ return combined_.masks[index] ;
+ }
+ inline MASK_TYPE& getHighEntry(int index) {
+ return combined_.masks[AVX_LENGTH/2+index] ;
+ }
+
+ inline const SIMD_TYPE& getCombinedMask() {
+ return combined_.vecf ;
+ }
+
+ inline void shift_left_1bit() {
+ VEC_SHIFT_LEFT_1BIT(combined_.vec) ;
+ }
+
+} ;
+
+#define BITMASK_VEC BitMaskVec_sse_double
+
diff --git a/public/VectorPairHMM/src/main/c++/define-sse-float.h b/public/VectorPairHMM/src/main/c++/define-sse-float.h
new file mode 100644
index 0000000..e9371c0
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/define-sse-float.h
@@ -0,0 +1,173 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifdef PRECISION
+#undef PRECISION
+#undef MAIN_TYPE
+#undef MAIN_TYPE_SIZE
+#undef UNION_TYPE
+#undef IF_128
+#undef IF_MAIN_TYPE
+#undef SHIFT_CONST1
+#undef SHIFT_CONST2
+#undef SHIFT_CONST3
+#undef _128_TYPE
+#undef SIMD_TYPE
+#undef AVX_LENGTH
+#undef HAP_TYPE
+#undef MASK_TYPE
+#undef MASK_ALL_ONES
+
+#undef VEC_EXTRACT_UNIT
+#undef VEC_INSERT_UNIT
+#undef SET_VEC_ZERO
+#undef VEC_OR
+#undef VEC_ADD
+#undef VEC_SUB
+#undef VEC_MUL
+#undef VEC_DIV
+#undef VEC_BLEND
+#undef VEC_BLENDV
+#undef VEC_CAST_256_128
+#undef VEC_EXTRACT_128
+#undef VEC_EXTRACT_UNIT
+#undef VEC_SET1_VAL128
+#undef VEC_MOVE
+#undef VEC_CAST_128_256
+#undef VEC_INSERT_VAL
+#undef VEC_CVT_128_256
+#undef VEC_SET1_VAL
+#undef VEC_POPCVT_CHAR
+#undef VEC_LDPOPCVT_CHAR
+#undef VEC_CMP_EQ
+#undef VEC_SET_LSE
+#undef SHIFT_HAP
+#undef MASK_VEC
+#undef VEC_SSE_TO_AVX
+#undef VEC_SHIFT_LEFT_1BIT
+#undef MASK_ALL_ONES
+#undef COMPARE_VECS
+#undef _256_INT_TYPE
+#undef BITMASK_VEC
+#endif
+
+#define SSE
+#define PRECISION s
+
+#define MAIN_TYPE float
+#define MAIN_TYPE_SIZE 32
+#define UNION_TYPE mix_F128
+#define IF_128 IF_128f
+#define IF_MAIN_TYPE IF_32
+#define SHIFT_CONST1 3
+#define SHIFT_CONST2 4
+#define SHIFT_CONST3 0
+#define _128_TYPE __m128
+#define SIMD_TYPE __m128
+#define _256_INT_TYPE __m128i
+#define AVX_LENGTH 4
+//#define MAVX_COUNT (MROWS+3)/AVX_LENGTH
+#define HAP_TYPE UNION_TYPE
+#define MASK_TYPE uint32_t
+#define MASK_ALL_ONES 0xFFFFFFFF
+#define MASK_VEC MaskVec_F
+
+#define VEC_EXTRACT_UNIT(__v1, __im) \
+ _mm_extract_epi32(__v1, __im)
+
+#define VEC_INSERT_UNIT(__v1,__ins,__im) \
+ _mm_insert_epi32(__v1,__ins,__im)
+
+#define VEC_OR(__v1, __v2) \
+ _mm_or_ps(__v1, __v2)
+
+#define VEC_ADD(__v1, __v2) \
+ _mm_add_ps(__v1, __v2)
+
+#define VEC_SUB(__v1, __v2) \
+ _mm_sub_ps(__v1, __v2)
+
+#define VEC_MUL(__v1, __v2) \
+ _mm_mul_ps(__v1, __v2)
+
+#define VEC_DIV(__v1, __v2) \
+ _mm_div_ps(__v1, __v2)
+
+#define VEC_CMP_EQ(__v1, __v2) \
+ _mm_cmpeq_ps(__v1, __v2)
+
+#define VEC_BLEND(__v1, __v2, __mask) \
+ _mm_blend_ps(__v1, __v2, __mask)
+
+#define VEC_BLENDV(__v1, __v2, __maskV) \
+ _mm_blendv_ps(__v1, __v2, __maskV)
+
+#define SHIFT_HAP(__v1, __val) \
+ _vector_shift_lastsses(__v1, __val.f)
+
+#define VEC_CVT_128_256(__v1) \
+ _mm_cvtepi32_ps(__v1.i)
+
+#define VEC_SET1_VAL(__val) \
+ _mm_set1_ps(__val)
+
+#define VEC_POPCVT_CHAR(__ch) \
+ _mm_cvtepi32_ps(_mm_set1_epi32(__ch))
+
+#define VEC_SET_LSE(__val) \
+ _mm_set_ps(zero, zero, zero, __val);
+
+#define VEC_LDPOPCVT_CHAR(__addr) \
+ _mm_cvtepi32_ps(_mm_loadu_si128((__m128i const *)__addr))
+
+#define VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) \
+ __vdst = _mm_cvtpi32x2_ps(__vsLow, __vsHigh)
+
+#define VEC_SHIFT_LEFT_1BIT(__vs) \
+ __vs = _mm_slli_epi32(__vs, 1)
+
+class BitMaskVec_sse_float {
+
+ MASK_VEC combined_ ;
+
+ public:
+ inline MASK_TYPE& getLowEntry(int index) {
+ return combined_.masks[index] ;
+ }
+ inline MASK_TYPE& getHighEntry(int index) {
+ return combined_.masks[AVX_LENGTH/2+index] ;
+ }
+
+ inline const SIMD_TYPE& getCombinedMask() {
+ return combined_.vecf ;
+ }
+
+ inline void shift_left_1bit() {
+ VEC_SHIFT_LEFT_1BIT(combined_.vec) ;
+ }
+
+} ;
+
+#define BITMASK_VEC BitMaskVec_sse_float
diff --git a/public/VectorPairHMM/src/main/c++/headers.h b/public/VectorPairHMM/src/main/c++/headers.h
new file mode 100644
index 0000000..4a0d89b
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/headers.h
@@ -0,0 +1,71 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef COMMON_HEADERS_H
+#define COMMON_HEADERS_H
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include <sys/time.h>
+
+#include <immintrin.h>
+#include <emmintrin.h>
+#include <omp.h>
+
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <vector>
+#include <map>
+#include <set>
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <cmath>
+#include <fenv.h>
+
+extern uint64_t exceptions_array[128];
+extern FILE* g_debug_fptr;
+#define STORE_FP_EXCEPTIONS(flagp, exceptions_array) \
+ fegetexceptflag(&flagp, FE_ALL_EXCEPT | __FE_DENORM); \
+ exceptions_array[FE_INVALID] += ((flagp & FE_INVALID)); \
+ exceptions_array[__FE_DENORM] += ((flagp & __FE_DENORM) >> 1); \
+ exceptions_array[FE_DIVBYZERO] += ((flagp & FE_DIVBYZERO) >> 2); \
+ exceptions_array[FE_OVERFLOW] += ((flagp & FE_OVERFLOW) >> 3); \
+ exceptions_array[FE_UNDERFLOW] += ((flagp & FE_UNDERFLOW) >> 4); \
+ feclearexcept(FE_ALL_EXCEPT | __FE_DENORM);
+
+#define CONVERT_AND_PRINT(X) \
+ g_converter.f = (X); \
+ fwrite(&(g_converter.i),4,1,g_debug_fptr); \
+
+#endif
diff --git a/public/VectorPairHMM/src/main/c++/jni_common.h b/public/VectorPairHMM/src/main/c++/jni_common.h
new file mode 100644
index 0000000..b3139d4
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/jni_common.h
@@ -0,0 +1,60 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef JNI_COMMON_H
+#define JNI_COMMON_H
+
+/*#define SINGLE_THREADED_ONLY 1*/
+#include <jni.h>
+/*#define ENABLE_ASSERTIONS 1*/
+#ifdef SINGLE_THREADED_ONLY
+#define DO_PROFILING 1
+#endif
+/*#define DEBUG0_1 1*/
+/*#define DEBUG3 1*/
+/*#define DUMP_TO_SANDBOX 1*/
+
+
+/*#define DIRECT_ACCESS_TO_JAVA_HEAP_MEMORY 1*/
+
+#ifdef DIRECT_ACCESS_TO_JAVA_HEAP_MEMORY
+//Gets direct access to Java arrays
+#define GET_BYTE_ARRAY_ELEMENTS env->GetPrimitiveArrayCritical
+#define RELEASE_BYTE_ARRAY_ELEMENTS env->ReleasePrimitiveArrayCritical
+#define JNI_RO_RELEASE_MODE JNI_ABORT
+#define GET_DOUBLE_ARRAY_ELEMENTS env->GetPrimitiveArrayCritical
+#define RELEASE_DOUBLE_ARRAY_ELEMENTS env->ReleasePrimitiveArrayCritical
+
+#else
+//Likely makes copy of Java arrays to JNI C++ space
+#define GET_BYTE_ARRAY_ELEMENTS env->GetByteArrayElements
+#define RELEASE_BYTE_ARRAY_ELEMENTS env->ReleaseByteArrayElements
+#define JNI_RO_RELEASE_MODE JNI_ABORT
+#define GET_DOUBLE_ARRAY_ELEMENTS env->GetDoubleArrayElements
+#define RELEASE_DOUBLE_ARRAY_ELEMENTS env->ReleaseDoubleArrayElements
+
+#endif //ifdef DIRECT_ACCESS_TO_JAVA_HEAP_MEMORY
+
+#endif //ifndef JNI_COMMON_H
diff --git a/public/VectorPairHMM/src/main/c++/jnidebug.h b/public/VectorPairHMM/src/main/c++/jnidebug.h
new file mode 100644
index 0000000..df2e207
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/jnidebug.h
@@ -0,0 +1,191 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef JNI_DEBUG_H
+#define JNI_DEBUG_H
+
+template<class NUMBER>
+class DataHolder
+{
+#define INIT_MATRIX(X) \
+ X = new NUMBER*[m_paddedMaxReadLength]; \
+ for(int i=0;i<m_paddedMaxReadLength;++i) \
+ { \
+ X[i] = new NUMBER[m_paddedMaxHaplotypeLength]; \
+ for(int j=0;j<m_paddedMaxHaplotypeLength;++j) \
+ X[i][j] = (NUMBER)0; \
+ }
+
+#define FREE_MATRIX(X) \
+ for(int i=0;i<m_paddedMaxReadLength;++i) \
+ delete[] X[i]; \
+ delete[] X;
+
+ public:
+ DataHolder() { m_is_initialized = false; }
+ void initialize(int readMaxLength, int haplotypeMaxLength)
+ {
+ if(m_is_initialized)
+ {
+ FREE_MATRIX(m_matchMatrix);
+ FREE_MATRIX(m_insertionMatrix);
+ FREE_MATRIX(m_deletionMatrix);
+ FREE_MATRIX(m_prior);
+ delete[] m_transition;
+ }
+
+ m_readMaxLength = readMaxLength;
+ m_haplotypeMaxLength = haplotypeMaxLength;
+ m_paddedMaxReadLength = readMaxLength + 1;
+ m_paddedMaxHaplotypeLength = haplotypeMaxLength + 1;
+
+ INIT_MATRIX(m_matchMatrix);
+ INIT_MATRIX(m_insertionMatrix);
+ INIT_MATRIX(m_deletionMatrix);
+ INIT_MATRIX(m_prior);
+ m_transition = new NUMBER[m_paddedMaxReadLength][6];
+ for(int i=0;i<m_paddedMaxReadLength;++i)
+ for(int j=0;j<6;++j)
+ m_transition[i][j] = (NUMBER)0;
+ m_is_initialized = true;
+ }
+
+ //Corresponds to initializeProbabilities
+ void initializeProbabilities(jint length, jbyte* insertionGOP, jbyte* deletionGOP, jbyte* overallGCP)
+ {
+ static unsigned g_num_prob_init = 0;
+ Context<NUMBER> ctx;
+ for (int r = 1; r <= length;r++) //in original code, r < ROWS (where ROWS = paddedReadLength)
+ {
+ int _i = insertionGOP[r-1]; //insertionGOP
+ int _d = deletionGOP[r-1]; //deletionGOP
+ int _c = overallGCP[r-1]; //overallGCP
+ m_transition[r][MM] = ctx._(1.0) - ctx.ph2pr[(_i + _d) & 127]; //lines 161-162
+ m_transition[r][GapM] = ctx._(1.0) - ctx.ph2pr[_c]; //line 163
+ m_transition[r][MX] = ctx.ph2pr[_i]; //164
+ m_transition[r][XX] = ctx.ph2pr[_c]; //165
+ m_transition[r][MY] = ctx.ph2pr[_d];//last row seems different, compared to line 166
+ m_transition[r][YY] = ctx.ph2pr[_c];//same as above for line 167
+ //m_transition[r][MY] = (r == length) ? ctx._(1.0) : ctx.ph2pr[_d];//last row seems different, compared to line 166
+ //m_transition[r][YY] = (r == length) ? ctx._(1.0) : ctx.ph2pr[_c];//same as above for line 167
+#ifdef DEBUG3
+ for(int j=0;j<6;++j)
+ debug_dump("transitions_jni.txt", to_string(m_transition[r][j]),true);
+#endif
+ }
+ ++g_num_prob_init;
+ }
+ bool m_is_initialized;
+ int m_readMaxLength;
+ int m_haplotypeMaxLength;
+ int m_paddedMaxReadLength;
+ int m_paddedMaxHaplotypeLength;
+ NUMBER** m_matchMatrix;
+ NUMBER** m_insertionMatrix;
+ NUMBER** m_deletionMatrix;
+ NUMBER** m_prior;
+ NUMBER (*m_transition)[6];
+};
+extern DataHolder<double> g_double_dataholder;
+
+template<class NUMBER>
+NUMBER compute_full_prob(testcase *tc, NUMBER** M, NUMBER** X, NUMBER** Y, NUMBER (*p)[6],
+ bool do_initialization, jint hapStartIndex, NUMBER *before_last_log = NULL)
+{
+ int r, c;
+ int ROWS = tc->rslen + 1; //ROWS = paddedReadLength
+ int COLS = tc->haplen + 1; //COLS = paddedHaplotypeLength
+
+ Context<NUMBER> ctx;
+ //////NOTES
+ ////ctx.ph2pr[quality]; //This quantity is QualityUtils.qualToErrorProb(quality)
+ ////1-ctx.ph2pr[quality]; //This corresponds to QualityUtils.qualToProb(quality);
+
+ //Initialization
+ if(do_initialization)
+ {
+ for (c = 0; c < COLS; c++)
+ {
+ M[0][c] = ctx._(0.0);
+ X[0][c] = ctx._(0.0);
+ Y[0][c] = ctx.INITIAL_CONSTANT / (tc->haplen); //code from 87-90 in LoglessPairHMM
+ }
+
+ for (r = 1; r < ROWS; r++)
+ {
+ M[r][0] = ctx._(0.0);
+ //deletionMatrix row 0 in above nest is initialized in the Java code
+ //However, insertionMatrix column 0 is not initialized in Java code, could it be that
+ //values are re-used from a previous iteration?
+ //Why even do this, X[0][0] = 0 from above loop nest, X[idx][0] = 0 from this computation
+ X[r][0] = X[r-1][0] * p[r][XX];
+ Y[r][0] = ctx._(0.0);
+ }
+ }
+
+ for (r = 1; r < ROWS; r++)
+ for (c = hapStartIndex+1; c < COLS; c++)
+ {
+ //The following lines correspond to initializePriors()
+ char _rs = tc->rs[r-1]; //line 137
+ char _hap = tc->hap[c-1]; //line 140
+ //int _q = tc->q[r-1] & 127; //line 138 - q is the quality (qual), should be byte hence int ANDed with 0xFF
+ int _q = tc->q[r-1]; //line 138 - q is the quality (qual), should be byte hence int ANDed with 0xFF
+ NUMBER distm = ctx.ph2pr[_q]; //This quantity is QualityUtils.qualToErrorProb(_q)
+ //The assumption here is that doNotUseTristateCorrection is true
+ //TOASK
+ if (_rs == _hap || _rs == 'N' || _hap == 'N')
+ distm = ctx._(1.0) - distm; //This is the quantity QualityUtils.qualToProb(qual)
+ else
+ distm = distm/3;
+#ifdef DEBUG3
+ debug_dump("priors_jni.txt",to_string(distm),true);
+#endif
+
+ //Computation inside updateCell
+ M[r][c] = distm * (M[r-1][c-1] * p[r][MM] + X[r-1][c-1] * p[r][GapM] + Y[r-1][c-1] * p[r][GapM]);
+ X[r][c] = M[r-1][c] * p[r][MX] + X[r-1][c] * p[r][XX];
+ Y[r][c] = M[r][c-1] * p[r][MY] + Y[r][c-1] * p[r][YY];
+#ifdef DEBUG3
+ debug_dump("matrices_jni.txt",to_string(M[r][c]),true);
+ debug_dump("matrices_jni.txt",to_string(X[r][c]),true);
+ debug_dump("matrices_jni.txt",to_string(Y[r][c]),true);
+#endif
+ }
+
+ NUMBER result = ctx._(0.0);
+ for (c = 0; c < COLS; c++)
+ result += M[ROWS-1][c] + X[ROWS-1][c];
+
+ if (before_last_log != NULL)
+ *before_last_log = result;
+
+#ifdef DEBUG
+ debug_dump("return_values_jni.txt",to_string(ctx.LOG10(result) - ctx.LOG10_INITIAL_CONSTANT),true);
+#endif
+ return ctx.LOG10(result) - ctx.LOG10_INITIAL_CONSTANT;
+}
+
+#endif
diff --git a/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc b/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc
new file mode 100644
index 0000000..42a9237
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.cc
@@ -0,0 +1,175 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include "headers.h"
+#include "jni_common.h"
+#include "org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.h"
+#include "utils.h"
+#include "LoadTimeInitializer.h"
+#include "jnidebug.h"
+DataHolder<double> g_double_dataholder;
+
+using namespace std;
+
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniInitialize
+(JNIEnv* env, jobject thisObject,
+ jint readMaxLength, jint haplotypeMaxLength)
+{
+ static int g_num_init_calls = 0;
+#ifdef DEBUG3
+ cout << "Entered alloc initialized .. readMaxLength "<<readMaxLength<<" haplotypeMaxLength "<<haplotypeMaxLength<<"\n";
+#endif
+ g_double_dataholder.initialize(readMaxLength, haplotypeMaxLength);
+#ifdef DEBUG3
+ debug_dump("lengths_jni.txt", to_string(readMaxLength)+" "+to_string(haplotypeMaxLength),true);
+#endif
+ ++g_num_init_calls;
+}
+
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniInitializeProbabilities
+(JNIEnv* env, jclass thisObject,
+ jobjectArray transition, jbyteArray insertionGOP, jbyteArray deletionGOP, jbyteArray overallGCP
+ )
+{
+ jboolean is_copy = JNI_FALSE;
+ jsize length = (env)->GetArrayLength(insertionGOP);
+#ifdef DEBUG3
+ cout << "Entered initializeProbabilities .. length "<<length<<"\n";
+#endif
+ jbyte* insertionGOPArray = (env)->GetByteArrayElements(insertionGOP, &is_copy);
+ jbyte* deletionGOPArray = (env)->GetByteArrayElements(deletionGOP, &is_copy);
+ jbyte* overallGCPArray = (env)->GetByteArrayElements(overallGCP, &is_copy);
+#ifdef DEBUG
+ if(insertionGOPArray == 0)
+ cerr << "insertionGOP array not initialized in JNI\n";
+ ////assert(insertionGOPArray && "insertionGOP array not initialized in JNI");
+ if(deletionGOPArray == 0)
+ cerr << "deletionGOP array not initialized in JNI\n";
+ ////assert(deletionGOPArray && "deletionGOP array not initialized in JNI");
+ assert(overallGCPArray && "OverallGCP array not initialized in JNI");
+#endif
+
+ g_double_dataholder.initializeProbabilities(length, insertionGOPArray, deletionGOPArray, overallGCPArray);
+
+ env->ReleaseByteArrayElements(overallGCP, overallGCPArray, JNI_ABORT);
+ env->ReleaseByteArrayElements(deletionGOP, deletionGOPArray, JNI_ABORT);
+ env->ReleaseByteArrayElements(insertionGOP, insertionGOPArray, JNI_ABORT);
+}
+
+JNIEXPORT jdouble JNICALL
+Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniInitializePriorsAndUpdateCells(
+ JNIEnv* env, jobject thisObject,
+ jboolean doInitialization, jint paddedReadLength, jint paddedHaplotypeLength,
+ jbyteArray readBases, jbyteArray haplotypeBases, jbyteArray readQuals,
+ jint hapStartIndex
+ )
+{
+#ifdef DEBUG3
+ cout << "Entered mainCompute .. doInitialization "<<(doInitialization == JNI_TRUE)<<" hapStartIndex "<<hapStartIndex<<"\n";
+ cout << "mainCompute padded lengths "<< paddedReadLength << " " << paddedHaplotypeLength <<"\n";
+#endif
+ jboolean is_copy = JNI_FALSE;
+ jbyte* readBasesArray = (env)->GetByteArrayElements(readBases, &is_copy);
+ jbyte* haplotypeBasesArray = (env)->GetByteArrayElements(haplotypeBases, &is_copy);
+ jbyte* readQualsArray = (env)->GetByteArrayElements(readQuals, &is_copy);
+#ifdef DEBUG
+ assert(readBasesArray && "readBasesArray not initialized in JNI");
+ assert(haplotypeBasesArray && "haplotypeBasesArray not initialized in JNI");
+ assert(readQualsArray && "readQualsArray not initialized in JNI");
+#endif
+ testcase tc;
+
+ tc.rslen = paddedReadLength-1;
+ tc.haplen = paddedHaplotypeLength-1;
+
+ tc.rs = (char*)readBasesArray;
+ tc.hap = (char*)haplotypeBasesArray;
+ tc.q = (char*)readQualsArray; //TOASK - q is now char*
+
+ compute_full_prob<double>(&tc, g_double_dataholder.m_matchMatrix, g_double_dataholder.m_insertionMatrix,
+ g_double_dataholder.m_deletionMatrix, g_double_dataholder.m_transition,
+ doInitialization == JNI_TRUE, hapStartIndex, NULL);
+
+ env->ReleaseByteArrayElements(readBases, readBasesArray, JNI_ABORT);
+ env->ReleaseByteArrayElements(haplotypeBases, haplotypeBasesArray, JNI_ABORT);
+ env->ReleaseByteArrayElements(readQuals, readQualsArray, JNI_ABORT);
+ return 0.0;
+}
+
+JNIEXPORT jdouble JNICALL
+Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniSubComputeReadLikelihoodGivenHaplotypeLog10(
+ JNIEnv* env, jobject thisObject,
+ jint readLength, jint haplotypeLength,
+ jbyteArray readBases, jbyteArray haplotypeBases, jbyteArray readQuals,
+ jbyteArray insertionGOP, jbyteArray deletionGOP, jbyteArray overallGCP,
+ jint hapStartIndex
+ )
+{
+ jboolean is_copy = JNI_FALSE;
+ jbyte* readBasesArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(readBases, &is_copy);
+ jbyte* haplotypeBasesArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(haplotypeBases, &is_copy);
+ jbyte* readQualsArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(readQuals, &is_copy);
+ jbyte* insertionGOPArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(insertionGOP, &is_copy);
+ jbyte* deletionGOPArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(deletionGOP, &is_copy);
+ jbyte* overallGCPArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(overallGCP, &is_copy);
+#ifdef DEBUG
+ assert(readBasesArray && "readBasesArray not initialized in JNI");
+ assert(haplotypeBasesArray && "haplotypeBasesArray not initialized in JNI");
+ assert(readQualsArray && "readQualsArray not initialized in JNI");
+ assert(insertionGOPArray && "insertionGOP array not initialized in JNI");
+ assert(deletionGOPArray && "deletionGOP array not initialized in JNI");
+ assert(overallGCPArray && "OverallGCP array not initialized in JNI");
+ //assert(readLength < MROWS);
+#endif
+ testcase tc;
+ tc.rslen = readLength;
+ tc.haplen = haplotypeLength;
+ tc.rs = (char*)readBasesArray;
+ tc.hap = (char*)haplotypeBasesArray;
+ for(unsigned i=0;i<readLength;++i)
+ {
+ tc.q[i] = (int)readQualsArray[i];
+ tc.i[i] = (int)insertionGOPArray[i];
+ tc.d[i] = (int)deletionGOPArray[i];
+ tc.c[i] = (int)overallGCPArray[i];
+ }
+
+ double result_avxd = g_compute_full_prob_double(&tc, 0);
+ double result = log10(result_avxd) - log10(ldexp(1.0, 1020));
+#ifdef DEBUG
+ g_load_time_initializer.debug_dump("return_values_jni.txt",to_string(result),true);
+#endif
+
+
+ RELEASE_BYTE_ARRAY_ELEMENTS(overallGCP, overallGCPArray, JNI_RO_RELEASE_MODE);
+ RELEASE_BYTE_ARRAY_ELEMENTS(deletionGOP, deletionGOPArray, JNI_RO_RELEASE_MODE);
+ RELEASE_BYTE_ARRAY_ELEMENTS(insertionGOP, insertionGOPArray, JNI_RO_RELEASE_MODE);
+ RELEASE_BYTE_ARRAY_ELEMENTS(readQuals, readQualsArray, JNI_RO_RELEASE_MODE);
+ RELEASE_BYTE_ARRAY_ELEMENTS(haplotypeBases, haplotypeBasesArray, JNI_RO_RELEASE_MODE);
+ RELEASE_BYTE_ARRAY_ELEMENTS(readBases, readBasesArray, JNI_RO_RELEASE_MODE);
+
+ return 0.0;
+}
+
diff --git a/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.h b/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.h
new file mode 100644
index 0000000..6fb440c
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM.h
@@ -0,0 +1,86 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM */
+
+#ifndef _Included_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM
+#define _Included_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_TRISTATE_CORRECTION
+#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_TRISTATE_CORRECTION 3.0
+#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_dumpSandboxOnly
+#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_dumpSandboxOnly 0L
+#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug
+#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug 0L
+#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_verify
+#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_verify 1L
+#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug0_1
+#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug0_1 0L
+#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug1
+#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug1 0L
+#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug2
+#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug2 0L
+#undef org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug3
+#define org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_debug3 0L
+/*
+ * Class: org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM
+ * Method: jniInitialize
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniInitialize
+ (JNIEnv *, jobject, jint, jint);
+
+/*
+ * Class: org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM
+ * Method: jniInitializeProbabilities
+ * Signature: ([[D[B[B[B)V
+ */
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniInitializeProbabilities
+ (JNIEnv *, jclass, jobjectArray, jbyteArray, jbyteArray, jbyteArray);
+
+/*
+ * Class: org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM
+ * Method: jniInitializePriorsAndUpdateCells
+ * Signature: (ZII[B[B[BI)D
+ */
+JNIEXPORT jdouble JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniInitializePriorsAndUpdateCells
+ (JNIEnv *, jobject, jboolean, jint, jint, jbyteArray, jbyteArray, jbyteArray, jint);
+
+/*
+ * Class: org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM
+ * Method: jniSubComputeReadLikelihoodGivenHaplotypeLog10
+ * Signature: (II[B[B[B[B[B[BI)D
+ */
+JNIEXPORT jdouble JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_DebugJNILoglessPairHMM_jniSubComputeReadLikelihoodGivenHaplotypeLog10
+ (JNIEnv *, jobject, jint, jint, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jbyteArray, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc b/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc
new file mode 100644
index 0000000..d9d2684
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.cc
@@ -0,0 +1,416 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include "headers.h"
+#include "jni_common.h"
+#include "org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.h"
+//#include "template.h"
+#include "utils.h"
+#include "LoadTimeInitializer.h"
+
+using namespace std;
+
+JNIEXPORT jlong JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniGetMachineType
+ (JNIEnv* env, jobject thisObject)
+{
+ return (jlong)get_machine_capabilities();
+}
+
+//Should be called only once for the whole Java process - initializes field ids for the classes JNIReadDataHolderClass
+//and JNIHaplotypeDataHolderClass
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeClassFieldsAndMachineMask
+ (JNIEnv* env, jobject thisObject, jclass readDataHolderClass, jclass haplotypeDataHolderClass, jlong mask)
+{
+ assert(readDataHolderClass);
+ assert(haplotypeDataHolderClass);
+ jfieldID fid;
+ fid = env->GetFieldID(readDataHolderClass, "readBases", "[B");
+ assert(fid && "JNI pairHMM: Could not get FID for readBases");
+ g_load_time_initializer.m_readBasesFID = fid;
+ fid = env->GetFieldID(readDataHolderClass, "readQuals", "[B");
+ assert(fid && "JNI pairHMM: Could not get FID for readQuals");
+ g_load_time_initializer.m_readQualsFID = fid;
+ fid = env->GetFieldID(readDataHolderClass, "insertionGOP", "[B");
+ assert(fid && "JNI pairHMM: Could not get FID for insertionGOP");
+ g_load_time_initializer.m_insertionGOPFID = fid;
+ fid = env->GetFieldID(readDataHolderClass, "deletionGOP", "[B");
+ assert(fid && "JNI pairHMM: Could not get FID for deletionGOP");
+ g_load_time_initializer.m_deletionGOPFID = fid;
+ fid = env->GetFieldID(readDataHolderClass, "overallGCP", "[B");
+ assert(fid && "JNI pairHMM: Could not get FID for overallGCP");
+ g_load_time_initializer.m_overallGCPFID = fid;
+
+ fid = env->GetFieldID(haplotypeDataHolderClass, "haplotypeBases", "[B");
+ assert(fid && "JNI pairHMM: Could not get FID for haplotypeBases");
+ g_load_time_initializer.m_haplotypeBasesFID = fid;
+ if(mask != ENABLE_ALL_HARDWARE_FEATURES)
+ {
+ cout << "Using user supplied hardware mask to re-initialize function pointers for PairHMM\n";
+ initialize_function_pointers((uint64_t)mask);
+ cout.flush();
+ }
+}
+
+JNIEXPORT void JNICALL initializeHaplotypes
+ (JNIEnv * env, jobject& thisObject, jint numHaplotypes, jobjectArray& haplotypeDataArray,
+ vector<pair<jbyteArray, jbyte*> >& haplotypeBasesArrayVector, vector<unsigned>& haplotypeBasesLengths)
+{
+ jboolean is_copy = JNI_FALSE;
+ haplotypeBasesArrayVector.clear();
+ haplotypeBasesLengths.clear();
+ haplotypeBasesArrayVector.resize(numHaplotypes);
+ haplotypeBasesLengths.resize(numHaplotypes);
+ jsize haplotypeBasesLength = 0;
+ for(unsigned j=0;j<numHaplotypes;++j)
+ {
+ jobject haplotypeObject = env->GetObjectArrayElement(haplotypeDataArray, j);
+ jbyteArray haplotypeBases = (jbyteArray)env->GetObjectField(haplotypeObject, g_load_time_initializer.m_haplotypeBasesFID);
+#ifdef ENABLE_ASSERTIONS
+ assert(haplotypeBases && ("haplotypeBases is NULL at index : "+to_string(j)+"\n").c_str());
+#endif
+ //Need a global reference as this will be accessed across multiple JNI calls to JNIComputeLikelihoods()
+ jbyteArray haplotypeBasesGlobalRef = (jbyteArray)env->NewGlobalRef(haplotypeBases);
+#ifdef ENABLE_ASSERTIONS
+ assert(haplotypeBasesGlobalRef && ("Could not get global ref to haplotypeBases at index : "+to_string(j)+"\n").c_str());
+#endif
+ env->DeleteLocalRef(haplotypeBases); //free the local reference
+ jbyte* haplotypeBasesArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(haplotypeBasesGlobalRef, &is_copy);
+ haplotypeBasesLength = env->GetArrayLength(haplotypeBasesGlobalRef);
+#ifdef ENABLE_ASSERTIONS
+ assert(haplotypeBasesArray && "haplotypeBasesArray not initialized in JNI");
+ //assert(haplotypeBasesLength < MCOLS);
+#endif
+#ifdef DEBUG0_1
+ cout << "JNI haplotype length "<<haplotypeBasesLength<<"\n";
+#endif
+ haplotypeBasesArrayVector[j] = make_pair(haplotypeBasesGlobalRef, haplotypeBasesArray);
+ haplotypeBasesLengths[j] = haplotypeBasesLength;
+#ifdef DEBUG3
+ for(unsigned k=0;k<haplotypeBasesLength;++k)
+ g_load_time_initializer.debug_dump("haplotype_bases_jni.txt",to_string((int)haplotypeBasesArray[k]),true);
+#endif
+#ifdef DO_PROFILING
+ g_load_time_initializer.update_stat(HAPLOTYPE_LENGTH_IDX, haplotypeBasesLength);
+ g_load_time_initializer.m_bytes_copied += (is_copy ? haplotypeBasesLength : 0);
+#endif
+ }
+}
+
+JNIEXPORT void JNICALL releaseHaplotypes(JNIEnv * env, jobject thisObject,
+ vector<pair<jbyteArray, jbyte*> >& haplotypeBasesArrayVector, vector<unsigned>& haplotypeBasesLengths
+ )
+{
+ //Now release haplotype arrays
+ for(int j=haplotypeBasesArrayVector.size()-1;j>=0;--j) //note the order - reverse of GET
+ {
+ RELEASE_BYTE_ARRAY_ELEMENTS(haplotypeBasesArrayVector[j].first, haplotypeBasesArrayVector[j].second, JNI_RO_RELEASE_MODE);
+ env->DeleteGlobalRef(haplotypeBasesArrayVector[j].first); //free the global reference
+ }
+ haplotypeBasesArrayVector.clear();
+ haplotypeBasesLengths.clear();
+}
+
+
+vector<pair<jbyteArray, jbyte*> > g_haplotypeBasesArrayVector;
+vector<unsigned> g_haplotypeBasesLengths;
+//Since the list of haplotypes against which the reads are evaluated in PairHMM is the same for a region,
+//transfer the list only once
+//Works only for ST case as the haplotype data is stored in global variables
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeHaplotypes
+ (JNIEnv * env, jobject thisObject, jint numHaplotypes, jobjectArray haplotypeDataArray)
+{
+#ifdef SINGLE_THREADED_ONLY
+ //To ensure, GET_BYTE_ARRAY_ELEMENTS is invoked only once for each haplotype, store bytearrays in a vector
+ initializeHaplotypes(env, thisObject, numHaplotypes, haplotypeDataArray, g_haplotypeBasesArrayVector, g_haplotypeBasesLengths);
+#endif
+}
+
+
+//Create a vector of testcases for computation - copy the references to bytearrays read/readQuals etc into the appropriate
+//testcase struct
+inline JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeTestcasesVector
+ (JNIEnv* env, jint numReads, jint numHaplotypes, jobjectArray& readDataArray,
+ vector<vector<pair<jbyteArray,jbyte*> > >& readBasesArrayVector,
+ vector<pair<jbyteArray, jbyte*> >& haplotypeBasesArrayVector, vector<unsigned>& haplotypeBasesLengths,
+ vector<testcase>& tc_array)
+{
+ jboolean is_copy = JNI_FALSE;
+ unsigned tc_idx = 0;
+ for(unsigned i=0;i<numReads;++i)
+ {
+ //Get bytearray fields from read
+ jobject readObject = env->GetObjectArrayElement(readDataArray, i);
+ jbyteArray readBases = (jbyteArray)env->GetObjectField(readObject, g_load_time_initializer.m_readBasesFID);
+ jbyteArray insertionGOP = (jbyteArray)env->GetObjectField(readObject, g_load_time_initializer.m_insertionGOPFID);
+ jbyteArray deletionGOP = (jbyteArray)env->GetObjectField(readObject, g_load_time_initializer.m_deletionGOPFID);
+ jbyteArray overallGCP = (jbyteArray)env->GetObjectField(readObject, g_load_time_initializer.m_overallGCPFID);
+ jbyteArray readQuals = (jbyteArray)env->GetObjectField(readObject, g_load_time_initializer.m_readQualsFID);
+
+#ifdef ENABLE_ASSERTIONS
+ assert(readBases && ("readBases is NULL at index : "+to_string(i)+"\n").c_str());
+ assert(insertionGOP && ("insertionGOP is NULL at index : "+to_string(i)+"\n").c_str());
+ assert(deletionGOP && ("deletionGOP is NULL at index : "+to_string(i)+"\n").c_str());
+ assert(overallGCP && ("overallGCP is NULL at index : "+to_string(i)+"\n").c_str());
+ assert(readQuals && ("readQuals is NULL at index : "+to_string(i)+"\n").c_str());
+#endif
+ jsize readLength = env->GetArrayLength(readBases);
+
+ jbyte* readBasesArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(readBases, &is_copy); //order of GET-RELEASE is important
+ jbyte* readQualsArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(readQuals, &is_copy);
+ jbyte* insertionGOPArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(insertionGOP, &is_copy);
+ jbyte* deletionGOPArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(deletionGOP, &is_copy);
+ jbyte* overallGCPArray = (jbyte*)GET_BYTE_ARRAY_ELEMENTS(overallGCP, &is_copy);
+#ifdef DO_PROFILING
+ g_load_time_initializer.m_bytes_copied += (is_copy ? readLength*5 : 0);
+ g_load_time_initializer.update_stat(READ_LENGTH_IDX, readLength);
+#endif
+#ifdef ENABLE_ASSERTIONS
+ assert(readBasesArray && "readBasesArray not initialized in JNI");
+ assert(readQualsArray && "readQualsArray not initialized in JNI");
+ assert(insertionGOPArray && "insertionGOP array not initialized in JNI");
+ assert(deletionGOPArray && "deletionGOP array not initialized in JNI");
+ assert(overallGCPArray && "overallGCP array not initialized in JNI");
+ //assert(readLength < MROWS);
+ assert(readLength == env->GetArrayLength(readQuals));
+ assert(readLength == env->GetArrayLength(insertionGOP));
+ assert(readLength == env->GetArrayLength(deletionGOP));
+ assert(readLength == env->GetArrayLength(overallGCP));
+#endif
+#ifdef DEBUG0_1
+ cout << "JNI read length "<<readLength<<"\n";
+#endif
+#ifdef DEBUG3
+ for(unsigned j=0;j<readLength;++j)
+ {
+ g_load_time_initializer.debug_dump("reads_jni.txt",to_string((int)readBasesArray[j]),true);
+ g_load_time_initializer.debug_dump("reads_jni.txt",to_string((int)readQualsArray[j]),true);
+ g_load_time_initializer.debug_dump("reads_jni.txt",to_string((int)insertionGOPArray[j]),true);
+ g_load_time_initializer.debug_dump("reads_jni.txt",to_string((int)deletionGOPArray[j]),true);
+ g_load_time_initializer.debug_dump("reads_jni.txt",to_string((int)overallGCPArray[j]),true);
+ }
+#endif
+ for(unsigned j=0;j<numHaplotypes;++j)
+ {
+ jsize haplotypeLength = (jsize)haplotypeBasesLengths[j];
+ jbyte* haplotypeBasesArray = haplotypeBasesArrayVector[j].second;
+ tc_array[tc_idx].rslen = (int)readLength;
+ tc_array[tc_idx].haplen = (int)haplotypeLength;
+ tc_array[tc_idx].hap = (char*)haplotypeBasesArray;
+ tc_array[tc_idx].rs = (char*)readBasesArray;
+ tc_array[tc_idx].q = (char*)readQualsArray;
+ tc_array[tc_idx].i = (char*)insertionGOPArray;
+ tc_array[tc_idx].d = (char*)deletionGOPArray;
+ tc_array[tc_idx].c = (char*)overallGCPArray;
+#ifdef DO_PROFILING
+ g_load_time_initializer.update_stat(PRODUCT_READ_LENGTH_HAPLOTYPE_LENGTH_IDX, ((uint64_t)readLength)*((uint64_t)haplotypeLength));
+#endif
+#ifdef DUMP_TO_SANDBOX
+ g_load_time_initializer.dump_sandbox(tc_array[tc_idx], tc_idx, numReads, numHaplotypes);
+#endif
+ ++tc_idx;
+ }
+ //Store the read array references and release them at the end because they are used by compute_full_prob
+ //Maintain order in which GET_BYTE_ARRAY_ELEMENTS called
+ readBasesArrayVector[i].clear();
+ readBasesArrayVector[i].resize(5);
+ readBasesArrayVector[i][0] = make_pair(readBases, readBasesArray);
+ readBasesArrayVector[i][1] = make_pair(readQuals, readQualsArray);
+ readBasesArrayVector[i][2] = make_pair(insertionGOP, insertionGOPArray);
+ readBasesArrayVector[i][3] = make_pair(deletionGOP, deletionGOPArray);
+ readBasesArrayVector[i][4] = make_pair(overallGCP, overallGCPArray);
+ }
+}
+
+//Do compute over vector of testcase structs
+inline void compute_testcases(vector<testcase>& tc_array, unsigned numTestCases, double* likelihoodDoubleArray,
+ unsigned maxNumThreadsToUse)
+{
+#ifdef DO_REPEAT_PROFILING
+ for(unsigned i=0;i<10;++i)
+#endif
+ {
+#pragma omp parallel for schedule (dynamic,10000) num_threads(maxNumThreadsToUse)
+ for(unsigned tc_idx=0;tc_idx<numTestCases;++tc_idx)
+ {
+ float result_avxf = g_compute_full_prob_float(&(tc_array[tc_idx]), 0);
+ double result = 0;
+ if (result_avxf < MIN_ACCEPTED) {
+ double result_avxd = g_compute_full_prob_double(&(tc_array[tc_idx]), 0);
+ result = log10(result_avxd) - log10(ldexp(1.0, 1020.0));
+#ifdef DO_PROFILING
+ g_load_time_initializer.update_stat(NUM_DOUBLE_INVOCATIONS_IDX, 1);
+#endif
+ }
+ else
+ result = (double)(log10f(result_avxf) - log10f(ldexpf(1.f, 120.f)));
+ likelihoodDoubleArray[tc_idx] = result;
+ }
+ }
+}
+
+//Inform the Java VM that we no longer need access to the read arrays (and free memory)
+inline JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniReleaseReadArrays
+ (JNIEnv* env, vector<vector<pair<jbyteArray,jbyte*> > >& readBasesArrayVector)
+{
+ //Release read arrays first
+ for(int i=readBasesArrayVector.size()-1;i>=0;--i)//note the order - reverse of GET
+ {
+ for(int j=readBasesArrayVector[i].size()-1;j>=0;--j)
+ RELEASE_BYTE_ARRAY_ELEMENTS(readBasesArrayVector[i][j].first, readBasesArrayVector[i][j].second, JNI_RO_RELEASE_MODE);
+ readBasesArrayVector[i].clear();
+ }
+ readBasesArrayVector.clear();
+}
+
+
+#ifdef DO_WARMUP
+uint64_t g_sum = 0;
+#endif
+//JNI function to invoke compute_full_prob_avx
+//readDataArray - array of JNIReadDataHolderClass objects which contain the readBases, readQuals etc
+//haplotypeDataArray - array of JNIHaplotypeDataHolderClass objects which contain the haplotypeBases
+//likelihoodArray - array of doubles to return results back to Java. Memory allocated by Java prior to JNI call
+//maxNumThreadsToUse - Max number of threads that OpenMP can use for the HMM computation
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniComputeLikelihoods
+ (JNIEnv* env, jobject thisObject, jint numReads, jint numHaplotypes,
+ jobjectArray readDataArray, jobjectArray haplotypeDataArray, jdoubleArray likelihoodArray, jint maxNumThreadsToUse)
+{
+#ifdef DEBUG0_1
+ cout << "JNI numReads "<<numReads<<" numHaplotypes "<<numHaplotypes<<"\n";
+#endif
+ jboolean is_copy = JNI_FALSE;
+ struct timespec start_time;
+ unsigned numTestCases = numReads*numHaplotypes;
+ //vector to store testcases
+ vector<testcase> tc_array;
+ tc_array.clear();
+ tc_array.resize(numTestCases);
+ //Store read arrays for release later
+ vector<vector<pair<jbyteArray,jbyte*> > > readBasesArrayVector;
+ readBasesArrayVector.clear();
+ readBasesArrayVector.resize(numReads);
+#ifdef DUMP_TO_SANDBOX
+ g_load_time_initializer.open_sandbox();
+#endif
+#ifdef DO_PROFILING
+ get_time(&start_time);
+#endif
+
+#ifdef SINGLE_THREADED_ONLY
+ vector<pair<jbyteArray, jbyte*> >& haplotypeBasesArrayVector = g_haplotypeBasesArrayVector;
+ vector<unsigned>& haplotypeBasesLengths = g_haplotypeBasesLengths;
+#else
+ vector<pair<jbyteArray, jbyte*> > l_haplotypeBasesArrayVector;
+ vector<pair<jbyteArray, jbyte*> >& haplotypeBasesArrayVector = l_haplotypeBasesArrayVector;
+ vector<unsigned> l_haplotypeBasesLengths;
+ vector<unsigned>& haplotypeBasesLengths = l_haplotypeBasesLengths;
+ initializeHaplotypes(env, thisObject, numHaplotypes, haplotypeDataArray, haplotypeBasesArrayVector, haplotypeBasesLengths);
+#endif
+ //Copy byte array references from Java memory into vector of testcase structs
+ Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeTestcasesVector(env,
+ numReads, numHaplotypes, readDataArray, readBasesArrayVector, haplotypeBasesArrayVector, haplotypeBasesLengths, tc_array);
+
+#ifdef DO_PROFILING
+ g_load_time_initializer.m_data_transfer_time += diff_time(start_time);
+#endif
+
+ //Get double array where results are stored (to pass back to java)
+ jdouble* likelihoodDoubleArray = (jdouble*)GET_DOUBLE_ARRAY_ELEMENTS(likelihoodArray, &is_copy);
+#ifdef ENABLE_ASSERTIONS
+ assert(likelihoodDoubleArray && "likelihoodArray is NULL");
+ assert(env->GetArrayLength(likelihoodArray) == numTestCases);
+#endif
+#ifdef DO_WARMUP //ignore - only for crazy profiling
+ for(unsigned i=0;i<haplotypeBasesArrayVector.size();++i)
+ {
+ unsigned curr_size = env->GetArrayLength(haplotypeBasesArrayVector[i].first);
+ for(unsigned j=0;j<curr_size;++j)
+ g_sum += ((uint64_t)((haplotypeBasesArrayVector[i].second)[j]));
+ }
+ for(unsigned i=0;i<readBasesArrayVector.size();++i)
+ {
+ for(unsigned j=0;j<readBasesArrayVector[i].size();++j)
+ {
+ unsigned curr_size = env->GetArrayLength(readBasesArrayVector[i][j].first);
+ for(unsigned k=0;k<curr_size;++k)
+ g_sum += ((uint64_t)((readBasesArrayVector[i][j].second)[k]));
+ }
+ }
+#endif
+#ifdef DO_PROFILING
+ g_load_time_initializer.m_bytes_copied += (is_copy ? numTestCases*sizeof(double) : 0);
+ get_time(&start_time);
+#endif
+ compute_testcases(tc_array, numTestCases, likelihoodDoubleArray, maxNumThreadsToUse); //actual computation
+#ifdef DO_PROFILING
+ g_load_time_initializer.m_compute_time += diff_time(start_time);
+#endif
+#ifdef DUMP_COMPUTE_VALUES
+ for(unsigned tc_idx=0;tc_idx<numTestCases;++tc_idx)
+ g_load_time_initializer.debug_dump("return_values_jni.txt",to_string(likelihoodDoubleArray[tc_idx]),true);
+#endif
+#ifdef DO_PROFILING
+ get_time(&start_time);
+#endif
+ RELEASE_DOUBLE_ARRAY_ELEMENTS(likelihoodArray, likelihoodDoubleArray, 0); //release mode 0, copy back results to Java memory (if copy made)
+ Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniReleaseReadArrays(env, readBasesArrayVector);
+#ifndef SINGLE_THREADED_ONLY
+ releaseHaplotypes(env, thisObject, haplotypeBasesArrayVector, haplotypeBasesLengths);
+#endif
+
+#ifdef DO_PROFILING
+ g_load_time_initializer.m_data_transfer_time += diff_time(start_time);
+ g_load_time_initializer.update_stat(NUM_REGIONS_IDX, 1);
+ g_load_time_initializer.update_stat(NUM_READS_IDX, numReads);
+ g_load_time_initializer.update_stat(NUM_HAPLOTYPES_IDX, numHaplotypes);
+ g_load_time_initializer.update_stat(NUM_TESTCASES_IDX, numTestCases);
+#endif
+ tc_array.clear();
+#ifdef DUMP_TO_SANDBOX
+ g_load_time_initializer.close_sandbox();
+#endif
+}
+
+//If single threaded, release haplotypes at the end of a region
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniFinalizeRegion
+ (JNIEnv * env, jobject thisObject)
+{
+#ifdef SINGLE_THREADED_ONLY
+ releaseHaplotypes(env, thisObject, g_haplotypeBasesArrayVector, g_haplotypeBasesLengths);
+#endif
+}
+
+
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniClose
+ (JNIEnv* env, jobject thisObject)
+{
+#ifdef DO_PROFILING
+ g_load_time_initializer.print_profiling();
+#endif
+#ifdef DUMP_COMPUTE_VALUES
+ g_load_time_initializer.debug_close();
+#endif
+}
+
diff --git a/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.h b/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.h
new file mode 100644
index 0000000..6172da5
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM.h
@@ -0,0 +1,96 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM */
+
+#ifndef _Included_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM
+#define _Included_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_TRISTATE_CORRECTION
+#define org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_TRISTATE_CORRECTION 3.0
+#undef org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_sse41Mask
+#define org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_sse41Mask 1LL
+#undef org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_sse42Mask
+#define org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_sse42Mask 2LL
+#undef org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_avxMask
+#define org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_avxMask 4LL
+#undef org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_enableAll
+#define org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_enableAll -1LL
+/*
+ * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM
+ * Method: jniGetMachineType
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniGetMachineType
+ (JNIEnv *, jobject);
+
+/*
+ * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM
+ * Method: jniInitializeClassFieldsAndMachineMask
+ * Signature: (Ljava/lang/Class;Ljava/lang/Class;J)V
+ */
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeClassFieldsAndMachineMask
+ (JNIEnv *, jobject, jclass, jclass, jlong);
+
+/*
+ * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM
+ * Method: jniInitializeHaplotypes
+ * Signature: (I[Lorg/broadinstitute/gatk/utils/pairhmm/VectorLoglessPairHMM/JNIHaplotypeDataHolderClass;)V
+ */
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniInitializeHaplotypes
+ (JNIEnv *, jobject, jint, jobjectArray);
+
+/*
+ * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM
+ * Method: jniFinalizeRegion
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniFinalizeRegion
+ (JNIEnv *, jobject);
+
+/*
+ * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM
+ * Method: jniComputeLikelihoods
+ * Signature: (II[Lorg/broadinstitute/gatk/utils/pairhmm/VectorLoglessPairHMM/JNIReadDataHolderClass;[Lorg/broadinstitute/gatk/utils/pairhmm/VectorLoglessPairHMM/JNIHaplotypeDataHolderClass;[DI)V
+ */
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniComputeLikelihoods
+ (JNIEnv *, jobject, jint, jint, jobjectArray, jobjectArray, jdoubleArray, jint);
+
+/*
+ * Class: org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM
+ * Method: jniClose
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_broadinstitute_gatk_utils_pairhmm_VectorLoglessPairHMM_jniClose
+ (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/public/VectorPairHMM/src/main/c++/pairhmm-1-base.cc b/public/VectorPairHMM/src/main/c++/pairhmm-1-base.cc
new file mode 100644
index 0000000..20e9910
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/pairhmm-1-base.cc
@@ -0,0 +1,65 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "headers.h"
+#include "utils.h"
+#include "LoadTimeInitializer.h"
+using namespace std;
+
+int main(int argc, char** argv)
+{
+ if(argc < 2)
+ {
+ cerr << "Needs path to input file as argument\n";
+ exit(0);
+ }
+ bool use_old_read_testcase = false;
+ if(argc >= 3 && string(argv[2]) == "1")
+ use_old_read_testcase = true;
+ unsigned chunk_size = 10000;
+ bool do_check = true;
+ uint64_t mask = ~(0ull);
+ for(int i=3;i<argc;++i)
+ {
+ if(strncmp(argv[i], "-chunk_size", 15) == 0)
+ {
+ ++i;
+ chunk_size = strtol(argv[i],0,10);
+ }
+ else
+ if(strncmp(argv[i], "-mask", 15) == 0)
+ {
+ ++i;
+ mask = strtoll(argv[i],0,16);
+ }
+ else
+ if(strncmp(argv[i], "-no-check", 15) == 0)
+ do_check = false;
+ }
+ if(mask != (~0ull))
+ initialize_function_pointers(mask);
+ do_compute(argv[1], use_old_read_testcase, chunk_size, do_check);
+ return 0;
+}
+
diff --git a/public/VectorPairHMM/src/main/c++/pairhmm-template-kernel.cc b/public/VectorPairHMM/src/main/c++/pairhmm-template-kernel.cc
new file mode 100644
index 0000000..8c62b3c
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/pairhmm-template-kernel.cc
@@ -0,0 +1,380 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifdef PRECISION
+
+#include <stdint.h>
+#include <assert.h>
+#include <stdlib.h>
+
+
+void CONCAT(CONCAT(precompute_masks_,SIMD_ENGINE), PRECISION)(const testcase& tc, int COLS, int numMaskVecs, MASK_TYPE (*maskArr)[NUM_DISTINCT_CHARS]) {
+
+ const int maskBitCnt = MAIN_TYPE_SIZE ;
+
+ for (int vi=0; vi < numMaskVecs; ++vi) {
+ for (int rs=0; rs < NUM_DISTINCT_CHARS; ++rs) {
+ maskArr[vi][rs] = 0 ;
+ }
+ maskArr[vi][AMBIG_CHAR] = MASK_ALL_ONES ;
+ }
+
+ for (int col=1; col < COLS; ++col) {
+ int mIndex = (col-1) / maskBitCnt ;
+ int mOffset = (col-1) % maskBitCnt ;
+ MASK_TYPE bitMask = ((MASK_TYPE)0x1) << (maskBitCnt-1-mOffset) ;
+
+ char hapChar = ConvertChar::get(tc.hap[col-1]);
+
+ if (hapChar == AMBIG_CHAR) {
+ for (int ci=0; ci < NUM_DISTINCT_CHARS; ++ci)
+ maskArr[mIndex][ci] |= bitMask ;
+ }
+
+ maskArr[mIndex][hapChar] |= bitMask ;
+ // bit corresponding to col 1 will be the MSB of the mask 0
+ // bit corresponding to col 2 will be the MSB-1 of the mask 0
+ // ...
+ // bit corresponding to col 32 will be the LSB of the mask 0
+ // bit corresponding to col 33 will be the MSB of the mask 1
+ // ...
+ }
+
+}
+
+void CONCAT(CONCAT(init_masks_for_row_,SIMD_ENGINE), PRECISION)(const testcase& tc, char* rsArr, MASK_TYPE* lastMaskShiftOut, int beginRowIndex, int numRowsToProcess) {
+
+ for (int ri=0; ri < numRowsToProcess; ++ri) {
+ rsArr[ri] = ConvertChar::get(tc.rs[ri+beginRowIndex-1]) ;
+ }
+
+ for (int ei=0; ei < AVX_LENGTH; ++ei) {
+ lastMaskShiftOut[ei] = 0 ;
+ }
+}
+
+#define SET_MASK_WORD(__dstMask, __srcMask, __lastShiftOut, __shiftBy, __maskBitCnt){ \
+ MASK_TYPE __bitMask = (((MASK_TYPE)0x1) << __shiftBy) - 1 ; \
+ MASK_TYPE __nextShiftOut = (__srcMask & __bitMask) << (__maskBitCnt - __shiftBy) ; \
+ __dstMask = (__srcMask >> __shiftBy) | __lastShiftOut ; \
+ __lastShiftOut = __nextShiftOut ; \
+}
+
+
+void CONCAT(CONCAT(update_masks_for_cols_,SIMD_ENGINE), PRECISION)(int maskIndex, BITMASK_VEC& bitMaskVec, MASK_TYPE (*maskArr) [NUM_DISTINCT_CHARS], char* rsArr, MASK_TYPE* lastMaskShiftOut, int maskBitCnt) {
+
+ for (int ei=0; ei < AVX_LENGTH/2; ++ei) {
+ SET_MASK_WORD(bitMaskVec.getLowEntry(ei), maskArr[maskIndex][rsArr[ei]],
+ lastMaskShiftOut[ei], ei, maskBitCnt) ;
+
+ int ei2 = ei + AVX_LENGTH/2 ; // the second entry index
+ SET_MASK_WORD(bitMaskVec.getHighEntry(ei), maskArr[maskIndex][rsArr[ei2]],
+ lastMaskShiftOut[ei2], ei2, maskBitCnt) ;
+ }
+
+}
+
+
+inline void CONCAT(CONCAT(computeDistVec,SIMD_ENGINE), PRECISION) (BITMASK_VEC& bitMaskVec, SIMD_TYPE& distm, SIMD_TYPE& _1_distm, SIMD_TYPE& distmChosen) {
+
+ distmChosen = VEC_BLENDV(distm, _1_distm, bitMaskVec.getCombinedMask()) ;
+
+ bitMaskVec.shift_left_1bit() ;
+}
+
+/*
+ * This function:
+ * 1- Intializes probability values p_MM, p_XX, P_YY, p_MX, p_GAPM and pack them into vectors (SSE or AVX)
+ * 2- Precompute parts of "distm" which only depeneds on a row number and pack it into vector
+ */
+
+template<class NUMBER> void CONCAT(CONCAT(initializeVectors,SIMD_ENGINE), PRECISION)(int ROWS, int COLS, NUMBER* shiftOutM, NUMBER *shiftOutX, NUMBER *shiftOutY, Context<NUMBER> ctx, testcase *tc, SIMD_TYPE *p_MM, SIMD_TYPE *p_GAPM, SIMD_TYPE *p_MX, SIMD_TYPE *p_XX, SIMD_TYPE *p_MY, SIMD_TYPE *p_YY, SIMD_TYPE *distm1D)
+{
+ NUMBER zero = ctx._(0.0);
+ NUMBER init_Y = ctx.INITIAL_CONSTANT / (tc->haplen);
+ for (int s=0;s<ROWS+COLS+AVX_LENGTH;s++)
+ {
+ shiftOutM[s] = zero;
+ shiftOutX[s] = zero;
+ shiftOutY[s] = init_Y;
+ }
+
+ NUMBER *ptr_p_MM = (NUMBER *)p_MM;
+ NUMBER *ptr_p_XX = (NUMBER *)p_XX;
+ NUMBER *ptr_p_YY = (NUMBER *)p_YY;
+ NUMBER *ptr_p_MX = (NUMBER *)p_MX;
+ NUMBER *ptr_p_MY = (NUMBER *)p_MY;
+ NUMBER *ptr_p_GAPM = (NUMBER *)p_GAPM;
+
+ *ptr_p_MM = ctx._(0.0);
+ *ptr_p_XX = ctx._(0.0);
+ *ptr_p_YY = ctx._(0.0);
+ *ptr_p_MX = ctx._(0.0);
+ *ptr_p_MY = ctx._(0.0);
+ *ptr_p_GAPM = ctx._(0.0);
+
+ for (int r = 1; r < ROWS; r++)
+ {
+ int _i = tc->i[r-1] & 127;
+ int _d = tc->d[r-1] & 127;
+ int _c = tc->c[r-1] & 127;
+
+ //*(ptr_p_MM+r-1) = ctx._(1.0) - ctx.ph2pr[(_i + _d) & 127];
+ SET_MATCH_TO_MATCH_PROB(*(ptr_p_MM+r-1), _i, _d);
+ *(ptr_p_GAPM+r-1) = ctx._(1.0) - ctx.ph2pr[_c];
+ *(ptr_p_MX+r-1) = ctx.ph2pr[_i];
+ *(ptr_p_XX+r-1) = ctx.ph2pr[_c];
+ *(ptr_p_MY+r-1) = ctx.ph2pr[_d];
+ *(ptr_p_YY+r-1) = ctx.ph2pr[_c];
+ }
+
+ NUMBER *ptr_distm1D = (NUMBER *)distm1D;
+ for (int r = 1; r < ROWS; r++)
+ {
+ int _q = tc->q[r-1] & 127;
+ ptr_distm1D[r-1] = ctx.ph2pr[_q];
+ }
+}
+
+/*
+ * This function handles pre-stripe computation:
+ * 1- Retrieve probaility vectors from memory
+ * 2- Initialize M, X, Y vectors with all 0's (for the first stripe) and shifting the last row from previous stripe for the rest
+ */
+
+template<class NUMBER> inline void CONCAT(CONCAT(stripeINITIALIZATION,SIMD_ENGINE), PRECISION)(
+ int stripeIdx, Context<NUMBER> ctx, testcase *tc, SIMD_TYPE &pGAPM, SIMD_TYPE &pMM, SIMD_TYPE &pMX, SIMD_TYPE &pXX, SIMD_TYPE &pMY, SIMD_TYPE &pYY,
+ SIMD_TYPE &rs, UNION_TYPE &rsN, SIMD_TYPE &distm, SIMD_TYPE &_1_distm, SIMD_TYPE *distm1D, SIMD_TYPE N_packed256, SIMD_TYPE *p_MM , SIMD_TYPE *p_GAPM ,
+ SIMD_TYPE *p_MX, SIMD_TYPE *p_XX , SIMD_TYPE *p_MY, SIMD_TYPE *p_YY, UNION_TYPE &M_t_2, UNION_TYPE &X_t_2, UNION_TYPE &M_t_1, UNION_TYPE &X_t_1,
+ UNION_TYPE &Y_t_2, UNION_TYPE &Y_t_1, UNION_TYPE &M_t_1_y, NUMBER* shiftOutX, NUMBER* shiftOutM)
+{
+ int i = stripeIdx;
+ pGAPM = p_GAPM[i];
+ pMM = p_MM[i];
+ pMX = p_MX[i];
+ pXX = p_XX[i];
+ pMY = p_MY[i];
+ pYY = p_YY[i];
+
+ NUMBER zero = ctx._(0.0);
+ NUMBER init_Y = ctx.INITIAL_CONSTANT / (tc->haplen);
+ UNION_TYPE packed1; packed1.d = VEC_SET1_VAL(1.0);
+ UNION_TYPE packed3; packed3.d = VEC_SET1_VAL(3.0);
+
+ distm = distm1D[i];
+ _1_distm = VEC_SUB(packed1.d, distm);
+
+ distm = VEC_DIV(distm, packed3.d);
+
+ /* initialize M_t_2, M_t_1, X_t_2, X_t_1, Y_t_2, Y_t_1 */
+ M_t_2.d = VEC_SET1_VAL(zero);
+ X_t_2.d = VEC_SET1_VAL(zero);
+
+ if (i==0) {
+ M_t_1.d = VEC_SET1_VAL(zero);
+ X_t_1.d = VEC_SET1_VAL(zero);
+ Y_t_2.d = VEC_SET_LSE(init_Y);
+ Y_t_1.d = VEC_SET1_VAL(zero);
+ }
+ else {
+ X_t_1.d = VEC_SET_LSE(shiftOutX[AVX_LENGTH]);
+ M_t_1.d = VEC_SET_LSE(shiftOutM[AVX_LENGTH]);
+ Y_t_2.d = VEC_SET1_VAL(zero);
+ Y_t_1.d = VEC_SET1_VAL(zero);
+ }
+ M_t_1_y = M_t_1;
+}
+
+/*
+ * This function is the main compute kernel to compute M, X and Y
+ */
+
+inline void CONCAT(CONCAT(computeMXY,SIMD_ENGINE), PRECISION)(UNION_TYPE &M_t, UNION_TYPE &X_t, UNION_TYPE &Y_t, UNION_TYPE &M_t_y,
+ UNION_TYPE M_t_2, UNION_TYPE X_t_2, UNION_TYPE Y_t_2, UNION_TYPE M_t_1, UNION_TYPE X_t_1, UNION_TYPE M_t_1_y, UNION_TYPE Y_t_1,
+ SIMD_TYPE pMM, SIMD_TYPE pGAPM, SIMD_TYPE pMX, SIMD_TYPE pXX, SIMD_TYPE pMY, SIMD_TYPE pYY, SIMD_TYPE distmSel)
+{
+ /* Compute M_t <= distm * (p_MM*M_t_2 + p_GAPM*X_t_2 + p_GAPM*Y_t_2) */
+ M_t.d = VEC_MUL(VEC_ADD(VEC_ADD(VEC_MUL(M_t_2.d, pMM), VEC_MUL(X_t_2.d, pGAPM)), VEC_MUL(Y_t_2.d, pGAPM)), distmSel);
+ //M_t.d = VEC_MUL( VEC_ADD(VEC_MUL(M_t_2.d, pMM), VEC_MUL(VEC_ADD(X_t_2.d, Y_t_2.d), pGAPM)), distmSel);
+
+ M_t_y = M_t;
+
+ /* Compute X_t */
+ X_t.d = VEC_ADD(VEC_MUL(M_t_1.d, pMX) , VEC_MUL(X_t_1.d, pXX));
+
+ /* Compute Y_t */
+ Y_t.d = VEC_ADD(VEC_MUL(M_t_1_y.d, pMY) , VEC_MUL(Y_t_1.d, pYY));
+}
+
+/*
+ * This is the main compute function. It operates on the matrix in s stripe manner.
+ * The stripe height is determined by the SIMD engine type.
+ * Stripe height: "AVX float": 8, "AVX double": 4, "SSE float": 4, "SSE double": 2
+ * For each stripe the operations are anti-diagonal based.
+ * Each anti-diagonal (M_t, Y_t, X_t) depends on the two previous anti-diagonals (M_t_2, X_t_2, Y_t_2, M_t_1, X_t_1, Y_t_1).
+ * Each stripe (except the fist one) depends on the last row of the previous stripe.
+ * The last stripe computation handles the addition of the last row of M and X, that's the reason for loop spliting.
+ */
+
+template<class NUMBER> NUMBER CONCAT(CONCAT(compute_full_prob_,SIMD_ENGINE), PRECISION) (testcase *tc, NUMBER *before_last_log = NULL)
+{
+ int ROWS = tc->rslen + 1;
+ int COLS = tc->haplen + 1;
+ int MAVX_COUNT = (ROWS+AVX_LENGTH-1)/AVX_LENGTH;
+
+ /* Probaility arrays */
+ SIMD_TYPE p_MM [MAVX_COUNT], p_GAPM [MAVX_COUNT], p_MX [MAVX_COUNT];
+ SIMD_TYPE p_XX [MAVX_COUNT], p_MY [MAVX_COUNT], p_YY [MAVX_COUNT];
+
+ /* For distm precomputation */
+ SIMD_TYPE distm1D[MAVX_COUNT];
+
+ /* Carries the values from each stripe to the next stripe */
+ NUMBER shiftOutM[ROWS+COLS+AVX_LENGTH], shiftOutX[ROWS+COLS+AVX_LENGTH], shiftOutY[ROWS+COLS+AVX_LENGTH];
+
+ /* The vector to keep the anti-diagonals of M, X, Y*/
+ /* Current: M_t, X_t, Y_t */
+ /* Previous: M_t_1, X_t_1, Y_t_1 */
+ /* Previous to previous: M_t_2, X_t_2, Y_t_2 */
+ UNION_TYPE M_t, M_t_1, M_t_2, X_t, X_t_1, X_t_2, Y_t, Y_t_1, Y_t_2, M_t_y, M_t_1_y;
+
+ /* Probality vectors */
+ SIMD_TYPE pGAPM, pMM, pMX, pXX, pMY, pYY;
+
+ struct timeval start, end;
+ NUMBER result_avx2;
+ Context<NUMBER> ctx;
+ UNION_TYPE rs , rsN;
+ HAP_TYPE hap;
+ SIMD_TYPE distmSel, distmChosen ;
+ SIMD_TYPE distm, _1_distm;
+
+ int r, c;
+ NUMBER zero = ctx._(0.0);
+ UNION_TYPE packed1; packed1.d = VEC_SET1_VAL(1.0);
+ SIMD_TYPE N_packed256 = VEC_POPCVT_CHAR('N');
+ NUMBER init_Y = ctx.INITIAL_CONSTANT / (tc->haplen);
+ int remainingRows = (ROWS-1) % AVX_LENGTH;
+ int stripe_cnt = ((ROWS-1) / AVX_LENGTH) + (remainingRows!=0);
+
+ const int maskBitCnt = MAIN_TYPE_SIZE ;
+ const int numMaskVecs = (COLS+ROWS+maskBitCnt-1)/maskBitCnt ; // ceil function
+
+ /* Mask precomputation for distm*/
+ MASK_TYPE maskArr[numMaskVecs][NUM_DISTINCT_CHARS] ;
+ CONCAT(CONCAT(precompute_masks_,SIMD_ENGINE), PRECISION)(*tc, COLS, numMaskVecs, maskArr) ;
+
+ char rsArr[AVX_LENGTH] ;
+ MASK_TYPE lastMaskShiftOut[AVX_LENGTH] ;
+
+ /* Precompute initialization for probabilities and shift vector*/
+ CONCAT(CONCAT(initializeVectors,SIMD_ENGINE), PRECISION)<NUMBER>(ROWS, COLS, shiftOutM, shiftOutX, shiftOutY,
+ ctx, tc, p_MM, p_GAPM, p_MX, p_XX, p_MY, p_YY, distm1D);
+
+ for (int i=0;i<stripe_cnt-1;i++)
+ {
+ //STRIPE_INITIALIZATION
+ CONCAT(CONCAT(stripeINITIALIZATION,SIMD_ENGINE), PRECISION)(i, ctx, tc, pGAPM, pMM, pMX, pXX, pMY, pYY, rs.d, rsN, distm, _1_distm, distm1D, N_packed256, p_MM , p_GAPM ,
+ p_MX, p_XX , p_MY, p_YY, M_t_2, X_t_2, M_t_1, X_t_1, Y_t_2, Y_t_1, M_t_1_y, shiftOutX, shiftOutM);
+ CONCAT(CONCAT(init_masks_for_row_,SIMD_ENGINE), PRECISION)(*tc, rsArr, lastMaskShiftOut, i*AVX_LENGTH+1, AVX_LENGTH) ;
+ // Since there are no shift intrinsics in AVX, keep the masks in 2 SSE vectors
+
+ BITMASK_VEC bitMaskVec ;
+
+ for (int begin_d=1;begin_d<COLS+AVX_LENGTH;begin_d+=MAIN_TYPE_SIZE)
+ {
+ int numMaskBitsToProcess = std::min(MAIN_TYPE_SIZE, COLS+AVX_LENGTH-begin_d) ;
+ CONCAT(CONCAT(update_masks_for_cols_,SIMD_ENGINE), PRECISION)((begin_d-1)/MAIN_TYPE_SIZE, bitMaskVec, maskArr, rsArr, lastMaskShiftOut, maskBitCnt) ;
+
+ for (int mbi=0; mbi < numMaskBitsToProcess; ++mbi) {
+ CONCAT(CONCAT(computeDistVec,SIMD_ENGINE), PRECISION) (bitMaskVec, distm, _1_distm, distmChosen) ;
+ int ShiftIdx = begin_d + mbi + AVX_LENGTH;
+
+ CONCAT(CONCAT(computeMXY,SIMD_ENGINE), PRECISION)(M_t, X_t, Y_t, M_t_y, M_t_2, X_t_2, Y_t_2, M_t_1, X_t_1, M_t_1_y, Y_t_1,
+ pMM, pGAPM, pMX, pXX, pMY, pYY, distmChosen);
+
+ CONCAT(CONCAT(_vector_shift,SIMD_ENGINE), PRECISION)(M_t, shiftOutM[ShiftIdx], shiftOutM[begin_d+mbi]);
+
+ CONCAT(CONCAT(_vector_shift,SIMD_ENGINE), PRECISION)(X_t, shiftOutX[ShiftIdx], shiftOutX[begin_d+mbi]);
+
+ CONCAT(CONCAT(_vector_shift,SIMD_ENGINE), PRECISION)(Y_t_1, shiftOutY[ShiftIdx], shiftOutY[begin_d+mbi]);
+
+ M_t_2 = M_t_1; M_t_1 = M_t; X_t_2 = X_t_1; X_t_1 = X_t;
+ Y_t_2 = Y_t_1; Y_t_1 = Y_t; M_t_1_y = M_t_y;
+ }
+ }
+ }
+
+ int i = stripe_cnt-1;
+ {
+ //STRIPE_INITIALIZATION
+ CONCAT(CONCAT(stripeINITIALIZATION,SIMD_ENGINE), PRECISION)(i, ctx, tc, pGAPM, pMM, pMX, pXX, pMY, pYY, rs.d, rsN, distm, _1_distm, distm1D, N_packed256, p_MM , p_GAPM ,
+ p_MX, p_XX , p_MY, p_YY, M_t_2, X_t_2, M_t_1, X_t_1, Y_t_2, Y_t_1, M_t_1_y, shiftOutX, shiftOutM);
+
+ if (remainingRows==0) remainingRows=AVX_LENGTH;
+ CONCAT(CONCAT(init_masks_for_row_,SIMD_ENGINE), PRECISION)(*tc, rsArr, lastMaskShiftOut, i*AVX_LENGTH+1, remainingRows) ;
+
+ SIMD_TYPE sumM, sumX;
+ sumM = VEC_SET1_VAL(zero);
+ sumX = VEC_SET1_VAL(zero);
+
+ // Since there are no shift intrinsics in AVX, keep the masks in 2 SSE vectors
+ BITMASK_VEC bitMaskVec ;
+
+ for (int begin_d=1;begin_d<COLS+remainingRows-1;begin_d+=MAIN_TYPE_SIZE)
+ {
+ int numMaskBitsToProcess = std::min(MAIN_TYPE_SIZE, COLS+remainingRows-1-begin_d) ;
+ CONCAT(CONCAT(update_masks_for_cols_,SIMD_ENGINE),PRECISION)((begin_d-1)/MAIN_TYPE_SIZE, bitMaskVec, maskArr, rsArr, lastMaskShiftOut, maskBitCnt) ;
+
+ for (int mbi=0; mbi < numMaskBitsToProcess; ++mbi) {
+
+ CONCAT(CONCAT(computeDistVec,SIMD_ENGINE), PRECISION) (bitMaskVec, distm, _1_distm, distmChosen) ;
+ int ShiftIdx = begin_d + mbi +AVX_LENGTH;
+
+ CONCAT(CONCAT(computeMXY,SIMD_ENGINE), PRECISION)(M_t, X_t, Y_t, M_t_y, M_t_2, X_t_2, Y_t_2, M_t_1, X_t_1, M_t_1_y, Y_t_1,
+ pMM, pGAPM, pMX, pXX, pMY, pYY, distmChosen);
+
+ sumM = VEC_ADD(sumM, M_t.d);
+ CONCAT(CONCAT(_vector_shift_last,SIMD_ENGINE), PRECISION)(M_t, shiftOutM[ShiftIdx]);
+
+ sumX = VEC_ADD(sumX, X_t.d);
+ CONCAT(CONCAT(_vector_shift_last,SIMD_ENGINE), PRECISION)(X_t, shiftOutX[ShiftIdx]);
+
+ CONCAT(CONCAT(_vector_shift_last,SIMD_ENGINE), PRECISION)(Y_t_1, shiftOutY[ShiftIdx]);
+
+ M_t_2 = M_t_1; M_t_1 = M_t; X_t_2 = X_t_1; X_t_1 = X_t;
+ Y_t_2 = Y_t_1; Y_t_1 = Y_t; M_t_1_y = M_t_y;
+
+ }
+ }
+ UNION_TYPE sumMX;
+ sumMX.d = VEC_ADD(sumM, sumX);
+ result_avx2 = sumMX.f[remainingRows-1];
+ }
+ return result_avx2;
+}
+
+#endif
+
diff --git a/public/VectorPairHMM/src/main/c++/pairhmm-template-main.cc b/public/VectorPairHMM/src/main/c++/pairhmm-template-main.cc
new file mode 100644
index 0000000..4f83046
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/pairhmm-template-main.cc
@@ -0,0 +1,113 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include "headers.h"
+
+#define SIMD_ENGINE avx
+#define SIMD_ENGINE_AVX
+
+#include "utils.h"
+
+#define BATCH_SIZE 10000
+#define RUN_HYBRID
+
+double getCurrClk();
+int thread_level_parallelism_enabled = false ;
+
+
+int main()
+{
+ testcase* tc = new testcase[BATCH_SIZE];
+ float result[BATCH_SIZE], result_avxf;
+ double result_avxd;
+ double lastClk = 0.0 ;
+ double aggregateTimeRead = 0.0;
+ double aggregateTimeCompute = 0.0;
+ double aggregateTimeWrite = 0.0;
+
+ // Need to call it once to initialize the static array
+ ConvertChar::init() ;
+
+ // char* ompEnvVar = getenv("OMP_NUM_THREADS") ;
+ // if (ompEnvVar != NULL && ompEnvVar != "" && ompEnvVar != "1" ) {
+ // thread_level_parallelism_enabled = true ;
+ // }
+
+ bool noMoreData = false;
+ int count =0;
+ while (!noMoreData)
+ {
+ int read_count = BATCH_SIZE;
+
+ lastClk = getCurrClk() ;
+ for (int b=0;b<BATCH_SIZE;b++)
+ if (read_testcase(&tc[b])==-1)
+ {
+ read_count = b;
+ noMoreData = true;
+ break;
+ }
+ aggregateTimeRead += (getCurrClk() - lastClk) ;
+ lastClk = getCurrClk() ;
+
+ //#pragma omp parallel for schedule(dynamic) if(thread_level_parallelism_enabled)
+ for (int b=0;b<read_count;b++)
+ {
+ result_avxf = CONCAT(CONCAT(compute_full_prob_,SIMD_ENGINE), s)<float>(&tc[b]);
+
+#ifdef RUN_HYBRID
+#define MIN_ACCEPTED 1e-28f
+ if (result_avxf < MIN_ACCEPTED) {
+ count++;
+ result_avxd = CONCAT(CONCAT(compute_full_prob_,SIMD_ENGINE), d)<double>(&tc[b]);
+ result[b] = log10(result_avxd) - log10(ldexp(1.0, 1020.f));
+ }
+ else
+ result[b] = log10f(result_avxf) - log10f(ldexpf(1.f, 120.f));
+#endif
+
+#ifndef RUN_HYBRID
+ result[b] = log10f(result_avxf) - log10f(ldexpf(1.f, 120.f));
+#endif
+ }
+ aggregateTimeCompute += (getCurrClk() - lastClk) ;
+ lastClk = getCurrClk() ;
+ for (int b=0;b<read_count;b++)
+ printf("%E\n", result[b]);
+ aggregateTimeWrite += (getCurrClk() - lastClk) ;
+ }
+
+ delete[] tc;
+ printf("AVX Read Time: %.2f\n", aggregateTimeRead);
+ printf("AVX Compute Time: %.2f\n", aggregateTimeCompute);
+ printf("AVX Write Time: %.2f\n", aggregateTimeWrite);
+ printf("AVX Total Time: %.2f\n", aggregateTimeRead + aggregateTimeCompute + aggregateTimeWrite);
+ printf("# Double called: %d\n", count);
+
+ return 0;
+}
+
+
+
diff --git a/public/VectorPairHMM/src/main/c++/run.sh b/public/VectorPairHMM/src/main/c++/run.sh
new file mode 100755
index 0000000..e821497
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/run.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+rm -f *.txt *.log
+GSA_ROOT_DIR=/home/karthikg/broad/gsa-unstable
+pair_hmm_implementation="VECTOR_LOGLESS_CACHING";
+if [ "$#" -ge 1 ];
+then
+ pair_hmm_implementation=$1;
+fi
+
+#-Djava.library.path is needed if you wish to override the default 'packed' library
+#java -jar $GSA_ROOT_DIR/target/GenomeAnalysisTK.jar -T HaplotypeCaller \
+java -Djava.library.path=${GSA_ROOT_DIR}/public/VectorPairHMM/src/main/c++ -jar $GSA_ROOT_DIR/target/GenomeAnalysisTK.jar -T HaplotypeCaller \
+--dbsnp /data/broad/samples/joint_variant_calling/dbSNP/00-All.vcf \
+-R /opt/Genomics/ohsu/dnapipeline/humanrefgenome/human_g1k_v37.fasta \
+-I /data/simulated/sim1M_pairs_final.bam \
+-stand_call_conf 50.0 \
+-stand_emit_conf 10.0 \
+--pair_hmm_implementation $pair_hmm_implementation \
+-o output.raw.snps.indels.vcf
+
+#--pair_hmm_implementation JNI_LOGLESS_CACHING \
+#-XL unmapped \
+#-I /data/simulated/sim1M_pairs_final.bam \
+#-I /data/broad/samples/joint_variant_calling/NA12878_low_coverage_alignment/NA12878.chrom11.ILLUMINA.bwa.CEU.low_coverage.20121211.bam \
+#-I /data/broad/samples/joint_variant_calling/NA12878_high_coverage_alignment/NA12878.mapped.ILLUMINA.bwa.CEU.high_coverage_pcr_free.20130906.bam \
+#-R /data/broad/samples/joint_variant_calling/broad_reference/Homo_sapiens_assembly18.fasta \
+#-R /data/broad/samples/joint_variant_calling/broad_reference/Homo_sapiens_assembly19.fasta \
+#-R /data/broad/samples/joint_variant_calling/broad_reference/ucsc.hg19.fasta \
+#-R /opt/Genomics/ohsu/dnapipeline/humanrefgenome/human_g1k_v37.fasta \
+#-R /data/broad/samples/joint_variant_calling/broad_reference/human_g1k_v37_decoy.fasta \
+#--dbsnp /data/broad/samples/joint_variant_calling/dbSNP/00-All.vcf \
+#--dbsnp /data/broad/samples/joint_variant_calling/dbSNP/dbsnp_138.hg19.vcf \
diff --git a/public/VectorPairHMM/src/main/c++/shift_template.c b/public/VectorPairHMM/src/main/c++/shift_template.c
new file mode 100644
index 0000000..c591c68
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/shift_template.c
@@ -0,0 +1,113 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifdef PRECISION
+
+#ifdef SIMD_ENGINE_AVX
+
+inline void CONCAT(CONCAT(_vector_shift,SIMD_ENGINE), PRECISION) (UNION_TYPE &x, MAIN_TYPE shiftIn, MAIN_TYPE &shiftOut)
+{
+ IF_128 xlow , xhigh;
+ /* cast x to xlow */
+ xlow.f = VEC_CAST_256_128(x.d);
+ /* extract x,1 to xhigh */
+ xhigh.f = VEC_EXTRACT_128(x.d, 1);
+ /* extract xlow[3] */
+ IF_128 shiftOutL128;
+ shiftOutL128.i = _mm_srli_si128(xlow.i, SHIFT_CONST1);
+ /* extract xhigh[3] */
+ IF_MAIN_TYPE shiftOutH;
+ shiftOutH.i = VEC_EXTRACT_UNIT(xhigh.i, SHIFT_CONST2);
+ shiftOut = shiftOutH.f;
+ /* shift xlow */
+ xlow.i = _mm_slli_si128 (xlow.i, SHIFT_CONST3);
+ /* shift xhigh */
+ xhigh.i = _mm_slli_si128 (xhigh.i, SHIFT_CONST3);
+ /*movss shiftIn to xlow[0] */
+ _128_TYPE shiftIn128 = VEC_SET1_VAL128(shiftIn);
+ xlow.f = VEC_MOVE(xlow.f , shiftIn128);
+ /*movss xlow[3] to xhigh[0] */
+ xhigh.f = VEC_MOVE(xhigh.f, shiftOutL128.f);
+ /* cast xlow to x */
+ x.d = VEC_CAST_128_256(xlow.f);
+ /* insert xhigh to x,1 */
+ x.d = VEC_INSERT_VAL(x.d, xhigh.f, 1);
+}
+
+
+inline void CONCAT(CONCAT(_vector_shift_last,SIMD_ENGINE), PRECISION) (UNION_TYPE &x, MAIN_TYPE shiftIn)
+{
+ IF_128 xlow , xhigh;
+ /* cast x to xlow */
+ xlow.f = VEC_CAST_256_128(x.d);
+ /* extract x,1 to xhigh */
+ xhigh.f = VEC_EXTRACT_128(x.d, 1);
+ /* extract xlow[3] */
+ IF_128 shiftOutL128;
+ shiftOutL128.i = _mm_srli_si128(xlow.i, SHIFT_CONST1);
+ /* shift xlow */
+ xlow.i = _mm_slli_si128 (xlow.i, SHIFT_CONST3);
+ /* shift xhigh */
+ xhigh.i = _mm_slli_si128 (xhigh.i, SHIFT_CONST3);
+ /*movss shiftIn to xlow[0] */
+ _128_TYPE shiftIn128 = VEC_SET1_VAL128(shiftIn);
+ xlow.f = VEC_MOVE(xlow.f , shiftIn128);
+ /*movss xlow[3] to xhigh[0] */
+ xhigh.f = VEC_MOVE(xhigh.f, shiftOutL128.f);
+ /* cast xlow to x */
+ x.d = VEC_CAST_128_256(xlow.f);
+ /* insert xhigh to x,1 */
+ x.d = VEC_INSERT_VAL(x.d, xhigh.f, 1);
+}
+
+#endif
+
+#ifdef SIMD_ENGINE_SSE
+
+inline void CONCAT(CONCAT(_vector_shift,SIMD_ENGINE), PRECISION) (UNION_TYPE &x, MAIN_TYPE shiftIn, MAIN_TYPE &shiftOut)
+{
+ IF_MAIN_TYPE tempIn, tempOut;
+ tempIn.f = shiftIn;
+ /* extratc H */
+ tempOut.i = VEC_EXTRACT_UNIT(x.i, SHIFT_CONST1);
+ shiftOut = tempOut.f;
+ /* shift */
+ x.i = _mm_slli_si128(x.i, SHIFT_CONST2);
+ /* insert L */
+ x.i = VEC_INSERT_UNIT(x.i , tempIn.i, SHIFT_CONST3);
+}
+
+inline void CONCAT(CONCAT(_vector_shift_last,SIMD_ENGINE), PRECISION) (UNION_TYPE &x, MAIN_TYPE shiftIn)
+{
+ IF_MAIN_TYPE temp; temp.f = shiftIn;
+ /* shift */
+ x.i = _mm_slli_si128(x.i, SHIFT_CONST2);
+ /* insert L */
+ x.i = VEC_INSERT_UNIT(x.i , temp.i, SHIFT_CONST3);
+}
+
+#endif
+
+#endif
diff --git a/public/VectorPairHMM/src/main/c++/sse_function_instantiations.cc b/public/VectorPairHMM/src/main/c++/sse_function_instantiations.cc
new file mode 100644
index 0000000..a8b88f6
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/sse_function_instantiations.cc
@@ -0,0 +1,44 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+
+#undef SIMD_ENGINE
+#undef SIMD_ENGINE_AVX
+
+#define SIMD_ENGINE sse
+#define SIMD_ENGINE_SSE
+
+#include "template.h"
+
+#include "define-sse-float.h"
+#include "shift_template.c"
+#include "pairhmm-template-kernel.cc"
+
+#include "define-sse-double.h"
+#include "shift_template.c"
+#include "pairhmm-template-kernel.cc"
+
+template double compute_full_prob_ssed<double>(testcase* tc, double* nextlog);
+template float compute_full_prob_sses<float>(testcase* tc, float* nextlog);
diff --git a/public/VectorPairHMM/src/main/c++/template.h b/public/VectorPairHMM/src/main/c++/template.h
new file mode 100644
index 0000000..550e763
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/template.h
@@ -0,0 +1,119 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef TEMPLATES_H_
+#define TEMPLATES_H_
+
+#include "headers.h"
+
+
+#define ALIGNED __attribute__((aligned(32)))
+
+#ifdef SIMD_ENGINE_AVX
+typedef union __attribute__((aligned(32))) {
+ ALIGNED __m256 ALIGNED d;
+ ALIGNED __m128i ALIGNED s[2];
+ ALIGNED float ALIGNED f[8];
+ ALIGNED __m256i ALIGNED i;
+} ALIGNED mix_F ALIGNED;
+#endif
+
+typedef union __attribute__((aligned(32))) {
+ ALIGNED __m128 ALIGNED d;
+ ALIGNED __m64 ALIGNED s[2];
+ ALIGNED float ALIGNED f[4];
+ ALIGNED __m128i ALIGNED i;
+} ALIGNED mix_F128 ALIGNED;
+
+typedef union ALIGNED {
+ __m128i vec ;
+ __m128 vecf ;
+ uint32_t masks[4] ;
+} MaskVec_F ;
+
+typedef union ALIGNED {
+ __m64 vec ;
+ __m64 vecf ;
+ uint32_t masks[2] ;
+} MaskVec_F128 ;
+
+typedef union ALIGNED
+{
+ ALIGNED __m128i ALIGNED i;
+ ALIGNED __m128 ALIGNED f;
+} ALIGNED IF_128f ALIGNED;
+
+typedef union ALIGNED
+{
+ ALIGNED int ALIGNED i;
+ ALIGNED float ALIGNED f;
+} ALIGNED IF_32 ALIGNED;
+
+#ifdef SIMD_ENGINE_AVX
+typedef union __attribute__((aligned(32))) {
+ ALIGNED __m256d ALIGNED d;
+ ALIGNED __m128i ALIGNED s[2];
+ ALIGNED double ALIGNED f[4];
+ ALIGNED __m256i ALIGNED i;
+} ALIGNED mix_D ALIGNED;
+#endif
+
+typedef union __attribute__((aligned(32))) {
+ ALIGNED __m128d ALIGNED d;
+ ALIGNED __m64 ALIGNED s[2];
+ ALIGNED double ALIGNED f[2];
+ ALIGNED __m128i ALIGNED i;
+} ALIGNED mix_D128 ALIGNED;
+
+typedef union ALIGNED {
+ __m128i vec ;
+ __m128d vecf ;
+ uint64_t masks[2] ;
+} MaskVec_D ;
+
+typedef union ALIGNED {
+ __m64 vec ;
+ __m64 vecf ;
+ uint64_t masks[1] ;
+} MaskVec_D128 ;
+
+typedef union ALIGNED
+{
+ ALIGNED __m128i ALIGNED i;
+ ALIGNED __m128d ALIGNED f;
+} ALIGNED IF_128d ALIGNED;
+
+typedef union ALIGNED
+{
+ ALIGNED int64_t ALIGNED i;
+ ALIGNED double ALIGNED f;
+} ALIGNED IF_64 ALIGNED;
+
+
+#include "common_data_structure.h"
+
+#endif
+
+
diff --git a/public/VectorPairHMM/src/main/c++/utils.cc b/public/VectorPairHMM/src/main/c++/utils.cc
new file mode 100644
index 0000000..3b0ce35
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/utils.cc
@@ -0,0 +1,567 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "headers.h"
+#include "utils.h"
+#include "LoadTimeInitializer.h"
+using namespace std;
+
+//static members from ConvertChar
+uint8_t ConvertChar::conversionTable[255];
+//Global function pointers in utils.h
+float (*g_compute_full_prob_float)(testcase *tc, float* before_last_log) = 0;
+double (*g_compute_full_prob_double)(testcase *tc, double* before_last_log) = 0;
+//Static members in ContextBase
+template<>
+bool ContextBase<double>::staticMembersInitializedFlag = false;
+template<>
+double ContextBase<double>::jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE] = { };
+template<>
+double ContextBase<double>::matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1] = { };
+template<>
+bool ContextBase<float>::staticMembersInitializedFlag = false;
+template<>
+float ContextBase<float>::jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE] = { };
+template<>
+float ContextBase<float>::matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1] = { };
+
+
+bool search_file_for_string(string filename, string search_string)
+{
+ ifstream fptr;
+ fptr.open(filename.c_str(),ios::in);
+ if(fptr.is_open())
+ {
+ string buffer;
+ buffer.clear();
+ buffer.resize(4096);
+ bool retvalue = false;
+ while(!fptr.eof())
+ {
+ fptr.getline(&(buffer[0]), 4096);
+ if(buffer.find(search_string) != string::npos) //found string
+ {
+ retvalue = true;
+ break;
+ }
+ }
+ buffer.clear();
+ fptr.close();
+ return retvalue;
+ }
+ else
+ return false;
+}
+
+bool is_cpuid_ecx_bit_set(int eax, int bitidx)
+{
+ int ecx = 0, edx = 0, ebx = 0;
+ __asm__ ("cpuid"
+ :"=b" (ebx),
+ "=c" (ecx),
+ "=d" (edx)
+ :"a" (eax)
+ );
+ return (((ecx >> bitidx)&1) == 1);
+}
+
+bool is_avx_supported()
+{
+#ifdef __INTEL_COMPILER
+ bool use_avx = _may_i_use_cpu_feature(_FEATURE_AVX);
+ if(use_avx)
+ return true;
+ else
+ {
+ //check if core supports AVX, but kernel does not and print info message
+ if(!is_cpuid_ecx_bit_set(1, 28)) //core does not support AVX
+ return false;
+ //else fall through to end of function
+ }
+#else
+ if(!__builtin_cpu_supports("avx")) //core does not support AVX
+ return false;
+ else
+ {
+ //core supports AVX, check if kernel supports
+ if(search_file_for_string("/proc/cpuinfo","avx"))
+ return true;
+ //else fall through to end of function
+
+ }
+#endif //__INTEL_COMPILER
+ clog << "INFO: Your CPU supports AVX vector instructions, but your kernel does not. Try upgrading to a kernel that supports AVX.\n";
+ clog << "INFO: Your program will run correctly, but slower than the AVX version\n";
+ return false;
+}
+
+bool is_sse41_supported()
+{
+#ifdef __INTEL_COMPILER
+ return (_may_i_use_cpu_feature(_FEATURE_SSE4_1) > 0);
+#else
+ return __builtin_cpu_supports("sse4.1");
+#endif
+ //return is_cpuid_ecx_bit_set(1, 19);
+}
+
+bool is_sse42_supported()
+{
+#ifdef __INTEL_COMPILER
+ return (_may_i_use_cpu_feature(_FEATURE_SSE4_2) > 0);
+#else
+ return __builtin_cpu_supports("sse4.2");
+#endif
+ //return is_cpuid_ecx_bit_set(1, 20);
+}
+
+uint64_t get_machine_capabilities()
+{
+ uint64_t machine_mask = 0ull;
+ if(is_avx_supported())
+ machine_mask |= (1 << AVX_CUSTOM_IDX);
+ if(is_sse42_supported())
+ machine_mask |= (1 << SSE42_CUSTOM_IDX);
+ if(is_sse41_supported())
+ machine_mask |= (1 << SSE41_CUSTOM_IDX);
+ return machine_mask;
+}
+
+void initialize_function_pointers(uint64_t mask)
+{
+ //mask = 0ull;
+ //mask = (1 << SSE41_CUSTOM_IDX);
+ if(is_avx_supported() && (mask & (1<< AVX_CUSTOM_IDX)))
+ {
+ cout << "Using AVX accelerated implementation of PairHMM\n";
+ g_compute_full_prob_float = compute_full_prob_avxs<float>;
+ g_compute_full_prob_double = compute_full_prob_avxd<double>;
+ }
+ else
+ if(is_sse41_supported() && (mask & ((1<< SSE41_CUSTOM_IDX) | (1<<SSE42_CUSTOM_IDX))))
+ {
+ cout << "Using SSE4.1 accelerated implementation of PairHMM\n";
+ g_compute_full_prob_float = compute_full_prob_sses<float>;
+ g_compute_full_prob_double = compute_full_prob_ssed<double>;
+ }
+ else
+ {
+ cout << "Using un-vectorized C++ implementation of PairHMM\n";
+ g_compute_full_prob_float = compute_full_prob<float>;
+ g_compute_full_prob_double = compute_full_prob<double>;
+ }
+}
+
+int normalize(char c)
+{
+ return ((int) (c - 33));
+}
+
+int read_testcase(testcase *tc, FILE* ifp)
+{
+ char *q, *i, *d, *c, *line = NULL;
+ int _q, _i, _d, _c;
+ int x, size = 0;
+ ssize_t read;
+
+
+ read = getline(&line, (size_t *) &size, ifp == 0 ? stdin : ifp);
+ if (read == -1)
+ {
+ free(line);
+ return -1;
+ }
+
+
+ tc->hap = (char *) malloc(size);
+ tc->rs = (char *) malloc(size);
+ q = (char *) malloc(size);
+ i = (char *) malloc(size);
+ d = (char *) malloc(size);
+ c = (char *) malloc(size);
+
+ if (sscanf(line, "%s %s %s %s %s %s\n", tc->hap, tc->rs, q, i, d, c) != 6)
+ return -1;
+
+
+ tc->haplen = strlen(tc->hap);
+ tc->rslen = strlen(tc->rs);
+ assert(strlen(q) == (size_t)tc->rslen);
+ assert(strlen(i) == (size_t)tc->rslen);
+ assert(strlen(d) == (size_t)tc->rslen);
+ assert(strlen(c) == (size_t)tc->rslen);
+
+ g_load_time_initializer.update_stat(READ_LENGTH_IDX, tc->rslen);
+ g_load_time_initializer.update_stat(HAPLOTYPE_LENGTH_IDX, tc->haplen);
+ g_load_time_initializer.update_stat(PRODUCT_READ_LENGTH_HAPLOTYPE_LENGTH_IDX, tc->haplen*tc->rslen);
+ //assert(tc->rslen < MROWS);
+ //tc->ihap = (int *) malloc(tc->haplen*sizeof(int));
+ //tc->irs = (int *) malloc(tc->rslen*sizeof(int));
+
+ tc->q = (char *) malloc(sizeof(char) * tc->rslen);
+ tc->i = (char *) malloc(sizeof(char) * tc->rslen);
+ tc->d = (char *) malloc(sizeof(char) * tc->rslen);
+ tc->c = (char *) malloc(sizeof(char) * tc->rslen);
+
+ for (x = 0; x < tc->rslen; x++)
+ {
+ _q = normalize(q[x]);
+ _i = normalize(i[x]);
+ _d = normalize(d[x]);
+ _c = normalize(c[x]);
+ tc->q[x] = (_q < 6) ? 6 : _q;
+ //tc->q[x] = _q;
+ tc->i[x] = _i;
+ tc->d[x] = _d;
+ tc->c[x] = _c;
+ //tc->irs[x] = tc->rs[x];
+ }
+ //for (x = 0; x < tc->haplen; x++)
+ //tc->ihap[x] = tc->hap[x];
+
+ free(q);
+ free(i);
+ free(d);
+ free(c);
+ free(line);
+
+
+
+ return 0;
+}
+
+unsigned MAX_LINE_LENGTH = 65536;
+int convToInt(std::string s)
+{
+ int i;
+ std::istringstream strin(s);
+ strin >> i;
+ return i;
+}
+
+void tokenize(std::ifstream& fptr, std::vector<std::string>& tokens)
+{
+ int i = 0;
+ std::string tmp;
+ std::vector<std::string> myVec;
+ vector<char> line;
+ line.clear();
+ line.resize(MAX_LINE_LENGTH);
+ vector<char> tmpline;
+ tmpline.clear();
+ tmpline.resize(MAX_LINE_LENGTH);
+ myVec.clear();
+
+ while(!fptr.eof())
+ {
+ i = 0;
+ bool still_read_line = true;
+ unsigned line_position = 0;
+ while(still_read_line)
+ {
+ fptr.getline(&(tmpline[0]), MAX_LINE_LENGTH);
+ if(line_position + MAX_LINE_LENGTH > line.size())
+ line.resize(2*line.size());
+ for(unsigned i=0;i<MAX_LINE_LENGTH && tmpline[i] != '\0';++i,++line_position)
+ line[line_position] = tmpline[i];
+ if(fptr.eof() || !fptr.fail())
+ {
+ still_read_line = false;
+ line[line_position++] = '\0';
+ }
+ }
+ std::istringstream kap(&(line[0]));
+
+ while(!kap.eof())
+ {
+ kap >> std::skipws >> tmp;
+ if(tmp != "")
+ {
+ myVec.push_back(tmp);
+ ++i;
+ //std::cout <<tmp <<"#";
+ }
+ tmp = "";
+ }
+ //std::cout << "\n";
+ if(myVec.size() > 0)
+ break;
+ }
+ tokens.clear();
+ //std::cout << "Why "<<myVec.size()<<"\n";
+ tokens.resize(myVec.size());
+ for(i=0;i<(int)myVec.size();++i)
+ tokens[i] = myVec[i];
+ line.clear();
+ tmpline.clear();
+}
+
+int read_mod_testcase(ifstream& fptr, testcase* tc, bool reformat)
+{
+ static bool first_call = true;
+ vector<string> tokens;
+ tokens.clear();
+ tokenize(fptr, tokens);
+ if(tokens.size() == 0)
+ return -1;
+ tc->hap = new char[tokens[0].size()+2];
+ tc->haplen = tokens[0].size();
+ memcpy(tc->hap, tokens[0].c_str(), tokens[0].size());
+ tc->rs = new char[tokens[1].size()+2];
+ tc->rslen = tokens[1].size();
+ tc->q = new char[tc->rslen];
+ tc->i = new char[tc->rslen];
+ tc->d = new char[tc->rslen];
+ tc->c = new char[tc->rslen];
+ //cout << "Lengths "<<tc->haplen <<" "<<tc->rslen<<"\n";
+ memcpy(tc->rs, tokens[1].c_str(),tokens[1].size());
+ assert(tokens.size() == (size_t)(2 + 4*(tc->rslen)));
+ //assert(tc->rslen < MROWS);
+ for(int j=0;j<tc->rslen;++j)
+ tc->q[j] = (char)convToInt(tokens[2+0*tc->rslen+j]);
+ for(int j=0;j<tc->rslen;++j)
+ tc->i[j] = (char)convToInt(tokens[2+1*tc->rslen+j]);
+ for(int j=0;j<tc->rslen;++j)
+ tc->d[j] = (char)convToInt(tokens[2+2*tc->rslen+j]);
+ for(int j=0;j<tc->rslen;++j)
+ tc->c[j] = (char)convToInt(tokens[2+3*tc->rslen+j]);
+
+ if(reformat)
+ {
+ ofstream ofptr;
+ ofptr.open("reformat/debug_dump.txt",first_call ? ios::out : ios::app);
+ assert(ofptr.is_open());
+ ofptr << tokens[0] << " ";
+ ofptr << tokens[1] << " ";
+ for(int j=0;j<tc->rslen;++j)
+ ofptr << ((char)(tc->q[j]+33));
+ ofptr << " ";
+ for(int j=0;j<tc->rslen;++j)
+ ofptr << ((char)(tc->i[j]+33));
+ ofptr << " ";
+ for(int j=0;j<tc->rslen;++j)
+ ofptr << ((char)(tc->d[j]+33));
+ ofptr << " ";
+ for(int j=0;j<tc->rslen;++j)
+ ofptr << ((char)(tc->c[j]+33));
+ ofptr << " 0 false\n";
+
+ ofptr.close();
+ first_call = false;
+ }
+
+
+ return tokens.size();
+}
+
+double getCurrClk() {
+ struct timeval tv ;
+ gettimeofday(&tv, NULL);
+ return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
+}
+
+inline unsigned long long rdtsc(void)
+{
+ unsigned hi, lo;
+ __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+ return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
+}
+
+void get_time(struct timespec* store_struct)
+{
+ clock_gettime(CLOCK_REALTIME, store_struct);
+}
+
+uint64_t diff_time(struct timespec& prev_time)
+{
+ struct timespec curr_time;
+ clock_gettime(CLOCK_REALTIME, &curr_time);
+ return (uint64_t)((curr_time.tv_sec-prev_time.tv_sec)*1000000000+(curr_time.tv_nsec-prev_time.tv_nsec));
+}
+
+
+#ifdef USE_PAPI
+#include "papi.h"
+#define NUM_PAPI_COUNTERS 4
+#endif
+
+void do_compute(char* filename, bool use_old_read_testcase, unsigned chunk_size, bool do_check)
+{
+ FILE* fptr = 0;
+ ifstream ifptr;
+ if(use_old_read_testcase)
+ {
+ fptr = fopen(filename,"r");
+ assert(fptr);
+ }
+ else
+ {
+ ifptr.open(filename);
+ assert(ifptr.is_open());
+ }
+#ifdef PRINT_PER_INTERVAL_TIMINGS
+ ofstream times_fptr;
+ times_fptr.open("native_timed_intervals.csv",ios::out);
+#endif
+ vector<testcase> tc_vector;
+ tc_vector.clear();
+ testcase tc;
+ uint64_t vector_compute_time = 0;
+ uint64_t baseline_compute_time = 0;
+ uint64_t num_double_calls = 0;
+ unsigned num_testcases = 0;
+ bool all_ok = do_check ? true : false;
+#ifdef USE_PAPI
+ uint32_t all_mask = (0);
+ uint32_t no_usr_mask = (1 << 16); //bit 16 user mode, bit 17 kernel mode
+ uint32_t no_kernel_mask = (1 << 17); //bit 16 user mode, bit 17 kernel mode
+ PAPI_num_counters();
+ int events[NUM_PAPI_COUNTERS] = { 0, 0, 0, 0 };
+ char* eventnames[NUM_PAPI_COUNTERS]= { "cycles", "l1_pending_miss", "lfb_hit", "l2_hit" };
+ assert(PAPI_event_name_to_code("UNHALTED_REFERENCE_CYCLES:u=1:k=1",&(events[0])) == PAPI_OK);
+ assert(PAPI_event_name_to_code("L1D_PEND_MISS:OCCURRENCES", &(events[1])) == PAPI_OK);
+ assert(PAPI_event_name_to_code("MEM_LOAD_UOPS_RETIRED:HIT_LFB", &(events[2])) == PAPI_OK);
+ assert(PAPI_event_name_to_code("MEM_LOAD_UOPS_RETIRED:L2_HIT", &(events[3])) == PAPI_OK);
+ long long values[NUM_PAPI_COUNTERS] = { 0, 0, 0, 0 };
+ long long accum_values[NUM_PAPI_COUNTERS] = { 0, 0, 0, 0 };
+#endif
+ while(1)
+ {
+ int break_value = use_old_read_testcase ? read_testcase(&tc, fptr) : read_mod_testcase(ifptr,&tc,true);
+ if(break_value >= 0)
+ tc_vector.push_back(tc);
+ if(tc_vector.size() == BATCH_SIZE || (break_value < 0 && tc_vector.size() > 0))
+ {
+ vector<double> results_vec;
+ vector<double> baseline_results_vec;
+ results_vec.clear();
+ baseline_results_vec.clear();
+ results_vec.resize(tc_vector.size());
+ baseline_results_vec.resize(tc_vector.size());
+ g_load_time_initializer.update_stat(NUM_TESTCASES_IDX, tc_vector.size());
+ g_load_time_initializer.update_stat(NUM_READS_IDX, tc_vector.size());
+ g_load_time_initializer.update_stat(NUM_HAPLOTYPES_IDX, tc_vector.size());
+ struct timespec start_time;
+#ifdef USE_PAPI
+ assert(PAPI_start_counters(events, NUM_PAPI_COUNTERS) == PAPI_OK);
+#endif
+ get_time(&start_time);
+#pragma omp parallel for schedule(dynamic,chunk_size) num_threads(12)
+#ifdef DO_REPEAT_PROFILING
+ for(unsigned z=0;z<10;++z)
+#endif
+ {
+ for(unsigned i=0;i<tc_vector.size();++i)
+ {
+ testcase& tc = tc_vector[i];
+ float result_avxf = g_compute_full_prob_float(&tc, 0);
+ double result = 0;
+ if (result_avxf < MIN_ACCEPTED) {
+ double result_avxd = g_compute_full_prob_double(&tc, 0);
+ result = log10(result_avxd) - log10(ldexp(1.0, 1020.0));
+ ++num_double_calls;
+ }
+ else
+ result = (double)(log10f(result_avxf) - log10f(ldexpf(1.f, 120.f)));
+#ifdef DUMP_COMPUTE_VALUES
+ g_load_time_initializer.debug_dump("return_values_vector.txt",to_string(result),true);
+#endif
+ results_vec[i] = result;
+ }
+ }
+#ifdef USE_PAPI
+ assert(PAPI_stop_counters(values, NUM_PAPI_COUNTERS) == PAPI_OK);
+#endif
+ uint64_t curr_interval = diff_time(start_time);
+#ifdef PRINT_PER_INTERVAL_TIMINGS
+ times_fptr << curr_interval << "\n";
+#endif
+ vector_compute_time += curr_interval;
+#ifdef USE_PAPI
+ for(unsigned k=0;k<NUM_PAPI_COUNTERS;++k)
+ accum_values[k] += values[k];
+#endif
+ num_testcases += tc_vector.size();
+ if(do_check)
+ {
+ get_time(&start_time);
+#pragma omp parallel for schedule(dynamic,chunk_size)
+ for(unsigned i=0;i<tc_vector.size();++i)
+ {
+ testcase& tc = tc_vector[i];
+ double baseline_result = compute_full_prob<double>(&tc);
+ baseline_result = log10(baseline_result) - log10(ldexp(1.0, 1020.0));
+ baseline_results_vec[i] = baseline_result;
+ }
+ baseline_compute_time += diff_time(start_time);
+ for(unsigned i=0;i<tc_vector.size();++i)
+ {
+ double baseline_result = baseline_results_vec[i];
+ double abs_error = fabs(baseline_result-results_vec[i]);
+ double rel_error = (baseline_result != 0) ? fabs(abs_error/baseline_result) : 0;
+ if(abs_error > 1e-5 && rel_error > 1e-5)
+ {
+ cout << std::scientific << baseline_result << " "<<results_vec[i]<<"\n";
+ all_ok = false;
+ }
+ }
+ }
+ for(unsigned i=0;i<tc_vector.size();++i)
+ {
+ delete[] tc_vector[i].rs;
+ delete[] tc_vector[i].hap;
+ delete[] tc_vector[i].q;
+ delete[] tc_vector[i].i;
+ delete[] tc_vector[i].d;
+ delete[] tc_vector[i].c;
+ }
+ results_vec.clear();
+ tc_vector.clear();
+ }
+ if(break_value < 0)
+ break;
+ }
+#ifdef DUMP_COMPUTE_VALUES
+ g_load_time_initializer.debug_close();
+#endif
+ if(all_ok)
+ {
+ cout << "All output values within acceptable error\n";
+ cout << "Baseline double precision compute time "<<baseline_compute_time*1e-9<<"\n";
+ }
+ cout << "Num testcase "<<num_testcases<< " num double invocations "<<num_double_calls<<"\n";
+ cout << "Vector compute time "<< vector_compute_time*1e-9 << "\n";
+#ifdef USE_PAPI
+ for(unsigned i=0;i<NUM_PAPI_COUNTERS;++i)
+ cout << eventnames[i] << " : "<<accum_values[i]<<"\n";
+#endif
+#ifdef PRINT_PER_INTERVAL_TIMINGS
+ times_fptr.close();
+#endif
+ if(use_old_read_testcase)
+ fclose(fptr);
+ else
+ ifptr.close();
+ g_load_time_initializer.print_profiling();
+}
diff --git a/public/VectorPairHMM/src/main/c++/utils.h b/public/VectorPairHMM/src/main/c++/utils.h
new file mode 100644
index 0000000..3b10a58
--- /dev/null
+++ b/public/VectorPairHMM/src/main/c++/utils.h
@@ -0,0 +1,85 @@
+/*Copyright (c) 2012 The Broad Institute
+
+*Permission is hereby granted, free of charge, to any person
+*obtaining a copy of this software and associated documentation
+*files (the "Software"), to deal in the Software without
+*restriction, including without limitation the rights to use,
+*copy, modify, merge, publish, distribute, sublicense, and/or sell
+*copies of the Software, and to permit persons to whom the
+*Software is furnished to do so, subject to the following
+*conditions:
+
+*The above copyright notice and this permission notice shall be
+*included in all copies or substantial portions of the Software.
+
+*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+*THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef PAIRHMM_UTIL_H
+#define PAIRHMM_UTIL_H
+
+#include "common_data_structure.h"
+
+template<class T>
+std::string to_string(T obj)
+{
+ std::stringstream ss;
+ std::string ret_string;
+ ss.clear();
+ ss << std::scientific << obj;
+ ss >> ret_string;
+ ss.clear();
+ return ret_string;
+}
+void debug_dump(std::string filename, std::string s, bool to_append, bool add_newline=true);
+
+int read_mod_testcase(std::ifstream& fptr, testcase* tc, bool reformat=false);
+
+bool is_avx_supported();
+bool is_sse42_supported();
+extern float (*g_compute_full_prob_float)(testcase *tc, float *before_last_log);
+extern double (*g_compute_full_prob_double)(testcase *tc, double* before_last_log);
+void debug_dump(std::string filename, std::string s, bool to_append, bool add_newline);
+template<class NUMBER>
+NUMBER compute_full_prob(testcase *tc, NUMBER *before_last_log=0);
+template<class NUMBER>
+NUMBER compute_full_prob_avxd(testcase *tc, NUMBER *before_last_log=0);
+template<class NUMBER>
+NUMBER compute_full_prob_avxs(testcase *tc, NUMBER *before_last_log=0);
+template<class NUMBER>
+NUMBER compute_full_prob_ssed(testcase *tc, NUMBER *before_last_log=0);
+template<class NUMBER>
+NUMBER compute_full_prob_sses(testcase *tc, NUMBER *before_last_log=0);
+
+double getCurrClk();
+void get_time(struct timespec* x);
+uint64_t diff_time(struct timespec& prev_time);
+
+//bit 0 is sse4.2, bit 1 is AVX
+enum ProcessorCapabilitiesEnum
+{
+ SSE41_CUSTOM_IDX=0,
+ SSE42_CUSTOM_IDX,
+ AVX_CUSTOM_IDX
+};
+#define ENABLE_ALL_HARDWARE_FEATURES 0xFFFFFFFFFFFFFFFFull
+uint64_t get_machine_capabilities();
+void initialize_function_pointers(uint64_t mask=ENABLE_ALL_HARDWARE_FEATURES);
+void do_compute(char* filename, bool use_old_read_testcase=true, unsigned chunk_size=10000, bool do_check=true);
+
+//#define DO_WARMUP
+//#define DO_REPEAT_PROFILING
+/*#define DUMP_COMPUTE_VALUES 1*/
+#define BATCH_SIZE 10000
+#define RUN_HYBRID
+/*#define PRINT_PER_INTERVAL_TIMINGS 1*/
+
+#endif
diff --git a/public/c/SeparateQltout.cc b/public/c/SeparateQltout.cc
new file mode 100644
index 0000000..7644c96
--- /dev/null
+++ b/public/c/SeparateQltout.cc
@@ -0,0 +1,70 @@
+#include "MainTools.h"
+#include "Basevector.h"
+#include "lookup/LookAlign.h"
+#include "lookup/SerialQltout.h"
+
+unsigned int MatchingEnd(look_align &la, vecbasevector &candidates, vecbasevector &ref) {
+ //la.PrintParseable(cout);
+
+ for (int i = 0; i < candidates.size(); i++) {
+ look_align newla = la;
+
+ if (newla.rc1) { candidates[i].ReverseComplement(); }
+ newla.ResetFromAlign(newla.a, candidates[i], ref[la.target_id]);
+
+ //newla.PrintParseable(cout, &candidates[i], &ref[newla.target_id]);
+ //cout << newla.Errors() << " " << la.Errors() << endl;
+
+ if (newla.Errors() == la.Errors()) {
+ return i;
+ }
+ }
+
+ //FatalErr("Query id " + ToString(la.query_id) + " had no matches.");
+
+ return candidates.size() + 1;
+}
+
+int main(int argc, char **argv) {
+ RunTime();
+
+ BeginCommandArguments;
+ CommandArgument_String(ALIGNS);
+ CommandArgument_String(FASTB_END_1);
+ CommandArgument_String(FASTB_END_2);
+ CommandArgument_String(REFERENCE);
+
+ CommandArgument_String(ALIGNS_END_1_OUT);
+ CommandArgument_String(ALIGNS_END_2_OUT);
+ EndCommandArguments;
+
+ vecbasevector ref(REFERENCE);
+ vecbasevector reads1(FASTB_END_1);
+ vecbasevector reads2(FASTB_END_2);
+
+ ofstream aligns1stream(ALIGNS_END_1_OUT.c_str());
+ ofstream aligns2stream(ALIGNS_END_2_OUT.c_str());
+
+ basevector bv;
+
+ SerialQltout sqltout(ALIGNS);
+ look_align la;
+ while (sqltout.Next(la)) {
+ vecbasevector candidates(2);
+ candidates[0] = reads1[la.query_id];
+ candidates[1] = reads2[la.query_id];
+
+ unsigned int matchingend = MatchingEnd(la, candidates, ref);
+ if (matchingend < 2) {
+ bv = (matchingend == 0) ? reads1[la.query_id] : reads2[la.query_id];
+
+ //la.PrintParseable(cout, &bv, &ref[la.target_id]);
+ la.PrintParseable(((matchingend == 0) ? aligns1stream : aligns2stream), &bv, &ref[la.target_id]);
+ }
+ }
+
+ aligns1stream.close();
+ aligns2stream.close();
+
+ return 0;
+}
diff --git a/public/c/libenvironhack/Makefile b/public/c/libenvironhack/Makefile
new file mode 100644
index 0000000..302ff8e
--- /dev/null
+++ b/public/c/libenvironhack/Makefile
@@ -0,0 +1,10 @@
+CC=gcc
+CCFLAGS=-Wall -dynamiclib -arch i386 -arch x86_64
+
+libenvironhack.dylib: libenvironhack.c
+ $(CC) $(CCFLAGS) -init _init_environ $< -o $@
+
+all: libenvironhack.dylib
+
+clean:
+ rm -f libenvironhack.dylib
diff --git a/public/c/libenvironhack/libenvironhack.c b/public/c/libenvironhack/libenvironhack.c
new file mode 100644
index 0000000..8b2a264
--- /dev/null
+++ b/public/c/libenvironhack/libenvironhack.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+LSF 7.0.6 on the mac is missing the unsatisfied exported symbol for environ which was removed on MacOS X 10.5+.
+nm $LSF_LIBDIR/liblsf.dylib | grep environ
+See "man environ" for more info, along with http://lists.apple.com/archives/java-dev/2007/Dec/msg00096.html
+*/
+
+#include <crt_externs.h>
+
+char **environ = (char **)0;
+
+void init_environ(void) {
+ environ = (*_NSGetEnviron());
+}
diff --git a/public/c/libenvironhack/libenvironhack.dylib b/public/c/libenvironhack/libenvironhack.dylib
new file mode 100755
index 0000000..a45e038
Binary files /dev/null and b/public/c/libenvironhack/libenvironhack.dylib differ
diff --git a/public/chainFiles/b36tob37.chain b/public/chainFiles/b36tob37.chain
new file mode 100644
index 0000000..f1de2b8
--- /dev/null
+++ b/public/chainFiles/b36tob37.chain
@@ -0,0 +1,30854 @@
+chain 1574309 MT 16571 + 0 16571 MT 16569 + 0 16569 1567
+302 1 0
+8 1 0
+2796 0 1
+13086 1 0
+376
+
+chain 21270159960 1 247249719 + 0 247199719 1 249250621 + 10000 249233096 2
+616 0 137
+166664 50000 50000
+40302 50000 50000
+153649 50000 50000
+1098446 269 272
+773 1 1
+43 1 1
+864369 2 2
+51 0 3
+104 13694 13694
+104 3 0
+51 2 2
+134936 50000 50000
+1161048 60000 150000
+1440092 50000 27273
+7590365 50000 50000
+116914 50088 100088
+237162 50000 50000
+3518496 50000 50000
+12702424 50000 150000
+16145012 1 0
+7772 0 1
+4705841 1 0
+52977198 50000 50000
+157344 50000 21065
+16604841 50000 50000
+189539 50000 150000
+398739 20290000 21050000
+195588 50000 50000
+186739 50000 150000
+175055 50000 50000
+201709 50000 100000
+126477 50000 130183
+381 3 0
+315 2 0
+62 1 1
+73 1 1
+1158 0 1
+314 1 0
+11 1 1
+2849 0 3
+5615 1 1
+37 1 1
+3172 4 6
+190 1 1
+34 1 1
+380 1 0
+2099 0 3
+1135 4 0
+970 5 5
+209 0 1
+460 1 0
+1242 28 28
+574 1 1
+21 1 1
+2268 0 3
+239 1 0
+970 11 11
+2365 1 1
+21 1 1
+384 8 8
+996 0 2
+10383 0 2
+713 1 0
+5188 1 1
+30 1 1
+1233 0 1
+132 1 1
+44 1 1
+2955 0 1
+512 1 1
+39 1 1
+1096 16 0
+743 0 1
+9028 1 0
+2506 6 0
+8446 0 2
+5505 3 0
+7541 0 1
+109864 50000 50000
+78698 50000 50000
+127263 50000 50000
+170669 50000 50000
+38311 100000 100000
+1022394 50000 50000
+281532 50000 294733
+1687 1 1
+39 0 1
+1018 1 1
+26 1 1
+1722 0 2
+158 0 4
+1602 6 0
+1384 0 1
+2066 1 1
+32 3 1
+1556908 50000 150000
+185320 50000 150000
+172789 50000 50000
+220313 50000 50000
+455185 50000 50000
+22047237 0 1
+34365824 50000 150000
+259514 50000 150000
+17265625 50000 50000
+11394365 50000 50000
+13665999 50000 150000
+174886
+
+chain 989083 1 247249719 + 2475290 2488984 1 249250621 - 246751494 246765188 1383
+13694
+
+chain 5421 1 247249719 + 1609759 1609849 1 249250621 + 1672838 1672928 2227793
+90
+
+chain 3303 1 247249719 + 13192499 13192587 1 249250621 - 236203315 236203403 109
+88
+
+chain 467 1 247249719 + 142633259 142633287 1 249250621 - 128420441 128420469 123
+28
+
+chain 12431961244 10 135374737 + 50000 135374737 10 135534747 + 60000 135524747 10
+5577107 50006 0
+12337568 50000 50000
+20794160 50000 50000
+286100 2480000 3200000
+191752 50000 50000
+3830277 150000 50000
+952205 150000 100000
+263307 150000 100000
+163231 150000 50000
+989829 150000 100000
+1941874 50000 50000
+211435 50000 50000
+30112515 319974 0
+13249156 10 0
+31058956 50000 50000
+2696597 50000 150000
+4615335 10000 50000
+246123 50000 50000
+1327328 1 1
+47 1 1
+1312 1 0
+56 1 1
+190 1 1
+31 1 1
+20182 0 1
+448068
+
+chain 8134587 10 135374737 + 81444609 81551340 10 135534747 + 88976631 89083503 218
+369 41 41
+149 6 6
+83 71 71
+548 9 9
+391 9 9
+334 42 42
+81 1 2
+954 1 0
+441 0 4
+922 37 37
+343 253 253
+278 59 58
+404 13 13
+90 39 37
+70 132 123
+145 4 4
+392 9 9
+58 29 29
+166 51 50
+78 14 14
+455 61 65
+243 41 41
+1183 17 17
+163 57 57
+169 51 51
+912 5 5
+667 12 12
+250 20 20
+506 8 8
+292 8 8
+266 17 17
+69 27 27
+131 22 22
+668 46 47
+270 13 13
+128 7 7
+300 48 48
+818 32 32
+667 67 67
+402 24 36
+293 18 18
+423 68 68
+113 9 9
+630 42 42
+269 51 51
+165 0 1
+645 52 52
+76 91 90
+505 13 13
+143 31 31
+319 68 70
+245 126 126
+145 35 37
+90 57 57
+378 41 38
+193 13 13
+333 51 30
+51 6 6
+821 56 56
+547 18 18
+343 9 9
+270 47 47
+706 1 0
+120 21 22
+371 35 35
+530 13 13
+51 36 36
+611 48 48
+587 18 18
+499 9 9
+183 26 26
+847 7 7
+134 5 4
+64 34 34
+120 66 66
+173 147 147
+126 19 16
+53 44 49
+69 1 0
+153 89 90
+81 16 16
+52 32 36
+72 28 28
+86 68 68
+56 51 51
+120 17 17
+181 5 5
+86 17 18
+68 36 36
+356 101 101
+90 3 11
+226 26 28
+70 19 19
+95 9 9
+88 16 16
+272 33 33
+216 71 71
+394 83 83
+853 14 15
+90 23 23
+130 0 3
+52 11 11
+192 49 49
+407 13 13
+122 71 34
+179 28 28
+102 10 10
+299 36 36
+268 4 4
+123 36 36
+112 41 41
+233 77 75
+73 88 92
+519 43 43
+118 101 101
+78 33 43
+117 31 31
+83 37 37
+86 3 0
+468 0 2
+791 55 55
+268 97 97
+111 55 59
+164 38 38
+176 0 3
+116 67 74
+269 0 3
+92 66 67
+205 50 55
+1339 33 34
+86 9 9
+310 34 34
+217 42 42
+194 18 17
+191 4 4
+250 0 3
+148 79 79
+77 3 0
+199 57 57
+200 53 53
+331 52 53
+136 32 42
+69 60 60
+169 0 1
+594 88 88
+174 70 70
+135 48 48
+53 9 9
+862 25 25
+1106 33 33
+974 76 76
+368 17 17
+369 43 43
+263 49 49
+143 8 8
+228 57 57
+74 3 0
+914 2 0
+137 77 74
+243 32 32
+166 53 53
+646 87 87
+71 0 1
+661 45 45
+142 76 76
+851 17 17
+56 60 60
+52 59 58
+80 60 60
+602 13 13
+617 76 78
+51 152 152
+77 38 38
+150 0 4
+386 45 45
+585 40 33
+108 12 12
+219 99 99
+1376 58 58
+517 27 27
+124 20 20
+566 58 58
+235 47 47
+72 26 26
+157 43 43
+208 31 31
+578 122 84
+259 15 15
+1141 119 119
+141 13 13
+817 14 14
+188 0 5
+323 62 75
+447 0 5
+64 161 161
+945 23 23
+66 35 35
+104 125 125
+613 186 184
+102 205 203
+767 27 27
+111 13 13
+107 80 83
+272 0 1
+438 4 4
+127 68 68
+564 44 44
+141 14 14
+137 13 17
+167 18 0
+241 25 25
+586 30 30
+178 44 44
+310 90 87
+1277 35 35
+646 32 32
+704 56 56
+367 93 101
+241 15 14
+340 64 64
+1000 23 26
+163 81 81
+895 12 12
+345 2 0
+117 48 49
+491 32 32
+206 17 17
+439 109 109
+202 6 7
+756 24 24
+380 63 62
+144 48 48
+608 80 80
+154 71 71
+232 16 16
+1809 40 40
+346 53 52
+117 10 0
+383 10 10
+1973 19 19
+879 42 42
+91 50 50
+1147 2 1
+210 68 88
+189 7 7
+595 50 49
+248 104 126
+265 106 106
+167 0 7
+141 93 62
+825 1 0
+348 47 46
+211 3 0
+114 52 56
+66 7 7
+759 48 48
+269 0 1
+106 109 114
+114 38 39
+282 20 20
+504 0 1
+174 14 7
+123 45 46
+82 58 58
+203 12 13
+153 44 44
+121 74 74
+805 43 43
+120 67 68
+171 6 6
+329 20 20
+151 33 33
+71 46 46
+195 25 21
+65 23 42
+96 78 78
+58 0 4
+389 0 3
+214 137 138
+111 2 3
+116 10 10
+128 0 3
+52 8 8
+62 43 43
+142 6 6
+214 0 112
+179 0 1
+234 4 0
+75 116 117
+119 63 67
+286 72 42
+73 150 150
+206 214 220
+73 2 0
+82 48 48
+135 40 67
+115 109 114
+185 49 49
+99 63 63
+52 204 205
+121
+
+chain 2724232 10 135374737 + 81309951 81339951 10 135534747 + 81320000 81350000 983
+22137 957 957
+46 77 77
+38 83 83
+51 54 54
+984 53 53
+5520
+
+chain 1898345 10 135374737 + 81349952 81369946 10 135534747 + 81360000 81380000 1327
+15902 21 27
+4071
+
+chain 946327 10 135374737 + 81339951 81349952 10 135534747 + 81350000 81360000 2894
+6692 1 0
+3308
+
+chain 939763 10 135374737 + 81430217 81440202 10 135534747 + 81440000 81450000 3159
+163 3 0
+518 0 16
+972 42 43
+5149 0 1
+3138
+
+chain 928169 10 135374737 + 81379935 81389948 10 135534747 + 81390000 81400000 3587
+1970 7 8
+141 10 0
+413 39 39
+622 4 0
+574 42 42
+2153 0 2
+1520 5 3
+2513
+
+chain 922636 10 135374737 + 81300280 81309951 10 135534747 + 81310330 81320000 2721
+2989 1 0
+6681
+
+chain 885793 10 135374737 + 81369946 81379851 10 135534747 + 81380000 81389916 4570
+507 30 32
+880 91 91
+1155 82 82
+784 10 10
+907 16 28
+1265 50 50
+859 0 3
+1375 1 2
+165 27 27
+124 29 29
+275 8 8
+308 6 0
+79 1 0
+871
+
+chain 839370 10 135374737 + 81389948 81399836 10 135534747 + 81400000 81409799 4960
+446 1 0
+639 0 1
+112 140 59
+198 24 22
+98 162 137
+63 10 10
+97 180 192
+71 31 33
+322 38 38
+431 0 1
+741 45 46
+229 1 3
+186 1 4
+3019 14 14
+131 1 0
+722 16 16
+1530 92 92
+32 2 1
+63
+
+chain 788625 10 135374737 + 81241464 81249852 10 135534747 + 81251575 81259959 6147
+783 1 0
+883 23 33
+3247 1 0
+143 31 31
+957 15 3
+2304
+
+chain 781678 10 135374737 + 81280054 81289770 10 135534747 + 81290109 81299824 3334
+65 841 841
+84 228 228
+27 240 240
+1767 0 10
+186 66 54
+976 0 3
+1495 0 7
+899 0 1
+376 7 7
+2156 10 0
+196 50 50
+47
+
+chain 778944 10 135374737 + 81250813 81551219 10 135534747 - 53516479 54101824 544
+53 63 72
+96 209 213
+193 44 44
+202 331 335
+149 28 28
+100 125 123
+56 238 272
+60 91 93
+123 9 11
+66 147 144
+82 210 211
+77 17 17
+196 31 31
+379 27 27
+954 71 71
+69 4431 3721
+746 66 66
+502 12 12
+282 28 28
+224 59 59
+52 35 35
+448 12 0
+474 42 42
+260 11 11
+83 38 44
+160 152 149
+284 76 76
+110 73 73
+284 9 9
+478 110 110
+95 5 5
+583 122 122
+116 1 1
+67 1 1
+118 1 1
+38 1 1
+566 1 1
+35 1 1
+287 1 0
+481 1 1
+42 1 1
+198 1 1
+22 1 1
+54 1 1
+25 1 1
+50 1 1
+50 1 1
+294 4 0
+158 1 1
+31 1 1
+255 8 8
+291 12 12
+171 2 2
+21 1 1
+685 77 77
+817 20 20
+312 39 39
+181 1 0
+249 50 47
+75 7 7
+86 4 4
+54 8 8
+518 134 134
+376 24 26
+189 17 27
+143 13 13
+93 16 16
+192 24 24
+992 140 132
+828 1 1
+40 1 1
+410 1 1
+25 0 2
+13 1 1
+83 8 8
+143 1 1
+20 1 1
+421 1 1
+49 1 1
+107 1 1
+28 1 1
+77 1 1
+32 0 2
+44 2 2
+348 1 1
+53 0 4
+58 1 1
+97 1 1
+125 56 53
+526 1 1
+46 1 1
+209 9 9
+76 1 1
+37 1 1
+53 1 1
+24 1 1
+141 1 1
+26 1 1
+304 1 1
+60 1 1
+199 1 1
+47 1 1
+92 6 0
+138 64 64
+299 65 65
+186 24 24
+631 84 84
+100 20 20
+108 27 27
+240 8134 8243
+50 47 45
+107 11 11
+750 5 5
+230 25 25
+221 62 62
+106 32 32
+106 52 52
+270 56 56
+166 31 31
+89 77 77
+127 666 662
+56 22 22
+55 95 83
+51 30 30
+77 35 35
+189 16 16
+130 53 53
+131 5 5
+158 140 131
+170 21 21
+55 79 79
+207 200 199
+152 11 11
+105 50 50
+104 34 34
+56 402 402
+69 0 1
+61 150 150
+181 10 10
+130 22 22
+180 5 0
+73 161 161
+77 151 151
+68 128 128
+330 138 126
+116 1211 328
+252 4 4
+102 8 8
+72 23 23
+51 51 51
+608 31808 287592
+56 14 14
+161 9 9
+717 46 50
+77 38 30
+83 51 51
+54 984 987
+53 65700 95386
+47 559 556
+99 119 119
+193 38 38
+164 12 7
+59 38 38
+58 9 5
+57 34 34
+68 30 30
+59 28 28
+51 82 87
+142 7 7
+67 162 152
+248 1 2
+114 34 34
+140 22 22
+58 119 118
+143 50 50
+255 69 65
+53 18 18
+127 11 13
+446 39 39
+134 24 24
+143 42 42
+123 65 65
+57 0 3
+199 73 73
+271 17 17
+113 24 24
+203 40 40
+51 38 38
+119 50 50
+81 60 60
+239 85 70
+79 219 219
+64 149 150
+29 211 211
+91 319 310
+76 40 40
+59 596 591
+34 579 579
+51 90 90
+169 336 329
+146 226 226
+50 480 479
+23 66 66
+95 447 447
+49 298 298
+29 180 180
+45 1186 1169
+53 2222 2217
+11 116 116
+33 313 313
+63 75 75
+14 257 258
+31 122 122
+73 311 316
+238 46 46
+130 81 78
+103 262 266
+56 168 163
+29 861 857
+61 655 666
+18 40 40
+436 1 1
+8 4 0
+35 1 1
+417 21 18
+51 2 0
+54 1 1
+126 10 9
+72 5 5
+377 1 1
+18 2 0
+35 2 2
+78 1 2
+18 2 2
+82 1 0
+99 1 1
+82 0 4
+99 1 1
+50 0 4
+50 7 7
+225 11 11
+135 2 0
+326 26 989
+2646 0 1
+560 10 0
+347 114 114
+284 118541 118621
+43 120 120
+65 1 0
+1 677 677
+33 71 71
+46 404 404
+78 661 663
+137 489 492
+43 854 846
+116 119 119
+63 286 286
+72 73 73
+150 206 206
+17 1 1
+85 1 1
+110 157 157
+48 135 135
+36 0 4
+4 115 115
+73 2 0
+19 1 1
+14 185 185
+49 99 99
+22 1 1
+40 79 80
+177
+
+chain 662550 10 135374737 + 81399647 81430169 10 135534747 - 46431029 46458544 512
+92 103 101
+125 0 2222
+53 53 50
+58 48 48
+298 191 189
+69 6167 5
+118 101 101
+128 111 111
+207 48 43
+55 175 169
+212 93 89
+159 23 23
+109 34 34
+150 21 20
+258 30 30
+120 51 54
+90 171 171
+268 224 219
+202 62 62
+480 237 237
+394 49 49
+100 28 28
+93 25 25
+52 29 29
+180 45 45
+141 47 47
+56 49 49
+169 39 42
+60 102 113
+53 1 13
+151 105 105
+58 33 30
+88 246 246
+334 116 116
+63 83 84
+268 115 113
+70 43 43
+252 2 1
+62 97 97
+88 6 0
+61 23 23
+84 75 75
+75 2 3
+83 8 8
+53 160 162
+312 153 152
+192 96 98
+122 95 100
+94 793 791
+61 1 5
+154 140 135
+130 32 33
+121 21 21
+82 6 6
+171 34 34
+110 52 49
+129 193 194
+64 26 29
+72 18 18
+286 75 58
+114 6596 7638
+114 284 172
+558 8 9
+111 5 5
+55 2 2
+80 0 1
+27 1 1
+72 1 1
+45 1 1
+516 1 1
+66 1 1
+106 23 42
+64 4 0
+21 1 1
+312 2 2
+30 1 1
+151 20 20
+193 1 1
+38 1 1
+96 6 6
+171 0 3
+27 0 2
+34 2 2
+120 3 3
+39 1 1
+752
+
+chain 650336 10 135374737 + 81249915 81259740 10 135534747 + 81260018 81269841 3195
+898 53 53
+63 96 96
+209 193 193
+44 202 202
+331 149 149
+28 100 100
+125 56 56
+238 60 60
+91 198 198
+147 82 82
+210 290 290
+31 1360 1360
+71 69 69
+196 1 0
+454 16 15
+3764
+
+chain 462746 10 135374737 + 81440202 81450008 10 135534747 + 81450000 81459803 2861
+1116 4 4
+801 3 0
+2483 369 369
+41 238 238
+71 1291 1291
+42 2400 2400
+37 343 343
+253 278 278
+36
+
+chain 389885 10 135374737 + 81290873 81299672 10 135534747 + 81300927 81309722 2802
+25 221 221
+62 106 106
+32 106 106
+52 270 270
+56 166 166
+31 89 89
+77 127 127
+666 133 133
+95 51 51
+30 77 77
+35 335 335
+53 294 294
+103 4 0
+33 246 246
+79 207 207
+200 268 268
+50 104 104
+34 56 56
+402 130 130
+150 601 601
+161 77 77
+151 68 68
+128 330 330
+138 116 116
+1211 512 512
+51
+
+chain 178315 10 135374737 + 81400041 81409702 10 135534747 + 81410003 81419664 4252
+32 404 404
+191 168 168
+119 193 193
+38 235 235
+38 124 124
+34 68 68
+30 59 59
+28 51 51
+82 216 216
+162 363 363
+34 220 220
+21 9 9
+89 143 143
+50 255 255
+69 995 995
+42 123 123
+65 256 256
+73 628 628
+40 208 208
+50 94 94
+47 239 239
+85 79 79
+219 64 64
+31 147 147
+72 625 625
+40 271 271
+93 754 754
+30 700 700
+66
+
+chain 157388 10 135374737 + 81410627 81419292 10 135534747 + 81420589 81429247 5183
+66 95 95
+53 1136 1136
+46 81 81
+25 268 268
+38 269 263
+105 58 58
+6 0 1
+27 88 88
+34 53 53
+81 32 32
+46 334 334
+116 63 63
+83 268 266
+115 429 428
+97 262 262
+75 757 757
+75 230 232
+41 343 343
+69 47 47
+78 238 238
+46 130 131
+17 36 34
+28 319 319
+46 56 56
+38 707 707
+52 129 129
+132 125 125
+26 376 376
+75
+
+chain 142913 10 135374737 + 81466547 81535718 10 135534747 - 46275769 46344990 569
+44 2128 2133
+24 2535 2533
+31 2379 2381
+34 143 143
+43 270 270
+50 1045 1058
+51 494 498
+36 2085 2105
+60 1979 1981
+71 1197 1197
+41 1594 1601
+37 2856 2871
+66 205 205
+50 1339 1339
+33 656 663
+42 805 805
+79 280 275
+56 200 200
+22 18 18
+13 1443 1450
+44 2526 2526
+33 974 974
+75 1489 1489
+47 1658 1653
+53 1652 1653
+41 1071 1071
+59 10705 10669
+57 6434 6441
+25 586 586
+30 178 178
+44 310 310
+74 7 1
+9 1277 1277
+35 5735 5751
+32 2139 2139
+63 3162 3162
+40 346 345
+53 3391 3390
+41 92 92
+50
+
+chain 97392 10 135374737 + 81500632 81510012 10 135534747 + 81510451 81519840 3573
+60 191 191
+60 1232 1232
+76 51 51
+152 77 77
+38 536 540
+45 585 586
+39 340 340
+99 1376 1373
+58 517 517
+27 710 710
+58 235 235
+47 72 72
+26 157 157
+43 208 208
+31 630 637
+70 1415 1415
+119
+
+chain 87386 10 135374737 + 81512081 81517268 10 135534747 + 81521923 81527111 3288
+161 1034 1034
+35 104 104
+125 613 613
+186 102 102
+205 767 767
+27 231 232
+80 841 841
+68 564 564
+44
+
+chain 81916 10 135374737 + 81260486 81269831 10 135534747 + 81270587 81279924 3410
+66 796 796
+28 224 224
+59 52 52
+35 934 925
+42 354 354
+1 0 2
+37 160 160
+121 19 18
+12 284 284
+76 110 110
+73 771 771
+110 683 683
+8 36 35
+78 4099 4100
+77
+
+chain 75208 10 135374737 + 81450008 81464865 10 135534747 + 81597933 81612795 1746
+23 1356 1354
+29 166 166
+51 547 547
+30 274 278
+40 1364 1363
+57 169 169
+51 3032 3032
+27 1585 1586
+48 818 818
+32 667 667
+67 1160 1160
+68 752 752
+42 269 269
+51 810 813
+52 76 76
+91 661 661
+31 319 319
+42
+
+chain 71596 10 135374737 + 81480667 81490183 10 135534747 + 81490477 81500000 3725
+36 395 395
+36 536 535
+88 519 519
+43 139 139
+80 78 78
+33 117 134
+31 1468 1468
+55 268 268
+97 111 111
+30 6 0
+19 164 164
+38 292 292
+67 2459 2459
+34 2063 2060
+52 136 136
+26
+
+chain 65913 10 135374737 + 81470614 81479436 10 135534747 + 81480422 81489246 3085
+36 1955 1955
+26 1450 1450
+97 248 248
+44 223 223
+89 149 149
+32 72 72
+28 86 86
+68 993 993
+49 0 1
+52 319 320
+26 569 569
+33 216 216
+71 1842 1842
+49
+
+chain 63808 10 135374737 + 81521220 81529648 10 135534747 + 81531068 81539504 3362
+32 704 704
+56 367 367
+93 596 601
+64 1186 1189
+81 1371 1371
+48 1185 1185
+109 1575 1575
+48 608 608
+80 154 154
+71
+
+chain 58084 10 135374737 + 81490258 81499708 10 135534747 + 81500075 81509527 2957
+60 807 808
+44 174 174
+70 135 135
+48 924 924
+25 2943 2943
+43 263 263
+49 1566 1566
+77 243 243
+32 865 865
+87 732 733
+45 183 183
+35
+
+chain 41373 10 135374737 + 81540284 81544136 10 135534747 + 81550136 81553982 6087
+47 328 324
+52 832 831
+48 375 375
+79 0 1
+30 114 114
+38 1117 1115
+45 82 82
+58 368 368
+44 121 121
+74
+
+chain 34777 10 135374737 + 81464865 81470020 10 135534747 + 81474671 81479828 3724
+26 245 245
+34 44 44
+48 145 145
+12 0 2
+23 90 90
+57 378 378
+41 1468 1468
+56 2453 2453
+35
+
+chain 34249 10 135374737 + 81270980 81279755 10 135534747 + 81281073 81289810 4510
+39 431 431
+50 752 752
+134 2175 2167
+44 3025 2995
+35 14 9
+7 2005 2010
+64
+
+chain 29298 10 135374737 + 81537077 81539110 10 135534747 + 81546931 81548963 3702
+68 791 797
+50 617 605
+33 0 2
+73 308 311
+93
+
+chain 18939 10 135374737 + 81450538 81452241 10 135534747 + 81460333 81462036 3255
+39 70 70
+132 1431 1431
+31
+
+chain 6030 10 135374737 + 81422413 81430217 10 135534747 + 81432363 81440000 5582
+26 7730 7563
+48
+
+chain 5154 10 135374737 + 81371363 81371422 10 135534747 - 72572913 72572972 4033525
+2 1 1
+56
+
+chain 1569 10 135374737 + 81371422 81371454 X 155270560 + 63278348 63278380 8657459
+32
+
+chain 1063 10 135374737 + 81231366 81231464 10 135534747 - 54101945 54102043 901
+98
+
+chain 4275918 10_random 113275 + 18676 65432 5 180915260 + 138864813 138909803 707
+204 2 0
+4653 4 0
+2427 0 1
+5957 0 1
+1558 1 0
+780 1794 33
+29376
+
+chain 870863 10_random 113275 + 9144 18556 10 135534747 - 46779061 46789268 4835
+301 2 0
+564 3 0
+802 1 0
+2624 0 112
+142 0 2
+128 100 787
+4745
+
+chain 637317 10_random 113275 + 102183 113228 10 135534747 + 88758795 88768050 8258
+1205 22 22
+793 0 1
+914 1 1
+9 0 1
+45 0 1
+9 2477 1631
+132 1562 615
+2006 1 1
+36 1 1
+557 24 23
+885 0 2
+194 1 0
+171
+
+chain 383436 10_random 113275 + 97894 101991 10 135534747 + 88848068 88852165 132306
+2932 0 1
+697 4 3
+464
+
+chain 312568 10_random 113275 + 0 3305 10 135534747 + 88861095 88864401 225266
+2905 0 1
+400
+
+chain 263395 10_random 113275 + 91858 94672 10 135534747 + 88776474 88779288 339622
+1683 3 3
+130 11 11
+987
+
+chain 254817 10_random 113275 + 83066 85798 10 135534747 - 46749813 46752549 368581
+201 0 6
+798 0 1
+403 4 0
+841 14 15
+471
+
+chain 244215 10_random 113275 + 5995 97779 10 135534747 + 88818267 88897264 4711
+966 0 1
+2072 66256 15486
+2428 10567 42513
+197 0 1
+820 6 6
+18 1 0
+21 0 1
+20 2 1
+1685 0 2
+703 3020 9053
+1156 0 1
+1846
+
+chain 216530 10_random 113275 + 72868 75170 10 135534747 - 93082016 93084318 524441
+2302
+
+chain 211663 10_random 113275 + 85898 88144 10 135534747 + 88832831 88835078 546276
+536 0 1
+1710
+
+chain 171789 10_random 113275 + 70706 72761 10 135534747 - 93140436 93143121 737133
+50 1 1
+68 85 4
+15 15 34
+17 7 53
+13 1 647
+81 1 1
+50 21 21
+1630
+
+chain 129924 10_random 113275 + 67807 109229 10 135534747 - 46627912 46728083 8515
+467 0 1
+256 0 1
+42 1 1
+1352 0 2
+308 10219 43352
+227 1 1
+22 1 1
+2232 22395 48006
+1581 0 2
+518 1 1
+30 1 0
+197 132 132
+1439
+
+chain 125160 10_random 113275 + 4561 5895 10 135534747 - 46655374 46656707 1028939
+94 1 0
+1239
+
+chain 104003 10_random 113275 + 65554 66651 10 135534747 - 93176760 93177857 1232247
+1097
+
+chain 92361 10_random 113275 + 66732 67707 10 135534747 - 93158718 93159693 1382147
+975
+
+chain 89191 10_random 113275 + 3509 4486 10 135534747 - 129898314 129899289 1428933
+69 1 1
+35 1 0
+336 1 0
+401 1 1
+44 1 1
+87
+
+chain 29685 10_random 113275 + 34270 80352 10 135534747 - 46758431 46763489 186939
+210 0 6
+1251 4 4
+73 42015 985
+1249 1 1
+46 1 1
+1232
+
+chain 4572 10_random 113275 + 70436 70610 10 135534747 - 93144449 93144623 2904410
+51 50 50
+73
+
+chain 3114 10_random 113275 + 70610 70643 10 135534747 - 93147281 93147314 29780913
+33
+
+chain 12415599352 11 134452384 + 50000 134451920 11 135006516 + 60000 134946516 11
+1102759 16576 50000
+49571094 207000 307000
+503352 3000000 3100000
+14395596 2605 50000
+488471 34 102
+26 0 176
+30213 141 350
+27914 1 0
+20009 1 0
+19 1 0
+39 1 0
+17 3 1
+10 1 0
+1008 1 0
+95 1 0
+5127 15 0
+302 1 0
+975 0 4
+1548 0 1
+190 20 0
+41 1 0
+29 1 1
+44 0 1
+101 1 0
+25 0 1
+6178 0 1
+1875 21437 52561
+468 1 1
+81 1 1
+2620 1 0
+1640 4 0
+3305 0 1
+3342 1 0
+17899663 12000 50000
+8549206 15562 150000
+38507165 2 0
+1327 174 0
+392 18 0
+48
+
+chain 188276 11 134452384 + 69433462 69437111 GL000202.1 40103 + 7212 10860 1247
+1868 1 0
+1780
+
+chain 38178 11 134452384 + 134451288 134452384 5 180915260 - 180902450 180903869 1901368
+174 458 926
+1 8 0
+63 136 1
+64 2 0
+190
+
+chain 6040 11 134452384 + 134451996 134452128 1 249250621 - 249240179 249240388 3449013
+89 36 113
+7
+
+chain 2221 11 134452384 + 134452085 134452111 Y 59373566 + 59362903 59362929 5436109
+26
+
+chain 4284950 11_random 215294 + 0 215294 11 135006516 - 65191297 65289033 706
+40524 167558 50000
+7212
+
+chain 3340892 11_random 215294 + 90524 125679 11 135006516 + 69689619 69724695 863
+1003 62 0
+3019 1 0
+695 1 1
+26 1 1
+1133 0 1
+1374 2 2
+20 1 1
+729 11 11
+269 0 1
+1091 14 14
+969 21 21
+532 5 5
+2677 18 0
+21481
+
+chain 3051979 11_random 215294 + 175679 208082 GL000202.1 40103 - 0 32891 790
+17546 11 51
+27 523 35
+32 6 6
+6712 100 1036
+7446
+
+chain 10612 11_random 215294 + 193466 193615 GL000202.1 40103 - 18116 18265 21504297
+59 27 27
+63
+
+chain 5102 11_random 215294 + 91527 91580 11 135006516 + 69690684 69690737 20979070
+53
+
+chain 12330181372 12 132349534 + 16000 132289534 12 133851895 + 145739 133779461 12
+7035083 0 4
+544 0 1
+3777 0 1
+3889 73000 52114
+6014 1 0
+6524 168 34
+20974 0 2
+3965 3 0
+444 0 11
+464 1 0
+27577110 1395000 3000000
+38631945 0 1
+14541 0 4
+1703 1 0
+789 250000 12128
+1783 1 0
+1075 0 2
+1042 1 0
+1526 1 1
+27 1 1
+2320 0 1
+166 1 0
+564 0 1
+2856 0 2
+900 0 1
+1387 1 1
+33 1 1
+2139 1 1
+48 1 1
+1305 0 2
+1533 1 2
+879 0 1
+744 26 26
+855 0 4
+1092 6 0
+1114 12 0
+817 1 1
+18 1 0
+217 1 1
+36 1 1
+2002 1 0
+1025 0 1
+450 1 1
+43 1 1
+919 1 0
+18 1 1
+3207 42 42
+1440 0 8
+148 4 0
+3655 2 0
+3403 1 1
+47 1 1
+1524 1 1
+28 1 1
+5561 0 2
+44 0 1
+676 8 8
+810 16 16
+536 2 0
+236 4 0
+167 0 4
+1419 49 53
+4688 1 1
+38 1 1
+18577 5 0
+5284 0 2
+1577 34 34
+4875 1 1
+25 1 1
+4340 0 14
+2663 5 0
+1170 1 0
+4268 0 4
+1036 0 1
+2117 0 8
+5917 1 0
+3239 0 4
+2619 1 1
+21 1 1
+937 1 1
+38 1 1
+2412 0 2
+38 17 0
+2732 0 2
+9314 2 0
+1986 2 2
+16 1 1
+229 1 1
+93 1 1
+895 12 0
+415 1 5
+27 1 1
+78 14 14
+185 8 9
+458 0 2
+89 1 1
+42 1 1
+2034 0 1
+1545 0 2
+280 0 4
+97 14 14
+231 0 2
+2816 5 0
+537 50 50
+1090 1 1
+27 1 1
+25758689 0 1
+6536665 0 1
+377270 57000 96749
+668 1 1
+20 1 0
+3348 1 1
+33 1 1
+648 1 1
+29 1 1
+3732 4 0
+977 46 46
+785 4 0
+34 1 0
+1688 0 10
+4248 1 0
+1167 1 0
+985 9 9
+2897 1 0
+1630 9 0
+1096 0 1
+1356 0 8
+13065723 150011 68363
+799 2 0
+343 0 1
+1771 0 1
+2702 7 6
+1900 1 0
+705 6 0
+303 1 0
+727 1 1
+43 1 0
+3 2 0
+490 1 1
+59 1 1
+226 1 1
+52 3 0
+465 0 8
+194 1 1
+25 1 0
+139 1 1
+15 1 1
+1833 1 0
+81 1 1
+39 1 1
+453 1 0
+719 1 1
+47 1 1
+558 1 0
+838 8 1
+288 10 9
+741 5 2
+465 1 1
+48 1 1
+268 1 1
+26 1 0
+1337 30 48
+84 2 85
+917 1 0
+110 31 31
+1580 1 1
+40 1 1
+683 1 1
+24 1 1
+247 1 1
+36 1 1
+1574 0 1
+10091386 0 3
+296 0 5
+220 45000 100872
+972469
+
+chain 2523 12 132349534 + 107924339 107924385 20 63025520 - 54448952 54448998 196257
+46
+
+chain 9007877316 13 114142980 + 17918000 114127980 13 115169878 + 19020000 115109878 14
+26987167 1 0
+40753157 50000 150000
+25443670 400000 150000
+1821999 384108 414007
+369878
+
+chain 17589560 13 114142980 + 113473994 113658050 13 115169878 - 529930 713796 162
+174857 2 0
+1328 144 0
+1156 1 1
+27 1 1
+2159 2 0
+49 1 1
+175 2 0
+20 4 0
+590 30 0
+163 8 4
+2905 2 0
+430
+
+chain 8677 13 114142980 + 113650223 113650314 13 115169878 - 706193 706284 25436870
+91
+
+chain 17750502 13_random 186858 + 0 186858 GL000212.1 186858 + 0 186858 156
+186858
+
+chain 8359013040 14 106368585 + 18070000 106360585 14 107349540 + 19000000 107289540 15
+1081285 1 1
+43 1 1
+76 2 0
+437 1 1
+19 1 1
+440 12 13
+59 15 15
+63 12 12
+70 0 1
+734 1 1
+165 1 4
+96 1 1
+46 1 0
+83 1 1
+149 4 4
+164 1 1
+18 1 1
+63 15 16
+359 1 1
+39 1 1
+103 1 1
+76 1 1
+139 1 1
+38 1 1
+344 1 1
+65 0 1
+166 5 5
+88 1 1
+66 0 287
+50 1 1
+317 0 1
+52 1 1
+92 4 0
+651 4 4
+82 1 1
+93 1 1
+64 1 1
+24 1 1
+856 1 1
+35 1 1
+258 1 1
+17 1 1
+478 1 0
+1048 70 70
+1279 1 1
+37 1 1
+1115 3 4
+72 1 1
+126 1 1
+102 1 1
+413 10 10
+132 6 6
+89 0 2
+209 15 4
+77 5 5
+427 1 1
+41 1 1
+949 1 1
+16 1 1
+732 1 1
+44 2 0
+128 0 1
+91 1 1
+180 6 6
+388 6 6
+50 13 12
+275 1 1
+33 1 1
+142 1 1
+61 1 1
+560 1 1
+20 1 1
+1327 6 13
+729 37 37
+284 1 1
+44 1 1
+205 0 4
+40 1 1
+352 10 10
+261 1 1
+39 1 1
+940 12 0
+1677 36 0
+159 1 1
+32 8 1
+818 0 6
+580 1 0
+931 1 0
+276 2 0
+3298 45 45
+169 14 0
+46 1 1
+882 2 0
+94 1 1
+49 1 1
+859 4 0
+45 1 1
+807 16 15
+416 0 3
+3345 15 15
+92 30 29
+80 1 1
+48 1 1
+2459 0 1
+646 1 1
+31 1 1
+392 1 1
+29 54 0
+1875 3 0
+141696 1 1
+32 1 1
+8201115 1 0
+107 1 0
+2137 1 1
+39 1 1
+8848 0 1
+4806 1 0
+2075 1 0
+16619 41 40
+2338 3 0
+11507 8 0
+1352 0 1
+4596 0 1
+2073 2 1
+28 1 1
+2311 1 1
+44 1 1
+10440 0 4
+894 0 1
+1641 0 96
+38 9 0
+20 1 1
+2706 6 0
+351 1 1
+25 1 1
+742 0 1
+1048 2 18
+12085977 0 1
+14871228 3 0
+29067652 1 1
+47 1 1
+20174307 1292 0
+2548043
+
+chain 14855 14 106368585 + 19159713 19190443 14 107349540 - 87865807 87904514 64
+20 0 6
+50 9933 9915
+37 16916 24930
+30 3690 3692
+25 27 0
+2
+
+chain 6432 14 106368585 + 19179765 19190441 22 51304566 + 16377620 16388301 97
+45 10604 10609
+27
+
+chain 7700812247 15 100338915 + 18260008 100338915 15 102531392 + 20000000 102521392 16
+8448 6 2
+4086 1 0
+9569 1 1
+40 0 5
+56 7 1
+872419 40441 40448
+553 4 4
+876 0 1
+38 1 1
+139 1 1
+23 1 1
+1881 1 1
+17 1 0
+499 8 8
+310 2 2
+25 11 5
+46 1 1
+78 1 1
+22 0 3
+181 5 6
+569 11 11
+539 1 1
+23 0 4
+261 1 1
+19 0 2
+776 13 15
+62 13 13
+860 1 0
+719 26 0
+1346 1 1
+134 0 1
+30 1 1
+1070 1 1
+21 1 1
+398 0 1
+177 5 21
+534 4 0
+770 0 6
+17 1 1
+606 1 1
+31 1 1
+1861 1 1
+53 1 1
+2169 3 0
+558 1 0
+18 1 1
+227 2 0
+13 1 1
+329 5 5
+430 1 1
+17 2 0
+620 0 1
+1112 2 0
+641 0 4
+476 1 1
+45 1 1
+1285 0 1
+1139 1 1
+47 1 1
+183 4 0
+1435 20 0
+176 0 1
+219 0 1
+607 1 1
+42 1 1
+371 2 8
+507 2 0
+66 1 0
+41 1 1
+999 4 4
+318 15 15
+1092 1 1
+72 1 1
+808 5 5
+54 2 2
+52 1 1
+40 1 1
+109 3 3
+47 1 1
+1535 14 0
+14012 4 0
+7954 4 1
+1350 1 0
+318 1 1
+25 1 1
+600 0 4
+442 0 1
+1396 1 1
+36 1 1
+1107 0 3
+1441 0 5
+360 1 1
+47 1 1
+228 10 0
+37 1 1
+497 1 1
+37 1 1
+2129 4 0
+1242 2 0
+478 4 0
+708 1 1
+90 1 1
+154 10 10
+1583 1 1
+31 1 1
+1302 0 37
+101 14 14
+1138 1 1
+83 10 0
+11 7 0
+111 1 1
+29 1 1
+2917 1 1
+32 1 1
+1762 1 1
+46 1 1
+449 1 0
+2458 9 1
+869 1 0
+534 1 1
+47 1 1
+309 1 0
+6358 22 0
+564 0 1
+1845 1 0
+660 1 1
+25 1 1
+68 1 0
+182 0 9
+54 3 18
+1519 1 1
+32 1 1
+559 1 1
+30 1 1
+3851 1 0
+265 8 7
+240 4474 0
+428 1 0
+1651 11 10
+297 1 0
+665 21 0
+48 1 1
+1763 2 0
+245 1 1
+39 1 1
+519 1 1
+31 1 1
+2398 0 6
+749 49 1
+2074 4 0
+701 5 5
+337 1 0
+470 1 1
+43 1 1
+1163 3 0
+1342 1 1
+43 1 1
+140 0 1
+83 1 1
+24 1 2
+37 1 1
+723 1 1
+36 1 1
+99 3 0
+27 1 1
+92 1 0
+80 43 43
+1095 0 13
+384 0 2
+292 1 1
+39 1 1
+101 12 12
+576 0 2
+1907 1 1
+19 1 1
+318 1 0
+1973 1 1
+32 1 1
+689 1 1
+49 1 1
+357 8 8
+2081 13 13
+260 15 15
+2295 1 1
+24 1 1
+2558 1 1
+26 1 1
+571 16 23
+323 0 1
+36 0 1
+5353 111 0
+1711 38 70
+272 13 13
+1284 0 1
+1128 4 4
+2189 1 0
+474 2 0
+1284 61 67
+643 1 1
+37 1 1
+381 0 2
+56 1 0
+2591 1 1
+55 1 1
+160 4 4
+116 1 1
+89 2 0
+316 0 1
+785 20 0
+152 1 1
+21 1 1
+600 0 6
+568 1 0
+278 1 1
+29 1 1
+89 0 4
+1737 1 1
+58 1 1
+368 24 24
+2113 20 24
+218 0 2
+18 1 1
+684 4 4
+3200 1 1
+31 1 1
+58 18 18
+164 1 1
+37 1 1
+296 6 6
+431 1 1
+35 1 1
+431 1 1
+45 1 1
+93 1 1
+24 1 1
+216 1 1
+46 1 1
+2773 0 17
+751 2 1
+104 1 1
+59 1 1
+445 1 1
+26 1 1
+356 1 0
+1484 1 2
+436 25 25
+306 1 1
+55 1 1
+230 4 4
+892 1 0
+364 7 7
+796 1 1
+26 1 1
+663 0 2
+80 0 15
+4391 1 0
+133 1 1
+25 0 4
+41 0 2
+164 1 1
+61 4 4
+925 3 0
+1882 13 13
+4513 1 0
+111 1 1
+76 1 1
+202 6 0
+680 0 1
+200 3 0
+429 0 2
+736 1 1
+18 1 1
+1573 0 1
+119 1 1
+245 0 9
+11 1 1
+1656 54 22
+616 2 1
+158 0 1
+587 1 1
+39 4 1
+1053 6 6
+1116 1 1
+34 1 1
+152 10 7
+448 0 1
+269024 100000 863295
+334079 100000 50000
+180553 0 74
+66 73 3
+40 1 0
+28 156 73
+202 1 1
+17 0 1
+156 1 1
+55 1 1
+111 0 1
+144 1 1
+57 0 1
+687074 50000 50000
+120647 0 348
+45586 0 1
+6994 1 0
+3398063 44008 12354
+7672 0 2
+1809 1 0
+428524 101014 10165
+43170 4 4
+1064959 128966 5086
+1021 0 1
+1710 1 0
+931 0 2
+4505 0 1
+686 525 2
+432 33 0
+58 20 20
+12369 1014 0
+6233 0 1
+359485 100000 111749
+33855821 0 239
+2852113 1 0
+7040367 0 1
+2815738 3 1
+7055922 60000 50000
+363827 32 32
+104991 0 1
+203136 0 6050
+2271 47 47
+1424473 60000 50000
+13510190 22012 5553
+9194 0 3
+109 0 4
+40 0 1
+43 0 7
+2352 0 13
+5027 0 2
+534 1 0
+794 0 2
+4233 0 2
+5769 1 0
+381 1 0
+2524 0 2
+547 0 5
+1967 0 1
+1207 105 0
+1027 0 6
+3935380
+
+chain 4143271 15 100338915 + 19154641 19368514 15 102531392 + 21901264 22115049 110
+40441 8593 8593
+26 89965 89965
+4257 1 1
+30 1 1
+185 16464 16391
+43 29947 29883
+25 1 1
+34 23835 23884
+25
+
+chain 390135 15 100338915 + 26478746 26483022 15 102531392 + 28681030 28685306 6048
+1039 22 22
+3215
+
+chain 187810 15 100338915 + 26483022 26517556 15 102531392 - 73809068 73843318 79
+41 12 0
+36 1 1
+490 5 5
+285 1 1
+71 1 1
+215 1 1
+53 0 12
+8114 1 0
+10796 15 15
+2483 0 1
+20 1 1
+2048 8856 8847
+163 792 517
+33
+
+chain 51529 15 100338915 + 26530390 26530949 15 102531392 + 28731348 28731907 2473877
+450 8 8
+101
+
+chain 17522 15 100338915 + 26516748 26516957 15 102531392 + 22658399 22658608 1968
+209
+
+chain 14035 15 100338915 + 20378176 20378474 15 102531392 + 22829101 22829399 772378
+73 69 69
+156
+
+chain 12347 15 100338915 + 26530060 26530390 15 102531392 + 22671289 22671619 3189077
+244 4 4
+82
+
+chain 5537 15 100338915 + 96402403 96402461 15 102531392 + 98585049 98585107 22350382
+58
+
+chain 4486 15 100338915 + 96402461 96402508 15 102531392 + 98585002 98585049 16761199
+47
+
+chain 2874 15 100338915 + 26517060 26517091 15 102531392 + 28719096 28719127 6634083
+31
+
+chain 2874 15 100338915 + 26517029 26517060 15 102531392 + 28719096 28719127 6634084
+31
+
+chain 2874 15 100338915 + 26516998 26517029 15 102531392 + 28719096 28719127 6634085
+31
+
+chain 2874 15 100338915 + 26516967 26516998 15 102531392 + 28719096 28719127 6634086
+31
+
+chain 2314 15 100338915 + 26530003 26530033 15 102531392 + 22671232 22671262 5236
+30
+
+chain 12940492 15_random 784346 + 189260 358080 15 102531392 + 28561246 28726591 233
+2522 0 1
+3762 1 1
+40 1 1
+2427 6472 2
+1744 0 1
+263 0 7
+2963 4 4
+1889 1 0
+2501 0 1
+3377 6 6
+5238 0 1
+1277 5 5
+38 1 1
+8232 12 8
+5507 0 18
+155 1 0
+379 14 14
+363 7 13
+336 1 1
+46 1 1
+218 8 8
+1074 0 4
+101 12 13
+178 1 1
+93 1 1
+156 10 11
+398 0 20
+45 1 1
+255 9 10
+2661 0 1
+17 1 1
+82 1 1
+14 1 1
+227 64 64
+1154 1 0
+493 1 1
+39 1 1
+369 1 0
+21 1 1
+322 2 7
+222 0 2
+171 15 0
+81 1 1
+47 1 1
+159 9 9
+154 1 0
+272 4 4
+26 1 1
+121 8 7
+659 1 0
+440 1 1
+35 1 0
+1419 15 0
+181 0 2
+292 0 15
+1767 1 1
+44 1 1
+59 0 1
+910 0 1
+290 1 0
+288 1 0
+567 2 0
+1088 0 1
+1758 1 0
+72 1 1
+21 1 1
+5748 17 17
+800 0 1
+2037 13 13
+113 5 5
+2832 1 1
+44 1 1
+3581 2 0
+33 1 1
+812 5 5
+33 0 1
+257 17 17
+1932 0 14
+168 0 1
+424 5 0
+24 1 1
+67 14 14
+90 1 5
+124 1 1
+34 1 1
+48 0 9
+460 0 8
+294 7 0
+813 1 3
+240 1 0
+511 0 9
+190 1 0
+267 1 1
+38 1 1
+1082 7 57
+21 15 0
+28 0 1
+5 1 1
+123 0 5
+781 1 1
+21 1 1
+390 1 1
+36 1 1
+287 1 1
+90 0 3
+6 2 2
+189 9 9
+263 2 1
+724 13 14
+308 2 0
+1752 1 1
+114 1 1
+236 4 0
+46 1 1
+72 5 0
+1039 1 1
+25 1 1
+403 1 1
+22 1 1
+231 6 6
+834 15 15
+617 1 1
+53 1 1
+243 1 1
+154 3 5
+571 11 16
+231 1 1
+47 1 1
+910 1 1
+45 1 1
+1510 1 1
+79 1 1
+2053 1 1
+48 1 1
+768 8 8
+546 1 1
+19 1 5702
+784 6 0
+275 20 13
+131 114 114
+363 1 1
+46 1 1
+396 1 1
+39 1 1
+75 15 15
+1875 1 0
+332 1 1
+49 1 1
+265 3 2
+55 1 1
+96 1 1
+136 1 0
+305 8 8
+297 0 2
+255 2 2
+23 1 1
+181 19 6
+151 0 1
+707 667 9324
+284 5 3
+73 1 1
+208 26 25
+34 0 773
+80 20 0
+2003 400 125
+163 2 0
+2630 9 1
+19 1 1
+100 12 0
+2421 0 2
+47 21227 0
+853 1 0
+1238 0 12
+3571 1 1
+20 0 1
+2483 15 15
+8803 287 9594
+5992
+
+chain 8627768 15_random 784346 + 422939 629603 15 102531392 - 19338638 19927596 385
+168 56 59
+73 4 4
+378 23 23
+868 29 29
+85 1 0
+528 119 5106
+152 31 31
+184 8 7
+322 0 1
+62 46 45
+77 37 46
+80 22 22
+201 45 47
+175 31 33
+1923 82 77
+546 7051 32690
+7810 209 153340
+1308 1 0
+9826 1 0
+1486 1 1
+148 1 0
+76 6 6
+53 36 34
+178 5447 565
+14 14505 121
+72 13 16
+57 1 1
+157 0 2
+11 1 1
+74 1 1
+24 3 3
+220 1 1
+54 1 1
+142 1 1
+82 2 0
+60 4 0
+99 1 1
+106 1 1
+98 1 1
+402 1 1
+79 4 7
+78 1 9
+5 0 1
+31 7 7
+65 1 1
+105 0 1
+22 6 8
+76 10 8
+47 0 1
+39 3 0
+5 1 3
+108 2 2
+61 16307 40121
+676 26 26
+7087 25 25
+20818 7 7
+2750 60358 90388
+69 54 53
+165 166 516
+42 0 42
+81 4 151
+18 0 42
+148 111 112
+73 4 4
+378 23 23
+868 29 29
+85 1 0
+528 8 8
+280 32 34
+426 78 79
+81 648 334
+181 8 7
+485 0 2
+1404 24 24
+101 36 38
+240 8 8
+77 53 54
+347 18 18
+72 9 9
+94 82 82
+384 8 8
+250 108 151474
+1152 0 1
+633 226 12498
+3255 4 0
+58 32 32
+6209 1 1
+30 1 0
+1060 2 0
+3747 4 4
+173 5 5
+2548 0 22
+2275 0 20
+606 41 41
+4653 12 12
+6138 0 1
+148 5 0
+244
+
+chain 3986761 15_random 784346 + 0 334816 15 102531392 - 78891064 79878228 248
+30328 8040 15984
+3015 1 0
+70 44499 160931
+52 0 5
+1038 1 1
+29 1 1
+1001 0 18
+680 0 329
+181 1 1
+32 1 1
+839 2 0
+440 0 3
+547 1 0
+278 1 0
+410 1 1
+26 3 0
+101 1 1
+24 1 1
+149 0 9
+179 2 1
+29 1 1
+226 3 0
+21 1 1
+473 10 0
+717 2 0
+1044 1 1
+23 1 1
+625 1 1
+41 1 0
+150 1 1
+62 1 1
+145 59 59
+242 12 12
+179 1 1
+64 1 1
+1405 1 1
+35 0 2
+469 5 0
+401 0 1
+25 0 10
+17 1 1
+55 1 1
+165 1 1
+1966 15 23
+839 0 18
+969 1 1
+44 1 1
+1905 1 1
+47 1 1
+1037 128 128
+486 5 0
+1086 2 1
+199 4 4
+59 2 0
+243 84 0
+410 1 1
+39 1 1
+70 0 324
+77 1 187
+42 4 151
+897 135051 676116
+64 54092 52483
+25 1 1
+88 9286 18277
+201 26614 5202
+33 1 0
+1
+
+chain 2185345 15_random 784346 + 423107 689458 15 102531392 + 82637661 83186296 482
+30 0 5
+26 1346 1346
+29 885 5865
+31 576 577
+46 77 77
+5 0 1
+32 303 304
+45 175 176
+31 1923 1923
+66 1943 144683
+715 0 1
+548 13 13
+1907 1 1
+16 1 1
+66 3 0
+1219 5 1
+1066 34012 198199
+7204 2446 2446
+2762 100 7680
+5162 1 0
+2782 1 1
+26 7 4
+49 1 1
+3627 3 0
+1686 133598 65296
+3109 1 1
+21 1 1
+1430 63 63
+335 3 3
+14 4 0
+203 1 1
+23 5 5
+1262 4 4
+323 1 1
+47 1 1
+417 0 1
+537 19 1
+1913 2 0
+1685 6 0
+1740 1 1
+49 1 1
+120 1 1
+30 0 3
+920 4 0
+479 30 30
+1207 1 1
+182 4 0
+72 3 1
+78 1 1
+150 1 1
+46 1 1
+222 1 1
+24 1 1
+74 1 1
+44 1 1
+391 1 1
+33 1 1
+149 9 8
+56 1 1
+30 1 0
+52 1 1
+298 6 0
+22 1 0
+29 1 1
+393 35 0
+145 36 36
+226 15 15
+185 7 7
+692 1 1
+34 1 1
+1291 0 2
+1824 5 5
+1119 1 1
+49 1 2
+1025 25013 44930
+835 88 11347
+692 0 2
+2551 3 0
+1144 82 77
+1939 26 28
+164 1 1
+44 0 2
+201 1 1
+133 5 14
+77 1 1
+44 1 0
+92 1 0
+293 8 7
+184 31 31
+381 8 8
+384 1 1
+80 1 1
+94 9 9
+57
+
+chain 1845967 15_random 784346 + 61569 84889 15 102531392 - 73695594 73766494 782
+153 33 33
+49 1 0
+197 15 15
+67 62 62
+241 12 9
+185 41 44
+64 23 23
+559 50 50
+333 46 46
+397 6 6
+141 4 0
+660 50 50
+315 38 38
+282 309 47864
+57 7 7
+85 39 39
+340 62 62
+43 0 1
+77 0 1
+768 0 12
+71 70 69
+102 17 17
+58 45 50
+676 2 0
+430 21 22
+112 0 1
+401 4 0
+617 95 95
+168 50 50
+442 4 0
+91 114 114
+463 0 1
+94 28 28
+1577 16 16
+572 0 1
+1451 55 55
+2327 51 51
+394 1 0
+109 21 24
+660 50 54
+703 1 0
+93 22 22
+94 48 48
+219 46 46
+352 22 22
+150 155 161
+173 19 19
+162 6 12
+1201 48 49
+119 17 17
+435 4 4
+146 38 38
+946 10 10
+98 37 37
+60 47 47
+579
+
+chain 1297748 15_random 784346 + 203918 328028 15 102531392 - 73698913 73856126 264
+567 109104 118059
+369 106 23997
+700 2 0
+40 0 248
+320 0 33
+130 1 1
+18 1 1
+138 20 20
+1341 8 0
+863 1 1
+48 1 1
+240 1 1
+34 20 0
+3218 1 1
+20 1 1
+2062 46 46
+285 14 14
+937 1 1
+25 3 3
+305 1 1
+42 1 1
+706 2 0
+232 1 1
+67 1 1
+88 4 5
+844 1 1
+82 1 1
+430 0 7
+78 1 1
+458 27 27
+52
+
+chain 898399 15_random 784346 + 457589 504019 15 102531392 - 19636589 19905366 626
+5344 14 14
+7167 26767 249114
+26 7087 7087
+25
+
+chain 844102 15_random 784346 + 95554 784338 15 102531392 + 22730405 27183335 411
+59 9906 9932
+128 2128 2090
+42 1792 637909
+89 10 10
+71 198 198
+122 137 141
+341 29 29
+104 103 103
+395 11 14
+667 6 7
+74 7 0
+178 1 5
+203 9 4
+172 55 55
+791 25 25
+714 19 22
+597 133 133
+142 2 0
+252 0 4
+260 67 67
+41 6 0
+860 29 30
+258 93 95
+1793 11 11
+358 71 70
+242 1 1
+20 1 1
+1308 0 3
+468 0 2
+755 1 1
+81 2 2
+72 3 0
+597 4 4
+492 25 7
+1459 10 9
+674 16 16
+711 1 1
+49 1 1
+1525 1 1
+45 1 1
+2919 1 1
+36 1 1
+493 1 1
+21 1 1
+830 16 0
+3 7 0
+644 17 17
+479 0 1
+2343 0 315
+307 8 311
+87 0 3
+330 42 0
+520 7 6
+72 2 1
+745 6 6
+324 6 0
+398 22 22
+118 27 27
+68 600887 3728395
+44872
+
+chain 555121 15_random 784346 + 634265 679702 15 102531392 + 82723475 82991213 602
+20 1 1
+41 24204 246463
+2085 6 6
+667 14 14
+596 0 24
+1743 415 422
+870 1 0
+3572 1 1
+1152 8 0
+498 0 1
+3239 1 1
+34 1 1
+1283 1 1
+41 1 0
+676 0 2
+2078 0 1
+1283 0 18
+681 1 0
+223
+
+chain 530253 15_random 784346 + 409131 430676 15 102531392 - 19567939 19581201 1716
+786 8 0
+171 8918 159
+2113 8268 8752
+1281
+
+chain 417534 15_random 784346 + 35735 80744 15 102531392 + 23413134 23608954 1095
+840 0 54
+916 0 2
+777 3337 13583
+637 50 57
+858 0 4
+779 0 14
+171 1 2
+927 4 0
+1753 2 0
+814 35 35
+1073 14 14
+81 99 101
+66 42 42
+1291 66 66
+240 45 48
+68 36 36
+98 38 38
+1141 5 5
+70 14 15
+150 46 46
+650 13461 153954
+62 1206 1201
+45 3148 3138
+46 6617 6616
+50 2415 2415
+46 615 621
+64
+
+chain 169648 15_random 784346 + 417136 418914 5 180915260 + 131590649 131592427 748288
+1778
+
+chain 152639 15_random 784346 + 200201 201828 15 102531392 + 28662778 28664407 841936
+970 0 1
+468 5 6
+184
+
+chain 151945 15_random 784346 + 110737 203590 15 102531392 - 73700255 73867708 1083
+74 87238 121334
+88 426 14673
+942 2 0
+567 1880 28137
+86 1 1
+62 1 1
+716 14 14
+212 0 1
+468 0 1
+76
+
+chain 142059 15_random 784346 + 583198 664057 15 102531392 - 16763491 17663089 651
+176 7 7
+242 7 7
+1002 1 1
+61 1 1
+286 10 10
+1697 57790 716388
+17 1 1
+12 3589 70884
+35 145 145
+36 6576 99374
+431 11 1
+19 0 4
+96 2 0
+98 1 1
+62 1 1
+1047 10 15
+223 1 0
+575 2 0
+465 1 0
+8 1 1
+140 1 4
+65 1 1
+381 5111 5164
+145 1 1
+29 1 6
+32 8 2
+199
+
+chain 140486 15_random 784346 + 414032 415531 5 180915260 + 131627050 131628561 916856
+486 0 13
+290 2 1
+721
+
+chain 136843 15_random 784346 + 411466 412886 5 180915260 - 49283520 49284940 941594
+1420
+
+chain 113176 15_random 784346 + 577887 601700 15 102531392 + 85729223 85793813 754
+51 12 12
+630 1 1
+27 5 5
+51 41 41
+249 505 29710
+148 24 24
+110 0 2
+145 12 11
+646 54 53
+291 404 700
+590 7 0
+154 1 1
+36 5 3
+106 1 1
+42 1 1
+517 181 27
+164 18572 30011
+30
+
+chain 110898 15_random 784346 + 410214 411366 5 180915260 - 49350156 49351308 1158024
+1152
+
+chain 90718 15_random 784346 + 415631 422839 5 180915260 - 49281425 49321173 523505
+1405 4191 36723
+57 0 4
+785 0 4
+770
+
+chain 87628 15_random 784346 + 412986 413908 15 102531392 + 82958289 82959211 1453275
+922
+
+chain 78489 15_random 784346 + 408080 408895 5 180915260 + 131628738 131629553 1616335
+815
+
+chain 75848 15_random 784346 + 328894 334289 15 102531392 + 28663807 28669202 22165
+415 0 1
+219 14 14
+716 1 1
+62 1 1
+1820 1 0
+432 1 1
+21 1 1
+549 1 1
+42 1 1
+1098
+
+chain 55946 15_random 784346 + 579203 582900 15 102531392 - 19568187 19572180 874
+256 1085 1091
+54 291 291
+49 100 396
+255 1464 1453
+62 1 6
+80
+
+chain 50039 15_random 784346 + 328288 328894 15 102531392 - 73792653 73793260 1678654
+449 99 100
+58
+
+chain 41737 15_random 784346 + 53223 55079 15 102531392 - 79138743 79140590 1899
+987 5 0
+378 4 0
+30 1 1
+324 1 1
+36 1 1
+89
+
+chain 40184 15_random 784346 + 35650 52319 15 102531392 + 23578289 23604839 1865
+85 6507 16388
+50 5309 5309
+35 1168 1168
+99 66 66
+42 1291 1291
+66 240 240
+45 68 68
+36 98 98
+38 1380 1380
+46
+
+chain 36402 15_random 784346 + 63654 139260 15 102531392 + 20712328 20743651 996
+46 46877 2371
+29 5894 5886
+28 261 261
+55 0 3
+35 2163 2163
+70 17110 17298
+32 0 42
+10 2220 2218
+27 68 68
+335 31 31
+315
+
+chain 33407 15_random 784346 + 63271 84310 15 102531392 + 28567817 28636450 784
+50 2730 50298
+39 1361 1355
+70 2485 2497
+95 168 168
+50 618 618
+33 8782 8789
+48 4472 4485
+38
+
+chain 26884 15_random 784346 + 71527 84203 15 102531392 + 23434933 23447596 1313
+28 3628 3632
+43 3563 3545
+38 1762 1762
+91 1625 1625
+17 1 1
+30 721 722
+38 1054 1054
+37
+
+chain 17994 15_random 784346 + 577754 595591 15 102531392 + 82746005 82941680 2345
+133 777 777
+41 8083 152910
+1120 114 33023
+47 1 1
+5 265 681
+66 293 293
+111 2277 2277
+32 585 587
+5 0 1
+25 0 1
+6 1 0
+11 3164 2847
+53 540 540
+82
+
+chain 17584 15_random 784346 + 334305 334490 15 102531392 - 73868107 73868292 12488910
+185
+
+chain 16638 15_random 784346 + 334590 334767 15 102531392 + 28693782 28693959 13398527
+177
+
+chain 15574 15_random 784346 + 203754 203918 15 102531392 + 20713399 20713563 2884965
+164
+
+chain 11941 15_random 784346 + 112567 138945 15 102531392 + 28572611 28599524 1070
+24 791 791
+25 2119 2124
+57 23331 23861
+31
+
+chain 10106 15_random 784346 + 307857 307966 15 102531392 - 73812018 73812127 6634519
+109
+
+chain 9879 15_random 784346 + 198177 198415 15 102531392 + 28709863 28710101 596395
+238
+
+chain 5493 15_random 784346 + 34234 34291 Y 59373566 + 27644447 27644504 32044688
+57
+
+chain 4133 15_random 784346 + 323293 323339 15 102531392 + 22666870 22666916 2166
+46
+
+chain 4016 15_random 784346 + 328237 328288 15 102531392 + 28668851 28668902 1790991
+51
+
+chain 3958 15_random 784346 + 107733 107775 15 102531392 - 78958306 78958348 1193
+42
+
+chain 3427 15_random 784346 + 198013 198049 15 102531392 + 20714128 20714164 4212128
+36
+
+chain 3014 15_random 784346 + 591545 685196 15 102531392 - 19431434 19585695 819
+47 89045 149655
+87 4422 4422
+50
+
+chain 2874 15_random 784346 + 307826 307857 15 102531392 - 73812018 73812049 6634520
+31
+
+chain 2855 15_random 784346 + 198147 198177 15 102531392 + 28831982 28832012 6776371
+30
+
+chain 2097 15_random 784346 + 200178 200201 15 102531392 - 79852957 79852980 911500
+23
+
+chain 1855 15_random 784346 + 307785 307816 15 102531392 + 28688468 28688499 5960032
+31
+
+chain 1291 15_random 784346 + 110710 110736 15 102531392 - 73822377 73822403 1552683
+26
+
+chain 1093 15_random 784346 + 687136 688443 15 102531392 - 19508634 19509938 742
+25 1251 1248
+31
+
+chain 7474990131 16 88827254 + 0 88822254 16 90354753 + 60000 90294753 17
+172342 0 1
+112 1 0
+5627 2 1
+8398838 17500 50000
+25336229 100000 150000
+1112651 9800000 11100000
+42003582 20000 50000
+1855370
+
+chain 9963354 16_random 105485 + 0 105485 16 90354753 + 29712462 29819360 326
+5589 7 8
+6783 0 218
+41 1 3
+38 1 1
+234 9 9
+219 46 0
+15 0 50
+3818 0 1
+1090 1 1
+45 1 1
+308 1 0
+524 0 4
+984 1 1
+24 1 0
+970 0 2
+106 1 1
+25 2 1
+436 0 5
+296 1 1
+23 2 0
+813 0 1
+1173 1 0
+5500 1 0
+1193 16 16
+1329 0 1
+2727 0 1
+3622 0 13
+3844 3 0
+5076 0 1
+4157 2 0
+178 0 2
+126 1 1
+344 5 6
+497 1 0
+620 7 7
+378 0 1
+669 24 25
+211 1 5
+453 0 11
+176 0 1
+486 0 8
+326 1 0
+2143 40 9
+2337 0 1
+866 1 0
+10 2 2
+1366 1 1
+44 1 1
+831 1 1
+45 1 1
+1612 6 5
+3801 0 1
+910 0 2
+486 0 1
+2775 1 0
+1083 1 0
+1793 1 1
+50 0 1
+1339 0 2
+145 17 17
+651 10 10
+1140 0 1
+724 1 1
+39 1 1
+3261 1 0
+1513 0 9
+606 22 0
+2027 27 19
+3470 11 0
+4100 3 0
+2045 0 4
+1047 0 1
+6647 78 1279
+748
+
+chain 7369813928 17 78774742 + 0 78653129 17 81195210 + 0 81060000 18
+252627 1 1
+24 1 1
+33 0 29
+566 87 0
+116 58 0
+92 29 0
+79 8 37
+485 1 59
+28 1 1
+76 233 1
+27 29 0
+2764 17 20
+2220 18 18
+837 1 1
+39 1 1
+564 1 1
+14 1 1
+2523 39 9
+1824 0 56
+76 29 0
+1681 0 1
+414 0 3
+256 0 68
+119 10 10
+290 0 4
+3193 1 0
+2562 0 4
+1809 3 0
+84 1 1
+62 1 1
+3703 0 27
+2041 16 0
+911 0 2
+696 4 4
+1428 15 15
+290 1 0
+1779 0 1
+60 1 1
+216 0 1
+375 1 1
+41 0 1
+9221 46522 100000
+3080543 0 1
+1208216 0 2
+1370 2 0
+1279 0 4
+322 0 5
+5661 210 0
+307 21 22
+973 8 0
+2901 1 0
+8479 0 1
+4122 7 0
+3187 4 0
+571 0 1
+167 0 1
+10174 7 7
+856 2 1
+1630 1 0
+4258 3 1
+1688 1 0
+264 0 304
+796 1 0
+8494 0 10
+2273 1 0
+8297 1 0
+1500 1 4
+733 2 2
+40 1 0
+4 0 1
+15 19 1
+64 1 253
+22 0 34
+18 1 205
+2070 2 0
+2981 14 13
+1309 0 1
+3991 3 0
+1939 0 3
+887 0 2
+463 18 0
+64 0 3
+2104 0 20
+556 0 4
+121 0 1
+3670 2 0
+4345 0 5394
+5334 0 1
+2505 4 10
+6776 14 11
+9573 0 1
+1136 0 2
+3754 1 0
+4588 1 0
+637 17 17
+1285 8 0
+369 0 1
+2084 1 0
+492 2 0
+517 0 4
+954 0 2
+1517 1 0
+958 9 0
+807 14 14
+357 0 10
+3611 0 2
+3191 0 39
+742 1 0
+646 2 0
+2211 1 0
+14829 1 0
+3465 11 0
+31 0 33
+833 16 16
+1345 0 1
+6443 5 4
+2627353 1 0
+11581979 0 43
+25 0 89
+238783 0 1
+1830653 1 0
+419873 100008 116477
+5587 6 0
+11056 0 2
+3240 1 0
+1237 0 2
+373 1 1
+43 1 1
+558379 100000 3000000
+1823446 0 1
+2728383 0 1
+29 0 1
+138 1 0
+144 6 8
+38 0 2
+7 0 1
+18 1 1
+70935 10 13
+52 28 31
+189 0 1
+41 2 2
+750363 44 44
+4038953 100000 50000
+1524006 1 1
+47 1 1
+231 2 0
+1175 1 0
+555 1 1
+49 1 1
+568 7 0
+605 2 0
+4954 1 1
+18 6 7
+567 0 1
+421 2 0
+943 75 67
+777 0 3
+925 3 0
+5 4 0
+318 1 0
+230 20 13
+244 1 1
+13 0 1
+42 1 1
+220 1 1
+56 1 1
+101 225 0
+1113 1 0
+17 1 1
+2614 4 0
+3186 50 50
+3872 0 2
+617 14 0
+5674 0 2
+1852 1 1
+63 1 1
+56 1 1
+25 1 1
+332 0 6
+423 5 5
+61 4 0
+108 1 1
+46 1 1
+160 2 2
+72 1 1
+162 1 1
+20 1 1
+53 1 1
+63 1 1
+112 1 1
+59 1 1
+5885 2 0
+255 36 36
+6246 1 1
+114 1 1
+255 1 1
+49 1 1
+210 1 1
+138 157793 28603
+927 5 0
+212 7 7
+641 17 17
+1296 46 46
+2513 71 69
+76 1 2
+61 50226 0
+1959 18 18
+2727 22 22
+6616 1 0
+5109 68 86
+2450 7 7
+50 10 0
+3439 0 4
+4179 0 4
+2749 0 1
+1124 8 0
+56 1 1
+1840 14 14
+624 8 0
+1743 4 0
+3689 0 4
+2051 0 1
+751 0 1
+2111 10 11
+3110 1 0
+682 1 0
+2795 5 2
+241 0 1
+165 1 3
+1258 0 1
+1602 5 0
+3715 0 1
+1308 0 1
+2058 1 0
+1624 0 1
+478 4 0
+9 6 0
+35 3 1
+47 0 1
+2425 1 0
+1178 0 4
+33 1 1
+415 5 5
+887 1 3
+946 29 29
+630 15 0
+259 2 0
+78 0 1
+4570 0 1
+322 1 0
+1801 2 0
+836 3 0
+1509 0 1
+1732 0 1
+935 0 6
+1372 1 0
+625 2 12
+5009 1 1
+75 0 1
+20 1 0
+153 20 21
+489 4 326
+1375 1 0
+774 1 1
+16 1 1
+3642 5 0
+497 4 0
+174 9 0
+1317 0 3
+508 0 1
+1126 1 0
+1952 0 2
+565 2 0
+871 0 1
+1460 6 0
+55 0 1
+420 6 0
+57 1 1
+119 1 1
+427 1 0
+459 14 11
+448 0 1
+1275 7 7
+360 1 0
+73 1 1
+48 1 1
+4920 3 0
+713 41 34
+691 1 1
+44 1 1
+1642 9 10
+566 0 1
+173 0 4
+798 0 10
+810 1 0
+78 18 17
+1531 0 2
+1274 1 1
+39 1 1
+53 3 1
+202 0 1
+707 17 17
+1733 0 1
+14053 3 0
+286 3 1
+5600 4 0
+6458 0 1
+4866371 102000 0
+1870113 257 0
+590050 6 18
+2095 12 12
+24846 1 0
+5154 22 22
+1561 0 4
+5946 1 0
+2317 0 4
+1643 1 1
+27 1 1
+1237 1 0
+2698 1 1
+140 1 1
+1689 0 2
+836 29 30
+5333 1 0
+509 1 0
+5216 6 0
+10782 47 47
+1095 13 3
+1039 0 1
+11605 1 0
+22064 0 1
+16612 8 0
+902 1 0
+757 1 0
+619 0 1
+10979 1 1
+18 1 1
+1517 1 0
+4576 1 0
+12559 4 0
+2725 0 1
+5291 2 0
+8706 0 1
+83 1 0
+424 0 7
+72 38 0
+5528 1 0
+23971 1 0
+7855 54 22
+4095 0 1
+803 5 5
+6382 6 0
+3545 0 28
+4265 0 2
+13194 6 6
+6463 1 0
+26075 1 1
+59 1 1
+10791 17 7
+707 0 1
+210 1 0
+1655 0 2
+5301 1 0
+1930 1 0
+14632 2 0
+1043 1 0
+3607 3 0
+312 0 1
+5953 2 0
+170 0 17
+489 0 1
+5260 0 28
+888 10 0
+2461 10 10
+237 2 0
+1716 3 1
+10691 0 4
+3757 1 0
+6173 0 1
+8017 1 2
+3594 0 4
+5439 0 1
+4138 28 57
+6418 0 1
+1267 1 0
+720 0 6
+1083 2 0
+3878 0 1
+3310 23 23
+4349 1 1
+44 1 1
+3135 0 1
+174853 1 2
+2008 7 7
+5657 0 1
+6496 0 3
+89 0 5
+665 0 1
+954 46 46
+375 7 8
+1248 28 28
+2041 0 2
+2753 1 0
+1863 0 3
+3228 1 0
+3575 0 4
+40 1 1
+6488 0 2
+8612 11 11
+3795 0 16
+2105 0 1
+268 1 1
+22 3 0
+7889 4 0
+701 4 0
+2411 28 34
+2943 2 3
+8420 1 0
+926 0 324
+6732 1 0
+543 4 3
+4028 2 0
+51 52 40
+3000 1 0
+530 1 0
+2083 0 2
+1173 0 17
+119 16 16
+2727 1 0
+543 0 1
+783 1 0
+1372 0 4
+8624 20 0
+278 44 44
+4364 51 50
+2856 0 1
+5399 0 1
+1506 1 0
+919 0 6
+7229 10 0
+3225 1 0
+435 1 0
+2814 47 47
+1577 0 132
+9785 0 1
+2035 6 0
+7655 1 0
+198207 0 132
+11704 0 5
+7648 1 0
+9062 4 0
+8778 0 2
+7014 1 0
+1613 0 2
+790 7 5
+7433 1 0
+6482 12 12
+6798 0 1
+1422 1 0
+3454 1 1
+43 1 1
+3097 0 2
+334 0 18
+1444 1 0
+2400 3 0
+3272 0 1
+9106 1 0
+1573 0 1
+4742 1 0
+3366 1 0
+5484 0 1
+2444 0 5
+5448 8 8
+2539 0 1
+1471 0 1
+238 1 1
+16 1 1
+288 5 5
+2995 0 2
+951 1 1
+35 1 1
+279 16 15
+3534 6 0
+3513 0 1
+163 0 1
+6173 0 1
+1074 1 0
+2818 1 0
+2868 0 1
+3796 1 0
+1118 1 167
+1278267 25 25
+10747172 0 217
+3504877 0 1053
+10844 13 11
+18805 1 0
+1960834 126729 50000
+3065 1 0
+3601036 90008 8833
+34292 1 0
+1834 0 44
+3083 1 1
+43 1 1
+789 1 0
+11432680 153000 50000
+1902015 0 4098
+99 0 21
+3183 6 6
+877 1 1
+49 1 1
+296 0 1
+1375 1 1
+21 1 1
+607 5 5
+98 0 22
+6811 1 1
+17 0 11
+3804 1 0
+1356 1 1
+29 1 1
+297 1 0
+9543 0 2
+3130 0 4
+861 0 1
+27346 1 0
+7547 8 6
+2834 0 2
+394 4 0
+6524 1 0
+405 11 8
+1128 7 0
+271 1 1
+21 0 28
+507 6 0
+1211 44 31
+384 0 3
+521 18 18
+395 11 0
+799 1 1
+25 3 2
+51 1 49
+49 1 1
+558 0 1
+351 1 0
+2779 13 13
+114398 65008 82124
+7795 0 1
+18 1 1
+4140 1 0
+28048 1 1
+32 1 1
+4630 1 0
+4573 3 0
+357 2 0
+4812 1 0
+14372 0 3
+203 0 1
+26257 1 0
+2734 0 2
+19262 5 5
+5022 0 1
+25471 0 1
+1114538 0 53
+82 126 0
+1416 16 16
+629 57 0
+463 1 0
+148 1 1
+24 1 1
+2322 1 1
+23 1 0
+725 0 16
+24 16 0
+95 9 9
+1277 0 1
+2498 0 1
+354 49 0
+41 0 50
+17 0 49
+37 0 49
+65 8 152
+906 0 47
+234
+
+chain 3352932 17 78774742 + 33364384 33585329 17 81195210 - 44852585 44945131 363
+36 7017 7017
+2072 1 1
+16 1 1
+2167 2 0
+2513 1 1
+44 1 1
+1296 17 17
+860 5 0
+1482 0 11
+3433 1 1
+18 1 1
+393 0 3
+198 19 18
+1850 4 5
+267 1 0
+1125 6 7
+1255 1 0
+1502 0 1
+37 0 1
+26 0 1
+302 0 1
+1164 4 2
+1145 8 8
+1170 0 1
+298 1 2
+330 1 0
+2433 13 13
+79 0 2
+5343 1 1
+26 1 1
+994 1 3
+943 0 3
+2485 1 1
+22 1 1
+1574 129212 0
+265 54 54
+5225 26 26
+995 36 36
+240 1 0
+5900 61 61
+112 65 65
+53 14 14
+150 95 95
+160 48 48
+108 70 66
+401 0 6
+354 27 27
+56 65 65
+716 5 3
+1097 4 0
+518 27 27
+944 11 11
+579 37 37
+614 1 0
+2967 12 0
+601 1 10
+1307 35 35
+1719 0 889
+1973 0 3
+709 2 0
+496 5 1
+185 11 11
+98 1 0
+724 3 0
+2103 0 5
+1038 0 1
+257 7 0
+231 1 0
+312 0 2
+423 6 6
+520 10 13
+294 1 0
+17 1 1
+413 4 0
+1698 1 1
+46 1 1
+597 1 1
+21 1 1
+1182 0 2
+50 1 1
+44 0 2
+34 66 3
+3318 3 0
+624 7 0
+507 0 1
+60 1 1
+49 1 1
+332 1 1
+38 1 1
+77 1 1
+19 1 1
+65 1 0
+1174 5 0
+76
+
+chain 1309281 17 78774742 + 33410392 33424757 17 81195210 + 36336024 36350387 1779
+203 116 116
+6522 2 0
+5195 584 584
+1743
+
+chain 421642 17 78774742 + 33424760 33429230 17 81195210 - 44789041 44793512 103557
+258 1 0
+320 0 1
+3477 0 1
+414
+
+chain 288364 17 78774742 + 33534894 33553104 17 81195210 + 60335980 60353933 1564
+39 403 82
+124 31 31
+264 17 18
+283 79 89
+146 36 36
+392 27 27
+75 32 32
+295 106 106
+170 1 0
+69 35 35
+148 57 57
+152 23 23
+96 16 16
+594 57 58
+172 87 87
+108 39 39
+156 68 68
+148 63 63
+54 9 9
+39 289 289
+30 13136 13189
+45
+
+chain 141893 17 78774742 + 38701721 38703214 17 81195210 + 41346194 41347687 907641
+1493
+
+chain 138910 17 78774742 + 59795041 59797994 3 198022430 + 46191235 46194190 927459
+65 140 139
+77 32 32
+50 53 53
+51 108 111
+72 86 86
+65 76 76
+109 74 74
+120 2 0
+121 111 111
+69 23 23
+101 39 39
+56 40 40
+294 20 20
+65 100 100
+105 124 124
+147 116 116
+64 108 110
+70
+
+chain 73899 17 78774742 + 33536708 33552896 17 81195210 + 36333128 36349315 1571
+27 75 75
+32 306 306
+95 240 240
+35 148 148
+57 881 881
+57 172 172
+87 108 108
+39 156 156
+68 148 148
+63 6667 6667
+36 6153 6152
+49 112 112
+64 239 239
+74
+
+chain 29385 17 78774742 + 33422514 33422962 17 81195210 + 60352539 60352987 2653
+73 72 72
+133 53 53
+117
+
+chain 28843 17 78774742 + 33535172 33536316 17 81195210 + 34740000 34741144 3516
+164 124 124
+31 564 564
+79 146 146
+36
+
+chain 23419 17 78774742 + 40573363 40573608 17 81195210 - 37977034 37977279 7093437
+245
+
+chain 22267 17 78774742 + 59795106 59797450 15 102531392 + 100960318 100962666 927477
+74 509 513
+86 250 250
+74 1061 1061
+100 108 108
+82
+
+chain 19110 17 78774742 + 33422430 33422845 17 81195210 + 34807497 34807912 5737
+84 73 73
+72 133 133
+53
+
+chain 15302 17 78774742 + 59872221 59872543 X 155270560 + 133327972 133328295 14745200
+91 145 146
+86
+
+chain 15089 17 78774742 + 33553212 33554185 17 81195210 + 34758015 34758988 3454
+70 755 755
+27 56 56
+65
+
+chain 12559 17 78774742 + 41846587 41875489 17 81195210 + 44708735 44737620 783
+44 4372 4365
+43 24396 24386
+47
+
+chain 12028 17 78774742 + 253252 253513 17 81195210 + 253455 253745 1186280
+87 116 116
+26 30 59
+2
+
+chain 9840 17 78774742 + 59850421 59850563 12 133851895 - 30785452 30785594 23191844
+56 27 27
+59
+
+chain 8117 17 78774742 + 33410595 33410681 17 81195210 + 34744635 34744721 10477
+86
+
+chain 7470 17 78774742 + 59872141 59872220 8 146364022 - 25940938 25941017 21166303
+79
+
+chain 6548 17 78774742 + 59823421 59823489 9 141213431 + 108396482 108396550 29214974
+68
+
+chain 6212 17 78774742 + 33601781 33601849 17 81195210 + 34807429 34807497 5781
+68
+
+chain 6147 17 78774742 + 33578902 33578968 17 81195210 + 34784578 34784649 3380
+29 0 5
+37
+
+chain 5883 17 78774742 + 33556525 33558123 17 81195210 + 34761324 34762919 3874
+27 1534 1531
+37
+
+chain 5739 17 78774742 + 59862459 59862519 13 115169878 + 43436593 43436653 31343618
+60
+
+chain 5729 17 78774742 + 59852430 59852489 7 159138663 - 42785228 42785287 31366016
+59
+
+chain 5493 17 78774742 + 254397 254454 17 81195210 + 254136 254193 32044913
+57
+
+chain 5493 17 78774742 + 254339 254396 17 81195210 + 254136 254193 32044914
+57
+
+chain 4633 17 78774742 + 59795405 59797489 7 159138663 + 22571262 22573349 985966
+53 1992 1995
+39
+
+chain 3684 17 78774742 + 59871978 59872017 5 180915260 + 67132991 67133030 32368210
+39
+
+chain 3604 17 78774742 + 59872312 59872350 6 171115067 + 73766967 73767005 18649321
+38
+
+chain 3578 17 78774742 + 59797823 59797921 9 141213431 - 46000791 46000889 1219359
+98
+
+chain 3496 17 78774742 + 59872079 59872141 X 155270560 - 52661918 52661980 17303862
+62
+
+chain 3063 17 78774742 + 59796390 59796453 18 78077248 + 3738092 3738155 1007405
+63
+
+chain 2832 17 78774742 + 78651772 78651801 17 81195210 + 81058451 81058480 35013371
+29
+
+chain 2507 17 78774742 + 254312 254338 17 81195210 + 254167 254193 28153285
+26
+
+chain 2327 17 78774742 + 253481 253511 17 81195210 + 253858 253888 2965414
+30
+
+chain 2229 17 78774742 + 59795509 59795562 9 141213431 + 99971007 99971060 1163412
+53
+
+chain 2158 17 78774742 + 59871912 59871978 10 135534747 - 7120285 7120351 17475521
+66
+
+chain 2116 17 78774742 + 41755737 41755765 17 81195210 - 18330211 18330239 723
+28
+
+chain 2038 17 78774742 + 59872018 59872072 12 133851895 - 60047857 60047911 21673207
+54
+
+chain 1971 17 78774742 + 33410681 33410711 17 81195210 + 58084086 58084116 2335
+30
+
+chain 1910 17 78774742 + 59797697 59797752 7 159138663 - 95523915 95523970 1276958
+55
+
+chain 1797 17 78774742 + 59795569 59795617 8 146364022 - 39560190 39560238 1234503
+48
+
+chain 1764 17 78774742 + 59795840 59795881 17 81195210 - 78142303 78142344 1077161
+41
+
+chain 1713 17 78774742 + 59797636 59797671 10 135534747 - 112842234 112842269 1000659
+35
+
+chain 1680 17 78774742 + 59795180 59795214 3 198022430 + 108471362 108471396 1315432
+34
+
+chain 1591 17 78774742 + 59795881 59795916 X 155270560 - 139019545 139019580 1025236
+35
+
+chain 1456 17 78774742 + 59796656 59796685 6 171115067 + 121488440 121488469 989186
+29
+
+chain 1332 17 78774742 + 33532356 33535172 17 81195210 + 34572150 34574966 5130
+25 2722 2722
+69
+
+chain 1250 17 78774742 + 59795215 59795246 11 135006516 - 104930893 104930924 1222490
+31
+
+chain 1089 17 78774742 + 59795324 59795355 X 155270560 - 141145732 141145763 1311664
+31
+
+chain 1006 17 78774742 + 59797671 59797695 X 155270560 + 72606434 72606458 1154867
+24
+
+chain 622 17 78774742 + 33334125 33344374 17 81195210 - 46414201 46424210 397
+69 10130 9890
+50
+
+chain 20335446 17_random 2617613 + 224588 1377183 17 81195210 - 41910550 46712950 133
+1433 3 0
+976 0 1
+281 0 1
+1231 0 14
+2584 0 15
+2816 1 0
+3815 1 0
+122 1 1
+25 1 1
+335 0 1
+4687 29 0
+68 0 1
+1769 32 0
+616 3 0
+1017 1 1
+35 1 1
+864 17 17
+321 4 4
+47 1 1
+6467 8 10
+746 1 0
+188 30 0
+179 14 14
+120 1 1
+19 1 1
+477 1 1
+25 1 1
+300 5 5
+33 4 4
+968 6 6
+1546 1 1
+39 1 1
+66 1 1
+92 1 1
+349 12 12
+839 3 3
+36 1 1
+654 1 1
+88 1 1
+647 3 0
+993 10 8
+296 0 12
+183 4 4
+385 1 1
+25 1 1
+405 1 1
+29 1 1
+108 1 1
+36 1 1
+57 1 1
+88 2 1
+78 4 4
+39 1 1
+133 1 1
+133 1 1
+162 1 8
+398 14 14
+52 16 16
+122 1 1
+56 1 1
+98 1 1
+25 1 1
+332 1 1
+48 1 1
+83 0 1
+25 1 1
+71 1 1
+71 1 1
+79 4 0
+87 1 1
+207 1 1
+70 1 1
+263 16 16
+143 1 1
+72 1 1
+198 0 1
+1062 104 0
+6 61 0
+278 8 8
+454 49 49
+297 0 1
+1271 1 1
+48 1 1
+85 1 1
+66 1 1
+89 1 0
+327 1 1
+61 1 1
+51 1 1
+25 2 2
+72 1 1
+80 1 1
+132 1 1
+136 4 4
+63 1 1
+47 1 1
+134 1 1
+28 1 1
+1004 1 1
+45 1 1
+2017 1 1
+22 1 1
+778 8 0
+3805 0 4
+3884 1 0
+1082 1 1
+39 1 1
+926 1 0
+12182 105 0
+19079 4 0
+108 0 6
+81968 13 12
+5894 126 0
+5069 696334 2698100
+65 1 1
+31 0 1
+165 15 0
+2504 0 2
+1155 0 10
+463 1 0
+2422 0 1
+90 10 0
+75 0 1
+397 0 1
+64 31 32
+1531 4 0
+2064 0 1
+1305 1 0
+1045 0 1
+1972 0 1
+3554 0 2
+428 1 0
+1541 10 12
+1808 1 0
+1758 0 1
+500 1 0
+737 1 0
+218 0 1
+2132 0 1
+744 0 1
+7456 2 0
+45 0 2
+2311 23 23
+727 0 2
+916 1 0
+360 5 5
+2956 0 1
+3263 3 0
+1460 1 1
+34 1 1
+117 1 0
+1852 10 0
+50 7 7
+3949 42 42
+528 40 40
+736 100 17954
+680 119199 29667
+516 22 22
+2397 100 1694896
+1291 0 4
+232 1 1
+32 1 1
+1529 0 4
+20 2 0
+42 0 2
+94 0 10
+402 1 1
+16 1 1
+1099 1 1
+49 1 1
+2223 32 32
+1530 36 36
+1563 57608 84063
+160 94 94
+164 108 108
+123 61 61
+136 449 449
+3509 28 28
+1092 1 0
+611 1 1
+28 1 1
+2932 1 1
+52 49 45
+64 1 1
+27 1 1
+1320 1074 0
+6819 0 1
+4716
+
+chain 16836081 17_random 2617613 + 2022361 2536424 17 81195210 + 77630507 81150656 169
+143 0 4
+116 4 4
+74 12 10
+298 1 0
+533 1 0
+340 27 27
+130 16 16
+184 15 14
+699 1 0
+68 1 0
+153 1 0
+1835 1 0
+5 2 0
+95 1 0
+105 6 4
+14 1 0
+10 1 0
+88 1 0
+63 1 0
+27 1 0
+37 1 0
+18 1 0
+75 1 0
+49 2 0
+366 1 0
+206 1 0
+114 1 0
+237 1 0
+265 16 12
+223 1 0
+182 1 0
+26 1 0
+34 1 0
+138 1 0
+170 1 0
+26 1 0
+16 1 0
+53 4 2
+85 1 0
+188 1 0
+107 1 0
+31 1 0
+180 1 0
+4 2 1
+4 1 0
+16 1 0
+21 1 0
+324 1 0
+106 2 0
+46 1 0
+74 1 0
+12 1 0
+557 2 0
+194 5 2
+23 1 0
+67 6 3
+7 1 0
+50 1 0
+143 1 0
+190 1 0
+24 1 0
+310 1 0
+204 1 0
+108 1 0
+15 1 0
+212 1 0
+3 1 0
+57 4 2
+44 1 0
+298 1 0
+38 1 0
+54 1 0
+112 1 0
+20 2 0
+79 1 0
+10 6 3
+12 1 0
+59 1 0
+51 1 0
+234 2 0
+43 1 0
+194 1 0
+5 1 0
+96 9 4
+67 2 0
+270 1 0
+13 1 0
+59 1 0
+54 1 0
+57 1 0
+375 1 0
+50 1 0
+87 1 0
+83 4 2
+234 4 2
+44 1 0
+24 7 4
+25 1 0
+44 1 0
+139 1 0
+201 12 9
+215 1 0
+5 1 0
+30 1 0
+43 1 1
+54 16 13
+210 1 0
+109 2 0
+55 1 0
+14 1 0
+126 1 0
+79 1 0
+326 1 0
+18 1 0
+150 1 0
+13 1 0
+85 1 0
+47 1 0
+16 1 0
+41 1 0
+43 5 3
+56 1 0
+62 1 0
+164 1 0
+108 1 0
+20 2 0
+137 1 0
+214 1 0
+14 1 0
+5 2 0
+60 5 3
+24 1 0
+72 2 0
+25 1 0
+23 1 0
+60 1 0
+53 1 0
+15 1 0
+145 1 0
+337 1 0
+112 1 0
+39 1 0
+234 1 0
+7 2 0
+108 1 0
+19 1 0
+150 1 0
+22 5 3
+221 1 0
+30 1 0
+195 1 0
+126 1 0
+116 1 0
+189 1 0
+231 1 0
+87 2 0
+136 2 0
+69 1 0
+350 1 1
+29 1 0
+76 1 0
+42 1 0
+10 3 1
+63 1 0
+168 1 0
+97 1 0
+11 1 0
+291 1 0
+150 1 0
+10 1 0
+141 15 12
+9 1 0
+35 1 1
+57 1 0
+9 2 0
+211 1 0
+193 1 0
+51 1 0
+337 1 0
+94 1 0
+9 1 0
+58 1 0
+152 1 0
+58 1 0
+127 1 0
+6 1 0
+65 1 0
+379 1 0
+93 1 0
+11 1 0
+106 1 0
+545 1 0
+11 1 0
+66 2 0
+28 1 0
+242 4 2
+32 8 5
+373 10 9
+242 1 0
+207 1 0
+51 1 0
+132 1 0
+118 1 0
+19 2 0
+116 1 0
+16 1 0
+23 1 0
+54 1 0
+67 1 0
+62 1 0
+52 10 7
+15 2 0
+33 1 0
+248 1 1
+27 1 0
+122 1 0
+25 1 0
+55 1 0
+141 1 0
+57 1 0
+45 1 0
+21 1 0
+66 4 2
+23 1 1
+234 1 1
+25 2 2
+56 1 0
+34 1 0
+12 1 0
+11 1 0
+5 1 0
+54 1 0
+16 1 0
+64 1 0
+361 1 1
+24 1 0
+111 1 0
+12 1 0
+74 1 0
+56 1 0
+43 1 0
+21 1 0
+8 1 0
+13 2 0
+34 1 0
+59 1 0
+79 1 0
+159 1 0
+69 2 0
+15 2 0
+8 1 0
+142 19 17
+302 1 0
+49 1 0
+114 1 0
+72 1 0
+38 1 0
+16 1 0
+39 1 0
+106 1 0
+16 3 1
+31 1 0
+5 1 0
+43 1 0
+120 1 0
+16 1 0
+82 1 0
+47 4 1
+10 6 3
+59 1 0
+10 1 0
+258 1 0
+97 14 13
+72 1 0
+126 1 0
+14 1 0
+92 1 0
+406 1 0
+194 1 0
+43 1 0
+30 1 0
+50 1 0
+8 1 0
+161 6 4
+39 1 0
+12 1 1
+60 1 0
+61 1 0
+23 1 0
+13 1 0
+41 2 0
+260 1 0
+144 1 0
+38 1 0
+45 1 0
+17 1 0
+73 1 0
+64 20 13
+25 1 0
+84 1 0
+42 11 6
+180 1 0
+32 2 0
+172 0 1
+65 1 0
+53 1 0
+39 3 1
+203 1 0
+16 3 1
+42 3 2
+27 6 4
+13 1 0
+99 1 0
+34 4 2
+511 1 0
+182 1 0
+230 8 3
+42 1 0
+16 1 1
+270 5 4
+13 1 0
+141 1 0
+100 1 0
+144 1 0
+146 1 0
+356 1 0
+99 1 0
+69 2 0
+146 1 0
+55 18 14
+54 7 4
+18 1 0
+170 2 0
+45 1 0
+13 1 0
+628 1 0
+93 1 0
+46 1 0
+131 1 0
+20 1 0
+98 1 0
+20 1 1
+355 0 2
+88 1 0
+121 1 0
+31 1 0
+27 1 0
+132 1 0
+64 1 0
+43 1 0
+30 1 0
+95 1 0
+22 1 0
+44 6 3
+20 1 0
+138 1 0
+198 1 0
+100 1 0
+163 1 0
+6 1 0
+155 1 0
+79 1 0
+34 1 0
+193 1 0
+159 1 0
+50 5 3
+30 1 0
+9 1 0
+115 1 0
+93 1 0
+54 1 0
+91 1 0
+336 1 0
+134 18 13
+126 1 0
+61 1 0
+133 1 0
+613 4 2
+244 1 0
+586 1 0
+5 1 0
+93 19 16
+148 6 3
+12 2 1
+20 1 1
+138 102 11399
+572 8 6
+529 1 0
+659 1 1
+35 1 0
+191 2 0
+56 1 0
+105 1 0
+18 1 0
+226 1 0
+59 15 16
+275 1 0
+87 1 0
+5 1 0
+85 1 0
+21 1 0
+71 1 0
+507 1 0
+21 3 1
+82 1 0
+32 1 0
+39 1 1
+312 1 0
+263 1 0
+196 5 3
+23 5 3
+275 1 0
+46 2 0
+154 0 6
+229 1 0
+27 1 0
+87 1 0
+5 2 0
+502 1 0
+97 105 101
+162 1 0
+114 1 0
+65 1 1
+43 1 0
+217 1 0
+14 1 0
+172 1 0
+326 1 0
+9 1 0
+446 1 0
+73 1 0
+245 2 0
+114 1 0
+237 1 0
+35 22 13
+318 1 0
+320 1 0
+76 1 1
+54 1 0
+44 1 1
+100 1 0
+30 0 1
+462 1 0
+22 1 1
+72 1 1
+121 1 0
+37 1 0
+22 5 0
+23 1 1
+154 1 0
+63 1 1
+87 1 0
+278 1 0
+36 1 1
+230 1 0
+182 3 1
+51 1 0
+7 1 0
+101 1 0
+39 1 0
+17 1 0
+55 1 0
+13 1 0
+114 1 0
+13 1 0
+24 1 1
+69 10 9
+171 1 0
+60 1 1
+77 1 1
+8 2 1
+25 1 0
+51 1 0
+327 1 0
+105 2 0
+133 0 1
+28 1 0
+67 1 0
+119 4 2
+334 1 0
+37 2 1
+47 1 0
+165 1 0
+29 1 0
+35 1 0
+46 1 0
+9 1 0
+657 1 0
+62 1 0
+171 1 0
+17 1 0
+113 1 0
+15 1 1
+123 1 1
+62 1 0
+4 1 1
+288 21 0
+809 0 1
+22 1 0
+61 1 0
+52 1 0
+25 2 0
+263 3 1
+35 1 0
+192 238701 2061422
+87 1 0
+6 1 0
+1080 1 0
+76 1 0
+1007 1 0
+98 1 0
+35 1 0
+134 1 0
+285 1 0
+33 0 1
+225 1 0
+281 1 0
+108 1 0
+55 1 0
+107 1 0
+202 15 12
+111 1 0
+36 2 0
+25 1 0
+202 1 0
+97 1 0
+143 1 1
+21 1 0
+222 1 0
+41 1 0
+492 0 4
+594 1 0
+181 1 0
+410 1 0
+37 1 0
+13 1 0
+34 1 0
+76 38 37
+204 27 27
+204 40 32
+432 1 0
+143 1 0
+271 1 0
+224 96 91
+385 1 0
+337 1 0
+375 1 0
+139 22 17
+297 1 0
+72 1 0
+5 2 0
+193 1 0
+8 1 0
+28 1 0
+17 1 0
+17 1 0
+445 1 0
+169 1 36
+35 3 1
+425 1 0
+41 1 0
+37 1 0
+79 1 0
+100 1 0
+130 1 0
+419 1 0
+17 1 1
+284 3 1
+56 1 0
+9 2 1
+655 1 0
+158 2 0
+8 1 0
+34 1 1
+519 1 0
+39 1 0
+78 1 0
+216 1 0
+3 1 0
+68 1 0
+56 1 0
+70 1 0
+290 0 4
+46 0 2
+108 0 2
+23 0 114
+830 1 0
+136 76 98
+63 65 64
+380 1 0
+106 1 1
+358 1 0
+64 1 1
+17 1 0
+171 5 3
+27 1 1
+130 13 10
+131 1 0
+415 1 0
+5 1 0
+37 1 0
+29 1 0
+27 1 0
+750 1 0
+249 1 0
+221 1 0
+109 1 0
+50 1 0
+323 1 0
+296 1 0
+383 1 0
+67 1 0
+239 2 0
+248 1 0
+9 1 0
+180 1 0
+241 1 0
+40 3 1
+6 1 0
+19 1 0
+27 1 0
+166 1 0
+80 1 0
+163 1 0
+33 1 0
+9 1 0
+172 1 0
+261 1 0
+200 1 0
+14 6 2
+121 1 0
+37 4 2
+74 1 0
+97 5 3
+10 2 1
+51 1 0
+642 1 0
+317 14 11
+163 3 1
+25 2 0
+875 1 0
+128 1 0
+211 8 4
+409 1 0
+233 1 0
+263 1 0
+12 1 0
+73 1 0
+188 1 0
+96 1 0
+183 1 0
+126 1 0
+235 1 1
+68 0 1
+618 1 0
+13 1 0
+73 1 0
+1315 883 57
+78 2 2
+774 1 0
+21 1 0
+13 1 0
+9 2 0
+168 1 0
+214 1 0
+84 3 1
+645 1 0
+150 1 0
+72 1 0
+8 1 0
+108 1 0
+120 1 0
+1469 1 0
+38 1 0
+697 1 0
+44 1 0
+345 1 0
+126 1 0
+46 1 0
+110 1 0
+972 1 0
+104 23 22
+93 2 2
+38 1 0
+34 3 1
+730 1 0
+151 1 0
+124 1 0
+210 1 0
+60 1 0
+227 1 0
+122 1 0
+225 2 0
+26 1 0
+85 1 0
+84 6 3
+408 1 0
+5 3 1
+18 1 0
+69 1 0
+76 1 0
+122 1 0
+288 1 0
+10 1 0
+55 1 0
+22 2 0
+455 1 0
+246 1 0
+37 1 0
+153 1 0
+27 1 0
+101 1 0
+158 1 0
+107 1 0
+437 1 0
+31 1 0
+149 1 0
+121 1 0
+5 1 0
+175 1 0
+76 1 0
+75 1 0
+26 2 0
+98 1 0
+169 1 0
+82 1 0
+20 1 0
+326 1 0
+274 1 0
+78 1 0
+42 1 0
+64 1 0
+11 7 4
+39 1 0
+91 1 0
+140 1 0
+397 14 12
+500 7 4
+879 5 2
+448 1 0
+42 1 0
+522 1 0
+247 1 0
+484 1 0
+689 1 0
+66 1 0
+198 1 0
+441 1 0
+143 1 0
+35 1 0
+84 1 0
+9 1 0
+445 1 0
+110 1 0
+204 1 0
+31 1 0
+77 1 0
+54 1 0
+213 1 0
+601 1 0
+25 1 0
+239 2 2
+42 1 0
+29 2 0
+15 1 0
+175 1 0
+611 1 0
+418 1 0
+191 1 0
+295 1 0
+30 8 5
+609 1 0
+372 1 0
+154 2 0
+117 1 0
+282 1 0
+360 1 0
+750 1 0
+402 1 0
+45 1 0
+678 1 0
+17 1 0
+117 1 0
+148 1 0
+164 3 1
+51 1 0
+65 1 0
+452 1 0
+1443 1 0
+142 1 0
+509 1 0
+92 10 6
+264 1 0
+69 1 0
+78 1 0
+43 1 0
+164 1 0
+349 1 0
+117 1 0
+373 1 0
+235 1 0
+160 1 0
+8 1 0
+263 1 0
+15 1 0
+23 1 0
+151 1 0
+100 1 0
+204 1 0
+250 1 0
+33 3 1
+272 1 0
+262 1 0
+55 1 0
+519 1 0
+251 1 0
+189 1 0
+459 1 0
+183 1 0
+295 1 0
+552 1 0
+94 16 12
+259 1 0
+30 1 0
+396 1 0
+17 1 0
+72 1 0
+56 1 0
+90 1 0
+106 1 0
+19 2 0
+271 1 0
+448 1 0
+628 497 497
+254 26 26
+391 1 0
+32 1 0
+171 1 0
+126 20 17
+94 1 0
+446 1 0
+30 1 0
+96 1 0
+17 1 0
+159 1 0
+390 1 0
+105 1 0
+94 1 0
+5 2 0
+21 1 0
+22 1 0
+380 1 0
+12 1 0
+211 1 0
+377 1 0
+3 1 0
+63 1 0
+37 2 2
+1596 1 0
+638 1 0
+30 1 0
+665 13 10
+32 1 0
+102 1 0
+361 1 0
+609 1 0
+590 1 0
+1189 29 29
+345 1 0
+732 1 0
+544 1 0
+272 1 0
+725 1 0
+198 1 0
+8 1 0
+275 1 0
+95 1 0
+101 1 0
+626 1 0
+154 1 0
+242 1 0
+937 1 0
+142 1 0
+236 1 0
+456 12 9
+77 1 0
+189 1 0
+172 1 0
+201 1 0
+417 1 0
+179 1 0
+141 1 0
+219 1 0
+164 1 0
+138 1 0
+500 2 0
+263 1 0
+48 1 0
+17 1 0
+91 1 0
+169 1 0
+8 1 0
+185 1 0
+48 1 0
+345 1 0
+546 2 2
+229 2 2
+614 1 0
+73 2 2
+129 1 0
+91 1 0
+287 3 1
+504 2 0
+264 22 22
+508 1 0
+1324 1 0
+1313 1 0
+36 1 0
+346 1 0
+285 5 2
+31 1 0
+6 1 0
+133 1 0
+27 1 0
+101 1 0
+249 1 0
+68 5 3
+34 1 0
+31 1 0
+140 1 0
+350 1 0
+312 1 0
+139 1 0
+66 1 0
+24 1 0
+37 1 0
+16 1 0
+32 1 0
+204 1 0
+21 1 0
+11 1 0
+120 2 0
+161 1 0
+13 1 0
+143 1 0
+46 1 0
+136 3 1
+75 1 0
+176 1 0
+23 1 0
+30 1 0
+34 1 0
+307 1 0
+27 1 0
+261 1 0
+39 1 0
+995 1 0
+556 1 0
+211 1 0
+278 1 0
+850 1 0
+285 1 0
+207 1 0
+154 1 0
+51 1 0
+237 1 0
+204 1 0
+11 1 0
+348 2 0
+41 1 0
+75 2 0
+47 1 0
+49 1 0
+253 1 0
+171 10 6
+106 1 0
+83 1 0
+86 1 0
+30 1 0
+166 1 0
+297 1 0
+480 1 0
+285 1 0
+339 1 0
+30 1 0
+74 1 0
+15 1 0
+310 1 0
+88 1 0
+111 1 0
+104 1 0
+644 1 0
+29 1 0
+413 2 0
+33 3 1
+19 1 0
+321 1 0
+318 1 0
+131 1 0
+111 1 0
+89 1 0
+751 120 120
+314 1 0
+613 2 0
+991 3 1
+44 1 0
+42 1 0
+57 1 0
+102 1 0
+318 1 0
+47 2 0
+186 1 0
+550 1 0
+504 1 0
+76 1 0
+336 1 0
+505 1 0
+34 2 0
+61 1 0
+257 1 0
+439 1 0
+94 1 0
+18 1 0
+6 1 0
+86 1 0
+18 1 0
+179 1 0
+52 1 0
+635 1 0
+535 1 0
+90 1 0
+531 2 0
+59 1 0
+132 1 0
+122 1 0
+17 1 0
+96 1 0
+281 1 0
+145 1 0
+342 1 0
+132 1 0
+95 16 12
+417 1 0
+143 1 0
+135 1 0
+11 1 0
+486 1 0
+224 1 0
+277 1 0
+449 1 0
+321 34 30
+96 1 0
+20 1 0
+358 1 0
+146 1 0
+176 1 0
+37 1 0
+92 1 0
+115 1 0
+245 1 0
+72 1 0
+65 1 0
+108 1 0
+41 13 10
+121 65 54
+54 1 0
+359 1 0
+53 1 0
+55 1 0
+10 1 0
+5 1 0
+6 2 1
+43 1 0
+9 1 0
+223 1 0
+90 1 0
+157 1 0
+686 1 0
+250 1 0
+160 1 0
+264 50363 1224780
+4948 0 1
+1850 60 67
+3859 0 1
+456 4 5
+1605 21 21
+1281 7 13
+5090 456 0
+1543 1 1
+37 1 1
+2825 1 1
+64 1 1
+1075 0 1
+721 0 1
+5566 22 5
+1136 1 0
+2390 0 3
+1347 0 2
+4617
+
+chain 16543266 17_random 2617613 + 0 174588 GL000205.1 174588 + 0 174588 172
+174588
+
+chain 10747371 17_random 2617613 + 1609852 1757206 17 81195210 - 15050606 15196423 297
+3573 1 0
+1031 1 0
+4890 10 7
+318 0 1
+667 1 0
+168 0 2
+974 2 0
+143 2 0
+208 4 0
+2621 10 10
+634 2 0
+1898 0 2
+99 21 21
+6731 1 1
+49 1 1
+345 2 0
+210 1 1
+1621 1 0
+1077 0 2
+371 6 0
+4548 5769 26131
+1148 0 1
+1283 1 1
+24 1 0
+2931 0 6
+38 22 0
+682 0 1
+1267 0 2
+470 9 19
+2335 0 9
+720 8 0
+2859 26315 4346
+4414 0 1
+777 1 4
+894 4 0
+3207 0 3
+3071 0 1
+1338 1 0
+869 1 0
+2072 0 1
+395 1 0
+1060 8 8
+1138 1 1
+6 2 0
+40 1 1
+473 0 1
+748 2 0
+306 8 0
+81 6 0
+748 4 0
+158 0 22
+6454 0 2
+145 1 1
+49 1 1
+619 0 1
+1579 14 14
+455 1 0
+5224 1 1
+31 1 0
+31 0 57
+3855 0 2
+2164 11 21
+1491 0 4
+213 16 4
+4589 6 6
+1564 0 6
+325 0 1
+2241 0 1
+149 0 1
+4150 0 4
+4768 0 12
+411 0 6
+804 2 0
+124 19 19
+937 2 0
+997 27 29
+685 37 37
+5 2 0
+35 37 48
+29 1 1
+237 2 0
+333 0 1
+1296 31 23
+472 4 0
+34 1 1
+683
+
+chain 7797784 17_random 2617613 + 2131554 2212864 GL000204.1 81310 + 0 81310 420
+81310
+
+chain 5191141 17_random 2617613 + 986480 1282720 17 81195210 + 34482891 34744119 309
+118 29 29
+73 435 3450
+113 9 9
+74 44 43
+109 53 55
+147 361 38
+603 128 128
+69 8 8
+278 22 22
+1262 20 20
+83 37 44
+478 1 1
+32 1 1
+54 1 1
+81 1 1
+57 0 1
+71 4 4
+83 1 1
+103 1 1
+80 1 1
+15 1 1
+312 15 15
+185 1 1
+24 1 1
+720 1 1
+19 1 1
+185 1 1
+35 1 1
+144 7 7
+238 1 1
+62 3 3
+196 10 10
+123 1 1
+99 1 1
+1997 1 1
+27 1 1
+64 49 45
+19 1 1
+547 1 1
+16 1 1
+796 0 2
+213 0 1
+1353 0 5
+59 1 1
+604 1 0
+1099 28 28
+2219 0 1
+1732 6 6
+115 1 1
+80 1 1
+123 1 1
+106 1 1
+164 1 1
+92 1 1
+160 34984 45270
+79 5 5
+348 149 150
+73 23 23
+322 46 46
+284 35 28
+1307 16 16
+515 89 89
+62 9 9
+203 3 0
+65 10 9
+188 33 32
+342 1 0
+100 0 1
+67 48 52
+69 1 0
+2330 39 42
+356 2 0
+767 5 9
+69 4 0
+373 29 30
+138 1 0
+571 0 1
+273 13 13
+140 25 24
+457 39 39
+204 19 19
+137 49 49
+178 59 59
+220 38 38
+66 23 22
+315 1 0
+399 30 30
+345 62 62
+200 36 36
+1097 33 35
+255 5 0
+61 4 0
+371 48 33
+119 30 30
+52 0 2
+236 0 2
+81 13 13
+168 12 12
+174 0 1
+250 81 81
+185 35 35
+343 27 35
+271 232 235
+79 116 119
+288 61 61
+869 9 8
+282 7 0
+6366 1 0
+2033 112 1128
+417 0 1
+64 145492 5631
+587 0 2
+184 392 14227
+792 0 4
+408 2 1
+1608 0 1
+1287 0 2
+676 1 1
+31 1 1
+112 1 1
+91 1 1
+173 1 0
+42 1 14
+784 11 11
+3219 0 13521
+8127 24 23
+7132 0 12
+9450 0 4
+3351 28 28
+5832 3 0
+100 0 1
+67 0 5
+31 6 5
+10 1 1
+69 2 0
+2314 1 0
+11507 0 1
+742 0 63471
+5695 0 1
+731 1 0
+3536
+
+chain 4342758 17_random 2617613 + 615163 663282 17 81195210 - 81146986 81195210 699
+117 89 88
+430 1 1
+8 7 3
+19 1 1
+521 14 7
+577 1 0
+4 1 0
+284 1 1
+19 12 6
+55 3 0
+193 1 0
+383 16 13
+508 5 0
+404 6 1
+1326 31 25
+723 84 3
+41 75 0
+21 1 0
+303 27 0
+65 81 27
+94 1 1
+40 1 1
+118 746 87
+30 2 1
+37 1 1
+179 2 0
+43 1 1
+46 27 0
+35 32 0
+278 1 0
+353 8 10
+363 13 1
+106 4 0
+188 34 34
+206 1 0
+3 1 0
+1339 1 0
+632 1 1
+21 0 4
+248 1 0
+655 1 0
+258 1 0
+777 1 0
+1440 16 16
+124 1 1
+36 1 0
+33 1 1
+89 1 0
+165 1 0
+86 1 1
+47 1 1
+319 8 4
+506 4 2
+537 16 12
+2310 1 0
+7 2 0
+922 9 0
+294 1 0
+145 1 0
+1890 2 0
+15 1 0
+38 1 0
+2030 12 6
+1208 2 0
+107 1 0
+438 2 0
+492 2 0
+184 1 0
+42 1 1
+646 1 35
+28 4 4
+62 4 36
+43 0 32
+54 1 1
+8 2 0
+23 1 1
+77 0 32
+34 0 32
+52 1 167
+69 70 6
+61 0 36
+99 0 64
+605 22 22
+133 1 0
+296 1 1
+42 1 0
+361 10 6
+225 14 14
+387 1 97
+405 0 480
+101 1 0
+24 2 2
+339 0 336
+1176 1 0
+192 1 0
+553 1 0
+114 4 1
+544 18 12
+575 3 0
+85 1 0
+934 1 0
+667 13 7
+28 18 12
+770 10 6
+149 1 0
+884 22 20
+214 0 1
+607 1 0
+129 1 0
+14 6 4
+27 6 3
+10 1 0
+4 2 0
+155 39 28
+214 2 0
+43 1 1
+1236 44 27
+1759 2 0
+472 6 2
+342 8 5
+970 6 0
+227 1 0
+691 1 0
+359 2 0
+141 1 0
+5 1 0
+2008 1 0
+302
+
+chain 3923033 17_random 2617613 + 864624 922266 17 81195210 + 81075742 81117538 762
+924 1 0
+428 1 0
+763 1 0
+19745 32 32
+637 15873 36
+186 1 0
+2389 1 0
+616 1 0
+1932 12 12
+10081 18 18
+2216 1 0
+92 1 0
+271 4 4
+67 5 5
+698 83 82
+473 27 27
+62
+
+chain 3905383 17_random 2617613 + 460666 565054 17 81195210 + 41343520 41406910 763
+9362 3 1
+1313 0 1
+344 1 0
+2289 0 2
+14919 0 1
+1393 6 4
+1047 1 0
+21 0 1
+31 5511 0
+28 783 8
+978 3 4
+213 0 2
+2198 0 702
+75 4479 3549
+723 0 13
+165 1 1
+19 3 3
+113 0 4
+88 1 1
+41 1 0
+38 7 7
+98 17 17
+152 50743 16221
+115 169 185
+169 0 4
+278 1 1
+48 1 1
+6399
+
+chain 3524656 17_random 2617613 + 1876393 1913891 GL000203.1 37498 + 0 37498 830
+37498
+
+chain 3296870 17_random 2617613 + 1963891 2002673 GL000204.1 81310 + 42877 81310 872
+560 1 0
+101 2 0
+296 42 39
+438 2 0
+256 1 0
+136 1 0
+109 1 0
+101 2 0
+234 64 62
+405 37 35
+61 1 0
+366 5 3
+501 39 37
+142 1 0
+191 27 24
+59 6 4
+53 67 62
+91 1 0
+159 1 0
+74 40 38
+164 1 0
+57 28 26
+75 1 0
+46 1 0
+61 45 43
+117 1 0
+360 45 43
+204 1 0
+180 61 58
+589 1 0
+212 1 0
+88 1 0
+53 1 0
+492 1 0
+75 26 24
+273 1 0
+701 1 0
+444 1 0
+75 1 0
+393 11 9
+105 59 56
+72 42 40
+79 1 0
+79 1 0
+95 153 144
+127 1 0
+85 4 2
+175 3 0
+222 1 0
+121 1 0
+48 1 0
+50 1 0
+61 1 0
+213 1 0
+73 1 0
+180 2 0
+83 1 0
+58 1 0
+192 11 5
+57 140 125
+101 1 0
+91 38 34
+190 1 0
+73 1 0
+116 6 4
+275 16 14
+200 1 0
+201 3 1
+632 1 0
+60 1 0
+198 9 1
+254 2 0
+89 1 0
+60 38 36
+326 32 28
+306 1 0
+55 1 0
+100 18 16
+127 36 32
+67 1 0
+78 1 0
+90 1 0
+63 35 31
+120 150 141
+103 9 7
+406 88 85
+54 15 13
+142 9 7
+112 32 30
+237 1 0
+114 27 18
+157 40 38
+145 1 0
+380 20 18
+73 109 104
+57 1 0
+83 68 65
+567 1 0
+378 0 4
+282 29 27
+725 1 0
+204 1 0
+246 1 0
+295 17 15
+243 1 0
+187 46 44
+56 1 0
+244 1 0
+303 1 0
+121 16 15
+253 1 0
+273 44 44
+427 10 0
+403 2 0
+219 1 0
+151 1 0
+115 14 13
+193 1 0
+63 1 0
+63 38 36
+609 1 0
+81 42 40
+297 1 0
+455 17 14
+278 3 1
+691 1 0
+417 104 101
+57 1 0
+93 5 3
+309 48 47
+303 1 0
+324 1 0
+126 41 37
+138 2 0
+233 1 0
+100 50 47
+86 9 7
+256 1 0
+208 1 0
+486 3 1
+118 1 0
+70 69 64
+455 8 6
+149 1 0
+175 5 2
+115 1 0
+159 1 0
+109 12 9
+135 33 31
+53 1 0
+256 5 3
+82 41 38
+268 70 67
+600 1 0
+128 18 16
+114 1 0
+149 62 58
+99 57 54
+158 42 38
+88 1 0
+75 46 43
+300 50 47
+71 13 11
+118 1 0
+177 1 0
+120 1 0
+275 1 0
+74 13 11
+230 1 0
+117 6 4
+113 39 37
+71 1 0
+597 9 8
+82 10 6
+195 10 8
+361 1 0
+53 1 0
+291 0 1
+149 1 0
+164
+
+chain 2935078 17_random 2617613 + 1427191 1457644 17 81195210 + 81045288 81075743 955
+1667 2 0
+1156 0 2
+25 0 2
+27603
+
+chain 2199778 17_random 2617613 + 671651 748529 11 135006516 - 134809692 134880676 533
+53 3 0
+176 68 0
+22 38 1
+38 43 16
+122 41 249
+34 4 16
+5 1 0
+6 1 0
+68 0 37
+1042 1 1
+35 1 1
+27 326 0
+359 1 0
+3 2 0
+176 16 5
+44 5 1
+224 1 0
+432 1 1
+35 1 1
+266 21 16
+109 14 10
+806 0 34
+465 56 0
+57 4 0
+787 1 0
+283 1 1
+27 1 1
+1090 1 1
+81 1 0
+1354 1 0
+40 1 1
+305 1 0
+89 1 1
+63 1 1
+48 1 1
+167 11 11
+83 8 4
+45 5 3
+343 1 1
+47 49 0
+56 0 294
+17 49 0
+79 5 103
+162 49 0
+442 10 10
+438 3 0
+50 1 1
+676 1 1
+39 1 1
+66 1 1
+7 1 0
+35 1 1
+547 7 2
+549 2393 0
+3 2913 0
+65 1 0
+60 1 1
+69 1 1
+42 0 1
+175 5 4
+100 1 0
+402 1 0
+39 1 0
+10 1 0
+10 1 0
+14 1 1
+95 4 2
+120 0 5
+126 1 1
+32 2 1
+72 1 1
+335 1 1
+45 1 0
+403 4 1
+54 1 0
+108 1 0
+289 1 1
+40 1 0
+164 12 12
+169 1 1
+76 1 1
+71 3 3
+34 1 1
+65 72 72
+84 64 1
+55 190 1
+52 1 1
+42 5 5
+138 1 1
+39 1 1
+311 6 7
+300 1 0
+597 17 17
+187 1 1
+32 100 2817
+24 203 202
+36 1 1
+115 4 0
+139 25 24
+1050 1 0
+56 1 0
+90 1 0
+33 1 0
+35 3 0
+114 1 1
+19 1 1
+215 1 0
+431 1 1
+23 1 0
+421 14 11
+292 1 1
+22 1 1
+49 2741 2490
+33 4095 4075
+9 0 3
+18 1474 1474
+3 6 1
+11 3 0
+38 14404 14348
+27 15613 15513
+5 5 5
+21 1 2
+13 19 20
+34 104 104
+44 214 216
+8 3 0
+27 2800 929
+60 1 1
+29 4270 3383
+30 49 0
+26 1 1
+40 2712 2960
+33 1 1
+7
+
+chain 2173268 17_random 2617613 + 699498 748919 1 249250621 - 248538148 248591008 468
+685 3 3
+36 4 4
+73 9 5
+59 70 63
+42 285 48
+44 1 1
+96 74 80
+321 1 1
+49 1 1
+107 1 1
+47 11 2
+85 3 0
+67 1 0
+179 19 16
+220 9 0
+138 33 33
+136 1 1
+26 1 1
+545 1 0
+8 14 10
+42 1 1
+64 1 1
+28 1 1
+119 1 1
+49 1 1
+54 1 1
+32 1 1
+960 1 1
+41 1 1
+731 16 16
+57 1 1
+19 1 1
+118 1 0
+196 1 1
+50 1 1
+263 1 1
+52 1 1
+171 1 1
+26 1 1
+181 25 16
+51 27 0
+56 1 1
+139 0 4
+33 1 1
+236 1 1
+17 1 1
+192 15 13
+186 1 1
+30 7 7
+280 1 1
+80 1 0
+196 62 54
+290 1 1
+38 1 1
+772 10 10
+123 1 1
+28 1 0
+20 34 22
+81 0 4
+45 1 1
+806 1 1
+31 1 0
+35 1 1
+101 17 15
+89 1 1
+34 1 0
+8 1 1
+290 13 9
+284 1 0
+53 7 0
+26 6 0
+605 4 0
+531 35 35
+704 1 1
+66 1 1
+168 1 1
+34 1 1
+527 1 1
+30 1 1
+249 16 7
+414 1 1
+27 1 1
+344 1 1
+43 1 1
+117 1 1
+30 1 1
+862 0 1
+229 1 1
+48 1 1
+197 14 14
+972 19 31
+924 1 1
+42 1 1
+123 1 1
+56 1 1
+77 1 1
+23 1 1
+119 1 1
+53 18 11
+382 1 1
+17 1 1
+116 5 2
+37 1 1
+38 2 0
+223 1 1
+21 6 1
+583 1 0
+400 0 4
+1574 27 27
+54 4 1
+158 10 7
+336 6 7
+492 1 0
+14 1 1
+843 1 2
+247 1 1
+41 1 1
+50 6 6
+513 17 13
+615 12 12
+585 32 23
+161 6 6
+515 9 5
+43 5 3
+460 5 5
+158 11 11
+252 1 1
+22 3 0
+135 12 12
+556 0 1
+542 3 0
+298 4 1
+24 4 0
+117 9 5
+151 0 1
+291 0 1
+360 15 15
+962 20 17
+231 1 0
+293 1 0
+33 32 0
+40 15 10
+213 23 23
+458 1 1
+51 1 1
+437 1 0
+394 1 1
+25 2 0
+117 10 4
+50 1 1
+40 1 1
+626 8 5
+492 1 0
+383 1 0
+672 1 1
+136 1 1
+203 2 2
+88 1 1
+261 1 1
+45 1 1
+189 15 15
+78 1 1
+49 1 1
+93 1 0
+35 13 10
+21 1 1
+527 99 94
+103 44 44
+79 24 26
+111 39 36
+235 24 27
+117 7 7
+127 222 1777
+58 167 165
+59 75 75
+203 12 12
+55 56 44
+269 34 32
+87 24 24
+250 35 29
+682 91 91
+312 4 3
+583 124 2653
+132 399 398
+134 1 1
+33 1 1
+179 1 1
+27 1 1
+245 4 4
+93 1 1
+940 1 1
+20 1 1
+271 1 1
+16 0 1
+353 24 17
+369 146 0
+83 1 1
+34 1 1
+1103 1 1
+26 1 1
+112 1 0
+3 1 0
+370 32 27
+410 170 174
+51 1 1
+310 42 41
+66 5 2
+319
+
+chain 2047886 17_random 2617613 + 532224 554093 17 81195210 - 39794017 39815907 1262
+682 50 50
+270 0 4
+316 0 1
+691 1 0
+678 1 2
+601 1 0
+383 1 0
+20 1 1
+1048 2 0
+1884 0 6
+690 0 5
+1205 1 1
+43 0 2
+891 19 19
+1916 7 6
+2354 0 3
+2253 10 0
+2406 0 13
+1972 6 6
+595 0 4
+148 100 100
+356 20 20
+109 4 4
+73 2 0
+59
+
+chain 1863993 17_random 2617613 + 1011919 1106715 17 81195210 + 34578530 36287451 432
+1027 148 148
+295 18 18
+204 37 37
+144 7 7
+238 38 38
+357 101 101
+125 64 64
+712 21 22
+181 126 1729
+702 0 2
+184 29 30
+236 37 37
+1080 60 65
+606 1 0
+328 63 63
+556 20 20
+94 37 37
+172 0 1
+1430 0 1
+151 53 53
+605 36 36
+292 1 0
+84 17921 60667
+87 11034 74480
+38 804 804
+30 345 345
+62 200 200
+36 1097 1097
+33 696 696
+48 119 119
+30 986 986
+81 185 185
+35 641 641
+232 79 79
+116 288 288
+61 11306 1517682
+155 7 0
+427 5 5
+742 2 0
+85 1 1
+401 1 1
+97 1 1
+566 1 0
+607 1 0
+1318 0 24
+1995 71 3
+34 0 2
+44 1 1
+39 0 1
+3518 0 4
+469 1 0
+294 10 13
+520 6 6
+403 0 3
+331 1 0
+231 7 0
+255 0 1
+3122 0 1
+729 0 1
+117 11 11
+186 4 0
+84 1 0
+412 2 0
+19 1 1
+1642 6 0
+628 1 1
+21 1 1
+377 50 50
+151 0 9
+2370 1 1
+35 1 1
+1328 1 10
+586 14 0
+789 12 13
+1397 0 1
+1521 0 2
+382 0 1
+866 1 1
+20 1 1
+710 2 0
+1259 161 161
+387 28 28
+53 24 24
+3626 1 0
+1718
+
+chain 1732426 17_random 2617613 + 2586433 2605017 17 81195210 - 39776940 39795500 1439
+1157 1 1
+31 0 5
+2053 8 8
+691 1 1
+30 1 1
+1212 3 0
+3864 1 0
+3 1 0
+56 15 0
+860 1 1
+30 1 1
+6532 4 4
+147 13 13
+1042 17 17
+319 7 0
+181 10 10
+68 42 42
+51 16 14
+115
+
+chain 1719393 17_random 2617613 + 1323861 1343929 17 81195210 + 45650033 45670000 1446
+76 1 1
+94 1 1
+84 9 9
+70 1 1
+43 1 0
+40 0 2
+126 1 1
+38 1 1
+391 1 1
+43 1 1
+100 0 1
+66 12 12
+65 1 1
+39 2 0
+9 4 0
+25 1 1
+99 1 1
+27 0 4
+362 22 4
+659 2 0
+433 0 20
+16 1 1
+117 1 1
+248 1 1
+200 1 1
+23 1 1
+248 6 0
+120 1 1
+930 1 1
+14 1 1
+76 1 1
+11 1 0
+23 2 0
+23 1 1
+236 1 1
+48 1 1
+108 1 1
+141 7 5
+50 1 1
+27 1 1
+306 0 3
+290 1 1
+20 0 1
+31 1 1
+618 5 6
+350 14 6
+55 0 2
+112 4 0
+50 1 1
+263 1 0
+51 1 1
+527 1 1
+47 1 1
+247 1 1
+34 3 3
+169 0 2
+33 3 0
+165 12 0
+163 1 1
+77 1 0
+56 26 26
+54 6 6
+338 2 0
+185 73 73
+336 0 3
+89 1 1
+19 1 1
+65 18 18
+89 0 1
+178 1 1
+45 1 1
+67 8 0
+347 0 1
+22 1 1
+192 1 1
+73 1 4
+38 0 1
+61 1 1
+164 1 1
+74 3 3
+260 5 0
+89 9 9
+142 1 1
+49 1 1
+71 0 1
+62 1 1
+391 1 1
+78 1 1
+100 1 1
+32 1 1
+155 11 12
+304 8 0
+79 1 1
+115 1 1
+29 1 1
+97 19 0
+168 1 1
+19 4 4
+359 2 0
+18 1 1
+358 1 1
+38 1 1
+83 1 1
+31 1 1
+389 1 1
+32 1 1
+128 1 1
+39 1 1
+54 1 1
+11 2 0
+165 4 0
+34 1 1
+58 1 1
+68 3 0
+230 1 1
+44 1 1
+276 16 16
+170 6 6
+104 1 1
+61 1 1
+107 6 6
+177 1 1
+66 5 0
+60 1 1
+14 1 1
+50 4 4
+15 1 1
+62 1 1
+194 1 1
+72 22 1
+39 1 1
+70 1 1
+42 1 1
+58 1 1
+36 1 1
+329 1 0
+136 1 1
+192 9 10
+682 24 21
+81 0 1
+367 12 12
+81
+
+chain 1570588 17_random 2617613 + 1644335 1687876 17 81195210 + 66068832 66112387 1087
+1168 16352 16361
+2197 2 0
+1554 1 0
+6339 0 4
+1936 0 7
+2357 2 0
+7231 1 0
+4401
+
+chain 1476469 17_random 2617613 + 2303443 2319476 17 81195210 + 79885696 79901628 1655
+880 1 0
+298 1 0
+60 43 40
+227 40 38
+326 1 0
+77 1 0
+148 1 0
+199 21 19
+60 1 0
+224 1 0
+173 1 0
+317 88 84
+84 1 0
+96 48 45
+432 1 0
+107 1 0
+505 1 0
+88 1 0
+551 1 0
+107 1 0
+176 1 0
+79 2 0
+127 1 0
+56 1 0
+239 1 0
+218 1 0
+11 1 0
+27 1 0
+256 1 0
+130 1 0
+60 1 0
+586 1 0
+96 1 0
+58 1 0
+80 1 0
+135 1 0
+55 1 0
+219 5 2
+11 4 2
+30 4 1
+368 1 0
+106 1 0
+119 18 13
+146 1 0
+636 1 0
+156 1 0
+541 1 0
+107 1 0
+97 1 0
+61 1 0
+66 1 0
+7 1 0
+238 1 0
+105 1 0
+13 1 0
+667 1 0
+85 1 0
+70 1 0
+642 1 0
+635 1 0
+57 1 0
+249 1 0
+237 1 0
+162 1 0
+166 1 0
+380 1 0
+271 1 0
+215 2 0
+260 1 0
+160 1 0
+62 1 0
+6 1 0
+185 1 0
+48 1 0
+265 5 2
+87 1 0
+186 1 0
+62 1 0
+20 1 0
+135
+
+chain 1260177 17_random 2617613 + 853052 928106 17 81195210 - 43628 125104 962
+949 1 0
+3976 1 0
+155 1 0
+1382 1 0
+174 1 0
+249 1 0
+3481 16 14
+138 196 313
+72 88 86
+491 22816 3210
+803 32 32
+116 1 0
+346 10 9
+779 1 0
+620 1 0
+336 1 0
+2035 1 0
+1010 1 0
+1029 22 20
+97 39 114
+77 79 0
+5135 26 26
+535 1 0
+2026 21 19
+206 2 0
+254 19578 45525
+174 1 1
+34 1 1
+97 25 25
+137 6 5
+2443 14 9
+445 1 0
+116 1 0
+2150
+
+chain 1227372 17_random 2617613 + 986700 1051441 17 81195210 + 34570816 36317431 617
+294 0 3023
+141 196 196
+44 109 109
+53 147 147
+19 33 32
+101 42 42
+166 603 602
+128 1742 1742
+37 15134 15157
+88 7169 151654
+89 3878 5468
+37 1080 1080
+60 1668 1668
+37 1753 1753
+53 605 605
+36 506 39138
+695 47 47
+375 59 59
+312 20 20
+185 37 37
+144 7 7
+238 38 38
+357 101 101
+125 64 64
+712 185 184
+2677 120 1494235
+1055 15 15
+700 4 4
+1174 24 24
+888 9 3
+1590 0 3
+913 18 20
+1011 1 1
+26 1 1
+2545 1 1
+35 1 1
+1283 87 87
+45 432 432
+149 418 418
+46 284 284
+2 3 3
+30 1838 1839
+89 540 540
+32 511 512
+48 2400 2403
+39 3223 3228
+39 360 360
+49 178 178
+59
+
+chain 1028733 17_random 2617613 + 2262901 2274699 17 81195210 - 1281214 1293541 2373
+276 161 161
+1171 1 0
+181 1 0
+943 1 0
+423 1 0
+384 47 47
+111 466 1042
+106 31 31
+75 4 4
+63 20 16
+142 1 0
+59 1 0
+607 1 0
+135 1 0
+31 1 0
+82 1 0
+266 1 0
+76 1 0
+5 4 2
+41 1 0
+52 1 0
+985 1 0
+87 1 0
+4 1 0
+114 1 0
+175 1 0
+30 1 0
+140 2 0
+22 1 0
+130 1 0
+239 1 0
+766 1 0
+203 1 0
+68 2 0
+252 1 0
+300 4 2
+377 1 0
+735 1 0
+279 5 2
+91 1 0
+66 1 0
+159 1 0
+7 1 0
+562
+
+chain 931587 17_random 2617613 + 978106 1010959 17 81195210 + 36277154 36406169 991
+1048 10 12
+382 0 1
+199 22 22
+381 8 8
+56 66 66
+80 176 176
+73 27 27
+90 32 32
+166 31 209
+634 0 4
+1199 65 65
+56 27 27
+255 27 27
+50 1 7
+422 5 5
+61 4 0
+80 311 311
+40 144 144
+53 3450 47979
+41 18030 69497
+201 21 0
+219 1 0
+310 0 1
+3136 0 1
+510 50 52
+321 3 0
+279
+
+chain 813092 17_random 2617613 + 1807252 1826317 17 81195210 + 22246129 22262163 2589
+338 20 20
+223 15 15
+164 162 162
+54 59 60
+73 230 230
+52 48 48
+50 66 66
+54 49 49
+257 14 14
+103 22 22
+96 5 5
+357 121 121
+100 88 88
+108 94 94
+490 34 34
+81 27 27
+54 82 82
+80 138 138
+128 12 12
+262 24 21
+199 35 35
+263 80 80
+84 52 52
+185 16 16
+75 113 113
+160 99 99
+70 27 27
+84 49 49
+59 25 25
+133 30 30
+64 45 45
+304 25 25
+986 74 74
+160 13 13
+209 22 22
+54 43 43
+61 156 156
+54 6 6
+77 5 5
+86 85 85
+117 48 165
+381 74 74
+262 32 32
+165 71 71
+57 95 95
+89 31 31
+114 140 140
+117 216 216
+77 5 5
+52 442 441
+185 60 60
+363 22 22
+179 11 11
+259 197 197
+118 35 35
+108 60 60
+61 61 61
+137 50 50
+53 56 56
+269 161 161
+106 103 105
+56 8 8
+368 41 41
+47 3145 0
+401 42 42
+90 23 23
+151 73 73
+81 148 146
+351
+
+chain 788653 17_random 2617613 + 1298766 1307227 17 81195210 - 44798207 44806654 6145
+463 1 0
+2422 0 1
+90 14 0
+75 0 1
+397 0 1
+64 1 1
+30 0 1
+202 1 0
+1329 2 0
+1396 1 0
+668 0 1
+280 45 45
+980
+
+chain 597412 17_random 2617613 + 807879 2303216 17 81195210 - 0 1281216 430
+180 1676 138
+25553 1 0
+149 14 14
+1938 1 0
+350 32 32
+1230 1 0
+3 1 0
+6237 1 0
+45 2 2
+6514 1 0
+228 662945 0
+7897 0 1
+2396 1 0
+1101 17 0
+41 1 1
+355 0 52
+50 18 1
+41 0 68
+84 34 0
+4918 0 1
+717 0 1
+313 1 1
+42 1 1
+73 29 31
+205 58 0
+414 1 1
+64 1 1
+959 1 1
+17 1 1
+2276 1 0
+739 0 1
+418 11 49
+1541 0 1
+3494 7 13
+1281 21 21
+1738 1 191
+26 0 38
+40 0 77
+67 5 5
+11 1 75
+55 2266 0
+112 47 9
+78 38 0
+24 1 1
+80 5 5
+551 0 5
+87 1 1
+35 1 1
+54 119 195
+74 1 1
+957 15 15
+64 1277 306
+91 1 1
+35 1 1
+820 48 67
+330 0 1
+2794 1 0
+1127 1 1
+19 0 5
+1483 715858 1169096
+78 1 0
+529 1 0
+25 1 0
+200 1 0
+643 2 0
+450 2 0
+211 1 0
+380 2 2
+180 2 1
+32 1 0
+246 1 0
+61 1 0
+5 1 0
+351 1 0
+37 1 0
+304 1 0
+18 1 0
+109 1 0
+16 1 0
+200 1 0
+105 1 0
+37 1 0
+376 1 0
+108 1 0
+91 1 0
+394 1 0
+20 1 0
+1014 32 30
+21 2 1
+34 1 0
+230 26 26
+941 1 0
+188 1 0
+610 1 0
+555 1 0
+303 1 0
+509 157 157
+169 22 22
+101 1 0
+501 1 0
+140 1 0
+78 2 1
+22 1 0
+39 6 5
+62 94 94
+593 114 111
+260 120 120
+362 1 0
+697 0 1
+123 28 28
+402 36 36
+904 1 0
+50 1 0
+379 1 0
+256 25 25
+23 17 17
+53 27 27
+556 1 0
+409 1 0
+106 1 0
+276 24 24
+35 2 0
+252 32 32
+213 4 4
+70 2 0
+27 4 2
+82 1 0
+17 1 0
+639 1 0
+172 11 7
+10 1 0
+76 1 0
+1582 1 0
+275 1 0
+21 1 0
+17 4 2
+66 1 0
+1653 1 0
+19 3 3
+139 179 179
+76 2 2
+60 1 0
+226 1 0
+538 1 0
+346 4 4
+42 25 25
+1319 1 0
+261 1 0
+512 1 0
+69 1 0
+480 2 0
+388 8 7
+305 5 5
+64 2 2
+846
+
+chain 590397 17_random 2617613 + 1317586 1323861 17 81195210 - 44817018 44823295 6400
+2259 1 0
+955 0 1
+2132 0 1
+744 0 1
+184
+
+chain 365975 17_random 2617613 + 1296053 1313819 17 81195210 + 45621804 45639993 6832
+81 12 44
+148 0 6
+401 61 62
+589 32 30
+259 39 57
+53 103 103
+231 127 131
+59 7954 7632
+45 980 978
+16 142 143
+82 46 46
+363 247 934
+159 50 48
+341 33 34
+57 16 16
+304 65 65
+69 9 9
+136 66 66
+138 57 57
+70 10 10
+70 123 120
+143 52 52
+152 15 19
+320 53 52
+121 0 1
+161 98 108
+97 59 59
+205 127 125
+55 11 11
+56 30 30
+88 43 43
+512 45 43
+125 143 136
+165 48 48
+56 24 24
+161 114 115
+364 40 40
+240
+
+chain 323854 17_random 2617613 + 753664 757726 11 135006516 + 51394886 51398944 206195
+84 571 570
+807 3 1
+2082 1 0
+514
+
+chain 193433 17_random 2617613 + 495545 497612 17 81195210 + 41377728 41379794 617459
+55 1 0
+1306 28 28
+677
+
+chain 170984 17_random 2617613 + 1315777 1317585 17 81195210 - 44815210 44817018 741311
+1808
+
+chain 158566 17_random 2617613 + 1808012 1818883 17 81195210 + 22251644 22262630 5258
+162 209 210
+87 88 88
+32 270 270
+48 855 855
+36 185 185
+88 888 888
+37 888 888
+35 263 263
+80 85 85
+51 276 276
+47 20 20
+46 329 329
+27 350 350
+4 5 5
+21 413 412
+25 986 986
+74 458 458
+43 137 137
+80 228 228
+85 546 663
+9 10 10
+55 262 262
+32 293 293
+68 116 116
+25 120 120
+109 148 148
+60 1 1
+67 6 4
+74 1 1
+7 134 134
+220 1 1
+65 1 1
+91 1 1
+62 186 186
+60
+
+chain 150869 17_random 2617613 + 749022 751008 11 135006516 + 51475668 51477652 852441
+306 379 377
+1301
+
+chain 148651 17_random 2617613 + 808184 809735 17 81195210 + 81137722 81139272 865111
+940 1 0
+610
+
+chain 145464 17_random 2617613 + 1314230 1315767 17 81195210 - 44813661 44815198 885049
+1537
+
+chain 120518 17_random 2617613 + 1343929 1345208 17 81195210 - 44843364 44844643 723183
+1279
+
+chain 116919 17_random 2617613 + 1353036 1364922 17 81195210 - 44845210 44857111 1380
+449 299 299
+31 164 164
+55 373 373
+449 9718 9733
+348
+
+chain 115845 17_random 2617613 + 508518 509981 17 81195210 - 39794017 39795500 1110103
+682 50 50
+270 0 4
+177 169 185
+115
+
+chain 114042 17_random 2617613 + 516500 517961 17 81195210 - 39794017 39795500 1127130
+682 50 50
+210 5 6
+54 0 6
+175 170 185
+115
+
+chain 113591 17_random 2617613 + 521388 522849 17 81195210 - 39794017 39795500 1131524
+58 0 1
+623 50 50
+210 5 6
+54 0 6
+175 171 185
+115
+
+chain 112548 17_random 2617613 + 503499 505329 17 81195210 - 39794017 39795500 1141710
+27 370 0
+655 50 50
+210 5 6
+54 0 7
+174 170 185
+115
+
+chain 92910 17_random 2617613 + 1642194 1643169 17 81195210 - 1314977 1315952 1374174
+975
+
+chain 86438 17_random 2617613 + 1345275 1346182 17 81195210 - 44844700 44845607 1472746
+907
+
+chain 80313 17_random 2617613 + 2609695 2610598 17 81195210 - 39794017 39794920 1580802
+682 50 50
+171
+
+chain 78741 17_random 2617613 + 1643269 1644095 17 81195210 + 79874782 79875608 1611354
+826
+
+chain 75472 17_random 2617613 + 1310578 1313579 17 81195210 - 44810007 44813007 188419
+53 282 282
+98 97 97
+59 205 205
+127 122 122
+30 88 88
+43 512 512
+45 125 125
+72 1 0
+70 165 165
+48 241 241
+114 364 364
+40
+
+chain 74354 17_random 2617613 + 1547620 1548395 8 146364022 - 2302524 2303299 1703290
+775
+
+chain 61189 17_random 2617613 + 1546707 1547351 8 146364022 + 144057273 144057917 2067192
+644
+
+chain 59362 17_random 2617613 + 751149 753548 1 249250621 - 248579195 248581575 182656
+35 2 1
+152 1 0
+15 1 0
+107 3 2
+74 1 0
+10 1 0
+19 1 0
+57 1 1
+48 3 1
+6 1 0
+107 12 330
+61 1 1
+51 357 35
+388 110 110
+84 38 38
+62 227 223
+116 106 105
+141
+
+chain 56858 17_random 2617613 + 1298104 1298766 17 81195210 - 44797535 44798197 1968612
+85 59 59
+518
+
+chain 56536 17_random 2617613 + 501286 502149 17 81195210 - 39794614 39795500 2243684
+85 50 50
+210 5 6
+54 0 7
+174 170 185
+115
+
+chain 55411 17_random 2617613 + 688273 689806 7 159138663 - 159114165 159114723 7844
+88 175 0
+148 458 0
+103 231 3
+111 117 3
+102
+
+chain 52941 17_random 2617613 + 1822234 1824166 17 81195210 - 58941545 58943477 1155
+887 1 1
+77 1 1
+300 1 1
+20 9 9
+133 1 1
+23 1 1
+59 1 1
+158 1 1
+91 1 1
+54 1 1
+112
+
+chain 52559 17_random 2617613 + 983839 1162005 17 81195210 - 44845659 46605886 726
+299 65 65
+117 68 68
+1986 9723 54270
+49 72036 1500609
+1027 6412 6412
+71 13528 13528
+50 11447 11447
+132 60546 169487
+42 528 528
+40
+
+chain 51097 17_random 2617613 + 1023443 1026449 17 81195210 + 34744258 34747264 8774
+47 375 375
+59 517 517
+37 389 389
+38 357 357
+101 125 125
+64 712 712
+185
+
+chain 49537 17_random 2617613 + 686221 687340 7 159138663 - 159114165 159114714 2581538
+393 570 0
+156
+
+chain 49422 17_random 2617613 + 2502237 2515076 GL000206.1 41001 + 6806 19645 760
+60 12323 12323
+456
+
+chain 46461 17_random 2617613 + 530697 531391 17 81195210 + 41399710 41400427 2769983
+115 170 185
+151 0 7
+77 5 6
+176
+
+chain 44819 17_random 2617613 + 1346282 1352646 17 81195210 + 36399842 36406169 117269
+158 113 113
+546 19 0
+337 0 1
+343 21 0
+219 1 0
+310 0 1
+3136 0 1
+510 1 1
+49 0 2
+321 1 0
+279
+
+chain 42351 17_random 2617613 + 1308282 1310091 17 81195210 - 44807710 44809519 659295
+50 341 341
+33 377 377
+65 214 214
+66 138 138
+57 150 150
+123 143 143
+52
+
+chain 41114 17_random 2617613 + 1307243 1308123 17 81195210 - 44806671 44807550 1295496
+142 82 82
+46 363 362
+247
+
+chain 38415 17_random 2617613 + 980212 983216 17 81195210 - 46382593 46436652 7347
+66 80 80
+176 73 73
+27 90 90
+32 166 166
+31 1833 52888
+65 56 56
+27 255 255
+27
+
+chain 37708 17_random 2617613 + 1313819 1314225 17 81195210 - 44813251 44813657 3332998
+406
+
+chain 34385 17_random 2617613 + 689365 745709 16 90354753 + 90179685 90235100 655
+111 4456 3661
+64 55 55
+25 28 28
+47 0 945
+90 45591 45393
+56 269 269
+34 5469 4540
+13 2 2
+32 0 48
+2
+
+chain 29758 17_random 2617613 + 1820296 1826385 17 81195210 + 22249775 22252718 80336
+37 643 643
+77 136 133
+51 3143 0
+44 74 74
+224 80 80
+64 79 79
+9 741 741
+39 82 82
+59 25 25
+56 358 358
+68
+
+chain 29219 17_random 2617613 + 1551349 1551651 17 81195210 + 81144397 81144699 5017519
+302
+
+chain 28762 17_random 2617613 + 686677 687796 7 159138663 - 159114165 159114714 2625478
+282 456 0
+111 3 3
+57 114 0
+96
+
+chain 26027 17_random 2617613 + 1296695 1298103 17 81195210 - 44796117 44797535 630440
+61 589 589
+32 259 269
+39 53 53
+103 231 231
+41
+
+chain 25589 17_random 2617613 + 1810180 1822057 17 81195210 + 22246679 22258671 5893
+31 6949 7063
+28 2666 2666
+60 580 580
+49 73 73
+37 1172 1173
+232
+
+chain 22463 17_random 2617613 + 503557 503790 17 81195210 - 39794076 39794309 8690008
+233
+
+chain 21299 17_random 2617613 + 1013035 1014722 17 81195210 + 34795732 34797419 1064
+59 517 517
+37 389 389
+38 357 357
+101 125 125
+64
+
+chain 20434 17_random 2617613 + 685587 686087 7 159138663 - 159114215 159114487 2822651
+209 248 20
+43
+
+chain 19692 17_random 2617613 + 2611651 2612116 17 81195210 - 39813091 39813524 10717347
+67 163 137
+78 68 62
+89
+
+chain 19589 17_random 2617613 + 2616810 2617276 17 81195210 + 41381686 41382119 10803726
+89 68 62
+77 165 138
+67
+
+chain 17762 17_random 2617613 + 852036 852257 5 180915260 - 51646 51969 938
+13 1 1
+60 1 1
+29 1 1
+13 0 102
+103
+
+chain 17600 17_random 2617613 + 1364922 1365125 17 81195210 - 46397651 46397854 1833
+172 1 1
+30
+
+chain 17149 17_random 2617613 + 1514626 1514877 1 249250621 + 547399 547650 3354419
+131 1 3
+101 2 0
+16
+
+chain 16567 17_random 2617613 + 2610699 2610873 17 81195210 - 39795026 39795200 13468304
+174
+
+chain 16365 17_random 2617613 + 1812948 1813633 17 81195210 + 22258959 22259644 44227
+99 181 181
+49 59 59
+25 227 227
+45
+
+chain 16348 17_random 2617613 + 525487 525673 11 135006516 + 62609095 62609281 13688187
+75 4 4
+107
+
+chain 14733 17_random 2617613 + 2605728 2605963 17 81195210 - 39813295 39813524 15353144
+78 68 62
+89
+
+chain 14711 17_random 2617613 + 556093 556262 11 135006516 - 72397235 72397404 15378622
+107 4 4
+58
+
+chain 14711 17_random 2617613 + 527846 528015 11 135006516 - 72397235 72397404 15378623
+107 4 4
+58
+
+chain 14711 17_random 2617613 + 512402 512571 11 135006516 - 72397235 72397404 15378624
+107 4 4
+58
+
+chain 14711 17_random 2617613 + 510910 511079 11 135006516 - 72397235 72397404 15378625
+107 4 4
+58
+
+chain 14711 17_random 2617613 + 494247 494416 11 135006516 - 72397235 72397404 15378626
+107 4 4
+58
+
+chain 14711 17_random 2617613 + 492878 493047 11 135006516 - 72397235 72397404 15378627
+107 4 4
+58
+
+chain 14711 17_random 2617613 + 519356 519525 11 135006516 + 62609112 62609281 15378630
+58 4 4
+107
+
+chain 14711 17_random 2617613 + 514467 514636 11 135006516 + 62609112 62609281 15378631
+58 4 4
+107
+
+chain 14711 17_random 2617613 + 492408 492577 11 135006516 + 62609112 62609281 15378632
+58 4 4
+107
+
+chain 13395 17_random 2617613 + 685879 686024 7 159138663 - 159114165 159114310 16961745
+145
+
+chain 12350 17_random 2617613 + 554102 554230 17 81195210 + 41401065 41401193 18472361
+128
+
+chain 11140 17_random 2617613 + 2611055 2611170 17 81195210 - 39795385 39795500 20498301
+115
+
+chain 11115 17_random 2617613 + 1365516 1365648 17 81195210 - 46613257 46613389 1914
+132
+
+chain 10814 17_random 2617613 + 689806 689963 7 159138663 - 159114495 159114652 3160720
+43 20 20
+94
+
+chain 10716 17_random 2617613 + 690046 690160 11 135006516 - 134823089 134823203 21297817
+114
+
+chain 10594 17_random 2617613 + 686107 686221 11 135006516 - 134823089 134823203 21541329
+114
+
+chain 10432 17_random 2617613 + 752965 753084 3 198022430 + 197944313 197944432 1419040
+26 27 27
+66
+
+chain 10233 17_random 2617613 + 751962 752152 1 249250621 - 25108929 25109119 2449036
+190
+
+chain 10215 17_random 2617613 + 298300 298405 17 81195210 - 41991981 41992086 2272776
+105
+
+chain 10088 17_random 2617613 + 2614941 2615048 11 135006516 - 72397235 72397342 22628945
+107
+
+chain 9967 17_random 2617613 + 687027 687133 7 159138663 - 159114173 159114279 19905170
+106
+
+chain 9953 17_random 2617613 + 1352829 1353036 17 81195210 - 44845003 44845210 3604154
+38 53 53
+37 50 50
+29
+
+chain 9937 17_random 2617613 + 2607755 2608553 17 81195210 + 41464708 41466209 22969163
+59 661 1364
+78
+
+chain 9782 17_random 2617613 + 685310 686656 7 159138663 - 159114165 159114714 2594423
+225 1079 282
+42
+
+chain 9490 17_random 2617613 + 268561 268666 17 81195210 + 39296306 39296411 8067183
+50 6 6
+49
+
+chain 9384 17_random 2617613 + 1808529 1810797 17 81195210 + 22256920 22261566 263516
+29 104 104
+28 50 50
+48 1976 4354
+33
+
+chain 9278 17_random 2617613 + 1333217 1333901 17 81195210 - 44832655 44833339 2515
+26 585 585
+73
+
+chain 9162 17_random 2617613 + 1819790 1824781 17 81195210 + 22261160 22263006 131478
+64 322 322
+59 818 816
+30 3642 499
+56
+
+chain 8930 17_random 2617613 + 507298 507390 17 81195210 + 41466131 41466223 25058540
+92
+
+chain 8739 17_random 2617613 + 1294354 1363161 17 81195210 - 46388680 46446941 1280
+36 59095 48559
+76 160 160
+63 250 250
+52 124 124
+61 4094 4092
+28 4719 4711
+49
+
+chain 7495 17_random 2617613 + 1514877 1514981 17 81195210 - 42613 42717 4053350
+104
+
+chain 7310 17_random 2617613 + 1352662 1353007 17 81195210 - 20840434 20840778 292042
+167 38 37
+53 37 37
+50
+
+chain 6706 17_random 2617613 + 687825 687939 7 159138663 - 159114173 159114287 10506562
+114
+
+chain 6456 17_random 2617613 + 673480 673547 11 135006516 - 134811854 134811921 22781013
+67
+
+chain 5049 17_random 2617613 + 752664 753185 1 249250621 - 248584104 248584621 921258
+110 84 84
+38 62 62
+7 119 119
+72 7 3
+22
+
+chain 5012 17_random 2617613 + 557502 557555 17 81195210 + 41382227 41382280 33565948
+53
+
+chain 4802 17_random 2617613 + 1345218 1345268 17 81195210 - 44844643 44844693 34312672
+50
+
+chain 4547 17_random 2617613 + 688053 688156 7 159138663 - 159114401 159114504 10358404
+103
+
+chain 4503 17_random 2617613 + 690214 690262 7 159138663 - 159114675 159114723 34814023
+48
+
+chain 4408 17_random 2617613 + 1808470 1808528 17 81195210 + 22261618 22261676 11976838
+58
+
+chain 4236 17_random 2617613 + 269418 269467 17 81195210 - 41933979 41934028 1349427
+49
+
+chain 3906 17_random 2617613 + 1365126 1365187 17 81195210 - 23109543 23109604 10221956
+61
+
+chain 3852 17_random 2617613 + 685196 685310 7 159138663 - 159114165 159114279 3139829
+114
+
+chain 3804 17_random 2617613 + 676798 676843 11 135006516 - 134814627 134814666 26257176
+33 6 0
+6
+
+chain 3734 17_random 2617613 + 1819749 1824493 17 81195210 + 22251604 22253205 550639
+41 1133 1133
+53 3451 308
+4 6 6
+56
+
+chain 3666 17_random 2617613 + 689649 689704 3 198022430 + 197891166 197891221 670
+55
+
+chain 3459 17_random 2617613 + 687133 687184 7 159138663 - 159114165 159114216 4526522
+51
+
+chain 3336 17_random 2617613 + 1365188 1365250 17 81195210 - 20853025 20853087 9938797
+62
+
+chain 3079 17_random 2617613 + 681792 681827 11 135006516 - 134820249 134820284 24010224
+35
+
+chain 2916 17_random 2617613 + 690160 690191 7 159138663 - 159114621 159114652 25187800
+31
+
+chain 2901 17_random 2617613 + 1010962 1011819 17 81195210 - 44844823 44845680 205824
+857
+
+chain 2668 17_random 2617613 + 837741 837773 8 146364022 + 31195 31227 1221
+32
+
+chain 2659 17_random 2617613 + 747955 747987 5 180915260 + 180755757 180755789 880
+32
+
+chain 2649 17_random 2617613 + 622962 622989 17 81195210 - 81153206 81153233 29165068
+27
+
+chain 2631 17_random 2617613 + 1252044 1252072 17 81195210 + 34548405 34548433 469
+28
+
+chain 2530 17_random 2617613 + 1100849 1100878 17 81195210 - 46384734 46384763 4689
+29
+
+chain 2422 17_random 2617613 + 621448 621568 17 81195210 - 81152835 81152952 7235512
+27 65 62
+28
+
+chain 2158 17_random 2617613 + 688361 688384 16 90354753 + 90179770 90179793 21906636
+23
+
+chain 2073 17_random 2617613 + 690420 690442 7 159138663 - 159114653 159114675 31315602
+22
+
+chain 1877 17_random 2617613 + 1533316 1533338 GL000206.1 41001 - 16469 16491 815
+22
+
+chain 1804 17_random 2617613 + 687361 687825 7 159138663 - 159114165 159114515 2659234
+54 381 267
+29
+
+chain 1771 17_random 2617613 + 742259 742283 1 249250621 - 248585388 248585412 123201
+24
+
+chain 1698 17_random 2617613 + 268509 268561 17 81195210 - 41933055 41933107 4387515
+52
+
+chain 1694 17_random 2617613 + 747513 747535 1 249250621 - 249115973 249115995 773
+22
+
+chain 1343 17_random 2617613 + 555358 555450 17 81195210 - 39728987 39729079 19263806
+92
+
+chain 1343 17_random 2617613 + 511667 511759 17 81195210 - 39728987 39729079 19263807
+92
+
+chain 1343 17_random 2617613 + 526316 526408 17 81195210 + 41466131 41466223 19263808
+92
+
+chain 1343 17_random 2617613 + 520168 520260 17 81195210 + 41466131 41466223 19263809
+92
+
+chain 1129 17_random 2617613 + 1019025 1019068 17 81195210 + 60348267 60348310 2834
+43
+
+chain 1082 17_random 2617613 + 686959 687027 7 159138663 - 159114561 159114629 2979122
+68
+
+chain 594 17_random 2617613 + 1548943 1548990 GL000206.1 41001 - 30268 30353 3713456
+4 9 47
+34
+
+chain 7055976638 18 76117153 + 0 76117153 18 78077248 + 10000 78016181 19
+15400898 1363998 3100000
+28218587 15 15
+5329636 47000 150000
+3667309 0 18
+16406890 28008 50000
+3388467 22000 50000
+2103304 3 0
+136125 7 9
+647 0 1
+1543 0 1
+25 0 1
+6 2 7
+19 0 2
+10 4 7
+9 2 4
+656 0 1
+358 0 1
+1625
+
+chain 404699 18_random 4262 + 0 4262 GL000207.1 4262 + 0 4262 116011
+4262
+
+chain 5307789368 19 63811651 + 11000 63806651 19 59128983 + 60000 59114839 21
+7286004 5000 50000
+1291194 5000 50000
+11767057 0 69160
+4058367 8000000 3100000
+20129228 0 2
+701 3 0
+347 1 1
+31 1 1
+1833 3 0
+1984 1 1
+47 1 1
+190 1 1
+34 1 1
+889 0 2
+1413 0 7
+2680 0 4
+375 0 1
+328 0 4
+15 0 1
+69 1 0
+3881 1 1
+36 0 12
+296 0 14
+1480 0 1
+233 1 1
+45 1 1
+1049 0 1
+1766 44 7
+220 3 0
+536 0 7
+352 8 8
+3603 1 1
+17 3 0
+697 1 0
+269 3 0
+974 6 5
+96 0 10
+1096 10 10
+1177 14 12
+110 3 3
+1028 12 9
+1090 1 0
+173 0 16
+1066 4 0
+4779 1 1
+42 1 1
+722 1 0
+548 2 2
+44 1 1
+424 54 54
+61 1 1
+59 1 1
+2086 0 15
+1500 1 0
+1754 2 0
+11209362
+
+chain 15150451 19_random 301858 + 142689 301858 GL000209.1 159169 + 0 159169 196
+159169
+
+chain 8748871 19_random 301858 + 0 92689 GL000208.1 92689 + 0 92689 377
+92689
+
+chain 14432273 1_random 1663265 + 444114 915337 1 249250621 - 104328377 105379619 206
+1802 63331 510
+7296 6958 14784
+7961 0 2
+631 19782 48350
+2466 1 1
+72 1 1
+281 2 2
+18 1 1
+2234 1 1
+23 2 1
+1869 0 2
+890 0 1
+2816 0 3
+59 12 12
+1298 1 1
+11 1 1
+294 214294 820733
+136815
+
+chain 10693564 1_random 1663265 + 965337 1079393 1 249250621 + 199645090 199759149 300
+3537 0 2
+1755 1 1
+38 1 1
+15918 1 0
+2372 0 1
+1251 34 34
+7007 1 6
+3552 1 1
+44 1 1
+799 1 1
+42 1 1
+3907 2 0
+1780 1 1
+49 1 1
+1586 2 0
+197 1 1
+37 1 1
+292 1 1
+47 1 1
+927 0 2
+549 1 1
+27 1 1
+595 1 1
+18 1 1
+291 0 2
+6685 1 0
+2369 1 0
+6503 13 13
+639 1 1
+70 1 1
+477 1 0
+1001 0 2
+1967 2 0
+3454 1 1
+26 1 1
+3144 0 4
+89 1 0
+6546 14 15
+6194 1 0
+5390 13 13
+196 1 0
+7401 1 9
+1242 1 0
+1702 1 0
+477 1 1
+61 0 1
+1487 1 0
+1276 1 0
+1950 9 0
+4681 0 2
+1332 1 0
+956
+
+chain 10110185 1_random 1663265 + 1464329 1570762 GL000191.1 106433 + 0 106433 317
+106433
+
+chain 6680210 1_random 1663265 + 198768 359123 1 249250621 + 1257620 1436018 467
+467 0 1
+41 0 1
+10 4 4
+930 2 3
+122 3 4
+138 66071 6986
+47 0 1
+945 0 1
+279 1 2
+508 0 1
+482 0 1
+1285 1 1
+40 1 1
+199 0 1
+207 1 1
+29 1 1
+1021 0 1
+1168 0 2
+388 0 1
+69 15 17
+195 4 4
+52 1 1
+9 1 3
+23 0 1
+284 0 1
+1485 15 16
+138 9 9
+27 44 5
+35 46 46
+97 0 1
+5 0 1
+734 0 3
+257 1 1
+18 1 1
+442 0 2
+51 4 0
+424 0 1
+134 1 1
+39 0 1
+22 1 1
+564 15 17
+469 0 3
+39 0 1
+22 2 2
+1076 0 1
+210 14 14
+166 0 1
+3264 1 0
+111 0 1
+309 19898 50666
+91 0 1
+116 0 1
+56 0 1
+152 0 1
+46 0 1
+51 0 1
+63 0 2
+420 4 5
+697 0 1
+2269 7 0
+48 1 1
+4086 0 2
+317 0 1
+49 0 1
+1795 0 1
+1147 1 1
+39 1 1
+1378 0 17
+477 2 0
+4457 1 1
+105 0 1
+1003 0 1
+232 1 2
+147 277 46717
+169 0 1
+37 1 1
+227 0 2
+651 1 0
+1805 1 1
+45 1 1
+498 1 0
+233 1 1
+29 1 1
+231 12 20
+2015 0 1
+20 1 1
+653 0 1
+12 0 1
+17 1 1
+139 0 1
+10 0 1
+22 0 1
+37 16 19
+38 0 5
+54 0 1
+437 0 1
+539 2 0
+1067 0 1
+1042 1 0
+2434 10 0
+256 133 0
+839 0 1
+267 0 1
+640 1 1
+35 1 1
+1351 15 15
+1316 1 1
+31 0 1
+1986 5 5
+1179 0 1
+3153 1 0
+1165 0 1
+22 0 1
+56 1 1
+27 1 1
+77 0 1
+81 15 17
+111 1 1
+44 0 1
+2254 1 0
+320 1 0
+2368 0 1
+26 0 1
+407 5 6
+2982 0 4
+852 0 5
+703 1 0
+191 2 3
+73 5 5
+72
+
+chain 4901563 1_random 1663265 + 676697 728522 1 249250621 - 205721991 205773795 637
+1664 1 0
+299 1 0
+1113 4 0
+100 1 0
+1522 1 1
+46 1 1
+83 1 1
+30 1 1
+62 1 1
+46 1 1
+1990 1 1
+41 1 1
+1403 0 4
+1148 0 5
+10134 1 1
+21 1 1
+1479 1 0
+1499 9 9
+3057 0 2
+137 6 0
+1251 2 0
+21 1 1
+897 5 4
+2851 1 0
+399 0 2
+624 6 5
+440 1 0
+5 1 0
+2953 1 0
+480 9 0
+2793 36 35
+6791 1 0
+4870 1 0
+1478
+
+chain 4504833 1_random 1663265 + 1205412 1353281 1 249250621 - 133273039 133340206 679
+3980 0 1
+79 1 1
+34 1 1
+916 4 6
+1818 34 28
+51 21 16
+5 1 0
+5 1 0
+4 1 0
+11 1 0
+28 1 0
+8 1 0
+8 1 0
+1366 1 1
+38 0 1
+7507 0 1
+3084 2 0
+2569 1 0
+20 1 0
+8 1 0
+10 21 16
+51 10 10
+3979 6 5
+2086 1 0
+5466 0 1
+27 1 1
+1117 1 0
+66 1 0
+23 1 0
+2070 0 1
+67 1 0
+2611 1 0
+9 1 0
+23 23 18
+577 97925 17254
+5929 0 1
+1948 1 0
+72 0 1
+1365 60 62
+706
+
+chain 3984524 1_random 1663265 + 1620762 1663230 X 155270560 - 27920664 27963158 751
+107 0 1
+696 27 12
+658 0 12
+1440 0 2
+671 0 2
+506 0 3
+806 0 1
+4759 0 12
+131 1 0
+848 1 0
+213 0 8
+2046 1 0
+4979 0 1
+2482 1 0
+1502 1 0
+3474 0 4
+782 0 1
+12366 1 0
+3969
+
+chain 2698055 1_random 1663265 + 6164 122978 1 249250621 - 139553697 139584554 1020
+486 1 1
+19 9 9
+297 1 1
+73 1 1
+341 1 0
+105 1 0
+286 47997 0
+689 1 1
+48 1 1
+53 0 2
+1870 1 1
+39 1 1
+1682 0 39
+470 8 9
+691 1 0
+370 1 1
+24 1 1
+356 0 1
+1496 9599 84
+28 0 1
+7 4 0
+131 0 1
+66 932 181
+88 9 11
+10 7 0
+10 8 5
+5 0 3
+76 27759 26
+44 3 0
+26 0 2
+6 1 1
+59 3 1
+121 2 4
+4990 1 0
+672 0 1
+1487 1 1
+39 1 1
+1691 0 1
+36 10 10
+3503 1 1
+46 1 1
+4128 0 1
+1818 0 5
+1107 16 16
+841
+
+chain 2474973 1_random 1663265 + 1129393 1155387 1 249250621 + 229232478 229258468 1104
+3505 1 1
+44 1 1
+5232 4 0
+17207
+
+chain 2468882 1_random 1663265 + 1280682 1387454 1 249250621 - 133163307 133238928 735
+149 0 1
+7073 122 124
+1799 1 1
+43 1 1
+5594 24 23
+60 12182 28596
+3279 1 0
+571 21 21
+1080 1 0
+10 0 2
+1138 1 0
+3484 1 0
+1689 0 8
+810 42350 1
+1088 1 1
+21 1 0
+78 30 29
+746 0 2
+2729 1 0
+2088 0 3
+1949 966 174
+31 9 0
+12 16 16
+29 0 4
+13 100 98
+53 1884 0
+16 1 0
+5 0 1
+18 3916 1388
+1729 0 1
+1373 1 0
+102 1 0
+21 1 0
+4 1 0
+7 1 0
+38 2 0
+48 1 0
+525 5 4
+645 5 5
+1189 1 0
+1911 4 0
+69 8 8
+24 5 4
+284 1 0
+1481
+
+chain 2064841 1_random 1663265 + 247141 392880 1 249250621 - 247850669 247948213 608
+351 1 0
+965 0 1
+35 0 1
+248 0 1
+122 0 1
+1194 11 11
+580 3 5
+969 0 1
+425 5 5
+25 1 1
+586 1 1
+77 1 1
+1895 1 1
+37 1 2
+253 0 1
+560 1 1
+62 1 1
+74 1 1
+27 1 1
+90 31631 11346
+887 0 40
+759 32 0
+2596 0 1
+308 1 0
+37 0 1
+40 0 1
+346 17 19
+89 2 2
+34 1 2
+44 0 2
+35 0 1
+20 0 1
+260 0 1
+3009 1 1
+30 0 1
+5 10 12
+104 1 1
+48 0 1
+67 13 15
+1226 0 1
+111 7 7
+31 0 1
+47 1 3
+13 3 5
+38 7 10
+7 0 2
+48 0 1
+110 1 0
+623 0 2
+241 1 1
+47 1 1
+1601 0 1
+582 13 21
+1128 2 0
+348 4 4
+28 22 23
+481 0 2
+30 1 1
+628 0 1
+96 0 1
+30 0 1
+78 17 173
+64 55865 28961
+69 13 14
+498 0 1
+1593 0 4
+183 26 27
+337 1 0
+1433 0 1
+6191 0 2
+2435 0 1
+3451 540 0
+83 695 0
+1318 5 5
+21 1 1
+526 0 1
+833 0 1
+144 0 1
+427 8 8
+235 1 2
+297 1 1
+34 0 1
+250 0 3
+1007 0 1
+1403 1 1
+37 1 1
+355 1 1
+6 0 2
+94 1 1
+278 2 2
+5 0 1
+20 1 1
+667 24 24
+1858 10 12
+146 8 7
+2002 0 1
+284 0 1
+1233 0 1
+840 11 0
+914 2 0
+122 1 1
+26 0 2
+118
+
+chain 1850028 1_random 1663265 + 76914 101906 1 249250621 - 139621990 139717568 1363
+3916 0 1
+77 20 20
+26 0 856
+764 17 16
+12 1 0
+295 1 0
+2648 2870 23264
+250 997 50331
+2203 0 5
+797 1 0
+2197 1 1
+117 7 8
+429 1 0
+7345
+
+chain 1707631 1_random 1663265 + 501749 626697 1 249250621 + 144188000 145316961 852
+223 42 42
+236 22 22
+242 91 103
+199 8 8
+102 112 112
+50 126 126
+290 32 32
+213 45 45
+125 1 1
+56 1 1
+82 1 1
+27 13 13
+71 5 5
+493 3 3
+15 1 1
+248 1 1
+44 1 1
+65 1 1
+52 1 1
+169 1 1
+82 1 1
+292 1 1
+83 0 1580
+458 1 1
+16 1 1
+478 5 5
+568 23 17
+634 1 1
+46 1 1
+50 14 14
+864 31 61
+55 23320 364967
+85 1 1
+107 1 1
+376 1 1
+20 0 1
+195 10 10
+150 1 1
+35 1 1
+274 5 5
+143 1 0
+862 7 0
+20 1 0
+504 1 1
+25 1 1
+238 1 1
+36 1 1
+139 0 1
+25 1 1
+157 8 8
+60 16 16
+59 17 17
+285 0 1
+120 1 1
+69 1 1
+509 1 1
+59 1 1
+162 0 322
+70 5 5
+2169 1 1
+31 1 1
+224 1 1
+36 1 1
+76 1 0
+5 5 0
+109 6 6
+139 5 3
+65 0 20
+360 47 48
+86 18 17
+149 44 44
+76 54 55
+196 38 38
+139 139 6280
+107 1 1
+95 0 1
+46 1 1
+91 1 1
+18 1 1
+62 11 11
+511 0 1
+106 1 0
+505 0 2
+443 9 9
+519 112 112
+396 1 1
+26 1 1
+225 1 1
+57 1 1
+502 1 0
+485 1 1
+105 0 2
+146 1 1
+41 1 1
+203 1 1
+45 1 1
+62 5 5
+850 1 1
+55 2 2
+215 1 1
+45 1 1
+474 0 3
+19 1 1
+2337 1 1
+34 1 1
+148 1 0
+159 1 1
+32 1 1
+64 0 4
+849 1 1
+34 1 1
+126 38816 272842
+32 0 140
+3176 18 17
+6689 1 0
+274 0 1
+1449 0 1
+1312 1 0
+1861 8888 417910
+92 172 6531
+148 0 2
+213 1 1
+30 1 1
+227 1 1
+62 6 0
+276 1 1
+35 1 1
+94 14 14
+325 5 5
+118 1 1
+81 1 1
+234 4 0
+15 1 1
+243 1 1
+39 1 1
+117 1 1
+35 1 1
+83 1 1
+64 5 5
+55 13 13
+61 11 11
+175 1 1
+27 1 1
+134 1 1
+60 1 1
+64 1 1
+87 1 1
+615 1 1
+22 1 1
+201 5 5
+48 1 1
+117 1 1
+23 3 3
+319 6 6
+156 0 1
+25 1 1
+215 13 13
+97 14 14
+113 0 3
+35 1 1
+65 15 15
+480 0 1
+636 1 1
+107 1 1
+753 1 1
+43 1 1
+861 17 16
+470 1 1
+38 1 1
+579 1 1
+25 1 1
+224 1 1
+71 1 1
+266 36 36
+167 88 88
+400 53 53
+131 6 5
+220 22 19
+317 23 23
+109 95 101
+73 0 4726
+208 28 28
+293
+
+chain 1680348 1_random 1663265 + 1245440 1263421 1 249250621 + 116101959 116120000 1475
+441 0 14
+728 0 2
+1146 2 0
+1829 6 6
+93 3 2
+2916 0 6
+2013 0 47
+369 1 1
+27 9 0
+37 1 1
+200 1 0
+2285 0 2
+3527 1 1
+24 0 1
+1001 0 1
+1195 1 1
+39 1 1
+85
+
+chain 1335863 1_random 1663265 + 231796 246037 4 191154276 - 30408128 30422371 1784
+3391 6 6
+562 7 7
+5976 2 3
+4144 10 11
+143
+
+chain 1170727 1_random 1663265 + 577933 590476 1 249250621 + 144898104 144910646 2036
+1896 48 48
+2779 1 0
+7128 45 45
+646
+
+chain 1143882 1_random 1663265 + 1330802 1343100 1 249250621 - 133251270 133263558 2093
+1050 1 1
+51 1 1
+237 1 1
+35 1 1
+514 16 12
+76 9 1
+1642 12 12
+53 0 1
+3766 0 1
+40 1 1
+1513 0 1
+195 11 11
+135 26 26
+2627 1 0
+284
+
+chain 988809 1_random 1663265 + 564355 574807 1 249250621 - 104390169 104400621 2516
+59 1 2
+5994 1 1
+45 1 1
+3985 3 3
+42 1 0
+320
+
+chain 957971 1_random 1663265 + 256162 266426 1 249250621 + 1291904 1302191 2686
+83 0 1
+585 0 1
+1018 0 1
+18 1 1
+59 16 16
+1569 0 1
+69 1 0
+35 0 1
+36 1 1
+176 0 1
+48 0 1
+56 2 3
+41 0 1
+160 17 1
+461 13 21
+174 0 4
+517 7 7
+141 4 4
+89 0 1
+1155 1 0
+370 7 7
+143 1 0
+1019 22 22
+1177 0 1
+607 0 16
+86 0 3
+279
+
+chain 895962 1_random 1663265 + 196343 223209 1 249250621 - 247894293 247990621 2587
+108 25 24
+131 0 1
+299 0 1
+137 44 45
+51 0 1
+572 0 1
+406 36 37
+508 2162 63455
+80 5 8
+86 0 1
+61 0 1
+31 1 0
+165 14 15
+78 75 78
+234 0 1
+152 13 15
+849 0 1
+1798 12505 20653
+3495 0 1
+43 0 1
+1944 1 1
+26 1 1
+169 0 1
+365 0 1
+196
+
+chain 884318 1_random 1663265 + 4444 145186 1 249250621 + 109546538 109651856 1047
+123 47 1183
+818 1 1
+75 1 0
+22 1 1
+455 18927 20784
+855 1 0
+74 12001 11300
+2581 2 2
+31 0 1
+81 1 0
+24 1 1
+123 1 0
+147 0 1
+45 0 1
+26 0 1
+9 1 0
+12 2330 786
+22 41 53
+127 1706 714
+3729 74524 39329
+68 5 7
+3088 2 2
+15 5 6
+14 0 2
+657 1 1
+37 1 1
+2140 1 0
+3034 1 0
+42 1 1
+446 0 1
+55 2 2
+30 1 1
+391 1 1
+35 1 1
+982 3 0
+123 1 1
+28 0 4
+1503 1 0
+1159 0 3
+1464 0 1
+838 1 1
+47 1 3
+162 1 0
+139 1 1
+10 0 1
+2424 6 6
+448 1 0
+846 5 0
+1509
+
+chain 739113 1_random 1663265 + 68329 76740 1 249250621 + 109654512 109662863 6250
+254 1 0
+27 1 1
+746 1 0
+315 19 19
+163 42 2
+51 3 1
+44 1 1
+592 0 1
+216 1 1
+34 1 1
+2323 10 0
+10 236 236
+125 1 0
+806 213 213
+828 6 0
+82 6 6
+1253
+
+chain 688441 1_random 1663265 + 605533 614556 1 249250621 + 144612760 144812114 1498
+76 1 1
+70 1 1
+73 4 2
+40 0 2
+159 1 1
+56 2 0
+911 1 1
+63 1 1
+84 9 1
+149 1 1
+21 1 0
+606 1 1
+21 3 3
+132 12 10
+368 1 1
+26 1 1
+50 1 1
+65 1 1
+57 1 1
+44 1 1
+279 0 1
+34 0 4
+7 1 1
+308 0 32
+331 1 1
+84 1 1
+286 1 1
+35 1 1
+59 8 8
+146 1 1
+237 1 1
+52 1 1
+35 2 0
+40 1 1
+53 3 3
+103 1 1
+397 1 1
+59 1 0
+33 1 1
+587 11 11
+219 10 10
+71 5 5
+62 1 1
+38 1 1
+240 1 1
+70 1 1
+85 12 12
+86 413 190724
+207 1 0
+825 186 186
+172
+
+chain 590572 1_random 1663265 + 516651 523401 1 249250621 - 104651805 104658532 8996
+157 1 1
+17 1 1
+395 1 1
+65 1 1
+187 0 9
+21 1 1
+62 16 16
+110 2 0
+205 1 0
+43 1 1
+248 1 1
+59 4 2
+725 1 1
+49 1 1
+455 1 1
+106 1 1
+450 1 1
+133 0 2
+383 1 1
+37 1 1
+178 4 4
+70 1 1
+85 2 2
+43 1 1
+56 1 1
+22 24 0
+30 1 1
+64 1 1
+21 1 1
+198 1 1
+67 1 1
+58 1 0
+79 7 6
+74 1 1
+79 1 0
+26 1 1
+202 15 15
+352 2 2
+16 1 1
+51 22 19
+574 0 1
+87 1 1
+46 1 1
+88 1 1
+27 1 1
+120
+
+chain 526301 1_random 1663265 + 1264935 1361969 1 249250621 + 116056429 116101915 1232
+69 0 1
+30 1 1
+2663 2 0
+4185 1 0
+229 1 0
+25 1 1
+1104 1 0
+604 4 0
+1264 1 0
+2613 1 1
+21 1 0
+12 1 13
+2785 72844 21309
+397 19 2
+2203 1 1
+31 1 1
+658 1 1
+27 1 1
+923 9 9
+168 1 1
+46 0 2
+2502 43 43
+879 17 17
+644
+
+chain 506365 1_random 1663265 + 1399143 1404500 1 249250621 - 133194419 133199775 28136
+3175 1 0
+1447 0 1
+512 1 0
+221
+
+chain 482769 1_random 1663265 + 211415 216543 1 249250621 - 247889067 247894197 45886
+70 2 3
+905 2 3
+1091 1 1
+23 1 1
+302 15 14
+393 1 1
+24 1 1
+1961 0 1
+336
+
+chain 474976 1_random 1663265 + 1295676 1399043 1 249250621 + 115999419 116093083 1267
+571 10 10
+627 7 6
+46 1 1
+3095 0 1
+960 0 1
+608 11 10
+426 39 35
+2035 1 1
+23 1 1
+1866 17 18
+79 1 1
+1530 63368 32589
+866 110 110
+100 53 53
+1884 40 40
+3775 15606 36683
+2322 14 14
+145 49 49
+296 96 96
+297 0 2
+465 58 58
+262 22 22
+182 0 1
+638 1 0
+764
+
+chain 456897 1_random 1663265 + 1317 37745 1 249250621 + 109592282 109609521 6704
+1178 0 1
+16 1 0
+10 0 1
+4 1 1
+245 7763 188
+27 1 1
+1155 1 1
+91 4156 3450
+1810 51 51
+50 9 10
+567 3839 4491
+37 6346 0
+128 0 2
+29 50 48
+45 1519 155
+6 2 0
+9 10 6
+246 1806 0
+18 1 0
+5 2068 31
+2018 2 2
+20 3 3
+833 1 0
+101 1 0
+149
+
+chain 426748 1_random 1663265 + 63710 68210 1 249250621 - 139547929 139552428 99412
+1542 1 0
+2957
+
+chain 353264 1_random 1663265 + 462791 467071 1 249250621 + 144608404 144612698 156569
+71 50 50
+33 29 29
+226 10 10
+526 66 67
+55 50 50
+414 5 5
+57 46 58
+57 12 12
+254 1 1
+25 1 1
+52 13 13
+638 16 16
+579 1 1
+60 1 1
+178 1 1
+79 1 0
+35 0 3
+111 1 1
+43 1 1
+264 1 0
+119 1 1
+15 0 1
+76 1 0
+5
+
+chain 327229 1_random 1663265 + 1409275 1412904 1 249250621 + 115977641 115981270 200837
+2640 156 155
+473 0 1
+360
+
+chain 312923 1_random 1663265 + 1319916 1393318 1 249250621 + 115926067 115986980 1722
+1418 1 0
+1389 1 0
+1620 0 1
+374 1 0
+1361 0 1
+1994 1 0
+827 0 6
+1784 56909 44431
+253 1 0
+12 2 0
+8 24 14
+5344 2 0
+76
+
+chain 244562 1_random 1663265 + 478502 503782 1 249250621 - 100680024 100953393 1328
+106 13 13
+478 55 55
+310 1 1
+23 1 1
+376 1 1
+61 1 1
+1100 10 10
+810 5 0
+53 1 1
+119 1 1
+44 1 0
+94 100 32051
+60 5 5
+744 1 1
+87 1 1
+44 2 0
+53 11 5
+584 2 2
+30 0 17
+73 1 1
+49 1 1
+456 8 8
+796 19 19
+166 1 1
+42 1 1
+105 1 1
+38 1 1
+55 1 1
+80 1 1
+293 2 2
+19 1 1
+550 5637 9366
+68 24 22
+103 1 1
+35 0 1
+102 1 1
+39 6 0
+388 9 9
+21 1 1
+338 27 27
+500 4 0
+117 5 5
+271 1 1
+38 1 1
+273 3 3
+16 3 3
+80 1 1
+63 1 1
+130 1 1
+18 1 1
+204 1 1
+45 1 1
+141 1 1
+112 1 1
+75 1 0
+75 4 4
+83 2 0
+854 5 5
+104 0 4
+12 1 1
+351 1 1
+40 1 1
+102 4779 217183
+40 502 502
+31 0 12
+58 311 311
+110 52 52
+78 1 1
+46 535 535
+45
+
+chain 239113 1_random 1663265 + 455713 471283 1 249250621 + 144877306 144889304 5703
+73 1 0
+944 0 1
+2741 1 1
+77 1770 1206
+12 1449 338
+10 71 1301
+14 10 145
+26 4281 1018
+2672 0 1
+1418
+
+chain 228041 1_random 1663265 + 450807 453388 GL000192.1 547496 + 525635 528523 474030
+521 25 26
+256 4 316
+195 1 0
+183 4 0
+249 48 48
+915 19 18
+161
+
+chain 219405 1_random 1663265 + 8071 23476 1 249250621 + 109602419 109665881 23204
+1669 2217 48069
+1950 5 1
+213 6609 8813
+681 1 0
+580 0 1
+296 37 38
+248 0 4
+301 31 31
+143 38 38
+386
+
+chain 219231 1_random 1663265 + 32127 34517 1 249250621 - 139682423 139684814 491274
+85 27 27
+14 0 1
+204 5 5
+63 24 24
+1968
+
+chain 210320 1_random 1663265 + 459650 474308 GL000192.1 547496 + 522489 531711 22108
+267 0 10
+1175 5 1
+48 0 2
+16 3 3
+119 0 12
+37 12 12
+1340 8711 3256
+34 0 2
+58 1 0
+38 1 0
+351 5 5
+486 17 15
+158 81 81
+76 1 1
+36 1 1
+69 12 13
+1500
+
+chain 207966 1_random 1663265 + 29704 55292 1 249250621 + 109529352 109557857 7568
+742 273 273
+560 0 1
+232 17541 20458
+729 2 2
+97 3 3
+89 1 1
+68 0 1
+28 1 1
+2575 2 0
+59 1 1
+2585
+
+chain 202325 1_random 1663265 + 27243 45056 1 249250621 - 139669260 139678536 8944
+1432 157 157
+50 45 45
+677 2608 49
+27 8791 867
+266 9 9
+169 1 1
+62 1 1
+67 7 5
+28 1 1
+1619 22 22
+41 127 127
+21 1 1
+40 2 1
+32 1 1
+362 0 1949
+1147
+
+chain 199687 1_random 1663265 + 18553 20627 1 249250621 + 109595202 109597276 600797
+2074
+
+chain 171508 1_random 1663265 + 447628 491985 1 249250621 + 148535207 148566609 6481
+121 14 14
+517 0 4
+507 1 0
+74 1 1
+41 0 1
+61 4541 11291
+1073 1 0
+718 70 44
+66 31371 11607
+690 1 1
+115 1 1
+61 1 1
+70 1 1
+57 0 4
+54 1 1
+41 2 6
+28 5 77
+73 1 1
+34 5 5
+887 1 0
+427 1 1
+7 0 5
+40 1 1
+59 1 1
+47 1 1
+121 9 9
+57 2 0
+362 1 1
+48 4 4
+429 1 1
+28 1 1
+160 1 1
+92 5 0
+15 0 5
+15 1 1
+139 5 5
+37 1 1
+87 1 1
+40 1 1
+253 1 1
+35 1 1
+197 1 1
+69 1 1
+114 1 1
+79 1 1
+51
+
+chain 170629 1_random 1663265 + 474420 479154 1 249250621 - 104365477 104643040 2652
+3982 697 273526
+55
+
+chain 143194 1_random 1663265 + 449166 450695 1 249250621 - 104373413 104374943 899312
+167 0 1
+362 11 11
+989
+
+chain 141808 1_random 1663265 + 195186 230464 1 249250621 + 1361949 1390000 8100
+66 0 1
+865 27548 20313
+75 1 1
+163 2 2
+2267 0 2
+1549 0 2
+37 1 1
+597 1 1
+28 1 1
+269 14 19
+59 1 1
+20 1 1
+734 2 0
+977
+
+chain 137395 1_random 1663265 + 446016 447466 1 249250621 + 144922370 144923820 937713
+1450
+
+chain 120082 1_random 1663265 + 1413004 1414278 1 249250621 + 115908963 115910237 1071399
+1274
+
+chain 110577 1_random 1663265 + 0 1193 5 180915260 + 33390295 33391489 1161255
+153 0 1
+942 4 4
+94
+
+chain 101176 1_random 1663265 + 442945 444014 1 249250621 - 104338746 104339815 1265508
+1069
+
+chain 61431 1_random 1663265 + 9891 10535 1 249250621 + 109697165 109697809 2020878
+644
+
+chain 48091 1_random 1663265 + 497444 501649 1 249250621 + 144842054 144846259 8551
+4205
+
+chain 31572 1_random 1663265 + 576223 577747 4 191154276 + 100714665 100716180 4375428
+114 20 20
+105 460 462
+56 375 378
+65 263 249
+66
+
+chain 28915 1_random 1663265 + 230464 231387 1 249250621 + 1420670 1421247 4712368
+191 574 228
+67 38 38
+53
+
+chain 27385 1_random 1663265 + 205390 205833 1 249250621 - 247799065 247799507 5896168
+141 86 86
+106 47 46
+63
+
+chain 25670 1_random 1663265 + 87811 88395 7 159138663 - 51241913 51242744 3648322
+121 405 652
+58
+
+chain 21035 1_random 1663265 + 376636 377171 1 249250621 - 247932544 247932844 3872256
+107 118 0
+61 93 15
+49 39 0
+68
+
+chain 18694 1_random 1663265 + 540390 626404 1 249250621 + 148529505 148589817 1111
+44 254 254
+43 76 73
+54 196 196
+37 240 6477
+31 4 4
+4 2528 2531
+8 1 1
+42 1 1
+60 70185 38258
+94 10137 10136
+31 1 1
+3 167 167
+88 400 400
+52 829 828
+33 10 0
+52 281 281
+28
+
+chain 18305 1_random 1663265 + 612752 613165 1 249250621 + 146400208 146400621 434456
+18 31 31
+215 97 97
+52
+
+chain 18205 1_random 1663265 + 210123 210768 1 249250621 + 1400633 1401273 11939617
+55 410 403
+82 10 12
+88
+
+chain 16211 1_random 1663265 + 84691 84862 5 180915260 + 68593902 68594073 10696361
+171
+
+chain 14543 1_random 1663265 + 375983 376437 1 249250621 - 247932585 247932921 12601411
+13 231 153
+56 101 61
+53
+
+chain 11766 1_random 1663265 + 209234 209374 6 171115067 + 48765751 48765891 19406706
+84 4 4
+52
+
+chain 10899 1_random 1663265 + 1264583 1264729 4 191154276 - 96228610 96228756 20935897
+69 19 19
+58
+
+chain 9779 1_random 1663265 + 575439 575892 5 180915260 - 127861600 127862049 19918678
+60 389 385
+4
+
+chain 9449 1_random 1663265 + 206282 206576 1 249250621 - 247814999 247815293 24134146
+64 179 179
+51
+
+chain 9080 1_random 1663265 + 376922 377270 1 249250621 - 247932789 247932982 12922008
+42 39 0
+12 156 79
+8 39 0
+52
+
+chain 7488 1_random 1663265 + 375996 376227 1 249250621 - 247932827 247932944 24096271
+39 178 64
+14
+
+chain 7272 1_random 1663265 + 492183 493450 GL000192.1 547496 + 517200 518462 5534
+104 1136 1131
+27
+
+chain 7258 1_random 1663265 + 576783 577499 14 107349540 - 76512188 76512903 4928952
+56 262 262
+101 216 215
+81
+
+chain 7167 1_random 1663265 + 376446 376521 1 249250621 - 247932507 247932582 27908410
+75
+
+chain 6857 1_random 1663265 + 87342 87413 4 191154276 - 48731804 48731875 28524152
+71
+
+chain 6426 1_random 1663265 + 508964 509092 1 249250621 + 144828390 144828518 146082
+13 51 51
+64
+
+chain 6204 1_random 1663265 + 211009 211075 1 249250621 + 1467491 1467557 30075428
+66
+
+chain 6008 1_random 1663265 + 376783 376999 1 249250621 - 247932727 247932982 14593768
+49 132 171
+35
+
+chain 5855 1_random 1663265 + 576112 576191 20 63025520 + 560198 560277 14627950
+79
+
+chain 5539 1_random 1663265 + 247082 247140 16 90354753 - 36623787 36623845 31913042
+58
+
+chain 5517 1_random 1663265 + 575499 575571 1 249250621 - 135388947 135389019 22575370
+19 14 14
+39
+
+chain 5153 1_random 1663265 + 463736 463802 1 249250621 - 100897669 100897735 496173
+66
+
+chain 4331 1_random 1663265 + 576997 577043 4 191154276 + 125192159 125192205 31588172
+46
+
+chain 4269 1_random 1663265 + 508977 509028 1 249250621 - 101245694 101245744 11082093
+11 1 0
+24 1 1
+14
+
+chain 3392 1_random 1663265 + 1264741 1264777 1 249250621 + 103601716 103601752 22855599
+36
+
+chain 2584 1_random 1663265 + 472532 472613 1 249250621 - 104701386 104701467 60543
+81
+
+chain 2530 1_random 1663265 + 576576 576677 2 243199373 + 18874674 18874775 4960893
+101
+
+chain 2443 1_random 1663265 + 508878 508906 1 249250621 + 145358788 145358816 8460
+28
+
+chain 2298 1_random 1663265 + 376035 376059 1 249250621 - 247932520 247932544 25650669
+24
+
+chain 2200 1_random 1663265 + 377179 377218 1 249250621 - 247932814 247932853 18046603
+39
+
+chain 2078 1_random 1663265 + 576191 576213 2 243199373 - 87184513 87184535 19810119
+22
+
+chain 1902 1_random 1663265 + 462945 462974 1 249250621 + 146388727 146388756 1440299
+29
+
+chain 1597 1_random 1663265 + 87932 87955 1 249250621 + 203810737 203810760 8954286
+23
+
+chain 1582 1_random 1663265 + 576728 576783 12 133851895 + 80469819 80469874 8882774
+55
+
+chain 1575 1_random 1663265 + 377270 377295 1 249250621 - 247932789 247932814 25950613
+25
+
+chain 1557 1_random 1663265 + 376743 376767 1 249250621 - 247932958 247932982 25686497
+24
+
+chain 1423 1_random 1663265 + 577528 577578 3 198022430 + 24122600 24122650 5633229
+50
+
+chain 1401 1_random 1663265 + 208964 209027 19 59128983 + 53692979 53693042 24768107
+63
+
+chain 1269 1_random 1663265 + 577058 577101 X 155270560 - 54470903 54470946 5438939
+43
+
+chain 1137 1_random 1663265 + 88481 88531 X 155270560 - 107394638 107394688 10193603
+50
+
+chain 1096 1_random 1663265 + 88429 88481 1 249250621 - 213837318 213837370 14790649
+52
+
+chain 963 1_random 1663265 + 575892 575970 1 249250621 - 198864223 198864301 11419759
+78
+
+chain 917 1_random 1663265 + 455298 455327 GL000192.1 547496 - 58673 58702 411262
+29
+
+chain 870 1_random 1663265 + 577218 577269 6 171115067 - 89553434 89553485 24911812
+51
+
+chain 794 1_random 1663265 + 88312 88337 4 191154276 + 171087862 171087887 6635553
+25
+
+chain 649 1_random 1663265 + 576545 576576 15 102531392 - 5321440 5321471 7251364
+31
+
+chain 622 1_random 1663265 + 576462 576495 11 135006516 + 114505284 114505317 6564387
+33
+
+chain 546 1_random 1663265 + 88531 88556 6 171115067 + 144792007 144792032 10415340
+25
+
+chain 398 1_random 1663265 + 575763 575814 14 107349540 + 34662629 34662680 24063646
+51
+
+chain 22466167312 2 242951149 + 0 242751149 2 243199373 + 10000 243102476 1
+1201236 1 0
+2057 1 1
+26 1 1
+4043 0 22
+82 101 7
+33 0 74
+36 13 1
+67 0 48
+152 0 418
+50 2 0
+6 6 0
+76 74 0
+20 6 0
+22 118 0
+374 0 2446
+836 0 2310
+21 0 2444
+21507 1 1
+50 0 4
+2041 4 0
+9052 0 2
+81 8 0
+10 42 0
+1078 1 0
+4122 0 1
+1608 1 28
+4029 9 0
+967 1000 4547
+414 0 27
+2237132 1 0
+2458 17 17
+3915 47 47
+633 0 4
+3531 14 14
+3954 50000 51129
+1426129 100025 160449
+11087286 3 0
+773 50000 103977
+1576 1 0
+240 1 0
+318 0 2
+258 16 0
+2848 10 10
+1404 1 1
+27 1 1
+703 0 13
+375 1 0
+4783388 25000 35000
+848 2 0
+1225 2 0
+391 0 1
+3445 24 24
+184 1 1
+28 1 1
+49 4 0
+4514 9 0
+9628 9 1
+1483 7 7
+1990 1 0
+1949 0 1
+2716230 0 1
+46732767 9 5
+9477928 3 0
+7520813 0 72396
+1900436 150000 294073
+17672 0 1
+5792 0 1
+9019 266 0
+2942 1 0
+9388 0 2
+37826 0 4
+23440 4 0
+290929 1000000 1273578
+731068 3000000 3000000
+2558421 1 0
+1196 0 10
+686 1 0
+26 3 0
+15 1 1
+2309 1 0
+1332 23 22
+344 1 0
+1645 4 4
+6564 0 1
+6329 0 1
+769 1 0
+873 0 7
+1299 1 0
+8250 15 15
+4291 12548 10626
+1054 0 103
+84 218 0
+5897 1 1
+33 1 1
+9905 37 51
+1645 113 113
+1597 4 4
+61 1 1
+866 0 13
+2830 0 3
+2819 2 0
+156 436 88
+100 54 0
+4753 8 0
+4903 6 6
+3847 2 0
+108126 145 0
+3542 0 1
+10276 1 0
+402 1 1
+47 1 1
+63 0 2
+583 1 1
+34 1 1
+8975 46 0
+378 1 1
+70 1 1
+2476 102 0
+1754 1 0
+8426 1 0
+11986570 142000 151150
+14207 1 1
+49 1 1
+1784 12 0
+406 0 1
+1874 1 1
+33 1 1
+4795 0 2
+3686 1 1
+15 1 1
+164 0 2
+7287 5 5
+702023 150000 72796
+69 0 1
+1598 1 0
+1340 1 0
+1030 4 0
+1166 10 10
+629 27 27
+5750 1 1
+34 1 1
+3283 4 2
+496 21 1
+25 1 9
+41 1 1
+329 4 4
+9955 41 41
+10953 1 2
+1417 44 0
+911 0 17
+18270 0 1
+178429 281526 0
+34455 406 0
+58863 2 1
+1843 2 0
+14994 1 0
+12992 0 2
+2571146 0 1
+35688061 100000 108224
+29671719 0 1
+39665349 0 1
+14876089 20000 64197
+401 3 0
+1831 1 1
+61 1 1
+654 1 11
+138 28 0
+105 1 1
+25 4 0
+73 9 9
+3247 0 2
+1355 0 1
+816 21 25
+526 1 1
+60 1 1
+773 0 1
+1494 0 1
+448 44 44
+1191 0 1
+21 1 1
+596 0 1
+1582 0 1
+425 3 0
+1141 8 0
+136 744 80
+18 1 0
+4 1 0
+8 4 2
+32 1 0
+71 0 1
+385747 1 1
+110 1 1
+51 7 7
+54 15205 15205
+54 7 7
+51 1 1
+110 1 1
+5198249 1 0
+108 0 40
+65 0 80
+100 2 82
+442 1 1
+35 1 1
+119 129 9
+33 40 0
+42 1 1
+86 40 0
+1330 1 0
+1194 2 0
+11 1 1
+1773 5 0
+1623 1 1
+25 1 1
+2422 1 1
+20 1 0
+2315 1 0
+31 1 1
+1508 3 0
+50 4 0
+970 6 6
+7234 0 4
+1228 0 1
+1233 1 8
+744 16 16
+3447 1 1
+41 1 1
+3297 2 0
+1714 0 2
+2299 0 2
+2143 1 1
+18 1 1
+917 0 1
+1082 1 1
+49 1 1
+9098 4 0
+5529 1 0
+3266 8 0
+894 0 6
+3536 0 2
+4179 13 18
+1785 1 0
+1675 6 0
+1216 33000 32348
+287 109 573
+12548 30000 30000
+952154 25000 41011
+1914 0 1
+225 1 1
+57 1 1
+2910 1 0
+471 0 1
+1956 1 1
+43 1 1
+1000 92 0
+2854 0 3
+1837 0 306
+1007 0 30
+206 35 32
+217 17 17
+1525 0 8
+413 1 1
+32 2 2
+1573 12 12
+2258676
+
+chain 1437141 2 242951149 + 234136066 234151271 2 243199373 - 8712841 8728046 1459
+15205
+
+chain 1229376 2 242951149 + 110524471 111016063 2 243199373 - 132402743 134718956 53
+41 12371 12350
+33 0 23
+11 197610 197512
+5295 5 5
+190 69 19
+2195 1 0
+285 34 34
+1682 1 0
+182 11 6
+291 0 1
+1506 15 16
+146 5 5
+2050 51 51
+186 8 7
+68 7 6
+41 1 0
+306 0 1
+1545 1 0
+1334 25 24
+543 0 2
+224 17 21
+615 1 0
+208 2 0
+158 27 21
+3320 0 1
+576 0 2
+4562 0 6
+1023 0 1
+977 0 1
+3904 1 0
+827 415 28
+1508 14 13
+9571 36 36
+1393 1 1
+42 1 1
+2205 0 2
+5258 36 0
+42 2 0
+4437 2 0
+3357 1 0
+6289 0 9
+1996 1 0
+3228 0 1
+202 0 1
+2743 7 0
+24 0 5
+549 3 1
+942 0 6
+1815 8 0
+874 0 3
+4737 0 2
+852 14 18
+518 14 14
+4377 1 1
+49 1 1
+3270 1 0
+753 0 4
+240 1 0
+2391 0 1
+4745 4 0
+5752 0 2
+880 0 1
+397 1 0
+1407 0 3
+120 1 1
+89 1 1
+7011 3 0
+188 8 8
+834 5 0
+94 18 18
+3711 150112 1975291
+345 52 52
+100 8 8
+52 6 6
+650 6 6
+273 91 95
+88 90 90
+331 116 116
+66 35 35
+145 13 15
+95 6 6
+301 43 47
+444 12 12
+645 116 119
+215 31 31
+748 58 57
+212 71 71
+420 38 38
+190 4 4
+51 32 32
+65 32 32
+182 69 69
+161 17 17
+74 36 36
+170 25 25
+124 19 15
+230
+
+chain 33206 2 242951149 + 111008548 111015495 2 243199373 + 113147044 113153995 310
+112 345 345
+52 1095 1095
+15 0 4
+76 88 88
+90 331 331
+116 66 66
+35 560 560
+43 1101 1101
+116 215 215
+31 748 748
+58 212 212
+71 420 420
+38 245 245
+32 65 65
+32 182 182
+69 252 252
+36
+
+chain 15095 2 242951149 + 97284299 97473552 2 243199373 - 145080546 145267103 122
+48 13638 11732
+218 15837 15837
+37 1645 1645
+113 8336 8336
+436 100 100
+54 121645 121635
+3 25 0
+101 26915 26159
+9 0 1
+93
+
+chain 10366 2 242951149 + 110742577 110753868 2 243199373 + 113162562 113173850 1257
+34 5889 5884
+51 5290 5292
+27
+
+chain 3994 2 242951149 + 111050518 111050561 2 243199373 - 132647167 132647210 483
+43
+
+chain 3626 2 242951149 + 1208025 1208063 2 243199373 + 1217618 1217656 30090800
+38
+
+chain 3098 2 242951149 + 110780566 110780602 2 243199373 + 100698198 100698234 394442
+36
+
+chain 2548 2 242951149 + 89594034 89594300 2 243199373 - 153635204 153635700 103
+90 9 107
+22 9 0
+32 3 0
+5 0 125
+21 15 30
+5 1 0
+25 0 5
+29
+
+chain 2507 2 242951149 + 1207989 1208025 2 243199373 + 1217656 1217692 7254147
+36
+
+chain 2306 2 242951149 + 97446409 97446434 2 243199373 + 98080299 98080324 1844703
+25
+
+chain 5644665978 20 62435964 + 8000 62435964 20 63025520 + 60000 62965520 20
+26259569 1765661 3100000
+234339 1000000 150000
+4004088 0 1
+6459 0 244
+37810 0 2
+1044573 20000 50000
+9411883 2 8
+362 0 1
+11607353 0 1
+1301304 1 0
+31033 0 9
+1154 0 2
+1088 1 1
+29 1 1
+2509 0 2
+407 1 0
+40 1 1
+3787164 27050 50000
+71932 110000 50000
+694117 0 1
+1008033
+
+chain 3228730713 21 46944323 + 9719767 46944323 21 48129895 + 10697896 48119895 23
+490233 3050000 3150000
+19828060 0 1
+8789369 1199 50000
+243783 1500 1500
+1381822 1359 50000
+3437231
+
+chain 42537850 21_random 1679693 + 281005 1255172 21 48129895 + 9411193 10647896 88
+184355 50000 489372
+131056 458754 281918
+150002
+
+chain 21600281 21_random 1679693 + 876305 1679693 21 48129895 - 37585054 38304458 99
+178865 280890 346005
+315 2 2
+38 1 1
+261 1 1
+24 1 1
+157 0 325
+16 1 1
+85 1 1
+66 1 1
+330 11 11
+235 1 1
+51 1 1
+405 1 1
+26 1 1
+130 5 5
+80 1 1
+91 1 1
+20 1 1
+244 0 1
+478 1 1
+5 1 0
+13 0 1
+49 1 1
+197 10 10
+158 1 1
+57 0 1
+829 1 1
+60 1 1
+51 0 1
+584 1 0
+21 2 0
+151 20 20
+316 1 1
+16 1 1
+100 7 7
+102 1 1
+49 1 1
+125 1 0
+102 13 13
+153 20 20
+199 1 0
+35 1 1
+367 1 1
+51 1 1
+344 1 1
+101 1 1
+243 1 1
+27 1 1
+338 0 4
+166 15 15
+73 1 1
+44 1 1
+282 4 4
+67 1 1
+54 1 1
+216 1 1
+48 1 1
+76 1 1
+70 1 1
+392 1 1
+44 1 1
+65 8 9
+362 0 4
+34 1 1
+68 1 1
+57 1 0
+120 1 1
+374 1 1
+21 1 1
+121 1 1
+34 1 1
+80 1 0
+64 2 0
+162 8 8
+184 1 1
+34 1 1
+658 2 2
+52 0 4
+297 1 0
+136 1 1
+20 1 1
+905 0 1
+250 7 8
+138 0 3
+104 1 0
+42 1 1
+539 0 1
+43 4 0
+633 0 20
+353 17 17
+969 4 0
+39 3 3
+210 3 1
+188 7 7
+459 2 2
+25 1 1
+207 1 1
+55 1 1
+375 1 1
+66 1 1
+599 0 2
+395 1 1
+33 1 1
+73 1 1
+35 2 0
+275 9999 10000
+353 1 1
+26 1 1
+423 1 1
+32 1 1
+86 7 7
+197 1 1
+44 1 1
+96 1 1
+77 7 0
+247 0 2
+77 1 1
+425 13 1
+32 1 1
+65 1 1
+217 3 2
+115 1 1
+33 1 1
+268 1 0
+959 1 1
+63 1 1
+93 5 5
+185 1 1
+31 1 1
+944 12 12
+413 1 1
+92 1 1
+276 1 1
+35 1 1
+500 1 1
+31 149436 9
+158069
+
+chain 14432948 21_random 1679693 + 78709 231005 21 48129895 + 9882623 10034920 205
+77296 0 1
+75000
+
+chain 7807601 21_random 1679693 + 1362161 1471624 1 249250621 - 105758025 105867745 293
+77 11427 11419
+174 5 5
+857 64 64
+2170 0 2
+621 1 1
+26 1 1
+4365 0 1
+155 0 1
+452 0 4
+941 0 4
+403 1 1
+45 1 1
+534 86 86
+2198 0 1
+303 2 0
+5470 6 6
+845 1 1
+45 1 1
+221 6 0
+321 1 1
+44 1 1
+354 1 0
+374 131 130
+577 6 5
+263 17 16
+207 0 2
+1746 14 14
+3223 1 1
+46 4 4
+1479 1 1
+46 1 1
+383 0 3
+44 1 1
+2724 67 67
+47 145 145
+350 116 116
+138 0 1
+1 65 65
+796 17 17
+645 1 0
+24 1 1
+1318 1 0
+687 1 1
+41 1 1
+2292 1 1
+37 1 1
+589 1 1
+37 1 0
+670 13 13
+357 4 0
+2667 3 0
+1941 1 1
+31 1 1
+1538 54 54
+64 166 166
+120 226 226
+46 14 0
+14 155 155
+92 54 54
+26 55 55
+98 131 131
+36 1 1
+76 391 391
+44 294 294
+37 813 813
+35 219 219
+898 1 1
+19 1 1
+213 12 12
+1926 1 1
+21 1 1
+4561 1 1
+28 1 1
+8361 1 1
+43 1 1
+429 211 492
+3095 0 1
+3873 1 1
+43 5 5
+3785 171 171
+65 122 122
+70 116 116
+29 459 459
+36 352 352
+39 93 93
+39 190 190
+41 1783 1784
+35 509 509
+27 394 394
+57 834 834
+58 10 10
+17 758 760
+41 0 4
+82 194 194
+60 543 543
+31 58 58
+46 607 607
+34 98 98
+31 1 1
+38 563 562
+135 1980 1976
+48 370 370
+42 515 515
+49 456 456
+3137 0 1
+2483 1 0
+357 1 1
+49 1 1
+1181 1 0
+885 1 0
+86
+
+chain 3630496 21_random 1679693 + 696416 1463441 21 48129895 + 9645548 10215976 235
+129889 481231 310631
+225 46 51
+383 6 6
+73 18 18
+200 18 39
+236 63 68
+123 340 365
+57 300 259
+51 138 138
+71 55 55
+60 152 152
+51 100 103
+61 358 357
+85 1906 236
+88 157 153
+56 39 39
+73 20146 20047
+67 1 0
+57 154 154
+59 940 953
+61 205 205
+60 46 46
+122 149 149
+53 64 56
+210 16 16
+209 1 0
+214 29 29
+71 69616 76139
+67 47 47
+145 350 354
+116 139 135
+65 13718 10425
+54 64 64
+166 120 120
+225 75 75
+74 14 13
+67 92 92
+54 26 26
+55 98 98
+127 117 117
+173 16 15
+202 44 44
+198 21 17
+75 37 37
+442 18 18
+353 35 35
+219 27532 0
+105 0 3
+66 65 65
+122 70 70
+116 29 29
+459 36 36
+278 17 17
+57 39 40
+93 39 39
+190 41 41
+285 16 20
+859 22 37
+176 4 4
+183 32 32
+206 35 36
+509 27 27
+394 57 56
+116 5 5
+596 1 0
+116 85 85
+54 0 1
+119 0 2
+585 124 127
+74 10 11
+109 60 60
+82 22 22
+439 31 31
+58 46 46
+106 21 22
+186 15 14
+279 34 34
+98 70 67
+166 1 0
+396 135 135
+1551 12 12
+90 0 3
+69 4 4
+48 3 0
+203 48 48
+370 42 42
+139 14 53
+362 49 49
+456
+
+chain 2630212 21_random 1679693 + 936 28709 21 48129895 + 44682664 44710462 1048
+3985 6 7
+8941 0 30
+3327 1 1
+74 1 1
+859 22 22
+89 70 70
+489 14 3
+11 2 1
+10 10 0
+10 0 1
+31 1 27
+556 3 0
+128 0 1
+358 1 1
+45 1 1
+1712 8 0
+6545 32 31
+431
+
+chain 517534 21_random 1679693 + 1332563 1373665 GL000194.1 191469 - 21469 62943 261
+130 2 2
+53 1 1
+139 1 1
+60 1 1
+321 125 125
+72 1 1
+81 59 59
+248 22 23
+250 13 13
+407 61 61
+205 60 60
+46 122 122
+149 53 53
+14 0 8
+50 650 650
+29 19697 20073
+100 1 4
+106 2 2
+158 1 1
+89 1 1
+10 1 1
+65 1 1
+48 1 1
+156 1 1
+61 1 1
+156 1 1
+81 1 1
+522 16 16
+377 22 22
+358 1 1
+17 1 1
+141 1 0
+29 0 1
+16 1 1
+105 1 1
+49 2 1
+63 1 1
+32 1 0
+7 1 1
+349 1 2
+102 1 1
+146 1 0
+93 3 0
+149 1 1
+86 1 1
+220 1 1
+111 1 1
+195 19 19
+108 1 1
+79 6 1
+98 0 1
+29 2 2
+98 1 1
+125 1 1
+196 1 1
+52 1 1
+767 1 1
+68 3 3
+70 1 1
+66 1 1
+331 1 1
+22 1 1
+60 77 77
+437 1 1
+61 1 1
+134 1 1
+48 4 2
+26 0 2
+79 1 1
+16 1 1
+77 1 1
+24 1 1
+176 1 1
+33 1 1
+61 0 4
+141 1 1
+17 1 1
+232 1 1
+42 1 1
+439 2 1
+31 1 1
+55 1 0
+181 1 1
+77 4 4
+145 4 5
+22 1 1
+159 1 6
+53 1 1
+63 1 1
+67 6 6
+71 1 1
+25 1 1
+103 6 6
+303 6513 6492
+211 1 1
+87 1 1
+170 2 2
+36 0 6
+361 1 1
+58 1 1
+292 10 10
+201 1 1
+35
+
+chain 353583 21_random 1679693 + 1323386 1332563 GL000218.1 161147 - 0 9198 304
+693 1 1
+28 4 0
+425 51 51
+874 2 4
+421 1 1
+23 1 1
+299 2 1
+20 3 3
+88 1 1
+35 1 1
+283 4 4
+42 4 4
+719 14 14
+181 1 1
+41 1 1
+1010 1 1
+59 1 1
+478 1 1
+45 1 0
+78 1 1
+315 1 1
+22 1 1
+342 1 1
+27 1 1
+716 0 25
+83 1 1
+44 1 1
+218 6 6
+142 1 1
+178 1 1
+220 1 1
+35 1 1
+55 1 1
+44 1 1
+143 1 1
+80 1 1
+85 1 1
+46 1 1
+169 1 1
+56 1 1
+94 1 1
+51 1 1
+48
+
+chain 153763 21_random 1679693 + 1307498 1317523 1 249250621 + 142541121 142549427 248494
+38 225 225
+46 934 934
+63 240 230
+50 653 627
+57 559 562
+4 186 183
+51 101 101
+16 235 235
+70 1848 174
+58 193 194
+3 255 257
+97 40 40
+164 35 35
+167 27 27
+82 213 218
+106 172 171
+55 274 274
+125 214 209
+158 123 124
+94 169 169
+69 430 425
+66 871 864
+95 213 213
+81
+
+chain 88175 21_random 1679693 + 0 28278 GL000210.1 27682 - 0 27251 1050
+107 675 0
+154 27310 26958
+32
+
+chain 46308 21_random 1679693 + 1305249 1307368 21 48129895 - 38147885 38150014 728191
+46 171 171
+69 165 166
+32 292 292
+34 184 184
+26 73 73
+23 117 117
+57 54 54
+7 16 25
+68 78 78
+23 242 242
+53 230 230
+59
+
+chain 40072 21_random 1679693 + 1311066 1311528 3 198022430 + 38430454 38430916 3283349
+95 1 1
+47 1 1
+177 1 1
+41 1 1
+98
+
+chain 25551 21_random 1679693 + 1316263 1317134 21 48129895 + 10022171 10023044 3443865
+97 94 94
+87 148 147
+94 340 343
+11
+
+chain 20886 21_random 1679693 + 1305172 1307309 Y 59373566 - 45989384 45991522 2022
+77 46 46
+64 50 50
+57 69 70
+165 32 32
+86 11 11
+195 34 34
+184 122 122
+117 57 57
+54 91 91
+50 51 51
+242 61 61
+68 9 9
+145
+
+chain 10360 21_random 1679693 + 1384481 1394861 21 48129895 - 38158677 38169079 831
+56 10224 10246
+100
+
+chain 9106 21_random 1679693 + 1316541 1317639 2 243199373 + 56015784 56016880 4408555
+45 37 37
+66 97 95
+66 672 672
+115
+
+chain 7814 21_random 1679693 + 1312477 1312593 8 146364022 + 34952530 34952621 21041862
+26 37 12
+53
+
+chain 6987 21_random 1679693 + 1305359 1306761 1 249250621 - 105769657 105771059 738748
+38 5 5
+7 1324 1324
+28
+
+chain 3478 21_random 1679693 + 1309705 1309742 X 155270560 - 92499801 92499838 30075241
+37
+
+chain 2939 21_random 1679693 + 1312274 1312311 1 249250621 - 217601682 217601719 16037052
+37
+
+chain 2906 21_random 1679693 + 1394861 1394892 GL000247.1 36422 - 2105 2136 848
+31
+
+chain 2805 21_random 1679693 + 1309675 1309705 4 191154276 - 16268024 16268054 28769751
+30
+
+chain 2788 21_random 1679693 + 1374701 1374765 GL000194.1 191469 - 63980 64044 1175
+9 36 36
+19
+
+chain 2571 21_random 1679693 + 1317411 1317442 20 63025520 - 39738360 39738391 24462467
+31
+
+chain 2324 21_random 1679693 + 1311588 1311646 2 243199373 + 3637936 3637994 8156424
+58
+
+chain 1980 21_random 1679693 + 1440240 1440313 1 249250621 + 142677559 142677632 922
+73
+
+chain 1679 21_random 1679693 + 1316387 1316422 13 115169878 + 41439086 41439121 11997585
+35
+
+chain 1437 21_random 1679693 + 1316422 1316454 3 198022430 + 119282439 119282471 8460363
+32
+
+chain 1151 21_random 1679693 + 1312216 1312274 13 115169878 + 46060123 46060181 10002138
+58
+
+chain 1007 21_random 1679693 + 1312144 1312195 17 81195210 + 33522637 33522688 8813060
+51
+
+chain 810 21_random 1679693 + 1306268 1306301 4 191154276 - 63157613 63157646 21715000
+33
+
+chain 762 21_random 1679693 + 1312422 1312477 7 159138663 + 153013126 153013181 10840208
+55
+
+chain 732 21_random 1679693 + 1312000 1312066 7 159138663 - 102920653 102920719 25474729
+66
+
+chain 561 21_random 1679693 + 18264 18311 21 48129895 + 44700101 44700148 25859698
+47
+
+chain 3320960322 22 49691432 + 14430000 49591432 22 51304566 + 16050000 51244566 22
+647850 150000 150000
+3661581 50000 100000
+15278435 0 18
+293 0 36
+1410 1 1
+46 1 1
+6626947 2 4
+1759 1 1
+43 1 1
+1367363 12000 10615
+7856 4 0
+809336 0 20
+6307 20 0
+6702 50000 2669
+4247727 10618 0
+1558 0 2719
+35231 0 131
+12647 4 0
+45594 85 9
+19562 0 506
+165501 5 7
+1103946 16700 60575
+644 0 2
+319796 1600 1155
+17927 19763 15469
+464566
+
+chain 6025887 22_h2_hap1 63661 + 0 63661 22 51304566 + 42594964 42658568 527
+748 1 0
+260 4 0
+675 1 0
+4844 0 2
+10592 8 0
+3276 29 0
+2384 10 0
+2795 0 2
+464 1 0
+3865 1 0
+1777 1 0
+1286 0 2
+875 1 0
+2336 1 0
+4337 1 0
+2724 0 3
+1087 6 0
+7154 0 1
+1045 2 0
+11070
+
+chain 15737781 22_random 257318 + 90752 257318 GL000211.1 166566 + 0 166566 187
+166566
+
+chain 3641362 22_random 257318 + 7 38789 11 135006516 - 18284691 18323344 804
+2900 3 1
+66 1 1
+55 1 1
+3449 0 1
+1785 1 1
+37 1 1
+178 1 0
+852 0 1
+2329 2 0
+4939 1 0
+1557 1 1
+30 1 1
+1005 1 0
+622 16 0
+39 0 1
+42 0 22
+755 1 1
+30 1 1
+952 1 1
+26 1 1
+141 18 17
+1110 2 0
+1529 1 1
+22 1 1
+399 1 1
+33 1 1
+1369 20 30
+3959 0 4
+1144 1 0
+1032 27 25
+8 23 0
+56 24 0
+51 0 9
+11 1 57
+34 4 4
+7 134 0
+296 26 0
+25 1 1
+2452 0 5
+19 1 1
+231 1 0
+327 1 0
+962 1 1
+22 1 1
+1571
+
+chain 109494 22_random 257318 + 39517 40750 22 51304566 - 30977735 30979001 1172425
+166 5 5
+133 3 3
+48 1 1
+297 0 33
+234 1 1
+58 4 4
+283
+
+chain 19094 22_random 257318 + 39007 39213 22 51304566 - 29625864 29626070 11204980
+206
+
+chain 8587 22_random 257318 + 39415 39517 22 51304566 - 29782769 29782871 2027258
+50 48 48
+4
+
+chain 3763 22_random 257318 + 39465 39513 22 51304566 - 30978529 30978577 2726523
+48
+
+chain 17719073 2_random 185571 + 0 185498 2 243199373 + 242522204 242710000 158
+43034 21 22
+16724 1 0
+52199 0 669
+3059 0 4
+14500 1 0
+409 1 1
+22 1 1
+2039 1 0
+809 0 1
+2041 0 4
+2258 6 6
+4179 12 13
+1973 1 1
+21 1 1
+1855 1 1
+37 2 2
+4315 0 1
+1584 14 0
+281 0 2
+78 1 1
+1497 9 0
+237 2 1
+826 4 0
+21273 4 0
+6716 0 1650
+3449
+
+chain 18404389309 3 199501827 + 35000 199446827 3 198022430 + 60000 197962430 3
+13552792 1 0
+585083 1 0
+2092 74 72
+31067262 1 0
+90 0 1
+5628461 15 0
+788 0 1
+3676 2 0
+35 1 1
+4682 0 1
+1295 5 0
+437 42 53
+326 2 0
+3309 1 1
+40 1 1
+998 3 0
+3584 0 5
+930 7 5
+845 1 1
+28 1 2
+303 1 0
+509 5 0
+2291 6 6
+2789 0 1
+2541 9692 9690
+949 4 4
+35 1 1
+2874 1 0
+6717 1 0
+2823 0 1
+704 4 0
+5142 0 1
+2490 10 10
+162 7 7
+6308 15 0
+15177535 260003 152352
+2532 0 1
+24209179 4400000 3000000
+60453438 4 0
+40076811 20000 20999
+8195 1 1
+44 1 1
+1408 1 1
+33 1 1
+172 4 3
+25 1 1
+538 13 13
+173 1 1
+27 1 1
+636 1 1
+28 1 1
+470 3 3
+112 1 1
+375 1 1
+26 0 26
+106 0 78
+72 9 6
+12 3 29
+79 5 262
+56 1 1
+20 1 1
+815 43 43
+457 1 1
+49 0 18
+509 3 4
+23 1 1
+391 1 1
+44 1 1
+1270 4 0
+40 1 1
+264 27 31
+2416 2 0
+4377 13 13
+736 1 1
+47 1 1
+1416 1 1
+20 1 1
+1020 1 1
+25 1 1
+482 0 5
+716 0 1
+1697 1 1
+29 1 1
+1270261 27000 23108
+40930 0 1
+17455 1 1
+28 4 4
+45 491 0
+1669 58 0
+18 3 61
+54863 16 53
+7653 6 0
+3 99 0
+170 30 0
+25 0 30
+210 0 45
+359 0 915
+5980 256 640
+1363 1 1
+37 1 1
+7958 1 0
+372 1 0
+2442058
+
+chain 572461 3 199501827 + 50900356 50910048 3 198022430 - 147087402 147097092 2111
+52 1 6
+5886 1 0
+2586 6 0
+1160
+
+chain 14997 3 199501827 + 196923229 196923617 3 198022430 + 195437554 195437811 3659243
+77 131 0
+180
+
+chain 6146 3 199501827 + 196987930 196988205 3 198022430 + 195502296 195502751 2529960
+74 171 141
+23 2 212
+5
+
+chain 4201 3 199501827 + 196923126 196923228 3 198022430 + 195438036 195438138 6236935
+102
+
+chain 2082 3 199501827 + 196994845 196994975 3 198022430 + 195509346 195509572 2249717
+55 18 114
+57
+
+chain 20970321 3_random 749256 + 196010 556188 3 198022430 - 121623404 130096441 129
+131258 0 1
+41217 50000 8162858
+137703
+
+chain 13779918 3_random 749256 + 0 146010 3 198022430 - 77602115 77748060 219
+64144 1 0
+1191 0 1
+633 0 1
+4651 29 21
+5147 0 1
+947 14 0
+64 56 0
+55 0 2
+2421 0 15
+741 9 0
+371 6 4
+554 1 0
+5424 0 1
+4074 1 1
+44 1 1
+3065 0 1
+2772 1 1
+36 1 1
+15950 1 0
+2351 0 2
+5999 1 0
+17825 0 13
+74 1 1
+367 1 1
+47 1 1
+2084 2 0
+288 0 3
+744 1 0
+131 0 1
+465 1 1
+29 1 1
+659 10 0
+830 0 3
+262 3 0
+1428
+
+chain 13528802 3_random 749256 + 606188 749256 3 198022430 + 46352896 46495976 221
+8517 0 10
+20860 0 6
+16120 0 1
+4148 7 6
+745 7 6
+517 6 0
+907 5 5
+1382 4 0
+2730 0 1
+1143 36 36
+457 13 17
+1748 1 1
+48 1 1
+954 0 2
+767 1 4
+7353 0 8
+4950 0 12
+13338 0 1
+4685 1 1
+21 1 1
+1414 3 0
+4158 23 23
+5081 0 1
+14097 1 1
+49 1 1
+770 16 16
+424 1 1
+17 1 1
+244 1 1
+23 1 1
+1462 12 0
+2048 14 0
+4573 1 0
+3856 2 0
+754 0 8
+7304 1 0
+5243
+
+chain 17653370240 4 191273063 + 0 191263063 4 191154276 + 10000 191029082 4
+1413146 51000 71672
+5369 5 6
+65 1 1
+67 1 1
+425 1 1
+32 1 1
+175 1 1
+34 1 1
+5092 1 1
+46 1 1
+1396 15 15
+1446 0 1
+5135 1 0
+586 1 1
+38 1 1
+10 0 21
+1587 0 6
+205 0 3
+97 6 0
+177 0 9
+4059 1 1
+71 1 1
+1413 83 1
+51 7 7
+105 7 7
+67 41 0
+67 42 1
+55 41 0
+25 41 0
+3244 558 0
+64 93 0
+93 558 0
+907 0 2
+1101 55 0
+3473 15 15
+1167 3 0
+25 0 29
+135 29 0
+5074 1 1
+42 1 1
+1825 14 14
+1992 0 3
+23 1 1
+4171 6 6
+796 0 165
+196 0 99
+87 0 33
+190 6 8
+107 2 2
+21 0 2
+62 1 68
+32 14 15
+81 18 18
+55 0 100
+17 1 1
+222 2 169
+51 0 35
+3289 18 18
+298 0 1
+373 0 1
+2965 1 1
+28 0 23
+1704 0 38
+114 0 38
+53 7 44
+119 77 0
+269 1 1
+70 1 1
+2000 23 33
+2400 1 1
+94 1 1
+6002 18 18
+776 1 0
+369 16 16
+418 51 0
+53 1 27
+2181 1 4
+57 1 1
+1973 10 0
+4184 11 11
+1594 0 18
+2038 0 109
+4332 0 7
+49 0 4
+1465 3 1
+4156 2 0
+5455 3 2
+129 4 4
+9082 0 1
+786 20 20
+1506 0 1
+252 8 7
+17512 50 1
+56 1 0
+2474 69 52
+69 0 30
+60 16 0
+19 15 0
+40 1 1
+138 16 0
+74 5 51
+3386 0 1
+968 0 4
+1624 11 11
+1065 0 3
+2935 8 0
+2312 0 181
+2300 1 0
+1641 6 1
+1955 0 1
+68 1 1
+347 1 1
+40 1 1
+1553 6 0
+678 16 16
+92 0 33
+390 4 0
+1147 0 1
+1948 4 4
+4296 18 18
+955 1 1
+47 1 1
+1555 1 0
+2251535 81122 0
+145 1 1
+48 1 1
+718 1 0
+2789 1 1
+27 1 1
+1601 4 0
+1048 39 39
+820 0 2
+20 6 0
+28 2 0
+76 12 18
+28 1 0
+11 9 3
+1772 0 6
+22 1 1
+946 1 1
+24 1 1
+1245 1 0
+3231 1 1
+41 1 1
+1652 20 20
+11270 3 0
+2704 1 1
+41 1 1
+1812 5 6
+1477 0 11
+3790 4 0
+2187 1 1
+48 1 1
+1704 1 1
+73 1 1
+2265 1 1
+10 1 1
+553 1 1
+49 1 1
+67 1 1
+33 1 1
+3932 5 0
+18 1 0
+780 0 1
+1260 0 1
+4203 0 25
+863 14 14
+7114 1 1
+70 1 1
+169 0 1
+43 1 1
+145 1 1
+39 0 3
+8 1 1
+753 0 1
+2255 1 1
+21 1 1
+1605 1 1
+19 2 1
+392 1 1
+29 1 0
+3673 1 0
+145 14 14
+39 0 1
+1246 0 1
+2302 1 0
+1554 9 9
+4537 0 1
+1064 2 0
+2051 1 0
+1130 0 2
+164 1 0
+1972 0 1
+18 3 3
+2597 1 1
+46 3 3
+196 1 1
+17 1 1
+60 4 4
+187 4 4
+46 1 1
+692 1 0
+3920 3 3
+15 1 1
+486 14 14
+1709 8 0
+169 1 0
+597 1 1
+18 0 7
+3423937 0 1
+1295496 1 1
+26 1 1
+760 150000 591802
+22468468 1 1
+27 1 1
+2592 0 2
+33 1 1
+2065 3 0
+1050 11 11
+1046 3 9
+52 11 11
+3200 1 0
+906 1 0
+1644 6 0
+1180 0 1
+475 0 5
+2556 26 22
+351 0 1
+1716 71000 36200
+976586 59000 26528
+7701 0 4
+9296 0 1
+1862 1 0
+3316 7 3
+1131 0 1
+1795 1 0
+569 1 0
+2895 44 44
+458 3 0
+5371 1 0
+6774 0 2
+2504 0 2
+1247 1 1
+45 1 1
+2415 17 17
+8215 1 1
+18 1 1
+272 10 10
+420 1 1
+34 1 1
+7961 4 0
+1973 1 1
+45 1 0
+529 1 0
+603 0 1
+18 1 1
+621 4 12
+67 2 0
+18 34 0
+516 0 1
+1400 38 41
+3786 0 1
+228 3 0
+1026 1 1
+49 1 1
+3336 0 3
+951 1 1
+77 2 1
+441 1 2
+1833 9 9
+301 5 5
+2787 17 17
+1747 1 0
+3040 2 9
+81 10 10
+86 2 0
+7354949 20000 1606
+1681 16 30
+13957 0 8
+1947 0 3
+1255 1 1
+38 0 1
+1788 12 17
+1045 6 0
+1327 0 1
+5775 1 1
+18 1 1
+1933 1 0
+1716 13 13
+255 1 0
+124 0 3
+792 0 5
+1521 1 1
+64 1 1
+9005617 150000 150000
+171176 3000000 3000000
+7074452 53320 65431
+1937 0 1
+2845 2 0
+1387 0 1
+114 1 0
+2382 0 4
+68 6 6
+60 4 0
+20 0 1
+93 0 51
+9781584 351994 0
+1909446 184275 0
+3919546 13 13
+435 23 23
+838 0 1
+807 6 6
+74 1 1
+43 1 1
+652 30000 29839
+13847966 0 1
+14069801 2 0
+8504 0 1
+32266 8 0
+12729 0 2
+35327 12 14
+1503 1 0
+1334 1 0
+759 0 1
+7479 34 34
+2523 7 1
+9912 18 17
+2523 1 0
+1321 0 1
+3684 18 18
+5282 2 0
+5505 20 20
+9694 6 6
+22003 9 0
+578 0 1
+5166 2 0
+92208 2 5
+8 1 0
+5 0 2
+113 4 0
+845 6 7
+2247 3 1
+3770 0 1
+5719 0 2
+2511 0 1
+1557 0 1
+5812 0 1
+3607 0 1
+7405 1 0
+11075 0 1
+2794 1 0
+2340 1 0
+429 0 1
+522 2 0
+2397 5 0
+371 11 0
+1376 1 0
+2416 8 0
+210 1 1
+20 1 1
+5104 1 1
+20 1 1
+525 2 0
+836 0 1
+2094 1 0
+2213 3 0
+327 9 6
+2593 1 1
+57 1 1
+1618 0 1
+1400 4 0
+254 0 2
+93 10 0
+754 0 6
+193 0 1
+2378 0 1
+1753 3 0
+1903 0 4
+29 1 1
+1136 14 14
+2452 4 0
+3622 31 3
+456 14 14
+1076 7 8
+68 1 1
+20 1 1
+145 1 1
+68 1 0
+12 0 1
+10 0 1
+11 1 0
+35 1 0
+5 0 1
+11 1 2
+32 6 7
+35 1 0
+8722 1 0
+888 0 4
+456 3 0
+45 0 1
+151 13 13
+756 0 1
+203 8 7
+140 1 1
+20 1 1
+308 5 0
+1020 0 1
+1258 0 1
+160 0 2
+1411 1 1
+22 1 1
+1180 12 12
+4521 0 2
+1155 27 0
+4954 3 0
+1392 1 1
+47 1 1
+3854 2 1
+130 1 0
+2633 2 0
+3053 12 13
+2308 0 1
+1747 0 45
+732 2 0
+1336 9 11
+3898 0 6
+437 1 0
+981 0 1
+1326 0 1
+382 4 0
+1081 10 0
+81 1 1
+142 0 2
+5452 29 29
+495 1 1
+26 1 1
+485 0 1
+525 0 4
+36 0 6
+3945 347 0
+1034 1 1
+27 1 1
+60 2 0
+2581 3 0
+3880 0 4
+1792 0 1
+20 1 1
+356 1 0
+4244 5 5
+36 1 1
+2232 2 2
+42 1 1
+4462 0 2
+1611 1 0
+1290 0 2
+110 1 0
+1466 0 1
+357 3 0
+850 12 0
+13547766 0 1
+3724943 2 0
+46473408 0 1
+1696 1 1
+28 1 1
+1629 0 4
+666 4 0
+13464 30000 12874
+8520008 2 0
+1107 1 1
+15 1 1
+1892 0 4
+6798 0 2
+1793 1 1
+25 0 3
+422 389 0
+786 2 0
+545 0 2
+54 1 0
+143 1 1
+39 1 1
+89 1 1
+29 1 0
+171 1 1
+46 1 0
+192 1 1
+33 1 1
+2580 0 1
+107 1 1
+29 1 1
+218 1 0
+175 6 5
+1407 1 1
+52 1 1
+8851 1 0
+14427 4 0
+1737 22 0
+5806 1 0
+1115 1 1
+29 0 2
+3395 0 1
+3164 0 2
+522 1 0
+24 1 1
+658 4 0
+5724 9 9
+1209 0 1
+5380 1 0
+97 1 0
+854 4 0
+78 5 11
+2728 6 7
+3754 17 13
+1363 1 0
+1025 1 0
+1811 0 1
+7507 0 4
+1184 3 0
+763 1 0
+797 3 0
+293 2 0
+2488 0 1
+335 0 1
+9959 1 0
+3255 1 0
+1322 0 1
+8118 2 0
+2908 49 49
+369 2 0
+632 1 0
+63 0 5
+3008 0 1
+9582 0 1
+14742673 0 3013
+39686
+
+chain 945825 4 191273063 + 69381892 69391896 4 191154276 + 69230000 69240000 2911
+2225 1 0
+4917 1 0
+2807 2 0
+51
+
+chain 941684 4 191273063 + 69471941 69481941 4 191154276 + 69320000 69330000 3076
+3521 0 1
+4784 1 0
+1694
+
+chain 941274 4 191273063 + 69614595 69624595 4 191154276 + 69580000 69590000 3093
+10000
+
+chain 940419 4 191273063 + 69564606 69574607 4 191154276 + 69530000 69540000 3129
+3216 5 5
+134 0 1
+5676 2 0
+968
+
+chain 939146 4 191273063 + 69534617 69544617 4 191154276 + 69500000 69510000 3182
+387 6 6
+9607
+
+chain 939091 4 191273063 + 69481941 69491934 4 191154276 + 69330000 69340000 3184
+8138 0 4
+1546 0 3
+309
+
+chain 938726 4 191273063 + 69461942 69471941 4 191154276 + 69310000 69320000 3193
+130 0 1
+9869
+
+chain 936769 4 191273063 + 69604595 69614595 4 191154276 + 69570000 69580000 3285
+2900 25 25
+7075
+
+chain 936653 4 191273063 + 69421914 69431904 4 191154276 + 69270000 69280000 3293
+6388 14 14
+338 29 29
+266 0 1
+2309 1 3
+55 1 0
+83 0 8
+506
+
+chain 936357 4 191273063 + 69391896 69401898 4 191154276 + 69240000 69250000 3304
+2367 1 0
+2329 0 1
+795 23 23
+2819 2 0
+1666
+
+chain 935200 4 191273063 + 69441943 69451948 4 191154276 + 69290000 69300000 3343
+1203 4 0
+488 57 57
+7133 2 1
+310 1 0
+551 0 1
+256
+
+chain 934799 4 191273063 + 69544617 69554606 4 191154276 + 69510000 69520000 3366
+1296 39 39
+1112 1 0
+204 1 0
+2340 0 12
+1710 0 1
+3286
+
+chain 933839 4 191273063 + 69584607 69594595 4 191154276 + 69550000 69560000 3402
+417 3 0
+966 1 0
+2053 0 1
+1784 5 8
+284 0 12
+4475
+
+chain 932655 4 191273063 + 69594595 69604545 4 191154276 + 69560000 69569950 3440
+8695 26 26
+1229
+
+chain 930772 4 191273063 + 69451948 69461942 4 191154276 + 69300000 69310000 3507
+1068 0 1
+1437 25 27
+806 0 4
+5337 50 50
+300 1 0
+970
+
+chain 928519 4 191273063 + 69411919 69421914 4 191154276 + 69260000 69270000 3571
+62 32 32
+801 11 11
+3595 38 38
+941 54 59
+4461
+
+chain 928371 4 191273063 + 69511937 69521941 4 191154276 + 69360000 69370000 3579
+6433 60 60
+335 10 6
+239 10 10
+2917
+
+chain 925594 4 191273063 + 69554606 69564602 4 191154276 + 69520000 69529997 3671
+2109 0 1
+4421 81 81
+1599 22 22
+1764
+
+chain 922960 4 191273063 + 69501928 69511937 4 191154276 + 69350000 69360000 3756
+714 8 8
+423 18 18
+882 33 33
+952 22 22
+607 1 0
+196 64 64
+495 3 0
+2055 2 0
+548 3 0
+2983
+
+chain 915200 4 191273063 + 69491934 69501928 4 191154276 + 69340000 69350000 3933
+1036 10 10
+2821 5 0
+53 40 40
+209 3 0
+3718 11 0
+421 0 23
+332 11 11
+292 0 2
+432 23 23
+159 20 20
+115 20 20
+263
+
+chain 911203 4 191273063 + 69431904 69441943 4 191154276 + 69280000 69290000 4026
+364 6 5
+212 4 0
+2445 40 15
+377 30 30
+1126 60 60
+262 8 6
+3222 145 138
+1738
+
+chain 903419 4 191273063 + 69401898 69411919 4 191154276 + 69250000 69260000 4208
+1051 52 52
+1007 0 1
+319 27 26
+154 98 97
+145 40 40
+512 23 0
+355 5 5
+126 19 19
+128 49 49
+67 0 1
+3337 0 2
+1729 5 5
+773
+
+chain 895926 4 191273063 + 69574644 69584607 4 191154276 + 69540037 69550000 4357
+3368 220 220
+1524 84 84
+1558 19 19
+889 41 41
+1592 43 43
+625
+
+chain 866339 4 191273063 + 69524748 69534617 4 191154276 + 69490119 69500000 4930
+190 50 50
+59 111 111
+51 7 7
+78 59 59
+58 121 121
+57 39 39
+70 0 1
+1558 108 108
+737 24 24
+3582 0 1
+84 0 10
+2826
+
+chain 659008 4 191273063 + 71711854 71718864 4 191154276 + 71492990 71500000 7936
+7010
+
+chain 608986 4 191273063 + 69375441 69381892 4 191154276 + 69223549 69230000 8701
+135 1 0
+2166 0 1
+4149
+
+chain 248590 4 191273063 + 69521941 69527313 4 191154276 + 69370000 69375377 111030
+2807 190 190
+50 59 59
+111 136 136
+59 58 58
+121 57 57
+39 1628 1633
+57
+
+chain 214386 4 191273063 + 71534589 71536854 4 191154276 + 71500000 71502265 534073
+2265
+
+chain 96900 4 191273063 + 3963456 3964475 4 191154276 + 3912520 3913539 1319679
+1019
+
+chain 52181 4 191273063 + 69624595 69625143 4 191154276 + 69590000 69590548 2441389
+548
+
+chain 20814 4 191273063 + 1495708 1495926 4 191154276 + 1526075 1526293 9826122
+218
+
+chain 8858 4 191273063 + 1496845 1496937 4 191154276 + 1526189 1526281 25171661
+92
+
+chain 8858 4 191273063 + 1496752 1496844 4 191154276 + 1526189 1526281 25171662
+92
+
+chain 8858 4 191273063 + 1496566 1496658 4 191154276 + 1526189 1526281 25171663
+92
+
+chain 7802 4 191273063 + 1492030 1492276 4 191154276 + 1522531 1522736 2805154
+25 83 42
+23 15 15
+4 55 55
+41
+
+chain 7606 4 191273063 + 69578098 69578232 12 133851895 + 88986938 88987072 9526361
+134
+
+chain 7510 4 191273063 + 1496208 1496286 4 191154276 + 1526203 1526281 25171660
+78
+
+chain 7439 4 191273063 + 1527942 1528019 4 191154276 + 1557568 1557645 18158883
+77
+
+chain 7376 4 191273063 + 1496452 1496529 4 191154276 + 1526075 1526152 27495831
+77
+
+chain 6986 4 191273063 + 59479326 59479400 7 159138663 + 119297971 119298045 28268313
+74
+
+chain 6131 4 191273063 + 1496080 1496144 4 191154276 + 1526075 1526139 27495827
+64
+
+chain 5599 4 191273063 + 1495650 1495708 4 191154276 + 1526203 1526261 27226300
+58
+
+chain 5460 4 191273063 + 1496658 1496715 4 191154276 + 1526095 1526152 27495830
+57
+
+chain 4356 4 191273063 + 1498960 1499009 4 191154276 + 1528103 1528152 18458745
+49
+
+chain 4121 4 191273063 + 69578012 69578069 3 198022430 - 95182224 95182281 17792812
+57
+
+chain 3000 4 191273063 + 1495929 1496022 4 191154276 + 1526110 1526203 11256589
+93
+
+chain 2961 4 191273063 + 69443663 69443695 4 191154276 - 68628109 68628141 14494983
+32
+
+chain 2485 4 191273063 + 1503833 1503862 4 191154276 + 1532970 1532999 23156792
+29
+
+chain 2401 4 191273063 + 1492301 1492331 4 191154276 + 1522679 1522709 5335388
+30
+
+chain 2012 4 191273063 + 1496731 1496752 4 191154276 + 1526075 1526096 27495829
+21
+
+chain 1744 4 191273063 + 1597414 1597448 4 191154276 + 1627062 1627096 3575887
+34
+
+chain 1461 4 191273063 + 69579763 69579840 5 180915260 + 121968423 121968500 3935628
+77
+
+chain 1332 4 191273063 + 69545913 69545943 11 135006516 - 130984886 130984916 21069914
+30
+
+chain 909 4 191273063 + 69582306 69582346 3 198022430 - 10790236 10790276 7796945
+40
+
+chain 18169122 4_random 842648 + 440032 631501 GL000194.1 191469 + 0 191469 150
+191469
+
+chain 18001815 4_random 842648 + 0 189789 GL000193.1 189789 + 0 189789 151
+189789
+
+chain 15268007 4_random 842648 + 681501 842648 GL000218.1 161147 + 0 161147 194
+161147
+
+chain 9245037 4_random 842648 + 239789 336038 4 191154276 + 8829368 8925617 353
+96249
+
+chain 137712 4_random 842648 + 388580 390032 4 191154276 + 9620000 9621452 935614
+1452
+
+chain 10386 4_random 842648 + 388312 388420 11 135006516 - 91778086 91778194 21974850
+108
+
+chain 3377 4_random 842648 + 388277 388312 11 135006516 - 84847900 84847935 23649965
+35
+
+chain 2456 4_random 842648 + 388184 388235 X 155270560 - 93144339 93144390 24160146
+51
+
+chain 16791974256 5 180857866 + 63000 180837866 5 180915260 + 10000 180905260 5
+17520657 24032 50000
+1688 3435 1
+37 1399 0
+27 2 1
+8 1 1
+3983 3434 0
+103 1 1
+32 1 1
+67 1 1
+35 1 1
+752 1669 0
+43 1 1
+1207 0 1
+46 0 1
+5 0 1
+19 1 1
+70 3434 0
+962 16 16
+1905 44 44
+85 41 41
+332 49 49
+1675 23 23
+1185 11 11
+124 35 35
+713 105 105
+408 4 4
+113 16 16
+1835 1 2
+26 7 8
+18 2730 25
+3103 1 0
+7858 718 10488
+307 1 636
+7461 0 1
+23772 51 0
+4031 0 1
+20571 0 1
+9135 0 2
+6885 2 3
+110 3 0
+816 2 3
+2295 0 34
+3936 28 28
+3536 0 2
+2917 0 1
+652 1 1
+37 1 1
+657 1 1
+22 1 1
+419 3 4
+3580 1 1
+29 1 1
+274 11 35
+835 3036 0
+1907 1 0
+10504 30 28
+784 0 6
+127 10 0
+668 1 1
+28 1 1
+2467 4 0
+179 0 2
+1650 1 1
+39 1 1
+2433 1 0
+720 1 1
+40 1 1
+772 1 1
+32 1 1
+353 1 1
+17 1 1
+1776 0 1
+6082 3 0
+2669 12 10
+2857 1 1
+35 1 1
+722 60 60
+200 1 1
+240 1 1
+4048 1 1
+49 1 1
+702 1 1
+33 1 1
+2927 1 2
+1487 17 0
+276 16 16
+1039 1 1
+35 1 1
+2068 1 1
+40 1 1
+828 1 1
+36 2 0
+317 8 0
+893 1 1
+33 1 0
+8143 0 4
+28632199 3000000 3000000
+12470071 0 1
+29760415 40000 50000
+5878002 23000 20845
+4521 1 0
+676 6 6
+5928 0 1
+372 1 1
+47 1 1
+6801 3 2
+639 0 1
+871 3 4
+11530 0 4
+22966 0 1
+15447 0 1
+53856 0 2
+15988 0 2
+906887 10 11
+40152817 5000 52715
+3521239 0 1
+1604 10 0
+12778810 4100 51715
+15152692 27 0
+1852096 1 0
+8710030
+
+chain 924655 5 180857866 + 17585088 17611949 5 180915260 - 163333152 163394435 1227
+14 409 52001
+494 3435 1
+24 1 1
+1487 10 10
+682 13 13
+132 3449 15
+306 1 1
+74 1 1
+967 3434 0
+1285 3434 0
+68 4569 1135
+2087 50 50
+435
+
+chain 315813 5 180857866 + 17584685 17618655 5 180915260 + 17581691 17599590 1580
+403 14 14
+237 1475 75
+628 25 25
+51 89 89
+304 24 24
+70 33 33
+37 698 698
+667 3506 72
+1354 96 96
+75 4 4
+752 1710 41
+450 382 382
+51 14129 7264
+237 12 12
+614 37 37
+134 16 16
+422 31 31
+796 4345 1642
+62
+
+chain 312488 5 180857866 + 17597387 17639380 5 180915260 + 17580657 17599710 1454
+373 70 70
+1245 2263 863
+1184 3434 0
+1733 3775 2106
+50 9111 2246
+1078 993 993
+1363 8015 1147
+44 85 85
+41 332 332
+49 6299 3596
+341 45 44
+70
+
+chain 265075 5 180857866 + 17745718 17748537 5 180915260 + 17713035 17715853 333767
+1906 1 0
+912
+
+chain 207388 5 180857866 + 17584033 17596937 5 180915260 + 17583073 17597745 2201
+51 557 557
+14 17 17
+13 654 654
+172 494 494
+219 23 23
+567 4975 6743
+176 6 6
+865 14 14
+96 1354 1354
+26 2261 2261
+350
+
+chain 193008 5 180857866 + 17583668 17629078 5 180915260 + 17580674 17599710 1465
+356 84 84
+533 3434 0
+698 5562 728
+51 4689 1255
+946 4787 1353
+543 8 8
+167 12743 7643
+324 5466 2032
+306 3553 850
+1045 45 44
+70
+
+chain 130263 5 180857866 + 17639380 17641654 5 180915260 + 17592112 17594386 19200
+936 23 23
+116 16 16
+1183
+
+chain 123401 5 180857866 + 17602522 17620625 5 180915260 + 17589594 17593961 2306
+159 16 16
+1763 19 19
+54 14448 712
+1644
+
+chain 53192 5 180857866 + 17626966 17629142 5 180915260 + 17590000 17592176 2614
+952 1045 1045
+45 70 70
+64
+
+chain 42492 5 180857866 + 17625757 17626966 5 180915260 - 163394507 163395716 9006
+1209
+
+chain 23743 5 180857866 + 17605548 17605956 5 180915260 + 17596054 17596462 38000
+290 9 9
+109
+
+chain 20601 5 180857866 + 17748538 17748754 5 180915260 + 17712817 17713033 9842237
+216
+
+chain 11635 5 180857866 + 17618762 17618981 5 180915260 + 17595532 17595751 149283
+219
+
+chain 9108 5 180857866 + 17618655 17618762 5 180915260 + 17583355 17583462 1340460
+107
+
+chain 7916 5 180857866 + 17587442 17604673 5 180915260 - 163387098 163397461 2244
+25 61 61
+79 398 398
+33 16608 9740
+27
+
+chain 7204 5 180857866 + 17604533 17604646 5 180915260 + 17599204 17599317 3499
+113
+
+chain 4292 5 180857866 + 17639265 17639310 5 180915260 + 17595431 17595476 67944
+45
+
+chain 2558 5 180857866 + 17604673 17604706 5 180915260 + 17591745 17591778 3790746
+33
+
+chain 2511 5 180857866 + 170275712 170275739 5 180915260 + 170343161 170343188 11152528
+27
+
+chain 2447 5 180857866 + 17635643 17636496 5 180915260 - 163394091 163394944 8841
+35 713 713
+105
+
+chain 2252 5 180857866 + 17601306 17601338 5 180915260 + 17595246 17595278 11344
+32
+
+chain 2027 5 180857866 + 17785693 17785748 18 78077248 - 45596607 45596662 524022
+55
+
+chain 1518 5 180857866 + 17629142 17629191 5 180915260 - 163394458 163394507 205933
+49
+
+chain 1109 5 180857866 + 17613421 17613452 5 180915260 - 163395907 163395938 8647
+31
+
+chain 143977943 5_h2_hap1 1794870 + 0 1794870 5 180915260 + 68505249 71134051 52
+5440 1 0
+1785 0 1
+12373 0 2
+7216 0 1
+714 2 0
+4360 0 1
+11179 1 0
+2027 1 0
+6969 0 2
+3779 1 0
+634 4 3
+1384 0 9
+378 0 2
+1153 3 0
+1246 0 6
+1427 0 2
+608 1 1
+23 1 1
+1981 44 44
+3998 1 1
+33 5 0
+148 1 1
+18 1 0
+331 2 0
+162 1 0
+333 0 1
+644 1 0
+2053 1 0
+1896 0 1
+2096 1 1
+32 1 1
+265 0 14
+1061 0 1
+7303 6 6
+1313 1 0
+3225 0 2
+65 1 1
+220 1 1
+1422 0 1
+248 1 1
+21 2 0
+641 0 1
+163 3 0
+522 1 0
+1685 0 1
+299 1 1
+16 1 0
+3259 1 0
+6492 9 9
+700 0 2
+379 1 0
+186 0 16
+21 0 27
+242 21 19
+156 0 3
+2040 1 0
+7852 0 2
+1267 0 4
+8016 0 1
+2057 85 0
+449 0 1
+2797 0 1
+3858 0 1
+2129 1 0
+234 1 1
+28 1 1
+2923 0 3
+4346 1 0
+2467 1 0
+11093 1 0
+3932 0 3
+2223 1 1
+22 0 1
+25 0 6
+1909 2 0
+1136 1 0
+658 2 0
+32 8 0
+9 2 0
+14 15 11
+22 14 0
+20 51 1
+34 2 0
+43 0 2
+38 127 19
+15 14 0
+41 0 5
+9200 1 0
+2655 1 0
+38 1 1
+237 1 1
+28 1 1
+1065 1 0
+2979 3 0
+13 1 1
+653 4 0
+1950 1 0
+2320 2 0
+817 3 0
+524 8 0
+417 1 0
+873 1 0
+352 1 0
+152 2 0
+651 1 0
+285 1 0
+1830 0 1
+1271 0 1
+957 0 1
+1506 2 0
+2454 4 0
+6 4 0
+300 1 1
+68 1 1
+1648 0 1
+10725 10 10
+1308 2 1
+48 1 1
+1242 15 0
+1869 1 0
+26 0 452
+1178 0 3
+43 0 4
+3567 0 1
+2289 0 1
+695 0 6
+721 13 14
+192 0 2
+1190 1 1
+36 1 1
+451 0 1
+4137 1 0
+809 23 0
+1624 0 4
+453 4 0
+983 0 1
+188 0 5
+489 0 1
+299 11 11
+1923 1 0
+168 0 1
+891 1 1
+54 0 1
+908 0 28
+1224 2 0
+175 0 1
+459 2 0
+119 133 153
+50 13 13
+4001 0 1
+4764 3 0
+90 1 1
+117 92 0
+325 0 27
+19 1 1
+92 1 67
+21 1 28
+15 1 28
+9013 0 1
+1376 0 1
+674 10 0
+87 0 1
+1317 43 35
+260 1 0
+1518 11 12
+232 0 1
+1093 0 1
+737 0 2
+176 10 10
+664 1 1
+33 1 1
+2816 3 0
+4679 0 2
+3212 0 2
+2383 14 16
+3049 0 1
+146 1 0
+721 1 1
+35 1 1
+2260 2 0
+1228 0 1
+682 1 0
+8927 1 0
+795 2 0
+5278 0 2
+5578 13 0
+3665 20 0
+1852 9 0
+4564 1 1
+20 4 0
+111 1 1
+1065 37 37
+2979 1 0
+820 0 1
+9147 0 1
+411 0 1
+745 2 0
+144 3 3
+27 2 0
+734 1 1
+38 1 1
+105 0 4
+554 1 0
+35 1 1
+226 2 0
+254 1 1
+39 1 1
+3302 0 2
+16 1 1
+1276 1 1
+57 1 1
+122 5 0
+178 0 1
+29 1 1
+89 1 1
+32 1 1
+1743 1 0
+294 1 1
+27 1 1
+1925 1 1
+48 1 1
+116 1 1
+20 1 1
+163 4 4
+821 4 3
+46 1 1
+247 1 1
+27 2 2
+613 1 1
+44 1 1
+181 9 7
+1220 1 1
+53 0 3
+596 1 0
+1052 12 12
+130 1 0
+1524 0 1
+1878 1 4
+76 0 1
+6 0 5
+895 0 1
+290 9 5
+783 1 1
+45 1 1
+1910 1 1
+48 1 1
+409 1 1
+30 1 1
+158 2 0
+69 6 0
+428 1 1
+136 1 1
+418 44 44
+767 35 27
+711 1 1
+28 1 1
+1137 1 0
+585 1 0
+433 13 0
+3034 1 0
+961 0 3
+950 1 1
+15 1 1
+948 0 5
+153 21 20
+181 38 38
+765 8 10
+207 13 15
+3092 4 0
+202 5 5
+1406 0 5
+205 1 1
+44 1 1
+2719 1 1
+36 1 1
+1050 0 9
+108 0 2
+1177 4 0
+115 1 1
+2051 15 0
+520 8 8
+1072 0 1
+595 2 0
+4576 73 73
+6176 1 0
+1299 1 1
+29 1 0
+496 0 4
+379 2024 0
+7 3663 0
+82 4 0
+79 6 1
+556 11 0
+598 9 9
+138 77 73
+1651 3 9
+3302 0 8
+429 1 0
+163 0 3
+60 3 0
+132 1 1
+23 1 0
+1660 1 16
+2124 0 1
+1601 9 0
+35 525 6
+38 1 1
+235 1 30
+497 1 1
+37 1 0
+79 0 1
+1239 1 1
+31 1 1
+135 1 0
+5 2 0
+669 0 1
+1158 1595 0
+21 3 0
+5 126998 500121
+730 31 27
+278 0 2
+352 0 12
+363 13 21
+366 1 0
+378 3 0
+61 1 0
+105 17 68
+1480 32 32
+640 1 1
+52 1 1
+482 1 0
+638 1 1
+20 1 0
+21 1 1
+326 1 1
+37 1 1
+995 0 7
+1685 0 1
+1607 9 8
+633 1 1
+37 1 1
+697 6 6
+1363 8 8
+234 1 1
+44 1 1
+3022 5 6
+96 12 11
+674 4 0
+768 0 1
+169 3 0
+2083 0 1
+1098 20 20
+5586 1 0
+174 28 13
+366 2 0
+202 1 1
+69 1 1
+682 5 5
+3457 1 0
+232 1 0
+305 10 0
+1770 40 40
+349 38 38
+401 0 1
+441 7 3
+547 11 10
+210 4 0
+779 4 0
+193 4 0
+576 0 4
+514 48 48
+789 23 16
+2496 25 25
+874 25 11
+2776 19 19
+2824 4 0
+440 0 2
+876 14 14
+1198 39 39
+521 6 0
+126 40 40
+315 29 29
+616 94 99
+285 35 35
+175 12 12
+320 17 1
+3339 0 1
+260 49 49
+109 11 11
+586 0 1
+133 19 13
+8202 0 1
+307 0 1
+1366 1 0
+1073 9 12
+1385 0 1
+321 106 108
+1101 28 28
+483 42 42
+1752 58 58
+166 37 36
+748 16 16
+52 1 0
+1679 0 2
+455 9 17
+484 1 10
+74 33 33
+155 0 1
+62 0 8
+424 23 23
+491 8 9
+450 0 2
+63 1 0
+410 5 0
+1131 165 170
+254 39 39
+1162 0 272664
+1919 1 1
+82 1 1
+740 4 4
+261 1 1
+83 1 1
+52 1 1
+49 1 1
+231 6 6
+244 1 1
+21 1 1
+52 44 44
+114 20 20
+87 32 32
+149 0 6
+202 50 50
+115 44 44
+114 65 65
+50 111 111
+61 52 52
+101 42 45
+250 15 15
+208 1 0
+2259 3 0
+239 64 66
+168 10 10
+2393 1 1
+38 1 1
+674 1 1
+29 1 1
+469 22 25
+827 1 0
+1679 0 1
+463 9 13
+232 1 0
+248 1 5
+325 0 7
+1389 0 4
+63 1 0
+410 6 0
+685 3 0
+35 1 1
+407 166 168
+253 39 39
+71 0 4
+1288 35 35
+1697 32 32
+243 22 22
+395 51 51
+259 49 49
+108 6 6
+54 168 168
+464 45 45
+81 20 20
+84 21 21
+240 25 25
+584 0 810
+126 4 4
+42 6 6
+101 0 3
+41 1 1
+473 1 0
+373 1 1
+41 1 1
+614 1 1
+41 1 18042
+857 50 50
+279 2 0
+246 67 69
+160 10 10
+199 0 1
+154 1 0
+276 28 28
+124 29 28
+105 7 7
+355 1 1
+45 1 1
+299 1 1
+25 1 1
+283 30 35
+594 2 0
+1401 1 1
+46 1 1
+123 4 0
+830 1 0
+100 1 1
+61 1 1
+737 2 7
+285 1 1
+58 1 1
+143 18 0
+19 1 1
+575 1 1
+91 1 1
+318 2 0
+4090 4 0
+702 0 1
+2007 0 2
+901 0 1
+79 9 9
+31 3 3
+1203 1 0
+16 1 1
+574 1 1
+28 1 1
+346 6 0
+25 1 3
+22 2 0
+34 4 0
+7 1 0
+20 18 22
+511 0 5
+5088 0 1
+1065 0 4
+51 2 0
+2714 25 25
+81 8 8
+56 788 18
+22 1 1
+4702 0 1
+536 6 6
+3900 1 0
+1063 0 8
+4095 1 0
+1841 1 3
+1015 0 1
+2808 1 1
+17 1 1
+340 1 1
+39 1 1
+1548 1 1
+73 1 1
+291 1 0
+236 72 43
+104 0 1
+1843 4 0
+80 15 15
+1140 29 1
+45 1 1
+1245 3 0
+194 1 0
+816 11 1
+25 1 11
+47 1 1
+508 0 1
+255 1 1
+24 1 0
+319 13 13
+1846 397 398
+803 0 37
+509 0 12
+130 0 4
+609 0 3
+6495 1251 1253
+1091 11 11
+384 2 0
+1657 31 30
+109 31 31
+2815 63 63
+85 0 13
+589 48 48
+194 25 25
+1068 16 16
+209 2 0
+215 47 47
+1775 127 77
+533 188 0
+1164 1 0
+1863 1 1
+29 1 1
+1993 1 1
+19 1 1
+782 2 0
+3224 2 0
+22 1 11
+473 332 0
+604 1 1
+28 1 1
+223 1 1
+28 1 1
+2870 0 1
+38 1 1
+313 1 0
+768 0 1
+1039 9 9
+886 0 4
+243 0 1
+172 17 17
+2721 1 1
+71 0 1
+607 105 117
+54 46 44
+2057 1 1
+32 1 1
+452 1 1
+49 1 1
+169 322 6
+26 1 0
+567 3 0
+2324 1 0
+825 4 0
+1251 4 4
+2651 0 4
+703 14 19
+10731 13 0
+741 2 0
+1659 0 12
+7683 0 6
+838 1 0
+2905 12 326
+1714 1 0
+1172 90 100
+619 2 0
+263 0 59
+730 1 0
+56 4 0
+1746 17 17
+377 1 1
+27 4 0
+836 1 1
+67 1 1
+1022 0 1
+1096 1 1
+40 0 1
+8 1 1
+1864 1 0
+56 5 1
+6 0 10
+114 1 1
+34 1 1
+631 19 19
+139 13 13
+1330 1 11
+22 2 0
+2846 1 0
+358 0 2
+798 11 11
+3004 1 1
+30 1 1
+2032 1 16
+752 16 0
+40 0 6
+3211 0 1
+965 0 14
+2978 1 1
+29 1 1
+138 0 2
+1646 2 0
+375 1 1
+31 1 1
+6235 0 2
+2598 0 3
+592 0 4
+135 0 12
+3892 1 0
+840 0 12
+5528 9 5
+5400 0 1
+181 0 1
+836 0 3
+3087 1 1
+46 1 1
+2796 11 9
+6282 1 1
+25 1 1
+2009 1 1
+56 0 2
+209 15 15
+2433 1 1
+50 1 1
+366 1 0
+3233 0 1
+5144 0 2
+811 53 22
+23 1 0
+6 1 3
+43 0 2
+13 2 0
+5 0 14
+634 8 8
+1663 10 12
+433 1 1
+43 1 1
+397 2 0
+638 1 1
+42 1 1
+285 1 1
+28 1 1
+516 1288 2
+424 4 0
+660 1 1
+49 1 1
+816 0 12
+1015 1 1
+47 1 1
+988 0 3
+1000 14 32
+330 1 1
+38 1 1
+124 7 2
+43 1 1
+693 1 1
+61 1 1
+94 0 1
+963 1 1
+46 1 1
+1393 0 2
+139 2 0
+113 1 1
+20 1 1
+323 6 0
+34 0 1
+978 1 1
+38 1 1
+105 1 1
+18 1 2
+43 1 1
+381 0 1
+811 15 8
+2537 0 2436
+2642 1 1
+42 4 0
+92 10 10
+1363 1 1
+37 1 1
+252 5 0
+165 1 1
+329 1 1
+77 1 1
+705 0 6
+258 6 6
+155 0 1
+57 2 0
+1380 5 0
+348 2 0
+489 9 5
+448 1 0
+1681 0 1
+835 29 25
+1359 36 36
+223 0 1
+399 15 15
+466 4 4
+75 10559 200741
+1150 1 0
+682 12 15
+802 53 53
+535 1 0
+65 62 63
+497 30 1
+1458 1 0
+683 0 1
+1449 1 0
+977 15 0
+1636 0 4
+216 3 0
+587 0 10
+4302 1 1
+28 1 1
+733 0 4
+138 9 9
+595 0 11
+249 1 1
+65 1 1
+242 1 6
+74 0 4
+87 6 5694
+363 4 0
+513 0 1
+29 1 1
+1297 0 1
+415 1 3
+1947 0 2
+978 0 1
+3121 1 1
+17 1 1
+872 1 1
+31 1 1
+602 8 8
+238 1 1
+36 1 1
+930 1 1
+36 1 1
+1073 22 0
+494 0 1
+66 1 5
+60 1 1
+15 1 1
+452 1 0
+1587 0 7
+1465 1 1
+27 1 1
+76 1 1
+44 1 1
+143 16 14
+323 23 23
+685 1 1
+15 1 1
+136 6 0
+400 0 2
+109 3 0
+50 1 1
+18 1 1
+985 1 1
+38 1 1
+1034 12 12
+247 1 1
+91 2 1
+1383 1 1
+44 1 1
+164 15 16
+292 1 1
+47 1 1
+73 1 1
+43 1 1
+203 1 0
+420 1 1
+37 1 1
+449 0 2
+25 0 4
+415 4 6
+155 1 1
+26 1 1
+199 1 1
+41 0 32
+20 1 1
+68 1 1
+28 1 1
+2097 13 15
+207 8 10
+984 21 20
+134 5 0
+967 10 10
+956 3 0
+4424 5 6
+595 0 1
+1140 1 1
+28 1 1
+733 7 16
+1218 149 149
+429 0 4
+59 0 2
+2568 1 1
+45 1 1
+784 5 8
+289 1 0
+877 5 0
+34 1 0
+68 4 1
+735 1 1
+35 1 1
+1094 4 4
+1519 5 6
+138 12 12
+1044 0 1
+91 80 80
+369 1 1
+53 2 0
+63 1 1
+1220 7 9
+181 1 1
+44 1 1
+134 0 3
+476 2 2
+27 1 1
+205 1 1
+88 2 2
+822 4 4
+163 22 22
+116 1 1
+48 1 1
+3849 1 1
+21 1 1
+120 1 1
+32 1 1
+89 1 1
+29 1 0
+178 3 6
+1452 19 17
+5455 1 0
+10333 1 0
+784 0 1
+55 8 0
+468 0 1
+539 12 0
+98 1 1
+24 1 1
+77 1 1
+81 1 1
+4604 17 19
+7803 7 7
+807 0 1
+2260 7 5
+980 0 1
+2105 0 1
+4083 0 1
+836 0 2
+5612 1 0
+519 0 1
+1334 0 1
+2401 0 9
+1823 1 0
+159 0 2
+484 2 0
+14815 1 1
+36 1 1
+2512 4 0
+58 3 0
+3277 1 0
+559 0 1
+4024 1 0
+4383 22 13
+4131 1 1
+35 1 1
+290 1 1
+29 3 0
+533 1 0
+305 0 1
+2608 0 1
+443 3 1
+2322 0 20
+514 1 1
+46 1 1
+791 19 30
+3206 3 0
+6272 0 2
+1789 8 0
+291 39 39
+521 6 0
+126 40 40
+315 29 29
+616 94 99
+206 114 109
+506 0 14
+2370 0 2
+4709 1 1
+36 1 1
+5588 0 11
+299 1 0
+1366 1 0
+1644 1 1
+28 1 0
+4859 16 21
+1992 0 10
+505 0 1
+448 8 12
+721 40973 60417
+3484 1 1
+40 1 1
+2152 0 2
+5298 39 40
+141 25 25
+427 0 11
+1543 1 0
+3707 0 1
+1056 292 8656
+1768 2 0
+717 1 0
+14041 0 1
+4167 0 2
+7403 5 0
+7673 0 1
+3630 67 67
+74 129 129
+226 1 0
+1720 138 136
+1185 1 0
+878 46874 0
+862 1 1
+31 1 1
+9409 1 1
+37 1 1
+2231 0 2
+1682 0 1
+13767 0 1
+9473 0 1
+7168 2 0
+12384 1 0
+1188 0 4
+2044 1 0
+3076 1 0
+796 0 1
+5477 0 2
+5780 1 0
+6338 1 0
+2680 0 4
+2033 0 1
+9452 0 12
+402983
+
+chain 13752336 5_h2_hap1 1794870 + 324513 1282806 5 180915260 - 110525721 111977366 61
+37 39926 39909
+44 767 767
+34 9178 9179
+38 20004 20004
+27 1 1
+44 8383 8384
+1071 3 3
+511 0 1
+439 7 7
+3663 1483 1482
+77 11199 11214
+525 4132 4132
+704 1 0
+729 3 0
+158 29 29
+653 0 3
+154 0 2
+7041 8 0
+2068 0 7
+166 1 0
+812 6 7
+25 1 1
+1423 0 8
+438 0 1
+4783 0 1
+31 1 1
+1269 1 0
+926 3 0
+2542 2 0
+112 1 1
+2183 1 1
+59 1 1
+1605 2 2
+4515 0 1
+4368 1 0
+382 0 34
+60 1 1
+86 0 1
+552 6 6
+892 1 1
+33 1 1
+6705 0 1
+934 0 2
+8985 2 1
+445 6 0
+6283 0 1
+456 0 1
+1101 0 5
+696 0 1
+2973 6 0
+158 0 3
+449 0 3
+657 12 12
+151 0 1
+406 1 1
+55 1 1
+163 1 1
+72 1 1
+1955 1 0
+713 0 1
+3050 1 1
+35 1 1
+3127 1 0
+233 1 0
+1343 17 7
+1250 3 0
+322 1 0
+2081 0 1
+2413 5 0
+818 0 1
+18 1 1
+268 0 1
+271 1 1
+35 1 0
+586 2 0
+1192 0 1
+494 2 0
+4657 1 1
+30 5 0
+2172 0 334
+1981 5 0
+33 321 0
+2633 2 0
+142 1 0
+1597 7 0
+248 1 0
+317 1 1
+21 1 1
+441 0 1
+600 6 4
+35 1 1
+1593 2 6
+9303 1 0
+2781 0 2
+6052 0 4
+771 1 0
+1500 14 0
+1544 730 730
+31 3419 3419
+30 30394 30395
+40 349 349
+38 3691 3690
+48 3308 3306
+25 874 880
+25 8151 8151
+39 653 653
+40 315 315
+29 616 616
+94 285 285
+35 4123 4120
+49 13570 13573
+58 30899 10440
+165 1652 1655
+35 1697 1697
+32 660 660
+51 259 259
+49 168 168
+168 464 464
+45 446 446
+25 3886 3879
+67 800 800
+28 124 124
+29 1123 1123
+30 24987 23723
+2 1 1
+21 146 146
+2 1 1
+785 22543 22552
+67 3192 3170
+28 5357 5348
+397 8546 8565
+1251 3145 3145
+31 110 110
+29 2816 2816
+63 674 688
+48 195 195
+23 1511 1509
+47 1810 1786
+37 14 0
+41 533 533
+182 1 16
+5 20555 20281
+49 1 21
+55 54 52
+46 2763 2762
+37 5 2
+280 124045 123118
+495 0 1
+703 3 0
+87 27183 48462
+36 1182 1182
+389 16 16
+257 1 0
+118 3 3
+547 1 1
+25 1 1
+126 0 2
+3598 810 0
+148 0 6
+483 1 1
+34 1 1
+266 6 6
+350 2 2
+30 1 1
+297 4 4
+666 1 1
+89 1 1
+52 15 15
+2220 2647 2651
+53 53651 53634
+149 9850 9843
+39 1 1
+39 116984 481498
+39 653 653
+40 315 315
+29 616 616
+94 206 206
+114 65101 68610
+358 27 27
+588 11156 11155
+25 56460 137674
+105 1 0
+2251 13 13
+319 25 26
+826 25 25
+370 7 7
+439 0 1
+192 7 1
+250 0 13
+1302 1 8
+866 91 94
+91 14 14
+501 1 0
+1238 1 0
+113 475 60006
+212 8 10
+907 0 4
+350 1 0
+486 9 17
+448 0 2
+515 0 10
+788 13213 230
+199 16 16
+645 0 2
+112 37 25
+634
+
+chain 283844 5_h2_hap1 1794870 + 1261701 1280951 5 180915260 + 69698102 69815360 1487
+91 6326 96869
+318 0 10
+505 0 1
+204 64 64
+440 1 0
+235 0 1
+1269 0 1
+945 1 0
+670 242 551
+75 3 0
+1233 50 50
+199 4900 12045
+409 59 59
+310 37 40
+664
+
+chain 206667 5_h2_hap1 1794870 + 1287039 1295912 17 81195210 + 76583705 76597262 568754
+558 4 0
+365 2 2
+40 0 1
+253 1 1
+31 1 1
+522 6316 11003
+780
+
+chain 184822 5_h2_hap1 1794870 + 1284679 1286632 17 81195210 - 4506444 4508397 671275
+1953
+
+chain 128717 5_h2_hap1 1794870 + 1283006 1284382 5 180915260 + 70517839 70519212 1000883
+791 20 17
+565
+
+chain 128621 5_h2_hap1 1794870 + 1291852 1293214 17 81195210 + 76573863 76575225 1001637
+1362
+
+chain 122147 5_h2_hap1 1794870 + 627399 939358 5 180915260 - 110828619 111993762 93
+42 1752 1753
+58 6978 6974
+165 255 254
+37 4915 4915
+44 4384 4378
+64 19819 875253
+39 1 1
+9 264030 261784
+58 0 6
+56 6 6
+105 3 3
+98 1 1
+483 7968 7968
+62 497 497
+30
+
+chain 118081 5_h2_hap1 1794870 + 1290357 1291631 4 191154276 - 20442500 20443774 1089300
+230 18 18
+1026
+
+chain 112391 5_h2_hap1 1794870 + 1288972 1290160 17 81195210 - 4580707 4581894 1143267
+1134 1 0
+53
+
+chain 92982 5_h2_hap1 1794870 + 1293593 1294614 4 191154276 + 170627590 170628611 1373141
+72 1 1
+129 1 1
+818
+
+chain 75482 5_h2_hap1 1794870 + 1274745 1276419 5 180915260 - 111410923 111412615 820
+271 0 10
+350 0 6
+499 9 9
+444 0 2
+101
+
+chain 68300 5_h2_hap1 1794870 + 1276804 1279228 5 180915260 - 110416917 110419341 216
+2424
+
+chain 29652 5_h2_hap1 1794870 + 524804 525112 3 198022430 + 8519605 8519913 4781887
+308
+
+chain 29428 5_h2_hap1 1794870 + 756919 757240 2 243199373 + 16251117 16251431 4913030
+177 7 0
+137
+
+chain 27649 5_h2_hap1 1794870 + 641866 1186473 5 180915260 + 68929706 69564604 89
+32 351 351
+50 115 115
+44 114 114
+65 50 50
+111 61 61
+52 101 101
+42 14056 14883
+33 529303 618767
+27
+
+chain 20581 5_h2_hap1 1794870 + 1249367 1254462 5 180915260 - 111122604 111127700 1762
+2153 24 24
+85 8 8
+1086 0 1
+1739
+
+chain 5516 5_h2_hap1 1794870 + 253548 253608 5 180915260 + 68759177 68759237 7759123
+60
+
+chain 5218 5_h2_hap1 1794870 + 1244675 1244945 5 180915260 - 159621198 159621468 493
+30 1 1
+36 122 122
+81
+
+chain 4702 5_h2_hap1 1794870 + 1279881 1280287 5 180915260 + 70518261 70518663 9283
+59 311 307
+36
+
+chain 4436 5_h2_hap1 1794870 + 1274323 1274373 5 180915260 + 70526833 70526883 9273
+50
+
+chain 4277 5_h2_hap1 1794870 + 625682 625728 5 180915260 - 111701952 111701998 814
+46
+
+chain 3978 5_h2_hap1 1794870 + 1276419 1276466 5 180915260 + 70082181 70082228 137301
+47
+
+chain 3805 5_h2_hap1 1794870 + 1244816 1244863 5 180915260 + 69926901 69926948 475
+47
+
+chain 2924 5_h2_hap1 1794870 + 253608 253640 5 180915260 + 68759034 68759066 4803455
+32
+
+chain 943 5_h2_hap1 1794870 + 1282135 1282172 5 180915260 - 111121871 111121900 54522
+21 8 0
+8
+
+chain 692 5_h2_hap1 1794870 + 1276691 1276804 5 180915260 + 21496928 21497041 821
+113
+
+chain 13519395 5_random 143687 + 0 143687 5 180915260 + 180261930 180405660 222
+5859 0 4
+460 1 1
+23 0 2
+42 1 3
+42 1 1
+1633 55 55
+2271 0 10
+1279 2 0
+761 2 0
+25 1 1
+150 13 13
+4989 0 1
+1174 1 1
+23 1 1
+495 16 16
+2709 1 4
+349 0 4
+466 0 1
+292 2 0
+184 0 5
+621 13 13
+1788 2 0
+21 1 1
+731 12 12
+149 0 3
+5100 1 0
+1059 0 3
+1724 2 0
+4111 1 0
+890 4 4
+47 1 1
+1137 0 1
+147 17 19
+72 1 1
+22 1 1
+365 1 1
+19 2 2
+1360 0 1
+1476 1 1
+43 1 1
+1141 1 0
+2615 18 18
+4308 0 4
+135 0 2
+1484 8 6
+7384 0 11
+284 1 1
+69 1 1
+232 6 0
+1064 0 2
+4530 0 1
+4542 6 6
+10543 1 0
+4051 2 0
+11340 5 6
+4936 1 0
+12029 3 3
+43 1 1
+2955 27 27
+775 0 10
+822 1 0
+2057 1 0
+733 0 1
+4016 0 1
+4514 1 1
+49 1 1
+4484 1 0
+784 1 1
+25 1 1
+5707 2 0
+1274 1 0
+289 1 1
+34 1 0
+80
+
+chain 15799018021 6 170899992 + 5000 170896992 6 171115067 + 60000 171055067 6
+1297281 0 1
+7806978 162987 0
+4013144 0 9
+261 15 13
+18786172 17 17
+439 16 16
+59 4 5
+32202 17 17
+439 16 16
+59 5 4
+15403 0 1
+13914166 0 4
+115 1 1
+17 1 1
+415 0 12
+105 3 6
+12160281 50000 50000
+642507 3050000 3100000
+248423 50000 50000
+2918791 0 1238
+9427508 4 4
+162 12 12
+2193 22 22
+293 1 1
+30 1 1
+845 0 1
+45 1 1
+9769 0 2
+6058 1 1
+24 1 1
+2223 1 1
+24 1 1
+182 12 12
+284 1 1
+20 1 1
+970 1 1
+64 36 7
+575 43 43
+389 1 1
+27 1 1
+3279 1 1
+44 1 0
+3012 0 1
+545 17 17
+2562 1 0
+251 1 0
+943 0 8
+29 1 1
+566 0 6
+1483 0 2
+1960 0 1
+4564 1 1
+25 1 1
+832 1 0
+801 8 8
+1131 1 1
+58 1 5
+6177 1 0
+3712 0 1
+2185 1 1
+35 1 1
+710 2 2
+78 1 1
+2201 1 1
+30 1 1
+283 1 1
+30 1 1
+448 0 1
+75012 0 8
+2508457 0 1
+4641788 5 5
+37 1 1
+8503609 2 0
+5363169 200000 150000
+6040303 1 1
+36 0 1
+2020 1 1
+46 1 1
+1559 1 1
+72 1 1
+1098 1 1
+29 1 1
+264 7 7
+580 1 0
+30 1 1
+536 1 1
+41 1 1
+5663 0 1
+423 0 2
+372 1 1
+18 1 1
+9612 0 1
+1414 0 1
+176 2 0
+2742 0 1
+1968 1 0
+754 0 1
+4237 1 0
+2388 1 1
+31 0 1
+3385 1 0
+2004 0 8
+3395 3 0
+32 1 1
+4109 1 0
+1055 0 20
+1611 0 1
+17198424 26 17
+7835 1 0
+11119 1 1
+5197 0 11
+4791 1486 66479
+6787989 1 0
+149 0 4
+947 0 4
+244 1 0
+28418215 1 1
+21 0 1
+3116903 50000 171704
+1939305 1 1
+19 2 0
+8192274 4 4
+122 2 0
+1127 0 1
+1104 1 102
+18 0 29
+40 0 3
+22 1 4
+50 0 26
+56 18125 195105
+950946 1 157
+51 1 1
+104 0 255
+610 0 408
+104 0 105
+1285158 150028 50028
+725067
+
+chain 8374990 6 170899992 + 9109557 9199728 6 171115067 + 9164559 9254607 394
+3887 2 0
+1509 45 45
+888 7 8
+372 0 1
+4746 3 0
+1114 31 31
+140 35 35
+2111 13 13
+445 248 137
+1437 38 38
+55 25 25
+739 19 19
+2479 70 58
+1297 0 4
+7065 24 24
+542 31 31
+531 22 22
+824 0 1
+2286 40 39
+1209 48 48
+1435 6 0
+4096 4 0
+495 41 42
+6884 0 1
+3177 0 1
+2843 0 1
+904 5 5
+830 18 18
+1997 0 1
+942 4 0
+122 33 33
+1012 0 10
+3751 0 1
+5959 49 49
+4503 0 20
+7514 8 8
+4012 15 15
+673 16 0
+83 4 0
+424 3 0
+3932
+
+chain 892181 6 170899992 + 9258019 9267980 6 171115067 + 9150000 9160000 4430
+970 53 55
+802 16 17
+389 27 27
+73 5 4
+118 9 5
+615 0 2
+69 17 15
+578 0 1
+114 22 22
+888 130 130
+252 3 9
+564 0 1
+211 5 0
+90 4 0
+1846 21 21
+1832 0 42
+238
+
+chain 763150 6 170899992 + 9249728 9258019 6 171115067 + 9141295 9150000 6494
+566 0 1
+140 8 0
+205 47 47
+145 18 12
+46 1 0
+3841 0 56
+172 0 372
+444 18 18
+2447 20 20
+173
+
+chain 369937 6 170899992 + 9267980 9272102 6 171115067 + 9160000 9164126 144773
+1134 49 45
+1420 38 38
+203 0 4
+144 0 3
+115 54 55
+965
+
+chain 4624 6 170899992 + 9129966 9130015 6 171115067 + 165872977 165873026 28640892
+49
+
+chain 1407 6 170899992 + 74606704 74606747 X 155270560 + 149588561 149588604 701656
+6 11 11
+26
+
+chain 414456960 6_cox_hap1 4731698 + 0 4731698 6 171115067 + 28541283 33351542 27
+3409 1 0
+3526 0 1
+2940 0 4
+981 0 1
+4053 0 2
+1433 0 1
+3153 2 0
+369 0 1
+1090 0 1
+884 1 4
+363 1 0
+1969 0 1
+994 5 0
+58 1 1
+131 1 0
+4080 1 0
+680 0 1
+978 0 1
+1062 1 0
+2669 19 19
+7247 1 2
+1704 0 4
+1513 0 2
+49 2 0
+2160 0 5
+672 1 1
+38 1 1
+1384 1 0
+1685 1 1
+30 1 1
+2421 1 1
+42 1 1
+830 1 1
+41 1 1
+1630 0 1
+7458 1 0
+691 0 1
+525 0 1
+79 1 1
+29 1 1
+2055 1 1
+16 0 24
+1867 5 7
+786 0 2
+280 0 1
+227 2 0
+6678 1 0
+4401 1 0
+210 1 0
+3193 2 0
+3619 0 1
+2414 0 2
+5387 0 3
+2927 0 1
+3304 0 1
+440 0 5
+415 0 9
+3597 1 1
+48 1 1
+3412 1 1
+46 1 1
+3604 4 4
+1063 1 1
+36 1 1
+3511 6 6
+2797 32 41
+393 0 1
+477 1 1
+37 1 1
+2459 2 0
+517 0 12
+318 0 1
+1010 7 6
+2103 0 1
+5171 0 8
+1483 1 0
+3813 888 0
+4675 0 2
+5620 1 0
+2017 1 0
+3363 0 5
+1197 0 3
+3208 1 0
+1928 1 0
+174 6 0
+780 1 3
+443 14 0
+3079 0 5
+1993 0 3
+1089 1 1
+58 1 1
+80 0 8
+256 2 0
+2473 37 43
+752 0 2
+33 0 2
+825 0 1
+787 1 1
+37 1 1
+1168 16 0
+377 5 1
+27 1 1
+2161 2 0
+636 25 25
+1663 1 0
+1757 6 6
+205 4 0
+203 7 7
+107 1 1
+28 1 1
+100 4 4
+258 5 0
+659 1 0
+3805 5 8
+1486 4 4
+213 39 43
+4429 0 2
+1199 13 13
+5803 12 0
+2987 0 1
+813 0 17
+920 2 0
+3820 1 3
+130 21 9
+1913 0 14
+1800 0 1
+1255 2 0
+1466 4 0
+747 0 1
+124 2 0
+2108 1 0
+169 0 26
+593 1 0
+632 5 0
+2711 0 4
+1042 0 1
+34 1 1
+1025 2 0
+27 4 18
+81 1 33
+33 0 1
+6 0 76
+3950 1 0
+86 1 1
+12 1 1
+2947 0 1
+1160 1 0
+2046 3 0
+720 1 0
+1341 1 0
+10205 0 5
+1265 1 0
+10 1 1
+1278 5 6
+399 0 32
+96 16 18
+605 4 0
+1072 12 12
+950 11 7
+5128 9 10
+2711 1 0
+676 0 1
+2904 1 1
+30 1 1
+851 0 1
+1410 0 1
+394 1 1
+57 1 1
+1561 0 2
+11062 1 1
+58 1 1
+3238 1 1
+42 1 1
+269 1 0
+284 3 3
+24 1 0
+2796 0 5
+2451 28 0
+2251 1 1
+32 1 0
+10 0 4
+24 1 1
+694 0 2
+3475 0 1
+2008 1 1
+49 1 1
+475 1 1
+28 1 1
+259 160 0
+1858 1 0
+1621 3 0
+1791 1 0
+316 0 2
+1169 0 1
+2549 1 0
+2941 1 1
+34 1 1
+243 9 0
+5157 0 2
+1748 0 8
+472 4 0
+2470 0 4
+402 1 0
+643 2 0
+748 0 2
+859 1 0
+409 2 0
+267 0 2
+322 0 4
+155 1 0
+9957 0 4
+1440 4 4
+127 1 0
+1085 1 0
+131 1 0
+767 1 0
+1160 21 21
+1294 1 0
+712 1 0
+1819 2 1
+464 1 0
+6944 0 4261
+55 0 7
+1235 0 3
+702 0 24
+2847 0 1
+2428 3 0
+7517 0 1
+3204 1 0
+611 1 0
+7104 1 0
+4959 14 14
+2827 1 0
+9421 82 25
+4428 8 0
+5987 41 41
+2108 0 2
+344 1 0
+4216 1 0
+810 0 5
+4443 1 0
+10291 10 0
+7265 5 0
+7041 1 0
+6007 1 0
+8185 4 0
+4961 0 3
+13564 0 1
+1475 0 2
+105 0 10
+10104 2 0
+3073 1 0
+3715 8 0
+2246 24 24
+11461 0 2
+837 61 1
+7660 39 39
+1705 0 1
+6068 7 0
+916 0 4
+569 1 1
+72 1 1
+2260 0 2
+7036 4 0
+3591 0 3
+713 4 0
+7058 11 11
+3319 0 2
+8475 0 1
+1324 0 2
+5438 5 0
+156 1 1
+44 0 1
+21501 7 7
+3359 16 16
+2138 0 5
+4406 11 11
+1525 1 1
+28 1 1
+2159 16 0
+48 4 0
+3030 0 1
+5717 10 0
+6594 2 0
+648 31 31
+1275 1 0
+4 1 0
+3599 1 0
+7515 4 0
+979 0 2
+1990 0 10
+123 1 1
+27 1 1
+1255 0 2
+2769 5 5
+727 1 1
+26 3 3
+785 0 1
+8871 29 29
+15459 1 0
+5978 5 5
+66 1 1
+46 1 1
+18539 1 0
+7732 2 0
+652 0 1
+861 0 1
+10658 17 17
+1313 0 1
+3515 3 0
+19 18 0
+539 0 1
+655 2 0
+10586 2 0
+2385 0 1
+7589 1 0
+29834 1 1
+27 1 1
+1216 1 0
+1323 1 0
+673 0 3
+20031 0 3
+2841 13 0
+1841 4 0
+6446 1 0
+11727 0 1
+8427 17 17
+2864 0 143
+4107 0 8
+748 0 2
+3417 1 1
+32 1 1
+18799 0 2
+21810 1 1
+34 1 1
+2784 2 0
+7864 2 0
+4498 0 1
+49089 1 1
+32 1 1
+509 1 1
+37 1 1
+5371 22 16
+389 1 1
+21 1 1
+806 1 0
+1638 6 6
+228 1 1
+45 1 1
+2068 6 3
+441 1 0
+2338 1 0
+1948 1 1
+26 1 1
+214 0 1
+6118 1 1
+31 1 1
+2382 5 5
+4335 1 1
+39 1 1
+4561 1 1
+38 1 1
+2199 1 1
+49 1 1
+243 19 6
+2779 1 1
+37 2 0
+24 1 1
+1966 3 0
+233 1 1
+29 1 1
+13756 0 4
+3956 4 1
+33765 46 46
+12758 1 0
+18985 0 8
+1384 3 1
+85 1 0
+3539 1 1
+32 1 1
+145 1 0
+1245 2 0
+1736 80 80
+1607 1 5
+712 10 11
+502 0 1
+3670 1 0
+740 0 1
+1693 0 1
+6497 0 2
+2898 1 3
+141 0 1
+1108 0 2
+1448 1 0
+1340 0 1
+7616 74 66
+2882 1 2
+30 8 0
+896 21 3
+395 1 1
+37 3 0
+23 1 2
+1210 18 0
+65 1 1
+20 1 1
+791 0 4
+389 1 0
+809 1 1
+55 0 7
+428 1 1
+17 1 1
+239 1 1
+20 1 1
+69 1 1
+37 1 1
+955 1 0
+839 0 1
+165 1 0
+3867 0 5
+70 1 1
+27 1 1
+899 1 2
+107 1 0
+1457 1 0
+763 12 5
+35 1 1
+1417 10 10
+121 1 1
+38 0 3
+377 1 0
+325 2 2
+178 1 0
+11 4 0
+297 0 24
+337 11 0
+134 1 1
+694 3 0
+72 1 1
+144 1 1
+96 1 1
+199 2 0
+1011 1 0
+107 1 1
+1280 1 1
+73 1 1
+84 25 25
+287 1 1
+26 1 1
+139 1 1
+41 1 1
+440 4 0
+130 12 12
+435 21 0
+85 1 1
+28 1 1
+73 1 1
+61 1 1
+53 5 1
+70 1 2
+52 2 0
+157 30 30
+554 2 2
+128 1 5
+68 1 1
+44 1 1
+125 0 1
+57 1 1
+308 0 7
+15 1 1
+725 9 0
+60 1 1
+180 1 1
+55 1 1
+61 1 1
+23 1 0
+5 1 2
+88 1 1
+56 1 1
+433 2 0
+84 68 68
+182 12 12
+216 1 1
+94 1 1
+561 1 1
+16 1 1
+113 1 1
+86 1 1
+148 2 0
+75 2 0
+77 1 21
+209 3 8
+374 1 0
+173 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+327 1 1
+54 5 5
+929 1 1
+21 1 1
+97 1 1
+28 0 3
+830 0 2
+68 1 1
+525 0 1
+2081 1 1
+41 1 1
+165 3 3
+46 1 0
+378 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 41 41
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+240 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+321 1 1
+63 1 1
+504 18 18
+662 1 1
+74 1 1
+248 1 1
+34 1 1
+1507 0 10
+1051 0 2611
+560 3 3
+23 1 1
+1631 0 15
+78 4 0
+160 0 21
+3764 0 4
+1358 0 1
+1773 1 1
+43 1 1
+1263 1 1
+39 1 1
+183 0 16
+4097 10 0
+1261 1 1
+20 1 1
+137 1 0
+2351 1 1
+43 1 1
+1010 0 4
+536 1 1
+38 1 1
+381 0 1
+888 19 19
+1521 1 1
+27 1 1
+161 1 1
+46 1 1
+2659 2 0
+533 10 0
+441 1 12
+1684 1 1
+26 3 4
+879 16 16
+514 0 2
+58 1 1
+117 1 1
+24 1 1
+207 1 0
+38 1 1
+730 1 1
+39 1 1
+429 10 10
+134 0 4
+37 1 1
+144 8 8
+1036 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+317 0 3
+1256 0 2
+332 1 1
+21 1 1
+193 8 28
+30 1 1
+79 1 1
+29 1 1
+536 1 0
+611 1 1
+25 1 1
+399 4 4
+118 0 32
+23 1 1
+116 1 1
+30 1 1
+503 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 4
+711 7 7
+89 1 0
+293 7 6
+159 1 1
+24 1 1
+167 6 6
+171 17 17
+681 1 1
+43 1 1
+538 1 1
+44 1 1
+537 16 16
+180 6 6
+778 2 2
+44 1 1
+168 0 7
+211 1 1
+42 1 1
+1253 1 1
+29 1 1
+320 1 1
+36 2 2
+55 1 2
+460 1 1
+35 1 1
+553 8 8
+386 1 1
+26 1 1
+540 1 1
+31 1 1
+65 0 1
+625 12 12
+313 0 1
+52 1 1
+22 1 1
+583 1 1
+49 1 1
+678 37 37
+784 3 0
+770 1 1
+87 11 0
+1129 1 1
+36 1 1
+553 8 8
+997 16 15
+157 1 1
+31 2 2
+204 18 19
+487 1 1
+29 1 1
+374 1 1
+67 1 1
+720 13 13
+266 10 10
+330 16 14
+413 1 1
+44 1 1
+78 6 6
+181 2 2
+36 1 1
+397 1 1
+20 1 1
+311 1 1
+48 2 2
+1298 11 11
+437 4 4
+35 1 1
+194 10 10
+310 1 1
+51 1 1
+136 1 1
+49 1 1
+521 1 1
+23 1 1
+220 1 1
+71 1 1
+1046 15 15
+216 1 1
+21 1 1
+51 1 1
+49 1 1
+527 17 17
+340 12 11
+1025 1 0
+2572 1 1
+29 1 1
+397 2 5
+668 13 13
+541 1 1
+59 0 2
+6 1 1
+122 14 14
+51 1 1
+46 1 1
+72 5 5
+352 0 21
+136 1 1
+12 1 1
+66 16 16
+456 37 34
+371 7 7
+48 1 1
+194 10 10
+108 1 1
+60 1 1
+122 0 1
+48 1 1
+238 1 1
+32 0 1
+100 1 0
+72 1 0
+390 1 1
+38 1 1
+144 1 1
+27 0 4
+184 21 228
+49 1 1
+608 0 1
+152 1 1
+31 1 1
+281 8 8
+337 1 1
+45 1 1
+222 1 1
+20 1 1
+380 1 0
+44 1 1
+368 1 1
+72 1 1
+502 36 18
+63 1 1
+43 0 4
+136 1 1
+42 1 1
+80 4 4
+35 1 0
+89 1 1
+24 0 5
+829 13 13
+102 14 0
+233 1 1
+42 0 3
+85 0 1
+400 1 1
+40 1 1
+538 25 25
+174 1 1
+20 1 1
+705 1 1
+26 2 2
+614 1 1
+44 1 1
+509 1 1
+32 1 1
+224 1 1
+42 1 1
+747 5 5
+804 1 1
+29 1 1
+166 1 1
+43 1 1
+233 1 1
+44 1 1
+620 8 8
+133 1 1
+31 1 1
+165 1 1
+29 1 1
+1249 1 1
+26 4 0
+56 1 1
+67 1 1
+716 1 1
+46 0 1
+16 1 1
+174 1 1
+96 1 1
+141 1 1
+39 0 4
+263 1 1
+18 1 1
+259 4 4
+38 1 1
+104 1 1
+40 1 0
+248 1 1
+18 1 1
+238 1 1
+32 1 1
+70 0 2
+16 1 1
+818 1 1
+22 4 4
+1641 1 1
+46 1 1
+53 1 0
+38 1 1
+373 1 1
+60 1 1
+1149 0 2
+19 1 1
+1653 4 4
+42 1 1
+218 12 12
+363 1 1
+24 1 1
+457 10 10
+414 13 13
+825 1 1
+41 1 1
+492 0 8
+1370 1 1
+18 1 1
+808 2 2
+335 6 4
+880 1 1
+35 1 1
+236 1 1
+67 1 1
+298 0 1
+147 4 4
+322 11 11
+613 1 1
+62 1 1
+340 1 1
+22 1 1
+1057 1 1
+57 1 1
+358 1 1
+128 1 1
+146 10 10
+490 1 1
+20 1 1
+62 1 1
+88 1 1
+293 1 1
+28 1 0
+20 1 1
+83 0 1
+90 1 1
+312 1 1
+44 1 1
+1213 1 1
+51 1 1
+467 1 1
+39 1 1
+122 14 0
+35 1 1
+485 14 14
+110 13 0
+127 1 1
+7150 9 13
+3278 0 2
+28 1 1
+2211 1 0
+1325 18 18
+1304 3727 0
+299 0 248
+2603 2 0
+160 1 1
+34 1 1
+631 1 1
+40 1 3
+38 1 1
+332 17 17
+231 14 14
+202 1 1
+199 1 1
+71 1 1
+42 1 0
+53 11 10
+82 34 34
+135 1 1
+50 3 0
+32 1 1
+194 1 1
+45 1 1
+143 1 1
+78 1 1
+193 6 0
+40 1 1
+432 1 1
+17 1 1
+429 3 6
+58 1 1
+85 1 1
+62 1 1
+85 1 1
+57 1 1
+51 2 2
+278 1 1
+49 1 1
+77 11 11
+120 0 4
+139 1 1
+30 2 2
+205 4 4
+131 1 1
+22 1 1
+251 1 1
+34 1 1
+175 1 1
+36 1 1
+239 1 1
+32 5 5
+63 1 1
+27 1 1
+78 1 1
+19 1 1
+209 1 1
+143 1 13
+176 0 1
+7 0 8
+375 0 1
+62 1 1
+129 2 2
+135 1 1
+88 8 0
+90 6 8
+796 2 0
+1219 1 1
+34 1 1
+833 1 1
+46 1 1
+74 1 1
+45 1 1
+95 1 1
+29 1 1
+298 0 3
+47 1 1
+311 1 1
+58 1 1
+349 15 15
+208 1 1
+37 3 0
+413 11 11
+54 1 1
+97 1 1
+137 0 2
+95 1 1
+257 3 0
+35 1 1
+66 1 1
+47 1 1
+104 7 7
+220 17 17
+228 4 4
+432 1 1
+34 3 3
+175 4 4
+26 1 2
+116 7 7
+60 13 13
+137 1 1
+44 1 1
+744 1 1
+29 1 1
+148 0 5
+30 1 1
+387 1 1
+22 1 1
+309 1 1
+82 1 1
+52 1 1
+32 1 1
+121 1 1
+37 1 1
+396 3 2
+324 1 1
+92 1 1
+51 9 9
+71 7 7
+24 1 1
+115 1 1
+101 1 1
+799 12 12
+197 1 1
+146 1 1
+103 1 1
+134 1 1
+16 1 1
+378 1 1
+85 1 1
+134 1 1
+25 1 1
+54 3 3
+55 1 1
+67 1 1
+22 1 1
+54 13 13
+55 11 11
+120 1 1
+23 1 1
+51 1 1
+22 1 1
+369 1 1
+273 1 1
+119 6 6
+229 34511 40178
+78 1 1
+22 1 1
+180 1 1
+33 1 2
+26 6 6
+474 1 1
+36 1 1
+151 1 1
+29 1 1
+120 1 1
+23 1 1
+865 1 1
+39 1 1
+330 1 1
+24 1 1
+197 1 1
+69 1 1
+116 3 0
+161 1 1
+38 1 1
+753 1 1
+57 3 3
+145 1 1
+121 1 1
+300 1 1
+147 1 1
+379 1 1
+55 2 2
+65 1 1
+32 1 1
+1008 1 1
+24 1 1
+159 18 18
+659 1 1
+76 0 2
+77 1 3
+65 1 1
+84 1 0
+119 1 1
+15 1 1
+247 4 0
+372 1 0
+1633 1 1
+16 1 1
+221 9772 11561
+315 1 1
+53 1 1
+67 1 1
+91 1 0
+23 1 0
+27 2 2
+66 2 2
+80 0 41
+12 1 1
+158 1 0
+92 2 0
+254 1 1
+43 1 1
+846 6 149
+84 1 1
+29 3 3
+315 17 17
+482 1 1
+29 3 3
+278 1 1
+73 1 1
+2767 1 1
+34 1 1
+192 1 1
+33 1 0
+168 6 0
+276 10 10
+344 1 1
+49 1 1
+109 1 1
+35 3 3
+561 24 27
+923 1 1
+102 1 1
+75 14 14
+266 1 1
+80 2 2
+185 1 0
+1035 1 1
+23 1 1
+417 10 10
+97 1 1
+94 1 1
+492 1 1
+37 5 5
+1429 1 1
+19 1 1
+839 1 1
+96 1 1
+1279 4 0
+683 1 1
+49 1 1
+514 1 1
+28 4 4
+2302 1 1
+42 1 1
+537 2 21
+1555 1 1
+42 0 1
+14 4 4
+86 1 1
+62 1 1
+515 5 1
+330 0 1
+159 0 22
+3841 1 0
+5065 12 12
+97 0 3
+772 1 1
+21 2 1
+1058 0 2
+349 2 0
+1080 6 0
+11 1 3
+53 0 2
+14 1 1
+1035 1 1
+85 1 1
+69 1 1
+27 1 1
+547 7 7
+195 1 1
+41 1 1
+395 1 1
+35 1 1
+73 0 1
+71 1 1
+557 3 3
+30 1 1
+66 49 49
+1310 0 2
+26 2 0
+10 1 15
+36 1 1
+196 1 1
+40 1 1
+141 1 1
+76 1 1
+1480 1 3
+347 1 1
+26 1 1
+231 1 1
+82 3 3
+69 3 0
+441 16 16
+147 1 1
+21 1 1
+3565 0 3
+877 2 0
+1036 1 1
+47 2 1
+3761 12 0
+5345 1 0
+11541 1 0
+1843 0 4
+1157 16 16
+7354 19 0
+736 0 1
+8058 1 0
+4449 21 21
+649 1 0
+2913 0 1
+381 331 0
+6066 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3870 0 1
+36 13 0
+1894 1 1
+40 0 4
+1137 6 0
+211 2 0
+345 1 0
+592 4 4
+1043 4 0
+686 14 0
+1032 0 1
+9035 0 4
+167 0 2
+19472 35 35
+4457 0 3
+1470 0 1
+289 3 0
+3780 41 41
+522 1 0
+2026 8 0
+430 0 1
+631 1 1
+21 1 1
+479 0 1
+697 4 0
+1779 1 1
+27 1 1
+196 4 0
+58 8 0
+2881 1 1
+39 1 1
+120 44 45
+538 1 0
+393 6 6
+3090 1 1
+43 1 1
+1246 1 0
+294 1 1
+27 1 1
+374 3 3
+144 1 1
+190 1 6
+750 1 0
+695 2 0
+1003 11 0
+1185 8 8
+763 0 4
+2737 11 11
+453 1 0
+536 1 1
+43 1 1
+57 1 0
+21 7 0
+3892 0 1
+3177 0 1
+8990 0 2
+2303 1 0
+2850 4 0
+1273 0 2
+5863 1 0
+9593 1 1
+81 1 1
+2777 0 2
+4564 34 34
+674 0 8
+11548 2 0
+6086 0 1
+109 1 1
+2286 0 1
+997 0 18
+3344 1 1
+40 1 1
+842 28 24
+1584 1 0
+1582 0 1
+1670 3 25
+17 0 4
+16 2 0
+6 12 0
+49 1 1
+538 1 1
+26 1 1
+5879 2 4
+2513 0 1
+346 8 8
+222 16 16
+103 1 0
+198 1 3
+539 1 1
+47 1 1
+1154 0 1
+3737 1 2
+370 2 0
+1178 1 1
+78 1 1
+47 0 1
+518 6 0
+646 13 13
+469 1 0
+1072 1 4
+858 1 0
+3674 1 0
+282 1 0
+597 0 6
+505 4 4
+183 1 1
+43 1 1
+1294 1 1
+40 1 1
+572 0 4
+464 0 4
+757 40 40
+1089 2 0
+548 1 0
+1300 0 3
+1839 2 0
+189 1 1
+49 1 1
+1253 1 1
+43 1 0
+498 1 1
+45 4 0
+3538 0 1
+1989 14 14
+1332 2 0
+3586 1 0
+989 1 2
+447 0 4
+40 1 1
+2445 16 17
+291 1 3
+7 1 0
+11 0 1
+41 1 1
+94 1 1
+49 1 1
+1515 6 0
+603 13 13
+163 1 1
+45 1 1
+2050 11 11
+1126 1 1
+16 1 1
+391 1 1
+19 0 1
+932 1 0
+42 1 1
+751 1 0
+287 1 1
+42 1 1
+464 0 4
+4069 5 5
+153 1 0
+514 2 0
+1093 1 1
+41 1 1
+1746 4 4
+1351 1 1
+38 1 1
+682 12 12
+519 0 72
+168 18 18
+146 7 7
+293 1 1
+61 0 1
+43 1 1
+236 1 0
+35 1 1
+152 14 14
+776 0 4
+809 4 0
+155 1 1
+44 1 1
+1068 1 1
+93 1 1
+209 15 15
+1331 0 3
+3912 0 1
+6624 0 4
+375 0 1
+7255 5 0
+419 2 0
+293 1 0
+10397 5 24
+11095 0 1
+1770 4 0
+374 0 4
+7714 1 0
+1229 7 6
+3055 1 0
+5818 1 0
+2415 11 9
+2056 0 1
+955 4 0
+3907 0 2
+16936 0 1
+1044 1 0
+2392 0 1
+158 2 1
+199 0 1
+75 6 6
+2094 8 0
+649 2 0
+373 75 75
+2253 1 0
+15 1 0
+1995 0 2
+818 4 0
+676 0 1
+3171 8 0
+170 0 3
+459 1 1
+37 1 1
+336 1 0
+206 1 1
+26 1 1
+224 15 15
+308 2 1
+82 1 1
+23 1 1
+562 1 1
+80 1 1
+241 0 8
+1530 1 1
+20 1 1
+1372 1 1
+44 1 1
+427 1 1
+20 1 1
+651 105 81
+221 1 1
+45 1 1
+1747 1 1
+27 1 1
+179 1 1
+70 1 1
+173 1 1
+84 0 36
+1864 1 1
+41 1 1
+44 9 0
+1028 1 0
+85 1 1
+21 1 1
+475 0 2
+256 1 1
+31 1 1
+653 1 1
+18 1 1
+62 1 1
+19 1 1
+997 1 1
+22 1 1
+326 1 0
+505 5 4
+386 0 7
+466 13 13
+870 11 12
+134 15 15
+248 0 2
+2281 1 1
+79 1 1
+56 9 6
+498 100 100
+802 1 0
+290 1 1
+38 1 1
+185 1 1
+61 1 1
+944 1 1
+22 1 1
+835 1 1
+66 1 1
+890 0 1
+3503 6 6
+231 0 1
+2136 1 0
+999 1 0
+5220 3 4
+830 1 1
+24 1 1
+1209 1 1
+38 1 1
+7077 1 0
+2939 1 0
+3959 0 2
+3746 0 2
+1011 1 1
+34 1 1
+7443 0 1
+688 2 0
+574 1 1
+29 1 1
+1785 2 0
+16 20 0
+4073 2 0
+136 1 1
+77 1 1
+528 27 0
+253 0 1
+204 1 0
+129 2 0
+811 1 1
+38 1 1
+2347 52 0
+4634 1 0
+856 14 14
+1052 1 1
+28 1 1
+1255 1 1
+36 1 1
+97 0 1
+58 1 1
+1708 1 1
+48 1 1
+958 13 0
+3371 1 1
+37 1 1
+4267 0 15
+1059 0 1
+272 0 20
+168 2 0
+26 4 32
+4090 0 2
+3269 1 1
+17 1 2
+1378 1 0
+1443 0 1
+6206 1 0
+2318 0 1
+7695 2 0
+396 22 12
+918 0 1
+1818 0 1
+28 1 1
+492 1 1
+33 1 1
+326 1 1
+80 1 1
+288 8 17
+2671 0 1
+1099 0 1
+144 1 1
+29 0 1
+2098 0 2
+24 4 0
+1207 4 4
+45 1 1
+757 0 5
+1926 1 1
+40 1 1
+2657 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+713 0 4
+58 1 0
+1041 3 0
+36 1 1
+377 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+8189 4 5
+36 1 1
+102 2 0
+14 1 1
+682 0 6
+147 0 1
+750 0 3
+40 1 1
+2428 0 1
+750 2 0
+473 0 2
+2032 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+11881 1 1
+30 1 1
+4383 2 0
+6883 49 49
+3146 0 1
+906 2 0
+887 1 1
+80 1 1
+2210 1 0
+905 0 1
+1037 1 0
+5866 0 2
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 4 0
+3170 1 0
+1751 0 1
+910 2 0
+691 0 1
+32873 0 1
+1722 0 1
+17559 16 24
+1369 29 0
+494 2 0
+4432 0 1
+23680 26 26
+10911 0 1
+920 0 1
+4586 0 2
+2232 1 0
+5718 0 1
+12415 1 1
+51 0 1
+7997 0 2
+1700 1 0
+2697 1 0
+2561 2 0
+1544 0 6
+1613 3 7
+37 9 1
+2113 1 0
+7174 0 34
+7914 1 1
+35 1 1
+5308 1 0
+2303 2 1
+423 7 7
+590 1 0
+24 1 1
+165 6 0
+2848 13 13
+64 0 1
+28 1 1
+723 0 4
+2868 0 1
+731 1 1
+60 1 1
+1012 3 0
+490 29 29
+1225 1 1
+78 1 1
+61 1 0
+2362 11 11
+399 1 0
+1494 16 16
+128 24 24
+530 1 1
+35 1 1
+5276 1 0
+415 0 1
+580 1 2
+1450 22 23
+816 1 0
+1953 1 0
+881 10 1
+885 8 14
+183 14 14
+1139 25 25
+155 1 1
+94 1 1
+419 3 3
+26 1 1
+56 1 0
+69 1 0
+117 1 1
+120 1 1
+42 1 1
+825 0 2
+108 1 1
+24 1 1
+956 3 0
+664 1 1
+41 1 1
+716 4 0
+1731 8 8
+4228 0 1
+5694 3 0
+4493 0 1
+2656 1 0
+3029 4 0
+5688 1 0
+170 2 0
+5972 0 2
+840 0 2
+55 1 1
+28 1 1
+2954 0 1
+4343 6 0
+1663 4 0
+150 1 0
+3128 1 0
+1449 3 0
+1534 1 0
+489 1 0
+431 0 4
+299 2 0
+5082 9 0
+413 0 1
+989 0 2
+4941 0 1
+6655 1 0
+349 8 7
+762 1 1
+29 0 3
+1434 0 1
+1267 0 1
+587 1 1
+22 0 1
+894 28 0
+1343 2 0
+2256 0 1
+4332 0 4
+22 1 1
+12415 12 10
+10485 0 1
+1429 0 12
+625 1 7
+1224 0 10
+1680 4 0
+5169 14 14
+3878 0 8
+2544 0 140
+9238 0 1
+1575 0 3
+1775 1 1
+31 1 1
+1200 1 0
+32 0 3
+797 0 8
+35 0 2
+599 1 1
+22 1 1
+5338 2 0
+1998 0 5
+146 0 4
+12031 0 1
+1993 0 1
+706 2 0
+2735 0 1
+3859 0 4
+4845 0 2
+268 2 0
+827 4 4
+1063 6 6
+7834 2 0
+3195 0 1
+4012 10 0
+6429 0 2
+308 0 1
+808 1 0
+17 8 0
+5472 19 2
+2436 0 14
+820 9 9
+2643 1 1
+32 1 1
+1189 1 0
+5710 0 3
+308 1 0
+4930 0 1
+4308 1 0
+946 82 0
+1790 0 2
+1218 25 0
+52 0 1
+1271 1 1
+33 1 1
+4760 1 0
+4924 0 1
+4817 4 4
+39 1 0
+1116 3715 901
+205 1 0
+1591 5 2
+138 2 2
+16 1 1
+802 0 89
+1600 0 6
+2175 0 5
+606 14 14
+519 1 0
+540 1 1
+40 1 1
+568 2 0
+458 1 1
+41 1 1
+1106 24 62
+818 1 1
+42 1 1
+2266 1 0
+14059 0 4
+5030 1 0
+12630 0 3
+84 9 9
+129 13 18
+564 10 15
+154 1 0
+438 10 10
+38 0 5
+98 11 9
+2034 1 1
+25 1 1
+73 10 10
+70 5 5
+132 1 1
+52 1 1
+599 1 1
+46 1 1
+279 1 1
+18 1 1
+239 3 0
+383 6 0
+224 0 1
+321 15 0
+1783 1 1
+18 3 0
+108 1 1
+60 1 1
+405 16 16
+60 1 1
+16 1 1
+970 1 1
+24 1 1
+424 3 0
+41 1 1
+57 8 8
+285 2 0
+672 1 1
+44 1 4
+103 0 1
+148 1 1
+49 3 0
+146 5 11
+91 1 1
+79 1 1
+94 1 1
+101 1 1
+88 16 16
+117 1 1
+15 1 1
+58 1 1
+93 1 1
+466 1 1
+44 1 1
+160 1 1
+23 1 1
+481 14 14
+181 4 4
+72 1 1
+25 1 1
+82 7 12
+4 0 1
+11 1 4
+20 0 5
+92 1 1
+56 10 0
+80 1 1
+141 2 0
+60 1 1
+372 0 2
+784 1 1
+85 1 1
+109 1 1
+16 1 1
+57 1 1
+92 3 1
+23 1 0
+26 1 1
+74 1 1
+33 1 1
+176 1 1
+25 2 2
+193 1 1
+35 0 1
+383 0 5
+249 1 1
+69 1 1
+98 1 1
+70 1 1
+55 1 1
+143 1 1
+438 1 1
+64 1 1
+53 4 0
+127 3 0
+75 5 5
+45 1 1
+197 1 1
+27 1 1
+116 13 13
+218 15 20
+1107 16 19
+73 1 1
+101 1 1
+123 1 1
+60 1 1
+994 1 1
+43 0 1
+18 1 1
+1215 18 18
+340 1 1
+34 1 1
+1350 16 16
+1417 1 1
+29 1 1
+475 1 1
+48 1 1
+198 10 10
+87 1 1
+18 1 1
+171 7 7
+427 1 1
+21 1 1
+2011 0 3
+17 1 1
+1412 1 1
+24 1 1
+214 8 4
+228 1 1
+34 1 1
+410 16 16
+185 1 1
+24 1 0
+164 0 1
+222 1 1
+25 1 1
+297 10 10
+1171 1 0
+569 19 19
+2755 1 0
+11 1 1
+2502 1 1
+23 1 1
+44 12 0
+2856 0 1
+148 1 1
+36 1 1
+993 2 0
+1251 2 0
+6619 14 14
+1014 4 0
+134 2 9
+818 1 0
+61 1 7
+563 46 0
+78 5 5
+1677 1 1
+49 1 1
+399 1 1
+32 1 1
+790 27 27
+104 1 1
+75 1 1
+1638 1 1
+16 1 1
+92 1 1
+44 1 1
+276 0 13
+1020 1 1
+35 1 1
+389 14 14
+256 1 0
+38 1 3
+631 1 1
+40 1 1
+2356 85 83
+1300 0 5
+511 0 2
+605 1 1
+17 1 1
+880 12 0
+1689 4 0
+2492 1 1
+39 1 1
+641 16 16
+682 0 5
+669 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+498 3 0
+321 0 1
+281 3 0
+450 1 1
+34 1 1
+498 1 1
+28 2 1
+280 0 2
+648 1 1
+47 1 1
+1002 4 0
+120 1 1
+1538 0 1
+75 1 1
+37 1 1
+510 91 91
+60 18 18
+2075 1 1
+19 1 1
+2429 1 1
+21 1 1
+107 1 0
+2786 0 2
+31 5 5
+1973 12 0
+3118 1 0
+246 0 1
+33 1 1
+6752 1 0
+822 2 9
+606 1 1
+18 1 1
+3920 1 1
+37 0 2
+4497 10 13
+301 20 20
+2130 1 1
+16 3 0
+1843 0 4
+3780 3 0
+850 0 1
+2774 0 3
+2065 0 1
+20 1 1
+1400 1 0
+3243 0 15
+1336 5 0
+448 49 49
+121 7 7
+1507 8 7
+422 1 0
+2184 0 1
+304 0 2
+19 0 1
+101 1 1
+417 3 3
+22 1 1
+672 4 4
+31 1 1
+150 1 1
+38 1 1
+161 5 0
+17 1 1
+72 1 0
+106 1 1
+463 1 1
+94 1 1
+138 3 4
+185 1 1
+29 1 1
+220 15 15
+167 1 1
+32 1 1
+93 1 3
+217 1 1
+23 1 1
+137 9 9
+62 0 3
+353 1 1
+27 1 1
+117 9 9
+421 1 1
+47 1 1
+124 0 1
+997 6 0
+54 5 5
+764 1 1
+45 1 1
+1431 7 7
+387 6 6
+1103 0 36
+767 1 1
+31 1 3
+208 5 5
+1610 1 1
+23 1 1
+779 0 8
+324 0 2
+45 1 1
+264 0 3
+45 1 1
+250 1 1
+18 1 1
+517 33 0
+117 1 1
+42 1 1
+550 1 1
+20 1 1
+671 1 1
+68 1 1
+89 1 1
+104 1 1
+172 0 1
+124 0 1
+522 0 1500
+466 5 5
+32 1 0
+171 1 1
+19 1 1
+67 1 1
+22 1 1
+654 1 1
+25 1 1
+68 1 1
+21 4 0
+1588 1 1
+66 1 1
+401 0 1
+186 1 1
+21 1 1
+168 0 1
+686 3 0
+19 1 1
+127 1 1
+29 1 1
+234 1 1
+30 1 1
+141 0 2
+33 1 1
+673 1 1
+89 1 1
+161 16 16
+504 20149 20139
+1269 1 1
+40 1 1
+327 1 1
+24 1 1
+172 2 2
+27 11 15
+381 10 11
+376 1 1
+45 1 1
+121 1 1
+62 1 1
+289 1 1
+26 1 1
+191 1 1
+20 11 11
+425 1 1
+37 1 1
+296 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+306 1 1
+24 1 1
+1299 1 1
+47 1 1
+2026 1 1
+20 1 1
+133 1 0
+9803 0 4
+15871 3 0
+2464 1 1
+24 1 1
+879 1 1
+73 1 1
+89 1 1
+42 1 1
+108 1 1
+43 0 1
+26 1 1
+511 5 6
+605 19531 20105
+55 1 1
+37 0 2
+89 1 1
+51 1 1
+85 1 1
+78 1 1
+173 1 1
+51 1 1
+90 3 3
+95 1 1
+32 1 1
+53 1 1
+231 1 0
+82 2 0
+27 0 1
+44 1 0
+96 10 7
+132 1 1
+233 1 1
+257 1 1
+56 5 5
+237 1 1
+141 1 1
+92 1 1
+154 7 7
+3208 1 1
+33 1 1
+671 1 1
+21 1 1
+955 0 3
+130 1 1
+26 1 1
+288 8 8
+218 0 3
+1076 8 0
+609 10041 10021
+240 2 2
+66 1 1
+228 1 1
+23 1 1
+1612 1 1
+21 1 1
+261 1 1
+99 1 1
+128 1 1
+15 1 1
+77 9 9
+618 8 8
+84 4 6
+438 1 1
+140 1 1
+158 4 3
+277 12 12
+165 4 4
+36 1 1
+253 1 1
+59 1 1
+910 0 1
+915 4 5
+276 15 15
+682 1 1
+28 1 1
+1483 13 13
+203 1 0
+52 1 1
+48 1 1
+229 12 12
+68 15 15
+83 1 1
+39 1 1
+194 1 1
+24 1 1
+251 8 8
+619 0 4
+15 1 1
+690 1 1
+28 1 1
+54 0 1
+463 1 1
+30 1 1
+449 1 1
+54 1 1
+58 5 5
+979 1 0
+318 1 1
+28 1 1
+898 10 10
+100 1 1
+22 1 1
+446 1 1
+74 1 1
+273 1 1
+19 1 1
+333 1 1
+44 1 1
+220 1 1
+56 2 0
+209 1 1
+70 1 1
+223 0 20
+220 1 1
+31 1 1
+56 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+195 1 1
+46 1 1
+184 1 1
+60 0 4
+76 0 4
+53 3 1
+43 1 1
+153 1 1
+53 1 1
+195 6 0
+60 1 1
+278 1 0
+42 1 1
+124 10014 10005
+302 1 1
+24 1 1
+135 20 19
+55 1 1
+40 1 1
+175 1 1
+46 1 1
+52 1 1
+19 1 1
+277 1 1
+88 1 1
+172 1 1
+26 1 1
+129 1 1
+35 1 1
+55 9 9
+318 3 3
+46 1 1
+101 8 8
+4653 1 1
+38 1 1
+817 2 0
+256 1 1
+27 1 1
+339 1 1
+48 1 1
+54 10 10
+1393 3 0
+1491 2 0
+1983 16 0
+167 0 4
+3886 7 8
+535 1 1
+16 1 1
+1555 3 0
+3131 1 1
+17 1 1
+4196 1 0
+14974 0 1
+3514 0 4
+29 1 1
+123 0 2
+51 33 0
+121 0 133
+80 1 10
+26 60 4
+52 13 0
+20 0 2
+19 2 0
+22 4 156
+57 156 3
+61 0 2
+29 20 0
+42 11 0
+21 2 0
+50 4 6
+31 1 3
+23 1 53
+25 0 32
+66 1 55
+11 0 2
+13 0 41
+68 1 42
+23 1 3
+12 2 0
+17 1 29
+51 17 13
+18 2 0
+28 2 0
+26 2 0
+158 1 25
+102 0 82
+99 280 0
+53 21 0
+5064 0 2
+7569 2 0
+2189 0 1
+85 1 1
+31 0 4
+399 14 14
+408 0 1
+681 0 5
+184 1 1
+20 1 1
+64 1 1
+29 1 0
+9 2 0
+442 4 0
+342 1 1
+24 1 1
+131 1 1
+198 1 1
+370 0 1
+34 1 1
+447 21 20
+259 1 1
+23 0 1
+121 2 0
+2257 1 1
+22 1 1
+811 1 1
+27 1 1
+95 18 18
+631 0 5
+843 0 2889
+55 0 88
+1189 0 2
+2274 1 0
+752 4 0
+164 1 1
+55 1 1
+1033 10 10
+683 1 1
+57 1 1
+3578 1 1
+34 1 1
+1446 1 0
+460 1 1
+31 0 1
+6 1 1
+163 1 1
+22 1 1
+81 1 1
+27 1 1
+548 1 1
+61 1 1
+1169 1 1
+41 1 1
+1568 14 14
+4889 1 1
+62 1 1
+530 17 17
+394 1 1
+40 7 0
+57 12 12
+69 2 2
+39 1 1
+70 1 1
+22 0 3
+2307 1 1
+30 1 1
+411 1 1
+104 1 1
+375 26 27
+1218 1 1
+35 1 1
+85 1 1
+20 6 0
+687 1 1
+34 1 1
+268 13 13
+74 1 1
+47 2 0
+69 1 1
+49 1 1
+73 1 1
+48 1 1
+218 1 1
+42 1 1
+197 1 1
+41 1 1
+313 1 1
+40 1 1
+476 1 1
+29 1 1
+185 1 1
+35 1 1
+594 1 1
+24 1 1
+220 26 0
+245 0 1
+261 13 13
+89 1 1
+90 1 1
+224 1 1
+201 1 1
+306 1 1
+29 5 5
+121 1 1
+31 1 1
+109 1 1
+25 1 1
+168 1 1
+19 1 1
+93 12 11
+132 1 0
+113 1 1
+30 1 1
+56 9 9
+300 1 1
+50 2 2
+96 1 1
+43 1 1
+76 1 1
+44 1 1
+197 1 1
+91 7 1
+119 0 9
+392 5 5
+89 1 1
+428 11 11
+260 1 1
+23 1 0
+10 1 1
+70 1 1
+65 2 0
+16 0 19
+28 1 1
+208 1 1
+70 1 1
+149 0 3
+51 29 29
+163 1 1
+55 1 1
+63 17 17
+1208 1 1
+98 1 1
+162 1 1
+45 1 1
+148 14 14
+51 5 5
+209 4 4
+1242 1 1
+42 5 0
+87 1 1
+522 0 3
+305 0 1
+1379 0 2
+390 0 15
+72 1 1
+16 1 1
+270 1 0
+280 7 7
+2763 20 20
+674 10 10
+1375 14 0
+327 2 0
+107 1 1
+629 16 16
+54 4 4
+680 16 16
+395 1 1
+42 1 1
+1763 1 1
+46 1 1
+282 1 1
+39 1 1
+860 1 1
+26 1 1
+745 0 2
+2081 2 0
+817 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+132 5 0
+555 1 1
+65 1 1
+550 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+15 1 5
+1404 0 1
+450 4 0
+626 1 0
+304 1 1
+39 1 1
+564 1 1
+45 1 1
+303 2 0
+409 1 1
+18 1 0
+858 2 0
+2168 0 1
+54 1 1
+20 1 1
+524 0 1
+410 10 10
+106 1 14
+2419 18 14
+64 1 1
+31 1 1
+185 0 5
+1646 1 1
+20 1 1
+227 1 1
+37 1 1
+500 1 0
+136 3 4
+8239 1 1
+23 1 1
+1114 0 2
+688 0 1
+901 18 18
+4781 0 4
+815 0 1
+5069 0 5
+415 0 2
+352 0 1
+1085 11 11
+1099 0 1
+991 0 1
+845 1 1
+32 0 2
+5751 0 3
+1553 1 1
+60 1 1
+278 0 1
+30 1 1
+1855 0 2
+958 0 1
+66 0 16
+2109 0 2
+1265 0 1
+17312 0 4
+1875 0 1
+2157 1 0
+915 0 6
+4940 1 0
+2649 0 1
+3331 2 0
+2276 14 0
+3128 0 4
+3496 1 0
+966 0 1
+3597 1 0
+1647 0 3
+1182 1 0
+654 0 3
+2049 1 0
+6838 1 1
+39 1 1
+186 1 0
+2718 1 1
+30 1 1
+160 11 11
+4954 0 1
+420 1 1
+123 1 1
+156 0 4
+219 4 0
+195 1 0
+4402 2 0
+4295 1 0
+4207 20 20
+468 0 1
+30 1 1
+6025 1 0
+4179 1 0
+19834 0 1
+11605 0 1
+4121 2 0
+2863 0 2
+4890 1 0
+5576 0 6
+4104 4 0
+19858 4 0
+1616 0 3
+1647 4 1
+36 0 12
+2213 0 14
+414 0 1
+458 20 20
+2860 0 3
+678 3 4
+292 2 0
+1922 0 1
+913 0 1
+2720 1 0
+1111 3 0
+2589 0 8
+9425 1 0
+1403 0 2
+1964 0 12
+4433 0 1
+1569 0 1
+7209 1 1
+41 1 1
+2257 1 0
+3001 0 1
+1845 1 0
+1593 0 1
+497 0 2
+6109 0 1
+2019 2 0
+921 0 1
+241 1 0
+5473 1 0
+2213 2 0
+1974 8 0
+4952 0 1
+6146 2 0
+953 1 0
+4141 0 1
+4244 5 0
+152 0 2
+209 0 1
+2400 0 10
+785 2 0
+1733 0 1
+554 1 0
+128 0 2
+3051 0 1
+8577 0 1
+1503 0 1
+1705 0 3
+2052 17 17
+998 177 0
+2804 1 0
+1925 1 0
+9215 0 1
+971 8 0
+36021 1 0
+8016 29 27
+3890 0 1
+67913 1 1
+18 1 6368
+73 1 32739
+14676 1 1
+19 1 1
+22867 1 1
+20 1 1
+5638 5 0
+47 12 0
+11313 0 1
+1769 0 1
+8355 0 3
+4114 0 2
+1403 1 0
+5140 0 1
+490 0 1
+219 1 0
+3483 1 0
+8939 1 1
+44 1 1
+10813 0 2
+7480 2 0
+617 1 0
+1464 0 1
+500 0 2
+1466 1 0
+527 5 0
+3593 0 1
+374 0 1
+2946 22 22
+698 0 1
+2149 1 0
+311 2 0
+6570 1 0
+962 1 0
+23 1 1
+2647 4 0
+588 1 1
+21 1 1
+3256 28 20
+870 0 1
+644 1 0
+602 2 1
+3730 1 1
+45 1 1
+12848 7 7
+7306 0 3
+6647 45 45
+1365 1 1
+63 1 1
+4166 1 0
+1887 10 0
+2949 1 1
+31 0 1
+669 1 0
+2190 2 0
+2081 0 2
+373 0 6
+421 4 4
+1460 0 1
+1699 0 8
+2882 2 0
+147 0 1
+1656 1 1
+27 1 1
+1828 0 2
+4066 35 38
+361 17 17
+1254 6 0
+1643 0 2
+2542 0 1
+848 2 1
+2117 0 2
+119 1 1
+44 1 1
+1104 0 1
+415 0 12
+634 18 1
+377 6 7
+227 6 0
+449 13 13
+895 0 17
+457 18 18
+663 0 3
+382 1 1
+26 1 1
+135 0 1
+105 1 1
+25 1 1
+620 2 0
+290 5 5
+375 1 1
+30 0 4
+98 1 0
+20 17 4
+3824 28 0
+39 4 0
+28 4 0
+44 4 0
+1898 9 9
+221 0 2
+10522 30 0
+783 1 1
+59 1 1
+94 1 1
+21 1 1
+491 1 1
+49 1 1
+289 2 0
+120 0 1
+37 1 1
+112 1 1
+21 1 1
+183 16 16
+73 2 0
+1007 1 1
+38 0 1
+79 1 1
+48 1 1
+561 1 1
+29 1 1
+145 5 5
+576 12 12
+834 1 0
+846 5 7
+34 1 1
+417 10 11
+55 1 1
+40 1 1
+110 1 1
+47 1 1
+351 1 1
+69 1 1
+53 1 1
+91 1 1
+260 1 1
+36 0 1
+604 1 0
+169 0 1
+2118 1 1
+34 1 1
+147 1 1
+213 1 1
+67 1 1
+31 1 1
+566 1 0
+17 1 1
+763 1 1
+34 1 1
+671 5 0
+41 2 2
+98 0 1
+449 0 2
+61 1 1
+38 1 1
+202 1 1
+44 1 1
+190 1 0
+46 4 4
+51 0 4
+476 1 1
+17 1 1
+212 1 1
+26 1 1
+485 1 1
+25 1 1
+263 1 1
+26 1 1
+1327 4 0
+44 1 0
+2397 1 1
+44 1 1
+4146 14 14
+901 0 1
+1769 14 14
+1721 1 0
+1125 1 0
+254 1 0
+427 0 1
+30 1 1
+111 0 2
+52 0 8
+528 44 0
+969 1 1
+10 1 0
+28 1 1
+140 1 1
+43 1 1
+1989 2 1
+598 1 1
+87 0 4
+124 1 0
+4840 1 1
+28 7 4
+505 0 2
+24 1 1
+5134 4 0
+543 1 0
+18 1 1
+97 1 1
+29 1 3
+101 6 0
+148 13 7
+1346 0 1
+128 7 0
+49 0 1
+876 2 0
+286 5 5
+184 0 1
+84 5 5
+365 9 9
+981 1 1
+11 1 1
+734 4 0
+563 4 0
+244 9 9
+379 1 1
+17 1 1
+49 2 0
+95 1 1
+30 1 1
+147 1 1
+37 0 6
+340 1 2
+58 1 1
+332 0 2
+233 6 9
+156 0 1
+26 1 1
+439 4 0
+34 0 2
+508 5 0
+96 1 1
+34 1 1
+1267 63 63
+590 1 1
+24 4 5
+1055 13 13
+135 0 1
+194 1 1
+61 1 1
+384 6 6
+2756 1 1
+19 1 1
+99 15 15
+1754 2 3
+2238 1 1
+31 1 1
+3002 4 0
+2156 15 15
+855 14 13
+442 5 5
+2022 6 6
+506 0 2
+1110 0 1
+2578 0 2
+4864 1 1
+36 1 0
+3187 1 1
+16 1 1
+184 1 1
+18 1 1
+1636 0 7
+23 1 1
+527 1 1
+39 1 1
+653 3 0
+227 1 1
+18 1 1
+102 7 7
+109 0 323
+91 1 0
+124 0 15
+621 0 4
+553 12 12
+463 1 1
+40 1 1
+372 1 1
+25 1 1
+188 12 12
+357 0 1
+250 0 5
+4193 0 4
+967 1 1
+76 1 1
+3236 4 4
+529 7 7
+246 4 0
+160 1 1
+34 0 3
+1469 0 2
+499 1 0
+937 1 1
+45 1 1
+356 71 65
+2127 0 1
+491 1 0
+80 1 1
+72 2 0
+255 6 6
+728 14 11
+702 3 0
+290 0 2
+210 19 1
+473 1 1
+42 4 0
+219 0 1
+348 1 1
+83 1 1
+851 0 16
+72 13 0
+246 1 1
+47 4 0
+410 1 0
+93 0 12
+225 0 16
+428 1 0
+4 6 0
+324 0 1
+3060 0 16
+1305 1 1
+29 1 1
+3094 0 7
+600 0 2
+5495 1 1
+47 1 1
+1247 49 55
+4351 1 1
+15 1 1
+2011 6 14
+8378 2 0
+295 0 17
+4583 1 0
+4132 0 4
+924 4 3
+1751 0 2
+1060 12 12
+380 0 2
+425 8 0
+84 0 1
+244 1 1
+28 1 1
+221 4 0
+348 1 1
+37 11 11
+50 1 1
+180 1 1
+348 1 1
+20 1 1
+1714 1 1
+79 1 1
+729 1 1
+44 1 0
+78 1 1
+112 1 1
+23 1 1
+55 9 9
+1044 1 1
+27 1 1
+494 1 1
+32 1 1
+237 1 1
+27 1 1
+1422 4 4
+413 7 1
+710 8 0
+185 0 2
+966 1 0
+13 15 1
+251 1 1
+47 1 1
+285 1 1
+103 1 1
+977 1 1
+41 1 0
+97 1 1
+131 1 0
+307 1 1
+47 1 1
+1070 1 1
+69 1 1
+382 0 1
+167 1 1
+35 1 1
+161 1 1
+30 1 1
+1068 18 0
+1173 1 1
+32 1 1
+59 1 1
+12 1 0
+18 1 1
+55 0 22
+72 1 1
+2806 1 1
+15 1 1
+1395 1 0
+157 13 0
+536 8 8
+101 1 1
+21 1 1
+147 8 8
+638 1 1
+18 1 1
+183 15 15
+990 0 12
+21 1 1
+145 0 1
+332 1 1
+31 1 1
+231 22 5
+39 1 1
+414 9 9
+93 1 1
+63 1 1
+739 0 2
+632 1 1
+74 1 1
+138 5 5
+128 0 1
+294 1 1
+45 1 1
+679 6 6
+1756 0 34
+560 27 27
+1608 5 0
+219 1 1
+134 0 3
+81 1 1
+82 0 1
+357 1 1
+28 1 1
+670 7 9
+270 0 1
+891 13 33
+257 4 0
+80 0 4
+130 2 0
+2504 42 42
+1226 1 1
+44 1 1
+2256 0 1
+80 12 0
+5544 1 0
+428 13 13
+77 4 4
+63 1 1
+64 13 19
+178 10023 10000
+157 3 3
+109 1 1
+180 1 1
+56 1 1
+169 1 0
+93 1 1
+33 2 2
+72 1 1
+30 1 1
+267 25 25
+65 1 1
+19 2 0
+108 27 27
+218 1 1
+37 1 1
+477 11 11
+93 1 1
+30 7 5
+242 0 1
+171 1 1
+29 1 1
+218 0 9
+241 1 1
+55 4 4
+88 1 1
+99 1 1
+57 0 1
+523 12 16
+399 1 1
+50 1 1
+389 1 1
+71 4 4
+173 12 12
+92 1 1
+20 1 1
+132 0 5
+15 1 1
+75 1 1
+26 5 5
+119 11 11
+542 1 1
+23 2 2
+254 1 1
+34 1 1
+172 1 1
+45 1 1
+95 11 11
+127 23 23
+64 1 1
+95 1 1
+390 1 1
+52 1 1
+170 1 1
+16 5 0
+30 1 1
+599 1 1
+119 1 1
+85 1 1
+75 1 1
+286 4 4
+61 1 1
+286 9 9
+429 1 1
+21 1 1
+53 1 1
+44 1 1
+77 165084 190027
+5156 0 1
+1680 1 1
+88 1 1
+4502 0 1
+46 1 1
+800 4 4
+23 1 1
+1305 2 0
+136 0 1
+4941 0 1
+547 0 1
+70 8 8
+293 1 1
+35 1 1
+1165 4 0
+6662 1 1
+121 1 1
+92 0 8
+214 1 1
+35 1 1
+108 1 0
+1063 0 1
+1017 1 1
+20 0 6
+1725 0 1
+150 5 5
+33 1 0
+12 1 1
+349 1 1
+24 0 1
+1562 1 1
+31 1 1
+2513 0 1
+73 36 36
+305 1 1
+27 1 1
+543 1 1
+47 4 28
+4874 0 3
+599 10 10
+137 1 0
+7 0 4
+54 1 1
+2497 1 1
+166 1 1
+637 3 3
+46 1 1
+74 4 4
+414 1 1
+48 1 1
+75 4 4
+153 0 26
+93 1 1
+39 1 0
+58 1 1
+51 1 1
+145 9 9
+29 1 1
+55 1 1
+427 1 0
+141 1 1
+87 1 1
+20 1 1
+89 3 3
+141 18 5
+48 1 1
+87 14 14
+173 1 1
+68 1 1
+54 1 1
+51 4 0
+22 1 0
+52 1 1
+171 1 1
+109 3 1
+6 0 2
+205 1 1
+54 10064 10083
+76 3 1
+197 15 15
+77 1 1
+70 1 1
+178 1 1
+60 1 1
+210 1 1
+28 1 1
+62 1 1
+33 1 1
+70 0 1
+202 1 1
+60 1 1
+106 2 0
+176 1 1
+79 0 1
+50 1 1
+50 3 3
+207 1 1
+272 5 5
+243 1 1
+84 1 1
+98 1 1
+50 5 5
+77 1 1
+74 1 1
+20 0 1
+143 1 1
+45 0 1
+4 1 1
+1088 1 1
+35 1 1
+320 1 1
+22 1 1
+275 1 1
+47 1 1
+370 19 19
+119 1 6
+51 1 1
+21 1 1
+244 0 1
+345 1 1
+24 1 1
+181 1 1
+61 3 3
+542 1 1
+16 1 1
+312 1 0
+353 4 3
+279 323 0
+86 1 1
+49 1 1
+342 1 1
+44 0 2
+222 1 1
+37 1 1
+588 8 8
+593 47 47
+359 1 1
+25 1 1
+2054 1 0
+2510 1 0
+5040 11 12
+1489 9 9
+3292 1 0
+1449 1 1
+21 1 1
+6768 1 0
+706 2 0
+7107 1 1
+38 1 1
+1163 1 1
+35 1 1
+435 1 1
+60 1 1
+325 0 1
+254 1 1
+43 1 1
+210 1 1
+7 1 0
+47 1 1
+130 4 4
+34 1 1
+208 1 1
+39 2 2
+526 1 1
+36 1 1
+99 9 7
+20 1 1
+73 1 1
+62 1 1
+425 1 1
+43 1 1
+811 1 1
+38 1 1
+362 1 1
+49 1 1
+109 1 1
+19 1 1
+79 1 1
+29 0 1
+26 1 1
+252 1 1
+75 1 1
+441 1 1
+66 1 1
+389 13 13
+67 7 7
+1185 0 311
+64 6 6
+389 31 31
+247 1 1
+38 1 1
+79 1 0
+553 1 1
+30 1 1
+433 1 1
+16 3 0
+1133 12 12
+262 5 5
+276 1 0
+960 14 14
+272 1 1
+41 1 1
+196 1 0
+1424 18 19
+314 1 1
+22 1 1
+345 1 1
+23 3 0
+245 1 1
+78 1 1
+77 1 1
+779 1 1
+32 1 1
+247 1 1
+48 1 1
+778 2 0
+226 1 1
+61 1 1
+867 0 1
+53 1 1
+397 1 1
+12 4 0
+46 1 1
+602 1 1
+35 1 1
+422 1 1
+49 1 1
+789 1 1
+37 1 1
+268 0 2
+589 8 8
+366 12 20
+1651 2 7
+19 1 1
+417 1 1
+37 1 1
+812 1 1
+33 3 0
+1351 18 18
+2186 1 1
+86 1 1
+1433 1 1
+39 1 1
+83 0 1
+238 0 1
+171 1 1
+7 2 1
+67 1 1
+596 1 1
+29 1 1
+144 4 6
+417 1 0
+88 1 1
+24 1 1
+390 18 18
+496 14 21
+145 1 1
+46 1 1
+310 1 1
+35 1 1
+214 1 1
+38 1 1
+206 1 1
+37 1 0
+240 1 1
+32 1 1
+469 1 1
+32 1 1
+208 1 1
+21 1 1
+343 1 1
+17 1 1
+88 1 1
+58 6 0
+169 1 1
+22 1 1
+162 0 1
+196 0 2
+500 6 5
+108 1 1
+40 2 0
+50 1 1
+111 1 0
+21 0 1066
+175 5 5
+155 1 1
+44 1 1
+11005 0 1
+6280 1 1
+48 1 1
+1173 1 1
+19 1 1
+2664 0 1
+351 1 0
+1059 14 14
+593 0 1
+869 16 16
+23065 2 0
+2197 0 1
+949 0 1
+15048 0 1
+606 1 0
+7820 0 4
+14669 1 0
+14708 0 1
+16326 0 1
+304 18 18
+388 2 0
+194 1 1
+49 1 1
+262 0 1
+92 1 1
+10677 2 0
+4856 3 0
+7447 6 6
+421 1 0
+884 6 0
+17 1 0
+3075 1 0
+1610 12 12
+13049 3 1
+3762 2 0
+601 2 0
+2461 0 2
+5154 1 0
+1604 0 16
+3338 26 26
+225 0 1
+1488 1 0
+1196 0 2
+683 0 1
+1218 1 0
+221 1 1
+22 1 1
+296 4 4
+1456 23 41
+880 1 12
+2490 1 0
+151 1 1
+33 1 1
+2809 4 4
+3645 1 1
+17 1 1
+3496 2 0
+154 1 1
+29 1 1
+158 0 1
+5981 1 1
+32 1 1
+1041 0 2
+174 9 0
+1383 0 1
+389 1 2
+1570 2 0
+3993 4 0
+4576 87 87
+142 8 8
+2203 20 24
+2009 1 1
+39 1 1
+489 1 1
+17 1 1
+628 1 1
+124 1 1
+1607 1 1
+23 1 1
+1021 0 8
+1249 0 20
+46 0 32
+46 6 0
+24 0 10
+7679 1 1
+44 1 1
+580 1 1
+28 1 1
+264 1 1
+65 0 1
+15 1 1
+1513 28 28
+830 19 19
+57 1 1
+21 1 1
+231 1 1
+94 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 1 1
+38 1 1
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 29 29
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+270 1 1
+272 1 1
+232 1 1
+94 1 1
+3189 0 176
+834 0 35
+303 0 51
+321 1 0
+17170 0 1
+321 1 1
+25 1 1
+679 1 1
+33 1 1
+990 11 11
+131 8 8
+79 9 9
+1284 9945 10022
+2039 8 23
+491 1 1
+32 1 1
+85 1 1
+41 1 1
+480 1 1
+74 2 2
+1108 59 0
+70 10 10
+325 11 11
+879 1 1
+34 1 1
+524 1 1
+25 1 1
+202 17 17
+1154 1 1
+26 1 1
+89 17 17
+87 1 1
+39 1 1
+950 1 1
+15 2 2
+51 1 1
+81 1 1
+180 1 0
+187 1 1
+37 1 1
+467 1 1
+19 1 1
+755 0 2
+81 3 1
+16 1 1
+67 6 6
+84 1 1
+37 2 0
+31 0 28
+15 0 37
+266 14 14
+372 1 1
+68 1 1
+462 1 1
+46 1 1
+563 19 0
+217 9 9
+363 1 1
+22 1 1
+884 1 1
+40 1 1
+179 1 1
+42 1 1
+94 6 6
+922 1 1
+30 1 1
+481 0 3
+7925 15 11
+333 5 0
+1235 6 6
+355 1 1
+27 1 1
+515 1 0
+1077 11 0
+1521 1 0
+38 1 1
+119 1 1
+58 1 1
+63 4 3
+385 1 1
+49 1 1
+77 44 46
+87 11 11
+190 2 2
+45 1 1
+373 1 1
+47 1 1
+77 10 10
+186 1 1
+24 1 1
+1140 1 0
+214 1 1
+34 1 1
+89 1 1
+36 1 1
+288 0 1
+544 0 331
+320 1 0
+199 1 1
+16 1 1
+112 1 1
+29 1 1
+783 0 3
+311 1 1
+38 1 1
+59 1 1
+68 1 1
+52 1 1
+98 1 1
+166 7 7
+698 1 1
+68 1 1
+165 0 1
+114 1 1
+92 0 1
+14 1 1
+215 1 1
+81 1 1
+792 1 1
+31 1 1
+54 1 1
+44 1 1
+179 1 1
+26 1 1
+200 1 1
+30 1 1
+639 7 7
+505 40 42
+549 12 0
+19 1 1
+2184 1 0
+840 1 1
+69 1 1
+966 21 21
+33 12 0
+56 1 1
+94 1 1
+237 11 9
+189 1 1
+47 1 1
+318 3 0
+80 1 1
+94 5 1
+32 1 1
+126 16 16
+83 1 1
+47 1 1
+104 6 5
+56 1 1
+68 1 1
+417 12 13
+636 0 2
+30 1 1
+694 0 4
+95 1 1
+28 1 1
+1358 1 1
+19 1 1
+68 1 1
+97 1 1
+155 15 15
+323 1 7
+158 2 0
+42 6 0
+59 1 1
+314 14 14
+94 1 1
+64 1 1
+637 1 1
+21 1 1
+144 2 1
+229 11 5
+410 1 1
+96 1 1
+272 1 1
+22 1 1
+118 1 1
+44 1 1
+96 1 1
+48 1 1
+414 22 22
+373 13 13
+554 1 1
+87 10 0
+313 1 1
+37 1 1
+122 17 18
+179 1 1
+40 1 1
+591 8 8
+129 1 0
+70 1 1
+71 1 0
+73 10 6
+12 1 1
+203 0 6
+24 2 0
+45 4 0
+46 1 1
+186 9 9
+87 1 1
+28 1 1
+3625 0 1
+71 1 1
+126 1 1
+34 1 1
+532 0 2
+696 2 0
+555 1 7
+287 1 1
+30 0 3
+946 0 1
+88 1 1
+60 12 0
+12546 1 1
+37 1 0
+2071 0 1
+1253 9 9
+2003 0 1
+24677 0 2
+6212 1 1
+26 1 1
+816 0 4
+13602 18 15
+2375 2 0
+1957 2 0
+2394 6 0
+1561 0 1
+2805 4 0
+12333 8 0
+835 0 1
+426 0 27
+12156 0 18
+6903 2 0
+21807 3 0
+1588 1 0
+2605 1 1
+23 1 1
+11252 8 0
+298 6 7
+946 2 0
+232 0 1
+501 1 0
+4748 0 4
+770 0 7
+914 0 1
+295 1 0
+214 3 0
+121 0 1
+784 0 1
+2512 0 1
+4476 3 0
+926 0 1
+189 2 0
+3543 2 0
+893 1 1
+46 1 1
+1296 0 1
+153 0 1
+336 5 0
+228 1 1
+45 1 1
+207 3 0
+322 0 1
+658 1 0
+1516 3 0
+1025 0 13
+1518 0 1
+591 10 10
+3384 0 2
+182 12 0
+328 1 0
+301 0 1
+994 1 1
+18 0 6
+1743 0 1
+2350 22 23
+1548 0 7
+1976 1 0
+199 0 1
+5922 12 12
+873 0 3
+3080 12 8
+322 1 0
+490 1 0
+3602 1 0
+482 1 0
+3178 1 0
+5157 0 10
+753 0 1
+885 20 0
+1746 10 0
+4045 6 1
+3520 5 13
+2048 0 1
+3529
+
+chain 323865 6_cox_hap1 4731698 + 1267152 1270823 12 133851895 - 763369 785145 206180
+2772 0 815
+201 0 17291
+643 1 0
+54
+
+chain 65284 6_cox_hap1 4731698 + 2460102 2460796 6 171115067 - 140105134 140105832 1936071
+178 0 4
+516
+
+chain 59092 6_cox_hap1 4731698 + 4004481 4005101 4 191154276 + 48364786 48365406 2142970
+620
+
+chain 52987 6_cox_hap1 4731698 + 2674042 2675969 3 198022430 - 151830192 151832103 2402006
+102 557 556
+77 395 393
+169 221 221
+81 15 15
+81 35 35
+55 44 31
+95
+
+chain 40067 6_cox_hap1 4731698 + 3843208 3843655 1 249250621 - 189436883 189437330 3283815
+379 3 3
+65
+
+chain 34258 6_cox_hap1 4731698 + 2746095 2746514 X 155270560 - 17905933 17906346 3956727
+73 15 15
+155 1 1
+20 6 0
+17 1 1
+131
+
+chain 30865 6_cox_hap1 4731698 + 3996373 3996892 6 171115067 + 32713281 32713770 4500603
+73 89 59
+184 77 77
+96
+
+chain 30808 6_cox_hap1 4731698 + 1446736 1447059 11 135006516 - 73898390 73898713 4511271
+323
+
+chain 29563 6_cox_hap1 4731698 + 4089902 4090211 1 249250621 - 75305559 75305868 4853755
+309
+
+chain 29490 6_cox_hap1 4731698 + 3888227 3888535 20 63025520 - 21266962 21267270 4884719
+308
+
+chain 23990 6_cox_hap1 4731698 + 1313393 1314169 7 159138663 - 51241795 51242737 7706852
+178 101 101
+72 385 551
+40
+
+chain 19279 6_cox_hap1 4731698 + 2759716 2759948 5 180915260 + 25289600 25289832 11061062
+91 17 17
+124
+
+chain 18106 6_cox_hap1 4731698 + 3844292 3845362 7 159138663 + 50640514 50641583 3599691
+33 446 444
+74 250 251
+5 55 55
+48 69 69
+90
+
+chain 17763 6_cox_hap1 4731698 + 3840247 3840451 6 171115067 - 2083149 2083361 12325354
+52 0 8
+26 2 2
+124
+
+chain 17263 6_cox_hap1 4731698 + 3890221 3890428 4 191154276 + 3927369 3927573 12785973
+50 3 0
+26 4 4
+124
+
+chain 16283 6_cox_hap1 4731698 + 3267732 3267909 2 243199373 + 128545205 128545381 580296
+28 2 1
+147
+
+chain 16000 6_cox_hap1 4731698 + 3842640 3845155 5 180915260 - 144997615 145000132 3598025
+127 1430 1431
+95 205 207
+98 29 29
+57 419 418
+55
+
+chain 15874 6_cox_hap1 4731698 + 2744265 2744697 6 171115067 + 31304784 31305225 14156555
+58 158 158
+72 76 85
+68
+
+chain 15671 6_cox_hap1 4731698 + 1306242 1307477 6 171115067 - 139875690 139876935 14366990
+56 408 416
+54 620 622
+97
+
+chain 15351 6_cox_hap1 4731698 + 2791400 2791601 11 135006516 + 74748600 74748801 14697621
+99 26 26
+76
+
+chain 14920 6_cox_hap1 4731698 + 2791114 2791352 12 133851895 + 56894984 56895263 15150280
+65 69 110
+104
+
+chain 14203 6_cox_hap1 4731698 + 4000567 4000717 6 171115067 - 148948255 148948405 15963295
+150
+
+chain 14065 6_cox_hap1 4731698 + 3901987 3902139 6 171115067 - 138602057 138602209 16122340
+152
+
+chain 13939 6_cox_hap1 4731698 + 2790912 2791061 15 102531392 - 60147333 60147482 16276423
+149
+
+chain 13590 6_cox_hap1 4731698 + 4000399 4000543 2 243199373 + 178345068 178345212 16711221
+144
+
+chain 13240 6_cox_hap1 4731698 + 3909742 3911000 6 171115067 + 32548108 32549235 17164167
+52 422 421
+78 652 522
+54
+
+chain 12556 6_cox_hap1 4731698 + 1348680 1348819 2 243199373 - 184149574 184149713 18162971
+139
+
+chain 12225 6_cox_hap1 4731698 + 3890501 3890631 13 115169878 - 44980182 44980312 18662730
+130
+
+chain 12178 6_cox_hap1 4731698 + 3972449 3972615 14 107349540 - 58393926 58394091 18734378
+55 26 25
+85
+
+chain 12008 6_cox_hap1 4731698 + 3896810 3896939 8 146364022 + 49154427 49154556 18990652
+129
+
+chain 11746 6_cox_hap1 4731698 + 1299553 1299701 7 159138663 - 7702899 7703047 19437477
+54 14 14
+80
+
+chain 11718 6_cox_hap1 4731698 + 299537 299697 13 115169878 + 54026210 54026329 7331663
+62 41 0
+40 13 13
+4
+
+chain 11503 6_cox_hap1 4731698 + 3894886 3895312 11 135006516 - 111045874 111046295 19852909
+57 287 282
+82
+
+chain 11377 6_cox_hap1 4731698 + 3840583 3840825 11 135006516 + 57049649 57049891 20071170
+62 107 107
+73
+
+chain 10960 6_cox_hap1 4731698 + 3841022 3841165 12 133851895 - 49356794 49356937 20822626
+50 15 15
+78
+
+chain 10867 6_cox_hap1 4731698 + 2681465 2681622 6 171115067 - 132617434 132617597 20998653
+55 29 35
+73
+
+chain 10738 6_cox_hap1 4731698 + 3896518 3896639 10 135534747 + 59600699 59600817 21255898
+61 3 0
+57
+
+chain 10496 6_cox_hap1 4731698 + 3892569 3892679 1 249250621 - 174039531 174039641 21744607
+110
+
+chain 10328 6_cox_hap1 4731698 + 3840451 3840892 4 191154276 - 114078209 114078650 18698120
+15 372 372
+54
+
+chain 9881 6_cox_hap1 4731698 + 2734004 2734554 6 171115067 + 31205448 31206008 23100546
+72 423 433
+55
+
+chain 9755 6_cox_hap1 4731698 + 4021493 4021793 6 171115067 + 162490109 162490409 23390927
+65 181 181
+54
+
+chain 9560 6_cox_hap1 4731698 + 1301303 1301404 6 171115067 - 141323187 141323288 23857061
+101
+
+chain 9455 6_cox_hap1 4731698 + 3891953 3892158 6 171115067 + 32468923 32469135 24116909
+54 91 98
+60
+
+chain 9090 6_cox_hap1 4731698 + 2680711 2680821 3 198022430 - 94212956 94213066 24807216
+53 4 4
+53
+
+chain 7297 6_cox_hap1 4731698 + 3844000 3844124 8 146364022 + 96809146 96809270 3974525
+124
+
+chain 7162 6_cox_hap1 4731698 + 2675969 2676329 17 81195210 - 22005566 22005927 2836104
+7 302 303
+51
+
+chain 7031 6_cox_hap1 4731698 + 2673410 2673921 5 180915260 + 106108094 106108601 3265511
+58 376 372
+77
+
+chain 6840 6_cox_hap1 4731698 + 3971466 3971538 11 135006516 + 40011829 40011901 28544257
+72
+
+chain 6473 6_cox_hap1 4731698 + 3890669 3890742 1 249250621 - 102907635 102907704 21815173
+11 4 0
+58
+
+chain 6422 6_cox_hap1 4731698 + 4013834 4013902 6 171115067 + 32728707 32728775 29535230
+68
+
+chain 5921 6_cox_hap1 4731698 + 2681183 2681245 4 191154276 - 94306644 94306706 30842389
+62
+
+chain 5676 6_cox_hap1 4731698 + 2671999 2672059 3 198022430 + 95260601 95260661 31509897
+60
+
+chain 5595 6_cox_hap1 4731698 + 3972615 3972674 14 107349540 - 80191032 80191091 27115653
+59
+
+chain 5576 6_cox_hap1 4731698 + 1302171 1302230 18 78077248 - 3698437 3698496 31796878
+59
+
+chain 5517 6_cox_hap1 4731698 + 3842389 3842453 20 63025520 - 5368566 5368630 20848663
+64
+
+chain 5458 6_cox_hap1 4731698 + 3985007 3985065 2 243199373 + 112827415 112827473 32167738
+58
+
+chain 5421 6_cox_hap1 4731698 + 2677334 2677391 19 59128983 - 38462903 38462960 32247802
+57
+
+chain 5403 6_cox_hap1 4731698 + 3897499 3897556 12 133851895 + 59864980 59865037 32286341
+57
+
+chain 5339 6_cox_hap1 4731698 + 4081817 4081873 17 81195210 + 16805661 16805717 32499905
+56
+
+chain 5266 6_cox_hap1 4731698 + 4021149 4021204 3 198022430 + 6923000 6923055 32744278
+55
+
+chain 5103 6_cox_hap1 4731698 + 2743431 2743485 3 198022430 + 27241143 27241197 33231446
+54
+
+chain 5094 6_cox_hap1 4731698 + 3984745 3984799 6 171115067 + 67966752 67966806 33279729
+54
+
+chain 5089 6_cox_hap1 4731698 + 2674314 2675775 1 249250621 + 7474130 7475590 2473669
+98 975 974
+58 295 295
+35
+
+chain 5076 6_cox_hap1 4731698 + 1300901 1300955 11 135006516 + 101518151 101518205 33343005
+54
+
+chain 5067 6_cox_hap1 4731698 + 2741303 2741357 19 59128983 - 37393851 37393905 33368570
+54
+
+chain 5058 6_cox_hap1 4731698 + 3967166 3967220 1 249250621 - 172942963 172943017 33379585
+54
+
+chain 5020 6_cox_hap1 4731698 + 1345886 1345938 6 171115067 + 29692684 29692736 33527644
+52
+
+chain 4959 6_cox_hap1 4731698 + 3892516 3892569 18 78077248 + 5090594 5090647 22176918
+53
+
+chain 4957 6_cox_hap1 4731698 + 2678048 2678100 9 141213431 - 31846047 31846099 33735026
+52
+
+chain 4957 6_cox_hap1 4731698 + 3946024 3946076 6 171115067 + 32439356 32439408 33735182
+52
+
+chain 4930 6_cox_hap1 4731698 + 3894496 3894548 X 155270560 - 4541772 4541824 33815607
+52
+
+chain 4914 6_cox_hap1 4731698 + 2673741 2673793 X 155270560 + 7935883 7935935 17711968
+52
+
+chain 4885 6_cox_hap1 4731698 + 2740950 2741002 5 180915260 - 163072859 163072911 33995114
+52
+
+chain 4884 6_cox_hap1 4731698 + 2760326 2760379 7 159138663 + 8699184 8699237 23141527
+53
+
+chain 4821 6_cox_hap1 4731698 + 3935381 3935432 6 171115067 - 11031703 11031754 34213824
+51
+
+chain 4685 6_cox_hap1 4731698 + 3915703 3915753 12 133851895 + 112261417 112261467 34690968
+50
+
+chain 4613 6_cox_hap1 4731698 + 2844682 2846505 13 115169878 - 41386504 41386960 3856143
+33 479 279
+7 46 0
+24 11 0
+33 1097 0
+24 13 0
+56
+
+chain 4221 6_cox_hap1 4731698 + 2437589 2437671 14 107349540 + 75461679 75461839 4623812
+28 0 78
+54
+
+chain 4202 6_cox_hap1 4731698 + 2673968 2674023 3 198022430 + 156309398 156309453 19139889
+55
+
+chain 4186 6_cox_hap1 4731698 + 3955813 3955860 5 180915260 - 113986983 113987030 34971958
+47
+
+chain 4136 6_cox_hap1 4731698 + 2672610 2672662 13 115169878 + 42049101 42049153 23521137
+52
+
+chain 3978 6_cox_hap1 4731698 + 2673481 2673609 X 155270560 - 130914483 130914611 4485241
+128
+
+chain 3891 6_cox_hap1 4731698 + 2760039 2760115 16 90354753 - 58442153 58442229 17002345
+76
+
+chain 3877 6_cox_hap1 4731698 + 2672485 2672526 15 102531392 + 40275232 40275273 21164310
+41
+
+chain 3776 6_cox_hap1 4731698 + 2759549 2759589 1 249250621 - 143888892 143888932 33598889
+40
+
+chain 3639 6_cox_hap1 4731698 + 3890631 3890669 3 198022430 + 101411146 101411184 20382394
+38
+
+chain 3574 6_cox_hap1 4731698 + 2673146 2673184 3 198022430 - 173409162 173409200 29596627
+38
+
+chain 3573 6_cox_hap1 4731698 + 2790788 2791088 16 90354753 + 31183111 31183406 18086604
+58 215 210
+27
+
+chain 3489 6_cox_hap1 4731698 + 3842885 3842952 X 155270560 - 48144545 48144612 19043441
+67
+
+chain 3394 6_cox_hap1 4731698 + 3896482 3896518 X 155270560 - 4545757 4545793 28280414
+36
+
+chain 3393 6_cox_hap1 4731698 + 3840688 3840752 8 146364022 + 7016797 7016861 21522443
+64
+
+chain 3345 6_cox_hap1 4731698 + 1313572 1313633 X 155270560 - 101738888 101738949 11083842
+61
+
+chain 3209 6_cox_hap1 4731698 + 3842526 3842560 4 191154276 + 80147803 80147837 32673071
+34
+
+chain 3189 6_cox_hap1 4731698 + 2790872 2790912 11 135006516 - 131957088 131957128 22905486
+40
+
+chain 3053 6_cox_hap1 4731698 + 4021558 4021590 2 243199373 + 38182694 38182726 24706669
+32
+
+chain 3045 6_cox_hap1 4731698 + 2677533 2677565 11 135006516 - 20509488 20509520 33762261
+32
+
+chain 3033 6_cox_hap1 4731698 + 3842991 3843062 1 249250621 - 90164672 90164743 11203780
+71
+
+chain 2997 6_cox_hap1 4731698 + 2759644 2759694 16 90354753 + 47212776 47212826 11278440
+50
+
+chain 2984 6_cox_hap1 4731698 + 3842575 3842625 X 155270560 + 76422698 76422748 20248077
+50
+
+chain 2960 6_cox_hap1 4731698 + 3896779 3896810 21 48129895 + 18677639 18677670 32477029
+31
+
+chain 2845 6_cox_hap1 4731698 + 2673184 2673214 3 198022430 - 156603737 156603767 26791325
+30
+
+chain 2761 6_cox_hap1 4731698 + 3844406 3844465 6 171115067 + 18547856 18547915 4276868
+59
+
+chain 2745 6_cox_hap1 4731698 + 3842326 3844197 11 135006516 - 48638733 48640605 3968835
+61 675 676
+53 1015 1015
+67
+
+chain 2739 6_cox_hap1 4731698 + 2673924 2673968 8 146364022 + 90457478 90457522 20607564
+44
+
+chain 2729 6_cox_hap1 4731698 + 1302230 1302259 14 107349540 + 79349511 79349540 33029767
+29
+
+chain 2723 6_cox_hap1 4731698 + 2673793 2673825 5 180915260 - 70673106 70673138 18877917
+32
+
+chain 2561 6_cox_hap1 4731698 + 299599 299640 6 171115067 + 20244702 20244743 12574490
+41
+
+chain 2518 6_cox_hap1 4731698 + 4021649 4021704 16 90354753 - 20685134 20685189 24272036
+55
+
+chain 2470 6_cox_hap1 4731698 + 2745980 2746030 1 249250621 + 111776293 111776343 7607561
+50
+
+chain 2373 6_cox_hap1 4731698 + 2760156 2760181 17 81195210 - 66761411 66761436 17362234
+25
+
+chain 2319 6_cox_hap1 4731698 + 2900811 2900837 6 171115067 + 31357660 31357686 3303778
+26
+
+chain 2312 6_cox_hap1 4731698 + 2759490 2759549 4 191154276 + 98204882 98204941 18366184
+59
+
+chain 2209 6_cox_hap1 4731698 + 3843799 3843896 12 133851895 + 60159606 60159703 5400255
+97
+
+chain 2146 6_cox_hap1 4731698 + 1299766 1299827 12 133851895 + 105697047 105697108 23835468
+61
+
+chain 2140 6_cox_hap1 4731698 + 3840491 3840558 6 171115067 - 96829007 96829074 20827044
+67
+
+chain 2000 6_cox_hap1 4731698 + 1313744 1313777 4 191154276 + 153686345 153686378 8134925
+33
+
+chain 1995 6_cox_hap1 4731698 + 3842817 3842864 4 191154276 - 47817470 47817517 17212566
+47
+
+chain 1991 6_cox_hap1 4731698 + 2845315 2845345 4 191154276 - 30046978 30047008 15284842
+30
+
+chain 1990 6_cox_hap1 4731698 + 4008195 4011710 6 171115067 + 32722816 32726965 28700009
+61 2506 2690
+85 515 965
+52 103 103
+193
+
+chain 1943 6_cox_hap1 4731698 + 3844851 3845272 11 135006516 + 83226111 83226530 3906185
+58 323 321
+40
+
+chain 1927 6_cox_hap1 4731698 + 2759609 2759644 7 159138663 - 110094552 110094587 24531071
+35
+
+chain 1727 6_cox_hap1 4731698 + 2674522 2674583 20 63025520 - 53185733 53185794 4777998
+61
+
+chain 1671 6_cox_hap1 4731698 + 3843897 3843947 9 141213431 + 78317603 78317653 4355881
+50
+
+chain 1637 6_cox_hap1 4731698 + 2760272 2760326 2 243199373 + 119859185 119859239 11695157
+54
+
+chain 1632 6_cox_hap1 4731698 + 2673214 2673313 4 191154276 - 69486891 69486990 2834158
+99
+
+chain 1628 6_cox_hap1 4731698 + 3842952 3842991 2 243199373 - 116273698 116273737 14990340
+39
+
+chain 1584 6_cox_hap1 4731698 + 1313851 1313915 1 249250621 - 24961912 24961976 17607390
+64
+
+chain 1548 6_cox_hap1 4731698 + 2672923 2673038 2 243199373 - 193655574 193655689 3516324
+115
+
+chain 1509 6_cox_hap1 4731698 + 2674838 2674895 5 180915260 + 165569524 165569581 2491813
+57
+
+chain 1508 6_cox_hap1 4731698 + 2675985 2676708 6 171115067 - 141365359 141366083 3289535
+50 615 616
+58
+
+chain 1507 6_cox_hap1 4731698 + 2673661 2673741 4 191154276 + 138835824 138835904 16168846
+80
+
+chain 1489 6_cox_hap1 4731698 + 2845209 2846585 X 155270560 - 102215688 102216455 6549884
+27 1297 452
+2 0 236
+50
+
+chain 1467 6_cox_hap1 4731698 + 2760221 2760272 7 159138663 + 122232756 122232807 13147168
+51
+
+chain 1456 6_cox_hap1 4731698 + 3844931 3844983 14 107349540 + 48881293 48881345 9320615
+52
+
+chain 1452 6_cox_hap1 4731698 + 2673321 2674838 X 155270560 - 1098426 1099942 3000529
+51 1428 1427
+38
+
+chain 1354 6_cox_hap1 4731698 + 1313967 1314021 4 191154276 + 544307 544361 14282164
+54
+
+chain 1310 6_cox_hap1 4731698 + 3843714 3843782 X 155270560 + 17249549 17249617 3972308
+68
+
+chain 1307 6_cox_hap1 4731698 + 1498573 1498607 5 180915260 - 156542608 156542642 2089959
+34
+
+chain 1294 6_cox_hap1 4731698 + 2760418 2760473 4 191154276 + 147516497 147516552 12285122
+55
+
+chain 1278 6_cox_hap1 4731698 + 3845015 3845082 15 102531392 + 92125438 92125505 4023305
+67
+
+chain 1247 6_cox_hap1 4731698 + 3844702 3844748 2 243199373 - 7511493 7511539 13743690
+46
+
+chain 1194 6_cox_hap1 4731698 + 2676043 2676103 1 249250621 + 94380187 94380247 20995710
+60
+
+chain 1160 6_cox_hap1 4731698 + 2676209 2676237 X 155270560 + 56836392 56836420 21177535
+28
+
+chain 1125 6_cox_hap1 4731698 + 3890818 3890886 8 146364022 - 86779351 86779419 20749389
+68
+
+chain 1106 6_cox_hap1 4731698 + 2760181 2760221 9 141213431 + 74027839 74027879 13331514
+40
+
+chain 1039 6_cox_hap1 4731698 + 2674441 2674507 3 198022430 - 71498815 71498881 4421669
+66
+
+chain 1033 6_cox_hap1 4731698 + 2676372 2676431 5 180915260 - 20894072 20894131 3124143
+59
+
+chain 1014 6_cox_hap1 4731698 + 2759961 2759990 10 135534747 + 69125589 69125618 23828230
+29
+
+chain 1005 6_cox_hap1 4731698 + 2760005 2760039 10 135534747 + 5299750 5299784 23898321
+34
+
+chain 982 6_cox_hap1 4731698 + 2759426 2759479 13 115169878 + 111326976 111327029 14386536
+53
+
+chain 977 6_cox_hap1 4731698 + 3845410 3845467 X 155270560 - 144584413 144584470 4043690
+57
+
+chain 963 6_cox_hap1 4731698 + 2674253 2676589 9 141213431 - 119032541 119034846 4479982
+47 2231 2200
+58
+
+chain 919 6_cox_hap1 4731698 + 2677255 2677315 4 191154276 + 45112377 45112437 22402156
+60
+
+chain 883 6_cox_hap1 4731698 + 3843656 3843714 18 78077248 + 28929278 28929336 6530663
+58
+
+chain 881 6_cox_hap1 4731698 + 2675038 2675098 5 180915260 - 79225133 79225193 14536118
+60
+
+chain 858 6_cox_hap1 4731698 + 2676338 2676372 7 159138663 - 148564023 148564057 6699557
+34
+
+chain 857 6_cox_hap1 4731698 + 2676103 2677646 4 191154276 + 171430336 171431860 18546235
+50 1412 1393
+81
+
+chain 838 6_cox_hap1 4731698 + 3843947 3843980 18 78077248 - 28720814 28720847 7914761
+33
+
+chain 819 6_cox_hap1 4731698 + 2673062 2673118 2 243199373 + 149156283 149156339 14209631
+56
+
+chain 796 6_cox_hap1 4731698 + 1314021 1314060 X 155270560 - 10752795 10752834 16687246
+39
+
+chain 747 6_cox_hap1 4731698 + 1314275 1314339 12 133851895 + 57178267 57178331 20664563
+64
+
+chain 731 6_cox_hap1 4731698 + 1638596 1638636 15 102531392 + 55738847 55738887 18753864
+40
+
+chain 704 6_cox_hap1 4731698 + 3842767 3842817 9 141213431 + 32212289 32212339 4117535
+50
+
+chain 701 6_cox_hap1 4731698 + 2674653 2674701 16 90354753 - 23821388 23821436 3556080
+48
+
+chain 679 6_cox_hap1 4731698 + 1313640 1313672 21 48129895 - 2887431 2887463 13569070
+32
+
+chain 672 6_cox_hap1 4731698 + 3844325 3844357 10 135534747 - 103351577 103351609 5595826
+32
+
+chain 661 6_cox_hap1 4731698 + 2676159 2676209 9 141213431 + 85388422 85388472 5334226
+50
+
+chain 661 6_cox_hap1 4731698 + 3844987 3845015 2 243199373 + 98215178 98215206 5611311
+28
+
+chain 650 6_cox_hap1 4731698 + 2672375 2672435 7 159138663 - 140047518 140047578 22707410
+60
+
+chain 643 6_cox_hap1 4731698 + 2677085 2677144 6 171115067 + 74793831 74793890 5895430
+59
+
+chain 604 6_cox_hap1 4731698 + 1314169 1314195 X 155270560 - 101522169 101522195 11588450
+26
+
+chain 595 6_cox_hap1 4731698 + 2675343 2675387 12 133851895 - 110550302 110550346 3606052
+44
+
+chain 571 6_cox_hap1 4731698 + 2672827 2672901 3 198022430 + 50956018 50956092 15278850
+74
+
+chain 525 6_cox_hap1 4731698 + 3902955 3903021 6 171115067 + 32474022 32474088 26162225
+66
+
+chain 485 6_cox_hap1 4731698 + 2671938 2671998 1 249250621 - 193322919 193322979 8312425
+60
+
+chain 412 6_cox_hap1 4731698 + 2672740 2672827 8 146364022 - 113140827 113140914 13566503
+87
+
+chain 395 6_cox_hap1 4731698 + 2846505 2846533 X 155270560 - 102216470 102216498 6380381
+28
+
+chain 395 6_cox_hap1 4731698 + 2675098 2675125 12 133851895 + 9999203 9999230 23891782
+27
+
+chain 347 6_cox_hap1 4731698 + 2671704 2671754 15 102531392 - 65978487 65978537 12839282
+50
+
+chain 251 6_cox_hap1 4731698 + 2671761 2671812 9 141213431 + 17677697 17677748 27279073
+51
+
+chain 184 6_cox_hap1 4731698 + 2672526 2672587 X 155270560 - 91681431 91681492 16167874
+61
+
+chain 369716150 6_qbl_hap2 4565931 + 0 4565931 6 171115067 + 28742641 33379750 32
+2350 0 1
+1750 0 2
+3815 1 0
+9743 0 2
+3960 0 4
+2109 0 2
+33 2 0
+9000 0 2
+16647 0 2
+38786 1 0
+80529 0 1
+14475 0 1
+6819 1 0
+6845 1 3
+6188 0 1
+6397 0 1
+345 1 0
+68374 2 0
+39133 39 39
+7774 7 0
+1489 1 1
+72 1 1
+2260 0 2
+10629 0 1
+1249 1 1
+195 1 1
+18132 0 1
+1324 0 2
+5438 5 0
+2061 1 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4235 18 18
+493 9 9
+4767 7 7
+1225 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+281 11 11
+1178 0 4
+685 8 0
+48 4 0
+1701 1 1
+43 5 5
+862 18 18
+58 1 1
+66 1 1
+420 1 1
+44 1 1
+680 4 4
+1675 1 1
+83 1 1
+3082 4 0
+5467 1 1
+27 0 1
+1099 16 0
+627 51 51
+1278 6 1
+129 1 1
+25 1 1
+1397 15 15
+810 1 1
+27 1 1
+1192 2 0
+7515 4 0
+979 0 3
+3406 0 2
+2340 1 1
+20 1 1
+1139 1 1
+26 1 1
+787 0 1
+1416 3 1
+22815 4 4
+126 1 0
+38 1 1
+140 1 0
+999 0 17
+56 0 15
+11759 161391 161513
+11155 0 2
+5376 0 1
+19253 1 0
+4212 1 1
+3671 1 0
+21 0 6
+4451 1 0
+27910 1 0
+9946 0 1
+11233 1 1
+32 1 1
+2238 1 1
+20 1 1
+3659 22 16
+1218 1 0
+1638 6 6
+228 1 1
+45 1 1
+2048 0 3
+461 1 0
+20759 1 0
+3778 2 1
+1268 1 0
+1511 1 1
+42 2 0
+24 1 1
+4119 22 0
+1757 1 0
+1527 1 1
+29 1 1
+1886 1 0
+10628 12 0
+46568 1 0
+18985 0 10
+1825 3 4
+5288 0 9
+1071 50 50
+1607 1 5
+722 0 1
+502 0 1
+1025 0 1
+134 14 0
+4944 0 1
+319 1 0
+6178 0 1
+2898 0 2
+143 0 1
+1775 1 0
+2123 0 1
+2715 1 0
+4901 70 66
+2884 1 0
+1362 1 0
+1233 0 8
+2134 0 1
+1042 0 1
+163 1 1
+45 1 1
+50 2 0
+64 1 1
+48 1 1
+380 0 1
+30 1 0
+30 1 1
+61 1 1
+22 1 1
+368 4 4
+319 5 7
+310 1 1
+37 3 1
+162 1 1
+194 2 0
+36 1 1
+242 9 9
+1932 1 1
+16 1 1
+528 1 1
+20 1 1
+509 0 5
+76 1 1
+21 1 1
+439 15 15
+2779 1 0
+1597 24 28
+59 12 12
+307 1 0
+516 1 0
+286 11 33
+339 5 0
+570 1 1
+37 1 1
+220 1 0
+72 1 1
+144 1 1
+48 1 1
+247 2 0
+174 9 10
+816 1 0
+940 1 1
+45 1 1
+91 3 3
+71 1 1
+291 14 14
+100 1 1
+23 1 1
+452 3 3
+85 1 1
+65 1 1
+77 1 1
+252 0 1
+129 15 15
+432 10 0
+85 1 1
+28 1 1
+189 2 1
+71 1 1
+52 8 0
+810 2 2
+63 1 1
+378 1 1
+26 1 1
+187 31 36
+966 1 1
+25 1 1
+91 12 12
+125 1 1
+38 1 1
+433 2 0
+596 1 1
+48 1 1
+465 4 4
+64 1 1
+20 1 1
+525 5 5
+237 3 8
+183 11 0
+364 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+67 16 16
+244 1 1
+54 5 5
+929 1 1
+21 1 1
+126 0 3
+830 1 11
+59 1 1
+537 0 2
+24 1 1
+745 15 15
+810 1 0
+425 1 1
+89 1 1
+592 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 41 41
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+155 155 0
+34 1 1
+50 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+345 1 1
+39 1 1
+504 18 18
+596 12 12
+54 1 1
+158 1 1
+164 1 1
+34 1 1
+626 15 15
+866 0 10
+1051 0 2611
+680 0 1
+1537 0 18
+75 1 0
+147 52 1
+119 0 12
+23 1 1
+1927 13 13
+1702 2 0
+3694 1 1
+18 1 1
+958 43 47
+246 2 0
+146 1 1
+49 1 1
+410 1 0
+667 1 1
+38 1 1
+362 7 1
+159 2 0
+515 2 0
+1026 1 1
+29 1 1
+249 0 6
+129 1 1
+33 4 0
+10 1 5
+1236 1 1
+20 1 1
+138 10 9
+448 0 3
+660 1 1
+28 1 1
+83 1 1
+51 1 1
+2659 1 1
+38 1 1
+424 0 1
+70 1 1
+820 1 1
+26 1 1
+1472 1 1
+21 1 1
+491 5 5
+2372 2 0
+533 6 0
+441 1 7
+1689 1 1
+26 3 4
+879 16 16
+514 0 2
+58 1 1
+350 1 0
+769 1 1
+39 1 1
+429 10 10
+134 0 4
+37 1 1
+144 8 8
+668 1 1
+22 1 1
+344 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+198 0 1
+32 1 1
+74 11 15
+1255 0 2
+332 1 1
+21 1 1
+193 8 24
+34 1 1
+79 1 1
+29 1 1
+536 1 0
+308 0 1
+850 0 32
+23 1 1
+651 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 2
+713 7 7
+89 1 0
+293 9 8
+125 1 1
+31 1 1
+192 6 6
+171 17 17
+681 1 1
+43 1 1
+514 1 1
+68 1 1
+537 1 1
+35 1 1
+159 6 6
+778 2 2
+44 1 1
+168 0 7
+211 1 1
+42 1 1
+1253 1 1
+29 1 1
+320 1 1
+36 2 2
+55 1 2
+108 1 1
+33 1 1
+317 1 1
+35 1 1
+553 8 8
+386 1 1
+26 1 1
+540 1 1
+31 1 1
+65 0 1
+625 12 12
+313 0 1
+52 1 1
+22 1 1
+583 1 1
+49 1 1
+678 37 37
+784 3 0
+838 1 1
+19 12 0
+1129 1 1
+36 1 1
+553 8 8
+109 1 1
+45 1 1
+841 16 15
+157 1 1
+31 2 2
+204 18 19
+487 1 1
+29 1 1
+374 1 1
+67 1 1
+720 13 13
+266 10 10
+330 16 14
+413 1 1
+44 1 1
+78 6 6
+181 2 2
+36 1 1
+397 1 1
+20 1 1
+311 1 1
+48 2 2
+1298 11 11
+186 1 1
+33 1 1
+216 4 4
+35 1 1
+194 10 10
+310 1 1
+51 1 1
+136 1 1
+49 1 1
+521 1 1
+23 1 1
+242 1 1
+49 1 1
+600 1 1
+31 1 1
+413 15 15
+290 1 1
+49 1 1
+527 17 17
+340 12 11
+1025 1 0
+2572 1 1
+29 1 1
+397 2 5
+668 13 13
+541 1 1
+59 0 2
+6 1 1
+122 14 14
+51 1 1
+46 1 1
+72 5 5
+110 1 1
+76 1 1
+164 0 21
+136 1 1
+12 1 1
+66 16 16
+456 37 34
+371 7 7
+48 1 1
+194 10 10
+108 1 1
+60 1 1
+122 0 1
+48 1 1
+238 1 1
+32 0 1
+100 1 0
+72 1 0
+390 1 1
+38 1 1
+144 1 1
+27 0 4
+184 21 228
+49 1 1
+608 0 1
+152 1 1
+31 1 1
+281 8 8
+337 1 1
+45 1 1
+222 1 1
+54 1 1
+346 1 0
+44 1 1
+368 1 1
+72 1 1
+502 36 18
+63 1 1
+43 0 4
+136 1 1
+42 1 1
+80 4 4
+35 1 0
+89 1 1
+24 0 5
+829 13 13
+73 1 1
+28 14 0
+233 1 1
+42 0 3
+85 0 1
+400 1 1
+40 1 1
+538 25 25
+174 1 1
+20 1 1
+705 1 1
+26 2 2
+614 1 1
+44 1 1
+793 1 1
+16 1 1
+747 5 5
+804 1 1
+29 1 1
+166 1 1
+43 1 1
+233 1 1
+44 1 1
+507 0 3
+110 8 8
+133 1 1
+31 1 1
+165 1 1
+29 1 1
+1249 1 1
+26 4 0
+56 1 1
+67 1 1
+716 1 1
+46 0 1
+16 1 1
+174 1 1
+96 1 1
+141 1 1
+39 0 4
+263 1 1
+18 1 1
+259 4 4
+38 1 1
+104 1 1
+40 1 0
+248 1 1
+18 1 1
+238 1 1
+32 1 1
+70 0 2
+16 1 1
+818 1 1
+22 4 4
+492 4 4
+1145 1 1
+46 1 1
+53 1 0
+38 1 1
+373 1 1
+60 1 1
+1149 0 1
+20 1 1
+1294 1 1
+41 1 1
+316 4 4
+42 1 1
+218 12 12
+363 1 1
+24 1 1
+457 10 10
+414 13 13
+825 1 1
+41 1 1
+492 0 4
+1374 1 1
+18 1 1
+808 2 2
+335 6 4
+880 1 1
+35 1 1
+236 1 1
+67 1 1
+298 0 1
+147 4 4
+322 11 11
+613 1 1
+62 1 1
+340 1 1
+22 1 1
+1057 1 1
+57 1 1
+358 1 1
+128 1 1
+146 10 10
+490 1 1
+20 1 1
+62 1 1
+88 1 1
+293 1 1
+28 1 0
+20 1 1
+83 0 1
+90 1 1
+312 1 1
+44 1 1
+1213 1 1
+51 1 1
+467 1 1
+39 1 1
+122 14 0
+35 1 1
+485 14 14
+110 12 0
+127 1 1
+5450 0 5
+1699 9 9
+3278 0 2
+28 1 1
+2211 2 0
+521 1 1
+18 1 1
+784 18 18
+1603 0 248
+4769 47 47
+4486 4 4
+103 0 2
+88 1 1
+95 1 1
+2174 1 1
+22 0 1
+1244 7 7
+922 2 0
+1507 1 1
+44 1 1
+208 6 1
+1946 2 2
+85 0 1
+133 1 1
+666 1 0
+52 1 1
+29 1 1
+148 0 5
+30 1 1
+790 14 14
+52 1 1
+32 1 1
+121 1 1
+37 1 1
+396 3 2
+324 1 1
+152 1 1
+71 4 4
+27 1 1
+115 1 1
+101 1 1
+423 10 10
+294 1 1
+101 1 0
+4 0 1
+174 1 1
+146 1 1
+103 1 1
+134 1 1
+16 1 1
+378 1 1
+85 1 1
+134 1 1
+25 1 1
+54 3 3
+55 1 1
+67 1 1
+22 1 1
+54 13 13
+55 11 11
+120 1 1
+23 1 1
+51 1 1
+22 1 1
+364 1 1
+278 1 1
+354 34448 40149
+311 1 1
+33 1 2
+26 6 6
+474 1 1
+36 1 1
+151 1 1
+29 1 1
+120 1 1
+23 1 1
+865 1 1
+39 1 1
+553 1 1
+69 1 1
+116 1 0
+1618 9 9
+820 11 11
+173 0 8
+405 9 9
+196 1 1
+26 1 1
+173 1 1
+27 5 1
+42 1 1
+676 17 19
+77 1 3
+65 16 16
+69 1 0
+277 1 1
+44 1 1
+72 0 3
+70 1 1
+54 1 1
+240 1 0
+31 1 1
+1192 18 19
+454 28 28
+373 1 1
+46 1 1
+1565 1 1
+53 2 2
+543 1 1
+38 1 1
+985 1 1
+27 0 1
+8 1 1
+158 0 38
+656 1 1
+104 1 1
+771 1 1
+21 1 1
+398 1 1
+16 1 2
+163 4 3
+94 1 1
+44 1 1
+172 1 0
+122 5 5
+193 16 16
+535 2 2
+17 1 0
+93 1 1
+580 1 1
+91 1 1
+141 1 1
+79 1 1
+80 13 13
+165 1 1
+129 1 1
+114 1 1
+30 1 1
+83 1 1
+35 1 1
+126 16 16
+270 0 1
+111 9 9
+151 1 1
+118 1 1
+253 1 1
+45 18468 20220
+102 1 1
+20 1 1
+111 1 1
+97 1 0
+86 1 1
+70 0 4
+69 1 1
+52 0 1
+219 3 3
+76 1 5
+209 4 4
+22 1 1
+61 1 1
+91 1 1
+194 0 21
+15 0 1
+229 1 1
+185 0 1
+113 5 5
+45 1 1
+53 1 1
+37 1 1
+157 1 1
+279 1 1
+233 1 1
+19 0 8
+67 2 0
+41 1 1
+102 12 12
+275 14 14
+70 1 1
+82 2 2
+224 5 1
+490 0 22
+3841 1 0
+3216 1 1
+42 1 1
+1914 0 3
+616 11 12
+144 1 1
+21 2 1
+775 1 1
+50 1 1
+50 2 2
+96 2 2
+1522 4 0
+58 0 2
+1099 1 1
+42 1 1
+3502 0 6
+255 1 1
+40 1 1
+150 0 4
+18 1 1
+589 1 1
+37 1 1
+539 5 5
+354 1 3
+128 1 1
+58 1 1
+159 1 1
+5 2 0
+21 1 1
+231 1 1
+82 3 3
+69 3 0
+549 1 1
+69 1 1
+74 9 9
+126 1 1
+47 1 1
+614 9 9
+138 1 1
+29 1 1
+681 1 1
+49 1 1
+67 1 1
+19 4 9
+234 1 1
+93 1 1
+60 4 4
+96 4 4
+76 1 1
+169 1 1
+418 1 1
+130 1 1
+44 1 1
+69 1 1
+80 1 1
+76 1 1
+41 1 1
+129 6 11
+363 1 1
+42 1 1
+295 1 1
+43 1 1
+83 6 0
+52 0 2
+1228 1 1
+34 1 1
+3527 20 0
+1768 2 1
+2467 0 2
+101 10 0
+129 1 1
+37 1 1
+121 1 1
+25 1 1
+161 1 0
+97 1 1
+124 1 0
+178 1 1
+34 1 1
+54 1 1
+38 1 2
+634 83 83
+874 1 1
+40 1 1
+59 0 1
+59 4 4
+316 1 1
+178 1 1
+103 1 1
+61 1 1
+220 1 1
+61 1 1
+296 1 1
+33 1 1
+185 12 12
+269 1 1
+84 1 1
+864 15 15
+241 1 0
+79 3 3
+161 1 1
+48 1 1
+539 1 1
+44 1 1
+357 1 1
+37 1 1
+436 1 1
+59 1 1
+71 1 1
+261 1 1
+289 1 1
+47 1 1
+95 12 12
+97 4 4
+27 1 1
+100 1 1
+16 1 1
+101 1 1
+33 1 2
+481 1 1
+42 1 1
+206 7 7
+56 12 12
+179 10 10
+80 1 1
+41 1 1
+251 1 1
+306 1 1
+80 2 0
+4 94 0
+433 1 1
+23 1 1
+107 1 0
+265 1 1
+49 1 1
+282 72 72
+838 7 7
+60 1 0
+108 1 1
+24 1 1
+134 1 1
+32 1 0
+158 0 2
+1040 1 1
+42 1 1
+737 1 0
+790 1 1
+9 2 1
+11 1 1
+129 1 1
+23 1 1
+894 1 1
+43 3 3
+854 1 1
+23 0 1
+23 2 0
+26 1 1
+395 0 15
+403 5 5
+14 1 1
+2454 1 1
+76 1 1
+170 1 1
+18 1 1
+574 4 0
+291 1 1
+47 1 1
+786 19 0
+88 10 11
+48 1 1
+58 1 1
+28 1 1
+500 0 2
+1280 1 1
+28 1 1
+975 1 0
+3231 1 0
+865 1 1
+39 1 1
+1561 109 100
+1037 0 1
+510 1 1
+49 1 1
+1253 1 1
+19 1 1
+1078 3 0
+221 1 1
+21 1 0
+899 0 4
+466 1 1
+38 1 1
+297 0 3
+730 19 6
+1043 1 1
+49 1 1
+273 0 1
+708 1 0
+364 14 13
+58 1 1
+74 1 1
+614 60 60
+1889 4 0
+531 1 1
+19 1 1
+1944 5 0
+163 6 7
+1206 0 2
+718 1 1
+41 7 0
+1795 13 13
+1390 1 0
+2933 0 16
+540 1 1
+14 1 1
+167 1 0
+897 17 4
+1208 1 0
+1307 1 1
+20 1 1
+540 0 10
+203 2 0
+44 1 1
+298 1 0
+87 11 10
+491 14 8
+991 1 1
+74 6 0
+179 1 1
+34 1 1
+448 10 0
+1688 1 1
+38 21 0
+173 1 1
+49 2 1
+2161 30 30
+203 1 0
+89 1 0
+492 1 1
+30 1 1
+1212 3 0
+990 1 1
+38 1 1
+780 1 0
+191 1 1
+47 6 6
+393 1 1
+41 1 1
+259 1 0
+941 1 1
+20 1 1
+185 0 6
+165 0 16
+420 3 1
+130 1 1
+31 1 1
+253 18 18
+720 16 18
+1257 3 0
+986 0 4
+3311 1 1
+26 1 1
+556 0 4
+120 0 1
+1273 1 1
+20 1 1
+338 8 8
+3965 0 3
+15 1 1
+2531 17 17
+3334 5 5
+121 13 13
+161 1 1
+45 1 1
+94 14 14
+63 9 10
+2108 1 1
+34 1 1
+1436 1 1
+47 1 1
+273 7 0
+153 0 5
+283 12 12
+619 1 1
+36 0 4
+225 1 1
+23 1 1
+553 5 0
+2334 1 1
+49 1 1
+350 1 1
+31 1 1
+1012 2 2
+422 1 1
+46 1 1
+91 4 19
+468 0 1
+46 1 1
+1491 0 4
+426 0 1
+1144 1 2
+1131 1 1
+20 1 1
+1533 16 0
+3103 44 45
+4016 12 12
+346 0 1
+943 1 0
+524 1 1
+20 1 1
+151 3 3
+144 1 1
+189 1 7
+750 1 0
+695 1 0
+1003 0 2
+7819 1 1
+78 1 1
+1811 0 1
+3177 0 1
+8990 0 1
+2268 1 1
+35 0 10
+8205 1 0
+3193 1 1
+76 1 1
+10955 0 1
+22875 0 20
+2417 1 0
+998 0 13
+4236 8 0
+4845 0 2
+64 40 34
+10941 1 1
+40 1 1
+4759 0 6
+12084 0 3
+3052 0 4
+2989 1 0
+13523 1 3
+16170 1 0
+11761 0 3
+3912 3 0
+6620 0 7
+7633 3 0
+419 2 0
+10690 5 24
+10798 0 1
+296 0 1
+1770 4 0
+374 0 4
+230 16 16
+7468 1 0
+1229 1 0
+3061 1 0
+5818 1 0
+2415 12 9
+2056 0 1
+955 4 0
+20022 0 1
+4418 2 1
+2375 0 4
+2086 1 1
+32 1 1
+1225 1 0
+857 2 0
+1154 0 1
+4667 1 0
+170 0 3
+2376 0 1
+2799 10 10
+1512 4 0
+68 9 1
+2170 1 1
+47 1 1
+318 2 0
+19 0 6
+14527 1 1
+33 1 1
+3080 1 1
+23 1 1
+1645 6 6
+231 0 1
+2136 2 0
+6222 0 1
+830 1 1
+24 1 1
+8326 1 0
+2939 1 0
+3959 0 2
+3746 0 2
+1011 1 1
+34 1 1
+7443 0 1
+688 2 0
+574 1 1
+29 1 1
+1799 13 1
+4074 2 0
+136 1 1
+77 1 1
+528 19 0
+253 0 1
+204 1 0
+129 2 0
+811 1 1
+38 1 1
+2347 52 0
+4634 1 0
+856 14 14
+193 0 4
+855 1 1
+28 1 1
+1255 1 1
+36 1 1
+97 0 1
+58 1 1
+1708 1 1
+48 1 1
+958 15 0
+3371 1 1
+37 1 1
+4267 0 13
+1061 0 1
+272 0 26
+8 1 15
+25 0 2
+112 2 0
+26 4 32
+4090 0 1
+3270 1 1
+17 1 1
+2822 0 1
+6206 1 0
+2318 0 2
+1504 0 1
+6189 3 0
+396 22 12
+918 0 1
+2340 1 1
+33 1 1
+326 1 1
+80 1 1
+205 3 2
+81 8 17
+2671 0 1
+1099 0 1
+144 1 1
+29 0 1
+2097 0 3
+24 3 0
+1207 4 4
+45 1 1
+757 0 5
+1926 1 1
+40 1 1
+2657 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+713 0 4
+58 3 0
+1027 3 0
+428 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+6611 0 3
+1575 4 5
+36 1 1
+99 2 0
+700 0 2
+151 0 1
+467 11 11
+272 0 3
+40 1 1
+2428 0 1
+750 2 0
+473 0 2
+421 1 1
+34 1 1
+1575 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+11881 1 1
+30 1 1
+4383 2 0
+6883 49 49
+3146 0 1
+906 3 0
+887 1 1
+80 1 1
+3115 0 1
+1037 1 0
+5866 0 2
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 3 0
+3170 1 0
+1751 0 1
+910 3 0
+691 0 1
+5793 0 1
+26407 1 0
+672 0 1
+19269 29 35
+1371 29 0
+494 2 0
+20417 1 0
+18633 0 1
+601 1 0
+319 0 1
+6820 1 0
+5718 0 2
+17894 1 0
+4272 1 0
+4967 3 1
+290 1 0
+2447 1 0
+740 1 9
+9299 0 18
+7427 1 0
+8151 2 1
+673 1 0
+3453 0 1
+149 0 1
+611 0 4
+4662 0 4
+1752 1 1
+78 1 1
+1581 0 1
+1092 2 0
+159 1 0
+4480 0 2
+4019 0 1
+1451 22 23
+816 1 0
+8701 1 1
+23 1 1
+1796 2 0
+5015 6 1
+1383 8 0
+2368 1 1
+31 1 0
+1883 3 0
+335 0 1
+4157 0 1
+561 4 0
+1538 1 1
+61 0 1
+159 0 2
+3362 4 0
+3333 1 1
+46 1 1
+2307 1 0
+170 1 0
+5972 0 2
+840 0 2
+55 1 1
+28 1 1
+1154 0 2
+650 0 4
+30 0 4
+1100 10 11
+4343 6 0
+1663 4 0
+150 1 0
+3128 1 0
+1449 1 0
+2023 0 1
+428 3 6
+299 2 0
+427 7 7
+1914 14 14
+1273 7 7
+1444 72 0
+423 0 4
+954 1 0
+2467 1 0
+190 8 8
+2034 3 1
+6396 1 1
+34 1 1
+485 1 0
+348 7 0
+770 1 1
+29 0 13
+65 1 1
+1358 0 1
+302 0 1
+659 12 12
+293 0 1
+610 0 1
+906 12 0
+1331 0 6
+1786 0 1
+463 0 1
+4305 0 4
+1041 1 0
+11424 3 1
+13797 0 8
+166 0 1
+1510 5 0
+9069 0 8
+25 1 1
+332 5 3
+76 0 1
+1306 1 1
+46 1 1
+134 19 23
+1467 1 1
+32 1 1
+449 17 0
+367 9 9
+3525 12 10
+91 3 0
+1430 1 1
+24 1 1
+1156 9 13
+843 1 1
+28 1 1
+515 0 17
+1559 0 4
+1045 9 9
+1953 1 0
+31 1 1
+843 0 1
+2174 1 0
+3788 1 0
+2001 0 1
+2400 0 1
+1614 1 0
+8167 0 1
+2700 2 0
+2735 0 1
+8508 1 1
+57 1 1
+141 0 3
+448 1 1
+22 1 1
+2215 1 1
+32 1 1
+1714 32 32
+667 14 14
+142 1 0
+789 1 1
+45 1 1
+84 1 1
+95 1 1
+465 1 1
+45 6 4
+541 1 1
+42 1 1
+1339 5 6
+391 1 1
+20 0 1
+251 1 1
+22 1 1
+561 0 2
+78 3 0
+1718 1 1
+12 1 1
+1042 1 1
+38 1 1
+301 14 0
+222 10 10
+436 10 10
+556 55 55
+953 1 1
+17 1 1
+1752 20 0
+1561 135 0
+58 0 45
+245 101 11
+46 90 0
+150 0 270
+54 180 0
+2130 12 12
+1630 1 1
+26 1 1
+189 0 14
+296 2 0
+809 2 0
+17 20 0
+665 0 40
+236 1 1
+44 1 1
+352 1 1
+25 1 1
+554 6 6
+850 1 1
+33 1 1
+809 3 13
+1832 7 9
+468 1 1
+21 1 1
+951 1 1
+22 1 1
+219 17 18
+733 0 14
+215 2 2
+36 1 1
+301 1 1
+22 1 1
+241 1 1
+52 0 1
+47 1 1
+72 1 1
+109 1 1
+129 1 1
+28 1 1
+174 8 8
+683 3 0
+1190 285 0
+48 1 1
+1330 12 0
+557 17 17
+932 3 1
+27 1 1
+166 1 1
+19 1 1
+406 1 1
+48 3 3
+137 1 0
+161 6 6
+884 2 0
+58 1 1
+107 1 1
+150 14 14
+522 1 1
+28 1 1
+945 4 4
+34 1 1
+472 0 2
+203 0 1
+281 1 1
+46 1 1
+1130 1 0
+232 17 17
+510 1 1
+33 1 1
+62 10 10
+1501 1 1
+20 1 1
+573 1 1
+29 1 1
+928 0 3
+304 1 1
+41 1 1
+160 1 1
+58 1 1
+656 1 1
+40 4 0
+108 6 6
+321 1 1
+14 0 16
+91 1 1
+184 1 1
+43 8 3
+180 1 1
+68 1 1
+144 1 1
+27 1 0
+17 1 1
+212 0 1
+212 1 1
+34 1 1
+115 1 1
+41 1 1
+407 10 10
+200 1 1
+44 2 0
+187 2 0
+146 1 1
+17 1 1
+122 4 4
+73 1 0
+56 1 1
+155 1 17
+80 15 15
+458 1 1
+16 3 3
+343 1 1
+111 1 1
+160 55 55
+157 12 12
+346 0 2
+382 4 0
+35 1 1
+937 0 1
+246 25 0
+52 0 1
+419 0 1
+165 1 0
+75 24 3
+297 1 1
+38 1 1
+5066 1 0
+4922 7 9
+2488 14 14
+2241 1 1
+67 4 4
+39 1 0
+547 1 1
+43 1 1
+524 3715 901
+1796 4 2
+138 2 2
+16 1 1
+415 1 1
+18 1 1
+367 0 89
+1600 0 6
+2175 0 5
+606 14 14
+519 1 0
+540 1 1
+40 1 1
+568 2 0
+165 1 2
+31 1 1
+259 1 1
+41 1 1
+452 31 31
+623 40 62
+818 1 1
+42 1 1
+565 1 1
+44 1 1
+571 10 8
+61 1 1
+28 1 1
+233 2 0
+33 28 0
+53 1 1
+37 1 1
+75 0 396
+156 1 0
+473 0 4
+421 1 1
+35 1 1
+2132 1 1
+80 0 2
+544 9 9
+152 2 1
+33 1 1
+2932 1 1
+44 0 1
+164 22 0
+149 1 0
+534 1 1
+36 1 1
+113 1 1
+15 1 1
+661 1 1
+48 1 1
+1987 1 0
+34 1 1
+444 1 1
+45 1 1
+65 1 1
+67 1 1
+210 1 1
+68 1 1
+55 1 1
+47 1 1
+169 1 1
+64 1 1
+109 0 6
+77 2 32
+6 0 5
+67 0 1
+7 16 0
+51 12 0
+36 0 12
+700 1 1
+33 1 0
+49 0 2
+450 0 1
+98 4 0
+489 32 0
+63 5 1
+78 7 7
+538 17 17
+1269 1 0
+841 1 1
+43 1 1
+2004 1 1
+41 1 1
+86 0 4
+5 1 0
+36 1 1
+573 2 1
+297 1 0
+85 1 1
+30 1 1
+1041 1 0
+12 1 1
+392 33 12
+515 5 6
+583 1 1
+33 1 1
+616 16 16
+1052 0 11
+39 1 1
+184 1 1
+67 1 1
+102 7 7
+58 0 1
+307 1 1
+56 0 3
+930 21 19
+1264 0 1
+832 1 1
+28 1 1
+272 1 1
+82 1 1
+56 1 0
+976 6 6
+2015 0 3
+84 9 9
+130 13 17
+564 10 15
+154 1 0
+438 10 10
+38 0 5
+2141 1 1
+25 1 1
+73 10 10
+70 5 5
+132 1 1
+52 1 1
+599 1 1
+46 1 1
+279 1 1
+18 1 1
+239 2 0
+383 6 0
+224 0 1
+321 3 0
+8 16 0
+1775 1 1
+18 2 0
+575 16 16
+60 1 1
+16 1 1
+1247 2 0
+173 3 0
+41 1 1
+57 8 8
+285 2 0
+672 1 1
+44 1 1
+106 0 1
+148 1 1
+49 3 0
+146 5 11
+91 1 1
+79 1 1
+94 1 1
+101 1 1
+88 16 16
+117 1 1
+15 1 1
+58 1 1
+93 1 1
+140 1 0
+326 1 1
+44 1 1
+160 1 1
+23 1 1
+481 14 14
+181 4 4
+72 1 1
+25 1 1
+88 1 3
+36 0 12
+92 1 1
+56 10 0
+13 0 1
+66 1 1
+141 2 0
+65 1 1
+367 0 2
+610 1 1
+22 1 1
+150 1 1
+85 1 1
+109 1 1
+167 3 1
+23 1 0
+26 1 1
+74 1 1
+33 1 1
+176 1 1
+25 2 2
+193 1 1
+35 0 1
+383 0 5
+249 1 1
+69 1 1
+98 1 1
+62 1 1
+62 1 2
+74 0 1
+68 1 1
+438 1 1
+64 1 1
+47 0 8
+125 3 0
+75 5 5
+45 1 1
+197 1 1
+27 1 1
+116 13 13
+218 15 20
+1107 16 19
+73 1 1
+25 1 1
+199 1 1
+60 1 1
+994 1 1
+43 0 1
+18 1 1
+1215 18 18
+340 1 1
+34 1 1
+1350 16 16
+1726 4 4
+193 1 1
+48 1 1
+295 1 1
+18 1 1
+411 19 19
+175 1 1
+49 1 1
+146 1 1
+61 1 1
+116 1 1
+41 1 1
+137 1 1
+30 1 1
+158 9 9
+136 10 13
+349 8 8
+468 1 1
+44 1 1
+862 17 17
+813 1 1
+24 1 1
+214 10 4
+228 1 1
+34 1 1
+101 12 12
+242 1 1
+69 1 1
+185 1 1
+24 1 0
+164 0 1
+222 1 1
+25 1 1
+297 10 10
+1171 1 0
+182 1 1
+35 1 1
+350 19 19
+1966 1 1
+24 1 1
+548 7 7
+208 13 12
+298 1 1
+65 1 1
+193 2 2
+28 1 1
+125 4 4
+95 7 7
+566 1 1
+40 1 1
+118 0 1
+318 1 0
+374 1 1
+58 1 1
+143 1 1
+74 1 1
+53 21 0
+81 1 1
+45 1 1
+138 15 16
+180 1 1
+62 1 1
+661 1 1
+48 1 1
+1463 1 0
+156 0 1
+148 1 1
+19 1 0
+17 1 1
+1927 4 0
+1469 14 14
+466 0 1
+3098 0 1
+1141 2 3
+743 14 14
+79 1 1
+22 1 1
+362 0 1
+682 16 9
+275 0 4
+539 1 0
+61 0 7
+331 0 4
+130 1 1
+31 0 3
+1554 1 1
+43 1 1
+224 1 1
+49 1 1
+159 3 0
+1064 27 27
+104 1 1
+21 1 1
+222 2 2
+49 1 1
+1397 1 1
+37 1 1
+414 0 2
+695 1 1
+31 1 1
+742 1 1
+21 1 1
+230 3 2
+42 1 1
+68 1 1
+37 1 1
+703 0 3
+2216 84 83
+1430 1 1
+23 1 1
+1867 13 0
+35 1 1
+137 16 16
+1500 4 0
+4546 1 1
+25 1 1
+358 19 19
+1549 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+498 3 0
+321 0 1
+281 3 0
+414 1 1
+70 1 1
+284 1 0
+214 1 1
+28 1 1
+280 1 0
+650 1 1
+47 1 1
+1030 1 1
+91 1 1
+6520 5 5
+462 1 0
+2864 0 3
+1930 0 4
+2915 1 1
+20 1 1
+413 1 0
+1844 11 11
+133 0 6
+569 10 10
+110 12 12
+184 0 3
+228 1 1
+43 2 2
+51 14 13
+1499 1 0
+12 1 1
+378 1 1
+49 1 1
+424 1 0
+1069 1 1
+142 0 1
+821 2 9
+311 1 6
+247 1 1
+86 1 1
+1850 1 1
+26 1 1
+498 1 1
+34 1 1
+688 5 9
+44 1 1
+369 1 1
+69 1 1
+156 2 0
+83 1 1
+128 1 1
+50 9 9
+249 1 1
+70 0 1
+624 2 0
+74 2 1
+300 1 1
+26 1 1
+240 4 0
+1705 1 1
+52 1 1
+231 29 24
+378 2 0
+236 1 1
+76 1 1
+116 9 12
+301 20 20
+59 0 6
+43 1 1
+384 15 15
+1414 5 0
+225 0 2
+1234 1 0
+29 1 1
+235 10 10
+227 1 1
+77 4 0
+43 5 9
+485 7 7
+380 10 0
+46 1 0
+90 1 1
+161 1 1
+401 1 1
+58 1 1
+2127 3 0
+186 20 20
+323 5 5
+47 1 1
+236 1 1
+31 0 2
+1568 1 1
+136 0 1
+202 0 3
+77 1 1
+44 1 1
+411 12 11
+317 0 2
+599 1 1
+37 1 1
+391 1 0
+273 1 0
+744 0 4
+703 1 1
+20 1 1
+198 3 0
+158 19 15
+27 12 0
+282 1 1
+32 4 0
+740 1 0
+327 1 1
+105 1 1
+146 16 16
+101 1 0
+21 1 1
+232 1 1
+33 2 0
+12 1 1
+189 1 1
+30 2 2
+544 1 1
+153 1 1
+586 5 0
+1351 21 0
+446 49 49
+121 7 7
+1147 12 12
+777 1 0
+701 1 1
+29 2 2
+154 12 12
+191 1 1
+55 1 1
+113 0 1142
+87 0 2
+15 0 1
+525 1 1
+22 1 1
+355 10 10
+50 0 8
+252 1 1
+31 1 1
+354 6 5
+148 15 15
+407 1 1
+42 1 1
+275 0 1
+737 5 9
+1432 1 1
+39 1 1
+84 0 2
+77 7 7
+514 20 20
+385 7 1
+815 1 1
+45 1 1
+487 1 1
+66 1 1
+2379 0 24
+779 1 1
+18 1 0
+2653 4 0
+34 1 1
+191 1 1
+35 1 1
+1174 12 0
+2497 1 1
+24 0 1500
+447 8 0
+3268 1 0
+946 1 0
+2223 20044 20060
+119 1 1
+71 0 3
+53 0 5
+40 1 1
+309 1 1
+57 1 1
+101 1 1
+47 2 2
+67 1 1
+47 1 1
+74 0 1
+28 1 1
+167 1 1
+33 1 1
+543 1 1
+27 11 34
+33 1 1
+149 7 7
+61 1 1
+120 1 1
+366 1 1
+55 1 1
+121 1 1
+62 1 1
+78 1 1
+48 1 1
+161 1 1
+26 1 1
+191 1 1
+20 11 11
+550 1 1
+76 1 0
+20 1 1
+112 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+83 1 1
+46 1 1
+1500 1 1
+81 1 1
+210 1 1
+26 1 1
+713 1 1
+48 1 1
+723 0 3
+196 6 6
+62 2 2
+32 1 1
+606 1 2
+357 1 1
+38 292 0
+589 1 1
+30 1 1
+714 8 8
+639 1 1
+20 1 1
+1068 0 1
+571 1 1
+49 1 1
+436 0 1
+609 0 2
+30 1 1
+66 0 1
+349 11 11
+65 1 1
+40 1 1
+717 0 3
+299 1 1
+29 1 1
+724 1 0
+275 1 1
+33 1 1
+318 0 3
+279 1 1
+28 1 1
+389 1 0
+548 0 8
+330 1 1
+47 1 1
+170 1 1
+47 1 1
+519 14 14
+841 24 24
+732 1 1
+29 3 3
+688 2 2
+23 0 1
+94 14 14
+726 13 13
+508 0 12
+21 6 0
+69 1 1
+37 1 1
+590 1 1
+59 1 1
+89 11 11
+164 1 1
+58 1 1
+1709 18 18
+520 1 1
+27 1 1
+683 10 10
+814 1 1
+26 1 1
+350 1 1
+39 1 1
+132 6 6
+439 10092 10075
+78 15 15
+3352 1 1
+23 1 1
+873 4 4
+887 1 0
+1827 1 0
+216 6 6
+805 2 0
+874 0 8
+2266 1 1
+47 1 1
+761 0 4
+86 1 1
+19 1 1
+1794 9 9
+271 0 1
+2266 1 1
+34 1 1
+916 0 1
+21 1 1
+108 21 21
+141 1 1
+27 1 1
+406 3 0
+3950 1 1
+38 1 1
+128 2 2
+56 1 1
+72 0 1
+96 1 1
+22 1 1
+169 7 7
+511 1 1
+38 1 1
+1070 1 1
+90 1 1
+50 1 1
+41 1 0
+30 1 1
+659 12 12
+701 1 1
+33 1 1
+569 15 15
+70 1 1
+38 1 1
+955 0 3
+130 1 1
+63 1 1
+251 8 8
+191 1 1
+26 0 3
+187 1 0
+916 5 1
+70 13 13
+498 20061 20021
+160 1 1
+76 1 1
+95 1 1
+76 1 1
+275 1 0
+101 1 1
+79 1 1
+100 7 7
+159 1 1
+75 0 8
+87 1 1
+76 1 1
+44 1 1
+71 32 32
+89 11 12
+196 1 1
+55 0 2
+61 1 1
+83 0 1
+944 1 1
+126 1 1
+81 6 6
+41 3 0
+641 1 1
+92 1 0
+113 1 1
+39 1 1
+671 1 1
+28 1 1
+123 1 1
+59 1 1
+210 1 1
+17 1 1
+168 15 14
+494 1 0
+22 1 1
+484 18 18
+376 1 1
+114 2 0
+67 1 1
+10 1 1
+109 1 1
+165 1 1
+149 6 6
+234 1 1
+19 5 5
+64 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+168 1 1
+73 1 1
+194 1 1
+50 0 4
+37 1 1
+95 3 1
+43 1 1
+153 1 1
+83 1 1
+55 1 1
+39 1 1
+70 7 0
+59 7 7
+75 1 1
+84 2 2
+110 1 0
+42 1 1
+129 9978 10000
+438 1 1
+43 1 0
+55 1 1
+40 1 1
+175 1 1
+46 1 1
+52 1 1
+19 1 1
+277 1 1
+60 1 1
+98 1 1
+24 1 1
+333 4 4
+1047 2 0
+4080 1 1
+38 1 1
+837 0 64
+172 1 1
+55 1 1
+1818 2 0
+1143 13 13
+335 1 0
+1944 5 0
+39 6 0
+4057 3 8
+9465 5 4
+301 19 1
+191 84 0
+427 1 1
+29 0 4
+157 4 5
+296 21 18
+158 2 2
+36 1 1
+539 13 13
+399 1 1
+46 1 1
+348 1 1
+49 1 1
+268 1 0
+66 0 4
+178 2 2
+107 1 1
+133 5 5
+355 1 1
+30 1 1
+346 1 1
+29 1 1
+161 1 1
+38 1 1
+121 4 4
+55 8 8
+67 7 7
+318 17 17
+259 1 1
+94 1 1
+80 1 1
+35 1 1
+260 1 1
+81 1 1
+106 1 1
+58 1 2
+301 3 0
+2052 1 1
+40 1 1
+174 20 22
+574 0 2
+414 1 0
+234 0 1
+425 51224 51060
+1568 14 14
+11956 0 1
+2667 0 2
+884 1 1
+19 1 1
+676 1 1
+63 1 1
+3138 0 3
+3038 5 2
+132 10 6
+136 18 13
+363 1 1
+89 1 1
+382 1 1
+29 1 1
+58 8 7
+297 4 0
+66 1 1
+93 2 0
+145 1 1
+31 5 5
+576 1 1
+89 1 1
+1256 0 12
+67 1 1
+193 2 2
+23 1 1
+51 1 0
+727 1 0
+1148 12 12
+837 1 1
+77 1 1
+941 10 10
+776 19 19
+300 1 1
+24 1 1
+256 1 7
+93 1 1
+224 2 0
+138 1 1
+563 1 1
+104 4 4
+2898 1 1
+46 1 1
+282 1 1
+39 1 1
+204 2 2
+22 1 1
+469 1 1
+20 1 1
+140 1 1
+26 1 1
+745 0 2
+539 0 6
+1536 1 0
+817 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+132 5 0
+555 1 1
+42 1 1
+573 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+15 1 5
+1404 0 1
+934 1 1
+49 1 1
+1350 1 0
+384 1 1
+24 1 1
+4169 0 15
+244 10 10
+2167 18 14
+64 1 1
+31 1 1
+185 0 4
+1647 1 1
+20 1 1
+227 1 1
+37 1 1
+636 3 4
+5590 1 1
+39 1 1
+461 0 2
+2145 1 1
+23 1 1
+1114 0 2
+688 0 1
+901 18 18
+4781 0 4
+815 0 1
+5027 42 47
+415 0 1
+2743 1 1
+78 1 1
+390 1 0
+328 0 1
+878 0 1
+5752 0 2
+1554 1 1
+60 1 1
+278 0 1
+19 1 1
+1164 11 11
+691 0 2
+960 1 0
+62 0 20
+2108 0 2
+1265 0 1
+1642 2 0
+3584 2 0
+12086 2 0
+3766 0 2
+1209 1 7
+3466 1 0
+1448 1 0
+1943 0 1
+698 0 8
+1166 135 135
+2030 2 0
+540 1 0
+1736 14 0
+3128 0 2
+4464 0 1
+3597 1 0
+378 1 0
+1269 0 3
+1182 1 0
+654 0 3
+2049 1 0
+6838 1 1
+69 0 3
+154 1 0
+2718 1 1
+30 1 1
+160 11 11
+4954 0 1
+420 1 1
+123 1 1
+156 0 4
+219 4 0
+195 1 0
+4402 3 0
+3045 0 1
+1249 1 0
+3522 0 10
+675 20 20
+117 8 0
+346 0 1
+8538 5 0
+455 1 0
+119 0 1
+355 48 48
+724 1 0
+9254 22 22
+1672 1 0
+833 0 1
+4251 1 0
+8 1 1
+2079 0 1
+1735 8 12
+1612 0 1
+1373 5 0
+8585 7 0
+64 1 1
+3799 1 0
+258 2 0
+899 1 0
+1362 8 9
+593 0 2
+3351 2 0
+618 0 4
+905 2 15
+2797 1 0
+2776 2 0
+4110 0 6
+4466 18 18
+1783 9 9
+475 0 4
+134 1 0
+12963 8 0
+1616 0 2
+1685 2 0
+2225 2 0
+428 0 1
+458 20 20
+2860 0 3
+677 4 6
+325 11 1
+1887 0 1
+913 0 1
+997 5 5
+2814 17 15
+1389 1 0
+1200 0 4
+2495 1 0
+3921 26431 26426
+2419 0 1
+6110 0 1
+1370 0 1
+3085 1 0
+3568 1 1
+24 0 9
+597 1 0
+2642 1 0
+1545 10 0
+4952 0 1
+6146 2 0
+1452 1 0
+2967 1 0
+4920 5 0
+147 4 5
+850 1 0
+1875 1 0
+695 3 1
+1719 0 1
+259 0 1
+294 1 0
+128 0 2
+3051 0 1
+908 0 4
+3399 0 1
+4673 1 0
+3179 1 0
+411 1 1
+44 1 1
+174 1 0
+1047 17 17
+998 178 0
+671 0 40
+2093 1 0
+313 0 1
+7581 1 0
+3245 1 0
+972 0 4
+4085 2 0
+346 1 1
+45 1 1
+368 1 0
+26 1 1
+8444 0 1
+17044 1 0
+2795 2 0
+2860 1 0
+622 0 1
+167 0 5
+1968 0 2
+259 2 0
+4992 29 27
+170 1 0
+3528 0 1
+191 1 2
+117 2 0
+2275 1 0
+12676 1 1
+20 1 1
+9972 1 0
+13955 0 5
+19867 1 0
+9612 1 0
+14233 0 32737
+6316 1 1
+19 1 1
+970 8 8
+2685 16 16
+18093 0 1
+6799 0 16
+3350 0 1
+7574 0 12
+2132 0 1
+7228 52793 52800
+1955 22 22
+698 0 1
+2149 1 0
+6880 0 2
+960 0 1
+23 1 1
+2646 2 0
+3867 5 0
+26077 0 3
+3174 1 0
+8183 0 1
+2817 10 0
+5841 1 0
+2081 0 1
+374 0 2
+3589 0 4
+10625 28 28
+3275 3 0
+773 7 7
+175 1 1
+79 1 1
+400 12 12
+1096 0 4
+717 7 7
+52 1 1
+68 5 1
+2117 0 3
+130 14 14
+1124 0 3
+413 0 4
+643 3 0
+58 1 1
+127 1 1
+196 0 2
+226 3 0
+136 3 4
+293 1 1
+25 0 3
+63 1 1
+417 0 2
+412 0 16
+737 4 0
+402 2 0
+654 1 1
+42 1 1
+75 1 1
+64 1 1
+2980 4 0
+576 0 1
+29 2 2
+715 1 1
+36 1 1
+511 38 38
+218 4 40
+44 1 5
+43 49 5
+709 21 21
+1147 9 9
+22 1 1
+195 7 4
+659 3 0
+27 1 1
+637 1 1
+42 1 1
+531 1 1
+67 1 1
+39 1 0
+717 11 11
+53 1 1
+61 1 1
+1535 1 1
+89 0 1
+49 1 0
+102 1 1
+67 1 1
+76 1 1
+129 1 1
+85 1 1
+607 10 0
+12 137 1
+41 1 1
+1043 1 1
+22 1 1
+203 3 0
+480 14 21
+91 23 23
+1345 2 1
+435 15 17
+1188 30 0
+1778 1 0
+120 0 3
+3797 1 0
+3211 0 1
+2456 4 0
+954 0 4
+1847 0 1
+5929 20 20
+984 14 0
+2112 1 0
+2013 1 0
+1770 14 14
+3100 1 0
+1160 16 0
+733 7 7
+238 3 2
+2203 2 1
+5654 1 1
+28 5 10
+482 0 1
+2970 0 4
+2892 0 1
+251 1 7
+1346 1 0
+877 0 4
+3583 0 1
+1178 0 1
+1293 0 2
+491 2 0
+6803 1 1
+22 1 1
+2218 1 1
+44 1 1
+4780 4 0
+3026 14 13
+442 5 5
+2022 6 6
+506 2 0
+8557 1 1
+36 1 0
+1575 1 0
+1329 1 1
+35 1 0
+247 1 1
+16 1 1
+184 1 1
+18 1 1
+1636 0 7
+23 1 1
+527 1 1
+39 1 1
+653 3 0
+227 1 1
+18 1 1
+218 0 323
+91 1 0
+124 0 15
+621 0 2
+555 8 8
+467 1 1
+40 1 1
+372 1 1
+25 1 1
+188 12 12
+357 0 2
+2389 1 1
+22 1 1
+2579 0 5
+461 1 1
+36 1 1
+1584 1 1
+26 1 0
+429 1 0
+33 1 1
+1071 0 4
+1068 9 0
+1472 0 2
+1839 94 92
+337 1 1
+46 1 1
+416 1 1
+42 1 1
+1255 0 2
+628 17 15
+587 15 15
+398 3 0
+623 1 1
+78 0 3
+287 10 0
+191 0 2
+493 1 1
+42 4 0
+219 0 1
+408 1 1
+23 1 1
+283 1 1
+21 1 1
+633 2 0
+241 6 6
+457 1 0
+330 0 16
+428 1 0
+4 6 0
+324 0 1
+3060 0 2
+9953 0 1
+1899 0 6
+6431 0 1
+8674 0 4
+4595 11 0
+5064 2 0
+2813 12 12
+1391 5 0
+3690 1 1
+64 1 1
+2635 1 1
+49 1 1
+69 1 1
+15 1 1
+605 4 4
+400 8 0
+735 0 20
+3074 2 0
+1879 0 1
+572 0 8
+576 1 1
+42 1 1
+265 24 0
+209 11 11
+953 1 1
+42 0 5
+58 1 0
+95 1 0
+1121 1 1
+17 1 1
+751 0 1
+24 1 1
+351 1 1
+43 3 3
+565 1 1
+15 1 1
+271 1 0
+323 1 1
+23 1 1
+221 7 7
+705 9 0
+631 2 0
+64 1 1
+1577 1 1
+21 0 1
+371 7 21
+160 0 1
+283 1 1
+48 1 1
+227 1 1
+40 0 1
+1359 0 2
+836 13 13
+722 7 7
+1153 1 1
+93 1 1
+797 14 14
+433 8 0
+108 11 11
+140 1 1
+40 1 1
+470 1 1
+42 1 1
+1106 0 1
+85 4 4
+129 1 1
+123 1 0
+95 1 1
+104 6 1
+641 1 1
+77 1 1
+57 1 1
+62 1 1
+473 2 0
+262 6 0
+45 1 1
+63 2 0
+39 1 1
+267 0 1
+197 2 104
+189 107 3
+112 0 4
+108 5 0
+563 14 14
+324 1 0
+205 1 1
+17 1 1
+495 0 1
+201 4 0
+14 1 1
+667 42 42
+178 1 1
+58 1 1
+133 1 1
+24 1 1
+91 24 24
+342 1 1
+32 1 1
+121 1 1
+62 1 1
+2371 2 0
+164 8 1
+655 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+1780 2 0
+742 1 1
+40 1 1
+2014 1 0
+1741 3 0
+3833 0 1
+14622 161198 190000
+5156 0 1
+1680 1 1
+88 1 1
+4502 0 1
+46 1 1
+800 4 4
+23 1 1
+1305 2 0
+136 0 1
+4941 0 1
+547 0 1
+70 8 8
+293 1 1
+35 1 1
+1165 4 0
+6662 1 1
+46 1 1
+167 0 8
+214 1 1
+35 1 1
+108 1 0
+1063 0 1
+1017 1 1
+20 0 6
+1725 0 1
+150 5 5
+33 1 0
+12 1 1
+349 1 1
+24 0 1
+1562 1 1
+31 1 1
+2513 0 1
+73 36 36
+305 1 1
+27 1 1
+543 1 1
+47 4 28
+5476 10 10
+531 1 1
+37 1 1
+776 1 1
+44 2 2
+115 22 20
+181 1 1
+125 3 3
+466 1 1
+76 1 1
+144 5 5
+32 1 1
+225 1 1
+41 1 1
+707 24 24
+66 4 4
+414 1 1
+42 1 1
+81 1 1
+63 1 1
+76 28 46
+187 1 1
+97 1 1
+99 9 9
+85 14 14
+81 6 6
+62 1 1
+109 4 5
+150 1 0
+44 4 4
+93 11 11
+188 3 3
+73 1 1
+52 1 1
+19 13 0
+48 1 1
+62 0 7
+205 1 1
+68 9 9
+99 4 0
+21 1 0
+52 1 1
+171 1 1
+109 3 1
+6 0 2
+190 1 1
+69 10078 10069
+90 3 1
+197 1 1
+157 0 6
+137 1 1
+101 2 2
+233 6 6
+62 1 1
+104 0 1
+143 1 1
+119 1 1
+106 2 0
+176 1 1
+79 0 1
+50 1 1
+50 3 3
+179 1 1
+159 1 1
+36 1 1
+107 1 1
+176 1 1
+154 0 5
+91 1 1
+54 1 1
+77 1 1
+238 2 2
+50 1 1
+1421 1 1
+23 1 1
+216 1 1
+122 1 1
+86 1 1
+41 3 1
+336 7 7
+41 9 0
+107 1 1
+90 1 3
+6 1 0
+84 1 1
+213 1 1
+26 1 1
+138 1 1
+25 1 1
+206 1 1
+36 3 3
+37 7 0
+500 1 1
+52 1 1
+52 1 1
+48 1 1
+395 1 1
+66 6 6
+72 1 0
+69 1 1
+100 10 10
+160 1 0
+64 7 7
+89 1 1
+123 1 1
+128 1 1
+36 1 1
+231 1 1
+61 1 1
+564 8 8
+593 47 47
+163 1 0
+196 8 8
+174 5 5
+37 1 1
+67 0 1
+192 1 1
+60 3 0
+19 1 1
+1149 1 1
+18 1 1
+77 1 1
+32 2 0
+32 1 1
+136 1 1
+78 2 0
+162 4 0
+41 1 1
+351 13 13
+1634 2 0
+229 8 8
+57 13 2
+410 1 1
+76 1 1
+180 1 1
+92 1 1
+270 1 1
+40 1 1
+92 1 1
+53 1 1
+227 1 1
+42 1 1
+357 4 4
+23 1 1
+94 1 0
+200 6 0
+201 7 7
+70 5 13
+57 4 0
+35 1 1
+206 1 1
+76 2 2
+651 1 1
+68 4 0
+73 1 1
+49 4 0
+37 1 1
+145 2 2
+78 2 2
+108 12 12
+52 1 1
+35 1 1
+242 1 3
+76 2 2
+50 12 12
+70 1 1
+33 0 2
+57 1 1
+64 15 15
+168 1 1
+22 1 1
+63 36 37
+73 0 2
+64 1 1
+177 2 0
+19 4 0
+55 1 0
+33 1 1
+51 1 1
+122 1 1
+296 1 1
+85 1 1
+109 1 1
+64 1 1
+155 1 1
+58 0 2
+72 1 1
+25 1 1
+128 1 1
+45 2 0
+444 1 1
+25 1 1
+64 1 1
+21 1 1
+368 15 15
+734 2 0
+701 15 15
+71 1 1
+41 1 1
+77 1 1
+56 1 1
+478 2 0
+714 8 7
+95 2 2
+50 4 3
+1129 1 1
+34 1 1
+1715 1 1
+87 1 1
+692 1 1
+47 0 1
+75 1 1
+541 12 12
+1602 10 10
+1265 1 1
+46 1 1
+298 1 1
+22 1 1
+186 1 1
+34 1 1
+202 1 1
+61 1 0
+185 1 1
+24 1 0
+98 0 2
+258 8 14
+967 1 1
+15 1 1
+625 1 0
+1362 0 4
+23365 4 0
+246 26975 26986
+3307 0 1
+13671 3 3
+52 1 1
+1308 2 0
+942 0 1
+17790 1 0
+4586 0 1
+949 0 2
+15047 0 1
+606 2 0
+7820 0 4
+22313 16 0
+10539 8 0
+4836 0 1
+8320 18 18
+388 2 0
+194 1 1
+49 1 1
+320 1 1
+34 1 1
+6813 0 1
+8719 3 0
+7037 1 0
+721 0 1
+999 6 0
+17 1 0
+3075 5 0
+593 13 11
+1006 12 12
+3487 1 0
+9535 0 4
+23 0 2
+23 2 0
+513 0 3
+377 1 0
+2627 0 2
+16 0 1
+211 18 18
+571 2 0
+7617 0 1
+1607 1 0
+69 1 1
+66 1 1
+275 1 1
+67 7 0
+25 1 1
+1206 1 0
+136 8 7
+612 1 1
+61 1 1
+740 0 2
+78 26 26
+129 15 15
+69 12 16
+1483 13 28
+1062 1 0
+108 4 0
+685 0 2
+1566 1 0
+192 4 4
+1452 9 45
+1514 1 1
+46 1 1
+1969 0 1
+35 1 1
+1094 1 0
+618 1 1
+43 1 1
+6580 1 0
+1636 5 0
+6325 1 1
+32 1 1
+1041 0 2
+174 9 0
+11983 18 18
+142 8 8
+2203 10 8
+2025 1 1
+39 1 1
+907 4 4
+225 1 1
+124 1 1
+3928 0 22
+38 2 0
+44 18 0
+46 0 6
+61 0 1
+3653 6 0
+34 1 1
+4559 1 1
+28 1 1
+283 5 5
+1572 28 28
+351 1 1
+34 1 1
+443 19 19
+57 1 1
+21 1 1
+231 1 1
+94 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 1 1
+38 1 1
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 5 5
+23 1 1
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+339 1 1
+56 0 5
+142 1 1
+232 1 1
+43 1 1
+332 1 1
+47 1 1
+479 1 0
+137 0 3
+1456 10 13
+63 1 1
+37 1 1
+261 0 2
+109 1 1
+50 1 1
+56 129 1
+88 1 0
+44 1 1
+54 1 1
+56 1 50
+58 50 1
+54 277 1
+44 1 1
+297 0 39
+142 1 1
+85 1 1
+124 16 16
+58 3 15
+677 1 0
+1333 2 0
+13591 6 0
+989 1 1
+107 1 1
+678 1 1
+31 1 1
+2571 5 5
+56 2 2
+39 1 1
+3986 0 4
+18351 32 30
+10811 1 1
+25 0 1
+417 1 1
+40 1 1
+159 4 4
+37 4 4
+179 1 1
+51 1 1
+103 2 0
+108 1 1
+79 1 1
+25 1 1
+58 1 1
+12 1 1
+275 14 0
+80 1 1
+83 1 1
+24 1 1
+59 1 0
+91 1 1
+65 1 1
+67 1 1
+136 4 0
+68 8 0
+331 5 0
+40 1 1
+110 10 6
+64 1 1
+368 1 1
+22 1 1
+509 1 1
+89 1 1
+926 1 0
+959 1 1
+44 1 1
+72 11 0
+47 1 1
+361 1 1
+37 1 1
+2204 2 2
+45 1 1
+1117 18 18
+141 1 1
+47 1 1
+148 1 1
+75 1 1
+104 1 0
+205 3 2
+249 1 1
+146 1 1
+94 1 1
+34 1 1
+700 0 331
+21 1 1
+73 1 1
+49 1 1
+356 1 1
+16 1 1
+112 1 1
+36 9 0
+515 1 1
+27 2 2
+192 1 1
+53 0 14
+82 1 1
+302 1 1
+68 1 1
+52 12 12
+52 1 1
+34 1 1
+166 7 7
+384 1 1
+31 1 1
+281 1 1
+57 1 1
+176 0 1
+1625 1 1
+26 1 1
+369 1 1
+21 1 1
+86 1 1
+134 1 1
+215 1 1
+214 15 1
+50 2 2
+26 1 1
+78 0 19
+64 1 1
+118 53 53
+433 1 1
+76 0 1
+6 12 0
+52 1 1
+108 1 1
+87 1 1
+62 1 1
+26 1 1
+291 2 1
+143 1 1
+29 1 1
+56 12 12
+230 1 1
+153 4 4
+87 32 32
+584 12 12
+227 1 0
+1931 4 0
+836 1 1
+68 1 1
+205 24 19
+816 1 2
+1932 0 7
+1732 13 0
+257 4 0
+1423 1 0
+129 6 0
+1505 1 1
+42 0 1
+373 13 13
+565 1 1
+76 1 0
+1881 0 4
+68 4 0
+43 0 4
+2201 8 8
+3726 3 0
+339 15 11
+249 1 1
+35 1 1
+250 1 1
+38 1 1
+359 11 12
+109 1 1
+43 18 0
+822 1 1
+53 1 1
+325 15 15
+123 1 1
+42 6 6
+240 1 1
+44 1 1
+438 7 7
+142 2 0
+1004 0 1
+9275 1 1
+37 1 0
+2071 0 1
+1253 9 9
+9137 0 1
+12513 2 1
+11243 1 1
+26 1 1
+816 4 0
+15996 2 0
+1594 1 0
+363 5 0
+6757 47 41
+2700 1 0
+841 0 1
+1807 0 2
+2565 11 0
+2089 0 2
+477 1 0
+657 0 1
+776 0 20
+365 82 49
+779 0 1
+401 25 63
+441 0 2
+1152 0 2
+1315 1 0
+5352 6 8
+902 0 1
+2154 1 1
+36 1 1
+109 0 1
+668 6 0
+1923 0 1
+91 3 2
+3560 1 0
+1235 1 0
+139 26 0
+7381 1 0
+155 0 14
+2393 1 1
+33 1 1
+507 4 0
+1337 0 1
+9954 3 0
+1588 1 0
+2605 1 1
+23 1 1
+3000 0 3
+8249 8 0
+912 0 1
+338 2 0
+734 1 0
+4332 1 0
+416 0 4
+1691 0 1
+295 1 0
+214 2 0
+121 0 1
+784 0 1
+2512 0 1
+4465 12 11
+926 1 0
+190 1 0
+5780 0 1
+490 5 0
+228 1 1
+45 1 1
+207 3 0
+322 0 1
+633 1 1
+24 1 0
+1516 5 0
+1025 0 13
+1518 0 1
+591 10 10
+1061 1 0
+1371 1 1
+22 1 1
+928 0 2
+182 8 0
+328 1 0
+301 0 1
+994 1 1
+18 0 6
+1743 0 1
+2350 22 23
+1548 0 2
+1498 8 6
+7484 0 3
+2988 7 7
+93 2 0
+322 1 0
+280 1 1
+49 1 1
+2114 16 17
+617 0 1
+1012 0 1
+495 1 0
+29 1 1
+3134 1 0
+1837 0 4
+4079 0 1
+905 8 0
+5764 0 1
+3493 0 20
+1174 0 1
+900 0 1
+1006 1 0
+1699 0 1
+1682 1 0
+688 1 1
+21 1 1
+3349 0 1
+384 3 1
+3616 3 0
+748 0 1
+3001 0 10
+541 1 0
+286 1 1
+22 0 1
+250 1 1
+27 1 1
+898 1 0
+1161 0 2
+2067 0 1
+8000 0 12
+857 29 0
+1399
+
+chain 72788 6_qbl_hap2 4565931 + 3808375 3809175 11 135006516 + 118201008 118201901 1739030
+615 13 107
+119 2 1
+51
+
+chain 65509 6_qbl_hap2 4565931 + 2258974 2259668 6 171115067 - 140105134 140105832 1929446
+178 0 4
+516
+
+chain 50097 6_qbl_hap2 4565931 + 2471491 2473781 6 171115067 + 44553942 44556234 2550079
+125 147 147
+81 297 298
+77 380 378
+160 345 343
+82 181 182
+60 299 303
+56
+
+chain 30865 6_qbl_hap2 4565931 + 3800272 3800791 6 171115067 + 32713281 32713770 4500604
+73 89 59
+184 77 77
+96
+
+chain 26769 6_qbl_hap2 4565931 + 2218659 2218944 1 249250621 - 83463584 83463869 6084938
+285
+
+chain 25453 6_qbl_hap2 4565931 + 1111775 1112573 8 146364022 + 94982474 94983353 6804147
+181 108 108
+72 385 466
+52
+
+chain 18586 6_qbl_hap2 4565931 + 2472758 2473366 3 198022430 - 151831455 151832050 2830221
+34 221 221
+81 91 91
+5 35 35
+55 44 31
+42
+
+chain 18520 6_qbl_hap2 4565931 + 2558133 2558568 13 115169878 - 5075411 5075846 11677159
+71 220 220
+144
+
+chain 17263 6_qbl_hap2 4565931 + 3694162 3694369 4 191154276 + 3927369 3927573 12785974
+50 3 0
+26 4 4
+124
+
+chain 16745 6_qbl_hap2 4565931 + 2589692 2589893 11 135006516 + 74748600 74748801 13289219
+113 12 12
+76
+
+chain 15761 6_qbl_hap2 4565931 + 3069257 3069435 19 59128983 - 18504215 18504393 607285
+59 1 1
+45 1 1
+72
+
+chain 15688 6_qbl_hap2 4565931 + 3804298 3804527 11 135006516 - 109492289 109492518 14350697
+129 50 50
+50
+
+chain 14458 6_qbl_hap2 4565931 + 3751685 3752808 6 171115067 + 32441118 32442245 15662572
+59 270 268
+88 656 662
+50
+
+chain 14065 6_qbl_hap2 4565931 + 3705931 3706083 6 171115067 - 138602057 138602209 16122341
+152
+
+chain 13955 6_qbl_hap2 4565931 + 2589304 2589471 9 141213431 - 10269188 10269355 16251226
+93 11 11
+63
+
+chain 13115 6_qbl_hap2 4565931 + 937718 937855 7 159138663 + 102343613 102343750 17340123
+137
+
+chain 12452 6_qbl_hap2 4565931 + 4213437 4214179 12 133851895 + 124586233 124586652 1913233
+57 408 105
+14 32 63
+45 0 78
+44 129 0
+13
+
+chain 12361 6_qbl_hap2 4565931 + 1150685 1150815 1 249250621 + 48985442 48985572 18455294
+130
+
+chain 12272 6_qbl_hap2 4565931 + 2479004 2479160 X 155270560 + 155194421 155194569 18587559
+71 1 1
+25 8 0
+51
+
+chain 12201 6_qbl_hap2 4565931 + 1105096 1105867 6 171115067 - 139876162 139876935 18699321
+54 620 622
+97
+
+chain 12178 6_qbl_hap2 4565931 + 3776349 3776515 14 107349540 - 58393926 58394091 18734379
+55 26 25
+85
+
+chain 12008 6_qbl_hap2 4565931 + 3700751 3700880 8 146364022 + 49154427 49154556 18990653
+129
+
+chain 11752 6_qbl_hap2 4565931 + 3745259 3747655 6 171115067 + 32491461 32493852 19428924
+56 676 682
+61 1516 1505
+87
+
+chain 11746 6_qbl_hap2 4565931 + 1097944 1098092 7 159138663 - 7702899 7703047 19437479
+54 14 14
+80
+
+chain 11503 6_qbl_hap2 4565931 + 3698827 3699253 11 135006516 - 111045874 111046295 19852910
+57 287 282
+82
+
+chain 10738 6_qbl_hap2 4565931 + 3700459 3700580 10 135534747 + 59600699 59600817 21255899
+61 3 0
+57
+
+chain 10686 6_qbl_hap2 4565931 + 2478152 2478673 18 78077248 + 11342173 11342695 21355061
+80 388 389
+53
+
+chain 10496 6_qbl_hap2 4565931 + 3696510 3696620 1 249250621 - 174039531 174039641 21744609
+110
+
+chain 10342 6_qbl_hap2 4565931 + 3714159 3714889 6 171115067 + 32548581 32549235 22073729
+78 598 522
+54
+
+chain 9560 6_qbl_hap2 4565931 + 1152614 1152715 6 171115067 - 141323187 141323288 23857063
+101
+
+chain 9560 6_qbl_hap2 4565931 + 1099695 1099796 6 171115067 - 141323187 141323288 23857064
+101
+
+chain 9385 6_qbl_hap2 4565931 + 3825573 3825778 16 90354753 - 20685009 20685189 24272037
+58 92 67
+55
+
+chain 9214 6_qbl_hap2 4565931 + 1102327 1102424 6 171115067 + 29758158 29758255 24607529
+97
+
+chain 9048 6_qbl_hap2 4565931 + 3694493 3695083 16 90354753 - 14504923 14505798 16016601
+79 460 745
+51
+
+chain 8993 6_qbl_hap2 4565931 + 2558568 2558745 2 243199373 + 116390976 116391155 17783325
+1 102 104
+74
+
+chain 8702 6_qbl_hap2 4565931 + 3686082 3686238 6 171115067 + 32439449 32439606 25393693
+54 51 52
+51
+
+chain 8427 6_qbl_hap2 4565931 + 3804527 3804616 6 171115067 - 148948316 148948405 15963296
+89
+
+chain 7704 6_qbl_hap2 4565931 + 3688237 3688318 6 171115067 + 32557831 32557912 26927503
+81
+
+chain 6794 6_qbl_hap2 4565931 + 3775350 3775421 3 198022430 - 94748615 94748686 28659148
+71
+
+chain 6473 6_qbl_hap2 4565931 + 3694610 3694683 1 249250621 - 102907635 102907704 21815174
+11 4 0
+58
+
+chain 6457 6_qbl_hap2 4565931 + 1158502 1158569 6 171115067 + 30228837 30228904 29438118
+67
+
+chain 6422 6_qbl_hap2 4565931 + 3817908 3817976 6 171115067 + 32728707 32728775 29535243
+68
+
+chain 6368 6_qbl_hap2 4565931 + 2478912 2479004 6 171115067 - 132617434 132617532 20998654
+55 29 35
+8
+
+chain 5830 6_qbl_hap2 4565931 + 1098157 1098218 7 159138663 - 104622057 104622118 31091038
+61
+
+chain 5757 6_qbl_hap2 4565931 + 3825218 3825278 14 107349540 - 70017731 70017791 31292281
+60
+
+chain 5558 6_qbl_hap2 4565931 + 2472407 2472466 15 102531392 + 37673660 37673719 31870719
+59
+
+chain 5479 6_qbl_hap2 4565931 + 1111956 1112025 9 141213431 - 103321949 103322018 11235972
+69
+
+chain 5339 6_qbl_hap2 4565931 + 3885926 3885982 X 155270560 + 55718242 55718298 32499987
+56
+
+chain 5185 6_qbl_hap2 4565931 + 3788909 3788964 14 107349540 + 22827226 22827281 32987373
+55
+
+chain 5179 6_qbl_hap2 4565931 + 1150896 1150960 19 59128983 - 37357346 37357410 20742827
+53 10 10
+1
+
+chain 5176 6_qbl_hap2 4565931 + 1100596 1100651 14 107349540 + 79349485 79349540 33029769
+55
+
+chain 5058 6_qbl_hap2 4565931 + 3771065 3771119 1 249250621 - 172942963 172943017 33379587
+54
+
+chain 5039 6_qbl_hap2 4565931 + 2475495 2475548 7 159138663 - 94193358 94193411 33438564
+53
+
+chain 5038 6_qbl_hap2 4565931 + 1148806 1148858 6 171115067 + 29856463 29856515 33456716
+52
+
+chain 4959 6_qbl_hap2 4565931 + 3696457 3696510 18 78077248 + 5090594 5090647 22176919
+53
+
+chain 4949 6_qbl_hap2 4565931 + 3825516 3825569 X 155270560 - 91231208 91231261 33742123
+53
+
+chain 4829 6_qbl_hap2 4565931 + 1159026 1159076 6 171115067 + 30459319 30459369 34177698
+50
+
+chain 4685 6_qbl_hap2 4565931 + 3719592 3719642 12 133851895 + 112261417 112261467 34690970
+50
+
+chain 4391 6_qbl_hap2 4565931 + 4214058 4214103 X 155270560 - 99494613 99494658 30227326
+45
+
+chain 4348 6_qbl_hap2 4565931 + 3739277 3739323 7 159138663 - 76863668 76863714 34891433
+46
+
+chain 4338 6_qbl_hap2 4565931 + 2201356 2201401 6 171115067 + 30954494 30954539 34909104
+45
+
+chain 4061 6_qbl_hap2 4565931 + 2201872 2201914 6 171115067 + 30955145 30955187 31149648
+42
+
+chain 4003 6_qbl_hap2 4565931 + 2470663 2474155 12 133851895 + 104783555 104787047 2981748
+99 961 960
+40 481 480
+76 473 472
+44 1256 1259
+62
+
+chain 3775 6_qbl_hap2 4565931 + 2471376 2471416 10 135534747 - 90944157 90944197 25967017
+40
+
+chain 3639 6_qbl_hap2 4565931 + 3694572 3694610 3 198022430 + 101411146 101411184 20382400
+38
+
+chain 3574 6_qbl_hap2 4565931 + 2470595 2470633 3 198022430 - 173409162 173409200 29596632
+38
+
+chain 3494 6_qbl_hap2 4565931 + 3700422 3700459 X 155270560 + 104134375 104134412 29536090
+37
+
+chain 3491 6_qbl_hap2 4565931 + 2471293 2472133 8 146364022 - 12751685 12752521 3617865
+79 701 697
+60
+
+chain 3436 6_qbl_hap2 4565931 + 2471844 2473225 1 249250621 + 7474211 7475590 2872741
+34 959 957
+58 295 295
+35
+
+chain 3220 6_qbl_hap2 4565931 + 3776529 3776563 12 133851895 + 85826623 85826657 35349035
+34
+
+chain 3148 6_qbl_hap2 4565931 + 3825631 3825664 2 243199373 + 38182693 38182726 24706670
+33
+
+chain 2975 6_qbl_hap2 4565931 + 2478232 2478268 3 198022430 - 94213030 94213066 24807218
+36
+
+chain 2972 6_qbl_hap2 4565931 + 1105868 1105908 6 171115067 + 30459045 30459085 20759384
+40
+
+chain 2845 6_qbl_hap2 4565931 + 2470633 2470663 3 198022430 - 156603737 156603767 26791326
+30
+
+chain 2838 6_qbl_hap2 4565931 + 2474990 2475020 4 191154276 + 92075174 92075204 21730347
+30
+
+chain 2761 6_qbl_hap2 4565931 + 3804625 3804685 4 191154276 + 37278694 37278754 22658556
+60
+
+chain 2671 6_qbl_hap2 4565931 + 2478852 2478911 9 141213431 - 60456470 60456529 21094091
+59
+
+chain 2604 6_qbl_hap2 4565931 + 1151032 1151059 17 81195210 + 6784720 6784747 30920849
+27
+
+chain 2579 6_qbl_hap2 4565931 + 3700720 3700751 21 48129895 + 18677639 18677670 26190064
+31
+
+chain 2574 6_qbl_hap2 4565931 + 1150960 1151032 X 155270560 + 72544773 72544845 18935818
+72
+
+chain 2481 6_qbl_hap2 4565931 + 3804442 3804477 3 198022430 - 58737971 58738006 17138123
+35
+
+chain 2394 6_qbl_hap2 4565931 + 2478673 2478698 11 135006516 - 67345781 67345806 29321362
+25
+
+chain 2363 6_qbl_hap2 4565931 + 2473435 2473485 3 198022430 - 59783725 59783775 3613581
+50
+
+chain 2322 6_qbl_hap2 4565931 + 2470859 2470989 15 102531392 - 72822940 72823070 3150079
+130
+
+chain 2266 6_qbl_hap2 4565931 + 2470989 2471957 9 141213431 - 114376815 114377769 4168715
+45 845 831
+78
+
+chain 2263 6_qbl_hap2 4565931 + 2471123 2471268 12 133851895 + 84401354 84401499 4041581
+145
+
+chain 2209 6_qbl_hap2 4565931 + 2470765 2470818 3 198022430 + 182918728 182918781 9563966
+53
+
+chain 2087 6_qbl_hap2 4565931 + 2558317 2558369 X 155270560 - 89201309 89201361 22578016
+52
+
+chain 2078 6_qbl_hap2 4565931 + 1112026 1112064 3 198022430 + 120909358 120909396 13027265
+38
+
+chain 2035 6_qbl_hap2 4565931 + 2557888 2557938 16 90354753 + 47212776 47212826 17692575
+50
+
+chain 1978 6_qbl_hap2 4565931 + 4213820 4213948 15 102531392 - 61555806 61555934 2051418
+28 68 68
+32
+
+chain 1899 6_qbl_hap2 4565931 + 2558399 2558424 X 155270560 + 94068150 94068175 17734181
+25
+
+chain 1860 6_qbl_hap2 4565931 + 1112180 1112230 8 146364022 + 68079613 68079663 13479327
+50
+
+chain 1860 6_qbl_hap2 4565931 + 3812269 3815784 6 171115067 + 32722816 32726965 29521084
+61 2506 2690
+85 515 965
+52 103 103
+193
+
+chain 1828 6_qbl_hap2 4565931 + 2473656 2473684 14 107349540 - 54723100 54723128 20222699
+28
+
+chain 1658 6_qbl_hap2 4565931 + 1112136 1112169 4 191154276 + 153686345 153686378 11053932
+33
+
+chain 1514 6_qbl_hap2 4565931 + 1112233 1112291 13 115169878 - 5205835 5205893 10260311
+58
+
+chain 1396 6_qbl_hap2 4565931 + 2473606 2473656 1 249250621 + 83820278 83820328 4577579
+50
+
+chain 1388 6_qbl_hap2 4565931 + 4214123 4214166 19 59128983 - 43654778 43654821 2801865
+43
+
+chain 1329 6_qbl_hap2 4565931 + 2557727 2557778 7 159138663 - 55106997 55107048 20610784
+51
+
+chain 1304 6_qbl_hap2 4565931 + 4213365 4213389 1 249250621 + 182710286 182710310 2078906
+24
+
+chain 1296 6_qbl_hap2 4565931 + 4213389 4213424 8 146364022 + 99694 99728 9829550
+12 1 0
+22
+
+chain 1233 6_qbl_hap2 4565931 + 2558102 2558133 5 180915260 + 67992831 67992862 12309329
+31
+
+chain 1171 6_qbl_hap2 4565931 + 2473569 2473606 X 155270560 - 90928252 90928289 23413190
+37
+
+chain 1170 6_qbl_hap2 4565931 + 2471983 2472043 9 141213431 + 232427 232487 4190853
+60
+
+chain 1144 6_qbl_hap2 4565931 + 2469449 2469508 2 243199373 + 81796678 81796737 21594602
+59
+
+chain 1125 6_qbl_hap2 4565931 + 3694759 3694827 8 146364022 - 86779351 86779419 20749390
+68
+
+chain 1106 6_qbl_hap2 4565931 + 1112362 1112413 1 249250621 - 17660691 17660742 13643228
+51
+
+chain 1071 6_qbl_hap2 4565931 + 2470508 2470575 12 133851895 + 78891507 78891574 9444392
+67
+
+chain 1040 6_qbl_hap2 4565931 + 2470400 2470457 5 180915260 - 146134722 146134779 6672758
+57
+
+chain 1023 6_qbl_hap2 4565931 + 2471416 2471471 2 243199373 + 162554783 162554838 24613681
+55
+
+chain 935 6_qbl_hap2 4565931 + 2558067 2558102 4 191154276 + 31205 31240 16972854
+35
+
+chain 919 6_qbl_hap2 4565931 + 2474702 2474762 4 191154276 + 45112377 45112437 22402157
+60
+
+chain 902 6_qbl_hap2 4565931 + 2474552 2474612 5 180915260 - 23766246 23766306 4704228
+60
+
+chain 884 6_qbl_hap2 4565931 + 2473696 2473725 1 249250621 - 199045131 199045160 12500824
+29
+
+chain 825 6_qbl_hap2 4565931 + 1112413 1112452 1 249250621 - 184583816 184583855 16072417
+39
+
+chain 801 6_qbl_hap2 4565931 + 2470111 2470156 1 249250621 - 71436588 71436633 19248116
+45
+
+chain 789 6_qbl_hap2 4565931 + 3698600 3699777 19 59128983 + 8446620 8447803 26630175
+58 1059 1065
+60
+
+chain 788 6_qbl_hap2 4565931 + 2470239 2470322 6 171115067 + 137168270 137168353 4512040
+83
+
+chain 740 6_qbl_hap2 4565931 + 1112667 1112731 12 133851895 + 57178267 57178331 20850792
+64
+
+chain 718 6_qbl_hap2 4565931 + 2474782 2474837 9 141213431 - 49469911 49469966 23568604
+55
+
+chain 694 6_qbl_hap2 4565931 + 2469923 2469992 X 155270560 - 140437581 140437650 5405913
+69
+
+chain 584 6_qbl_hap2 4565931 + 2474349 2474405 15 102531392 + 67105223 67105279 15249534
+56
+
+chain 562 6_qbl_hap2 4565931 + 2557778 2557819 X 155270560 + 91975692 91975733 21019876
+41
+
+chain 562 6_qbl_hap2 4565931 + 2469824 2469884 2 243199373 - 169790362 169790422 25410177
+60
+
+chain 552 6_qbl_hap2 4565931 + 2237356 2237383 17 81195210 - 14890828 14890855 11066346
+27
+
+chain 523 6_qbl_hap2 4565931 + 2470057 2470111 13 115169878 + 42049099 42049153 16964924
+54
+
+chain 489 6_qbl_hap2 4565931 + 2469992 2470048 14 107349540 + 79003493 79003549 5260265
+56
+
+chain 481 6_qbl_hap2 4565931 + 2470189 2470239 8 146364022 + 50441810 50441860 5267091
+50
+
+chain 481 6_qbl_hap2 4565931 + 2469386 2469447 1 249250621 - 193322918 193322979 8728434
+61
+
+chain 455 6_qbl_hap2 4565931 + 2472488 2472547 6 171115067 - 85200236 85200295 17778688
+59
+
+chain 445 6_qbl_hap2 4565931 + 2469210 2469265 X 155270560 - 127487766 127487821 16318369
+55
+
+chain 358 6_qbl_hap2 4565931 + 2475020 2475084 4 191154276 + 74158363 74158427 16300933
+64
+
+chain 347 6_qbl_hap2 4565931 + 2469153 2469203 15 102531392 - 65978487 65978537 12839283
+50
+
+chain 246 6_qbl_hap2 4565931 + 3697415 3697467 12 133851895 - 104314075 104314127 28162397
+52
+
+chain 47340388 6_random 1875562 + 1357431 1875562 6 171115067 + 157393490 158069469 78
+906 2 2
+193 1 0
+29 1 0
+8 10 8
+11 2 1
+842 41 40
+754 2304 72101
+91082 5628 50000
+31833 338 50000
+42477 272 0
+39 168 66
+53 1 1
+15 1 103
+64 2 172
+23 1 103
+14474 4 0
+30198 0 8
+1391 2 0
+1319 4 0
+142 0 3
+3412 9 7
+372 1 1
+22 1 1
+5871 0 1
+237 26 25
+3020 1 1
+83 1 1
+141 7 7
+201 2 1
+403 1 0
+3638 1 0
+20 1 0
+552 32 32
+1386 0 1
+4174 1 1
+37 1 1
+3912 5 5
+4160 2 0
+6561 0 1
+3879 0 1
+8665 0 1
+2170 0 3
+895 1 0
+1812 0 1
+36 0 4
+133 1 0
+165 0 9
+427 0 1
+917 1 0
+3166 0 1
+16647 1 0
+6161 10 10
+833 4 0
+1934 1 1
+56 1 1
+2622 9 9
+749 1 0
+482 0 2
+344 1 1
+32 1 1
+868 2 0
+444 0 3
+1096 12 0
+709 0 1
+113 1 1
+35 1 1
+2349 20 0
+175 0 1
+1675 0 2
+1206 0 3
+345 0 5
+4695 1 0
+6715 1 1
+35 1 1
+2131 0 1
+4220 8 0
+2065 1 0
+1986 0 1
+484 0 1
+1543 4 4
+52 22 0
+5090 0 1
+2768 9 2
+12577 0 5
+13727 9 9
+51 4 4
+26 2 3
+11 0 1
+735 1 1
+35 0 1
+12 1 1
+2616 1 0
+327 1 1
+35 1 1
+345 0 20
+50 98 187
+975 1 0
+7329 0 1
+3241 0 35
+583 5 5
+278 1 1
+40 1 1
+123 12 12
+1208 17 0
+477 0 1
+163 1 1
+28 1 1
+3307 1 0
+66 1 1
+25 4 0
+2459 0 1
+1326 1 0
+700 1 0
+2316 6067 13
+725 3 0
+42 1 1
+8162 0 2
+2147 0 2
+79 1 1
+25 1 1
+313 1 0
+2194 1 0
+709 1 1
+33 1 1
+934 4 4
+543 1 1
+37 1 1
+2581 1 0
+606 1 0
+666 1 1
+34 2 2
+250 9 8
+652 1 0
+2306 22 0
+38 0 24
+946 1 0
+3766 1 1
+57 1 1
+3591 2 0
+128 1 1
+1414 7 1
+435 1 1
+29 1 0
+529 0 1
+3649 1 1
+32 0 1
+9760 0 18
+6470 1 1
+49 1 1
+488 0 1
+304 2 0
+1780 0 5
+2759 1 0
+48 1 1
+380 1 1
+33 1 1
+5102 1 1
+33 1 1
+192 0 1
+1103 1 1
+29 1 1
+12912 0 1
+9445 2 0
+2949 1 1
+28 1 1
+826 1 1
+19 1 1
+404 1 1
+49 1 1
+1408 8 0
+1625 10 0
+2962 0 1
+1824
+
+chain 37689909 6_random 1875562 + 884671 1286589 5 180915260 - 167715260 168127349 92
+6889 0 1
+34829 1 0
+4156 0 2
+4477 0 8
+7827 0 415
+37 9 9
+207 0 1
+272 7 7
+7925 1 0
+75982 0 1
+11336 0 1
+4233 14 14
+362 10 10
+4607 4 0
+1310 0 3
+1741 4 0
+499 1 1
+69 1 1
+509 15 15
+166 12 8
+145 0 2
+66 1 1
+16 1 1
+325 1 1
+31 1 1
+804 1 1
+109 1 1
+1071 0 106
+73 38 121
+1998 1 1
+37 1 1
+500 0 5
+625 3 0
+2354 1 1
+42 1 1
+1652 0 1
+92 1 1
+68 1 1
+1023 1 1
+16 1 1
+849 2 1
+28 1 1
+1793 4 2
+850 26 26
+251 0 2
+794 1 1
+26 1 1
+798 1 1
+80 1 1
+211 20 12
+153 1 3
+373 6 6
+231 0 4
+302 1 1
+26 1 1
+305 0 4
+3735 1 0
+342 0 2
+2211 0 1
+1969 2 0
+2834 0 10
+1054 0 14
+2176 0 2
+10517 0 2
+3071 6 0
+5697 21 21
+2458 0 5
+1335 3 0
+411 1 5
+2718 10 11
+3652 1 0
+785 1 0
+777 1 0
+2088 0 1
+24 1 1
+1005 16 16
+5426 18 0
+378 1 0
+19 1 1
+5303 0 14
+19 18 0
+2125 1 0
+936 0 5
+29 1 1
+893 19 19
+312 0 2
+32151 1 0
+14548 1 0
+109 0 1
+1481 1 0
+6537 0 2
+3390 1 0
+7479 6 0
+29963 4 0
+3972 9 5
+1637 0 9
+7977 1 0
+1973 0 3
+1212 0 5
+372 29 19
+1216 0 50
+628 0 4
+8388 0 1
+1429 1 0
+3029 2 4
+785 1 0
+291 10 9516
+1642 0 1
+5042 1 0
+1117 1 0
+1558 8 7
+1475 4 0
+1859 0 1
+9528 0 1
+877
+
+chain 31999718 6_random 1875562 + 165017 507468 6 171115067 - 55532370 55875067 101
+42954 0 1
+24905 1 0
+579 0 6
+612 0 1
+1128 0 2
+5541 1 1
+30 1 1
+2064 1 0
+505 0 1
+1974 0 1
+5299 1 1
+16 1 1
+368 1 1
+28 1 1
+7024 1 0
+19574 8 9
+6646 4 0
+6060 0 1
+2290 0 1
+22638 6 58
+1402 0 1
+502 0 1
+218 0 1
+5768 0 1
+178 0 3
+659 1 1
+33 0 8
+92 4 0
+693 0 2
+1190 0 3
+375 5 0
+422 3 0
+2215 1 0
+7271 1 1
+33 1 1
+817 1 1
+67 1 1
+2442 1 1
+62 16 0
+165 1 0
+1535 1 1
+32 1 1
+596 4 4
+627 1 1
+22 1 2
+201 5 5
+35 1 1
+232 5 0
+651 4 4
+26 1 1
+105 1 1
+45 1 1
+325 1 1
+34 1 1
+265 1 1
+91 2 0
+1383 1 1
+35 1 1
+1469 19 19
+295 0 1
+644 0 1
+3324 1 1
+44 1 1
+1797 1 5
+21 2 0
+10 11 1
+58 2 0
+61 1 9
+715 0 1
+388 1 1
+47 1 1
+774 1 0
+571 0 3
+2308 0 1
+103 15 15
+1339 1 1
+19 1 1
+348 0 1
+372 1 1
+31 0 1
+4 4 0
+14 1 5
+14 1 25
+4634 1 1
+16 2 2
+305 27 24
+2252 10 217
+1695 0 2
+2541 0 7
+741 2 0
+1401 0 2
+202 2 13
+3853 1 0
+3037 36 0
+18 2 0
+25 94 0
+14 0 4
+487 0 1
+5889 0 1
+572 1 1
+17 1 1
+806 1 1
+24 1 1
+723 0 2
+1640 1 0
+2023 1 1
+21 1 1
+192 15 1
+994 0 106
+1362 2 0
+324 1 1
+19 1 1
+683 1 1
+39 1 0
+771 1 0
+1211 13 0
+1728 1 1
+23 1 1
+911 0 2
+1042 6 6
+206 5 0
+17 1 1
+3351 14 19
+783 1 1
+48 1 1
+673 0 4
+137 1 1
+23 1 0
+1357 4 0
+254 0 1
+1408 0 7
+564 1 1
+49 1 1
+319 13 13
+721 12 12
+821 2 0
+912 4 4
+47 1 1
+148 1 1
+61 1 1
+267 1 1
+46 1 1
+421 1 1
+36 1 1
+577 1 1
+35 1 1
+122 1 1
+95 1 1
+241 1 1
+40 1 1
+585 10 1
+1286 0 1
+97 2 0
+22 1 1
+969 0 1
+1448 14 20
+2000 1 0
+1448 0 1
+2390 1 1
+18 5 5
+1421 1 0
+412 0 1
+1867 2 1
+179 3 0
+852 1 0
+1426 20 18
+151 1 1
+26 1 1
+581 1 1
+86 2 1
+2659 1 0
+12163 2 0
+1149 13 13
+818 16 16
+113 1 1
+51 1 1
+343 1 1
+91 0 4
+7 2 0
+8 0 2
+914 1 1
+28 1 1
+670 1 0
+151 7 7
+1887 18 18
+119 0 5
+2395 2 0
+4395 0 6
+380 6 1
+423 17 17
+531 1 0
+23 0 6
+592 1 1
+23 1 0
+844 4 0
+1497 6 0
+407 17 17
+341 19 17
+1020 0 6
+178 1 0
+1233 0 1
+1861 0 1
+2007 2 0
+6480 1 1
+36 1 1
+6817 17 20
+3356 7 5
+1788 1 1
+83 0 1
+7678 18 18
+2095 1 1
+19 1 1
+4934
+
+chain 25195472 6_random 1875562 + 615192 884135 6 171115067 + 167833423 168297434 120
+2006 1 0
+2654 1 1
+28 1 1
+3139 1 1
+85 1 1
+690 0 1
+639 0 2
+1589 4 4
+122 2 0
+1127 0 1
+1104 1 102
+18 0 29
+40 0 3
+22 1 4
+50 0 26
+56 124 195105
+10440 18 25
+3042 0 24
+72 0 8
+206 4 0
+146 4 0
+2483 0 4
+702 0 1
+1035 0 8
+85 3 1
+2710 1 1
+84 1 1
+3774 1 1
+58 1 1
+20613 15 53
+14 32 0
+52 0 4
+1883 4 0
+52 3 0
+44036 171 0
+2224 2 2
+57 1 1
+7263 0 64
+5311 0 2
+24677 8 8
+1972 1 0
+3543 2 2
+46 1 0
+11768 1 0
+494 47 19
+36447 1 1
+67 1 1
+11347 8 0
+4230 1 3
+591 5 5
+1020 0 8
+680 1 1
+60 1 1
+4536 0 1
+1417 0 2
+2471 1 1
+22 1 1
+6781 0 5
+4943 5 0
+1067 2 0
+2588 2 0
+523 34 35
+9266 0 2
+3897 0 2
+1404 0 1
+3120 0 1
+2566 1 0
+1825 0 8
+5342
+
+chain 9830417 6_random 1875562 + 510011 615192 5 180915260 - 108917398 109022458 335
+331 57 57
+1247 1 0
+4094 15 15
+6775 12 0
+6148 1 0
+30 1 1
+251 0 1
+26 26 1
+238 1 1
+29 1 1
+148 1 1
+41 1 1
+5831 6 7
+2439 1 0
+4247 12 42
+2333 1 9
+3039 5 0
+476 2 2
+4359 0 1
+1237 11 11
+1223 12 0
+2800 2 0
+2660 0 1
+4531 1 1
+24 1 1
+7407 0 1
+395 2 0
+1841 391 0
+410 50 26
+321 1 1
+27 1 1
+226 9 9
+157 6 6
+80 1 1
+70 1 1
+5158 10 10
+1385 4 0
+991 0 2
+48 1 1
+1083 0 2
+751 0 1
+4266 1 1
+48 1 1
+1557 0 304
+1552 1 1
+21 1 1
+2652 1 0
+598 0 8
+115 15 16
+1277 1 1
+38 1 1
+898 1 1
+27 1 1
+699 0 1
+34 1 1
+279 4 0
+12 1 1
+2863 1 1
+25 1 1
+2484 12 15
+1447 1 0
+8689
+
+chain 8736931 6_random 1875562 + 25094 155092 6 171115067 - 3172994 3267843 378
+3079 5 5
+1125 2 0
+1270 7 14
+1955 1 1
+47 1 1
+4538 38 38
+1300 25 26
+67 7 8
+176 3 0
+1132 3 0
+906 103 48
+5311 0 16
+133 1 0
+94 153 987
+142 13 13
+2453 2 0
+238 2 0
+960 13 13
+4697 1 1
+26 1 1
+3575 36650 734
+4434 0 1
+5190 138 107
+33 1 1
+5998 4 0
+1660 1 0
+4740 1 1
+29 1 1
+7196 0 12
+17519 30 29
+12768
+
+chain 553807 6_random 1875562 + 1768811 1774813 4 191154276 - 111879139 111885141 10762
+1294 2 2
+109 1 1
+242 1 1
+106 1 1
+2122 1 1
+17 1 1
+200 1 1
+40 1 1
+1071 1 1
+24 1 1
+284 1 1
+77 1 1
+403
+
+chain 255982 6_random 1875562 + 1456339 1459136 6 171115067 + 157377507 157380303 364419
+1101 4 4
+21 1 0
+70 43 44
+1490 1 0
+66
+
+chain 238316 6_random 1875562 + 1453720 1456237 6 171115067 - 13762873 13765390 431401
+2517
+
+chain 190390 6_random 1875562 + 1355230 1357270 6 171115067 - 13765611 13767650 644275
+875 0 1
+30 1 0
+7 0 1
+32 2 0
+1093
+
+chain 147846 6_random 1875562 + 163259 164828 10 135534747 - 86648034 86649603 870502
+1569
+
+chain 66179 6_random 1875562 + 509035 509994 6 171115067 - 55868072 55869030 1909901
+52 241 240
+666
+
+chain 39557 6_random 1875562 + 507468 508471 14 107349540 - 76514262 76515265 2447482
+67 13 13
+252 48 48
+70 43 43
+73 340 340
+97
+
+chain 15445 6_random 1875562 + 574580 574743 6 171115067 + 168277787 168277950 14597733
+163
+
+chain 11899 6_random 1875562 + 508034 508258 7 159138663 - 61729371 61729595 2527246
+50 119 119
+55
+
+chain 6795 6_random 1875562 + 508264 508336 5 180915260 + 74550099 74550171 28643390
+72
+
+chain 5830 6_random 1875562 + 884328 884389 6 171115067 - 37135398 37135459 31091070
+61
+
+chain 5767 6_random 1875562 + 508601 508846 8 146364022 + 54253304 54253548 3655159
+50 103 102
+92
+
+chain 4821 6_random 1875562 + 16131 16182 10 135534747 - 59552661 59552712 34213212
+51
+
+chain 3598 6_random 1875562 + 720272 720329 6 171115067 + 168133749 168133806 2857460
+57
+
+chain 3185 6_random 1875562 + 1768774 1768810 2 243199373 + 130168617 130168653 16948
+36
+
+chain 2982 6_random 1875562 + 508896 508970 12 133851895 - 4327021 4327095 12758815
+74
+
+chain 2685 6_random 1875562 + 509240 510388 3 198022430 - 97729559 97730704 3388749
+33 1069 1066
+46
+
+chain 2530 6_random 1875562 + 720329 720365 6 171115067 + 168133920 168133956 3810246
+36
+
+chain 2208 6_random 1875562 + 720386 720422 6 171115067 + 168133692 168133728 3917950
+36
+
+chain 1957 6_random 1875562 + 507800 507848 1 249250621 - 36684504 36684552 2679811
+48
+
+chain 1423 6_random 1875562 + 508846 508894 2 243199373 - 143356177 143356225 7803118
+48
+
+chain 1172 6_random 1875562 + 508537 508601 X 155270560 + 123719418 123719482 4007841
+64
+
+chain 1047 6_random 1875562 + 509273 509328 20 63025520 + 3479096 3479151 2808508
+55
+
+chain 560 6_random 1875562 + 508669 508719 5 180915260 - 128392227 128392277 20287927
+50
+
+chain 14618906734 7 158821424 + 102995 158821424 7 159138663 + 10238 159128663 7
+973 5 0
+3912 0 2
+1234 4 0
+51 0 6
+70 1 1
+24 1 0
+143 8 0
+16 170 1
+47 1 1
+243 0 6
+913 3 0
+2538 980 0
+63 1610 0
+1362 0 1
+2104 0 456
+1158 0 1
+791 1 1
+49 0 1
+4175 8 0
+17 1 1
+4845 12 0
+2509 0 1
+1697 6 6
+192827 150000 278557
+5682472 0 1
+42007910 40000 35970
+4371 7 16
+17699 0 4
+5249 4 0
+2088410 1 1
+47 1 1
+4565 0 1
+7116 0 1
+2706 40000 43050
+6577293 50000 13552
+1052855 3000000 3000000
+256182 50000 416507
+190137 50000 50000
+5722629 24 25
+239 1 1
+59 2 2
+138 1 1
+34 1 1
+206 1 3
+18 1 0
+410 1 1
+72 1 1
+199 1 1
+62 5 5
+120 1 0
+468 1 1
+32 1 1
+264 1 1
+23 1 1
+1459 4 4
+107 1 1
+42 1 0
+14 1 1
+201 1 1
+46 1 1
+268 20 20
+303 2 1
+866 0 4
+76 3 3
+63 1 1
+74 1 0
+25 1 1
+66 1 1
+34 0 2
+180 35 36
+93 1 1
+41 1 1
+70 1 1
+49 1 1
+63 1 1
+57 1 1
+383 1 1
+133 1 1
+87 1 1
+38 4 4
+50 0 1
+46 5 6
+136 11 11
+200 1 1
+63 4 0
+6 9 0
+263 1 1
+32 3 3
+152 16 16
+567 1 0
+322 3 0
+1258 0 1
+505 4 0
+1141 11 10
+537 12 12
+1418 1 1
+47 0 1
+164 7 7
+90 5 0
+156 1 1
+20 1 1
+380 3 3
+41 3 0
+5 2 2
+921 1 1
+34 1 1
+1607 2 2
+73 66 0
+46 14 0
+168 1 1
+53 1 1
+3195 1 1
+23 1 1
+2115 0 14
+9872 1 0
+1204 13 13
+416 1 0
+2311 319 0
+6906 0 10
+184 24 0
+2933 4 0
+1392 0 12
+1856 5 0
+3439 0 1
+469 3 0
+771 15 12
+497 1 1
+65 1 1
+1210 0 2
+4131 10 10
+1198 1 0
+718 1 1
+21 1 1
+3668 1 0
+874 1 1
+25 1 1
+2444 0 1
+1867 1 1
+29 1 1
+1660 0 1
+1232 0 6
+784 1 0
+705 0 3
+3577 1 0
+365 1 0
+3389 8 4
+2652 0 3
+664 0 1
+169 1 0
+8 1 1
+138 0 1
+8037 0 56
+112 196 0
+495 0 35
+3028 1 1
+40 1 1
+1068 4 0
+631 0 33
+29 2 0
+86 9 1
+3081 2 0
+806 0 1
+21 1 1
+3901 26 27
+843 0 1
+6916420 250000 50000
+25789103 0 51216
+1399994 1 0
+3623 0 212
+38 1 1
+210 1 0
+5 1 0
+6 1 0
+18 1 0
+1321 16 0
+2187 1 0
+145 0 1
+1388 7 7
+2240 14 14
+771 1 1
+34 1 1
+92 1 1
+39 1 1
+505 1 0
+66 1 1
+49 1 1
+159 1 0
+78 3 0
+15 2 0
+7 1 0
+28 1 0
+27 468 5
+2022 1 0
+1796 7 7
+61 1 1
+20 1 1
+4560 3 0
+157730 1 0
+194 14 14
+650 0 12
+717 26 26
+819 0 5
+278 60 32
+69 0 5
+1345 8 0
+652 84 0
+118 0 4
+498 0 1
+3187 1 1
+43 1 1
+1476 0 3
+2101 5 0
+788 6 6
+872 0 6
+893 3 0
+155 33 33
+4610 5 7
+521 10 0
+2773 40 40
+627 43 43
+1424 0 1
+2554 8 8
+44 0 7
+615 1 1
+32 3 0
+2693 0 1
+1029 0 2
+151 0 1
+1753 0 21
+370 2 3
+969 0 1
+452 1 0
+3035 1 1
+40 1 1
+704 0 2
+2472 0 6
+238 1 0
+1442 1 1
+37 5 5
+126 0 1
+795 0 1
+1191 1 0
+171 17 16
+724 6 5
+2988 40 42
+359 2 0
+199 19 19
+1969 1 0
+251 0 1
+729 0 1
+992 27 27
+205 4 0
+3209 0 2
+1006 8 10
+1571 10 10
+756 0 1
+36 1 1
+433 0 1
+672 0 3
+4430 157 0
+5606 5 1
+17 1 1
+942 10 9
+3433 2 1
+24 1 1
+4262 13 0
+661 2 0
+167 8 0
+3474 6 11
+217 0 2
+778 34 34
+158 0 1
+1167 0 1
+684 0 1
+878 39 39
+2012 0 1
+345 52 52
+640 0 2
+27874045 0 136705
+2519 0 2
+1000 8 0
+14695 1 0
+4456 1 0
+2977 1 0
+9065130 25000 29055
+2369 1 0
+12174 18 20
+877 0 4
+5247 0 12
+3483 2 0
+6766 0 1
+2469878 0 1
+734 2 2
+99 0 1
+2471 1 1
+11 1 1
+758 8 0
+2234 13 14
+8394 1 0
+47 1 1
+903 0 1
+5537 0 1
+269 1 0
+7114 1 1
+30 1 1
+2412 0 1
+2442 21 21
+91 1 1
+37 1 1
+96 1 1
+22 1 1
+246 1 1
+23 1 1
+254 12 12
+569 1 1
+27 1 1
+1624 1 0
+112 3 3
+45 1 1
+384 13 13
+70 1 0
+658 1 1
+20 1 1
+176 1 0
+307 19 19
+428 1 1
+19 1 1
+87 1 1
+30 1 1
+140 1 0
+292 2 0
+1492 1 0
+302 0 2
+364 1 1
+35 1 1
+1956 0 1
+728 12 12
+6522 2 2
+1531 1 0
+488 1 0
+2056 18 8
+1286 1 1
+27 1 1
+731 1 0
+1423 0 7
+2010 1 1
+19 1 1
+6423 0 4
+57 1 1
+4505 13 0
+933 0 12
+1250 0 1
+1313 1 0
+2610 0 1
+2398 0 1
+453 1 0
+346 1 1
+12 1 1
+83 25 25
+83 12 12
+277 0 1
+45 1 0
+811 2 0
+164 0 1
+104 0 1
+32 1 1
+1386 0 14
+306 1 1
+43 1 1
+2765 0 1
+1819 0 1
+1480 1 1
+24 1 1
+276 0 1
+21 0 1
+119 2 0
+12 26 0
+541 1 1
+63 1 1
+180 0 1
+2456 1 0
+1055 1 0
+1166 2 0
+784 0 4
+170 1 0
+939 6 0
+5597 15 15
+1253 0 1
+3336 0 18
+1851 9 0
+45 1 1
+657 38 38
+4099 0 1
+1387 2 0
+1460 1 0
+204 0 5
+1506 0 1
+2621 1 0
+6620 0 1
+34 1 1
+249 1 0
+1440 0 10
+245 0 1
+368 1 9
+257 4 0
+1589 6 0
+1543 0 1
+4189 120 0
+354 312446 278046
+3734 24 25
+3097 1 0
+8 1 1
+4861 0 4
+5649 1 0
+2011 0 1
+4344 24 24
+10546 42 1467
+20955 0 1
+2075 2 1
+5546 1 0
+2168 4 0
+1266 1 0
+4124 1 1
+46 1 1
+54 1 1
+43 15 0
+780 1 1
+25 1 1
+497 0 1
+46 1 1
+810 0 1
+5701 0 1
+6998 0 1
+2002 0 3
+7160 1 1
+24 1 1
+479 2 0
+1872 0 1
+1192 1 0
+371 2 0
+31 1 1
+572 16 16
+1725 16 16
+588 1 1
+90 1 1
+2483 3 19
+187 0 1
+20 1 1
+3673 1 1
+27 4 0
+3021 1 0
+1323 19 6
+498 13 13
+1618 2 0
+5282 0 1
+719 0 8
+2994 1 0
+2822 0 2
+1396 1 1
+48 1 1
+8723 5 0
+291 1 1
+25 1 1
+116 0 1
+2809 1 1
+27 1 1
+224 1 1
+48 1 1
+292 0 2
+400 0 1
+754 1 1
+19 1 1
+4225 1 1
+28 1 1
+801 1 0
+671 1 1
+17 1 1
+390 1 1
+28 1 1
+84 7 7
+568 1 1
+56 1 1
+499 7 8
+266 1 1
+31 1 1
+518 18 18
+164 1 1
+50 1 1
+162 1 1
+60 1 1
+702 1 1
+28 1 1
+146 18 17
+517 1 1
+24 1 1
+686 12 12
+101 1 1
+22 5 5
+107 5 5
+277 9 9
+272 1 1
+48 1 1
+77 1 1
+67 1 1
+1548 1 1
+40 1 1
+763 1 1
+42 1 1
+541 8 8
+88 1 1
+77 1 1
+233 11 11
+311 1 1
+22 1 1
+147 1 8
+504 1 1
+26 1 1
+987 20433 0
+3090 1 0
+405 5 5
+1811 1 0
+1174 0 1
+70 1 1
+1100 10143 18
+2722 0 1
+2957 1 1
+32 1 1
+9585 0 1
+1350 0 1
+473 0 1
+675 0 1
+1435 0 1
+805423 0 79189
+10872737 100000 100000
+721570 1 1
+19 1 1
+816 1 1
+44 1 1
+572 8 6
+2021 0 4
+1001 2 0
+3757 1 0
+5942 2 2
+70 1 1
+100 7 7
+395 80000 17188
+1010 1 1
+45 1 1
+1486 18 18
+173 1 17
+15 1 17
+158 0 192
+33 0 368
+50 50 2
+40 1 1
+95 4 52
+60 39 8
+15 16 0
+92 16 0
+1589 0 1
+897 13 13
+28 3 3
+2454 1 1
+44 1 1
+301 0 468
+2030 1 1
+45 1 1
+1277 8 0
+1716 1 0
+1579 11 15
+2439 36 0
+39 37 1
+349 21 92
+2096 13 11
+192 1 1
+48 1 1
+130 1 1
+22 1 1
+970 1 1
+23 4 0
+64 0 14
+129 17 11
+154 13 14
+53 15 5
+48 1 1
+47 0 2
+114 18 16
+363 1 1
+43 1 1
+559 1 1
+32 1 1
+3980007
+
+chain 16701236 7 158821424 + 141723881 141902219 7 159138663 - 16862466 17040468 171
+1662 1 1
+69 1 1
+887 1 1
+16 1 1
+115 339 1
+1512 0 1
+3597 0 1
+309 2 0
+34 1 1
+623 0 2
+1746 2 0
+816 4 0
+7868 1 0
+22 0 4
+593 0 1
+2757 0 1
+1147 7 7
+134 1 1
+42 1 1
+669 1 1
+25 1 1
+539 1 1
+49 1 1
+1387 1 1
+53 0 1
+19 1 1
+878 1 1
+27 1 1
+9739 1 1
+15 1 1
+2064 0 1
+1069 1 1
+31 1 1
+612 0 1
+21 1 1
+821 2 0
+1002 2 0
+3478 4 0
+1394 1 1
+25 1 0
+60 1 0
+4 1 0
+10 1 0
+23 0 1
+12 0 1
+2396 1 1
+25 1 1
+401 0 2
+1918 0 2
+43 1 1
+806 1 1
+36 1 1
+126 1 1
+53 1 1
+411 5 5
+524 13 13
+2896 1 1
+62 1 1
+4194 2 0
+8269 2 0
+368 11 10
+546 1 0
+1040 2 0
+45 1 1
+234 1 1
+29 1 1
+1218 16 16
+206 11 11
+584 13 13
+334 4 4
+167 3 3
+31 1 1
+973 9 9
+142 81 81
+58 1 0
+74 1 0
+1707 19 19
+2413 1 1
+57 1 1
+160 1 1
+23 1 1
+2380 0 1
+5561 0 4
+2790 14 14
+76 3 0
+1823 1 1
+11 0 9
+6 2 0
+5 3 0
+9 5 0
+28 1 1
+727 1 1
+37 1 1
+2678 0 3
+1497 1 0
+3414 1 0
+1171 6 6
+4018 7 7
+269 1 1
+36 1 1
+366 1 1
+22 1 1
+916 0 9
+2431 1 1
+68 1 1
+855 4 4
+1052 2 2
+81 0 2
+45 7 7
+648 1 1
+27 1 1
+402 1 0
+791 1 1
+41 1 1
+1041 20 20
+1094 1 1
+29 4 0
+364 1 1
+40 0 1
+22 0 1
+124 0 1
+205 0 1
+720 0 1
+59 1 1
+1063 2 0
+112 2 0
+3106 15 15
+2542 1 1
+64 1 1
+3052 1 1
+73 1 1
+3722 1 1
+31 1 1
+3476 1 0
+229 1 1
+40 1 1
+1321 0 5
+1845 1 0
+558 5 5
+3811 19 19
+125 1 1
+25 1 1
+3387 1 0
+1781 4 4
+2191 0 1
+1201 0 1
+260 1 1
+17 7 7
+137 0 1
+38 1 1
+732 0 1
+1626 1 0
+1987 2 0
+45 1 1
+763 0 1
+1978 0 1
+135 1 0
+6209 1 0
+24 1 1
+4867 0 1
+171 0 1
+6299
+
+chain 6490016 7 158821424 + 34000 116005 16 90354753 - 90001 171511 354
+591 11 11
+383 0 4
+1364 1 0
+430 12 13
+1431 1 1
+21 1 1
+490 12 12
+509 1 1
+97 1 1
+604 2 0
+1188 1 3
+665 1 1
+22 6 0
+499 1 1
+19 1 1
+402 1 1
+51 1 1
+1193 0 4
+245 1 0
+688 0 1
+975 2 0
+463 0 23
+73 24 0
+32 7 0
+165 1 0
+1593 1 1
+20 1 1
+1203 1 1
+31 1 1
+740 2 0
+47 1 1
+485 1 1
+63 1 1
+381 5 0
+28 1 1
+254 1 1
+22 1 1
+306 0 1
+34 1 1
+283 0 2
+627 10 10
+74 1 1
+50 1 1
+1053 0 1
+54 1 1
+77 1 1
+210 1 1
+70 0 3
+1957 0 4
+2154 1 1
+69 1 1
+147 67 67
+69 1 1
+74 1 1
+242 1 1
+41 1 1
+63 5 5
+155 3 1
+101 1 1
+53 1 1
+877 1 1
+21 1 1
+60 1 1
+49 1 1
+167 1 1
+21 1 1
+623 15 15
+202 0 97
+86 0 49
+9 2 2
+84 5 248
+56 1 98
+40 0 1
+48 1 0
+87 1 1
+55 99 1
+50 50 0
+23 1 1
+81 0 194
+78 1 1
+55 3 3
+53 6 344
+15 1 1
+262 1 1
+80 1 1
+455 1 1
+108 3 3
+431 1 1
+101 1 1
+158 1 0
+9 1 1
+323 3 0
+85 1 1
+19 1 1
+345 32 0
+24 1 1
+342 1 1
+65 1 1
+90 8 8
+545 1 1
+130 2 2
+87 4 3
+62 3 3
+34 2 2
+77 1 1
+47 1 1
+61 1 1
+27 1 1
+224 7 7
+117 2 0
+17 1 1
+242 1 1
+34 1 1
+107 1 1
+36 1 1
+100 15 15
+154 0 8
+13 1 0
+34 5 5
+100 27 27
+263 11 11
+116 1 1
+41 1 1
+117 1 1
+49 1 1
+116 2 0
+70 1 1
+174 1 1
+125 1 1
+70 1 1
+30 1 1
+74 1 1
+32 1 1
+337 1 1
+49 1 1
+2127 1 1
+35 1 1
+538 1 1
+32 1 1
+744 10 10
+471 53 17
+2001 7 7
+453 1 0
+2656 0 1
+1785 1 0
+1454 1 1
+33 1 1
+419 1 1
+49 1 1
+4610 1 1
+36 1 1
+905 1 1
+13 0 2
+5128 17 17
+519 0 3
+613 7 0
+660 0 4
+2632 1 2
+278 21 21
+969 1 0
+2852 14 14
+149 1 1
+21 1 1
+198 1 1
+29 1 1
+801 6442 6416
+125 6 0
+39 3745 3755
+814 162 1
+4 63 63
+74 63 0
+47 1056 13
+370
+
+chain 227647 7 158821424 + 141707499 141716076 7 159138663 + 142043811 142047809 475649
+53 484 465
+55 51 51
+78 242 220
+60 274 271
+51 13 13
+51 37 37
+229 4 4
+228 16 16
+108 47 47
+50 4583 49
+498 131 130
+945 36 36
+253
+
+chain 87685 7 158821424 + 58756 115635 3 198022430 - 71488 126874 406
+67 3328 3375
+28 1 1
+29 2 2
+39 50 50
+7 2 2
+41 2708 1663
+32 2831 2828
+27 46647 46820
+96 378 0
+152 47 12
+72 252 0
+43
+
+chain 48969 7 158821424 + 142175391 142175904 7 159138663 + 142475439 142475952 2613549
+513
+
+chain 47803 7 158821424 + 141911444 141913842 7 159138663 - 17029555 17031946 2683091
+78 139 139
+57 226 225
+124 92 92
+56 135 135
+72 193 193
+53 23 23
+133 958 952
+59
+
+chain 43189 7 158821424 + 142199519 142199970 7 159138663 + 142498738 142499189 3009311
+451
+
+chain 30396 7 158821424 + 67364377 67364696 15 102531392 - 56463077 56463396 4465114
+319
+
+chain 30094 7 158821424 + 141700053 141707301 7 159138663 + 142042846 142043613 4669748
+89 15 15
+68 6585 104
+66 129 129
+62 35 35
+199
+
+chain 30060 7 158821424 + 141963578 141964737 11 135006516 + 33264685 33266127 4680203
+91 398 397
+87 228 512
+77 163 163
+115
+
+chain 28591 7 158821424 + 141910578 141910878 7 159138663 - 17028690 17028990 5361712
+300
+
+chain 21822 7 158821424 + 141716123 141716468 7 159138663 + 142047850 142048195 9124304
+170 99 99
+76
+
+chain 20144 7 158821424 + 142166403 142167075 9 141213431 + 33792981 33793662 10344618
+82 380 389
+66 18 18
+51 19 19
+56
+
+chain 16654 7 158821424 + 101805867 101806156 7 159138663 - 92369277 92369565 11127744
+33 12 11
+63 91 91
+90
+
+chain 14923 7 158821424 + 102039289 102039446 7 159138663 + 102153090 102153247 2823
+157
+
+chain 10542 7 158821424 + 115456 115592 16 90354753 - 170836 170972 2672410
+136
+
+chain 10012 7 158821424 + 114469 115025 9 141213431 - 90660 90901 550
+63 395 80
+98
+
+chain 9195 7 158821424 + 141943788 141943884 7 159138663 - 16914722 16914818 24637833
+96
+
+chain 8667 7 158821424 + 142177809 142178136 7 159138663 + 142477851 142478180 25450135
+54 219 221
+54
+
+chain 7349 7 158821424 + 142180607 142180684 7 159138663 + 142480664 142480741 27551182
+77
+
+chain 7340 7 158821424 + 142180197 142180274 7 159138663 + 142480253 142480330 27565643
+77
+
+chain 6886 7 158821424 + 141960844 141960917 8 146364022 - 77913390 77913463 28463282
+73
+
+chain 6730 7 158821424 + 102059075 102062034 7 159138663 + 102172727 102175692 3338
+34 2887 2893
+38
+
+chain 6431 7 158821424 + 142166514 142166582 7 159138663 + 142454997 142455065 29498865
+68
+
+chain 6414 7 158821424 + 114166 115456 9 141213431 - 90644 91234 1816570
+68 791 378
+44 328 41
+59
+
+chain 6276 7 158821424 + 142176939 142177005 7 159138663 + 142476982 142477048 29891950
+66
+
+chain 6166 7 158821424 + 142179945 142180009 7 159138663 + 142480002 142480066 30171758
+64
+
+chain 5761 7 158821424 + 141963726 141963989 14 107349540 - 25420241 25420503 6848073
+68 130 129
+65
+
+chain 5666 7 158821424 + 142179798 142179857 7 159138663 + 142479855 142479914 31548103
+59
+
+chain 5608 7 158821424 + 101977370 101977454 7 159138663 + 44036096 44036185 7960
+10 0 5
+74
+
+chain 5430 7 158821424 + 142178562 142178619 7 159138663 + 142478613 142478670 32231795
+57
+
+chain 5139 7 158821424 + 142176520 142176574 7 159138663 + 142476565 142476619 33117712
+54
+
+chain 5020 7 158821424 + 141966623 141966675 12 133851895 + 53762512 53762564 33527602
+52
+
+chain 4939 7 158821424 + 142176195 142176247 7 159138663 + 142476241 142476293 33775264
+52
+
+chain 4778 7 158821424 + 73598 73651 5 180915260 - 172444 172497 587
+53
+
+chain 4039 7 158821424 + 101996220 101996263 7 159138663 + 102308194 102308237 1871
+43
+
+chain 3908 7 158821424 + 142167123 142167183 7 159138663 + 142455620 142455680 17639294
+60
+
+chain 3217 7 158821424 + 141963833 141963883 6 171115067 - 41704900 41704950 22743877
+50
+
+chain 2759 7 158821424 + 67423135 67423165 7 159138663 + 67785172 67785202 11329361
+30
+
+chain 2575 7 158821424 + 67423107 67423135 7 159138663 + 67785172 67785200 11329362
+28
+
+chain 2575 7 158821424 + 67423079 67423107 7 159138663 + 67785172 67785200 11329363
+28
+
+chain 2575 7 158821424 + 67423051 67423079 7 159138663 + 67785172 67785200 11329364
+28
+
+chain 2575 7 158821424 + 67423023 67423051 7 159138663 + 67785172 67785200 11329365
+28
+
+chain 2575 7 158821424 + 67422995 67423023 7 159138663 + 67785172 67785200 11329366
+28
+
+chain 2457 7 158821424 + 114257 114311 16 90354753 - 170806 170860 17475755
+54
+
+chain 2391 7 158821424 + 67422969 67422995 7 159138663 + 67785202 67785228 13667102
+26
+
+chain 2359 7 158821424 + 101974113 101974139 7 159138663 + 102286210 102286236 158723
+26
+
+chain 1502 7 158821424 + 141709533 141709580 7 159138663 + 142013474 142013521 12917072
+47
+
+chain 721 7 158821424 + 141963699 141963726 17 81195210 + 19853796 19853823 7983736
+27
+
+chain 615 7 158821424 + 141964154 141964190 19 59128983 - 28688778 28688814 21921932
+36
+
+chain 362 7 158821424 + 101987601 101987634 7 159138663 - 57149003 57149036 1101
+33
+
+chain 17312866 7_random 549659 + 162804 345700 GL000195.1 182896 + 0 182896 164
+182896
+
+chain 10142542 7_random 549659 + 0 112804 7 159138663 + 158928464 159038297 315
+4073 0 1
+5056 1 0
+1766 1 1
+63 5 5
+2422 1 0
+1297 1 0
+1967 196 0
+230 28 0
+2331 5 0
+47 1 1
+345 1 0
+41 1 1
+807 1 1
+31 1 1
+238 3 0
+100 1 0
+281 1 1
+43 1 1
+359 27 26
+59 1 1
+43 1 1
+1385 1 0
+161 1 0
+45 1 1
+1693 1 0
+93 1 0
+5 1 0
+805 0 3
+649 0 49
+1400 1 1
+4 1 0
+28 0 1
+7 0 1
+157 1 1
+117 0 31
+166 13 12
+138 1 0
+556 1 1
+46 1 1
+204 1 1
+21 1 1
+511 2 0
+390 1 1
+29 1 1
+60 1 1
+68 0 3
+27 1 1
+71 0 1
+37 5 0
+18 0 6
+56 3 3
+89 2 0
+103 6 15
+43 5 0
+7 0 11
+55 0 4
+456 46 45
+1286 1 1
+46 1 0
+36 2 0
+57 1 0
+396 1 1
+38 1 1
+298 1 1
+16 1 1
+602 224 0
+82 1 56
+1115 1 74
+17 3 3
+88 1 74
+98 158 12
+90 3 3
+70 3 3
+117 1 1
+43 1 1
+53 1 1
+21 1 1
+53 229 10
+120 81 8
+59 8 10
+411 1 0
+47 1 1
+723 0 9
+8142 6 6
+1297 1 1
+22 0 1
+7799 12 11
+1878 1 0
+70 5 5
+592 1 1
+28 1 1
+2251 1 0
+1474 1 0
+1975 0 1
+2577 0 1
+612 15 15
+93 1 0
+3 1 0
+149 1 0
+61 3 3
+34 1 0
+11 2101 0
+63 73 3
+67 106 1
+57 83 13
+60 70 0
+79 561 1
+321 70 0
+262 0 35
+83 183 8
+2406 0 549
+85 32 0
+27 0 26
+72 0 35
+22 3 0
+24 0 93
+74 2 0
+17 28 0
+63 1 0
+6 1 0
+1451 44 4
+23 1 1
+38 0 40
+80 1 121
+34 1 1
+58 0 82
+839 1 0
+31 1 1
+2861 0 4
+1376 1 1
+20 0 1
+78 2 0
+24 2 2
+2760 3 1
+585 8 0
+761 1 0
+6449 4 1
+259 1 1
+22 1 1
+717 0 1
+887 7 8
+2174 3 0
+970 1 0
+1768 12 0
+4378 0 1
+5 0 1
+13 1 0
+1637 5 10
+312 0 1
+2167 11 0
+164 10 10
+1517 1 1
+42 0 3
+698 0 4
+90 1 1
+20 1 1
+167 1 1
+16 1 1
+860 0 1
+1719
+
+chain 9633059 7_random 549659 + 402818 549659 7 159138663 + 514489 666751 345
+3766 22099 5004
+26 4 4
+11014 7 5
+17 1 0
+8 21 0
+3389 1 1
+54 1 1
+55 1 1
+66 1 1
+165 1 1
+38 1 1
+52 22350 21842
+816 4 4
+10432 15 15
+20532 1 1
+29 9 9
+13871 157 23205
+37837
+
+chain 2073422 7_random 549659 + 444161 465736 7 159138663 - 158510053 158531628 1246
+21575
+
+chain 1225579 7_random 549659 + 415456 428202 7 159138663 + 537499 550245 1943
+12746
+
+chain 745495 7_random 549659 + 406711 414469 7 159138663 - 158580384 158588142 6708
+215 11 11
+2423 4 4
+5105
+
+chain 224185 7_random 549659 + 399770 402202 7 159138663 + 518876 521308 490490
+367 50 50
+1609 1 1
+53 3 3
+304 1 1
+44
+
+chain 25943 7_random 549659 + 67571 70764 7 159138663 + 158995434 158996421 1881723
+67 73 3
+55 13 153
+17 71 0
+159 183 8
+119 21 21
+154 1960 0
+64 35 0
+105 35 0
+62
+
+chain 21070 7_random 549659 + 68795 70055 7 159138663 + 158995572 158996097 2684005
+86 98 63
+43 35 0
+76 455 0
+18 248 38
+61 57 57
+83
+
+chain 19298 7_random 549659 + 67796 68209 7 159138663 + 158995799 158996246 2040899
+35 195 229
+183
+
+chain 8295 7_random 549659 + 70341 70449 7 159138663 + 158996348 158996421 13908836
+11 35 0
+62
+
+chain 8007 7_random 549659 + 70264 70825 7 159138663 + 158995746 158996237 2373081
+77 186 46
+35 218 288
+45
+
+chain 7010 7_random 549659 + 69669 69742 7 159138663 + 158996026 158996099 13809421
+73
+
+chain 6757 7_random 549659 + 71674 71744 7 159138663 + 158996246 158996316 26425870
+70
+
+chain 6582 7_random 549659 + 16740 16849 7 159138663 + 158945342 158945395 9902405
+48 56 0
+5
+
+chain 5793 7_random 549659 + 36845 36905 7 159138663 + 158964922 158964982 31172491
+60
+
+chain 5504 7_random 549659 + 68645 69446 7 159138663 + 158995947 158996153 2767372
+68 176 1
+63 420 0
+74
+
+chain 5075 7_random 549659 + 34499 34552 7 159138663 + 158962931 158962984 33354772
+53
+
+chain 4386 7_random 549659 + 36139 36193 7 159138663 + 158964435 158964489 9901820
+54
+
+chain 4359 7_random 549659 + 69809 69854 7 159138663 + 158996061 158996106 24027999
+45
+
+chain 3345 7_random 549659 + 71561 71653 7 159138663 + 158995923 158996015 5823696
+92
+
+chain 3242 7_random 549659 + 36212 36249 7 159138663 + 158964435 158964472 7647561
+37
+
+chain 3169 7_random 549659 + 68713 69336 7 159138663 + 158995385 158995658 13517397
+46 500 150
+77
+
+chain 2856 7_random 549659 + 36091 36138 7 159138663 + 158964168 158964215 3415068
+47
+
+chain 2508 7_random 549659 + 74235 74267 7 159138663 + 158999705 158999737 11181217
+32
+
+chain 2422 7_random 549659 + 16701 16740 7 159138663 + 158944995 158945034 20425801
+39
+
+chain 2296 7_random 549659 + 76078 76102 7 159138663 + 159001472 159001496 26237556
+24
+
+chain 1888 7_random 549659 + 68772 68795 7 159138663 + 158995829 158995852 23967691
+23
+
+chain 1646 7_random 549659 + 16653 16684 7 159138663 + 158945171 158945202 6593972
+31
+
+chain 1510 7_random 549659 + 34573 34664 7 159138663 + 158962893 158962984 9181320
+91
+
+chain 1319 7_random 549659 + 70142 70185 7 159138663 + 158996289 158996332 23051286
+43
+
+chain 1065 7_random 549659 + 69520 69582 7 159138663 + 158996297 158996359 18766264
+62
+
+chain 13483752813 8 146274826 + 0 146274826 8 146364022 + 10000 146304022 9
+930417 1 1243
+52 10 10
+44 0 972
+100 0 54
+162 0 324
+409 0 1
+2323216 1 0
+3352649 2 0
+854996 100000 50000
+3399023 1 1
+46 1 1
+13965 1 1
+30 1 1
+121189 1 1
+35 1 1
+283700 0 1
+719291 100016 93054
+1155 0 2
+755 26 26
+980 21 21
+1479 54 54
+3597 1 0
+1937 19 19
+322 1 0
+1758 2 0
+1141 0 1
+956 48 48
+739 21 21
+1005 0 1
+543 1734 1734
+5338 15 15
+1029 1 1
+28 1 1
+305 57 57
+164 27 27
+5130707 0 1
+1288 0 1
+446 1 1
+80 1 1
+2123 4 4
+2514 3 0
+545 9 0
+527 1 1
+18 1 1
+256 9 9
+79 1 1
+40 1 1
+148 0 2
+2231 0 27
+958 1 1
+20 1 1
+2487 1 1
+113 1 1
+73 13 13
+365 10 10
+151 1 1
+32 3 0
+26 1 1
+1480 1 1
+29 1 1
+621 1 1
+28 1 1
+701 9 9
+362 1 1
+19 1 1
+691 1 1
+44 6 0
+47 1 1
+513 12 11
+382 1 1
+22 1 1
+111 1 1
+36 1 1
+337 1 1
+42 1 1
+602 2 0
+36 1 1
+475 1 1
+23 0 1
+32 4 3
+65 1 1
+59 1 1
+688 1 1
+22 1 1
+1473 1 1
+36 1 1
+372 1 1
+16 6 6
+1605 1 1
+38 1 1
+816 1 1
+17 1 0
+374 1 1
+17 1 1
+48 1 0
+82 1 1
+45 1 1
+263 1 1
+23 1 1
+204 1 1
+39 1 1
+2341 0 1
+2989 9 11
+811 8 8
+741 0 2
+337 1 1
+25 4 4
+763 1 1
+19 1 1
+343 1 1
+31 1 1
+1953 1 1
+74 1 1
+67 1 1
+18 4 4
+73 1 1
+31 1 1
+114 11 1
+87 1 1
+65 1 1
+125 9 9
+378 49 48
+90 1 1
+99 1 0
+173 13 7
+696 0 1
+6184 13 13
+830 13 13
+128 1 1
+37 1 1
+136 1 0
+66 5 6
+870 1 0
+4877 0 1
+585 3 7
+1728 1 0
+33 1 1
+465 1 1
+68 1 1
+581 6 0
+2088 1 0
+304 0 1
+2674 1 1
+28 1 0
+54 8 8
+846 0 1
+1409 16 16
+559 0 1
+407 0 5
+11 5 1
+29 1 1
+4051 1 1
+10 0 1
+43 1 1
+385 1 1
+35 1 1
+101 11 11
+602 1 0
+491 14 16
+1366 19 19
+321 1 1
+49 1 1
+546 1 1
+25 1 1
+2568 1 1
+51 4 0
+119 1 1
+39 0 1
+1040 0 1
+1682 0 4
+39 8 0
+862 1 1
+17 1 1
+587 1 1
+21 1 1
+904 0 1
+261 0 1
+1151 0 2
+2325 5 5
+5415 0 3
+1545 1 0
+428 4 4
+1950 2 0
+1073 0 1
+3653 0 86
+1283 1 1
+79 1 1
+6656 12 12
+1550 0 18
+5832 1 0
+4835 10 10
+1719 1 1
+84 1 1
+848 0 2
+236 1 1
+42 1 1
+1272 12 0
+49 1 1
+820 1 1
+22 1 0
+58 0 22
+510 8 8
+983 6 0
+539 14 14
+863 0 2
+27 1 1
+204 14 14
+163 4 4
+290 1 1
+59 1 1
+842 0 2
+2044 1 1
+90 0 1
+3434 0 3
+356 0 1
+873 0 1
+864 25 1
+630 12 7
+62 10 10
+156 11 11
+1364 19 19
+156 4 4
+244 4 18
+505 1 0
+109 1 1
+230 1 1
+107 4 3
+150 1 1
+83 5 5
+70 1 1
+33 1 0
+142 1 1
+626 5 6
+274 10 10
+128 1 1
+35 1 1
+216 1 1
+44 1 1
+312 1 1
+16 1 1
+1496 8 7
+451 0 1
+855 1 1
+20 1 1
+350 1 1
+62 1 1
+617 10 10
+845 1 1
+58 1 1
+2189 1 1
+147 1 1
+475 1 1
+27 1 1
+278 1 1
+17 1 1
+994 1 1
+40 1 1
+219 5 5
+26 1 1
+900 1 1
+29 1 0
+26 1 1
+484 15 16
+61 9 9
+114 21 26
+801 1 1
+33 1 1
+560 1 1
+37 1 1
+80 14 14
+211 1 1
+43 1 1
+156 1 1
+20 1 1
+685 1 1
+18 1 1
+48 4 0
+711 1 1
+38 1 1
+402 7 7
+1045 1 1
+37 1 1
+4035 9 9
+247 4 0
+4146274 17400 5734
+330366 0 1
+2346742 0 55
+413177 3 0
+450 1 0
+9436 3 1
+7044 4 0
+2886 1 0
+635 1 0
+16567 1 0
+6926 29 28
+9249 1 0
+14916 8 0
+12872 2 0
+3330 2 0
+2673376 2 0
+2603 1 1
+78 1 1
+2170491 7 7
+29817 66108 2485
+6473782 5 5
+39 1 1
+9574 0 2
+5879 1 1
+29 1 1
+6139 1 0
+2354 1 1
+28 1 1
+91 88 87
+142 16 15
+54 1 1
+22 3 3
+1479 4 4
+221 4 4
+132 1 0
+574 11 11
+23 1 0
+604 1 1
+44 1 1
+899 1 0
+70 1 0
+10 1 0
+13561 1 1
+44 1 1
+4476 4 4
+799 26 25
+1466 18 18
+17897 4 0
+1667 1 0
+4250 1 1
+44 1 3
+14 1 1
+4956 1 1
+18 1 0
+39 3 2
+4990 1 1
+47 13 13
+69 4 0
+9729 1 0
+355 0 1
+2186 1 1
+37 1 1
+6111 3 3
+100 4 4
+68 1 1
+43 1 1
+1126 5 7
+5520 8 8
+2316 1 1
+181 6 6
+50 1 1
+29 1 0
+83 1 1
+1073 245 639
+150 1 1
+25272 0 1
+2132 0 4
+2522 1 1
+48 1 1
+1498528 0 1
+6044582 3000008 3000000
+1291113 60074 16691
+3837 3 0
+811 1 0
+2567 1 0
+7375465 11 11
+42062 1 0
+19604621 1 0
+10692667 1 0
+110 0 1
+3577 0 3
+907 1 1
+18 1 1
+897 1 1
+64 535 251
+21 0 1
+140 0 1
+70 1 0
+77 9 10
+149 4 0
+5 1 5
+68 1 0
+142 5 5
+57 14 14
+43 1 1
+31034 124100 99683
+2301 0 2
+44 2 0
+568015 87325 183549
+330 5 5
+114 0 3088
+1776 0 3085
+949 0 4
+514 37 37
+963 15 14
+1351 71 71
+56 15 15
+405 713 713
+651 1 1
+41 1 1
+837 1 0
+658 0 1
+794 0 1
+73 1 1
+30 1 1
+817 51 51
+566 72 72
+195 0 12193
+1599 0 3085
+217 43 43
+247 29 29
+4148 1 0
+158 266 266
+696 20 20
+58 69 69
+100 13 13
+326 137 137
+151 35 35
+1804 151 151
+1341 289 289
+154 23 23
+1932 17 17
+111 47 47
+128 16 16
+78 30 30
+1022 6 10
+78 1 0
+342 31 31
+86 23 23
+1601 41 41
+144 49 49
+170 10 10
+398 23 23
+419 20 20
+955 55 55
+1139 11 11
+1925 0 276
+223 58 58
+702 25 25
+1030 23 23
+363 164 164
+653 16 16
+78 13 13
+1035 0 4
+514 37 37
+1069 10 10
+321 15 15
+603 68 68
+789 20 20
+56 25 25
+1007 5 5
+1198 24 24
+689 3 0
+743 32 32
+817 43 43
+574 11 11
+123 19 19
+618 28 28
+1270 15 15
+289 29 29
+106 11 11
+1395 46 46
+850 4 4
+777 62 62
+86 36 36
+374 97 97
+2072 31 31
+195 56 56
+379 80 80
+64 11 11
+191 18 18
+1051 13 13
+52 163 169
+1297 1 1
+25 1 1
+3451 0 188
+3097 0 9
+2715 1 0
+11829 0 3
+6001 28 0
+10728 0 1
+3770769 1 0
+62 1 0
+22 1 0
+827 1 0
+1485 1 0
+242 0 1
+7142 1 0
+4029 3 3
+69 1 1
+15865 1 0
+83463 4 0
+5976 9 0
+2661 1 0
+1483 1 0
+15868 4 0
+17798 1 0
+2649 1 0
+3627 1 0
+4789 1 0
+9541 1 0
+6844 1 0
+3187 2 0
+411 14 0
+3056 4 0
+19776 3 0
+29085 0 1
+745 2 0
+11453 2 0
+16739 1 0
+14697 1 0
+8539 1 0
+25514443 1 0
+17680 0 1
+55359 0 1
+58 57 59
+1515 1 0
+1111 1 0
+5736 6 6
+66213 1 0
+68 1 1
+24 6 7
+43 1 1
+33414 7 7
+22 1 1
+19312 0 1
+8588 1 1
+31 1 1
+15969 1 1
+32 1 1
+27034 1 1
+42 1 1
+3352 0 1
+15009 1 0
+20433 18 18
+32141 9 8
+116 41 41
+4920 1 0
+33364 1 0
+11160 15 17
+28423 1 0
+43835 1 1
+24 4 2
+269244 4 4
+37 1 1
+17193 4 3
+53 12 11
+23 2 1
+7 1 1
+37978 9 9
+37743 1 1
+35 3 3
+26636 1 1
+17 1 1
+8728292 1 0
+16734742 0 71275
+27 1 1
+657033 0 2
+2911 0 2
+1941 1 1
+35 1 1
+835 1 1
+116 1 1
+399 1 1
+101 1 0
+194 1 2
+450 1 0
+825 1 1
+73 1 1
+156 1 1
+58 1 1
+50 5 5
+153 11 11
+189 5 5
+233 1 1
+83 1 1
+642 0 1
+1380 1 1
+17 1 1
+315 1 1
+26 1 1
+786 0 901
+76 1 1
+45 1 1
+535 1 1
+34 1 1
+2007 7 7
+159 1 1
+26 1 1
+6362 13 13
+504325 100008 25635
+420771 0 232
+287680 0 104
+73 0 364
+181 0 55
+95 1 1
+46 1 1
+4002 1 1
+24 1 1
+183 49 0
+72 1 2
+8 1 0
+39 688 1
+306 0 50
+1939 0 1
+615 684 0
+254 0 1
+572035 7362 108542
+480202 1 0
+11866 6 6
+26917 0 1
+6097 15 15
+3074 0 1
+12292 0 1
+2209 0 1
+7358 0 1
+321393
+
+chain 161719 8 146274826 + 12213564 12217654 8 146364022 + 11922619 11926713 3890
+48 2333 2337
+1544 26 26
+139
+
+chain 94297 8 146274826 + 86864948 86909782 8 146364022 + 86767902 86816113 712
+43 4583 4586
+51 23 23
+69 22 22
+81 3466 3466
+114 1460 1461
+170 2237 2237
+47 3442 3445
+24 161 161
+49 1995 1995
+32 5554 5830
+116 4 4
+12 2309 5394
+37 2018 2018
+68 865 865
+25 3669 3669
+32 817 817
+42 1346 1346
+28 1574 1574
+29 1512 1515
+46 1652 1652
+41 2665 2665
+30 2224 2230
+50
+
+chain 49697 8 146274826 + 86036864 86037399 8 146364022 + 85964814 85965349 932809
+535
+
+chain 26725 8 146274826 + 86857851 86907733 8 146364022 + 86754632 86786590 1026
+491 49362 31438
+29
+
+chain 24621 8 146274826 + 145396034 145396288 8 146364022 + 145493131 145493385 2960834
+254
+
+chain 18039 8 146274826 + 144819613 144819801 8 146364022 + 144748845 144749033 12082915
+188
+
+chain 14890 8 146274826 + 86857082 86862299 8 146364022 - 59611598 59616815 1124
+71 476 476
+222 4397 4397
+51
+
+chain 13243 8 146274826 + 144819801 144819938 8 146364022 + 144748593 144748730 12136518
+137
+
+chain 9530 8 146274826 + 144823061 144823289 8 146364022 + 144751680 144751756 18947814
+3 152 0
+73
+
+chain 9463 8 146274826 + 144819938 144820036 8 146364022 + 144748632 144748730 13619337
+98
+
+chain 8087 8 146274826 + 86874741 86874834 8 146364022 + 86817360 86817453 1088
+93
+
+chain 7965 8 146274826 + 86865238 86879045 8 146364022 + 86780387 86797281 766
+29 7982 7984
+37 5729 8814
+30
+
+chain 7439 8 146274826 + 12201270 12203830 8 146364022 + 11910337 11912897 3584
+26 2480 2480
+54
+
+chain 6315 8 146274826 + 86909619 86909690 8 146364022 + 86556151 86556222 765064
+71
+
+chain 6303 8 146274826 + 144823559 144823625 8 146364022 + 144751722 144751788 29838951
+66
+
+chain 5756 8 146274826 + 86854716 86862896 8 146364022 + 86782059 86817706 1940
+37 8112 35579
+31
+
+chain 5521 8 146274826 + 144823643 144823701 8 146364022 + 144751730 144751788 31959915
+58
+
+chain 5339 8 146274826 + 144823077 144823133 8 146364022 + 144751620 144751676 32492605
+56
+
+chain 4702 8 146274826 + 144819343 144819392 8 146364022 + 144748967 144749016 12082914
+49
+
+chain 4684 8 146274826 + 144823154 144823323 8 146364022 + 144751621 144751752 19314390
+33 102 64
+34
+
+chain 4385 8 146274826 + 144820066 144820134 8 146364022 + 144748613 144748681 20813384
+68
+
+chain 3959 8 146274826 + 144820160 144820201 8 146364022 + 144748560 144748601 13619336
+41
+
+chain 3959 8 146274826 + 144819572 144819613 8 146364022 + 144748560 144748601 13619338
+41
+
+chain 3270 8 146274826 + 86905368 86905406 8 146364022 - 59611399 59611437 120315
+38
+
+chain 3190 8 146274826 + 144819513 144819546 8 146364022 + 144748697 144748730 12136519
+33
+
+chain 2525 8 146274826 + 144823339 144823377 8 146364022 + 144751692 144751730 23202086
+38
+
+chain 2511 8 146274826 + 144819546 144819572 8 146364022 + 144748632 144748658 13619339
+26
+
+chain 2509 8 146274826 + 144820134 144820160 8 146364022 + 144748632 144748658 22535050
+26
+
+chain 2395 8 146274826 + 144820036 144820061 8 146364022 + 144748974 144748999 15328526
+25
+
+chain 2146 8 146274826 + 86862896 86862937 8 146364022 - 59626667 59626708 2042
+38 1 1
+2
+
+chain 2013 8 146274826 + 12224371 12224395 8 146364022 + 11933433 11933457 5802
+24
+
+chain 928 8 146274826 + 86871422 86871445 8 146364022 + 86566156 86566179 4371
+23
+
+chain 19961283 8_random 943810 + 732172 943810 5 180915260 + 69954173 70165811 138
+211638
+
+chain 4772201 8_random 943810 + 62854 113804 8 146364022 + 16274686 16325603 650
+4146 9 9
+1642 5 9
+541 4 0
+1197 1 1
+27 1 1
+2498 0 1
+20171 4 0
+2761 3 0
+1978 0 1
+628 10 0
+5533 3 0
+2428 24 0
+47 5 9
+197 11 11
+687 0 2
+642 1 1
+17 1 1
+2228 0 4
+1978 1 0
+1521
+
+chain 4401722 8_random 943810 + 396973 443039 8 146364022 - 801667 847519 685
+2079 1 0
+22818 62 9
+50 57 0
+25 0 8
+40 91 0
+5953 32 0
+1937 0 2
+803 13 14
+786 0 5
+3908 2 0
+783 0 1
+854 1 0
+142 1 0
+1521 1 0
+114 0 1
+498 4 4
+591 2 0
+2750 0 9
+147
+
+chain 3680035 8_random 943810 + 643258 682172 GL000196.1 38914 + 0 38914 797
+38914
+
+chain 3554032 8_random 943810 + 493047 530222 GL000197.1 37175 + 0 37175 825
+37175
+
+chain 1222443 8_random 943810 + 0 12854 8 146364022 - 108556772 108569616 1946
+5765 0 1
+2843 2 0
+279 0 1
+299 1 0
+1113 9 0
+2543
+
+chain 995258 8_random 943810 + 250482 297042 8 146364022 + 46838897 46856230 2491
+52 5 5
+72 1882 0
+246 1888 0
+158 79 78
+59 82 81
+53 46 46
+76 18 18
+100 1942 59
+231 1 0
+84 1 0
+49 23 22
+65 25 25
+312 49 47
+118 1 0
+169 645 640
+71 18 18
+202 15 15
+74 114 112
+65 1444 30
+86 2249 34
+216 9 8
+173 33 30
+63 81 79
+265 87 84
+103 11 10
+122 1 1
+47 1 1
+165 858 0
+14 1027 0
+88 1879 0
+148 7 6
+166 1 0
+288 1888 1
+62 1 1
+90 1 0
+35 1890 1
+280 3 3
+23 1 0
+109 1 1
+283 4 4
+88 1 1
+67 1 1
+23 1 1
+109 680 0
+89 1876 0
+41 1 0
+45 1898 0
+107 18 18
+18 1 0
+28 1 1
+50 1 0
+35 1 1
+50 7 4
+54 1 0
+37 1 1
+298 11 10
+94 1 0
+17 1 0
+36 1 0
+55 1 0
+12 1 1
+148 1 1
+79 11 9
+78 1 1
+140 5 4
+54 3 0
+97 1 0
+138 6 4
+73 1 0
+59 19 19
+207 1 1
+45 1 1
+76 1 0
+8 3 1
+60 2 2
+56 1 1
+70 1 0
+45 1 1
+136 131 128
+86 17 16
+75 7 7
+53 483 144
+75 26 26
+230 135 132
+110 15 15
+61 25 23
+76 43 42
+120 1 0
+78 1735 1728
+192 42 41
+61 82 82
+190 37 37
+90 1911 30
+168 56 56
+56 10 10
+83 26 26
+230 1927 49
+224 1937 52
+244 41 41
+125 36 36
+96 26 26
+83 81 78
+272 2019 139
+59 236 231
+103 71 70
+183 31 31
+58 119 117
+131 1 0
+167 25 25
+72 97 96
+91 6 6
+75 10 9
+219
+
+chain 895028 8_random 943810 + 298039 346176 8 146364022 - 99507152 99525054 4376
+63 126 463
+229 1883 1
+104 25 25
+58 6 6
+155 36 35
+84 10 10
+88 23 23
+53 1 0
+164 5 5
+68 56 55
+231 24 24
+149 409 408
+53 1 0
+69 1 0
+134 6 6
+201 318 315
+27 1885 0
+105 1 0
+82 82 82
+144 27 27
+56 238 235
+130 24 23
+109 1 0
+77 2 1
+100 31 30
+102 14 14
+63 11 10
+108 91 91
+72 94 93
+169 149 148
+198 238 234
+86 2 0
+169 3 1
+72 11 11
+66 1 0
+247 18 17
+392 540 533
+186 7 7
+121 1 0
+254 1977 89
+53 7 7
+193 483 475
+93 50 47
+198 28 28
+76 1883 8
+61 130 129
+123 29 29
+112 201 199
+138 12 11
+21 1873 0
+107 33 33
+53 1880 1
+118 40 38
+141 1943 53
+168 137 134
+81 16 16
+115 2216 0
+103 32 29
+71 128 127
+104 54 53
+121 128 127
+66 99 96
+80 75 74
+128 1924 40
+53 2 1
+288 1910 24
+53 1907 23
+56 40 40
+72 111 111
+62 127 127
+122 65 65
+80 210 206
+115 0 1
+146 5663 0
+183 40 40
+53 34 33
+229 28 28
+92 83 83
+234 1983 101
+57 1885 0
+44 11 11
+62 1 0
+69 28 28
+126 1 0
+148 147 144
+58 14 12
+53 1 0
+66 1 0
+105 34 33
+71 39 38
+69 17 17
+56 6 5
+79 48 46
+53 6 6
+57 38 35
+77 78 75
+111 649 644
+110 45 43
+235
+
+chain 604051 8_random 943810 + 178170 281976 8 146364022 + 46838954 46856867 5476
+212 1875 0
+272 566 562
+114 1 0
+143 1 0
+55 74 74
+65 25 25
+63 62 62
+61 31 31
+102 23 23
+215 1 0
+63 67 68
+68 373 34
+158 64 63
+53 46 46
+105 67 67
+55 2294 38
+202 15 15
+63 51 51
+246 23 23
+71 1 0
+271 103 102
+427 6 5
+51 25 22
+54 1878 0
+36 10 10
+122 26 26
+134 1886 0
+121 93 92
+51 1 2
+246 54742 0
+134 1884 0
+129 33 31
+147 39 38
+116 65 61
+66 43 41
+62 1982 95
+213 196 193
+339 260 254
+187 89 88
+10 2292 403
+57 5123 1343
+293 24 22
+61 1 0
+73 7 7
+53 1877 144
+91 4270 499
+59 2463 581
+37 339 671
+59 342 0
+110 266 261
+150 6 6
+92 244 241
+51 62 62
+51 3119 1229
+91 761 80
+60 48 47
+137 1876 0
+136 12 10
+131 12 11
+290 1 0
+45 4005 2083
+59 88 424
+59
+
+chain 496223 8_random 943810 + 580222 593236 8 146364022 - 59615387 59795086 34662
+2144 4634 17818
+237 1 1
+31 1 1
+194 35 40
+1575 162 153603
+534 0 55
+995 64 64
+1343 58 58
+112 1 1
+38 1 1
+70 1 1
+41 1 1
+81 1 1
+34 1 1
+624
+
+chain 279595 8_random 943810 + 199376 329223 8 146364022 - 99506514 99525054 6095
+67 50 47
+55 631 967
+63 1082 0
+177 61 58
+147 6 6
+143 1 0
+42 1882 0
+74 31 30
+83 23 23
+13 1879 0
+204 5 5
+58 69 69
+227 1933 51
+152 123 122
+83 1 0
+118 72 72
+159 17 17
+119 34 34
+230 36 36
+134 1929 32
+189 3017 0
+24 83 83
+121 1 0
+49 5680 1
+325 136 129
+277 30 30
+335 1436 53
+51 63 62
+99 867 859
+154 860 855
+269 32 31
+112 1 0
+50 1877 0
+99 58 58
+108 1 0
+96 2221 0
+37 1546 0
+136 2648 89
+52 7 8
+278 1 0
+202 139 136
+145 65 63
+51 44 42
+62 143 139
+61 156 155
+243 214 215
+20 1872 0
+194 74 75
+337 25 25
+145 15 15
+71 65 65
+84 1878 0
+60 1 0
+244 227 225
+226 53 53
+62 42 41
+66 63 61
+120 35 34
+64 56110 1
+98 41 40
+53 2795 914
+65 10 10
+57 8290 755
+67 63 61
+66 17 16
+53 1 0
+58 36 36
+92 3924 162
+40 61 61
+58 4119 368
+133 2082 185
+58 42 42
+167 2235 21
+50 4401 627
+71 40 39
+147 360 353
+60 174 173
+446
+
+chain 208078 8_random 943810 + 170910 242131 8 146364022 - 99506628 99524507 6380
+55 632 967
+69 73 73
+115 28 28
+146 4836 20
+75 1 0
+54 58 58
+87 10 10
+294 22105 209
+184 59 59
+53 209 208
+64 1388 305
+56 340 338
+60 50 50
+134 32 32
+108 2 0
+106 83 82
+108 1884 0
+62 68 68
+216 1 0
+55 20 20
+107 3862 104
+61 311 311
+29 2182 2154
+53 1 0
+93 1388 251
+108 3 2
+129 159 158
+109 1 0
+31 114 113
+51 60 60
+78 14 14
+99 14 13
+152 64 62
+60 13 12
+120 98 98
+138 115 114
+56 6 4
+26 438 436
+213 183 182
+53 1 0
+81 2318 428
+71 25 25
+145 15 15
+71 65 65
+109 1956 43
+69 112 108
+33 397 392
+58 1466 80
+62 46 46
+401 64 64
+45 51 51
+56 1 0
+6 99 99
+54 146 144
+187 67 67
+166 52 49
+51 9 8
+63 11 10
+61 186 186
+68 38 38
+168 105 102
+125 3 2
+113 17 17
+186 2 0
+3 6394 747
+113 762 83
+102 4015 254
+238 102 101
+91 6 6
+85 1999 129
+12 9 9
+44 2322 442
+90 319 318
+42
+
+chain 110041 8_random 943810 + 584910 586860 8 146364022 - 59525621 59532924 58275
+151 1 1
+64 1 1
+158 1 1
+137 0 5353
+14 3 3
+73 8 8
+52 11 11
+57 9 9
+54 15 15
+289 15 15
+837
+
+chain 81230 8_random 943810 + 228410 243660 8 146364022 - 99515272 99524158 121868
+53 818 813
+113 55 55
+76 1036 1025
+78 1 0
+115 1280 591
+98 36 34
+79 25 25
+73 189 188
+120 2622 738
+79 145 145
+8 21 19
+36 157 155
+27 18 14
+98 82 81
+130 280 280
+78 83 83
+21 20 20
+27 51 51
+134 238 238
+10 39 39
+53 216 215
+252 5175 1418
+73 6 6
+146 231 228
+111 1 0
+201 35 35
+101
+
+chain 78595 8_random 943810 + 271315 287023 8 146364022 + 46844767 46855610 13381
+177 7 6
+61 49 46
+54 86 84
+62 24 23
+151 92 91
+73 109 107
+108 1 0
+51 8 6
+97 2409 1723
+29 1995 118
+92 64 63
+24 701 695
+42 7 7
+53 90 89
+54 403 392
+25 6360 4099
+70 192 192
+26 77 76
+63 336 336
+129 125 126
+143 878 869
+27 23 23
+61
+
+chain 70241 8_random 943810 + 583972 584708 8 146364022 - 2327498 2328234 1800744
+736
+
+chain 67060 8_random 943810 + 583131 583834 8 146364022 + 144032710 144033413 1885205
+703
+
+chain 60161 8_random 943810 + 163863 193392 8 146364022 + 46840361 46854926 51951
+69 30 30
+79 155 153
+22 224 224
+36 635 633
+54 78 77
+53 1660 61
+55 408 405
+36 32 32
+40 163 161
+29 96 89
+5 85 85
+4 108 106
+193 10362 0
+211 23 23
+164 214 212
+108 41 40
+217 35 35
+85 25 25
+266 2366 490
+48 600 260
+32 3507 4987
+74 590 587
+105 2319 2307
+66 2880 990
+102 1 0
+89 507 168
+143
+
+chain 59106 8_random 943810 + 169718 174718 8 146364022 - 99507650 99524666 884317
+69 73 73
+53 107 105
+145 323 5927
+57 45 43
+58 51 49
+65 130 129
+16 74 74
+175 49 49
+53 423 422
+53 2360 8782
+34 55 55
+95 1 0
+28 1 0
+2 113 113
+292
+
+chain 53138 8_random 943810 + 171392 346403 8 146364022 - 102525263 102570806 8603
+57 57 57
+79 626 627
+64 1139 91
+72 32 32
+61 1 0
+192 55 53
+253 233 231
+113 1894 10
+151 18218 118
+161 39 39
+89 168 167
+68 174 168
+68 7236 473
+76 2229 347
+40 124 120
+50 21 21
+55 1906 29
+98 2 0
+51 3928 158
+113 3230 214
+58 5760 82
+62 113 112
+39 7442 4152
+122 13 12
+149 90 90
+56 48 47
+71 400 397
+133 1910 21
+97 23 23
+92 2561 0
+54 15 13
+67 70 69
+90 95 94
+59 72 72
+139 45 45
+101 71659 2394
+62 72 72
+84 1 0
+9 2000 117
+95 39 39
+65 70 68
+87 2031 150
+103 1949 61
+106 17 17
+136 75 74
+53 5662 38
+58 1936 41
+42 168 168
+108 95 95
+66 243 241
+50 5018 908
+53 4282 513
+74 1906 30
+83 2078 26035
+107 1947 59
+57 500 483
+160 1936 53
+185 1897 12
+119 3972 202
+29 14 14
+79 61 61
+44
+
+chain 52733 8_random 943810 + 164218 295513 8 146364022 + 43821028 43838759 7574
+63 20 20
+141 36 36
+153 32 31
+103 40 40
+53 86 85
+99 1658 59
+83 265 263
+110 21 21
+51 29 27
+160 108 108
+51 1 0
+49 1 0
+61 130 123
+85 12281 44
+69 272 272
+118 62 62
+75 7995 1645
+102 45 45
+59 32 32
+14 328 328
+126 2372 483
+86 58668 153
+40 4323 551
+31 1938 56
+58 2392 511
+58 234 222
+51 1403 0
+51 91 91
+50 218 218
+83 67 66
+75 77 77
+110 391 53
+2 2678 792
+147 104 101
+59 1917 33
+92 1958 75
+54 5899 1442
+11 105 104
+132 1 0
+50 2212 332
+66 5506 1369
+60 189 189
+173 223 221
+222 1874 0
+87 23 23
+54 108 108
+109 29 28
+94 64 63
+70 91 86
+97 164 161
+112 123 123
+78 1942 66
+145 118 118
+69 1917 31
+51 10 10
+113 235 231
+193 327 327
+41 392 391
+51 363 361
+123 1977 94
+57
+
+chain 48120 8_random 943810 + 172087 205615 8 146364022 - 99508140 99525054 275640
+50 1136 89
+81 56 55
+4 1876 5603
+199 577 570
+71 144 141
+39 17920 1690
+56 276 276
+117 289 289
+64 172 170
+10 18 18
+76 284 279
+308 237 229
+64 1904 0
+33 2094 204
+40 43 43
+63 3 2
+59 12 12
+306 15 15
+33 1146 61
+49 757 4487
+37 62 62
+83 46 46
+112 178 174
+95 1 0
+29 1956 73
+248
+
+chain 37837 8_random 943810 + 253130 272078 8 146364022 + 46839659 46847391 87472
+42 44 44
+61 2771 880
+109 37 36
+171 1 0
+120 209 204
+98 56 55
+61 10 9
+23 187 186
+75 18 18
+17 5316 1682
+9 145 143
+53 1 0
+29 137 137
+73 132 128
+65 14 14
+79 6214 2430
+95 70 70
+83 2232 342
+91
+
+chain 33662 8_random 943810 + 209837 215530 8 146364022 - 99514311 99520696 710844
+71 67 65
+87 1 0
+118 10 8
+19 543 533
+53 11 11
+89 4 2
+68 143 138
+148 1307 167
+110 627 624
+30 2103 3960
+84
+
+chain 32940 8_random 943810 + 226035 229035 8 146364022 - 102534454 102537445 203694
+68 23 23
+49 847 842
+50 91 91
+134 57 57
+61 1290 1287
+37 113 113
+86 41 40
+53
+
+chain 31024 8_random 943810 + 206449 211988 8 146364022 - 99514678 99520173 701886
+8 43 43
+64 6 5
+58 14 12
+82 340 0
+49 416 749
+81 59 59
+117 75 75
+207 1422 3285
+36 2428 531
+34
+
+chain 29825 8_random 943810 + 245532 246838 8 146364022 + 46839602 46840894 3893579
+57 560 553
+119 226 222
+5 184 184
+21 75 72
+59
+
+chain 28513 8_random 943810 + 169082 170209 8 146364022 - 99514495 99515614 2995290
+72 337 330
+70 17 17
+84 143 144
+53 81 80
+64 162 161
+44
+
+chain 28403 8_random 943810 + 244271 247583 8 146364022 + 46840215 46841632 1514192
+150 21 21
+65 247 246
+61 60 60
+144 37 36
+68 1 0
+56 146 144
+158 1945 55
+153
+
+chain 27366 8_random 943810 + 305024 329400 8 146364022 - 99508828 99514021 185326
+30 144 144
+27 1950 69
+57 1 0
+69 4733 954
+80 7 7
+60 2015 139
+144 51 51
+17 50 48
+20 2199 324
+179 83 83
+149 1 0
+45 50 50
+29 198 197
+38 56 56
+36 163 162
+27 2035 153
+71 157 157
+56 6099 109
+62 47 47
+93 104 100
+75 1 0
+39 342 0
+49 1641 94
+81 539 539
+177
+
+chain 25161 8_random 943810 + 165410 166073 8 146364022 + 46840031 46840686 5084847
+51 107 104
+69 107 106
+77 51 48
+53 79 78
+69
+
+chain 23498 8_random 943810 + 275598 276538 8 146364022 + 46848347 46849285 1106774
+150 39 39
+58 1 0
+156 159 160
+43 237 235
+97
+
+chain 22556 8_random 943810 + 221873 233787 8 146364022 - 102535430 102541485 264178
+56 92 91
+134 1524 140
+26 9348 4879
+77 298 294
+159 126 126
+55 8 7
+11
+
+chain 21554 8_random 943810 + 211856 229563 8 146364022 - 102534119 102541711 230838
+98 1283 144
+76 1760 1749
+25 1 0
+80 1889 12
+87 80 79
+50 14 14
+51 55 50
+59 207 201
+52 31 30
+212 2303 390
+120 3503 2102
+43 5590 1830
+38
+
+chain 21378 8_random 943810 + 315539 346866 8 146364022 - 99515536 99522005 182294
+65 7 7
+59 1872 0
+52 1 0
+110 59 59
+145 1929 47
+157 4107 0
+50 19 19
+76 11 11
+9 218 215
+20 69 68
+27 104 104
+38 3941 169
+93 9868 446
+40 53 53
+33 350 349
+83 1915 34
+228 2 1
+71 4993 3080
+80 103 101
+58 162 162
+50
+
+chain 20133 8_random 943810 + 187153 190961 8 146364022 + 46839718 46841635 711123
+27 2490 610
+70 193 186
+75 6 6
+22 81 81
+48 1 0
+41 200 200
+10 13 12
+78 103 101
+193 10 10
+147
+
+chain 19851 8_random 943810 + 184692 274845 8 146364022 + 46839508 46849467 34309
+59 20 20
+103 2903 645
+204 29 27
+122 5 4
+251 1 1
+19 1 1
+370 102 102
+45 59 59
+32 2407 520
+35 53082 226
+207 6009 346
+163 6 4
+101 79 79
+50 419 416
+33 1900 15
+227 6 6
+48 1 0
+53 22 21
+65 58 57
+59 43 42
+133 81 80
+20 44 42
+50 14 12
+53 37 36
+104 2375 490
+62 1340 1334
+14 1 0
+183 3854 228
+49 6055 405
+35 6036 1578
+80 25 25
+89 8 7
+13
+
+chain 19146 8_random 943810 + 175023 175290 8 146364022 - 99508150 99508416 4025470
+88 58 57
+65 25 25
+31
+
+chain 17870 8_random 943810 + 167013 193249 8 146364022 + 46840039 46851047 112211
+37 407 404
+31 233 231
+41 10382 13
+26 802 800
+40 282 279
+41 6132 1660
+77 3954 2070
+28 510 4239
+81 90 89
+50 30 30
+120 2083 201
+60 192 191
+51 338 0
+118
+
+chain 17758 8_random 943810 + 265412 266607 8 146364022 + 43830436 43831619 676151
+58 100 98
+16 14 14
+59 946 936
+2
+
+chain 17102 8_random 943810 + 196211 212812 8 146364022 - 102534634 102539542 315778
+4 176 169
+110 677 661
+101 229 222
+63 12 11
+71 2311 416
+66 5 5
+3 2545 1456
+25 7 5
+52 21 20
+3 9994 1320
+61 8 7
+57
+
+chain 16958 8_random 943810 + 303736 319647 8 146364022 - 99509421 99514022 288375
+62 1 0
+115 55 55
+12 6716 1059
+173 60 58
+5 238 238
+27 142 138
+80 1 0
+32 1181 1170
+56 95 93
+15 6818 1186
+27
+
+chain 16519 8_random 943810 + 191041 191237 8 146364022 + 46841712 46841907 5194781
+138 7 6
+51
+
+chain 16395 8_random 943810 + 250196 250458 8 146364022 + 46842349 46842610 5706058
+109 63 63
+38 1 0
+51
+
+chain 16284 8_random 943810 + 248826 295566 8 146364022 + 43821313 43835075 8983
+38 3114 1217
+58 3878 108
+134 2320 436
+35 2074 180
+90 6230 729
+53 51 51
+165 2138 257
+18 1 0
+14 9087 4604
+68 26 23
+70 26 25
+165 4726 2469
+31 113 113
+45 6358 726
+53 323 321
+29 3160 1272
+53 1943 60
+1 1 0
+51
+
+chain 16072 8_random 943810 + 313809 340982 8 146364022 - 102527896 102533983 267291
+28 5309 1547
+73 15383 1858
+110 23 22
+51 120 119
+75 171 167
+144 2405 509
+56 2087 199
+104 240 238
+93 367 364
+59 113 109
+162
+
+chain 15849 8_random 943810 + 261982 295288 8 146364022 + 43821759 43829198 76114
+110 412 75
+52 237 234
+137 1904 21
+61 17 17
+88 8048 505
+97 1212 533
+118 1 0
+62 80 80
+12 643 644
+105 9123 1231
+153 113 112
+50 1019 1018
+55 3899 142
+89 478 475
+43 4836 1068
+52
+
+chain 15670 8_random 943810 + 194296 345941 8 146364022 - 102525263 102540770 8834
+113 3789 1
+79 5134 279
+81 25039 3655
+36 72 71
+66 2073 189
+82 66 62
+87 280 277
+20 23 23
+59 87 84
+72 49 48
+51 7 7
+82 1014 334
+62 79983 3178
+76 18 17
+68 2382 504
+43 42 41
+108 10477 733
+134 2033 147
+59 5650 11
+88 3846 65
+64 297 293
+50 3779 12
+69 123 122
+120 121 120
+68 15 15
+57 136 135
+139 239 237
+72 1 0
+63 4 3
+53 59 59
+8 490 488
+28 84 81
+35 298 293
+34 805 799
+67 1 0
+53 69 67
+100 14 14
+81 134 132
+53 38 38
+39 110 109
+45
+
+chain 14986 8_random 943810 + 225882 226349 8 146364022 - 99518359 99518822 2174986
+18 53 51
+56 166 164
+73 33 33
+68
+
+chain 14834 8_random 943810 + 243014 243551 8 146364022 - 99519780 99520313 2299338
+16 162 159
+19 313 312
+27
+
+chain 14491 8_random 943810 + 298927 299279 8 146364022 - 102541139 102541484 3650546
+95 253 246
+4
+
+chain 13927 8_random 943810 + 330425 330634 8 146364022 - 99513165 99513373 16289681
+108 47 46
+54
+
+chain 13708 8_random 943810 + 204114 204446 8 146364022 - 99514221 99514551 7956244
+38 2 1
+51 137 136
+104
+
+chain 13201 8_random 943810 + 267894 296641 8 146364022 + 46841376 46846486 149880
+47 8325 118
+153 12619 975
+124 10 10
+59 1933 45
+415 178 178
+62 103 99
+67 193 193
+45 34 34
+4 542 542
+26 2853 963
+60 194 194
+31 632 628
+38
+
+chain 12234 8_random 943810 + 261803 269960 8 146364022 + 46841266 46843423 172872
+35 2890 667
+1 24 24
+60 15 15
+6 166 166
+32 2034 149
+193 134 132
+81 69 68
+116 2096 211
+21 87 83
+97
+
+chain 10617 8_random 943810 + 337138 337293 8 146364022 - 99523571 99523724 21494273
+69 29 27
+57
+
+chain 10554 8_random 943810 + 261774 276161 8 146364022 + 46850579 46856384 287750
+26 3379 1156
+30 20 20
+51 4844 1067
+12 16 15
+65 51 50
+53 361 357
+85 102 101
+13 51 51
+26 87 87
+46 4988 2413
+81
+
+chain 10039 8_random 943810 + 325665 325968 8 146364022 - 99512180 99512483 3203386
+32 146 146
+51 12 12
+62
+
+chain 9889 8_random 943810 + 299929 343052 8 146364022 - 99507161 99512618 194143
+54 125 463
+172 6011 368
+29 4240 471
+68 8003 490
+69 47 47
+10 133 133
+55 45 44
+46 4488 379
+66 1908 22
+82 7833 307
+63 2043 161
+90 115 115
+101 1 0
+97 2144 241
+32 4543 773
+83 294 293
+33
+
+chain 9887 8_random 943810 + 315022 315154 8 146364022 - 99513153 99513284 7544872
+79 1 0
+52
+
+chain 9860 8_random 943810 + 311200 311307 8 146364022 - 99513093 99513199 8991129
+52 1 0
+54
+
+chain 9817 8_random 943810 + 331048 331155 8 146364022 - 99513786 99513892 13428201
+64 1 0
+42
+
+chain 9446 8_random 943810 + 266857 296082 8 146364022 + 43794817 43828117 103381
+44 9743 27369
+146 121 120
+47 983 976
+79 10221 2331
+165 112 112
+51 81 80
+39 1877 0
+66 2043 157
+36 3318 1429
+53
+
+chain 9082 8_random 943810 + 283227 283503 8 146364022 + 46855567 46855841 3572014
+72 39 38
+7 101 100
+57
+
+chain 9078 8_random 943810 + 266179 266275 8 146364022 + 46841541 46841637 24832874
+96
+
+chain 9056 8_random 943810 + 234327 343102 8 146364022 - 102532678 102541696 177988
+49 2060 180
+83 4311 566
+60 72559 3258
+278 110 111
+124 380 378
+51 246 244
+21 14 13
+37 2147 273
+83 195 193
+50 29 28
+5 2000 121
+73 4435 328
+132 3864 97
+47 5706 63
+45 54 54
+151 1883 5
+99 3796 15
+99 63 61
+64 1 0
+58 1881 0
+137 76 74
+53 53 48
+27 312 310
+85 17 16
+19 140 140
+52 244 244
+62 105 104
+50
+
+chain 8907 8_random 943810 + 174718 174972 8 146364022 - 99514987 99515577 3222521
+12 195 531
+47
+
+chain 8843 8_random 943810 + 329461 329557 8 146364022 - 99512211 99512306 12312646
+78 1 0
+17
+
+chain 8728 8_random 943810 + 244822 248433 8 146364022 + 46838897 46840609 1548241
+52 2949 1051
+100 1 0
+231 55 55
+65 34 34
+124
+
+chain 8619 8_random 943810 + 294534 295111 8 146364022 + 46855606 46856180 1696895
+31 25 25
+71 52 51
+46 97 97
+58 132 130
+65
+
+chain 8428 8_random 943810 + 281982 282213 8 146364022 + 46854328 46854560 448042
+60 97 98
+56 17 17
+1
+
+chain 8419 8_random 943810 + 261190 261281 8 146364022 + 43820969 43821060 10860311
+91
+
+chain 8395 8_random 943810 + 294914 295046 8 146364022 + 46848509 46848640 12873675
+58 69 68
+5
+
+chain 8358 8_random 943810 + 183391 183662 8 146364022 + 46851295 46851565 1204104
+177 39 38
+55
+
+chain 8235 8_random 943810 + 303417 303563 8 146364022 - 99516580 99516725 5721277
+92 1 0
+53
+
+chain 8187 8_random 943810 + 330253 330340 8 146364022 - 99512994 99513081 26147162
+87
+
+chain 7754 8_random 943810 + 175981 176066 8 146364022 - 99524049 99524133 15930227
+61 1 0
+23
+
+chain 7677 8_random 943810 + 237294 312035 8 146364022 - 99517817 99525125 210590
+33 254 254
+156 1 0
+142 25 25
+70 127 127
+226 1925 53
+62 55 55
+112 29 28
+91 36 36
+139 46 43
+7 796 791
+54 65384 1748
+45 3060 1165
+46 839 833
+119 535 529
+77 214 206
+36
+
+chain 7632 8_random 943810 + 192816 192897 8 146364022 + 46850614 46850695 27043702
+81
+
+chain 7605 8_random 943810 + 285785 290878 8 146364022 + 46850643 46851974 486318
+50 2571 689
+13 4 4
+73 73 73
+25 2038 160
+132 56 54
+58
+
+chain 7406 8_random 943810 + 221929 222203 8 146364022 - 99519540 99519813 598559
+62 1 0
+29 134 134
+48
+
+chain 7383 8_random 943810 + 294257 294361 8 146364022 + 43837510 43837614 4128881
+70 9 9
+25
+
+chain 7298 8_random 943810 + 168270 168367 8 146364022 + 46839414 46839508 6543284
+4 56 53
+37
+
+chain 7295 8_random 943810 + 336620 336697 8 146364022 - 99513722 99513799 27625946
+77
+
+chain 7211 8_random 943810 + 261472 261549 8 146364022 + 46839068 46839145 24666501
+77
+
+chain 7186 8_random 943810 + 330047 330123 8 146364022 - 99512791 99512867 27853996
+76
+
+chain 7178 8_random 943810 + 316571 316677 8 146364022 - 102541857 102541963 5712191
+106
+
+chain 7102 8_random 943810 + 318170 320971 8 146364022 - 99520028 99520932 765669
+72 19 19
+135 121 121
+72 13 12
+29 2280 384
+60
+
+chain 7077 8_random 943810 + 192950 193025 8 146364022 + 46850748 46850823 28082919
+75
+
+chain 7057 8_random 943810 + 203108 206189 8 146364022 - 99515093 99516287 1156085
+30 91 89
+53 2333 448
+35 503 503
+36
+
+chain 6980 8_random 943810 + 332337 335152 8 146364022 - 99522544 99523471 1124480
+50 412 409
+6 79 79
+50 126 126
+65 1978 93
+49
+
+chain 6922 8_random 943810 + 183305 183378 8 146364022 + 46840000 46840073 28376594
+73
+
+chain 6904 8_random 943810 + 266355 266429 8 146364022 + 46841714 46841788 28413782
+74
+
+chain 6731 8_random 943810 + 303313 303384 8 146364022 - 99509001 99509072 28774708
+71
+
+chain 6664 8_random 943810 + 303981 314057 8 146364022 - 99517140 99519668 641395
+51 3 2
+55 1 0
+72 170 168
+30 7422 1761
+7 12 11
+54 1882 0
+68 153 153
+96
+
+chain 6603 8_random 943810 + 322619 327380 8 146364022 - 99513231 99513884 1344743
+127 337 0
+120 9 8
+78 1963 78
+31 1885 0
+211
+
+chain 6584 8_random 943810 + 197737 202982 8 146364022 - 102536127 102540259 775939
+91 1155 1137
+22 12 11
+57 3876 2782
+32
+
+chain 6449 8_random 943810 + 218412 233428 8 146364022 - 99516080 99519573 697985
+27 8506 1438
+73 54 54
+91 295 295
+235 28 28
+6 100 100
+56 5516 1061
+29
+
+chain 6331 8_random 943810 + 327023 327090 8 146364022 - 99511661 99511728 29751334
+67
+
+chain 6250 8_random 943810 + 208146 208242 8 146364022 - 99508890 99508983 12204367
+15 70 67
+11
+
+chain 6212 8_random 943810 + 207786 207861 8 146364022 - 99514136 99514211 3829743
+75
+
+chain 6150 8_random 943810 + 203513 205795 8 146364022 - 102537045 102537445 1909663
+16 3 2
+125 118 117
+8 1955 75
+57
+
+chain 6094 8_random 943810 + 299279 299402 8 146364022 - 99508718 99508841 2977078
+68 21 21
+34
+
+chain 6085 8_random 943810 + 250101 250166 8 146364022 + 46842254 46842319 30387783
+65
+
+chain 6067 8_random 943810 + 293889 294038 8 146364022 + 46845620 46845767 4301892
+66 21 19
+62
+
+chain 6049 8_random 943810 + 230044 230135 8 146364022 - 102569888 102569979 10345810
+91
+
+chain 5962 8_random 943810 + 207380 207446 8 146364022 - 99509995 99510061 8394857
+66
+
+chain 5949 8_random 943810 + 272784 272847 8 146364022 + 46853694 46853757 30762472
+63
+
+chain 5823 8_random 943810 + 299452 300023 8 146364022 - 99514497 99515068 1422380
+470 61 61
+40
+
+chain 5814 8_random 943810 + 289476 289952 8 146364022 + 46839369 46839842 2257769
+77 110 110
+124 92 90
+42 1 0
+30
+
+chain 5753 8_random 943810 + 192024 192086 8 146364022 + 46838954 46839016 21955899
+62
+
+chain 5749 8_random 943810 + 233271 233333 8 146364022 - 102570546 102570608 31315232
+62
+
+chain 5681 8_random 943810 + 341821 341883 8 146364022 - 99511396 99511458 7040566
+62
+
+chain 5649 8_random 943810 + 174777 174837 8 146364022 - 99507908 99507968 31588023
+60
+
+chain 5623 8_random 943810 + 175706 175950 8 146364022 - 102534119 102534360 3287579
+59 23 22
+63 22 20
+77
+
+chain 5394 8_random 943810 + 322313 322370 8 146364022 - 99511057 99511114 32316179
+57
+
+chain 5303 8_random 943810 + 187437 187493 8 146364022 + 46840000 46840056 32583273
+56
+
+chain 5285 8_random 943810 + 290446 290502 8 146364022 + 43794807 43794863 32673339
+56
+
+chain 5276 8_random 943810 + 336755 336811 8 146364022 - 99513853 99513909 32693850
+56
+
+chain 5265 8_random 943810 + 208344 208568 8 146364022 - 99514691 99514915 3842595
+38 152 152
+34
+
+chain 5263 8_random 943810 + 587464 592229 8 146364022 + 86573610 86746488 37343
+35 3283 168311
+47 1343 1343
+20 1 3086
+36
+
+chain 5194 8_random 943810 + 184072 184128 8 146364022 + 46838897 46838953 32965865
+56
+
+chain 5184 8_random 943810 + 329855 329911 8 146364022 - 99512600 99512656 19420929
+56
+
+chain 5176 8_random 943810 + 177599 177656 8 146364022 - 99506628 99506685 33029925
+57
+
+chain 5155 8_random 943810 + 281730 289038 8 146364022 + 46843205 46844537 960143
+32 6927 953
+200 103 101
+46
+
+chain 5093 8_random 943810 + 184617 184671 8 146364022 + 43793908 43793962 23494272
+54
+
+chain 5050 8_random 943810 + 326962 327016 8 146364022 - 102542496 102542550 23236949
+54
+
+chain 5030 8_random 943810 + 212164 212217 8 146364022 - 99524079 99524132 33461083
+53
+
+chain 5021 8_random 943810 + 265903 265956 8 146364022 + 46841267 46841320 33516233
+53
+
+chain 5010 8_random 943810 + 325697 333370 8 146364022 - 99519686 99521704 323579
+146 5416 1638
+176 1905 28
+30
+
+chain 4963 8_random 943810 + 195042 195095 8 146364022 - 99525006 99525059 2910708
+53
+
+chain 4923 8_random 943810 + 294759 294811 8 146364022 + 46846486 46846538 24481170
+52
+
+chain 4775 8_random 943810 + 300049 300108 8 146364022 - 99511357 99511416 2287019
+59
+
+chain 4729 8_random 943810 + 323590 341586 8 146364022 - 99508256 99511164 508733
+81 188 186
+45 5653 0
+76 6291 651
+50 2125 222
+31 36 36
+21 50 50
+1 57 52
+62 3121 1237
+18 5 4
+85
+
+chain 4516 8_random 943810 + 291820 291870 8 146364022 + 46839826 46839876 19135311
+50
+
+chain 4460 8_random 943810 + 340307 340812 8 146364022 - 99522970 99523472 2799007
+59 396 393
+50
+
+chain 4363 8_random 943810 + 169662 169718 8 146364022 - 99524410 99524466 15024078
+25 20 20
+11
+
+chain 4245 8_random 943810 + 323934 340633 8 146364022 - 102539490 102542980 824111
+57 5415 1637
+55 4265 507
+46 6509 840
+13 129 125
+132 10 10
+68
+
+chain 4191 8_random 943810 + 346770 346816 8 146364022 - 99523777 99523823 32415009
+46
+
+chain 4157 8_random 943810 + 182640 182685 8 146364022 + 46841541 46841586 34989719
+45
+
+chain 4075 8_random 943810 + 287206 294116 8 146364022 + 46853923 46857394 507901
+58 44 43
+3 6754 3316
+51
+
+chain 4035 8_random 943810 + 210210 231774 8 146364022 - 99509073 99511132 504053
+68 1 0
+87 1 0
+47 151 148
+33 3084 58
+60 3981 215
+31 2075 179
+62 11852 1040
+31
+
+chain 3902 8_random 943810 + 322746 322788 8 146364022 - 99511490 99511532 25070576
+42
+
+chain 3842 8_random 943810 + 326212 339029 8 146364022 - 99518333 99519833 259270
+47 312 308
+17 60 57
+117 12236 926
+28
+
+chain 3793 8_random 943810 + 191943 191984 8 146364022 + 43793349 43793390 19585042
+41
+
+chain 3728 8_random 943810 + 267941 270995 8 146364022 + 46845159 46846318 991534
+57 2323 433
+41 406 402
+51 140 139
+36
+
+chain 3715 8_random 943810 + 252408 255104 8 146364022 + 46840810 46841615 879027
+44 1 0
+30 2575 685
+46
+
+chain 3689 8_random 943810 + 281829 281916 8 146364022 + 46850779 46850864 2001274
+26 3 1
+58
+
+chain 3667 8_random 943810 + 254324 254368 8 146364022 + 46840842 46840884 6647423
+30 11 9
+3
+
+chain 3646 8_random 943810 + 267998 268037 8 146364022 + 46850823 46850862 21797624
+39
+
+chain 3562 8_random 943810 + 168212 168270 8 146364022 + 43793831 43793889 3070871
+58
+
+chain 3504 8_random 943810 + 293480 293517 8 146364022 + 46839611 46839648 25642059
+37
+
+chain 3471 8_random 943810 + 337522 337596 8 146364022 - 99523948 99524022 18137430
+74
+
+chain 3448 8_random 943810 + 276204 276644 8 146364022 + 46854559 46854996 1897606
+49 365 362
+26
+
+chain 3411 8_random 943810 + 253189 255402 8 146364022 + 46850929 46853124 621337
+27 1269 1253
+37 776 774
+2 49 49
+53
+
+chain 3373 8_random 943810 + 338130 338166 8 146364022 - 99513335 99513371 20995505
+36
+
+chain 3359 8_random 943810 + 165298 184945 8 146364022 + 43823972 43836890 282023
+56 2595 8459
+64 12771 2404
+3 8 8
+69 4024 1798
+57
+
+chain 3297 8_random 943810 + 194502 225687 8 146364022 - 102525468 102530377 366001
+70 4347 545
+64 92 91
+87 8182 1452
+36 9798 1128
+56 8421 1348
+32
+
+chain 3286 8_random 943810 + 278118 290566 8 146364022 + 43833036 43837583 504233
+53 11 9
+65 12260 4361
+59
+
+chain 3257 8_random 943810 + 218922 219219 8 146364022 - 99516581 99516875 4722847
+56 32 30
+58 32 31
+119
+
+chain 3241 8_random 943810 + 233589 233706 8 146364022 - 102539417 102539534 832166
+52 16 16
+49
+
+chain 3212 8_random 943810 + 266430 268559 8 146364022 + 46841788 46842035 1348744
+53 1890 10
+128 11 9
+47
+
+chain 3157 8_random 943810 + 327996 328036 8 146364022 - 99512626 99512665 16621225
+16 15 14
+9
+
+chain 3082 8_random 943810 + 310645 310683 8 146364022 - 99512541 99512579 16551162
+38
+
+chain 3062 8_random 943810 + 163933 165245 8 146364022 + 46851641 46852949 942341
+29 1223 1219
+60
+
+chain 3030 8_random 943810 + 262108 262298 8 146364022 + 43831228 43834818 1405601
+67 13 3413
+110
+
+chain 2982 8_random 943810 + 183568 183600 8 146364022 + 46840262 46840294 9991965
+32
+
+chain 2745 8_random 943810 + 335974 336003 8 146364022 - 99513082 99513111 33185960
+29
+
+chain 2672 8_random 943810 + 298503 298547 8 146364022 - 99522900 99522944 24221385
+44
+
+chain 2671 8_random 943810 + 332183 346560 8 146364022 - 102528996 102533910 187401
+51 6123 457
+105 6796 3008
+38 249 246
+57 891 885
+67
+
+chain 2639 8_random 943810 + 219413 219441 8 146364022 - 99507721 99507749 35294427
+28
+
+chain 2612 8_random 943810 + 200816 200846 8 146364022 - 99525102 99525132 4075609
+30
+
+chain 2604 8_random 943810 + 240329 240369 8 146364022 - 99522715 99522755 8959532
+40
+
+chain 2556 8_random 943810 + 216929 216957 8 146364022 - 99514612 99514640 10325210
+28
+
+chain 2552 8_random 943810 + 191384 191411 8 146364022 + 46840185 46840212 15340406
+27
+
+chain 2552 8_random 943810 + 304972 304999 8 146364022 - 99516251 99516278 22571486
+27
+
+chain 2523 8_random 943810 + 327142 327169 8 146364022 - 99524856 99524883 11689776
+27
+
+chain 2451 8_random 943810 + 317909 318170 8 146364022 - 99521638 99521896 1452880
+31 226 223
+4
+
+chain 2447 8_random 943810 + 313295 313321 8 146364022 - 99513300 99513326 34910154
+26
+
+chain 2433 8_random 943810 + 230135 233158 8 146364022 - 99507638 99508095 1270471
+81 73 73
+21 37 37
+40 18 18
+82 2643 77
+28
+
+chain 2394 8_random 943810 + 309803 310102 8 146364022 - 102570308 102570605 11245020
+97 185 183
+17
+
+chain 2370 8_random 943810 + 237880 237905 8 146364022 - 99520270 99520295 11943708
+25
+
+chain 2370 8_random 943810 + 302899 302924 8 146364022 - 99512327 99512352 35222469
+25
+
+chain 2330 8_random 943810 + 274710 274735 8 146364022 + 46843727 46843752 26272760
+25
+
+chain 2188 8_random 943810 + 303139 303300 8 146364022 - 99512566 99512727 1325340
+161
+
+chain 2164 8_random 943810 + 254246 254269 8 146364022 + 46840765 46840788 24904248
+23
+
+chain 2146 8_random 943810 + 166073 166100 8 146364022 + 43793293 43793320 16498497
+27
+
+chain 2129 8_random 943810 + 171463 171506 8 146364022 - 99524332 99524375 3948851
+43
+
+chain 2094 8_random 943810 + 256486 256530 8 146364022 + 46856070 46856114 4878843
+44
+
+chain 2067 8_random 943810 + 182380 182437 8 146364022 + 46850625 46850682 3805032
+57
+
+chain 2054 8_random 943810 + 318711 318733 8 146364022 - 99511225 99511247 10715405
+22
+
+chain 1964 8_random 943810 + 202805 202867 8 146364022 - 99509184 99509246 3143072
+62
+
+chain 1962 8_random 943810 + 187357 187601 8 146364022 + 46841788 46842031 9057308
+62 87 86
+95
+
+chain 1941 8_random 943810 + 278085 278118 8 146364022 + 46854559 46854592 1239137
+33
+
+chain 1922 8_random 943810 + 294361 294534 8 146364022 + 46849827 46850000 1057760
+173
+
+chain 1907 8_random 943810 + 166115 166177 8 146364022 + 46850070 46850132 2756260
+62
+
+chain 1904 8_random 943810 + 294565 294590 8 146364022 + 46846293 46846318 7797359
+25
+
+chain 1899 8_random 943810 + 239038 239062 8 146364022 - 99519559 99519583 3632092
+24
+
+chain 1874 8_random 943810 + 311858 316542 8 146364022 - 99523087 99524010 1127459
+40 4555 794
+89
+
+chain 1842 8_random 943810 + 208242 208344 8 146364022 - 99510852 99510954 1122309
+102
+
+chain 1826 8_random 943810 + 333370 333404 8 146364022 - 102528310 102528344 12860155
+34
+
+chain 1699 8_random 943810 + 189740 189801 8 146364022 + 43830083 43830143 11700756
+13 1 0
+47
+
+chain 1671 8_random 943810 + 586860 586891 8 146364022 - 59596972 59597003 79385
+31
+
+chain 1671 8_random 943810 + 582366 582405 8 146364022 + 86778164 86778203 135745
+39
+
+chain 1614 8_random 943810 + 174855 174917 8 146364022 - 102535142 102535204 7562660
+62
+
+chain 1604 8_random 943810 + 210485 210541 8 146364022 - 99516819 99516875 24689779
+56
+
+chain 1577 8_random 943810 + 165529 165568 8 146364022 + 43833540 43833579 5487018
+39
+
+chain 1529 8_random 943810 + 199844 199893 8 146364022 - 99524132 99524181 16599934
+49
+
+chain 1430 8_random 943810 + 204007 204051 8 146364022 - 102535667 102535711 2444362
+44
+
+chain 1384 8_random 943810 + 331973 334317 8 146364022 - 99510969 99511436 2459541
+88 2124 247
+132
+
+chain 1361 8_random 943810 + 178432 178456 8 146364022 + 43821398 43821422 13532386
+24
+
+chain 1349 8_random 943810 + 282101 282136 8 146364022 + 43834762 43834797 3301014
+35
+
+chain 1325 8_random 943810 + 330748 334904 8 146364022 - 99513486 99513886 3761248
+39 3999 243
+118
+
+chain 1299 8_random 943810 + 216700 216875 8 146364022 - 99512515 99512690 2121346
+175
+
+chain 1278 8_random 943810 + 275077 288204 8 146364022 + 46842223 46845574 199410
+48 13052 3276
+27
+
+chain 1258 8_random 943810 + 272883 272996 8 146364022 + 43835974 43836087 2232086
+113
+
+chain 1256 8_random 943810 + 324880 325008 8 146364022 - 99513272 99513400 5381670
+128
+
+chain 1237 8_random 943810 + 196535 196612 8 146364022 - 99507792 99507869 15310375
+77
+
+chain 1235 8_random 943810 + 284286 284429 8 146364022 + 46839806 46839949 2930992
+143
+
+chain 1191 8_random 943810 + 293574 293786 8 146364022 + 46839704 46839915 1788603
+62 1 0
+149
+
+chain 1161 8_random 943810 + 294116 294212 8 146364022 + 43829899 43829995 1318655
+4 39 39
+53
+
+chain 1160 8_random 943810 + 183897 184027 8 146364022 + 43793197 43793327 2884372
+130
+
+chain 1130 8_random 943810 + 241032 308421 8 146364022 - 102539359 102541234 585349
+125 60736 871
+57 75 74
+53 2150 266
+105 4036 272
+52
+
+chain 1119 8_random 943810 + 229190 229281 8 146364022 - 99508572 99508663 1537143
+73 17 17
+1
+
+chain 1018 8_random 943810 + 315759 315867 8 146364022 - 102570622 102570730 1907772
+108
+
+chain 1013 8_random 943810 + 274298 274330 8 146364022 + 46839580 46839612 3252033
+32
+
+chain 968 8_random 943810 + 209695 209807 8 146364022 - 102537590 102537702 976902
+112
+
+chain 955 8_random 943810 + 319692 319755 8 146364022 - 102541225 102541288 3356813
+63
+
+chain 920 8_random 943810 + 258623 258775 8 146364022 + 46839508 46839659 980562
+59 25 24
+68
+
+chain 912 8_random 943810 + 192332 192490 8 146364022 + 46839260 46839417 3759652
+73 1 0
+84
+
+chain 891 8_random 943810 + 282553 282623 8 146364022 + 46843688 46843758 5243973
+70
+
+chain 873 8_random 943810 + 329911 329999 8 146364022 - 99523866 99523954 8492095
+88
+
+chain 847 8_random 943810 + 202393 202429 8 146364022 - 99516251 99516287 1768031
+36
+
+chain 808 8_random 943810 + 208103 208146 8 146364022 - 99506642 99506685 12166401
+43
+
+chain 772 8_random 943810 + 215530 215581 8 146364022 - 102536642 102536693 4621463
+51
+
+chain 770 8_random 943810 + 298794 298927 8 146364022 - 102529795 102529928 1833110
+38 53 53
+42
+
+chain 762 8_random 943810 + 250305 250368 8 146364022 + 43793197 43793260 2202736
+63
+
+chain 756 8_random 943810 + 175550 175595 8 146364022 - 102569149 102569194 15473865
+45
+
+chain 725 8_random 943810 + 227416 227458 8 146364022 - 102569147 102569189 2128584
+42
+
+chain 715 8_random 943810 + 237975 238010 8 146364022 - 99524101 99524136 9984625
+35
+
+chain 713 8_random 943810 + 336818 336983 8 146364022 - 102542943 102543107 12287033
+51 32 31
+82
+
+chain 659 8_random 943810 + 178382 178432 8 146364022 + 43825088 43825138 1126561
+50
+
+chain 630 8_random 943810 + 343296 343350 8 146364022 - 102532544 102532598 1087222
+54
+
+chain 622 8_random 943810 + 284683 284767 8 146364022 + 46845804 46845888 4299331
+84
+
+chain 618 8_random 943810 + 240201 240253 8 146364022 - 99520719 99520771 5790991
+52
+
+chain 609 8_random 943810 + 323290 333340 8 146364022 - 99511696 99512332 2037608
+32 1962 77
+33 7985 456
+38
+
+chain 511 8_random 943810 + 216312 216456 8 146364022 - 99508390 99508534 2116227
+83 23 23
+38
+
+chain 484 8_random 943810 + 208068 208103 8 146364022 - 102535970 102536005 2214348
+35
+
+chain 473 8_random 943810 + 323389 323449 8 146364022 - 102540821 102540881 1734527
+60
+
+chain 468 8_random 943810 + 200282 202177 8 146364022 - 99515228 99517906 493558
+37 1827 2610
+31
+
+chain 468 8_random 943810 + 309496 309560 8 146364022 - 99509535 99509598 902510
+13 1 0
+50
+
+chain 464 8_random 943810 + 238361 238411 8 146364022 - 102570011 102570061 2549299
+50
+
+chain 406 8_random 943810 + 336390 336452 8 146364022 - 99513496 99513558 3227798
+62
+
+chain 400 8_random 943810 + 198171 198198 8 146364022 - 99524348 99524375 19170252
+27
+
+chain 389 8_random 943810 + 239467 298039 8 146364022 - 99516251 99516834 914933
+36 19 19
+76 58363 374
+78
+
+chain 383 8_random 943810 + 268230 268298 8 146364022 + 43829500 43829568 7647204
+68
+
+chain 371 8_random 943810 + 289553 289594 8 146364022 + 43829105 43829146 1419836
+41
+
+chain 325 8_random 943810 + 171359 194889 8 146364022 - 102534570 102537063 1177879
+33 23458 2421
+39
+
+chain 321 8_random 943810 + 245198 245253 8 146364022 + 46850481 46850536 16403329
+55
+
+chain 316 8_random 943810 + 336558 336619 8 146364022 - 99513661 99513722 9588463
+61
+
+chain 316 8_random 943810 + 215939 215982 8 146364022 - 102570362 102570405 11794790
+43
+
+chain 307 8_random 943810 + 268331 268373 8 146364022 + 46843677 46843719 14936951
+42
+
+chain 302 8_random 943810 + 246654 246683 8 146364022 + 46846317 46846346 2597963
+29
+
+chain 277 8_random 943810 + 330681 336249 8 146364022 - 99513081 99513355 13257215
+37 5476 182
+55
+
+chain 224 8_random 943810 + 233016 233053 8 146364022 - 102535110 102535147 5909193
+37
+
+chain 219 8_random 943810 + 216875 216929 8 146364022 - 99508952 99509006 1250703
+54
+
+chain 217 8_random 943810 + 192086 192136 8 146364022 + 43793491 43793541 12267504
+50
+
+chain 176 8_random 943810 + 230251 230289 8 146364022 - 99522702 99522740 26486914
+38
+
+chain 171 8_random 943810 + 301863 301893 8 146364022 - 99524375 99524405 2607431
+30
+
+chain 128 8_random 943810 + 303580 303689 8 146364022 - 102542031 102542140 1606173
+109
+
+chain 117 8_random 943810 + 213542 213590 8 146364022 - 102569848 102569896 24793283
+48
+
+chain 107 8_random 943810 + 265719 265758 8 146364022 + 43793691 43793730 32387625
+39
+
+chain 103 8_random 943810 + 302985 303114 8 146364022 - 99516149 99516278 2070053
+129
+
+chain 102 8_random 943810 + 266041 266087 8 146364022 + 43794012 43794058 15664471
+46
+
+chain 87 8_random 943810 + 266314 266347 8 146364022 + 46839806 46839839 33038660
+33
+
+chain 11336435868 9 140273252 + 0 140273252 9 141213431 + 10000 141153431 13
+189075 1 1
+14 2 2
+39464594 50000 50000
+261110 50000 50000
+208233 50000 50000
+142805 50000 50000
+464507 50000 50000
+152873 50000 50000
+172579 50000 50000
+799200 0 4
+398958 50000 50000
+549743 50000 100000
+632871 50000 50000
+680077 50000 50000
+181647 50000 50000
+291910 50000 100000
+465318 50000 50000
+350909 50000 50000
+194609 50000 100000
+370335 0 176
+128583 50000 100000
+157546 18100000 18150000
+450681 50000 50000
+223855 50000 50000
+162441 50000 50000
+159539 50000 50000
+199148 50000 50000
+194491 50000 100000
+158462 50000 150000
+471702 50000 150000
+376183 50000 150000
+174765 50000 150000
+289439 50000 50000
+682157 50000 50000
+158187 50000 100000
+187806 50000 50000
+178933 50000 100000
+21507948 50000 100000
+85380 50000 150000
+834971 1 0
+39559293 100000 150000
+3818133 200000 50000
+2075804 30000 50000
+1936434
+
+chain 19053295 9_random 1146434 + 140076 853151 9 141213431 + 43822338 44639038 145
+1110 1 1
+47 1 0
+215 1 0
+468 9 9
+1934 0 1
+953 14319 26012
+970 11 11
+117 1 1
+57 1 1
+127 0 1
+1035 1 1
+123 1 1
+1418 29455 36221
+965 1 1
+33 5 5
+816 1 1
+38 1 1
+87 8 8
+588 6 6
+286 13 13
+967 6 6
+911 125 14857
+67 1 1
+18 1 1
+472 11 11
+269 7 0
+869 1 1
+23 1 1
+240 1 0
+456 1 1
+96 1 1
+247 22 22
+225 1 1
+13 0 4
+40 1 1
+211 13 29
+582 1 1
+22 4 0
+453 1 1
+37 1 1
+251 11 11
+87 1 1
+49 1 1
+95 11 11
+149 1 1
+31 1 1
+205 5 0
+1090 5 5
+89 1 1
+74 14 14
+83 1 1
+51 1 1
+594 1 3
+462 85 85
+635 50621 3293
+88 0 1
+148 18 18
+428 2 0
+5 2 0
+19 0 1
+43 1 1
+529 1 6
+77 1 1
+31 1 1
+39 0 5
+124 15 15
+51 1 1
+80 1 1
+103 1 1
+77 1 1
+147 1 1
+72 1 1
+95 10 10
+657 1 1
+57 1 1
+69 1 1
+32 1 1
+587 4 4
+298 14 14
+1505 10 8
+560 0 4
+171 1 1
+44 1 1
+211 1 1
+22 1 1
+649 1 1
+42 0 2
+96 8 8
+45 1 0
+195 402195 519766
+38949 0 176
+45847 1 0
+46124 1 0
+3889 0 1
+52224
+
+chain 10363290 9_random 1146434 + 903151 1075657 GL000199.1 169874 + 0 130000 308
+35955 882 0
+20 1020 0
+32 3062 0
+106 14 15
+100 9 7
+334 16 18
+121 1 0
+84 3469 73
+179 1193 0
+255 3064 0
+235 844 167
+325 2720 0
+211 25 25
+216 3639 67
+100 681 1
+58 5271 0
+71 36 36
+155 11817 855
+1017 1 0
+10599 1 1
+42 0 1
+8519 112 112
+9882 0 680
+263 8 8
+56 30 30
+206 865 183
+1131 1 0
+12309 16295 0
+37 2637 0
+463 15 15
+739 1 1
+64 1 1
+2323 1 0
+743 202 202
+245 2 0
+10307 33 32
+8496 15 15
+1065 3 3
+49 1 1
+67 1 1
+24 1 1
+150 15 15
+81 1112 7412
+104 5 5
+160 48 48
+156 31 31
+109 29 29
+32 0 337
+118 36 36
+108 21 21
+69 163 165
+105 29 29
+255 32 32
+176 46 46
+97 54 54
+158 110 5213
+54 5 5
+61 1 0
+12 66 578
+49 0 1
+256 0 1
+5 1 0
+110 0 507
+39 59 227
+44 1 0
+5 1 2
+13 268 611
+32 340 0
+2169 5 5
+109
+
+chain 8496666 9_random 1146434 + 526031 616031 GL000198.1 90085 + 0 90000 391
+90000
+
+chain 3482851 9_random 1146434 + 0 36148 GL000201.1 36148 + 0 36148 837
+36148
+
+chain 3114479 9_random 1146434 + 350153 383343 7 159138663 + 58020084 58054331 923
+5741 0 1
+5176 1 1
+36 1 1
+8401 0 3
+180 1 0
+1283 1 371
+2015 11 695
+10343
+
+chain 2652717 9_random 1146434 + 939453 971857 GL000199.1 169874 + 50544 169869 966
+78 104 103
+57 43 43
+41 0 1193
+212 20 20
+112 51 51
+93 1 0
+763 32 32
+929 0 85729
+2133 785 785
+1551 1 1
+38 0 1
+29 1 1
+1849 179 179
+1081 14 14
+98 255 255
+3064 235 235
+844 325 325
+2000 1 1
+55 1 1
+663 211 211
+25 216 216
+3639 100 100
+681 58 58
+5271 71 71
+36 155 155
+4203
+
+chain 864673 9_random 1146434 + 1126594 1146123 9 141213431 - 1097613 1113419 4959
+1953 6 5
+978 2409 6373
+1991 1 1
+30 1 1
+1102 7741 55
+57 1 1
+3259
+
+chain 850211 9_random 1146434 + 1025598 1042157 GL000199.1 169874 + 85137 125159 1202
+223 15 15
+69 106 782
+56 4 4
+103 0 1190
+57 51 51
+154 11 11
+103 0 1190
+303 94 5704
+122 20 700
+283 11 11
+564 0 6798
+68 31 31
+85 0 1
+80 48 48
+422 49 50
+604 27 3091
+147 0 4594
+563 468 470
+104 1 1
+65 1 1
+786 1 1
+26 4 4
+3436 346 0
+2356 158 158
+2985 37 37
+170 167 170
+910 11 11
+54
+
+chain 769263 9_random 1146434 + 86461 232520 9 141213431 + 40031497 40507253 306
+1287 1 1
+39 9090 8469
+1482 3 0
+72 22972 39210
+845 1 5
+1628 100 33581
+19 1 1
+708 1 1
+40 1 1
+1672 2596 163229
+3012 1 1
+27 1 0
+759 0 1
+98 72164 49914
+85 17764 159979
+3474 1 1
+50 1 1
+6064
+
+chain 759449 9_random 1146434 + 205961 214049 9 141213431 + 40301888 40309971 6546
+2149 0 1
+2715 38 32
+3186
+
+chain 584316 9_random 1146434 + 1135427 1141773 9 141213431 + 140095418 140108346 9081
+578 0 1
+958 0 1
+3002 120 6700
+1688
+
+chain 406492 9_random 1146434 + 174973 187473 9 141213431 - 97329171 97382324 1352
+1045 1 0
+610 3 3
+25 1 1
+707 0 1
+949 1 0
+476 1 1
+37 0 2
+115 22 0
+99 2 0
+19 0 1
+85 84 84
+391 0 2
+2020 102 40820
+178 0 5
+70 1 1
+108 1 0
+1683 56 22
+203 4 0
+53 0 3
+1920 1 0
+25 15 0
+171 0 4
+991 1 0
+102 1 1
+39 1 0
+81
+
+chain 392431 9_random 1146434 + 102229 150933 9 141213431 - 100800050 101111299 1649
+1200 31 31
+61 100 87
+1550 13066 115954
+174 1 7
+2845 28138 189099
+40 1462 165
+36
+
+chain 384690 9_random 1146434 + 98535 256322 9 141213431 - 100787713 101169878 613
+1160 1 0
+743 100 2055
+1590 33793 2374
+3943 1 0
+110 10986 2654
+28 3892 11
+65 38 37
+101 8010 603
+1627 0 1
+4154 127 18597
+1903 17 17
+1098 1 0
+907 16 6
+635 1 0
+110 11 10
+1170 39276 55950
+254 1 1
+16 1 1
+222 1 1
+23 0 3
+11 1 1
+963 0 1
+1311 1 1
+22 1 1
+1083 0 2
+4770 9790 219711
+142 1 1
+35 1 1
+191 1 1
+48 1 1
+4295 1 0
+1323 1 1
+26 1 0
+2991 1 0
+1653 100 28511
+184 1 1
+25 1 1
+2332 2 0
+2424 1 1
+18 1 1
+1612 0 2
+1973 2 0
+4314
+
+chain 222862 9_random 1146434 + 974475 976909 GL000199.1 169874 - 29206 35723 496317
+103 0 512
+103 0 2379
+1951 0 1192
+277
+
+chain 216950 9_random 1146434 + 179171 191499 9 141213431 - 75591738 75613431 4354
+84 8327 17685
+315 1 1
+43 1 1
+565 1 1
+45 1 1
+144 1 1
+47 3 3
+216 4 8
+856 15 15
+173 1 1
+23 0 1
+306 1 1
+34 1 2
+855 1 1
+41 1 1
+59 0 1
+60 1 1
+46 1 1
+55
+
+chain 213582 9_random 1146434 + 1129631 1131840 9 141213431 - 1091833 1094042 537694
+2209
+
+chain 165378 9_random 1146434 + 971957 973731 X 155270560 + 21244335 21246110 770883
+1088 0 1
+111 1 1
+46 3 3
+525
+
+chain 132596 9_random 1146434 + 92033 271291 9 141213431 - 75460140 75627580 890
+687 15 5
+714 42447 12782
+26 11947 6649
+27 11 12
+38 1490 2
+104 2 0
+98 117515 142147
+548 14 14
+760 1 1
+15 5 5
+244 0 8
+225 1 1
+25 1 1
+184 1 1
+24 1 1
+112 1 1
+49 1 1
+657 0 4
+26 1 1
+142 1 1
+117 1 1
+521 1 1
+30 1 1
+427
+
+chain 126182 9_random 1146434 + 264182 265594 9 141213431 + 41417376 41418784 8289
+408 11 11
+453 3 0
+470 1 0
+66
+
+chain 121265 9_random 1146434 + 153981 183865 9 141213431 + 40369543 40485128 5651
+820 1 0
+80 65 65
+38 101 101
+1814 1 1
+19 1 1
+2113 24775 110477
+56
+
+chain 112452 9_random 1146434 + 977951 979143 9 141213431 + 41554070 41555262 1142654
+1192
+
+chain 111666 9_random 1146434 + 115028 116206 9 141213431 + 38976673 38977851 1144814
+1178
+
+chain 91839 9_random 1146434 + 95026 96000 9 141213431 - 97340505 97341479 1389514
+974
+
+chain 86695 9_random 1146434 + 89274 94894 9 141213431 + 40421854 40482922 755289
+656 0 1
+294 1 0
+357 1 1
+58 1 1
+181 2726 58174
+1345
+
+chain 85848 9_random 1146434 + 116324 118085 9 141213431 + 40126032 40127795 187229
+1300 0 2
+247 1 1
+31 1 1
+181
+
+chain 83527 9_random 1146434 + 105271 111078 9 141213431 + 43838264 43842306 8535
+1025 1 1
+44 1 1
+374 2077 318
+609 3 0
+643 18 19
+121 15 16
+135 5 0
+736
+
+chain 82351 9_random 1146434 + 265594 267154 9 141213431 - 97363431 97364991 1727
+341 2 2
+20 1 1
+738 1 1
+34 1 1
+206 1 1
+40 1 1
+174
+
+chain 74906 9_random 1146434 + 107880 108681 9 141213431 + 40288016 40288817 1344818
+46 1 0
+553 0 1
+201
+
+chain 73427 9_random 1146434 + 106816 115028 9 141213431 - 93902441 93905998 1707
+229 0 1
+500 19 19
+145 5760 1098
+49 0 1
+9 0 1
+188 1 1
+43 1 1
+243 1 1
+41 1 1
+206 1 1
+25 1 1
+443 0 1
+171 0 3
+135
+
+chain 72594 9_random 1146434 + 977068 977842 9 141213431 - 99740263 99741035 1743552
+651 1 0
+45 1 0
+76
+
+chain 68316 9_random 1146434 + 87923 91873 9 141213431 - 101134923 101183249 1049825
+372 0 1
+115 1 1
+37 1 1
+725 1749 46124
+950
+
+chain 61838 9_random 1146434 + 1042331 1042988 GL000199.1 169874 - 40496 41153 2045151
+657
+
+chain 55013 9_random 1146434 + 1075993 1076574 2 243199373 - 242829160 242829741 2308873
+581
+
+chain 54512 9_random 1146434 + 144930 149178 9 141213431 - 75605255 75609502 8620
+250 1 1
+26 1 1
+262 14 19
+1397 10 9
+876 1 0
+98 79 75
+65 1 1
+772 1 1
+31 1 1
+235 1 1
+74 1 1
+51
+
+chain 52053 9_random 1146434 + 149316 153855 9 141213431 + 40375457 40380000 99648
+79 244 244
+76 2437 2440
+75 10 10
+247 0 1
+19 1304 1304
+48
+
+chain 51431 9_random 1146434 + 126523 128919 9 141213431 - 101152632 101155028 6098
+2396
+
+chain 48062 9_random 1146434 + 390785 391322 5 180915260 - 163073999 163074536 2667488
+241 1 1
+201 3 3
+91
+
+chain 43629 9_random 1146434 + 1073062 1075987 GL000199.1 169874 + 35053 37976 298767
+312 2456 2456
+1 2 0
+78 21 21
+55
+
+chain 37453 9_random 1146434 + 1024767 1030521 GL000199.1 169874 + 88172 123905 8301
+52 0 3738
+40 1994 12406
+94 1068 11110
+31 165 2038
+48 1933 5847
+329
+
+chain 33524 9_random 1146434 + 133017 135796 9 141213431 + 39163384 39166153 115831
+53 1 1
+307 5 4
+44 1 1
+406 1 1
+21 5 0
+43 1 1
+177 1 1
+25 1 0
+31 1 1
+137 5 5
+20 1 1
+52 1 1
+27 1 1
+233 1 1
+20 1 1
+394 3 0
+363 1 1
+24 1 1
+370
+
+chain 29196 9_random 1146434 + 343146 344485 3 198022430 + 156000638 156001989 5034584
+50 1 0
+56 1 1
+104 128 140
+64 838 839
+97
+
+chain 28265 9_random 1146434 + 96095 96747 9 141213431 - 93903474 93904131 1828707
+74 0 10
+511 4 0
+47 1 0
+15
+
+chain 26156 9_random 1146434 + 111189 113362 9 141213431 - 102220148 102222323 47568
+1400 0 1
+94 5 6
+674
+
+chain 25868 9_random 1146434 + 149715 153807 9 141213431 - 93950637 93954729 91748
+181 1 1
+57 1 1
+353 15 15
+330 1 0
+22 1 1
+220 93 93
+114 0 17
+104 9 9
+290 2 0
+293 1 1
+20 1 1
+328 351 343
+127 1 1
+76 1 1
+331 4 0
+52 1 1
+17 1 1
+106 5 0
+146 1 1
+38 0 3
+7 1 0
+116 3 3
+16 1 1
+168 0 1
+85
+
+chain 25003 9_random 1146434 + 1069304 1075830 GL000199.1 169874 + 56286 59580 21268
+305 7 7
+77 487 487
+25 288 288
+36 198 198
+163 105 105
+29 463 463
+46 1256 67
+82 36 36
+95 32 32
+28 2595 552
+103 9 9
+61
+
+chain 23281 9_random 1146434 + 1028681 1035309 GL000199.1 169874 + 97567 114227 7110
+30 1360 6799
+121 342 0
+5 4424 9363
+103 237 233
+6
+
+chain 21805 9_random 1146434 + 1135081 1135321 9 141213431 + 140101239 140101479 9135145
+197 1 1
+42
+
+chain 21533 9_random 1146434 + 1010735 1043373 GL000199.1 169874 + 61213 69988 6310
+337 14018 4703
+439 42 42
+27 307 307
+106 220 220
+51 16938 2390
+153
+
+chain 19014 9_random 1146434 + 335566 335883 16 90354753 - 56512811 56513131 11268597
+170 97 100
+50
+
+chain 18803 9_random 1146434 + 86148 86348 9 141213431 - 100705477 100705677 11441237
+200
+
+chain 13349 9_random 1146434 + 1068589 1070018 GL000199.1 169874 + 79052 79803 7749
+23 14 14
+253 37 37
+60 717 39
+8 269 269
+48
+
+chain 13149 9_random 1146434 + 410938 411078 8 146364022 + 38639711 38639851 17290853
+140
+
+chain 12972 9_random 1146434 + 332343 332481 7 159138663 + 61759398 61759536 17535033
+138
+
+chain 12821 9_random 1146434 + 388858 389014 15 102531392 + 80798356 80798512 17757829
+81 12 12
+63
+
+chain 11442 9_random 1146434 + 388166 388417 12 133851895 + 34836761 34837526 19956621
+81 109 623
+61
+
+chain 11149 9_random 1146434 + 343358 343713 3 198022430 - 62479553 62479920 5356830
+1 103 115
+24 134 134
+93
+
+chain 11085 9_random 1146434 + 468603 468722 9 141213431 + 42720405 42720524 20596057
+119
+
+chain 9550 9_random 1146434 + 389696 390760 X 155270560 + 61752907 61753125 23891795
+65 939 93
+60
+
+chain 9178 9_random 1146434 + 345818 345932 16 90354753 + 32819577 32819691 24666411
+52 7 7
+55
+
+chain 9128 9_random 1146434 + 321692 322933 7 159138663 + 61799163 61799701 24755828
+61 1115 412
+65
+
+chain 9086 9_random 1146434 + 338884 339289 16 90354753 + 32789437 32789842 24819157
+53 289 289
+63
+
+chain 9023 9_random 1146434 + 387021 388166 7 159138663 + 61404533 61405164 23790101
+52 1085 571
+8
+
+chain 7872 9_random 1146434 + 1069035 1072121 GL000199.1 169874 + 119465 157584 536281
+72 46 46
+97 2835 37868
+36
+
+chain 7579 9_random 1146434 + 402601 403961 3 198022430 - 107545066 107546932 27123369
+31 1026 0
+52 201 1733
+50
+
+chain 7458 9_random 1146434 + 343360 343449 6 171115067 + 69499143 69499232 6836024
+89
+
+chain 6713 9_random 1146434 + 425056 425127 16 90354753 + 46455806 46455877 28826250
+71
+
+chain 6541 9_random 1146434 + 468921 468991 7 159138663 + 61361207 61361277 29216706
+70
+
+chain 6486 9_random 1146434 + 330636 330705 10 135534747 + 42383267 42383336 29375264
+69
+
+chain 6456 9_random 1146434 + 411427 412083 11 135006516 + 48877623 48879132 29439180
+48 554 1407
+54
+
+chain 6295 9_random 1146434 + 404771 404838 8 146364022 + 43770407 43770474 29850106
+67
+
+chain 6049 9_random 1146434 + 414120 414184 7 159138663 - 101095351 101095415 30492982
+64
+
+chain 6040 9_random 1146434 + 465963 466027 6 171115067 + 83274875 83274939 30512451
+64
+
+chain 5969 9_random 1146434 + 389015 389089 Y 59373566 - 43064540 43064609 20514560
+61 5 0
+8
+
+chain 5636 9_random 1146434 + 406636 407740 8 146364022 + 43770397 43770476 31630565
+28 1025 0
+51
+
+chain 5631 9_random 1146434 + 426803 426863 10 135534747 + 42387748 42387808 31636152
+60
+
+chain 5540 9_random 1146434 + 419067 419126 7 159138663 + 61079182 61079241 31906304
+59
+
+chain 5476 9_random 1146434 + 398987 399045 12 133851895 + 34839855 34839913 32105830
+58
+
+chain 5376 9_random 1146434 + 415322 415379 11 135006516 - 86268315 86268372 32415872
+57
+
+chain 5358 9_random 1146434 + 413960 414017 Y 59373566 - 49305277 49305334 32458256
+57
+
+chain 5349 9_random 1146434 + 411179 411236 7 159138663 + 91218545 91218602 32466470
+57
+
+chain 5349 9_random 1146434 + 417041 417098 11 135006516 - 84295010 84295067 32466776
+57
+
+chain 5305 9_random 1146434 + 979284 979471 GL000199.1 169874 + 100510 100697 1541
+187
+
+chain 5294 9_random 1146434 + 393589 393645 GL000208.1 92689 - 78786 78842 32648958
+56
+
+chain 5285 9_random 1146434 + 407829 407885 16 90354753 + 34022252 34022308 32672407
+56
+
+chain 5248 9_random 1146434 + 345095 345150 3 198022430 + 72765342 72765397 32777800
+55
+
+chain 5194 9_random 1146434 + 325928 325983 16 90354753 + 46454212 46454267 32965981
+55
+
+chain 5076 9_random 1146434 + 385523 385577 9 141213431 - 74211269 74211323 33342253
+54
+
+chain 5012 9_random 1146434 + 398477 398530 3 198022430 - 107545544 107545597 33565319
+53
+
+chain 4985 9_random 1146434 + 417987 418040 8 146364022 + 43776134 43776187 33649135
+53
+
+chain 4821 9_random 1146434 + 397137 397188 X 155270560 + 61817502 61817553 34214385
+51
+
+chain 4794 9_random 1146434 + 414576 414627 11 135006516 + 50778923 50778974 34325073
+51
+
+chain 4794 9_random 1146434 + 397714 397765 GL000208.1 92689 - 71810 71861 34325191
+51
+
+chain 4730 9_random 1146434 + 411917 411967 21 48129895 - 33764186 33764236 34527656
+50
+
+chain 4709 9_random 1146434 + 107713 107880 9 141213431 + 40326898 40327067 460940
+64 0 2
+103
+
+chain 4703 9_random 1146434 + 396620 396670 11 135006516 + 50701175 50701225 34648839
+50
+
+chain 4594 9_random 1146434 + 460317 460366 1 249250621 + 72586197 72586246 34758860
+49
+
+chain 4154 9_random 1146434 + 389765 389825 X 155270560 + 61859291 61859351 24051909
+60
+
+chain 4125 9_random 1146434 + 1047887 1048034 GL000199.1 169874 + 145761 145908 266403
+21 18 18
+108
+
+chain 4032 9_random 1146434 + 1010207 1010501 GL000199.1 169874 + 46738 47032 105345
+133 51 51
+110
+
+chain 3744 9_random 1146434 + 974418 974475 GL000199.1 169874 - 111819 111876 792102
+57
+
+chain 3426 9_random 1146434 + 939387 939437 GL000199.1 169874 + 161370 161420 23133078
+50
+
+chain 3397 9_random 1146434 + 1069115 1069304 GL000199.1 169874 + 57287 57476 721888
+38 97 97
+54
+
+chain 3297 9_random 1146434 + 1037665 1037723 GL000199.1 169874 + 108413 108471 1099981
+5 32 32
+21
+
+chain 2900 9_random 1146434 + 210827 210859 9 141213431 + 43889710 43889742 6957
+32
+
+chain 2688 9_random 1146434 + 1042157 1042279 GL000199.1 169874 + 112227 112349 8300
+65 9 9
+48
+
+chain 2652 9_random 1146434 + 999650 1043482 GL000199.1 169874 + 41812 46278 8409
+112 43376 4009
+54 0 1
+28 153 153
+109
+
+chain 2438 9_random 1146434 + 1025529 1025571 GL000199.1 169874 + 134052 134094 269933
+42
+
+chain 2404 9_random 1146434 + 153855 153881 9 141213431 + 40071265 40071291 103174
+26
+
+chain 2298 9_random 1146434 + 1010672 1010735 GL000199.1 169874 + 66766 66829 8935
+63
+
+chain 2164 9_random 1146434 + 1010368 1010391 9 141213431 - 71502272 71502295 32168220
+23
+
+chain 2160 9_random 1146434 + 388789 388840 7 159138663 - 101569537 101569588 23945255
+51
+
+chain 2026 9_random 1146434 + 343746 343819 10 135534747 + 18324071 18324144 14357746
+73
+
+chain 1834 9_random 1146434 + 1010501 1010672 GL000199.1 169874 + 60299 60470 7461
+171
+
+chain 1808 9_random 1146434 + 391322 391360 7 159138663 - 47529927 47529965 6263864
+38
+
+chain 1777 9_random 1146434 + 343550 344817 22 51304566 + 35077657 35078810 5733588
+48 1167 1053
+52
+
+chain 1529 9_random 1146434 + 263922 264091 9 141213431 + 65673675 65673833 515
+62 10 0
+17 1 0
+14 2 2
+63
+
+chain 1325 9_random 1146434 + 1037723 1037780 GL000199.1 169874 + 96057 96114 245438
+57
+
+chain 1237 9_random 1146434 + 1024624 1024767 GL000199.1 169874 + 49580 49723 8604
+143
+
+chain 1217 9_random 1146434 + 1071842 1072151 GL000199.1 169874 + 48108 48417 165690
+30 6 6
+74 169 169
+30
+
+chain 897 9_random 1146434 + 1035274 1035303 GL000199.1 169874 + 108574 108603 711169
+29
+
+chain 881 9_random 1146434 + 345308 345393 X 155270560 - 77826120 77826205 8910963
+85
+
+chain 812 9_random 1146434 + 344331 344387 9 141213431 + 18649465 18649521 20542621
+56
+
+chain 538 9_random 1146434 + 1029334 1029359 GL000199.1 169874 + 75943 75968 9317
+25
+
+chain 480 9_random 1146434 + 344828 344880 4 191154276 - 62643619 62643671 15050009
+52
+
+chain 461 9_random 1146434 + 96747 96777 9 141213431 + 38980922 38980952 1279
+30
+
+chain 364 9_random 1146434 + 1025018 1025062 GL000199.1 169874 + 64308 64352 115390
+44
+
+chain 296 9_random 1146434 + 1009971 1010001 GL000199.1 169874 + 44634 44664 18919
+30
+
+chain 288 9_random 1146434 + 974120 974172 GL000199.1 169874 + 44920 44972 1936043
+52
+
+chain 260 9_random 1146434 + 394227 394279 11 135006516 + 50701175 50701227 28339537
+52
+
+chain 210 9_random 1146434 + 1025062 1025090 GL000199.1 169874 + 71670 71699 216729
+6 0 1
+22
+
+chain 209 9_random 1146434 + 388033 388083 11 135006516 - 84294197 84294247 27927923
+50
+
+chain 152 9_random 1146434 + 393023 393074 20 63025520 + 26259164 26259215 28112557
+51
+
+chain 86 9_random 1146434 + 405210 405252 3 198022430 - 107550280 107550322 32195393
+42
+
+chain 79 9_random 1146434 + 392892 392941 11 135006516 + 50661000 50661049 27948217
+49
+
+chain 14267288654 X 154913754 + 0 154913754 X 155270560 + 60000 155260560 8
+34821 50000 50000
+86563 30000 50000
+766173 50000 50000
+36556 50000 50000
+80121 90000 50000
+754004 100000 50000
+5505644 0 50000
+3064785 0 50079
+26309510 25000 50000
+201175 0 8
+7417 2 0
+53136 0 8
+3076 12 0
+21092 2 0
+60831 0 2
+57728 20 0
+54336 1 0
+31676 4 0
+9986 0 4
+12109 4 0
+11227342 2000 0
+354815 50000 50000
+77401 1 1
+17 1 1
+94 3 0
+266 10 10
+113 1 1
+21 1 1
+5401 5 0
+4970 2 0
+33 6 0
+3221 1 5
+6456 0 1
+1476 5 5
+2100 1 1
+40 1 1
+1316 1 0
+2446 0 1
+1589 17 15
+11171 0 1
+2639 0 1
+5190 4 0
+78 0 8
+5087 1 0
+2663 0 1
+9149 8 7
+1851 1 0
+9081 1 0
+7249 0 25
+199 2 0
+12 2 0
+16 0 209
+37 0 20
+2536 1 0
+1394 6 0
+12550 42 0
+821 0 4
+30579 0 1
+3710 0 4
+3638 0 1
+11945 1 0
+20204 1 0
+4171 0 8
+5680 0 1
+23827 2 0
+54817 1 0
+657 1 0
+342931 180000 50000
+2052068 1 27
+5375 0 2
+46 2 0
+6489 1 0
+7175 0 2
+1239 0 2
+4302 4 0
+27253 1 0
+4244 2 0
+717 2 0
+261 6 0
+26074 0 1
+236464 50000 50000
+6136098 3000000 3100000
+13518993 0 1
+449 0 1
+4533 0 4
+757 0 1
+1102 25 26
+107 0 2
+3470 1 0
+1108 0 1
+4775 0 1
+8628 1 1
+46 1 1
+1072 1 1
+44 1 1
+292 5 4
+9091 4 4
+2218 4 4
+705 1 5
+452 1 0
+88 32 32
+212 1 0
+1801 1 7
+3960 0 1
+2007 0 1
+1979 38 38
+1320 0 1
+2093 0 1
+403 0 310
+6134 1 1
+36 1 1
+1697 0 1
+97 0 13
+7624 1 1
+19 1 1
+6933 0 1
+779 7 7
+721 1 1
+43 1 1
+1626 1 0
+6146 2 0
+150 1 1
+47 1 1
+2172 2 0
+398 1 1
+31 1 1
+1149 2 2
+183 16 16
+1663 1 1
+18 1 1
+2105 10 11
+1409 1 1
+33 1 1
+1753 0 1
+408 1 0
+1916 0 1
+477 37 37
+1415 12 0
+3799 17 17
+2921 1 0
+1811 33 33
+2753 2 0
+486 0 6
+1388 1 1
+44 1 1
+186 1 1
+46 1 1
+3037 1 0
+2301 3 0
+3876 1 1
+22 1 1
+1724 0 1
+3733 0 1
+627 0 1
+250 1 0
+194 1 1
+26 1 1
+20797 10 10
+2445 1 0
+1733 0 2
+1001 12 0
+4394 9 9
+4052 10 9
+670 1 1
+97 6 0
+25 1486 1188
+10 3 2
+28 41 41
+28 2 3
+10 126 1058
+11 1051 417
+25 0 6
+18 1 1
+62 17 17
+77 0 1
+1009 41 41
+3899 10 10
+4690 0 1
+7343 1 0
+1248 1 0
+1259 1 0
+1345 0 4
+1534 1 0
+3797 16 16
+807 1 0
+2427 1 0
+48 0 1
+287 1 0
+611353 0 1
+1041 6 0
+371 0 1
+227 0 1
+2806 1 0
+36 1 1
+234 1 1
+23 1 1
+584 1 0
+22241 1 1
+65 1 1
+4605 0 1
+2326 0 20
+2130 0 1
+6170 9 13
+10665 0 1
+14631 1 0
+5359 4 0
+4004 1 0
+3182 11 0
+3897 14 16
+2551 1 0
+1824 1 0
+5274 1 1
+41 1 1
+4309 0 1
+3827 0 1
+4594 0 1
+65 1 1
+1170 1 1
+42 4 4
+214 0 1
+5228 0 1
+553 1 0
+5528 7 7
+735 14 14
+2861 1 0
+156 0 2
+6183 42 42
+2595 1 1
+41 1 1
+472 1 1
+65 0 1
+8 1 1
+1162 1 0
+565 1 1
+48 1 1
+536 2 1
+766 0 2
+4520 0 1
+1574 1 0
+503 0 1
+2558 0 1
+250061 7 7
+9650 18 18
+3208 1 1
+25 0 1
+744 2 0
+2994 1 1
+33 1 1
+1331 1 0
+2042 6 17
+1292 1 1
+35 1 1
+2485 1 1
+35 1 1
+17284 1 0
+7 7 1
+670 0 4
+429 0 1
+4736 1 0
+3849 0 1
+6745 16 16
+2344 1 1
+41 1 1
+4459 9 9
+3449 0 1
+3876 1 1
+75 1 1
+1429 7 7
+11126 26 26
+781 1 1
+28 1 1
+409 12 13
+1223 12 12
+5354 0 1
+1255 0 6
+851 65 65
+126 1 1
+47 5 5
+5931 4 0
+420 0 1
+2949 0 6
+193 324 324
+6740 1 3
+1074 1 0
+2465 1 1
+40 1 1
+640 2 0
+550 1 1
+32 1 1
+4096 1 1
+29 1 1
+949 6 6
+6258 1 0
+3957 1 0
+19608 1 1
+48 1 1
+234 0 1
+13246 13 13
+4651 321 0
+2617 1 0
+4553 0 3
+491 0 6
+7496 1 1
+9 0 10
+77 0 4
+3314 1 1
+32 1 1
+5217 1 0
+1500 17 17
+2023 1 0
+2425 0 18
+3110 8 8
+3248 1 0
+1946 1 1
+48 1 1
+9620 0 2
+31242 20000 50000
+36075685 3 0
+36004 1 1
+27 1 1
+5196 0 1
+293 0 2
+13307 0 3
+2420 6 0
+1863 0 2
+2911 0 1
+3233 2 0
+66 1 0
+2376 10 0
+4893 1 0
+745 1 0
+3897 0 13
+3835 1 1
+55 1 1
+538 1 1
+48 4 1
+20 0 2
+279 0 2
+33 1 1
+48 1 0
+387 8 8
+692 0 1
+375 3 0
+383 1 1
+18 1 1
+1289 1 1
+29 1 1
+12332 0 331
+856 4 0
+48 0 4
+8716 0 5
+130 2 0
+3001 0 1
+1332 8 5
+23273 0 1
+30174 27 39
+337 0 3
+2838 1 0
+1614 0 9
+313 0 1
+83 4 0
+172 1 1
+25 1 1
+4912 0 39
+1863 0 1
+2931 1 0
+3134 0 3
+390880 0 1
+7199 1 0
+305 2 0
+1811 2 0
+5449 0 3
+7443 0 2
+2171 1 1
+27 1 1
+2668 0 2
+2180 0 1
+1170 0 9
+1450 16 16
+3080 1 0
+920 18 18
+10219 1 0
+678 1 1
+28 1 1
+698 1 0
+112 1 0
+1831 3 0
+14327 2 0
+2087 10 10
+150 0 3
+380 1 1
+28 1 1
+1265 19 21
+7184 3 2
+4225 9 14
+1002 0 1
+3855 4 0
+2534 1 1
+30 1 1
+794 1 0
+25 1 1
+76140 70000 50000
+1432750 4799 0
+8 2973 0
+681864 20000 50000
+4278742 0 56347
+12021233 9 9
+1775 1 0
+1468 1 1
+51 16 14
+6 0 1
+6 0 1
+11 4 5
+7 0 1
+4 0 1
+75 1 2
+26 1 0
+16 0 1
+9 0 1
+19 0 2
+22 1 0
+9 0 1
+5 1 3
+14 6 7
+38 1 0
+26 1 1
+62 0 1
+38 1 1
+1687 0 1
+54 0 1
+8528 0 1
+2722 0 1
+6240 0 1
+33 0 1
+121285 1 0
+6 0 1
+35 1 0
+1381 0 1
+5368 1 0
+3079 0 1
+10863441 0 4
+1799 1 1
+24 1 1
+334 1 0
+4960 17 0
+1160 1 1
+34 1 1
+6153 3 0
+1346 4 0
+103 4 0
+2835 12 12
+304 0 16
+719 0 1
+3286 1 0
+10182 0 9
+804 1 1
+28 1 1
+749 0 1
+3387 1 1
+47 1 1
+482 0 1
+455 15 15
+719 1 1
+18 1 1
+2074 0 1
+1348 0 4
+3928 1 1
+18 1 1
+907 0 1
+2972 2 0
+115 1 1
+37 1 1
+4428 1 0
+1120 1 0
+4055 5 0
+2753 18 18
+158 3 0
+3590 1 1
+47 1 1
+62 1 0
+947 1 1
+45 1 1
+1639 1 1
+32 1 1
+1076 0 1
+3996 4 0
+7965 1 0
+1733 1 0
+1451 0 2
+617 1 0
+4375 0 1
+2194 64 63
+301 1 1
+27 1 1
+6661 1 1
+79 1 1
+1495 1 0
+499 1 1
+37 2 2
+968 1 0
+34 1 1
+6337 1 1
+18 1 1
+8162 1 1
+22 5 0
+9274 1 0
+6017 5 5
+3872 8 0
+5421 1 0
+532 6 7
+5673 0 4
+1542 4 0
+890 3 1
+2561 1 0
+1692 1 0
+1142 1 1
+32 1 1
+503 2 1
+123 1 1
+75 1 1
+2322 1 0
+201 1 0
+40 3 3
+149 3 0
+1441 1 1
+40 1 1
+159 2 0
+1278 1 1
+33 1 1
+221 0 1
+31 1 1
+161 9 10
+1890 0 1
+132 1 1
+37 1 1
+514 17 23
+1373 4 0
+907 1 1
+15 1 1
+714 1 1
+18 0 1
+10 1 1
+55 1 1
+24 1 1
+1038 2 0
+95 1 5
+1094 1 1
+170 1 1
+844 0 3
+369 1 1
+39 1 1
+650 1 1
+41 1 1
+176 12 12
+688 1 0
+7640 4 0
+2650 1 1
+28 0 4
+44 1 1
+728 8 0
+2196 0 1
+13466 0 1
+3510 0 2
+2147 1 1
+44 0 3
+1320 11 11
+210 0 4
+105 1 0
+3239 0 1
+1496 142 153
+2391 1 1
+39 0 2
+438 4 0
+2272 8 0
+6865 0 3
+7183 0 1
+5104 0 3
+182 1 0
+3131 1 1
+31 1 0
+14 1 1
+59 1 0
+373 1 1
+42 1 1
+235 13 13
+1608 0 5
+152 1 1
+106 1 1
+783 34 34
+1633 1 1
+29 3 0
+821 1 1
+24 1 1
+1178 1 1
+33 1 1
+328 1 1
+27 1 1
+5682 16 13
+146398 30000 50000
+59809 0 2
+3389 1 1
+37 1 1
+11606 0 1
+1597 0 1
+618 1 1
+47 1 1
+2698 0 1
+826 5 5
+33 0 2
+2560 0 14
+98 0 3
+1287 0 1
+7600 0 1
+9894 0 8
+7160 0 1
+32 1 1
+1698 0 1
+754 2 0
+6787 0 1
+584 0 2
+1107 1 1
+40 1 1
+365 1 1
+35 1 1
+399 0 8
+11444 0 1
+1973 0 1
+1200 0 1
+716 1 1
+25 1 1
+1570 0 2
+433 2 0
+905 0 2
+94 1 1
+28 1 1
+2490 18 18
+5054 9 1
+2184 0 2
+2955 23 21
+431 49 49
+314 1 0
+1563 1 1
+20 1 1
+1632 11 0
+1671 2 0
+1527 0 1
+676 1 1
+29 1 1
+1245 1 1
+34 0 1
+1203 22 30
+1934 1 0
+3421 0 2
+17 1 1
+774 0 30
+97 6 6
+59 12 26
+840 1 1
+19 1 1
+2036 27 53
+683 30 30
+401 0 1
+25 1 1
+381 16 0
+159 1 1
+17 1 1
+1150 0 4
+700 1 0
+29 0 2
+409 1 1
+49 1 1
+1240 1 1
+37 3 3
+2248 0 1
+1828 0 1
+1997 1 5
+4640 4 4
+4555 2 0
+150 52 0
+618 2 2
+16 1 1
+83 0 22
+56 1 57
+2531 8 0
+4250 17 17
+2203 4 0
+1665 10 0
+415 0 2
+393 0 1
+15728 1 0
+158 0 4
+82 0 14
+543 1 1
+42 1 1
+3261 18 18
+139 1 1
+37 1 1
+410 1 1
+18 1 1
+5405 0 1
+1104 1 1
+53 1 1
+392 1 1
+55 3 3
+3352 0 9
+692 106 52
+27 4 0
+13 1 3
+14 88 0
+61 2 0
+8931 0 1
+6692 2 1
+253 19 19
+869 2 0
+196 0 2
+389 1 1
+30 1 1
+949 1 0
+6057 3 0
+4741 0 1
+7689 0 2
+2046 18 18
+215 1 0
+46885 0 2
+24138 0 2
+4037 0 1
+4047693 0 1
+9545 2 0
+11590 0 4
+1698 3 1
+18923 0 4
+1806 1 1
+44 1 1
+2581 2 0
+10620 1 0
+3804 1 0
+339 2 0
+476 1 0
+5861 5 8
+109 14 0
+901 1 1
+19 1 1
+45 0 2
+1736 0 1
+6625 0 2
+7812 0 4
+7678 0 2
+5086 3 8
+4170 1 0
+1671 0 6
+6333 16 0
+902 1 1
+44 1 1
+384 6 0
+23181 4 4
+214 0 2
+8958 4 0
+220 1 1
+49 1 1
+2783 1 0
+2641 1 0
+136 20 20
+1279 1 0
+3924 6 6
+13054 0 6
+8954 13 0
+4128 0 2
+2269 0 1
+16258 2 0
+30076 1 1
+49 1 1
+102 0 1
+8824 27 27
+1730 1 1
+47 1 1
+3339 1 0
+132 16 0
+81 0 16
+89 0 6
+6369 0 1
+541 0 1
+6288 4 0
+3814 0 2
+7260 1 0
+802 0 68
+1166 1 0
+2230 0 1
+1109 1 0
+1106 0 2
+12396 1 0
+26207 1 1
+21 1 1
+4087 16 0
+1323 7 7
+525 1 0
+4198 1 0
+4682 13 13
+890 2 0
+816 2 0
+1961 4 0
+24586 1 1
+19 1 1
+4403 0 1
+1342 0 1
+57 11 12
+2229 30 31
+1979 35 0
+10541 1 0
+9725 6 0
+2536 1 2
+20 1 1
+1541 12 0
+1130 1 1
+34 1 1
+927 1 0
+4003 1 0
+966 0 1
+149 1 0
+842 0 8
+4326 1 1
+25 1 1
+569 6 7
+664 2 2
+5695 0 1
+3074 1 0
+1539 9 3
+634 1 1
+39 1 1
+8610 1 1
+11 0 1
+345 43 43
+372 0 2
+4311 6 0
+3122 2 0
+369 0 1
+9963 10 10
+2191 1 1
+23 1 1
+1060 1 1
+19 1 1
+240 12 12
+1748 1 1
+45 1 1
+1040 1 1
+31 1 1
+7446 1 1
+25 1 1
+8379 7 7
+7325 0 3
+357 1 0
+1313 1 0
+11624 0 4
+5865 0 1
+9750 0 1
+3540 16 0
+5671 13 13
+2885 4 0
+8179 0 1
+753 1 0
+2289 49 49
+1979 2 0
+1318 0 1
+957 1 0
+825 12 12
+1110 16 0
+3735 17 17
+9997 223 53
+149 22 24
+636 1 1
+22 0 1
+42 1 1
+1634 4 4
+3380 3 0
+979 0 2
+3429 1 0
+7138 14 0
+1727 1 1
+38 1 0
+88 0 1
+630 20 20
+476 0 5
+21 0 1
+94 0 1
+42 1 0
+17 0 1
+27 0 1
+172 1 1
+37 1 1
+191 1 1
+66 1 1
+630 0 1
+261 1 1
+28 1 1
+1282 17 18
+429 0 1
+1588 1 1
+20 1 1
+1416 1 1
+33 1 1
+529 0 1
+25 0 1
+1863 0 4
+1651 1 1
+28 1 1
+11815 0 1
+26 0 1
+19 1 1
+3105 0 1
+700 0 1
+150 0 1
+68 0 1
+1420 0 6
+568 14 16
+2415 0 1
+41 1 1
+415 1 1
+33 1 1
+4521 1 1
+33 1 1
+307 1 0
+176 1 0
+3790 1 1
+86 1 1
+67 1 1
+65 0 1
+7439 1 1
+18 1 1
+16805 0 1
+1764 1 0
+3104 35 35
+3845 0 1
+3384 0 2
+17 0 18
+156 1 1
+30 1 1
+165 0 2
+1087 1 0
+953 1 0
+483 0 1
+632 1 0
+652 1 0
+8563 9 7
+1860 1 0
+398 1 0
+2219 1 1
+53 1 1
+756 1 1
+66 1 1
+69 1 1
+48 1 1
+63 1 1
+28 3 0
+1057 3 0
+63 0 3
+55 1 1
+74 3 2
+159 0 3
+92 1 1
+29 1 1
+58 3 0
+1210 9 9
+54 1 1
+27 1 1
+1374 0 2
+1775 17 2
+764 14 14
+331 16 16
+2291 3 4
+1687 1 1
+26 1 1
+2469 1 0
+3243 0 1
+3636 1 1
+24 1 1
+615 1 0
+2566 0 1
+275 5 0
+695 7 0
+9686 32 32
+3416 0 1
+1452 4 0
+214 13 13
+49 0 124
+1393 9 9
+5812 1 1
+24 1 1
+5703 0 1
+4006 1 0
+1462 3 0
+5199 2 0
+1554 0 2
+715 10 12
+1966 0 2
+2801 0 16
+618 0 1
+413 18 0
+730 1 1
+31 1 1
+4372 5 0
+10789 1 0
+2399 1 0
+6750 0 2
+1363 6 0
+6736 2 0
+4457 0 4
+7867 1 0
+3495 2 1
+7584 0 1
+2652 1 0
+1771 0 1
+14808 41015 41008
+19235 0 1
+9638 0 1
+2994 0 1
+469 3 1
+499 0 1
+12074 13 13
+2807 10 11
+715 0 2
+1627 6 6
+5099 1 0
+488 1 5
+975 0 2
+1761 0 1
+1794 5 0
+8254 3 3
+18 1 1
+3737 9 9
+1442 13 13
+212 0 10
+7712 1 1
+44 1 1
+4480 40 40
+1751 1 0
+1316 1 1
+49 1 1
+9050 4 0
+143 0 2
+2813 13 13
+1286 2857 49999
+75638 40000 50000
+1583473 0 2
+1564099 1 97463
+2933461
+
+chain 1621142 X 154913754 + 148570601 148611616 X 155270560 - 6466757 6507765 175
+13140 0 1
+20345 6 0
+3704 1 0
+1517 1 0
+2301
+
+chain 259772 X 154913754 + 75282398 75286444 X 155270560 - 79901776 79905823 6183
+1486 41 41
+41 40 40
+126 11 11
+1051 1209 1210
+41
+
+chain 192506 X 154913754 + 114908114 114911060 X 155270560 + 114997023 115000000 3054
+63 528 528
+60 0 16
+630 28 44
+689 16 16
+436 1 0
+495
+
+chain 188216 X 154913754 + 114908656 114914454 X 155270560 + 115000574 115005488 36116
+49 2721 1850
+47 8 8
+197 704 696
+2 16 0
+1155 42 43
+455 2 12
+400
+
+chain 119665 X 154913754 + 114906873 114908114 X 155270560 + 115003848 115005094 1024208
+1216 0 5
+25
+
+chain 29390 X 154913754 + 76491035 76491342 1 249250621 - 136684922 136685229 4932608
+307
+
+chain 25643 X 154913754 + 114911150 114911426 X 155270560 + 115005157 115005433 246321
+276
+
+chain 19821 X 154913754 + 114908177 114911739 X 155270560 + 114982173 114982762 1997
+479 3022 49
+61
+
+chain 15998 X 154913754 + 114911743 114912382 X 155270560 + 114967843 114968482 6239
+639
+
+chain 9708 X 154913754 + 148714470 148714905 5 180915260 - 8837105 8837560 23506322
+56 313 333
+66
+
+chain 9294 X 154913754 + 114906712 114906808 X 155270560 + 115005518 115005614 24447825
+96
+
+chain 6266 X 154913754 + 114906808 114906873 X 155270560 + 114962882 114962947 1027613
+65
+
+chain 6215 X 154913754 + 76426104 76426191 X 155270560 + 29934095 29934182 9535161
+87
+
+chain 5894 X 154913754 + 143027611 143027675 2 243199373 - 154977524 154977591 249
+15 0 3
+49
+
+chain 3277 X 154913754 + 76426069 76426104 1 249250621 - 60612464 60612499 19993171
+35
+
+chain 2407 X 154913754 + 148714814 148714839 2 243199373 + 100113459 100113484 27784968
+25
+
+chain 1984 X 154913754 + 76426191 76426234 8 146364022 - 27059036 27059079 21505033
+43
+
+chain 1549 X 154913754 + 114911087 114911150 X 155270560 + 114976136 114976199 336010
+63
+
+chain 1443 X 154913754 + 114913555 114913597 X 155270560 + 114984570 114984612 98822
+42
+
+chain 1245 X 154913754 + 148714288 148714366 4 191154276 - 133575330 133575408 22672116
+78
+
+chain 1030 X 154913754 + 114911060 114911082 X 155270560 + 114988042 114988064 7002
+22
+
+chain 733 X 154913754 + 148715982 148716070 X 155270560 - 110405878 110405966 21525610
+88
+
+chain 469 X 154913754 + 76426248 76426375 8 146364022 - 18567958 18568085 6841016
+127
+
+chain 293 X 154913754 + 148716634 148716684 2 243199373 - 107635751 107635801 26436223
+50
+
+chain 50554324 X_random 1719168 + 610279 1452044 X 155270560 + 76412035 77367385 75
+7124 5 6
+4742 1 1
+31 1 1
+1606 21 28
+3800 1 1
+23 1 1
+6209 1 1
+4 1 0
+22 1 0
+13 1 0
+1193 1 1
+32 1 1
+2218 0 1
+7608 6 1
+670 0 2
+1396 0 2
+1207 20 20
+5098 1 0
+1294 1 0
+119 0 1
+6626 16 16
+8221 1 0
+3722 4 0
+169 0 4
+1754 11 13
+58 0 1
+239 1 1
+75 1 1
+910 0 1
+518 7 7
+6771 0 1
+4354 26 26
+781 1 1
+28 1 1
+406 16 16
+4353 1 0
+22 100 24
+930 1 0
+33 1 1
+1226 0 1
+1278 660 1078
+3884 2 2
+22 1 1
+2022 4 0
+2593 1 0
+777 0 3
+4596 153 64
+2593 1 10
+1074 1 0
+3147 1 0
+2227 1 0
+9697 1 0
+3957 1 0
+3098 0 186786
+22519 1 0
+204 1 0
+22 1 0
+63 17 18
+9565 0 6
+6660 129 0
+58 1 0
+17671 100 83
+39 1 1
+9798 2 1
+5 0 1
+19 100 237
+1127 0 1
+4928 133 164
+8370 115 394
+3028 259 91
+9555 100 1670
+18018 6 0
+3818 1 0
+72 1 0
+15 1 0
+11 1 0
+4 1 0
+10 100 30
+18171 0 1
+18316 0 28
+22590 0 1
+2592 2 0
+8265 0 2
+4335 4 3
+14218 100 218
+8896 0 2
+5422 18 17
+1347 4 4
+83 166 0
+5120 101 153
+3114 126 148
+4567 1 0
+2511 0 1
+1289 2 0
+3129 124 175
+5332 1 0
+20 1 0
+15993 0 4
+9940 115 1562
+10856 1 1
+18 0 1
+2379 1 1
+32 74 72
+41 1 1
+3148 155 3622
+2876 621 0
+31 1 1
+2212 81729 108028
+557 0 1
+4283 1 0
+148 0 457
+722 1 1
+49 113 176
+33 2 2
+2654 1 0
+25 188 415
+1394 12 0
+5398 0 1
+28 100 19
+5509 151745 28754
+87 102 102
+66 5 5
+53 70 72
+56 201 601
+7819 256 150
+16 0 1
+6 0 1
+8001 4 0
+8135 0 1
+528 12 0
+797 100 193
+2857 496 0
+5822 153 0
+8578 1 0
+10594 1 0
+6352 3 3
+35 6 7
+50 55655 72028
+890 0 1
+72 0 1
+2125 1 1
+64 1 0
+15 1 0
+5 22 19
+12 129 67
+11 1 0
+8 0 1
+4 1 0
+16 2 2
+3637 1 1
+36 1 0
+28 1 0
+942 0 1
+231 1 1
+109 101 336
+18 11 294
+14959 0 2
+22656 3 1
+1280
+
+chain 6857177 X_random 1719168 + 1212241 1285856 X 155270560 + 76337041 76411192 460
+53 4 4
+3247 0 6
+51 2 0
+2014 2 0
+45 4 0
+20 4 0
+48 1 0
+5158 1 1
+29 1 1
+394 16 13
+1410 1 0
+12 1 0
+14 1 0
+7 1 0
+5 1 0
+13 1 0
+36 106 188
+1195 0 31
+133 0 4
+28 1 1
+1388 1 1
+18 1 1
+2790 0 1
+767 4 4
+49 0 1
+10 110 385
+52 0 1
+56 0 1
+4004 182 11
+23 1 1
+767 1 1
+66 1 1
+3217 2 0
+25 1 1
+4309 1 0
+26 0 1
+820 2 2
+4450 0 1
+1391 1 1
+33 0 1
+31 0 8
+3634 1 0
+1669 111 432
+10524 1 2
+8620 1 0
+2158 1 0
+1513 7 7
+4600 4 4
+2111
+
+chain 5479158 X_random 1719168 + 19684 169644 X 155270560 + 3753512 3953553 578
+1162 21228 9243
+742 1 0
+2200 7659 14347
+948 1 0
+4152 211 33421
+819 48 49
+92 22 22
+544 44 42
+175 0 1
+63 102 104
+246 37 37
+203 6 5
+279 27 27
+206 54 54
+394 39 40
+260 2 0
+311 16 16
+208 57 57
+349 6 6
+262 134 134
+481 0 6
+56 1 1
+868 0 5
+1387 18095 3193
+790 8 6
+1718 0 2
+3436 13 13
+241 40033 77157
+63 10 10
+425 63 0
+38963
+
+chain 5155611 X_random 1719168 + 1349115 1404263 X 155270560 - 77841540 77897663 609
+4514 1 1
+4 1 0
+15 0 1
+1714 142 0
+26953 1 1
+31 100 192
+4795 129 41
+2612 4 0
+3389 4 0
+5037 1 1
+22 101 1223
+13 9 8
+34 2 2
+5520
+
+chain 4548442 X_random 1719168 + 595876 1601165 X 155270560 - 77827311 79038577 141
+3039 114 45
+9150 2 0
+1995 422998 109473
+19795 1 0
+23 1 0
+12 111 343
+20 5 4
+13 1 1
+2240 1980 60
+2381 1 3
+44 1 0
+37 0 1
+24 100 79
+2445 100 136
+5050 0 1
+8804 4 0
+4444 704 262
+34 2 2
+12610 100 395
+4803 1 1
+22 1 1
+4171 128 46
+569 0 1
+2902 29308 112180
+236 1 0
+659 1 0
+711 1 0
+104 0 6764
+3212 4 2485
+1198 1 0
+8224 110 1
+4 0 1
+8 0 1
+21 0 1
+23 4 4
+5939 0 1
+182 101 1162
+2127 1 0
+28 100 77
+5048 2 0
+2345 1 0
+3616 100 211
+11 10 11
+1378 0 44
+1405 0 1
+1238 0 1
+575 0 20
+9423 100 122
+20 1 1
+7723 0 1
+431 0 1
+181 2 0
+5386 16 0
+866 105 61
+1365 0 1
+11613 318206 1966
+13 1 2
+40 1 1
+781 0 2
+5976 121 213
+3371 0 1
+693 1 0
+169 2337 746790
+586 1 0
+2072 1 1
+34 1 1
+58 13 13
+211 1 1
+28 1 1
+332 1 1
+31 1 1
+179 11 0
+2785 0 5
+1418 1 0
+12774 0 1
+3561 1 0
+4305 1 1
+120 1 1
+377 1 1
+68 1 1
+208 9 9
+998 15 15
+2146 0 1
+693 101 90
+36 1 1
+1743 1 1
+18 1 1
+2412 15 15
+1943 29 30
+3136 0 3
+12327 3 4
+2517
+
+chain 4126434 X_random 1719168 + 1485975 1530227 X 155270560 + 76291305 76335950 725
+1188 0 2
+717 1 1
+34 1 1
+1032 1 1
+42 1 1
+974 1 0
+5479 16 16
+2476 1 1
+35 1 1
+1212 3 0
+152 1 1
+46 1 1
+77 7 6
+912 1 1
+38 1 1
+4230 17 17
+617 146 545
+27 3 3
+374 1 1
+18 1 1
+3639 1 1
+122 1 1
+435 4 4
+1916 16 16
+2739 1 0
+622 16 16
+6383 2 0
+2520 35 35
+5915
+
+chain 3853214 X_random 1719168 + 170863 1715347 X 155270560 - 151357158 154150181 220
+101 0 61
+11 0 2
+38 0 155
+54 0 1
+34100 0 1
+12001 158233 27287
+105 0 1
+847 4191 3311
+101 25049 633
+4294 18781 8391
+120 26 27
+1173 0 1
+2374 87 87
+206 41 40
+40 7493 0
+1552 0 1
+194 0 1
+6613 4 3
+492 13807 11516
+2651 0 2
+1724 0 2
+2453 0 1
+3866 165 10497
+2912 8 0
+2305 93 94
+6287 1 0
+3225 7 7
+393 1 1
+18 1 1
+298 495 25877
+271 0 138
+31886 6 0
+14613 3 0
+9199 1105799 2318225
+448 0 73
+215 36 2
+248 14 15
+1012 1 0
+110 1 1
+211 15 16
+87 3 0
+268 10 6
+108 12 12
+74 1 1
+27 1 1
+178 1 1
+18 1 1
+1429 0 10
+168 1 1
+36 1 1
+64 1 1
+62 0 1
+129 2 0
+80 13 10
+11 3 0
+19 823 1702
+36 1 0
+605 17 17
+193 1 0
+215 12 13
+271 1 1
+18 1 1
+91 1 0
+178 4 4
+39 1 1
+233 1 1
+31 1 1
+500 1 1
+68 1 1
+325 9 9
+244 0 1
+843 1 1
+46 1 1
+202 0 1
+957 0 1
+150 1 1
+81 1 0
+6 1 1
+303 8540 16182
+59 4 0
+415 4 7
+127 38 38
+333 0 44
+16 0 252
+226 27 26
+64 4 0
+91 0 4
+56 32 32
+977 0 16
+701 1 1
+29 1 1
+1743 1 0
+676 0 2
+2780 0 16
+85 0 11
+22 1 1
+952 3 0
+470 1 0
+840 4 0
+146 0 4
+131 0 34
+39 4 0
+99 1 1
+26 0 4
+80 1 1
+1476 0 13
+977 0 2
+480 0 800
+1133 4 5
+532 1 1
+37 1 1
+207 0 117633
+2070 1 1
+30 2 0
+524 2 0
+484 0 1
+446 1 0
+1642 2 0
+63 1 1
+43 1 1
+148 12 12
+2115 0 1
+116 1 1
+182 10 10
+88 1 1
+65 0 320
+107 0 2
+2083 295 0
+1170 10932 59997
+1792 0 1
+292 6 7
+677 8 11
+1932
+
+chain 2670012 X_random 1719168 + 22277 129533 X 155270560 - 151420019 151525192 697
+318 0 8
+1212 7792 0
+1334 4590 634
+3132 4549 4298
+403 12 12
+889 7 7
+393 20 20
+2070 17932 14002
+179 0 1
+1042 0 1
+4330 476 475
+66 0 1
+1653 797 0
+2278 8 0
+5943 18846 26826
+69 77 81
+86 822 824
+287 1 0
+7796 1771 9789
+1118 1349 0
+2572 2 0
+4177 1 0
+2904 5 0
+881 1 1
+56 6 0
+590 1 1
+23 1 1
+262 6 6
+349 1 1
+55 1 1
+208 16 16
+311 0 2
+260 1 0
+34 5 5
+394 54 54
+206 27 27
+199
+
+chain 2529127 X_random 1719168 + 1458959 1485875 X 155270560 + 77160344 77187173 1079
+634 0 1
+9184 1 0
+59 1 0
+14 100 16
+21 1 0
+53 2 2
+11087 2 0
+2487 0 2
+2602 1 0
+667
+
+chain 902700 X_random 1719168 + 269161 291745 Y 59373566 - 58967799 59197152 4215
+4053 3 0
+293 1 1
+26 0 1
+791 0 165863
+51 243 5
+66 134 1
+42 388 5
+141 0 15
+35 2 2
+42 361 0
+256 1 0
+341 3 36
+453 301 1
+147 0 1
+278 4 4
+15 0 3
+29 1 1
+122 2 0
+148 430 0
+222 151 0
+55 0 2
+149 1 0
+687 6309 50121
+61 1 1
+43 1 1
+408 80 0
+147 11 11
+228 1 1
+48 2 2
+1372 1 1
+31 1 1
+75 1 1
+28 97 0
+263 0 1
+495 98 1
+51 1 33
+52 1 1
+51 33 1
+226 1 1
+20 4 0
+211 340 0
+179 1 0
+10 1 1
+236 341 1
+555
+
+chain 569801 X_random 1719168 + 1106858 1112877 X 155270560 - 78234537 78240560 9279
+4787 0 4
+1232
+
+chain 569444 X_random 1719168 + 1452563 1458801 X 155270560 - 78136578 78142679 9342
+609 3 13
+1692 0 8
+1539 155 0
+30 3 3
+254 9 9
+1944
+
+chain 534458 X_random 1719168 + 90245 170863 X 155270560 - 151402385 151465977 943
+12303 69 69
+77 86 86
+822 66146 49119
+57 3 4
+1055
+
+chain 494413 X_random 1719168 + 391508 439759 X 155270560 - 151446976 151536655 1213
+50 57 60
+3938 36909 78166
+87 206 206
+41 40 40
+6143 240 408
+340 6 6
+194
+
+chain 379298 X_random 1719168 + 415243 419212 X 155270560 - 151507548 151511517 135808
+663 12 12
+3294
+
+chain 372919 X_random 1719168 + 1663885 1667930 X 155270560 - 153907181 153911269 141765
+802 0 3
+83 1 1
+47 1 1
+767 17 17
+1585 0 73
+215 36 2
+248 14 15
+229
+
+chain 274258 X_random 1719168 + 1667930 1671196 X 155270560 - 154066175 154070218 305212
+2034 1 281
+24 1 1
+190 0 200
+632 326 623
+58
+
+chain 267510 X_random 1719168 + 422339 428025 X 155270560 - 151460048 151465730 1055
+1034 4 3
+2317 3 0
+2328
+
+chain 266050 X_random 1719168 + 27992 75212 X 155270560 - 151430977 151495459 1091
+2648 315 25719
+644 9056 5097
+1296 30530 26348
+164 1 0
+310 1720 1720
+536
+
+chain 247472 X_random 1719168 + 49544 52383 X 155270560 + 3800594 3803433 7089
+2766 6 6
+67
+
+chain 247318 X_random 1719168 + 58807 462399 X 155270560 + 3743706 3828677 987
+48 658 658
+44 238 238
+102 246 246
+37 488 488
+27 206 206
+54 394 394
+39 797 797
+57 617 617
+134 287931 26427
+60 1338 0
+1419 8746 13247
+2214 50 50
+51 31242 578
+263 4 4
+5180 1349 0
+1121 24105 7962
+467 20820 8687
+32 2 2
+3992 2 0
+898 48 49
+92 22 22
+544 44 42
+175 0 1
+63 102 104
+246 37 37
+203 6 5
+279 27 27
+206 54 54
+394 39 40
+260 2 0
+311 16 16
+208 57 57
+349 6 6
+262 25 25
+590 57 63
+881 1017 1022
+1498
+
+chain 203629 X_random 1719168 + 419791 421950 X 155270560 - 151464996 151467156 582605
+2107 0 1
+52
+
+chain 199106 X_random 1719168 + 1699808 1701947 X 155270560 - 153935858 153937997 603481
+61 1 1
+57 1 1
+1588 4 4
+59 7 7
+361
+
+chain 199089 X_random 1719168 + 378452 380544 X 155270560 + 3796616 3798707 602253
+1586 1 0
+505
+
+chain 187776 X_random 1719168 + 376353 378301 X 155270560 + 3798256 3800203 654951
+729 1 0
+1218
+
+chain 174234 X_random 1719168 + 1285969 1288372 X 155270560 + 77019422 77021825 343560
+1763 87 87
+102 124 124
+70 56 56
+201
+
+chain 157788 X_random 1719168 + 111815 113457 X 155270560 + 3753462 3755104 810742
+1642
+
+chain 154415 X_random 1719168 + 1055747 1057376 X 155270560 + 77369279 77370908 822932
+1629
+
+chain 134293 X_random 1719168 + 1708912 1710376 X 155270560 + 1185231 1187137 959481
+129 1 1
+82 1 1
+350 2 297
+68 0 147
+831
+
+chain 132265 X_random 1719168 + 403961 405553 X 155270560 - 151477034 151478628 31377
+436 0 2
+1156
+
+chain 90853 X_random 1719168 + 1707707 1708693 X 155270560 + 1353464 1354449 1404000
+164 1 0
+46 1 1
+620 1 1
+37 1 1
+115
+
+chain 74037 X_random 1719168 + 267762 268693 Y 59373566 - 59139189 59140054 1710353
+79 97 0
+220 1 0
+317 27 60
+128 1 0
+61
+
+chain 63811 X_random 1719168 + 410390 415127 X 155270560 + 3822705 3827447 11885
+2487 0 6
+1981 48 47
+221
+
+chain 61116 X_random 1719168 + 346359 347004 X 155270560 + 3777922 3778567 2069731
+645
+
+chain 55813 X_random 1719168 + 2787 3496 X 155270560 - 151499719 151505905 2274078
+50 6 6
+412 0 5477
+241
+
+chain 38577 X_random 1719168 + 1651263 1651671 X 155270560 - 153943757 153944164 3434500
+271 1 0
+136
+
+chain 34659 X_random 1719168 + 1707297 1707664 X 155270560 + 1118849 1119216 3901406
+367
+
+chain 33830 X_random 1719168 + 267400 267758 X 155270560 - 154819600 154819959 4017435
+54 0 1
+304
+
+chain 33594 X_random 1719168 + 347004 347356 X 155270560 - 151523309 151523661 4010211
+352
+
+chain 33500 X_random 1719168 + 290273 291150 X 155270560 - 155043354 155044230 1935940
+149 427 427
+91 1 0
+137 17 17
+55
+
+chain 33229 X_random 1719168 + 1452213 1452563 X 155270560 - 78136229 78136579 3954656
+350
+
+chain 31748 X_random 1719168 + 1656832 1657169 X 155270560 - 154080972 154081310 4345014
+118 0 1
+219
+
+chain 31047 X_random 1719168 + 364702 460901 X 155270560 + 3752840 3788747 1318
+48 54 53
+80 31133 470
+26 58237 28604
+46 660 660
+40 242 241
+78 0 2
+22 248 248
+33 492 491
+25 208 208
+52 400 400
+34 798 798
+56 1232 1232
+21 1 1
+34 882 887
+1017
+
+chain 26366 X_random 1719168 + 1717468 1717765 X 155270560 - 154599490 154599787 6355797
+65 8 8
+224
+
+chain 20775 X_random 1719168 + 1657225 1657446 Y 59373566 + 1138227 1138450 9855403
+101 0 2
+120
+
+chain 20767 X_random 1719168 + 4453 4700 X 155270560 - 151332163 151332410 9860775
+174 10 10
+63
+
+chain 20271 X_random 1719168 + 1698243 1698467 X 155270560 - 154161726 154161950 2868
+224
+
+chain 20189 X_random 1719168 + 22064 22277 X 155270560 + 3752676 3752889 10232162
+213
+
+chain 20092 X_random 1719168 + 410218 414905 X 155270560 + 3784106 3788794 77876
+172 4468 4469
+47
+
+chain 19894 X_random 1719168 + 365127 367414 X 155270560 + 3744796 3747084 92469
+246 37 37
+203 5 6
+279 27 27
+206 54 54
+394 41 39
+260 0 2
+535
+
+chain 19881 X_random 1719168 + 217168 217385 X 155270560 + 3913712 3913929 10410664
+217
+
+chain 19372 X_random 1719168 + 1704190 1704597 2 243199373 + 106598364 106598785 10983407
+91 100 114
+81 74 74
+61
+
+chain 17351 X_random 1719168 + 365104 366619 X 155270560 + 3783188 3784703 560009
+23 246 246
+37 487 487
+27 206 206
+54 394 394
+41
+
+chain 16176 X_random 1719168 + 3557 21469 X 155270560 + 3768043 3793719 20345
+896 16406 24170
+326 33 33
+130 29 29
+92
+
+chain 15865 X_random 1719168 + 276938 277188 Y 59373566 - 59140528 59140772 2014767
+82 6 0
+162
+
+chain 15331 X_random 1719168 + 367414 367617 X 155270560 + 3823924 3824127 647220
+203
+
+chain 13713 X_random 1719168 + 489399 489544 X 155270560 + 3712149 3712294 16431967
+145
+
+chain 12918 X_random 1719168 + 274951 275159 Y 59373566 - 59139058 59139278 8720139
+52 0 12
+156
+
+chain 12632 X_random 1719168 + 1705530 1705970 X 155270560 + 145057484 145057926 18056495
+78 288 290
+74
+
+chain 12447 X_random 1719168 + 1030429 1030575 5 180915260 - 168461964 168462110 18325086
+146
+
+chain 12016 X_random 1719168 + 1317064 1317191 X 155270560 + 77214259 77214386 18979178
+127
+
+chain 11687 X_random 1719168 + 278072 278210 X 155270560 - 154988343 154988492 4329206
+112 25 36
+1
+
+chain 11514 X_random 1719168 + 278210 278346 Y 59373566 - 59141204 59141340 4138572
+136
+
+chain 10224 X_random 1719168 + 1704620 1704728 19 59128983 - 37939031 37939139 22329028
+108
+
+chain 10213 X_random 1719168 + 277934 278654 Y 59373566 - 59141065 59141499 2702219
+138 514 228
+68
+
+chain 9983 X_random 1719168 + 290082 290229 X 155270560 - 155043503 155043650 2501552
+48 40 40
+59
+
+chain 9686 X_random 1719168 + 1671544 1671645 X 155270560 + 1359785 1359886 23561825
+101
+
+chain 8627 X_random 1719168 + 274506 274913 X 155270560 - 154985996 154986278 9490470
+54 20 20
+32 0 8
+10 242 109
+49
+
+chain 7400 X_random 1719168 + 1030281 1030397 9 141213431 + 129760930 129761046 27439238
+59 26 26
+31
+
+chain 7194 X_random 1719168 + 274704 274779 Y 59373566 - 59139208 59139283 27842833
+75
+
+chain 7041 X_random 1719168 + 129047 129334 X 155270560 - 151486292 151486579 1717
+54 206 206
+27
+
+chain 6777 X_random 1719168 + 275159 275252 X 155270560 - 154986140 154986238 15049098
+1 37 42
+55
+
+chain 6125 X_random 1719168 + 479075 479168 X 155270560 - 151461082 151461175 898
+93
+
+chain 5720 X_random 1719168 + 1705205 1705283 3 198022430 - 36255828 36255906 21764861
+52 21 21
+5
+
+chain 5699 X_random 1719168 + 57777 57859 X 155270560 + 3747892 3747974 156364
+82
+
+chain 5684 X_random 1719168 + 275730 275789 X 155270560 - 154985991 154986050 31480070
+59
+
+chain 5671 X_random 1719168 + 278678 278737 X 155270560 - 154987944 154988003 7684992
+59
+
+chain 5648 X_random 1719168 + 288487 288546 Y 59373566 - 59194675 59194734 31602153
+59
+
+chain 5292 X_random 1719168 + 1698467 1698538 X 155270560 - 154160180 154160251 1242775
+71
+
+chain 4986 X_random 1719168 + 1705613 1705672 7 159138663 + 43857891 43857950 19004666
+59
+
+chain 4456 X_random 1719168 + 1030620 1030666 X 155270560 + 76367481 76367527 34837220
+46
+
+chain 4200 X_random 1719168 + 65786 66804 X 155270560 + 3789104 3790122 1705
+1018
+
+chain 4147 X_random 1719168 + 1704281 1704341 4 191154276 - 52750556 52750615 11058024
+1 2 1
+57
+
+chain 4142 X_random 1719168 + 276887 276938 Y 59373566 - 59140619 59140670 3855343
+51
+
+chain 3859 X_random 1719168 + 291150 291190 Y 59373566 - 59196218 59196258 16097861
+40
+
+chain 3722 X_random 1719168 + 1703633 1706063 17 81195210 - 47362086 47364493 15646977
+109 441 439
+7 1805 1784
+68
+
+chain 3009 X_random 1719168 + 1705804 1705856 X 155270560 + 62632912 62632964 24180689
+52
+
+chain 2509 X_random 1719168 + 1708877 1708912 X 155270560 + 1109247 1109282 2078841
+35
+
+chain 2078 X_random 1719168 + 1706063 1706085 1 249250621 + 114909259 114909281 21967653
+22
+
+chain 1700 X_random 1719168 + 274379 274412 Y 59373566 - 59139235 59139268 19436247
+33
+
+chain 990 X_random 1719168 + 1705283 1705342 X 155270560 + 119232530 119232589 19658805
+59
+
+chain 463 X_random 1719168 + 1703519 1703583 X 155270560 + 65440530 65440594 26501250
+64
+
+chain 2373402471 Y 57772954 + 0 27228749 Y 59373566 + 10000 28819361 24
+34821 50000 50000
+86563 30000 50000
+766173 50000 50000
+36556 50000 50000
+80121 90000 50000
+754004 100000 50000
+6846717 50000 50000
+276367 600000 50000
+813231 500000 3000000
+39401 400000 50000
+554624 100000 50000
+535761 1 0
+32919 1 0
+10 1 1
+12811 5 0
+18899 1 1
+121 5 4
+230478 1 0
+750 24 24
+14340 1 1
+43 1 1
+2095 1 0
+14635 9 0
+2781 1 0
+45022 6 5
+7151 1 0
+9343 0 628
+5417477 0 50006
+2175794 0 50000
+1481749 50000 50000
+4867933
+
+chain 46617811 Y 57772954 + 57228749 57772954 Y 59373566 + 58819361 59363566 80
+98295 50000 50000
+395910
+
diff --git a/public/chainFiles/b37tob36.chain b/public/chainFiles/b37tob36.chain
new file mode 100644
index 0000000..e808435
--- /dev/null
+++ b/public/chainFiles/b37tob36.chain
@@ -0,0 +1,12268 @@
+chain 21270171362 1 249250621 + 10000 249233096 1 247249719 + 0 247199719 2
+619 137 0
+166661 50000 50000
+40302 50000 50000
+153649 50000 50000
+1098479 1 1
+47 1 1
+73 117 114
+773 1 1
+43 1 1
+864369 2 2
+51 3 0
+104 13694 13694
+104 0 3
+51 2 2
+134936 50000 50000
+1161048 150000 60000
+1440092 27273 50000
+7590365 50000 50000
+116914 100000 50000
+237250 50000 50000
+3518496 50000 50000
+12702424 150000 50000
+16145012 0 1
+7772 1 0
+4705841 0 1
+52977198 50000 50000
+157344 21065 50000
+16604841 50000 50000
+189539 150000 50000
+398739 21050000 20290000
+195588 50000 50000
+186739 150000 50000
+175055 50000 50000
+201709 100000 50000
+126477 130183 50000
+381 0 3
+315 0 2
+62 1 1
+45 1 0
+19 0 1
+8 1 1
+1158 1 0
+314 12 13
+2849 3 0
+5615 1 1
+37 1 1
+3172 6 4
+190 1 1
+34 1 1
+380 0 1
+2099 3 0
+765 2 2
+366 0 4
+1186 1 0
+460 0 1
+1242 28 28
+574 1 1
+21 1 1
+1460 1 1
+105 1 1
+701 3 0
+239 0 1
+970 11 11
+2365 1 1
+21 1 1
+384 8 8
+996 2 0
+10383 2 0
+713 0 1
+5188 1 1
+30 1 1
+1233 1 0
+132 1 1
+44 1 1
+1123 22 22
+1810 1 0
+512 1 1
+39 1 1
+1096 0 16
+743 1 0
+9028 0 1
+2506 0 6
+8446 2 0
+5505 0 3
+7541 1 0
+109864 50000 50000
+78698 50000 50000
+127263 50000 50000
+170669 50000 50000
+38311 100000 100000
+1022394 50000 50000
+281532 289973 50000
+1648 1539 0
+76 3225 3
+1018 34 34
+1716 2 0
+159 4 0
+1600 0 6
+1385 1 0
+2066 1 1
+32 1 3
+1556908 150000 50000
+185320 150000 50000
+172789 50000 50000
+220313 50000 50000
+455185 50000 50000
+22047237 1 0
+34365824 150000 50000
+259514 150000 50000
+17265625 50000 50000
+11394365 50000 50000
+13665999 150000 50000
+174886
+
+chain 3264727 1 249250621 + 146303299 146341166 16 88827254 - 19388358 19424466 890
+577 1 1
+25 1 1
+63 19 19
+840 1 1
+60 1 1
+146 8 8
+874 1 1
+17 1 1
+386 1 1
+27 1 1
+931 1 1
+19 1 1
+200 1 1
+26 1 1
+72 1 0
+39 1 1
+107 2 1
+26 1 0
+25 1 1
+146 1 1
+45 1 1
+49 0 1
+434 0 4
+21 1 1
+572 0 2
+464 1 1
+50 1 1
+628 1 1
+48 1 1
+184 1 1
+25 1 1
+330 0 3
+308 14 14
+289 1 1
+57 1 1
+709 107 107
+247 1 1
+72 1 1
+470 1 1
+36 1 1
+353 1 0
+27 1 1
+92 12 12
+1001 1 1
+39 1 1
+650 1 1
+22 1 1
+171 1 1
+21 1 1
+88 0 9
+107 36 11
+23 0 1
+29 0 26
+20 3 79
+161 11 11
+134 1 1
+89 1 1
+547 1 1
+15 1 1
+409 1 1
+36 1 1
+376 11 10
+1545 1 0
+4 0 1
+36 1 1
+373 0 1
+326 1 1
+42 17 0
+97 1 0
+187 2 0
+503 1 1
+57 1 1
+443 1 1
+35 1 1
+633 1 0
+2044 3 13
+299 1 1
+37 1 1
+1159 1 1
+39 1 1
+124 1 1
+74 1 1
+103 1 1
+55 1 1
+280 10 9
+474 0 1
+382 1 1
+31 1 1
+1812 1 1
+76 1681 0
+25 1 1
+145 1 1
+18 1 1
+1228 1 1
+31 1 1
+126 9 9
+186 2 0
+142 1 1
+25 1 0
+442 10 0
+339 0 1
+89 1 1
+21 2 0
+21 151 4
+15 1 1
+489 9 9
+311 1 1
+75 1 1
+75 1 0
+124 1 1
+114 1 1
+23 1 1
+1489 0 3
+391 1 0
+2141 10 10
+460 11 11
+422 1 1
+30 1 1
+296 8 8
+638 1 1
+38 1 1
+341
+
+chain 2374970 1 249250621 + 146214652 146460889 1 247249719 - 102316553 102503720 74
+488 1 1
+24 1 1
+971 6293 0
+994 2 0
+183 2 0
+1408 1 0
+1360 1541 0
+211 0 12
+1506 111528 93105
+421 5 6
+2973 8 8
+118 12 12
+157 10 10
+706 0 18
+26 2884 0
+127 4 1
+1518 1 1
+33 1 1
+934 9 9
+908 0 1
+126 1 0
+695 20 20
+2250 5 5
+1662 179 172
+975 1 1
+53 1 1
+62 2 2
+40 1 1
+1561 1 1
+34 1 1
+668 1 0
+1671 2 0
+480 1 1
+17 4 4
+103 0 1
+50 6 6
+230 1 1
+71 1 1
+139 1 0
+975 5 0
+180 1 1
+37 1 1
+1888 3 2
+1101 1 0
+354 64 9327
+654 1 1
+36 1 1
+888 0 2
+18 1 1
+74 1 1
+25 1 1
+81 2 0
+779 1 1
+41 0 12
+22 1 1
+436 1 6
+293 1 1
+31 1 1
+83 4 0
+694 1 1
+42 1 1
+913 0 9
+472 0 1
+253 12 12
+148 89 1
+41 89 1
+342 1 1
+72 1 1
+97 1 1
+41 1 1
+108 13 16
+280 12 12
+61 1 1
+30 0 1
+71 1 1
+42 2 2
+139 0 3
+85 5 5
+90 1 1
+39 0 1
+366 13 14
+332 0 3744
+123 1 1
+19 1 1
+264 2 0
+47 1 1
+381 3 5
+109 0 1
+521 0 1
+503 1 1
+42 0 1
+739 1 1
+77 1 1
+883 0 2
+220 0 3
+93 4 0
+12 4 0
+39 5 0
+91 1 1
+34 1 1
+562 1 1
+30 1 1
+660 13 0
+1172 16 16
+69 1 1
+32 1 1
+310 1 1
+33 1 1
+97 0 1
+38 1 1
+295 0 2
+499 1 1
+57 31 14
+607 10 10
+145 1 1
+101 1 1
+346 1 1
+30 1 1
+74 1 1
+16 1 1
+203 1 1
+36 12 0
+483 16 0
+977 1 1
+86 1 1
+66 1 1
+35 1 1
+692 16 13
+402 34 34
+287 0 5
+523 0 18
+350 4 0
+32 0 2
+108 39 45
+66 30 0
+969 0 5
+1749 5 5
+95 2 0
+5 1 0
+4 0 1
+79 0 2
+65 8 11
+63 1 1
+49 1 1
+1381 0 1
+870 17 0
+139 1 1
+89 1 1
+270 3 3
+97 1 1
+66 1 1
+50 1 1
+126 1 0
+182 1 1
+83 0 4
+125 1 1
+35 1 1
+263 1 1
+32 4 4
+202 1 0
+94 1 1
+46 1 1
+206 1 1
+56 1 1
+50 1 1
+49 1 1
+188 16 16
+589 1 1
+38 1 1
+178 0 4
+67 1 1
+421 51 0
+117 1 1
+36 1 1
+71 1 1
+74 1 1
+68 10 10
+131 3 3
+56 1 0
+52 1 1
+207 4 4
+30 1 1
+283 14 14
+93 0 4
+66 1 1
+89 7 5
+36 1 1
+79 1 1
+46 21 0
+99 1 1
+229 10 10
+100 5 0
+19 8 8
+78 1 1
+87 1 1
+125 5 5
+65 1 1
+74 3 3
+344 1 1
+24 1 1
+683 1 1
+43 6287 0
+250 15 15
+798 13 12
+267 2 1
+881 1 0
+374 10 10
+1237 1 1
+40 1 1
+620 1 1
+43 1 1
+1491 1 1
+28 1 1
+68 5 5
+413 1 2
+183 5 5
+42 1 1
+363 1 1
+26 23 0
+53 1 0
+1011 15 15
+173 4 4
+15 1 1
+801 4 4
+1197 0 10
+432 22154 19
+283 4702 22
+850 9524 0
+78 76 76
+568 10 10
+775 40 32
+274 4 0
+1120 17 17
+195
+
+chain 990444 1 249250621 + 2485433 2499127 1 247249719 - 244760735 244774429 1366
+13694
+
+chain 614409 1 249250621 + 249233096 249240448 21 46944323 + 46937133 46944296 2013
+2867 16 16
+420 9 9
+176 0 1
+1252 6 0
+1275 1 1
+25 0 344
+76 0 58
+545 484 7
+40 109 0
+51
+
+chain 498595 1 249250621 + 146216137 146242853 1 247249719 - 104315183 104389677 383
+30 657 657
+196 19 18
+134 27 27
+445 20 20
+101 9 9
+169 62 62
+116 10 10
+70 62 62
+54 26 26
+70 0 22267
+240 1539 0
+91 20 24
+246 22 22
+270 112 112
+118 143 143
+86 24 24
+184 81 81
+67 47 46
+110 83 95
+335 59 59
+139 4179 2633
+241 27 27
+273 109 109
+185 76 76
+86 24 24
+184 81 81
+26 1717 1732
+80 85 53
+151 37 37
+99 37 37
+113 20 20
+101 9 9
+169 62 62
+89 37 37
+70 62 62
+54 33 33
+382 279 5055
+291 112 112
+125 147 147
+256 382 24225
+58 106 106
+51 29 29
+422 19 19
+221 84 84
+156 29 29
+162 33 33
+80 4 4
+79 11 11
+209 29 29
+183 34 34
+116 44 44
+122 5 5
+554 41 41
+140 8 8
+161 0 1
+67 58 51
+138 10 10
+246 60 60
+124 59 60
+101 138 138
+109 161 161
+56 31 28
+163 74 74
+136 7 7
+303 34 34
+119 10 10
+339 30 30
+141 91 91
+222 107 93
+237 205 205
+134 49 49
+87 22 22
+128 87 87
+105 33 33
+52 58 58
+52 87 87
+198 158 162
+125 44 44
+82 42 42
+54 10 9
+72 27 27
+154 18 18
+186 39 39
+61 87 86
+71 38 38
+116 43 43
+268 50 50
+58 120 120
+152
+
+chain 376931 1 249250621 + 143880003 143901185 1 247249719 - 126576077 126597249 122
+127 70 71
+181 31 31
+3325 1 1
+49 1 1
+820 1 1
+75 1 1
+393 1 1
+21 1 1
+2956 3 0
+232 0 5
+77 4 4
+531 1 1
+42 5 3
+183 1 1
+19 1 1
+644 1 1
+25 1 1
+701 1 1
+21 1 1
+954 1 1
+31 1 1
+129 24 14
+650 1 1
+25 1 1
+560 0 2
+1372 1 1
+46 1 1
+1547 3 1
+883 1 0
+22 1 1
+818 1 1
+30 1 1
+1231 1 1
+34 1 1
+1758 1 1
+35 1 1
+468
+
+chain 360128 1 249250621 + 146427813 146438983 1 247249719 + 144926007 144932406 9045
+138 252 252
+1258 1540 0
+76 3256 30
+81 283 283
+87 185 185
+109 273 273
+7 19 19
+155 43 43
+91 1 0
+1185 11 11
+212 2 0
+158 2 0
+1336 64 64
+346
+
+chain 260187 1 249250621 + 146226436 146443808 1 247249719 - 100391956 100589719 716
+173 5526 775
+60 400 391
+120 18 17
+164 81 83
+26 45 45
+35 1589 1589
+29 2518 2516
+7 17 17
+56 30 30
+51 56 53
+31 163 163
+74 446 446
+34 468 468
+30 141 141
+33 624 609
+8 133 133
+64 134 134
+49 237 237
+71 316 316
+58 1199 1203
+39 219 219
+38 6697 424
+97 18 18
+77 219 219
+114 64 64
+138 183 187
+118 99 99
+89 25 31
+69 24 24
+100 30 30
+69 49 49
+54 125 125
+182 197 197
+107 156930 137139
+140 175 171
+75 164 162
+157 49 49
+69 45 45
+61 48 48
+51 61 60
+71 70 70
+108 10955 10956
+84 24 24
+75 87 87
+185 109 109
+273 22 22
+246 20 24
+49 494 19550
+70 10 10
+116 62 9592
+169 9 9
+324 83 83
+151 87 77
+90 22 22
+196 68 68
+95 5 5
+57 71 71
+196 17 17
+75 73 73
+563 83 87
+110 1555 14
+45 7990 0
+54 81 81
+184 24 24
+75 87 87
+185 109 109
+273 3222 27
+64 1605 35
+142 1567 44
+37 1539 0
+281
+
+chain 257136 1 249250621 + 146423276 146434218 1 247249719 + 144926235 144932406 9046
+68 157 157
+71 288 288
+73 563 563
+83 4962 196
+1052 19 19
+155 43 43
+91 1 0
+99 76 76
+1010 11 11
+212 2 0
+158 2 0
+1746
+
+chain 252664 1 249250621 + 146424776 146427813 1 247249719 + 144927734 144930766 96654
+1055 16 16
+124 74 74
+74 224 223
+979 11 11
+212 2 0
+158 2 0
+106
+
+chain 244411 1 249250621 + 146449863 146457732 1 247249719 + 144926007 144929115 8960
+1648 1539 0
+76 3225 3
+265 45 45
+708 34 34
+329
+
+chain 149837 1 249250621 + 146221841 146454623 1 247249719 + 146043049 146859300 923
+56 335 335
+59 4859 3299
+109 185 185
+76 5018 258
+57 409 426
+45 777 777
+84 1850 1850
+41 841 820
+47 125 126
+58 101 101
+138 2026 2026
+51 4 2
+52 297 297
+81 786 786
+33 347 347
+90 23 23
+35 125 125
+44 82 81
+42 634 634
+74 225 224
+43 268 267
+50 58 58
+120 152 152
+515 62 62
+68 41 41
+432 0 18
+180 46 46
+67 26 28
+192 26 26
+231 107 107
+67 72 67
+53 67 67
+151 171 168
+59 46 47
+86 57 54
+51 138 138
+397 18 18
+114 3 2
+182 20 20
+86 167 167
+51 48 48
+233 42 42
+89 55 55
+163 43 44
+112 70 70
+355 154 154
+174 157 641342
+145 228 228
+152 366 366
+64 1134 1135
+35 269 265
+46 15 14
+137 8 8
+70 11 11
+73 29 29
+55 63 63
+62 262 247
+77 100 100
+155 39 39
+215 72 72
+178 20 20
+64 13 13
+123 12 12
+124 127 127
+100 135495 128258
+34 14433 8189
+138 64 64
+114 219 219
+77 19 19
+96 17464 11155
+185 22232 98
+69 26 26
+54 62 62
+70 10 10
+116 62 62
+169 32 32
+211 37 37
+99 9482 37
+161 23 13
+130
+
+chain 121346 1 249250621 + 146403114 146428203 1 247249719 - 230466401 230485108 1747
+70 156 156
+17 25 25
+22 146 146
+152 249 249
+94 2285 2290
+63 34 34
+79 80 80
+89 48 42
+85 127 127
+68 502 495
+87 61 61
+136 127 126
+4 272 272
+43 396 396
+49 175 175
+48 183 187
+40 11298 11284
+59 5488 723
+50 98 104
+107 63 63
+54 1608 4
+83 9 9
+160
+
+chain 97594 1 249250621 + 146218654 146221704 1 247249719 - 102320562 102322071 123803
+154 24 24
+174 6 6
+1045 1614 73
+33
+
+chain 76810 1 249250621 + 146441138 146441951 1 247249719 - 102499725 102500538 1571454
+813
+
+chain 54094 1 249250621 + 146439071 146449863 1 247249719 + 144927734 144930766 9063
+156 32 32
+864 3151 76
+253 432 432
+62 196 196
+62 169 169
+32 211 211
+37 99 99
+87 4753 70
+88 2 0
+106
+
+chain 51170 1 249250621 + 146420674 146422968 1 247249719 + 144928397 144930686 91522
+82 822 821
+37 60 60
+212 196 196
+62 502 502
+83 151 149
+59 2 0
+26
+
+chain 47243 1 249250621 + 146249630 146253102 1 247249719 + 146058248 146061700 347899
+23 176 176
+41 89 89
+25 420 420
+79 245 245
+20 78 78
+29 495 490
+29 72 72
+46 158 145
+143 628 627
+53 534 533
+17 5 5
+67
+
+chain 34253 1 249250621 + 146404045 146461111 1 247249719 - 100757623 100773572 2307
+96 91 95
+87 237 237
+54 39 39
+166 170 170
+93 270 264
+54 177 172
+56 15121 8830
+27 23096 966
+26 9686 241
+71 62 62
+168 10 10
+112 7057 3813
+40
+
+chain 33489 1 249250621 + 146442066 146462163 1 247249719 + 144023055 144028915 8758
+86 162 162
+20 322 322
+153 82 82
+116 7 7
+260 4934 262
+352 142 142
+79 60 60
+57 99 99
+135 6 6
+234 31 31
+264 6949 535
+45 4229 1077
+134 1105 1106
+34
+
+chain 33218 1 249250621 + 146446746 146453724 1 247249719 + 144927655 144929867 162700
+76 4 3
+532 5285 520
+407 76 76
+465 71 71
+62
+
+chain 32794 1 249250621 + 146404432 146406255 1 247249719 - 230461418 230463242 176920
+104 280 280
+90 172 172
+62 25 26
+120 135 135
+128 18 18
+13 515 515
+161
+
+chain 26745 1 249250621 + 146451818 146452101 1 247249719 - 102499420 102499703 6165314
+283
+
+chain 22423 1 249250621 + 146216204 146248536 1 247249719 + 146043705 146710884 2213
+65 5 5
+58 95 95
+44 58 58
+67 1348 1339
+20 10 10
+32 196 196
+62 2594 1055
+96 153 153
+108 10232 605314
+55 16610 57923
+59 315 315
+50
+
+chain 21816 1 249250621 + 146442152 146442891 1 247249719 + 144927740 144928479 1347746
+148 509 509
+82
+
+chain 20351 1 249250621 + 146356780 146459279 1 247249719 - 101132456 101205064 466
+178 42398 55179
+51 39820 14441
+32 3075 0
+39 16869 2651
+37
+
+chain 17175 1 249250621 + 249240118 249240599 1 247249719 - 247249264 247249719 6645750
+53 7 10
+47 109 0
+21 6 0
+36 51 102
+5 22 73
+56 16 0
+52
+
+chain 16391 1 249250621 + 146446357 146448997 1 247249719 + 144928805 144929904 1203759
+155 2048 507
+109 112 112
+60 57 57
+99
+
+chain 14917 1 249250621 + 146407068 146408474 1 247249719 + 144010187 144011603 12383
+76 149 159
+73 240 240
+47 136 136
+39 587 587
+59
+
+chain 14732 1 249250621 + 104074421 104074580 20 62435964 - 41767962 41768121 15357748
+159
+
+chain 13179 1 249250621 + 146404319 146408384 1 247249719 + 146846894 147006750 8455
+113 104 104
+20 54 54
+39 1744 1736
+34 1903 157702
+54
+
+chain 12360 1 249250621 + 146216167 146250305 1 247249719 - 103194351 103244298 1211
+37 128 128
+95 44 44
+58 67 67
+60 5 5
+51 3345 6525
+128 0 9435
+8 6200 4617
+43 3518 3485
+37 13507 18215
+40 613 636
+46 716 718
+72 53 53
+30 240 240
+72 1522 1531
+48 233 233
+42 89 89
+36 14 14
+5 804 801
+66 696 696
+34 1307 1378
+29
+
+chain 11952 1 249250621 + 146445104 146445575 1 247249719 - 100776503 100776974 637661
+94 18 18
+359
+
+chain 11854 1 249250621 + 146229744 146232010 1 247249719 + 144747607 144749863 153009
+21 19 9
+19 736 736
+20 10 10
+32 196 196
+62 54 54
+33 556 556
+43 383 383
+82
+
+chain 10753 1 249250621 + 146408065 146408192 1 247249719 - 101190210 101190337 3832842
+127
+
+chain 10394 1 249250621 + 104091245 104091359 5 180857866 + 153305659 153305773 21933263
+114
+
+chain 10333 1 249250621 + 104091131 104091240 X 154913754 + 74963065 74963174 22062861
+109
+
+chain 9815 1 249250621 + 146403058 146404974 1 247249719 - 101191494 101193412 750328
+43 256 256
+25 136 136
+32 152 152
+35 1179 1181
+58
+
+chain 9804 1 249250621 + 146245618 146249581 1 247249719 + 16785678 16789645 248382
+32 19 19
+6 51 51
+11 80 80
+47 3688 3692
+29
+
+chain 8504 1 249250621 + 146408954 146409155 1 247249719 - 101191099 101191300 2114480
+61 111 111
+29
+
+chain 8318 1 249250621 + 146407418 146407505 1 247249719 - 102486621 102486708 14753827
+87
+
+chain 7171 1 249250621 + 1619987 1620086 1 247249719 + 1662789 1662888 1670813
+99
+
+chain 7168 1 249250621 + 146247532 146247756 1 247249719 + 144759088 144759312 2272140
+43 123 123
+58
+
+chain 6908 1 249250621 + 146440123 146445030 1 247249719 - 101203201 101205034 129817
+119 142 142
+69 4461 1387
+116
+
+chain 6650 1 249250621 + 146406255 146406330 1 247249719 - 101188413 101188487 10133477
+21 3 2
+51
+
+chain 6566 1 249250621 + 146445881 146445977 1 247249719 + 144059904 144060000 2107997
+23 21 21
+52
+
+chain 6380 1 249250621 + 10629 10716 Y 57772954 - 1612 1699 6955
+87
+
+chain 5940 1 249250621 + 146231384 146231447 1 247249719 - 102320696 102320759 393064
+63
+
+chain 5684 1 249250621 + 146407187 146407246 1 247249719 - 101189341 101189400 31412390
+59
+
+chain 5266 1 249250621 + 249240022 249240077 1 247249719 - 247249582 247249637 32667083
+55
+
+chain 5203 1 249250621 + 146446237 146446668 1 247249719 - 102500144 102500575 1674615
+120 155 155
+156
+
+chain 4958 1 249250621 + 146451766 146451818 1 247249719 + 142879884 142879936 20619966
+52
+
+chain 4944 1 249250621 + 104074593 104074659 8 146274826 - 121738108 121738174 21132898
+66
+
+chain 4456 1 249250621 + 146406808 146406855 1 247249719 - 101188965 101189012 6127414
+47
+
+chain 4404 1 249250621 + 146406008 146406074 1 247249719 - 100540708 100540774 1844606
+66
+
+chain 4255 1 249250621 + 146230090 146231384 1 247249719 - 103181490 103211127 6721
+37 1201 29544
+56
+
+chain 4244 1 249250621 + 146216712 146216757 1 247249719 - 102323372 102323417 831523
+45
+
+chain 4123 1 249250621 + 146421615 146421675 1 247249719 + 143536766 143536826 34723
+60
+
+chain 3877 1 249250621 + 146435532 146435575 1 247249719 - 101203375 101203418 141544
+43
+
+chain 3825 1 249250621 + 146430767 146430810 1 247249719 - 101203375 101203418 118474
+43
+
+chain 3528 1 249250621 + 146454014 146454173 1 247249719 - 100628659 100628818 205230
+159
+
+chain 3185 1 249250621 + 146406525 146406559 1 247249719 - 101188682 101188716 16359386
+34
+
+chain 3178 1 249250621 + 104074770 104074842 7 158821424 + 21042162 21042234 21615733
+72
+
+chain 3121 1 249250621 + 146445079 146445768 1 247249719 + 144930661 144931350 792159
+25 471 471
+193
+
+chain 3050 1 249250621 + 146407036 146407068 1 247249719 - 101189190 101189222 23011976
+32
+
+chain 2960 1 249250621 + 146249122 146249154 1 247249719 + 144760680 144760712 1406096
+32
+
+chain 2741 1 249250621 + 146231545 146231601 1 247249719 - 104345036 104345092 8679
+56
+
+chain 2464 1 249250621 + 146424736 146424776 1 247249719 + 144037261 144037301 21508852
+40
+
+chain 2405 1 249250621 + 249239910 249239972 1 247249719 - 247249327 247249389 7681464
+62
+
+chain 2390 1 249250621 + 249240288 249240334 1 247249719 - 247249596 247249642 26481552
+46
+
+chain 2344 1 249250621 + 146216757 146250883 1 247249719 - 103711249 103726499 1396
+67 32948 14063
+57 892 901
+7 127 127
+28
+
+chain 2164 1 249250621 + 146237300 146252192 1 247249719 + 16771061 16779662 20592
+30 14825 8534
+37
+
+chain 1926 1 249250621 + 10623 10756 15 100338915 - 932 978 361
+6 87 0
+40
+
+chain 1909 1 249250621 + 146251590 146251644 1 247249719 - 103917507 103917561 1304306
+54
+
+chain 1317 1 249250621 + 146445768 146445881 1 247249719 + 142919887 142920000 1148922
+113
+
+chain 1215 1 249250621 + 146245082 146245105 1 247249719 + 144762924 144762947 79987
+23
+
+chain 1154 1 249250621 + 146232196 146232260 1 247249719 + 16765963 16766027 137025
+64
+
+chain 1035 1 249250621 + 146367698 146367747 1 247249719 - 99837677 99837726 4094688
+49
+
+chain 827 1 249250621 + 146445037 146445075 1 247249719 - 102502075 102502113 153232
+38
+
+chain 691 1 249250621 + 146454173 146454226 1 247249719 - 100557283 100557336 435331
+53
+
+chain 604 1 249250621 + 146429501 146429541 1 247249719 + 147018285 147018325 1335641
+40
+
+chain 424 1 249250621 + 146449372 146449403 1 247249719 - 100776122 100776153 793932
+31
+
+chain 395 1 249250621 + 146448669 146448702 1 247249719 + 144078479 144078512 164120
+33
+
+chain 88 1 249250621 + 146452351 146452395 1 247249719 - 99890656 99890700 12702616
+44
+
+chain 71 1 249250621 + 146451564 146451618 1 247249719 - 102499166 102499220 29039078
+54
+
+chain 12431961244 10 135534747 + 60000 135524747 10 135374737 + 50000 135374737 10
+5577104 0 50006
+12337571 50000 50000
+20794160 50000 50000
+286100 3200000 2480000
+191752 50000 50000
+3830277 50000 150000
+952205 100000 150000
+263307 100000 150000
+163231 50000 150000
+989829 100000 150000
+1941874 50000 50000
+211435 50000 50000
+30112515 0 319974
+13249156 0 10
+31058956 50000 50000
+2696597 150000 50000
+4615335 50000 10000
+246123 50000 50000
+1327328 1 1
+47 1 1
+1312 0 1
+56 1 1
+190 1 1
+31 1 1
+20182 1 0
+448068
+
+chain 12415603391 11 135006516 + 60000 134946516 11 134452384 + 50000 134451988 11
+1102759 50000 16576
+49571094 307000 207000
+503352 3100000 3000000
+14395596 47395 0
+491076 304 60
+30213 182 114
+26 142 1
+27914 0 1
+20009 0 1
+19 0 1
+39 0 1
+17 1 3
+10 0 1
+1008 0 1
+95 0 1
+5126 0 15
+303 0 1
+975 4 0
+1548 1 0
+191 0 20
+40 0 1
+74 1 0
+101 0 1
+25 1 0
+6178 1 0
+1875 52561 21437
+468 1 1
+81 1 1
+2620 0 1
+1640 0 4
+3305 1 0
+3342 0 1
+17899663 50000 12000
+8549206 150000 15562
+38507167 37 39
+1282 0 174
+387 0 86
+59
+
+chain 12330185447 12 133851895 + 145739 133779461 12 132349534 + 16000 132289534 12
+7035084 4 0
+543 1 0
+3777 1 0
+3889 52114 73000
+6014 0 1
+6524 5 126
+29 0 13
+20974 2 0
+3965 0 3
+444 11 0
+464 0 1
+27577110 3000000 1395000
+38631945 1 0
+14544 4 0
+1700 0 1
+789 12128 250000
+1783 0 1
+1075 2 0
+1042 0 1
+1526 1 1
+27 1 1
+2320 1 0
+166 0 1
+564 1 0
+2856 2 0
+900 1 0
+1387 1 1
+33 1 1
+2139 1 1
+48 1 1
+1305 2 0
+1533 2 1
+879 1 0
+744 26 26
+858 4 0
+1089 0 6
+1113 0 12
+818 1 1
+18 0 1
+217 1 1
+36 1 1
+2002 0 1
+1025 1 0
+450 48 48
+916 0 1
+18 1 1
+4694 8 0
+142 0 4
+3656 0 2
+3403 1 1
+47 1 1
+1524 1 1
+28 1 1
+5560 48 45
+676 8 8
+810 16 16
+536 0 2
+236 0 4
+167 4 0
+1419 53 49
+4688 1 1
+38 1 1
+18576 0 5
+5285 2 0
+6486 1 1
+25 1 1
+4341 14 0
+2662 0 5
+1170 0 1
+4268 4 0
+1036 1 0
+2117 8 0
+5917 0 1
+3239 4 0
+2619 1 1
+21 1 1
+937 1 1
+38 1 1
+2412 124 139
+2648 2 0
+9314 0 2
+1986 2 2
+16 1 1
+229 1 1
+93 1 1
+895 0 12
+415 5 1
+119 1 1
+185 9 8
+458 2 0
+89 1 1
+42 1 1
+2034 1 0
+1545 2 0
+280 4 0
+97 14 14
+231 2 0
+2814 0 5
+1679 1 1
+27 1 1
+25758689 1 0
+6536665 1 0
+377270 96749 57000
+668 1 1
+20 0 1
+3348 1 1
+33 1 1
+648 1 1
+29 1 1
+3731 0 4
+1834 9 14
+1688 10 0
+3103 5 5
+1140 0 1
+1167 0 1
+985 9 9
+2897 0 1
+1625 0 9
+1101 1 0
+1358 8 0
+13065721 68352 150000
+810 0 2
+343 1 0
+1771 1 0
+2702 6 7
+1900 0 1
+705 0 6
+303 0 1
+727 1 1
+43 3 6
+490 1 1
+59 1 1
+226 1 1
+52 0 3
+465 8 0
+194 1 1
+25 0 1
+139 17 17
+1833 0 1
+81 1 1
+39 1 1
+453 0 1
+719 1 1
+47 1 1
+558 0 1
+838 1 8
+288 9 10
+741 2 5
+465 1 1
+48 1 1
+268 1 1
+26 0 1
+1337 17 0
+12 2 1
+16 1 1
+84 85 2
+917 0 1
+110 1 1
+29 1 1
+1580 1 1
+40 1 1
+683 1 1
+24 1 1
+247 1 1
+36 1 1
+1411 14 14
+149 1 0
+10091386 3 0
+296 5 0
+220 100872 45000
+972469
+
+chain 2067120 12 133851895 + 60245 88108 2 242951149 + 114046160 114069967 1234
+334 1 1
+47 1 1
+111 1 1
+20 0 13
+84 1 1
+84 7 15
+55 1 1
+28 1 1
+77 1 1
+49 1 1
+99 10 10
+345 1 1
+48 0 4
+16 2 2
+168 1 1
+160 1 1
+68 1 0
+62 1 1
+23 1 1
+144 7 7
+94 2128 0
+762 12 12
+305 1 1
+40 1 1
+385 196 196
+207 0 1
+267 1 1
+53 1 1
+58 0 12
+43 1 1
+55 4 4
+38 1 0
+361 1 0
+53 1 1
+27 1 1
+448 1 1
+18 1 1
+309 4 0
+104 1 1
+35 1 1
+394 1 1
+16 1 1
+159 1 1
+38 1 1
+413 14 14
+82 5 7
+699 0 1
+52 23 24
+1077 9 9
+492 1 0
+144 18 19
+69 1 1
+26 1 1
+689 2 0
+34 5 6
+34 1 1
+187 1 1
+65 1 1
+181 9 9
+82 1 1
+55 0 2
+310 1 1
+25 1 1
+71 1 1
+74 3 3
+64 6 6
+216 5 5
+62 1 1
+35 8 3
+803 1 0
+23 1 1
+124 1 1
+90 1 1
+300 4 0
+48 0 4
+28 1 0
+85 7 4
+63 2 0
+7 3 0
+49 1 1
+255 31 31
+462 1 1
+38 1 1
+414 1 1
+37 1 1
+304 1 1
+36 1 1
+119 16 19
+62 1 1
+26 1 1
+306 1 1
+93 1 1
+114 1 1
+141 1 1
+464 1 1
+25 1 1
+145 1 1
+21 1 1
+196 1 1
+46 1 1
+295 11 11
+255 1 1
+21 1 1
+280 1 1
+90 1 1
+413 8 8
+1039 24 24
+761 1 0
+53 1 1
+94 1 0
+25 1 1
+63 1 1
+71 2070 1
+21 2 47
+228 3 0
+17 1 1
+133 11 0
+137 1 1
+43 1 1
+90 3 3
+23 2 0
+144 1 1
+99 1 1
+349 3 3
+29 5 5
+60 0 70
+93 1 1
+21 1 1
+138 0 2
+83 1 1
+68 1 1
+166 1 1
+49 1 1
+461 1 1
+18 0 17
+26 1 1
+50 1 1
+14 0 1
+34 1 1
+370 1 1
+32 1 1
+68 14 14
+98
+
+chain 484774 12 133851895 + 88108 95739 X 154913754 + 154905409 154913416 8417
+2 1 1
+34 1 1
+80 1 1
+32 1 1
+415 1 1
+48 1 1
+73 1 1
+44 1 1
+149 13 13
+211 1 1
+26 1 1
+271 0 3
+528 1 1
+96 1 1
+507 1 1
+100 1 1
+121 37 37
+520 1 1
+34 1 1
+166 1 1
+45 1 1
+96 1 1
+87 1 1
+82 4 4
+71 1 1
+34 1 1
+132 1 1
+23 1 1
+97 1 1
+30 2 2
+109 3 3
+36 1 1
+134 2135 2017
+245 454 1029
+82 84 0
+113
+
+chain 233388 12 133851895 + 133837240 133840071 7 158821424 + 158817351 158819960 454901
+564 1 1
+52 1 0
+36 1 1
+470 1 1
+28 1 1
+359 1 1
+38 1 1
+130 5 0
+3 216 0
+97 3 2
+46 1 1
+559 1 1
+43 0 1
+78 1 1
+94
+
+chain 194103 12 133851895 + 62428 64518 14 106368585 + 64430621 64433205 634790
+748 40 40
+140 0 1
+167 0 373
+27 0 120
+968
+
+chain 49263 12 133851895 + 133825767 133827148 11 134452384 + 74280352 74281733 2582033
+188 22 24
+55 110 110
+117 297 297
+62 252 253
+116 101 98
+61
+
+chain 35717 12 133851895 + 133841521 133841895 5 180857866 - 180793287 180793661 3746803
+374
+
+chain 32957 12 133851895 + 133823831 133824928 X 154913754 - 110744397 110745491 4131553
+102 47 47
+104 308 309
+61 155 155
+59 173 169
+88
+
+chain 18331 12 133851895 + 133822513 133823307 7 158821424 + 35158939 35159735 11829157
+110 151 152
+60 413 414
+60
+
+chain 16856 12 133851895 + 66036 76221 19 63811651 - 63781390 63791585 1292
+70 1 1
+57 16 16
+51 9959 9969
+31
+
+chain 16157 12 133851895 + 109428208 109428485 2 242951149 - 225002676 225002954 13880737
+71 91 92
+115
+
+chain 11750 12 133851895 + 60000 60122 12 132349534 - 132324140 132324262 19413804
+122
+
+chain 9037 12 133851895 + 133826997 133827421 2 242951149 + 160701141 160701565 3717783
+90 61 61
+34 175 175
+64
+
+chain 8057 12 133851895 + 133826086 133826759 3 199501827 - 98694913 98695583 3241421
+56 127 126
+50 305 303
+135
+
+chain 4873 12 133851895 + 133822983 133823177 6 170899992 + 146924403 146924597 15743780
+57 73 73
+64
+
+chain 4427 12 133851895 + 133827536 133827658 3 199501827 - 37386916 37387038 7696734
+122
+
+chain 4266 12 133851895 + 109428325 109428370 8 146274826 + 102422247 102422292 23131068
+45
+
+chain 4036 12 133851895 + 133826320 133826456 X 154913754 + 144352164 144352300 4124454
+136
+
+chain 3880 12 133851895 + 95312 95362 1 247249719 - 247249339 247249389 25961870
+50
+
+chain 3693 12 133851895 + 63176 63216 6 170899992 - 141104715 141104755 640206
+40
+
+chain 3673 12 133851895 + 133827423 133827506 2 242951149 - 104106513 104106596 10382380
+83
+
+chain 3091 12 133851895 + 133826496 133826821 11 134452384 - 91473718 91474043 4183905
+58 205 205
+62
+
+chain 3057 12 133851895 + 133822699 133822767 2 242951149 + 211079534 211079602 19980130
+68
+
+chain 2758 12 133851895 + 133827507 133827536 3 199501827 - 112531647 112531676 15775673
+29
+
+chain 2377 12 133851895 + 133825725 133826065 1 247249719 + 157351310 157351652 3309912
+42 265 267
+33
+
+chain 2375 12 133851895 + 95368 95419 1 247249719 - 247249256 247249307 12772530
+51
+
+chain 2223 12 133851895 + 133827262 133827357 6 170899992 + 81976496 81976591 4176034
+95
+
+chain 2091 12 133851895 + 109428279 109428301 20 62435964 + 39979396 39979418 21613404
+22
+
+chain 1955 12 133851895 + 133822880 133822953 4 191273063 - 60412182 60412255 19166211
+73
+
+chain 1569 12 133851895 + 133823330 133823447 5 180857866 + 90128366 90128483 9408356
+117
+
+chain 1532 12 133851895 + 133822199 133822253 12 132349534 + 77527067 77527121 12101346
+54
+
+chain 1265 12 133851895 + 133825609 133825680 2 242951149 + 183532658 183532729 7750866
+71
+
+chain 1251 12 133851895 + 95185 95235 18 76117153 - 76117025 76117075 24929113
+50
+
+chain 1165 12 133851895 + 133826456 133826496 X 154913754 - 53085075 53085115 5993397
+40
+
+chain 1153 12 133851895 + 133824667 133824711 10 135374737 - 97414674 97414718 8388000
+44
+
+chain 852 12 133851895 + 133822443 133822508 5 180857866 + 49699275 49699340 23831787
+65
+
+chain 636 12 133851895 + 133823040 133823067 6 170899992 + 127619395 127619422 20859432
+27
+
+chain 615 12 133851895 + 133823498 133823556 14 106368585 - 76653675 76653733 3589163
+58
+
+chain 440 12 133851895 + 133827198 133827224 1 247249719 - 50786620 50786646 7302157
+26
+
+chain 9007882413 13 115169878 + 19020000 115109878 13 114142980 + 17918000 114127980 14
+26987167 0 1
+40753157 150000 50000
+25443670 150000 400000
+1821999 413955 384056
+369930
+
+chain 17589438 13 115169878 + 114456082 114639948 13 114142980 - 484930 668986 160
+430 0 2
+2905 4 8
+143 0 30
+612 0 4
+18 0 2
+175 1 1
+49 0 2
+2159 1 1
+27 1 1
+979 0 144
+1492 0 2
+174870
+
+chain 8359015315 14 107349540 + 19000000 107289540 14 106368585 + 18070000 106360585 15
+1081285 1 1
+43 1 1
+76 0 2
+437 1 1
+19 1 1
+440 1 0
+11 1 1
+59 15 15
+63 12 12
+70 1 0
+734 1 1
+165 4 1
+96 1 1
+46 0 1
+83 1 1
+149 4 4
+164 20 20
+63 16 15
+359 1 1
+39 1 1
+103 1 1
+76 1 1
+139 1 1
+38 1 1
+344 1 1
+65 1 0
+166 5 5
+88 1 1
+57 287 0
+59 1 1
+317 1 0
+52 1 1
+92 0 4
+651 4 4
+82 1 1
+93 1 1
+64 1 1
+24 1 1
+856 1 1
+35 1 1
+258 1 1
+17 1 1
+478 0 1
+1335 33 33
+1029 1 1
+37 1 1
+1115 4 3
+72 1 1
+643 10 10
+132 6 6
+89 2 0
+209 4 15
+77 5 5
+427 1 1
+41 1 1
+949 1 1
+16 1 1
+732 1 1
+44 0 2
+128 1 0
+91 1 1
+180 6 6
+388 6 6
+50 12 13
+275 1 1
+33 1 1
+142 1 1
+61 1 1
+560 1 1
+20 1 1
+1327 13 6
+1013 83 83
+202 4 0
+43 1 1
+352 10 10
+261 1 1
+39 1 1
+939 0 12
+1678 0 36
+159 1 1
+32 1 8
+818 6 0
+580 0 1
+931 0 1
+276 0 2
+3513 46 60
+882 0 2
+94 1 1
+49 1 1
+864 0 4
+40 1 1
+807 15 16
+416 3 0
+3345 15 15
+92 29 30
+80 1 1
+48 1 1
+2459 1 0
+646 66 66
+359 1 1
+29 0 54
+1875 0 3
+141696 1 1
+32 1 1
+8201115 0 1
+107 0 1
+2137 1 1
+39 1 1
+8848 1 0
+4806 0 1
+2075 0 1
+16612 0 1
+2385 0 3
+11506 0 8
+1353 1 0
+4596 1 0
+2073 1 2
+28 1 1
+2311 1 1
+44 1 1
+10440 4 0
+894 1 0
+1638 96 0
+41 0 9
+20 1 1
+2705 0 6
+352 1 1
+25 1 1
+742 1 0
+1048 18 2
+12085977 1 0
+14871228 0 3
+29067652 1 1
+47 1 1
+20173856 0 1292
+2548494
+
+chain 25802 14 107349540 + 20085579 20085848 8 146274826 + 118781991 118782260 6606813
+269
+
+chain 9908 14 107349540 + 20110215 20120217 22 49691432 + 14757849 14767860 97
+45 9891 9900
+66
+
+chain 8901 14 107349540 + 20090287 20100367 14 106368585 - 87815145 87825210 65
+33 9964 9949
+83
+
+chain 7700563179 15 102531392 + 20000000 102521392 15 100338915 + 18260008 100338915 16
+8448 2 6
+4086 0 1
+9569 1 1
+40 5 0
+56 1 7
+872354 40513 40506
+553 4 4
+876 40 39
+139 25 25
+1881 18 19
+499 8 8
+310 79 85
+78 26 23
+181 6 5
+569 11 11
+539 28 24
+261 22 20
+776 15 13
+62 13 13
+860 0 1
+716 0 26
+1349 167 166
+1070 23 23
+398 1 0
+177 21 5
+534 0 4
+770 24 18
+606 33 33
+1861 55 55
+2169 0 3
+558 19 20
+227 14 16
+329 5 5
+430 18 20
+620 1 0
+1112 0 2
+641 4 0
+476 47 47
+1285 1 0
+1139 49 49
+183 0 4
+1425 0 20
+186 1 0
+219 1 0
+607 44 44
+371 8 2
+507 0 2
+66 42 43
+999 4 4
+318 15 15
+1092 74 74
+808 61 61
+52 42 42
+109 51 51
+1535 0 14
+14011 0 4
+7955 1 4
+1350 0 1
+318 27 27
+600 4 0
+442 1 0
+1396 38 38
+1107 3 0
+1441 5 0
+360 49 49
+256 10 20
+497 39 39
+2129 0 4
+1242 0 2
+478 0 4
+708 92 92
+154 10 10
+1583 33 33
+1303 37 0
+100 14 14
+1138 92 109
+114 31 31
+2917 34 34
+1762 48 48
+449 0 1
+2458 1 9
+869 0 1
+534 49 49
+309 0 1
+2627 1 1
+3729 0 22
+565 1 0
+1845 0 1
+660 27 27
+68 0 1
+217 46 22
+1519 34 34
+559 32 32
+3851 0 1
+265 7 8
+224 0 4474
+444 0 1
+1651 10 11
+297 0 1
+665 0 21
+48 1 1
+1763 0 2
+245 1 1
+39 1 1
+519 1 1
+31 1 1
+2398 6 0
+749 1 49
+2072 0 4
+703 5 5
+337 0 1
+470 45 45
+1163 0 3
+1342 45 45
+140 1 0
+83 65 64
+723 38 38
+99 28 31
+92 0 1
+1218 13 0
+384 2 0
+292 41 41
+101 12 12
+576 2 0
+1907 21 21
+318 0 1
+1973 34 34
+689 51 51
+357 8 8
+2354 15 15
+2295 26 26
+2558 28 28
+571 2 0
+16 5 0
+323 1 0
+36 1 0
+5342 0 111
+1722 70 38
+272 13 13
+1284 1 0
+1128 4 4
+2189 0 1
+474 0 2
+1284 27 27
+36 6 0
+641 39 39
+381 2 0
+56 0 1
+2591 57 57
+160 121 121
+89 0 2
+316 1 0
+782 0 20
+155 1 1
+21 1 1
+601 6 0
+567 0 1
+278 1 1
+29 1 1
+89 4 0
+1737 1 1
+58 1 1
+368 24 24
+2113 24 20
+218 2 0
+18 1 1
+684 4 4
+3200 33 33
+58 18 18
+164 39 39
+296 6 6
+431 37 37
+431 47 47
+93 26 26
+216 48 48
+2779 17 0
+745 1 2
+104 61 61
+445 28 28
+356 0 1
+1484 2 1
+436 25 25
+306 57 57
+230 4 4
+843 49 50
+364 7 7
+796 28 28
+663 2 0
+93 15 0
+4378 0 1
+133 30 26
+41 2 0
+80 150 150
+925 0 3
+1882 13 13
+4513 0 1
+111 78 78
+200 0 6
+682 1 0
+200 0 3
+429 2 0
+736 20 20
+1573 121 120
+245 21 12
+1656 22 54
+616 1 2
+158 1 0
+587 41 44
+1053 6 6
+1116 36 36
+152 7 10
+448 1 0
+269024 863295 100000
+334079 50000 100000
+180557 74 0
+62 0 107
+7 2 1
+26 3 4
+4 0 1
+19 3 4
+10 42 87
+27 1 1
+202 1 1
+17 1 0
+156 1 1
+55 1 1
+111 1 0
+144 1 1
+57 1 0
+687074 50000 50000
+120648 348 0
+45585 1 0
+6994 0 1
+3398063 12354 44008
+7672 2 0
+1809 0 1
+428524 10165 101014
+43170 4 4
+1064959 5086 128966
+1021 1 0
+1710 0 1
+931 2 0
+4505 1 0
+686 2 525
+360 0 33
+130 1 1
+18 1 1
+12369 0 1014
+6233 1 0
+359485 111749 100000
+33855822 239 0
+2852112 0 1
+7040367 1 0
+2815738 1 3
+7055922 50000 60000
+363827 32 32
+104991 1 0
+203136 6050 0
+1426791 50000 60000
+13510190 5553 22012
+9194 3 0
+108 4 0
+41 1 0
+45 7 0
+2350 13 0
+5027 2 0
+534 0 1
+794 2 0
+4227 8 6
+5769 0 1
+381 0 1
+2524 2 0
+547 5 0
+1967 1 0
+1192 0 105
+1042 6 0
+3935380
+
+chain 22529558 15 102531392 + 21901199 22210800 15 100338915 + 19154576 19464222 111
+143347 1 1
+30 1 1
+2265 10 11
+297 0 1
+665 49 70
+240 39 39
+1731 41 41
+519 33 33
+339 22 22
+2037 4 0
+749 1 49
+910 38 38
+1831 3 9
+333 0 1
+470 1 1
+43 1 1
+1518 1 1
+51 1 1
+1122 1 0
+2351 19 6
+376 2 0
+1022 2 0
+1907 1 1
+19 1 1
+318 0 1
+3104 8 8
+179 1 1
+29 1 1
+3162 2 0
+2854 1 1
+26 1 1
+482 1 0
+512 1 1
+26 1 1
+571 27 16
+323 37 36
+5342 0 111
+542 40 39
+1141 64 35
+275 13 13
+503 26 26
+130 44 44
+581 4 0
+1128 4 4
+749 0 1
+1439 0 1
+474 0 16
+1270 1 1
+25 1 1
+54 11 0
+623 1 1
+37 1 1
+381 20 0
+56 0 1
+2591 1 1
+55 1 1
+160 4 4
+75 14 14
+1217 0 15
+742 59 53
+955 3 0
+1737 60 60
+391 43 43
+2071 24 20
+218 21 19
+684 4 4
+1195 4 4
+2001 1 1
+31 1 1
+58 18 18
+499 6 6
+431 1 1
+35 1 1
+431 1 1
+45 1 1
+3158 17 0
+983 0 1
+773 16 16
+1457 4 1
+767 1 1
+55 1 1
+338 10 10
+650 0 2
+123 3 4
+261 1 1
+48 1 1
+53 7 7
+776 1 1
+46 1 1
+663 2 0
+377 13 13
+4081 0 1
+159 5 0
+41 1 0
+164 1 1
+61 4 4
+925 0 3
+934 18 18
+1971 0 5
+3592 1 1
+76 1 1
+200 0 6
+682 1 0
+632 2 0
+2338 1 0
+110 1 1
+231 10 0
+1682 42 54
+616 1 2
+171 2 1
+543 1 1
+45 0 12
+2837 1 0
+441 2 0
+4958 5 5
+455 37 37
+330 22 22
+711 46 46
+184 49 49
+153 61 62
+392 11 11
+1266 8 7
+241 42 41
+198 31 31
+1064 78 78
+528 0 4
+431 1 0
+108 64 53
+358 5 5
+566 35 33
+168 1 0
+251 41 41
+880 33 33
+248 7 9
+583 3 4
+217 41 41
+117 13 14
+203 78 78
+133 44 45
+59 43 43
+129 19 19
+887 1 0
+264 30 30
+352 16 16
+719 36 35
+196 49 49
+425 4 0
+358 15 15
+151 22 22
+714 0 3
+165 41 0
+199 134 134
+504 47 47
+526 12 16
+206 39 39
+372 6 6
+224 25 25
+304 7 7
+186 90 90
+1872 0 3
+1066 7 7
+180 85 75
+63 37 37
+157 65 65
+331 3 0
+302 3 6
+213 42 45
+350 45 49
+580 42 45
+252 43 43
+337 4 0
+667 10 7
+94 9 9
+441 18 18
+124 0 1
+277 42 42
+1729 37 37
+1562 3 1
+546 15 13
+409 22 22
+312 45 45
+46 0 2
+268 14 14
+1166 35 38
+460 0 2
+74 0 1
+323 27 26
+2747 24 28
+322 10 0
+592 23 21
+161 45 45
+207 50 50
+409 22 23
+188 50 49
+396 152 151
+343 26 28
+3430 49 49
+2161 72 72
+1696 5 0
+389 50 50
+340 23 23
+169 0 3
+70 0 4
+392 0 1
+106 32 32
+2476 23 23
+1397 53 54
+2187 18 18
+489 9 9
+2018 4 0
+108 17 14
+836 5 5
+417 48 48
+358 34 34
+481 55 56
+277 48 48
+180 25 21
+356 3 0
+66 66 66
+407 28 27
+603 36 36
+1239 0 3
+194 8 8
+444 0 1
+204 35 35
+162 15 15
+418 6 5
+236 9 9
+55 52 52
+105 145 146
+57 143 143
+52
+
+chain 868538 15 102531392 + 21886534 21896633 15 100338915 + 19140000 19150000 4870
+1208 1 0
+245 165 68
+494 89 89
+824 15 15
+196 0 1
+197 50 50
+274 0 1
+1127 15 15
+230 4 0
+76 48 49
+671 0 1
+352 24 19
+117 11 11
+288 5 4
+122 0 3
+135 37 37
+265 0 2
+62 2 0
+656 0 2
+792 69 69
+142 73 73
+307 2 0
+331 0 2
+378
+
+chain 566185 15 102531392 + 83551634 83557670 8 146274826 + 129534406 129540446 9431
+549 1 1
+105 1 1
+1154 0 4
+273 6 6
+3947
+
+chain 334937 15 102531392 + 21896662 21900709 15 100338915 + 19150028 19154088 190582
+86 46 44
+567 11 9
+733 23 25
+212 2 0
+100 40 40
+155 1 0
+189 34 34
+165 42 42
+219 56 68
+259 61 62
+380 3 8
+242 13 13
+408
+
+chain 246244 15 102531392 + 22183221 22212114 15 100338915 + 19767012 19795905 936
+45 207 207
+50 619 619
+50 396 396
+152 343 343
+26 3430 3430
+49 2161 2161
+72 2090 2090
+50 1100 1100
+32 3896 3896
+53 6108 6108
+48 358 358
+34 481 481
+55 277 277
+48 180 180
+25 425 425
+66 407 407
+28 603 603
+36 2089 2089
+35 901 901
+52 105 105
+145 57 57
+143 52 52
+1314
+
+chain 136774 15 102531392 + 21885000 21886534 15 100338915 + 19138465 19140000 942717
+402 49 49
+445 0 1
+638
+
+chain 38827 15 102531392 + 28705151 28710237 15 100338915 - 73838719 73843805 82
+5086
+
+chain 9597 15 102531392 + 29116154 29116267 19 63811651 - 22308947 22309060 23761910
+59 4 4
+50
+
+chain 6273 15 102531392 + 23685556 23685849 15 100338915 + 21236652 21236834 12713809
+67 205 94
+21
+
+chain 4893 15 102531392 + 29111049 29111100 21 46944323 + 41885809 41885860 33898070
+51
+
+chain 3039 15 102531392 + 22178426 22178458 8 146274826 + 6100529 6100561 34349851
+32
+
+chain 2975 15 102531392 + 22826750 22826789 15 100338915 + 20381852 20381891 2718765
+39
+
+chain 2542 15 102531392 + 21049663 21065195 18 76117153 + 14510749 14526638 994
+38 2128 2130
+28 13310 13665
+28
+
+chain 1826 15 102531392 + 20950735 20950759 19 63811651 - 51273213 51273237 15159639
+24
+
+chain 1062 15 102531392 + 21028626 21028659 21 46944323 - 32992576 32992609 1118
+33
+
+chain 912 15 102531392 + 22826789 22826824 15 100338915 + 20377303 20377338 985154
+35
+
+chain 7474990131 16 90354753 + 60000 90294753 16 88827254 + 0 88822254 17
+172343 1 0
+111 0 1
+5627 1 2
+8398838 50000 17500
+25336229 150000 100000
+1112651 11100000 9800000
+42003582 50000 20000
+1855370
+
+chain 7369719958 17 81195210 + 0 81060651 17 78774742 + 0 78654742 18
+252627 1 1
+24 1 1
+41 29 0
+295 0 29
+261 0 58
+116 0 58
+94 0 29
+79 37 8
+485 59 1
+28 1 1
+76 1 233
+26 0 29
+2765 1 0
+17 2 0
+2220 18 18
+343 37 37
+457 1 1
+39 1 1
+564 16 16
+2523 9 39
+1878 56 0
+22 0 29
+1681 1 0
+414 3 0
+282 68 0
+93 10 10
+293 4 0
+3190 0 1
+2562 4 0
+1809 0 3
+84 1 1
+62 1 1
+3775 27 0
+1968 0 16
+912 2 0
+696 4 4
+1428 15 15
+290 0 1
+1779 1 0
+60 1 1
+216 1 0
+375 1 1
+41 1 0
+9221 100000 46522
+3080543 1 0
+1208216 2 0
+1370 0 2
+1279 4 0
+322 5 0
+5660 0 210
+308 22 21
+973 0 8
+2901 0 1
+8479 1 0
+4122 0 7
+3187 0 4
+571 1 0
+167 1 0
+10174 7 7
+856 1 2
+1630 0 1
+4258 1 3
+1688 0 1
+388 304 0
+672 0 1
+8495 10 0
+2272 0 1
+8297 0 1
+1500 4 1
+733 2 37
+57 17 0
+51 532 42
+2085 0 2
+52 1 1
+2913 13 14
+1309 1 0
+3991 0 3
+1939 3 0
+887 2 0
+463 0 18
+64 3 0
+2104 20 0
+557 4 0
+120 1 0
+3670 0 2
+4347 5394 0
+5332 1 0
+2505 10 4
+6776 11 14
+9573 1 0
+1136 2 0
+3754 0 1
+4588 0 1
+637 17 17
+1283 0 8
+371 1 0
+2084 0 1
+492 0 2
+519 4 0
+952 2 0
+1517 0 1
+987 0 9
+1152 10 0
+3608 2 0
+3199 39 0
+734 0 1
+646 0 2
+2211 0 1
+14829 0 1
+3473 34 1
+22 0 11
+2194 1 0
+6443 4 5
+2627353 0 1
+11581974 43 0
+31 89 0
+238782 1 0
+1830653 0 1
+419873 116477 100008
+5586 0 6
+11057 2 0
+3240 0 1
+1237 2 0
+373 1 1
+43 1 1
+558379 3000000 100000
+1823446 1 0
+2728383 1 0
+29 1 0
+138 0 1
+144 8 6
+38 2 0
+7 1 0
+18 1 1
+70935 1 0
+10 2 0
+52 31 28
+189 1 0
+41 2 2
+750363 44 44
+4038953 50039 100039
+1523967 1 1
+47 1 1
+231 0 2
+1175 0 1
+555 1 1
+49 1 1
+566 0 7
+607 0 2
+4954 1 1
+18 7 6
+567 1 0
+421 0 2
+1010 0 8
+777 3 0
+925 5 12
+318 0 1
+230 13 20
+244 1 1
+13 1 0
+42 1 1
+220 1 1
+56 1 1
+101 0 225
+1113 0 1
+17 1 1
+2614 0 4
+7108 2 0
+617 0 14
+5674 2 0
+1852 1 1
+63 1 1
+56 1 1
+25 1 1
+332 6 0
+423 5 5
+61 0 4
+108 1 1
+46 1 1
+160 2 2
+72 1 1
+162 1 1
+20 1 1
+53 1 1
+63 1 1
+112 1 1
+59 1 1
+5885 0 2
+5871 30040 159230
+925 0 5
+214 7 7
+641 17 17
+1296 46 46
+2513 69 71
+76 2 1
+57 0 50226
+1963 18 18
+2694 55 55
+6616 0 1
+5106 18 0
+2521 7 7
+49 0 10
+3440 4 0
+4179 4 0
+2749 1 0
+1125 0 8
+55 1 1
+1840 14 14
+624 0 8
+1742 0 4
+3690 4 0
+2051 1 0
+751 1 0
+2111 11 10
+3110 0 1
+682 0 1
+2795 2 5
+241 1 0
+165 3 1
+1258 1 0
+1601 0 5
+3716 1 0
+1308 1 0
+2058 0 1
+1624 1 0
+478 0 4
+9 0 6
+35 1 3
+47 1 0
+2425 0 1
+1178 4 0
+33 1 1
+415 5 5
+887 3 1
+1605 0 15
+259 0 2
+78 1 0
+4570 1 0
+322 0 1
+1801 0 2
+836 0 3
+1509 1 0
+1732 1 0
+936 6 0
+1371 0 1
+625 12 2
+5009 1 1
+75 1 0
+20 0 1
+139 1 0
+523 3 0
+11 319 0
+1368 0 1
+774 1 1
+16 1 1
+3523 119 124
+497 0 4
+174 0 9
+1317 3 0
+508 1 0
+1126 0 1
+1952 2 0
+565 0 2
+871 1 0
+1460 0 6
+55 1 0
+420 0 6
+57 1 1
+119 1 1
+427 0 1
+459 11 14
+448 1 0
+1275 7 7
+360 0 1
+73 1 1
+48 1 1
+4920 0 3
+713 1 1
+21 0 3
+6 0 3
+6 0 1
+691 1 1
+44 1 1
+1158 38 38
+446 10 9
+566 1 0
+175 4 0
+796 10 0
+810 0 1
+78 17 18
+1531 2 0
+1274 1 1
+39 1 1
+53 1 3
+202 1 0
+707 17 17
+1733 1 0
+1540 42 42
+12471 0 3
+286 1 3
+5600 0 4
+6458 1 0
+4866328 0 102000
+1870126 0 257
+590080 18 6
+26953 0 1
+6737 4 0
+5946 0 1
+2319 4 0
+1641 1 1
+27 1 1
+1237 0 1
+2698 1 1
+140 1 1
+1689 2 0
+836 30 29
+5333 0 1
+509 0 1
+224 9 9
+4983 0 6
+4981 30 30
+6913 3 13
+1039 1 0
+11605 0 1
+22064 1 0
+16612 0 8
+902 0 1
+757 0 1
+84 46 46
+489 1 0
+10979 1 1
+18 1 1
+1517 0 1
+4576 0 1
+12558 0 4
+2726 1 0
+5291 0 2
+8706 1 0
+83 0 1
+406 7 0
+87 0 38
+5531 0 1
+23971 0 1
+7855 22 54
+4095 1 0
+803 5 5
+6382 0 6
+3546 28 0
+4264 2 0
+13194 6 6
+6463 0 1
+26075 1 1
+59 1 1
+10791 7 17
+707 1 0
+210 0 1
+1655 2 0
+5301 0 1
+1930 0 1
+14632 0 2
+1043 0 1
+3607 0 3
+312 1 0
+5953 0 2
+170 17 0
+489 1 0
+5260 28 0
+888 0 10
+2461 10 10
+237 0 2
+1716 1 3
+10694 4 0
+3754 0 1
+6173 1 0
+8017 2 1
+3594 4 0
+5439 1 0
+4137 14 0
+29 15 0
+6418 1 0
+1267 0 1
+723 6 0
+1080 0 2
+3878 1 0
+7682 1 1
+44 1 1
+3135 1 0
+174853 2 1
+2008 7 7
+5657 1 0
+6496 3 0
+89 5 0
+665 1 0
+954 1 1
+44 1 1
+375 8 7
+3317 2 0
+2753 0 1
+1863 3 0
+3228 0 1
+3571 49 45
+6488 2 0
+8451 172 172
+3797 16 0
+2103 1 0
+268 23 26
+7888 0 4
+701 0 4
+2402 6 0
+37 1 1
+2943 3 2
+8420 0 1
+932 324 0
+6726 0 1
+543 3 4
+4028 0 18
+88 4 0
+2999 0 1
+530 0 1
+1153 11 11
+919 2 0
+1174 17 0
+118 16 16
+2727 0 1
+543 1 0
+783 0 1
+1374 4 0
+8619 0 20
+281 44 44
+4364 50 51
+2856 1 0
+5399 1 0
+1506 0 1
+919 6 0
+7228 0 10
+3226 0 1
+435 0 1
+4463 132 0
+9760 1 0
+2034 0 6
+7656 0 1
+198212 132 0
+11700 5 0
+7647 0 1
+9062 0 4
+8778 2 0
+7014 0 1
+1613 2 0
+790 5 7
+7433 0 1
+6482 12 12
+6798 1 0
+1422 0 1
+3454 1 1
+43 1 1
+3097 2 0
+334 18 0
+1444 0 1
+2400 0 3
+3272 1 0
+9106 0 1
+1573 1 0
+4742 0 1
+3366 0 1
+5484 1 0
+2445 5 0
+5447 8 8
+2539 1 0
+1471 1 0
+238 1 1
+16 1 1
+288 5 5
+2995 2 0
+951 1 1
+35 1 1
+279 15 16
+3534 0 6
+3513 1 0
+163 1 0
+6173 1 0
+1074 0 1
+2818 0 1
+2868 1 0
+3796 0 1
+1118 167 1
+1278267 25 25
+10747175 217 0
+3504874 1053 0
+10844 11 13
+18805 0 1
+1960834 50000 126729
+3065 0 1
+3601036 8833 90008
+34292 0 1
+376 14 14
+1447 44 0
+3080 1 1
+43 1 1
+789 0 1
+11432680 50000 153000
+1902016 4098 0
+102 21 0
+3179 6 6
+877 1 1
+49 1 1
+296 1 0
+1375 1 1
+21 1 1
+607 5 5
+98 22 0
+6811 1 1
+17 11 0
+3804 0 1
+1356 1 1
+29 1 1
+297 0 1
+9543 2 0
+3131 4 0
+860 1 0
+27346 0 1
+7553 0 2
+2834 2 0
+394 0 4
+6322 44 44
+158 0 1
+405 8 11
+1128 0 7
+271 1 1
+21 28 0
+504 0 6
+1214 31 44
+384 3 0
+521 18 18
+392 0 11
+802 1 1
+25 2 3
+51 49 1
+49 1 1
+558 1 0
+351 0 1
+2779 13 13
+114398 82124 65008
+7795 1 0
+18 1 1
+4140 0 1
+28048 1 1
+32 1 1
+4630 0 1
+4573 0 3
+357 0 2
+4812 0 1
+14372 3 0
+203 1 0
+26257 0 1
+2734 2 0
+19262 5 5
+5022 1 0
+25471 1 0
+1114538 53 0
+82 0 126
+1416 16 16
+610 0 57
+482 0 1
+148 1 1
+24 1 1
+2322 1 1
+23 0 1
+719 16 0
+20 0 16
+105 9 9
+1277 1 0
+2498 1 0
+352 0 49
+50 50 0
+21 49 0
+28 49 0
+60 47 0
+17 97 0
+901 47 0
+272 14 1104
+279 1 0
+37 12 11
+65 32 0
+18 94 0
+60
+
+chain 2732964 17 81195210 + 36295616 36336227 17 78774742 - 45363365 45403960 362
+666 1 1
+114 1 1
+1777 1 1
+22 1 1
+2481 3 0
+947 3 1
+994 1 1
+26 1 1
+5327 2 0
+95 13 13
+2424 0 1
+339 2 1
+288 1 0
+1180 8 8
+1145 2 4
+1144 1 0
+322 1 0
+28 1 0
+35 1 0
+1499 0 1
+1258 7 6
+1123 0 1
+269 5 4
+1850 18 19
+188 3 0
+403 1 1
+18 1 1
+3148 1 1
+160 1 1
+105 11 0
+573 10538 10545
+33
+
+chain 30167 17 81195210 + 44458173 44458487 2 242951149 - 34181426 34181740 4632506
+314
+
+chain 29586 17 81195210 + 36420504 36420817 7 158821424 - 10371995 10372309 4828537
+136 0 1
+177
+
+chain 20882 17 81195210 + 56914122 56914339 X 154913754 + 31643322 31643539 5151267
+217
+
+chain 16484 17 81195210 + 44491151 44521781 17 78774742 + 42064051 42094670 662
+44 30454 30443
+132
+
+chain 14999 17 81195210 + 44428451 44428612 17 78774742 + 42001706 42001867 887
+161
+
+chain 12695 17 81195210 + 44739444 44739576 17 78774742 + 41877181 41877313 13974721
+132
+
+chain 12494 17 81195210 + 19077136 19077299 17 78774742 - 59726399 59726562 431
+43 31 31
+89
+
+chain 7858 17 81195210 + 253568 254148 17 78774742 + 253365 253974 1160836
+37 486 515
+57
+
+chain 5202 17 81195210 + 79704633 79704687 Y 57772954 - 54321400 54321454 32857515
+54
+
+chain 5149 17 81195210 + 36426505 36456524 17 78774742 - 35824084 35853324 896
+73 1 1
+45 29858 29079
+42
+
+chain 3754 17 81195210 + 60419213 60419252 8 146274826 - 11845696 11845735 33181261
+39
+
+chain 3753 17 81195210 + 44413461 44413510 17 78774742 - 18492830 18492879 715
+49
+
+chain 2637 17 81195210 + 252694 252723 17 78774742 + 252810 252839 1426666
+29
+
+chain 2581 17 81195210 + 81166856 81166888 1 247249719 + 441705 441737 997
+32
+
+chain 1872 17 81195210 + 79585571 79585619 11 134452384 + 72960908 72960956 2849402
+48
+
+chain 7055977505 18 78077248 + 10000 78016181 18 76117153 + 0 76117153 19
+15400898 3100000 1363998
+28218587 15 15
+5329636 150000 47000
+3667310 18 0
+16406889 50000 28008
+3388467 50000 22000
+2103304 0 3
+136125 1 0
+7 1 0
+647 1 0
+1543 1 0
+25 14 8
+19 2 0
+10 7 4
+9 4 2
+663 1 0
+359 1 0
+1617
+
+chain 5307806876 19 59128983 + 60000 59114839 19 63811651 + 11000 63806651 21
+7286004 50000 5000
+1291194 45000 0
+11772188 69160 0
+4058236 3100000 8000000
+20129228 2 0
+701 0 3
+347 1 1
+31 1 1
+1833 0 3
+1984 1 1
+47 1 1
+190 1 1
+34 1 1
+889 2 0
+1413 7 0
+2680 4 0
+375 1 0
+314 4 0
+29 1 0
+69 0 1
+3881 1 1
+40 12 0
+293 14 0
+1479 1 0
+233 1 1
+45 1 1
+1049 1 0
+1766 7 44
+220 0 3
+537 7 0
+351 8 8
+3603 1 1
+17 0 3
+697 0 1
+269 0 3
+974 5 6
+96 10 0
+1096 10 10
+1177 12 14
+1141 9 12
+1090 0 1
+175 16 0
+1063 0 4
+4780 44 44
+722 0 1
+548 2 2
+44 1 1
+424 2 2
+26 1 0
+4 0 1
+82 1 1
+59 1 1
+2087 15 0
+1499 0 1
+1754 0 2
+11209362
+
+chain 1655749 19 59128983 + 20505321 20523415 19 63811651 + 20366320 20387252 1476
+2041 4 4
+5604 0 2
+363 0 1
+2655 5 2857
+153 46 46
+705 79 83
+370 6 1
+1668 27 26
+347 21 0
+191 6 6
+369 0 2
+393 68 67
+328 0 6
+2049 1 0
+464 35 35
+96
+
+chain 207934 19 59128983 + 59114839 59117224 22 49691432 + 49588728 49591432 1471
+992 1 1
+63 1 1
+125 152 154
+174 1 1
+47 3 0
+214 5 5
+254 1 1
+67 1 1
+55 1 321
+72 14 14
+142
+
+chain 126422 19 59128983 + 59117224 59118680 10 135374737 + 135372723 135373917 1944
+177 13 13
+165 1 1
+156 1 1
+205 4 4
+93 1 1
+14 5 0
+88 1 1
+110 1 1
+52 2 1
+28 2 1
+14 255 0
+68
+
+chain 13558 19 59128983 + 59116021 59116173 2 242951149 - 128870722 128870873 1493
+33 1 0
+24 1 1
+57 1 1
+35
+
+chain 7358 19 59128983 + 59118906 59118983 21 46944323 + 46944213 46944290 27502546
+77
+
+chain 3811 19 59128983 + 20573506 20573546 19 63811651 - 43994109 43994149 26416662
+40
+
+chain 174 19 59128983 + 47898161 47898204 18 76117153 + 27836426 27836469 20429401
+43
+
+chain 22466185064 2 243199373 + 10000 243102476 2 242951149 + 0 242751149 1
+1201236 0 1
+2057 1 1
+26 1 1
+4043 22 0
+82 7 101
+33 84 0
+26 1 23
+67 48 0
+176 318 0
+40 92 0
+33 0 74
+62 0 6
+22 0 118
+387 2446 0
+843 2450 0
+167 2304 0
+21342 1 1
+50 4 0
+2040 0 4
+9053 2 0
+88 3 53
+1078 0 1
+4122 1 0
+1608 28 1
+4029 0 9
+967 4547 1000
+420 27 0
+2237126 0 1
+2458 17 17
+4595 4 0
+3531 14 14
+3954 51129 50000
+1426129 160449 100025
+11087286 0 3
+773 103977 50000
+1576 0 1
+240 0 1
+318 2 0
+255 0 16
+2851 10 10
+1404 1 1
+27 1 1
+703 13 0
+375 0 1
+4783388 35000 25000
+848 0 2
+1225 0 2
+391 1 0
+3653 1 1
+28 1 1
+49 0 4
+4514 0 9
+9628 1 9
+1483 7 7
+1990 0 1
+1949 1 0
+2716230 1 0
+7799848 851 851
+38932068 5 9
+9477928 0 3
+7529698 72396 0
+1891551 294073 150000
+17672 1 0
+5792 1 0
+9017 0 266
+2944 0 1
+9388 2 0
+37828 4 0
+23436 0 4
+290931 1273578 1000000
+731068 3000000 3000000
+2558421 0 1
+1197 10 0
+685 42 46
+2309 0 1
+1332 22 23
+344 0 1
+1645 4 4
+4093 25 25
+2446 1 0
+6329 1 0
+769 0 1
+873 7 0
+1299 0 1
+8250 15 15
+4291 10626 12548
+1063 103 0
+75 0 218
+5897 1 1
+33 1 1
+9905 51 37
+1711 1 1
+45 1 1
+1597 4 4
+61 1 1
+869 13 0
+1633 15 15
+1179 3 0
+2819 0 2
+156 88 465
+100 0 25
+4753 0 8
+4903 6 6
+3847 0 2
+108126 0 145
+3542 1 0
+10276 0 1
+402 1 1
+47 1 1
+63 2 0
+583 1 1
+34 1 1
+8974 0 46
+379 1 1
+70 1 1
+2474 0 102
+1756 0 1
+8426 0 1
+11986570 151150 142000
+14207 1 1
+49 1 1
+1781 0 12
+409 1 0
+1874 1 1
+33 1 1
+4795 2 0
+3686 1 1
+15 1 1
+164 2 0
+7287 5 5
+702023 72796 150000
+69 1 0
+1598 0 1
+1340 0 1
+1030 0 4
+1166 10 10
+6406 1 1
+34 1 1
+3283 2 4
+496 1 23
+25 10 0
+40 1 1
+21282 2 1
+1406 0 44
+937 17 0
+18255 1 0
+172366 0 281526
+40517 0 406
+58864 1 2
+1843 0 2
+14994 0 1
+12992 2 0
+2571146 1 0
+35688061 108224 100000
+29671719 1 0
+39665349 1 0
+14876089 64197 20000
+401 0 3
+1831 1 1
+61 1 1
+654 11 1
+127 0 28
+116 25 29
+74 9 9
+3247 2 0
+1355 1 0
+816 1 0
+21 3 0
+526 1 1
+60 1 1
+773 1 0
+1494 1 0
+1683 1 0
+21 1 1
+596 1 0
+1582 1 0
+425 0 3
+1139 0 8
+138 144 813
+71 1 0
+385638 1 1
+219 1 1
+51 7 7
+54 15205 15205
+54 7 7
+51 1 1
+110 1 1
+5198249 0 1
+115 80 0
+60 40 0
+80 100 20
+442 1 1
+35 1 1
+119 9 129
+14 0 40
+61 1 1
+85 0 40
+1331 0 1
+1194 12 14
+1773 0 5
+1623 1 1
+25 1 1
+2422 21 22
+2315 0 1
+31 1 1
+1508 0 3
+50 0 4
+970 6 6
+7234 4 0
+1228 1 0
+1233 8 1
+4207 1 1
+41 1 1
+1715 50 50
+1532 0 2
+1714 2 0
+2299 2 0
+2143 1 1
+18 1 1
+917 1 0
+1082 1 1
+49 1 1
+9098 0 4
+5529 0 1
+3266 0 8
+894 6 0
+1440 1 1
+2095 2 0
+4179 18 13
+1785 0 1
+1674 0 6
+1217 32348 33000
+287 17 23
+40 173 0
+20 161 0
+13 66 0
+12 71 1
+12548 30000 30000
+952154 41011 25000
+1914 1 0
+225 1 1
+57 1 1
+2910 0 1
+471 1 0
+1956 1 1
+43 1 1
+991 0 92
+2863 3 0
+1838 306 0
+1006 30 0
+206 1 1
+27 0 3
+221 17 17
+1525 8 0
+413 1 1
+32 2 2
+1573 12 12
+2258676
+
+chain 8298836 2 243199373 + 90373613 90527957 2 242951149 + 90958828 91114560 236
+29837 32 32
+212 25 25
+508 90 90
+1291 33 33
+2574 1 0
+833 28 28
+2712 0 1
+805 10 5
+565 68 68
+75 69 57
+176 58 513
+63 105 105
+336 33 33
+69 1 0
+280 4 4
+111 12 12
+523 1 0
+136 55 56
+198 0 1
+630 0 1
+362 42 42
+405 30 30
+78 5 0
+125 5 0
+75 140 0
+166 49 49
+1653 30 30
+3790 5 5
+500 21 21
+577 23 23
+180 0 1
+1105 1 0
+231 4 4
+333 33 33
+852 2 0
+2709 16 16
+476 28 28
+53 33 57
+256 0 3
+900 0 1
+227 0 2
+718 0 2
+244 42 42
+302 30 30
+211 21 21
+1809 16 17
+204 33 32
+341 9 9
+176 0 5
+180 67 67
+73 39 39
+369 49 49
+52 9 15
+699 9 13
+142 0 4
+184 0 4
+248 27 26
+306 10 10
+63 20 20
+533 22 22
+432 86 85
+97 19 19
+383 19 23
+642 10 9
+156 88 88
+217 0 6
+1798 9 7
+425 0 4
+1191 0 4
+465 40 37
+671 7 7
+450 0 1
+714 31 32
+682 38 15
+230 28 1076
+95 220 261
+80 1967 0
+118 383 158
+81 28 2
+247 0 1
+181 0 1
+702 47 47
+361 39 39
+300 50 50
+195 9 9
+179 35 35
+228 0 10
+321 65 65
+233 20 20
+368 35 35
+1436 37 37
+985 5 5
+140 73 73
+1031 25 25
+957 51 51
+690 23 48
+1047 49 49
+186 1 0
+244 4 4
+166 16 16
+173 1 0
+387 51 51
+122 59 58
+141 1 0
+72 102 84
+75 203 201
+276 30 30
+367 20 20
+105 67 68
+82 0 1
+386 7 7
+68 61 61
+514 56 56
+92 91 91
+268 89 89
+200 4 4
+526 33 36
+370 10 10
+366 20 26
+1107 0 2
+130 74 74
+101 0 1
+542 32 34
+179 43 43
+151 84 84
+421 25 25
+332 1 0
+561 64 65
+1406 10 10
+161 97 88
+564 27 30
+123 29 33
+170 0 1
+183 94 94
+52 4 0
+379 83 83
+237 32 31
+187 46 46
+236 728 703
+50 1494 1865
+72 67 32
+25 1732 6535
+52 52 52
+104 647 648
+27 494 471
+23 0 137
+1 1884 302
+115 8 8
+76 3078 388
+26 200 44
+59 2295 2292
+40 1854 1861
+54 2541 2546
+27 28 27
+57 56 56
+26 2212 2216
+181 494 652
+42 2237 2213
+40 2572 2562
+36 1791 1791
+34 2776 2807
+23 7115 7113
+44 509 509
+36 664 665
+43 1891 2219
+36 256 256
+31 276 289
+42 881 1734
+67 149 144
+49 190 190
+73 357 345
+30 1074 1075
+42 1850 1850
+47 469 481
+24 2460 2482
+41 3325 3319
+32 306 296
+26
+
+chain 2305993 2 243199373 + 243162866 243189340 16 88827254 - 5000 31222 1142
+136 9 9
+870 16 16
+229 1 1
+44 1 1
+330 10 14
+243 1 1
+93 1 1
+58 1 1
+144 1 1
+62 95 95
+333 1 1
+77 1 1
+494 9 11
+230 8 8
+61 12 13
+128 14 14
+123 1 1
+68 1 1
+4208 5 1
+1989 71 0
+121 1 1
+35 1 1
+1498 59 0
+443 69 69
+237 1 1
+45 1 1
+75 1 1
+32 2 1
+20 1 1
+152 1 1
+129 0 1
+1040 1 1
+70 2 0
+128 1 1
+50 1 1
+605 9 8
+62 1 1
+155 1 1
+50 11 6
+94 1 1
+409 1 1
+34 1 1
+217 1 1
+39 1 1
+287 0 9
+102 1 1
+56 30 26
+64 108 0
+127 1 0
+373 1 1
+18 1 1
+194 1 1
+10 1 1
+98 1 1
+67 1 1
+184 1 1
+21 1 1
+86 0 1
+44 1 1
+50 15 15
+177 1 1
+72 1 1
+222 1 1
+44 1 1
+50 1 1
+46 1 1
+449 1 1
+118 1 1
+127 0 1
+242 1 1
+36 1 1
+710 4 4
+69 1 1
+87 1 1
+115 1 1
+68 17 0
+12 2 1
+14 0 12
+36 4 0
+102 1 1
+105 24 24
+131 18 18
+64 19 19
+293 1 1
+43 1 1
+134 25 25
+77 14 14
+225 1 0
+93 1 1
+363 11 11
+271 25 25
+136 1 1
+36 1 1
+102 4 4
+29 1 1
+51 2 0
+162 0 4
+61 1 0
+65 1 1
+26 4 4
+140 17 17
+336 1 1
+25 1 1
+408 16 16
+311 27 27
+90 7 7
+449 1 1
+47 1 1
+133 1 1
+62 7 7
+194 1 1
+13 3 0
+54 2 0
+28 1 1
+72 1 1
+45 1 1
+65 1 1
+23 1 1
+279 1 1
+61 1 1
+55
+
+chain 1358560 2 243199373 + 89890737 90543561 2 242951149 - 153539598 155537136 99
+8973 0 1
+939 0 1
+4351 0 2
+2413 1 1
+37 1 1
+515 1 0
+224 1 1
+22 1 1
+203 1 1
+18 1 1
+249 8 7
+830 4 0
+177 1 0
+30 1 1
+224 1 1
+75 1 1
+243 1 1
+20 0 5
+2724 0 137
+439 1 1
+35 1 1
+444 0 2
+1484 1 1
+41 1 1
+395 1 1
+40 1 1
+417 1 1
+44 1 1
+909 1 1
+32 24 14
+1057 2 2
+46 1 1
+306 1 1
+32 3 0
+269 10 10
+535 10 10
+615 1 1
+42 1 1
+1295 1 1
+21 1 1
+84 1 1
+30 0 1
+19 1 1
+434 57 57
+283 15 15
+304 12 12
+149 17 17
+1413 1 1
+32 1 1
+66 550910 1890523
+54 205 14
+64 147 86
+119 57 8
+71 27 96
+100 1265 73
+307 7 9
+182 31 30
+128 15 15
+95 61 59
+92 20 296
+50 77 75
+255 261 3338
+95 264 262
+204 53 55
+136 81 81
+173 62 57
+130 77 76
+241 35 35
+424 0 154
+42 3 3
+109 0 434
+68 0 59
+215 1 1
+47 1 1
+109 0 180
+10 4 0
+21 7 104
+33 31 37
+62 17 17
+114 1 1
+50 0 9
+117 9 0
+63 1 1
+92 1 1
+37 146 0
+49 956 0
+32 163 4
+37 619 0
+42 1 1
+108 973 20
+91 1 18
+215 19 19
+20 26 0
+124 56 0
+14 65 0
+65 1 1
+465 1 1
+45 1 0
+126 1 1
+46 1 1
+1501 1 1
+41 40 0
+58 2 5
+574 8 0
+830 0 5
+121 0 3
+26 0 2
+52 0 2
+183 54 0
+1069 1 1
+62 4 0
+23 1 1
+62 0 3
+233 0 2
+32 3 0
+1051 112 112
+56 26 26
+59 7 7
+588 17 18
+401 18 18
+472 1 0
+398 2 3
+249 181 22
+397 0 158
+97 42 42
+1302 24 2
+162 9 9
+740 40 40
+554 0 1
+1362 23 19
+249 12 12
+372 36 36
+987 1 0
+221 10 8
+394 9 9
+169 34 36
+170 1 1
+27 1 1
+61 1 0
+396 0 120
+152 1 13
+60 0 5
+12 1 1
+145 1 1
+51 1 1
+847 6 6
+420 1 1
+46 1 0
+43 1 1
+145 1 1
+41 1 1
+142 25 24
+332 14 14
+310 1 1
+91 1 1
+605 1 1
+47 1 1
+361 10 10
+183 0 5
+672 8 8
+76 17 20
+227 1 1
+86 1 1
+60 1 0
+30 5 5
+2399 1 1
+29 1 1
+547 10 17
+195 3 0
+609 3 0
+175 44 44
+292 8 8
+209 36 37
+543 39 39
+82 43 43
+235 38 38
+760 20 20
+502 8 0
+108 7 18
+66 2 0
+57 0 3
+88 36 36
+77 0 15
+94 24 24
+61 31 1532
+146 38 41
+92 82 77
+151 0 2606
+94 93 1000
+189 50 50
+234 100 94
+146 49 49
+189 74 74
+62 37 17
+258 30 30
+114 47 47
+494 96 98
+323 42 43
+106 20 20
+142 250 250
+161 7 7
+651 21 21
+492 237 249
+144 23 23
+88 48 48
+52 15 15
+201 6 0
+105 29 29
+68 18 18
+87 50 50
+227 147 147
+176 17 17
+404 9 9
+457 0 23
+392 41 41
+196 18 18
+99 77 80
+219 52 53
+156 0 7
+323 28 28
+99 43 42
+229 27 27
+156 107 103
+95 1 0
+1118 0 1
+282 41 41
+172 21 3
+104 26 0
+21 1 71
+54 6 76
+63 1 1
+58 1 1
+84 1 1
+285 1 1
+46 1 1
+320 15 15
+326 7 7
+170 1 1
+73 1 1
+214 1 1
+40 1 1
+613 1 0
+772 0 2
+424 1 1
+34 1 1
+423 1 1
+33 1 1
+1157 1 1
+43 2 2
+82 1 1
+21 1 1
+65 1 1
+62 1 1
+250 1 1
+79 1 1
+88 2 2
+79 1 1
+68 11 11
+115 1 1
+38 1 1
+63 9 0
+39 1 1
+73 1 1
+77 3 3
+55 1 1
+46 1 1
+157 1 1
+58 0 2
+92 1 1
+67 1 1
+48 1 1
+289 1 1
+40 1 0
+398 1 1
+31 1 1
+729 1 1
+72 1 1
+575 1 1
+86 1 1
+495 3 0
+472 1 1
+34 1 1
+87 1 0
+28 1 1
+441 20 0
+31 1 1
+61 1 1
+152 5 5
+774 0 1
+114 2 0
+355 0 3
+415 5 0
+76 1 1
+18 1 1
+308 1 1
+18 1 1
+226 4 4
+490 0 3
+104 1 1
+47 1 1
+542 6 6
+131 8 0
+152 49 1
+68 9 9
+198 1 1
+40 0 10
+78 1 1
+108 1 1
+73 1 1
+50
+
+chain 1317324 2 243199373 + 234472598 234486532 2 242951149 - 8801149 8815083 1658
+13934
+
+chain 1182591 2 243199373 + 111018489 111031067 2 242951149 - 132350497 132363075 1985
+750 1 0
+155 1 0
+2029 0 1
+2687 0 1
+2417 3 0
+3105 1 3
+965 35 36
+238 6 6
+185
+
+chain 907761 2 243199373 + 111000659 111010676 2 242951149 + 110060000 110070000 4064
+3405 66 54
+839 0 1
+854 33 33
+1502 180 174
+250 88 88
+1904 40 40
+856
+
+chain 864618 2 243199373 + 110991361 111000659 2 242951149 + 110050705 110060000 3488
+3987 37 37
+135 34 34
+2446 4 0
+1497 0 1
+1158
+
+chain 730598 2 243199373 + 111010676 111018489 2 242951149 + 110070000 110077815 3339
+976 16 15
+4855 0 3
+320 26 26
+1620
+
+chain 247895 2 243199373 + 111031067 111033745 2 242951149 - 131778891 131781575 150672
+814 1 1
+73 1 1
+148 0 6
+1211 4 4
+426
+
+chain 233678 2 243199373 + 87718206 87726480 2 242951149 - 151887377 151890935 691
+139 0 3
+233 4 2
+36 0 1
+291 21 13
+104 28 28
+303 26 26
+314 134 82
+86 0 1
+53 4314 721
+22 22 0
+50 389 652
+54 1133 0
+17 214 6
+79 34 60
+62 59 67
+53
+
+chain 228678 2 243199373 + 243159401 243162866 1 247249719 + 217390 220668 1312
+57 88 88
+22 186 0
+101 49 49
+417 53 54
+61 3 0
+141 0 1
+198 8 8
+852 39 39
+405 56 56
+61 27 27
+589 1 1
+51
+
+chain 207578 2 243199373 + 243152688 243155284 10 135374737 - 346 2792 2690
+533 150 0
+105 1 1
+49 1 1
+260 1 1
+69 1 1
+262 1 1
+29 1 1
+1133
+
+chain 148868 2 243199373 + 243155284 243160374 5 180857866 - 20000 25834 2103
+547 1 1
+38 1 1
+431 1 1
+24 1 1
+1389 1 1
+36 1 1
+1646 57 57
+82 0 744
+6 22 22
+186 101 101
+49 417 417
+53
+
+chain 147892 2 243199373 + 97920581 97932373 2 242951149 - 145465890 145477699 123
+1513 0 1
+2596 1 1
+36 1 1
+1383 5 1
+46 4 0
+550 1 4
+1798 7 8
+158 1 29
+18 1 1
+110 1 1
+48 1 1
+1617 7 0
+723 1063 1063
+93 1 0
+9
+
+chain 133880 2 243199373 + 87666489 111064157 2 242951149 - 130965951 132771520 53
+624 23366717 1774574
+2397 0 12
+14288 0 1
+1427 1 1
+24 1 1
+1756 10 10
+83 69 69
+698 0 21
+1910 1 1
+61 1 1
+3754 0 8
+243 1 1
+33 1 1
+320 0 1
+163 1 1
+36 1 1
+809 0 1
+1762 1 1
+49 1 1
+425
+
+chain 127176 2 243199373 + 5140970 5146585 2 242951149 - 235014747 235020583 1011815
+158 1545 1830
+107 308 308
+50 129 129
+85 163 165
+62 65 65
+282 81 63
+147 650 624
+67 138 138
+59 285 285
+76 61 62
+92 72 72
+76 266 249
+70 129 128
+83 107 102
+202
+
+chain 104115 2 243199373 + 87667113 87668206 2 242951149 + 87520624 87521717 786265
+1093
+
+chain 95484 2 243199373 + 87729232 87738885 2 242951149 + 87510347 87520000 5761
+9653
+
+chain 84057 2 243199373 + 90492917 90545103 2 242951149 - 152993866 153046874 435
+28 21223 21222
+38 2087 2087
+38 134 134
+40 246 246
+45 0 255
+13 0 572
+34 189 189
+50 234 234
+30 1029 1029
+47 494 494
+96 633 633
+250 1379 1379
+190 682 682
+29 173 173
+50 227 227
+147 1809 1804
+77 219 219
+52 479 479
+28 99 99
+43 229 229
+27 156 156
+107 16787 16788
+49 628 628
+1542
+
+chain 73315 2 243199373 + 87720014 87720774 2 242951149 - 155450797 155451557 1717423
+760
+
+chain 66981 2 243199373 + 1219529 1222202 2 242951149 + 1208584 1209647 1299817
+61 279 0
+275 1051 0
+115 843 563
+49
+
+chain 64603 2 243199373 + 90371566 90373613 2 242951149 + 90963202 90965490 370989
+76 46 46
+165 47 47
+460 75 75
+51 403 393
+63 64 364
+66 168 168
+56 68 19
+69 135 135
+35
+
+chain 46427 2 243199373 + 1223650 1226709 2 242951149 + 1208645 1209604 1438302
+140 630 0
+183 167 167
+210 1050 0
+171 420 0
+88
+
+chain 36623 2 243199373 + 89847430 89848295 5 180857866 + 153976522 153977390 3635252
+54 96 96
+262 346 349
+107
+
+chain 34396 2 243199373 + 87721616 87729232 2 242951149 + 87502993 87507825 13964
+67 36 543
+1013 77 25
+569 4 4
+189 715 6
+6 94 94
+389 54 54
+542 2531 33
+70 11 11
+68 21 21
+129 10 10
+126 0 22
+162 9 0
+89 28 26
+108 298 307
+116 64 12
+21
+
+chain 31906 2 243199373 + 90476997 90485104 2 242951149 - 155439923 155448722 818134
+65 4692 1587
+31 1167 442
+62 157 183
+65 24 24
+92 31 191
+67 10 184
+32 72 0
+76 105 36
+60 4 0
+97 52 697
+66 9 0
+169 1 23
+85 272 2102
+131 95 43
+149 89 1960
+80
+
+chain 31233 2 243199373 + 239788914 239789423 2 242951149 + 239454423 239454932 2214253
+173 20 20
+161 13 13
+66 12 12
+64
+
+chain 27639 2 243199373 + 243165116 243187640 8 146274826 + 470 67316 1215
+95 9992 9923
+69 4222 48594
+49 1 1
+58 4967 4926
+25 3019 3079
+27
+
+chain 25982 2 243199373 + 16340754 16341023 3 199501827 - 118072788 118073057 6523537
+269
+
+chain 25898 2 243199373 + 1220683 1220990 2 242951149 + 1208828 1209135 2249524
+307
+
+chain 25826 2 243199373 + 87728597 87729031 2 242951149 + 87491002 87491436 712257
+28 108 108
+298
+
+chain 25128 2 243199373 + 5141270 5144398 1 247249719 + 207689145 207692170 1456022
+66 87 87
+79 23 23
+95 979 893
+74 119 119
+116 487 487
+54 893 876
+56
+
+chain 24661 2 243199373 + 16273805 16274100 4 191273063 - 182882474 182882769 7289877
+128 26 26
+141
+
+chain 19295 2 243199373 + 90372486 90373577 2 242951149 + 90976555 90977646 1336226
+61 57 57
+56 292 292
+41 202 202
+55 193 193
+134
+
+chain 19158 2 243199373 + 1225400 1225680 2 242951149 + 1208855 1209065 11144872
+180 70 0
+30
+
+chain 18303 2 243199373 + 1219198 1219473 2 242951149 + 1208603 1208808 11853376
+134 73 3
+68
+
+chain 13465 2 243199373 + 16354747 16354888 5 180857866 + 167726962 167727103 16868271
+141
+
+chain 13298 2 243199373 + 89875086 89876327 20 62435964 + 29293186 29293377 17078580
+57 350 0
+39 320 0
+36 155 0
+6 225 0
+53
+
+chain 13261 2 243199373 + 1224140 1224280 2 242951149 + 1208645 1208785 17127371
+140
+
+chain 12749 2 243199373 + 5141660 5146147 5 180857866 - 44949635 44952639 1949230
+55 641 482
+80 490 492
+69 238 238
+34 2813 1487
+67
+
+chain 11727 2 243199373 + 240838559 240838726 2 242951149 + 240487433 240487623 18443158
+86 35 58
+46
+
+chain 11295 2 243199373 + 1226909 1227026 2 242951149 + 1209530 1209647 20202652
+117
+
+chain 11288 2 243199373 + 1223295 1223413 2 242951149 + 1208990 1209108 3139804
+118
+
+chain 10759 2 243199373 + 90430195 90457119 2 242951149 - 151338126 151363320 2584
+28 2775 2822
+30 11958 12016
+40 1843 1850
+30 5080 3227
+47 361 361
+39 312 312
+38 383 383
+35 2707 2718
+36 1130 1130
+52
+
+chain 9553 2 243199373 + 89869741 89871237 Y 57772954 + 11913136 11913399 23867669
+64 1367 134
+65
+
+chain 9489 2 243199373 + 110253717 110253937 2 242951149 + 106303434 106303606 24025084
+58 106 58
+56
+
+chain 9445 2 243199373 + 1223971 1224070 2 242951149 + 1208756 1208855 24130758
+99
+
+chain 8720 2 243199373 + 1222223 1225291 2 242951149 + 1208828 1209516 2041184
+278 99 99
+79 2535 155
+77
+
+chain 8428 2 243199373 + 90482794 90485288 2 242951149 - 155439240 155441007 1572933
+56 44 44
+58 400 417
+31 1832 1088
+73
+
+chain 8213 2 243199373 + 87720809 87720895 2 242951149 + 87507349 87507434 5227216
+41 1 0
+44
+
+chain 8069 2 243199373 + 90483014 90484786 2 242951149 - 155448229 155461339 1164914
+45 110 127
+2 735 1564
+52 750 11246
+68 4 0
+6
+
+chain 7776 2 243199373 + 1217508 1217592 2 242951149 + 1207753 1207837 7243988
+84
+
+chain 7421 2 243199373 + 1226334 1226411 2 242951149 + 1209439 1209516 27381596
+77
+
+chain 7358 2 243199373 + 89880461 89880538 22 49691432 - 33895115 33895192 27502443
+77
+
+chain 7257 2 243199373 + 1219025 1219100 2 242951149 + 1208570 1208645 27695248
+75
+
+chain 7028 2 243199373 + 1220317 1225128 2 242951149 + 1208603 1209423 1749868
+42 70 0
+111 1961 0
+99 2380 420
+148
+
+chain 6973 2 243199373 + 1223223 1223295 2 242951149 + 1208568 1208640 27324023
+72
+
+chain 6924 2 243199373 + 1220268 1221195 2 242951149 + 1208974 1209200 2111755
+49 743 42
+135
+
+chain 6823 2 243199373 + 243161637 243162225 6 170899992 - 4262 4850 1512
+39 405 405
+56 61 61
+27
+
+chain 6757 2 243199373 + 1224280 1224350 2 242951149 + 1209065 1209135 28694341
+70
+
+chain 6747 2 243199373 + 1219799 1219869 2 242951149 + 1208645 1208715 25148698
+70
+
+chain 6633 2 243199373 + 89847849 89847926 14 106368585 - 28607150 28607227 5517613
+77
+
+chain 6601 2 243199373 + 239685120 239685200 2 242951149 + 239350340 239350540 24829287
+66 1 121
+13
+
+chain 6531 2 243199373 + 89865276 89865345 16 88827254 - 55053025 55053094 29215386
+69
+
+chain 6312 2 243199373 + 111004064 111004130 2 242951149 - 132336069 132336135 211650
+66
+
+chain 6255 2 243199373 + 1226201 1226267 2 242951149 + 1209586 1209652 12280449
+66
+
+chain 6049 2 243199373 + 89847131 89847195 1 247249719 + 184405152 184405216 30439720
+64
+
+chain 6014 2 243199373 + 89850535 89853562 10 135374737 - 96209116 96209251 30527518
+57 2911 19
+59
+
+chain 5970 2 243199373 + 87721480 87727902 2 242951149 + 87501266 87503920 375724
+136 1955 628
+417 2657 546
+67 36 27
+57 474 105
+64 294 290
+36 0 52
+229
+
+chain 5911 2 243199373 + 87725643 87726005 2 242951149 + 87495962 87496324 1452475
+79 29 29
+211 17 17
+26
+
+chain 5902 2 243199373 + 90476920 90476981 2 242951149 - 155440689 155440750 30819911
+61
+
+chain 5764 2 243199373 + 1219128 1219198 2 242951149 + 1208603 1208673 13156733
+70
+
+chain 5625 2 243199373 + 87727023 87727089 2 242951149 + 87494216 87494282 1840679
+66
+
+chain 5449 2 243199373 + 1221033 1223650 2 242951149 + 1208828 1209415 2333010
+27 2353 323
+237
+
+chain 5435 2 243199373 + 87725371 87725531 2 242951149 + 87487864 87488024 3394118
+65 44 44
+51
+
+chain 5351 2 243199373 + 243152496 243152579 21 46944323 - 27 110 6622
+83
+
+chain 5348 2 243199373 + 5153354 5153410 2 242951149 + 239297362 239297418 32407088
+56
+
+chain 5167 2 243199373 + 89830753 89830808 16 88827254 - 55048203 55048258 32968623
+55
+
+chain 5034 2 243199373 + 90484935 90484987 2 242951149 - 155462101 155462153 29809699
+52
+
+chain 5012 2 243199373 + 89872838 89872891 4 191273063 + 48825877 48825930 33453820
+53
+
+chain 4920 2 243199373 + 89890558 89890609 2 242951149 + 89623647 89623698 33788797
+51
+
+chain 4886 2 243199373 + 90477063 90477242 2 242951149 - 155440771 155441314 25803008
+53 75 439
+51
+
+chain 4812 2 243199373 + 89870406 89870457 4 191273063 + 48802771 48802822 34140093
+51
+
+chain 4757 2 243199373 + 234058786 234058836 13 114142980 + 90951015 90951065 34330265
+50
+
+chain 4737 2 243199373 + 5145834 5145884 3 199501827 - 155139362 155139412 33407240
+50
+
+chain 4647 2 243199373 + 1226779 1226827 2 242951149 + 1209604 1209652 34630462
+48
+
+chain 4644 2 243199373 + 111007822 111007876 2 242951149 - 132339823 132339877 533729
+54
+
+chain 4607 2 243199373 + 5145066 5145350 3 199501827 + 191348934 191349218 1967131
+93 45 45
+57 39 39
+50
+
+chain 4552 2 243199373 + 1219473 1219520 2 242951149 + 1208598 1208645 27324024
+47
+
+chain 4467 2 243199373 + 5146638 5146689 8 146274826 + 70047993 70048044 10546953
+51
+
+chain 4382 2 243199373 + 239685380 239685447 2 242951149 + 239350400 239350507 10821439
+47 0 40
+20
+
+chain 4286 2 243199373 + 89847926 89848007 18 76117153 + 56250573 56250654 7293717
+81
+
+chain 4166 2 243199373 + 90482850 90482893 2 242951149 - 155471295 155471338 33373631
+43
+
+chain 4069 2 243199373 + 90483640 90483682 2 242951149 - 155471279 155471321 32448532
+42
+
+chain 4027 2 243199373 + 89848079 89848577 11 134452384 - 130303828 130304326 4308822
+70 372 372
+56
+
+chain 3915 2 243199373 + 89847485 89847537 4 191273063 - 120181520 120181572 9841777
+52
+
+chain 3887 2 243199373 + 1222921 1225400 2 242951149 + 1208756 1209205 3355598
+176 2233 203
+70
+
+chain 3870 2 243199373 + 5146741 5146807 4 191273063 - 106282745 106282811 8233254
+2 4 4
+60
+
+chain 3851 2 243199373 + 243174715 243174760 1 247249719 + 80163 80208 1584
+45
+
+chain 3776 2 243199373 + 1223932 1223971 2 242951149 + 1208577 1208616 29100476
+39
+
+chain 3766 2 243199373 + 1225991 1226030 2 242951149 + 1209516 1209555 18014514
+39
+
+chain 3567 2 243199373 + 89848026 89848188 6 170899992 - 102513053 102513215 4544108
+53 70 70
+39
+
+chain 3456 2 243199373 + 87720895 87724286 2 242951149 + 87506634 87508855 332559
+59 4 143
+126 0 22
+162 9 0
+89 28 26
+108 1252 650
+77 1179 461
+298
+
+chain 3166 2 243199373 + 90482349 90482483 2 242951149 - 155440886 155440924 3921176
+20 96 0
+18
+
+chain 3114 2 243199373 + 1223097 1223130 2 242951149 + 1209002 1209035 21012522
+33
+
+chain 3110 2 243199373 + 1225750 1225960 2 242951149 + 1209065 1209275 3693305
+210
+
+chain 2962 2 243199373 + 16340723 16340754 16 88827254 + 56242121 56242152 7757072
+31
+
+chain 2946 2 243199373 + 1225580 1225611 2 242951149 + 1209315 1209346 16952082
+31
+
+chain 2859 2 243199373 + 243189340 243189373 2 242951149 - 213544 213577 2192
+33
+
+chain 2638 2 243199373 + 5146355 5146383 9 140273252 + 31324189 31324217 27516381
+28
+
+chain 2632 2 243199373 + 87721683 87721719 2 242951149 + 87489021 87489057 886310
+36
+
+chain 2630 2 243199373 + 5144933 5144985 19 63811651 + 23161927 23161979 24515130
+52
+
+chain 2538 2 243199373 + 16338477 16338504 3 199501827 - 154040818 154040845 35425972
+27
+
+chain 2527 2 243199373 + 111053817 111053884 2 242951149 + 110544305 110544372 1691975
+67
+
+chain 2476 2 243199373 + 5146689 5146741 2 242951149 - 88851718 88851770 6471285
+52
+
+chain 2465 2 243199373 + 16260450 16260476 14 106368585 - 56125663 56125689 35442474
+26
+
+chain 2448 2 243199373 + 90475509 90477186 2 242951149 - 155452726 155455668 5069202
+50 704 1477
+39 832 1324
+52
+
+chain 2256 2 243199373 + 89865421 89865445 4 191273063 + 48820096 48820120 35487368
+24
+
+chain 2132 2 243199373 + 90371525 90371566 2 242951149 + 90975643 90975684 3405316
+41
+
+chain 2046 2 243199373 + 87729180 87729211 2 242951149 + 87489147 87489178 2812396
+31
+
+chain 2012 2 243199373 + 16273933 16273955 11 134452384 + 22938127 22938149 7662326
+22
+
+chain 1994 2 243199373 + 5144152 5145822 11 134452384 + 133004933 133006812 2924035
+46 1530 1739
+23 20 20
+51
+
+chain 1907 2 243199373 + 5146585 5146633 1 247249719 - 174030724 174030772 3467396
+48
+
+chain 1894 2 243199373 + 1220990 1221013 2 242951149 + 1208785 1208808 13156732
+23
+
+chain 1847 2 243199373 + 87729147 87729180 2 242951149 + 87508312 87508345 2784752
+33
+
+chain 1616 2 243199373 + 5141194 5141259 4 191273063 + 140068684 140068749 14298254
+65
+
+chain 1606 2 243199373 + 89847307 89847375 6 170899992 + 54305106 54305174 19190580
+68
+
+chain 1373 2 243199373 + 243172974 243173045 8 146274826 + 8401 8472 3798112
+71
+
+chain 1350 2 243199373 + 87719705 87727637 2 242951149 + 87486442 87489057 666335
+5 4 8
+60 6231 0
+175 909 1819
+190 64 64
+294
+
+chain 1237 2 243199373 + 5143151 5144336 3 199501827 - 33955506 33956705 3724972
+50 1070 1084
+65
+
+chain 1182 2 243199373 + 1222834 1225214 2 242951149 + 1208599 1208809 9180420
+46 2248 78
+86
+
+chain 1157 2 243199373 + 87726368 87726988 2 242951149 + 87492753 87493373 434529
+59 53 53
+165 67 67
+36 57 57
+183
+
+chain 1107 2 243199373 + 5141765 5144570 1 247249719 + 5005582 5008225 2100127
+50 2701 2539
+54
+
+chain 1007 2 243199373 + 5142524 5142584 7 158821424 - 115940368 115940428 3379044
+60
+
+chain 998 2 243199373 + 234471343 234471369 18 76117153 + 53315026 53315052 2684166
+26
+
+chain 997 2 243199373 + 1223799 1223839 2 242951149 + 1209424 1209464 2284434
+40
+
+chain 932 2 243199373 + 87725722 87725751 2 242951149 + 87499077 87499106 1733344
+29
+
+chain 867 2 243199373 + 1226560 1226598 2 242951149 + 1209385 1209423 17548334
+38
+
+chain 822 2 243199373 + 5144726 5144801 2 242951149 - 76674151 76674226 3649555
+75
+
+chain 767 2 243199373 + 5141372 5141411 7 158821424 + 51905543 51905582 3310848
+39
+
+chain 651 2 243199373 + 5141336 5141372 5 180857866 - 59015526 59015562 2717102
+36
+
+chain 561 2 243199373 + 5140901 5140953 6 170899992 + 131686128 131686180 4225085
+52
+
+chain 545 2 243199373 + 90414124 90414152 7 158821424 - 94210194 94210222 18407154
+28
+
+chain 270 2 243199373 + 89868258 89868320 Y 57772954 + 11916008 11916070 28746465
+62
+
+chain 5644665978 20 63025520 + 60000 62965520 20 62435964 + 8000 62435964 20
+26259569 3100000 1765661
+234339 150000 1000000
+4004088 1 0
+6459 244 0
+37810 2 0
+1044573 50000 20000
+9411883 8 2
+362 1 0
+11607353 1 0
+1301304 0 1
+31036 9 0
+1151 2 0
+1088 1 1
+29 1 1
+2509 2 0
+407 0 1
+40 1 1
+3787164 50000 27050
+71932 50000 110000
+694117 1 0
+1008033
+
+chain 3228736998 21 48129895 + 10697896 48119895 21 46944323 + 9719767 46944323 23
+490233 3150000 3050000
+19828060 1 0
+8789369 48801 0
+222468 500 500
+22014 1500 1500
+1381822 48641 0
+3438590
+
+chain 2365142 21 48129895 + 9686364 9760752 1 247249719 - 105115380 105189719 169
+453 1 1
+62 1 1
+312 9 9
+152 1 1
+34 1 1
+205 1 1
+109 44 0
+14 7 65
+203 5 5
+26 1 1
+70 1 1
+17 1 1
+847 1 1
+49 1 1
+99 1 1
+87 1 1
+51 1 1
+26 1 1
+374 1 1
+43 0 6
+139 1 1
+128 1 1
+54 1 1
+45 2 0
+17 1 1
+75 1 1
+59 1 1
+210 1 1
+70 1 1
+158 43 43
+56 12 12
+109 1 1
+48 5 5
+116 1 1
+49 1 1
+307 1 1
+45 1 1
+440 5 5
+106 9 9
+784 1 1
+42 1 1
+228 0 1
+114 17 17
+88 11 11
+161 1 1
+38 1 1
+825 2 2
+38 1 1
+105 22 22
+81 1 1
+29 1 1
+300 23 23
+147 1 1
+26 1 1
+164 1 1
+35 1 1
+227 6 6
+56 2 2
+109 1 1
+25 4 0
+116 15 23
+172 1 1
+40 1 1
+68 15 15
+158 7 7
+349 14 14
+133 1 1
+39 1 1
+145 12 12
+60 1 1
+43 1 1
+101 21 21
+307 1 1
+42 1 1
+93 1 1
+162 1 1
+143 1 1
+40 1 1
+54 1 1
+107 9 10
+319 1 1
+43 4 4
+200 1 1
+18 1 1
+127 1 1
+90 1 1
+250 3 3
+93 148 1
+443 0 1
+77 9 9
+295 1 1
+59 1 1
+438 31 31
+127 3 0
+88 1 1
+109 7 8
+79 14 14
+112 10 8
+114 1 1
+94 1 1
+150 10 7
+69 1 1
+110 1 1
+17 1 0
+222 0 1
+195 1 1
+16 1 0
+89 1 1
+123 38 0
+43 1 1
+83 1 1
+47 3 4
+64 0 3
+38 1 1
+268 1 1
+27 1 1
+230 17 17
+252 1 1
+24 0 3
+168 1 1
+41 5 0
+50 1 1
+212 9 9
+40 29 0
+271 1 1
+48 1 1
+124 1 1
+57 1 1
+125 16 16
+136 29 29
+157 1 1
+27 7 0
+482 10 4
+158 1 1
+62 1 1
+371 1 1
+83 1 1
+120 1 1
+45 1 1
+189 0 1
+84 1 1
+103 18 18
+494 1 1
+55 3 0
+139 1 1
+264 18 18
+75 2 3
+130 1 1
+97 1 1
+193 1 1
+25 1 1
+167 1 1
+49 1 1
+62 16 16
+65 13 13
+62 1 1
+101 1 1
+60 1 1
+50 1 1
+307 9 9
+131 13 13
+94 1 1
+78 1 1
+132 1 1
+27 1 1
+358 1 1
+21 1 1
+466 14 14
+590 1 1
+34 1 1
+242 1 1
+29 1 1
+116 1 1
+44 1 1
+117 1 1
+67 2 1
+71 1 1
+32 1 1
+506 18 18
+88 1 1
+27 1 1
+78 0 11
+215 1 1
+77 1 1
+291 1 1
+56 3 3
+126 1 1
+42 1 1
+332 9 9
+280 6 9
+641 15 15
+59 6 10
+31 1 1
+62 1 1
+40 1 1
+298 1 1
+40 1 1
+146 1 1
+66 1 0
+757 2 0
+169 1 1
+65 1 0
+285 1 1
+20 1 1
+109 1 1
+67 1 1
+68 1 1
+32 1 1
+93 4 4
+147 0 14
+646 0 1
+544 8 8
+47 1 0
+141 14 14
+678 1 0
+154 0 1
+346 1 1
+73 1 1
+232 5 5
+113 1 1
+32 2 0
+23 1 1
+92 10 10
+1121 1 1
+143 1 1
+300 1 1
+49 1 1
+392 5 5
+242 1 1
+21 1 1
+369 1 1
+67 1 1
+47 0 1
+618 23 23
+565 1 1
+140 1 1
+247 1 1
+41 1 1
+50 1 1
+18 1 1
+65 1 1
+66 1 1
+108 0 4
+158 1 1
+105 1 1
+70 1 1
+25 6 8
+77 1 1
+323 1 1
+28 1 1
+258 1 1
+47 1 1
+393 1 1
+72 1 1
+149 13 13
+142 1 0
+60 0 1
+78 4 4
+100 1 1
+51 1 1
+156 1 1
+20 1 1
+510 1 1
+22 1 0
+67 1 1
+54 1 1
+45 1 1
+133 1 1
+23 1 1
+63 1 1
+32 1 1
+349 1 1
+15 1 1
+103 1 1
+36 1 1
+119 1 1
+47 1 1
+312 4 4
+66 13 13
+357 0 76
+20 1 1
+177 1 1
+91 1 1
+52 1 1
+36 1 1
+141 10060 10099
+90 1 1
+49 1 1
+212 1 1
+20 1 1
+286 1 1
+48 2 1
+50 1 1
+67 8 8
+63 1 1
+30 1 1
+93 1 1
+48 1 1
+129 1 1
+46 1 1
+455 1 1
+46 3 0
+84 1 1
+39 0 1
+229 2 11
+79 4 4
+731 17 16
+725 8 8
+249 1 1
+78 1 1
+1065 3 0
+735 0 1
+124 10 10
+51 1 1
+35 1 1
+315 25 25
+749 6 6
+343 1 1
+29 1 1
+386 1 1
+24 1 1
+407 1 0
+73 1 1
+708 1 1
+71 0 1
+16 1 1
+92 1 1
+25 1 1
+447 14 14
+190 85 85
+60 1 1
+66 1 1
+238 1 1
+87 5 5
+118 7 7
+696 0 12
+49 1 1
+823 1 1
+77 1 1
+154 0 3
+102 12 12
+698 1 1
+21 1 1
+591 1 1
+16 1 1
+59 1 1
+27 1 1
+114 1 0
+593 1 1
+30 1 1
+1351 1 1
+17 1 1
+77 6 0
+647 1 1
+23 1 1
+235 1 1
+39 1 1
+141 1 1
+80 5 5
+181 10 11
+1091 1 1
+58 0 1
+19 1 1
+305 0 1
+429 17 17
+107 1 1
+25 1 1
+156 5 5
+22 1 1
+188
+
+chain 3320966530 22 51304566 + 16050000 51244566 22 49691432 + 14430000 49591432 22
+647850 150000 150000
+3661581 100000 50000
+15278437 18 0
+294 36 0
+1407 1 1
+46 1 1
+6626947 4 2
+1759 1 1
+43 1 1
+1367363 10613 11998
+7858 0 4
+809337 20 0
+6305 0 20
+6703 2669 50000
+4247674 0 10618
+1611 2719 0
+35235 131 0
+12642 0 4
+45595 9 85
+19564 506 0
+165499 7 5
+1103946 60575 16700
+644 2 0
+319796 1155 1600
+17927 15406 19700
+464629
+
+chain 11044 22 51304566 + 50772606 50772840 1 247249719 + 28744016 28744317 20648865
+55 103 170
+76
+
+chain 18404394637 3 198022430 + 60000 197962430 3 199501827 + 35000 199446827 3
+13552792 0 1
+585083 0 1
+2092 1 2
+71 0 1
+31067262 0 1
+90 1 0
+5628461 0 15
+788 1 0
+3676 0 2
+35 1 1
+4682 1 0
+1295 0 5
+437 53 42
+326 0 2
+3309 1 1
+40 1 1
+998 0 3
+3584 5 0
+930 5 7
+845 1 1
+28 2 1
+303 0 1
+507 0 5
+5088 1 0
+2185 10046 10048
+949 4 4
+35 1 1
+2874 0 1
+6717 0 1
+2823 1 0
+703 0 4
+5143 1 0
+2490 10 10
+162 7 7
+6308 0 15
+15177535 152352 260003
+2532 1 0
+1633 2 2
+24207544 3000000 4400000
+60453436 0 4
+40076813 20999 20000
+8195 1 1
+44 1 1
+1408 1 1
+33 1 1
+172 3 4
+25 1 1
+538 13 13
+173 1 1
+27 1 1
+636 1 1
+28 1 1
+470 3 3
+112 1 1
+375 1 1
+26 26 0
+115 78 0
+52 23 0
+104 26 0
+15 231 0
+56 1 1
+20 1 1
+815 16 16
+484 1 1
+49 18 0
+509 4 3
+23 1 1
+391 1 1
+44 1 1
+1278 0 4
+32 1 1
+263 4 0
+27 1 1
+2416 0 2
+3184 43 43
+1150 13 13
+736 1 1
+47 1 1
+1416 1 1
+20 1 1
+1020 1 1
+25 1 1
+482 5 0
+716 1 0
+1697 1 1
+29 1 1
+1270261 23108 27000
+40930 1 0
+17455 1 1
+28 4 4
+43 0 491
+1679 1 1
+33 7 5
+29 1 3
+54863 53 16
+7653 2 2
+29 2 2
+15 0 30
+180 0 75
+215 45 0
+360 915 0
+6188 96 0
+17 288 0
+1388 1 1
+37 1 1
+7956 0 1
+374 0 1
+2442058
+
+chain 905554 3 198022430 + 50925386 50935027 3 199501827 - 148591827 148601470 3167
+1111 0 6
+2584 0 1
+5889 6 1
+51
+
+chain 274603 3 198022430 + 195356374 195379482 3 199501827 - 629997 657219 690
+621 1 1
+42 1 1
+893 1 121
+66 1 1
+693 1 1
+27 1 1
+761 1 1
+79 2 2
+297 1 1
+40 1 1
+643 1 1
+22 1 1
+410 8 9
+110 1 1
+16 0 5
+314 3 0
+1846 4 7
+39 1 1
+420 10 9
+335 6 0
+238 0 1
+76 1 0
+310 1 2
+175 1 1
+17 1 1
+268 1 1
+46 1 1
+114 1 1
+19 1 1
+127 8 8
+30 1 1
+207 6 6
+62 9 9
+505 22 22
+160 1 1
+34 1 1
+187 1 1
+138 0 1
+844 1 1
+103 0 1
+65 3459 3402
+90 4 4
+90 42 794
+52 478 4
+78 154 154
+28 235 0
+59 1501 5454
+143 19 19
+425 7 54
+39 46 0
+75 8 8
+73 1 95
+58 1 1
+51 16 63
+140 1 1
+33 1 1
+682 1 1
+68 1 1
+147 1 1
+82 1 1
+119 33 0
+262 0 1
+54 1 0
+13 56 0
+111 5 5
+722 1 1
+19 1 1
+60 1 1
+33 1 0
+7 1 1
+108 0 2
+302 1 1
+68 1 0
+42 1 1
+50 1 1
+80 1 0
+95 1 1
+19 1 1
+119 0 1
+493 16 16
+316
+
+chain 30227 3 198022430 + 66156466 66156782 5 180857866 - 15729243 15729559 4617547
+316
+
+chain 25764 3 198022430 + 195503126 195503723 3 199501827 + 196988790 196989012 1952307
+75 360 0
+127 20 5
+15
+
+chain 19039 3 198022430 + 195503723 195504023 3 199501827 + 196988637 196988937 1894839
+300
+
+chain 11786 3 198022430 + 195373997 195374119 3 199501827 - 651916 652038 19355983
+122
+
+chain 9624 3 198022430 + 195503246 195503561 3 199501827 + 196988205 196988400 2003832
+53 137 2
+73 4 19
+48
+
+chain 7908 3 198022430 + 195510214 195510615 3 199501827 + 196993313 196993714 919394
+96 17 17
+288
+
+chain 6921 3 198022430 + 66275488 66275560 6 170899992 + 144236219 144236291 28346484
+72
+
+chain 6012 3 198022430 + 66274973 66275036 15 100338915 - 38411650 38411713 30540003
+63
+
+chain 5039 3 198022430 + 66276813 66276866 9 140273252 + 71084115 71084168 33364454
+53
+
+chain 4902 3 198022430 + 66152713 66152764 11 134452384 + 5803379 5803430 33869306
+51
+
+chain 3381 3 198022430 + 195371524 195371562 3 199501827 - 645118 645156 13662757
+38
+
+chain 3356 3 198022430 + 50925108 50925187 3 199501827 - 92152745 92152824 20266108
+79
+
+chain 2109 3 198022430 + 195371614 195371638 3 199501827 - 645161 645185 16027164
+24
+
+chain 1800 3 198022430 + 195503201 195503246 3 199501827 + 196989165 196989195 4219824
+23 17 2
+5
+
+chain 1295 3 198022430 + 195372257 195372308 3 199501827 - 2286585 2286636 21843906
+51
+
+chain 17653654354 4 191154276 + 10000 191029082 4 191273063 + 0 191263063 4
+1413146 71672 51000
+5369 6 5
+65 1 1
+67 1 1
+425 1 1
+32 1 1
+175 1 1
+34 1 1
+5092 1 1
+46 1 1
+1396 15 15
+1446 1 0
+1679 13 13
+3443 0 1
+586 1 1
+38 1 1
+18 21 0
+1582 6 0
+202 3 0
+92 0 6
+187 9 0
+4054 1 1
+71 1 1
+1413 1 83
+51 7 7
+105 7 7
+53 0 41
+81 1 42
+41 0 41
+37 0 41
+3274 1 94
+114 0 1116
+921 2 0
+935 0 55
+3639 15 15
+1167 0 3
+44 29 0
+44 0 29
+5146 1 1
+42 1 1
+3831 3 0
+23 1 1
+4171 6 6
+796 165 0
+196 99 0
+94 33 0
+183 8 6
+107 2 2
+21 2 0
+62 68 1
+32 15 14
+81 18 18
+55 1 0
+17 67 1
+188 133 0
+44 67 0
+43 35 0
+3289 18 18
+298 1 0
+373 1 0
+2965 1 1
+30 23 0
+1718 38 0
+98 38 0
+53 44 7
+116 0 77
+272 1 1
+70 1 1
+1591 49 49
+360 33 23
+2400 1 1
+94 1 1
+6002 1 1
+16 1 1
+776 0 1
+324 46 46
+433 0 51
+53 27 1
+2181 4 1
+57 1 1
+1969 0 10
+4188 11 11
+1595 18 0
+2050 109 0
+4319 7 0
+50 4 0
+1464 1 3
+4156 0 2
+5455 2 3
+129 4 4
+9082 1 0
+786 20 20
+1506 1 0
+252 7 8
+17512 1 50
+56 0 1
+2474 52 69
+75 30 0
+61 0 16
+11 0 15
+41 1 1
+133 0 16
+79 17 0
+16 29 0
+3375 1 0
+969 4 0
+1623 11 11
+1065 3 0
+2934 0 8
+2323 181 0
+2290 0 1
+1641 1 6
+1955 1 0
+68 1 1
+347 1 1
+40 1 1
+1553 0 6
+678 16 16
+92 33 0
+390 0 4
+1147 1 0
+1948 4 4
+4296 1 1
+16 1 1
+955 1 1
+47 1 1
+1555 0 1
+2251509 0 81122
+171 1 1
+48 1 1
+718 0 1
+2789 1 1
+27 1 1
+1601 0 4
+1907 2 0
+31 1 5
+16 0 4
+76 2 0
+13 4 0
+27 1 0
+12 1 9
+1772 6 0
+22 1 1
+946 1 1
+24 1 1
+1245 0 1
+3231 1 1
+41 1 1
+736 4 4
+912 1 1
+18 1 1
+11270 0 3
+2704 1 1
+41 1 1
+1812 6 5
+1477 11 0
+1744 6 6
+2039 0 4
+2188 1 1
+48 1 1
+1704 1 1
+73 1 1
+2265 12 12
+553 1 1
+49 1 1
+67 1 1
+33 1 1
+3935 0 5
+15 0 1
+780 1 0
+1260 1 0
+4204 25 0
+862 14 14
+7114 1 1
+70 1 1
+169 1 0
+43 1 1
+145 1 1
+39 3 0
+8 1 1
+753 1 0
+1535 41 41
+679 1 1
+21 1 1
+1605 1 1
+19 1 2
+392 1 1
+29 0 1
+3673 0 1
+145 14 14
+39 1 0
+1246 1 0
+2302 0 1
+1554 9 9
+4537 1 0
+1064 0 2
+2051 0 1
+1130 2 0
+164 0 1
+1972 1 0
+18 3 3
+2597 1 1
+46 3 3
+196 1 1
+17 1 1
+60 4 4
+187 4 4
+46 1 1
+692 0 1
+3382 41 41
+497 3 3
+15 1 1
+486 14 14
+1709 0 8
+169 0 1
+597 1 1
+18 7 0
+3423937 1 0
+1295496 1 1
+26 1 1
+760 591802 150000
+22468468 1 1
+27 1 1
+2592 2 0
+33 1 1
+2065 0 3
+1050 11 11
+1046 9 3
+3263 0 1
+906 0 1
+1643 0 6
+1181 1 0
+475 5 0
+2522 0 4
+407 1 0
+517 77 77
+1122 36199 70999
+976587 26528 59000
+7703 4 0
+4545 9 9
+4740 1 0
+1862 0 1
+3316 3 7
+51 14 14
+1066 1 0
+1795 0 1
+569 0 1
+2895 1 1
+39 1 1
+461 0 3
+3168 6 6
+2197 0 1
+6774 2 0
+2504 2 0
+1247 1 1
+45 1 1
+2415 17 17
+4792 36 36
+3387 20 20
+272 10 10
+420 1 1
+34 1 1
+7961 0 4
+1973 1 1
+45 0 1
+529 0 1
+603 1 0
+18 1 1
+606 4 0
+65 1 25
+41 0 8
+517 1 0
+1400 41 38
+3786 1 0
+228 0 3
+1026 1 1
+49 1 1
+3336 3 0
+951 1 1
+77 1 2
+441 2 1
+1833 9 9
+301 5 5
+2787 17 17
+1747 0 1
+3040 9 2
+81 10 10
+86 0 2
+2113 45 45
+7352791 1606 20000
+1651 0 2
+45 16 0
+13956 8 0
+1947 3 0
+1255 1 1
+38 1 0
+1778 4 0
+22 1 0
+1045 0 6
+1327 1 0
+5775 1 1
+18 1 1
+1933 0 1
+1716 13 13
+255 0 1
+124 3 0
+792 5 0
+1521 1 1
+64 1 1
+9005617 150000 150000
+171176 3000000 3000000
+7074452 62111 50000
+5257 1 0
+2845 0 2
+1387 1 0
+114 0 1
+2385 4 0
+65 6 6
+62 0 4
+18 1 0
+100 51 0
+9781577 0 351994
+1903288 0 184275
+3925704 13 13
+435 1 1
+21 1 1
+838 1 0
+281 35 35
+491 6 6
+74 1 1
+43 1 1
+652 29839 30000
+13847966 1 0
+14069801 0 2
+8504 1 0
+32265 0 8
+12730 2 0
+35327 14 12
+1503 0 1
+1334 0 1
+759 1 0
+10036 1 7
+9912 17 18
+2523 0 1
+1321 1 0
+8984 0 2
+5505 20 20
+9694 6 6
+22003 0 9
+578 1 0
+5166 0 2
+92208 5 2
+8 0 1
+5 2 0
+110 0 4
+848 7 6
+2247 1 3
+3770 1 0
+5719 2 0
+2511 1 0
+1557 1 0
+5812 1 0
+3607 1 0
+7405 0 1
+11075 1 0
+2794 0 1
+2340 0 1
+429 1 0
+233 27 27
+262 0 2
+2397 0 5
+371 0 11
+1376 0 1
+2416 0 8
+210 1 1
+20 1 1
+5104 1 1
+20 1 1
+525 0 2
+836 1 0
+2094 0 1
+2213 0 3
+327 6 9
+1711 45 45
+837 1 1
+57 1 1
+1618 1 0
+1400 0 4
+254 2 0
+93 0 10
+755 6 0
+192 1 0
+2378 1 0
+1753 0 3
+644 14 14
+1244 4 0
+30 1 1
+1136 14 14
+2450 0 4
+3624 3 31
+456 14 14
+1076 8 7
+68 1 1
+20 1 1
+145 1 1
+68 0 1
+12 1 0
+10 1 0
+11 0 1
+35 0 1
+5 1 0
+11 2 1
+32 7 6
+35 0 1
+8722 0 1
+888 4 0
+456 0 3
+45 1 0
+151 13 13
+756 1 0
+203 7 8
+140 1 1
+20 1 1
+308 0 5
+1020 1 0
+1258 1 0
+160 2 0
+1411 1 1
+22 1 1
+1180 12 12
+4521 2 0
+1153 0 27
+4956 0 3
+1392 1 1
+47 1 1
+3854 1 2
+130 0 1
+2633 0 2
+3030 1 0
+2343 1 0
+1748 45 0
+731 0 2
+1336 11 9
+3899 6 0
+436 0 1
+981 1 0
+1326 1 0
+382 0 4
+1081 0 10
+81 1 1
+142 2 0
+5976 1 1
+26 1 1
+377 22 22
+86 1 0
+55 1 1
+93 1 1
+374 4 0
+38 6 0
+3944 0 347
+1034 1 1
+27 1 1
+60 0 2
+2581 0 3
+3882 4 0
+1790 1 0
+20 1 1
+356 0 1
+4244 5 5
+36 1 1
+2232 2 2
+42 1 1
+4462 2 0
+1611 0 1
+1290 2 0
+110 0 1
+1466 1 0
+357 0 3
+850 0 12
+13547766 1 0
+3724943 0 2
+46473408 1 0
+1696 1 1
+28 1 1
+1629 4 0
+666 0 4
+13464 12874 30000
+8520008 0 2
+1107 1 1
+15 1 1
+1892 4 0
+6798 2 0
+1793 1 1
+25 3 0
+421 0 389
+787 0 2
+545 2 0
+54 0 1
+143 1 1
+39 1 1
+89 1 1
+29 0 1
+171 1 1
+46 0 1
+192 1 1
+33 1 1
+336 18 18
+2226 1 0
+107 1 1
+29 1 1
+218 0 1
+175 5 6
+1407 1 1
+52 1 1
+8851 0 1
+14427 0 4
+1737 0 22
+5806 0 1
+1115 1 1
+29 2 0
+3395 1 0
+386 38 38
+2740 2 0
+522 0 1
+24 1 1
+658 0 4
+5724 9 9
+1209 1 0
+5380 0 1
+97 0 1
+853 0 4
+79 11 5
+2728 7 6
+3754 13 17
+1363 0 1
+1025 0 1
+1811 1 0
+7507 4 0
+1184 0 3
+763 0 1
+797 0 3
+293 0 2
+2488 1 0
+335 1 0
+9959 0 1
+3255 0 1
+1322 1 0
+8118 0 2
+3326 0 2
+632 0 1
+63 5 0
+1886 12 12
+1110 1 0
+9582 1 0
+14742673 3013 0
+39686
+
+chain 1255876 4 191154276 + 9214880 9257600 4 191273063 + 8933741 8943231 721
+156 22 22
+1030 14 14
+303 27 27
+166 4935 184
+220 23 24
+72 54 54
+771 13 13
+270 4744 0
+2627 17 17
+289 4743 0
+890 4745 0
+772 9500 0
+268 4749 1
+266 11 11
+1023
+
+chain 912330 4 191154276 + 9211690 9265763 4 191273063 + 8940042 8979863 947
+75 220 220
+51 122 122
+54 54 54
+51 167 167
+180 47 47
+70 24 24
+94 37 37
+257 59 59
+316 11 11
+163 60 60
+53 61 61
+95 21 21
+109 24 24
+217 32 32
+186 47 47
+233 1926 1924
+88 13 13
+123 125 126
+1453 4747 0
+2227 0 1
+278 535 535
+213 87 87
+92 7 7
+755 18715 9222
+268 6439 6434
+1089 14 14
+243 9 9
+78 4 4
+157 214 209
+200 23 24
+72 5972 5972
+655 413 413
+1441 14 14
+243 9 9
+78 4 4
+157 213 209
+200 23 24
+72 54 54
+771 13 13
+119 17 17
+221
+
+chain 676976 4 191154276 + 191033807 191044200 4 191273063 - 191263147 191273063 1558
+68 4 0
+34 1 1
+323 3 3
+31 1 1
+807 1 1
+26 1 1
+526 2 3
+34 1 0
+704 1 0
+6 1 0
+240 1 0
+237 2 0
+8 1 1
+371 10 0
+264 1 0
+205 1 1
+57 1 0
+601 1 1
+15 1 1
+1214 4 8
+1661 3 0
+94 1 1
+50 1 1
+355 15 15
+638 1 1
+54 1 1
+54 8 9
+323 67 9
+85 0 1
+96 1 1
+58 1 1
+35 1 0
+31 1 1
+86 1 1
+30 1 1
+76 1 1
+40 1 1
+121 282 27
+49 53 0
+63 92 0
+52
+
+chain 512088 4 191154276 + 8956990 9037962 4 191273063 + 9100119 9179836 26299
+71 118 113
+60 152 152
+88 33 33
+136 71 71
+85 43 43
+87 66 66
+92 87 87
+88 187 185
+156 1 81
+67 128 129
+76 143 143
+50 44 44
+212 52 52
+64 13 16
+267 79 79
+284 58 58
+51 76 76
+51 94 91
+55 77 77
+95 15 15
+74 251 251
+116 107 28
+64 188 188
+77 4 4
+113 11 11
+62 44 44
+102 237 237
+154 79 79
+58 86 86
+53 39 39
+50 36 35
+412 36 36
+75 225 225
+313 30 30
+54 84 83
+69 156 147
+104 89 77
+54 162 162
+226 16 16
+95 26 26
+60 14 14
+59 8 8
+120 7 7
+162 67 67
+65 210 210
+112 204 203
+63 53 53
+50 140 139
+127 143 143
+149 97 97
+88 61282 60044
+56 370 381
+50 56 56
+84 370 368
+52 288 288
+54 25 25
+72 923 933
+55 768 765
+68 70 70
+52 196 196
+62 305 305
+50 43 43
+129 114 114
+53 66 65
+116 411 423
+58 314 324
+68 0 1
+123 0 1
+53 58 59
+116 401 399
+539 6 0
+397 18 18
+60 211 211
+55 175 175
+63 553 556
+55 10 10
+53 1024 1003
+58 34 34
+81 43 43
+75 9 9
+51 1 0
+69
+
+chain 476298 4 191154276 + 9230645 9271936 4 191273063 + 8940012 8967053 893
+192 87 88
+429 187 187
+754 4750 6
+744 23 25
+2003 14 14
+246 42 42
+74 48 48
+71 104 104
+291 226 226
+81 4533 4529
+47 562 562
+111 285 285
+89 35 35
+2637 17 17
+240 9 9
+78 4 4
+157 215 209
+179 17 17
+100 4802 54
+343 13 13
+785 10920 6171
+1114 17 17
+243 6 6
+58 2 1
+272 1 0
+404 10 10
+1194 31 31
+266 11 11
+770 21 21
+327
+
+chain 377656 4 191154276 + 9257600 9267189 4 191273063 + 8933740 8938580 708
+1209 17 17
+571 1 0
+1617 4779 31
+1395
+
+chain 310844 4 191154276 + 9241835 9252105 4 191273063 + 8941714 8947231 850
+2726 14 14
+243 9 9
+78 4 4
+157 213 211
+265 85 85
+524 4751 0
+379 283 283
+539
+
+chain 275688 4 191154276 + 190986479 190989396 4 191273063 + 191223755 191226674 1129
+58 2 0
+265 1 0
+205 0 1
+208 4 5
+205 1 0
+122 55 53
+54 0 1
+411 25 25
+282 1 0
+419 14 20
+585
+
+chain 164691 4 191154276 + 9225860 9240813 4 191273063 + 8954210 8973910 1376
+232 87 87
+216 5946 5946
+93 12 12
+116 46 46
+231 32 32
+884 2511 7257
+718 3769 3770
+60
+
+chain 136190 4 191154276 + 9219745 9221340 4 191273063 + 8971822 8973417 7780
+1090 14 14
+243 9 9
+78 80 80
+81
+
+chain 127110 4 191154276 + 9223074 9241806 4 191273063 + 8960913 8979648 1585
+266 11 11
+4 10400 10401
+206 20 21
+668 26 27
+395 17 17
+14 6682 6682
+23
+
+chain 113888 4 191154276 + 59794841 59796661 7 158821424 + 43068053 43069865 1124766
+203 13 13
+161 140 141
+116 42 42
+240 178 178
+142 63 63
+254 11 11
+90 67 58
+100
+
+chain 91306 4 191154276 + 9218608 9227700 4 191273063 + 8961194 8975031 2525
+1019 3329 8072
+118 4492 4494
+89 35 35
+10
+
+chain 70288 4 191154276 + 9018276 9021043 11 134452384 - 130908986 130911761 1790585
+117 359 362
+150 330 330
+55 237 237
+99 73 73
+100 253 253
+70 73 78
+137 311 312
+72 249 248
+82
+
+chain 69967 4 191154276 + 8969559 8971297 11 134452384 - 66940622 66942298 1798470
+59 244 176
+78 49 49
+76 0 4
+72 217 218
+85 102 102
+264 12 12
+52 246 247
+66 24 24
+92
+
+chain 66013 4 191154276 + 9271936 9272654 4 191273063 + 8948073 8948792 572417
+692 0 1
+26
+
+chain 45624 4 191154276 + 9079872 9084019 4 191273063 - 187198263 187202501 2810559
+137 1640 1673
+114 79 83
+52 281 281
+64 700 698
+99 226 253
+83 576 605
+96
+
+chain 42774 4 191154276 + 9272654 9274373 4 191273063 + 8958282 8960000 1428
+395 17 17
+243 6 6
+329 3 2
+726
+
+chain 41852 4 191154276 + 9086638 9087081 1 247249719 - 105679719 105680162 3102182
+443
+
+chain 32596 4 191154276 + 9003477 9005348 8 146274826 + 6937943 6939835 4188535
+92 357 358
+96 443 443
+52 521 541
+122 129 129
+59
+
+chain 27953 4 191154276 + 9001038 9001387 11 134452384 - 130891915 130892264 5650797
+153 24 24
+85 11 11
+76
+
+chain 25460 4 191154276 + 1547039 1548332 4 191273063 + 1517808 1518962 1406869
+132 196 194
+8 33 0
+58 94 94
+33 400 430
+53 219 85
+67
+
+chain 23919 4 191154276 + 9060276 9060815 X 154913754 - 61464264 61464816 7738233
+150 249 262
+51 8 8
+81
+
+chain 23663 4 191154276 + 9250380 9252971 4 191273063 + 8954996 8957588 1596
+343 1382 1382
+494 21 21
+330 20 21
+1
+
+chain 23348 4 191154276 + 8954155 8955149 13 114142980 + 67377165 67378170 8084807
+108 119 119
+58 448 459
+78 128 128
+55
+
+chain 23051 4 191154276 + 9178657 9179321 8 146274826 - 138181840 138182484 8260527
+67 301 281
+58 86 86
+152
+
+chain 21854 4 191154276 + 9064978 9065877 1 247249719 + 159299736 159300622 9096955
+140 389 376
+61 239 239
+70
+
+chain 20302 4 191154276 + 59794670 59795934 19 63811651 - 51831683 51832948 1313667
+101 447 447
+6 69 70
+65 116 116
+17 4 4
+21 351 351
+67
+
+chain 19591 4 191154276 + 9123525 9124535 8 146274826 - 133912952 133913964 10789494
+68 696 699
+88 66 65
+92
+
+chain 17609 4 191154276 + 9152849 9153208 8 146274826 - 133934464 133934826 12466518
+149 157 160
+53
+
+chain 17420 4 191154276 + 9097653 9099623 11 134452384 - 51628045 51630034 12637575
+61 831 818
+58 894 926
+126
+
+chain 17154 4 191154276 + 8944061 8944687 3 199501827 - 68270290 68270918 12891537
+94 361 363
+56 52 52
+63
+
+chain 16449 4 191154276 + 9179756 9180625 8 146274826 + 7630543 7631403 13585678
+50 232 222
+54 427 428
+106
+
+chain 16159 4 191154276 + 9066614 9068459 16 88827254 - 83675354 83677175 13878826
+62 1020 1018
+99 597 575
+67
+
+chain 16115 4 191154276 + 9109381 9109952 21 46944323 + 28460282 28460853 13923553
+84 119 119
+62 249 249
+57
+
+chain 15306 4 191154276 + 8980490 8981996 4 191273063 - 187061282 187061823 14745791
+66 1267 302
+72 36 36
+65
+
+chain 15299 4 191154276 + 9056645 9056806 7 158821424 - 61471183 61471344 14752363
+161
+
+chain 14776 4 191154276 + 8950227 8950452 10 135374737 - 120304145 120304370 15312555
+84 55 55
+86
+
+chain 14403 4 191154276 + 9126194 9127408 5 180857866 - 26856190 26857401 15732261
+94 264 256
+54 752 757
+50
+
+chain 14224 4 191154276 + 8969618 8970298 11 134452384 - 67220551 67221216 1931088
+4 94 93
+78 397 383
+107
+
+chain 14155 4 191154276 + 9145781 9146043 X 154913754 - 45908091 45908403 16013758
+81 98 148
+83
+
+chain 14099 4 191154276 + 9060197 9060675 3 199501827 + 53477967 53478452 7798477
+58 172 171
+90 137 145
+21
+
+chain 13997 4 191154276 + 9005833 9006439 8 146274826 - 139204211 139204817 16201090
+60 438 438
+108
+
+chain 13823 4 191154276 + 8945988 8946280 4 191273063 + 9373057 9373350 16411372
+60 133 134
+99
+
+chain 13439 4 191154276 + 8975637 8975779 3 199501827 + 126919507 126919649 16900342
+142
+
+chain 12765 4 191154276 + 9077064 9077200 1 247249719 - 177698311 177698447 17836871
+136
+
+chain 12497 4 191154276 + 8950452 8951505 4 191273063 - 187091946 187092996 17010995
+3 953 950
+97
+
+chain 12348 4 191154276 + 8983189 8983604 8 146274826 - 138673776 138674197 18460871
+61 268 274
+86
+
+chain 11880 4 191154276 + 8972496 8973020 14 106368585 - 55089898 55090495 19186930
+61 378 451
+85
+
+chain 11818 4 191154276 + 9096126 9096305 11 134452384 - 67086036 67086266 19295429
+55 42 93
+82
+
+chain 11496 4 191154276 + 8948423 8949198 12 132349534 + 50778185 50778960 19846856
+94 629 629
+52
+
+chain 11391 4 191154276 + 8947143 8947401 8 146274826 - 134472454 134472711 20027902
+53 123 122
+82
+
+chain 11111 4 191154276 + 9107828 9107946 16 88827254 + 2897686 2897804 20531108
+118
+
+chain 10916 4 191154276 + 9261701 9262066 4 191273063 + 8952078 8952443 1072
+365
+
+chain 10832 4 191154276 + 8994164 8994326 6 170899992 - 100664994 100665156 21051510
+55 36 36
+71
+
+chain 10756 4 191154276 + 8943247 8943361 4 191273063 + 9116977 9117091 21193988
+114
+
+chain 10679 4 191154276 + 191030273 191030443 3 199501827 + 127002379 127002551 21342971
+68 44 46
+58
+
+chain 10668 4 191154276 + 1582572 1582681 4 191273063 + 1552756 1552865 12282737
+109
+
+chain 10529 4 191154276 + 191032229 191032410 11 134452384 + 3430296 3430477 21654608
+64 55 55
+62
+
+chain 10273 4 191154276 + 9096703 9097008 3 199501827 + 187858881 187859186 22199926
+64 181 181
+60
+
+chain 10137 4 191154276 + 9099965 9100095 6 170899992 - 166526436 166526567 22497437
+61 12 13
+57
+
+chain 10052 4 191154276 + 9066676 9066805 10 135374737 - 108696851 108696974 16846521
+41 9 9
+20 6 0
+53
+
+chain 9949 4 191154276 + 8999157 8999260 6 170899992 + 1823421 1823524 22925909
+103
+
+chain 9823 4 191154276 + 9071238 9072065 19 63811651 - 22299002 22299820 23218142
+65 697 688
+65
+
+chain 9746 4 191154276 + 8950613 8951219 7 158821424 - 151976579 151977185 23399634
+66 481 481
+59
+
+chain 9713 4 191154276 + 9012936 9013126 X 154913754 + 119487462 119487653 23485630
+58 74 75
+58
+
+chain 9679 4 191154276 + 9083038 9083589 12 132349534 + 77527128 77527707 10056562
+24 185 212
+17 262 263
+63
+
+chain 9579 4 191154276 + 9105290 9105637 8 146274826 - 6609 6954 23801877
+63 229 227
+55
+
+chain 9552 4 191154276 + 8956536 8957179 8 146274826 - 139187457 139188099 13944787
+92 234 234
+51 240 239
+26
+
+chain 9532 4 191154276 + 8978497 8978597 21 46944323 - 3695413 3695513 23932747
+100
+
+chain 9412 4 191154276 + 9108273 9108605 2 242951149 + 34780701 34781033 24211634
+61 216 216
+55
+
+chain 9361 4 191154276 + 9207159 9207725 7 158821424 + 92958588 92959148 24306771
+65 445 439
+56
+
+chain 9304 4 191154276 + 8946418 8946780 13 114142980 + 45938942 45939304 24422281
+63 247 247
+52
+
+chain 9136 4 191154276 + 9129485 9129655 1 247249719 - 82404984 82405154 24736407
+59 59 59
+52
+
+chain 9105 4 191154276 + 8982741 8983189 10 135374737 - 120304868 120305301 22041837
+59 380 365
+9
+
+chain 8777 4 191154276 + 9118310 9118402 11 134452384 - 67092191 67092283 25280535
+92
+
+chain 8617 4 191154276 + 59794359 59794524 X 154913754 + 69736929 69737094 2995761
+75 86 86
+4
+
+chain 8389 4 191154276 + 9219628 9219725 4 191273063 + 8933741 8933838 871949
+97
+
+chain 8260 4 191154276 + 8989895 8989983 4 191273063 + 9362532 9362620 26013719
+88
+
+chain 8131 4 191154276 + 9102626 9102711 4 191273063 - 187087880 187087965 26219988
+85
+
+chain 7754 4 191154276 + 190986383 190986479 10 135374737 + 135327923 135328019 562
+96
+
+chain 7688 4 191154276 + 8999849 9001530 8 146274826 + 7459813 7461495 7287525
+76 15 15
+50 236 236
+59 1157 1158
+88
+
+chain 7445 4 191154276 + 1642823 1642928 4 191273063 + 1612696 1612801 10569689
+105
+
+chain 7390 4 191154276 + 9235101 9235376 4 191273063 + 8934980 8935255 884
+275
+
+chain 6985 4 191154276 + 9132536 9132609 10 135374737 + 82556085 82556158 28236044
+73
+
+chain 6957 4 191154276 + 9079830 9084724 8 146274826 - 133860764 133864463 3584848
+42 1125 1126
+68 534 536
+50 1109 1111
+56 1741 541
+169
+
+chain 6924 4 191154276 + 9086283 9086357 3 199501827 + 28200221 28200295 17749225
+74
+
+chain 6522 4 191154276 + 59794524 59794670 4 191273063 + 131104023 131104168 2551460
+51 42 41
+53
+
+chain 6459 4 191154276 + 191029213 191029282 11 134452384 - 63299390 63299459 29377341
+69
+
+chain 6349 4 191154276 + 8971797 8971864 9 140273252 + 68477506 68477573 29649127
+67
+
+chain 6310 4 191154276 + 1548554 1548645 4 191273063 + 1518821 1518912 10939184
+91
+
+chain 6297 4 191154276 + 59793454 59794143 3 199501827 - 40571037 40571724 2330420
+79 562 560
+48
+
+chain 6221 4 191154276 + 9064020 9064085 16 88827254 - 83673859 83673924 29990023
+65
+
+chain 6094 4 191154276 + 9110081 9110145 1 247249719 + 181849295 181849359 30306899
+64
+
+chain 6086 4 191154276 + 191030472 191030537 11 134452384 - 75925756 75925821 30317869
+65
+
+chain 5966 4 191154276 + 9104473 9104535 11 134452384 + 71003965 71004027 30644952
+62
+
+chain 5912 4 191154276 + 8947661 8947723 9 140273252 - 2802727 2802789 30796182
+62
+
+chain 5903 4 191154276 + 9101296 9101358 4 191273063 + 9087606 9087668 30814689
+62
+
+chain 5842 4 191154276 + 9036574 9036668 4 191273063 - 85960898 85960992 17872768
+94
+
+chain 5712 4 191154276 + 9132160 9132220 12 132349534 + 8264132 8264192 31330015
+60
+
+chain 5710 4 191154276 + 191042876 191042934 4 191273063 - 191272139 191272197 15878613
+58
+
+chain 5622 4 191154276 + 9070424 9070484 3 199501827 - 68123367 68123427 31584493
+60
+
+chain 5594 4 191154276 + 1547006 1547408 4 191273063 + 1517841 1518435 2949224
+33 336 530
+7 8 6
+18
+
+chain 5494 4 191154276 + 8989383 8989441 10 135374737 + 82555871 82555929 31956576
+58
+
+chain 5493 4 191154276 + 9123841 9123899 3 199501827 - 55547554 55547612 22296298
+58
+
+chain 5485 4 191154276 + 9108193 9108251 17 78774742 + 49845783 49845841 31992260
+58
+
+chain 5354 4 191154276 + 9123785 9123841 19 63811651 + 46743056 46743112 26997396
+56
+
+chain 5287 4 191154276 + 191044097 191044231 11 134452384 + 134452193 134452328 8509115
+51 52 53
+31
+
+chain 5247 4 191154276 + 1642928 1642982 4 191273063 + 1612682 1612736 32710536
+54
+
+chain 5146 4 191154276 + 9109529 9109584 3 199501827 + 191350023 191350078 20827932
+55
+
+chain 5102 4 191154276 + 9012475 9012528 7 158821424 - 61434988 61435041 33179954
+53
+
+chain 4979 4 191154276 + 59793133 59793454 14 106368585 + 47992116 47992437 1636209
+52 1 1
+72 116 116
+45 1 1
+34
+
+chain 4919 4 191154276 + 59793533 59793585 1 247249719 + 177132715 177132767 25644257
+52
+
+chain 4894 4 191154276 + 8980336 8980388 8 146274826 - 134343460 134343512 33871905
+52
+
+chain 4776 4 191154276 + 59793593 59793649 8 146274826 + 78720544 78720600 25267381
+56
+
+chain 4646 4 191154276 + 9032086 9032149 11 134452384 - 67001981 67002044 11075042
+63
+
+chain 4523 4 191154276 + 9083642 9083690 4 191273063 + 9229696 9229744 33561479
+48
+
+chain 4481 4 191154276 + 9110034 9110081 1 247249719 + 117212387 117212434 31311635
+47
+
+chain 4466 4 191154276 + 8975249 8975296 4 191273063 + 9087559 9087606 34734206
+47
+
+chain 4380 4 191154276 + 9065601 9065685 14 106368585 - 65288844 65288928 12690014
+84
+
+chain 4316 4 191154276 + 8994219 8994386 9 140273252 - 20618312 20618467 21123765
+25 83 71
+59
+
+chain 4224 4 191154276 + 1548697 1548764 4 191273063 + 1518798 1518831 14337246
+14 34 0
+19
+
+chain 4196 4 191154276 + 59793649 59793759 3 199501827 - 110817223 110817333 10064550
+110
+
+chain 4174 4 191154276 + 9006462 9006529 3 199501827 - 68301162 68301229 17546615
+67
+
+chain 4160 4 191154276 + 9087190 9087234 3 199501827 + 69469088 69469132 19451262
+44
+
+chain 4035 4 191154276 + 59793991 59794095 4 191273063 - 43511377 43511481 1601554
+104
+
+chain 3949 4 191154276 + 59793891 59793960 7 158821424 - 5091499 5091568 15707336
+69
+
+chain 3917 4 191154276 + 59794575 59794617 19 63811651 + 46686810 46686852 11955254
+42
+
+chain 3916 4 191154276 + 9180332 9180405 8 146274826 + 7130141 7130214 14314247
+73
+
+chain 3790 4 191154276 + 9231440 9231540 4 191273063 + 8950300 8950400 218917
+92 7 7
+1
+
+chain 3686 4 191154276 + 59793772 59793811 15 100338915 + 77825223 77825262 17426618
+39
+
+chain 3659 4 191154276 + 9096554 9096861 3 199501827 - 6400721 6401028 23757316
+67 190 190
+50
+
+chain 3657 4 191154276 + 59794470 59794516 6 170899992 - 3232006 3232052 26376367
+46
+
+chain 3647 4 191154276 + 1557695 1557733 4 191273063 + 1527878 1527916 12331685
+38
+
+chain 3642 4 191154276 + 9109808 9109863 6 170899992 - 83529676 83529731 23755843
+55
+
+chain 3437 4 191154276 + 9178724 9179540 12 132349534 + 34224690 34225504 10931865
+32 667 665
+117
+
+chain 3342 4 191154276 + 9274373 9274605 4 191273063 + 8969490 8969722 4902
+232
+
+chain 3310 4 191154276 + 8971045 8971455 9 140273252 - 10330739 10331149 20511421
+70 288 288
+52
+
+chain 3302 4 191154276 + 1548711 1548745 4 191273063 + 1518614 1518648 32145222
+34
+
+chain 3283 4 191154276 + 9102560 9102594 10 135374737 - 120311822 120311856 35225233
+34
+
+chain 3261 4 191154276 + 8994091 8994458 8 146274826 + 9742146 9742512 23065618
+62 246 245
+59
+
+chain 3172 4 191154276 + 59794789 59794841 3 199501827 - 24852035 24852087 14612523
+52
+
+chain 3108 4 191154276 + 9060565 9060615 13 114142980 - 41995201 41995251 9632166
+50
+
+chain 3078 4 191154276 + 1548520 1548554 4 191273063 + 1518360 1518394 5794973
+34
+
+chain 3017 4 191154276 + 9065206 9065807 10 135374737 + 117208692 117209275 9578047
+65 480 462
+56
+
+chain 2924 4 191154276 + 59795756 59795800 5 180857866 + 175080369 175080413 1478283
+44
+
+chain 2887 4 191154276 + 59793960 59793991 2 242951149 - 7484272 7484303 15380677
+31
+
+chain 2846 4 191154276 + 9001603 9001654 8 146274826 - 133764474 133764525 19750221
+51
+
+chain 2767 4 191154276 + 8957324 8957381 4 191273063 + 9129618 9129675 15542671
+57
+
+chain 2754 4 191154276 + 9087109 9087190 6 170899992 + 92706078 92706159 16313416
+81
+
+chain 2673 4 191154276 + 9065350 9065411 1 247249719 - 53009045 53009106 13821618
+61
+
+chain 2622 4 191154276 + 59793258 59793374 14 106368585 + 42536813 42536929 1616879
+116
+
+chain 2598 4 191154276 + 59795229 59795281 6 170899992 + 57310821 57310873 1524793
+52
+
+chain 2565 4 191154276 + 190987578 190987605 4 191273063 + 191231440 191231467 2372
+27
+
+chain 2557 4 191154276 + 9066521 9067027 12 132349534 + 72855206 72855711 22561893
+55 378 377
+73
+
+chain 2500 4 191154276 + 9083457 9083524 8 146274826 + 32149594 32149661 28386486
+67
+
+chain 2474 4 191154276 + 1651689 1651722 4 191273063 + 1621541 1621574 19254204
+33
+
+chain 2389 4 191154276 + 9036810 9036873 2 242951149 - 1691358 1691421 23135357
+63
+
+chain 2338 4 191154276 + 59796505 59796540 17 78774742 + 47057876 47057911 2877115
+35
+
+chain 2291 4 191154276 + 9216761 9217155 8 146274826 - 133997030 133997425 4114277
+45 320 321
+29
+
+chain 2265 4 191154276 + 9065418 9065482 9 140273252 + 44106224 44106288 9767431
+64
+
+chain 2116 4 191154276 + 8944155 8944177 3 199501827 + 126918676 126918698 25172225
+22
+
+chain 2099 4 191154276 + 9099268 9099290 2 242951149 + 169698626 169698648 26708137
+22
+
+chain 2025 4 191154276 + 9097343 9097409 3 199501827 + 179409375 179409441 24047564
+66
+
+chain 2003 4 191154276 + 9108252 9108273 2 242951149 - 190846639 190846660 24998179
+21
+
+chain 1997 4 191154276 + 9146164 9146218 15 100338915 - 2487154 2487208 24249848
+54
+
+chain 1870 4 191154276 + 190988070 190988095 10 135374737 + 135329605 135329630 1377
+25
+
+chain 1826 4 191154276 + 8957935 8957992 4 191273063 + 9362404 9362461 11066413
+57
+
+chain 1826 4 191154276 + 9097476 9098043 12 132349534 - 122338357 122338925 15828070
+57 424 425
+86
+
+chain 1767 4 191154276 + 8990059 8990106 1 247249719 + 148949220 148949267 26452494
+47
+
+chain 1744 4 191154276 + 59793037 59793133 3 199501827 + 30427927 30428023 1883621
+96
+
+chain 1736 4 191154276 + 9086392 9087109 4 191273063 - 127153063 127153784 14070511
+50 639 643
+28
+
+chain 1668 4 191154276 + 9124660 9124729 4 191273063 + 9269820 9269889 23245150
+69
+
+chain 1556 4 191154276 + 9060815 9060839 10 135374737 - 108080722 108080746 12503169
+24
+
+chain 1546 4 191154276 + 9180153 9180207 8 146274826 - 138844855 138844909 16808195
+54
+
+chain 1517 4 191154276 + 59794322 59794359 11 134452384 - 119842384 119842421 16271509
+37
+
+chain 1488 4 191154276 + 59796097 59796124 9 140273252 + 9925299 9925326 2265670
+27
+
+chain 1436 4 191154276 + 191043722 191043759 1 247249719 - 247249574 247249611 18645625
+37
+
+chain 1374 4 191154276 + 9065276 9065337 1 247249719 - 201083821 201083882 10540800
+61
+
+chain 1348 4 191154276 + 9109064 9109144 2 242951149 - 126292213 126292293 15140626
+80
+
+chain 1343 4 191154276 + 9146043 9146068 18 76117153 + 30068723 30068748 16305066
+25
+
+chain 1292 4 191154276 + 9123899 9123951 4 191273063 - 148574019 148574071 20863102
+52
+
+chain 1290 4 191154276 + 9179321 9179368 11 134452384 + 3426025 3426072 10983647
+47
+
+chain 1231 4 191154276 + 59794434 59794461 5 180857866 + 147382264 147382291 9387523
+27
+
+chain 1177 4 191154276 + 9065884 9065939 9 140273252 - 70318092 70318147 10006368
+55
+
+chain 1097 4 191154276 + 9086357 9086392 1 247249719 - 129588705 129588740 16923174
+35
+
+chain 1085 4 191154276 + 9066380 9066450 13 114142980 + 68490318 68490388 22728993
+70
+
+chain 1083 4 191154276 + 9032737 9032804 13 114142980 + 26049760 26049827 24893033
+67
+
+chain 1011 4 191154276 + 9067073 9067124 10 135374737 - 108679092 108679143 23379890
+51
+
+chain 996 4 191154276 + 8971509 8971561 12 132349534 + 31168410 31168462 23661941
+52
+
+chain 963 4 191154276 + 9066836 9066890 1 247249719 - 151454542 151454596 25048936
+54
+
+chain 958 4 191154276 + 9145173 9145232 1 247249719 - 217919030 217919089 20381976
+59
+
+chain 937 4 191154276 + 8958092 8958125 11 134452384 + 67446107 67446140 12651114
+33
+
+chain 917 4 191154276 + 9146455 9146505 8 146274826 + 19957787 19957837 24577235
+50
+
+chain 910 4 191154276 + 9097602 9098317 2 242951149 - 190844271 190844995 14887788
+50 595 604
+70
+
+chain 894 4 191154276 + 9109146 9109219 X 154913754 - 13573867 13573940 23078019
+73
+
+chain 878 4 191154276 + 9178986 9179012 2 242951149 - 137542666 137542692 11507142
+26
+
+chain 871 4 191154276 + 9082368 9082425 3 199501827 - 78731030 78731087 22332859
+57
+
+chain 858 4 191154276 + 9098043 9099355 5 180857866 - 58871729 58873086 24126323
+56 1191 1236
+65
+
+chain 777 4 191154276 + 8955354 8955423 3 199501827 - 68281758 68281827 15856837
+69
+
+chain 715 4 191154276 + 191033511 191033568 7 158821424 + 30724536 30724593 23744345
+57
+
+chain 650 4 191154276 + 9126884 9126934 3 199501827 + 102896742 102896792 23688110
+50
+
+chain 507 4 191154276 + 59793857 59793890 8 146274826 + 107120151 107120184 20878932
+33
+
+chain 468 4 191154276 + 40297344 40297404 4 191273063 + 39972706 39972766 25333266
+60
+
+chain 438 4 191154276 + 9098988 9099041 4 191273063 - 56600577 56600630 25949595
+53
+
+chain 368 4 191154276 + 191031439 191031496 19 63811651 - 43557899 43557956 26568315
+57
+
+chain 315 4 191154276 + 8972631 8972682 12 132349534 - 123858147 123858198 26303923
+51
+
+chain 268 4 191154276 + 59793813 59793857 13 114142980 - 20847506 20847550 12435901
+44
+
+chain 209 4 191154276 + 9096427 9096486 3 199501827 - 25140168 25140227 30710814
+59
+
+chain 16792065298 5 180915260 + 10000 180905260 5 180857866 + 63000 180837866 5
+17520657 50017 11
+356 84 84
+496 0 3434
+735 75 1475
+628 25 3459
+51 50 3484
+3427 1 1
+39 3 3437
+577 8 8
+167 44 1713
+23 0 3434
+1184 1 0
+46 1 0
+5 1 0
+266 1 1
+21 1 1
+763 16 16
+422 1 1
+29 1 1
+5243 1 1
+37 1 1
+978 1 1
+21 1 1
+116 16 3450
+1792 146 16585
+3079 0 1
+7857 9770 0
+1026 636 1
+7461 1 0
+23769 0 51
+4034 1 0
+20571 1 0
+9135 2 0
+6885 3 2
+110 0 3
+816 3 2
+2296 34 0
+7499 2 0
+2917 1 0
+652 1 1
+37 1 1
+657 1 1
+22 1 1
+419 4 3
+3580 1 1
+29 1 1
+274 35 11
+833 1 0
+1908 0 3038
+10504 1 1
+27 0 2
+784 6 0
+127 0 10
+668 1 1
+28 1 1
+2464 0 4
+182 2 0
+1650 1 1
+39 1 1
+2433 0 1
+720 1 1
+40 1 1
+772 1 1
+32 1 1
+353 1 1
+17 1 1
+1776 1 0
+6082 0 3
+2669 10 12
+2857 1 1
+35 1 1
+982 1 1
+173 1 1
+4115 1 1
+49 1 1
+702 1 1
+33 1 1
+2927 2 1
+1472 0 17
+1346 1 1
+35 1 1
+2068 1 1
+40 1 1
+828 1 1
+36 0 2
+317 0 8
+893 1 1
+33 0 1
+8145 4 0
+28632197 3000000 3000000
+12470071 1 0
+29760415 50000 40000
+5878002 20845 23000
+4521 0 1
+676 6 6
+5928 1 0
+372 1 1
+47 1 1
+6801 2 3
+639 1 0
+871 4 3
+11530 4 0
+22966 1 0
+15447 1 0
+53856 2 0
+15988 2 0
+906887 1 0
+8 2 2
+40152828 47715 0
+3526228 1 0
+1604 0 10
+12778810 51715 4100
+15152690 0 27
+1852098 0 1
+8710030
+
+chain 78758 5 180915260 + 17610410 17613099 5 180857866 + 17647305 17649997 1601642
+85 49 49
+57 201 201
+189 17 17
+78 77 77
+75 178 181
+116 179 179
+91 8 8
+51 298 300
+51 664 662
+64 26 26
+135
+
+chain 31383 5 180915260 + 97574240 97575427 4 191273063 - 170991967 170993160 4391624
+188 108 110
+89 705 709
+97
+
+chain 22831 5 180915260 + 97580590 97581374 2 242951149 - 86243998 86244777 8407693
+68 180 179
+95 326 322
+115
+
+chain 16108 5 180915260 + 97571166 97571372 3 199501827 + 12403992 12404198 13932022
+51 22 22
+133
+
+chain 10260 5 180915260 + 97573380 97573866 X 154913754 + 72466087 72466572 22227065
+67 357 356
+62
+
+chain 9281 5 180915260 + 97573916 97574127 3 199501827 - 17931346 17931561 24462523
+61 98 102
+52
+
+chain 8534 5 180915260 + 17581030 17583073 5 180857866 + 17608062 17614939 1974
+70 1948 6782
+25
+
+chain 7377 5 180915260 + 17614165 17614243 8 146274826 + 118652818 118652896 27454171
+78
+
+chain 7140 5 180915260 + 97574682 97574775 9 140273252 + 18188007 18188100 13076039
+11 6 6
+76
+
+chain 6854 5 180915260 + 97574980 97575063 2 242951149 + 163688921 163689004 19449593
+83
+
+chain 6104 5 180915260 + 97573580 97573645 X 154913754 + 86697567 86697632 30283885
+65
+
+chain 5931 5 180915260 + 97571838 97571901 11 134452384 + 21528921 21528984 30747470
+63
+
+chain 5358 5 180915260 + 97565266 97565323 3 199501827 + 123413571 123413628 32371600
+57
+
+chain 5211 5 180915260 + 97574626 97575600 2 242951149 - 205065194 205066172 4657168
+56 746 750
+172
+
+chain 4836 5 180915260 + 97570927 97570987 12 132349534 + 79028695 79028755 21429371
+60
+
+chain 3976 5 180915260 + 97580463 97580554 X 154913754 + 120621333 120621424 19038460
+91
+
+chain 3896 5 180915260 + 17583124 17583167 5 180857866 + 17601254 17601297 1526
+43
+
+chain 3528 5 180915260 + 97573879 97573916 4 191273063 - 42047288 42047325 31874217
+37
+
+chain 3107 5 180915260 + 97574479 97575651 2 242951149 + 88874356 88875531 4418505
+53 767 770
+31 271 271
+50
+
+chain 3026 5 180915260 + 97580178 97580228 15 100338915 - 8217824 8217874 19735797
+50
+
+chain 2922 5 180915260 + 97575231 97575262 5 180857866 - 151978291 151978322 11789776
+31
+
+chain 2640 5 180915260 + 97575132 97575230 6 170899992 - 85176442 85176540 6161475
+98
+
+chain 2605 5 180915260 + 97580235 97580338 6 170899992 - 161277959 161278062 12089137
+103
+
+chain 2572 5 180915260 + 97580955 97581020 4 191273063 + 75087136 75087201 9159879
+65
+
+chain 2511 5 180915260 + 97573039 97573123 5 180857866 + 96582581 96582665 20564544
+84
+
+chain 2425 5 180915260 + 97580778 97580807 7 158821424 + 56235832 56235861 15947917
+29
+
+chain 2390 5 180915260 + 97580658 97580706 6 170899992 + 77924350 77924398 14557662
+48
+
+chain 2360 5 180915260 + 97575070 97575127 15 100338915 - 65496060 65496117 11267266
+57
+
+chain 2316 5 180915260 + 97574862 97574967 5 180857866 + 122822031 122822136 6403532
+105
+
+chain 2262 5 180915260 + 97575262 97575299 5 180857866 + 117084659 117084696 9926189
+37
+
+chain 2258 5 180915260 + 97570996 97571059 6 170899992 + 98788934 98788997 20073703
+63
+
+chain 2234 5 180915260 + 97575771 97575825 15 100338915 + 19192799 19192853 13777203
+54
+
+chain 2112 5 180915260 + 17598551 17598575 5 180857866 + 17621050 17621074 2441
+24
+
+chain 2082 5 180915260 + 97581410 97581440 5 180857866 - 81177483 81177513 18145628
+30
+
+chain 2013 5 180915260 + 97574428 97574456 6 170899992 + 12662047 12662075 5707452
+28
+
+chain 1804 5 180915260 + 97574815 97574862 7 158821424 + 102470537 102470584 21213680
+47
+
+chain 1676 5 180915260 + 97571668 97571723 9 140273252 - 49451145 49451200 15925569
+55
+
+chain 1630 5 180915260 + 97575847 97575921 14 106368585 + 65599248 65599322 16554081
+74
+
+chain 1394 5 180915260 + 17611593 17611672 5 180857866 - 163271537 163271616 20711197
+79
+
+chain 1250 5 180915260 + 97570872 97570926 X 154913754 + 128632888 128632942 22138126
+54
+
+chain 1212 5 180915260 + 17598429 17598472 5 180857866 - 163276581 163276624 866388
+43
+
+chain 683 5 180915260 + 97570493 97570549 4 191273063 + 125149085 125149141 22694892
+56
+
+chain 625 5 180915260 + 97572119 97572183 5 180857866 - 153619225 153619289 25061319
+64
+
+chain 466 5 180915260 + 97569261 97569351 7 158821424 - 120247996 120248086 22482305
+90
+
+chain 395 5 180915260 + 97572751 97572804 2 242951149 - 47300723 47300776 19687839
+53
+
+chain 15799169383 6 171115067 + 60000 171055067 6 170899992 + 5000 170896992 6
+1297281 1 0
+7806968 0 162987
+4013154 9 0
+261 13 15
+18786172 17 17
+439 16 16
+59 5 4
+32202 17 17
+439 16 16
+59 4 5
+15403 1 0
+13914169 4 0
+112 1 1
+17 1 1
+415 12 0
+105 6 3
+12160281 50000 50000
+642507 3100000 3050000
+248423 50000 50000
+2918791 1238 0
+9427508 4 4
+162 12 12
+2193 22 22
+293 1 1
+30 1 1
+845 1 0
+45 1 1
+9769 2 0
+6058 1 1
+24 1 1
+2223 1 1
+24 1 1
+182 12 12
+284 1 1
+20 1 1
+1035 7 36
+1007 1 1
+27 1 1
+3279 1 1
+44 0 1
+3012 1 0
+545 17 17
+2562 0 1
+251 0 1
+935 8 0
+37 1 1
+566 6 0
+1483 2 0
+1960 1 0
+4564 1 1
+25 1 1
+832 0 1
+801 8 8
+1131 1 1
+58 5 1
+6177 0 1
+3712 1 0
+2185 1 1
+35 1 1
+710 2 2
+78 1 1
+2201 1 1
+30 1 1
+283 1 1
+30 1 1
+448 1 0
+74814 2 2
+197 8 0
+2508456 1 0
+4641788 5 5
+37 1 1
+8503609 0 2
+5363169 150000 200000
+6040303 1 1
+36 1 0
+2020 1 1
+46 1 1
+1559 1 1
+72 1 1
+1098 1 1
+29 1 1
+264 7 7
+580 0 1
+30 1 1
+536 1 1
+41 1 1
+5663 1 0
+438 5 3
+354 1 1
+18 1 1
+9613 14 13
+1400 1 0
+176 0 2
+2742 1 0
+1968 0 1
+754 1 0
+4237 0 1
+2388 1 1
+31 1 0
+3385 0 1
+2004 8 0
+3395 0 3
+32 1 1
+4109 0 1
+1058 20 0
+1608 1 0
+17198424 17 26
+7835 0 1
+16317 11 0
+6277 64993 0
+6787989 0 1
+149 4 0
+949 4 0
+242 0 1
+28418215 1 1
+21 1 0
+3116903 171704 50000
+1939305 1 1
+19 0 2
+8192274 4 4
+122 0 2
+1127 1 0
+1102 75 0
+21 8 5
+30 29 0
+27 6 3
+62 52 0
+42 195105 18125
+950946 1 1
+51 157 1
+107 255 0
+714 513 0
+1285155 50000 150000
+725095
+
+chain 27931 6 171115067 + 168993335 168994451 6 170899992 + 168736232 168737615 1527785
+96 36 36
+16 0 51
+107 739 901
+51 0 54
+71
+
+chain 17101 6 171115067 + 119158013 119159004 8 146274826 + 76280127 76281098 12940826
+78 146 105
+78 622 643
+67
+
+chain 14766 6 171115067 + 119189669 119190286 7 158821424 - 68703788 68704409 15321990
+54 439 443
+124
+
+chain 13062 6 171115067 + 168994482 168994817 6 170899992 + 168736716 168737003 1274096
+205 50 2
+80
+
+chain 12205 6 171115067 + 119155128 119155329 8 146274826 - 70047959 70048173 18676577
+72 59 72
+70
+
+chain 11124 6 171115067 + 168993071 168993228 6 170899992 + 168736229 168736638 2160304
+29 1 52
+50 25 226
+52
+
+chain 10673 6 171115067 + 119159180 119160231 10 135374737 - 59595554 59596042 21356650
+62 913 350
+76
+
+chain 10669 6 171115067 + 119157022 119157134 14 106368585 + 59942933 59943045 21369163
+112
+
+chain 9554 6 171115067 + 119189632 119189818 X 154913754 + 133155010 133155200 16872824
+37 54 54
+12 31 35
+52
+
+chain 7241 6 171115067 + 119190390 119190581 13 114142980 + 101174758 101174949 23777400
+2 136 136
+53
+
+chain 6904 6 171115067 + 119156272 119156345 11 134452384 - 108078565 108078638 28375374
+73
+
+chain 6531 6 171115067 + 119159999 119160068 4 191273063 - 87162214 87162283 29199925
+69
+
+chain 5948 6 171115067 + 119160915 119160977 X 154913754 - 59556739 59556801 30709264
+62
+
+chain 5818 6 171115067 + 119158407 119158509 18 76117153 + 30261305 30261403 24322730
+1 51 47
+50
+
+chain 5749 6 171115067 + 119155939 119156000 6 170899992 + 92063509 92063570 31228902
+61
+
+chain 5103 6 171115067 + 119189831 119189885 X 154913754 - 76833525 76833579 33162260
+54
+
+chain 5032 6 171115067 + 119156645 119156719 X 154913754 + 87420725 87420799 20704812
+74
+
+chain 5002 6 171115067 + 119160862 119160914 X 154913754 + 56955255 56955307 33524497
+52
+
+chain 4995 6 171115067 + 168994451 168994737 6 170899992 + 168737201 168737385 2349016
+31 205 103
+50
+
+chain 4921 6 171115067 + 119156041 119156093 9 140273252 + 81227536 81227588 33775667
+52
+
+chain 4912 6 171115067 + 119160087 119160139 5 180857866 + 63815067 63815119 33803556
+52
+
+chain 3597 6 171115067 + 119157136 119157361 2 242951149 + 31758724 31758949 14786968
+84 78 78
+63
+
+chain 3223 6 171115067 + 119156854 119156913 15 100338915 - 54365651 54365710 24573102
+59
+
+chain 3204 6 171115067 + 119155364 119155420 6 170899992 - 73613724 73613780 24603360
+56
+
+chain 2966 6 171115067 + 119156499 119156577 X 154913754 - 137505405 137505483 21485501
+78
+
+chain 2728 6 171115067 + 119159004 119159033 3 199501827 - 198198433 198198462 28454448
+29
+
+chain 2528 6 171115067 + 119156618 119156645 11 134452384 + 82352593 82352620 34284540
+27
+
+chain 2454 6 171115067 + 119155233 119155259 9 140273252 + 122001720 122001746 35057240
+26
+
+chain 2315 6 171115067 + 119156723 119156806 4 191273063 + 116661391 116661474 16361102
+83
+
+chain 2146 6 171115067 + 119158341 119158407 6 170899992 + 115819766 115819832 17078055
+66
+
+chain 1866 6 171115067 + 119190053 119190120 5 180857866 + 56063062 56063129 22879278
+67
+
+chain 1656 6 171115067 + 119158523 119158602 11 134452384 + 2473635 2473714 18654554
+79
+
+chain 1624 6 171115067 + 119189898 119189948 4 191273063 - 66123378 66123428 24040914
+50
+
+chain 1451 6 171115067 + 119158163 119158229 15 100338915 - 64161282 64161348 22109122
+66
+
+chain 1209 6 171115067 + 168994304 168994329 6 170899992 + 168736283 168736308 2117199
+25
+
+chain 1198 6 171115067 + 119156176 119156250 5 180857866 + 3717928 3718002 22194292
+74
+
+chain 980 6 171115067 + 119158602 119158634 8 146274826 + 104450758 104450790 18747323
+32
+
+chain 943 6 171115067 + 119157563 119157614 2 242951149 + 163020248 163020299 23359839
+51
+
+chain 785 6 171115067 + 119156425 119156485 17 78774742 - 29484860 29484920 22136428
+60
+
+chain 779 6 171115067 + 119190333 119190390 3 199501827 - 104453282 104453339 22453017
+57
+
+chain 696 6 171115067 + 119158674 119158726 6 170899992 - 83894386 83894438 23403881
+52
+
+chain 689 6 171115067 + 119157650 119157707 X 154913754 + 101935638 101935695 24716105
+57
+
+chain 360 6 171115067 + 119160319 119160372 3 199501827 - 158113258 158113311 26359861
+53
+
+chain 282 6 171115067 + 119159242 119159272 19 63811651 + 46835118 46835148 25343818
+30
+
+chain 14618488008 7 159138663 + 10238 159128663 7 158821424 + 102995 158821424 7
+973 0 5
+3912 2 0
+1234 0 4
+51 6 0
+70 1 1
+24 0 1
+147 0 8
+12 1 170
+47 1 1
+246 6 0
+99 4 4
+807 0 3
+2546 0 63
+44 0 2527
+1373 1 0
+2109 456 0
+1153 1 0
+791 1 1
+49 1 0
+4175 18 26
+4318 11 11
+514 0 12
+2511 1 0
+1697 6 6
+192827 278557 150000
+5682433 40 39
+42007910 35970 40000
+2048 3 3
+2320 16 7
+17699 4 0
+5248 0 4
+2088411 1 1
+47 1 1
+4565 1 0
+7116 1 0
+2706 43050 40000
+6577293 13552 50000
+1052855 3000000 3000000
+256182 416507 50000
+190137 50000 50000
+5722629 1 0
+23 1 1
+239 1 1
+59 2 2
+138 1 1
+34 1 1
+206 3 1
+18 0 1
+410 1 1
+72 1 1
+199 1 1
+62 5 5
+120 0 1
+468 1 1
+32 1 1
+264 1 1
+23 1 1
+1459 4 4
+107 1 1
+42 0 1
+14 1 1
+201 1 1
+46 1 1
+268 20 20
+303 1 2
+866 4 0
+76 3 3
+63 1 1
+74 0 1
+25 1 1
+66 1 1
+34 2 0
+180 36 35
+93 1 1
+41 1 1
+70 1 1
+49 1 1
+63 1 1
+57 1 1
+383 1 1
+133 1 1
+87 1 1
+38 4 4
+50 1 0
+46 6 5
+136 11 11
+200 1 1
+64 5 18
+263 1 1
+32 3 3
+152 16 16
+567 0 1
+322 0 3
+1258 1 0
+504 0 4
+1142 10 11
+537 12 12
+1418 1 1
+47 1 0
+164 7 7
+113 0 5
+59 2 2
+72 1 1
+20 1 1
+380 3 3
+41 0 3
+5 2 2
+921 1 1
+34 1 1
+1607 2 2
+73 0 66
+45 0 14
+169 1 1
+53 1 1
+3195 1 1
+23 1 1
+2115 14 0
+9872 0 1
+1204 13 13
+416 0 1
+2298 0 319
+6918 10 0
+184 0 24
+2932 0 4
+1394 12 0
+1853 0 5
+3442 1 0
+469 0 3
+771 12 15
+497 1 1
+65 1 1
+1210 2 0
+4131 10 10
+1198 0 1
+718 1 1
+21 1 1
+3668 0 1
+874 1 1
+25 1 1
+2444 1 0
+1867 1 1
+29 1 1
+1660 1 0
+1233 6 0
+783 0 1
+705 3 0
+3577 0 1
+365 0 1
+3389 4 8
+2652 3 0
+664 1 0
+169 9 10
+138 1 0
+8038 56 0
+109 0 196
+522 35 0
+3003 1 1
+40 1 1
+1065 0 4
+634 1 0
+51 30 0
+66 1 9
+3081 0 2
+806 1 0
+21 1 1
+3901 27 26
+843 1 0
+6916420 50000 250000
+25789109 51216 0
+1399988 0 1
+3623 212 0
+38 1 1
+210 29 33
+1318 0 16
+2190 0 1
+145 1 0
+1388 7 7
+2240 14 14
+771 1 1
+34 1 1
+92 1 1
+39 1 1
+505 0 1
+66 1 1
+49 1 1
+159 0 1
+78 0 2
+2 0 1
+13 0 2
+7 0 1
+28 0 1
+27 5 468
+2022 0 1
+1796 7 7
+61 1 1
+20 1 1
+4560 0 3
+157730 0 1
+194 14 14
+650 12 0
+669 74 74
+820 5 0
+277 32 60
+69 5 0
+1345 0 8
+652 0 84
+118 4 0
+498 1 0
+3187 1 1
+43 1 1
+1476 3 0
+2101 0 5
+788 6 6
+872 6 0
+691 202 205
+155 33 33
+4610 7 5
+521 0 10
+2773 1 1
+38 1 1
+627 1 1
+41 1 1
+1424 1 0
+2554 8 8
+45 7 0
+614 1 1
+32 0 3
+2693 1 0
+1029 2 0
+151 1 0
+1753 21 0
+370 3 2
+969 1 0
+452 0 1
+3035 42 42
+704 2 0
+2472 6 0
+238 0 1
+1442 43 43
+126 1 0
+795 1 0
+1191 0 1
+171 16 17
+724 27 28
+2966 1 1
+38 3 1
+359 0 2
+199 1 1
+17 1 1
+1969 0 1
+251 1 0
+729 1 0
+992 1 1
+25 1 1
+203 0 4
+3211 2 0
+1006 10 8
+1571 10 10
+756 38 37
+433 1 0
+672 3 0
+4460 25 182
+5551 19 23
+942 9 10
+3433 1 2
+24 1 1
+4262 0 13
+661 0 2
+167 0 8
+3474 66 61
+162 2 0
+778 34 34
+158 1 0
+1167 1 0
+684 1 0
+878 39 39
+2012 1 0
+345 1 1
+50 1 1
+626 2 0
+27874083 136705 0
+2495 2 0
+1000 0 8
+14695 0 1
+4456 0 1
+2977 0 1
+9065130 29055 25000
+2369 0 1
+12174 20 18
+878 4 0
+5247 12 0
+3482 0 2
+6766 1 0
+2469878 1 0
+835 1 0
+2471 13 13
+751 0 8
+2241 1 0
+12 1 1
+8394 0 1
+47 1 1
+903 1 0
+5537 1 0
+269 0 1
+7114 1 1
+30 1 1
+2412 1 0
+2442 21 21
+91 1 1
+37 1 1
+96 1 1
+22 1 1
+246 1 1
+23 1 1
+241 25 25
+569 1 1
+27 1 1
+1624 0 1
+112 3 3
+45 1 1
+384 13 13
+70 0 1
+658 1 1
+20 1 1
+176 0 1
+307 19 19
+428 1 1
+19 1 1
+87 1 1
+30 1 1
+140 0 1
+292 0 2
+1492 0 1
+302 2 0
+364 1 1
+35 1 1
+1956 1 0
+728 57 57
+8010 0 1
+488 0 1
+2056 8 18
+1286 1 1
+27 1 1
+731 0 1
+1423 7 0
+2010 1 1
+19 1 1
+3925 37 37
+2438 4 0
+80 1 1
+4505 0 13
+933 12 0
+1250 1 0
+1313 0 1
+2610 1 0
+2398 1 0
+453 0 1
+346 14 14
+83 0 1
+24 1 0
+83 12 12
+277 1 0
+45 0 1
+811 0 2
+164 1 0
+104 1 0
+32 1 1
+1386 14 0
+306 1 1
+43 1 1
+2765 1 0
+1819 1 0
+1480 1 1
+24 1 1
+276 1 0
+21 1 0
+119 11 39
+542 1 1
+63 1 1
+180 1 0
+2456 0 1
+392 62 62
+601 0 1
+1166 0 2
+784 4 0
+170 0 1
+939 0 6
+5597 15 15
+1253 1 0
+3336 18 0
+1851 0 9
+45 1 1
+4794 1 0
+1387 0 2
+1460 0 1
+204 5 0
+1506 1 0
+2621 0 1
+6620 1 0
+34 1 1
+249 0 1
+1443 10 0
+242 1 0
+368 9 1
+257 0 4
+1588 0 6
+1544 1 0
+4189 0 120
+354 278046 312446
+3728 1 0
+3127 9 10
+4861 4 0
+5649 0 1
+2011 1 0
+14914 1467 42
+20955 1 0
+2075 1 2
+5546 0 1
+2168 0 4
+1266 0 1
+4124 1 1
+46 1 1
+54 1 1
+43 0 15
+780 1 1
+25 1 1
+497 1 0
+46 1 1
+770 41 40
+5701 1 0
+4251 8 8
+2739 1 0
+2002 3 0
+7160 1 1
+24 1 1
+479 0 2
+1872 1 0
+1192 0 1
+371 0 2
+31 1 1
+572 16 16
+1725 16 16
+588 1 1
+90 1 1
+2483 19 3
+187 1 0
+20 1 1
+3673 1 1
+27 0 4
+3021 0 1
+1323 6 19
+498 13 13
+1618 0 2
+5282 1 0
+720 8 0
+2993 0 1
+2822 2 0
+1396 1 1
+48 1 1
+8723 0 5
+291 1 1
+25 1 1
+116 1 0
+2809 1 1
+27 1 1
+224 1 1
+48 1 1
+292 2 0
+400 1 0
+754 1 1
+19 1 1
+4225 1 1
+28 1 1
+801 0 1
+671 1 1
+17 1 1
+390 1 1
+28 1 1
+84 7 7
+568 1 1
+56 1 1
+499 8 7
+266 1 1
+31 1 1
+518 18 18
+164 1 1
+50 1 1
+162 1 1
+60 1 1
+702 1 1
+28 1 1
+146 17 18
+517 1 1
+24 1 1
+799 1 1
+22 5 5
+107 5 5
+277 9 9
+272 1 1
+48 1 1
+77 1 1
+67 1 1
+1548 1 1
+40 1 1
+763 1 1
+42 1 1
+541 8 8
+88 1 1
+77 1 1
+233 11 11
+311 1 1
+22 1 1
+147 8 1
+504 1 1
+26 1 1
+996 3615 24049
+1687 0 1
+1174 1 0
+70 1 1
+1100 18 10143
+2722 1 0
+2957 1 1
+32 1 1
+9585 1 0
+1350 1 0
+473 1 0
+675 1 0
+1435 1 0
+805463 79189 0
+10872697 100000 100000
+721570 1 1
+19 1 1
+816 1 1
+44 1 1
+572 6 8
+2021 4 0
+1001 0 2
+3757 0 1
+5942 2 2
+70 1 1
+100 7 7
+395 17188 80000
+1010 1 1
+45 1 1
+1486 18 18
+173 145 1
+139 65 1
+41 16 0
+32 368 0
+44 2 50
+40 1 1
+95 52 4
+60 8 39
+12 0 16
+93 0 16
+1591 1 0
+897 13 13
+28 3 3
+2454 1 1
+44 1 1
+305 468 0
+2026 1 1
+45 1 1
+1273 3 11
+1717 0 1
+1575 4 0
+14 1 1
+2428 0 36
+50 10 154
+247 185 6
+2096 11 13
+192 1 1
+48 1 1
+130 1 1
+22 1 1
+970 1 1
+22 0 4
+76 14 0
+118 58 64
+107 1 0
+12 1 1
+53 5 15
+48 1 1
+47 2 0
+114 16 18
+363 1 1
+43 1 1
+559 1 1
+32 1 1
+3980007
+
+chain 16700437 7 159138663 + 142098195 142276197 7 158821424 - 16919205 17097543 171
+6297 1 0
+171 1 0
+4869 1 1
+24 0 1
+6208 0 1
+135 1 0
+1978 1 0
+764 1 1
+45 0 2
+1984 0 1
+1628 1 0
+733 1 1
+38 1 0
+137 7 7
+17 1 1
+259 1 0
+1200 1 0
+2193 4 4
+1781 0 1
+3387 1 1
+25 1 1
+125 1 1
+17 1 1
+3811 5 5
+556 0 1
+1846 5 0
+1322 1 1
+40 1 1
+228 0 1
+3477 1 1
+31 1 1
+3722 1 1
+73 1 1
+3052 66 66
+2542 15 15
+3103 0 2
+112 0 2
+1066 1 1
+59 1 0
+719 1 0
+203 1 0
+127 1 0
+30 1 0
+32 1 1
+366 0 4
+27 1 1
+2155 1 1
+41 1 1
+790 0 1
+403 1 1
+27 1 1
+648 7 7
+48 2 0
+78 2 2
+1052 4 4
+855 1 1
+68 1 1
+2428 9 0
+919 1 1
+22 1 1
+366 1 1
+36 1 1
+269 7 7
+4018 6 6
+1168 0 1
+3409 0 1
+1503 3 0
+2680 1 1
+37 1 1
+727 1 1
+28 0 5
+9 0 3
+5 0 2
+4 9 0
+13 1 1
+1801 0 3
+98 14 14
+2789 4 0
+5562 1 0
+2380 1 1
+23 1 1
+160 1 1
+57 1 1
+2413 19 19
+1704 0 1
+67 0 1
+68 1 1
+45 1 1
+176 9 9
+973 1 1
+31 3 3
+167 4 4
+334 13 13
+584 11 11
+206 16 16
+1218 1 1
+29 1 1
+234 1 1
+45 0 2
+1027 0 1
+559 10 11
+367 0 2
+8269 0 2
+4195 1 1
+62 1 1
+2896 13 13
+524 5 5
+411 1 1
+53 1 1
+126 1 1
+36 1 1
+806 1 1
+43 2 0
+1905 2 0
+414 1 1
+25 1 1
+2396 1 0
+12 1 0
+23 0 1
+10 0 1
+4 0 1
+60 0 1
+25 1 1
+1387 0 4
+3461 0 2
+1026 0 2
+821 1 1
+21 1 0
+612 1 1
+31 1 1
+1053 1 0
+2080 17 17
+9739 5 12
+17 7 0
+878 1 1
+19 1 0
+53 1 1
+839 26 26
+522 1 1
+49 1 1
+539 1 1
+25 1 1
+669 1 1
+42 1 1
+134 7 7
+1145 1 0
+2731 1 0
+590 4 0
+41 0 1
+7853 0 4
+830 0 2
+1742 2 0
+640 1 1
+34 0 2
+298 1 0
+3598 1 0
+1522 1 339
+115 18 18
+887 1 1
+69 1 1
+1662
+
+chain 1755125 7 159138663 + 143318748 143347897 7 158821424 - 15657394 15686558 532
+923 0 15
+1431 698 698
+3421 10 12
+405 1 1
+16 1 1
+5116 1 1
+27 1 1
+334 1 1
+15 1 0
+724 13 13
+109 0 2
+1784 1 0
+1588 1 1
+43 1 1
+908 9684 9682
+464 445 445
+982
+
+chain 939937 7 159138663 + 61402791 61412791 7 158821424 + 61280000 61290000 3137
+10000
+
+chain 921443 7 159138663 + 61382791 61392786 7 158821424 + 61260000 61269994 3741
+1722 1 0
+433 30 30
+1603 4 4
+4846 27 27
+478 19 19
+584 36 36
+212
+
+chain 898631 7 159138663 + 61392792 61402791 7 158821424 + 61270000 61280000 4251
+316 76 76
+3924 49 49
+2708 28 28
+1134 174 174
+156 40 41
+1394
+
+chain 896117 7 159138663 + 61422788 61432614 7 158821424 + 61300000 61310000 4294
+1207 50 50
+1637 22 22
+347 30 30
+983 48 48
+2562 0 172
+1941 14 14
+487 39 41
+459
+
+chain 881174 7 159138663 + 61412791 61422788 7 158821424 + 61290000 61300000 4600
+2588 34 34
+299 23 23
+1680 4 6
+286 395 396
+256 39 39
+220 18 18
+675 16 16
+3464
+
+chain 807485 7 159138663 + 61372814 61382791 7 158821424 + 61250000 61260000 5800
+91 75 75
+308 91 91
+99 88 88
+175 43 43
+577 65 65
+289 17 17
+186 21 21
+119 72 72
+80 98 98
+114 2 1
+115 51 51
+319 90 97
+54 49 50
+590 135 136
+749 1 0
+467 41 41
+153 21 21
+97 102 118
+935 19 19
+3186 43 43
+150
+
+chain 475263 7 159138663 + 143336322 143346915 7 158821424 - 15765291 15775883 242
+2017 14 14
+1214 1 1
+32 1 1
+3171 0 8
+760 1 1
+49 1 1
+68 10 10
+1210 1 1
+39 1 1
+60 18 9
+568 4 4
+357 12 12
+75 512 512
+397
+
+chain 413572 7 159138663 + 61432614 61437066 7 158821424 + 61310000 61314455 110492
+105 12 12
+1311 18 21
+3006
+
+chain 327362 7 159138663 + 130261501 130267755 7 158821424 - 80118425 80124354 202501
+81 547 220
+108 98 98
+188 35 35
+305 168 168
+59 47 46
+67 25 25
+301 6 6
+107 44 44
+133 23 23
+174 0 4
+110 27 27
+188 31 31
+86 62 62
+284 66 66
+205 34 34
+171 16 16
+85 35 35
+152 206 205
+64 33 33
+71 76 76
+129 26 26
+52 79 80
+203 92 92
+193 64 64
+113 490 490
+131 98 97
+66
+
+chain 116757 7 159138663 + 56987924 57001476 7 158821424 - 96066875 96080423 71
+182 4 0
+366 2 0
+47 6 0
+1290 7 1
+317 25 25
+90 14 15
+195 1 6
+96 1 1
+280 1 1
+59 1 1
+435 1 1
+51 1 1
+1067 22 22
+3594 0 1
+645 0 1
+507 7 7
+1383 0 6
+531 0 1
+1396 1 0
+927
+
+chain 94083 7 159138663 + 61667110 61669673 9 140273252 - 71180528 71183093 1349166
+123 22 22
+57 154 154
+93 530 532
+407 16 16
+95 28 28
+72 290 290
+83 43 43
+61 266 266
+77 77 77
+69
+
+chain 75094 7 159138663 + 433321 434167 14 106368585 - 82907729 82908574 1677524
+115 1 1
+30 1 0
+335 22 22
+342
+
+chain 74694 7 159138663 + 61674373 61676412 2 242951149 + 91627954 91629996 1686429
+59 154 155
+210 438 438
+221 259 259
+81 77 77
+52 201 203
+222 15 15
+50
+
+chain 54428 7 159138663 + 61360568 61361523 9 140273252 + 69464390 69465353 2322078
+76 100 105
+56 176 179
+432 51 51
+64
+
+chain 45723 7 159138663 + 100554977 100556023 7 158821424 + 100392913 100393963 2803709
+153 225 232
+246 8 8
+74 288 285
+52
+
+chain 42415 7 159138663 + 130262863 130266857 20 62435964 + 18530662 18534660 203154
+65 162 162
+47 67 67
+25 425 425
+33 1127 1130
+57 206 206
+33 274 274
+33 152 152
+121 149 149
+33 83 83
+64 129 129
+26 335 336
+91 194 194
+63
+
+chain 34286 7 159138663 + 61670163 61670988 1 247249719 - 187008143 187008914 3936433
+177 89 89
+59 338 284
+162
+
+chain 30309 7 159138663 + 61417768 61418394 15 100338915 + 53005912 53006538 319980
+332 256 256
+38
+
+chain 29619 7 159138663 + 130261638 130262129 18 76117153 - 20889181 20889344 211760
+82 389 61
+20
+
+chain 28749 7 159138663 + 102187071 102200348 7 158821424 + 102073398 102086671 912
+74 1102 1102
+32 11867 11863
+202
+
+chain 27540 7 159138663 + 61526936 61527567 17 78774742 - 13987513 13988140 5824140
+131 255 251
+90 52 52
+103
+
+chain 25455 7 159138663 + 61658206 61658677 21 46944323 + 31224827 31225297 6797318
+187 186 185
+98
+
+chain 25398 7 159138663 + 130275431 130276578 X 154913754 + 99697151 99697788 219009
+66 77 207
+69 353 1
+53 369 81
+54 49 49
+57
+
+chain 24368 7 159138663 + 61663982 61664383 7 158821424 - 97410910 97411311 7475570
+54 99 99
+67 16 16
+165
+
+chain 23018 7 159138663 + 61372081 61372809 7 158821424 + 61249436 61249995 8282044
+79 92 92
+52 313 144
+58 34 34
+100
+
+chain 22330 7 159138663 + 61674796 61675234 16 88827254 - 56087354 56087792 5126597
+69 100 100
+51 129 129
+89
+
+chain 22048 7 159138663 + 61583753 61648197 7 158821424 - 97506969 97571424 1587
+3024 0 1
+5860 1 1
+34 1 1
+1210 1 1
+46 1 1
+1360 1 1
+20 1 1
+6247 7 7
+2011 22 23
+15979 1 1
+20 0 1
+39 1 1
+156 1 1
+79 1 1
+1227 1 1
+26 1 1
+201 17 17
+6321 11 11
+106 2 2
+66 33 33
+316 6 6
+832 1 1
+17 1 1
+478 1 1
+25 1 1
+4306 14 0
+14 1 1
+525 4 4
+1603 1 1
+28 1 1
+433 1 0
+1365 1 1
+35 1 1
+3699 1 1
+17 1 1
+962 0 16
+124 1 1
+221 1 1
+50 1 1
+446 1 0
+788 0 1
+38 1 1
+470 14 14
+173 1 1
+48 0 1
+54 1 1
+71 0 7
+17 1 1
+319 1 1
+49 1 1
+115 2 1
+167 1 1
+41 3 3
+80 1 1
+70 1 1
+119 1 1
+19 1 1
+186 17 17
+347 7 7
+549 1 1
+69 1 1
+175 1 1
+55 1 1
+101 1 1
+118 2 2
+307 1 1
+73 1 1
+91
+
+chain 20717 7 159138663 + 61531674 61531894 Y 57772954 + 23149505 23149725 9889131
+220
+
+chain 20603 7 159138663 + 61525953 61526232 8 146274826 + 92437703 92437982 9974457
+114 48 48
+117
+
+chain 20209 7 159138663 + 61534129 61534693 5 180857866 - 39454690 39455254 10284708
+41 129 129
+72 189 189
+133
+
+chain 19256 7 159138663 + 10000 10238 11 134452384 - 108 510 10867298
+115 1 145
+57 3 0
+12 3 26
+47
+
+chain 17549 7 159138663 + 23954 24387 3 199501827 - 125819 126212 1017
+61 27 17
+87 27 17
+87 27 17
+87 27 17
+3
+
+chain 17511 7 159138663 + 61459516 61459775 3 199501827 + 156410667 156410926 12559831
+104 60 60
+95
+
+chain 17423 7 159138663 + 130286013 130286315 3 199501827 + 134941335 134941641 12635149
+64 74 78
+72 18 18
+74
+
+chain 17216 7 159138663 + 61561042 61561226 18 76117153 + 1344411 1344595 12834816
+184
+
+chain 15818 7 159138663 + 130258842 130259235 20 62435964 - 56174662 56175052 14212289
+60 144 139
+68 52 54
+69
+
+chain 15803 7 159138663 + 434188 434399 9 140273252 - 53303336 53303547 1693631
+211
+
+chain 15460 7 159138663 + 61363520 61363685 14 106368585 + 46013452 46013617 14586403
+165
+
+chain 15455 7 159138663 + 61533249 61533413 10 135374737 - 122138066 122138230 14591550
+164
+
+chain 14801 7 159138663 + 61526597 61527118 11 134452384 + 128715236 128715756 6490404
+89 98 98
+58 225 224
+51
+
+chain 14577 7 159138663 + 61459836 61459991 2 242951149 - 172428837 172428992 15528208
+155
+
+chain 14381 7 159138663 + 61532809 61533249 5 180857866 - 128913075 128913510 15277847
+110 278 273
+52
+
+chain 14182 7 159138663 + 61362349 61362804 1 247249719 - 101935287 101935742 15983329
+55 287 287
+113
+
+chain 13384 7 159138663 + 130261760 130262050 18 76117153 - 65538588 65538878 302793
+128 17 17
+145
+
+chain 12863 7 159138663 + 61659684 61659821 18 76117153 + 15161457 15161594 17682773
+137
+
+chain 12713 7 159138663 + 130268588 130270221 7 158821424 - 62883278 62884905 17912238
+74 1316 1311
+67 121 120
+55
+
+chain 12498 7 159138663 + 61527567 61527825 2 242951149 - 136022598 136022856 13034573
+7 155 155
+96
+
+chain 12424 7 159138663 + 61560835 61560980 21 46944323 - 5411573 5411718 18347201
+82 1 1
+62
+
+chain 11917 7 159138663 + 130274671 130277102 2 242951149 + 85567844 85569506 1111973
+198 73 73
+65 403 530
+21 111 209
+32 1149 157
+77 81 81
+50 6 4
+165
+
+chain 11414 7 159138663 + 61446485 61446604 8 146274826 - 97728756 97728875 19987436
+119
+
+chain 11204 7 159138663 + 323186 323319 13 114142980 - 47557127 47557260 20361650
+67 7 7
+59
+
+chain 11191 7 159138663 + 61533547 61533688 10 135374737 + 121736617 121736758 14568606
+63 20 20
+58
+
+chain 11162 7 159138663 + 143321102 143321761 7 158821424 + 143031254 143031913 1465
+659
+
+chain 11033 7 159138663 + 155133717 155133867 7 158821424 + 154826660 154826810 3228542
+150
+
+chain 10743 7 159138663 + 130272956 130273070 20 62435964 - 54784771 54784885 21217928
+114
+
+chain 10697 7 159138663 + 61363082 61363210 8 146274826 + 114533399 114533527 21308454
+63 1 1
+64
+
+chain 10686 7 159138663 + 130276049 130276418 5 180857866 - 110000669 110000947 1711166
+8 218 161
+54 34 0
+55
+
+chain 10550 7 159138663 + 61534371 61534497 2 242951149 - 102597516 102597642 13706867
+22 1 1
+103
+
+chain 10502 7 159138663 + 61658058 61658206 3 199501827 - 100394760 100394909 7999945
+74 51 52
+23
+
+chain 9908 7 159138663 + 155127373 155127651 7 158821424 + 154820991 154821604 23020589
+62 155 490
+61
+
+chain 9705 7 159138663 + 130254993 130255333 5 180857866 - 86134908 86135248 23505792
+58 220 220
+62
+
+chain 9691 7 159138663 + 61363878 61364175 6 170899992 - 83481581 83481894 23533804
+52 178 194
+67
+
+chain 9557 7 159138663 + 130275060 130277190 4 191273063 + 57733996 57734920 1639272
+2 161 201
+75 1804 558
+40 10 10
+38
+
+chain 9406 7 159138663 + 61531909 61532009 3 199501827 - 114948547 114948647 24221847
+100
+
+chain 9378 7 159138663 + 61670488 61670618 1 247249719 + 166585217 166585347 4198164
+130
+
+chain 9215 7 159138663 + 61369893 61370445 20 62435964 + 26207014 26207215 24594255
+60 436 85
+56
+
+chain 8793 7 159138663 + 61533688 61534015 8 146274826 + 132629025 132629349 11801047
+54 54 51
+58 97 97
+64
+
+chain 8578 7 159138663 + 61650566 61651111 20 62435964 - 36228749 36228943 25570183
+56 436 85
+53
+
+chain 8304 7 159138663 + 61532721 61532809 5 180857866 - 33354116 33354204 19653256
+88
+
+chain 8273 7 159138663 + 61375213 61375308 10 135374737 - 99567310 99567405 2885342
+95
+
+chain 7707 7 159138663 + 61670340 61670429 11 134452384 + 5653851 5653940 4693035
+89
+
+chain 7687 7 159138663 + 61362996 61363078 1 247249719 - 62796192 62796274 26921084
+82
+
+chain 7328 7 159138663 + 130260449 130260631 6 170899992 + 18975635 18975819 23797357
+8 121 123
+53
+
+chain 7084 7 159138663 + 155107000 155107125 8 146274826 + 127792382 127792507 21399384
+5 63 63
+57
+
+chain 6750 7 159138663 + 130268276 130268348 9 140273252 + 6309168 6309240 28699203
+72
+
+chain 6727 7 159138663 + 61364306 61364811 19 63811651 + 24391898 24393602 28746452
+47 400 1599
+58
+
+chain 6689 7 159138663 + 130262523 130267689 14 106368585 - 15396362 15401535 205901
+35 1928 1932
+35 3110 3113
+58
+
+chain 6657 7 159138663 + 130262248 130266269 20 62435964 - 53906684 53910704 204336
+68 3910 3909
+43
+
+chain 6632 7 159138663 + 61362621 61362691 14 106368585 - 25756639 25756709 18227251
+70
+
+chain 6604 7 159138663 + 61516196 61516266 14 106368585 + 18700177 18700247 29040667
+70
+
+chain 6561 7 159138663 + 61362487 61362621 5 180857866 - 77495083 77495217 25581093
+60 70 70
+4
+
+chain 6504 7 159138663 + 61563734 61563803 14 106368585 + 18700333 18700402 29292943
+69
+
+chain 6504 7 159138663 + 61457014 61457083 14 106368585 + 19014991 19015060 29292944
+69
+
+chain 6486 7 159138663 + 61439583 61439652 7 158821424 + 61677724 61677793 29330266
+69
+
+chain 6486 7 159138663 + 61453269 61453338 11 134452384 + 54672038 54672107 29330599
+69
+
+chain 6415 7 159138663 + 130266970 130267081 2 242951149 - 44689835 44689946 206027
+111
+
+chain 6395 7 159138663 + 61581171 61581239 12 132349534 + 36481345 36481413 29552558
+68
+
+chain 6295 7 159138663 + 130268491 130268558 12 132349534 - 16670768 16670835 29797454
+67
+
+chain 6222 7 159138663 + 61516757 61516823 7 158821424 - 100865546 100865612 29971261
+66
+
+chain 6149 7 159138663 + 61518444 61518509 9 140273252 - 73547747 73547812 30146556
+65
+
+chain 6147 7 159138663 + 61360661 61361459 1 247249719 - 99965931 99966729 2490905
+65 694 694
+39
+
+chain 6131 7 159138663 + 61545392 61545457 9 140273252 - 71283139 71283204 30224431
+65
+
+chain 6031 7 159138663 + 61649702 61649766 8 146274826 - 102385209 102385273 30479392
+64
+
+chain 5940 7 159138663 + 61567501 61567564 11 134452384 - 79723078 79723141 30715303
+63
+
+chain 5895 7 159138663 + 130261352 130261415 12 132349534 - 16670326 16670389 30822868
+63
+
+chain 5890 7 159138663 + 130272150 130272376 5 180857866 - 150003108 150003332 287879
+73 71 69
+82
+
+chain 5831 7 159138663 + 61540614 61540676 20 62435964 + 26207004 26207066 31016062
+62
+
+chain 5822 7 159138663 + 61534741 61534803 2 242951149 + 182601389 182601451 31037299
+62
+
+chain 5767 7 159138663 + 61657263 61657324 X 154913754 + 145511099 145511160 31173265
+61
+
+chain 5740 7 159138663 + 61561871 61561932 X 154913754 + 61825831 61825892 31255925
+61
+
+chain 5707 7 159138663 + 155133639 155133717 7 158821424 + 154826660 154826738 3248987
+78
+
+chain 5671 7 159138663 + 130267178 130267274 3 199501827 + 136865539 136865635 212140
+96
+
+chain 5649 7 159138663 + 61510793 61510853 14 106368585 + 18700200 18700260 31523979
+60
+
+chain 5614 7 159138663 + 61459620 61459680 8 146274826 + 85828676 85828736 12834914
+60
+
+chain 5505 7 159138663 + 130286091 130286151 11 134452384 + 126327988 126328048 18815467
+60
+
+chain 5376 7 159138663 + 61368713 61368770 5 180857866 - 134492854 134492911 32331066
+57
+
+chain 5358 7 159138663 + 130272706 130272763 4 191273063 - 62601703 62601760 32378845
+57
+
+chain 5239 7 159138663 + 61375927 61375982 3 199501827 + 176568366 176568421 32719676
+55
+
+chain 5238 7 159138663 + 155133561 155133639 7 158821424 + 154826660 154826738 3316763
+78
+
+chain 5212 7 159138663 + 48202742 48202797 Y 57772954 + 8140437 8140492 32786933
+55
+
+chain 5203 7 159138663 + 61362897 61362952 2 242951149 - 204521553 204521608 32840726
+55
+
+chain 5203 7 159138663 + 61514738 61514793 3 199501827 - 109094736 109094791 32841435
+55
+
+chain 5196 7 159138663 + 102270836 102270891 7 158821424 + 101958735 101958790 2864
+55
+
+chain 5085 7 159138663 + 61522548 61522602 11 134452384 - 85760698 85760752 33224588
+54
+
+chain 5081 7 159138663 + 61542952 61543361 X 154913754 - 96402533 96402599 33252017
+22 343 0
+44
+
+chain 5076 7 159138663 + 61566776 61566830 X 154913754 + 58536057 58536111 33266851
+54
+
+chain 5003 7 159138663 + 321166 321219 9 140273252 + 26769862 26769915 33490833
+53
+
+chain 4985 7 159138663 + 61511756 61511809 X 154913754 + 58510881 58510934 33583214
+53
+
+chain 4976 7 159138663 + 61453966 61454019 11 134452384 + 48695047 48695100 33600288
+53
+
+chain 4976 7 159138663 + 61579973 61580026 12 132349534 + 36420396 36420449 33600992
+53
+
+chain 4967 7 159138663 + 61528283 61528336 2 242951149 - 102597577 102597630 33622422
+53
+
+chain 4930 7 159138663 + 61528065 61528117 11 134452384 - 85701922 85701974 33735561
+52
+
+chain 4921 7 159138663 + 61566142 61566194 3 199501827 - 104503080 104503132 33762259
+52
+
+chain 4903 7 159138663 + 61364673 61364725 9 140273252 + 69253479 69253531 33844300
+52
+
+chain 4894 7 159138663 + 61535225 61535277 X 154913754 + 61822223 61822275 33894839
+52
+
+chain 4894 7 159138663 + 61555289 61555341 X 154913754 - 93093366 93093418 33894887
+52
+
+chain 4894 7 159138663 + 61367691 61367743 11 134452384 + 48824621 48824673 33895037
+52
+
+chain 4876 7 159138663 + 61446263 61446315 11 134452384 + 54670005 54670057 33929755
+52
+
+chain 4860 7 159138663 + 61671055 61671121 6 170899992 - 77150208 77150274 16663217
+66
+
+chain 4803 7 159138663 + 61582505 61582556 5 180857866 + 46128392 46128443 34201035
+51
+
+chain 4803 7 159138663 + 61548133 61548184 5 180857866 - 134730739 134730790 34201101
+51
+
+chain 4803 7 159138663 + 61656299 61656350 8 146274826 - 102385679 102385730 34201707
+51
+
+chain 4803 7 159138663 + 61371246 61371297 20 62435964 + 26207164 26207215 34201851
+51
+
+chain 4803 7 159138663 + 61538491 61538542 X 154913754 + 61822744 61822795 34202106
+51
+
+chain 4803 7 159138663 + 61550591 61550642 X 154913754 - 96402828 96402879 34202170
+51
+
+chain 4794 7 159138663 + 61568385 61568436 12 132349534 - 30627763 30627814 34229426
+51
+
+chain 4794 7 159138663 + 61560404 61560455 X 154913754 + 58511165 58511216 34229878
+51
+
+chain 4785 7 159138663 + 61555628 61555679 5 180857866 + 49580248 49580299 34261015
+51
+
+chain 4757 7 159138663 + 155127495 155127545 7 158821424 + 154820841 154820891 34330191
+50
+
+chain 4745 7 159138663 + 61527127 61527200 1 247249719 - 196249350 196249423 12580328
+73
+
+chain 4730 7 159138663 + 61454627 61454677 X 154913754 - 93091546 93091596 34451023
+50
+
+chain 4721 7 159138663 + 61547785 61547835 14 106368585 + 19015139 19015189 34474345
+50
+
+chain 4712 7 159138663 + 61542078 61542128 7 158821424 - 97143221 97143271 34536293
+50
+
+chain 4712 7 159138663 + 61650232 61650282 7 158821424 + 61292872 61292922 34536325
+50
+
+chain 4712 7 159138663 + 61447406 61447456 12 132349534 - 95867613 95867663 34536696
+50
+
+chain 4712 7 159138663 + 61573362 61573412 11 134452384 - 79778078 79778128 34537090
+50
+
+chain 4694 7 159138663 + 61361784 61361834 20 62435964 + 26208957 26209007 34582417
+50
+
+chain 4533 7 159138663 + 61657325 61657373 14 106368585 - 60354968 60355016 14458107
+48
+
+chain 4330 7 159138663 + 61571756 61571802 X 154913754 + 58511174 58511220 34815702
+46
+
+chain 4322 7 159138663 + 61527200 61527268 1 247249719 + 66112503 66112571 10645536
+68
+
+chain 4309 7 159138663 + 130262963 130263031 20 62435964 + 59813 59881 233275
+68
+
+chain 4243 7 159138663 + 130267293 130267390 15 100338915 - 46124324 46124421 430805
+97
+
+chain 4225 7 159138663 + 130272413 130272571 3 199501827 - 60665919 60666077 310359
+158
+
+chain 4225 7 159138663 + 130275130 130275387 10 135374737 + 61126513 61126771 1703431
+71 112 113
+74
+
+chain 4135 7 159138663 + 61657814 61657864 4 191273063 - 103880681 103880731 24177091
+50
+
+chain 4106 7 159138663 + 130265690 130265763 2 242951149 + 45160326 45160399 259070
+73
+
+chain 4049 7 159138663 + 61417706 61417751 19 63811651 + 35324192 35324237 995629
+45
+
+chain 4036 7 159138663 + 102224324 102224366 7 158821424 + 102110621 102110663 1050243
+42
+
+chain 3993 7 159138663 + 130270112 130270163 3 199501827 - 142320121 142320172 24066397
+51
+
+chain 3975 7 159138663 + 130269077 130269119 8 146274826 + 76339197 76339239 33761016
+42
+
+chain 3839 7 159138663 + 61659187 61659228 7 158821424 - 97183039 97183080 35036445
+41
+
+chain 3820 7 159138663 + 143397897 143397937 7 158821424 - 15657354 15657394 1380183
+40
+
+chain 3770 7 159138663 + 130272223 130272265 7 158821424 - 144399150 144399192 18136384
+42
+
+chain 3724 7 159138663 + 61669828 61671669 18 76117153 - 60916397 60916965 5934170
+170 1399 126
+50 156 156
+66
+
+chain 3694 7 159138663 + 130276177 130276253 X 154913754 + 40955942 40956018 2422661
+76
+
+chain 3685 7 159138663 + 102274757 102274796 7 158821424 + 101962659 101962698 2923
+39
+
+chain 3592 7 159138663 + 102246649 102246687 7 158821424 + 101934491 101934529 2920
+38
+
+chain 3540 7 159138663 + 61670988 61671026 1 247249719 - 1293349 1293387 6950988
+38
+
+chain 3536 7 159138663 + 155127890 155127927 7 158821424 + 154820516 154820553 31559480
+37
+
+chain 3321 7 159138663 + 130259738 130259803 5 180857866 + 117134963 117135028 22545496
+65
+
+chain 3254 7 159138663 + 155127171 155127205 7 158821424 + 154821284 154821318 30495954
+34
+
+chain 3179 7 159138663 + 61671122 61671197 3 199501827 + 3741295 3741370 21259213
+75
+
+chain 3139 7 159138663 + 61669998 61670032 7 158821424 - 73313700 73313734 35261607
+34
+
+chain 3136 7 159138663 + 155133873 155133906 7 158821424 + 154826660 154826693 3164897
+33
+
+chain 3128 7 159138663 + 61657490 61657523 14 106368585 + 19500965 19500998 15505654
+33
+
+chain 3124 7 159138663 + 61362864 61362897 13 114142980 - 56785908 56785941 33122705
+33
+
+chain 3114 7 159138663 + 61363362 61363395 11 134452384 + 38920746 38920779 30450202
+33
+
+chain 3035 7 159138663 + 130267390 130267459 5 180857866 + 148307658 148307727 349562
+69
+
+chain 3005 7 159138663 + 130258675 130258738 3 199501827 - 66319298 66319361 23438786
+63
+
+chain 2998 7 159138663 + 61670741 61670826 2 242951149 - 144372974 144373059 5019535
+68 11 11
+6
+
+chain 2929 7 159138663 + 61366904 61366935 9 140273252 + 69000834 69000865 35330365
+31
+
+chain 2883 7 159138663 + 130274908 130276723 12 132349534 - 84232022 84233270 1810563
+34 1716 687
+63 1 463
+1
+
+chain 2844 7 159138663 + 61525923 61525953 11 134452384 + 42874872 42874902 16620335
+30
+
+chain 2837 7 159138663 + 155133483 155133522 7 158821424 + 154826738 154826777 5314872
+39
+
+chain 2752 7 159138663 + 130270309 130270363 15 100338915 - 53351487 53351541 22720352
+54
+
+chain 2749 7 159138663 + 61657932 61657999 9 140273252 + 120725102 120725169 13790105
+67
+
+chain 2677 7 159138663 + 61657615 61657668 2 242951149 - 80490248 80490301 14907722
+53
+
+chain 2675 7 159138663 + 61657868 61657928 14 106368585 - 67199431 67199491 8049700
+60
+
+chain 2656 7 159138663 + 61658132 61658174 14 106368585 - 39618235 39618277 11504442
+42
+
+chain 2625 7 159138663 + 61376053 61376101 2 242951149 - 165273826 165273874 3000213
+48
+
+chain 2574 7 159138663 + 130285941 130286005 3 199501827 + 177805790 177805854 20115306
+64
+
+chain 2555 7 159138663 + 61657373 61657490 10 135374737 + 110991454 110991571 9489838
+117
+
+chain 2533 7 159138663 + 130255333 130255360 5 180857866 + 110504974 110505001 34260994
+27
+
+chain 2525 7 159138663 + 155133522 155133561 7 158821424 + 154826699 154826738 3760022
+39
+
+chain 2511 7 159138663 + 130261431 130261481 6 170899992 - 80902268 80902318 240832
+50
+
+chain 2491 7 159138663 + 130275062 130277276 7 158821424 + 139777825 139778654 1647744
+34 1723 339
+29 404 403
+24
+
+chain 2465 7 159138663 + 102229230 102229256 7 158821424 + 101917063 101917089 2852
+26
+
+chain 2367 7 159138663 + 61656836 61656861 8 146274826 - 114798799 114798824 27799318
+25
+
+chain 2262 7 159138663 + 61363303 61363362 15 100338915 - 25052381 25052440 19971588
+59
+
+chain 2184 7 159138663 + 61360913 61360944 16 88827254 + 45047397 45047428 3009512
+31
+
+chain 2183 7 159138663 + 61655805 61655828 8 146274826 - 102376418 102376441 35497387
+23
+
+chain 2181 7 159138663 + 61362804 61362827 8 146274826 - 64142945 64142968 28339747
+23
+
+chain 2177 7 159138663 + 61363497 61363520 15 100338915 - 57516283 57516306 24810342
+23
+
+chain 2111 7 159138663 + 102252256 102252279 7 158821424 + 101940282 101940305 3979
+23
+
+chain 2085 7 159138663 + 61668033 61668084 9 140273252 + 42719058 42719109 1926685
+51
+
+chain 2073 7 159138663 + 130274605 130277252 2 242951149 - 168073547 168075372 1534321
+53 350 351
+52 688 693
+76 1025 208
+32 309 298
+62
+
+chain 2067 7 159138663 + 155127207 155127236 7 158821424 + 154821033 154821062 24052540
+29
+
+chain 2049 7 159138663 + 130259609 130260449 2 242951149 + 217320568 217321411 19749334
+52 691 694
+97
+
+chain 1867 7 159138663 + 61360944 61360976 1 247249719 + 146935382 146935414 2538402
+32
+
+chain 1866 7 159138663 + 130286570 130286642 8 146274826 + 120193638 120193710 13784733
+72
+
+chain 1860 7 159138663 + 130271889 130271917 3 199501827 + 158050218 158050246 8145167
+28
+
+chain 1834 7 159138663 + 130267107 130267162 2 242951149 - 74722759 74722814 2183237
+55
+
+chain 1810 7 159138663 + 434399 434426 8 146274826 + 50019771 50019798 1840028
+27
+
+chain 1807 7 159138663 + 61459483 61459516 20 62435964 - 10907955 10907988 13772492
+33
+
+chain 1749 7 159138663 + 61534521 61534560 8 146274826 - 57707270 57707309 18613209
+39
+
+chain 1741 7 159138663 + 130275927 130275994 3 199501827 - 85253648 85253715 1907688
+67
+
+chain 1725 7 159138663 + 130286346 130286404 5 180857866 - 156929708 156929766 24410167
+58
+
+chain 1675 7 159138663 + 61360800 61360833 2 242951149 - 151940057 151940090 10244640
+33
+
+chain 1649 7 159138663 + 61527639 61527689 10 135374737 - 21832678 21832728 15020107
+50
+
+chain 1626 7 159138663 + 61525699 61525759 5 180857866 + 119849560 119849620 22270263
+60
+
+chain 1538 7 159138663 + 130271917 130271979 X 154913754 + 106499092 106499154 335529
+62
+
+chain 1512 7 159138663 + 130270436 130270487 7 158821424 + 123638895 123638946 23964536
+51
+
+chain 1449 7 159138663 + 61671198 61671257 11 134452384 + 48551200 48551259 6005368
+59
+
+chain 1444 7 159138663 + 130272046 130272150 5 180857866 - 107650838 107650942 1109190
+41 46 46
+17
+
+chain 1406 7 159138663 + 130268385 130269191 13 114142980 + 104373808 104374629 24734362
+65 682 697
+59
+
+chain 1391 7 159138663 + 130271979 130272046 12 132349534 + 128856107 128856174 572332
+67
+
+chain 1342 7 159138663 + 130255652 130255716 6 170899992 - 118498216 118498280 24733557
+64
+
+chain 1277 7 159138663 + 61525407 61525458 14 106368585 - 54569941 54569992 25208354
+51
+
+chain 1239 7 159138663 + 61657050 61657132 1 247249719 + 60704689 60704771 10216239
+82
+
+chain 1222 7 159138663 + 24387 24410 9 140273252 - 34976 34999 792
+23
+
+chain 1201 7 159138663 + 130267591 130267617 3 199501827 - 22519451 22519477 371093
+26
+
+chain 1176 7 159138663 + 61533413 61533439 9 140273252 + 78066621 78066647 21815254
+26
+
+chain 1159 7 159138663 + 130255953 130256003 18 76117153 + 30232927 30232977 26680295
+50
+
+chain 1143 7 159138663 + 130272637 130272705 4 191273063 - 164951872 164951940 23193314
+68
+
+chain 1120 7 159138663 + 130267081 130267107 4 191273063 + 53894987 53895013 453066
+26
+
+chain 1090 7 159138663 + 61375539 61375583 16 88827254 - 2017000 2017044 2867569
+44
+
+chain 967 7 159138663 + 61363930 61363960 5 180857866 - 77417997 77418027 26429199
+30
+
+chain 922 7 159138663 + 130269744 130269794 6 170899992 - 168370205 168370255 24919326
+50
+
+chain 916 7 159138663 + 130272376 130272413 7 158821424 - 119807072 119807109 361270
+37
+
+chain 903 7 159138663 + 130274518 130274571 18 76117153 + 7087852 7087905 2747041
+53
+
+chain 875 7 159138663 + 61656861 61656912 1 247249719 - 3737712 3737763 19994037
+51
+
+chain 825 7 159138663 + 130276127 130276177 9 140273252 + 78760365 78760415 3856900
+50
+
+chain 821 7 159138663 + 61657151 61657205 18 76117153 - 50729761 50729815 10763263
+54
+
+chain 764 7 159138663 + 155106965 155107000 2 242951149 - 97843675 97843710 19287766
+35
+
+chain 760 7 159138663 + 130260179 130260244 15 100338915 - 29035916 29035981 5017751
+65
+
+chain 738 7 159138663 + 61528144 61528186 5 180857866 + 37689556 37689598 26578239
+42
+
+chain 665 7 159138663 + 61657587 61657615 4 191273063 - 56344538 56344566 26451583
+28
+
+chain 506 7 159138663 + 130259438 130259491 7 158821424 - 81365049 81365102 23441660
+53
+
+chain 492 7 159138663 + 130276335 130276363 8 146274826 - 17074751 17074779 8865204
+28
+
+chain 466 7 159138663 + 130268939 130269012 2 242951149 - 225017173 225017246 26097376
+73
+
+chain 388 7 159138663 + 130271813 130271889 3 199501827 + 120370918 120370994 4694596
+76
+
+chain 379 7 159138663 + 130275097 130275130 3 199501827 + 9586745 9586778 4580558
+33
+
+chain 379 7 159138663 + 61363702 61363740 5 180857866 - 91082220 91082258 29303651
+38
+
+chain 348 7 159138663 + 102200504 102200535 7 158821424 - 57045045 57045076 1079
+31
+
+chain 13484003737 8 146364022 + 10000 146304022 8 146274826 + 0 146274826 9
+930417 1243 1
+52 10 10
+91 972 0
+54 54 0
+281 324 0
+289 1 0
+2323216 0 1
+3352649 0 2
+854996 50000 100000
+3399023 1 1
+46 1 1
+13965 1 1
+30 1 1
+121189 1 1
+35 1 1
+283700 1 0
+719291 93054 100016
+1155 2 0
+755 26 26
+980 21 21
+1479 422 422
+3229 0 1
+1937 1 1
+17 1 1
+322 0 1
+1758 0 2
+1141 1 0
+956 48 48
+1765 1 0
+543 25 25
+7047 15 15
+1029 1 1
+28 1 1
+314 1 1
+46 1 1
+164 1 1
+25 1 1
+5130707 1 0
+1288 1 0
+446 1 1
+80 1 1
+2123 4 4
+2514 0 3
+545 0 9
+527 1 1
+18 1 1
+256 9 9
+79 1 1
+40 1 1
+148 2 0
+2236 27 0
+953 1 1
+20 1 1
+2487 1 1
+113 1 1
+73 13 13
+365 10 10
+151 1 1
+32 0 3
+26 1 1
+1480 1 1
+29 1 1
+621 1 1
+28 1 1
+701 9 9
+362 1 1
+19 1 1
+691 1 1
+45 0 6
+46 1 1
+513 11 12
+382 1 1
+22 1 1
+111 1 1
+36 1 1
+337 1 1
+42 1 1
+602 0 2
+36 1 1
+475 1 1
+23 1 0
+32 3 4
+65 1 1
+59 1 1
+688 1 1
+22 1 1
+1473 1 1
+36 1 1
+372 1 1
+16 6 6
+640 25 25
+940 1 1
+38 1 1
+816 1 1
+17 0 1
+374 1 1
+17 1 1
+48 0 1
+82 1 1
+45 1 1
+263 1 1
+23 1 1
+204 1 1
+39 1 1
+2341 1 0
+2989 1 0
+9 1 0
+811 8 8
+741 2 0
+337 1 1
+25 4 4
+763 1 1
+19 1 1
+343 1 1
+31 1 1
+1953 1 1
+74 1 1
+67 1 1
+18 4 4
+73 1 1
+31 1 1
+114 1 11
+87 1 1
+65 1 1
+125 9 9
+378 0 1
+47 1 1
+90 1 1
+96 0 1
+176 7 13
+696 1 0
+6184 13 13
+830 13 13
+128 1 1
+37 1 1
+136 0 1
+66 6 5
+870 0 1
+4877 1 0
+585 7 3
+1728 0 1
+33 1 1
+465 1 1
+68 1 1
+581 0 6
+2088 0 1
+304 1 0
+2674 1 1
+28 0 1
+54 8 8
+846 1 0
+1409 16 16
+559 1 0
+401 5 0
+17 1 5
+29 1 1
+4051 1 1
+10 1 0
+43 1 1
+385 1 1
+35 1 1
+101 11 11
+602 0 1
+491 16 14
+1366 19 19
+321 1 1
+49 1 1
+546 1 1
+25 1 1
+1333 28 28
+1207 1 1
+51 0 4
+159 1 0
+1040 1 0
+1682 4 0
+34 0 8
+867 1 1
+17 1 1
+587 1 1
+21 1 1
+904 1 0
+261 1 0
+1151 2 0
+2325 5 5
+5415 3 0
+1545 0 1
+428 4 4
+1950 0 2
+1073 1 0
+3658 86 0
+1278 1 1
+79 1 1
+6656 12 12
+1550 18 0
+5832 0 1
+4835 10 10
+1719 1 1
+84 1 1
+848 2 0
+236 1 1
+42 1 1
+1286 0 12
+35 1 1
+820 1 1
+22 0 1
+63 22 0
+167 23 23
+315 8 8
+983 0 6
+539 14 14
+863 2 0
+27 1 1
+204 14 14
+163 4 4
+290 1 1
+59 1 1
+842 2 0
+2044 1 1
+90 1 0
+3434 3 0
+356 1 0
+873 1 0
+864 1 25
+630 7 12
+62 1 1
+88 1 1
+76 11 11
+1366 17 17
+156 4 4
+244 18 4
+505 0 1
+109 1 1
+230 1 1
+107 3 4
+150 1 1
+83 5 5
+70 1 1
+33 0 1
+142 1 1
+626 6 5
+274 10 10
+128 1 1
+35 1 1
+216 1 1
+44 1 1
+312 18 18
+1496 7 8
+451 1 0
+212 14 14
+629 1 1
+20 1 1
+350 1 1
+62 1 1
+617 10 10
+845 1 1
+58 1 1
+2189 1 1
+147 1 1
+475 1 1
+27 1 1
+278 1 1
+17 1 1
+994 1 1
+40 1 1
+219 5 5
+26 1 1
+900 1 1
+29 0 1
+26 1 1
+484 16 15
+61 9 9
+114 26 21
+801 1 1
+33 1 1
+465 32 32
+63 1 1
+37 1 1
+80 14 14
+211 1 1
+43 1 1
+156 1 1
+20 1 1
+685 1 1
+67 0 4
+711 1 1
+38 1 1
+402 7 7
+1045 1 1
+37 1 1
+4035 9 9
+247 0 4
+4146274 5734 17400
+330366 1 0
+2346742 55 0
+413177 0 3
+450 0 1
+9436 1 3
+7044 0 4
+2886 0 1
+635 0 1
+16567 0 1
+6918 0 1
+9285 0 1
+14909 0 8
+12879 0 2
+3330 0 2
+2673376 0 2
+2173174 7 7
+29817 2485 66108
+6473782 5 5
+39 1 1
+9574 2 0
+5879 1 1
+29 1 1
+6139 0 1
+2354 1 1
+28 1 1
+91 1 1
+23 0 1
+62 1 1
+142 15 16
+54 1 1
+22 3 3
+1479 4 4
+221 4 4
+132 0 1
+574 11 11
+23 0 1
+604 1 1
+44 1 1
+899 0 1
+70 10 12
+13561 1 1
+44 1 1
+4476 4 4
+799 25 26
+1466 18 18
+17896 0 4
+1668 0 1
+4250 1 1
+44 1 0
+4 1 0
+11 1 1
+4956 1 1
+18 0 1
+39 2 3
+4990 1 1
+47 13 13
+68 0 4
+9730 0 1
+355 1 0
+2186 1 1
+37 1 1
+6111 3 3
+100 4 4
+68 1 1
+43 1 1
+1126 7 5
+5520 8 8
+2316 1 1
+181 6 6
+50 1 1
+29 0 1
+83 1 1
+1073 150 154
+100 398 0
+141 1 1
+25272 1 0
+2132 4 0
+2522 1 1
+48 1 1
+1498528 1 0
+6044582 3000000 3000008
+1291149 16655 60038
+3837 0 3
+811 0 1
+2567 0 1
+7375465 1 0
+10 0 1
+42062 0 1
+19604621 0 1
+10692667 0 1
+110 1 0
+3577 3 0
+907 1 1
+18 1 1
+528 1 1
+50 1 1
+317 1 1
+64 251 535
+21 1 0
+140 1 0
+70 0 1
+77 10 9
+227 0 1
+142 5 5
+57 14 14
+43 1 1
+31034 99683 124100
+2301 2 0
+44 0 2
+568015 186612 87300
+355 5 5
+1916 3085 0
+924 4 0
+339 211 211
+963 14 15
+1157 12194 0
+242 23 23
+56 15 15
+405 20 20
+955 49 49
+1347 1 1
+2289 51 51
+555 253 253
+1723 77 77
+396 13 13
+112 3085 0
+3945 0 1
+209 23 23
+69 22 22
+81 20 20
+696 20 20
+58 69 69
+100 13 13
+326 137 137
+151 35 35
+1804 37 37
+1548 26 26
+324 23 23
+1932 17 17
+111 47 47
+128 16 16
+78 30 30
+1022 10 6
+78 0 1
+342 31 31
+86 23 23
+1580 255 255
+170 10 10
+398 23 23
+419 20 20
+955 55 55
+1139 11 11
+1925 276 0
+223 1 1
+56 1 1
+702 5 5
+17 3 3
+1030 1 1
+21 1 1
+363 1 1
+30 1 1
+785 16 16
+78 13 13
+1036 4 0
+482 68 68
+1069 10 10
+321 200 200
+434 43 43
+798 20 20
+56 25 25
+1007 5 5
+1198 24 24
+689 0 3
+743 32 32
+817 43 43
+574 11 11
+760 69 69
+1229 32 32
+272 29 29
+106 97 97
+1309 46 46
+850 4 4
+777 62 62
+86 36 36
+374 93 93
+2076 31 31
+195 56 56
+379 80 80
+64 11 11
+191 18 18
+1051 13 13
+52 119 113
+1347 1 1
+25 1 1
+3451 188 0
+3097 9 0
+2715 0 1
+11829 3 0
+6000 0 28
+10729 1 0
+3770769 0 1
+62 0 1
+22 0 1
+827 0 1
+1485 0 1
+242 1 0
+7142 0 1
+4029 3 3
+69 1 1
+15865 0 1
+83461 0 4
+5978 0 9
+2661 0 1
+1483 0 1
+15868 0 4
+17798 0 1
+2649 0 1
+3627 0 1
+4789 0 1
+9541 0 1
+6844 0 1
+3187 0 2
+411 0 14
+3056 0 4
+19776 0 3
+29085 1 0
+745 0 2
+11453 0 2
+16739 0 1
+14697 0 1
+8539 0 1
+25514443 0 1
+17680 1 0
+55359 1 0
+58 13 11
+5 1 0
+6 1 0
+5 1 0
+22 0 1
+4 1 3
+1515 0 1
+1111 0 1
+5736 6 6
+66213 0 1
+68 1 1
+24 7 6
+43 1 1
+33414 7 7
+22 1 1
+12288 22 22
+7002 1 0
+8588 1 1
+31 1 1
+15969 1 1
+32 1 1
+27034 1 1
+42 1 1
+3352 1 0
+15009 0 1
+20433 18 18
+32141 8 9
+116 41 41
+4920 0 1
+33364 0 1
+11160 1 0
+15 1 0
+28423 0 1
+43835 1 1
+24 2 4
+269244 4 4
+37 1 1
+17193 3 4
+53 11 12
+23 1 2
+7 1 1
+37978 9 9
+37743 1 1
+35 3 3
+26636 1 1
+17 1 1
+8728292 0 1
+16734777 71275 0
+657026 2 0
+2911 2 0
+1941 1 1
+35 1 1
+835 1 1
+116 1 1
+399 1 1
+101 0 1
+194 2 1
+450 0 1
+825 1 1
+73 1 1
+156 1 1
+58 1 1
+50 5 5
+153 11 11
+189 5 5
+233 1 1
+83 1 1
+642 1 0
+1380 1 1
+17 1 1
+315 1 1
+26 1 1
+789 901 0
+73 1 1
+45 1 1
+535 1 1
+34 1 1
+2007 7 7
+159 1 1
+26 1 1
+6362 13 13
+504325 25635 100008
+420771 232 0
+287688 104 0
+65 364 0
+183 55 0
+93 1 1
+46 1 1
+4002 1 1
+24 1 1
+190 0 147
+65 2 1
+8 0 1
+39 2 591
+306 50 0
+1938 1 0
+578 0 684
+291 1 0
+572289 108288 7108
+480202 0 1
+11866 6 6
+26917 1 0
+6097 15 15
+3074 1 0
+12292 1 0
+2209 1 0
+7358 1 0
+321393
+
+chain 2607822 8 146364022 + 12061935 12091854 8 146274826 + 12348580 12378713 990
+895 20 0
+1391 22 21
+53 88 0
+99 36 0
+9 0 346
+255 0 44
+496 1 0
+1013 0 4
+1698 1 0
+1054 37 37
+915 52 54
+2295 9 9
+123 1 0
+1295 162 162
+2903 50 50
+913 24 24
+2382 1 0
+299 85 85
+61 27 16
+1351 37 37
+974 4 4
+571 1 0
+530 11 0
+572 18 18
+76 4 4
+398 0 2
+54 31 31
+115 37 37
+125 364 364
+70 47 47
+56 8 8
+979 57 57
+248 50 50
+65 100 100
+82 1 0
+428 34 34
+51 6 0
+156 66 66
+257 132 132
+56 49 49
+91 19 19
+67 38 37
+142 6 6
+249 17 17
+123 104 104
+190 36 37
+355 5 1
+161 1 0
+89 48 48
+62 38 38
+136 67 67
+839
+
+chain 2498503 8 146364022 + 86726531 86754632 8 146274826 - 59364826 59419953 1092
+268 2 2
+114 6 0
+49 13 13
+1051 18 18
+117 8 3
+81 1 1
+64 4 4
+73 3 3
+379 1 1
+54 1 1
+183 13 13
+374 1 1
+43 1 1
+874 2 2
+22 1 1
+56 20 20
+712 1 1
+91 1 1
+374 1 1
+73 1 1
+88 21 21
+83 1 1
+27 1 1
+302 29 29
+1591 1 1
+27 4 0
+1250 1 1
+20 1 1
+2246 10 9115
+1002 49 49
+314 4 4
+116 32 32
+363 23 23
+1050 13 13
+119 0 8829
+1050 16 16
+1869 31 31
+119 0 9106
+593 13 13
+396 77 77
+1017 32 32
+888 39 39
+2895 1 1
+964 43 43
+1769 15 15
+292 35 35
+97 5 5
+313 13 13
+248 40 40
+435 10 11
+129 6 6
+712
+
+chain 1152177 8 146364022 + 142754466 142766515 8 146274826 + 142956164 142968213 2035
+12049
+
+chain 1081960 8 146364022 + 86772301 86823828 8 146274826 + 86857153 86905309 683
+56 15 15
+405 21 21
+1003 383 383
+837 0 1
+126 1 1
+531 1 0
+794 1 0
+73 32 32
+817 43 43
+214 432 432
+212 114 114
+373 28 28
+159 32 32
+832 44 44
+217 192 192
+330 927 923
+88 39 40
+1839 279 279
+283 13 13
+143 1716 1717
+49 3637 3637
+51 555 555
+97 1 1
+21 1 1
+133 1723 1723
+13 16 16
+48 8749 5664
+69 439 439
+62 43 43
+32 151 151
+35 1804 1804
+37 1548 1272
+26 2407 2407
+32 1719 1716
+31 1784 1784
+160 1995 1995
+55 3075 3075
+276 4870 4866
+68 1429 1429
+83 21 21
+67 434 434
+36
+
+chain 801068 8 146364022 + 145324300 145332588 8 146274826 + 145464193 145472508 5275
+3979 8 0
+2057 0 35
+2244
+
+chain 744541 8 146364022 + 86754632 86807992 8 146274826 + 86857851 86901670 688
+637 20 20
+440 88 88
+964 1 1
+2289 52 52
+554 1 1
+37 1 1
+1606 46 43
+288 6565 395
+203 3612 3608
+265 1500 1501
+278 1 1
+104 3213 3212
+43 214 214
+138 26 26
+268 212 212
+80 594 594
+32 832 832
+34 227 227
+16 27 27
+149 330 330
+33 21 21
+873 88 85
+39 1839 1839
+229 17 17
+33 9021 8745
+425 14725 11640
+30
+
+chain 657279 8 146364022 + 12141854 12149156 8 146274826 + 11932698 11940000 7963
+232 8 8
+466 34 34
+801 48 48
+815 68 68
+1203 29 29
+407 31 31
+467 26 26
+1146 18 18
+1503
+
+chain 521724 8 146364022 + 12149156 12156927 8 146274826 + 11940000 11947772 4417
+2168 0 1
+503 25 25
+153 202 202
+106 107 107
+851 39 39
+1679 1912 1912
+26
+
+chain 511532 8 146364022 + 142816515 142822092 8 146274826 + 142814667 142820000 26584
+2797 244 0
+2536
+
+chain 345755 8 146364022 + 142822092 142825705 8 146274826 + 142820000 142823612 174979
+3531 1 0
+81
+
+chain 305790 8 146364022 + 86765339 86795897 8 146274826 + 86865470 86901765 930
+477 0 9106
+123 31 31
+1705 14 14
+503 14 14
+15 1470 1466
+91 31 31
+52 35 35
+2 7890 7613
+26 560 560
+34 16750 13662
+405 127 127
+203
+
+chain 137107 8 146364022 + 85964683 85966170 8 146274826 + 86036733 86038220 940425
+1283 19 19
+185
+
+chain 118247 8 146364022 + 86759071 86769900 8 146274826 + 86874481 86903237 1649
+52 2533 2530
+13 16 16
+1046 0 8829
+123 13 13
+196 2878 11983
+29 3812 3808
+31 52 52
+35
+
+chain 97713 8 146364022 + 86793362 86840444 8 146274826 + 86862935 86885634 1255
+1752 44 44
+4 38618 14235
+46 1631 1631
+62 86 86
+36 374 374
+93 2302 2302
+56 379 379
+80 1400 1400
+119
+
+chain 85095 8 146364022 + 85924850 85927320 2 242951149 - 28701067 28703532 1485529
+52 143 142
+173 208 208
+107 181 181
+68 70 66
+129 101 101
+183 373 373
+87 163 163
+164 198 198
+70
+
+chain 47407 8 146364022 + 85907218 85908847 10 135374737 - 19950497 19952126 2691979
+115 531 531
+182 240 240
+64 202 202
+122 22 22
+52 45 45
+54
+
+chain 45318 8 146364022 + 85909407 85911400 3 199501827 - 58732681 58734687 2832173
+138 151 157
+53 129 125
+171 674 685
+80 116 116
+82 347 347
+52
+
+chain 43260 8 146364022 + 12069066 12090712 8 146274826 - 138168279 138189929 1162
+37 915 915
+52 6789 6802
+48 3620 3620
+85 61 59
+27 1351 1348
+5 1 1
+30 3223 3218
+22 115 115
+37 465 465
+24 3764 3760
+90 837 842
+48
+
+chain 38958 8 146364022 + 12159413 12159829 8 146274826 + 11950258 11950674 3228
+416
+
+chain 38127 8 146364022 + 86726451 86753339 8 146274826 - 59376930 59524482 1121
+80 11856 20676
+48 435 435
+32 4503 13609
+31 1121 10227
+77 1017 94649
+32 888 888
+39 3860 3860
+15 1 1
+26 2078 2078
+33 678 678
+38
+
+chain 31437 8 146364022 + 85955665 85955994 3 199501827 - 6162711 6163040 4382021
+329
+
+chain 30755 8 146364022 + 85915208 85915710 8 146274826 - 4216734 4217241 4503764
+255 160 165
+87
+
+chain 27896 8 146364022 + 940417 941596 8 146274826 + 930633 930948 5586021
+100 54 0
+108 810 0
+107
+
+chain 26413 8 146364022 + 85978864 85981144 9 140273252 - 40203469 40205589 6324943
+79 1134 635
+70 83 416
+56 207 205
+56 22 22
+63 455 463
+55
+
+chain 25390 8 146364022 + 85975200 85975766 6 170899992 - 89617888 89618457 6830715
+67 141 143
+50 38 39
+54 78 78
+138
+
+chain 20285 8 146364022 + 85975766 85977415 3 199501827 - 82189783 82191451 9116338
+8 700 763
+50 465 465
+54 309 265
+63
+
+chain 20226 8 146364022 + 85979170 85979799 3 199501827 - 161413320 161413963 10270718
+61 394 408
+174
+
+chain 20141 8 146364022 + 12151827 12152420 8 146274826 + 11902715 11903309 638255
+25 153 154
+202 106 106
+107
+
+chain 19400 8 146364022 + 85925267 85925628 10 135374737 + 135080720 135081080 3597149
+102 2 1
+54 131 131
+72
+
+chain 18915 8 146364022 + 942460 942893 8 146274826 + 930516 930733 3835109
+63 162 0
+46 108 54
+54
+
+chain 18062 8 146364022 + 942088 942460 8 146274826 + 930684 930948 5250846
+157 108 0
+107
+
+chain 17886 8 146364022 + 943174 943431 8 146274826 + 930690 930893 4105167
+149 55 1
+53
+
+chain 15443 8 146364022 + 941596 942029 8 146274826 + 930516 930841 4827909
+64 207 153
+65 54 0
+43
+
+chain 14855 8 146364022 + 85924497 85927134 X 154913754 + 50874366 50877002 1910511
+90 57 57
+50 108 108
+48 52 52
+79 801 801
+50 953 952
+50 236 236
+63
+
+chain 12854 8 146364022 + 144743895 144744094 8 146274826 + 144814885 144815084 3961669
+199
+
+chain 12042 8 146364022 + 85907589 85907864 4 191273063 + 22500316 22500591 2841396
+81 177 177
+17
+
+chain 11713 8 146364022 + 36265496 36265620 7 158821424 - 150143040 150143164 19315609
+124
+
+chain 10744 8 146364022 + 85909592 85910073 4 191273063 - 317022 317498 3271263
+71 86 86
+68 232 227
+24
+
+chain 10295 8 146364022 + 85917935 85918395 16 88827254 - 19324120 19324578 22152835
+60 331 329
+69
+
+chain 9964 8 146364022 + 85927135 85927250 3 199501827 - 159900532 159900647 3087651
+115
+
+chain 9833 8 146364022 + 85908046 85908504 8 146274826 - 114124165 114124623 2795681
+56 59 59
+58 162 162
+123
+
+chain 9709 8 146364022 + 943330 943485 8 146274826 + 930684 930839 15332741
+48 53 53
+54
+
+chain 9657 8 146364022 + 86004292 86004501 X 154913754 + 27575363 27575573 23616431
+52 93 94
+64
+
+chain 9406 8 146364022 + 85945093 85945452 12 132349534 + 8944725 8945099 24220725
+61 243 258
+55
+
+chain 9151 8 146364022 + 85910121 85910218 10 135374737 - 38564811 38564908 24713323
+97
+
+chain 8406 8 146364022 + 85924386 85924476 5 180857866 + 127114677 127114767 25803856
+90
+
+chain 7367 8 146364022 + 85911400 85911623 X 154913754 - 44623158 44623382 4824008
+72 91 92
+60
+
+chain 7214 8 146364022 + 85983029 85983106 3 199501827 + 182981094 182981171 27755476
+77
+
+chain 7178 8 146364022 + 85926461 85926638 7 158821424 + 131250991 131251168 8959140
+97 79 79
+1
+
+chain 6913 8 146364022 + 85946010 85946083 5 180857866 - 76444763 76444836 28360557
+73
+
+chain 6866 8 146364022 + 85981016 85981089 3 199501827 - 137848275 137848348 18929141
+73
+
+chain 6722 8 146364022 + 85915749 85915820 6 170899992 - 41858720 41858791 28750065
+71
+
+chain 6523 8 146364022 + 85874468 85874538 6 170899992 + 80165568 80165638 29222062
+70
+
+chain 6284 8 146364022 + 48138290 48138355 12 132349534 - 99530740 99530805 29826800
+65
+
+chain 6255 8 146364022 + 86830665 86832268 8 146274826 + 86851473 86853076 5870
+41 1533 1533
+29
+
+chain 6230 8 146364022 + 143494784 143494849 8 146274826 + 143492621 143492686 29969115
+65
+
+chain 5949 8 146364022 + 85946624 85946687 7 158821424 - 150469376 150469439 30705065
+63
+
+chain 5930 8 146364022 + 86000088 86000150 4 191273063 - 114595117 114595179 30759641
+62
+
+chain 5722 8 146364022 + 85909210 85909271 4 191273063 - 32715229 32715290 31306692
+61
+
+chain 5681 8 146364022 + 85907187 85907519 7 158821424 - 141596962 141597294 3108677
+31 137 137
+3 85 85
+76
+
+chain 5594 8 146364022 + 85966181 85966240 2 242951149 + 129692100 129692159 31643052
+59
+
+chain 5348 8 146364022 + 85946168 85946224 X 154913754 + 22697258 22697314 32405249
+56
+
+chain 5330 8 146364022 + 85945000 85945056 X 154913754 - 56717679 56717735 32442268
+56
+
+chain 5292 8 146364022 + 85926370 85926785 12 132349534 + 42776733 42777148 2271290
+75 280 280
+14 27 27
+19
+
+chain 5161 8 146364022 + 941932 941986 8 146274826 + 930312 930366 21107216
+54
+
+chain 5012 8 146364022 + 85946286 85946339 1 247249719 - 150482359 150482412 33477745
+53
+
+chain 4929 8 146364022 + 941384 941435 8 146274826 + 930304 930355 33748771
+51
+
+chain 4927 8 146364022 + 85874401 85874458 12 132349534 + 21319375 21319432 33750711
+57
+
+chain 4920 8 146364022 + 85945525 85945576 10 135374737 + 87468307 87468358 33788347
+51
+
+chain 4810 8 146364022 + 942523 942621 8 146274826 + 930741 930839 7547023
+98
+
+chain 4803 8 146364022 + 85970009 85970060 11 134452384 + 10157776 10157827 34198727
+51
+
+chain 4793 8 146364022 + 85975065 85975115 21 46944323 - 30257577 30257627 34245350
+50
+
+chain 4738 8 146364022 + 942303 942352 8 146274826 + 930521 930570 34412340
+49
+
+chain 4461 8 146364022 + 85910862 85910919 X 154913754 + 151305652 151305709 4935543
+57
+
+chain 4271 8 146364022 + 86793237 86793293 8 146274826 + 86902190 86902246 1452514
+56
+
+chain 4178 8 146364022 + 85915489 85915539 3 199501827 + 132299011 132299061 5319224
+50
+
+chain 4079 8 146364022 + 85926268 85926343 2 242951149 - 211437807 211437882 2547607
+75
+
+chain 3965 8 146364022 + 85910617 85910659 5 180857866 + 105218926 105218968 18292131
+42
+
+chain 3826 8 146364022 + 85911256 85911310 7 158821424 + 49570162 49570216 23840400
+54
+
+chain 3809 8 146364022 + 86829249 86829292 8 146274826 + 86874439 86874482 7328
+43
+
+chain 3796 8 146364022 + 85928889 85929141 X 154913754 + 121492736 121492988 2565989
+99 40 40
+113
+
+chain 3755 8 146364022 + 85925629 85925714 5 180857866 + 141403818 141403903 2005326
+54 23 23
+8
+
+chain 3680 8 146364022 + 36265255 36265294 21 46944323 - 8931342 8931381 34138292
+39
+
+chain 3466 8 146364022 + 85917822 85917882 11 134452384 - 107659023 107659083 22827264
+60
+
+chain 3460 8 146364022 + 85925991 85926082 19 63811651 + 46688677 46688768 2544872
+91
+
+chain 3412 8 146364022 + 85981195 85981250 12 132349534 - 23016451 23016506 20760996
+55
+
+chain 3378 8 146364022 + 144744318 144744353 8 146274826 + 144814727 144814762 26884487
+35
+
+chain 3372 8 146364022 + 12064503 12064539 8 146274826 + 12351001 12351037 28926895
+36
+
+chain 3336 8 146364022 + 85910527 85910617 6 170899992 + 121091189 121091279 5885029
+90
+
+chain 3306 8 146364022 + 85975140 85975200 5 180857866 - 14200316 14200376 14215921
+60
+
+chain 3123 8 146364022 + 144455804 144455869 8 146274826 + 144526757 144526822 16634618
+65
+
+chain 3122 8 146364022 + 85910073 85910106 10 135374737 + 91515201 91515234 27999029
+33
+
+chain 2973 8 146364022 + 85975297 85975339 11 134452384 + 70894433 70894475 12515399
+42
+
+chain 2846 8 146364022 + 85980398 85980477 6 170899992 + 12780268 12780347 14041671
+79
+
+chain 2664 8 146364022 + 85980653 85980843 13 114142980 + 79661332 79661527 13462115
+54 70 75
+66
+
+chain 2542 8 146364022 + 86811232 86811259 8 146274826 + 86750599 86750626 581042
+27
+
+chain 2408 8 146364022 + 86780113 86780140 8 146274826 + 86901259 86901286 3284
+27
+
+chain 2314 8 146364022 + 85909329 85909403 5 180857866 - 126448590 126448664 8133335
+74
+
+chain 2312 8 146364022 + 85964546 85964619 5 180857866 - 22206487 22206560 13216855
+73
+
+chain 2306 8 146364022 + 85909062 85909878 5 180857866 - 76491094 76491924 7171448
+57 726 740
+33
+
+chain 2277 8 146364022 + 85945069 85945093 2 242951149 - 76417863 76417887 30610067
+24
+
+chain 2276 8 146364022 + 85915156 85915196 9 140273252 + 96271703 96271743 9134049
+40
+
+chain 2255 8 146364022 + 12171549 12171574 8 146274826 + 11962388 11962413 4339
+25
+
+chain 2213 8 146364022 + 85976678 85976734 10 135374737 + 107478570 107478626 23840391
+56
+
+chain 2193 8 146364022 + 85909817 85909844 1 247249719 - 204777828 204777855 6141044
+27
+
+chain 2188 8 146364022 + 85915463 85915489 4 191273063 + 117566433 117566459 5547542
+26
+
+chain 2086 8 146364022 + 85907670 85907692 9 140273252 + 84577624 84577646 25068333
+22
+
+chain 2042 8 146364022 + 85906786 85906876 1 247249719 - 187757137 187757227 3120497
+90
+
+chain 2008 8 146364022 + 85975339 85978010 12 132349534 - 60955403 60957663 7657094
+69 2448 2037
+58 20 20
+76
+
+chain 1976 8 146364022 + 85910386 85910476 11 134452384 + 108691426 108691516 10944711
+90
+
+chain 1915 8 146364022 + 85915895 85915946 2 242951149 - 57258601 57258652 18793758
+51
+
+chain 1706 8 146364022 + 85926558 85926608 20 62435964 + 52983902 52983952 9284939
+50
+
+chain 1666 8 146364022 + 85915539 85915568 3 199501827 - 58686941 58686970 11643280
+29
+
+chain 1625 8 146364022 + 85977632 85977856 3 199501827 - 45071352 45071581 10048168
+62 161 166
+1
+
+chain 1603 8 146364022 + 36265620 36265653 4 191273063 + 189716401 189716434 1596951
+33
+
+chain 1585 8 146364022 + 85907040 85907092 7 158821424 + 38674874 38674926 25744726
+52
+
+chain 1584 8 146364022 + 85964393 85964443 1 247249719 - 57954630 57954680 20174423
+50
+
+chain 1470 8 146364022 + 85911121 85911160 15 100338915 + 92120615 92120654 21684489
+39
+
+chain 1463 8 146364022 + 942731 942785 8 146274826 + 930679 930733 5019737
+54
+
+chain 1440 8 146364022 + 85911043 85911098 1 247249719 - 141715465 141715520 4313974
+55
+
+chain 1426 8 146364022 + 85978253 85978320 2 242951149 - 208172805 208172872 22624190
+67
+
+chain 1403 8 146364022 + 85928837 85929028 18 76117153 + 39707440 39707631 2816562
+52 99 99
+40
+
+chain 1344 8 146364022 + 85907124 85907170 12 132349534 + 45103963 45104009 16171151
+46
+
+chain 1332 8 146364022 + 85927450 85927503 1 247249719 - 29234742 29234795 3133635
+53
+
+chain 1287 8 146364022 + 85907361 85907411 1 247249719 - 78547145 78547195 4245040
+50
+
+chain 1276 8 146364022 + 85927323 85927376 4 191273063 - 93337200 93337253 2720957
+53
+
+chain 1269 8 146364022 + 85908257 85908286 9 140273252 - 124490379 124490408 3695355
+29
+
+chain 1238 8 146364022 + 85978601 85978678 9 140273252 - 23294193 23294270 19053025
+77
+
+chain 1193 8 146364022 + 144455743 144455792 8 146274826 + 144526504 144526553 26679478
+49
+
+chain 1175 8 146364022 + 12087452 12087488 11 134452384 - 63301652 63301688 1994288
+36
+
+chain 1137 8 146364022 + 85909119 85909164 2 242951149 + 35848313 35848358 13461114
+45
+
+chain 1048 8 146364022 + 86824709 86824734 8 146274826 + 86857705 86857730 2636
+25
+
+chain 1045 8 146364022 + 85911001 85911043 15 100338915 - 40210675 40210717 4055996
+42
+
+chain 1028 8 146364022 + 85910323 85910373 4 191273063 + 26203887 26203937 5050480
+50
+
+chain 1020 8 146364022 + 85924694 85924736 3 199501827 + 1701599 1701641 4262142
+42
+
+chain 1005 8 146364022 + 85977261 85977320 10 135374737 + 45388722 45388781 14596230
+59
+
+chain 998 8 146364022 + 85908847 85908872 4 191273063 + 183519567 183519592 8543079
+25
+
+chain 985 8 146364022 + 85918576 85918627 3 199501827 - 21820872 21820923 24828426
+51
+
+chain 981 8 146364022 + 144744094 144744133 8 146274826 + 144814821 144814860 14840226
+39
+
+chain 922 8 146364022 + 85918981 85919046 X 154913754 - 100261670 100261735 22334691
+65
+
+chain 912 8 146364022 + 85964449 85964513 6 170899992 + 131272389 131272453 24950513
+64
+
+chain 888 8 146364022 + 85915710 85915739 9 140273252 + 12069456 12069485 13568361
+29
+
+chain 867 8 146364022 + 85976220 85976271 X 154913754 - 36573362 36573413 23586363
+51
+
+chain 857 8 146364022 + 86832445 86832471 8 146274826 + 86747431 86747457 7742
+26
+
+chain 802 8 146364022 + 85978516 85978572 3 199501827 + 80520031 80520087 22639668
+56
+
+chain 801 8 146364022 + 85911160 85911249 16 88827254 + 31611661 31611750 16482423
+89
+
+chain 785 8 146364022 + 85917259 85917324 5 180857866 - 163179499 163179564 25049793
+65
+
+chain 721 8 146364022 + 85926739 85926765 18 76117153 + 15364211 15364237 2792298
+26
+
+chain 647 8 146364022 + 85918645 85918703 11 134452384 - 90657004 90657062 25582649
+58
+
+chain 612 8 146364022 + 941818 941867 8 146274826 + 930360 930409 12502809
+49
+
+chain 596 8 146364022 + 85976593 85979111 X 154913754 - 42670843 42673368 13030869
+53 2388 2395
+77
+
+chain 568 8 146364022 + 85966335 85966385 X 154913754 + 36275879 36275929 27751459
+50
+
+chain 474 8 146364022 + 85917714 85917772 1 247249719 + 62707004 62707062 26279221
+58
+
+chain 396 8 146364022 + 85977502 85977572 X 154913754 - 138803117 138803187 17501406
+70
+
+chain 369 8 146364022 + 85976646 85976678 7 158821424 + 51906674 51906706 15299893
+32
+
+chain 360 8 146364022 + 85980297 85980349 12 132349534 - 124024481 124024533 24774043
+52
+
+chain 337 8 146364022 + 85981293 85981372 1 247249719 - 152445011 152445090 12777550
+79
+
+chain 328 8 146364022 + 85976447 85976474 2 242951149 - 99982783 99982810 22051776
+27
+
+chain 310 8 146364022 + 85976849 85976905 3 199501827 - 69459686 69459742 25770085
+56
+
+chain 286 8 146364022 + 85979114 85979170 7 158821424 - 11181572 11181628 19756881
+56
+
+chain 232 8 146364022 + 85978010 85978057 1 247249719 + 108819891 108819938 19586297
+47
+
+chain 11336430536 9 141213431 + 10000 141153431 9 140273252 + 0 140273252 13
+189075 17 17
+39464594 50000 50000
+261110 50000 50000
+208233 50000 50000
+142805 50000 50000
+464507 50000 50000
+152873 50000 50000
+172579 50000 50000
+799200 4 0
+398958 50000 50000
+549743 100000 50000
+632871 50000 50000
+680077 50000 50000
+181647 50000 50000
+291910 100000 50000
+465318 50000 50000
+350909 50000 50000
+194609 100000 50000
+370337 176 0
+128581 100047 50047
+157499 18150000 18100000
+450681 50000 50000
+223855 50000 50000
+162441 50000 50000
+159539 50000 50000
+199148 50000 50000
+194491 100000 50000
+158462 150000 50000
+471702 150000 50000
+376183 150000 50000
+174765 150000 50000
+289439 50000 50000
+682157 50000 50000
+158187 100000 50000
+187806 50000 50000
+178933 100000 50000
+21507948 100000 50000
+85380 150000 50000
+834971 0 1
+39559293 150000 100000
+3818133 50000 200000
+2075804 50000 30000
+1936434
+
+chain 1179 9 141213431 + 46931376 46931552 9 140273252 - 98415895 98416071 50
+176
+
+chain 443 9 141213431 + 47160133 47160180 9 140273252 - 72994158 72994205 112
+47
+
+chain 1574309 MT 16571 + 0 16571 MT 16571 + 0 16571 1542
+16571
+
+chain 14267284136 X 155270560 + 60000 155260560 X 154913754 + 0 154913754 8
+34821 50000 50000
+86563 50000 30000
+766173 50000 50000
+36556 50000 50000
+80121 50000 90000
+754004 50000 100000
+5505644 50000 0
+3064790 50079 0
+26309505 50000 25000
+201176 8 0
+7416 0 2
+53134 8 0
+3073 0 12
+21097 0 2
+60831 2 0
+57728 0 20
+54336 0 1
+31675 0 4
+9987 4 0
+12108 0 4
+11225906 0 2000
+356252 50059 50059
+77342 1 1
+17 1 1
+94 0 3
+266 10 10
+113 1 1
+21 1 1
+5400 0 5
+4996 7 15
+3222 5 1
+6456 1 0
+1476 5 5
+2100 1 1
+40 1 1
+1316 0 1
+2446 1 0
+1555 0 2
+11220 1 0
+2639 1 0
+5190 0 4
+79 8 0
+5086 0 1
+2663 1 0
+9149 7 8
+1851 0 1
+9081 0 1
+7248 25 0
+208 28 0
+25 2 0
+15 83 0
+17 116 4
+2536 0 1
+1394 0 6
+12550 0 42
+822 4 0
+30578 1 0
+3711 4 0
+3637 1 0
+11945 0 1
+20204 0 1
+4172 8 0
+5679 1 0
+23827 0 2
+54817 0 1
+657 0 1
+342931 50000 180000
+2052068 27 1
+5375 2 0
+46 0 2
+6489 0 1
+7175 2 0
+1239 2 0
+4301 0 4
+27254 0 1
+4244 0 2
+717 0 2
+260 0 6
+26075 1 0
+236464 50000 50000
+6136098 3100000 3000000
+13518993 1 0
+449 1 0
+4535 4 0
+755 1 0
+1102 1 0
+24 1 1
+107 2 0
+3470 0 1
+1108 1 0
+4775 1 0
+8628 1 1
+46 1 1
+1072 1 1
+44 1 1
+292 4 5
+9091 4 4
+2218 4 4
+705 5 1
+452 0 1
+332 0 1
+1801 7 1
+3960 1 0
+2007 1 0
+3337 1 0
+2093 1 0
+407 310 0
+6130 1 1
+36 1 1
+1697 1 0
+97 13 0
+7624 1 1
+19 1 1
+3806 24 24
+3103 1 0
+779 7 7
+721 1 1
+43 1 1
+1626 0 1
+6146 0 2
+150 1 1
+47 1 1
+2172 0 2
+398 1 1
+31 1 1
+1334 16 16
+1663 1 1
+18 1 1
+2105 1 0
+9 1 1
+1409 1 1
+33 1 1
+1753 1 0
+408 0 1
+1916 1 0
+1928 0 12
+3800 1 1
+15 1 1
+2921 0 1
+4597 0 2
+486 6 0
+308 24 24
+1056 1 1
+44 1 1
+186 1 1
+46 1 1
+3037 0 1
+2301 0 3
+3876 1 1
+22 1 1
+1724 1 0
+3733 1 0
+627 1 0
+250 0 1
+194 1 1
+26 1 1
+20797 10 10
+2445 0 1
+1733 2 0
+1001 0 12
+4394 9 9
+4052 9 10
+670 1 1
+96 0 6
+26 1269 1568
+28 3 2
+10 1486 1188
+25 6 0
+18 1 1
+62 17 17
+77 1 0
+4949 10 10
+4690 1 0
+7343 0 1
+1248 0 1
+1259 0 1
+1347 4 0
+1532 0 1
+3797 16 16
+807 0 1
+2427 0 1
+48 1 0
+287 0 1
+611353 1 0
+1041 0 6
+371 1 0
+227 1 0
+2806 0 1
+36 1 1
+234 1 1
+23 1 1
+584 0 1
+22241 1 1
+65 1 1
+4605 1 0
+2337 20 0
+2119 1 0
+6170 13 9
+10665 1 0
+14631 0 1
+5359 0 4
+4004 0 1
+3182 0 11
+3897 16 14
+2551 0 1
+1824 0 1
+5274 1 1
+41 1 1
+4309 1 0
+3827 1 0
+4594 1 0
+65 1 1
+1170 1 1
+42 4 4
+214 1 0
+5228 1 0
+553 0 1
+6270 1 1
+12 1 1
+2849 12 13
+156 2 0
+8820 1 1
+41 1 1
+472 1 1
+65 1 0
+8 1 1
+1162 0 1
+565 1 1
+48 1 1
+536 1 2
+766 2 0
+4520 1 0
+1574 0 1
+503 1 0
+2558 1 0
+250061 7 7
+9650 18 18
+3208 1 1
+25 1 0
+744 0 2
+2994 1 1
+33 1 1
+1331 0 1
+87 19 19
+1935 5 0
+7 6 0
+1292 1 1
+35 1 1
+2485 1 1
+35 1 1
+4184 23 23
+13077 8 15
+671 4 0
+428 1 0
+4736 0 1
+3849 1 0
+6745 16 16
+2344 1 1
+41 1 1
+7917 1 0
+3876 1 1
+75 1 1
+1429 7 7
+11933 1 1
+28 1 1
+409 1 0
+11 1 1
+1223 12 12
+5354 1 0
+1255 6 0
+851 1 1
+45 1 1
+144 1 1
+47 5 5
+5929 0 4
+422 1 0
+2949 6 0
+193 1 1
+319 4 4
+3592 33 33
+3115 3 1
+1074 0 1
+2465 1 1
+40 1 1
+640 0 2
+550 1 1
+32 1 1
+4096 1 1
+29 1 1
+949 6 6
+6258 0 1
+3957 0 1
+19608 1 1
+48 1 1
+234 1 0
+16874 11 11
+1018 0 321
+2624 0 1
+4553 3 0
+491 6 0
+7496 1 1
+10 10 0
+76 4 0
+3314 1 1
+32 1 1
+5217 0 1
+3540 0 1
+1254 48 48
+1124 18 0
+3109 8 8
+3248 0 1
+1946 1 1
+48 1 1
+9620 2 0
+31242 50000 20000
+36075685 0 3
+36004 1 1
+27 1 1
+5196 1 0
+293 2 0
+13307 3 0
+2420 0 6
+1863 2 0
+2911 1 0
+3233 0 2
+66 0 1
+2375 0 10
+4894 0 1
+745 0 1
+3897 13 0
+4430 1 1
+48 1 4
+20 2 0
+279 2 0
+33 1 1
+48 0 1
+387 8 8
+692 1 0
+375 0 3
+380 23 23
+1289 1 1
+29 1 1
+12336 331 0
+852 0 4
+48 4 0
+4350 1 1
+59 1 1
+4306 5 0
+129 0 2
+3001 1 0
+1332 5 8
+23273 1 0
+30174 39 27
+337 3 0
+2838 0 1
+1614 9 0
+313 1 0
+82 0 4
+173 1 1
+25 1 1
+4912 39 0
+1863 1 0
+2931 0 1
+3134 3 0
+390880 1 0
+7199 0 1
+305 0 2
+1811 0 2
+5449 3 0
+7443 2 0
+2171 1 1
+27 1 1
+2668 2 0
+2180 1 0
+1170 9 0
+1450 16 16
+3080 0 1
+11157 0 1
+678 1 1
+28 1 1
+698 0 1
+112 0 1
+1831 0 3
+14327 0 2
+2247 3 0
+380 1 1
+28 1 1
+1265 21 19
+7184 2 3
+4225 14 9
+1002 1 0
+3854 0 4
+2535 1 1
+30 1 1
+794 0 1
+25 1 1
+76140 50000 70000
+1432750 0 7772
+681872 50000 20000
+4278742 56347 0
+12021233 1 0
+8 0 1
+1775 0 1
+1468 1 1
+51 14 16
+6 1 0
+6 1 0
+11 5 4
+7 1 0
+4 1 0
+75 2 1
+26 0 1
+16 1 0
+9 1 0
+19 2 0
+22 0 1
+9 1 0
+5 3 1
+14 7 6
+38 0 1
+26 1 1
+62 40 39
+1687 1 0
+54 1 0
+8528 1 0
+2722 1 0
+6240 1 0
+33 1 0
+121285 0 1
+6 1 0
+35 0 1
+1381 1 0
+5368 0 1
+3079 1 0
+10863441 4 0
+1799 1 1
+24 1 1
+334 0 1
+4960 0 17
+1160 1 1
+34 1 1
+6153 0 3
+1346 0 4
+103 0 4
+168 27 27
+2640 12 12
+304 16 0
+719 1 0
+3286 0 1
+10182 9 0
+804 1 1
+28 1 1
+749 1 0
+3387 1 1
+47 1 1
+482 1 0
+455 15 15
+719 1 1
+18 1 1
+2074 1 0
+1349 4 0
+3927 1 1
+18 1 1
+907 1 0
+2972 0 2
+115 1 1
+37 1 1
+4428 0 1
+1120 0 1
+4055 0 5
+2929 0 3
+3590 1 1
+47 1 1
+62 0 1
+947 1 1
+45 1 1
+1639 1 1
+32 1 1
+1076 1 0
+3996 0 4
+686 41 41
+7238 0 1
+1733 0 1
+1451 2 0
+617 0 1
+4375 1 0
+2194 15 16
+349 1 1
+27 1 1
+8237 0 1
+499 1 1
+37 2 2
+968 0 1
+34 1 1
+6337 1 1
+18 1 1
+8162 1 1
+21 0 5
+7668 45 45
+1562 0 1
+6017 5 5
+3872 0 8
+5421 0 1
+532 7 6
+5673 4 0
+1542 0 4
+890 1 3
+2561 0 1
+1692 0 1
+1142 1 1
+32 1 1
+503 1 2
+123 1 1
+75 1 1
+2322 0 1
+201 0 1
+40 3 3
+149 0 3
+1441 1 1
+40 1 1
+159 0 2
+1278 1 1
+33 1 1
+221 1 0
+31 1 1
+161 10 9
+1890 1 0
+132 1 1
+37 1 1
+514 23 17
+1373 0 4
+907 17 17
+714 31 30
+55 1 1
+24 1 1
+1038 0 2
+95 5 1
+1094 1 1
+170 1 1
+844 3 0
+369 1 1
+39 1 1
+650 1 1
+41 1 1
+176 1 1
+10 1 1
+688 0 1
+7637 0 4
+2653 1 1
+26 4 0
+46 1 1
+727 0 8
+2197 1 0
+13466 1 0
+3510 2 0
+2147 1 1
+44 3 0
+1320 11 11
+213 4 0
+102 0 1
+3239 1 0
+1492 0 3
+107 1 1
+35 14 0
+2391 1 1
+39 2 0
+436 0 4
+2271 0 8
+6868 3 0
+7183 1 0
+5104 3 0
+182 0 1
+3131 1 1
+31 0 1
+14 1 1
+59 0 1
+373 1 1
+42 1 1
+235 13 13
+1608 5 0
+152 1 1
+106 1 1
+783 34 34
+1633 1 1
+29 0 3
+821 1 1
+24 1 1
+1178 1 1
+33 1 1
+328 1 1
+27 1 1
+5682 1 0
+11 1 5
+146398 50000 30000
+59809 2 0
+3389 1 1
+37 1 1
+11606 1 0
+1597 1 0
+618 1 1
+47 1 1
+2698 1 0
+826 5 5
+33 2 0
+2560 14 0
+98 3 0
+1287 1 0
+7600 1 0
+9897 8 0
+7157 1 0
+32 1 1
+1698 1 0
+754 0 2
+6787 1 0
+584 2 0
+1107 1 1
+40 1 1
+365 1 1
+35 1 1
+400 8 0
+11443 1 0
+1973 1 0
+497 46 46
+657 1 0
+716 1 1
+25 1 1
+1570 2 0
+433 0 2
+905 2 0
+94 1 1
+28 1 1
+2490 1 1
+16 1 1
+5054 1 9
+2184 2 0
+2955 21 23
+794 0 1
+1563 1 1
+20 1 1
+1627 0 11
+1676 0 2
+1527 1 0
+676 1 1
+29 1 1
+1245 1 1
+34 1 0
+1192 7 0
+27 1 0
+1940 0 1
+3421 2 0
+17 1 1
+774 30 0
+97 6 6
+59 26 12
+840 1 1
+19 1 1
+2036 13 1
+26 14 0
+1114 1 0
+25 1 1
+380 0 16
+160 1 1
+17 1 1
+1151 4 0
+699 0 1
+29 2 0
+409 1 1
+49 1 1
+1240 1 1
+37 3 3
+2248 1 0
+1828 1 0
+1997 5 1
+4640 4 4
+4555 0 2
+149 0 52
+619 2 2
+16 1 1
+83 22 0
+56 57 1
+2531 0 8
+4250 1 1
+15 1 1
+2203 0 4
+1665 0 10
+415 2 0
+395 19 18
+15708 0 1
+161 4 0
+79 14 0
+543 1 1
+42 1 1
+3261 18 18
+139 46 46
+403 1 1
+18 1 1
+5405 1 0
+1104 1 1
+53 1 1
+392 1 1
+55 3 3
+3352 9 0
+692 1 9
+8 4 0
+27 3 97
+39 3 1
+21 3 51
+61 0 2
+8931 1 0
+6692 1 2
+1141 0 2
+196 2 0
+389 1 1
+30 1 1
+949 0 1
+6057 0 3
+4741 1 0
+7689 2 0
+2046 18 18
+215 0 1
+46885 2 0
+24138 2 0
+4037 1 0
+4047693 1 0
+9545 0 2
+11590 4 0
+1698 1 3
+13506 37 37
+5380 4 0
+1806 1 1
+44 1 1
+2581 0 2
+10620 0 1
+3804 0 1
+339 0 2
+476 0 1
+5861 8 5
+109 0 14
+901 1 1
+19 1 1
+45 2 0
+1736 1 0
+6625 2 0
+7812 4 0
+7678 2 0
+5068 4 0
+21 1 0
+4170 0 1
+1671 6 0
+6333 0 16
+902 1 1
+44 1 1
+384 0 6
+23418 2 0
+36 1 1
+8900 0 4
+222 1 1
+49 1 1
+2783 0 1
+2641 0 1
+136 20 20
+1279 0 1
+3924 6 6
+13054 6 0
+8965 23 36
+4094 2 0
+2269 1 0
+13621 16 16
+2621 0 2
+30076 1 1
+49 1 1
+102 1 0
+8824 1 1
+25 1 1
+1730 1 1
+47 1 1
+3339 0 1
+131 0 16
+83 16 0
+89 6 0
+2826 33 33
+3509 1 0
+541 1 0
+6288 0 4
+3814 2 0
+7260 0 1
+806 68 0
+1162 0 1
+2230 1 0
+1109 0 1
+1106 2 0
+12396 0 1
+26207 1 1
+21 1 1
+3541 18 18
+525 0 16
+1326 7 7
+525 0 1
+4198 0 1
+4682 13 13
+890 0 2
+816 0 2
+1961 0 4
+24586 1 1
+19 1 1
+4403 1 0
+1342 1 0
+57 12 11
+2225 1 0
+2011 0 35
+10543 0 1
+9766 6 12
+2489 2 1
+20 1 1
+1541 0 12
+1130 1 1
+34 1 1
+927 0 1
+4003 0 1
+966 1 0
+149 0 1
+844 8 0
+4324 1 1
+25 1 1
+569 7 6
+6361 1 0
+3074 0 1
+1539 3 9
+634 1 1
+39 1 1
+8610 13 12
+760 2 0
+4311 0 6
+3122 0 2
+369 1 0
+9963 10 10
+2191 1 1
+23 1 1
+1060 1 1
+19 1 1
+240 12 12
+1748 1 1
+45 1 1
+1040 1 1
+31 1 1
+7446 1 1
+25 1 1
+8379 7 7
+7325 3 0
+357 0 1
+1313 0 1
+11627 4 0
+5862 1 0
+9750 1 0
+3539 0 16
+5672 13 13
+2885 0 4
+8179 1 0
+753 0 1
+4317 0 2
+1318 1 0
+957 0 1
+825 12 12
+1109 0 16
+3736 17 17
+2236 8 8
+7791 15 185
+149 1 1
+21 2 0
+636 1 1
+22 1 0
+42 1 1
+1634 4 4
+3380 0 3
+979 2 0
+3429 0 1
+7132 0 14
+1733 1 1
+38 0 1
+88 1 0
+630 6 6
+489 5 0
+22 1 0
+94 1 0
+42 0 1
+17 1 0
+27 1 0
+172 1 1
+37 1 1
+191 1 1
+66 1 1
+630 1 0
+261 30 30
+1282 1 0
+16 1 1
+429 1 0
+1588 1 1
+20 1 1
+1416 1 1
+33 1 1
+529 1 0
+25 1 0
+1863 4 0
+1651 1 1
+28 1 1
+11815 1 0
+26 1 0
+19 1 1
+3105 1 0
+700 1 0
+150 1 0
+68 1 0
+1421 6 0
+567 1 0
+14 1 0
+2415 1 0
+41 1 1
+415 1 1
+33 1 1
+4521 1 1
+33 1 1
+307 0 1
+176 0 1
+3790 1 1
+86 1 1
+67 1 1
+65 1 0
+7439 1 1
+18 1 1
+16805 1 0
+1764 0 1
+6984 1 0
+3401 20 0
+156 1 1
+30 1 1
+165 2 0
+1087 0 1
+953 0 1
+483 1 0
+632 0 1
+652 0 1
+8559 0 2
+1871 0 1
+398 0 1
+2219 1 1
+53 1 1
+756 1 1
+66 1 1
+69 1 1
+48 1 1
+63 1 1
+28 0 3
+1057 0 3
+63 3 0
+55 1 1
+74 2 3
+159 3 0
+92 1 1
+29 1 1
+58 0 3
+1210 9 9
+54 1 1
+27 1 1
+1374 2 0
+1775 2 17
+764 14 14
+331 16 16
+2291 4 3
+1687 1 1
+26 1 1
+2469 0 1
+3243 1 0
+3636 1 1
+24 1 1
+615 0 1
+2566 1 0
+275 0 5
+690 0 7
+13139 1 0
+1452 0 4
+214 13 13
+61 124 0
+1381 9 9
+5812 1 1
+24 1 1
+5703 1 0
+3992 14 15
+1462 0 3
+5199 0 2
+1554 2 0
+715 12 10
+1966 2 0
+2808 16 0
+611 1 0
+406 0 18
+737 1 1
+31 1 1
+4372 0 5
+10789 0 1
+2399 0 1
+6750 2 0
+96 48 48
+1219 0 6
+6736 0 2
+4457 4 0
+7867 0 1
+3495 1 2
+6215 12 12
+1357 1 0
+2652 0 1
+1771 1 0
+14207 41609 41616
+18338 46 46
+851 1 0
+9638 1 0
+2994 1 0
+469 1 3
+499 1 0
+12074 13 13
+2807 11 10
+715 2 0
+1627 6 6
+5099 0 1
+488 5 1
+975 2 0
+1730 32 31
+1791 0 5
+8135 38 38
+84 3 3
+18 1 1
+3737 9 9
+1442 13 13
+212 10 0
+7712 1 1
+44 1 1
+6271 0 1
+1316 1 1
+49 1 1
+9052 28 32
+113 2 0
+2813 13 13
+1285 50000 2858
+75638 50000 40000
+1583473 2 0
+1564100 97462 0
+2933461
+
+chain 4369679 X 155270560 + 152229637 152277099 X 154913754 + 151980294 152116665 696
+7131 26 26
+1319 1 0
+10288 0 88910
+2852 19 19
+3721 0 1
+13270 1 0
+8834
+
+chain 2629454 X 155270560 + 120011032 120067379 X 154913754 + 119895063 119899921 647
+714 51489 0
+4144
+
+chain 1494650 X 155270560 + 148762194 148872193 X 154913754 - 6301537 6445444 168
+2899 0 1
+1499 0 1
+3725 0 6
+20333 1 0
+13152 18338 18338
+46 40010 73911
+32 9926 9926
+38
+
+chain 260907 X 155270560 + 75365988 75368784 X 154913754 - 79628560 79631356 2215
+1269 41 41
+1486
+
+chain 138004 X 155270560 + 120011746 120013199 X 154913754 + 119920102 119921555 138939
+1453
+
+chain 29712 X 155270560 + 112877029 112877338 12 132349534 + 121720730 121721039 4776951
+309
+
+chain 29117 X 155270560 + 75253866 75254170 12 132349534 - 49782819 49783123 5064709
+304
+
+chain 10575 X 155270560 + 143182285 143275757 2 242951149 - 154930543 155024664 254
+41 49992 50582
+45 43365 43424
+29
+
+chain 3572 X 155270560 + 148224541 148224579 X 154913754 + 148032219 148032257 5503764
+38
+
+chain 3404 X 155270560 + 120013199 120013235 X 154913754 + 119931276 119931312 297576
+36
+
+chain 3363 X 155270560 + 49293018 49293056 X 154913754 + 49218184 49218222 1450
+38
+
+chain 2275 X 155270560 + 152236768 152236794 X 154913754 - 2913071 2913097 1916
+26
+
+chain 2111 X 155270560 + 143122309 143122332 17 78774742 - 16413594 16413617 6765736
+23
+
+chain 2063 X 155270560 + 148224511 148224541 X 154913754 + 148032257 148032287 9904071
+30
+
+chain 1275 X 155270560 + 148522048 148522077 11 134452384 + 59964168 59964197 432609
+29
+
+chain 391 X 155270560 + 112955240 112955279 3 199501827 - 80088461 80088500 4668596
+20 4 4
+15
+
+chain 2373403023 Y 59373566 + 10000 28819361 Y 57772954 + 0 27228749 24
+34821 50000 50000
+86563 50000 30000
+766173 50000 50000
+36556 50000 50000
+80121 50000 90000
+754004 50000 100000
+6846717 50000 50000
+276367 50000 600000
+813231 3000000 500000
+39401 50000 400000
+554624 50000 100000
+535761 0 1
+32919 11 12
+12810 0 5
+18900 1 1
+121 4 5
+230478 0 1
+750 1 1
+22 1 1
+14340 1 1
+43 1 1
+2095 0 1
+14635 0 9
+2781 0 1
+45022 5 6
+7151 0 1
+9344 628 0
+5417479 50006 0
+2175791 50000 0
+1481749 50000 50000
+4867933
+
+chain 46617811 Y 59373566 + 58819361 59363566 Y 57772954 + 57228749 57772954 80
+98295 50000 50000
+395910
+
+chain 9624 Y 59373566 + 14725909 14726162 X 154913754 + 99410441 99410697 23695076
+50 136 139
+67
+
diff --git a/public/chainFiles/b37tohg18.chain b/public/chainFiles/b37tohg18.chain
new file mode 100644
index 0000000..37c2264
--- /dev/null
+++ b/public/chainFiles/b37tohg18.chain
@@ -0,0 +1,49040 @@
+chain 21270171362 1 249250621 + 10000 249233096 chr1 247249719 + 0 247199719 2
+619 137 0
+166661 50000 50000
+40302 50000 50000
+153649 50000 50000
+1098479 1 1
+47 1 1
+73 117 114
+773 1 1
+43 1 1
+864369 2 2
+51 3 0
+104 13694 13694
+104 0 3
+51 2 2
+134936 50000 50000
+1161048 150000 60000
+1440092 27273 50000
+7590365 50000 50000
+116914 100000 50000
+237250 50000 50000
+3518496 50000 50000
+12702424 150000 50000
+16145012 0 1
+7772 1 0
+4705841 0 1
+52977198 50000 50000
+157344 21065 50000
+16604841 50000 50000
+189539 150000 50000
+398739 21050000 20290000
+195588 50000 50000
+186739 150000 50000
+175055 50000 50000
+201709 100000 50000
+126477 130183 50000
+381 0 3
+315 0 2
+62 1 1
+45 1 0
+19 0 1
+8 1 1
+1158 1 0
+314 12 13
+2849 3 0
+5615 1 1
+37 1 1
+3172 6 4
+190 1 1
+34 1 1
+380 0 1
+2099 3 0
+765 2 2
+366 0 4
+1186 1 0
+460 0 1
+1242 28 28
+574 1 1
+21 1 1
+1460 1 1
+105 1 1
+701 3 0
+239 0 1
+970 11 11
+2365 1 1
+21 1 1
+384 8 8
+996 2 0
+10383 2 0
+713 0 1
+5188 1 1
+30 1 1
+1233 1 0
+132 1 1
+44 1 1
+1123 22 22
+1810 1 0
+512 1 1
+39 1 1
+1096 0 16
+743 1 0
+9028 0 1
+2506 0 6
+8446 2 0
+5505 0 3
+7541 1 0
+109864 50000 50000
+78698 50000 50000
+127263 50000 50000
+170669 50000 50000
+38311 100000 100000
+1022394 50000 50000
+281532 289973 50000
+1648 1539 0
+76 3225 3
+1018 34 34
+1716 2 0
+159 4 0
+1600 0 6
+1385 1 0
+2066 1 1
+32 1 3
+1556908 150000 50000
+185320 150000 50000
+172789 50000 50000
+220313 50000 50000
+455185 50000 50000
+22047237 1 0
+34365824 150000 50000
+259514 150000 50000
+17265625 50000 50000
+11394365 50000 50000
+13665999 150000 50000
+174886
+
+chain 3264727 1 249250621 + 146303299 146341166 chr16 88827254 - 19388358 19424466 890
+577 1 1
+25 1 1
+63 19 19
+840 1 1
+60 1 1
+146 8 8
+874 1 1
+17 1 1
+386 1 1
+27 1 1
+931 1 1
+19 1 1
+200 1 1
+26 1 1
+72 1 0
+39 1 1
+107 2 1
+26 1 0
+25 1 1
+146 1 1
+45 1 1
+49 0 1
+434 0 4
+21 1 1
+572 0 2
+464 1 1
+50 1 1
+628 1 1
+48 1 1
+184 1 1
+25 1 1
+330 0 3
+308 14 14
+289 1 1
+57 1 1
+709 107 107
+247 1 1
+72 1 1
+470 1 1
+36 1 1
+353 1 0
+27 1 1
+92 12 12
+1001 1 1
+39 1 1
+650 1 1
+22 1 1
+171 1 1
+21 1 1
+88 0 9
+107 36 11
+23 0 1
+29 0 26
+20 3 79
+161 11 11
+134 1 1
+89 1 1
+547 1 1
+15 1 1
+409 1 1
+36 1 1
+376 11 10
+1545 1 0
+4 0 1
+36 1 1
+373 0 1
+326 1 1
+42 17 0
+97 1 0
+187 2 0
+503 1 1
+57 1 1
+443 1 1
+35 1 1
+633 1 0
+2044 3 13
+299 1 1
+37 1 1
+1159 1 1
+39 1 1
+124 1 1
+74 1 1
+103 1 1
+55 1 1
+280 10 9
+474 0 1
+382 1 1
+31 1 1
+1812 1 1
+76 1681 0
+25 1 1
+145 1 1
+18 1 1
+1228 1 1
+31 1 1
+126 9 9
+186 2 0
+142 1 1
+25 1 0
+442 10 0
+339 0 1
+89 1 1
+21 2 0
+21 151 4
+15 1 1
+489 9 9
+311 1 1
+75 1 1
+75 1 0
+124 1 1
+114 1 1
+23 1 1
+1489 0 3
+391 1 0
+2141 10 10
+460 11 11
+422 1 1
+30 1 1
+296 8 8
+638 1 1
+38 1 1
+341
+
+chain 2374970 1 249250621 + 146214652 146460889 chr1 247249719 - 102316553 102503720 74
+488 1 1
+24 1 1
+971 6293 0
+994 2 0
+183 2 0
+1408 1 0
+1360 1541 0
+211 0 12
+1506 111528 93105
+421 5 6
+2973 8 8
+118 12 12
+157 10 10
+706 0 18
+26 2884 0
+127 4 1
+1518 1 1
+33 1 1
+934 9 9
+908 0 1
+126 1 0
+695 20 20
+2250 5 5
+1662 179 172
+975 1 1
+53 1 1
+62 2 2
+40 1 1
+1561 1 1
+34 1 1
+668 1 0
+1671 2 0
+480 1 1
+17 4 4
+103 0 1
+50 6 6
+230 1 1
+71 1 1
+139 1 0
+975 5 0
+180 1 1
+37 1 1
+1888 3 2
+1101 1 0
+354 64 9327
+654 1 1
+36 1 1
+888 0 2
+18 1 1
+74 1 1
+25 1 1
+81 2 0
+779 1 1
+41 0 12
+22 1 1
+436 1 6
+293 1 1
+31 1 1
+83 4 0
+694 1 1
+42 1 1
+913 0 9
+472 0 1
+253 12 12
+148 89 1
+41 89 1
+342 1 1
+72 1 1
+97 1 1
+41 1 1
+108 13 16
+280 12 12
+61 1 1
+30 0 1
+71 1 1
+42 2 2
+139 0 3
+85 5 5
+90 1 1
+39 0 1
+366 13 14
+332 0 3744
+123 1 1
+19 1 1
+264 2 0
+47 1 1
+381 3 5
+109 0 1
+521 0 1
+503 1 1
+42 0 1
+739 1 1
+77 1 1
+883 0 2
+220 0 3
+93 4 0
+12 4 0
+39 5 0
+91 1 1
+34 1 1
+562 1 1
+30 1 1
+660 13 0
+1172 16 16
+69 1 1
+32 1 1
+310 1 1
+33 1 1
+97 0 1
+38 1 1
+295 0 2
+499 1 1
+57 31 14
+607 10 10
+145 1 1
+101 1 1
+346 1 1
+30 1 1
+74 1 1
+16 1 1
+203 1 1
+36 12 0
+483 16 0
+977 1 1
+86 1 1
+66 1 1
+35 1 1
+692 16 13
+402 34 34
+287 0 5
+523 0 18
+350 4 0
+32 0 2
+108 39 45
+66 30 0
+969 0 5
+1749 5 5
+95 2 0
+5 1 0
+4 0 1
+79 0 2
+65 8 11
+63 1 1
+49 1 1
+1381 0 1
+870 17 0
+139 1 1
+89 1 1
+270 3 3
+97 1 1
+66 1 1
+50 1 1
+126 1 0
+182 1 1
+83 0 4
+125 1 1
+35 1 1
+263 1 1
+32 4 4
+202 1 0
+94 1 1
+46 1 1
+206 1 1
+56 1 1
+50 1 1
+49 1 1
+188 16 16
+589 1 1
+38 1 1
+178 0 4
+67 1 1
+421 51 0
+117 1 1
+36 1 1
+71 1 1
+74 1 1
+68 10 10
+131 3 3
+56 1 0
+52 1 1
+207 4 4
+30 1 1
+283 14 14
+93 0 4
+66 1 1
+89 7 5
+36 1 1
+79 1 1
+46 21 0
+99 1 1
+229 10 10
+100 5 0
+19 8 8
+78 1 1
+87 1 1
+125 5 5
+65 1 1
+74 3 3
+344 1 1
+24 1 1
+683 1 1
+43 6287 0
+250 15 15
+798 13 12
+267 2 1
+881 1 0
+374 10 10
+1237 1 1
+40 1 1
+620 1 1
+43 1 1
+1491 1 1
+28 1 1
+68 5 5
+413 1 2
+183 5 5
+42 1 1
+363 1 1
+26 23 0
+53 1 0
+1011 15 15
+173 4 4
+15 1 1
+801 4 4
+1197 0 10
+432 22154 19
+283 4702 22
+850 9524 0
+78 76 76
+568 10 10
+775 40 32
+274 4 0
+1120 17 17
+195
+
+chain 990444 1 249250621 + 2485433 2499127 chr1 247249719 - 244760735 244774429 1366
+13694
+
+chain 614409 1 249250621 + 249233096 249240448 chr21 46944323 + 46937133 46944296 2013
+2867 16 16
+420 9 9
+176 0 1
+1252 6 0
+1275 1 1
+25 0 344
+76 0 58
+545 484 7
+40 109 0
+51
+
+chain 498595 1 249250621 + 146216137 146242853 chr1 247249719 - 104315183 104389677 383
+30 657 657
+196 19 18
+134 27 27
+445 20 20
+101 9 9
+169 62 62
+116 10 10
+70 62 62
+54 26 26
+70 0 22267
+240 1539 0
+91 20 24
+246 22 22
+270 112 112
+118 143 143
+86 24 24
+184 81 81
+67 47 46
+110 83 95
+335 59 59
+139 4179 2633
+241 27 27
+273 109 109
+185 76 76
+86 24 24
+184 81 81
+26 1717 1732
+80 85 53
+151 37 37
+99 37 37
+113 20 20
+101 9 9
+169 62 62
+89 37 37
+70 62 62
+54 33 33
+382 279 5055
+291 112 112
+125 147 147
+256 382 24225
+58 106 106
+51 29 29
+422 19 19
+221 84 84
+156 29 29
+162 33 33
+80 4 4
+79 11 11
+209 29 29
+183 34 34
+116 44 44
+122 5 5
+554 41 41
+140 8 8
+161 0 1
+67 58 51
+138 10 10
+246 60 60
+124 59 60
+101 138 138
+109 161 161
+56 31 28
+163 74 74
+136 7 7
+303 34 34
+119 10 10
+339 30 30
+141 91 91
+222 107 93
+237 205 205
+134 49 49
+87 22 22
+128 87 87
+105 33 33
+52 58 58
+52 87 87
+198 158 162
+125 44 44
+82 42 42
+54 10 9
+72 27 27
+154 18 18
+186 39 39
+61 87 86
+71 38 38
+116 43 43
+268 50 50
+58 120 120
+152
+
+chain 376931 1 249250621 + 143880003 143901185 chr1 247249719 - 126576077 126597249 122
+127 70 71
+181 31 31
+3325 1 1
+49 1 1
+820 1 1
+75 1 1
+393 1 1
+21 1 1
+2956 3 0
+232 0 5
+77 4 4
+531 1 1
+42 5 3
+183 1 1
+19 1 1
+644 1 1
+25 1 1
+701 1 1
+21 1 1
+954 1 1
+31 1 1
+129 24 14
+650 1 1
+25 1 1
+560 0 2
+1372 1 1
+46 1 1
+1547 3 1
+883 1 0
+22 1 1
+818 1 1
+30 1 1
+1231 1 1
+34 1 1
+1758 1 1
+35 1 1
+468
+
+chain 360128 1 249250621 + 146427813 146438983 chr1 247249719 + 144926007 144932406 9045
+138 252 252
+1258 1540 0
+76 3256 30
+81 283 283
+87 185 185
+109 273 273
+7 19 19
+155 43 43
+91 1 0
+1185 11 11
+212 2 0
+158 2 0
+1336 64 64
+346
+
+chain 260187 1 249250621 + 146226436 146443808 chr1 247249719 - 100391956 100589719 716
+173 5526 775
+60 400 391
+120 18 17
+164 81 83
+26 45 45
+35 1589 1589
+29 2518 2516
+7 17 17
+56 30 30
+51 56 53
+31 163 163
+74 446 446
+34 468 468
+30 141 141
+33 624 609
+8 133 133
+64 134 134
+49 237 237
+71 316 316
+58 1199 1203
+39 219 219
+38 6697 424
+97 18 18
+77 219 219
+114 64 64
+138 183 187
+118 99 99
+89 25 31
+69 24 24
+100 30 30
+69 49 49
+54 125 125
+182 197 197
+107 156930 137139
+140 175 171
+75 164 162
+157 49 49
+69 45 45
+61 48 48
+51 61 60
+71 70 70
+108 10955 10956
+84 24 24
+75 87 87
+185 109 109
+273 22 22
+246 20 24
+49 494 19550
+70 10 10
+116 62 9592
+169 9 9
+324 83 83
+151 87 77
+90 22 22
+196 68 68
+95 5 5
+57 71 71
+196 17 17
+75 73 73
+563 83 87
+110 1555 14
+45 7990 0
+54 81 81
+184 24 24
+75 87 87
+185 109 109
+273 3222 27
+64 1605 35
+142 1567 44
+37 1539 0
+281
+
+chain 257136 1 249250621 + 146423276 146434218 chr1 247249719 + 144926235 144932406 9046
+68 157 157
+71 288 288
+73 563 563
+83 4962 196
+1052 19 19
+155 43 43
+91 1 0
+99 76 76
+1010 11 11
+212 2 0
+158 2 0
+1746
+
+chain 252664 1 249250621 + 146424776 146427813 chr1 247249719 + 144927734 144930766 96654
+1055 16 16
+124 74 74
+74 224 223
+979 11 11
+212 2 0
+158 2 0
+106
+
+chain 244411 1 249250621 + 146449863 146457732 chr1 247249719 + 144926007 144929115 8960
+1648 1539 0
+76 3225 3
+265 45 45
+708 34 34
+329
+
+chain 149837 1 249250621 + 146221841 146454623 chr1 247249719 + 146043049 146859300 923
+56 335 335
+59 4859 3299
+109 185 185
+76 5018 258
+57 409 426
+45 777 777
+84 1850 1850
+41 841 820
+47 125 126
+58 101 101
+138 2026 2026
+51 4 2
+52 297 297
+81 786 786
+33 347 347
+90 23 23
+35 125 125
+44 82 81
+42 634 634
+74 225 224
+43 268 267
+50 58 58
+120 152 152
+515 62 62
+68 41 41
+432 0 18
+180 46 46
+67 26 28
+192 26 26
+231 107 107
+67 72 67
+53 67 67
+151 171 168
+59 46 47
+86 57 54
+51 138 138
+397 18 18
+114 3 2
+182 20 20
+86 167 167
+51 48 48
+233 42 42
+89 55 55
+163 43 44
+112 70 70
+355 154 154
+174 157 641342
+145 228 228
+152 366 366
+64 1134 1135
+35 269 265
+46 15 14
+137 8 8
+70 11 11
+73 29 29
+55 63 63
+62 262 247
+77 100 100
+155 39 39
+215 72 72
+178 20 20
+64 13 13
+123 12 12
+124 127 127
+100 135495 128258
+34 14433 8189
+138 64 64
+114 219 219
+77 19 19
+96 17464 11155
+185 22232 98
+69 26 26
+54 62 62
+70 10 10
+116 62 62
+169 32 32
+211 37 37
+99 9482 37
+161 23 13
+130
+
+chain 124274 chr1 249250621 + 143871002 143921945 chr1_random 1663265 - 747928 798871 209
+9001 127 127
+70 181 181
+31 41505 41505
+28
+
+chain 121346 1 249250621 + 146403114 146428203 chr1 247249719 - 230466401 230485108 1747
+70 156 156
+17 25 25
+22 146 146
+152 249 249
+94 2285 2290
+63 34 34
+79 80 80
+89 48 42
+85 127 127
+68 502 495
+87 61 61
+136 127 126
+4 272 272
+43 396 396
+49 175 175
+48 183 187
+40 11298 11284
+59 5488 723
+50 98 104
+107 63 63
+54 1608 4
+83 9 9
+160
+
+chain 97594 1 249250621 + 146218654 146221704 chr1 247249719 - 102320562 102322071 123803
+154 24 24
+174 6 6
+1045 1614 73
+33
+
+chain 76810 1 249250621 + 146441138 146441951 chr1 247249719 - 102499725 102500538 1571454
+813
+
+chain 54094 1 249250621 + 146439071 146449863 chr1 247249719 + 144927734 144930766 9063
+156 32 32
+864 3151 76
+253 432 432
+62 196 196
+62 169 169
+32 211 211
+37 99 99
+87 4753 70
+88 2 0
+106
+
+chain 51170 1 249250621 + 146420674 146422968 chr1 247249719 + 144928397 144930686 91522
+82 822 821
+37 60 60
+212 196 196
+62 502 502
+83 151 149
+59 2 0
+26
+
+chain 47243 1 249250621 + 146249630 146253102 chr1 247249719 + 146058248 146061700 347899
+23 176 176
+41 89 89
+25 420 420
+79 245 245
+20 78 78
+29 495 490
+29 72 72
+46 158 145
+143 628 627
+53 534 533
+17 5 5
+67
+
+chain 34253 1 249250621 + 146404045 146461111 chr1 247249719 - 100757623 100773572 2307
+96 91 95
+87 237 237
+54 39 39
+166 170 170
+93 270 264
+54 177 172
+56 15121 8830
+27 23096 966
+26 9686 241
+71 62 62
+168 10 10
+112 7057 3813
+40
+
+chain 33489 1 249250621 + 146442066 146462163 chr1 247249719 + 144023055 144028915 8758
+86 162 162
+20 322 322
+153 82 82
+116 7 7
+260 4934 262
+352 142 142
+79 60 60
+57 99 99
+135 6 6
+234 31 31
+264 6949 535
+45 4229 1077
+134 1105 1106
+34
+
+chain 33218 1 249250621 + 146446746 146453724 chr1 247249719 + 144927655 144929867 162700
+76 4 3
+532 5285 520
+407 76 76
+465 71 71
+62
+
+chain 32794 1 249250621 + 146404432 146406255 chr1 247249719 - 230461418 230463242 176920
+104 280 280
+90 172 172
+62 25 26
+120 135 135
+128 18 18
+13 515 515
+161
+
+chain 26745 1 249250621 + 146451818 146452101 chr1 247249719 - 102499420 102499703 6165314
+283
+
+chain 24305 chr1 249250621 + 146405140 146406723 chr1_random 1663265 + 611385 612968 836039
+25 120 120
+23 14 14
+26 287 287
+50 8 8
+128 685 685
+19 35 35
+26 105 105
+32
+
+chain 22423 1 249250621 + 146216204 146248536 chr1 247249719 + 146043705 146710884 2213
+65 5 5
+58 95 95
+44 58 58
+67 1348 1339
+20 10 10
+32 196 196
+62 2594 1055
+96 153 153
+108 10232 605314
+55 16610 57923
+59 315 315
+50
+
+chain 21816 1 249250621 + 146442152 146442891 chr1 247249719 + 144927740 144928479 1347746
+148 509 509
+82
+
+chain 20351 1 249250621 + 146356780 146459279 chr1 247249719 - 101132456 101205064 466
+178 42398 55179
+51 39820 14441
+32 3075 0
+39 16869 2651
+37
+
+chain 17175 1 249250621 + 249240118 249240599 chr1 247249719 - 247249264 247249719 6645750
+53 7 10
+47 109 0
+21 6 0
+36 51 102
+5 22 73
+56 16 0
+52
+
+chain 16391 1 249250621 + 146446357 146448997 chr1 247249719 + 144928805 144929904 1203759
+155 2048 507
+109 112 112
+60 57 57
+99
+
+chain 14917 1 249250621 + 146407068 146408474 chr1 247249719 + 144010187 144011603 12383
+76 149 159
+73 240 240
+47 136 136
+39 587 587
+59
+
+chain 14732 1 249250621 + 104074421 104074580 chr20 62435964 - 41767962 41768121 15357748
+159
+
+chain 13179 1 249250621 + 146404319 146408384 chr1 247249719 + 146846894 147006750 8455
+113 104 104
+20 54 54
+39 1744 1736
+34 1903 157702
+54
+
+chain 12360 1 249250621 + 146216167 146250305 chr1 247249719 - 103194351 103244298 1211
+37 128 128
+95 44 44
+58 67 67
+60 5 5
+51 3345 6525
+128 0 9435
+8 6200 4617
+43 3518 3485
+37 13507 18215
+40 613 636
+46 716 718
+72 53 53
+30 240 240
+72 1522 1531
+48 233 233
+42 89 89
+36 14 14
+5 804 801
+66 696 696
+34 1307 1378
+29
+
+chain 11952 1 249250621 + 146445104 146445575 chr1 247249719 - 100776503 100776974 637661
+94 18 18
+359
+
+chain 11854 1 249250621 + 146229744 146232010 chr1 247249719 + 144747607 144749863 153009
+21 19 9
+19 736 736
+20 10 10
+32 196 196
+62 54 54
+33 556 556
+43 383 383
+82
+
+chain 10753 1 249250621 + 146408065 146408192 chr1 247249719 - 101190210 101190337 3832842
+127
+
+chain 10394 1 249250621 + 104091245 104091359 chr5 180857866 + 153305659 153305773 21933263
+114
+
+chain 10333 1 249250621 + 104091131 104091240 chrX 154913754 + 74963065 74963174 22062861
+109
+
+chain 9815 1 249250621 + 146403058 146404974 chr1 247249719 - 101191494 101193412 750328
+43 256 256
+25 136 136
+32 152 152
+35 1179 1181
+58
+
+chain 9804 1 249250621 + 146245618 146249581 chr1 247249719 + 16785678 16789645 248382
+32 19 19
+6 51 51
+11 80 80
+47 3688 3692
+29
+
+chain 8504 1 249250621 + 146408954 146409155 chr1 247249719 - 101191099 101191300 2114480
+61 111 111
+29
+
+chain 8318 1 249250621 + 146407418 146407505 chr1 247249719 - 102486621 102486708 14753827
+87
+
+chain 7171 1 249250621 + 1619987 1620086 chr1 247249719 + 1662789 1662888 1670813
+99
+
+chain 7168 1 249250621 + 146247532 146247756 chr1 247249719 + 144759088 144759312 2272140
+43 123 123
+58
+
+chain 6908 1 249250621 + 146440123 146445030 chr1 247249719 - 101203201 101205034 129817
+119 142 142
+69 4461 1387
+116
+
+chain 6650 1 249250621 + 146406255 146406330 chr1 247249719 - 101188413 101188487 10133477
+21 3 2
+51
+
+chain 6566 1 249250621 + 146445881 146445977 chr1 247249719 + 144059904 144060000 2107997
+23 21 21
+52
+
+chain 6380 1 249250621 + 10629 10716 chrY 57772954 - 1612 1699 6955
+87
+
+chain 5940 1 249250621 + 146231384 146231447 chr1 247249719 - 102320696 102320759 393064
+63
+
+chain 5684 1 249250621 + 146407187 146407246 chr1 247249719 - 101189341 101189400 31412390
+59
+
+chain 5452 chr1 249250621 + 146243368 146248596 chr1_random 1663265 - 1047698 1052949 2624
+34 4838 4857
+26 270 274
+60
+
+chain 5266 1 249250621 + 249240022 249240077 chr1 247249719 - 247249582 247249637 32667083
+55
+
+chain 5203 1 249250621 + 146446237 146446668 chr1 247249719 - 102500144 102500575 1674615
+120 155 155
+156
+
+chain 4958 1 249250621 + 146451766 146451818 chr1 247249719 + 142879884 142879936 20619966
+52
+
+chain 4944 1 249250621 + 104074593 104074659 chr8 146274826 - 121738108 121738174 21132898
+66
+
+chain 4456 1 249250621 + 146406808 146406855 chr1 247249719 - 101188965 101189012 6127414
+47
+
+chain 4404 1 249250621 + 146406008 146406074 chr1 247249719 - 100540708 100540774 1844606
+66
+
+chain 4255 1 249250621 + 146230090 146231384 chr1 247249719 - 103181490 103211127 6721
+37 1201 29544
+56
+
+chain 4244 1 249250621 + 146216712 146216757 chr1 247249719 - 102323372 102323417 831523
+45
+
+chain 4123 1 249250621 + 146421615 146421675 chr1 247249719 + 143536766 143536826 34723
+60
+
+chain 3877 1 249250621 + 146435532 146435575 chr1 247249719 - 101203375 101203418 141544
+43
+
+chain 3825 1 249250621 + 146430767 146430810 chr1 247249719 - 101203375 101203418 118474
+43
+
+chain 3528 1 249250621 + 146454014 146454173 chr1 247249719 - 100628659 100628818 205230
+159
+
+chain 3185 1 249250621 + 146406525 146406559 chr1 247249719 - 101188682 101188716 16359386
+34
+
+chain 3178 1 249250621 + 104074770 104074842 chr7 158821424 + 21042162 21042234 21615733
+72
+
+chain 3121 1 249250621 + 146445079 146445768 chr1 247249719 + 144930661 144931350 792159
+25 471 471
+193
+
+chain 3050 1 249250621 + 146407036 146407068 chr1 247249719 - 101189190 101189222 23011976
+32
+
+chain 2960 1 249250621 + 146249122 146249154 chr1 247249719 + 144760680 144760712 1406096
+32
+
+chain 2741 1 249250621 + 146231545 146231601 chr1 247249719 - 104345036 104345092 8679
+56
+
+chain 2464 1 249250621 + 146424736 146424776 chr1 247249719 + 144037261 144037301 21508852
+40
+
+chain 2405 1 249250621 + 249239910 249239972 chr1 247249719 - 247249327 247249389 7681464
+62
+
+chain 2390 1 249250621 + 249240288 249240334 chr1 247249719 - 247249596 247249642 26481552
+46
+
+chain 2344 1 249250621 + 146216757 146250883 chr1 247249719 - 103711249 103726499 1396
+67 32948 14063
+57 892 901
+7 127 127
+28
+
+chain 2164 1 249250621 + 146237300 146252192 chr1 247249719 + 16771061 16779662 20592
+30 14825 8534
+37
+
+chain 1926 1 249250621 + 10623 10756 chr15 100338915 - 932 978 361
+6 87 0
+40
+
+chain 1909 1 249250621 + 146251590 146251644 chr1 247249719 - 103917507 103917561 1304306
+54
+
+chain 1317 1 249250621 + 146445768 146445881 chr1 247249719 + 142919887 142920000 1148922
+113
+
+chain 1215 1 249250621 + 146245082 146245105 chr1 247249719 + 144762924 144762947 79987
+23
+
+chain 1154 1 249250621 + 146232196 146232260 chr1 247249719 + 16765963 16766027 137025
+64
+
+chain 1035 1 249250621 + 146367698 146367747 chr1 247249719 - 99837677 99837726 4094688
+49
+
+chain 827 1 249250621 + 146445037 146445075 chr1 247249719 - 102502075 102502113 153232
+38
+
+chain 691 1 249250621 + 146454173 146454226 chr1 247249719 - 100557283 100557336 435331
+53
+
+chain 604 1 249250621 + 146429501 146429541 chr1 247249719 + 147018285 147018325 1335641
+40
+
+chain 424 1 249250621 + 146449372 146449403 chr1 247249719 - 100776122 100776153 793932
+31
+
+chain 395 1 249250621 + 146448669 146448702 chr1 247249719 + 144078479 144078512 164120
+33
+
+chain 88 1 249250621 + 146452351 146452395 chr1 247249719 - 99890656 99890700 12702616
+44
+
+chain 71 1 249250621 + 146451564 146451618 chr1 247249719 - 102499166 102499220 29039078
+54
+
+chain 12431961244 10 135534747 + 60000 135524747 chr10 135374737 + 50000 135374737 10
+5577104 0 50006
+12337571 50000 50000
+20794160 50000 50000
+286100 3200000 2480000
+191752 50000 50000
+3830277 50000 150000
+952205 100000 150000
+263307 100000 150000
+163231 50000 150000
+989829 100000 150000
+1941874 50000 50000
+211435 50000 50000
+30112515 0 319974
+13249156 0 10
+31058956 50000 50000
+2696597 150000 50000
+4615335 50000 10000
+246123 50000 50000
+1327328 1 1
+47 1 1
+1312 0 1
+56 1 1
+190 1 1
+31 1 1
+20182 1 0
+448068
+
+chain 12415603391 11 135006516 + 60000 134946516 chr11 134452384 + 50000 134451988 11
+1102759 50000 16576
+49571094 307000 207000
+503352 3100000 3000000
+14395596 47395 0
+491076 304 60
+30213 182 114
+26 142 1
+27914 0 1
+20009 0 1
+19 0 1
+39 0 1
+17 1 3
+10 0 1
+1008 0 1
+95 0 1
+5126 0 15
+303 0 1
+975 4 0
+1548 1 0
+191 0 20
+40 0 1
+74 1 0
+101 0 1
+25 1 0
+6178 1 0
+1875 52561 21437
+468 1 1
+81 1 1
+2620 0 1
+1640 0 4
+3305 1 0
+3342 0 1
+17899663 50000 12000
+8549206 150000 15562
+38507167 37 39
+1282 0 174
+387 0 86
+59
+
+chain 112280 chr11 135006516 + 69774695 69777256 chr11_random 215294 - 174770 177331 705
+2561
+
+chain 3731264 chr11_gl000202_random 40103 + 0 40103 chr11_random 215294 - 0 39615 791
+14658 1036 100
+6712 6 6
+32 35 523
+27 51 11
+17546
+
+chain 12330185447 12 133851895 + 145739 133779461 chr12 132349534 + 16000 132289534 12
+7035084 4 0
+543 1 0
+3777 1 0
+3889 52114 73000
+6014 0 1
+6524 5 126
+29 0 13
+20974 2 0
+3965 0 3
+444 11 0
+464 0 1
+27577110 3000000 1395000
+38631945 1 0
+14544 4 0
+1700 0 1
+789 12128 250000
+1783 0 1
+1075 2 0
+1042 0 1
+1526 1 1
+27 1 1
+2320 1 0
+166 0 1
+564 1 0
+2856 2 0
+900 1 0
+1387 1 1
+33 1 1
+2139 1 1
+48 1 1
+1305 2 0
+1533 2 1
+879 1 0
+744 26 26
+858 4 0
+1089 0 6
+1113 0 12
+818 1 1
+18 0 1
+217 1 1
+36 1 1
+2002 0 1
+1025 1 0
+450 48 48
+916 0 1
+18 1 1
+4694 8 0
+142 0 4
+3656 0 2
+3403 1 1
+47 1 1
+1524 1 1
+28 1 1
+5560 48 45
+676 8 8
+810 16 16
+536 0 2
+236 0 4
+167 4 0
+1419 53 49
+4688 1 1
+38 1 1
+18576 0 5
+5285 2 0
+6486 1 1
+25 1 1
+4341 14 0
+2662 0 5
+1170 0 1
+4268 4 0
+1036 1 0
+2117 8 0
+5917 0 1
+3239 4 0
+2619 1 1
+21 1 1
+937 1 1
+38 1 1
+2412 124 139
+2648 2 0
+9314 0 2
+1986 2 2
+16 1 1
+229 1 1
+93 1 1
+895 0 12
+415 5 1
+119 1 1
+185 9 8
+458 2 0
+89 1 1
+42 1 1
+2034 1 0
+1545 2 0
+280 4 0
+97 14 14
+231 2 0
+2814 0 5
+1679 1 1
+27 1 1
+25758689 1 0
+6536665 1 0
+377270 96749 57000
+668 1 1
+20 0 1
+3348 1 1
+33 1 1
+648 1 1
+29 1 1
+3731 0 4
+1834 9 14
+1688 10 0
+3103 5 5
+1140 0 1
+1167 0 1
+985 9 9
+2897 0 1
+1625 0 9
+1101 1 0
+1358 8 0
+13065721 68352 150000
+810 0 2
+343 1 0
+1771 1 0
+2702 6 7
+1900 0 1
+705 0 6
+303 0 1
+727 1 1
+43 3 6
+490 1 1
+59 1 1
+226 1 1
+52 0 3
+465 8 0
+194 1 1
+25 0 1
+139 17 17
+1833 0 1
+81 1 1
+39 1 1
+453 0 1
+719 1 1
+47 1 1
+558 0 1
+838 1 8
+288 9 10
+741 2 5
+465 1 1
+48 1 1
+268 1 1
+26 0 1
+1337 17 0
+12 2 1
+16 1 1
+84 85 2
+917 0 1
+110 1 1
+29 1 1
+1580 1 1
+40 1 1
+683 1 1
+24 1 1
+247 1 1
+36 1 1
+1411 14 14
+149 1 0
+10091386 3 0
+296 5 0
+220 100872 45000
+972469
+
+chain 2067120 12 133851895 + 60245 88108 chr2 242951149 + 114046160 114069967 1234
+334 1 1
+47 1 1
+111 1 1
+20 0 13
+84 1 1
+84 7 15
+55 1 1
+28 1 1
+77 1 1
+49 1 1
+99 10 10
+345 1 1
+48 0 4
+16 2 2
+168 1 1
+160 1 1
+68 1 0
+62 1 1
+23 1 1
+144 7 7
+94 2128 0
+762 12 12
+305 1 1
+40 1 1
+385 196 196
+207 0 1
+267 1 1
+53 1 1
+58 0 12
+43 1 1
+55 4 4
+38 1 0
+361 1 0
+53 1 1
+27 1 1
+448 1 1
+18 1 1
+309 4 0
+104 1 1
+35 1 1
+394 1 1
+16 1 1
+159 1 1
+38 1 1
+413 14 14
+82 5 7
+699 0 1
+52 23 24
+1077 9 9
+492 1 0
+144 18 19
+69 1 1
+26 1 1
+689 2 0
+34 5 6
+34 1 1
+187 1 1
+65 1 1
+181 9 9
+82 1 1
+55 0 2
+310 1 1
+25 1 1
+71 1 1
+74 3 3
+64 6 6
+216 5 5
+62 1 1
+35 8 3
+803 1 0
+23 1 1
+124 1 1
+90 1 1
+300 4 0
+48 0 4
+28 1 0
+85 7 4
+63 2 0
+7 3 0
+49 1 1
+255 31 31
+462 1 1
+38 1 1
+414 1 1
+37 1 1
+304 1 1
+36 1 1
+119 16 19
+62 1 1
+26 1 1
+306 1 1
+93 1 1
+114 1 1
+141 1 1
+464 1 1
+25 1 1
+145 1 1
+21 1 1
+196 1 1
+46 1 1
+295 11 11
+255 1 1
+21 1 1
+280 1 1
+90 1 1
+413 8 8
+1039 24 24
+761 1 0
+53 1 1
+94 1 0
+25 1 1
+63 1 1
+71 2070 1
+21 2 47
+228 3 0
+17 1 1
+133 11 0
+137 1 1
+43 1 1
+90 3 3
+23 2 0
+144 1 1
+99 1 1
+349 3 3
+29 5 5
+60 0 70
+93 1 1
+21 1 1
+138 0 2
+83 1 1
+68 1 1
+166 1 1
+49 1 1
+461 1 1
+18 0 17
+26 1 1
+50 1 1
+14 0 1
+34 1 1
+370 1 1
+32 1 1
+68 14 14
+98
+
+chain 484774 12 133851895 + 88108 95739 chrX 154913754 + 154905409 154913416 8417
+2 1 1
+34 1 1
+80 1 1
+32 1 1
+415 1 1
+48 1 1
+73 1 1
+44 1 1
+149 13 13
+211 1 1
+26 1 1
+271 0 3
+528 1 1
+96 1 1
+507 1 1
+100 1 1
+121 37 37
+520 1 1
+34 1 1
+166 1 1
+45 1 1
+96 1 1
+87 1 1
+82 4 4
+71 1 1
+34 1 1
+132 1 1
+23 1 1
+97 1 1
+30 2 2
+109 3 3
+36 1 1
+134 2135 2017
+245 454 1029
+82 84 0
+113
+
+chain 233388 12 133851895 + 133837240 133840071 chr7 158821424 + 158817351 158819960 454901
+564 1 1
+52 1 0
+36 1 1
+470 1 1
+28 1 1
+359 1 1
+38 1 1
+130 5 0
+3 216 0
+97 3 2
+46 1 1
+559 1 1
+43 0 1
+78 1 1
+94
+
+chain 194103 12 133851895 + 62428 64518 chr14 106368585 + 64430621 64433205 634790
+748 40 40
+140 0 1
+167 0 373
+27 0 120
+968
+
+chain 49263 12 133851895 + 133825767 133827148 chr11 134452384 + 74280352 74281733 2582033
+188 22 24
+55 110 110
+117 297 297
+62 252 253
+116 101 98
+61
+
+chain 35717 12 133851895 + 133841521 133841895 chr5 180857866 - 180793287 180793661 3746803
+374
+
+chain 32957 12 133851895 + 133823831 133824928 chrX 154913754 - 110744397 110745491 4131553
+102 47 47
+104 308 309
+61 155 155
+59 173 169
+88
+
+chain 18331 12 133851895 + 133822513 133823307 chr7 158821424 + 35158939 35159735 11829157
+110 151 152
+60 413 414
+60
+
+chain 16856 12 133851895 + 66036 76221 chr19 63811651 - 63781390 63791585 1292
+70 1 1
+57 16 16
+51 9959 9969
+31
+
+chain 16157 12 133851895 + 109428208 109428485 chr2 242951149 - 225002676 225002954 13880737
+71 91 92
+115
+
+chain 11750 12 133851895 + 60000 60122 chr12 132349534 - 132324140 132324262 19413804
+122
+
+chain 9037 12 133851895 + 133826997 133827421 chr2 242951149 + 160701141 160701565 3717783
+90 61 61
+34 175 175
+64
+
+chain 8057 12 133851895 + 133826086 133826759 chr3 199501827 - 98694913 98695583 3241421
+56 127 126
+50 305 303
+135
+
+chain 4873 12 133851895 + 133822983 133823177 chr6 170899992 + 146924403 146924597 15743780
+57 73 73
+64
+
+chain 4427 12 133851895 + 133827536 133827658 chr3 199501827 - 37386916 37387038 7696734
+122
+
+chain 4266 12 133851895 + 109428325 109428370 chr8 146274826 + 102422247 102422292 23131068
+45
+
+chain 4036 12 133851895 + 133826320 133826456 chrX 154913754 + 144352164 144352300 4124454
+136
+
+chain 3880 12 133851895 + 95312 95362 chr1 247249719 - 247249339 247249389 25961870
+50
+
+chain 3693 12 133851895 + 63176 63216 chr6 170899992 - 141104715 141104755 640206
+40
+
+chain 3673 12 133851895 + 133827423 133827506 chr2 242951149 - 104106513 104106596 10382380
+83
+
+chain 3091 12 133851895 + 133826496 133826821 chr11 134452384 - 91473718 91474043 4183905
+58 205 205
+62
+
+chain 3057 12 133851895 + 133822699 133822767 chr2 242951149 + 211079534 211079602 19980130
+68
+
+chain 2758 12 133851895 + 133827507 133827536 chr3 199501827 - 112531647 112531676 15775673
+29
+
+chain 2377 12 133851895 + 133825725 133826065 chr1 247249719 + 157351310 157351652 3309912
+42 265 267
+33
+
+chain 2375 12 133851895 + 95368 95419 chr1 247249719 - 247249256 247249307 12772530
+51
+
+chain 2223 12 133851895 + 133827262 133827357 chr6 170899992 + 81976496 81976591 4176034
+95
+
+chain 2091 12 133851895 + 109428279 109428301 chr20 62435964 + 39979396 39979418 21613404
+22
+
+chain 1955 12 133851895 + 133822880 133822953 chr4 191273063 - 60412182 60412255 19166211
+73
+
+chain 1569 12 133851895 + 133823330 133823447 chr5 180857866 + 90128366 90128483 9408356
+117
+
+chain 1532 12 133851895 + 133822199 133822253 chr12 132349534 + 77527067 77527121 12101346
+54
+
+chain 1265 12 133851895 + 133825609 133825680 chr2 242951149 + 183532658 183532729 7750866
+71
+
+chain 1251 12 133851895 + 95185 95235 chr18 76117153 - 76117025 76117075 24929113
+50
+
+chain 1165 12 133851895 + 133826456 133826496 chrX 154913754 - 53085075 53085115 5993397
+40
+
+chain 1153 12 133851895 + 133824667 133824711 chr10 135374737 - 97414674 97414718 8388000
+44
+
+chain 852 12 133851895 + 133822443 133822508 chr5 180857866 + 49699275 49699340 23831787
+65
+
+chain 636 12 133851895 + 133823040 133823067 chr6 170899992 + 127619395 127619422 20859432
+27
+
+chain 615 12 133851895 + 133823498 133823556 chr14 106368585 - 76653675 76653733 3589163
+58
+
+chain 440 12 133851895 + 133827198 133827224 chr1 247249719 - 50786620 50786646 7302157
+26
+
+chain 9007882413 13 115169878 + 19020000 115109878 chr13 114142980 + 17918000 114127980 14
+26987167 0 1
+40753157 150000 50000
+25443670 150000 400000
+1821999 413955 384056
+369930
+
+chain 17589438 13 115169878 + 114456082 114639948 chr13 114142980 - 484930 668986 160
+430 0 2
+2905 4 8
+143 0 30
+612 0 4
+18 0 2
+175 1 1
+49 0 2
+2159 1 1
+27 1 1
+979 0 144
+1492 0 2
+174870
+
+chain 8359015315 14 107349540 + 19000000 107289540 chr14 106368585 + 18070000 106360585 15
+1081285 1 1
+43 1 1
+76 0 2
+437 1 1
+19 1 1
+440 1 0
+11 1 1
+59 15 15
+63 12 12
+70 1 0
+734 1 1
+165 4 1
+96 1 1
+46 0 1
+83 1 1
+149 4 4
+164 20 20
+63 16 15
+359 1 1
+39 1 1
+103 1 1
+76 1 1
+139 1 1
+38 1 1
+344 1 1
+65 1 0
+166 5 5
+88 1 1
+57 287 0
+59 1 1
+317 1 0
+52 1 1
+92 0 4
+651 4 4
+82 1 1
+93 1 1
+64 1 1
+24 1 1
+856 1 1
+35 1 1
+258 1 1
+17 1 1
+478 0 1
+1335 33 33
+1029 1 1
+37 1 1
+1115 4 3
+72 1 1
+643 10 10
+132 6 6
+89 2 0
+209 4 15
+77 5 5
+427 1 1
+41 1 1
+949 1 1
+16 1 1
+732 1 1
+44 0 2
+128 1 0
+91 1 1
+180 6 6
+388 6 6
+50 12 13
+275 1 1
+33 1 1
+142 1 1
+61 1 1
+560 1 1
+20 1 1
+1327 13 6
+1013 83 83
+202 4 0
+43 1 1
+352 10 10
+261 1 1
+39 1 1
+939 0 12
+1678 0 36
+159 1 1
+32 1 8
+818 6 0
+580 0 1
+931 0 1
+276 0 2
+3513 46 60
+882 0 2
+94 1 1
+49 1 1
+864 0 4
+40 1 1
+807 15 16
+416 3 0
+3345 15 15
+92 29 30
+80 1 1
+48 1 1
+2459 1 0
+646 66 66
+359 1 1
+29 0 54
+1875 0 3
+141696 1 1
+32 1 1
+8201115 0 1
+107 0 1
+2137 1 1
+39 1 1
+8848 1 0
+4806 0 1
+2075 0 1
+16612 0 1
+2385 0 3
+11506 0 8
+1353 1 0
+4596 1 0
+2073 1 2
+28 1 1
+2311 1 1
+44 1 1
+10440 4 0
+894 1 0
+1638 96 0
+41 0 9
+20 1 1
+2705 0 6
+352 1 1
+25 1 1
+742 1 0
+1048 18 2
+12085977 1 0
+14871228 0 3
+29067652 1 1
+47 1 1
+20173856 0 1292
+2548494
+
+chain 25802 14 107349540 + 20085579 20085848 chr8 146274826 + 118781991 118782260 6606813
+269
+
+chain 9908 14 107349540 + 20110215 20120217 chr22 49691432 + 14757849 14767860 97
+45 9891 9900
+66
+
+chain 8901 14 107349540 + 20090287 20100367 chr14 106368585 - 87815145 87825210 65
+33 9964 9949
+83
+
+chain 7700563179 15 102531392 + 20000000 102521392 chr15 100338915 + 18260008 100338915 16
+8448 2 6
+4086 0 1
+9569 1 1
+40 5 0
+56 1 7
+872354 40513 40506
+553 4 4
+876 40 39
+139 25 25
+1881 18 19
+499 8 8
+310 79 85
+78 26 23
+181 6 5
+569 11 11
+539 28 24
+261 22 20
+776 15 13
+62 13 13
+860 0 1
+716 0 26
+1349 167 166
+1070 23 23
+398 1 0
+177 21 5
+534 0 4
+770 24 18
+606 33 33
+1861 55 55
+2169 0 3
+558 19 20
+227 14 16
+329 5 5
+430 18 20
+620 1 0
+1112 0 2
+641 4 0
+476 47 47
+1285 1 0
+1139 49 49
+183 0 4
+1425 0 20
+186 1 0
+219 1 0
+607 44 44
+371 8 2
+507 0 2
+66 42 43
+999 4 4
+318 15 15
+1092 74 74
+808 61 61
+52 42 42
+109 51 51
+1535 0 14
+14011 0 4
+7955 1 4
+1350 0 1
+318 27 27
+600 4 0
+442 1 0
+1396 38 38
+1107 3 0
+1441 5 0
+360 49 49
+256 10 20
+497 39 39
+2129 0 4
+1242 0 2
+478 0 4
+708 92 92
+154 10 10
+1583 33 33
+1303 37 0
+100 14 14
+1138 92 109
+114 31 31
+2917 34 34
+1762 48 48
+449 0 1
+2458 1 9
+869 0 1
+534 49 49
+309 0 1
+2627 1 1
+3729 0 22
+565 1 0
+1845 0 1
+660 27 27
+68 0 1
+217 46 22
+1519 34 34
+559 32 32
+3851 0 1
+265 7 8
+224 0 4474
+444 0 1
+1651 10 11
+297 0 1
+665 0 21
+48 1 1
+1763 0 2
+245 1 1
+39 1 1
+519 1 1
+31 1 1
+2398 6 0
+749 1 49
+2072 0 4
+703 5 5
+337 0 1
+470 45 45
+1163 0 3
+1342 45 45
+140 1 0
+83 65 64
+723 38 38
+99 28 31
+92 0 1
+1218 13 0
+384 2 0
+292 41 41
+101 12 12
+576 2 0
+1907 21 21
+318 0 1
+1973 34 34
+689 51 51
+357 8 8
+2354 15 15
+2295 26 26
+2558 28 28
+571 2 0
+16 5 0
+323 1 0
+36 1 0
+5342 0 111
+1722 70 38
+272 13 13
+1284 1 0
+1128 4 4
+2189 0 1
+474 0 2
+1284 27 27
+36 6 0
+641 39 39
+381 2 0
+56 0 1
+2591 57 57
+160 121 121
+89 0 2
+316 1 0
+782 0 20
+155 1 1
+21 1 1
+601 6 0
+567 0 1
+278 1 1
+29 1 1
+89 4 0
+1737 1 1
+58 1 1
+368 24 24
+2113 24 20
+218 2 0
+18 1 1
+684 4 4
+3200 33 33
+58 18 18
+164 39 39
+296 6 6
+431 37 37
+431 47 47
+93 26 26
+216 48 48
+2779 17 0
+745 1 2
+104 61 61
+445 28 28
+356 0 1
+1484 2 1
+436 25 25
+306 57 57
+230 4 4
+843 49 50
+364 7 7
+796 28 28
+663 2 0
+93 15 0
+4378 0 1
+133 30 26
+41 2 0
+80 150 150
+925 0 3
+1882 13 13
+4513 0 1
+111 78 78
+200 0 6
+682 1 0
+200 0 3
+429 2 0
+736 20 20
+1573 121 120
+245 21 12
+1656 22 54
+616 1 2
+158 1 0
+587 41 44
+1053 6 6
+1116 36 36
+152 7 10
+448 1 0
+269024 863295 100000
+334079 50000 100000
+180557 74 0
+62 0 107
+7 2 1
+26 3 4
+4 0 1
+19 3 4
+10 42 87
+27 1 1
+202 1 1
+17 1 0
+156 1 1
+55 1 1
+111 1 0
+144 1 1
+57 1 0
+687074 50000 50000
+120648 348 0
+45585 1 0
+6994 0 1
+3398063 12354 44008
+7672 2 0
+1809 0 1
+428524 10165 101014
+43170 4 4
+1064959 5086 128966
+1021 1 0
+1710 0 1
+931 2 0
+4505 1 0
+686 2 525
+360 0 33
+130 1 1
+18 1 1
+12369 0 1014
+6233 1 0
+359485 111749 100000
+33855822 239 0
+2852112 0 1
+7040367 1 0
+2815738 1 3
+7055922 50000 60000
+363827 32 32
+104991 1 0
+203136 6050 0
+1426791 50000 60000
+13510190 5553 22012
+9194 3 0
+108 4 0
+41 1 0
+45 7 0
+2350 13 0
+5027 2 0
+534 0 1
+794 2 0
+4227 8 6
+5769 0 1
+381 0 1
+2524 2 0
+547 5 0
+1967 1 0
+1192 0 105
+1042 6 0
+3935380
+
+chain 22529558 15 102531392 + 21901199 22210800 chr15 100338915 + 19154576 19464222 111
+143347 1 1
+30 1 1
+2265 10 11
+297 0 1
+665 49 70
+240 39 39
+1731 41 41
+519 33 33
+339 22 22
+2037 4 0
+749 1 49
+910 38 38
+1831 3 9
+333 0 1
+470 1 1
+43 1 1
+1518 1 1
+51 1 1
+1122 1 0
+2351 19 6
+376 2 0
+1022 2 0
+1907 1 1
+19 1 1
+318 0 1
+3104 8 8
+179 1 1
+29 1 1
+3162 2 0
+2854 1 1
+26 1 1
+482 1 0
+512 1 1
+26 1 1
+571 27 16
+323 37 36
+5342 0 111
+542 40 39
+1141 64 35
+275 13 13
+503 26 26
+130 44 44
+581 4 0
+1128 4 4
+749 0 1
+1439 0 1
+474 0 16
+1270 1 1
+25 1 1
+54 11 0
+623 1 1
+37 1 1
+381 20 0
+56 0 1
+2591 1 1
+55 1 1
+160 4 4
+75 14 14
+1217 0 15
+742 59 53
+955 3 0
+1737 60 60
+391 43 43
+2071 24 20
+218 21 19
+684 4 4
+1195 4 4
+2001 1 1
+31 1 1
+58 18 18
+499 6 6
+431 1 1
+35 1 1
+431 1 1
+45 1 1
+3158 17 0
+983 0 1
+773 16 16
+1457 4 1
+767 1 1
+55 1 1
+338 10 10
+650 0 2
+123 3 4
+261 1 1
+48 1 1
+53 7 7
+776 1 1
+46 1 1
+663 2 0
+377 13 13
+4081 0 1
+159 5 0
+41 1 0
+164 1 1
+61 4 4
+925 0 3
+934 18 18
+1971 0 5
+3592 1 1
+76 1 1
+200 0 6
+682 1 0
+632 2 0
+2338 1 0
+110 1 1
+231 10 0
+1682 42 54
+616 1 2
+171 2 1
+543 1 1
+45 0 12
+2837 1 0
+441 2 0
+4958 5 5
+455 37 37
+330 22 22
+711 46 46
+184 49 49
+153 61 62
+392 11 11
+1266 8 7
+241 42 41
+198 31 31
+1064 78 78
+528 0 4
+431 1 0
+108 64 53
+358 5 5
+566 35 33
+168 1 0
+251 41 41
+880 33 33
+248 7 9
+583 3 4
+217 41 41
+117 13 14
+203 78 78
+133 44 45
+59 43 43
+129 19 19
+887 1 0
+264 30 30
+352 16 16
+719 36 35
+196 49 49
+425 4 0
+358 15 15
+151 22 22
+714 0 3
+165 41 0
+199 134 134
+504 47 47
+526 12 16
+206 39 39
+372 6 6
+224 25 25
+304 7 7
+186 90 90
+1872 0 3
+1066 7 7
+180 85 75
+63 37 37
+157 65 65
+331 3 0
+302 3 6
+213 42 45
+350 45 49
+580 42 45
+252 43 43
+337 4 0
+667 10 7
+94 9 9
+441 18 18
+124 0 1
+277 42 42
+1729 37 37
+1562 3 1
+546 15 13
+409 22 22
+312 45 45
+46 0 2
+268 14 14
+1166 35 38
+460 0 2
+74 0 1
+323 27 26
+2747 24 28
+322 10 0
+592 23 21
+161 45 45
+207 50 50
+409 22 23
+188 50 49
+396 152 151
+343 26 28
+3430 49 49
+2161 72 72
+1696 5 0
+389 50 50
+340 23 23
+169 0 3
+70 0 4
+392 0 1
+106 32 32
+2476 23 23
+1397 53 54
+2187 18 18
+489 9 9
+2018 4 0
+108 17 14
+836 5 5
+417 48 48
+358 34 34
+481 55 56
+277 48 48
+180 25 21
+356 3 0
+66 66 66
+407 28 27
+603 36 36
+1239 0 3
+194 8 8
+444 0 1
+204 35 35
+162 15 15
+418 6 5
+236 9 9
+55 52 52
+105 145 146
+57 143 143
+52
+
+chain 868538 15 102531392 + 21886534 21896633 chr15 100338915 + 19140000 19150000 4870
+1208 1 0
+245 165 68
+494 89 89
+824 15 15
+196 0 1
+197 50 50
+274 0 1
+1127 15 15
+230 4 0
+76 48 49
+671 0 1
+352 24 19
+117 11 11
+288 5 4
+122 0 3
+135 37 37
+265 0 2
+62 2 0
+656 0 2
+792 69 69
+142 73 73
+307 2 0
+331 0 2
+378
+
+chain 566185 15 102531392 + 83551634 83557670 chr8 146274826 + 129534406 129540446 9431
+549 1 1
+105 1 1
+1154 0 4
+273 6 6
+3947
+
+chain 334937 15 102531392 + 21896662 21900709 chr15 100338915 + 19150028 19154088 190582
+86 46 44
+567 11 9
+733 23 25
+212 2 0
+100 40 40
+155 1 0
+189 34 34
+165 42 42
+219 56 68
+259 61 62
+380 3 8
+242 13 13
+408
+
+chain 246244 15 102531392 + 22183221 22212114 chr15 100338915 + 19767012 19795905 936
+45 207 207
+50 619 619
+50 396 396
+152 343 343
+26 3430 3430
+49 2161 2161
+72 2090 2090
+50 1100 1100
+32 3896 3896
+53 6108 6108
+48 358 358
+34 481 481
+55 277 277
+48 180 180
+25 425 425
+66 407 407
+28 603 603
+36 2089 2089
+35 901 901
+52 105 105
+145 57 57
+143 52 52
+1314
+
+chain 136774 15 102531392 + 21885000 21886534 chr15 100338915 + 19138465 19140000 942717
+402 49 49
+445 0 1
+638
+
+chain 38827 15 102531392 + 28705151 28710237 chr15 100338915 - 73838719 73843805 82
+5086
+
+chain 19525 chr15 102531392 + 27138463 27148846 chr15_random 784346 + 739466 749849 392
+10383
+
+chain 9597 15 102531392 + 29116154 29116267 chr19 63811651 - 22308947 22309060 23761910
+59 4 4
+50
+
+chain 6273 15 102531392 + 23685556 23685849 chr15 100338915 + 21236652 21236834 12713809
+67 205 94
+21
+
+chain 4893 15 102531392 + 29111049 29111100 chr21 46944323 + 41885809 41885860 33898070
+51
+
+chain 3039 15 102531392 + 22178426 22178458 chr8 146274826 + 6100529 6100561 34349851
+32
+
+chain 2975 15 102531392 + 22826750 22826789 chr15 100338915 + 20381852 20381891 2718765
+39
+
+chain 2542 15 102531392 + 21049663 21065195 chr18 76117153 + 14510749 14526638 994
+38 2128 2130
+28 13310 13665
+28
+
+chain 1826 15 102531392 + 20950735 20950759 chr19 63811651 - 51273213 51273237 15159639
+24
+
+chain 1062 15 102531392 + 21028626 21028659 chr21 46944323 - 32992576 32992609 1118
+33
+
+chain 912 15 102531392 + 22826789 22826824 chr15 100338915 + 20377303 20377338 985154
+35
+
+chain 7474990131 16 90354753 + 60000 90294753 chr16 88827254 + 0 88822254 17
+172343 1 0
+111 0 1
+5627 1 2
+8398838 50000 17500
+25336229 150000 100000
+1112651 11100000 9800000
+42003582 50000 20000
+1855370
+
+chain 7369719958 17 81195210 + 0 81060651 chr17 78774742 + 0 78654742 18
+252627 1 1
+24 1 1
+41 29 0
+295 0 29
+261 0 58
+116 0 58
+94 0 29
+79 37 8
+485 59 1
+28 1 1
+76 1 233
+26 0 29
+2765 1 0
+17 2 0
+2220 18 18
+343 37 37
+457 1 1
+39 1 1
+564 16 16
+2523 9 39
+1878 56 0
+22 0 29
+1681 1 0
+414 3 0
+282 68 0
+93 10 10
+293 4 0
+3190 0 1
+2562 4 0
+1809 0 3
+84 1 1
+62 1 1
+3775 27 0
+1968 0 16
+912 2 0
+696 4 4
+1428 15 15
+290 0 1
+1779 1 0
+60 1 1
+216 1 0
+375 1 1
+41 1 0
+9221 100000 46522
+3080543 1 0
+1208216 2 0
+1370 0 2
+1279 4 0
+322 5 0
+5660 0 210
+308 22 21
+973 0 8
+2901 0 1
+8479 1 0
+4122 0 7
+3187 0 4
+571 1 0
+167 1 0
+10174 7 7
+856 1 2
+1630 0 1
+4258 1 3
+1688 0 1
+388 304 0
+672 0 1
+8495 10 0
+2272 0 1
+8297 0 1
+1500 4 1
+733 2 37
+57 17 0
+51 532 42
+2085 0 2
+52 1 1
+2913 13 14
+1309 1 0
+3991 0 3
+1939 3 0
+887 2 0
+463 0 18
+64 3 0
+2104 20 0
+557 4 0
+120 1 0
+3670 0 2
+4347 5394 0
+5332 1 0
+2505 10 4
+6776 11 14
+9573 1 0
+1136 2 0
+3754 0 1
+4588 0 1
+637 17 17
+1283 0 8
+371 1 0
+2084 0 1
+492 0 2
+519 4 0
+952 2 0
+1517 0 1
+987 0 9
+1152 10 0
+3608 2 0
+3199 39 0
+734 0 1
+646 0 2
+2211 0 1
+14829 0 1
+3473 34 1
+22 0 11
+2194 1 0
+6443 4 5
+2627353 0 1
+11581974 43 0
+31 89 0
+238782 1 0
+1830653 0 1
+419873 116477 100008
+5586 0 6
+11057 2 0
+3240 0 1
+1237 2 0
+373 1 1
+43 1 1
+558379 3000000 100000
+1823446 1 0
+2728383 1 0
+29 1 0
+138 0 1
+144 8 6
+38 2 0
+7 1 0
+18 1 1
+70935 1 0
+10 2 0
+52 31 28
+189 1 0
+41 2 2
+750363 44 44
+4038953 50039 100039
+1523967 1 1
+47 1 1
+231 0 2
+1175 0 1
+555 1 1
+49 1 1
+566 0 7
+607 0 2
+4954 1 1
+18 7 6
+567 1 0
+421 0 2
+1010 0 8
+777 3 0
+925 5 12
+318 0 1
+230 13 20
+244 1 1
+13 1 0
+42 1 1
+220 1 1
+56 1 1
+101 0 225
+1113 0 1
+17 1 1
+2614 0 4
+7108 2 0
+617 0 14
+5674 2 0
+1852 1 1
+63 1 1
+56 1 1
+25 1 1
+332 6 0
+423 5 5
+61 0 4
+108 1 1
+46 1 1
+160 2 2
+72 1 1
+162 1 1
+20 1 1
+53 1 1
+63 1 1
+112 1 1
+59 1 1
+5885 0 2
+5871 30040 159230
+925 0 5
+214 7 7
+641 17 17
+1296 46 46
+2513 69 71
+76 2 1
+57 0 50226
+1963 18 18
+2694 55 55
+6616 0 1
+5106 18 0
+2521 7 7
+49 0 10
+3440 4 0
+4179 4 0
+2749 1 0
+1125 0 8
+55 1 1
+1840 14 14
+624 0 8
+1742 0 4
+3690 4 0
+2051 1 0
+751 1 0
+2111 11 10
+3110 0 1
+682 0 1
+2795 2 5
+241 1 0
+165 3 1
+1258 1 0
+1601 0 5
+3716 1 0
+1308 1 0
+2058 0 1
+1624 1 0
+478 0 4
+9 0 6
+35 1 3
+47 1 0
+2425 0 1
+1178 4 0
+33 1 1
+415 5 5
+887 3 1
+1605 0 15
+259 0 2
+78 1 0
+4570 1 0
+322 0 1
+1801 0 2
+836 0 3
+1509 1 0
+1732 1 0
+936 6 0
+1371 0 1
+625 12 2
+5009 1 1
+75 1 0
+20 0 1
+139 1 0
+523 3 0
+11 319 0
+1368 0 1
+774 1 1
+16 1 1
+3523 119 124
+497 0 4
+174 0 9
+1317 3 0
+508 1 0
+1126 0 1
+1952 2 0
+565 0 2
+871 1 0
+1460 0 6
+55 1 0
+420 0 6
+57 1 1
+119 1 1
+427 0 1
+459 11 14
+448 1 0
+1275 7 7
+360 0 1
+73 1 1
+48 1 1
+4920 0 3
+713 1 1
+21 0 3
+6 0 3
+6 0 1
+691 1 1
+44 1 1
+1158 38 38
+446 10 9
+566 1 0
+175 4 0
+796 10 0
+810 0 1
+78 17 18
+1531 2 0
+1274 1 1
+39 1 1
+53 1 3
+202 1 0
+707 17 17
+1733 1 0
+1540 42 42
+12471 0 3
+286 1 3
+5600 0 4
+6458 1 0
+4866328 0 102000
+1870126 0 257
+590080 18 6
+26953 0 1
+6737 4 0
+5946 0 1
+2319 4 0
+1641 1 1
+27 1 1
+1237 0 1
+2698 1 1
+140 1 1
+1689 2 0
+836 30 29
+5333 0 1
+509 0 1
+224 9 9
+4983 0 6
+4981 30 30
+6913 3 13
+1039 1 0
+11605 0 1
+22064 1 0
+16612 0 8
+902 0 1
+757 0 1
+84 46 46
+489 1 0
+10979 1 1
+18 1 1
+1517 0 1
+4576 0 1
+12558 0 4
+2726 1 0
+5291 0 2
+8706 1 0
+83 0 1
+406 7 0
+87 0 38
+5531 0 1
+23971 0 1
+7855 22 54
+4095 1 0
+803 5 5
+6382 0 6
+3546 28 0
+4264 2 0
+13194 6 6
+6463 0 1
+26075 1 1
+59 1 1
+10791 7 17
+707 1 0
+210 0 1
+1655 2 0
+5301 0 1
+1930 0 1
+14632 0 2
+1043 0 1
+3607 0 3
+312 1 0
+5953 0 2
+170 17 0
+489 1 0
+5260 28 0
+888 0 10
+2461 10 10
+237 0 2
+1716 1 3
+10694 4 0
+3754 0 1
+6173 1 0
+8017 2 1
+3594 4 0
+5439 1 0
+4137 14 0
+29 15 0
+6418 1 0
+1267 0 1
+723 6 0
+1080 0 2
+3878 1 0
+7682 1 1
+44 1 1
+3135 1 0
+174853 2 1
+2008 7 7
+5657 1 0
+6496 3 0
+89 5 0
+665 1 0
+954 1 1
+44 1 1
+375 8 7
+3317 2 0
+2753 0 1
+1863 3 0
+3228 0 1
+3571 49 45
+6488 2 0
+8451 172 172
+3797 16 0
+2103 1 0
+268 23 26
+7888 0 4
+701 0 4
+2402 6 0
+37 1 1
+2943 3 2
+8420 0 1
+932 324 0
+6726 0 1
+543 3 4
+4028 0 18
+88 4 0
+2999 0 1
+530 0 1
+1153 11 11
+919 2 0
+1174 17 0
+118 16 16
+2727 0 1
+543 1 0
+783 0 1
+1374 4 0
+8619 0 20
+281 44 44
+4364 50 51
+2856 1 0
+5399 1 0
+1506 0 1
+919 6 0
+7228 0 10
+3226 0 1
+435 0 1
+4463 132 0
+9760 1 0
+2034 0 6
+7656 0 1
+198212 132 0
+11700 5 0
+7647 0 1
+9062 0 4
+8778 2 0
+7014 0 1
+1613 2 0
+790 5 7
+7433 0 1
+6482 12 12
+6798 1 0
+1422 0 1
+3454 1 1
+43 1 1
+3097 2 0
+334 18 0
+1444 0 1
+2400 0 3
+3272 1 0
+9106 0 1
+1573 1 0
+4742 0 1
+3366 0 1
+5484 1 0
+2445 5 0
+5447 8 8
+2539 1 0
+1471 1 0
+238 1 1
+16 1 1
+288 5 5
+2995 2 0
+951 1 1
+35 1 1
+279 15 16
+3534 0 6
+3513 1 0
+163 1 0
+6173 1 0
+1074 0 1
+2818 0 1
+2868 1 0
+3796 0 1
+1118 167 1
+1278267 25 25
+10747175 217 0
+3504874 1053 0
+10844 11 13
+18805 0 1
+1960834 50000 126729
+3065 0 1
+3601036 8833 90008
+34292 0 1
+376 14 14
+1447 44 0
+3080 1 1
+43 1 1
+789 0 1
+11432680 50000 153000
+1902016 4098 0
+102 21 0
+3179 6 6
+877 1 1
+49 1 1
+296 1 0
+1375 1 1
+21 1 1
+607 5 5
+98 22 0
+6811 1 1
+17 11 0
+3804 0 1
+1356 1 1
+29 1 1
+297 0 1
+9543 2 0
+3131 4 0
+860 1 0
+27346 0 1
+7553 0 2
+2834 2 0
+394 0 4
+6322 44 44
+158 0 1
+405 8 11
+1128 0 7
+271 1 1
+21 28 0
+504 0 6
+1214 31 44
+384 3 0
+521 18 18
+392 0 11
+802 1 1
+25 2 3
+51 49 1
+49 1 1
+558 1 0
+351 0 1
+2779 13 13
+114398 82124 65008
+7795 1 0
+18 1 1
+4140 0 1
+28048 1 1
+32 1 1
+4630 0 1
+4573 0 3
+357 0 2
+4812 0 1
+14372 3 0
+203 1 0
+26257 0 1
+2734 2 0
+19262 5 5
+5022 1 0
+25471 1 0
+1114538 53 0
+82 0 126
+1416 16 16
+610 0 57
+482 0 1
+148 1 1
+24 1 1
+2322 1 1
+23 0 1
+719 16 0
+20 0 16
+105 9 9
+1277 1 0
+2498 1 0
+352 0 49
+50 50 0
+21 49 0
+28 49 0
+60 47 0
+17 97 0
+901 47 0
+272 14 1104
+279 1 0
+37 12 11
+65 32 0
+18 94 0
+60
+
+chain 3227650 chr17 81195210 + 81075742 81110122 chr17_random 2617613 + 864624 914847 755
+922 0 1
+430 0 1
+763 0 1
+19745 32 32
+637 36 15873
+186 0 1
+2389 0 1
+616 0 1
+1932 12 12
+6680
+
+chain 2732964 17 81195210 + 36295616 36336227 chr17 78774742 - 45363365 45403960 362
+666 1 1
+114 1 1
+1777 1 1
+22 1 1
+2481 3 0
+947 3 1
+994 1 1
+26 1 1
+5327 2 0
+95 13 13
+2424 0 1
+339 2 1
+288 1 0
+1180 8 8
+1145 2 4
+1144 1 0
+322 1 0
+28 1 0
+35 1 0
+1499 0 1
+1258 7 6
+1123 0 1
+269 5 4
+1850 18 19
+188 3 0
+403 1 1
+18 1 1
+3148 1 1
+160 1 1
+105 11 0
+573 10538 10545
+33
+
+chain 1501094 chr17 81195210 + 81048174 81075742 chr17_random 2617613 + 1430075 1457643 965
+53 10174 10174
+50 21 21
+49 28 28
+49 60 60
+47 17 17
+97 901 901
+47 680 680
+32 18 18
+94 60 60
+15091
+
+chain 1197294 chr17 81195210 + 21670280 21683085 chr17_random 2617613 - 711226 724030 995
+6335 1 0
+1486 0 2
+2024 2 0
+2957
+
+chain 653269 chr17 81195210 + 66064861 66073694 chr17_random 2617613 - 926391 957193 299
+3246 4346 26315
+1241
+
+chain 307142 chr17 81195210 + 79761820 81150656 chr17_random 2617613 + 2320255 2536424 170
+87 6 8
+1077 0 1
+77 0 1
+1009 0 1
+98 0 1
+35 0 1
+131 0 1
+288 0 1
+33 1 0
+225 0 1
+279 0 1
+110 0 1
+55 0 1
+107 0 1
+202 12 15
+111 0 1
+36 0 2
+25 0 1
+202 0 1
+95 0 1
+145 1 1
+21 0 1
+222 0 1
+41 0 1
+492 4 0
+594 0 1
+179 0 1
+412 0 1
+37 0 1
+13 0 1
+34 0 1
+76 37 38
+204 27 27
+204 1 3
+8 0 5
+23 0 1
+430 0 1
+145 0 1
+271 0 1
+222 0 1
+51 0 1
+17 0 1
+23 2 4
+385 0 1
+337 0 1
+374 0 1
+140 17 22
+297 0 1
+72 5 8
+193 0 1
+8 0 1
+28 0 1
+17 0 1
+17 0 1
+445 0 1
+169 0 1
+35 37 3
+425 0 1
+41 0 1
+37 0 1
+79 0 1
+100 0 1
+127 0 1
+422 0 1
+17 1 1
+284 1 3
+56 10 12
+650 0 1
+163 0 2
+6 0 1
+36 1 1
+519 0 1
+39 0 1
+78 0 1
+216 3 5
+66 0 1
+58 0 1
+68 0 1
+292 4 0
+46 2 0
+108 2 0
+23 114 0
+830 0 1
+136 43 43
+23 32 10
+63 64 65
+380 0 1
+22 1 1
+440 0 1
+66 1 1
+17 0 1
+171 3 5
+27 1 1
+130 10 13
+128 0 1
+418 0 1
+4 1 2
+37 0 1
+29 0 1
+27 0 1
+748 0 1
+251 0 1
+219 0 1
+111 0 1
+48 0 1
+325 0 1
+296 0 1
+383 0 1
+62 0 1
+244 0 2
+248 9 11
+180 0 1
+241 0 1
+40 1 3
+6 0 1
+19 0 1
+27 0 1
+166 0 1
+78 0 1
+165 0 1
+33 0 1
+9 0 1
+172 0 1
+261 0 1
+200 16 21
+121 0 1
+37 2 4
+74 0 1
+97 3 5
+11 0 1
+51 0 1
+642 0 1
+317 11 14
+138 1324229 151143
+4948 1 0
+1850 67 60
+3859 1 0
+456 5 4
+1605 21 21
+1281 13 7
+5085 0 456
+1548 1 1
+37 1 1
+2825 1 1
+64 1 1
+1075 1 0
+721 1 0
+5566 5 22
+1136 0 1
+2390 3 0
+1347 2 0
+4617
+
+chain 266741 chr17 81195210 + 81150656 81195210 chr17_random 2617613 - 1100691 1809734 427
+1871 0 662945
+298 0 1
+6514 2 2
+45 0 1
+6237 3 5
+1230 32 32
+347 0 1
+1941 14 14
+149 0 1
+25553 59 1621
+16 63 39
+180
+
+chain 215840 chr17 81195210 + 66068832 66109867 chr17_random 2617613 + 1644335 1685356 1023
+3394 37597 37583
+44
+
+chain 30167 17 81195210 + 44458173 44458487 chr2 242951149 - 34181426 34181740 4632506
+314
+
+chain 29586 17 81195210 + 36420504 36420817 chr7 158821424 - 10371995 10372309 4828537
+136 0 1
+177
+
+chain 20882 17 81195210 + 56914122 56914339 chrX 154913754 + 31643322 31643539 5151267
+217
+
+chain 16484 17 81195210 + 44491151 44521781 chr17 78774742 + 42064051 42094670 662
+44 30454 30443
+132
+
+chain 14999 17 81195210 + 44428451 44428612 chr17 78774742 + 42001706 42001867 887
+161
+
+chain 12695 17 81195210 + 44739444 44739576 chr17 78774742 + 41877181 41877313 13974721
+132
+
+chain 12494 17 81195210 + 19077136 19077299 chr17 78774742 - 59726399 59726562 431
+43 31 31
+89
+
+chain 7858 17 81195210 + 253568 254148 chr17 78774742 + 253365 253974 1160836
+37 486 515
+57
+
+chain 5202 17 81195210 + 79704633 79704687 chrY 57772954 - 54321400 54321454 32857515
+54
+
+chain 5149 17 81195210 + 36426505 36456524 chr17 78774742 - 35824084 35853324 896
+73 1 1
+45 29858 29079
+42
+
+chain 3754 17 81195210 + 60419213 60419252 chr8 146274826 - 11845696 11845735 33181261
+39
+
+chain 3753 17 81195210 + 44413461 44413510 chr17 78774742 - 18492830 18492879 715
+49
+
+chain 3637 chr17 81195210 + 79776689 79776727 chr17_random 2617613 + 2335092 2335130 5614693
+38
+
+chain 3637 chr17 81195210 + 79776651 79776689 chr17_random 2617613 + 2335092 2335130 5614694
+38
+
+chain 3636 chr17 81195210 + 79776613 79776651 chr17_random 2617613 + 2335130 2335168 7454076
+38
+
+chain 2637 17 81195210 + 252694 252723 chr17 78774742 + 252810 252839 1426666
+29
+
+chain 2581 17 81195210 + 81166856 81166888 chr1 247249719 + 441705 441737 997
+32
+
+chain 2427 chr17 81195210 + 79772596 79772621 chr17_random 2617613 + 2331168 2331193 24392944
+25
+
+chain 1872 17 81195210 + 79585571 79585619 chr11 134452384 + 72960908 72960956 2849402
+48
+
+chain 790 chr17 81195210 + 36328756 36331384 chr17_random 2617613 - 1242589 1245215 133
+46 2513 2511
+69
+
+chain 170 chr17 81195210 + 34725848 34725887 chr17_random 2617613 + 1051433 1051472 428
+39
+
+chain 94559897 chr17_ctg5_hap1 1680828 + 188271 1499222 chr17 78774742 - 36776984 37845687 55
+188 30 30
+348 14 15
+235 24 24
+194 3 0
+334 40 40
+270 54 54
+61 87 84
+948 4 3
+1658 2 0
+1730 0 2
+285 0 1
+2885 1 1
+38 1 1
+2933 0 1
+1942 10 0
+375 0 1
+5094 0 1
+814 1 1
+18 1 1
+4676 8 0
+578 10 7
+467 0 1
+892 1 0
+479 48 48
+132 0 6
+61 13 15
+66 38 38
+1901 35 35
+862 7 0
+3895 1 0
+740 44 44
+313 7 6
+4916 4 4
+507 0 1
+2214 1 1
+25 0 3
+106 2 0
+40 1 1
+146 1 1
+30 1 1
+63 0 1
+192 5 5
+3242 0 2
+385 33 33
+972 12 0
+93 1 1
+3332 2 2
+71 1 1
+57 1 1
+149 0 2
+91 1 1
+219 14 14
+606 1 1
+53 1 1
+1068 0 12
+3191 29 29
+7028 1 0
+478 1 0
+2064 0 1
+408 17 21
+675 1 1
+17 1 0
+4 1 1
+3445 0 1
+158 0 2
+312 0 14
+1801 0 1
+1424 4 0
+1894 2 0
+364 6 6
+54 2 0
+47 1 1
+1105 10 1
+3088 0 1
+1176 6 0
+4141 1 1
+24 0 1
+169 71 71
+1596 1 1
+37 1 1
+2758 5 0
+2986 1 1
+20 1 1
+206 4 0
+11154 0 17
+583 0 8
+1703 0 10
+1675 1 0
+392 1 0
+6851 37 37
+2872 132 0
+446 9 0
+3437 5 5
+995 0 2
+898 1 1
+18 1 1
+128 0 1
+2151 2 0
+6413 1 1
+48 1 1
+786 0 1
+939 0 1
+258 0 4
+1247 2 0
+4742 0 1
+3520 54 51
+1220 1 1
+30 1 1
+638 1 0
+2474 1 1
+42 1 1
+266 0 16
+106 1 1
+19 1 1
+3806 328 0
+1161 1 0
+4896 0 1
+779 0 2
+543 1 0
+4979 11 11
+1670 1 0
+889 3 0
+2126 2 0
+87 0 18
+193 1 0
+3840 12 0
+3234 4 0
+2802 0 1
+873 1 0
+1288 1 5
+2202 1 1
+21 1 0
+1366 0 1
+4830 4 0
+48 1 1
+2894 1 1
+7 14 0
+43 0 4
+1003 1 1
+28 1 1
+102 3 0
+370 50 50
+830 1 3
+674 3 7
+2759 2 0
+4559 14 12
+862 1 0
+245 49 49
+1367 0 3
+428 13 41
+77 0 9
+701 1 0
+528 1 1
+31 1 1
+1397 0 2
+832 1 1
+34 2 0
+404 1 0
+142 1 1
+30 1 1
+272 2 0
+783 0 2
+4039 1 0
+449 8 0
+2647 1 0
+1730 7 1
+38 80 0
+160 5 0
+492 0 12
+1920 1 1
+117 1 1
+350 1 1
+38 1 1
+279 1 1
+40 1 1
+1367 4 0
+427 35 35
+141 46 46
+399 1 0
+1786 35 35
+697 0 1
+1104 20 20
+290 28 28
+1774 0 5
+1339 5 0
+527 1 0
+312 62 62
+199 1 1
+239 42 42
+629 1 1
+41 1 1
+298 3 3
+26 1 1
+642 1 1
+52 1 1
+206 8 0
+1930 0 1
+806 19 12
+578 10 7
+375 1 1
+44 1 1
+939 2 0
+679 10 0
+56 0 2
+73 13 13
+556 1 1
+18 1 1
+1386 1 1
+35 281 0
+106 1 1
+435 13 0
+686 2 0
+1401 0 8
+1799 1 0
+1566 0 3
+692 21 21
+1368 5 5
+150 28 28
+53 6 11
+54 50 50
+129 4 4
+550 15 0
+160 13 13
+1640 1 0
+170 31 31
+1087 124 123
+249 12 12
+407 1 1
+18 1 1
+637 13 13
+450 1 1
+30 1 1
+100 1 1
+37 1 1
+407 0 2
+2327 8 1
+107 1 1
+37 1 1
+885 1 1
+20 1 1
+134 18 18
+168 1 0
+161 6 6
+497 1 1
+16 1 1
+2755 29 29
+102 242 244
+58 8 8
+153 14 14
+711 41 41
+76 35 35
+287 93 93
+472 14 21
+608 7 8
+171 34873 0
+117 7 7
+68 10 0
+31 1 1
+95 11 11
+267 1 1
+19 1 1
+494 1 1
+26 1 1
+135 1 0
+302 1 1
+26 1 1
+349 0 1
+37 1 1
+254 1 1
+24 1 1
+550 1 0
+170 1 1
+38 1 1
+100 1 1
+31 0 1
+305 6 8
+370 0 3
+162 7 0
+39 4 4
+112 6 6
+318 1 1
+49 1 1
+135 1 1
+34 1 1
+129 1 1
+49 1 1
+620 0 1
+98 1 1
+43 1 1
+252 1 1
+37 1 1
+824 5 5
+131 9 10
+247 1 1
+20 1 1
+303 1 0
+668 1 1
+45 1 1
+316 14 14
+657 1 1
+93 1 1
+290 0 3
+148 1 1
+29 5 5
+74 1 1
+40 1 1
+1516 1 1
+57 1 1
+132 3 0
+178 1 1
+131 1 1
+127 1 1
+103 0 1
+61 1 1
+460 5 7
+90 1 1
+22 1 1
+87 1 1
+44 1 1
+85 1 3
+767 0 7
+60 1 1
+79 1 1
+31 1 1
+258 1 1
+26 0 1
+11 2 2
+140 1 1
+31 1 1
+110 1 0
+12 9 0
+776 8 8
+50 1 0
+445 1 1
+34 1 1
+278 15 15
+125 1 0
+635 18 19
+183 0 1
+75 10 10
+200 19 21
+832 14 14
+2247 6 0
+318 0 2
+180 10 0
+167 1 1
+43 1 1
+60 1 1
+43 1 1
+268 0 11
+1220 1 1
+46 5 5
+1001 16 16
+218 7 7
+142 17 0
+74 1 1
+130 1 1
+30 2 0
+588 1 1
+83 2 2
+58 25 25
+65 50 50
+873 23 23
+277 21 20
+237 3 0
+66 0 51
+145 0 1
+133 1 1
+23 1 1
+1087 3 2
+295 4 5
+57 10 8
+347 1 1
+18 1 1
+350 3 5
+259 0 1
+771 3 4
+85 1 1
+62 8 8
+224 1 1
+40 1 1
+50 0 3
+137 1 1
+199 3 3
+21 1 1
+272 0 10
+66 12 0
+27 1 1
+138 6 5
+762 1 1
+20 1 1
+324 9 9
+71 0 4
+174 5 12
+237 6 6
+57 1 6
+21 1 1
+156 0 2
+89 1 1
+140 1 1
+69 11 0
+407 0 2
+20 1 1
+131 0 2
+162 1 1
+29 1 1
+65 7 7
+1199 1 1
+68 1 1
+75 12 12
+78 3 3
+37 1 1
+499 1 1
+44 1 0
+397 1 1
+116 1 1
+147 1 0
+286 4 0
+122 31 0
+436 1 1
+27 1 1
+137 11 0
+448 40 0
+174 5 5
+148 1 0
+42 40 0
+506 850 23
+509 1 1
+61 1 1
+113 1 1
+83 1 0
+90 1 1
+229 0 1
+366 0 6
+625 0 1
+160 1 1
+43 1 1
+174 1 1
+53 1 1
+129 10 10
+205 1 1
+18 1 1
+386 1 1
+36 1 1
+775 1 1
+49 0 2
+118 10 10
+238 4 0
+801 0 5
+164 73 73
+1003 22 15
+181 1 1
+62 1 1
+1006 1 1
+25 1 1
+361 1 1
+76 21 0
+386 9 0
+224 25 34
+1276 0 4
+157 4 4
+450 1 1
+15 1 0
+36 1 1
+402 15 0
+1572 8 9
+272 3 0
+319 9 9
+673 0 724
+177 23 26
+230 2 0
+107 1 1
+80 99 99
+319 1 0
+711 0 1
+18 1 1
+674 3 0
+826 0 2
+503 1 1
+25 32 0
+42 1 1
+67 1 0
+395 19 14
+328 1 1
+69 1 1
+520 1 1
+31 1 1
+1063 1 1
+67 2 2
+55 4 0
+477 4 0
+69 0 1
+807 4 3
+26 1 1
+400 2 0
+707 5 0
+41 1 1
+200 1 1
+33 1 1
+744 1 1
+25 1 1
+224 2 0
+121 9 4
+44 1 1
+266 78 94
+522 0 1
+81 1 1
+3286 0 1
+341 1 1
+17 2 1
+445 1 1
+23 1 1
+1029 2 0
+169 1 1
+30 1 1
+577 1 0
+754 2 2
+43 1 1
+170 20 14
+365 1 1
+88 0 1
+1312 0 1
+354 1 4
+526 4 2
+1931 3 0
+650 17 17
+454 1 1
+59 2 3
+167 3 0
+1448 13 13
+69 1 1
+48 1 1
+398 1 1
+89 5 0
+33 1 1
+422 1 1
+39 0 1
+250 86 15
+1631 0 1
+20 1 1
+69 1 1
+38 1 1
+104 0 2
+30 1 1
+420 1 1
+70 1 0
+497 1 0
+68 0 14
+1402 1 1
+28 1 1
+385 4 0
+42 1 1
+245 1 1
+31 2 1
+1110 1 1
+44 1 1
+1784 1 1
+42 1 1
+194 0 1
+181 0 4
+278 14 13
+800 1 0
+160 0 2
+259 1 1
+48 1 1
+336 5 0
+49 12 0
+814 1 1
+39 1 1
+144 4 0
+618 0 4
+159 0 3
+30 1 1
+443 2 0
+140 1 1
+49 1 1
+510 1 1
+22 1 1
+1186 1 1
+45 1 1
+2488 9 0
+226 12 8
+769 1 1
+36 3 0
+1785 1 1
+40 1 1
+570 5 0
+122 7 7
+181 11 11
+539 0 8
+1090 7 7
+128 0 1
+918 0 1
+314 43 43
+173 26 25
+374 0 1
+267 43 49
+69 16 15
+531 16 16
+179 0 6
+604 2 0
+646 28 35
+276 0 1
+1116 21 21
+257 1 0
+165 56 57
+85 41 41
+939 52 52
+134 6 6
+966 5 0
+1657 1 0
+142 22 23
+301 14 0
+280 35 35
+304 3 0
+1345 4 0
+219 1 1
+93 1 1
+646 1 1
+70 1 1
+115 1 1
+25 0 2
+6 1 1
+876 0 1
+750 1 0
+1106 1 1
+44 1 1
+1136 0 1
+2705 1 1
+29 1 1
+474 1 0
+24 1 1
+517 18 17
+283 45 35
+190 6 3
+714 102 102
+1046 0 2
+2521 29 29
+123 1 0
+171 0 8
+504 5 6
+2380 0 1
+1479 53 42
+159 5 5
+248 1 1
+34 1 1
+643 2 0
+586 0 4
+1216 1 1
+30 1 1
+1308 1 1
+25 1 1
+244 0 4
+1092 11 11
+297 0 4
+776 22 22
+62 1 0
+222 0 1
+38 1 1
+808 0 7
+45 1 1
+42 2 0
+313 5 0
+1028 2 3
+366 0 2
+298 41 355
+1457 37 37
+356 49 49
+849 140 128
+155 0 4
+92 6 6
+2333 1 0
+546 1 0
+612 68 68
+259 1 0
+304 3 0
+1246 1 0
+351 22 21
+1110 14 14
+364 0 3
+349 1 1
+39 1 1
+76 0 8
+152 9 0
+283 1 0
+117 1 2
+304 1 0
+1958 19 0
+278 1 1
+109 1 1
+1942 1 1
+31 2 0
+13 1 1
+312 18 0
+151 7 0
+62 1 1
+694 1 1
+18 1 1
+163 1 1
+17 1 0
+1103 2 0
+218 1 0
+21 1 1
+372 11 11
+434 3 4
+440 4 0
+45 1 0
+402 1 1
+46 1 1
+757 1 1
+43 1 1
+96 27 81
+499 1 1
+21 1 1
+184 14 14
+307 15 16
+1265 1 1
+62 1 1
+1051 1 0
+1157 1 1
+28 2 0
+349 3 0
+606 1 1
+22 1 1
+107 0 1
+36 1 1
+499 1 1
+27 1 1
+505 0 1
+1698 6 0
+38 1 1
+924 1 1
+33 1 1
+108 0 2
+196 1 1
+25 1 0
+24 1 1
+824 6 0
+725 0 1
+917 17 0
+185 1 1
+51 4 4
+93 0 1
+351 1 1
+34 1 1
+608 10 10
+82 2 0
+27 1 1
+2343 1 1
+48 1 1
+188 9 9
+623 4 3
+603 0 6
+11 1 1
+379 1 1
+52 1 1
+157 37 20
+879 51 58
+229 14 2
+83 1 1
+70 1 0
+1849 1 1
+42 1 1
+961 1 1
+22 1 1
+219 1 1
+25 1 1
+551 0 3
+26 1 7
+250 1 1
+44 1 1
+1028 9 2
+471 1 1
+31 0 1
+574 0 323
+192 1 1
+44 1 1
+1934 168 168
+186 1 0
+197 25 0
+161 1 0
+15 6 0
+806 1 1
+18 1 1
+184 1 0
+86 1 1
+16 1 1
+183 0 1
+641 12 12
+687 0 2
+735 2 0
+45 0 6
+308 11 11
+153 1 1
+23 1 1
+143 1 1
+59 1 1
+178 28 0
+899 0 3
+1351 2 0
+168 3 0
+407 1 0
+290 2 1
+227 1 1
+48 1 1
+704 1 1
+48 1 1
+866 93 93
+536 1 5
+1481 8 11
+180 16 16
+88 6 0
+249 0 44
+37 1 1
+294 1 1
+32 0 20
+1368 1 1
+93 1 1
+1638 11 11
+303 0 1
+55 1 1
+24 1 1
+1188 1 0
+227 2 2
+45 3 0
+205 0 4
+34 0 1
+159 1 1
+24 1 1
+398 0 1
+1259 16 16
+64 2336 0
+59 1 1
+44 0 3
+25 1 1
+209 1 1
+18 1 1
+348 1 1
+30 1 1
+413 27 0
+53 1 1
+23 2 0
+25 0 4
+532 0 12
+184 1 0
+278 1 1
+29 1 1
+1186 1 1
+15 1 1
+300 12 12
+570 1 1
+43 1 1
+183 5 6
+134 1 0
+508 1 1
+30 1 1
+1074 1 1
+24 1 1
+162 8 8
+1046 1 1
+20 1 1
+817 0 3
+1128 1 1
+41 1 1
+166 27 27
+667 15 15
+967 2 0
+10 2 0
+261 1 0
+792 1 8
+153 0 3
+1788 13 22
+1089 1 0
+994 2 0
+368 0 18
+207 1 1
+39 1 1
+332 0 3
+298 5 3
+68 1 1
+44 1 1
+958 1 1
+41 1 1
+1009 0 24
+12 1 0
+118 0 1
+171 16 16
+229 8 8
+233 21 21
+71 1 1
+38 1 1
+185 1 0
+544 1 1
+64 2 0
+614 1 1
+62 1 1
+536 1 1
+143 1 1
+679 0 5
+169 0 3
+597 1 0
+654 1 0
+1270 0 11
+174 0 2
+606 1 1
+59 2 0
+153 3 4
+1186 10 11
+92 1 4
+956 4 0
+302 0 9
+199 1 1
+31 1 1
+878 31 0
+452 10 10
+988 20 15
+1054 0 1
+131 0 4
+652 2 0
+37 1 1
+142 1 1
+36 0 5
+29 0 8
+4136 1 1
+32 1 1
+701 11 11
+258 0 1
+133 7 7
+170 1 0
+372 0 1
+26 4 3
+31 1 1
+131 1 0
+29 1 0
+2657 10 10
+2046 7 0
+870 1 0
+101 16 18
+163 0 1
+526 4 3
+281 0 3
+1907 0 1
+30 0 3
+164 0 3
+132 0 1
+352 1 0
+455 1 0
+726 0 2
+107 1 1
+33 1 1
+156 2 0
+576 1 1
+16 1 0
+76 1 0
+862 11 11
+1049 1 0
+47 1 1
+69 0 3
+607 1 1
+46 1 1
+1700 0 1
+825 13 13
+813 0 1
+213 1 0
+46 1 1
+630 1 0
+683 51 52
+118 1 1
+28 1 1
+1162 1 1
+66 0 3
+472 14 0
+16 1 1
+134 1 1
+119 1 1
+1129 5 5
+149 1 1
+57 1 1
+918 1 1
+36 1 1
+752 12 12
+1962 0 238
+2372 0 15
+175 7 7
+833 1 1
+25 1 1
+315 1 1
+16 1 0
+436 15 15
+67 15 15
+1207 6 5
+732 6 0
+79 1 1
+53 1 1
+1521 5 6
+140 1 0
+3576 12 12
+479 1 1
+37 1 1
+1518 1 1
+77 1 1
+102 1 1
+26 1 1
+812 1 1
+23 1 1
+1740 0 1
+1077 1 1
+17 1 1
+885 6 6
+441 17 17
+284 1 1
+37 1 1
+107 1 1
+17 1 1
+335 1 1
+50 1 1
+120 8 7
+588 0 8
+1512 38 1
+550 45 45
+376 1 1
+63 1 1
+2111 0 1
+574 14 14
+1622 3 1
+683 23 26
+673 1 1
+45 12 0
+98 3 4
+93 20 0
+2130 10 10
+941 1 1
+24 1 1
+1362 2 0
+1696 1 1
+22 2 2
+737 1 1
+26 1 1
+922 1 1
+32 1 1
+923 7 8
+432 0 1
+152 1 1
+26 1 1
+841 0 4
+441 0 103
+1348 10 11
+589 1 1
+44 1 1
+775 8 8
+1051 0 2
+152 13 13
+572 6 6
+543 1 1
+45 1 1
+663 7 7
+802 1 0
+888 1 1
+44 1 1
+210 1 0
+111 1 1
+34 1 1
+459 0 1
+323 1 0
+1116 1 0
+27 1 1
+142 1 1
+21 1 1
+784 1 1
+37 0 4
+40 1 1
+813 1 3
+371 1 1
+25 1 1
+257 1 1
+88 1 1
+276 47 47
+192 5 9
+445 1 1
+19 1 1
+66 8 8
+205 1 1
+79 11 0
+106 1 1
+122 1 1
+2478 0 6
+89 1 1
+47 1 0
+68 1 1
+680 0 4
+1040 0 1
+424 1 1
+33 1 1
+170 0 1
+456 1 1
+66 1 1
+820 18 18
+146 11 11
+642 2 0
+28 1 1
+242 1 0
+50 0 3
+7 1 1
+301 13 13
+126 1 1
+40 1 1
+98 0 2
+202 11 11
+564 23 0
+145 10 7
+1202 1 1
+103 1 1
+459 1 1
+24 1 1
+298 1 1
+44 1 1
+1384 1 1
+31 1 1
+569 1 1
+68 1 1
+535 5 45
+575 1 1
+30 1 1
+1885 1 0
+426 3 0
+19 1 1
+136 1 0
+556 1 1
+17 1 1
+463 6 8
+803 35 35
+170 1 0
+28 1 1
+454 9 9
+450 1 1
+34 1 1
+728 12 13
+1023 0 3
+204 1 1
+33 1 1
+322 1 1
+35 5 0
+147 1 1
+6 1 0
+107 1 1
+442 1 1
+44 1 1
+407 1 0
+1683 1 5
+53 1 1
+1265 1 0
+209 1 1
+28 1 1
+92 1 1
+44 1 1
+671 1 1
+42 0 2
+39 1 1
+74 1 1
+67 1 1
+854 0 30
+676 2 0
+33 0 1
+145 1 1
+48 1 1
+261 3 0
+166 1 1
+24 0 1
+311 1 1
+76 1 1
+893 1 1
+39 1 1
+65 1 0
+1321 1 1
+31 1 1
+316 0 14
+78 9 9
+2264 1 1
+20 1 1
+777 1 2
+274 0 1
+1285 0 11
+500 1 1
+24 1 1
+107 0 3
+77 1 1
+76 1 1
+1414 5 5
+54 37 0
+421 8 8
+150 1 1
+71 1 1
+128 0 1
+514 75 0
+116 1 0
+201 1 1
+17 0 1
+1181 1 1
+30 1 1
+131 12 12
+386 0 1
+351 3 3
+6 4 0
+14 0 1
+48 1 1
+1034 0 4
+789 2 0
+76 1 1
+29 1 1
+691 1 1
+65 1 1
+1723 4 4
+22 1 1
+2576 1 3
+235 1 1
+35 1 1
+52 70 144
+15 1 3
+5 1 0
+51 1 3
+6 3 0
+6 1 0
+4 1 0
+8 0 2
+15 1 0
+8 2 1
+20 1 0
+7 130 13
+22 2 0
+22 2 0
+17 43 281
+23 6 0
+1593 1 1
+35 1 1
+171 0 1
+670 1 1
+20 1 1
+283 1 1
+24 1 1
+448 1 1
+18 1 1
+78 11 0
+46 1 1
+652 1 1
+30 1 1
+333 1 1
+56 1 1
+1209 22 44
+88 1 1
+21 1 1
+908 7 10
+114 26 26
+791 6 6
+286 1 1
+40 1 1
+623 4 0
+430 0 1
+423 8 8
+115 1 1
+23 1 1
+215 11 0
+27 0 5
+797 4 0
+95 15 15
+148 1 1
+141 2 0
+60 1 1
+692 1 0
+91 1 1
+31 1 1
+116 1 1
+24 1 1
+56 1 1
+99 3 0
+101 8 0
+273 1 1
+47 1 1
+1276 14 13
+169 1 1
+40 3 0
+119 1 1
+45 1 1
+466 1 1
+21 1 1
+572 8 8
+247 0 1
+290 0 1
+573 1 1
+27 1 1
+333 47 47
+2439 23 25
+654 1 1
+46 1 1
+78 8 8
+569 1 1
+57 1 1
+666 0 1
+502 1 1
+20 1 1
+347 9 9
+358 0 2
+13 1 1
+148 2 0
+134 1 1
+809 1 1
+47 1 1
+442 1 1
+43 1 1
+308 1 1
+54 1 1
+48 0 2
+152 5 0
+1137 1 1
+27 0 11
+575 1 0
+189 18 18
+490 25 25
+165 1 1
+26 1 1
+241 0 6
+75 1 1
+162 1 1
+1156 0 7
+248 0 4
+972 8 7
+177 0 1
+50 1 1
+1385 1 1
+30 1 1
+1048 1 1
+44 1 17
+690 6 7
+295 1 1
+36 1 1
+519 1 1
+26 1 1
+352 8 8
+204 1 1
+38 1 1
+580 7 7
+888 54 54
+183 18 18
+2465 16 16
+1454 10 10
+352 1 1
+49 1 1
+176 1 1
+32 11 11
+1717 1 1
+37 1 1
+127 1 1
+44 1 1
+275 1 1
+21 1 1
+349 9 9
+1977 1 1
+78 0 1
+8 0 1
+144 0 1
+335 46 46
+79 0 6
+10 1 1
+137 12 0
+99 1 1
+44 5 13
+31 1 1
+416 0 1
+177 0 6
+19 1 1
+372 2 2
+55 1 1
+256 0 6
+313 1 1
+43 1 1
+79 1 1
+20 1 1
+120 1 1
+38 0 8
+880 1 1
+24 1 1
+921 1 1
+40 1 1
+1358 0 4
+56 1 1
+1282 1 1
+34 1 1
+262 1 1
+43 1 1
+158 1 1
+33 1 1
+637 0 4
+1310 1 1
+26 1 1
+544 32 32
+496 1 1
+48 1 1
+3097 2 0
+145 1 1
+32 1 1
+152 0 3
+1117 1 1
+31 6 6
+416 1 1
+37 1 1
+293 0 14
+66 1 1
+48 1 1
+371 1 1
+41 1 1
+639 1 1
+49 1 1
+2092 10 13
+381 1 1
+39 5 5
+995 15 15
+165 0 12
+536 1 1
+43 1 1
+295 1 1
+35 1 1
+171 9 8
+831 20 20
+1980 12 0
+31 1 1
+389 1 1
+32 1 1
+414 20 0
+97 0 1
+835 6 0
+4305 1 1
+37 1 1
+191 1 1
+16 1 1
+227 1 1
+61 1 1
+257 1 1
+35 1 1
+946 1 1
+29 1 1
+710 1 1
+56 1 1
+534 2 0
+439 1 1
+58 1 1
+69 3 3
+43 1 1
+193 1 1
+15 1 1
+1032 1 4
+884 1 1
+30 1 1
+202 1 1
+43 1 1
+171 0 4
+163 0 1
+128 1 1
+43 1 1
+52 1 1
+20 1 1
+818 1 1
+45 1 1
+54 1 1
+42 1 1
+122 1 1
+28 1 1
+329 1 0
+163 1 1
+17 1 1
+442 1 1
+61 1 0
+695 0 1
+13 1 7
+54 1 1
+553 0 14
+360 5 5
+11641 3 7
+7822 1 0
+4105 0 8
+5193 0 1
+516 1 0
+3576 3 0
+825 1 1
+40 1 1
+738 1 1
+18 1 1
+989 0 5
+579 1 1
+19 1 1
+337 1 1
+42 55 0
+726 1 1
+99 1 2
+32 1 1
+932 1 1
+33 1 1
+234 33 33
+1101 1 1
+23 1 1
+345 0 1
+30 1 1
+111 17 17
+1395 1 0
+243 1 1
+29 4 5
+881 2 0
+465 0 1
+165 1 1
+87 1 1
+565 1 1
+10 1 1
+102 9 10
+176 1 1
+48 1 1
+499 1 1
+43 1 1
+263 0 8
+427 2 0
+75 1 1
+2053 1 1
+63 1 1
+744 32 32
+1706 1 1
+31 1 1
+829 12 0
+258 0 2
+433 1 1
+70 1 1
+137 2 0
+45 1 1
+664 11 11
+844 0 1
+440 1 1
+41 1 1
+760 1 6
+39 15 0
+757 1 1
+23 1 1
+137 1 1
+32 1 1
+246 9 9
+549 3 0
+1242 6 1
+200 1 0
+2306 1 1
+29 1 1
+197 2 0
+24 1 1
+1224 0 124
+61 1 1
+64 1 1
+3131 1 1
+116 1 1
+146 1 1
+34 1 1
+51 0 1
+805 1 1
+45 1 1
+579 15 15
+134 9 9
+1033 1 5
+147 1 1
+33 1 1
+118 29 29
+311 10 10
+1107 4 4
+3165 0 1
+122 1 1
+64 0 2
+29 1 1
+437 1 1
+39 1 1
+215 1 1
+78 1 1
+1953 3 3
+49 1 1
+745 1 1
+38 1 1
+881 0 4
+562 0 1
+956 1 1
+44 1 1
+685 1 1
+84 1 1
+380 1 1
+40 1 1
+182 0 4
+40 1 1
+877 13 13
+157 1 1
+50 1 1
+1282 0 1
+1612 17 37
+772 1 1
+70 1 1
+1866 0 2
+1406 16 15
+1398 1 0
+1112 1 1
+77 1 1
+1374 7 7
+751 5 5
+14 1 1
+239 6 6
+12 1 1
+189 0 1
+38 1 1
+144 1 1
+40 1 1
+1200 0 1
+758 0 1
+338 18 0
+15 10 0
+187 1 1
+90 1 1
+76 0 6
+611 6 131
+44 1 1
+221 5 0
+460 64 64
+488 15 15
+262 1 1
+45 1 1
+848 4 0
+75 8 8
+52 1 1
+31 1 1
+226 10 10
+437 1 1
+67 1 1
+115 1 1
+62 1 1
+60 13 13
+721 2 0
+164 1 1
+44 1 1
+395 1 1
+33 1 1
+260 13 13
+283 10 18
+600 1 1
+28 1 1
+100 18 18
+229 1 1
+47 1 1
+1672 1 1
+21 1 1
+1571 12 9
+101 1 1
+58 1 1
+706 11 11
+627 1 1
+16 1 1
+864 16 16
+200 1 1
+36 1 1
+676 1 1
+51 5 0
+2069 1 1
+32 1 1
+584 7 0
+271 1 1
+15 1 1
+435 0 1
+312 1 1
+38 0 3
+80 1 1
+32 0 12
+91 1 1
+34 1 1
+131 1 1
+35 1 1
+754 1 1
+44 2 2
+132 2 9
+174 3 1
+53 1 1
+213 2 0
+937 0 3
+720 1 1
+48 0 2
+32 12 0
+155 38 42
+692 9 2
+399 1 1
+54 0 1
+2625 1 1
+26 1 1
+584 0 5
+505 1 1
+43 1 1
+549 1 1
+23 1 1
+69 8 9
+123 1 1
+33 1 1
+651 1 1
+41 1 1
+141 4 4
+408 1 1
+30 1 1
+690 2 1
+78 4 4
+2106 8 4
+245 0 16
+802 1 1
+38 1 1
+607 1 1
+56 1 1
+358 0 1
+192 1 1
+45 1 1
+373 1 1
+82 1 1
+720 0 1
+161 1 1
+21 1 1
+187 7 6
+184 8 8
+760 6 6
+527 14 14
+94 4 4
+44 1 1
+455 7 0
+48 1 1
+89 1 1
+27 0 4
+38 1 1
+1571 1 1
+47 1 1
+81 1 1
+35 1 1
+161 4 0
+1244 0 2
+82 1 1
+67 0 4
+202 8 8
+351 9 9
+2130 1 0
+82 11 0
+397 0 1
+37 1 0
+315 1 1
+22 1 1
+1212 1 1
+60 1 1
+1847 1 1
+54 1 1
+362 7 7
+1065 3 0
+422 0 1
+3143 1 1
+33 1 1
+552 0 1
+822 1 0
+493 0 4
+26 1 1
+2435 1 1
+48 1 1
+3350 1 1
+17 1 1
+953 86 87
+509 0 1
+1811 1 1
+58 1 1
+1200 1 1
+55 4 0
+863 0 1
+284 1 1
+47 1 1
+2795 15 15
+2326 31 30
+2510 0 8
+1829 1 1
+40 1 1
+3584 58 90
+1937 29 28
+3805 14 14
+477 1 1
+25 1 1
+529 0 1
+918 1 2
+461 5 5
+102 9 10
+3603 18 18
+790 1 0
+797 881 2
+226 10 10
+52 4 4
+40 1 1
+128 5 5
+28 1 1
+50 14 11
+53 2 1
+1451 2 1
+119 1 1
+68 1 1
+164 0 2
+1257 1 1
+12 1 0
+42 1 1
+882 1 1
+47 1 1
+274 16 16
+82 1 1
+63 1 1
+100 11 11
+581 0 1
+60 1 1
+464 1 1
+29 1 0
+5 13 0
+23 1 1
+286 1 1
+38 0 2
+17 0 5
+108 6 0
+73 7 6
+105 1 1
+72 1 1
+115 1 1
+37 1 1
+86 1 1
+34 1 1
+143 28 25
+572 4 1
+114 3 0
+134 57 56
+836 0 1
+39 1 1
+1284 0 3
+858 2 1
+42 1 1
+795 1 0
+105 1 0
+343 3 0
+1040 0 3
+548 1 1
+67 1 1
+206 6 14
+830 0 1
+1490 10 10
+139 1 1
+29 0 1
+236 6 4
+217 1 1
+48 1 1
+578 0 1
+165 1 0
+59 9 9
+113 1 2
+294 0 3
+41 0 2
+126 1 1
+29 1 1
+393 7 7
+791 1 1
+51 1 0
+30 1 1
+110 21 11
+57 1 1
+64 1 1
+68 3 3
+58 1 1
+52 9 9
+63 1 1
+85 1 1
+72 1 1
+32 1 1
+315 13 13
+138 1 0
+1106 8 4
+923 12 12
+1310 1 0
+20 1 1
+307 18 15
+995 9 9
+71 1 1
+71 1 1
+85 6 1
+202 1 1
+57 1 1
+483 1 1
+57 1 2
+185 1 1
+17 1 1
+129 1 1
+34 0 2
+179 8 10
+175 1 1
+102 1 1
+154 220 220
+71 1 1
+62 1 1
+60 1 1
+164 7 7
+126 1 1
+19 1 1
+118 13 13
+126 1 1
+53 1 1
+67 4 4
+42 7 7
+54 1 1
+51 1 1
+139 13 14
+96 1 1
+19 1 1
+163 1 1
+33 1 1
+309 0 18
+38 1 1
+318 3 0
+70 4 0
+203 3 3
+30 1 1
+606 1 1
+22 1 0
+209 0 1
+520 1 0
+415 1 1
+51 1 1
+367 5 1
+16 0 8
+137 6 3
+290 0 4
+157 1 1
+79 1 1
+275 1 1
+14 4 0
+69 1 1
+215 1 1
+7 1 0
+7 1 4
+33 1 1
+169 1 1
+101 1 1
+78 1 1
+41 3 3
+364 0 2
+577 34 29
+268 60 60
+60 47 47
+133 8 8
+68 2 0
+172 2 3
+162 30 30
+186 3 8
+235 58 58
+64 16 12
+138 24 17
+112 246 235
+51 56 56
+146 18 18
+206 49 49
+267 18 18
+152 1 1
+18 1 1
+63 13 1
+235 6 5
+209 1 1
+24 4 0
+53 1 1
+73 29409 0
+126 1 1
+85 1 1
+76 3 3
+159 1 0
+29 11 11
+72 8 8
+496 9 9
+202 1 1
+90 1 1
+692 1 1
+27 1 1
+111 0 10
+89 1 1
+33 1 1
+153 3268 0
+205 0 3
+50 3 0
+605 6 6
+59 16 16
+136 1 1
+28 1 1
+417 1 1
+17 1 1
+70 10 10
+259 1 1
+37 0 1
+352 1 1
+40 1 1
+814 1 1
+80 1 1
+125 11 11
+137 1 1
+82 1 1
+408 1 1
+56 1 1
+367 1 0
+26 1 1
+390 185277 11600
+75 2 0
+81 1 1
+175 1 1
+23 1 1
+56 1 1
+37 3 0
+55 1 1
+248 3 0
+74 2 0
+139 1 1
+26 1 1
+131 1 1
+32 5 9
+246 3 5
+53 0 4
+22 5 0
+71 0 1
+255 1 1
+189 1 1
+121 1 1
+149 1 1
+65 1 1
+322 1 1
+36 17 5
+27 4 0
+39 1 1
+346 15 1
+48 0 1
+148 1 1
+57 1 1
+38 1 1
+653 1 0
+213 1 1
+35 1 1
+60 1 1
+72 1 1
+71 6 6
+76 1 1
+73 5 5
+114 1 1
+92 1 1
+145 1 1
+108 1 1
+54 0 2
+82 11 11
+303 0 4
+149 23 23
+57 1 1
+57 1 1
+485 1 1
+64 1 1
+112 1 1
+19 1 1
+226 1 1
+70 0 1
+83 1 1
+60 1 0
+28 1 1
+1629 34 1
+5621 0 12
+37 1 1
+1691 14 14
+151 10 10
+58 1 1
+91 0 2
+149 1 1
+57 1 1
+72 1 1
+932 1 1
+21 1 1
+732 1 1
+24 1 1
+438 1 1
+17 1 1
+1100 146 145
+189 18 18
+1079 1 1
+37 1 1
+69 10 1
+241 1 1
+23 1 1
+247 1 1
+48 1 1
+3441 1 1
+18 1 1
+491 0 1
+250 12 8
+108 1 1
+37 1 2
+339 1 1
+36 1 1
+1289 4 4
+406 9 9
+579 1 1
+37 1 1
+282 2 0
+6 12 0
+42 1 1
+55 1 1
+36 1 1
+396 54 54
+1355 2 0
+101 0 1
+149 1 1
+25 1 1
+611 1 1
+60 1 1
+224 20 0
+60 1 1
+398 0 2
+819 1 1
+48 1 1
+233 1 0
+459 6 6
+1131 10 10
+129 791 450
+41 119 117
+102 14 24
+16 1 1
+379 11 10
+240 1 1
+49 1 1
+203 1 1
+96 1 1
+50 896 15
+110 1 1
+59 1 1
+387 10 10
+157 1 1
+126 1 1
+60 1 1
+86 1 1
+124 1 1
+118 1 1
+160 3 1
+82 1 1
+64 0 1
+59 1 1
+235 1 1
+43 1 1
+126 45 34
+50 0 27
+37 0 2
+74 1 1
+69 13484 10061
+60 44 44
+112 244 248
+256 4076 10878
+54 1 1
+18 0 1
+10 1 1
+76 1 1
+36 1 1
+130 1 1
+25 1 1
+85 2 2
+21 1 0
+67 1 1
+32 1 1
+162 1 1
+23 1 1
+453 10 10
+396 5 0
+82 1 1
+397 0 1
+89 3 0
+40 1 1
+157 1 1
+43 0 8
+146 1 1
+38 1 1
+101 1 1
+33 7 1
+53 1 1
+41 1 1
+60 25 18
+60 1 1
+25 1 1
+80 1 1
+31 1 1
+88 8 7
+24 1 1
+417 0 1
+42 1 1
+122 1 1
+72 5 5
+88 1 1
+36 1 1
+495 14 14
+278 3 3
+48 1 1
+50 11 0
+147 1 1
+87 1 1
+67 1 1
+788 8 0
+51 1 1
+37 1 1
+107 1 1
+22 1 1
+290 1 0
+58 3 3
+804 12 12
+133 5 0
+34 0 8
+116 1 1
+592 112 115
+93 0 1
+84 1 1
+22 1 1
+188 1 1
+46 1 0
+10 1 0
+375 6 6
+117
+
+chain 13264711 chr17_ctg5_hap1 1680828 + 0 1680828 chr17 78774742 + 40740646 42268630 76
+1491 0 1
+105829 1 0
+7 1 0
+38 1 0
+39 0 3
+1127 2 0
+399 1 1
+36 1 1
+1284 2 0
+96 1 1
+18 1 1
+402 0 1
+1243 1 17
+1187 1 1
+93 2 2
+135 1 0
+1300 1 0
+970 1 1
+33 1 1
+1390 1 1
+32 0 1
+1238 11 11
+1231 1 0
+4784 7 7
+1610 0 43
+312 0 20
+4544 1 1
+80 1 1
+5233 1 1
+31 1 1
+1582 0 4
+606 1 0
+1781 1 0
+183 14 16
+1226 6 0
+3095 1 1
+81 1 1
+4769 1 0
+4452 3 3
+41 1 1
+1401 1 1
+34 1 1
+1154 1 1
+28 1 1
+2549 12 12
+2173 2 0
+2280 1 1
+38 1 3
+2217 0 1
+498 0 1
+93 1 1
+22 1 1
+1950 0 2
+66 0 2
+1228 8 5
+1593 0 1
+468 1 1
+21 0 1
+170 10 0
+794 0 8
+1870 8 2
+3575 2 2
+43 1 1
+244 13 13
+611 5 5
+4057 4 1
+721 0 1
+1373 0 3
+28 1 1
+1422 1 0
+788 2 0
+584 188 188
+30 1152 1152
+40 270 270
+53 62 62
+87 227791 12647
+23 8319 12304
+52 449 449
+41 17972 13320
+26 114 119
+50 2682 2667
+31 1087 1088
+42 10911 10903
+41 76 76
+35 287 287
+93 1272 1285
+4834 34 1
+1629 1 1
+28 0 1
+59 1 1
+83 0 1
+25 1 1
+271 1 1
+19 1 1
+112 1 1
+64 1 1
+485 1 1
+57 1 1
+57 23 23
+144 0 4
+308 11 11
+82 0 2
+54 1 1
+70 1 1
+37 1 1
+145 1 1
+92 1 1
+114 5 5
+73 1 1
+76 6 6
+71 1 1
+72 1 1
+60 1 1
+35 1 1
+208 1 0
+658 1 1
+38 1 1
+57 1 1
+148 0 1
+48 14 1
+238 1 1
+34 1 1
+72 1 1
+39 4 0
+27 17 5
+36 1 1
+322 1 1
+65 1 1
+149 1 1
+121 1 1
+189 14 14
+54 1 1
+187 0 1
+71 5 0
+22 0 4
+53 3 5
+246 5 9
+32 1 1
+131 1 1
+26 1 1
+139 2 0
+74 3 0
+248 1 1
+70 3 0
+22 1 1
+56 1 1
+23 1 1
+175 1 1
+81 2 0
+75 32 32
+220 14 13
+196 178 178
+126 28 22
+332 8 8
+98 35 35
+82 0 1
+246 10 10
+80 24 21
+105 4 4
+104 18 20
+52 22 22
+224 6 6
+62 174 173
+149 6 9
+188 4 0
+164 0 1
+157 1 1
+264 8 0
+51 0 1
+5 0 1
+5 1 0
+32 1 1
+262 1 1
+42 1 1
+59 1 1
+68 1 1
+277 1 1
+48 1 1
+52 1 1
+30 4 4
+92 1 1
+40 1 1
+164 1 1
+34 1 1
+249 5 5
+70 5 5
+145 1 1
+55 1 1
+56 0 1
+38 1 1
+96 0 3
+143 1 1
+146 1 1
+158 15 15
+775 8 0
+80 1 1
+38 1 1
+556 1 1
+44 1 1
+79 1 0
+44 1 1
+86 4 4
+121 1 1
+13 0 1
+13 1 1
+203 1 1
+44 1 1
+567 1 0
+384 1 1
+43 1 1
+576 0 2
+167 1 1
+698 1 1
+41 1 1
+207 2 0
+342 0 1
+113 1 1
+595 13 13
+666 1 1
+19 1 1
+471 1 1
+25 1 1
+327 1 1
+36 1 1
+549 0 16
+83 17 17
+149 1 1
+40 1 1
+206 1 1
+48 1 1
+96 0 1
+87 1 1
+83 1 1
+130 1 1
+350 1 1
+17 1 1
+141 1 1
+45 1 0
+210 0 4
+428 13 13
+135 1 0
+555 8 0
+29 1 1
+108 1 1
+67 1 1
+481 2 0
+575 4 4
+10 0 3
+28 1 1
+55 4 4
+125 0 9
+59 3 3
+73 8 8
+146 1 1
+203 1 1
+132 1 1
+71 48592 13305
+71 3382 3374
+25 5834 5854
+89 1 1
+9 10000 10418
+20 1 1
+40 0 4
+13 1 1
+3 602540 600615
+450 1 1
+71 1 1
+126 4 0
+131 2 2
+95 7526 7516
+28 827 819
+39 10 10
+8 19785 19984
+220 7353 7908
+33 269 269
+60 61 61
+46 547 550
+30 424 423
+57 355 353
+45 1 1
+108 46 38
+46 51 51
+56 371 371
+48 1139 1133
+154 7 7
+118 1 1
+28 1 1
+69 1 1
+80 2 1
+56 0 3
+50 1 1
+40 1 1
+47 0 1
+176 8 8
+35 1 1
+86 1 1
+19 0 7
+57 1 1
+179 1 1
+53 1 1
+64 1 1
+39 1 1
+93 2 2
+138 0 2
+402 3 5
+350 1 1
+18 1 1
+413 8 4
+297 7 0
+273 5 0
+96 1 1
+17 1 1
+241 0 1
+593 4 0
+50 1 1
+179 30 0
+8 0 2
+6 0 1
+27 6 0
+7 1 15
+77 51 25
+119 16 15
+89 1 1
+36 5 5
+156 23 23
+66 1 1
+20 1 1
+785 62 62
+118 1 1
+97 1 1
+84 1 1
+53 2 2
+141 0 12
+60 1 1
+47 1 1
+67 1 1
+61 1 1
+61 2 0
+64 1 1
+160 1 12
+1118 3 3
+54 9 31
+96 1 1
+20 1 1
+55 1 1
+23 1 1
+260 12 12
+134 13 13
+447 5 5
+659 1 1
+76 1 1
+57 1 1
+30 1 1
+150 11 0
+11 3 0
+85 1 1
+82 0 3
+128 1 1
+83 1 1
+35 0 2
+17 1 1
+157 0 1
+5 0 2
+14 3 3
+177 1 1
+32 1 1
+355 1 1
+25 1 0
+26 0 2
+77 1 1
+31 1 1
+190 1 1
+34 1 1
+77 15 15
+79 12 14
+200 17 17
+721 1 1
+35 1 1
+247 1 1
+44 1 1
+107 1 1
+52 1 1
+391 19 23
+467 18 19
+535 1 1
+30 1 1
+54 1 2
+55 3 3
+22 2 2
+348 1 1
+34 1 1
+429 4 0
+66 8 8
+298 1 1
+56 1 1
+316 5 5
+71 1 1
+11 10 0
+31 12 0
+90 1 1
+16 1 4457
+76 1 1
+48 1 1
+66 4 5
+164 1 0
+354 1 1
+46 1 1
+779 19 19
+189 1 1
+45 1 1
+477 9 9
+180 1 0
+305 1 1
+20 1 1
+247 9 10
+131 5 5
+1115 1 1
+43 1 1
+98 0 1
+27 1 1
+152 15 15
+295 1 1
+18 1 1
+110 1 1
+49 1 1
+129 1 1
+34 1 1
+93 1 1
+91 1 1
+318 6 6
+112 4 4
+31 7 0
+150 0 2
+130 1 1
+19 1 1
+747 8 8
+708 9 9
+295 0 1
+25 1 1
+320 1 1
+26 1 1
+302 1 0
+45 15 0
+14 1 1
+75 1 1
+26 1 1
+494 1 1
+19 1 1
+267 11 11
+95 1 1
+15 4 0
+84 7 7
+87 206984 212276
+34 11226 11239
+62 1 1
+82 9866 9856
+54 5848 5823
+791 41 41
+31 1 1
+47 1 1
+39 1165 1166
+864 1 1
+31 2021 2021
+8 0 8
+37 259 273
+434 1 0
+1376 9 7
+578 14 5
+814 6 5
+638 0 1
+416 1 1
+49 1 1
+5436 0 6
+3224 0 1
+352 1 1
+31 10 0
+65 60 60
+44 112 112
+244 256 256
+1152 1 0
+773 0 5
+2150 2914 2914
+7 0 1
+18 5377 5375
+112 946 946
+2705 0 2
+1072 1 1
+30 1 1
+126 0 1
+1278 0 2
+1963 1 0
+706 0 9
+89 1 29
+428 0 3
+306 0 14
+149 1 1
+22 1 1
+1153 1 0
+877 14 12
+1014 1 1
+49 1 1
+3485 1 0
+2740 1 1
+27 4 0
+238 1 1
+48 1 1
+385 6 0
+1355 1 1
+27 2 2
+1020 10 0
+2311 0 2
+646 0 2
+8446 1 0
+1582 3 4
+2031 1 0
+1347 0 4
+939 1 1
+82 1 1
+2216 0 12
+806 0 4
+3009 7 0
+73 1 1
+37 1 1
+88 79 85
+2100 2 0
+804 1 1
+31 1 1
+56 1 0
+531 0 1
+3255 0 17
+119 16 16
+2727 0 5
+1516 1 0
+88 1 1
+31 1 1
+2085 0 1
+2381 3 0
+988 0 1
+1138 2 2
+37 1 1
+3015 12 0
+3465 1 1
+30 1 1
+1220 54 43
+3519 0 1
+4735 1 0
+1246 0 4
+257 1 0
+919 0 5
+811 53 53
+5990 0 1
+369 0 4
+1080 50000 139273
+41860
+
+chain 2227376 chr17_ctg5_hap1 1680828 + 1397503 1425444 chr17 78774742 + 41665512 41694673 1168
+810 6 0
+20 1 0
+396 1 0
+77 1 1
+160 1 1
+198 18 18
+170 1 0
+835 7 0
+178 0 1
+512 1 1
+18 0 1
+91 1 1
+41 5 4
+205 1 1
+46 1 1
+313 1 0
+195 1 1
+34 1 1
+81 114 114
+158 1 1
+29 5 0
+216 7 0
+202 0 724
+357 0 2
+36 1 1
+281 25 26
+94 1 1
+45 1 0
+56 1 1
+102 5 0
+286 8 9
+1295 1 1
+110 1 1
+117 0 5
+157 16 16
+272 1 1
+26 2 0
+277 6 6
+193 4 4
+153 1 9
+20 1 1
+1068 8 4
+216 2 0
+224 9 0
+383 21 0
+79 1 1
+361 1 1
+25 1 1
+1006 1 1
+62 1 1
+60 15 15
+107 12 14
+73 0 3
+33 0 4
+890 73 73
+139 0 5
+826 5 0
+366 0 2
+187 0 2
+175 146 146
+739 20 20
+205 13 13
+355 45 45
+160 0 1
+617 0 15
+366 28 27
+202 111 110
+154 52 52
+368 997 1615
+183 2 2
+449 4 0
+108 17 0
+162 0 2
+93 1 1
+31 0 1
+149 9 9
+69 11 11
+275 1 1
+14 0 4
+120 1 1
+115 1 1
+76 2 1
+121 1 1
+72 1 1
+88 3 3
+68 1 1
+96 57 1
+229 1 1
+21 0 1
+25 2 0
+112 2 2
+84 5 0
+75 3 3
+171 66 65
+113 18 18
+348 81 73
+67 44 44
+67 16 19
+149 0 3
+72 36 36
+123 92 91
+67 297 297
+178 433 428
+365 20 20
+130 51 51
+302 17 17
+62 20 20
+316 1 0
+138 37 25
+75 5 9
+267 7 7
+118 30 30
+69 92 92
+99 42 42
+47 0 1
+113
+
+chain 1902497 chr17_ctg5_hap1 1680828 + 1349157 1369929 chr17 78774742 - 37173234 37193985 1316
+1852 2 0
+9 8 8
+283 11 0
+34 0 1
+190 1 0
+3 2 0
+457 2 0
+106 1 1
+28 1 1
+144 4 0
+2112 6 6
+1530 1 1
+27 1 1
+123 1 0
+171 0 8
+504 5 6
+2360 1 1
+19 1 0
+1463 10 0
+471 36 36
+785 32 32
+412 0 3
+1217 32 32
+1308 28 26
+1339 13 13
+311 29 33
+733 22 22
+62 2 0
+251 11 11
+799 0 7
+97 3 0
+324 4 0
+473 46 46
+459
+
+chain 1776951 chr17_ctg5_hap1 1680828 + 1329556 1349123 chr17 78774742 - 37153638 37173199 1401
+128 0 1
+918 0 1
+530 2 0
+20 1 1
+129 1 0
+249 0 1
+279 4 0
+12 4 0
+26 4 0
+614 16 16
+179 4 0
+610 2 0
+646 28 35
+276 0 1
+1341 1 0
+360 1 1
+39 1 1
+467 1 1
+23 1 1
+633 6 6
+309 1 1
+27 0 2
+627 5 0
+1032 8 8
+226 1 1
+17 1 1
+385 5 4
+125 22 23
+301 14 0
+199 1 1
+26 1 1
+53 1 1
+33 1 1
+304 3 0
+1345 0 16
+944 72 72
+115 82 91
+248 14 14
+558 0 1
+750 1 0
+1083 69 69
+1136 0 2
+82 22 16
+836 0 4
+926
+
+chain 893264 chr17_ctg5_hap1 1680828 + 1372124 1381789 chr17 78774742 - 37196506 37206183 4351
+35 1 1
+343 27 25
+861 0 10
+298 0 4
+92 6 6
+784 0 5
+2089 1 0
+940 1 0
+304 2 0
+1246 1 0
+168 2 0
+171 1 0
+32 1 1
+1110 14 14
+833 0 4
+155 1 0
+146
+
+chain 666279 chr17_ctg5_hap1 1680828 + 1381822 1393172 chr17 78774742 + 60348942 60360296 7820
+119 36 36
+84 52 49
+205 29 29
+190 52 58
+180 57 57
+51 14 14
+312 54 54
+55 16 16
+52 88 88
+203 0 5
+250 22 25
+110 147 149
+328 217 214
+84 88 88
+79 39 39
+231 67 53
+89 16 17
+62 15 15
+187 47 51
+315 45 45
+78 214 214
+360 182 184
+116 67 67
+75 70 75
+106 18 20
+98 95 95
+54 19 19
+292 76 76
+171 87 87
+338 28 28
+98 78 75
+53 77 77
+51 62 62
+118 32 32
+192 39 39
+52 62 62
+175 44 44
+195 97 97
+75 173 173
+154 50 50
+125 17 17
+71 57 59
+92 12 12
+303 164 166
+258 424 419
+69 123 123
+345 40 39
+240 14 14
+128 87 86
+73
+
+chain 416007 chr17_ctg5_hap1 1680828 + 1245181 1252036 chr17 78774742 + 60351908 60358760 108741
+51 63 63
+229 10 10
+151 43 37
+58 47 48
+62 20 20
+152 91 97
+163 9 9
+305 11 11
+75 57 57
+75 6 6
+295 59 59
+64 15 17
+160 30 30
+112 70 75
+96 28 30
+98 95 95
+54 63 63
+249 75 75
+324 49 49
+113 42 41
+69 28 28
+98 78 75
+53 77 77
+51 62 62
+342 39 39
+52 62 62
+173 28 28
+82 49 49
+82 94 94
+78 209 203
+52 122 122
+206 100 102
+341 71 71
+53 44 44
+82 29 24
+180
+
+chain 246453 chr17_ctg5_hap1 1680828 + 1237068 1240267 chr9 140273252 + 109577466 109580401 401240
+805 41 1
+100 1 1
+90 49 0
+45 176 0
+349 1 1
+67 1 50
+65 127 0
+114 1 1
+48 1 1
+139 98 1
+58 1 0
+53 1 1
+94 1 178
+186 1 1
+21 2 2
+463
+
+chain 239377 chr17_ctg5_hap1 1680828 + 1312949 1315506 chr17 78774742 - 37137002 37139560 429566
+798 1 0
+565 0 1
+1034 0 1
+159
+
+chain 228096 chr17_ctg5_hap1 1680828 + 1321688 1324178 chr17 78774742 - 37145748 37148235 477585
+1787 39 36
+563 23 23
+78
+
+chain 196783 chr17_ctg5_hap1 1680828 + 1369959 1372123 chr17 78774742 - 37194027 37196505 622087
+666 41 355
+857 1 1
+25 1 1
+573
+
+chain 176658 chr17_ctg5_hap1 1680828 + 1325052 1326989 chr17 78774742 - 37149126 37151061 719570
+150 2 0
+143 37 37
+1605
+
+chain 168141 chr17_ctg5_hap1 1680828 + 711752 714062 chr16 88827254 + 28616023 28618285 762738
+361 1 1
+33 1 1
+130 127 0
+96 1 0
+50 19 19
+119 49 0
+110 1 2
+9 48 0
+90 98 0
+72 11 325
+56 14 14
+246 40 0
+212 17 17
+299
+
+chain 154508 chr17_ctg5_hap1 1680828 + 1307063 1308700 chr17 78774742 - 37131110 37132746 835029
+145 1 0
+1491
+
+chain 148102 chr17_ctg5_hap1 1680828 + 1232106 1430374 chr17 78774742 - 18425735 18434371 621
+4 1 1
+60 1 1
+112 0 1
+97 1 1
+125 2 0
+21 2 2
+61 1 1
+74 1 1
+73 1 1
+34 1 1
+300 1 1
+38 1 1
+80 12 12
+97 8 0
+29 2 2
+185 4 0
+515 2 0
+42 4 4
+430 190939 1320
+75 1 1
+18 1 1
+338 6 6
+61 1 0
+467 12 12
+451 1 0
+100 1 1
+50 1 1
+27 1 1
+132 0 2
+233 1 1
+37 1 1
+50 0 3
+469 1 1
+37 1 1
+94 1 1
+36 1 1
+125 4 4
+132 0 2
+39 1 1
+213 12 12
+184 3 0
+52 1 1
+16 1 1
+159 1 1
+19 2 2
+686 10 10
+230 15 15
+296
+
+chain 145367 chr17_ctg5_hap1 1680828 + 1327932 1329549 chr17 78774742 - 37151994 37153631 887940
+554 56 76
+1007
+
+chain 137569 chr17_ctg5_hap1 1680828 + 1309956 1311426 chr17 78774742 - 37134002 37135486 937317
+68 0 14
+1402
+
+chain 110156 chr17_ctg5_hap1 1680828 + 1320345 1321641 chr17 78774742 - 37144406 37145701 1161060
+640 31 31
+224 12 12
+204 52 51
+133
+
+chain 108079 chr17_ctg5_hap1 1680828 + 1315884 1317028 chr17 78774742 - 37139952 37141098 1182036
+885 0 2
+259
+
+chain 107213 chr17_ctg5_hap1 1680828 + 216004 477608 chr17 78774742 - 36300720 36848371 128
+48 7751 7515
+31 3 3
+10 52129 338773
+71 29976 29992
+37 2872 2872
+132 77377 77001
+50 9950 9939
+49 15970 16004
+80 5205 5206
+35 2373 2374
+35 2111 2102
+28 13945 13928
+281 29828 29826
+34 8713 8715
+32 430 430
+178 126 126
+28 438 438
+35 1039 1039
+174
+
+chain 88256 chr17_ctg5_hap1 1680828 + 1254762 1255800 chr17 78774742 - 37066345 37067387 1434130
+467 19 23
+391 54 54
+107
+
+chain 84535 chr17_ctg5_hap1 1680828 + 1416653 1417623 chr17 78774742 - 37747883 37748853 1275488
+209 0 1
+520 1 0
+240
+
+chain 83787 chr17_ctg5_hap1 1680828 + 1255846 1256794 chr17 78774742 - 37067433 37068381 1508032
+247 37 37
+664
+
+chain 81881 chr17_ctg5_hap1 1680828 + 1394662 1395623 chr17 78774742 - 37062220 37063176 1542051
+178 0 4
+127 43 43
+207 27 18
+379
+
+chain 78522 chr17_ctg5_hap1 1680828 + 1324178 1325052 chr17 78774742 - 37148244 37149121 1606324
+554 0 3
+200 43 43
+77
+
+chain 75262 chr17_ctg5_hap1 1680828 + 1317476 1318285 chr17 78774742 - 37141533 37142347 1673849
+255 0 5
+554
+
+chain 72597 chr17_ctg5_hap1 1680828 + 1318474 1319252 chr17 78774742 - 37142532 37143313 1734349
+618 0 3
+160
+
+chain 68786 chr17_ctg5_hap1 1680828 + 1312168 1312905 chr17 78774742 - 37136222 37136958 1829107
+216 1 0
+520
+
+chain 66138 chr17_ctg5_hap1 1680828 + 458426 496420 chr17 78774742 + 60323662 60348977 381
+29 102 102
+150 0 2
+92 35229 22555
+47 1 1
+72 0 3
+361 0 1
+361 1 1
+59 1 1
+79 1 1
+12 4 0
+22 8 0
+164 1 1
+29 8 0
+22 1 1
+166 1 1
+38 1 1
+167 0 3
+68 1 1
+61 1 1
+34 0 19
+130 1 1
+61 2 2
+22 7 0
+118 7 0
+90 0 1
+162
+
+chain 63091 chr17_ctg5_hap1 1680828 + 1252401 1253149 chr17 78774742 - 37063986 37064734 1993873
+71 5 5
+316 58 58
+298
+
+chain 58162 chr17_ctg5_hap1 1680828 + 1254067 1254744 chr17 78774742 - 37065648 37066326 2166241
+55 1 2
+54 32 32
+535
+
+chain 54716 chr17_ctg5_hap1 1680828 + 1319283 1319868 chr17 78774742 - 37143347 37143930 2309300
+443 2 0
+140
+
+chain 54428 chr17_ctg5_hap1 1680828 + 1396409 1397035 chr17 78774742 - 37063962 37064589 2322100
+416 38 39
+172
+
+chain 53306 chr17_ctg5_hap1 1680828 + 1327031 1327602 chr17 78774742 - 37151103 37151673 2373745
+61 1 0
+509
+
+chain 45719 chr17_ctg5_hap1 1680828 + 1253157 1253656 chr17 78774742 - 37064742 37065237 2803981
+63 4 0
+432
+
+chain 44822 chr17_ctg5_hap1 1680828 + 1308965 1309441 chr17 78774742 - 37133014 37133490 2867866
+476
+
+chain 44716 chr17_ctg5_hap1 1680828 + 1309483 1309955 chr17 78774742 - 37133530 37134002 2875759
+472
+
+chain 42970 chr17_ctg5_hap1 1680828 + 1249019 1250432 chr17 78774742 - 37056169 37057582 957875
+28 98 98
+37 9 10
+32 53 53
+77 51 51
+55 349 348
+39 52 52
+47 9 9
+6 173 173
+28 82 82
+49 82 82
+57
+
+chain 39900 chr17_ctg5_hap1 1680828 + 1311434 1311858 chr17 78774742 - 37135495 37135919 3282293
+424
+
+chain 36548 chr17_ctg5_hap1 1680828 + 1397076 1397503 chr17 78774742 - 37727818 37728245 1867431
+351 31 31
+45
+
+chain 35186 chr17_ctg5_hap1 1680828 + 1319971 1320341 chr17 78774742 - 37144033 37144403 3815477
+370
+
+chain 32846 chr17_ctg5_hap1 1680828 + 1253692 1254040 chr17 78774742 - 37065273 37065621 4148877
+348
+
+chain 32058 chr17_ctg5_hap1 1680828 + 1394126 1394519 chr17 78774742 - 37061682 37062075 4275850
+85 42 42
+266
+
+chain 30381 chr17_ctg5_hap1 1680828 + 343779 344098 chr13 114142980 + 60207729 60208048 4580555
+319
+
+chain 29004 chr17_ctg5_hap1 1680828 + 1317078 1317414 chr17 78774742 - 37141148 37141484 5128137
+110 17 17
+209
+
+chain 28739 chr17_ctg5_hap1 1680828 + 1393298 1393613 chr17 78774742 - 37060859 37061169 5278988
+151 5 0
+159
+
+chain 28608 chr17_ctg5_hap1 1680828 + 1381941 1384110 chr17 78774742 - 37049506 37051670 737272
+33 87 87
+3 16 17
+33 205 205
+29 190 190
+52 180 180
+57 377 361
+54 123 123
+34 639 649
+57
+
+chain 27290 chr17_ctg5_hap1 1680828 + 1250687 1251236 chr17 78774742 - 37057837 37058386 1723424
+69 52 52
+122 206 206
+100
+
+chain 23334 chr17_ctg5_hap1 1680828 + 1315561 1315806 chr17 78774742 - 37139619 37139864 8092879
+245
+
+chain 22172 chr17_ctg5_hap1 1680828 + 1247931 1248795 chr17 78774742 - 37055081 37055945 1359053
+50 54 54
+63 249 249
+75 324 324
+49
+
+chain 21861 chr17_ctg5_hap1 1680828 + 1311933 1312163 chr17 78774742 - 37135987 37136217 9092092
+230
+
+chain 20267 chr17_ctg5_hap1 1680828 + 1388625 1389065 chr17 78774742 - 37056169 37056610 1819714
+28 98 98
+37 9 10
+32 53 53
+77 51 51
+55
+
+chain 19257 chr17_ctg5_hap1 1680828 + 1251577 1252102 chr17 78774742 - 37058727 37059253 2345365
+71 53 53
+44 82 82
+24 1 0
+4 180 182
+66
+
+chain 18858 chr17_ctg5_hap1 1680828 + 1395798 1396023 chr17 78774742 - 37063364 37063589 11391766
+69 17 17
+139
+
+chain 17539 chr17_ctg5_hap1 1680828 + 1306794 1306981 chr17 78774742 - 37130913 37131100 12530835
+187
+
+chain 17362 chr17_ctg5_hap1 1680828 + 1327740 1327921 chr17 78774742 - 37151802 37151983 12688794
+181
+
+chain 16114 chr17_ctg5_hap1 1680828 + 1386775 1387126 chr17 78774742 - 37054317 37054668 3847861
+129 155 155
+67
+
+chain 14712 chr17_ctg5_hap1 1680828 + 1471572 1581528 chr17 78774742 + 41752645 41862594 227
+27 72594 72528
+20 0 36
+59 37204 37227
+3 1 1
+48
+
+chain 14021 chr17_ctg5_hap1 1680828 + 1391766 1393099 chr17 78774742 - 37059329 37060660 1551546
+50 88 88
+58 1094 1092
+43
+
+chain 13718 chr17_ctg5_hap1 1680828 + 1245232 1246117 chr17 78774742 - 37052388 37053271 1534336
+63 390 390
+37 2 0
+4 339 339
+50
+
+chain 13678 chr17_ctg5_hap1 1680828 + 1387543 1388241 chr17 78774742 - 37055086 37055784 1538578
+45 365 365
+76 171 171
+41
+
+chain 13678 chr17_ctg5_hap1 1680828 + 1386064 1386301 chr17 78774742 - 37053606 37053843 4358174
+45 78 78
+49 4 4
+61
+
+chain 12960 chr17_ctg5_hap1 1680828 + 1390153 1390290 chr17 78774742 - 37057697 37057834 10954124
+137
+
+chain 12859 chr17_ctg5_hap1 1680828 + 712690 713529 chr13 114142980 - 94890835 94891950 786174
+26 1 277
+22 258 82
+37 49 0
+12 399 624
+35
+
+chain 11529 chr17_ctg5_hap1 1680828 + 1327611 1327733 chr17 78774742 - 37151673 37151795 19785711
+122
+
+chain 11334 chr17_ctg5_hap1 1680828 + 1238199 1238375 chr13 114142980 + 19251561 19251738 585429
+101 4 5
+56 1 1
+14
+
+chain 11041 chr17_ctg5_hap1 1680828 + 1384528 1384669 chr17 78774742 - 37052089 37052230 4204331
+1 58 58
+82
+
+chain 10878 chr17_ctg5_hap1 1680828 + 1393633 1393747 chr17 78774742 - 37061189 37061303 20959654
+114
+
+chain 10460 chr17_ctg5_hap1 1680828 + 1396115 1396225 chr17 78774742 - 37063682 37063792 21801362
+110
+
+chain 10352 chr17_ctg5_hap1 1680828 + 1391207 1391342 chr17 78774742 - 37058757 37058894 7784932
+37 10 12
+88
+
+chain 9842 chr17_ctg5_hap1 1680828 + 1308830 1308934 chr17 78774742 - 37132877 37132981 23170572
+104
+
+chain 9287 chr17_ctg5_hap1 1680828 + 1318326 1318424 chr17 78774742 - 37142388 37142486 24449821
+98
+
+chain 8968 chr17_ctg5_hap1 1680828 + 1389414 1389567 chr17 78774742 - 37056958 37057111 4148137
+39 52 52
+47 9 9
+6
+
+chain 8877 chr17_ctg5_hap1 1680828 + 1252246 1252339 chr17 78774742 - 37063853 37063946 25134532
+93
+
+chain 8768 chr17_ctg5_hap1 1680828 + 1393172 1393264 chr17 78774742 - 37060733 37060825 25011976
+92
+
+chain 8158 chr17_ctg5_hap1 1680828 + 1393848 1393933 chr17 78774742 - 37061404 37061489 26172124
+85
+
+chain 7594 chr17_ctg5_hap1 1680828 + 1416023 1416258 chr17 78774742 - 37747254 37747489 2219812
+29 154 154
+52
+
+chain 7515 chr17_ctg5_hap1 1680828 + 1389981 1390060 chr17 78774742 - 37057525 37057604 6485868
+79
+
+chain 7285 chr17_ctg5_hap1 1680828 + 1252152 1252228 chr17 78774742 - 37059303 37059379 27632598
+76
+
+chain 6684 chr17_ctg5_hap1 1680828 + 1308721 1308790 chr17 78774742 - 37132768 37132837 28870693
+69
+
+chain 6515 chr17_ctg5_hap1 1680828 + 1247168 1247482 chr17 78774742 - 37054317 37054631 3599890
+45 239 239
+30
+
+chain 6497 chr17_ctg5_hap1 1680828 + 1387201 1387271 chr17 78774742 - 37054743 37054813 5969263
+70
+
+chain 6494 chr17_ctg5_hap1 1680828 + 1396307 1396375 chr17 78774742 - 37063872 37063940 29322189
+68
+
+chain 6058 chr17_ctg5_hap1 1680828 + 1315820 1315884 chr17 78774742 - 37139877 37139941 30402031
+64
+
+chain 5566 chr17_ctg5_hap1 1680828 + 218263 246046 chr17 78774742 + 60300789 60329221 713
+35 27719 28368
+29
+
+chain 5502 chr17_ctg5_hap1 1680828 + 1238858 1238932 chr5 180857866 - 146515862 146515936 441292
+74
+
+chain 5265 chr17_ctg5_hap1 1680828 + 1247608 1247664 chr17 78774742 - 37054757 37054813 15861596
+56
+
+chain 5130 chr17_ctg5_hap1 1680828 + 1393995 1394049 chr17 78774742 - 37061551 37061605 33050310
+54
+
+chain 4602 chr17_ctg5_hap1 1680828 + 1415941 1415989 chr17 78774742 - 37747172 37747220 10895303
+48
+
+chain 4584 chr17_ctg5_hap1 1680828 + 1237882 1239358 chr3 199501827 + 130155920 130156866 476764
+32 1412 882
+32
+
+chain 4558 chr17_ctg5_hap1 1680828 + 1317419 1317468 chr17 78774742 - 37141484 37141533 34680290
+49
+
+chain 4268 chr17_ctg5_hap1 1680828 + 1385266 1385319 chr17 78774742 - 37052825 37052878 8381466
+53
+
+chain 4260 chr17_ctg5_hap1 1680828 + 1246721 1246766 chr17 78774742 - 37053870 37053915 4651304
+45
+
+chain 4113 chr17_ctg5_hap1 1680828 + 1390480 1390530 chr17 78774742 - 37058030 37058080 2324449
+50
+
+chain 4082 chr17_ctg5_hap1 1680828 + 1239288 1239381 chr3 199501827 + 42815100 42815194 539611
+38 32 33
+23
+
+chain 4047 chr17_ctg5_hap1 1680828 + 833483 833530 chr2 242951149 + 222576128 222576175 5745276
+47
+
+chain 4004 chr17_ctg5_hap1 1680828 + 1413149 1413191 chr17 78774742 - 37744368 37744410 15417978
+42
+
+chain 3932 chr17_ctg5_hap1 1680828 + 1246117 1246158 chr17 78774742 - 37053273 37053314 13638111
+41
+
+chain 3773 chr17_ctg5_hap1 1680828 + 1250577 1250669 chr2 242951149 + 55360621 55360713 11417907
+92
+
+chain 3751 chr17_ctg5_hap1 1680828 + 1385702 1385742 chr17 78774742 - 37053251 37053291 3400438
+40
+
+chain 3702 chr17_ctg5_hap1 1680828 + 712859 712906 chr3 199501827 - 151273341 151273388 853543
+47
+
+chain 3381 chr17_ctg5_hap1 1680828 + 713034 713083 chr1 247249719 - 160795106 160795155 805231
+49
+
+chain 3244 chr17_ctg5_hap1 1680828 + 1389742 1389776 chrX 154913754 - 110129876 110129910 25281679
+34
+
+chain 2964 chr17_ctg5_hap1 1680828 + 236048 236081 chr17 78774742 - 37041849 37041882 635
+33
+
+chain 2912 chr17_ctg5_hap1 1680828 + 448843 448913 chr17 78774742 - 36315447 36315517 1328
+70
+
+chain 2802 chr17_ctg5_hap1 1680828 + 1237022 1237068 chr18 76117153 + 50122791 50122837 616904
+46
+
+chain 2574 chr17_ctg5_hap1 1680828 + 1384829 1384856 chr17 78774742 - 37052388 37052415 20977188
+27
+
+chain 2078 chr17_ctg5_hap1 1680828 + 1250433 1250469 chr3 199501827 - 96596057 96596093 10950065
+36
+
+chain 1744 chr17_ctg5_hap1 1680828 + 1238128 1238154 chr10 135374737 + 101842906 101842932 538799
+26
+
+chain 1504 chr17_ctg5_hap1 1680828 + 1238956 1238985 chr16 88827254 + 28335851 28335880 780320
+29
+
+chain 1483 chr17_ctg5_hap1 1680828 + 1250547 1250577 chr19 63811651 + 22556112 22556142 10358829
+30
+
+chain 1204 chr17_ctg5_hap1 1680828 + 1386904 1386940 chr7 158821424 - 133749629 133749665 22723933
+36
+
+chain 996 chr17_ctg5_hap1 1680828 + 535350 535379 chr20 62435964 + 35074223 35074252 2591094
+29
+
+chain 372 chr17_ctg5_hap1 1680828 + 1421954 1423021 chr17 78774742 - 37753177 37754232 1257025
+92 67 67
+4 0 5
+235 1 1
+56 179 175
+23 17 0
+223 1 1
+102 1 5
+66
+
+chain 3524656 chr17_gl000203_random 37498 + 0 37498 chr17_random 2617613 + 1876393 1913891 829
+37498
+
+chain 7797784 chr17_gl000204_random 81310 + 0 81310 chr17_random 2617613 + 2131554 2212864 420
+81310
+
+chain 16543266 chr17_gl000205_random 174588 + 0 174588 chr17_random 2617613 + 0 174588 173
+174588
+
+chain 3927003 chr17_gl000206_random 41001 + 0 41001 chr17_random 2617613 + 2495431 2536432 754
+41001
+
+chain 7055977505 18 78077248 + 10000 78016181 chr18 76117153 + 0 76117153 19
+15400898 3100000 1363998
+28218587 15 15
+5329636 150000 47000
+3667310 18 0
+16406889 50000 28008
+3388467 50000 22000
+2103304 0 3
+136125 1 0
+7 1 0
+647 1 0
+1543 1 0
+25 14 8
+19 2 0
+10 7 4
+9 4 2
+663 1 0
+359 1 0
+1617
+
+chain 404699 chr18_gl000207_random 4262 + 0 4262 chr18_random 4262 + 0 4262 116705
+4262
+
+chain 5307806876 19 59128983 + 60000 59114839 chr19 63811651 + 11000 63806651 21
+7286004 50000 5000
+1291194 45000 0
+11772188 69160 0
+4058236 3100000 8000000
+20129228 2 0
+701 0 3
+347 1 1
+31 1 1
+1833 0 3
+1984 1 1
+47 1 1
+190 1 1
+34 1 1
+889 2 0
+1413 7 0
+2680 4 0
+375 1 0
+314 4 0
+29 1 0
+69 0 1
+3881 1 1
+40 12 0
+293 14 0
+1479 1 0
+233 1 1
+45 1 1
+1049 1 0
+1766 7 44
+220 0 3
+537 7 0
+351 8 8
+3603 1 1
+17 0 3
+697 0 1
+269 0 3
+974 5 6
+96 10 0
+1096 10 10
+1177 12 14
+1141 9 12
+1090 0 1
+175 16 0
+1063 0 4
+4780 44 44
+722 0 1
+548 2 2
+44 1 1
+424 2 2
+26 1 0
+4 0 1
+82 1 1
+59 1 1
+2087 15 0
+1499 0 1
+1754 0 2
+11209362
+
+chain 1655749 19 59128983 + 20505321 20523415 chr19 63811651 + 20366320 20387252 1476
+2041 4 4
+5604 0 2
+363 0 1
+2655 5 2857
+153 46 46
+705 79 83
+370 6 1
+1668 27 26
+347 21 0
+191 6 6
+369 0 2
+393 68 67
+328 0 6
+2049 1 0
+464 35 35
+96
+
+chain 207934 19 59128983 + 59114839 59117224 chr22 49691432 + 49588728 49591432 1471
+992 1 1
+63 1 1
+125 152 154
+174 1 1
+47 3 0
+214 5 5
+254 1 1
+67 1 1
+55 1 321
+72 14 14
+142
+
+chain 126422 19 59128983 + 59117224 59118680 chr10 135374737 + 135372723 135373917 1944
+177 13 13
+165 1 1
+156 1 1
+205 4 4
+93 1 1
+14 5 0
+88 1 1
+110 1 1
+52 2 1
+28 2 1
+14 255 0
+68
+
+chain 13558 19 59128983 + 59116021 59116173 chr2 242951149 - 128870722 128870873 1493
+33 1 0
+24 1 1
+57 1 1
+35
+
+chain 7358 19 59128983 + 59118906 59118983 chr21 46944323 + 46944213 46944290 27502546
+77
+
+chain 3811 19 59128983 + 20573506 20573546 chr19 63811651 - 43994109 43994149 26416662
+40
+
+chain 174 19 59128983 + 47898161 47898204 chr18 76117153 + 27836426 27836469 20429401
+43
+
+chain 8748871 chr19_gl000208_random 92689 + 0 92689 chr19_random 301858 + 0 92689 377
+92689
+
+chain 15150451 chr19_gl000209_random 159169 + 0 159169 chr19_random 301858 + 142689 301858 196
+159169
+
+chain 10110185 chr1_gl000191_random 106433 + 0 106433 chr1_random 1663265 + 1464329 1570762 316
+106433
+
+chain 32373596 chr1_gl000192_random 547496 + 48723 413485 chr16 88827254 + 69402787 69760000 100
+342 1 1
+38 1 1
+638 8 8
+750 11 11
+240 11 11
+1444 1 1
+23 1 1
+1265 0 3
+1506 1 1
+23 1 1
+114 1 1
+80 1 1
+118 1 1
+75 1 1
+311 9 9
+489 1 1
+27 168 14
+109 0 1
+340 5 0
+442 1 0
+25 1 1
+336 0 2
+672 1 1
+21 1 1
+691 1 1
+18 1 1
+144 2 2
+22 1681 0
+79 1 1
+1812 1 1
+31 1 1
+382 0 1
+474 10 9
+280 1 1
+39 0 2
+14 1 1
+103 1 1
+74 1 1
+124 1 1
+39 1 1
+471 1 1
+33 1 1
+653 1 1
+37 1 1
+94 9 10
+195 1 13
+2039 1 0
+1635 1 1
+27 1 0
+301 17 0
+42 1 1
+315 0 1
+384 1 1
+36 0 1
+8 2 0
+1541 11 10
+376 1 1
+36 1 1
+409 1 1
+15 1 1
+547 1 1
+89 1 1
+134 11 11
+161 3 79
+23 0 26
+39 0 1
+6 25 0
+14 1 1
+101 0 9
+94 1 1
+21 1 1
+171 1 1
+81 1 1
+1737 1 1
+27 1 0
+353 1 1
+36 1 1
+470 1 1
+72 1 1
+247 107 107
+709 1 1
+57 1 1
+289 14 14
+296 0 3
+342 1 1
+25 1 1
+184 1 1
+48 1 1
+628 1 1
+50 1 1
+457 0 2
+579 1 1
+21 0 4
+431 0 1
+52 1 1
+45 1 1
+146 1 1
+25 1 0
+26 2 1
+107 1 1
+39 1 0
+72 1 1
+26 1 1
+200 1 1
+19 1 1
+931 1 1
+27 1 1
+386 1 1
+17 1 1
+874 8 8
+146 1 1
+60 1 1
+840 19 19
+63 1 1
+25 1 1
+704 0 1
+721 1 1
+23 1 1
+673 29 14
+370 2 0
+25 1 1
+53 10 10
+591 1 1
+17 1 1
+124 0 1
+373 11 11
+234 12 12
+230 1 1
+31 1 1
+63 0 3
+903 27 28
+874 1 0
+290 11 12
+275 15 15
+290 3 0
+140 1 1
+36 1 1
+99 1 1
+38 1 1
+291 7 7
+1388 8 8
+1013 0 1
+2046 1 2
+423 1 1
+51 1 1
+1534 1 1
+78 1 1
+345 1 1
+37 1 1
+673 16 17
+742 1 1
+41 1 1
+545 1 1
+21 4 4
+387 5 0
+36 1 1
+420 0 28
+640 1 1
+23 1 1
+109 10 10
+1286 1 1
+37 2 2
+294 0 1
+24 1 1
+235 5 8
+223 1 1
+17 1 1
+673 1 1
+22 1 1
+685 10 10
+1762 1 0
+560 1 1
+37 1 1
+279 1 1
+73 1 3
+124 7 8
+495 0 1
+361 0 12
+63 4 0
+127 0 3
+129 0 8
+96 1 1
+34 4 0
+2212 3 0
+954 8 9
+1081 1 1
+45 1 1
+1449 62 57
+910 1 1
+33 1 1
+627 4 0
+933 1 1
+65 0 4
+196 1 1
+198 5 1
+268 1 1
+27 1 1
+994 1 1
+93 1 1
+839 1 1
+31 1 1
+798 0 25
+1007 1 1
+27 0 1
+1076 1 0
+216 0 8
+865 1 1
+61 1 1
+627 9 9
+98 1 1
+25 1 1
+1211 1 1
+61 1 1
+1142 1 1
+37 1 2
+25 1 1
+1594 1 1
+57 1 1
+310 1 1
+21 1 1
+324 3 0
+648 1 1
+44 1 1
+128 1 1
+65 1 1
+1411 1 1
+49 2 2
+563 1 1
+109 1 1
+95 1 1
+16 4 0
+869 1 1
+68 1 1
+178 1 1
+16 1 1
+952 3 0
+206 14 6
+916 10 10
+591 0 1
+240 0 8
+189 0 14
+383 10 10
+242 27 22
+393 310 0
+472 0 1
+364 0 18
+58 1 1
+27 1 1
+40 0 1
+1533 1 24
+460 1 1
+31 1 1
+637 0 5
+63 1 1
+440 8 9
+997 1 1
+25 1 1
+1009 12 12
+317 68 68
+1117 12 8
+97 1 1
+24 1 1
+413 0 1
+1417 1 1
+28 1 1
+165 1 1
+40 1 1
+1132 1 1
+22 1 1
+193 1 1
+124 1 1
+812 1 0
+3002 1 1
+48 1 1
+1345 48 48
+673 4 0
+1213 1 1
+17 1 1
+118 2 2
+33 1 1
+84 13 28
+55 1 1
+34 1 1
+105 1 1
+29 1 1
+348 0 6
+39 0 8
+826 1 1
+26 1 1
+489 25 28
+655 0 1
+179 7 13
+51 1 1
+81 1 1
+24 0 1
+1169 0 1
+178 14 15
+410 1 1
+98 1 1
+90 0 1
+81 1 1
+120 1 1
+57 1 1
+101 11 11
+98 1 1
+16 1 1
+1379 1 1
+106 1 1
+82 1 1
+30 1 1
+85 3 20
+1047 17 17
+780 1 1
+33 1 1
+431 1 1
+62 1 1
+272 1 1
+45 1 1
+363 1 1
+50 1 1
+121 8 1
+188 1 1
+56 1 1
+358 1 1
+36 1 0
+158 0 3
+44 1 0
+253 16 16
+829 1 1
+17 1 1
+78 6 6
+473 1 1
+39 1 1
+92 1 0
+87 1 1
+2589 1 0
+85 13 13
+499 16 20
+512 7 0
+47 1 1
+257 1 1
+32 1 1
+272 14 15
+559 1 1
+25 1 1
+3126 7 4
+461 1 1
+26 1 1
+323 1 1
+30 1 1
+695 0 1
+61 1 1
+178 1 1
+100 0 2095
+496 1 1
+23 1 1
+907 1 1
+35 1 1
+300 1 1
+30 1 1
+215 1 1
+43 1 1
+542 58 58
+88 1 1
+19 1 1
+327 1 1
+61 418 1
+335 0 1
+318 1 1
+45 0 3
+922 15 15
+370 1 1
+20 1 1
+69 0 20
+25 0 4
+32 1 1
+77 7 0
+45 1 1
+3019 34 0
+111 13 13
+514 11 11
+278 1 1
+35 1 1
+462 10 10
+354 0 3
+82 5 1
+366 1 1
+43 1 1
+728 1 1
+51 1 1
+609 1 1
+21 1 1
+428 28 28
+1350 5 5
+737 1 1
+23 1 1
+499 1 1
+21 1 1
+957 3 7
+324 1 2
+466 14 14
+90 8 8
+2017 1 1
+41 1 1
+58 0 2
+498 5 5
+899 1 1
+40 1 1
+62 16 16
+422 0 1
+38 1 1
+264 2 0
+67 1 1
+988 41 41
+267 1 1
+19 1 1
+1598 61 0
+309 1 1
+35 1 1
+469 0 2
+751 0 3
+2839 1 1
+42 1 1
+1760 0 2
+330 1 1
+34 1 1
+561 1 1
+30 1 1
+664 1 1
+79 1 1
+194 67 67
+518 1 1
+29 1 1
+68 1 1
+29 1 1
+615 22 21
+389 0 1
+197 30 0
+271 1 0
+448 1 1
+33 1 1
+839 14 13
+78 1 1
+20 1 1
+331 4 0
+1237 1 1
+40 1 1
+489 1 1
+44 1 0
+303 1 1
+40 1 1
+196 0 1
+129 9 8
+424 1 1
+35 1 1
+852 5 0
+105 1 1
+2114 30 30
+513 1 1
+22 1 1
+56 2 0
+704 1 1
+35 1 1
+427 1 1
+34 0 10
+42 1 0
+294 1 0
+153 9 8
+84 1 1
+45 4 4
+1521 1 1
+29 1 1
+530 1 1
+43 1 1
+894 6127 21
+161 0 4
+175 17 17
+636 12 12
+79 11 11
+69 0 1
+76 1 1
+359 1 1
+31 0 4
+67 1 1
+439 14 14
+343 0 3
+254 0 1
+189 0 1
+35 1 1
+1458 48 48
+1591 14 14
+708 8 8
+976 6 17
+637 1 1
+33 0 1
+956 1 1
+54 1 1
+135 1 1
+23 1 1
+467 1 1
+22 1 1
+87 1 0
+11 1 1
+94 4 0
+684 17 17
+344 1 1
+23 1 1
+1534 1 1
+32 4 0
+245 1 1
+44 1 1
+880 0 5
+105 1 1
+48 1 1
+2535 9 9
+129 0 12
+287 1 1
+46 1 1
+121 1 5
+158 13 14
+80 6 6
+698 5 6
+75 1 1
+43 1 1
+123 1 1
+24 2 7
+58 7 0
+2751 8 8
+528 1 1
+39 1 1
+223 1 0
+912 1 1
+39 0 1
+1215 30 30
+874 1 1
+31 1 1
+113 0 1
+511 1 1
+28 1 1
+291 1 3
+81 1 1
+109 1 1
+152 1 1
+39 10 5
+361 1 1
+31 2 0
+20 1 1
+180 1 1
+109 1 1
+324 1 1
+25 1 1
+539 1 1
+5 2 0
+61 1 1
+395 1 0
+1146 1 1
+45 1 1
+804 1 1
+95 1 1
+856 15 15
+541 322 0
+256 1 1
+23 1 1
+347 1 1
+21 1 1
+332 1 1
+71 1 1
+531 1 0
+488 1 1
+21 0 1
+74 20 19
+517 1 1
+35 1 1
+738 1 1
+41 1 1
+91 3 3
+117 1 1
+85 9 10
+200 6 0
+489 1 1
+271 10 0
+208 1 1
+46 2 2
+708 11 11
+70 1 1
+61 1 0
+88 1 1
+45 1 1
+1206 3 0
+19 1 1
+521 1 1
+25 1 1
+1518 1 1
+42 6 6
+1124 7 8
+53 1 1
+42 1 1
+825 17 17
+825 0 3
+568 1 1
+66 1 1
+394 17 17
+126 1 1
+41 1 1
+577 26 28
+367 12 11
+489 1 1
+65 1 1
+457 1 1
+16 1 1
+350 8 8
+18 4 4
+402 1 0
+103 1 0
+648 1 1
+36 1 1
+446 0 3
+61 16 16
+823 1 1
+32 1 1
+516 1 1
+111 1 1
+1091 1 1
+38 1 1
+49 1 0
+635 0 3
+14 1 1
+153 1 1
+40 1 1
+359 1 1
+35 4 4
+283 2 0
+557 1 1
+19 1 1
+293 3 4
+454 1 1
+70 1 1
+405 0 4
+1613 1 1
+26 13 15
+44 1 1
+458 13 13
+253 0 1
+1200 0 2
+244 1 4
+247 1 1
+38 1 1
+102 0 14
+710 1 1
+20 1 1
+1098 0 4
+200 2 0
+386 0 3
+683 1 1
+26 1 1
+327 4 0
+172 1 1
+311 1 1
+18 1 1
+338 28 28
+420 1 1
+29 1 1
+352 12 12
+301 1 1
+75 1 1
+205 1 0
+250 1 1
+20 1 1
+990 1 1
+20 1 1
+233 0 6
+342 5 9
+156 1 1
+30 1 1
+321 16 16
+420 11 11
+968 3 3
+15 1 1
+162 1 1
+68 1 1
+825 18 18
+153 1 1
+42 1 1
+711 1 1
+20 1 1
+269 1 0
+1414 4 3
+641 9 9
+1000 1 1
+29 1 1
+437 0 6
+45 1 1
+261 1 1
+31 0 2
+168 1 1
+26 1 1
+73 15 7
+29 4 0
+56 1 1
+126 1 1
+32 1 1
+463 6 6
+388 14 14
+1024 1 1
+54 1 1
+1019 1 1
+27 1 1
+428 3 3
+40 1 1
+86 1 1
+29 1 0
+610 6 10
+492 1 1
+28 3 3
+1202 11 11
+981 1 1
+28 1 1
+306 1 1
+39 1 1
+696 1 0
+157 1 1
+38 1 1
+170 1 1
+44 1 1
+2005 1 1
+26 1 1
+473 4 4
+491 0 1
+331 12 12
+1430 3 3
+11 0 5
+662 2 1
+494 12 13
+673 1 1
+76 1 1
+584 1 1
+36 1 1
+872 12 12
+123 1 1
+24 1 1
+540 15 15
+1309 1 1
+22 1 1
+71 15 15
+289 1 1
+38 1 1
+145 0 4
+731 3 0
+44 1 1
+2057 6 0
+446 4 0
+156 9 9
+55 0 1
+503 0 5
+38 1 1
+341 15 15
+493 1 1
+29 5 5
+1796 2 0
+1039 7 7
+444 8 8
+37 1 1
+205 0 1
+106 1 1
+386 1 1
+20 0 6
+2818 12 12
+498 15 15
+593 1 0
+203 1 1
+49 1 1
+313 1 2
+666 1 1
+46 0 2
+1360 1 0
+954 1 1
+65 1 1
+67 1 1
+33 1 1
+1062 1 1
+48 4 4
+600 16 16
+139 1 1
+29 1 1
+150 103 103
+813 1 1
+23 1 1
+775 1 1
+28 2 0
+55 13 0
+39 2 0
+17 0 1
+23 0 1
+7 11 1
+94 74 0
+163 1 1
+27 1 1
+2843 7 7
+73 4 0
+151 1 1
+22 0 1
+90 1 1
+316 15 15
+787 0 1
+405 1 1
+36 1 1
+833 2 0
+18 1 1
+1716 12 12
+78 0 1
+1860 0 1
+696 0 4
+16 1 1
+2116 3 4
+1554 1 1
+53 1 1
+1460 1 1
+25 1 1
+427 1 1
+37 1 1
+554 1 1
+36 1 1
+1626 40 40
+1079 1 1
+26 1 1
+427 2 0
+344 6 333
+1112 1 1
+19 1 1
+796 6 0
+373 1 1
+22 1 1
+787 1 0
+34 1 1
+1007 1 1
+36 2 0
+52 1 1
+945 1 0
+11 1 1
+743 1 1
+28 2 0
+1105 5 0
+45 2 0
+17 0 2
+49 1 1
+832 1 1
+33 1 1
+176 1 1
+48 0 4
+83 1 1
+91 1 1
+47 1 1
+256 1 1
+32 1 1
+1635 3 0
+175 5 1
+30 1 1
+1026 1 0
+13 1 1
+2090 20 20
+655 0 3
+628 1 1
+63 1 1
+380 1 1
+47 1 1
+2190 24 24
+149 0 2
+747 1 1
+17 0 7
+238 1048 0
+904 1 1
+78 1 1
+433 14 14
+153 1 1
+19 1 1
+561 1 1
+35 1 1
+271 2 0
+699 1 1
+53 1 1
+1273 0 1
+3111 11 11
+235 16 16
+490 3 0
+190 32 0
+83 18 19
+182 4 5
+78 0 4
+1098 1 1
+43 2 1
+1431 1 1
+35 4 4
+1822 0 6
+198 1 1
+41 1 1
+683 15 15
+1327 0 2
+18 1 1
+324 4 7
+1392 14 14
+1447
+
+chain 5080406 chr1_gl000192_random 547496 + 490457 547496 chr1 247249719 - 103949739 104006714 618
+285 2 1
+83 1 1
+1165 5 5
+59 1 1
+331 3 3
+32 1 1
+159 9 8
+140 1 1
+34 1 1
+111 1 1
+56 1 1
+419 1 1
+30 0 1
+231 16 16
+720 1 1
+47 1 1
+992 14 14
+147 1 1
+35 1 1
+270 2 2
+55 1 1
+204 1 1
+35 1 1
+189 12 12
+393 2 0
+504 2 0
+443 0 1
+181 0 6
+45 1 1
+719 1 1
+26 1 1
+723 9 9
+295 1 1
+56 1 1
+384 0 1
+516 1 0
+24 1 1
+81 0 1
+748 1 1
+47 1 1
+110 1 1
+38 82 0
+28 1 1
+526 1 1
+27 5 5
+166 8 7
+1312 0 4
+31 1 1
+230 1 1
+87 1 1
+309 13 0
+405 1 1
+33 1 0
+100 1 1
+59 1 1
+39 1 9
+184 0 4
+50 1 1
+211 4 4
+435 1 1
+55 1 1
+160 1 1
+39 1 1
+1986 1 1
+16 1 1
+117 0 1
+55 1 1
+357 0 1
+50 1 0
+368 0 20
+62 2 0
+4 2 0
+97 1 1
+121 0 1
+29 3 0
+857 36 36
+1724 0 322
+1221 1 1
+15 1 1
+135 8 8
+157 1 1
+25 0 1
+139 1 1
+36 1 1
+722 1 1
+46 1 0
+20 7 0
+862 1 0
+143 5 5
+274 1 1
+35 1 1
+355 0 1
+20 1 1
+376 1 1
+63 1 1
+199 1 1
+31 1 1
+261 0 1
+155 20 21
+52 0 1
+56 3 0
+151 23 23
+214 16 16
+105 1 1
+9 0 4
+41 1 1
+155 1 1
+77 1 1
+487 4 0
+82 1 1
+34 1 1
+275 1 1
+38 1 1
+334 1 1
+45 1 0
+4 0 4
+455 1 1
+47 1 1
+282 3 0
+74 14 14
+82 7 0
+717 1 1
+39 1 1
+197 0 4
+12 1 1
+50 17 17
+76 1 1
+38 1 1
+148 1 1
+60 1 1
+245 1 1
+18 1 1
+380 10 0
+348 1 1
+17 1 1
+515 1 1
+24 1 1
+267 5 7
+44 2 0
+25 1 1
+111 18 0
+162 1 1
+66 0 4
+109 1 1
+39 1 1
+676 16 16
+256 1 1
+48 1 1
+791 2 1
+61 1 1
+55 312 0
+281 7 7
+98 0 4
+66 1 1
+115 9 9
+678 1 1
+37 1 1
+304 1 1
+23 1 1
+283 1 1
+19 1 1
+164 10 10
+252 0 2
+131 4 4
+36 5 5
+83 1 1
+40 1 1
+361 27 20
+303 1 1
+69 1 1
+324 40 40
+72 12 0
+397 1 1
+23 1 1
+467 0 1
+418 6 6
+77 0 1
+21 1 1
+98 0 1
+21 1 1
+282 1 2
+107 22 22
+74 3 3
+47 1 1
+193 1 1
+46 1 1
+334 0 1
+78 0 1
+355 11 12
+823 1 1
+20 1 1
+173 1 1
+65 1 1
+335 0 4
+599 12 12
+143 1 1
+25 1 1
+1136 1 1
+38 1 1
+247 0 4
+30 1 1
+86 1 1
+19 1 1
+735 8 8
+679 15 15
+456 1 1
+43 1 1
+312 1 1
+94 1 1
+1047 1 1
+40 1 1
+1645 1 1
+37 1 1
+267 1 1
+55 1 1
+187 8 18
+480 1 1
+85 1 1
+537 1 1
+80 1 0
+80 0 11
+249 1 1
+24 1 1
+134 1 1
+36 1 1
+62 1 1
+81 0 2
+93 5 5
+46 1 1
+158 1 1
+36 1 1
+148 1 1
+67 1 1
+595 1 1
+30 1 1
+946 14 14
+58 1 1
+15 1 1
+321
+
+chain 2388490 chr1_gl000192_random 547496 + 0 480547 chr1 247249719 + 146071331 146197786 328
+299 0 14
+547 0 5
+291 3 3
+30 1 1
+1107 1 1
+35 1 1
+66 1 1
+86 1 1
+975 16 0
+485 12 0
+240 1 1
+16 1 1
+452 1 1
+26 2 2
+219 10 10
+607 31 14
+57 1 1
+397 1 1
+27 1 1
+69 0 2
+299 1 1
+38 0 1
+97 1 1
+33 1 1
+310 1 1
+63 1 1
+1214 11 0
+672 1 1
+30 1 1
+562 1 1
+34 1 1
+86 5 0
+36 52 0
+40 36 0
+73 0 3
+218 0 2
+885 1 1
+77 1 1
+153 1 1
+46 1 1
+538 0 1
+42 1 1
+495 0 1
+618 0 1
+406 1 1
+47 2 0
+264 1 1
+19 1 1
+112 0 3744
+343 13 14
+366 0 1
+39 1 1
+90 5 5
+72 0 3
+152 2 2
+42 1 1
+71 0 1
+30 1 1
+61 12 12
+280 0 3
+12 1 1
+101 1 1
+48 1 1
+97 1 1
+115 1 1
+299 1 1
+41 89 1
+148 7 7
+250 0 1
+1402 1 1
+69 1 0
+239 1 1
+38 1 1
+376 2 0
+96 1 1
+31 1 1
+273 0 4
+458 1 1
+22 0 12
+149 1 1
+38 0 2
+18 1 1
+443 1 0
+252 1 1
+25 1 1
+74 1 1
+18 0 1
+1535 108 9368
+354 1 0
+37 1 1
+1063 3 2
+3079 1 0
+142 1 1
+71 1 1
+230 6 6
+41 0 1
+112 4 4
+17 1 1
+478 2 0
+242 1 1
+21 1 1
+1407 1 0
+669 1 1
+34 1 1
+1561 1 1
+40 2 2
+62 1 1
+53 1 1
+975 1 1
+119 1 1
+1713 5 5
+132 0 3
+2570 1 0
+1294 9 9
+934 1 1
+33 1 1
+1518 4 1
+125 2889 0
+28 0 18
+706 10 10
+156 13 13
+1659 13 14
+1183 1 1
+49 1 1
+173 23 25
+420 364833 841
+3162 1 1
+44 1 1
+3579 1 1
+17 2 1
+30 3 0
+56 13 14
+298 1 1
+45 1 1
+388 1 1
+85 1 3
+162 2 0
+3397 3 5
+143 1 1
+19 1 1
+1299 1 1
+27 1 1
+10915 0 1
+4994 8 0
+1610 0 1
+3783 7 7
+606 4 0
+304 0 15
+143 12 14
+390 1 1
+43 0 2
+16 1 1
+231 5 0
+127 0 2
+222 2 0
+218 1 1
+45 1 1
+331 1 1
+23 1 1
+216 1 1
+21 1 1
+999 5 0
+563 1 1
+23 1 1
+305 1 1
+44 1 1
+466 2 0
+20 0 4
+234 16 21
+104 1 1
+28 1 1
+465 0 6
+137 1 3
+115 1 1
+23 1 1
+409 1 2
+762 1 1
+34 1 1
+133 1 1
+67 1 1
+1539 1 1
+24 1 1
+1362 9 2
+1632 1 1
+28 1 1
+1531 2 0
+26 1 1
+1909 10 2
+1605 1 1
+26 0 1
+834 0 1
+393 1 0
+40 1 1
+1724 1 1
+46 1 1
+588 8 8
+61 16 16
+669 1 1
+39 1 0
+1028 1 0
+21 1 1
+320 8 4
+1618 13 13
+569 18 15
+151 76 46
+2055 1 1
+35 1 1
+232 2 2
+26 1 1
+244 23 21
+54 16 16
+162 9 9
+61 1 1
+45 1 1
+72 1 1
+81 1 1
+197 1 1
+39 1 1
+300 1 1
+19 1 1
+370 9 9
+1433 1 0
+76 1 1
+21 1 1
+415 1 1
+26 1 1
+175 1 1
+9 2 0
+25 1 1
+413 1 1
+32 1 1
+299
+
+chain 551976 chr1_gl000192_random 547496 + 231797 237825 chr6 170899992 - 168530959 168536987 11545
+330 1 1
+17 2 2
+622 1 1
+19 1 1
+487 6 6
+662 1 1
+28 1 1
+1141 1 1
+84 1 1
+122 1 1
+29 1 1
+938 1 1
+49 1 1
+234 1 1
+107 1 1
+1138
+
+chain 488033 chr1_gl000192_random 547496 + 485075 510500 chr1 247249719 - 100429719 100455173 784
+56 1 1
+59 1 1
+88 1 0
+166 1 1
+42 1 1
+157 3 0
+1500 0 4
+24 1 1
+173 13 13
+537 1 1
+71 1 1
+274 1 1
+48 2 0
+29 1 1
+419 1 1
+75 1 1
+714 1 0
+919 11263 11275
+82 8662 8682
+36
+
+chain 29331 chr1_gl000192_random 547496 + 141011 141318 chr6 170899992 + 18853789 18854096 4814875
+307
+
+chain 25541 chr1_gl000192_random 547496 + 270161 270431 chr1 247249719 - 64213918 64214188 6752530
+270
+
+chain 18946 chr1_gl000192_random 547496 + 186298 186626 chr3 199501827 + 41796165 41796493 1046918
+124 44 44
+160
+
+chain 12970 chr1_gl000192_random 547496 + 526591 526726 chr14 106368585 + 78475097 78475232 7622843
+135
+
+chain 5617 chr1_gl000192_random 547496 + 185742 186466 chr4 191273063 - 143160847 143161571 1095905
+58 622 622
+44
+
+chain 2480 chr1_gl000192_random 547496 + 270431 270457 chr18 76117153 + 32169444 32169470 11367132
+26
+
+chain 2357 chr1_gl000192_random 547496 + 186676 186702 chr16 88827254 + 78288031 78288057 25120671
+26
+
+chain 2224 chr1_gl000192_random 547496 + 530486 530526 chr1_random 1663265 + 473083 473123 25958
+40
+
+chain 22466185064 2 243199373 + 10000 243102476 chr2 242951149 + 0 242751149 1
+1201236 0 1
+2057 1 1
+26 1 1
+4043 22 0
+82 7 101
+33 84 0
+26 1 23
+67 48 0
+176 318 0
+40 92 0
+33 0 74
+62 0 6
+22 0 118
+387 2446 0
+843 2450 0
+167 2304 0
+21342 1 1
+50 4 0
+2040 0 4
+9053 2 0
+88 3 53
+1078 0 1
+4122 1 0
+1608 28 1
+4029 0 9
+967 4547 1000
+420 27 0
+2237126 0 1
+2458 17 17
+4595 4 0
+3531 14 14
+3954 51129 50000
+1426129 160449 100025
+11087286 0 3
+773 103977 50000
+1576 0 1
+240 0 1
+318 2 0
+255 0 16
+2851 10 10
+1404 1 1
+27 1 1
+703 13 0
+375 0 1
+4783388 35000 25000
+848 0 2
+1225 0 2
+391 1 0
+3653 1 1
+28 1 1
+49 0 4
+4514 0 9
+9628 1 9
+1483 7 7
+1990 0 1
+1949 1 0
+2716230 1 0
+7799848 851 851
+38932068 5 9
+9477928 0 3
+7529698 72396 0
+1891551 294073 150000
+17672 1 0
+5792 1 0
+9017 0 266
+2944 0 1
+9388 2 0
+37828 4 0
+23436 0 4
+290931 1273578 1000000
+731068 3000000 3000000
+2558421 0 1
+1197 10 0
+685 42 46
+2309 0 1
+1332 22 23
+344 0 1
+1645 4 4
+4093 25 25
+2446 1 0
+6329 1 0
+769 0 1
+873 7 0
+1299 0 1
+8250 15 15
+4291 10626 12548
+1063 103 0
+75 0 218
+5897 1 1
+33 1 1
+9905 51 37
+1711 1 1
+45 1 1
+1597 4 4
+61 1 1
+869 13 0
+1633 15 15
+1179 3 0
+2819 0 2
+156 88 465
+100 0 25
+4753 0 8
+4903 6 6
+3847 0 2
+108126 0 145
+3542 1 0
+10276 0 1
+402 1 1
+47 1 1
+63 2 0
+583 1 1
+34 1 1
+8974 0 46
+379 1 1
+70 1 1
+2474 0 102
+1756 0 1
+8426 0 1
+11986570 151150 142000
+14207 1 1
+49 1 1
+1781 0 12
+409 1 0
+1874 1 1
+33 1 1
+4795 2 0
+3686 1 1
+15 1 1
+164 2 0
+7287 5 5
+702023 72796 150000
+69 1 0
+1598 0 1
+1340 0 1
+1030 0 4
+1166 10 10
+6406 1 1
+34 1 1
+3283 2 4
+496 1 23
+25 10 0
+40 1 1
+21282 2 1
+1406 0 44
+937 17 0
+18255 1 0
+172366 0 281526
+40517 0 406
+58864 1 2
+1843 0 2
+14994 0 1
+12992 2 0
+2571146 1 0
+35688061 108224 100000
+29671719 1 0
+39665349 1 0
+14876089 64197 20000
+401 0 3
+1831 1 1
+61 1 1
+654 11 1
+127 0 28
+116 25 29
+74 9 9
+3247 2 0
+1355 1 0
+816 1 0
+21 3 0
+526 1 1
+60 1 1
+773 1 0
+1494 1 0
+1683 1 0
+21 1 1
+596 1 0
+1582 1 0
+425 0 3
+1139 0 8
+138 144 813
+71 1 0
+385638 1 1
+219 1 1
+51 7 7
+54 15205 15205
+54 7 7
+51 1 1
+110 1 1
+5198249 0 1
+115 80 0
+60 40 0
+80 100 20
+442 1 1
+35 1 1
+119 9 129
+14 0 40
+61 1 1
+85 0 40
+1331 0 1
+1194 12 14
+1773 0 5
+1623 1 1
+25 1 1
+2422 21 22
+2315 0 1
+31 1 1
+1508 0 3
+50 0 4
+970 6 6
+7234 4 0
+1228 1 0
+1233 8 1
+4207 1 1
+41 1 1
+1715 50 50
+1532 0 2
+1714 2 0
+2299 2 0
+2143 1 1
+18 1 1
+917 1 0
+1082 1 1
+49 1 1
+9098 0 4
+5529 0 1
+3266 0 8
+894 6 0
+1440 1 1
+2095 2 0
+4179 18 13
+1785 0 1
+1674 0 6
+1217 32348 33000
+287 17 23
+40 173 0
+20 161 0
+13 66 0
+12 71 1
+12548 30000 30000
+952154 41011 25000
+1914 1 0
+225 1 1
+57 1 1
+2910 0 1
+471 1 0
+1956 1 1
+43 1 1
+991 0 92
+2863 3 0
+1838 306 0
+1006 30 0
+206 1 1
+27 0 3
+221 17 17
+1525 8 0
+413 1 1
+32 2 2
+1573 12 12
+2258676
+
+chain 8298836 2 243199373 + 90373613 90527957 chr2 242951149 + 90958828 91114560 236
+29837 32 32
+212 25 25
+508 90 90
+1291 33 33
+2574 1 0
+833 28 28
+2712 0 1
+805 10 5
+565 68 68
+75 69 57
+176 58 513
+63 105 105
+336 33 33
+69 1 0
+280 4 4
+111 12 12
+523 1 0
+136 55 56
+198 0 1
+630 0 1
+362 42 42
+405 30 30
+78 5 0
+125 5 0
+75 140 0
+166 49 49
+1653 30 30
+3790 5 5
+500 21 21
+577 23 23
+180 0 1
+1105 1 0
+231 4 4
+333 33 33
+852 2 0
+2709 16 16
+476 28 28
+53 33 57
+256 0 3
+900 0 1
+227 0 2
+718 0 2
+244 42 42
+302 30 30
+211 21 21
+1809 16 17
+204 33 32
+341 9 9
+176 0 5
+180 67 67
+73 39 39
+369 49 49
+52 9 15
+699 9 13
+142 0 4
+184 0 4
+248 27 26
+306 10 10
+63 20 20
+533 22 22
+432 86 85
+97 19 19
+383 19 23
+642 10 9
+156 88 88
+217 0 6
+1798 9 7
+425 0 4
+1191 0 4
+465 40 37
+671 7 7
+450 0 1
+714 31 32
+682 38 15
+230 28 1076
+95 220 261
+80 1967 0
+118 383 158
+81 28 2
+247 0 1
+181 0 1
+702 47 47
+361 39 39
+300 50 50
+195 9 9
+179 35 35
+228 0 10
+321 65 65
+233 20 20
+368 35 35
+1436 37 37
+985 5 5
+140 73 73
+1031 25 25
+957 51 51
+690 23 48
+1047 49 49
+186 1 0
+244 4 4
+166 16 16
+173 1 0
+387 51 51
+122 59 58
+141 1 0
+72 102 84
+75 203 201
+276 30 30
+367 20 20
+105 67 68
+82 0 1
+386 7 7
+68 61 61
+514 56 56
+92 91 91
+268 89 89
+200 4 4
+526 33 36
+370 10 10
+366 20 26
+1107 0 2
+130 74 74
+101 0 1
+542 32 34
+179 43 43
+151 84 84
+421 25 25
+332 1 0
+561 64 65
+1406 10 10
+161 97 88
+564 27 30
+123 29 33
+170 0 1
+183 94 94
+52 4 0
+379 83 83
+237 32 31
+187 46 46
+236 728 703
+50 1494 1865
+72 67 32
+25 1732 6535
+52 52 52
+104 647 648
+27 494 471
+23 0 137
+1 1884 302
+115 8 8
+76 3078 388
+26 200 44
+59 2295 2292
+40 1854 1861
+54 2541 2546
+27 28 27
+57 56 56
+26 2212 2216
+181 494 652
+42 2237 2213
+40 2572 2562
+36 1791 1791
+34 2776 2807
+23 7115 7113
+44 509 509
+36 664 665
+43 1891 2219
+36 256 256
+31 276 289
+42 881 1734
+67 149 144
+49 190 190
+73 357 345
+30 1074 1075
+42 1850 1850
+47 469 481
+24 2460 2482
+41 3325 3319
+32 306 296
+26
+
+chain 2305993 2 243199373 + 243162866 243189340 chr16 88827254 - 5000 31222 1142
+136 9 9
+870 16 16
+229 1 1
+44 1 1
+330 10 14
+243 1 1
+93 1 1
+58 1 1
+144 1 1
+62 95 95
+333 1 1
+77 1 1
+494 9 11
+230 8 8
+61 12 13
+128 14 14
+123 1 1
+68 1 1
+4208 5 1
+1989 71 0
+121 1 1
+35 1 1
+1498 59 0
+443 69 69
+237 1 1
+45 1 1
+75 1 1
+32 2 1
+20 1 1
+152 1 1
+129 0 1
+1040 1 1
+70 2 0
+128 1 1
+50 1 1
+605 9 8
+62 1 1
+155 1 1
+50 11 6
+94 1 1
+409 1 1
+34 1 1
+217 1 1
+39 1 1
+287 0 9
+102 1 1
+56 30 26
+64 108 0
+127 1 0
+373 1 1
+18 1 1
+194 1 1
+10 1 1
+98 1 1
+67 1 1
+184 1 1
+21 1 1
+86 0 1
+44 1 1
+50 15 15
+177 1 1
+72 1 1
+222 1 1
+44 1 1
+50 1 1
+46 1 1
+449 1 1
+118 1 1
+127 0 1
+242 1 1
+36 1 1
+710 4 4
+69 1 1
+87 1 1
+115 1 1
+68 17 0
+12 2 1
+14 0 12
+36 4 0
+102 1 1
+105 24 24
+131 18 18
+64 19 19
+293 1 1
+43 1 1
+134 25 25
+77 14 14
+225 1 0
+93 1 1
+363 11 11
+271 25 25
+136 1 1
+36 1 1
+102 4 4
+29 1 1
+51 2 0
+162 0 4
+61 1 0
+65 1 1
+26 4 4
+140 17 17
+336 1 1
+25 1 1
+408 16 16
+311 27 27
+90 7 7
+449 1 1
+47 1 1
+133 1 1
+62 7 7
+194 1 1
+13 3 0
+54 2 0
+28 1 1
+72 1 1
+45 1 1
+65 1 1
+23 1 1
+279 1 1
+61 1 1
+55
+
+chain 1358560 2 243199373 + 89890737 90543561 chr2 242951149 - 153539598 155537136 99
+8973 0 1
+939 0 1
+4351 0 2
+2413 1 1
+37 1 1
+515 1 0
+224 1 1
+22 1 1
+203 1 1
+18 1 1
+249 8 7
+830 4 0
+177 1 0
+30 1 1
+224 1 1
+75 1 1
+243 1 1
+20 0 5
+2724 0 137
+439 1 1
+35 1 1
+444 0 2
+1484 1 1
+41 1 1
+395 1 1
+40 1 1
+417 1 1
+44 1 1
+909 1 1
+32 24 14
+1057 2 2
+46 1 1
+306 1 1
+32 3 0
+269 10 10
+535 10 10
+615 1 1
+42 1 1
+1295 1 1
+21 1 1
+84 1 1
+30 0 1
+19 1 1
+434 57 57
+283 15 15
+304 12 12
+149 17 17
+1413 1 1
+32 1 1
+66 550910 1890523
+54 205 14
+64 147 86
+119 57 8
+71 27 96
+100 1265 73
+307 7 9
+182 31 30
+128 15 15
+95 61 59
+92 20 296
+50 77 75
+255 261 3338
+95 264 262
+204 53 55
+136 81 81
+173 62 57
+130 77 76
+241 35 35
+424 0 154
+42 3 3
+109 0 434
+68 0 59
+215 1 1
+47 1 1
+109 0 180
+10 4 0
+21 7 104
+33 31 37
+62 17 17
+114 1 1
+50 0 9
+117 9 0
+63 1 1
+92 1 1
+37 146 0
+49 956 0
+32 163 4
+37 619 0
+42 1 1
+108 973 20
+91 1 18
+215 19 19
+20 26 0
+124 56 0
+14 65 0
+65 1 1
+465 1 1
+45 1 0
+126 1 1
+46 1 1
+1501 1 1
+41 40 0
+58 2 5
+574 8 0
+830 0 5
+121 0 3
+26 0 2
+52 0 2
+183 54 0
+1069 1 1
+62 4 0
+23 1 1
+62 0 3
+233 0 2
+32 3 0
+1051 112 112
+56 26 26
+59 7 7
+588 17 18
+401 18 18
+472 1 0
+398 2 3
+249 181 22
+397 0 158
+97 42 42
+1302 24 2
+162 9 9
+740 40 40
+554 0 1
+1362 23 19
+249 12 12
+372 36 36
+987 1 0
+221 10 8
+394 9 9
+169 34 36
+170 1 1
+27 1 1
+61 1 0
+396 0 120
+152 1 13
+60 0 5
+12 1 1
+145 1 1
+51 1 1
+847 6 6
+420 1 1
+46 1 0
+43 1 1
+145 1 1
+41 1 1
+142 25 24
+332 14 14
+310 1 1
+91 1 1
+605 1 1
+47 1 1
+361 10 10
+183 0 5
+672 8 8
+76 17 20
+227 1 1
+86 1 1
+60 1 0
+30 5 5
+2399 1 1
+29 1 1
+547 10 17
+195 3 0
+609 3 0
+175 44 44
+292 8 8
+209 36 37
+543 39 39
+82 43 43
+235 38 38
+760 20 20
+502 8 0
+108 7 18
+66 2 0
+57 0 3
+88 36 36
+77 0 15
+94 24 24
+61 31 1532
+146 38 41
+92 82 77
+151 0 2606
+94 93 1000
+189 50 50
+234 100 94
+146 49 49
+189 74 74
+62 37 17
+258 30 30
+114 47 47
+494 96 98
+323 42 43
+106 20 20
+142 250 250
+161 7 7
+651 21 21
+492 237 249
+144 23 23
+88 48 48
+52 15 15
+201 6 0
+105 29 29
+68 18 18
+87 50 50
+227 147 147
+176 17 17
+404 9 9
+457 0 23
+392 41 41
+196 18 18
+99 77 80
+219 52 53
+156 0 7
+323 28 28
+99 43 42
+229 27 27
+156 107 103
+95 1 0
+1118 0 1
+282 41 41
+172 21 3
+104 26 0
+21 1 71
+54 6 76
+63 1 1
+58 1 1
+84 1 1
+285 1 1
+46 1 1
+320 15 15
+326 7 7
+170 1 1
+73 1 1
+214 1 1
+40 1 1
+613 1 0
+772 0 2
+424 1 1
+34 1 1
+423 1 1
+33 1 1
+1157 1 1
+43 2 2
+82 1 1
+21 1 1
+65 1 1
+62 1 1
+250 1 1
+79 1 1
+88 2 2
+79 1 1
+68 11 11
+115 1 1
+38 1 1
+63 9 0
+39 1 1
+73 1 1
+77 3 3
+55 1 1
+46 1 1
+157 1 1
+58 0 2
+92 1 1
+67 1 1
+48 1 1
+289 1 1
+40 1 0
+398 1 1
+31 1 1
+729 1 1
+72 1 1
+575 1 1
+86 1 1
+495 3 0
+472 1 1
+34 1 1
+87 1 0
+28 1 1
+441 20 0
+31 1 1
+61 1 1
+152 5 5
+774 0 1
+114 2 0
+355 0 3
+415 5 0
+76 1 1
+18 1 1
+308 1 1
+18 1 1
+226 4 4
+490 0 3
+104 1 1
+47 1 1
+542 6 6
+131 8 0
+152 49 1
+68 9 9
+198 1 1
+40 0 10
+78 1 1
+108 1 1
+73 1 1
+50
+
+chain 1317324 2 243199373 + 234472598 234486532 chr2 242951149 - 8801149 8815083 1658
+13934
+
+chain 1182591 2 243199373 + 111018489 111031067 chr2 242951149 - 132350497 132363075 1985
+750 1 0
+155 1 0
+2029 0 1
+2687 0 1
+2417 3 0
+3105 1 3
+965 35 36
+238 6 6
+185
+
+chain 907761 2 243199373 + 111000659 111010676 chr2 242951149 + 110060000 110070000 4064
+3405 66 54
+839 0 1
+854 33 33
+1502 180 174
+250 88 88
+1904 40 40
+856
+
+chain 864618 2 243199373 + 110991361 111000659 chr2 242951149 + 110050705 110060000 3488
+3987 37 37
+135 34 34
+2446 4 0
+1497 0 1
+1158
+
+chain 730598 2 243199373 + 111010676 111018489 chr2 242951149 + 110070000 110077815 3339
+976 16 15
+4855 0 3
+320 26 26
+1620
+
+chain 247895 2 243199373 + 111031067 111033745 chr2 242951149 - 131778891 131781575 150672
+814 1 1
+73 1 1
+148 0 6
+1211 4 4
+426
+
+chain 233678 2 243199373 + 87718206 87726480 chr2 242951149 - 151887377 151890935 691
+139 0 3
+233 4 2
+36 0 1
+291 21 13
+104 28 28
+303 26 26
+314 134 82
+86 0 1
+53 4314 721
+22 22 0
+50 389 652
+54 1133 0
+17 214 6
+79 34 60
+62 59 67
+53
+
+chain 228678 2 243199373 + 243159401 243162866 chr1 247249719 + 217390 220668 1312
+57 88 88
+22 186 0
+101 49 49
+417 53 54
+61 3 0
+141 0 1
+198 8 8
+852 39 39
+405 56 56
+61 27 27
+589 1 1
+51
+
+chain 207578 2 243199373 + 243152688 243155284 chr10 135374737 - 346 2792 2690
+533 150 0
+105 1 1
+49 1 1
+260 1 1
+69 1 1
+262 1 1
+29 1 1
+1133
+
+chain 148868 2 243199373 + 243155284 243160374 chr5 180857866 - 20000 25834 2103
+547 1 1
+38 1 1
+431 1 1
+24 1 1
+1389 1 1
+36 1 1
+1646 57 57
+82 0 744
+6 22 22
+186 101 101
+49 417 417
+53
+
+chain 147892 2 243199373 + 97920581 97932373 chr2 242951149 - 145465890 145477699 123
+1513 0 1
+2596 1 1
+36 1 1
+1383 5 1
+46 4 0
+550 1 4
+1798 7 8
+158 1 29
+18 1 1
+110 1 1
+48 1 1
+1617 7 0
+723 1063 1063
+93 1 0
+9
+
+chain 133880 2 243199373 + 87666489 111064157 chr2 242951149 - 130965951 132771520 53
+624 23366717 1774574
+2397 0 12
+14288 0 1
+1427 1 1
+24 1 1
+1756 10 10
+83 69 69
+698 0 21
+1910 1 1
+61 1 1
+3754 0 8
+243 1 1
+33 1 1
+320 0 1
+163 1 1
+36 1 1
+809 0 1
+1762 1 1
+49 1 1
+425
+
+chain 127176 2 243199373 + 5140970 5146585 chr2 242951149 - 235014747 235020583 1011815
+158 1545 1830
+107 308 308
+50 129 129
+85 163 165
+62 65 65
+282 81 63
+147 650 624
+67 138 138
+59 285 285
+76 61 62
+92 72 72
+76 266 249
+70 129 128
+83 107 102
+202
+
+chain 104115 2 243199373 + 87667113 87668206 chr2 242951149 + 87520624 87521717 786265
+1093
+
+chain 95484 2 243199373 + 87729232 87738885 chr2 242951149 + 87510347 87520000 5761
+9653
+
+chain 84057 2 243199373 + 90492917 90545103 chr2 242951149 - 152993866 153046874 435
+28 21223 21222
+38 2087 2087
+38 134 134
+40 246 246
+45 0 255
+13 0 572
+34 189 189
+50 234 234
+30 1029 1029
+47 494 494
+96 633 633
+250 1379 1379
+190 682 682
+29 173 173
+50 227 227
+147 1809 1804
+77 219 219
+52 479 479
+28 99 99
+43 229 229
+27 156 156
+107 16787 16788
+49 628 628
+1542
+
+chain 73315 2 243199373 + 87720014 87720774 chr2 242951149 - 155450797 155451557 1717423
+760
+
+chain 66981 2 243199373 + 1219529 1222202 chr2 242951149 + 1208584 1209647 1299817
+61 279 0
+275 1051 0
+115 843 563
+49
+
+chain 64603 2 243199373 + 90371566 90373613 chr2 242951149 + 90963202 90965490 370989
+76 46 46
+165 47 47
+460 75 75
+51 403 393
+63 64 364
+66 168 168
+56 68 19
+69 135 135
+35
+
+chain 46427 2 243199373 + 1223650 1226709 chr2 242951149 + 1208645 1209604 1438302
+140 630 0
+183 167 167
+210 1050 0
+171 420 0
+88
+
+chain 36623 2 243199373 + 89847430 89848295 chr5 180857866 + 153976522 153977390 3635252
+54 96 96
+262 346 349
+107
+
+chain 34396 2 243199373 + 87721616 87729232 chr2 242951149 + 87502993 87507825 13964
+67 36 543
+1013 77 25
+569 4 4
+189 715 6
+6 94 94
+389 54 54
+542 2531 33
+70 11 11
+68 21 21
+129 10 10
+126 0 22
+162 9 0
+89 28 26
+108 298 307
+116 64 12
+21
+
+chain 31906 2 243199373 + 90476997 90485104 chr2 242951149 - 155439923 155448722 818134
+65 4692 1587
+31 1167 442
+62 157 183
+65 24 24
+92 31 191
+67 10 184
+32 72 0
+76 105 36
+60 4 0
+97 52 697
+66 9 0
+169 1 23
+85 272 2102
+131 95 43
+149 89 1960
+80
+
+chain 31233 2 243199373 + 239788914 239789423 chr2 242951149 + 239454423 239454932 2214253
+173 20 20
+161 13 13
+66 12 12
+64
+
+chain 27639 2 243199373 + 243165116 243187640 chr8 146274826 + 470 67316 1215
+95 9992 9923
+69 4222 48594
+49 1 1
+58 4967 4926
+25 3019 3079
+27
+
+chain 25982 2 243199373 + 16340754 16341023 chr3 199501827 - 118072788 118073057 6523537
+269
+
+chain 25898 2 243199373 + 1220683 1220990 chr2 242951149 + 1208828 1209135 2249524
+307
+
+chain 25826 2 243199373 + 87728597 87729031 chr2 242951149 + 87491002 87491436 712257
+28 108 108
+298
+
+chain 25128 2 243199373 + 5141270 5144398 chr1 247249719 + 207689145 207692170 1456022
+66 87 87
+79 23 23
+95 979 893
+74 119 119
+116 487 487
+54 893 876
+56
+
+chain 24661 2 243199373 + 16273805 16274100 chr4 191273063 - 182882474 182882769 7289877
+128 26 26
+141
+
+chain 19295 2 243199373 + 90372486 90373577 chr2 242951149 + 90976555 90977646 1336226
+61 57 57
+56 292 292
+41 202 202
+55 193 193
+134
+
+chain 19158 2 243199373 + 1225400 1225680 chr2 242951149 + 1208855 1209065 11144872
+180 70 0
+30
+
+chain 18303 2 243199373 + 1219198 1219473 chr2 242951149 + 1208603 1208808 11853376
+134 73 3
+68
+
+chain 13465 2 243199373 + 16354747 16354888 chr5 180857866 + 167726962 167727103 16868271
+141
+
+chain 13298 2 243199373 + 89875086 89876327 chr20 62435964 + 29293186 29293377 17078580
+57 350 0
+39 320 0
+36 155 0
+6 225 0
+53
+
+chain 13261 2 243199373 + 1224140 1224280 chr2 242951149 + 1208645 1208785 17127371
+140
+
+chain 12749 2 243199373 + 5141660 5146147 chr5 180857866 - 44949635 44952639 1949230
+55 641 482
+80 490 492
+69 238 238
+34 2813 1487
+67
+
+chain 11727 2 243199373 + 240838559 240838726 chr2 242951149 + 240487433 240487623 18443158
+86 35 58
+46
+
+chain 11295 2 243199373 + 1226909 1227026 chr2 242951149 + 1209530 1209647 20202652
+117
+
+chain 11288 2 243199373 + 1223295 1223413 chr2 242951149 + 1208990 1209108 3139804
+118
+
+chain 10759 2 243199373 + 90430195 90457119 chr2 242951149 - 151338126 151363320 2584
+28 2775 2822
+30 11958 12016
+40 1843 1850
+30 5080 3227
+47 361 361
+39 312 312
+38 383 383
+35 2707 2718
+36 1130 1130
+52
+
+chain 9553 2 243199373 + 89869741 89871237 chrY 57772954 + 11913136 11913399 23867669
+64 1367 134
+65
+
+chain 9489 2 243199373 + 110253717 110253937 chr2 242951149 + 106303434 106303606 24025084
+58 106 58
+56
+
+chain 9445 2 243199373 + 1223971 1224070 chr2 242951149 + 1208756 1208855 24130758
+99
+
+chain 8720 2 243199373 + 1222223 1225291 chr2 242951149 + 1208828 1209516 2041184
+278 99 99
+79 2535 155
+77
+
+chain 8428 2 243199373 + 90482794 90485288 chr2 242951149 - 155439240 155441007 1572933
+56 44 44
+58 400 417
+31 1832 1088
+73
+
+chain 8213 2 243199373 + 87720809 87720895 chr2 242951149 + 87507349 87507434 5227216
+41 1 0
+44
+
+chain 8069 2 243199373 + 90483014 90484786 chr2 242951149 - 155448229 155461339 1164914
+45 110 127
+2 735 1564
+52 750 11246
+68 4 0
+6
+
+chain 7776 2 243199373 + 1217508 1217592 chr2 242951149 + 1207753 1207837 7243988
+84
+
+chain 7421 2 243199373 + 1226334 1226411 chr2 242951149 + 1209439 1209516 27381596
+77
+
+chain 7358 2 243199373 + 89880461 89880538 chr22 49691432 - 33895115 33895192 27502443
+77
+
+chain 7257 2 243199373 + 1219025 1219100 chr2 242951149 + 1208570 1208645 27695248
+75
+
+chain 7028 2 243199373 + 1220317 1225128 chr2 242951149 + 1208603 1209423 1749868
+42 70 0
+111 1961 0
+99 2380 420
+148
+
+chain 6973 2 243199373 + 1223223 1223295 chr2 242951149 + 1208568 1208640 27324023
+72
+
+chain 6924 2 243199373 + 1220268 1221195 chr2 242951149 + 1208974 1209200 2111755
+49 743 42
+135
+
+chain 6823 2 243199373 + 243161637 243162225 chr6 170899992 - 4262 4850 1512
+39 405 405
+56 61 61
+27
+
+chain 6757 2 243199373 + 1224280 1224350 chr2 242951149 + 1209065 1209135 28694341
+70
+
+chain 6747 2 243199373 + 1219799 1219869 chr2 242951149 + 1208645 1208715 25148698
+70
+
+chain 6633 2 243199373 + 89847849 89847926 chr14 106368585 - 28607150 28607227 5517613
+77
+
+chain 6601 2 243199373 + 239685120 239685200 chr2 242951149 + 239350340 239350540 24829287
+66 1 121
+13
+
+chain 6531 2 243199373 + 89865276 89865345 chr16 88827254 - 55053025 55053094 29215386
+69
+
+chain 6312 2 243199373 + 111004064 111004130 chr2 242951149 - 132336069 132336135 211650
+66
+
+chain 6255 2 243199373 + 1226201 1226267 chr2 242951149 + 1209586 1209652 12280449
+66
+
+chain 6049 2 243199373 + 89847131 89847195 chr1 247249719 + 184405152 184405216 30439720
+64
+
+chain 6014 2 243199373 + 89850535 89853562 chr10 135374737 - 96209116 96209251 30527518
+57 2911 19
+59
+
+chain 5970 2 243199373 + 87721480 87727902 chr2 242951149 + 87501266 87503920 375724
+136 1955 628
+417 2657 546
+67 36 27
+57 474 105
+64 294 290
+36 0 52
+229
+
+chain 5911 2 243199373 + 87725643 87726005 chr2 242951149 + 87495962 87496324 1452475
+79 29 29
+211 17 17
+26
+
+chain 5902 2 243199373 + 90476920 90476981 chr2 242951149 - 155440689 155440750 30819911
+61
+
+chain 5764 2 243199373 + 1219128 1219198 chr2 242951149 + 1208603 1208673 13156733
+70
+
+chain 5625 2 243199373 + 87727023 87727089 chr2 242951149 + 87494216 87494282 1840679
+66
+
+chain 5449 2 243199373 + 1221033 1223650 chr2 242951149 + 1208828 1209415 2333010
+27 2353 323
+237
+
+chain 5435 2 243199373 + 87725371 87725531 chr2 242951149 + 87487864 87488024 3394118
+65 44 44
+51
+
+chain 5351 2 243199373 + 243152496 243152579 chr21 46944323 - 27 110 6622
+83
+
+chain 5348 2 243199373 + 5153354 5153410 chr2 242951149 + 239297362 239297418 32407088
+56
+
+chain 5167 2 243199373 + 89830753 89830808 chr16 88827254 - 55048203 55048258 32968623
+55
+
+chain 5034 2 243199373 + 90484935 90484987 chr2 242951149 - 155462101 155462153 29809699
+52
+
+chain 5012 2 243199373 + 89872838 89872891 chr4 191273063 + 48825877 48825930 33453820
+53
+
+chain 4920 2 243199373 + 89890558 89890609 chr2 242951149 + 89623647 89623698 33788797
+51
+
+chain 4886 2 243199373 + 90477063 90477242 chr2 242951149 - 155440771 155441314 25803008
+53 75 439
+51
+
+chain 4812 2 243199373 + 89870406 89870457 chr4 191273063 + 48802771 48802822 34140093
+51
+
+chain 4757 2 243199373 + 234058786 234058836 chr13 114142980 + 90951015 90951065 34330265
+50
+
+chain 4737 2 243199373 + 5145834 5145884 chr3 199501827 - 155139362 155139412 33407240
+50
+
+chain 4647 2 243199373 + 1226779 1226827 chr2 242951149 + 1209604 1209652 34630462
+48
+
+chain 4644 2 243199373 + 111007822 111007876 chr2 242951149 - 132339823 132339877 533729
+54
+
+chain 4607 2 243199373 + 5145066 5145350 chr3 199501827 + 191348934 191349218 1967131
+93 45 45
+57 39 39
+50
+
+chain 4552 2 243199373 + 1219473 1219520 chr2 242951149 + 1208598 1208645 27324024
+47
+
+chain 4467 2 243199373 + 5146638 5146689 chr8 146274826 + 70047993 70048044 10546953
+51
+
+chain 4382 2 243199373 + 239685380 239685447 chr2 242951149 + 239350400 239350507 10821439
+47 0 40
+20
+
+chain 4286 2 243199373 + 89847926 89848007 chr18 76117153 + 56250573 56250654 7293717
+81
+
+chain 4166 2 243199373 + 90482850 90482893 chr2 242951149 - 155471295 155471338 33373631
+43
+
+chain 4069 2 243199373 + 90483640 90483682 chr2 242951149 - 155471279 155471321 32448532
+42
+
+chain 4027 2 243199373 + 89848079 89848577 chr11 134452384 - 130303828 130304326 4308822
+70 372 372
+56
+
+chain 3915 2 243199373 + 89847485 89847537 chr4 191273063 - 120181520 120181572 9841777
+52
+
+chain 3887 2 243199373 + 1222921 1225400 chr2 242951149 + 1208756 1209205 3355598
+176 2233 203
+70
+
+chain 3870 2 243199373 + 5146741 5146807 chr4 191273063 - 106282745 106282811 8233254
+2 4 4
+60
+
+chain 3851 2 243199373 + 243174715 243174760 chr1 247249719 + 80163 80208 1584
+45
+
+chain 3776 2 243199373 + 1223932 1223971 chr2 242951149 + 1208577 1208616 29100476
+39
+
+chain 3766 2 243199373 + 1225991 1226030 chr2 242951149 + 1209516 1209555 18014514
+39
+
+chain 3567 2 243199373 + 89848026 89848188 chr6 170899992 - 102513053 102513215 4544108
+53 70 70
+39
+
+chain 3456 2 243199373 + 87720895 87724286 chr2 242951149 + 87506634 87508855 332559
+59 4 143
+126 0 22
+162 9 0
+89 28 26
+108 1252 650
+77 1179 461
+298
+
+chain 3166 2 243199373 + 90482349 90482483 chr2 242951149 - 155440886 155440924 3921176
+20 96 0
+18
+
+chain 3114 2 243199373 + 1223097 1223130 chr2 242951149 + 1209002 1209035 21012522
+33
+
+chain 3110 2 243199373 + 1225750 1225960 chr2 242951149 + 1209065 1209275 3693305
+210
+
+chain 2962 2 243199373 + 16340723 16340754 chr16 88827254 + 56242121 56242152 7757072
+31
+
+chain 2946 2 243199373 + 1225580 1225611 chr2 242951149 + 1209315 1209346 16952082
+31
+
+chain 2859 2 243199373 + 243189340 243189373 chr2 242951149 - 213544 213577 2192
+33
+
+chain 2638 2 243199373 + 5146355 5146383 chr9 140273252 + 31324189 31324217 27516381
+28
+
+chain 2632 2 243199373 + 87721683 87721719 chr2 242951149 + 87489021 87489057 886310
+36
+
+chain 2630 2 243199373 + 5144933 5144985 chr19 63811651 + 23161927 23161979 24515130
+52
+
+chain 2538 2 243199373 + 16338477 16338504 chr3 199501827 - 154040818 154040845 35425972
+27
+
+chain 2527 2 243199373 + 111053817 111053884 chr2 242951149 + 110544305 110544372 1691975
+67
+
+chain 2476 2 243199373 + 5146689 5146741 chr2 242951149 - 88851718 88851770 6471285
+52
+
+chain 2465 2 243199373 + 16260450 16260476 chr14 106368585 - 56125663 56125689 35442474
+26
+
+chain 2448 2 243199373 + 90475509 90477186 chr2 242951149 - 155452726 155455668 5069202
+50 704 1477
+39 832 1324
+52
+
+chain 2256 2 243199373 + 89865421 89865445 chr4 191273063 + 48820096 48820120 35487368
+24
+
+chain 2132 2 243199373 + 90371525 90371566 chr2 242951149 + 90975643 90975684 3405316
+41
+
+chain 2046 2 243199373 + 87729180 87729211 chr2 242951149 + 87489147 87489178 2812396
+31
+
+chain 2012 2 243199373 + 16273933 16273955 chr11 134452384 + 22938127 22938149 7662326
+22
+
+chain 1994 2 243199373 + 5144152 5145822 chr11 134452384 + 133004933 133006812 2924035
+46 1530 1739
+23 20 20
+51
+
+chain 1907 2 243199373 + 5146585 5146633 chr1 247249719 - 174030724 174030772 3467396
+48
+
+chain 1894 2 243199373 + 1220990 1221013 chr2 242951149 + 1208785 1208808 13156732
+23
+
+chain 1847 2 243199373 + 87729147 87729180 chr2 242951149 + 87508312 87508345 2784752
+33
+
+chain 1616 2 243199373 + 5141194 5141259 chr4 191273063 + 140068684 140068749 14298254
+65
+
+chain 1606 2 243199373 + 89847307 89847375 chr6 170899992 + 54305106 54305174 19190580
+68
+
+chain 1373 2 243199373 + 243172974 243173045 chr8 146274826 + 8401 8472 3798112
+71
+
+chain 1350 2 243199373 + 87719705 87727637 chr2 242951149 + 87486442 87489057 666335
+5 4 8
+60 6231 0
+175 909 1819
+190 64 64
+294
+
+chain 1237 2 243199373 + 5143151 5144336 chr3 199501827 - 33955506 33956705 3724972
+50 1070 1084
+65
+
+chain 1182 2 243199373 + 1222834 1225214 chr2 242951149 + 1208599 1208809 9180420
+46 2248 78
+86
+
+chain 1157 2 243199373 + 87726368 87726988 chr2 242951149 + 87492753 87493373 434529
+59 53 53
+165 67 67
+36 57 57
+183
+
+chain 1107 2 243199373 + 5141765 5144570 chr1 247249719 + 5005582 5008225 2100127
+50 2701 2539
+54
+
+chain 1007 2 243199373 + 5142524 5142584 chr7 158821424 - 115940368 115940428 3379044
+60
+
+chain 998 2 243199373 + 234471343 234471369 chr18 76117153 + 53315026 53315052 2684166
+26
+
+chain 997 2 243199373 + 1223799 1223839 chr2 242951149 + 1209424 1209464 2284434
+40
+
+chain 932 2 243199373 + 87725722 87725751 chr2 242951149 + 87499077 87499106 1733344
+29
+
+chain 867 2 243199373 + 1226560 1226598 chr2 242951149 + 1209385 1209423 17548334
+38
+
+chain 822 2 243199373 + 5144726 5144801 chr2 242951149 - 76674151 76674226 3649555
+75
+
+chain 767 2 243199373 + 5141372 5141411 chr7 158821424 + 51905543 51905582 3310848
+39
+
+chain 651 2 243199373 + 5141336 5141372 chr5 180857866 - 59015526 59015562 2717102
+36
+
+chain 561 2 243199373 + 5140901 5140953 chr6 170899992 + 131686128 131686180 4225085
+52
+
+chain 545 2 243199373 + 90414124 90414152 chr7 158821424 - 94210194 94210222 18407154
+28
+
+chain 270 2 243199373 + 89868258 89868320 chrY 57772954 + 11916008 11916070 28746465
+62
+
+chain 5644665978 20 63025520 + 60000 62965520 chr20 62435964 + 8000 62435964 20
+26259569 3100000 1765661
+234339 150000 1000000
+4004088 1 0
+6459 244 0
+37810 2 0
+1044573 50000 20000
+9411883 8 2
+362 1 0
+11607353 1 0
+1301304 0 1
+31036 9 0
+1151 2 0
+1088 1 1
+29 1 1
+2509 2 0
+407 0 1
+40 1 1
+3787164 50000 27050
+71932 50000 110000
+694117 1 0
+1008033
+
+chain 3228736998 21 48129895 + 10697896 48119895 chr21 46944323 + 9719767 46944323 23
+490233 3150000 3050000
+19828060 1 0
+8789369 48801 0
+222468 500 500
+22014 1500 1500
+1381822 48641 0
+3438590
+
+chain 42537850 chr21 48129895 + 9411193 10647896 chr21_random 1679693 + 281005 1255172 87
+184355 489372 50000
+131056 281918 458754
+150002
+
+chain 16006699 chr21 48129895 + 9825437 10497894 chr21_random 1679693 - 0 756441 94
+158053 0 149427
+56 1 1
+500 1 1
+35 1 1
+276 1 1
+92 1 1
+413 12 12
+944 1 1
+31 1 1
+185 5 5
+93 1 1
+63 1 1
+959 0 1
+268 1 1
+33 1 1
+115 1 0
+12 0 2
+56 1 1
+99 1 1
+49 1 1
+65 1 1
+32 1 13
+425 1 1
+77 2 0
+252 0 7
+72 1 1
+96 1 1
+44 1 1
+197 7 7
+86 1 1
+32 1 1
+423 1 1
+26 1 1
+758 1 1
+77 1 1
+217 3 0
+50 1 1
+290 1 1
+112 1 1
+66 14 14
+116 18 22
+727 19 19
+140 4 0
+393 1 1
+28 1 1
+50 2 0
+38 6 1
+21 1 1
+80 1 1
+71 1 1
+179 1 1
+35 1 1
+69 1 1
+20 1 1
+216 1 1
+31 1 1
+182 1 1
+43 1 1
+97 1 1
+22 1 1
+87 1 1
+66 1 1
+72 1 1
+68 1 1
+312 1 1
+28 1 1
+478 1 1
+111 1 1
+191 1 1
+18 1 1
+98 1 2
+29 2 1
+57 1 1
+44 1 6
+74 1 1
+79 77 78
+186 1 1
+107 1 1
+202 2 2
+135 1 1
+95 0 3
+93 1 0
+48 5 0
+170 1 1
+43 1 0
+260 1 1
+23 1 1
+312 1 0
+26 1 0
+28 0 1
+87 0 10
+157 8 8
+900 1 1
+56 1 1
+235 1 1
+81 1 1
+156 1 1
+61 1 1
+156 1 1
+48 1 1
+65 12 12
+89 1 1
+158 2 2
+106 3 1
+375 0 2
+35 1 1
+73 1 1
+33 1 1
+392 2 0
+602 1 1
+66 1 1
+375 1 1
+55 1 1
+207 1 1
+25 2 2
+459 7 7
+188 1 3
+210 3 3
+28 0 4
+980 1 1
+15 1 1
+350 20 0
+636 0 4
+43 1 0
+539 63 64
+80 3 0
+142 8 7
+247 1 0
+908 1 1
+20 1 1
+128 0 1
+301 4 0
+56 2 2
+658 1 1
+34 1 1
+184 8 8
+162 0 2
+64 0 1
+80 1 1
+34 1 1
+121 1 1
+21 1 1
+374 1 1
+130 0 1
+47 1 1
+68 1 1
+35 4 0
+361 1 0
+73 1 1
+44 1 1
+392 1 1
+70 1 1
+76 1 1
+48 1 1
+216 1 1
+54 1 1
+67 4 4
+282 1 1
+44 1 1
+73 15 15
+166 4 0
+338 1 1
+27 1 1
+243 1 1
+101 1 1
+344 1 1
+51 1 1
+367 1 1
+35 0 1
+199 1 1
+18 1 1
+153 13 13
+102 0 1
+125 1 1
+49 1 1
+102 7 7
+100 18 18
+316 20 20
+151 0 2
+21 0 1
+575 1 0
+60 1 1
+60 1 1
+441 24 24
+364 1 0
+57 1 1
+158 10 10
+197 1 1
+49 1 0
+13 0 1
+5 1 1
+478 1 0
+244 22 22
+91 1 1
+80 5 5
+130 1 1
+26 1 1
+405 1 1
+51 1 1
+235 11 11
+330 1 1
+66 1 1
+85 342 17
+157 26 26
+261 1 1
+38 2 2
+824 20 20
+252 12 0
+119 1 1
+42 1 1
+1237 23 22
+103 1 1
+70 1 1
+155 1 1
+26 0 1
+80 1 1
+468 1 1
+60 1 1
+139 1 1
+53 2 2
+194 1 1
+35 1 1
+94 1 1
+56 1 1
+128 1 1
+40 1 1
+124 0 1
+54 1 1
+75 1 1
+79 1 1
+66 1 1
+82 0 1
+88 1 1
+146 0 3
+60 1 1
+67 2 2
+36 5 5
+147 1 1
+32 1 1
+185 1 1
+44 1 1
+68 40 15
+201 1 1
+37 1 1
+387 1 1
+18 1 1
+103 339913 274830
+131918
+
+chain 2365142 21 48129895 + 9686364 9760752 chr1 247249719 - 105115380 105189719 169
+453 1 1
+62 1 1
+312 9 9
+152 1 1
+34 1 1
+205 1 1
+109 44 0
+14 7 65
+203 5 5
+26 1 1
+70 1 1
+17 1 1
+847 1 1
+49 1 1
+99 1 1
+87 1 1
+51 1 1
+26 1 1
+374 1 1
+43 0 6
+139 1 1
+128 1 1
+54 1 1
+45 2 0
+17 1 1
+75 1 1
+59 1 1
+210 1 1
+70 1 1
+158 43 43
+56 12 12
+109 1 1
+48 5 5
+116 1 1
+49 1 1
+307 1 1
+45 1 1
+440 5 5
+106 9 9
+784 1 1
+42 1 1
+228 0 1
+114 17 17
+88 11 11
+161 1 1
+38 1 1
+825 2 2
+38 1 1
+105 22 22
+81 1 1
+29 1 1
+300 23 23
+147 1 1
+26 1 1
+164 1 1
+35 1 1
+227 6 6
+56 2 2
+109 1 1
+25 4 0
+116 15 23
+172 1 1
+40 1 1
+68 15 15
+158 7 7
+349 14 14
+133 1 1
+39 1 1
+145 12 12
+60 1 1
+43 1 1
+101 21 21
+307 1 1
+42 1 1
+93 1 1
+162 1 1
+143 1 1
+40 1 1
+54 1 1
+107 9 10
+319 1 1
+43 4 4
+200 1 1
+18 1 1
+127 1 1
+90 1 1
+250 3 3
+93 148 1
+443 0 1
+77 9 9
+295 1 1
+59 1 1
+438 31 31
+127 3 0
+88 1 1
+109 7 8
+79 14 14
+112 10 8
+114 1 1
+94 1 1
+150 10 7
+69 1 1
+110 1 1
+17 1 0
+222 0 1
+195 1 1
+16 1 0
+89 1 1
+123 38 0
+43 1 1
+83 1 1
+47 3 4
+64 0 3
+38 1 1
+268 1 1
+27 1 1
+230 17 17
+252 1 1
+24 0 3
+168 1 1
+41 5 0
+50 1 1
+212 9 9
+40 29 0
+271 1 1
+48 1 1
+124 1 1
+57 1 1
+125 16 16
+136 29 29
+157 1 1
+27 7 0
+482 10 4
+158 1 1
+62 1 1
+371 1 1
+83 1 1
+120 1 1
+45 1 1
+189 0 1
+84 1 1
+103 18 18
+494 1 1
+55 3 0
+139 1 1
+264 18 18
+75 2 3
+130 1 1
+97 1 1
+193 1 1
+25 1 1
+167 1 1
+49 1 1
+62 16 16
+65 13 13
+62 1 1
+101 1 1
+60 1 1
+50 1 1
+307 9 9
+131 13 13
+94 1 1
+78 1 1
+132 1 1
+27 1 1
+358 1 1
+21 1 1
+466 14 14
+590 1 1
+34 1 1
+242 1 1
+29 1 1
+116 1 1
+44 1 1
+117 1 1
+67 2 1
+71 1 1
+32 1 1
+506 18 18
+88 1 1
+27 1 1
+78 0 11
+215 1 1
+77 1 1
+291 1 1
+56 3 3
+126 1 1
+42 1 1
+332 9 9
+280 6 9
+641 15 15
+59 6 10
+31 1 1
+62 1 1
+40 1 1
+298 1 1
+40 1 1
+146 1 1
+66 1 0
+757 2 0
+169 1 1
+65 1 0
+285 1 1
+20 1 1
+109 1 1
+67 1 1
+68 1 1
+32 1 1
+93 4 4
+147 0 14
+646 0 1
+544 8 8
+47 1 0
+141 14 14
+678 1 0
+154 0 1
+346 1 1
+73 1 1
+232 5 5
+113 1 1
+32 2 0
+23 1 1
+92 10 10
+1121 1 1
+143 1 1
+300 1 1
+49 1 1
+392 5 5
+242 1 1
+21 1 1
+369 1 1
+67 1 1
+47 0 1
+618 23 23
+565 1 1
+140 1 1
+247 1 1
+41 1 1
+50 1 1
+18 1 1
+65 1 1
+66 1 1
+108 0 4
+158 1 1
+105 1 1
+70 1 1
+25 6 8
+77 1 1
+323 1 1
+28 1 1
+258 1 1
+47 1 1
+393 1 1
+72 1 1
+149 13 13
+142 1 0
+60 0 1
+78 4 4
+100 1 1
+51 1 1
+156 1 1
+20 1 1
+510 1 1
+22 1 0
+67 1 1
+54 1 1
+45 1 1
+133 1 1
+23 1 1
+63 1 1
+32 1 1
+349 1 1
+15 1 1
+103 1 1
+36 1 1
+119 1 1
+47 1 1
+312 4 4
+66 13 13
+357 0 76
+20 1 1
+177 1 1
+91 1 1
+52 1 1
+36 1 1
+141 10060 10099
+90 1 1
+49 1 1
+212 1 1
+20 1 1
+286 1 1
+48 2 1
+50 1 1
+67 8 8
+63 1 1
+30 1 1
+93 1 1
+48 1 1
+129 1 1
+46 1 1
+455 1 1
+46 3 0
+84 1 1
+39 0 1
+229 2 11
+79 4 4
+731 17 16
+725 8 8
+249 1 1
+78 1 1
+1065 3 0
+735 0 1
+124 10 10
+51 1 1
+35 1 1
+315 25 25
+749 6 6
+343 1 1
+29 1 1
+386 1 1
+24 1 1
+407 1 0
+73 1 1
+708 1 1
+71 0 1
+16 1 1
+92 1 1
+25 1 1
+447 14 14
+190 85 85
+60 1 1
+66 1 1
+238 1 1
+87 5 5
+118 7 7
+696 0 12
+49 1 1
+823 1 1
+77 1 1
+154 0 3
+102 12 12
+698 1 1
+21 1 1
+591 1 1
+16 1 1
+59 1 1
+27 1 1
+114 1 0
+593 1 1
+30 1 1
+1351 1 1
+17 1 1
+77 6 0
+647 1 1
+23 1 1
+235 1 1
+39 1 1
+141 1 1
+80 5 5
+181 10 11
+1091 1 1
+58 0 1
+19 1 1
+305 0 1
+429 17 17
+107 1 1
+25 1 1
+156 5 5
+22 1 1
+188
+
+chain 1441791 chr21 48129895 + 9645548 9775437 chr21_random 1679693 + 696416 826305 252
+40816 1341 1341
+44 2893 2893
+43 8663 8663
+148 1323 1323
+31 1767 1767
+38 1629 1629
+29 781 781
+29 25619 25619
+10060 6346 6346
+25 3590 3590
+85 9904 9904
+14685
+
+chain 891297 chr21 48129895 + 9995689 10034920 chr21_random 1679693 + 191774 231005 206
+77 9866 9866
+63 13134 13134
+342 157 157
+26 5919 5919
+40 750 750
+8857
+
+chain 2615495 chr21_gl000210_random 27682 + 0 27682 chr21_random 1679693 - 1650984 1679693 1058
+9933 367 719
+17272 0 675
+110
+
+chain 25569 chr21_gl000210_random 27682 + 10033 10300 chr21_random 1679693 - 1660317 1660584 5767478
+267
+
+chain 3320966530 22 51304566 + 16050000 51244566 chr22 49691432 + 14430000 49591432 22
+647850 150000 150000
+3661581 100000 50000
+15278437 18 0
+294 36 0
+1407 1 1
+46 1 1
+6626947 4 2
+1759 1 1
+43 1 1
+1367363 10613 11998
+7858 0 4
+809337 20 0
+6305 0 20
+6703 2669 50000
+4247674 0 10618
+1611 2719 0
+35235 131 0
+12642 0 4
+45595 9 85
+19564 506 0
+165499 7 5
+1103946 60575 16700
+644 2 0
+319796 1155 1600
+17927 15406 19700
+464629
+
+chain 11044 22 51304566 + 50772606 50772840 chr1 247249719 + 28744016 28744317 20648865
+55 103 170
+76
+
+chain 18404394637 3 198022430 + 60000 197962430 chr3 199501827 + 35000 199446827 3
+13552792 0 1
+585083 0 1
+2092 1 2
+71 0 1
+31067262 0 1
+90 1 0
+5628461 0 15
+788 1 0
+3676 0 2
+35 1 1
+4682 1 0
+1295 0 5
+437 53 42
+326 0 2
+3309 1 1
+40 1 1
+998 0 3
+3584 5 0
+930 5 7
+845 1 1
+28 2 1
+303 0 1
+507 0 5
+5088 1 0
+2185 10046 10048
+949 4 4
+35 1 1
+2874 0 1
+6717 0 1
+2823 1 0
+703 0 4
+5143 1 0
+2490 10 10
+162 7 7
+6308 0 15
+15177535 152352 260003
+2532 1 0
+1633 2 2
+24207544 3000000 4400000
+60453436 0 4
+40076813 20999 20000
+8195 1 1
+44 1 1
+1408 1 1
+33 1 1
+172 3 4
+25 1 1
+538 13 13
+173 1 1
+27 1 1
+636 1 1
+28 1 1
+470 3 3
+112 1 1
+375 1 1
+26 26 0
+115 78 0
+52 23 0
+104 26 0
+15 231 0
+56 1 1
+20 1 1
+815 16 16
+484 1 1
+49 18 0
+509 4 3
+23 1 1
+391 1 1
+44 1 1
+1278 0 4
+32 1 1
+263 4 0
+27 1 1
+2416 0 2
+3184 43 43
+1150 13 13
+736 1 1
+47 1 1
+1416 1 1
+20 1 1
+1020 1 1
+25 1 1
+482 5 0
+716 1 0
+1697 1 1
+29 1 1
+1270261 23108 27000
+40930 1 0
+17455 1 1
+28 4 4
+43 0 491
+1679 1 1
+33 7 5
+29 1 3
+54863 53 16
+7653 2 2
+29 2 2
+15 0 30
+180 0 75
+215 45 0
+360 915 0
+6188 96 0
+17 288 0
+1388 1 1
+37 1 1
+7956 0 1
+374 0 1
+2442058
+
+chain 905554 3 198022430 + 50925386 50935027 chr3 199501827 - 148591827 148601470 3167
+1111 0 6
+2584 0 1
+5889 6 1
+51
+
+chain 274603 3 198022430 + 195356374 195379482 chr3 199501827 - 629997 657219 690
+621 1 1
+42 1 1
+893 1 121
+66 1 1
+693 1 1
+27 1 1
+761 1 1
+79 2 2
+297 1 1
+40 1 1
+643 1 1
+22 1 1
+410 8 9
+110 1 1
+16 0 5
+314 3 0
+1846 4 7
+39 1 1
+420 10 9
+335 6 0
+238 0 1
+76 1 0
+310 1 2
+175 1 1
+17 1 1
+268 1 1
+46 1 1
+114 1 1
+19 1 1
+127 8 8
+30 1 1
+207 6 6
+62 9 9
+505 22 22
+160 1 1
+34 1 1
+187 1 1
+138 0 1
+844 1 1
+103 0 1
+65 3459 3402
+90 4 4
+90 42 794
+52 478 4
+78 154 154
+28 235 0
+59 1501 5454
+143 19 19
+425 7 54
+39 46 0
+75 8 8
+73 1 95
+58 1 1
+51 16 63
+140 1 1
+33 1 1
+682 1 1
+68 1 1
+147 1 1
+82 1 1
+119 33 0
+262 0 1
+54 1 0
+13 56 0
+111 5 5
+722 1 1
+19 1 1
+60 1 1
+33 1 0
+7 1 1
+108 0 2
+302 1 1
+68 1 0
+42 1 1
+50 1 1
+80 1 0
+95 1 1
+19 1 1
+119 0 1
+493 16 16
+316
+
+chain 30227 3 198022430 + 66156466 66156782 chr5 180857866 - 15729243 15729559 4617547
+316
+
+chain 25764 3 198022430 + 195503126 195503723 chr3 199501827 + 196988790 196989012 1952307
+75 360 0
+127 20 5
+15
+
+chain 19039 3 198022430 + 195503723 195504023 chr3 199501827 + 196988637 196988937 1894839
+300
+
+chain 11786 3 198022430 + 195373997 195374119 chr3 199501827 - 651916 652038 19355983
+122
+
+chain 9624 3 198022430 + 195503246 195503561 chr3 199501827 + 196988205 196988400 2003832
+53 137 2
+73 4 19
+48
+
+chain 7908 3 198022430 + 195510214 195510615 chr3 199501827 + 196993313 196993714 919394
+96 17 17
+288
+
+chain 6921 3 198022430 + 66275488 66275560 chr6 170899992 + 144236219 144236291 28346484
+72
+
+chain 6012 3 198022430 + 66274973 66275036 chr15 100338915 - 38411650 38411713 30540003
+63
+
+chain 5039 3 198022430 + 66276813 66276866 chr9 140273252 + 71084115 71084168 33364454
+53
+
+chain 4902 3 198022430 + 66152713 66152764 chr11 134452384 + 5803379 5803430 33869306
+51
+
+chain 3381 3 198022430 + 195371524 195371562 chr3 199501827 - 645118 645156 13662757
+38
+
+chain 3356 3 198022430 + 50925108 50925187 chr3 199501827 - 92152745 92152824 20266108
+79
+
+chain 2109 3 198022430 + 195371614 195371638 chr3 199501827 - 645161 645185 16027164
+24
+
+chain 1800 3 198022430 + 195503201 195503246 chr3 199501827 + 196989165 196989195 4219824
+23 17 2
+5
+
+chain 1295 3 198022430 + 195372257 195372308 chr3 199501827 - 2286585 2286636 21843906
+51
+
+chain 17653654354 4 191154276 + 10000 191029082 chr4 191273063 + 0 191263063 4
+1413146 71672 51000
+5369 6 5
+65 1 1
+67 1 1
+425 1 1
+32 1 1
+175 1 1
+34 1 1
+5092 1 1
+46 1 1
+1396 15 15
+1446 1 0
+1679 13 13
+3443 0 1
+586 1 1
+38 1 1
+18 21 0
+1582 6 0
+202 3 0
+92 0 6
+187 9 0
+4054 1 1
+71 1 1
+1413 1 83
+51 7 7
+105 7 7
+53 0 41
+81 1 42
+41 0 41
+37 0 41
+3274 1 94
+114 0 1116
+921 2 0
+935 0 55
+3639 15 15
+1167 0 3
+44 29 0
+44 0 29
+5146 1 1
+42 1 1
+3831 3 0
+23 1 1
+4171 6 6
+796 165 0
+196 99 0
+94 33 0
+183 8 6
+107 2 2
+21 2 0
+62 68 1
+32 15 14
+81 18 18
+55 1 0
+17 67 1
+188 133 0
+44 67 0
+43 35 0
+3289 18 18
+298 1 0
+373 1 0
+2965 1 1
+30 23 0
+1718 38 0
+98 38 0
+53 44 7
+116 0 77
+272 1 1
+70 1 1
+1591 49 49
+360 33 23
+2400 1 1
+94 1 1
+6002 1 1
+16 1 1
+776 0 1
+324 46 46
+433 0 51
+53 27 1
+2181 4 1
+57 1 1
+1969 0 10
+4188 11 11
+1595 18 0
+2050 109 0
+4319 7 0
+50 4 0
+1464 1 3
+4156 0 2
+5455 2 3
+129 4 4
+9082 1 0
+786 20 20
+1506 1 0
+252 7 8
+17512 1 50
+56 0 1
+2474 52 69
+75 30 0
+61 0 16
+11 0 15
+41 1 1
+133 0 16
+79 17 0
+16 29 0
+3375 1 0
+969 4 0
+1623 11 11
+1065 3 0
+2934 0 8
+2323 181 0
+2290 0 1
+1641 1 6
+1955 1 0
+68 1 1
+347 1 1
+40 1 1
+1553 0 6
+678 16 16
+92 33 0
+390 0 4
+1147 1 0
+1948 4 4
+4296 1 1
+16 1 1
+955 1 1
+47 1 1
+1555 0 1
+2251509 0 81122
+171 1 1
+48 1 1
+718 0 1
+2789 1 1
+27 1 1
+1601 0 4
+1907 2 0
+31 1 5
+16 0 4
+76 2 0
+13 4 0
+27 1 0
+12 1 9
+1772 6 0
+22 1 1
+946 1 1
+24 1 1
+1245 0 1
+3231 1 1
+41 1 1
+736 4 4
+912 1 1
+18 1 1
+11270 0 3
+2704 1 1
+41 1 1
+1812 6 5
+1477 11 0
+1744 6 6
+2039 0 4
+2188 1 1
+48 1 1
+1704 1 1
+73 1 1
+2265 12 12
+553 1 1
+49 1 1
+67 1 1
+33 1 1
+3935 0 5
+15 0 1
+780 1 0
+1260 1 0
+4204 25 0
+862 14 14
+7114 1 1
+70 1 1
+169 1 0
+43 1 1
+145 1 1
+39 3 0
+8 1 1
+753 1 0
+1535 41 41
+679 1 1
+21 1 1
+1605 1 1
+19 1 2
+392 1 1
+29 0 1
+3673 0 1
+145 14 14
+39 1 0
+1246 1 0
+2302 0 1
+1554 9 9
+4537 1 0
+1064 0 2
+2051 0 1
+1130 2 0
+164 0 1
+1972 1 0
+18 3 3
+2597 1 1
+46 3 3
+196 1 1
+17 1 1
+60 4 4
+187 4 4
+46 1 1
+692 0 1
+3382 41 41
+497 3 3
+15 1 1
+486 14 14
+1709 0 8
+169 0 1
+597 1 1
+18 7 0
+3423937 1 0
+1295496 1 1
+26 1 1
+760 591802 150000
+22468468 1 1
+27 1 1
+2592 2 0
+33 1 1
+2065 0 3
+1050 11 11
+1046 9 3
+3263 0 1
+906 0 1
+1643 0 6
+1181 1 0
+475 5 0
+2522 0 4
+407 1 0
+517 77 77
+1122 36199 70999
+976587 26528 59000
+7703 4 0
+4545 9 9
+4740 1 0
+1862 0 1
+3316 3 7
+51 14 14
+1066 1 0
+1795 0 1
+569 0 1
+2895 1 1
+39 1 1
+461 0 3
+3168 6 6
+2197 0 1
+6774 2 0
+2504 2 0
+1247 1 1
+45 1 1
+2415 17 17
+4792 36 36
+3387 20 20
+272 10 10
+420 1 1
+34 1 1
+7961 0 4
+1973 1 1
+45 0 1
+529 0 1
+603 1 0
+18 1 1
+606 4 0
+65 1 25
+41 0 8
+517 1 0
+1400 41 38
+3786 1 0
+228 0 3
+1026 1 1
+49 1 1
+3336 3 0
+951 1 1
+77 1 2
+441 2 1
+1833 9 9
+301 5 5
+2787 17 17
+1747 0 1
+3040 9 2
+81 10 10
+86 0 2
+2113 45 45
+7352791 1606 20000
+1651 0 2
+45 16 0
+13956 8 0
+1947 3 0
+1255 1 1
+38 1 0
+1778 4 0
+22 1 0
+1045 0 6
+1327 1 0
+5775 1 1
+18 1 1
+1933 0 1
+1716 13 13
+255 0 1
+124 3 0
+792 5 0
+1521 1 1
+64 1 1
+9005617 150000 150000
+171176 3000000 3000000
+7074452 62111 50000
+5257 1 0
+2845 0 2
+1387 1 0
+114 0 1
+2385 4 0
+65 6 6
+62 0 4
+18 1 0
+100 51 0
+9781577 0 351994
+1903288 0 184275
+3925704 13 13
+435 1 1
+21 1 1
+838 1 0
+281 35 35
+491 6 6
+74 1 1
+43 1 1
+652 29839 30000
+13847966 1 0
+14069801 0 2
+8504 1 0
+32265 0 8
+12730 2 0
+35327 14 12
+1503 0 1
+1334 0 1
+759 1 0
+10036 1 7
+9912 17 18
+2523 0 1
+1321 1 0
+8984 0 2
+5505 20 20
+9694 6 6
+22003 0 9
+578 1 0
+5166 0 2
+92208 5 2
+8 0 1
+5 2 0
+110 0 4
+848 7 6
+2247 1 3
+3770 1 0
+5719 2 0
+2511 1 0
+1557 1 0
+5812 1 0
+3607 1 0
+7405 0 1
+11075 1 0
+2794 0 1
+2340 0 1
+429 1 0
+233 27 27
+262 0 2
+2397 0 5
+371 0 11
+1376 0 1
+2416 0 8
+210 1 1
+20 1 1
+5104 1 1
+20 1 1
+525 0 2
+836 1 0
+2094 0 1
+2213 0 3
+327 6 9
+1711 45 45
+837 1 1
+57 1 1
+1618 1 0
+1400 0 4
+254 2 0
+93 0 10
+755 6 0
+192 1 0
+2378 1 0
+1753 0 3
+644 14 14
+1244 4 0
+30 1 1
+1136 14 14
+2450 0 4
+3624 3 31
+456 14 14
+1076 8 7
+68 1 1
+20 1 1
+145 1 1
+68 0 1
+12 1 0
+10 1 0
+11 0 1
+35 0 1
+5 1 0
+11 2 1
+32 7 6
+35 0 1
+8722 0 1
+888 4 0
+456 0 3
+45 1 0
+151 13 13
+756 1 0
+203 7 8
+140 1 1
+20 1 1
+308 0 5
+1020 1 0
+1258 1 0
+160 2 0
+1411 1 1
+22 1 1
+1180 12 12
+4521 2 0
+1153 0 27
+4956 0 3
+1392 1 1
+47 1 1
+3854 1 2
+130 0 1
+2633 0 2
+3030 1 0
+2343 1 0
+1748 45 0
+731 0 2
+1336 11 9
+3899 6 0
+436 0 1
+981 1 0
+1326 1 0
+382 0 4
+1081 0 10
+81 1 1
+142 2 0
+5976 1 1
+26 1 1
+377 22 22
+86 1 0
+55 1 1
+93 1 1
+374 4 0
+38 6 0
+3944 0 347
+1034 1 1
+27 1 1
+60 0 2
+2581 0 3
+3882 4 0
+1790 1 0
+20 1 1
+356 0 1
+4244 5 5
+36 1 1
+2232 2 2
+42 1 1
+4462 2 0
+1611 0 1
+1290 2 0
+110 0 1
+1466 1 0
+357 0 3
+850 0 12
+13547766 1 0
+3724943 0 2
+46473408 1 0
+1696 1 1
+28 1 1
+1629 4 0
+666 0 4
+13464 12874 30000
+8520008 0 2
+1107 1 1
+15 1 1
+1892 4 0
+6798 2 0
+1793 1 1
+25 3 0
+421 0 389
+787 0 2
+545 2 0
+54 0 1
+143 1 1
+39 1 1
+89 1 1
+29 0 1
+171 1 1
+46 0 1
+192 1 1
+33 1 1
+336 18 18
+2226 1 0
+107 1 1
+29 1 1
+218 0 1
+175 5 6
+1407 1 1
+52 1 1
+8851 0 1
+14427 0 4
+1737 0 22
+5806 0 1
+1115 1 1
+29 2 0
+3395 1 0
+386 38 38
+2740 2 0
+522 0 1
+24 1 1
+658 0 4
+5724 9 9
+1209 1 0
+5380 0 1
+97 0 1
+853 0 4
+79 11 5
+2728 7 6
+3754 13 17
+1363 0 1
+1025 0 1
+1811 1 0
+7507 4 0
+1184 0 3
+763 0 1
+797 0 3
+293 0 2
+2488 1 0
+335 1 0
+9959 0 1
+3255 0 1
+1322 1 0
+8118 0 2
+3326 0 2
+632 0 1
+63 5 0
+1886 12 12
+1110 1 0
+9582 1 0
+14742673 3013 0
+39686
+
+chain 9245037 chr4 191154276 + 8829368 8925617 chr4_random 842648 + 239789 336038 353
+96249
+
+chain 1255876 4 191154276 + 9214880 9257600 chr4 191273063 + 8933741 8943231 721
+156 22 22
+1030 14 14
+303 27 27
+166 4935 184
+220 23 24
+72 54 54
+771 13 13
+270 4744 0
+2627 17 17
+289 4743 0
+890 4745 0
+772 9500 0
+268 4749 1
+266 11 11
+1023
+
+chain 912330 4 191154276 + 9211690 9265763 chr4 191273063 + 8940042 8979863 947
+75 220 220
+51 122 122
+54 54 54
+51 167 167
+180 47 47
+70 24 24
+94 37 37
+257 59 59
+316 11 11
+163 60 60
+53 61 61
+95 21 21
+109 24 24
+217 32 32
+186 47 47
+233 1926 1924
+88 13 13
+123 125 126
+1453 4747 0
+2227 0 1
+278 535 535
+213 87 87
+92 7 7
+755 18715 9222
+268 6439 6434
+1089 14 14
+243 9 9
+78 4 4
+157 214 209
+200 23 24
+72 5972 5972
+655 413 413
+1441 14 14
+243 9 9
+78 4 4
+157 213 209
+200 23 24
+72 54 54
+771 13 13
+119 17 17
+221
+
+chain 676976 4 191154276 + 191033807 191044200 chr4 191273063 - 191263147 191273063 1558
+68 4 0
+34 1 1
+323 3 3
+31 1 1
+807 1 1
+26 1 1
+526 2 3
+34 1 0
+704 1 0
+6 1 0
+240 1 0
+237 2 0
+8 1 1
+371 10 0
+264 1 0
+205 1 1
+57 1 0
+601 1 1
+15 1 1
+1214 4 8
+1661 3 0
+94 1 1
+50 1 1
+355 15 15
+638 1 1
+54 1 1
+54 8 9
+323 67 9
+85 0 1
+96 1 1
+58 1 1
+35 1 0
+31 1 1
+86 1 1
+30 1 1
+76 1 1
+40 1 1
+121 282 27
+49 53 0
+63 92 0
+52
+
+chain 512088 4 191154276 + 8956990 9037962 chr4 191273063 + 9100119 9179836 26299
+71 118 113
+60 152 152
+88 33 33
+136 71 71
+85 43 43
+87 66 66
+92 87 87
+88 187 185
+156 1 81
+67 128 129
+76 143 143
+50 44 44
+212 52 52
+64 13 16
+267 79 79
+284 58 58
+51 76 76
+51 94 91
+55 77 77
+95 15 15
+74 251 251
+116 107 28
+64 188 188
+77 4 4
+113 11 11
+62 44 44
+102 237 237
+154 79 79
+58 86 86
+53 39 39
+50 36 35
+412 36 36
+75 225 225
+313 30 30
+54 84 83
+69 156 147
+104 89 77
+54 162 162
+226 16 16
+95 26 26
+60 14 14
+59 8 8
+120 7 7
+162 67 67
+65 210 210
+112 204 203
+63 53 53
+50 140 139
+127 143 143
+149 97 97
+88 61282 60044
+56 370 381
+50 56 56
+84 370 368
+52 288 288
+54 25 25
+72 923 933
+55 768 765
+68 70 70
+52 196 196
+62 305 305
+50 43 43
+129 114 114
+53 66 65
+116 411 423
+58 314 324
+68 0 1
+123 0 1
+53 58 59
+116 401 399
+539 6 0
+397 18 18
+60 211 211
+55 175 175
+63 553 556
+55 10 10
+53 1024 1003
+58 34 34
+81 43 43
+75 9 9
+51 1 0
+69
+
+chain 476298 4 191154276 + 9230645 9271936 chr4 191273063 + 8940012 8967053 893
+192 87 88
+429 187 187
+754 4750 6
+744 23 25
+2003 14 14
+246 42 42
+74 48 48
+71 104 104
+291 226 226
+81 4533 4529
+47 562 562
+111 285 285
+89 35 35
+2637 17 17
+240 9 9
+78 4 4
+157 215 209
+179 17 17
+100 4802 54
+343 13 13
+785 10920 6171
+1114 17 17
+243 6 6
+58 2 1
+272 1 0
+404 10 10
+1194 31 31
+266 11 11
+770 21 21
+327
+
+chain 377656 4 191154276 + 9257600 9267189 chr4 191273063 + 8933740 8938580 708
+1209 17 17
+571 1 0
+1617 4779 31
+1395
+
+chain 310844 4 191154276 + 9241835 9252105 chr4 191273063 + 8941714 8947231 850
+2726 14 14
+243 9 9
+78 4 4
+157 213 211
+265 85 85
+524 4751 0
+379 283 283
+539
+
+chain 275688 4 191154276 + 190986479 190989396 chr4 191273063 + 191223755 191226674 1129
+58 2 0
+265 1 0
+205 0 1
+208 4 5
+205 1 0
+122 55 53
+54 0 1
+411 25 25
+282 1 0
+419 14 20
+585
+
+chain 164691 4 191154276 + 9225860 9240813 chr4 191273063 + 8954210 8973910 1376
+232 87 87
+216 5946 5946
+93 12 12
+116 46 46
+231 32 32
+884 2511 7257
+718 3769 3770
+60
+
+chain 136190 4 191154276 + 9219745 9221340 chr4 191273063 + 8971822 8973417 7780
+1090 14 14
+243 9 9
+78 80 80
+81
+
+chain 127110 4 191154276 + 9223074 9241806 chr4 191273063 + 8960913 8979648 1585
+266 11 11
+4 10400 10401
+206 20 21
+668 26 27
+395 17 17
+14 6682 6682
+23
+
+chain 113888 4 191154276 + 59794841 59796661 chr7 158821424 + 43068053 43069865 1124766
+203 13 13
+161 140 141
+116 42 42
+240 178 178
+142 63 63
+254 11 11
+90 67 58
+100
+
+chain 91306 4 191154276 + 9218608 9227700 chr4 191273063 + 8961194 8975031 2525
+1019 3329 8072
+118 4492 4494
+89 35 35
+10
+
+chain 70288 4 191154276 + 9018276 9021043 chr11 134452384 - 130908986 130911761 1790585
+117 359 362
+150 330 330
+55 237 237
+99 73 73
+100 253 253
+70 73 78
+137 311 312
+72 249 248
+82
+
+chain 69967 4 191154276 + 8969559 8971297 chr11 134452384 - 66940622 66942298 1798470
+59 244 176
+78 49 49
+76 0 4
+72 217 218
+85 102 102
+264 12 12
+52 246 247
+66 24 24
+92
+
+chain 66013 4 191154276 + 9271936 9272654 chr4 191273063 + 8948073 8948792 572417
+692 0 1
+26
+
+chain 45624 4 191154276 + 9079872 9084019 chr4 191273063 - 187198263 187202501 2810559
+137 1640 1673
+114 79 83
+52 281 281
+64 700 698
+99 226 253
+83 576 605
+96
+
+chain 42774 4 191154276 + 9272654 9274373 chr4 191273063 + 8958282 8960000 1428
+395 17 17
+243 6 6
+329 3 2
+726
+
+chain 41852 4 191154276 + 9086638 9087081 chr1 247249719 - 105679719 105680162 3102182
+443
+
+chain 32596 4 191154276 + 9003477 9005348 chr8 146274826 + 6937943 6939835 4188535
+92 357 358
+96 443 443
+52 521 541
+122 129 129
+59
+
+chain 27953 4 191154276 + 9001038 9001387 chr11 134452384 - 130891915 130892264 5650797
+153 24 24
+85 11 11
+76
+
+chain 25460 4 191154276 + 1547039 1548332 chr4 191273063 + 1517808 1518962 1406869
+132 196 194
+8 33 0
+58 94 94
+33 400 430
+53 219 85
+67
+
+chain 23919 4 191154276 + 9060276 9060815 chrX 154913754 - 61464264 61464816 7738233
+150 249 262
+51 8 8
+81
+
+chain 23663 4 191154276 + 9250380 9252971 chr4 191273063 + 8954996 8957588 1596
+343 1382 1382
+494 21 21
+330 20 21
+1
+
+chain 23348 4 191154276 + 8954155 8955149 chr13 114142980 + 67377165 67378170 8084807
+108 119 119
+58 448 459
+78 128 128
+55
+
+chain 23051 4 191154276 + 9178657 9179321 chr8 146274826 - 138181840 138182484 8260527
+67 301 281
+58 86 86
+152
+
+chain 21854 4 191154276 + 9064978 9065877 chr1 247249719 + 159299736 159300622 9096955
+140 389 376
+61 239 239
+70
+
+chain 20302 4 191154276 + 59794670 59795934 chr19 63811651 - 51831683 51832948 1313667
+101 447 447
+6 69 70
+65 116 116
+17 4 4
+21 351 351
+67
+
+chain 19591 4 191154276 + 9123525 9124535 chr8 146274826 - 133912952 133913964 10789494
+68 696 699
+88 66 65
+92
+
+chain 17609 4 191154276 + 9152849 9153208 chr8 146274826 - 133934464 133934826 12466518
+149 157 160
+53
+
+chain 17420 4 191154276 + 9097653 9099623 chr11 134452384 - 51628045 51630034 12637575
+61 831 818
+58 894 926
+126
+
+chain 17154 4 191154276 + 8944061 8944687 chr3 199501827 - 68270290 68270918 12891537
+94 361 363
+56 52 52
+63
+
+chain 16449 4 191154276 + 9179756 9180625 chr8 146274826 + 7630543 7631403 13585678
+50 232 222
+54 427 428
+106
+
+chain 16159 4 191154276 + 9066614 9068459 chr16 88827254 - 83675354 83677175 13878826
+62 1020 1018
+99 597 575
+67
+
+chain 16115 4 191154276 + 9109381 9109952 chr21 46944323 + 28460282 28460853 13923553
+84 119 119
+62 249 249
+57
+
+chain 15306 4 191154276 + 8980490 8981996 chr4 191273063 - 187061282 187061823 14745791
+66 1267 302
+72 36 36
+65
+
+chain 15299 4 191154276 + 9056645 9056806 chr7 158821424 - 61471183 61471344 14752363
+161
+
+chain 14776 4 191154276 + 8950227 8950452 chr10 135374737 - 120304145 120304370 15312555
+84 55 55
+86
+
+chain 14403 4 191154276 + 9126194 9127408 chr5 180857866 - 26856190 26857401 15732261
+94 264 256
+54 752 757
+50
+
+chain 14224 4 191154276 + 8969618 8970298 chr11 134452384 - 67220551 67221216 1931088
+4 94 93
+78 397 383
+107
+
+chain 14155 4 191154276 + 9145781 9146043 chrX 154913754 - 45908091 45908403 16013758
+81 98 148
+83
+
+chain 14099 4 191154276 + 9060197 9060675 chr3 199501827 + 53477967 53478452 7798477
+58 172 171
+90 137 145
+21
+
+chain 13997 4 191154276 + 9005833 9006439 chr8 146274826 - 139204211 139204817 16201090
+60 438 438
+108
+
+chain 13823 4 191154276 + 8945988 8946280 chr4 191273063 + 9373057 9373350 16411372
+60 133 134
+99
+
+chain 13439 4 191154276 + 8975637 8975779 chr3 199501827 + 126919507 126919649 16900342
+142
+
+chain 12765 4 191154276 + 9077064 9077200 chr1 247249719 - 177698311 177698447 17836871
+136
+
+chain 12497 4 191154276 + 8950452 8951505 chr4 191273063 - 187091946 187092996 17010995
+3 953 950
+97
+
+chain 12348 4 191154276 + 8983189 8983604 chr8 146274826 - 138673776 138674197 18460871
+61 268 274
+86
+
+chain 11880 4 191154276 + 8972496 8973020 chr14 106368585 - 55089898 55090495 19186930
+61 378 451
+85
+
+chain 11818 4 191154276 + 9096126 9096305 chr11 134452384 - 67086036 67086266 19295429
+55 42 93
+82
+
+chain 11496 4 191154276 + 8948423 8949198 chr12 132349534 + 50778185 50778960 19846856
+94 629 629
+52
+
+chain 11391 4 191154276 + 8947143 8947401 chr8 146274826 - 134472454 134472711 20027902
+53 123 122
+82
+
+chain 11111 4 191154276 + 9107828 9107946 chr16 88827254 + 2897686 2897804 20531108
+118
+
+chain 10916 4 191154276 + 9261701 9262066 chr4 191273063 + 8952078 8952443 1072
+365
+
+chain 10832 4 191154276 + 8994164 8994326 chr6 170899992 - 100664994 100665156 21051510
+55 36 36
+71
+
+chain 10756 4 191154276 + 8943247 8943361 chr4 191273063 + 9116977 9117091 21193988
+114
+
+chain 10679 4 191154276 + 191030273 191030443 chr3 199501827 + 127002379 127002551 21342971
+68 44 46
+58
+
+chain 10668 4 191154276 + 1582572 1582681 chr4 191273063 + 1552756 1552865 12282737
+109
+
+chain 10529 4 191154276 + 191032229 191032410 chr11 134452384 + 3430296 3430477 21654608
+64 55 55
+62
+
+chain 10273 4 191154276 + 9096703 9097008 chr3 199501827 + 187858881 187859186 22199926
+64 181 181
+60
+
+chain 10137 4 191154276 + 9099965 9100095 chr6 170899992 - 166526436 166526567 22497437
+61 12 13
+57
+
+chain 10052 4 191154276 + 9066676 9066805 chr10 135374737 - 108696851 108696974 16846521
+41 9 9
+20 6 0
+53
+
+chain 9949 4 191154276 + 8999157 8999260 chr6 170899992 + 1823421 1823524 22925909
+103
+
+chain 9823 4 191154276 + 9071238 9072065 chr19 63811651 - 22299002 22299820 23218142
+65 697 688
+65
+
+chain 9746 4 191154276 + 8950613 8951219 chr7 158821424 - 151976579 151977185 23399634
+66 481 481
+59
+
+chain 9713 4 191154276 + 9012936 9013126 chrX 154913754 + 119487462 119487653 23485630
+58 74 75
+58
+
+chain 9679 4 191154276 + 9083038 9083589 chr12 132349534 + 77527128 77527707 10056562
+24 185 212
+17 262 263
+63
+
+chain 9579 4 191154276 + 9105290 9105637 chr8 146274826 - 6609 6954 23801877
+63 229 227
+55
+
+chain 9552 4 191154276 + 8956536 8957179 chr8 146274826 - 139187457 139188099 13944787
+92 234 234
+51 240 239
+26
+
+chain 9532 4 191154276 + 8978497 8978597 chr21 46944323 - 3695413 3695513 23932747
+100
+
+chain 9412 4 191154276 + 9108273 9108605 chr2 242951149 + 34780701 34781033 24211634
+61 216 216
+55
+
+chain 9361 4 191154276 + 9207159 9207725 chr7 158821424 + 92958588 92959148 24306771
+65 445 439
+56
+
+chain 9304 4 191154276 + 8946418 8946780 chr13 114142980 + 45938942 45939304 24422281
+63 247 247
+52
+
+chain 9136 4 191154276 + 9129485 9129655 chr1 247249719 - 82404984 82405154 24736407
+59 59 59
+52
+
+chain 9105 4 191154276 + 8982741 8983189 chr10 135374737 - 120304868 120305301 22041837
+59 380 365
+9
+
+chain 8777 4 191154276 + 9118310 9118402 chr11 134452384 - 67092191 67092283 25280535
+92
+
+chain 8617 4 191154276 + 59794359 59794524 chrX 154913754 + 69736929 69737094 2995761
+75 86 86
+4
+
+chain 8389 4 191154276 + 9219628 9219725 chr4 191273063 + 8933741 8933838 871949
+97
+
+chain 8260 4 191154276 + 8989895 8989983 chr4 191273063 + 9362532 9362620 26013719
+88
+
+chain 8131 4 191154276 + 9102626 9102711 chr4 191273063 - 187087880 187087965 26219988
+85
+
+chain 7754 4 191154276 + 190986383 190986479 chr10 135374737 + 135327923 135328019 562
+96
+
+chain 7688 4 191154276 + 8999849 9001530 chr8 146274826 + 7459813 7461495 7287525
+76 15 15
+50 236 236
+59 1157 1158
+88
+
+chain 7445 4 191154276 + 1642823 1642928 chr4 191273063 + 1612696 1612801 10569689
+105
+
+chain 7390 4 191154276 + 9235101 9235376 chr4 191273063 + 8934980 8935255 884
+275
+
+chain 6985 4 191154276 + 9132536 9132609 chr10 135374737 + 82556085 82556158 28236044
+73
+
+chain 6957 4 191154276 + 9079830 9084724 chr8 146274826 - 133860764 133864463 3584848
+42 1125 1126
+68 534 536
+50 1109 1111
+56 1741 541
+169
+
+chain 6924 4 191154276 + 9086283 9086357 chr3 199501827 + 28200221 28200295 17749225
+74
+
+chain 6522 4 191154276 + 59794524 59794670 chr4 191273063 + 131104023 131104168 2551460
+51 42 41
+53
+
+chain 6459 4 191154276 + 191029213 191029282 chr11 134452384 - 63299390 63299459 29377341
+69
+
+chain 6349 4 191154276 + 8971797 8971864 chr9 140273252 + 68477506 68477573 29649127
+67
+
+chain 6310 4 191154276 + 1548554 1548645 chr4 191273063 + 1518821 1518912 10939184
+91
+
+chain 6297 4 191154276 + 59793454 59794143 chr3 199501827 - 40571037 40571724 2330420
+79 562 560
+48
+
+chain 6221 4 191154276 + 9064020 9064085 chr16 88827254 - 83673859 83673924 29990023
+65
+
+chain 6094 4 191154276 + 9110081 9110145 chr1 247249719 + 181849295 181849359 30306899
+64
+
+chain 6086 4 191154276 + 191030472 191030537 chr11 134452384 - 75925756 75925821 30317869
+65
+
+chain 5966 4 191154276 + 9104473 9104535 chr11 134452384 + 71003965 71004027 30644952
+62
+
+chain 5912 4 191154276 + 8947661 8947723 chr9 140273252 - 2802727 2802789 30796182
+62
+
+chain 5903 4 191154276 + 9101296 9101358 chr4 191273063 + 9087606 9087668 30814689
+62
+
+chain 5842 4 191154276 + 9036574 9036668 chr4 191273063 - 85960898 85960992 17872768
+94
+
+chain 5712 4 191154276 + 9132160 9132220 chr12 132349534 + 8264132 8264192 31330015
+60
+
+chain 5710 4 191154276 + 191042876 191042934 chr4 191273063 - 191272139 191272197 15878613
+58
+
+chain 5622 4 191154276 + 9070424 9070484 chr3 199501827 - 68123367 68123427 31584493
+60
+
+chain 5594 4 191154276 + 1547006 1547408 chr4 191273063 + 1517841 1518435 2949224
+33 336 530
+7 8 6
+18
+
+chain 5494 4 191154276 + 8989383 8989441 chr10 135374737 + 82555871 82555929 31956576
+58
+
+chain 5493 4 191154276 + 9123841 9123899 chr3 199501827 - 55547554 55547612 22296298
+58
+
+chain 5485 4 191154276 + 9108193 9108251 chr17 78774742 + 49845783 49845841 31992260
+58
+
+chain 5354 4 191154276 + 9123785 9123841 chr19 63811651 + 46743056 46743112 26997396
+56
+
+chain 5287 4 191154276 + 191044097 191044231 chr11 134452384 + 134452193 134452328 8509115
+51 52 53
+31
+
+chain 5247 4 191154276 + 1642928 1642982 chr4 191273063 + 1612682 1612736 32710536
+54
+
+chain 5146 4 191154276 + 9109529 9109584 chr3 199501827 + 191350023 191350078 20827932
+55
+
+chain 5102 4 191154276 + 9012475 9012528 chr7 158821424 - 61434988 61435041 33179954
+53
+
+chain 4979 4 191154276 + 59793133 59793454 chr14 106368585 + 47992116 47992437 1636209
+52 1 1
+72 116 116
+45 1 1
+34
+
+chain 4919 4 191154276 + 59793533 59793585 chr1 247249719 + 177132715 177132767 25644257
+52
+
+chain 4894 4 191154276 + 8980336 8980388 chr8 146274826 - 134343460 134343512 33871905
+52
+
+chain 4776 4 191154276 + 59793593 59793649 chr8 146274826 + 78720544 78720600 25267381
+56
+
+chain 4646 4 191154276 + 9032086 9032149 chr11 134452384 - 67001981 67002044 11075042
+63
+
+chain 4523 4 191154276 + 9083642 9083690 chr4 191273063 + 9229696 9229744 33561479
+48
+
+chain 4481 4 191154276 + 9110034 9110081 chr1 247249719 + 117212387 117212434 31311635
+47
+
+chain 4466 4 191154276 + 8975249 8975296 chr4 191273063 + 9087559 9087606 34734206
+47
+
+chain 4380 4 191154276 + 9065601 9065685 chr14 106368585 - 65288844 65288928 12690014
+84
+
+chain 4316 4 191154276 + 8994219 8994386 chr9 140273252 - 20618312 20618467 21123765
+25 83 71
+59
+
+chain 4224 4 191154276 + 1548697 1548764 chr4 191273063 + 1518798 1518831 14337246
+14 34 0
+19
+
+chain 4196 4 191154276 + 59793649 59793759 chr3 199501827 - 110817223 110817333 10064550
+110
+
+chain 4174 4 191154276 + 9006462 9006529 chr3 199501827 - 68301162 68301229 17546615
+67
+
+chain 4160 4 191154276 + 9087190 9087234 chr3 199501827 + 69469088 69469132 19451262
+44
+
+chain 4035 4 191154276 + 59793991 59794095 chr4 191273063 - 43511377 43511481 1601554
+104
+
+chain 3949 4 191154276 + 59793891 59793960 chr7 158821424 - 5091499 5091568 15707336
+69
+
+chain 3917 4 191154276 + 59794575 59794617 chr19 63811651 + 46686810 46686852 11955254
+42
+
+chain 3916 4 191154276 + 9180332 9180405 chr8 146274826 + 7130141 7130214 14314247
+73
+
+chain 3790 4 191154276 + 9231440 9231540 chr4 191273063 + 8950300 8950400 218917
+92 7 7
+1
+
+chain 3686 4 191154276 + 59793772 59793811 chr15 100338915 + 77825223 77825262 17426618
+39
+
+chain 3659 4 191154276 + 9096554 9096861 chr3 199501827 - 6400721 6401028 23757316
+67 190 190
+50
+
+chain 3657 4 191154276 + 59794470 59794516 chr6 170899992 - 3232006 3232052 26376367
+46
+
+chain 3647 4 191154276 + 1557695 1557733 chr4 191273063 + 1527878 1527916 12331685
+38
+
+chain 3642 4 191154276 + 9109808 9109863 chr6 170899992 - 83529676 83529731 23755843
+55
+
+chain 3437 4 191154276 + 9178724 9179540 chr12 132349534 + 34224690 34225504 10931865
+32 667 665
+117
+
+chain 3342 4 191154276 + 9274373 9274605 chr4 191273063 + 8969490 8969722 4902
+232
+
+chain 3310 4 191154276 + 8971045 8971455 chr9 140273252 - 10330739 10331149 20511421
+70 288 288
+52
+
+chain 3302 4 191154276 + 1548711 1548745 chr4 191273063 + 1518614 1518648 32145222
+34
+
+chain 3283 4 191154276 + 9102560 9102594 chr10 135374737 - 120311822 120311856 35225233
+34
+
+chain 3261 4 191154276 + 8994091 8994458 chr8 146274826 + 9742146 9742512 23065618
+62 246 245
+59
+
+chain 3172 4 191154276 + 59794789 59794841 chr3 199501827 - 24852035 24852087 14612523
+52
+
+chain 3108 4 191154276 + 9060565 9060615 chr13 114142980 - 41995201 41995251 9632166
+50
+
+chain 3078 4 191154276 + 1548520 1548554 chr4 191273063 + 1518360 1518394 5794973
+34
+
+chain 3017 4 191154276 + 9065206 9065807 chr10 135374737 + 117208692 117209275 9578047
+65 480 462
+56
+
+chain 2924 4 191154276 + 59795756 59795800 chr5 180857866 + 175080369 175080413 1478283
+44
+
+chain 2887 4 191154276 + 59793960 59793991 chr2 242951149 - 7484272 7484303 15380677
+31
+
+chain 2846 4 191154276 + 9001603 9001654 chr8 146274826 - 133764474 133764525 19750221
+51
+
+chain 2767 4 191154276 + 8957324 8957381 chr4 191273063 + 9129618 9129675 15542671
+57
+
+chain 2754 4 191154276 + 9087109 9087190 chr6 170899992 + 92706078 92706159 16313416
+81
+
+chain 2673 4 191154276 + 9065350 9065411 chr1 247249719 - 53009045 53009106 13821618
+61
+
+chain 2622 4 191154276 + 59793258 59793374 chr14 106368585 + 42536813 42536929 1616879
+116
+
+chain 2598 4 191154276 + 59795229 59795281 chr6 170899992 + 57310821 57310873 1524793
+52
+
+chain 2565 4 191154276 + 190987578 190987605 chr4 191273063 + 191231440 191231467 2372
+27
+
+chain 2557 4 191154276 + 9066521 9067027 chr12 132349534 + 72855206 72855711 22561893
+55 378 377
+73
+
+chain 2500 4 191154276 + 9083457 9083524 chr8 146274826 + 32149594 32149661 28386486
+67
+
+chain 2474 4 191154276 + 1651689 1651722 chr4 191273063 + 1621541 1621574 19254204
+33
+
+chain 2389 4 191154276 + 9036810 9036873 chr2 242951149 - 1691358 1691421 23135357
+63
+
+chain 2338 4 191154276 + 59796505 59796540 chr17 78774742 + 47057876 47057911 2877115
+35
+
+chain 2291 4 191154276 + 9216761 9217155 chr8 146274826 - 133997030 133997425 4114277
+45 320 321
+29
+
+chain 2265 4 191154276 + 9065418 9065482 chr9 140273252 + 44106224 44106288 9767431
+64
+
+chain 2116 4 191154276 + 8944155 8944177 chr3 199501827 + 126918676 126918698 25172225
+22
+
+chain 2099 4 191154276 + 9099268 9099290 chr2 242951149 + 169698626 169698648 26708137
+22
+
+chain 2025 4 191154276 + 9097343 9097409 chr3 199501827 + 179409375 179409441 24047564
+66
+
+chain 2003 4 191154276 + 9108252 9108273 chr2 242951149 - 190846639 190846660 24998179
+21
+
+chain 1997 4 191154276 + 9146164 9146218 chr15 100338915 - 2487154 2487208 24249848
+54
+
+chain 1870 4 191154276 + 190988070 190988095 chr10 135374737 + 135329605 135329630 1377
+25
+
+chain 1826 4 191154276 + 8957935 8957992 chr4 191273063 + 9362404 9362461 11066413
+57
+
+chain 1826 4 191154276 + 9097476 9098043 chr12 132349534 - 122338357 122338925 15828070
+57 424 425
+86
+
+chain 1767 4 191154276 + 8990059 8990106 chr1 247249719 + 148949220 148949267 26452494
+47
+
+chain 1744 4 191154276 + 59793037 59793133 chr3 199501827 + 30427927 30428023 1883621
+96
+
+chain 1736 4 191154276 + 9086392 9087109 chr4 191273063 - 127153063 127153784 14070511
+50 639 643
+28
+
+chain 1668 4 191154276 + 9124660 9124729 chr4 191273063 + 9269820 9269889 23245150
+69
+
+chain 1556 4 191154276 + 9060815 9060839 chr10 135374737 - 108080722 108080746 12503169
+24
+
+chain 1546 4 191154276 + 9180153 9180207 chr8 146274826 - 138844855 138844909 16808195
+54
+
+chain 1517 4 191154276 + 59794322 59794359 chr11 134452384 - 119842384 119842421 16271509
+37
+
+chain 1488 4 191154276 + 59796097 59796124 chr9 140273252 + 9925299 9925326 2265670
+27
+
+chain 1436 4 191154276 + 191043722 191043759 chr1 247249719 - 247249574 247249611 18645625
+37
+
+chain 1374 4 191154276 + 9065276 9065337 chr1 247249719 - 201083821 201083882 10540800
+61
+
+chain 1348 4 191154276 + 9109064 9109144 chr2 242951149 - 126292213 126292293 15140626
+80
+
+chain 1343 4 191154276 + 9146043 9146068 chr18 76117153 + 30068723 30068748 16305066
+25
+
+chain 1292 4 191154276 + 9123899 9123951 chr4 191273063 - 148574019 148574071 20863102
+52
+
+chain 1290 4 191154276 + 9179321 9179368 chr11 134452384 + 3426025 3426072 10983647
+47
+
+chain 1231 4 191154276 + 59794434 59794461 chr5 180857866 + 147382264 147382291 9387523
+27
+
+chain 1177 4 191154276 + 9065884 9065939 chr9 140273252 - 70318092 70318147 10006368
+55
+
+chain 1097 4 191154276 + 9086357 9086392 chr1 247249719 - 129588705 129588740 16923174
+35
+
+chain 1085 4 191154276 + 9066380 9066450 chr13 114142980 + 68490318 68490388 22728993
+70
+
+chain 1083 4 191154276 + 9032737 9032804 chr13 114142980 + 26049760 26049827 24893033
+67
+
+chain 1011 4 191154276 + 9067073 9067124 chr10 135374737 - 108679092 108679143 23379890
+51
+
+chain 996 4 191154276 + 8971509 8971561 chr12 132349534 + 31168410 31168462 23661941
+52
+
+chain 963 4 191154276 + 9066836 9066890 chr1 247249719 - 151454542 151454596 25048936
+54
+
+chain 958 4 191154276 + 9145173 9145232 chr1 247249719 - 217919030 217919089 20381976
+59
+
+chain 937 4 191154276 + 8958092 8958125 chr11 134452384 + 67446107 67446140 12651114
+33
+
+chain 917 4 191154276 + 9146455 9146505 chr8 146274826 + 19957787 19957837 24577235
+50
+
+chain 910 4 191154276 + 9097602 9098317 chr2 242951149 - 190844271 190844995 14887788
+50 595 604
+70
+
+chain 894 4 191154276 + 9109146 9109219 chrX 154913754 - 13573867 13573940 23078019
+73
+
+chain 878 4 191154276 + 9178986 9179012 chr2 242951149 - 137542666 137542692 11507142
+26
+
+chain 871 4 191154276 + 9082368 9082425 chr3 199501827 - 78731030 78731087 22332859
+57
+
+chain 858 4 191154276 + 9098043 9099355 chr5 180857866 - 58871729 58873086 24126323
+56 1191 1236
+65
+
+chain 777 4 191154276 + 8955354 8955423 chr3 199501827 - 68281758 68281827 15856837
+69
+
+chain 715 4 191154276 + 191033511 191033568 chr7 158821424 + 30724536 30724593 23744345
+57
+
+chain 650 4 191154276 + 9126884 9126934 chr3 199501827 + 102896742 102896792 23688110
+50
+
+chain 507 4 191154276 + 59793857 59793890 chr8 146274826 + 107120151 107120184 20878932
+33
+
+chain 468 4 191154276 + 40297344 40297404 chr4 191273063 + 39972706 39972766 25333266
+60
+
+chain 438 4 191154276 + 9098988 9099041 chr4 191273063 - 56600577 56600630 25949595
+53
+
+chain 368 4 191154276 + 191031439 191031496 chr19 63811651 - 43557899 43557956 26568315
+57
+
+chain 315 4 191154276 + 8972631 8972682 chr12 132349534 - 123858147 123858198 26303923
+51
+
+chain 268 4 191154276 + 59793813 59793857 chr13 114142980 - 20847506 20847550 12435901
+44
+
+chain 209 4 191154276 + 9096427 9096486 chr3 199501827 - 25140168 25140227 30710814
+59
+
+chain 54948874 chr4_ctg9_hap1 590426 + 0 590426 chr4 191273063 + 68852671 69912764 73
+1837 0 2
+151607 0 469345
+122242 3 1
+4137 1 1
+70 1 1
+5254 0 2
+2782 48 48
+1074 0 2
+2825 0 5
+2047 2 0
+6949 1 1
+41 1 1
+232 0 1
+1965 12 0
+694 1 1
+22 1 0
+945 14 14
+416 1 1
+36 2 0
+75 1 1
+21 1 0
+52 1 1
+41 1 1
+144 1 1
+87 1 1
+71 1 1
+35 1 1
+145 0 1
+503 1 1
+88 1 1
+99 1 1
+30 1 1
+293 0 5
+360 19 19
+380 1 1
+23 1 1
+209 36 36
+557 10 10
+820 1 1
+38 1 1
+868 0 2
+227 0 353
+5432 0 1
+1459 1 0
+210 20 20
+125 8 0
+5 32 0
+65 0 2
+10 23 5
+240 0 1
+233 14 14
+1076 14 14
+100 1 1
+28 1 1
+199 0 1
+287 1 1
+36 1 0
+17 1 1
+132 1 1
+25 1 1
+193 1 0
+305 0 28
+50 0 1
+544 1 1
+40 4 0
+794 15 15
+179 1 1
+72 1 1
+142 1 1
+65 1 1
+364 0 1
+335 0 1
+52 4 4
+48 1 1
+934 1 1
+50 0 1
+44 1 1
+1074 1 1
+22 1 1
+286 4 0
+33 1 1
+303 1 1
+5 0 1
+63 1 1
+972 1 1
+69 1 1
+602 1 1
+25 1 1
+2469 5 5
+1033 1 1
+63 1 1
+233 0 3
+311 1 1
+29 1 1
+881 6 6
+123 15 16
+283 1 1
+39 1 1
+57 5 0
+613 1 1
+42 1 1
+1598 0 2
+730 1 1
+47 1 1
+459 1 1
+25 1 1
+775 7 7
+534 0 1
+1090 5 5
+375 1 1
+62 1 1
+133 15 15
+700 1 1
+36 4 0
+365 9 9
+468 1 1
+45 1 1
+1356 16 16
+422 1 0
+55 0 2
+7890 1 1
+30 1 1
+1445 1 1
+27 1 1
+96 4 0
+2114 10 11
+1940 2 0
+1687 1 1
+40 1 1
+1679 1 0
+734 0 1
+480 1 0
+7344 1 0
+3930 17 17
+1001 0 8
+216373
+
+chain 4430 chr4_ctg9_hap1 590426 + 287934 287982 chr4 191273063 + 69257952 69258000 221
+48
+
+chain 18001815 chr4_gl000193_random 189789 + 0 189789 chr4_random 842648 + 0 189789 149
+189789
+
+chain 18169122 chr4_gl000194_random 191469 + 0 191469 chr4_random 842648 + 440032 631501 148
+191469
+
+chain 16792065298 5 180915260 + 10000 180905260 chr5 180857866 + 63000 180837866 5
+17520657 50017 11
+356 84 84
+496 0 3434
+735 75 1475
+628 25 3459
+51 50 3484
+3427 1 1
+39 3 3437
+577 8 8
+167 44 1713
+23 0 3434
+1184 1 0
+46 1 0
+5 1 0
+266 1 1
+21 1 1
+763 16 16
+422 1 1
+29 1 1
+5243 1 1
+37 1 1
+978 1 1
+21 1 1
+116 16 3450
+1792 146 16585
+3079 0 1
+7857 9770 0
+1026 636 1
+7461 1 0
+23769 0 51
+4034 1 0
+20571 1 0
+9135 2 0
+6885 3 2
+110 0 3
+816 3 2
+2296 34 0
+7499 2 0
+2917 1 0
+652 1 1
+37 1 1
+657 1 1
+22 1 1
+419 4 3
+3580 1 1
+29 1 1
+274 35 11
+833 1 0
+1908 0 3038
+10504 1 1
+27 0 2
+784 6 0
+127 0 10
+668 1 1
+28 1 1
+2464 0 4
+182 2 0
+1650 1 1
+39 1 1
+2433 0 1
+720 1 1
+40 1 1
+772 1 1
+32 1 1
+353 1 1
+17 1 1
+1776 1 0
+6082 0 3
+2669 10 12
+2857 1 1
+35 1 1
+982 1 1
+173 1 1
+4115 1 1
+49 1 1
+702 1 1
+33 1 1
+2927 2 1
+1472 0 17
+1346 1 1
+35 1 1
+2068 1 1
+40 1 1
+828 1 1
+36 0 2
+317 0 8
+893 1 1
+33 0 1
+8145 4 0
+28632197 3000000 3000000
+12470071 1 0
+29760415 50000 40000
+5878002 20845 23000
+4521 0 1
+676 6 6
+5928 1 0
+372 1 1
+47 1 1
+6801 2 3
+639 1 0
+871 4 3
+11530 4 0
+22966 1 0
+15447 1 0
+53856 2 0
+15988 2 0
+906887 1 0
+8 2 2
+40152828 47715 0
+3526228 1 0
+1604 0 10
+12778810 51715 4100
+15152690 0 27
+1852098 0 1
+8710030
+
+chain 78758 5 180915260 + 17610410 17613099 chr5 180857866 + 17647305 17649997 1601642
+85 49 49
+57 201 201
+189 17 17
+78 77 77
+75 178 181
+116 179 179
+91 8 8
+51 298 300
+51 664 662
+64 26 26
+135
+
+chain 31383 5 180915260 + 97574240 97575427 chr4 191273063 - 170991967 170993160 4391624
+188 108 110
+89 705 709
+97
+
+chain 22831 5 180915260 + 97580590 97581374 chr2 242951149 - 86243998 86244777 8407693
+68 180 179
+95 326 322
+115
+
+chain 16108 5 180915260 + 97571166 97571372 chr3 199501827 + 12403992 12404198 13932022
+51 22 22
+133
+
+chain 10260 5 180915260 + 97573380 97573866 chrX 154913754 + 72466087 72466572 22227065
+67 357 356
+62
+
+chain 9281 5 180915260 + 97573916 97574127 chr3 199501827 - 17931346 17931561 24462523
+61 98 102
+52
+
+chain 8534 5 180915260 + 17581030 17583073 chr5 180857866 + 17608062 17614939 1974
+70 1948 6782
+25
+
+chain 7377 5 180915260 + 17614165 17614243 chr8 146274826 + 118652818 118652896 27454171
+78
+
+chain 7140 5 180915260 + 97574682 97574775 chr9 140273252 + 18188007 18188100 13076039
+11 6 6
+76
+
+chain 6854 5 180915260 + 97574980 97575063 chr2 242951149 + 163688921 163689004 19449593
+83
+
+chain 6104 5 180915260 + 97573580 97573645 chrX 154913754 + 86697567 86697632 30283885
+65
+
+chain 5931 5 180915260 + 97571838 97571901 chr11 134452384 + 21528921 21528984 30747470
+63
+
+chain 5358 5 180915260 + 97565266 97565323 chr3 199501827 + 123413571 123413628 32371600
+57
+
+chain 5211 5 180915260 + 97574626 97575600 chr2 242951149 - 205065194 205066172 4657168
+56 746 750
+172
+
+chain 4836 5 180915260 + 97570927 97570987 chr12 132349534 + 79028695 79028755 21429371
+60
+
+chain 3976 5 180915260 + 97580463 97580554 chrX 154913754 + 120621333 120621424 19038460
+91
+
+chain 3896 5 180915260 + 17583124 17583167 chr5 180857866 + 17601254 17601297 1526
+43
+
+chain 3528 5 180915260 + 97573879 97573916 chr4 191273063 - 42047288 42047325 31874217
+37
+
+chain 3107 5 180915260 + 97574479 97575651 chr2 242951149 + 88874356 88875531 4418505
+53 767 770
+31 271 271
+50
+
+chain 3026 5 180915260 + 97580178 97580228 chr15 100338915 - 8217824 8217874 19735797
+50
+
+chain 2922 5 180915260 + 97575231 97575262 chr5 180857866 - 151978291 151978322 11789776
+31
+
+chain 2640 5 180915260 + 97575132 97575230 chr6 170899992 - 85176442 85176540 6161475
+98
+
+chain 2605 5 180915260 + 97580235 97580338 chr6 170899992 - 161277959 161278062 12089137
+103
+
+chain 2572 5 180915260 + 97580955 97581020 chr4 191273063 + 75087136 75087201 9159879
+65
+
+chain 2511 5 180915260 + 97573039 97573123 chr5 180857866 + 96582581 96582665 20564544
+84
+
+chain 2425 5 180915260 + 97580778 97580807 chr7 158821424 + 56235832 56235861 15947917
+29
+
+chain 2390 5 180915260 + 97580658 97580706 chr6 170899992 + 77924350 77924398 14557662
+48
+
+chain 2360 5 180915260 + 97575070 97575127 chr15 100338915 - 65496060 65496117 11267266
+57
+
+chain 2316 5 180915260 + 97574862 97574967 chr5 180857866 + 122822031 122822136 6403532
+105
+
+chain 2262 5 180915260 + 97575262 97575299 chr5 180857866 + 117084659 117084696 9926189
+37
+
+chain 2258 5 180915260 + 97570996 97571059 chr6 170899992 + 98788934 98788997 20073703
+63
+
+chain 2234 5 180915260 + 97575771 97575825 chr15 100338915 + 19192799 19192853 13777203
+54
+
+chain 2112 5 180915260 + 17598551 17598575 chr5 180857866 + 17621050 17621074 2441
+24
+
+chain 2082 5 180915260 + 97581410 97581440 chr5 180857866 - 81177483 81177513 18145628
+30
+
+chain 2013 5 180915260 + 97574428 97574456 chr6 170899992 + 12662047 12662075 5707452
+28
+
+chain 1804 5 180915260 + 97574815 97574862 chr7 158821424 + 102470537 102470584 21213680
+47
+
+chain 1676 5 180915260 + 97571668 97571723 chr9 140273252 - 49451145 49451200 15925569
+55
+
+chain 1630 5 180915260 + 97575847 97575921 chr14 106368585 + 65599248 65599322 16554081
+74
+
+chain 1394 5 180915260 + 17611593 17611672 chr5 180857866 - 163271537 163271616 20711197
+79
+
+chain 1250 5 180915260 + 97570872 97570926 chrX 154913754 + 128632888 128632942 22138126
+54
+
+chain 1212 5 180915260 + 17598429 17598472 chr5 180857866 - 163276581 163276624 866388
+43
+
+chain 683 5 180915260 + 97570493 97570549 chr4 191273063 + 125149085 125149141 22694892
+56
+
+chain 625 5 180915260 + 97572119 97572183 chr5 180857866 - 153619225 153619289 25061319
+64
+
+chain 466 5 180915260 + 97569261 97569351 chr7 158821424 - 120247996 120248086 22482305
+90
+
+chain 395 5 180915260 + 97572751 97572804 chr2 242951149 - 47300723 47300776 19687839
+53
+
+chain 15799169383 6 171115067 + 60000 171055067 chr6 170899992 + 5000 170896992 6
+1297281 1 0
+7806968 0 162987
+4013154 9 0
+261 13 15
+18786172 17 17
+439 16 16
+59 5 4
+32202 17 17
+439 16 16
+59 4 5
+15403 1 0
+13914169 4 0
+112 1 1
+17 1 1
+415 12 0
+105 6 3
+12160281 50000 50000
+642507 3100000 3050000
+248423 50000 50000
+2918791 1238 0
+9427508 4 4
+162 12 12
+2193 22 22
+293 1 1
+30 1 1
+845 1 0
+45 1 1
+9769 2 0
+6058 1 1
+24 1 1
+2223 1 1
+24 1 1
+182 12 12
+284 1 1
+20 1 1
+1035 7 36
+1007 1 1
+27 1 1
+3279 1 1
+44 0 1
+3012 1 0
+545 17 17
+2562 0 1
+251 0 1
+935 8 0
+37 1 1
+566 6 0
+1483 2 0
+1960 1 0
+4564 1 1
+25 1 1
+832 0 1
+801 8 8
+1131 1 1
+58 5 1
+6177 0 1
+3712 1 0
+2185 1 1
+35 1 1
+710 2 2
+78 1 1
+2201 1 1
+30 1 1
+283 1 1
+30 1 1
+448 1 0
+74814 2 2
+197 8 0
+2508456 1 0
+4641788 5 5
+37 1 1
+8503609 0 2
+5363169 150000 200000
+6040303 1 1
+36 1 0
+2020 1 1
+46 1 1
+1559 1 1
+72 1 1
+1098 1 1
+29 1 1
+264 7 7
+580 0 1
+30 1 1
+536 1 1
+41 1 1
+5663 1 0
+438 5 3
+354 1 1
+18 1 1
+9613 14 13
+1400 1 0
+176 0 2
+2742 1 0
+1968 0 1
+754 1 0
+4237 0 1
+2388 1 1
+31 1 0
+3385 0 1
+2004 8 0
+3395 0 3
+32 1 1
+4109 0 1
+1058 20 0
+1608 1 0
+17198424 17 26
+7835 0 1
+16317 11 0
+6277 64993 0
+6787989 0 1
+149 4 0
+949 4 0
+242 0 1
+28418215 1 1
+21 1 0
+3116903 171704 50000
+1939305 1 1
+19 0 2
+8192274 4 4
+122 0 2
+1127 1 0
+1102 75 0
+21 8 5
+30 29 0
+27 6 3
+62 52 0
+42 195105 18125
+950946 1 1
+51 157 1
+107 255 0
+714 513 0
+1285155 50000 150000
+725095
+
+chain 12021668 chr6 171115067 + 157540957 157712661 chr6_random 1875562 + 1435107 1512777 78
+18510 50000 5628
+31833 50000 338
+21361
+
+chain 8743144 chr6 171115067 + 167847224 167942073 chr6_random 1875562 - 1720470 1850468 378
+12768 1 1
+28 0 1
+17496 12 0
+7219 1 1
+29 1 1
+4716 0 1
+1645 0 4
+6037 1 1
+33 94 125
+10 3 3
+5171 1 0
+4453 734 36650
+3575 1 1
+26 1 1
+4697 13 13
+958 0 2
+228 0 2
+2465 13 13
+142 1 1
+15 1 0
+33 937 104
+94 0 1
+125 16 0
+5319 48 103
+897 0 3
+1130 0 3
+187 8 7
+67 26 25
+5876 1 1
+47 1 1
+1955 14 7
+575 36 36
+641 0 2
+1143 5 5
+3079
+
+chain 27931 6 171115067 + 168993335 168994451 chr6 170899992 + 168736232 168737615 1527785
+96 36 36
+16 0 51
+107 739 901
+51 0 54
+71
+
+chain 17101 6 171115067 + 119158013 119159004 chr8 146274826 + 76280127 76281098 12940826
+78 146 105
+78 622 643
+67
+
+chain 14766 6 171115067 + 119189669 119190286 chr7 158821424 - 68703788 68704409 15321990
+54 439 443
+124
+
+chain 13062 6 171115067 + 168994482 168994817 chr6 170899992 + 168736716 168737003 1274096
+205 50 2
+80
+
+chain 12205 6 171115067 + 119155128 119155329 chr8 146274826 - 70047959 70048173 18676577
+72 59 72
+70
+
+chain 11124 6 171115067 + 168993071 168993228 chr6 170899992 + 168736229 168736638 2160304
+29 1 52
+50 25 226
+52
+
+chain 10673 6 171115067 + 119159180 119160231 chr10 135374737 - 59595554 59596042 21356650
+62 913 350
+76
+
+chain 10669 6 171115067 + 119157022 119157134 chr14 106368585 + 59942933 59943045 21369163
+112
+
+chain 9554 6 171115067 + 119189632 119189818 chrX 154913754 + 133155010 133155200 16872824
+37 54 54
+12 31 35
+52
+
+chain 7928 chr6 171115067 + 167846995 167847141 chr6_random 1875562 + 628575 628698 120
+41 26 0
+57 0 3
+22
+
+chain 7384 chr6 171115067 + 167920474 167920550 chr6_random 1875562 - 1829156 1829232 27447594
+76
+
+chain 7241 6 171115067 + 119190390 119190581 chr13 114142980 + 101174758 101174949 23777400
+2 136 136
+53
+
+chain 6904 6 171115067 + 119156272 119156345 chr11 134452384 - 108078565 108078638 28375374
+73
+
+chain 6531 6 171115067 + 119159999 119160068 chr4 191273063 - 87162214 87162283 29199925
+69
+
+chain 5948 6 171115067 + 119160915 119160977 chrX 154913754 - 59556739 59556801 30709264
+62
+
+chain 5818 6 171115067 + 119158407 119158509 chr18 76117153 + 30261305 30261403 24322730
+1 51 47
+50
+
+chain 5749 6 171115067 + 119155939 119156000 chr6 170899992 + 92063509 92063570 31228902
+61
+
+chain 5103 6 171115067 + 119189831 119189885 chrX 154913754 - 76833525 76833579 33162260
+54
+
+chain 5032 6 171115067 + 119156645 119156719 chrX 154913754 + 87420725 87420799 20704812
+74
+
+chain 5002 6 171115067 + 119160862 119160914 chrX 154913754 + 56955255 56955307 33524497
+52
+
+chain 4995 6 171115067 + 168994451 168994737 chr6 170899992 + 168737201 168737385 2349016
+31 205 103
+50
+
+chain 4921 6 171115067 + 119156041 119156093 chr9 140273252 + 81227536 81227588 33775667
+52
+
+chain 4912 6 171115067 + 119160087 119160139 chr5 180857866 + 63815067 63815119 33803556
+52
+
+chain 3597 6 171115067 + 119157136 119157361 chr2 242951149 + 31758724 31758949 14786968
+84 78 78
+63
+
+chain 3223 6 171115067 + 119156854 119156913 chr15 100338915 - 54365651 54365710 24573102
+59
+
+chain 3204 6 171115067 + 119155364 119155420 chr6 170899992 - 73613724 73613780 24603360
+56
+
+chain 2966 6 171115067 + 119156499 119156577 chrX 154913754 - 137505405 137505483 21485501
+78
+
+chain 2728 6 171115067 + 119159004 119159033 chr3 199501827 - 198198433 198198462 28454448
+29
+
+chain 2528 6 171115067 + 119156618 119156645 chr11 134452384 + 82352593 82352620 34284540
+27
+
+chain 2454 6 171115067 + 119155233 119155259 chr9 140273252 + 122001720 122001746 35057240
+26
+
+chain 2315 6 171115067 + 119156723 119156806 chr4 191273063 + 116661391 116661474 16361102
+83
+
+chain 2146 6 171115067 + 119158341 119158407 chr6 170899992 + 115819766 115819832 17078055
+66
+
+chain 1866 6 171115067 + 119190053 119190120 chr5 180857866 + 56063062 56063129 22879278
+67
+
+chain 1656 6 171115067 + 119158523 119158602 chr11 134452384 + 2473635 2473714 18654554
+79
+
+chain 1624 6 171115067 + 119189898 119189948 chr4 191273063 - 66123378 66123428 24040914
+50
+
+chain 1451 6 171115067 + 119158163 119158229 chr15 100338915 - 64161282 64161348 22109122
+66
+
+chain 1209 6 171115067 + 168994304 168994329 chr6 170899992 + 168736283 168736308 2117199
+25
+
+chain 1198 6 171115067 + 119156176 119156250 chr5 180857866 + 3717928 3718002 22194292
+74
+
+chain 980 6 171115067 + 119158602 119158634 chr8 146274826 + 104450758 104450790 18747323
+32
+
+chain 943 6 171115067 + 119157563 119157614 chr2 242951149 + 163020248 163020299 23359839
+51
+
+chain 785 6 171115067 + 119156425 119156485 chr17 78774742 - 29484860 29484920 22136428
+60
+
+chain 779 6 171115067 + 119190333 119190390 chr3 199501827 - 104453282 104453339 22453017
+57
+
+chain 696 6 171115067 + 119158674 119158726 chr6 170899992 - 83894386 83894438 23403881
+52
+
+chain 689 6 171115067 + 119157650 119157707 chrX 154913754 + 101935638 101935695 24716105
+57
+
+chain 360 6 171115067 + 119160319 119160372 chr3 199501827 - 158113258 158113311 26359861
+53
+
+chain 282 6 171115067 + 119159242 119159272 chr19 63811651 + 46835118 46835148 25343818
+30
+
+chain 202629822 chr6_apd_hap1 4622290 + 0 4622290 chr6 170899992 + 28804582 33443471 49
+932 3 0
+804 0 1
+2406 2 0
+178370 1 0
+25289 44253 44253
+3450 0 1
+345 1 0
+3096 39 0
+16669 1 0
+48609 0 2
+2804 29384 29384
+14756 7 0
+1489 1 1
+72 1 1
+2260 0 2
+7033 0 8
+3588 0 1
+9760 32 32
+9786 0 1
+1324 0 2
+5438 5 0
+2061 2 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4746 9 9
+4767 7 7
+1225 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+249 43 43
+1178 0 4
+685 8 0
+48 4 0
+1144 87598 87598
+5106 2 0
+1514 0 1
+3116 0 1
+3278 1 1
+21 1 1
+1738 0 1
+8576 19 0
+8020 1 0
+2049 1 0
+518 13 11
+1704 1 1
+117 1 1
+1448 10 0
+4403 9 9
+2265 1 0
+8656 104192 104192
+1686 0 2
+5376 0 1
+19253 1 0
+7884 1 0
+21 0 6
+4451 1 0
+27910 1 0
+9946 0 1
+11233 1 1
+32 1 1
+2238 1 1
+20 1 1
+3659 22 16
+1218 1 0
+1638 6 6
+228 1 1
+45 1 1
+2048 0 2
+462 1 0
+20759 1 0
+3778 2 1
+1268 1 0
+1511 1 1
+42 2 0
+24 1 1
+4119 22 0
+1757 1 0
+1527 1 1
+29 1 1
+1886 1 0
+6666 0 4
+1349 0 4
+1102 10 8
+1463 34 31
+168 1 1
+21 1 1
+304 1 1
+31 1 1
+549 1 0
+5745 1 0
+5097 0 1
+534 1 1
+17 1 1
+2233 1 1
+37 1 1
+3328 0 1
+4783 6 0
+3323 0 3
+965 1 0
+1234 28 0
+1194 1 0
+1855 18 18
+1024 0 1
+5932 1 0
+5395 9 9
+2759 0 10
+618 5 0
+667 0 8
+580 0 1
+109 1 1
+326 1 0
+9436 5 0
+6164 0 1
+1064 0 6
+1374 2 0
+3637 1 1
+32 1 1
+145 1 0
+1245 2 0
+1736 1 1
+29 1 1
+1656 1 5
+712 10 11
+502 0 1
+3670 1 0
+740 0 1
+1693 0 1
+6497 0 2
+2700 1 0
+198 1 3
+141 0 1
+1108 0 2
+1448 1 0
+947 31 31
+8047 4 0
+842 19167 19167
+101 1 0
+11 4 0
+297 0 24
+337 11 0
+134 1 1
+694 3 0
+72 1 1
+144 128 128
+169 2 0
+1011 1 0
+107 1 1
+1280 1 1
+73 1 1
+84 25 25
+287 1 1
+26 1 1
+139 1 1
+41 1 1
+440 4 0
+130 12 12
+435 18 0
+85 1 1
+28 1 1
+73 59397 59260
+107 0 32
+23 1 1
+116 1 1
+30 1 1
+503 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 4
+711 7 7
+89 1 0
+291 1 0
+167 1 1
+24 1 1
+167 6 6
+171 17 17
+681 1 1
+43 1 1
+538 1 1
+44 1 1
+537 16 16
+180 6 6
+778 2 2
+44 1 1
+168 0 7
+211 1 1
+42 1 1
+1253 1 1
+29 1 1
+320 1 1
+36 2 2
+55 1 2
+228 1 1
+17 1 1
+213 1 1
+35 1 1
+553 8 8
+386 1 1
+26 1 1
+540 1 1
+31 1 1
+65 0 1
+625 12 12
+313 0 1
+52 1 1
+22 1 1
+583 1 1
+49 1 1
+1499 3 0
+729 1 1
+40 1 1
+67 1 1
+19 11 0
+323 19 19
+787 1 1
+36 1 1
+553 8 8
+997 16 15
+157 1 1
+31 2 2
+204 18 19
+487 1 1
+29 1 1
+374 1 1
+67 1 1
+720 13 13
+266 10 10
+330 16 14
+413 1 1
+44 1 1
+78 6 6
+181 2 2
+36 1 1
+397 1 1
+20 1 1
+311 1 1
+48 2 2
+1746 4 4
+35 1 1
+194 10 10
+310 1 1
+51 1 1
+84 1 1
+101 1 1
+521 1 1
+23 1 1
+220 73 73
+1046 15 15
+216 1 1
+21 1 1
+51 1 1
+49 1 1
+527 17 17
+340 12 11
+1025 1 0
+2572 1 1
+29 1 1
+397 2 5
+668 13 13
+541 1 1
+59 0 2
+6 1 1
+122 14 14
+51 1 1
+46 1 1
+429 0 21
+136 1 1
+12 1 1
+66 16 16
+456 37 34
+371 7 7
+48 1 1
+194 10 10
+108 1 1
+60 1 1
+122 49 50
+238 1 1
+32 0 1
+100 1 0
+72 1 0
+390 1 1
+38 1 1
+144 1 1
+27 0 4
+184 21 228
+49 1 1
+608 0 1
+152 1 1
+31 1 1
+281 8 8
+337 1 1
+45 1 1
+222 1 1
+20 1 1
+380 1 0
+44 1 1
+368 1 1
+72 1 1
+502 36 18
+63 1 1
+43 0 4
+136 1 1
+42 1 1
+80 4 4
+35 1 0
+89 1 1
+24 0 5
+829 13 13
+102 14 0
+233 1 1
+42 0 3
+85 0 1
+400 1 1
+40 1 1
+538 25 25
+174 1 1
+20 1 1
+705 1 1
+26 2 2
+614 1 1
+44 1 1
+509 1 1
+32 1 1
+224 1 1
+42 1 1
+99 38 38
+610 5 5
+804 1 1
+29 1 1
+166 1 1
+43 1 1
+233 1 1
+44 1 1
+620 8 8
+133 1 1
+31 1 1
+165 1 1
+29 1 1
+1249 1 1
+26 4 0
+56 1 1
+67 1 1
+716 1 1
+46 0 1
+16 1 1
+174 1 1
+96 1 1
+141 1 1
+39 0 4
+263 1 1
+18 1 1
+259 4 4
+38 1 1
+104 1 1
+40 1 0
+248 1 1
+18 1 1
+238 1 1
+32 1 1
+70 0 2
+16 1 1
+818 1 1
+22 4 4
+1641 1 1
+46 1 1
+53 1 0
+38 1 1
+373 38443 100035
+112 1 1
+39 1 1
+330 1 1
+24 1 1
+197 1 1
+69 1 1
+116 3 0
+161 1 1
+38 1 1
+753 1 1
+57 3 3
+145 1 1
+121 1 1
+300 1 1
+147 1 1
+379 1 1
+55 2 2
+65 1 1
+32 1 1
+1008 1 1
+24 1 1
+159 18 18
+659 1 1
+76 0 2
+77 1 3
+65 1 1
+84 1 0
+119 1 1
+15 1 1
+247 4 0
+372 1 0
+1633 1 1
+16 1 1
+456 7 7
+114 1 1
+102 1 1
+109 4 0
+61 2 2
+80 1 1
+47 1 1
+168 1 1
+31 1 1
+269 2 2
+42 1 1
+626 2 2
+14 1 1
+76 8356 10147
+66 2 2
+80 0 41
+12 1 1
+158 1 0
+92 1 0
+254 1 1
+43 1 1
+846 6 149
+84 1 1
+29 3 3
+315 17 17
+482 1 1
+29 3 3
+278 1 1
+73 1 1
+2767 1 1
+34 1 1
+192 1 1
+33 1 0
+168 6 0
+276 10 10
+344 1 1
+49 1 1
+109 1 1
+35 3 3
+561 24 27
+923 1 1
+102 1 1
+75 14 14
+266 1 1
+80 2 2
+185 1 0
+1035 1 1
+23 1 1
+417 10 10
+97 1 1
+94 1 1
+492 1 1
+37 5 5
+1429 1 1
+19 1 1
+839 1 1
+96 1 1
+1279 4 0
+683 1 1
+49 1 1
+514 1 1
+28 4 4
+2302 1 1
+42 1 1
+537 2 21
+1555 1 1
+42 0 1
+14 4 4
+86 1 1
+62 1 1
+515 5 1
+330 0 1
+159 0 22
+3841 1 0
+3862 16 16
+1187 12 12
+97 0 3
+748 24594 24594
+686 1 0
+11541 1 0
+1843 0 4
+1157 16 16
+7354 19 0
+741 0 1
+8053 1 0
+4449 21 21
+649 1 0
+2913 0 1
+381 332 0
+3533 31 31
+2502 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3870 0 1
+36 13 0
+1894 1 1
+40 0 4
+1137 2 0
+211 2 0
+345 1 0
+592 4 4
+1043 4 0
+686 14 0
+1032 0 1
+9035 0 4
+167 0 2
+23964 0 3
+1760 3 0
+3371 1 1
+23 1 1
+321 5 0
+644 8 0
+47 1 1
+322 1 1
+145 1 1
+1551 11 15
+355 0 1
+1831 4 0
+1779 1 1
+27 1 1
+199 43 55
+767 9786 9786
+338 0 1
+1002 0 1
+7912 4 0
+4977 0 1
+9275 2953 2950
+21511 0 1
+4385 0 7
+881 0 8
+17594 0 20
+2417 1 0
+998 0 10
+4239 7 0
+4845 0 2
+95 28 23
+10921 1 1
+40 1 1
+4759 0 6
+12084 0 3
+3052 0 4
+2989 1 0
+13523 1 3
+3050 104591 33135
+2281 0 7
+377 3 0
+7256 3 0
+419 2 0
+10674 0 17
+5362 16440 16440
+408 1 0
+3061 2 0
+5818 1 0
+2415 11 9
+2056 0 1
+955 4 0
+17260 1 0
+9557 0 2
+5358 0 1
+11548 13 13
+2604 2 0
+57496 1 1
+29 1 1
+6617 19 0
+12369 49753 49753
+608 0 5
+1926 1 1
+40 1 1
+330 3 0
+2327 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+713 0 8
+54 3 0
+1027 3 0
+428 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+8189 4 5
+36 1 1
+99 2 0
+700 0 3
+150 0 1
+750 0 3
+40 1 1
+3179 2 0
+473 0 2
+2032 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+5394 103872 103871
+16267 1 0
+18633 0 1
+920 0 1
+6820 1 0
+1376 1 2
+1931 33 33
+2376 0 1
+12415 1 1
+51 0 1
+9375 0 1
+323 1 0
+1715 154558 154558
+4522 85167 85167
+6234 0 3
+4009 0 5
+6425 2 0
+1119 2 0
+17 8 0
+2256 0 1
+3209 15 8
+2436 0 14
+1040 1 1
+52 1 1
+6972 1 0
+2357 0 1
+29 1 1
+262 1 0
+72 1 1
+45 1 1
+57 17 17
+1390 0 16
+328 312 0
+65 1 1
+217 10 10
+925 0 33
+1490 1 0
+35 1 1
+226 0 3
+805 1 1
+46 1 1
+192 1 1
+56 1 1
+245 1 1
+61 1 1
+198 4 0
+82 2 2
+29 1 1
+57 0 2
+320 1 1
+22 1 1
+267 5 0
+427 1 0
+17 1 1
+425 1 1
+34 1 1
+565 10 10
+432 9 0
+55 1 1
+90 1 1
+140 1 1
+83 1 1
+1035 1 1
+33 1 1
+144 4 4
+38 1 1
+171 1 1
+35 3 3
+161 6 6
+731 7 3
+1216 25 0
+52 0 1
+419 2 0
+87 1 1
+54 1 1
+4713 30 0
+791 3 0
+2849 1 1
+33 1 1
+6790 1 1
+67 4 4
+39 2 0
+251 1 1
+37 1 1
+826 3715 901
+205 2 0
+946 1 1
+30 1 1
+613 5 2
+128 29 29
+802 0 89
+1600 0 6
+2155 1 0
+1164 1 0
+1310 1 0
+2327 1 1
+42 1 1
+2266 1 0
+21451 401282 401282
+2475 1 1
+58 1 1
+375 25 27
+9941 0 1
+6798 0 19
+5779 11 10
+21042 0 1
+13887 36782 36752
+28930 1 1
+19 1 1
+1494 7 0
+148 15 0
+2797 0 2
+329 10 0
+2475 142825 142825
+382 4 0
+707 0 1
+12092 0 1
+2431 1 0
+158 0 1
+281 1 0
+1573 0 1
+11079 1 0
+6938 0 1
+14766 1 0
+4187 10 0
+11099 3 0
+9487 0 6
+467 1 0
+2143 1 0
+697 1 1
+25 0 6
+58 8 8
+1733 0 1
+259 2 0
+295 1 0
+128 0 1
+3052 0 1
+1419 13507 13507
+201 13 12
+15310 1 1
+26 1 1
+461 1 1
+33 0 2
+16 1 1
+649 1 1
+48 1 1
+818 1 1
+21 1 1
+424 1 1
+25 1 1
+632 1 1
+39 1 1
+310 1 1
+27 1 1
+616 1 0
+17240 4 0
+3936 3 0
+2976 174972 174972
+5315 0 20
+2124 0 1
+7445 45267 45267
+361 0 2
+1466 1 0
+6628 1 1
+110 0 1
+1422 0 1
+324 1 0
+1825 1 0
+311 0 1
+6568 1 0
+5228 1 0
+2273 2 1
+6123 1 0
+18640 29 29
+1283 0 3
+11560 6 6
+708 15 14
+1887 10 0
+509 1 0
+1581 1 1
+46 1 1
+811 1 1
+31 0 1
+1557 43 43
+1172 1 1
+18 1 1
+67 1 0
+2081 0 2
+373 0 4
+538 103035 103035
+2665 46 46
+554 0 21
+4473 2 3
+921 1 1
+47 1 1
+2605 9 3
+50 1 1
+178 1 1
+26 1 1
+316 0 2
+1120 4 0
+177 1 2
+960 1 1
+65 1 1
+964 4 4
+783 8 8
+61 34 13
+121 1 1
+22 1 0
+118 1 1
+49 4 4
+281 1 1
+27 1 1
+958 0 1
+107 1 1
+31 1 1
+171 14 14
+302 0 13
+33 1 1
+108 0 4
+98 1 1
+53 1 1
+986 1 1
+37 2 0
+1829 1 1
+38 1 1
+440 1 1
+82 3 4
+647 45 45
+660 1 1
+28 1 1
+1993 0 1
+373 19 19
+835 1 1
+42 1 1
+635 0 5
+307 1 1
+36 1 0
+1055 1 1
+43 1 1
+475 1 0
+60 1 1
+127 1 1
+509 1 1
+71 1 1
+485 1 0
+26 1 1
+531 1 1
+18 1 1
+551 1 1
+18 1 1
+884 5 5
+147 53 60
+527 1 1
+26 2 2
+322 0 17
+32 2 2
+85 1 1
+45 1 1
+625 0 323
+540 0 1
+43 1 1
+266 0 2
+228 1 1
+42 1 1
+283 1 1
+92 1 1
+381 1 1
+40 1 1
+1906 0 4
+3495 0 4
+561 36 36
+370 1 1
+76 1 1
+1824 3653 3651
+214 0 2
+499 1 0
+937 1 1
+45 1 1
+421 6 0
+87 22 22
+1254 1 1
+36 0 1
+357 18 18
+391 0 1
+451 1 0
+105 1 1
+47 1 0
+255 6 6
+739 3 0
+386 1 1
+33 1 1
+281 4 0
+481 2 0
+495 1 1
+42 4 0
+219 0 1
+408 1 1
+23 1 1
+283 1 1
+25 0 1
+541 1 0
+88 2 0
+216 1 1
+29 1 1
+457 1 0
+331 7 19
+181 15 15
+228 1 0
+4 2 0
+324 0 1
+3063 0 2
+11850 0 12
+839 0 1
+14260 0 2
+9658 4 3
+2813 12 12
+782 39571 39571
+1619 2 0
+164 8 1
+655 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+516 1 1
+19 1 1
+1243 2 0
+742 1 1
+40 1 1
+3755 3 0
+13 1 1
+3819 0 1
+10010 1 0
+3051 1 1
+46 3322 3320
+1751 1 1
+103 1 2
+74 1 1
+93 1 0
+22 1 1
+149 4 0
+94 1 1
+31 7 0
+74 1 1
+275 1 0
+99 221094 247530
+272 5 5
+243 1 1
+84 1 1
+98 1 1
+50 5 5
+77 1 1
+74 1 1
+20 0 1
+143 1 1
+45 0 1
+4 1 1
+1088 1 1
+35 1 1
+320 1 1
+22 1 1
+275 1 1
+47 1 1
+370 19 19
+119 1 6
+51 1 1
+21 1 1
+244 0 1
+345 1 1
+24 1 1
+181 1 1
+61 3 3
+542 1 1
+16 1 1
+312 1 0
+353 4 3
+279 323 0
+86 1 1
+49 1 1
+342 1 1
+44 0 2
+222 1 1
+37 1 1
+588 8 8
+593 2 2
+44 1 1
+359 1 1
+25 1 1
+1612 14 14
+428 1 0
+2510 1 0
+5051 0 1
+1489 9 9
+3292 1 0
+1449 1 1
+21 1 1
+6768 1 0
+706 2 0
+6662 1 1
+30 1 1
+228 1 1
+28 0 2
+300 5 5
+887 1 1
+23 1 1
+104 9625 10000
+107 1 1
+47 0 1
+63 1 1
+114 1 1
+219 1 1
+63 9 9
+35 1 1
+290 0 4
+45 0 1
+54 0 1
+40 1 3
+21 6 6
+54 1 1
+41 1 1
+155 1 1
+29 1 1
+220 1 1
+27 1 1
+611 1 1
+163 1 1
+134 1 1
+16 1 0
+5 1 1
+151 15 15
+138 2 2
+27 1 1
+73 2 2
+97 1 1
+204 1 1
+47 1 1
+84 1 1
+74 2 2
+381 20 20
+425 1 1
+21 1 1
+71 1 1
+28 1 1
+245 25 22
+71 1 1
+93 1 0
+82 1 1
+129 1 1
+26 1 1
+294 16 16
+1139 0 1
+1588 0 1
+51 9 9
+60 26 25
+312 15 11
+1008 17 17
+85 1 1
+49 1 1
+702 1 0
+87 1 1
+37 1 1
+859 8 8
+296 4 4
+105 0 4
+43 1 1
+67 10 7
+2839 3 0
+1283 1 1
+67 0 1
+32 2 0
+61 1 1
+140 15 15
+1047 1 1
+38 1 1
+87 1 1
+24 5 4
+1291 1 1
+49 1 1
+421 0 1
+75 1 1
+78 1 1
+243 1 0
+33 1 1
+116 19 19
+65 0 1
+238 0 1
+179 2 1
+67 1 1
+60 1 1
+32 1 1
+677 4 6
+83 314 0
+334 1 0
+1018 5 5
+127 1 1
+83 1 1
+347 0 2
+111 1 1
+30 1 1
+66 1 1
+38 1 1
+218 8 8
+754 1 1
+65 1 1
+182 1 1
+21 1 1
+285 1 1
+75 1 1
+147 6 0
+65 1 1
+42 1 1
+380 1 1
+84 2 0
+88 1 1
+25 1 1
+210 1 1
+17 1 1
+136 6 5
+108 1 1
+40 1 0
+50 1 1
+111 1 0
+21 0 1066
+119 0 1
+2641 1 1
+22 1 1
+689 1 1
+41 1 1
+1415 1 1
+29 1 1
+2252 1 1
+19 1 1
+1524 0 10
+2104 0 1
+511 2 0
+1696 26 8
+2593 0 177
+338 1 1
+37 2 2
+395 10 0
+67 1 1
+131 1 1
+31 1 1
+386 1 1
+42 1 1
+372 1 1
+48 1 1
+8705 0 3
+330 9 9
+600 2 0
+261 8 8
+9909 0 2
+2337 2 0
+2567 1 1
+26 1 1
+561 1 1
+48 1 1
+2440 1 1
+30 1 1
+1289 0 1
+162 1 0
+730 0 3
+658 1 0
+25 1 1
+1027 1 1
+43 1 1
+472 0 1
+219 1 1
+20 1 1
+495 1 0
+6 2 0
+1007 0 1
+169 0 10
+33 1 1
+266 11 11
+752 1 1
+30 1 1
+438 1 1
+39 1 1
+511 0 1
+1247 1 0
+1055 1 0
+491 1 0
+108 1 1
+48 1 1
+1324 0 1
+143 1 1
+40 1 1
+679 1 1
+45 1 1
+1036 0 2
+58 1 1
+46 1 1
+229 16 16
+149 10 10
+94 1 1
+63 1 1
+222 1 0
+55 1 1
+115 5 1
+219 15 15
+692 28 28
+159 1 1
+41 1 1
+211 1 0
+20 1 1
+1099 0 4
+155 6 0
+178 13 15
+32 1 1
+953 1 1
+47 1 1
+174 1 1
+22 1 1
+401 0 13
+588 5 21
+130 1 1
+157 4 4
+86 1 1
+29 0 2
+67 3 0
+641 0 1
+571 0 1
+250 1 1
+34 1 1
+255 0 2
+572 12 12
+275 6 1
+974 0 1
+578 12 12
+612 1 1
+43 1 1
+56 0 7
+1170 0 1
+1236 0 4
+2118 5 0
+1090 0 2
+4424 1 1
+34 1 1
+4897 8 0
+2112 0 1
+2874 1 1
+21 1 1
+442 22 22
+805 0 1
+3476 16 0
+7063 0 1
+65 3 0
+4293 0 1
+3181 0 4
+9515 5 1
+172 1 1
+49 1 1
+320 1 1
+34 1 1
+10677 2 0
+4856 3 0
+6082 1 0
+955 0 1
+1720 6 0
+17 1 0
+8156 53709 53709
+819 9 0
+1244 1 1
+32 5 5
+2063 14 0
+357 3 0
+321 46 46
+873 1 1
+47 1 1
+1156 10 9
+1180 29 25
+247 9 9
+1870 0 1
+17 1 0
+366 7 7
+101 0 1
+134 8 8
+1654 0 4
+8741 1 1
+24 1 1
+991 0 210
+20 2 0
+906 13 13
+478 1 1
+21 1 1
+812 88 88
+2215 16 16
+1485 1 1
+18 1 1
+883 1 1
+20 1 1
+1354 1 1
+28 1 1
+283 5 5
+640 1 1
+40 1 1
+560 1 1
+42 1 1
+1144 19 19
+57 1 1
+21 1 1
+216 1 1
+109 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 40 40
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 5 5
+23 1 1
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+427 1 1
+115 1 1
+232 1 1
+94 1 1
+809 1 0
+2261 16 15
+1824 1 0
+1990 1 0
+9965 0 18
+2951 6 0
+798 1 1
+30 1 1
+159 1 1
+124 1 1
+661 1 1
+31 1 1
+2632 4 4
+4024 0 16
+9373 7 7
+8626 0 1
+316 0 26
+10715 6 6
+110 1 1
+25 0 1
+7753 1 1
+30 0 1
+4078 0 2
+5144 1 1
+36 1 1
+69 1 1
+21 1 1
+135 1 1
+85 1 1
+125 3 4
+128 5 5
+24 1 1
+91 1 1
+61 15 0
+69 1 1
+78 0 19
+64 1 1
+138 1 1
+31 1 1
+510 18 7
+161 1 1
+30 1 1
+119 1 1
+26 1 1
+291 2 1
+143 1 1
+29 1 1
+293 1 1
+158 4 4
+87 32 32
+778 1 1
+58 0 1
+127 1 1
+75 28 0
+26 0 2
+204 207869 207869
+1739 1 0
+702 0 1
+5133 0 2
+3096 1 0
+315 1 0
+490 0 1
+2588 3 0
+1013 0 1
+3659 1 0
+2412 1 2
+2723 4 0
+523
+
+chain 80965 chr6_apd_hap1 4622290 + 2323391 2324248 chr6 170899992 - 139781917 139782778 1559018
+341 0 4
+516
+
+chain 30899 chr6_apd_hap1 4622290 + 1238363 1238687 chr13 114142980 + 81787211 81787535 4477038
+324
+
+chain 29563 chr6_apd_hap1 4622290 + 3995951 3996260 chr1 247249719 - 75038034 75038343 4838475
+309
+
+chain 28633 chr6_apd_hap1 4622290 + 2292529 2292831 chr7 158821424 - 147037095 147037398 5180885
+171 0 1
+131
+
+chain 28481 chr6_apd_hap1 4622290 + 4061349 4061647 chr17 78774742 + 29063769 29064067 5407270
+298
+
+chain 23990 chr6_apd_hap1 4622290 + 1105022 1105798 chr7 158821424 - 51137320 51138262 7695539
+178 101 101
+72 385 551
+40
+
+chain 15671 chr6_apd_hap1 4622290 + 1097871 1099106 chr6 170899992 - 139552636 139553881 14365447
+56 408 416
+54 620 622
+97
+
+chain 15338 chr6_apd_hap1 4622290 + 4034892 4035065 chr1 247249719 - 181871461 181871634 14713407
+25 1 0
+58 0 1
+89
+
+chain 13894 chr6_apd_hap1 4622290 + 1139363 1141753 chr6 170899992 + 30021566 30022999 16323533
+75 1920 964
+70 255 254
+70
+
+chain 11891 chr6_apd_hap1 4622290 + 3988844 3989392 chrX 154913754 + 64750681 64751228 19168306
+89 401 400
+58
+
+chain 11819 chr6_apd_hap1 4622290 + 1140317 1140448 chr19 63811651 + 15986621 15986752 19293908
+131
+
+chain 11746 chr6_apd_hap1 4622290 + 1091182 1091330 chr7 158821424 - 7754727 7754875 19419742
+54 14 14
+80
+
+chain 9888 chr6_apd_hap1 4622290 + 4031953 4032128 chr8 146274826 + 50466266 50466441 23070160
+60 56 56
+59
+
+chain 9560 chr6_apd_hap1 4622290 + 1092932 1093033 chr6 170899992 - 141000133 141000234 23851264
+101
+
+chain 7776 chr6_apd_hap1 4622290 + 4298814 4298901 chr8 146274826 + 14484871 14484958 2851549
+87
+
+chain 6175 chr6_apd_hap1 4622290 + 1094444 1094508 chr6 170899992 + 30079296 30079360 30094026
+64
+
+chain 6113 chr6_apd_hap1 4622290 + 3989871 3989936 chrX 154913754 - 39339630 39339695 30268027
+65
+
+chain 5831 chr6_apd_hap1 4622290 + 3989150 3989212 chr2 242951149 + 73586935 73586997 31012834
+62
+
+chain 5731 chr6_apd_hap1 4622290 + 1104489 1104550 chr6 170899992 + 29872087 29872148 31286972
+61
+
+chain 5730 chr6_apd_hap1 4622290 + 1107647 1107707 chr6 170899992 + 29878483 29878543 31293431
+60
+
+chain 5676 chr6_apd_hap1 4622290 + 1093802 1093862 chr8 146274826 - 42258664 42258724 31433499
+60
+
+chain 5492 chr6_apd_hap1 4622290 + 4034227 4034285 chr22 49691432 - 27111287 27111345 17799541
+58
+
+chain 5339 chr6_apd_hap1 4622290 + 3987866 3987922 chr2 242951149 + 186720203 186720259 32420506
+56
+
+chain 5203 chr6_apd_hap1 4622290 + 3989590 3989645 chr5 180857866 + 19136434 19136489 32834289
+55
+
+chain 4712 chr6_apd_hap1 4622290 + 4038649 4038699 chr4 191273063 + 53804403 53804453 34512110
+50
+
+chain 4392 chr6_apd_hap1 4622290 + 1105241 1105300 chr7 158821424 - 126060926 126060985 9905437
+59
+
+chain 2852 chr6_apd_hap1 4622290 + 4034783 4034846 chr15 100338915 + 44177073 44177136 17837211
+63
+
+chain 2740 chr6_apd_hap1 4622290 + 3988933 3988962 chr7 158821424 + 83092272 83092301 22772951
+29
+
+chain 2440 chr6_apd_hap1 4622290 + 3988349 3988416 chr3 199501827 + 102678562 102678629 22367094
+67
+
+chain 2360 chr6_apd_hap1 4622290 + 4034867 4034892 chr4 191273063 - 72949130 72949155 34483441
+25
+
+chain 2247 chr6_apd_hap1 4622290 + 4033024 4033048 chr20 62435964 - 19518135 19518159 35490184
+24
+
+chain 2194 chr6_apd_hap1 4622290 + 1105201 1105241 chrX 154913754 - 101365357 101365397 11073770
+40
+
+chain 2146 chr6_apd_hap1 4622290 + 1091395 1091456 chr12 132349534 + 104221177 104221238 23825288
+61
+
+chain 2000 chr6_apd_hap1 4622290 + 1105373 1105406 chr4 191273063 + 153905795 153905828 8127683
+33
+
+chain 1977 chr6_apd_hap1 4622290 + 3989088 3989138 chr18 76117153 - 10057795 10057845 19617710
+50
+
+chain 1946 chr6_apd_hap1 4622290 + 1105615 1105690 chr1 247249719 - 137852311 137852386 12720712
+75
+
+chain 1584 chr6_apd_hap1 4622290 + 1105480 1105544 chr1 247249719 - 24894387 24894451 17598706
+64
+
+chain 1098 chr6_apd_hap1 4622290 + 4034150 4034227 chr3 199501827 + 101474041 101474118 17425868
+77
+
+chain 917 chr6_apd_hap1 4622290 + 4034367 4034423 chr8 146274826 + 48207051 48207107 19960483
+56
+
+chain 847 chr6_apd_hap1 4622290 + 3988270 3988330 chr20 62435964 - 51574691 51574751 25106564
+60
+
+chain 754 chr6_apd_hap1 4622290 + 3988131 3988185 chr6 170899992 + 30241568 30241622 20370721
+54
+
+chain 747 chr6_apd_hap1 4622290 + 1105904 1105968 chr12 132349534 + 55464534 55464598 20643869
+64
+
+chain 716 chr6_apd_hap1 4622290 + 3989517 3989569 chr16 88827254 - 38714794 38714846 22851158
+52
+
+chain 604 chr6_apd_hap1 4622290 + 1105798 1105824 chrX 154913754 - 101148638 101148664 11583040
+26
+
+chain 420574415 chr6_cox_hap2 4795371 + 0 4795371 chr6 170899992 + 28585775 33459520 26
+95659 1 0
+2669 19 19
+7247 1 2
+1704 0 4
+1513 0 2
+49 2 0
+2160 0 5
+672 1 1
+38 1 1
+1384 1 0
+1685 1 1
+30 1 1
+2421 1 1
+42 1 1
+830 1 1
+41 1 1
+1630 0 1
+7458 1 0
+691 0 1
+525 0 1
+79 1 1
+29 1 1
+2055 1 1
+16 0 24
+1867 5 7
+786 0 2
+280 0 1
+227 2 0
+6678 1 0
+4401 1 0
+210 1 0
+3193 2 0
+3619 0 1
+2414 0 2
+5387 0 3
+2927 0 1
+3304 0 1
+440 0 5
+415 0 9
+3597 1 1
+48 1 1
+3412 1 1
+46 1 1
+3604 4 4
+1063 1 1
+36 1 1
+6311 0 1
+35 0 8
+393 0 1
+477 1 1
+37 1 1
+2459 2 0
+517 0 12
+318 0 1
+1010 7 6
+2103 0 1
+5171 0 8
+1483 1 0
+3813 888 0
+4675 0 2
+5620 1 0
+2017 1 0
+3363 0 5
+1197 0 3
+3208 1 0
+1928 1 0
+174 6 0
+780 1 3
+443 14 0
+3079 0 5
+1993 0 3
+1089 1 1
+58 1 1
+80 0 8
+256 2 0
+2473 37 43
+752 0 2
+33 0 2
+825 0 1
+787 1 1
+37 1 1
+1168 16 0
+377 5 1
+27 1 1
+2161 2 0
+2324 1 0
+1757 6 6
+205 4 0
+203 7 7
+107 1 1
+28 1 1
+100 4 4
+258 5 0
+659 1 0
+3805 5 8
+1486 4 4
+213 39 43
+4429 0 2
+1199 13 13
+5814 18 6
+2970 0 1
+813 0 17
+920 2 0
+3820 1 3
+130 21 9
+1913 0 14
+1800 0 1
+1255 2 0
+1466 4 0
+747 0 1
+124 2 0
+2108 1 0
+169 0 26
+593 1 0
+632 5 0
+2711 0 4
+1042 0 1
+34 1 1
+1025 2 0
+27 4 18
+81 1 33
+33 0 1
+6 0 76
+3950 1 0
+86 1 1
+12 1 1
+2947 0 1
+1160 1 0
+2046 3 0
+720 1 0
+1341 1 0
+10205 0 5
+1265 1 0
+10 1 1
+1278 5 6
+340 9 9
+50 0 32
+96 16 18
+605 4 0
+1072 12 12
+950 11 7
+5137 0 1
+2711 1 0
+676 0 1
+2904 1 1
+30 1 1
+851 0 1
+1410 0 1
+394 1 1
+57 1 1
+1561 0 2
+14360 1 1
+42 1 1
+269 1 0
+284 3 3
+24 1 0
+2796 0 5
+2451 28 0
+2251 1 1
+32 1 0
+10 0 4
+24 1 1
+694 0 2
+3475 0 1
+2008 1 1
+49 1 1
+475 1 1
+28 1 1
+259 160 0
+1854 5 4
+1621 3 0
+1791 1 0
+316 0 2
+1169 0 1
+2549 1 0
+2941 1 1
+34 1 1
+243 9 0
+5157 0 2
+1748 0 8
+472 4 0
+2470 0 4
+402 1 0
+643 2 0
+748 0 2
+859 1 0
+409 2 0
+267 0 2
+322 0 4
+155 1 0
+9957 0 4
+1440 4 4
+127 1 0
+1085 1 0
+131 1 0
+767 1 0
+1160 21 21
+1294 1 0
+712 1 0
+1819 2 1
+464 1 0
+6944 0 4261
+55 0 7
+1235 0 3
+702 0 24
+2847 0 1
+2428 3 0
+7517 0 1
+3204 1 0
+611 1 0
+7104 1 0
+4959 14 14
+2827 1 0
+9421 82 25
+2434 43 43
+1951 8 0
+8136 0 2
+344 1 0
+4216 1 0
+810 0 5
+4443 1 0
+10291 10 0
+7265 5 0
+7041 1 0
+6007 1 0
+8185 4 0
+4961 0 3
+13564 0 1
+1475 0 2
+105 0 10
+10104 2 0
+3073 1 0
+3715 8 0
+13731 0 2
+837 61 1
+9404 0 1
+6068 7 0
+916 0 4
+569 1 1
+72 1 1
+2260 0 2
+7036 4 0
+3591 0 3
+713 4 0
+10388 0 2
+8475 0 1
+1324 0 2
+5438 5 0
+156 1 1
+44 0 1
+21501 7 7
+3359 16 16
+2138 0 5
+4406 11 11
+1525 1 1
+28 1 1
+2159 16 0
+48 4 0
+3030 0 1
+5717 10 0
+6594 2 0
+1954 1 0
+4 1 0
+3599 1 0
+7515 4 0
+979 0 2
+1990 0 10
+123 1 1
+27 1 1
+1255 0 2
+2769 5 5
+727 1 1
+26 3 3
+785 0 1
+24359 1 0
+5978 5 5
+66 1 1
+46 1 1
+18539 1 0
+7732 2 0
+652 0 1
+861 0 1
+11988 0 1
+3515 3 0
+19 18 0
+539 0 1
+655 2 0
+10586 2 0
+2385 0 1
+2979 10 10
+4600 1 0
+29834 1 1
+27 1 1
+1216 1 0
+1323 1 0
+673 0 3
+20031 0 3
+2841 13 0
+1841 4 0
+6446 1 0
+11727 0 1
+8427 17 17
+2864 0 143
+4107 0 8
+748 0 2
+3417 1 1
+32 1 1
+18799 0 2
+21810 1 1
+34 1 1
+2784 2 0
+7864 2 0
+4498 0 1
+49089 1 1
+32 1 1
+509 1 1
+37 1 1
+5371 22 16
+389 1 1
+21 1 1
+806 1 0
+1638 6 6
+228 1 1
+45 1 1
+2068 6 3
+441 1 0
+2338 1 0
+1948 1 1
+26 1 1
+214 0 1
+6118 1 1
+31 1 1
+2382 5 5
+4335 1 1
+39 1 1
+4561 1 1
+38 1 1
+2199 1 1
+49 1 1
+243 19 6
+2779 1 1
+37 2 0
+24 1 1
+1966 3 0
+233 1 1
+29 1 1
+13756 0 4
+3956 4 1
+46569 1 0
+18985 0 8
+1384 3 1
+85 1 0
+3539 1 1
+32 1 1
+145 1 0
+1245 2 0
+1736 1 1
+29 1 1
+1656 1 5
+712 10 11
+502 0 1
+3670 1 0
+740 0 1
+1693 0 1
+6497 0 2
+2898 1 3
+141 0 1
+1108 0 2
+1448 1 0
+947 31 31
+362 0 1
+7684 8 0
+2880 1 2
+30 8 0
+896 21 3
+395 1 1
+37 3 0
+23 1 2
+1210 18 0
+65 1 1
+20 1 1
+791 0 4
+389 1 0
+809 1 1
+55 0 7
+428 1 1
+17 1 1
+239 1 1
+20 1 1
+69 1 1
+37 1 1
+955 1 0
+839 0 1
+165 1 0
+3867 0 5
+70 1 1
+27 1 1
+899 1 2
+107 1 0
+1457 1 0
+763 12 5
+35 1 1
+1417 10 10
+121 1 1
+38 0 3
+377 1 0
+505 1 0
+11 4 0
+297 0 24
+337 11 0
+134 1 1
+694 3 0
+72 1 1
+144 128 128
+169 2 0
+1011 1 0
+107 1 1
+1280 1 1
+73 1 1
+84 25 25
+287 1 1
+26 1 1
+139 1 1
+41 1 1
+440 4 0
+130 12 12
+435 21 0
+85 1 1
+28 1 1
+73 1 1
+115 5 1
+70 1 2
+52 2 0
+157 30 30
+554 2 2
+128 1 5
+68 1 1
+44 1 1
+125 0 1
+57 1 1
+308 0 7
+15 1 1
+725 9 0
+60 1 1
+180 1 1
+55 1 1
+61 1 1
+23 1 0
+5 1 2
+88 1 1
+56 1 1
+433 2 0
+84 1 1
+66 1 1
+182 12 12
+216 1 1
+94 1 1
+561 1 1
+16 1 1
+113 1 1
+86 1 1
+148 2 0
+75 2 0
+77 1 21
+209 3 8
+99 31 31
+244 1 0
+173 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+327 1 1
+54 5 5
+929 1 1
+21 1 1
+97 1 1
+28 0 3
+830 0 2
+68 1 1
+525 0 1
+2081 1 1
+41 1 1
+165 3 3
+46 1 0
+378 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 1 1
+39 1 1
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+240 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+321 1 1
+63 1 1
+504 18 18
+662 1 1
+74 1 1
+248 1 1
+34 1 1
+1507 0 10
+1051 0 2611
+560 3 3
+23 1 1
+1631 0 15
+78 4 0
+160 0 21
+3764 0 4
+1358 0 1
+1773 1 1
+43 1 1
+1263 1 1
+39 1 1
+183 0 16
+3001 40 40
+1056 10 0
+1261 1 1
+20 1 1
+137 1 0
+2351 1 1
+43 1 1
+1010 0 4
+536 1 1
+38 1 1
+381 0 1
+888 19 19
+1521 1 1
+27 1 1
+161 1 1
+46 1 1
+2659 2 0
+533 10 0
+441 1 12
+1684 1 1
+26 3 4
+879 16 16
+514 0 2
+58 1 1
+117 1 1
+24 1 1
+207 1 0
+38 1 1
+730 1 1
+39 1 1
+573 0 4
+37 1 1
+144 8 8
+1036 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+317 0 3
+1256 0 2
+332 1 1
+21 1 1
+193 8 28
+30 1 1
+79 1 1
+29 1 1
+536 1 0
+611 1 1
+25 1 1
+399 4 4
+118 0 32
+23 1 1
+116 1 1
+30 1 1
+503 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 4
+711 7 7
+89 1 0
+291 1 0
+167 1 1
+24 1 1
+167 6 6
+171 17 17
+681 1 1
+43 1 1
+538 1 1
+44 1 1
+537 16 16
+180 6 6
+778 2 2
+44 1 1
+168 0 7
+211 1 1
+42 1 1
+1253 1 1
+29 1 1
+320 1 1
+36 2 2
+55 1 2
+460 1 1
+35 1 1
+553 8 8
+386 1 1
+26 1 1
+540 1 1
+31 1 1
+65 0 1
+625 12 12
+313 0 1
+52 1 1
+22 1 1
+583 1 1
+49 1 1
+1499 3 0
+770 1 1
+87 11 0
+323 19 19
+787 1 1
+36 1 1
+553 8 8
+997 16 15
+157 1 1
+31 2 2
+204 18 19
+487 1 1
+29 1 1
+374 1 1
+67 1 1
+720 13 13
+266 10 10
+330 16 14
+413 1 1
+44 1 1
+78 6 6
+181 2 2
+36 1 1
+397 1 1
+20 1 1
+311 1 1
+48 2 2
+1746 4 4
+35 1 1
+194 10 10
+310 1 1
+51 1 1
+136 1 1
+49 1 1
+521 1 1
+23 1 1
+220 73 73
+735 3 3
+123 1 1
+184 15 15
+216 1 1
+21 1 1
+51 1 1
+49 1 1
+527 17 17
+340 12 11
+1025 1 0
+2572 1 1
+29 1 1
+397 2 5
+668 13 13
+541 1 1
+59 0 2
+6 1 1
+122 14 14
+51 1 1
+46 1 1
+429 0 21
+136 1 1
+12 1 1
+66 16 16
+456 37 34
+371 7 7
+48 1 1
+194 10 10
+108 1 1
+60 1 1
+122 49 50
+238 1 1
+32 0 1
+100 1 0
+72 1 0
+390 1 1
+38 1 1
+144 1 1
+27 0 4
+184 21 228
+49 1 1
+608 0 1
+152 1 1
+31 1 1
+281 8 8
+337 1 1
+45 1 1
+222 1 1
+20 1 1
+380 1 0
+44 1 1
+368 1 1
+72 1 1
+502 36 18
+63 1 1
+43 0 4
+136 1 1
+42 1 1
+80 4 4
+35 1 0
+89 1 1
+24 0 5
+829 13 13
+102 14 0
+233 1 1
+42 0 3
+85 0 1
+400 1 1
+40 1 1
+538 25 25
+174 1 1
+20 1 1
+705 1 1
+26 2 2
+614 1 1
+44 1 1
+509 1 1
+32 1 1
+224 1 1
+42 1 1
+99 38 38
+610 5 5
+804 1 1
+29 1 1
+166 1 1
+43 1 1
+233 1 1
+44 1 1
+620 8 8
+133 1 1
+31 1 1
+165 1 1
+29 1 1
+1249 1 1
+26 4 0
+56 1 1
+67 1 1
+716 1 1
+46 0 1
+16 1 1
+174 1 1
+96 1 1
+141 1 1
+39 0 4
+263 1 1
+18 1 1
+259 4 4
+38 1 1
+104 1 1
+40 1 0
+248 1 1
+18 1 1
+238 1 1
+32 1 1
+70 0 2
+16 1 1
+818 1 1
+22 4 4
+1641 1 1
+46 1 1
+53 1 0
+38 1 1
+373 62 62
+1149 0 2
+19 1 1
+1653 4 4
+42 1 1
+218 12 12
+363 1 1
+24 1 1
+457 10 10
+414 13 13
+825 1 1
+41 1 1
+492 0 8
+1370 1 1
+18 1 1
+1145 6 4
+880 1 1
+35 1 1
+236 1 1
+67 1 1
+298 0 1
+147 14 14
+312 11 11
+613 1 1
+62 1 1
+340 1 1
+22 1 1
+1057 1 1
+57 1 1
+358 1 1
+128 1 1
+146 10 10
+490 1 1
+20 1 1
+62 1 1
+88 1 1
+293 1 1
+28 1 0
+20 1 1
+83 0 1
+90 1 1
+312 1 1
+44 1 1
+1213 1 1
+51 1 1
+467 1 1
+39 1 1
+122 14 0
+35 1 1
+485 14 14
+110 13 0
+127 1 1
+7112 0 8
+45 4 0
+3276 0 2
+28 1 1
+2195 17 16
+1325 18 18
+1304 3727 0
+299 0 248
+2603 2 0
+160 1 1
+34 1 1
+631 1 1
+40 1 3
+38 1 1
+332 17 17
+231 14 14
+202 1 1
+199 1 1
+71 1 1
+42 1 0
+53 11 10
+83 1 1
+31 1 1
+135 1 1
+50 3 0
+32 1 1
+194 1 1
+45 1 1
+143 1 1
+78 1 1
+193 6 0
+40 1 1
+432 1 1
+17 1 1
+429 3 6
+58 236 236
+57 1 1
+51 2 2
+278 1 1
+49 1 1
+77 11 11
+120 0 4
+139 1 1
+30 2 2
+205 4 4
+131 1 1
+22 1 1
+251 1 1
+34 1 1
+175 1 1
+36 1 1
+239 1 1
+32 5 5
+63 1 1
+27 1 1
+78 1 1
+19 1 1
+209 1 1
+143 1 13
+176 0 1
+7 0 8
+375 0 1
+62 1 1
+129 2 2
+135 1 1
+88 8 0
+90 6 8
+796 2 0
+1219 1 1
+34 1 1
+833 1 1
+46 1 1
+74 1 1
+45 1 1
+95 1 1
+29 1 1
+298 0 3
+47 1 1
+311 1 1
+58 1 1
+349 9 9
+214 1 1
+37 3 0
+413 11 11
+54 1 1
+97 1 1
+137 0 2
+95 1 1
+257 3 0
+35 1 1
+66 1 1
+47 1 1
+104 7 7
+220 17 17
+207 44327 50000
+112 1 1
+39 1 1
+330 1 1
+24 1 1
+197 1 1
+69 1 1
+116 3 0
+161 1 1
+38 1 1
+753 1 1
+57 3 3
+145 1 1
+121 1 1
+300 1 1
+147 1 1
+379 1 1
+55 2 2
+65 1 1
+32 1 1
+1008 1 1
+24 1 1
+159 18 18
+659 1 1
+76 0 2
+77 1 3
+65 1 1
+84 1 0
+119 1 1
+15 1 1
+247 4 0
+372 1 0
+1633 1 1
+16 1 1
+456 7 7
+114 1 1
+102 1 1
+109 4 0
+61 2 2
+80 1 1
+47 1 1
+168 1 1
+31 1 1
+269 2 2
+42 1 1
+626 2 2
+14 1 1
+76 8356 10147
+66 2 2
+80 0 41
+12 1 1
+158 1 0
+92 2 0
+254 1 1
+43 1 1
+846 6 149
+84 1 1
+29 3 3
+315 17 17
+482 1 1
+29 3 3
+278 1 1
+73 1 1
+2767 1 1
+34 1 1
+192 1 1
+33 1 0
+168 6 0
+276 10 10
+344 1 1
+49 1 1
+109 1 1
+35 3 3
+561 24 27
+923 1 1
+102 1 1
+75 14 14
+266 1 1
+80 2 2
+185 1 0
+1035 1 1
+23 1 1
+417 10 10
+97 1 1
+94 1 1
+492 1 1
+37 5 5
+1429 1 1
+19 1 1
+839 1 1
+96 1 1
+1279 4 0
+683 1 1
+49 1 1
+514 1 1
+28 4 4
+2302 1 1
+42 1 1
+537 2 21
+1555 1 1
+42 0 1
+14 4 4
+86 1 1
+62 1 1
+515 5 1
+330 0 1
+159 0 22
+3841 1 0
+3862 16 16
+1187 12 12
+97 0 3
+772 1 1
+21 2 1
+1058 0 2
+349 2 0
+1080 6 0
+11 1 3
+53 0 2
+14 1 1
+1035 1 1
+85 1 1
+69 1 1
+27 1 1
+547 7 7
+195 1 1
+41 1 1
+395 1 1
+35 1 1
+73 0 1
+71 1 1
+557 3 3
+30 1 1
+66 1 1
+25 1 1
+1332 0 2
+26 2 0
+10 1 15
+36 1 1
+196 1 1
+40 1 1
+141 1 1
+76 1 1
+1480 1 3
+347 1 1
+26 1 1
+231 1 1
+82 3 3
+69 3 0
+441 16 16
+147 1 1
+21 1 1
+3565 0 3
+877 2 0
+1036 1 1
+47 2 1
+3761 12 0
+5345 1 0
+11541 1 0
+1843 0 4
+1157 16 16
+7354 19 0
+741 0 1
+8053 1 0
+4449 21 21
+649 1 0
+2913 0 1
+381 331 0
+3533 31 31
+2502 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3870 0 1
+36 13 0
+1894 1 1
+40 0 4
+1137 6 0
+211 2 0
+345 1 0
+592 4 4
+1043 4 0
+686 14 0
+1032 0 1
+9035 0 4
+167 0 2
+23964 0 3
+1470 0 1
+289 3 0
+4343 1 0
+2026 8 0
+430 0 1
+631 1 1
+21 1 1
+479 0 1
+697 4 0
+1779 1 1
+27 1 1
+196 4 0
+58 8 0
+2881 1 1
+39 1 1
+120 1 2
+24 1 1
+556 1 0
+393 6 6
+3090 1 1
+43 1 1
+1246 1 0
+294 1 1
+27 1 1
+374 3 3
+144 1 1
+190 1 6
+750 1 0
+695 2 0
+1003 11 0
+1956 0 4
+1235 19 19
+1483 11 11
+453 1 0
+536 1 1
+43 1 1
+57 1 0
+21 7 0
+3892 0 1
+3177 0 1
+8990 0 2
+2267 1 1
+35 1 0
+2850 4 0
+1273 0 2
+5863 1 0
+9593 1 1
+81 1 1
+2777 0 2
+5272 0 8
+11548 2 0
+6086 0 1
+109 1 1
+2286 0 1
+997 0 18
+3344 1 1
+40 1 1
+842 28 24
+1584 1 0
+1582 0 1
+1670 3 25
+17 0 4
+16 2 0
+6 12 0
+49 1 1
+538 1 1
+26 1 1
+5879 2 4
+2513 0 1
+346 8 8
+222 16 16
+103 1 0
+198 1 3
+539 1 1
+47 1 1
+1154 0 1
+3737 1 2
+370 2 0
+1178 1 1
+78 1 1
+47 0 1
+518 6 0
+646 13 13
+469 1 0
+1072 1 4
+858 1 0
+3674 1 0
+282 1 0
+597 0 6
+505 4 4
+183 1 1
+43 1 1
+1294 1 1
+40 1 1
+572 0 4
+464 0 4
+1886 2 0
+548 1 0
+1300 0 3
+1839 2 0
+189 1 1
+49 1 1
+1253 1 1
+43 1 0
+498 1 1
+45 4 0
+3538 0 1
+1582 31 31
+376 14 14
+1332 2 0
+3586 1 0
+989 1 2
+447 0 4
+40 1 1
+2445 16 17
+291 1 3
+7 1 0
+11 0 1
+41 1 1
+94 1 1
+49 1 1
+1515 6 0
+603 13 13
+163 1 1
+45 1 1
+2050 11 11
+1126 1 1
+16 1 1
+391 1 1
+19 0 1
+932 1 0
+42 1 1
+751 1 0
+287 1 1
+42 1 1
+464 0 4
+4069 5 5
+153 1 0
+514 2 0
+1093 1 1
+41 1 1
+1746 4 4
+1351 1 1
+38 1 1
+1213 0 72
+168 18 18
+146 7 7
+293 1 1
+61 0 1
+43 1 1
+236 1 0
+35 1 1
+152 14 14
+240 13 13
+523 0 4
+809 4 0
+155 1 1
+44 1 1
+1068 1 1
+93 1 1
+209 15 15
+1331 0 3
+3912 0 1
+6624 0 4
+375 0 1
+7255 5 0
+419 2 0
+293 1 0
+10397 5 24
+11095 0 1
+1770 4 0
+374 0 4
+7714 1 0
+1229 7 6
+3055 1 0
+5818 1 0
+2415 11 9
+2056 0 1
+955 4 0
+3907 0 2
+16936 0 1
+1044 1 0
+2392 0 1
+158 2 1
+199 0 1
+75 6 6
+2094 8 0
+649 2 0
+373 1 1
+39 1 1
+2287 1 0
+15 1 0
+1995 0 2
+818 4 0
+676 0 1
+3171 8 0
+170 0 3
+459 1 1
+37 1 1
+336 1 0
+206 1 1
+26 1 1
+224 15 15
+308 2 1
+82 1 1
+23 1 1
+562 1 1
+80 1 1
+241 0 8
+1530 1 1
+20 1 1
+1372 1 1
+44 1 1
+427 1 1
+20 1 1
+651 105 81
+221 1 1
+45 1 1
+1747 1 1
+27 1 1
+179 1 1
+70 1 1
+173 1 1
+84 0 36
+1864 1 1
+41 1 1
+44 9 0
+1028 1 0
+85 1 1
+21 1 1
+474 1 3
+256 1 1
+31 1 1
+653 1 1
+18 1 1
+62 1 1
+19 1 1
+997 1 1
+22 1 1
+326 1 0
+505 5 4
+386 0 7
+466 13 13
+870 11 12
+134 15 15
+248 0 2
+2281 1 1
+79 1 1
+56 9 6
+528 1 1
+68 1 1
+802 1 0
+290 1 1
+38 1 1
+185 1 1
+61 1 1
+944 1 1
+22 1 1
+835 1 1
+66 1 1
+890 0 1
+3503 6 6
+231 0 1
+2136 1 0
+999 1 0
+5220 3 4
+830 1 1
+24 1 1
+1209 1 1
+38 1 1
+7077 1 0
+2939 1 0
+3511 47 47
+401 0 2
+3746 0 2
+1011 1 1
+34 1 1
+7443 0 1
+688 2 0
+574 1 1
+29 1 1
+1785 2 0
+16 20 0
+4073 2 0
+136 79 79
+528 27 0
+253 0 1
+204 1 0
+129 2 0
+811 1 1
+38 1 1
+2347 52 0
+4634 1 0
+856 14 14
+1052 1 1
+28 1 1
+1255 1 1
+36 1 1
+97 0 1
+58 1 1
+1708 1 1
+48 1 1
+958 13 0
+3371 1 1
+37 1 1
+4267 0 15
+1059 0 1
+272 0 20
+168 2 0
+26 4 32
+4090 0 2
+3269 1 1
+17 1 2
+1378 1 0
+1443 0 1
+6206 1 0
+2318 0 1
+7695 2 0
+396 22 12
+918 0 1
+1818 0 1
+28 1 1
+492 1 1
+33 1 1
+326 1 1
+80 1 1
+288 8 17
+2671 0 1
+1099 0 1
+144 1 1
+29 0 1
+2098 0 2
+24 4 0
+1207 4 4
+45 1 1
+757 0 5
+1926 1 1
+40 1 1
+2657 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+713 0 4
+58 1 0
+1027 3 0
+428 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+8189 4 5
+36 1 1
+102 2 0
+14 1 1
+682 0 6
+147 0 1
+750 0 3
+40 1 1
+2428 0 1
+750 2 0
+473 0 2
+2032 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+11881 1 1
+30 1 1
+4383 2 0
+10078 0 1
+906 2 0
+887 1 1
+80 1 1
+2210 1 0
+905 0 1
+1037 1 0
+5866 0 2
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 4 0
+700 1 1
+2469 1 0
+1751 0 1
+910 2 0
+691 0 1
+32873 0 1
+1722 0 1
+17575 0 8
+1369 29 0
+494 2 0
+4432 0 1
+34617 0 1
+920 0 1
+4586 0 2
+2232 1 0
+5718 0 1
+12415 1 1
+51 0 1
+7997 0 2
+1700 1 0
+2697 1 0
+2561 2 0
+1544 0 6
+1613 3 7
+37 9 1
+2113 1 0
+7174 0 34
+7914 1 1
+35 1 1
+5308 1 0
+2303 2 1
+423 7 7
+590 1 0
+24 1 1
+165 6 0
+896 33 33
+1919 13 13
+64 0 1
+28 1 1
+723 0 4
+2868 0 1
+731 1 1
+60 1 1
+1012 3 0
+1744 1 1
+78 1 1
+61 1 0
+2362 11 11
+399 1 0
+1494 16 16
+128 24 24
+530 1 1
+35 1 1
+5276 1 0
+415 0 1
+580 1 2
+1450 22 23
+816 1 0
+1953 1 0
+881 10 1
+885 8 14
+183 14 14
+1319 1 1
+94 1 1
+419 3 3
+26 1 1
+56 1 0
+69 1 0
+117 1 1
+120 1 1
+42 1 1
+834 125 127
+956 3 0
+664 1 1
+41 1 1
+716 4 0
+1731 8 8
+4228 0 1
+5694 3 0
+4493 0 1
+1373 20 20
+1263 1 0
+3029 4 0
+5702 7 6
+150 2 0
+5972 0 2
+840 0 2
+55 1 1
+28 1 1
+2949 5 6
+4343 6 0
+1663 4 0
+150 1 0
+3128 1 0
+1449 3 0
+1534 1 0
+489 1 0
+431 0 4
+299 2 0
+5082 9 0
+156 1 1
+256 0 1
+992 14 16
+4924 0 1
+6655 1 0
+349 8 7
+762 1 1
+29 0 3
+1434 0 1
+1267 0 1
+587 1 1
+22 0 1
+894 28 0
+1343 2 0
+2256 0 1
+4332 0 4
+22 1 1
+5069 33 33
+7313 12 10
+10485 0 1
+1429 0 12
+625 1 7
+1224 0 10
+1680 4 0
+9061 0 8
+2544 0 140
+5451 33 33
+3754 0 1
+1575 0 3
+1775 1 1
+31 1 1
+1200 1 0
+32 0 3
+790 0 8
+42 0 2
+599 1 1
+22 1 1
+5338 2 0
+1998 0 5
+146 0 4
+12031 0 1
+1993 0 1
+706 2 0
+2735 0 1
+3859 0 4
+1304 47 47
+3494 0 2
+268 2 0
+827 4 4
+1063 6 6
+7834 2 0
+3195 0 1
+4012 10 0
+6429 0 2
+308 0 1
+808 1 0
+17 8 0
+5472 19 2
+2436 0 14
+820 9 9
+2643 1 1
+32 1 1
+1189 1 0
+5710 0 3
+308 1 0
+3028 14 14
+1888 0 1
+4308 1 0
+946 82 0
+1790 0 2
+1218 25 0
+52 0 1
+1271 1 1
+33 1 1
+4760 1 0
+4924 0 1
+4817 4 4
+39 1 0
+1116 3715 901
+205 1 0
+1591 5 2
+128 29 29
+802 0 89
+1600 0 6
+2175 0 5
+606 14 14
+519 1 0
+540 1 1
+40 1 1
+568 2 0
+458 1 1
+41 1 1
+1106 24 62
+818 1 1
+42 1 1
+2266 1 0
+14059 0 4
+5030 1 0
+12630 0 3
+84 9 9
+129 13 18
+564 10 15
+154 1 0
+438 10 10
+38 0 5
+98 11 9
+2034 1 1
+25 1 1
+73 10 10
+70 5 5
+132 1 1
+52 1 1
+599 1 1
+46 1 1
+279 1 1
+18 1 1
+239 3 0
+383 6 0
+224 0 1
+321 15 0
+1783 1 1
+18 3 0
+575 16 16
+60 1 1
+16 1 1
+970 1 1
+24 1 1
+424 3 0
+41 1 1
+57 8 8
+285 2 0
+672 1 1
+44 1 4
+103 0 1
+148 1 1
+49 3 0
+146 5 11
+91 1 1
+79 1 1
+94 1 1
+101 1 1
+88 16 16
+117 1 1
+15 1 1
+58 1 1
+93 1 1
+466 1 1
+44 1 1
+160 1 1
+23 1 1
+481 14 14
+181 4 4
+72 1 1
+25 1 1
+82 7 12
+4 0 1
+11 1 4
+20 0 5
+92 1 1
+56 10 0
+80 1 1
+141 2 0
+60 1 1
+372 0 2
+784 1 1
+85 1 1
+109 1 1
+16 1 1
+57 1 1
+92 3 1
+23 1 0
+26 1 1
+74 1 1
+33 1 1
+176 1 1
+25 2 2
+193 42 43
+377 0 5
+249 1 1
+69 1 1
+98 1 1
+70 1 1
+55 1 1
+143 1 1
+438 1 1
+64 1 1
+53 4 0
+127 3 0
+75 5 5
+45 1 1
+197 1 1
+27 1 1
+116 13 13
+218 15 20
+1107 16 19
+73 1 1
+25 1 1
+199 1 1
+60 1 1
+994 1 1
+43 0 1
+18 1 1
+1215 18 18
+340 1 1
+34 1 1
+2783 1 1
+29 1 1
+475 82 82
+166 10 10
+87 1 1
+18 1 1
+171 7 7
+427 1 1
+21 1 1
+2011 0 3
+17 1 1
+1412 1 1
+24 1 1
+214 8 4
+228 1 1
+34 1 1
+410 16 16
+185 1 1
+24 1 0
+164 0 1
+222 1 1
+25 1 1
+297 10 10
+1171 1 0
+3343 1 0
+11 1 1
+2502 1 1
+23 1 1
+44 12 0
+2856 0 1
+148 1 1
+36 1 1
+993 2 0
+1251 2 0
+6619 14 14
+1014 4 0
+134 2 9
+818 1 0
+61 1 7
+563 46 0
+78 5 5
+1677 1 1
+49 1 1
+399 1 1
+32 1 1
+790 27 27
+104 1 1
+75 1 1
+1638 1 1
+16 1 1
+92 1 1
+44 1 1
+276 0 13
+1020 1 1
+35 1 1
+389 14 14
+256 1 0
+38 1 3
+631 1 1
+40 1 1
+2356 1 1
+82 2 0
+1300 0 5
+511 0 2
+605 1 1
+17 1 1
+880 12 0
+1689 4 0
+2492 1 1
+39 1 1
+641 16 16
+682 0 5
+669 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+498 3 0
+321 0 1
+281 3 0
+450 1 1
+34 1 1
+498 1 1
+28 2 1
+280 0 2
+648 1 1
+47 1 1
+1002 4 0
+120 1 1
+1538 0 1
+75 1 1
+37 1 1
+517 1 1
+79 4 4
+60 18 18
+2075 1 1
+19 1 1
+2429 1 1
+21 1 1
+107 1 0
+2786 0 2
+31 5 5
+1973 12 0
+3118 1 0
+246 0 1
+33 1 1
+6752 1 0
+822 2 9
+606 1 1
+18 1 1
+3920 1 1
+37 0 2
+4497 10 13
+2451 1 1
+16 3 0
+1843 0 4
+3780 3 0
+850 0 1
+2774 0 3
+2065 0 1
+20 1 1
+1400 1 0
+3243 0 15
+1336 5 0
+618 7 7
+1507 8 7
+379 44 43
+2184 0 1
+304 0 2
+19 0 1
+101 1 1
+417 3 3
+22 1 1
+672 4 4
+221 1 1
+161 5 0
+17 1 1
+72 1 0
+106 1 1
+463 1 1
+94 1 1
+138 3 4
+185 1 1
+29 1 1
+220 15 15
+167 1 1
+32 1 1
+93 1 3
+217 1 1
+23 1 1
+137 9 9
+62 0 3
+353 1 1
+27 1 1
+117 9 9
+421 1 1
+47 1 1
+124 0 1
+997 6 0
+54 5 5
+764 1 1
+45 1 1
+1431 7 7
+387 6 6
+1103 0 36
+767 1 1
+31 1 3
+208 5 5
+1610 1 1
+23 1 1
+779 0 8
+324 0 2
+45 1 1
+264 0 3
+45 1 1
+250 1 1
+18 1 1
+517 33 0
+117 1 1
+42 1 1
+550 1 1
+20 1 1
+671 1 1
+68 1 1
+89 1 1
+104 1 1
+172 0 1
+124 0 1
+524 0 1500
+464 5 5
+32 1 0
+171 1 1
+19 1 1
+67 1 1
+22 1 1
+654 1 1
+25 1 1
+68 1 1
+21 4 0
+1588 1 1
+66 1 1
+401 0 1
+186 1 1
+21 1 1
+168 0 1
+686 3 0
+19 1 1
+127 1 1
+29 1 1
+234 1 1
+30 1 1
+141 0 2
+33 1 1
+673 1 1
+89 1 1
+161 16 16
+504 1 1
+192 0 3
+105 1 1
+286 1 1
+101 15 16
+158 8 0
+57 1 1
+332 2 2
+35 1 1
+371 1 1
+55 1 1
+86 1 1
+29 1 1
+196 1 1
+44 1 0
+52 10019 10030
+89 1 1
+35 1 1
+153 1 0
+37 35 6
+68 1 1
+69 3 3
+78 28 28
+85 1 1
+148 1 1
+248 1 1
+77 1 1
+61 1 1
+55 1 1
+82 1 1
+41 2 2
+113 1 1
+59 1 1
+417 5 5
+65 1 1
+55 1 1
+212 0 14
+40 1 1
+112 1 1
+22 0 2
+47 1 1
+75 1 1
+208 5 5
+55 1 1
+78 1 1
+136 13 13
+93 3 0
+140 1 2
+46 1 1
+78 6 6
+52 1 1
+51 1 1
+97 1 1
+107 1 1
+5453 1 1
+40 1 1
+327 1 1
+24 1 1
+172 2 2
+27 11 15
+381 10 11
+376 1 1
+45 1 1
+121 1 1
+62 1 1
+289 1 1
+26 1 1
+191 1 1
+20 11 11
+425 1 1
+37 1 1
+296 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+306 1 1
+24 1 1
+1299 1 1
+47 1 1
+2026 1 1
+20 1 1
+133 1 0
+9803 0 4
+15871 3 0
+2464 1 1
+24 1 1
+879 1 1
+73 1 1
+89 1 1
+42 1 1
+108 1 1
+43 0 1
+26 1 1
+511 5 6
+605 1 1
+47 1 1
+73 1 1
+62 1 1
+1928 19438 20008
+56 5 5
+237 1 1
+141 1 1
+92 1 1
+154 7 7
+3208 1 1
+33 1 1
+671 1 1
+21 1 1
+955 0 3
+130 1 1
+26 1 1
+288 8 8
+218 0 3
+1076 8 0
+609 1 0
+55 2 1
+242 1 1
+23 1 1
+834 1 1
+112 1 1
+67 1 1
+43 1 1
+86 1 1
+30 1 1
+73 13 13
+88 11 11
+145 13 13
+63 1 1
+62 1 1
+59 51 50
+432 1 1
+45 1 1
+68 1 1
+48 1 1
+64 9 9
+299 14 14
+169 10 10
+69 2 2
+85 1 1
+207 6 6
+85 1 1
+44 3 3
+181 11 11
+55 13 13
+258 1 1
+103 1 1
+298 7 7
+268 1 1
+16 1 1
+66 1 1
+97 16 0
+322 1 1
+58 1 1
+55 1 1
+77 1 1
+186 1 1
+55 1 1
+218 1 1
+153 1 1
+53 1 1
+98 1 1
+371 1 1
+303 3 3
+63 1 1
+303 1 1
+121 0 2
+55 8 8
+208 1 1
+26 1 1
+447 6 6
+76 1 1
+46 1 1
+782 12 12
+230 1 1
+67 1 1
+60 1 1
+80 1 1
+170 3 0
+53 1 1
+31 1 1
+317 2 2
+66 1 1
+228 1 1
+23 1 1
+1612 1 1
+21 1 1
+261 1 1
+99 1 1
+128 1 1
+15 1 1
+77 9 9
+618 8 8
+84 4 6
+438 1 1
+140 1 1
+158 4 3
+277 12 12
+165 4 4
+36 1 1
+253 1 1
+59 1 1
+910 0 1
+915 4 5
+276 15 15
+682 1 1
+28 1 1
+1483 13 13
+203 1 0
+52 1 1
+48 1 1
+229 12 12
+166 1 1
+39 1 1
+194 1 1
+24 1 1
+251 8 8
+619 0 4
+15 1 1
+690 84 85
+463 1 1
+30 1 1
+449 1 1
+54 1 1
+58 5 5
+979 1 0
+318 1 1
+28 1 1
+898 10 10
+100 1 1
+22 1 1
+446 1 1
+74 1 1
+273 1 1
+19 1 1
+333 1 1
+44 1 1
+220 1 1
+56 2 0
+209 1 1
+70 1 1
+223 0 20
+220 1 1
+31 1 1
+56 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+195 1 1
+46 1 1
+184 1 1
+60 0 4
+76 0 4
+53 3 1
+43 1 1
+153 1 1
+53 1 1
+195 6 0
+60 1 1
+278 1 0
+42 1 1
+341 13 13
+262 4 4
+67 1 1
+32 1 0
+28 1 1
+287 7 7
+318 1 1
+78 1 1
+157 1 1
+19 1 1
+64 1 2
+31 1 1
+52 1 1
+51 1 1
+77 10280 10270
+101 8 8
+4653 1 1
+38 1 1
+817 2 0
+256 1 1
+27 1 1
+339 1 1
+48 1 1
+54 10 10
+1393 3 0
+1491 2 0
+1983 16 0
+167 0 4
+3886 7 8
+535 1 1
+16 1 1
+1555 3 0
+3131 1 1
+17 1 1
+4196 1 0
+14974 0 1
+3514 0 4
+29 1 1
+123 0 2
+27 11 0
+35 0 50
+43 2 0
+55 6 100
+96 11 0
+22 67 0
+49 13 0
+20 0 2
+19 2 0
+22 4 156
+57 156 3
+61 0 2
+29 20 0
+42 11 0
+21 2 0
+50 4 6
+31 1 3
+23 1 53
+25 0 32
+66 1 55
+11 0 2
+13 0 41
+68 1 42
+23 1 3
+12 2 0
+17 1 29
+51 17 13
+18 2 0
+28 2 0
+26 2 0
+158 1 25
+96 0 28
+51 1 29
+79 254 0
+53 21 0
+5064 0 2
+7569 2 0
+2189 0 1
+85 1 1
+31 0 4
+399 14 14
+408 0 1
+681 0 5
+184 1 1
+20 1 1
+64 1 1
+29 1 0
+9 2 0
+442 4 0
+342 1 1
+24 1 1
+131 1 1
+198 1 1
+370 0 1
+34 1 1
+447 21 20
+259 1 1
+23 0 1
+121 2 0
+2257 1 1
+22 1 1
+811 1 1
+27 1 1
+744 0 5
+843 0 2889
+55 0 88
+1189 0 2
+2274 1 0
+752 4 0
+164 1 1
+55 1 1
+1726 1 1
+57 1 1
+3578 1 1
+34 1 1
+1446 1 0
+460 1 1
+31 0 1
+6 1 1
+163 1 1
+22 1 1
+81 1 1
+27 1 1
+548 1 1
+61 1 1
+1169 1 1
+41 1 1
+6471 1 1
+62 1 1
+530 17 17
+394 1 1
+40 7 0
+57 12 12
+69 2 2
+39 1 1
+70 1 1
+22 0 3
+2307 1 1
+30 1 1
+411 1 1
+104 1 1
+375 26 27
+1218 1 1
+35 1 1
+85 1 1
+20 6 0
+687 1 1
+34 1 1
+268 13 13
+74 1 1
+47 2 0
+51 69 69
+73 1 1
+48 1 1
+218 1 1
+42 1 1
+197 1 1
+41 1 1
+313 1 1
+40 1 1
+476 1 1
+29 1 1
+185 1 1
+35 1 1
+594 1 1
+24 1 1
+220 26 0
+245 0 1
+261 13 13
+89 1 1
+90 1 1
+224 1 1
+201 1 1
+306 1 1
+29 5 5
+121 1 1
+31 1 1
+109 1 1
+25 1 1
+168 1 1
+19 1 1
+93 12 11
+132 1 0
+113 1 1
+30 1 1
+56 9 9
+300 1 1
+50 2 2
+96 1 1
+43 1 1
+76 1 1
+44 1 1
+197 1 1
+91 7 1
+119 0 9
+392 5 5
+89 1 1
+428 11 11
+260 1 1
+23 1 0
+10 1 1
+70 1 1
+65 2 0
+16 0 19
+28 1 1
+208 1 1
+70 1 1
+149 0 3
+243 1 1
+55 1 1
+63 17 17
+1208 1 1
+98 1 1
+162 1 1
+45 1 1
+148 70 70
+209 4 4
+1242 1 1
+42 5 0
+87 1 1
+522 0 3
+305 0 1
+1379 0 2
+390 0 15
+72 1 1
+16 1 1
+270 1 0
+280 7 7
+2763 20 20
+674 10 10
+1375 14 0
+294 143 141
+629 16 16
+54 4 4
+680 16 16
+395 1 1
+42 1 1
+1763 1 1
+46 1 1
+282 1 1
+39 1 1
+860 1 1
+26 1 1
+745 0 2
+2081 2 0
+817 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+132 5 0
+555 1 1
+65 1 1
+550 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+15 1 5
+1404 0 1
+450 4 0
+626 1 0
+304 1 1
+39 1 1
+564 1 1
+45 1 1
+303 2 0
+409 1 1
+18 1 0
+858 2 0
+2168 0 1
+54 22 22
+524 0 1
+410 10 10
+106 1 14
+2419 18 14
+64 1 1
+31 1 1
+185 0 5
+1646 1 1
+20 1 1
+227 1 1
+37 1 1
+500 1 0
+136 3 4
+8239 1 1
+23 1 1
+1114 0 2
+688 0 1
+901 18 18
+4781 0 4
+815 0 1
+5069 0 5
+415 0 2
+352 0 1
+1085 11 11
+1099 0 1
+991 0 1
+845 1 1
+32 0 2
+5751 0 3
+1553 1 1
+60 1 1
+278 0 1
+30 1 1
+1855 0 2
+958 0 1
+66 0 16
+2109 0 2
+1265 0 1
+17312 0 4
+1875 0 1
+2157 1 0
+915 0 6
+4940 1 0
+2649 0 1
+3322 11 9
+2276 14 0
+3128 0 4
+3496 1 0
+966 0 1
+120 4 4
+3473 1 0
+1647 0 3
+1182 1 0
+654 0 3
+2049 1 0
+6838 1 1
+39 1 1
+186 1 0
+2718 1 1
+30 1 1
+160 11 11
+4954 0 1
+420 1 1
+123 1 1
+156 0 4
+219 4 0
+195 1 0
+4402 2 0
+4295 1 0
+4695 0 1
+30 1 1
+6025 1 0
+4179 1 0
+19834 0 1
+11605 0 1
+4121 2 0
+2863 0 2
+4890 1 0
+5576 0 6
+4104 4 0
+19858 4 0
+1616 0 3
+1647 4 1
+36 0 12
+2213 0 14
+414 0 1
+3338 0 3
+678 3 4
+292 2 0
+1922 0 1
+913 0 1
+2720 1 0
+1111 3 0
+2589 0 8
+9425 1 0
+1403 0 2
+1964 0 12
+4433 0 1
+1569 0 1
+89 46 46
+7074 1 1
+41 1 1
+2257 1 0
+3001 0 1
+1845 1 0
+1593 0 1
+497 0 2
+6109 0 1
+2019 2 0
+921 0 1
+241 1 0
+4348 72 72
+1053 1 0
+2213 2 0
+1974 8 0
+4952 0 1
+6146 2 0
+953 1 0
+4141 0 1
+4244 5 0
+152 0 2
+209 0 1
+2400 0 10
+785 2 0
+1733 0 1
+554 1 0
+128 0 2
+3051 0 1
+5221 17 17
+3339 0 1
+1503 0 1
+1705 0 3
+2052 17 17
+998 177 0
+2804 1 0
+1925 1 0
+5635 17 17
+3563 0 1
+971 8 0
+36021 1 0
+8016 29 27
+3890 0 1
+67913 1 1
+18 1 6368
+73 1 1
+3119 23 23
+7239 0 32738
+4295 1 1
+19 1 1
+6198 1 0
+16668 1 1
+20 1 1
+5638 5 0
+47 12 0
+11313 0 1
+1769 0 1
+8355 0 3
+4114 0 2
+1403 1 0
+5140 0 1
+490 0 1
+219 1 0
+3483 1 0
+8939 1 1
+44 1 1
+10813 0 2
+7480 2 0
+617 1 0
+1464 0 1
+500 0 2
+1466 1 0
+527 5 0
+3593 0 1
+374 0 1
+3666 0 1
+2149 1 0
+311 2 0
+6570 1 0
+962 1 0
+23 1 1
+2647 4 0
+588 1 1
+21 1 1
+3256 28 20
+870 0 1
+644 1 0
+602 2 1
+3730 1 1
+45 1 1
+12848 7 7
+5994 29 29
+1283 0 3
+8057 1 1
+63 1 1
+4166 1 0
+1887 10 0
+2949 1 1
+31 0 1
+669 1 0
+888 43 43
+1259 2 0
+2081 0 2
+373 0 6
+421 4 4
+1460 0 1
+1699 0 8
+2882 2 0
+147 0 1
+1656 1 1
+27 1 1
+1828 0 2
+4066 0 3
+34 1 1
+361 17 17
+1254 6 0
+1643 0 2
+2542 0 1
+848 2 1
+2117 0 2
+119 1 1
+44 1 1
+1104 0 1
+415 0 12
+634 18 1
+377 6 7
+227 6 0
+449 13 13
+895 0 17
+457 18 18
+663 0 3
+382 1 1
+26 1 1
+135 0 1
+105 1 1
+25 1 1
+620 2 0
+290 5 5
+375 1 1
+30 0 4
+98 1 0
+20 17 4
+3824 28 0
+39 4 0
+28 4 0
+44 4 0
+1898 9 9
+221 0 2
+10522 30 0
+783 1 1
+59 1 1
+94 1 1
+21 1 1
+491 1 1
+49 1 1
+289 2 0
+120 0 1
+37 1 1
+112 1 1
+21 1 1
+183 16 16
+73 2 0
+1007 1 1
+38 0 1
+79 1 1
+48 1 1
+561 1 1
+29 1 1
+145 5 5
+576 12 12
+834 1 0
+846 5 7
+34 1 1
+417 0 1
+65 1 1
+40 1 1
+110 1 1
+47 1 1
+351 1 1
+69 1 1
+53 1 1
+91 1 1
+260 1 1
+36 0 1
+604 1 0
+169 0 1
+2118 1 1
+34 1 1
+147 1 1
+213 1 1
+67 1 1
+31 1 1
+566 1 0
+17 1 1
+763 1 1
+34 1 1
+671 5 0
+41 2 2
+98 0 1
+449 0 2
+61 1 1
+38 1 1
+202 1 1
+44 1 1
+190 1 0
+46 4 4
+51 0 4
+476 1 1
+17 1 1
+212 1 1
+26 1 1
+485 1 1
+25 1 1
+263 1 1
+26 1 1
+1327 4 0
+44 1 0
+2397 1 1
+44 1 1
+4146 14 14
+901 0 1
+3504 1 0
+1125 1 0
+254 1 0
+427 0 1
+30 1 1
+111 0 2
+52 0 8
+528 44 0
+969 1 1
+10 1 0
+28 1 1
+140 1 1
+43 1 1
+1989 2 1
+598 1 1
+87 0 4
+124 1 0
+4840 1 1
+28 7 4
+505 0 2
+24 1 1
+5134 4 0
+543 1 0
+18 1 1
+97 1 1
+29 1 3
+101 6 0
+148 13 7
+1346 0 1
+128 7 0
+49 0 1
+876 2 0
+286 5 5
+184 0 1
+84 5 5
+365 9 9
+981 1 1
+11 1 1
+734 4 0
+563 4 0
+244 9 9
+379 1 1
+17 1 1
+49 2 0
+95 1 1
+30 1 1
+147 1 1
+37 0 6
+340 1 2
+58 1 1
+332 0 2
+233 6 9
+156 0 1
+26 1 1
+439 4 0
+34 0 2
+508 5 0
+96 1 1
+34 1 1
+1267 15 15
+638 1 1
+24 4 5
+1055 13 13
+135 0 1
+194 63 63
+384 6 6
+2756 1 1
+19 1 1
+99 15 15
+1754 2 3
+2238 1 1
+31 1 1
+3002 4 0
+2156 15 15
+855 14 13
+442 5 5
+2022 6 6
+506 0 2
+1110 0 1
+2578 0 2
+4864 1 1
+36 1 0
+3187 1 1
+16 1 1
+184 1 1
+18 1 1
+1607 53 60
+527 1 1
+39 1 1
+653 3 0
+227 1 1
+18 1 1
+102 7 7
+109 0 323
+91 1 0
+124 0 15
+621 0 4
+553 12 12
+463 1 1
+40 1 1
+372 1 1
+25 1 1
+188 12 12
+357 0 1
+250 0 5
+4193 0 4
+967 1 1
+76 1 1
+3236 4 4
+529 7 7
+246 4 0
+160 1 1
+34 0 3
+1469 0 2
+499 1 0
+937 1 1
+45 1 1
+421 6 0
+2127 0 1
+491 1 0
+80 1 1
+72 2 0
+255 6 6
+728 14 11
+702 3 0
+290 0 2
+210 19 1
+473 1 1
+42 4 0
+219 0 1
+348 1 1
+83 1 1
+851 0 16
+72 13 0
+246 1 1
+47 4 0
+410 1 0
+93 0 12
+225 0 16
+428 1 0
+4 6 0
+324 0 1
+3060 0 16
+1305 1 1
+29 1 1
+3094 0 7
+600 0 2
+5495 1 1
+47 1 1
+1247 9 21
+35 6 0
+4350 1 1
+15 1 1
+2011 6 14
+8378 2 0
+295 0 17
+4583 1 0
+4132 0 4
+924 4 3
+1751 0 2
+1060 12 12
+380 0 2
+425 8 0
+84 0 1
+244 1 1
+28 1 1
+221 4 0
+348 1 1
+37 11 11
+50 1 1
+180 1 1
+348 1 1
+20 1 1
+1714 1 1
+79 1 1
+729 1 1
+44 1 0
+78 1 1
+112 1 1
+23 1 1
+55 9 9
+1044 1 1
+27 1 1
+494 1 1
+32 1 1
+237 1 1
+27 1 1
+1839 7 1
+710 8 0
+185 0 2
+966 1 0
+13 15 1
+251 1 1
+47 1 1
+285 1 1
+103 1 1
+977 1 1
+41 1 0
+97 1 1
+131 1 0
+307 1 1
+47 1 1
+1070 1 1
+69 1 1
+382 0 1
+167 1 1
+35 1 1
+161 1 1
+30 1 1
+1068 18 0
+1173 1 1
+32 1 1
+59 1 1
+12 1 0
+18 1 1
+55 0 22
+72 1 1
+2806 1 1
+15 1 1
+1395 1 0
+157 13 0
+536 8 8
+101 1 1
+21 1 1
+147 8 8
+638 1 1
+18 1 1
+183 15 15
+990 0 12
+21 1 1
+145 0 1
+332 1 1
+31 1 1
+231 22 5
+39 1 1
+414 9 9
+93 1 1
+63 1 1
+739 0 2
+632 1 1
+74 1 1
+138 5 5
+128 0 1
+294 1 1
+45 1 1
+679 6 6
+1773 0 34
+543 27 27
+1608 5 0
+219 1 1
+134 0 3
+164 0 1
+357 1 1
+28 1 1
+670 7 9
+270 0 1
+891 13 33
+257 4 0
+80 0 4
+130 2 0
+3772 1 1
+44 1 1
+2256 0 1
+80 12 0
+5544 1 0
+428 13 13
+77 4 4
+63 1 1
+64 13 19
+906 1 1
+84 1 1
+290 1 1
+41 1 1
+144 15 15
+238 3 0
+61 1 1
+31 1 1
+189 10245 10222
+107 11 11
+93 1 1
+30 7 5
+242 0 1
+171 1 1
+29 1 1
+218 0 9
+241 1 1
+55 4 4
+88 1 1
+99 1 1
+57 0 1
+523 12 16
+399 1 1
+50 1 1
+389 1 1
+71 4 4
+173 12 12
+92 1 1
+20 1 1
+132 0 5
+15 1 1
+75 1 1
+26 5 5
+119 11 11
+542 1 1
+23 2 2
+254 1 1
+34 1 1
+172 1 1
+45 1 1
+95 11 11
+127 23 23
+64 1 1
+95 1 1
+390 1 1
+52 1 1
+170 1 1
+16 5 0
+30 1 1
+599 1 1
+119 1 1
+85 1 1
+75 1 1
+286 4 4
+61 1 1
+286 9 9
+429 1 1
+21 1 1
+53 1 1
+44 1 1
+130 1 1
+30 1 1
+190 2 2
+127 1 1
+96 4 4
+112 1 1
+105 5 5
+19 3659 4
+244 10 11
+69 1 1
+29 1 1
+281 1 1
+38 1 1
+212 1 1
+36 1 1
+79 1 1
+29 3 3
+125 161746 190163
+3115 0 1
+152 1 1
+1518 1 1
+88 1 1
+4502 0 1
+46 1 1
+800 4 4
+23 1 1
+1305 2 0
+136 0 1
+4941 0 1
+547 0 1
+70 8 8
+293 1 1
+35 1 1
+1165 4 0
+6662 1 1
+121 1 1
+92 0 8
+214 1 1
+35 1 1
+108 1 0
+1063 0 1
+1017 1 1
+20 0 6
+1725 0 1
+134 68 67
+349 1 1
+24 0 1
+1562 1 1
+31 1 1
+2513 0 1
+73 36 36
+305 1 1
+27 1 1
+543 1 1
+47 4 28
+4387 20057 20086
+272 5 5
+243 1 1
+84 1 1
+98 1 1
+50 5 5
+77 1 1
+74 1 1
+20 0 1
+143 1 1
+45 0 1
+4 1 1
+1088 1 1
+35 1 1
+320 1 1
+22 1 1
+275 1 1
+47 1 1
+370 19 19
+119 1 6
+51 1 1
+21 1 1
+244 0 1
+345 1 1
+24 1 1
+181 1 1
+61 3 3
+542 1 1
+16 1 1
+312 1 0
+353 4 3
+279 323 0
+86 1 1
+49 1 1
+342 1 1
+44 0 2
+222 1 1
+37 1 1
+588 8 8
+593 2 2
+44 1 1
+359 1 1
+25 1 1
+2054 1 0
+2510 1 0
+5051 0 1
+1489 9 9
+3292 1 0
+1449 1 1
+21 1 1
+6768 1 0
+706 2 0
+7107 1 1
+38 1 1
+1127 73 73
+435 1 1
+60 1 1
+325 0 1
+254 1 1
+43 1 1
+210 1 1
+7 1 0
+47 1 1
+130 4 4
+34 1 1
+208 1 1
+39 2 2
+526 1 1
+36 1 1
+99 9 7
+20 1 1
+73 1 1
+62 1 1
+425 1 1
+43 1 1
+811 1 1
+38 1 1
+362 1 1
+49 1 1
+109 1 1
+19 1 1
+79 1 1
+29 0 1
+26 1 1
+252 1 1
+75 1 1
+441 1 1
+66 1 1
+389 13 13
+67 7 7
+1185 0 311
+64 6 6
+667 1 1
+38 1 1
+79 1 0
+553 1 1
+30 1 1
+433 1 1
+16 3 0
+1133 12 12
+262 5 5
+276 1 0
+960 14 14
+272 1 1
+41 1 1
+196 1 0
+1424 18 19
+314 1 1
+22 1 1
+345 1 1
+23 3 0
+245 1 1
+78 1 1
+77 1 1
+779 1 1
+32 1 1
+247 1 1
+48 1 1
+778 2 0
+226 1 1
+61 1 1
+861 0 1
+51 9 9
+397 1 1
+12 4 0
+46 1 1
+602 1 1
+35 1 1
+422 1 1
+49 1 1
+789 1 1
+37 1 1
+268 0 2
+589 8 8
+366 1 1
+6 0 7
+5 0 1
+66 1 1
+1584 2 7
+19 1 1
+417 1 1
+37 1 1
+812 1 1
+33 3 0
+1351 18 18
+2186 1 1
+86 1 1
+1433 59 59
+65 0 1
+238 0 1
+171 1 1
+7 2 1
+67 1 1
+596 1 1
+29 1 1
+144 4 6
+417 1 0
+88 1 1
+24 1 1
+390 18 18
+496 14 21
+145 1 1
+46 1 1
+310 1 1
+35 1 1
+214 1 1
+38 1 1
+206 1 1
+37 1 0
+240 1 1
+32 1 1
+469 1 1
+32 1 1
+208 1 1
+21 1 1
+343 1 1
+17 1 1
+88 1 1
+58 6 0
+169 1 1
+22 1 1
+162 0 1
+196 0 2
+500 6 5
+108 1 1
+40 2 0
+50 1 1
+111 1 0
+21 0 1066
+335 1 1
+44 1 1
+11005 0 1
+6280 1 1
+48 1 1
+1173 1 1
+19 1 1
+2664 0 1
+351 1 0
+1059 14 14
+593 0 1
+869 16 16
+23065 2 0
+2197 0 1
+949 0 1
+15048 0 1
+606 1 0
+7820 0 4
+14669 1 0
+14708 0 1
+16326 0 1
+710 2 0
+194 1 1
+49 1 1
+262 0 1
+92 1 1
+10677 2 0
+4856 3 0
+7447 6 6
+421 1 0
+884 6 0
+17 1 0
+3075 1 0
+14671 3 1
+3762 2 0
+601 2 0
+2461 0 2
+5154 1 0
+1604 0 16
+3589 0 1
+1488 1 0
+1196 0 2
+683 0 1
+1218 1 0
+221 1 1
+22 1 1
+296 4 4
+1456 23 41
+880 1 12
+2490 1 0
+151 1 1
+33 1 1
+2809 4 4
+3645 1 1
+17 1 1
+3496 2 0
+154 1 1
+29 1 1
+158 0 1
+5981 1 1
+32 1 1
+1041 0 2
+174 9 0
+1383 0 1
+389 1 2
+1570 2 0
+3993 4 0
+4576 1 1
+45 1 1
+182 8 8
+2203 20 24
+2009 1 1
+39 1 1
+489 1 1
+17 1 1
+628 1 1
+124 1 1
+1607 1 1
+23 1 1
+1021 0 8
+1249 0 20
+46 0 32
+46 6 0
+24 0 10
+7679 1 1
+44 1 1
+580 1 1
+28 1 1
+264 1 1
+65 0 1
+15 1 1
+2371 19 19
+57 1 1
+21 1 1
+231 1 1
+94 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 40 40
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 29 29
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+270 1 1
+272 1 1
+232 1 1
+94 1 1
+3189 0 176
+834 0 35
+303 0 51
+321 1 0
+17170 0 1
+321 1 1
+25 1 1
+679 1 1
+33 1 1
+990 11 11
+131 8 8
+79 9 9
+1284 5 5
+537 6 6
+127 1 1
+28 1 1
+145 1 1
+47 1 1
+399 4 4
+35 1 1
+143 1 1
+39 1 1
+53 9 9
+61 1 1
+95 12 22
+86 1 0
+71 5 0
+11 1 1
+58 8490 8674
+113 1403 1307
+491 1 1
+32 1 1
+85 1 1
+41 1 1
+480 1 1
+74 2 2
+1108 59 0
+70 10 10
+325 11 11
+879 1 1
+34 1 1
+524 1 1
+25 1 1
+202 17 17
+1154 1 1
+26 1 1
+89 17 17
+87 1 1
+39 1 1
+950 1 1
+15 2 2
+51 1 1
+81 1 1
+180 1 0
+187 1 1
+37 1 1
+467 1 1
+19 1 1
+755 0 2
+81 3 1
+16 1 1
+67 6 6
+84 1 1
+37 2 0
+31 0 28
+15 0 37
+266 14 14
+372 1 1
+68 1 1
+205 40 40
+217 1 1
+46 1 1
+563 19 0
+217 9 9
+363 1 1
+22 1 1
+884 1 1
+40 1 1
+179 1 1
+42 1 1
+94 6 6
+922 1 1
+30 1 1
+481 0 3
+7925 15 11
+333 5 0
+1235 6 6
+355 1 1
+27 1 1
+515 1 0
+1077 11 0
+1521 1 0
+38 1 1
+119 1 1
+58 1 1
+63 4 3
+385 1 1
+49 1 1
+77 20 22
+111 11 11
+190 2 2
+45 1 1
+373 1 1
+47 1 1
+77 10 10
+186 1 1
+24 1 1
+965 27 27
+148 1 0
+214 1 1
+34 1 1
+89 1 1
+36 1 1
+288 0 1
+544 0 331
+320 1 0
+199 1 1
+16 1 1
+112 1 1
+29 1 1
+808 0 3
+45 1 1
+240 1 1
+38 1 1
+59 1 1
+68 1 1
+52 1 1
+98 1 1
+166 7 7
+698 1 1
+68 1 1
+165 0 1
+114 1 1
+92 0 1
+14 1 1
+215 1 1
+81 1 1
+792 1 1
+31 1 1
+54 1 1
+44 1 1
+179 1 1
+26 1 1
+200 1 1
+30 1 1
+639 7 7
+505 0 1
+18 0 1
+21 1 1
+549 12 0
+19 1 1
+1413 19 19
+752 1 0
+840 1 1
+69 1 1
+966 21 21
+33 12 0
+56 1 1
+94 1 1
+237 11 9
+189 1 1
+47 1 1
+318 3 0
+80 16 16
+67 1 2
+11 5 0
+32 1 1
+126 1 1
+146 1 1
+104 6 5
+56 1 1
+68 1 1
+417 12 13
+636 0 2
+30 1 1
+694 0 4
+95 1 1
+28 1 1
+1358 1 1
+19 1 1
+68 1 1
+97 1 1
+493 1 7
+158 2 0
+42 6 0
+59 1 1
+314 14 14
+94 1 1
+64 1 1
+637 1 1
+21 1 1
+144 2 1
+229 11 5
+410 1 1
+96 1 1
+272 1 1
+22 1 1
+118 1 1
+44 1 1
+96 1 1
+48 1 1
+414 22 22
+373 13 13
+554 1 1
+87 10 0
+313 1 1
+37 1 1
+122 17 18
+179 1 1
+40 1 1
+591 8 8
+129 1 0
+70 1 1
+71 1 0
+73 10 6
+12 1 1
+203 0 6
+24 2 0
+45 4 0
+46 1 1
+186 9 9
+87 1 1
+28 1 1
+3625 0 1
+233 1 1
+532 0 2
+696 2 0
+555 1 7
+287 1 1
+30 0 3
+946 0 1
+88 1 1
+60 12 0
+12546 1 1
+37 1 0
+2071 0 1
+3270 4 5
+24668 0 2
+6212 1 1
+26 1 1
+816 0 4
+8244 26 26
+5332 18 15
+2375 2 0
+1957 2 0
+2394 6 0
+1561 0 1
+2805 4 0
+12333 8 0
+835 0 1
+391 35 62
+12156 0 18
+6903 2 0
+21807 3 0
+1588 1 0
+2605 1 1
+23 1 1
+11252 8 0
+298 6 7
+946 2 0
+232 0 1
+501 1 0
+4748 0 4
+770 0 7
+914 0 1
+295 1 0
+214 3 0
+121 0 1
+784 0 1
+2512 0 1
+1205 21 21
+3250 3 0
+926 0 1
+189 2 0
+3543 2 0
+893 1 1
+46 1 1
+1296 0 1
+153 0 1
+336 5 0
+228 1 1
+45 1 1
+207 3 0
+322 0 1
+658 1 0
+1516 3 0
+1025 0 13
+1518 0 1
+591 10 10
+3384 0 2
+182 12 0
+328 1 0
+301 0 1
+994 1 1
+18 0 6
+1743 0 1
+2350 22 23
+1548 0 7
+1976 1 0
+199 0 1
+5922 12 12
+873 0 3
+3080 12 8
+322 1 0
+490 1 0
+3602 1 0
+482 1 0
+3178 1 0
+5157 0 10
+753 0 1
+885 20 0
+1746 10 0
+4045 6 1
+3520 5 13
+2048 0 1
+3529
+
+chain 323865 chr6_cox_hap2 4795371 + 1330645 1334316 chr12 132349534 - 750935 772711 208090
+2772 0 815
+201 0 17291
+643 1 0
+54
+
+chain 80740 chr6_cox_hap2 4795371 + 2523432 2524289 chr6 170899992 - 139781917 139782778 1563239
+341 0 4
+516
+
+chain 70254 chr6_cox_hap2 4795371 + 4067974 4068737 chr9 140273252 + 98508948 98509710 1791394
+611 16 15
+136
+
+chain 49863 chr6_cox_hap2 4795371 + 2736707 2740201 chr12 132349534 + 103307685 103311177 2548369
+99 961 960
+121 35 35
+77 287 287
+76 473 472
+80 230 229
+64 37 37
+96 796 797
+62
+
+chain 42593 chr6_cox_hap2 4795371 + 3906996 3908960 chrX 154913754 - 144265701 144267664 3039954
+86 125 125
+67 358 358
+186 154 154
+98 734 733
+51 48 48
+57
+
+chain 34258 chr6_cox_hap2 4795371 + 2809588 2810007 chrX 154913754 - 17721461 17721874 3940368
+73 15 15
+155 1 1
+20 6 0
+17 1 1
+131
+
+chain 30865 chr6_cox_hap2 4795371 + 4059866 4060385 chr6 170899992 + 32821259 32821748 4483190
+73 89 59
+184 77 77
+96
+
+chain 30808 chr6_cox_hap2 4795371 + 1510229 1510552 chr13 114142980 + 81787211 81787534 4493802
+323
+
+chain 29563 chr6_cox_hap2 4795371 + 4153575 4153884 chr1 247249719 - 75038034 75038343 4838476
+309
+
+chain 29490 chr6_cox_hap2 4795371 + 3951720 3952028 chr20 62435964 - 21243992 21244300 4870682
+308
+
+chain 27083 chr6_cox_hap2 4795371 + 3906819 3907206 chr15 100338915 - 11358130 11358517 3142845
+177 86 86
+124
+
+chain 23990 chr6_cox_hap2 4795371 + 1376886 1377662 chr7 158821424 - 51137320 51138262 7695540
+178 101 101
+72 385 551
+40
+
+chain 17935 chr6_cox_hap2 4795371 + 3928197 3929285 chr6 170899992 + 32648139 32649803 12171469
+63 855 1431
+170
+
+chain 17763 chr6_cox_hap2 4795371 + 3903740 3903944 chr6 170899992 - 2126149 2126361 12324873
+52 0 8
+26 2 2
+124
+
+chain 17461 chr6_cox_hap2 4795371 + 3908117 3908804 chr7 158821424 + 50608340 50609026 3099178
+57 90 88
+74 250 251
+108 69 69
+39
+
+chain 17263 chr6_cox_hap2 4795371 + 3953714 3953921 chr4 191273063 + 3978296 3978500 12788147
+50 3 0
+26 4 4
+124
+
+chain 16515 chr6_cox_hap2 4795371 + 3904181 3904724 chr8 146274826 - 138245724 138246268 13519146
+75 324 325
+78 15 15
+51
+
+chain 16283 chr6_cox_hap2 4795371 + 3331225 3331402 chr2 242951149 + 128261675 128261851 587006
+28 2 1
+147
+
+chain 15874 chr6_cox_hap2 4795371 + 2807758 2808190 chr6 170899992 + 31412763 31413204 14155918
+58 158 158
+72 76 85
+68
+
+chain 15671 chr6_cox_hap2 4795371 + 1369735 1370970 chr6 170899992 - 139552636 139553881 14365445
+56 408 416
+54 620 622
+97
+
+chain 15351 chr6_cox_hap2 4795371 + 2854893 2855094 chr11 134452384 + 74426248 74426449 14701290
+99 26 26
+76
+
+chain 15299 chr6_cox_hap2 4795371 + 2737173 2739469 chr4 191273063 + 161293453 161295747 2664175
+134 30 30
+77 352 352
+1 899 896
+68 663 664
+72
+
+chain 15059 chr6_cox_hap2 4795371 + 3958379 3959329 chr11 134452384 - 110535166 110536123 15004208
+57 287 282
+82 464 476
+60
+
+chain 14920 chr6_cox_hap2 4795371 + 2854607 2854845 chr12 132349534 + 55181251 55181530 15152322
+65 69 110
+104
+
+chain 14553 chr6_cox_hap2 4795371 + 4145755 4147026 chr20 62435964 - 45982841 45983887 15553025
+59 654 439
+82 417 407
+59
+
+chain 14203 chr6_cox_hap2 4795371 + 4064060 4064210 chr6 170899992 - 148625201 148625351 15961753
+150
+
+chain 14065 chr6_cox_hap2 4795371 + 3965480 3965632 chr6 170899992 - 138279004 138279156 16120854
+152
+
+chain 13894 chr6_cox_hap2 4795371 + 1411227 1413617 chr6 170899992 + 30021566 30022999 16323534
+75 1920 964
+70 255 254
+70
+
+chain 13590 chr6_cox_hap2 4795371 + 4063892 4064036 chr2 242951149 + 178053314 178053458 16703151
+144
+
+chain 13480 chr6_cox_hap2 4795371 + 1351610 1352327 chr6 170899992 + 29984509 29985227 16847522
+104 551 552
+62
+
+chain 13240 chr6_cox_hap2 4795371 + 3973235 3974493 chr6 170899992 + 32656086 32657213 17156367
+52 422 421
+78 652 522
+54
+
+chain 12556 chr6_cox_hap2 4795371 + 1412173 1412312 chr2 242951149 - 184047846 184047985 18149165
+139
+
+chain 12225 chr6_cox_hap2 4795371 + 3953994 3954124 chr13 114142980 - 45055283 45055413 18644548
+130
+
+chain 12178 chr6_cox_hap2 4795371 + 4035942 4036108 chr14 106368585 - 58343221 58343386 18718227
+55 26 25
+85
+
+chain 11746 chr6_cox_hap2 4795371 + 1363046 1363194 chr7 158821424 - 7754727 7754875 19419744
+54 14 14
+80
+
+chain 11718 chr6_cox_hap2 4795371 + 363030 363190 chr13 114142980 + 52924211 52924330 7321463
+62 41 0
+40 13 13
+4
+
+chain 11256 chr6_cox_hap2 4795371 + 4009517 4011696 chr6 170899992 + 32547334 32549511 20265569
+52 1710 1710
+59 270 268
+88
+
+chain 11034 chr6_cox_hap2 4795371 + 3906701 3906819 chr11 134452384 - 106076910 106077028 5031217
+118
+
+chain 10867 chr6_cox_hap2 4795371 + 2744958 2745115 chr6 170899992 - 132294381 132294544 20980270
+55 29 35
+73
+
+chain 10852 chr6_cox_hap2 4795371 + 2854438 2854554 chr15 100338915 - 60167597 60167713 16273329
+116
+
+chain 10738 chr6_cox_hap2 4795371 + 3960011 3960132 chr10 135374737 + 59270705 59270823 21232182
+61 3 0
+57
+
+chain 10631 chr6_cox_hap2 4795371 + 4504746 4504857 chr6 170899992 + 33168511 33168622 21069572
+111
+
+chain 10496 chr6_cox_hap2 4795371 + 3956062 3956172 chr1 247249719 - 172266041 172266151 21720779
+110
+
+chain 10389 chr6_cox_hap2 4795371 + 2738194 2739397 chr3 199501827 - 153335243 153336431 2813504
+77 463 461
+101 221 221
+81 230 217
+30
+
+chain 9881 chr6_cox_hap2 4795371 + 2797497 2798047 chr6 170899992 + 31313427 31313987 23083507
+72 423 433
+55
+
+chain 9755 chr6_cox_hap2 4795371 + 4085166 4085466 chr6 170899992 + 162410099 162410399 23379361
+65 181 181
+54
+
+chain 9455 chr6_cox_hap2 4795371 + 3955446 3955651 chr6 170899992 + 32576901 32577113 24108453
+54 91 98
+60
+
+chain 9090 chr6_cox_hap2 4795371 + 2744204 2744314 chr3 199501827 - 94209663 94209773 24799752
+53 4 4
+53
+
+chain 9032 chr6_cox_hap2 4795371 + 4005585 4007249 chr6 170899992 + 32600177 32601830 24897713
+61 1516 1505
+87
+
+chain 8805 chr6_cox_hap2 4795371 + 4070123 4070583 chr6 170899992 + 32730844 32731277 25222810
+56 347 320
+57
+
+chain 8241 chr6_cox_hap2 4795371 + 4030549 4030636 chr6 170899992 + 65319659 65319746 26041488
+87
+
+chain 7395 chr6_cox_hap2 4795371 + 3960355 3960433 chr12 132349534 + 58155129 58155207 27414638
+78
+
+chain 7276 chr6_cox_hap2 4795371 + 4034939 4035015 chr6 170899992 - 67344251 67344327 27653179
+76
+
+chain 7068 chr6_cox_hap2 4795371 + 3976155 3976230 chr3 199501827 - 153055114 153055189 28061906
+75
+
+chain 6977 chr6_cox_hap2 4795371 + 3979195 3979269 chr3 199501827 - 153056804 153056878 28244736
+74
+
+chain 6795 chr6_cox_hap2 4795371 + 2799999 2800071 chr6 170899992 + 31318116 31318188 28604513
+72
+
+chain 6742 chr6_cox_hap2 4795371 + 3906310 3906388 chr13 114142980 - 44754607 44754685 6636725
+47 2 2
+29
+
+chain 6584 chr6_cox_hap2 4795371 + 3989668 3989736 chr6 170899992 + 32559900 32559968 29100412
+68
+
+chain 6522 chr6_cox_hap2 4795371 + 4087338 4087407 chr15 100338915 + 41279078 41279147 29241043
+69
+
+chain 6495 chr6_cox_hap2 4795371 + 4147491 4147560 chr3 199501827 + 170919021 170919090 29304086
+69
+
+chain 6422 chr6_cox_hap2 4795371 + 4077507 4077575 chr6 170899992 + 32836685 32836753 29490822
+68
+
+chain 6368 chr6_cox_hap2 4795371 + 4147386 4147454 chr14 106368585 + 45132269 45132337 29601986
+68
+
+chain 6249 chr6_cox_hap2 4795371 + 2736394 2736460 chr4 191273063 - 25496702 25496768 29900240
+66
+
+chain 5885 chr6_cox_hap2 4795371 + 4087248 4087310 chr1 247249719 - 180983801 180983863 30853903
+62
+
+chain 5792 chr6_cox_hap2 4795371 + 4036108 4036169 chr10 135374737 - 103149812 103149873 26755013
+61
+
+chain 5767 chr6_cox_hap2 4795371 + 4085838 4085899 chr6 170899992 + 75566512 75566573 31174158
+61
+
+chain 5767 chr6_cox_hap2 4795371 + 4147632 4147693 chr2 242951149 - 84322530 84322591 31176268
+61
+
+chain 5731 chr6_cox_hap2 4795371 + 1376353 1376414 chr6 170899992 + 29872087 29872148 31286976
+61
+
+chain 5730 chr6_cox_hap2 4795371 + 1379511 1379571 chr6 170899992 + 29878483 29878543 31293433
+60
+
+chain 5576 chr6_cox_hap2 4795371 + 1365664 1365723 chr18 76117153 - 3609354 3609413 31727123
+59
+
+chain 5458 chr6_cox_hap2 4795371 + 4048500 4048558 chr16 88827254 + 47978524 47978582 32101537
+58
+
+chain 5403 chr6_cox_hap2 4795371 + 3960992 3961049 chr8 146274826 - 83195522 83195579 32234296
+57
+
+chain 5339 chr6_cox_hap2 4795371 + 4145490 4145546 chr3 199501827 + 495644 495700 32419958
+56
+
+chain 5275 chr6_cox_hap2 4795371 + 4086549 4086604 chr8 146274826 - 2308124 2308179 32643336
+55
+
+chain 5206 chr6_cox_hap2 4795371 + 3904515 3904580 chr1 247249719 - 87949826 87949891 19914856
+50 10 10
+5
+
+chain 5193 chr6_cox_hap2 4795371 + 4086093 4086147 chr5 180857866 + 130110350 130110404 32896485
+54
+
+chain 5184 chr6_cox_hap2 4795371 + 4084818 4084872 chrX 154913754 + 10188597 10188651 32929250
+54
+
+chain 5094 chr6_cox_hap2 4795371 + 4048238 4048292 chr6 170899992 + 68023473 68023527 33192695
+54
+
+chain 5067 chr6_cox_hap2 4795371 + 2804796 2804850 chr19 63811651 - 42284679 42284733 33279532
+54
+
+chain 5066 chr6_cox_hap2 4795371 + 1412096 1412149 chr21 46944323 - 1867343 1867396 33290791
+53
+
+chain 5020 chr6_cox_hap2 4795371 + 1409379 1409431 chr6 170899992 + 29800663 29800715 33444450
+52
+
+chain 4959 chr6_cox_hap2 4795371 + 3956009 3956062 chr18 76117153 + 5080594 5080647 22154822
+53
+
+chain 4930 chr6_cox_hap2 4795371 + 3957989 3958041 chrX 154913754 - 4434310 4434362 33717677
+52
+
+chain 4885 chr6_cox_hap2 4795371 + 2804443 2804495 chr5 180857866 - 162979708 162979760 33920646
+52
+
+chain 4847 chr6_cox_hap2 4795371 + 4047956 4048006 chr8 146274826 + 123332061 123332111 34011268
+50
+
+chain 4821 chr6_cox_hap2 4795371 + 3998874 3998925 chr6 170899992 - 10896638 10896689 34121637
+51
+
+chain 4712 chr6_cox_hap2 4795371 + 1364779 1364829 chr8 146274826 + 57925971 57926021 34511278
+50
+
+chain 4712 chr6_cox_hap2 4795371 + 4048918 4048968 chrX 154913754 + 54878538 54878588 34513604
+50
+
+chain 4392 chr6_cox_hap2 4795371 + 1377105 1377164 chr7 158821424 - 126060926 126060985 9905438
+59
+
+chain 4221 chr6_cox_hap2 4795371 + 2501082 2501164 chr14 106368585 + 74531432 74531592 4607333
+28 0 78
+54
+
+chain 4156 chr6_cox_hap2 4795371 + 3908195 3908241 chr2 242951149 - 7598530 7598576 17599965
+46
+
+chain 3903 chr6_cox_hap2 4795371 + 2908687 2909998 chr13 114142980 - 41461917 41462061 3840414
+7 46 0
+24 11 0
+33 1102 5
+19 13 0
+56
+
+chain 3865 chr6_cox_hap2 4795371 + 3903984 3904315 chr6 170899992 - 96557211 96557546 20806006
+67 210 214
+54
+
+chain 3734 chr6_cox_hap2 4795371 + 4145889 4145954 chr6 170899992 + 80018577 80018642 19955866
+65
+
+chain 3639 chr6_cox_hap2 4795371 + 3954124 3954162 chr3 199501827 + 102893836 102893874 20360982
+38
+
+chain 3394 chr6_cox_hap2 4795371 + 3959975 3960011 chrX 154913754 - 4438295 4438331 28244218
+36
+
+chain 3053 chr6_cox_hap2 4795371 + 4085231 4085263 chr2 242951149 + 38036198 38036230 24698963
+32
+
+chain 2845 chr6_cox_hap2 4795371 + 2736677 2736707 chr3 199501827 - 158108130 158108160 26771662
+30
+
+chain 2771 chr6_cox_hap2 4795371 + 2403948 2403980 chr16 88827254 + 61371572 61371604 11881973
+32
+
+chain 2645 chr6_cox_hap2 4795371 + 3954296 3954371 chr19 63811651 - 40112981 40113056 21687958
+75
+
+chain 2587 chr6_cox_hap2 4795371 + 2737535 2737662 chr15 100338915 + 91973389 91973516 3332233
+127
+
+chain 2561 chr6_cox_hap2 4795371 + 363092 363133 chr6 170899992 + 20352681 20352722 12577879
+41
+
+chain 2518 chr6_cox_hap2 4795371 + 4085322 4085377 chr16 88827254 - 20600134 20600189 24262923
+55
+
+chain 2470 chr6_cox_hap2 4795371 + 2809473 2809523 chr1 247249719 + 111577816 111577866 7596664
+50
+
+chain 2411 chr6_cox_hap2 4795371 + 3932607 3932633 chr1 247249719 - 51484714 51484740 35456234
+26
+
+chain 2403 chr6_cox_hap2 4795371 + 3907493 3907603 chr2 242951149 + 38214752 38214862 4277847
+110
+
+chain 2400 chr6_cox_hap2 4795371 + 2741593 2741618 chr4 191273063 + 159509242 159509267 32929303
+25
+
+chain 2393 chr6_cox_hap2 4795371 + 4068737 4068764 chrX 154913754 - 92588093 92588120 1797125
+27
+
+chain 2375 chr6_cox_hap2 4795371 + 3904076 3904137 chr11 134452384 - 60265228 60265289 23423532
+61
+
+chain 2319 chr6_cox_hap2 4795371 + 2964304 2964330 chr6 170899992 + 31465639 31465665 3286069
+26
+
+chain 2194 chr6_cox_hap2 4795371 + 1377065 1377105 chrX 154913754 - 101365357 101365397 11073776
+40
+
+chain 2146 chr6_cox_hap2 4795371 + 1363259 1363320 chr12 132349534 + 104221177 104221238 23825280
+61
+
+chain 2104 chr6_cox_hap2 4795371 + 4036001 4036023 chr6 170899992 - 77175689 77175711 26219289
+22
+
+chain 2011 chr6_cox_hap2 4795371 + 4029977 4029999 chrX 154913754 + 85587943 85587965 35529089
+22
+
+chain 2000 chr6_cox_hap2 4795371 + 1377237 1377270 chr4 191273063 + 153905795 153905828 8127681
+33
+
+chain 1991 chr6_cox_hap2 4795371 + 2908808 2908838 chr4 191273063 - 29946315 29946345 15287751
+30
+
+chain 1988 chr6_cox_hap2 4795371 + 3958152 3958211 chr1 247249719 + 152912877 152912936 23823437
+59
+
+chain 1918 chr6_cox_hap2 4795371 + 2736976 2737099 chr5 180857866 + 51070203 51070326 3385212
+123
+
+chain 1873 chr6_cox_hap2 4795371 + 3906133 3906260 chr5 180857866 - 144904464 144904591 3580450
+127
+
+chain 1857 chr6_cox_hap2 4795371 + 4071868 4075383 chr6 170899992 + 32830794 32834943 29519981
+61 2506 2690
+85 515 965
+52 103 103
+193
+
+chain 1825 chr6_cox_hap2 4795371 + 3906512 3906555 chr4 191273063 - 47717007 47717050 17204973
+43
+
+chain 1793 chr6_cox_hap2 4795371 + 3907342 3908508 chr2 242951149 + 97580469 97581638 5600825
+48 1090 1093
+28
+
+chain 1708 chr6_cox_hap2 4795371 + 3906388 3906482 chr7 158821424 + 109077307 109077401 4717797
+94
+
+chain 1690 chr6_cox_hap2 4795371 + 4147205 4147262 chr11 134452384 - 120264308 120264365 24918209
+57
+
+chain 1584 chr6_cox_hap2 4795371 + 1377344 1377408 chr1 247249719 - 24894387 24894451 17598707
+64
+
+chain 1503 chr6_cox_hap2 4795371 + 2736094 2736140 chr13 114142980 - 72925076 72925122 23344710
+46
+
+chain 1489 chr6_cox_hap2 4795371 + 2908702 2910078 chrX 154913754 - 101842157 101842924 6540871
+27 1297 452
+2 0 236
+50
+
+chain 1456 chr6_cox_hap2 4795371 + 3908424 3908476 chr14 106368585 + 47951043 47951095 9313420
+52
+
+chain 1455 chr6_cox_hap2 4795371 + 2738121 2739528 chr6 170899992 - 65542196 65543586 3697883
+64 1285 1268
+58
+
+chain 1368 chr6_cox_hap2 4795371 + 1377482 1377548 chr11 134452384 + 118435255 118435321 13435147
+66
+
+chain 1368 chr6_cox_hap2 4795371 + 4145973 4146044 chr5 180857866 - 127160909 127160980 20267229
+71
+
+chain 1324 chr6_cox_hap2 4795371 + 3907899 3907958 chr1 247249719 + 29601245 29601304 5732716
+59
+
+chain 1278 chr6_cox_hap2 4795371 + 3908508 3908575 chr15 100338915 + 89926442 89926509 4006770
+67
+
+chain 1265 chr6_cox_hap2 4795371 + 3904331 3904385 chr4 191273063 - 113978359 113978413 18680359
+54
+
+chain 1224 chr6_cox_hap2 4795371 + 2740399 2740456 chr4 191273063 - 135903806 135903863 24465805
+57
+
+chain 1167 chr6_cox_hap2 4795371 + 3908344 3908402 chr4 191273063 + 111464967 111465025 3502724
+58
+
+chain 1054 chr6_cox_hap2 4795371 + 3907390 3907440 chr10 135374737 + 6453196 6453246 3643427
+50
+
+chain 1002 chr6_cox_hap2 4795371 + 2736140 2736200 chr1 247249719 - 71169048 71169108 10800621
+60
+
+chain 988 chr6_cox_hap2 4795371 + 2739771 2739829 chr15 100338915 - 47558730 47558788 2837698
+58
+
+chain 983 chr6_cox_hap2 4795371 + 2737443 2737516 chr11 134452384 - 130067201 130067274 24083146
+73
+
+chain 952 chr6_cox_hap2 4795371 + 2735975 2736093 chr12 132349534 - 67686596 67686714 8250173
+118
+
+chain 919 chr6_cox_hap2 4795371 + 2740748 2740808 chr4 191273063 + 44807134 44807194 22381054
+60
+
+chain 915 chr6_cox_hap2 4795371 + 2736903 2736961 chr18 76117153 + 57868323 57868381 3224910
+58
+
+chain 912 chr6_cox_hap2 4795371 + 2740082 2740112 chr7 158821424 + 107644178 107644208 21981894
+30
+
+chain 876 chr6_cox_hap2 4795371 + 2739742 2739771 chr1 247249719 - 197271642 197271671 12596898
+29
+
+chain 869 chr6_cox_hap2 4795371 + 3907293 3907342 chr10 135374737 + 5116762 5116811 5781535
+49
+
+chain 859 chr6_cox_hap2 4795371 + 2736813 2741147 chr15 100338915 + 18498519 18502823 4451069
+52 4214 4184
+68
+
+chain 858 chr6_cox_hap2 4795371 + 2739831 2739865 chr7 158821424 - 148280259 148280293 6691657
+34
+
+chain 832 chr6_cox_hap2 4795371 + 3906555 3906608 chr11 134452384 - 48407690 48407743 4638931
+53
+
+chain 819 chr6_cox_hap2 4795371 + 3906260 3906310 chr9 140273252 + 32202289 32202339 4057214
+50
+
+chain 781 chr6_cox_hap2 4795371 + 2736320 2736393 chr5 180857866 - 50968960 50969033 9780107
+73
+
+chain 771 chr6_cox_hap2 4795371 + 3907818 3907850 chr10 135374737 - 103151561 103151593 7179825
+32
+
+chain 761 chr6_cox_hap2 4795371 + 2736552 2736619 chr2 242951149 - 140069145 140069212 14744509
+67
+
+chain 747 chr6_cox_hap2 4795371 + 1377768 1377832 chr12 132349534 + 55464534 55464598 20643860
+64
+
+chain 734 chr6_cox_hap2 4795371 + 2739880 2739936 chr3 199501827 - 145206053 145206109 3741906
+56
+
+chain 734 chr6_cox_hap2 4795371 + 2735396 2736320 chr8 146274826 - 112931559 112932176 13565225
+68 769 462
+87
+
+chain 718 chr6_cox_hap2 4795371 + 2740828 2740883 chr9 140273252 - 49339912 49339967 23555332
+55
+
+chain 716 chr6_cox_hap2 4795371 + 4147141 4147193 chr16 88827254 - 38714794 38714846 22851159
+52
+
+chain 709 chr6_cox_hap2 4795371 + 2739652 2739702 chr11 134452384 - 107252690 107252740 6149448
+50
+
+chain 685 chr6_cox_hap2 4795371 + 2738531 2738584 chrX 154913754 - 2978832 2978885 8357317
+53
+
+chain 604 chr6_cox_hap2 4795371 + 1377662 1377688 chrX 154913754 - 101148638 101148664 11583046
+26
+
+chain 566 chr6_cox_hap2 4795371 + 2740606 2740665 chr2 242951149 + 168011719 168011778 5902375
+59
+
+chain 547 chr6_cox_hap2 4795371 + 2740492 2740542 chr11 134452384 - 79794459 79794509 15991276
+50
+
+chain 544 chr6_cox_hap2 4795371 + 2738003 2738054 chr13 114142980 + 104410064 104410115 4879951
+51
+
+chain 541 chr6_cox_hap2 4795371 + 2738408 2738434 chr2 242951149 - 229173591 229173617 17449766
+26
+
+chain 532 chr6_cox_hap2 4795371 + 2740024 2740082 chr9 140273252 - 118104609 118104667 4462652
+58
+
+chain 525 chr6_cox_hap2 4795371 + 3966448 3966514 chr6 170899992 + 32582000 32582066 26144539
+66
+
+chain 497 chr6_cox_hap2 4795371 + 2738584 2738618 chr12 132349534 + 9890463 9890497 23880878
+34
+
+chain 493 chr6_cox_hap2 4795371 + 2739023 2739056 chr22 49691432 + 27063354 27063387 3888752
+33
+
+chain 395 chr6_cox_hap2 4795371 + 2909998 2910026 chrX 154913754 - 101842939 101842967 6370567
+28
+
+chain 367 chr6_cox_hap2 4795371 + 2735248 2735298 chrX 154913754 + 118995097 118995147 25845816
+50
+
+chain 290 chr6_cox_hap2 4795371 + 2741541 2741593 chr1 247249719 - 204952078 204952130 18508596
+52
+
+chain 288 chr6_cox_hap2 4795371 + 3906008 3906069 chr4 191273063 - 55159498 55159559 26293742
+61
+
+chain 182 chr6_cox_hap2 4795371 + 3905895 3905941 chr9 140273252 + 29711555 29711601 32244349
+46
+
+chain 172 chr6_cox_hap2 4795371 + 4087589 4087640 chr1 247249719 - 204983626 204983677 25877235
+51
+
+chain 361837920 chr6_dbb_hap3 4610396 + 0 4610396 chr6 170899992 + 28804582 33437054 36
+932 3 0
+804 0 1
+2406 2 0
+9637 0 1
+2736 6 0
+4013 2 0
+6498 4 0
+6886 0 4
+15284 1 0
+937 0 8
+13552 0 2
+3960 0 2
+2111 0 2
+41 19 0
+8992 0 4
+59229 107905 107904
+87624 0 1
+5902 0 1
+31697 7 0
+1489 1 1
+72 1 1
+2260 0 2
+7033 0 4
+3592 0 1
+19578 0 1
+1324 0 2
+5438 5 0
+2061 1 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4746 9 9
+4767 7 7
+1225 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+249 43 43
+1178 0 4
+685 8 0
+48 4 0
+1701 1 1
+43 5 5
+862 18 18
+58 1 1
+66 1 1
+420 1 1
+44 1 1
+680 4 4
+1675 1 1
+83 1 1
+3082 4 0
+5467 1 1
+27 0 1
+1099 12 0
+627 12 12
+1317 6 1
+129 1 1
+25 1 1
+1397 15 15
+810 1 1
+27 1 1
+1192 3 0
+7515 4 0
+979 0 3
+3406 0 2
+3501 1 1
+26 1 1
+787 0 1
+1416 3 1
+22815 4 4
+126 1 0
+38 1 1
+140 1 0
+999 0 17
+56 0 15
+15438 4 0
+6165 0 1
+1768 1 0
+7727 1 0
+1514 0 1
+3116 0 1
+3278 1 1
+21 1 1
+1738 0 1
+8576 19 0
+8020 1 0
+2049 1 0
+518 13 11
+1704 1 1
+117 1 1
+1448 10 0
+4403 9 9
+2265 1 0
+25400 9 9
+4420 1 1
+32 1 1
+2539 1 0
+9981 17923 17922
+148 1 1
+25 1 1
+1461 4 1
+1402 0 1
+3961 0 3
+58 1 1
+112 1 1
+1419 1 1
+34 0 1
+2697 0 2
+40 1 1
+2168 0 1
+1019 0 2
+1099 0 4
+40 1 1
+1374 11 0
+31 1 1
+189 1 1
+26 1 1
+327 1 1
+38 1 1
+177 11 11
+303 1 1
+34 1 1
+1438 1 1
+46 1 1
+727 1 1
+26 1 1
+2373 5 0
+321 1 0
+933 17 17
+82 9 9
+2773 0 143
+80 1 1
+25 1 1
+467 1 1
+27 1 1
+143 1 1
+47 4 4
+1194 10 10
+1455 1 1
+33 1 1
+601 1 1
+46 0 4
+694 1 3
+91 1 1
+59 1 1
+167 6 6
+113 1 1
+31 1 1
+1181 0 1
+422 15 0
+36 1 1
+2219 1 1
+35 1 1
+2116 0 1
+8249 0 3
+1120 1 0
+870 16 0
+5547 0 2
+5376 0 6
+2275 1 1
+43 1 1
+78 4 4
+24710 1 0
+64762 6 3
+441 1 0
+2338 1 0
+1948 1 1
+26 1 1
+214 0 1
+6118 1 1
+31 1 1
+2382 5 5
+4335 1 1
+39 1 1
+4561 1 1
+38 1 1
+2199 1 1
+49 1 1
+243 17 6
+2779 1 1
+37 2 0
+24 1 1
+1966 3 0
+233 1 1
+29 1 1
+17718 6 0
+46568 1 0
+18985 0 2
+1833 3 4
+5288 0 9
+2728 1 5
+722 0 1
+502 0 1
+1025 0 1
+134 14 0
+4944 0 1
+319 1 0
+6178 0 1
+2880 1 1
+17 0 2
+143 0 1
+1775 1 0
+2123 0 1
+2715 1 0
+4921 1 1
+47 4 0
+2882 1 0
+1362 1 0
+1233 0 8
+2134 0 1
+1042 0 1
+163 1 1
+45 1 1
+50 2 0
+64 1 1
+48 1 1
+380 0 1
+30 1 0
+30 1 1
+61 1 1
+22 1 1
+691 0 2
+84 1 1
+230 1 1
+37 3 1
+162 1 1
+194 2 0
+36 1 1
+242 9 9
+697 33 33
+1202 1 1
+16 1 1
+528 1 1
+20 1 1
+131 9 9
+369 0 5
+76 1 1
+21 1 1
+439 15 15
+2779 1 0
+1597 24 28
+59 12 12
+307 1 0
+516 1 0
+286 11 33
+339 5 0
+570 1 1
+37 1 1
+220 1 0
+72 1 1
+144 1 1
+48 1 1
+247 2 0
+174 9 10
+816 1 0
+940 1 1
+45 1 1
+91 3 3
+71 1 1
+291 14 14
+100 1 1
+23 1 1
+452 3 3
+229 1 1
+252 0 1
+129 15 15
+432 10 0
+85 1 1
+28 1 1
+189 2 1
+71 1 1
+52 8 0
+810 2 2
+63 1 1
+378 1 1
+26 1 1
+187 31 36
+966 1 1
+25 1 1
+91 12 12
+125 1 1
+38 1 1
+433 2 0
+596 1 1
+48 1 1
+465 4 4
+64 1 1
+20 1 1
+525 5 5
+237 3 8
+99 31 31
+53 11 0
+364 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+67 16 16
+244 1 1
+54 5 5
+929 1 1
+21 1 1
+126 0 3
+830 1 11
+59 1 1
+537 0 2
+24 1 1
+745 15 15
+810 1 0
+425 1 1
+89 1 1
+592 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 1 1
+39 1 1
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+155 156 0
+34 1 1
+50 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+345 1 1
+39 1 1
+504 18 18
+596 12 12
+54 1 1
+158 1 1
+164 1 1
+34 1 1
+626 15 15
+866 0 10
+1051 0 2611
+680 0 1
+1537 0 18
+75 1 0
+145 6 0
+9 39 0
+107 0 18
+23 1 1
+1927 13 13
+1702 2 0
+3694 1 1
+18 1 1
+958 39 47
+246 2 0
+146 1 1
+49 1 1
+410 1 0
+667 1 1
+38 1 1
+362 7 1
+159 2 0
+515 2 0
+1026 1 1
+29 1 1
+249 0 6
+129 1 1
+33 4 0
+10 1 5
+1236 1 1
+20 1 1
+138 10 9
+448 0 3
+660 1 1
+28 1 1
+83 1 1
+51 1 1
+2659 1 1
+38 1 1
+424 0 1
+70 1 1
+694 1 1
+19 1 1
+105 1 1
+26 1 1
+1472 1 1
+21 1 1
+491 5 5
+163 15 15
+2194 2 0
+533 2 0
+441 1 7
+1689 1 1
+26 3 4
+879 16 16
+514 0 2
+58 1 1
+350 1 0
+769 1 1
+39 1 1
+573 0 4
+37 1 1
+144 8 8
+1036 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+169 62 63
+74 11 15
+1255 0 2
+332 1 1
+21 1 1
+193 8 24
+34 1 1
+79 1 1
+29 1 1
+536 1 0
+308 0 1
+850 0 32
+23 1 1
+651 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 2
+713 7 7
+89 1 0
+293 9 8
+125 1 1
+31 1 1
+192 6 6
+171 17 17
+681 1 1
+43 1 1
+514 1 1
+68 1 1
+537 1 1
+35 1 1
+159 6 6
+778 17 17
+198 0 7
+105 1 1
+40 1 1
+95 13 13
+247 1 1
+19 1 1
+2044 7 8
+2512 0 15
+2982 4 0
+3135 1 2
+1698 13 13
+15862 0 1
+925 0 183
+36 16 1
+18 0 1
+25 1 1
+7717 1 1
+40 1 1
+758 1 1
+46 1 1
+5530 11 9
+3326 1 1
+37 1 1
+6743 0 4
+7923 1 1
+26 5 5
+3475 26 0
+8 1 1
+566 4 0
+141 0 1
+2078 24 24
+2759 0 4
+1659 4 0
+52 4 0
+3265 0 2
+2235 17 16
+2946 0 372
+2644 31 31
+92 1 1
+35 1 1
+705 323 0
+3157 40 40
+718 0 4
+787 1 1
+34 1 1
+927 4 4
+72 1 1
+2414 0 1
+993 1 1
+31 1 1
+1514 1 1
+29 1 1
+1109 1 1
+44 1 1
+208 4 1
+1022 11767 11699
+85 98 98
+60 2515 8169
+103 11 11
+41 1 1
+72 4 4
+76 1 1
+70 5 5
+83 1 1
+117 1 1
+130 1 1
+44 1 1
+414 1 1
+152 1 0
+218 1 1
+161 1 0
+120 14 14
+145 1 1
+49 4 4
+72 1 1
+53 19 19
+111 2 2
+32 3 3
+553 0 2
+336 12 12
+54 24 24
+171 0 6
+90 1 1
+28 1 1
+142 16 16
+36 1 1
+428 1 1
+16 1 1
+338 1 1
+31 1 1
+294 1 1
+92 0 1
+129 13 14
+602 1 1
+112 1 1
+247 1 1
+80 1 1
+173 1 1
+44 1 5
+497 1 1
+38 1 1
+98 1 1
+130 1 1
+319 1 1
+16 1 1
+59 1 1
+82 1 1
+141 1 1
+23 1 1
+241 1 1
+26 1 1
+184 0 3
+19 1 1
+510 1 1
+36 1 1
+162 2 2
+15 1 1
+145 1 1
+28 1 1
+120 0 3
+93 1 2
+24 0 9
+169 12 0
+292 9911 10000
+401 1 1
+27 1 1
+296 1 1
+120 1 1
+357 1 1
+107 2 0
+31 1 1
+83 89 0
+194 1 1
+33 1 1
+230 1 1
+142 5 5
+108 1 1
+36 1 1
+287 1 1
+19 1 1
+104 1 1
+31 1 1
+144 1 1
+212 1 1
+452 5 6
+148 1 1
+70 1 1
+137 3 3
+67 1 1
+73 22 22
+115 12 12
+142 5 5
+269 15 15
+102 6 6
+93 1 1
+82 1 1
+170 1 1
+22 1 1
+504 2 2
+60 1 1
+150 1 1
+31 1 1
+90 1 1
+15 1 0
+258 6 7
+85 1 1
+77 1 1
+123 2 2
+67 0 1
+56 2 2
+25 1 1
+71 1 1
+28 2 2
+50 1 1
+85 2 2
+66 6 6
+186 1 1
+20 1 1
+67 1 1
+25 1 1
+227 2 2
+155 1 1
+777 1 1
+33 1 2
+26 6 6
+474 1 1
+36 1 1
+151 1 1
+29 1 1
+120 1 1
+23 1 1
+736 17 17
+112 1 1
+39 1 1
+553 1 1
+69 1 1
+116 2 0
+161 1 1
+86 1 1
+705 1 1
+57 3 3
+145 1 1
+204 1 1
+88 1 1
+35 1 1
+92 1 1
+147 1 1
+149 20 20
+210 1 1
+55 2 2
+65 1 1
+32 1 1
+1008 1 1
+24 1 1
+159 18 18
+391 0 1
+327 17 19
+77 1 3
+65 1 1
+84 1 0
+392 2 0
+363 1 0
+1024 0 1
+480 9 9
+119 1 1
+72 1 1
+400 1 1
+46 1 1
+288 11 7
+53 1 1
+80 1 1
+37 1 1
+129 1 1
+80 1 1
+252 4 4
+86 0 1
+129 3 3
+67 1 1
+123 9 9
+199 2 2
+80 1 1
+114 28369 30000
+51 5 5
+45 1 1
+53 1 1
+37 1 1
+81 1 1
+369 1 1
+72 15 15
+98 1 1
+53 0 8
+67 2 0
+41 1 1
+92 1 1
+20 1 1
+283 6 6
+70 7 7
+50 1 1
+25 1 1
+225 5 1
+31 1 1
+449 2 1
+10 1 23
+64 4 4
+3770 1 0
+3862 16 16
+1187 12 12
+97 0 3
+772 1 1
+21 2 1
+1058 0 2
+349 2 0
+1080 18 14
+53 15 17
+1035 1 1
+85 1 1
+69 1 1
+27 1 1
+547 7 7
+195 1 1
+41 1 1
+395 1 1
+35 1 1
+73 0 1
+71 1 1
+557 3 3
+30 1 1
+66 1 1
+25 1 1
+1332 0 2
+26 2 0
+10 1 15
+36 1 1
+196 1 1
+40 1 1
+141 1 1
+76 1 1
+1480 1 3
+347 1 1
+26 1 1
+231 1 1
+82 3 3
+69 3 0
+441 16 16
+147 1 1
+21 1 1
+3565 0 6
+874 2 0
+1036 1 1
+47 3 1
+3761 12 0
+5345 1 0
+11541 1 0
+1843 0 4
+1157 16 16
+7354 19 0
+741 0 1
+8053 1 0
+4449 21 21
+649 1 0
+2913 0 1
+381 332 0
+3533 31 31
+2502 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3870 0 1
+36 13 0
+1894 1 1
+40 0 4
+1348 2 0
+345 1 0
+592 4 4
+1043 4 0
+686 14 0
+1032 0 1
+9035 0 4
+167 0 2
+13644 6258 6257
+4063 0 3
+1760 3 0
+3371 1 1
+23 1 1
+321 5 0
+644 8 0
+47 1 1
+322 1 1
+145 1 1
+1551 11 15
+355 0 1
+1831 4 0
+1779 1 1
+27 1 1
+199 43 55
+2881 1 1
+39 1 1
+120 1 2
+24 1 1
+556 1 0
+393 6 6
+4381 1 0
+524 1 1
+20 1 1
+151 3 3
+144 1 1
+189 1 7
+1445 0 1
+1002 0 1
+7912 4 0
+4977 0 1
+10485 1 1
+48 1 1
+724 1 1
+51 5 0
+39 1 1
+6830 0 1
+15554 0 1
+4385 0 7
+881 0 8
+17594 0 20
+2417 1 0
+998 0 10
+4239 7 0
+4845 0 2
+95 28 23
+10921 1 1
+40 1 1
+4759 0 6
+12084 0 3
+3052 0 4
+2989 1 0
+13523 1 3
+16170 1 0
+11761 0 6
+1158 3 0
+2751 0 6
+1294 1 1
+43 1 1
+5275 0 7
+377 3 0
+7256 3 0
+419 2 0
+10674 0 17
+10821 0 1
+296 0 1
+1770 2 0
+374 0 3
+7469 0 4
+1471 1 0
+3061 2 0
+5818 1 0
+2415 11 9
+2056 0 1
+955 4 0
+17260 1 0
+9557 0 2
+5358 0 1
+11538 4 0
+2627 2 0
+57496 1 1
+29 1 1
+6617 19 0
+254 0 1
+14267 2 0
+9045 3 1
+174 2 0
+4155 1 0
+1153 1 0
+1289 0 40
+12155 0 4
+7692 2 0
+396 22 12
+918 0 1
+1818 0 1
+28 1 1
+492 1 1
+33 1 1
+326 1 1
+80 1 1
+288 8 17
+2671 0 1
+1099 0 1
+144 1 1
+29 0 1
+2098 0 2
+24 3 0
+1207 4 4
+45 1 1
+757 0 5
+1926 1 1
+40 1 1
+330 3 0
+340 1 1
+43 1 1
+1942 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+754 0 4
+17 3 0
+1027 3 0
+428 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+8189 4 5
+36 1 1
+99 2 0
+700 0 4
+149 0 1
+750 0 3
+40 1 1
+3179 2 0
+473 0 2
+2032 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+11881 1 1
+30 1 1
+4383 3 0
+9930 1 1
+56 510 509
+518 8 5
+853 1 1
+80 1 1
+2210 1 0
+905 0 1
+1037 2 0
+5866 0 2
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 2 0
+700 1 1
+1970 0 1
+498 1 0
+1751 0 1
+910 2 0
+691 0 1
+32873 0 1
+19298 0 6
+1371 29 0
+494 2 0
+39050 0 1
+920 0 1
+6820 1 0
+1376 1 2
+1931 33 33
+2376 0 1
+12415 1 1
+51 0 1
+9375 0 1
+323 1 0
+2697 1 0
+15090 120 0
+7116 1 0
+2469 1 0
+5977 2 1
+4888 0 4
+4674 1 0
+2044 1 0
+2153 0 1
+1964 5 5
+2153 1 1
+41 1 1
+774 0 2
+2623 1 1
+81 1 1
+335 2 2
+59 1 1
+335 0 3
+533 2 0
+45 4 0
+986 2 0
+13 1 1
+450 28 27
+295 1 0
+202 1 1
+27 1 1
+70 312 0
+218 1 0
+51 1 1
+31 1 1
+428 0 1
+28 1 1
+118 1 1
+24 1 18
+34 1 1
+75 1 1
+43 2 2
+73 1 1
+29 1 1
+246 1 1
+42 1 1
+409 4 4
+1168 10 1
+310 1 1
+49 1 1
+3002 1 1
+38 1 1
+789 0 1
+63 9 9
+2434 0 8
+980 0 2
+749 8 8
+528 1 1
+24 1 1
+1646 15 15
+528 1 1
+16 1 1
+1402 1 1
+23 1 1
+67 7 0
+35 2 0
+7 0 2
+221 1 1
+45 1 1
+259 1 1
+47 1 1
+384 1 1
+47 1 1
+330 0 4
+490 1 1
+33 1 1
+1841 1 1
+52 0 2
+6 11 0
+193 1 1
+47 1 1
+164 3 7
+31 0 1
+291 1 1
+15 1 1
+877 4 0
+30 1 1
+194 6 0
+93 4 4
+1004 1 1
+20 1 1
+345 1 1
+43 1 1
+365 0 1
+388 1 1
+27 1 1
+253 9 9
+390 1 0
+118 0 1
+170 4 0
+915 1 0
+352 0 4
+520 1 1
+29 20 0
+1167 1 1
+45 1 1
+213 8 0
+51 1 1
+107 10 11
+134 2 0
+228 103 1
+51 2 1
+68 1 1
+59 1 1
+195 1 161
+13 1 1
+553 2 2
+36 1 1
+143 1 0
+1874 4 0
+519 0 1
+476 1 0
+1530 0 1
+1126 2 0
+831 1 1
+40 1 1
+1131 88 87
+2063 0 2
+1950 1 1
+32 1 1
+2217 2 1
+661 0 2
+1239 0 1
+64 1 1
+33 1 1
+13968 0 1
+1222 2 0
+5082 10 0
+413 0 1
+986 23 22
+1194 2527 2526
+12324 0 2
+893 8 0
+1343 2 0
+5784 9 9
+770 12 0
+1044 2 0
+2231 1 1
+48 1 1
+557 0 1
+7497 8 8
+1051 16 0
+49 1 1
+10474 0 3
+1427 1 0
+670 1 3
+766 1 1
+32 1 1
+395 0 9
+170 1 0
+792 2 0
+286 1 0
+117 11 12
+283 26 21
+277 0 2
+48 1 1
+124 1 1
+34 2 1
+316 1 1
+41 1 1
+8214 0 8
+368 2 0
+4 4 0
+3535 17 0
+4228 33 33
+945 0 1
+562 0 1
+1440 0 1
+804 0 11
+1565 0 3
+3008 1 0
+31 1 1
+800 21 17
+650 1 1
+30 1 1
+82 13 13
+5212 1 0
+2003 1 2
+12179 0 1
+2700 2 0
+2735 0 1
+4202 0 3
+4503 1 0
+270 1 0
+12929 0 3
+4009 0 5
+6425 2 0
+310 1 0
+809 2 0
+17 8 0
+2256 0 1
+3207 17 10
+2436 0 14
+1040 1 1
+52 1 1
+6972 1 0
+2357 0 1
+29 1 1
+262 1 0
+72 1 1
+45 1 1
+57 17 17
+1390 0 16
+328 312 0
+65 1 1
+217 10 10
+925 0 33
+1490 1 0
+35 1 1
+226 0 3
+805 1 1
+46 1 1
+192 1 1
+56 1 1
+245 1 1
+61 1 1
+198 4 0
+82 2 2
+29 1 1
+57 0 2
+320 1 1
+22 1 1
+267 5 0
+427 1 0
+17 1 1
+425 1 1
+34 1 1
+565 10 10
+432 10 0
+55 1 1
+90 1 1
+140 1 1
+83 1 1
+1035 1 1
+33 1 1
+144 4 4
+38 1 1
+171 1 1
+35 3 3
+161 6 6
+731 7 3
+1216 25 0
+52 0 1
+419 2 0
+87 8 8
+757 1 1
+67 1 1
+3935 30 0
+791 3 0
+2849 1 1
+33 1 1
+6790 1 1
+67 4 4
+39 2 0
+251 1 1
+37 1 1
+826 3715 901
+205 2 0
+946 1 1
+30 1 1
+613 5 2
+128 29 29
+802 0 89
+1600 0 6
+2112 1 1
+42 1 0
+1164 1 0
+1310 1 0
+1501 0 4
+822 1 1
+42 1 1
+2266 1 0
+25235 0 1
+6697 1 0
+766 1 0
+4188 0 2
+2710 1 1
+17 1 1
+1924 0 7
+5868 1 1
+22 1 1
+2394 0 4
+125 3 0
+718 1 0
+8414 1 1
+49 1 1
+146 1 1
+61 1 1
+116 1 1
+41 1 1
+137 1 1
+30 1 1
+158 9 9
+136 10 13
+1733 17 17
+1053 4 4
+228 1 1
+34 1 1
+355 1 1
+113 1 1
+330 0 1
+222 1 1
+25 1 1
+267 1 1
+38 1 1
+709 2 0
+1448 0 1
+152 1 1
+46 1 1
+237 1 1
+20 1 1
+195 21 21
+88 1 1
+33 1 1
+211 1 1
+65 1 1
+516 58 58
+491 7 7
+208 13 12
+558 2 2
+28 1 1
+125 4 4
+634 1 1
+33 1 1
+159 0 1
+318 1 0
+370 5 5
+80 1 1
+250 0 3
+78 1 1
+45 1 1
+130 3 1
+22 0 1
+180 1 1
+90 1 1
+633 1 1
+36 0 1
+388 0 1
+861 1 1
+103 1 1
+274 16 18
+170 30 30
+796 0 1
+167 0 1
+871 1 1
+27 1 1
+32 0 8
+831 0 13
+90 1 1
+527 1 1
+125 1 1
+1050 10 10
+624 16 16
+1093 5 5
+48 1 0
+168 30 34
+1315 1 1
+33 1 1
+303 1 1
+36 1 1
+601 14 14
+1014 4 0
+134 2 9
+818 1 0
+61 1 7
+641 5 5
+1677 1 1
+49 1 1
+346 87 87
+790 27 27
+104 1 1
+75 1 1
+1638 1 1
+16 1 1
+92 1 1
+44 1 1
+276 0 13
+1020 1 1
+35 1 1
+389 14 14
+256 1 0
+38 1 3
+106 1 1
+21 1 1
+502 1 1
+40 1 1
+2356 1 1
+82 2 0
+1300 0 5
+511 0 2
+605 1 1
+17 1 1
+880 13 0
+1689 4 0
+2492 1 1
+39 1 1
+641 16 16
+682 0 5
+669 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+501 4 1
+317 0 1
+281 3 0
+450 1 1
+34 1 1
+498 1 1
+28 2 1
+280 0 2
+648 1 1
+47 1 1
+1002 4 0
+120 1 1
+1538 0 1
+75 1 1
+37 1 1
+517 1 1
+79 4 4
+60 18 18
+2075 1 1
+19 1 1
+2429 1 1
+21 1 1
+107 1 0
+2786 0 2
+33 3 3
+1973 8 0
+3118 1 0
+246 0 1
+33 1 1
+1333 9 9
+5410 1 0
+822 2 9
+606 1 1
+18 1 1
+3920 1 1
+37 0 2
+4497 10 13
+2468 2 0
+1510 1 1
+23 1 1
+308 0 4
+3780 3 0
+850 0 1
+2774 0 3
+3487 1 0
+3243 0 15
+1336 5 0
+618 7 7
+1507 8 7
+379 44 43
+2184 0 1
+304 0 2
+19 0 1
+101 1 1
+417 3 3
+22 1 1
+672 4 4
+31 1 1
+150 1 1
+38 1 1
+161 5 0
+17 1 1
+72 1 0
+106 1 1
+463 1 1
+236 0 2
+184 1 1
+29 1 1
+220 15 15
+167 1 1
+32 1 1
+93 1 3
+217 1 1
+23 1 1
+137 9 9
+62 0 3
+353 1 1
+27 1 1
+117 9 9
+421 1 1
+47 1 1
+124 0 1
+997 6 0
+54 5 5
+764 1 1
+45 1 1
+1431 7 7
+387 6 6
+1103 0 44
+759 1 1
+31 1 3
+208 5 5
+1610 1 1
+23 1 1
+779 0 8
+311 0 3
+322 0 3
+45 1 1
+250 1 1
+18 1 1
+517 29 0
+117 1 1
+42 1 1
+550 1 1
+20 1 1
+671 1 1
+68 1 1
+89 1 1
+104 1 1
+172 0 1
+124 0 1
+522 0 1500
+466 5 5
+32 1 0
+171 1 1
+19 1 1
+67 1 1
+22 1 1
+654 1 1
+25 1 1
+68 1 1
+21 4 0
+1588 1 1
+66 1 1
+401 0 1
+186 1 1
+21 1 1
+168 0 1
+686 3 0
+19 1 1
+127 1 1
+29 1 1
+234 1 1
+30 1 1
+141 0 2
+33 1 1
+673 1 1
+89 1 1
+161 16 16
+504 1 1
+192 0 3
+105 1 1
+286 1 1
+101 15 16
+158 8 0
+57 1 1
+332 2 2
+35 1 1
+371 1 1
+55 1 1
+86 1 1
+29 1 1
+196 1 1
+44 1 0
+52 19995 20030
+60 8 8
+50 0 3
+129 1 1
+281 1 1
+30 1 1
+109 1 1
+35 1 1
+113 1 1
+34 1 1
+734 1 1
+44 1 1
+106 1 1
+62 1 1
+140 1 1
+76 1 0
+34 1 1
+98 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 1 1
+55 1 1
+1470 0 7
+258 1 1
+48 1 1
+1807 6 6
+63 1 1
+32 1 1
+346 18 18
+9596 12 0
+3853 9 9
+317 4 4
+30 1 1
+71 1 1
+60 1 1
+103 10 10
+71 2 0
+30 1 1
+312 5 0
+170 13 13
+55 2 2
+58 1 0
+30 1 1
+189 37 38
+827 0 17
+26 1 1
+1461 1 1
+24 1 1
+2968 22 22
+137 12 14
+889 11 11
+4010 0 6
+1377 1 1
+34 1 1
+312 1 1
+16 1 1
+715 1 1
+24 1 1
+930 1 1
+22 1 1
+89 1 1
+42 1 1
+108 44 45
+228 149088 159295
+108 1 1
+41 1 1
+11025 4 4
+1194 1 1
+59 1 1
+128 1 0
+1177 82 82
+60 1 1
+48 1 1
+501 19 19
+336 1 1
+42 1 1
+176 4 4
+469 1 1
+35 1 1
+270 1 1
+33 1 1
+289 1 1
+24 1 1
+226 64 0
+42 1 1
+651 1 1
+39 1 1
+123 1 1
+35 1 0
+294 1 1
+32 18 4
+351 1 1
+39 1 1
+135 1 1
+46 1 1
+121 1 1
+19 1 1
+755 4 4
+70 1 1
+456 39 36
+82 1 1
+48 1 1
+441 1 1
+70 1 1
+381 1 1
+46 1 1
+239 1 1
+30 1 1
+87 1 1
+102 3 4
+34 1 1
+488 12 12
+1059 1 1
+45 1 1
+705 1 1
+21 1 1
+107 111 111
+432 3 0
+460 4 4
+1212 0 2
+306 0 1
+1446 19 19
+299 7 33
+78 195 6
+66 1 1
+135 12 12
+778 1 0
+773 1 1
+45 1 1
+253 6 6
+823 1 1
+22 1 1
+2476 10 0
+294 28 10
+307 3 11
+65 0 4
+40 1 1
+4535 1 1
+26 1 1
+371 0 2
+3510 1 1
+16 1 1
+189 1 1
+19 1 1
+814 0 1
+2785 6 1
+1424 0 1
+934 1 1
+49 1 1
+1350 1 0
+384 1 1
+24 1 1
+3117 10 10
+518 0 1
+523 0 16
+243 10 10
+2167 18 14
+64 1 1
+31 1 1
+185 0 4
+1647 1 1
+20 1 1
+227 1 1
+37 1 1
+636 3 4
+8239 1 1
+23 1 1
+1114 0 2
+1590 18 18
+4781 0 4
+815 0 1
+5069 0 5
+415 0 1
+3541 0 1
+878 0 1
+5752 0 2
+1502 0 1
+51 1 1
+60 1 1
+278 0 1
+19 1 1
+1164 11 11
+691 0 2
+960 1 0
+63 0 18
+2109 0 2
+1265 0 1
+1642 2 0
+10831 4 2
+188 0 1
+1650 1 0
+40 1 1
+2962 2 0
+48 1 1
+4899 6 0
+4945 1 0
+60 4 0
+964 0 1
+918 1 0
+706 0 3
+349 1 0
+1673 0 1
+1909 11 11
+1662 15 0
+720 0 1
+2076 0 2
+329 14 0
+3605 0 3
+853 5 6
+3597 1 0
+378 0 1
+969 2 0
+299 0 1
+874 0 4
+663 6 0
+297 0 3
+2049 0 3
+878 11 11
+93 43 43
+13912 0 1
+398 1 1
+145 1 1
+512 16 16
+3139 0 4
+1305 7 0
+3045 1 0
+4179 1 1
+37 1 1
+1336 4 0
+13736 1 0
+11145 1 0
+3867 1 0
+1713 0 1
+2721 0 9
+8875 0 2
+4120 2 0
+13331 0 2
+15149 0 1
+8815 2 0
+1617 0 1
+1686 4 0
+2225 4 0
+7008 1 0
+4374 0 1
+2620 4 0
+43394 1 0
+10823 4 0
+25730 0 1
+554 1 0
+128 0 1
+8274 17 17
+22100 0 4
+40775 1 0
+5693 29 27
+170 1 0
+3528 0 1
+191 1 2
+117 2 0
+2275 1 0
+12676 1 1
+20 1 1
+5364 1 0
+1275 0 2
+3331 1 0
+310 1 0
+13645 0 5
+14860 1 1
+38 1 1
+3605 0 1
+2898 0 1
+10662 1 0
+8241 17 17
+439 16 16
+59 5 4
+7707 1 0
+3007 1 1
+40 1 1
+1569 1 1
+30 1 1
+163 11 11
+8253 35 6402
+5016 17 17
+439 16 16
+59 4 5
+9184 1 1
+19 1 1
+2941 1 1
+105 1 1
+803 5 4
+1011 1 1
+43 1 1
+705 8 8
+574 1 0
+7691 1 0
+5183 0 2
+9452 5 0
+45 0 8
+4438 1 0
+6869 1 0
+1770 0 1
+4094 0 12
+4249 0 3
+4114 0 1
+1404 0 1
+1229 0 2
+3129 0 10
+769 0 2
+709 1 0
+161 0 1
+969 0 1
+1492 0 7
+655 8 8
+251 0 2
+234 1 0
+19500 0 2
+8097 1 0
+1243 0 4
+718 0 2
+1466 1 0
+527 1 0
+3294 1 0
+299 0 1
+374 1 0
+107 1 1
+21 1 1
+2114 0 1
+1422 0 1
+2149 1 0
+311 2 0
+2025 1 1
+36 1 1
+4504 2 0
+3636 10 0
+588 1 1
+21 1 1
+3237 15 0
+39 6 0
+547 74304 74303
+1020 0 3
+747 0 1
+1011 1 1
+43 1 1
+3164 1 0
+1681 0 2
+473 1 5
+107 4 0
+719 0 1
+1154 9 9
+221 0 2
+9332 1 0
+1190 30 0
+783 1 1
+59 1 1
+94 1 1
+21 1 1
+430 11 11
+50 1 1
+49 1 1
+289 3 0
+120 0 1
+37 1 1
+112 1 1
+21 1 1
+183 16 16
+73 2 0
+1007 1 1
+38 0 1
+79 1 1
+48 1 1
+561 1 1
+29 1 1
+145 5 5
+576 12 12
+834 1 0
+846 5 7
+34 1 1
+483 1 1
+40 1 1
+110 7 7
+393 1 1
+215 1 1
+260 1 1
+36 0 1
+604 1 0
+169 0 1
+2118 1 1
+34 1 1
+147 1 1
+213 1 1
+67 1 1
+31 1 1
+566 1 0
+17 1 1
+210 0 2
+551 1 1
+34 1 1
+685 0 3
+24 2 2
+98 0 1
+449 0 2
+61 1 1
+38 1 1
+202 1 1
+44 1 1
+190 1 0
+46 4 4
+51 0 4
+476 1 1
+17 1 1
+82 1 1
+46 1 1
+82 1 1
+26 1 1
+485 1 1
+25 1 1
+263 1 1
+26 1 1
+1327 4 0
+44 1 0
+2397 1 1
+44 1 1
+928 4 0
+3218 14 14
+4406 1 0
+1125 1 0
+254 1 0
+427 0 1
+30 1 1
+111 0 2
+586 17 1
+970 1 1
+10 1 0
+28 1 1
+140 1 1
+43 1 1
+1327 1 1
+24 1 1
+636 2 1
+598 1 1
+44 1 1
+170 1 0
+4840 1 1
+28 11 7
+485 0 1
+263 0 2
+4912 4 0
+543 1 0
+18 1 1
+127 1 2
+102 6 0
+148 16 7
+1346 0 1
+128 7 0
+49 0 1
+876 1 0
+286 5 5
+184 0 1
+84 5 5
+365 9 9
+981 1 1
+11 1 1
+734 4 0
+563 4 0
+632 1 1
+17 1 1
+49 1 0
+95 1 1
+30 1 1
+147 1 1
+37 0 6
+340 1 2
+58 1 1
+112 0 1
+219 0 2
+231 0 3
+164 0 1
+26 1 1
+439 4 0
+34 0 2
+508 3 0
+96 1 1
+34 1 1
+829 1 1
+31 1 1
+405 15 15
+663 4 5
+1055 13 13
+135 0 1
+194 63 63
+384 6 6
+2756 1 1
+19 1 1
+1868 2 3
+2238 1 1
+31 1 1
+3002 4 0
+1116 1 1
+22 1 1
+1016 15 15
+855 15 13
+442 5 5
+2022 6 6
+506 0 2
+1110 0 1
+7396 1 1
+84 1 0
+3187 1 1
+16 1 1
+184 1 1
+18 1 1
+1607 53 60
+527 1 1
+39 1 1
+288 0 1
+364 3 0
+227 1 1
+18 1 1
+218 0 323
+91 1 0
+124 0 15
+621 0 4
+553 8 8
+467 1 1
+40 1 1
+372 1 1
+25 1 1
+188 12 12
+357 0 1
+250 0 5
+4193 0 4
+597 49 49
+321 1 1
+76 1 1
+2040 11 10
+1137 1 1
+48 4 4
+529 7 7
+246 4 0
+160 1 1
+34 0 3
+1469 0 2
+241 1 1
+17 1 1
+239 1 0
+937 1 1
+45 1 1
+421 6 0
+2127 0 1
+491 1 0
+80 1 1
+72 2 0
+255 6 6
+739 3 0
+702 5 0
+290 0 2
+210 5 1
+473 1 1
+42 4 0
+219 0 1
+348 1 1
+83 1 1
+851 0 16
+72 14 0
+246 1 1
+47 4 0
+410 1 0
+93 0 12
+225 0 14
+430 1 0
+4 6 0
+324 0 1
+939 1 1
+27 1 1
+142 1 1
+37 1 1
+1246 1 1
+44 1 1
+445 0 4
+173 0 2
+10545 1 1
+47 1 1
+1247 37 55
+805 1 0
+3789 1 1
+35 1 1
+1731 30 30
+2105 1 1
+30 1 1
+6075 1 0
+462 0 15
+4585 1 0
+3297 1 1
+49 1 1
+606 1 1
+48 1 1
+123 5 9
+109 1 31
+44 10 781
+77 2 0
+114 1 1
+62 1 1
+106 1 1
+268 18 4
+1079 0 2
+381 4 4
+106 1 1
+376 1 0
+1011 8 0
+584 5 0
+7537 7 0
+736 13 3
+2095 1 1
+45 1 1
+12786 0 11
+43 1 1
+720 5 7
+1358 0 2
+3813 19986 20000
+486 1 1
+46 1 1
+412 1 1
+23 1 0
+174 1 1
+24 1 1
+83 15 15
+363 1 1
+91 1 1
+51 17 17
+315 20 20
+199 13 13
+976 1 1
+39 0 3
+161 14 15
+127 16 16
+517 1 1
+81 1 1
+218 28 28
+124 1 1
+68 0 22
+252 1 1
+36 1 1
+784 0 1
+175 1 0
+148 1 1
+83 1 1
+469 1 1
+69 1 1
+245 1 1
+90 4 4
+1034 15 15
+69 1 1
+33 1 1
+174 1 1
+56 1 1
+169 1 0
+201 1 1
+30 1 1
+58 1 1
+38 1 1
+91 1 1
+98 4 4
+65 1 1
+19 2 0
+104 6 5
+25 1 1
+218 1 1
+37 1 1
+343 153809 150023
+66 8 8
+36 0 11
+62 1 1
+107 1 1
+68 3 130
+66 4 4
+50 21 21
+98 1 1
+127 1 0
+192 1 1
+71 1 1
+52 1 1
+200 1 1
+97 4 4
+85 5 5
+448 1 1
+97 11 11
+171 1 1
+61 1 1
+37 1 1
+156 3 0
+63 0 3
+155 3 0
+32 2 0
+232 1 1
+33 1 1
+175 2 0
+131 6 6
+1409 0 3
+222 1 1
+23 0 1
+1470 1 1
+21 1 1
+460 1 1
+71 1 1
+394 2 8
+37 1 1
+90 1 1
+43 1 1
+650 1 1
+34 1 1
+839 0 1
+431 1 1
+36 1 1
+284 60066 60160
+93 1 1
+75 808 0
+46 1 1
+221 1 1
+213 8 0
+63 1 1
+60 17 17
+53 1 1
+29 1 1
+68 8 8
+62 9 9
+51 1 1
+85 1 1
+101 1 1
+54 2 2
+116 1 1
+66 1 1
+182 1 0
+37 1 1
+134 14 14
+117 1 1
+45 1 1
+120 1 1
+47 1 1
+342 1 1
+46 1 1
+237 12 12
+107 8 8
+754 1 0
+880 1 1
+16 1 1
+741 1 1
+47 0 1
+19 2 2
+165 0 21
+26 1 1
+183 13 13
+72 1 1
+23 1 0
+268 14 14
+320 1 1
+55 1 1
+414 5 5
+172 0 1
+620 1 1
+18 1 1
+190 1 1
+20 0 8
+849 1 1
+29 1 1
+978 30213 30058
+159 1 1
+36 1 1
+107 1 1
+176 1 1
+154 0 5
+91 1 1
+54 1 1
+77 1 1
+239 1 1
+50 1 1
+128 1 1
+40 1 1
+62 1 0
+111 11 11
+734 1 1
+31 1 1
+215 1 1
+108 1 1
+259 1 1
+79 1 1
+80 1 1
+47 3 1
+40 1 1
+54 1 1
+46 1 1
+118 9 9
+98 1 0
+5 11 4
+23 0 7
+84 1 1
+84 2 2
+6 0 1
+6 1 0
+110 0 7
+537 1 1
+96 1 1
+441 1 1
+101 1 1
+242 14 14
+255 16 16
+142 1 0
+345 10 10
+54 1 1
+26 1 1
+108 1 1
+83 1 1
+128 1 1
+36 1 1
+231 1 1
+37 1 1
+534 1 1
+60 1 1
+804 0 3
+43 1 1
+148 1 1
+25 1 1
+69 10 10
+76 5 5
+37 1 1
+66 0 2
+192 1 1
+60 3 0
+19 1 1
+1149 1 1
+18 1 1
+77 1 1
+22 3 0
+42 1 1
+136 1 1
+78 2 0
+1712 8 9
+548 1 1
+50 1 1
+177 1 0
+410 1 1
+42 1 1
+422 10 10
+963 4 4
+329 1 9
+648 5 1
+117 1 1
+27 1 1
+574 1 0
+507 1 1
+39 1 1
+294 3 2
+549 1 1
+22 1 1
+74 0 1
+98 1 1
+65 3 3
+230 1 1
+18 1 0
+33 1 1
+51 1 1
+24 1 1
+811 1 1
+59 0 2
+8 1 1
+80 9 9
+437 14 14
+57 4 4
+588 15 15
+305 1 1
+17 1 1
+135 1 1
+50 1 1
+59 16 16
+129 1 1
+25 2 0
+12 1 1
+106 1 1
+31 1 1
+350 1 1
+47 1 1
+340 1 1
+65 1 1
+478 2 0
+714 8 7
+95 2 2
+52 2 1
+1129 1 1
+34 1 1
+1715 1 1
+87 1 1
+692 1 1
+47 0 1
+75 1 1
+2155 10 10
+1407 0 2
+202 1 1
+22 1 1
+186 1 1
+34 1 1
+264 1 0
+185 1 1
+24 1 0
+98 0 2
+258 8 14
+967 1 1
+37 3 3
+502 1 1
+22 1 1
+75 0 3
+163 1 1
+40 1 1
+638 0 3
+150 1 1
+11 0 1
+29 1 1
+125 1 1
+78 1 1
+115 8 0
+195 14 14
+1413 18 19
+1471 1 1
+30 1 1
+228 1 1
+28 0 2
+1142 1 1
+73 1 1
+104 73 73
+435 1 1
+37 1 3
+601 1 1
+43 1 1
+181 14 0
+37 1 0
+52 1 1
+125 4 4
+34 1 1
+208 1 1
+39 2 2
+418 1 1
+25 1 1
+81 1 1
+36 1 1
+99 6 7
+20 1 1
+73 1 1
+62 1 1
+103 1 1
+34 1 1
+772 0 1
+369 1 1
+29 0 2
+220 1 1
+89 1 1
+58 2 2
+103 1 1
+55 1 1
+19 1 1
+79 1 1
+29 0 1
+26 1 1
+252 1 1
+75 1 1
+467 1 1
+40 1 1
+389 13 13
+67 7 7
+1185 0 311
+64 6 6
+667 1 1
+38 1 1
+79 1 0
+517 1 1
+66 1 1
+450 3 0
+1133 12 12
+543 2 0
+960 14 14
+272 1 1
+41 1 1
+196 1 0
+1424 18 19
+271 1 1
+65 1 1
+345 1 1
+23 3 0
+116 3 3
+86 1 1
+39 1 1
+129 1 1
+26 1 1
+779 1 1
+32 1 1
+247 1 1
+48 1 1
+379 1 1
+18 1 1
+379 1 0
+226 1 1
+61 1 1
+861 0 1
+51 9 9
+397 1 1
+12 4 0
+46 1 1
+602 1 1
+35 1 1
+422 1 1
+49 1 1
+789 1 1
+37 1 1
+859 8 8
+378 0 4
+703 0 4
+2277 3 0
+1334 1 1
+10 0 1
+38 2 0
+61 1 1
+140 15 15
+1047 1 1
+38 1 1
+87 1 1
+24 5 4
+1291 1 1
+49 1 1
+307 14 14
+100 0 1
+75 1 1
+78 1 1
+243 1 0
+33 1 1
+116 19 19
+65 0 1
+238 0 1
+179 2 1
+67 1 1
+60 1 1
+32 1 1
+677 4 6
+83 318 0
+334 1 0
+1018 5 5
+559 0 2
+111 1 1
+30 1 1
+66 1 1
+38 1 1
+218 8 8
+754 1 1
+65 1 1
+182 1 1
+21 1 1
+285 1 1
+75 1 1
+147 6 0
+65 1 1
+42 1 1
+380 1 1
+84 6 0
+88 1 1
+25 1 1
+365 6 5
+108 1 1
+40 1 0
+50 1 1
+111 1 0
+21 0 1066
+119 0 1
+2641 1 1
+22 1 1
+2147 1 1
+29 1 1
+2252 1 1
+19 1 1
+1650 6 6
+1982 0 2
+2213 23 1
+2593 0 177
+338 1 1
+37 2 2
+395 10 0
+67 1 1
+131 1 1
+31 1 1
+386 1 1
+42 1 1
+372 1 1
+48 1 1
+3858 0 1
+351 1 0
+2536 16 16
+253 1 1
+16 1 1
+308 3 3
+52 1 1
+1308 0 3
+330 9 9
+600 2 0
+261 8 8
+9909 0 2
+2337 2 0
+3769 1 0
+1505 0 1
+4327 1 1
+15 1 1
+241 0 1
+230 1 0
+5263 1 0
+1386 0 41
+119 1 0
+4323 0 1
+54 1 1
+116 0 4
+1354 1 0
+1161 20 21
+1946 0 1
+584 0 2
+3100 1 0
+3491 1 0
+461 1 0
+762 0 8
+14669 1 0
+7644 6 0
+10539 4 0
+24841 1 0
+4856 3 0
+6082 2 0
+955 0 2
+1622 20422 20421
+76 0 3
+1724 2 0
+1173 1 0
+1783 1 1
+41 1 1
+4618 1 0
+232 0 2
+4975 2 0
+1487 15 14
+1184 2 0
+342 16 15
+328 0 3
+570 1 0
+995 1 0
+192 4 4
+1434 4 0
+62 1 1
+3531 2 3
+2846 1 1
+17 1 1
+704 0 1
+4801 1 0
+1417 0 4
+50 3 0
+165 0 1
+7575 9 0
+7359 11 0
+14219 0 2
+50 24 10
+38 2 0
+42 0 24
+24 0 18
+8297 1 1
+28 1 1
+264 1 1
+65 0 1
+15 1 1
+2371 19 19
+57 1 1
+21 1 1
+231 1 1
+94 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 40 40
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 5 5
+23 1 1
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+427 1 1
+115 1 1
+28630 0 8
+18331 0 26
+1830 22668 22667
+16645 4 0
+4458 0 2
+2318 1 1
+24 1 1
+2089 0 1
+68717 1 0
+8718 4 0
+12333 12 0
+835 0 1
+391 58 61
+12157 1 0
+5577 1 0
+23151 3 0
+1588 1 0
+2605 1 1
+23 1 1
+11252 8 0
+298 6 7
+946 2 0
+232 0 1
+501 1 0
+4748 0 4
+770 0 7
+914 0 1
+295 1 0
+214 2 0
+121 0 1
+784 0 1
+2512 0 1
+1205 21 21
+3250 1 0
+926 0 1
+189 2 0
+3543 2 0
+893 1 1
+46 1 1
+1296 0 1
+153 0 2
+335 5 0
+187 1 1
+86 1 1
+207 3 0
+322 0 1
+658 1 0
+1516 3 0
+1025 0 13
+1518 0 1
+591 10 10
+3384 0 2
+182 12 0
+328 1 0
+301 0 1
+994 1 1
+18 0 6
+1743 0 1
+2350 22 23
+1548 0 7
+1976 1 0
+199 0 1
+3290 1 1
+28 1 1
+2602 12 12
+873 0 3
+3080 12 8
+322 1 0
+490 1 0
+4084 1 0
+2421
+
+chain 584308 chr6_dbb_hap3 4610396 + 3832023 3871403 chr5 180857866 - 25428915 25436336 9077
+107 1 1
+69 1 1
+306 1 1
+71 1 1
+121 1 1
+88 1 1
+96 12 1
+257 1 1
+92 32139 188
+68 1 0
+39 1 1
+136 4 4
+14 1 1
+82 1 1
+80 1 1
+217 1 1
+28 0 4
+34 1 1
+114 1 1
+29 2 2
+1703 4 4
+315 13 13
+184 1 1
+31 1 1
+789 1 1
+47 5 5
+415 8 8
+85 13 13
+985 1 1
+142 1 1
+205 1 1
+35 1 1
+174
+
+chain 148040 chr6_dbb_hap3 4610396 + 3896754 3898327 chr9 140273252 + 114315581 114318014 872071
+803 1 1
+32 0 453
+67 2 409
+668
+
+chain 80965 chr6_dbb_hap3 4610396 + 2305865 2306722 chr6 170899992 - 139781917 139782778 1559016
+341 0 4
+516
+
+chain 59035 chr6_dbb_hap3 4610396 + 3814253 3815703 chr1 247249719 + 235898881 235900160 2133080
+173 33 33
+70 99 102
+68 14 14
+66 427 253
+104 96 96
+78 80 80
+142
+
+chain 56303 chr6_dbb_hap3 4610396 + 3895098 3898571 chr8 146274826 - 53671532 53672205 16841
+99 13 14
+38 12 0
+6 3 15
+341 2802 1
+101 1 1
+57
+
+chain 51533 chr6_dbb_hap3 4610396 + 2519888 2521822 chr1 247249719 + 7396445 7398379 2460894
+102 170 170
+98 761 760
+135 79 79
+58 214 214
+173 73 74
+71
+
+chain 35778 chr6_dbb_hap3 4610396 + 1195644 1199573 chr6 170899992 + 29950082 29959351 3739128
+53 1042 1027
+90 511 191
+90 460 6138
+153 336 337
+77 683 679
+78 267 267
+89
+
+chain 29930 chr6_dbb_hap3 4610396 + 1291857 1292168 chr10 135374737 + 129836562 129836873 4701711
+311
+
+chain 29904 chr6_dbb_hap3 4610396 + 1119153 1119465 chr7 158821424 + 38479558 38479870 4710596
+312
+
+chain 29422 chr6_dbb_hap3 4610396 + 2048496 2048802 chr6 170899992 + 69396184 69396490 4710630
+306
+
+chain 29265 chr6_dbb_hap3 4610396 + 2582091 2582592 chr2 242951149 + 112146990 112147493 4980566
+65 94 96
+54 27 27
+152 33 33
+76
+
+chain 28976 chr6_dbb_hap3 4610396 + 4055704 4056006 chr2 242951149 - 177193633 177193935 5141771
+302
+
+chain 28679 chr6_dbb_hap3 4610396 + 2275002 2275314 chr3 199501827 - 86469460 86469765 4692119
+171 7 0
+134
+
+chain 26875 chr6_dbb_hap3 4610396 + 2605062 2605840 chr6 170899992 + 31342625 31343398 6110200
+75 247 243
+74 12 16
+72 194 189
+104
+
+chain 23264 chr6_dbb_hap3 4610396 + 3891437 3892382 chr6 170899992 + 32821586 32822354 8135396
+218 677 500
+50
+
+chain 23054 chr6_dbb_hap3 4610396 + 3970815 3971054 chr3 199501827 - 39984613 39984852 8258949
+239
+
+chain 22312 chr6_dbb_hap3 4610396 + 1158170 1158946 chr7 158821424 - 51137320 51138262 8787332
+90 9 9
+79 101 101
+72 385 551
+40
+
+chain 21919 chr6_dbb_hap3 4610396 + 3896060 3896302 chrX 154913754 - 82335943 82336185 9052373
+242
+
+chain 19800 chr6_dbb_hap3 4610396 + 3895610 3895845 chr7 158821424 - 34919795 34920030 7485763
+5 1 1
+87 3 3
+71 1 1
+67
+
+chain 19015 chr6_dbb_hap3 4610396 + 3943955 3944187 chr11 134452384 + 111558067 111558299 11259777
+149 20 20
+63
+
+chain 18237 chr6_dbb_hap3 4610396 + 2595793 2596391 chr13 114142980 + 51183720 51184326 11909510
+52 119 119
+108 253 261
+66
+
+chain 17641 chr6_dbb_hap3 4610396 + 3836782 3837025 chrX 154913754 + 35042287 35042530 12436913
+99 43 43
+101
+
+chain 17270 chr6_dbb_hap3 4610396 + 3918499 3918707 chr10 135374737 - 70196080 70196288 12781659
+86 2 2
+48 5 5
+67
+
+chain 16865 chr6_dbb_hap3 4610396 + 3983463 3983966 chrX 154913754 + 8861421 8861925 13172813
+68 216 217
+63 77 77
+79
+
+chain 16634 chr6_dbb_hap3 4610396 + 3895901 3896503 chr2 242951149 + 35312811 35313413 7601022
+134 363 363
+105
+
+chain 13803 chr6_dbb_hap3 4610396 + 3796429 3796972 chr2 242951149 - 211383777 211384322 16433564
+114 376 378
+53
+
+chain 13479 chr6_dbb_hap3 4610396 + 1132829 1133547 chr6 170899992 + 29984509 29985227 16848878
+104 552 552
+62
+
+chain 13400 chr6_dbb_hap3 4610396 + 3837061 3837652 chr1 247249719 + 76199329 76199914 13528533
+72 466 460
+53
+
+chain 13024 chr6_dbb_hap3 4610396 + 983805 983941 chr11 134452384 - 45905925 45906061 17454496
+136
+
+chain 12671 chr6_dbb_hap3 4610396 + 3940526 3940660 chrX 154913754 - 65797896 65798030 17982412
+134
+
+chain 12198 chr6_dbb_hap3 4610396 + 3795847 3796096 chr7 158821424 + 40936078 40936329 18688113
+94 105 107
+50
+
+chain 11398 chr6_dbb_hap3 4610396 + 2592168 2592321 chr6 170899992 - 161606914 161607067 20013435
+64 22 22
+67
+
+chain 11324 chr6_dbb_hap3 4610396 + 3938144 3938291 chr6 170899992 - 138135992 138136139 20148164
+68 15 15
+64
+
+chain 10873 chr6_dbb_hap3 4610396 + 1193470 1193591 chr19 63811651 + 15986631 15986752 20965589
+121
+
+chain 10867 chr6_dbb_hap3 4610396 + 2527311 2527468 chr6 170899992 - 132294381 132294544 20980273
+55 29 35
+73
+
+chain 10755 chr6_dbb_hap3 4610396 + 2751799 2751912 chrX 154913754 - 134479310 134479423 11323978
+113
+
+chain 10634 chr6_dbb_hap3 4610396 + 3919991 3920105 chr5 180857866 + 34801263 34801377 21438493
+114
+
+chain 10332 chr6_dbb_hap3 4610396 + 3984189 3984438 chr18 76117153 - 27021129 27021380 22068171
+57 124 126
+68
+
+chain 10015 chr6_dbb_hap3 4610396 + 3921148 3921283 chr14 106368585 + 84133812 84133947 22772205
+59 19 19
+57
+
+chain 9987 chr6_dbb_hap3 4610396 + 3796659 3796919 chr12 132349534 + 56701652 56701911 19406222
+70 165 164
+25
+
+chain 9750 chr6_dbb_hap3 4610396 + 2598300 2598402 chr6 170899992 + 31328563 31328665 23393690
+102
+
+chain 9528 chr6_dbb_hap3 4610396 + 1160418 1160855 chr6 170899992 + 29878108 29878543 23937745
+59 318 316
+60
+
+chain 9496 chr6_dbb_hap3 4610396 + 3698327 3698427 chr11 134452384 - 102104468 102104568 24009659
+100
+
+chain 9090 chr6_dbb_hap3 4610396 + 2526557 2526667 chr3 199501827 - 94209663 94209773 24799755
+53 4 4
+53
+
+chain 9042 chr6_dbb_hap3 4610396 + 3982887 3983463 chrX 154913754 - 39105241 39105605 22912000
+59 507 295
+10
+
+chain 8509 chr6_dbb_hap3 4610396 + 3919900 3919991 chr9 140273252 - 54900636 54900727 21580039
+91
+
+chain 7414 chr6_dbb_hap3 4610396 + 3922665 3922744 chr6 170899992 - 151548315 151548394 27385131
+79
+
+chain 7276 chr6_dbb_hap3 4610396 + 3860392 3860468 chr6 170899992 - 67344251 67344327 27653182
+76
+
+chain 7202 chr6_dbb_hap3 4610396 + 3830969 3832020 chr3 199501827 + 106790123 106791174 346924
+69 5 5
+109 2 2
+142 1 1
+77 1 1
+51 1 0
+194 0 1
+399
+
+chain 6804 chr6_dbb_hap3 4610396 + 3735469 3735541 chr6 170899992 + 32582474 32582546 28581342
+72
+
+chain 6776 chr6_dbb_hap3 4610396 + 3900841 3908708 chr6 170899992 + 32827127 32834907 28655646
+50 4318 3617
+61 2532 2695
+93 658 1109
+155
+
+chain 6739 chr6_dbb_hap3 4610396 + 3920547 3920617 chr6 170899992 + 53525586 53525656 28727012
+70
+
+chain 6718 chr6_dbb_hap3 4610396 + 3983858 3984010 chr15 100338915 - 66378648 66378800 16209113
+29 79 79
+44
+
+chain 6712 chr6_dbb_hap3 4610396 + 2536742 2536812 chr6 170899992 - 140565854 140565924 28801697
+70
+
+chain 6657 chr6_dbb_hap3 4610396 + 3814584 3815561 chr4 191273063 - 103136563 103137365 2286737
+44 251 76
+51 551 551
+20 37 37
+23
+
+chain 6566 chr6_dbb_hap3 4610396 + 1190938 1191006 chr6 170899992 + 30567038 30567106 29137401
+68
+
+chain 6566 chr6_dbb_hap3 4610396 + 3835601 3835669 chr6 170899992 + 32665461 32665529 29137402
+68
+
+chain 6459 chr6_dbb_hap3 4610396 + 3795625 3795694 chr11 134452384 + 89638894 89638963 29378141
+69
+
+chain 6457 chr6_dbb_hap3 4610396 + 1205138 1205205 chr6 170899992 + 30336816 30336883 29393793
+67
+
+chain 6404 chr6_dbb_hap3 4610396 + 3984475 3984543 chr7 158821424 + 141217888 141217956 29535627
+68
+
+chain 6112 chr6_dbb_hap3 4610396 + 3700406 3700470 chr18 76117153 - 19156586 19156650 30278938
+64
+
+chain 6077 chr6_dbb_hap3 4610396 + 3828852 3828917 chr6 170899992 + 32661358 32661423 30333820
+65
+
+chain 6003 chr6_dbb_hap3 4610396 + 2599299 2599362 chr6 170899992 + 31329552 31329615 30561641
+63
+
+chain 5676 chr6_dbb_hap3 4610396 + 2522554 2523018 chr1 247249719 + 71360098 71360557 7933597
+8 394 389
+62
+
+chain 5420 chr6_dbb_hap3 4610396 + 1191387 1191443 chr6 170899992 + 29965652 29965708 32189291
+56
+
+chain 5384 chr6_dbb_hap3 4610396 + 3920366 3920422 chr5 180857866 + 130110350 130110406 32314816
+56
+
+chain 5365 chr6_dbb_hap3 4610396 + 1189212 1189267 chr6 170899992 + 30335396 30335451 32370613
+55
+
+chain 5349 chr6_dbb_hap3 4610396 + 1146055 1146112 chr1 247249719 + 172045890 172045947 32394662
+57
+
+chain 5348 chr6_dbb_hap3 4610396 + 3704305 3704361 chr13 114142980 - 61076835 61076891 32406029
+56
+
+chain 5312 chr6_dbb_hap3 4610396 + 3955463 3955519 chr2 242951149 - 134958526 134958582 32494768
+56
+
+chain 5202 chr6_dbb_hap3 4610396 + 3920808 3920862 chr12 132349534 + 102926992 102927046 32856661
+54
+
+chain 5194 chr6_dbb_hap3 4610396 + 2522678 2522733 chr2 242951149 + 136412357 136412412 32870828
+55
+
+chain 5157 chr6_dbb_hap3 4610396 + 3919474 3919528 chr18 76117153 - 75578306 75578360 33003263
+54
+
+chain 5129 chr6_dbb_hap3 4610396 + 3699000 3699053 chr5 180857866 + 132341386 132341439 33069683
+53
+
+chain 5112 chr6_dbb_hap3 4610396 + 3702291 3702345 chr21 46944323 - 8455162 8455216 33113520
+54
+
+chain 5085 chr6_dbb_hap3 4610396 + 3943091 3943145 chrX 154913754 - 38541067 38541121 33235366
+54
+
+chain 5066 chr6_dbb_hap3 4610396 + 1193375 1193428 chr21 46944323 - 1867343 1867396 33290795
+53
+
+chain 5058 chr6_dbb_hap3 4610396 + 3934514 3934568 chr11 134452384 + 35678810 35678864 33301897
+54
+
+chain 4994 chr6_dbb_hap3 4610396 + 3795260 3795313 chr12 132349534 + 29061661 29061714 33541955
+53
+
+chain 4994 chr6_dbb_hap3 4610396 + 3796133 3796186 chr4 191273063 + 58121526 58121579 33542099
+53
+
+chain 4976 chr6_dbb_hap3 4610396 + 3794848 3794901 chrX 154913754 - 55960756 55960809 33594824
+53
+
+chain 4966 chr6_dbb_hap3 4610396 + 3797697 3797749 chr2 242951149 - 82237285 82237337 33630342
+52
+
+chain 4930 chr6_dbb_hap3 4610396 + 3702504 3702556 chr9 140273252 + 93086155 93086207 33718599
+52
+
+chain 4923 chr6_dbb_hap3 4610396 + 1158348 1158410 chr9 140273252 - 102391777 102391839 11227004
+62
+
+chain 4922 chr6_dbb_hap3 4610396 + 3834682 3834735 chr6 170899992 + 32548301 32548354 33750858
+53
+
+chain 4921 chr6_dbb_hap3 4610396 + 3919158 3919210 chrX 154913754 - 85139489 85139541 33755277
+52
+
+chain 4914 chr6_dbb_hap3 4610396 + 2519587 2519639 chrX 154913754 + 7895883 7895935 17698100
+52
+
+chain 4895 chr6_dbb_hap3 4610396 + 3971054 3971105 chr9 140273252 + 7362065 7362116 8474619
+51
+
+chain 4839 chr6_dbb_hap3 4610396 + 2523181 2523232 chr1 247249719 - 83322643 83322694 34042185
+51
+
+chain 4829 chr6_dbb_hap3 4610396 + 1205662 1205712 chr6 170899992 + 30567298 30567348 34088050
+50
+
+chain 4821 chr6_dbb_hap3 4610396 + 3921606 3921657 chr19 63811651 + 44797095 44797146 34119671
+51
+
+chain 4821 chr6_dbb_hap3 4610396 + 3795725 3795776 chr6 170899992 - 89445109 89445160 34121660
+51
+
+chain 4812 chr6_dbb_hap3 4610396 + 3797020 3797071 chr9 140273252 - 60383600 60383651 34150921
+51
+
+chain 4802 chr6_dbb_hap3 4610396 + 3704401 3704451 chr4 191273063 - 155219143 155219193 34221295
+50
+
+chain 4766 chr6_dbb_hap3 4610396 + 3700117 3700167 chr9 140273252 + 86874856 86874906 34319112
+50
+
+chain 4694 chr6_dbb_hap3 4610396 + 3910535 3910585 chr6 170899992 + 32836714 32836764 34581613
+50
+
+chain 4630 chr6_dbb_hap3 4610396 + 2519306 2519455 chrX 154913754 - 130647735 130647884 4467919
+8 13 13
+128
+
+chain 4435 chr6_dbb_hap3 4610396 + 2521889 2521945 chr1 247249719 + 68329905 68329961 24341076
+56
+
+chain 4406 chr6_dbb_hap3 4610396 + 3836685 3836748 chr12 132349534 + 83019068 83019131 17889506
+63
+
+chain 4295 chr6_dbb_hap3 4610396 + 2518454 2518508 chr13 114142980 + 40947099 40947153 23509760
+54
+
+chain 4259 chr6_dbb_hap3 4610396 + 2520658 2522182 chr1 247249719 + 175639486 175641011 2690506
+58 695 694
+59 250 251
+31 373 374
+58
+
+chain 4202 chr6_dbb_hap3 4610396 + 2519814 2519869 chr3 199501827 + 157792092 157792147 19123443
+55
+
+chain 4148 chr6_dbb_hap3 4610396 + 2596230 2596277 chr7 158821424 - 75232531 75232578 15855534
+47
+
+chain 3884 chr6_dbb_hap3 4610396 + 2596391 2596432 chr8 146274826 + 74136425 74136466 15736555
+41
+
+chain 3783 chr6_dbb_hap3 4610396 + 2595924 2595964 chr2 242951149 - 166645324 166645364 18114608
+40
+
+chain 3633 chr6_dbb_hap3 4610396 + 2595546 2596150 chr14 106368585 - 51104394 51104979 12640292
+71 478 459
+55
+
+chain 3600 chr6_dbb_hap3 4610396 + 3984599 3984637 chr2 242951149 + 129304609 129304647 25766382
+38
+
+chain 3466 chr6_dbb_hap3 4610396 + 3944209 3944269 chr5 180857866 - 165236686 165236746 13055377
+60
+
+chain 3427 chr6_dbb_hap3 4610396 + 2595867 2595923 chrX 154913754 - 74451128 74451184 24425971
+56
+
+chain 3366 chr6_dbb_hap3 4610396 + 3697430 3697469 chr7 158821424 - 31427441 31427480 35195573
+39
+
+chain 3356 chr6_dbb_hap3 4610396 + 2596277 2596325 chr6 170899992 + 67193869 67193917 14667051
+48
+
+chain 3333 chr6_dbb_hap3 4610396 + 3796616 3796658 chr6 170899992 + 112361298 112361340 25801948
+42
+
+chain 3275 chr6_dbb_hap3 4610396 + 1138782 1138817 chr6 170899992 + 29990315 29990350 35226052
+35
+
+chain 3219 chr6_dbb_hap3 4610396 + 2595512 2595546 chr15 100338915 + 54012038 54012072 22943633
+34
+
+chain 3113 chr6_dbb_hap3 4610396 + 2519060 2522554 chr12 132349534 + 103307685 103311177 2899166
+99 961 960
+40 1029 1028
+44 1259 1259
+62
+
+chain 2845 chr6_dbb_hap3 4610396 + 2519030 2519060 chr3 199501827 - 158108130 158108160 26771667
+30
+
+chain 2771 chr6_dbb_hap3 4610396 + 2186148 2186180 chr16 88827254 + 61371572 61371604 11881974
+32
+
+chain 2656 chr6_dbb_hap3 4610396 + 3920105 3920152 chr1 247249719 + 97086811 97086858 21929674
+47
+
+chain 2634 chr6_dbb_hap3 4610396 + 3702345 3702373 chr4 191273063 - 9754971 9754999 34558482
+28
+
+chain 2599 chr6_dbb_hap3 4610396 + 1158410 1158448 chr7 158821424 - 126060947 126060985 11258553
+38
+
+chain 2560 chr6_dbb_hap3 4610396 + 3796543 3796570 chr9 140273252 + 82550760 82550787 23127746
+27
+
+chain 2433 chr6_dbb_hap3 4610396 + 3814163 3814213 chr5 180857866 - 58683848 58683898 14264874
+50
+
+chain 2422 chr6_dbb_hap3 4610396 + 3815331 3815377 chr6 170899992 + 32052376 32052422 9201222
+46
+
+chain 2386 chr6_dbb_hap3 4610396 + 3944336 3944393 chr4 191273063 + 105171966 105172023 11828581
+57
+
+chain 2350 chr6_dbb_hap3 4610396 + 1144323 1144351 chr9 140273252 + 98495373 98495401 22648902
+28
+
+chain 2334 chr6_dbb_hap3 4610396 + 1197501 1197553 chr1 247249719 + 48751712 48751764 24363112
+52
+
+chain 2326 chr6_dbb_hap3 4610396 + 3944285 3944315 chr5 180857866 - 104226614 104226644 17910212
+30
+
+chain 2262 chr6_dbb_hap3 4610396 + 1158146 1158170 chr19 63811651 - 5696072 5696096 21221760
+24
+
+chain 2258 chr6_dbb_hap3 4610396 + 2582592 2582621 chr10 135374737 - 49445077 49445106 7325456
+29
+
+chain 2252 chr6_dbb_hap3 4610396 + 3944437 3944463 chr1 247249719 - 9396437 9396463 17746619
+26
+
+chain 2238 chr6_dbb_hap3 4610396 + 3984543 3984572 chr8 146274826 + 40415013 40415042 30916283
+1 3 0
+5 0 3
+20
+
+chain 2198 chr6_dbb_hap3 4610396 + 3591295 3591318 chrX 154913754 - 138619630 138619653 32682302
+23
+
+chain 2171 chr6_dbb_hap3 4610396 + 3944636 3944659 chr5 180857866 - 116975655 116975678 23231315
+23
+
+chain 2164 chr6_dbb_hap3 4610396 + 2581904 2581960 chr15 100338915 + 41094361 41094417 6236685
+56
+
+chain 2136 chr6_dbb_hap3 4610396 + 2582305 2582331 chrX 154913754 + 74544454 74544480 5553867
+24 1 1
+1
+
+chain 2131 chr6_dbb_hap3 4610396 + 3895846 3896559 chr7 158821424 + 107074762 107075475 8294701
+30 628 628
+55
+
+chain 2073 chr6_dbb_hap3 4610396 + 1158564 1158618 chr1 247249719 + 222604152 222604206 12884992
+54
+
+chain 2063 chr6_dbb_hap3 4610396 + 2527468 2527490 chr10 135374737 + 5170837 5170859 26024714
+22
+
+chain 2035 chr6_dbb_hap3 4610396 + 3944660 3944732 chr8 146274826 + 40414891 40414930 35524999
+20 2 0
+3 8 0
+5 23 0
+11
+
+chain 1939 chr6_dbb_hap3 4610396 + 1197585 1197647 chr4_random 842648 + 579429 579491 24056746
+62
+
+chain 1911 chr6_dbb_hap3 4610396 + 3796202 3796275 chr20 62435964 - 40308436 40308509 20356789
+73
+
+chain 1856 chr6_dbb_hap3 4610396 + 1158521 1158554 chr4 191273063 + 153905795 153905828 9266240
+33
+
+chain 1843 chr6_dbb_hap3 4610396 + 2520547 2520624 chr3 199501827 - 153335243 153335320 2775919
+77
+
+chain 1791 chr6_dbb_hap3 4610396 + 3814944 3814997 chr2 242951149 + 15669060 15669113 2773805
+53
+
+chain 1791 chr6_dbb_hap3 4610396 + 3896327 3896371 chr3 199501827 - 21590873 21590917 16297046
+44
+
+chain 1748 chr6_dbb_hap3 4610396 + 3896647 3898412 chr12 132349534 + 37486950 37487098 8651766
+20 2 0
+53 1616 1
+74
+
+chain 1729 chr6_dbb_hap3 4610396 + 2592021 2592074 chr14 106368585 - 49465840 49465893 23309002
+53
+
+chain 1667 chr6_dbb_hap3 4610396 + 2519690 2519769 chr4 191273063 + 150810923 150811002 4477040
+79
+
+chain 1644 chr6_dbb_hap3 4610396 + 3795469 3795533 chr5 180857866 - 17624826 17624890 19426880
+64
+
+chain 1588 chr6_dbb_hap3 4610396 + 2519256 2520761 chr7 158821424 + 116147190 116148689 3019444
+50 1410 1404
+45
+
+chain 1514 chr6_dbb_hap3 4610396 + 1158618 1158676 chr13 114142980 - 5380936 5380994 10250152
+58
+
+chain 1507 chr6_dbb_hap3 4610396 + 2519507 2519587 chr4 191273063 + 139055274 139055354 16166689
+80
+
+chain 1497 chr6_dbb_hap3 4610396 + 2596436 2596504 chr13 114142980 - 63160902 63160970 14379683
+68
+
+chain 1378 chr6_dbb_hap3 4610396 + 2518320 2518446 chr9 140273252 + 106017756 106017882 9913209
+126
+
+chain 1359 chr6_dbb_hap3 4610396 + 1158766 1158832 chr11 134452384 + 118435255 118435321 13536573
+66
+
+chain 1326 chr6_dbb_hap3 4610396 + 2518769 2518884 chr2 242951149 - 193553846 193553961 4392729
+115
+
+chain 1279 chr6_dbb_hap3 4610396 + 3895876 3895901 chr5 180857866 - 141473608 141473633 7934834
+25
+
+chain 1261 chr6_dbb_hap3 4610396 + 2595748 2595793 chr7 158821424 - 113148258 113148303 12073479
+45
+
+chain 1252 chr6_dbb_hap3 4610396 + 3944555 3944605 chr10 135374737 + 81711914 81711964 14060366
+50
+
+chain 1247 chr6_dbb_hap3 4610396 + 3837297 3837358 chrY 57772954 + 10103368 10103429 19375318
+61
+
+chain 1238 chr6_dbb_hap3 4610396 + 1193115 1193174 chr8 146274826 - 84904941 84905000 22834115
+59
+
+chain 1229 chr6_dbb_hap3 4610396 + 3797090 3797164 chr7 158821424 - 63976160 63976234 19674520
+74
+
+chain 1211 chr6_dbb_hap3 4610396 + 2596569 2596648 chr11 134452384 + 125240934 125241013 21730841
+79
+
+chain 1198 chr6_dbb_hap3 4610396 + 3983120 3983171 chrX 154913754 - 112657474 112657525 22999394
+51
+
+chain 1198 chr6_dbb_hap3 4610396 + 2520259 2520315 chr1 247249719 - 41799264 41799320 23684518
+56
+
+chain 1160 chr6_dbb_hap3 4610396 + 2522055 2522083 chrX 154913754 + 56853117 56853145 21155197
+28
+
+chain 1156 chr6_dbb_hap3 4610396 + 3814529 3814567 chr1 247249719 - 95427068 95427106 3236426
+38
+
+chain 1115 chr6_dbb_hap3 4610396 + 2519770 2519814 chr17 78774742 - 18978582 18978626 19145840
+44
+
+chain 1092 chr6_dbb_hap3 4610396 + 3815720 3815773 chr6 170899992 + 33136473 33136526 4404150
+53
+
+chain 1080 chr6_dbb_hap3 4610396 + 3982965 3983026 chr4 191273063 + 91007246 91007307 23248893
+61
+
+chain 1070 chr6_dbb_hap3 4610396 + 3983531 3983571 chr13 114142980 + 78421238 78421278 18216872
+40
+
+chain 1033 chr6_dbb_hap3 4610396 + 3797495 3797589 chr2 242951149 - 222175668 222175762 18472154
+94
+
+chain 1021 chr6_dbb_hap3 4610396 + 3944605 3944636 chr3 199501827 + 41781985 41782016 21488147
+31
+
+chain 961 chr6_dbb_hap3 4610396 + 2591988 2592021 chr6 170899992 + 31311499 31311532 23940424
+33
+
+chain 912 chr6_dbb_hap3 4610396 + 2522218 2522277 chr5 180857866 - 20904100 20904159 3597825
+59
+
+chain 912 chr6_dbb_hap3 4610396 + 2522435 2522465 chr7 158821424 + 107644178 107644208 21981895
+30
+
+chain 892 chr6_dbb_hap3 4610396 + 3815177 3815203 chr1 247249719 - 223546777 223546803 2552155
+26
+
+chain 886 chr6_dbb_hap3 4610396 + 2518921 2518972 chrX 154913754 - 65002049 65002100 8335918
+51
+
+chain 881 chr6_dbb_hap3 4610396 + 2521831 2521881 chr4 191273063 + 5547185 5547235 3823174
+50
+
+chain 876 chr6_dbb_hap3 4610396 + 2522095 2522124 chr1 247249719 - 197271642 197271671 12596899
+29
+
+chain 858 chr6_dbb_hap3 4610396 + 2522184 2522218 chr7 158821424 - 148280259 148280293 6691658
+34
+
+chain 850 chr6_dbb_hap3 4610396 + 3815307 3815331 chr11 134452384 + 75267105 75267129 2466745
+24
+
+chain 846 chr6_dbb_hap3 4610396 + 3896560 3896615 chr1 247249719 - 102242947 102243002 13724822
+55
+
+chain 818 chr6_dbb_hap3 4610396 + 3815047 3815103 chr9 140273252 - 13362556 13362612 11609524
+56
+
+chain 787 chr6_dbb_hap3 4610396 + 2522005 2522055 chr2 242951149 + 76860552 76860602 3963281
+50
+
+chain 742 chr6_dbb_hap3 4610396 + 2520888 2520940 chr10 135374737 + 51611354 51611406 20534291
+52
+
+chain 740 chr6_dbb_hap3 4610396 + 1159052 1159116 chr12 132349534 + 55464534 55464598 20832677
+64
+
+chain 734 chr6_dbb_hap3 4610396 + 2517749 2518673 chr8 146274826 - 112931559 112932176 13565224
+68 769 462
+87
+
+chain 717 chr6_dbb_hap3 4610396 + 3984125 3984177 chr16 88827254 - 38714794 38714846 22849175
+52
+
+chain 688 chr6_dbb_hap3 4610396 + 2519167 2519218 chr12 132349534 - 101137563 101137614 3748471
+51
+
+chain 684 chr6_dbb_hap3 4610396 + 2522743 2522826 chr1 247249719 + 68246247 68246330 16550290
+83
+
+chain 681 chr6_dbb_hap3 4610396 + 3982752 3982809 chr8 146274826 - 64029404 64029461 24731945
+57
+
+chain 668 chr6_dbb_hap3 4610396 + 3714611 3714639 chr13 114142980 + 25366313 25366341 2606938
+28
+
+chain 661 chr6_dbb_hap3 4610396 + 2523098 2523163 chr5 180857866 + 99923773 99923838 9614006
+65
+
+chain 654 chr6_dbb_hap3 4610396 + 1158946 1158972 chr4 191273063 - 137719796 137719822 10317120
+26
+
+chain 638 chr6_dbb_hap3 4610396 + 3795059 3795115 chr1 247249719 - 190736869 190736925 22996754
+56
+
+chain 603 chr6_dbb_hap3 4610396 + 3896371 3896398 chr6 170899992 + 38375889 38375916 7901672
+27
+
+chain 602 chr6_dbb_hap3 4610396 + 2519990 2520031 chr6 170899992 - 100068900 100068941 3263990
+41
+
+chain 571 chr6_dbb_hap3 4610396 + 2518673 2518747 chr3 199501827 + 50931043 50931117 15282719
+74
+
+chain 547 chr6_dbb_hap3 4610396 + 2522845 2522895 chr11 134452384 - 79794459 79794509 15991277
+50
+
+chain 544 chr6_dbb_hap3 4610396 + 2520356 2520407 chr13 114142980 + 104410064 104410115 4879952
+51
+
+chain 461 chr6_dbb_hap3 4610396 + 2522377 2522435 chr9 140273252 - 118104609 118104667 6129577
+58
+
+chain 447 chr6_dbb_hap3 4610396 + 2517845 2517905 chr8 146274826 - 66271750 66271810 23464585
+60
+
+chain 423 chr6_dbb_hap3 4610396 + 2520499 2520535 chr16 88827254 - 23736388 23736424 4641188
+36
+
+chain 407 chr6_dbb_hap3 4610396 + 3833249 3833277 chr11 134452384 + 92791982 92792010 9335
+28
+
+chain 395 chr6_dbb_hap3 4610396 + 3896615 3896647 chr10 135374737 - 43610926 43610958 15449290
+32
+
+chain 363 chr6_dbb_hap3 4610396 + 2522305 2522360 chr2 242951149 + 137419466 137419521 26505689
+55
+
+chain 350 chr6_dbb_hap3 4610396 + 2523417 2523489 chr15 100338915 + 97778900 97778972 9309023
+72
+
+chain 312 chr6_dbb_hap3 4610396 + 2520407 2520446 chr10 135374737 - 80033072 80033111 12533916
+39
+
+chain 290 chr6_dbb_hap3 4610396 + 2523894 2523946 chr1 247249719 - 204952078 204952130 18508597
+52
+
+chain 258 chr6_dbb_hap3 4610396 + 2518973 2519027 chr2 242951149 + 129418481 129418535 12872927
+54
+
+chain 235 chr6_dbb_hap3 4610396 + 3982484 3982540 chr21 46944323 + 15992125 15992181 26051708
+56
+
+chain 337820870 chr6_mann_hap4 4683263 + 0 4683263 chr6 170899992 + 28804582 33333955 39
+932 3 0
+804 0 1
+2406 2 0
+141275 1 0
+429 38391 38391
+17722 4 0
+12815 0 1
+28140 1 3
+12586 0 1
+9819 0 1
+69013 0 1
+22684 1 0
+14147 7 0
+1489 1 1
+72 1 1
+2260 0 2
+7033 0 4
+13929 13 14
+9228 0 1
+1324 0 3
+5437 5 0
+2061 1 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4746 9 9
+4767 7 7
+1169 1 1
+55 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+249 43 43
+1178 0 4
+685 8 0
+48 8 0
+1701 1 1
+43 5 5
+862 18 18
+58 1 1
+66 1 1
+420 1 1
+44 1 1
+680 4 4
+1675 1 1
+83 1 1
+3082 4 0
+5467 1 1
+27 0 1
+1099 16 0
+627 12 12
+1317 6 1
+129 1 1
+25 1 1
+1397 15 15
+810 1 1
+27 1 1
+1192 2 0
+7515 4 0
+979 0 4
+3405 0 2
+3501 1 1
+26 1 1
+787 0 1
+1416 3 1
+22815 4 4
+126 1 0
+38 1 1
+140 1 0
+999 0 17
+56 0 15
+15438 4 0
+6165 0 1
+1768 1 0
+7727 2 0
+1514 0 1
+3116 0 1
+3278 1 1
+21 1 1
+1738 0 1
+8576 19 0
+1877 15 15
+6128 1 0
+2049 1 0
+518 13 11
+1704 1 1
+117 1 1
+1448 10 0
+1521 0 4
+2878 9 9
+2265 1 0
+25400 9 9
+4420 1 1
+32 1 1
+2539 1 0
+18012 1 1
+42 1 1
+2651 0 3
+2544 0 318
+1507 1 0
+313 4 0
+2659 1 1
+25 1 1
+1461 4 1
+1402 0 1
+3961 0 3
+58 1 1
+112 1 1
+1419 1 1
+34 0 1
+2697 0 2
+40 1 1
+2168 0 1
+1019 0 2
+1099 0 4
+40 1 1
+1374 11 0
+31 1 1
+189 1 1
+26 1 1
+327 1 1
+38 1 1
+177 11 11
+303 1 1
+34 1 1
+5868 17 17
+2864 0 143
+4107 0 4
+752 0 2
+10360 0 1
+37 1 1
+11851 0 2
+5376 0 1
+19253 0 6
+7878 1 0
+21 0 6
+4451 1 0
+27910 1 0
+9946 0 1
+11233 1 1
+32 1 1
+366 1 1
+38 1 1
+1832 1 1
+20 1 1
+3659 22 16
+1218 1 0
+1638 6 6
+228 1 1
+45 1 1
+2048 0 2
+462 1 0
+20759 1 0
+3778 2 1
+1268 1 0
+1511 1 1
+42 2 0
+24 1 1
+4119 22 0
+1757 1 0
+1527 1 1
+29 1 1
+1886 1 0
+6666 0 4
+2358 1 1
+23 1 1
+1549 12 0
+36 12 0
+484 1 1
+31 1 1
+549 3 0
+5745 1 0
+19358 0 3
+12224 1 0
+34 1 1
+3228 11 16
+250 1 1
+17 1 1
+1482 0 1
+1280 1 0
+103 1 1
+29 1 1
+68 4 4
+1493 1 1
+49 1 1
+102 4 0
+287 1 1
+21 3 0
+273 1 1
+43 9 1
+667 0 8
+138 1 1
+20 1 1
+255 0 2
+67 1 1
+33 1 1
+62 1 0
+118 0 5
+313 0 3
+2354 0 28
+1203 0 3
+3975 1 1
+44 1 1
+4899 3 0
+2101 2 0
+363 1 1
+49 1 1
+1639 0 30
+248 46 46
+1068 4 1
+85 1 0
+357 3 4
+5288 0 9
+2728 1 5
+722 0 1
+502 0 1
+1025 0 1
+134 12 0
+4944 0 1
+319 1 0
+1314 5 6
+4858 0 1
+2923 1 3
+117 0 1
+1775 1 0
+2123 0 1
+2715 1 0
+4921 1 1
+17 1 1
+4273 1 0
+1233 0 8
+2134 0 1
+1042 0 1
+163 1 1
+45 1 1
+50 2 0
+64 1 1
+48 1 1
+379 0 3
+29 1 0
+30 1 1
+61 1 1
+22 1 1
+691 5 7
+310 1 1
+37 3 1
+225 1 1
+131 2 0
+36 1 1
+242 9 9
+697 33 33
+1202 1 1
+16 1 1
+528 1 1
+20 1 1
+509 0 5
+76 1 1
+21 1 1
+439 15 15
+2778 2 1
+1597 24 28
+59 12 12
+307 1 0
+516 1 0
+286 11 33
+339 5 0
+570 1 1
+37 1 1
+220 1 0
+72 1 1
+144 1 1
+48 1 1
+247 2 0
+174 9 10
+816 1 0
+940 1 1
+45 1 1
+91 3 3
+71 1 1
+291 14 14
+100 1 1
+23 1 1
+452 3 3
+85 1 1
+65 1 1
+77 1 1
+252 0 1
+129 15 15
+432 14 0
+85 1 1
+28 1 1
+189 2 1
+71 1 1
+52 8 0
+810 2 2
+63 1 1
+378 1 1
+26 1 1
+187 31 36
+966 1 1
+25 1 1
+72 1 1
+29 1 1
+125 1 1
+38 1 1
+433 2 0
+596 1 1
+48 1 1
+465 4 4
+64 1 1
+20 1 1
+525 5 5
+237 3 8
+99 31 31
+53 11 0
+364 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+67 16 16
+244 1 1
+54 5 5
+929 1 1
+21 1 1
+126 0 3
+830 1 11
+59 1 1
+537 0 2
+24 1 1
+745 15 15
+810 1 0
+425 1 1
+89 1 1
+592 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 1 1
+39 1 1
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+155 154 0
+34 1 1
+50 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+345 1 1
+39 1 1
+504 18 18
+596 12 12
+54 1 1
+158 1 1
+164 1 1
+34 1 1
+626 15 15
+866 0 10
+1051 0 2611
+680 0 1
+1537 0 18
+75 1 0
+145 60 0
+122 0 12
+23 1 1
+1927 13 13
+1702 2 0
+3694 1 1
+18 1 1
+958 43 47
+246 2 0
+146 1 1
+49 1 1
+410 1 0
+667 1 1
+38 1 1
+362 7 1
+159 3 0
+515 2 0
+1026 1 1
+29 1 1
+249 0 6
+129 1 1
+33 4 0
+9 0 6
+1236 1 1
+20 1 1
+138 10 9
+448 0 3
+660 1 1
+28 1 1
+83 1 1
+51 1 1
+2659 1 1
+38 1 1
+424 0 1
+70 1 1
+820 1 1
+26 1 1
+1472 1 1
+21 1 1
+491 5 5
+163 15 15
+2194 2 0
+533 6 0
+441 1 7
+1689 1 1
+26 3 4
+879 16 16
+75 10 10
+429 0 2
+58 1 1
+350 1 0
+769 1 1
+39 1 1
+573 0 4
+37 1 1
+144 8 8
+1036 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+169 147 153
+1254 0 2
+332 1 1
+21 1 1
+193 8 24
+34 1 1
+79 1 1
+29 1 1
+536 1 0
+308 0 1
+850 0 32
+23 1 1
+651 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 1
+714 7 7
+89 1 0
+293 9 8
+125 1 1
+31 1 1
+192 6 6
+171 17 17
+681 1 1
+43 1 1
+514 1 1
+68 1 1
+537 1 1
+35 1 1
+159 6 6
+179 1 1
+37 1 1
+560 17 17
+198 0 7
+105 1 1
+40 1 1
+95 13 13
+247 1 1
+19 1 1
+2044 7 8
+2512 0 15
+2982 4 0
+342 41 41
+2752 1 2
+1698 13 13
+4264 0 4
+12512 105 53
+7 0 5
+29 5 129
+49 1 1
+7717 1 1
+40 1 1
+4564 1 1
+45 1 1
+2289 1 1
+41 1 1
+1994 0 1
+733 1 1
+37 1 1
+5170 1 1
+22 1 1
+718 0 3
+828 0 8
+2128 11 11
+5142 0 1
+4144 18 0
+8 1 1
+4824 12 12
+727 6 16
+1705 4 0
+3265 0 2
+2235 18 16
+2946 0 372
+2644 31 31
+3991 40 40
+559 1 1
+28 1 1
+129 0 4
+787 1 1
+34 1 1
+927 4 4
+123 0 4
+6 1 1
+2353 0 1
+331 1 1
+27 1 1
+633 1 1
+31 1 1
+1147 1 0
+1507 1 1
+44 1 1
+166 1 1
+41 3 1
+1022 34253 40039
+275 1 1
+38 1 1
+1307 1 1
+26 1 1
+1467 1 1
+27 1 1
+568 11 11
+693 1 1
+26 1 1
+297 11 11
+183 1 1
+40 1 1
+589 1 1
+26 1 1
+838 1 1
+44 0 1
+877 1 1
+39 1 1
+347 1 1
+36 1 1
+1288 10 10
+731 2 1
+75 3 3
+91 171 171
+553 1 1
+61 1 1
+70 1 1
+53 0 2
+315 1 1
+29 1 1
+581 1 1
+82 1 1
+605 9 9
+691 2 2
+72 1 1
+55 1 1
+45 1 1
+196 4 4
+123 0 1
+40 1 1
+183 23 23
+183 1 1
+67 1 1
+304 1 1
+108 1 1
+165 1 1
+72 1 1
+167 1 1
+59 0 1
+10 3 1
+21 82 2
+58 0 2
+69 1 1
+25 1 1
+57 2 1
+107 2 2
+93 1 1
+194 0 3
+120 7 4
+431 1 1
+78 1 1
+84 0 1
+74 1 1
+52 13 13
+158 5 7
+434 0 1
+295 16 16
+290 1 1
+26 1 1
+373 1 1
+46 1 1
+94 1 1
+81 1 1
+109 4 0
+61 2 2
+80 1 1
+47 1 1
+168 1 1
+31 1 1
+269 2 2
+42 1 1
+322 2 2
+36 1 1
+265 2 2
+14 1 1
+76 7762 9566
+315 55 55
+67 36167 30035
+308 1 1
+49 1 1
+219 0 1
+87 7 5
+223 10 8
+235 11 11
+772 0 2
+187 2 1
+1058 0 2
+349 0 1
+264 1 1
+43 1 1
+781 3 1
+55 0 2
+13 0 4
+1077 1 1
+48 1 1
+62 1 1
+27 1 1
+1270 1 1
+44 1 1
+2070 3 1
+27 1 7
+251 1 1
+40 1 1
+130 1 1
+41 4 4
+478 1 1
+30 1 1
+162 11 11
+209 10 0
+150 1 1
+36 0 2
+31 1 1
+55 1 1
+51 1 1
+221 8 13
+418 1 1
+26 1 1
+386 3 0
+549 1 1
+76 1 1
+67 1 1
+25 3 3
+777 1 1
+17 1 1
+970 3 8
+714 1 1
+25 1 1
+192 1 1
+236 1 1
+524 0 12
+51 10 9
+664 1 1
+29 1 1
+62 1 1
+50 2 0
+119 1 1
+10 0 2
+19 4 6
+117 1 1
+69 1 1
+731 1 0
+3768 9 1
+1328 0 1
+6188 1 1
+43 1 1
+7157 4 0
+2168 1 0
+10374 19 0
+742 2 3
+4846 0 1
+3203 1 0
+2662 1 1
+27 1 1
+3920 1 1
+47 1 1
+2081 1 0
+377 1 0
+172 0 1
+5189 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3902 17 4
+310 0 5
+2762 0 10
+201 2 0
+345 1 0
+594 0 2
+1043 10 0
+1426 0 9
+17 1 1
+265 0 1
+6069 0 3
+2963 0 3
+168 0 3
+194 2 1
+4260 1 0
+19508 0 1
+1762 0 3
+4356 0 4
+401 1 0
+1148 1 1
+28 0 11
+847 0 1
+1133 0 1
+1143 1 1
+20 1 1
+1533 0 8
+128 0 4
+2963 0 1
+25 1 1
+5336 1 0
+322 6 6
+196 1 1
+20 1 1
+151 3 3
+87 1 1
+246 1 7
+368 1 1
+26 1 1
+1049 0 1
+1002 0 1
+7912 4 0
+3532 50004 0
+1445 0 1
+10485 1 1
+48 1 1
+724 1 1
+51 5 0
+39 1 1
+22385 0 1
+4385 0 7
+881 0 12
+11532 13 12
+409 0 1
+3492 0 2
+2158 0 25
+109 1 1
+3284 0 19
+2586 2 0
+757 1 1
+22 1 1
+860 29 24
+1584 1 0
+1598 1 2
+1653 3 25
+17 0 4
+16 2 0
+6 10 0
+40 1 0
+10 6 0
+6448 0 1
+2513 0 1
+576 16 16
+103 1 0
+198 1 3
+539 1 1
+47 1 1
+158 2 0
+996 0 1
+3736 1 3
+371 1 3
+1174 1 1
+56 1 1
+69 0 1
+518 6 0
+646 13 13
+469 1 0
+1072 1 4
+911 1 1
+16 1 1
+3603 1 0
+282 1 0
+597 0 6
+496 13 13
+183 1 1
+43 1 1
+1294 1 1
+40 1 1
+572 0 5
+463 0 4
+1886 1 0
+548 1 0
+1300 0 3
+1839 2 0
+189 1 1
+49 1 1
+1253 1 1
+43 1 0
+498 1 1
+45 4 0
+3538 0 1
+1582 31 31
+376 14 14
+867 3 4
+253 1 1
+34 1 1
+172 2 0
+1094 0 1
+281 1 1
+49 1 1
+397 1 1
+43 1 1
+1082 1 1
+26 1 1
+1030 1 1
+24 0 419
+125 2 0
+709 1 1
+36 1 1
+393 1 1
+21 1 1
+1773 16 17
+181 12 12
+98 1 4
+6 1 0
+53 1 1
+94 1 1
+49 1 1
+1495 10 0
+623 13 13
+163 1 1
+45 1 1
+2050 11 11
+2452 1 1
+42 1 0
+35 1 1
+751 1 0
+287 1 1
+60 1 1
+446 0 4
+2620 8 7
+1442 5 5
+153 1 0
+514 2 0
+3349 1 1
+23 0 1
+12 1 1
+296 8 9
+291 1 1
+21 1 0
+245 2 2
+24 1 1
+150 1 1
+46 1 1
+325 1 1
+38 1 1
+52 6 9
+154 1 1
+42 1 1
+942 1 1
+36 1 1
+5168 0 3
+2172 1 0
+1740 0 8
+4919 1 0
+1388 4 0
+310 0 9
+370 22 0
+503 0 3
+6750 8 0
+419 2 0
+945 0 4
+3485 5 1
+789 0 1
+1882 45 44
+1047 1 1
+60 1 1
+2432 0 15
+16 1 1
+5898 0 1
+2260 1 0
+2629 0 5
+55 1 1
+28 1 1
+1978 1 0
+374 0 5
+7713 1 0
+1229 1 0
+708 2 0
+84 5 0
+2071 1 1
+23 1 0
+174 5 0
+1776 0 9
+15 6 11
+4007 1 0
+2414 12 10
+2056 0 1
+955 4 0
+9566 1 0
+1267 2 0
+1646 2 2
+30 1 1
+4770 7 6
+150 14 14
+9365 0 2
+5358 0 1
+4837 1 0
+6701 4 0
+66771 0 2
+54634 0 2
+8292 0 4
+7941 0 8
+7495 1 0
+5591 4 0
+4127 1 0
+473 1 0
+6435 1 0
+53744 1 0
+6522 0 1
+48591 18 23
+4935 29 0
+40465 0 1
+12538 0 1
+24928 8701 8701
+6291 0 10
+15586 2 1
+56398 4 0
+5858 1 0
+5972 0 2
+2081 0 1
+12533 1 0
+25305 0 1
+2237 0 2
+18999 0 4
+13824 0 2
+11096 2 0
+10773 0 1
+804 1 0
+5431 31 34
+598 1 1
+22 1 1
+2240 24813 24813
+1765 0 4
+4845 0 3
+448 1 1
+22 1 1
+2215 1 1
+32 1 1
+2413 14 14
+142 1 0
+789 1 1
+45 1 1
+154 1 1
+25 1 1
+465 1 1
+45 6 4
+541 1 1
+42 1 1
+1339 5 6
+391 1 1
+20 0 1
+251 1 1
+22 1 1
+561 0 2
+78 3 0
+1718 1 1
+12 1 1
+1042 1 1
+38 0 1
+301 14 0
+222 10 10
+436 10 10
+1564 1 1
+17 1 1
+1752 5 0
+1561 135 0
+58 0 45
+212 90 0
+42 2 2
+43 1 1
+152 0 270
+54 180 0
+2130 12 12
+1630 1 1
+26 1 1
+189 0 14
+296 2 0
+809 2 0
+17 16 0
+665 0 40
+236 1 1
+44 1 1
+352 1 1
+25 1 1
+316 14442 14257
+51 2 0
+58 1 1
+107 1 1
+150 14 14
+522 1 1
+28 1 1
+945 4 4
+34 1 1
+472 0 2
+203 0 1
+281 1 1
+46 1 1
+1130 1 0
+232 17 17
+510 1 1
+33 1 1
+62 10 10
+1501 1 1
+20 1 1
+573 1 1
+29 1 1
+928 0 3
+304 1 1
+41 1 1
+160 1 1
+58 1 1
+656 1 1
+40 4 0
+108 6 6
+321 1 1
+14 0 16
+91 1 1
+184 1 1
+43 8 3
+180 1 1
+68 1 1
+144 1 1
+27 1 0
+17 1 1
+212 0 1
+212 1 1
+34 1 1
+115 1 1
+41 1 1
+407 10 10
+200 1 1
+44 2 0
+187 3 0
+146 1 1
+17 1 1
+122 4 4
+73 1 0
+56 1 1
+155 1 17
+80 15 15
+458 1 1
+16 3 3
+343 1 1
+111 1 1
+201 14 14
+157 12 12
+346 0 2
+382 4 0
+35 1 1
+937 0 1
+246 25 0
+52 0 1
+419 0 1
+165 1 0
+75 24 3
+297 1 1
+38 1 1
+271 1 1
+33 1 1
+4777 4 2
+43 3 0
+1254 0 1
+16 1 1
+1411 0 4
+424 1 1
+51 1 1
+113 1 1
+34 1 1
+344 9 9
+15845 1 0
+2814 1 5
+2389 0 4
+3883 0 1
+10926 0 4
+17866 4 10
+744 1 0
+564 2 0
+16701 3 0
+7721 11 0
+1411 1 1
+49 1 1
+146 1 1
+61 1 1
+116 1 1
+41 1 1
+137 1 1
+30 1 1
+158 9 9
+136 10 13
+973 6 6
+547 1 1
+41 1 1
+164 17 17
+137 1 1
+68 1 1
+846 4 4
+228 1 1
+34 1 1
+355 1 1
+113 1 1
+330 0 1
+222 1 1
+25 1 1
+267 1 1
+38 1 1
+716 2 0
+23 1 1
+1417 0 1
+152 1 1
+46 1 1
+237 1 1
+20 1 1
+211 5 5
+88 1 1
+33 1 1
+211 1 1
+65 1 1
+516 58 58
+491 7 7
+208 13 12
+558 2 2
+28 1 1
+125 4 4
+1853 12 0
+845 6 6
+2005 0 1
+148 1 1
+36 1 1
+993 1 0
+3580 10 10
+1203 1 0
+530 5 5
+216 1 1
+32 1 1
+312 1 1
+44 1 1
+1934 14 14
+1149 0 8
+835 1 1
+29 0 2
+2323 1 1
+18 1 1
+1273 27 27
+104 1 1
+21 1 1
+1520 1 1
+23 1 1
+147 1 1
+16 1 1
+429 8 16
+1419 23 23
+256 1 0
+39 1 2
+106 1 1
+21 1 1
+501 2 2
+40 1 1
+2249 1 1
+19 1 1
+86 1 1
+82 0 1
+180 14 1
+1272 17 17
+345 0 2
+1504 14 0
+1689 4 0
+3174 16 16
+607 4 34
+41 0 5
+669 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+466 1 1
+31 3 0
+321 0 1
+281 3 0
+450 1 1
+34 1 1
+498 1 1
+28 2 1
+280 0 1
+649 1 1
+47 1 1
+1002 4 0
+120 1 1
+533 7 7
+998 0 1
+75 1 1
+37 1 1
+473 1 0
+44 1 1
+64 19 19
+60 18 18
+2075 1 1
+51 1 1
+779 0 1
+1286 0 2
+271 1 1
+57 1 1
+129 4 0
+87 1 1
+160 1 1
+49 1 1
+147 18 14
+128 4 4
+34 1 1
+865 4 0
+160 1 1
+35 1 1
+1119 1 1
+13 0 3
+242 1 1
+23 1 1
+1705 0 4
+103 0 1
+1117 2 0
+67 1 1
+1825 0 1
+855 8 0
+1368 3 0
+320 1 1
+19 1 1
+100 1 1
+28 1 1
+97 1 1
+15 1 1
+442 1 1
+189 0 2
+5 1 1
+1520 1 1
+28 1 1
+367 4 0
+267 13 13
+175 1 0
+225 1 1
+45 1 1
+859 1 1
+80 2 0
+38 0 2
+318 8 7
+50 1 1
+29 1 1
+376 4 9
+548 1 1
+57 1 1
+665 4 0
+146 30562 30549
+225 2 2
+49 1 1
+129 1 1
+20 1 1
+757 9 9
+151 1 1
+49 1 1
+282 0 2
+128 0 1
+174 15 18
+175 1 1
+16 1 1
+332 1 1
+22 1 1
+554 0 1
+120 1 1
+31 1 1
+351 5 0
+80 1 0
+76 1 1
+39 1 1
+1447 1 0
+1072 1 1
+43 0 4
+43 1 1
+393 0 1
+1820 6 6
+457 1 1
+18 1 1
+87 1 1
+30 1 1
+861 1 1
+20 1 1
+1057 23 23
+416 0 16
+787 1 1
+17 1 2
+37 1 1
+1675 1 1
+27 1 1
+901 0 8
+47 1 1
+274 0 3
+75 0 1
+234 0 3
+45 1 1
+250 1 1
+18 1 1
+517 33 0
+117 1 1
+55 1 1
+537 1 1
+20 1 1
+671 1 1
+68 1 1
+89 1 1
+104 1 1
+172 0 1
+124 0 1
+522 0 1500
+466 5 5
+32 1 0
+171 1 1
+19 1 1
+67 1 1
+22 1 1
+654 1 1
+25 1 1
+68 1 1
+21 4 0
+1588 1 1
+66 1 1
+401 0 1
+186 1 1
+21 1 1
+168 0 1
+601 1 1
+29 1 1
+36 4 0
+37 1 1
+127 1 1
+29 1 1
+404 0 2
+710 1 1
+89 1 1
+161 16 16
+405 1 1
+39 3 3
+56 1 1
+192 0 4
+104 1 1
+89 1 1
+64 1 1
+102 1 1
+130 15 16
+158 8 0
+57 1 1
+731 1 1
+57 1 1
+321 1 1
+44 3 0
+52 19987 20030
+60 8 8
+133 1 1
+48 1 1
+287 1 1
+24 1 1
+1273 1 1
+24 1 1
+86 1 1
+76 1 0
+20 1 1
+112 1 1
+149 1 1
+284 1 1
+37 1 1
+559 10 10
+136 1 12
+106 12 12
+3153 1 1
+34 1 1
+453 1 1
+63 1 1
+645 0 2
+50 1 0
+712 1 1
+35 1 1
+158 1 1
+52 1 1
+123 1 1
+45 0 1
+32 1 1
+253 1 1
+48 1 1
+101 16 16
+64 1 1
+124 1 1
+1429 13 13
+196 0 1
+1629 1 1
+39 0 1
+30 1 1
+514 1 1
+32 0 3
+3600 1 13
+1047 1 1
+43 1 1
+55 14 14
+853 12 12
+2313 13 13
+537 6 0
+1430 1 1
+48 1 1
+400 1 1
+100 1 1
+148 19 19
+152 1 1
+25 1 1
+70 1 1
+102 1 1
+158 1 1
+56 2 2
+57 1 1
+10 5 10
+24 2 0
+71 1 1
+54 1 1
+73 1 1
+85 1 1
+105 1 1
+117 2 2
+29 1 1
+92 2 2
+42 0 1
+154 1 1
+10 1 0
+47 4 5
+35 1 1
+56 1 1
+64 3 3
+67 5 5
+72 1 1
+60 1 1
+45 1 1
+82 1 1
+95 2 2
+161 1 1
+301 1 1
+67 1 0
+430 1 1
+105 10 10
+38 0 4
+386 11 11
+101 3 2
+117 0 2
+77 1 1
+481 0 1
+68 1 1
+81 1 1
+467 1 1
+34 1 1
+359 1 1
+35 1 1
+2283 1 1
+26 1 1
+506 19 0
+51 0 1
+166 1 1
+65 1 0
+211 0 17
+410 3 0
+622 0 1
+143 1 1
+22 1 1
+150 2 2
+49 1 1
+312 1 1
+16 1 1
+715 1 1
+24 1 1
+896 1 1
+33 1 1
+308 22 28
+78 1 1
+144 1 1
+733 0 1
+212 1 1
+40 1 1
+1233 1 1
+48 1 1
+741 49699 50070
+885 1 1
+113 1 1
+141 2 0
+842 1 0
+1507 1 1
+40 1 1
+279 0 1
+724 1 1
+15 1 1
+252 1 1
+29 2 0
+229 1 1
+50 3 3
+221 7 7
+216 1 1
+36 5 5
+64 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+195 1 1
+46 1 1
+245 0 4
+70 1 1
+62 4 1
+43 1 1
+153 1 1
+93 1 1
+85 1 1
+68 5 0
+47 2 2
+291 1 0
+42 1 1
+341 13 13
+262 4 4
+67 1 1
+32 1 0
+28 1 1
+612 1 1
+123 1 1
+112 1 1
+19 1 4
+61 1 2
+136 1 1
+83 1 1
+78 1 1
+61 288 288
+119 1 1
+158 1 1
+146 1 1
+28 1 1
+372 1 1
+18 0 4
+44 1 1
+120 7 7
+73 1 4
+42 1 1
+52 1 1
+24 1 1
+143 1 1
+34 1 1
+376 1 1
+26 1 1
+243 1 1
+41 1 1
+53 1 1
+35 5 5
+101 1 1
+20 1 1
+114 1 1
+43 1 1
+184 4 8
+650 23 23
+192 1 1
+44 1 0
+103 1 1
+202 2 2
+33 1 1
+51 1 1
+26 1 1
+277 3 0
+19 1 1
+263 2 2
+49 1 1
+63 1 1
+200 1 1
+320 4 12
+10 2 0
+11 8 1
+26 1 1
+86 13 13
+15 1 1
+3255 1 1
+52 1 1
+159 1 1
+88 1 0
+118 1 1
+172 1 1
+26 1 1
+69 1 1
+95 1 1
+124 1 1
+30 1 1
+216 41 41
+51 5 5
+123 1 1
+53 1 1
+110 1 1
+307 1 1
+101 1 1
+53 15 15
+127 2 2
+65 1 1
+553 1 1
+45 1 1
+52 0 1
+99 4 4
+1538 1 1
+31 1 1
+930 7 3
+472 13 13
+606 1 1
+38 1 1
+230 10 0
+30 6 0
+35 0 22
+168 1 1
+55 1 1
+309 2 3
+58 1 1
+44 1 1
+333 1 1
+81 3 3
+77 1 1
+140 1 1
+136 1 1
+40 5 5
+160 1 1
+21 5 5
+253 1 1
+37 1 1
+104 3 0
+867 14 15
+178 1 1
+94 1 1
+254 0 1
+101 0 5
+17 1 1
+528 1 1
+42 1 1
+261 1 1
+19 3 3
+83 10 10
+114 1 1
+194 1 1
+19 1 1
+286 1 1
+38 1 1
+295 0 4
+35 10 0
+205 0 2
+29 1 1
+178 1 1
+31 1 1
+57 1 1
+76 1 1
+228 1 1
+28 1 1
+101 1 1
+109 0 1
+93 0 2
+46 1 1
+109 1 1
+33 1 1
+932 12 12
+1047 1 1
+26 1 1
+699 0 8
+35 1 1
+472 1 1
+43 1 1
+242 1 1
+28 1 1
+385 1 1
+91 1 1
+805 0 2
+4744 3 2
+1144 0 1
+1453 0 1
+934 1 1
+28 3 7
+155 0 1
+840 18 18
+346 1 1
+25 1 1
+1020 2 0
+260 1 1
+26 1 1
+357 1 1
+44 1 1
+639 1 1
+26 1 1
+3965 1 1
+40 1 1
+194 1 0
+279 1 1
+18 1 1
+277 0 2
+1883 0 1
+31 1 1
+1925 1 0
+2650 16 16
+2463 117 0
+67 8 17
+77 0 2
+55 17 17
+60 24 0
+126 0 64
+26 0 7
+19 0 7
+38 18 0
+40 40 0
+49 0 124
+32 15 8
+22 43 4
+36 1 614
+68 1 1
+7 0 2
+17 2 0
+7 0 2
+17 2 0
+20 0 2
+76 41 13
+71 60 21
+122 0 73
+72 28 0
+117 11 35
+24 13 0
+56 19 0
+3413 6 0
+9102 0 1
+87 0 2
+2219 0 1
+85 1 1
+31 0 4
+399 14 14
+408 0 1
+148 0 1
+807 1 1
+28 1 0
+452 4 0
+499 1 1
+25 1 1
+1037 1 0
+1066 1 1
+102 1 1
+1111 1 1
+47 1 1
+291 1 1
+49 1 1
+1195 1 1
+46 1 1
+370 1 1
+56 1 1
+142 1 1
+54 1 1
+538 0 1
+46 1 2890
+74 9 97
+1161 0 1
+1161 1 1
+23 1 1
+189 1 1
+43 1 1
+855 1 0
+353 8 0
+751 42950 42933
+383 0 4
+40 1 1
+3304 1 1
+46 1 1
+282 1 1
+39 1 1
+698 1 1
+20 1 1
+140 1 1
+26 1 1
+745 0 2
+2081 1 0
+817 4 4
+206 1 1
+44 1 1
+168 1 1
+20 1 1
+164 1 0
+21 1 1
+648 1 0
+912 6 0
+55 0 1
+1116 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+16 1 4
+1404 0 1
+450 4 0
+612 15 14
+304 1 1
+39 1 1
+564 1 1
+45 1 1
+303 2 0
+409 1 1
+18 1 0
+858 2 0
+2168 0 1
+54 22 22
+524 0 1
+523 0 12
+2424 18 14
+64 1 1
+31 1 1
+185 0 4
+657 10 10
+980 1 1
+20 1 1
+227 1 1
+37 1 1
+636 3 4
+3780 0 1
+4458 1 1
+23 1 1
+1114 1 3
+696 16 32
+861 18 18
+4781 0 4
+815 0 1
+9910 0 1
+10538 0 6
+25675 0 6
+10912 9 10
+824 0 1
+1450 11 0
+403 0 1
+154 1 1
+34 1 1
+146 1 0
+26 1 1
+2361 0 2
+775 8460 8460
+474 0 1
+1838 0 3
+2049 3 0
+14940 0 1
+398 17 17
+3797 0 4
+1305 10 0
+15047 1 0
+20201 1 0
+3812 0 1
+11605 0 1
+4121 2 0
+7755 1 0
+2661 3 1
+138 1 0
+2776 0 2
+4108 0 4
+8944 1 0
+10910 4 0
+1616 0 1
+1645 4 5
+36 0 2
+2223 0 16
+4729 10 0
+1921 0 1
+913 0 1
+2531 89346 89346
+3450 17 17
+3339 0 1
+3130 0 1
+2106 1 1
+42 1 1
+382 1 0
+616 178 0
+9555 52932 52932
+383 0 1
+2529 19 19
+10441 0 1
+24 1 1
+246 0 4
+1724 1 1
+37 1 1
+141 11 11
+103 1 128
+292 1 1
+20 1 1
+67 0 117
+30 1 1
+2771 0 3
+1487 0 3
+251 1 0
+1263 18 12
+888 1 1
+20 1 1
+2423 10 0
+1337 10 10
+6619 2 0
+982 113131 113131
+3241 16 0
+10939 12 0
+2143 0 1
+8355 0 3
+4114 0 1
+1404 0 1
+5850 1 0
+1691 38609 38609
+338 6 6
+2331 0 1
+2149 1 0
+10496 17 35
+3831 1 0
+8737 0 3
+16043 29 29
+1283 0 3
+8057 1 1
+63 1 1
+6053 5 0
+4539 43 43
+1259 2 0
+1628 5 5
+448 0 1
+374 0 1
+3431 1 0
+3049 32 0
+147 0 1
+1181 10 15
+206 3 4
+613 0 1
+1815 1 1
+18 1 1
+3726 0 3
+34 1 1
+361 17 17
+1252 0 3
+1642 1 0
+374 1 1
+19 1 1
+316 1 0
+13 2 0
+712 12 12
+204 1 1
+60 1 1
+843 1 3
+705 7 7
+72 1 1
+29 0 2
+332 0 1
+136 1 1
+1071 3 0
+548 1 1
+45 3 0
+121 1 1
+24 1 1
+262 16 16
+846 0 4
+412 0 2
+644 0 1
+26 1 1
+75 1 1
+32 1 1
+247 0 1
+174 1 2
+77 3 0
+113 0 1
+79 44 44
+186 0 14
+80 1 1
+813 0 9
+465 1 1
+60 1 1
+217 0 2
+400 0 3
+367 1 1
+37 1 1
+245 1 1
+25 1 1
+469 0 8
+857 17 18
+278 0 1
+1507 3 0
+1681 0 2
+429 4 0
+148 17 5
+278 4362 4362
+3670 16 16
+108 1 2
+197 1 1
+20 1 1
+367 20 19
+488 0 4
+1457 2 1
+205 5 5
+11 1 1
+213 20 15
+1190 30 0
+35 1 1
+1742 1 0
+123 1 0
+4678 0 2
+5739 0 1
+1167 0 1
+1767 1 0
+253 15 15
+5582 1 21
+8987 1 0
+2138 3 2
+2203 2 1
+5654 1 1
+24 3 3
+3229 0 1
+3385 4 4
+6989 1 0
+1294 4 0
+9088 2 3
+2270 1 1
+32 1 1
+6293 1 1
+26 1 1
+2668 4 0
+7792 1 0
+7099 2 0
+1639 1 0
+13217 0 2
+6668 0 2
+2319 1 0
+1034 0 6
+430 1 0
+1276 1 1
+27 1 1
+142 3 3
+35 1 1
+1211 1 1
+34 1 1
+664 0 10
+59 1 1
+78 1 1
+1519 1 1
+27 1 1
+154 14 14
+2525 0 4
+79 1 1
+145 1 1
+63 1 1
+70 1 1
+21 1 1
+695 1 1
+41 2 2
+564 1 1
+46 1 1
+279 4 0
+38 5 5
+201 22 22
+1020 1 1
+25 1 1
+2253 32 32
+545 1 1
+27 1 0
+54 15 16
+363 0 1
+845 0 2
+60 7 0
+787 2 0
+3691 1 0
+1843 1 1
+45 1 0
+11 1 2
+3499 1 1
+27 1 1
+970 0 1
+76 0 2
+1804 2 0
+1079 1 1
+17 1 1
+639 3 5
+73 1 1
+13 13 0
+66 1 1
+96 0 1
+294 14 0
+4554 0 1
+53 9 6
+691 0 1
+989 1 1
+143 1 1
+223 0 2
+95 1 1
+1136 1 1
+49 1 1
+606 1 1
+48 1 1
+128 0 4
+109 1 31
+44 10 781
+62 4 0
+129 1 1
+62 1 1
+106 1 1
+268 18 4
+125 1 1
+43 1 1
+909 0 2
+381 4 4
+74 1 1
+408 1 0
+1011 8 0
+8833 1 1
+23 6 19
+6628 1 1
+28 1 1
+4872 20 20
+692 1 0
+2650 0 4
+194 0 1
+596 5 6
+1359 0 1
+1572 7 7
+299 1 1
+49 1 1
+803 1 1
+93 1 1
+797 14 14
+433 8 0
+108 11 11
+140 1 1
+40 1 1
+470 1 1
+42 1 1
+1192 4 4
+129 1 1
+123 2 0
+95 1 1
+82 3 0
+664 1 1
+77 1 1
+57 1 1
+62 1 1
+473 2 0
+262 6 0
+45 1 1
+63 2 0
+39 1 1
+267 0 1
+197 2 104
+87 111 0
+122 0 7
+88 0 4
+86 1 1
+21 6 0
+563 14 14
+324 1 0
+205 1 1
+17 1 1
+426 17 17
+52 0 1
+201 4 0
+14 1 1
+1080 1 1
+24 1 1
+91 24 24
+279 9 8
+55 1 1
+32 1 1
+121 1 1
+62 1 1
+80 1 1
+72 1 1
+2217 2 0
+820 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+1780 2 0
+742 1 1
+40 1 1
+272 1 1
+52 1 1
+1187 1 1
+23 1 1
+254 1 1
+60 1 1
+176 3 6
+463 1 1
+36 1 1
+797 1 1
+22 1 1
+395 5 2
+61 1 1
+31 3 3
+226 1 1
+59 1 1
+581 1 1
+46 1 1
+412 1 1
+23 1 0
+174 1 1
+24 1 1
+83 15 15
+363 1 1
+91 1 1
+383 20 20
+90 1 1
+44 1 1
+63 13 13
+976 1 1
+29 1 0
+10 0 3
+161 14 15
+127 16 16
+517 1 1
+81 1 1
+218 28 28
+124 1 1
+68 0 22
+399 7 7
+668 0 1
+175 1 0
+1018 1 1
+90 4 4
+1034 15 15
+69 1 1
+33 1 1
+174 1 1
+56 1 1
+169 1 0
+201 1 1
+30 1 1
+58 1 1
+38 1 1
+91 1 1
+98 4 4
+65 1 1
+19 2 0
+104 6 5
+25 1 1
+218 1 1
+37 1 1
+343 264243 150023
+66 8 8
+36 0 11
+62 1 1
+107 1 1
+68 3 130
+66 4 4
+50 21 21
+98 1 1
+127 1 0
+192 1 1
+71 1 1
+52 1 1
+200 1 1
+97 4 4
+85 5 5
+448 1 1
+97 11 11
+171 1 1
+61 1 1
+37 1 1
+156 3 0
+63 0 3
+155 3 0
+32 2 0
+232 1 1
+33 1 1
+175 2 0
+131 6 6
+1409 0 3
+222 1 1
+23 0 1
+1470 1 1
+21 1 1
+460 1 1
+71 1 1
+394 2 8
+37 1 1
+90 1 1
+43 1 1
+650 1 1
+34 1 1
+839 0 1
+431 1 1
+36 1 1
+284 51277 50054
+255 1 1
+80 5 5
+71 1 1
+48 3 3
+65 1 1
+83 1 1
+292 1 1
+33 1 1
+421 1 1
+74 1 0
+151 8 0
+65 1 1
+70 0 2
+58 0 8
+157 1 1
+64 1 1
+66 2 1
+97 1 1
+54 1 1
+46 0 1
+20 1 1
+210 16 16
+270 1 1
+46 1 1
+202 1 1
+22 1 1
+309 1 1
+25 0 1
+174 10 10
+305 1 1
+40 1 1
+75 32 30
+150 1 0
+17 1 1
+69 2 2
+27 1 1
+38 6 0
+49 5 3
+255 1 1
+43 1 1
+90 1 1
+74 1 1
+364 1 1
+23 3 3
+69 1 1
+22 2 0
+78 1 1
+29 1 0
+96 1 1
+56 8 0
+87 5 10
+85 2 2
+39 1 1
+87 314 0
+364 1 1
+64 1 1
+201 0 4
+42 0 1
+56 5 9
+62 0 5
+45 1 1
+109 25 25
+314 1 2
+16 0 2
+45 1 1
+103 17 17
+84 8 8
+294 17 17
+527 10 10
+435 4 0
+91 0 4
+387 10 10
+312 1 1
+43 1 1
+181 1 0
+1737 2 3
+50 1 1
+140 1 1
+33 1 0
+113 7 7
+353 6 6
+794 8 8
+510 1 1
+18 1 1
+124 1 1
+19 8 4
+76 1 0
+880 1 1
+16 1 1
+491 1 1
+49 1 1
+239 1 1
+7 0 1
+67 1 1
+114 0 25
+26 1 1
+183 13 13
+72 1 1
+26 1 0
+42 1 1
+222 14 14
+320 1 1
+55 1 1
+414 6 5
+1003 1 1
+20 0 8
+849 1 1
+29 1 1
+978 29539 30058
+159 1 1
+36 1 1
+107 1 1
+176 1 1
+154 0 5
+91 1 1
+54 1 1
+77 1 1
+238 2 2
+50 1 1
+1421 1 1
+23 1 1
+216 1 1
+122 1 1
+86 1 1
+41 3 1
+336 7 7
+41 9 0
+107 1 1
+90 1 3
+6 1 0
+84 1 1
+213 1 1
+26 1 1
+138 1 1
+25 1 1
+206 1 1
+36 3 3
+37 7 0
+500 1 1
+52 1 1
+52 1 1
+48 1 1
+186 1 1
+66 1 1
+141 1 1
+66 6 6
+72 1 0
+69 1 1
+100 10 10
+160 1 0
+64 7 7
+89 1 1
+123 1 1
+128 1 1
+36 1 1
+231 1 1
+61 1 1
+564 8 8
+593 1 1
+45 1 1
+163 1 0
+196 8 8
+97 1 1
+118 1 1
+67 0 1
+192 1 1
+60 3 0
+19 1 1
+1149 1 1
+18 1 1
+77 1 1
+32 2 0
+32 1 1
+136 1 1
+78 2 0
+162 4 0
+41 1 1
+351 13 13
+1634 2 0
+229 8 8
+59 11 0
+410 1 1
+76 1 1
+180 1 1
+92 1 1
+270 1 1
+40 1 1
+92 1 1
+53 1 1
+227 1 1
+42 1 1
+357 4 4
+23 1 1
+94 1 0
+200 6 0
+201 7 7
+70 5 13
+57 4 0
+35 1 1
+206 1 1
+76 2 2
+651 1 1
+68 4 0
+73 1 1
+49 4 0
+37 1 1
+145 2 2
+78 2 2
+108 12 12
+52 1 1
+35 1 1
+242 1 3
+76 2 2
+50 12 12
+70 1 1
+33 0 2
+57 1 1
+64 15 15
+168 1 1
+22 1 1
+66 2 2
+6 0 1
+24 1 1
+73 0 2
+64 1 1
+177 2 0
+19 4 0
+55 1 0
+33 1 1
+51 1 1
+122 1 1
+296 1 1
+85 1 1
+109 1 1
+64 1 1
+155 1 1
+58 0 2
+72 1 1
+25 1 1
+128 1 1
+45 2 0
+334 4 4
+106 1 1
+25 1 1
+64 1 1
+21 1 1
+368 15 15
+734 2 0
+701 15 15
+71 1 1
+41 1 1
+77 1 1
+56 1 1
+478 2 0
+714 8 7
+95 2 2
+52 2 1
+1129 1 1
+34 1 1
+1715 1 1
+87 1 1
+692 1 1
+47 0 1
+75 1 1
+2155 10 10
+1265 1 1
+46 1 1
+298 1 1
+22 1 1
+186 1 1
+34 1 1
+202 1 1
+61 1 0
+185 1 1
+24 1 0
+98 0 2
+258 8 14
+967 1 1
+15 1 1
+625 1 0
+1362 0 4
+23365 4 0
+6220 3 0
+1351 18 18
+11498 8145 8145
+3307 0 1
+13671 3 3
+52 1 1
+1308 2 0
+942 0 1
+17790 1 0
+4586 0 1
+949 0 2
+15047 0 1
+606 3 0
+7820 0 4
+22313 6 0
+10539 12 0
+4836 0 1
+8726 2 0
+194 1 1
+49 1 1
+15889 3 0
+2693 0 2
+2787 56 56
+544 0 1
+2673 26 19
+3075 2 0
+4230 8 0
+879 0 1
+9534 0 4
+23 1 1
+599 0 1
+317 1 0
+2844 27 31
+571 2 0
+3158 0 4
+4455 2 0
+1609 0 7
+61 1 1
+66 1 1
+343 7 0
+25 1 1
+246 0 1
+15 1 1
+943 2 0
+136 8 7
+589 1 1
+84 1 1
+280 17 15
+680 15 15
+81 0 3
+1484 12 28
+1016 1 1
+45 1 0
+108 0 10
+675 4 0
+1568 0 1
+191 4 4
+1484 9 13
+3530 2 4
+2846 1 1
+17 1 1
+704 0 1
+4801 1 0
+1417 0 4
+50 3 0
+165 0 1
+4044 39283 39283
+854 1 1
+47 1 1
+479 1 0
+137 0 3
+1456 10 13
+63 1 1
+37 1 1
+261 0 2
+109 1 1
+50 1 1
+56 129 1
+88 1 0
+44 1 1
+54 1 1
+56 1 50
+58 50 1
+54 277 1
+44 1 1
+297 0 39
+142 1 1
+85 1 1
+124 16 16
+58 3 15
+677 1 0
+1333 2 0
+13591 6 0
+1050 1 1
+46 1 1
+678 1 1
+31 1 1
+2632 4 4
+37 1 1
+22341 32 30
+10811 1 1
+25 0 1
+129 62 62
+226 1 1
+40 1 1
+159 4 4
+37 4 4
+179 1 1
+51 1 1
+103 2 0
+108 1 1
+79 1 1
+25 1 1
+58 1 1
+12 1 1
+275 14 0
+80 1 1
+83 1 1
+24 1 1
+59 1 0
+91 1 1
+65 1 1
+67 1 1
+136 4 0
+68 8 0
+331 5 0
+40 1 1
+110 10 6
+64 1 1
+368 1 1
+22 1 1
+509 1 1
+89 1 1
+926 1 0
+959 1 1
+44 1 1
+72 11 0
+47 1 1
+361 1 1
+37 1 1
+2204 2 2
+45 1 1
+1117 18 18
+141 1 1
+47 1 1
+148 1 1
+75 1 1
+107 57 56
+146 3 2
+249 1 1
+146 1 1
+94 1 1
+34 1 1
+700 0 331
+21 1 1
+73 1 1
+49 1 1
+356 1 1
+16 1 1
+112 1 1
+36 9 0
+515 1 1
+27 2 2
+192 1 1
+53 0 14
+82 1 1
+302 1 1
+68 1 1
+52 12 12
+52 1 1
+34 1 1
+166 7 7
+384 1 1
+31 1 1
+281 1 1
+57 1 1
+176 0 1
+1625 1 1
+26 1 1
+369 1 1
+21 1 1
+86 1 1
+134 1 1
+215 1 1
+214 15 1
+50 2 2
+26 1 1
+78 0 19
+64 1 1
+126 1 1
+43 1 1
+433 1 1
+76 0 1
+6 12 0
+52 1 1
+108 1 1
+87 1 1
+62 1 1
+26 1 1
+291 2 1
+143 1 1
+29 1 1
+56 12 12
+230 1 1
+153 4 4
+87 32 32
+584 12 12
+227 1 0
+1931 4 0
+836 1 1
+68 1 1
+205 24 19
+816 1 2
+1932 0 7
+1732 13 0
+257 4 0
+1441 1 0
+111 6 0
+1505 1 1
+42 0 1
+373 13 13
+565 1 1
+76 1 0
+1881 0 4
+68 4 0
+43 0 4
+2201 8 8
+3726 3 0
+339 15 11
+249 1 1
+35 1 1
+250 1 1
+38 1 1
+359 11 12
+109 1 1
+43 18 0
+822 1 1
+53 1 1
+325 15 15
+123 1 1
+42 6 6
+240 1 1
+44 1 1
+438 7 7
+142 2 0
+1004 0 1
+9275 1 1
+37 1 0
+2071 0 1
+10399 0 1
+12513 2 1
+11243 1 1
+26 1 1
+816 4 0
+8248 26 26
+7722 2 0
+1594 1 0
+363 5 0
+2394 0 2
+4361 43 41
+12296 4 0
+835 0 1
+391 34 61
+12157 0 18
+1719
+
+chain 576814 chr6_mann_hap4 4683263 + 1212600 1230600 chr10 135374737 - 28241612 28250801 9180
+481 1 1
+46 1 1
+3015 1 1
+93 1 1
+2394 11402 2623
+68 26 25
+5 0 2
+124 0 1
+62 39 3
+39 3 5
+199
+
+chain 536760 chr6_mann_hap4 4683263 + 4039899 4045825 chr5 180857866 + 39823592 39829519 16844
+294 1 1
+54 1 1
+302 0 1
+93 1 1
+29 2 2
+134 1 1
+55 1 1
+603 13 13
+1215 13 13
+1780 1 1
+42 1 1
+233 1 1
+94 1 1
+485 1 1
+173 1 1
+76 1 1
+24 1 1
+71 1 1
+44 1 1
+82
+
+chain 146874 chr6_mann_hap4 4683263 + 4071169 4072762 chr6 170899992 + 134026872 134029045 878977
+503 1 1
+42 1 1
+274 1 1
+24 0 1
+48 1 0
+10 0 1
+42 0 579
+646
+
+chain 102870 chr6_mann_hap4 4683263 + 3889360 3891944 chr7 158821424 + 116952571 116956379 1238703
+117 2 2
+40 1 1
+56 1 1
+110 1 1
+92 1 1
+113 2 2
+63 1 1
+85 102 1326
+64 26 26
+95 124 124
+108 355 355
+211 690 690
+124
+
+chain 88220 chr6_mann_hap4 4683263 + 4099145 4105339 chr12 132349534 - 75332582 75341961 1434691
+65 33 33
+177 10 15
+106 4900 8080
+86 4 4
+267 1 1
+40 1 1
+504
+
+chain 82095 chr6_mann_hap4 4683263 + 3946479 3947465 chr2 242951149 - 63941857 63946734 1538129
+173 0 3890
+317 1 1
+39 1 1
+234 0 4
+116 1 1
+18 3 0
+83
+
+chain 77658 chr6_mann_hap4 4683263 + 3855504 3856400 chrX 154913754 + 120225651 120226547 1623639
+896
+
+chain 47748 chr6_mann_hap4 4683263 + 3888321 3890147 chrX 154913754 + 47530376 47536125 1299062
+73 10 10
+52 18 17
+100 64 64
+53 6 6
+131 99 99
+213 51 51
+144 732 4656
+80
+
+chain 47213 chr6_mann_hap4 4683263 + 3989872 3990794 chr5 180857866 + 134244858 134245983 2704506
+144 28 28
+67 90 94
+193 60 61
+52 141 339
+53 41 41
+53
+
+chain 46978 chr6_mann_hap4 4683263 + 2571063 2572874 chr3 199501827 - 190558999 190560805 2719824
+64 48 48
+112 161 161
+89 220 218
+60 475 474
+84 303 301
+99 9 9
+87
+
+chain 44341 chr6_mann_hap4 4683263 + 3927110 3927612 chrX 154913754 - 52960373 52960875 2903522
+147 1 1
+78 1 1
+160 1 1
+114
+
+chain 44107 chr6_mann_hap4 4683263 + 3835941 3836978 chr5 180857866 + 173373371 173375321 2921175
+63 100 100
+147 427 1340
+300
+
+chain 39461 chr6_mann_hap4 4683263 + 4070547 4070992 chr9 140273252 + 112733643 112734088 3326103
+238 2 2
+149 1 1
+55
+
+chain 35818 chr6_mann_hap4 4683263 + 3871024 3871462 chr17 78774742 - 29841443 29841854 3734139
+50 1 1
+51 12 0
+240 15 0
+69
+
+chain 30934 chr6_mann_hap4 4683263 + 2643294 2643706 chr7 158821424 + 2168309 2168721 4470814
+207 3 3
+37 1 1
+54 50 50
+60
+
+chain 26090 chr6_mann_hap4 4683263 + 1150980 1153720 chr6 170899992 + 30003398 30007118 6475487
+62 70 70
+76 766 798
+93 658 655
+52 786 1737
+53 61 61
+63
+
+chain 23990 chr6_mann_hap4 4683263 + 1157427 1158203 chr7 158821424 - 51137320 51138262 7695541
+178 101 101
+72 385 551
+40
+
+chain 23264 chr6_mann_hap4 4683263 + 4065870 4066815 chr6 170899992 + 32821586 32822354 8135397
+218 677 500
+50
+
+chain 21807 chr6_mann_hap4 4683263 + 2512201 2512573 chrX 154913754 - 34520894 34521266 9125800
+131 125 125
+116
+
+chain 20350 chr6_mann_hap4 4683263 + 2657077 2657501 chr7 158821424 - 21000102 21000525 10170609
+90 41 41
+55 140 139
+98
+
+chain 20145 chr6_mann_hap4 4683263 + 4080253 4081781 chr7 158821424 + 28844408 28845333 2477233
+50 75 74
+83 106 109
+74 174 246
+103 816 139
+47
+
+chain 19089 chr6_mann_hap4 4683263 + 3856636 3856946 chr6 170899992 - 57258123 57258433 11200200
+55 51 51
+66 32 32
+106
+
+chain 17641 chr6_mann_hap4 4683263 + 4011215 4011458 chrX 154913754 + 35042287 35042530 12436915
+99 43 43
+101
+
+chain 16962 chr6_mann_hap4 4683263 + 2570543 2573577 chr6 170899992 - 142198254 142201285 2740643
+52 14 14
+92 178 178
+78 1931 1927
+60 60 61
+102 387 387
+80
+
+chain 16215 chr6_mann_hap4 4683263 + 3951844 3952907 chr6 170899992 + 32656500 32657559 13820716
+58 826 822
+72 27 27
+80
+
+chain 16190 chr6_mann_hap4 4683263 + 3164538 3164716 chr2 242951149 + 128261675 128261851 597537
+28 10 8
+140
+
+chain 16086 chr6_mann_hap4 4683263 + 4006818 4007634 chr1 247249719 - 180906629 180907434 2580692
+2 123 123
+47 104 104
+70 400 389
+70
+
+chain 15557 chr6_mann_hap4 4683263 + 4157319 4158144 chr7 158821424 + 130132312 130132930 14485178
+71 636 429
+118
+
+chain 15452 chr6_mann_hap4 4683263 + 3929430 3929596 chrX 154913754 + 67920599 67920765 14594392
+166
+
+chain 14605 chr6_mann_hap4 4683263 + 4069695 4069910 chr5 180857866 + 98319067 98319283 15498993
+64 48 49
+103
+
+chain 14320 chr6_mann_hap4 4683263 + 3970754 3970920 chr5 180857866 + 46013667 46013833 15829593
+166
+
+chain 13359 chr6_mann_hap4 4683263 + 4006581 4006818 chr5 180857866 - 39455571 39455808 2075146
+237
+
+chain 13048 chr6_mann_hap4 4683263 + 3971467 3971895 chr2 242951149 + 206984071 206984490 17422560
+94 272 263
+62
+
+chain 13024 chr6_mann_hap4 4683263 + 983409 983545 chr11 134452384 - 45905925 45906061 17454497
+136
+
+chain 12983 chr6_mann_hap4 4683263 + 3892428 3892585 chr15 100338915 + 59852230 59852387 17511267
+67 7 7
+83
+
+chain 12686 chr6_mann_hap4 4683263 + 3839048 3839184 chr6 170899992 - 138278996 138279132 17957207
+136
+
+chain 12556 chr6_mann_hap4 4683263 + 1192697 1192836 chr2 242951149 - 184047846 184047985 18149168
+139
+
+chain 12476 chr6_mann_hap4 4683263 + 3826791 3826924 chr6 170899992 + 32549390 32549523 18269668
+133
+
+chain 12434 chr6_mann_hap4 4683263 + 3808825 3809130 chr7 158821424 - 76714202 76714512 18331176
+70 158 163
+77
+
+chain 12179 chr6_mann_hap4 4683263 + 3831748 3831876 chr6 170899992 + 32566069 32566197 18716372
+128
+
+chain 12137 chr6_mann_hap4 4683263 + 3872720 3873131 chr7 158821424 + 90920405 90920810 18779045
+54 266 260
+91
+
+chain 12051 chr6_mann_hap4 4683263 + 1151414 1151573 chr6 170899992 + 30566919 30567079 18913589
+81 23 24
+55
+
+chain 11900 chr6_mann_hap4 4683263 + 3926391 3926689 chr5 180857866 - 150002482 150002780 2916742
+72 52 52
+94 24 24
+56
+
+chain 11872 chr6_mann_hap4 4683263 + 1146859 1148064 chr6 170899992 + 29900614 29901492 19205041
+65 1050 723
+90
+
+chain 11746 chr6_mann_hap4 4683263 + 1143598 1143746 chr7 158821424 - 7754727 7754875 19419747
+54 14 14
+80
+
+chain 11745 chr6_mann_hap4 4683263 + 1218680 1218806 chr10 135374737 - 135314271 135314397 19420295
+126
+
+chain 11699 chr6_mann_hap4 4683263 + 1229899 1230035 chr10 135374737 + 90412720 90412856 14918390
+117 3 3
+16
+
+chain 11593 chr6_mann_hap4 4683263 + 3807962 3808085 chr1 247249719 - 238369051 238369174 19677684
+123
+
+chain 11428 chr6_mann_hap4 4683263 + 3972086 3972349 chr9 140273252 + 73803510 73803773 19960546
+86 127 127
+50
+
+chain 11397 chr6_mann_hap4 4683263 + 3965743 3966049 chr6 170899992 + 32661358 32661660 20018576
+64 168 164
+74
+
+chain 11122 chr6_mann_hap4 4683263 + 1203623 1204440 chr6 170899992 - 139553083 139553887 20511870
+77 676 663
+64
+
+chain 11075 chr6_mann_hap4 4683263 + 3824678 3824943 chrX 154913754 - 91757488 91757751 20592182
+66 132 130
+67
+
+chain 11034 chr6_mann_hap4 4683263 + 2653282 2653431 chr6 170899992 - 161606914 161607063 20670487
+64 22 22
+63
+
+chain 10867 chr6_mann_hap4 4683263 + 2578599 2578756 chr6 170899992 - 132294381 132294544 20980274
+55 29 35
+73
+
+chain 10661 chr6_mann_hap4 4683263 + 4070344 4070547 chr9 140273252 + 21133799 21134002 3998059
+43 83 83
+77
+
+chain 10522 chr6_mann_hap4 4683263 + 3881310 3881592 chr6 170899992 + 32650612 32650898 21668160
+51 155 159
+76
+
+chain 10446 chr6_mann_hap4 4683263 + 3833364 3833476 chr10 135374737 + 116791472 116791584 21828222
+112
+
+chain 10440 chr6_mann_hap4 4683263 + 3811691 3811821 chr3 199501827 - 53390365 53390495 21843018
+67 9 9
+54
+
+chain 10424 chr6_mann_hap4 4683263 + 1196400 1196662 chr1 247249719 - 93388912 93389184 21873906
+71 137 147
+54
+
+chain 10120 chr6_mann_hap4 4683263 + 4070282 4070470 chr7 158821424 - 148539669 148539857 3454343
+62 43 43
+83
+
+chain 10097 chr6_mann_hap4 4683263 + 3811321 3811557 chr6 170899992 - 10896454 10896689 22596969
+52 115 114
+69
+
+chain 10000 chr6_mann_hap4 4683263 + 4096293 4096805 chr2 242951149 - 75663422 75663931 22813441
+66 387 384
+59
+
+chain 9988 chr6_mann_hap4 4683263 + 3809787 3810216 chr10 135374737 - 44216709 44217139 22840112
+60 305 306
+64
+
+chain 9977 chr6_mann_hap4 4683263 + 4081621 4081734 chr6 170899992 - 39392888 39393001 3205407
+113
+
+chain 9923 chr6_mann_hap4 4683263 + 1132190 1132294 chr6 170899992 + 29984509 29984613 22990369
+104
+
+chain 9759 chr6_mann_hap4 4683263 + 3834344 3834498 chr10 135374737 + 105999092 105999246 23372649
+62 39 39
+53
+
+chain 9755 chr6_mann_hap4 4683263 + 3833117 3833361 chrX 154913754 - 4438295 4438540 23379344
+56 126 127
+62
+
+chain 9686 chr6_mann_hap4 4683263 + 3810435 3810616 chr18 76117153 - 71040520 71040702 23549061
+65 65 66
+51
+
+chain 9627 chr6_mann_hap4 4683263 + 3972992 3973194 chr2 242951149 + 230690248 230690450 23687186
+65 86 86
+51
+
+chain 9614 chr6_mann_hap4 4683263 + 2669709 2670446 chr6 170899992 - 140934793 140935541 23727233
+66 613 624
+58
+
+chain 9599 chr6_mann_hap4 4683263 + 4070139 4070248 chr11 134452384 + 56073710 56073819 11992436
+109
+
+chain 9564 chr6_mann_hap4 4683263 + 3827056 3827221 chr6 170899992 + 32549657 32549823 23841399
+59 50 51
+56
+
+chain 9528 chr6_mann_hap4 4683263 + 1159675 1160112 chr6 170899992 + 29878108 29878543 23937749
+59 318 316
+60
+
+chain 9459 chr6_mann_hap4 4683263 + 4095177 4095476 chr6 170899992 + 162410099 162410399 24103461
+60 183 184
+56
+
+chain 9368 chr6_mann_hap4 4683263 + 3972521 3972756 chr12 132349534 - 95011118 95011354 24299159
+63 120 121
+52
+
+chain 9354 chr6_mann_hap4 4683263 + 3870808 3870942 chr6 170899992 + 119226702 119226836 9825430
+89 20 20
+25
+
+chain 9352 chr6_mann_hap4 4683263 + 3873416 3873994 chr1 247249719 - 127730766 127731350 24325058
+63 457 463
+58
+
+chain 9220 chr6_mann_hap4 4683263 + 3811888 3812097 chr14 106368585 - 26360313 26360419 24589598
+77 103 0
+29
+
+chain 9090 chr6_mann_hap4 4683263 + 2577845 2577955 chr3 199501827 - 94209663 94209773 24799757
+53 4 4
+53
+
+chain 8867 chr6_mann_hap4 4683263 + 2303270 2303362 chr6 170899992 + 31062348 31062440 25148412
+92
+
+chain 8658 chr6_mann_hap4 4683263 + 3940022 3940112 chr6 170899992 + 32624355 32624445 25451087
+90
+
+chain 8423 chr6_mann_hap4 4683263 + 4072785 4072907 chr8 146274826 - 73050790 73050912 14363914
+122
+
+chain 8057 chr6_mann_hap4 4683263 + 3926870 3927000 chr16 88827254 + 18531944 18532074 3198196
+130
+
+chain 7759 chr6_mann_hap4 4683263 + 2673921 2674003 chr6 170899992 + 31350450 31350532 26801069
+82
+
+chain 7673 chr6_mann_hap4 4683263 + 2657501 2657610 chr6 170899992 + 83069844 83069953 14556403
+4 44 44
+61
+
+chain 7642 chr6_mann_hap4 4683263 + 3888828 3890773 chr8 146274826 - 66025745 66026665 1359052
+97 215 215
+31 1 1
+19 1532 507
+50
+
+chain 7574 chr6_mann_hap4 4683263 + 4484512 4485183 chr20 62435964 + 45587686 45587880 2535008
+51 481 51
+16 61 14
+62
+
+chain 7541 chr6_mann_hap4 4683263 + 2688373 2688460 chr9 140273252 - 10289268 10289355 15645101
+13 6 6
+68
+
+chain 7487 chr6_mann_hap4 4683263 + 2574042 2574244 chr12 132349534 - 40641236 40641438 23940543
+56 141 141
+5
+
+chain 7440 chr6_mann_hap4 4683263 + 3850580 3850658 chrX 154913754 - 39741290 39741368 27355538
+78
+
+chain 7404 chr6_mann_hap4 4683263 + 3850662 3850740 chr11 134452384 + 35675434 35675512 27404541
+78
+
+chain 7364 chr6_mann_hap4 4683263 + 4081165 4082062 chr1 247249719 + 33290703 33291601 1419850
+50 1 0
+53 86 88
+56 370 370
+160 42 42
+79
+
+chain 7276 chr6_mann_hap4 4683263 + 4034825 4034901 chr6 170899992 - 67344251 67344327 27653184
+76
+
+chain 7232 chr6_mann_hap4 4683263 + 3936821 3936898 chr6 170899992 + 32620027 32620104 27728489
+77
+
+chain 7204 chr6_mann_hap4 4683263 + 3963650 3963727 chr13 114142980 + 48271341 48271418 27789281
+77
+
+chain 7199 chr6_mann_hap4 4683263 + 4005404 4006455 chr3 199501827 + 106790123 106791174 347314
+69 5 5
+109 2 2
+142 1 1
+77 1 1
+51 1 0
+194 0 1
+399
+
+chain 7168 chr6_mann_hap4 4683263 + 4101507 4101583 chr12 132349534 + 30936505 30936581 27864404
+76
+
+chain 7077 chr6_mann_hap4 4683263 + 3870942 3871024 chr3 199501827 - 45186978 45187059 5450943
+68 1 0
+13
+
+chain 7012 chr6_mann_hap4 4683263 + 4115371 4115645 chr5 180857866 - 50439772 50440046 4370271
+130 8 8
+64 1 1
+71
+
+chain 6949 chr6_mann_hap4 4683263 + 3795791 3795864 chr6 170899992 + 32549387 32549460 28300222
+73
+
+chain 6804 chr6_mann_hap4 4683263 + 3799462 3799534 chr6 170899992 + 32582474 32582546 28581367
+72
+
+chain 6732 chr6_mann_hap4 4683263 + 2675578 2675667 chr18 76117153 - 11487790 11487879 28728624
+29 7 7
+53
+
+chain 6712 chr6_mann_hap4 4683263 + 2588030 2588100 chr6 170899992 - 140565854 140565924 28801698
+70
+
+chain 6680 chr6_mann_hap4 4683263 + 4075286 4087765 chr6 170899992 + 32827127 32836923 21175981
+50 4327 3617
+61 4734 2690
+85 515 965
+52 119 119
+177 2121 1742
+68 118 118
+52
+
+chain 6622 chr6_mann_hap4 4683263 + 3824747 3824817 chr11 134452384 + 57802002 57802072 28988414
+70
+
+chain 6586 chr6_mann_hap4 4683263 + 2674213 2674283 chr6 170899992 - 140567268 140567338 29088341
+70
+
+chain 6584 chr6_mann_hap4 4683263 + 3990111 3990185 chr18 76117153 - 4274607 4274681 4481991
+74
+
+chain 6566 chr6_mann_hap4 4683263 + 4010034 4010102 chr6 170899992 + 32665461 32665529 29137405
+68
+
+chain 6513 chr6_mann_hap4 4683263 + 4099018 4099087 chr12 132349534 + 47073126 47073195 29262419
+69
+
+chain 6495 chr6_mann_hap4 4683263 + 4159049 4159118 chr5 180857866 + 76445848 76445917 29303918
+69
+
+chain 6436 chr6_mann_hap4 4683263 + 3871527 3871805 chr7 158821424 + 110932926 110933204 10468972
+57 171 171
+50
+
+chain 6411 chr6_mann_hap4 4683263 + 4039821 4039893 chr7 158821424 + 30445389 30445461 17285
+72
+
+chain 6359 chr6_mann_hap4 4683263 + 3869372 3869440 chr6 170899992 + 32566306 32566374 29618338
+68
+
+chain 6271 chr6_mann_hap4 4683263 + 3932457 3932523 chr18 76117153 + 11207587 11207653 29843873
+66
+
+chain 6221 chr6_mann_hap4 4683263 + 4094828 4094893 chr13 114142980 + 50378597 50378662 29991830
+65
+
+chain 6213 chr6_mann_hap4 4683263 + 1229662 1229728 chrX 154913754 + 137911239 137911305 30001477
+66
+
+chain 6203 chr6_mann_hap4 4683263 + 3873624 3873689 chr10 135374737 + 5090148 5090213 30033078
+65
+
+chain 6176 chr6_mann_hap4 4683263 + 4099536 4099611 chr11 134452384 - 71399807 71399882 3438338
+75
+
+chain 6158 chr6_mann_hap4 4683263 + 3877219 3877284 chr8 146274826 + 95080661 95080726 30127968
+65
+
+chain 6140 chr6_mann_hap4 4683263 + 4095848 4095913 chr6 170899992 - 34774251 34774316 30199403
+65
+
+chain 6109 chr6_mann_hap4 4683263 + 3890332 3891494 chr3 199501827 - 173189040 173190202 2018297
+14 5 5
+73 23 23
+9 985 985
+53
+
+chain 6085 chr6_mann_hap4 4683263 + 3815553 3815617 chr6 170899992 - 55240220 55240284 30326057
+64
+
+chain 6021 chr6_mann_hap4 4683263 + 4094914 4094977 chr10 135374737 - 117721859 117721922 30522771
+63
+
+chain 5976 chr6_mann_hap4 4683263 + 2676901 2676964 chr6 170899992 + 31358648 31358711 30614230
+63
+
+chain 5949 chr6_mann_hap4 4683263 + 3824409 3824472 chr7 158821424 + 26639264 26639327 30690415
+63
+
+chain 5940 chr6_mann_hap4 4683263 + 3886792 3886855 chr2 242951149 - 15301589 15301652 30719367
+63
+
+chain 5911 chr6_mann_hap4 4683263 + 3951381 3951442 chrX 154913754 - 11371530 11371591 30799839
+61
+
+chain 5847 chr6_mann_hap4 4683263 + 4105339 4105404 chr17 78774742 - 73855979 73856044 1451430
+65
+
+chain 5813 chr6_mann_hap4 4683263 + 3850423 3850485 chr1 247249719 + 47323960 47324022 31053357
+62
+
+chain 5712 chr6_mann_hap4 4683263 + 3809370 3809430 chr12 132349534 - 114271713 114271773 31330278
+60
+
+chain 5702 chr6_mann_hap4 4683263 + 3970106 3970165 chr6 170899992 + 32605878 32605937 31357679
+59
+
+chain 5680 chr6_mann_hap4 4683263 + 2302831 2302921 chr6 170899992 + 31062944 31063124 23617653
+33 39 129
+18
+
+chain 5655 chr6_mann_hap4 4683263 + 3855204 3855371 chrX 154913754 + 81246238 81246422 14247867
+57 109 126
+1
+
+chain 5594 chr6_mann_hap4 4683263 + 3796059 3796118 chr6 170899992 + 32549657 32549716 31663072
+59
+
+chain 5594 chr6_mann_hap4 4683263 + 3893458 3893517 chr1 247249719 - 146336256 146336315 31665010
+59
+
+chain 5512 chr6_mann_hap4 4683263 + 3824164 3824222 chr7 158821424 + 45670922 45670980 31905208
+58
+
+chain 5502 chr6_mann_hap4 4683263 + 3808491 3808548 chr1 247249719 - 79348621 79348678 31943034
+57
+
+chain 5494 chr6_mann_hap4 4683263 + 4130703 4130761 chr5 180857866 - 119300515 119300573 31945207
+58
+
+chain 5494 chr6_mann_hap4 4683263 + 3808247 3808305 chr4 191273063 - 5377020 5377078 31946828
+58
+
+chain 5476 chr6_mann_hap4 4683263 + 2311526 2311584 chrX 154913754 + 154691014 154691072 32018635
+58
+
+chain 5448 chr6_mann_hap4 4683263 + 1152324 1152381 chr6 170899992 + 29906136 29906193 32122349
+57
+
+chain 5435 chr6_mann_hap4 4683263 + 4007164 4007322 chr6 170899992 - 63943483 63943641 1906371
+158
+
+chain 5402 chr6_mann_hap4 4683263 + 1156066 1156122 chr10 135374737 + 63402064 63402120 32243879
+56
+
+chain 5394 chr6_mann_hap4 4683263 + 3972634 3972691 chr9 140273252 - 60383594 60383651 32250416
+57
+
+chain 5385 chr6_mann_hap4 4683263 + 4130844 4130901 chr6 170899992 - 83909587 83909644 32298057
+57
+
+chain 5367 chr6_mann_hap4 4683263 + 2578199 2578256 chr18 76117153 + 1134159 1134216 32358571
+57
+
+chain 5330 chr6_mann_hap4 4683263 + 3931278 3931334 chr6 170899992 + 32568311 32568367 32437916
+56
+
+chain 5276 chr6_mann_hap4 4683263 + 4098513 4098569 chr12 132349534 + 40414598 40414654 32640380
+56
+
+chain 5229 chr6_mann_hap4 4683263 + 2586412 2586466 chr6 170899992 - 140897459 140897513 32754405
+54
+
+chain 5211 chr6_mann_hap4 4683263 + 3836033 3836093 chr18 76117153 - 36956615 36956675 5572697
+38 15 15
+7
+
+chain 5158 chr6_mann_hap4 4683263 + 3970466 3970521 chr10 135374737 - 40576729 40576784 32990090
+55
+
+chain 5146 chr6_mann_hap4 4683263 + 3856405 3856719 chr8 146274826 + 48564292 48564606 15853984
+85 201 201
+28
+
+chain 5121 chr6_mann_hap4 4683263 + 3811628 3811682 chr10 135374737 - 125001214 125001268 33093899
+54
+
+chain 5103 chr6_mann_hap4 4683263 + 1145020 1145074 chr6 170899992 + 76955761 76955815 33170027
+54
+
+chain 5103 chr6_mann_hap4 4683263 + 2640619 2640673 chr4 191273063 + 102542252 102542306 33171908
+54
+
+chain 5085 chr6_mann_hap4 4683263 + 4098430 4098484 chrX 154913754 - 140611616 140611670 33235342
+54
+
+chain 5066 chr6_mann_hap4 4683263 + 1192620 1192673 chr21 46944323 - 1867343 1867396 33290792
+53
+
+chain 5062 chr6_mann_hap4 4683263 + 2570759 2570813 chr8 146274826 - 12544502 12544556 11634211
+54
+
+chain 5031 chr6_mann_hap4 4683263 + 3825550 3825604 chr11 134452384 + 134387408 134387462 33376435
+54
+
+chain 5030 chr6_mann_hap4 4683263 + 4130785 4130838 chr15 100338915 + 69519076 69519129 33389328
+53
+
+chain 5021 chr6_mann_hap4 4683263 + 2574130 2574183 chrX 154913754 + 36345885 36345938 33439867
+53
+
+chain 5020 chr6_mann_hap4 4683263 + 4060907 4060959 chr3 199501827 + 48220698 48220750 33444406
+52
+
+chain 5012 chr6_mann_hap4 4683263 + 3951677 3951730 chr6 170899992 + 32629462 32629515 33454256
+53
+
+chain 5003 chr6_mann_hap4 4683263 + 4102005 4102058 chr5 180857866 + 152654188 152654241 33499797
+53
+
+chain 5003 chr6_mann_hap4 4683263 + 1229462 1229515 chr19 63811651 - 15372469 15372522 33501003
+53
+
+chain 4985 chr6_mann_hap4 4683263 + 2640409 2640462 chr16 88827254 - 40848691 40848744 33578669
+53
+
+chain 4971 chr6_mann_hap4 4683263 + 2512062 2512133 chr4 191273063 - 56892114 56892185 10839773
+71
+
+chain 4967 chr6_mann_hap4 4683263 + 3825268 3825321 chr3 199501827 + 186460138 186460191 33617850
+53
+
+chain 4957 chr6_mann_hap4 4683263 + 3885923 3885975 chrX 154913754 + 147065533 147065585 33651269
+52
+
+chain 4957 chr6_mann_hap4 4683263 + 2575182 2575234 chr9 140273252 - 31866047 31866099 33651494
+52
+
+chain 4948 chr6_mann_hap4 4683263 + 4100717 4100769 chr1 247249719 - 35792193 35792245 33679191
+52
+
+chain 4948 chr6_mann_hap4 4683263 + 2574667 2574719 chr8 146274826 - 9857366 9857418 33680602
+52
+
+chain 4922 chr6_mann_hap4 4683263 + 4009115 4009168 chr6 170899992 + 32548301 32548354 33750859
+53
+
+chain 4903 chr6_mann_hap4 4683263 + 3850504 3850556 chr10 135374737 - 57466002 57466054 33851105
+52
+
+chain 4903 chr6_mann_hap4 4683263 + 4012033 4012085 chr10 135374737 + 117209347 117209399 33851122
+52
+
+chain 4863 chr6_mann_hap4 4683263 + 4069590 4069643 chr17 78774742 + 14392768 14392821 28434808
+53
+
+chain 4829 chr6_mann_hap4 4683263 + 1204441 1204491 chr6 170899992 + 29800923 29800973 34088054
+50
+
+chain 4821 chr6_mann_hap4 4683263 + 4157686 4157737 chrX 154913754 - 88293005 88293056 34119905
+51
+
+chain 4821 chr6_mann_hap4 4683263 + 3816946 3816997 chrX 154913754 + 135859174 135859225 34119936
+51
+
+chain 4812 chr6_mann_hap4 4683263 + 1190701 1190752 chr6 170899992 + 30567861 30567912 34152526
+51
+
+chain 4784 chr6_mann_hap4 4683263 + 3932557 3932607 chr3 199501827 + 84648995 84649045 34278095
+50
+
+chain 4758 chr6_mann_hap4 4683263 + 4095126 4095177 chr11 134452384 + 59226474 59226525 34323839
+51
+
+chain 4757 chr6_mann_hap4 4683263 + 2310474 2310524 chr11 134452384 + 7692440 7692490 34342561
+50
+
+chain 4739 chr6_mann_hap4 4683263 + 2310303 2310353 chr18 76117153 + 71840104 71840154 34400727
+50
+
+chain 4730 chr6_mann_hap4 4683263 + 3787434 3787484 chr4 191273063 - 37377714 37377764 34442427
+50
+
+chain 4712 chr6_mann_hap4 4683263 + 1146218 1146268 chr14 106368585 - 81295539 81295589 34510763
+50
+
+chain 4703 chr6_mann_hap4 4683263 + 2675065 2675115 chr8 146274826 + 89610032 89610082 34558303
+50
+
+chain 4685 chr6_mann_hap4 4683263 + 1229409 1229459 chrX 154913754 - 17497814 17497864 34590611
+50
+
+chain 4676 chr6_mann_hap4 4683263 + 3971574 3971624 chr8 146274826 + 69479304 69479354 34603338
+50
+
+chain 4606 chr6_mann_hap4 4683263 + 4016520 4016570 chr5 180857866 - 14463729 14463779 34659648
+50
+
+chain 4600 chr6_mann_hap4 4683263 + 2569984 2570033 chr12 132349534 - 4862576 4862625 22913313
+49
+
+chain 4530 chr6_mann_hap4 4683263 + 3886656 3886704 chr13 114142980 - 22170853 22170901 34701009
+48
+
+chain 4406 chr6_mann_hap4 4683263 + 4011118 4011181 chr12 132349534 + 83019068 83019131 17889504
+63
+
+chain 4392 chr6_mann_hap4 4683263 + 1157646 1157705 chr7 158821424 - 126060926 126060985 9905440
+59
+
+chain 4358 chr6_mann_hap4 4683263 + 3963545 3963592 chr4 191273063 + 98116240 98116287 34788627
+47
+
+chain 4338 chr6_mann_hap4 4683263 + 2302495 2302540 chr6 170899992 + 31062473 31062518 34812241
+45
+
+chain 4205 chr6_mann_hap4 4683263 + 2570813 2571448 chr4 191273063 + 161293453 161294088 2765734
+66 98 98
+77 6 6
+3 343 343
+42
+
+chain 4169 chr6_mann_hap4 4683263 + 4069643 4069694 chrX 154913754 + 84821116 84821167 24393818
+51
+
+chain 4167 chr6_mann_hap4 4683263 + 3838733 3838778 chr16 88827254 - 62536028 62536073 34880256
+45
+
+chain 4152 chr6_mann_hap4 4683263 + 3836004 3836104 chr19 63811651 + 19808105 19808205 3095372
+29 60 60
+11
+
+chain 4047 chr6_mann_hap4 4683263 + 3972236 3972287 chr6 170899992 + 112361298 112361349 25801950
+42 5 5
+4
+
+chain 3949 chr6_mann_hap4 4683263 + 2688555 2688633 chr19 63811651 + 60123016 60123094 19419643
+78
+
+chain 3938 chr6_mann_hap4 4683263 + 3812129 3812170 chr12 132349534 + 106783136 106783177 34996469
+41
+
+chain 3933 chr6_mann_hap4 4683263 + 2511488 2511645 chr1 247249719 - 10334654 10334811 9926759
+99 7 7
+51
+
+chain 3926 chr6_mann_hap4 4683263 + 4006888 4006943 chr9 140273252 - 21404336 21404391 4875740
+55
+
+chain 3812 chr6_mann_hap4 4683263 + 4007464 4007564 chr3 199501827 + 15208966 15209066 3047556
+56 42 42
+2
+
+chain 3783 chr6_mann_hap4 4683263 + 2657037 2657077 chr2 242951149 - 166645324 166645364 18114610
+40
+
+chain 3746 chr6_mann_hap4 4683263 + 3833193 3833245 chr3 199501827 + 114553026 114553078 23981702
+52
+
+chain 3734 chr6_mann_hap4 4683263 + 4157453 4157518 chr6 170899992 + 80018577 80018642 19955867
+65
+
+chain 3720 chr6_mann_hap4 4683263 + 4102548 4102587 chr5 180857866 - 28755460 28755499 35075682
+39
+
+chain 3600 chr6_mann_hap4 4683263 + 4159173 4159211 chr2 242951149 + 129304609 129304647 25766361
+38
+
+chain 3592 chr6_mann_hap4 4683263 + 3870724 3870762 chr3 199501827 - 38712743 38712781 26080747
+38
+
+chain 3526 chr6_mann_hap4 4683263 + 1196363 1196400 chr3 199501827 + 179624737 179624774 21949405
+37
+
+chain 3503 chr6_mann_hap4 4683263 + 3972049 3972086 chrX 154913754 + 6516305 6516342 20940830
+37
+
+chain 3405 chr6_mann_hap4 4683263 + 3888574 3888637 chr12 132349534 - 63727404 63727467 1360984
+63
+
+chain 3368 chr6_mann_hap4 4683263 + 3807881 3807940 chr10 135374737 - 122033518 122033577 24304357
+59
+
+chain 3334 chr6_mann_hap4 4683263 + 3942243 3942283 chr16 88827254 - 56809950 56809989 35201127
+19 1 0
+20
+
+chain 3303 chr6_mann_hap4 4683263 + 3972756 3972791 chr1 247249719 + 73729369 73729404 27153556
+35
+
+chain 3293 chr6_mann_hap4 4683263 + 4158373 4158408 chr7 158821424 - 26273345 26273380 30505739
+35
+
+chain 3293 chr6_mann_hap4 4683263 + 3825694 3825729 chr16 88827254 - 56536304 56536339 35220873
+35
+
+chain 3290 chr6_mann_hap4 4683263 + 2574386 2574448 chr8 146274826 + 34715687 34715749 20565863
+62
+
+chain 3284 chr6_mann_hap4 4683263 + 3962434 3962469 chr7 158821424 - 75715212 75715247 35222192
+35
+
+chain 3275 chr6_mann_hap4 4683263 + 1138144 1138179 chr6 170899992 + 29990315 29990350 35226053
+35
+
+chain 3266 chr6_mann_hap4 4683263 + 3971216 3971273 chr3 199501827 - 22333077 22333134 22107564
+57
+
+chain 3253 chr6_mann_hap4 4683263 + 4099622 4099676 chr19 63811651 + 42514641 42514695 4288250
+54
+
+chain 3205 chr6_mann_hap4 4683263 + 4070992 4071055 chr1 247249719 + 196464086 196464149 10251011
+63
+
+chain 3203 chr6_mann_hap4 4683263 + 3824817 3824851 chr3 199501827 - 28583100 28583134 30999626
+34
+
+chain 3180 chr6_mann_hap4 4683263 + 3893634 3893669 chr18 76117153 - 75290002 75290037 35254886
+35
+
+chain 3155 chr6_mann_hap4 4683263 + 4006480 4006566 chr8 146274826 - 94420792 94420878 3680803
+86
+
+chain 3107 chr6_mann_hap4 4683263 + 3887907 3887940 chr2 242951149 + 18209140 18209173 23522185
+33
+
+chain 3079 chr6_mann_hap4 4683263 + 2571537 2573841 chr6 170899992 + 126959071 126961365 3502977
+2 117 114
+67 2060 2053
+58
+
+chain 3064 chr6_mann_hap4 4683263 + 2303363 2303395 chr6 170899992 + 31062756 31062788 33922186
+32
+
+chain 3031 chr6_mann_hap4 4683263 + 3886413 3886445 chr2 242951149 + 186256011 186256043 29433855
+32
+
+chain 3016 chr6_mann_hap4 4683263 + 2311494 2311526 chrX 154913754 + 79124038 79124070 32077336
+32
+
+chain 2979 chr6_mann_hap4 4683263 + 3855470 3855504 chr3 199501827 + 4042271 4042305 1799588
+34
+
+chain 2964 chr6_mann_hap4 4683263 + 1196678 1196709 chrX 154913754 + 72461549 72461580 26677785
+31
+
+chain 2956 chr6_mann_hap4 4683263 + 3866093 3866129 chr1 247249719 - 141171387 141171423 35318155
+36
+
+chain 2906 chr6_mann_hap4 4683263 + 3932526 3932557 chr9 140273252 + 22587602 22587633 35284164
+31
+
+chain 2906 chr6_mann_hap4 4683263 + 3886745 3886778 chr8 146274826 - 118435747 118435780 35339754
+33
+
+chain 2872 chr6_mann_hap4 4683263 + 3971341 3971392 chr12 132349534 + 117591668 117591719 18400010
+51
+
+chain 2863 chr6_mann_hap4 4683263 + 2569913 2569984 chrX 154913754 + 15788619 15788690 15376547
+71
+
+chain 2850 chr6_mann_hap4 4683263 + 3872455 3872908 chr4 191273063 + 173531459 173531912 22440020
+66 326 326
+61
+
+chain 2847 chr6_mann_hap4 4683263 + 3886091 3886121 chr14 106368585 + 78698582 78698612 35350318
+30
+
+chain 2843 chr6_mann_hap4 4683263 + 4080743 4081595 chr9 140273252 + 76002383 76002587 2839818
+50 737 89
+65
+
+chain 2810 chr6_mann_hap4 4683263 + 3944503 3944532 chr1 247249719 - 39748406 39748435 35362931
+29
+
+chain 2797 chr6_mann_hap4 4683263 + 4484961 4485121 chr19 63811651 - 12967948 12968184 2658963
+29 70 70
+17 13 89
+31
+
+chain 2786 chr6_mann_hap4 4683263 + 3891682 3891777 chrX 154913754 - 85953788 85953883 2307593
+61 1 1
+33
+
+chain 2782 chr6_mann_hap4 4683263 + 2656861 2656923 chr8 146274826 - 144762871 144762933 15570304
+62
+
+chain 2778 chr6_mann_hap4 4683263 + 4115342 4115371 chr5 180857866 - 91122400 91122429 5117904
+29
+
+chain 2753 chr6_mann_hap4 4683263 + 1196549 1196608 chr12 132349534 + 50414483 50414542 22637630
+59
+
+chain 2740 chr6_mann_hap4 4683263 + 3887725 3887787 chr5 180857866 + 121612373 121612435 20400020
+62
+
+chain 2671 chr6_mann_hap4 4683263 + 2578539 2578598 chr9 140273252 - 60326471 60326530 21074054
+59
+
+chain 2624 chr6_mann_hap4 4683263 + 2643215 2643265 chr12 132349534 - 76880491 76880541 6796930
+50
+
+chain 2617 chr6_mann_hap4 4683263 + 4484579 4484636 chr11 134452384 - 70226060 70226117 2741353
+57
+
+chain 2617 chr6_mann_hap4 4683263 + 3951354 3951381 chrX 154913754 + 30529839 30529866 35092612
+27
+
+chain 2616 chr6_mann_hap4 4683263 + 3927817 3927913 chr6 170899992 - 159168046 159168142 3467812
+96
+
+chain 2596 chr6_mann_hap4 4683263 + 3973087 3973114 chr3 199501827 + 56590732 56590759 32896512
+27
+
+chain 2531 chr6_mann_hap4 4683263 + 3971895 3971925 chr3 199501827 + 180701028 180701058 25637788
+30
+
+chain 2466 chr6_mann_hap4 4683263 + 3824382 3824409 chr3 199501827 - 192093673 192093700 31748081
+27
+
+chain 2451 chr6_mann_hap4 4683263 + 3971666 3971716 chr2 242951149 + 181100921 181100971 18669842
+50
+
+chain 2440 chr6_mann_hap4 4683263 + 2572049 2572075 chr12 132349534 - 35755450 35755476 32394235
+26
+
+chain 2374 chr6_mann_hap4 4683263 + 3950266 3950291 chr1 247249719 - 157289487 157289512 35464629
+25
+
+chain 2364 chr6_mann_hap4 4683263 + 3819663 3819687 chr11 134452384 - 104747367 104747391 35468112
+24
+
+chain 2345 chr6_mann_hap4 4683263 + 2657279 2657339 chr9 140273252 + 101754649 101754709 22265309
+60
+
+chain 2313 chr6_mann_hap4 4683263 + 3890591 3890665 chr6 170899992 + 55285173 55285247 1894941
+74
+
+chain 2296 chr6_mann_hap4 4683263 + 2570274 2570347 chr10 135374737 + 81973802 81973875 17155090
+73
+
+chain 2290 chr6_mann_hap4 4683263 + 1157821 1157878 chr1 247249719 + 222604152 222604209 12152480
+57
+
+chain 2274 chr6_mann_hap4 4683263 + 3934768 3934792 chr3 199501827 + 107081622 107081646 35482673
+24
+
+chain 2265 chr6_mann_hap4 4683263 + 3887959 3887983 chrX 154913754 - 124439583 124439607 35484926
+24
+
+chain 2258 chr6_mann_hap4 4683263 + 3824852 3824876 chrX 154913754 - 132191215 132191239 25992080
+24
+
+chain 2257 chr6_mann_hap4 4683263 + 4006990 4007066 chr6 170899992 - 104582331 104582407 2576654
+76
+
+chain 2255 chr6_mann_hap4 4683263 + 4159118 4159146 chr8 146274826 + 40415014 40415042 30252789
+28
+
+chain 2253 chr6_mann_hap4 4683263 + 2653160 2653184 chr2 242951149 + 186158239 186158263 32681827
+24
+
+chain 2249 chr6_mann_hap4 4683263 + 4006455 4006480 chr5 180857866 - 144759522 144759547 4178637
+25
+
+chain 2214 chr6_mann_hap4 4683263 + 3971284 3971340 chr11 134452384 + 87181255 87181311 21919084
+56
+
+chain 2211 chr6_mann_hap4 4683263 + 3809943 3809993 chr20 62435964 - 30230318 30230368 23880964
+50
+
+chain 2210 chr6_mann_hap4 4683263 + 3835038 3835061 chr1 247249719 + 53077746 53077769 35492698
+23
+
+chain 2194 chr6_mann_hap4 4683263 + 1157606 1157646 chrX 154913754 - 101365357 101365397 11073773
+40
+
+chain 2181 chr6_mann_hap4 4683263 + 4081491 4081530 chrX 154913754 - 85175003 85175042 4116465
+39
+
+chain 2160 chr6_mann_hap4 4683263 + 3942219 3942243 chr1 247249719 - 214605983 214606007 35201144
+24
+
+chain 2156 chr6_mann_hap4 4683263 + 1145077 1145100 chr1 247249719 + 41331153 41331176 35506781
+23
+
+chain 2149 chr6_mann_hap4 4683263 + 4099822 4099870 chr9 140273252 + 102195866 102195914 4118428
+48
+
+chain 2146 chr6_mann_hap4 4683263 + 1143811 1143872 chr12 132349534 + 104221177 104221238 23825289
+61
+
+chain 2141 chr6_mann_hap4 4683263 + 4081286 4081346 chr20 62435964 - 10135341 10135401 5446947
+60
+
+chain 2127 chr6_mann_hap4 4683263 + 4045825 4045849 chr6 170899992 + 156402969 156402993 17746
+24
+
+chain 2123 chr6_mann_hap4 4683263 + 4007634 4007684 chr1 247249719 - 1324986 1325036 2693877
+50
+
+chain 2120 chr6_mann_hap4 4683263 + 3892019 3892104 chr14 106368585 + 35729289 35729374 2483709
+85
+
+chain 2099 chr6_mann_hap4 4683263 + 1196341 1196363 chr8 146274826 + 94956096 94956118 22553599
+22
+
+chain 2075 chr6_mann_hap4 4683263 + 4011497 4011566 chr6 170899992 - 138358121 138358190 21792053
+69
+
+chain 2039 chr6_mann_hap4 4683263 + 2571934 2572049 chr7 158821424 + 116148574 116148689 3252915
+115
+
+chain 2027 chr6_mann_hap4 4683263 + 3809848 3810361 chr5 180857866 - 108598115 108598712 24999557
+55 397 481
+61
+
+chain 2014 chr6_mann_hap4 4683263 + 4099976 4100031 chr3 199501827 + 188094551 188094606 22317615
+55
+
+chain 2010 chr6_mann_hap4 4683263 + 3935813 3935834 chrX 154913754 + 30529615 30529636 35529704
+21
+
+chain 2000 chr6_mann_hap4 4683263 + 1157778 1157811 chr4 191273063 + 153905795 153905828 8127682
+33
+
+chain 2000 chr6_mann_hap4 4683263 + 4158272 4158321 chr6 170899992 - 39092714 39092763 20395916
+49
+
+chain 1976 chr6_mann_hap4 4683263 + 1229873 1229899 chr9 140273252 + 92917708 92917734 26443005
+26
+
+chain 1931 chr6_mann_hap4 4683263 + 3926709 3926764 chr3 199501827 + 181243093 181243148 3766615
+55
+
+chain 1921 chr6_mann_hap4 4683263 + 4158321 4158373 chr11 134452384 + 132133410 132133462 17748702
+52
+
+chain 1919 chr6_mann_hap4 4683263 + 2511945 2511997 chr4 191273063 + 131153712 131153764 15450947
+52
+
+chain 1907 chr6_mann_hap4 4683263 + 2572521 2573169 chr12 132349534 - 49839290 49839926 3124499
+58 540 528
+50
+
+chain 1805 chr6_mann_hap4 4683263 + 3891144 3891220 chrX 154913754 + 107411806 107411882 2933427
+76
+
+chain 1798 chr6_mann_hap4 4683263 + 3870776 3870808 chr5 180857866 + 161128758 161128790 11651368
+32
+
+chain 1772 chr6_mann_hap4 4683263 + 4007367 4007430 chr16 88827254 - 2018363 2018426 2212652
+63
+
+chain 1763 chr6_mann_hap4 4683263 + 4080494 4080567 chr14 106368585 - 71004341 71004414 2917022
+73
+
+chain 1747 chr6_mann_hap4 4683263 + 2573669 2574306 chr1 247249719 + 71359925 71360557 7388765
+54 521 516
+62
+
+chain 1746 chr6_mann_hap4 4683263 + 3990700 3990741 chr6 170899992 + 88517978 88518019 3345644
+17 14 14
+10
+
+chain 1730 chr6_mann_hap4 4683263 + 2653102 2653160 chr15 100338915 + 50804927 50804985 23248991
+58
+
+chain 1696 chr6_mann_hap4 4683263 + 4006820 4006866 chrX 154913754 - 37494215 37494261 4107897
+46
+
+chain 1694 chr6_mann_hap4 4683263 + 4099748 4099799 chr1 247249719 + 46568424 46568475 18602659
+51
+
+chain 1690 chr6_mann_hap4 4683263 + 4158763 4158820 chr11 134452384 - 120264308 120264365 24918211
+57
+
+chain 1684 chr6_mann_hap4 4683263 + 3891607 3891668 chr9 140273252 - 45892574 45892635 2466690
+61
+
+chain 1664 chr6_mann_hap4 4683263 + 2656660 2656721 chr14 106368585 - 51104394 51104455 13584343
+61
+
+chain 1636 chr6_mann_hap4 4683263 + 3926463 3926504 chr15 100338915 - 30465019 30465060 3027934
+41
+
+chain 1600 chr6_mann_hap4 4683263 + 3973114 3973143 chr13 114142980 - 18785120 18785149 24380543
+29
+
+chain 1599 chr6_mann_hap4 4683263 + 3971096 3971159 chr8 146274826 + 126278291 126278354 19925893
+63
+
+chain 1591 chr6_mann_hap4 4683263 + 2511679 2511736 chr12 132349534 + 73083054 73083111 11729778
+57
+
+chain 1570 chr6_mann_hap4 4683263 + 4158461 4158521 chr12 132349534 + 40906087 40906147 15863002
+60
+
+chain 1569 chr6_mann_hap4 4683263 + 2569611 2569737 chr1 247249719 + 93626635 93626761 9616359
+126
+
+chain 1566 chr6_mann_hap4 4683263 + 3927068 3927110 chr4 191273063 - 20598961 20599003 3502725
+42
+
+chain 1557 chr6_mann_hap4 4683263 + 3927759 3927810 chrX 154913754 + 117055564 117055615 4598072
+51
+
+chain 1477 chr6_mann_hap4 4683263 + 3891945 3892006 chr10 135374737 + 87524787 87524848 2722375
+61
+
+chain 1473 chr6_mann_hap4 4683263 + 4080991 4081045 chr17 78774742 + 33000128 33000182 3754636
+54
+
+chain 1460 chr6_mann_hap4 4683263 + 3890832 3890888 chr8 146274826 + 57494812 57494868 2709746
+56
+
+chain 1455 chr6_mann_hap4 4683263 + 4007066 4007094 chr6 170899992 - 11011124 11011152 3343257
+28
+
+chain 1453 chr6_mann_hap4 4683263 + 3891391 3891437 chr8 146274826 + 51746327 51746373 3488858
+46
+
+chain 1424 chr6_mann_hap4 4683263 + 2571563 2571641 chr9 140273252 - 113447512 113447590 4199477
+78
+
+chain 1424 chr6_mann_hap4 4683263 + 3871462 3871507 chr1 247249719 - 200018115 200018160 11574863
+45
+
+chain 1406 chr6_mann_hap4 4683263 + 3890773 3890831 chr4 191273063 + 55621101 55621159 1970745
+58
+
+chain 1406 chr6_mann_hap4 4683263 + 4158521 4158575 chr1 247249719 + 49943386 49943440 15855508
+54
+
+chain 1397 chr6_mann_hap4 4683263 + 3890211 3890236 chr10 135374737 - 71340044 71340069 2299991
+25
+
+chain 1392 chr6_mann_hap4 4683263 + 3971636 3971666 chr3 199501827 - 51819316 51819346 23522768
+30
+
+chain 1373 chr6_mann_hap4 4683263 + 2511768 2511834 chr5 180857866 + 26360477 26360543 20230569
+66
+
+chain 1361 chr6_mann_hap4 4683263 + 4070248 4070282 chr4 191273063 + 53456808 53456842 4749510
+34
+
+chain 1354 chr6_mann_hap4 4683263 + 1158001 1158055 chr4 191273063 + 534307 534361 14280054
+54
+
+chain 1345 chr6_mann_hap4 4683263 + 3855264 3855317 chrX 154913754 + 62583130 62583183 22642552
+53
+
+chain 1311 chr6_mann_hap4 4683263 + 3990016 3990044 chr12 132349534 - 10940806 10940834 3119062
+28
+
+chain 1285 chr6_mann_hap4 4683263 + 2741741 2741814 chrX 154913754 - 101841552 101841726 4764485
+55 2 103
+16
+
+chain 1271 chr6_mann_hap4 4683263 + 4485264 4485308 chr2 242951149 + 42686810 42686854 6287037
+44
+
+chain 1232 chr6_mann_hap4 4683263 + 3891286 3891326 chr4 191273063 + 121886954 121886994 3320472
+40
+
+chain 1228 chr6_mann_hap4 4683263 + 4081088 4081138 chr7 158821424 + 22807318 22807368 2860523
+50
+
+chain 1216 chr6_mann_hap4 4683263 + 3886222 3886374 chr6 170899992 + 81566192 81566344 3344709
+59 17 17
+76
+
+chain 1200 chr6_mann_hap4 4683263 + 4080922 4080972 chrX 154913754 - 78005269 78005319 2937486
+50
+
+chain 1196 chr6_mann_hap4 4683263 + 2642964 2643022 chr13 114142980 - 87864434 87864492 20517842
+58
+
+chain 1192 chr6_mann_hap4 4683263 + 3871650 3871705 chr15 100338915 - 25838674 25838729 13558940
+55
+
+chain 1173 chr6_mann_hap4 4683263 + 3856498 3856532 chr11 134452384 - 32778066 32778100 22709110
+34
+
+chain 1168 chr6_mann_hap4 4683263 + 3891494 3891535 chr15 100338915 + 80079703 80079744 3327446
+41
+
+chain 1163 chr6_mann_hap4 4683263 + 3926838 3926870 chr6 170899992 + 66742660 66742692 3612231
+32
+
+chain 1163 chr6_mann_hap4 4683263 + 3887419 3887473 chrX 154913754 + 89074833 89074887 25104537
+54
+
+chain 1160 chr6_mann_hap4 4683263 + 2573343 2573371 chrX 154913754 + 56853117 56853145 21155199
+28
+
+chain 1149 chr6_mann_hap4 4683263 + 3856532 3856615 chr10 135374737 + 110407978 110408061 14842132
+83
+
+chain 1128 chr6_mann_hap4 4683263 + 2742956 2742992 chr13 114142980 - 41462025 41462061 4150569
+36
+
+chain 1122 chr6_mann_hap4 4683263 + 4080072 4080135 chr19 63811651 + 62685625 62685688 7787530
+63
+
+chain 1120 chr6_mann_hap4 4683263 + 3927728 3927759 chr20 62435964 + 16923180 16923211 7977510
+31
+
+chain 1120 chr6_mann_hap4 4683263 + 3887060 3887131 chr11 134452384 - 72766723 72766794 12188515
+71
+
+chain 1113 chr6_mann_hap4 4683263 + 2570192 2570259 chr2 242951149 - 140069145 140069212 8748780
+67
+
+chain 1096 chr6_mann_hap4 4683263 + 2643706 2643734 chr15 100338915 + 86869156 86869184 12823891
+28
+
+chain 1076 chr6_mann_hap4 4683263 + 3892300 3892346 chr11 134452384 + 14828539 14828585 2361427
+46
+
+chain 1041 chr6_mann_hap4 4683263 + 4080135 4080193 chr6 170899992 - 117620920 117620978 4257272
+58
+
+chain 1023 chr6_mann_hap4 4683263 + 4007334 4007366 chr9 140273252 + 86970417 86970449 7865338
+32
+
+chain 1010 chr6_mann_hap4 4683263 + 4082082 4082129 chr3 199501827 + 184810220 184810267 11973355
+47
+
+chain 998 chr6_mann_hap4 4683263 + 3886377 3886573 chrX 154913754 - 91757557 91757751 5295832
+36 35 33
+55 3 3
+67
+
+chain 990 chr6_mann_hap4 4683263 + 4007430 4007464 chr4 191273063 + 5326352 5326386 2516557
+34
+
+chain 984 chr6_mann_hap4 4683263 + 4072955 4073012 chr5 180857866 - 58582170 58582227 6154457
+57
+
+chain 967 chr6_mann_hap4 4683263 + 2573177 2573236 chr6 170899992 + 103362020 103362079 14394857
+59
+
+chain 965 chr6_mann_hap4 4683263 + 3891326 3891365 chr9 140273252 + 71286813 71286852 2824412
+39
+
+chain 945 chr6_mann_hap4 4683263 + 3694820 3694851 chr14 106368585 - 6650576 6650607 2401116
+31
+
+chain 927 chr6_mann_hap4 4683263 + 2572422 2572476 chr15 100338915 - 47557741 47557795 3382810
+54
+
+chain 920 chr6_mann_hap4 4683263 + 1157878 1157917 chr16 88827254 - 23604715 23604754 19693069
+39
+
+chain 898 chr6_mann_hap4 4683263 + 4081045 4081072 chr22 49691432 - 26647849 26647876 3840718
+27
+
+chain 895 chr6_mann_hap4 4683263 + 3891777 3891813 chr14 106368585 - 61283307 61283343 2761593
+36
+
+chain 893 chr6_mann_hap4 4683263 + 2570451 2570505 chr3 199501827 + 23577885 23577939 11107673
+54
+
+chain 890 chr6_mann_hap4 4683263 + 3892242 3892300 chr1 247249719 - 65356530 65356588 2061731
+58
+
+chain 880 chr6_mann_hap4 4683263 + 2570034 2570140 chr20 62435964 - 37396821 37396927 8091728
+106
+
+chain 869 chr6_mann_hap4 4683263 + 3887839 3887907 chr6 170899992 + 169492007 169492075 20963963
+68
+
+chain 868 chr6_mann_hap4 4683263 + 3891249 3891286 chrX 154913754 - 77282087 77282124 4725533
+37
+
+chain 836 chr6_mann_hap4 4683263 + 3890695 3890723 chrX 154913754 + 120843366 120843394 2304611
+28
+
+chain 836 chr6_mann_hap4 4683263 + 2570399 2570451 chr6 170899992 - 98122344 98122396 3449700
+52
+
+chain 827 chr6_mann_hap4 4683263 + 3855371 3855442 chr15 100338915 - 22701000 22701071 11814601
+71
+
+chain 815 chr6_mann_hap4 4683263 + 2572376 2572422 chr8 146274826 - 36260073 36260119 3779418
+46
+
+chain 812 chr6_mann_hap4 4683263 + 2571127 2571156 chr4 191273063 + 177039024 177039053 12879824
+29
+
+chain 785 chr6_mann_hap4 4683263 + 2569744 2569799 chr10 135374737 - 48892377 48892432 10678423
+55
+
+chain 771 chr6_mann_hap4 4683263 + 2573374 2573466 chr4 191273063 - 179199127 179199219 9189435
+92
+
+chain 767 chr6_mann_hap4 4683263 + 2511738 2511768 chr12 132349534 + 6687829 6687859 23736981
+30
+
+chain 753 chr6_mann_hap4 4683263 + 3873530 3873605 chr13 114142980 + 107345301 107345376 25181199
+75
+
+chain 746 chr6_mann_hap4 4683263 + 2572477 2572521 chrX 154913754 + 101830803 101830847 3498092
+44
+
+chain 715 chr6_mann_hap4 4683263 + 3891220 3891248 chr1 247249719 - 137161636 137161664 4268110
+28
+
+chain 711 chr6_mann_hap4 4683263 + 3892346 3892371 chr5 180857866 - 112926636 112926661 14369717
+25
+
+chain 705 chr6_mann_hap4 4683263 + 3891557 3891590 chr20 62435964 + 38686583 38686616 3341082
+33
+
+chain 701 chr6_mann_hap4 4683263 + 4158699 4158752 chr6 170899992 + 104136271 104136324 24904048
+53
+
+chain 698 chr6_mann_hap4 4683263 + 3885778 3885835 chrX 154913754 - 89052462 89052519 24703469
+57
+
+chain 694 chr6_mann_hap4 4683263 + 3890564 3890590 chr20 62435964 + 53857851 53857877 2569420
+26
+
+chain 686 chr6_mann_hap4 4683263 + 4080461 4080493 chr9 140273252 + 6612523 6612555 3647698
+32
+
+chain 684 chr6_mann_hap4 4683263 + 2569065 2569115 chr10 135374737 + 37248665 37248715 24627179
+50
+
+chain 630 chr6_mann_hap4 4683263 + 3887534 3887605 chr7 158821424 + 132658309 132658380 10507147
+71
+
+chain 626 chr6_mann_hap4 4683263 + 2571287 2571318 chr20 62435964 - 10143997 10144028 3304786
+31
+
+chain 604 chr6_mann_hap4 4683263 + 1158203 1158229 chrX 154913754 - 101148638 101148664 11583043
+26
+
+chain 598 chr6_mann_hap4 4683263 + 2573593 2573648 chr4 191273063 - 105845249 105845304 24500343
+55
+
+chain 587 chr6_mann_hap4 4683263 + 4081958 4081983 chr17 78774742 + 38379379 38379404 3048972
+25
+
+chain 582 chr6_mann_hap4 4683263 + 1229585 1229648 chrX 154913754 - 143767987 143768050 25106055
+63
+
+chain 511 chr6_mann_hap4 4683263 + 1158055 1158090 chr3 199501827 + 56593596 56593631 24560538
+35
+
+chain 500 chr6_mann_hap4 4683263 + 3810617 3810668 chr2 242951149 - 179547194 179547245 25332432
+51
+
+chain 484 chr6_mann_hap4 4683263 + 3874010 3874062 chr2 242951149 - 202196458 202196510 23986516
+52
+
+chain 477 chr6_mann_hap4 4683263 + 4080303 4080328 chr1 247249719 + 23702472 23702497 3860771
+25
+
+chain 433 chr6_mann_hap4 4683263 + 3970685 3970735 chr12 132349534 + 80047789 80047839 27634717
+50
+
+chain 409 chr6_mann_hap4 4683263 + 2572208 2572259 chr12 132349534 + 9890446 9890497 14217469
+51
+
+chain 405 chr6_mann_hap4 4683263 + 3838348 3838386 chr6 170899992 + 85325597 85325635 11867781
+38
+
+chain 400 chr6_mann_hap4 4683263 + 2570347 2570381 chr20 62435964 + 18791073 18791107 4207227
+34
+
+chain 399 chr6_mann_hap4 4683263 + 3891365 3891391 chr14 106368585 - 67199393 67199419 2293377
+26
+
+chain 392 chr6_mann_hap4 4683263 + 2573293 2573343 chr7 158821424 + 83182800 83182850 10714169
+50
+
+chain 389 chr6_mann_hap4 4683263 + 2574727 2574788 chr5 180857866 + 78276420 78276481 6835510
+61
+
+chain 320 chr6_mann_hap4 4683263 + 2572172 2572208 chrX 154913754 - 2978832 2978868 15103888
+36
+
+chain 315 chr6_mann_hap4 4683263 + 2572091 2572150 chr12 132349534 + 56700130 56700189 16626895
+59
+
+chain 314 chr6_mann_hap4 4683263 + 3838291 3838335 chr7 158821424 + 152689672 152689716 19362320
+44
+
+chain 313 chr6_mann_hap4 4683263 + 3838601 3838636 chr8 146274826 + 137657008 137657043 12505292
+35
+
+chain 281 chr6_mann_hap4 4683263 + 2568901 2568956 chr11 134452384 - 27880406 27880461 26521414
+55
+
+chain 157 chr6_mann_hap4 4683263 + 4157054 4157110 chr2 242951149 - 84321569 84321625 30149802
+56
+
+chain 327477534 chr6_mcf_hap5 4833398 + 0 4833398 chr6 170899992 + 28804582 33467620 43
+932 3 0
+804 0 1
+2406 2 0
+88370 0 6
+2011 17 17
+871 93 85
+100 12 14
+2623 33 29
+3737 1 1
+39 1 1
+3903 2 0
+844 0 1
+5198 0 1
+2452 0 1
+14547 0 1
+603 2 0
+4648 0 3
+887 2902 2902
+668 1 0
+3862 0 6
+1025 160 0
+3444 3 0
+1791 1 0
+2207 0 3
+1827 1 0
+3220 9 0
+5157 0 4
+1394 1 0
+279 0 2
+71 0 4
+163 1 1
+31 1 1
+280 8 0
+1059 0 2
+1373 40 40
+402 1 0
+642 1 3
+746 0 2
+1268 2 0
+267 0 1
+1868 1 1
+44 1 1
+8066 7328 7328
+1695 2 1
+4264 0 1
+3195 0 2
+2504 39 38
+70 1 1
+1649 1 0
+953 0 1
+295 1 1
+32 0 6
+661 4 0
+5298 1 0
+1243 1 0
+122 0 1
+6151 2 0
+1123 0 9
+2073 1 0
+611 1 0
+1053 5 5
+71 0 3
+562 11 11
+8681 53599 53599
+1476 0 3
+3442 1 1
+61 1 1
+472 1 0
+1606 1 0
+2825 1 1
+15 1 1
+2498 1 0
+1445 2 0
+3490 0 1
+31 1 1
+4168 1 0
+4249 0 3
+27 0 1
+660 1 3
+1336 2 1
+3805 1 1
+20 1 1
+2330 0 4
+782 0 3
+3397 0 3
+46 1 2
+2599 7 0
+167 0 1
+670 8 0
+686 13 15
+1313 1 1
+41 1 1
+5555 1 1
+31 1 1
+5562 0 11
+82 1 1
+1227 0 1
+1556 1 0
+817 2 0
+22 8 0
+11441 0 4
+2264 0 2
+2164 0 6
+5363 1 1
+20 1 1
+45 1 0
+1351 1 0
+1292 0 2
+6063 8 1
+3826 10 0
+7034 0 8
+1703 6 6
+72 20447 20447
+2264 0 3
+5437 5 0
+3414 35 35
+12896 0 4
+3018 1 1
+24 1 1
+2310 7 7
+11460 1 1
+28 1 1
+2157 0 4
+46 8 0
+8748 6 0
+8539 1 0
+753 1 2
+651 8 8
+7720 1 0
+2972 1 0
+6912 1 1
+26 1 1
+7721 68853 68853
+7209 1 0
+313 21 0
+2014 2 0
+631 1 1
+120 1 1
+1202 1 1
+84 0 1
+1481 10 0
+785 34 0
+493 0 2
+283 11 1
+513 67 67
+212 16 16
+1192 0 1
+3112 1 0
+25400 9 9
+6993 1 0
+675 1 0
+20032 0 3
+2544 0 318
+1507 2 0
+313 4 0
+2659 1 1
+25 1 1
+1461 4 1
+364 1 1
+33 1 1
+1003 0 1
+1656 1 1
+42 1 1
+3874 2 0
+149 0 1
+6897 0 3
+40 1 1
+1374 1 0
+5757 5 0
+1254 17 17
+2864 0 143
+4107 0 6
+5270 8989 8989
+14121 1 0
+19254 2 0
+7864 2 0
+635 1 0
+39010 1 0
+13943 1 1
+32 1 1
+509 1 1
+73 1 1
+5335 22 16
+1218 1 0
+1638 6 6
+228 1 1
+45 1 1
+2048 0 1
+463 1 0
+24243 1 1
+19 1 1
+7240 22 0
+3284 1 1
+29 1 1
+8552 0 4
+3962 7 16
+474 1 1
+31 1 1
+549 2 0
+5745 1 0
+5097 1 0
+34650 0 1
+16931 0 1
+2053 1 7
+1384 3 1
+442 3 4
+1804 1 1
+101 1 1
+1465 2 0
+1230 2 0
+3399 0 8
+743 0 1
+502 0 1
+732 0 1
+5371 0 1
+1633 6 5
+4859 0 1
+3043 0 1
+1108 0 2
+1448 1 0
+2959 10 10
+6054 0 4
+1927 18 24
+890 1 1
+16 1 0
+2617 2 0
+4921 1 0
+570 2 0
+8231 1 1
+25 1 0
+1193 0 11
+350 0 1
+4470 1 1
+41 1 1
+942 4 5
+1892 0 5
+15 1 1
+2144 1 1
+194 1 1
+938 0 1
+141 5 5
+237 3 8
+99 31 31
+53 11 0
+364 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+67 16 16
+244 1 1
+54 5 5
+929 1 1
+21 1 1
+126 0 3
+830 0 14
+56 1 1
+525 0 2
+782 15 15
+810 1 0
+272 8 8
+145 1 1
+89 1 1
+592 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 1 1
+39 1 1
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+240 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+345 1 1
+39 1 1
+504 18 18
+662 1 1
+74 1 1
+248 1 1
+34 1 1
+1507 0 10
+1051 0 2611
+680 0 1
+1537 0 19
+74 1 0
+137 50 11
+112 0 18
+24 1 1
+1927 13 13
+1082 15046 15046
+185 0 1
+70 1 1
+2835 4 4
+163 15 15
+685 0 1
+1508 1 0
+533 14 0
+441 0 13
+2121 1 1
+40 1 1
+2754 0 4
+37 1 1
+144 8 8
+1040 2 0
+28 1 1
+229 12 12
+201 13 13
+169 19 20
+118 10 12
+1257 0 2
+243 16 16
+73 1 1
+21 1 1
+201 0 14
+116 1 1
+29 1 1
+536 1 0
+1159 0 32
+23 1 1
+674 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 2
+713 7 7
+89 1 0
+293 9 8
+350 6 6
+145 1 1
+41 1 1
+681 1 1
+43 1 1
+1121 16 16
+964 17 17
+198 0 7
+105 1 1
+40 1 1
+95 13 13
+247 1 1
+19 1 1
+2044 7 8
+2512 0 15
+2982 4 0
+3135 1 2
+1698 13 13
+15862 0 1
+925 0 191
+23 15 1
+23 0 1
+25 1 1
+7717 1 1
+40 1 1
+758 1 1
+46 1 1
+5530 11 9
+3326 1 1
+37 1 1
+2148 2 1
+4594 0 4
+7923 1 1
+26 5 5
+3475 24 0
+8 1 1
+566 4 0
+141 0 1
+2078 24 24
+171 18 18
+2570 0 6
+1709 4 0
+3265 0 2
+2235 17 16
+2946 0 372
+2644 31 31
+92 1 1
+35 1 1
+705 321 0
+3157 40 40
+718 0 4
+787 1 1
+34 1 1
+927 4 4
+103 0 8
+2376 0 1
+993 1 1
+31 1 1
+2654 1 1
+44 1 1
+208 4 1
+1022 11763 11699
+85 98 98
+60 2515 8169
+103 11 11
+41 1 1
+72 4 4
+76 1 1
+70 5 5
+83 1 1
+117 1 1
+130 1 1
+44 1 1
+414 1 1
+152 1 0
+218 1 1
+161 1 0
+120 14 14
+145 1 1
+49 4 4
+72 1 1
+53 19 19
+111 2 2
+32 3 3
+554 0 1
+336 12 12
+54 24 24
+171 0 6
+90 1 1
+28 1 1
+142 16 16
+36 1 1
+428 1 1
+16 1 1
+338 1 1
+31 1 1
+294 1 1
+92 0 1
+129 13 14
+602 1 1
+112 1 1
+247 1 1
+80 1 1
+173 1 1
+44 1 5
+497 1 1
+38 1 1
+98 1 1
+130 1 1
+319 1 1
+16 1 1
+59 1 1
+82 1 1
+141 1 1
+23 1 1
+241 1 1
+26 1 1
+109 3 3
+72 0 3
+19 1 1
+510 1 1
+36 1 1
+162 2 2
+15 1 1
+145 1 1
+28 1 1
+120 0 3
+93 1 2
+24 0 9
+169 12 0
+292 9911 10000
+401 1 1
+27 1 1
+296 1 1
+120 1 1
+357 1 1
+107 2 0
+31 1 1
+83 89 0
+194 1 1
+33 1 1
+230 1 1
+142 5 5
+108 1 1
+36 1 1
+287 1 1
+19 1 1
+104 1 1
+31 1 1
+144 1 1
+212 1 1
+452 5 6
+148 1 1
+70 1 1
+137 3 3
+67 1 1
+73 22 22
+115 12 12
+142 5 5
+269 15 15
+102 6 6
+93 1 1
+82 1 1
+170 1 1
+22 1 1
+504 2 2
+60 1 1
+150 1 1
+31 1 1
+90 1 1
+15 1 0
+258 6 7
+85 1 1
+77 1 1
+123 2 2
+67 0 1
+56 2 2
+25 1 1
+71 1 1
+28 2 2
+50 1 1
+85 2 2
+66 6 6
+186 1 1
+20 1 1
+67 1 1
+25 1 1
+227 2 2
+155 1 1
+777 1 1
+33 1 2
+26 6 6
+474 1 1
+36 1 1
+151 1 1
+29 1 1
+120 1 1
+23 1 1
+736 127279 40017
+51 5 5
+45 1 1
+53 1 1
+37 1 1
+81 1 1
+369 1 1
+72 15 15
+98 1 1
+53 0 8
+67 2 0
+41 1 1
+92 1 1
+20 1 1
+283 6 6
+70 7 7
+50 1 1
+25 1 1
+225 5 1
+31 1 1
+449 2 1
+10 1 23
+64 4 4
+832 1 0
+492 1 0
+587 0 15
+1821 1 1
+22 1 0
+36 1 1
+73 1 1
+38 1 1
+318 1 1
+20 1 1
+176 13 13
+216 1 1
+17 1 1
+515 0 1
+704 0 4
+153 1 1
+44 1 1
+538 1 1
+30 1 1
+411 0 8
+419 1 1
+34 1 1
+66 15 15
+308 1 1
+49 1 1
+484 1 1
+50 10 8
+1019 17 5
+132 1 1
+50 2 1
+38 1 1
+736 0 1
+50 1 1
+50 1 1
+23 2 1
+156 0 1
+385 15 15
+207 1 1
+92 1 1
+415 1 1
+43 1 1
+52 5 5
+223 2 0
+31 4 0
+17 3 27
+88 13 1
+308 1 1
+43 2 2
+186 0 4
+153 1 1
+69 0 3
+14 1 1
+159 1 1
+92 1 1
+62 1 1
+27 1 1
+443 10 10
+77 1 1
+51 1 1
+604 1 1
+35 1 1
+703 1 1
+32 1 1
+1452 4 0
+259 1 1
+40 1 1
+130 1 1
+87 1 1
+164 105 105
+64 14 15
+87 1 1
+30 1 1
+123 2 2
+91 0 3
+95 1 1
+67 10 0
+631 1 3
+315 1 1
+31 1 1
+315 1 1
+25 3 3
+80 3 0
+45 1 1
+511 1 1
+57 1 1
+3565 0 12
+39 0 1
+5674 16 0
+1327 0 1
+7941 1 1
+26 1 1
+13472 1 1
+48 1 1
+4441 19 0
+741 0 1
+8053 0 1
+3976 1 0
+10503 0 1
+5525 0 2
+306 1 0
+3902 17 4
+3077 0 4
+207 2 0
+1984 8 0
+686 2 0
+10068 0 3
+32266 0 2
+428 0 1
+3832 0 12
+8454 1 0
+524 1 1
+59 1 1
+112 3 3
+50 1 1
+267 0 4
+1464 2 0
+1003 0 1
+4062 1 0
+3850 4 0
+4977 0 1
+2718 1 0
+1588 1 1
+30 4 0
+879 0 1
+1332 18 12
+1688 4 4
+88 1 1
+439 2 0
+209 1 0
+1322 54 54
+893 1 1
+49 1 2
+1773 1 1
+24 1 1
+540 1 1
+41 1 1
+460 1 7
+165 1 1
+45 1 1
+903 1 2
+140 0 1
+36 1 1
+2019 0 1
+657 1 1
+48 1 0
+1329 0 1
+268 1 1
+47 1 1
+336 1 1
+25 2 0
+43 1 1
+1484 1 1
+53 1 1
+1151 1 1
+42 1 1
+1870 1 1
+24 5 5
+853 0 3
+23 0 1
+326 9 9
+131 9 9
+623 0 3
+34 1 1
+809 1 1
+36 1 1
+690 2 0
+44 1 1
+285 8 7
+455 1 1
+32 1 1
+102 1 1
+47 1 1
+4338 0 1
+5273 0 4
+11552 1 0
+409 16 17
+3476 0 1
+2160 0 24
+109 1 1
+3284 0 19
+2586 2 0
+757 1 1
+22 1 1
+860 17 24
+1584 1 0
+1582 0 2
+117 1 0
+1552 3 25
+17 0 4
+16 2 0
+6 10 0
+40 9 0
+10 8 0
+10605 1 0
+4733 1 3
+370 2 0
+1305 0 1
+518 6 0
+646 13 13
+469 1 0
+1072 1 4
+404 163747 163747
+942 4 0
+68 13 1
+2539 25 19
+1982 6 0
+5362 0 9
+10293 1 1
+98 1 1
+1006 1 1
+44 1 1
+518 1 1
+26 0 4
+185 0 1
+30 1 0
+19 1 1
+599 1 1
+22 1 1
+218 1 1
+49 1 1
+362 0 1
+852 0 2
+1066 0 2
+811 21 21
+1434 1 1
+27 1 1
+2116 1 1
+25 1 1
+82 7 7
+625 0 1
+1756 4 4
+93 1 1
+26 1 1
+320 0 3
+2150 1 1
+41 1 1
+1091 2 1
+8378 0 1
+2212 0 2
+671 1 0
+4088 1 1
+34 1 1
+2520 0 1
+1933 4 3
+2567 0 5
+1677 1 1
+29 1 1
+1829 12 0
+4788 13 0
+253 2 1
+204 0 1
+128 1 0
+4271 0 1
+6896 0 1
+2766 1 0
+2234 1 1
+52 1 1
+1098 1 1
+37 1 1
+3385 22337 22337
+10967 0 4
+6064 0 1
+10170 0 8
+17213 1 0
+6908 1 0
+328 1 0
+53416 3 2
+4463 1 0
+2057 0 1
+15162 1 0
+25886 3 1
+12500 29 0
+4926 0 1
+9038 0 1
+26499 0 1
+12538 0 1
+34918 97959 97959
+758 4 0
+150 1 0
+3128 1 0
+1300 0 1
+148 1 0
+1534 0 1
+488 0 1
+429 3 5
+299 2 0
+427 7 7
+1914 14 14
+1556 1 1
+28 1 1
+1138 78 0
+409 0 1
+985 22 23
+2430 1 0
+190 8 8
+2034 3 1
+5337 42 42
+1017 1 1
+34 1 1
+485 1 0
+348 7 0
+770 1 1
+8 1 0
+22 0 13
+64 1 1
+1358 0 1
+302 0 1
+964 0 1
+610 0 1
+906 12 0
+1331 0 8
+1784 0 1
+463 0 1
+4305 0 4
+1041 1 0
+11424 3 1
+530 10174 10174
+1857 0 1
+1230 0 8
+1682 5 0
+9069 0 8
+25 1 1
+330 5 5
+76 0 1
+1306 1 1
+46 1 1
+134 19 23
+1467 1 1
+32 1 1
+449 17 0
+367 9 9
+3525 12 10
+105 7 4
+208 33 33
+1171 1 1
+24 1 1
+1156 9 13
+841 3 3
+28 1 1
+515 0 17
+1559 0 4
+1045 9 9
+1953 1 0
+31 1 1
+843 0 1
+2174 1 0
+3788 1 0
+6017 1 0
+5658 4797 4797
+413 2 0
+2735 0 1
+941 4 0
+7767 0 1
+17211 5 0
+7531 0 1
+5505 1 2
+3443 0 2
+24240 1 1
+33 1 1
+4777 4 2
+43 3 0
+1254 0 1
+16 1 1
+1411 0 4
+424 1 1
+51 1 1
+113 1 1
+34 1 1
+344 9 9
+15845 1 0
+1155 1 0
+1648 0 16
+2071 0 9
+25450 1 0
+7543 4 10
+744 1 0
+564 2 0
+16701 3 0
+9132 1 1
+49 1 1
+146 1 1
+61 1 1
+116 1 1
+41 1 1
+137 1 1
+30 1 1
+158 9 9
+136 10 13
+973 6 6
+547 1 1
+41 1 1
+164 17 17
+1053 4 4
+228 1 1
+34 1 1
+355 1 1
+113 1 1
+330 0 1
+222 1 1
+25 1 1
+267 1 1
+38 1 1
+709 2 0
+1448 0 1
+152 1 1
+46 1 1
+237 1 1
+20 1 1
+211 5 5
+88 1 1
+33 1 1
+211 1 1
+65 1 1
+516 58 58
+491 7 7
+208 13 12
+558 2 2
+28 1 1
+125 4 4
+1853 21 0
+845 6 6
+2005 0 1
+148 1 1
+36 1 1
+993 1 0
+3580 10 10
+1203 1 0
+530 5 5
+216 1 1
+32 1 1
+312 1 1
+44 1 1
+1934 14 14
+1149 0 8
+835 1 1
+29 0 1
+2324 1 1
+18 1 1
+1273 27 27
+104 1 1
+21 1 1
+53 8 8
+1631 1 1
+16 1 1
+429 8 16
+1419 23 23
+256 1 0
+40 1 1
+106 1 1
+21 1 1
+501 2 2
+40 1 1
+2249 1 1
+189 0 1
+180 14 1
+1272 17 17
+345 0 2
+1504 14 0
+1689 4 0
+3174 16 16
+607 4 34
+41 0 5
+669 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+466 1 1
+31 3 0
+321 0 1
+281 3 0
+450 1 1
+34 1 1
+498 1 1
+28 2 1
+280 0 1
+649 1 1
+47 1 1
+1002 4 0
+120 1 1
+533 7 7
+998 0 1
+75 1 1
+37 1 1
+582 19 19
+60 18 18
+4194 0 2
+216 1 1
+112 1 1
+129 4 0
+87 1 1
+160 1 1
+49 1 1
+147 18 14
+128 1 1
+37 1 1
+865 4 0
+160 1 1
+35 1 1
+1119 1 1
+13 0 3
+242 1 1
+23 1 1
+1705 0 4
+103 0 1
+1117 2 0
+67 1 1
+1825 0 1
+855 8 0
+1368 3 0
+320 1 1
+149 1 1
+97 1 1
+15 1 1
+371 1 1
+165 1 1
+61 1 1
+32 0 2
+5 1 1
+1520 1 1
+28 1 1
+367 4 0
+267 13 13
+175 1 0
+225 1 1
+45 1 1
+797 1 1
+142 1 0
+38 0 2
+318 8 7
+50 1 1
+29 1 1
+376 4 9
+548 1 1
+57 1 1
+665 4 0
+1690 17 17
+208 6 6
+398 13 13
+63 1 1
+80 1 1
+57 1 1
+61 1 1
+170 1 1
+56 1 1
+93 1 1
+106 1 1
+41 1 1
+68 12 7
+13 4 0
+68 1 1
+76 1 1
+658 11 11
+447 4 4
+385 1 1
+35 1 1
+108 1 1
+37 4 0
+304 1 1
+70 1 0
+1242 12 12
+371 50 8
+386 2 0
+29 1 1
+204 1 1
+80 1 1
+112 12 11
+315 7 7
+97 0 2
+1756 1 1
+38 1 1
+106 23 23
+125 20 0
+1226 1 0
+16 5 0
+21 1 1
+235 10 10
+181 1 1
+72 1 1
+51 5 1
+43 5 7
+485 7 7
+127 1 1
+140 1 1
+105 5 6
+18 1 1
+88 1 1
+190 1 1
+68 10 10
+323 1 1
+59 4 0
+1507 3 0
+123 1 1
+73 1 1
+137 16 16
+132 1 1
+131 2 0
+5 0 3
+76 1 1
+40 1 1
+273 9 10
+172 1 1
+76 1 1
+98 1 1
+57 1 1
+54 1 0
+16 1 1
+66 1 1
+36 1 1
+120 1 1
+77 0 1
+34 1 1
+102 1 1
+41 1 1
+126 6 7
+1059 0 1
+1067 0 12
+1292 1 0
+744 0 4
+990 2 2
+58 1 1
+45 0 1
+308 1 1
+49 0 1
+21 1 1
+700 1 0
+973 2 0
+548 0 2
+982 10 0
+242 1 1
+38 1 1
+1067 3 0
+618 7 7
+1893 44 43
+731 2 2
+49 1 1
+908 9 9
+484 0 2
+128 0 1
+174 15 18
+175 1 1
+16 1 1
+332 1 1
+22 1 1
+554 0 1
+120 1 1
+31 1 1
+351 5 0
+80 1 0
+76 1 1
+39 1 1
+1447 1 0
+1072 1 1
+43 0 4
+43 1 1
+393 0 1
+1820 6 6
+457 1 1
+18 1 1
+87 1 1
+30 1 1
+861 1 1
+20 1 1
+1057 23 23
+416 0 24
+779 1 1
+17 1 2
+37 1 1
+1675 1 1
+27 1 1
+901 0 8
+47 1 1
+262 0 3
+57 1 1
+29 0 1
+234 0 3
+45 1 1
+250 1 1
+18 1 1
+517 33 0
+117 1 1
+55 1 1
+537 1 1
+20 1 1
+671 1 1
+68 1 1
+89 1 1
+104 1 1
+172 0 1
+124 0 1
+522 0 1500
+466 5 5
+32 1 0
+171 1 1
+19 1 1
+67 1 1
+22 1 1
+654 1 1
+25 1 1
+68 1 1
+21 4 0
+1588 1 1
+66 1 1
+401 0 1
+186 1 1
+21 1 1
+168 0 1
+601 1 1
+29 1 1
+36 4 0
+37 1 1
+127 1 1
+29 1 1
+404 0 2
+710 1 1
+89 1 1
+161 16 16
+405 1 1
+39 3 3
+56 1 1
+82 1 1
+71 1 1
+37 0 4
+104 1 1
+89 1 1
+64 1 1
+102 1 1
+130 15 16
+158 8 0
+57 1 1
+731 1 1
+65 1 1
+313 1 1
+44 1 0
+52 20006 20030
+60 8 8
+61 1 1
+120 1 1
+366 1 1
+55 1 1
+121 1 1
+62 1 1
+127 1 1
+18 1 1
+142 1 1
+26 1 1
+149 1 1
+62 11 11
+550 1 1
+76 1 0
+20 1 1
+112 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+1631 1 1
+47 1 1
+244 3 3
+22 3 3
+1486 0 3
+196 6 6
+63 1 1
+70 1 1
+325 14 19
+220 0 1
+773 1 1
+35 1 1
+153 1 1
+57 1 1
+123 1 1
+45 0 1
+15 1 1
+270 1 1
+48 1 1
+101 16 16
+64 1 1
+124 1 1
+1429 25 25
+184 0 1
+4315 4 4
+1530 4 0
+1062 1 1
+43 1 1
+55 14 14
+853 12 12
+2313 13 13
+537 9 0
+1430 1 1
+48 1 1
+400 1 1
+100 1 1
+148 19 19
+152 1 1
+25 1 1
+70 1 1
+102 1 1
+158 1 1
+56 2 2
+57 1 1
+10 5 10
+24 2 0
+71 1 1
+54 1 1
+73 1 1
+85 1 1
+105 1 1
+117 2 2
+29 1 1
+92 2 2
+42 0 1
+154 1 1
+10 1 0
+47 4 5
+35 1 1
+56 1 1
+64 3 3
+67 5 5
+72 1 1
+60 1 1
+45 1 1
+82 1 1
+95 2 2
+161 1 1
+301 1 1
+67 1 0
+430 1 1
+105 10 10
+38 0 4
+386 11 11
+101 3 2
+117 0 2
+77 1 1
+481 0 2
+67 1 1
+45 1 1
+503 1 1
+34 1 1
+359 1 1
+35 1 1
+534 11 11
+1738 1 1
+26 1 1
+506 19 0
+356 1 1
+138 0 3
+1403 13 13
+1045 1 1
+24 1 1
+879 1 1
+73 1 1
+89 1 1
+42 1 1
+108 1 1
+19 1 5
+41 0 1
+4 1 1
+511 5 6
+605 1 1
+47 1 1
+73 1 1
+62 1 1
+1912 49303 50027
+638 99452 99452
+4150 1 1
+31 0 1
+6 1 1
+163 1 1
+22 1 1
+81 1 1
+27 1 1
+548 1 1
+61 1 1
+1169 1 1
+41 1 1
+6471 1 1
+62 1 1
+530 17 17
+394 1 1
+40 7 0
+57 12 12
+69 2 2
+39 1 1
+70 1 1
+22 0 3
+2796 1 1
+58 1 1
+375 25 27
+1218 1 1
+35 1 1
+85 1 1
+20 6 0
+687 1 1
+34 1 1
+355 1 1
+47 1 0
+51 69 69
+73 1 1
+48 1 1
+218 1 1
+42 1 1
+197 1 1
+41 1 1
+313 1 1
+40 1 1
+476 1 1
+29 1 1
+185 1 1
+35 1 1
+594 1 1
+24 1 1
+219 2 0
+246 0 1
+261 4 4
+43 1 1
+54 1 1
+130 1 1
+184 1 1
+201 1 1
+306 1 1
+29 5 5
+121 1 1
+31 1 1
+109 1 1
+25 1 1
+168 1 1
+19 1 1
+104 1 0
+132 1 0
+113 1 1
+30 1 1
+56 9 9
+300 1 1
+50 2 2
+96 1 1
+43 1 1
+76 1 1
+44 1 1
+197 1 1
+38 2 1
+52 0 2
+18 1 1
+99 0 9
+392 5 5
+89 1 1
+399 1 1
+35 3 4
+260 1 1
+23 1 0
+10 1 1
+70 1 1
+65 2 0
+17 0 18
+28 1 1
+208 1 1
+70 1 1
+149 0 3
+243 1 1
+55 1 1
+63 17 17
+1208 1 1
+98 1 1
+58 1 1
+43 1 1
+59 1 1
+45 1 1
+148 70 70
+209 4 4
+1242 1 1
+42 5 0
+87 1 1
+522 0 3
+305 0 1
+1379 0 2
+390 0 15
+72 1 1
+16 1 1
+270 1 0
+280 7 7
+2763 20 20
+674 10 10
+1375 8 0
+294 142 141
+145 1 1
+35 1 1
+447 16 16
+54 4 4
+680 16 16
+1123 4 4
+1075 1 1
+46 1 1
+282 1 1
+39 1 1
+860 1 1
+26 1 1
+745 0 2
+2081 2 0
+817 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+135 5 0
+1169 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+16 1 4
+1404 0 1
+450 4 0
+626 1 0
+304 1 1
+39 1 1
+564 1 1
+45 1 1
+303 2 0
+409 1 1
+18 1 0
+858 3 0
+2168 0 1
+54 22 22
+220 1 1
+48 1 1
+254 0 1
+523 0 13
+2423 18 14
+64 1 1
+30 2 2
+185 0 4
+966 16 16
+123 11 11
+531 1 1
+20 1 1
+227 1 1
+37 1 1
+636 3 4
+8239 1 1
+23 1 1
+1114 0 2
+688 0 1
+901 18 18
+4781 0 4
+815 0 1
+5069 0 5
+415 0 1
+353 0 1
+1087 9 9
+108 30 30
+144 1 0
+817 1 0
+194 10 10
+460 0 1
+327 0 1
+878 0 1
+854 0 1
+4897 0 2
+1554 1 1
+60 1 1
+278 0 1
+19 1 1
+1866 0 1
+961 0 3
+60 0 18
+2122 0 2
+19 1 1
+1232 0 2
+1641 2 0
+10831 3 2
+188 0 1
+1650 3 6
+2842 0 4
+146 2 0
+4952 0 2
+4944 1 0
+1024 0 1
+803 11423 11423
+1739 0 4
+852 5 6
+1925 15 15
+1657 1 0
+378 0 2
+968 1 0
+1174 0 4
+663 6 0
+297 0 3
+2049 0 5
+876 11 11
+12081 1 1
+33 1 1
+1932 0 1
+398 1 1
+145 1 1
+3667 0 4
+1305 0 10
+3035 1 0
+5554 6 0
+42067 0 1
+4121 2 0
+13331 4 0
+2404 8 8
+1698 0 2
+19856 4 0
+1616 0 1
+1686 0 2
+2223 0 4
+4741 12 0
+1921 0 1
+913 0 1
+3801 0 1
+2620 8 0
+12800 0 1
+2431 1 0
+158 0 1
+281 1 0
+12653 1 0
+6938 0 1
+14766 1 0
+1654 34221 34221
+3000 17 17
+689 0 3
+62 1 0
+5716 1 0
+456 1 0
+2077 2 0
+616 178 0
+14916 0 4
+672 1 1
+26 1 1
+461 1 1
+33 0 2
+16 1 1
+649 1 1
+48 1 1
+818 1 1
+21 1 1
+424 1 1
+25 1 1
+632 1 1
+39 1 1
+310 1 1
+27 1 1
+616 1 0
+17240 4 0
+3936 3 0
+3834 2 0
+426 1 0
+5704 1 1
+43 1 0
+622 0 1
+167 0 5
+1968 0 3
+258 2 0
+4089 1 0
+903 29 27
+1088 7 6
+290 3 3
+117 13 0
+2194 0 1
+191 0 1
+118 1 0
+2013 1 0
+7453 1 0
+3382 0 1
+1544 0 1
+634 0 49
+5260 0 1
+4607 1 0
+32465 1 0
+1323 1 0
+39 0 1
+5117 27143 27143
+480 9 9
+746 11 11
+29289 0 3
+99 1 1
+19 1 1
+259 1 1
+57 1 1
+105 0 1
+2134 9 9
+2299 1 1
+43 1 1
+1287 1 0
+22328 5 0
+47 8 0
+4444 2 0
+6495 0 16
+2128 0 1
+8355 0 3
+4114 0 1
+1404 0 1
+5139 0 2
+1840 2 0
+1214 6 6
+273 0 7
+653 10 10
+189 1 0
+27280 0 2
+615 1 0
+1600 0 1
+364 0 2
+1466 1 0
+6628 1 1
+110 0 1
+1422 0 1
+324 1 0
+173 0 1
+1651 1 0
+311 0 1
+10202 4 0
+3867 9 7
+19808 0 2
+4947 29 29
+1283 0 3
+14175 10 0
+29 1 1
+4509 43 43
+1259 1 0
+2089 1 2
+365 0 2
+3430 1 0
+159 0 4
+2886 28 0
+147 0 1
+1181 10 15
+206 3 4
+208 1 1
+25 1 1
+2194 1 1
+18 1 1
+3726 0 3
+34 1 1
+361 17 17
+6271 1 0
+4854 0 1
+1587 0 1
+9534 1 1
+50 1 0
+1082 1 1
+42 1 1
+639 1 0
+145 13 15
+557 11 11
+53 1 1
+61 1 1
+454 1 1
+26 1 1
+1053 1 1
+60 1 1
+51 1 1
+26 1 0
+102 1 1
+67 1 1
+71 1 1
+134 1 1
+85 1 1
+607 36 0
+58 1 1
+1266 2 0
+480 14 21
+1459 2 1
+435 15 17
+224 57380 57335
+2665 46 46
+554 0 21
+4473 2 3
+921 1 1
+47 1 1
+2605 9 3
+50 1 1
+178 1 1
+26 1 1
+316 0 2
+1120 4 0
+177 1 2
+1991 4 4
+783 8 8
+61 34 13
+121 1 1
+22 1 0
+118 1 1
+49 4 4
+217 1 1
+91 1 1
+958 0 1
+107 1 1
+31 1 1
+171 14 14
+302 0 13
+33 1 1
+108 0 4
+98 1 1
+53 1 1
+457 2 0
+529 1 1
+37 2 0
+1829 1 1
+38 1 1
+440 1 1
+82 3 4
+647 45 45
+660 1 1
+28 1 1
+1993 0 1
+373 19 19
+835 1 1
+42 1 1
+947 1 1
+36 1 0
+1055 1 1
+43 1 1
+475 1 0
+60 1 1
+127 1 1
+509 1 1
+71 1 1
+485 1 0
+26 1 1
+531 1 1
+18 1 1
+551 1 1
+18 1 1
+884 5 5
+147 53 60
+527 1 1
+26 2 2
+322 0 17
+32 2 2
+85 1 1
+45 1 1
+625 0 323
+540 0 1
+43 1 1
+266 0 2
+228 1 1
+42 1 1
+283 1 1
+92 1 1
+381 1 1
+40 1 1
+1906 0 4
+3495 0 4
+967 1 1
+76 1 1
+3236 4 4
+529 7 7
+246 4 0
+38 1 1
+156 0 6
+1466 0 2
+499 1 0
+937 1 1
+45 1 1
+421 6 0
+87 22 22
+1254 1 1
+36 0 1
+357 18 18
+391 0 1
+451 1 0
+105 1 1
+47 1 0
+255 6 6
+739 3 0
+386 1 1
+33 1 1
+281 5 0
+481 2 0
+495 1 1
+42 4 0
+219 0 1
+408 1 1
+23 1 1
+283 1 1
+25 0 1
+541 1 0
+88 2 0
+216 1 1
+29 1 1
+457 1 0
+331 9 3
+197 15 15
+228 1 0
+4 2 0
+333 0 1
+19 1 1
+1081 3 3
+35 1 1
+1211 1 1
+34 1 1
+667 0 2
+64 1 1
+78 1 1
+1519 1 1
+27 1 1
+154 14 14
+1090 1 1
+40 0 3
+35 1 1
+1355 0 4
+79 1 1
+145 1 1
+63 1 1
+70 1 1
+21 1 1
+695 1 1
+41 2 2
+564 1 1
+46 1 1
+279 4 0
+38 5 5
+3523 32 32
+545 1 1
+27 1 0
+54 15 16
+1212 0 14
+34 0 11
+787 2 0
+3691 1 0
+1843 1 1
+45 1 0
+11 1 2
+3499 1 1
+27 1 1
+1047 0 2
+1804 2 0
+1079 1 1
+17 1 1
+639 3 5
+73 1 1
+13 13 0
+66 1 1
+391 0 7
+4547 0 1
+53 9 6
+691 0 1
+989 1 1
+143 1 1
+223 0 2
+95 1 1
+1000 1 1
+41 1 1
+93 1 1
+49 1 1
+606 1 1
+48 1 1
+128 0 4
+109 1 31
+44 10 781
+62 4 0
+129 1 1
+62 1 1
+106 1 1
+247 1 1
+20 18 4
+125 1 1
+43 1 1
+909 0 2
+381 4 4
+74 1 1
+408 1 0
+1595 5 0
+3690 1 1
+64 1 1
+754 0 4
+1877 1 1
+49 1 1
+1095 11 0
+732 0 27
+3070 2 0
+1879 0 1
+572 0 8
+215 1 1
+58 1 1
+301 1 1
+42 1 1
+265 24 0
+209 11 11
+953 1 1
+42 0 5
+58 1 0
+95 1 0
+210 1 1
+27 1 1
+882 1 1
+17 1 1
+751 0 1
+24 1 1
+351 1 1
+43 3 3
+565 1 1
+15 1 1
+150 27 27
+94 1 0
+323 1 1
+23 1 1
+221 7 7
+705 15 0
+631 2 0
+64 1 1
+1577 1 1
+21 0 1
+354 0 10
+188 0 1
+283 1 1
+48 1 1
+227 1 1
+40 0 3
+1357 0 2
+1571 7 7
+1153 1 1
+93 1 1
+797 14 14
+433 8 0
+108 11 11
+140 1 1
+40 1 1
+470 1 1
+42 1 1
+1106 0 2
+84 4 4
+129 1 1
+123 1 0
+95 1 1
+82 0 3
+661 1 1
+77 1 1
+57 1 1
+62 1 1
+473 2 0
+262 6 0
+45 1 1
+49 3 0
+321 0 1
+197 2 104
+202 0 10
+92 0 4
+108 6 0
+563 14 14
+324 1 0
+205 1 1
+17 1 1
+495 0 1
+201 4 0
+14 1 1
+1080 1 1
+24 1 1
+91 24 24
+279 1 1
+95 1 1
+121 1 1
+62 1 1
+2371 1 0
+164 9 1
+655 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+1780 2 0
+742 1 1
+40 1 1
+272 1 1
+52 1 1
+1187 1 1
+23 1 1
+254 1 1
+60 1 1
+176 3 6
+463 1 1
+36 1 1
+797 1 1
+22 1 1
+395 5 2
+61 1 1
+31 3 3
+226 1 1
+59 1 1
+581 1 1
+46 1 1
+412 1 1
+23 1 0
+74 1 1
+17 1 1
+81 1 1
+24 1 1
+83 15 15
+363 1 1
+91 1 1
+383 20 20
+199 13 13
+976 1 1
+39 0 3
+161 14 15
+127 16 16
+517 1 1
+132 1 1
+167 28 28
+124 1 1
+68 0 22
+1074 0 1
+175 1 0
+1018 1 1
+90 4 4
+1034 15 15
+69 1 1
+33 1 1
+174 1 1
+56 1 1
+169 1 0
+201 1 1
+30 1 1
+58 1 1
+38 1 1
+91 1 1
+98 4 4
+65 1 1
+19 2 0
+104 6 5
+25 1 1
+218 1 1
+37 1 1
+343 110361 150022
+67 8 8
+36 0 11
+62 1 1
+107 1 1
+68 3 130
+66 4 4
+50 22 21
+98 1 1
+127 1 0
+192 1 1
+71 1 1
+52 1 1
+200 1 1
+307 0 1
+331 1 1
+97 11 11
+171 1 1
+61 1 1
+37 1 1
+156 3 0
+63 0 3
+155 4 1
+31 2 0
+232 1 1
+33 1 1
+175 2 0
+131 6 6
+1409 0 3
+180 1 1
+65 0 1
+703 1 1
+19 1 1
+254 1 1
+22 1 1
+424 1 1
+65 1 1
+532 1 1
+48 1 1
+347 0 12
+578 16 17
+965 1 1
+45 1 1
+893 57505 60106
+93 1 1
+75 808 0
+46 1 1
+221 1 1
+213 8 0
+63 1 1
+60 17 17
+53 1 1
+29 1 1
+68 8 8
+62 9 9
+51 1 1
+85 1 1
+101 1 1
+54 2 2
+116 1 1
+66 1 1
+182 1 0
+37 1 1
+134 14 14
+117 1 1
+45 1 1
+120 1 1
+47 1 1
+342 1 1
+46 1 1
+237 12 12
+107 8 8
+754 1 0
+880 1 1
+16 1 1
+491 1 1
+49 1 1
+192 1 1
+54 0 1
+19 2 2
+165 0 21
+26 1 1
+183 13 13
+72 1 1
+23 1 0
+268 14 14
+320 1 1
+55 1 1
+414 5 5
+172 0 1
+620 1 1
+18 1 1
+190 1 1
+20 0 8
+849 1 1
+29 1 1
+978 30198 30058
+159 1 1
+36 1 1
+107 1 1
+176 1 1
+154 0 5
+91 1 1
+54 1 1
+77 1 1
+239 1 1
+50 1 1
+128 1 1
+40 1 1
+173 11 11
+734 1 1
+31 1 1
+215 1 1
+108 1 1
+259 1 1
+79 1 1
+80 1 1
+47 3 1
+40 1 1
+54 1 1
+46 1 1
+118 9 9
+98 1 0
+5 11 4
+23 0 7
+84 1 1
+84 2 2
+6 0 1
+6 1 0
+110 0 7
+537 1 1
+96 1 1
+441 1 1
+101 1 1
+242 14 14
+255 16 16
+142 1 0
+345 10 10
+54 1 1
+26 1 1
+108 1 1
+83 1 1
+128 1 1
+36 1 1
+231 1 1
+37 1 1
+534 1 1
+60 1 1
+804 0 3
+43 1 1
+148 1 1
+25 1 1
+69 10 10
+76 5 5
+37 1 1
+66 0 2
+192 1 1
+60 3 0
+19 1 1
+1149 1 1
+18 1 1
+77 1 1
+32 2 0
+32 1 1
+136 1 1
+78 2 0
+1680 1 1
+39 0 1
+548 1 1
+50 1 1
+177 2 0
+340 1 1
+112 1 1
+422 10 10
+963 4 4
+329 1 9
+648 5 1
+117 1 1
+27 1 1
+574 1 0
+507 1 1
+39 1 1
+294 3 2
+549 1 1
+22 1 1
+74 0 1
+98 1 1
+65 3 3
+230 1 1
+18 1 0
+33 1 1
+51 1 1
+24 1 1
+811 1 1
+59 0 2
+8 1 1
+80 9 9
+437 14 14
+57 4 4
+588 15 15
+305 1 1
+17 1 1
+135 1 1
+50 1 1
+59 16 16
+129 1 1
+25 2 0
+12 1 1
+106 1 1
+31 1 1
+350 1 1
+47 1 1
+340 1 1
+65 1 1
+478 2 0
+714 8 7
+95 2 2
+52 2 1
+1129 1 1
+34 1 1
+1715 1 1
+87 1 1
+692 1 1
+47 0 1
+75 1 1
+2155 10 10
+1611 1 1
+22 1 1
+186 1 1
+34 1 1
+98 1 1
+47 1 1
+117 1 0
+185 1 1
+24 1 0
+98 0 2
+258 8 14
+967 1 1
+37 3 3
+502 1 1
+22 1 1
+75 0 3
+163 1 1
+40 1 1
+638 0 3
+150 1 1
+11 0 1
+29 1 1
+125 1 1
+78 1 1
+115 8 0
+1622 18 19
+1471 1 1
+30 1 1
+1580 73 73
+435 1 1
+60 1 1
+325 0 1
+254 1 1
+43 1 1
+181 14 0
+37 1 0
+47 1 1
+130 4 4
+34 1 1
+208 1 1
+39 2 2
+526 1 1
+36 1 1
+99 9 7
+20 1 1
+73 1 1
+62 1 1
+425 1 1
+43 1 1
+811 1 1
+38 1 1
+362 1 1
+49 1 1
+109 1 1
+19 1 1
+79 1 1
+29 0 1
+26 1 1
+252 1 1
+75 1 1
+467 1 1
+40 1 1
+389 13 13
+57 17 17
+544 1 1
+42 1 1
+597 0 311
+64 6 6
+568 1 1
+35 1 1
+62 1 1
+38 1 1
+79 1 0
+553 1 1
+30 1 1
+433 1 1
+16 3 0
+1133 12 12
+1503 14 14
+272 1 1
+41 1 1
+196 1 0
+571 1 1
+38 1 1
+813 18 19
+314 1 1
+22 1 1
+345 1 1
+23 3 0
+245 1 1
+129 1 1
+26 1 1
+435 1 1
+16 0 4
+323 1 1
+32 1 1
+247 1 1
+48 1 1
+778 2 0
+226 1 1
+61 1 1
+861 3 0
+471 4 0
+6220 3 0
+1351 18 18
+1560 1 0
+8099 1 0
+7388 0 5
+5386 0 1
+511 0 1
+599 0 6
+10541 11 21
+1909 16 16
+253 1 1
+16 1 1
+308 3 3
+27 1 1
+1333 0 3
+330 9 9
+600 2 0
+261 8 8
+5249 47 47
+4613 0 2
+2337 2 0
+2567 1 1
+26 1 1
+561 1 1
+48 1 1
+2440 1 1
+30 1 1
+1289 0 1
+162 1 0
+730 0 3
+663 1 0
+20 1 1
+1027 1 1
+43 1 1
+472 0 1
+219 1 1
+20 1 1
+495 1 0
+6 2 0
+1007 0 1
+169 0 10
+33 1 1
+1029 1 1
+30 1 1
+438 1 1
+39 1 1
+511 0 1
+1247 1 0
+1055 1 0
+491 1 0
+108 1 1
+48 1 1
+1324 0 1
+143 1 1
+40 1 1
+679 1 1
+45 1 1
+1036 0 1
+59 1 1
+46 1 1
+229 16 16
+149 10 10
+94 1 1
+63 1 1
+222 2 0
+55 1 1
+115 1 1
+219 15 15
+692 28 28
+159 1 1
+41 1 1
+211 1 0
+20 1 1
+1099 0 4
+28 13 12
+32 1 1
+60 1 1
+21 6 0
+178 13 15
+32 1 1
+953 1 1
+47 1 1
+174 1 1
+22 1 1
+401 0 13
+588 5 21
+288 4 4
+86 1 1
+29 0 2
+67 3 0
+641 0 1
+571 0 1
+250 1 1
+34 1 1
+255 0 2
+572 12 12
+275 6 1
+974 0 1
+578 12 12
+612 1 1
+43 1 1
+56 0 7
+1170 0 1
+477 4 3
+282 8 8
+466 0 4
+2118 5 0
+1090 0 2
+4424 1 1
+34 1 1
+4897 8 0
+2112 0 1
+2874 1 1
+21 1 1
+442 22 22
+805 0 1
+3476 10 0
+7129 3 0
+7475 0 4
+9494 2 0
+194 1 1
+49 1 1
+1349 22 22
+9662 2 0
+4856 3 0
+7447 6 6
+421 1 0
+884 6 0
+17 1 0
+3075 1 0
+14671 3 1
+3762 2 0
+601 2 0
+57 17921 17921
+1415 0 8
+42791 2 0
+100 2 0
+50 2 0
+13955 1 1
+272 1 1
+1137 1 0
+2261 16 15
+1824 1 0
+1990 1 0
+9965 0 18
+2951 6 0
+798 1 1
+30 1 1
+159 1 1
+124 1 1
+661 1 1
+31 1 1
+2632 4 4
+4024 0 16
+9373 7 7
+8626 0 1
+316 0 26
+10715 6 6
+110 1 1
+25 0 1
+3506 172081 34208
+1156 1 1
+161 1 1
+532 1 0
+698 2 0
+549 1 13
+287 1 1
+32 1 1
+1073 1 1
+22 6 0
+1829 3 923
+21 1 1
+721 1 1
+16 1 1
+1033 0 1
+10108 0 1
+10399 0 1
+14490 0 2
+3051 0 1
+6213 1 1
+26 1 1
+9064 26 26
+7722 3 0
+1957 2 0
+2288 1 0
+4470 0 4
+2115 1 0
+621 1 0
+563 0 2
+68 13 30
+160 18 19
+1807 0 2
+291 0 1
+2273 7 0
+2089 2 0
+479 1 0
+657 0 1
+772 4 0
+384 98 54
+779 0 2
+390 62 73
+1595 2 0
+1317 2 0
+5358 0 3
+2273 0 1
+597 0 8
+993 0 26
+1897 1 0
+76 0 1
+966 1 0
+2611 2 0
+1374 20 0
+831 33 33
+1574 0 2
+5096 0 3
+2404 1 1
+33 1 1
+507 4 0
+6366 0 25
+1550 0 5
+25133 1 0
+2111 0 1
+630 0 1
+784 0 1
+6989 1 0
+1116 0 1
+6270 0 1
+9520 1 0
+184 2 0
+328 1 0
+1089 1 0
+6600 0 1
+2450 1 0
+702 0 1
+5133 0 2
+3096 1 0
+315 1 0
+490 0 1
+684 9 9
+1895 3 0
+1013 0 1
+3659 1 0
+2412 1 2
+2723 4 0
+761 1 0
+22 0 1
+885 20 0
+5236 1 0
+2186 0 4
+1852 0 12
+991 0 1
+1091 0 1
+1006 1 0
+1699 0 1
+1682 1 0
+3693 1 0
+752 3 1
+497 5 6
+2292
+
+chain 61057 chr6_mcf_hap5 4833398 + 3953063 3953737 chr5 180857866 - 98127116 98127790 2061247
+526 1 1
+147
+
+chain 45613 chr6_mcf_hap5 4833398 + 2604717 2606756 chrX 154913754 + 17160000 17162038 2811400
+57 320 319
+92 373 373
+91 278 277
+94 320 320
+74 118 118
+78 42 43
+102
+
+chain 37022 chr6_mcf_hap5 4833398 + 2676816 2677228 chr7 158821424 + 107683864 107684276 3588094
+68 1 1
+54 1 1
+288
+
+chain 29722 chr6_mcf_hap5 4833398 + 1118803 1119113 chr7 158821424 + 38479558 38479868 4774007
+310
+
+chain 28137 chr6_mcf_hap5 4833398 + 3872548 3872872 chr18 76117153 - 36956533 36956857 5572699
+120 15 15
+189
+
+chain 28017 chr6_mcf_hap5 4833398 + 4025444 4025737 chr3 199501827 - 39984613 39984906 5625287
+293
+
+chain 26200 chr6_mcf_hap5 4833398 + 3998590 3999326 chr11 134452384 + 59999264 60000000 6424852
+154 126 126
+50 51 51
+57 235 235
+63
+
+chain 24804 chr6_mcf_hap5 4833398 + 1157807 1158609 chr7 158821424 - 51137320 51138288 7188387
+90 9 9
+79 101 101
+72 385 551
+66
+
+chain 21727 chr6_mcf_hap5 4833398 + 2690400 2690887 chr7 158821424 + 97232934 97233614 9179962
+159 171 400
+51 53 17
+53
+
+chain 21165 chr6_mcf_hap5 4833398 + 3891845 3892417 chr2 242951149 + 148617877 148618443 9563049
+63 162 156
+73 154 154
+120
+
+chain 20574 chr6_mcf_hap5 4833398 + 3328381 3329672 chr6 170899992 + 32089252 32090543 23930
+1291
+
+chain 19063 chr6_mcf_hap5 4833398 + 3948619 3949559 chr6 170899992 + 32821586 32822354 11222040
+175 715 543
+50
+
+chain 17270 chr6_mcf_hap5 4833398 + 3973147 3973355 chr10 135374737 - 70196080 70196288 12781660
+86 2 2
+48 5 5
+67
+
+chain 16223 chr6_mcf_hap5 4833398 + 3893015 3893224 chrX 154913754 - 4338266 4338475 13813426
+77 26 26
+106
+
+chain 15776 chr6_mcf_hap5 4833398 + 3956381 3966455 chr6 170899992 + 32827127 32836991 14253206
+50 4318 3617
+61 2558 2719
+69 660 1109
+229 767 762
+55 1248 1134
+59
+
+chain 15767 chr6_mcf_hap5 4833398 + 3201357 3201535 chr19 63811651 - 18495043 18495221 597719
+59 1 1
+45 1 1
+72
+
+chain 15397 chr6_mcf_hap5 4833398 + 4023860 4024020 chr7 158821424 + 63574132 63574292 14648759
+160
+
+chain 14519 chr6_mcf_hap5 4833398 + 3953825 3954073 chr3 199501827 + 161525390 161525638 4654449
+168 65 65
+15
+
+chain 14389 chr6_mcf_hap5 4833398 + 3863245 3863650 chr6 170899992 + 32665471 32665876 15746939
+57 86 85
+55 139 140
+68
+
+chain 13989 chr6_mcf_hap5 4833398 + 4038478 4038630 chr15 100338915 - 66378648 66378800 16209114
+152
+
+chain 13654 chr6_mcf_hap5 4833398 + 143599 143759 chr18 76117153 - 3498140 3498418 7857182
+83 1 1
+24 4 122
+48
+
+chain 12613 chr6_mcf_hap5 4833398 + 3848362 3848586 chr7 158821424 + 82112728 82112976 18070517
+51 77 101
+96
+
+chain 12612 chr6_mcf_hap5 4833398 + 3974617 3974791 chr6 170899992 - 53320727 53320901 18071926
+52 29 29
+93
+
+chain 12358 chr6_mcf_hap5 4833398 + 3995163 3995295 chr3 199501827 - 96522027 96522159 18443506
+132
+
+chain 12272 chr6_mcf_hap5 4833398 + 2612337 2612493 chrX 154913754 + 154847615 154847763 18572107
+71 1 1
+25 8 0
+51
+
+chain 12186 chr6_mcf_hap5 4833398 + 4038990 4039164 chr8 146274826 + 100984503 100984677 18706381
+68 32 32
+74
+
+chain 11876 chr6_mcf_hap5 4833398 + 2675238 2675454 chr6 170899992 + 31412979 31413204 19200916
+72 76 85
+68
+
+chain 11593 chr6_mcf_hap5 4833398 + 3844564 3844687 chr1 247249719 - 238369051 238369174 19677685
+123
+
+chain 11398 chr6_mcf_hap5 4833398 + 2686795 2686948 chr6 170899992 - 161606914 161607067 20013430
+64 22 22
+67
+
+chain 11324 chr6_mcf_hap5 4833398 + 3992779 3992926 chr6 170899992 - 138135992 138136139 20148163
+68 15 15
+64
+
+chain 10446 chr6_mcf_hap5 4833398 + 3869965 3870077 chr10 135374737 + 116791472 116791584 21828223
+112
+
+chain 9923 chr6_mcf_hap5 4833398 + 1132469 1132573 chr6 170899992 + 29984509 29984613 22990373
+104
+
+chain 9881 chr6_mcf_hap5 4833398 + 2664761 2665311 chr6 170899992 + 31313427 31313987 23083508
+72 423 433
+55
+
+chain 9817 chr6_mcf_hap5 4833398 + 3847924 3848156 chr8 146274826 + 42542364 42542493 23227154
+51 115 12
+66
+
+chain 9806 chr6_mcf_hap5 4833398 + 3846392 3846808 chr9 140273252 + 87960114 87960526 23254845
+57 294 290
+65
+
+chain 9661 chr6_mcf_hap5 4833398 + 3952556 3954131 chr6 170899992 + 104209491 104209913 3704454
+364 1153 0
+58
+
+chain 9564 chr6_mcf_hap5 4833398 + 3863653 3863818 chr6 170899992 + 32549657 32549823 23841400
+59 50 51
+56
+
+chain 9560 chr6_mcf_hap5 4833398 + 1145708 1145809 chr6 170899992 - 141000133 141000234 23851242
+101
+
+chain 9528 chr6_mcf_hap5 4833398 + 1160055 1160492 chr6 170899992 + 29878108 29878543 23937752
+59 318 316
+60
+
+chain 9472 chr6_mcf_hap5 4833398 + 3845655 3846032 chr1 247249719 - 150861000 150861377 24067468
+58 259 259
+60
+
+chain 9229 chr6_mcf_hap5 4833398 + 1293933 1294239 chr6 170899992 + 30567017 30567348 24575632
+62 194 219
+50
+
+chain 9124 chr6_mcf_hap5 4833398 + 3952955 3953063 chr3 199501827 + 1828344 1828452 9077956
+37 5 5
+66
+
+chain 9090 chr6_mcf_hap5 4833398 + 2611491 2611601 chr3 199501827 - 94209663 94209773 24799758
+53 4 4
+53
+
+chain 8464 chr6_mcf_hap5 4833398 + 2604519 2607426 chr2 242951149 + 56633977 56636883 3022124
+85 222 222
+134 2098 2097
+59 305 305
+4
+
+chain 8278 chr6_mcf_hap5 4833398 + 3861449 3861537 chr6 170899992 + 109538171 109538259 25991766
+88
+
+chain 8104 chr6_mcf_hap5 4833398 + 2618687 2620101 chr6 170899992 - 140880008 140881409 26266194
+74 1287 1274
+53
+
+chain 7774 chr6_mcf_hap5 4833398 + 2606022 2606534 chr1 247249719 + 7397644 7398156 2978583
+66 79 79
+58 214 214
+95
+
+chain 7592 chr6_mcf_hap5 4833398 + 3998745 3998829 chr8 146274826 + 68214220 68214304 9264343
+84
+
+chain 7141 chr6_mcf_hap5 4833398 + 3891766 3891845 chr12 132349534 + 113006300 113006379 12958594
+79
+
+chain 7041 chr6_mcf_hap5 4833398 + 3977312 3977387 chr4 191273063 + 139492368 139492443 28109801
+75
+
+chain 6949 chr6_mcf_hap5 4833398 + 3832393 3832466 chr6 170899992 + 32549387 32549460 28300224
+73
+
+chain 6795 chr6_mcf_hap5 4833398 + 2667263 2667335 chr6 170899992 + 31318116 31318188 28604524
+72
+
+chain 6658 chr6_mcf_hap5 4833398 + 3886931 3887001 chr5 180857866 - 20421148 20421218 28921167
+70
+
+chain 6650 chr6_mcf_hap5 4833398 + 3892813 3892896 chr11 134452384 - 10112929 10113012 19771549
+83
+
+chain 6648 chr6_mcf_hap5 4833398 + 3975186 3975255 chr12 132349534 - 72343253 72343322 28941661
+69
+
+chain 6613 chr6_mcf_hap5 4833398 + 3860999 3861069 chr1 247249719 + 37577726 37577796 29019074
+70
+
+chain 6545 chr6_mcf_hap5 4833398 + 3974547 3974617 chr9 140273252 - 54900636 54900706 21580040
+70
+
+chain 6522 chr6_mcf_hap5 4833398 + 3976253 3976322 chr15 100338915 + 41279078 41279147 29241047
+69
+
+chain 6504 chr6_mcf_hap5 4833398 + 3997726 3997795 chrX 154913754 - 101090292 101090361 29284261
+69
+
+chain 6494 chr6_mcf_hap5 4833398 + 2693655 2693723 chr6 170899992 + 30480336 30480404 29322144
+68
+
+chain 6459 chr6_mcf_hap5 4833398 + 2707667 2707736 chr6 170899992 + 31350859 31350928 29378028
+69
+
+chain 6376 chr6_mcf_hap5 4833398 + 3878588 3878655 chr1 247249719 - 291603 291670 29590708
+67
+
+chain 6368 chr6_mcf_hap5 4833398 + 2612245 2612337 chr6 170899992 - 132294381 132294479 20980271
+55 29 35
+8
+
+chain 6240 chr6_mcf_hap5 4833398 + 3861275 3861341 chr7 158821424 + 89136765 89136831 29917654
+66
+
+chain 6086 chr6_mcf_hap5 4833398 + 3886692 3886757 chr11 134452384 + 38517427 38517492 30319385
+65
+
+chain 5976 chr6_mcf_hap5 4833398 + 2710238 2710301 chr6 170899992 + 31358648 31358711 30614233
+63
+
+chain 5852 chr6_mcf_hap5 4833398 + 3892417 3892480 chr15 100338915 - 42450883 42450946 16059711
+63
+
+chain 5666 chr6_mcf_hap5 4833398 + 2692721 2692780 chr6 170899992 + 31328563 31328622 31482266
+59
+
+chain 5512 chr6_mcf_hap5 4833398 + 3860761 3860819 chr7 158821424 + 45670922 45670980 31905209
+58
+
+chain 5511 chr6_mcf_hap5 4833398 + 3953994 3954057 chr10 135374737 + 9454041 9454104 5673198
+63
+
+chain 5494 chr6_mcf_hap5 4833398 + 4010098 4010156 chr12 132349534 + 106784665 106784723 31946442
+58
+
+chain 5381 chr6_mcf_hap5 4833398 + 3848293 3848360 chr3 199501827 - 53390365 53390432 21843019
+67
+
+chain 5267 chr6_mcf_hap5 4833398 + 3861386 3861442 chr11 134452384 - 52779924 52779980 32661477
+56
+
+chain 5202 chr6_mcf_hap5 4833398 + 3975455 3975509 chr5 180857866 - 172710630 172710684 32856943
+54
+
+chain 5103 chr6_mcf_hap5 4833398 + 1145380 1145434 chr6 170899992 + 76955761 76955815 33170037
+54
+
+chain 5030 chr6_mcf_hap5 4833398 + 4010180 4010233 chr15 100338915 + 69519076 69519129 33389330
+53
+
+chain 5012 chr6_mcf_hap5 4833398 + 2695933 2695986 chr6 170899992 + 30481807 30481860 33454260
+53
+
+chain 4957 chr6_mcf_hap5 4833398 + 2608828 2608880 chr7 158821424 + 132662537 132662589 33651030
+52
+
+chain 4923 chr6_mcf_hap5 4833398 + 1157985 1158047 chr9 140273252 - 102391777 102391839 11227007
+62
+
+chain 4903 chr6_mcf_hap5 4833398 + 3886776 3886828 chrX 154913754 + 93227263 93227315 33852040
+52
+
+chain 4884 chr6_mcf_hap5 4833398 + 2690887 2690940 chr7 158821424 + 8665709 8665762 23124552
+53
+
+chain 4830 chr6_mcf_hap5 4833398 + 3870967 3871018 chr7 158821424 + 82104686 82104737 34087624
+51
+
+chain 4730 chr6_mcf_hap5 4833398 + 4037119 4037169 chr10 135374737 + 93200055 93200105 34443435
+50
+
+chain 4636 chr6_mcf_hap5 4833398 + 3953764 3953825 chr15 100338915 + 36217680 36217741 14854688
+61
+
+chain 4082 chr6_mcf_hap5 4833398 + 3861341 3861384 chr2 242951149 - 201903615 201903658 30854026
+43
+
+chain 3962 chr6_mcf_hap5 4833398 + 2605054 2607488 chr12 132349534 + 103308744 103311177 2987803
+40 116 116
+77 836 835
+44 1259 1259
+62
+
+chain 3938 chr6_mcf_hap5 4833398 + 3848731 3848772 chr12 132349534 + 106783136 106783177 34996470
+41
+
+chain 3860 chr6_mcf_hap5 4833398 + 3952301 3952346 chr3 199501827 + 112943878 112943923 15335435
+45
+
+chain 3596 chr6_mcf_hap5 4833398 + 3844515 3844564 chr19 63811651 + 37876836 37876885 21722630
+49
+
+chain 3519 chr6_mcf_hap5 4833398 + 3892776 3892813 chr10 135374737 + 82581588 82581625 28921113
+37
+
+chain 3457 chr6_mcf_hap5 4833398 + 3892907 3892997 chr5 180857866 + 79763558 79763648 18723404
+90
+
+chain 3302 chr6_mcf_hap5 4833398 + 2677228 2677268 chrX 154913754 - 17721831 17721871 3601717
+40
+
+chain 3266 chr6_mcf_hap5 4833398 + 3862147 3862182 chr9 140273252 + 83968215 83968250 35227644
+35
+
+chain 3215 chr6_mcf_hap5 4833398 + 2690311 2690345 chr13 114142980 - 34852829 34852863 33454154
+34
+
+chain 3191 chr6_mcf_hap5 4833398 + 2608477 2608530 chr16 88827254 + 57584329 57584382 22020535
+53
+
+chain 2914 chr6_mcf_hap5 4833398 + 3891647 3891703 chrX 154913754 + 119403135 119403191 11929641
+56
+
+chain 2795 chr6_mcf_hap5 4833398 + 3892480 3892522 chr15 100338915 + 56426321 56426363 16223719
+42
+
+chain 2771 chr6_mcf_hap5 4833398 + 2273985 2274017 chr16 88827254 + 61371572 61371604 11881975
+32
+
+chain 2705 chr6_mcf_hap5 4833398 + 3974669 3974698 chr5 180857866 + 34801294 34801323 21438495
+29
+
+chain 2671 chr6_mcf_hap5 4833398 + 2612185 2612244 chr9 140273252 - 60326471 60326530 21074056
+59
+
+chain 2599 chr6_mcf_hap5 4833398 + 1158047 1158085 chr7 158821424 - 126060947 126060985 11258554
+38
+
+chain 2590 chr6_mcf_hap5 4833398 + 3892269 3892297 chr5 180857866 - 137356848 137356876 18664742
+28
+
+chain 2589 chr6_mcf_hap5 4833398 + 3891454 3891482 chr11 134452384 - 49993356 49993384 29810036
+28
+
+chain 2555 chr6_mcf_hap5 4833398 + 2690245 2690311 chr18 76117153 + 25734423 25734489 18753960
+66
+
+chain 2509 chr6_mcf_hap5 4833398 + 2605481 2605558 chr3 199501827 - 153335243 153335320 3148850
+77
+
+chain 2466 chr6_mcf_hap5 4833398 + 2605403 2605466 chr2 242951149 + 186971340 186971403 6103613
+63
+
+chain 2459 chr6_mcf_hap5 4833398 + 3974791 3974822 chr14 106368585 + 48563076 48563107 22466897
+31
+
+chain 2459 chr6_mcf_hap5 4833398 + 3780767 3780793 chr17 78774742 - 42818294 42818320 32009757
+26
+
+chain 2427 chr6_mcf_hap5 4833398 + 2690989 2691048 chr3 199501827 - 193383909 193383968 24279045
+59
+
+chain 2365 chr6_mcf_hap5 4833398 + 4038809 4038866 chrX 154913754 + 103588329 103588386 22063660
+57
+
+chain 2350 chr6_mcf_hap5 4833398 + 1143959 1143987 chr9 140273252 + 98495373 98495401 22648903
+28
+
+chain 2348 chr6_mcf_hap5 4833398 + 2602541 2602596 chr7 158821424 + 35337254 35337309 23750584
+55
+
+chain 2343 chr6_mcf_hap5 4833398 + 3952502 3952527 chr11 134452384 - 60697549 60697574 22749508
+25
+
+chain 2320 chr6_mcf_hap5 4833398 + 4019609 4019634 chr19 63811651 - 56872967 56872992 35475512
+25
+
+chain 2317 chr6_mcf_hap5 4833398 + 2604190 2604320 chr15 100338915 - 72843171 72843301 3140919
+130
+
+chain 2262 chr6_mcf_hap5 4833398 + 1157783 1157807 chr19 63811651 - 5696072 5696096 21221761
+24
+
+chain 2188 chr6_mcf_hap5 4833398 + 1158201 1158258 chr1 247249719 + 222604152 222604209 12884993
+57
+
+chain 2183 chr6_mcf_hap5 4833398 + 3892590 3892636 chr7 158821424 + 113918927 113918973 16141801
+46
+
+chain 2172 chr6_mcf_hap5 4833398 + 3845632 3845655 chr3 199501827 + 38460301 38460324 24137330
+23
+
+chain 2171 chr6_mcf_hap5 4833398 + 3892683 3892706 chr13 114142980 - 13381431 13381454 25956368
+23
+
+chain 2132 chr6_mcf_hap5 4833398 + 2603254 2603380 chr1 247249719 + 93626635 93626761 5313263
+126
+
+chain 1996 chr6_mcf_hap5 4833398 + 2607152 2607223 chr3 199501827 + 178864208 178864279 4788720
+71
+
+chain 1952 chr6_mcf_hap5 4833398 + 3999028 3999070 chr2 242951149 - 218681061 218681103 8791220
+42
+
+chain 1946 chr6_mcf_hap5 4833398 + 1158400 1158475 chr1_random 1663265 - 1644029 1644104 12720667
+75
+
+chain 1930 chr6_mcf_hap5 4833398 + 3891482 3891539 chrX 154913754 + 81246238 81246295 14247869
+57
+
+chain 1927 chr6_mcf_hap5 4833398 + 2690365 2690400 chr7 158821424 - 109806767 109806802 24526345
+35
+
+chain 1921 chr6_mcf_hap5 4833398 + 4038367 4038423 chr11 134452384 - 48517870 48517926 18924823
+56
+
+chain 1856 chr6_mcf_hap5 4833398 + 1158158 1158191 chr4 191273063 + 153905795 153905828 9266241
+33
+
+chain 1833 chr6_mcf_hap5 4833398 + 2606939 2606989 chr9 140273252 + 84578242 84578292 7882125
+50
+
+chain 1827 chr6_mcf_hap5 4833398 + 3844483 3844515 chr10 135374737 - 122033518 122033550 24304365
+32
+
+chain 1796 chr6_mcf_hap5 4833398 + 2603994 2604348 chrX 154913754 + 100577502 100577856 3969599
+99 227 227
+28
+
+chain 1766 chr6_mcf_hap5 4833398 + 2690182 2690238 chr4 191273063 - 32209724 32209780 19175813
+56
+
+chain 1695 chr6_mcf_hap5 4833398 + 2604644 2604717 chr5 180857866 + 63682850 63682923 4402620
+59 4 4
+10
+
+chain 1651 chr6_mcf_hap5 4833398 + 3892522 3892590 chr11 134452384 + 18101372 18101440 12538366
+68
+
+chain 1629 chr6_mcf_hap5 4833398 + 4038630 4038657 chr2 242951149 - 84022333 84022360 21351212
+27
+
+chain 1606 chr6_mcf_hap5 4833398 + 3869684 3869743 chr4 191273063 - 166421863 166421922 24717461
+59
+
+chain 1597 chr6_mcf_hap5 4833398 + 3845427 3846126 chrX 154913754 - 128485360 128486059 24583609
+70 578 578
+51
+
+chain 1587 chr6_mcf_hap5 4833398 + 4039212 4039257 chr14 106368585 + 80426596 80426641 23776282
+45
+
+chain 1583 chr6_mcf_hap5 4833398 + 2676737 2676787 chr8 146274826 - 103361273 103361323 22022004
+50
+
+chain 1578 chr6_mcf_hap5 4833398 + 2686639 2686691 chr2 242951149 + 183623425 183623477 24278977
+52
+
+chain 1568 chr6_mcf_hap5 4833398 + 3998920 3998948 chr16 88827254 - 17543433 17543461 11021050
+28
+
+chain 1537 chr6_mcf_hap5 4833398 + 3999190 3999240 chr5 180857866 + 49878691 49878741 10672840
+50
+
+chain 1433 chr6_mcf_hap5 4833398 + 3999082 3999106 chr2 242951149 - 185977428 185977452 16089470
+24
+
+chain 1432 chr6_mcf_hap5 4833398 + 2607885 2607952 chr4 191273063 - 25455517 25455584 19723766
+67
+
+chain 1386 chr6_mcf_hap5 4833398 + 4037584 4037655 chr5 180857866 - 127160909 127160980 20252959
+71
+
+chain 1383 chr6_mcf_hap5 4833398 + 3892706 3892771 chr14 106368585 - 49729815 49729880 20850419
+65
+
+chain 1324 chr6_mcf_hap5 4833398 + 4038089 4038139 chr11 134452384 - 110737438 110737488 16281354
+50
+
+chain 1320 chr6_mcf_hap5 4833398 + 2607682 2607744 chr3 199501827 - 89080446 89080508 24774355
+62
+
+chain 1310 chr6_mcf_hap5 4833398 + 3891543 3891595 chrX 154913754 + 62583131 62583183 22867198
+52
+
+chain 1254 chr6_mcf_hap5 4833398 + 2605313 2605381 chr9 140273252 + 222427 222495 3502715
+68
+
+chain 1253 chr6_mcf_hap5 4833398 + 4038318 4038354 chr6 170899992 - 39092714 39092750 23906153
+36
+
+chain 1143 chr6_mcf_hap5 4833398 + 3998844 3998870 chr1 247249719 + 180123990 180124016 10456151
+26
+
+chain 1071 chr6_mcf_hap5 4833398 + 2603839 2603906 chr12 132349534 + 77415638 77415705 9437719
+67
+
+chain 1059 chr6_mcf_hap5 4833398 + 3952346 3952428 chr17 78774742 - 53522383 53522465 12152498
+82
+
+chain 1040 chr6_mcf_hap5 4833398 + 2603731 2603788 chr5 180857866 - 146041571 146041628 6664547
+57
+
+chain 1025 chr6_mcf_hap5 4833398 + 3892143 3892170 chr2 242951149 - 81435622 81435649 19840221
+27
+
+chain 1003 chr6_mcf_hap5 4833398 + 3731571 3731602 chr2 242951149 - 44758448 44758479 2126761
+31
+
+chain 978 chr6_mcf_hap5 4833398 + 1158258 1158286 chr6 170899992 - 112879191 112879219 17119903
+28
+
+chain 958 chr6_mcf_hap5 4833398 + 2606823 2606882 chr18 76117153 + 12161176 12161235 15243828
+59
+
+chain 919 chr6_mcf_hap5 4833398 + 2608035 2608095 chr4 191273063 + 44807134 44807194 22381057
+60
+
+chain 910 chr6_mcf_hap5 4833398 + 2604348 2604389 chrX 154913754 - 130647843 130647884 6306827
+41
+
+chain 899 chr6_mcf_hap5 4833398 + 3952444 3952502 chr9 140273252 + 66213924 66213982 10448615
+58
+
+chain 889 chr6_mcf_hap5 4833398 + 1158286 1158322 chr1 247249719 - 24894408 24894444 17913365
+36
+
+chain 857 chr6_mcf_hap5 4833398 + 4037505 4037565 chr20 62435964 - 51574691 51574751 25098794
+60
+
+chain 841 chr6_mcf_hap5 4833398 + 2603443 2603495 chr20 62435964 - 59823019 59823071 21526397
+52
+
+chain 825 chr6_mcf_hap5 4833398 + 2604460 2604519 chr7 158821424 + 140056560 140056619 5253720
+59
+
+chain 798 chr6_mcf_hap5 4833398 + 3846536 3846592 chr1 247249719 - 94337351 94337407 25194613
+56
+
+chain 791 chr6_mcf_hap5 4833398 + 2606765 2606815 chr2 242951149 + 171191285 171191335 4492406
+50
+
+chain 774 chr6_mcf_hap5 4833398 + 4038161 4038190 chr13 114142980 + 78421249 78421278 18219143
+29
+
+chain 760 chr6_mcf_hap5 4833398 + 2605737 2605796 chr12 132349534 + 56700130 56700189 25330835
+59
+
+chain 740 chr6_mcf_hap5 4833398 + 1158689 1158753 chr12 132349534 + 55464534 55464598 20832675
+64
+
+chain 725 chr6_mcf_hap5 4833398 + 2603907 2603961 chr2 242951149 + 129418481 129418535 15959343
+54
+
+chain 718 chr6_mcf_hap5 4833398 + 2608115 2608170 chr9 140273252 - 49339912 49339967 23555333
+55
+
+chain 716 chr6_mcf_hap5 4833398 + 4038745 4038797 chr16 88827254 - 38714794 38714846 22851160
+52
+
+chain 700 chr6_mcf_hap5 4833398 + 2604093 2604149 chr1 247249719 + 47033162 47033218 11748494
+56
+
+chain 697 chr6_mcf_hap5 4833398 + 2606088 2606122 chr18 76117153 + 57870219 57870253 3091588
+34
+
+chain 684 chr6_mcf_hap5 4833398 + 2603585 2603653 chrX 154913754 - 140171184 140171252 5395481
+68
+
+chain 681 chr6_mcf_hap5 4833398 + 4037371 4037428 chr8 146274826 - 64029404 64029461 24731946
+57
+
+chain 668 chr6_mcf_hap5 4833398 + 3815206 3815234 chr13 114142980 + 25366313 25366341 2606939
+28
+
+chain 607 chr6_mcf_hap5 4833398 + 2608345 2608426 chr12 132349534 + 61847837 61847918 15157322
+81
+
+chain 554 chr6_mcf_hap5 4833398 + 2607118 2607152 chr6 170899992 + 75108555 75108589 7134095
+34
+
+chain 547 chr6_mcf_hap5 4833398 + 2607779 2607829 chr11 134452384 - 79794459 79794509 15991278
+50
+
+chain 541 chr6_mcf_hap5 4833398 + 2605695 2605721 chr2 242951149 - 229173591 229173617 17449769
+26
+
+chain 537 chr6_mcf_hap5 4833398 + 2602778 2602824 chr20 62435964 + 38578434 38578480 23803873
+46
+
+chain 487 chr6_mcf_hap5 4833398 + 2603535 2603585 chr18 76117153 - 44468395 44468445 11618572
+50
+
+chain 479 chr6_mcf_hap5 4833398 + 3847219 3847270 chr8 146274826 - 91739126 91739177 25862760
+51
+
+chain 461 chr6_mcf_hap5 4833398 + 2607311 2607369 chr9 140273252 - 118104609 118104667 6129578
+58
+
+chain 456 chr6_mcf_hap5 4833398 + 2605822 2605854 chr10 135374737 + 51611354 51611386 20534292
+32
+
+chain 442 chr6_mcf_hap5 4833398 + 2602717 2602778 chr4 191273063 - 135500139 135500200 15116367
+61
+
+chain 412 chr6_mcf_hap5 4833398 + 2605854 2605905 chr12 132349534 + 9890446 9890497 14104676
+51
+
+chain 263 chr6_mcf_hap5 4833398 + 2604406 2604441 chr6 170899992 + 111492261 111492296 25439357
+35
+
+chain 227 chr6_mcf_hap5 4833398 + 2621672 2621728 chr6 170899992 - 140565854 140565910 28646895
+56
+
+chain 373682699 chr6_qbl_hap6 4611984 + 0 4611984 chr6 170899992 + 28804582 33487728 31
+932 3 0
+804 0 1
+2406 2 0
+210632 0 1
+14475 0 1
+6819 1 0
+6845 1 3
+6188 0 1
+6397 0 1
+345 1 0
+68374 2 0
+46946 7 0
+1489 1 1
+72 1 1
+2260 0 2
+10629 0 1
+19578 0 1
+1324 0 2
+5438 5 0
+2061 1 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4746 9 9
+4767 7 7
+1169 1 1
+55 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+249 43 43
+1178 0 4
+685 8 0
+48 4 0
+1701 1 1
+43 5 5
+862 18 18
+58 1 1
+66 1 1
+420 1 1
+44 1 1
+680 4 4
+1675 1 1
+83 1 1
+3082 4 0
+5467 1 1
+27 0 1
+1099 16 0
+627 12 12
+1317 6 1
+129 1 1
+25 1 1
+1397 15 15
+810 1 1
+27 1 1
+1192 2 0
+7515 4 0
+979 0 3
+3406 0 2
+2340 1 1
+20 1 1
+1139 1 1
+26 1 1
+787 0 1
+1416 3 1
+22815 4 4
+126 1 0
+38 1 1
+140 1 0
+999 0 17
+56 0 15
+11759 163412 163534
+9134 0 2
+5376 0 1
+19253 1 0
+7884 1 0
+21 0 6
+4451 1 0
+27910 1 0
+9946 0 1
+11233 1 1
+32 1 1
+2238 1 1
+20 1 1
+3659 22 16
+1218 1 0
+1638 6 6
+228 1 1
+45 1 1
+2048 0 3
+461 1 0
+20759 1 0
+3778 2 1
+1268 1 0
+1511 1 1
+42 2 0
+24 1 1
+4119 22 0
+1757 1 0
+1527 1 1
+29 1 1
+1886 1 0
+10628 12 0
+46568 1 0
+18985 0 10
+1825 3 4
+5288 0 9
+2728 1 5
+722 0 1
+502 0 1
+1025 0 1
+134 14 0
+4944 0 1
+319 1 0
+6178 0 1
+2898 0 2
+143 0 1
+1775 1 0
+2123 0 1
+2715 1 0
+4921 1 1
+47 4 0
+2882 1 0
+1362 1 0
+1233 0 8
+2134 0 1
+1042 0 1
+163 1 1
+45 1 1
+50 2 0
+64 1 1
+48 1 1
+380 0 1
+30 1 0
+30 1 1
+61 1 1
+22 1 1
+691 5 7
+310 1 1
+37 3 1
+162 1 1
+194 2 0
+36 1 1
+242 9 9
+697 33 33
+1202 1 1
+16 1 1
+528 1 1
+20 1 1
+509 0 5
+76 1 1
+21 1 1
+439 15 15
+2779 1 0
+1597 24 28
+59 12 12
+307 1 0
+516 1 0
+286 11 33
+339 5 0
+570 1 1
+37 1 1
+220 1 0
+72 1 1
+144 1 1
+48 1 1
+247 2 0
+174 9 10
+816 1 0
+940 1 1
+45 1 1
+91 3 3
+71 1 1
+291 14 14
+100 1 1
+23 1 1
+452 3 3
+229 1 1
+252 0 1
+129 15 15
+432 10 0
+85 1 1
+28 1 1
+189 2 1
+71 1 1
+52 8 0
+810 2 2
+63 1 1
+378 1 1
+26 1 1
+187 31 36
+966 1 1
+25 1 1
+91 12 12
+125 1 1
+38 1 1
+433 2 0
+596 1 1
+48 1 1
+465 4 4
+64 1 1
+20 1 1
+525 5 5
+237 3 8
+99 31 31
+53 11 0
+364 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+67 16 16
+244 1 1
+54 5 5
+929 1 1
+21 1 1
+126 0 3
+830 1 11
+59 1 1
+537 0 2
+24 1 1
+745 15 15
+810 1 0
+425 1 1
+89 1 1
+592 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 1 1
+39 1 1
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+155 155 0
+34 1 1
+50 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+345 1 1
+39 1 1
+504 18 18
+596 12 12
+54 1 1
+158 1 1
+164 1 1
+34 1 1
+626 15 15
+866 0 10
+1051 0 2611
+680 0 1
+1537 0 18
+75 1 0
+147 52 1
+119 0 12
+23 1 1
+1927 13 13
+1702 2 0
+3694 1 1
+18 1 1
+958 43 47
+246 2 0
+146 1 1
+49 1 1
+410 1 0
+667 1 1
+38 1 1
+362 7 1
+159 2 0
+515 2 0
+1026 1 1
+29 1 1
+249 0 6
+129 1 1
+33 4 0
+10 1 5
+1236 1 1
+20 1 1
+138 10 9
+448 0 3
+660 1 1
+28 1 1
+83 1 1
+51 1 1
+2659 1 1
+38 1 1
+424 0 1
+70 1 1
+820 1 1
+26 1 1
+1472 1 1
+21 1 1
+491 5 5
+163 15 15
+2194 2 0
+533 6 0
+441 1 7
+1689 1 1
+26 3 4
+879 16 16
+514 0 2
+58 1 1
+350 1 0
+769 1 1
+39 1 1
+573 0 4
+37 1 1
+144 8 8
+668 1 1
+22 1 1
+344 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+169 62 63
+74 11 15
+1255 0 2
+332 1 1
+21 1 1
+193 8 24
+34 1 1
+79 1 1
+29 1 1
+536 1 0
+308 0 1
+850 0 32
+23 1 1
+651 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 2
+713 7 7
+89 1 0
+293 9 8
+125 1 1
+31 1 1
+192 6 6
+171 17 17
+681 1 1
+43 1 1
+514 1 1
+68 1 1
+537 1 1
+35 1 1
+159 6 6
+778 2 2
+44 1 1
+168 0 7
+211 1 1
+42 1 1
+1253 1 1
+29 1 1
+320 1 1
+36 2 2
+55 1 2
+108 1 1
+33 1 1
+317 1 1
+35 1 1
+553 8 8
+386 1 1
+26 1 1
+540 1 1
+31 1 1
+65 0 1
+625 12 12
+313 0 1
+52 1 1
+22 1 1
+583 1 1
+49 1 1
+1499 3 0
+838 1 1
+19 12 0
+1129 1 1
+36 1 1
+553 8 8
+109 1 1
+45 1 1
+841 16 15
+157 1 1
+31 2 2
+204 18 19
+487 1 1
+29 1 1
+374 1 1
+67 1 1
+720 13 13
+266 10 10
+330 16 14
+413 1 1
+44 1 1
+78 6 6
+181 2 2
+36 1 1
+397 1 1
+20 1 1
+311 1 1
+48 2 2
+1495 1 1
+33 1 1
+216 4 4
+35 1 1
+194 10 10
+310 1 1
+51 1 1
+84 1 1
+101 1 1
+521 1 1
+23 1 1
+242 51 51
+600 1 1
+31 1 1
+413 15 15
+290 1 1
+49 1 1
+527 17 17
+340 12 11
+1025 1 0
+2572 1 1
+29 1 1
+397 2 5
+668 13 13
+541 1 1
+59 0 2
+6 1 1
+122 14 14
+51 1 1
+46 1 1
+187 1 1
+76 1 1
+164 0 21
+136 1 1
+12 1 1
+66 16 16
+456 37 34
+371 7 7
+48 1 1
+194 10 10
+108 1 1
+60 1 1
+122 49 50
+238 1 1
+32 0 1
+100 1 0
+72 1 0
+390 1 1
+38 1 1
+144 1 1
+27 0 4
+184 21 228
+49 1 1
+608 0 1
+152 1 1
+31 1 1
+281 8 8
+337 1 1
+45 1 1
+222 1 1
+54 1 1
+346 1 0
+44 1 1
+368 1 1
+72 1 1
+502 36 18
+63 1 1
+43 0 4
+136 1 1
+42 1 1
+80 4 4
+35 1 0
+89 1 1
+24 0 5
+829 13 13
+73 1 1
+28 14 0
+233 1 1
+42 0 3
+85 0 1
+400 1 1
+40 1 1
+538 25 25
+174 1 1
+20 1 1
+705 1 1
+26 2 2
+614 1 1
+44 1 1
+793 1 1
+16 1 1
+99 38 38
+610 5 5
+804 1 1
+29 1 1
+166 1 1
+43 1 1
+233 1 1
+44 1 1
+507 0 3
+110 8 8
+133 1 1
+31 1 1
+165 1 1
+29 1 1
+1249 1 1
+26 4 0
+56 1 1
+67 1 1
+716 1 1
+46 0 1
+16 1 1
+174 1 1
+96 1 1
+141 1 1
+39 0 4
+263 1 1
+18 1 1
+259 4 4
+38 1 1
+104 1 1
+40 1 0
+248 1 1
+18 1 1
+238 1 1
+32 1 1
+70 0 2
+16 1 1
+818 1 1
+22 4 4
+492 4 4
+1145 1 1
+46 1 1
+53 1 0
+38 1 1
+373 62 62
+1149 0 1
+20 1 1
+1294 1 1
+41 1 1
+316 4 4
+42 1 1
+218 12 12
+363 1 1
+24 1 1
+457 10 10
+414 13 13
+825 1 1
+41 1 1
+492 0 4
+1374 1 1
+18 1 1
+1145 6 4
+880 1 1
+35 1 1
+236 1 1
+67 1 1
+298 0 1
+147 14 14
+312 11 11
+613 1 1
+62 1 1
+340 1 1
+22 1 1
+1057 1 1
+57 1 1
+358 1 1
+128 1 1
+146 10 10
+490 1 1
+20 1 1
+62 1 1
+88 1 1
+293 1 1
+28 1 0
+20 1 1
+83 0 1
+90 1 1
+312 1 1
+44 1 1
+1213 1 1
+51 1 1
+467 1 1
+39 1 1
+122 14 0
+35 1 1
+485 14 14
+110 12 0
+127 1 1
+5450 0 5
+1699 9 9
+3278 0 2
+28 1 1
+2195 18 16
+521 1 1
+18 1 1
+784 18 18
+1603 0 248
+9302 4 4
+72 1 1
+30 0 2
+2359 1 1
+22 0 1
+1244 7 7
+922 2 0
+1507 1 1
+44 1 1
+208 6 1
+1022 34244 40039
+401 1 1
+27 1 1
+369 1 1
+47 1 1
+256 1 1
+27 1 1
+72 1 1
+107 2 0
+21 1 1
+93 89 0
+194 1 1
+33 1 1
+230 1 1
+142 5 5
+108 1 1
+99 1 1
+349 1 1
+31 1 1
+144 1 1
+155 1 1
+56 1 1
+46 1 1
+405 5 6
+148 1 1
+70 1 1
+137 3 3
+67 1 1
+73 22 22
+115 12 12
+142 5 5
+269 15 15
+102 6 6
+93 30 30
+224 1 1
+22 1 1
+459 1 1
+106 1 1
+150 1 1
+50 1 1
+71 1 1
+15 1 0
+258 6 7
+117 1 1
+45 1 1
+123 2 2
+49 1 1
+173 1 1
+28 2 2
+50 1 1
+158 1 1
+186 1 1
+20 1 1
+67 1 1
+25 1 1
+227 2 2
+155 1 1
+777 1 1
+33 1 2
+26 6 6
+474 1 1
+36 1 1
+151 1 1
+29 1 1
+120 1 1
+23 1 1
+736 17 17
+112 1 1
+39 1 1
+553 1 1
+69 1 1
+116 1 0
+1618 9 9
+820 11 11
+173 0 8
+405 9 9
+196 1 1
+26 1 1
+173 1 1
+27 5 1
+42 1 1
+676 17 19
+77 1 3
+65 16 16
+69 1 0
+277 1 1
+44 1 1
+72 0 3
+70 1 1
+54 1 1
+240 1 0
+31 1 1
+1192 18 19
+454 28 28
+373 1 1
+46 1 1
+1565 1 1
+53 2 2
+543 1 1
+38 1 1
+985 1 1
+27 0 1
+8 1 1
+158 0 38
+656 1 1
+104 1 1
+771 1 1
+21 1 1
+398 1 1
+16 1 2
+163 4 3
+94 1 1
+44 1 1
+172 1 0
+122 5 5
+193 16 16
+535 2 2
+17 1 0
+93 1 1
+580 1 1
+91 1 1
+141 1 1
+79 1 1
+80 13 13
+165 1 1
+129 1 1
+114 1 1
+30 1 1
+83 1 1
+35 1 1
+126 16 16
+270 0 1
+111 9 9
+151 1 1
+118 1 1
+253 1 1
+45 20456 22239
+51 5 5
+45 1 1
+53 1 1
+37 1 1
+157 1 1
+279 1 1
+233 1 1
+19 0 8
+67 2 0
+41 1 1
+102 12 12
+275 14 14
+70 1 1
+82 2 2
+224 5 1
+490 0 22
+3841 1 0
+3216 1 1
+42 1 1
+1914 0 3
+616 11 12
+144 1 1
+21 2 1
+775 1 1
+50 1 1
+50 2 2
+96 2 2
+1522 4 0
+58 0 2
+1099 1 1
+42 1 1
+3502 0 6
+255 1 1
+40 1 1
+150 0 4
+18 1 1
+589 1 1
+37 1 1
+539 5 5
+354 1 3
+128 1 1
+58 1 1
+159 1 1
+5 2 0
+21 1 1
+231 1 1
+82 3 3
+69 3 0
+549 1 1
+69 1 1
+74 9 9
+126 1 1
+47 1 1
+614 9 9
+138 1 1
+29 1 1
+681 1 1
+49 1 1
+67 1 1
+19 4 9
+234 1 1
+93 1 1
+60 4 4
+96 4 4
+76 1 1
+169 1 1
+50 1 1
+54 1 1
+312 1 1
+130 1 1
+44 1 1
+69 1 1
+80 1 1
+76 1 1
+41 1 1
+89 0 6
+45 1 0
+363 1 1
+42 1 1
+295 1 1
+43 1 1
+83 6 0
+52 0 2
+1228 1 1
+34 1 1
+3527 20 0
+1768 2 1
+2467 0 2
+101 10 0
+129 1 1
+37 1 1
+121 1 1
+25 1 1
+161 1 0
+97 1 1
+124 1 0
+178 1 1
+34 1 1
+54 1 1
+38 1 2
+670 1 1
+45 1 1
+874 1 1
+40 1 1
+59 0 1
+59 4 4
+316 1 1
+178 1 1
+103 1 1
+61 1 1
+220 63 63
+296 1 1
+33 1 1
+185 12 12
+269 1 1
+84 1 1
+864 15 15
+241 1 0
+79 3 3
+161 1 1
+48 1 1
+539 1 1
+44 1 1
+357 1 1
+37 1 1
+436 1 1
+59 1 1
+71 1 1
+261 1 1
+289 1 1
+47 1 1
+95 12 12
+97 4 4
+27 1 1
+100 1 1
+16 1 1
+101 1 1
+33 1 2
+481 1 1
+42 1 1
+206 7 7
+56 12 12
+179 10 10
+80 1 1
+41 1 1
+251 1 1
+306 1 1
+80 2 0
+4 94 0
+433 1 1
+23 1 1
+107 1 0
+265 1 1
+49 1 1
+282 1 1
+43 1 1
+865 7 7
+60 1 0
+108 1 1
+24 1 1
+134 1 1
+32 1 0
+158 0 2
+1040 1 1
+42 1 1
+737 1 0
+790 1 1
+9 2 1
+11 1 1
+129 1 1
+23 1 1
+894 1 1
+43 3 3
+854 1 1
+23 0 1
+23 2 0
+26 1 1
+395 0 15
+403 5 5
+14 1 1
+2454 1 1
+76 1 1
+170 1 1
+18 1 1
+574 4 0
+291 1 1
+47 1 1
+786 19 0
+88 10 11
+48 1 1
+58 1 1
+28 1 1
+504 0 2
+1276 1 1
+28 1 1
+975 1 0
+3231 1 0
+865 1 1
+39 1 1
+1604 1 1
+56 9 0
+1037 0 1
+510 1 1
+49 1 1
+1253 1 1
+19 1 1
+1078 3 0
+221 1 1
+21 1 0
+899 0 4
+466 1 1
+38 1 1
+297 0 3
+730 19 6
+1043 1 1
+49 1 1
+273 0 1
+708 1 0
+364 14 13
+58 1 1
+74 1 1
+2563 4 0
+531 1 1
+19 1 1
+1944 5 0
+163 6 7
+1206 0 2
+718 1 1
+41 7 0
+1795 13 13
+1390 1 0
+2933 0 16
+540 1 1
+14 1 1
+167 1 0
+897 17 4
+1208 1 0
+1307 1 1
+20 1 1
+540 0 10
+203 2 0
+44 1 1
+298 1 0
+87 11 10
+491 14 8
+991 1 1
+74 6 0
+179 1 1
+34 1 1
+448 10 0
+1688 102 81
+131 1 1
+49 2 1
+2161 30 30
+203 1 0
+89 1 0
+492 1 1
+30 1 1
+1212 3 0
+990 1 1
+38 1 1
+780 1 0
+191 1 1
+47 6 6
+393 1 1
+41 1 1
+259 1 0
+941 1 1
+20 1 1
+185 0 6
+165 0 16
+420 3 1
+130 1 1
+31 1 1
+253 18 18
+720 16 18
+1257 3 0
+986 0 4
+3311 1 1
+26 1 1
+556 0 4
+120 0 1
+1273 1 1
+20 1 1
+4311 0 3
+15 1 1
+2531 17 17
+3334 5 5
+295 1 1
+45 1 1
+94 1 1
+85 0 1
+1603 16 16
+489 1 1
+34 1 1
+1436 1 1
+47 1 1
+273 7 0
+153 0 5
+283 12 12
+619 1 1
+36 0 4
+225 1 1
+23 1 1
+553 5 0
+2334 1 1
+49 1 1
+350 1 1
+31 1 1
+1436 1 1
+46 1 1
+91 4 19
+468 0 1
+46 1 1
+923 37 37
+531 0 4
+426 0 1
+1144 1 2
+1131 1 1
+20 1 1
+1533 16 0
+3103 0 1
+25 1 1
+4034 12 12
+346 0 1
+943 1 0
+524 1 1
+20 1 1
+151 3 3
+144 1 1
+189 1 7
+750 1 0
+695 1 0
+1003 0 2
+9710 0 1
+3177 0 1
+8990 0 1
+2268 1 1
+35 0 10
+8205 1 0
+3193 1 1
+76 1 1
+10955 0 1
+22875 0 20
+2417 1 0
+998 0 13
+4236 8 0
+4845 0 2
+64 40 34
+10941 1 1
+40 1 1
+4759 0 6
+12084 0 3
+3052 0 4
+2989 1 0
+13523 1 3
+16170 1 0
+11761 0 3
+3912 3 0
+6620 0 7
+7633 3 0
+419 2 0
+10690 5 24
+10798 0 1
+296 0 1
+1770 4 0
+374 0 4
+230 16 16
+7468 1 0
+1229 1 0
+3061 1 0
+5818 1 0
+2415 12 9
+2056 0 1
+955 4 0
+20022 0 1
+4418 2 1
+2375 0 4
+2086 1 1
+32 1 1
+1225 1 0
+857 2 0
+1154 0 1
+4667 1 0
+170 0 3
+2376 0 1
+503 37 37
+2259 10 10
+1512 4 0
+68 9 1
+2170 1 1
+47 1 1
+318 2 0
+19 0 6
+14527 1 1
+33 1 1
+3080 1 1
+23 1 1
+1645 6 6
+231 0 1
+2136 2 0
+6222 0 1
+830 1 1
+24 1 1
+8326 1 0
+2939 1 0
+3959 0 2
+3746 0 2
+1011 1 1
+34 1 1
+7443 0 1
+688 2 0
+574 1 1
+29 1 1
+1799 13 1
+4074 2 0
+136 79 79
+528 19 0
+253 0 1
+204 1 0
+129 2 0
+811 1 1
+38 1 1
+2347 52 0
+4634 1 0
+856 14 14
+159 34 38
+855 1 1
+28 1 1
+1255 1 1
+36 1 1
+97 0 1
+58 1 1
+1708 1 1
+48 1 1
+958 15 0
+3371 1 1
+37 1 1
+4267 0 13
+1061 0 1
+272 0 26
+8 1 15
+25 0 2
+112 2 0
+26 4 32
+4090 0 1
+3270 1 1
+17 1 1
+2822 0 1
+6206 1 0
+2318 0 2
+1504 0 1
+6189 3 0
+396 22 12
+918 0 1
+2340 1 1
+33 1 1
+326 1 1
+80 1 1
+205 3 2
+81 8 17
+2671 0 1
+1099 0 1
+144 1 1
+29 0 1
+2097 0 3
+24 3 0
+1207 4 4
+45 1 1
+757 0 5
+1926 1 1
+40 1 1
+2657 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+754 0 4
+17 3 0
+1027 3 0
+428 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+6611 0 3
+1575 4 5
+36 1 1
+99 2 0
+700 0 2
+151 0 1
+467 11 11
+272 0 3
+40 1 1
+2428 0 1
+750 2 0
+473 0 2
+421 1 1
+34 1 1
+1575 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+11881 1 1
+30 1 1
+4406 2 0
+183 1 1
+9871 0 1
+906 3 0
+887 1 1
+80 1 1
+3115 0 1
+1037 1 0
+5866 0 2
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 3 0
+700 1 1
+2469 1 0
+1751 0 1
+910 3 0
+691 0 1
+5793 0 1
+26407 1 0
+672 0 1
+19269 1 1
+28 0 6
+1371 29 0
+494 2 0
+20417 1 0
+18633 0 1
+601 1 0
+319 0 1
+6820 1 0
+5718 0 2
+17894 1 0
+4272 1 0
+4967 3 1
+290 1 0
+2447 1 0
+740 1 9
+9299 0 18
+7427 1 0
+8151 2 1
+673 1 0
+3453 0 1
+149 0 1
+611 0 4
+4669 0 4
+176 1 1
+3229 0 1
+1092 2 0
+159 1 0
+4480 0 2
+4019 0 1
+1451 22 23
+816 1 0
+8701 1 1
+23 1 1
+1796 2 0
+5015 6 1
+1383 8 0
+2368 1 1
+31 1 0
+1883 3 0
+335 0 1
+4157 0 1
+561 4 0
+1538 1 1
+61 0 1
+159 0 2
+3362 4 0
+3333 1 1
+46 1 1
+2321 7 6
+150 1 0
+5972 0 2
+840 0 2
+55 1 1
+28 1 1
+1154 0 2
+650 0 4
+30 0 4
+1100 10 11
+4343 6 0
+1663 4 0
+150 1 0
+3128 1 0
+1449 1 0
+2023 0 1
+428 3 6
+299 2 0
+427 7 7
+1914 14 14
+1273 7 7
+1444 72 0
+423 0 4
+969 23 22
+2430 1 0
+190 8 8
+2034 3 1
+5337 42 42
+1017 1 1
+34 1 1
+485 1 0
+348 7 0
+770 1 1
+28 0 13
+1425 0 1
+302 0 1
+659 12 12
+293 0 1
+610 0 1
+906 12 0
+1331 0 6
+1686 26 26
+74 0 1
+463 0 1
+4305 0 4
+1041 1 0
+11424 3 1
+13797 0 8
+166 0 1
+1510 5 0
+9069 0 8
+25 1 1
+332 5 3
+76 0 1
+1306 1 1
+46 1 1
+134 19 23
+1467 1 1
+32 1 1
+449 17 0
+367 9 9
+3525 12 10
+91 3 0
+226 33 33
+1171 1 1
+24 1 1
+1156 9 13
+843 1 1
+28 1 1
+515 0 17
+1559 0 4
+1045 9 9
+1953 1 0
+31 1 1
+843 0 1
+2174 1 0
+3788 1 0
+2001 0 1
+2400 0 1
+1614 1 0
+8167 0 1
+2700 2 0
+2735 0 1
+8708 0 3
+448 1 1
+22 1 1
+2215 1 1
+32 1 1
+2413 14 14
+142 1 0
+789 1 1
+45 1 1
+154 1 1
+25 1 1
+465 1 1
+45 6 4
+541 1 1
+42 1 1
+1339 5 6
+391 1 1
+20 0 1
+251 1 1
+22 1 1
+561 0 2
+78 3 0
+1718 1 1
+12 1 1
+1042 1 1
+38 1 1
+301 14 0
+222 10 10
+436 10 10
+1564 1 1
+17 1 1
+1752 20 0
+1561 135 0
+58 0 45
+245 101 11
+46 90 0
+150 0 270
+54 180 0
+2130 12 12
+1630 1 1
+26 1 1
+189 0 14
+296 2 0
+809 2 0
+17 20 0
+665 0 40
+236 1 1
+44 1 1
+352 1 1
+25 1 1
+554 6 6
+850 1 1
+33 1 1
+809 3 13
+1832 7 9
+468 1 1
+21 1 1
+951 1 1
+22 1 1
+219 17 18
+733 0 14
+215 2 2
+36 1 1
+301 1 1
+22 1 1
+241 1 1
+52 0 1
+47 1 1
+72 1 1
+109 1 1
+129 1 1
+28 1 1
+174 8 8
+683 3 0
+1190 285 0
+439 13 13
+927 12 0
+557 17 17
+932 3 1
+27 1 1
+166 1 1
+19 1 1
+406 1 1
+48 3 3
+137 1 0
+161 6 6
+884 2 0
+58 1 1
+107 1 1
+150 14 14
+522 1 1
+28 1 1
+945 4 4
+34 1 1
+472 0 2
+203 0 1
+281 1 1
+46 1 1
+1130 1 0
+232 17 17
+510 1 1
+33 1 1
+62 10 10
+1501 1 1
+20 1 1
+573 1 1
+29 1 1
+928 0 3
+304 1 1
+41 1 1
+160 1 1
+58 1 1
+656 1 1
+40 4 0
+108 6 6
+321 1 1
+14 0 16
+91 1 1
+184 1 1
+43 8 3
+180 1 1
+68 1 1
+144 1 1
+27 1 0
+17 1 1
+212 0 1
+212 1 1
+34 1 1
+115 1 1
+41 1 1
+407 10 10
+200 1 1
+44 2 0
+187 2 0
+146 1 1
+17 1 1
+122 4 4
+73 1 0
+56 1 1
+155 1 17
+80 15 15
+458 1 1
+16 3 3
+343 1 1
+111 1 1
+201 14 14
+157 12 12
+346 0 2
+382 4 0
+35 1 1
+937 0 1
+246 25 0
+52 0 1
+419 0 1
+165 1 0
+75 24 3
+297 1 1
+38 1 1
+5066 1 0
+4922 7 9
+2488 14 14
+2241 1 1
+67 4 4
+39 1 0
+547 1 1
+43 1 1
+524 3715 901
+1796 4 2
+128 29 29
+415 1 1
+18 1 1
+367 0 89
+1600 0 6
+2175 0 5
+606 14 14
+519 1 0
+540 1 1
+40 1 1
+568 2 0
+165 1 2
+31 1 1
+259 1 1
+41 1 1
+1106 40 62
+818 1 1
+42 1 1
+565 1 1
+44 1 1
+571 10 8
+61 1 1
+28 1 1
+233 2 0
+33 28 0
+53 1 1
+37 1 1
+75 0 396
+156 1 0
+473 0 4
+421 1 1
+35 1 1
+2132 1 1
+80 0 2
+544 9 9
+152 2 1
+33 1 1
+2977 0 1
+164 22 0
+149 1 0
+534 1 1
+36 1 1
+113 1 1
+15 1 1
+661 1 1
+48 1 1
+1987 1 0
+34 1 1
+444 1 1
+45 1 1
+65 1 1
+67 1 1
+210 1 1
+68 1 1
+55 1 1
+47 1 1
+169 1 1
+64 1 1
+109 0 6
+77 2 32
+6 0 5
+67 0 1
+7 16 0
+51 12 0
+36 0 12
+700 1 1
+33 1 0
+49 0 2
+450 0 1
+98 4 0
+489 32 0
+63 5 1
+78 7 7
+538 17 17
+1269 1 0
+841 1 1
+43 1 1
+1257 49 49
+698 1 1
+41 1 1
+86 0 4
+5 1 0
+36 1 1
+573 2 1
+297 1 0
+85 1 1
+30 1 1
+1041 1 0
+12 1 1
+392 33 12
+515 5 6
+583 1 1
+33 1 1
+616 16 16
+1052 0 11
+39 1 1
+184 1 1
+67 1 1
+102 7 7
+58 0 1
+307 1 1
+56 0 3
+918 2 0
+1295 0 1
+832 1 1
+28 1 1
+272 1 1
+82 1 1
+56 1 0
+976 6 6
+2015 0 3
+84 9 9
+130 13 17
+564 10 15
+154 1 0
+438 10 10
+38 0 5
+2141 1 1
+25 1 1
+73 10 10
+70 5 5
+132 1 1
+52 1 1
+599 1 1
+46 1 1
+279 1 1
+18 1 1
+239 2 0
+383 6 0
+224 0 1
+321 3 0
+8 16 0
+1775 1 1
+18 2 0
+575 16 16
+60 1 1
+16 1 1
+1247 2 0
+173 3 0
+41 1 1
+57 8 8
+285 2 0
+672 1 1
+44 1 1
+106 0 1
+148 1 1
+49 3 0
+146 5 11
+91 1 1
+79 1 1
+94 1 1
+101 1 1
+88 16 16
+117 1 1
+15 1 1
+58 1 1
+93 1 1
+140 1 0
+326 1 1
+44 1 1
+160 1 1
+23 1 1
+481 14 14
+181 4 4
+72 1 1
+25 1 1
+88 1 3
+36 0 12
+92 1 1
+56 10 0
+13 0 1
+66 1 1
+141 2 0
+65 1 1
+367 0 2
+610 1 1
+22 1 1
+150 1 1
+85 1 1
+109 1 1
+167 3 1
+23 1 0
+26 1 1
+74 1 1
+33 1 1
+176 1 1
+25 2 2
+193 42 43
+377 0 5
+249 1 1
+69 1 1
+98 1 1
+62 1 1
+62 1 2
+74 0 1
+68 1 1
+438 1 1
+64 1 1
+47 0 8
+125 3 0
+75 5 5
+45 1 1
+197 1 1
+27 1 1
+116 13 13
+218 15 20
+1107 16 19
+73 1 1
+25 1 1
+199 1 1
+60 1 1
+994 1 1
+43 0 1
+18 1 1
+1215 18 18
+340 1 1
+34 1 1
+1358 8 8
+1726 4 4
+193 82 82
+263 1 1
+18 1 1
+411 19 19
+175 1 1
+49 1 1
+146 1 1
+61 1 1
+116 1 1
+41 1 1
+137 1 1
+30 1 1
+158 9 9
+136 10 13
+349 8 8
+468 1 1
+44 1 1
+862 17 17
+813 1 1
+24 1 1
+214 10 4
+228 1 1
+34 1 1
+101 12 12
+242 1 1
+69 1 1
+185 1 1
+24 1 0
+164 0 1
+222 1 1
+25 1 1
+297 10 10
+1171 1 0
+182 1 1
+35 1 1
+2335 83 83
+491 7 7
+208 13 12
+298 1 1
+65 1 1
+193 2 2
+28 1 1
+125 4 4
+95 7 7
+566 1 1
+40 1 1
+118 0 1
+318 1 0
+374 1 1
+58 1 1
+143 1 1
+74 1 1
+53 21 0
+81 1 1
+45 1 1
+138 15 16
+180 1 1
+62 1 1
+661 1 1
+48 1 1
+1463 1 0
+156 0 1
+148 1 1
+19 1 0
+17 1 1
+1927 4 0
+1469 14 14
+466 0 1
+3098 0 1
+1141 2 3
+743 14 14
+79 1 1
+22 1 1
+362 0 1
+682 16 9
+275 0 4
+462 1 1
+76 1 0
+47 1 0
+13 0 8
+331 0 4
+130 1 1
+31 0 3
+1554 1 1
+43 1 1
+224 1 1
+49 1 1
+159 3 0
+1064 27 27
+104 1 1
+21 1 1
+222 2 2
+49 1 1
+1397 1 1
+37 1 1
+414 0 2
+695 1 1
+31 1 1
+742 1 1
+21 1 1
+230 3 2
+42 1 1
+68 1 1
+37 1 1
+703 0 3
+2216 1 1
+82 1 0
+1430 1 1
+23 1 1
+1867 13 0
+35 1 1
+137 16 16
+1500 4 0
+4546 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+498 3 0
+321 0 1
+281 3 0
+414 1 1
+70 1 1
+284 1 0
+214 1 1
+28 1 1
+280 1 0
+650 1 1
+47 1 1
+1030 1 1
+91 1 1
+6520 5 5
+478 1 0
+76 1 1
+2771 0 3
+1930 0 4
+2915 1 1
+20 1 1
+413 1 0
+1844 11 11
+133 0 6
+569 10 10
+110 12 12
+184 0 3
+228 1 1
+43 2 2
+51 14 13
+1499 1 0
+12 1 1
+378 1 1
+49 1 1
+424 1 0
+1131 1 1
+80 0 1
+821 2 9
+311 1 6
+247 1 1
+86 1 1
+1850 1 1
+26 1 1
+498 1 1
+34 1 1
+688 5 9
+44 1 1
+369 1 1
+69 1 1
+156 2 0
+83 1 1
+128 1 1
+50 9 9
+249 1 1
+70 0 1
+624 2 0
+74 2 1
+300 1 1
+26 1 1
+240 4 0
+1705 1 1
+52 1 1
+231 29 24
+378 2 0
+236 1 1
+76 1 1
+116 9 12
+380 0 6
+43 1 1
+384 15 15
+1414 5 0
+225 0 2
+1234 1 0
+29 1 1
+235 10 10
+227 1 1
+77 4 0
+43 5 9
+485 7 7
+380 10 0
+46 1 0
+90 1 1
+161 1 1
+401 1 1
+58 1 1
+2127 3 0
+186 20 20
+323 5 5
+47 1 1
+236 1 1
+31 0 2
+1692 13 14
+202 0 3
+77 1 1
+44 1 1
+411 12 11
+317 0 2
+599 39 39
+391 1 0
+273 1 0
+744 0 4
+703 1 1
+20 1 1
+198 3 0
+158 1 1
+14 4 0
+27 12 0
+282 1 1
+32 4 0
+740 1 0
+327 1 1
+105 1 1
+146 16 16
+101 1 0
+21 1 1
+232 1 1
+33 2 0
+12 1 1
+189 1 1
+30 2 2
+544 1 1
+153 1 1
+586 5 0
+1351 21 0
+446 1 1
+32 1 1
+136 7 7
+1147 12 12
+734 44 43
+701 1 1
+29 2 2
+154 12 12
+191 1 1
+55 1 1
+28 0 1142
+172 15 18
+525 1 1
+22 1 1
+355 10 10
+50 0 8
+252 1 1
+31 1 1
+354 6 5
+148 15 15
+407 1 1
+42 1 1
+275 0 1
+737 5 9
+1432 1 1
+39 1 1
+84 0 2
+77 7 7
+919 7 1
+815 1 1
+45 1 1
+487 1 1
+66 1 1
+2379 0 24
+779 1 1
+18 1 0
+2653 4 0
+34 1 1
+191 1 1
+35 1 1
+1174 12 0
+2497 25 1525
+447 8 0
+3268 1 0
+946 1 0
+2277 0 2
+1446 1 1
+77 1 1
+313 1 1
+44 1 0
+52 19983 20030
+61 7 7
+61 1 1
+120 1 1
+366 1 1
+55 1 1
+121 1 1
+62 1 1
+78 1 1
+48 1 1
+161 1 1
+26 1 1
+191 1 1
+20 11 11
+550 1 1
+76 1 0
+20 1 1
+112 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+83 1 1
+46 1 1
+1500 1 1
+81 1 1
+210 1 1
+26 1 1
+713 1 1
+48 1 1
+723 0 3
+196 6 6
+62 2 2
+32 1 1
+606 1 2
+357 1 1
+38 292 0
+589 1 1
+30 1 1
+714 8 8
+639 1 1
+20 1 1
+1068 0 1
+571 1 1
+49 1 1
+436 0 1
+609 0 2
+30 1 1
+66 0 1
+349 11 11
+65 1 1
+40 1 1
+717 0 3
+299 1 1
+29 1 1
+724 1 0
+275 1 1
+33 1 1
+318 0 3
+279 1 1
+28 1 1
+389 1 0
+548 0 8
+330 1 1
+47 1 1
+170 1 1
+47 1 1
+519 14 14
+841 24 24
+732 1 1
+29 3 3
+688 2 2
+23 0 1
+94 14 14
+726 13 13
+508 0 12
+21 6 0
+69 1 1
+37 1 1
+590 1 1
+59 1 1
+89 11 11
+164 1 1
+58 1 1
+1709 18 18
+520 1 1
+27 1 1
+683 10 10
+814 1 1
+26 1 1
+350 1 1
+39 1 1
+132 6 6
+439 1 1
+38 41 6
+15 0 1
+5 4 11
+81 1 1
+19 0 2
+167 1 1
+90 0 2
+85 1 1
+78 1 1
+87 19 2
+53 23 0
+255 0 1
+211 1 1
+54 1 1
+206 0 1
+60 35 33
+279 1 1
+76 179 180
+90 1 1
+119 3 0
+19 1 1
+60 1 1
+347 0 4
+30 2 2
+68 1 1
+78 1 1
+298 5 5
+67 1 1
+99 1 1
+97 1 1
+74 1 1
+52 1 1
+44 1 1
+65 1 4
+349 14 14
+109 1 1
+159 2 2
+214 9 9
+97 1 1
+73 1 1
+58 1 1
+42 1 1
+133 1 1
+99 0 10
+124 12 12
+281 3 0
+940 2 2
+49 1 1
+303 1 1
+25 1 1
+309 15 22
+384 1 1
+24 1 1
+896 1 1
+56 1 1
+168 0 19
+54 0 6
+60 0 1
+13 1 1
+502 1 1
+4 0 1
+23 1 1
+581 1 1
+47 1 1
+122 15 15
+3352 1 1
+23 1 1
+873 4 4
+887 1 0
+1827 1 0
+216 6 6
+805 2 0
+874 0 8
+2266 1 1
+47 1 1
+736 25 29
+86 1 1
+19 1 1
+1794 9 9
+271 0 1
+2266 1 1
+34 1 1
+916 0 1
+21 1 1
+108 21 21
+141 1 1
+27 1 1
+406 3 0
+3830 59 59
+61 1 1
+38 1 1
+128 2 2
+56 1 1
+72 0 1
+96 1 1
+22 1 1
+169 7 7
+511 1 1
+38 1 1
+1070 1 1
+90 1 1
+50 1 1
+41 1 0
+30 1 1
+659 12 12
+701 1 1
+33 1 1
+569 15 15
+70 1 1
+38 1 1
+955 0 3
+130 1 1
+63 1 1
+251 8 8
+191 1 1
+26 0 3
+187 1 0
+916 5 1
+70 13 13
+498 1 0
+55 0 1
+242 25 25
+237 1 1
+20 0 1
+61 1 1
+203 6 6
+262 1 1
+154 1 1
+104 1 1
+20 1 1
+156 1 1
+32 1 1
+88 17 17
+139 13 13
+148 20091 20061
+944 1 1
+126 1 1
+81 6 6
+41 3 0
+641 1 1
+92 1 0
+113 1 1
+39 1 1
+671 1 1
+28 1 1
+123 1 1
+59 1 1
+210 1 1
+17 1 1
+168 15 14
+494 1 0
+22 1 1
+484 18 18
+376 1 1
+114 2 0
+67 1 1
+10 1 1
+109 1 1
+165 1 1
+149 6 6
+234 1 1
+19 5 5
+64 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+168 1 1
+73 1 1
+194 1 1
+50 0 4
+37 1 1
+95 3 1
+43 1 1
+153 1 1
+83 1 1
+55 1 1
+39 1 1
+70 7 0
+59 7 7
+75 1 1
+84 2 2
+110 1 0
+42 1 1
+341 13 13
+262 4 4
+67 1 1
+32 1 0
+38 1 1
+277 7 7
+318 1 1
+145 1 1
+90 1 1
+19 4 4
+61 1 2
+31 1 1
+52 1 1
+214 1 1
+61 10083 10104
+701 2 0
+4080 1 1
+38 1 1
+837 0 64
+172 1 1
+55 1 1
+1818 2 0
+1143 13 13
+335 1 0
+1944 5 0
+39 6 0
+4057 3 8
+9465 5 4
+301 19 1
+191 84 0
+427 1 1
+29 0 4
+157 4 5
+296 21 18
+158 2 2
+36 1 1
+539 13 13
+399 1 1
+46 1 1
+348 1 1
+49 1 1
+268 1 0
+66 0 4
+178 2 2
+107 1 1
+133 5 5
+355 1 1
+30 1 1
+346 1 1
+29 1 1
+161 1 1
+38 1 1
+121 4 4
+55 8 8
+67 7 7
+318 17 17
+259 1 1
+94 1 1
+80 1 1
+35 1 1
+260 1 1
+81 1 1
+106 1 1
+58 1 2
+55 1 1
+245 3 0
+2052 1 1
+40 1 1
+174 20 22
+574 0 2
+414 1 0
+234 0 1
+425 51224 51060
+13549 39 40
+2617 0 2
+884 1 1
+19 1 1
+676 1 1
+63 1 1
+3138 0 3
+3038 5 2
+132 10 6
+136 18 13
+363 1 1
+89 1 1
+382 1 1
+29 1 1
+58 8 7
+297 4 0
+66 1 1
+93 2 0
+145 1 1
+31 5 5
+576 1 1
+89 1 1
+1256 0 12
+67 1 1
+193 2 2
+23 1 1
+51 1 0
+727 1 0
+1148 12 12
+837 1 1
+77 1 1
+941 10 10
+776 19 19
+300 1 1
+24 1 1
+256 1 7
+93 1 1
+191 174 172
+563 1 1
+104 4 4
+2898 1 1
+46 1 1
+282 1 1
+39 1 1
+204 2 2
+22 1 1
+469 1 1
+20 1 1
+140 1 1
+26 1 1
+745 0 2
+539 0 6
+1536 1 0
+817 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+132 5 0
+555 1 1
+42 1 1
+573 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+15 1 5
+1404 0 1
+934 1 1
+49 1 1
+1350 1 0
+384 1 1
+24 1 1
+3117 10 10
+1042 0 15
+244 10 10
+2167 18 14
+64 1 1
+31 1 1
+185 0 4
+1647 1 1
+20 1 1
+227 1 1
+37 1 1
+636 3 4
+5590 1 1
+39 1 1
+461 0 2
+2145 1 1
+23 1 1
+1114 0 2
+688 0 1
+901 18 18
+4781 0 4
+815 0 1
+5069 0 5
+415 0 1
+2743 1 1
+78 1 1
+390 1 0
+328 0 1
+878 0 1
+5752 0 2
+1554 1 1
+60 1 1
+278 0 1
+19 1 1
+1164 11 11
+691 0 2
+960 1 0
+62 0 20
+2108 0 2
+1265 0 1
+1642 2 0
+3584 2 0
+12086 2 0
+3766 0 2
+1209 1 7
+3466 1 0
+1448 1 0
+1943 0 1
+698 0 8
+1166 1 1
+34 1 1
+2120 11 9
+540 1 0
+1736 14 0
+3128 0 2
+4464 0 1
+120 4 4
+3473 1 0
+378 1 0
+1269 0 3
+1182 1 0
+654 0 3
+2049 1 0
+6838 1 1
+69 0 3
+154 1 0
+2718 1 1
+30 1 1
+160 11 11
+4954 0 1
+420 1 1
+123 1 1
+156 0 4
+219 4 0
+195 1 0
+4402 3 0
+3045 0 1
+1249 1 0
+3522 0 10
+812 8 0
+346 0 1
+8538 5 0
+455 1 0
+119 0 1
+1127 1 0
+10948 1 0
+833 0 1
+4251 1 0
+8 1 1
+2079 0 1
+1735 8 12
+1612 0 1
+1373 5 0
+8585 7 0
+64 1 1
+3799 1 0
+258 2 0
+899 1 0
+1362 8 9
+593 0 2
+3351 2 0
+618 0 4
+905 2 15
+2797 1 0
+2776 2 0
+4110 0 6
+4466 18 18
+2267 0 4
+134 1 0
+12963 8 0
+1616 0 2
+1685 2 0
+2225 2 0
+428 0 1
+3338 0 3
+677 4 6
+325 11 1
+1887 0 1
+913 0 1
+997 5 5
+2814 17 15
+1389 1 0
+1200 0 4
+2495 1 0
+3921 26431 26426
+2419 0 1
+6110 0 1
+1370 0 1
+3085 1 0
+3568 1 1
+24 0 9
+597 1 0
+2642 1 0
+1545 10 0
+4952 0 1
+6146 2 0
+1452 1 0
+2967 1 0
+4920 5 0
+147 4 5
+850 1 0
+1875 1 0
+695 3 1
+1719 0 1
+259 0 1
+294 1 0
+128 0 2
+3051 0 1
+908 0 4
+3399 0 1
+909 17 17
+3747 1 0
+3179 1 0
+411 1 1
+44 1 1
+174 1 0
+1047 17 17
+998 178 0
+671 0 40
+2093 1 0
+313 0 1
+7168 78 78
+335 1 0
+3245 1 0
+972 0 4
+4085 2 0
+346 1 1
+45 1 1
+368 1 0
+26 1 1
+8444 0 1
+17044 1 0
+2795 2 0
+2860 1 0
+622 0 1
+167 0 5
+1968 0 2
+259 2 0
+4992 29 27
+170 1 0
+3528 0 1
+191 1 2
+117 2 0
+2275 1 0
+12676 1 1
+20 1 1
+9972 1 0
+13955 0 5
+19867 1 0
+5866 0 32737
+3746 1 0
+20549 1 1
+19 1 1
+970 8 8
+5220 1 0
+15573 0 1
+6799 0 16
+3350 0 1
+7574 0 12
+2132 0 1
+7228 52793 52800
+2675 0 1
+2149 1 0
+6880 0 2
+960 0 1
+23 1 1
+2646 2 0
+3867 5 0
+24765 29 29
+1283 0 3
+3174 1 0
+8183 0 1
+2817 10 0
+4539 43 43
+1259 1 0
+2081 0 1
+374 0 2
+3589 0 4
+13928 3 0
+773 7 7
+175 1 1
+79 1 1
+400 12 12
+1096 0 4
+717 7 7
+52 1 1
+68 5 1
+2117 0 3
+130 14 14
+1124 0 3
+413 0 4
+643 3 0
+58 1 1
+127 1 1
+208 0 2
+45 1 1
+168 3 0
+136 3 4
+79 44 44
+170 1 1
+25 0 3
+63 1 1
+417 0 2
+412 0 16
+737 4 0
+402 2 0
+654 1 1
+42 1 1
+75 1 1
+64 1 1
+938 1 1
+53 1 1
+1987 4 0
+576 0 1
+29 2 2
+715 1 1
+36 1 1
+767 4 40
+44 1 5
+43 49 5
+709 21 21
+1147 9 9
+22 1 1
+195 7 4
+659 3 0
+27 1 1
+637 1 1
+42 1 1
+531 1 1
+67 1 1
+39 1 0
+717 11 11
+53 1 1
+61 1 1
+1535 1 1
+89 0 1
+49 1 0
+102 1 1
+67 1 1
+76 1 1
+129 1 1
+85 1 1
+607 10 0
+12 137 1
+41 1 1
+1043 1 1
+22 1 1
+203 3 0
+480 14 21
+1459 2 1
+435 15 17
+1188 30 0
+1778 1 0
+120 0 3
+3797 1 0
+887 1 1
+58 1 1
+2264 0 1
+2456 4 0
+954 0 4
+1847 0 1
+5929 20 20
+984 14 0
+2112 1 0
+2013 1 0
+4884 1 0
+1160 16 0
+733 7 7
+238 3 2
+2203 2 1
+5654 1 1
+28 5 10
+482 0 1
+2970 0 4
+2892 0 1
+251 1 7
+1346 1 0
+877 0 4
+3583 0 1
+1178 0 1
+1293 0 2
+491 2 0
+3501 46 46
+3256 1 1
+22 1 1
+2218 1 1
+44 1 1
+4780 4 0
+3026 14 13
+442 5 5
+2022 6 6
+546 2 0
+31 1 1
+8485 1 1
+36 1 0
+1575 1 0
+1329 1 1
+35 1 0
+247 1 1
+16 1 1
+184 1 1
+18 1 1
+1607 53 60
+527 1 1
+39 1 1
+653 3 0
+227 1 1
+18 1 1
+218 0 323
+91 1 0
+124 0 15
+621 0 2
+555 8 8
+467 1 1
+40 1 1
+372 1 1
+25 1 1
+188 12 12
+357 0 2
+2389 1 1
+22 1 1
+2579 0 5
+461 1 1
+36 1 1
+1584 1 1
+26 1 0
+429 1 0
+33 1 1
+1071 0 4
+1068 9 0
+1472 0 2
+1859 1 1
+61 2 0
+9 1 1
+337 1 1
+46 1 1
+416 1 1
+42 1 1
+1060 25 25
+170 0 2
+628 17 15
+587 15 15
+398 3 0
+696 6 9
+287 10 0
+191 0 2
+493 1 1
+42 4 0
+219 0 1
+408 1 1
+23 1 1
+283 1 1
+21 1 1
+633 2 0
+241 6 6
+457 1 0
+330 0 16
+428 1 0
+4 6 0
+324 0 1
+3063 0 2
+9960 39 40
+1850 0 6
+6431 0 1
+8674 0 4
+4595 11 0
+5064 2 0
+2813 12 12
+1391 5 0
+3690 1 1
+64 1 1
+2635 1 1
+49 1 1
+69 1 1
+15 1 1
+1009 8 0
+735 0 20
+3074 2 0
+1879 0 1
+572 0 8
+576 1 1
+42 1 1
+265 24 0
+209 11 11
+953 1 1
+42 0 5
+58 1 0
+95 1 0
+1121 1 1
+17 1 1
+751 0 1
+24 1 1
+351 1 1
+43 3 3
+565 1 1
+15 1 1
+150 27 27
+94 1 0
+323 1 1
+23 1 1
+221 7 7
+705 9 0
+631 2 0
+64 1 1
+1577 1 1
+21 0 1
+371 7 21
+160 0 1
+283 1 1
+48 1 1
+227 1 1
+40 0 1
+1359 0 2
+836 13 13
+722 7 7
+1153 1 1
+93 1 1
+797 14 14
+433 8 0
+108 11 11
+140 1 1
+40 1 1
+470 1 1
+42 1 1
+1106 0 1
+85 4 4
+129 1 1
+123 1 0
+95 1 1
+104 6 1
+641 1 1
+77 1 1
+57 1 1
+62 1 1
+473 2 0
+262 6 0
+45 1 1
+63 2 0
+39 1 1
+267 0 1
+197 2 104
+87 111 0
+122 0 7
+88 0 4
+108 5 0
+563 14 14
+324 1 0
+205 1 1
+17 1 1
+495 0 1
+201 4 0
+14 1 1
+887 1 1
+58 1 1
+133 1 1
+24 1 1
+91 24 24
+342 1 1
+32 1 1
+121 1 1
+62 1 1
+2371 2 0
+164 8 1
+655 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+1780 2 0
+742 1 1
+40 1 1
+2014 1 0
+1741 3 0
+3833 0 1
+16381 3 3
+25 1 1
+234 161226 190028
+3106 0 1
+1680 1 1
+88 1 1
+4502 0 1
+46 1 1
+800 4 4
+23 1 1
+1305 2 0
+136 0 1
+4941 0 1
+547 0 1
+70 8 8
+293 1 1
+35 1 1
+1165 4 0
+6662 1 1
+46 1 1
+167 0 8
+214 1 1
+35 1 1
+108 1 0
+1063 0 1
+1017 1 1
+20 0 6
+1725 0 1
+134 68 67
+349 1 1
+24 0 1
+1562 1 1
+31 1 1
+2513 0 1
+73 36 36
+305 1 1
+27 1 1
+543 1 1
+47 4 28
+4387 20058 20058
+159 1 1
+36 1 1
+107 1 1
+176 1 1
+154 0 5
+91 1 1
+54 1 1
+77 1 1
+238 2 2
+50 1 1
+1421 1 1
+23 1 1
+216 1 1
+122 1 1
+86 1 1
+41 3 1
+336 7 7
+41 9 0
+107 1 1
+90 8 9
+53 1 1
+30 1 1
+213 1 1
+26 1 1
+138 1 1
+25 1 1
+206 1 1
+36 3 3
+37 7 0
+500 1 1
+52 1 1
+52 1 1
+48 1 1
+395 1 1
+66 6 6
+72 1 0
+69 1 1
+100 10 10
+160 1 0
+64 7 7
+89 1 1
+123 1 1
+128 1 1
+36 1 1
+231 1 1
+61 1 1
+564 8 8
+593 1 1
+45 1 1
+163 1 0
+196 8 8
+174 5 5
+37 1 1
+67 0 1
+192 1 1
+60 3 0
+19 1 1
+1149 1 1
+18 1 1
+77 1 1
+32 2 0
+32 1 1
+136 1 1
+78 2 0
+162 4 0
+41 1 1
+351 13 13
+1634 2 0
+229 8 8
+57 13 2
+410 1 1
+76 1 1
+180 1 1
+92 1 1
+270 1 1
+40 1 1
+92 1 1
+53 1 1
+227 1 1
+42 1 1
+357 4 4
+23 1 1
+94 1 0
+200 6 0
+201 7 7
+70 5 13
+57 4 0
+35 1 1
+206 1 1
+76 2 2
+651 1 1
+68 4 0
+73 1 1
+49 4 0
+37 1 1
+145 2 2
+78 2 2
+108 12 12
+52 1 1
+35 1 1
+242 1 3
+76 2 2
+50 12 12
+70 1 1
+33 0 2
+57 1 1
+64 15 15
+168 1 1
+22 1 1
+66 2 2
+6 0 1
+24 1 1
+73 0 2
+64 1 1
+177 2 0
+19 4 0
+55 1 0
+33 1 1
+51 1 1
+122 1 1
+296 1 1
+85 1 1
+109 1 1
+64 1 1
+155 1 1
+58 0 2
+72 1 1
+25 1 1
+128 1 1
+45 2 0
+334 4 4
+106 1 1
+25 1 1
+64 1 1
+21 1 1
+368 15 15
+734 2 0
+701 15 15
+71 1 1
+41 1 1
+77 1 1
+56 1 1
+478 2 0
+714 8 7
+95 2 2
+50 4 3
+1129 1 1
+34 1 1
+1715 1 1
+87 1 1
+692 1 1
+47 0 1
+75 1 1
+2155 10 10
+1265 1 1
+46 1 1
+298 1 1
+22 1 1
+186 1 1
+34 1 1
+202 1 1
+61 1 0
+185 1 1
+24 1 0
+98 0 2
+258 8 14
+967 1 1
+15 1 1
+625 1 0
+1362 0 4
+23365 4 0
+246 26975 26986
+3307 0 1
+13671 3 3
+52 1 1
+1308 2 0
+942 0 1
+17790 1 0
+4586 0 1
+949 0 2
+15047 0 1
+606 2 0
+7820 0 4
+22313 16 0
+10539 8 0
+4836 0 1
+8726 2 0
+194 1 1
+49 1 1
+320 1 1
+34 1 1
+6813 0 1
+8719 3 0
+5482 46 46
+1509 1 0
+721 0 1
+999 6 0
+17 1 0
+3075 5 0
+593 13 11
+4505 1 0
+9535 0 4
+23 0 2
+23 2 0
+513 0 3
+377 1 0
+2627 0 2
+16 0 1
+211 18 18
+571 2 0
+7617 0 1
+1607 1 0
+69 1 1
+66 1 1
+275 1 1
+67 7 0
+25 1 1
+1206 1 0
+136 8 7
+612 1 1
+61 1 1
+740 0 2
+233 1 1
+95 0 4
+1483 13 28
+1062 1 0
+108 4 0
+685 0 2
+1566 1 0
+192 4 4
+1452 9 45
+1514 1 1
+46 1 1
+1969 0 1
+35 1 1
+1094 1 0
+618 1 1
+43 1 1
+6580 1 0
+1636 5 0
+6325 1 1
+32 1 1
+1041 0 2
+174 9 0
+4023 14 14
+8106 8 8
+2203 10 8
+2025 1 1
+39 1 1
+907 4 4
+225 1 1
+124 1 1
+3928 0 22
+38 2 0
+44 18 0
+46 0 6
+61 0 1
+3653 6 0
+34 1 1
+4559 1 1
+28 1 1
+283 5 5
+1951 1 1
+34 1 1
+443 19 19
+57 1 1
+21 1 1
+231 1 1
+94 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 40 40
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 5 5
+23 1 1
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+339 1 1
+56 0 5
+142 1 1
+232 1 1
+43 1 1
+332 1 1
+47 1 1
+479 1 0
+137 0 3
+1456 10 13
+63 1 1
+37 1 1
+261 0 2
+109 1 1
+50 1 1
+56 129 1
+88 1 0
+44 1 1
+54 1 1
+56 1 50
+58 50 1
+54 277 1
+44 1 1
+297 0 39
+142 1 1
+85 1 1
+124 16 16
+58 3 15
+677 1 0
+1333 2 0
+13591 6 0
+989 1 1
+107 1 1
+678 1 1
+31 1 1
+2571 5 5
+56 2 2
+39 1 1
+3986 0 4
+18351 32 30
+10811 1 1
+25 0 1
+129 62 62
+226 1 1
+40 1 1
+159 4 4
+37 4 4
+179 1 1
+51 1 1
+103 2 0
+108 1 1
+79 1 1
+25 1 1
+58 1 1
+12 1 1
+275 14 0
+80 1 1
+83 1 1
+24 1 1
+59 1 0
+91 1 1
+65 1 1
+67 1 1
+136 4 0
+68 8 0
+331 5 0
+40 1 1
+110 10 6
+64 1 1
+368 1 1
+22 1 1
+509 1 1
+89 1 1
+926 1 0
+959 1 1
+44 1 1
+72 11 0
+47 1 1
+361 1 1
+37 1 1
+2204 2 2
+45 1 1
+1117 18 18
+141 1 1
+47 1 1
+148 1 1
+75 1 1
+107 57 56
+146 3 2
+249 1 1
+146 1 1
+94 1 1
+34 1 1
+700 0 331
+21 1 1
+73 1 1
+49 1 1
+356 1 1
+16 1 1
+112 1 1
+36 9 0
+515 1 1
+27 2 2
+192 1 1
+53 0 14
+82 1 1
+302 1 1
+68 1 1
+52 12 12
+52 1 1
+34 1 1
+166 7 7
+384 1 1
+31 1 1
+281 1 1
+57 1 1
+176 0 1
+1625 1 1
+26 1 1
+369 1 1
+21 1 1
+86 1 1
+134 1 1
+215 1 1
+214 15 1
+50 2 2
+26 1 1
+78 0 19
+64 1 1
+126 1 1
+43 1 1
+433 1 1
+76 0 1
+6 12 0
+52 1 1
+108 1 1
+87 1 1
+62 1 1
+26 1 1
+291 2 1
+143 1 1
+29 1 1
+56 12 12
+230 1 1
+153 4 4
+87 32 32
+584 12 12
+227 1 0
+1931 4 0
+836 1 1
+68 1 1
+205 24 19
+816 1 2
+1932 0 7
+1732 13 0
+257 4 0
+1441 1 0
+111 6 0
+1505 1 1
+42 0 1
+373 13 13
+565 1 1
+76 1 0
+1881 0 4
+68 4 0
+43 0 4
+2201 8 8
+3726 3 0
+339 15 11
+249 1 1
+35 1 1
+250 1 1
+38 1 1
+359 11 12
+109 1 1
+43 18 0
+822 1 1
+53 1 1
+325 15 15
+123 1 1
+42 6 6
+240 1 1
+44 1 1
+438 7 7
+142 2 0
+1004 0 1
+9275 1 1
+37 1 0
+2071 0 1
+10399 0 1
+12513 2 1
+11243 1 1
+26 1 1
+816 4 0
+8248 26 26
+7722 2 0
+1594 1 0
+363 5 0
+6757 47 41
+2700 1 0
+823 18 19
+1807 0 2
+2565 11 0
+2089 0 2
+477 1 0
+657 0 1
+776 0 20
+365 82 49
+779 0 1
+391 35 73
+441 0 2
+1152 0 2
+1315 1 0
+5352 6 8
+902 0 1
+2154 1 1
+36 1 1
+109 0 1
+668 6 0
+1923 0 1
+91 3 2
+3560 1 0
+1235 1 0
+139 26 0
+831 3 3
+6547 1 0
+155 0 14
+2393 1 1
+33 1 1
+507 4 0
+1337 0 1
+9954 3 0
+1588 1 0
+2605 1 1
+23 1 1
+3000 0 3
+8249 8 0
+912 0 1
+338 2 0
+734 1 0
+4332 1 0
+416 0 4
+1691 0 1
+295 1 0
+214 2 0
+121 0 1
+784 0 1
+2512 0 1
+1205 21 21
+3239 12 11
+926 1 0
+190 1 0
+5780 0 1
+490 5 0
+228 1 1
+45 1 1
+207 3 0
+322 0 1
+633 1 1
+24 1 0
+1516 5 0
+1025 0 13
+1518 0 1
+591 10 10
+1061 1 0
+1371 1 1
+22 1 1
+928 0 2
+182 8 0
+328 1 0
+301 0 1
+994 1 1
+18 0 6
+1743 0 1
+2350 22 23
+1548 0 2
+1498 8 6
+7484 0 3
+2988 7 7
+93 2 0
+322 1 0
+280 1 1
+49 1 1
+2114 16 17
+617 0 1
+1012 0 1
+495 1 0
+29 1 1
+3134 1 0
+1837 0 4
+4079 0 1
+905 8 0
+5764 0 1
+3493 0 20
+1174 0 1
+900 0 1
+1006 1 0
+1699 0 1
+1682 1 0
+688 1 1
+21 1 1
+3349 0 1
+384 3 1
+3616 3 0
+748 0 1
+3001 0 10
+541 1 0
+286 1 1
+22 0 1
+250 1 1
+27 1 1
+898 1 0
+1161 0 2
+2067 0 1
+8000 0 12
+857 29 0
+1399
+
+chain 80965 chr6_qbl_hap6 4611984 + 2304864 2305721 chr6 170899992 - 139781917 139782778 1559017
+341 0 4
+516
+
+chain 72788 chr6_qbl_hap6 4611984 + 3854428 3855228 chr11 134452384 + 117706218 117707111 1729754
+615 13 107
+119 2 1
+51
+
+chain 45972 chr6_qbl_hap6 4611984 + 2517561 2519479 chr10 135374737 + 90380381 90382315 2786707
+110 146 146
+63 324 322
+53 379 396
+81 331 331
+99 110 110
+78 40 41
+104
+
+chain 30865 chr6_qbl_hap6 4611984 + 3846325 3846844 chr6 170899992 + 32821259 32821748 4483191
+73 89 59
+184 77 77
+96
+
+chain 26769 chr6_qbl_hap6 4611984 + 2264712 2264997 chr1 247249719 - 83196058 83196343 6075821
+285
+
+chain 22241 chr6_qbl_hap6 4611984 + 1157838 1158189 chr4 191273063 + 37186911 37187262 8835264
+178 101 101
+72
+
+chain 17263 chr6_qbl_hap6 4611984 + 3740215 3740422 chr4 191273063 + 3978296 3978500 12788148
+50 3 0
+26 4 4
+124
+
+chain 16745 chr6_qbl_hap6 4611984 + 2635745 2635946 chr11 134452384 + 74426248 74426449 13289834
+113 12 12
+76
+
+chain 16124 chr6_qbl_hap6 4611984 + 3115310 3115488 chr2 242951149 + 128261675 128261851 618783
+28 10 8
+140
+
+chain 15557 chr6_qbl_hap6 4611984 + 3932244 3933069 chr7 158821424 + 130132312 130132930 14485186
+71 636 429
+118
+
+chain 14855 chr6_qbl_hap6 4611984 + 3933226 3933509 chr9 140273252 - 14741363 14741645 15225313
+54 109 108
+120
+
+chain 14065 chr6_qbl_hap6 4611984 + 3751984 3752136 chr6 170899992 - 138279004 138279156 16120856
+152
+
+chain 13590 chr6_qbl_hap6 4611984 + 3850351 3850495 chr2 242951149 + 178053314 178053458 16703161
+144
+
+chain 13364 chr6_qbl_hap6 4611984 + 3822393 3822546 chr3 199501827 + 102278307 102278460 16996123
+67 1 1
+85
+
+chain 13024 chr6_qbl_hap6 4611984 + 983771 983907 chr11 134452384 - 45905925 45906061 17454498
+136
+
+chain 12452 chr6_qbl_hap6 4611984 + 4259490 4260232 chr12 132349534 + 123152186 123152605 1903988
+57 408 105
+14 32 63
+45 0 78
+44 129 0
+13
+
+chain 12361 chr6_qbl_hap6 4611984 + 1196738 1196868 chr1 247249719 + 48758029 48758159 18440544
+130
+
+chain 12272 chr6_qbl_hap6 4611984 + 2525057 2525213 chrX 154913754 + 154847615 154847763 18572106
+71 1 1
+25 8 0
+51
+
+chain 12201 chr6_qbl_hap6 4611984 + 1151149 1151920 chr6 170899992 - 139553108 139553881 18681505
+54 620 622
+97
+
+chain 11746 chr6_qbl_hap6 4611984 + 1143997 1144145 chr7 158821424 - 7754727 7754875 19419749
+54 14 14
+80
+
+chain 11418 chr6_qbl_hap6 4611984 + 3733988 3734369 chr6 170899992 + 32605989 32606372 19978843
+55 244 246
+82
+
+chain 11340 chr6_qbl_hap6 4611984 + 3744880 3745292 chr11 134452384 + 42855603 42856006 20116653
+57 275 266
+80
+
+chain 11205 chr6_qbl_hap6 4611984 + 3740546 3740663 chr3 199501827 + 102893757 102893874 20360983
+117
+
+chain 10738 chr6_qbl_hap6 4611984 + 3746512 3746633 chr10 135374737 + 59270705 59270823 21232184
+61 3 0
+57
+
+chain 10686 chr6_qbl_hap6 4611984 + 2524205 2524726 chr18 76117153 + 11332173 11332695 21332094
+80 388 389
+53
+
+chain 10567 chr6_qbl_hap6 4611984 + 3783253 3785836 chr6 170899992 + 32627140 32629242 21577879
+86 1741 1742
+57 646 164
+53
+
+chain 10496 chr6_qbl_hap6 4611984 + 3742563 3742673 chr1 247249719 - 172266041 172266151 21720781
+110
+
+chain 10342 chr6_qbl_hap6 4611984 + 3760212 3760942 chr6 170899992 + 32656559 32657213 22046794
+78 598 522
+54
+
+chain 10139 chr6_qbl_hap6 4611984 + 1198462 1198648 chr16 88827254 + 79406655 79406844 22494560
+65 65 68
+56
+
+chain 9962 chr6_qbl_hap6 4611984 + 3745365 3745830 chr4 191273063 - 17741127 17741604 22894345
+65 340 352
+60
+
+chain 9923 chr6_qbl_hap6 4611984 + 1132589 1132693 chr6 170899992 + 29984509 29984613 22990380
+104
+
+chain 9560 chr6_qbl_hap6 4611984 + 1145748 1145849 chr6 170899992 - 141000133 141000234 23851260
+101
+
+chain 9413 chr6_qbl_hap6 4611984 + 2517880 2518811 chr3 199501827 - 190559447 190560375 2816976
+26 220 218
+60 531 530
+94
+
+chain 9385 chr6_qbl_hap6 4611984 + 3871626 3871831 chr16 88827254 - 20600009 20600189 24262926
+58 92 67
+55
+
+chain 9214 chr6_qbl_hap6 4611984 + 1148380 1148477 chr6 170899992 + 29866137 29866234 24599827
+97
+
+chain 9032 chr6_qbl_hap6 4611984 + 3792044 3793708 chr6 170899992 + 32600177 32601830 24897719
+61 1516 1505
+87
+
+chain 8560 chr6_qbl_hap6 4611984 + 1158286 1158614 chr13 114142980 - 5380936 5381417 10250153
+58 237 390
+33
+
+chain 8241 chr6_qbl_hap6 4611984 + 3817008 3817095 chr6 170899992 + 65319659 65319746 26041518
+87
+
+chain 7487 chr6_qbl_hap6 4611984 + 3850495 3850589 chr16 88827254 + 12353631 12353725 21356530
+23 11 11
+60
+
+chain 7405 chr6_qbl_hap6 4611984 + 3933869 3933948 chr6 170899992 + 125781203 125781282 27398065
+79
+
+chain 7276 chr6_qbl_hap6 4611984 + 3821398 3821474 chr6 170899992 - 67344251 67344327 27653186
+76
+
+chain 7270 chr6_qbl_hap6 4611984 + 2635437 2635524 chr9 140273252 - 10289268 10289355 16248608
+13 11 11
+63
+
+chain 7204 chr6_qbl_hap6 4611984 + 3822572 3822648 chr7 158821424 - 147092048 147092124 27788942
+76
+
+chain 6530 chr6_qbl_hap6 4611984 + 3872997 3873065 chr8 146274826 + 43408268 43408336 29217082
+68
+
+chain 6522 chr6_qbl_hap6 4611984 + 3873792 3873861 chr15 100338915 + 41279078 41279147 29241048
+69
+
+chain 6486 chr6_qbl_hap6 4611984 + 3835377 3835446 chr4 191273063 - 136771275 136771344 29334522
+69
+
+chain 6459 chr6_qbl_hap6 4611984 + 2621390 2621459 chr6 170899992 + 31350859 31350928 29378034
+69
+
+chain 6457 chr6_qbl_hap6 4611984 + 1204555 1204622 chr6 170899992 + 30336816 30336883 29393800
+67
+
+chain 6422 chr6_qbl_hap6 4611984 + 3863961 3864029 chr6 170899992 + 32836685 32836753 29490928
+68
+
+chain 6404 chr6_qbl_hap6 4611984 + 3933974 3934042 chr7 158821424 + 141217888 141217956 29535655
+68
+
+chain 6368 chr6_qbl_hap6 4611984 + 2524965 2525057 chr6 170899992 - 132294381 132294479 20980275
+55 29 35
+8
+
+chain 6276 chr6_qbl_hap6 4611984 + 3873712 3873778 chrX 154913754 + 50967168 50967234 29833134
+66
+
+chain 5979 chr6_qbl_hap6 4611984 + 3850589 3850678 chr7 158821424 + 47749290 47749379 21749072
+4 34 34
+51
+
+chain 5976 chr6_qbl_hap6 4611984 + 2623961 2624024 chr6 170899992 + 31358648 31358711 30614264
+63
+
+chain 5908 chr6_qbl_hap6 4611984 + 1197012 1197085 chr19 63811651 - 42248237 42248310 20723418
+73
+
+chain 5877 chr6_qbl_hap6 4611984 + 3715034 3715097 chr6 170899992 + 32648139 32648202 30861180
+63
+
+chain 5767 chr6_qbl_hap6 4611984 + 3872292 3872353 chr6 170899992 + 75566512 75566573 31174250
+61
+
+chain 5730 chr6_qbl_hap6 4611984 + 1160462 1160522 chr6 170899992 + 29878483 29878543 31293472
+60
+
+chain 5694 chr6_qbl_hap6 4611984 + 3933682 3933742 chr5 180857866 - 92908144 92908204 31375044
+60
+
+chain 5621 chr6_qbl_hap6 4611984 + 1160085 1160144 chr6 170899992 + 29878108 29878167 31597733
+59
+
+chain 5594 chr6_qbl_hap6 4611984 + 2515502 2515561 chrX 154913754 - 63050736 63050795 31662666
+59
+
+chain 5458 chr6_qbl_hap6 4611984 + 3834959 3835017 chr16 88827254 + 47978524 47978582 32101539
+58
+
+chain 5276 chr6_qbl_hap6 4611984 + 3754169 3754225 chr6 170899992 + 32648605 32648661 32642677
+56
+
+chain 5193 chr6_qbl_hap6 4611984 + 3872547 3872601 chr5 180857866 + 130110350 130110404 32896488
+54
+
+chain 5176 chr6_qbl_hap6 4611984 + 1146649 1146704 chr14 106368585 + 78419238 78419293 32952450
+55
+
+chain 5094 chr6_qbl_hap6 4611984 + 3834697 3834751 chr6 170899992 + 68023473 68023527 33192803
+54
+
+chain 4984 chr6_qbl_hap6 4611984 + 3871272 3871324 chr1 247249719 - 76982562 76982614 33591211
+52
+
+chain 4959 chr6_qbl_hap6 4611984 + 3742510 3742563 chr18 76117153 + 5080594 5080647 22154819
+53
+
+chain 4930 chr6_qbl_hap6 4611984 + 3744490 3744542 chrX 154913754 - 4434310 4434362 33717622
+52
+
+chain 4923 chr6_qbl_hap6 4611984 + 1158016 1158078 chr9 140273252 - 102391777 102391839 11227006
+62
+
+chain 4829 chr6_qbl_hap6 4611984 + 1205079 1205129 chr6 170899992 + 30567298 30567348 34088060
+50
+
+chain 4815 chr6_qbl_hap6 4611984 + 2517906 2519257 chr1 247249719 + 7396807 7398156 2855562
+25 959 957
+58 214 214
+95
+
+chain 4391 chr6_qbl_hap6 4611984 + 4260111 4260156 chrX 154913754 - 99121082 99121127 30173418
+45
+
+chain 4349 chr6_qbl_hap6 4611984 + 2517042 2517321 chr5 180857866 + 51070260 51070539 3385343
+66 110 110
+103
+
+chain 4295 chr6_qbl_hap6 4611984 + 2516110 2516164 chr13 114142980 + 40947099 40947153 23509762
+54
+
+chain 3734 chr6_qbl_hap6 4611984 + 3932378 3932443 chr6 170899992 + 80018577 80018642 19955879
+65
+
+chain 3600 chr6_qbl_hap6 4611984 + 3934098 3934136 chr2 242951149 + 129304609 129304647 25766390
+38
+
+chain 3399 chr6_qbl_hap6 4611984 + 1196935 1197002 chr12 132349534 + 50414483 50414550 19205048
+67
+
+chain 3394 chr6_qbl_hap6 4611984 + 3746476 3746512 chrX 154913754 - 4438295 4438331 28244178
+36
+
+chain 3148 chr6_qbl_hap6 4611984 + 3871684 3871717 chr2 242951149 + 38036197 38036230 24698966
+33
+
+chain 2975 chr6_qbl_hap6 4611984 + 2524285 2524321 chr3 199501827 - 94209737 94209773 24799760
+36
+
+chain 2972 chr6_qbl_hap6 4611984 + 1151921 1151961 chr6 170899992 + 30567024 30567064 20739259
+40
+
+chain 2845 chr6_qbl_hap6 4611984 + 2516686 2516716 chr3 199501827 - 158108130 158108160 26771673
+30
+
+chain 2771 chr6_qbl_hap6 4611984 + 2185017 2185049 chr16 88827254 + 61371572 61371604 11881976
+32
+
+chain 2691 chr6_qbl_hap6 4611984 + 3933197 3933226 chr3 199501827 - 121608742 121608771 23862843
+29
+
+chain 2671 chr6_qbl_hap6 4611984 + 2524905 2524964 chr9 140273252 - 60326471 60326530 21074055
+59
+
+chain 2645 chr6_qbl_hap6 4611984 + 3740797 3740872 chr19 63811651 - 40112981 40113056 21687959
+75
+
+chain 2599 chr6_qbl_hap6 4611984 + 1158078 1158116 chr7 158821424 - 126060947 126060985 11258555
+38
+
+chain 2365 chr6_qbl_hap6 4611984 + 3662868 3662893 chr9 140273252 - 56082033 56082058 25372966
+25
+
+chain 2302 chr6_qbl_hap6 4611984 + 2518282 2518373 chrX 154913754 + 17160841 17160932 3083108
+91
+
+chain 2226 chr6_qbl_hap6 4611984 + 2516716 2520208 chr12 132349534 + 103307685 103311177 3426888
+99 961 960
+41 2329 2330
+62
+
+chain 2196 chr6_qbl_hap6 4611984 + 3573229 3573252 chr8 146274826 - 36256974 36256997 29790670
+23
+
+chain 2146 chr6_qbl_hap6 4611984 + 1144210 1144271 chr12 132349534 + 104221177 104221238 23825291
+61
+
+chain 2027 chr6_qbl_hap6 4611984 + 2518845 2519837 chr4 191273063 + 75333400 75334396 3306565
+44 889 893
+59
+
+chain 2011 chr6_qbl_hap6 4611984 + 3750379 3750401 chr12 132349534 - 27555073 27555095 35529087
+22
+
+chain 2003 chr6_qbl_hap6 4611984 + 1715012 1715046 chr6 170899992 + 30558380 30558414 2034666
+34
+
+chain 1988 chr6_qbl_hap6 4611984 + 3744653 3744712 chr1 247249719 + 152912877 152912936 23823439
+59
+
+chain 1906 chr6_qbl_hap6 4611984 + 2517426 2517496 chr17 78774742 - 18978582 18978652 12332136
+70
+
+chain 1860 chr6_qbl_hap6 4611984 + 1158233 1158283 chr8 146274826 + 68242167 68242217 13480681
+50
+
+chain 1860 chr6_qbl_hap6 4611984 + 3858322 3861837 chr6 170899992 + 32830794 32834943 29475612
+61 2506 2690
+85 515 965
+52 103 103
+193
+
+chain 1658 chr6_qbl_hap6 4611984 + 1158189 1158222 chr4 191273063 + 153905795 153905828 11042895
+33
+
+chain 1451 chr6_qbl_hap6 4611984 + 2516912 2518845 chr18 76117153 + 57868323 57870253 3225031
+58 1841 1838
+34
+
+chain 1444 chr6_qbl_hap6 4611984 + 2517346 2518418 chr3 199501827 + 26257399 26258470 3460386
+77 968 967
+27
+
+chain 1437 chr6_qbl_hap6 4611984 + 2517932 2518010 chr9 140273252 - 113447512 113447590 4152331
+78
+
+chain 1395 chr6_qbl_hap6 4611984 + 2517496 2517525 chr4 191273063 + 177039024 177039053 17309502
+29
+
+chain 1388 chr6_qbl_hap6 4611984 + 4260176 4260219 chr19 63811651 - 48476446 48476489 2785288
+43
+
+chain 1332 chr6_qbl_hap6 4611984 + 3612848 3612887 chr2 242951149 - 44758440 44758479 1994605
+39
+
+chain 1326 chr6_qbl_hap6 4611984 + 2516425 2516540 chr2 242951149 - 193553846 193553961 4393012
+115
+
+chain 1313 chr6_qbl_hap6 4611984 + 4259851 4259901 chr1 247249719 - 36229834 36229933 2748513
+7 14 63
+29
+
+chain 1148 chr6_qbl_hap6 4611984 + 4259442 4259473 chr8 146274826 + 89694 89724 9819782
+12 1 0
+18
+
+chain 1111 chr6_qbl_hap6 4611984 + 1158412 1158466 chr19 63811651 - 5696793 5696847 17027637
+54
+
+chain 1071 chr6_qbl_hap6 4611984 + 2516561 2516628 chr12 132349534 + 77415638 77415705 9437720
+67
+
+chain 1001 chr6_qbl_hap6 4611984 + 4259418 4259442 chr1 247249719 + 40151331 40151355 3139135
+24
+
+chain 975 chr6_qbl_hap6 4611984 + 2516971 2517042 chr1 247249719 + 183489007 183489078 3337949
+71
+
+chain 917 chr6_qbl_hap6 4611984 + 2518025 2518086 chr8 146274826 - 9314035 9314096 4594958
+61
+
+chain 884 chr6_qbl_hap6 4611984 + 2519749 2519778 chr1 247249719 - 197271642 197271671 12501548
+29
+
+chain 844 chr6_qbl_hap6 4611984 + 2520091 2520119 chr7 158821424 + 107644180 107644208 22181631
+28
+
+chain 841 chr6_qbl_hap6 4611984 + 2516165 2516217 chr20 62435964 - 59823019 59823071 21526398
+52
+
+chain 836 chr6_qbl_hap6 4611984 + 4259969 4260001 chr3 199501827 + 123981761 123981793 2757122
+32
+
+chain 835 chr6_qbl_hap6 4611984 + 2519837 2519906 chr4 191273063 + 99162526 99162595 6917305
+69
+
+chain 764 chr6_qbl_hap6 4611984 + 1158466 1158505 chr14 106368585 - 57011112 57011151 17388689
+39
+
+chain 760 chr6_qbl_hap6 4611984 + 2520610 2520672 chr1 247249719 + 71360495 71360557 7931067
+62
+
+chain 760 chr6_qbl_hap6 4611984 + 2518460 2518519 chr12 132349534 + 56700130 56700189 25330836
+59
+
+chain 746 chr6_qbl_hap6 4611984 + 2519488 2519538 chr22 49691432 + 27063810 27063860 3889151
+50
+
+chain 745 chr6_qbl_hap6 4611984 + 2516014 2516077 chr6 170899992 + 44660392 44660455 3181879
+63
+
+chain 740 chr6_qbl_hap6 4611984 + 1158720 1158784 chr12 132349534 + 55464534 55464598 20832676
+64
+
+chain 718 chr6_qbl_hap6 4611984 + 2520835 2520890 chr9 140273252 - 49339912 49339967 23555331
+55
+
+chain 716 chr6_qbl_hap6 4611984 + 3933624 3933676 chr16 88827254 - 38714794 38714846 22851161
+52
+
+chain 710 chr6_qbl_hap6 4611984 + 2519659 2519709 chr11 134452384 - 107252690 107252740 6149242
+50
+
+chain 706 chr6_qbl_hap6 4611984 + 2516328 2516399 chr18 76117153 + 57376973 57377044 7676567
+71
+
+chain 700 chr6_qbl_hap6 4611984 + 2516815 2516871 chr1 247249719 + 47033162 47033218 11749470
+56
+
+chain 685 chr6_qbl_hap6 4611984 + 2520397 2520480 chr1 247249719 + 68246247 68246330 16545799
+83
+
+chain 662 chr6_qbl_hap6 4611984 + 2520752 2520817 chr5 180857866 + 99923773 99923838 9608666
+65
+
+chain 654 chr6_qbl_hap6 4611984 + 1158614 1158640 chr4 191273063 - 137719796 137719822 10317123
+26
+
+chain 604 chr6_qbl_hap6 4611984 + 2520031 2520091 chr8 146274826 - 111755913 111755973 4980877
+60
+
+chain 569 chr6_qbl_hap6 4611984 + 2515445 2515500 chr12 132349534 - 4861980 4862035 16127490
+55
+
+chain 521 chr6_qbl_hap6 4611984 + 2517182 2517218 chr15 100338915 - 47556137 47556173 3431041
+36
+
+chain 465 chr6_qbl_hap6 4611984 + 2518541 2518594 chrX 154913754 - 2978832 2978885 15318329
+53
+
+chain 465 chr6_qbl_hap6 4611984 + 2515257 2515307 chr13 114142980 + 94087883 94087933 15752176
+50
+
+chain 431 chr6_qbl_hap6 4611984 + 2516292 2516328 chrX 154913754 + 109116067 109116103 11044816
+36
+
+chain 377 chr6_qbl_hap6 4611984 + 2521082 2521150 chrX 154913754 - 100727898 100727966 10456810
+68
+
+chain 364 chr6_qbl_hap6 4611984 + 2519959 2520014 chr2 242951149 + 137419466 137419521 26497561
+55
+
+chain 357 chr6_qbl_hap6 4611984 + 2516242 2516292 chr3 199501827 + 59182343 59182393 15538406
+50
+
+chain 252 chr6_qbl_hap6 4611984 + 2519906 2519943 chr10 135374737 + 69013226 69013263 15789370
+37
+
+chain 172 chr6_qbl_hap6 4611984 + 3874043 3874094 chr1 247249719 - 204983626 204983677 25877237
+51
+
+chain 126 chr6_qbl_hap6 4611984 + 2521548 2521600 chr16 88827254 - 42325840 42325892 26081164
+52
+
+chain 345833726 chr6_ssto_hap7 4928567 + 0 4928567 chr6 170899992 + 28767121 33556332 37
+43705 3 0
+396 1 1
+36 1 1
+327 0 2
+458 8 0
+6175 1 1
+58 1 1
+80 0 7
+257 2 0
+2504 0 12
+1614 0 1
+1985 6 0
+370 1 0
+2206 2 0
+4292 4 0
+5173 33 8
+1486 4 4
+213 2 2
+71 0 1
+437 0 1
+897 1 1
+34 1 1
+10055 18 6
+2970 0 1
+813 0 15
+922 0 20
+1095 1 1
+43 1 1
+1829 0 1
+2885 0 10
+5273 0 1
+108 2 0
+571 0 3
+2338 1 0
+934 1 0
+2409 0 8
+2132 54 16
+77 1 52
+38 0 59
+40 0 2
+3908 1 0
+3045 2 4
+758 0 1
+174 15 15
+211 1 0
+608 0 4
+1434 2 0
+2061 2 0
+10205 0 6
+2011 17 17
+871 89 85
+91 0 2
+2644 33 29
+3737 1 1
+39 1 1
+1512 1 0
+2391 2 0
+844 0 1
+5198 0 1
+17000 0 1
+603 2 0
+4648 0 3
+2281 1 0
+38 1 1
+334 1 1
+41 1 1
+1760 1 0
+3862 0 6
+1025 160 0
+3444 3 0
+282 0 1
+1508 1 0
+2207 0 3
+1827 1 0
+3220 9 0
+5157 0 4
+1394 1 0
+279 0 2
+71 0 4
+163 1 1
+31 1 1
+280 8 0
+1059 0 2
+1409 0 4
+402 1 0
+643 0 2
+746 0 2
+1268 2 0
+267 0 1
+1868 1 1
+44 1 1
+8525 0 4
+1440 4 4
+127 0 6
+204 1 2
+873 1 0
+131 2 0
+3954 0 1
+1818 2 1
+4264 0 1
+3195 0 2
+2446 1 1
+70 26 25
+70 1 1
+1649 1 0
+953 0 1
+295 1 1
+32 0 6
+661 8 0
+5298 1 0
+1365 0 1
+6151 2 0
+1123 0 9
+2073 1 0
+611 1 0
+1129 0 3
+562 11 11
+9680 4 4
+316 19 19
+831 2 0
+3215 1 0
+1710 0 1
+2693 0 3
+4148 82 25
+807 0 1
+85 1 1
+114 1 1
+489 10 0
+936 43 43
+6001 0 1
+3807 5 0
+191 14 14
+73 0 1
+345 2 0
+3436 3 0
+780 1 0
+6 1 0
+2268 0 1
+569 5 5
+1359 2 1
+1049 3 0
+371 1 0
+5832 1 1
+13 1 1
+4064 0 105
+776 3 2
+1696 1 1
+34 1 1
+5830 0 3
+3442 1 1
+61 1 1
+472 1 0
+22361 20 19
+3288 0 3
+10522 4 0
+16901 2 0
+30045 7 0
+1489 1 1
+72 1 1
+2260 0 2
+7033 0 4
+3592 0 1
+11101 0 1
+8476 0 1
+1324 0 2
+5438 5 0
+2061 1 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4746 9 9
+4767 7 7
+1225 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+249 43 43
+1178 0 4
+685 12 0
+48 8 0
+1701 1 1
+43 5 5
+862 18 18
+58 1 1
+66 1 1
+420 1 1
+44 1 1
+680 4 4
+1675 1 1
+83 1 1
+3082 4 0
+5467 1 1
+27 0 1
+1099 16 0
+627 12 12
+1317 6 1
+129 1 1
+25 1 1
+1397 15 15
+810 1 1
+27 1 1
+1192 2 0
+7515 4 0
+979 0 3
+3406 0 2
+1730 11 11
+1760 1 1
+26 1 1
+787 0 1
+1416 3 1
+22815 4 4
+126 1 0
+38 1 1
+140 1 0
+1072 0 15
+15438 4 0
+6165 0 1
+1768 1 0
+7727 2 0
+1514 0 1
+3116 0 1
+3278 1 1
+21 1 1
+1738 0 1
+8576 19 0
+8020 1 0
+2049 1 0
+528 3 1
+1704 1 1
+117 1 1
+1448 10 0
+4403 9 9
+1142 9 9
+1114 1 0
+1382 1 1
+32 1 1
+1519 11 11
+2877 0 2
+1221 0 1
+1974 4 0
+71 32 24
+565 1 0
+1447 1 0
+1362 0 4
+4579 0 1
+3278 0 1
+2020 1 1
+31 1 1
+673 1 0
+2321 9 9
+155 1 1
+18 1 1
+1427 1 0
+4008 1 1
+59 2 0
+1998 11 0
+942 1 1
+39 1 1
+2252 1 0
+6944 0 4
+342 1 1
+16 1 1
+4918 1 1
+30 1 1
+1530 0 1
+313 1 1
+59 1 1
+1737 1 1
+34 1 1
+852 9 12
+1814 0 5
+742 0 318
+10 1 1
+484 0 2
+993 0 1
+312 4 0
+23 1 1
+476 0 1
+195 2 0
+1963 1 1
+25 1 1
+1942 1 1
+26 0 1
+13516 0 3
+40 1 1
+1374 20 0
+31 1 1
+189 1 1
+26 1 1
+327 1 1
+38 1 1
+177 11 11
+709 1 1
+38 1 1
+1803 1 1
+26 1 1
+2373 5 0
+321 1 0
+933 17 17
+82 9 9
+2773 0 143
+80 1 1
+25 1 1
+467 1 1
+27 1 1
+143 1 1
+47 1 1
+1197 10 10
+1455 1 1
+33 1 1
+601 1 1
+48 0 2
+694 1 4
+132 1 1
+17 1 1
+167 6 6
+113 1 1
+31 1 1
+1181 0 1
+422 15 0
+36 1 1
+2219 1 1
+35 1 1
+2116 0 1
+15789 0 2
+24630 1 0
+7864 1 0
+13424 0 2
+12333 1 1
+41 1 1
+33759 6 0
+3090 1 1
+41 1 1
+2048 0 2
+462 1 0
+31504 22 0
+880 79442 79440
+1063 1 7
+1384 4 1
+85 1 0
+357 3 4
+9255 0 1
+6104 0 1
+6497 0 1
+713 0 4
+2181 2 0
+145 0 1
+1108 0 2
+1448 1 0
+1835 1 0
+4207 1 0
+5843 0 1
+1398 0 1
+5972 1 0
+7345 4 0
+2841 1 0
+361 1 0
+5438 0 1
+1889 0 3
+1737 2 0
+5252 2 0
+9241 0 10
+575 1 1
+30 2 2
+78 1 1
+49 1 1
+294 1 1
+37 1 2612
+385 17 17
+259 0 1
+107 32 32
+72 1 1
+29 1 1
+123 1 1
+121 1 1
+435 1 0
+32 1 1
+255 1 1
+52 1 1
+201 1 1
+59 0 2
+9 0 21
+72 0 2
+141 5 137
+425 1 1
+42 1 1
+572 1 1
+30 1 1
+560 1 1
+28 1 1
+98 0 12
+18 0 15
+144 13 13
+1410 1 0
+291 0 4
+1637 0 1
+231 1 1
+35 1 1
+2158 1 1
+21 1 1
+581 59 48
+181 4 0
+65 0 4
+603 3 0
+591 1 1
+23 1 1
+51 1 1
+38 1 1
+362 1 1
+44 1 1
+1935 0 2
+165 13 19
+1394 8 7
+450 7 0
+483 1 1
+27 1 1
+264 1 1
+51 1 1
+355 1 1
+45 1 1
+1717 0 4
+80 1 1
+18 1 0
+437 1 1
+38 1 1
+454 1 1
+40 1 1
+2320 1 1
+21 1 1
+161 1 1
+37 1 1
+1424 1 1
+48 1 1
+392 1 1
+35 1 1
+147 4 4
+436 1 1
+28 4 5
+144 3 0
+533 0 4
+437 1 9
+1714 0 1
+31 0 1
+850 16 16
+515 0 1
+58 1 1
+142 1 1
+33 1 1
+173 1 0
+753 1 1
+55 1 1
+573 0 4
+37 1 1
+144 8 8
+1004 0 4
+28 2 0
+153 15 15
+94 12 12
+201 12 13
+169 19 20
+118 10 15
+1254 0 2
+243 16 16
+73 1 1
+21 1 1
+196 0 28
+36 2 0
+18 1 1
+52 1 1
+29 1 1
+162 2 1
+373 1 0
+1159 0 32
+23 1 1
+674 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 1 0
+715 7 7
+89 1 0
+115 1 1
+31 1 1
+145 9 8
+350 6 6
+145 1 1
+41 1 1
+681 1 1
+43 1 1
+518 1 1
+19 1 1
+582 16 16
+180 6 6
+993 0 7
+9811 1 1
+27 1 1
+1374 1 0
+1705 13 13
+4591 1 1
+9 1 1
+5418 1 0
+5474 33 33
+1261 74 190
+19692 5 1
+1674 4 4
+42 1 1
+593 1 1
+24 1 1
+457 10 10
+414 13 13
+825 1 1
+41 1 1
+492 0 8
+1196 1 1
+23 1 1
+149 1 1
+18 1 1
+1145 6 4
+880 1 1
+35 1 1
+236 1 1
+67 1 1
+298 0 1
+147 14 14
+312 11 11
+99 1 1
+43 1 1
+469 1 1
+62 1 1
+288 0 1
+51 1 1
+22 1 1
+204 1 1
+39 1 1
+812 1 1
+57 1 1
+358 1 1
+128 1 1
+146 10 10
+490 1 1
+20 1 1
+62 1 1
+88 1 1
+135 1 1
+47 1 1
+109 1 1
+28 1 0
+20 1 1
+83 0 1
+90 1 1
+312 1 1
+44 1 1
+1213 1 1
+51 1 1
+473 1 1
+33 1 1
+122 14 0
+35 1 1
+485 14 14
+110 9 0
+127 1 1
+746 1 1
+40 1 1
+50 1 0
+1765 5 5
+773 1 2
+48 1 0
+1699 1 0
+293 1 1
+33 13 0
+7 7 27
+303 1 1
+16 1 1
+289 1 1
+23 1 1
+217 1 1
+42 1 1
+320 1 1
+44 1 1
+298 1 1
+7 4 0
+32 0 7
+14 1 0
+6 5 37
+272 6 0
+1071 8 8
+143 10 10
+522 8 13
+85 1 1
+49 0 1
+90 1 1
+85 1 1
+89 1 1
+568 1 0
+265 0 2
+501 1 1
+36 1 1
+330 0 1
+1365 23 16
+81 1 1
+36 1 1
+184 0 1
+465 1 1
+26 1 1
+139 1 1
+87 0 3
+298 1 1
+45 1 1
+118 1 1
+44 1 1
+1277 6 4
+129 0 496
+233 1 1
+73 1 1
+1947 0 4
+265 1 1
+25 1 1
+200 6 6
+93 1 1
+34 2 2
+98 3 0
+1010 15 15
+366 1 0
+610 1 1
+21 1 1
+422 6 0
+358 1 1
+51 1 1
+700 40 40
+127 1 1
+51 2 2
+395 13 13
+148 0 5
+119 1 1
+103 1 1
+268 1 1
+22 1 1
+251 1 1
+34 1 1
+175 1 1
+36 1 1
+239 1 1
+32 5 5
+63 1 1
+126 1 1
+209 1 1
+143 1 13
+175 7 17
+393 1 1
+44 1 1
+129 1 1
+84 1 1
+140 8 0
+90 6 8
+450 1 1
+25 1 1
+265 1 1
+35 0 1
+17 2 0
+428 1 1
+92 1 1
+697 1 1
+34 1 1
+955 1 1
+45 1 1
+95 1 1
+29 1 1
+660 1 1
+18 1 1
+389 9 9
+252 3 0
+284 1 1
+38 1 1
+81 9 9
+90 1 1
+71 1 1
+132 0 6
+96 1 1
+257 3 0
+56 1 1
+159 1 1
+44 1 1
+409 34254 40035
+275 1 1
+38 1 1
+1307 1 1
+26 1 1
+1467 1 1
+27 1 1
+568 11 11
+693 1 1
+47 1 1
+276 11 11
+183 1 1
+40 1 1
+589 1 1
+26 1 1
+4216 2 1
+170 17 17
+893 2 0
+24 1 1
+2666 4 4
+545 1 1
+76 1 1
+163 4 0
+141 1 1
+108 1 1
+165 1 1
+72 1 1
+167 1 1
+33 0 1
+42 0 2
+83 0 2
+60 1 1
+84 1 0
+383 2 0
+736 15 15
+770 13 13
+76 14 14
+410 1 1
+43 1 1
+542 1 1
+81 1 1
+111 8 4
+137 1 1
+37 1 1
+127 1 1
+34 0 3
+45 1 1
+269 2 2
+126 1 1
+259 26 26
+257 2 2
+14 1 1
+114 5483 21566
+75 1919 964
+70 30518 17325
+308 1 1
+49 1 1
+285 29 27
+223 10 8
+230 1 2
+69 12 12
+705 0 2
+187 2 1
+402 1 0
+656 0 2
+614 1 1
+43 1 1
+781 3 1
+55 13 19
+1083 5 5
+38 1 1
+62 1 1
+80 1 1
+1217 1 1
+44 1 1
+2070 27 27
+259 1 1
+40 1 1
+115 1 1
+56 4 4
+478 1 1
+30 1 1
+162 11 11
+209 10 0
+150 1 1
+36 0 2
+31 1 1
+55 1 1
+51 1 1
+221 8 13
+386 1 1
+58 1 1
+397 3 0
+45 1 1
+547 1 1
+21 1 1
+4446 4 0
+1282 1 1
+44 1 1
+8862 1 0
+4998 10 10
+6533 1 0
+1116 28 28
+9230 19 0
+741 0 1
+2695 0 1
+5382 1 0
+4424 21 21
+3562 0 1
+381 1072 0
+6066 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3902 17 4
+1895 1 1
+40 0 4
+1137 0 6
+205 2 0
+345 1 0
+1639 8 0
+686 5 0
+1032 0 1
+9206 0 4
+1574 1 0
+22388 1 0
+1656 2 0
+118 1 5
+4748 1 0
+2035 0 1
+1151 5 6
+1120 1 1
+20 1 1
+1533 16 0
+3103 0 1
+25 1 1
+2642 1 1
+43 0 3
+1703 0 1
+409 7 7
+527 1 0
+524 1 1
+59 1 1
+112 3 3
+50 1 1
+267 0 7
+286 14 14
+1161 2 0
+1003 0 1
+4062 1 0
+3850 4 0
+4977 0 1
+2718 1 0
+1588 1 1
+30 4 0
+879 0 1
+1332 18 12
+1688 4 4
+88 1 1
+439 2 0
+209 1 0
+1322 54 54
+893 1 1
+49 1 2
+1773 1 1
+24 1 1
+540 1 1
+41 1 1
+460 1 7
+165 1 1
+45 1 1
+903 1 2
+140 0 1
+36 1 1
+2019 0 1
+657 1 1
+48 1 0
+1329 0 1
+268 1 1
+47 1 1
+336 1 1
+25 2 0
+43 1 1
+1484 1 1
+53 1 1
+1151 1 1
+42 1 1
+1870 1 1
+24 5 5
+853 0 3
+23 0 1
+326 9 9
+131 9 9
+623 0 3
+34 1 1
+809 1 1
+36 1 1
+690 2 0
+44 1 1
+285 8 7
+455 1 1
+32 1 1
+102 1 1
+47 1 1
+4338 0 1
+5275 4 0
+11554 1 0
+409 16 17
+3476 0 1
+2160 0 24
+109 1 1
+3284 0 19
+2586 2 0
+757 1 1
+22 1 1
+860 17 24
+1584 1 0
+1582 0 2
+117 1 0
+1552 3 25
+17 0 4
+20 14 0
+42 9 0
+10 6 0
+10605 1 0
+4733 1 3
+371 4 0
+1177 1 1
+85 1 1
+40 0 1
+518 6 0
+646 13 13
+469 1 0
+1072 1 4
+565 1 1
+44 1 1
+3082 1 0
+839 1 0
+282 1 0
+597 0 6
+505 4 4
+45 1 1
+137 1 1
+43 1 1
+1294 1 1
+40 1 1
+572 0 5
+463 0 4
+1886 1 0
+548 1 0
+1300 0 3
+1839 2 0
+189 1 1
+49 1 1
+1253 1 1
+43 1 0
+498 1 1
+45 4 0
+3538 0 1
+1582 31 31
+376 14 14
+867 3 4
+253 1 1
+34 1 1
+172 2 0
+1094 0 1
+2856 1 1
+82 0 419
+125 3 0
+709 1 1
+36 1 1
+2189 16 17
+181 1 1
+109 0 1
+8 0 1
+53 1 1
+94 1 1
+49 1 1
+1495 15 0
+623 13 13
+163 1 1
+45 1 1
+2050 11 11
+474 1 1
+29 1 1
+1947 1 1
+42 1 0
+35 1 1
+751 1 0
+287 1 1
+60 1 1
+446 0 4
+2620 8 7
+1600 1 0
+11761 0 12
+3903 0 5
+4922 0 1
+1697 9 0
+379 0 1
+16104 1 0
+2244 0 14
+1780 1 1
+32 1 1
+9010 0 1
+296 0 1
+9862 0 1
+10107 1 0
+2415 11 9
+29829 0 12
+5348 0 1
+4837 0 1
+461 1 1
+37 1 1
+6200 4 0
+68 13 1
+2539 25 19
+1982 3 0
+5200 1 0
+162 0 9
+11963 1 1
+26 0 4
+206 1 0
+652 1 1
+27 1 1
+150 1 0
+1774 1 1
+18 1 1
+1410 4 4
+323 1 1
+64 5 5
+126 1 1
+28 1 1
+318 16 16
+579 1 1
+35 1 1
+206 1 1
+32 1 1
+50 1 1
+16 1 1
+279 1 1
+52 1 1
+167 16 16
+135 8 8
+802 1 1
+21 1 1
+278 1 1
+35 1 1
+663 1 1
+57 0 3
+29 1 0
+792 7 7
+111 1 1
+25 1 1
+387 1 1
+37 1 1
+55 1 1
+23 1 1
+623 1 1
+46 1 1
+494 1 1
+84 1 1
+276 0 2
+83 7 8
+114 1 1
+52 1 1
+48 0 1
+440 0 5
+101 1 1
+73 1 1
+329 0 2
+84 1 1
+41 1 1
+162 1 1
+29 1 1
+658 1 1
+28 1 1
+246 1 0
+155 28 28
+263 16 16
+1316 1 1
+29 1 1
+92 1 1
+30 1 1
+517 1 1
+23 1 1
+161 7 7
+668 1 1
+56 1 1
+761 1 1
+29 1 1
+276 16 16
+305 1 0
+546 3 5
+77 2 2
+45 0 2
+76 0 7
+18 1 1
+969 7 7
+84 0 3
+208 1 1
+25 1 1
+670 1 0
+179 0 1
+294 6 6
+578 1 1
+176 1 1
+216 1 1
+19 1 1
+142 4 4
+201 1 1
+34 1 1
+63 1 1
+49 1 1
+136 1 1
+112 0 1
+58 1 1
+46 1 0
+26 1 1
+80 0 3
+142 22576 22570
+400 1 1
+29 1 1
+982 0 2
+559 1 1
+59 1 1
+367 6 6
+288 1 1
+49 1 1
+193 1 1
+45 1 1
+183 16 16
+651 0 1
+136 1 1
+89 1 1
+341 14 14
+90 1 1
+151 1 1
+196 1 1
+66 1 1
+118 1 1
+55 1 1
+305 1 1
+81 1 1
+178 1 1
+18 1 1
+138 1 1
+103 1 1
+161 1 1
+27 1 1
+477 21 21
+417 2 2
+60 1 1
+51 1 1
+25 2 2
+231 1 1
+9 0 1
+24 1 1
+759 14 14
+107 1 1
+99 7 7
+236 1 1
+35 1 1
+121 1 1
+24 1 1
+92 0 2
+43 1 1
+68 1 1
+110 2 2
+52 1 1
+30 1 1
+201 1 1
+70 2 0
+99 1 1
+54 10 10
+125 0 1
+7 1 1
+132 18 25
+235 1 2
+189 1 1
+21 1 1
+278 1 1
+22 1 3
+22 1 1
+801 1 1
+51 1 1
+265 1 1
+84 1 1
+350 15 15
+259 1 0
+5 18 0
+368 1 1
+30 1 1
+840 1 1
+33 1 1
+490 1 1
+64 1 1
+1540 1 1
+37 1 1
+3927 1 1
+22 1 1
+316 0 5
+1069 0 2
+277 0 2
+69 14 0
+19 0 2
+31 2 0
+17 4 92
+2837 1 1
+197 2419 0
+840 1 1
+45 1 1
+176 1 0
+277 1 0
+1541 1 1
+17 1 1
+1434 18 22
+322 1 0
+193 0 1
+366 0 1
+493 1 0
+378 1 0
+1065 0 1
+4782 1 0
+656 13 13
+705 1 1
+49 0 3
+2315 0 3
+7693 2 0
+396 22 12
+918 0 1
+1126 0 4
+1210 1 1
+33 1 1
+326 1 1
+80 1 1
+288 8 17
+2671 0 1
+1244 1 1
+29 0 1
+2098 0 2
+24 4 0
+1207 4 4
+45 1 1
+175 34 34
+548 0 5
+1926 1 1
+40 1 1
+2657 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+713 0 4
+58 3 0
+1041 3 0
+36 1 1
+377 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+8168 1 1
+5 0 2
+18 1 0
+36 1 1
+99 2 0
+700 0 5
+148 0 1
+750 0 3
+40 1 1
+2428 0 1
+750 2 0
+473 0 2
+2032 1 0
+1184 2260 2258
+399 1 0
+560 1 0
+1108 1 0
+8087 1 0
+4298 0 2
+7581 1 1
+30 1 1
+4383 2 0
+10078 0 1
+906 4 0
+887 1 1
+80 1 1
+2210 1 0
+905 0 1
+1037 1 0
+5867 0 1
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 1 0
+700 1 1
+4220 0 1
+910 2 0
+687 0 1
+32877 1 0
+19299 0 8
+1369 29 0
+494 2 0
+6182 1 0
+12 1 1
+23175 14263 14261
+152 1 0
+8727 0 1
+9606 1 0
+15258 1 0
+5758 8 0
+3591 1 0
+5707 0 28
+6100 34700 34698
+298 0 1
+28 1 1
+118 1 1
+24 1 18
+34 1 1
+75 1 1
+43 2 2
+73 1 1
+29 1 1
+246 1 1
+42 1 1
+409 4 4
+1168 10 1
+310 1 1
+49 1 1
+3002 1 1
+38 1 1
+789 0 1
+63 9 9
+2434 0 8
+980 0 2
+749 8 8
+528 1 1
+24 1 1
+1646 15 15
+528 1 1
+16 1 1
+165 12467 12465
+758 1 1
+45 1 1
+213 8 0
+51 1 1
+107 10 11
+134 2 0
+228 103 1
+51 2 1
+68 1 1
+59 1 1
+195 1 161
+13 1 1
+553 2 2
+36 1 1
+143 1 0
+1874 4 0
+519 0 1
+476 1 0
+1530 0 1
+1126 2 0
+831 1 1
+40 1 1
+1131 88 87
+598 1 1
+41 1 1
+1422 0 2
+1950 1 1
+32 1 1
+2037 0 2
+178 2 1
+7938 164527 164525
+7881 0 3
+162 1 1
+39 0 1
+281 1 1
+46 1 1
+1703 1 0
+1253 1 1
+48 1 1
+538 0 2
+576 1 1
+21 1 1
+561 1 0
+3867 10 10
+200 1 1
+29 1 1
+201 2 0
+508 11 11
+1281 1 1
+35 1 1
+299 0 1
+588 1 0
+1231 25 0
+52 0 1
+419 1 0
+1601 6 6
+4040 2 0
+4924 0 1
+4749 1 1
+67 4 4
+39 1 0
+1116 3715 901
+205 2 0
+1591 5 2
+128 29 29
+802 0 89
+1600 0 6
+2177 0 3
+606 14 14
+519 1 0
+540 1 1
+40 1 1
+568 2 0
+458 1 1
+41 1 1
+1105 5 0
+58 1 5
+30 1 1
+558 1 0
+229 1 1
+42 1 1
+610 1 1
+115 1 1
+214 12 12
+237 9 7
+279 1 1
+49 0 2
+13 5 11
+86 1 1
+627 1 0
+473 0 4
+974 7 7
+717 1 1
+19 1 1
+531 1 1
+47 1 1
+372 0 2
+703 0 1
+35 1 1
+53 1 1
+46 1 1
+1322 0 1
+45 1 1
+148 1 1
+19 1 1
+1293 1 1
+44 0 1
+158 0 2
+153 1 0
+1027 21 21
+315 1 1
+48 1 1
+647 0 1
+104 1 1
+31 1 1
+1332 1 1
+63 5 5
+392 5 5
+127 5 5
+68 8 8
+66 1 1
+172 1 1
+156 1 1
+77 1 1
+192 1 1
+25 0 23
+57 0 24
+39 6 0
+34 1 1
+713 1 1
+33 1 0
+507 2 3
+90 4 0
+489 40 0
+63 5 1
+623 17 17
+353 14 14
+1743 1 1
+43 1 1
+1257 49 49
+698 1 1
+41 1 1
+109 1 0
+22 1 1
+288 1 1
+16 1 1
+267 2 1
+175 0 1
+121 1 0
+1158 2 0
+12 1 1
+392 29 12
+515 5 6
+583 1 1
+33 1 1
+616 16 16
+1050 0 10
+42 1 1
+184 1 1
+67 1 1
+102 7 7
+58 0 1
+307 1 1
+36 4 0
+20 24 0
+921 1 0
+913 1 0
+304 0 1
+77 0 1
+756 106 106
+272 1 1
+82 1 1
+56 2 0
+367 4 7
+602 6 6
+2102 9 9
+96 1 1
+45 0 5
+564 10 15
+154 1 0
+438 10 10
+38 0 5
+94 9 13
+2034 1 1
+25 1 1
+73 10 10
+70 5 5
+132 1 1
+52 1 1
+599 1 1
+46 1 1
+279 1 1
+18 1 1
+622 6 0
+224 0 1
+321 16 0
+1783 1 1
+18 2 0
+575 16 16
+60 1 1
+16 1 1
+609 1 1
+28 1 1
+781 3 0
+41 1 1
+57 8 8
+285 2 0
+717 1 1
+85 1 1
+402 0 4
+23 1 1
+64 1 1
+56 1 1
+1387 0 1
+972 4 1
+2390 1 2
+120 0 4
+11 1 1
+652 2 86
+42 0 1
+85 0 1
+22 1 1
+323 1 1
+39 1 1
+185 1 1
+53 4 0
+127 3 0
+703 2 0
+15 1 0
+619 1 1
+45 1 1
+442 16 19
+73 1 1
+25 1 1
+194 1 1
+65 1 1
+129 1 0
+201 49946 49944
+3358 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+498 3 0
+321 0 1
+281 3 0
+414 1 1
+70 1 1
+284 1 0
+214 1 1
+28 1 1
+930 1 1
+47 1 1
+1030 1 1
+91 1 1
+1538 0 1
+3268 1 0
+2180 1 0
+2256 14 14
+594 0 3
+1930 0 4
+3114 1 0
+3833 1 1
+32 1 1
+1073 0 1
+2092 1 0
+38 1 0
+327 2 0
+460 0 6
+8619 0 1
+463 10 12
+315 7 7
+1903 1 1
+18 5 0
+227 5 0
+162 1 1
+28 1 0
+1043 1 0
+29 1 1
+334 1 1
+37 1 1
+177 4 0
+46 0 1
+4 2 2
+484 7 7
+230 1 1
+37 1 1
+81 0 6
+160 1 1
+206 1 1
+356 6 6
+54 1 0
+1704 1 1
+85 1 1
+51 13 13
+207 1 1
+57 2 0
+20 4 7
+59 1 1
+40 1 1
+80 5 5
+16 1 1
+169 12 12
+125 5 5
+119 1 1
+98 1 1
+458 1 1
+26 1 1
+1064 1 1
+30 1 1
+227 0 14
+264 1 1
+44 1 1
+422 1 0
+317 0 6
+282 9 9
+762 8 8
+237 1 0
+199 0 1
+47 1 1
+496 0 3
+1097 4 0
+188 11 11
+143 5 0
+740 1 0
+558 1 1
+36 1 1
+98 1 1
+23 1 1
+232 1 1
+21 0 1
+244 1 1
+35 1 1
+620 1 1
+56 1 1
+470 1 1
+16 1 1
+540 1 1
+42 1 1
+90 1 1
+32 1 1
+110 2 0
+609 12 6
+17 5 1
+21 1 1
+352 2 0
+56 1 1
+175 1 1
+769 1 1
+78 1 1
+87 6 6
+586 0 1
+51 1 1
+92 1 1
+23 1 1
+195 73 72
+619 1 0
+53 1 1
+29 2 2
+357 1 1
+84 1 0
+516 1 1
+41 1 1
+107 11 11
+323 22 25
+114 1 0
+1881 2 0
+1560 2 0
+5260 6 0
+1103 0 4
+832 2 1
+2627 3 11
+34 1 1
+599 0 3
+65 1 1
+230 1 1
+18 1 1
+484 24 0
+150 1 1
+42 1 1
+184 1 1
+8 0 1
+27 1 1
+320 9 9
+376 1 1
+48 1 1
+266 1 1
+44 1 1
+113 1 1
+104 1 1
+297 0 1
+522 0 1500
+471 4 0
+32 1 0
+124 1 1
+46 1 1
+784 8 8
+68 1 1
+21 4 0
+193 7 7
+457 1 1
+23 1 1
+906 1 1
+78 1 1
+385 4 5
+344 1 1
+32 1 0
+669 6 0
+37 1 1
+127 1 1
+29 1 1
+60 5 5
+48 1 1
+290 0 2
+1482 1 1
+39 1 1
+114 1 1
+37 0 4
+104 1 1
+257 1 1
+130 15 16
+158 8 0
+57 1 1
+332 2 2
+35 1 1
+197 1 1
+44 1 1
+106 1 1
+77 1 1
+313 1 1
+44 1 0
+52 19983 20030
+61 7 7
+61 1 1
+120 1 1
+366 1 1
+55 1 1
+121 1 1
+62 1 1
+78 1 1
+48 1 1
+161 1 1
+26 1 1
+191 1 1
+20 11 11
+550 1 1
+76 1 0
+20 1 1
+112 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+83 1 1
+46 1 1
+1500 1 1
+81 1 1
+210 1 1
+26 1 1
+713 1 1
+48 1 1
+723 0 3
+196 6 6
+62 2 2
+32 1 1
+606 1 2
+357 1 1
+38 292 0
+589 1 1
+30 1 1
+714 8 8
+639 1 1
+20 1 1
+1068 0 1
+571 1 1
+49 1 1
+436 0 1
+609 0 2
+30 1 1
+66 0 1
+349 11 11
+65 1 1
+40 1 1
+717 0 3
+299 1 1
+29 1 1
+724 1 0
+275 1 1
+33 1 1
+318 0 3
+279 1 1
+28 1 1
+389 1 0
+548 0 8
+330 1 1
+47 1 1
+170 1 1
+47 1 1
+519 14 14
+841 24 24
+732 1 1
+29 3 3
+688 2 2
+23 0 1
+94 14 14
+726 13 13
+508 0 12
+21 6 0
+69 1 1
+37 1 1
+590 1 1
+59 1 1
+89 11 11
+164 1 1
+58 1 1
+1709 18 18
+520 1 1
+27 1 1
+683 10 10
+814 1 1
+26 1 1
+350 1 1
+39 1 1
+132 6 6
+439 1 1
+38 41 6
+15 0 1
+5 4 11
+81 1 1
+19 0 2
+167 1 1
+90 0 2
+85 1 1
+78 1 1
+87 19 2
+53 23 0
+255 0 1
+211 1 1
+54 1 1
+206 0 1
+60 35 33
+279 1 1
+76 179 180
+90 1 1
+119 3 0
+19 1 1
+60 1 1
+347 0 4
+30 2 2
+68 1 1
+78 1 1
+298 5 5
+67 1 1
+99 1 1
+97 1 1
+74 1 1
+52 1 1
+44 1 1
+65 1 4
+349 14 14
+109 1 1
+159 2 2
+214 9 9
+97 1 1
+73 1 1
+58 1 1
+42 1 1
+133 1 1
+99 0 10
+124 12 12
+281 3 0
+940 2 2
+49 1 1
+303 1 1
+25 1 1
+309 15 22
+384 1 1
+24 1 1
+896 1 1
+56 1 1
+168 0 19
+54 6 14
+66 1 1
+502 1 1
+4 0 1
+23 1 1
+581 1 1
+47 1 1
+122 15 15
+3352 1 1
+23 1 1
+873 4 4
+887 1 0
+1827 1 0
+216 6 6
+805 2 0
+874 8 0
+2274 1 1
+47 1 1
+736 25 29
+86 1 1
+19 1 1
+1794 9 9
+271 0 1
+2266 1 1
+34 1 1
+916 0 1
+21 1 1
+108 21 21
+141 1 1
+27 1 1
+406 3 0
+3830 59 59
+61 1 1
+38 1 1
+128 2 2
+56 1 1
+72 0 1
+96 1 1
+22 1 1
+169 7 7
+511 1 1
+38 1 1
+1070 1 1
+90 1 1
+50 1 1
+41 1 0
+30 1 1
+659 12 12
+701 1 1
+33 1 1
+569 15 15
+70 1 1
+38 1 1
+955 0 3
+130 1 1
+63 1 1
+251 8 8
+191 1 1
+26 0 3
+187 1 0
+916 5 1
+70 13 13
+498 1 0
+55 0 1
+242 25 25
+237 1 1
+20 0 1
+61 1 1
+203 6 6
+262 1 1
+154 1 1
+104 1 1
+20 1 1
+156 1 1
+32 1 1
+88 17 17
+139 13 13
+148 20156 20120
+885 1 1
+113 1 1
+141 2 0
+842 1 0
+1246 1 1
+29 1 1
+898 1 1
+19 1 1
+333 1 1
+44 1 1
+220 1 1
+56 2 0
+209 1 1
+70 1 1
+223 0 20
+182 1 1
+69 1 1
+56 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+195 1 1
+46 1 1
+101 8 8
+85 1 1
+50 0 4
+76 0 4
+53 3 1
+43 1 1
+153 1 1
+53 1 1
+195 6 0
+60 1 1
+278 1 0
+42 1 1
+298 1 1
+54 1 1
+262 4 4
+67 1 1
+32 1 0
+28 1 1
+612 1 1
+78 1 1
+157 1 1
+19 1 1
+64 1 2
+31 1 1
+52 1 1
+51 1 1
+77 10295 10251
+91 1 1
+35 1 1
+5232 1 1
+47 1 1
+295 2 0
+2065 2 0
+1143 13 13
+335 2 0
+1944 4 0
+39 6 0
+4057 5 8
+535 1 1
+16 1 1
+1555 0 1
+3130 1 1
+17 1 1
+4196 1 0
+14974 0 1
+3667 2 6
+42 22 0
+63 2 0
+15 2 0
+61 0 160
+66 1 14
+70 2 0
+25 44 4
+49 6 77
+18 0 6
+24 0 2
+57 143 3
+61 0 2
+29 20 0
+37 0 2
+29 0 74
+58 1 29
+34 1 5
+21 31 0
+12 0 65
+62 11 0
+5 0 41
+68 1 42
+23 1 3
+12 2 0
+17 1 29
+51 29 1
+6 2 0
+25 53 1
+52 2 0
+125 19 58
+124 41 0
+51 49 29
+79 89 0
+53 21 0
+5064 0 2
+6897 1 1
+38 1 1
+2821 0 1
+85 1 1
+31 0 4
+399 14 14
+408 0 1
+956 1 1
+29 1 0
+9 2 0
+442 4 0
+342 1 1
+24 1 1
+131 1 1
+198 1 1
+370 0 1
+34 1 1
+447 21 20
+259 1 1
+23 0 1
+121 2 0
+2257 1 1
+22 1 1
+811 1 1
+27 1 1
+484 0 1
+259 0 5
+843 0 2889
+55 0 88
+1189 2 0
+2276 1 0
+353 8 0
+7126 0 1
+798 1 1
+31 0 1
+6 1 1
+268 1 1
+27 1 1
+131 0 2
+47 1 1
+367 1 1
+61 1 1
+84 14 14
+173 15 15
+883 1 1
+41 1 1
+1356 1 1
+134 1 1
+62 1 1
+18 1 1
+644 1 1
+17 1 1
+297 15 14
+1015 26 26
+1532 4 0
+16 1 1
+183 1 0
+2792 12 12
+2660 0 2
+254 1 2
+1369 1 0
+342 0 1
+49 1 1
+733 0 1
+50 82 82
+60 1 1
+48 1 1
+1488 1 0
+97 1 1
+84 6 6
+214 1 1
+37 1 1
+222 1 1
+53 1 1
+220 58 0
+238 0 3
+459 1 1
+39 1 1
+222 1 1
+67 1 1
+280 1 1
+45 0 16
+208 1 1
+39 1 1
+135 1 1
+46 1 1
+121 1 1
+19 1 1
+349 1 1
+30 1 1
+56 1 1
+23 1 1
+283 1 1
+51 2 2
+217 1 1
+44 1 1
+92 1 1
+36 1 1
+67 1 1
+38 3 1
+23 4 0
+598 1 1
+45 1 1
+663 1 1
+59 1 0
+10 1 1
+70 1 1
+65 2 0
+11 0 16
+36 1 1
+342 17 17
+70 0 3
+243 1 1
+55 1 1
+63 17 17
+2165 5 2
+132 10 6
+136 18 13
+363 1 1
+89 1 1
+382 1 1
+29 1 1
+58 8 7
+297 4 0
+66 1 1
+93 1 0
+145 1 1
+31 5 5
+576 1 1
+89 1 1
+811 16 16
+428 0 13
+67 1 1
+193 2 2
+23 1 1
+51 1 0
+727 1 0
+1148 12 12
+837 1 1
+77 1 1
+941 10 10
+776 19 19
+300 1 1
+24 1 1
+256 1 7
+93 1 1
+188 17 13
+117 1 1
+43 1 1
+563 1 1
+104 4 4
+2898 1 1
+46 1 1
+282 1 1
+39 1 1
+698 1 1
+20 1 1
+140 1 1
+26 1 1
+745 0 2
+541 6 0
+1540 1 0
+781 1 1
+35 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+132 5 0
+555 1 1
+42 1 1
+573 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+13 1 7
+8319 1 0
+21899 0 1
+8703 0 1
+1206 0 1
+13954 0 1
+12475 1 0
+6716 0 1
+3072 0 4
+7591 0 1
+3322 9 10
+539 1 0
+1736 14 0
+3128 0 2
+4464 0 1
+120 4 4
+3473 1 0
+378 1 0
+576 5 9
+684 0 3
+1182 1 0
+654 0 3
+2049 1 0
+6838 1 1
+39 1 1
+186 1 0
+2718 1 1
+30 1 1
+160 11 11
+4954 0 1
+420 1 1
+123 1 1
+156 0 4
+219 4 0
+195 1 0
+4402 3 0
+3045 0 1
+1249 1 0
+3522 0 10
+808 5 1
+349 0 1
+8538 5 0
+455 1 0
+119 0 1
+1127 1 0
+276 1 0
+10672 1 0
+833 0 1
+4251 1 0
+8 1 1
+2079 0 1
+1736 8 11
+1612 0 1
+1373 5 0
+2438 4 0
+6147 7 0
+64 1 1
+3799 1 0
+258 2 0
+899 1 0
+1362 8 9
+593 0 2
+3351 2 0
+618 0 4
+917 0 3
+2797 2 0
+2776 2 0
+23968 6 0
+1616 0 1
+1686 0 4
+2221 0 8
+252 14783 14780
+11763 0 1
+2431 1 0
+158 0 1
+281 1 0
+1573 0 1
+11079 1 0
+6938 0 1
+4376 61201 59265
+14552 0 4
+672 1 1
+26 1 1
+461 1 1
+33 0 2
+16 1 1
+649 1 1
+48 1 1
+818 1 1
+21 1 1
+424 1 1
+25 1 1
+632 1 1
+39 1 1
+310 1 1
+27 1 1
+616 1 0
+17043 23170 23168
+104 7 6
+290 3 3
+117 13 0
+2194 0 1
+191 0 1
+118 1 0
+1283 7 7
+723 1 0
+7453 1 0
+3382 0 1
+2179 0 49
+5260 0 1
+4607 1 0
+32465 1 0
+1362 0 1
+20971 5 4
+11765 9 9
+746 11 11
+19671 17 17
+439 16 16
+9146 0 3
+99 1 1
+19 1 1
+259 1 1
+57 1 1
+202 1 1
+27 1 1
+2009 9 9
+2299 1 1
+43 1 1
+1287 1 0
+22328 5 0
+47 12 0
+1295 77056 62052
+228 0 2
+615 1 0
+1965 0 2
+1466 1 0
+3821 0 1
+2806 1 1
+110 0 1
+1422 0 1
+324 1 0
+1825 1 0
+311 0 1
+11796 1 0
+2273 2 1
+6123 1 0
+18640 29 29
+1283 0 3
+167 1 0
+11393 6 6
+708 15 14
+1887 10 0
+509 1 0
+1581 1 1
+46 1 1
+811 1 1
+31 0 1
+1557 43 43
+1172 1 1
+18 1 1
+67 1 0
+2081 0 2
+373 0 4
+1829 1 1
+56 0 1
+1700 0 4
+2886 2 0
+14416 1 0
+2137 1 0
+2717 0 1
+1587 0 1
+7106 8 0
+2428 1 1
+50 1 0
+1082 1 1
+42 1 1
+639 1 0
+717 11 11
+53 1 1
+61 1 1
+454 1 1
+26 1 1
+1053 1 1
+60 1 1
+51 1 1
+26 1 0
+102 1 1
+67 1 1
+71 1 1
+134 1 1
+85 1 1
+607 36 0
+58 1 1
+1266 2 0
+480 14 21
+1459 2 1
+435 15 17
+1204 30 0
+1762 2 0
+123 1 0
+3025 0 1
+771 1 0
+3211 0 1
+3410 13 0
+1260 1 0
+591 0 1
+1107 15 15
+5811 0 22
+4103 0 2
+4882 1 0
+2138 3 2
+2203 2 1
+2338 1 0
+3316 1 1
+27 2 0
+6360 0 1
+251 19 7
+6605 1 1
+23 2 0
+360 0 2
+1292 0 2
+3992 46 46
+554 0 21
+4473 2 3
+921 1 1
+47 1 1
+2605 9 3
+50 1 1
+178 1 1
+26 1 1
+316 0 2
+1120 4 0
+177 1 2
+960 1 1
+65 1 1
+964 4 4
+783 8 8
+61 34 13
+121 1 1
+22 1 0
+118 1 1
+49 4 4
+281 1 1
+27 1 1
+958 0 1
+107 1 1
+31 1 1
+171 14 14
+302 0 13
+33 1 1
+108 0 4
+98 1 1
+53 1 1
+457 2 0
+529 1 1
+37 2 0
+1829 1 1
+38 1 1
+440 1 1
+82 3 4
+647 45 45
+660 1 1
+28 1 1
+1993 0 1
+373 19 19
+835 1 1
+42 1 1
+947 1 1
+36 1 0
+1055 1 1
+43 1 1
+475 1 0
+60 1 1
+127 1 1
+509 1 1
+71 1 1
+485 1 0
+26 1 1
+531 1 1
+18 1 1
+551 1 1
+18 1 1
+884 5 5
+147 53 60
+527 1 1
+26 2 2
+322 0 17
+32 2 2
+85 1 1
+45 1 1
+625 0 323
+540 0 1
+43 1 1
+266 0 2
+228 1 1
+42 1 1
+283 1 1
+92 1 1
+381 1 1
+40 1 1
+1906 0 4
+3495 0 4
+967 1 1
+76 1 1
+3236 4 4
+529 7 7
+246 4 0
+38 1 1
+156 0 6
+1466 0 2
+499 1 0
+937 1 1
+45 1 1
+421 6 0
+87 22 22
+1254 1 1
+36 0 1
+357 18 18
+391 0 1
+451 1 0
+105 1 1
+47 1 0
+255 6 6
+739 3 0
+386 1 1
+33 1 1
+281 4 0
+481 2 0
+495 1 1
+42 4 0
+219 0 1
+408 1 1
+23 1 1
+283 1 1
+25 0 1
+541 1 0
+88 2 0
+216 1 1
+29 1 1
+457 1 0
+331 9 1
+199 15 15
+228 1 0
+4 2 0
+333 0 1
+19 1 1
+910 1 1
+27 1 1
+142 3 3
+35 1 1
+1211 1 1
+34 1 1
+667 0 2
+64 1 1
+78 1 1
+1519 1 1
+27 1 1
+154 14 14
+1090 1 1
+40 0 3
+35 1 1
+1355 0 4
+79 1 1
+145 1 1
+63 1 1
+70 1 1
+21 1 1
+695 1 1
+41 2 2
+564 1 1
+46 1 1
+279 4 0
+38 5 5
+3523 32 32
+545 1 1
+27 1 0
+54 15 16
+1212 0 14
+34 0 11
+787 2 0
+3691 1 0
+1843 1 1
+45 1 0
+11 1 2
+3499 1 1
+27 1 1
+1047 0 2
+1804 2 0
+1079 1 1
+17 1 1
+639 3 5
+73 1 1
+13 13 0
+66 1 1
+391 0 7
+4547 0 1
+53 9 6
+691 0 1
+989 1 1
+143 1 1
+223 0 2
+95 1 1
+1000 1 1
+41 1 1
+93 1 1
+49 1 1
+606 1 1
+48 1 1
+128 0 4
+109 1 31
+44 10 781
+62 4 0
+129 1 1
+62 1 1
+106 1 1
+247 1 1
+20 18 4
+125 1 1
+43 1 1
+909 0 2
+381 4 4
+74 1 1
+408 1 0
+1595 5 0
+3690 1 1
+64 1 1
+754 0 4
+1877 1 1
+49 1 1
+1095 11 0
+734 0 23
+3072 2 0
+1879 0 1
+572 0 8
+215 1 1
+58 1 1
+301 1 1
+42 1 1
+265 24 0
+209 11 11
+953 1 1
+42 0 5
+58 1 0
+95 1 0
+210 1 1
+27 1 1
+882 1 1
+17 1 1
+751 0 1
+24 1 1
+351 1 1
+43 3 3
+565 1 1
+15 1 1
+150 27 27
+94 1 0
+323 1 1
+23 1 1
+221 7 7
+705 15 0
+631 2 0
+64 1 1
+1577 1 1
+21 0 1
+354 0 9
+189 0 1
+283 1 1
+48 1 1
+227 1 1
+40 0 3
+1357 0 2
+1571 7 7
+1153 1 1
+93 1 1
+797 14 14
+433 8 0
+108 11 11
+140 1 1
+40 1 1
+470 1 1
+42 1 1
+1106 0 2
+84 4 4
+129 1 1
+123 1 0
+95 1 1
+82 0 3
+661 1 1
+77 1 1
+57 1 1
+62 1 1
+473 2 0
+262 6 0
+45 1 1
+49 3 0
+321 0 1
+197 2 104
+87 222 0
+115 0 10
+92 0 4
+108 6 0
+563 14 14
+324 1 0
+205 1 1
+17 1 1
+495 0 1
+201 4 0
+14 1 1
+1080 1 1
+24 1 1
+91 24 24
+279 1 1
+95 1 1
+121 1 1
+62 1 1
+2371 1 0
+164 9 1
+655 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+1780 2 0
+742 1 1
+40 1 1
+272 1 1
+52 1 1
+1187 1 1
+23 1 1
+254 1 1
+60 1 1
+176 3 6
+463 1 1
+36 1 1
+797 1 1
+22 1 1
+395 5 2
+61 1 1
+31 3 3
+226 1 1
+59 1 1
+581 1 1
+46 1 1
+412 1 1
+23 1 0
+74 1 1
+17 1 1
+81 1 1
+24 1 1
+83 15 15
+363 1 1
+91 1 1
+383 20 20
+199 13 13
+976 1 1
+39 0 3
+161 14 15
+127 16 16
+517 1 1
+132 1 1
+167 28 28
+124 1 1
+68 0 22
+1074 0 1
+175 1 0
+1018 1 1
+90 4 4
+1034 15 15
+69 1 1
+33 1 1
+174 1 1
+56 1 1
+169 1 0
+201 1 1
+30 1 1
+58 1 1
+38 1 1
+91 1 1
+98 4 4
+65 1 1
+19 2 0
+104 6 5
+25 1 1
+218 1 1
+37 1 1
+343 236832 150022
+67 8 8
+36 0 11
+62 1 1
+107 1 1
+68 3 130
+66 4 4
+50 21 21
+98 1 1
+127 1 0
+192 1 1
+71 1 1
+52 1 1
+200 1 1
+307 0 1
+331 1 1
+97 11 11
+171 1 1
+61 1 1
+37 1 1
+156 3 0
+63 0 3
+155 4 1
+31 2 0
+232 1 1
+33 1 1
+175 2 0
+131 6 6
+1409 0 3
+180 1 1
+65 0 1
+703 1 1
+19 1 1
+702 1 1
+65 1 1
+532 1 1
+48 1 1
+347 0 12
+578 16 17
+965 1 1
+45 1 1
+893 78201 80000
+406 1 1
+22 1 1
+462 1 1
+139 1 1
+154 1 0
+37 1 9
+11 2 0
+22 2 0
+14 46 22
+320 1 1
+117 1 1
+493 1 1
+129 1 1
+243 27 30
+170 1 1
+125 3 3
+2476 4 0
+27525 1 0
+2162 0 2
+2887 0 1
+17286 4 0
+22898 0 1
+51 9 9
+60 26 25
+312 15 11
+1008 17 17
+85 1 1
+49 1 1
+702 1 0
+87 1 1
+37 1 1
+859 8 8
+296 4 4
+105 0 4
+43 1 1
+67 10 7
+2839 3 0
+1283 1 1
+67 0 1
+32 2 0
+61 1 1
+140 15 15
+1047 1 1
+38 1 1
+87 1 1
+24 5 4
+1291 1 1
+49 1 1
+421 0 1
+75 1 1
+78 1 1
+243 1 0
+33 1 1
+116 19 19
+65 0 1
+238 0 1
+179 2 1
+67 1 1
+60 1 1
+32 1 1
+677 4 6
+83 314 0
+334 1 0
+1018 5 5
+127 1 1
+83 1 1
+347 0 2
+111 1 1
+30 1 1
+66 1 1
+38 1 1
+218 8 8
+754 1 1
+65 1 1
+182 1 1
+21 1 1
+285 1 1
+75 1 1
+147 6 0
+65 1 1
+42 1 1
+380 1 1
+84 2 0
+88 1 1
+25 1 1
+210 1 1
+17 1 1
+136 6 5
+108 1 1
+40 1 0
+50 1 1
+111 1 0
+21 0 1066
+119 0 1
+2641 1 1
+22 1 1
+689 1 1
+41 1 1
+1415 1 1
+29 1 1
+2252 1 1
+19 1 1
+1524 0 10
+2104 0 1
+511 2 0
+1696 26 8
+2593 0 177
+338 1 1
+37 2 2
+395 10 0
+67 1 1
+131 1 1
+31 1 1
+386 1 1
+42 1 1
+372 1 1
+48 1 1
+8705 0 4
+329 9 9
+600 2 0
+261 8 8
+9909 0 2
+2337 2 0
+2567 1 1
+26 1 1
+561 1 1
+48 1 1
+2440 1 1
+30 1 1
+1289 0 1
+162 1 0
+730 0 3
+658 1 0
+25 1 1
+1027 1 1
+43 1 1
+472 0 1
+219 1 1
+20 1 1
+495 1 0
+6 2 0
+1007 0 1
+169 0 10
+33 1 1
+266 11 11
+752 1 1
+30 1 1
+438 1 1
+39 1 1
+511 0 1
+1247 1 0
+1055 1 0
+491 1 0
+108 1 1
+48 1 1
+1324 0 1
+143 1 1
+40 1 1
+679 1 1
+45 1 1
+1036 0 2
+58 1 1
+46 1 1
+229 16 16
+149 10 10
+94 1 1
+63 1 1
+222 2 0
+55 1 1
+115 5 1
+219 15 15
+692 28 28
+159 1 1
+41 1 1
+211 1 0
+20 1 1
+1099 0 4
+155 6 0
+178 13 15
+32 1 1
+953 1 1
+47 1 1
+174 1 1
+22 1 1
+402 0 12
+588 5 21
+288 4 4
+86 1 1
+29 0 2
+67 3 0
+641 0 1
+571 0 1
+250 1 1
+34 1 1
+255 0 2
+572 12 12
+275 6 1
+974 0 1
+578 12 12
+612 1 1
+43 1 1
+56 0 7
+1170 0 1
+1242 0 8
+2108 5 0
+1090 0 2
+4424 1 1
+34 1 1
+4897 8 0
+1998 2 0
+114 0 1
+2874 1 1
+21 1 1
+442 22 22
+805 0 1
+3476 16 0
+7063 0 1
+65 3 0
+7475 0 4
+9515 5 1
+172 1 1
+49 1 1
+1349 22 22
+9662 2 0
+4856 3 0
+7447 6 6
+421 1 0
+884 6 0
+17 1 0
+3075 1 0
+11403 50004 0
+1397 12 12
+1859 3 1
+3762 2 0
+601 2 0
+7617 1 0
+1604 0 16
+3589 0 1
+1487 2 1
+1196 0 20
+2233 1 0
+192 4 4
+1470 9 27
+880 1 12
+2490 1 0
+151 1 1
+33 1 1
+2191 1 1
+47 1 1
+572 1 1
+17 1 1
+512 1 1
+83 1 1
+107 0 1
+4191 1 1
+36 1 1
+1530 1 1
+23 1 1
+311 0 4
+47 1 1
+141 2 0
+73 1 1
+330 1 1
+54 0 1
+32 0 1
+210 4 0
+219 1 0
+24 1 1
+425 1 1
+34 2 2
+1227 11 11
+2454 1 1
+36 1 1
+1368 1 1
+39 1 1
+134 1 1
+28 1 1
+123 1 1
+46 4 4
+839 9 0
+1244 1 1
+32 5 5
+2063 12 0
+357 3 0
+321 46 46
+873 1 1
+47 1 1
+1156 10 9
+1180 9 1
+271 9 9
+1870 0 1
+17 1 0
+366 7 7
+101 0 1
+134 8 8
+1654 0 4
+8741 1 1
+24 1 1
+1003 0 186
+12 0 20
+906 13 13
+1313 241 241
+2062 16 16
+1485 1 1
+18 1 1
+883 1 1
+20 1 1
+1354 1 1
+28 1 1
+283 5 5
+640 1 1
+40 1 1
+560 1 1
+42 1 1
+1144 19 19
+57 1 1
+21 1 1
+216 1 1
+109 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 40 40
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 5 5
+23 1 1
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+5071 0 35
+42407 0 26
+13084 15 11
+333 5 0
+1235 6 6
+899 1 0
+1077 11 0
+1521 1 0
+38 1 1
+135 1 1
+42 1 1
+63 4 3
+385 1 1
+49 1 1
+77 20 22
+111 11 11
+190 2 2
+45 1 1
+373 1 1
+47 1 1
+77 10 10
+186 1 1
+24 1 1
+855 1 0
+23 1 1
+86 27 27
+148 1 0
+249 1 1
+22 1 1
+88 1 1
+31 1 1
+816 0 331
+433 1 1
+31 1 1
+53 1 1
+27 1 1
+101 1 1
+29 1 1
+406 1 1
+43 1 1
+306 1 1
+25 0 5
+68 1 1
+727 7 7
+237 1 1
+65 1 1
+178 1 1
+52 1 1
+667 1 1
+17 1 1
+359 1 1
+22 1 1
+1244 1 1
+36 1 1
+1349 29808 29806
+7637 1 1
+37 1 1
+1019 0 1
+10399 0 1
+10494 21750 21748
+607 26 26
+5347 2 0
+2375 3 0
+1594 1 0
+363 4 0
+2394 2 0
+3590 0 2
+2891 1 0
+621 1 0
+563 0 2
+85 0 13
+160 18 19
+1807 0 2
+291 0 1
+2273 8 0
+2568 1 0
+657 0 1
+772 4 0
+377 8 0
+62 52 0
+778 0 1
+391 62 72
+1596 2 0
+1317 2 0
+5358 0 3
+2273 0 1
+597 0 8
+993 0 26
+1897 1 0
+76 0 1
+966 1 0
+2611 2 0
+1374 18 0
+831 33 33
+1574 0 2
+306 0 1
+4789 0 3
+2404 1 1
+33 1 1
+507 4 0
+1627 50858 50856
+7863 53819 53813
+259 1 0
+752 3 1
+497 5 6
+3113 3 0
+748 1 0
+3002 0 1
+836 1 1
+22 1 0
+251 1 1
+27 1 1
+4128 0 1
+8869 29 0
+4065 0 2
+19869 0 1
+564 1 0
+4734 1 1
+36 1 1
+5630 1 0
+339 0 3
+1029 12 12
+15996 0 3
+1380 6 6
+57 0 1
+6265 14 14
+127 1 1
+21 1 1
+1709 1 1
+131 1 1
+64 9 9
+67 0 2
+290 23 22
+456 1 0
+587 0 1
+1610 0 2
+1243 1 0
+26 1 1
+2049 0 1
+1091 0 21
+357 11 14
+90
+
+chain 125812 chr6_ssto_hap7 4928567 + 3907506 3911494 chr4 191273063 + 128070000 128074446 1022492
+87 39 39
+217 93 93
+54 128 128
+101 185 185
+82 24 24
+306 274 274
+86 19 19
+109 42 42
+79 311 313
+96 87 87
+72 74 530
+57 170 170
+64 268 268
+56 709 709
+99
+
+chain 123442 chr6_ssto_hap7 4928567 + 3929629 3931354 chr2 242951149 - 63927014 63946734 1041108
+108 1 1
+44 0 2
+39 0 554
+170 0 2655
+81 3 3007
+63 15 1052
+119 0 1562
+96 0 5290
+67 9 9
+97 0 3890
+317 1 1
+39 1 1
+234 0 4
+116 1 1
+18 3 0
+83
+
+chain 92865 chr6_ssto_hap7 4928567 + 3892702 3894943 chr5 180857866 - 117045391 117059708 1366079
+75 6 6
+69 60 59
+68 1 0
+272 118 118
+148 29 29
+50 4 4
+75 91 91
+79 11 11
+52 94 94
+155 362 12440
+253 93 93
+76
+
+chain 86945 chr6_ssto_hap7 4928567 + 4078541 4079510 chr17 78774742 - 73855076 73856044 1454888
+79 12 12
+357 1 1
+20 1 1
+121 1 0
+377
+
+chain 80740 chr6_ssto_hap7 4928567 + 2343665 2344522 chr6 170899992 - 139781917 139782778 1563240
+341 0 4
+516
+
+chain 52870 chr6_ssto_hap7 4928567 + 2557772 2559707 chr1 247249719 + 7396445 7398379 2394598
+102 170 170
+115 745 743
+132 82 82
+58 214 214
+173 73 74
+71
+
+chain 47213 chr6_ssto_hap7 4928567 + 3973739 3974661 chr5 180857866 + 134244858 134245983 2704507
+144 28 28
+67 90 94
+193 60 61
+52 141 339
+53 41 41
+53
+
+chain 45302 chr6_ssto_hap7 4928567 + 4047815 4048319 chr5 180857866 - 98127286 98127790 2833261
+202 1 1
+153 1 1
+147
+
+chain 41978 chr6_ssto_hap7 4928567 + 1328154 1328662 chr6 170899992 + 30106460 30106967 3091365
+343 49 48
+116
+
+chain 40676 chr6_ssto_hap7 4928567 + 3875056 3875551 chr11 134452384 - 84966990 84967480 3207740
+246 1 1
+93 33 28
+122
+
+chain 35112 chr6_ssto_hap7 4928567 + 3906419 3911395 chr6 170899992 - 169520190 169525607 1043651
+51 464 464
+53 202 202
+87 154 151
+74 492 483
+28 798 798
+12 65 65
+50 80 80
+67 619 621
+27 1627 2078
+26
+
+chain 32670 chr6_ssto_hap7 4928567 + 3859757 3860527 chrX 154913754 + 119403135 119403904 4176412
+56 142 141
+152 178 178
+66 56 56
+120
+
+chain 29091 chr6_ssto_hap7 4928567 + 3895286 3896158 chr11 134452384 + 7157531 7158401 1526824
+161 614 612
+97
+
+chain 28481 chr6_ssto_hap7 4928567 + 4205119 4205417 chr17 78774742 + 29063769 29064067 5407271
+298
+
+chain 27018 chr6_ssto_hap7 4928567 + 3840659 3840971 chr18 76117153 - 36956533 36956845 6049052
+120 15 15
+177
+
+chain 25604 chr6_ssto_hap7 4928567 + 3994310 3994584 chr15 100338915 - 55375038 55375312 6715162
+274
+
+chain 23990 chr6_ssto_hap7 4928567 + 1194494 1195270 chr7 158821424 - 51137320 51138262 7695545
+178 101 101
+72 385 551
+40
+
+chain 23269 chr6_ssto_hap7 4928567 + 4043201 4044141 chr6 170899992 + 32821586 32822354 8132442
+218 672 500
+50
+
+chain 22259 chr6_ssto_hap7 4928567 + 1328662 1328894 chr10 135374737 + 129836641 129836873 8045146
+232
+
+chain 21089 chr6_ssto_hap7 4928567 + 3982819 3983044 chr14 106368585 + 105956394 105956619 9616367
+225
+
+chain 21066 chr6_ssto_hap7 4928567 + 4492538 4492777 chr8 146274826 + 14484871 14485110 2051461
+239
+
+chain 19470 chr6_ssto_hap7 4928567 + 3875397 3875736 chrX 154913754 - 111580561 111580900 4149836
+32 122 122
+185
+
+chain 19015 chr6_ssto_hap7 4928567 + 4093694 4093926 chr11 134452384 + 111558067 111558299 11259779
+149 20 20
+63
+
+chain 18910 chr6_ssto_hap7 4928567 + 3979875 3980839 chr6 170899992 + 32656485 32657452 11346766
+153 738 741
+73
+
+chain 18705 chr6_ssto_hap7 4928567 + 4047429 4047645 chr3 199501827 + 1828236 1828452 4490189
+145 5 5
+66
+
+chain 15452 chr6_ssto_hap7 4928567 + 3913430 3913596 chrX 154913754 + 67920599 67920765 14594390
+166
+
+chain 15351 chr6_ssto_hap7 4928567 + 2675966 2676167 chr11 134452384 + 74426248 74426449 14701293
+99 26 26
+76
+
+chain 15233 chr6_ssto_hap7 4928567 + 4047645 4047815 chr9 140273252 + 78741245 78741415 2998928
+170
+
+chain 15018 chr6_ssto_hap7 4928567 + 1260636 1260812 chr10 135374737 + 90412720 90412896 15044285
+117 3 3
+56
+
+chain 13654 chr6_ssto_hap7 4928567 + 180964 181124 chr18 76117153 - 3498140 3498418 7857183
+83 1 1
+24 4 122
+48
+
+chain 13627 chr6_ssto_hap7 4928567 + 3831356 3831761 chr6 170899992 + 32665471 32665876 16657612
+57 86 85
+47 147 148
+68
+
+chain 13048 chr6_ssto_hap7 4928567 + 3955374 3955802 chr2 242951149 + 206984071 206984490 17422582
+94 272 263
+62
+
+chain 12923 chr6_ssto_hap7 4928567 + 3954673 3954823 chr18 76117153 - 36956845 36956995 17596042
+150
+
+chain 12671 chr6_ssto_hap7 4928567 + 4090259 4090393 chrX 154913754 - 65797896 65798030 17982401
+134
+
+chain 12395 chr6_ssto_hap7 4928567 + 3983294 3983607 chrX 154913754 - 110185784 110186095 13720297
+4 222 220
+87
+
+chain 12272 chr6_ssto_hap7 4928567 + 2565285 2565441 chrX 154913754 + 154847615 154847763 18572104
+71 1 1
+25 8 0
+51
+
+chain 12207 chr6_ssto_hap7 4928567 + 3955802 3957116 chr4 191273063 - 84720316 84722799 17649000
+5 186 1341
+68 1003 1017
+52
+
+chain 12179 chr6_ssto_hap7 4928567 + 3836462 3836590 chr6 170899992 + 32566069 32566197 18716373
+128
+
+chain 12178 chr6_ssto_hap7 4928567 + 4018814 4018980 chr14 106368585 - 58343221 58343386 18718222
+55 26 25
+85
+
+chain 12137 chr6_ssto_hap7 4928567 + 3877094 3877505 chr7 158821424 + 90920405 90920810 18779047
+54 266 260
+91
+
+chain 11985 chr6_ssto_hap7 4928567 + 3892853 3894867 chr3 199501827 - 92708356 92711059 1441087
+59 394 394
+65 307 307
+90 391 391
+54 622 1311
+32
+
+chain 11952 chr6_ssto_hap7 4928567 + 4105293 4105419 chr4 191273063 - 72853862 72853988 19072608
+126
+
+chain 11593 chr6_ssto_hap7 4928567 + 3812675 3812798 chr1 247249719 - 238369051 238369174 19677686
+123
+
+chain 11535 chr6_ssto_hap7 4928567 + 1260812 1261322 chr1 247249719 - 129350638 129351114 18024798
+7 405 371
+98
+
+chain 11457 chr6_ssto_hap7 4928567 + 3994790 3994923 chr3 199501827 - 53316844 53316977 14718915
+32 6 6
+95
+
+chain 11393 chr6_ssto_hap7 4928567 + 4065042 4065262 chr10 135374737 - 122210308 122210526 20025571
+60 86 84
+74
+
+chain 11122 chr6_ssto_hap7 4928567 + 1240573 1241390 chr6 170899992 - 139553083 139553887 20511868
+77 676 663
+64
+
+chain 10873 chr6_ssto_hap7 4928567 + 1229721 1229842 chr19 63811651 + 15986631 15986752 20965590
+121
+
+chain 10852 chr6_ssto_hap7 4928567 + 2675511 2675627 chr15 100338915 - 60167597 60167713 16273330
+116
+
+chain 10686 chr6_ssto_hap7 4928567 + 2564433 2564954 chr18 76117153 + 11332173 11332695 21332096
+80 388 389
+53
+
+chain 10631 chr6_ssto_hap7 4928567 + 3935233 3935343 chr12 132349534 - 69483966 69484076 21446055
+110
+
+chain 10605 chr6_ssto_hap7 4928567 + 1188476 1188620 chr6 170899992 + 30566919 30567064 21497459
+81 23 24
+40
+
+chain 10522 chr6_ssto_hap7 4928567 + 3885687 3885969 chr6 170899992 + 32650612 32650898 21668161
+51 155 159
+76
+
+chain 10487 chr6_ssto_hap7 4928567 + 3763802 3763912 chr6 170899992 + 32525095 32525205 21738406
+110
+
+chain 10446 chr6_ssto_hap7 4928567 + 3838076 3838188 chr10 135374737 + 116791472 116791584 21828224
+112
+
+chain 10440 chr6_ssto_hap7 4928567 + 3816404 3816534 chr3 199501827 - 53390365 53390495 21843020
+67 9 9
+54
+
+chain 10424 chr6_ssto_hap7 4928567 + 1233358 1233620 chr1 247249719 - 93388912 93389184 21873908
+71 137 147
+54
+
+chain 10414 chr6_ssto_hap7 4928567 + 3814490 3814706 chr20 62435964 - 30230151 30230368 21892854
+65 92 93
+59
+
+chain 10301 chr6_ssto_hap7 4928567 + 3898517 3899557 chr6 170899992 + 32656523 32657565 22135092
+82 902 904
+56
+
+chain 10251 chr6_ssto_hap7 4928567 + 3994584 3994790 chr1 247249719 - 4492483 4492689 9976242
+1 153 153
+52
+
+chain 10098 chr6_ssto_hap7 4928567 + 3860255 3860748 chr12 132349534 - 132021867 132022360 5505364
+30 66 66
+56 251 251
+90
+
+chain 10097 chr6_ssto_hap7 4928567 + 3816034 3816270 chr6 170899992 - 10896454 10896689 22596963
+52 115 114
+69
+
+chain 10009 chr6_ssto_hap7 4928567 + 1180658 1180788 chr7 158821424 - 7754727 7754857 22790797
+54 14 14
+62
+
+chain 9863 chr6_ssto_hap7 4928567 + 4074075 4074200 chr1 247249719 + 10410145 10410270 23122655
+62 11 11
+52
+
+chain 9833 chr6_ssto_hap7 4928567 + 1235234 1235338 chr6 170899992 - 141000130 141000234 23192992
+104
+
+chain 9829 chr6_ssto_hap7 4928567 + 3815276 3815381 chr2 242951149 - 95164602 95164707 23200543
+105
+
+chain 9703 chr6_ssto_hap7 4928567 + 4070399 4070911 chr2 242951149 - 75663422 75663931 23509887
+63 390 387
+59
+
+chain 9614 chr6_ssto_hap7 4928567 + 2657013 2657750 chr6 170899992 - 140934793 140935541 23727231
+66 613 624
+58
+
+chain 9528 chr6_ssto_hap7 4928567 + 1196742 1197179 chr6 170899992 + 29878108 29878543 23937753
+59 318 316
+60
+
+chain 9448 chr6_ssto_hap7 4928567 + 4048489 4048611 chr8 146274826 - 73050790 73050912 12492975
+122
+
+chain 9438 chr6_ssto_hap7 4928567 + 3910395 3911369 chr15 100338915 - 30464954 30465929 1082363
+106 42 42
+63 674 675
+89
+
+chain 9407 chr6_ssto_hap7 4928567 + 3856752 3857141 chr6 170899992 + 32635022 32635416 24217249
+67 271 276
+51
+
+chain 9325 chr6_ssto_hap7 4928567 + 3877913 3878051 chr5 180857866 - 41992384 41992522 24382359
+55 28 28
+55
+
+chain 9223 chr6_ssto_hap7 4928567 + 4072536 4072675 chr3 199501827 + 115197797 115197935 24583947
+54 29 28
+56
+
+chain 8918 chr6_ssto_hap7 4928567 + 3893253 3894424 chr9 140273252 - 41262761 41263931 1574906
+43 979 978
+149
+
+chain 8559 chr6_ssto_hap7 4928567 + 1185037 1185127 chr6 170899992 + 29901402 29901492 25589405
+90
+
+chain 8551 chr6_ssto_hap7 4928567 + 3829560 3829651 chrX 154913754 + 101188135 101188226 25594732
+91
+
+chain 8473 chr6_ssto_hap7 4928567 + 3956061 3956256 chr9 140273252 + 73803578 73803773 19960547
+18 127 127
+50
+
+chain 8431 chr6_ssto_hap7 4928567 + 4017811 4017899 chr6 170899992 - 67344251 67344339 25766641
+88
+
+chain 8320 chr6_ssto_hap7 4928567 + 4046958 4047055 chr3 199501827 + 112943953 112944050 15335436
+35 7 7
+55
+
+chain 8195 chr6_ssto_hap7 4928567 + 1189357 1189443 chr6 170899992 + 29906107 29906193 26123218
+86
+
+chain 7977 chr6_ssto_hap7 4928567 + 3854972 3855056 chr3 199501827 - 65120650 65120734 26447349
+84
+
+chain 7864 chr6_ssto_hap7 4928567 + 3956899 3957064 chr2 242951149 + 230690248 230690413 23687196
+65 86 86
+14
+
+chain 7746 chr6_ssto_hap7 4928567 + 4069960 4070399 chr1 247249719 + 17543299 17543737 25591741
+58 375 374
+6
+
+chain 7672 chr6_ssto_hap7 4928567 + 3894447 3895071 chr11 134452384 + 90348791 90349415 1473761
+74 253 253
+37 159 159
+101
+
+chain 7498 chr6_ssto_hap7 4928567 + 3878051 3879311 chr1 247249719 + 173341048 173342322 26722357
+5 1190 1204
+65
+
+chain 7331 chr6_ssto_hap7 4928567 + 4098258 4098335 chr16 88827254 - 31115279 31115356 27543534
+77
+
+chain 7232 chr6_ssto_hap7 4928567 + 3920814 3920891 chr6 170899992 + 32620027 32620104 27728494
+77
+
+chain 7168 chr6_ssto_hap7 4928567 + 4075613 4075689 chr1 247249719 - 67121697 67121773 27863207
+76
+
+chain 7154 chr6_ssto_hap7 4928567 + 3982483 3982643 chrX 154913754 + 57427313 57427473 11452806
+160
+
+chain 6975 chr6_ssto_hap7 4928567 + 1189014 1189086 chr6 170899992 + 29905761 29905833 28257011
+72
+
+chain 6949 chr6_ssto_hap7 4928567 + 3816604 3816677 chr8 146274826 - 83195506 83195579 28299872
+73
+
+chain 6859 chr6_ssto_hap7 4928567 + 3943496 3943569 chr6 170899992 + 32632193 32632266 28469740
+73
+
+chain 6788 chr6_ssto_hap7 4928567 + 4050963 4058824 chr6 170899992 + 32827127 32834907 28622110
+50 4319 3617
+61 2525 2695
+93 658 1109
+155
+
+chain 6731 chr6_ssto_hap7 4928567 + 1724741 1724812 chrX 154913754 + 77548522 77548593 28736593
+71
+
+chain 6723 chr6_ssto_hap7 4928567 + 3873757 3873829 chr6 170899992 + 32566306 32566378 28747170
+72
+
+chain 6686 chr6_ssto_hap7 4928567 + 1260394 1260465 chr10 135374737 - 59340781 59340852 28859379
+71
+
+chain 6665 chr6_ssto_hap7 4928567 + 3154699 3154769 chr19 63811651 - 18495515 18495585 1124045
+70
+
+chain 6650 chr6_ssto_hap7 4928567 + 3860923 3861067 chr11 134452384 - 10112929 10113073 19771550
+33 61 61
+50
+
+chain 6622 chr6_ssto_hap7 4928567 + 3829455 3829525 chr2 242951149 - 225543946 225544016 28987379
+70
+
+chain 6618 chr6_ssto_hap7 4928567 + 3895820 3896010 chr13 114142980 + 101977588 101977777 1936459
+53 63 62
+74
+
+chain 6613 chr6_ssto_hap7 4928567 + 3829110 3829180 chrX 154913754 + 79202976 79203046 29019460
+70
+
+chain 6584 chr6_ssto_hap7 4928567 + 3973978 3974052 chr18 76117153 - 4274607 4274681 4481992
+74
+
+chain 6521 chr6_ssto_hap7 4928567 + 3924035 3924103 chr6 170899992 + 32624377 32624445 29251175
+68
+
+chain 6513 chr6_ssto_hap7 4928567 + 4073124 4073193 chr12 132349534 + 47073126 47073195 29262428
+69
+
+chain 6459 chr6_ssto_hap7 4928567 + 2661634 2661703 chr6 170899992 + 31350859 31350928 29378029
+69
+
+chain 6412 chr6_ssto_hap7 4928567 + 3941116 3941183 chr5 180857866 - 156512753 156512820 29524988
+67
+
+chain 6368 chr6_ssto_hap7 4928567 + 2565193 2565285 chr6 170899992 - 132294381 132294479 20980272
+55 29 35
+8
+
+chain 6368 chr6_ssto_hap7 4928567 + 4074498 4074566 chr21 46944323 + 22987814 22987882 29601883
+68
+
+chain 6359 chr6_ssto_hap7 4928567 + 3988556 3988624 chr6 170899992 + 32661355 32661423 29618339
+68
+
+chain 6278 chr6_ssto_hap7 4928567 + 3866522 3866590 chr6 170899992 + 32559120 32559188 29828351
+68
+
+chain 6275 chr6_ssto_hap7 4928567 + 1183919 1183984 chr6 170899992 + 29900614 29900679 29842805
+65
+
+chain 6265 chr6_ssto_hap7 4928567 + 3855056 3855122 chr11 134452384 + 35675446 35675512 27404543
+66
+
+chain 6240 chr6_ssto_hap7 4928567 + 3829386 3829452 chr7 158821424 + 89136765 89136831 29917662
+66
+
+chain 6231 chr6_ssto_hap7 4928567 + 4071456 4071522 chr15 100338915 + 41279078 41279144 29959209
+66
+
+chain 6221 chr6_ssto_hap7 4928567 + 4068934 4068999 chr5 180857866 + 81769172 81769237 29991772
+65
+
+chain 6158 chr6_ssto_hap7 4928567 + 3881593 3881658 chr8 146274826 + 95080661 95080726 30127973
+65
+
+chain 6116 chr6_ssto_hap7 4928567 + 3859885 3859954 chr6 170899992 - 133628666 133628735 10717008
+69
+
+chain 6039 chr6_ssto_hap7 4928567 + 3985075 3985138 chr6 170899992 + 32660531 32660594 30469869
+63
+
+chain 5986 chr6_ssto_hap7 4928567 + 4018730 4018794 chr1 247249719 - 129681820 129681884 30582101
+64
+
+chain 5986 chr6_ssto_hap7 4928567 + 3949638 3949702 chr6 170899992 + 32601206 32601270 30582240
+64
+
+chain 5977 chr6_ssto_hap7 4928567 + 3861125 3861202 chrX 154913754 - 4338266 4338343 13813425
+77
+
+chain 5976 chr6_ssto_hap7 4928567 + 2664206 2664269 chr6 170899992 + 31358648 31358711 30614237
+63
+
+chain 5958 chr6_ssto_hap7 4928567 + 3891447 3891510 chr2 242951149 + 38038620 38038683 30678163
+63
+
+chain 5912 chr6_ssto_hap7 4928567 + 3875752 3875836 chr7 158821424 - 35299548 35299632 7605861
+84
+
+chain 5886 chr6_ssto_hap7 4928567 + 1725643 1725706 chr4 191273063 - 86591247 86591310 30840494
+63
+
+chain 5792 chr6_ssto_hap7 4928567 + 4018980 4019041 chr10 135374737 - 103149812 103149873 26755020
+61
+
+chain 5742 chr6_ssto_hap7 4928567 + 3983333 3983412 chr5 180857866 + 128901198 128901277 14868038
+79
+
+chain 5702 chr6_ssto_hap7 4928567 + 3954013 3954072 chr6 170899992 + 32605878 32605937 31357680
+59
+
+chain 5594 chr6_ssto_hap7 4928567 + 4069284 4069343 chr3 199501827 - 15131518 15131577 31663339
+59
+
+chain 5502 chr6_ssto_hap7 4928567 + 3813204 3813261 chr1 247249719 - 79348621 79348678 31943035
+57
+
+chain 5348 chr6_ssto_hap7 4928567 + 4071259 4071315 chr3 199501827 + 160253017 160253073 32406182
+56
+
+chain 5330 chr6_ssto_hap7 4928567 + 3915278 3915334 chr6 170899992 + 32568311 32568367 32437918
+56
+
+chain 5330 chr6_ssto_hap7 4928567 + 2561771 2561827 chr9 140273252 - 28635638 28635694 32438181
+56
+
+chain 5304 chr6_ssto_hap7 4928567 + 4073642 4073717 chr11 134452384 - 71399807 71399882 4131480
+75
+
+chain 5230 chr6_ssto_hap7 4928567 + 3820271 3820326 chrX 154913754 - 97033891 97033946 32742019
+55
+
+chain 5203 chr6_ssto_hap7 4928567 + 4076111 4076166 chr5 180857866 + 152654188 152654243 32834294
+55
+
+chain 5185 chr6_ssto_hap7 4928567 + 4075517 4075572 chr1 247249719 + 155449681 155449736 32900354
+55
+
+chain 5152 chr6_ssto_hap7 4928567 + 3860576 3860657 chr6 170899992 + 32435407 32435488 15981349
+81
+
+chain 5151 chr6_ssto_hap7 4928567 + 3860169 3860251 chr10 135374737 - 104426563 104426645 8666574
+82
+
+chain 5139 chr6_ssto_hap7 4928567 + 4018355 4018409 chr4 191273063 + 178947604 178947658 33042950
+54
+
+chain 5132 chr6_ssto_hap7 4928567 + 3876113 3876181 chr3 199501827 + 30016279 30016347 19245837
+68
+
+chain 5130 chr6_ssto_hap7 4928567 + 3954272 3954326 chr6 170899992 + 32549431 32549485 33050033
+54
+
+chain 5103 chr6_ssto_hap7 4928567 + 1182080 1182134 chr6 170899992 + 76955761 76955815 33170047
+54
+
+chain 5094 chr6_ssto_hap7 4928567 + 1724204 1724258 chr7 158821424 + 103641158 103641212 33192903
+54
+
+chain 5085 chr6_ssto_hap7 4928567 + 1328098 1328151 chr10 135374737 + 129836820 129836873 10408987
+53
+
+chain 5085 chr6_ssto_hap7 4928567 + 4092830 4092884 chrX 154913754 - 38541067 38541121 33235347
+54
+
+chain 5066 chr6_ssto_hap7 4928567 + 1229626 1229679 chr21 46944323 - 1867343 1867396 33290794
+53
+
+chain 5031 chr6_ssto_hap7 4928567 + 3830258 3830312 chr11 134452384 + 134387408 134387462 33376437
+54
+
+chain 5021 chr6_ssto_hap7 4928567 + 3819996 3820049 chr12 132349534 - 47076480 47076533 33436792
+53
+
+chain 5018 chr6_ssto_hap7 4928567 + 4073251 4073642 chr3 199501827 - 85266868 85267256 1587398
+65 97 89
+113 2 7
+114
+
+chain 5003 chr6_ssto_hap7 4928567 + 3830053 3830106 chr1 247249719 - 154726869 154726922 33499615
+53
+
+chain 5003 chr6_ssto_hap7 4928567 + 4072679 4072732 chr16 88827254 + 14169487 14169540 33499780
+53
+
+chain 4994 chr6_ssto_hap7 4928567 + 3891033 3891086 chr21 46944323 - 10747178 10747231 33543756
+53
+
+chain 4967 chr6_ssto_hap7 4928567 + 3832675 3832728 chr6 170899992 + 32558903 32558956 33617414
+53
+
+chain 4965 chr6_ssto_hap7 4928567 + 2731195 2731249 chr6 170899992 + 31505531 31505585 32711054
+54
+
+chain 4948 chr6_ssto_hap7 4928567 + 4074823 4074875 chr4 191273063 - 118568999 118569051 33679640
+52
+
+chain 4921 chr6_ssto_hap7 4928567 + 3956534 3956586 chr1 247249719 + 94607233 94607285 33754873
+52
+
+chain 4903 chr6_ssto_hap7 4928567 + 3854886 3854938 chr7 158821424 + 104157517 104157569 33851522
+52
+
+chain 4893 chr6_ssto_hap7 4928567 + 3982754 3982817 chr22 49691432 + 37111300 37111363 16902914
+63
+
+chain 4873 chr6_ssto_hap7 4928567 + 3911814 3911922 chr18 76117153 - 50730715 50730823 6267534
+108
+
+chain 4830 chr6_ssto_hap7 4928567 + 3900138 3900189 chr6 170899992 + 32631274 32631325 34086153
+51
+
+chain 4830 chr6_ssto_hap7 4928567 + 3839078 3839129 chr7 158821424 + 82104686 82104737 34087626
+51
+
+chain 4829 chr6_ssto_hap7 4928567 + 1241391 1241441 chr6 170899992 + 29800923 29800973 34088055
+50
+
+chain 4821 chr6_ssto_hap7 4928567 + 2662906 2662957 chr3 199501827 - 33183122 33183173 34119642
+51
+
+chain 4775 chr6_ssto_hap7 4928567 + 2648374 2648424 chr6 170899992 + 31537299 31537349 34295026
+50
+
+chain 4758 chr6_ssto_hap7 4928567 + 4069230 4069281 chr12 132349534 + 47071874 47071925 34323771
+51
+
+chain 4757 chr6_ssto_hap7 4928567 + 3952724 3952774 chr6 170899992 + 32548169 32548219 34341756
+50
+
+chain 4730 chr6_ssto_hap7 4928567 + 3994932 3994982 chrX 154913754 + 47978704 47978754 34444069
+50
+
+chain 4716 chr6_ssto_hap7 4928567 + 4048342 4048408 chr3 199501827 - 34165769 34165835 12625077
+66
+
+chain 4703 chr6_ssto_hap7 4928567 + 2662371 2662421 chr19 63811651 + 65370 65420 34557514
+50
+
+chain 4694 chr6_ssto_hap7 4928567 + 4060651 4060701 chr6 170899992 + 32836714 32836764 34581664
+50
+
+chain 4679 chr6_ssto_hap7 4928567 + 3906823 3908410 chr10 135374737 + 93253585 93255039 1065758
+52 974 846
+68 463 458
+30
+
+chain 4568 chr6_ssto_hap7 4928567 + 1261137 1261199 chrX 154913754 - 132036612 132036674 19096001
+62
+
+chain 4552 chr6_ssto_hap7 4928567 + 3860527 3860576 chr15 100338915 - 42450883 42450932 16059710
+49
+
+chain 4547 chr6_ssto_hap7 4928567 + 2556944 2560436 chr12 132349534 + 103307685 103311177 2570686
+99 961 960
+40 481 480
+76 473 472
+44 1256 1259
+62
+
+chain 4462 chr6_ssto_hap7 4928567 + 2729793 2731102 chr13 114142980 - 41461751 41462033 3580573
+3 13 0
+61 0 13
+33 683 3
+44 2 0
+7 414 58
+20 0 11
+29
+
+chain 4428 chr6_ssto_hap7 4928567 + 4094024 4094075 chr14 106368585 + 31457415 31457466 15616811
+28 1 1
+22
+
+chain 4397 chr6_ssto_hap7 4928567 + 4073349 4073413 chr11 134452384 - 124082096 124082160 4425866
+64
+
+chain 4392 chr6_ssto_hap7 4928567 + 1194713 1194772 chr7 158821424 - 126060926 126060985 9905441
+59
+
+chain 4342 chr6_ssto_hap7 4928567 + 4094294 4094398 chr5 180857866 - 116975574 116975678 23231318
+23 58 58
+23
+
+chain 4295 chr6_ssto_hap7 4928567 + 2556338 2556392 chr13 114142980 + 40947099 40947153 23509763
+54
+
+chain 4294 chr6_ssto_hap7 4928567 + 1260590 1260636 chr12 132349534 - 115571292 115571338 21618938
+46
+
+chain 4197 chr6_ssto_hap7 4928567 + 4047303 4047429 chr5 180857866 + 138042715 138042841 4048116
+126
+
+chain 4074 chr6_ssto_hap7 4928567 + 3895452 3896721 chr2 242951149 - 163460907 163462170 1597366
+57 1112 1106
+100
+
+chain 4047 chr6_ssto_hap7 4928567 + 1227212 1227254 chr6 170899992 + 30567064 30567106 34943638
+42
+
+chain 4028 chr6_ssto_hap7 4928567 + 2557654 2557724 chr8 146274826 - 45767632 45767702 6509640
+70
+
+chain 3802 chr6_ssto_hap7 4928567 + 3983413 3983485 chr9 140273252 - 109331781 109331853 15187387
+72
+
+chain 3788 chr6_ssto_hap7 4928567 + 3983607 3983647 chr5 180857866 + 163886600 163886640 18371448
+40
+
+chain 3783 chr6_ssto_hap7 4928567 + 3861067 3861107 chr8 146274826 + 47663219 47663259 26644949
+40
+
+chain 3780 chr6_ssto_hap7 4928567 + 1260148 1260195 chr3 199501827 + 129107515 129107562 25050682
+47
+
+chain 3771 chr6_ssto_hap7 4928567 + 3910850 3910969 chr11 134452384 + 91939775 91939894 1347783
+119
+
+chain 3720 chr6_ssto_hap7 4928567 + 4076654 4076693 chr5 180857866 - 28755460 28755499 35075689
+39
+
+chain 3674 chr6_ssto_hap7 4928567 + 1327942 1328098 chr13 114142980 - 16623521 16623677 9556113
+156
+
+chain 3526 chr6_ssto_hap7 4928567 + 1233321 1233358 chr3 199501827 + 179624737 179624774 21949411
+37
+
+chain 3523 chr6_ssto_hap7 4928567 + 3861357 3861409 chrX 154913754 - 71079157 71079209 23377911
+52
+
+chain 3519 chr6_ssto_hap7 4928567 + 3860886 3860923 chr10 135374737 + 82581588 82581625 28921115
+37
+
+chain 3516 chr6_ssto_hap7 4928567 + 3983122 3983159 chr14 106368585 + 44215304 44215341 21050502
+37
+
+chain 3503 chr6_ssto_hap7 4928567 + 3955956 3955993 chrX 154913754 + 6516305 6516342 20940822
+37
+
+chain 3500 chr6_ssto_hap7 4928567 + 3911536 3911575 chr13 114142980 + 94757263 94757302 7214953
+39
+
+chain 3483 chr6_ssto_hap7 4928567 + 4093962 4094024 chr18 76117153 - 13046880 13046942 11655771
+62
+
+chain 3478 chr6_ssto_hap7 4928567 + 3815148 3815213 chr18 76117153 - 71040520 71040585 23549077
+65
+
+chain 3458 chr6_ssto_hap7 4928567 + 3983209 3983294 chr8 146274826 - 67597789 67597874 12879815
+85
+
+chain 3397 chr6_ssto_hap7 4928567 + 4048453 4048489 chr17 78774742 - 56852494 56852530 15165556
+36
+
+chain 3368 chr6_ssto_hap7 4928567 + 3812594 3812653 chr10 135374737 - 122033518 122033577 24304367
+59
+
+chain 3327 chr6_ssto_hap7 4928567 + 1327907 1327942 chr2 242951149 - 102468165 102468200 11981936
+35
+
+chain 3310 chr6_ssto_hap7 4928567 + 3973883 3974608 chr4 191273063 + 16003477 16004520 2930244
+28 656 974
+41
+
+chain 3301 chr6_ssto_hap7 4928567 + 2558188 2558238 chr3 199501827 + 116399611 116399661 15972636
+50
+
+chain 3279 chr6_ssto_hap7 4928567 + 2675861 2675917 chrX 154913754 + 134744376 134744432 23888160
+56
+
+chain 3275 chr6_ssto_hap7 4928567 + 1175210 1175245 chr6 170899992 + 29990315 29990350 35226054
+35
+
+chain 3266 chr6_ssto_hap7 4928567 + 3955123 3955180 chr3 199501827 - 22333077 22333134 22107567
+57
+
+chain 3198 chr6_ssto_hap7 4928567 + 3983298 3983333 chr9 140273252 - 16426927 16426962 15083539
+35
+
+chain 3194 chr6_ssto_hap7 4928567 + 3955248 3955303 chr12 132349534 + 117591668 117591723 17819023
+55
+
+chain 3180 chr6_ssto_hap7 4928567 + 3983045 3983105 chr5 180857866 - 166783333 166783393 16589034
+60
+
+chain 3166 chr6_ssto_hap7 4928567 + 3843125 3843159 chr4 191273063 + 105842978 105843012 35258022
+34
+
+chain 3121 chr6_ssto_hap7 4928567 + 3896015 3896048 chr12 132349534 + 40503685 40503718 34691345
+33
+
+chain 3047 chr6_ssto_hap7 4928567 + 3816677 3816709 chr10 135374737 - 66254665 66254697 30311304
+32
+
+chain 3032 chr6_ssto_hap7 4928567 + 4105261 4105293 chr8 146274826 - 64365138 64365170 21873611
+32
+
+chain 3023 chr6_ssto_hap7 4928567 + 4076166 4076198 chr7 158821424 - 25244743 25244775 33809340
+32
+
+chain 3020 chr6_ssto_hap7 4928567 + 3860793 3860825 chr14 106368585 - 87125958 87125990 25956389
+32
+
+chain 3015 chr6_ssto_hap7 4928567 + 3983163 3983195 chr3 199501827 + 120260171 120260203 17223389
+32
+
+chain 2990 chr6_ssto_hap7 4928567 + 3896241 3896359 chr13 114142980 + 83437980 83438098 1629523
+118
+
+chain 2988 chr6_ssto_hap7 4928567 + 3982643 3982709 chr1 247249719 + 240403964 240404030 13152492
+66
+
+chain 2975 chr6_ssto_hap7 4928567 + 2564513 2564549 chr3 199501827 - 94209737 94209773 24799761
+36
+
+chain 2970 chr6_ssto_hap7 4928567 + 4070462 4070493 chr3 199501827 - 179622086 179622117 31254285
+31
+
+chain 2964 chr6_ssto_hap7 4928567 + 3891798 3891851 chr5 180857866 + 101832950 101833003 21914612
+53
+
+chain 2888 chr6_ssto_hap7 4928567 + 4065158 4065188 chr19 63811651 - 5427097 5427127 31160360
+30
+
+chain 2845 chr6_ssto_hap7 4928567 + 2556914 2556944 chr3 199501827 - 158108130 158108160 26771676
+30
+
+chain 2753 chr6_ssto_hap7 4928567 + 1233507 1233566 chr12 132349534 + 50414483 50414542 22637631
+59
+
+chain 2740 chr6_ssto_hap7 4928567 + 3892104 3892166 chr5 180857866 + 121612373 121612435 20400021
+62
+
+chain 2698 chr6_ssto_hap7 4928567 + 3907323 3908062 chr7 158821424 + 92810174 92810913 1211789
+52 649 649
+38
+
+chain 2671 chr6_ssto_hap7 4928567 + 2565133 2565192 chr9 140273252 - 60326471 60326530 21074057
+59
+
+chain 2634 chr6_ssto_hap7 4928567 + 3829525 3829553 chr11 134452384 - 52779952 52779980 32661482
+28
+
+chain 2606 chr6_ssto_hap7 4928567 + 4048612 4048640 chr10 135374737 - 125708744 125708772 21482387
+28
+
+chain 2596 chr6_ssto_hap7 4928567 + 3956994 3957021 chr3 199501827 + 56590732 56590759 32896514
+27
+
+chain 2579 chr6_ssto_hap7 4928567 + 2557143 2557298 chr6 170899992 - 49784063 49784218 3056426
+155
+
+chain 2576 chr6_ssto_hap7 4928567 + 3895108 3895185 chr6 170899992 + 169119449 169119526 1708984
+77
+
+chain 2565 chr6_ssto_hap7 4928567 + 3829029 3829056 chr12 132349534 - 5427347 5427374 35416045
+27
+
+chain 2538 chr6_ssto_hap7 4928567 + 4095308 4095335 chrX 154913754 - 17724530 17724557 35428225
+27
+
+chain 2483 chr6_ssto_hap7 4928567 + 2785408 2785434 chr6 170899992 + 31465639 31465665 7427670
+26
+
+chain 2481 chr6_ssto_hap7 4928567 + 2556543 2556631 chr3 199501827 + 50931029 50931117 15954243
+88
+
+chain 2458 chr6_ssto_hap7 4928567 + 3955303 3955329 chr2 242951149 + 162131406 162131432 29918335
+26
+
+chain 2454 chr6_ssto_hap7 4928567 + 4073316 4073349 chr4 191273063 + 122379593 122379626 9286528
+33
+
+chain 2452 chr6_ssto_hap7 4928567 + 3955573 3955623 chr15 100338915 - 6219909 6219959 18667645
+50
+
+chain 2424 chr6_ssto_hap7 4928567 + 235781 235807 chr6 170899992 - 141897118 141897144 13814892
+26
+
+chain 2387 chr6_ssto_hap7 4928567 + 3979548 3981344 chr6 170899992 + 32629287 32631086 11569193
+64 1054 1061
+59 8 8
+33 512 508
+66
+
+chain 2367 chr6_ssto_hap7 4928567 + 3861203 3861228 chr5 180857866 - 25449026 25449051 27433905
+25
+
+chain 2364 chr6_ssto_hap7 4928567 + 3896486 3896567 chr12 132349534 - 118913454 118913535 1891796
+81
+
+chain 2348 chr6_ssto_hap7 4928567 + 2555491 2555546 chr7 158821424 + 35337254 35337309 23750585
+55
+
+chain 2343 chr6_ssto_hap7 4928567 + 3895509 3895593 chr5 180857866 + 145974017 145974101 2481028
+84
+
+chain 2329 chr6_ssto_hap7 4928567 + 3908230 3908283 chr14 106368585 - 66110025 66110078 1963434
+53
+
+chain 2303 chr6_ssto_hap7 4928567 + 3910235 3910298 chr9 140273252 + 106520457 106520520 13548409
+63
+
+chain 2290 chr6_ssto_hap7 4928567 + 1194888 1194945 chr1 247249719 + 222604152 222604209 12152481
+57
+
+chain 2264 chr6_ssto_hap7 4928567 + 4094107 4094165 chr6 170899992 - 103114933 103114991 11782722
+58
+
+chain 2239 chr6_ssto_hap7 4928567 + 3859859 3859885 chr10 135374737 - 31460228 31460254 11102876
+26
+
+chain 2227 chr6_ssto_hap7 4928567 + 3896386 3896483 chr3 199501827 + 28081389 28081486 2734455
+97
+
+chain 2194 chr6_ssto_hap7 4928567 + 1194673 1194713 chrX 154913754 - 101365357 101365397 11073774
+40
+
+chain 2194 chr6_ssto_hap7 4928567 + 3911725 3911783 chr20 62435964 + 16923180 16923238 16666656
+58
+
+chain 2183 chr6_ssto_hap7 4928567 + 3982709 3982750 chrX 154913754 + 100681659 100681700 16994110
+41
+
+chain 2146 chr6_ssto_hap7 4928567 + 1180871 1180932 chr12 132349534 + 104221177 104221238 23825292
+61
+
+chain 2099 chr6_ssto_hap7 4928567 + 1233299 1233321 chr8 146274826 + 94956096 94956118 22553602
+22
+
+chain 2073 chr6_ssto_hap7 4928567 + 3956611 3956663 chr12 132349534 - 95011302 95011354 24299162
+52
+
+chain 2037 chr6_ssto_hap7 4928567 + 3907120 3907174 chr16 88827254 + 61739431 61739485 9206264
+54
+
+chain 1971 chr6_ssto_hap7 4928567 + 1260864 1260916 chr6 170899992 - 43699516 43699568 21479541
+52
+
+chain 1962 chr6_ssto_hap7 4928567 + 3860956 3861008 chr2 242951149 - 71012239 71012291 15891024
+52
+
+chain 1959 chr6_ssto_hap7 4928567 + 4047151 4047237 chr9 140273252 + 88182498 88182584 7672012
+86
+
+chain 1911 chr6_ssto_hap7 4928567 + 4094317 4094375 chr3 199501827 + 41781958 41782016 21488153
+58
+
+chain 1911 chr6_ssto_hap7 4928567 + 1260320 1260381 chr10 135374737 - 106297874 106297935 24479059
+61
+
+chain 1874 chr6_ssto_hap7 4928567 + 2557724 2557753 chr7 158821424 + 91452357 91452386 16326510
+29
+
+chain 1780 chr6_ssto_hap7 4928567 + 3910029 3910068 chr14 106368585 - 82341010 82341049 3087250
+39
+
+chain 1777 chr6_ssto_hap7 4928567 + 2675677 2675732 chr16 88827254 + 88260921 88260976 23365193
+55
+
+chain 1697 chr6_ssto_hap7 4928567 + 2559283 2559636 chr4 191273063 - 69388564 69388918 2817550
+72 250 251
+31
+
+chain 1664 chr6_ssto_hap7 4928567 + 3911192 3911255 chr5 180857866 - 81785123 81785186 3114861
+63
+
+chain 1653 chr6_ssto_hap7 4928567 + 2560066 2560131 chr7 158821424 - 148280259 148280324 6636035
+65
+
+chain 1644 chr6_ssto_hap7 4928567 + 3910172 3910234 chrX 154913754 - 124216188 124216250 1928091
+62
+
+chain 1640 chr6_ssto_hap7 4928567 + 3906670 3906720 chr3 199501827 - 110018776 110018826 1171918
+50
+
+chain 1620 chr6_ssto_hap7 4928567 + 4048655 4048716 chr11 134452384 - 43500788 43500849 9791170
+61
+
+chain 1606 chr6_ssto_hap7 4928567 + 3837795 3837854 chr4 191273063 - 166421863 166421922 24717464
+59
+
+chain 1605 chr6_ssto_hap7 4928567 + 3875836 3875881 chr1 247249719 - 200018115 200018160 9990642
+45
+
+chain 1600 chr6_ssto_hap7 4928567 + 3957021 3957050 chr13 114142980 - 18785120 18785149 24380544
+29
+
+chain 1599 chr6_ssto_hap7 4928567 + 3955003 3955066 chr8 146274826 + 126278291 126278354 19925896
+63
+
+chain 1576 chr6_ssto_hap7 4928567 + 3910706 3910761 chr3 199501827 + 169002538 169002593 7318777
+55
+
+chain 1576 chr6_ssto_hap7 4928567 + 3876008 3876074 chr21 46944323 + 28977016 28977082 11761970
+66
+
+chain 1567 chr6_ssto_hap7 4928567 + 3909838 3909895 chr12 132349534 + 31210742 31210799 2955344
+57
+
+chain 1566 chr6_ssto_hap7 4928567 + 3893961 3894004 chr5 180857866 - 2394787 2394830 2003043
+43
+
+chain 1548 chr6_ssto_hap7 4928567 + 2556653 2556768 chr2 242951149 - 193553846 193553961 3498208
+115
+
+chain 1539 chr6_ssto_hap7 4928567 + 3891177 3891234 chr1 247249719 - 78251618 78251675 24446661
+57
+
+chain 1535 chr6_ssto_hap7 4928567 + 3911107 3911157 chr1 247249719 - 72372939 72372989 9173856
+50
+
+chain 1534 chr6_ssto_hap7 4928567 + 4094211 4094262 chrX 154913754 - 868272 868323 12957412
+51
+
+chain 1513 chr6_ssto_hap7 4928567 + 3906987 3907031 chr5 180857866 - 10434692 10434736 1299581
+44
+
+chain 1493 chr6_ssto_hap7 4928567 + 2556789 2556856 chr13 114142980 + 99769649 99769716 4762882
+67
+
+chain 1490 chr6_ssto_hap7 4928567 + 3814865 3814929 chr10 135374737 - 44217075 44217139 22840138
+64
+
+chain 1482 chr6_ssto_hap7 4928567 + 3909632 3909684 chr11 134452384 + 100031701 100031753 1214591
+52
+
+chain 1453 chr6_ssto_hap7 4928567 + 1327842 1327906 chr7 158821424 + 38479547 38479611 8534629
+64
+
+chain 1406 chr6_ssto_hap7 4928567 + 3909452 3909505 chr2 242951149 - 92980714 92980767 1301647
+53
+
+chain 1403 chr6_ssto_hap7 4928567 + 3860825 3860881 chr2 242951149 + 213976883 213976939 18753925
+56
+
+chain 1392 chr6_ssto_hap7 4928567 + 3955543 3955573 chr3 199501827 - 51819316 51819346 23522770
+30
+
+chain 1378 chr6_ssto_hap7 4928567 + 2556204 2556330 chr9 140273252 + 106017756 106017882 9913210
+126
+
+chain 1352 chr6_ssto_hap7 4928567 + 4047237 4047285 chr4 191273063 - 68812874 68812922 21085894
+48
+
+chain 1344 chr6_ssto_hap7 4928567 + 3893519 3893548 chr4 191273063 + 75333241 75333270 1578953
+29
+
+chain 1342 chr6_ssto_hap7 4928567 + 2557427 2557573 chr1 247249719 + 169787922 169788068 14592994
+146
+
+chain 1328 chr6_ssto_hap7 4928567 + 3895210 3895266 chr1 247249719 - 722390 722446 2029679
+56
+
+chain 1323 chr6_ssto_hap7 4928567 + 3815012 3815074 chrY 57772954 + 15217299 15217361 24773594
+62
+
+chain 1317 chr6_ssto_hap7 4928567 + 2559037 2559074 chr2 242951149 - 160628689 160628726 4907065
+37
+
+chain 1310 chr6_ssto_hap7 4928567 + 3859653 3859705 chrX 154913754 + 62583131 62583183 22867194
+52
+
+chain 1305 chr6_ssto_hap7 4928567 + 1233633 1233684 chr10 135374737 - 7751536 7751587 24635136
+51
+
+chain 1291 chr6_ssto_hap7 4928567 + 3908834 3908875 chr4 191273063 - 115939442 115939483 1333239
+41
+
+chain 1287 chr6_ssto_hap7 4928567 + 3909608 3909632 chr5 180857866 + 103723323 103723347 7290377
+24
+
+chain 1280 chr6_ssto_hap7 4928567 + 3895766 3895816 chr8 146274826 + 51746323 51746373 2903032
+50
+
+chain 1274 chr6_ssto_hap7 4928567 + 2557298 2557339 chrX 154913754 - 130647843 130647884 4467918
+41
+
+chain 1257 chr6_ssto_hap7 4928567 + 2558435 2558509 chr10 135374737 + 60854508 60854582 4145356
+74
+
+chain 1250 chr6_ssto_hap7 4928567 + 4094075 4094107 chr12 132349534 + 74093056 74093088 12787103
+32
+
+chain 1238 chr6_ssto_hap7 4928567 + 1229366 1229425 chr8 146274826 - 84904941 84905000 22834116
+59
+
+chain 1235 chr6_ssto_hap7 4928567 + 3861228 3861334 chr15 100338915 - 22701786 22701892 11814602
+106
+
+chain 1193 chr6_ssto_hap7 4928567 + 3906339 3906392 chr6 170899992 + 117066655 117066708 1525034
+53
+
+chain 1176 chr6_ssto_hap7 4928567 + 3909895 3909925 chr8 146274826 - 24546743 24546773 1399929
+30
+
+chain 1144 chr6_ssto_hap7 4928567 + 3892335 3892388 chrX 154913754 - 80891112 80891165 18462511
+53
+
+chain 1143 chr6_ssto_hap7 4928567 + 3876074 3876097 chr4 191273063 - 150305688 150305711 12943108
+23
+
+chain 1107 chr6_ssto_hap7 4928567 + 3890850 3890949 chr11 134452384 - 72766127 72766226 17974034
+99
+
+chain 1099 chr6_ssto_hap7 4928567 + 2557592 2557651 chr14 106368585 + 52836717 52836776 3332437
+59
+
+chain 1093 chr6_ssto_hap7 4928567 + 2560006 2560065 chr11 134452384 + 32923634 32923693 3048042
+59
+
+chain 1080 chr6_ssto_hap7 4928567 + 4073853 4073903 chr19 63811651 - 3657843 3657893 23666214
+50
+
+chain 1031 chr6_ssto_hap7 4928567 + 3910512 3910543 chr8 146274826 + 76357761 76357792 1122615
+31
+
+chain 1019 chr6_ssto_hap7 4928567 + 3956446 3956499 chr2 242951149 - 47303049 47303102 21955737
+53
+
+chain 1013 chr6_ssto_hap7 4928567 + 3876829 3876895 chr5 180857866 - 104615327 104615393 22955784
+66
+
+chain 1003 chr6_ssto_hap7 4928567 + 3699456 3699487 chr2 242951149 - 44758448 44758479 2126762
+31
+
+chain 980 chr6_ssto_hap7 4928567 + 1260084 1260145 chrX 154913754 - 382349 382410 22927465
+61
+
+chain 926 chr6_ssto_hap7 4928567 + 3896721 3896750 chr5 180857866 - 112926632 112926661 13782082
+29
+
+chain 919 chr6_ssto_hap7 4928567 + 2560983 2561043 chr4 191273063 + 44807134 44807194 22381059
+60
+
+chain 917 chr6_ssto_hap7 4928567 + 3906720 3906770 chr1 247249719 - 157593440 157593490 1436049
+50
+
+chain 909 chr6_ssto_hap7 4928567 + 3909310 3909343 chr3 199501827 + 106500697 106500730 2326646
+33
+
+chain 904 chr6_ssto_hap7 4928567 + 2560317 2560347 chr7 158821424 + 107644178 107644208 22181612
+30
+
+chain 884 chr6_ssto_hap7 4928567 + 2559977 2560006 chr1 247249719 - 197271642 197271671 12501549
+29
+
+chain 879 chr6_ssto_hap7 4928567 + 3814083 3814143 chr2 242951149 + 8957980 8958040 24745704
+60
+
+chain 871 chr6_ssto_hap7 4928567 + 3908354 3908380 chr5 180857866 - 86285693 86285719 1813846
+26
+
+chain 854 chr6_ssto_hap7 4928567 + 2559716 2559766 chr4 191273063 + 5547185 5547235 3968222
+50
+
+chain 842 chr6_ssto_hap7 4928567 + 3909997 3910029 chr12 132349534 + 65262069 65262101 1358106
+32
+
+chain 834 chr6_ssto_hap7 4928567 + 2558357 2558414 chr5 180857866 - 149870489 149870546 4554917
+57
+
+chain 818 chr6_ssto_hap7 4928567 + 3895593 3895627 chr1 247249719 - 137161630 137161664 3053056
+34
+
+chain 805 chr6_ssto_hap7 4928567 + 4046900 4046958 chr3 199501827 - 135889823 135889881 13048217
+58
+
+chain 792 chr6_ssto_hap7 4928567 + 2556476 2556543 chrX 154913754 - 448312 448379 10955677
+67
+
+chain 788 chr6_ssto_hap7 4928567 + 2557050 2557102 chr9 140273252 - 129331917 129331969 3471854
+52
+
+chain 766 chr6_ssto_hap7 4928567 + 3895074 3895108 chrX 154913754 - 143143280 143143314 1988289
+34
+
+chain 764 chr6_ssto_hap7 4928567 + 3911494 3911520 chr5 180857866 - 28611213 28611239 1520834
+26
+
+chain 760 chr6_ssto_hap7 4928567 + 3891913 3891984 chr7 158821424 + 132658309 132658380 7665022
+71
+
+chain 760 chr6_ssto_hap7 4928567 + 2558688 2558747 chr12 132349534 + 56700130 56700189 25330837
+59
+
+chain 751 chr6_ssto_hap7 4928567 + 3908062 3908116 chrX 154913754 - 27278752 27278806 23595528
+54
+
+chain 750 chr6_ssto_hap7 4928567 + 2558241 2558292 chr3 199501827 - 21470788 21470839 4018903
+51
+
+chain 747 chr6_ssto_hap7 4928567 + 1195376 1195440 chr12 132349534 + 55464534 55464598 20643872
+64
+
+chain 741 chr6_ssto_hap7 4928567 + 2558773 2558825 chr10 135374737 + 51611354 51611406 20535555
+52
+
+chain 725 chr6_ssto_hap7 4928567 + 2556857 2556911 chr2 242951149 + 129418481 129418535 15959344
+54
+
+chain 718 chr6_ssto_hap7 4928567 + 3906470 3906504 chr13 114142980 + 74008819 74008853 1439498
+34
+
+chain 683 chr6_ssto_hap7 4928567 + 4094187 4094211 chr12 132349534 - 78902290 78902314 13929920
+24
+
+chain 678 chr6_ssto_hap7 4928567 + 2557391 2557427 chr4 191273063 + 139055274 139055310 16166693
+36
+
+chain 667 chr6_ssto_hap7 4928567 + 2560843 2560917 chr5 180857866 - 57070089 57070163 4646233
+74
+
+chain 646 chr6_ssto_hap7 4928567 + 2558159 2558188 chr1 247249719 - 41799280 41799309 22422429
+29
+
+chain 632 chr6_ssto_hap7 4928567 + 3892229 3892286 chr5 180857866 + 40599364 40599421 14690520
+57
+
+chain 624 chr6_ssto_hap7 4928567 + 2558292 2558324 chr9 140273252 + 222455 222487 4174075
+32
+
+chain 617 chr6_ssto_hap7 4928567 + 3894943 3894969 chr9 140273252 - 67269827 67269853 2340131
+26
+
+chain 612 chr6_ssto_hap7 4928567 + 1195270 1195296 chr2 242951149 + 158875930 158875956 11360379
+26
+
+chain 602 chr6_ssto_hap7 4928567 + 3896359 3896385 chr2 242951149 + 96414192 96414218 2435436
+26
+
+chain 600 chr6_ssto_hap7 4928567 + 2560187 2560242 chr4 191273063 - 105845249 105845304 24497060
+55
+
+chain 588 chr6_ssto_hap7 4928567 + 3911575 3911637 chr9 140273252 + 26038500 26038562 6400007
+62
+
+chain 588 chr6_ssto_hap7 4928567 + 3911157 3911192 chr2 242951149 - 186209425 186209460 7977621
+35
+
+chain 537 chr6_ssto_hap7 4928567 + 3890472 3890554 chr20 62435964 + 39823688 39823770 23049583
+82
+
+chain 533 chr6_ssto_hap7 4928567 + 2560261 2560317 chr7 158821424 + 35749861 35749917 7559420
+56
+
+chain 506 chr6_ssto_hap7 4928567 + 1194845 1194871 chr17 78774742 + 16156064 16156090 14435127
+26
+
+chain 492 chr6_ssto_hap7 4928567 + 2561299 2561367 chr13 114142980 - 65973713 65973781 6503172
+68
+
+chain 482 chr6_ssto_hap7 4928567 + 3909557 3909588 chr4 191273063 + 109100594 109100625 25171244
+31
+
+chain 475 chr6_ssto_hap7 4928567 + 3910969 3910996 chr2 242951149 + 170022712 170022739 3066592
+27
+
+chain 474 chr6_ssto_hap7 4928567 + 2555667 2555728 chr3 199501827 + 34096453 34096514 5935624
+61
+
+chain 454 chr6_ssto_hap7 4928567 + 3783318 3783345 chr7 158821424 + 43780404 43780431 3672784
+27
+
+chain 453 chr6_ssto_hap7 4928567 + 2558825 2558856 chr12 132349534 + 9890466 9890497 23880886
+31
+
+chain 435 chr6_ssto_hap7 4928567 + 3813557 3813608 chrX 154913754 + 70635923 70635974 25591729
+51
+
+chain 433 chr6_ssto_hap7 4928567 + 3954592 3954642 chr12 132349534 + 80047789 80047839 27634718
+50
+
+chain 421 chr6_ssto_hap7 4928567 + 3906299 3906339 chr6 170899992 - 100687874 100687914 2311527
+40
+
+chain 415 chr6_ssto_hap7 4928567 + 4047055 4047086 chr2 242951149 - 64586829 64586860 16220906
+31
+
+chain 395 chr6_ssto_hap7 4928567 + 3877505 3877535 chr2 242951149 - 195767137 195767167 24444969
+30
+
+chain 389 chr6_ssto_hap7 4928567 + 2560634 2560691 chr4 191273063 - 135903806 135903863 10538130
+57
+
+chain 364 chr6_ssto_hap7 4928567 + 3892286 3892319 chr2 242951149 + 18209140 18209173 14942259
+33
+
+chain 312 chr6_ssto_hap7 4928567 + 2559887 2559937 chr6 170899992 + 118230705 118230755 8173852
+50
+
+chain 289 chr6_ssto_hap7 4928567 + 2561063 2561118 chr9 140273252 - 49339912 49339967 9048484
+55
+
+chain 276 chr6_ssto_hap7 4928567 + 3878310 3878371 chr4 191273063 - 5378508 5378569 28215176
+61
+
+chain 273 chr6_ssto_hap7 4928567 + 2560131 2560171 chr10 135374737 + 69013223 69013263 15789387
+40
+
+chain 167 chr6_ssto_hap7 4928567 + 3908301 3908353 chr3 199501827 + 163583012 163583064 2366456
+52
+
+chain 14618488008 7 159138663 + 10238 159128663 chr7 158821424 + 102995 158821424 7
+973 0 5
+3912 2 0
+1234 0 4
+51 6 0
+70 1 1
+24 0 1
+147 0 8
+12 1 170
+47 1 1
+246 6 0
+99 4 4
+807 0 3
+2546 0 63
+44 0 2527
+1373 1 0
+2109 456 0
+1153 1 0
+791 1 1
+49 1 0
+4175 18 26
+4318 11 11
+514 0 12
+2511 1 0
+1697 6 6
+192827 278557 150000
+5682433 40 39
+42007910 35970 40000
+2048 3 3
+2320 16 7
+17699 4 0
+5248 0 4
+2088411 1 1
+47 1 1
+4565 1 0
+7116 1 0
+2706 43050 40000
+6577293 13552 50000
+1052855 3000000 3000000
+256182 416507 50000
+190137 50000 50000
+5722629 1 0
+23 1 1
+239 1 1
+59 2 2
+138 1 1
+34 1 1
+206 3 1
+18 0 1
+410 1 1
+72 1 1
+199 1 1
+62 5 5
+120 0 1
+468 1 1
+32 1 1
+264 1 1
+23 1 1
+1459 4 4
+107 1 1
+42 0 1
+14 1 1
+201 1 1
+46 1 1
+268 20 20
+303 1 2
+866 4 0
+76 3 3
+63 1 1
+74 0 1
+25 1 1
+66 1 1
+34 2 0
+180 36 35
+93 1 1
+41 1 1
+70 1 1
+49 1 1
+63 1 1
+57 1 1
+383 1 1
+133 1 1
+87 1 1
+38 4 4
+50 1 0
+46 6 5
+136 11 11
+200 1 1
+64 5 18
+263 1 1
+32 3 3
+152 16 16
+567 0 1
+322 0 3
+1258 1 0
+504 0 4
+1142 10 11
+537 12 12
+1418 1 1
+47 1 0
+164 7 7
+113 0 5
+59 2 2
+72 1 1
+20 1 1
+380 3 3
+41 0 3
+5 2 2
+921 1 1
+34 1 1
+1607 2 2
+73 0 66
+45 0 14
+169 1 1
+53 1 1
+3195 1 1
+23 1 1
+2115 14 0
+9872 0 1
+1204 13 13
+416 0 1
+2298 0 319
+6918 10 0
+184 0 24
+2932 0 4
+1394 12 0
+1853 0 5
+3442 1 0
+469 0 3
+771 12 15
+497 1 1
+65 1 1
+1210 2 0
+4131 10 10
+1198 0 1
+718 1 1
+21 1 1
+3668 0 1
+874 1 1
+25 1 1
+2444 1 0
+1867 1 1
+29 1 1
+1660 1 0
+1233 6 0
+783 0 1
+705 3 0
+3577 0 1
+365 0 1
+3389 4 8
+2652 3 0
+664 1 0
+169 9 10
+138 1 0
+8038 56 0
+109 0 196
+522 35 0
+3003 1 1
+40 1 1
+1065 0 4
+634 1 0
+51 30 0
+66 1 9
+3081 0 2
+806 1 0
+21 1 1
+3901 27 26
+843 1 0
+6916420 50000 250000
+25789109 51216 0
+1399988 0 1
+3623 212 0
+38 1 1
+210 29 33
+1318 0 16
+2190 0 1
+145 1 0
+1388 7 7
+2240 14 14
+771 1 1
+34 1 1
+92 1 1
+39 1 1
+505 0 1
+66 1 1
+49 1 1
+159 0 1
+78 0 2
+2 0 1
+13 0 2
+7 0 1
+28 0 1
+27 5 468
+2022 0 1
+1796 7 7
+61 1 1
+20 1 1
+4560 0 3
+157730 0 1
+194 14 14
+650 12 0
+669 74 74
+820 5 0
+277 32 60
+69 5 0
+1345 0 8
+652 0 84
+118 4 0
+498 1 0
+3187 1 1
+43 1 1
+1476 3 0
+2101 0 5
+788 6 6
+872 6 0
+691 202 205
+155 33 33
+4610 7 5
+521 0 10
+2773 1 1
+38 1 1
+627 1 1
+41 1 1
+1424 1 0
+2554 8 8
+45 7 0
+614 1 1
+32 0 3
+2693 1 0
+1029 2 0
+151 1 0
+1753 21 0
+370 3 2
+969 1 0
+452 0 1
+3035 42 42
+704 2 0
+2472 6 0
+238 0 1
+1442 43 43
+126 1 0
+795 1 0
+1191 0 1
+171 16 17
+724 27 28
+2966 1 1
+38 3 1
+359 0 2
+199 1 1
+17 1 1
+1969 0 1
+251 1 0
+729 1 0
+992 1 1
+25 1 1
+203 0 4
+3211 2 0
+1006 10 8
+1571 10 10
+756 38 37
+433 1 0
+672 3 0
+4460 25 182
+5551 19 23
+942 9 10
+3433 1 2
+24 1 1
+4262 0 13
+661 0 2
+167 0 8
+3474 66 61
+162 2 0
+778 34 34
+158 1 0
+1167 1 0
+684 1 0
+878 39 39
+2012 1 0
+345 1 1
+50 1 1
+626 2 0
+27874083 136705 0
+2495 2 0
+1000 0 8
+14695 0 1
+4456 0 1
+2977 0 1
+9065130 29055 25000
+2369 0 1
+12174 20 18
+878 4 0
+5247 12 0
+3482 0 2
+6766 1 0
+2469878 1 0
+835 1 0
+2471 13 13
+751 0 8
+2241 1 0
+12 1 1
+8394 0 1
+47 1 1
+903 1 0
+5537 1 0
+269 0 1
+7114 1 1
+30 1 1
+2412 1 0
+2442 21 21
+91 1 1
+37 1 1
+96 1 1
+22 1 1
+246 1 1
+23 1 1
+241 25 25
+569 1 1
+27 1 1
+1624 0 1
+112 3 3
+45 1 1
+384 13 13
+70 0 1
+658 1 1
+20 1 1
+176 0 1
+307 19 19
+428 1 1
+19 1 1
+87 1 1
+30 1 1
+140 0 1
+292 0 2
+1492 0 1
+302 2 0
+364 1 1
+35 1 1
+1956 1 0
+728 57 57
+8010 0 1
+488 0 1
+2056 8 18
+1286 1 1
+27 1 1
+731 0 1
+1423 7 0
+2010 1 1
+19 1 1
+3925 37 37
+2438 4 0
+80 1 1
+4505 0 13
+933 12 0
+1250 1 0
+1313 0 1
+2610 1 0
+2398 1 0
+453 0 1
+346 14 14
+83 0 1
+24 1 0
+83 12 12
+277 1 0
+45 0 1
+811 0 2
+164 1 0
+104 1 0
+32 1 1
+1386 14 0
+306 1 1
+43 1 1
+2765 1 0
+1819 1 0
+1480 1 1
+24 1 1
+276 1 0
+21 1 0
+119 11 39
+542 1 1
+63 1 1
+180 1 0
+2456 0 1
+392 62 62
+601 0 1
+1166 0 2
+784 4 0
+170 0 1
+939 0 6
+5597 15 15
+1253 1 0
+3336 18 0
+1851 0 9
+45 1 1
+4794 1 0
+1387 0 2
+1460 0 1
+204 5 0
+1506 1 0
+2621 0 1
+6620 1 0
+34 1 1
+249 0 1
+1443 10 0
+242 1 0
+368 9 1
+257 0 4
+1588 0 6
+1544 1 0
+4189 0 120
+354 278046 312446
+3728 1 0
+3127 9 10
+4861 4 0
+5649 0 1
+2011 1 0
+14914 1467 42
+20955 1 0
+2075 1 2
+5546 0 1
+2168 0 4
+1266 0 1
+4124 1 1
+46 1 1
+54 1 1
+43 0 15
+780 1 1
+25 1 1
+497 1 0
+46 1 1
+770 41 40
+5701 1 0
+4251 8 8
+2739 1 0
+2002 3 0
+7160 1 1
+24 1 1
+479 0 2
+1872 1 0
+1192 0 1
+371 0 2
+31 1 1
+572 16 16
+1725 16 16
+588 1 1
+90 1 1
+2483 19 3
+187 1 0
+20 1 1
+3673 1 1
+27 0 4
+3021 0 1
+1323 6 19
+498 13 13
+1618 0 2
+5282 1 0
+720 8 0
+2993 0 1
+2822 2 0
+1396 1 1
+48 1 1
+8723 0 5
+291 1 1
+25 1 1
+116 1 0
+2809 1 1
+27 1 1
+224 1 1
+48 1 1
+292 2 0
+400 1 0
+754 1 1
+19 1 1
+4225 1 1
+28 1 1
+801 0 1
+671 1 1
+17 1 1
+390 1 1
+28 1 1
+84 7 7
+568 1 1
+56 1 1
+499 8 7
+266 1 1
+31 1 1
+518 18 18
+164 1 1
+50 1 1
+162 1 1
+60 1 1
+702 1 1
+28 1 1
+146 17 18
+517 1 1
+24 1 1
+799 1 1
+22 5 5
+107 5 5
+277 9 9
+272 1 1
+48 1 1
+77 1 1
+67 1 1
+1548 1 1
+40 1 1
+763 1 1
+42 1 1
+541 8 8
+88 1 1
+77 1 1
+233 11 11
+311 1 1
+22 1 1
+147 8 1
+504 1 1
+26 1 1
+996 3615 24049
+1687 0 1
+1174 1 0
+70 1 1
+1100 18 10143
+2722 1 0
+2957 1 1
+32 1 1
+9585 1 0
+1350 1 0
+473 1 0
+675 1 0
+1435 1 0
+805463 79189 0
+10872697 100000 100000
+721570 1 1
+19 1 1
+816 1 1
+44 1 1
+572 6 8
+2021 4 0
+1001 0 2
+3757 0 1
+5942 2 2
+70 1 1
+100 7 7
+395 17188 80000
+1010 1 1
+45 1 1
+1486 18 18
+173 145 1
+139 65 1
+41 16 0
+32 368 0
+44 2 50
+40 1 1
+95 52 4
+60 8 39
+12 0 16
+93 0 16
+1591 1 0
+897 13 13
+28 3 3
+2454 1 1
+44 1 1
+305 468 0
+2026 1 1
+45 1 1
+1273 3 11
+1717 0 1
+1575 4 0
+14 1 1
+2428 0 36
+50 10 154
+247 185 6
+2096 11 13
+192 1 1
+48 1 1
+130 1 1
+22 1 1
+970 1 1
+22 0 4
+76 14 0
+118 58 64
+107 1 0
+12 1 1
+53 5 15
+48 1 1
+47 2 0
+114 16 18
+363 1 1
+43 1 1
+559 1 1
+32 1 1
+3980007
+
+chain 16700437 7 159138663 + 142098195 142276197 chr7 158821424 - 16919205 17097543 171
+6297 1 0
+171 1 0
+4869 1 1
+24 0 1
+6208 0 1
+135 1 0
+1978 1 0
+764 1 1
+45 0 2
+1984 0 1
+1628 1 0
+733 1 1
+38 1 0
+137 7 7
+17 1 1
+259 1 0
+1200 1 0
+2193 4 4
+1781 0 1
+3387 1 1
+25 1 1
+125 1 1
+17 1 1
+3811 5 5
+556 0 1
+1846 5 0
+1322 1 1
+40 1 1
+228 0 1
+3477 1 1
+31 1 1
+3722 1 1
+73 1 1
+3052 66 66
+2542 15 15
+3103 0 2
+112 0 2
+1066 1 1
+59 1 0
+719 1 0
+203 1 0
+127 1 0
+30 1 0
+32 1 1
+366 0 4
+27 1 1
+2155 1 1
+41 1 1
+790 0 1
+403 1 1
+27 1 1
+648 7 7
+48 2 0
+78 2 2
+1052 4 4
+855 1 1
+68 1 1
+2428 9 0
+919 1 1
+22 1 1
+366 1 1
+36 1 1
+269 7 7
+4018 6 6
+1168 0 1
+3409 0 1
+1503 3 0
+2680 1 1
+37 1 1
+727 1 1
+28 0 5
+9 0 3
+5 0 2
+4 9 0
+13 1 1
+1801 0 3
+98 14 14
+2789 4 0
+5562 1 0
+2380 1 1
+23 1 1
+160 1 1
+57 1 1
+2413 19 19
+1704 0 1
+67 0 1
+68 1 1
+45 1 1
+176 9 9
+973 1 1
+31 3 3
+167 4 4
+334 13 13
+584 11 11
+206 16 16
+1218 1 1
+29 1 1
+234 1 1
+45 0 2
+1027 0 1
+559 10 11
+367 0 2
+8269 0 2
+4195 1 1
+62 1 1
+2896 13 13
+524 5 5
+411 1 1
+53 1 1
+126 1 1
+36 1 1
+806 1 1
+43 2 0
+1905 2 0
+414 1 1
+25 1 1
+2396 1 0
+12 1 0
+23 0 1
+10 0 1
+4 0 1
+60 0 1
+25 1 1
+1387 0 4
+3461 0 2
+1026 0 2
+821 1 1
+21 1 0
+612 1 1
+31 1 1
+1053 1 0
+2080 17 17
+9739 5 12
+17 7 0
+878 1 1
+19 1 0
+53 1 1
+839 26 26
+522 1 1
+49 1 1
+539 1 1
+25 1 1
+669 1 1
+42 1 1
+134 7 7
+1145 1 0
+2731 1 0
+590 4 0
+41 0 1
+7853 0 4
+830 0 2
+1742 2 0
+640 1 1
+34 0 2
+298 1 0
+3598 1 0
+1522 1 339
+115 18 18
+887 1 1
+69 1 1
+1662
+
+chain 1755125 7 159138663 + 143318748 143347897 chr7 158821424 - 15657394 15686558 532
+923 0 15
+1431 698 698
+3421 10 12
+405 1 1
+16 1 1
+5116 1 1
+27 1 1
+334 1 1
+15 1 0
+724 13 13
+109 0 2
+1784 1 0
+1588 1 1
+43 1 1
+908 9684 9682
+464 445 445
+982
+
+chain 939937 7 159138663 + 61402791 61412791 chr7 158821424 + 61280000 61290000 3137
+10000
+
+chain 921443 7 159138663 + 61382791 61392786 chr7 158821424 + 61260000 61269994 3741
+1722 1 0
+433 30 30
+1603 4 4
+4846 27 27
+478 19 19
+584 36 36
+212
+
+chain 898631 7 159138663 + 61392792 61402791 chr7 158821424 + 61270000 61280000 4251
+316 76 76
+3924 49 49
+2708 28 28
+1134 174 174
+156 40 41
+1394
+
+chain 896117 7 159138663 + 61422788 61432614 chr7 158821424 + 61300000 61310000 4294
+1207 50 50
+1637 22 22
+347 30 30
+983 48 48
+2562 0 172
+1941 14 14
+487 39 41
+459
+
+chain 881174 7 159138663 + 61412791 61422788 chr7 158821424 + 61290000 61300000 4600
+2588 34 34
+299 23 23
+1680 4 6
+286 395 396
+256 39 39
+220 18 18
+675 16 16
+3464
+
+chain 807485 7 159138663 + 61372814 61382791 chr7 158821424 + 61250000 61260000 5800
+91 75 75
+308 91 91
+99 88 88
+175 43 43
+577 65 65
+289 17 17
+186 21 21
+119 72 72
+80 98 98
+114 2 1
+115 51 51
+319 90 97
+54 49 50
+590 135 136
+749 1 0
+467 41 41
+153 21 21
+97 102 118
+935 19 19
+3186 43 43
+150
+
+chain 475263 7 159138663 + 143336322 143346915 chr7 158821424 - 15765291 15775883 242
+2017 14 14
+1214 1 1
+32 1 1
+3171 0 8
+760 1 1
+49 1 1
+68 10 10
+1210 1 1
+39 1 1
+60 18 9
+568 4 4
+357 12 12
+75 512 512
+397
+
+chain 413572 7 159138663 + 61432614 61437066 chr7 158821424 + 61310000 61314455 110492
+105 12 12
+1311 18 21
+3006
+
+chain 327362 7 159138663 + 130261501 130267755 chr7 158821424 - 80118425 80124354 202501
+81 547 220
+108 98 98
+188 35 35
+305 168 168
+59 47 46
+67 25 25
+301 6 6
+107 44 44
+133 23 23
+174 0 4
+110 27 27
+188 31 31
+86 62 62
+284 66 66
+205 34 34
+171 16 16
+85 35 35
+152 206 205
+64 33 33
+71 76 76
+129 26 26
+52 79 80
+203 92 92
+193 64 64
+113 490 490
+131 98 97
+66
+
+chain 116757 7 159138663 + 56987924 57001476 chr7 158821424 - 96066875 96080423 71
+182 4 0
+366 2 0
+47 6 0
+1290 7 1
+317 25 25
+90 14 15
+195 1 6
+96 1 1
+280 1 1
+59 1 1
+435 1 1
+51 1 1
+1067 22 22
+3594 0 1
+645 0 1
+507 7 7
+1383 0 6
+531 0 1
+1396 1 0
+927
+
+chain 94083 7 159138663 + 61667110 61669673 chr9 140273252 - 71180528 71183093 1349166
+123 22 22
+57 154 154
+93 530 532
+407 16 16
+95 28 28
+72 290 290
+83 43 43
+61 266 266
+77 77 77
+69
+
+chain 75094 7 159138663 + 433321 434167 chr14 106368585 - 82907729 82908574 1677524
+115 1 1
+30 1 0
+335 22 22
+342
+
+chain 74694 7 159138663 + 61674373 61676412 chr2 242951149 + 91627954 91629996 1686429
+59 154 155
+210 438 438
+221 259 259
+81 77 77
+52 201 203
+222 15 15
+50
+
+chain 54428 7 159138663 + 61360568 61361523 chr9 140273252 + 69464390 69465353 2322078
+76 100 105
+56 176 179
+432 51 51
+64
+
+chain 45723 7 159138663 + 100554977 100556023 chr7 158821424 + 100392913 100393963 2803709
+153 225 232
+246 8 8
+74 288 285
+52
+
+chain 42415 7 159138663 + 130262863 130266857 chr20 62435964 + 18530662 18534660 203154
+65 162 162
+47 67 67
+25 425 425
+33 1127 1130
+57 206 206
+33 274 274
+33 152 152
+121 149 149
+33 83 83
+64 129 129
+26 335 336
+91 194 194
+63
+
+chain 34286 7 159138663 + 61670163 61670988 chr1 247249719 - 187008143 187008914 3936433
+177 89 89
+59 338 284
+162
+
+chain 30309 7 159138663 + 61417768 61418394 chr15 100338915 + 53005912 53006538 319980
+332 256 256
+38
+
+chain 29619 7 159138663 + 130261638 130262129 chr18 76117153 - 20889181 20889344 211760
+82 389 61
+20
+
+chain 28749 7 159138663 + 102187071 102200348 chr7 158821424 + 102073398 102086671 912
+74 1102 1102
+32 11867 11863
+202
+
+chain 27540 7 159138663 + 61526936 61527567 chr17 78774742 - 13987513 13988140 5824140
+131 255 251
+90 52 52
+103
+
+chain 25455 7 159138663 + 61658206 61658677 chr21 46944323 + 31224827 31225297 6797318
+187 186 185
+98
+
+chain 25398 7 159138663 + 130275431 130276578 chrX 154913754 + 99697151 99697788 219009
+66 77 207
+69 353 1
+53 369 81
+54 49 49
+57
+
+chain 24368 7 159138663 + 61663982 61664383 chr7 158821424 - 97410910 97411311 7475570
+54 99 99
+67 16 16
+165
+
+chain 23018 7 159138663 + 61372081 61372809 chr7 158821424 + 61249436 61249995 8282044
+79 92 92
+52 313 144
+58 34 34
+100
+
+chain 22330 7 159138663 + 61674796 61675234 chr16 88827254 - 56087354 56087792 5126597
+69 100 100
+51 129 129
+89
+
+chain 22048 7 159138663 + 61583753 61648197 chr7 158821424 - 97506969 97571424 1587
+3024 0 1
+5860 1 1
+34 1 1
+1210 1 1
+46 1 1
+1360 1 1
+20 1 1
+6247 7 7
+2011 22 23
+15979 1 1
+20 0 1
+39 1 1
+156 1 1
+79 1 1
+1227 1 1
+26 1 1
+201 17 17
+6321 11 11
+106 2 2
+66 33 33
+316 6 6
+832 1 1
+17 1 1
+478 1 1
+25 1 1
+4306 14 0
+14 1 1
+525 4 4
+1603 1 1
+28 1 1
+433 1 0
+1365 1 1
+35 1 1
+3699 1 1
+17 1 1
+962 0 16
+124 1 1
+221 1 1
+50 1 1
+446 1 0
+788 0 1
+38 1 1
+470 14 14
+173 1 1
+48 0 1
+54 1 1
+71 0 7
+17 1 1
+319 1 1
+49 1 1
+115 2 1
+167 1 1
+41 3 3
+80 1 1
+70 1 1
+119 1 1
+19 1 1
+186 17 17
+347 7 7
+549 1 1
+69 1 1
+175 1 1
+55 1 1
+101 1 1
+118 2 2
+307 1 1
+73 1 1
+91
+
+chain 20717 7 159138663 + 61531674 61531894 chrY 57772954 + 23149505 23149725 9889131
+220
+
+chain 20603 7 159138663 + 61525953 61526232 chr8 146274826 + 92437703 92437982 9974457
+114 48 48
+117
+
+chain 20209 7 159138663 + 61534129 61534693 chr5 180857866 - 39454690 39455254 10284708
+41 129 129
+72 189 189
+133
+
+chain 19256 7 159138663 + 10000 10238 chr11 134452384 - 108 510 10867298
+115 1 145
+57 3 0
+12 3 26
+47
+
+chain 17549 7 159138663 + 23954 24387 chr3 199501827 - 125819 126212 1017
+61 27 17
+87 27 17
+87 27 17
+87 27 17
+3
+
+chain 17511 7 159138663 + 61459516 61459775 chr3 199501827 + 156410667 156410926 12559831
+104 60 60
+95
+
+chain 17423 7 159138663 + 130286013 130286315 chr3 199501827 + 134941335 134941641 12635149
+64 74 78
+72 18 18
+74
+
+chain 17216 7 159138663 + 61561042 61561226 chr18 76117153 + 1344411 1344595 12834816
+184
+
+chain 15818 7 159138663 + 130258842 130259235 chr20 62435964 - 56174662 56175052 14212289
+60 144 139
+68 52 54
+69
+
+chain 15803 7 159138663 + 434188 434399 chr9 140273252 - 53303336 53303547 1693631
+211
+
+chain 15460 7 159138663 + 61363520 61363685 chr14 106368585 + 46013452 46013617 14586403
+165
+
+chain 15455 7 159138663 + 61533249 61533413 chr10 135374737 - 122138066 122138230 14591550
+164
+
+chain 14801 7 159138663 + 61526597 61527118 chr11 134452384 + 128715236 128715756 6490404
+89 98 98
+58 225 224
+51
+
+chain 14577 7 159138663 + 61459836 61459991 chr2 242951149 - 172428837 172428992 15528208
+155
+
+chain 14381 7 159138663 + 61532809 61533249 chr5 180857866 - 128913075 128913510 15277847
+110 278 273
+52
+
+chain 14182 7 159138663 + 61362349 61362804 chr1 247249719 - 101935287 101935742 15983329
+55 287 287
+113
+
+chain 13384 7 159138663 + 130261760 130262050 chr18 76117153 - 65538588 65538878 302793
+128 17 17
+145
+
+chain 12863 7 159138663 + 61659684 61659821 chr18 76117153 + 15161457 15161594 17682773
+137
+
+chain 12713 7 159138663 + 130268588 130270221 chr7 158821424 - 62883278 62884905 17912238
+74 1316 1311
+67 121 120
+55
+
+chain 12498 7 159138663 + 61527567 61527825 chr2 242951149 - 136022598 136022856 13034573
+7 155 155
+96
+
+chain 12424 7 159138663 + 61560835 61560980 chr21 46944323 - 5411573 5411718 18347201
+82 1 1
+62
+
+chain 11917 7 159138663 + 130274671 130277102 chr2 242951149 + 85567844 85569506 1111973
+198 73 73
+65 403 530
+21 111 209
+32 1149 157
+77 81 81
+50 6 4
+165
+
+chain 11414 7 159138663 + 61446485 61446604 chr8 146274826 - 97728756 97728875 19987436
+119
+
+chain 11204 7 159138663 + 323186 323319 chr13 114142980 - 47557127 47557260 20361650
+67 7 7
+59
+
+chain 11191 7 159138663 + 61533547 61533688 chr10 135374737 + 121736617 121736758 14568606
+63 20 20
+58
+
+chain 11162 7 159138663 + 143321102 143321761 chr7 158821424 + 143031254 143031913 1465
+659
+
+chain 11033 7 159138663 + 155133717 155133867 chr7 158821424 + 154826660 154826810 3228542
+150
+
+chain 10743 7 159138663 + 130272956 130273070 chr20 62435964 - 54784771 54784885 21217928
+114
+
+chain 10697 7 159138663 + 61363082 61363210 chr8 146274826 + 114533399 114533527 21308454
+63 1 1
+64
+
+chain 10686 7 159138663 + 130276049 130276418 chr5 180857866 - 110000669 110000947 1711166
+8 218 161
+54 34 0
+55
+
+chain 10550 7 159138663 + 61534371 61534497 chr2 242951149 - 102597516 102597642 13706867
+22 1 1
+103
+
+chain 10502 7 159138663 + 61658058 61658206 chr3 199501827 - 100394760 100394909 7999945
+74 51 52
+23
+
+chain 9908 7 159138663 + 155127373 155127651 chr7 158821424 + 154820991 154821604 23020589
+62 155 490
+61
+
+chain 9705 7 159138663 + 130254993 130255333 chr5 180857866 - 86134908 86135248 23505792
+58 220 220
+62
+
+chain 9691 7 159138663 + 61363878 61364175 chr6 170899992 - 83481581 83481894 23533804
+52 178 194
+67
+
+chain 9557 7 159138663 + 130275060 130277190 chr4 191273063 + 57733996 57734920 1639272
+2 161 201
+75 1804 558
+40 10 10
+38
+
+chain 9406 7 159138663 + 61531909 61532009 chr3 199501827 - 114948547 114948647 24221847
+100
+
+chain 9378 7 159138663 + 61670488 61670618 chr1 247249719 + 166585217 166585347 4198164
+130
+
+chain 9215 7 159138663 + 61369893 61370445 chr20 62435964 + 26207014 26207215 24594255
+60 436 85
+56
+
+chain 8793 7 159138663 + 61533688 61534015 chr8 146274826 + 132629025 132629349 11801047
+54 54 51
+58 97 97
+64
+
+chain 8578 7 159138663 + 61650566 61651111 chr20 62435964 - 36228749 36228943 25570183
+56 436 85
+53
+
+chain 8304 7 159138663 + 61532721 61532809 chr5 180857866 - 33354116 33354204 19653256
+88
+
+chain 8273 7 159138663 + 61375213 61375308 chr10 135374737 - 99567310 99567405 2885342
+95
+
+chain 7707 7 159138663 + 61670340 61670429 chr11 134452384 + 5653851 5653940 4693035
+89
+
+chain 7687 7 159138663 + 61362996 61363078 chr1 247249719 - 62796192 62796274 26921084
+82
+
+chain 7328 7 159138663 + 130260449 130260631 chr6 170899992 + 18975635 18975819 23797357
+8 121 123
+53
+
+chain 7084 7 159138663 + 155107000 155107125 chr8 146274826 + 127792382 127792507 21399384
+5 63 63
+57
+
+chain 6750 7 159138663 + 130268276 130268348 chr9 140273252 + 6309168 6309240 28699203
+72
+
+chain 6727 7 159138663 + 61364306 61364811 chr19 63811651 + 24391898 24393602 28746452
+47 400 1599
+58
+
+chain 6689 7 159138663 + 130262523 130267689 chr14 106368585 - 15396362 15401535 205901
+35 1928 1932
+35 3110 3113
+58
+
+chain 6657 7 159138663 + 130262248 130266269 chr20 62435964 - 53906684 53910704 204336
+68 3910 3909
+43
+
+chain 6632 7 159138663 + 61362621 61362691 chr14 106368585 - 25756639 25756709 18227251
+70
+
+chain 6604 7 159138663 + 61516196 61516266 chr14 106368585 + 18700177 18700247 29040667
+70
+
+chain 6561 7 159138663 + 61362487 61362621 chr5 180857866 - 77495083 77495217 25581093
+60 70 70
+4
+
+chain 6504 7 159138663 + 61563734 61563803 chr14 106368585 + 18700333 18700402 29292943
+69
+
+chain 6504 7 159138663 + 61457014 61457083 chr14 106368585 + 19014991 19015060 29292944
+69
+
+chain 6486 7 159138663 + 61439583 61439652 chr7 158821424 + 61677724 61677793 29330266
+69
+
+chain 6486 7 159138663 + 61453269 61453338 chr11 134452384 + 54672038 54672107 29330599
+69
+
+chain 6415 7 159138663 + 130266970 130267081 chr2 242951149 - 44689835 44689946 206027
+111
+
+chain 6395 7 159138663 + 61581171 61581239 chr12 132349534 + 36481345 36481413 29552558
+68
+
+chain 6295 7 159138663 + 130268491 130268558 chr12 132349534 - 16670768 16670835 29797454
+67
+
+chain 6222 7 159138663 + 61516757 61516823 chr7 158821424 - 100865546 100865612 29971261
+66
+
+chain 6149 7 159138663 + 61518444 61518509 chr9 140273252 - 73547747 73547812 30146556
+65
+
+chain 6147 7 159138663 + 61360661 61361459 chr1 247249719 - 99965931 99966729 2490905
+65 694 694
+39
+
+chain 6131 7 159138663 + 61545392 61545457 chr9 140273252 - 71283139 71283204 30224431
+65
+
+chain 6031 7 159138663 + 61649702 61649766 chr8 146274826 - 102385209 102385273 30479392
+64
+
+chain 5940 7 159138663 + 61567501 61567564 chr11 134452384 - 79723078 79723141 30715303
+63
+
+chain 5895 7 159138663 + 130261352 130261415 chr12 132349534 - 16670326 16670389 30822868
+63
+
+chain 5890 7 159138663 + 130272150 130272376 chr5 180857866 - 150003108 150003332 287879
+73 71 69
+82
+
+chain 5831 7 159138663 + 61540614 61540676 chr20 62435964 + 26207004 26207066 31016062
+62
+
+chain 5822 7 159138663 + 61534741 61534803 chr2 242951149 + 182601389 182601451 31037299
+62
+
+chain 5767 7 159138663 + 61657263 61657324 chrX 154913754 + 145511099 145511160 31173265
+61
+
+chain 5740 7 159138663 + 61561871 61561932 chrX 154913754 + 61825831 61825892 31255925
+61
+
+chain 5707 7 159138663 + 155133639 155133717 chr7 158821424 + 154826660 154826738 3248987
+78
+
+chain 5671 7 159138663 + 130267178 130267274 chr3 199501827 + 136865539 136865635 212140
+96
+
+chain 5649 7 159138663 + 61510793 61510853 chr14 106368585 + 18700200 18700260 31523979
+60
+
+chain 5614 7 159138663 + 61459620 61459680 chr8 146274826 + 85828676 85828736 12834914
+60
+
+chain 5505 7 159138663 + 130286091 130286151 chr11 134452384 + 126327988 126328048 18815467
+60
+
+chain 5376 7 159138663 + 61368713 61368770 chr5 180857866 - 134492854 134492911 32331066
+57
+
+chain 5358 7 159138663 + 130272706 130272763 chr4 191273063 - 62601703 62601760 32378845
+57
+
+chain 5239 7 159138663 + 61375927 61375982 chr3 199501827 + 176568366 176568421 32719676
+55
+
+chain 5238 7 159138663 + 155133561 155133639 chr7 158821424 + 154826660 154826738 3316763
+78
+
+chain 5212 7 159138663 + 48202742 48202797 chrY 57772954 + 8140437 8140492 32786933
+55
+
+chain 5203 7 159138663 + 61362897 61362952 chr2 242951149 - 204521553 204521608 32840726
+55
+
+chain 5203 7 159138663 + 61514738 61514793 chr3 199501827 - 109094736 109094791 32841435
+55
+
+chain 5196 7 159138663 + 102270836 102270891 chr7 158821424 + 101958735 101958790 2864
+55
+
+chain 5085 7 159138663 + 61522548 61522602 chr11 134452384 - 85760698 85760752 33224588
+54
+
+chain 5081 7 159138663 + 61542952 61543361 chrX 154913754 - 96402533 96402599 33252017
+22 343 0
+44
+
+chain 5076 7 159138663 + 61566776 61566830 chrX 154913754 + 58536057 58536111 33266851
+54
+
+chain 5003 7 159138663 + 321166 321219 chr9 140273252 + 26769862 26769915 33490833
+53
+
+chain 4985 7 159138663 + 61511756 61511809 chrX 154913754 + 58510881 58510934 33583214
+53
+
+chain 4976 7 159138663 + 61453966 61454019 chr11 134452384 + 48695047 48695100 33600288
+53
+
+chain 4976 7 159138663 + 61579973 61580026 chr12 132349534 + 36420396 36420449 33600992
+53
+
+chain 4967 7 159138663 + 61528283 61528336 chr2 242951149 - 102597577 102597630 33622422
+53
+
+chain 4930 7 159138663 + 61528065 61528117 chr11 134452384 - 85701922 85701974 33735561
+52
+
+chain 4921 7 159138663 + 61566142 61566194 chr3 199501827 - 104503080 104503132 33762259
+52
+
+chain 4903 7 159138663 + 61364673 61364725 chr9 140273252 + 69253479 69253531 33844300
+52
+
+chain 4894 7 159138663 + 61535225 61535277 chrX 154913754 + 61822223 61822275 33894839
+52
+
+chain 4894 7 159138663 + 61555289 61555341 chrX 154913754 - 93093366 93093418 33894887
+52
+
+chain 4894 7 159138663 + 61367691 61367743 chr11 134452384 + 48824621 48824673 33895037
+52
+
+chain 4876 7 159138663 + 61446263 61446315 chr11 134452384 + 54670005 54670057 33929755
+52
+
+chain 4860 7 159138663 + 61671055 61671121 chr6 170899992 - 77150208 77150274 16663217
+66
+
+chain 4803 7 159138663 + 61582505 61582556 chr5 180857866 + 46128392 46128443 34201035
+51
+
+chain 4803 7 159138663 + 61548133 61548184 chr5 180857866 - 134730739 134730790 34201101
+51
+
+chain 4803 7 159138663 + 61656299 61656350 chr8 146274826 - 102385679 102385730 34201707
+51
+
+chain 4803 7 159138663 + 61371246 61371297 chr20 62435964 + 26207164 26207215 34201851
+51
+
+chain 4803 7 159138663 + 61538491 61538542 chrX 154913754 + 61822744 61822795 34202106
+51
+
+chain 4803 7 159138663 + 61550591 61550642 chrX 154913754 - 96402828 96402879 34202170
+51
+
+chain 4794 7 159138663 + 61568385 61568436 chr12 132349534 - 30627763 30627814 34229426
+51
+
+chain 4794 7 159138663 + 61560404 61560455 chrX 154913754 + 58511165 58511216 34229878
+51
+
+chain 4785 7 159138663 + 61555628 61555679 chr5 180857866 + 49580248 49580299 34261015
+51
+
+chain 4757 7 159138663 + 155127495 155127545 chr7 158821424 + 154820841 154820891 34330191
+50
+
+chain 4745 7 159138663 + 61527127 61527200 chr1 247249719 - 196249350 196249423 12580328
+73
+
+chain 4730 7 159138663 + 61454627 61454677 chrX 154913754 - 93091546 93091596 34451023
+50
+
+chain 4721 7 159138663 + 61547785 61547835 chr14 106368585 + 19015139 19015189 34474345
+50
+
+chain 4712 7 159138663 + 61542078 61542128 chr7 158821424 - 97143221 97143271 34536293
+50
+
+chain 4712 7 159138663 + 61650232 61650282 chr7 158821424 + 61292872 61292922 34536325
+50
+
+chain 4712 7 159138663 + 61447406 61447456 chr12 132349534 - 95867613 95867663 34536696
+50
+
+chain 4712 7 159138663 + 61573362 61573412 chr11 134452384 - 79778078 79778128 34537090
+50
+
+chain 4694 7 159138663 + 61361784 61361834 chr20 62435964 + 26208957 26209007 34582417
+50
+
+chain 4533 7 159138663 + 61657325 61657373 chr14 106368585 - 60354968 60355016 14458107
+48
+
+chain 4330 7 159138663 + 61571756 61571802 chrX 154913754 + 58511174 58511220 34815702
+46
+
+chain 4322 7 159138663 + 61527200 61527268 chr1 247249719 + 66112503 66112571 10645536
+68
+
+chain 4309 7 159138663 + 130262963 130263031 chr20 62435964 + 59813 59881 233275
+68
+
+chain 4243 7 159138663 + 130267293 130267390 chr15 100338915 - 46124324 46124421 430805
+97
+
+chain 4225 7 159138663 + 130272413 130272571 chr3 199501827 - 60665919 60666077 310359
+158
+
+chain 4225 7 159138663 + 130275130 130275387 chr10 135374737 + 61126513 61126771 1703431
+71 112 113
+74
+
+chain 4135 7 159138663 + 61657814 61657864 chr4 191273063 - 103880681 103880731 24177091
+50
+
+chain 4106 7 159138663 + 130265690 130265763 chr2 242951149 + 45160326 45160399 259070
+73
+
+chain 4049 7 159138663 + 61417706 61417751 chr19 63811651 + 35324192 35324237 995629
+45
+
+chain 4036 7 159138663 + 102224324 102224366 chr7 158821424 + 102110621 102110663 1050243
+42
+
+chain 3993 7 159138663 + 130270112 130270163 chr3 199501827 - 142320121 142320172 24066397
+51
+
+chain 3975 7 159138663 + 130269077 130269119 chr8 146274826 + 76339197 76339239 33761016
+42
+
+chain 3893 chr7 159138663 + 61535529 61535570 chr9_random 1146434 - 229264 229305 35008771
+41
+
+chain 3839 7 159138663 + 61659187 61659228 chr7 158821424 - 97183039 97183080 35036445
+41
+
+chain 3820 7 159138663 + 143397897 143397937 chr7 158821424 - 15657354 15657394 1380183
+40
+
+chain 3770 7 159138663 + 130272223 130272265 chr7 158821424 - 144399150 144399192 18136384
+42
+
+chain 3724 7 159138663 + 61669828 61671669 chr18 76117153 - 60916397 60916965 5934170
+170 1399 126
+50 156 156
+66
+
+chain 3694 7 159138663 + 130276177 130276253 chrX 154913754 + 40955942 40956018 2422661
+76
+
+chain 3685 7 159138663 + 102274757 102274796 chr7 158821424 + 101962659 101962698 2923
+39
+
+chain 3592 7 159138663 + 102246649 102246687 chr7 158821424 + 101934491 101934529 2920
+38
+
+chain 3540 7 159138663 + 61670988 61671026 chr1 247249719 - 1293349 1293387 6950988
+38
+
+chain 3536 7 159138663 + 155127890 155127927 chr7 158821424 + 154820516 154820553 31559480
+37
+
+chain 3498 chr7 159138663 + 61668816 61668875 chr21_random 1679693 + 339817 339876 2744470
+59
+
+chain 3321 7 159138663 + 130259738 130259803 chr5 180857866 + 117134963 117135028 22545496
+65
+
+chain 3254 7 159138663 + 155127171 155127205 chr7 158821424 + 154821284 154821318 30495954
+34
+
+chain 3179 7 159138663 + 61671122 61671197 chr3 199501827 + 3741295 3741370 21259213
+75
+
+chain 3139 7 159138663 + 61669998 61670032 chr7 158821424 - 73313700 73313734 35261607
+34
+
+chain 3136 7 159138663 + 155133873 155133906 chr7 158821424 + 154826660 154826693 3164897
+33
+
+chain 3128 7 159138663 + 61657490 61657523 chr14 106368585 + 19500965 19500998 15505654
+33
+
+chain 3124 7 159138663 + 61362864 61362897 chr13 114142980 - 56785908 56785941 33122705
+33
+
+chain 3114 7 159138663 + 61363362 61363395 chr11 134452384 + 38920746 38920779 30450202
+33
+
+chain 3035 7 159138663 + 130267390 130267459 chr5 180857866 + 148307658 148307727 349562
+69
+
+chain 3005 7 159138663 + 130258675 130258738 chr3 199501827 - 66319298 66319361 23438786
+63
+
+chain 2998 7 159138663 + 61670741 61670826 chr2 242951149 - 144372974 144373059 5019535
+68 11 11
+6
+
+chain 2929 7 159138663 + 61366904 61366935 chr9 140273252 + 69000834 69000865 35330365
+31
+
+chain 2883 7 159138663 + 130274908 130276723 chr12 132349534 - 84232022 84233270 1810563
+34 1716 687
+63 1 463
+1
+
+chain 2844 7 159138663 + 61525923 61525953 chr11 134452384 + 42874872 42874902 16620335
+30
+
+chain 2837 7 159138663 + 155133483 155133522 chr7 158821424 + 154826738 154826777 5314872
+39
+
+chain 2752 7 159138663 + 130270309 130270363 chr15 100338915 - 53351487 53351541 22720352
+54
+
+chain 2749 7 159138663 + 61657932 61657999 chr9 140273252 + 120725102 120725169 13790105
+67
+
+chain 2677 7 159138663 + 61657615 61657668 chr2 242951149 - 80490248 80490301 14907722
+53
+
+chain 2675 7 159138663 + 61657868 61657928 chr14 106368585 - 67199431 67199491 8049700
+60
+
+chain 2656 7 159138663 + 61658132 61658174 chr14 106368585 - 39618235 39618277 11504442
+42
+
+chain 2625 7 159138663 + 61376053 61376101 chr2 242951149 - 165273826 165273874 3000213
+48
+
+chain 2574 7 159138663 + 130285941 130286005 chr3 199501827 + 177805790 177805854 20115306
+64
+
+chain 2555 7 159138663 + 61657373 61657490 chr10 135374737 + 110991454 110991571 9489838
+117
+
+chain 2533 7 159138663 + 130255333 130255360 chr5 180857866 + 110504974 110505001 34260994
+27
+
+chain 2525 7 159138663 + 155133522 155133561 chr7 158821424 + 154826699 154826738 3760022
+39
+
+chain 2511 7 159138663 + 130261431 130261481 chr6 170899992 - 80902268 80902318 240832
+50
+
+chain 2491 7 159138663 + 130275062 130277276 chr7 158821424 + 139777825 139778654 1647744
+34 1723 339
+29 404 403
+24
+
+chain 2465 7 159138663 + 102229230 102229256 chr7 158821424 + 101917063 101917089 2852
+26
+
+chain 2367 7 159138663 + 61656836 61656861 chr8 146274826 - 114798799 114798824 27799318
+25
+
+chain 2262 7 159138663 + 61363303 61363362 chr15 100338915 - 25052381 25052440 19971588
+59
+
+chain 2184 7 159138663 + 61360913 61360944 chr16 88827254 + 45047397 45047428 3009512
+31
+
+chain 2183 7 159138663 + 61655805 61655828 chr8 146274826 - 102376418 102376441 35497387
+23
+
+chain 2181 7 159138663 + 61362804 61362827 chr8 146274826 - 64142945 64142968 28339747
+23
+
+chain 2177 7 159138663 + 61363497 61363520 chr15 100338915 - 57516283 57516306 24810342
+23
+
+chain 2111 7 159138663 + 102252256 102252279 chr7 158821424 + 101940282 101940305 3979
+23
+
+chain 2085 7 159138663 + 61668033 61668084 chr9 140273252 + 42719058 42719109 1926685
+51
+
+chain 2073 7 159138663 + 130274605 130277252 chr2 242951149 - 168073547 168075372 1534321
+53 350 351
+52 688 693
+76 1025 208
+32 309 298
+62
+
+chain 2067 7 159138663 + 155127207 155127236 chr7 158821424 + 154821033 154821062 24052540
+29
+
+chain 2049 7 159138663 + 130259609 130260449 chr2 242951149 + 217320568 217321411 19749334
+52 691 694
+97
+
+chain 1867 7 159138663 + 61360944 61360976 chr1 247249719 + 146935382 146935414 2538402
+32
+
+chain 1866 7 159138663 + 130286570 130286642 chr8 146274826 + 120193638 120193710 13784733
+72
+
+chain 1860 7 159138663 + 130271889 130271917 chr3 199501827 + 158050218 158050246 8145167
+28
+
+chain 1834 7 159138663 + 130267107 130267162 chr2 242951149 - 74722759 74722814 2183237
+55
+
+chain 1810 7 159138663 + 434399 434426 chr8 146274826 + 50019771 50019798 1840028
+27
+
+chain 1807 7 159138663 + 61459483 61459516 chr20 62435964 - 10907955 10907988 13772492
+33
+
+chain 1749 7 159138663 + 61534521 61534560 chr8 146274826 - 57707270 57707309 18613209
+39
+
+chain 1741 7 159138663 + 130275927 130275994 chr3 199501827 - 85253648 85253715 1907688
+67
+
+chain 1725 7 159138663 + 130286346 130286404 chr5 180857866 - 156929708 156929766 24410167
+58
+
+chain 1675 7 159138663 + 61360800 61360833 chr2 242951149 - 151940057 151940090 10244640
+33
+
+chain 1649 7 159138663 + 61527639 61527689 chr10 135374737 - 21832678 21832728 15020107
+50
+
+chain 1626 7 159138663 + 61525699 61525759 chr5 180857866 + 119849560 119849620 22270263
+60
+
+chain 1538 7 159138663 + 130271917 130271979 chrX 154913754 + 106499092 106499154 335529
+62
+
+chain 1512 7 159138663 + 130270436 130270487 chr7 158821424 + 123638895 123638946 23964536
+51
+
+chain 1449 7 159138663 + 61671198 61671257 chr11 134452384 + 48551200 48551259 6005368
+59
+
+chain 1444 7 159138663 + 130272046 130272150 chr5 180857866 - 107650838 107650942 1109190
+41 46 46
+17
+
+chain 1406 7 159138663 + 130268385 130269191 chr13 114142980 + 104373808 104374629 24734362
+65 682 697
+59
+
+chain 1391 7 159138663 + 130271979 130272046 chr12 132349534 + 128856107 128856174 572332
+67
+
+chain 1342 7 159138663 + 130255652 130255716 chr6 170899992 - 118498216 118498280 24733557
+64
+
+chain 1277 7 159138663 + 61525407 61525458 chr14 106368585 - 54569941 54569992 25208354
+51
+
+chain 1239 7 159138663 + 61657050 61657132 chr1 247249719 + 60704689 60704771 10216239
+82
+
+chain 1222 7 159138663 + 24387 24410 chr9 140273252 - 34976 34999 792
+23
+
+chain 1201 7 159138663 + 130267591 130267617 chr3 199501827 - 22519451 22519477 371093
+26
+
+chain 1176 7 159138663 + 61533413 61533439 chr9 140273252 + 78066621 78066647 21815254
+26
+
+chain 1159 7 159138663 + 130255953 130256003 chr18 76117153 + 30232927 30232977 26680295
+50
+
+chain 1143 7 159138663 + 130272637 130272705 chr4 191273063 - 164951872 164951940 23193314
+68
+
+chain 1120 7 159138663 + 130267081 130267107 chr4 191273063 + 53894987 53895013 453066
+26
+
+chain 1090 7 159138663 + 61375539 61375583 chr16 88827254 - 2017000 2017044 2867569
+44
+
+chain 967 7 159138663 + 61363930 61363960 chr5 180857866 - 77417997 77418027 26429199
+30
+
+chain 922 7 159138663 + 130269744 130269794 chr6 170899992 - 168370205 168370255 24919326
+50
+
+chain 916 7 159138663 + 130272376 130272413 chr7 158821424 - 119807072 119807109 361270
+37
+
+chain 903 7 159138663 + 130274518 130274571 chr18 76117153 + 7087852 7087905 2747041
+53
+
+chain 875 7 159138663 + 61656861 61656912 chr1 247249719 - 3737712 3737763 19994037
+51
+
+chain 825 7 159138663 + 130276127 130276177 chr9 140273252 + 78760365 78760415 3856900
+50
+
+chain 821 7 159138663 + 61657151 61657205 chr18 76117153 - 50729761 50729815 10763263
+54
+
+chain 764 7 159138663 + 155106965 155107000 chr2 242951149 - 97843675 97843710 19287766
+35
+
+chain 760 7 159138663 + 130260179 130260244 chr15 100338915 - 29035916 29035981 5017751
+65
+
+chain 738 7 159138663 + 61528144 61528186 chr5 180857866 + 37689556 37689598 26578239
+42
+
+chain 665 7 159138663 + 61657587 61657615 chr4 191273063 - 56344538 56344566 26451583
+28
+
+chain 506 7 159138663 + 130259438 130259491 chr7 158821424 - 81365049 81365102 23441660
+53
+
+chain 492 7 159138663 + 130276335 130276363 chr8 146274826 - 17074751 17074779 8865204
+28
+
+chain 466 7 159138663 + 130268939 130269012 chr2 242951149 - 225017173 225017246 26097376
+73
+
+chain 388 7 159138663 + 130271813 130271889 chr3 199501827 + 120370918 120370994 4694596
+76
+
+chain 379 7 159138663 + 130275097 130275130 chr3 199501827 + 9586745 9586778 4580558
+33
+
+chain 379 7 159138663 + 61363702 61363740 chr5 180857866 - 91082220 91082258 29303651
+38
+
+chain 348 7 159138663 + 102200504 102200535 chr7 158821424 - 57045045 57045076 1079
+31
+
+chain 17312866 chr7_gl000195_random 182896 + 0 182896 chr7_random 549659 + 162804 345700 162
+182896
+
+chain 13484003737 8 146364022 + 10000 146304022 chr8 146274826 + 0 146274826 9
+930417 1243 1
+52 10 10
+91 972 0
+54 54 0
+281 324 0
+289 1 0
+2323216 0 1
+3352649 0 2
+854996 50000 100000
+3399023 1 1
+46 1 1
+13965 1 1
+30 1 1
+121189 1 1
+35 1 1
+283700 1 0
+719291 93054 100016
+1155 2 0
+755 26 26
+980 21 21
+1479 422 422
+3229 0 1
+1937 1 1
+17 1 1
+322 0 1
+1758 0 2
+1141 1 0
+956 48 48
+1765 1 0
+543 25 25
+7047 15 15
+1029 1 1
+28 1 1
+314 1 1
+46 1 1
+164 1 1
+25 1 1
+5130707 1 0
+1288 1 0
+446 1 1
+80 1 1
+2123 4 4
+2514 0 3
+545 0 9
+527 1 1
+18 1 1
+256 9 9
+79 1 1
+40 1 1
+148 2 0
+2236 27 0
+953 1 1
+20 1 1
+2487 1 1
+113 1 1
+73 13 13
+365 10 10
+151 1 1
+32 0 3
+26 1 1
+1480 1 1
+29 1 1
+621 1 1
+28 1 1
+701 9 9
+362 1 1
+19 1 1
+691 1 1
+45 0 6
+46 1 1
+513 11 12
+382 1 1
+22 1 1
+111 1 1
+36 1 1
+337 1 1
+42 1 1
+602 0 2
+36 1 1
+475 1 1
+23 1 0
+32 3 4
+65 1 1
+59 1 1
+688 1 1
+22 1 1
+1473 1 1
+36 1 1
+372 1 1
+16 6 6
+640 25 25
+940 1 1
+38 1 1
+816 1 1
+17 0 1
+374 1 1
+17 1 1
+48 0 1
+82 1 1
+45 1 1
+263 1 1
+23 1 1
+204 1 1
+39 1 1
+2341 1 0
+2989 1 0
+9 1 0
+811 8 8
+741 2 0
+337 1 1
+25 4 4
+763 1 1
+19 1 1
+343 1 1
+31 1 1
+1953 1 1
+74 1 1
+67 1 1
+18 4 4
+73 1 1
+31 1 1
+114 1 11
+87 1 1
+65 1 1
+125 9 9
+378 0 1
+47 1 1
+90 1 1
+96 0 1
+176 7 13
+696 1 0
+6184 13 13
+830 13 13
+128 1 1
+37 1 1
+136 0 1
+66 6 5
+870 0 1
+4877 1 0
+585 7 3
+1728 0 1
+33 1 1
+465 1 1
+68 1 1
+581 0 6
+2088 0 1
+304 1 0
+2674 1 1
+28 0 1
+54 8 8
+846 1 0
+1409 16 16
+559 1 0
+401 5 0
+17 1 5
+29 1 1
+4051 1 1
+10 1 0
+43 1 1
+385 1 1
+35 1 1
+101 11 11
+602 0 1
+491 16 14
+1366 19 19
+321 1 1
+49 1 1
+546 1 1
+25 1 1
+1333 28 28
+1207 1 1
+51 0 4
+159 1 0
+1040 1 0
+1682 4 0
+34 0 8
+867 1 1
+17 1 1
+587 1 1
+21 1 1
+904 1 0
+261 1 0
+1151 2 0
+2325 5 5
+5415 3 0
+1545 0 1
+428 4 4
+1950 0 2
+1073 1 0
+3658 86 0
+1278 1 1
+79 1 1
+6656 12 12
+1550 18 0
+5832 0 1
+4835 10 10
+1719 1 1
+84 1 1
+848 2 0
+236 1 1
+42 1 1
+1286 0 12
+35 1 1
+820 1 1
+22 0 1
+63 22 0
+167 23 23
+315 8 8
+983 0 6
+539 14 14
+863 2 0
+27 1 1
+204 14 14
+163 4 4
+290 1 1
+59 1 1
+842 2 0
+2044 1 1
+90 1 0
+3434 3 0
+356 1 0
+873 1 0
+864 1 25
+630 7 12
+62 1 1
+88 1 1
+76 11 11
+1366 17 17
+156 4 4
+244 18 4
+505 0 1
+109 1 1
+230 1 1
+107 3 4
+150 1 1
+83 5 5
+70 1 1
+33 0 1
+142 1 1
+626 6 5
+274 10 10
+128 1 1
+35 1 1
+216 1 1
+44 1 1
+312 18 18
+1496 7 8
+451 1 0
+212 14 14
+629 1 1
+20 1 1
+350 1 1
+62 1 1
+617 10 10
+845 1 1
+58 1 1
+2189 1 1
+147 1 1
+475 1 1
+27 1 1
+278 1 1
+17 1 1
+994 1 1
+40 1 1
+219 5 5
+26 1 1
+900 1 1
+29 0 1
+26 1 1
+484 16 15
+61 9 9
+114 26 21
+801 1 1
+33 1 1
+465 32 32
+63 1 1
+37 1 1
+80 14 14
+211 1 1
+43 1 1
+156 1 1
+20 1 1
+685 1 1
+67 0 4
+711 1 1
+38 1 1
+402 7 7
+1045 1 1
+37 1 1
+4035 9 9
+247 0 4
+4146274 5734 17400
+330366 1 0
+2346742 55 0
+413177 0 3
+450 0 1
+9436 1 3
+7044 0 4
+2886 0 1
+635 0 1
+16567 0 1
+6918 0 1
+9285 0 1
+14909 0 8
+12879 0 2
+3330 0 2
+2673376 0 2
+2173174 7 7
+29817 2485 66108
+6473782 5 5
+39 1 1
+9574 2 0
+5879 1 1
+29 1 1
+6139 0 1
+2354 1 1
+28 1 1
+91 1 1
+23 0 1
+62 1 1
+142 15 16
+54 1 1
+22 3 3
+1479 4 4
+221 4 4
+132 0 1
+574 11 11
+23 0 1
+604 1 1
+44 1 1
+899 0 1
+70 10 12
+13561 1 1
+44 1 1
+4476 4 4
+799 25 26
+1466 18 18
+17896 0 4
+1668 0 1
+4250 1 1
+44 1 0
+4 1 0
+11 1 1
+4956 1 1
+18 0 1
+39 2 3
+4990 1 1
+47 13 13
+68 0 4
+9730 0 1
+355 1 0
+2186 1 1
+37 1 1
+6111 3 3
+100 4 4
+68 1 1
+43 1 1
+1126 7 5
+5520 8 8
+2316 1 1
+181 6 6
+50 1 1
+29 0 1
+83 1 1
+1073 150 154
+100 398 0
+141 1 1
+25272 1 0
+2132 4 0
+2522 1 1
+48 1 1
+1498528 1 0
+6044582 3000000 3000008
+1291149 16655 60038
+3837 0 3
+811 0 1
+2567 0 1
+7375465 1 0
+10 0 1
+42062 0 1
+19604621 0 1
+10692667 0 1
+110 1 0
+3577 3 0
+907 1 1
+18 1 1
+528 1 1
+50 1 1
+317 1 1
+64 251 535
+21 1 0
+140 1 0
+70 0 1
+77 10 9
+227 0 1
+142 5 5
+57 14 14
+43 1 1
+31034 99683 124100
+2301 2 0
+44 0 2
+568015 186612 87300
+355 5 5
+1916 3085 0
+924 4 0
+339 211 211
+963 14 15
+1157 12194 0
+242 23 23
+56 15 15
+405 20 20
+955 49 49
+1347 1 1
+2289 51 51
+555 253 253
+1723 77 77
+396 13 13
+112 3085 0
+3945 0 1
+209 23 23
+69 22 22
+81 20 20
+696 20 20
+58 69 69
+100 13 13
+326 137 137
+151 35 35
+1804 37 37
+1548 26 26
+324 23 23
+1932 17 17
+111 47 47
+128 16 16
+78 30 30
+1022 10 6
+78 0 1
+342 31 31
+86 23 23
+1580 255 255
+170 10 10
+398 23 23
+419 20 20
+955 55 55
+1139 11 11
+1925 276 0
+223 1 1
+56 1 1
+702 5 5
+17 3 3
+1030 1 1
+21 1 1
+363 1 1
+30 1 1
+785 16 16
+78 13 13
+1036 4 0
+482 68 68
+1069 10 10
+321 200 200
+434 43 43
+798 20 20
+56 25 25
+1007 5 5
+1198 24 24
+689 0 3
+743 32 32
+817 43 43
+574 11 11
+760 69 69
+1229 32 32
+272 29 29
+106 97 97
+1309 46 46
+850 4 4
+777 62 62
+86 36 36
+374 93 93
+2076 31 31
+195 56 56
+379 80 80
+64 11 11
+191 18 18
+1051 13 13
+52 119 113
+1347 1 1
+25 1 1
+3451 188 0
+3097 9 0
+2715 0 1
+11829 3 0
+6000 0 28
+10729 1 0
+3770769 0 1
+62 0 1
+22 0 1
+827 0 1
+1485 0 1
+242 1 0
+7142 0 1
+4029 3 3
+69 1 1
+15865 0 1
+83461 0 4
+5978 0 9
+2661 0 1
+1483 0 1
+15868 0 4
+17798 0 1
+2649 0 1
+3627 0 1
+4789 0 1
+9541 0 1
+6844 0 1
+3187 0 2
+411 0 14
+3056 0 4
+19776 0 3
+29085 1 0
+745 0 2
+11453 0 2
+16739 0 1
+14697 0 1
+8539 0 1
+25514443 0 1
+17680 1 0
+55359 1 0
+58 13 11
+5 1 0
+6 1 0
+5 1 0
+22 0 1
+4 1 3
+1515 0 1
+1111 0 1
+5736 6 6
+66213 0 1
+68 1 1
+24 7 6
+43 1 1
+33414 7 7
+22 1 1
+12288 22 22
+7002 1 0
+8588 1 1
+31 1 1
+15969 1 1
+32 1 1
+27034 1 1
+42 1 1
+3352 1 0
+15009 0 1
+20433 18 18
+32141 8 9
+116 41 41
+4920 0 1
+33364 0 1
+11160 1 0
+15 1 0
+28423 0 1
+43835 1 1
+24 2 4
+269244 4 4
+37 1 1
+17193 3 4
+53 11 12
+23 1 2
+7 1 1
+37978 9 9
+37743 1 1
+35 3 3
+26636 1 1
+17 1 1
+8728292 0 1
+16734777 71275 0
+657026 2 0
+2911 2 0
+1941 1 1
+35 1 1
+835 1 1
+116 1 1
+399 1 1
+101 0 1
+194 2 1
+450 0 1
+825 1 1
+73 1 1
+156 1 1
+58 1 1
+50 5 5
+153 11 11
+189 5 5
+233 1 1
+83 1 1
+642 1 0
+1380 1 1
+17 1 1
+315 1 1
+26 1 1
+789 901 0
+73 1 1
+45 1 1
+535 1 1
+34 1 1
+2007 7 7
+159 1 1
+26 1 1
+6362 13 13
+504325 25635 100008
+420771 232 0
+287688 104 0
+65 364 0
+183 55 0
+93 1 1
+46 1 1
+4002 1 1
+24 1 1
+190 0 147
+65 2 1
+8 0 1
+39 2 591
+306 50 0
+1938 1 0
+578 0 684
+291 1 0
+572289 108288 7108
+480202 0 1
+11866 6 6
+26917 1 0
+6097 15 15
+3074 1 0
+12292 1 0
+2209 1 0
+7358 1 0
+321393
+
+chain 2607822 8 146364022 + 12061935 12091854 chr8 146274826 + 12348580 12378713 990
+895 20 0
+1391 22 21
+53 88 0
+99 36 0
+9 0 346
+255 0 44
+496 1 0
+1013 0 4
+1698 1 0
+1054 37 37
+915 52 54
+2295 9 9
+123 1 0
+1295 162 162
+2903 50 50
+913 24 24
+2382 1 0
+299 85 85
+61 27 16
+1351 37 37
+974 4 4
+571 1 0
+530 11 0
+572 18 18
+76 4 4
+398 0 2
+54 31 31
+115 37 37
+125 364 364
+70 47 47
+56 8 8
+979 57 57
+248 50 50
+65 100 100
+82 1 0
+428 34 34
+51 6 0
+156 66 66
+257 132 132
+56 49 49
+91 19 19
+67 38 37
+142 6 6
+249 17 17
+123 104 104
+190 36 37
+355 5 1
+161 1 0
+89 48 48
+62 38 38
+136 67 67
+839
+
+chain 2498503 8 146364022 + 86726531 86754632 chr8 146274826 - 59364826 59419953 1092
+268 2 2
+114 6 0
+49 13 13
+1051 18 18
+117 8 3
+81 1 1
+64 4 4
+73 3 3
+379 1 1
+54 1 1
+183 13 13
+374 1 1
+43 1 1
+874 2 2
+22 1 1
+56 20 20
+712 1 1
+91 1 1
+374 1 1
+73 1 1
+88 21 21
+83 1 1
+27 1 1
+302 29 29
+1591 1 1
+27 4 0
+1250 1 1
+20 1 1
+2246 10 9115
+1002 49 49
+314 4 4
+116 32 32
+363 23 23
+1050 13 13
+119 0 8829
+1050 16 16
+1869 31 31
+119 0 9106
+593 13 13
+396 77 77
+1017 32 32
+888 39 39
+2895 1 1
+964 43 43
+1769 15 15
+292 35 35
+97 5 5
+313 13 13
+248 40 40
+435 10 11
+129 6 6
+712
+
+chain 1152177 8 146364022 + 142754466 142766515 chr8 146274826 + 142956164 142968213 2035
+12049
+
+chain 1081960 8 146364022 + 86772301 86823828 chr8 146274826 + 86857153 86905309 683
+56 15 15
+405 21 21
+1003 383 383
+837 0 1
+126 1 1
+531 1 0
+794 1 0
+73 32 32
+817 43 43
+214 432 432
+212 114 114
+373 28 28
+159 32 32
+832 44 44
+217 192 192
+330 927 923
+88 39 40
+1839 279 279
+283 13 13
+143 1716 1717
+49 3637 3637
+51 555 555
+97 1 1
+21 1 1
+133 1723 1723
+13 16 16
+48 8749 5664
+69 439 439
+62 43 43
+32 151 151
+35 1804 1804
+37 1548 1272
+26 2407 2407
+32 1719 1716
+31 1784 1784
+160 1995 1995
+55 3075 3075
+276 4870 4866
+68 1429 1429
+83 21 21
+67 434 434
+36
+
+chain 801068 8 146364022 + 145324300 145332588 chr8 146274826 + 145464193 145472508 5275
+3979 8 0
+2057 0 35
+2244
+
+chain 744541 8 146364022 + 86754632 86807992 chr8 146274826 + 86857851 86901670 688
+637 20 20
+440 88 88
+964 1 1
+2289 52 52
+554 1 1
+37 1 1
+1606 46 43
+288 6565 395
+203 3612 3608
+265 1500 1501
+278 1 1
+104 3213 3212
+43 214 214
+138 26 26
+268 212 212
+80 594 594
+32 832 832
+34 227 227
+16 27 27
+149 330 330
+33 21 21
+873 88 85
+39 1839 1839
+229 17 17
+33 9021 8745
+425 14725 11640
+30
+
+chain 657279 8 146364022 + 12141854 12149156 chr8 146274826 + 11932698 11940000 7963
+232 8 8
+466 34 34
+801 48 48
+815 68 68
+1203 29 29
+407 31 31
+467 26 26
+1146 18 18
+1503
+
+chain 521724 8 146364022 + 12149156 12156927 chr8 146274826 + 11940000 11947772 4417
+2168 0 1
+503 25 25
+153 202 202
+106 107 107
+851 39 39
+1679 1912 1912
+26
+
+chain 511532 8 146364022 + 142816515 142822092 chr8 146274826 + 142814667 142820000 26584
+2797 244 0
+2536
+
+chain 345755 8 146364022 + 142822092 142825705 chr8 146274826 + 142820000 142823612 174979
+3531 1 0
+81
+
+chain 305790 8 146364022 + 86765339 86795897 chr8 146274826 + 86865470 86901765 930
+477 0 9106
+123 31 31
+1705 14 14
+503 14 14
+15 1470 1466
+91 31 31
+52 35 35
+2 7890 7613
+26 560 560
+34 16750 13662
+405 127 127
+203
+
+chain 137107 8 146364022 + 85964683 85966170 chr8 146274826 + 86036733 86038220 940425
+1283 19 19
+185
+
+chain 118247 8 146364022 + 86759071 86769900 chr8 146274826 + 86874481 86903237 1649
+52 2533 2530
+13 16 16
+1046 0 8829
+123 13 13
+196 2878 11983
+29 3812 3808
+31 52 52
+35
+
+chain 109647 chr8 146364022 + 21624541 21625686 chr8_random 943810 + 516200 517342 1758
+687 1 0
+241 2 0
+214
+
+chain 97713 8 146364022 + 86793362 86840444 chr8 146274826 + 86862935 86885634 1255
+1752 44 44
+4 38618 14235
+46 1631 1631
+62 86 86
+36 374 374
+93 2302 2302
+56 379 379
+80 1400 1400
+119
+
+chain 85095 8 146364022 + 85924850 85927320 chr2 242951149 - 28701067 28703532 1485529
+52 143 142
+173 208 208
+107 181 181
+68 70 66
+129 101 101
+183 373 373
+87 163 163
+164 198 198
+70
+
+chain 67060 chr8 146364022 + 144032710 144033413 chr8_random 943810 + 583131 583834 1875893
+703
+
+chain 47407 8 146364022 + 85907218 85908847 chr10 135374737 - 19950497 19952126 2691979
+115 531 531
+182 240 240
+64 202 202
+122 22 22
+52 45 45
+54
+
+chain 45318 8 146364022 + 85909407 85911400 chr3 199501827 - 58732681 58734687 2832173
+138 151 157
+53 129 125
+171 674 685
+80 116 116
+82 347 347
+52
+
+chain 43260 8 146364022 + 12069066 12090712 chr8 146274826 - 138168279 138189929 1162
+37 915 915
+52 6789 6802
+48 3620 3620
+85 61 59
+27 1351 1348
+5 1 1
+30 3223 3218
+22 115 115
+37 465 465
+24 3764 3760
+90 837 842
+48
+
+chain 38958 8 146364022 + 12159413 12159829 chr8 146274826 + 11950258 11950674 3228
+416
+
+chain 38127 8 146364022 + 86726451 86753339 chr8 146274826 - 59376930 59524482 1121
+80 11856 20676
+48 435 435
+32 4503 13609
+31 1121 10227
+77 1017 94649
+32 888 888
+39 3860 3860
+15 1 1
+26 2078 2078
+33 678 678
+38
+
+chain 31437 8 146364022 + 85955665 85955994 chr3 199501827 - 6162711 6163040 4382021
+329
+
+chain 30755 8 146364022 + 85915208 85915710 chr8 146274826 - 4216734 4217241 4503764
+255 160 165
+87
+
+chain 27896 8 146364022 + 940417 941596 chr8 146274826 + 930633 930948 5586021
+100 54 0
+108 810 0
+107
+
+chain 26413 8 146364022 + 85978864 85981144 chr9 140273252 - 40203469 40205589 6324943
+79 1134 635
+70 83 416
+56 207 205
+56 22 22
+63 455 463
+55
+
+chain 25390 8 146364022 + 85975200 85975766 chr6 170899992 - 89617888 89618457 6830715
+67 141 143
+50 38 39
+54 78 78
+138
+
+chain 20285 8 146364022 + 85975766 85977415 chr3 199501827 - 82189783 82191451 9116338
+8 700 763
+50 465 465
+54 309 265
+63
+
+chain 20226 8 146364022 + 85979170 85979799 chr3 199501827 - 161413320 161413963 10270718
+61 394 408
+174
+
+chain 20141 8 146364022 + 12151827 12152420 chr8 146274826 + 11902715 11903309 638255
+25 153 154
+202 106 106
+107
+
+chain 19400 8 146364022 + 85925267 85925628 chr10 135374737 + 135080720 135081080 3597149
+102 2 1
+54 131 131
+72
+
+chain 18915 8 146364022 + 942460 942893 chr8 146274826 + 930516 930733 3835109
+63 162 0
+46 108 54
+54
+
+chain 18062 8 146364022 + 942088 942460 chr8 146274826 + 930684 930948 5250846
+157 108 0
+107
+
+chain 17886 8 146364022 + 943174 943431 chr8 146274826 + 930690 930893 4105167
+149 55 1
+53
+
+chain 15443 8 146364022 + 941596 942029 chr8 146274826 + 930516 930841 4827909
+64 207 153
+65 54 0
+43
+
+chain 14855 8 146364022 + 85924497 85927134 chrX 154913754 + 50874366 50877002 1910511
+90 57 57
+50 108 108
+48 52 52
+79 801 801
+50 953 952
+50 236 236
+63
+
+chain 12854 8 146364022 + 144743895 144744094 chr8 146274826 + 144814885 144815084 3961669
+199
+
+chain 12042 8 146364022 + 85907589 85907864 chr4 191273063 + 22500316 22500591 2841396
+81 177 177
+17
+
+chain 11713 8 146364022 + 36265496 36265620 chr7 158821424 - 150143040 150143164 19315609
+124
+
+chain 10744 8 146364022 + 85909592 85910073 chr4 191273063 - 317022 317498 3271263
+71 86 86
+68 232 227
+24
+
+chain 10295 8 146364022 + 85917935 85918395 chr16 88827254 - 19324120 19324578 22152835
+60 331 329
+69
+
+chain 9964 8 146364022 + 85927135 85927250 chr3 199501827 - 159900532 159900647 3087651
+115
+
+chain 9833 8 146364022 + 85908046 85908504 chr8 146274826 - 114124165 114124623 2795681
+56 59 59
+58 162 162
+123
+
+chain 9709 8 146364022 + 943330 943485 chr8 146274826 + 930684 930839 15332741
+48 53 53
+54
+
+chain 9657 8 146364022 + 86004292 86004501 chrX 154913754 + 27575363 27575573 23616431
+52 93 94
+64
+
+chain 9406 8 146364022 + 85945093 85945452 chr12 132349534 + 8944725 8945099 24220725
+61 243 258
+55
+
+chain 9151 8 146364022 + 85910121 85910218 chr10 135374737 - 38564811 38564908 24713323
+97
+
+chain 8406 8 146364022 + 85924386 85924476 chr5 180857866 + 127114677 127114767 25803856
+90
+
+chain 7367 8 146364022 + 85911400 85911623 chrX 154913754 - 44623158 44623382 4824008
+72 91 92
+60
+
+chain 7214 8 146364022 + 85983029 85983106 chr3 199501827 + 182981094 182981171 27755476
+77
+
+chain 7178 8 146364022 + 85926461 85926638 chr7 158821424 + 131250991 131251168 8959140
+97 79 79
+1
+
+chain 6913 8 146364022 + 85946010 85946083 chr5 180857866 - 76444763 76444836 28360557
+73
+
+chain 6866 8 146364022 + 85981016 85981089 chr3 199501827 - 137848275 137848348 18929141
+73
+
+chain 6722 8 146364022 + 85915749 85915820 chr6 170899992 - 41858720 41858791 28750065
+71
+
+chain 6523 8 146364022 + 85874468 85874538 chr6 170899992 + 80165568 80165638 29222062
+70
+
+chain 6284 8 146364022 + 48138290 48138355 chr12 132349534 - 99530740 99530805 29826800
+65
+
+chain 6255 8 146364022 + 86830665 86832268 chr8 146274826 + 86851473 86853076 5870
+41 1533 1533
+29
+
+chain 6230 8 146364022 + 143494784 143494849 chr8 146274826 + 143492621 143492686 29969115
+65
+
+chain 5949 8 146364022 + 85946624 85946687 chr7 158821424 - 150469376 150469439 30705065
+63
+
+chain 5930 8 146364022 + 86000088 86000150 chr4 191273063 - 114595117 114595179 30759641
+62
+
+chain 5722 8 146364022 + 85909210 85909271 chr4 191273063 - 32715229 32715290 31306692
+61
+
+chain 5681 8 146364022 + 85907187 85907519 chr7 158821424 - 141596962 141597294 3108677
+31 137 137
+3 85 85
+76
+
+chain 5594 8 146364022 + 85966181 85966240 chr2 242951149 + 129692100 129692159 31643052
+59
+
+chain 5348 8 146364022 + 85946168 85946224 chrX 154913754 + 22697258 22697314 32405249
+56
+
+chain 5330 8 146364022 + 85945000 85945056 chrX 154913754 - 56717679 56717735 32442268
+56
+
+chain 5292 8 146364022 + 85926370 85926785 chr12 132349534 + 42776733 42777148 2271290
+75 280 280
+14 27 27
+19
+
+chain 5194 chr8 146364022 + 85992019 85992074 chr17_random 2617613 - 1345968 1346023 32873362
+55
+
+chain 5161 8 146364022 + 941932 941986 chr8 146274826 + 930312 930366 21107216
+54
+
+chain 5012 8 146364022 + 85946286 85946339 chr1 247249719 - 150482359 150482412 33477745
+53
+
+chain 4929 8 146364022 + 941384 941435 chr8 146274826 + 930304 930355 33748771
+51
+
+chain 4927 8 146364022 + 85874401 85874458 chr12 132349534 + 21319375 21319432 33750711
+57
+
+chain 4920 8 146364022 + 85945525 85945576 chr10 135374737 + 87468307 87468358 33788347
+51
+
+chain 4810 8 146364022 + 942523 942621 chr8 146274826 + 930741 930839 7547023
+98
+
+chain 4803 8 146364022 + 85970009 85970060 chr11 134452384 + 10157776 10157827 34198727
+51
+
+chain 4793 8 146364022 + 85975065 85975115 chr21 46944323 - 30257577 30257627 34245350
+50
+
+chain 4738 8 146364022 + 942303 942352 chr8 146274826 + 930521 930570 34412340
+49
+
+chain 4461 8 146364022 + 85910862 85910919 chrX 154913754 + 151305652 151305709 4935543
+57
+
+chain 4271 8 146364022 + 86793237 86793293 chr8 146274826 + 86902190 86902246 1452514
+56
+
+chain 4178 8 146364022 + 85915489 85915539 chr3 199501827 + 132299011 132299061 5319224
+50
+
+chain 4079 8 146364022 + 85926268 85926343 chr2 242951149 - 211437807 211437882 2547607
+75
+
+chain 3965 8 146364022 + 85910617 85910659 chr5 180857866 + 105218926 105218968 18292131
+42
+
+chain 3826 8 146364022 + 85911256 85911310 chr7 158821424 + 49570162 49570216 23840400
+54
+
+chain 3809 8 146364022 + 86829249 86829292 chr8 146274826 + 86874439 86874482 7328
+43
+
+chain 3796 8 146364022 + 85928889 85929141 chrX 154913754 + 121492736 121492988 2565989
+99 40 40
+113
+
+chain 3755 8 146364022 + 85925629 85925714 chr5 180857866 + 141403818 141403903 2005326
+54 23 23
+8
+
+chain 3680 8 146364022 + 36265255 36265294 chr21 46944323 - 8931342 8931381 34138292
+39
+
+chain 3466 8 146364022 + 85917822 85917882 chr11 134452384 - 107659023 107659083 22827264
+60
+
+chain 3460 8 146364022 + 85925991 85926082 chr19 63811651 + 46688677 46688768 2544872
+91
+
+chain 3412 8 146364022 + 85981195 85981250 chr12 132349534 - 23016451 23016506 20760996
+55
+
+chain 3378 8 146364022 + 144744318 144744353 chr8 146274826 + 144814727 144814762 26884487
+35
+
+chain 3372 8 146364022 + 12064503 12064539 chr8 146274826 + 12351001 12351037 28926895
+36
+
+chain 3336 8 146364022 + 85910527 85910617 chr6 170899992 + 121091189 121091279 5885029
+90
+
+chain 3306 8 146364022 + 85975140 85975200 chr5 180857866 - 14200316 14200376 14215921
+60
+
+chain 3123 8 146364022 + 144455804 144455869 chr8 146274826 + 144526757 144526822 16634618
+65
+
+chain 3122 8 146364022 + 85910073 85910106 chr10 135374737 + 91515201 91515234 27999029
+33
+
+chain 2973 8 146364022 + 85975297 85975339 chr11 134452384 + 70894433 70894475 12515399
+42
+
+chain 2846 8 146364022 + 85980398 85980477 chr6 170899992 + 12780268 12780347 14041671
+79
+
+chain 2664 8 146364022 + 85980653 85980843 chr13 114142980 + 79661332 79661527 13462115
+54 70 75
+66
+
+chain 2542 8 146364022 + 86811232 86811259 chr8 146274826 + 86750599 86750626 581042
+27
+
+chain 2408 8 146364022 + 86780113 86780140 chr8 146274826 + 86901259 86901286 3284
+27
+
+chain 2361 chr8 146364022 + 86795114 86795665 chr8_random 943810 - 353250 353801 88303
+34 419 419
+98
+
+chain 2314 8 146364022 + 85909329 85909403 chr5 180857866 - 126448590 126448664 8133335
+74
+
+chain 2312 8 146364022 + 85964546 85964619 chr5 180857866 - 22206487 22206560 13216855
+73
+
+chain 2306 8 146364022 + 85909062 85909878 chr5 180857866 - 76491094 76491924 7171448
+57 726 740
+33
+
+chain 2277 8 146364022 + 85945069 85945093 chr2 242951149 - 76417863 76417887 30610067
+24
+
+chain 2276 8 146364022 + 85915156 85915196 chr9 140273252 + 96271703 96271743 9134049
+40
+
+chain 2255 8 146364022 + 12171549 12171574 chr8 146274826 + 11962388 11962413 4339
+25
+
+chain 2213 8 146364022 + 85976678 85976734 chr10 135374737 + 107478570 107478626 23840391
+56
+
+chain 2193 8 146364022 + 85909817 85909844 chr1 247249719 - 204777828 204777855 6141044
+27
+
+chain 2188 8 146364022 + 85915463 85915489 chr4 191273063 + 117566433 117566459 5547542
+26
+
+chain 2086 8 146364022 + 85907670 85907692 chr9 140273252 + 84577624 84577646 25068333
+22
+
+chain 2042 8 146364022 + 85906786 85906876 chr1 247249719 - 187757137 187757227 3120497
+90
+
+chain 2008 8 146364022 + 85975339 85978010 chr12 132349534 - 60955403 60957663 7657094
+69 2448 2037
+58 20 20
+76
+
+chain 1976 8 146364022 + 85910386 85910476 chr11 134452384 + 108691426 108691516 10944711
+90
+
+chain 1915 8 146364022 + 85915895 85915946 chr2 242951149 - 57258601 57258652 18793758
+51
+
+chain 1706 8 146364022 + 85926558 85926608 chr20 62435964 + 52983902 52983952 9284939
+50
+
+chain 1666 8 146364022 + 85915539 85915568 chr3 199501827 - 58686941 58686970 11643280
+29
+
+chain 1625 8 146364022 + 85977632 85977856 chr3 199501827 - 45071352 45071581 10048168
+62 161 166
+1
+
+chain 1603 8 146364022 + 36265620 36265653 chr4 191273063 + 189716401 189716434 1596951
+33
+
+chain 1586 chr8 146364022 + 86793293 86793362 chr8_random 943810 + 582217 582286 150907
+69
+
+chain 1585 8 146364022 + 85907040 85907092 chr7 158821424 + 38674874 38674926 25744726
+52
+
+chain 1584 8 146364022 + 85964393 85964443 chr1 247249719 - 57954630 57954680 20174423
+50
+
+chain 1470 8 146364022 + 85911121 85911160 chr15 100338915 + 92120615 92120654 21684489
+39
+
+chain 1463 8 146364022 + 942731 942785 chr8 146274826 + 930679 930733 5019737
+54
+
+chain 1440 8 146364022 + 85911043 85911098 chr1 247249719 - 141715465 141715520 4313974
+55
+
+chain 1426 8 146364022 + 85978253 85978320 chr2 242951149 - 208172805 208172872 22624190
+67
+
+chain 1403 8 146364022 + 85928837 85929028 chr18 76117153 + 39707440 39707631 2816562
+52 99 99
+40
+
+chain 1344 8 146364022 + 85907124 85907170 chr12 132349534 + 45103963 45104009 16171151
+46
+
+chain 1332 8 146364022 + 85927450 85927503 chr1 247249719 - 29234742 29234795 3133635
+53
+
+chain 1287 8 146364022 + 85907361 85907411 chr1 247249719 - 78547145 78547195 4245040
+50
+
+chain 1276 8 146364022 + 85927323 85927376 chr4 191273063 - 93337200 93337253 2720957
+53
+
+chain 1269 8 146364022 + 85908257 85908286 chr9 140273252 - 124490379 124490408 3695355
+29
+
+chain 1238 8 146364022 + 85978601 85978678 chr9 140273252 - 23294193 23294270 19053025
+77
+
+chain 1193 8 146364022 + 144455743 144455792 chr8 146274826 + 144526504 144526553 26679478
+49
+
+chain 1175 8 146364022 + 12087452 12087488 chr11 134452384 - 63301652 63301688 1994288
+36
+
+chain 1137 8 146364022 + 85909119 85909164 chr2 242951149 + 35848313 35848358 13461114
+45
+
+chain 1067 chr8 146364022 + 86832385 86832437 chr8_random 943810 - 358237 358289 86749
+52
+
+chain 1048 8 146364022 + 86824709 86824734 chr8 146274826 + 86857705 86857730 2636
+25
+
+chain 1045 8 146364022 + 85911001 85911043 chr15 100338915 - 40210675 40210717 4055996
+42
+
+chain 1028 8 146364022 + 85910323 85910373 chr4 191273063 + 26203887 26203937 5050480
+50
+
+chain 1020 8 146364022 + 85924694 85924736 chr3 199501827 + 1701599 1701641 4262142
+42
+
+chain 1005 8 146364022 + 85977261 85977320 chr10 135374737 + 45388722 45388781 14596230
+59
+
+chain 998 8 146364022 + 85908847 85908872 chr4 191273063 + 183519567 183519592 8543079
+25
+
+chain 985 8 146364022 + 85918576 85918627 chr3 199501827 - 21820872 21820923 24828426
+51
+
+chain 981 8 146364022 + 144744094 144744133 chr8 146274826 + 144814821 144814860 14840226
+39
+
+chain 922 8 146364022 + 85918981 85919046 chrX 154913754 - 100261670 100261735 22334691
+65
+
+chain 912 8 146364022 + 85964449 85964513 chr6 170899992 + 131272389 131272453 24950513
+64
+
+chain 888 8 146364022 + 85915710 85915739 chr9 140273252 + 12069456 12069485 13568361
+29
+
+chain 867 8 146364022 + 85976220 85976271 chrX 154913754 - 36573362 36573413 23586363
+51
+
+chain 857 8 146364022 + 86832445 86832471 chr8 146274826 + 86747431 86747457 7742
+26
+
+chain 802 8 146364022 + 85978516 85978572 chr3 199501827 + 80520031 80520087 22639668
+56
+
+chain 801 8 146364022 + 85911160 85911249 chr16 88827254 + 31611661 31611750 16482423
+89
+
+chain 785 8 146364022 + 85917259 85917324 chr5 180857866 - 163179499 163179564 25049793
+65
+
+chain 721 8 146364022 + 85926739 85926765 chr18 76117153 + 15364211 15364237 2792298
+26
+
+chain 647 8 146364022 + 85918645 85918703 chr11 134452384 - 90657004 90657062 25582649
+58
+
+chain 612 8 146364022 + 941818 941867 chr8 146274826 + 930360 930409 12502809
+49
+
+chain 596 8 146364022 + 85976593 85979111 chrX 154913754 - 42670843 42673368 13030869
+53 2388 2395
+77
+
+chain 568 8 146364022 + 85966335 85966385 chrX 154913754 + 36275879 36275929 27751459
+50
+
+chain 474 8 146364022 + 85917714 85917772 chr1 247249719 + 62707004 62707062 26279221
+58
+
+chain 396 8 146364022 + 85977502 85977572 chrX 154913754 - 138803117 138803187 17501406
+70
+
+chain 369 8 146364022 + 85976646 85976678 chr7 158821424 + 51906674 51906706 15299893
+32
+
+chain 360 8 146364022 + 85980297 85980349 chr12 132349534 - 124024481 124024533 24774043
+52
+
+chain 337 8 146364022 + 85981293 85981372 chr1 247249719 - 152445011 152445090 12777550
+79
+
+chain 328 8 146364022 + 85976447 85976474 chr2 242951149 - 99982783 99982810 22051776
+27
+
+chain 310 8 146364022 + 85976849 85976905 chr3 199501827 - 69459686 69459742 25770085
+56
+
+chain 286 8 146364022 + 85979114 85979170 chr7 158821424 - 11181572 11181628 19756881
+56
+
+chain 232 8 146364022 + 85978010 85978057 chr1 247249719 + 108819891 108819938 19586297
+47
+
+chain 3680035 chr8_gl000196_random 38914 + 0 38914 chr8_random 943810 + 643258 682172 798
+38914
+
+chain 3554032 chr8_gl000197_random 37175 + 0 37175 chr8_random 943810 + 493047 530222 826
+37175
+
+chain 11336430536 9 141213431 + 10000 141153431 chr9 140273252 + 0 140273252 13
+189075 17 17
+39464594 50000 50000
+261110 50000 50000
+208233 50000 50000
+142805 50000 50000
+464507 50000 50000
+152873 50000 50000
+172579 50000 50000
+799200 4 0
+398958 50000 50000
+549743 100000 50000
+632871 50000 50000
+680077 50000 50000
+181647 50000 50000
+291910 100000 50000
+465318 50000 50000
+350909 50000 50000
+194609 100000 50000
+370337 176 0
+128581 100047 50047
+157499 18150000 18100000
+450681 50000 50000
+223855 50000 50000
+162441 50000 50000
+159539 50000 50000
+199148 50000 50000
+194491 100000 50000
+158462 150000 50000
+471702 150000 50000
+376183 150000 50000
+174765 150000 50000
+289439 50000 50000
+682157 50000 50000
+158187 100000 50000
+187806 50000 50000
+178933 100000 50000
+21507948 100000 50000
+85380 150000 50000
+834971 0 1
+39559293 150000 100000
+3818133 50000 200000
+2075804 50000 30000
+1936434
+
+chain 1179 9 141213431 + 46931376 46931552 chr9 140273252 - 98415895 98416071 50
+176
+
+chain 443 9 141213431 + 47160133 47160180 chr9 140273252 - 72994158 72994205 112
+47
+
+chain 8504653 chr9_gl000198_random 90085 + 0 90085 chr9_random 1146434 + 526031 616116 387
+90085
+
+chain 10524551 chr9_gl000199_random 169874 + 0 146316 chr9_random 1146434 + 903151 1075994 305
+35956 981 11726
+149 118 118
+212 21 21
+101 50 50
+98 0 8841
+196 126 126
+211 19 19
+115 44 44
+76 72 72
+100 9 9
+92 107 107
+86 1193 169
+50 168 18105
+488 0 1
+10599 1 1
+42 1 0
+8869 101 101
+10239 51 51
+179 500 502
+1131 0 1
+12346 0 18932
+463 15 15
+739 1 1
+64 1 1
+2323 0 1
+755 1 1
+188 1 1
+245 0 2
+10316 4 5
+18 1 1
+8496 15 15
+1065 3 3
+49 1 1
+67 1 1
+24 1 1
+150 15 15
+2700 5110 0
+46 11735 0
+376 5 5
+2019 342 0
+1220 1192 0
+221 37 37
+60 21 21
+334 6678 50
+235 1381 27
+52 2571 21
+62
+
+chain 3014585 chr9_gl000199_random 169874 + 136786 169869 chr9_random 1146434 + 939452 971857 944
+79 683 6
+4467 235 235
+1381 52 52
+786 1 1
+38 1 0
+29 1 1
+1715 62 62
+1332 14 14
+6821 1 1
+55 1 1
+15329
+
+chain 306268 chr9_gl000199_random 169874 + 114056 136743 chr9_random 1146434 + 1030711 1052467 1210
+785 60 60
+2828 46 46
+527 6 352
+63 378 378
+514 181 181
+824 72 72
+329 1 1
+35 1 1
+68 1 1
+37 1 1
+3228 135 132
+81 325 325
+52 391 391
+60 10252 2341
+243 179 691
+73 42 42
+155 0 1190
+24 0 1871
+442 0 3064
+2 95 95
+151
+
+chain 178734 chr9_gl000199_random 169874 + 38939 136592 chr9_random 1146434 + 940083 990000 1006
+27 31954 13752
+34 77 77
+166 43 43
+110 68 68
+2 41253 31459
+196 349 7
+48 5105 0
+83 14 14
+62 11 11
+208 514 2
+181 824 144
+72 3917 172
+325 52 52
+391 9096 1608
+467 1909 41
+95
+
+chain 108146 chr9_gl000199_random 169874 + 35956 37588 chr9_random 1146434 + 1073965 1075597 311529
+981 149 149
+118 334 334
+50
+
+chain 94079 chr9_gl000199_random 169874 + 125187 127738 chr9_random 1146434 + 934627 937178 173754
+2551
+
+chain 56396 chr9_gl000199_random 169874 + 38488 39821 chr9_random 1146434 + 1072584 1073917 324037
+57 225 225
+83 113 113
+855
+
+chain 37331 chr9_gl000199_random 169874 + 127738 129141 chr9_random 1146434 + 1073395 1074798 197032
+1403
+
+chain 15154 chr9_gl000199_random 169874 + 133472 133633 chr9_random 1146434 - 103942 104103 2035052
+161
+
+chain 14222 chr9_gl000199_random 169874 + 39821 40265 chr9_random 1146434 + 982531 990446 140426
+290 71 7542
+83
+
+chain 13688 chr9_gl000199_random 169874 + 112619 134922 chr9_random 1146434 + 997840 1005340 1760
+54 480 138
+65 48 48
+86 0 1
+62 27 27
+193 20460 5998
+27 467 467
+2 15 15
+59 221 221
+37
+
+chain 12407 chr9_gl000199_random 169874 + 60350 137506 chr9_random 1146434 + 944493 957004 1913
+35 10569 695
+47 196 196
+40 113 113
+68 62256 9695
+367 1799 779
+34 1232 42
+400
+
+chain 5910 chr9_gl000199_random 169874 + 112953 113153 chr9_random 1146434 + 1036251 1036451 100700
+200
+
+chain 4997 chr9_gl000199_random 169874 + 124080 124135 chr9_random 1146434 + 959057 959112 19926960
+55
+
+chain 4162 chr9_gl000199_random 169874 + 113634 113846 chr9_random 1146434 + 995454 995665 201802
+27 40 39
+145
+
+chain 3441 chr9_gl000199_random 169874 + 37915 38008 chr9_random 1146434 + 950621 950714 48386
+93
+
+chain 3360 chr9_gl000199_random 169874 + 129226 129424 chr9_random 1146434 + 996412 996610 9342
+198
+
+chain 3255 chr9_gl000199_random 169874 + 70690 70741 chr9_random 1146434 + 1012726 1012777 23586
+51
+
+chain 3031 chr9_gl000199_random 169874 + 112869 137060 chr9_random 1146434 + 964682 969139 3960
+84 23929 4195
+178
+
+chain 2784 chr9_gl000199_random 169874 + 60406 60450 chr9_random 1146434 + 1000736 1000780 8481
+44
+
+chain 2406 chr9_gl000199_random 169874 + 38361 40328 chr9_random 1146434 + 940183 941126 6867
+36 1868 844
+63
+
+chain 2091 chr9_gl000199_random 169874 + 135580 135759 chr9_random 1146434 + 1043989 1044168 130849
+179
+
+chain 1790 chr9_gl000199_random 169874 + 113899 113969 chr9 140273252 - 71272426 71272496 22178754
+70
+
+chain 1047 chr9_gl000199_random 169874 + 114872 114901 chr9_random 1146434 + 1035274 1035303 118930
+29
+
+chain 1014 chr9_gl000199_random 169874 + 129141 129510 chr9_random 1146434 + 949663 949862 115384
+82 201 31
+86
+
+chain 827 chr9_gl000199_random 169874 + 125159 125187 chr9 140273252 - 71272290 71272318 10194134
+28
+
+chain 754 chr9_gl000199_random 169874 + 136743 136786 chr9_random 1146434 - 170925 170968 528799
+43
+
+chain 683 chr9_gl000199_random 169874 + 134041 134094 chr9_random 1146434 + 1025518 1025571 412663
+53
+
+chain 494 chr9_gl000199_random 169874 + 71001 71031 chr9_random 1146434 + 983095 983125 1059560
+30
+
+chain 444 chr9_gl000199_random 169874 + 133651 133674 chr9_random 1146434 + 1066888 1066911 84972
+23
+
+chain 309 chr9_gl000199_random 169874 + 137506 137547 chr9_random 1146434 + 967717 967758 659942
+41
+
+chain 254 chr9_gl000199_random 169874 + 125119 125159 chr9_random 1146434 + 1071966 1072006 1499804
+40
+
+chain 241 chr9_gl000199_random 169874 + 137060 137086 chr9_random 1146434 + 965055 965081 39489
+26
+
+chain 190 chr9_gl000199_random 169874 + 124136 124176 chr9_random 1146434 + 947206 947246 772655
+40
+
+chain 17692629 chr9_gl000200_random 187035 + 0 187035 chr9_random 1146434 + 666116 853151 157
+187035
+
+chain 3482851 chr9_gl000201_random 36148 + 0 36148 chr9_random 1146434 + 0 36148 835
+36148
+
+chain 1574309 MT 16571 + 0 16571 chrM 16571 + 0 16571 1542
+16571
+
+chain 15737781 chrUn_gl000211 166566 + 0 166566 chr22_random 257318 + 90752 257318 187
+166566
+
+chain 17750502 chrUn_gl000212 186858 + 0 186858 chr13_random 186858 + 0 186858 154
+186858
+
+chain 15269201 chrUn_gl000213 164239 + 0 164239 chr21 46944323 - 32900547 33064909 192
+4659 1 0
+8525 1 0
+592 12 11
+2258 2 0
+942 18 18
+7633 0 33
+6726 1 1
+49 4 4
+119 1 1
+127 6 0
+114 1 1
+1963 1 1
+856 0 1
+2836 1 0
+20 0 1
+262 6 6
+128 1 1
+22 1 1
+8105 14 0
+16 4 0
+1875 0 1
+8447 4 0
+157 10 10
+2207 0 1
+2729 0 2
+9463 1 0
+239 1 0
+17 2 0
+1990 3 0
+7559 3 2
+1342 1 1
+73 1 1
+1095 9 9
+57 1 1
+80 1 1
+290 16 16
+79 9 9
+151 4 4
+728 4 0
+580 4 0
+160 8 8
+184 1 1
+21 1 1
+3074 12 10
+471 6 6
+698 11 11
+338 0 3
+205 0 28
+1909 0 10
+508 1 1
+31 1 1
+847 1 2
+271 0 4
+337 1 1
+31 3 0
+355 1 1
+61 1 1
+237 1 1
+60 24 0
+307 0 4
+941 1 1
+37 5 0
+338 31 24
+563 0 644
+637 12 12
+369 1 1
+26 1 1
+136 630 0
+374 1 1
+31 1 1
+375 1 1
+48 1 1
+2210 1 1
+35 0 1
+1039 19 1
+53 1 1
+270 8 6
+337 1 1
+40 1 1
+2174 6 6
+841 1 1
+29 1 1
+1975 0 10
+37 1 1
+703 0 60
+223 15 15
+1844 0 4
+394 3 0
+63 1 1
+34 1 1
+121 1 1
+25 4 10
+12 12 0
+2694 8 8
+100 2 0
+2952 1 1
+27 1 1
+1508 0 4
+2169 16 16
+48 1 0
+894 9 9
+310 0 1
+2288 0 2
+4522 0 4
+32 1 1
+3231 0 6
+2045 1 1
+44 1 1
+955 9 9
+345 6 6
+129 1 1
+19 1 1
+167 1 0
+333 2 0
+716 22 22
+1384 1 0
+189 1 1
+23 0 28
+1452 1 1
+28 1 1
+1661 1 4
+496 18 17
+141 1 1
+44 1 1
+1971 1 6
+103 1 1
+47 1 1
+662 6 0
+318 0 5
+935 1 1
+47 1 1
+220 1 1
+36 1 1
+815 1 0
+49 1 0
+224 3 4
+86 1 1
+47 1 1
+683 2 2
+42 1 1
+1493 0 1
+373 0 1
+454 0 2
+179 0 12
+639 0 5
+616 66 81
+613 0 1
+198 8 11
+1412 4 0
+604 4 0
+1065 5 0
+3599 1 1
+44 1 1
+311 4 0
+302 1 0
+1762 31 31
+555
+
+chain 19447 chrUn_gl000213 164239 + 98731 98946 chr21 46944323 - 32999281 32999496 6410578
+102 6 6
+107
+
+chain 5115 chrUn_gl000213 164239 + 98535 98731 chr15 100338915 + 19297082 19297917 3190124
+68 49 688
+79
+
+chain 918427 chrUn_gl000214 137718 + 80069 90748 chr1 247249719 - 105489797 105500468 3815
+119 1 1
+25 1 1
+201 5 5
+65 5 5
+139 1 1
+69 1 1
+150 1 1
+67 4 4
+380 6 0
+73 10 10
+167 10 10
+63 1 1
+23 1 1
+369 4 4
+43 1 1
+235 1 1
+83 6 6
+99 1 1
+91 1 1
+116 14 14
+488 3 3
+47 1 0
+11 1 1
+216 1 1
+23 1 1
+84 1 1
+71 1 1
+549 1 1
+22 1 1
+146 1 1
+102 1 1
+104 1 1
+80 1 1
+59 1 1
+19 1 1
+402 1 1
+39 1 1
+284 1 1
+33 1 1
+161 4 4
+34 1 1
+125 1 1
+20 1 1
+472 1 1
+19 1 1
+228 23 23
+425 1 1
+99 1 1
+266 1 1
+42 1 1
+54 1 1
+62 1 1
+228 4 2
+85 6 6
+68 1 1
+242 1 1
+167 1 1
+33 1 1
+133 24 24
+773 7 7
+379 0 1
+218 62 62
+81 1 1
+37 1 1
+364 1 1
+29 1 1
+234
+
+chain 143213 chrUn_gl000214 137718 + 129234 137707 chr4 191273063 - 142244722 142253930 901087
+227 142 142
+52 32 32
+60 159 159
+56 5 5
+135 69 69
+183 83 83
+78 152 152
+70 161 161
+102 13 13
+186 9 9
+127 123 123
+78 241 241
+116 4845 5724
+91 242 98
+110 65 65
+64 13 13
+72 181 181
+131
+
+chain 112581 chrUn_gl000214 137718 + 116800 119267 chr4 191273063 + 48987510 48989977 1137439
+144 225 225
+135 141 141
+87 10 10
+130 173 173
+90 147 147
+57 103 103
+70 22 22
+84 50 50
+113 26 26
+103 37 37
+69 102 102
+127 4 4
+58 73 73
+87
+
+chain 35731 chrUn_gl000214 137718 + 49713 50123 chr21_random 1679693 + 637667 638077 3744988
+55 5 5
+34 1 1
+315
+
+chain 33173 chrUn_gl000214 137718 + 125487 134177 chr1 247249719 - 105123947 105126634 1162767
+65 110 110
+58 32 32
+395 7 7
+90 6069 74
+68 8 0
+64 36 36
+114 56 56
+54 63 63
+58 137 137
+182 277 277
+54 21 21
+122 248 248
+52 190 190
+60
+
+chain 26395 chrUn_gl000214 137718 + 40302 40606 chr1 247249719 - 18749005 18749307 6333362
+57 1 0
+75 1 0
+112 1 1
+57
+
+chain 25884 chrUn_gl000214 137718 + 126321 126850 chr21_random 1679693 + 746615 747120 6569895
+87 97 73
+114 5 5
+50 118 118
+58
+
+chain 25524 chrUn_gl000214 137718 + 41463 41766 chr9 140273252 - 40046622 40046925 6760130
+54 7 7
+122 4 4
+116
+
+chain 25177 chrUn_gl000214 137718 + 122978 125190 chr21_random 1679693 - 928041 930254 1258444
+118 228 229
+72 288 288
+139 44 44
+185 600 600
+136 37 37
+126 58 58
+181
+
+chain 23478 chrUn_gl000214 137718 + 136191 136535 chr4 191273063 + 48976406 48976750 8004925
+183 83 83
+78
+
+chain 20443 chrUn_gl000214 137718 + 41766 42878 chr3 199501827 + 629423 630533 8757399
+9 908 906
+118 25 25
+52
+
+chain 20379 chrUn_gl000214 137718 + 135162 135774 chr21_random 1679693 - 927923 928535 1491304
+50 44 44
+225 152 152
+141
+
+chain 18931 chrUn_gl000214 137718 + 44528 44730 chr10 135374737 - 38544783 38544985 11331455
+202
+
+chain 18826 chrUn_gl000214 137718 + 43343 43562 chr2 242951149 - 53551644 53551863 11416331
+110 1 1
+31 1 1
+76
+
+chain 18670 chrUn_gl000214 137718 + 90865 91063 chr1 247249719 - 105065042 105065240 11545618
+198
+
+chain 17773 chrUn_gl000214 137718 + 131919 132224 chr1 247249719 - 105124387 105124692 2973977
+225 10 10
+70
+
+chain 16259 chrUn_gl000214 137718 + 112825 112997 chr2 242951149 + 132826168 132826340 13778307
+172
+
+chain 16179 chrUn_gl000214 137718 + 117367 119564 chr1 247249719 + 142120582 142122781 1230197
+57 994 995
+43 121 121
+25 103 103
+37 69 69
+76 567 568
+105
+
+chain 14745 chrUn_gl000214 137718 + 40137 40293 chr18 76117153 + 36159000 36159156 15342897
+156
+
+chain 14511 chrUn_gl000214 137718 + 35480 35726 chr21_random 1679693 + 599809 599984 15605110
+107 80 9
+59
+
+chain 13694 chrUn_gl000214 137718 + 21320 21487 chrX 154913754 - 125740203 125740370 16565517
+81 11 11
+75
+
+chain 13486 chrUn_gl000214 137718 + 6106 6250 chr5 180857866 + 84443323 84443467 16839883
+144
+
+chain 13485 chrUn_gl000214 137718 + 18381 18548 chrX 154913754 + 88818181 88818344 16841154
+59 4 0
+49 4 4
+51
+
+chain 12687 chrUn_gl000214 137718 + 41058 41208 chr4 191273063 - 138230980 138231130 9286530
+62 5 5
+83
+
+chain 12516 chrUn_gl000214 137718 + 121124 121344 chr4 191273063 + 48979662 48979882 18214722
+66 74 74
+80
+
+chain 12053 chrUn_gl000214 137718 + 40633 40761 chrX 154913754 + 112045399 112045527 18908316
+128
+
+chain 11633 chrUn_gl000214 137718 + 43977 44114 chr4 191273063 - 11125034 11125171 12115615
+68 9 9
+60
+
+chain 11343 chrUn_gl000214 137718 + 39886 40006 chr13 114142980 + 66998338 66998458 20107936
+120
+
+chain 10884 chrUn_gl000214 137718 + 18108 18254 chr7 158821424 - 131367688 131367833 20945231
+55 19 18
+72
+
+chain 10521 chrUn_gl000214 137718 + 42241 42602 chr8 146274826 - 25959812 25960177 13454333
+84 222 226
+55
+
+chain 10411 chrUn_gl000214 137718 + 45055 45186 chr20 62435964 + 7050253 7050384 21896014
+54 12 12
+65
+
+chain 10343 chrUn_gl000214 137718 + 8804 8914 chrY 57772954 + 22287260 22287370 22043563
+110
+
+chain 9757 chrUn_gl000214 137718 + 19458 19875 chr3 199501827 - 187590477 187590901 23376485
+52 295 302
+70
+
+chain 9700 chrUn_gl000214 137718 + 39692 39809 chrX 154913754 - 41279737 41279854 23514677
+52 4 4
+61
+
+chain 9578 chrUn_gl000214 137718 + 45502 45617 chrX 154913754 + 43420636 43420751 23808291
+55 5 5
+55
+
+chain 7894 chrUn_gl000214 137718 + 124390 125487 chr4 191273063 - 142252912 142254012 6167993
+130 754 757
+69 123 123
+21
+
+chain 7612 chrUn_gl000214 137718 + 129655 137576 chr1 247249719 + 142120436 142122192 1126110
+32 89 89
+59 44 44
+27 862 716
+54 6116 97
+123 138 138
+47 149 149
+97 35 35
+49
+
+chain 7146 chrUn_gl000214 137718 + 43209 43286 chr18 76117153 - 9582204 9582281 16185526
+77
+
+chain 6775 chrUn_gl000214 137718 + 131335 131918 chr4 191273063 - 142062211 142062794 1233528
+62 218 218
+89 189 189
+25
+
+chain 6321 chrUn_gl000214 137718 + 44440 44513 chr1 247249719 + 157810312 157810385 13757396
+56 5 5
+12
+
+chain 5727 chrUn_gl000214 137718 + 119564 119897 chr4 191273063 - 142062730 142063063 7342832
+77 196 196
+60
+
+chain 5584 chrUn_gl000214 137718 + 136603 136661 chr4 191273063 + 48976819 48976877 31707162
+58
+
+chain 5192 chrUn_gl000214 137718 + 41407 41463 chr4 191273063 + 95935104 95935160 21196855
+56
+
+chain 4895 chrUn_gl000214 137718 + 6041 6105 chr11 134452384 + 65843917 65843981 20155275
+64
+
+chain 4869 chrUn_gl000214 137718 + 43083 43135 chr9 140273252 - 106613347 106613399 21934699
+52
+
+chain 4480 chrUn_gl000214 137718 + 42602 42659 chr7 158821424 - 39929511 39929568 12681275
+57
+
+chain 4078 chrUn_gl000214 137718 + 41235 41291 chrX 154913754 - 134405062 134405118 18412789
+56
+
+chain 4015 chrUn_gl000214 137718 + 42902 42960 chr10 135374737 + 54220968 54221026 24474909
+58
+
+chain 3895 chrUn_gl000214 137718 + 40957 41057 chr14 106368585 + 31140172 31140272 6582169
+100
+
+chain 3738 chrUn_gl000214 137718 + 42125 42173 chrX 154913754 + 103679820 103679868 22522957
+48
+
+chain 3537 chrUn_gl000214 137718 + 136028 136122 chr4 191273063 + 48976243 48976337 4189785
+94
+
+chain 3097 chrUn_gl000214 137718 + 17979 18039 chrX 154913754 - 102020287 102020347 24003938
+60
+
+chain 2977 chrUn_gl000214 137718 + 126408 126469 chr1 247249719 - 105124849 105124910 6601664
+61
+
+chain 2968 chrUn_gl000214 137718 + 41775 41809 chr8 146274826 + 100416036 100416070 11606659
+34
+
+chain 2831 chrUn_gl000214 137718 + 137492 137527 chr4 191273063 + 48977417 48977452 2940885
+17 9 9
+9
+
+chain 2572 chrUn_gl000214 137718 + 44291 44369 chr11 134452384 - 117952414 117952492 17845944
+78
+
+chain 2345 chrUn_gl000214 137718 + 42033 42103 chr4 191273063 - 122527078 122527148 13059103
+70
+
+chain 2276 chrUn_gl000214 137718 + 43135 43209 chr1 247249719 + 86869873 86869947 13860931
+74
+
+chain 1770 chrUn_gl000214 137718 + 44144 44227 chr3 199501827 + 24100092 24100175 18271654
+83
+
+chain 1506 chrUn_gl000214 137718 + 36174 36256 chr1 247249719 - 105422371 105422453 16376759
+82
+
+chain 1502 chrUn_gl000214 137718 + 43875 43977 chr9 140273252 + 102510935 102511037 11228177
+102
+
+chain 1456 chrUn_gl000214 137718 + 130737 130768 chr21_random 1679693 - 929809 929840 22601085
+31
+
+chain 1365 chrUn_gl000214 137718 + 125246 125274 chr21_random 1679693 - 930310 930338 15151243
+28
+
+chain 1098 chrUn_gl000214 137718 + 42962 43013 chr6 170899992 - 83239423 83239474 24355258
+51
+
+chain 931 chrUn_gl000214 137718 + 41878 41928 chr11 134452384 - 41659375 41659425 15038916
+50
+
+chain 888 chrUn_gl000214 137718 + 45207 45259 chr11 134452384 + 93610909 93610961 21407350
+52
+
+chain 856 chrUn_gl000214 137718 + 119897 119930 chr19 63811651 - 14205840 14205873 23032647
+33
+
+chain 766 chrUn_gl000214 137718 + 127016 127090 chr19 63811651 - 14200495 14200569 19831992
+74
+
+chain 676 chrUn_gl000214 137718 + 18987 19049 chr11 134452384 + 106173710 106173772 23556763
+62
+
+chain 650 chrUn_gl000214 137718 + 132603 132659 chr21_random 1679693 + 746889 746945 1349757
+56
+
+chain 423 chrUn_gl000214 137718 + 20746 20796 chr2 242951149 - 226029097 226029147 25845790
+50
+
+chain 16237347 chrUn_gl000215 172545 + 28 172526 chr21 46944323 + 13950000 14122426 177
+3255 0 4
+29034 1 0
+5104 4 0
+10299 0 8
+14263 11 11
+94 6 0
+113 107 1
+75 1 1
+91 1 1
+24 1 1
+6681 0 33
+907 41 41
+7674 2 0
+2274 12 11
+563 0 1
+8540 1 0
+12525 1 1
+36 1 1
+25408 0 12
+3782 0 2
+694 85 67
+996 1 3
+1425 12 12
+1827 1 1
+21 1 1
+941 13 13
+2073 0 8
+28 1 1
+506 0 2
+1227 1 0
+1108 2 2
+28 1 1
+396 1 0
+253 14 14
+184 1 1
+49 1 1
+2962 1 1
+45 4 0
+1510 19 19
+2709 25 25
+1068 0 4
+836 1 0
+1871 0 1
+579 4 0
+60 14 14
+2466 27 27
+1450 1 0
+19 1 1
+618 6 6
+2880 1 0
+450 0 2
+27 0 4
+4576 1 1
+20 1 1
+789 0 1
+721 14 14
+1438 35 31
+1381 1 1
+18 1 1
+73 12 12
+195 1 1
+35 1 1
+708
+
+chain 40526 chrUn_gl000216 172294 + 149263 155793 chr18 76117153 - 76016375 76018189 3221814
+113 325 326
+78 431 292
+71 14 14
+107 786 375
+37 69 0
+81 2953 216
+58 1361 0
+46
+
+chain 27660 chrUn_gl000216 172294 + 75671 76099 chr20 62435964 - 33142597 33142960 5774439
+63 0 10
+32 5 0
+14 10 0
+50 35 0
+20 10 0
+56 5 0
+53 21 11
+54
+
+chain 27279 chrUn_gl000216 172294 + 130292 130617 chrX 154913754 + 63390360 63390685 5931924
+69 12 12
+78 1 1
+165
+
+chain 17860 chrUn_gl000216 172294 + 130000 130214 chr4 191273063 + 73778471 73778685 12240737
+58 12 12
+144
+
+chain 16947 chrUn_gl000216 172294 + 147288 147775 chr18 76117153 - 76016450 76016937 13094679
+76 288 288
+123
+
+chain 13816 chrUn_gl000216 172294 + 129031 129176 chr8 146274826 - 38602125 38602270 16419487
+145
+
+chain 12180 chrUn_gl000216 172294 + 145189 145506 chrY 57772954 + 11928279 11928596 18712695
+46 95 95
+51 66 66
+59
+
+chain 11701 chrUn_gl000216 172294 + 158739 158864 chr18 76117153 + 99277 99402 19495084
+125
+
+chain 11637 chrUn_gl000216 172294 + 171754 172194 chrY 57772954 + 11932706 11933147 19600583
+53 299 300
+88
+
+chain 11521 chrUn_gl000216 172294 + 129787 129947 chr6 170899992 + 5983639 5983799 19799726
+64 26 26
+70
+
+chain 10625 chrUn_gl000216 172294 + 164963 165111 chr18 76117153 + 100265 100413 21456050
+73 25 25
+50
+
+chain 10470 chrUn_gl000216 172294 + 131591 131702 chrX 154913754 + 36583233 36583344 21778508
+111
+
+chain 10288 chrUn_gl000216 172294 + 131963 132072 chr3 199501827 - 99262429 99262538 22162166
+109
+
+chain 9778 chrUn_gl000216 172294 + 141853 142019 chr18 76117153 - 76016600 76016834 23327029
+64 49 117
+53
+
+chain 9609 chrUn_gl000216 172294 + 135933 137341 chrY 57772954 + 11926871 11928279 23735609
+56 647 1260
+56 613 0
+36
+
+chain 9489 chrUn_gl000216 172294 + 169302 169609 chrY 57772954 + 11921023 11921330 24024953
+52 191 191
+64
+
+chain 9460 chrUn_gl000216 172294 + 132170 132290 chrY 57772954 + 11935643 11935763 24098583
+50 10 10
+60
+
+chain 9059 chrUn_gl000216 172294 + 169179 169274 chrY 57772954 - 366511 366606 24861253
+95
+
+chain 8863 chrUn_gl000216 172294 + 133271 135681 chrY 57772954 - 372628 372853 25150456
+61 2277 92
+72
+
+chain 8329 chrUn_gl000216 172294 + 1479 1877 chr4 191273063 - 141929935 141931620 25915977
+67 278 1565
+53
+
+chain 8155 chrUn_gl000216 172294 + 150573 151188 chrY 57772954 - 377413 378366 22301630
+51 559 897
+5
+
+chain 8086 chrUn_gl000216 172294 + 168370 168455 chr18 76117153 - 76017788 76017873 26288571
+85
+
+chain 7777 chrUn_gl000216 172294 + 34186 34268 chr1 247249719 - 24981278 24981360 26771397
+82
+
+chain 6822 chrUn_gl000216 172294 + 132393 132465 chrY 57772954 - 376390 376462 28544596
+72
+
+chain 6622 chrUn_gl000216 172294 + 9240 9310 chr10 135374737 + 41683434 41683504 28988878
+70
+
+chain 6573 chrUn_gl000216 172294 + 130631 130733 chr5 180857866 - 72032622 72032724 12023329
+102
+
+chain 6476 chrUn_gl000216 172294 + 146529 146597 chr18 76117153 - 76017808 76017876 29355811
+68
+
+chain 6422 chrUn_gl000216 172294 + 8523 8591 chr4 191273063 + 48829234 48829302 29489285
+68
+
+chain 6384 chrUn_gl000216 172294 + 148442 148586 chrY 57772954 - 378355 378430 29582296
+29 69 0
+46
+
+chain 6003 chrUn_gl000216 172294 + 133483 133546 chrY 57772954 - 370776 370839 30561430
+63
+
+chain 5985 chrUn_gl000216 172294 + 11844 11907 chr4 191273063 + 48811176 48811239 30589131
+63
+
+chain 5885 chrUn_gl000216 172294 + 151788 151850 chrY 57772954 - 366263 366325 30854068
+62
+
+chain 5721 chrUn_gl000216 172294 + 136853 136913 chrY 57772954 - 372235 372295 31317120
+60
+
+chain 5667 chrUn_gl000216 172294 + 19071 19131 chr4 191273063 + 48811263 48811323 31460984
+60
+
+chain 5339 chrUn_gl000216 172294 + 145664 145720 chrY 57772954 + 11941006 11941062 32420221
+56
+
+chain 5322 chrUn_gl000216 172294 + 130963 131035 chr5 180857866 - 36043748 36043820 20305124
+72
+
+chain 5257 chrUn_gl000216 172294 + 158216 158271 chr18 76117153 + 96100 96155 32682417
+55
+
+chain 5221 chrUn_gl000216 172294 + 7155 7210 chr4 191273063 + 48836505 48836560 32772522
+55
+
+chain 5121 chrUn_gl000216 172294 + 15141 15195 chr4 191273063 + 48847759 48847813 33093239
+54
+
+chain 5012 chrUn_gl000216 172294 + 26593 26646 chr21 46944323 - 37095349 37095402 33456608
+53
+
+chain 4930 chrUn_gl000216 172294 + 37276 37328 chr1 247249719 - 24981705 24981757 33717061
+52
+
+chain 4884 chrUn_gl000216 172294 + 137193 137244 chrY 57772954 - 377416 377467 33922210
+51
+
+chain 4821 chrUn_gl000216 172294 + 20849 20900 chr20 62435964 - 33142732 33142783 34122269
+51
+
+chain 4766 chrUn_gl000216 172294 + 152958 153008 chr18 76117153 - 76017195 76017245 34319410
+50
+
+chain 4757 chrUn_gl000216 172294 + 155624 155674 chr18 76117153 - 76018020 76018070 34342345
+50
+
+chain 2863 chrUn_gl000216 172294 + 172194 172224 chrY 57772954 + 11925069 11925099 19922357
+30
+
+chain 2829 chrUn_gl000216 172294 + 131145 131290 chr12 132349534 + 50244945 50245090 12112131
+51 88 88
+6
+
+chain 2529 chrUn_gl000216 172294 + 129176 129203 chr9 140273252 - 119219512 119219539 22134781
+27
+
+chain 2341 chrUn_gl000216 172294 + 131196 131233 chr3 199501827 - 98572452 98572489 18288091
+37
+
+chain 2151 chrUn_gl000216 172294 + 131290 131397 chr7 158821424 - 127191925 127192032 12067691
+107
+
+chain 2108 chrUn_gl000216 172294 + 149377 153105 chrY 57772954 + 11933439 11934497 20496839
+67 3022 286
+50 506 572
+83
+
+chain 1614 chrUn_gl000216 172294 + 130868 130925 chr3 199501827 - 79251115 79251172 16953843
+57
+
+chain 1538 chrUn_gl000216 172294 + 76099 76129 chr21 46944323 - 37102976 37103006 11762953
+30
+
+chain 694 chrUn_gl000216 172294 + 135555 135593 chrY 57772954 - 377637 377675 25976788
+38
+
+chain 532 chrUn_gl000216 172294 + 153980 155370 chrY 57772954 - 378352 378449 22847936
+39 1293 0
+58
+
+chain 454 chrUn_gl000216 172294 + 863 915 chr4 191273063 + 48799453 48799505 31198348
+52
+
+chain 383 chrUn_gl000216 172294 + 153157 153210 chr18 76117153 - 76017394 76017447 29745290
+53
+
+chain 174 chrUn_gl000216 172294 + 138050 138103 chrY 57772954 + 11945950 11946003 28091780
+53
+
+chain 99 chrUn_gl000216 172294 + 11396 11447 chr20 62435964 - 33142766 33142817 31359773
+51
+
+chain 13777792 chrUn_gl000217 172149 + 23665 172149 chr21_random 1679693 - 1239693 1388121 218
+366 17 17
+766 1 0
+21 0 8
+60 2 0
+3460 4 0
+2511 2 0
+113 1 0
+1145 0 1
+931 1 1
+37 1 1
+107 13 13
+4657 1 1
+48 1 1
+2113 0 1
+574 10 0
+111 1 0
+49 1 1
+1025 3 0
+497 0 11
+154 5 0
+640 0 6
+1684 0 16
+300 1 0
+1527 0 6
+147 1 0
+718 18 0
+30 1 1
+1243 1 1
+16 1 1
+162 28 0
+401 0 11
+281 1 1
+27 1 1
+892 1 0
+45 1 1
+2501 0 26
+74 115 11
+2278 8 8
+1028 0 1
+756 7 7
+1386 1 0
+3286 40 0
+504 1 0
+989 1 1
+24 1 1
+123 36 37
+2057 0 26
+72 2 0
+945 1 1
+22 1 1
+1558 1 1
+43 2 0
+2083 22 0
+462 0 1
+86 1 1
+37 1 1
+1415 0 1
+22 0 1
+1139 24 25
+1775 11 11
+2714 1 1
+41 1 1
+4780 0 1
+352 1 1
+25 1 1
+171 1 0
+514 1 0
+2199 1 1
+48 1 1
+262 3 1
+2426 0 1
+502 0 2
+1043 1 1
+49 1 0
+3147 0 3
+4432 1 1
+17 1 1
+2420 1 0
+43 1 1
+1809 1 0
+15 1 1
+1710 0 34
+61 36 0
+119 0 2
+4683 1 1
+44 1 1
+58 23 0
+44 0 104
+50 98 0
+43 1 1
+214 1 41
+29 0 1
+4 6 13
+39 0 105
+122 1 1
+31 17 1
+69 234 6
+48 1 17
+40 1 1
+1306 2 0
+3089 0 1
+2059 1 1
+32 1 1
+137 1 4
+584 1 0
+2518 1 0
+480 0 4
+6 2 0
+22 8 0
+177 1 1
+29 1 1
+6728 0 1
+1945 0 2
+8972 11 11
+806 1 3
+3054 0 3
+649 0 4
+1956 1 3
+795 1 0
+16 1 1
+1498 1 1
+28 1 1
+3012 5 0
+238 0 5
+220 0 5
+441 0 31
+141 10 0
+57 5 0
+1652 1 0
+233 1 0
+855 1 0
+845 38 0
+395 0 38
+182 22 0
+494 0 139
+1699 1 1
+42 0 1
+2261 1 1
+33 1 1
+3400 1 1
+41 1 1
+2247 0 2
+46 4 0
+34 0 14
+1049 1 13
+223 1 1
+49 1 1
+746 1 1
+36 1 1
+3491 0 1
+528
+
+chain 29979 chrUn_gl000217 172149 + 0 388 chr9 140273252 - 70842853 70843241 4686196
+80 39 39
+172 1 1
+24 1 1
+71
+
+chain 18989 chrUn_gl000217 172149 + 8221 8418 chr12 132349534 - 39661230 39661427 11281819
+197
+
+chain 10175 chrUn_gl000217 172149 + 14880 15009 chr19 63811651 + 45504623 45504752 22420709
+57 12 12
+60
+
+chain 3003 chrUn_gl000217 172149 + 63765 63801 chr6 170899992 + 56559189 56559225 3519131
+36
+
+chain 15268007 chrUn_gl000218 161147 + 0 161147 chr4_random 842648 + 681501 842648 193
+161147
+
+chain 274326 chrUn_gl000219 179198 + 111203 114251 chr8 146274826 - 136639851 136643413 309026
+102 1 1
+45 1 1
+484 9 9
+416 19 537
+171 4 0
+45 1 1
+189 7 7
+1328 1 1
+25 1 1
+199
+
+chain 235925 chrUn_gl000219 179198 + 35758 40113 chr15 100338915 - 47328984 47333335 444051
+127 1 1
+284 1 1
+140 1 1
+133 1 1
+73 1 1
+89 1 1
+75 13 8
+90 1 1
+92 1 1
+53 1 1
+73 1 1
+71 137 137
+163 8 8
+63 55 55
+141 31 31
+188 97 97
+60 103 103
+177 192 193
+314 188 188
+58 236 236
+75 260 260
+62 155 155
+105 29 29
+135
+
+chain 46161 chrUn_gl000219 179198 + 66272 68851 chrX 154913754 - 104037210 104039793 2773810
+120 238 238
+52 281 281
+59 653 657
+101 247 247
+106 343 343
+50 27 27
+62 173 173
+67
+
+chain 39536 chrUn_gl000219 179198 + 161917 162706 chr3 199501827 + 46165513 46166302 3318717
+67 218 218
+170 33 33
+104 60 60
+51 4 4
+82
+
+chain 37284 chrUn_gl000219 179198 + 19843 20929 chr8 146274826 + 98123209 98124295 3557690
+51 99 100
+128 134 134
+52 226 225
+160 168 168
+68
+
+chain 28967 chrUn_gl000219 179198 + 161273 161605 chr11 134452384 - 120964606 120964939 5150829
+171 2 3
+60 3 3
+96
+
+chain 28762 chrUn_gl000219 179198 + 6734 7878 chr3 199501827 - 92709198 92710343 5264432
+50 316 316
+83 67 67
+64 228 228
+51 85 86
+50 65 65
+85
+
+chain 21234 chrUn_gl000219 179198 + 175633 175875 chr1 247249719 - 2003467 2003709 9514914
+86 1 1
+40 1 1
+114
+
+chain 19234 chrUn_gl000219 179198 + 161066 161917 chr3 199501827 - 120235323 120237534 3582834
+110 737 2097
+4
+
+chain 14579 chrUn_gl000219 179198 + 21180 21751 chr1 247249719 - 137161846 137162418 6911796
+101 255 256
+2 163 163
+50
+
+chain 14519 chrUn_gl000219 179198 + 21064 21625 chr8 146274826 - 24167411 24167976 5552170
+59 415 419
+87
+
+chain 12254 chrUn_gl000219 179198 + 20707 20861 chr10 135374737 - 130087649 130087801 7386312
+11 3 1
+47 1 0
+4 0 1
+88
+
+chain 9835 chrUn_gl000219 179198 + 175209 175553 chr1 247249719 + 75620763 75621106 11122143
+78 179 178
+87
+
+chain 9013 chrUn_gl000219 179198 + 69512 69754 chr7 158821424 - 49488455 49488697 24923378
+57 133 133
+52
+
+chain 8698 chrUn_gl000219 179198 + 38816 38977 chr2 242951149 + 197483269 197483430 445169
+50 27 27
+84
+
+chain 7558 chrUn_gl000219 179198 + 37648 39844 chr4 191273063 - 67477312 67479509 573905
+31 2054 2055
+111
+
+chain 7043 chrUn_gl000219 179198 + 7883 7996 chrX 154913754 + 69120337 69120450 10599908
+113
+
+chain 6948 chrUn_gl000219 179198 + 21437 21525 chr10 135374737 - 55879531 55879619 9852807
+88
+
+chain 6886 chrUn_gl000219 179198 + 69191 69264 chrX 154913754 - 102980817 102980890 28429791
+73
+
+chain 6839 chrUn_gl000219 179198 + 21356 21436 chr11 134452384 + 41149119 41149199 10517795
+80
+
+chain 6788 chrUn_gl000219 179198 + 67776 67858 chr1 247249719 - 168765537 168765619 14909693
+1 2 2
+79
+
+chain 6785 chrUn_gl000219 179198 + 65376 65449 chr6 170899992 - 64502886 64502959 18163056
+73
+
+chain 6479 chrUn_gl000219 179198 + 35525 35758 chr13 114142980 - 61572553 61572786 1009673
+94 1 1
+129 2 2
+7
+
+chain 6180 chrUn_gl000219 179198 + 161178 161256 chr16 88827254 + 48470284 48470362 9569492
+78
+
+chain 5767 chrUn_gl000219 179198 + 65835 65896 chr1 247249719 + 223356684 223356745 31174397
+61
+
+chain 5622 chrUn_gl000219 179198 + 64700 64760 chr20 62435964 - 34176164 34176224 31585501
+60
+
+chain 4453 chrUn_gl000219 179198 + 175305 175363 chr7 158821424 - 154223466 154223524 19289607
+58
+
+chain 4398 chrUn_gl000219 179198 + 39190 39280 chr3 199501827 - 39205036 39205126 641764
+90
+
+chain 4168 chrUn_gl000219 179198 + 39128 39178 chrX 154913754 + 101254041 101254091 4762602
+50
+
+chain 4142 chrUn_gl000219 179198 + 160731 161020 chr7 158821424 + 108154685 108154975 5568871
+69 147 148
+73
+
+chain 4059 chrUn_gl000219 179198 + 39531 39627 chrY 57772954 + 3377002 3377098 1049766
+96
+
+chain 3905 chrUn_gl000219 179198 + 39425 39515 chr4 191273063 - 20599126 20599216 1025664
+90
+
+chain 3833 chrUn_gl000219 179198 + 19916 19966 chr11 134452384 - 24481539 24481589 14324455
+50
+
+chain 3723 chrUn_gl000219 179198 + 21281 21353 chr8 146274826 + 142341809 142341882 8036105
+11 0 1
+61
+
+chain 3631 chrUn_gl000219 179198 + 7185 7231 chr4 191273063 - 60113302 60113348 10096087
+46
+
+chain 3560 chrUn_gl000219 179198 + 35297 35440 chrX 154913754 + 31459857 31460000 1356163
+59 9 9
+75
+
+chain 3418 chrUn_gl000219 179198 + 74680 74734 chr2 242951149 + 159856161 159856226 35171835
+17 0 12
+9 2 1
+26
+
+chain 3363 chrUn_gl000219 179198 + 65597 65637 chr10 135374737 + 67903510 67903550 17680942
+40
+
+chain 3281 chrUn_gl000219 179198 + 38411 38486 chr18 76117153 + 65271563 65271638 907991
+75
+
+chain 3262 chrUn_gl000219 179198 + 162509 162544 chrX 154913754 - 14195886 14195921 20233062
+35
+
+chain 3092 chrUn_gl000219 179198 + 161605 161689 chr2 242951149 - 35465049 35465133 8792079
+19 6 6
+59
+
+chain 3074 chrUn_gl000219 179198 + 8990 9025 chr5 180857866 - 164468813 164468848 19527162
+35
+
+chain 3012 chrUn_gl000219 179198 + 38101 39406 chr14 106368585 - 62185839 62187145 783679
+26 1240 1241
+39
+
+chain 2934 chrUn_gl000219 179198 + 161840 161913 chr5 180857866 + 13471789 13471862 3866284
+73
+
+chain 2839 chrUn_gl000219 179198 + 34989 35118 chr8 146274826 + 40409778 40409907 1133484
+56 12 12
+61
+
+chain 2727 chrUn_gl000219 179198 + 21634 21700 chr14 106368585 - 78516623 78516689 9118599
+66
+
+chain 2697 chrUn_gl000219 179198 + 68852 68888 chr5 180857866 + 9312654 9312690 14610628
+36
+
+chain 2584 chrUn_gl000219 179198 + 35177 35274 chr3 199501827 + 147129328 147129425 4467916
+97
+
+chain 2547 chrUn_gl000219 179198 + 161690 161789 chr5 180857866 + 112830789 112830888 9276265
+99
+
+chain 2541 chrUn_gl000219 179198 + 162131 162175 chr12 132349534 + 54242993 54243037 9307702
+44
+
+chain 2485 chrUn_gl000219 179198 + 66217 68255 chr3 199501827 - 72358479 72360521 2866668
+55 1368 1372
+35 524 524
+56
+
+chain 2353 chrUn_gl000219 179198 + 38305 38360 chr8 146274826 - 49639359 49639414 1034303
+55
+
+chain 2230 chrUn_gl000219 179198 + 19408 19487 chr7 158821424 - 133365577 133365656 10769161
+79
+
+chain 2205 chrUn_gl000219 179198 + 37167 37218 chr2 242951149 - 113063084 113063135 1010147
+51
+
+chain 2136 chrUn_gl000219 179198 + 65993 67374 chr8 146274826 - 58386388 58387767 6969587
+99 1231 1229
+51
+
+chain 2065 chrUn_gl000219 179198 + 7314 7369 chr14 106368585 + 55554421 55554476 5303485
+55
+
+chain 1985 chrUn_gl000219 179198 + 5703 5757 chr4 191273063 - 94652192 94652246 23958560
+54
+
+chain 1979 chrUn_gl000219 179198 + 66506 66565 chr7 158821424 + 94546370 94546429 13229356
+59
+
+chain 1960 chrUn_gl000219 179198 + 8700 8761 chrY 57772954 + 20614456 20614517 21829859
+61
+
+chain 1888 chrUn_gl000219 179198 + 38366 38411 chr2 242951149 - 129971519 129971564 1057646
+45
+
+chain 1811 chrUn_gl000219 179198 + 160836 160864 chr22 49691432 - 22795768 22795796 23819908
+28
+
+chain 1737 chrUn_gl000219 179198 + 20319 20358 chrX 154913754 + 73928334 73928373 13243726
+39
+
+chain 1736 chrUn_gl000219 179198 + 19558 19630 chr12 132349534 - 63652443 63652515 6467659
+72
+
+chain 1682 chrUn_gl000219 179198 + 39076 39116 chr3 199501827 + 15208154 15208194 1287150
+40
+
+chain 1666 chrUn_gl000219 179198 + 38024 38063 chr1 247249719 - 83040882 83040921 867179
+39
+
+chain 1646 chrUn_gl000219 179198 + 37115 37153 chr15 100338915 - 50839190 50839228 850747
+38
+
+chain 1585 chrUn_gl000219 179198 + 67541 68190 chr8 146274826 - 129698985 129699635 3519578
+54 538 539
+57
+
+chain 1568 chrUn_gl000219 179198 + 21824 21882 chr4 191273063 + 144137347 144137405 18944021
+58
+
+chain 1525 chrUn_gl000219 179198 + 6513 6565 chr8 146274826 - 33560291 33560343 10738256
+52
+
+chain 1509 chrUn_gl000219 179198 + 162035 162086 chr3 199501827 + 35122783 35122834 10573790
+51
+
+chain 1485 chrUn_gl000219 179198 + 160887 160939 chr4 191273063 + 75861307 75861359 9708390
+52
+
+chain 1479 chrUn_gl000219 179198 + 65726 65767 chrX 154913754 - 87810259 87810300 15949912
+41
+
+chain 1467 chrUn_gl000219 179198 + 39689 39722 chrX 154913754 + 69240387 69240420 781473
+33
+
+chain 1461 chrUn_gl000219 179198 + 67280 67323 chr10 135374737 - 66201225 66201268 13894764
+43
+
+chain 1450 chrUn_gl000219 179198 + 67375 67437 chr5 180857866 + 57384861 57384923 6350454
+62
+
+chain 1396 chrUn_gl000219 179198 + 67210 67264 chr9 140273252 - 22551031 22551085 6094817
+54
+
+chain 1389 chrUn_gl000219 179198 + 66392 68784 chr1 247249719 + 65797848 65800245 3034140
+29 2307 2312
+56
+
+chain 1366 chrUn_gl000219 179198 + 20143 20198 chr4 191273063 - 69480908 69480963 5880463
+55
+
+chain 1339 chrUn_gl000219 179198 + 162175 162202 chr1 247249719 - 74777177 74777204 3339890
+27
+
+chain 1337 chrUn_gl000219 179198 + 68329 68386 chr10 135374737 - 97276986 97277043 13905473
+57
+
+chain 1334 chrUn_gl000219 179198 + 39950 39978 chr8 146274826 - 60735711 60735739 964260
+28
+
+chain 1215 chrUn_gl000219 179198 + 19784 19836 chr1 247249719 - 212757024 212757076 9451024
+52
+
+chain 1204 chrUn_gl000219 179198 + 9400 9453 chr2 242951149 - 221538709 221538762 17248558
+53
+
+chain 1196 chrUn_gl000219 179198 + 65543 65596 chrX 154913754 - 74732188 74732241 11122165
+53
+
+chain 1136 chrUn_gl000219 179198 + 160693 160717 chr2 242951149 + 96004141 96004165 19597584
+24
+
+chain 1088 chrUn_gl000219 179198 + 19507 19558 chr9 140273252 + 124212712 124212763 4480835
+51
+
+chain 1079 chrUn_gl000219 179198 + 37482 37507 chr4 191273063 - 92702671 92702696 10491706
+25
+
+chain 1063 chrUn_gl000219 179198 + 6670 6734 chr3 199501827 + 6965033 6965097 10403549
+64
+
+chain 1052 chrUn_gl000219 179198 + 19721 19774 chr1 247249719 + 112545490 112545543 7413376
+53
+
+chain 1038 chrUn_gl000219 179198 + 160800 160824 chrX 154913754 + 84200659 84200683 17773754
+24
+
+chain 979 chrUn_gl000219 179198 + 67437 67498 chr12 132349534 + 127544420 127544481 8975114
+61
+
+chain 882 chrUn_gl000219 179198 + 68888 68940 chr2 242951149 + 41597257 41597309 8629613
+52
+
+chain 862 chrUn_gl000219 179198 + 34692 34749 chr7 158821424 + 91057493 91057550 3914497
+57
+
+chain 862 chrUn_gl000219 179198 + 19258 19321 chr17 78774742 + 11706793 11706856 10608405
+63
+
+chain 836 chrUn_gl000219 179198 + 6404 6488 chrX_random 1719168 - 557556 557640 15714908
+84
+
+chain 826 chrUn_gl000219 179198 + 6064 6121 chr4 191273063 + 114632432 114632489 6389008
+57
+
+chain 786 chrUn_gl000219 179198 + 19327 19383 chr4 191273063 + 95451114 95451170 8391346
+56
+
+chain 781 chrUn_gl000219 179198 + 66882 66938 chr15 100338915 + 35480475 35480531 9740616
+56
+
+chain 780 chrUn_gl000219 179198 + 5491 5548 chr19 63811651 + 45237769 45237826 8205599
+57
+
+chain 773 chrUn_gl000219 179198 + 18906 18956 chr5 180857866 - 161656026 161656076 5757214
+50
+
+chain 756 chrUn_gl000219 179198 + 5561 5620 chr8 146274826 - 76452822 76452881 8679584
+59
+
+chain 744 chrUn_gl000219 179198 + 8892 8945 chr18 76117153 + 27187323 27187376 6534410
+53
+
+chain 702 chrUn_gl000219 179198 + 67866 67921 chr11 134452384 - 45331858 45331913 4032419
+55
+
+chain 658 chrUn_gl000219 179198 + 65665 65726 chr11 134452384 - 71401302 71401363 8693276
+61
+
+chain 610 chrUn_gl000219 179198 + 68611 68641 chr6 170899992 - 104159480 104159510 6224934
+30
+
+chain 600 chrUn_gl000219 179198 + 34306 34379 chr9 140273252 + 67999140 67999213 8057147
+73
+
+chain 566 chrUn_gl000219 179198 + 68393 68455 chr13 114142980 + 104410587 104410649 8663433
+62
+
+chain 556 chrUn_gl000219 179198 + 66682 66718 chr4 191273063 - 23557773 23557809 3204114
+36
+
+chain 543 chrUn_gl000219 179198 + 66718 66743 chr4 191273063 + 67612053 67612078 7944900
+25
+
+chain 543 chrUn_gl000219 179198 + 8373 8450 chr1 247249719 - 76782344 76782421 23880934
+77
+
+chain 532 chrUn_gl000219 179198 + 6121 6161 chr13 114142980 - 84408205 84408245 7620044
+40
+
+chain 531 chrUn_gl000219 179198 + 66743 66797 chr3 199501827 - 142542844 142542898 11924432
+54
+
+chain 522 chrUn_gl000219 179198 + 7996 8024 chr12 132349534 + 73188186 73188214 12754595
+28
+
+chain 500 chrUn_gl000219 179198 + 67110 67168 chr5 180857866 + 134363242 134363300 15867098
+58
+
+chain 485 chrUn_gl000219 179198 + 69293 69355 chr1 247249719 + 99641891 99641953 7463394
+62
+
+chain 483 chrUn_gl000219 179198 + 66186 66217 chrX 154913754 - 138658729 138658760 7191935
+31
+
+chain 477 chrUn_gl000219 179198 + 19687 19721 chr7 158821424 + 45385787 45385821 16982489
+34
+
+chain 474 chrUn_gl000219 179198 + 8598 8650 chrX 154913754 - 113360025 113360077 16003052
+52
+
+chain 421 chrUn_gl000219 179198 + 65449 65511 chr1 247249719 + 187704570 187704632 12170451
+62
+
+chain 402 chrUn_gl000219 179198 + 8487 8537 chr8 146274826 - 79772642 79772692 15615542
+50
+
+chain 400 chrUn_gl000219 179198 + 67611 67640 chr1 247249719 - 149721975 149722004 3673241
+29
+
+chain 357 chrUn_gl000219 179198 + 8945 8990 chr3 199501827 - 164258935 164258980 15296887
+45
+
+chain 325 chrUn_gl000219 179198 + 66571 66608 chr6 170899992 - 28562683 28562720 10433787
+37
+
+chain 267 chrUn_gl000219 179198 + 66437 66493 chr8 146274826 + 91475861 91475917 20384527
+56
+
+chain 259 chrUn_gl000219 179198 + 68682 68710 chr11 134452384 - 28278838 28278866 23153636
+28
+
+chain 207038 chrUn_gl000220 161802 + 151486 153627 chr21_random 1679693 - 0 2145 573346
+1058 0 1
+394 0 4
+106 1 0
+582
+
+chain 207038 chrUn_gl000220 161802 + 107514 109655 chr21_random 1679693 - 0 2145 573347
+1058 0 1
+394 0 4
+106 1 0
+582
+
+chain 69503 chrUn_gl000220 161802 + 67389 69230 chr2 242951149 + 25799043 25800417 1810371
+218 1 1
+72 2 2
+113 1024 551
+85 19 19
+226 0 6
+81
+
+chain 31351 chrUn_gl000220 161802 + 117547 117875 chr1 247249719 - 155624021 155624349 4397311
+328
+
+chain 29427 chrUn_gl000220 161802 + 67361 68249 chr1 247249719 - 87588997 87589612 2331939
+28 406 406
+54 1 1
+64 273 0
+62
+
+chain 27049 chrUn_gl000220 161802 + 161519 161802 chr1 247249719 - 155624021 155624304 6035035
+283
+
+chain 25088 chrUn_gl000220 161802 + 36919 37185 chr1 247249719 - 45093231 45093497 6989949
+266
+
+chain 24729 chrUn_gl000220 161802 + 117030 117449 chrX 154913754 + 108184031 108184449 7237839
+197 142 141
+80
+
+chain 20499 chrUn_gl000220 161802 + 65633 66956 chr8 146274826 - 2314439 2315749 10054888
+157 1045 1032
+53 13 13
+55
+
+chain 20386 chrUn_gl000220 161802 + 75253 75471 chr11 134452384 + 26865999 26866217 10139728
+218
+
+chain 17914 chrUn_gl000220 161802 + 106337 107514 chr20 62435964 - 36297925 36299106 11745937
+55 875 884
+91 103 98
+53
+
+chain 17680 chrUn_gl000220 161802 + 84353 85836 chr15 100338915 + 87980076 87981560 12400789
+131 384 386
+57 861 860
+50
+
+chain 16118 chrUn_gl000220 161802 + 159904 160089 chr5 180857866 + 71182513 71182698 13920446
+124 8 8
+53
+
+chain 16118 chrUn_gl000220 161802 + 115932 116117 chr5 180857866 + 71182513 71182698 13920447
+124 8 8
+53
+
+chain 15578 chrUn_gl000220 161802 + 85289 85786 chr10 135374737 - 97997712 97998207 12517238
+97 354 352
+46
+
+chain 14161 chrUn_gl000220 161802 + 154326 154474 chr12 132349534 + 20595624 20595772 16008128
+148
+
+chain 14161 chrUn_gl000220 161802 + 110354 110502 chr12 132349534 + 20595624 20595772 16008129
+148
+
+chain 13476 chrUn_gl000220 161802 + 149534 149686 chr1 247249719 + 154452993 154453145 16852628
+91 5 5
+56
+
+chain 13476 chrUn_gl000220 161802 + 105562 105714 chr1 247249719 + 154452993 154453145 16852629
+91 5 5
+56
+
+chain 13074 chrUn_gl000220 161802 + 75664 75872 chr5 180857866 + 148307676 148307883 12475568
+65 80 79
+63
+
+chain 12291 chrUn_gl000220 161802 + 109957 110143 chr2 242951149 - 110221779 110221963 18542579
+61 44 42
+81
+
+chain 11141 chrUn_gl000220 161802 + 65790 65916 chr6 170899992 - 125538722 125538849 11778575
+19 0 1
+11 1 1
+95
+
+chain 11117 chrUn_gl000220 161802 + 113673 113902 chr11 134452384 + 84872723 84872926 20519201
+78 99 73
+52
+
+chain 10468 chrUn_gl000220 161802 + 30468 30675 chr1 247249719 + 43344900 43345108 21782937
+53 83 84
+71
+
+chain 10467 chrUn_gl000220 161802 + 122720 122828 chr16 88827254 - 74338770 74338878 21787089
+108
+
+chain 10454 chrUn_gl000220 161802 + 159242 159370 chr19 63811651 + 40758345 40758473 21809803
+64 8 8
+56
+
+chain 10022 chrUn_gl000220 161802 + 109687 109957 chr16 88827254 + 33870609 33870877 21321955
+66 160 158
+44
+
+chain 9617 chrUn_gl000220 161802 + 65083 65225 chr6 170899992 - 64517981 64518123 23713679
+59 28 28
+55
+
+chain 9067 chrUn_gl000220 161802 + 65995 66091 chr5 180857866 - 61890711 61890807 15044279
+96
+
+chain 8090 chrUn_gl000220 161802 + 66643 66751 chrX 154913754 + 93027353 93027460 18331310
+57 8 8
+30 1 0
+12
+
+chain 7895 chrUn_gl000220 161802 + 83808 83891 chr8 146274826 - 74499810 74499893 26574027
+83
+
+chain 7508 chrUn_gl000220 161802 + 130266 131540 chr16 88827254 + 33860661 33862774 27224265
+76 1140 1979
+58
+
+chain 6793 chrUn_gl000220 161802 + 85386 85459 chr4 191273063 - 132701421 132701494 16466620
+73
+
+chain 6622 chrUn_gl000220 161802 + 69230 69303 chr7 158821424 + 72850229 72850302 6119994
+73
+
+chain 6240 chrUn_gl000220 161802 + 117008 117283 chr8 146274826 - 75509656 75509931 8997966
+22 197 197
+56
+
+chain 6018 chrUn_gl000220 161802 + 66770 66835 chr7 158821424 + 124008505 124008570 12829512
+65
+
+chain 5720 chrUn_gl000220 161802 + 75185 75250 chr19 63811651 + 15679634 15679699 12473683
+65
+
+chain 4703 chrUn_gl000220 161802 + 23204 23254 chr5 180857866 + 95719433 95719483 34557350
+50
+
+chain 4701 chrUn_gl000220 161802 + 84689 84759 chr7 158821424 - 101943693 101943763 18053161
+10 42 42
+18
+
+chain 4653 chrUn_gl000220 161802 + 75476 75531 chr2 242951149 + 164831342 164831397 18833276
+55
+
+chain 4071 chrUn_gl000220 161802 + 75577 75664 chr7 158821424 + 127724988 127725075 11086017
+87
+
+chain 3907 chrUn_gl000220 161802 + 84699 84740 chr8 146274826 - 59752347 59752388 23243247
+41
+
+chain 3445 chrUn_gl000220 161802 + 84526 84576 chr7 158821424 - 54802302 54802352 16133139
+50
+
+chain 3298 chrUn_gl000220 161802 + 84484 84519 chr4 191273063 + 150269733 150269768 14985224
+35
+
+chain 3145 chrUn_gl000220 161802 + 68319 68372 chr3 199501827 - 131923719 131923772 22478960
+53
+
+chain 2432 chrUn_gl000220 161802 + 68042 68092 chrX 154913754 - 83094892 83094942 21808406
+50
+
+chain 2258 chrUn_gl000220 161802 + 85510 85565 chr1 247249719 - 82513050 82513105 16301029
+55
+
+chain 1955 chrUn_gl000220 161802 + 67950 68004 chr10 135374737 - 36348792 36348846 20124747
+54
+
+chain 1529 chrUn_gl000220 161802 + 84950 85016 chr15 100338915 + 47627030 47627096 15111622
+66
+
+chain 994 chrUn_gl000220 161802 + 68645 68697 chr6 170899992 - 81185693 81185745 23384366
+52
+
+chain 895 chrUn_gl000220 161802 + 75776 75809 chrX 154913754 - 34420755 34420788 14557377
+33
+
+chain 866 chrUn_gl000220 161802 + 65932 65995 chr12 132349534 - 68316854 68316917 13749883
+63
+
+chain 724 chrUn_gl000220 161802 + 83556 83614 chrX 154913754 - 81676829 81676887 19557019
+58
+
+chain 624 chrUn_gl000220 161802 + 83438 83493 chr11 134452384 + 91542956 91543011 19738951
+55
+
+chain 591 chrUn_gl000220 161802 + 84637 84689 chr12 132349534 - 49421504 49421556 13261533
+52
+
+chain 561 chrUn_gl000220 161802 + 84759 84817 chr6_random 1875562 - 1459651 1459709 15884202
+58
+
+chain 14216718 chrUn_gl000221 155397 + 0 155355 chr1 247249719 + 141752984 141907993 211
+623 1 1
+49 1 1
+619 1 1
+34 1 1
+307 1 1
+31 1 1
+1912 1 1
+41 1 1
+994 1 1
+23 1 1
+1203 0 1
+1157 57 60
+181 1 1
+26 1 1
+643 1 2
+61 1 1
+43 1 1
+300 6 6
+241 11 11
+1194 8 8
+173 1 1
+31 1 1
+1099 13 13
+321 0 3
+456 23 24
+402 1 1
+28 1 1
+533 0 3
+476 2 0
+870 1 1
+47 1 1
+1339 4 4
+25 1 1
+474 0 1
+869 34 34
+615 1 1
+18 1 1
+1449 1 1
+47 1 1
+60 11 11
+465 8 8
+54 6 0
+164 11 11
+546 15 15
+172 1 0
+1686 0 1
+987 1 1
+38 1 1
+2146 1 1
+29 1 1
+645 1 1
+19 1 1
+804 10 10
+2676 0 1
+430 1 1
+48 1 1
+1099 1 1
+39 1 1
+127 0 1
+450 0 1
+22 1 1
+1754 1 1
+38 1 1
+152 3 0
+1066 1 1
+41 1 1
+3598 1 1
+17 1 1
+363 4 4
+63 504 9
+154 1 1
+15 1 1
+574 1 1
+43 1 1
+515 1 1
+31 1 1
+99 0 8
+378 1 1
+25 1 1
+477 1 1
+19 1 1
+466 1 1
+70 5 5
+79 1 1
+108 1 1
+210 1 1
+156 1 1
+265 7 7
+64 1 1
+98 1 1
+114 1 1
+39 1 1
+363 5 5
+28 1 1
+2637 1 1
+35 1 1
+702 1 1
+15 1 1
+122 30 30
+60 20 19
+194 1 1
+44 1 1
+1196 4 3
+141 1 1
+49 1 1
+274 2 0
+235 3 0
+152 9 9
+258 1 1
+34 1 0
+45 1 1
+370 1 1
+27 1 1
+235 10 0
+378 1 1
+17 1 0
+4 7 4
+437 15 16
+291 12 12
+101 1 1
+29 0 1
+219 0 1
+90 0 1
+164 1 1
+35 1 0
+916 1 1
+44 1 1
+54 29 25
+111 1 1
+31 1 1
+199 2 0
+360 2 0
+533 7 7
+281 14 14
+1751 1 1
+16 1 1
+136 1 0
+513 1 0
+216 2 0
+694 1 1
+30 1 1
+136 1 1
+34 1 1
+640 1 0
+17 1 0
+910 5 5
+36 4 4
+1047 1 1
+91 1 1
+1268 1 1
+49 4 4
+2141 1 1
+78 1 1
+309 1 1
+19 1 1
+116 1 1
+51 1 1
+282 4 4
+626 14 14
+2635 2 2
+37 1 1
+1324 1 1
+111 1 1
+332 1 1
+40 1 1
+1585 0 1
+1044 0 1
+456 1 1
+56 1 1
+733 0 37
+398 1 1
+24 1 1
+941 0 1
+533 1 1
+46 1 1
+425 1 1
+29 1 1
+209 1 1
+656 14 14
+2193 0 1
+340 0 1
+1318 1 1
+29 1 1
+734 13 0
+736 2 0
+395 0 1
+543 1 0
+449 2 0
+2005 1 1
+29 1 1
+748 0 1
+1298 1 1
+18 1 1
+1823 1 1
+26 1 1
+735 16 16
+1067 1 1
+20 1 1
+205 1 1
+36 1 1
+1358 0 1
+938 1 1
+87 1 1
+1100 1 1
+30 1 0
+2470 0 16
+317 10 0
+1289 5 5
+78 1 1
+1424 0 2
+656 2 2
+32 2 1
+223 0 1
+71 1 1
+289 1 0
+15 1 1
+104 1 1
+147 0 2
+15 1 1
+187 1 1
+50 1 1
+56 1 1
+31 3 3
+103 1 1
+130 1 1
+58 10 76
+99 3 3
+352 1 1
+72 1 1
+49 1 1
+105 1 1
+71 2 2
+120 1 1
+152 1 1
+87 15 84
+27 1 0
+5 1 1
+779 1 1
+42 1 1
+351 1 1
+45 1 1
+74 1 1
+46 1 1
+583 9 9
+3745 27 27
+500 0 2
+56 8 0
+105 4 4
+54 3 3
+39 1 1
+111 5 5
+2408 0 3
+1986 0 1
+4003 1 1
+38 1 1
+2084 1 1
+88 1 1
+1007 10 0
+1048 0 1
+180 6 6
+1628 0 1
+1953 1 0
+1428 1 1
+44 1 1
+475 11 11
+551 0 3
+702 2 1
+137 0 6
+829 6 6
+1463 1 1
+30 1 1
+155 1 1
+23 1 1
+1026 7 7
+987 1 1
+48 1 1
+94 1 1
+45 1 1
+706 1 1
+28 1 1
+1055 1 1
+26 1 1
+71 1 1
+53 1 1
+2245 1 1
+22 1 1
+328 1 1
+16 1 1
+1264 1 1
+33 1 1
+247 0 1
+2369 11 11
+105 11 11
+665 0 1
+27 1 1
+379 4 0
+1936 4 3
+441 1 1
+28 1 1
+736 0 5
+248 1 1
+55 1 1
+853 1 0
+415 1 1
+63 2 0
+7 1 2
+49 1 1
+324 1 1
+25 1 1
+2107 0 4
+431 9 9
+204 1 1
+25 1 1
+93 1 1
+46 1 1
+425 1 0
+321 12 12
+266
+
+chain 55879 chrUn_gl000221 155397 + 39022 155397 chr21_random 1679693 - 1044434 1160777 269
+504 7942 7889
+30 63609 63627
+27 44221 44224
+42
+
+chain 7421 chrUn_gl000221 155397 + 7003 17005 chr1 247249719 + 142211716 142221729 942
+52 9916 9927
+34
+
+chain 17470138 chrUn_gl000222 186861 + 0 186861 chr3 199501827 - 123616420 123803195 161
+1250 0 4
+3271 1 1
+48 1 1
+748 1 1
+29 1 1
+336 0 1
+397 14 15
+315 1 1
+47 1 1
+76 1 1
+49 1 1
+1417 5 0
+399 2 1
+112 1 1
+20 1 1
+667 0 3
+1357 1 1
+24 1 1
+409 1 0
+9 1 1
+173 0 1
+36 1 1
+1372 1 0
+369 9 10
+484 0 4
+411 21 25
+242 1 0
+833 14 14
+895 0 9
+1067 0 3
+87 1 1
+33 1 1
+52 1 1
+35 1 1
+564 3 2
+80 9 9
+77 3 0
+126 120 0
+626 1 1
+84 0 5
+30 1 1
+337 0 8
+384 1 1
+30 0 1
+153 0 1
+16 1 1
+52 6 0
+185 1 2
+111 4 4
+54 1 1
+29 1 1
+479 1 0
+23 1 1
+1089 1 1
+21 1 1
+194 1 1
+20 1 0
+1217 0 1
+728 1 0
+497 120 0
+130 1 1
+45 1 1
+364 0 3
+2459 4 4
+883 5 4
+785 14 14
+1180 5 0
+420 1 1
+39 0 4
+13 1 1
+60 16 16
+592 11 14
+246 0 1
+520 1 1
+19 1 1
+843 1 1
+33 1 1
+462 0 9
+24 1 1
+661 3 0
+22 1 1
+1102 6 6
+2016 1 0
+106 1 1
+40 0 1
+2177 1 1
+39 1 1
+806 0 4
+412 1 0
+317 0 2
+775 0 4
+289 1 1
+22 1 1
+920 1 1
+72 0 5
+58 1 1
+345 1 1
+22 1 1
+302 2 2
+84 1 1
+210 8 8
+98 3 1
+673 1 1
+33 1 1
+299 4 0
+1477 4 4
+475 1 1
+46 1 1
+369 13 13
+60 1 1
+37 1 1
+260 1 0
+274 6 0
+1598 1 1
+28 1 1
+2138 16 16
+793 1 0
+142 1 1
+18 1 0
+1920 0 1
+164 6 0
+859 1 1
+49 1 0
+333 2 0
+1437 1 1
+32 1 1
+243 4 5
+719 0 1
+39 1 1
+861 1 1
+41 1 1
+812 1 1
+46 9 8
+145 1 1
+50 1 1
+552 2 2
+27 0 3
+477 1 1
+41 1 1
+307 1 1
+67 1 1
+283 1 1
+27 1 1
+151 0 1
+21 1 1
+128 1 0
+42 1 1
+415 0 110
+781 2 2
+44 1 1
+176 2 2
+21 1 1
+181 4 0
+440 47 47
+326 1 1
+27 1 1
+228 1 1
+36 1 1
+138 12 12
+3038 11 11
+3781 0 1
+1856 0 58
+1813 1 0
+3776 21 0
+1096 8 0
+9578 0 4
+924 0 1
+662 1 0
+942 1 0
+1709 8 8
+167 1 0
+6850 0 6
+58 1 1
+5315 1 1
+22 1 1
+2377 1 0
+3702 1 1
+17 1 1
+1405 1 0
+38 3 0
+10654 0 1
+35 1 1
+3464 0 1
+424 12 12
+6848 13 13
+444 0 5
+1121 0 10
+3015 11 10
+5936 1 1
+45 1 1
+134 1 1
+33 1 1
+913 1 1
+33 1 1
+7377 1 1
+26 1 1
+2213 3 0
+1310 19 16
+1028 1 1
+30 1 1
+1346 0 1
+3453 23 23
+2511 0 2
+2170 1 0
+5294 16 17
+1031 0 1
+5779 30 0
+4540
+
+chain 4695 chrUn_gl000222 186861 + 24563 24635 chr3 199501827 - 123640889 123640961 14387967
+72
+
+chain 1361 chrUn_gl000222 186861 + 182291 182321 chr3 199501827 - 123798570 123798600 19416990
+30
+
+chain 17090000 chrUn_gl000223 180455 + 8 180455 chr12 132349534 - 156807 337156 167
+1699 1 0
+921 0 1
+476 0 3
+2781 5 0
+2337 0 4
+2044 1 1
+52 1 1
+99 4 0
+3342 10 10
+76207 0 1
+61652 112 0
+5333 2 15
+2060 0 1
+6964 2 2
+29 1 1
+4046 1 1
+74 0 2
+1140 1 1
+45 1 0
+610 2 0
+5062 1 0
+917 0 3
+2412
+
+chain 149624 chrUn_gl000224 179693 + 16452 19204 chr21_random 1679693 - 927993 930745 862809
+59 44 44
+122 26 26
+66 78 78
+132 53 53
+52 89 89
+402 80 80
+70 427 427
+293 109 109
+159 56 56
+159 73 73
+203
+
+chain 136876 chrUn_gl000224 179693 + 10143 12844 chr21_random 1679693 - 927993 930694 942020
+59 44 44
+122 243 243
+59 53 53
+52 89 89
+402 291 291
+56 138 138
+69 23 23
+293 109 109
+159 56 56
+159 73 73
+152
+
+chain 125386 chrUn_gl000224 179693 + 4608 7033 chr4 191273063 - 142060444 142063015 1025800
+181 62 62
+67 290 436
+77 128 128
+226 170 170
+58 50 50
+165 20 20
+83 29 29
+137 31 31
+189 59 59
+173 72 72
+64 43 43
+51
+
+chain 115319 chrUn_gl000224 179693 + 12844 15391 chr1 247249719 - 105124090 105126655 1054758
+4 101 101
+115 120 120
+83 6 6
+88 7 7
+90 138 143
+213 56 56
+54 27 27
+110 76 76
+135 22 22
+85 408 408
+51 98 112
+51 71 70
+151 97 97
+90
+
+chain 114018 chrUn_gl000224 179693 + 0 2892 chr4 191273063 - 142260101 142263001 1123540
+55 9 9
+211 93 93
+53 8 8
+62 480 490
+69 30 30
+169 1 0
+59 374 374
+170 104 104
+66 127 127
+67 134 134
+53 28 28
+127 117 117
+109 4 4
+55 1 0
+57
+
+chain 36836 chrUn_gl000224 179693 + 6824 7667 chr1 247249719 - 105124398 105125248 1790194
+51 165 165
+90 136 143
+213 56 56
+54 27 27
+51
+
+chain 33992 chrUn_gl000224 179693 + 112940 113352 chrX 154913754 - 88823320 88823732 3977820
+120 1 1
+31 1 1
+187 19 19
+53
+
+chain 18992 chrUn_gl000224 179693 + 17725 19327 chr4 191273063 - 142245973 142247284 981259
+45 153 153
+54 736 445
+17 9 9
+9 181 181
+60 269 269
+69
+
+chain 18703 chrUn_gl000224 179693 + 36684 37079 chr4 191273063 - 141982606 141983001 11515138
+60 182 182
+153
+
+chain 18089 chrUn_gl000224 179693 + 111527 111723 chr9 140273252 - 128738409 128738605 12039465
+196
+
+chain 15842 chrUn_gl000224 179693 + 43681 43852 chr5 180857866 + 121997129 121997300 14188216
+171
+
+chain 14214 chrUn_gl000224 179693 + 491 737 chr4 191273063 - 142062769 142063015 3040816
+16 72 72
+64 43 43
+51
+
+chain 12738 chrUn_gl000224 179693 + 10425 11345 chr1 247249719 + 142120275 142121196 1008989
+81 89 89
+16 667 668
+67
+
+chain 12408 chrUn_gl000224 179693 + 111770 111902 chr13 114142980 + 92814175 92814307 18368674
+132
+
+chain 11212 chrUn_gl000224 179693 + 19478 19617 chr21_random 1679693 + 1399634 1399773 20347362
+79 8 8
+52
+
+chain 11202 chrUn_gl000224 179693 + 112010 112131 chr2 242951149 - 63390730 63390851 20364580
+121
+
+chain 10961 chrUn_gl000224 179693 + 113403 113519 chr15 100338915 + 33416357 33416473 20796127
+116
+
+chain 10599 chrUn_gl000224 179693 + 45499 45614 chr4 191273063 - 16476018 16476133 21505928
+115
+
+chain 10461 chrUn_gl000224 179693 + 5286 5406 chr4 191273063 - 142252631 142253042 21797237
+48 0 291
+72
+
+chain 9625 chrUn_gl000224 179693 + 45086 45377 chr7 158821424 + 147179139 147179431 23689916
+56 173 174
+62
+
+chain 8966 chrUn_gl000224 179693 + 43852 44339 chr6 170899992 - 123605243 123606037 22200679
+5 424 731
+58
+
+chain 8686 chrUn_gl000224 179693 + 150637 150728 chr17_random 2617613 - 2481086 2481177 25413154
+91
+
+chain 8418 chrUn_gl000224 179693 + 113901 114092 chr1 247249719 + 51102379 51102577 12937085
+62 97 104
+32
+
+chain 7836 chrUn_gl000224 179693 + 113729 114060 chr15 100338915 + 29700006 29700343 12648008
+52 182 188
+97
+
+chain 7180 chrUn_gl000224 179693 + 111450 111527 chr20 62435964 + 7228195 7228272 16795381
+77
+
+chain 6302 chrUn_gl000224 179693 + 16769 18129 chr1 247249719 + 142120310 142121524 963429
+46 1235 1089
+79
+
+chain 6103 chrUn_gl000224 179693 + 42952 43016 chr3 199501827 - 123620077 123620141 30294157
+64
+
+chain 5895 chrUn_gl000224 179693 + 2013 2591 chr1 247249719 - 105125890 105126468 2699632
+97 439 439
+42
+
+chain 5875 chrUn_gl000224 179693 + 112823 112897 chr5 180857866 + 101476275 101476349 19139195
+74
+
+chain 5761 chrUn_gl000224 179693 + 112501 112575 chr5 180857866 - 18785409 18785483 18767594
+74
+
+chain 5594 chrUn_gl000224 179693 + 14410 14469 chr2 242951149 + 132757818 132757877 31664825
+59
+
+chain 5426 chrUn_gl000224 179693 + 112319 112377 chrX 154913754 + 51601613 51601671 20663092
+58
+
+chain 5157 chrUn_gl000224 179693 + 36781 36835 chr3 199501827 - 123619604 123619658 33003364
+54
+
+chain 4848 chrUn_gl000224 179693 + 38244 38295 chr17_random 2617613 - 2478551 2478602 33999646
+51
+
+chain 4029 chrUn_gl000224 179693 + 112591 112679 chr5 180857866 + 175637665 175637753 5293308
+88
+
+chain 3738 chrUn_gl000224 179693 + 13809 15505 chr21_random 1679693 + 746889 748597 1305848
+56 1588 1600
+52
+
+chain 3444 chrUn_gl000224 179693 + 17845 17922 chr4 191273063 - 142061190 142061267 1001031
+77
+
+chain 2897 chrUn_gl000224 179693 + 17977 18049 chr4 191273063 - 142253123 142253195 6314050
+72
+
+chain 2788 chrUn_gl000224 179693 + 7479 7535 chr21_random 1679693 + 746889 746945 1938894
+56
+
+chain 2567 chrUn_gl000224 179693 + 112204 112294 chr11 134452384 - 41661604 41661694 17596092
+90
+
+chain 2514 chrUn_gl000224 179693 + 112910 112940 chr7 158821424 - 149074801 149074831 4457011
+30
+
+chain 2362 chrUn_gl000224 179693 + 112294 112319 chr6 170899992 + 161846864 161846889 20635445
+25
+
+chain 2067 chrUn_gl000224 179693 + 113791 113854 chr10 135374737 - 12705669 12705732 4536722
+63
+
+chain 2066 chrUn_gl000224 179693 + 12137 18504 chr4 191273063 + 48989335 49001828 975845
+58 6251 12377
+58
+
+chain 1330 chrUn_gl000224 179693 + 113854 113878 chr5 180857866 - 104048317 104048341 15104584
+24
+
+chain 1281 chrUn_gl000224 179693 + 13065 13119 chr2 242951149 + 132762412 132762466 24130660
+54
+
+chain 1137 chrUn_gl000224 179693 + 4993 5088 chr21_random 1679693 - 929171 929266 9927235
+95
+
+chain 848 chrUn_gl000224 179693 + 1580 1641 chr19 63811651 - 14200495 14200556 15170632
+61
+
+chain 531 chrUn_gl000224 179693 + 111324 111398 chrX 154913754 + 45796753 45796827 23841494
+74
+
+chain 30238 chrUn_gl000225 211173 + 3384 6975 chr18 76117153 - 76016439 76019286 4615508
+88 182 182
+34 2463 1785
+83 385 319
+50 111 111
+195
+
+chain 23455 chrUn_gl000225 211173 + 60973 61217 chr12 132349534 - 101518303 101518547 8018503
+244
+
+chain 20111 chrUn_gl000225 211173 + 166962 167202 chrY 57772954 - 350039 350279 10363809
+137 15 15
+88
+
+chain 18512 chrUn_gl000225 211173 + 25429 25744 chrY 57772954 - 45830615 45830930 11677619
+72 105 105
+138
+
+chain 17348 chrUn_gl000225 211173 + 69995 70696 chr18 76117153 + 100273 101110 12705104
+54 377 445
+95 106 174
+69
+
+chain 16827 chrUn_gl000225 211173 + 145466 146389 chr12 132349534 - 82104353 82105276 13209656
+90 95 95
+78 609 609
+51
+
+chain 16532 chrUn_gl000225 211173 + 6975 7480 chrY 57772954 + 11929182 11929688 9693145
+6 195 195
+56 193 194
+55
+
+chain 14751 chrUn_gl000225 211173 + 146689 146847 chr12 132349534 + 39722955 39723113 15337789
+158
+
+chain 14284 chrUn_gl000225 211173 + 109330 111760 chrY 57772954 + 11933408 11933865 15870073
+76 260 260
+66 1973 0
+55
+
+chain 14255 chrUn_gl000225 211173 + 98785 99342 chr18 76117153 + 100216 100772 15900410
+38 387 386
+132
+
+chain 13725 chrUn_gl000225 211173 + 126918 127062 chr18 76117153 + 100627 100771 16530918
+144
+
+chain 13602 chrUn_gl000225 211173 + 147672 147817 chr8 146274826 + 107672556 107672701 16687743
+145
+
+chain 12515 chrUn_gl000225 211173 + 44909 48118 chrY 57772954 + 11932705 11933485 18215669
+61 2725 295
+67 280 281
+76
+
+chain 11840 chrUn_gl000225 211173 + 21194 21753 chrY 57772954 - 366515 367006 19262147
+78 414 346
+67
+
+chain 11658 chrUn_gl000225 211173 + 205576 205759 chr2 242951149 - 95682635 95682818 19568742
+65 47 47
+71
+
+chain 11142 chrUn_gl000225 211173 + 75498 75615 chrY 57772954 - 45851825 45851942 20475254
+117
+
+chain 10869 chrUn_gl000225 211173 + 51801 51915 chr18 76117153 - 76020289 76020403 20977270
+114
+
+chain 10758 chrUn_gl000225 211173 + 209713 209913 chr4 191273063 + 39081959 39082160 21190890
+74 74 75
+52
+
+chain 10616 chrUn_gl000225 211173 + 146389 146556 chr5 180857866 - 159454687 159454854 16369709
+43 58 58
+66
+
+chain 10035 chrUn_gl000225 211173 + 171673 171813 chr8 146274826 - 67038436 67038576 22726539
+51 22 22
+67
+
+chain 9917 chrUn_gl000225 211173 + 144822 145109 chr5 180857866 + 8336803 8337089 22999312
+67 165 164
+55
+
+chain 9896 chrUn_gl000225 211173 + 62060 62164 chr18 76117153 + 100627 100731 23055661
+104
+
+chain 9807 chrUn_gl000225 211173 + 137863 140640 chrY 57772954 - 45826954 45827260 23254439
+47 2048 0
+54 576 153
+52
+
+chain 8932 chrUn_gl000225 211173 + 69636 69730 chrY 57772954 - 45829605 45829699 25046033
+94
+
+chain 8413 chrUn_gl000225 211173 + 85100 85188 chrY 57772954 - 45832076 45832164 25801593
+88
+
+chain 8359 chrUn_gl000225 211173 + 142638 142726 chrY 57772954 + 57394412 57394500 25874101
+88
+
+chain 8122 chrUn_gl000225 211173 + 119411 119496 chr18 76117153 + 100254 100339 26237196
+85
+
+chain 8086 chrUn_gl000225 211173 + 55593 55678 chr18 76117153 - 76016415 76016500 26288572
+85
+
+chain 7431 chrUn_gl000225 211173 + 23911 23989 chrY 57772954 - 45832097 45832175 27364689
+78
+
+chain 7085 chrUn_gl000225 211173 + 97023 98440 chrY 57772954 - 45830811 45832294 28041027
+71 1296 1362
+50
+
+chain 7083 chrUn_gl000225 211173 + 18039 19438 chrY 57772954 - 366566 367008 28041757
+40 1295 338
+64
+
+chain 6978 chrUn_gl000225 211173 + 146217 146291 chr8 146274826 - 115673008 115673082 20162064
+74
+
+chain 6840 chrUn_gl000225 211173 + 144371 144443 chr18 76117153 + 100407 100479 28513456
+72
+
+chain 6667 chrUn_gl000225 211173 + 66486 66556 chrY 57772954 - 45828773 45828843 28907810
+70
+
+chain 6303 chrUn_gl000225 211173 + 137 203 chrY 57772954 - 45847922 45847988 29790939
+66
+
+chain 6276 chrUn_gl000225 211173 + 106597 106663 chr18 76117153 - 76016724 76016790 29833436
+66
+
+chain 6212 chrUn_gl000225 211173 + 69391 69456 chrY 57772954 - 45832092 45832157 30018585
+65
+
+chain 6148 chrUn_gl000225 211173 + 11132 11196 chrY 57772954 + 11939704 11939768 30172463
+64
+
+chain 6094 chrUn_gl000225 211173 + 68190 68254 chrY 57772954 + 57406356 57406420 30311205
+64
+
+chain 6058 chrUn_gl000225 211173 + 127450 127514 chrY 57772954 - 45844945 45845009 30402909
+64
+
+chain 6003 chrUn_gl000225 211173 + 143303 143366 chrY 57772954 + 57402115 57402178 30561429
+63
+
+chain 5903 chrUn_gl000225 211173 + 139264 139326 chrY 57772954 - 45844705 45844767 30818028
+62
+
+chain 5884 chrUn_gl000225 211173 + 104096 104157 chr18 76117153 + 102216 102277 30859822
+61
+
+chain 5803 chrUn_gl000225 211173 + 103301 103362 chr18 76117153 + 99316 99377 31083648
+61
+
+chain 5794 chrUn_gl000225 211173 + 26451 26512 chrY 57772954 - 45851626 45851687 31099284
+61
+
+chain 5721 chrUn_gl000225 211173 + 139049 139109 chrY 57772954 + 57400659 57400719 31317119
+60
+
+chain 5684 chrUn_gl000225 211173 + 146628 146689 chr1 247249719 - 54812307 54812368 16334743
+61
+
+chain 5630 chrUn_gl000225 211173 + 92437 92496 chr18 76117153 + 98445 98504 31574579
+59
+
+chain 5539 chrUn_gl000225 211173 + 140791 140849 chrY 57772954 + 57392905 57392963 31849395
+58
+
+chain 5539 chrUn_gl000225 211173 + 4266 4324 chrY 57772954 + 11928245 11928303 31849396
+58
+
+chain 5521 chrUn_gl000225 211173 + 40432 40490 chrY 57772954 - 370968 371026 31891738
+58
+
+chain 5438 chrUn_gl000225 211173 + 36214 36270 chrY 57772954 + 11930450 11930506 32145366
+56
+
+chain 5339 chrUn_gl000225 211173 + 74478 74534 chrY 57772954 - 45832726 45832782 32420219
+56
+
+chain 5339 chrUn_gl000225 211173 + 28866 28922 chrY 57772954 - 45832726 45832782 32420220
+56
+
+chain 5321 chrUn_gl000225 211173 + 77215 77271 chrY 57772954 - 45830350 45830406 32462996
+56
+
+chain 5248 chrUn_gl000225 211173 + 101556 101611 chrY 57772954 - 45844698 45844753 32703748
+55
+
+chain 5182 chrUn_gl000225 211173 + 145986 146041 chr9 140273252 + 120936021 120936076 15500236
+55
+
+chain 5139 chrUn_gl000225 211173 + 133143 133197 chrY 57772954 - 45844651 45844705 33042666
+54
+
+chain 5074 chrUn_gl000225 211173 + 44289 44341 chr18 76117153 - 76014945 76014997 33275500
+52
+
+chain 5048 chrUn_gl000225 211173 + 121427 121480 chrY 57772954 - 45831892 45831945 33345462
+53
+
+chain 5048 chrUn_gl000225 211173 + 133955 134008 chr18 76117153 + 100319 100372 33345768
+53
+
+chain 4966 chrUn_gl000225 211173 + 41802 41854 chr18 76117153 - 76019839 76019891 33630431
+52
+
+chain 4957 chrUn_gl000225 211173 + 75225 75277 chrY 57772954 + 57406623 57406675 33650989
+52
+
+chain 4953 chrUn_gl000225 211173 + 145598 145651 chr12 132349534 + 53460575 53460628 18762227
+53
+
+chain 4857 chrUn_gl000225 211173 + 102498 102549 chrY 57772954 - 45844483 45844534 33969906
+51
+
+chain 4802 chrUn_gl000225 211173 + 22297 22347 chr18 76117153 - 76019708 76019758 34221217
+50
+
+chain 4766 chrUn_gl000225 211173 + 81781 81831 chrY 57772954 - 45844484 45844534 34318861
+50
+
+chain 4730 chrUn_gl000225 211173 + 116183 116233 chrY 57772954 - 45830882 45830932 34441464
+50
+
+chain 4684 chrUn_gl000225 211173 + 16126 16175 chr18 76117153 - 76016743 76016792 34599346
+49
+
+chain 4593 chrUn_gl000225 211173 + 106022 106070 chrY 57772954 + 11933099 11933147 34665488
+48
+
+chain 4475 chrUn_gl000225 211173 + 6365 6412 chrY 57772954 - 366519 366566 34731069
+47
+
+chain 4436 chrUn_gl000225 211173 + 146291 146338 chr11 134452384 + 56488704 56488751 17449786
+47
+
+chain 3836 chrUn_gl000225 211173 + 145834 145884 chr5 180857866 + 144814068 144814118 22871561
+50
+
+chain 3811 chrUn_gl000225 211173 + 55287 55327 chrY 57772954 + 11933059 11933099 35041388
+40
+
+chain 3584 chrUn_gl000225 211173 + 145220 145258 chrX 154913754 - 118330483 118330521 21778509
+38
+
+chain 3107 chrUn_gl000225 211173 + 145429 145466 chr16 88827254 + 32289765 32289802 21377803
+37
+
+chain 3086 chrUn_gl000225 211173 + 145167 145986 chr10 135374737 + 122669077 122669897 13514114
+53 666 667
+100
+
+chain 2556 chrUn_gl000225 211173 + 117483 117510 chrY 57772954 - 45844918 45844945 35420092
+27
+
+chain 2529 chrUn_gl000225 211173 + 147645 147672 chr9 140273252 + 21053713 21053740 22333825
+27
+
+chain 2173 chrUn_gl000225 211173 + 146432 146455 chrX 154913754 - 151862289 151862312 20635516
+23
+
+chain 1176 chrUn_gl000225 211173 + 24983 25041 chrY 57772954 + 57406385 57406443 21696161
+58
+
+chain 970 chrUn_gl000225 211173 + 65774 66239 chr10 135374737 - 23380 24256 23288653
+57 372 783
+36
+
+chain 296 chrUn_gl000225 211173 + 124568 124644 chr18 76117153 + 100627 100703 23494333
+76
+
+chain 11961323 chrUn_gl000227 128374 + 0 128374 chr6 170899992 + 19668 147274 264
+1643 0 1
+255 1 1
+40 1 0
+61 4 4
+343 1 1
+168 1 1
+211 1 1
+18 1 1
+525 0 4
+549 1 1
+22 1 1
+440 16 16
+122 14 17
+167 4 4
+205 4 0
+98 1 1
+164 8 9
+585 0 1
+1278 1 1
+26 1 1
+2038 1 1
+17 1 1
+1741 15 15
+917 1 1
+26 1 1
+1021 0 1
+1314 77 0
+306 0 1
+109 0 153
+152 79 2
+199 153 0
+146 1 1
+49 1 1
+144 385 0
+4558 1 0
+5544 4 3
+2373 1 1
+40 1 0
+14638 6 0
+5386 0 1
+1491 2 0
+1835 20 20
+1481 0 4
+5348 0 1
+135 0 2
+2128 35 35
+4707 0 1
+1696 0 1
+893 1 1
+47 1 1
+766 1 1
+49 1 1
+542 1 1
+28 2 0
+334 1 1
+31 1 1
+1092 0 1
+803 1 0
+1815 6 0
+25 134 0
+37 79 0
+7668 1 0
+603 1 1
+28 1 1
+1020 0 1
+3033 0 2
+619 7 7
+1434 1 0
+1954 1 0
+9909 1 0
+1155 1 1
+36 1 1
+327 7 7
+133 4 0
+1499 0 2
+96 1 0
+3257 11 0
+46 1 1
+207 1 1
+20 1 1
+2919 18 18
+765 4 4
+1829 0 1
+1864 5 5
+123 15 15
+13751
+
+chain 49410 chrUn_gl000227 128374 + 14106 15875 chr8 146274826 + 86449 88144 529
+45 569 417
+43 288 289
+64 1 1
+12 362 363
+150 18 18
+153 1 77
+63
+
+chain 13413 chrUn_gl000227 128374 + 14996 15149 chr19 63811651 + 91181 91257 491
+55 77 0
+21
+
+chain 5337 chrUn_gl000227 128374 + 73853 73996 chr1 247249719 + 231 416 19004415
+27 66 108
+50
+
+chain 5015 chrUn_gl000227 128374 + 14074 14797 chr1 247249719 - 246873620 246874345 559
+32 658 660
+33
+
+chain 2271 chrUn_gl000227 128374 + 73917 73946 chr15 100338915 - 29 58 23118832
+29
+
+chain 8904085 chrUn_gl000228 129120 + 0 98333 chr4 191273063 + 191152836 191248399 371
+1288 1 1
+65 1 1
+695 1 1
+24 1 0
+6 1 1
+50 0 312
+260 1 1
+46 1 1
+993 1 0
+2168 1 1
+31 1 1
+3958 0 4
+257 0 18
+9 1 1
+267 3 3
+16 1 1
+1441 0 4
+68 0 1
+1387 0 2
+3469 11 11
+3245 1 0
+777 1 1
+25 1 1
+597 2 0
+30 1 1
+1792 1 1
+34 1 1
+543 0 1
+98 1 1
+25 1 1
+1024 8 0
+2103 1 1
+1898 0 12
+71 10 11
+1335 0 2
+7908 172 0
+4213 0 1
+4548 43 43
+334 0 1
+381 3 3
+46 1 1
+1201 1 1
+25 0 2
+1296 0 1
+526 4 0
+459 1 1
+56 1 1
+2023 2 2
+35 1 1
+1479 0 142
+2019 0 1
+370 8 8
+1586 1 0
+337 0 1
+921 2 0
+84 1 1
+22 1 0
+8 1 2
+206 0 4
+799 1 1
+18 0 1
+223 0 1
+295 1 70
+43 0 1
+72 68 0
+41 1 1
+90 4 4
+1051 1 1
+32 1 1
+182 7 7
+225 3 3
+22 1 1
+1660 0 1
+357 8 8
+101 13 13
+198 7 7
+412 1 0
+4 0 1
+19 1 0
+137 6 7
+361 0 2
+1716 1 0
+511 0 1
+91 0 1
+954 3024 0
+365 13 13
+1256 1 1
+74 1 1
+256 1 1
+68 1 1
+671 5 0
+144 4 0
+2140 1 1
+44 4 0
+223 1 1
+23 1 1
+716 5 0
+144 4 0
+2080 109 105
+223 70 70
+671 5 0
+144 4 0
+2140 16 16
+982 16 14
+148 4 0
+1095 66 60
+945 50 50
+996 2 0
+148 4 0
+2080 109 105
+964 5 0
+144 4 0
+2106 50 50
+996 2 0
+148 4 0
+2106 50 50
+242
+
+chain 2215952 chrUn_gl000228 129120 + 46991 129120 chr10 135374737 + 135304834 135360693 463
+43 23181 23046
+6 90 90
+334 6 0
+395 27 27
+494 145 149
+426 19 19
+480 1 11
+131 1 1
+19 4 0
+120 1 1
+35 1 1
+289 8247 8248
+26 0 8
+78 17650 1111
+121 3307 1
+35 1 1
+1001 6 0
+395 1 1
+25 1 1
+494 1 1
+26 0 8
+78 4 0
+35 1 1
+426 1 1
+17 1 1
+480 1 11
+131 1 1
+19 4 0
+120 1 1
+35 1 1
+1001 6 0
+395 1 1
+25 1 1
+494 1 1
+26 0 8
+78 4 0
+35 1 1
+426 1 1
+17 1 1
+474 10 9
+128 1 1
+19 4 0
+120 1 1
+35 1 1
+1001 6 0
+395 1 1
+25 1 1
+376 3306 0
+74 1 1
+83 1 1
+60 1 1
+52 1 1
+55 1 1
+32 1 1
+360 1 1
+88 1 1
+180 27 27
+1282 2251 0
+30 545 0
+105 1 1
+46 136 0
+1176 1 1
+47 18 0
+18 18 0
+55 18 0
+793 1 1
+28 1 1
+581 1 0
+4074 2 1
+2446
+
+chain 254528 chrUn_gl000228 129120 + 88123 111265 chr4 191273063 + 191234920 191248107 1604
+34 10176 3552
+754 2 0
+148 124 120
+1960 109 105
+964 5 0
+144 4 0
+121 8453 5141
+144
+
+chain 164891 chrUn_gl000228 129120 + 101397 114404 chr4 191273063 + 191238264 191247940 1939
+33 9885 6560
+996 2 0
+148 4 0
+1939
+
+chain 40159 chrUn_gl000228 129120 + 70221 91512 chr4 191273063 + 191223665 191244890 1141
+90 735 735
+27 570 570
+69 10105 10070
+70 5225 5207
+66 4225 4212
+26 50 50
+33
+
+chain 6229 chrUn_gl000228 129120 + 38164 38230 chr4 191273063 + 191191215 191191281 15369017
+66
+
+chain 5671 chrUn_gl000228 129120 + 71567 71627 chr4 191273063 + 191228308 191228368 1250
+60
+
+chain 3930 chrUn_gl000228 129120 + 118712 119504 chr18 76117153 - 76020078 76020393 13741639
+85 601 124
+106
+
+chain 1375 chrUn_gl000228 129120 + 91429 91463 chr4 191273063 + 191234920 191234954 1972
+34
+
+chain 1278 chrUn_gl000228 129120 + 101321 101347 chr4 191273063 + 191244781 191244807 2333
+26
+
+chain 1170 chrUn_gl000228 129120 + 94735 94769 chr4 191273063 + 191234920 191234954 2163
+34
+
+chain 1124 chrUn_gl000228 129120 + 98041 98075 chr4 191273063 + 191234920 191234954 26578
+34
+
+chain 919 chrUn_gl000228 129120 + 101347 101381 chr4 191273063 + 191234920 191234954 6339
+34
+
+chain 827 chrUn_gl000228 129120 + 111265 111299 chr4 191273063 + 191234920 191234954 87434
+34
+
+chain 12702 chrUn_gl000229 19913 + 412 548 chrX 154913754 - 39233529 39233665 17935142
+136
+
+chain 5098 chrUn_gl000229 19913 + 301 375 chr7 158821424 - 9920014 9920088 18279747
+74
+
+chain 15401 chrUn_gl000230 43691 + 29842 30067 chr20 62435964 - 41024366 41024591 14643913
+125 46 46
+54
+
+chain 12153 chrUn_gl000230 43691 + 28959 29088 chr10 135374737 - 34208037 34208166 18757529
+129
+
+chain 12020 chrUn_gl000230 43691 + 8092 8221 chrX 154913754 - 124835983 124836112 18957002
+129
+
+chain 10060 chrUn_gl000230 43691 + 30261 30455 chr3 199501827 - 88301345 88301539 22679433
+66 74 74
+54
+
+chain 7157 chrUn_gl000230 43691 + 30067 30154 chr2 242951149 + 86047836 86047923 19665405
+3 7 7
+77
+
+chain 24015 chrUn_gl000231 27386 + 4654 6337 chr5 180857866 + 70288528 70290201 7680780
+118 1377 1367
+188
+
+chain 18946 chrUn_gl000231 27386 + 6337 7360 chr5 180857866 - 104048753 104049775 8708063
+12 704 704
+72 144 143
+91
+
+chain 16625 chrUn_gl000231 27386 + 2163 2336 chr10 135374737 - 36902825 36902998 13411217
+173
+
+chain 16014 chrUn_gl000231 27386 + 5036 5206 chrX 154913754 + 20633055 20633225 14022851
+170
+
+chain 12702 chrUn_gl000231 27386 + 25798 25934 chrX 154913754 - 39233529 39233665 17935131
+136
+
+chain 12391 chrUn_gl000231 27386 + 23126 23294 chr11 134452384 + 50262817 50262985 18392381
+50 25 25
+93
+
+chain 12273 chrUn_gl000231 27386 + 3627 3759 chr1 247249719 - 155709229 155709361 18571004
+132
+
+chain 11334 chrUn_gl000231 27386 + 4172 4292 chr9 140273252 + 21364524 21364644 20124920
+120
+
+chain 10621 chrUn_gl000231 27386 + 8382 8524 chr4 191273063 + 136252211 136252355 21465956
+54 20 22
+68
+
+chain 10028 chrUn_gl000231 27386 + 22560 22688 chr10 135374737 + 99449647 99449775 22748041
+55 11 11
+62
+
+chain 9550 chrUn_gl000231 27386 + 3054 3241 chr11 134452384 + 46467217 46467406 23880867
+57 73 75
+57
+
+chain 9277 chrUn_gl000231 27386 + 7360 7468 chr2 242951149 - 156204992 156205100 12158462
+56 1 1
+51
+
+chain 8841 chrUn_gl000231 27386 + 25683 25776 chr5 180857866 - 144622856 144622949 25181714
+93
+
+chain 6713 chrUn_gl000231 27386 + 4772 4844 chr5 180857866 + 161861178 161861250 12370362
+72
+
+chain 5312 chrUn_gl000231 27386 + 6933 6989 chr2 242951149 + 51579869 51579925 20211932
+56
+
+chain 5053 chrUn_gl000231 27386 + 6349 6408 chr3 199501827 + 110713055 110713114 8874439
+59
+
+chain 3623 chrUn_gl000231 27386 + 5878 5917 chr8 146274826 - 130943147 130943186 24063221
+39
+
+chain 3087 chrUn_gl000231 27386 + 4499 4564 chr5 180857866 - 151976801 151976866 22766591
+65
+
+chain 2462 chrUn_gl000231 27386 + 23294 23322 chr5 180857866 - 140993746 140993774 21430514
+28
+
+chain 2380 chrUn_gl000231 27386 + 6863 7736 chrX 154913754 + 74323412 74324284 13413701
+70 748 747
+55
+
+chain 1938 chrUn_gl000231 27386 + 6415 7249 chr11 134452384 - 85742217 85743051 12694925
+59 715 715
+60
+
+chain 1209 chrUn_gl000231 27386 + 5917 6017 chr14 106368585 - 47277371 47277471 12257740
+100
+
+chain 575 chrUn_gl000231 27386 + 5818 5878 chr10 135374737 + 22451146 22451206 15305599
+60
+
+chain 354 chrUn_gl000231 27386 + 8607 8658 chr12 132349534 + 50248139 50248190 23666106
+51
+
+chain 55981 chrUn_gl000232 40652 + 2672 3286 chr1 247249719 + 29558771 29559386 2254424
+370 0 4
+68 3 0
+173
+
+chain 30625 chrUn_gl000232 40652 + 2331 2672 chrY 57772954 - 44046862 44047204 2487561
+217 1 1
+106 0 1
+17
+
+chain 14972 chrUn_gl000232 40652 + 34329 34487 chrX 154913754 + 113699598 113699756 15100139
+158
+
+chain 13390 chrUn_gl000232 40652 + 34068 34210 chr20 62435964 + 22916565 22916707 16960157
+142
+
+chain 12645 chrUn_gl000232 40652 + 33771 33906 chr14 106368585 - 63812125 63812260 18020773
+135
+
+chain 10324 chrUn_gl000232 40652 + 33919 34028 chr6 170899992 - 74634926 74635035 22085896
+109
+
+chain 3584 chrUn_gl000232 40652 + 34210 34248 chrX 154913754 - 70416101 70416139 23473516
+38
+
+chain 52638 chrUn_gl000233 45941 + 802 3019 chr12 132349534 + 50244492 50249723 2405861
+98 46 46
+53 1005 4019
+127 111 110
+54 26 26
+50 78 79
+98 98 98
+201 114 114
+58
+
+chain 27263 chrUn_gl000233 45941 + 999 1823 chr10 135374737 - 12704868 12705692 5123253
+41 437 437
+167 94 94
+85
+
+chain 26029 chrUn_gl000233 45941 + 396 699 chr5 180857866 - 24413022 24413325 6500883
+125 1 1
+95 4 4
+78
+
+chain 17811 chrUn_gl000233 45941 + 38826 39439 chr5 180857866 + 131253656 131254277 12283916
+54 333 341
+69 57 57
+100
+
+chain 13316 chrUn_gl000233 45941 + 3397 4215 chr1 247249719 + 164486340 164487158 3912391
+74 253 253
+51 378 378
+62
+
+chain 12153 chrUn_gl000233 45941 + 40193 40322 chr10 135374737 + 101166571 101166700 18757528
+129
+
+chain 10603 chrUn_gl000233 45941 + 723 943 chrX 154913754 - 28357792 28358012 5819450
+79 98 98
+4 1 1
+38
+
+chain 10115 chrUn_gl000233 45941 + 229 336 chr16 88827254 - 77406522 77406629 22552939
+107
+
+chain 10011 chrUn_gl000233 45941 + 39757 39898 chr3 199501827 - 59132119 59132260 22787689
+54 23 23
+64
+
+chain 9607 chrUn_gl000233 45941 + 40007 40142 chr6 170899992 + 77925734 77925869 23736932
+53 22 22
+60
+
+chain 8580 chrUn_gl000233 45941 + 2847 2960 chr3 199501827 + 21585914 21586027 3712717
+12 37 37
+64
+
+chain 8195 chrUn_gl000233 45941 + 1041 1127 chr2 242951149 - 119093538 119093624 26123131
+86
+
+chain 7332 chrUn_gl000233 45941 + 23927 24005 chr21_random 1679693 + 1414162 1414240 27537185
+78
+
+chain 7075 chrUn_gl000233 45941 + 39127 39213 chr2 242951149 - 156903226 156903312 19665406
+77 7 7
+2
+
+chain 6404 chrUn_gl000233 45941 + 24027 24095 chrY 57772954 - 45969314 45969382 29536962
+68
+
+chain 5994 chrUn_gl000233 45941 + 27720 27783 chr21_random 1679693 + 736671 736734 30572390
+63
+
+chain 5521 chrUn_gl000233 45941 + 35462 35520 chr1 247249719 + 141994539 141994597 31891728
+58
+
+chain 5421 chrUn_gl000233 45941 + 28860 28917 chrY 57772954 - 45972382 45972439 32185620
+57
+
+chain 5057 chrUn_gl000233 45941 + 42227 42280 chr21_random 1679693 + 1416441 1416494 33306944
+53
+
+chain 4977 chrUn_gl000233 45941 + 1660 1713 chr4 191273063 + 44000159 44000212 13885847
+53
+
+chain 4794 chrUn_gl000233 45941 + 1831 1882 chr3 199501827 + 28976359 28976410 34225448
+51
+
+chain 4402 chrUn_gl000233 45941 + 1908 1964 chr13 114142980 + 80218714 80218770 15308796
+56
+
+chain 2915 chrUn_gl000233 45941 + 2179 2231 chrX 154913754 - 85677566 85677618 5760053
+52
+
+chain 2427 chrUn_gl000233 45941 + 2296 2322 chr19 63811651 + 22356620 22356646 20880110
+26
+
+chain 2315 chrUn_gl000233 45941 + 3684 3890 chr3 199501827 - 103452931 103453137 5210342
+40 106 106
+60
+
+chain 2208 chrUn_gl000233 45941 + 2131 2646 chr1 247249719 - 90778455 90778971 3568552
+48 399 400
+51 14 14
+3
+
+chain 1953 chrUn_gl000233 45941 + 38960 39031 chr5 180857866 - 170798397 170798468 22477108
+71
+
+chain 1946 chrUn_gl000233 45941 + 39721 39757 chr4 191273063 + 150118550 150118586 24103400
+36
+
+chain 1711 chrUn_gl000233 45941 + 39314 39339 chr20 62435964 + 21411473 21411498 14643912
+25
+
+chain 1675 chrUn_gl000233 45941 + 40142 40172 chr2 242951149 + 189896983 189897013 24596006
+30
+
+chain 1565 chrUn_gl000233 45941 + 363 396 chr12 132349534 + 84953855 84953888 22905876
+33
+
+chain 1086 chrUn_gl000233 45941 + 38662 38716 chr5 180857866 - 112830741 112830795 14413069
+54
+
+chain 921 chrUn_gl000233 45941 + 38880 38926 chr2 242951149 - 186445721 186445767 19984811
+46
+
+chain 665 chrUn_gl000233 45941 + 38435 38508 chr7 158821424 - 45635266 45635339 24997339
+73
+
+chain 567 chrUn_gl000233 45941 + 4533 4589 chr4 191273063 - 120708136 120708192 24665208
+56
+
+chain 30885 chrUn_gl000234 40531 + 20770 21098 chrX 154913754 - 26469860 26470188 4479555
+328
+
+chain 18772 chrUn_gl000234 40531 + 29542 30847 chr2 242951149 + 66700377 66701693 11461281
+64 220 219
+130 836 848
+55
+
+chain 13381 chrUn_gl000234 40531 + 28891 29033 chr18 76117153 - 28506207 28506349 16971585
+142
+
+chain 13011 chrUn_gl000234 40531 + 32848 33004 chr21 46944323 - 3527568 3527724 17471551
+76 8 8
+72
+
+chain 12758 chrUn_gl000234 40531 + 27971 28107 chr9 140273252 + 40275857 40275993 17847477
+136
+
+chain 12298 chrUn_gl000234 40531 + 28202 28332 chr17 78774742 - 28650231 28650361 18533743
+130
+
+chain 9791 chrUn_gl000234 40531 + 31998 32458 chr4 191273063 + 52500251 52500712 23294807
+66 336 337
+58
+
+chain 9445 chrUn_gl000234 40531 + 21230 21331 chr5 180857866 + 160948764 160948865 16866863
+101
+
+chain 9406 chrUn_gl000234 40531 + 8297 8397 chr11 134452384 + 7899462 7899562 24219742
+100
+
+chain 6549 chrUn_gl000234 40531 + 28360 28429 chr3 199501827 - 77716231 77716300 29160148
+69
+
+chain 6432 chrUn_gl000234 40531 + 29956 30025 chr9 140273252 - 130605711 130605780 11645810
+69
+
+chain 5827 chrUn_gl000234 40531 + 29314 29391 chr4 191273063 + 65542826 65542903 22318479
+51 16 16
+10
+
+chain 5276 chrUn_gl000234 40531 + 28653 28709 chr11 134452384 + 42875218 42875274 32641801
+56
+
+chain 4982 chrUn_gl000234 40531 + 30259 30327 chr14 106368585 + 25312855 25312923 19084936
+68
+
+chain 4894 chrUn_gl000234 40531 + 31773 31825 chr12 132349534 + 50249715 50249767 33891551
+52
+
+chain 4820 chrUn_gl000234 40531 + 29245 29296 chr14 106368585 - 60597784 60597835 15880947
+51
+
+chain 4045 chrUn_gl000234 40531 + 29485 29542 chr4 191273063 + 52727852 52727909 20475295
+29 27 27
+1
+
+chain 4004 chrUn_gl000234 40531 + 32772 32822 chr11 134452384 + 25701880 25701930 20350535
+50
+
+chain 3827 chrUn_gl000234 40531 + 28796 28856 chr4 191273063 - 132749043 132749103 24150596
+60
+
+chain 3767 chrUn_gl000234 40531 + 29621 29672 chr4 191273063 + 109408128 109408179 23756830
+51
+
+chain 3326 chrUn_gl000234 40531 + 28132 28194 chr11 134452384 - 79489503 79489565 19687374
+62
+
+chain 3219 chrUn_gl000234 40531 + 21331 21396 chr1 247249719 + 86010808 86010873 5256643
+65
+
+chain 3215 chrUn_gl000234 40531 + 29391 30409 chr8 146274826 + 121721424 121722437 11517523
+94 843 838
+81
+
+chain 2086 chrUn_gl000234 40531 + 20746 20770 chr3 199501827 + 2077213 2077237 10890452
+24
+
+chain 1294 chrUn_gl000234 40531 + 30170 30235 chr5 180857866 + 175635483 175635548 13040504
+65
+
+chain 1179 chrUn_gl000234 40531 + 29160 29245 chr12 132349534 - 94862097 94862182 15299249
+85
+
+chain 30892 chrUn_gl000235 34474 + 10284 10636 chrX 154913754 - 137753964 137754316 4478171
+63 1 1
+187 1 1
+100
+
+chain 28245 chrUn_gl000235 34474 + 6990 7286 chr1 247249719 - 201110718 201111014 5523327
+296
+
+chain 15633 chrUn_gl000235 34474 + 10772 10939 chrX 154913754 + 111228690 111228857 14403755
+167
+
+chain 15123 chrUn_gl000235 34474 + 11327 11488 chr2 242951149 - 221981770 221981931 14935235
+161
+
+chain 15020 chrUn_gl000235 34474 + 8981 9146 chrX 154913754 + 150122103 150122269 15041806
+50 0 1
+115
+
+chain 14740 chrUn_gl000235 34474 + 10108 10284 chr1 247249719 - 105280685 105280865 6177884
+93 11 15
+68 3 3
+1
+
+chain 14088 chrUn_gl000235 34474 + 24168 24356 chrX 154913754 + 151092975 151093164 16094556
+70 28 29
+90
+
+chain 13398 chrUn_gl000235 34474 + 8127 8288 chr19 63811651 + 57248305 57248465 16951668
+53 1 0
+22 4 4
+81
+
+chain 11780 chrUn_gl000235 34474 + 9511 9636 chr4 191273063 - 168773683 168773808 19365753
+125
+
+chain 11069 chrUn_gl000235 34474 + 356 472 chrY 57772954 - 45847823 45847939 20603157
+116
+
+chain 10033 chrUn_gl000235 34474 + 11631 11737 chr1 247249719 + 193278857 193278963 22733668
+106
+
+chain 9778 chrUn_gl000235 34474 + 9888 9991 chr12 132349534 - 43209673 43209776 23326812
+103
+
+chain 8409 chrUn_gl000235 34474 + 11238 11327 chr2 242951149 - 175961361 175961450 14938980
+89
+
+chain 7852 chrUn_gl000235 34474 + 10013 10108 chr6 170899992 - 132065708 132065803 19855689
+76 7 7
+12
+
+chain 6783 chrUn_gl000235 34474 + 11488 11562 chr6 170899992 - 86591617 86591691 15132212
+74
+
+chain 5385 chrUn_gl000235 34474 + 11562 11620 chr5 180857866 + 115696160 115696218 18047359
+58
+
+chain 2922 chrUn_gl000235 34474 + 11207 11238 chrX 154913754 - 92875478 92875509 23049192
+31
+
+chain 2825 chrUn_gl000235 34474 + 10636 10670 chr12 132349534 - 101871456 101871490 12092770
+34
+
+chain 2162 chrUn_gl000235 34474 + 6967 6990 chr2 242951149 - 129587776 129587799 9249038
+23
+
+chain 1547 chrUn_gl000235 34474 + 7820 7881 chr12 132349534 + 82509454 82509515 19217212
+61
+
+chain 923 chrUn_gl000235 34474 + 7388 7458 chr11 134452384 + 54653442 54653512 19210883
+70
+
+chain 719 chrUn_gl000235 34474 + 8037 8087 chr5 180857866 - 7479901 7479951 22691815
+50
+
+chain 508 chrUn_gl000235 34474 + 9360 9418 chr10 135374737 + 96904139 96904197 25463139
+58
+
+chain 3900762 chrUn_gl000236 41934 + 0 41934 chr22 49691432 + 15341912 15383621 761
+910 1 1
+44 1 1
+601 16 16
+51 24 24
+382 118 108
+316 0 158
+302 1 1
+33 1 1
+1588 1 1
+18 1 1
+15101 0 1
+1338 0 39
+4044 417 7
+5600 2 0
+8329 1 0
+2693
+
+chain 39503 chrUn_gl000236 41934 + 24892 25309 chr22 49691432 + 15365763 15366180 3274701
+417
+
+chain 2040494 chrUn_gl000237 45867 + 12002 45867 chr21 46944323 + 10130092 10164119 1248
+88 1 1
+65 1 1
+74 5 15
+34 1 1
+139 1 1
+26 0 1
+241 1 1
+50 0 1
+91 1 1
+194 1 1
+29 1 1
+59 13 13
+54 1 1
+75 1 1
+89 1 1
+230 1 1
+59 3 3
+74 1 1
+199 1 1
+54 1 1
+488 1 16
+78 1 1
+75 1 1
+151 1 1
+93 1 1
+323 18 18
+327 1 1
+52 1 1
+853 1 1
+54 1 1
+409 1 1
+16 1 1
+42 0 1
+336 1 1
+61 1 1
+326 12 12
+295 1 0
+10 1 1
+201 3 1
+316 1 1
+15 1 1
+121 11 11
+574 1 1
+36 0 1
+40 1 1
+80 9 6
+383 4 0
+81 17 17
+172 0 4
+104 2 0
+542 1 0
+249 1 1
+48 1 1
+357 0 20
+81 0 4
+218 0 4
+46 4 0
+31 7 7
+58 4 0
+53 21 21
+2520 14 16
+343 0 1
+641 1 1
+40 0 1
+106 1 1
+353 0 49
+582 1 1
+108 0 3
+12 15 0
+14 3 18
+64 1 1
+37 1 1
+64 1 1
+27 1 1
+239 6 7
+69 2 4
+61 2 2
+29 3 3
+125 1 1
+20 1 1
+164 1 1
+98 1 1
+76 1 1
+33 1 1
+94 84 66
+45 3 0
+14 0 12
+28 3 0
+7 66 0
+56 12 0
+121 1 1
+139 1 1
+253 5 5
+79 3 0
+227 1 1
+115 1 1
+101 0 1
+116 3 3
+33 5 14
+140 1 1
+61 0 3
+70 0 1
+97 0 13
+150 1 1
+50 1 1
+52 3 3
+116 5 5
+114 1 1
+20 1 1
+94 8 8
+82 3 3
+70 1 1
+62 0 1
+20 1 1
+181 1 1
+122 0 130
+79 1 1
+27 103 0
+63 0 104
+146 52 0
+58 1 1
+74 1 1
+54 0 26
+66 3036 1025
+74 6289 8520
+54 654 456
+65 1 1
+25 1 1
+394 10 10
+48 0 1
+244 1 1
+44 1 1
+103 0 1
+74 1 1
+56 4 4
+94 1 1
+452 1 1
+33 1 1
+158 1 1
+63 1 1
+64 7 12
+33 11 11
+295 2 0
+560 1 1
+45 1 1
+1120 4 0
+97
+
+chain 3720276 chrUn_gl000238 39939 + 0 39939 chr22 49691432 - 34115067 34154863 793
+2039 8 12
+1016 5 5
+4821 1 0
+921 2 1
+890 0 1
+423 0 2
+3925 1 1
+72 1 1
+67 1 1
+148 1 1
+74 167 5
+60 1 1
+50 13 13
+3576 1 1
+54 1 1
+575 1 1
+26 1 1
+165 1 1
+46 1 1
+1550 1 1
+35 1 1
+3673 0 14
+2364 11 11
+568 0 3
+2927 4 0
+4923 1 0
+11 1 1
+988 0 1
+81 4 0
+545 1 1
+20 0 1
+1072 0 2
+750 7 7
+640 0 2
+606
+
+chain 2054582 chrUn_gl000239 33824 + 0 33798 chr21 46944323 + 10136554 10170496 1239
+77 1 1
+15 1 1
+121 11 11
+574 1 1
+36 0 1
+40 1 1
+80 9 6
+383 4 0
+81 17 17
+172 0 4
+104 2 0
+542 1 0
+249 1 1
+48 1 1
+357 0 20
+81 0 4
+218 0 4
+46 4 0
+31 7 7
+58 4 0
+53 21 21
+2520 14 16
+343 0 1
+641 1 1
+40 0 1
+106 1 1
+353 0 49
+582 1 1
+108 0 3
+12 15 0
+14 3 18
+64 1 1
+37 1 1
+64 1 1
+27 1 1
+239 6 7
+69 2 4
+61 2 2
+29 3 3
+125 1 1
+20 1 1
+164 1 1
+98 1 1
+76 1 1
+33 1 1
+94 84 66
+45 3 0
+14 0 12
+28 3 0
+7 66 0
+56 18 0
+121 1 1
+139 1 1
+253 5 5
+79 3 0
+227 1 1
+115 1 1
+101 0 1
+116 3 3
+33 5 14
+140 1 1
+61 0 3
+70 0 1
+97 0 13
+150 1 1
+50 1 1
+52 3 3
+116 5 5
+114 1 1
+20 1 1
+94 8 8
+82 3 3
+70 1 1
+62 0 1
+20 1 1
+181 1 1
+122 0 130
+79 1 1
+27 103 0
+63 0 104
+146 52 0
+58 1 1
+74 1 1
+54 0 26
+66 10199 10221
+394 10 10
+48 0 1
+244 1 1
+44 1 1
+103 0 1
+131 4 4
+94 1 1
+452 1 1
+33 1 1
+158 1 1
+63 1 1
+64 7 12
+33 11 11
+295 2 0
+560 1 1
+45 1 1
+1120 4 0
+137 4 0
+672 0 4
+1808 0 14
+3268 1 0
+571
+
+chain 3684438 chrUn_gl000240 41933 + 27 41933 chr4 191273063 - 142375113 142417352 796
+132 1 1
+44 1 1
+295 1 1
+24 1 1
+488 1 1
+52 1 1
+33 0 48
+279 7 7
+772 1 1
+16 1 1
+244 4 4
+486 0 4
+29 1 1
+375 0 48
+45 1 1
+61 0 48
+516 55 7
+557 1 1
+48 1 1
+61 1 1
+33 1 1
+195 1 1
+32 1 1
+304 1 1
+58 1 1
+428 3 0
+350 1 0
+477 15 12
+413 1 1
+46 1 1
+66 19 19
+257 1 1
+80 1 1
+180 1 1
+18 1 1
+92 1 1
+61 1 1
+80 25 25
+574 1 1
+33 1 1
+124 10 10
+1336 7 7
+113 1 1
+170 1 1
+22 0 4
+173 1 1
+21 1 1
+198 1 0
+62 1 1
+269 10 10
+109 1 3
+136 1 1
+38 1 0
+26 1 1
+514 1 1
+68 0 1
+76 0 1
+712 1 0
+9 0 1
+38 1 1
+53 1 1
+21 1 1
+369 1 0
+243 1 1
+28 1 1
+111 0 5
+186 1 1
+117 1 1
+29 0 5
+343 1 0
+77 1 1
+23 1 1
+69 1 1
+41 1 1
+237 11 11
+518 1 1
+79 1 1
+332 1 1
+70 1 1
+610 1 1
+27 1 1
+86 22 24
+793 1 1
+48 1 1
+80 1 1
+85 1 1
+366 38 38
+1127 1 1
+42 1 1
+607 9 9
+69 0 3
+45 0 1
+77 1 1
+30 5 5
+797 1 1
+49 1 1
+152 14 14
+65 13 13
+79 1 1
+37 1 1
+129 4 4
+192 1 1
+28 1 1
+124 17 17
+518 1 1
+99 1 1
+308 16 16
+70 1 1
+134 1 1
+69 1 1
+34 1 1
+162 1 1
+61 1 1
+405 1 1
+45 2 2
+183 1 1
+60 1 1
+227 4 4
+72 1 1
+190 1 1
+30 1 1
+387 1 1
+37 1 1
+553 1 1
+20 0 1
+58 1 1
+23 1 1
+72 5 4
+27 1 1
+322 0 7
+46 1 1
+83 1 1
+16 1 1
+60 1 1
+204 1 1
+895 8 8
+191 1 1
+44 1 1
+378 86 86
+148 9 9
+123 1 1
+48 1 1
+292 7 7
+106 1 1
+16 1 1
+350 15 15
+66 1 1
+43 1 0
+684 1 1
+74 1 1
+97 1 1
+66 1 1
+144 1 1
+45 1 1
+64 1 1
+24 1 1
+131 0 1
+30 1 1
+104 14 14
+228 1 1
+69 1 1
+247 1 0
+50 1 1
+54 1 1
+26 3 0
+73 2 0
+181 1 1
+18 1 1
+185 6 6
+280 1 0
+435 1 1
+40 0 10
+14 1 1
+52 1 1
+85 2 1
+27 1 1
+625 1 1
+15 1 1
+237 1 1
+26 1 1
+349 0 1
+51 1 1
+488 0 175
+143 36 0
+83 0 74
+38 1 1
+58 1 1
+51 2 2
+57 1 1
+144 1 1
+131 17 17
+487 1 1
+83 1 1
+137 12 12
+419 1 1
+24 1 1
+97 12 12
+64 18 18
+310 1 1
+31 1 1
+186 1 1
+36 1 1
+316 10 11
+301 1 1
+176 1 1
+599 4 0
+63 1 1
+511 11 11
+79 1 1
+44 3 3
+51 1 1
+116 1 1
+146 1 1
+135 2 2
+216 1 0
+21 1 1
+227 1 1
+58 1 1
+883 1 1
+62 1 1
+375 0 1
+366
+
+chain 6945 chrUn_gl000240 41933 + 0 3993 chr4 191273063 + 49288042 49296423 8111
+27 3912 8300
+54
+
+chain 3230 chrUn_gl000240 41933 + 27771 27827 chr3_random 749256 - 628862 628918 7525302
+56
+
+chain 28578 chrUn_gl000241 42152 + 7510 7836 chr10 135374737 - 24528620 24528946 5359884
+111 1 1
+117 1 1
+96
+
+chain 20691 chrUn_gl000241 42152 + 6884 7123 chr10 135374737 + 90379126 90379365 9909152
+113 1 1
+27 1 1
+97
+
+chain 19954 chrUn_gl000241 42152 + 8113 8344 chr11 134452384 + 17008798 17009029 10487677
+119 1 1
+24 1 1
+86
+
+chain 18714 chrUn_gl000241 42152 + 6396 7510 chr11 134452384 - 41660838 41661948 7928017
+55 850 846
+81 125 125
+3
+
+chain 18427 chrUn_gl000241 42152 + 6233 6498 chrX 154913754 + 121132265 121132530 8141535
+145 8 8
+10 55 55
+47
+
+chain 15897 chrUn_gl000241 42152 + 8957 9127 chr13 114142980 - 60623878 60624048 14134116
+170
+
+chain 13800 chrUn_gl000241 42152 + 6632 6782 chr2 242951149 + 123256405 123256555 16436015
+150
+
+chain 7239 chrUn_gl000241 42152 + 7836 7932 chr5 180857866 + 56109789 56109885 15641960
+1 26 26
+69
+
+chain 6771 chrUn_gl000241 42152 + 7140 7224 chr3 199501827 - 172585013 172585097 14071569
+84
+
+chain 4980 chrUn_gl000241 42152 + 6505 6564 chr9 140273252 - 115026189 115026248 16703028
+59
+
+chain 4801 chrUn_gl000241 42152 + 8656 8714 chr6 170899992 + 62873357 62873415 24154704
+58
+
+chain 4757 chrUn_gl000241 42152 + 6569 6626 chr3 199501827 - 23594171 23594228 19385889
+57
+
+chain 3592 chrUn_gl000241 42152 + 6075 6113 chr5 180857866 + 41171487 41171525 22768222
+38
+
+chain 2241 chrUn_gl000241 42152 + 6207 6233 chr5 180857866 - 32390164 32390190 11097341
+26
+
+chain 1486 chrUn_gl000241 42152 + 6113 6164 chr12 132349534 - 4193660 4193711 21729418
+51
+
+chain 1297 chrUn_gl000241 42152 + 6024 6075 chr6 170899992 + 73104104 73104155 18904124
+51
+
+chain 1062 chrUn_gl000241 42152 + 8600 8652 chr11 134452384 - 41655227 41655279 14169249
+52
+
+chain 4122233 chrUn_gl000242 43523 + 0 43523 chr22 49691432 + 23741157 23784637 726
+37 0 1
+501 0 1
+108 3 0
+187 0 1
+1121 1 1
+20 1 1
+1027 1 1
+34 1 1
+52 0 1
+765 0 4
+610 1 1
+19 0 1
+4259 1 0
+1146 31 0
+6060 1 1
+22 1 1
+2400 5 0
+8889 3 0
+179 0 1
+1992 0 1
+1767 16 0
+568 0 2
+178 0 2
+2610 4 0
+1173 1 0
+3097 0 2
+1764 0 6
+1838 2 0
+1027
+
+chain 4053524 chrUn_gl000243 43341 + 0 43341 chr21_random 1679693 + 729451 772721 736
+1181 1 1
+44 1 1
+164 1 1
+68 1 1
+111 1 1
+38 0 1
+6062 1 1
+22 3 3
+1372 1 1
+42 14 0
+910 1 1
+31 1 1
+463 28 28
+3921 1 0
+409 1 0
+1228 13 13
+561 1 1
+22 1 1
+527 4 0
+1153 1 1
+35 1 1
+2127 15 15
+1821 1 0
+407 0 1
+391 0 6
+613 1 1
+28 1 1
+191 36 0
+25 0 2
+13 0 2
+41 9 15
+922 16 16
+114 1 0
+479 29 0
+1850 1 0
+1511 0 3
+355 1 1
+48 1 1
+3880 1 1
+29 1 1
+1605 1 1
+47 1 1
+1485 1 1
+34 1 1
+907 8 8
+532 0 1
+1067 1 0
+1245 1 0
+2731 4 4
+31 3 0
+236
+
+chain 2844 chrUn_gl000243 43341 + 25693 25722 chr22_random 257318 + 139119 139148 22581207
+29
+
+chain 3756669 chrUn_gl000244 39929 + 8 39929 chr22 49691432 - 35197541 35237456 785
+890 0 2
+6963 1 0
+6036 101 101
+1666 0 1
+212 0 5
+237 1 0
+873 1 0
+227 3 0
+42 1 1
+4812 1 1
+36 1 1
+6217 2 0
+192 4 0
+249 1 0
+4665 0 5
+662 30 34
+257 12 12
+841 10 0
+4675
+
+chain 11637 chrUn_gl000244 39929 + 13898 34133 chr14 106368585 + 18813314 18833199 821
+26 1 1
+73 20106 19756
+29
+
+chain 3438216 chrUn_gl000245 36651 + 0 36651 chr1 247249719 - 105352682 105389363 845
+12574 2 0
+842 0 2
+6285 0 1
+6019 0 21
+4218 0 3
+2704 0 4
+81 0 1
+1294 1 1
+47 1 1
+1004 1 1
+21 1 1
+73 16 16
+108 1 1
+32 1 1
+1325
+
+chain 3563345 chrUn_gl000246 38154 + 0 38154 chr22 49691432 - 34033100 34071273 824
+1862 1 1
+45 1 1
+3608 0 3
+107 1 15
+848 1 1
+43 1 0
+337 1 1
+35 1 1
+176 0 2
+91 3 4
+2683 0 1
+1321 18 2
+519 1 1
+27 1 1
+472 1 1
+44 1 1
+2452 0 8
+253 1 1
+21 1 1
+48 8 0
+6372 1 1
+38 1 0
+33 1 1
+777 0 1
+139 0 3
+2402 0 2
+3053 1 1
+46 1 1
+198 4 4
+27 1 1
+1883 0 9
+1592 0 4
+320 0 1
+1542 11 11
+412 12 12
+1421 4 0
+2828
+
+chain 3430032 chrUn_gl000247 36422 + 0 36422 chr1 247249719 + 142267104 142303524 847
+151 8 8
+412 1 0
+642 0 1
+3260 12 12
+7577 0 1
+311 3 0
+2665 4 0
+3223 0 1
+437 0 1
+726 0 2
+340 1 0
+1345 1 0
+1511 0 2
+890 1 1
+29 1 1
+2699 1 1
+41 0 2
+1893 1 1
+49 1 1
+5180 1 0
+296 0 4
+573 1 0
+35 1 1
+1170 4 0
+925
+
+chain 3751823 chrUn_gl000248 39786 + 0 39786 chr22 49691432 + 31380700 31420473 786
+9870 4 0
+430 0 3
+13 1 1
+275 3 3
+48 0 1
+149 0 4
+854 1 0
+15 1 0
+1499 1 0
+3772 2 0
+2363 16 16
+1406 10 10
+813 1 0
+269 0 1
+2137 0 3
+379 0 1
+286 1 0
+504 7 0
+2925 1 0
+41 1 1
+1183 25 25
+1285 0 1
+1290 0 1
+93 5 4
+521 1 0
+239 1 0
+304 1 0
+202 1 0
+774 1 0
+3448 1 1
+29 1 1
+565 1 0
+303 2 0
+1412
+
+chain 3662710 chrUn_gl000249 38502 + 0 38502 chr22 49691432 + 26547108 26585613 801
+1207 1 0
+15053 0 12
+44 8 0
+22189
+
+chain 14267284136 X 155270560 + 60000 155260560 chrX 154913754 + 0 154913754 8
+34821 50000 50000
+86563 50000 30000
+766173 50000 50000
+36556 50000 50000
+80121 50000 90000
+754004 50000 100000
+5505644 50000 0
+3064790 50079 0
+26309505 50000 25000
+201176 8 0
+7416 0 2
+53134 8 0
+3073 0 12
+21097 0 2
+60831 2 0
+57728 0 20
+54336 0 1
+31675 0 4
+9987 4 0
+12108 0 4
+11225906 0 2000
+356252 50059 50059
+77342 1 1
+17 1 1
+94 0 3
+266 10 10
+113 1 1
+21 1 1
+5400 0 5
+4996 7 15
+3222 5 1
+6456 1 0
+1476 5 5
+2100 1 1
+40 1 1
+1316 0 1
+2446 1 0
+1555 0 2
+11220 1 0
+2639 1 0
+5190 0 4
+79 8 0
+5086 0 1
+2663 1 0
+9149 7 8
+1851 0 1
+9081 0 1
+7248 25 0
+208 28 0
+25 2 0
+15 83 0
+17 116 4
+2536 0 1
+1394 0 6
+12550 0 42
+822 4 0
+30578 1 0
+3711 4 0
+3637 1 0
+11945 0 1
+20204 0 1
+4172 8 0
+5679 1 0
+23827 0 2
+54817 0 1
+657 0 1
+342931 50000 180000
+2052068 27 1
+5375 2 0
+46 0 2
+6489 0 1
+7175 2 0
+1239 2 0
+4301 0 4
+27254 0 1
+4244 0 2
+717 0 2
+260 0 6
+26075 1 0
+236464 50000 50000
+6136098 3100000 3000000
+13518993 1 0
+449 1 0
+4535 4 0
+755 1 0
+1102 1 0
+24 1 1
+107 2 0
+3470 0 1
+1108 1 0
+4775 1 0
+8628 1 1
+46 1 1
+1072 1 1
+44 1 1
+292 4 5
+9091 4 4
+2218 4 4
+705 5 1
+452 0 1
+332 0 1
+1801 7 1
+3960 1 0
+2007 1 0
+3337 1 0
+2093 1 0
+407 310 0
+6130 1 1
+36 1 1
+1697 1 0
+97 13 0
+7624 1 1
+19 1 1
+3806 24 24
+3103 1 0
+779 7 7
+721 1 1
+43 1 1
+1626 0 1
+6146 0 2
+150 1 1
+47 1 1
+2172 0 2
+398 1 1
+31 1 1
+1334 16 16
+1663 1 1
+18 1 1
+2105 1 0
+9 1 1
+1409 1 1
+33 1 1
+1753 1 0
+408 0 1
+1916 1 0
+1928 0 12
+3800 1 1
+15 1 1
+2921 0 1
+4597 0 2
+486 6 0
+308 24 24
+1056 1 1
+44 1 1
+186 1 1
+46 1 1
+3037 0 1
+2301 0 3
+3876 1 1
+22 1 1
+1724 1 0
+3733 1 0
+627 1 0
+250 0 1
+194 1 1
+26 1 1
+20797 10 10
+2445 0 1
+1733 2 0
+1001 0 12
+4394 9 9
+4052 9 10
+670 1 1
+96 0 6
+26 1269 1568
+28 3 2
+10 1486 1188
+25 6 0
+18 1 1
+62 17 17
+77 1 0
+4949 10 10
+4690 1 0
+7343 0 1
+1248 0 1
+1259 0 1
+1347 4 0
+1532 0 1
+3797 16 16
+807 0 1
+2427 0 1
+48 1 0
+287 0 1
+611353 1 0
+1041 0 6
+371 1 0
+227 1 0
+2806 0 1
+36 1 1
+234 1 1
+23 1 1
+584 0 1
+22241 1 1
+65 1 1
+4605 1 0
+2337 20 0
+2119 1 0
+6170 13 9
+10665 1 0
+14631 0 1
+5359 0 4
+4004 0 1
+3182 0 11
+3897 16 14
+2551 0 1
+1824 0 1
+5274 1 1
+41 1 1
+4309 1 0
+3827 1 0
+4594 1 0
+65 1 1
+1170 1 1
+42 4 4
+214 1 0
+5228 1 0
+553 0 1
+6270 1 1
+12 1 1
+2849 12 13
+156 2 0
+8820 1 1
+41 1 1
+472 1 1
+65 1 0
+8 1 1
+1162 0 1
+565 1 1
+48 1 1
+536 1 2
+766 2 0
+4520 1 0
+1574 0 1
+503 1 0
+2558 1 0
+250061 7 7
+9650 18 18
+3208 1 1
+25 1 0
+744 0 2
+2994 1 1
+33 1 1
+1331 0 1
+87 19 19
+1935 5 0
+7 6 0
+1292 1 1
+35 1 1
+2485 1 1
+35 1 1
+4184 23 23
+13077 8 15
+671 4 0
+428 1 0
+4736 0 1
+3849 1 0
+6745 16 16
+2344 1 1
+41 1 1
+7917 1 0
+3876 1 1
+75 1 1
+1429 7 7
+11933 1 1
+28 1 1
+409 1 0
+11 1 1
+1223 12 12
+5354 1 0
+1255 6 0
+851 1 1
+45 1 1
+144 1 1
+47 5 5
+5929 0 4
+422 1 0
+2949 6 0
+193 1 1
+319 4 4
+3592 33 33
+3115 3 1
+1074 0 1
+2465 1 1
+40 1 1
+640 0 2
+550 1 1
+32 1 1
+4096 1 1
+29 1 1
+949 6 6
+6258 0 1
+3957 0 1
+19608 1 1
+48 1 1
+234 1 0
+16874 11 11
+1018 0 321
+2624 0 1
+4553 3 0
+491 6 0
+7496 1 1
+10 10 0
+76 4 0
+3314 1 1
+32 1 1
+5217 0 1
+3540 0 1
+1254 48 48
+1124 18 0
+3109 8 8
+3248 0 1
+1946 1 1
+48 1 1
+9620 2 0
+31242 50000 20000
+36075685 0 3
+36004 1 1
+27 1 1
+5196 1 0
+293 2 0
+13307 3 0
+2420 0 6
+1863 2 0
+2911 1 0
+3233 0 2
+66 0 1
+2375 0 10
+4894 0 1
+745 0 1
+3897 13 0
+4430 1 1
+48 1 4
+20 2 0
+279 2 0
+33 1 1
+48 0 1
+387 8 8
+692 1 0
+375 0 3
+380 23 23
+1289 1 1
+29 1 1
+12336 331 0
+852 0 4
+48 4 0
+4350 1 1
+59 1 1
+4306 5 0
+129 0 2
+3001 1 0
+1332 5 8
+23273 1 0
+30174 39 27
+337 3 0
+2838 0 1
+1614 9 0
+313 1 0
+82 0 4
+173 1 1
+25 1 1
+4912 39 0
+1863 1 0
+2931 0 1
+3134 3 0
+390880 1 0
+7199 0 1
+305 0 2
+1811 0 2
+5449 3 0
+7443 2 0
+2171 1 1
+27 1 1
+2668 2 0
+2180 1 0
+1170 9 0
+1450 16 16
+3080 0 1
+11157 0 1
+678 1 1
+28 1 1
+698 0 1
+112 0 1
+1831 0 3
+14327 0 2
+2247 3 0
+380 1 1
+28 1 1
+1265 21 19
+7184 2 3
+4225 14 9
+1002 1 0
+3854 0 4
+2535 1 1
+30 1 1
+794 0 1
+25 1 1
+76140 50000 70000
+1432750 0 7772
+681872 50000 20000
+4278742 56347 0
+12021233 1 0
+8 0 1
+1775 0 1
+1468 1 1
+51 14 16
+6 1 0
+6 1 0
+11 5 4
+7 1 0
+4 1 0
+75 2 1
+26 0 1
+16 1 0
+9 1 0
+19 2 0
+22 0 1
+9 1 0
+5 3 1
+14 7 6
+38 0 1
+26 1 1
+62 40 39
+1687 1 0
+54 1 0
+8528 1 0
+2722 1 0
+6240 1 0
+33 1 0
+121285 0 1
+6 1 0
+35 0 1
+1381 1 0
+5368 0 1
+3079 1 0
+10863441 4 0
+1799 1 1
+24 1 1
+334 0 1
+4960 0 17
+1160 1 1
+34 1 1
+6153 0 3
+1346 0 4
+103 0 4
+168 27 27
+2640 12 12
+304 16 0
+719 1 0
+3286 0 1
+10182 9 0
+804 1 1
+28 1 1
+749 1 0
+3387 1 1
+47 1 1
+482 1 0
+455 15 15
+719 1 1
+18 1 1
+2074 1 0
+1349 4 0
+3927 1 1
+18 1 1
+907 1 0
+2972 0 2
+115 1 1
+37 1 1
+4428 0 1
+1120 0 1
+4055 0 5
+2929 0 3
+3590 1 1
+47 1 1
+62 0 1
+947 1 1
+45 1 1
+1639 1 1
+32 1 1
+1076 1 0
+3996 0 4
+686 41 41
+7238 0 1
+1733 0 1
+1451 2 0
+617 0 1
+4375 1 0
+2194 15 16
+349 1 1
+27 1 1
+8237 0 1
+499 1 1
+37 2 2
+968 0 1
+34 1 1
+6337 1 1
+18 1 1
+8162 1 1
+21 0 5
+7668 45 45
+1562 0 1
+6017 5 5
+3872 0 8
+5421 0 1
+532 7 6
+5673 4 0
+1542 0 4
+890 1 3
+2561 0 1
+1692 0 1
+1142 1 1
+32 1 1
+503 1 2
+123 1 1
+75 1 1
+2322 0 1
+201 0 1
+40 3 3
+149 0 3
+1441 1 1
+40 1 1
+159 0 2
+1278 1 1
+33 1 1
+221 1 0
+31 1 1
+161 10 9
+1890 1 0
+132 1 1
+37 1 1
+514 23 17
+1373 0 4
+907 17 17
+714 31 30
+55 1 1
+24 1 1
+1038 0 2
+95 5 1
+1094 1 1
+170 1 1
+844 3 0
+369 1 1
+39 1 1
+650 1 1
+41 1 1
+176 1 1
+10 1 1
+688 0 1
+7637 0 4
+2653 1 1
+26 4 0
+46 1 1
+727 0 8
+2197 1 0
+13466 1 0
+3510 2 0
+2147 1 1
+44 3 0
+1320 11 11
+213 4 0
+102 0 1
+3239 1 0
+1492 0 3
+107 1 1
+35 14 0
+2391 1 1
+39 2 0
+436 0 4
+2271 0 8
+6868 3 0
+7183 1 0
+5104 3 0
+182 0 1
+3131 1 1
+31 0 1
+14 1 1
+59 0 1
+373 1 1
+42 1 1
+235 13 13
+1608 5 0
+152 1 1
+106 1 1
+783 34 34
+1633 1 1
+29 0 3
+821 1 1
+24 1 1
+1178 1 1
+33 1 1
+328 1 1
+27 1 1
+5682 1 0
+11 1 5
+146398 50000 30000
+59809 2 0
+3389 1 1
+37 1 1
+11606 1 0
+1597 1 0
+618 1 1
+47 1 1
+2698 1 0
+826 5 5
+33 2 0
+2560 14 0
+98 3 0
+1287 1 0
+7600 1 0
+9897 8 0
+7157 1 0
+32 1 1
+1698 1 0
+754 0 2
+6787 1 0
+584 2 0
+1107 1 1
+40 1 1
+365 1 1
+35 1 1
+400 8 0
+11443 1 0
+1973 1 0
+497 46 46
+657 1 0
+716 1 1
+25 1 1
+1570 2 0
+433 0 2
+905 2 0
+94 1 1
+28 1 1
+2490 1 1
+16 1 1
+5054 1 9
+2184 2 0
+2955 21 23
+794 0 1
+1563 1 1
+20 1 1
+1627 0 11
+1676 0 2
+1527 1 0
+676 1 1
+29 1 1
+1245 1 1
+34 1 0
+1192 7 0
+27 1 0
+1940 0 1
+3421 2 0
+17 1 1
+774 30 0
+97 6 6
+59 26 12
+840 1 1
+19 1 1
+2036 13 1
+26 14 0
+1114 1 0
+25 1 1
+380 0 16
+160 1 1
+17 1 1
+1151 4 0
+699 0 1
+29 2 0
+409 1 1
+49 1 1
+1240 1 1
+37 3 3
+2248 1 0
+1828 1 0
+1997 5 1
+4640 4 4
+4555 0 2
+149 0 52
+619 2 2
+16 1 1
+83 22 0
+56 57 1
+2531 0 8
+4250 1 1
+15 1 1
+2203 0 4
+1665 0 10
+415 2 0
+395 19 18
+15708 0 1
+161 4 0
+79 14 0
+543 1 1
+42 1 1
+3261 18 18
+139 46 46
+403 1 1
+18 1 1
+5405 1 0
+1104 1 1
+53 1 1
+392 1 1
+55 3 3
+3352 9 0
+692 1 9
+8 4 0
+27 3 97
+39 3 1
+21 3 51
+61 0 2
+8931 1 0
+6692 1 2
+1141 0 2
+196 2 0
+389 1 1
+30 1 1
+949 0 1
+6057 0 3
+4741 1 0
+7689 2 0
+2046 18 18
+215 0 1
+46885 2 0
+24138 2 0
+4037 1 0
+4047693 1 0
+9545 0 2
+11590 4 0
+1698 1 3
+13506 37 37
+5380 4 0
+1806 1 1
+44 1 1
+2581 0 2
+10620 0 1
+3804 0 1
+339 0 2
+476 0 1
+5861 8 5
+109 0 14
+901 1 1
+19 1 1
+45 2 0
+1736 1 0
+6625 2 0
+7812 4 0
+7678 2 0
+5068 4 0
+21 1 0
+4170 0 1
+1671 6 0
+6333 0 16
+902 1 1
+44 1 1
+384 0 6
+23418 2 0
+36 1 1
+8900 0 4
+222 1 1
+49 1 1
+2783 0 1
+2641 0 1
+136 20 20
+1279 0 1
+3924 6 6
+13054 6 0
+8965 23 36
+4094 2 0
+2269 1 0
+13621 16 16
+2621 0 2
+30076 1 1
+49 1 1
+102 1 0
+8824 1 1
+25 1 1
+1730 1 1
+47 1 1
+3339 0 1
+131 0 16
+83 16 0
+89 6 0
+2826 33 33
+3509 1 0
+541 1 0
+6288 0 4
+3814 2 0
+7260 0 1
+806 68 0
+1162 0 1
+2230 1 0
+1109 0 1
+1106 2 0
+12396 0 1
+26207 1 1
+21 1 1
+3541 18 18
+525 0 16
+1326 7 7
+525 0 1
+4198 0 1
+4682 13 13
+890 0 2
+816 0 2
+1961 0 4
+24586 1 1
+19 1 1
+4403 1 0
+1342 1 0
+57 12 11
+2225 1 0
+2011 0 35
+10543 0 1
+9766 6 12
+2489 2 1
+20 1 1
+1541 0 12
+1130 1 1
+34 1 1
+927 0 1
+4003 0 1
+966 1 0
+149 0 1
+844 8 0
+4324 1 1
+25 1 1
+569 7 6
+6361 1 0
+3074 0 1
+1539 3 9
+634 1 1
+39 1 1
+8610 13 12
+760 2 0
+4311 0 6
+3122 0 2
+369 1 0
+9963 10 10
+2191 1 1
+23 1 1
+1060 1 1
+19 1 1
+240 12 12
+1748 1 1
+45 1 1
+1040 1 1
+31 1 1
+7446 1 1
+25 1 1
+8379 7 7
+7325 3 0
+357 0 1
+1313 0 1
+11627 4 0
+5862 1 0
+9750 1 0
+3539 0 16
+5672 13 13
+2885 0 4
+8179 1 0
+753 0 1
+4317 0 2
+1318 1 0
+957 0 1
+825 12 12
+1109 0 16
+3736 17 17
+2236 8 8
+7791 15 185
+149 1 1
+21 2 0
+636 1 1
+22 1 0
+42 1 1
+1634 4 4
+3380 0 3
+979 2 0
+3429 0 1
+7132 0 14
+1733 1 1
+38 0 1
+88 1 0
+630 6 6
+489 5 0
+22 1 0
+94 1 0
+42 0 1
+17 1 0
+27 1 0
+172 1 1
+37 1 1
+191 1 1
+66 1 1
+630 1 0
+261 30 30
+1282 1 0
+16 1 1
+429 1 0
+1588 1 1
+20 1 1
+1416 1 1
+33 1 1
+529 1 0
+25 1 0
+1863 4 0
+1651 1 1
+28 1 1
+11815 1 0
+26 1 0
+19 1 1
+3105 1 0
+700 1 0
+150 1 0
+68 1 0
+1421 6 0
+567 1 0
+14 1 0
+2415 1 0
+41 1 1
+415 1 1
+33 1 1
+4521 1 1
+33 1 1
+307 0 1
+176 0 1
+3790 1 1
+86 1 1
+67 1 1
+65 1 0
+7439 1 1
+18 1 1
+16805 1 0
+1764 0 1
+6984 1 0
+3401 20 0
+156 1 1
+30 1 1
+165 2 0
+1087 0 1
+953 0 1
+483 1 0
+632 0 1
+652 0 1
+8559 0 2
+1871 0 1
+398 0 1
+2219 1 1
+53 1 1
+756 1 1
+66 1 1
+69 1 1
+48 1 1
+63 1 1
+28 0 3
+1057 0 3
+63 3 0
+55 1 1
+74 2 3
+159 3 0
+92 1 1
+29 1 1
+58 0 3
+1210 9 9
+54 1 1
+27 1 1
+1374 2 0
+1775 2 17
+764 14 14
+331 16 16
+2291 4 3
+1687 1 1
+26 1 1
+2469 0 1
+3243 1 0
+3636 1 1
+24 1 1
+615 0 1
+2566 1 0
+275 0 5
+690 0 7
+13139 1 0
+1452 0 4
+214 13 13
+61 124 0
+1381 9 9
+5812 1 1
+24 1 1
+5703 1 0
+3992 14 15
+1462 0 3
+5199 0 2
+1554 2 0
+715 12 10
+1966 2 0
+2808 16 0
+611 1 0
+406 0 18
+737 1 1
+31 1 1
+4372 0 5
+10789 0 1
+2399 0 1
+6750 2 0
+96 48 48
+1219 0 6
+6736 0 2
+4457 4 0
+7867 0 1
+3495 1 2
+6215 12 12
+1357 1 0
+2652 0 1
+1771 1 0
+14207 41609 41616
+18338 46 46
+851 1 0
+9638 1 0
+2994 1 0
+469 1 3
+499 1 0
+12074 13 13
+2807 11 10
+715 2 0
+1627 6 6
+5099 0 1
+488 5 1
+975 2 0
+1730 32 31
+1791 0 5
+8135 38 38
+84 3 3
+18 1 1
+3737 9 9
+1442 13 13
+212 10 0
+7712 1 1
+44 1 1
+6271 0 1
+1316 1 1
+49 1 1
+9052 28 32
+113 2 0
+2813 13 13
+1285 50000 2858
+75638 50000 40000
+1583473 2 0
+1564100 97462 0
+2933461
+
+chain 4369679 X 155270560 + 152229637 152277099 chrX 154913754 + 151980294 152116665 696
+7131 26 26
+1319 1 0
+10288 0 88910
+2852 19 19
+3721 0 1
+13270 1 0
+8834
+
+chain 2629454 X 155270560 + 120011032 120067379 chrX 154913754 + 119895063 119899921 647
+714 51489 0
+4144
+
+chain 1494650 X 155270560 + 148762194 148872193 chrX 154913754 - 6301537 6445444 168
+2899 0 1
+1499 0 1
+3725 0 6
+20333 1 0
+13152 18338 18338
+46 40010 73911
+32 9926 9926
+38
+
+chain 260907 X 155270560 + 75365988 75368784 chrX 154913754 - 79628560 79631356 2215
+1269 41 41
+1486
+
+chain 138004 X 155270560 + 120011746 120013199 chrX 154913754 + 119920102 119921555 138939
+1453
+
+chain 29712 X 155270560 + 112877029 112877338 chr12 132349534 + 121720730 121721039 4776951
+309
+
+chain 29117 X 155270560 + 75253866 75254170 chr12 132349534 - 49782819 49783123 5064709
+304
+
+chain 10575 X 155270560 + 143182285 143275757 chr2 242951149 - 154930543 155024664 254
+41 49992 50582
+45 43365 43424
+29
+
+chain 3572 X 155270560 + 148224541 148224579 chrX 154913754 + 148032219 148032257 5503764
+38
+
+chain 3404 X 155270560 + 120013199 120013235 chrX 154913754 + 119931276 119931312 297576
+36
+
+chain 3363 X 155270560 + 49293018 49293056 chrX 154913754 + 49218184 49218222 1450
+38
+
+chain 2275 X 155270560 + 152236768 152236794 chrX 154913754 - 2913071 2913097 1916
+26
+
+chain 2111 X 155270560 + 143122309 143122332 chr17 78774742 - 16413594 16413617 6765736
+23
+
+chain 2063 X 155270560 + 148224511 148224541 chrX 154913754 + 148032257 148032287 9904071
+30
+
+chain 1738 chrX 155270560 + 76513595 76513628 chrX_random 1719168 + 711492 711525 75
+33
+
+chain 1275 X 155270560 + 148522048 148522077 chr11 134452384 + 59964168 59964197 432609
+29
+
+chain 391 X 155270560 + 112955240 112955279 chr3 199501827 - 80088461 80088500 4668596
+20 4 4
+15
+
+chain 2373403023 Y 59373566 + 10000 28819361 chrY 57772954 + 0 27228749 24
+34821 50000 50000
+86563 50000 30000
+766173 50000 50000
+36556 50000 50000
+80121 50000 90000
+754004 50000 100000
+6846717 50000 50000
+276367 50000 600000
+813231 3000000 500000
+39401 50000 400000
+554624 50000 100000
+535761 0 1
+32919 11 12
+12810 0 5
+18900 1 1
+121 4 5
+230478 0 1
+750 1 1
+22 1 1
+14340 1 1
+43 1 1
+2095 0 1
+14635 0 9
+2781 0 1
+45022 5 6
+7151 0 1
+9344 628 0
+5417479 50006 0
+2175791 50000 0
+1481749 50000 50000
+4867933
+
+chain 46617811 Y 59373566 + 58819361 59363566 chrY 57772954 + 57228749 57772954 80
+98295 50000 50000
+395910
+
+chain 9624 Y 59373566 + 14725909 14726162 chrX 154913754 + 99410441 99410697 23695076
+50 136 139
+67
+
diff --git a/public/chainFiles/b37tohg19.chain b/public/chainFiles/b37tohg19.chain
new file mode 100644
index 0000000..ecc442f
--- /dev/null
+++ b/public/chainFiles/b37tohg19.chain
@@ -0,0 +1,75 @@
+chain 1 1 249250621 + 0 249250621 chr1 249250621 + 0 249250621 1
+249250621
+
+chain 1 2 243199373 + 0 243199373 chr2 243199373 + 0 243199373 2
+243199373
+
+chain 1 3 198022430 + 0 198022430 chr3 198022430 + 0 198022430 3
+198022430
+
+chain 1 4 191154276 + 0 191154276 chr4 191154276 + 0 191154276 4
+191154276
+
+chain 1 5 180915260 + 0 180915260 chr5 180915260 + 0 180915260 5
+180915260
+
+chain 1 6 171115067 + 0 171115067 chr6 171115067 + 0 171115067 6
+171115067
+
+chain 1 7 159138663 + 0 159138663 chr7 159138663 + 0 159138663 7
+159138663
+
+chain 1 8 146364022 + 0 146364022 chr8 146364022 + 0 146364022 8
+146364022
+
+chain 1 9 141213431 + 0 141213431 chr9 141213431 + 0 141213431 9
+141213431
+
+chain 1 10 135534747 + 0 135534747 chr10 135534747 + 0 135534747 10
+135534747
+
+chain 1 11 135006516 + 0 135006516 chr11 135006516 + 0 135006516 11
+135006516
+
+chain 1 12 133851895 + 0 133851895 chr12 133851895 + 0 133851895 12
+133851895
+
+chain 1 13 115169878 + 0 115169878 chr13 115169878 + 0 115169878 13
+115169878
+
+chain 1 14 107349540 + 0 107349540 chr14 107349540 + 0 107349540 14
+107349540
+
+chain 1 15 102531392 + 0 102531392 chr15 102531392 + 0 102531392 15
+102531392
+
+chain 1 16 90354753 + 0 90354753 chr16 90354753 + 0 90354753 16
+90354753
+
+chain 1 17 81195210 + 0 81195210 chr17 81195210 + 0 81195210 17
+81195210
+
+chain 1 18 78077248 + 0 78077248 chr18 78077248 + 0 78077248 18
+78077248
+
+chain 1 19 59128983 + 0 59128983 chr19 59128983 + 0 59128983 19
+59128983
+
+chain 1 20 63025520 + 0 63025520 chr20 63025520 + 0 63025520 20
+63025520
+
+chain 1 21 48129895 + 0 48129895 chr21 48129895 + 0 48129895 21
+48129895
+
+chain 1 22 51304566 + 0 51304566 chr22 51304566 + 0 51304566 22
+51304566
+
+chain 1 X 155270560 + 0 155270560 chrX 155270560 + 0 155270560 23
+155270560
+
+chain 1 Y 59373566 + 0 59373566 chrY 59373566 + 0 59373566 24
+59373566
+
+chain 1 MT 16569 + 0 16569 chrM 16569 + 0 16569 25
+16569
+
diff --git a/public/chainFiles/hg18tob37.chain b/public/chainFiles/hg18tob37.chain
new file mode 100644
index 0000000..6261eae
--- /dev/null
+++ b/public/chainFiles/hg18tob37.chain
@@ -0,0 +1,30854 @@
+chain 21270159960 chr1 247249719 + 0 247199719 1 249250621 + 10000 249233096 2
+616 0 137
+166664 50000 50000
+40302 50000 50000
+153649 50000 50000
+1098446 269 272
+773 1 1
+43 1 1
+864369 2 2
+51 0 3
+104 13694 13694
+104 3 0
+51 2 2
+134936 50000 50000
+1161048 60000 150000
+1440092 50000 27273
+7590365 50000 50000
+116914 50088 100088
+237162 50000 50000
+3518496 50000 50000
+12702424 50000 150000
+16145012 1 0
+7772 0 1
+4705841 1 0
+52977198 50000 50000
+157344 50000 21065
+16604841 50000 50000
+189539 50000 150000
+398739 20290000 21050000
+195588 50000 50000
+186739 50000 150000
+175055 50000 50000
+201709 50000 100000
+126477 50000 130183
+381 3 0
+315 2 0
+62 1 1
+73 1 1
+1158 0 1
+314 1 0
+11 1 1
+2849 0 3
+5615 1 1
+37 1 1
+3172 4 6
+190 1 1
+34 1 1
+380 1 0
+2099 0 3
+1135 4 0
+970 5 5
+209 0 1
+460 1 0
+1242 28 28
+574 1 1
+21 1 1
+2268 0 3
+239 1 0
+970 11 11
+2365 1 1
+21 1 1
+384 8 8
+996 0 2
+10383 0 2
+713 1 0
+5188 1 1
+30 1 1
+1233 0 1
+132 1 1
+44 1 1
+2955 0 1
+512 1 1
+39 1 1
+1096 16 0
+743 0 1
+9028 1 0
+2506 6 0
+8446 0 2
+5505 3 0
+7541 0 1
+109864 50000 50000
+78698 50000 50000
+127263 50000 50000
+170669 50000 50000
+38311 100000 100000
+1022394 50000 50000
+281532 50000 294733
+1687 1 1
+39 0 1
+1018 1 1
+26 1 1
+1722 0 2
+158 0 4
+1602 6 0
+1384 0 1
+2066 1 1
+32 3 1
+1556908 50000 150000
+185320 50000 150000
+172789 50000 50000
+220313 50000 50000
+455185 50000 50000
+22047237 0 1
+34365824 50000 150000
+259514 50000 150000
+17265625 50000 50000
+11394365 50000 50000
+13665999 50000 150000
+174886
+
+chain 989083 chr1 247249719 + 2475290 2488984 1 249250621 - 246751494 246765188 1383
+13694
+
+chain 5421 chr1 247249719 + 1609759 1609849 1 249250621 + 1672838 1672928 2227793
+90
+
+chain 3303 chr1 247249719 + 13192499 13192587 1 249250621 - 236203315 236203403 109
+88
+
+chain 467 chr1 247249719 + 142633259 142633287 1 249250621 - 128420441 128420469 123
+28
+
+chain 12431961244 chr10 135374737 + 50000 135374737 10 135534747 + 60000 135524747 10
+5577107 50006 0
+12337568 50000 50000
+20794160 50000 50000
+286100 2480000 3200000
+191752 50000 50000
+3830277 150000 50000
+952205 150000 100000
+263307 150000 100000
+163231 150000 50000
+989829 150000 100000
+1941874 50000 50000
+211435 50000 50000
+30112515 319974 0
+13249156 10 0
+31058956 50000 50000
+2696597 50000 150000
+4615335 10000 50000
+246123 50000 50000
+1327328 1 1
+47 1 1
+1312 1 0
+56 1 1
+190 1 1
+31 1 1
+20182 0 1
+448068
+
+chain 8134587 chr10 135374737 + 81444609 81551340 10 135534747 + 88976631 89083503 218
+369 41 41
+149 6 6
+83 71 71
+548 9 9
+391 9 9
+334 42 42
+81 1 2
+954 1 0
+441 0 4
+922 37 37
+343 253 253
+278 59 58
+404 13 13
+90 39 37
+70 132 123
+145 4 4
+392 9 9
+58 29 29
+166 51 50
+78 14 14
+455 61 65
+243 41 41
+1183 17 17
+163 57 57
+169 51 51
+912 5 5
+667 12 12
+250 20 20
+506 8 8
+292 8 8
+266 17 17
+69 27 27
+131 22 22
+668 46 47
+270 13 13
+128 7 7
+300 48 48
+818 32 32
+667 67 67
+402 24 36
+293 18 18
+423 68 68
+113 9 9
+630 42 42
+269 51 51
+165 0 1
+645 52 52
+76 91 90
+505 13 13
+143 31 31
+319 68 70
+245 126 126
+145 35 37
+90 57 57
+378 41 38
+193 13 13
+333 51 30
+51 6 6
+821 56 56
+547 18 18
+343 9 9
+270 47 47
+706 1 0
+120 21 22
+371 35 35
+530 13 13
+51 36 36
+611 48 48
+587 18 18
+499 9 9
+183 26 26
+847 7 7
+134 5 4
+64 34 34
+120 66 66
+173 147 147
+126 19 16
+53 44 49
+69 1 0
+153 89 90
+81 16 16
+52 32 36
+72 28 28
+86 68 68
+56 51 51
+120 17 17
+181 5 5
+86 17 18
+68 36 36
+356 101 101
+90 3 11
+226 26 28
+70 19 19
+95 9 9
+88 16 16
+272 33 33
+216 71 71
+394 83 83
+853 14 15
+90 23 23
+130 0 3
+52 11 11
+192 49 49
+407 13 13
+122 71 34
+179 28 28
+102 10 10
+299 36 36
+268 4 4
+123 36 36
+112 41 41
+233 77 75
+73 88 92
+519 43 43
+118 101 101
+78 33 43
+117 31 31
+83 37 37
+86 3 0
+468 0 2
+791 55 55
+268 97 97
+111 55 59
+164 38 38
+176 0 3
+116 67 74
+269 0 3
+92 66 67
+205 50 55
+1339 33 34
+86 9 9
+310 34 34
+217 42 42
+194 18 17
+191 4 4
+250 0 3
+148 79 79
+77 3 0
+199 57 57
+200 53 53
+331 52 53
+136 32 42
+69 60 60
+169 0 1
+594 88 88
+174 70 70
+135 48 48
+53 9 9
+862 25 25
+1106 33 33
+974 76 76
+368 17 17
+369 43 43
+263 49 49
+143 8 8
+228 57 57
+74 3 0
+914 2 0
+137 77 74
+243 32 32
+166 53 53
+646 87 87
+71 0 1
+661 45 45
+142 76 76
+851 17 17
+56 60 60
+52 59 58
+80 60 60
+602 13 13
+617 76 78
+51 152 152
+77 38 38
+150 0 4
+386 45 45
+585 40 33
+108 12 12
+219 99 99
+1376 58 58
+517 27 27
+124 20 20
+566 58 58
+235 47 47
+72 26 26
+157 43 43
+208 31 31
+578 122 84
+259 15 15
+1141 119 119
+141 13 13
+817 14 14
+188 0 5
+323 62 75
+447 0 5
+64 161 161
+945 23 23
+66 35 35
+104 125 125
+613 186 184
+102 205 203
+767 27 27
+111 13 13
+107 80 83
+272 0 1
+438 4 4
+127 68 68
+564 44 44
+141 14 14
+137 13 17
+167 18 0
+241 25 25
+586 30 30
+178 44 44
+310 90 87
+1277 35 35
+646 32 32
+704 56 56
+367 93 101
+241 15 14
+340 64 64
+1000 23 26
+163 81 81
+895 12 12
+345 2 0
+117 48 49
+491 32 32
+206 17 17
+439 109 109
+202 6 7
+756 24 24
+380 63 62
+144 48 48
+608 80 80
+154 71 71
+232 16 16
+1809 40 40
+346 53 52
+117 10 0
+383 10 10
+1973 19 19
+879 42 42
+91 50 50
+1147 2 1
+210 68 88
+189 7 7
+595 50 49
+248 104 126
+265 106 106
+167 0 7
+141 93 62
+825 1 0
+348 47 46
+211 3 0
+114 52 56
+66 7 7
+759 48 48
+269 0 1
+106 109 114
+114 38 39
+282 20 20
+504 0 1
+174 14 7
+123 45 46
+82 58 58
+203 12 13
+153 44 44
+121 74 74
+805 43 43
+120 67 68
+171 6 6
+329 20 20
+151 33 33
+71 46 46
+195 25 21
+65 23 42
+96 78 78
+58 0 4
+389 0 3
+214 137 138
+111 2 3
+116 10 10
+128 0 3
+52 8 8
+62 43 43
+142 6 6
+214 0 112
+179 0 1
+234 4 0
+75 116 117
+119 63 67
+286 72 42
+73 150 150
+206 214 220
+73 2 0
+82 48 48
+135 40 67
+115 109 114
+185 49 49
+99 63 63
+52 204 205
+121
+
+chain 2724232 chr10 135374737 + 81309951 81339951 10 135534747 + 81320000 81350000 983
+22137 957 957
+46 77 77
+38 83 83
+51 54 54
+984 53 53
+5520
+
+chain 1898345 chr10 135374737 + 81349952 81369946 10 135534747 + 81360000 81380000 1327
+15902 21 27
+4071
+
+chain 946327 chr10 135374737 + 81339951 81349952 10 135534747 + 81350000 81360000 2894
+6692 1 0
+3308
+
+chain 939763 chr10 135374737 + 81430217 81440202 10 135534747 + 81440000 81450000 3159
+163 3 0
+518 0 16
+972 42 43
+5149 0 1
+3138
+
+chain 928169 chr10 135374737 + 81379935 81389948 10 135534747 + 81390000 81400000 3587
+1970 7 8
+141 10 0
+413 39 39
+622 4 0
+574 42 42
+2153 0 2
+1520 5 3
+2513
+
+chain 922636 chr10 135374737 + 81300280 81309951 10 135534747 + 81310330 81320000 2721
+2989 1 0
+6681
+
+chain 885793 chr10 135374737 + 81369946 81379851 10 135534747 + 81380000 81389916 4570
+507 30 32
+880 91 91
+1155 82 82
+784 10 10
+907 16 28
+1265 50 50
+859 0 3
+1375 1 2
+165 27 27
+124 29 29
+275 8 8
+308 6 0
+79 1 0
+871
+
+chain 839370 chr10 135374737 + 81389948 81399836 10 135534747 + 81400000 81409799 4960
+446 1 0
+639 0 1
+112 140 59
+198 24 22
+98 162 137
+63 10 10
+97 180 192
+71 31 33
+322 38 38
+431 0 1
+741 45 46
+229 1 3
+186 1 4
+3019 14 14
+131 1 0
+722 16 16
+1530 92 92
+32 2 1
+63
+
+chain 788625 chr10 135374737 + 81241464 81249852 10 135534747 + 81251575 81259959 6147
+783 1 0
+883 23 33
+3247 1 0
+143 31 31
+957 15 3
+2304
+
+chain 781678 chr10 135374737 + 81280054 81289770 10 135534747 + 81290109 81299824 3334
+65 841 841
+84 228 228
+27 240 240
+1767 0 10
+186 66 54
+976 0 3
+1495 0 7
+899 0 1
+376 7 7
+2156 10 0
+196 50 50
+47
+
+chain 778944 chr10 135374737 + 81250813 81551219 10 135534747 - 53516479 54101824 544
+53 63 72
+96 209 213
+193 44 44
+202 331 335
+149 28 28
+100 125 123
+56 238 272
+60 91 93
+123 9 11
+66 147 144
+82 210 211
+77 17 17
+196 31 31
+379 27 27
+954 71 71
+69 4431 3721
+746 66 66
+502 12 12
+282 28 28
+224 59 59
+52 35 35
+448 12 0
+474 42 42
+260 11 11
+83 38 44
+160 152 149
+284 76 76
+110 73 73
+284 9 9
+478 110 110
+95 5 5
+583 122 122
+116 1 1
+67 1 1
+118 1 1
+38 1 1
+566 1 1
+35 1 1
+287 1 0
+481 1 1
+42 1 1
+198 1 1
+22 1 1
+54 1 1
+25 1 1
+50 1 1
+50 1 1
+294 4 0
+158 1 1
+31 1 1
+255 8 8
+291 12 12
+171 2 2
+21 1 1
+685 77 77
+817 20 20
+312 39 39
+181 1 0
+249 50 47
+75 7 7
+86 4 4
+54 8 8
+518 134 134
+376 24 26
+189 17 27
+143 13 13
+93 16 16
+192 24 24
+992 140 132
+828 1 1
+40 1 1
+410 1 1
+25 0 2
+13 1 1
+83 8 8
+143 1 1
+20 1 1
+421 1 1
+49 1 1
+107 1 1
+28 1 1
+77 1 1
+32 0 2
+44 2 2
+348 1 1
+53 0 4
+58 1 1
+97 1 1
+125 56 53
+526 1 1
+46 1 1
+209 9 9
+76 1 1
+37 1 1
+53 1 1
+24 1 1
+141 1 1
+26 1 1
+304 1 1
+60 1 1
+199 1 1
+47 1 1
+92 6 0
+138 64 64
+299 65 65
+186 24 24
+631 84 84
+100 20 20
+108 27 27
+240 8134 8243
+50 47 45
+107 11 11
+750 5 5
+230 25 25
+221 62 62
+106 32 32
+106 52 52
+270 56 56
+166 31 31
+89 77 77
+127 666 662
+56 22 22
+55 95 83
+51 30 30
+77 35 35
+189 16 16
+130 53 53
+131 5 5
+158 140 131
+170 21 21
+55 79 79
+207 200 199
+152 11 11
+105 50 50
+104 34 34
+56 402 402
+69 0 1
+61 150 150
+181 10 10
+130 22 22
+180 5 0
+73 161 161
+77 151 151
+68 128 128
+330 138 126
+116 1211 328
+252 4 4
+102 8 8
+72 23 23
+51 51 51
+608 31808 287592
+56 14 14
+161 9 9
+717 46 50
+77 38 30
+83 51 51
+54 984 987
+53 65700 95386
+47 559 556
+99 119 119
+193 38 38
+164 12 7
+59 38 38
+58 9 5
+57 34 34
+68 30 30
+59 28 28
+51 82 87
+142 7 7
+67 162 152
+248 1 2
+114 34 34
+140 22 22
+58 119 118
+143 50 50
+255 69 65
+53 18 18
+127 11 13
+446 39 39
+134 24 24
+143 42 42
+123 65 65
+57 0 3
+199 73 73
+271 17 17
+113 24 24
+203 40 40
+51 38 38
+119 50 50
+81 60 60
+239 85 70
+79 219 219
+64 149 150
+29 211 211
+91 319 310
+76 40 40
+59 596 591
+34 579 579
+51 90 90
+169 336 329
+146 226 226
+50 480 479
+23 66 66
+95 447 447
+49 298 298
+29 180 180
+45 1186 1169
+53 2222 2217
+11 116 116
+33 313 313
+63 75 75
+14 257 258
+31 122 122
+73 311 316
+238 46 46
+130 81 78
+103 262 266
+56 168 163
+29 861 857
+61 655 666
+18 40 40
+436 1 1
+8 4 0
+35 1 1
+417 21 18
+51 2 0
+54 1 1
+126 10 9
+72 5 5
+377 1 1
+18 2 0
+35 2 2
+78 1 2
+18 2 2
+82 1 0
+99 1 1
+82 0 4
+99 1 1
+50 0 4
+50 7 7
+225 11 11
+135 2 0
+326 26 989
+2646 0 1
+560 10 0
+347 114 114
+284 118541 118621
+43 120 120
+65 1 0
+1 677 677
+33 71 71
+46 404 404
+78 661 663
+137 489 492
+43 854 846
+116 119 119
+63 286 286
+72 73 73
+150 206 206
+17 1 1
+85 1 1
+110 157 157
+48 135 135
+36 0 4
+4 115 115
+73 2 0
+19 1 1
+14 185 185
+49 99 99
+22 1 1
+40 79 80
+177
+
+chain 662550 chr10 135374737 + 81399647 81430169 10 135534747 - 46431029 46458544 512
+92 103 101
+125 0 2222
+53 53 50
+58 48 48
+298 191 189
+69 6167 5
+118 101 101
+128 111 111
+207 48 43
+55 175 169
+212 93 89
+159 23 23
+109 34 34
+150 21 20
+258 30 30
+120 51 54
+90 171 171
+268 224 219
+202 62 62
+480 237 237
+394 49 49
+100 28 28
+93 25 25
+52 29 29
+180 45 45
+141 47 47
+56 49 49
+169 39 42
+60 102 113
+53 1 13
+151 105 105
+58 33 30
+88 246 246
+334 116 116
+63 83 84
+268 115 113
+70 43 43
+252 2 1
+62 97 97
+88 6 0
+61 23 23
+84 75 75
+75 2 3
+83 8 8
+53 160 162
+312 153 152
+192 96 98
+122 95 100
+94 793 791
+61 1 5
+154 140 135
+130 32 33
+121 21 21
+82 6 6
+171 34 34
+110 52 49
+129 193 194
+64 26 29
+72 18 18
+286 75 58
+114 6596 7638
+114 284 172
+558 8 9
+111 5 5
+55 2 2
+80 0 1
+27 1 1
+72 1 1
+45 1 1
+516 1 1
+66 1 1
+106 23 42
+64 4 0
+21 1 1
+312 2 2
+30 1 1
+151 20 20
+193 1 1
+38 1 1
+96 6 6
+171 0 3
+27 0 2
+34 2 2
+120 3 3
+39 1 1
+752
+
+chain 650336 chr10 135374737 + 81249915 81259740 10 135534747 + 81260018 81269841 3195
+898 53 53
+63 96 96
+209 193 193
+44 202 202
+331 149 149
+28 100 100
+125 56 56
+238 60 60
+91 198 198
+147 82 82
+210 290 290
+31 1360 1360
+71 69 69
+196 1 0
+454 16 15
+3764
+
+chain 462746 chr10 135374737 + 81440202 81450008 10 135534747 + 81450000 81459803 2861
+1116 4 4
+801 3 0
+2483 369 369
+41 238 238
+71 1291 1291
+42 2400 2400
+37 343 343
+253 278 278
+36
+
+chain 389885 chr10 135374737 + 81290873 81299672 10 135534747 + 81300927 81309722 2802
+25 221 221
+62 106 106
+32 106 106
+52 270 270
+56 166 166
+31 89 89
+77 127 127
+666 133 133
+95 51 51
+30 77 77
+35 335 335
+53 294 294
+103 4 0
+33 246 246
+79 207 207
+200 268 268
+50 104 104
+34 56 56
+402 130 130
+150 601 601
+161 77 77
+151 68 68
+128 330 330
+138 116 116
+1211 512 512
+51
+
+chain 178315 chr10 135374737 + 81400041 81409702 10 135534747 + 81410003 81419664 4252
+32 404 404
+191 168 168
+119 193 193
+38 235 235
+38 124 124
+34 68 68
+30 59 59
+28 51 51
+82 216 216
+162 363 363
+34 220 220
+21 9 9
+89 143 143
+50 255 255
+69 995 995
+42 123 123
+65 256 256
+73 628 628
+40 208 208
+50 94 94
+47 239 239
+85 79 79
+219 64 64
+31 147 147
+72 625 625
+40 271 271
+93 754 754
+30 700 700
+66
+
+chain 157388 chr10 135374737 + 81410627 81419292 10 135534747 + 81420589 81429247 5183
+66 95 95
+53 1136 1136
+46 81 81
+25 268 268
+38 269 263
+105 58 58
+6 0 1
+27 88 88
+34 53 53
+81 32 32
+46 334 334
+116 63 63
+83 268 266
+115 429 428
+97 262 262
+75 757 757
+75 230 232
+41 343 343
+69 47 47
+78 238 238
+46 130 131
+17 36 34
+28 319 319
+46 56 56
+38 707 707
+52 129 129
+132 125 125
+26 376 376
+75
+
+chain 142913 chr10 135374737 + 81466547 81535718 10 135534747 - 46275769 46344990 569
+44 2128 2133
+24 2535 2533
+31 2379 2381
+34 143 143
+43 270 270
+50 1045 1058
+51 494 498
+36 2085 2105
+60 1979 1981
+71 1197 1197
+41 1594 1601
+37 2856 2871
+66 205 205
+50 1339 1339
+33 656 663
+42 805 805
+79 280 275
+56 200 200
+22 18 18
+13 1443 1450
+44 2526 2526
+33 974 974
+75 1489 1489
+47 1658 1653
+53 1652 1653
+41 1071 1071
+59 10705 10669
+57 6434 6441
+25 586 586
+30 178 178
+44 310 310
+74 7 1
+9 1277 1277
+35 5735 5751
+32 2139 2139
+63 3162 3162
+40 346 345
+53 3391 3390
+41 92 92
+50
+
+chain 97392 chr10 135374737 + 81500632 81510012 10 135534747 + 81510451 81519840 3573
+60 191 191
+60 1232 1232
+76 51 51
+152 77 77
+38 536 540
+45 585 586
+39 340 340
+99 1376 1373
+58 517 517
+27 710 710
+58 235 235
+47 72 72
+26 157 157
+43 208 208
+31 630 637
+70 1415 1415
+119
+
+chain 87386 chr10 135374737 + 81512081 81517268 10 135534747 + 81521923 81527111 3288
+161 1034 1034
+35 104 104
+125 613 613
+186 102 102
+205 767 767
+27 231 232
+80 841 841
+68 564 564
+44
+
+chain 81916 chr10 135374737 + 81260486 81269831 10 135534747 + 81270587 81279924 3410
+66 796 796
+28 224 224
+59 52 52
+35 934 925
+42 354 354
+1 0 2
+37 160 160
+121 19 18
+12 284 284
+76 110 110
+73 771 771
+110 683 683
+8 36 35
+78 4099 4100
+77
+
+chain 75208 chr10 135374737 + 81450008 81464865 10 135534747 + 81597933 81612795 1746
+23 1356 1354
+29 166 166
+51 547 547
+30 274 278
+40 1364 1363
+57 169 169
+51 3032 3032
+27 1585 1586
+48 818 818
+32 667 667
+67 1160 1160
+68 752 752
+42 269 269
+51 810 813
+52 76 76
+91 661 661
+31 319 319
+42
+
+chain 71596 chr10 135374737 + 81480667 81490183 10 135534747 + 81490477 81500000 3725
+36 395 395
+36 536 535
+88 519 519
+43 139 139
+80 78 78
+33 117 134
+31 1468 1468
+55 268 268
+97 111 111
+30 6 0
+19 164 164
+38 292 292
+67 2459 2459
+34 2063 2060
+52 136 136
+26
+
+chain 65913 chr10 135374737 + 81470614 81479436 10 135534747 + 81480422 81489246 3085
+36 1955 1955
+26 1450 1450
+97 248 248
+44 223 223
+89 149 149
+32 72 72
+28 86 86
+68 993 993
+49 0 1
+52 319 320
+26 569 569
+33 216 216
+71 1842 1842
+49
+
+chain 63808 chr10 135374737 + 81521220 81529648 10 135534747 + 81531068 81539504 3362
+32 704 704
+56 367 367
+93 596 601
+64 1186 1189
+81 1371 1371
+48 1185 1185
+109 1575 1575
+48 608 608
+80 154 154
+71
+
+chain 58084 chr10 135374737 + 81490258 81499708 10 135534747 + 81500075 81509527 2957
+60 807 808
+44 174 174
+70 135 135
+48 924 924
+25 2943 2943
+43 263 263
+49 1566 1566
+77 243 243
+32 865 865
+87 732 733
+45 183 183
+35
+
+chain 41373 chr10 135374737 + 81540284 81544136 10 135534747 + 81550136 81553982 6087
+47 328 324
+52 832 831
+48 375 375
+79 0 1
+30 114 114
+38 1117 1115
+45 82 82
+58 368 368
+44 121 121
+74
+
+chain 34777 chr10 135374737 + 81464865 81470020 10 135534747 + 81474671 81479828 3724
+26 245 245
+34 44 44
+48 145 145
+12 0 2
+23 90 90
+57 378 378
+41 1468 1468
+56 2453 2453
+35
+
+chain 34249 chr10 135374737 + 81270980 81279755 10 135534747 + 81281073 81289810 4510
+39 431 431
+50 752 752
+134 2175 2167
+44 3025 2995
+35 14 9
+7 2005 2010
+64
+
+chain 29298 chr10 135374737 + 81537077 81539110 10 135534747 + 81546931 81548963 3702
+68 791 797
+50 617 605
+33 0 2
+73 308 311
+93
+
+chain 18939 chr10 135374737 + 81450538 81452241 10 135534747 + 81460333 81462036 3255
+39 70 70
+132 1431 1431
+31
+
+chain 6030 chr10 135374737 + 81422413 81430217 10 135534747 + 81432363 81440000 5582
+26 7730 7563
+48
+
+chain 5154 chr10 135374737 + 81371363 81371422 10 135534747 - 72572913 72572972 4033525
+2 1 1
+56
+
+chain 1569 chr10 135374737 + 81371422 81371454 X 155270560 + 63278348 63278380 8657459
+32
+
+chain 1063 chr10 135374737 + 81231366 81231464 10 135534747 - 54101945 54102043 901
+98
+
+chain 4275918 chr10_random 113275 + 18676 65432 5 180915260 + 138864813 138909803 707
+204 2 0
+4653 4 0
+2427 0 1
+5957 0 1
+1558 1 0
+780 1794 33
+29376
+
+chain 870863 chr10_random 113275 + 9144 18556 10 135534747 - 46779061 46789268 4835
+301 2 0
+564 3 0
+802 1 0
+2624 0 112
+142 0 2
+128 100 787
+4745
+
+chain 637317 chr10_random 113275 + 102183 113228 10 135534747 + 88758795 88768050 8258
+1205 22 22
+793 0 1
+914 1 1
+9 0 1
+45 0 1
+9 2477 1631
+132 1562 615
+2006 1 1
+36 1 1
+557 24 23
+885 0 2
+194 1 0
+171
+
+chain 383436 chr10_random 113275 + 97894 101991 10 135534747 + 88848068 88852165 132306
+2932 0 1
+697 4 3
+464
+
+chain 312568 chr10_random 113275 + 0 3305 10 135534747 + 88861095 88864401 225266
+2905 0 1
+400
+
+chain 263395 chr10_random 113275 + 91858 94672 10 135534747 + 88776474 88779288 339622
+1683 3 3
+130 11 11
+987
+
+chain 254817 chr10_random 113275 + 83066 85798 10 135534747 - 46749813 46752549 368581
+201 0 6
+798 0 1
+403 4 0
+841 14 15
+471
+
+chain 244215 chr10_random 113275 + 5995 97779 10 135534747 + 88818267 88897264 4711
+966 0 1
+2072 66256 15486
+2428 10567 42513
+197 0 1
+820 6 6
+18 1 0
+21 0 1
+20 2 1
+1685 0 2
+703 3020 9053
+1156 0 1
+1846
+
+chain 216530 chr10_random 113275 + 72868 75170 10 135534747 - 93082016 93084318 524441
+2302
+
+chain 211663 chr10_random 113275 + 85898 88144 10 135534747 + 88832831 88835078 546276
+536 0 1
+1710
+
+chain 171789 chr10_random 113275 + 70706 72761 10 135534747 - 93140436 93143121 737133
+50 1 1
+68 85 4
+15 15 34
+17 7 53
+13 1 647
+81 1 1
+50 21 21
+1630
+
+chain 129924 chr10_random 113275 + 67807 109229 10 135534747 - 46627912 46728083 8515
+467 0 1
+256 0 1
+42 1 1
+1352 0 2
+308 10219 43352
+227 1 1
+22 1 1
+2232 22395 48006
+1581 0 2
+518 1 1
+30 1 0
+197 132 132
+1439
+
+chain 125160 chr10_random 113275 + 4561 5895 10 135534747 - 46655374 46656707 1028939
+94 1 0
+1239
+
+chain 104003 chr10_random 113275 + 65554 66651 10 135534747 - 93176760 93177857 1232247
+1097
+
+chain 92361 chr10_random 113275 + 66732 67707 10 135534747 - 93158718 93159693 1382147
+975
+
+chain 89191 chr10_random 113275 + 3509 4486 10 135534747 - 129898314 129899289 1428933
+69 1 1
+35 1 0
+336 1 0
+401 1 1
+44 1 1
+87
+
+chain 29685 chr10_random 113275 + 34270 80352 10 135534747 - 46758431 46763489 186939
+210 0 6
+1251 4 4
+73 42015 985
+1249 1 1
+46 1 1
+1232
+
+chain 4572 chr10_random 113275 + 70436 70610 10 135534747 - 93144449 93144623 2904410
+51 50 50
+73
+
+chain 3114 chr10_random 113275 + 70610 70643 10 135534747 - 93147281 93147314 29780913
+33
+
+chain 12415599352 chr11 134452384 + 50000 134451920 11 135006516 + 60000 134946516 11
+1102759 16576 50000
+49571094 207000 307000
+503352 3000000 3100000
+14395596 2605 50000
+488471 34 102
+26 0 176
+30213 141 350
+27914 1 0
+20009 1 0
+19 1 0
+39 1 0
+17 3 1
+10 1 0
+1008 1 0
+95 1 0
+5127 15 0
+302 1 0
+975 0 4
+1548 0 1
+190 20 0
+41 1 0
+29 1 1
+44 0 1
+101 1 0
+25 0 1
+6178 0 1
+1875 21437 52561
+468 1 1
+81 1 1
+2620 1 0
+1640 4 0
+3305 0 1
+3342 1 0
+17899663 12000 50000
+8549206 15562 150000
+38507165 2 0
+1327 174 0
+392 18 0
+48
+
+chain 188276 chr11 134452384 + 69433462 69437111 GL000202.1 40103 + 7212 10860 1247
+1868 1 0
+1780
+
+chain 38178 chr11 134452384 + 134451288 134452384 5 180915260 - 180902450 180903869 1901368
+174 458 926
+1 8 0
+63 136 1
+64 2 0
+190
+
+chain 6040 chr11 134452384 + 134451996 134452128 1 249250621 - 249240179 249240388 3449013
+89 36 113
+7
+
+chain 2221 chr11 134452384 + 134452085 134452111 Y 59373566 + 59362903 59362929 5436109
+26
+
+chain 4284950 chr11_random 215294 + 0 215294 11 135006516 - 65191297 65289033 706
+40524 167558 50000
+7212
+
+chain 3340892 chr11_random 215294 + 90524 125679 11 135006516 + 69689619 69724695 863
+1003 62 0
+3019 1 0
+695 1 1
+26 1 1
+1133 0 1
+1374 2 2
+20 1 1
+729 11 11
+269 0 1
+1091 14 14
+969 21 21
+532 5 5
+2677 18 0
+21481
+
+chain 3051979 chr11_random 215294 + 175679 208082 GL000202.1 40103 - 0 32891 790
+17546 11 51
+27 523 35
+32 6 6
+6712 100 1036
+7446
+
+chain 10612 chr11_random 215294 + 193466 193615 GL000202.1 40103 - 18116 18265 21504297
+59 27 27
+63
+
+chain 5102 chr11_random 215294 + 91527 91580 11 135006516 + 69690684 69690737 20979070
+53
+
+chain 12330181372 chr12 132349534 + 16000 132289534 12 133851895 + 145739 133779461 12
+7035083 0 4
+544 0 1
+3777 0 1
+3889 73000 52114
+6014 1 0
+6524 168 34
+20974 0 2
+3965 3 0
+444 0 11
+464 1 0
+27577110 1395000 3000000
+38631945 0 1
+14541 0 4
+1703 1 0
+789 250000 12128
+1783 1 0
+1075 0 2
+1042 1 0
+1526 1 1
+27 1 1
+2320 0 1
+166 1 0
+564 0 1
+2856 0 2
+900 0 1
+1387 1 1
+33 1 1
+2139 1 1
+48 1 1
+1305 0 2
+1533 1 2
+879 0 1
+744 26 26
+855 0 4
+1092 6 0
+1114 12 0
+817 1 1
+18 1 0
+217 1 1
+36 1 1
+2002 1 0
+1025 0 1
+450 1 1
+43 1 1
+919 1 0
+18 1 1
+3207 42 42
+1440 0 8
+148 4 0
+3655 2 0
+3403 1 1
+47 1 1
+1524 1 1
+28 1 1
+5561 0 2
+44 0 1
+676 8 8
+810 16 16
+536 2 0
+236 4 0
+167 0 4
+1419 49 53
+4688 1 1
+38 1 1
+18577 5 0
+5284 0 2
+1577 34 34
+4875 1 1
+25 1 1
+4340 0 14
+2663 5 0
+1170 1 0
+4268 0 4
+1036 0 1
+2117 0 8
+5917 1 0
+3239 0 4
+2619 1 1
+21 1 1
+937 1 1
+38 1 1
+2412 0 2
+38 17 0
+2732 0 2
+9314 2 0
+1986 2 2
+16 1 1
+229 1 1
+93 1 1
+895 12 0
+415 1 5
+27 1 1
+78 14 14
+185 8 9
+458 0 2
+89 1 1
+42 1 1
+2034 0 1
+1545 0 2
+280 0 4
+97 14 14
+231 0 2
+2816 5 0
+537 50 50
+1090 1 1
+27 1 1
+25758689 0 1
+6536665 0 1
+377270 57000 96749
+668 1 1
+20 1 0
+3348 1 1
+33 1 1
+648 1 1
+29 1 1
+3732 4 0
+977 46 46
+785 4 0
+34 1 0
+1688 0 10
+4248 1 0
+1167 1 0
+985 9 9
+2897 1 0
+1630 9 0
+1096 0 1
+1356 0 8
+13065723 150011 68363
+799 2 0
+343 0 1
+1771 0 1
+2702 7 6
+1900 1 0
+705 6 0
+303 1 0
+727 1 1
+43 1 0
+3 2 0
+490 1 1
+59 1 1
+226 1 1
+52 3 0
+465 0 8
+194 1 1
+25 1 0
+139 1 1
+15 1 1
+1833 1 0
+81 1 1
+39 1 1
+453 1 0
+719 1 1
+47 1 1
+558 1 0
+838 8 1
+288 10 9
+741 5 2
+465 1 1
+48 1 1
+268 1 1
+26 1 0
+1337 30 48
+84 2 85
+917 1 0
+110 31 31
+1580 1 1
+40 1 1
+683 1 1
+24 1 1
+247 1 1
+36 1 1
+1574 0 1
+10091386 0 3
+296 0 5
+220 45000 100872
+972469
+
+chain 2523 chr12 132349534 + 107924339 107924385 20 63025520 - 54448952 54448998 196257
+46
+
+chain 9007877316 chr13 114142980 + 17918000 114127980 13 115169878 + 19020000 115109878 14
+26987167 1 0
+40753157 50000 150000
+25443670 400000 150000
+1821999 384108 414007
+369878
+
+chain 17589560 chr13 114142980 + 113473994 113658050 13 115169878 - 529930 713796 162
+174857 2 0
+1328 144 0
+1156 1 1
+27 1 1
+2159 2 0
+49 1 1
+175 2 0
+20 4 0
+590 30 0
+163 8 4
+2905 2 0
+430
+
+chain 8677 chr13 114142980 + 113650223 113650314 13 115169878 - 706193 706284 25436870
+91
+
+chain 17750502 chr13_random 186858 + 0 186858 GL000212.1 186858 + 0 186858 156
+186858
+
+chain 8359013040 chr14 106368585 + 18070000 106360585 14 107349540 + 19000000 107289540 15
+1081285 1 1
+43 1 1
+76 2 0
+437 1 1
+19 1 1
+440 12 13
+59 15 15
+63 12 12
+70 0 1
+734 1 1
+165 1 4
+96 1 1
+46 1 0
+83 1 1
+149 4 4
+164 1 1
+18 1 1
+63 15 16
+359 1 1
+39 1 1
+103 1 1
+76 1 1
+139 1 1
+38 1 1
+344 1 1
+65 0 1
+166 5 5
+88 1 1
+66 0 287
+50 1 1
+317 0 1
+52 1 1
+92 4 0
+651 4 4
+82 1 1
+93 1 1
+64 1 1
+24 1 1
+856 1 1
+35 1 1
+258 1 1
+17 1 1
+478 1 0
+1048 70 70
+1279 1 1
+37 1 1
+1115 3 4
+72 1 1
+126 1 1
+102 1 1
+413 10 10
+132 6 6
+89 0 2
+209 15 4
+77 5 5
+427 1 1
+41 1 1
+949 1 1
+16 1 1
+732 1 1
+44 2 0
+128 0 1
+91 1 1
+180 6 6
+388 6 6
+50 13 12
+275 1 1
+33 1 1
+142 1 1
+61 1 1
+560 1 1
+20 1 1
+1327 6 13
+729 37 37
+284 1 1
+44 1 1
+205 0 4
+40 1 1
+352 10 10
+261 1 1
+39 1 1
+940 12 0
+1677 36 0
+159 1 1
+32 8 1
+818 0 6
+580 1 0
+931 1 0
+276 2 0
+3298 45 45
+169 14 0
+46 1 1
+882 2 0
+94 1 1
+49 1 1
+859 4 0
+45 1 1
+807 16 15
+416 0 3
+3345 15 15
+92 30 29
+80 1 1
+48 1 1
+2459 0 1
+646 1 1
+31 1 1
+392 1 1
+29 54 0
+1875 3 0
+141696 1 1
+32 1 1
+8201115 1 0
+107 1 0
+2137 1 1
+39 1 1
+8848 0 1
+4806 1 0
+2075 1 0
+16619 41 40
+2338 3 0
+11507 8 0
+1352 0 1
+4596 0 1
+2073 2 1
+28 1 1
+2311 1 1
+44 1 1
+10440 0 4
+894 0 1
+1641 0 96
+38 9 0
+20 1 1
+2706 6 0
+351 1 1
+25 1 1
+742 0 1
+1048 2 18
+12085977 0 1
+14871228 3 0
+29067652 1 1
+47 1 1
+20174307 1292 0
+2548043
+
+chain 14855 chr14 106368585 + 19159713 19190443 14 107349540 - 87865807 87904514 64
+20 0 6
+50 9933 9915
+37 16916 24930
+30 3690 3692
+25 27 0
+2
+
+chain 6432 chr14 106368585 + 19179765 19190441 22 51304566 + 16377620 16388301 97
+45 10604 10609
+27
+
+chain 7700812247 chr15 100338915 + 18260008 100338915 15 102531392 + 20000000 102521392 16
+8448 6 2
+4086 1 0
+9569 1 1
+40 0 5
+56 7 1
+872419 40441 40448
+553 4 4
+876 0 1
+38 1 1
+139 1 1
+23 1 1
+1881 1 1
+17 1 0
+499 8 8
+310 2 2
+25 11 5
+46 1 1
+78 1 1
+22 0 3
+181 5 6
+569 11 11
+539 1 1
+23 0 4
+261 1 1
+19 0 2
+776 13 15
+62 13 13
+860 1 0
+719 26 0
+1346 1 1
+134 0 1
+30 1 1
+1070 1 1
+21 1 1
+398 0 1
+177 5 21
+534 4 0
+770 0 6
+17 1 1
+606 1 1
+31 1 1
+1861 1 1
+53 1 1
+2169 3 0
+558 1 0
+18 1 1
+227 2 0
+13 1 1
+329 5 5
+430 1 1
+17 2 0
+620 0 1
+1112 2 0
+641 0 4
+476 1 1
+45 1 1
+1285 0 1
+1139 1 1
+47 1 1
+183 4 0
+1435 20 0
+176 0 1
+219 0 1
+607 1 1
+42 1 1
+371 2 8
+507 2 0
+66 1 0
+41 1 1
+999 4 4
+318 15 15
+1092 1 1
+72 1 1
+808 5 5
+54 2 2
+52 1 1
+40 1 1
+109 3 3
+47 1 1
+1535 14 0
+14012 4 0
+7954 4 1
+1350 1 0
+318 1 1
+25 1 1
+600 0 4
+442 0 1
+1396 1 1
+36 1 1
+1107 0 3
+1441 0 5
+360 1 1
+47 1 1
+228 10 0
+37 1 1
+497 1 1
+37 1 1
+2129 4 0
+1242 2 0
+478 4 0
+708 1 1
+90 1 1
+154 10 10
+1583 1 1
+31 1 1
+1302 0 37
+101 14 14
+1138 1 1
+83 10 0
+11 7 0
+111 1 1
+29 1 1
+2917 1 1
+32 1 1
+1762 1 1
+46 1 1
+449 1 0
+2458 9 1
+869 1 0
+534 1 1
+47 1 1
+309 1 0
+6358 22 0
+564 0 1
+1845 1 0
+660 1 1
+25 1 1
+68 1 0
+182 0 9
+54 3 18
+1519 1 1
+32 1 1
+559 1 1
+30 1 1
+3851 1 0
+265 8 7
+240 4474 0
+428 1 0
+1651 11 10
+297 1 0
+665 21 0
+48 1 1
+1763 2 0
+245 1 1
+39 1 1
+519 1 1
+31 1 1
+2398 0 6
+749 49 1
+2074 4 0
+701 5 5
+337 1 0
+470 1 1
+43 1 1
+1163 3 0
+1342 1 1
+43 1 1
+140 0 1
+83 1 1
+24 1 2
+37 1 1
+723 1 1
+36 1 1
+99 3 0
+27 1 1
+92 1 0
+80 43 43
+1095 0 13
+384 0 2
+292 1 1
+39 1 1
+101 12 12
+576 0 2
+1907 1 1
+19 1 1
+318 1 0
+1973 1 1
+32 1 1
+689 1 1
+49 1 1
+357 8 8
+2081 13 13
+260 15 15
+2295 1 1
+24 1 1
+2558 1 1
+26 1 1
+571 16 23
+323 0 1
+36 0 1
+5353 111 0
+1711 38 70
+272 13 13
+1284 0 1
+1128 4 4
+2189 1 0
+474 2 0
+1284 61 67
+643 1 1
+37 1 1
+381 0 2
+56 1 0
+2591 1 1
+55 1 1
+160 4 4
+116 1 1
+89 2 0
+316 0 1
+785 20 0
+152 1 1
+21 1 1
+600 0 6
+568 1 0
+278 1 1
+29 1 1
+89 0 4
+1737 1 1
+58 1 1
+368 24 24
+2113 20 24
+218 0 2
+18 1 1
+684 4 4
+3200 1 1
+31 1 1
+58 18 18
+164 1 1
+37 1 1
+296 6 6
+431 1 1
+35 1 1
+431 1 1
+45 1 1
+93 1 1
+24 1 1
+216 1 1
+46 1 1
+2773 0 17
+751 2 1
+104 1 1
+59 1 1
+445 1 1
+26 1 1
+356 1 0
+1484 1 2
+436 25 25
+306 1 1
+55 1 1
+230 4 4
+892 1 0
+364 7 7
+796 1 1
+26 1 1
+663 0 2
+80 0 15
+4391 1 0
+133 1 1
+25 0 4
+41 0 2
+164 1 1
+61 4 4
+925 3 0
+1882 13 13
+4513 1 0
+111 1 1
+76 1 1
+202 6 0
+680 0 1
+200 3 0
+429 0 2
+736 1 1
+18 1 1
+1573 0 1
+119 1 1
+245 0 9
+11 1 1
+1656 54 22
+616 2 1
+158 0 1
+587 1 1
+39 4 1
+1053 6 6
+1116 1 1
+34 1 1
+152 10 7
+448 0 1
+269024 100000 863295
+334079 100000 50000
+180553 0 74
+66 73 3
+40 1 0
+28 156 73
+202 1 1
+17 0 1
+156 1 1
+55 1 1
+111 0 1
+144 1 1
+57 0 1
+687074 50000 50000
+120647 0 348
+45586 0 1
+6994 1 0
+3398063 44008 12354
+7672 0 2
+1809 1 0
+428524 101014 10165
+43170 4 4
+1064959 128966 5086
+1021 0 1
+1710 1 0
+931 0 2
+4505 0 1
+686 525 2
+432 33 0
+58 20 20
+12369 1014 0
+6233 0 1
+359485 100000 111749
+33855821 0 239
+2852113 1 0
+7040367 0 1
+2815738 3 1
+7055922 60000 50000
+363827 32 32
+104991 0 1
+203136 0 6050
+2271 47 47
+1424473 60000 50000
+13510190 22012 5553
+9194 0 3
+109 0 4
+40 0 1
+43 0 7
+2352 0 13
+5027 0 2
+534 1 0
+794 0 2
+4233 0 2
+5769 1 0
+381 1 0
+2524 0 2
+547 0 5
+1967 0 1
+1207 105 0
+1027 0 6
+3935380
+
+chain 4143271 chr15 100338915 + 19154641 19368514 15 102531392 + 21901264 22115049 110
+40441 8593 8593
+26 89965 89965
+4257 1 1
+30 1 1
+185 16464 16391
+43 29947 29883
+25 1 1
+34 23835 23884
+25
+
+chain 390135 chr15 100338915 + 26478746 26483022 15 102531392 + 28681030 28685306 6048
+1039 22 22
+3215
+
+chain 187810 chr15 100338915 + 26483022 26517556 15 102531392 - 73809068 73843318 79
+41 12 0
+36 1 1
+490 5 5
+285 1 1
+71 1 1
+215 1 1
+53 0 12
+8114 1 0
+10796 15 15
+2483 0 1
+20 1 1
+2048 8856 8847
+163 792 517
+33
+
+chain 51529 chr15 100338915 + 26530390 26530949 15 102531392 + 28731348 28731907 2473877
+450 8 8
+101
+
+chain 17522 chr15 100338915 + 26516748 26516957 15 102531392 + 22658399 22658608 1968
+209
+
+chain 14035 chr15 100338915 + 20378176 20378474 15 102531392 + 22829101 22829399 772378
+73 69 69
+156
+
+chain 12347 chr15 100338915 + 26530060 26530390 15 102531392 + 22671289 22671619 3189077
+244 4 4
+82
+
+chain 5537 chr15 100338915 + 96402403 96402461 15 102531392 + 98585049 98585107 22350382
+58
+
+chain 4486 chr15 100338915 + 96402461 96402508 15 102531392 + 98585002 98585049 16761199
+47
+
+chain 2874 chr15 100338915 + 26517060 26517091 15 102531392 + 28719096 28719127 6634083
+31
+
+chain 2874 chr15 100338915 + 26517029 26517060 15 102531392 + 28719096 28719127 6634084
+31
+
+chain 2874 chr15 100338915 + 26516998 26517029 15 102531392 + 28719096 28719127 6634085
+31
+
+chain 2874 chr15 100338915 + 26516967 26516998 15 102531392 + 28719096 28719127 6634086
+31
+
+chain 2314 chr15 100338915 + 26530003 26530033 15 102531392 + 22671232 22671262 5236
+30
+
+chain 12940492 chr15_random 784346 + 189260 358080 15 102531392 + 28561246 28726591 233
+2522 0 1
+3762 1 1
+40 1 1
+2427 6472 2
+1744 0 1
+263 0 7
+2963 4 4
+1889 1 0
+2501 0 1
+3377 6 6
+5238 0 1
+1277 5 5
+38 1 1
+8232 12 8
+5507 0 18
+155 1 0
+379 14 14
+363 7 13
+336 1 1
+46 1 1
+218 8 8
+1074 0 4
+101 12 13
+178 1 1
+93 1 1
+156 10 11
+398 0 20
+45 1 1
+255 9 10
+2661 0 1
+17 1 1
+82 1 1
+14 1 1
+227 64 64
+1154 1 0
+493 1 1
+39 1 1
+369 1 0
+21 1 1
+322 2 7
+222 0 2
+171 15 0
+81 1 1
+47 1 1
+159 9 9
+154 1 0
+272 4 4
+26 1 1
+121 8 7
+659 1 0
+440 1 1
+35 1 0
+1419 15 0
+181 0 2
+292 0 15
+1767 1 1
+44 1 1
+59 0 1
+910 0 1
+290 1 0
+288 1 0
+567 2 0
+1088 0 1
+1758 1 0
+72 1 1
+21 1 1
+5748 17 17
+800 0 1
+2037 13 13
+113 5 5
+2832 1 1
+44 1 1
+3581 2 0
+33 1 1
+812 5 5
+33 0 1
+257 17 17
+1932 0 14
+168 0 1
+424 5 0
+24 1 1
+67 14 14
+90 1 5
+124 1 1
+34 1 1
+48 0 9
+460 0 8
+294 7 0
+813 1 3
+240 1 0
+511 0 9
+190 1 0
+267 1 1
+38 1 1
+1082 7 57
+21 15 0
+28 0 1
+5 1 1
+123 0 5
+781 1 1
+21 1 1
+390 1 1
+36 1 1
+287 1 1
+90 0 3
+6 2 2
+189 9 9
+263 2 1
+724 13 14
+308 2 0
+1752 1 1
+114 1 1
+236 4 0
+46 1 1
+72 5 0
+1039 1 1
+25 1 1
+403 1 1
+22 1 1
+231 6 6
+834 15 15
+617 1 1
+53 1 1
+243 1 1
+154 3 5
+571 11 16
+231 1 1
+47 1 1
+910 1 1
+45 1 1
+1510 1 1
+79 1 1
+2053 1 1
+48 1 1
+768 8 8
+546 1 1
+19 1 5702
+784 6 0
+275 20 13
+131 114 114
+363 1 1
+46 1 1
+396 1 1
+39 1 1
+75 15 15
+1875 1 0
+332 1 1
+49 1 1
+265 3 2
+55 1 1
+96 1 1
+136 1 0
+305 8 8
+297 0 2
+255 2 2
+23 1 1
+181 19 6
+151 0 1
+707 667 9324
+284 5 3
+73 1 1
+208 26 25
+34 0 773
+80 20 0
+2003 400 125
+163 2 0
+2630 9 1
+19 1 1
+100 12 0
+2421 0 2
+47 21227 0
+853 1 0
+1238 0 12
+3571 1 1
+20 0 1
+2483 15 15
+8803 287 9594
+5992
+
+chain 8627768 chr15_random 784346 + 422939 629603 15 102531392 - 19338638 19927596 385
+168 56 59
+73 4 4
+378 23 23
+868 29 29
+85 1 0
+528 119 5106
+152 31 31
+184 8 7
+322 0 1
+62 46 45
+77 37 46
+80 22 22
+201 45 47
+175 31 33
+1923 82 77
+546 7051 32690
+7810 209 153340
+1308 1 0
+9826 1 0
+1486 1 1
+148 1 0
+76 6 6
+53 36 34
+178 5447 565
+14 14505 121
+72 13 16
+57 1 1
+157 0 2
+11 1 1
+74 1 1
+24 3 3
+220 1 1
+54 1 1
+142 1 1
+82 2 0
+60 4 0
+99 1 1
+106 1 1
+98 1 1
+402 1 1
+79 4 7
+78 1 9
+5 0 1
+31 7 7
+65 1 1
+105 0 1
+22 6 8
+76 10 8
+47 0 1
+39 3 0
+5 1 3
+108 2 2
+61 16307 40121
+676 26 26
+7087 25 25
+20818 7 7
+2750 60358 90388
+69 54 53
+165 166 516
+42 0 42
+81 4 151
+18 0 42
+148 111 112
+73 4 4
+378 23 23
+868 29 29
+85 1 0
+528 8 8
+280 32 34
+426 78 79
+81 648 334
+181 8 7
+485 0 2
+1404 24 24
+101 36 38
+240 8 8
+77 53 54
+347 18 18
+72 9 9
+94 82 82
+384 8 8
+250 108 151474
+1152 0 1
+633 226 12498
+3255 4 0
+58 32 32
+6209 1 1
+30 1 0
+1060 2 0
+3747 4 4
+173 5 5
+2548 0 22
+2275 0 20
+606 41 41
+4653 12 12
+6138 0 1
+148 5 0
+244
+
+chain 3986761 chr15_random 784346 + 0 334816 15 102531392 - 78891064 79878228 248
+30328 8040 15984
+3015 1 0
+70 44499 160931
+52 0 5
+1038 1 1
+29 1 1
+1001 0 18
+680 0 329
+181 1 1
+32 1 1
+839 2 0
+440 0 3
+547 1 0
+278 1 0
+410 1 1
+26 3 0
+101 1 1
+24 1 1
+149 0 9
+179 2 1
+29 1 1
+226 3 0
+21 1 1
+473 10 0
+717 2 0
+1044 1 1
+23 1 1
+625 1 1
+41 1 0
+150 1 1
+62 1 1
+145 59 59
+242 12 12
+179 1 1
+64 1 1
+1405 1 1
+35 0 2
+469 5 0
+401 0 1
+25 0 10
+17 1 1
+55 1 1
+165 1 1
+1966 15 23
+839 0 18
+969 1 1
+44 1 1
+1905 1 1
+47 1 1
+1037 128 128
+486 5 0
+1086 2 1
+199 4 4
+59 2 0
+243 84 0
+410 1 1
+39 1 1
+70 0 324
+77 1 187
+42 4 151
+897 135051 676116
+64 54092 52483
+25 1 1
+88 9286 18277
+201 26614 5202
+33 1 0
+1
+
+chain 2185345 chr15_random 784346 + 423107 689458 15 102531392 + 82637661 83186296 482
+30 0 5
+26 1346 1346
+29 885 5865
+31 576 577
+46 77 77
+5 0 1
+32 303 304
+45 175 176
+31 1923 1923
+66 1943 144683
+715 0 1
+548 13 13
+1907 1 1
+16 1 1
+66 3 0
+1219 5 1
+1066 34012 198199
+7204 2446 2446
+2762 100 7680
+5162 1 0
+2782 1 1
+26 7 4
+49 1 1
+3627 3 0
+1686 133598 65296
+3109 1 1
+21 1 1
+1430 63 63
+335 3 3
+14 4 0
+203 1 1
+23 5 5
+1262 4 4
+323 1 1
+47 1 1
+417 0 1
+537 19 1
+1913 2 0
+1685 6 0
+1740 1 1
+49 1 1
+120 1 1
+30 0 3
+920 4 0
+479 30 30
+1207 1 1
+182 4 0
+72 3 1
+78 1 1
+150 1 1
+46 1 1
+222 1 1
+24 1 1
+74 1 1
+44 1 1
+391 1 1
+33 1 1
+149 9 8
+56 1 1
+30 1 0
+52 1 1
+298 6 0
+22 1 0
+29 1 1
+393 35 0
+145 36 36
+226 15 15
+185 7 7
+692 1 1
+34 1 1
+1291 0 2
+1824 5 5
+1119 1 1
+49 1 2
+1025 25013 44930
+835 88 11347
+692 0 2
+2551 3 0
+1144 82 77
+1939 26 28
+164 1 1
+44 0 2
+201 1 1
+133 5 14
+77 1 1
+44 1 0
+92 1 0
+293 8 7
+184 31 31
+381 8 8
+384 1 1
+80 1 1
+94 9 9
+57
+
+chain 1845967 chr15_random 784346 + 61569 84889 15 102531392 - 73695594 73766494 782
+153 33 33
+49 1 0
+197 15 15
+67 62 62
+241 12 9
+185 41 44
+64 23 23
+559 50 50
+333 46 46
+397 6 6
+141 4 0
+660 50 50
+315 38 38
+282 309 47864
+57 7 7
+85 39 39
+340 62 62
+43 0 1
+77 0 1
+768 0 12
+71 70 69
+102 17 17
+58 45 50
+676 2 0
+430 21 22
+112 0 1
+401 4 0
+617 95 95
+168 50 50
+442 4 0
+91 114 114
+463 0 1
+94 28 28
+1577 16 16
+572 0 1
+1451 55 55
+2327 51 51
+394 1 0
+109 21 24
+660 50 54
+703 1 0
+93 22 22
+94 48 48
+219 46 46
+352 22 22
+150 155 161
+173 19 19
+162 6 12
+1201 48 49
+119 17 17
+435 4 4
+146 38 38
+946 10 10
+98 37 37
+60 47 47
+579
+
+chain 1297748 chr15_random 784346 + 203918 328028 15 102531392 - 73698913 73856126 264
+567 109104 118059
+369 106 23997
+700 2 0
+40 0 248
+320 0 33
+130 1 1
+18 1 1
+138 20 20
+1341 8 0
+863 1 1
+48 1 1
+240 1 1
+34 20 0
+3218 1 1
+20 1 1
+2062 46 46
+285 14 14
+937 1 1
+25 3 3
+305 1 1
+42 1 1
+706 2 0
+232 1 1
+67 1 1
+88 4 5
+844 1 1
+82 1 1
+430 0 7
+78 1 1
+458 27 27
+52
+
+chain 898399 chr15_random 784346 + 457589 504019 15 102531392 - 19636589 19905366 626
+5344 14 14
+7167 26767 249114
+26 7087 7087
+25
+
+chain 844102 chr15_random 784346 + 95554 784338 15 102531392 + 22730405 27183335 411
+59 9906 9932
+128 2128 2090
+42 1792 637909
+89 10 10
+71 198 198
+122 137 141
+341 29 29
+104 103 103
+395 11 14
+667 6 7
+74 7 0
+178 1 5
+203 9 4
+172 55 55
+791 25 25
+714 19 22
+597 133 133
+142 2 0
+252 0 4
+260 67 67
+41 6 0
+860 29 30
+258 93 95
+1793 11 11
+358 71 70
+242 1 1
+20 1 1
+1308 0 3
+468 0 2
+755 1 1
+81 2 2
+72 3 0
+597 4 4
+492 25 7
+1459 10 9
+674 16 16
+711 1 1
+49 1 1
+1525 1 1
+45 1 1
+2919 1 1
+36 1 1
+493 1 1
+21 1 1
+830 16 0
+3 7 0
+644 17 17
+479 0 1
+2343 0 315
+307 8 311
+87 0 3
+330 42 0
+520 7 6
+72 2 1
+745 6 6
+324 6 0
+398 22 22
+118 27 27
+68 600887 3728395
+44872
+
+chain 555121 chr15_random 784346 + 634265 679702 15 102531392 + 82723475 82991213 602
+20 1 1
+41 24204 246463
+2085 6 6
+667 14 14
+596 0 24
+1743 415 422
+870 1 0
+3572 1 1
+1152 8 0
+498 0 1
+3239 1 1
+34 1 1
+1283 1 1
+41 1 0
+676 0 2
+2078 0 1
+1283 0 18
+681 1 0
+223
+
+chain 530253 chr15_random 784346 + 409131 430676 15 102531392 - 19567939 19581201 1716
+786 8 0
+171 8918 159
+2113 8268 8752
+1281
+
+chain 417534 chr15_random 784346 + 35735 80744 15 102531392 + 23413134 23608954 1095
+840 0 54
+916 0 2
+777 3337 13583
+637 50 57
+858 0 4
+779 0 14
+171 1 2
+927 4 0
+1753 2 0
+814 35 35
+1073 14 14
+81 99 101
+66 42 42
+1291 66 66
+240 45 48
+68 36 36
+98 38 38
+1141 5 5
+70 14 15
+150 46 46
+650 13461 153954
+62 1206 1201
+45 3148 3138
+46 6617 6616
+50 2415 2415
+46 615 621
+64
+
+chain 169648 chr15_random 784346 + 417136 418914 5 180915260 + 131590649 131592427 748288
+1778
+
+chain 152639 chr15_random 784346 + 200201 201828 15 102531392 + 28662778 28664407 841936
+970 0 1
+468 5 6
+184
+
+chain 151945 chr15_random 784346 + 110737 203590 15 102531392 - 73700255 73867708 1083
+74 87238 121334
+88 426 14673
+942 2 0
+567 1880 28137
+86 1 1
+62 1 1
+716 14 14
+212 0 1
+468 0 1
+76
+
+chain 142059 chr15_random 784346 + 583198 664057 15 102531392 - 16763491 17663089 651
+176 7 7
+242 7 7
+1002 1 1
+61 1 1
+286 10 10
+1697 57790 716388
+17 1 1
+12 3589 70884
+35 145 145
+36 6576 99374
+431 11 1
+19 0 4
+96 2 0
+98 1 1
+62 1 1
+1047 10 15
+223 1 0
+575 2 0
+465 1 0
+8 1 1
+140 1 4
+65 1 1
+381 5111 5164
+145 1 1
+29 1 6
+32 8 2
+199
+
+chain 140486 chr15_random 784346 + 414032 415531 5 180915260 + 131627050 131628561 916856
+486 0 13
+290 2 1
+721
+
+chain 136843 chr15_random 784346 + 411466 412886 5 180915260 - 49283520 49284940 941594
+1420
+
+chain 113176 chr15_random 784346 + 577887 601700 15 102531392 + 85729223 85793813 754
+51 12 12
+630 1 1
+27 5 5
+51 41 41
+249 505 29710
+148 24 24
+110 0 2
+145 12 11
+646 54 53
+291 404 700
+590 7 0
+154 1 1
+36 5 3
+106 1 1
+42 1 1
+517 181 27
+164 18572 30011
+30
+
+chain 110898 chr15_random 784346 + 410214 411366 5 180915260 - 49350156 49351308 1158024
+1152
+
+chain 90718 chr15_random 784346 + 415631 422839 5 180915260 - 49281425 49321173 523505
+1405 4191 36723
+57 0 4
+785 0 4
+770
+
+chain 87628 chr15_random 784346 + 412986 413908 15 102531392 + 82958289 82959211 1453275
+922
+
+chain 78489 chr15_random 784346 + 408080 408895 5 180915260 + 131628738 131629553 1616335
+815
+
+chain 75848 chr15_random 784346 + 328894 334289 15 102531392 + 28663807 28669202 22165
+415 0 1
+219 14 14
+716 1 1
+62 1 1
+1820 1 0
+432 1 1
+21 1 1
+549 1 1
+42 1 1
+1098
+
+chain 55946 chr15_random 784346 + 579203 582900 15 102531392 - 19568187 19572180 874
+256 1085 1091
+54 291 291
+49 100 396
+255 1464 1453
+62 1 6
+80
+
+chain 50039 chr15_random 784346 + 328288 328894 15 102531392 - 73792653 73793260 1678654
+449 99 100
+58
+
+chain 41737 chr15_random 784346 + 53223 55079 15 102531392 - 79138743 79140590 1899
+987 5 0
+378 4 0
+30 1 1
+324 1 1
+36 1 1
+89
+
+chain 40184 chr15_random 784346 + 35650 52319 15 102531392 + 23578289 23604839 1865
+85 6507 16388
+50 5309 5309
+35 1168 1168
+99 66 66
+42 1291 1291
+66 240 240
+45 68 68
+36 98 98
+38 1380 1380
+46
+
+chain 36402 chr15_random 784346 + 63654 139260 15 102531392 + 20712328 20743651 996
+46 46877 2371
+29 5894 5886
+28 261 261
+55 0 3
+35 2163 2163
+70 17110 17298
+32 0 42
+10 2220 2218
+27 68 68
+335 31 31
+315
+
+chain 33407 chr15_random 784346 + 63271 84310 15 102531392 + 28567817 28636450 784
+50 2730 50298
+39 1361 1355
+70 2485 2497
+95 168 168
+50 618 618
+33 8782 8789
+48 4472 4485
+38
+
+chain 26884 chr15_random 784346 + 71527 84203 15 102531392 + 23434933 23447596 1313
+28 3628 3632
+43 3563 3545
+38 1762 1762
+91 1625 1625
+17 1 1
+30 721 722
+38 1054 1054
+37
+
+chain 17994 chr15_random 784346 + 577754 595591 15 102531392 + 82746005 82941680 2345
+133 777 777
+41 8083 152910
+1120 114 33023
+47 1 1
+5 265 681
+66 293 293
+111 2277 2277
+32 585 587
+5 0 1
+25 0 1
+6 1 0
+11 3164 2847
+53 540 540
+82
+
+chain 17584 chr15_random 784346 + 334305 334490 15 102531392 - 73868107 73868292 12488910
+185
+
+chain 16638 chr15_random 784346 + 334590 334767 15 102531392 + 28693782 28693959 13398527
+177
+
+chain 15574 chr15_random 784346 + 203754 203918 15 102531392 + 20713399 20713563 2884965
+164
+
+chain 11941 chr15_random 784346 + 112567 138945 15 102531392 + 28572611 28599524 1070
+24 791 791
+25 2119 2124
+57 23331 23861
+31
+
+chain 10106 chr15_random 784346 + 307857 307966 15 102531392 - 73812018 73812127 6634519
+109
+
+chain 9879 chr15_random 784346 + 198177 198415 15 102531392 + 28709863 28710101 596395
+238
+
+chain 5493 chr15_random 784346 + 34234 34291 Y 59373566 + 27644447 27644504 32044688
+57
+
+chain 4133 chr15_random 784346 + 323293 323339 15 102531392 + 22666870 22666916 2166
+46
+
+chain 4016 chr15_random 784346 + 328237 328288 15 102531392 + 28668851 28668902 1790991
+51
+
+chain 3958 chr15_random 784346 + 107733 107775 15 102531392 - 78958306 78958348 1193
+42
+
+chain 3427 chr15_random 784346 + 198013 198049 15 102531392 + 20714128 20714164 4212128
+36
+
+chain 3014 chr15_random 784346 + 591545 685196 15 102531392 - 19431434 19585695 819
+47 89045 149655
+87 4422 4422
+50
+
+chain 2874 chr15_random 784346 + 307826 307857 15 102531392 - 73812018 73812049 6634520
+31
+
+chain 2855 chr15_random 784346 + 198147 198177 15 102531392 + 28831982 28832012 6776371
+30
+
+chain 2097 chr15_random 784346 + 200178 200201 15 102531392 - 79852957 79852980 911500
+23
+
+chain 1855 chr15_random 784346 + 307785 307816 15 102531392 + 28688468 28688499 5960032
+31
+
+chain 1291 chr15_random 784346 + 110710 110736 15 102531392 - 73822377 73822403 1552683
+26
+
+chain 1093 chr15_random 784346 + 687136 688443 15 102531392 - 19508634 19509938 742
+25 1251 1248
+31
+
+chain 7474990131 chr16 88827254 + 0 88822254 16 90354753 + 60000 90294753 17
+172342 0 1
+112 1 0
+5627 2 1
+8398838 17500 50000
+25336229 100000 150000
+1112651 9800000 11100000
+42003582 20000 50000
+1855370
+
+chain 9963354 chr16_random 105485 + 0 105485 16 90354753 + 29712462 29819360 326
+5589 7 8
+6783 0 218
+41 1 3
+38 1 1
+234 9 9
+219 46 0
+15 0 50
+3818 0 1
+1090 1 1
+45 1 1
+308 1 0
+524 0 4
+984 1 1
+24 1 0
+970 0 2
+106 1 1
+25 2 1
+436 0 5
+296 1 1
+23 2 0
+813 0 1
+1173 1 0
+5500 1 0
+1193 16 16
+1329 0 1
+2727 0 1
+3622 0 13
+3844 3 0
+5076 0 1
+4157 2 0
+178 0 2
+126 1 1
+344 5 6
+497 1 0
+620 7 7
+378 0 1
+669 24 25
+211 1 5
+453 0 11
+176 0 1
+486 0 8
+326 1 0
+2143 40 9
+2337 0 1
+866 1 0
+10 2 2
+1366 1 1
+44 1 1
+831 1 1
+45 1 1
+1612 6 5
+3801 0 1
+910 0 2
+486 0 1
+2775 1 0
+1083 1 0
+1793 1 1
+50 0 1
+1339 0 2
+145 17 17
+651 10 10
+1140 0 1
+724 1 1
+39 1 1
+3261 1 0
+1513 0 9
+606 22 0
+2027 27 19
+3470 11 0
+4100 3 0
+2045 0 4
+1047 0 1
+6647 78 1279
+748
+
+chain 7369813928 chr17 78774742 + 0 78653129 17 81195210 + 0 81060000 18
+252627 1 1
+24 1 1
+33 0 29
+566 87 0
+116 58 0
+92 29 0
+79 8 37
+485 1 59
+28 1 1
+76 233 1
+27 29 0
+2764 17 20
+2220 18 18
+837 1 1
+39 1 1
+564 1 1
+14 1 1
+2523 39 9
+1824 0 56
+76 29 0
+1681 0 1
+414 0 3
+256 0 68
+119 10 10
+290 0 4
+3193 1 0
+2562 0 4
+1809 3 0
+84 1 1
+62 1 1
+3703 0 27
+2041 16 0
+911 0 2
+696 4 4
+1428 15 15
+290 1 0
+1779 0 1
+60 1 1
+216 0 1
+375 1 1
+41 0 1
+9221 46522 100000
+3080543 0 1
+1208216 0 2
+1370 2 0
+1279 0 4
+322 0 5
+5661 210 0
+307 21 22
+973 8 0
+2901 1 0
+8479 0 1
+4122 7 0
+3187 4 0
+571 0 1
+167 0 1
+10174 7 7
+856 2 1
+1630 1 0
+4258 3 1
+1688 1 0
+264 0 304
+796 1 0
+8494 0 10
+2273 1 0
+8297 1 0
+1500 1 4
+733 2 2
+40 1 0
+4 0 1
+15 19 1
+64 1 253
+22 0 34
+18 1 205
+2070 2 0
+2981 14 13
+1309 0 1
+3991 3 0
+1939 0 3
+887 0 2
+463 18 0
+64 0 3
+2104 0 20
+556 0 4
+121 0 1
+3670 2 0
+4345 0 5394
+5334 0 1
+2505 4 10
+6776 14 11
+9573 0 1
+1136 0 2
+3754 1 0
+4588 1 0
+637 17 17
+1285 8 0
+369 0 1
+2084 1 0
+492 2 0
+517 0 4
+954 0 2
+1517 1 0
+958 9 0
+807 14 14
+357 0 10
+3611 0 2
+3191 0 39
+742 1 0
+646 2 0
+2211 1 0
+14829 1 0
+3465 11 0
+31 0 33
+833 16 16
+1345 0 1
+6443 5 4
+2627353 1 0
+11581979 0 43
+25 0 89
+238783 0 1
+1830653 1 0
+419873 100008 116477
+5587 6 0
+11056 0 2
+3240 1 0
+1237 0 2
+373 1 1
+43 1 1
+558379 100000 3000000
+1823446 0 1
+2728383 0 1
+29 0 1
+138 1 0
+144 6 8
+38 0 2
+7 0 1
+18 1 1
+70935 10 13
+52 28 31
+189 0 1
+41 2 2
+750363 44 44
+4038953 100000 50000
+1524006 1 1
+47 1 1
+231 2 0
+1175 1 0
+555 1 1
+49 1 1
+568 7 0
+605 2 0
+4954 1 1
+18 6 7
+567 0 1
+421 2 0
+943 75 67
+777 0 3
+925 3 0
+5 4 0
+318 1 0
+230 20 13
+244 1 1
+13 0 1
+42 1 1
+220 1 1
+56 1 1
+101 225 0
+1113 1 0
+17 1 1
+2614 4 0
+3186 50 50
+3872 0 2
+617 14 0
+5674 0 2
+1852 1 1
+63 1 1
+56 1 1
+25 1 1
+332 0 6
+423 5 5
+61 4 0
+108 1 1
+46 1 1
+160 2 2
+72 1 1
+162 1 1
+20 1 1
+53 1 1
+63 1 1
+112 1 1
+59 1 1
+5885 2 0
+255 36 36
+6246 1 1
+114 1 1
+255 1 1
+49 1 1
+210 1 1
+138 157793 28603
+927 5 0
+212 7 7
+641 17 17
+1296 46 46
+2513 71 69
+76 1 2
+61 50226 0
+1959 18 18
+2727 22 22
+6616 1 0
+5109 68 86
+2450 7 7
+50 10 0
+3439 0 4
+4179 0 4
+2749 0 1
+1124 8 0
+56 1 1
+1840 14 14
+624 8 0
+1743 4 0
+3689 0 4
+2051 0 1
+751 0 1
+2111 10 11
+3110 1 0
+682 1 0
+2795 5 2
+241 0 1
+165 1 3
+1258 0 1
+1602 5 0
+3715 0 1
+1308 0 1
+2058 1 0
+1624 0 1
+478 4 0
+9 6 0
+35 3 1
+47 0 1
+2425 1 0
+1178 0 4
+33 1 1
+415 5 5
+887 1 3
+946 29 29
+630 15 0
+259 2 0
+78 0 1
+4570 0 1
+322 1 0
+1801 2 0
+836 3 0
+1509 0 1
+1732 0 1
+935 0 6
+1372 1 0
+625 2 12
+5009 1 1
+75 0 1
+20 1 0
+153 20 21
+489 4 326
+1375 1 0
+774 1 1
+16 1 1
+3642 5 0
+497 4 0
+174 9 0
+1317 0 3
+508 0 1
+1126 1 0
+1952 0 2
+565 2 0
+871 0 1
+1460 6 0
+55 0 1
+420 6 0
+57 1 1
+119 1 1
+427 1 0
+459 14 11
+448 0 1
+1275 7 7
+360 1 0
+73 1 1
+48 1 1
+4920 3 0
+713 41 34
+691 1 1
+44 1 1
+1642 9 10
+566 0 1
+173 0 4
+798 0 10
+810 1 0
+78 18 17
+1531 0 2
+1274 1 1
+39 1 1
+53 3 1
+202 0 1
+707 17 17
+1733 0 1
+14053 3 0
+286 3 1
+5600 4 0
+6458 0 1
+4866371 102000 0
+1870113 257 0
+590050 6 18
+2095 12 12
+24846 1 0
+5154 22 22
+1561 0 4
+5946 1 0
+2317 0 4
+1643 1 1
+27 1 1
+1237 1 0
+2698 1 1
+140 1 1
+1689 0 2
+836 29 30
+5333 1 0
+509 1 0
+5216 6 0
+10782 47 47
+1095 13 3
+1039 0 1
+11605 1 0
+22064 0 1
+16612 8 0
+902 1 0
+757 1 0
+619 0 1
+10979 1 1
+18 1 1
+1517 1 0
+4576 1 0
+12559 4 0
+2725 0 1
+5291 2 0
+8706 0 1
+83 1 0
+424 0 7
+72 38 0
+5528 1 0
+23971 1 0
+7855 54 22
+4095 0 1
+803 5 5
+6382 6 0
+3545 0 28
+4265 0 2
+13194 6 6
+6463 1 0
+26075 1 1
+59 1 1
+10791 17 7
+707 0 1
+210 1 0
+1655 0 2
+5301 1 0
+1930 1 0
+14632 2 0
+1043 1 0
+3607 3 0
+312 0 1
+5953 2 0
+170 0 17
+489 0 1
+5260 0 28
+888 10 0
+2461 10 10
+237 2 0
+1716 3 1
+10691 0 4
+3757 1 0
+6173 0 1
+8017 1 2
+3594 0 4
+5439 0 1
+4138 28 57
+6418 0 1
+1267 1 0
+720 0 6
+1083 2 0
+3878 0 1
+3310 23 23
+4349 1 1
+44 1 1
+3135 0 1
+174853 1 2
+2008 7 7
+5657 0 1
+6496 0 3
+89 0 5
+665 0 1
+954 46 46
+375 7 8
+1248 28 28
+2041 0 2
+2753 1 0
+1863 0 3
+3228 1 0
+3575 0 4
+40 1 1
+6488 0 2
+8612 11 11
+3795 0 16
+2105 0 1
+268 1 1
+22 3 0
+7889 4 0
+701 4 0
+2411 28 34
+2943 2 3
+8420 1 0
+926 0 324
+6732 1 0
+543 4 3
+4028 2 0
+51 52 40
+3000 1 0
+530 1 0
+2083 0 2
+1173 0 17
+119 16 16
+2727 1 0
+543 0 1
+783 1 0
+1372 0 4
+8624 20 0
+278 44 44
+4364 51 50
+2856 0 1
+5399 0 1
+1506 1 0
+919 0 6
+7229 10 0
+3225 1 0
+435 1 0
+2814 47 47
+1577 0 132
+9785 0 1
+2035 6 0
+7655 1 0
+198207 0 132
+11704 0 5
+7648 1 0
+9062 4 0
+8778 0 2
+7014 1 0
+1613 0 2
+790 7 5
+7433 1 0
+6482 12 12
+6798 0 1
+1422 1 0
+3454 1 1
+43 1 1
+3097 0 2
+334 0 18
+1444 1 0
+2400 3 0
+3272 0 1
+9106 1 0
+1573 0 1
+4742 1 0
+3366 1 0
+5484 0 1
+2444 0 5
+5448 8 8
+2539 0 1
+1471 0 1
+238 1 1
+16 1 1
+288 5 5
+2995 0 2
+951 1 1
+35 1 1
+279 16 15
+3534 6 0
+3513 0 1
+163 0 1
+6173 0 1
+1074 1 0
+2818 1 0
+2868 0 1
+3796 1 0
+1118 1 167
+1278267 25 25
+10747172 0 217
+3504877 0 1053
+10844 13 11
+18805 1 0
+1960834 126729 50000
+3065 1 0
+3601036 90008 8833
+34292 1 0
+1834 0 44
+3083 1 1
+43 1 1
+789 1 0
+11432680 153000 50000
+1902015 0 4098
+99 0 21
+3183 6 6
+877 1 1
+49 1 1
+296 0 1
+1375 1 1
+21 1 1
+607 5 5
+98 0 22
+6811 1 1
+17 0 11
+3804 1 0
+1356 1 1
+29 1 1
+297 1 0
+9543 0 2
+3130 0 4
+861 0 1
+27346 1 0
+7547 8 6
+2834 0 2
+394 4 0
+6524 1 0
+405 11 8
+1128 7 0
+271 1 1
+21 0 28
+507 6 0
+1211 44 31
+384 0 3
+521 18 18
+395 11 0
+799 1 1
+25 3 2
+51 1 49
+49 1 1
+558 0 1
+351 1 0
+2779 13 13
+114398 65008 82124
+7795 0 1
+18 1 1
+4140 1 0
+28048 1 1
+32 1 1
+4630 1 0
+4573 3 0
+357 2 0
+4812 1 0
+14372 0 3
+203 0 1
+26257 1 0
+2734 0 2
+19262 5 5
+5022 0 1
+25471 0 1
+1114538 0 53
+82 126 0
+1416 16 16
+629 57 0
+463 1 0
+148 1 1
+24 1 1
+2322 1 1
+23 1 0
+725 0 16
+24 16 0
+95 9 9
+1277 0 1
+2498 0 1
+354 49 0
+41 0 50
+17 0 49
+37 0 49
+65 8 152
+906 0 47
+234
+
+chain 3352932 chr17 78774742 + 33364384 33585329 17 81195210 - 44852585 44945131 363
+36 7017 7017
+2072 1 1
+16 1 1
+2167 2 0
+2513 1 1
+44 1 1
+1296 17 17
+860 5 0
+1482 0 11
+3433 1 1
+18 1 1
+393 0 3
+198 19 18
+1850 4 5
+267 1 0
+1125 6 7
+1255 1 0
+1502 0 1
+37 0 1
+26 0 1
+302 0 1
+1164 4 2
+1145 8 8
+1170 0 1
+298 1 2
+330 1 0
+2433 13 13
+79 0 2
+5343 1 1
+26 1 1
+994 1 3
+943 0 3
+2485 1 1
+22 1 1
+1574 129212 0
+265 54 54
+5225 26 26
+995 36 36
+240 1 0
+5900 61 61
+112 65 65
+53 14 14
+150 95 95
+160 48 48
+108 70 66
+401 0 6
+354 27 27
+56 65 65
+716 5 3
+1097 4 0
+518 27 27
+944 11 11
+579 37 37
+614 1 0
+2967 12 0
+601 1 10
+1307 35 35
+1719 0 889
+1973 0 3
+709 2 0
+496 5 1
+185 11 11
+98 1 0
+724 3 0
+2103 0 5
+1038 0 1
+257 7 0
+231 1 0
+312 0 2
+423 6 6
+520 10 13
+294 1 0
+17 1 1
+413 4 0
+1698 1 1
+46 1 1
+597 1 1
+21 1 1
+1182 0 2
+50 1 1
+44 0 2
+34 66 3
+3318 3 0
+624 7 0
+507 0 1
+60 1 1
+49 1 1
+332 1 1
+38 1 1
+77 1 1
+19 1 1
+65 1 0
+1174 5 0
+76
+
+chain 1309281 chr17 78774742 + 33410392 33424757 17 81195210 + 36336024 36350387 1779
+203 116 116
+6522 2 0
+5195 584 584
+1743
+
+chain 421642 chr17 78774742 + 33424760 33429230 17 81195210 - 44789041 44793512 103557
+258 1 0
+320 0 1
+3477 0 1
+414
+
+chain 288364 chr17 78774742 + 33534894 33553104 17 81195210 + 60335980 60353933 1564
+39 403 82
+124 31 31
+264 17 18
+283 79 89
+146 36 36
+392 27 27
+75 32 32
+295 106 106
+170 1 0
+69 35 35
+148 57 57
+152 23 23
+96 16 16
+594 57 58
+172 87 87
+108 39 39
+156 68 68
+148 63 63
+54 9 9
+39 289 289
+30 13136 13189
+45
+
+chain 141893 chr17 78774742 + 38701721 38703214 17 81195210 + 41346194 41347687 907641
+1493
+
+chain 138910 chr17 78774742 + 59795041 59797994 3 198022430 + 46191235 46194190 927459
+65 140 139
+77 32 32
+50 53 53
+51 108 111
+72 86 86
+65 76 76
+109 74 74
+120 2 0
+121 111 111
+69 23 23
+101 39 39
+56 40 40
+294 20 20
+65 100 100
+105 124 124
+147 116 116
+64 108 110
+70
+
+chain 73899 chr17 78774742 + 33536708 33552896 17 81195210 + 36333128 36349315 1571
+27 75 75
+32 306 306
+95 240 240
+35 148 148
+57 881 881
+57 172 172
+87 108 108
+39 156 156
+68 148 148
+63 6667 6667
+36 6153 6152
+49 112 112
+64 239 239
+74
+
+chain 29385 chr17 78774742 + 33422514 33422962 17 81195210 + 60352539 60352987 2653
+73 72 72
+133 53 53
+117
+
+chain 28843 chr17 78774742 + 33535172 33536316 17 81195210 + 34740000 34741144 3516
+164 124 124
+31 564 564
+79 146 146
+36
+
+chain 23419 chr17 78774742 + 40573363 40573608 17 81195210 - 37977034 37977279 7093437
+245
+
+chain 22267 chr17 78774742 + 59795106 59797450 15 102531392 + 100960318 100962666 927477
+74 509 513
+86 250 250
+74 1061 1061
+100 108 108
+82
+
+chain 19110 chr17 78774742 + 33422430 33422845 17 81195210 + 34807497 34807912 5737
+84 73 73
+72 133 133
+53
+
+chain 15302 chr17 78774742 + 59872221 59872543 X 155270560 + 133327972 133328295 14745200
+91 145 146
+86
+
+chain 15089 chr17 78774742 + 33553212 33554185 17 81195210 + 34758015 34758988 3454
+70 755 755
+27 56 56
+65
+
+chain 12559 chr17 78774742 + 41846587 41875489 17 81195210 + 44708735 44737620 783
+44 4372 4365
+43 24396 24386
+47
+
+chain 12028 chr17 78774742 + 253252 253513 17 81195210 + 253455 253745 1186280
+87 116 116
+26 30 59
+2
+
+chain 9840 chr17 78774742 + 59850421 59850563 12 133851895 - 30785452 30785594 23191844
+56 27 27
+59
+
+chain 8117 chr17 78774742 + 33410595 33410681 17 81195210 + 34744635 34744721 10477
+86
+
+chain 7470 chr17 78774742 + 59872141 59872220 8 146364022 - 25940938 25941017 21166303
+79
+
+chain 6548 chr17 78774742 + 59823421 59823489 9 141213431 + 108396482 108396550 29214974
+68
+
+chain 6212 chr17 78774742 + 33601781 33601849 17 81195210 + 34807429 34807497 5781
+68
+
+chain 6147 chr17 78774742 + 33578902 33578968 17 81195210 + 34784578 34784649 3380
+29 0 5
+37
+
+chain 5883 chr17 78774742 + 33556525 33558123 17 81195210 + 34761324 34762919 3874
+27 1534 1531
+37
+
+chain 5739 chr17 78774742 + 59862459 59862519 13 115169878 + 43436593 43436653 31343618
+60
+
+chain 5729 chr17 78774742 + 59852430 59852489 7 159138663 - 42785228 42785287 31366016
+59
+
+chain 5493 chr17 78774742 + 254397 254454 17 81195210 + 254136 254193 32044913
+57
+
+chain 5493 chr17 78774742 + 254339 254396 17 81195210 + 254136 254193 32044914
+57
+
+chain 4633 chr17 78774742 + 59795405 59797489 7 159138663 + 22571262 22573349 985966
+53 1992 1995
+39
+
+chain 3684 chr17 78774742 + 59871978 59872017 5 180915260 + 67132991 67133030 32368210
+39
+
+chain 3604 chr17 78774742 + 59872312 59872350 6 171115067 + 73766967 73767005 18649321
+38
+
+chain 3578 chr17 78774742 + 59797823 59797921 9 141213431 - 46000791 46000889 1219359
+98
+
+chain 3496 chr17 78774742 + 59872079 59872141 X 155270560 - 52661918 52661980 17303862
+62
+
+chain 3063 chr17 78774742 + 59796390 59796453 18 78077248 + 3738092 3738155 1007405
+63
+
+chain 2832 chr17 78774742 + 78651772 78651801 17 81195210 + 81058451 81058480 35013371
+29
+
+chain 2507 chr17 78774742 + 254312 254338 17 81195210 + 254167 254193 28153285
+26
+
+chain 2327 chr17 78774742 + 253481 253511 17 81195210 + 253858 253888 2965414
+30
+
+chain 2229 chr17 78774742 + 59795509 59795562 9 141213431 + 99971007 99971060 1163412
+53
+
+chain 2158 chr17 78774742 + 59871912 59871978 10 135534747 - 7120285 7120351 17475521
+66
+
+chain 2116 chr17 78774742 + 41755737 41755765 17 81195210 - 18330211 18330239 723
+28
+
+chain 2038 chr17 78774742 + 59872018 59872072 12 133851895 - 60047857 60047911 21673207
+54
+
+chain 1971 chr17 78774742 + 33410681 33410711 17 81195210 + 58084086 58084116 2335
+30
+
+chain 1910 chr17 78774742 + 59797697 59797752 7 159138663 - 95523915 95523970 1276958
+55
+
+chain 1797 chr17 78774742 + 59795569 59795617 8 146364022 - 39560190 39560238 1234503
+48
+
+chain 1764 chr17 78774742 + 59795840 59795881 17 81195210 - 78142303 78142344 1077161
+41
+
+chain 1713 chr17 78774742 + 59797636 59797671 10 135534747 - 112842234 112842269 1000659
+35
+
+chain 1680 chr17 78774742 + 59795180 59795214 3 198022430 + 108471362 108471396 1315432
+34
+
+chain 1591 chr17 78774742 + 59795881 59795916 X 155270560 - 139019545 139019580 1025236
+35
+
+chain 1456 chr17 78774742 + 59796656 59796685 6 171115067 + 121488440 121488469 989186
+29
+
+chain 1332 chr17 78774742 + 33532356 33535172 17 81195210 + 34572150 34574966 5130
+25 2722 2722
+69
+
+chain 1250 chr17 78774742 + 59795215 59795246 11 135006516 - 104930893 104930924 1222490
+31
+
+chain 1089 chr17 78774742 + 59795324 59795355 X 155270560 - 141145732 141145763 1311664
+31
+
+chain 1006 chr17 78774742 + 59797671 59797695 X 155270560 + 72606434 72606458 1154867
+24
+
+chain 622 chr17 78774742 + 33334125 33344374 17 81195210 - 46414201 46424210 397
+69 10130 9890
+50
+
+chain 20335446 chr17_random 2617613 + 224588 1377183 17 81195210 - 41910550 46712950 133
+1433 3 0
+976 0 1
+281 0 1
+1231 0 14
+2584 0 15
+2816 1 0
+3815 1 0
+122 1 1
+25 1 1
+335 0 1
+4687 29 0
+68 0 1
+1769 32 0
+616 3 0
+1017 1 1
+35 1 1
+864 17 17
+321 4 4
+47 1 1
+6467 8 10
+746 1 0
+188 30 0
+179 14 14
+120 1 1
+19 1 1
+477 1 1
+25 1 1
+300 5 5
+33 4 4
+968 6 6
+1546 1 1
+39 1 1
+66 1 1
+92 1 1
+349 12 12
+839 3 3
+36 1 1
+654 1 1
+88 1 1
+647 3 0
+993 10 8
+296 0 12
+183 4 4
+385 1 1
+25 1 1
+405 1 1
+29 1 1
+108 1 1
+36 1 1
+57 1 1
+88 2 1
+78 4 4
+39 1 1
+133 1 1
+133 1 1
+162 1 8
+398 14 14
+52 16 16
+122 1 1
+56 1 1
+98 1 1
+25 1 1
+332 1 1
+48 1 1
+83 0 1
+25 1 1
+71 1 1
+71 1 1
+79 4 0
+87 1 1
+207 1 1
+70 1 1
+263 16 16
+143 1 1
+72 1 1
+198 0 1
+1062 104 0
+6 61 0
+278 8 8
+454 49 49
+297 0 1
+1271 1 1
+48 1 1
+85 1 1
+66 1 1
+89 1 0
+327 1 1
+61 1 1
+51 1 1
+25 2 2
+72 1 1
+80 1 1
+132 1 1
+136 4 4
+63 1 1
+47 1 1
+134 1 1
+28 1 1
+1004 1 1
+45 1 1
+2017 1 1
+22 1 1
+778 8 0
+3805 0 4
+3884 1 0
+1082 1 1
+39 1 1
+926 1 0
+12182 105 0
+19079 4 0
+108 0 6
+81968 13 12
+5894 126 0
+5069 696334 2698100
+65 1 1
+31 0 1
+165 15 0
+2504 0 2
+1155 0 10
+463 1 0
+2422 0 1
+90 10 0
+75 0 1
+397 0 1
+64 31 32
+1531 4 0
+2064 0 1
+1305 1 0
+1045 0 1
+1972 0 1
+3554 0 2
+428 1 0
+1541 10 12
+1808 1 0
+1758 0 1
+500 1 0
+737 1 0
+218 0 1
+2132 0 1
+744 0 1
+7456 2 0
+45 0 2
+2311 23 23
+727 0 2
+916 1 0
+360 5 5
+2956 0 1
+3263 3 0
+1460 1 1
+34 1 1
+117 1 0
+1852 10 0
+50 7 7
+3949 42 42
+528 40 40
+736 100 17954
+680 119199 29667
+516 22 22
+2397 100 1694896
+1291 0 4
+232 1 1
+32 1 1
+1529 0 4
+20 2 0
+42 0 2
+94 0 10
+402 1 1
+16 1 1
+1099 1 1
+49 1 1
+2223 32 32
+1530 36 36
+1563 57608 84063
+160 94 94
+164 108 108
+123 61 61
+136 449 449
+3509 28 28
+1092 1 0
+611 1 1
+28 1 1
+2932 1 1
+52 49 45
+64 1 1
+27 1 1
+1320 1074 0
+6819 0 1
+4716
+
+chain 16836081 chr17_random 2617613 + 2022361 2536424 17 81195210 + 77630507 81150656 169
+143 0 4
+116 4 4
+74 12 10
+298 1 0
+533 1 0
+340 27 27
+130 16 16
+184 15 14
+699 1 0
+68 1 0
+153 1 0
+1835 1 0
+5 2 0
+95 1 0
+105 6 4
+14 1 0
+10 1 0
+88 1 0
+63 1 0
+27 1 0
+37 1 0
+18 1 0
+75 1 0
+49 2 0
+366 1 0
+206 1 0
+114 1 0
+237 1 0
+265 16 12
+223 1 0
+182 1 0
+26 1 0
+34 1 0
+138 1 0
+170 1 0
+26 1 0
+16 1 0
+53 4 2
+85 1 0
+188 1 0
+107 1 0
+31 1 0
+180 1 0
+4 2 1
+4 1 0
+16 1 0
+21 1 0
+324 1 0
+106 2 0
+46 1 0
+74 1 0
+12 1 0
+557 2 0
+194 5 2
+23 1 0
+67 6 3
+7 1 0
+50 1 0
+143 1 0
+190 1 0
+24 1 0
+310 1 0
+204 1 0
+108 1 0
+15 1 0
+212 1 0
+3 1 0
+57 4 2
+44 1 0
+298 1 0
+38 1 0
+54 1 0
+112 1 0
+20 2 0
+79 1 0
+10 6 3
+12 1 0
+59 1 0
+51 1 0
+234 2 0
+43 1 0
+194 1 0
+5 1 0
+96 9 4
+67 2 0
+270 1 0
+13 1 0
+59 1 0
+54 1 0
+57 1 0
+375 1 0
+50 1 0
+87 1 0
+83 4 2
+234 4 2
+44 1 0
+24 7 4
+25 1 0
+44 1 0
+139 1 0
+201 12 9
+215 1 0
+5 1 0
+30 1 0
+43 1 1
+54 16 13
+210 1 0
+109 2 0
+55 1 0
+14 1 0
+126 1 0
+79 1 0
+326 1 0
+18 1 0
+150 1 0
+13 1 0
+85 1 0
+47 1 0
+16 1 0
+41 1 0
+43 5 3
+56 1 0
+62 1 0
+164 1 0
+108 1 0
+20 2 0
+137 1 0
+214 1 0
+14 1 0
+5 2 0
+60 5 3
+24 1 0
+72 2 0
+25 1 0
+23 1 0
+60 1 0
+53 1 0
+15 1 0
+145 1 0
+337 1 0
+112 1 0
+39 1 0
+234 1 0
+7 2 0
+108 1 0
+19 1 0
+150 1 0
+22 5 3
+221 1 0
+30 1 0
+195 1 0
+126 1 0
+116 1 0
+189 1 0
+231 1 0
+87 2 0
+136 2 0
+69 1 0
+350 1 1
+29 1 0
+76 1 0
+42 1 0
+10 3 1
+63 1 0
+168 1 0
+97 1 0
+11 1 0
+291 1 0
+150 1 0
+10 1 0
+141 15 12
+9 1 0
+35 1 1
+57 1 0
+9 2 0
+211 1 0
+193 1 0
+51 1 0
+337 1 0
+94 1 0
+9 1 0
+58 1 0
+152 1 0
+58 1 0
+127 1 0
+6 1 0
+65 1 0
+379 1 0
+93 1 0
+11 1 0
+106 1 0
+545 1 0
+11 1 0
+66 2 0
+28 1 0
+242 4 2
+32 8 5
+373 10 9
+242 1 0
+207 1 0
+51 1 0
+132 1 0
+118 1 0
+19 2 0
+116 1 0
+16 1 0
+23 1 0
+54 1 0
+67 1 0
+62 1 0
+52 10 7
+15 2 0
+33 1 0
+248 1 1
+27 1 0
+122 1 0
+25 1 0
+55 1 0
+141 1 0
+57 1 0
+45 1 0
+21 1 0
+66 4 2
+23 1 1
+234 1 1
+25 2 2
+56 1 0
+34 1 0
+12 1 0
+11 1 0
+5 1 0
+54 1 0
+16 1 0
+64 1 0
+361 1 1
+24 1 0
+111 1 0
+12 1 0
+74 1 0
+56 1 0
+43 1 0
+21 1 0
+8 1 0
+13 2 0
+34 1 0
+59 1 0
+79 1 0
+159 1 0
+69 2 0
+15 2 0
+8 1 0
+142 19 17
+302 1 0
+49 1 0
+114 1 0
+72 1 0
+38 1 0
+16 1 0
+39 1 0
+106 1 0
+16 3 1
+31 1 0
+5 1 0
+43 1 0
+120 1 0
+16 1 0
+82 1 0
+47 4 1
+10 6 3
+59 1 0
+10 1 0
+258 1 0
+97 14 13
+72 1 0
+126 1 0
+14 1 0
+92 1 0
+406 1 0
+194 1 0
+43 1 0
+30 1 0
+50 1 0
+8 1 0
+161 6 4
+39 1 0
+12 1 1
+60 1 0
+61 1 0
+23 1 0
+13 1 0
+41 2 0
+260 1 0
+144 1 0
+38 1 0
+45 1 0
+17 1 0
+73 1 0
+64 20 13
+25 1 0
+84 1 0
+42 11 6
+180 1 0
+32 2 0
+172 0 1
+65 1 0
+53 1 0
+39 3 1
+203 1 0
+16 3 1
+42 3 2
+27 6 4
+13 1 0
+99 1 0
+34 4 2
+511 1 0
+182 1 0
+230 8 3
+42 1 0
+16 1 1
+270 5 4
+13 1 0
+141 1 0
+100 1 0
+144 1 0
+146 1 0
+356 1 0
+99 1 0
+69 2 0
+146 1 0
+55 18 14
+54 7 4
+18 1 0
+170 2 0
+45 1 0
+13 1 0
+628 1 0
+93 1 0
+46 1 0
+131 1 0
+20 1 0
+98 1 0
+20 1 1
+355 0 2
+88 1 0
+121 1 0
+31 1 0
+27 1 0
+132 1 0
+64 1 0
+43 1 0
+30 1 0
+95 1 0
+22 1 0
+44 6 3
+20 1 0
+138 1 0
+198 1 0
+100 1 0
+163 1 0
+6 1 0
+155 1 0
+79 1 0
+34 1 0
+193 1 0
+159 1 0
+50 5 3
+30 1 0
+9 1 0
+115 1 0
+93 1 0
+54 1 0
+91 1 0
+336 1 0
+134 18 13
+126 1 0
+61 1 0
+133 1 0
+613 4 2
+244 1 0
+586 1 0
+5 1 0
+93 19 16
+148 6 3
+12 2 1
+20 1 1
+138 102 11399
+572 8 6
+529 1 0
+659 1 1
+35 1 0
+191 2 0
+56 1 0
+105 1 0
+18 1 0
+226 1 0
+59 15 16
+275 1 0
+87 1 0
+5 1 0
+85 1 0
+21 1 0
+71 1 0
+507 1 0
+21 3 1
+82 1 0
+32 1 0
+39 1 1
+312 1 0
+263 1 0
+196 5 3
+23 5 3
+275 1 0
+46 2 0
+154 0 6
+229 1 0
+27 1 0
+87 1 0
+5 2 0
+502 1 0
+97 105 101
+162 1 0
+114 1 0
+65 1 1
+43 1 0
+217 1 0
+14 1 0
+172 1 0
+326 1 0
+9 1 0
+446 1 0
+73 1 0
+245 2 0
+114 1 0
+237 1 0
+35 22 13
+318 1 0
+320 1 0
+76 1 1
+54 1 0
+44 1 1
+100 1 0
+30 0 1
+462 1 0
+22 1 1
+72 1 1
+121 1 0
+37 1 0
+22 5 0
+23 1 1
+154 1 0
+63 1 1
+87 1 0
+278 1 0
+36 1 1
+230 1 0
+182 3 1
+51 1 0
+7 1 0
+101 1 0
+39 1 0
+17 1 0
+55 1 0
+13 1 0
+114 1 0
+13 1 0
+24 1 1
+69 10 9
+171 1 0
+60 1 1
+77 1 1
+8 2 1
+25 1 0
+51 1 0
+327 1 0
+105 2 0
+133 0 1
+28 1 0
+67 1 0
+119 4 2
+334 1 0
+37 2 1
+47 1 0
+165 1 0
+29 1 0
+35 1 0
+46 1 0
+9 1 0
+657 1 0
+62 1 0
+171 1 0
+17 1 0
+113 1 0
+15 1 1
+123 1 1
+62 1 0
+4 1 1
+288 21 0
+809 0 1
+22 1 0
+61 1 0
+52 1 0
+25 2 0
+263 3 1
+35 1 0
+192 238701 2061422
+87 1 0
+6 1 0
+1080 1 0
+76 1 0
+1007 1 0
+98 1 0
+35 1 0
+134 1 0
+285 1 0
+33 0 1
+225 1 0
+281 1 0
+108 1 0
+55 1 0
+107 1 0
+202 15 12
+111 1 0
+36 2 0
+25 1 0
+202 1 0
+97 1 0
+143 1 1
+21 1 0
+222 1 0
+41 1 0
+492 0 4
+594 1 0
+181 1 0
+410 1 0
+37 1 0
+13 1 0
+34 1 0
+76 38 37
+204 27 27
+204 40 32
+432 1 0
+143 1 0
+271 1 0
+224 96 91
+385 1 0
+337 1 0
+375 1 0
+139 22 17
+297 1 0
+72 1 0
+5 2 0
+193 1 0
+8 1 0
+28 1 0
+17 1 0
+17 1 0
+445 1 0
+169 1 36
+35 3 1
+425 1 0
+41 1 0
+37 1 0
+79 1 0
+100 1 0
+130 1 0
+419 1 0
+17 1 1
+284 3 1
+56 1 0
+9 2 1
+655 1 0
+158 2 0
+8 1 0
+34 1 1
+519 1 0
+39 1 0
+78 1 0
+216 1 0
+3 1 0
+68 1 0
+56 1 0
+70 1 0
+290 0 4
+46 0 2
+108 0 2
+23 0 114
+830 1 0
+136 76 98
+63 65 64
+380 1 0
+106 1 1
+358 1 0
+64 1 1
+17 1 0
+171 5 3
+27 1 1
+130 13 10
+131 1 0
+415 1 0
+5 1 0
+37 1 0
+29 1 0
+27 1 0
+750 1 0
+249 1 0
+221 1 0
+109 1 0
+50 1 0
+323 1 0
+296 1 0
+383 1 0
+67 1 0
+239 2 0
+248 1 0
+9 1 0
+180 1 0
+241 1 0
+40 3 1
+6 1 0
+19 1 0
+27 1 0
+166 1 0
+80 1 0
+163 1 0
+33 1 0
+9 1 0
+172 1 0
+261 1 0
+200 1 0
+14 6 2
+121 1 0
+37 4 2
+74 1 0
+97 5 3
+10 2 1
+51 1 0
+642 1 0
+317 14 11
+163 3 1
+25 2 0
+875 1 0
+128 1 0
+211 8 4
+409 1 0
+233 1 0
+263 1 0
+12 1 0
+73 1 0
+188 1 0
+96 1 0
+183 1 0
+126 1 0
+235 1 1
+68 0 1
+618 1 0
+13 1 0
+73 1 0
+1315 883 57
+78 2 2
+774 1 0
+21 1 0
+13 1 0
+9 2 0
+168 1 0
+214 1 0
+84 3 1
+645 1 0
+150 1 0
+72 1 0
+8 1 0
+108 1 0
+120 1 0
+1469 1 0
+38 1 0
+697 1 0
+44 1 0
+345 1 0
+126 1 0
+46 1 0
+110 1 0
+972 1 0
+104 23 22
+93 2 2
+38 1 0
+34 3 1
+730 1 0
+151 1 0
+124 1 0
+210 1 0
+60 1 0
+227 1 0
+122 1 0
+225 2 0
+26 1 0
+85 1 0
+84 6 3
+408 1 0
+5 3 1
+18 1 0
+69 1 0
+76 1 0
+122 1 0
+288 1 0
+10 1 0
+55 1 0
+22 2 0
+455 1 0
+246 1 0
+37 1 0
+153 1 0
+27 1 0
+101 1 0
+158 1 0
+107 1 0
+437 1 0
+31 1 0
+149 1 0
+121 1 0
+5 1 0
+175 1 0
+76 1 0
+75 1 0
+26 2 0
+98 1 0
+169 1 0
+82 1 0
+20 1 0
+326 1 0
+274 1 0
+78 1 0
+42 1 0
+64 1 0
+11 7 4
+39 1 0
+91 1 0
+140 1 0
+397 14 12
+500 7 4
+879 5 2
+448 1 0
+42 1 0
+522 1 0
+247 1 0
+484 1 0
+689 1 0
+66 1 0
+198 1 0
+441 1 0
+143 1 0
+35 1 0
+84 1 0
+9 1 0
+445 1 0
+110 1 0
+204 1 0
+31 1 0
+77 1 0
+54 1 0
+213 1 0
+601 1 0
+25 1 0
+239 2 2
+42 1 0
+29 2 0
+15 1 0
+175 1 0
+611 1 0
+418 1 0
+191 1 0
+295 1 0
+30 8 5
+609 1 0
+372 1 0
+154 2 0
+117 1 0
+282 1 0
+360 1 0
+750 1 0
+402 1 0
+45 1 0
+678 1 0
+17 1 0
+117 1 0
+148 1 0
+164 3 1
+51 1 0
+65 1 0
+452 1 0
+1443 1 0
+142 1 0
+509 1 0
+92 10 6
+264 1 0
+69 1 0
+78 1 0
+43 1 0
+164 1 0
+349 1 0
+117 1 0
+373 1 0
+235 1 0
+160 1 0
+8 1 0
+263 1 0
+15 1 0
+23 1 0
+151 1 0
+100 1 0
+204 1 0
+250 1 0
+33 3 1
+272 1 0
+262 1 0
+55 1 0
+519 1 0
+251 1 0
+189 1 0
+459 1 0
+183 1 0
+295 1 0
+552 1 0
+94 16 12
+259 1 0
+30 1 0
+396 1 0
+17 1 0
+72 1 0
+56 1 0
+90 1 0
+106 1 0
+19 2 0
+271 1 0
+448 1 0
+628 497 497
+254 26 26
+391 1 0
+32 1 0
+171 1 0
+126 20 17
+94 1 0
+446 1 0
+30 1 0
+96 1 0
+17 1 0
+159 1 0
+390 1 0
+105 1 0
+94 1 0
+5 2 0
+21 1 0
+22 1 0
+380 1 0
+12 1 0
+211 1 0
+377 1 0
+3 1 0
+63 1 0
+37 2 2
+1596 1 0
+638 1 0
+30 1 0
+665 13 10
+32 1 0
+102 1 0
+361 1 0
+609 1 0
+590 1 0
+1189 29 29
+345 1 0
+732 1 0
+544 1 0
+272 1 0
+725 1 0
+198 1 0
+8 1 0
+275 1 0
+95 1 0
+101 1 0
+626 1 0
+154 1 0
+242 1 0
+937 1 0
+142 1 0
+236 1 0
+456 12 9
+77 1 0
+189 1 0
+172 1 0
+201 1 0
+417 1 0
+179 1 0
+141 1 0
+219 1 0
+164 1 0
+138 1 0
+500 2 0
+263 1 0
+48 1 0
+17 1 0
+91 1 0
+169 1 0
+8 1 0
+185 1 0
+48 1 0
+345 1 0
+546 2 2
+229 2 2
+614 1 0
+73 2 2
+129 1 0
+91 1 0
+287 3 1
+504 2 0
+264 22 22
+508 1 0
+1324 1 0
+1313 1 0
+36 1 0
+346 1 0
+285 5 2
+31 1 0
+6 1 0
+133 1 0
+27 1 0
+101 1 0
+249 1 0
+68 5 3
+34 1 0
+31 1 0
+140 1 0
+350 1 0
+312 1 0
+139 1 0
+66 1 0
+24 1 0
+37 1 0
+16 1 0
+32 1 0
+204 1 0
+21 1 0
+11 1 0
+120 2 0
+161 1 0
+13 1 0
+143 1 0
+46 1 0
+136 3 1
+75 1 0
+176 1 0
+23 1 0
+30 1 0
+34 1 0
+307 1 0
+27 1 0
+261 1 0
+39 1 0
+995 1 0
+556 1 0
+211 1 0
+278 1 0
+850 1 0
+285 1 0
+207 1 0
+154 1 0
+51 1 0
+237 1 0
+204 1 0
+11 1 0
+348 2 0
+41 1 0
+75 2 0
+47 1 0
+49 1 0
+253 1 0
+171 10 6
+106 1 0
+83 1 0
+86 1 0
+30 1 0
+166 1 0
+297 1 0
+480 1 0
+285 1 0
+339 1 0
+30 1 0
+74 1 0
+15 1 0
+310 1 0
+88 1 0
+111 1 0
+104 1 0
+644 1 0
+29 1 0
+413 2 0
+33 3 1
+19 1 0
+321 1 0
+318 1 0
+131 1 0
+111 1 0
+89 1 0
+751 120 120
+314 1 0
+613 2 0
+991 3 1
+44 1 0
+42 1 0
+57 1 0
+102 1 0
+318 1 0
+47 2 0
+186 1 0
+550 1 0
+504 1 0
+76 1 0
+336 1 0
+505 1 0
+34 2 0
+61 1 0
+257 1 0
+439 1 0
+94 1 0
+18 1 0
+6 1 0
+86 1 0
+18 1 0
+179 1 0
+52 1 0
+635 1 0
+535 1 0
+90 1 0
+531 2 0
+59 1 0
+132 1 0
+122 1 0
+17 1 0
+96 1 0
+281 1 0
+145 1 0
+342 1 0
+132 1 0
+95 16 12
+417 1 0
+143 1 0
+135 1 0
+11 1 0
+486 1 0
+224 1 0
+277 1 0
+449 1 0
+321 34 30
+96 1 0
+20 1 0
+358 1 0
+146 1 0
+176 1 0
+37 1 0
+92 1 0
+115 1 0
+245 1 0
+72 1 0
+65 1 0
+108 1 0
+41 13 10
+121 65 54
+54 1 0
+359 1 0
+53 1 0
+55 1 0
+10 1 0
+5 1 0
+6 2 1
+43 1 0
+9 1 0
+223 1 0
+90 1 0
+157 1 0
+686 1 0
+250 1 0
+160 1 0
+264 50363 1224780
+4948 0 1
+1850 60 67
+3859 0 1
+456 4 5
+1605 21 21
+1281 7 13
+5090 456 0
+1543 1 1
+37 1 1
+2825 1 1
+64 1 1
+1075 0 1
+721 0 1
+5566 22 5
+1136 1 0
+2390 0 3
+1347 0 2
+4617
+
+chain 16543266 chr17_random 2617613 + 0 174588 GL000205.1 174588 + 0 174588 172
+174588
+
+chain 10747371 chr17_random 2617613 + 1609852 1757206 17 81195210 - 15050606 15196423 297
+3573 1 0
+1031 1 0
+4890 10 7
+318 0 1
+667 1 0
+168 0 2
+974 2 0
+143 2 0
+208 4 0
+2621 10 10
+634 2 0
+1898 0 2
+99 21 21
+6731 1 1
+49 1 1
+345 2 0
+210 1 1
+1621 1 0
+1077 0 2
+371 6 0
+4548 5769 26131
+1148 0 1
+1283 1 1
+24 1 0
+2931 0 6
+38 22 0
+682 0 1
+1267 0 2
+470 9 19
+2335 0 9
+720 8 0
+2859 26315 4346
+4414 0 1
+777 1 4
+894 4 0
+3207 0 3
+3071 0 1
+1338 1 0
+869 1 0
+2072 0 1
+395 1 0
+1060 8 8
+1138 1 1
+6 2 0
+40 1 1
+473 0 1
+748 2 0
+306 8 0
+81 6 0
+748 4 0
+158 0 22
+6454 0 2
+145 1 1
+49 1 1
+619 0 1
+1579 14 14
+455 1 0
+5224 1 1
+31 1 0
+31 0 57
+3855 0 2
+2164 11 21
+1491 0 4
+213 16 4
+4589 6 6
+1564 0 6
+325 0 1
+2241 0 1
+149 0 1
+4150 0 4
+4768 0 12
+411 0 6
+804 2 0
+124 19 19
+937 2 0
+997 27 29
+685 37 37
+5 2 0
+35 37 48
+29 1 1
+237 2 0
+333 0 1
+1296 31 23
+472 4 0
+34 1 1
+683
+
+chain 7797784 chr17_random 2617613 + 2131554 2212864 GL000204.1 81310 + 0 81310 420
+81310
+
+chain 5191141 chr17_random 2617613 + 986480 1282720 17 81195210 + 34482891 34744119 309
+118 29 29
+73 435 3450
+113 9 9
+74 44 43
+109 53 55
+147 361 38
+603 128 128
+69 8 8
+278 22 22
+1262 20 20
+83 37 44
+478 1 1
+32 1 1
+54 1 1
+81 1 1
+57 0 1
+71 4 4
+83 1 1
+103 1 1
+80 1 1
+15 1 1
+312 15 15
+185 1 1
+24 1 1
+720 1 1
+19 1 1
+185 1 1
+35 1 1
+144 7 7
+238 1 1
+62 3 3
+196 10 10
+123 1 1
+99 1 1
+1997 1 1
+27 1 1
+64 49 45
+19 1 1
+547 1 1
+16 1 1
+796 0 2
+213 0 1
+1353 0 5
+59 1 1
+604 1 0
+1099 28 28
+2219 0 1
+1732 6 6
+115 1 1
+80 1 1
+123 1 1
+106 1 1
+164 1 1
+92 1 1
+160 34984 45270
+79 5 5
+348 149 150
+73 23 23
+322 46 46
+284 35 28
+1307 16 16
+515 89 89
+62 9 9
+203 3 0
+65 10 9
+188 33 32
+342 1 0
+100 0 1
+67 48 52
+69 1 0
+2330 39 42
+356 2 0
+767 5 9
+69 4 0
+373 29 30
+138 1 0
+571 0 1
+273 13 13
+140 25 24
+457 39 39
+204 19 19
+137 49 49
+178 59 59
+220 38 38
+66 23 22
+315 1 0
+399 30 30
+345 62 62
+200 36 36
+1097 33 35
+255 5 0
+61 4 0
+371 48 33
+119 30 30
+52 0 2
+236 0 2
+81 13 13
+168 12 12
+174 0 1
+250 81 81
+185 35 35
+343 27 35
+271 232 235
+79 116 119
+288 61 61
+869 9 8
+282 7 0
+6366 1 0
+2033 112 1128
+417 0 1
+64 145492 5631
+587 0 2
+184 392 14227
+792 0 4
+408 2 1
+1608 0 1
+1287 0 2
+676 1 1
+31 1 1
+112 1 1
+91 1 1
+173 1 0
+42 1 14
+784 11 11
+3219 0 13521
+8127 24 23
+7132 0 12
+9450 0 4
+3351 28 28
+5832 3 0
+100 0 1
+67 0 5
+31 6 5
+10 1 1
+69 2 0
+2314 1 0
+11507 0 1
+742 0 63471
+5695 0 1
+731 1 0
+3536
+
+chain 4342758 chr17_random 2617613 + 615163 663282 17 81195210 - 81146986 81195210 699
+117 89 88
+430 1 1
+8 7 3
+19 1 1
+521 14 7
+577 1 0
+4 1 0
+284 1 1
+19 12 6
+55 3 0
+193 1 0
+383 16 13
+508 5 0
+404 6 1
+1326 31 25
+723 84 3
+41 75 0
+21 1 0
+303 27 0
+65 81 27
+94 1 1
+40 1 1
+118 746 87
+30 2 1
+37 1 1
+179 2 0
+43 1 1
+46 27 0
+35 32 0
+278 1 0
+353 8 10
+363 13 1
+106 4 0
+188 34 34
+206 1 0
+3 1 0
+1339 1 0
+632 1 1
+21 0 4
+248 1 0
+655 1 0
+258 1 0
+777 1 0
+1440 16 16
+124 1 1
+36 1 0
+33 1 1
+89 1 0
+165 1 0
+86 1 1
+47 1 1
+319 8 4
+506 4 2
+537 16 12
+2310 1 0
+7 2 0
+922 9 0
+294 1 0
+145 1 0
+1890 2 0
+15 1 0
+38 1 0
+2030 12 6
+1208 2 0
+107 1 0
+438 2 0
+492 2 0
+184 1 0
+42 1 1
+646 1 35
+28 4 4
+62 4 36
+43 0 32
+54 1 1
+8 2 0
+23 1 1
+77 0 32
+34 0 32
+52 1 167
+69 70 6
+61 0 36
+99 0 64
+605 22 22
+133 1 0
+296 1 1
+42 1 0
+361 10 6
+225 14 14
+387 1 97
+405 0 480
+101 1 0
+24 2 2
+339 0 336
+1176 1 0
+192 1 0
+553 1 0
+114 4 1
+544 18 12
+575 3 0
+85 1 0
+934 1 0
+667 13 7
+28 18 12
+770 10 6
+149 1 0
+884 22 20
+214 0 1
+607 1 0
+129 1 0
+14 6 4
+27 6 3
+10 1 0
+4 2 0
+155 39 28
+214 2 0
+43 1 1
+1236 44 27
+1759 2 0
+472 6 2
+342 8 5
+970 6 0
+227 1 0
+691 1 0
+359 2 0
+141 1 0
+5 1 0
+2008 1 0
+302
+
+chain 3923033 chr17_random 2617613 + 864624 922266 17 81195210 + 81075742 81117538 762
+924 1 0
+428 1 0
+763 1 0
+19745 32 32
+637 15873 36
+186 1 0
+2389 1 0
+616 1 0
+1932 12 12
+10081 18 18
+2216 1 0
+92 1 0
+271 4 4
+67 5 5
+698 83 82
+473 27 27
+62
+
+chain 3905383 chr17_random 2617613 + 460666 565054 17 81195210 + 41343520 41406910 763
+9362 3 1
+1313 0 1
+344 1 0
+2289 0 2
+14919 0 1
+1393 6 4
+1047 1 0
+21 0 1
+31 5511 0
+28 783 8
+978 3 4
+213 0 2
+2198 0 702
+75 4479 3549
+723 0 13
+165 1 1
+19 3 3
+113 0 4
+88 1 1
+41 1 0
+38 7 7
+98 17 17
+152 50743 16221
+115 169 185
+169 0 4
+278 1 1
+48 1 1
+6399
+
+chain 3524656 chr17_random 2617613 + 1876393 1913891 GL000203.1 37498 + 0 37498 830
+37498
+
+chain 3296870 chr17_random 2617613 + 1963891 2002673 GL000204.1 81310 + 42877 81310 872
+560 1 0
+101 2 0
+296 42 39
+438 2 0
+256 1 0
+136 1 0
+109 1 0
+101 2 0
+234 64 62
+405 37 35
+61 1 0
+366 5 3
+501 39 37
+142 1 0
+191 27 24
+59 6 4
+53 67 62
+91 1 0
+159 1 0
+74 40 38
+164 1 0
+57 28 26
+75 1 0
+46 1 0
+61 45 43
+117 1 0
+360 45 43
+204 1 0
+180 61 58
+589 1 0
+212 1 0
+88 1 0
+53 1 0
+492 1 0
+75 26 24
+273 1 0
+701 1 0
+444 1 0
+75 1 0
+393 11 9
+105 59 56
+72 42 40
+79 1 0
+79 1 0
+95 153 144
+127 1 0
+85 4 2
+175 3 0
+222 1 0
+121 1 0
+48 1 0
+50 1 0
+61 1 0
+213 1 0
+73 1 0
+180 2 0
+83 1 0
+58 1 0
+192 11 5
+57 140 125
+101 1 0
+91 38 34
+190 1 0
+73 1 0
+116 6 4
+275 16 14
+200 1 0
+201 3 1
+632 1 0
+60 1 0
+198 9 1
+254 2 0
+89 1 0
+60 38 36
+326 32 28
+306 1 0
+55 1 0
+100 18 16
+127 36 32
+67 1 0
+78 1 0
+90 1 0
+63 35 31
+120 150 141
+103 9 7
+406 88 85
+54 15 13
+142 9 7
+112 32 30
+237 1 0
+114 27 18
+157 40 38
+145 1 0
+380 20 18
+73 109 104
+57 1 0
+83 68 65
+567 1 0
+378 0 4
+282 29 27
+725 1 0
+204 1 0
+246 1 0
+295 17 15
+243 1 0
+187 46 44
+56 1 0
+244 1 0
+303 1 0
+121 16 15
+253 1 0
+273 44 44
+427 10 0
+403 2 0
+219 1 0
+151 1 0
+115 14 13
+193 1 0
+63 1 0
+63 38 36
+609 1 0
+81 42 40
+297 1 0
+455 17 14
+278 3 1
+691 1 0
+417 104 101
+57 1 0
+93 5 3
+309 48 47
+303 1 0
+324 1 0
+126 41 37
+138 2 0
+233 1 0
+100 50 47
+86 9 7
+256 1 0
+208 1 0
+486 3 1
+118 1 0
+70 69 64
+455 8 6
+149 1 0
+175 5 2
+115 1 0
+159 1 0
+109 12 9
+135 33 31
+53 1 0
+256 5 3
+82 41 38
+268 70 67
+600 1 0
+128 18 16
+114 1 0
+149 62 58
+99 57 54
+158 42 38
+88 1 0
+75 46 43
+300 50 47
+71 13 11
+118 1 0
+177 1 0
+120 1 0
+275 1 0
+74 13 11
+230 1 0
+117 6 4
+113 39 37
+71 1 0
+597 9 8
+82 10 6
+195 10 8
+361 1 0
+53 1 0
+291 0 1
+149 1 0
+164
+
+chain 2935078 chr17_random 2617613 + 1427191 1457644 17 81195210 + 81045288 81075743 955
+1667 2 0
+1156 0 2
+25 0 2
+27603
+
+chain 2199778 chr17_random 2617613 + 671651 748529 11 135006516 - 134809692 134880676 533
+53 3 0
+176 68 0
+22 38 1
+38 43 16
+122 41 249
+34 4 16
+5 1 0
+6 1 0
+68 0 37
+1042 1 1
+35 1 1
+27 326 0
+359 1 0
+3 2 0
+176 16 5
+44 5 1
+224 1 0
+432 1 1
+35 1 1
+266 21 16
+109 14 10
+806 0 34
+465 56 0
+57 4 0
+787 1 0
+283 1 1
+27 1 1
+1090 1 1
+81 1 0
+1354 1 0
+40 1 1
+305 1 0
+89 1 1
+63 1 1
+48 1 1
+167 11 11
+83 8 4
+45 5 3
+343 1 1
+47 49 0
+56 0 294
+17 49 0
+79 5 103
+162 49 0
+442 10 10
+438 3 0
+50 1 1
+676 1 1
+39 1 1
+66 1 1
+7 1 0
+35 1 1
+547 7 2
+549 2393 0
+3 2913 0
+65 1 0
+60 1 1
+69 1 1
+42 0 1
+175 5 4
+100 1 0
+402 1 0
+39 1 0
+10 1 0
+10 1 0
+14 1 1
+95 4 2
+120 0 5
+126 1 1
+32 2 1
+72 1 1
+335 1 1
+45 1 0
+403 4 1
+54 1 0
+108 1 0
+289 1 1
+40 1 0
+164 12 12
+169 1 1
+76 1 1
+71 3 3
+34 1 1
+65 72 72
+84 64 1
+55 190 1
+52 1 1
+42 5 5
+138 1 1
+39 1 1
+311 6 7
+300 1 0
+597 17 17
+187 1 1
+32 100 2817
+24 203 202
+36 1 1
+115 4 0
+139 25 24
+1050 1 0
+56 1 0
+90 1 0
+33 1 0
+35 3 0
+114 1 1
+19 1 1
+215 1 0
+431 1 1
+23 1 0
+421 14 11
+292 1 1
+22 1 1
+49 2741 2490
+33 4095 4075
+9 0 3
+18 1474 1474
+3 6 1
+11 3 0
+38 14404 14348
+27 15613 15513
+5 5 5
+21 1 2
+13 19 20
+34 104 104
+44 214 216
+8 3 0
+27 2800 929
+60 1 1
+29 4270 3383
+30 49 0
+26 1 1
+40 2712 2960
+33 1 1
+7
+
+chain 2173268 chr17_random 2617613 + 699498 748919 1 249250621 - 248538148 248591008 468
+685 3 3
+36 4 4
+73 9 5
+59 70 63
+42 285 48
+44 1 1
+96 74 80
+321 1 1
+49 1 1
+107 1 1
+47 11 2
+85 3 0
+67 1 0
+179 19 16
+220 9 0
+138 33 33
+136 1 1
+26 1 1
+545 1 0
+8 14 10
+42 1 1
+64 1 1
+28 1 1
+119 1 1
+49 1 1
+54 1 1
+32 1 1
+960 1 1
+41 1 1
+731 16 16
+57 1 1
+19 1 1
+118 1 0
+196 1 1
+50 1 1
+263 1 1
+52 1 1
+171 1 1
+26 1 1
+181 25 16
+51 27 0
+56 1 1
+139 0 4
+33 1 1
+236 1 1
+17 1 1
+192 15 13
+186 1 1
+30 7 7
+280 1 1
+80 1 0
+196 62 54
+290 1 1
+38 1 1
+772 10 10
+123 1 1
+28 1 0
+20 34 22
+81 0 4
+45 1 1
+806 1 1
+31 1 0
+35 1 1
+101 17 15
+89 1 1
+34 1 0
+8 1 1
+290 13 9
+284 1 0
+53 7 0
+26 6 0
+605 4 0
+531 35 35
+704 1 1
+66 1 1
+168 1 1
+34 1 1
+527 1 1
+30 1 1
+249 16 7
+414 1 1
+27 1 1
+344 1 1
+43 1 1
+117 1 1
+30 1 1
+862 0 1
+229 1 1
+48 1 1
+197 14 14
+972 19 31
+924 1 1
+42 1 1
+123 1 1
+56 1 1
+77 1 1
+23 1 1
+119 1 1
+53 18 11
+382 1 1
+17 1 1
+116 5 2
+37 1 1
+38 2 0
+223 1 1
+21 6 1
+583 1 0
+400 0 4
+1574 27 27
+54 4 1
+158 10 7
+336 6 7
+492 1 0
+14 1 1
+843 1 2
+247 1 1
+41 1 1
+50 6 6
+513 17 13
+615 12 12
+585 32 23
+161 6 6
+515 9 5
+43 5 3
+460 5 5
+158 11 11
+252 1 1
+22 3 0
+135 12 12
+556 0 1
+542 3 0
+298 4 1
+24 4 0
+117 9 5
+151 0 1
+291 0 1
+360 15 15
+962 20 17
+231 1 0
+293 1 0
+33 32 0
+40 15 10
+213 23 23
+458 1 1
+51 1 1
+437 1 0
+394 1 1
+25 2 0
+117 10 4
+50 1 1
+40 1 1
+626 8 5
+492 1 0
+383 1 0
+672 1 1
+136 1 1
+203 2 2
+88 1 1
+261 1 1
+45 1 1
+189 15 15
+78 1 1
+49 1 1
+93 1 0
+35 13 10
+21 1 1
+527 99 94
+103 44 44
+79 24 26
+111 39 36
+235 24 27
+117 7 7
+127 222 1777
+58 167 165
+59 75 75
+203 12 12
+55 56 44
+269 34 32
+87 24 24
+250 35 29
+682 91 91
+312 4 3
+583 124 2653
+132 399 398
+134 1 1
+33 1 1
+179 1 1
+27 1 1
+245 4 4
+93 1 1
+940 1 1
+20 1 1
+271 1 1
+16 0 1
+353 24 17
+369 146 0
+83 1 1
+34 1 1
+1103 1 1
+26 1 1
+112 1 0
+3 1 0
+370 32 27
+410 170 174
+51 1 1
+310 42 41
+66 5 2
+319
+
+chain 2047886 chr17_random 2617613 + 532224 554093 17 81195210 - 39794017 39815907 1262
+682 50 50
+270 0 4
+316 0 1
+691 1 0
+678 1 2
+601 1 0
+383 1 0
+20 1 1
+1048 2 0
+1884 0 6
+690 0 5
+1205 1 1
+43 0 2
+891 19 19
+1916 7 6
+2354 0 3
+2253 10 0
+2406 0 13
+1972 6 6
+595 0 4
+148 100 100
+356 20 20
+109 4 4
+73 2 0
+59
+
+chain 1863993 chr17_random 2617613 + 1011919 1106715 17 81195210 + 34578530 36287451 432
+1027 148 148
+295 18 18
+204 37 37
+144 7 7
+238 38 38
+357 101 101
+125 64 64
+712 21 22
+181 126 1729
+702 0 2
+184 29 30
+236 37 37
+1080 60 65
+606 1 0
+328 63 63
+556 20 20
+94 37 37
+172 0 1
+1430 0 1
+151 53 53
+605 36 36
+292 1 0
+84 17921 60667
+87 11034 74480
+38 804 804
+30 345 345
+62 200 200
+36 1097 1097
+33 696 696
+48 119 119
+30 986 986
+81 185 185
+35 641 641
+232 79 79
+116 288 288
+61 11306 1517682
+155 7 0
+427 5 5
+742 2 0
+85 1 1
+401 1 1
+97 1 1
+566 1 0
+607 1 0
+1318 0 24
+1995 71 3
+34 0 2
+44 1 1
+39 0 1
+3518 0 4
+469 1 0
+294 10 13
+520 6 6
+403 0 3
+331 1 0
+231 7 0
+255 0 1
+3122 0 1
+729 0 1
+117 11 11
+186 4 0
+84 1 0
+412 2 0
+19 1 1
+1642 6 0
+628 1 1
+21 1 1
+377 50 50
+151 0 9
+2370 1 1
+35 1 1
+1328 1 10
+586 14 0
+789 12 13
+1397 0 1
+1521 0 2
+382 0 1
+866 1 1
+20 1 1
+710 2 0
+1259 161 161
+387 28 28
+53 24 24
+3626 1 0
+1718
+
+chain 1732426 chr17_random 2617613 + 2586433 2605017 17 81195210 - 39776940 39795500 1439
+1157 1 1
+31 0 5
+2053 8 8
+691 1 1
+30 1 1
+1212 3 0
+3864 1 0
+3 1 0
+56 15 0
+860 1 1
+30 1 1
+6532 4 4
+147 13 13
+1042 17 17
+319 7 0
+181 10 10
+68 42 42
+51 16 14
+115
+
+chain 1719393 chr17_random 2617613 + 1323861 1343929 17 81195210 + 45650033 45670000 1446
+76 1 1
+94 1 1
+84 9 9
+70 1 1
+43 1 0
+40 0 2
+126 1 1
+38 1 1
+391 1 1
+43 1 1
+100 0 1
+66 12 12
+65 1 1
+39 2 0
+9 4 0
+25 1 1
+99 1 1
+27 0 4
+362 22 4
+659 2 0
+433 0 20
+16 1 1
+117 1 1
+248 1 1
+200 1 1
+23 1 1
+248 6 0
+120 1 1
+930 1 1
+14 1 1
+76 1 1
+11 1 0
+23 2 0
+23 1 1
+236 1 1
+48 1 1
+108 1 1
+141 7 5
+50 1 1
+27 1 1
+306 0 3
+290 1 1
+20 0 1
+31 1 1
+618 5 6
+350 14 6
+55 0 2
+112 4 0
+50 1 1
+263 1 0
+51 1 1
+527 1 1
+47 1 1
+247 1 1
+34 3 3
+169 0 2
+33 3 0
+165 12 0
+163 1 1
+77 1 0
+56 26 26
+54 6 6
+338 2 0
+185 73 73
+336 0 3
+89 1 1
+19 1 1
+65 18 18
+89 0 1
+178 1 1
+45 1 1
+67 8 0
+347 0 1
+22 1 1
+192 1 1
+73 1 4
+38 0 1
+61 1 1
+164 1 1
+74 3 3
+260 5 0
+89 9 9
+142 1 1
+49 1 1
+71 0 1
+62 1 1
+391 1 1
+78 1 1
+100 1 1
+32 1 1
+155 11 12
+304 8 0
+79 1 1
+115 1 1
+29 1 1
+97 19 0
+168 1 1
+19 4 4
+359 2 0
+18 1 1
+358 1 1
+38 1 1
+83 1 1
+31 1 1
+389 1 1
+32 1 1
+128 1 1
+39 1 1
+54 1 1
+11 2 0
+165 4 0
+34 1 1
+58 1 1
+68 3 0
+230 1 1
+44 1 1
+276 16 16
+170 6 6
+104 1 1
+61 1 1
+107 6 6
+177 1 1
+66 5 0
+60 1 1
+14 1 1
+50 4 4
+15 1 1
+62 1 1
+194 1 1
+72 22 1
+39 1 1
+70 1 1
+42 1 1
+58 1 1
+36 1 1
+329 1 0
+136 1 1
+192 9 10
+682 24 21
+81 0 1
+367 12 12
+81
+
+chain 1570588 chr17_random 2617613 + 1644335 1687876 17 81195210 + 66068832 66112387 1087
+1168 16352 16361
+2197 2 0
+1554 1 0
+6339 0 4
+1936 0 7
+2357 2 0
+7231 1 0
+4401
+
+chain 1476469 chr17_random 2617613 + 2303443 2319476 17 81195210 + 79885696 79901628 1655
+880 1 0
+298 1 0
+60 43 40
+227 40 38
+326 1 0
+77 1 0
+148 1 0
+199 21 19
+60 1 0
+224 1 0
+173 1 0
+317 88 84
+84 1 0
+96 48 45
+432 1 0
+107 1 0
+505 1 0
+88 1 0
+551 1 0
+107 1 0
+176 1 0
+79 2 0
+127 1 0
+56 1 0
+239 1 0
+218 1 0
+11 1 0
+27 1 0
+256 1 0
+130 1 0
+60 1 0
+586 1 0
+96 1 0
+58 1 0
+80 1 0
+135 1 0
+55 1 0
+219 5 2
+11 4 2
+30 4 1
+368 1 0
+106 1 0
+119 18 13
+146 1 0
+636 1 0
+156 1 0
+541 1 0
+107 1 0
+97 1 0
+61 1 0
+66 1 0
+7 1 0
+238 1 0
+105 1 0
+13 1 0
+667 1 0
+85 1 0
+70 1 0
+642 1 0
+635 1 0
+57 1 0
+249 1 0
+237 1 0
+162 1 0
+166 1 0
+380 1 0
+271 1 0
+215 2 0
+260 1 0
+160 1 0
+62 1 0
+6 1 0
+185 1 0
+48 1 0
+265 5 2
+87 1 0
+186 1 0
+62 1 0
+20 1 0
+135
+
+chain 1260177 chr17_random 2617613 + 853052 928106 17 81195210 - 43628 125104 962
+949 1 0
+3976 1 0
+155 1 0
+1382 1 0
+174 1 0
+249 1 0
+3481 16 14
+138 196 313
+72 88 86
+491 22816 3210
+803 32 32
+116 1 0
+346 10 9
+779 1 0
+620 1 0
+336 1 0
+2035 1 0
+1010 1 0
+1029 22 20
+97 39 114
+77 79 0
+5135 26 26
+535 1 0
+2026 21 19
+206 2 0
+254 19578 45525
+174 1 1
+34 1 1
+97 25 25
+137 6 5
+2443 14 9
+445 1 0
+116 1 0
+2150
+
+chain 1227372 chr17_random 2617613 + 986700 1051441 17 81195210 + 34570816 36317431 617
+294 0 3023
+141 196 196
+44 109 109
+53 147 147
+19 33 32
+101 42 42
+166 603 602
+128 1742 1742
+37 15134 15157
+88 7169 151654
+89 3878 5468
+37 1080 1080
+60 1668 1668
+37 1753 1753
+53 605 605
+36 506 39138
+695 47 47
+375 59 59
+312 20 20
+185 37 37
+144 7 7
+238 38 38
+357 101 101
+125 64 64
+712 185 184
+2677 120 1494235
+1055 15 15
+700 4 4
+1174 24 24
+888 9 3
+1590 0 3
+913 18 20
+1011 1 1
+26 1 1
+2545 1 1
+35 1 1
+1283 87 87
+45 432 432
+149 418 418
+46 284 284
+2 3 3
+30 1838 1839
+89 540 540
+32 511 512
+48 2400 2403
+39 3223 3228
+39 360 360
+49 178 178
+59
+
+chain 1028733 chr17_random 2617613 + 2262901 2274699 17 81195210 - 1281214 1293541 2373
+276 161 161
+1171 1 0
+181 1 0
+943 1 0
+423 1 0
+384 47 47
+111 466 1042
+106 31 31
+75 4 4
+63 20 16
+142 1 0
+59 1 0
+607 1 0
+135 1 0
+31 1 0
+82 1 0
+266 1 0
+76 1 0
+5 4 2
+41 1 0
+52 1 0
+985 1 0
+87 1 0
+4 1 0
+114 1 0
+175 1 0
+30 1 0
+140 2 0
+22 1 0
+130 1 0
+239 1 0
+766 1 0
+203 1 0
+68 2 0
+252 1 0
+300 4 2
+377 1 0
+735 1 0
+279 5 2
+91 1 0
+66 1 0
+159 1 0
+7 1 0
+562
+
+chain 931587 chr17_random 2617613 + 978106 1010959 17 81195210 + 36277154 36406169 991
+1048 10 12
+382 0 1
+199 22 22
+381 8 8
+56 66 66
+80 176 176
+73 27 27
+90 32 32
+166 31 209
+634 0 4
+1199 65 65
+56 27 27
+255 27 27
+50 1 7
+422 5 5
+61 4 0
+80 311 311
+40 144 144
+53 3450 47979
+41 18030 69497
+201 21 0
+219 1 0
+310 0 1
+3136 0 1
+510 50 52
+321 3 0
+279
+
+chain 813092 chr17_random 2617613 + 1807252 1826317 17 81195210 + 22246129 22262163 2589
+338 20 20
+223 15 15
+164 162 162
+54 59 60
+73 230 230
+52 48 48
+50 66 66
+54 49 49
+257 14 14
+103 22 22
+96 5 5
+357 121 121
+100 88 88
+108 94 94
+490 34 34
+81 27 27
+54 82 82
+80 138 138
+128 12 12
+262 24 21
+199 35 35
+263 80 80
+84 52 52
+185 16 16
+75 113 113
+160 99 99
+70 27 27
+84 49 49
+59 25 25
+133 30 30
+64 45 45
+304 25 25
+986 74 74
+160 13 13
+209 22 22
+54 43 43
+61 156 156
+54 6 6
+77 5 5
+86 85 85
+117 48 165
+381 74 74
+262 32 32
+165 71 71
+57 95 95
+89 31 31
+114 140 140
+117 216 216
+77 5 5
+52 442 441
+185 60 60
+363 22 22
+179 11 11
+259 197 197
+118 35 35
+108 60 60
+61 61 61
+137 50 50
+53 56 56
+269 161 161
+106 103 105
+56 8 8
+368 41 41
+47 3145 0
+401 42 42
+90 23 23
+151 73 73
+81 148 146
+351
+
+chain 788653 chr17_random 2617613 + 1298766 1307227 17 81195210 - 44798207 44806654 6145
+463 1 0
+2422 0 1
+90 14 0
+75 0 1
+397 0 1
+64 1 1
+30 0 1
+202 1 0
+1329 2 0
+1396 1 0
+668 0 1
+280 45 45
+980
+
+chain 597412 chr17_random 2617613 + 807879 2303216 17 81195210 - 0 1281216 430
+180 1676 138
+25553 1 0
+149 14 14
+1938 1 0
+350 32 32
+1230 1 0
+3 1 0
+6237 1 0
+45 2 2
+6514 1 0
+228 662945 0
+7897 0 1
+2396 1 0
+1101 17 0
+41 1 1
+355 0 52
+50 18 1
+41 0 68
+84 34 0
+4918 0 1
+717 0 1
+313 1 1
+42 1 1
+73 29 31
+205 58 0
+414 1 1
+64 1 1
+959 1 1
+17 1 1
+2276 1 0
+739 0 1
+418 11 49
+1541 0 1
+3494 7 13
+1281 21 21
+1738 1 191
+26 0 38
+40 0 77
+67 5 5
+11 1 75
+55 2266 0
+112 47 9
+78 38 0
+24 1 1
+80 5 5
+551 0 5
+87 1 1
+35 1 1
+54 119 195
+74 1 1
+957 15 15
+64 1277 306
+91 1 1
+35 1 1
+820 48 67
+330 0 1
+2794 1 0
+1127 1 1
+19 0 5
+1483 715858 1169096
+78 1 0
+529 1 0
+25 1 0
+200 1 0
+643 2 0
+450 2 0
+211 1 0
+380 2 2
+180 2 1
+32 1 0
+246 1 0
+61 1 0
+5 1 0
+351 1 0
+37 1 0
+304 1 0
+18 1 0
+109 1 0
+16 1 0
+200 1 0
+105 1 0
+37 1 0
+376 1 0
+108 1 0
+91 1 0
+394 1 0
+20 1 0
+1014 32 30
+21 2 1
+34 1 0
+230 26 26
+941 1 0
+188 1 0
+610 1 0
+555 1 0
+303 1 0
+509 157 157
+169 22 22
+101 1 0
+501 1 0
+140 1 0
+78 2 1
+22 1 0
+39 6 5
+62 94 94
+593 114 111
+260 120 120
+362 1 0
+697 0 1
+123 28 28
+402 36 36
+904 1 0
+50 1 0
+379 1 0
+256 25 25
+23 17 17
+53 27 27
+556 1 0
+409 1 0
+106 1 0
+276 24 24
+35 2 0
+252 32 32
+213 4 4
+70 2 0
+27 4 2
+82 1 0
+17 1 0
+639 1 0
+172 11 7
+10 1 0
+76 1 0
+1582 1 0
+275 1 0
+21 1 0
+17 4 2
+66 1 0
+1653 1 0
+19 3 3
+139 179 179
+76 2 2
+60 1 0
+226 1 0
+538 1 0
+346 4 4
+42 25 25
+1319 1 0
+261 1 0
+512 1 0
+69 1 0
+480 2 0
+388 8 7
+305 5 5
+64 2 2
+846
+
+chain 590397 chr17_random 2617613 + 1317586 1323861 17 81195210 - 44817018 44823295 6400
+2259 1 0
+955 0 1
+2132 0 1
+744 0 1
+184
+
+chain 365975 chr17_random 2617613 + 1296053 1313819 17 81195210 + 45621804 45639993 6832
+81 12 44
+148 0 6
+401 61 62
+589 32 30
+259 39 57
+53 103 103
+231 127 131
+59 7954 7632
+45 980 978
+16 142 143
+82 46 46
+363 247 934
+159 50 48
+341 33 34
+57 16 16
+304 65 65
+69 9 9
+136 66 66
+138 57 57
+70 10 10
+70 123 120
+143 52 52
+152 15 19
+320 53 52
+121 0 1
+161 98 108
+97 59 59
+205 127 125
+55 11 11
+56 30 30
+88 43 43
+512 45 43
+125 143 136
+165 48 48
+56 24 24
+161 114 115
+364 40 40
+240
+
+chain 323854 chr17_random 2617613 + 753664 757726 11 135006516 + 51394886 51398944 206195
+84 571 570
+807 3 1
+2082 1 0
+514
+
+chain 193433 chr17_random 2617613 + 495545 497612 17 81195210 + 41377728 41379794 617459
+55 1 0
+1306 28 28
+677
+
+chain 170984 chr17_random 2617613 + 1315777 1317585 17 81195210 - 44815210 44817018 741311
+1808
+
+chain 158566 chr17_random 2617613 + 1808012 1818883 17 81195210 + 22251644 22262630 5258
+162 209 210
+87 88 88
+32 270 270
+48 855 855
+36 185 185
+88 888 888
+37 888 888
+35 263 263
+80 85 85
+51 276 276
+47 20 20
+46 329 329
+27 350 350
+4 5 5
+21 413 412
+25 986 986
+74 458 458
+43 137 137
+80 228 228
+85 546 663
+9 10 10
+55 262 262
+32 293 293
+68 116 116
+25 120 120
+109 148 148
+60 1 1
+67 6 4
+74 1 1
+7 134 134
+220 1 1
+65 1 1
+91 1 1
+62 186 186
+60
+
+chain 150869 chr17_random 2617613 + 749022 751008 11 135006516 + 51475668 51477652 852441
+306 379 377
+1301
+
+chain 148651 chr17_random 2617613 + 808184 809735 17 81195210 + 81137722 81139272 865111
+940 1 0
+610
+
+chain 145464 chr17_random 2617613 + 1314230 1315767 17 81195210 - 44813661 44815198 885049
+1537
+
+chain 120518 chr17_random 2617613 + 1343929 1345208 17 81195210 - 44843364 44844643 723183
+1279
+
+chain 116919 chr17_random 2617613 + 1353036 1364922 17 81195210 - 44845210 44857111 1380
+449 299 299
+31 164 164
+55 373 373
+449 9718 9733
+348
+
+chain 115845 chr17_random 2617613 + 508518 509981 17 81195210 - 39794017 39795500 1110103
+682 50 50
+270 0 4
+177 169 185
+115
+
+chain 114042 chr17_random 2617613 + 516500 517961 17 81195210 - 39794017 39795500 1127130
+682 50 50
+210 5 6
+54 0 6
+175 170 185
+115
+
+chain 113591 chr17_random 2617613 + 521388 522849 17 81195210 - 39794017 39795500 1131524
+58 0 1
+623 50 50
+210 5 6
+54 0 6
+175 171 185
+115
+
+chain 112548 chr17_random 2617613 + 503499 505329 17 81195210 - 39794017 39795500 1141710
+27 370 0
+655 50 50
+210 5 6
+54 0 7
+174 170 185
+115
+
+chain 92910 chr17_random 2617613 + 1642194 1643169 17 81195210 - 1314977 1315952 1374174
+975
+
+chain 86438 chr17_random 2617613 + 1345275 1346182 17 81195210 - 44844700 44845607 1472746
+907
+
+chain 80313 chr17_random 2617613 + 2609695 2610598 17 81195210 - 39794017 39794920 1580802
+682 50 50
+171
+
+chain 78741 chr17_random 2617613 + 1643269 1644095 17 81195210 + 79874782 79875608 1611354
+826
+
+chain 75472 chr17_random 2617613 + 1310578 1313579 17 81195210 - 44810007 44813007 188419
+53 282 282
+98 97 97
+59 205 205
+127 122 122
+30 88 88
+43 512 512
+45 125 125
+72 1 0
+70 165 165
+48 241 241
+114 364 364
+40
+
+chain 74354 chr17_random 2617613 + 1547620 1548395 8 146364022 - 2302524 2303299 1703290
+775
+
+chain 61189 chr17_random 2617613 + 1546707 1547351 8 146364022 + 144057273 144057917 2067192
+644
+
+chain 59362 chr17_random 2617613 + 751149 753548 1 249250621 - 248579195 248581575 182656
+35 2 1
+152 1 0
+15 1 0
+107 3 2
+74 1 0
+10 1 0
+19 1 0
+57 1 1
+48 3 1
+6 1 0
+107 12 330
+61 1 1
+51 357 35
+388 110 110
+84 38 38
+62 227 223
+116 106 105
+141
+
+chain 56858 chr17_random 2617613 + 1298104 1298766 17 81195210 - 44797535 44798197 1968612
+85 59 59
+518
+
+chain 56536 chr17_random 2617613 + 501286 502149 17 81195210 - 39794614 39795500 2243684
+85 50 50
+210 5 6
+54 0 7
+174 170 185
+115
+
+chain 55411 chr17_random 2617613 + 688273 689806 7 159138663 - 159114165 159114723 7844
+88 175 0
+148 458 0
+103 231 3
+111 117 3
+102
+
+chain 52941 chr17_random 2617613 + 1822234 1824166 17 81195210 - 58941545 58943477 1155
+887 1 1
+77 1 1
+300 1 1
+20 9 9
+133 1 1
+23 1 1
+59 1 1
+158 1 1
+91 1 1
+54 1 1
+112
+
+chain 52559 chr17_random 2617613 + 983839 1162005 17 81195210 - 44845659 46605886 726
+299 65 65
+117 68 68
+1986 9723 54270
+49 72036 1500609
+1027 6412 6412
+71 13528 13528
+50 11447 11447
+132 60546 169487
+42 528 528
+40
+
+chain 51097 chr17_random 2617613 + 1023443 1026449 17 81195210 + 34744258 34747264 8774
+47 375 375
+59 517 517
+37 389 389
+38 357 357
+101 125 125
+64 712 712
+185
+
+chain 49537 chr17_random 2617613 + 686221 687340 7 159138663 - 159114165 159114714 2581538
+393 570 0
+156
+
+chain 49422 chr17_random 2617613 + 2502237 2515076 GL000206.1 41001 + 6806 19645 760
+60 12323 12323
+456
+
+chain 46461 chr17_random 2617613 + 530697 531391 17 81195210 + 41399710 41400427 2769983
+115 170 185
+151 0 7
+77 5 6
+176
+
+chain 44819 chr17_random 2617613 + 1346282 1352646 17 81195210 + 36399842 36406169 117269
+158 113 113
+546 19 0
+337 0 1
+343 21 0
+219 1 0
+310 0 1
+3136 0 1
+510 1 1
+49 0 2
+321 1 0
+279
+
+chain 42351 chr17_random 2617613 + 1308282 1310091 17 81195210 - 44807710 44809519 659295
+50 341 341
+33 377 377
+65 214 214
+66 138 138
+57 150 150
+123 143 143
+52
+
+chain 41114 chr17_random 2617613 + 1307243 1308123 17 81195210 - 44806671 44807550 1295496
+142 82 82
+46 363 362
+247
+
+chain 38415 chr17_random 2617613 + 980212 983216 17 81195210 - 46382593 46436652 7347
+66 80 80
+176 73 73
+27 90 90
+32 166 166
+31 1833 52888
+65 56 56
+27 255 255
+27
+
+chain 37708 chr17_random 2617613 + 1313819 1314225 17 81195210 - 44813251 44813657 3332998
+406
+
+chain 34385 chr17_random 2617613 + 689365 745709 16 90354753 + 90179685 90235100 655
+111 4456 3661
+64 55 55
+25 28 28
+47 0 945
+90 45591 45393
+56 269 269
+34 5469 4540
+13 2 2
+32 0 48
+2
+
+chain 29758 chr17_random 2617613 + 1820296 1826385 17 81195210 + 22249775 22252718 80336
+37 643 643
+77 136 133
+51 3143 0
+44 74 74
+224 80 80
+64 79 79
+9 741 741
+39 82 82
+59 25 25
+56 358 358
+68
+
+chain 29219 chr17_random 2617613 + 1551349 1551651 17 81195210 + 81144397 81144699 5017519
+302
+
+chain 28762 chr17_random 2617613 + 686677 687796 7 159138663 - 159114165 159114714 2625478
+282 456 0
+111 3 3
+57 114 0
+96
+
+chain 26027 chr17_random 2617613 + 1296695 1298103 17 81195210 - 44796117 44797535 630440
+61 589 589
+32 259 269
+39 53 53
+103 231 231
+41
+
+chain 25589 chr17_random 2617613 + 1810180 1822057 17 81195210 + 22246679 22258671 5893
+31 6949 7063
+28 2666 2666
+60 580 580
+49 73 73
+37 1172 1173
+232
+
+chain 22463 chr17_random 2617613 + 503557 503790 17 81195210 - 39794076 39794309 8690008
+233
+
+chain 21299 chr17_random 2617613 + 1013035 1014722 17 81195210 + 34795732 34797419 1064
+59 517 517
+37 389 389
+38 357 357
+101 125 125
+64
+
+chain 20434 chr17_random 2617613 + 685587 686087 7 159138663 - 159114215 159114487 2822651
+209 248 20
+43
+
+chain 19692 chr17_random 2617613 + 2611651 2612116 17 81195210 - 39813091 39813524 10717347
+67 163 137
+78 68 62
+89
+
+chain 19589 chr17_random 2617613 + 2616810 2617276 17 81195210 + 41381686 41382119 10803726
+89 68 62
+77 165 138
+67
+
+chain 17762 chr17_random 2617613 + 852036 852257 5 180915260 - 51646 51969 938
+13 1 1
+60 1 1
+29 1 1
+13 0 102
+103
+
+chain 17600 chr17_random 2617613 + 1364922 1365125 17 81195210 - 46397651 46397854 1833
+172 1 1
+30
+
+chain 17149 chr17_random 2617613 + 1514626 1514877 1 249250621 + 547399 547650 3354419
+131 1 3
+101 2 0
+16
+
+chain 16567 chr17_random 2617613 + 2610699 2610873 17 81195210 - 39795026 39795200 13468304
+174
+
+chain 16365 chr17_random 2617613 + 1812948 1813633 17 81195210 + 22258959 22259644 44227
+99 181 181
+49 59 59
+25 227 227
+45
+
+chain 16348 chr17_random 2617613 + 525487 525673 11 135006516 + 62609095 62609281 13688187
+75 4 4
+107
+
+chain 14733 chr17_random 2617613 + 2605728 2605963 17 81195210 - 39813295 39813524 15353144
+78 68 62
+89
+
+chain 14711 chr17_random 2617613 + 556093 556262 11 135006516 - 72397235 72397404 15378622
+107 4 4
+58
+
+chain 14711 chr17_random 2617613 + 527846 528015 11 135006516 - 72397235 72397404 15378623
+107 4 4
+58
+
+chain 14711 chr17_random 2617613 + 512402 512571 11 135006516 - 72397235 72397404 15378624
+107 4 4
+58
+
+chain 14711 chr17_random 2617613 + 510910 511079 11 135006516 - 72397235 72397404 15378625
+107 4 4
+58
+
+chain 14711 chr17_random 2617613 + 494247 494416 11 135006516 - 72397235 72397404 15378626
+107 4 4
+58
+
+chain 14711 chr17_random 2617613 + 492878 493047 11 135006516 - 72397235 72397404 15378627
+107 4 4
+58
+
+chain 14711 chr17_random 2617613 + 519356 519525 11 135006516 + 62609112 62609281 15378630
+58 4 4
+107
+
+chain 14711 chr17_random 2617613 + 514467 514636 11 135006516 + 62609112 62609281 15378631
+58 4 4
+107
+
+chain 14711 chr17_random 2617613 + 492408 492577 11 135006516 + 62609112 62609281 15378632
+58 4 4
+107
+
+chain 13395 chr17_random 2617613 + 685879 686024 7 159138663 - 159114165 159114310 16961745
+145
+
+chain 12350 chr17_random 2617613 + 554102 554230 17 81195210 + 41401065 41401193 18472361
+128
+
+chain 11140 chr17_random 2617613 + 2611055 2611170 17 81195210 - 39795385 39795500 20498301
+115
+
+chain 11115 chr17_random 2617613 + 1365516 1365648 17 81195210 - 46613257 46613389 1914
+132
+
+chain 10814 chr17_random 2617613 + 689806 689963 7 159138663 - 159114495 159114652 3160720
+43 20 20
+94
+
+chain 10716 chr17_random 2617613 + 690046 690160 11 135006516 - 134823089 134823203 21297817
+114
+
+chain 10594 chr17_random 2617613 + 686107 686221 11 135006516 - 134823089 134823203 21541329
+114
+
+chain 10432 chr17_random 2617613 + 752965 753084 3 198022430 + 197944313 197944432 1419040
+26 27 27
+66
+
+chain 10233 chr17_random 2617613 + 751962 752152 1 249250621 - 25108929 25109119 2449036
+190
+
+chain 10215 chr17_random 2617613 + 298300 298405 17 81195210 - 41991981 41992086 2272776
+105
+
+chain 10088 chr17_random 2617613 + 2614941 2615048 11 135006516 - 72397235 72397342 22628945
+107
+
+chain 9967 chr17_random 2617613 + 687027 687133 7 159138663 - 159114173 159114279 19905170
+106
+
+chain 9953 chr17_random 2617613 + 1352829 1353036 17 81195210 - 44845003 44845210 3604154
+38 53 53
+37 50 50
+29
+
+chain 9937 chr17_random 2617613 + 2607755 2608553 17 81195210 + 41464708 41466209 22969163
+59 661 1364
+78
+
+chain 9782 chr17_random 2617613 + 685310 686656 7 159138663 - 159114165 159114714 2594423
+225 1079 282
+42
+
+chain 9490 chr17_random 2617613 + 268561 268666 17 81195210 + 39296306 39296411 8067183
+50 6 6
+49
+
+chain 9384 chr17_random 2617613 + 1808529 1810797 17 81195210 + 22256920 22261566 263516
+29 104 104
+28 50 50
+48 1976 4354
+33
+
+chain 9278 chr17_random 2617613 + 1333217 1333901 17 81195210 - 44832655 44833339 2515
+26 585 585
+73
+
+chain 9162 chr17_random 2617613 + 1819790 1824781 17 81195210 + 22261160 22263006 131478
+64 322 322
+59 818 816
+30 3642 499
+56
+
+chain 8930 chr17_random 2617613 + 507298 507390 17 81195210 + 41466131 41466223 25058540
+92
+
+chain 8739 chr17_random 2617613 + 1294354 1363161 17 81195210 - 46388680 46446941 1280
+36 59095 48559
+76 160 160
+63 250 250
+52 124 124
+61 4094 4092
+28 4719 4711
+49
+
+chain 7495 chr17_random 2617613 + 1514877 1514981 17 81195210 - 42613 42717 4053350
+104
+
+chain 7310 chr17_random 2617613 + 1352662 1353007 17 81195210 - 20840434 20840778 292042
+167 38 37
+53 37 37
+50
+
+chain 6706 chr17_random 2617613 + 687825 687939 7 159138663 - 159114173 159114287 10506562
+114
+
+chain 6456 chr17_random 2617613 + 673480 673547 11 135006516 - 134811854 134811921 22781013
+67
+
+chain 5049 chr17_random 2617613 + 752664 753185 1 249250621 - 248584104 248584621 921258
+110 84 84
+38 62 62
+7 119 119
+72 7 3
+22
+
+chain 5012 chr17_random 2617613 + 557502 557555 17 81195210 + 41382227 41382280 33565948
+53
+
+chain 4802 chr17_random 2617613 + 1345218 1345268 17 81195210 - 44844643 44844693 34312672
+50
+
+chain 4547 chr17_random 2617613 + 688053 688156 7 159138663 - 159114401 159114504 10358404
+103
+
+chain 4503 chr17_random 2617613 + 690214 690262 7 159138663 - 159114675 159114723 34814023
+48
+
+chain 4408 chr17_random 2617613 + 1808470 1808528 17 81195210 + 22261618 22261676 11976838
+58
+
+chain 4236 chr17_random 2617613 + 269418 269467 17 81195210 - 41933979 41934028 1349427
+49
+
+chain 3906 chr17_random 2617613 + 1365126 1365187 17 81195210 - 23109543 23109604 10221956
+61
+
+chain 3852 chr17_random 2617613 + 685196 685310 7 159138663 - 159114165 159114279 3139829
+114
+
+chain 3804 chr17_random 2617613 + 676798 676843 11 135006516 - 134814627 134814666 26257176
+33 6 0
+6
+
+chain 3734 chr17_random 2617613 + 1819749 1824493 17 81195210 + 22251604 22253205 550639
+41 1133 1133
+53 3451 308
+4 6 6
+56
+
+chain 3666 chr17_random 2617613 + 689649 689704 3 198022430 + 197891166 197891221 670
+55
+
+chain 3459 chr17_random 2617613 + 687133 687184 7 159138663 - 159114165 159114216 4526522
+51
+
+chain 3336 chr17_random 2617613 + 1365188 1365250 17 81195210 - 20853025 20853087 9938797
+62
+
+chain 3079 chr17_random 2617613 + 681792 681827 11 135006516 - 134820249 134820284 24010224
+35
+
+chain 2916 chr17_random 2617613 + 690160 690191 7 159138663 - 159114621 159114652 25187800
+31
+
+chain 2901 chr17_random 2617613 + 1010962 1011819 17 81195210 - 44844823 44845680 205824
+857
+
+chain 2668 chr17_random 2617613 + 837741 837773 8 146364022 + 31195 31227 1221
+32
+
+chain 2659 chr17_random 2617613 + 747955 747987 5 180915260 + 180755757 180755789 880
+32
+
+chain 2649 chr17_random 2617613 + 622962 622989 17 81195210 - 81153206 81153233 29165068
+27
+
+chain 2631 chr17_random 2617613 + 1252044 1252072 17 81195210 + 34548405 34548433 469
+28
+
+chain 2530 chr17_random 2617613 + 1100849 1100878 17 81195210 - 46384734 46384763 4689
+29
+
+chain 2422 chr17_random 2617613 + 621448 621568 17 81195210 - 81152835 81152952 7235512
+27 65 62
+28
+
+chain 2158 chr17_random 2617613 + 688361 688384 16 90354753 + 90179770 90179793 21906636
+23
+
+chain 2073 chr17_random 2617613 + 690420 690442 7 159138663 - 159114653 159114675 31315602
+22
+
+chain 1877 chr17_random 2617613 + 1533316 1533338 GL000206.1 41001 - 16469 16491 815
+22
+
+chain 1804 chr17_random 2617613 + 687361 687825 7 159138663 - 159114165 159114515 2659234
+54 381 267
+29
+
+chain 1771 chr17_random 2617613 + 742259 742283 1 249250621 - 248585388 248585412 123201
+24
+
+chain 1698 chr17_random 2617613 + 268509 268561 17 81195210 - 41933055 41933107 4387515
+52
+
+chain 1694 chr17_random 2617613 + 747513 747535 1 249250621 - 249115973 249115995 773
+22
+
+chain 1343 chr17_random 2617613 + 555358 555450 17 81195210 - 39728987 39729079 19263806
+92
+
+chain 1343 chr17_random 2617613 + 511667 511759 17 81195210 - 39728987 39729079 19263807
+92
+
+chain 1343 chr17_random 2617613 + 526316 526408 17 81195210 + 41466131 41466223 19263808
+92
+
+chain 1343 chr17_random 2617613 + 520168 520260 17 81195210 + 41466131 41466223 19263809
+92
+
+chain 1129 chr17_random 2617613 + 1019025 1019068 17 81195210 + 60348267 60348310 2834
+43
+
+chain 1082 chr17_random 2617613 + 686959 687027 7 159138663 - 159114561 159114629 2979122
+68
+
+chain 594 chr17_random 2617613 + 1548943 1548990 GL000206.1 41001 - 30268 30353 3713456
+4 9 47
+34
+
+chain 7055976638 chr18 76117153 + 0 76117153 18 78077248 + 10000 78016181 19
+15400898 1363998 3100000
+28218587 15 15
+5329636 47000 150000
+3667309 0 18
+16406890 28008 50000
+3388467 22000 50000
+2103304 3 0
+136125 7 9
+647 0 1
+1543 0 1
+25 0 1
+6 2 7
+19 0 2
+10 4 7
+9 2 4
+656 0 1
+358 0 1
+1625
+
+chain 404699 chr18_random 4262 + 0 4262 GL000207.1 4262 + 0 4262 116011
+4262
+
+chain 5307789368 chr19 63811651 + 11000 63806651 19 59128983 + 60000 59114839 21
+7286004 5000 50000
+1291194 5000 50000
+11767057 0 69160
+4058367 8000000 3100000
+20129228 0 2
+701 3 0
+347 1 1
+31 1 1
+1833 3 0
+1984 1 1
+47 1 1
+190 1 1
+34 1 1
+889 0 2
+1413 0 7
+2680 0 4
+375 0 1
+328 0 4
+15 0 1
+69 1 0
+3881 1 1
+36 0 12
+296 0 14
+1480 0 1
+233 1 1
+45 1 1
+1049 0 1
+1766 44 7
+220 3 0
+536 0 7
+352 8 8
+3603 1 1
+17 3 0
+697 1 0
+269 3 0
+974 6 5
+96 0 10
+1096 10 10
+1177 14 12
+110 3 3
+1028 12 9
+1090 1 0
+173 0 16
+1066 4 0
+4779 1 1
+42 1 1
+722 1 0
+548 2 2
+44 1 1
+424 54 54
+61 1 1
+59 1 1
+2086 0 15
+1500 1 0
+1754 2 0
+11209362
+
+chain 15150451 chr19_random 301858 + 142689 301858 GL000209.1 159169 + 0 159169 196
+159169
+
+chain 8748871 chr19_random 301858 + 0 92689 GL000208.1 92689 + 0 92689 377
+92689
+
+chain 14432273 chr1_random 1663265 + 444114 915337 1 249250621 - 104328377 105379619 206
+1802 63331 510
+7296 6958 14784
+7961 0 2
+631 19782 48350
+2466 1 1
+72 1 1
+281 2 2
+18 1 1
+2234 1 1
+23 2 1
+1869 0 2
+890 0 1
+2816 0 3
+59 12 12
+1298 1 1
+11 1 1
+294 214294 820733
+136815
+
+chain 10693564 chr1_random 1663265 + 965337 1079393 1 249250621 + 199645090 199759149 300
+3537 0 2
+1755 1 1
+38 1 1
+15918 1 0
+2372 0 1
+1251 34 34
+7007 1 6
+3552 1 1
+44 1 1
+799 1 1
+42 1 1
+3907 2 0
+1780 1 1
+49 1 1
+1586 2 0
+197 1 1
+37 1 1
+292 1 1
+47 1 1
+927 0 2
+549 1 1
+27 1 1
+595 1 1
+18 1 1
+291 0 2
+6685 1 0
+2369 1 0
+6503 13 13
+639 1 1
+70 1 1
+477 1 0
+1001 0 2
+1967 2 0
+3454 1 1
+26 1 1
+3144 0 4
+89 1 0
+6546 14 15
+6194 1 0
+5390 13 13
+196 1 0
+7401 1 9
+1242 1 0
+1702 1 0
+477 1 1
+61 0 1
+1487 1 0
+1276 1 0
+1950 9 0
+4681 0 2
+1332 1 0
+956
+
+chain 10110185 chr1_random 1663265 + 1464329 1570762 GL000191.1 106433 + 0 106433 317
+106433
+
+chain 6680210 chr1_random 1663265 + 198768 359123 1 249250621 + 1257620 1436018 467
+467 0 1
+41 0 1
+10 4 4
+930 2 3
+122 3 4
+138 66071 6986
+47 0 1
+945 0 1
+279 1 2
+508 0 1
+482 0 1
+1285 1 1
+40 1 1
+199 0 1
+207 1 1
+29 1 1
+1021 0 1
+1168 0 2
+388 0 1
+69 15 17
+195 4 4
+52 1 1
+9 1 3
+23 0 1
+284 0 1
+1485 15 16
+138 9 9
+27 44 5
+35 46 46
+97 0 1
+5 0 1
+734 0 3
+257 1 1
+18 1 1
+442 0 2
+51 4 0
+424 0 1
+134 1 1
+39 0 1
+22 1 1
+564 15 17
+469 0 3
+39 0 1
+22 2 2
+1076 0 1
+210 14 14
+166 0 1
+3264 1 0
+111 0 1
+309 19898 50666
+91 0 1
+116 0 1
+56 0 1
+152 0 1
+46 0 1
+51 0 1
+63 0 2
+420 4 5
+697 0 1
+2269 7 0
+48 1 1
+4086 0 2
+317 0 1
+49 0 1
+1795 0 1
+1147 1 1
+39 1 1
+1378 0 17
+477 2 0
+4457 1 1
+105 0 1
+1003 0 1
+232 1 2
+147 277 46717
+169 0 1
+37 1 1
+227 0 2
+651 1 0
+1805 1 1
+45 1 1
+498 1 0
+233 1 1
+29 1 1
+231 12 20
+2015 0 1
+20 1 1
+653 0 1
+12 0 1
+17 1 1
+139 0 1
+10 0 1
+22 0 1
+37 16 19
+38 0 5
+54 0 1
+437 0 1
+539 2 0
+1067 0 1
+1042 1 0
+2434 10 0
+256 133 0
+839 0 1
+267 0 1
+640 1 1
+35 1 1
+1351 15 15
+1316 1 1
+31 0 1
+1986 5 5
+1179 0 1
+3153 1 0
+1165 0 1
+22 0 1
+56 1 1
+27 1 1
+77 0 1
+81 15 17
+111 1 1
+44 0 1
+2254 1 0
+320 1 0
+2368 0 1
+26 0 1
+407 5 6
+2982 0 4
+852 0 5
+703 1 0
+191 2 3
+73 5 5
+72
+
+chain 4901563 chr1_random 1663265 + 676697 728522 1 249250621 - 205721991 205773795 637
+1664 1 0
+299 1 0
+1113 4 0
+100 1 0
+1522 1 1
+46 1 1
+83 1 1
+30 1 1
+62 1 1
+46 1 1
+1990 1 1
+41 1 1
+1403 0 4
+1148 0 5
+10134 1 1
+21 1 1
+1479 1 0
+1499 9 9
+3057 0 2
+137 6 0
+1251 2 0
+21 1 1
+897 5 4
+2851 1 0
+399 0 2
+624 6 5
+440 1 0
+5 1 0
+2953 1 0
+480 9 0
+2793 36 35
+6791 1 0
+4870 1 0
+1478
+
+chain 4504833 chr1_random 1663265 + 1205412 1353281 1 249250621 - 133273039 133340206 679
+3980 0 1
+79 1 1
+34 1 1
+916 4 6
+1818 34 28
+51 21 16
+5 1 0
+5 1 0
+4 1 0
+11 1 0
+28 1 0
+8 1 0
+8 1 0
+1366 1 1
+38 0 1
+7507 0 1
+3084 2 0
+2569 1 0
+20 1 0
+8 1 0
+10 21 16
+51 10 10
+3979 6 5
+2086 1 0
+5466 0 1
+27 1 1
+1117 1 0
+66 1 0
+23 1 0
+2070 0 1
+67 1 0
+2611 1 0
+9 1 0
+23 23 18
+577 97925 17254
+5929 0 1
+1948 1 0
+72 0 1
+1365 60 62
+706
+
+chain 3984524 chr1_random 1663265 + 1620762 1663230 X 155270560 - 27920664 27963158 751
+107 0 1
+696 27 12
+658 0 12
+1440 0 2
+671 0 2
+506 0 3
+806 0 1
+4759 0 12
+131 1 0
+848 1 0
+213 0 8
+2046 1 0
+4979 0 1
+2482 1 0
+1502 1 0
+3474 0 4
+782 0 1
+12366 1 0
+3969
+
+chain 2698055 chr1_random 1663265 + 6164 122978 1 249250621 - 139553697 139584554 1020
+486 1 1
+19 9 9
+297 1 1
+73 1 1
+341 1 0
+105 1 0
+286 47997 0
+689 1 1
+48 1 1
+53 0 2
+1870 1 1
+39 1 1
+1682 0 39
+470 8 9
+691 1 0
+370 1 1
+24 1 1
+356 0 1
+1496 9599 84
+28 0 1
+7 4 0
+131 0 1
+66 932 181
+88 9 11
+10 7 0
+10 8 5
+5 0 3
+76 27759 26
+44 3 0
+26 0 2
+6 1 1
+59 3 1
+121 2 4
+4990 1 0
+672 0 1
+1487 1 1
+39 1 1
+1691 0 1
+36 10 10
+3503 1 1
+46 1 1
+4128 0 1
+1818 0 5
+1107 16 16
+841
+
+chain 2474973 chr1_random 1663265 + 1129393 1155387 1 249250621 + 229232478 229258468 1104
+3505 1 1
+44 1 1
+5232 4 0
+17207
+
+chain 2468882 chr1_random 1663265 + 1280682 1387454 1 249250621 - 133163307 133238928 735
+149 0 1
+7073 122 124
+1799 1 1
+43 1 1
+5594 24 23
+60 12182 28596
+3279 1 0
+571 21 21
+1080 1 0
+10 0 2
+1138 1 0
+3484 1 0
+1689 0 8
+810 42350 1
+1088 1 1
+21 1 0
+78 30 29
+746 0 2
+2729 1 0
+2088 0 3
+1949 966 174
+31 9 0
+12 16 16
+29 0 4
+13 100 98
+53 1884 0
+16 1 0
+5 0 1
+18 3916 1388
+1729 0 1
+1373 1 0
+102 1 0
+21 1 0
+4 1 0
+7 1 0
+38 2 0
+48 1 0
+525 5 4
+645 5 5
+1189 1 0
+1911 4 0
+69 8 8
+24 5 4
+284 1 0
+1481
+
+chain 2064841 chr1_random 1663265 + 247141 392880 1 249250621 - 247850669 247948213 608
+351 1 0
+965 0 1
+35 0 1
+248 0 1
+122 0 1
+1194 11 11
+580 3 5
+969 0 1
+425 5 5
+25 1 1
+586 1 1
+77 1 1
+1895 1 1
+37 1 2
+253 0 1
+560 1 1
+62 1 1
+74 1 1
+27 1 1
+90 31631 11346
+887 0 40
+759 32 0
+2596 0 1
+308 1 0
+37 0 1
+40 0 1
+346 17 19
+89 2 2
+34 1 2
+44 0 2
+35 0 1
+20 0 1
+260 0 1
+3009 1 1
+30 0 1
+5 10 12
+104 1 1
+48 0 1
+67 13 15
+1226 0 1
+111 7 7
+31 0 1
+47 1 3
+13 3 5
+38 7 10
+7 0 2
+48 0 1
+110 1 0
+623 0 2
+241 1 1
+47 1 1
+1601 0 1
+582 13 21
+1128 2 0
+348 4 4
+28 22 23
+481 0 2
+30 1 1
+628 0 1
+96 0 1
+30 0 1
+78 17 173
+64 55865 28961
+69 13 14
+498 0 1
+1593 0 4
+183 26 27
+337 1 0
+1433 0 1
+6191 0 2
+2435 0 1
+3451 540 0
+83 695 0
+1318 5 5
+21 1 1
+526 0 1
+833 0 1
+144 0 1
+427 8 8
+235 1 2
+297 1 1
+34 0 1
+250 0 3
+1007 0 1
+1403 1 1
+37 1 1
+355 1 1
+6 0 2
+94 1 1
+278 2 2
+5 0 1
+20 1 1
+667 24 24
+1858 10 12
+146 8 7
+2002 0 1
+284 0 1
+1233 0 1
+840 11 0
+914 2 0
+122 1 1
+26 0 2
+118
+
+chain 1850028 chr1_random 1663265 + 76914 101906 1 249250621 - 139621990 139717568 1363
+3916 0 1
+77 20 20
+26 0 856
+764 17 16
+12 1 0
+295 1 0
+2648 2870 23264
+250 997 50331
+2203 0 5
+797 1 0
+2197 1 1
+117 7 8
+429 1 0
+7345
+
+chain 1707631 chr1_random 1663265 + 501749 626697 1 249250621 + 144188000 145316961 852
+223 42 42
+236 22 22
+242 91 103
+199 8 8
+102 112 112
+50 126 126
+290 32 32
+213 45 45
+125 1 1
+56 1 1
+82 1 1
+27 13 13
+71 5 5
+493 3 3
+15 1 1
+248 1 1
+44 1 1
+65 1 1
+52 1 1
+169 1 1
+82 1 1
+292 1 1
+83 0 1580
+458 1 1
+16 1 1
+478 5 5
+568 23 17
+634 1 1
+46 1 1
+50 14 14
+864 31 61
+55 23320 364967
+85 1 1
+107 1 1
+376 1 1
+20 0 1
+195 10 10
+150 1 1
+35 1 1
+274 5 5
+143 1 0
+862 7 0
+20 1 0
+504 1 1
+25 1 1
+238 1 1
+36 1 1
+139 0 1
+25 1 1
+157 8 8
+60 16 16
+59 17 17
+285 0 1
+120 1 1
+69 1 1
+509 1 1
+59 1 1
+162 0 322
+70 5 5
+2169 1 1
+31 1 1
+224 1 1
+36 1 1
+76 1 0
+5 5 0
+109 6 6
+139 5 3
+65 0 20
+360 47 48
+86 18 17
+149 44 44
+76 54 55
+196 38 38
+139 139 6280
+107 1 1
+95 0 1
+46 1 1
+91 1 1
+18 1 1
+62 11 11
+511 0 1
+106 1 0
+505 0 2
+443 9 9
+519 112 112
+396 1 1
+26 1 1
+225 1 1
+57 1 1
+502 1 0
+485 1 1
+105 0 2
+146 1 1
+41 1 1
+203 1 1
+45 1 1
+62 5 5
+850 1 1
+55 2 2
+215 1 1
+45 1 1
+474 0 3
+19 1 1
+2337 1 1
+34 1 1
+148 1 0
+159 1 1
+32 1 1
+64 0 4
+849 1 1
+34 1 1
+126 38816 272842
+32 0 140
+3176 18 17
+6689 1 0
+274 0 1
+1449 0 1
+1312 1 0
+1861 8888 417910
+92 172 6531
+148 0 2
+213 1 1
+30 1 1
+227 1 1
+62 6 0
+276 1 1
+35 1 1
+94 14 14
+325 5 5
+118 1 1
+81 1 1
+234 4 0
+15 1 1
+243 1 1
+39 1 1
+117 1 1
+35 1 1
+83 1 1
+64 5 5
+55 13 13
+61 11 11
+175 1 1
+27 1 1
+134 1 1
+60 1 1
+64 1 1
+87 1 1
+615 1 1
+22 1 1
+201 5 5
+48 1 1
+117 1 1
+23 3 3
+319 6 6
+156 0 1
+25 1 1
+215 13 13
+97 14 14
+113 0 3
+35 1 1
+65 15 15
+480 0 1
+636 1 1
+107 1 1
+753 1 1
+43 1 1
+861 17 16
+470 1 1
+38 1 1
+579 1 1
+25 1 1
+224 1 1
+71 1 1
+266 36 36
+167 88 88
+400 53 53
+131 6 5
+220 22 19
+317 23 23
+109 95 101
+73 0 4726
+208 28 28
+293
+
+chain 1680348 chr1_random 1663265 + 1245440 1263421 1 249250621 + 116101959 116120000 1475
+441 0 14
+728 0 2
+1146 2 0
+1829 6 6
+93 3 2
+2916 0 6
+2013 0 47
+369 1 1
+27 9 0
+37 1 1
+200 1 0
+2285 0 2
+3527 1 1
+24 0 1
+1001 0 1
+1195 1 1
+39 1 1
+85
+
+chain 1335863 chr1_random 1663265 + 231796 246037 4 191154276 - 30408128 30422371 1784
+3391 6 6
+562 7 7
+5976 2 3
+4144 10 11
+143
+
+chain 1170727 chr1_random 1663265 + 577933 590476 1 249250621 + 144898104 144910646 2036
+1896 48 48
+2779 1 0
+7128 45 45
+646
+
+chain 1143882 chr1_random 1663265 + 1330802 1343100 1 249250621 - 133251270 133263558 2093
+1050 1 1
+51 1 1
+237 1 1
+35 1 1
+514 16 12
+76 9 1
+1642 12 12
+53 0 1
+3766 0 1
+40 1 1
+1513 0 1
+195 11 11
+135 26 26
+2627 1 0
+284
+
+chain 988809 chr1_random 1663265 + 564355 574807 1 249250621 - 104390169 104400621 2516
+59 1 2
+5994 1 1
+45 1 1
+3985 3 3
+42 1 0
+320
+
+chain 957971 chr1_random 1663265 + 256162 266426 1 249250621 + 1291904 1302191 2686
+83 0 1
+585 0 1
+1018 0 1
+18 1 1
+59 16 16
+1569 0 1
+69 1 0
+35 0 1
+36 1 1
+176 0 1
+48 0 1
+56 2 3
+41 0 1
+160 17 1
+461 13 21
+174 0 4
+517 7 7
+141 4 4
+89 0 1
+1155 1 0
+370 7 7
+143 1 0
+1019 22 22
+1177 0 1
+607 0 16
+86 0 3
+279
+
+chain 895962 chr1_random 1663265 + 196343 223209 1 249250621 - 247894293 247990621 2587
+108 25 24
+131 0 1
+299 0 1
+137 44 45
+51 0 1
+572 0 1
+406 36 37
+508 2162 63455
+80 5 8
+86 0 1
+61 0 1
+31 1 0
+165 14 15
+78 75 78
+234 0 1
+152 13 15
+849 0 1
+1798 12505 20653
+3495 0 1
+43 0 1
+1944 1 1
+26 1 1
+169 0 1
+365 0 1
+196
+
+chain 884318 chr1_random 1663265 + 4444 145186 1 249250621 + 109546538 109651856 1047
+123 47 1183
+818 1 1
+75 1 0
+22 1 1
+455 18927 20784
+855 1 0
+74 12001 11300
+2581 2 2
+31 0 1
+81 1 0
+24 1 1
+123 1 0
+147 0 1
+45 0 1
+26 0 1
+9 1 0
+12 2330 786
+22 41 53
+127 1706 714
+3729 74524 39329
+68 5 7
+3088 2 2
+15 5 6
+14 0 2
+657 1 1
+37 1 1
+2140 1 0
+3034 1 0
+42 1 1
+446 0 1
+55 2 2
+30 1 1
+391 1 1
+35 1 1
+982 3 0
+123 1 1
+28 0 4
+1503 1 0
+1159 0 3
+1464 0 1
+838 1 1
+47 1 3
+162 1 0
+139 1 1
+10 0 1
+2424 6 6
+448 1 0
+846 5 0
+1509
+
+chain 739113 chr1_random 1663265 + 68329 76740 1 249250621 + 109654512 109662863 6250
+254 1 0
+27 1 1
+746 1 0
+315 19 19
+163 42 2
+51 3 1
+44 1 1
+592 0 1
+216 1 1
+34 1 1
+2323 10 0
+10 236 236
+125 1 0
+806 213 213
+828 6 0
+82 6 6
+1253
+
+chain 688441 chr1_random 1663265 + 605533 614556 1 249250621 + 144612760 144812114 1498
+76 1 1
+70 1 1
+73 4 2
+40 0 2
+159 1 1
+56 2 0
+911 1 1
+63 1 1
+84 9 1
+149 1 1
+21 1 0
+606 1 1
+21 3 3
+132 12 10
+368 1 1
+26 1 1
+50 1 1
+65 1 1
+57 1 1
+44 1 1
+279 0 1
+34 0 4
+7 1 1
+308 0 32
+331 1 1
+84 1 1
+286 1 1
+35 1 1
+59 8 8
+146 1 1
+237 1 1
+52 1 1
+35 2 0
+40 1 1
+53 3 3
+103 1 1
+397 1 1
+59 1 0
+33 1 1
+587 11 11
+219 10 10
+71 5 5
+62 1 1
+38 1 1
+240 1 1
+70 1 1
+85 12 12
+86 413 190724
+207 1 0
+825 186 186
+172
+
+chain 590572 chr1_random 1663265 + 516651 523401 1 249250621 - 104651805 104658532 8996
+157 1 1
+17 1 1
+395 1 1
+65 1 1
+187 0 9
+21 1 1
+62 16 16
+110 2 0
+205 1 0
+43 1 1
+248 1 1
+59 4 2
+725 1 1
+49 1 1
+455 1 1
+106 1 1
+450 1 1
+133 0 2
+383 1 1
+37 1 1
+178 4 4
+70 1 1
+85 2 2
+43 1 1
+56 1 1
+22 24 0
+30 1 1
+64 1 1
+21 1 1
+198 1 1
+67 1 1
+58 1 0
+79 7 6
+74 1 1
+79 1 0
+26 1 1
+202 15 15
+352 2 2
+16 1 1
+51 22 19
+574 0 1
+87 1 1
+46 1 1
+88 1 1
+27 1 1
+120
+
+chain 526301 chr1_random 1663265 + 1264935 1361969 1 249250621 + 116056429 116101915 1232
+69 0 1
+30 1 1
+2663 2 0
+4185 1 0
+229 1 0
+25 1 1
+1104 1 0
+604 4 0
+1264 1 0
+2613 1 1
+21 1 0
+12 1 13
+2785 72844 21309
+397 19 2
+2203 1 1
+31 1 1
+658 1 1
+27 1 1
+923 9 9
+168 1 1
+46 0 2
+2502 43 43
+879 17 17
+644
+
+chain 506365 chr1_random 1663265 + 1399143 1404500 1 249250621 - 133194419 133199775 28136
+3175 1 0
+1447 0 1
+512 1 0
+221
+
+chain 482769 chr1_random 1663265 + 211415 216543 1 249250621 - 247889067 247894197 45886
+70 2 3
+905 2 3
+1091 1 1
+23 1 1
+302 15 14
+393 1 1
+24 1 1
+1961 0 1
+336
+
+chain 474976 chr1_random 1663265 + 1295676 1399043 1 249250621 + 115999419 116093083 1267
+571 10 10
+627 7 6
+46 1 1
+3095 0 1
+960 0 1
+608 11 10
+426 39 35
+2035 1 1
+23 1 1
+1866 17 18
+79 1 1
+1530 63368 32589
+866 110 110
+100 53 53
+1884 40 40
+3775 15606 36683
+2322 14 14
+145 49 49
+296 96 96
+297 0 2
+465 58 58
+262 22 22
+182 0 1
+638 1 0
+764
+
+chain 456897 chr1_random 1663265 + 1317 37745 1 249250621 + 109592282 109609521 6704
+1178 0 1
+16 1 0
+10 0 1
+4 1 1
+245 7763 188
+27 1 1
+1155 1 1
+91 4156 3450
+1810 51 51
+50 9 10
+567 3839 4491
+37 6346 0
+128 0 2
+29 50 48
+45 1519 155
+6 2 0
+9 10 6
+246 1806 0
+18 1 0
+5 2068 31
+2018 2 2
+20 3 3
+833 1 0
+101 1 0
+149
+
+chain 426748 chr1_random 1663265 + 63710 68210 1 249250621 - 139547929 139552428 99412
+1542 1 0
+2957
+
+chain 353264 chr1_random 1663265 + 462791 467071 1 249250621 + 144608404 144612698 156569
+71 50 50
+33 29 29
+226 10 10
+526 66 67
+55 50 50
+414 5 5
+57 46 58
+57 12 12
+254 1 1
+25 1 1
+52 13 13
+638 16 16
+579 1 1
+60 1 1
+178 1 1
+79 1 0
+35 0 3
+111 1 1
+43 1 1
+264 1 0
+119 1 1
+15 0 1
+76 1 0
+5
+
+chain 327229 chr1_random 1663265 + 1409275 1412904 1 249250621 + 115977641 115981270 200837
+2640 156 155
+473 0 1
+360
+
+chain 312923 chr1_random 1663265 + 1319916 1393318 1 249250621 + 115926067 115986980 1722
+1418 1 0
+1389 1 0
+1620 0 1
+374 1 0
+1361 0 1
+1994 1 0
+827 0 6
+1784 56909 44431
+253 1 0
+12 2 0
+8 24 14
+5344 2 0
+76
+
+chain 244562 chr1_random 1663265 + 478502 503782 1 249250621 - 100680024 100953393 1328
+106 13 13
+478 55 55
+310 1 1
+23 1 1
+376 1 1
+61 1 1
+1100 10 10
+810 5 0
+53 1 1
+119 1 1
+44 1 0
+94 100 32051
+60 5 5
+744 1 1
+87 1 1
+44 2 0
+53 11 5
+584 2 2
+30 0 17
+73 1 1
+49 1 1
+456 8 8
+796 19 19
+166 1 1
+42 1 1
+105 1 1
+38 1 1
+55 1 1
+80 1 1
+293 2 2
+19 1 1
+550 5637 9366
+68 24 22
+103 1 1
+35 0 1
+102 1 1
+39 6 0
+388 9 9
+21 1 1
+338 27 27
+500 4 0
+117 5 5
+271 1 1
+38 1 1
+273 3 3
+16 3 3
+80 1 1
+63 1 1
+130 1 1
+18 1 1
+204 1 1
+45 1 1
+141 1 1
+112 1 1
+75 1 0
+75 4 4
+83 2 0
+854 5 5
+104 0 4
+12 1 1
+351 1 1
+40 1 1
+102 4779 217183
+40 502 502
+31 0 12
+58 311 311
+110 52 52
+78 1 1
+46 535 535
+45
+
+chain 239113 chr1_random 1663265 + 455713 471283 1 249250621 + 144877306 144889304 5703
+73 1 0
+944 0 1
+2741 1 1
+77 1770 1206
+12 1449 338
+10 71 1301
+14 10 145
+26 4281 1018
+2672 0 1
+1418
+
+chain 228041 chr1_random 1663265 + 450807 453388 GL000192.1 547496 + 525635 528523 474030
+521 25 26
+256 4 316
+195 1 0
+183 4 0
+249 48 48
+915 19 18
+161
+
+chain 219405 chr1_random 1663265 + 8071 23476 1 249250621 + 109602419 109665881 23204
+1669 2217 48069
+1950 5 1
+213 6609 8813
+681 1 0
+580 0 1
+296 37 38
+248 0 4
+301 31 31
+143 38 38
+386
+
+chain 219231 chr1_random 1663265 + 32127 34517 1 249250621 - 139682423 139684814 491274
+85 27 27
+14 0 1
+204 5 5
+63 24 24
+1968
+
+chain 210320 chr1_random 1663265 + 459650 474308 GL000192.1 547496 + 522489 531711 22108
+267 0 10
+1175 5 1
+48 0 2
+16 3 3
+119 0 12
+37 12 12
+1340 8711 3256
+34 0 2
+58 1 0
+38 1 0
+351 5 5
+486 17 15
+158 81 81
+76 1 1
+36 1 1
+69 12 13
+1500
+
+chain 207966 chr1_random 1663265 + 29704 55292 1 249250621 + 109529352 109557857 7568
+742 273 273
+560 0 1
+232 17541 20458
+729 2 2
+97 3 3
+89 1 1
+68 0 1
+28 1 1
+2575 2 0
+59 1 1
+2585
+
+chain 202325 chr1_random 1663265 + 27243 45056 1 249250621 - 139669260 139678536 8944
+1432 157 157
+50 45 45
+677 2608 49
+27 8791 867
+266 9 9
+169 1 1
+62 1 1
+67 7 5
+28 1 1
+1619 22 22
+41 127 127
+21 1 1
+40 2 1
+32 1 1
+362 0 1949
+1147
+
+chain 199687 chr1_random 1663265 + 18553 20627 1 249250621 + 109595202 109597276 600797
+2074
+
+chain 171508 chr1_random 1663265 + 447628 491985 1 249250621 + 148535207 148566609 6481
+121 14 14
+517 0 4
+507 1 0
+74 1 1
+41 0 1
+61 4541 11291
+1073 1 0
+718 70 44
+66 31371 11607
+690 1 1
+115 1 1
+61 1 1
+70 1 1
+57 0 4
+54 1 1
+41 2 6
+28 5 77
+73 1 1
+34 5 5
+887 1 0
+427 1 1
+7 0 5
+40 1 1
+59 1 1
+47 1 1
+121 9 9
+57 2 0
+362 1 1
+48 4 4
+429 1 1
+28 1 1
+160 1 1
+92 5 0
+15 0 5
+15 1 1
+139 5 5
+37 1 1
+87 1 1
+40 1 1
+253 1 1
+35 1 1
+197 1 1
+69 1 1
+114 1 1
+79 1 1
+51
+
+chain 170629 chr1_random 1663265 + 474420 479154 1 249250621 - 104365477 104643040 2652
+3982 697 273526
+55
+
+chain 143194 chr1_random 1663265 + 449166 450695 1 249250621 - 104373413 104374943 899312
+167 0 1
+362 11 11
+989
+
+chain 141808 chr1_random 1663265 + 195186 230464 1 249250621 + 1361949 1390000 8100
+66 0 1
+865 27548 20313
+75 1 1
+163 2 2
+2267 0 2
+1549 0 2
+37 1 1
+597 1 1
+28 1 1
+269 14 19
+59 1 1
+20 1 1
+734 2 0
+977
+
+chain 137395 chr1_random 1663265 + 446016 447466 1 249250621 + 144922370 144923820 937713
+1450
+
+chain 120082 chr1_random 1663265 + 1413004 1414278 1 249250621 + 115908963 115910237 1071399
+1274
+
+chain 110577 chr1_random 1663265 + 0 1193 5 180915260 + 33390295 33391489 1161255
+153 0 1
+942 4 4
+94
+
+chain 101176 chr1_random 1663265 + 442945 444014 1 249250621 - 104338746 104339815 1265508
+1069
+
+chain 61431 chr1_random 1663265 + 9891 10535 1 249250621 + 109697165 109697809 2020878
+644
+
+chain 48091 chr1_random 1663265 + 497444 501649 1 249250621 + 144842054 144846259 8551
+4205
+
+chain 31572 chr1_random 1663265 + 576223 577747 4 191154276 + 100714665 100716180 4375428
+114 20 20
+105 460 462
+56 375 378
+65 263 249
+66
+
+chain 28915 chr1_random 1663265 + 230464 231387 1 249250621 + 1420670 1421247 4712368
+191 574 228
+67 38 38
+53
+
+chain 27385 chr1_random 1663265 + 205390 205833 1 249250621 - 247799065 247799507 5896168
+141 86 86
+106 47 46
+63
+
+chain 25670 chr1_random 1663265 + 87811 88395 7 159138663 - 51241913 51242744 3648322
+121 405 652
+58
+
+chain 21035 chr1_random 1663265 + 376636 377171 1 249250621 - 247932544 247932844 3872256
+107 118 0
+61 93 15
+49 39 0
+68
+
+chain 18694 chr1_random 1663265 + 540390 626404 1 249250621 + 148529505 148589817 1111
+44 254 254
+43 76 73
+54 196 196
+37 240 6477
+31 4 4
+4 2528 2531
+8 1 1
+42 1 1
+60 70185 38258
+94 10137 10136
+31 1 1
+3 167 167
+88 400 400
+52 829 828
+33 10 0
+52 281 281
+28
+
+chain 18305 chr1_random 1663265 + 612752 613165 1 249250621 + 146400208 146400621 434456
+18 31 31
+215 97 97
+52
+
+chain 18205 chr1_random 1663265 + 210123 210768 1 249250621 + 1400633 1401273 11939617
+55 410 403
+82 10 12
+88
+
+chain 16211 chr1_random 1663265 + 84691 84862 5 180915260 + 68593902 68594073 10696361
+171
+
+chain 14543 chr1_random 1663265 + 375983 376437 1 249250621 - 247932585 247932921 12601411
+13 231 153
+56 101 61
+53
+
+chain 11766 chr1_random 1663265 + 209234 209374 6 171115067 + 48765751 48765891 19406706
+84 4 4
+52
+
+chain 10899 chr1_random 1663265 + 1264583 1264729 4 191154276 - 96228610 96228756 20935897
+69 19 19
+58
+
+chain 9779 chr1_random 1663265 + 575439 575892 5 180915260 - 127861600 127862049 19918678
+60 389 385
+4
+
+chain 9449 chr1_random 1663265 + 206282 206576 1 249250621 - 247814999 247815293 24134146
+64 179 179
+51
+
+chain 9080 chr1_random 1663265 + 376922 377270 1 249250621 - 247932789 247932982 12922008
+42 39 0
+12 156 79
+8 39 0
+52
+
+chain 7488 chr1_random 1663265 + 375996 376227 1 249250621 - 247932827 247932944 24096271
+39 178 64
+14
+
+chain 7272 chr1_random 1663265 + 492183 493450 GL000192.1 547496 + 517200 518462 5534
+104 1136 1131
+27
+
+chain 7258 chr1_random 1663265 + 576783 577499 14 107349540 - 76512188 76512903 4928952
+56 262 262
+101 216 215
+81
+
+chain 7167 chr1_random 1663265 + 376446 376521 1 249250621 - 247932507 247932582 27908410
+75
+
+chain 6857 chr1_random 1663265 + 87342 87413 4 191154276 - 48731804 48731875 28524152
+71
+
+chain 6426 chr1_random 1663265 + 508964 509092 1 249250621 + 144828390 144828518 146082
+13 51 51
+64
+
+chain 6204 chr1_random 1663265 + 211009 211075 1 249250621 + 1467491 1467557 30075428
+66
+
+chain 6008 chr1_random 1663265 + 376783 376999 1 249250621 - 247932727 247932982 14593768
+49 132 171
+35
+
+chain 5855 chr1_random 1663265 + 576112 576191 20 63025520 + 560198 560277 14627950
+79
+
+chain 5539 chr1_random 1663265 + 247082 247140 16 90354753 - 36623787 36623845 31913042
+58
+
+chain 5517 chr1_random 1663265 + 575499 575571 1 249250621 - 135388947 135389019 22575370
+19 14 14
+39
+
+chain 5153 chr1_random 1663265 + 463736 463802 1 249250621 - 100897669 100897735 496173
+66
+
+chain 4331 chr1_random 1663265 + 576997 577043 4 191154276 + 125192159 125192205 31588172
+46
+
+chain 4269 chr1_random 1663265 + 508977 509028 1 249250621 - 101245694 101245744 11082093
+11 1 0
+24 1 1
+14
+
+chain 3392 chr1_random 1663265 + 1264741 1264777 1 249250621 + 103601716 103601752 22855599
+36
+
+chain 2584 chr1_random 1663265 + 472532 472613 1 249250621 - 104701386 104701467 60543
+81
+
+chain 2530 chr1_random 1663265 + 576576 576677 2 243199373 + 18874674 18874775 4960893
+101
+
+chain 2443 chr1_random 1663265 + 508878 508906 1 249250621 + 145358788 145358816 8460
+28
+
+chain 2298 chr1_random 1663265 + 376035 376059 1 249250621 - 247932520 247932544 25650669
+24
+
+chain 2200 chr1_random 1663265 + 377179 377218 1 249250621 - 247932814 247932853 18046603
+39
+
+chain 2078 chr1_random 1663265 + 576191 576213 2 243199373 - 87184513 87184535 19810119
+22
+
+chain 1902 chr1_random 1663265 + 462945 462974 1 249250621 + 146388727 146388756 1440299
+29
+
+chain 1597 chr1_random 1663265 + 87932 87955 1 249250621 + 203810737 203810760 8954286
+23
+
+chain 1582 chr1_random 1663265 + 576728 576783 12 133851895 + 80469819 80469874 8882774
+55
+
+chain 1575 chr1_random 1663265 + 377270 377295 1 249250621 - 247932789 247932814 25950613
+25
+
+chain 1557 chr1_random 1663265 + 376743 376767 1 249250621 - 247932958 247932982 25686497
+24
+
+chain 1423 chr1_random 1663265 + 577528 577578 3 198022430 + 24122600 24122650 5633229
+50
+
+chain 1401 chr1_random 1663265 + 208964 209027 19 59128983 + 53692979 53693042 24768107
+63
+
+chain 1269 chr1_random 1663265 + 577058 577101 X 155270560 - 54470903 54470946 5438939
+43
+
+chain 1137 chr1_random 1663265 + 88481 88531 X 155270560 - 107394638 107394688 10193603
+50
+
+chain 1096 chr1_random 1663265 + 88429 88481 1 249250621 - 213837318 213837370 14790649
+52
+
+chain 963 chr1_random 1663265 + 575892 575970 1 249250621 - 198864223 198864301 11419759
+78
+
+chain 917 chr1_random 1663265 + 455298 455327 GL000192.1 547496 - 58673 58702 411262
+29
+
+chain 870 chr1_random 1663265 + 577218 577269 6 171115067 - 89553434 89553485 24911812
+51
+
+chain 794 chr1_random 1663265 + 88312 88337 4 191154276 + 171087862 171087887 6635553
+25
+
+chain 649 chr1_random 1663265 + 576545 576576 15 102531392 - 5321440 5321471 7251364
+31
+
+chain 622 chr1_random 1663265 + 576462 576495 11 135006516 + 114505284 114505317 6564387
+33
+
+chain 546 chr1_random 1663265 + 88531 88556 6 171115067 + 144792007 144792032 10415340
+25
+
+chain 398 chr1_random 1663265 + 575763 575814 14 107349540 + 34662629 34662680 24063646
+51
+
+chain 22466167312 chr2 242951149 + 0 242751149 2 243199373 + 10000 243102476 1
+1201236 1 0
+2057 1 1
+26 1 1
+4043 0 22
+82 101 7
+33 0 74
+36 13 1
+67 0 48
+152 0 418
+50 2 0
+6 6 0
+76 74 0
+20 6 0
+22 118 0
+374 0 2446
+836 0 2310
+21 0 2444
+21507 1 1
+50 0 4
+2041 4 0
+9052 0 2
+81 8 0
+10 42 0
+1078 1 0
+4122 0 1
+1608 1 28
+4029 9 0
+967 1000 4547
+414 0 27
+2237132 1 0
+2458 17 17
+3915 47 47
+633 0 4
+3531 14 14
+3954 50000 51129
+1426129 100025 160449
+11087286 3 0
+773 50000 103977
+1576 1 0
+240 1 0
+318 0 2
+258 16 0
+2848 10 10
+1404 1 1
+27 1 1
+703 0 13
+375 1 0
+4783388 25000 35000
+848 2 0
+1225 2 0
+391 0 1
+3445 24 24
+184 1 1
+28 1 1
+49 4 0
+4514 9 0
+9628 9 1
+1483 7 7
+1990 1 0
+1949 0 1
+2716230 0 1
+46732767 9 5
+9477928 3 0
+7520813 0 72396
+1900436 150000 294073
+17672 0 1
+5792 0 1
+9019 266 0
+2942 1 0
+9388 0 2
+37826 0 4
+23440 4 0
+290929 1000000 1273578
+731068 3000000 3000000
+2558421 1 0
+1196 0 10
+686 1 0
+26 3 0
+15 1 1
+2309 1 0
+1332 23 22
+344 1 0
+1645 4 4
+6564 0 1
+6329 0 1
+769 1 0
+873 0 7
+1299 1 0
+8250 15 15
+4291 12548 10626
+1054 0 103
+84 218 0
+5897 1 1
+33 1 1
+9905 37 51
+1645 113 113
+1597 4 4
+61 1 1
+866 0 13
+2830 0 3
+2819 2 0
+156 436 88
+100 54 0
+4753 8 0
+4903 6 6
+3847 2 0
+108126 145 0
+3542 0 1
+10276 1 0
+402 1 1
+47 1 1
+63 0 2
+583 1 1
+34 1 1
+8975 46 0
+378 1 1
+70 1 1
+2476 102 0
+1754 1 0
+8426 1 0
+11986570 142000 151150
+14207 1 1
+49 1 1
+1784 12 0
+406 0 1
+1874 1 1
+33 1 1
+4795 0 2
+3686 1 1
+15 1 1
+164 0 2
+7287 5 5
+702023 150000 72796
+69 0 1
+1598 1 0
+1340 1 0
+1030 4 0
+1166 10 10
+629 27 27
+5750 1 1
+34 1 1
+3283 4 2
+496 21 1
+25 1 9
+41 1 1
+329 4 4
+9955 41 41
+10953 1 2
+1417 44 0
+911 0 17
+18270 0 1
+178429 281526 0
+34455 406 0
+58863 2 1
+1843 2 0
+14994 1 0
+12992 0 2
+2571146 0 1
+35688061 100000 108224
+29671719 0 1
+39665349 0 1
+14876089 20000 64197
+401 3 0
+1831 1 1
+61 1 1
+654 1 11
+138 28 0
+105 1 1
+25 4 0
+73 9 9
+3247 0 2
+1355 0 1
+816 21 25
+526 1 1
+60 1 1
+773 0 1
+1494 0 1
+448 44 44
+1191 0 1
+21 1 1
+596 0 1
+1582 0 1
+425 3 0
+1141 8 0
+136 744 80
+18 1 0
+4 1 0
+8 4 2
+32 1 0
+71 0 1
+385747 1 1
+110 1 1
+51 7 7
+54 15205 15205
+54 7 7
+51 1 1
+110 1 1
+5198249 1 0
+108 0 40
+65 0 80
+100 2 82
+442 1 1
+35 1 1
+119 129 9
+33 40 0
+42 1 1
+86 40 0
+1330 1 0
+1194 2 0
+11 1 1
+1773 5 0
+1623 1 1
+25 1 1
+2422 1 1
+20 1 0
+2315 1 0
+31 1 1
+1508 3 0
+50 4 0
+970 6 6
+7234 0 4
+1228 0 1
+1233 1 8
+744 16 16
+3447 1 1
+41 1 1
+3297 2 0
+1714 0 2
+2299 0 2
+2143 1 1
+18 1 1
+917 0 1
+1082 1 1
+49 1 1
+9098 4 0
+5529 1 0
+3266 8 0
+894 0 6
+3536 0 2
+4179 13 18
+1785 1 0
+1675 6 0
+1216 33000 32348
+287 109 573
+12548 30000 30000
+952154 25000 41011
+1914 0 1
+225 1 1
+57 1 1
+2910 1 0
+471 0 1
+1956 1 1
+43 1 1
+1000 92 0
+2854 0 3
+1837 0 306
+1007 0 30
+206 35 32
+217 17 17
+1525 0 8
+413 1 1
+32 2 2
+1573 12 12
+2258676
+
+chain 1437141 chr2 242951149 + 234136066 234151271 2 243199373 - 8712841 8728046 1459
+15205
+
+chain 1229376 chr2 242951149 + 110524471 111016063 2 243199373 - 132402743 134718956 53
+41 12371 12350
+33 0 23
+11 197610 197512
+5295 5 5
+190 69 19
+2195 1 0
+285 34 34
+1682 1 0
+182 11 6
+291 0 1
+1506 15 16
+146 5 5
+2050 51 51
+186 8 7
+68 7 6
+41 1 0
+306 0 1
+1545 1 0
+1334 25 24
+543 0 2
+224 17 21
+615 1 0
+208 2 0
+158 27 21
+3320 0 1
+576 0 2
+4562 0 6
+1023 0 1
+977 0 1
+3904 1 0
+827 415 28
+1508 14 13
+9571 36 36
+1393 1 1
+42 1 1
+2205 0 2
+5258 36 0
+42 2 0
+4437 2 0
+3357 1 0
+6289 0 9
+1996 1 0
+3228 0 1
+202 0 1
+2743 7 0
+24 0 5
+549 3 1
+942 0 6
+1815 8 0
+874 0 3
+4737 0 2
+852 14 18
+518 14 14
+4377 1 1
+49 1 1
+3270 1 0
+753 0 4
+240 1 0
+2391 0 1
+4745 4 0
+5752 0 2
+880 0 1
+397 1 0
+1407 0 3
+120 1 1
+89 1 1
+7011 3 0
+188 8 8
+834 5 0
+94 18 18
+3711 150112 1975291
+345 52 52
+100 8 8
+52 6 6
+650 6 6
+273 91 95
+88 90 90
+331 116 116
+66 35 35
+145 13 15
+95 6 6
+301 43 47
+444 12 12
+645 116 119
+215 31 31
+748 58 57
+212 71 71
+420 38 38
+190 4 4
+51 32 32
+65 32 32
+182 69 69
+161 17 17
+74 36 36
+170 25 25
+124 19 15
+230
+
+chain 33206 chr2 242951149 + 111008548 111015495 2 243199373 + 113147044 113153995 310
+112 345 345
+52 1095 1095
+15 0 4
+76 88 88
+90 331 331
+116 66 66
+35 560 560
+43 1101 1101
+116 215 215
+31 748 748
+58 212 212
+71 420 420
+38 245 245
+32 65 65
+32 182 182
+69 252 252
+36
+
+chain 15095 chr2 242951149 + 97284299 97473552 2 243199373 - 145080546 145267103 122
+48 13638 11732
+218 15837 15837
+37 1645 1645
+113 8336 8336
+436 100 100
+54 121645 121635
+3 25 0
+101 26915 26159
+9 0 1
+93
+
+chain 10366 chr2 242951149 + 110742577 110753868 2 243199373 + 113162562 113173850 1257
+34 5889 5884
+51 5290 5292
+27
+
+chain 3994 chr2 242951149 + 111050518 111050561 2 243199373 - 132647167 132647210 483
+43
+
+chain 3626 chr2 242951149 + 1208025 1208063 2 243199373 + 1217618 1217656 30090800
+38
+
+chain 3098 chr2 242951149 + 110780566 110780602 2 243199373 + 100698198 100698234 394442
+36
+
+chain 2548 chr2 242951149 + 89594034 89594300 2 243199373 - 153635204 153635700 103
+90 9 107
+22 9 0
+32 3 0
+5 0 125
+21 15 30
+5 1 0
+25 0 5
+29
+
+chain 2507 chr2 242951149 + 1207989 1208025 2 243199373 + 1217656 1217692 7254147
+36
+
+chain 2306 chr2 242951149 + 97446409 97446434 2 243199373 + 98080299 98080324 1844703
+25
+
+chain 5644665978 chr20 62435964 + 8000 62435964 20 63025520 + 60000 62965520 20
+26259569 1765661 3100000
+234339 1000000 150000
+4004088 0 1
+6459 0 244
+37810 0 2
+1044573 20000 50000
+9411883 2 8
+362 0 1
+11607353 0 1
+1301304 1 0
+31033 0 9
+1154 0 2
+1088 1 1
+29 1 1
+2509 0 2
+407 1 0
+40 1 1
+3787164 27050 50000
+71932 110000 50000
+694117 0 1
+1008033
+
+chain 3228730713 chr21 46944323 + 9719767 46944323 21 48129895 + 10697896 48119895 23
+490233 3050000 3150000
+19828060 0 1
+8789369 1199 50000
+243783 1500 1500
+1381822 1359 50000
+3437231
+
+chain 42537850 chr21_random 1679693 + 281005 1255172 21 48129895 + 9411193 10647896 88
+184355 50000 489372
+131056 458754 281918
+150002
+
+chain 21600281 chr21_random 1679693 + 876305 1679693 21 48129895 - 37585054 38304458 99
+178865 280890 346005
+315 2 2
+38 1 1
+261 1 1
+24 1 1
+157 0 325
+16 1 1
+85 1 1
+66 1 1
+330 11 11
+235 1 1
+51 1 1
+405 1 1
+26 1 1
+130 5 5
+80 1 1
+91 1 1
+20 1 1
+244 0 1
+478 1 1
+5 1 0
+13 0 1
+49 1 1
+197 10 10
+158 1 1
+57 0 1
+829 1 1
+60 1 1
+51 0 1
+584 1 0
+21 2 0
+151 20 20
+316 1 1
+16 1 1
+100 7 7
+102 1 1
+49 1 1
+125 1 0
+102 13 13
+153 20 20
+199 1 0
+35 1 1
+367 1 1
+51 1 1
+344 1 1
+101 1 1
+243 1 1
+27 1 1
+338 0 4
+166 15 15
+73 1 1
+44 1 1
+282 4 4
+67 1 1
+54 1 1
+216 1 1
+48 1 1
+76 1 1
+70 1 1
+392 1 1
+44 1 1
+65 8 9
+362 0 4
+34 1 1
+68 1 1
+57 1 0
+120 1 1
+374 1 1
+21 1 1
+121 1 1
+34 1 1
+80 1 0
+64 2 0
+162 8 8
+184 1 1
+34 1 1
+658 2 2
+52 0 4
+297 1 0
+136 1 1
+20 1 1
+905 0 1
+250 7 8
+138 0 3
+104 1 0
+42 1 1
+539 0 1
+43 4 0
+633 0 20
+353 17 17
+969 4 0
+39 3 3
+210 3 1
+188 7 7
+459 2 2
+25 1 1
+207 1 1
+55 1 1
+375 1 1
+66 1 1
+599 0 2
+395 1 1
+33 1 1
+73 1 1
+35 2 0
+275 9999 10000
+353 1 1
+26 1 1
+423 1 1
+32 1 1
+86 7 7
+197 1 1
+44 1 1
+96 1 1
+77 7 0
+247 0 2
+77 1 1
+425 13 1
+32 1 1
+65 1 1
+217 3 2
+115 1 1
+33 1 1
+268 1 0
+959 1 1
+63 1 1
+93 5 5
+185 1 1
+31 1 1
+944 12 12
+413 1 1
+92 1 1
+276 1 1
+35 1 1
+500 1 1
+31 149436 9
+158069
+
+chain 14432948 chr21_random 1679693 + 78709 231005 21 48129895 + 9882623 10034920 205
+77296 0 1
+75000
+
+chain 7807601 chr21_random 1679693 + 1362161 1471624 1 249250621 - 105758025 105867745 293
+77 11427 11419
+174 5 5
+857 64 64
+2170 0 2
+621 1 1
+26 1 1
+4365 0 1
+155 0 1
+452 0 4
+941 0 4
+403 1 1
+45 1 1
+534 86 86
+2198 0 1
+303 2 0
+5470 6 6
+845 1 1
+45 1 1
+221 6 0
+321 1 1
+44 1 1
+354 1 0
+374 131 130
+577 6 5
+263 17 16
+207 0 2
+1746 14 14
+3223 1 1
+46 4 4
+1479 1 1
+46 1 1
+383 0 3
+44 1 1
+2724 67 67
+47 145 145
+350 116 116
+138 0 1
+1 65 65
+796 17 17
+645 1 0
+24 1 1
+1318 1 0
+687 1 1
+41 1 1
+2292 1 1
+37 1 1
+589 1 1
+37 1 0
+670 13 13
+357 4 0
+2667 3 0
+1941 1 1
+31 1 1
+1538 54 54
+64 166 166
+120 226 226
+46 14 0
+14 155 155
+92 54 54
+26 55 55
+98 131 131
+36 1 1
+76 391 391
+44 294 294
+37 813 813
+35 219 219
+898 1 1
+19 1 1
+213 12 12
+1926 1 1
+21 1 1
+4561 1 1
+28 1 1
+8361 1 1
+43 1 1
+429 211 492
+3095 0 1
+3873 1 1
+43 5 5
+3785 171 171
+65 122 122
+70 116 116
+29 459 459
+36 352 352
+39 93 93
+39 190 190
+41 1783 1784
+35 509 509
+27 394 394
+57 834 834
+58 10 10
+17 758 760
+41 0 4
+82 194 194
+60 543 543
+31 58 58
+46 607 607
+34 98 98
+31 1 1
+38 563 562
+135 1980 1976
+48 370 370
+42 515 515
+49 456 456
+3137 0 1
+2483 1 0
+357 1 1
+49 1 1
+1181 1 0
+885 1 0
+86
+
+chain 3630496 chr21_random 1679693 + 696416 1463441 21 48129895 + 9645548 10215976 235
+129889 481231 310631
+225 46 51
+383 6 6
+73 18 18
+200 18 39
+236 63 68
+123 340 365
+57 300 259
+51 138 138
+71 55 55
+60 152 152
+51 100 103
+61 358 357
+85 1906 236
+88 157 153
+56 39 39
+73 20146 20047
+67 1 0
+57 154 154
+59 940 953
+61 205 205
+60 46 46
+122 149 149
+53 64 56
+210 16 16
+209 1 0
+214 29 29
+71 69616 76139
+67 47 47
+145 350 354
+116 139 135
+65 13718 10425
+54 64 64
+166 120 120
+225 75 75
+74 14 13
+67 92 92
+54 26 26
+55 98 98
+127 117 117
+173 16 15
+202 44 44
+198 21 17
+75 37 37
+442 18 18
+353 35 35
+219 27532 0
+105 0 3
+66 65 65
+122 70 70
+116 29 29
+459 36 36
+278 17 17
+57 39 40
+93 39 39
+190 41 41
+285 16 20
+859 22 37
+176 4 4
+183 32 32
+206 35 36
+509 27 27
+394 57 56
+116 5 5
+596 1 0
+116 85 85
+54 0 1
+119 0 2
+585 124 127
+74 10 11
+109 60 60
+82 22 22
+439 31 31
+58 46 46
+106 21 22
+186 15 14
+279 34 34
+98 70 67
+166 1 0
+396 135 135
+1551 12 12
+90 0 3
+69 4 4
+48 3 0
+203 48 48
+370 42 42
+139 14 53
+362 49 49
+456
+
+chain 2630212 chr21_random 1679693 + 936 28709 21 48129895 + 44682664 44710462 1048
+3985 6 7
+8941 0 30
+3327 1 1
+74 1 1
+859 22 22
+89 70 70
+489 14 3
+11 2 1
+10 10 0
+10 0 1
+31 1 27
+556 3 0
+128 0 1
+358 1 1
+45 1 1
+1712 8 0
+6545 32 31
+431
+
+chain 517534 chr21_random 1679693 + 1332563 1373665 GL000194.1 191469 - 21469 62943 261
+130 2 2
+53 1 1
+139 1 1
+60 1 1
+321 125 125
+72 1 1
+81 59 59
+248 22 23
+250 13 13
+407 61 61
+205 60 60
+46 122 122
+149 53 53
+14 0 8
+50 650 650
+29 19697 20073
+100 1 4
+106 2 2
+158 1 1
+89 1 1
+10 1 1
+65 1 1
+48 1 1
+156 1 1
+61 1 1
+156 1 1
+81 1 1
+522 16 16
+377 22 22
+358 1 1
+17 1 1
+141 1 0
+29 0 1
+16 1 1
+105 1 1
+49 2 1
+63 1 1
+32 1 0
+7 1 1
+349 1 2
+102 1 1
+146 1 0
+93 3 0
+149 1 1
+86 1 1
+220 1 1
+111 1 1
+195 19 19
+108 1 1
+79 6 1
+98 0 1
+29 2 2
+98 1 1
+125 1 1
+196 1 1
+52 1 1
+767 1 1
+68 3 3
+70 1 1
+66 1 1
+331 1 1
+22 1 1
+60 77 77
+437 1 1
+61 1 1
+134 1 1
+48 4 2
+26 0 2
+79 1 1
+16 1 1
+77 1 1
+24 1 1
+176 1 1
+33 1 1
+61 0 4
+141 1 1
+17 1 1
+232 1 1
+42 1 1
+439 2 1
+31 1 1
+55 1 0
+181 1 1
+77 4 4
+145 4 5
+22 1 1
+159 1 6
+53 1 1
+63 1 1
+67 6 6
+71 1 1
+25 1 1
+103 6 6
+303 6513 6492
+211 1 1
+87 1 1
+170 2 2
+36 0 6
+361 1 1
+58 1 1
+292 10 10
+201 1 1
+35
+
+chain 353583 chr21_random 1679693 + 1323386 1332563 GL000218.1 161147 - 0 9198 304
+693 1 1
+28 4 0
+425 51 51
+874 2 4
+421 1 1
+23 1 1
+299 2 1
+20 3 3
+88 1 1
+35 1 1
+283 4 4
+42 4 4
+719 14 14
+181 1 1
+41 1 1
+1010 1 1
+59 1 1
+478 1 1
+45 1 0
+78 1 1
+315 1 1
+22 1 1
+342 1 1
+27 1 1
+716 0 25
+83 1 1
+44 1 1
+218 6 6
+142 1 1
+178 1 1
+220 1 1
+35 1 1
+55 1 1
+44 1 1
+143 1 1
+80 1 1
+85 1 1
+46 1 1
+169 1 1
+56 1 1
+94 1 1
+51 1 1
+48
+
+chain 153763 chr21_random 1679693 + 1307498 1317523 1 249250621 + 142541121 142549427 248494
+38 225 225
+46 934 934
+63 240 230
+50 653 627
+57 559 562
+4 186 183
+51 101 101
+16 235 235
+70 1848 174
+58 193 194
+3 255 257
+97 40 40
+164 35 35
+167 27 27
+82 213 218
+106 172 171
+55 274 274
+125 214 209
+158 123 124
+94 169 169
+69 430 425
+66 871 864
+95 213 213
+81
+
+chain 88175 chr21_random 1679693 + 0 28278 GL000210.1 27682 - 0 27251 1050
+107 675 0
+154 27310 26958
+32
+
+chain 46308 chr21_random 1679693 + 1305249 1307368 21 48129895 - 38147885 38150014 728191
+46 171 171
+69 165 166
+32 292 292
+34 184 184
+26 73 73
+23 117 117
+57 54 54
+7 16 25
+68 78 78
+23 242 242
+53 230 230
+59
+
+chain 40072 chr21_random 1679693 + 1311066 1311528 3 198022430 + 38430454 38430916 3283349
+95 1 1
+47 1 1
+177 1 1
+41 1 1
+98
+
+chain 25551 chr21_random 1679693 + 1316263 1317134 21 48129895 + 10022171 10023044 3443865
+97 94 94
+87 148 147
+94 340 343
+11
+
+chain 20886 chr21_random 1679693 + 1305172 1307309 Y 59373566 - 45989384 45991522 2022
+77 46 46
+64 50 50
+57 69 70
+165 32 32
+86 11 11
+195 34 34
+184 122 122
+117 57 57
+54 91 91
+50 51 51
+242 61 61
+68 9 9
+145
+
+chain 10360 chr21_random 1679693 + 1384481 1394861 21 48129895 - 38158677 38169079 831
+56 10224 10246
+100
+
+chain 9106 chr21_random 1679693 + 1316541 1317639 2 243199373 + 56015784 56016880 4408555
+45 37 37
+66 97 95
+66 672 672
+115
+
+chain 7814 chr21_random 1679693 + 1312477 1312593 8 146364022 + 34952530 34952621 21041862
+26 37 12
+53
+
+chain 6987 chr21_random 1679693 + 1305359 1306761 1 249250621 - 105769657 105771059 738748
+38 5 5
+7 1324 1324
+28
+
+chain 3478 chr21_random 1679693 + 1309705 1309742 X 155270560 - 92499801 92499838 30075241
+37
+
+chain 2939 chr21_random 1679693 + 1312274 1312311 1 249250621 - 217601682 217601719 16037052
+37
+
+chain 2906 chr21_random 1679693 + 1394861 1394892 GL000247.1 36422 - 2105 2136 848
+31
+
+chain 2805 chr21_random 1679693 + 1309675 1309705 4 191154276 - 16268024 16268054 28769751
+30
+
+chain 2788 chr21_random 1679693 + 1374701 1374765 GL000194.1 191469 - 63980 64044 1175
+9 36 36
+19
+
+chain 2571 chr21_random 1679693 + 1317411 1317442 20 63025520 - 39738360 39738391 24462467
+31
+
+chain 2324 chr21_random 1679693 + 1311588 1311646 2 243199373 + 3637936 3637994 8156424
+58
+
+chain 1980 chr21_random 1679693 + 1440240 1440313 1 249250621 + 142677559 142677632 922
+73
+
+chain 1679 chr21_random 1679693 + 1316387 1316422 13 115169878 + 41439086 41439121 11997585
+35
+
+chain 1437 chr21_random 1679693 + 1316422 1316454 3 198022430 + 119282439 119282471 8460363
+32
+
+chain 1151 chr21_random 1679693 + 1312216 1312274 13 115169878 + 46060123 46060181 10002138
+58
+
+chain 1007 chr21_random 1679693 + 1312144 1312195 17 81195210 + 33522637 33522688 8813060
+51
+
+chain 810 chr21_random 1679693 + 1306268 1306301 4 191154276 - 63157613 63157646 21715000
+33
+
+chain 762 chr21_random 1679693 + 1312422 1312477 7 159138663 + 153013126 153013181 10840208
+55
+
+chain 732 chr21_random 1679693 + 1312000 1312066 7 159138663 - 102920653 102920719 25474729
+66
+
+chain 561 chr21_random 1679693 + 18264 18311 21 48129895 + 44700101 44700148 25859698
+47
+
+chain 3320960322 chr22 49691432 + 14430000 49591432 22 51304566 + 16050000 51244566 22
+647850 150000 150000
+3661581 50000 100000
+15278435 0 18
+293 0 36
+1410 1 1
+46 1 1
+6626947 2 4
+1759 1 1
+43 1 1
+1367363 12000 10615
+7856 4 0
+809336 0 20
+6307 20 0
+6702 50000 2669
+4247727 10618 0
+1558 0 2719
+35231 0 131
+12647 4 0
+45594 85 9
+19562 0 506
+165501 5 7
+1103946 16700 60575
+644 0 2
+319796 1600 1155
+17927 19763 15469
+464566
+
+chain 6025887 chr22_h2_hap1 63661 + 0 63661 22 51304566 + 42594964 42658568 527
+748 1 0
+260 4 0
+675 1 0
+4844 0 2
+10592 8 0
+3276 29 0
+2384 10 0
+2795 0 2
+464 1 0
+3865 1 0
+1777 1 0
+1286 0 2
+875 1 0
+2336 1 0
+4337 1 0
+2724 0 3
+1087 6 0
+7154 0 1
+1045 2 0
+11070
+
+chain 15737781 chr22_random 257318 + 90752 257318 GL000211.1 166566 + 0 166566 187
+166566
+
+chain 3641362 chr22_random 257318 + 7 38789 11 135006516 - 18284691 18323344 804
+2900 3 1
+66 1 1
+55 1 1
+3449 0 1
+1785 1 1
+37 1 1
+178 1 0
+852 0 1
+2329 2 0
+4939 1 0
+1557 1 1
+30 1 1
+1005 1 0
+622 16 0
+39 0 1
+42 0 22
+755 1 1
+30 1 1
+952 1 1
+26 1 1
+141 18 17
+1110 2 0
+1529 1 1
+22 1 1
+399 1 1
+33 1 1
+1369 20 30
+3959 0 4
+1144 1 0
+1032 27 25
+8 23 0
+56 24 0
+51 0 9
+11 1 57
+34 4 4
+7 134 0
+296 26 0
+25 1 1
+2452 0 5
+19 1 1
+231 1 0
+327 1 0
+962 1 1
+22 1 1
+1571
+
+chain 109494 chr22_random 257318 + 39517 40750 22 51304566 - 30977735 30979001 1172425
+166 5 5
+133 3 3
+48 1 1
+297 0 33
+234 1 1
+58 4 4
+283
+
+chain 19094 chr22_random 257318 + 39007 39213 22 51304566 - 29625864 29626070 11204980
+206
+
+chain 8587 chr22_random 257318 + 39415 39517 22 51304566 - 29782769 29782871 2027258
+50 48 48
+4
+
+chain 3763 chr22_random 257318 + 39465 39513 22 51304566 - 30978529 30978577 2726523
+48
+
+chain 17719073 chr2_random 185571 + 0 185498 2 243199373 + 242522204 242710000 158
+43034 21 22
+16724 1 0
+52199 0 669
+3059 0 4
+14500 1 0
+409 1 1
+22 1 1
+2039 1 0
+809 0 1
+2041 0 4
+2258 6 6
+4179 12 13
+1973 1 1
+21 1 1
+1855 1 1
+37 2 2
+4315 0 1
+1584 14 0
+281 0 2
+78 1 1
+1497 9 0
+237 2 1
+826 4 0
+21273 4 0
+6716 0 1650
+3449
+
+chain 18404389309 chr3 199501827 + 35000 199446827 3 198022430 + 60000 197962430 3
+13552792 1 0
+585083 1 0
+2092 74 72
+31067262 1 0
+90 0 1
+5628461 15 0
+788 0 1
+3676 2 0
+35 1 1
+4682 0 1
+1295 5 0
+437 42 53
+326 2 0
+3309 1 1
+40 1 1
+998 3 0
+3584 0 5
+930 7 5
+845 1 1
+28 1 2
+303 1 0
+509 5 0
+2291 6 6
+2789 0 1
+2541 9692 9690
+949 4 4
+35 1 1
+2874 1 0
+6717 1 0
+2823 0 1
+704 4 0
+5142 0 1
+2490 10 10
+162 7 7
+6308 15 0
+15177535 260003 152352
+2532 0 1
+24209179 4400000 3000000
+60453438 4 0
+40076811 20000 20999
+8195 1 1
+44 1 1
+1408 1 1
+33 1 1
+172 4 3
+25 1 1
+538 13 13
+173 1 1
+27 1 1
+636 1 1
+28 1 1
+470 3 3
+112 1 1
+375 1 1
+26 0 26
+106 0 78
+72 9 6
+12 3 29
+79 5 262
+56 1 1
+20 1 1
+815 43 43
+457 1 1
+49 0 18
+509 3 4
+23 1 1
+391 1 1
+44 1 1
+1270 4 0
+40 1 1
+264 27 31
+2416 2 0
+4377 13 13
+736 1 1
+47 1 1
+1416 1 1
+20 1 1
+1020 1 1
+25 1 1
+482 0 5
+716 0 1
+1697 1 1
+29 1 1
+1270261 27000 23108
+40930 0 1
+17455 1 1
+28 4 4
+45 491 0
+1669 58 0
+18 3 61
+54863 16 53
+7653 6 0
+3 99 0
+170 30 0
+25 0 30
+210 0 45
+359 0 915
+5980 256 640
+1363 1 1
+37 1 1
+7958 1 0
+372 1 0
+2442058
+
+chain 572461 chr3 199501827 + 50900356 50910048 3 198022430 - 147087402 147097092 2111
+52 1 6
+5886 1 0
+2586 6 0
+1160
+
+chain 14997 chr3 199501827 + 196923229 196923617 3 198022430 + 195437554 195437811 3659243
+77 131 0
+180
+
+chain 6146 chr3 199501827 + 196987930 196988205 3 198022430 + 195502296 195502751 2529960
+74 171 141
+23 2 212
+5
+
+chain 4201 chr3 199501827 + 196923126 196923228 3 198022430 + 195438036 195438138 6236935
+102
+
+chain 2082 chr3 199501827 + 196994845 196994975 3 198022430 + 195509346 195509572 2249717
+55 18 114
+57
+
+chain 20970321 chr3_random 749256 + 196010 556188 3 198022430 - 121623404 130096441 129
+131258 0 1
+41217 50000 8162858
+137703
+
+chain 13779918 chr3_random 749256 + 0 146010 3 198022430 - 77602115 77748060 219
+64144 1 0
+1191 0 1
+633 0 1
+4651 29 21
+5147 0 1
+947 14 0
+64 56 0
+55 0 2
+2421 0 15
+741 9 0
+371 6 4
+554 1 0
+5424 0 1
+4074 1 1
+44 1 1
+3065 0 1
+2772 1 1
+36 1 1
+15950 1 0
+2351 0 2
+5999 1 0
+17825 0 13
+74 1 1
+367 1 1
+47 1 1
+2084 2 0
+288 0 3
+744 1 0
+131 0 1
+465 1 1
+29 1 1
+659 10 0
+830 0 3
+262 3 0
+1428
+
+chain 13528802 chr3_random 749256 + 606188 749256 3 198022430 + 46352896 46495976 221
+8517 0 10
+20860 0 6
+16120 0 1
+4148 7 6
+745 7 6
+517 6 0
+907 5 5
+1382 4 0
+2730 0 1
+1143 36 36
+457 13 17
+1748 1 1
+48 1 1
+954 0 2
+767 1 4
+7353 0 8
+4950 0 12
+13338 0 1
+4685 1 1
+21 1 1
+1414 3 0
+4158 23 23
+5081 0 1
+14097 1 1
+49 1 1
+770 16 16
+424 1 1
+17 1 1
+244 1 1
+23 1 1
+1462 12 0
+2048 14 0
+4573 1 0
+3856 2 0
+754 0 8
+7304 1 0
+5243
+
+chain 17653370240 chr4 191273063 + 0 191263063 4 191154276 + 10000 191029082 4
+1413146 51000 71672
+5369 5 6
+65 1 1
+67 1 1
+425 1 1
+32 1 1
+175 1 1
+34 1 1
+5092 1 1
+46 1 1
+1396 15 15
+1446 0 1
+5135 1 0
+586 1 1
+38 1 1
+10 0 21
+1587 0 6
+205 0 3
+97 6 0
+177 0 9
+4059 1 1
+71 1 1
+1413 83 1
+51 7 7
+105 7 7
+67 41 0
+67 42 1
+55 41 0
+25 41 0
+3244 558 0
+64 93 0
+93 558 0
+907 0 2
+1101 55 0
+3473 15 15
+1167 3 0
+25 0 29
+135 29 0
+5074 1 1
+42 1 1
+1825 14 14
+1992 0 3
+23 1 1
+4171 6 6
+796 0 165
+196 0 99
+87 0 33
+190 6 8
+107 2 2
+21 0 2
+62 1 68
+32 14 15
+81 18 18
+55 0 100
+17 1 1
+222 2 169
+51 0 35
+3289 18 18
+298 0 1
+373 0 1
+2965 1 1
+28 0 23
+1704 0 38
+114 0 38
+53 7 44
+119 77 0
+269 1 1
+70 1 1
+2000 23 33
+2400 1 1
+94 1 1
+6002 18 18
+776 1 0
+369 16 16
+418 51 0
+53 1 27
+2181 1 4
+57 1 1
+1973 10 0
+4184 11 11
+1594 0 18
+2038 0 109
+4332 0 7
+49 0 4
+1465 3 1
+4156 2 0
+5455 3 2
+129 4 4
+9082 0 1
+786 20 20
+1506 0 1
+252 8 7
+17512 50 1
+56 1 0
+2474 69 52
+69 0 30
+60 16 0
+19 15 0
+40 1 1
+138 16 0
+74 5 51
+3386 0 1
+968 0 4
+1624 11 11
+1065 0 3
+2935 8 0
+2312 0 181
+2300 1 0
+1641 6 1
+1955 0 1
+68 1 1
+347 1 1
+40 1 1
+1553 6 0
+678 16 16
+92 0 33
+390 4 0
+1147 0 1
+1948 4 4
+4296 18 18
+955 1 1
+47 1 1
+1555 1 0
+2251535 81122 0
+145 1 1
+48 1 1
+718 1 0
+2789 1 1
+27 1 1
+1601 4 0
+1048 39 39
+820 0 2
+20 6 0
+28 2 0
+76 12 18
+28 1 0
+11 9 3
+1772 0 6
+22 1 1
+946 1 1
+24 1 1
+1245 1 0
+3231 1 1
+41 1 1
+1652 20 20
+11270 3 0
+2704 1 1
+41 1 1
+1812 5 6
+1477 0 11
+3790 4 0
+2187 1 1
+48 1 1
+1704 1 1
+73 1 1
+2265 1 1
+10 1 1
+553 1 1
+49 1 1
+67 1 1
+33 1 1
+3932 5 0
+18 1 0
+780 0 1
+1260 0 1
+4203 0 25
+863 14 14
+7114 1 1
+70 1 1
+169 0 1
+43 1 1
+145 1 1
+39 0 3
+8 1 1
+753 0 1
+2255 1 1
+21 1 1
+1605 1 1
+19 2 1
+392 1 1
+29 1 0
+3673 1 0
+145 14 14
+39 0 1
+1246 0 1
+2302 1 0
+1554 9 9
+4537 0 1
+1064 2 0
+2051 1 0
+1130 0 2
+164 1 0
+1972 0 1
+18 3 3
+2597 1 1
+46 3 3
+196 1 1
+17 1 1
+60 4 4
+187 4 4
+46 1 1
+692 1 0
+3920 3 3
+15 1 1
+486 14 14
+1709 8 0
+169 1 0
+597 1 1
+18 0 7
+3423937 0 1
+1295496 1 1
+26 1 1
+760 150000 591802
+22468468 1 1
+27 1 1
+2592 0 2
+33 1 1
+2065 3 0
+1050 11 11
+1046 3 9
+52 11 11
+3200 1 0
+906 1 0
+1644 6 0
+1180 0 1
+475 0 5
+2556 26 22
+351 0 1
+1716 71000 36200
+976586 59000 26528
+7701 0 4
+9296 0 1
+1862 1 0
+3316 7 3
+1131 0 1
+1795 1 0
+569 1 0
+2895 44 44
+458 3 0
+5371 1 0
+6774 0 2
+2504 0 2
+1247 1 1
+45 1 1
+2415 17 17
+8215 1 1
+18 1 1
+272 10 10
+420 1 1
+34 1 1
+7961 4 0
+1973 1 1
+45 1 0
+529 1 0
+603 0 1
+18 1 1
+621 4 12
+67 2 0
+18 34 0
+516 0 1
+1400 38 41
+3786 0 1
+228 3 0
+1026 1 1
+49 1 1
+3336 0 3
+951 1 1
+77 2 1
+441 1 2
+1833 9 9
+301 5 5
+2787 17 17
+1747 1 0
+3040 2 9
+81 10 10
+86 2 0
+7354949 20000 1606
+1681 16 30
+13957 0 8
+1947 0 3
+1255 1 1
+38 0 1
+1788 12 17
+1045 6 0
+1327 0 1
+5775 1 1
+18 1 1
+1933 1 0
+1716 13 13
+255 1 0
+124 0 3
+792 0 5
+1521 1 1
+64 1 1
+9005617 150000 150000
+171176 3000000 3000000
+7074452 53320 65431
+1937 0 1
+2845 2 0
+1387 0 1
+114 1 0
+2382 0 4
+68 6 6
+60 4 0
+20 0 1
+93 0 51
+9781584 351994 0
+1909446 184275 0
+3919546 13 13
+435 23 23
+838 0 1
+807 6 6
+74 1 1
+43 1 1
+652 30000 29839
+13847966 0 1
+14069801 2 0
+8504 0 1
+32266 8 0
+12729 0 2
+35327 12 14
+1503 1 0
+1334 1 0
+759 0 1
+7479 34 34
+2523 7 1
+9912 18 17
+2523 1 0
+1321 0 1
+3684 18 18
+5282 2 0
+5505 20 20
+9694 6 6
+22003 9 0
+578 0 1
+5166 2 0
+92208 2 5
+8 1 0
+5 0 2
+113 4 0
+845 6 7
+2247 3 1
+3770 0 1
+5719 0 2
+2511 0 1
+1557 0 1
+5812 0 1
+3607 0 1
+7405 1 0
+11075 0 1
+2794 1 0
+2340 1 0
+429 0 1
+522 2 0
+2397 5 0
+371 11 0
+1376 1 0
+2416 8 0
+210 1 1
+20 1 1
+5104 1 1
+20 1 1
+525 2 0
+836 0 1
+2094 1 0
+2213 3 0
+327 9 6
+2593 1 1
+57 1 1
+1618 0 1
+1400 4 0
+254 0 2
+93 10 0
+754 0 6
+193 0 1
+2378 0 1
+1753 3 0
+1903 0 4
+29 1 1
+1136 14 14
+2452 4 0
+3622 31 3
+456 14 14
+1076 7 8
+68 1 1
+20 1 1
+145 1 1
+68 1 0
+12 0 1
+10 0 1
+11 1 0
+35 1 0
+5 0 1
+11 1 2
+32 6 7
+35 1 0
+8722 1 0
+888 0 4
+456 3 0
+45 0 1
+151 13 13
+756 0 1
+203 8 7
+140 1 1
+20 1 1
+308 5 0
+1020 0 1
+1258 0 1
+160 0 2
+1411 1 1
+22 1 1
+1180 12 12
+4521 0 2
+1155 27 0
+4954 3 0
+1392 1 1
+47 1 1
+3854 2 1
+130 1 0
+2633 2 0
+3053 12 13
+2308 0 1
+1747 0 45
+732 2 0
+1336 9 11
+3898 0 6
+437 1 0
+981 0 1
+1326 0 1
+382 4 0
+1081 10 0
+81 1 1
+142 0 2
+5452 29 29
+495 1 1
+26 1 1
+485 0 1
+525 0 4
+36 0 6
+3945 347 0
+1034 1 1
+27 1 1
+60 2 0
+2581 3 0
+3880 0 4
+1792 0 1
+20 1 1
+356 1 0
+4244 5 5
+36 1 1
+2232 2 2
+42 1 1
+4462 0 2
+1611 1 0
+1290 0 2
+110 1 0
+1466 0 1
+357 3 0
+850 12 0
+13547766 0 1
+3724943 2 0
+46473408 0 1
+1696 1 1
+28 1 1
+1629 0 4
+666 4 0
+13464 30000 12874
+8520008 2 0
+1107 1 1
+15 1 1
+1892 0 4
+6798 0 2
+1793 1 1
+25 0 3
+422 389 0
+786 2 0
+545 0 2
+54 1 0
+143 1 1
+39 1 1
+89 1 1
+29 1 0
+171 1 1
+46 1 0
+192 1 1
+33 1 1
+2580 0 1
+107 1 1
+29 1 1
+218 1 0
+175 6 5
+1407 1 1
+52 1 1
+8851 1 0
+14427 4 0
+1737 22 0
+5806 1 0
+1115 1 1
+29 0 2
+3395 0 1
+3164 0 2
+522 1 0
+24 1 1
+658 4 0
+5724 9 9
+1209 0 1
+5380 1 0
+97 1 0
+854 4 0
+78 5 11
+2728 6 7
+3754 17 13
+1363 1 0
+1025 1 0
+1811 0 1
+7507 0 4
+1184 3 0
+763 1 0
+797 3 0
+293 2 0
+2488 0 1
+335 0 1
+9959 1 0
+3255 1 0
+1322 0 1
+8118 2 0
+2908 49 49
+369 2 0
+632 1 0
+63 0 5
+3008 0 1
+9582 0 1
+14742673 0 3013
+39686
+
+chain 945825 chr4 191273063 + 69381892 69391896 4 191154276 + 69230000 69240000 2911
+2225 1 0
+4917 1 0
+2807 2 0
+51
+
+chain 941684 chr4 191273063 + 69471941 69481941 4 191154276 + 69320000 69330000 3076
+3521 0 1
+4784 1 0
+1694
+
+chain 941274 chr4 191273063 + 69614595 69624595 4 191154276 + 69580000 69590000 3093
+10000
+
+chain 940419 chr4 191273063 + 69564606 69574607 4 191154276 + 69530000 69540000 3129
+3216 5 5
+134 0 1
+5676 2 0
+968
+
+chain 939146 chr4 191273063 + 69534617 69544617 4 191154276 + 69500000 69510000 3182
+387 6 6
+9607
+
+chain 939091 chr4 191273063 + 69481941 69491934 4 191154276 + 69330000 69340000 3184
+8138 0 4
+1546 0 3
+309
+
+chain 938726 chr4 191273063 + 69461942 69471941 4 191154276 + 69310000 69320000 3193
+130 0 1
+9869
+
+chain 936769 chr4 191273063 + 69604595 69614595 4 191154276 + 69570000 69580000 3285
+2900 25 25
+7075
+
+chain 936653 chr4 191273063 + 69421914 69431904 4 191154276 + 69270000 69280000 3293
+6388 14 14
+338 29 29
+266 0 1
+2309 1 3
+55 1 0
+83 0 8
+506
+
+chain 936357 chr4 191273063 + 69391896 69401898 4 191154276 + 69240000 69250000 3304
+2367 1 0
+2329 0 1
+795 23 23
+2819 2 0
+1666
+
+chain 935200 chr4 191273063 + 69441943 69451948 4 191154276 + 69290000 69300000 3343
+1203 4 0
+488 57 57
+7133 2 1
+310 1 0
+551 0 1
+256
+
+chain 934799 chr4 191273063 + 69544617 69554606 4 191154276 + 69510000 69520000 3366
+1296 39 39
+1112 1 0
+204 1 0
+2340 0 12
+1710 0 1
+3286
+
+chain 933839 chr4 191273063 + 69584607 69594595 4 191154276 + 69550000 69560000 3402
+417 3 0
+966 1 0
+2053 0 1
+1784 5 8
+284 0 12
+4475
+
+chain 932655 chr4 191273063 + 69594595 69604545 4 191154276 + 69560000 69569950 3440
+8695 26 26
+1229
+
+chain 930772 chr4 191273063 + 69451948 69461942 4 191154276 + 69300000 69310000 3507
+1068 0 1
+1437 25 27
+806 0 4
+5337 50 50
+300 1 0
+970
+
+chain 928519 chr4 191273063 + 69411919 69421914 4 191154276 + 69260000 69270000 3571
+62 32 32
+801 11 11
+3595 38 38
+941 54 59
+4461
+
+chain 928371 chr4 191273063 + 69511937 69521941 4 191154276 + 69360000 69370000 3579
+6433 60 60
+335 10 6
+239 10 10
+2917
+
+chain 925594 chr4 191273063 + 69554606 69564602 4 191154276 + 69520000 69529997 3671
+2109 0 1
+4421 81 81
+1599 22 22
+1764
+
+chain 922960 chr4 191273063 + 69501928 69511937 4 191154276 + 69350000 69360000 3756
+714 8 8
+423 18 18
+882 33 33
+952 22 22
+607 1 0
+196 64 64
+495 3 0
+2055 2 0
+548 3 0
+2983
+
+chain 915200 chr4 191273063 + 69491934 69501928 4 191154276 + 69340000 69350000 3933
+1036 10 10
+2821 5 0
+53 40 40
+209 3 0
+3718 11 0
+421 0 23
+332 11 11
+292 0 2
+432 23 23
+159 20 20
+115 20 20
+263
+
+chain 911203 chr4 191273063 + 69431904 69441943 4 191154276 + 69280000 69290000 4026
+364 6 5
+212 4 0
+2445 40 15
+377 30 30
+1126 60 60
+262 8 6
+3222 145 138
+1738
+
+chain 903419 chr4 191273063 + 69401898 69411919 4 191154276 + 69250000 69260000 4208
+1051 52 52
+1007 0 1
+319 27 26
+154 98 97
+145 40 40
+512 23 0
+355 5 5
+126 19 19
+128 49 49
+67 0 1
+3337 0 2
+1729 5 5
+773
+
+chain 895926 chr4 191273063 + 69574644 69584607 4 191154276 + 69540037 69550000 4357
+3368 220 220
+1524 84 84
+1558 19 19
+889 41 41
+1592 43 43
+625
+
+chain 866339 chr4 191273063 + 69524748 69534617 4 191154276 + 69490119 69500000 4930
+190 50 50
+59 111 111
+51 7 7
+78 59 59
+58 121 121
+57 39 39
+70 0 1
+1558 108 108
+737 24 24
+3582 0 1
+84 0 10
+2826
+
+chain 659008 chr4 191273063 + 71711854 71718864 4 191154276 + 71492990 71500000 7936
+7010
+
+chain 608986 chr4 191273063 + 69375441 69381892 4 191154276 + 69223549 69230000 8701
+135 1 0
+2166 0 1
+4149
+
+chain 248590 chr4 191273063 + 69521941 69527313 4 191154276 + 69370000 69375377 111030
+2807 190 190
+50 59 59
+111 136 136
+59 58 58
+121 57 57
+39 1628 1633
+57
+
+chain 214386 chr4 191273063 + 71534589 71536854 4 191154276 + 71500000 71502265 534073
+2265
+
+chain 96900 chr4 191273063 + 3963456 3964475 4 191154276 + 3912520 3913539 1319679
+1019
+
+chain 52181 chr4 191273063 + 69624595 69625143 4 191154276 + 69590000 69590548 2441389
+548
+
+chain 20814 chr4 191273063 + 1495708 1495926 4 191154276 + 1526075 1526293 9826122
+218
+
+chain 8858 chr4 191273063 + 1496845 1496937 4 191154276 + 1526189 1526281 25171661
+92
+
+chain 8858 chr4 191273063 + 1496752 1496844 4 191154276 + 1526189 1526281 25171662
+92
+
+chain 8858 chr4 191273063 + 1496566 1496658 4 191154276 + 1526189 1526281 25171663
+92
+
+chain 7802 chr4 191273063 + 1492030 1492276 4 191154276 + 1522531 1522736 2805154
+25 83 42
+23 15 15
+4 55 55
+41
+
+chain 7606 chr4 191273063 + 69578098 69578232 12 133851895 + 88986938 88987072 9526361
+134
+
+chain 7510 chr4 191273063 + 1496208 1496286 4 191154276 + 1526203 1526281 25171660
+78
+
+chain 7439 chr4 191273063 + 1527942 1528019 4 191154276 + 1557568 1557645 18158883
+77
+
+chain 7376 chr4 191273063 + 1496452 1496529 4 191154276 + 1526075 1526152 27495831
+77
+
+chain 6986 chr4 191273063 + 59479326 59479400 7 159138663 + 119297971 119298045 28268313
+74
+
+chain 6131 chr4 191273063 + 1496080 1496144 4 191154276 + 1526075 1526139 27495827
+64
+
+chain 5599 chr4 191273063 + 1495650 1495708 4 191154276 + 1526203 1526261 27226300
+58
+
+chain 5460 chr4 191273063 + 1496658 1496715 4 191154276 + 1526095 1526152 27495830
+57
+
+chain 4356 chr4 191273063 + 1498960 1499009 4 191154276 + 1528103 1528152 18458745
+49
+
+chain 4121 chr4 191273063 + 69578012 69578069 3 198022430 - 95182224 95182281 17792812
+57
+
+chain 3000 chr4 191273063 + 1495929 1496022 4 191154276 + 1526110 1526203 11256589
+93
+
+chain 2961 chr4 191273063 + 69443663 69443695 4 191154276 - 68628109 68628141 14494983
+32
+
+chain 2485 chr4 191273063 + 1503833 1503862 4 191154276 + 1532970 1532999 23156792
+29
+
+chain 2401 chr4 191273063 + 1492301 1492331 4 191154276 + 1522679 1522709 5335388
+30
+
+chain 2012 chr4 191273063 + 1496731 1496752 4 191154276 + 1526075 1526096 27495829
+21
+
+chain 1744 chr4 191273063 + 1597414 1597448 4 191154276 + 1627062 1627096 3575887
+34
+
+chain 1461 chr4 191273063 + 69579763 69579840 5 180915260 + 121968423 121968500 3935628
+77
+
+chain 1332 chr4 191273063 + 69545913 69545943 11 135006516 - 130984886 130984916 21069914
+30
+
+chain 909 chr4 191273063 + 69582306 69582346 3 198022430 - 10790236 10790276 7796945
+40
+
+chain 18169122 chr4_random 842648 + 440032 631501 GL000194.1 191469 + 0 191469 150
+191469
+
+chain 18001815 chr4_random 842648 + 0 189789 GL000193.1 189789 + 0 189789 151
+189789
+
+chain 15268007 chr4_random 842648 + 681501 842648 GL000218.1 161147 + 0 161147 194
+161147
+
+chain 9245037 chr4_random 842648 + 239789 336038 4 191154276 + 8829368 8925617 353
+96249
+
+chain 137712 chr4_random 842648 + 388580 390032 4 191154276 + 9620000 9621452 935614
+1452
+
+chain 10386 chr4_random 842648 + 388312 388420 11 135006516 - 91778086 91778194 21974850
+108
+
+chain 3377 chr4_random 842648 + 388277 388312 11 135006516 - 84847900 84847935 23649965
+35
+
+chain 2456 chr4_random 842648 + 388184 388235 X 155270560 - 93144339 93144390 24160146
+51
+
+chain 16791974256 chr5 180857866 + 63000 180837866 5 180915260 + 10000 180905260 5
+17520657 24032 50000
+1688 3435 1
+37 1399 0
+27 2 1
+8 1 1
+3983 3434 0
+103 1 1
+32 1 1
+67 1 1
+35 1 1
+752 1669 0
+43 1 1
+1207 0 1
+46 0 1
+5 0 1
+19 1 1
+70 3434 0
+962 16 16
+1905 44 44
+85 41 41
+332 49 49
+1675 23 23
+1185 11 11
+124 35 35
+713 105 105
+408 4 4
+113 16 16
+1835 1 2
+26 7 8
+18 2730 25
+3103 1 0
+7858 718 10488
+307 1 636
+7461 0 1
+23772 51 0
+4031 0 1
+20571 0 1
+9135 0 2
+6885 2 3
+110 3 0
+816 2 3
+2295 0 34
+3936 28 28
+3536 0 2
+2917 0 1
+652 1 1
+37 1 1
+657 1 1
+22 1 1
+419 3 4
+3580 1 1
+29 1 1
+274 11 35
+835 3036 0
+1907 1 0
+10504 30 28
+784 0 6
+127 10 0
+668 1 1
+28 1 1
+2467 4 0
+179 0 2
+1650 1 1
+39 1 1
+2433 1 0
+720 1 1
+40 1 1
+772 1 1
+32 1 1
+353 1 1
+17 1 1
+1776 0 1
+6082 3 0
+2669 12 10
+2857 1 1
+35 1 1
+722 60 60
+200 1 1
+240 1 1
+4048 1 1
+49 1 1
+702 1 1
+33 1 1
+2927 1 2
+1487 17 0
+276 16 16
+1039 1 1
+35 1 1
+2068 1 1
+40 1 1
+828 1 1
+36 2 0
+317 8 0
+893 1 1
+33 1 0
+8143 0 4
+28632199 3000000 3000000
+12470071 0 1
+29760415 40000 50000
+5878002 23000 20845
+4521 1 0
+676 6 6
+5928 0 1
+372 1 1
+47 1 1
+6801 3 2
+639 0 1
+871 3 4
+11530 0 4
+22966 0 1
+15447 0 1
+53856 0 2
+15988 0 2
+906887 10 11
+40152817 5000 52715
+3521239 0 1
+1604 10 0
+12778810 4100 51715
+15152692 27 0
+1852096 1 0
+8710030
+
+chain 924655 chr5 180857866 + 17585088 17611949 5 180915260 - 163333152 163394435 1227
+14 409 52001
+494 3435 1
+24 1 1
+1487 10 10
+682 13 13
+132 3449 15
+306 1 1
+74 1 1
+967 3434 0
+1285 3434 0
+68 4569 1135
+2087 50 50
+435
+
+chain 315813 chr5 180857866 + 17584685 17618655 5 180915260 + 17581691 17599590 1580
+403 14 14
+237 1475 75
+628 25 25
+51 89 89
+304 24 24
+70 33 33
+37 698 698
+667 3506 72
+1354 96 96
+75 4 4
+752 1710 41
+450 382 382
+51 14129 7264
+237 12 12
+614 37 37
+134 16 16
+422 31 31
+796 4345 1642
+62
+
+chain 312488 chr5 180857866 + 17597387 17639380 5 180915260 + 17580657 17599710 1454
+373 70 70
+1245 2263 863
+1184 3434 0
+1733 3775 2106
+50 9111 2246
+1078 993 993
+1363 8015 1147
+44 85 85
+41 332 332
+49 6299 3596
+341 45 44
+70
+
+chain 265075 chr5 180857866 + 17745718 17748537 5 180915260 + 17713035 17715853 333767
+1906 1 0
+912
+
+chain 207388 chr5 180857866 + 17584033 17596937 5 180915260 + 17583073 17597745 2201
+51 557 557
+14 17 17
+13 654 654
+172 494 494
+219 23 23
+567 4975 6743
+176 6 6
+865 14 14
+96 1354 1354
+26 2261 2261
+350
+
+chain 193008 chr5 180857866 + 17583668 17629078 5 180915260 + 17580674 17599710 1465
+356 84 84
+533 3434 0
+698 5562 728
+51 4689 1255
+946 4787 1353
+543 8 8
+167 12743 7643
+324 5466 2032
+306 3553 850
+1045 45 44
+70
+
+chain 130263 chr5 180857866 + 17639380 17641654 5 180915260 + 17592112 17594386 19200
+936 23 23
+116 16 16
+1183
+
+chain 123401 chr5 180857866 + 17602522 17620625 5 180915260 + 17589594 17593961 2306
+159 16 16
+1763 19 19
+54 14448 712
+1644
+
+chain 53192 chr5 180857866 + 17626966 17629142 5 180915260 + 17590000 17592176 2614
+952 1045 1045
+45 70 70
+64
+
+chain 42492 chr5 180857866 + 17625757 17626966 5 180915260 - 163394507 163395716 9006
+1209
+
+chain 23743 chr5 180857866 + 17605548 17605956 5 180915260 + 17596054 17596462 38000
+290 9 9
+109
+
+chain 20601 chr5 180857866 + 17748538 17748754 5 180915260 + 17712817 17713033 9842237
+216
+
+chain 11635 chr5 180857866 + 17618762 17618981 5 180915260 + 17595532 17595751 149283
+219
+
+chain 9108 chr5 180857866 + 17618655 17618762 5 180915260 + 17583355 17583462 1340460
+107
+
+chain 7916 chr5 180857866 + 17587442 17604673 5 180915260 - 163387098 163397461 2244
+25 61 61
+79 398 398
+33 16608 9740
+27
+
+chain 7204 chr5 180857866 + 17604533 17604646 5 180915260 + 17599204 17599317 3499
+113
+
+chain 4292 chr5 180857866 + 17639265 17639310 5 180915260 + 17595431 17595476 67944
+45
+
+chain 2558 chr5 180857866 + 17604673 17604706 5 180915260 + 17591745 17591778 3790746
+33
+
+chain 2511 chr5 180857866 + 170275712 170275739 5 180915260 + 170343161 170343188 11152528
+27
+
+chain 2447 chr5 180857866 + 17635643 17636496 5 180915260 - 163394091 163394944 8841
+35 713 713
+105
+
+chain 2252 chr5 180857866 + 17601306 17601338 5 180915260 + 17595246 17595278 11344
+32
+
+chain 2027 chr5 180857866 + 17785693 17785748 18 78077248 - 45596607 45596662 524022
+55
+
+chain 1518 chr5 180857866 + 17629142 17629191 5 180915260 - 163394458 163394507 205933
+49
+
+chain 1109 chr5 180857866 + 17613421 17613452 5 180915260 - 163395907 163395938 8647
+31
+
+chain 143977943 chr5_h2_hap1 1794870 + 0 1794870 5 180915260 + 68505249 71134051 52
+5440 1 0
+1785 0 1
+12373 0 2
+7216 0 1
+714 2 0
+4360 0 1
+11179 1 0
+2027 1 0
+6969 0 2
+3779 1 0
+634 4 3
+1384 0 9
+378 0 2
+1153 3 0
+1246 0 6
+1427 0 2
+608 1 1
+23 1 1
+1981 44 44
+3998 1 1
+33 5 0
+148 1 1
+18 1 0
+331 2 0
+162 1 0
+333 0 1
+644 1 0
+2053 1 0
+1896 0 1
+2096 1 1
+32 1 1
+265 0 14
+1061 0 1
+7303 6 6
+1313 1 0
+3225 0 2
+65 1 1
+220 1 1
+1422 0 1
+248 1 1
+21 2 0
+641 0 1
+163 3 0
+522 1 0
+1685 0 1
+299 1 1
+16 1 0
+3259 1 0
+6492 9 9
+700 0 2
+379 1 0
+186 0 16
+21 0 27
+242 21 19
+156 0 3
+2040 1 0
+7852 0 2
+1267 0 4
+8016 0 1
+2057 85 0
+449 0 1
+2797 0 1
+3858 0 1
+2129 1 0
+234 1 1
+28 1 1
+2923 0 3
+4346 1 0
+2467 1 0
+11093 1 0
+3932 0 3
+2223 1 1
+22 0 1
+25 0 6
+1909 2 0
+1136 1 0
+658 2 0
+32 8 0
+9 2 0
+14 15 11
+22 14 0
+20 51 1
+34 2 0
+43 0 2
+38 127 19
+15 14 0
+41 0 5
+9200 1 0
+2655 1 0
+38 1 1
+237 1 1
+28 1 1
+1065 1 0
+2979 3 0
+13 1 1
+653 4 0
+1950 1 0
+2320 2 0
+817 3 0
+524 8 0
+417 1 0
+873 1 0
+352 1 0
+152 2 0
+651 1 0
+285 1 0
+1830 0 1
+1271 0 1
+957 0 1
+1506 2 0
+2454 4 0
+6 4 0
+300 1 1
+68 1 1
+1648 0 1
+10725 10 10
+1308 2 1
+48 1 1
+1242 15 0
+1869 1 0
+26 0 452
+1178 0 3
+43 0 4
+3567 0 1
+2289 0 1
+695 0 6
+721 13 14
+192 0 2
+1190 1 1
+36 1 1
+451 0 1
+4137 1 0
+809 23 0
+1624 0 4
+453 4 0
+983 0 1
+188 0 5
+489 0 1
+299 11 11
+1923 1 0
+168 0 1
+891 1 1
+54 0 1
+908 0 28
+1224 2 0
+175 0 1
+459 2 0
+119 133 153
+50 13 13
+4001 0 1
+4764 3 0
+90 1 1
+117 92 0
+325 0 27
+19 1 1
+92 1 67
+21 1 28
+15 1 28
+9013 0 1
+1376 0 1
+674 10 0
+87 0 1
+1317 43 35
+260 1 0
+1518 11 12
+232 0 1
+1093 0 1
+737 0 2
+176 10 10
+664 1 1
+33 1 1
+2816 3 0
+4679 0 2
+3212 0 2
+2383 14 16
+3049 0 1
+146 1 0
+721 1 1
+35 1 1
+2260 2 0
+1228 0 1
+682 1 0
+8927 1 0
+795 2 0
+5278 0 2
+5578 13 0
+3665 20 0
+1852 9 0
+4564 1 1
+20 4 0
+111 1 1
+1065 37 37
+2979 1 0
+820 0 1
+9147 0 1
+411 0 1
+745 2 0
+144 3 3
+27 2 0
+734 1 1
+38 1 1
+105 0 4
+554 1 0
+35 1 1
+226 2 0
+254 1 1
+39 1 1
+3302 0 2
+16 1 1
+1276 1 1
+57 1 1
+122 5 0
+178 0 1
+29 1 1
+89 1 1
+32 1 1
+1743 1 0
+294 1 1
+27 1 1
+1925 1 1
+48 1 1
+116 1 1
+20 1 1
+163 4 4
+821 4 3
+46 1 1
+247 1 1
+27 2 2
+613 1 1
+44 1 1
+181 9 7
+1220 1 1
+53 0 3
+596 1 0
+1052 12 12
+130 1 0
+1524 0 1
+1878 1 4
+76 0 1
+6 0 5
+895 0 1
+290 9 5
+783 1 1
+45 1 1
+1910 1 1
+48 1 1
+409 1 1
+30 1 1
+158 2 0
+69 6 0
+428 1 1
+136 1 1
+418 44 44
+767 35 27
+711 1 1
+28 1 1
+1137 1 0
+585 1 0
+433 13 0
+3034 1 0
+961 0 3
+950 1 1
+15 1 1
+948 0 5
+153 21 20
+181 38 38
+765 8 10
+207 13 15
+3092 4 0
+202 5 5
+1406 0 5
+205 1 1
+44 1 1
+2719 1 1
+36 1 1
+1050 0 9
+108 0 2
+1177 4 0
+115 1 1
+2051 15 0
+520 8 8
+1072 0 1
+595 2 0
+4576 73 73
+6176 1 0
+1299 1 1
+29 1 0
+496 0 4
+379 2024 0
+7 3663 0
+82 4 0
+79 6 1
+556 11 0
+598 9 9
+138 77 73
+1651 3 9
+3302 0 8
+429 1 0
+163 0 3
+60 3 0
+132 1 1
+23 1 0
+1660 1 16
+2124 0 1
+1601 9 0
+35 525 6
+38 1 1
+235 1 30
+497 1 1
+37 1 0
+79 0 1
+1239 1 1
+31 1 1
+135 1 0
+5 2 0
+669 0 1
+1158 1595 0
+21 3 0
+5 126998 500121
+730 31 27
+278 0 2
+352 0 12
+363 13 21
+366 1 0
+378 3 0
+61 1 0
+105 17 68
+1480 32 32
+640 1 1
+52 1 1
+482 1 0
+638 1 1
+20 1 0
+21 1 1
+326 1 1
+37 1 1
+995 0 7
+1685 0 1
+1607 9 8
+633 1 1
+37 1 1
+697 6 6
+1363 8 8
+234 1 1
+44 1 1
+3022 5 6
+96 12 11
+674 4 0
+768 0 1
+169 3 0
+2083 0 1
+1098 20 20
+5586 1 0
+174 28 13
+366 2 0
+202 1 1
+69 1 1
+682 5 5
+3457 1 0
+232 1 0
+305 10 0
+1770 40 40
+349 38 38
+401 0 1
+441 7 3
+547 11 10
+210 4 0
+779 4 0
+193 4 0
+576 0 4
+514 48 48
+789 23 16
+2496 25 25
+874 25 11
+2776 19 19
+2824 4 0
+440 0 2
+876 14 14
+1198 39 39
+521 6 0
+126 40 40
+315 29 29
+616 94 99
+285 35 35
+175 12 12
+320 17 1
+3339 0 1
+260 49 49
+109 11 11
+586 0 1
+133 19 13
+8202 0 1
+307 0 1
+1366 1 0
+1073 9 12
+1385 0 1
+321 106 108
+1101 28 28
+483 42 42
+1752 58 58
+166 37 36
+748 16 16
+52 1 0
+1679 0 2
+455 9 17
+484 1 10
+74 33 33
+155 0 1
+62 0 8
+424 23 23
+491 8 9
+450 0 2
+63 1 0
+410 5 0
+1131 165 170
+254 39 39
+1162 0 272664
+1919 1 1
+82 1 1
+740 4 4
+261 1 1
+83 1 1
+52 1 1
+49 1 1
+231 6 6
+244 1 1
+21 1 1
+52 44 44
+114 20 20
+87 32 32
+149 0 6
+202 50 50
+115 44 44
+114 65 65
+50 111 111
+61 52 52
+101 42 45
+250 15 15
+208 1 0
+2259 3 0
+239 64 66
+168 10 10
+2393 1 1
+38 1 1
+674 1 1
+29 1 1
+469 22 25
+827 1 0
+1679 0 1
+463 9 13
+232 1 0
+248 1 5
+325 0 7
+1389 0 4
+63 1 0
+410 6 0
+685 3 0
+35 1 1
+407 166 168
+253 39 39
+71 0 4
+1288 35 35
+1697 32 32
+243 22 22
+395 51 51
+259 49 49
+108 6 6
+54 168 168
+464 45 45
+81 20 20
+84 21 21
+240 25 25
+584 0 810
+126 4 4
+42 6 6
+101 0 3
+41 1 1
+473 1 0
+373 1 1
+41 1 1
+614 1 1
+41 1 18042
+857 50 50
+279 2 0
+246 67 69
+160 10 10
+199 0 1
+154 1 0
+276 28 28
+124 29 28
+105 7 7
+355 1 1
+45 1 1
+299 1 1
+25 1 1
+283 30 35
+594 2 0
+1401 1 1
+46 1 1
+123 4 0
+830 1 0
+100 1 1
+61 1 1
+737 2 7
+285 1 1
+58 1 1
+143 18 0
+19 1 1
+575 1 1
+91 1 1
+318 2 0
+4090 4 0
+702 0 1
+2007 0 2
+901 0 1
+79 9 9
+31 3 3
+1203 1 0
+16 1 1
+574 1 1
+28 1 1
+346 6 0
+25 1 3
+22 2 0
+34 4 0
+7 1 0
+20 18 22
+511 0 5
+5088 0 1
+1065 0 4
+51 2 0
+2714 25 25
+81 8 8
+56 788 18
+22 1 1
+4702 0 1
+536 6 6
+3900 1 0
+1063 0 8
+4095 1 0
+1841 1 3
+1015 0 1
+2808 1 1
+17 1 1
+340 1 1
+39 1 1
+1548 1 1
+73 1 1
+291 1 0
+236 72 43
+104 0 1
+1843 4 0
+80 15 15
+1140 29 1
+45 1 1
+1245 3 0
+194 1 0
+816 11 1
+25 1 11
+47 1 1
+508 0 1
+255 1 1
+24 1 0
+319 13 13
+1846 397 398
+803 0 37
+509 0 12
+130 0 4
+609 0 3
+6495 1251 1253
+1091 11 11
+384 2 0
+1657 31 30
+109 31 31
+2815 63 63
+85 0 13
+589 48 48
+194 25 25
+1068 16 16
+209 2 0
+215 47 47
+1775 127 77
+533 188 0
+1164 1 0
+1863 1 1
+29 1 1
+1993 1 1
+19 1 1
+782 2 0
+3224 2 0
+22 1 11
+473 332 0
+604 1 1
+28 1 1
+223 1 1
+28 1 1
+2870 0 1
+38 1 1
+313 1 0
+768 0 1
+1039 9 9
+886 0 4
+243 0 1
+172 17 17
+2721 1 1
+71 0 1
+607 105 117
+54 46 44
+2057 1 1
+32 1 1
+452 1 1
+49 1 1
+169 322 6
+26 1 0
+567 3 0
+2324 1 0
+825 4 0
+1251 4 4
+2651 0 4
+703 14 19
+10731 13 0
+741 2 0
+1659 0 12
+7683 0 6
+838 1 0
+2905 12 326
+1714 1 0
+1172 90 100
+619 2 0
+263 0 59
+730 1 0
+56 4 0
+1746 17 17
+377 1 1
+27 4 0
+836 1 1
+67 1 1
+1022 0 1
+1096 1 1
+40 0 1
+8 1 1
+1864 1 0
+56 5 1
+6 0 10
+114 1 1
+34 1 1
+631 19 19
+139 13 13
+1330 1 11
+22 2 0
+2846 1 0
+358 0 2
+798 11 11
+3004 1 1
+30 1 1
+2032 1 16
+752 16 0
+40 0 6
+3211 0 1
+965 0 14
+2978 1 1
+29 1 1
+138 0 2
+1646 2 0
+375 1 1
+31 1 1
+6235 0 2
+2598 0 3
+592 0 4
+135 0 12
+3892 1 0
+840 0 12
+5528 9 5
+5400 0 1
+181 0 1
+836 0 3
+3087 1 1
+46 1 1
+2796 11 9
+6282 1 1
+25 1 1
+2009 1 1
+56 0 2
+209 15 15
+2433 1 1
+50 1 1
+366 1 0
+3233 0 1
+5144 0 2
+811 53 22
+23 1 0
+6 1 3
+43 0 2
+13 2 0
+5 0 14
+634 8 8
+1663 10 12
+433 1 1
+43 1 1
+397 2 0
+638 1 1
+42 1 1
+285 1 1
+28 1 1
+516 1288 2
+424 4 0
+660 1 1
+49 1 1
+816 0 12
+1015 1 1
+47 1 1
+988 0 3
+1000 14 32
+330 1 1
+38 1 1
+124 7 2
+43 1 1
+693 1 1
+61 1 1
+94 0 1
+963 1 1
+46 1 1
+1393 0 2
+139 2 0
+113 1 1
+20 1 1
+323 6 0
+34 0 1
+978 1 1
+38 1 1
+105 1 1
+18 1 2
+43 1 1
+381 0 1
+811 15 8
+2537 0 2436
+2642 1 1
+42 4 0
+92 10 10
+1363 1 1
+37 1 1
+252 5 0
+165 1 1
+329 1 1
+77 1 1
+705 0 6
+258 6 6
+155 0 1
+57 2 0
+1380 5 0
+348 2 0
+489 9 5
+448 1 0
+1681 0 1
+835 29 25
+1359 36 36
+223 0 1
+399 15 15
+466 4 4
+75 10559 200741
+1150 1 0
+682 12 15
+802 53 53
+535 1 0
+65 62 63
+497 30 1
+1458 1 0
+683 0 1
+1449 1 0
+977 15 0
+1636 0 4
+216 3 0
+587 0 10
+4302 1 1
+28 1 1
+733 0 4
+138 9 9
+595 0 11
+249 1 1
+65 1 1
+242 1 6
+74 0 4
+87 6 5694
+363 4 0
+513 0 1
+29 1 1
+1297 0 1
+415 1 3
+1947 0 2
+978 0 1
+3121 1 1
+17 1 1
+872 1 1
+31 1 1
+602 8 8
+238 1 1
+36 1 1
+930 1 1
+36 1 1
+1073 22 0
+494 0 1
+66 1 5
+60 1 1
+15 1 1
+452 1 0
+1587 0 7
+1465 1 1
+27 1 1
+76 1 1
+44 1 1
+143 16 14
+323 23 23
+685 1 1
+15 1 1
+136 6 0
+400 0 2
+109 3 0
+50 1 1
+18 1 1
+985 1 1
+38 1 1
+1034 12 12
+247 1 1
+91 2 1
+1383 1 1
+44 1 1
+164 15 16
+292 1 1
+47 1 1
+73 1 1
+43 1 1
+203 1 0
+420 1 1
+37 1 1
+449 0 2
+25 0 4
+415 4 6
+155 1 1
+26 1 1
+199 1 1
+41 0 32
+20 1 1
+68 1 1
+28 1 1
+2097 13 15
+207 8 10
+984 21 20
+134 5 0
+967 10 10
+956 3 0
+4424 5 6
+595 0 1
+1140 1 1
+28 1 1
+733 7 16
+1218 149 149
+429 0 4
+59 0 2
+2568 1 1
+45 1 1
+784 5 8
+289 1 0
+877 5 0
+34 1 0
+68 4 1
+735 1 1
+35 1 1
+1094 4 4
+1519 5 6
+138 12 12
+1044 0 1
+91 80 80
+369 1 1
+53 2 0
+63 1 1
+1220 7 9
+181 1 1
+44 1 1
+134 0 3
+476 2 2
+27 1 1
+205 1 1
+88 2 2
+822 4 4
+163 22 22
+116 1 1
+48 1 1
+3849 1 1
+21 1 1
+120 1 1
+32 1 1
+89 1 1
+29 1 0
+178 3 6
+1452 19 17
+5455 1 0
+10333 1 0
+784 0 1
+55 8 0
+468 0 1
+539 12 0
+98 1 1
+24 1 1
+77 1 1
+81 1 1
+4604 17 19
+7803 7 7
+807 0 1
+2260 7 5
+980 0 1
+2105 0 1
+4083 0 1
+836 0 2
+5612 1 0
+519 0 1
+1334 0 1
+2401 0 9
+1823 1 0
+159 0 2
+484 2 0
+14815 1 1
+36 1 1
+2512 4 0
+58 3 0
+3277 1 0
+559 0 1
+4024 1 0
+4383 22 13
+4131 1 1
+35 1 1
+290 1 1
+29 3 0
+533 1 0
+305 0 1
+2608 0 1
+443 3 1
+2322 0 20
+514 1 1
+46 1 1
+791 19 30
+3206 3 0
+6272 0 2
+1789 8 0
+291 39 39
+521 6 0
+126 40 40
+315 29 29
+616 94 99
+206 114 109
+506 0 14
+2370 0 2
+4709 1 1
+36 1 1
+5588 0 11
+299 1 0
+1366 1 0
+1644 1 1
+28 1 0
+4859 16 21
+1992 0 10
+505 0 1
+448 8 12
+721 40973 60417
+3484 1 1
+40 1 1
+2152 0 2
+5298 39 40
+141 25 25
+427 0 11
+1543 1 0
+3707 0 1
+1056 292 8656
+1768 2 0
+717 1 0
+14041 0 1
+4167 0 2
+7403 5 0
+7673 0 1
+3630 67 67
+74 129 129
+226 1 0
+1720 138 136
+1185 1 0
+878 46874 0
+862 1 1
+31 1 1
+9409 1 1
+37 1 1
+2231 0 2
+1682 0 1
+13767 0 1
+9473 0 1
+7168 2 0
+12384 1 0
+1188 0 4
+2044 1 0
+3076 1 0
+796 0 1
+5477 0 2
+5780 1 0
+6338 1 0
+2680 0 4
+2033 0 1
+9452 0 12
+402983
+
+chain 13752336 chr5_h2_hap1 1794870 + 324513 1282806 5 180915260 - 110525721 111977366 61
+37 39926 39909
+44 767 767
+34 9178 9179
+38 20004 20004
+27 1 1
+44 8383 8384
+1071 3 3
+511 0 1
+439 7 7
+3663 1483 1482
+77 11199 11214
+525 4132 4132
+704 1 0
+729 3 0
+158 29 29
+653 0 3
+154 0 2
+7041 8 0
+2068 0 7
+166 1 0
+812 6 7
+25 1 1
+1423 0 8
+438 0 1
+4783 0 1
+31 1 1
+1269 1 0
+926 3 0
+2542 2 0
+112 1 1
+2183 1 1
+59 1 1
+1605 2 2
+4515 0 1
+4368 1 0
+382 0 34
+60 1 1
+86 0 1
+552 6 6
+892 1 1
+33 1 1
+6705 0 1
+934 0 2
+8985 2 1
+445 6 0
+6283 0 1
+456 0 1
+1101 0 5
+696 0 1
+2973 6 0
+158 0 3
+449 0 3
+657 12 12
+151 0 1
+406 1 1
+55 1 1
+163 1 1
+72 1 1
+1955 1 0
+713 0 1
+3050 1 1
+35 1 1
+3127 1 0
+233 1 0
+1343 17 7
+1250 3 0
+322 1 0
+2081 0 1
+2413 5 0
+818 0 1
+18 1 1
+268 0 1
+271 1 1
+35 1 0
+586 2 0
+1192 0 1
+494 2 0
+4657 1 1
+30 5 0
+2172 0 334
+1981 5 0
+33 321 0
+2633 2 0
+142 1 0
+1597 7 0
+248 1 0
+317 1 1
+21 1 1
+441 0 1
+600 6 4
+35 1 1
+1593 2 6
+9303 1 0
+2781 0 2
+6052 0 4
+771 1 0
+1500 14 0
+1544 730 730
+31 3419 3419
+30 30394 30395
+40 349 349
+38 3691 3690
+48 3308 3306
+25 874 880
+25 8151 8151
+39 653 653
+40 315 315
+29 616 616
+94 285 285
+35 4123 4120
+49 13570 13573
+58 30899 10440
+165 1652 1655
+35 1697 1697
+32 660 660
+51 259 259
+49 168 168
+168 464 464
+45 446 446
+25 3886 3879
+67 800 800
+28 124 124
+29 1123 1123
+30 24987 23723
+2 1 1
+21 146 146
+2 1 1
+785 22543 22552
+67 3192 3170
+28 5357 5348
+397 8546 8565
+1251 3145 3145
+31 110 110
+29 2816 2816
+63 674 688
+48 195 195
+23 1511 1509
+47 1810 1786
+37 14 0
+41 533 533
+182 1 16
+5 20555 20281
+49 1 21
+55 54 52
+46 2763 2762
+37 5 2
+280 124045 123118
+495 0 1
+703 3 0
+87 27183 48462
+36 1182 1182
+389 16 16
+257 1 0
+118 3 3
+547 1 1
+25 1 1
+126 0 2
+3598 810 0
+148 0 6
+483 1 1
+34 1 1
+266 6 6
+350 2 2
+30 1 1
+297 4 4
+666 1 1
+89 1 1
+52 15 15
+2220 2647 2651
+53 53651 53634
+149 9850 9843
+39 1 1
+39 116984 481498
+39 653 653
+40 315 315
+29 616 616
+94 206 206
+114 65101 68610
+358 27 27
+588 11156 11155
+25 56460 137674
+105 1 0
+2251 13 13
+319 25 26
+826 25 25
+370 7 7
+439 0 1
+192 7 1
+250 0 13
+1302 1 8
+866 91 94
+91 14 14
+501 1 0
+1238 1 0
+113 475 60006
+212 8 10
+907 0 4
+350 1 0
+486 9 17
+448 0 2
+515 0 10
+788 13213 230
+199 16 16
+645 0 2
+112 37 25
+634
+
+chain 283844 chr5_h2_hap1 1794870 + 1261701 1280951 5 180915260 + 69698102 69815360 1487
+91 6326 96869
+318 0 10
+505 0 1
+204 64 64
+440 1 0
+235 0 1
+1269 0 1
+945 1 0
+670 242 551
+75 3 0
+1233 50 50
+199 4900 12045
+409 59 59
+310 37 40
+664
+
+chain 206667 chr5_h2_hap1 1794870 + 1287039 1295912 17 81195210 + 76583705 76597262 568754
+558 4 0
+365 2 2
+40 0 1
+253 1 1
+31 1 1
+522 6316 11003
+780
+
+chain 184822 chr5_h2_hap1 1794870 + 1284679 1286632 17 81195210 - 4506444 4508397 671275
+1953
+
+chain 128717 chr5_h2_hap1 1794870 + 1283006 1284382 5 180915260 + 70517839 70519212 1000883
+791 20 17
+565
+
+chain 128621 chr5_h2_hap1 1794870 + 1291852 1293214 17 81195210 + 76573863 76575225 1001637
+1362
+
+chain 122147 chr5_h2_hap1 1794870 + 627399 939358 5 180915260 - 110828619 111993762 93
+42 1752 1753
+58 6978 6974
+165 255 254
+37 4915 4915
+44 4384 4378
+64 19819 875253
+39 1 1
+9 264030 261784
+58 0 6
+56 6 6
+105 3 3
+98 1 1
+483 7968 7968
+62 497 497
+30
+
+chain 118081 chr5_h2_hap1 1794870 + 1290357 1291631 4 191154276 - 20442500 20443774 1089300
+230 18 18
+1026
+
+chain 112391 chr5_h2_hap1 1794870 + 1288972 1290160 17 81195210 - 4580707 4581894 1143267
+1134 1 0
+53
+
+chain 92982 chr5_h2_hap1 1794870 + 1293593 1294614 4 191154276 + 170627590 170628611 1373141
+72 1 1
+129 1 1
+818
+
+chain 75482 chr5_h2_hap1 1794870 + 1274745 1276419 5 180915260 - 111410923 111412615 820
+271 0 10
+350 0 6
+499 9 9
+444 0 2
+101
+
+chain 68300 chr5_h2_hap1 1794870 + 1276804 1279228 5 180915260 - 110416917 110419341 216
+2424
+
+chain 29652 chr5_h2_hap1 1794870 + 524804 525112 3 198022430 + 8519605 8519913 4781887
+308
+
+chain 29428 chr5_h2_hap1 1794870 + 756919 757240 2 243199373 + 16251117 16251431 4913030
+177 7 0
+137
+
+chain 27649 chr5_h2_hap1 1794870 + 641866 1186473 5 180915260 + 68929706 69564604 89
+32 351 351
+50 115 115
+44 114 114
+65 50 50
+111 61 61
+52 101 101
+42 14056 14883
+33 529303 618767
+27
+
+chain 20581 chr5_h2_hap1 1794870 + 1249367 1254462 5 180915260 - 111122604 111127700 1762
+2153 24 24
+85 8 8
+1086 0 1
+1739
+
+chain 5516 chr5_h2_hap1 1794870 + 253548 253608 5 180915260 + 68759177 68759237 7759123
+60
+
+chain 5218 chr5_h2_hap1 1794870 + 1244675 1244945 5 180915260 - 159621198 159621468 493
+30 1 1
+36 122 122
+81
+
+chain 4702 chr5_h2_hap1 1794870 + 1279881 1280287 5 180915260 + 70518261 70518663 9283
+59 311 307
+36
+
+chain 4436 chr5_h2_hap1 1794870 + 1274323 1274373 5 180915260 + 70526833 70526883 9273
+50
+
+chain 4277 chr5_h2_hap1 1794870 + 625682 625728 5 180915260 - 111701952 111701998 814
+46
+
+chain 3978 chr5_h2_hap1 1794870 + 1276419 1276466 5 180915260 + 70082181 70082228 137301
+47
+
+chain 3805 chr5_h2_hap1 1794870 + 1244816 1244863 5 180915260 + 69926901 69926948 475
+47
+
+chain 2924 chr5_h2_hap1 1794870 + 253608 253640 5 180915260 + 68759034 68759066 4803455
+32
+
+chain 943 chr5_h2_hap1 1794870 + 1282135 1282172 5 180915260 - 111121871 111121900 54522
+21 8 0
+8
+
+chain 692 chr5_h2_hap1 1794870 + 1276691 1276804 5 180915260 + 21496928 21497041 821
+113
+
+chain 13519395 chr5_random 143687 + 0 143687 5 180915260 + 180261930 180405660 222
+5859 0 4
+460 1 1
+23 0 2
+42 1 3
+42 1 1
+1633 55 55
+2271 0 10
+1279 2 0
+761 2 0
+25 1 1
+150 13 13
+4989 0 1
+1174 1 1
+23 1 1
+495 16 16
+2709 1 4
+349 0 4
+466 0 1
+292 2 0
+184 0 5
+621 13 13
+1788 2 0
+21 1 1
+731 12 12
+149 0 3
+5100 1 0
+1059 0 3
+1724 2 0
+4111 1 0
+890 4 4
+47 1 1
+1137 0 1
+147 17 19
+72 1 1
+22 1 1
+365 1 1
+19 2 2
+1360 0 1
+1476 1 1
+43 1 1
+1141 1 0
+2615 18 18
+4308 0 4
+135 0 2
+1484 8 6
+7384 0 11
+284 1 1
+69 1 1
+232 6 0
+1064 0 2
+4530 0 1
+4542 6 6
+10543 1 0
+4051 2 0
+11340 5 6
+4936 1 0
+12029 3 3
+43 1 1
+2955 27 27
+775 0 10
+822 1 0
+2057 1 0
+733 0 1
+4016 0 1
+4514 1 1
+49 1 1
+4484 1 0
+784 1 1
+25 1 1
+5707 2 0
+1274 1 0
+289 1 1
+34 1 0
+80
+
+chain 15799018021 chr6 170899992 + 5000 170896992 6 171115067 + 60000 171055067 6
+1297281 0 1
+7806978 162987 0
+4013144 0 9
+261 15 13
+18786172 17 17
+439 16 16
+59 4 5
+32202 17 17
+439 16 16
+59 5 4
+15403 0 1
+13914166 0 4
+115 1 1
+17 1 1
+415 0 12
+105 3 6
+12160281 50000 50000
+642507 3050000 3100000
+248423 50000 50000
+2918791 0 1238
+9427508 4 4
+162 12 12
+2193 22 22
+293 1 1
+30 1 1
+845 0 1
+45 1 1
+9769 0 2
+6058 1 1
+24 1 1
+2223 1 1
+24 1 1
+182 12 12
+284 1 1
+20 1 1
+970 1 1
+64 36 7
+575 43 43
+389 1 1
+27 1 1
+3279 1 1
+44 1 0
+3012 0 1
+545 17 17
+2562 1 0
+251 1 0
+943 0 8
+29 1 1
+566 0 6
+1483 0 2
+1960 0 1
+4564 1 1
+25 1 1
+832 1 0
+801 8 8
+1131 1 1
+58 1 5
+6177 1 0
+3712 0 1
+2185 1 1
+35 1 1
+710 2 2
+78 1 1
+2201 1 1
+30 1 1
+283 1 1
+30 1 1
+448 0 1
+75012 0 8
+2508457 0 1
+4641788 5 5
+37 1 1
+8503609 2 0
+5363169 200000 150000
+6040303 1 1
+36 0 1
+2020 1 1
+46 1 1
+1559 1 1
+72 1 1
+1098 1 1
+29 1 1
+264 7 7
+580 1 0
+30 1 1
+536 1 1
+41 1 1
+5663 0 1
+423 0 2
+372 1 1
+18 1 1
+9612 0 1
+1414 0 1
+176 2 0
+2742 0 1
+1968 1 0
+754 0 1
+4237 1 0
+2388 1 1
+31 0 1
+3385 1 0
+2004 0 8
+3395 3 0
+32 1 1
+4109 1 0
+1055 0 20
+1611 0 1
+17198424 26 17
+7835 1 0
+11119 1 1
+5197 0 11
+4791 1486 66479
+6787989 1 0
+149 0 4
+947 0 4
+244 1 0
+28418215 1 1
+21 0 1
+3116903 50000 171704
+1939305 1 1
+19 2 0
+8192274 4 4
+122 2 0
+1127 0 1
+1104 1 102
+18 0 29
+40 0 3
+22 1 4
+50 0 26
+56 18125 195105
+950946 1 157
+51 1 1
+104 0 255
+610 0 408
+104 0 105
+1285158 150028 50028
+725067
+
+chain 8374990 chr6 170899992 + 9109557 9199728 6 171115067 + 9164559 9254607 394
+3887 2 0
+1509 45 45
+888 7 8
+372 0 1
+4746 3 0
+1114 31 31
+140 35 35
+2111 13 13
+445 248 137
+1437 38 38
+55 25 25
+739 19 19
+2479 70 58
+1297 0 4
+7065 24 24
+542 31 31
+531 22 22
+824 0 1
+2286 40 39
+1209 48 48
+1435 6 0
+4096 4 0
+495 41 42
+6884 0 1
+3177 0 1
+2843 0 1
+904 5 5
+830 18 18
+1997 0 1
+942 4 0
+122 33 33
+1012 0 10
+3751 0 1
+5959 49 49
+4503 0 20
+7514 8 8
+4012 15 15
+673 16 0
+83 4 0
+424 3 0
+3932
+
+chain 892181 chr6 170899992 + 9258019 9267980 6 171115067 + 9150000 9160000 4430
+970 53 55
+802 16 17
+389 27 27
+73 5 4
+118 9 5
+615 0 2
+69 17 15
+578 0 1
+114 22 22
+888 130 130
+252 3 9
+564 0 1
+211 5 0
+90 4 0
+1846 21 21
+1832 0 42
+238
+
+chain 763150 chr6 170899992 + 9249728 9258019 6 171115067 + 9141295 9150000 6494
+566 0 1
+140 8 0
+205 47 47
+145 18 12
+46 1 0
+3841 0 56
+172 0 372
+444 18 18
+2447 20 20
+173
+
+chain 369937 chr6 170899992 + 9267980 9272102 6 171115067 + 9160000 9164126 144773
+1134 49 45
+1420 38 38
+203 0 4
+144 0 3
+115 54 55
+965
+
+chain 4624 chr6 170899992 + 9129966 9130015 6 171115067 + 165872977 165873026 28640892
+49
+
+chain 1407 chr6 170899992 + 74606704 74606747 X 155270560 + 149588561 149588604 701656
+6 11 11
+26
+
+chain 414456960 chr6_cox_hap1 4731698 + 0 4731698 6 171115067 + 28541283 33351542 27
+3409 1 0
+3526 0 1
+2940 0 4
+981 0 1
+4053 0 2
+1433 0 1
+3153 2 0
+369 0 1
+1090 0 1
+884 1 4
+363 1 0
+1969 0 1
+994 5 0
+58 1 1
+131 1 0
+4080 1 0
+680 0 1
+978 0 1
+1062 1 0
+2669 19 19
+7247 1 2
+1704 0 4
+1513 0 2
+49 2 0
+2160 0 5
+672 1 1
+38 1 1
+1384 1 0
+1685 1 1
+30 1 1
+2421 1 1
+42 1 1
+830 1 1
+41 1 1
+1630 0 1
+7458 1 0
+691 0 1
+525 0 1
+79 1 1
+29 1 1
+2055 1 1
+16 0 24
+1867 5 7
+786 0 2
+280 0 1
+227 2 0
+6678 1 0
+4401 1 0
+210 1 0
+3193 2 0
+3619 0 1
+2414 0 2
+5387 0 3
+2927 0 1
+3304 0 1
+440 0 5
+415 0 9
+3597 1 1
+48 1 1
+3412 1 1
+46 1 1
+3604 4 4
+1063 1 1
+36 1 1
+3511 6 6
+2797 32 41
+393 0 1
+477 1 1
+37 1 1
+2459 2 0
+517 0 12
+318 0 1
+1010 7 6
+2103 0 1
+5171 0 8
+1483 1 0
+3813 888 0
+4675 0 2
+5620 1 0
+2017 1 0
+3363 0 5
+1197 0 3
+3208 1 0
+1928 1 0
+174 6 0
+780 1 3
+443 14 0
+3079 0 5
+1993 0 3
+1089 1 1
+58 1 1
+80 0 8
+256 2 0
+2473 37 43
+752 0 2
+33 0 2
+825 0 1
+787 1 1
+37 1 1
+1168 16 0
+377 5 1
+27 1 1
+2161 2 0
+636 25 25
+1663 1 0
+1757 6 6
+205 4 0
+203 7 7
+107 1 1
+28 1 1
+100 4 4
+258 5 0
+659 1 0
+3805 5 8
+1486 4 4
+213 39 43
+4429 0 2
+1199 13 13
+5803 12 0
+2987 0 1
+813 0 17
+920 2 0
+3820 1 3
+130 21 9
+1913 0 14
+1800 0 1
+1255 2 0
+1466 4 0
+747 0 1
+124 2 0
+2108 1 0
+169 0 26
+593 1 0
+632 5 0
+2711 0 4
+1042 0 1
+34 1 1
+1025 2 0
+27 4 18
+81 1 33
+33 0 1
+6 0 76
+3950 1 0
+86 1 1
+12 1 1
+2947 0 1
+1160 1 0
+2046 3 0
+720 1 0
+1341 1 0
+10205 0 5
+1265 1 0
+10 1 1
+1278 5 6
+399 0 32
+96 16 18
+605 4 0
+1072 12 12
+950 11 7
+5128 9 10
+2711 1 0
+676 0 1
+2904 1 1
+30 1 1
+851 0 1
+1410 0 1
+394 1 1
+57 1 1
+1561 0 2
+11062 1 1
+58 1 1
+3238 1 1
+42 1 1
+269 1 0
+284 3 3
+24 1 0
+2796 0 5
+2451 28 0
+2251 1 1
+32 1 0
+10 0 4
+24 1 1
+694 0 2
+3475 0 1
+2008 1 1
+49 1 1
+475 1 1
+28 1 1
+259 160 0
+1858 1 0
+1621 3 0
+1791 1 0
+316 0 2
+1169 0 1
+2549 1 0
+2941 1 1
+34 1 1
+243 9 0
+5157 0 2
+1748 0 8
+472 4 0
+2470 0 4
+402 1 0
+643 2 0
+748 0 2
+859 1 0
+409 2 0
+267 0 2
+322 0 4
+155 1 0
+9957 0 4
+1440 4 4
+127 1 0
+1085 1 0
+131 1 0
+767 1 0
+1160 21 21
+1294 1 0
+712 1 0
+1819 2 1
+464 1 0
+6944 0 4261
+55 0 7
+1235 0 3
+702 0 24
+2847 0 1
+2428 3 0
+7517 0 1
+3204 1 0
+611 1 0
+7104 1 0
+4959 14 14
+2827 1 0
+9421 82 25
+4428 8 0
+5987 41 41
+2108 0 2
+344 1 0
+4216 1 0
+810 0 5
+4443 1 0
+10291 10 0
+7265 5 0
+7041 1 0
+6007 1 0
+8185 4 0
+4961 0 3
+13564 0 1
+1475 0 2
+105 0 10
+10104 2 0
+3073 1 0
+3715 8 0
+2246 24 24
+11461 0 2
+837 61 1
+7660 39 39
+1705 0 1
+6068 7 0
+916 0 4
+569 1 1
+72 1 1
+2260 0 2
+7036 4 0
+3591 0 3
+713 4 0
+7058 11 11
+3319 0 2
+8475 0 1
+1324 0 2
+5438 5 0
+156 1 1
+44 0 1
+21501 7 7
+3359 16 16
+2138 0 5
+4406 11 11
+1525 1 1
+28 1 1
+2159 16 0
+48 4 0
+3030 0 1
+5717 10 0
+6594 2 0
+648 31 31
+1275 1 0
+4 1 0
+3599 1 0
+7515 4 0
+979 0 2
+1990 0 10
+123 1 1
+27 1 1
+1255 0 2
+2769 5 5
+727 1 1
+26 3 3
+785 0 1
+8871 29 29
+15459 1 0
+5978 5 5
+66 1 1
+46 1 1
+18539 1 0
+7732 2 0
+652 0 1
+861 0 1
+10658 17 17
+1313 0 1
+3515 3 0
+19 18 0
+539 0 1
+655 2 0
+10586 2 0
+2385 0 1
+7589 1 0
+29834 1 1
+27 1 1
+1216 1 0
+1323 1 0
+673 0 3
+20031 0 3
+2841 13 0
+1841 4 0
+6446 1 0
+11727 0 1
+8427 17 17
+2864 0 143
+4107 0 8
+748 0 2
+3417 1 1
+32 1 1
+18799 0 2
+21810 1 1
+34 1 1
+2784 2 0
+7864 2 0
+4498 0 1
+49089 1 1
+32 1 1
+509 1 1
+37 1 1
+5371 22 16
+389 1 1
+21 1 1
+806 1 0
+1638 6 6
+228 1 1
+45 1 1
+2068 6 3
+441 1 0
+2338 1 0
+1948 1 1
+26 1 1
+214 0 1
+6118 1 1
+31 1 1
+2382 5 5
+4335 1 1
+39 1 1
+4561 1 1
+38 1 1
+2199 1 1
+49 1 1
+243 19 6
+2779 1 1
+37 2 0
+24 1 1
+1966 3 0
+233 1 1
+29 1 1
+13756 0 4
+3956 4 1
+33765 46 46
+12758 1 0
+18985 0 8
+1384 3 1
+85 1 0
+3539 1 1
+32 1 1
+145 1 0
+1245 2 0
+1736 80 80
+1607 1 5
+712 10 11
+502 0 1
+3670 1 0
+740 0 1
+1693 0 1
+6497 0 2
+2898 1 3
+141 0 1
+1108 0 2
+1448 1 0
+1340 0 1
+7616 74 66
+2882 1 2
+30 8 0
+896 21 3
+395 1 1
+37 3 0
+23 1 2
+1210 18 0
+65 1 1
+20 1 1
+791 0 4
+389 1 0
+809 1 1
+55 0 7
+428 1 1
+17 1 1
+239 1 1
+20 1 1
+69 1 1
+37 1 1
+955 1 0
+839 0 1
+165 1 0
+3867 0 5
+70 1 1
+27 1 1
+899 1 2
+107 1 0
+1457 1 0
+763 12 5
+35 1 1
+1417 10 10
+121 1 1
+38 0 3
+377 1 0
+325 2 2
+178 1 0
+11 4 0
+297 0 24
+337 11 0
+134 1 1
+694 3 0
+72 1 1
+144 1 1
+96 1 1
+199 2 0
+1011 1 0
+107 1 1
+1280 1 1
+73 1 1
+84 25 25
+287 1 1
+26 1 1
+139 1 1
+41 1 1
+440 4 0
+130 12 12
+435 21 0
+85 1 1
+28 1 1
+73 1 1
+61 1 1
+53 5 1
+70 1 2
+52 2 0
+157 30 30
+554 2 2
+128 1 5
+68 1 1
+44 1 1
+125 0 1
+57 1 1
+308 0 7
+15 1 1
+725 9 0
+60 1 1
+180 1 1
+55 1 1
+61 1 1
+23 1 0
+5 1 2
+88 1 1
+56 1 1
+433 2 0
+84 68 68
+182 12 12
+216 1 1
+94 1 1
+561 1 1
+16 1 1
+113 1 1
+86 1 1
+148 2 0
+75 2 0
+77 1 21
+209 3 8
+374 1 0
+173 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+327 1 1
+54 5 5
+929 1 1
+21 1 1
+97 1 1
+28 0 3
+830 0 2
+68 1 1
+525 0 1
+2081 1 1
+41 1 1
+165 3 3
+46 1 0
+378 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 41 41
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+240 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+321 1 1
+63 1 1
+504 18 18
+662 1 1
+74 1 1
+248 1 1
+34 1 1
+1507 0 10
+1051 0 2611
+560 3 3
+23 1 1
+1631 0 15
+78 4 0
+160 0 21
+3764 0 4
+1358 0 1
+1773 1 1
+43 1 1
+1263 1 1
+39 1 1
+183 0 16
+4097 10 0
+1261 1 1
+20 1 1
+137 1 0
+2351 1 1
+43 1 1
+1010 0 4
+536 1 1
+38 1 1
+381 0 1
+888 19 19
+1521 1 1
+27 1 1
+161 1 1
+46 1 1
+2659 2 0
+533 10 0
+441 1 12
+1684 1 1
+26 3 4
+879 16 16
+514 0 2
+58 1 1
+117 1 1
+24 1 1
+207 1 0
+38 1 1
+730 1 1
+39 1 1
+429 10 10
+134 0 4
+37 1 1
+144 8 8
+1036 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+317 0 3
+1256 0 2
+332 1 1
+21 1 1
+193 8 28
+30 1 1
+79 1 1
+29 1 1
+536 1 0
+611 1 1
+25 1 1
+399 4 4
+118 0 32
+23 1 1
+116 1 1
+30 1 1
+503 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 4
+711 7 7
+89 1 0
+293 7 6
+159 1 1
+24 1 1
+167 6 6
+171 17 17
+681 1 1
+43 1 1
+538 1 1
+44 1 1
+537 16 16
+180 6 6
+778 2 2
+44 1 1
+168 0 7
+211 1 1
+42 1 1
+1253 1 1
+29 1 1
+320 1 1
+36 2 2
+55 1 2
+460 1 1
+35 1 1
+553 8 8
+386 1 1
+26 1 1
+540 1 1
+31 1 1
+65 0 1
+625 12 12
+313 0 1
+52 1 1
+22 1 1
+583 1 1
+49 1 1
+678 37 37
+784 3 0
+770 1 1
+87 11 0
+1129 1 1
+36 1 1
+553 8 8
+997 16 15
+157 1 1
+31 2 2
+204 18 19
+487 1 1
+29 1 1
+374 1 1
+67 1 1
+720 13 13
+266 10 10
+330 16 14
+413 1 1
+44 1 1
+78 6 6
+181 2 2
+36 1 1
+397 1 1
+20 1 1
+311 1 1
+48 2 2
+1298 11 11
+437 4 4
+35 1 1
+194 10 10
+310 1 1
+51 1 1
+136 1 1
+49 1 1
+521 1 1
+23 1 1
+220 1 1
+71 1 1
+1046 15 15
+216 1 1
+21 1 1
+51 1 1
+49 1 1
+527 17 17
+340 12 11
+1025 1 0
+2572 1 1
+29 1 1
+397 2 5
+668 13 13
+541 1 1
+59 0 2
+6 1 1
+122 14 14
+51 1 1
+46 1 1
+72 5 5
+352 0 21
+136 1 1
+12 1 1
+66 16 16
+456 37 34
+371 7 7
+48 1 1
+194 10 10
+108 1 1
+60 1 1
+122 0 1
+48 1 1
+238 1 1
+32 0 1
+100 1 0
+72 1 0
+390 1 1
+38 1 1
+144 1 1
+27 0 4
+184 21 228
+49 1 1
+608 0 1
+152 1 1
+31 1 1
+281 8 8
+337 1 1
+45 1 1
+222 1 1
+20 1 1
+380 1 0
+44 1 1
+368 1 1
+72 1 1
+502 36 18
+63 1 1
+43 0 4
+136 1 1
+42 1 1
+80 4 4
+35 1 0
+89 1 1
+24 0 5
+829 13 13
+102 14 0
+233 1 1
+42 0 3
+85 0 1
+400 1 1
+40 1 1
+538 25 25
+174 1 1
+20 1 1
+705 1 1
+26 2 2
+614 1 1
+44 1 1
+509 1 1
+32 1 1
+224 1 1
+42 1 1
+747 5 5
+804 1 1
+29 1 1
+166 1 1
+43 1 1
+233 1 1
+44 1 1
+620 8 8
+133 1 1
+31 1 1
+165 1 1
+29 1 1
+1249 1 1
+26 4 0
+56 1 1
+67 1 1
+716 1 1
+46 0 1
+16 1 1
+174 1 1
+96 1 1
+141 1 1
+39 0 4
+263 1 1
+18 1 1
+259 4 4
+38 1 1
+104 1 1
+40 1 0
+248 1 1
+18 1 1
+238 1 1
+32 1 1
+70 0 2
+16 1 1
+818 1 1
+22 4 4
+1641 1 1
+46 1 1
+53 1 0
+38 1 1
+373 1 1
+60 1 1
+1149 0 2
+19 1 1
+1653 4 4
+42 1 1
+218 12 12
+363 1 1
+24 1 1
+457 10 10
+414 13 13
+825 1 1
+41 1 1
+492 0 8
+1370 1 1
+18 1 1
+808 2 2
+335 6 4
+880 1 1
+35 1 1
+236 1 1
+67 1 1
+298 0 1
+147 4 4
+322 11 11
+613 1 1
+62 1 1
+340 1 1
+22 1 1
+1057 1 1
+57 1 1
+358 1 1
+128 1 1
+146 10 10
+490 1 1
+20 1 1
+62 1 1
+88 1 1
+293 1 1
+28 1 0
+20 1 1
+83 0 1
+90 1 1
+312 1 1
+44 1 1
+1213 1 1
+51 1 1
+467 1 1
+39 1 1
+122 14 0
+35 1 1
+485 14 14
+110 13 0
+127 1 1
+7150 9 13
+3278 0 2
+28 1 1
+2211 1 0
+1325 18 18
+1304 3727 0
+299 0 248
+2603 2 0
+160 1 1
+34 1 1
+631 1 1
+40 1 3
+38 1 1
+332 17 17
+231 14 14
+202 1 1
+199 1 1
+71 1 1
+42 1 0
+53 11 10
+82 34 34
+135 1 1
+50 3 0
+32 1 1
+194 1 1
+45 1 1
+143 1 1
+78 1 1
+193 6 0
+40 1 1
+432 1 1
+17 1 1
+429 3 6
+58 1 1
+85 1 1
+62 1 1
+85 1 1
+57 1 1
+51 2 2
+278 1 1
+49 1 1
+77 11 11
+120 0 4
+139 1 1
+30 2 2
+205 4 4
+131 1 1
+22 1 1
+251 1 1
+34 1 1
+175 1 1
+36 1 1
+239 1 1
+32 5 5
+63 1 1
+27 1 1
+78 1 1
+19 1 1
+209 1 1
+143 1 13
+176 0 1
+7 0 8
+375 0 1
+62 1 1
+129 2 2
+135 1 1
+88 8 0
+90 6 8
+796 2 0
+1219 1 1
+34 1 1
+833 1 1
+46 1 1
+74 1 1
+45 1 1
+95 1 1
+29 1 1
+298 0 3
+47 1 1
+311 1 1
+58 1 1
+349 15 15
+208 1 1
+37 3 0
+413 11 11
+54 1 1
+97 1 1
+137 0 2
+95 1 1
+257 3 0
+35 1 1
+66 1 1
+47 1 1
+104 7 7
+220 17 17
+228 4 4
+432 1 1
+34 3 3
+175 4 4
+26 1 2
+116 7 7
+60 13 13
+137 1 1
+44 1 1
+744 1 1
+29 1 1
+148 0 5
+30 1 1
+387 1 1
+22 1 1
+309 1 1
+82 1 1
+52 1 1
+32 1 1
+121 1 1
+37 1 1
+396 3 2
+324 1 1
+92 1 1
+51 9 9
+71 7 7
+24 1 1
+115 1 1
+101 1 1
+799 12 12
+197 1 1
+146 1 1
+103 1 1
+134 1 1
+16 1 1
+378 1 1
+85 1 1
+134 1 1
+25 1 1
+54 3 3
+55 1 1
+67 1 1
+22 1 1
+54 13 13
+55 11 11
+120 1 1
+23 1 1
+51 1 1
+22 1 1
+369 1 1
+273 1 1
+119 6 6
+229 34511 40178
+78 1 1
+22 1 1
+180 1 1
+33 1 2
+26 6 6
+474 1 1
+36 1 1
+151 1 1
+29 1 1
+120 1 1
+23 1 1
+865 1 1
+39 1 1
+330 1 1
+24 1 1
+197 1 1
+69 1 1
+116 3 0
+161 1 1
+38 1 1
+753 1 1
+57 3 3
+145 1 1
+121 1 1
+300 1 1
+147 1 1
+379 1 1
+55 2 2
+65 1 1
+32 1 1
+1008 1 1
+24 1 1
+159 18 18
+659 1 1
+76 0 2
+77 1 3
+65 1 1
+84 1 0
+119 1 1
+15 1 1
+247 4 0
+372 1 0
+1633 1 1
+16 1 1
+221 9772 11561
+315 1 1
+53 1 1
+67 1 1
+91 1 0
+23 1 0
+27 2 2
+66 2 2
+80 0 41
+12 1 1
+158 1 0
+92 2 0
+254 1 1
+43 1 1
+846 6 149
+84 1 1
+29 3 3
+315 17 17
+482 1 1
+29 3 3
+278 1 1
+73 1 1
+2767 1 1
+34 1 1
+192 1 1
+33 1 0
+168 6 0
+276 10 10
+344 1 1
+49 1 1
+109 1 1
+35 3 3
+561 24 27
+923 1 1
+102 1 1
+75 14 14
+266 1 1
+80 2 2
+185 1 0
+1035 1 1
+23 1 1
+417 10 10
+97 1 1
+94 1 1
+492 1 1
+37 5 5
+1429 1 1
+19 1 1
+839 1 1
+96 1 1
+1279 4 0
+683 1 1
+49 1 1
+514 1 1
+28 4 4
+2302 1 1
+42 1 1
+537 2 21
+1555 1 1
+42 0 1
+14 4 4
+86 1 1
+62 1 1
+515 5 1
+330 0 1
+159 0 22
+3841 1 0
+5065 12 12
+97 0 3
+772 1 1
+21 2 1
+1058 0 2
+349 2 0
+1080 6 0
+11 1 3
+53 0 2
+14 1 1
+1035 1 1
+85 1 1
+69 1 1
+27 1 1
+547 7 7
+195 1 1
+41 1 1
+395 1 1
+35 1 1
+73 0 1
+71 1 1
+557 3 3
+30 1 1
+66 49 49
+1310 0 2
+26 2 0
+10 1 15
+36 1 1
+196 1 1
+40 1 1
+141 1 1
+76 1 1
+1480 1 3
+347 1 1
+26 1 1
+231 1 1
+82 3 3
+69 3 0
+441 16 16
+147 1 1
+21 1 1
+3565 0 3
+877 2 0
+1036 1 1
+47 2 1
+3761 12 0
+5345 1 0
+11541 1 0
+1843 0 4
+1157 16 16
+7354 19 0
+736 0 1
+8058 1 0
+4449 21 21
+649 1 0
+2913 0 1
+381 331 0
+6066 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3870 0 1
+36 13 0
+1894 1 1
+40 0 4
+1137 6 0
+211 2 0
+345 1 0
+592 4 4
+1043 4 0
+686 14 0
+1032 0 1
+9035 0 4
+167 0 2
+19472 35 35
+4457 0 3
+1470 0 1
+289 3 0
+3780 41 41
+522 1 0
+2026 8 0
+430 0 1
+631 1 1
+21 1 1
+479 0 1
+697 4 0
+1779 1 1
+27 1 1
+196 4 0
+58 8 0
+2881 1 1
+39 1 1
+120 44 45
+538 1 0
+393 6 6
+3090 1 1
+43 1 1
+1246 1 0
+294 1 1
+27 1 1
+374 3 3
+144 1 1
+190 1 6
+750 1 0
+695 2 0
+1003 11 0
+1185 8 8
+763 0 4
+2737 11 11
+453 1 0
+536 1 1
+43 1 1
+57 1 0
+21 7 0
+3892 0 1
+3177 0 1
+8990 0 2
+2303 1 0
+2850 4 0
+1273 0 2
+5863 1 0
+9593 1 1
+81 1 1
+2777 0 2
+4564 34 34
+674 0 8
+11548 2 0
+6086 0 1
+109 1 1
+2286 0 1
+997 0 18
+3344 1 1
+40 1 1
+842 28 24
+1584 1 0
+1582 0 1
+1670 3 25
+17 0 4
+16 2 0
+6 12 0
+49 1 1
+538 1 1
+26 1 1
+5879 2 4
+2513 0 1
+346 8 8
+222 16 16
+103 1 0
+198 1 3
+539 1 1
+47 1 1
+1154 0 1
+3737 1 2
+370 2 0
+1178 1 1
+78 1 1
+47 0 1
+518 6 0
+646 13 13
+469 1 0
+1072 1 4
+858 1 0
+3674 1 0
+282 1 0
+597 0 6
+505 4 4
+183 1 1
+43 1 1
+1294 1 1
+40 1 1
+572 0 4
+464 0 4
+757 40 40
+1089 2 0
+548 1 0
+1300 0 3
+1839 2 0
+189 1 1
+49 1 1
+1253 1 1
+43 1 0
+498 1 1
+45 4 0
+3538 0 1
+1989 14 14
+1332 2 0
+3586 1 0
+989 1 2
+447 0 4
+40 1 1
+2445 16 17
+291 1 3
+7 1 0
+11 0 1
+41 1 1
+94 1 1
+49 1 1
+1515 6 0
+603 13 13
+163 1 1
+45 1 1
+2050 11 11
+1126 1 1
+16 1 1
+391 1 1
+19 0 1
+932 1 0
+42 1 1
+751 1 0
+287 1 1
+42 1 1
+464 0 4
+4069 5 5
+153 1 0
+514 2 0
+1093 1 1
+41 1 1
+1746 4 4
+1351 1 1
+38 1 1
+682 12 12
+519 0 72
+168 18 18
+146 7 7
+293 1 1
+61 0 1
+43 1 1
+236 1 0
+35 1 1
+152 14 14
+776 0 4
+809 4 0
+155 1 1
+44 1 1
+1068 1 1
+93 1 1
+209 15 15
+1331 0 3
+3912 0 1
+6624 0 4
+375 0 1
+7255 5 0
+419 2 0
+293 1 0
+10397 5 24
+11095 0 1
+1770 4 0
+374 0 4
+7714 1 0
+1229 7 6
+3055 1 0
+5818 1 0
+2415 11 9
+2056 0 1
+955 4 0
+3907 0 2
+16936 0 1
+1044 1 0
+2392 0 1
+158 2 1
+199 0 1
+75 6 6
+2094 8 0
+649 2 0
+373 75 75
+2253 1 0
+15 1 0
+1995 0 2
+818 4 0
+676 0 1
+3171 8 0
+170 0 3
+459 1 1
+37 1 1
+336 1 0
+206 1 1
+26 1 1
+224 15 15
+308 2 1
+82 1 1
+23 1 1
+562 1 1
+80 1 1
+241 0 8
+1530 1 1
+20 1 1
+1372 1 1
+44 1 1
+427 1 1
+20 1 1
+651 105 81
+221 1 1
+45 1 1
+1747 1 1
+27 1 1
+179 1 1
+70 1 1
+173 1 1
+84 0 36
+1864 1 1
+41 1 1
+44 9 0
+1028 1 0
+85 1 1
+21 1 1
+475 0 2
+256 1 1
+31 1 1
+653 1 1
+18 1 1
+62 1 1
+19 1 1
+997 1 1
+22 1 1
+326 1 0
+505 5 4
+386 0 7
+466 13 13
+870 11 12
+134 15 15
+248 0 2
+2281 1 1
+79 1 1
+56 9 6
+498 100 100
+802 1 0
+290 1 1
+38 1 1
+185 1 1
+61 1 1
+944 1 1
+22 1 1
+835 1 1
+66 1 1
+890 0 1
+3503 6 6
+231 0 1
+2136 1 0
+999 1 0
+5220 3 4
+830 1 1
+24 1 1
+1209 1 1
+38 1 1
+7077 1 0
+2939 1 0
+3959 0 2
+3746 0 2
+1011 1 1
+34 1 1
+7443 0 1
+688 2 0
+574 1 1
+29 1 1
+1785 2 0
+16 20 0
+4073 2 0
+136 1 1
+77 1 1
+528 27 0
+253 0 1
+204 1 0
+129 2 0
+811 1 1
+38 1 1
+2347 52 0
+4634 1 0
+856 14 14
+1052 1 1
+28 1 1
+1255 1 1
+36 1 1
+97 0 1
+58 1 1
+1708 1 1
+48 1 1
+958 13 0
+3371 1 1
+37 1 1
+4267 0 15
+1059 0 1
+272 0 20
+168 2 0
+26 4 32
+4090 0 2
+3269 1 1
+17 1 2
+1378 1 0
+1443 0 1
+6206 1 0
+2318 0 1
+7695 2 0
+396 22 12
+918 0 1
+1818 0 1
+28 1 1
+492 1 1
+33 1 1
+326 1 1
+80 1 1
+288 8 17
+2671 0 1
+1099 0 1
+144 1 1
+29 0 1
+2098 0 2
+24 4 0
+1207 4 4
+45 1 1
+757 0 5
+1926 1 1
+40 1 1
+2657 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+713 0 4
+58 1 0
+1041 3 0
+36 1 1
+377 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+8189 4 5
+36 1 1
+102 2 0
+14 1 1
+682 0 6
+147 0 1
+750 0 3
+40 1 1
+2428 0 1
+750 2 0
+473 0 2
+2032 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+11881 1 1
+30 1 1
+4383 2 0
+6883 49 49
+3146 0 1
+906 2 0
+887 1 1
+80 1 1
+2210 1 0
+905 0 1
+1037 1 0
+5866 0 2
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 4 0
+3170 1 0
+1751 0 1
+910 2 0
+691 0 1
+32873 0 1
+1722 0 1
+17559 16 24
+1369 29 0
+494 2 0
+4432 0 1
+23680 26 26
+10911 0 1
+920 0 1
+4586 0 2
+2232 1 0
+5718 0 1
+12415 1 1
+51 0 1
+7997 0 2
+1700 1 0
+2697 1 0
+2561 2 0
+1544 0 6
+1613 3 7
+37 9 1
+2113 1 0
+7174 0 34
+7914 1 1
+35 1 1
+5308 1 0
+2303 2 1
+423 7 7
+590 1 0
+24 1 1
+165 6 0
+2848 13 13
+64 0 1
+28 1 1
+723 0 4
+2868 0 1
+731 1 1
+60 1 1
+1012 3 0
+490 29 29
+1225 1 1
+78 1 1
+61 1 0
+2362 11 11
+399 1 0
+1494 16 16
+128 24 24
+530 1 1
+35 1 1
+5276 1 0
+415 0 1
+580 1 2
+1450 22 23
+816 1 0
+1953 1 0
+881 10 1
+885 8 14
+183 14 14
+1139 25 25
+155 1 1
+94 1 1
+419 3 3
+26 1 1
+56 1 0
+69 1 0
+117 1 1
+120 1 1
+42 1 1
+825 0 2
+108 1 1
+24 1 1
+956 3 0
+664 1 1
+41 1 1
+716 4 0
+1731 8 8
+4228 0 1
+5694 3 0
+4493 0 1
+2656 1 0
+3029 4 0
+5688 1 0
+170 2 0
+5972 0 2
+840 0 2
+55 1 1
+28 1 1
+2954 0 1
+4343 6 0
+1663 4 0
+150 1 0
+3128 1 0
+1449 3 0
+1534 1 0
+489 1 0
+431 0 4
+299 2 0
+5082 9 0
+413 0 1
+989 0 2
+4941 0 1
+6655 1 0
+349 8 7
+762 1 1
+29 0 3
+1434 0 1
+1267 0 1
+587 1 1
+22 0 1
+894 28 0
+1343 2 0
+2256 0 1
+4332 0 4
+22 1 1
+12415 12 10
+10485 0 1
+1429 0 12
+625 1 7
+1224 0 10
+1680 4 0
+5169 14 14
+3878 0 8
+2544 0 140
+9238 0 1
+1575 0 3
+1775 1 1
+31 1 1
+1200 1 0
+32 0 3
+797 0 8
+35 0 2
+599 1 1
+22 1 1
+5338 2 0
+1998 0 5
+146 0 4
+12031 0 1
+1993 0 1
+706 2 0
+2735 0 1
+3859 0 4
+4845 0 2
+268 2 0
+827 4 4
+1063 6 6
+7834 2 0
+3195 0 1
+4012 10 0
+6429 0 2
+308 0 1
+808 1 0
+17 8 0
+5472 19 2
+2436 0 14
+820 9 9
+2643 1 1
+32 1 1
+1189 1 0
+5710 0 3
+308 1 0
+4930 0 1
+4308 1 0
+946 82 0
+1790 0 2
+1218 25 0
+52 0 1
+1271 1 1
+33 1 1
+4760 1 0
+4924 0 1
+4817 4 4
+39 1 0
+1116 3715 901
+205 1 0
+1591 5 2
+138 2 2
+16 1 1
+802 0 89
+1600 0 6
+2175 0 5
+606 14 14
+519 1 0
+540 1 1
+40 1 1
+568 2 0
+458 1 1
+41 1 1
+1106 24 62
+818 1 1
+42 1 1
+2266 1 0
+14059 0 4
+5030 1 0
+12630 0 3
+84 9 9
+129 13 18
+564 10 15
+154 1 0
+438 10 10
+38 0 5
+98 11 9
+2034 1 1
+25 1 1
+73 10 10
+70 5 5
+132 1 1
+52 1 1
+599 1 1
+46 1 1
+279 1 1
+18 1 1
+239 3 0
+383 6 0
+224 0 1
+321 15 0
+1783 1 1
+18 3 0
+108 1 1
+60 1 1
+405 16 16
+60 1 1
+16 1 1
+970 1 1
+24 1 1
+424 3 0
+41 1 1
+57 8 8
+285 2 0
+672 1 1
+44 1 4
+103 0 1
+148 1 1
+49 3 0
+146 5 11
+91 1 1
+79 1 1
+94 1 1
+101 1 1
+88 16 16
+117 1 1
+15 1 1
+58 1 1
+93 1 1
+466 1 1
+44 1 1
+160 1 1
+23 1 1
+481 14 14
+181 4 4
+72 1 1
+25 1 1
+82 7 12
+4 0 1
+11 1 4
+20 0 5
+92 1 1
+56 10 0
+80 1 1
+141 2 0
+60 1 1
+372 0 2
+784 1 1
+85 1 1
+109 1 1
+16 1 1
+57 1 1
+92 3 1
+23 1 0
+26 1 1
+74 1 1
+33 1 1
+176 1 1
+25 2 2
+193 1 1
+35 0 1
+383 0 5
+249 1 1
+69 1 1
+98 1 1
+70 1 1
+55 1 1
+143 1 1
+438 1 1
+64 1 1
+53 4 0
+127 3 0
+75 5 5
+45 1 1
+197 1 1
+27 1 1
+116 13 13
+218 15 20
+1107 16 19
+73 1 1
+101 1 1
+123 1 1
+60 1 1
+994 1 1
+43 0 1
+18 1 1
+1215 18 18
+340 1 1
+34 1 1
+1350 16 16
+1417 1 1
+29 1 1
+475 1 1
+48 1 1
+198 10 10
+87 1 1
+18 1 1
+171 7 7
+427 1 1
+21 1 1
+2011 0 3
+17 1 1
+1412 1 1
+24 1 1
+214 8 4
+228 1 1
+34 1 1
+410 16 16
+185 1 1
+24 1 0
+164 0 1
+222 1 1
+25 1 1
+297 10 10
+1171 1 0
+569 19 19
+2755 1 0
+11 1 1
+2502 1 1
+23 1 1
+44 12 0
+2856 0 1
+148 1 1
+36 1 1
+993 2 0
+1251 2 0
+6619 14 14
+1014 4 0
+134 2 9
+818 1 0
+61 1 7
+563 46 0
+78 5 5
+1677 1 1
+49 1 1
+399 1 1
+32 1 1
+790 27 27
+104 1 1
+75 1 1
+1638 1 1
+16 1 1
+92 1 1
+44 1 1
+276 0 13
+1020 1 1
+35 1 1
+389 14 14
+256 1 0
+38 1 3
+631 1 1
+40 1 1
+2356 85 83
+1300 0 5
+511 0 2
+605 1 1
+17 1 1
+880 12 0
+1689 4 0
+2492 1 1
+39 1 1
+641 16 16
+682 0 5
+669 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+498 3 0
+321 0 1
+281 3 0
+450 1 1
+34 1 1
+498 1 1
+28 2 1
+280 0 2
+648 1 1
+47 1 1
+1002 4 0
+120 1 1
+1538 0 1
+75 1 1
+37 1 1
+510 91 91
+60 18 18
+2075 1 1
+19 1 1
+2429 1 1
+21 1 1
+107 1 0
+2786 0 2
+31 5 5
+1973 12 0
+3118 1 0
+246 0 1
+33 1 1
+6752 1 0
+822 2 9
+606 1 1
+18 1 1
+3920 1 1
+37 0 2
+4497 10 13
+301 20 20
+2130 1 1
+16 3 0
+1843 0 4
+3780 3 0
+850 0 1
+2774 0 3
+2065 0 1
+20 1 1
+1400 1 0
+3243 0 15
+1336 5 0
+448 49 49
+121 7 7
+1507 8 7
+422 1 0
+2184 0 1
+304 0 2
+19 0 1
+101 1 1
+417 3 3
+22 1 1
+672 4 4
+31 1 1
+150 1 1
+38 1 1
+161 5 0
+17 1 1
+72 1 0
+106 1 1
+463 1 1
+94 1 1
+138 3 4
+185 1 1
+29 1 1
+220 15 15
+167 1 1
+32 1 1
+93 1 3
+217 1 1
+23 1 1
+137 9 9
+62 0 3
+353 1 1
+27 1 1
+117 9 9
+421 1 1
+47 1 1
+124 0 1
+997 6 0
+54 5 5
+764 1 1
+45 1 1
+1431 7 7
+387 6 6
+1103 0 36
+767 1 1
+31 1 3
+208 5 5
+1610 1 1
+23 1 1
+779 0 8
+324 0 2
+45 1 1
+264 0 3
+45 1 1
+250 1 1
+18 1 1
+517 33 0
+117 1 1
+42 1 1
+550 1 1
+20 1 1
+671 1 1
+68 1 1
+89 1 1
+104 1 1
+172 0 1
+124 0 1
+522 0 1500
+466 5 5
+32 1 0
+171 1 1
+19 1 1
+67 1 1
+22 1 1
+654 1 1
+25 1 1
+68 1 1
+21 4 0
+1588 1 1
+66 1 1
+401 0 1
+186 1 1
+21 1 1
+168 0 1
+686 3 0
+19 1 1
+127 1 1
+29 1 1
+234 1 1
+30 1 1
+141 0 2
+33 1 1
+673 1 1
+89 1 1
+161 16 16
+504 20149 20139
+1269 1 1
+40 1 1
+327 1 1
+24 1 1
+172 2 2
+27 11 15
+381 10 11
+376 1 1
+45 1 1
+121 1 1
+62 1 1
+289 1 1
+26 1 1
+191 1 1
+20 11 11
+425 1 1
+37 1 1
+296 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+306 1 1
+24 1 1
+1299 1 1
+47 1 1
+2026 1 1
+20 1 1
+133 1 0
+9803 0 4
+15871 3 0
+2464 1 1
+24 1 1
+879 1 1
+73 1 1
+89 1 1
+42 1 1
+108 1 1
+43 0 1
+26 1 1
+511 5 6
+605 19531 20105
+55 1 1
+37 0 2
+89 1 1
+51 1 1
+85 1 1
+78 1 1
+173 1 1
+51 1 1
+90 3 3
+95 1 1
+32 1 1
+53 1 1
+231 1 0
+82 2 0
+27 0 1
+44 1 0
+96 10 7
+132 1 1
+233 1 1
+257 1 1
+56 5 5
+237 1 1
+141 1 1
+92 1 1
+154 7 7
+3208 1 1
+33 1 1
+671 1 1
+21 1 1
+955 0 3
+130 1 1
+26 1 1
+288 8 8
+218 0 3
+1076 8 0
+609 10041 10021
+240 2 2
+66 1 1
+228 1 1
+23 1 1
+1612 1 1
+21 1 1
+261 1 1
+99 1 1
+128 1 1
+15 1 1
+77 9 9
+618 8 8
+84 4 6
+438 1 1
+140 1 1
+158 4 3
+277 12 12
+165 4 4
+36 1 1
+253 1 1
+59 1 1
+910 0 1
+915 4 5
+276 15 15
+682 1 1
+28 1 1
+1483 13 13
+203 1 0
+52 1 1
+48 1 1
+229 12 12
+68 15 15
+83 1 1
+39 1 1
+194 1 1
+24 1 1
+251 8 8
+619 0 4
+15 1 1
+690 1 1
+28 1 1
+54 0 1
+463 1 1
+30 1 1
+449 1 1
+54 1 1
+58 5 5
+979 1 0
+318 1 1
+28 1 1
+898 10 10
+100 1 1
+22 1 1
+446 1 1
+74 1 1
+273 1 1
+19 1 1
+333 1 1
+44 1 1
+220 1 1
+56 2 0
+209 1 1
+70 1 1
+223 0 20
+220 1 1
+31 1 1
+56 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+195 1 1
+46 1 1
+184 1 1
+60 0 4
+76 0 4
+53 3 1
+43 1 1
+153 1 1
+53 1 1
+195 6 0
+60 1 1
+278 1 0
+42 1 1
+124 10014 10005
+302 1 1
+24 1 1
+135 20 19
+55 1 1
+40 1 1
+175 1 1
+46 1 1
+52 1 1
+19 1 1
+277 1 1
+88 1 1
+172 1 1
+26 1 1
+129 1 1
+35 1 1
+55 9 9
+318 3 3
+46 1 1
+101 8 8
+4653 1 1
+38 1 1
+817 2 0
+256 1 1
+27 1 1
+339 1 1
+48 1 1
+54 10 10
+1393 3 0
+1491 2 0
+1983 16 0
+167 0 4
+3886 7 8
+535 1 1
+16 1 1
+1555 3 0
+3131 1 1
+17 1 1
+4196 1 0
+14974 0 1
+3514 0 4
+29 1 1
+123 0 2
+51 33 0
+121 0 133
+80 1 10
+26 60 4
+52 13 0
+20 0 2
+19 2 0
+22 4 156
+57 156 3
+61 0 2
+29 20 0
+42 11 0
+21 2 0
+50 4 6
+31 1 3
+23 1 53
+25 0 32
+66 1 55
+11 0 2
+13 0 41
+68 1 42
+23 1 3
+12 2 0
+17 1 29
+51 17 13
+18 2 0
+28 2 0
+26 2 0
+158 1 25
+102 0 82
+99 280 0
+53 21 0
+5064 0 2
+7569 2 0
+2189 0 1
+85 1 1
+31 0 4
+399 14 14
+408 0 1
+681 0 5
+184 1 1
+20 1 1
+64 1 1
+29 1 0
+9 2 0
+442 4 0
+342 1 1
+24 1 1
+131 1 1
+198 1 1
+370 0 1
+34 1 1
+447 21 20
+259 1 1
+23 0 1
+121 2 0
+2257 1 1
+22 1 1
+811 1 1
+27 1 1
+95 18 18
+631 0 5
+843 0 2889
+55 0 88
+1189 0 2
+2274 1 0
+752 4 0
+164 1 1
+55 1 1
+1033 10 10
+683 1 1
+57 1 1
+3578 1 1
+34 1 1
+1446 1 0
+460 1 1
+31 0 1
+6 1 1
+163 1 1
+22 1 1
+81 1 1
+27 1 1
+548 1 1
+61 1 1
+1169 1 1
+41 1 1
+1568 14 14
+4889 1 1
+62 1 1
+530 17 17
+394 1 1
+40 7 0
+57 12 12
+69 2 2
+39 1 1
+70 1 1
+22 0 3
+2307 1 1
+30 1 1
+411 1 1
+104 1 1
+375 26 27
+1218 1 1
+35 1 1
+85 1 1
+20 6 0
+687 1 1
+34 1 1
+268 13 13
+74 1 1
+47 2 0
+69 1 1
+49 1 1
+73 1 1
+48 1 1
+218 1 1
+42 1 1
+197 1 1
+41 1 1
+313 1 1
+40 1 1
+476 1 1
+29 1 1
+185 1 1
+35 1 1
+594 1 1
+24 1 1
+220 26 0
+245 0 1
+261 13 13
+89 1 1
+90 1 1
+224 1 1
+201 1 1
+306 1 1
+29 5 5
+121 1 1
+31 1 1
+109 1 1
+25 1 1
+168 1 1
+19 1 1
+93 12 11
+132 1 0
+113 1 1
+30 1 1
+56 9 9
+300 1 1
+50 2 2
+96 1 1
+43 1 1
+76 1 1
+44 1 1
+197 1 1
+91 7 1
+119 0 9
+392 5 5
+89 1 1
+428 11 11
+260 1 1
+23 1 0
+10 1 1
+70 1 1
+65 2 0
+16 0 19
+28 1 1
+208 1 1
+70 1 1
+149 0 3
+51 29 29
+163 1 1
+55 1 1
+63 17 17
+1208 1 1
+98 1 1
+162 1 1
+45 1 1
+148 14 14
+51 5 5
+209 4 4
+1242 1 1
+42 5 0
+87 1 1
+522 0 3
+305 0 1
+1379 0 2
+390 0 15
+72 1 1
+16 1 1
+270 1 0
+280 7 7
+2763 20 20
+674 10 10
+1375 14 0
+327 2 0
+107 1 1
+629 16 16
+54 4 4
+680 16 16
+395 1 1
+42 1 1
+1763 1 1
+46 1 1
+282 1 1
+39 1 1
+860 1 1
+26 1 1
+745 0 2
+2081 2 0
+817 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+132 5 0
+555 1 1
+65 1 1
+550 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+15 1 5
+1404 0 1
+450 4 0
+626 1 0
+304 1 1
+39 1 1
+564 1 1
+45 1 1
+303 2 0
+409 1 1
+18 1 0
+858 2 0
+2168 0 1
+54 1 1
+20 1 1
+524 0 1
+410 10 10
+106 1 14
+2419 18 14
+64 1 1
+31 1 1
+185 0 5
+1646 1 1
+20 1 1
+227 1 1
+37 1 1
+500 1 0
+136 3 4
+8239 1 1
+23 1 1
+1114 0 2
+688 0 1
+901 18 18
+4781 0 4
+815 0 1
+5069 0 5
+415 0 2
+352 0 1
+1085 11 11
+1099 0 1
+991 0 1
+845 1 1
+32 0 2
+5751 0 3
+1553 1 1
+60 1 1
+278 0 1
+30 1 1
+1855 0 2
+958 0 1
+66 0 16
+2109 0 2
+1265 0 1
+17312 0 4
+1875 0 1
+2157 1 0
+915 0 6
+4940 1 0
+2649 0 1
+3331 2 0
+2276 14 0
+3128 0 4
+3496 1 0
+966 0 1
+3597 1 0
+1647 0 3
+1182 1 0
+654 0 3
+2049 1 0
+6838 1 1
+39 1 1
+186 1 0
+2718 1 1
+30 1 1
+160 11 11
+4954 0 1
+420 1 1
+123 1 1
+156 0 4
+219 4 0
+195 1 0
+4402 2 0
+4295 1 0
+4207 20 20
+468 0 1
+30 1 1
+6025 1 0
+4179 1 0
+19834 0 1
+11605 0 1
+4121 2 0
+2863 0 2
+4890 1 0
+5576 0 6
+4104 4 0
+19858 4 0
+1616 0 3
+1647 4 1
+36 0 12
+2213 0 14
+414 0 1
+458 20 20
+2860 0 3
+678 3 4
+292 2 0
+1922 0 1
+913 0 1
+2720 1 0
+1111 3 0
+2589 0 8
+9425 1 0
+1403 0 2
+1964 0 12
+4433 0 1
+1569 0 1
+7209 1 1
+41 1 1
+2257 1 0
+3001 0 1
+1845 1 0
+1593 0 1
+497 0 2
+6109 0 1
+2019 2 0
+921 0 1
+241 1 0
+5473 1 0
+2213 2 0
+1974 8 0
+4952 0 1
+6146 2 0
+953 1 0
+4141 0 1
+4244 5 0
+152 0 2
+209 0 1
+2400 0 10
+785 2 0
+1733 0 1
+554 1 0
+128 0 2
+3051 0 1
+8577 0 1
+1503 0 1
+1705 0 3
+2052 17 17
+998 177 0
+2804 1 0
+1925 1 0
+9215 0 1
+971 8 0
+36021 1 0
+8016 29 27
+3890 0 1
+67913 1 1
+18 1 6368
+73 1 32739
+14676 1 1
+19 1 1
+22867 1 1
+20 1 1
+5638 5 0
+47 12 0
+11313 0 1
+1769 0 1
+8355 0 3
+4114 0 2
+1403 1 0
+5140 0 1
+490 0 1
+219 1 0
+3483 1 0
+8939 1 1
+44 1 1
+10813 0 2
+7480 2 0
+617 1 0
+1464 0 1
+500 0 2
+1466 1 0
+527 5 0
+3593 0 1
+374 0 1
+2946 22 22
+698 0 1
+2149 1 0
+311 2 0
+6570 1 0
+962 1 0
+23 1 1
+2647 4 0
+588 1 1
+21 1 1
+3256 28 20
+870 0 1
+644 1 0
+602 2 1
+3730 1 1
+45 1 1
+12848 7 7
+7306 0 3
+6647 45 45
+1365 1 1
+63 1 1
+4166 1 0
+1887 10 0
+2949 1 1
+31 0 1
+669 1 0
+2190 2 0
+2081 0 2
+373 0 6
+421 4 4
+1460 0 1
+1699 0 8
+2882 2 0
+147 0 1
+1656 1 1
+27 1 1
+1828 0 2
+4066 35 38
+361 17 17
+1254 6 0
+1643 0 2
+2542 0 1
+848 2 1
+2117 0 2
+119 1 1
+44 1 1
+1104 0 1
+415 0 12
+634 18 1
+377 6 7
+227 6 0
+449 13 13
+895 0 17
+457 18 18
+663 0 3
+382 1 1
+26 1 1
+135 0 1
+105 1 1
+25 1 1
+620 2 0
+290 5 5
+375 1 1
+30 0 4
+98 1 0
+20 17 4
+3824 28 0
+39 4 0
+28 4 0
+44 4 0
+1898 9 9
+221 0 2
+10522 30 0
+783 1 1
+59 1 1
+94 1 1
+21 1 1
+491 1 1
+49 1 1
+289 2 0
+120 0 1
+37 1 1
+112 1 1
+21 1 1
+183 16 16
+73 2 0
+1007 1 1
+38 0 1
+79 1 1
+48 1 1
+561 1 1
+29 1 1
+145 5 5
+576 12 12
+834 1 0
+846 5 7
+34 1 1
+417 10 11
+55 1 1
+40 1 1
+110 1 1
+47 1 1
+351 1 1
+69 1 1
+53 1 1
+91 1 1
+260 1 1
+36 0 1
+604 1 0
+169 0 1
+2118 1 1
+34 1 1
+147 1 1
+213 1 1
+67 1 1
+31 1 1
+566 1 0
+17 1 1
+763 1 1
+34 1 1
+671 5 0
+41 2 2
+98 0 1
+449 0 2
+61 1 1
+38 1 1
+202 1 1
+44 1 1
+190 1 0
+46 4 4
+51 0 4
+476 1 1
+17 1 1
+212 1 1
+26 1 1
+485 1 1
+25 1 1
+263 1 1
+26 1 1
+1327 4 0
+44 1 0
+2397 1 1
+44 1 1
+4146 14 14
+901 0 1
+1769 14 14
+1721 1 0
+1125 1 0
+254 1 0
+427 0 1
+30 1 1
+111 0 2
+52 0 8
+528 44 0
+969 1 1
+10 1 0
+28 1 1
+140 1 1
+43 1 1
+1989 2 1
+598 1 1
+87 0 4
+124 1 0
+4840 1 1
+28 7 4
+505 0 2
+24 1 1
+5134 4 0
+543 1 0
+18 1 1
+97 1 1
+29 1 3
+101 6 0
+148 13 7
+1346 0 1
+128 7 0
+49 0 1
+876 2 0
+286 5 5
+184 0 1
+84 5 5
+365 9 9
+981 1 1
+11 1 1
+734 4 0
+563 4 0
+244 9 9
+379 1 1
+17 1 1
+49 2 0
+95 1 1
+30 1 1
+147 1 1
+37 0 6
+340 1 2
+58 1 1
+332 0 2
+233 6 9
+156 0 1
+26 1 1
+439 4 0
+34 0 2
+508 5 0
+96 1 1
+34 1 1
+1267 63 63
+590 1 1
+24 4 5
+1055 13 13
+135 0 1
+194 1 1
+61 1 1
+384 6 6
+2756 1 1
+19 1 1
+99 15 15
+1754 2 3
+2238 1 1
+31 1 1
+3002 4 0
+2156 15 15
+855 14 13
+442 5 5
+2022 6 6
+506 0 2
+1110 0 1
+2578 0 2
+4864 1 1
+36 1 0
+3187 1 1
+16 1 1
+184 1 1
+18 1 1
+1636 0 7
+23 1 1
+527 1 1
+39 1 1
+653 3 0
+227 1 1
+18 1 1
+102 7 7
+109 0 323
+91 1 0
+124 0 15
+621 0 4
+553 12 12
+463 1 1
+40 1 1
+372 1 1
+25 1 1
+188 12 12
+357 0 1
+250 0 5
+4193 0 4
+967 1 1
+76 1 1
+3236 4 4
+529 7 7
+246 4 0
+160 1 1
+34 0 3
+1469 0 2
+499 1 0
+937 1 1
+45 1 1
+356 71 65
+2127 0 1
+491 1 0
+80 1 1
+72 2 0
+255 6 6
+728 14 11
+702 3 0
+290 0 2
+210 19 1
+473 1 1
+42 4 0
+219 0 1
+348 1 1
+83 1 1
+851 0 16
+72 13 0
+246 1 1
+47 4 0
+410 1 0
+93 0 12
+225 0 16
+428 1 0
+4 6 0
+324 0 1
+3060 0 16
+1305 1 1
+29 1 1
+3094 0 7
+600 0 2
+5495 1 1
+47 1 1
+1247 49 55
+4351 1 1
+15 1 1
+2011 6 14
+8378 2 0
+295 0 17
+4583 1 0
+4132 0 4
+924 4 3
+1751 0 2
+1060 12 12
+380 0 2
+425 8 0
+84 0 1
+244 1 1
+28 1 1
+221 4 0
+348 1 1
+37 11 11
+50 1 1
+180 1 1
+348 1 1
+20 1 1
+1714 1 1
+79 1 1
+729 1 1
+44 1 0
+78 1 1
+112 1 1
+23 1 1
+55 9 9
+1044 1 1
+27 1 1
+494 1 1
+32 1 1
+237 1 1
+27 1 1
+1422 4 4
+413 7 1
+710 8 0
+185 0 2
+966 1 0
+13 15 1
+251 1 1
+47 1 1
+285 1 1
+103 1 1
+977 1 1
+41 1 0
+97 1 1
+131 1 0
+307 1 1
+47 1 1
+1070 1 1
+69 1 1
+382 0 1
+167 1 1
+35 1 1
+161 1 1
+30 1 1
+1068 18 0
+1173 1 1
+32 1 1
+59 1 1
+12 1 0
+18 1 1
+55 0 22
+72 1 1
+2806 1 1
+15 1 1
+1395 1 0
+157 13 0
+536 8 8
+101 1 1
+21 1 1
+147 8 8
+638 1 1
+18 1 1
+183 15 15
+990 0 12
+21 1 1
+145 0 1
+332 1 1
+31 1 1
+231 22 5
+39 1 1
+414 9 9
+93 1 1
+63 1 1
+739 0 2
+632 1 1
+74 1 1
+138 5 5
+128 0 1
+294 1 1
+45 1 1
+679 6 6
+1756 0 34
+560 27 27
+1608 5 0
+219 1 1
+134 0 3
+81 1 1
+82 0 1
+357 1 1
+28 1 1
+670 7 9
+270 0 1
+891 13 33
+257 4 0
+80 0 4
+130 2 0
+2504 42 42
+1226 1 1
+44 1 1
+2256 0 1
+80 12 0
+5544 1 0
+428 13 13
+77 4 4
+63 1 1
+64 13 19
+178 10023 10000
+157 3 3
+109 1 1
+180 1 1
+56 1 1
+169 1 0
+93 1 1
+33 2 2
+72 1 1
+30 1 1
+267 25 25
+65 1 1
+19 2 0
+108 27 27
+218 1 1
+37 1 1
+477 11 11
+93 1 1
+30 7 5
+242 0 1
+171 1 1
+29 1 1
+218 0 9
+241 1 1
+55 4 4
+88 1 1
+99 1 1
+57 0 1
+523 12 16
+399 1 1
+50 1 1
+389 1 1
+71 4 4
+173 12 12
+92 1 1
+20 1 1
+132 0 5
+15 1 1
+75 1 1
+26 5 5
+119 11 11
+542 1 1
+23 2 2
+254 1 1
+34 1 1
+172 1 1
+45 1 1
+95 11 11
+127 23 23
+64 1 1
+95 1 1
+390 1 1
+52 1 1
+170 1 1
+16 5 0
+30 1 1
+599 1 1
+119 1 1
+85 1 1
+75 1 1
+286 4 4
+61 1 1
+286 9 9
+429 1 1
+21 1 1
+53 1 1
+44 1 1
+77 165084 190027
+5156 0 1
+1680 1 1
+88 1 1
+4502 0 1
+46 1 1
+800 4 4
+23 1 1
+1305 2 0
+136 0 1
+4941 0 1
+547 0 1
+70 8 8
+293 1 1
+35 1 1
+1165 4 0
+6662 1 1
+121 1 1
+92 0 8
+214 1 1
+35 1 1
+108 1 0
+1063 0 1
+1017 1 1
+20 0 6
+1725 0 1
+150 5 5
+33 1 0
+12 1 1
+349 1 1
+24 0 1
+1562 1 1
+31 1 1
+2513 0 1
+73 36 36
+305 1 1
+27 1 1
+543 1 1
+47 4 28
+4874 0 3
+599 10 10
+137 1 0
+7 0 4
+54 1 1
+2497 1 1
+166 1 1
+637 3 3
+46 1 1
+74 4 4
+414 1 1
+48 1 1
+75 4 4
+153 0 26
+93 1 1
+39 1 0
+58 1 1
+51 1 1
+145 9 9
+29 1 1
+55 1 1
+427 1 0
+141 1 1
+87 1 1
+20 1 1
+89 3 3
+141 18 5
+48 1 1
+87 14 14
+173 1 1
+68 1 1
+54 1 1
+51 4 0
+22 1 0
+52 1 1
+171 1 1
+109 3 1
+6 0 2
+205 1 1
+54 10064 10083
+76 3 1
+197 15 15
+77 1 1
+70 1 1
+178 1 1
+60 1 1
+210 1 1
+28 1 1
+62 1 1
+33 1 1
+70 0 1
+202 1 1
+60 1 1
+106 2 0
+176 1 1
+79 0 1
+50 1 1
+50 3 3
+207 1 1
+272 5 5
+243 1 1
+84 1 1
+98 1 1
+50 5 5
+77 1 1
+74 1 1
+20 0 1
+143 1 1
+45 0 1
+4 1 1
+1088 1 1
+35 1 1
+320 1 1
+22 1 1
+275 1 1
+47 1 1
+370 19 19
+119 1 6
+51 1 1
+21 1 1
+244 0 1
+345 1 1
+24 1 1
+181 1 1
+61 3 3
+542 1 1
+16 1 1
+312 1 0
+353 4 3
+279 323 0
+86 1 1
+49 1 1
+342 1 1
+44 0 2
+222 1 1
+37 1 1
+588 8 8
+593 47 47
+359 1 1
+25 1 1
+2054 1 0
+2510 1 0
+5040 11 12
+1489 9 9
+3292 1 0
+1449 1 1
+21 1 1
+6768 1 0
+706 2 0
+7107 1 1
+38 1 1
+1163 1 1
+35 1 1
+435 1 1
+60 1 1
+325 0 1
+254 1 1
+43 1 1
+210 1 1
+7 1 0
+47 1 1
+130 4 4
+34 1 1
+208 1 1
+39 2 2
+526 1 1
+36 1 1
+99 9 7
+20 1 1
+73 1 1
+62 1 1
+425 1 1
+43 1 1
+811 1 1
+38 1 1
+362 1 1
+49 1 1
+109 1 1
+19 1 1
+79 1 1
+29 0 1
+26 1 1
+252 1 1
+75 1 1
+441 1 1
+66 1 1
+389 13 13
+67 7 7
+1185 0 311
+64 6 6
+389 31 31
+247 1 1
+38 1 1
+79 1 0
+553 1 1
+30 1 1
+433 1 1
+16 3 0
+1133 12 12
+262 5 5
+276 1 0
+960 14 14
+272 1 1
+41 1 1
+196 1 0
+1424 18 19
+314 1 1
+22 1 1
+345 1 1
+23 3 0
+245 1 1
+78 1 1
+77 1 1
+779 1 1
+32 1 1
+247 1 1
+48 1 1
+778 2 0
+226 1 1
+61 1 1
+867 0 1
+53 1 1
+397 1 1
+12 4 0
+46 1 1
+602 1 1
+35 1 1
+422 1 1
+49 1 1
+789 1 1
+37 1 1
+268 0 2
+589 8 8
+366 12 20
+1651 2 7
+19 1 1
+417 1 1
+37 1 1
+812 1 1
+33 3 0
+1351 18 18
+2186 1 1
+86 1 1
+1433 1 1
+39 1 1
+83 0 1
+238 0 1
+171 1 1
+7 2 1
+67 1 1
+596 1 1
+29 1 1
+144 4 6
+417 1 0
+88 1 1
+24 1 1
+390 18 18
+496 14 21
+145 1 1
+46 1 1
+310 1 1
+35 1 1
+214 1 1
+38 1 1
+206 1 1
+37 1 0
+240 1 1
+32 1 1
+469 1 1
+32 1 1
+208 1 1
+21 1 1
+343 1 1
+17 1 1
+88 1 1
+58 6 0
+169 1 1
+22 1 1
+162 0 1
+196 0 2
+500 6 5
+108 1 1
+40 2 0
+50 1 1
+111 1 0
+21 0 1066
+175 5 5
+155 1 1
+44 1 1
+11005 0 1
+6280 1 1
+48 1 1
+1173 1 1
+19 1 1
+2664 0 1
+351 1 0
+1059 14 14
+593 0 1
+869 16 16
+23065 2 0
+2197 0 1
+949 0 1
+15048 0 1
+606 1 0
+7820 0 4
+14669 1 0
+14708 0 1
+16326 0 1
+304 18 18
+388 2 0
+194 1 1
+49 1 1
+262 0 1
+92 1 1
+10677 2 0
+4856 3 0
+7447 6 6
+421 1 0
+884 6 0
+17 1 0
+3075 1 0
+1610 12 12
+13049 3 1
+3762 2 0
+601 2 0
+2461 0 2
+5154 1 0
+1604 0 16
+3338 26 26
+225 0 1
+1488 1 0
+1196 0 2
+683 0 1
+1218 1 0
+221 1 1
+22 1 1
+296 4 4
+1456 23 41
+880 1 12
+2490 1 0
+151 1 1
+33 1 1
+2809 4 4
+3645 1 1
+17 1 1
+3496 2 0
+154 1 1
+29 1 1
+158 0 1
+5981 1 1
+32 1 1
+1041 0 2
+174 9 0
+1383 0 1
+389 1 2
+1570 2 0
+3993 4 0
+4576 87 87
+142 8 8
+2203 20 24
+2009 1 1
+39 1 1
+489 1 1
+17 1 1
+628 1 1
+124 1 1
+1607 1 1
+23 1 1
+1021 0 8
+1249 0 20
+46 0 32
+46 6 0
+24 0 10
+7679 1 1
+44 1 1
+580 1 1
+28 1 1
+264 1 1
+65 0 1
+15 1 1
+1513 28 28
+830 19 19
+57 1 1
+21 1 1
+231 1 1
+94 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 1 1
+38 1 1
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 29 29
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+270 1 1
+272 1 1
+232 1 1
+94 1 1
+3189 0 176
+834 0 35
+303 0 51
+321 1 0
+17170 0 1
+321 1 1
+25 1 1
+679 1 1
+33 1 1
+990 11 11
+131 8 8
+79 9 9
+1284 9945 10022
+2039 8 23
+491 1 1
+32 1 1
+85 1 1
+41 1 1
+480 1 1
+74 2 2
+1108 59 0
+70 10 10
+325 11 11
+879 1 1
+34 1 1
+524 1 1
+25 1 1
+202 17 17
+1154 1 1
+26 1 1
+89 17 17
+87 1 1
+39 1 1
+950 1 1
+15 2 2
+51 1 1
+81 1 1
+180 1 0
+187 1 1
+37 1 1
+467 1 1
+19 1 1
+755 0 2
+81 3 1
+16 1 1
+67 6 6
+84 1 1
+37 2 0
+31 0 28
+15 0 37
+266 14 14
+372 1 1
+68 1 1
+462 1 1
+46 1 1
+563 19 0
+217 9 9
+363 1 1
+22 1 1
+884 1 1
+40 1 1
+179 1 1
+42 1 1
+94 6 6
+922 1 1
+30 1 1
+481 0 3
+7925 15 11
+333 5 0
+1235 6 6
+355 1 1
+27 1 1
+515 1 0
+1077 11 0
+1521 1 0
+38 1 1
+119 1 1
+58 1 1
+63 4 3
+385 1 1
+49 1 1
+77 44 46
+87 11 11
+190 2 2
+45 1 1
+373 1 1
+47 1 1
+77 10 10
+186 1 1
+24 1 1
+1140 1 0
+214 1 1
+34 1 1
+89 1 1
+36 1 1
+288 0 1
+544 0 331
+320 1 0
+199 1 1
+16 1 1
+112 1 1
+29 1 1
+783 0 3
+311 1 1
+38 1 1
+59 1 1
+68 1 1
+52 1 1
+98 1 1
+166 7 7
+698 1 1
+68 1 1
+165 0 1
+114 1 1
+92 0 1
+14 1 1
+215 1 1
+81 1 1
+792 1 1
+31 1 1
+54 1 1
+44 1 1
+179 1 1
+26 1 1
+200 1 1
+30 1 1
+639 7 7
+505 40 42
+549 12 0
+19 1 1
+2184 1 0
+840 1 1
+69 1 1
+966 21 21
+33 12 0
+56 1 1
+94 1 1
+237 11 9
+189 1 1
+47 1 1
+318 3 0
+80 1 1
+94 5 1
+32 1 1
+126 16 16
+83 1 1
+47 1 1
+104 6 5
+56 1 1
+68 1 1
+417 12 13
+636 0 2
+30 1 1
+694 0 4
+95 1 1
+28 1 1
+1358 1 1
+19 1 1
+68 1 1
+97 1 1
+155 15 15
+323 1 7
+158 2 0
+42 6 0
+59 1 1
+314 14 14
+94 1 1
+64 1 1
+637 1 1
+21 1 1
+144 2 1
+229 11 5
+410 1 1
+96 1 1
+272 1 1
+22 1 1
+118 1 1
+44 1 1
+96 1 1
+48 1 1
+414 22 22
+373 13 13
+554 1 1
+87 10 0
+313 1 1
+37 1 1
+122 17 18
+179 1 1
+40 1 1
+591 8 8
+129 1 0
+70 1 1
+71 1 0
+73 10 6
+12 1 1
+203 0 6
+24 2 0
+45 4 0
+46 1 1
+186 9 9
+87 1 1
+28 1 1
+3625 0 1
+71 1 1
+126 1 1
+34 1 1
+532 0 2
+696 2 0
+555 1 7
+287 1 1
+30 0 3
+946 0 1
+88 1 1
+60 12 0
+12546 1 1
+37 1 0
+2071 0 1
+1253 9 9
+2003 0 1
+24677 0 2
+6212 1 1
+26 1 1
+816 0 4
+13602 18 15
+2375 2 0
+1957 2 0
+2394 6 0
+1561 0 1
+2805 4 0
+12333 8 0
+835 0 1
+426 0 27
+12156 0 18
+6903 2 0
+21807 3 0
+1588 1 0
+2605 1 1
+23 1 1
+11252 8 0
+298 6 7
+946 2 0
+232 0 1
+501 1 0
+4748 0 4
+770 0 7
+914 0 1
+295 1 0
+214 3 0
+121 0 1
+784 0 1
+2512 0 1
+4476 3 0
+926 0 1
+189 2 0
+3543 2 0
+893 1 1
+46 1 1
+1296 0 1
+153 0 1
+336 5 0
+228 1 1
+45 1 1
+207 3 0
+322 0 1
+658 1 0
+1516 3 0
+1025 0 13
+1518 0 1
+591 10 10
+3384 0 2
+182 12 0
+328 1 0
+301 0 1
+994 1 1
+18 0 6
+1743 0 1
+2350 22 23
+1548 0 7
+1976 1 0
+199 0 1
+5922 12 12
+873 0 3
+3080 12 8
+322 1 0
+490 1 0
+3602 1 0
+482 1 0
+3178 1 0
+5157 0 10
+753 0 1
+885 20 0
+1746 10 0
+4045 6 1
+3520 5 13
+2048 0 1
+3529
+
+chain 323865 chr6_cox_hap1 4731698 + 1267152 1270823 12 133851895 - 763369 785145 206180
+2772 0 815
+201 0 17291
+643 1 0
+54
+
+chain 65284 chr6_cox_hap1 4731698 + 2460102 2460796 6 171115067 - 140105134 140105832 1936071
+178 0 4
+516
+
+chain 59092 chr6_cox_hap1 4731698 + 4004481 4005101 4 191154276 + 48364786 48365406 2142970
+620
+
+chain 52987 chr6_cox_hap1 4731698 + 2674042 2675969 3 198022430 - 151830192 151832103 2402006
+102 557 556
+77 395 393
+169 221 221
+81 15 15
+81 35 35
+55 44 31
+95
+
+chain 40067 chr6_cox_hap1 4731698 + 3843208 3843655 1 249250621 - 189436883 189437330 3283815
+379 3 3
+65
+
+chain 34258 chr6_cox_hap1 4731698 + 2746095 2746514 X 155270560 - 17905933 17906346 3956727
+73 15 15
+155 1 1
+20 6 0
+17 1 1
+131
+
+chain 30865 chr6_cox_hap1 4731698 + 3996373 3996892 6 171115067 + 32713281 32713770 4500603
+73 89 59
+184 77 77
+96
+
+chain 30808 chr6_cox_hap1 4731698 + 1446736 1447059 11 135006516 - 73898390 73898713 4511271
+323
+
+chain 29563 chr6_cox_hap1 4731698 + 4089902 4090211 1 249250621 - 75305559 75305868 4853755
+309
+
+chain 29490 chr6_cox_hap1 4731698 + 3888227 3888535 20 63025520 - 21266962 21267270 4884719
+308
+
+chain 23990 chr6_cox_hap1 4731698 + 1313393 1314169 7 159138663 - 51241795 51242737 7706852
+178 101 101
+72 385 551
+40
+
+chain 19279 chr6_cox_hap1 4731698 + 2759716 2759948 5 180915260 + 25289600 25289832 11061062
+91 17 17
+124
+
+chain 18106 chr6_cox_hap1 4731698 + 3844292 3845362 7 159138663 + 50640514 50641583 3599691
+33 446 444
+74 250 251
+5 55 55
+48 69 69
+90
+
+chain 17763 chr6_cox_hap1 4731698 + 3840247 3840451 6 171115067 - 2083149 2083361 12325354
+52 0 8
+26 2 2
+124
+
+chain 17263 chr6_cox_hap1 4731698 + 3890221 3890428 4 191154276 + 3927369 3927573 12785973
+50 3 0
+26 4 4
+124
+
+chain 16283 chr6_cox_hap1 4731698 + 3267732 3267909 2 243199373 + 128545205 128545381 580296
+28 2 1
+147
+
+chain 16000 chr6_cox_hap1 4731698 + 3842640 3845155 5 180915260 - 144997615 145000132 3598025
+127 1430 1431
+95 205 207
+98 29 29
+57 419 418
+55
+
+chain 15874 chr6_cox_hap1 4731698 + 2744265 2744697 6 171115067 + 31304784 31305225 14156555
+58 158 158
+72 76 85
+68
+
+chain 15671 chr6_cox_hap1 4731698 + 1306242 1307477 6 171115067 - 139875690 139876935 14366990
+56 408 416
+54 620 622
+97
+
+chain 15351 chr6_cox_hap1 4731698 + 2791400 2791601 11 135006516 + 74748600 74748801 14697621
+99 26 26
+76
+
+chain 14920 chr6_cox_hap1 4731698 + 2791114 2791352 12 133851895 + 56894984 56895263 15150280
+65 69 110
+104
+
+chain 14203 chr6_cox_hap1 4731698 + 4000567 4000717 6 171115067 - 148948255 148948405 15963295
+150
+
+chain 14065 chr6_cox_hap1 4731698 + 3901987 3902139 6 171115067 - 138602057 138602209 16122340
+152
+
+chain 13939 chr6_cox_hap1 4731698 + 2790912 2791061 15 102531392 - 60147333 60147482 16276423
+149
+
+chain 13590 chr6_cox_hap1 4731698 + 4000399 4000543 2 243199373 + 178345068 178345212 16711221
+144
+
+chain 13240 chr6_cox_hap1 4731698 + 3909742 3911000 6 171115067 + 32548108 32549235 17164167
+52 422 421
+78 652 522
+54
+
+chain 12556 chr6_cox_hap1 4731698 + 1348680 1348819 2 243199373 - 184149574 184149713 18162971
+139
+
+chain 12225 chr6_cox_hap1 4731698 + 3890501 3890631 13 115169878 - 44980182 44980312 18662730
+130
+
+chain 12178 chr6_cox_hap1 4731698 + 3972449 3972615 14 107349540 - 58393926 58394091 18734378
+55 26 25
+85
+
+chain 12008 chr6_cox_hap1 4731698 + 3896810 3896939 8 146364022 + 49154427 49154556 18990652
+129
+
+chain 11746 chr6_cox_hap1 4731698 + 1299553 1299701 7 159138663 - 7702899 7703047 19437477
+54 14 14
+80
+
+chain 11718 chr6_cox_hap1 4731698 + 299537 299697 13 115169878 + 54026210 54026329 7331663
+62 41 0
+40 13 13
+4
+
+chain 11503 chr6_cox_hap1 4731698 + 3894886 3895312 11 135006516 - 111045874 111046295 19852909
+57 287 282
+82
+
+chain 11377 chr6_cox_hap1 4731698 + 3840583 3840825 11 135006516 + 57049649 57049891 20071170
+62 107 107
+73
+
+chain 10960 chr6_cox_hap1 4731698 + 3841022 3841165 12 133851895 - 49356794 49356937 20822626
+50 15 15
+78
+
+chain 10867 chr6_cox_hap1 4731698 + 2681465 2681622 6 171115067 - 132617434 132617597 20998653
+55 29 35
+73
+
+chain 10738 chr6_cox_hap1 4731698 + 3896518 3896639 10 135534747 + 59600699 59600817 21255898
+61 3 0
+57
+
+chain 10496 chr6_cox_hap1 4731698 + 3892569 3892679 1 249250621 - 174039531 174039641 21744607
+110
+
+chain 10328 chr6_cox_hap1 4731698 + 3840451 3840892 4 191154276 - 114078209 114078650 18698120
+15 372 372
+54
+
+chain 9881 chr6_cox_hap1 4731698 + 2734004 2734554 6 171115067 + 31205448 31206008 23100546
+72 423 433
+55
+
+chain 9755 chr6_cox_hap1 4731698 + 4021493 4021793 6 171115067 + 162490109 162490409 23390927
+65 181 181
+54
+
+chain 9560 chr6_cox_hap1 4731698 + 1301303 1301404 6 171115067 - 141323187 141323288 23857061
+101
+
+chain 9455 chr6_cox_hap1 4731698 + 3891953 3892158 6 171115067 + 32468923 32469135 24116909
+54 91 98
+60
+
+chain 9090 chr6_cox_hap1 4731698 + 2680711 2680821 3 198022430 - 94212956 94213066 24807216
+53 4 4
+53
+
+chain 7297 chr6_cox_hap1 4731698 + 3844000 3844124 8 146364022 + 96809146 96809270 3974525
+124
+
+chain 7162 chr6_cox_hap1 4731698 + 2675969 2676329 17 81195210 - 22005566 22005927 2836104
+7 302 303
+51
+
+chain 7031 chr6_cox_hap1 4731698 + 2673410 2673921 5 180915260 + 106108094 106108601 3265511
+58 376 372
+77
+
+chain 6840 chr6_cox_hap1 4731698 + 3971466 3971538 11 135006516 + 40011829 40011901 28544257
+72
+
+chain 6473 chr6_cox_hap1 4731698 + 3890669 3890742 1 249250621 - 102907635 102907704 21815173
+11 4 0
+58
+
+chain 6422 chr6_cox_hap1 4731698 + 4013834 4013902 6 171115067 + 32728707 32728775 29535230
+68
+
+chain 5921 chr6_cox_hap1 4731698 + 2681183 2681245 4 191154276 - 94306644 94306706 30842389
+62
+
+chain 5676 chr6_cox_hap1 4731698 + 2671999 2672059 3 198022430 + 95260601 95260661 31509897
+60
+
+chain 5595 chr6_cox_hap1 4731698 + 3972615 3972674 14 107349540 - 80191032 80191091 27115653
+59
+
+chain 5576 chr6_cox_hap1 4731698 + 1302171 1302230 18 78077248 - 3698437 3698496 31796878
+59
+
+chain 5517 chr6_cox_hap1 4731698 + 3842389 3842453 20 63025520 - 5368566 5368630 20848663
+64
+
+chain 5458 chr6_cox_hap1 4731698 + 3985007 3985065 2 243199373 + 112827415 112827473 32167738
+58
+
+chain 5421 chr6_cox_hap1 4731698 + 2677334 2677391 19 59128983 - 38462903 38462960 32247802
+57
+
+chain 5403 chr6_cox_hap1 4731698 + 3897499 3897556 12 133851895 + 59864980 59865037 32286341
+57
+
+chain 5339 chr6_cox_hap1 4731698 + 4081817 4081873 17 81195210 + 16805661 16805717 32499905
+56
+
+chain 5266 chr6_cox_hap1 4731698 + 4021149 4021204 3 198022430 + 6923000 6923055 32744278
+55
+
+chain 5103 chr6_cox_hap1 4731698 + 2743431 2743485 3 198022430 + 27241143 27241197 33231446
+54
+
+chain 5094 chr6_cox_hap1 4731698 + 3984745 3984799 6 171115067 + 67966752 67966806 33279729
+54
+
+chain 5089 chr6_cox_hap1 4731698 + 2674314 2675775 1 249250621 + 7474130 7475590 2473669
+98 975 974
+58 295 295
+35
+
+chain 5076 chr6_cox_hap1 4731698 + 1300901 1300955 11 135006516 + 101518151 101518205 33343005
+54
+
+chain 5067 chr6_cox_hap1 4731698 + 2741303 2741357 19 59128983 - 37393851 37393905 33368570
+54
+
+chain 5058 chr6_cox_hap1 4731698 + 3967166 3967220 1 249250621 - 172942963 172943017 33379585
+54
+
+chain 5020 chr6_cox_hap1 4731698 + 1345886 1345938 6 171115067 + 29692684 29692736 33527644
+52
+
+chain 4959 chr6_cox_hap1 4731698 + 3892516 3892569 18 78077248 + 5090594 5090647 22176918
+53
+
+chain 4957 chr6_cox_hap1 4731698 + 2678048 2678100 9 141213431 - 31846047 31846099 33735026
+52
+
+chain 4957 chr6_cox_hap1 4731698 + 3946024 3946076 6 171115067 + 32439356 32439408 33735182
+52
+
+chain 4930 chr6_cox_hap1 4731698 + 3894496 3894548 X 155270560 - 4541772 4541824 33815607
+52
+
+chain 4914 chr6_cox_hap1 4731698 + 2673741 2673793 X 155270560 + 7935883 7935935 17711968
+52
+
+chain 4885 chr6_cox_hap1 4731698 + 2740950 2741002 5 180915260 - 163072859 163072911 33995114
+52
+
+chain 4884 chr6_cox_hap1 4731698 + 2760326 2760379 7 159138663 + 8699184 8699237 23141527
+53
+
+chain 4821 chr6_cox_hap1 4731698 + 3935381 3935432 6 171115067 - 11031703 11031754 34213824
+51
+
+chain 4685 chr6_cox_hap1 4731698 + 3915703 3915753 12 133851895 + 112261417 112261467 34690968
+50
+
+chain 4613 chr6_cox_hap1 4731698 + 2844682 2846505 13 115169878 - 41386504 41386960 3856143
+33 479 279
+7 46 0
+24 11 0
+33 1097 0
+24 13 0
+56
+
+chain 4221 chr6_cox_hap1 4731698 + 2437589 2437671 14 107349540 + 75461679 75461839 4623812
+28 0 78
+54
+
+chain 4202 chr6_cox_hap1 4731698 + 2673968 2674023 3 198022430 + 156309398 156309453 19139889
+55
+
+chain 4186 chr6_cox_hap1 4731698 + 3955813 3955860 5 180915260 - 113986983 113987030 34971958
+47
+
+chain 4136 chr6_cox_hap1 4731698 + 2672610 2672662 13 115169878 + 42049101 42049153 23521137
+52
+
+chain 3978 chr6_cox_hap1 4731698 + 2673481 2673609 X 155270560 - 130914483 130914611 4485241
+128
+
+chain 3891 chr6_cox_hap1 4731698 + 2760039 2760115 16 90354753 - 58442153 58442229 17002345
+76
+
+chain 3877 chr6_cox_hap1 4731698 + 2672485 2672526 15 102531392 + 40275232 40275273 21164310
+41
+
+chain 3776 chr6_cox_hap1 4731698 + 2759549 2759589 1 249250621 - 143888892 143888932 33598889
+40
+
+chain 3639 chr6_cox_hap1 4731698 + 3890631 3890669 3 198022430 + 101411146 101411184 20382394
+38
+
+chain 3574 chr6_cox_hap1 4731698 + 2673146 2673184 3 198022430 - 173409162 173409200 29596627
+38
+
+chain 3573 chr6_cox_hap1 4731698 + 2790788 2791088 16 90354753 + 31183111 31183406 18086604
+58 215 210
+27
+
+chain 3489 chr6_cox_hap1 4731698 + 3842885 3842952 X 155270560 - 48144545 48144612 19043441
+67
+
+chain 3394 chr6_cox_hap1 4731698 + 3896482 3896518 X 155270560 - 4545757 4545793 28280414
+36
+
+chain 3393 chr6_cox_hap1 4731698 + 3840688 3840752 8 146364022 + 7016797 7016861 21522443
+64
+
+chain 3345 chr6_cox_hap1 4731698 + 1313572 1313633 X 155270560 - 101738888 101738949 11083842
+61
+
+chain 3209 chr6_cox_hap1 4731698 + 3842526 3842560 4 191154276 + 80147803 80147837 32673071
+34
+
+chain 3189 chr6_cox_hap1 4731698 + 2790872 2790912 11 135006516 - 131957088 131957128 22905486
+40
+
+chain 3053 chr6_cox_hap1 4731698 + 4021558 4021590 2 243199373 + 38182694 38182726 24706669
+32
+
+chain 3045 chr6_cox_hap1 4731698 + 2677533 2677565 11 135006516 - 20509488 20509520 33762261
+32
+
+chain 3033 chr6_cox_hap1 4731698 + 3842991 3843062 1 249250621 - 90164672 90164743 11203780
+71
+
+chain 2997 chr6_cox_hap1 4731698 + 2759644 2759694 16 90354753 + 47212776 47212826 11278440
+50
+
+chain 2984 chr6_cox_hap1 4731698 + 3842575 3842625 X 155270560 + 76422698 76422748 20248077
+50
+
+chain 2960 chr6_cox_hap1 4731698 + 3896779 3896810 21 48129895 + 18677639 18677670 32477029
+31
+
+chain 2845 chr6_cox_hap1 4731698 + 2673184 2673214 3 198022430 - 156603737 156603767 26791325
+30
+
+chain 2761 chr6_cox_hap1 4731698 + 3844406 3844465 6 171115067 + 18547856 18547915 4276868
+59
+
+chain 2745 chr6_cox_hap1 4731698 + 3842326 3844197 11 135006516 - 48638733 48640605 3968835
+61 675 676
+53 1015 1015
+67
+
+chain 2739 chr6_cox_hap1 4731698 + 2673924 2673968 8 146364022 + 90457478 90457522 20607564
+44
+
+chain 2729 chr6_cox_hap1 4731698 + 1302230 1302259 14 107349540 + 79349511 79349540 33029767
+29
+
+chain 2723 chr6_cox_hap1 4731698 + 2673793 2673825 5 180915260 - 70673106 70673138 18877917
+32
+
+chain 2561 chr6_cox_hap1 4731698 + 299599 299640 6 171115067 + 20244702 20244743 12574490
+41
+
+chain 2518 chr6_cox_hap1 4731698 + 4021649 4021704 16 90354753 - 20685134 20685189 24272036
+55
+
+chain 2470 chr6_cox_hap1 4731698 + 2745980 2746030 1 249250621 + 111776293 111776343 7607561
+50
+
+chain 2373 chr6_cox_hap1 4731698 + 2760156 2760181 17 81195210 - 66761411 66761436 17362234
+25
+
+chain 2319 chr6_cox_hap1 4731698 + 2900811 2900837 6 171115067 + 31357660 31357686 3303778
+26
+
+chain 2312 chr6_cox_hap1 4731698 + 2759490 2759549 4 191154276 + 98204882 98204941 18366184
+59
+
+chain 2209 chr6_cox_hap1 4731698 + 3843799 3843896 12 133851895 + 60159606 60159703 5400255
+97
+
+chain 2146 chr6_cox_hap1 4731698 + 1299766 1299827 12 133851895 + 105697047 105697108 23835468
+61
+
+chain 2140 chr6_cox_hap1 4731698 + 3840491 3840558 6 171115067 - 96829007 96829074 20827044
+67
+
+chain 2000 chr6_cox_hap1 4731698 + 1313744 1313777 4 191154276 + 153686345 153686378 8134925
+33
+
+chain 1995 chr6_cox_hap1 4731698 + 3842817 3842864 4 191154276 - 47817470 47817517 17212566
+47
+
+chain 1991 chr6_cox_hap1 4731698 + 2845315 2845345 4 191154276 - 30046978 30047008 15284842
+30
+
+chain 1990 chr6_cox_hap1 4731698 + 4008195 4011710 6 171115067 + 32722816 32726965 28700009
+61 2506 2690
+85 515 965
+52 103 103
+193
+
+chain 1943 chr6_cox_hap1 4731698 + 3844851 3845272 11 135006516 + 83226111 83226530 3906185
+58 323 321
+40
+
+chain 1927 chr6_cox_hap1 4731698 + 2759609 2759644 7 159138663 - 110094552 110094587 24531071
+35
+
+chain 1727 chr6_cox_hap1 4731698 + 2674522 2674583 20 63025520 - 53185733 53185794 4777998
+61
+
+chain 1671 chr6_cox_hap1 4731698 + 3843897 3843947 9 141213431 + 78317603 78317653 4355881
+50
+
+chain 1637 chr6_cox_hap1 4731698 + 2760272 2760326 2 243199373 + 119859185 119859239 11695157
+54
+
+chain 1632 chr6_cox_hap1 4731698 + 2673214 2673313 4 191154276 - 69486891 69486990 2834158
+99
+
+chain 1628 chr6_cox_hap1 4731698 + 3842952 3842991 2 243199373 - 116273698 116273737 14990340
+39
+
+chain 1584 chr6_cox_hap1 4731698 + 1313851 1313915 1 249250621 - 24961912 24961976 17607390
+64
+
+chain 1548 chr6_cox_hap1 4731698 + 2672923 2673038 2 243199373 - 193655574 193655689 3516324
+115
+
+chain 1509 chr6_cox_hap1 4731698 + 2674838 2674895 5 180915260 + 165569524 165569581 2491813
+57
+
+chain 1508 chr6_cox_hap1 4731698 + 2675985 2676708 6 171115067 - 141365359 141366083 3289535
+50 615 616
+58
+
+chain 1507 chr6_cox_hap1 4731698 + 2673661 2673741 4 191154276 + 138835824 138835904 16168846
+80
+
+chain 1489 chr6_cox_hap1 4731698 + 2845209 2846585 X 155270560 - 102215688 102216455 6549884
+27 1297 452
+2 0 236
+50
+
+chain 1467 chr6_cox_hap1 4731698 + 2760221 2760272 7 159138663 + 122232756 122232807 13147168
+51
+
+chain 1456 chr6_cox_hap1 4731698 + 3844931 3844983 14 107349540 + 48881293 48881345 9320615
+52
+
+chain 1452 chr6_cox_hap1 4731698 + 2673321 2674838 X 155270560 - 1098426 1099942 3000529
+51 1428 1427
+38
+
+chain 1354 chr6_cox_hap1 4731698 + 1313967 1314021 4 191154276 + 544307 544361 14282164
+54
+
+chain 1310 chr6_cox_hap1 4731698 + 3843714 3843782 X 155270560 + 17249549 17249617 3972308
+68
+
+chain 1307 chr6_cox_hap1 4731698 + 1498573 1498607 5 180915260 - 156542608 156542642 2089959
+34
+
+chain 1294 chr6_cox_hap1 4731698 + 2760418 2760473 4 191154276 + 147516497 147516552 12285122
+55
+
+chain 1278 chr6_cox_hap1 4731698 + 3845015 3845082 15 102531392 + 92125438 92125505 4023305
+67
+
+chain 1247 chr6_cox_hap1 4731698 + 3844702 3844748 2 243199373 - 7511493 7511539 13743690
+46
+
+chain 1194 chr6_cox_hap1 4731698 + 2676043 2676103 1 249250621 + 94380187 94380247 20995710
+60
+
+chain 1160 chr6_cox_hap1 4731698 + 2676209 2676237 X 155270560 + 56836392 56836420 21177535
+28
+
+chain 1125 chr6_cox_hap1 4731698 + 3890818 3890886 8 146364022 - 86779351 86779419 20749389
+68
+
+chain 1106 chr6_cox_hap1 4731698 + 2760181 2760221 9 141213431 + 74027839 74027879 13331514
+40
+
+chain 1039 chr6_cox_hap1 4731698 + 2674441 2674507 3 198022430 - 71498815 71498881 4421669
+66
+
+chain 1033 chr6_cox_hap1 4731698 + 2676372 2676431 5 180915260 - 20894072 20894131 3124143
+59
+
+chain 1014 chr6_cox_hap1 4731698 + 2759961 2759990 10 135534747 + 69125589 69125618 23828230
+29
+
+chain 1005 chr6_cox_hap1 4731698 + 2760005 2760039 10 135534747 + 5299750 5299784 23898321
+34
+
+chain 982 chr6_cox_hap1 4731698 + 2759426 2759479 13 115169878 + 111326976 111327029 14386536
+53
+
+chain 977 chr6_cox_hap1 4731698 + 3845410 3845467 X 155270560 - 144584413 144584470 4043690
+57
+
+chain 963 chr6_cox_hap1 4731698 + 2674253 2676589 9 141213431 - 119032541 119034846 4479982
+47 2231 2200
+58
+
+chain 919 chr6_cox_hap1 4731698 + 2677255 2677315 4 191154276 + 45112377 45112437 22402156
+60
+
+chain 883 chr6_cox_hap1 4731698 + 3843656 3843714 18 78077248 + 28929278 28929336 6530663
+58
+
+chain 881 chr6_cox_hap1 4731698 + 2675038 2675098 5 180915260 - 79225133 79225193 14536118
+60
+
+chain 858 chr6_cox_hap1 4731698 + 2676338 2676372 7 159138663 - 148564023 148564057 6699557
+34
+
+chain 857 chr6_cox_hap1 4731698 + 2676103 2677646 4 191154276 + 171430336 171431860 18546235
+50 1412 1393
+81
+
+chain 838 chr6_cox_hap1 4731698 + 3843947 3843980 18 78077248 - 28720814 28720847 7914761
+33
+
+chain 819 chr6_cox_hap1 4731698 + 2673062 2673118 2 243199373 + 149156283 149156339 14209631
+56
+
+chain 796 chr6_cox_hap1 4731698 + 1314021 1314060 X 155270560 - 10752795 10752834 16687246
+39
+
+chain 747 chr6_cox_hap1 4731698 + 1314275 1314339 12 133851895 + 57178267 57178331 20664563
+64
+
+chain 731 chr6_cox_hap1 4731698 + 1638596 1638636 15 102531392 + 55738847 55738887 18753864
+40
+
+chain 704 chr6_cox_hap1 4731698 + 3842767 3842817 9 141213431 + 32212289 32212339 4117535
+50
+
+chain 701 chr6_cox_hap1 4731698 + 2674653 2674701 16 90354753 - 23821388 23821436 3556080
+48
+
+chain 679 chr6_cox_hap1 4731698 + 1313640 1313672 21 48129895 - 2887431 2887463 13569070
+32
+
+chain 672 chr6_cox_hap1 4731698 + 3844325 3844357 10 135534747 - 103351577 103351609 5595826
+32
+
+chain 661 chr6_cox_hap1 4731698 + 2676159 2676209 9 141213431 + 85388422 85388472 5334226
+50
+
+chain 661 chr6_cox_hap1 4731698 + 3844987 3845015 2 243199373 + 98215178 98215206 5611311
+28
+
+chain 650 chr6_cox_hap1 4731698 + 2672375 2672435 7 159138663 - 140047518 140047578 22707410
+60
+
+chain 643 chr6_cox_hap1 4731698 + 2677085 2677144 6 171115067 + 74793831 74793890 5895430
+59
+
+chain 604 chr6_cox_hap1 4731698 + 1314169 1314195 X 155270560 - 101522169 101522195 11588450
+26
+
+chain 595 chr6_cox_hap1 4731698 + 2675343 2675387 12 133851895 - 110550302 110550346 3606052
+44
+
+chain 571 chr6_cox_hap1 4731698 + 2672827 2672901 3 198022430 + 50956018 50956092 15278850
+74
+
+chain 525 chr6_cox_hap1 4731698 + 3902955 3903021 6 171115067 + 32474022 32474088 26162225
+66
+
+chain 485 chr6_cox_hap1 4731698 + 2671938 2671998 1 249250621 - 193322919 193322979 8312425
+60
+
+chain 412 chr6_cox_hap1 4731698 + 2672740 2672827 8 146364022 - 113140827 113140914 13566503
+87
+
+chain 395 chr6_cox_hap1 4731698 + 2846505 2846533 X 155270560 - 102216470 102216498 6380381
+28
+
+chain 395 chr6_cox_hap1 4731698 + 2675098 2675125 12 133851895 + 9999203 9999230 23891782
+27
+
+chain 347 chr6_cox_hap1 4731698 + 2671704 2671754 15 102531392 - 65978487 65978537 12839282
+50
+
+chain 251 chr6_cox_hap1 4731698 + 2671761 2671812 9 141213431 + 17677697 17677748 27279073
+51
+
+chain 184 chr6_cox_hap1 4731698 + 2672526 2672587 X 155270560 - 91681431 91681492 16167874
+61
+
+chain 369716150 chr6_qbl_hap2 4565931 + 0 4565931 6 171115067 + 28742641 33379750 32
+2350 0 1
+1750 0 2
+3815 1 0
+9743 0 2
+3960 0 4
+2109 0 2
+33 2 0
+9000 0 2
+16647 0 2
+38786 1 0
+80529 0 1
+14475 0 1
+6819 1 0
+6845 1 3
+6188 0 1
+6397 0 1
+345 1 0
+68374 2 0
+39133 39 39
+7774 7 0
+1489 1 1
+72 1 1
+2260 0 2
+10629 0 1
+1249 1 1
+195 1 1
+18132 0 1
+1324 0 2
+5438 5 0
+2061 1 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4235 18 18
+493 9 9
+4767 7 7
+1225 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+281 11 11
+1178 0 4
+685 8 0
+48 4 0
+1701 1 1
+43 5 5
+862 18 18
+58 1 1
+66 1 1
+420 1 1
+44 1 1
+680 4 4
+1675 1 1
+83 1 1
+3082 4 0
+5467 1 1
+27 0 1
+1099 16 0
+627 51 51
+1278 6 1
+129 1 1
+25 1 1
+1397 15 15
+810 1 1
+27 1 1
+1192 2 0
+7515 4 0
+979 0 3
+3406 0 2
+2340 1 1
+20 1 1
+1139 1 1
+26 1 1
+787 0 1
+1416 3 1
+22815 4 4
+126 1 0
+38 1 1
+140 1 0
+999 0 17
+56 0 15
+11759 161391 161513
+11155 0 2
+5376 0 1
+19253 1 0
+4212 1 1
+3671 1 0
+21 0 6
+4451 1 0
+27910 1 0
+9946 0 1
+11233 1 1
+32 1 1
+2238 1 1
+20 1 1
+3659 22 16
+1218 1 0
+1638 6 6
+228 1 1
+45 1 1
+2048 0 3
+461 1 0
+20759 1 0
+3778 2 1
+1268 1 0
+1511 1 1
+42 2 0
+24 1 1
+4119 22 0
+1757 1 0
+1527 1 1
+29 1 1
+1886 1 0
+10628 12 0
+46568 1 0
+18985 0 10
+1825 3 4
+5288 0 9
+1071 50 50
+1607 1 5
+722 0 1
+502 0 1
+1025 0 1
+134 14 0
+4944 0 1
+319 1 0
+6178 0 1
+2898 0 2
+143 0 1
+1775 1 0
+2123 0 1
+2715 1 0
+4901 70 66
+2884 1 0
+1362 1 0
+1233 0 8
+2134 0 1
+1042 0 1
+163 1 1
+45 1 1
+50 2 0
+64 1 1
+48 1 1
+380 0 1
+30 1 0
+30 1 1
+61 1 1
+22 1 1
+368 4 4
+319 5 7
+310 1 1
+37 3 1
+162 1 1
+194 2 0
+36 1 1
+242 9 9
+1932 1 1
+16 1 1
+528 1 1
+20 1 1
+509 0 5
+76 1 1
+21 1 1
+439 15 15
+2779 1 0
+1597 24 28
+59 12 12
+307 1 0
+516 1 0
+286 11 33
+339 5 0
+570 1 1
+37 1 1
+220 1 0
+72 1 1
+144 1 1
+48 1 1
+247 2 0
+174 9 10
+816 1 0
+940 1 1
+45 1 1
+91 3 3
+71 1 1
+291 14 14
+100 1 1
+23 1 1
+452 3 3
+85 1 1
+65 1 1
+77 1 1
+252 0 1
+129 15 15
+432 10 0
+85 1 1
+28 1 1
+189 2 1
+71 1 1
+52 8 0
+810 2 2
+63 1 1
+378 1 1
+26 1 1
+187 31 36
+966 1 1
+25 1 1
+91 12 12
+125 1 1
+38 1 1
+433 2 0
+596 1 1
+48 1 1
+465 4 4
+64 1 1
+20 1 1
+525 5 5
+237 3 8
+183 11 0
+364 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+67 16 16
+244 1 1
+54 5 5
+929 1 1
+21 1 1
+126 0 3
+830 1 11
+59 1 1
+537 0 2
+24 1 1
+745 15 15
+810 1 0
+425 1 1
+89 1 1
+592 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 41 41
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+155 155 0
+34 1 1
+50 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+345 1 1
+39 1 1
+504 18 18
+596 12 12
+54 1 1
+158 1 1
+164 1 1
+34 1 1
+626 15 15
+866 0 10
+1051 0 2611
+680 0 1
+1537 0 18
+75 1 0
+147 52 1
+119 0 12
+23 1 1
+1927 13 13
+1702 2 0
+3694 1 1
+18 1 1
+958 43 47
+246 2 0
+146 1 1
+49 1 1
+410 1 0
+667 1 1
+38 1 1
+362 7 1
+159 2 0
+515 2 0
+1026 1 1
+29 1 1
+249 0 6
+129 1 1
+33 4 0
+10 1 5
+1236 1 1
+20 1 1
+138 10 9
+448 0 3
+660 1 1
+28 1 1
+83 1 1
+51 1 1
+2659 1 1
+38 1 1
+424 0 1
+70 1 1
+820 1 1
+26 1 1
+1472 1 1
+21 1 1
+491 5 5
+2372 2 0
+533 6 0
+441 1 7
+1689 1 1
+26 3 4
+879 16 16
+514 0 2
+58 1 1
+350 1 0
+769 1 1
+39 1 1
+429 10 10
+134 0 4
+37 1 1
+144 8 8
+668 1 1
+22 1 1
+344 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+198 0 1
+32 1 1
+74 11 15
+1255 0 2
+332 1 1
+21 1 1
+193 8 24
+34 1 1
+79 1 1
+29 1 1
+536 1 0
+308 0 1
+850 0 32
+23 1 1
+651 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 2
+713 7 7
+89 1 0
+293 9 8
+125 1 1
+31 1 1
+192 6 6
+171 17 17
+681 1 1
+43 1 1
+514 1 1
+68 1 1
+537 1 1
+35 1 1
+159 6 6
+778 2 2
+44 1 1
+168 0 7
+211 1 1
+42 1 1
+1253 1 1
+29 1 1
+320 1 1
+36 2 2
+55 1 2
+108 1 1
+33 1 1
+317 1 1
+35 1 1
+553 8 8
+386 1 1
+26 1 1
+540 1 1
+31 1 1
+65 0 1
+625 12 12
+313 0 1
+52 1 1
+22 1 1
+583 1 1
+49 1 1
+678 37 37
+784 3 0
+838 1 1
+19 12 0
+1129 1 1
+36 1 1
+553 8 8
+109 1 1
+45 1 1
+841 16 15
+157 1 1
+31 2 2
+204 18 19
+487 1 1
+29 1 1
+374 1 1
+67 1 1
+720 13 13
+266 10 10
+330 16 14
+413 1 1
+44 1 1
+78 6 6
+181 2 2
+36 1 1
+397 1 1
+20 1 1
+311 1 1
+48 2 2
+1298 11 11
+186 1 1
+33 1 1
+216 4 4
+35 1 1
+194 10 10
+310 1 1
+51 1 1
+136 1 1
+49 1 1
+521 1 1
+23 1 1
+242 1 1
+49 1 1
+600 1 1
+31 1 1
+413 15 15
+290 1 1
+49 1 1
+527 17 17
+340 12 11
+1025 1 0
+2572 1 1
+29 1 1
+397 2 5
+668 13 13
+541 1 1
+59 0 2
+6 1 1
+122 14 14
+51 1 1
+46 1 1
+72 5 5
+110 1 1
+76 1 1
+164 0 21
+136 1 1
+12 1 1
+66 16 16
+456 37 34
+371 7 7
+48 1 1
+194 10 10
+108 1 1
+60 1 1
+122 0 1
+48 1 1
+238 1 1
+32 0 1
+100 1 0
+72 1 0
+390 1 1
+38 1 1
+144 1 1
+27 0 4
+184 21 228
+49 1 1
+608 0 1
+152 1 1
+31 1 1
+281 8 8
+337 1 1
+45 1 1
+222 1 1
+54 1 1
+346 1 0
+44 1 1
+368 1 1
+72 1 1
+502 36 18
+63 1 1
+43 0 4
+136 1 1
+42 1 1
+80 4 4
+35 1 0
+89 1 1
+24 0 5
+829 13 13
+73 1 1
+28 14 0
+233 1 1
+42 0 3
+85 0 1
+400 1 1
+40 1 1
+538 25 25
+174 1 1
+20 1 1
+705 1 1
+26 2 2
+614 1 1
+44 1 1
+793 1 1
+16 1 1
+747 5 5
+804 1 1
+29 1 1
+166 1 1
+43 1 1
+233 1 1
+44 1 1
+507 0 3
+110 8 8
+133 1 1
+31 1 1
+165 1 1
+29 1 1
+1249 1 1
+26 4 0
+56 1 1
+67 1 1
+716 1 1
+46 0 1
+16 1 1
+174 1 1
+96 1 1
+141 1 1
+39 0 4
+263 1 1
+18 1 1
+259 4 4
+38 1 1
+104 1 1
+40 1 0
+248 1 1
+18 1 1
+238 1 1
+32 1 1
+70 0 2
+16 1 1
+818 1 1
+22 4 4
+492 4 4
+1145 1 1
+46 1 1
+53 1 0
+38 1 1
+373 1 1
+60 1 1
+1149 0 1
+20 1 1
+1294 1 1
+41 1 1
+316 4 4
+42 1 1
+218 12 12
+363 1 1
+24 1 1
+457 10 10
+414 13 13
+825 1 1
+41 1 1
+492 0 4
+1374 1 1
+18 1 1
+808 2 2
+335 6 4
+880 1 1
+35 1 1
+236 1 1
+67 1 1
+298 0 1
+147 4 4
+322 11 11
+613 1 1
+62 1 1
+340 1 1
+22 1 1
+1057 1 1
+57 1 1
+358 1 1
+128 1 1
+146 10 10
+490 1 1
+20 1 1
+62 1 1
+88 1 1
+293 1 1
+28 1 0
+20 1 1
+83 0 1
+90 1 1
+312 1 1
+44 1 1
+1213 1 1
+51 1 1
+467 1 1
+39 1 1
+122 14 0
+35 1 1
+485 14 14
+110 12 0
+127 1 1
+5450 0 5
+1699 9 9
+3278 0 2
+28 1 1
+2211 2 0
+521 1 1
+18 1 1
+784 18 18
+1603 0 248
+4769 47 47
+4486 4 4
+103 0 2
+88 1 1
+95 1 1
+2174 1 1
+22 0 1
+1244 7 7
+922 2 0
+1507 1 1
+44 1 1
+208 6 1
+1946 2 2
+85 0 1
+133 1 1
+666 1 0
+52 1 1
+29 1 1
+148 0 5
+30 1 1
+790 14 14
+52 1 1
+32 1 1
+121 1 1
+37 1 1
+396 3 2
+324 1 1
+152 1 1
+71 4 4
+27 1 1
+115 1 1
+101 1 1
+423 10 10
+294 1 1
+101 1 0
+4 0 1
+174 1 1
+146 1 1
+103 1 1
+134 1 1
+16 1 1
+378 1 1
+85 1 1
+134 1 1
+25 1 1
+54 3 3
+55 1 1
+67 1 1
+22 1 1
+54 13 13
+55 11 11
+120 1 1
+23 1 1
+51 1 1
+22 1 1
+364 1 1
+278 1 1
+354 34448 40149
+311 1 1
+33 1 2
+26 6 6
+474 1 1
+36 1 1
+151 1 1
+29 1 1
+120 1 1
+23 1 1
+865 1 1
+39 1 1
+553 1 1
+69 1 1
+116 1 0
+1618 9 9
+820 11 11
+173 0 8
+405 9 9
+196 1 1
+26 1 1
+173 1 1
+27 5 1
+42 1 1
+676 17 19
+77 1 3
+65 16 16
+69 1 0
+277 1 1
+44 1 1
+72 0 3
+70 1 1
+54 1 1
+240 1 0
+31 1 1
+1192 18 19
+454 28 28
+373 1 1
+46 1 1
+1565 1 1
+53 2 2
+543 1 1
+38 1 1
+985 1 1
+27 0 1
+8 1 1
+158 0 38
+656 1 1
+104 1 1
+771 1 1
+21 1 1
+398 1 1
+16 1 2
+163 4 3
+94 1 1
+44 1 1
+172 1 0
+122 5 5
+193 16 16
+535 2 2
+17 1 0
+93 1 1
+580 1 1
+91 1 1
+141 1 1
+79 1 1
+80 13 13
+165 1 1
+129 1 1
+114 1 1
+30 1 1
+83 1 1
+35 1 1
+126 16 16
+270 0 1
+111 9 9
+151 1 1
+118 1 1
+253 1 1
+45 18468 20220
+102 1 1
+20 1 1
+111 1 1
+97 1 0
+86 1 1
+70 0 4
+69 1 1
+52 0 1
+219 3 3
+76 1 5
+209 4 4
+22 1 1
+61 1 1
+91 1 1
+194 0 21
+15 0 1
+229 1 1
+185 0 1
+113 5 5
+45 1 1
+53 1 1
+37 1 1
+157 1 1
+279 1 1
+233 1 1
+19 0 8
+67 2 0
+41 1 1
+102 12 12
+275 14 14
+70 1 1
+82 2 2
+224 5 1
+490 0 22
+3841 1 0
+3216 1 1
+42 1 1
+1914 0 3
+616 11 12
+144 1 1
+21 2 1
+775 1 1
+50 1 1
+50 2 2
+96 2 2
+1522 4 0
+58 0 2
+1099 1 1
+42 1 1
+3502 0 6
+255 1 1
+40 1 1
+150 0 4
+18 1 1
+589 1 1
+37 1 1
+539 5 5
+354 1 3
+128 1 1
+58 1 1
+159 1 1
+5 2 0
+21 1 1
+231 1 1
+82 3 3
+69 3 0
+549 1 1
+69 1 1
+74 9 9
+126 1 1
+47 1 1
+614 9 9
+138 1 1
+29 1 1
+681 1 1
+49 1 1
+67 1 1
+19 4 9
+234 1 1
+93 1 1
+60 4 4
+96 4 4
+76 1 1
+169 1 1
+418 1 1
+130 1 1
+44 1 1
+69 1 1
+80 1 1
+76 1 1
+41 1 1
+129 6 11
+363 1 1
+42 1 1
+295 1 1
+43 1 1
+83 6 0
+52 0 2
+1228 1 1
+34 1 1
+3527 20 0
+1768 2 1
+2467 0 2
+101 10 0
+129 1 1
+37 1 1
+121 1 1
+25 1 1
+161 1 0
+97 1 1
+124 1 0
+178 1 1
+34 1 1
+54 1 1
+38 1 2
+634 83 83
+874 1 1
+40 1 1
+59 0 1
+59 4 4
+316 1 1
+178 1 1
+103 1 1
+61 1 1
+220 1 1
+61 1 1
+296 1 1
+33 1 1
+185 12 12
+269 1 1
+84 1 1
+864 15 15
+241 1 0
+79 3 3
+161 1 1
+48 1 1
+539 1 1
+44 1 1
+357 1 1
+37 1 1
+436 1 1
+59 1 1
+71 1 1
+261 1 1
+289 1 1
+47 1 1
+95 12 12
+97 4 4
+27 1 1
+100 1 1
+16 1 1
+101 1 1
+33 1 2
+481 1 1
+42 1 1
+206 7 7
+56 12 12
+179 10 10
+80 1 1
+41 1 1
+251 1 1
+306 1 1
+80 2 0
+4 94 0
+433 1 1
+23 1 1
+107 1 0
+265 1 1
+49 1 1
+282 72 72
+838 7 7
+60 1 0
+108 1 1
+24 1 1
+134 1 1
+32 1 0
+158 0 2
+1040 1 1
+42 1 1
+737 1 0
+790 1 1
+9 2 1
+11 1 1
+129 1 1
+23 1 1
+894 1 1
+43 3 3
+854 1 1
+23 0 1
+23 2 0
+26 1 1
+395 0 15
+403 5 5
+14 1 1
+2454 1 1
+76 1 1
+170 1 1
+18 1 1
+574 4 0
+291 1 1
+47 1 1
+786 19 0
+88 10 11
+48 1 1
+58 1 1
+28 1 1
+500 0 2
+1280 1 1
+28 1 1
+975 1 0
+3231 1 0
+865 1 1
+39 1 1
+1561 109 100
+1037 0 1
+510 1 1
+49 1 1
+1253 1 1
+19 1 1
+1078 3 0
+221 1 1
+21 1 0
+899 0 4
+466 1 1
+38 1 1
+297 0 3
+730 19 6
+1043 1 1
+49 1 1
+273 0 1
+708 1 0
+364 14 13
+58 1 1
+74 1 1
+614 60 60
+1889 4 0
+531 1 1
+19 1 1
+1944 5 0
+163 6 7
+1206 0 2
+718 1 1
+41 7 0
+1795 13 13
+1390 1 0
+2933 0 16
+540 1 1
+14 1 1
+167 1 0
+897 17 4
+1208 1 0
+1307 1 1
+20 1 1
+540 0 10
+203 2 0
+44 1 1
+298 1 0
+87 11 10
+491 14 8
+991 1 1
+74 6 0
+179 1 1
+34 1 1
+448 10 0
+1688 1 1
+38 21 0
+173 1 1
+49 2 1
+2161 30 30
+203 1 0
+89 1 0
+492 1 1
+30 1 1
+1212 3 0
+990 1 1
+38 1 1
+780 1 0
+191 1 1
+47 6 6
+393 1 1
+41 1 1
+259 1 0
+941 1 1
+20 1 1
+185 0 6
+165 0 16
+420 3 1
+130 1 1
+31 1 1
+253 18 18
+720 16 18
+1257 3 0
+986 0 4
+3311 1 1
+26 1 1
+556 0 4
+120 0 1
+1273 1 1
+20 1 1
+338 8 8
+3965 0 3
+15 1 1
+2531 17 17
+3334 5 5
+121 13 13
+161 1 1
+45 1 1
+94 14 14
+63 9 10
+2108 1 1
+34 1 1
+1436 1 1
+47 1 1
+273 7 0
+153 0 5
+283 12 12
+619 1 1
+36 0 4
+225 1 1
+23 1 1
+553 5 0
+2334 1 1
+49 1 1
+350 1 1
+31 1 1
+1012 2 2
+422 1 1
+46 1 1
+91 4 19
+468 0 1
+46 1 1
+1491 0 4
+426 0 1
+1144 1 2
+1131 1 1
+20 1 1
+1533 16 0
+3103 44 45
+4016 12 12
+346 0 1
+943 1 0
+524 1 1
+20 1 1
+151 3 3
+144 1 1
+189 1 7
+750 1 0
+695 1 0
+1003 0 2
+7819 1 1
+78 1 1
+1811 0 1
+3177 0 1
+8990 0 1
+2268 1 1
+35 0 10
+8205 1 0
+3193 1 1
+76 1 1
+10955 0 1
+22875 0 20
+2417 1 0
+998 0 13
+4236 8 0
+4845 0 2
+64 40 34
+10941 1 1
+40 1 1
+4759 0 6
+12084 0 3
+3052 0 4
+2989 1 0
+13523 1 3
+16170 1 0
+11761 0 3
+3912 3 0
+6620 0 7
+7633 3 0
+419 2 0
+10690 5 24
+10798 0 1
+296 0 1
+1770 4 0
+374 0 4
+230 16 16
+7468 1 0
+1229 1 0
+3061 1 0
+5818 1 0
+2415 12 9
+2056 0 1
+955 4 0
+20022 0 1
+4418 2 1
+2375 0 4
+2086 1 1
+32 1 1
+1225 1 0
+857 2 0
+1154 0 1
+4667 1 0
+170 0 3
+2376 0 1
+2799 10 10
+1512 4 0
+68 9 1
+2170 1 1
+47 1 1
+318 2 0
+19 0 6
+14527 1 1
+33 1 1
+3080 1 1
+23 1 1
+1645 6 6
+231 0 1
+2136 2 0
+6222 0 1
+830 1 1
+24 1 1
+8326 1 0
+2939 1 0
+3959 0 2
+3746 0 2
+1011 1 1
+34 1 1
+7443 0 1
+688 2 0
+574 1 1
+29 1 1
+1799 13 1
+4074 2 0
+136 1 1
+77 1 1
+528 19 0
+253 0 1
+204 1 0
+129 2 0
+811 1 1
+38 1 1
+2347 52 0
+4634 1 0
+856 14 14
+193 0 4
+855 1 1
+28 1 1
+1255 1 1
+36 1 1
+97 0 1
+58 1 1
+1708 1 1
+48 1 1
+958 15 0
+3371 1 1
+37 1 1
+4267 0 13
+1061 0 1
+272 0 26
+8 1 15
+25 0 2
+112 2 0
+26 4 32
+4090 0 1
+3270 1 1
+17 1 1
+2822 0 1
+6206 1 0
+2318 0 2
+1504 0 1
+6189 3 0
+396 22 12
+918 0 1
+2340 1 1
+33 1 1
+326 1 1
+80 1 1
+205 3 2
+81 8 17
+2671 0 1
+1099 0 1
+144 1 1
+29 0 1
+2097 0 3
+24 3 0
+1207 4 4
+45 1 1
+757 0 5
+1926 1 1
+40 1 1
+2657 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+713 0 4
+58 3 0
+1027 3 0
+428 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+6611 0 3
+1575 4 5
+36 1 1
+99 2 0
+700 0 2
+151 0 1
+467 11 11
+272 0 3
+40 1 1
+2428 0 1
+750 2 0
+473 0 2
+421 1 1
+34 1 1
+1575 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+11881 1 1
+30 1 1
+4383 2 0
+6883 49 49
+3146 0 1
+906 3 0
+887 1 1
+80 1 1
+3115 0 1
+1037 1 0
+5866 0 2
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 3 0
+3170 1 0
+1751 0 1
+910 3 0
+691 0 1
+5793 0 1
+26407 1 0
+672 0 1
+19269 29 35
+1371 29 0
+494 2 0
+20417 1 0
+18633 0 1
+601 1 0
+319 0 1
+6820 1 0
+5718 0 2
+17894 1 0
+4272 1 0
+4967 3 1
+290 1 0
+2447 1 0
+740 1 9
+9299 0 18
+7427 1 0
+8151 2 1
+673 1 0
+3453 0 1
+149 0 1
+611 0 4
+4662 0 4
+1752 1 1
+78 1 1
+1581 0 1
+1092 2 0
+159 1 0
+4480 0 2
+4019 0 1
+1451 22 23
+816 1 0
+8701 1 1
+23 1 1
+1796 2 0
+5015 6 1
+1383 8 0
+2368 1 1
+31 1 0
+1883 3 0
+335 0 1
+4157 0 1
+561 4 0
+1538 1 1
+61 0 1
+159 0 2
+3362 4 0
+3333 1 1
+46 1 1
+2307 1 0
+170 1 0
+5972 0 2
+840 0 2
+55 1 1
+28 1 1
+1154 0 2
+650 0 4
+30 0 4
+1100 10 11
+4343 6 0
+1663 4 0
+150 1 0
+3128 1 0
+1449 1 0
+2023 0 1
+428 3 6
+299 2 0
+427 7 7
+1914 14 14
+1273 7 7
+1444 72 0
+423 0 4
+954 1 0
+2467 1 0
+190 8 8
+2034 3 1
+6396 1 1
+34 1 1
+485 1 0
+348 7 0
+770 1 1
+29 0 13
+65 1 1
+1358 0 1
+302 0 1
+659 12 12
+293 0 1
+610 0 1
+906 12 0
+1331 0 6
+1786 0 1
+463 0 1
+4305 0 4
+1041 1 0
+11424 3 1
+13797 0 8
+166 0 1
+1510 5 0
+9069 0 8
+25 1 1
+332 5 3
+76 0 1
+1306 1 1
+46 1 1
+134 19 23
+1467 1 1
+32 1 1
+449 17 0
+367 9 9
+3525 12 10
+91 3 0
+1430 1 1
+24 1 1
+1156 9 13
+843 1 1
+28 1 1
+515 0 17
+1559 0 4
+1045 9 9
+1953 1 0
+31 1 1
+843 0 1
+2174 1 0
+3788 1 0
+2001 0 1
+2400 0 1
+1614 1 0
+8167 0 1
+2700 2 0
+2735 0 1
+8508 1 1
+57 1 1
+141 0 3
+448 1 1
+22 1 1
+2215 1 1
+32 1 1
+1714 32 32
+667 14 14
+142 1 0
+789 1 1
+45 1 1
+84 1 1
+95 1 1
+465 1 1
+45 6 4
+541 1 1
+42 1 1
+1339 5 6
+391 1 1
+20 0 1
+251 1 1
+22 1 1
+561 0 2
+78 3 0
+1718 1 1
+12 1 1
+1042 1 1
+38 1 1
+301 14 0
+222 10 10
+436 10 10
+556 55 55
+953 1 1
+17 1 1
+1752 20 0
+1561 135 0
+58 0 45
+245 101 11
+46 90 0
+150 0 270
+54 180 0
+2130 12 12
+1630 1 1
+26 1 1
+189 0 14
+296 2 0
+809 2 0
+17 20 0
+665 0 40
+236 1 1
+44 1 1
+352 1 1
+25 1 1
+554 6 6
+850 1 1
+33 1 1
+809 3 13
+1832 7 9
+468 1 1
+21 1 1
+951 1 1
+22 1 1
+219 17 18
+733 0 14
+215 2 2
+36 1 1
+301 1 1
+22 1 1
+241 1 1
+52 0 1
+47 1 1
+72 1 1
+109 1 1
+129 1 1
+28 1 1
+174 8 8
+683 3 0
+1190 285 0
+48 1 1
+1330 12 0
+557 17 17
+932 3 1
+27 1 1
+166 1 1
+19 1 1
+406 1 1
+48 3 3
+137 1 0
+161 6 6
+884 2 0
+58 1 1
+107 1 1
+150 14 14
+522 1 1
+28 1 1
+945 4 4
+34 1 1
+472 0 2
+203 0 1
+281 1 1
+46 1 1
+1130 1 0
+232 17 17
+510 1 1
+33 1 1
+62 10 10
+1501 1 1
+20 1 1
+573 1 1
+29 1 1
+928 0 3
+304 1 1
+41 1 1
+160 1 1
+58 1 1
+656 1 1
+40 4 0
+108 6 6
+321 1 1
+14 0 16
+91 1 1
+184 1 1
+43 8 3
+180 1 1
+68 1 1
+144 1 1
+27 1 0
+17 1 1
+212 0 1
+212 1 1
+34 1 1
+115 1 1
+41 1 1
+407 10 10
+200 1 1
+44 2 0
+187 2 0
+146 1 1
+17 1 1
+122 4 4
+73 1 0
+56 1 1
+155 1 17
+80 15 15
+458 1 1
+16 3 3
+343 1 1
+111 1 1
+160 55 55
+157 12 12
+346 0 2
+382 4 0
+35 1 1
+937 0 1
+246 25 0
+52 0 1
+419 0 1
+165 1 0
+75 24 3
+297 1 1
+38 1 1
+5066 1 0
+4922 7 9
+2488 14 14
+2241 1 1
+67 4 4
+39 1 0
+547 1 1
+43 1 1
+524 3715 901
+1796 4 2
+138 2 2
+16 1 1
+415 1 1
+18 1 1
+367 0 89
+1600 0 6
+2175 0 5
+606 14 14
+519 1 0
+540 1 1
+40 1 1
+568 2 0
+165 1 2
+31 1 1
+259 1 1
+41 1 1
+452 31 31
+623 40 62
+818 1 1
+42 1 1
+565 1 1
+44 1 1
+571 10 8
+61 1 1
+28 1 1
+233 2 0
+33 28 0
+53 1 1
+37 1 1
+75 0 396
+156 1 0
+473 0 4
+421 1 1
+35 1 1
+2132 1 1
+80 0 2
+544 9 9
+152 2 1
+33 1 1
+2932 1 1
+44 0 1
+164 22 0
+149 1 0
+534 1 1
+36 1 1
+113 1 1
+15 1 1
+661 1 1
+48 1 1
+1987 1 0
+34 1 1
+444 1 1
+45 1 1
+65 1 1
+67 1 1
+210 1 1
+68 1 1
+55 1 1
+47 1 1
+169 1 1
+64 1 1
+109 0 6
+77 2 32
+6 0 5
+67 0 1
+7 16 0
+51 12 0
+36 0 12
+700 1 1
+33 1 0
+49 0 2
+450 0 1
+98 4 0
+489 32 0
+63 5 1
+78 7 7
+538 17 17
+1269 1 0
+841 1 1
+43 1 1
+2004 1 1
+41 1 1
+86 0 4
+5 1 0
+36 1 1
+573 2 1
+297 1 0
+85 1 1
+30 1 1
+1041 1 0
+12 1 1
+392 33 12
+515 5 6
+583 1 1
+33 1 1
+616 16 16
+1052 0 11
+39 1 1
+184 1 1
+67 1 1
+102 7 7
+58 0 1
+307 1 1
+56 0 3
+930 21 19
+1264 0 1
+832 1 1
+28 1 1
+272 1 1
+82 1 1
+56 1 0
+976 6 6
+2015 0 3
+84 9 9
+130 13 17
+564 10 15
+154 1 0
+438 10 10
+38 0 5
+2141 1 1
+25 1 1
+73 10 10
+70 5 5
+132 1 1
+52 1 1
+599 1 1
+46 1 1
+279 1 1
+18 1 1
+239 2 0
+383 6 0
+224 0 1
+321 3 0
+8 16 0
+1775 1 1
+18 2 0
+575 16 16
+60 1 1
+16 1 1
+1247 2 0
+173 3 0
+41 1 1
+57 8 8
+285 2 0
+672 1 1
+44 1 1
+106 0 1
+148 1 1
+49 3 0
+146 5 11
+91 1 1
+79 1 1
+94 1 1
+101 1 1
+88 16 16
+117 1 1
+15 1 1
+58 1 1
+93 1 1
+140 1 0
+326 1 1
+44 1 1
+160 1 1
+23 1 1
+481 14 14
+181 4 4
+72 1 1
+25 1 1
+88 1 3
+36 0 12
+92 1 1
+56 10 0
+13 0 1
+66 1 1
+141 2 0
+65 1 1
+367 0 2
+610 1 1
+22 1 1
+150 1 1
+85 1 1
+109 1 1
+167 3 1
+23 1 0
+26 1 1
+74 1 1
+33 1 1
+176 1 1
+25 2 2
+193 1 1
+35 0 1
+383 0 5
+249 1 1
+69 1 1
+98 1 1
+62 1 1
+62 1 2
+74 0 1
+68 1 1
+438 1 1
+64 1 1
+47 0 8
+125 3 0
+75 5 5
+45 1 1
+197 1 1
+27 1 1
+116 13 13
+218 15 20
+1107 16 19
+73 1 1
+25 1 1
+199 1 1
+60 1 1
+994 1 1
+43 0 1
+18 1 1
+1215 18 18
+340 1 1
+34 1 1
+1350 16 16
+1726 4 4
+193 1 1
+48 1 1
+295 1 1
+18 1 1
+411 19 19
+175 1 1
+49 1 1
+146 1 1
+61 1 1
+116 1 1
+41 1 1
+137 1 1
+30 1 1
+158 9 9
+136 10 13
+349 8 8
+468 1 1
+44 1 1
+862 17 17
+813 1 1
+24 1 1
+214 10 4
+228 1 1
+34 1 1
+101 12 12
+242 1 1
+69 1 1
+185 1 1
+24 1 0
+164 0 1
+222 1 1
+25 1 1
+297 10 10
+1171 1 0
+182 1 1
+35 1 1
+350 19 19
+1966 1 1
+24 1 1
+548 7 7
+208 13 12
+298 1 1
+65 1 1
+193 2 2
+28 1 1
+125 4 4
+95 7 7
+566 1 1
+40 1 1
+118 0 1
+318 1 0
+374 1 1
+58 1 1
+143 1 1
+74 1 1
+53 21 0
+81 1 1
+45 1 1
+138 15 16
+180 1 1
+62 1 1
+661 1 1
+48 1 1
+1463 1 0
+156 0 1
+148 1 1
+19 1 0
+17 1 1
+1927 4 0
+1469 14 14
+466 0 1
+3098 0 1
+1141 2 3
+743 14 14
+79 1 1
+22 1 1
+362 0 1
+682 16 9
+275 0 4
+539 1 0
+61 0 7
+331 0 4
+130 1 1
+31 0 3
+1554 1 1
+43 1 1
+224 1 1
+49 1 1
+159 3 0
+1064 27 27
+104 1 1
+21 1 1
+222 2 2
+49 1 1
+1397 1 1
+37 1 1
+414 0 2
+695 1 1
+31 1 1
+742 1 1
+21 1 1
+230 3 2
+42 1 1
+68 1 1
+37 1 1
+703 0 3
+2216 84 83
+1430 1 1
+23 1 1
+1867 13 0
+35 1 1
+137 16 16
+1500 4 0
+4546 1 1
+25 1 1
+358 19 19
+1549 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+498 3 0
+321 0 1
+281 3 0
+414 1 1
+70 1 1
+284 1 0
+214 1 1
+28 1 1
+280 1 0
+650 1 1
+47 1 1
+1030 1 1
+91 1 1
+6520 5 5
+462 1 0
+2864 0 3
+1930 0 4
+2915 1 1
+20 1 1
+413 1 0
+1844 11 11
+133 0 6
+569 10 10
+110 12 12
+184 0 3
+228 1 1
+43 2 2
+51 14 13
+1499 1 0
+12 1 1
+378 1 1
+49 1 1
+424 1 0
+1069 1 1
+142 0 1
+821 2 9
+311 1 6
+247 1 1
+86 1 1
+1850 1 1
+26 1 1
+498 1 1
+34 1 1
+688 5 9
+44 1 1
+369 1 1
+69 1 1
+156 2 0
+83 1 1
+128 1 1
+50 9 9
+249 1 1
+70 0 1
+624 2 0
+74 2 1
+300 1 1
+26 1 1
+240 4 0
+1705 1 1
+52 1 1
+231 29 24
+378 2 0
+236 1 1
+76 1 1
+116 9 12
+301 20 20
+59 0 6
+43 1 1
+384 15 15
+1414 5 0
+225 0 2
+1234 1 0
+29 1 1
+235 10 10
+227 1 1
+77 4 0
+43 5 9
+485 7 7
+380 10 0
+46 1 0
+90 1 1
+161 1 1
+401 1 1
+58 1 1
+2127 3 0
+186 20 20
+323 5 5
+47 1 1
+236 1 1
+31 0 2
+1568 1 1
+136 0 1
+202 0 3
+77 1 1
+44 1 1
+411 12 11
+317 0 2
+599 1 1
+37 1 1
+391 1 0
+273 1 0
+744 0 4
+703 1 1
+20 1 1
+198 3 0
+158 19 15
+27 12 0
+282 1 1
+32 4 0
+740 1 0
+327 1 1
+105 1 1
+146 16 16
+101 1 0
+21 1 1
+232 1 1
+33 2 0
+12 1 1
+189 1 1
+30 2 2
+544 1 1
+153 1 1
+586 5 0
+1351 21 0
+446 49 49
+121 7 7
+1147 12 12
+777 1 0
+701 1 1
+29 2 2
+154 12 12
+191 1 1
+55 1 1
+113 0 1142
+87 0 2
+15 0 1
+525 1 1
+22 1 1
+355 10 10
+50 0 8
+252 1 1
+31 1 1
+354 6 5
+148 15 15
+407 1 1
+42 1 1
+275 0 1
+737 5 9
+1432 1 1
+39 1 1
+84 0 2
+77 7 7
+514 20 20
+385 7 1
+815 1 1
+45 1 1
+487 1 1
+66 1 1
+2379 0 24
+779 1 1
+18 1 0
+2653 4 0
+34 1 1
+191 1 1
+35 1 1
+1174 12 0
+2497 1 1
+24 0 1500
+447 8 0
+3268 1 0
+946 1 0
+2223 20044 20060
+119 1 1
+71 0 3
+53 0 5
+40 1 1
+309 1 1
+57 1 1
+101 1 1
+47 2 2
+67 1 1
+47 1 1
+74 0 1
+28 1 1
+167 1 1
+33 1 1
+543 1 1
+27 11 34
+33 1 1
+149 7 7
+61 1 1
+120 1 1
+366 1 1
+55 1 1
+121 1 1
+62 1 1
+78 1 1
+48 1 1
+161 1 1
+26 1 1
+191 1 1
+20 11 11
+550 1 1
+76 1 0
+20 1 1
+112 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+83 1 1
+46 1 1
+1500 1 1
+81 1 1
+210 1 1
+26 1 1
+713 1 1
+48 1 1
+723 0 3
+196 6 6
+62 2 2
+32 1 1
+606 1 2
+357 1 1
+38 292 0
+589 1 1
+30 1 1
+714 8 8
+639 1 1
+20 1 1
+1068 0 1
+571 1 1
+49 1 1
+436 0 1
+609 0 2
+30 1 1
+66 0 1
+349 11 11
+65 1 1
+40 1 1
+717 0 3
+299 1 1
+29 1 1
+724 1 0
+275 1 1
+33 1 1
+318 0 3
+279 1 1
+28 1 1
+389 1 0
+548 0 8
+330 1 1
+47 1 1
+170 1 1
+47 1 1
+519 14 14
+841 24 24
+732 1 1
+29 3 3
+688 2 2
+23 0 1
+94 14 14
+726 13 13
+508 0 12
+21 6 0
+69 1 1
+37 1 1
+590 1 1
+59 1 1
+89 11 11
+164 1 1
+58 1 1
+1709 18 18
+520 1 1
+27 1 1
+683 10 10
+814 1 1
+26 1 1
+350 1 1
+39 1 1
+132 6 6
+439 10092 10075
+78 15 15
+3352 1 1
+23 1 1
+873 4 4
+887 1 0
+1827 1 0
+216 6 6
+805 2 0
+874 0 8
+2266 1 1
+47 1 1
+761 0 4
+86 1 1
+19 1 1
+1794 9 9
+271 0 1
+2266 1 1
+34 1 1
+916 0 1
+21 1 1
+108 21 21
+141 1 1
+27 1 1
+406 3 0
+3950 1 1
+38 1 1
+128 2 2
+56 1 1
+72 0 1
+96 1 1
+22 1 1
+169 7 7
+511 1 1
+38 1 1
+1070 1 1
+90 1 1
+50 1 1
+41 1 0
+30 1 1
+659 12 12
+701 1 1
+33 1 1
+569 15 15
+70 1 1
+38 1 1
+955 0 3
+130 1 1
+63 1 1
+251 8 8
+191 1 1
+26 0 3
+187 1 0
+916 5 1
+70 13 13
+498 20061 20021
+160 1 1
+76 1 1
+95 1 1
+76 1 1
+275 1 0
+101 1 1
+79 1 1
+100 7 7
+159 1 1
+75 0 8
+87 1 1
+76 1 1
+44 1 1
+71 32 32
+89 11 12
+196 1 1
+55 0 2
+61 1 1
+83 0 1
+944 1 1
+126 1 1
+81 6 6
+41 3 0
+641 1 1
+92 1 0
+113 1 1
+39 1 1
+671 1 1
+28 1 1
+123 1 1
+59 1 1
+210 1 1
+17 1 1
+168 15 14
+494 1 0
+22 1 1
+484 18 18
+376 1 1
+114 2 0
+67 1 1
+10 1 1
+109 1 1
+165 1 1
+149 6 6
+234 1 1
+19 5 5
+64 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+168 1 1
+73 1 1
+194 1 1
+50 0 4
+37 1 1
+95 3 1
+43 1 1
+153 1 1
+83 1 1
+55 1 1
+39 1 1
+70 7 0
+59 7 7
+75 1 1
+84 2 2
+110 1 0
+42 1 1
+129 9978 10000
+438 1 1
+43 1 0
+55 1 1
+40 1 1
+175 1 1
+46 1 1
+52 1 1
+19 1 1
+277 1 1
+60 1 1
+98 1 1
+24 1 1
+333 4 4
+1047 2 0
+4080 1 1
+38 1 1
+837 0 64
+172 1 1
+55 1 1
+1818 2 0
+1143 13 13
+335 1 0
+1944 5 0
+39 6 0
+4057 3 8
+9465 5 4
+301 19 1
+191 84 0
+427 1 1
+29 0 4
+157 4 5
+296 21 18
+158 2 2
+36 1 1
+539 13 13
+399 1 1
+46 1 1
+348 1 1
+49 1 1
+268 1 0
+66 0 4
+178 2 2
+107 1 1
+133 5 5
+355 1 1
+30 1 1
+346 1 1
+29 1 1
+161 1 1
+38 1 1
+121 4 4
+55 8 8
+67 7 7
+318 17 17
+259 1 1
+94 1 1
+80 1 1
+35 1 1
+260 1 1
+81 1 1
+106 1 1
+58 1 2
+301 3 0
+2052 1 1
+40 1 1
+174 20 22
+574 0 2
+414 1 0
+234 0 1
+425 51224 51060
+1568 14 14
+11956 0 1
+2667 0 2
+884 1 1
+19 1 1
+676 1 1
+63 1 1
+3138 0 3
+3038 5 2
+132 10 6
+136 18 13
+363 1 1
+89 1 1
+382 1 1
+29 1 1
+58 8 7
+297 4 0
+66 1 1
+93 2 0
+145 1 1
+31 5 5
+576 1 1
+89 1 1
+1256 0 12
+67 1 1
+193 2 2
+23 1 1
+51 1 0
+727 1 0
+1148 12 12
+837 1 1
+77 1 1
+941 10 10
+776 19 19
+300 1 1
+24 1 1
+256 1 7
+93 1 1
+224 2 0
+138 1 1
+563 1 1
+104 4 4
+2898 1 1
+46 1 1
+282 1 1
+39 1 1
+204 2 2
+22 1 1
+469 1 1
+20 1 1
+140 1 1
+26 1 1
+745 0 2
+539 0 6
+1536 1 0
+817 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+132 5 0
+555 1 1
+42 1 1
+573 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+15 1 5
+1404 0 1
+934 1 1
+49 1 1
+1350 1 0
+384 1 1
+24 1 1
+4169 0 15
+244 10 10
+2167 18 14
+64 1 1
+31 1 1
+185 0 4
+1647 1 1
+20 1 1
+227 1 1
+37 1 1
+636 3 4
+5590 1 1
+39 1 1
+461 0 2
+2145 1 1
+23 1 1
+1114 0 2
+688 0 1
+901 18 18
+4781 0 4
+815 0 1
+5027 42 47
+415 0 1
+2743 1 1
+78 1 1
+390 1 0
+328 0 1
+878 0 1
+5752 0 2
+1554 1 1
+60 1 1
+278 0 1
+19 1 1
+1164 11 11
+691 0 2
+960 1 0
+62 0 20
+2108 0 2
+1265 0 1
+1642 2 0
+3584 2 0
+12086 2 0
+3766 0 2
+1209 1 7
+3466 1 0
+1448 1 0
+1943 0 1
+698 0 8
+1166 135 135
+2030 2 0
+540 1 0
+1736 14 0
+3128 0 2
+4464 0 1
+3597 1 0
+378 1 0
+1269 0 3
+1182 1 0
+654 0 3
+2049 1 0
+6838 1 1
+69 0 3
+154 1 0
+2718 1 1
+30 1 1
+160 11 11
+4954 0 1
+420 1 1
+123 1 1
+156 0 4
+219 4 0
+195 1 0
+4402 3 0
+3045 0 1
+1249 1 0
+3522 0 10
+675 20 20
+117 8 0
+346 0 1
+8538 5 0
+455 1 0
+119 0 1
+355 48 48
+724 1 0
+9254 22 22
+1672 1 0
+833 0 1
+4251 1 0
+8 1 1
+2079 0 1
+1735 8 12
+1612 0 1
+1373 5 0
+8585 7 0
+64 1 1
+3799 1 0
+258 2 0
+899 1 0
+1362 8 9
+593 0 2
+3351 2 0
+618 0 4
+905 2 15
+2797 1 0
+2776 2 0
+4110 0 6
+4466 18 18
+1783 9 9
+475 0 4
+134 1 0
+12963 8 0
+1616 0 2
+1685 2 0
+2225 2 0
+428 0 1
+458 20 20
+2860 0 3
+677 4 6
+325 11 1
+1887 0 1
+913 0 1
+997 5 5
+2814 17 15
+1389 1 0
+1200 0 4
+2495 1 0
+3921 26431 26426
+2419 0 1
+6110 0 1
+1370 0 1
+3085 1 0
+3568 1 1
+24 0 9
+597 1 0
+2642 1 0
+1545 10 0
+4952 0 1
+6146 2 0
+1452 1 0
+2967 1 0
+4920 5 0
+147 4 5
+850 1 0
+1875 1 0
+695 3 1
+1719 0 1
+259 0 1
+294 1 0
+128 0 2
+3051 0 1
+908 0 4
+3399 0 1
+4673 1 0
+3179 1 0
+411 1 1
+44 1 1
+174 1 0
+1047 17 17
+998 178 0
+671 0 40
+2093 1 0
+313 0 1
+7581 1 0
+3245 1 0
+972 0 4
+4085 2 0
+346 1 1
+45 1 1
+368 1 0
+26 1 1
+8444 0 1
+17044 1 0
+2795 2 0
+2860 1 0
+622 0 1
+167 0 5
+1968 0 2
+259 2 0
+4992 29 27
+170 1 0
+3528 0 1
+191 1 2
+117 2 0
+2275 1 0
+12676 1 1
+20 1 1
+9972 1 0
+13955 0 5
+19867 1 0
+9612 1 0
+14233 0 32737
+6316 1 1
+19 1 1
+970 8 8
+2685 16 16
+18093 0 1
+6799 0 16
+3350 0 1
+7574 0 12
+2132 0 1
+7228 52793 52800
+1955 22 22
+698 0 1
+2149 1 0
+6880 0 2
+960 0 1
+23 1 1
+2646 2 0
+3867 5 0
+26077 0 3
+3174 1 0
+8183 0 1
+2817 10 0
+5841 1 0
+2081 0 1
+374 0 2
+3589 0 4
+10625 28 28
+3275 3 0
+773 7 7
+175 1 1
+79 1 1
+400 12 12
+1096 0 4
+717 7 7
+52 1 1
+68 5 1
+2117 0 3
+130 14 14
+1124 0 3
+413 0 4
+643 3 0
+58 1 1
+127 1 1
+196 0 2
+226 3 0
+136 3 4
+293 1 1
+25 0 3
+63 1 1
+417 0 2
+412 0 16
+737 4 0
+402 2 0
+654 1 1
+42 1 1
+75 1 1
+64 1 1
+2980 4 0
+576 0 1
+29 2 2
+715 1 1
+36 1 1
+511 38 38
+218 4 40
+44 1 5
+43 49 5
+709 21 21
+1147 9 9
+22 1 1
+195 7 4
+659 3 0
+27 1 1
+637 1 1
+42 1 1
+531 1 1
+67 1 1
+39 1 0
+717 11 11
+53 1 1
+61 1 1
+1535 1 1
+89 0 1
+49 1 0
+102 1 1
+67 1 1
+76 1 1
+129 1 1
+85 1 1
+607 10 0
+12 137 1
+41 1 1
+1043 1 1
+22 1 1
+203 3 0
+480 14 21
+91 23 23
+1345 2 1
+435 15 17
+1188 30 0
+1778 1 0
+120 0 3
+3797 1 0
+3211 0 1
+2456 4 0
+954 0 4
+1847 0 1
+5929 20 20
+984 14 0
+2112 1 0
+2013 1 0
+1770 14 14
+3100 1 0
+1160 16 0
+733 7 7
+238 3 2
+2203 2 1
+5654 1 1
+28 5 10
+482 0 1
+2970 0 4
+2892 0 1
+251 1 7
+1346 1 0
+877 0 4
+3583 0 1
+1178 0 1
+1293 0 2
+491 2 0
+6803 1 1
+22 1 1
+2218 1 1
+44 1 1
+4780 4 0
+3026 14 13
+442 5 5
+2022 6 6
+506 2 0
+8557 1 1
+36 1 0
+1575 1 0
+1329 1 1
+35 1 0
+247 1 1
+16 1 1
+184 1 1
+18 1 1
+1636 0 7
+23 1 1
+527 1 1
+39 1 1
+653 3 0
+227 1 1
+18 1 1
+218 0 323
+91 1 0
+124 0 15
+621 0 2
+555 8 8
+467 1 1
+40 1 1
+372 1 1
+25 1 1
+188 12 12
+357 0 2
+2389 1 1
+22 1 1
+2579 0 5
+461 1 1
+36 1 1
+1584 1 1
+26 1 0
+429 1 0
+33 1 1
+1071 0 4
+1068 9 0
+1472 0 2
+1839 94 92
+337 1 1
+46 1 1
+416 1 1
+42 1 1
+1255 0 2
+628 17 15
+587 15 15
+398 3 0
+623 1 1
+78 0 3
+287 10 0
+191 0 2
+493 1 1
+42 4 0
+219 0 1
+408 1 1
+23 1 1
+283 1 1
+21 1 1
+633 2 0
+241 6 6
+457 1 0
+330 0 16
+428 1 0
+4 6 0
+324 0 1
+3060 0 2
+9953 0 1
+1899 0 6
+6431 0 1
+8674 0 4
+4595 11 0
+5064 2 0
+2813 12 12
+1391 5 0
+3690 1 1
+64 1 1
+2635 1 1
+49 1 1
+69 1 1
+15 1 1
+605 4 4
+400 8 0
+735 0 20
+3074 2 0
+1879 0 1
+572 0 8
+576 1 1
+42 1 1
+265 24 0
+209 11 11
+953 1 1
+42 0 5
+58 1 0
+95 1 0
+1121 1 1
+17 1 1
+751 0 1
+24 1 1
+351 1 1
+43 3 3
+565 1 1
+15 1 1
+271 1 0
+323 1 1
+23 1 1
+221 7 7
+705 9 0
+631 2 0
+64 1 1
+1577 1 1
+21 0 1
+371 7 21
+160 0 1
+283 1 1
+48 1 1
+227 1 1
+40 0 1
+1359 0 2
+836 13 13
+722 7 7
+1153 1 1
+93 1 1
+797 14 14
+433 8 0
+108 11 11
+140 1 1
+40 1 1
+470 1 1
+42 1 1
+1106 0 1
+85 4 4
+129 1 1
+123 1 0
+95 1 1
+104 6 1
+641 1 1
+77 1 1
+57 1 1
+62 1 1
+473 2 0
+262 6 0
+45 1 1
+63 2 0
+39 1 1
+267 0 1
+197 2 104
+189 107 3
+112 0 4
+108 5 0
+563 14 14
+324 1 0
+205 1 1
+17 1 1
+495 0 1
+201 4 0
+14 1 1
+667 42 42
+178 1 1
+58 1 1
+133 1 1
+24 1 1
+91 24 24
+342 1 1
+32 1 1
+121 1 1
+62 1 1
+2371 2 0
+164 8 1
+655 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+1780 2 0
+742 1 1
+40 1 1
+2014 1 0
+1741 3 0
+3833 0 1
+14622 161198 190000
+5156 0 1
+1680 1 1
+88 1 1
+4502 0 1
+46 1 1
+800 4 4
+23 1 1
+1305 2 0
+136 0 1
+4941 0 1
+547 0 1
+70 8 8
+293 1 1
+35 1 1
+1165 4 0
+6662 1 1
+46 1 1
+167 0 8
+214 1 1
+35 1 1
+108 1 0
+1063 0 1
+1017 1 1
+20 0 6
+1725 0 1
+150 5 5
+33 1 0
+12 1 1
+349 1 1
+24 0 1
+1562 1 1
+31 1 1
+2513 0 1
+73 36 36
+305 1 1
+27 1 1
+543 1 1
+47 4 28
+5476 10 10
+531 1 1
+37 1 1
+776 1 1
+44 2 2
+115 22 20
+181 1 1
+125 3 3
+466 1 1
+76 1 1
+144 5 5
+32 1 1
+225 1 1
+41 1 1
+707 24 24
+66 4 4
+414 1 1
+42 1 1
+81 1 1
+63 1 1
+76 28 46
+187 1 1
+97 1 1
+99 9 9
+85 14 14
+81 6 6
+62 1 1
+109 4 5
+150 1 0
+44 4 4
+93 11 11
+188 3 3
+73 1 1
+52 1 1
+19 13 0
+48 1 1
+62 0 7
+205 1 1
+68 9 9
+99 4 0
+21 1 0
+52 1 1
+171 1 1
+109 3 1
+6 0 2
+190 1 1
+69 10078 10069
+90 3 1
+197 1 1
+157 0 6
+137 1 1
+101 2 2
+233 6 6
+62 1 1
+104 0 1
+143 1 1
+119 1 1
+106 2 0
+176 1 1
+79 0 1
+50 1 1
+50 3 3
+179 1 1
+159 1 1
+36 1 1
+107 1 1
+176 1 1
+154 0 5
+91 1 1
+54 1 1
+77 1 1
+238 2 2
+50 1 1
+1421 1 1
+23 1 1
+216 1 1
+122 1 1
+86 1 1
+41 3 1
+336 7 7
+41 9 0
+107 1 1
+90 1 3
+6 1 0
+84 1 1
+213 1 1
+26 1 1
+138 1 1
+25 1 1
+206 1 1
+36 3 3
+37 7 0
+500 1 1
+52 1 1
+52 1 1
+48 1 1
+395 1 1
+66 6 6
+72 1 0
+69 1 1
+100 10 10
+160 1 0
+64 7 7
+89 1 1
+123 1 1
+128 1 1
+36 1 1
+231 1 1
+61 1 1
+564 8 8
+593 47 47
+163 1 0
+196 8 8
+174 5 5
+37 1 1
+67 0 1
+192 1 1
+60 3 0
+19 1 1
+1149 1 1
+18 1 1
+77 1 1
+32 2 0
+32 1 1
+136 1 1
+78 2 0
+162 4 0
+41 1 1
+351 13 13
+1634 2 0
+229 8 8
+57 13 2
+410 1 1
+76 1 1
+180 1 1
+92 1 1
+270 1 1
+40 1 1
+92 1 1
+53 1 1
+227 1 1
+42 1 1
+357 4 4
+23 1 1
+94 1 0
+200 6 0
+201 7 7
+70 5 13
+57 4 0
+35 1 1
+206 1 1
+76 2 2
+651 1 1
+68 4 0
+73 1 1
+49 4 0
+37 1 1
+145 2 2
+78 2 2
+108 12 12
+52 1 1
+35 1 1
+242 1 3
+76 2 2
+50 12 12
+70 1 1
+33 0 2
+57 1 1
+64 15 15
+168 1 1
+22 1 1
+63 36 37
+73 0 2
+64 1 1
+177 2 0
+19 4 0
+55 1 0
+33 1 1
+51 1 1
+122 1 1
+296 1 1
+85 1 1
+109 1 1
+64 1 1
+155 1 1
+58 0 2
+72 1 1
+25 1 1
+128 1 1
+45 2 0
+444 1 1
+25 1 1
+64 1 1
+21 1 1
+368 15 15
+734 2 0
+701 15 15
+71 1 1
+41 1 1
+77 1 1
+56 1 1
+478 2 0
+714 8 7
+95 2 2
+50 4 3
+1129 1 1
+34 1 1
+1715 1 1
+87 1 1
+692 1 1
+47 0 1
+75 1 1
+541 12 12
+1602 10 10
+1265 1 1
+46 1 1
+298 1 1
+22 1 1
+186 1 1
+34 1 1
+202 1 1
+61 1 0
+185 1 1
+24 1 0
+98 0 2
+258 8 14
+967 1 1
+15 1 1
+625 1 0
+1362 0 4
+23365 4 0
+246 26975 26986
+3307 0 1
+13671 3 3
+52 1 1
+1308 2 0
+942 0 1
+17790 1 0
+4586 0 1
+949 0 2
+15047 0 1
+606 2 0
+7820 0 4
+22313 16 0
+10539 8 0
+4836 0 1
+8320 18 18
+388 2 0
+194 1 1
+49 1 1
+320 1 1
+34 1 1
+6813 0 1
+8719 3 0
+7037 1 0
+721 0 1
+999 6 0
+17 1 0
+3075 5 0
+593 13 11
+1006 12 12
+3487 1 0
+9535 0 4
+23 0 2
+23 2 0
+513 0 3
+377 1 0
+2627 0 2
+16 0 1
+211 18 18
+571 2 0
+7617 0 1
+1607 1 0
+69 1 1
+66 1 1
+275 1 1
+67 7 0
+25 1 1
+1206 1 0
+136 8 7
+612 1 1
+61 1 1
+740 0 2
+78 26 26
+129 15 15
+69 12 16
+1483 13 28
+1062 1 0
+108 4 0
+685 0 2
+1566 1 0
+192 4 4
+1452 9 45
+1514 1 1
+46 1 1
+1969 0 1
+35 1 1
+1094 1 0
+618 1 1
+43 1 1
+6580 1 0
+1636 5 0
+6325 1 1
+32 1 1
+1041 0 2
+174 9 0
+11983 18 18
+142 8 8
+2203 10 8
+2025 1 1
+39 1 1
+907 4 4
+225 1 1
+124 1 1
+3928 0 22
+38 2 0
+44 18 0
+46 0 6
+61 0 1
+3653 6 0
+34 1 1
+4559 1 1
+28 1 1
+283 5 5
+1572 28 28
+351 1 1
+34 1 1
+443 19 19
+57 1 1
+21 1 1
+231 1 1
+94 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 1 1
+38 1 1
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 5 5
+23 1 1
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+339 1 1
+56 0 5
+142 1 1
+232 1 1
+43 1 1
+332 1 1
+47 1 1
+479 1 0
+137 0 3
+1456 10 13
+63 1 1
+37 1 1
+261 0 2
+109 1 1
+50 1 1
+56 129 1
+88 1 0
+44 1 1
+54 1 1
+56 1 50
+58 50 1
+54 277 1
+44 1 1
+297 0 39
+142 1 1
+85 1 1
+124 16 16
+58 3 15
+677 1 0
+1333 2 0
+13591 6 0
+989 1 1
+107 1 1
+678 1 1
+31 1 1
+2571 5 5
+56 2 2
+39 1 1
+3986 0 4
+18351 32 30
+10811 1 1
+25 0 1
+417 1 1
+40 1 1
+159 4 4
+37 4 4
+179 1 1
+51 1 1
+103 2 0
+108 1 1
+79 1 1
+25 1 1
+58 1 1
+12 1 1
+275 14 0
+80 1 1
+83 1 1
+24 1 1
+59 1 0
+91 1 1
+65 1 1
+67 1 1
+136 4 0
+68 8 0
+331 5 0
+40 1 1
+110 10 6
+64 1 1
+368 1 1
+22 1 1
+509 1 1
+89 1 1
+926 1 0
+959 1 1
+44 1 1
+72 11 0
+47 1 1
+361 1 1
+37 1 1
+2204 2 2
+45 1 1
+1117 18 18
+141 1 1
+47 1 1
+148 1 1
+75 1 1
+104 1 0
+205 3 2
+249 1 1
+146 1 1
+94 1 1
+34 1 1
+700 0 331
+21 1 1
+73 1 1
+49 1 1
+356 1 1
+16 1 1
+112 1 1
+36 9 0
+515 1 1
+27 2 2
+192 1 1
+53 0 14
+82 1 1
+302 1 1
+68 1 1
+52 12 12
+52 1 1
+34 1 1
+166 7 7
+384 1 1
+31 1 1
+281 1 1
+57 1 1
+176 0 1
+1625 1 1
+26 1 1
+369 1 1
+21 1 1
+86 1 1
+134 1 1
+215 1 1
+214 15 1
+50 2 2
+26 1 1
+78 0 19
+64 1 1
+118 53 53
+433 1 1
+76 0 1
+6 12 0
+52 1 1
+108 1 1
+87 1 1
+62 1 1
+26 1 1
+291 2 1
+143 1 1
+29 1 1
+56 12 12
+230 1 1
+153 4 4
+87 32 32
+584 12 12
+227 1 0
+1931 4 0
+836 1 1
+68 1 1
+205 24 19
+816 1 2
+1932 0 7
+1732 13 0
+257 4 0
+1423 1 0
+129 6 0
+1505 1 1
+42 0 1
+373 13 13
+565 1 1
+76 1 0
+1881 0 4
+68 4 0
+43 0 4
+2201 8 8
+3726 3 0
+339 15 11
+249 1 1
+35 1 1
+250 1 1
+38 1 1
+359 11 12
+109 1 1
+43 18 0
+822 1 1
+53 1 1
+325 15 15
+123 1 1
+42 6 6
+240 1 1
+44 1 1
+438 7 7
+142 2 0
+1004 0 1
+9275 1 1
+37 1 0
+2071 0 1
+1253 9 9
+9137 0 1
+12513 2 1
+11243 1 1
+26 1 1
+816 4 0
+15996 2 0
+1594 1 0
+363 5 0
+6757 47 41
+2700 1 0
+841 0 1
+1807 0 2
+2565 11 0
+2089 0 2
+477 1 0
+657 0 1
+776 0 20
+365 82 49
+779 0 1
+401 25 63
+441 0 2
+1152 0 2
+1315 1 0
+5352 6 8
+902 0 1
+2154 1 1
+36 1 1
+109 0 1
+668 6 0
+1923 0 1
+91 3 2
+3560 1 0
+1235 1 0
+139 26 0
+7381 1 0
+155 0 14
+2393 1 1
+33 1 1
+507 4 0
+1337 0 1
+9954 3 0
+1588 1 0
+2605 1 1
+23 1 1
+3000 0 3
+8249 8 0
+912 0 1
+338 2 0
+734 1 0
+4332 1 0
+416 0 4
+1691 0 1
+295 1 0
+214 2 0
+121 0 1
+784 0 1
+2512 0 1
+4465 12 11
+926 1 0
+190 1 0
+5780 0 1
+490 5 0
+228 1 1
+45 1 1
+207 3 0
+322 0 1
+633 1 1
+24 1 0
+1516 5 0
+1025 0 13
+1518 0 1
+591 10 10
+1061 1 0
+1371 1 1
+22 1 1
+928 0 2
+182 8 0
+328 1 0
+301 0 1
+994 1 1
+18 0 6
+1743 0 1
+2350 22 23
+1548 0 2
+1498 8 6
+7484 0 3
+2988 7 7
+93 2 0
+322 1 0
+280 1 1
+49 1 1
+2114 16 17
+617 0 1
+1012 0 1
+495 1 0
+29 1 1
+3134 1 0
+1837 0 4
+4079 0 1
+905 8 0
+5764 0 1
+3493 0 20
+1174 0 1
+900 0 1
+1006 1 0
+1699 0 1
+1682 1 0
+688 1 1
+21 1 1
+3349 0 1
+384 3 1
+3616 3 0
+748 0 1
+3001 0 10
+541 1 0
+286 1 1
+22 0 1
+250 1 1
+27 1 1
+898 1 0
+1161 0 2
+2067 0 1
+8000 0 12
+857 29 0
+1399
+
+chain 72788 chr6_qbl_hap2 4565931 + 3808375 3809175 11 135006516 + 118201008 118201901 1739030
+615 13 107
+119 2 1
+51
+
+chain 65509 chr6_qbl_hap2 4565931 + 2258974 2259668 6 171115067 - 140105134 140105832 1929446
+178 0 4
+516
+
+chain 50097 chr6_qbl_hap2 4565931 + 2471491 2473781 6 171115067 + 44553942 44556234 2550079
+125 147 147
+81 297 298
+77 380 378
+160 345 343
+82 181 182
+60 299 303
+56
+
+chain 30865 chr6_qbl_hap2 4565931 + 3800272 3800791 6 171115067 + 32713281 32713770 4500604
+73 89 59
+184 77 77
+96
+
+chain 26769 chr6_qbl_hap2 4565931 + 2218659 2218944 1 249250621 - 83463584 83463869 6084938
+285
+
+chain 25453 chr6_qbl_hap2 4565931 + 1111775 1112573 8 146364022 + 94982474 94983353 6804147
+181 108 108
+72 385 466
+52
+
+chain 18586 chr6_qbl_hap2 4565931 + 2472758 2473366 3 198022430 - 151831455 151832050 2830221
+34 221 221
+81 91 91
+5 35 35
+55 44 31
+42
+
+chain 18520 chr6_qbl_hap2 4565931 + 2558133 2558568 13 115169878 - 5075411 5075846 11677159
+71 220 220
+144
+
+chain 17263 chr6_qbl_hap2 4565931 + 3694162 3694369 4 191154276 + 3927369 3927573 12785974
+50 3 0
+26 4 4
+124
+
+chain 16745 chr6_qbl_hap2 4565931 + 2589692 2589893 11 135006516 + 74748600 74748801 13289219
+113 12 12
+76
+
+chain 15761 chr6_qbl_hap2 4565931 + 3069257 3069435 19 59128983 - 18504215 18504393 607285
+59 1 1
+45 1 1
+72
+
+chain 15688 chr6_qbl_hap2 4565931 + 3804298 3804527 11 135006516 - 109492289 109492518 14350697
+129 50 50
+50
+
+chain 14458 chr6_qbl_hap2 4565931 + 3751685 3752808 6 171115067 + 32441118 32442245 15662572
+59 270 268
+88 656 662
+50
+
+chain 14065 chr6_qbl_hap2 4565931 + 3705931 3706083 6 171115067 - 138602057 138602209 16122341
+152
+
+chain 13955 chr6_qbl_hap2 4565931 + 2589304 2589471 9 141213431 - 10269188 10269355 16251226
+93 11 11
+63
+
+chain 13115 chr6_qbl_hap2 4565931 + 937718 937855 7 159138663 + 102343613 102343750 17340123
+137
+
+chain 12452 chr6_qbl_hap2 4565931 + 4213437 4214179 12 133851895 + 124586233 124586652 1913233
+57 408 105
+14 32 63
+45 0 78
+44 129 0
+13
+
+chain 12361 chr6_qbl_hap2 4565931 + 1150685 1150815 1 249250621 + 48985442 48985572 18455294
+130
+
+chain 12272 chr6_qbl_hap2 4565931 + 2479004 2479160 X 155270560 + 155194421 155194569 18587559
+71 1 1
+25 8 0
+51
+
+chain 12201 chr6_qbl_hap2 4565931 + 1105096 1105867 6 171115067 - 139876162 139876935 18699321
+54 620 622
+97
+
+chain 12178 chr6_qbl_hap2 4565931 + 3776349 3776515 14 107349540 - 58393926 58394091 18734379
+55 26 25
+85
+
+chain 12008 chr6_qbl_hap2 4565931 + 3700751 3700880 8 146364022 + 49154427 49154556 18990653
+129
+
+chain 11752 chr6_qbl_hap2 4565931 + 3745259 3747655 6 171115067 + 32491461 32493852 19428924
+56 676 682
+61 1516 1505
+87
+
+chain 11746 chr6_qbl_hap2 4565931 + 1097944 1098092 7 159138663 - 7702899 7703047 19437479
+54 14 14
+80
+
+chain 11503 chr6_qbl_hap2 4565931 + 3698827 3699253 11 135006516 - 111045874 111046295 19852910
+57 287 282
+82
+
+chain 10738 chr6_qbl_hap2 4565931 + 3700459 3700580 10 135534747 + 59600699 59600817 21255899
+61 3 0
+57
+
+chain 10686 chr6_qbl_hap2 4565931 + 2478152 2478673 18 78077248 + 11342173 11342695 21355061
+80 388 389
+53
+
+chain 10496 chr6_qbl_hap2 4565931 + 3696510 3696620 1 249250621 - 174039531 174039641 21744609
+110
+
+chain 10342 chr6_qbl_hap2 4565931 + 3714159 3714889 6 171115067 + 32548581 32549235 22073729
+78 598 522
+54
+
+chain 9560 chr6_qbl_hap2 4565931 + 1152614 1152715 6 171115067 - 141323187 141323288 23857063
+101
+
+chain 9560 chr6_qbl_hap2 4565931 + 1099695 1099796 6 171115067 - 141323187 141323288 23857064
+101
+
+chain 9385 chr6_qbl_hap2 4565931 + 3825573 3825778 16 90354753 - 20685009 20685189 24272037
+58 92 67
+55
+
+chain 9214 chr6_qbl_hap2 4565931 + 1102327 1102424 6 171115067 + 29758158 29758255 24607529
+97
+
+chain 9048 chr6_qbl_hap2 4565931 + 3694493 3695083 16 90354753 - 14504923 14505798 16016601
+79 460 745
+51
+
+chain 8993 chr6_qbl_hap2 4565931 + 2558568 2558745 2 243199373 + 116390976 116391155 17783325
+1 102 104
+74
+
+chain 8702 chr6_qbl_hap2 4565931 + 3686082 3686238 6 171115067 + 32439449 32439606 25393693
+54 51 52
+51
+
+chain 8427 chr6_qbl_hap2 4565931 + 3804527 3804616 6 171115067 - 148948316 148948405 15963296
+89
+
+chain 7704 chr6_qbl_hap2 4565931 + 3688237 3688318 6 171115067 + 32557831 32557912 26927503
+81
+
+chain 6794 chr6_qbl_hap2 4565931 + 3775350 3775421 3 198022430 - 94748615 94748686 28659148
+71
+
+chain 6473 chr6_qbl_hap2 4565931 + 3694610 3694683 1 249250621 - 102907635 102907704 21815174
+11 4 0
+58
+
+chain 6457 chr6_qbl_hap2 4565931 + 1158502 1158569 6 171115067 + 30228837 30228904 29438118
+67
+
+chain 6422 chr6_qbl_hap2 4565931 + 3817908 3817976 6 171115067 + 32728707 32728775 29535243
+68
+
+chain 6368 chr6_qbl_hap2 4565931 + 2478912 2479004 6 171115067 - 132617434 132617532 20998654
+55 29 35
+8
+
+chain 5830 chr6_qbl_hap2 4565931 + 1098157 1098218 7 159138663 - 104622057 104622118 31091038
+61
+
+chain 5757 chr6_qbl_hap2 4565931 + 3825218 3825278 14 107349540 - 70017731 70017791 31292281
+60
+
+chain 5558 chr6_qbl_hap2 4565931 + 2472407 2472466 15 102531392 + 37673660 37673719 31870719
+59
+
+chain 5479 chr6_qbl_hap2 4565931 + 1111956 1112025 9 141213431 - 103321949 103322018 11235972
+69
+
+chain 5339 chr6_qbl_hap2 4565931 + 3885926 3885982 X 155270560 + 55718242 55718298 32499987
+56
+
+chain 5185 chr6_qbl_hap2 4565931 + 3788909 3788964 14 107349540 + 22827226 22827281 32987373
+55
+
+chain 5179 chr6_qbl_hap2 4565931 + 1150896 1150960 19 59128983 - 37357346 37357410 20742827
+53 10 10
+1
+
+chain 5176 chr6_qbl_hap2 4565931 + 1100596 1100651 14 107349540 + 79349485 79349540 33029769
+55
+
+chain 5058 chr6_qbl_hap2 4565931 + 3771065 3771119 1 249250621 - 172942963 172943017 33379587
+54
+
+chain 5039 chr6_qbl_hap2 4565931 + 2475495 2475548 7 159138663 - 94193358 94193411 33438564
+53
+
+chain 5038 chr6_qbl_hap2 4565931 + 1148806 1148858 6 171115067 + 29856463 29856515 33456716
+52
+
+chain 4959 chr6_qbl_hap2 4565931 + 3696457 3696510 18 78077248 + 5090594 5090647 22176919
+53
+
+chain 4949 chr6_qbl_hap2 4565931 + 3825516 3825569 X 155270560 - 91231208 91231261 33742123
+53
+
+chain 4829 chr6_qbl_hap2 4565931 + 1159026 1159076 6 171115067 + 30459319 30459369 34177698
+50
+
+chain 4685 chr6_qbl_hap2 4565931 + 3719592 3719642 12 133851895 + 112261417 112261467 34690970
+50
+
+chain 4391 chr6_qbl_hap2 4565931 + 4214058 4214103 X 155270560 - 99494613 99494658 30227326
+45
+
+chain 4348 chr6_qbl_hap2 4565931 + 3739277 3739323 7 159138663 - 76863668 76863714 34891433
+46
+
+chain 4338 chr6_qbl_hap2 4565931 + 2201356 2201401 6 171115067 + 30954494 30954539 34909104
+45
+
+chain 4061 chr6_qbl_hap2 4565931 + 2201872 2201914 6 171115067 + 30955145 30955187 31149648
+42
+
+chain 4003 chr6_qbl_hap2 4565931 + 2470663 2474155 12 133851895 + 104783555 104787047 2981748
+99 961 960
+40 481 480
+76 473 472
+44 1256 1259
+62
+
+chain 3775 chr6_qbl_hap2 4565931 + 2471376 2471416 10 135534747 - 90944157 90944197 25967017
+40
+
+chain 3639 chr6_qbl_hap2 4565931 + 3694572 3694610 3 198022430 + 101411146 101411184 20382400
+38
+
+chain 3574 chr6_qbl_hap2 4565931 + 2470595 2470633 3 198022430 - 173409162 173409200 29596632
+38
+
+chain 3494 chr6_qbl_hap2 4565931 + 3700422 3700459 X 155270560 + 104134375 104134412 29536090
+37
+
+chain 3491 chr6_qbl_hap2 4565931 + 2471293 2472133 8 146364022 - 12751685 12752521 3617865
+79 701 697
+60
+
+chain 3436 chr6_qbl_hap2 4565931 + 2471844 2473225 1 249250621 + 7474211 7475590 2872741
+34 959 957
+58 295 295
+35
+
+chain 3220 chr6_qbl_hap2 4565931 + 3776529 3776563 12 133851895 + 85826623 85826657 35349035
+34
+
+chain 3148 chr6_qbl_hap2 4565931 + 3825631 3825664 2 243199373 + 38182693 38182726 24706670
+33
+
+chain 2975 chr6_qbl_hap2 4565931 + 2478232 2478268 3 198022430 - 94213030 94213066 24807218
+36
+
+chain 2972 chr6_qbl_hap2 4565931 + 1105868 1105908 6 171115067 + 30459045 30459085 20759384
+40
+
+chain 2845 chr6_qbl_hap2 4565931 + 2470633 2470663 3 198022430 - 156603737 156603767 26791326
+30
+
+chain 2838 chr6_qbl_hap2 4565931 + 2474990 2475020 4 191154276 + 92075174 92075204 21730347
+30
+
+chain 2761 chr6_qbl_hap2 4565931 + 3804625 3804685 4 191154276 + 37278694 37278754 22658556
+60
+
+chain 2671 chr6_qbl_hap2 4565931 + 2478852 2478911 9 141213431 - 60456470 60456529 21094091
+59
+
+chain 2604 chr6_qbl_hap2 4565931 + 1151032 1151059 17 81195210 + 6784720 6784747 30920849
+27
+
+chain 2579 chr6_qbl_hap2 4565931 + 3700720 3700751 21 48129895 + 18677639 18677670 26190064
+31
+
+chain 2574 chr6_qbl_hap2 4565931 + 1150960 1151032 X 155270560 + 72544773 72544845 18935818
+72
+
+chain 2481 chr6_qbl_hap2 4565931 + 3804442 3804477 3 198022430 - 58737971 58738006 17138123
+35
+
+chain 2394 chr6_qbl_hap2 4565931 + 2478673 2478698 11 135006516 - 67345781 67345806 29321362
+25
+
+chain 2363 chr6_qbl_hap2 4565931 + 2473435 2473485 3 198022430 - 59783725 59783775 3613581
+50
+
+chain 2322 chr6_qbl_hap2 4565931 + 2470859 2470989 15 102531392 - 72822940 72823070 3150079
+130
+
+chain 2266 chr6_qbl_hap2 4565931 + 2470989 2471957 9 141213431 - 114376815 114377769 4168715
+45 845 831
+78
+
+chain 2263 chr6_qbl_hap2 4565931 + 2471123 2471268 12 133851895 + 84401354 84401499 4041581
+145
+
+chain 2209 chr6_qbl_hap2 4565931 + 2470765 2470818 3 198022430 + 182918728 182918781 9563966
+53
+
+chain 2087 chr6_qbl_hap2 4565931 + 2558317 2558369 X 155270560 - 89201309 89201361 22578016
+52
+
+chain 2078 chr6_qbl_hap2 4565931 + 1112026 1112064 3 198022430 + 120909358 120909396 13027265
+38
+
+chain 2035 chr6_qbl_hap2 4565931 + 2557888 2557938 16 90354753 + 47212776 47212826 17692575
+50
+
+chain 1978 chr6_qbl_hap2 4565931 + 4213820 4213948 15 102531392 - 61555806 61555934 2051418
+28 68 68
+32
+
+chain 1899 chr6_qbl_hap2 4565931 + 2558399 2558424 X 155270560 + 94068150 94068175 17734181
+25
+
+chain 1860 chr6_qbl_hap2 4565931 + 1112180 1112230 8 146364022 + 68079613 68079663 13479327
+50
+
+chain 1860 chr6_qbl_hap2 4565931 + 3812269 3815784 6 171115067 + 32722816 32726965 29521084
+61 2506 2690
+85 515 965
+52 103 103
+193
+
+chain 1828 chr6_qbl_hap2 4565931 + 2473656 2473684 14 107349540 - 54723100 54723128 20222699
+28
+
+chain 1658 chr6_qbl_hap2 4565931 + 1112136 1112169 4 191154276 + 153686345 153686378 11053932
+33
+
+chain 1514 chr6_qbl_hap2 4565931 + 1112233 1112291 13 115169878 - 5205835 5205893 10260311
+58
+
+chain 1396 chr6_qbl_hap2 4565931 + 2473606 2473656 1 249250621 + 83820278 83820328 4577579
+50
+
+chain 1388 chr6_qbl_hap2 4565931 + 4214123 4214166 19 59128983 - 43654778 43654821 2801865
+43
+
+chain 1329 chr6_qbl_hap2 4565931 + 2557727 2557778 7 159138663 - 55106997 55107048 20610784
+51
+
+chain 1304 chr6_qbl_hap2 4565931 + 4213365 4213389 1 249250621 + 182710286 182710310 2078906
+24
+
+chain 1296 chr6_qbl_hap2 4565931 + 4213389 4213424 8 146364022 + 99694 99728 9829550
+12 1 0
+22
+
+chain 1233 chr6_qbl_hap2 4565931 + 2558102 2558133 5 180915260 + 67992831 67992862 12309329
+31
+
+chain 1171 chr6_qbl_hap2 4565931 + 2473569 2473606 X 155270560 - 90928252 90928289 23413190
+37
+
+chain 1170 chr6_qbl_hap2 4565931 + 2471983 2472043 9 141213431 + 232427 232487 4190853
+60
+
+chain 1144 chr6_qbl_hap2 4565931 + 2469449 2469508 2 243199373 + 81796678 81796737 21594602
+59
+
+chain 1125 chr6_qbl_hap2 4565931 + 3694759 3694827 8 146364022 - 86779351 86779419 20749390
+68
+
+chain 1106 chr6_qbl_hap2 4565931 + 1112362 1112413 1 249250621 - 17660691 17660742 13643228
+51
+
+chain 1071 chr6_qbl_hap2 4565931 + 2470508 2470575 12 133851895 + 78891507 78891574 9444392
+67
+
+chain 1040 chr6_qbl_hap2 4565931 + 2470400 2470457 5 180915260 - 146134722 146134779 6672758
+57
+
+chain 1023 chr6_qbl_hap2 4565931 + 2471416 2471471 2 243199373 + 162554783 162554838 24613681
+55
+
+chain 935 chr6_qbl_hap2 4565931 + 2558067 2558102 4 191154276 + 31205 31240 16972854
+35
+
+chain 919 chr6_qbl_hap2 4565931 + 2474702 2474762 4 191154276 + 45112377 45112437 22402157
+60
+
+chain 902 chr6_qbl_hap2 4565931 + 2474552 2474612 5 180915260 - 23766246 23766306 4704228
+60
+
+chain 884 chr6_qbl_hap2 4565931 + 2473696 2473725 1 249250621 - 199045131 199045160 12500824
+29
+
+chain 825 chr6_qbl_hap2 4565931 + 1112413 1112452 1 249250621 - 184583816 184583855 16072417
+39
+
+chain 801 chr6_qbl_hap2 4565931 + 2470111 2470156 1 249250621 - 71436588 71436633 19248116
+45
+
+chain 789 chr6_qbl_hap2 4565931 + 3698600 3699777 19 59128983 + 8446620 8447803 26630175
+58 1059 1065
+60
+
+chain 788 chr6_qbl_hap2 4565931 + 2470239 2470322 6 171115067 + 137168270 137168353 4512040
+83
+
+chain 740 chr6_qbl_hap2 4565931 + 1112667 1112731 12 133851895 + 57178267 57178331 20850792
+64
+
+chain 718 chr6_qbl_hap2 4565931 + 2474782 2474837 9 141213431 - 49469911 49469966 23568604
+55
+
+chain 694 chr6_qbl_hap2 4565931 + 2469923 2469992 X 155270560 - 140437581 140437650 5405913
+69
+
+chain 584 chr6_qbl_hap2 4565931 + 2474349 2474405 15 102531392 + 67105223 67105279 15249534
+56
+
+chain 562 chr6_qbl_hap2 4565931 + 2557778 2557819 X 155270560 + 91975692 91975733 21019876
+41
+
+chain 562 chr6_qbl_hap2 4565931 + 2469824 2469884 2 243199373 - 169790362 169790422 25410177
+60
+
+chain 552 chr6_qbl_hap2 4565931 + 2237356 2237383 17 81195210 - 14890828 14890855 11066346
+27
+
+chain 523 chr6_qbl_hap2 4565931 + 2470057 2470111 13 115169878 + 42049099 42049153 16964924
+54
+
+chain 489 chr6_qbl_hap2 4565931 + 2469992 2470048 14 107349540 + 79003493 79003549 5260265
+56
+
+chain 481 chr6_qbl_hap2 4565931 + 2470189 2470239 8 146364022 + 50441810 50441860 5267091
+50
+
+chain 481 chr6_qbl_hap2 4565931 + 2469386 2469447 1 249250621 - 193322918 193322979 8728434
+61
+
+chain 455 chr6_qbl_hap2 4565931 + 2472488 2472547 6 171115067 - 85200236 85200295 17778688
+59
+
+chain 445 chr6_qbl_hap2 4565931 + 2469210 2469265 X 155270560 - 127487766 127487821 16318369
+55
+
+chain 358 chr6_qbl_hap2 4565931 + 2475020 2475084 4 191154276 + 74158363 74158427 16300933
+64
+
+chain 347 chr6_qbl_hap2 4565931 + 2469153 2469203 15 102531392 - 65978487 65978537 12839283
+50
+
+chain 246 chr6_qbl_hap2 4565931 + 3697415 3697467 12 133851895 - 104314075 104314127 28162397
+52
+
+chain 47340388 chr6_random 1875562 + 1357431 1875562 6 171115067 + 157393490 158069469 78
+906 2 2
+193 1 0
+29 1 0
+8 10 8
+11 2 1
+842 41 40
+754 2304 72101
+91082 5628 50000
+31833 338 50000
+42477 272 0
+39 168 66
+53 1 1
+15 1 103
+64 2 172
+23 1 103
+14474 4 0
+30198 0 8
+1391 2 0
+1319 4 0
+142 0 3
+3412 9 7
+372 1 1
+22 1 1
+5871 0 1
+237 26 25
+3020 1 1
+83 1 1
+141 7 7
+201 2 1
+403 1 0
+3638 1 0
+20 1 0
+552 32 32
+1386 0 1
+4174 1 1
+37 1 1
+3912 5 5
+4160 2 0
+6561 0 1
+3879 0 1
+8665 0 1
+2170 0 3
+895 1 0
+1812 0 1
+36 0 4
+133 1 0
+165 0 9
+427 0 1
+917 1 0
+3166 0 1
+16647 1 0
+6161 10 10
+833 4 0
+1934 1 1
+56 1 1
+2622 9 9
+749 1 0
+482 0 2
+344 1 1
+32 1 1
+868 2 0
+444 0 3
+1096 12 0
+709 0 1
+113 1 1
+35 1 1
+2349 20 0
+175 0 1
+1675 0 2
+1206 0 3
+345 0 5
+4695 1 0
+6715 1 1
+35 1 1
+2131 0 1
+4220 8 0
+2065 1 0
+1986 0 1
+484 0 1
+1543 4 4
+52 22 0
+5090 0 1
+2768 9 2
+12577 0 5
+13727 9 9
+51 4 4
+26 2 3
+11 0 1
+735 1 1
+35 0 1
+12 1 1
+2616 1 0
+327 1 1
+35 1 1
+345 0 20
+50 98 187
+975 1 0
+7329 0 1
+3241 0 35
+583 5 5
+278 1 1
+40 1 1
+123 12 12
+1208 17 0
+477 0 1
+163 1 1
+28 1 1
+3307 1 0
+66 1 1
+25 4 0
+2459 0 1
+1326 1 0
+700 1 0
+2316 6067 13
+725 3 0
+42 1 1
+8162 0 2
+2147 0 2
+79 1 1
+25 1 1
+313 1 0
+2194 1 0
+709 1 1
+33 1 1
+934 4 4
+543 1 1
+37 1 1
+2581 1 0
+606 1 0
+666 1 1
+34 2 2
+250 9 8
+652 1 0
+2306 22 0
+38 0 24
+946 1 0
+3766 1 1
+57 1 1
+3591 2 0
+128 1 1
+1414 7 1
+435 1 1
+29 1 0
+529 0 1
+3649 1 1
+32 0 1
+9760 0 18
+6470 1 1
+49 1 1
+488 0 1
+304 2 0
+1780 0 5
+2759 1 0
+48 1 1
+380 1 1
+33 1 1
+5102 1 1
+33 1 1
+192 0 1
+1103 1 1
+29 1 1
+12912 0 1
+9445 2 0
+2949 1 1
+28 1 1
+826 1 1
+19 1 1
+404 1 1
+49 1 1
+1408 8 0
+1625 10 0
+2962 0 1
+1824
+
+chain 37689909 chr6_random 1875562 + 884671 1286589 5 180915260 - 167715260 168127349 92
+6889 0 1
+34829 1 0
+4156 0 2
+4477 0 8
+7827 0 415
+37 9 9
+207 0 1
+272 7 7
+7925 1 0
+75982 0 1
+11336 0 1
+4233 14 14
+362 10 10
+4607 4 0
+1310 0 3
+1741 4 0
+499 1 1
+69 1 1
+509 15 15
+166 12 8
+145 0 2
+66 1 1
+16 1 1
+325 1 1
+31 1 1
+804 1 1
+109 1 1
+1071 0 106
+73 38 121
+1998 1 1
+37 1 1
+500 0 5
+625 3 0
+2354 1 1
+42 1 1
+1652 0 1
+92 1 1
+68 1 1
+1023 1 1
+16 1 1
+849 2 1
+28 1 1
+1793 4 2
+850 26 26
+251 0 2
+794 1 1
+26 1 1
+798 1 1
+80 1 1
+211 20 12
+153 1 3
+373 6 6
+231 0 4
+302 1 1
+26 1 1
+305 0 4
+3735 1 0
+342 0 2
+2211 0 1
+1969 2 0
+2834 0 10
+1054 0 14
+2176 0 2
+10517 0 2
+3071 6 0
+5697 21 21
+2458 0 5
+1335 3 0
+411 1 5
+2718 10 11
+3652 1 0
+785 1 0
+777 1 0
+2088 0 1
+24 1 1
+1005 16 16
+5426 18 0
+378 1 0
+19 1 1
+5303 0 14
+19 18 0
+2125 1 0
+936 0 5
+29 1 1
+893 19 19
+312 0 2
+32151 1 0
+14548 1 0
+109 0 1
+1481 1 0
+6537 0 2
+3390 1 0
+7479 6 0
+29963 4 0
+3972 9 5
+1637 0 9
+7977 1 0
+1973 0 3
+1212 0 5
+372 29 19
+1216 0 50
+628 0 4
+8388 0 1
+1429 1 0
+3029 2 4
+785 1 0
+291 10 9516
+1642 0 1
+5042 1 0
+1117 1 0
+1558 8 7
+1475 4 0
+1859 0 1
+9528 0 1
+877
+
+chain 31999718 chr6_random 1875562 + 165017 507468 6 171115067 - 55532370 55875067 101
+42954 0 1
+24905 1 0
+579 0 6
+612 0 1
+1128 0 2
+5541 1 1
+30 1 1
+2064 1 0
+505 0 1
+1974 0 1
+5299 1 1
+16 1 1
+368 1 1
+28 1 1
+7024 1 0
+19574 8 9
+6646 4 0
+6060 0 1
+2290 0 1
+22638 6 58
+1402 0 1
+502 0 1
+218 0 1
+5768 0 1
+178 0 3
+659 1 1
+33 0 8
+92 4 0
+693 0 2
+1190 0 3
+375 5 0
+422 3 0
+2215 1 0
+7271 1 1
+33 1 1
+817 1 1
+67 1 1
+2442 1 1
+62 16 0
+165 1 0
+1535 1 1
+32 1 1
+596 4 4
+627 1 1
+22 1 2
+201 5 5
+35 1 1
+232 5 0
+651 4 4
+26 1 1
+105 1 1
+45 1 1
+325 1 1
+34 1 1
+265 1 1
+91 2 0
+1383 1 1
+35 1 1
+1469 19 19
+295 0 1
+644 0 1
+3324 1 1
+44 1 1
+1797 1 5
+21 2 0
+10 11 1
+58 2 0
+61 1 9
+715 0 1
+388 1 1
+47 1 1
+774 1 0
+571 0 3
+2308 0 1
+103 15 15
+1339 1 1
+19 1 1
+348 0 1
+372 1 1
+31 0 1
+4 4 0
+14 1 5
+14 1 25
+4634 1 1
+16 2 2
+305 27 24
+2252 10 217
+1695 0 2
+2541 0 7
+741 2 0
+1401 0 2
+202 2 13
+3853 1 0
+3037 36 0
+18 2 0
+25 94 0
+14 0 4
+487 0 1
+5889 0 1
+572 1 1
+17 1 1
+806 1 1
+24 1 1
+723 0 2
+1640 1 0
+2023 1 1
+21 1 1
+192 15 1
+994 0 106
+1362 2 0
+324 1 1
+19 1 1
+683 1 1
+39 1 0
+771 1 0
+1211 13 0
+1728 1 1
+23 1 1
+911 0 2
+1042 6 6
+206 5 0
+17 1 1
+3351 14 19
+783 1 1
+48 1 1
+673 0 4
+137 1 1
+23 1 0
+1357 4 0
+254 0 1
+1408 0 7
+564 1 1
+49 1 1
+319 13 13
+721 12 12
+821 2 0
+912 4 4
+47 1 1
+148 1 1
+61 1 1
+267 1 1
+46 1 1
+421 1 1
+36 1 1
+577 1 1
+35 1 1
+122 1 1
+95 1 1
+241 1 1
+40 1 1
+585 10 1
+1286 0 1
+97 2 0
+22 1 1
+969 0 1
+1448 14 20
+2000 1 0
+1448 0 1
+2390 1 1
+18 5 5
+1421 1 0
+412 0 1
+1867 2 1
+179 3 0
+852 1 0
+1426 20 18
+151 1 1
+26 1 1
+581 1 1
+86 2 1
+2659 1 0
+12163 2 0
+1149 13 13
+818 16 16
+113 1 1
+51 1 1
+343 1 1
+91 0 4
+7 2 0
+8 0 2
+914 1 1
+28 1 1
+670 1 0
+151 7 7
+1887 18 18
+119 0 5
+2395 2 0
+4395 0 6
+380 6 1
+423 17 17
+531 1 0
+23 0 6
+592 1 1
+23 1 0
+844 4 0
+1497 6 0
+407 17 17
+341 19 17
+1020 0 6
+178 1 0
+1233 0 1
+1861 0 1
+2007 2 0
+6480 1 1
+36 1 1
+6817 17 20
+3356 7 5
+1788 1 1
+83 0 1
+7678 18 18
+2095 1 1
+19 1 1
+4934
+
+chain 25195472 chr6_random 1875562 + 615192 884135 6 171115067 + 167833423 168297434 120
+2006 1 0
+2654 1 1
+28 1 1
+3139 1 1
+85 1 1
+690 0 1
+639 0 2
+1589 4 4
+122 2 0
+1127 0 1
+1104 1 102
+18 0 29
+40 0 3
+22 1 4
+50 0 26
+56 124 195105
+10440 18 25
+3042 0 24
+72 0 8
+206 4 0
+146 4 0
+2483 0 4
+702 0 1
+1035 0 8
+85 3 1
+2710 1 1
+84 1 1
+3774 1 1
+58 1 1
+20613 15 53
+14 32 0
+52 0 4
+1883 4 0
+52 3 0
+44036 171 0
+2224 2 2
+57 1 1
+7263 0 64
+5311 0 2
+24677 8 8
+1972 1 0
+3543 2 2
+46 1 0
+11768 1 0
+494 47 19
+36447 1 1
+67 1 1
+11347 8 0
+4230 1 3
+591 5 5
+1020 0 8
+680 1 1
+60 1 1
+4536 0 1
+1417 0 2
+2471 1 1
+22 1 1
+6781 0 5
+4943 5 0
+1067 2 0
+2588 2 0
+523 34 35
+9266 0 2
+3897 0 2
+1404 0 1
+3120 0 1
+2566 1 0
+1825 0 8
+5342
+
+chain 9830417 chr6_random 1875562 + 510011 615192 5 180915260 - 108917398 109022458 335
+331 57 57
+1247 1 0
+4094 15 15
+6775 12 0
+6148 1 0
+30 1 1
+251 0 1
+26 26 1
+238 1 1
+29 1 1
+148 1 1
+41 1 1
+5831 6 7
+2439 1 0
+4247 12 42
+2333 1 9
+3039 5 0
+476 2 2
+4359 0 1
+1237 11 11
+1223 12 0
+2800 2 0
+2660 0 1
+4531 1 1
+24 1 1
+7407 0 1
+395 2 0
+1841 391 0
+410 50 26
+321 1 1
+27 1 1
+226 9 9
+157 6 6
+80 1 1
+70 1 1
+5158 10 10
+1385 4 0
+991 0 2
+48 1 1
+1083 0 2
+751 0 1
+4266 1 1
+48 1 1
+1557 0 304
+1552 1 1
+21 1 1
+2652 1 0
+598 0 8
+115 15 16
+1277 1 1
+38 1 1
+898 1 1
+27 1 1
+699 0 1
+34 1 1
+279 4 0
+12 1 1
+2863 1 1
+25 1 1
+2484 12 15
+1447 1 0
+8689
+
+chain 8736931 chr6_random 1875562 + 25094 155092 6 171115067 - 3172994 3267843 378
+3079 5 5
+1125 2 0
+1270 7 14
+1955 1 1
+47 1 1
+4538 38 38
+1300 25 26
+67 7 8
+176 3 0
+1132 3 0
+906 103 48
+5311 0 16
+133 1 0
+94 153 987
+142 13 13
+2453 2 0
+238 2 0
+960 13 13
+4697 1 1
+26 1 1
+3575 36650 734
+4434 0 1
+5190 138 107
+33 1 1
+5998 4 0
+1660 1 0
+4740 1 1
+29 1 1
+7196 0 12
+17519 30 29
+12768
+
+chain 553807 chr6_random 1875562 + 1768811 1774813 4 191154276 - 111879139 111885141 10762
+1294 2 2
+109 1 1
+242 1 1
+106 1 1
+2122 1 1
+17 1 1
+200 1 1
+40 1 1
+1071 1 1
+24 1 1
+284 1 1
+77 1 1
+403
+
+chain 255982 chr6_random 1875562 + 1456339 1459136 6 171115067 + 157377507 157380303 364419
+1101 4 4
+21 1 0
+70 43 44
+1490 1 0
+66
+
+chain 238316 chr6_random 1875562 + 1453720 1456237 6 171115067 - 13762873 13765390 431401
+2517
+
+chain 190390 chr6_random 1875562 + 1355230 1357270 6 171115067 - 13765611 13767650 644275
+875 0 1
+30 1 0
+7 0 1
+32 2 0
+1093
+
+chain 147846 chr6_random 1875562 + 163259 164828 10 135534747 - 86648034 86649603 870502
+1569
+
+chain 66179 chr6_random 1875562 + 509035 509994 6 171115067 - 55868072 55869030 1909901
+52 241 240
+666
+
+chain 39557 chr6_random 1875562 + 507468 508471 14 107349540 - 76514262 76515265 2447482
+67 13 13
+252 48 48
+70 43 43
+73 340 340
+97
+
+chain 15445 chr6_random 1875562 + 574580 574743 6 171115067 + 168277787 168277950 14597733
+163
+
+chain 11899 chr6_random 1875562 + 508034 508258 7 159138663 - 61729371 61729595 2527246
+50 119 119
+55
+
+chain 6795 chr6_random 1875562 + 508264 508336 5 180915260 + 74550099 74550171 28643390
+72
+
+chain 5830 chr6_random 1875562 + 884328 884389 6 171115067 - 37135398 37135459 31091070
+61
+
+chain 5767 chr6_random 1875562 + 508601 508846 8 146364022 + 54253304 54253548 3655159
+50 103 102
+92
+
+chain 4821 chr6_random 1875562 + 16131 16182 10 135534747 - 59552661 59552712 34213212
+51
+
+chain 3598 chr6_random 1875562 + 720272 720329 6 171115067 + 168133749 168133806 2857460
+57
+
+chain 3185 chr6_random 1875562 + 1768774 1768810 2 243199373 + 130168617 130168653 16948
+36
+
+chain 2982 chr6_random 1875562 + 508896 508970 12 133851895 - 4327021 4327095 12758815
+74
+
+chain 2685 chr6_random 1875562 + 509240 510388 3 198022430 - 97729559 97730704 3388749
+33 1069 1066
+46
+
+chain 2530 chr6_random 1875562 + 720329 720365 6 171115067 + 168133920 168133956 3810246
+36
+
+chain 2208 chr6_random 1875562 + 720386 720422 6 171115067 + 168133692 168133728 3917950
+36
+
+chain 1957 chr6_random 1875562 + 507800 507848 1 249250621 - 36684504 36684552 2679811
+48
+
+chain 1423 chr6_random 1875562 + 508846 508894 2 243199373 - 143356177 143356225 7803118
+48
+
+chain 1172 chr6_random 1875562 + 508537 508601 X 155270560 + 123719418 123719482 4007841
+64
+
+chain 1047 chr6_random 1875562 + 509273 509328 20 63025520 + 3479096 3479151 2808508
+55
+
+chain 560 chr6_random 1875562 + 508669 508719 5 180915260 - 128392227 128392277 20287927
+50
+
+chain 14618906734 chr7 158821424 + 102995 158821424 7 159138663 + 10238 159128663 7
+973 5 0
+3912 0 2
+1234 4 0
+51 0 6
+70 1 1
+24 1 0
+143 8 0
+16 170 1
+47 1 1
+243 0 6
+913 3 0
+2538 980 0
+63 1610 0
+1362 0 1
+2104 0 456
+1158 0 1
+791 1 1
+49 0 1
+4175 8 0
+17 1 1
+4845 12 0
+2509 0 1
+1697 6 6
+192827 150000 278557
+5682472 0 1
+42007910 40000 35970
+4371 7 16
+17699 0 4
+5249 4 0
+2088410 1 1
+47 1 1
+4565 0 1
+7116 0 1
+2706 40000 43050
+6577293 50000 13552
+1052855 3000000 3000000
+256182 50000 416507
+190137 50000 50000
+5722629 24 25
+239 1 1
+59 2 2
+138 1 1
+34 1 1
+206 1 3
+18 1 0
+410 1 1
+72 1 1
+199 1 1
+62 5 5
+120 1 0
+468 1 1
+32 1 1
+264 1 1
+23 1 1
+1459 4 4
+107 1 1
+42 1 0
+14 1 1
+201 1 1
+46 1 1
+268 20 20
+303 2 1
+866 0 4
+76 3 3
+63 1 1
+74 1 0
+25 1 1
+66 1 1
+34 0 2
+180 35 36
+93 1 1
+41 1 1
+70 1 1
+49 1 1
+63 1 1
+57 1 1
+383 1 1
+133 1 1
+87 1 1
+38 4 4
+50 0 1
+46 5 6
+136 11 11
+200 1 1
+63 4 0
+6 9 0
+263 1 1
+32 3 3
+152 16 16
+567 1 0
+322 3 0
+1258 0 1
+505 4 0
+1141 11 10
+537 12 12
+1418 1 1
+47 0 1
+164 7 7
+90 5 0
+156 1 1
+20 1 1
+380 3 3
+41 3 0
+5 2 2
+921 1 1
+34 1 1
+1607 2 2
+73 66 0
+46 14 0
+168 1 1
+53 1 1
+3195 1 1
+23 1 1
+2115 0 14
+9872 1 0
+1204 13 13
+416 1 0
+2311 319 0
+6906 0 10
+184 24 0
+2933 4 0
+1392 0 12
+1856 5 0
+3439 0 1
+469 3 0
+771 15 12
+497 1 1
+65 1 1
+1210 0 2
+4131 10 10
+1198 1 0
+718 1 1
+21 1 1
+3668 1 0
+874 1 1
+25 1 1
+2444 0 1
+1867 1 1
+29 1 1
+1660 0 1
+1232 0 6
+784 1 0
+705 0 3
+3577 1 0
+365 1 0
+3389 8 4
+2652 0 3
+664 0 1
+169 1 0
+8 1 1
+138 0 1
+8037 0 56
+112 196 0
+495 0 35
+3028 1 1
+40 1 1
+1068 4 0
+631 0 33
+29 2 0
+86 9 1
+3081 2 0
+806 0 1
+21 1 1
+3901 26 27
+843 0 1
+6916420 250000 50000
+25789103 0 51216
+1399994 1 0
+3623 0 212
+38 1 1
+210 1 0
+5 1 0
+6 1 0
+18 1 0
+1321 16 0
+2187 1 0
+145 0 1
+1388 7 7
+2240 14 14
+771 1 1
+34 1 1
+92 1 1
+39 1 1
+505 1 0
+66 1 1
+49 1 1
+159 1 0
+78 3 0
+15 2 0
+7 1 0
+28 1 0
+27 468 5
+2022 1 0
+1796 7 7
+61 1 1
+20 1 1
+4560 3 0
+157730 1 0
+194 14 14
+650 0 12
+717 26 26
+819 0 5
+278 60 32
+69 0 5
+1345 8 0
+652 84 0
+118 0 4
+498 0 1
+3187 1 1
+43 1 1
+1476 0 3
+2101 5 0
+788 6 6
+872 0 6
+893 3 0
+155 33 33
+4610 5 7
+521 10 0
+2773 40 40
+627 43 43
+1424 0 1
+2554 8 8
+44 0 7
+615 1 1
+32 3 0
+2693 0 1
+1029 0 2
+151 0 1
+1753 0 21
+370 2 3
+969 0 1
+452 1 0
+3035 1 1
+40 1 1
+704 0 2
+2472 0 6
+238 1 0
+1442 1 1
+37 5 5
+126 0 1
+795 0 1
+1191 1 0
+171 17 16
+724 6 5
+2988 40 42
+359 2 0
+199 19 19
+1969 1 0
+251 0 1
+729 0 1
+992 27 27
+205 4 0
+3209 0 2
+1006 8 10
+1571 10 10
+756 0 1
+36 1 1
+433 0 1
+672 0 3
+4430 157 0
+5606 5 1
+17 1 1
+942 10 9
+3433 2 1
+24 1 1
+4262 13 0
+661 2 0
+167 8 0
+3474 6 11
+217 0 2
+778 34 34
+158 0 1
+1167 0 1
+684 0 1
+878 39 39
+2012 0 1
+345 52 52
+640 0 2
+27874045 0 136705
+2519 0 2
+1000 8 0
+14695 1 0
+4456 1 0
+2977 1 0
+9065130 25000 29055
+2369 1 0
+12174 18 20
+877 0 4
+5247 0 12
+3483 2 0
+6766 0 1
+2469878 0 1
+734 2 2
+99 0 1
+2471 1 1
+11 1 1
+758 8 0
+2234 13 14
+8394 1 0
+47 1 1
+903 0 1
+5537 0 1
+269 1 0
+7114 1 1
+30 1 1
+2412 0 1
+2442 21 21
+91 1 1
+37 1 1
+96 1 1
+22 1 1
+246 1 1
+23 1 1
+254 12 12
+569 1 1
+27 1 1
+1624 1 0
+112 3 3
+45 1 1
+384 13 13
+70 1 0
+658 1 1
+20 1 1
+176 1 0
+307 19 19
+428 1 1
+19 1 1
+87 1 1
+30 1 1
+140 1 0
+292 2 0
+1492 1 0
+302 0 2
+364 1 1
+35 1 1
+1956 0 1
+728 12 12
+6522 2 2
+1531 1 0
+488 1 0
+2056 18 8
+1286 1 1
+27 1 1
+731 1 0
+1423 0 7
+2010 1 1
+19 1 1
+6423 0 4
+57 1 1
+4505 13 0
+933 0 12
+1250 0 1
+1313 1 0
+2610 0 1
+2398 0 1
+453 1 0
+346 1 1
+12 1 1
+83 25 25
+83 12 12
+277 0 1
+45 1 0
+811 2 0
+164 0 1
+104 0 1
+32 1 1
+1386 0 14
+306 1 1
+43 1 1
+2765 0 1
+1819 0 1
+1480 1 1
+24 1 1
+276 0 1
+21 0 1
+119 2 0
+12 26 0
+541 1 1
+63 1 1
+180 0 1
+2456 1 0
+1055 1 0
+1166 2 0
+784 0 4
+170 1 0
+939 6 0
+5597 15 15
+1253 0 1
+3336 0 18
+1851 9 0
+45 1 1
+657 38 38
+4099 0 1
+1387 2 0
+1460 1 0
+204 0 5
+1506 0 1
+2621 1 0
+6620 0 1
+34 1 1
+249 1 0
+1440 0 10
+245 0 1
+368 1 9
+257 4 0
+1589 6 0
+1543 0 1
+4189 120 0
+354 312446 278046
+3734 24 25
+3097 1 0
+8 1 1
+4861 0 4
+5649 1 0
+2011 0 1
+4344 24 24
+10546 42 1467
+20955 0 1
+2075 2 1
+5546 1 0
+2168 4 0
+1266 1 0
+4124 1 1
+46 1 1
+54 1 1
+43 15 0
+780 1 1
+25 1 1
+497 0 1
+46 1 1
+810 0 1
+5701 0 1
+6998 0 1
+2002 0 3
+7160 1 1
+24 1 1
+479 2 0
+1872 0 1
+1192 1 0
+371 2 0
+31 1 1
+572 16 16
+1725 16 16
+588 1 1
+90 1 1
+2483 3 19
+187 0 1
+20 1 1
+3673 1 1
+27 4 0
+3021 1 0
+1323 19 6
+498 13 13
+1618 2 0
+5282 0 1
+719 0 8
+2994 1 0
+2822 0 2
+1396 1 1
+48 1 1
+8723 5 0
+291 1 1
+25 1 1
+116 0 1
+2809 1 1
+27 1 1
+224 1 1
+48 1 1
+292 0 2
+400 0 1
+754 1 1
+19 1 1
+4225 1 1
+28 1 1
+801 1 0
+671 1 1
+17 1 1
+390 1 1
+28 1 1
+84 7 7
+568 1 1
+56 1 1
+499 7 8
+266 1 1
+31 1 1
+518 18 18
+164 1 1
+50 1 1
+162 1 1
+60 1 1
+702 1 1
+28 1 1
+146 18 17
+517 1 1
+24 1 1
+686 12 12
+101 1 1
+22 5 5
+107 5 5
+277 9 9
+272 1 1
+48 1 1
+77 1 1
+67 1 1
+1548 1 1
+40 1 1
+763 1 1
+42 1 1
+541 8 8
+88 1 1
+77 1 1
+233 11 11
+311 1 1
+22 1 1
+147 1 8
+504 1 1
+26 1 1
+987 20433 0
+3090 1 0
+405 5 5
+1811 1 0
+1174 0 1
+70 1 1
+1100 10143 18
+2722 0 1
+2957 1 1
+32 1 1
+9585 0 1
+1350 0 1
+473 0 1
+675 0 1
+1435 0 1
+805423 0 79189
+10872737 100000 100000
+721570 1 1
+19 1 1
+816 1 1
+44 1 1
+572 8 6
+2021 0 4
+1001 2 0
+3757 1 0
+5942 2 2
+70 1 1
+100 7 7
+395 80000 17188
+1010 1 1
+45 1 1
+1486 18 18
+173 1 17
+15 1 17
+158 0 192
+33 0 368
+50 50 2
+40 1 1
+95 4 52
+60 39 8
+15 16 0
+92 16 0
+1589 0 1
+897 13 13
+28 3 3
+2454 1 1
+44 1 1
+301 0 468
+2030 1 1
+45 1 1
+1277 8 0
+1716 1 0
+1579 11 15
+2439 36 0
+39 37 1
+349 21 92
+2096 13 11
+192 1 1
+48 1 1
+130 1 1
+22 1 1
+970 1 1
+23 4 0
+64 0 14
+129 17 11
+154 13 14
+53 15 5
+48 1 1
+47 0 2
+114 18 16
+363 1 1
+43 1 1
+559 1 1
+32 1 1
+3980007
+
+chain 16701236 chr7 158821424 + 141723881 141902219 7 159138663 - 16862466 17040468 171
+1662 1 1
+69 1 1
+887 1 1
+16 1 1
+115 339 1
+1512 0 1
+3597 0 1
+309 2 0
+34 1 1
+623 0 2
+1746 2 0
+816 4 0
+7868 1 0
+22 0 4
+593 0 1
+2757 0 1
+1147 7 7
+134 1 1
+42 1 1
+669 1 1
+25 1 1
+539 1 1
+49 1 1
+1387 1 1
+53 0 1
+19 1 1
+878 1 1
+27 1 1
+9739 1 1
+15 1 1
+2064 0 1
+1069 1 1
+31 1 1
+612 0 1
+21 1 1
+821 2 0
+1002 2 0
+3478 4 0
+1394 1 1
+25 1 0
+60 1 0
+4 1 0
+10 1 0
+23 0 1
+12 0 1
+2396 1 1
+25 1 1
+401 0 2
+1918 0 2
+43 1 1
+806 1 1
+36 1 1
+126 1 1
+53 1 1
+411 5 5
+524 13 13
+2896 1 1
+62 1 1
+4194 2 0
+8269 2 0
+368 11 10
+546 1 0
+1040 2 0
+45 1 1
+234 1 1
+29 1 1
+1218 16 16
+206 11 11
+584 13 13
+334 4 4
+167 3 3
+31 1 1
+973 9 9
+142 81 81
+58 1 0
+74 1 0
+1707 19 19
+2413 1 1
+57 1 1
+160 1 1
+23 1 1
+2380 0 1
+5561 0 4
+2790 14 14
+76 3 0
+1823 1 1
+11 0 9
+6 2 0
+5 3 0
+9 5 0
+28 1 1
+727 1 1
+37 1 1
+2678 0 3
+1497 1 0
+3414 1 0
+1171 6 6
+4018 7 7
+269 1 1
+36 1 1
+366 1 1
+22 1 1
+916 0 9
+2431 1 1
+68 1 1
+855 4 4
+1052 2 2
+81 0 2
+45 7 7
+648 1 1
+27 1 1
+402 1 0
+791 1 1
+41 1 1
+1041 20 20
+1094 1 1
+29 4 0
+364 1 1
+40 0 1
+22 0 1
+124 0 1
+205 0 1
+720 0 1
+59 1 1
+1063 2 0
+112 2 0
+3106 15 15
+2542 1 1
+64 1 1
+3052 1 1
+73 1 1
+3722 1 1
+31 1 1
+3476 1 0
+229 1 1
+40 1 1
+1321 0 5
+1845 1 0
+558 5 5
+3811 19 19
+125 1 1
+25 1 1
+3387 1 0
+1781 4 4
+2191 0 1
+1201 0 1
+260 1 1
+17 7 7
+137 0 1
+38 1 1
+732 0 1
+1626 1 0
+1987 2 0
+45 1 1
+763 0 1
+1978 0 1
+135 1 0
+6209 1 0
+24 1 1
+4867 0 1
+171 0 1
+6299
+
+chain 6490016 chr7 158821424 + 34000 116005 16 90354753 - 90001 171511 354
+591 11 11
+383 0 4
+1364 1 0
+430 12 13
+1431 1 1
+21 1 1
+490 12 12
+509 1 1
+97 1 1
+604 2 0
+1188 1 3
+665 1 1
+22 6 0
+499 1 1
+19 1 1
+402 1 1
+51 1 1
+1193 0 4
+245 1 0
+688 0 1
+975 2 0
+463 0 23
+73 24 0
+32 7 0
+165 1 0
+1593 1 1
+20 1 1
+1203 1 1
+31 1 1
+740 2 0
+47 1 1
+485 1 1
+63 1 1
+381 5 0
+28 1 1
+254 1 1
+22 1 1
+306 0 1
+34 1 1
+283 0 2
+627 10 10
+74 1 1
+50 1 1
+1053 0 1
+54 1 1
+77 1 1
+210 1 1
+70 0 3
+1957 0 4
+2154 1 1
+69 1 1
+147 67 67
+69 1 1
+74 1 1
+242 1 1
+41 1 1
+63 5 5
+155 3 1
+101 1 1
+53 1 1
+877 1 1
+21 1 1
+60 1 1
+49 1 1
+167 1 1
+21 1 1
+623 15 15
+202 0 97
+86 0 49
+9 2 2
+84 5 248
+56 1 98
+40 0 1
+48 1 0
+87 1 1
+55 99 1
+50 50 0
+23 1 1
+81 0 194
+78 1 1
+55 3 3
+53 6 344
+15 1 1
+262 1 1
+80 1 1
+455 1 1
+108 3 3
+431 1 1
+101 1 1
+158 1 0
+9 1 1
+323 3 0
+85 1 1
+19 1 1
+345 32 0
+24 1 1
+342 1 1
+65 1 1
+90 8 8
+545 1 1
+130 2 2
+87 4 3
+62 3 3
+34 2 2
+77 1 1
+47 1 1
+61 1 1
+27 1 1
+224 7 7
+117 2 0
+17 1 1
+242 1 1
+34 1 1
+107 1 1
+36 1 1
+100 15 15
+154 0 8
+13 1 0
+34 5 5
+100 27 27
+263 11 11
+116 1 1
+41 1 1
+117 1 1
+49 1 1
+116 2 0
+70 1 1
+174 1 1
+125 1 1
+70 1 1
+30 1 1
+74 1 1
+32 1 1
+337 1 1
+49 1 1
+2127 1 1
+35 1 1
+538 1 1
+32 1 1
+744 10 10
+471 53 17
+2001 7 7
+453 1 0
+2656 0 1
+1785 1 0
+1454 1 1
+33 1 1
+419 1 1
+49 1 1
+4610 1 1
+36 1 1
+905 1 1
+13 0 2
+5128 17 17
+519 0 3
+613 7 0
+660 0 4
+2632 1 2
+278 21 21
+969 1 0
+2852 14 14
+149 1 1
+21 1 1
+198 1 1
+29 1 1
+801 6442 6416
+125 6 0
+39 3745 3755
+814 162 1
+4 63 63
+74 63 0
+47 1056 13
+370
+
+chain 227647 chr7 158821424 + 141707499 141716076 7 159138663 + 142043811 142047809 475649
+53 484 465
+55 51 51
+78 242 220
+60 274 271
+51 13 13
+51 37 37
+229 4 4
+228 16 16
+108 47 47
+50 4583 49
+498 131 130
+945 36 36
+253
+
+chain 87685 chr7 158821424 + 58756 115635 3 198022430 - 71488 126874 406
+67 3328 3375
+28 1 1
+29 2 2
+39 50 50
+7 2 2
+41 2708 1663
+32 2831 2828
+27 46647 46820
+96 378 0
+152 47 12
+72 252 0
+43
+
+chain 48969 chr7 158821424 + 142175391 142175904 7 159138663 + 142475439 142475952 2613549
+513
+
+chain 47803 chr7 158821424 + 141911444 141913842 7 159138663 - 17029555 17031946 2683091
+78 139 139
+57 226 225
+124 92 92
+56 135 135
+72 193 193
+53 23 23
+133 958 952
+59
+
+chain 43189 chr7 158821424 + 142199519 142199970 7 159138663 + 142498738 142499189 3009311
+451
+
+chain 30396 chr7 158821424 + 67364377 67364696 15 102531392 - 56463077 56463396 4465114
+319
+
+chain 30094 chr7 158821424 + 141700053 141707301 7 159138663 + 142042846 142043613 4669748
+89 15 15
+68 6585 104
+66 129 129
+62 35 35
+199
+
+chain 30060 chr7 158821424 + 141963578 141964737 11 135006516 + 33264685 33266127 4680203
+91 398 397
+87 228 512
+77 163 163
+115
+
+chain 28591 chr7 158821424 + 141910578 141910878 7 159138663 - 17028690 17028990 5361712
+300
+
+chain 21822 chr7 158821424 + 141716123 141716468 7 159138663 + 142047850 142048195 9124304
+170 99 99
+76
+
+chain 20144 chr7 158821424 + 142166403 142167075 9 141213431 + 33792981 33793662 10344618
+82 380 389
+66 18 18
+51 19 19
+56
+
+chain 16654 chr7 158821424 + 101805867 101806156 7 159138663 - 92369277 92369565 11127744
+33 12 11
+63 91 91
+90
+
+chain 14923 chr7 158821424 + 102039289 102039446 7 159138663 + 102153090 102153247 2823
+157
+
+chain 10542 chr7 158821424 + 115456 115592 16 90354753 - 170836 170972 2672410
+136
+
+chain 10012 chr7 158821424 + 114469 115025 9 141213431 - 90660 90901 550
+63 395 80
+98
+
+chain 9195 chr7 158821424 + 141943788 141943884 7 159138663 - 16914722 16914818 24637833
+96
+
+chain 8667 chr7 158821424 + 142177809 142178136 7 159138663 + 142477851 142478180 25450135
+54 219 221
+54
+
+chain 7349 chr7 158821424 + 142180607 142180684 7 159138663 + 142480664 142480741 27551182
+77
+
+chain 7340 chr7 158821424 + 142180197 142180274 7 159138663 + 142480253 142480330 27565643
+77
+
+chain 6886 chr7 158821424 + 141960844 141960917 8 146364022 - 77913390 77913463 28463282
+73
+
+chain 6730 chr7 158821424 + 102059075 102062034 7 159138663 + 102172727 102175692 3338
+34 2887 2893
+38
+
+chain 6431 chr7 158821424 + 142166514 142166582 7 159138663 + 142454997 142455065 29498865
+68
+
+chain 6414 chr7 158821424 + 114166 115456 9 141213431 - 90644 91234 1816570
+68 791 378
+44 328 41
+59
+
+chain 6276 chr7 158821424 + 142176939 142177005 7 159138663 + 142476982 142477048 29891950
+66
+
+chain 6166 chr7 158821424 + 142179945 142180009 7 159138663 + 142480002 142480066 30171758
+64
+
+chain 5761 chr7 158821424 + 141963726 141963989 14 107349540 - 25420241 25420503 6848073
+68 130 129
+65
+
+chain 5666 chr7 158821424 + 142179798 142179857 7 159138663 + 142479855 142479914 31548103
+59
+
+chain 5608 chr7 158821424 + 101977370 101977454 7 159138663 + 44036096 44036185 7960
+10 0 5
+74
+
+chain 5430 chr7 158821424 + 142178562 142178619 7 159138663 + 142478613 142478670 32231795
+57
+
+chain 5139 chr7 158821424 + 142176520 142176574 7 159138663 + 142476565 142476619 33117712
+54
+
+chain 5020 chr7 158821424 + 141966623 141966675 12 133851895 + 53762512 53762564 33527602
+52
+
+chain 4939 chr7 158821424 + 142176195 142176247 7 159138663 + 142476241 142476293 33775264
+52
+
+chain 4778 chr7 158821424 + 73598 73651 5 180915260 - 172444 172497 587
+53
+
+chain 4039 chr7 158821424 + 101996220 101996263 7 159138663 + 102308194 102308237 1871
+43
+
+chain 3908 chr7 158821424 + 142167123 142167183 7 159138663 + 142455620 142455680 17639294
+60
+
+chain 3217 chr7 158821424 + 141963833 141963883 6 171115067 - 41704900 41704950 22743877
+50
+
+chain 2759 chr7 158821424 + 67423135 67423165 7 159138663 + 67785172 67785202 11329361
+30
+
+chain 2575 chr7 158821424 + 67423107 67423135 7 159138663 + 67785172 67785200 11329362
+28
+
+chain 2575 chr7 158821424 + 67423079 67423107 7 159138663 + 67785172 67785200 11329363
+28
+
+chain 2575 chr7 158821424 + 67423051 67423079 7 159138663 + 67785172 67785200 11329364
+28
+
+chain 2575 chr7 158821424 + 67423023 67423051 7 159138663 + 67785172 67785200 11329365
+28
+
+chain 2575 chr7 158821424 + 67422995 67423023 7 159138663 + 67785172 67785200 11329366
+28
+
+chain 2457 chr7 158821424 + 114257 114311 16 90354753 - 170806 170860 17475755
+54
+
+chain 2391 chr7 158821424 + 67422969 67422995 7 159138663 + 67785202 67785228 13667102
+26
+
+chain 2359 chr7 158821424 + 101974113 101974139 7 159138663 + 102286210 102286236 158723
+26
+
+chain 1502 chr7 158821424 + 141709533 141709580 7 159138663 + 142013474 142013521 12917072
+47
+
+chain 721 chr7 158821424 + 141963699 141963726 17 81195210 + 19853796 19853823 7983736
+27
+
+chain 615 chr7 158821424 + 141964154 141964190 19 59128983 - 28688778 28688814 21921932
+36
+
+chain 362 chr7 158821424 + 101987601 101987634 7 159138663 - 57149003 57149036 1101
+33
+
+chain 17312866 chr7_random 549659 + 162804 345700 GL000195.1 182896 + 0 182896 164
+182896
+
+chain 10142542 chr7_random 549659 + 0 112804 7 159138663 + 158928464 159038297 315
+4073 0 1
+5056 1 0
+1766 1 1
+63 5 5
+2422 1 0
+1297 1 0
+1967 196 0
+230 28 0
+2331 5 0
+47 1 1
+345 1 0
+41 1 1
+807 1 1
+31 1 1
+238 3 0
+100 1 0
+281 1 1
+43 1 1
+359 27 26
+59 1 1
+43 1 1
+1385 1 0
+161 1 0
+45 1 1
+1693 1 0
+93 1 0
+5 1 0
+805 0 3
+649 0 49
+1400 1 1
+4 1 0
+28 0 1
+7 0 1
+157 1 1
+117 0 31
+166 13 12
+138 1 0
+556 1 1
+46 1 1
+204 1 1
+21 1 1
+511 2 0
+390 1 1
+29 1 1
+60 1 1
+68 0 3
+27 1 1
+71 0 1
+37 5 0
+18 0 6
+56 3 3
+89 2 0
+103 6 15
+43 5 0
+7 0 11
+55 0 4
+456 46 45
+1286 1 1
+46 1 0
+36 2 0
+57 1 0
+396 1 1
+38 1 1
+298 1 1
+16 1 1
+602 224 0
+82 1 56
+1115 1 74
+17 3 3
+88 1 74
+98 158 12
+90 3 3
+70 3 3
+117 1 1
+43 1 1
+53 1 1
+21 1 1
+53 229 10
+120 81 8
+59 8 10
+411 1 0
+47 1 1
+723 0 9
+8142 6 6
+1297 1 1
+22 0 1
+7799 12 11
+1878 1 0
+70 5 5
+592 1 1
+28 1 1
+2251 1 0
+1474 1 0
+1975 0 1
+2577 0 1
+612 15 15
+93 1 0
+3 1 0
+149 1 0
+61 3 3
+34 1 0
+11 2101 0
+63 73 3
+67 106 1
+57 83 13
+60 70 0
+79 561 1
+321 70 0
+262 0 35
+83 183 8
+2406 0 549
+85 32 0
+27 0 26
+72 0 35
+22 3 0
+24 0 93
+74 2 0
+17 28 0
+63 1 0
+6 1 0
+1451 44 4
+23 1 1
+38 0 40
+80 1 121
+34 1 1
+58 0 82
+839 1 0
+31 1 1
+2861 0 4
+1376 1 1
+20 0 1
+78 2 0
+24 2 2
+2760 3 1
+585 8 0
+761 1 0
+6449 4 1
+259 1 1
+22 1 1
+717 0 1
+887 7 8
+2174 3 0
+970 1 0
+1768 12 0
+4378 0 1
+5 0 1
+13 1 0
+1637 5 10
+312 0 1
+2167 11 0
+164 10 10
+1517 1 1
+42 0 3
+698 0 4
+90 1 1
+20 1 1
+167 1 1
+16 1 1
+860 0 1
+1719
+
+chain 9633059 chr7_random 549659 + 402818 549659 7 159138663 + 514489 666751 345
+3766 22099 5004
+26 4 4
+11014 7 5
+17 1 0
+8 21 0
+3389 1 1
+54 1 1
+55 1 1
+66 1 1
+165 1 1
+38 1 1
+52 22350 21842
+816 4 4
+10432 15 15
+20532 1 1
+29 9 9
+13871 157 23205
+37837
+
+chain 2073422 chr7_random 549659 + 444161 465736 7 159138663 - 158510053 158531628 1246
+21575
+
+chain 1225579 chr7_random 549659 + 415456 428202 7 159138663 + 537499 550245 1943
+12746
+
+chain 745495 chr7_random 549659 + 406711 414469 7 159138663 - 158580384 158588142 6708
+215 11 11
+2423 4 4
+5105
+
+chain 224185 chr7_random 549659 + 399770 402202 7 159138663 + 518876 521308 490490
+367 50 50
+1609 1 1
+53 3 3
+304 1 1
+44
+
+chain 25943 chr7_random 549659 + 67571 70764 7 159138663 + 158995434 158996421 1881723
+67 73 3
+55 13 153
+17 71 0
+159 183 8
+119 21 21
+154 1960 0
+64 35 0
+105 35 0
+62
+
+chain 21070 chr7_random 549659 + 68795 70055 7 159138663 + 158995572 158996097 2684005
+86 98 63
+43 35 0
+76 455 0
+18 248 38
+61 57 57
+83
+
+chain 19298 chr7_random 549659 + 67796 68209 7 159138663 + 158995799 158996246 2040899
+35 195 229
+183
+
+chain 8295 chr7_random 549659 + 70341 70449 7 159138663 + 158996348 158996421 13908836
+11 35 0
+62
+
+chain 8007 chr7_random 549659 + 70264 70825 7 159138663 + 158995746 158996237 2373081
+77 186 46
+35 218 288
+45
+
+chain 7010 chr7_random 549659 + 69669 69742 7 159138663 + 158996026 158996099 13809421
+73
+
+chain 6757 chr7_random 549659 + 71674 71744 7 159138663 + 158996246 158996316 26425870
+70
+
+chain 6582 chr7_random 549659 + 16740 16849 7 159138663 + 158945342 158945395 9902405
+48 56 0
+5
+
+chain 5793 chr7_random 549659 + 36845 36905 7 159138663 + 158964922 158964982 31172491
+60
+
+chain 5504 chr7_random 549659 + 68645 69446 7 159138663 + 158995947 158996153 2767372
+68 176 1
+63 420 0
+74
+
+chain 5075 chr7_random 549659 + 34499 34552 7 159138663 + 158962931 158962984 33354772
+53
+
+chain 4386 chr7_random 549659 + 36139 36193 7 159138663 + 158964435 158964489 9901820
+54
+
+chain 4359 chr7_random 549659 + 69809 69854 7 159138663 + 158996061 158996106 24027999
+45
+
+chain 3345 chr7_random 549659 + 71561 71653 7 159138663 + 158995923 158996015 5823696
+92
+
+chain 3242 chr7_random 549659 + 36212 36249 7 159138663 + 158964435 158964472 7647561
+37
+
+chain 3169 chr7_random 549659 + 68713 69336 7 159138663 + 158995385 158995658 13517397
+46 500 150
+77
+
+chain 2856 chr7_random 549659 + 36091 36138 7 159138663 + 158964168 158964215 3415068
+47
+
+chain 2508 chr7_random 549659 + 74235 74267 7 159138663 + 158999705 158999737 11181217
+32
+
+chain 2422 chr7_random 549659 + 16701 16740 7 159138663 + 158944995 158945034 20425801
+39
+
+chain 2296 chr7_random 549659 + 76078 76102 7 159138663 + 159001472 159001496 26237556
+24
+
+chain 1888 chr7_random 549659 + 68772 68795 7 159138663 + 158995829 158995852 23967691
+23
+
+chain 1646 chr7_random 549659 + 16653 16684 7 159138663 + 158945171 158945202 6593972
+31
+
+chain 1510 chr7_random 549659 + 34573 34664 7 159138663 + 158962893 158962984 9181320
+91
+
+chain 1319 chr7_random 549659 + 70142 70185 7 159138663 + 158996289 158996332 23051286
+43
+
+chain 1065 chr7_random 549659 + 69520 69582 7 159138663 + 158996297 158996359 18766264
+62
+
+chain 13483752813 chr8 146274826 + 0 146274826 8 146364022 + 10000 146304022 9
+930417 1 1243
+52 10 10
+44 0 972
+100 0 54
+162 0 324
+409 0 1
+2323216 1 0
+3352649 2 0
+854996 100000 50000
+3399023 1 1
+46 1 1
+13965 1 1
+30 1 1
+121189 1 1
+35 1 1
+283700 0 1
+719291 100016 93054
+1155 0 2
+755 26 26
+980 21 21
+1479 54 54
+3597 1 0
+1937 19 19
+322 1 0
+1758 2 0
+1141 0 1
+956 48 48
+739 21 21
+1005 0 1
+543 1734 1734
+5338 15 15
+1029 1 1
+28 1 1
+305 57 57
+164 27 27
+5130707 0 1
+1288 0 1
+446 1 1
+80 1 1
+2123 4 4
+2514 3 0
+545 9 0
+527 1 1
+18 1 1
+256 9 9
+79 1 1
+40 1 1
+148 0 2
+2231 0 27
+958 1 1
+20 1 1
+2487 1 1
+113 1 1
+73 13 13
+365 10 10
+151 1 1
+32 3 0
+26 1 1
+1480 1 1
+29 1 1
+621 1 1
+28 1 1
+701 9 9
+362 1 1
+19 1 1
+691 1 1
+44 6 0
+47 1 1
+513 12 11
+382 1 1
+22 1 1
+111 1 1
+36 1 1
+337 1 1
+42 1 1
+602 2 0
+36 1 1
+475 1 1
+23 0 1
+32 4 3
+65 1 1
+59 1 1
+688 1 1
+22 1 1
+1473 1 1
+36 1 1
+372 1 1
+16 6 6
+1605 1 1
+38 1 1
+816 1 1
+17 1 0
+374 1 1
+17 1 1
+48 1 0
+82 1 1
+45 1 1
+263 1 1
+23 1 1
+204 1 1
+39 1 1
+2341 0 1
+2989 9 11
+811 8 8
+741 0 2
+337 1 1
+25 4 4
+763 1 1
+19 1 1
+343 1 1
+31 1 1
+1953 1 1
+74 1 1
+67 1 1
+18 4 4
+73 1 1
+31 1 1
+114 11 1
+87 1 1
+65 1 1
+125 9 9
+378 49 48
+90 1 1
+99 1 0
+173 13 7
+696 0 1
+6184 13 13
+830 13 13
+128 1 1
+37 1 1
+136 1 0
+66 5 6
+870 1 0
+4877 0 1
+585 3 7
+1728 1 0
+33 1 1
+465 1 1
+68 1 1
+581 6 0
+2088 1 0
+304 0 1
+2674 1 1
+28 1 0
+54 8 8
+846 0 1
+1409 16 16
+559 0 1
+407 0 5
+11 5 1
+29 1 1
+4051 1 1
+10 0 1
+43 1 1
+385 1 1
+35 1 1
+101 11 11
+602 1 0
+491 14 16
+1366 19 19
+321 1 1
+49 1 1
+546 1 1
+25 1 1
+2568 1 1
+51 4 0
+119 1 1
+39 0 1
+1040 0 1
+1682 0 4
+39 8 0
+862 1 1
+17 1 1
+587 1 1
+21 1 1
+904 0 1
+261 0 1
+1151 0 2
+2325 5 5
+5415 0 3
+1545 1 0
+428 4 4
+1950 2 0
+1073 0 1
+3653 0 86
+1283 1 1
+79 1 1
+6656 12 12
+1550 0 18
+5832 1 0
+4835 10 10
+1719 1 1
+84 1 1
+848 0 2
+236 1 1
+42 1 1
+1272 12 0
+49 1 1
+820 1 1
+22 1 0
+58 0 22
+510 8 8
+983 6 0
+539 14 14
+863 0 2
+27 1 1
+204 14 14
+163 4 4
+290 1 1
+59 1 1
+842 0 2
+2044 1 1
+90 0 1
+3434 0 3
+356 0 1
+873 0 1
+864 25 1
+630 12 7
+62 10 10
+156 11 11
+1364 19 19
+156 4 4
+244 4 18
+505 1 0
+109 1 1
+230 1 1
+107 4 3
+150 1 1
+83 5 5
+70 1 1
+33 1 0
+142 1 1
+626 5 6
+274 10 10
+128 1 1
+35 1 1
+216 1 1
+44 1 1
+312 1 1
+16 1 1
+1496 8 7
+451 0 1
+855 1 1
+20 1 1
+350 1 1
+62 1 1
+617 10 10
+845 1 1
+58 1 1
+2189 1 1
+147 1 1
+475 1 1
+27 1 1
+278 1 1
+17 1 1
+994 1 1
+40 1 1
+219 5 5
+26 1 1
+900 1 1
+29 1 0
+26 1 1
+484 15 16
+61 9 9
+114 21 26
+801 1 1
+33 1 1
+560 1 1
+37 1 1
+80 14 14
+211 1 1
+43 1 1
+156 1 1
+20 1 1
+685 1 1
+18 1 1
+48 4 0
+711 1 1
+38 1 1
+402 7 7
+1045 1 1
+37 1 1
+4035 9 9
+247 4 0
+4146274 17400 5734
+330366 0 1
+2346742 0 55
+413177 3 0
+450 1 0
+9436 3 1
+7044 4 0
+2886 1 0
+635 1 0
+16567 1 0
+6926 29 28
+9249 1 0
+14916 8 0
+12872 2 0
+3330 2 0
+2673376 2 0
+2603 1 1
+78 1 1
+2170491 7 7
+29817 66108 2485
+6473782 5 5
+39 1 1
+9574 0 2
+5879 1 1
+29 1 1
+6139 1 0
+2354 1 1
+28 1 1
+91 88 87
+142 16 15
+54 1 1
+22 3 3
+1479 4 4
+221 4 4
+132 1 0
+574 11 11
+23 1 0
+604 1 1
+44 1 1
+899 1 0
+70 1 0
+10 1 0
+13561 1 1
+44 1 1
+4476 4 4
+799 26 25
+1466 18 18
+17897 4 0
+1667 1 0
+4250 1 1
+44 1 3
+14 1 1
+4956 1 1
+18 1 0
+39 3 2
+4990 1 1
+47 13 13
+69 4 0
+9729 1 0
+355 0 1
+2186 1 1
+37 1 1
+6111 3 3
+100 4 4
+68 1 1
+43 1 1
+1126 5 7
+5520 8 8
+2316 1 1
+181 6 6
+50 1 1
+29 1 0
+83 1 1
+1073 245 639
+150 1 1
+25272 0 1
+2132 0 4
+2522 1 1
+48 1 1
+1498528 0 1
+6044582 3000008 3000000
+1291113 60074 16691
+3837 3 0
+811 1 0
+2567 1 0
+7375465 11 11
+42062 1 0
+19604621 1 0
+10692667 1 0
+110 0 1
+3577 0 3
+907 1 1
+18 1 1
+897 1 1
+64 535 251
+21 0 1
+140 0 1
+70 1 0
+77 9 10
+149 4 0
+5 1 5
+68 1 0
+142 5 5
+57 14 14
+43 1 1
+31034 124100 99683
+2301 0 2
+44 2 0
+568015 87325 183549
+330 5 5
+114 0 3088
+1776 0 3085
+949 0 4
+514 37 37
+963 15 14
+1351 71 71
+56 15 15
+405 713 713
+651 1 1
+41 1 1
+837 1 0
+658 0 1
+794 0 1
+73 1 1
+30 1 1
+817 51 51
+566 72 72
+195 0 12193
+1599 0 3085
+217 43 43
+247 29 29
+4148 1 0
+158 266 266
+696 20 20
+58 69 69
+100 13 13
+326 137 137
+151 35 35
+1804 151 151
+1341 289 289
+154 23 23
+1932 17 17
+111 47 47
+128 16 16
+78 30 30
+1022 6 10
+78 1 0
+342 31 31
+86 23 23
+1601 41 41
+144 49 49
+170 10 10
+398 23 23
+419 20 20
+955 55 55
+1139 11 11
+1925 0 276
+223 58 58
+702 25 25
+1030 23 23
+363 164 164
+653 16 16
+78 13 13
+1035 0 4
+514 37 37
+1069 10 10
+321 15 15
+603 68 68
+789 20 20
+56 25 25
+1007 5 5
+1198 24 24
+689 3 0
+743 32 32
+817 43 43
+574 11 11
+123 19 19
+618 28 28
+1270 15 15
+289 29 29
+106 11 11
+1395 46 46
+850 4 4
+777 62 62
+86 36 36
+374 97 97
+2072 31 31
+195 56 56
+379 80 80
+64 11 11
+191 18 18
+1051 13 13
+52 163 169
+1297 1 1
+25 1 1
+3451 0 188
+3097 0 9
+2715 1 0
+11829 0 3
+6001 28 0
+10728 0 1
+3770769 1 0
+62 1 0
+22 1 0
+827 1 0
+1485 1 0
+242 0 1
+7142 1 0
+4029 3 3
+69 1 1
+15865 1 0
+83463 4 0
+5976 9 0
+2661 1 0
+1483 1 0
+15868 4 0
+17798 1 0
+2649 1 0
+3627 1 0
+4789 1 0
+9541 1 0
+6844 1 0
+3187 2 0
+411 14 0
+3056 4 0
+19776 3 0
+29085 0 1
+745 2 0
+11453 2 0
+16739 1 0
+14697 1 0
+8539 1 0
+25514443 1 0
+17680 0 1
+55359 0 1
+58 57 59
+1515 1 0
+1111 1 0
+5736 6 6
+66213 1 0
+68 1 1
+24 6 7
+43 1 1
+33414 7 7
+22 1 1
+19312 0 1
+8588 1 1
+31 1 1
+15969 1 1
+32 1 1
+27034 1 1
+42 1 1
+3352 0 1
+15009 1 0
+20433 18 18
+32141 9 8
+116 41 41
+4920 1 0
+33364 1 0
+11160 15 17
+28423 1 0
+43835 1 1
+24 4 2
+269244 4 4
+37 1 1
+17193 4 3
+53 12 11
+23 2 1
+7 1 1
+37978 9 9
+37743 1 1
+35 3 3
+26636 1 1
+17 1 1
+8728292 1 0
+16734742 0 71275
+27 1 1
+657033 0 2
+2911 0 2
+1941 1 1
+35 1 1
+835 1 1
+116 1 1
+399 1 1
+101 1 0
+194 1 2
+450 1 0
+825 1 1
+73 1 1
+156 1 1
+58 1 1
+50 5 5
+153 11 11
+189 5 5
+233 1 1
+83 1 1
+642 0 1
+1380 1 1
+17 1 1
+315 1 1
+26 1 1
+786 0 901
+76 1 1
+45 1 1
+535 1 1
+34 1 1
+2007 7 7
+159 1 1
+26 1 1
+6362 13 13
+504325 100008 25635
+420771 0 232
+287680 0 104
+73 0 364
+181 0 55
+95 1 1
+46 1 1
+4002 1 1
+24 1 1
+183 49 0
+72 1 2
+8 1 0
+39 688 1
+306 0 50
+1939 0 1
+615 684 0
+254 0 1
+572035 7362 108542
+480202 1 0
+11866 6 6
+26917 0 1
+6097 15 15
+3074 0 1
+12292 0 1
+2209 0 1
+7358 0 1
+321393
+
+chain 161719 chr8 146274826 + 12213564 12217654 8 146364022 + 11922619 11926713 3890
+48 2333 2337
+1544 26 26
+139
+
+chain 94297 chr8 146274826 + 86864948 86909782 8 146364022 + 86767902 86816113 712
+43 4583 4586
+51 23 23
+69 22 22
+81 3466 3466
+114 1460 1461
+170 2237 2237
+47 3442 3445
+24 161 161
+49 1995 1995
+32 5554 5830
+116 4 4
+12 2309 5394
+37 2018 2018
+68 865 865
+25 3669 3669
+32 817 817
+42 1346 1346
+28 1574 1574
+29 1512 1515
+46 1652 1652
+41 2665 2665
+30 2224 2230
+50
+
+chain 49697 chr8 146274826 + 86036864 86037399 8 146364022 + 85964814 85965349 932809
+535
+
+chain 26725 chr8 146274826 + 86857851 86907733 8 146364022 + 86754632 86786590 1026
+491 49362 31438
+29
+
+chain 24621 chr8 146274826 + 145396034 145396288 8 146364022 + 145493131 145493385 2960834
+254
+
+chain 18039 chr8 146274826 + 144819613 144819801 8 146364022 + 144748845 144749033 12082915
+188
+
+chain 14890 chr8 146274826 + 86857082 86862299 8 146364022 - 59611598 59616815 1124
+71 476 476
+222 4397 4397
+51
+
+chain 13243 chr8 146274826 + 144819801 144819938 8 146364022 + 144748593 144748730 12136518
+137
+
+chain 9530 chr8 146274826 + 144823061 144823289 8 146364022 + 144751680 144751756 18947814
+3 152 0
+73
+
+chain 9463 chr8 146274826 + 144819938 144820036 8 146364022 + 144748632 144748730 13619337
+98
+
+chain 8087 chr8 146274826 + 86874741 86874834 8 146364022 + 86817360 86817453 1088
+93
+
+chain 7965 chr8 146274826 + 86865238 86879045 8 146364022 + 86780387 86797281 766
+29 7982 7984
+37 5729 8814
+30
+
+chain 7439 chr8 146274826 + 12201270 12203830 8 146364022 + 11910337 11912897 3584
+26 2480 2480
+54
+
+chain 6315 chr8 146274826 + 86909619 86909690 8 146364022 + 86556151 86556222 765064
+71
+
+chain 6303 chr8 146274826 + 144823559 144823625 8 146364022 + 144751722 144751788 29838951
+66
+
+chain 5756 chr8 146274826 + 86854716 86862896 8 146364022 + 86782059 86817706 1940
+37 8112 35579
+31
+
+chain 5521 chr8 146274826 + 144823643 144823701 8 146364022 + 144751730 144751788 31959915
+58
+
+chain 5339 chr8 146274826 + 144823077 144823133 8 146364022 + 144751620 144751676 32492605
+56
+
+chain 4702 chr8 146274826 + 144819343 144819392 8 146364022 + 144748967 144749016 12082914
+49
+
+chain 4684 chr8 146274826 + 144823154 144823323 8 146364022 + 144751621 144751752 19314390
+33 102 64
+34
+
+chain 4385 chr8 146274826 + 144820066 144820134 8 146364022 + 144748613 144748681 20813384
+68
+
+chain 3959 chr8 146274826 + 144820160 144820201 8 146364022 + 144748560 144748601 13619336
+41
+
+chain 3959 chr8 146274826 + 144819572 144819613 8 146364022 + 144748560 144748601 13619338
+41
+
+chain 3270 chr8 146274826 + 86905368 86905406 8 146364022 - 59611399 59611437 120315
+38
+
+chain 3190 chr8 146274826 + 144819513 144819546 8 146364022 + 144748697 144748730 12136519
+33
+
+chain 2525 chr8 146274826 + 144823339 144823377 8 146364022 + 144751692 144751730 23202086
+38
+
+chain 2511 chr8 146274826 + 144819546 144819572 8 146364022 + 144748632 144748658 13619339
+26
+
+chain 2509 chr8 146274826 + 144820134 144820160 8 146364022 + 144748632 144748658 22535050
+26
+
+chain 2395 chr8 146274826 + 144820036 144820061 8 146364022 + 144748974 144748999 15328526
+25
+
+chain 2146 chr8 146274826 + 86862896 86862937 8 146364022 - 59626667 59626708 2042
+38 1 1
+2
+
+chain 2013 chr8 146274826 + 12224371 12224395 8 146364022 + 11933433 11933457 5802
+24
+
+chain 928 chr8 146274826 + 86871422 86871445 8 146364022 + 86566156 86566179 4371
+23
+
+chain 19961283 chr8_random 943810 + 732172 943810 5 180915260 + 69954173 70165811 138
+211638
+
+chain 4772201 chr8_random 943810 + 62854 113804 8 146364022 + 16274686 16325603 650
+4146 9 9
+1642 5 9
+541 4 0
+1197 1 1
+27 1 1
+2498 0 1
+20171 4 0
+2761 3 0
+1978 0 1
+628 10 0
+5533 3 0
+2428 24 0
+47 5 9
+197 11 11
+687 0 2
+642 1 1
+17 1 1
+2228 0 4
+1978 1 0
+1521
+
+chain 4401722 chr8_random 943810 + 396973 443039 8 146364022 - 801667 847519 685
+2079 1 0
+22818 62 9
+50 57 0
+25 0 8
+40 91 0
+5953 32 0
+1937 0 2
+803 13 14
+786 0 5
+3908 2 0
+783 0 1
+854 1 0
+142 1 0
+1521 1 0
+114 0 1
+498 4 4
+591 2 0
+2750 0 9
+147
+
+chain 3680035 chr8_random 943810 + 643258 682172 GL000196.1 38914 + 0 38914 797
+38914
+
+chain 3554032 chr8_random 943810 + 493047 530222 GL000197.1 37175 + 0 37175 825
+37175
+
+chain 1222443 chr8_random 943810 + 0 12854 8 146364022 - 108556772 108569616 1946
+5765 0 1
+2843 2 0
+279 0 1
+299 1 0
+1113 9 0
+2543
+
+chain 995258 chr8_random 943810 + 250482 297042 8 146364022 + 46838897 46856230 2491
+52 5 5
+72 1882 0
+246 1888 0
+158 79 78
+59 82 81
+53 46 46
+76 18 18
+100 1942 59
+231 1 0
+84 1 0
+49 23 22
+65 25 25
+312 49 47
+118 1 0
+169 645 640
+71 18 18
+202 15 15
+74 114 112
+65 1444 30
+86 2249 34
+216 9 8
+173 33 30
+63 81 79
+265 87 84
+103 11 10
+122 1 1
+47 1 1
+165 858 0
+14 1027 0
+88 1879 0
+148 7 6
+166 1 0
+288 1888 1
+62 1 1
+90 1 0
+35 1890 1
+280 3 3
+23 1 0
+109 1 1
+283 4 4
+88 1 1
+67 1 1
+23 1 1
+109 680 0
+89 1876 0
+41 1 0
+45 1898 0
+107 18 18
+18 1 0
+28 1 1
+50 1 0
+35 1 1
+50 7 4
+54 1 0
+37 1 1
+298 11 10
+94 1 0
+17 1 0
+36 1 0
+55 1 0
+12 1 1
+148 1 1
+79 11 9
+78 1 1
+140 5 4
+54 3 0
+97 1 0
+138 6 4
+73 1 0
+59 19 19
+207 1 1
+45 1 1
+76 1 0
+8 3 1
+60 2 2
+56 1 1
+70 1 0
+45 1 1
+136 131 128
+86 17 16
+75 7 7
+53 483 144
+75 26 26
+230 135 132
+110 15 15
+61 25 23
+76 43 42
+120 1 0
+78 1735 1728
+192 42 41
+61 82 82
+190 37 37
+90 1911 30
+168 56 56
+56 10 10
+83 26 26
+230 1927 49
+224 1937 52
+244 41 41
+125 36 36
+96 26 26
+83 81 78
+272 2019 139
+59 236 231
+103 71 70
+183 31 31
+58 119 117
+131 1 0
+167 25 25
+72 97 96
+91 6 6
+75 10 9
+219
+
+chain 895028 chr8_random 943810 + 298039 346176 8 146364022 - 99507152 99525054 4376
+63 126 463
+229 1883 1
+104 25 25
+58 6 6
+155 36 35
+84 10 10
+88 23 23
+53 1 0
+164 5 5
+68 56 55
+231 24 24
+149 409 408
+53 1 0
+69 1 0
+134 6 6
+201 318 315
+27 1885 0
+105 1 0
+82 82 82
+144 27 27
+56 238 235
+130 24 23
+109 1 0
+77 2 1
+100 31 30
+102 14 14
+63 11 10
+108 91 91
+72 94 93
+169 149 148
+198 238 234
+86 2 0
+169 3 1
+72 11 11
+66 1 0
+247 18 17
+392 540 533
+186 7 7
+121 1 0
+254 1977 89
+53 7 7
+193 483 475
+93 50 47
+198 28 28
+76 1883 8
+61 130 129
+123 29 29
+112 201 199
+138 12 11
+21 1873 0
+107 33 33
+53 1880 1
+118 40 38
+141 1943 53
+168 137 134
+81 16 16
+115 2216 0
+103 32 29
+71 128 127
+104 54 53
+121 128 127
+66 99 96
+80 75 74
+128 1924 40
+53 2 1
+288 1910 24
+53 1907 23
+56 40 40
+72 111 111
+62 127 127
+122 65 65
+80 210 206
+115 0 1
+146 5663 0
+183 40 40
+53 34 33
+229 28 28
+92 83 83
+234 1983 101
+57 1885 0
+44 11 11
+62 1 0
+69 28 28
+126 1 0
+148 147 144
+58 14 12
+53 1 0
+66 1 0
+105 34 33
+71 39 38
+69 17 17
+56 6 5
+79 48 46
+53 6 6
+57 38 35
+77 78 75
+111 649 644
+110 45 43
+235
+
+chain 604051 chr8_random 943810 + 178170 281976 8 146364022 + 46838954 46856867 5476
+212 1875 0
+272 566 562
+114 1 0
+143 1 0
+55 74 74
+65 25 25
+63 62 62
+61 31 31
+102 23 23
+215 1 0
+63 67 68
+68 373 34
+158 64 63
+53 46 46
+105 67 67
+55 2294 38
+202 15 15
+63 51 51
+246 23 23
+71 1 0
+271 103 102
+427 6 5
+51 25 22
+54 1878 0
+36 10 10
+122 26 26
+134 1886 0
+121 93 92
+51 1 2
+246 54742 0
+134 1884 0
+129 33 31
+147 39 38
+116 65 61
+66 43 41
+62 1982 95
+213 196 193
+339 260 254
+187 89 88
+10 2292 403
+57 5123 1343
+293 24 22
+61 1 0
+73 7 7
+53 1877 144
+91 4270 499
+59 2463 581
+37 339 671
+59 342 0
+110 266 261
+150 6 6
+92 244 241
+51 62 62
+51 3119 1229
+91 761 80
+60 48 47
+137 1876 0
+136 12 10
+131 12 11
+290 1 0
+45 4005 2083
+59 88 424
+59
+
+chain 496223 chr8_random 943810 + 580222 593236 8 146364022 - 59615387 59795086 34662
+2144 4634 17818
+237 1 1
+31 1 1
+194 35 40
+1575 162 153603
+534 0 55
+995 64 64
+1343 58 58
+112 1 1
+38 1 1
+70 1 1
+41 1 1
+81 1 1
+34 1 1
+624
+
+chain 279595 chr8_random 943810 + 199376 329223 8 146364022 - 99506514 99525054 6095
+67 50 47
+55 631 967
+63 1082 0
+177 61 58
+147 6 6
+143 1 0
+42 1882 0
+74 31 30
+83 23 23
+13 1879 0
+204 5 5
+58 69 69
+227 1933 51
+152 123 122
+83 1 0
+118 72 72
+159 17 17
+119 34 34
+230 36 36
+134 1929 32
+189 3017 0
+24 83 83
+121 1 0
+49 5680 1
+325 136 129
+277 30 30
+335 1436 53
+51 63 62
+99 867 859
+154 860 855
+269 32 31
+112 1 0
+50 1877 0
+99 58 58
+108 1 0
+96 2221 0
+37 1546 0
+136 2648 89
+52 7 8
+278 1 0
+202 139 136
+145 65 63
+51 44 42
+62 143 139
+61 156 155
+243 214 215
+20 1872 0
+194 74 75
+337 25 25
+145 15 15
+71 65 65
+84 1878 0
+60 1 0
+244 227 225
+226 53 53
+62 42 41
+66 63 61
+120 35 34
+64 56110 1
+98 41 40
+53 2795 914
+65 10 10
+57 8290 755
+67 63 61
+66 17 16
+53 1 0
+58 36 36
+92 3924 162
+40 61 61
+58 4119 368
+133 2082 185
+58 42 42
+167 2235 21
+50 4401 627
+71 40 39
+147 360 353
+60 174 173
+446
+
+chain 208078 chr8_random 943810 + 170910 242131 8 146364022 - 99506628 99524507 6380
+55 632 967
+69 73 73
+115 28 28
+146 4836 20
+75 1 0
+54 58 58
+87 10 10
+294 22105 209
+184 59 59
+53 209 208
+64 1388 305
+56 340 338
+60 50 50
+134 32 32
+108 2 0
+106 83 82
+108 1884 0
+62 68 68
+216 1 0
+55 20 20
+107 3862 104
+61 311 311
+29 2182 2154
+53 1 0
+93 1388 251
+108 3 2
+129 159 158
+109 1 0
+31 114 113
+51 60 60
+78 14 14
+99 14 13
+152 64 62
+60 13 12
+120 98 98
+138 115 114
+56 6 4
+26 438 436
+213 183 182
+53 1 0
+81 2318 428
+71 25 25
+145 15 15
+71 65 65
+109 1956 43
+69 112 108
+33 397 392
+58 1466 80
+62 46 46
+401 64 64
+45 51 51
+56 1 0
+6 99 99
+54 146 144
+187 67 67
+166 52 49
+51 9 8
+63 11 10
+61 186 186
+68 38 38
+168 105 102
+125 3 2
+113 17 17
+186 2 0
+3 6394 747
+113 762 83
+102 4015 254
+238 102 101
+91 6 6
+85 1999 129
+12 9 9
+44 2322 442
+90 319 318
+42
+
+chain 110041 chr8_random 943810 + 584910 586860 8 146364022 - 59525621 59532924 58275
+151 1 1
+64 1 1
+158 1 1
+137 0 5353
+14 3 3
+73 8 8
+52 11 11
+57 9 9
+54 15 15
+289 15 15
+837
+
+chain 81230 chr8_random 943810 + 228410 243660 8 146364022 - 99515272 99524158 121868
+53 818 813
+113 55 55
+76 1036 1025
+78 1 0
+115 1280 591
+98 36 34
+79 25 25
+73 189 188
+120 2622 738
+79 145 145
+8 21 19
+36 157 155
+27 18 14
+98 82 81
+130 280 280
+78 83 83
+21 20 20
+27 51 51
+134 238 238
+10 39 39
+53 216 215
+252 5175 1418
+73 6 6
+146 231 228
+111 1 0
+201 35 35
+101
+
+chain 78595 chr8_random 943810 + 271315 287023 8 146364022 + 46844767 46855610 13381
+177 7 6
+61 49 46
+54 86 84
+62 24 23
+151 92 91
+73 109 107
+108 1 0
+51 8 6
+97 2409 1723
+29 1995 118
+92 64 63
+24 701 695
+42 7 7
+53 90 89
+54 403 392
+25 6360 4099
+70 192 192
+26 77 76
+63 336 336
+129 125 126
+143 878 869
+27 23 23
+61
+
+chain 70241 chr8_random 943810 + 583972 584708 8 146364022 - 2327498 2328234 1800744
+736
+
+chain 67060 chr8_random 943810 + 583131 583834 8 146364022 + 144032710 144033413 1885205
+703
+
+chain 60161 chr8_random 943810 + 163863 193392 8 146364022 + 46840361 46854926 51951
+69 30 30
+79 155 153
+22 224 224
+36 635 633
+54 78 77
+53 1660 61
+55 408 405
+36 32 32
+40 163 161
+29 96 89
+5 85 85
+4 108 106
+193 10362 0
+211 23 23
+164 214 212
+108 41 40
+217 35 35
+85 25 25
+266 2366 490
+48 600 260
+32 3507 4987
+74 590 587
+105 2319 2307
+66 2880 990
+102 1 0
+89 507 168
+143
+
+chain 59106 chr8_random 943810 + 169718 174718 8 146364022 - 99507650 99524666 884317
+69 73 73
+53 107 105
+145 323 5927
+57 45 43
+58 51 49
+65 130 129
+16 74 74
+175 49 49
+53 423 422
+53 2360 8782
+34 55 55
+95 1 0
+28 1 0
+2 113 113
+292
+
+chain 53138 chr8_random 943810 + 171392 346403 8 146364022 - 102525263 102570806 8603
+57 57 57
+79 626 627
+64 1139 91
+72 32 32
+61 1 0
+192 55 53
+253 233 231
+113 1894 10
+151 18218 118
+161 39 39
+89 168 167
+68 174 168
+68 7236 473
+76 2229 347
+40 124 120
+50 21 21
+55 1906 29
+98 2 0
+51 3928 158
+113 3230 214
+58 5760 82
+62 113 112
+39 7442 4152
+122 13 12
+149 90 90
+56 48 47
+71 400 397
+133 1910 21
+97 23 23
+92 2561 0
+54 15 13
+67 70 69
+90 95 94
+59 72 72
+139 45 45
+101 71659 2394
+62 72 72
+84 1 0
+9 2000 117
+95 39 39
+65 70 68
+87 2031 150
+103 1949 61
+106 17 17
+136 75 74
+53 5662 38
+58 1936 41
+42 168 168
+108 95 95
+66 243 241
+50 5018 908
+53 4282 513
+74 1906 30
+83 2078 26035
+107 1947 59
+57 500 483
+160 1936 53
+185 1897 12
+119 3972 202
+29 14 14
+79 61 61
+44
+
+chain 52733 chr8_random 943810 + 164218 295513 8 146364022 + 43821028 43838759 7574
+63 20 20
+141 36 36
+153 32 31
+103 40 40
+53 86 85
+99 1658 59
+83 265 263
+110 21 21
+51 29 27
+160 108 108
+51 1 0
+49 1 0
+61 130 123
+85 12281 44
+69 272 272
+118 62 62
+75 7995 1645
+102 45 45
+59 32 32
+14 328 328
+126 2372 483
+86 58668 153
+40 4323 551
+31 1938 56
+58 2392 511
+58 234 222
+51 1403 0
+51 91 91
+50 218 218
+83 67 66
+75 77 77
+110 391 53
+2 2678 792
+147 104 101
+59 1917 33
+92 1958 75
+54 5899 1442
+11 105 104
+132 1 0
+50 2212 332
+66 5506 1369
+60 189 189
+173 223 221
+222 1874 0
+87 23 23
+54 108 108
+109 29 28
+94 64 63
+70 91 86
+97 164 161
+112 123 123
+78 1942 66
+145 118 118
+69 1917 31
+51 10 10
+113 235 231
+193 327 327
+41 392 391
+51 363 361
+123 1977 94
+57
+
+chain 48120 chr8_random 943810 + 172087 205615 8 146364022 - 99508140 99525054 275640
+50 1136 89
+81 56 55
+4 1876 5603
+199 577 570
+71 144 141
+39 17920 1690
+56 276 276
+117 289 289
+64 172 170
+10 18 18
+76 284 279
+308 237 229
+64 1904 0
+33 2094 204
+40 43 43
+63 3 2
+59 12 12
+306 15 15
+33 1146 61
+49 757 4487
+37 62 62
+83 46 46
+112 178 174
+95 1 0
+29 1956 73
+248
+
+chain 37837 chr8_random 943810 + 253130 272078 8 146364022 + 46839659 46847391 87472
+42 44 44
+61 2771 880
+109 37 36
+171 1 0
+120 209 204
+98 56 55
+61 10 9
+23 187 186
+75 18 18
+17 5316 1682
+9 145 143
+53 1 0
+29 137 137
+73 132 128
+65 14 14
+79 6214 2430
+95 70 70
+83 2232 342
+91
+
+chain 33662 chr8_random 943810 + 209837 215530 8 146364022 - 99514311 99520696 710844
+71 67 65
+87 1 0
+118 10 8
+19 543 533
+53 11 11
+89 4 2
+68 143 138
+148 1307 167
+110 627 624
+30 2103 3960
+84
+
+chain 32940 chr8_random 943810 + 226035 229035 8 146364022 - 102534454 102537445 203694
+68 23 23
+49 847 842
+50 91 91
+134 57 57
+61 1290 1287
+37 113 113
+86 41 40
+53
+
+chain 31024 chr8_random 943810 + 206449 211988 8 146364022 - 99514678 99520173 701886
+8 43 43
+64 6 5
+58 14 12
+82 340 0
+49 416 749
+81 59 59
+117 75 75
+207 1422 3285
+36 2428 531
+34
+
+chain 29825 chr8_random 943810 + 245532 246838 8 146364022 + 46839602 46840894 3893579
+57 560 553
+119 226 222
+5 184 184
+21 75 72
+59
+
+chain 28513 chr8_random 943810 + 169082 170209 8 146364022 - 99514495 99515614 2995290
+72 337 330
+70 17 17
+84 143 144
+53 81 80
+64 162 161
+44
+
+chain 28403 chr8_random 943810 + 244271 247583 8 146364022 + 46840215 46841632 1514192
+150 21 21
+65 247 246
+61 60 60
+144 37 36
+68 1 0
+56 146 144
+158 1945 55
+153
+
+chain 27366 chr8_random 943810 + 305024 329400 8 146364022 - 99508828 99514021 185326
+30 144 144
+27 1950 69
+57 1 0
+69 4733 954
+80 7 7
+60 2015 139
+144 51 51
+17 50 48
+20 2199 324
+179 83 83
+149 1 0
+45 50 50
+29 198 197
+38 56 56
+36 163 162
+27 2035 153
+71 157 157
+56 6099 109
+62 47 47
+93 104 100
+75 1 0
+39 342 0
+49 1641 94
+81 539 539
+177
+
+chain 25161 chr8_random 943810 + 165410 166073 8 146364022 + 46840031 46840686 5084847
+51 107 104
+69 107 106
+77 51 48
+53 79 78
+69
+
+chain 23498 chr8_random 943810 + 275598 276538 8 146364022 + 46848347 46849285 1106774
+150 39 39
+58 1 0
+156 159 160
+43 237 235
+97
+
+chain 22556 chr8_random 943810 + 221873 233787 8 146364022 - 102535430 102541485 264178
+56 92 91
+134 1524 140
+26 9348 4879
+77 298 294
+159 126 126
+55 8 7
+11
+
+chain 21554 chr8_random 943810 + 211856 229563 8 146364022 - 102534119 102541711 230838
+98 1283 144
+76 1760 1749
+25 1 0
+80 1889 12
+87 80 79
+50 14 14
+51 55 50
+59 207 201
+52 31 30
+212 2303 390
+120 3503 2102
+43 5590 1830
+38
+
+chain 21378 chr8_random 943810 + 315539 346866 8 146364022 - 99515536 99522005 182294
+65 7 7
+59 1872 0
+52 1 0
+110 59 59
+145 1929 47
+157 4107 0
+50 19 19
+76 11 11
+9 218 215
+20 69 68
+27 104 104
+38 3941 169
+93 9868 446
+40 53 53
+33 350 349
+83 1915 34
+228 2 1
+71 4993 3080
+80 103 101
+58 162 162
+50
+
+chain 20133 chr8_random 943810 + 187153 190961 8 146364022 + 46839718 46841635 711123
+27 2490 610
+70 193 186
+75 6 6
+22 81 81
+48 1 0
+41 200 200
+10 13 12
+78 103 101
+193 10 10
+147
+
+chain 19851 chr8_random 943810 + 184692 274845 8 146364022 + 46839508 46849467 34309
+59 20 20
+103 2903 645
+204 29 27
+122 5 4
+251 1 1
+19 1 1
+370 102 102
+45 59 59
+32 2407 520
+35 53082 226
+207 6009 346
+163 6 4
+101 79 79
+50 419 416
+33 1900 15
+227 6 6
+48 1 0
+53 22 21
+65 58 57
+59 43 42
+133 81 80
+20 44 42
+50 14 12
+53 37 36
+104 2375 490
+62 1340 1334
+14 1 0
+183 3854 228
+49 6055 405
+35 6036 1578
+80 25 25
+89 8 7
+13
+
+chain 19146 chr8_random 943810 + 175023 175290 8 146364022 - 99508150 99508416 4025470
+88 58 57
+65 25 25
+31
+
+chain 17870 chr8_random 943810 + 167013 193249 8 146364022 + 46840039 46851047 112211
+37 407 404
+31 233 231
+41 10382 13
+26 802 800
+40 282 279
+41 6132 1660
+77 3954 2070
+28 510 4239
+81 90 89
+50 30 30
+120 2083 201
+60 192 191
+51 338 0
+118
+
+chain 17758 chr8_random 943810 + 265412 266607 8 146364022 + 43830436 43831619 676151
+58 100 98
+16 14 14
+59 946 936
+2
+
+chain 17102 chr8_random 943810 + 196211 212812 8 146364022 - 102534634 102539542 315778
+4 176 169
+110 677 661
+101 229 222
+63 12 11
+71 2311 416
+66 5 5
+3 2545 1456
+25 7 5
+52 21 20
+3 9994 1320
+61 8 7
+57
+
+chain 16958 chr8_random 943810 + 303736 319647 8 146364022 - 99509421 99514022 288375
+62 1 0
+115 55 55
+12 6716 1059
+173 60 58
+5 238 238
+27 142 138
+80 1 0
+32 1181 1170
+56 95 93
+15 6818 1186
+27
+
+chain 16519 chr8_random 943810 + 191041 191237 8 146364022 + 46841712 46841907 5194781
+138 7 6
+51
+
+chain 16395 chr8_random 943810 + 250196 250458 8 146364022 + 46842349 46842610 5706058
+109 63 63
+38 1 0
+51
+
+chain 16284 chr8_random 943810 + 248826 295566 8 146364022 + 43821313 43835075 8983
+38 3114 1217
+58 3878 108
+134 2320 436
+35 2074 180
+90 6230 729
+53 51 51
+165 2138 257
+18 1 0
+14 9087 4604
+68 26 23
+70 26 25
+165 4726 2469
+31 113 113
+45 6358 726
+53 323 321
+29 3160 1272
+53 1943 60
+1 1 0
+51
+
+chain 16072 chr8_random 943810 + 313809 340982 8 146364022 - 102527896 102533983 267291
+28 5309 1547
+73 15383 1858
+110 23 22
+51 120 119
+75 171 167
+144 2405 509
+56 2087 199
+104 240 238
+93 367 364
+59 113 109
+162
+
+chain 15849 chr8_random 943810 + 261982 295288 8 146364022 + 43821759 43829198 76114
+110 412 75
+52 237 234
+137 1904 21
+61 17 17
+88 8048 505
+97 1212 533
+118 1 0
+62 80 80
+12 643 644
+105 9123 1231
+153 113 112
+50 1019 1018
+55 3899 142
+89 478 475
+43 4836 1068
+52
+
+chain 15670 chr8_random 943810 + 194296 345941 8 146364022 - 102525263 102540770 8834
+113 3789 1
+79 5134 279
+81 25039 3655
+36 72 71
+66 2073 189
+82 66 62
+87 280 277
+20 23 23
+59 87 84
+72 49 48
+51 7 7
+82 1014 334
+62 79983 3178
+76 18 17
+68 2382 504
+43 42 41
+108 10477 733
+134 2033 147
+59 5650 11
+88 3846 65
+64 297 293
+50 3779 12
+69 123 122
+120 121 120
+68 15 15
+57 136 135
+139 239 237
+72 1 0
+63 4 3
+53 59 59
+8 490 488
+28 84 81
+35 298 293
+34 805 799
+67 1 0
+53 69 67
+100 14 14
+81 134 132
+53 38 38
+39 110 109
+45
+
+chain 14986 chr8_random 943810 + 225882 226349 8 146364022 - 99518359 99518822 2174986
+18 53 51
+56 166 164
+73 33 33
+68
+
+chain 14834 chr8_random 943810 + 243014 243551 8 146364022 - 99519780 99520313 2299338
+16 162 159
+19 313 312
+27
+
+chain 14491 chr8_random 943810 + 298927 299279 8 146364022 - 102541139 102541484 3650546
+95 253 246
+4
+
+chain 13927 chr8_random 943810 + 330425 330634 8 146364022 - 99513165 99513373 16289681
+108 47 46
+54
+
+chain 13708 chr8_random 943810 + 204114 204446 8 146364022 - 99514221 99514551 7956244
+38 2 1
+51 137 136
+104
+
+chain 13201 chr8_random 943810 + 267894 296641 8 146364022 + 46841376 46846486 149880
+47 8325 118
+153 12619 975
+124 10 10
+59 1933 45
+415 178 178
+62 103 99
+67 193 193
+45 34 34
+4 542 542
+26 2853 963
+60 194 194
+31 632 628
+38
+
+chain 12234 chr8_random 943810 + 261803 269960 8 146364022 + 46841266 46843423 172872
+35 2890 667
+1 24 24
+60 15 15
+6 166 166
+32 2034 149
+193 134 132
+81 69 68
+116 2096 211
+21 87 83
+97
+
+chain 10617 chr8_random 943810 + 337138 337293 8 146364022 - 99523571 99523724 21494273
+69 29 27
+57
+
+chain 10554 chr8_random 943810 + 261774 276161 8 146364022 + 46850579 46856384 287750
+26 3379 1156
+30 20 20
+51 4844 1067
+12 16 15
+65 51 50
+53 361 357
+85 102 101
+13 51 51
+26 87 87
+46 4988 2413
+81
+
+chain 10039 chr8_random 943810 + 325665 325968 8 146364022 - 99512180 99512483 3203386
+32 146 146
+51 12 12
+62
+
+chain 9889 chr8_random 943810 + 299929 343052 8 146364022 - 99507161 99512618 194143
+54 125 463
+172 6011 368
+29 4240 471
+68 8003 490
+69 47 47
+10 133 133
+55 45 44
+46 4488 379
+66 1908 22
+82 7833 307
+63 2043 161
+90 115 115
+101 1 0
+97 2144 241
+32 4543 773
+83 294 293
+33
+
+chain 9887 chr8_random 943810 + 315022 315154 8 146364022 - 99513153 99513284 7544872
+79 1 0
+52
+
+chain 9860 chr8_random 943810 + 311200 311307 8 146364022 - 99513093 99513199 8991129
+52 1 0
+54
+
+chain 9817 chr8_random 943810 + 331048 331155 8 146364022 - 99513786 99513892 13428201
+64 1 0
+42
+
+chain 9446 chr8_random 943810 + 266857 296082 8 146364022 + 43794817 43828117 103381
+44 9743 27369
+146 121 120
+47 983 976
+79 10221 2331
+165 112 112
+51 81 80
+39 1877 0
+66 2043 157
+36 3318 1429
+53
+
+chain 9082 chr8_random 943810 + 283227 283503 8 146364022 + 46855567 46855841 3572014
+72 39 38
+7 101 100
+57
+
+chain 9078 chr8_random 943810 + 266179 266275 8 146364022 + 46841541 46841637 24832874
+96
+
+chain 9056 chr8_random 943810 + 234327 343102 8 146364022 - 102532678 102541696 177988
+49 2060 180
+83 4311 566
+60 72559 3258
+278 110 111
+124 380 378
+51 246 244
+21 14 13
+37 2147 273
+83 195 193
+50 29 28
+5 2000 121
+73 4435 328
+132 3864 97
+47 5706 63
+45 54 54
+151 1883 5
+99 3796 15
+99 63 61
+64 1 0
+58 1881 0
+137 76 74
+53 53 48
+27 312 310
+85 17 16
+19 140 140
+52 244 244
+62 105 104
+50
+
+chain 8907 chr8_random 943810 + 174718 174972 8 146364022 - 99514987 99515577 3222521
+12 195 531
+47
+
+chain 8843 chr8_random 943810 + 329461 329557 8 146364022 - 99512211 99512306 12312646
+78 1 0
+17
+
+chain 8728 chr8_random 943810 + 244822 248433 8 146364022 + 46838897 46840609 1548241
+52 2949 1051
+100 1 0
+231 55 55
+65 34 34
+124
+
+chain 8619 chr8_random 943810 + 294534 295111 8 146364022 + 46855606 46856180 1696895
+31 25 25
+71 52 51
+46 97 97
+58 132 130
+65
+
+chain 8428 chr8_random 943810 + 281982 282213 8 146364022 + 46854328 46854560 448042
+60 97 98
+56 17 17
+1
+
+chain 8419 chr8_random 943810 + 261190 261281 8 146364022 + 43820969 43821060 10860311
+91
+
+chain 8395 chr8_random 943810 + 294914 295046 8 146364022 + 46848509 46848640 12873675
+58 69 68
+5
+
+chain 8358 chr8_random 943810 + 183391 183662 8 146364022 + 46851295 46851565 1204104
+177 39 38
+55
+
+chain 8235 chr8_random 943810 + 303417 303563 8 146364022 - 99516580 99516725 5721277
+92 1 0
+53
+
+chain 8187 chr8_random 943810 + 330253 330340 8 146364022 - 99512994 99513081 26147162
+87
+
+chain 7754 chr8_random 943810 + 175981 176066 8 146364022 - 99524049 99524133 15930227
+61 1 0
+23
+
+chain 7677 chr8_random 943810 + 237294 312035 8 146364022 - 99517817 99525125 210590
+33 254 254
+156 1 0
+142 25 25
+70 127 127
+226 1925 53
+62 55 55
+112 29 28
+91 36 36
+139 46 43
+7 796 791
+54 65384 1748
+45 3060 1165
+46 839 833
+119 535 529
+77 214 206
+36
+
+chain 7632 chr8_random 943810 + 192816 192897 8 146364022 + 46850614 46850695 27043702
+81
+
+chain 7605 chr8_random 943810 + 285785 290878 8 146364022 + 46850643 46851974 486318
+50 2571 689
+13 4 4
+73 73 73
+25 2038 160
+132 56 54
+58
+
+chain 7406 chr8_random 943810 + 221929 222203 8 146364022 - 99519540 99519813 598559
+62 1 0
+29 134 134
+48
+
+chain 7383 chr8_random 943810 + 294257 294361 8 146364022 + 43837510 43837614 4128881
+70 9 9
+25
+
+chain 7298 chr8_random 943810 + 168270 168367 8 146364022 + 46839414 46839508 6543284
+4 56 53
+37
+
+chain 7295 chr8_random 943810 + 336620 336697 8 146364022 - 99513722 99513799 27625946
+77
+
+chain 7211 chr8_random 943810 + 261472 261549 8 146364022 + 46839068 46839145 24666501
+77
+
+chain 7186 chr8_random 943810 + 330047 330123 8 146364022 - 99512791 99512867 27853996
+76
+
+chain 7178 chr8_random 943810 + 316571 316677 8 146364022 - 102541857 102541963 5712191
+106
+
+chain 7102 chr8_random 943810 + 318170 320971 8 146364022 - 99520028 99520932 765669
+72 19 19
+135 121 121
+72 13 12
+29 2280 384
+60
+
+chain 7077 chr8_random 943810 + 192950 193025 8 146364022 + 46850748 46850823 28082919
+75
+
+chain 7057 chr8_random 943810 + 203108 206189 8 146364022 - 99515093 99516287 1156085
+30 91 89
+53 2333 448
+35 503 503
+36
+
+chain 6980 chr8_random 943810 + 332337 335152 8 146364022 - 99522544 99523471 1124480
+50 412 409
+6 79 79
+50 126 126
+65 1978 93
+49
+
+chain 6922 chr8_random 943810 + 183305 183378 8 146364022 + 46840000 46840073 28376594
+73
+
+chain 6904 chr8_random 943810 + 266355 266429 8 146364022 + 46841714 46841788 28413782
+74
+
+chain 6731 chr8_random 943810 + 303313 303384 8 146364022 - 99509001 99509072 28774708
+71
+
+chain 6664 chr8_random 943810 + 303981 314057 8 146364022 - 99517140 99519668 641395
+51 3 2
+55 1 0
+72 170 168
+30 7422 1761
+7 12 11
+54 1882 0
+68 153 153
+96
+
+chain 6603 chr8_random 943810 + 322619 327380 8 146364022 - 99513231 99513884 1344743
+127 337 0
+120 9 8
+78 1963 78
+31 1885 0
+211
+
+chain 6584 chr8_random 943810 + 197737 202982 8 146364022 - 102536127 102540259 775939
+91 1155 1137
+22 12 11
+57 3876 2782
+32
+
+chain 6449 chr8_random 943810 + 218412 233428 8 146364022 - 99516080 99519573 697985
+27 8506 1438
+73 54 54
+91 295 295
+235 28 28
+6 100 100
+56 5516 1061
+29
+
+chain 6331 chr8_random 943810 + 327023 327090 8 146364022 - 99511661 99511728 29751334
+67
+
+chain 6250 chr8_random 943810 + 208146 208242 8 146364022 - 99508890 99508983 12204367
+15 70 67
+11
+
+chain 6212 chr8_random 943810 + 207786 207861 8 146364022 - 99514136 99514211 3829743
+75
+
+chain 6150 chr8_random 943810 + 203513 205795 8 146364022 - 102537045 102537445 1909663
+16 3 2
+125 118 117
+8 1955 75
+57
+
+chain 6094 chr8_random 943810 + 299279 299402 8 146364022 - 99508718 99508841 2977078
+68 21 21
+34
+
+chain 6085 chr8_random 943810 + 250101 250166 8 146364022 + 46842254 46842319 30387783
+65
+
+chain 6067 chr8_random 943810 + 293889 294038 8 146364022 + 46845620 46845767 4301892
+66 21 19
+62
+
+chain 6049 chr8_random 943810 + 230044 230135 8 146364022 - 102569888 102569979 10345810
+91
+
+chain 5962 chr8_random 943810 + 207380 207446 8 146364022 - 99509995 99510061 8394857
+66
+
+chain 5949 chr8_random 943810 + 272784 272847 8 146364022 + 46853694 46853757 30762472
+63
+
+chain 5823 chr8_random 943810 + 299452 300023 8 146364022 - 99514497 99515068 1422380
+470 61 61
+40
+
+chain 5814 chr8_random 943810 + 289476 289952 8 146364022 + 46839369 46839842 2257769
+77 110 110
+124 92 90
+42 1 0
+30
+
+chain 5753 chr8_random 943810 + 192024 192086 8 146364022 + 46838954 46839016 21955899
+62
+
+chain 5749 chr8_random 943810 + 233271 233333 8 146364022 - 102570546 102570608 31315232
+62
+
+chain 5681 chr8_random 943810 + 341821 341883 8 146364022 - 99511396 99511458 7040566
+62
+
+chain 5649 chr8_random 943810 + 174777 174837 8 146364022 - 99507908 99507968 31588023
+60
+
+chain 5623 chr8_random 943810 + 175706 175950 8 146364022 - 102534119 102534360 3287579
+59 23 22
+63 22 20
+77
+
+chain 5394 chr8_random 943810 + 322313 322370 8 146364022 - 99511057 99511114 32316179
+57
+
+chain 5303 chr8_random 943810 + 187437 187493 8 146364022 + 46840000 46840056 32583273
+56
+
+chain 5285 chr8_random 943810 + 290446 290502 8 146364022 + 43794807 43794863 32673339
+56
+
+chain 5276 chr8_random 943810 + 336755 336811 8 146364022 - 99513853 99513909 32693850
+56
+
+chain 5265 chr8_random 943810 + 208344 208568 8 146364022 - 99514691 99514915 3842595
+38 152 152
+34
+
+chain 5263 chr8_random 943810 + 587464 592229 8 146364022 + 86573610 86746488 37343
+35 3283 168311
+47 1343 1343
+20 1 3086
+36
+
+chain 5194 chr8_random 943810 + 184072 184128 8 146364022 + 46838897 46838953 32965865
+56
+
+chain 5184 chr8_random 943810 + 329855 329911 8 146364022 - 99512600 99512656 19420929
+56
+
+chain 5176 chr8_random 943810 + 177599 177656 8 146364022 - 99506628 99506685 33029925
+57
+
+chain 5155 chr8_random 943810 + 281730 289038 8 146364022 + 46843205 46844537 960143
+32 6927 953
+200 103 101
+46
+
+chain 5093 chr8_random 943810 + 184617 184671 8 146364022 + 43793908 43793962 23494272
+54
+
+chain 5050 chr8_random 943810 + 326962 327016 8 146364022 - 102542496 102542550 23236949
+54
+
+chain 5030 chr8_random 943810 + 212164 212217 8 146364022 - 99524079 99524132 33461083
+53
+
+chain 5021 chr8_random 943810 + 265903 265956 8 146364022 + 46841267 46841320 33516233
+53
+
+chain 5010 chr8_random 943810 + 325697 333370 8 146364022 - 99519686 99521704 323579
+146 5416 1638
+176 1905 28
+30
+
+chain 4963 chr8_random 943810 + 195042 195095 8 146364022 - 99525006 99525059 2910708
+53
+
+chain 4923 chr8_random 943810 + 294759 294811 8 146364022 + 46846486 46846538 24481170
+52
+
+chain 4775 chr8_random 943810 + 300049 300108 8 146364022 - 99511357 99511416 2287019
+59
+
+chain 4729 chr8_random 943810 + 323590 341586 8 146364022 - 99508256 99511164 508733
+81 188 186
+45 5653 0
+76 6291 651
+50 2125 222
+31 36 36
+21 50 50
+1 57 52
+62 3121 1237
+18 5 4
+85
+
+chain 4516 chr8_random 943810 + 291820 291870 8 146364022 + 46839826 46839876 19135311
+50
+
+chain 4460 chr8_random 943810 + 340307 340812 8 146364022 - 99522970 99523472 2799007
+59 396 393
+50
+
+chain 4363 chr8_random 943810 + 169662 169718 8 146364022 - 99524410 99524466 15024078
+25 20 20
+11
+
+chain 4245 chr8_random 943810 + 323934 340633 8 146364022 - 102539490 102542980 824111
+57 5415 1637
+55 4265 507
+46 6509 840
+13 129 125
+132 10 10
+68
+
+chain 4191 chr8_random 943810 + 346770 346816 8 146364022 - 99523777 99523823 32415009
+46
+
+chain 4157 chr8_random 943810 + 182640 182685 8 146364022 + 46841541 46841586 34989719
+45
+
+chain 4075 chr8_random 943810 + 287206 294116 8 146364022 + 46853923 46857394 507901
+58 44 43
+3 6754 3316
+51
+
+chain 4035 chr8_random 943810 + 210210 231774 8 146364022 - 99509073 99511132 504053
+68 1 0
+87 1 0
+47 151 148
+33 3084 58
+60 3981 215
+31 2075 179
+62 11852 1040
+31
+
+chain 3902 chr8_random 943810 + 322746 322788 8 146364022 - 99511490 99511532 25070576
+42
+
+chain 3842 chr8_random 943810 + 326212 339029 8 146364022 - 99518333 99519833 259270
+47 312 308
+17 60 57
+117 12236 926
+28
+
+chain 3793 chr8_random 943810 + 191943 191984 8 146364022 + 43793349 43793390 19585042
+41
+
+chain 3728 chr8_random 943810 + 267941 270995 8 146364022 + 46845159 46846318 991534
+57 2323 433
+41 406 402
+51 140 139
+36
+
+chain 3715 chr8_random 943810 + 252408 255104 8 146364022 + 46840810 46841615 879027
+44 1 0
+30 2575 685
+46
+
+chain 3689 chr8_random 943810 + 281829 281916 8 146364022 + 46850779 46850864 2001274
+26 3 1
+58
+
+chain 3667 chr8_random 943810 + 254324 254368 8 146364022 + 46840842 46840884 6647423
+30 11 9
+3
+
+chain 3646 chr8_random 943810 + 267998 268037 8 146364022 + 46850823 46850862 21797624
+39
+
+chain 3562 chr8_random 943810 + 168212 168270 8 146364022 + 43793831 43793889 3070871
+58
+
+chain 3504 chr8_random 943810 + 293480 293517 8 146364022 + 46839611 46839648 25642059
+37
+
+chain 3471 chr8_random 943810 + 337522 337596 8 146364022 - 99523948 99524022 18137430
+74
+
+chain 3448 chr8_random 943810 + 276204 276644 8 146364022 + 46854559 46854996 1897606
+49 365 362
+26
+
+chain 3411 chr8_random 943810 + 253189 255402 8 146364022 + 46850929 46853124 621337
+27 1269 1253
+37 776 774
+2 49 49
+53
+
+chain 3373 chr8_random 943810 + 338130 338166 8 146364022 - 99513335 99513371 20995505
+36
+
+chain 3359 chr8_random 943810 + 165298 184945 8 146364022 + 43823972 43836890 282023
+56 2595 8459
+64 12771 2404
+3 8 8
+69 4024 1798
+57
+
+chain 3297 chr8_random 943810 + 194502 225687 8 146364022 - 102525468 102530377 366001
+70 4347 545
+64 92 91
+87 8182 1452
+36 9798 1128
+56 8421 1348
+32
+
+chain 3286 chr8_random 943810 + 278118 290566 8 146364022 + 43833036 43837583 504233
+53 11 9
+65 12260 4361
+59
+
+chain 3257 chr8_random 943810 + 218922 219219 8 146364022 - 99516581 99516875 4722847
+56 32 30
+58 32 31
+119
+
+chain 3241 chr8_random 943810 + 233589 233706 8 146364022 - 102539417 102539534 832166
+52 16 16
+49
+
+chain 3212 chr8_random 943810 + 266430 268559 8 146364022 + 46841788 46842035 1348744
+53 1890 10
+128 11 9
+47
+
+chain 3157 chr8_random 943810 + 327996 328036 8 146364022 - 99512626 99512665 16621225
+16 15 14
+9
+
+chain 3082 chr8_random 943810 + 310645 310683 8 146364022 - 99512541 99512579 16551162
+38
+
+chain 3062 chr8_random 943810 + 163933 165245 8 146364022 + 46851641 46852949 942341
+29 1223 1219
+60
+
+chain 3030 chr8_random 943810 + 262108 262298 8 146364022 + 43831228 43834818 1405601
+67 13 3413
+110
+
+chain 2982 chr8_random 943810 + 183568 183600 8 146364022 + 46840262 46840294 9991965
+32
+
+chain 2745 chr8_random 943810 + 335974 336003 8 146364022 - 99513082 99513111 33185960
+29
+
+chain 2672 chr8_random 943810 + 298503 298547 8 146364022 - 99522900 99522944 24221385
+44
+
+chain 2671 chr8_random 943810 + 332183 346560 8 146364022 - 102528996 102533910 187401
+51 6123 457
+105 6796 3008
+38 249 246
+57 891 885
+67
+
+chain 2639 chr8_random 943810 + 219413 219441 8 146364022 - 99507721 99507749 35294427
+28
+
+chain 2612 chr8_random 943810 + 200816 200846 8 146364022 - 99525102 99525132 4075609
+30
+
+chain 2604 chr8_random 943810 + 240329 240369 8 146364022 - 99522715 99522755 8959532
+40
+
+chain 2556 chr8_random 943810 + 216929 216957 8 146364022 - 99514612 99514640 10325210
+28
+
+chain 2552 chr8_random 943810 + 191384 191411 8 146364022 + 46840185 46840212 15340406
+27
+
+chain 2552 chr8_random 943810 + 304972 304999 8 146364022 - 99516251 99516278 22571486
+27
+
+chain 2523 chr8_random 943810 + 327142 327169 8 146364022 - 99524856 99524883 11689776
+27
+
+chain 2451 chr8_random 943810 + 317909 318170 8 146364022 - 99521638 99521896 1452880
+31 226 223
+4
+
+chain 2447 chr8_random 943810 + 313295 313321 8 146364022 - 99513300 99513326 34910154
+26
+
+chain 2433 chr8_random 943810 + 230135 233158 8 146364022 - 99507638 99508095 1270471
+81 73 73
+21 37 37
+40 18 18
+82 2643 77
+28
+
+chain 2394 chr8_random 943810 + 309803 310102 8 146364022 - 102570308 102570605 11245020
+97 185 183
+17
+
+chain 2370 chr8_random 943810 + 237880 237905 8 146364022 - 99520270 99520295 11943708
+25
+
+chain 2370 chr8_random 943810 + 302899 302924 8 146364022 - 99512327 99512352 35222469
+25
+
+chain 2330 chr8_random 943810 + 274710 274735 8 146364022 + 46843727 46843752 26272760
+25
+
+chain 2188 chr8_random 943810 + 303139 303300 8 146364022 - 99512566 99512727 1325340
+161
+
+chain 2164 chr8_random 943810 + 254246 254269 8 146364022 + 46840765 46840788 24904248
+23
+
+chain 2146 chr8_random 943810 + 166073 166100 8 146364022 + 43793293 43793320 16498497
+27
+
+chain 2129 chr8_random 943810 + 171463 171506 8 146364022 - 99524332 99524375 3948851
+43
+
+chain 2094 chr8_random 943810 + 256486 256530 8 146364022 + 46856070 46856114 4878843
+44
+
+chain 2067 chr8_random 943810 + 182380 182437 8 146364022 + 46850625 46850682 3805032
+57
+
+chain 2054 chr8_random 943810 + 318711 318733 8 146364022 - 99511225 99511247 10715405
+22
+
+chain 1964 chr8_random 943810 + 202805 202867 8 146364022 - 99509184 99509246 3143072
+62
+
+chain 1962 chr8_random 943810 + 187357 187601 8 146364022 + 46841788 46842031 9057308
+62 87 86
+95
+
+chain 1941 chr8_random 943810 + 278085 278118 8 146364022 + 46854559 46854592 1239137
+33
+
+chain 1922 chr8_random 943810 + 294361 294534 8 146364022 + 46849827 46850000 1057760
+173
+
+chain 1907 chr8_random 943810 + 166115 166177 8 146364022 + 46850070 46850132 2756260
+62
+
+chain 1904 chr8_random 943810 + 294565 294590 8 146364022 + 46846293 46846318 7797359
+25
+
+chain 1899 chr8_random 943810 + 239038 239062 8 146364022 - 99519559 99519583 3632092
+24
+
+chain 1874 chr8_random 943810 + 311858 316542 8 146364022 - 99523087 99524010 1127459
+40 4555 794
+89
+
+chain 1842 chr8_random 943810 + 208242 208344 8 146364022 - 99510852 99510954 1122309
+102
+
+chain 1826 chr8_random 943810 + 333370 333404 8 146364022 - 102528310 102528344 12860155
+34
+
+chain 1699 chr8_random 943810 + 189740 189801 8 146364022 + 43830083 43830143 11700756
+13 1 0
+47
+
+chain 1671 chr8_random 943810 + 586860 586891 8 146364022 - 59596972 59597003 79385
+31
+
+chain 1671 chr8_random 943810 + 582366 582405 8 146364022 + 86778164 86778203 135745
+39
+
+chain 1614 chr8_random 943810 + 174855 174917 8 146364022 - 102535142 102535204 7562660
+62
+
+chain 1604 chr8_random 943810 + 210485 210541 8 146364022 - 99516819 99516875 24689779
+56
+
+chain 1577 chr8_random 943810 + 165529 165568 8 146364022 + 43833540 43833579 5487018
+39
+
+chain 1529 chr8_random 943810 + 199844 199893 8 146364022 - 99524132 99524181 16599934
+49
+
+chain 1430 chr8_random 943810 + 204007 204051 8 146364022 - 102535667 102535711 2444362
+44
+
+chain 1384 chr8_random 943810 + 331973 334317 8 146364022 - 99510969 99511436 2459541
+88 2124 247
+132
+
+chain 1361 chr8_random 943810 + 178432 178456 8 146364022 + 43821398 43821422 13532386
+24
+
+chain 1349 chr8_random 943810 + 282101 282136 8 146364022 + 43834762 43834797 3301014
+35
+
+chain 1325 chr8_random 943810 + 330748 334904 8 146364022 - 99513486 99513886 3761248
+39 3999 243
+118
+
+chain 1299 chr8_random 943810 + 216700 216875 8 146364022 - 99512515 99512690 2121346
+175
+
+chain 1278 chr8_random 943810 + 275077 288204 8 146364022 + 46842223 46845574 199410
+48 13052 3276
+27
+
+chain 1258 chr8_random 943810 + 272883 272996 8 146364022 + 43835974 43836087 2232086
+113
+
+chain 1256 chr8_random 943810 + 324880 325008 8 146364022 - 99513272 99513400 5381670
+128
+
+chain 1237 chr8_random 943810 + 196535 196612 8 146364022 - 99507792 99507869 15310375
+77
+
+chain 1235 chr8_random 943810 + 284286 284429 8 146364022 + 46839806 46839949 2930992
+143
+
+chain 1191 chr8_random 943810 + 293574 293786 8 146364022 + 46839704 46839915 1788603
+62 1 0
+149
+
+chain 1161 chr8_random 943810 + 294116 294212 8 146364022 + 43829899 43829995 1318655
+4 39 39
+53
+
+chain 1160 chr8_random 943810 + 183897 184027 8 146364022 + 43793197 43793327 2884372
+130
+
+chain 1130 chr8_random 943810 + 241032 308421 8 146364022 - 102539359 102541234 585349
+125 60736 871
+57 75 74
+53 2150 266
+105 4036 272
+52
+
+chain 1119 chr8_random 943810 + 229190 229281 8 146364022 - 99508572 99508663 1537143
+73 17 17
+1
+
+chain 1018 chr8_random 943810 + 315759 315867 8 146364022 - 102570622 102570730 1907772
+108
+
+chain 1013 chr8_random 943810 + 274298 274330 8 146364022 + 46839580 46839612 3252033
+32
+
+chain 968 chr8_random 943810 + 209695 209807 8 146364022 - 102537590 102537702 976902
+112
+
+chain 955 chr8_random 943810 + 319692 319755 8 146364022 - 102541225 102541288 3356813
+63
+
+chain 920 chr8_random 943810 + 258623 258775 8 146364022 + 46839508 46839659 980562
+59 25 24
+68
+
+chain 912 chr8_random 943810 + 192332 192490 8 146364022 + 46839260 46839417 3759652
+73 1 0
+84
+
+chain 891 chr8_random 943810 + 282553 282623 8 146364022 + 46843688 46843758 5243973
+70
+
+chain 873 chr8_random 943810 + 329911 329999 8 146364022 - 99523866 99523954 8492095
+88
+
+chain 847 chr8_random 943810 + 202393 202429 8 146364022 - 99516251 99516287 1768031
+36
+
+chain 808 chr8_random 943810 + 208103 208146 8 146364022 - 99506642 99506685 12166401
+43
+
+chain 772 chr8_random 943810 + 215530 215581 8 146364022 - 102536642 102536693 4621463
+51
+
+chain 770 chr8_random 943810 + 298794 298927 8 146364022 - 102529795 102529928 1833110
+38 53 53
+42
+
+chain 762 chr8_random 943810 + 250305 250368 8 146364022 + 43793197 43793260 2202736
+63
+
+chain 756 chr8_random 943810 + 175550 175595 8 146364022 - 102569149 102569194 15473865
+45
+
+chain 725 chr8_random 943810 + 227416 227458 8 146364022 - 102569147 102569189 2128584
+42
+
+chain 715 chr8_random 943810 + 237975 238010 8 146364022 - 99524101 99524136 9984625
+35
+
+chain 713 chr8_random 943810 + 336818 336983 8 146364022 - 102542943 102543107 12287033
+51 32 31
+82
+
+chain 659 chr8_random 943810 + 178382 178432 8 146364022 + 43825088 43825138 1126561
+50
+
+chain 630 chr8_random 943810 + 343296 343350 8 146364022 - 102532544 102532598 1087222
+54
+
+chain 622 chr8_random 943810 + 284683 284767 8 146364022 + 46845804 46845888 4299331
+84
+
+chain 618 chr8_random 943810 + 240201 240253 8 146364022 - 99520719 99520771 5790991
+52
+
+chain 609 chr8_random 943810 + 323290 333340 8 146364022 - 99511696 99512332 2037608
+32 1962 77
+33 7985 456
+38
+
+chain 511 chr8_random 943810 + 216312 216456 8 146364022 - 99508390 99508534 2116227
+83 23 23
+38
+
+chain 484 chr8_random 943810 + 208068 208103 8 146364022 - 102535970 102536005 2214348
+35
+
+chain 473 chr8_random 943810 + 323389 323449 8 146364022 - 102540821 102540881 1734527
+60
+
+chain 468 chr8_random 943810 + 200282 202177 8 146364022 - 99515228 99517906 493558
+37 1827 2610
+31
+
+chain 468 chr8_random 943810 + 309496 309560 8 146364022 - 99509535 99509598 902510
+13 1 0
+50
+
+chain 464 chr8_random 943810 + 238361 238411 8 146364022 - 102570011 102570061 2549299
+50
+
+chain 406 chr8_random 943810 + 336390 336452 8 146364022 - 99513496 99513558 3227798
+62
+
+chain 400 chr8_random 943810 + 198171 198198 8 146364022 - 99524348 99524375 19170252
+27
+
+chain 389 chr8_random 943810 + 239467 298039 8 146364022 - 99516251 99516834 914933
+36 19 19
+76 58363 374
+78
+
+chain 383 chr8_random 943810 + 268230 268298 8 146364022 + 43829500 43829568 7647204
+68
+
+chain 371 chr8_random 943810 + 289553 289594 8 146364022 + 43829105 43829146 1419836
+41
+
+chain 325 chr8_random 943810 + 171359 194889 8 146364022 - 102534570 102537063 1177879
+33 23458 2421
+39
+
+chain 321 chr8_random 943810 + 245198 245253 8 146364022 + 46850481 46850536 16403329
+55
+
+chain 316 chr8_random 943810 + 336558 336619 8 146364022 - 99513661 99513722 9588463
+61
+
+chain 316 chr8_random 943810 + 215939 215982 8 146364022 - 102570362 102570405 11794790
+43
+
+chain 307 chr8_random 943810 + 268331 268373 8 146364022 + 46843677 46843719 14936951
+42
+
+chain 302 chr8_random 943810 + 246654 246683 8 146364022 + 46846317 46846346 2597963
+29
+
+chain 277 chr8_random 943810 + 330681 336249 8 146364022 - 99513081 99513355 13257215
+37 5476 182
+55
+
+chain 224 chr8_random 943810 + 233016 233053 8 146364022 - 102535110 102535147 5909193
+37
+
+chain 219 chr8_random 943810 + 216875 216929 8 146364022 - 99508952 99509006 1250703
+54
+
+chain 217 chr8_random 943810 + 192086 192136 8 146364022 + 43793491 43793541 12267504
+50
+
+chain 176 chr8_random 943810 + 230251 230289 8 146364022 - 99522702 99522740 26486914
+38
+
+chain 171 chr8_random 943810 + 301863 301893 8 146364022 - 99524375 99524405 2607431
+30
+
+chain 128 chr8_random 943810 + 303580 303689 8 146364022 - 102542031 102542140 1606173
+109
+
+chain 117 chr8_random 943810 + 213542 213590 8 146364022 - 102569848 102569896 24793283
+48
+
+chain 107 chr8_random 943810 + 265719 265758 8 146364022 + 43793691 43793730 32387625
+39
+
+chain 103 chr8_random 943810 + 302985 303114 8 146364022 - 99516149 99516278 2070053
+129
+
+chain 102 chr8_random 943810 + 266041 266087 8 146364022 + 43794012 43794058 15664471
+46
+
+chain 87 chr8_random 943810 + 266314 266347 8 146364022 + 46839806 46839839 33038660
+33
+
+chain 11336435868 chr9 140273252 + 0 140273252 9 141213431 + 10000 141153431 13
+189075 1 1
+14 2 2
+39464594 50000 50000
+261110 50000 50000
+208233 50000 50000
+142805 50000 50000
+464507 50000 50000
+152873 50000 50000
+172579 50000 50000
+799200 0 4
+398958 50000 50000
+549743 50000 100000
+632871 50000 50000
+680077 50000 50000
+181647 50000 50000
+291910 50000 100000
+465318 50000 50000
+350909 50000 50000
+194609 50000 100000
+370335 0 176
+128583 50000 100000
+157546 18100000 18150000
+450681 50000 50000
+223855 50000 50000
+162441 50000 50000
+159539 50000 50000
+199148 50000 50000
+194491 50000 100000
+158462 50000 150000
+471702 50000 150000
+376183 50000 150000
+174765 50000 150000
+289439 50000 50000
+682157 50000 50000
+158187 50000 100000
+187806 50000 50000
+178933 50000 100000
+21507948 50000 100000
+85380 50000 150000
+834971 1 0
+39559293 100000 150000
+3818133 200000 50000
+2075804 30000 50000
+1936434
+
+chain 19053295 chr9_random 1146434 + 140076 853151 9 141213431 + 43822338 44639038 145
+1110 1 1
+47 1 0
+215 1 0
+468 9 9
+1934 0 1
+953 14319 26012
+970 11 11
+117 1 1
+57 1 1
+127 0 1
+1035 1 1
+123 1 1
+1418 29455 36221
+965 1 1
+33 5 5
+816 1 1
+38 1 1
+87 8 8
+588 6 6
+286 13 13
+967 6 6
+911 125 14857
+67 1 1
+18 1 1
+472 11 11
+269 7 0
+869 1 1
+23 1 1
+240 1 0
+456 1 1
+96 1 1
+247 22 22
+225 1 1
+13 0 4
+40 1 1
+211 13 29
+582 1 1
+22 4 0
+453 1 1
+37 1 1
+251 11 11
+87 1 1
+49 1 1
+95 11 11
+149 1 1
+31 1 1
+205 5 0
+1090 5 5
+89 1 1
+74 14 14
+83 1 1
+51 1 1
+594 1 3
+462 85 85
+635 50621 3293
+88 0 1
+148 18 18
+428 2 0
+5 2 0
+19 0 1
+43 1 1
+529 1 6
+77 1 1
+31 1 1
+39 0 5
+124 15 15
+51 1 1
+80 1 1
+103 1 1
+77 1 1
+147 1 1
+72 1 1
+95 10 10
+657 1 1
+57 1 1
+69 1 1
+32 1 1
+587 4 4
+298 14 14
+1505 10 8
+560 0 4
+171 1 1
+44 1 1
+211 1 1
+22 1 1
+649 1 1
+42 0 2
+96 8 8
+45 1 0
+195 402195 519766
+38949 0 176
+45847 1 0
+46124 1 0
+3889 0 1
+52224
+
+chain 10363290 chr9_random 1146434 + 903151 1075657 GL000199.1 169874 + 0 130000 308
+35955 882 0
+20 1020 0
+32 3062 0
+106 14 15
+100 9 7
+334 16 18
+121 1 0
+84 3469 73
+179 1193 0
+255 3064 0
+235 844 167
+325 2720 0
+211 25 25
+216 3639 67
+100 681 1
+58 5271 0
+71 36 36
+155 11817 855
+1017 1 0
+10599 1 1
+42 0 1
+8519 112 112
+9882 0 680
+263 8 8
+56 30 30
+206 865 183
+1131 1 0
+12309 16295 0
+37 2637 0
+463 15 15
+739 1 1
+64 1 1
+2323 1 0
+743 202 202
+245 2 0
+10307 33 32
+8496 15 15
+1065 3 3
+49 1 1
+67 1 1
+24 1 1
+150 15 15
+81 1112 7412
+104 5 5
+160 48 48
+156 31 31
+109 29 29
+32 0 337
+118 36 36
+108 21 21
+69 163 165
+105 29 29
+255 32 32
+176 46 46
+97 54 54
+158 110 5213
+54 5 5
+61 1 0
+12 66 578
+49 0 1
+256 0 1
+5 1 0
+110 0 507
+39 59 227
+44 1 0
+5 1 2
+13 268 611
+32 340 0
+2169 5 5
+109
+
+chain 8496666 chr9_random 1146434 + 526031 616031 GL000198.1 90085 + 0 90000 391
+90000
+
+chain 3482851 chr9_random 1146434 + 0 36148 GL000201.1 36148 + 0 36148 837
+36148
+
+chain 3114479 chr9_random 1146434 + 350153 383343 7 159138663 + 58020084 58054331 923
+5741 0 1
+5176 1 1
+36 1 1
+8401 0 3
+180 1 0
+1283 1 371
+2015 11 695
+10343
+
+chain 2652717 chr9_random 1146434 + 939453 971857 GL000199.1 169874 + 50544 169869 966
+78 104 103
+57 43 43
+41 0 1193
+212 20 20
+112 51 51
+93 1 0
+763 32 32
+929 0 85729
+2133 785 785
+1551 1 1
+38 0 1
+29 1 1
+1849 179 179
+1081 14 14
+98 255 255
+3064 235 235
+844 325 325
+2000 1 1
+55 1 1
+663 211 211
+25 216 216
+3639 100 100
+681 58 58
+5271 71 71
+36 155 155
+4203
+
+chain 864673 chr9_random 1146434 + 1126594 1146123 9 141213431 - 1097613 1113419 4959
+1953 6 5
+978 2409 6373
+1991 1 1
+30 1 1
+1102 7741 55
+57 1 1
+3259
+
+chain 850211 chr9_random 1146434 + 1025598 1042157 GL000199.1 169874 + 85137 125159 1202
+223 15 15
+69 106 782
+56 4 4
+103 0 1190
+57 51 51
+154 11 11
+103 0 1190
+303 94 5704
+122 20 700
+283 11 11
+564 0 6798
+68 31 31
+85 0 1
+80 48 48
+422 49 50
+604 27 3091
+147 0 4594
+563 468 470
+104 1 1
+65 1 1
+786 1 1
+26 4 4
+3436 346 0
+2356 158 158
+2985 37 37
+170 167 170
+910 11 11
+54
+
+chain 769263 chr9_random 1146434 + 86461 232520 9 141213431 + 40031497 40507253 306
+1287 1 1
+39 9090 8469
+1482 3 0
+72 22972 39210
+845 1 5
+1628 100 33581
+19 1 1
+708 1 1
+40 1 1
+1672 2596 163229
+3012 1 1
+27 1 0
+759 0 1
+98 72164 49914
+85 17764 159979
+3474 1 1
+50 1 1
+6064
+
+chain 759449 chr9_random 1146434 + 205961 214049 9 141213431 + 40301888 40309971 6546
+2149 0 1
+2715 38 32
+3186
+
+chain 584316 chr9_random 1146434 + 1135427 1141773 9 141213431 + 140095418 140108346 9081
+578 0 1
+958 0 1
+3002 120 6700
+1688
+
+chain 406492 chr9_random 1146434 + 174973 187473 9 141213431 - 97329171 97382324 1352
+1045 1 0
+610 3 3
+25 1 1
+707 0 1
+949 1 0
+476 1 1
+37 0 2
+115 22 0
+99 2 0
+19 0 1
+85 84 84
+391 0 2
+2020 102 40820
+178 0 5
+70 1 1
+108 1 0
+1683 56 22
+203 4 0
+53 0 3
+1920 1 0
+25 15 0
+171 0 4
+991 1 0
+102 1 1
+39 1 0
+81
+
+chain 392431 chr9_random 1146434 + 102229 150933 9 141213431 - 100800050 101111299 1649
+1200 31 31
+61 100 87
+1550 13066 115954
+174 1 7
+2845 28138 189099
+40 1462 165
+36
+
+chain 384690 chr9_random 1146434 + 98535 256322 9 141213431 - 100787713 101169878 613
+1160 1 0
+743 100 2055
+1590 33793 2374
+3943 1 0
+110 10986 2654
+28 3892 11
+65 38 37
+101 8010 603
+1627 0 1
+4154 127 18597
+1903 17 17
+1098 1 0
+907 16 6
+635 1 0
+110 11 10
+1170 39276 55950
+254 1 1
+16 1 1
+222 1 1
+23 0 3
+11 1 1
+963 0 1
+1311 1 1
+22 1 1
+1083 0 2
+4770 9790 219711
+142 1 1
+35 1 1
+191 1 1
+48 1 1
+4295 1 0
+1323 1 1
+26 1 0
+2991 1 0
+1653 100 28511
+184 1 1
+25 1 1
+2332 2 0
+2424 1 1
+18 1 1
+1612 0 2
+1973 2 0
+4314
+
+chain 222862 chr9_random 1146434 + 974475 976909 GL000199.1 169874 - 29206 35723 496317
+103 0 512
+103 0 2379
+1951 0 1192
+277
+
+chain 216950 chr9_random 1146434 + 179171 191499 9 141213431 - 75591738 75613431 4354
+84 8327 17685
+315 1 1
+43 1 1
+565 1 1
+45 1 1
+144 1 1
+47 3 3
+216 4 8
+856 15 15
+173 1 1
+23 0 1
+306 1 1
+34 1 2
+855 1 1
+41 1 1
+59 0 1
+60 1 1
+46 1 1
+55
+
+chain 213582 chr9_random 1146434 + 1129631 1131840 9 141213431 - 1091833 1094042 537694
+2209
+
+chain 165378 chr9_random 1146434 + 971957 973731 X 155270560 + 21244335 21246110 770883
+1088 0 1
+111 1 1
+46 3 3
+525
+
+chain 132596 chr9_random 1146434 + 92033 271291 9 141213431 - 75460140 75627580 890
+687 15 5
+714 42447 12782
+26 11947 6649
+27 11 12
+38 1490 2
+104 2 0
+98 117515 142147
+548 14 14
+760 1 1
+15 5 5
+244 0 8
+225 1 1
+25 1 1
+184 1 1
+24 1 1
+112 1 1
+49 1 1
+657 0 4
+26 1 1
+142 1 1
+117 1 1
+521 1 1
+30 1 1
+427
+
+chain 126182 chr9_random 1146434 + 264182 265594 9 141213431 + 41417376 41418784 8289
+408 11 11
+453 3 0
+470 1 0
+66
+
+chain 121265 chr9_random 1146434 + 153981 183865 9 141213431 + 40369543 40485128 5651
+820 1 0
+80 65 65
+38 101 101
+1814 1 1
+19 1 1
+2113 24775 110477
+56
+
+chain 112452 chr9_random 1146434 + 977951 979143 9 141213431 + 41554070 41555262 1142654
+1192
+
+chain 111666 chr9_random 1146434 + 115028 116206 9 141213431 + 38976673 38977851 1144814
+1178
+
+chain 91839 chr9_random 1146434 + 95026 96000 9 141213431 - 97340505 97341479 1389514
+974
+
+chain 86695 chr9_random 1146434 + 89274 94894 9 141213431 + 40421854 40482922 755289
+656 0 1
+294 1 0
+357 1 1
+58 1 1
+181 2726 58174
+1345
+
+chain 85848 chr9_random 1146434 + 116324 118085 9 141213431 + 40126032 40127795 187229
+1300 0 2
+247 1 1
+31 1 1
+181
+
+chain 83527 chr9_random 1146434 + 105271 111078 9 141213431 + 43838264 43842306 8535
+1025 1 1
+44 1 1
+374 2077 318
+609 3 0
+643 18 19
+121 15 16
+135 5 0
+736
+
+chain 82351 chr9_random 1146434 + 265594 267154 9 141213431 - 97363431 97364991 1727
+341 2 2
+20 1 1
+738 1 1
+34 1 1
+206 1 1
+40 1 1
+174
+
+chain 74906 chr9_random 1146434 + 107880 108681 9 141213431 + 40288016 40288817 1344818
+46 1 0
+553 0 1
+201
+
+chain 73427 chr9_random 1146434 + 106816 115028 9 141213431 - 93902441 93905998 1707
+229 0 1
+500 19 19
+145 5760 1098
+49 0 1
+9 0 1
+188 1 1
+43 1 1
+243 1 1
+41 1 1
+206 1 1
+25 1 1
+443 0 1
+171 0 3
+135
+
+chain 72594 chr9_random 1146434 + 977068 977842 9 141213431 - 99740263 99741035 1743552
+651 1 0
+45 1 0
+76
+
+chain 68316 chr9_random 1146434 + 87923 91873 9 141213431 - 101134923 101183249 1049825
+372 0 1
+115 1 1
+37 1 1
+725 1749 46124
+950
+
+chain 61838 chr9_random 1146434 + 1042331 1042988 GL000199.1 169874 - 40496 41153 2045151
+657
+
+chain 55013 chr9_random 1146434 + 1075993 1076574 2 243199373 - 242829160 242829741 2308873
+581
+
+chain 54512 chr9_random 1146434 + 144930 149178 9 141213431 - 75605255 75609502 8620
+250 1 1
+26 1 1
+262 14 19
+1397 10 9
+876 1 0
+98 79 75
+65 1 1
+772 1 1
+31 1 1
+235 1 1
+74 1 1
+51
+
+chain 52053 chr9_random 1146434 + 149316 153855 9 141213431 + 40375457 40380000 99648
+79 244 244
+76 2437 2440
+75 10 10
+247 0 1
+19 1304 1304
+48
+
+chain 51431 chr9_random 1146434 + 126523 128919 9 141213431 - 101152632 101155028 6098
+2396
+
+chain 48062 chr9_random 1146434 + 390785 391322 5 180915260 - 163073999 163074536 2667488
+241 1 1
+201 3 3
+91
+
+chain 43629 chr9_random 1146434 + 1073062 1075987 GL000199.1 169874 + 35053 37976 298767
+312 2456 2456
+1 2 0
+78 21 21
+55
+
+chain 37453 chr9_random 1146434 + 1024767 1030521 GL000199.1 169874 + 88172 123905 8301
+52 0 3738
+40 1994 12406
+94 1068 11110
+31 165 2038
+48 1933 5847
+329
+
+chain 33524 chr9_random 1146434 + 133017 135796 9 141213431 + 39163384 39166153 115831
+53 1 1
+307 5 4
+44 1 1
+406 1 1
+21 5 0
+43 1 1
+177 1 1
+25 1 0
+31 1 1
+137 5 5
+20 1 1
+52 1 1
+27 1 1
+233 1 1
+20 1 1
+394 3 0
+363 1 1
+24 1 1
+370
+
+chain 29196 chr9_random 1146434 + 343146 344485 3 198022430 + 156000638 156001989 5034584
+50 1 0
+56 1 1
+104 128 140
+64 838 839
+97
+
+chain 28265 chr9_random 1146434 + 96095 96747 9 141213431 - 93903474 93904131 1828707
+74 0 10
+511 4 0
+47 1 0
+15
+
+chain 26156 chr9_random 1146434 + 111189 113362 9 141213431 - 102220148 102222323 47568
+1400 0 1
+94 5 6
+674
+
+chain 25868 chr9_random 1146434 + 149715 153807 9 141213431 - 93950637 93954729 91748
+181 1 1
+57 1 1
+353 15 15
+330 1 0
+22 1 1
+220 93 93
+114 0 17
+104 9 9
+290 2 0
+293 1 1
+20 1 1
+328 351 343
+127 1 1
+76 1 1
+331 4 0
+52 1 1
+17 1 1
+106 5 0
+146 1 1
+38 0 3
+7 1 0
+116 3 3
+16 1 1
+168 0 1
+85
+
+chain 25003 chr9_random 1146434 + 1069304 1075830 GL000199.1 169874 + 56286 59580 21268
+305 7 7
+77 487 487
+25 288 288
+36 198 198
+163 105 105
+29 463 463
+46 1256 67
+82 36 36
+95 32 32
+28 2595 552
+103 9 9
+61
+
+chain 23281 chr9_random 1146434 + 1028681 1035309 GL000199.1 169874 + 97567 114227 7110
+30 1360 6799
+121 342 0
+5 4424 9363
+103 237 233
+6
+
+chain 21805 chr9_random 1146434 + 1135081 1135321 9 141213431 + 140101239 140101479 9135145
+197 1 1
+42
+
+chain 21533 chr9_random 1146434 + 1010735 1043373 GL000199.1 169874 + 61213 69988 6310
+337 14018 4703
+439 42 42
+27 307 307
+106 220 220
+51 16938 2390
+153
+
+chain 19014 chr9_random 1146434 + 335566 335883 16 90354753 - 56512811 56513131 11268597
+170 97 100
+50
+
+chain 18803 chr9_random 1146434 + 86148 86348 9 141213431 - 100705477 100705677 11441237
+200
+
+chain 13349 chr9_random 1146434 + 1068589 1070018 GL000199.1 169874 + 79052 79803 7749
+23 14 14
+253 37 37
+60 717 39
+8 269 269
+48
+
+chain 13149 chr9_random 1146434 + 410938 411078 8 146364022 + 38639711 38639851 17290853
+140
+
+chain 12972 chr9_random 1146434 + 332343 332481 7 159138663 + 61759398 61759536 17535033
+138
+
+chain 12821 chr9_random 1146434 + 388858 389014 15 102531392 + 80798356 80798512 17757829
+81 12 12
+63
+
+chain 11442 chr9_random 1146434 + 388166 388417 12 133851895 + 34836761 34837526 19956621
+81 109 623
+61
+
+chain 11149 chr9_random 1146434 + 343358 343713 3 198022430 - 62479553 62479920 5356830
+1 103 115
+24 134 134
+93
+
+chain 11085 chr9_random 1146434 + 468603 468722 9 141213431 + 42720405 42720524 20596057
+119
+
+chain 9550 chr9_random 1146434 + 389696 390760 X 155270560 + 61752907 61753125 23891795
+65 939 93
+60
+
+chain 9178 chr9_random 1146434 + 345818 345932 16 90354753 + 32819577 32819691 24666411
+52 7 7
+55
+
+chain 9128 chr9_random 1146434 + 321692 322933 7 159138663 + 61799163 61799701 24755828
+61 1115 412
+65
+
+chain 9086 chr9_random 1146434 + 338884 339289 16 90354753 + 32789437 32789842 24819157
+53 289 289
+63
+
+chain 9023 chr9_random 1146434 + 387021 388166 7 159138663 + 61404533 61405164 23790101
+52 1085 571
+8
+
+chain 7872 chr9_random 1146434 + 1069035 1072121 GL000199.1 169874 + 119465 157584 536281
+72 46 46
+97 2835 37868
+36
+
+chain 7579 chr9_random 1146434 + 402601 403961 3 198022430 - 107545066 107546932 27123369
+31 1026 0
+52 201 1733
+50
+
+chain 7458 chr9_random 1146434 + 343360 343449 6 171115067 + 69499143 69499232 6836024
+89
+
+chain 6713 chr9_random 1146434 + 425056 425127 16 90354753 + 46455806 46455877 28826250
+71
+
+chain 6541 chr9_random 1146434 + 468921 468991 7 159138663 + 61361207 61361277 29216706
+70
+
+chain 6486 chr9_random 1146434 + 330636 330705 10 135534747 + 42383267 42383336 29375264
+69
+
+chain 6456 chr9_random 1146434 + 411427 412083 11 135006516 + 48877623 48879132 29439180
+48 554 1407
+54
+
+chain 6295 chr9_random 1146434 + 404771 404838 8 146364022 + 43770407 43770474 29850106
+67
+
+chain 6049 chr9_random 1146434 + 414120 414184 7 159138663 - 101095351 101095415 30492982
+64
+
+chain 6040 chr9_random 1146434 + 465963 466027 6 171115067 + 83274875 83274939 30512451
+64
+
+chain 5969 chr9_random 1146434 + 389015 389089 Y 59373566 - 43064540 43064609 20514560
+61 5 0
+8
+
+chain 5636 chr9_random 1146434 + 406636 407740 8 146364022 + 43770397 43770476 31630565
+28 1025 0
+51
+
+chain 5631 chr9_random 1146434 + 426803 426863 10 135534747 + 42387748 42387808 31636152
+60
+
+chain 5540 chr9_random 1146434 + 419067 419126 7 159138663 + 61079182 61079241 31906304
+59
+
+chain 5476 chr9_random 1146434 + 398987 399045 12 133851895 + 34839855 34839913 32105830
+58
+
+chain 5376 chr9_random 1146434 + 415322 415379 11 135006516 - 86268315 86268372 32415872
+57
+
+chain 5358 chr9_random 1146434 + 413960 414017 Y 59373566 - 49305277 49305334 32458256
+57
+
+chain 5349 chr9_random 1146434 + 411179 411236 7 159138663 + 91218545 91218602 32466470
+57
+
+chain 5349 chr9_random 1146434 + 417041 417098 11 135006516 - 84295010 84295067 32466776
+57
+
+chain 5305 chr9_random 1146434 + 979284 979471 GL000199.1 169874 + 100510 100697 1541
+187
+
+chain 5294 chr9_random 1146434 + 393589 393645 GL000208.1 92689 - 78786 78842 32648958
+56
+
+chain 5285 chr9_random 1146434 + 407829 407885 16 90354753 + 34022252 34022308 32672407
+56
+
+chain 5248 chr9_random 1146434 + 345095 345150 3 198022430 + 72765342 72765397 32777800
+55
+
+chain 5194 chr9_random 1146434 + 325928 325983 16 90354753 + 46454212 46454267 32965981
+55
+
+chain 5076 chr9_random 1146434 + 385523 385577 9 141213431 - 74211269 74211323 33342253
+54
+
+chain 5012 chr9_random 1146434 + 398477 398530 3 198022430 - 107545544 107545597 33565319
+53
+
+chain 4985 chr9_random 1146434 + 417987 418040 8 146364022 + 43776134 43776187 33649135
+53
+
+chain 4821 chr9_random 1146434 + 397137 397188 X 155270560 + 61817502 61817553 34214385
+51
+
+chain 4794 chr9_random 1146434 + 414576 414627 11 135006516 + 50778923 50778974 34325073
+51
+
+chain 4794 chr9_random 1146434 + 397714 397765 GL000208.1 92689 - 71810 71861 34325191
+51
+
+chain 4730 chr9_random 1146434 + 411917 411967 21 48129895 - 33764186 33764236 34527656
+50
+
+chain 4709 chr9_random 1146434 + 107713 107880 9 141213431 + 40326898 40327067 460940
+64 0 2
+103
+
+chain 4703 chr9_random 1146434 + 396620 396670 11 135006516 + 50701175 50701225 34648839
+50
+
+chain 4594 chr9_random 1146434 + 460317 460366 1 249250621 + 72586197 72586246 34758860
+49
+
+chain 4154 chr9_random 1146434 + 389765 389825 X 155270560 + 61859291 61859351 24051909
+60
+
+chain 4125 chr9_random 1146434 + 1047887 1048034 GL000199.1 169874 + 145761 145908 266403
+21 18 18
+108
+
+chain 4032 chr9_random 1146434 + 1010207 1010501 GL000199.1 169874 + 46738 47032 105345
+133 51 51
+110
+
+chain 3744 chr9_random 1146434 + 974418 974475 GL000199.1 169874 - 111819 111876 792102
+57
+
+chain 3426 chr9_random 1146434 + 939387 939437 GL000199.1 169874 + 161370 161420 23133078
+50
+
+chain 3397 chr9_random 1146434 + 1069115 1069304 GL000199.1 169874 + 57287 57476 721888
+38 97 97
+54
+
+chain 3297 chr9_random 1146434 + 1037665 1037723 GL000199.1 169874 + 108413 108471 1099981
+5 32 32
+21
+
+chain 2900 chr9_random 1146434 + 210827 210859 9 141213431 + 43889710 43889742 6957
+32
+
+chain 2688 chr9_random 1146434 + 1042157 1042279 GL000199.1 169874 + 112227 112349 8300
+65 9 9
+48
+
+chain 2652 chr9_random 1146434 + 999650 1043482 GL000199.1 169874 + 41812 46278 8409
+112 43376 4009
+54 0 1
+28 153 153
+109
+
+chain 2438 chr9_random 1146434 + 1025529 1025571 GL000199.1 169874 + 134052 134094 269933
+42
+
+chain 2404 chr9_random 1146434 + 153855 153881 9 141213431 + 40071265 40071291 103174
+26
+
+chain 2298 chr9_random 1146434 + 1010672 1010735 GL000199.1 169874 + 66766 66829 8935
+63
+
+chain 2164 chr9_random 1146434 + 1010368 1010391 9 141213431 - 71502272 71502295 32168220
+23
+
+chain 2160 chr9_random 1146434 + 388789 388840 7 159138663 - 101569537 101569588 23945255
+51
+
+chain 2026 chr9_random 1146434 + 343746 343819 10 135534747 + 18324071 18324144 14357746
+73
+
+chain 1834 chr9_random 1146434 + 1010501 1010672 GL000199.1 169874 + 60299 60470 7461
+171
+
+chain 1808 chr9_random 1146434 + 391322 391360 7 159138663 - 47529927 47529965 6263864
+38
+
+chain 1777 chr9_random 1146434 + 343550 344817 22 51304566 + 35077657 35078810 5733588
+48 1167 1053
+52
+
+chain 1529 chr9_random 1146434 + 263922 264091 9 141213431 + 65673675 65673833 515
+62 10 0
+17 1 0
+14 2 2
+63
+
+chain 1325 chr9_random 1146434 + 1037723 1037780 GL000199.1 169874 + 96057 96114 245438
+57
+
+chain 1237 chr9_random 1146434 + 1024624 1024767 GL000199.1 169874 + 49580 49723 8604
+143
+
+chain 1217 chr9_random 1146434 + 1071842 1072151 GL000199.1 169874 + 48108 48417 165690
+30 6 6
+74 169 169
+30
+
+chain 897 chr9_random 1146434 + 1035274 1035303 GL000199.1 169874 + 108574 108603 711169
+29
+
+chain 881 chr9_random 1146434 + 345308 345393 X 155270560 - 77826120 77826205 8910963
+85
+
+chain 812 chr9_random 1146434 + 344331 344387 9 141213431 + 18649465 18649521 20542621
+56
+
+chain 538 chr9_random 1146434 + 1029334 1029359 GL000199.1 169874 + 75943 75968 9317
+25
+
+chain 480 chr9_random 1146434 + 344828 344880 4 191154276 - 62643619 62643671 15050009
+52
+
+chain 461 chr9_random 1146434 + 96747 96777 9 141213431 + 38980922 38980952 1279
+30
+
+chain 364 chr9_random 1146434 + 1025018 1025062 GL000199.1 169874 + 64308 64352 115390
+44
+
+chain 296 chr9_random 1146434 + 1009971 1010001 GL000199.1 169874 + 44634 44664 18919
+30
+
+chain 288 chr9_random 1146434 + 974120 974172 GL000199.1 169874 + 44920 44972 1936043
+52
+
+chain 260 chr9_random 1146434 + 394227 394279 11 135006516 + 50701175 50701227 28339537
+52
+
+chain 210 chr9_random 1146434 + 1025062 1025090 GL000199.1 169874 + 71670 71699 216729
+6 0 1
+22
+
+chain 209 chr9_random 1146434 + 388033 388083 11 135006516 - 84294197 84294247 27927923
+50
+
+chain 152 chr9_random 1146434 + 393023 393074 20 63025520 + 26259164 26259215 28112557
+51
+
+chain 86 chr9_random 1146434 + 405210 405252 3 198022430 - 107550280 107550322 32195393
+42
+
+chain 79 chr9_random 1146434 + 392892 392941 11 135006516 + 50661000 50661049 27948217
+49
+
+chain 1574309 chrM 16571 + 0 16571 MT 16569 + 0 16569 1567
+302 1 0
+8 1 0
+2796 0 1
+13086 1 0
+376
+
+chain 14267288654 chrX 154913754 + 0 154913754 X 155270560 + 60000 155260560 8
+34821 50000 50000
+86563 30000 50000
+766173 50000 50000
+36556 50000 50000
+80121 90000 50000
+754004 100000 50000
+5505644 0 50000
+3064785 0 50079
+26309510 25000 50000
+201175 0 8
+7417 2 0
+53136 0 8
+3076 12 0
+21092 2 0
+60831 0 2
+57728 20 0
+54336 1 0
+31676 4 0
+9986 0 4
+12109 4 0
+11227342 2000 0
+354815 50000 50000
+77401 1 1
+17 1 1
+94 3 0
+266 10 10
+113 1 1
+21 1 1
+5401 5 0
+4970 2 0
+33 6 0
+3221 1 5
+6456 0 1
+1476 5 5
+2100 1 1
+40 1 1
+1316 1 0
+2446 0 1
+1589 17 15
+11171 0 1
+2639 0 1
+5190 4 0
+78 0 8
+5087 1 0
+2663 0 1
+9149 8 7
+1851 1 0
+9081 1 0
+7249 0 25
+199 2 0
+12 2 0
+16 0 209
+37 0 20
+2536 1 0
+1394 6 0
+12550 42 0
+821 0 4
+30579 0 1
+3710 0 4
+3638 0 1
+11945 1 0
+20204 1 0
+4171 0 8
+5680 0 1
+23827 2 0
+54817 1 0
+657 1 0
+342931 180000 50000
+2052068 1 27
+5375 0 2
+46 2 0
+6489 1 0
+7175 0 2
+1239 0 2
+4302 4 0
+27253 1 0
+4244 2 0
+717 2 0
+261 6 0
+26074 0 1
+236464 50000 50000
+6136098 3000000 3100000
+13518993 0 1
+449 0 1
+4533 0 4
+757 0 1
+1102 25 26
+107 0 2
+3470 1 0
+1108 0 1
+4775 0 1
+8628 1 1
+46 1 1
+1072 1 1
+44 1 1
+292 5 4
+9091 4 4
+2218 4 4
+705 1 5
+452 1 0
+88 32 32
+212 1 0
+1801 1 7
+3960 0 1
+2007 0 1
+1979 38 38
+1320 0 1
+2093 0 1
+403 0 310
+6134 1 1
+36 1 1
+1697 0 1
+97 0 13
+7624 1 1
+19 1 1
+6933 0 1
+779 7 7
+721 1 1
+43 1 1
+1626 1 0
+6146 2 0
+150 1 1
+47 1 1
+2172 2 0
+398 1 1
+31 1 1
+1149 2 2
+183 16 16
+1663 1 1
+18 1 1
+2105 10 11
+1409 1 1
+33 1 1
+1753 0 1
+408 1 0
+1916 0 1
+477 37 37
+1415 12 0
+3799 17 17
+2921 1 0
+1811 33 33
+2753 2 0
+486 0 6
+1388 1 1
+44 1 1
+186 1 1
+46 1 1
+3037 1 0
+2301 3 0
+3876 1 1
+22 1 1
+1724 0 1
+3733 0 1
+627 0 1
+250 1 0
+194 1 1
+26 1 1
+20797 10 10
+2445 1 0
+1733 0 2
+1001 12 0
+4394 9 9
+4052 10 9
+670 1 1
+97 6 0
+25 1486 1188
+10 3 2
+28 41 41
+28 2 3
+10 126 1058
+11 1051 417
+25 0 6
+18 1 1
+62 17 17
+77 0 1
+1009 41 41
+3899 10 10
+4690 0 1
+7343 1 0
+1248 1 0
+1259 1 0
+1345 0 4
+1534 1 0
+3797 16 16
+807 1 0
+2427 1 0
+48 0 1
+287 1 0
+611353 0 1
+1041 6 0
+371 0 1
+227 0 1
+2806 1 0
+36 1 1
+234 1 1
+23 1 1
+584 1 0
+22241 1 1
+65 1 1
+4605 0 1
+2326 0 20
+2130 0 1
+6170 9 13
+10665 0 1
+14631 1 0
+5359 4 0
+4004 1 0
+3182 11 0
+3897 14 16
+2551 1 0
+1824 1 0
+5274 1 1
+41 1 1
+4309 0 1
+3827 0 1
+4594 0 1
+65 1 1
+1170 1 1
+42 4 4
+214 0 1
+5228 0 1
+553 1 0
+5528 7 7
+735 14 14
+2861 1 0
+156 0 2
+6183 42 42
+2595 1 1
+41 1 1
+472 1 1
+65 0 1
+8 1 1
+1162 1 0
+565 1 1
+48 1 1
+536 2 1
+766 0 2
+4520 0 1
+1574 1 0
+503 0 1
+2558 0 1
+250061 7 7
+9650 18 18
+3208 1 1
+25 0 1
+744 2 0
+2994 1 1
+33 1 1
+1331 1 0
+2042 6 17
+1292 1 1
+35 1 1
+2485 1 1
+35 1 1
+17284 1 0
+7 7 1
+670 0 4
+429 0 1
+4736 1 0
+3849 0 1
+6745 16 16
+2344 1 1
+41 1 1
+4459 9 9
+3449 0 1
+3876 1 1
+75 1 1
+1429 7 7
+11126 26 26
+781 1 1
+28 1 1
+409 12 13
+1223 12 12
+5354 0 1
+1255 0 6
+851 65 65
+126 1 1
+47 5 5
+5931 4 0
+420 0 1
+2949 0 6
+193 324 324
+6740 1 3
+1074 1 0
+2465 1 1
+40 1 1
+640 2 0
+550 1 1
+32 1 1
+4096 1 1
+29 1 1
+949 6 6
+6258 1 0
+3957 1 0
+19608 1 1
+48 1 1
+234 0 1
+13246 13 13
+4651 321 0
+2617 1 0
+4553 0 3
+491 0 6
+7496 1 1
+9 0 10
+77 0 4
+3314 1 1
+32 1 1
+5217 1 0
+1500 17 17
+2023 1 0
+2425 0 18
+3110 8 8
+3248 1 0
+1946 1 1
+48 1 1
+9620 0 2
+31242 20000 50000
+36075685 3 0
+36004 1 1
+27 1 1
+5196 0 1
+293 0 2
+13307 0 3
+2420 6 0
+1863 0 2
+2911 0 1
+3233 2 0
+66 1 0
+2376 10 0
+4893 1 0
+745 1 0
+3897 0 13
+3835 1 1
+55 1 1
+538 1 1
+48 4 1
+20 0 2
+279 0 2
+33 1 1
+48 1 0
+387 8 8
+692 0 1
+375 3 0
+383 1 1
+18 1 1
+1289 1 1
+29 1 1
+12332 0 331
+856 4 0
+48 0 4
+8716 0 5
+130 2 0
+3001 0 1
+1332 8 5
+23273 0 1
+30174 27 39
+337 0 3
+2838 1 0
+1614 0 9
+313 0 1
+83 4 0
+172 1 1
+25 1 1
+4912 0 39
+1863 0 1
+2931 1 0
+3134 0 3
+390880 0 1
+7199 1 0
+305 2 0
+1811 2 0
+5449 0 3
+7443 0 2
+2171 1 1
+27 1 1
+2668 0 2
+2180 0 1
+1170 0 9
+1450 16 16
+3080 1 0
+920 18 18
+10219 1 0
+678 1 1
+28 1 1
+698 1 0
+112 1 0
+1831 3 0
+14327 2 0
+2087 10 10
+150 0 3
+380 1 1
+28 1 1
+1265 19 21
+7184 3 2
+4225 9 14
+1002 0 1
+3855 4 0
+2534 1 1
+30 1 1
+794 1 0
+25 1 1
+76140 70000 50000
+1432750 4799 0
+8 2973 0
+681864 20000 50000
+4278742 0 56347
+12021233 9 9
+1775 1 0
+1468 1 1
+51 16 14
+6 0 1
+6 0 1
+11 4 5
+7 0 1
+4 0 1
+75 1 2
+26 1 0
+16 0 1
+9 0 1
+19 0 2
+22 1 0
+9 0 1
+5 1 3
+14 6 7
+38 1 0
+26 1 1
+62 0 1
+38 1 1
+1687 0 1
+54 0 1
+8528 0 1
+2722 0 1
+6240 0 1
+33 0 1
+121285 1 0
+6 0 1
+35 1 0
+1381 0 1
+5368 1 0
+3079 0 1
+10863441 0 4
+1799 1 1
+24 1 1
+334 1 0
+4960 17 0
+1160 1 1
+34 1 1
+6153 3 0
+1346 4 0
+103 4 0
+2835 12 12
+304 0 16
+719 0 1
+3286 1 0
+10182 0 9
+804 1 1
+28 1 1
+749 0 1
+3387 1 1
+47 1 1
+482 0 1
+455 15 15
+719 1 1
+18 1 1
+2074 0 1
+1348 0 4
+3928 1 1
+18 1 1
+907 0 1
+2972 2 0
+115 1 1
+37 1 1
+4428 1 0
+1120 1 0
+4055 5 0
+2753 18 18
+158 3 0
+3590 1 1
+47 1 1
+62 1 0
+947 1 1
+45 1 1
+1639 1 1
+32 1 1
+1076 0 1
+3996 4 0
+7965 1 0
+1733 1 0
+1451 0 2
+617 1 0
+4375 0 1
+2194 64 63
+301 1 1
+27 1 1
+6661 1 1
+79 1 1
+1495 1 0
+499 1 1
+37 2 2
+968 1 0
+34 1 1
+6337 1 1
+18 1 1
+8162 1 1
+22 5 0
+9274 1 0
+6017 5 5
+3872 8 0
+5421 1 0
+532 6 7
+5673 0 4
+1542 4 0
+890 3 1
+2561 1 0
+1692 1 0
+1142 1 1
+32 1 1
+503 2 1
+123 1 1
+75 1 1
+2322 1 0
+201 1 0
+40 3 3
+149 3 0
+1441 1 1
+40 1 1
+159 2 0
+1278 1 1
+33 1 1
+221 0 1
+31 1 1
+161 9 10
+1890 0 1
+132 1 1
+37 1 1
+514 17 23
+1373 4 0
+907 1 1
+15 1 1
+714 1 1
+18 0 1
+10 1 1
+55 1 1
+24 1 1
+1038 2 0
+95 1 5
+1094 1 1
+170 1 1
+844 0 3
+369 1 1
+39 1 1
+650 1 1
+41 1 1
+176 12 12
+688 1 0
+7640 4 0
+2650 1 1
+28 0 4
+44 1 1
+728 8 0
+2196 0 1
+13466 0 1
+3510 0 2
+2147 1 1
+44 0 3
+1320 11 11
+210 0 4
+105 1 0
+3239 0 1
+1496 142 153
+2391 1 1
+39 0 2
+438 4 0
+2272 8 0
+6865 0 3
+7183 0 1
+5104 0 3
+182 1 0
+3131 1 1
+31 1 0
+14 1 1
+59 1 0
+373 1 1
+42 1 1
+235 13 13
+1608 0 5
+152 1 1
+106 1 1
+783 34 34
+1633 1 1
+29 3 0
+821 1 1
+24 1 1
+1178 1 1
+33 1 1
+328 1 1
+27 1 1
+5682 16 13
+146398 30000 50000
+59809 0 2
+3389 1 1
+37 1 1
+11606 0 1
+1597 0 1
+618 1 1
+47 1 1
+2698 0 1
+826 5 5
+33 0 2
+2560 0 14
+98 0 3
+1287 0 1
+7600 0 1
+9894 0 8
+7160 0 1
+32 1 1
+1698 0 1
+754 2 0
+6787 0 1
+584 0 2
+1107 1 1
+40 1 1
+365 1 1
+35 1 1
+399 0 8
+11444 0 1
+1973 0 1
+1200 0 1
+716 1 1
+25 1 1
+1570 0 2
+433 2 0
+905 0 2
+94 1 1
+28 1 1
+2490 18 18
+5054 9 1
+2184 0 2
+2955 23 21
+431 49 49
+314 1 0
+1563 1 1
+20 1 1
+1632 11 0
+1671 2 0
+1527 0 1
+676 1 1
+29 1 1
+1245 1 1
+34 0 1
+1203 22 30
+1934 1 0
+3421 0 2
+17 1 1
+774 0 30
+97 6 6
+59 12 26
+840 1 1
+19 1 1
+2036 27 53
+683 30 30
+401 0 1
+25 1 1
+381 16 0
+159 1 1
+17 1 1
+1150 0 4
+700 1 0
+29 0 2
+409 1 1
+49 1 1
+1240 1 1
+37 3 3
+2248 0 1
+1828 0 1
+1997 1 5
+4640 4 4
+4555 2 0
+150 52 0
+618 2 2
+16 1 1
+83 0 22
+56 1 57
+2531 8 0
+4250 17 17
+2203 4 0
+1665 10 0
+415 0 2
+393 0 1
+15728 1 0
+158 0 4
+82 0 14
+543 1 1
+42 1 1
+3261 18 18
+139 1 1
+37 1 1
+410 1 1
+18 1 1
+5405 0 1
+1104 1 1
+53 1 1
+392 1 1
+55 3 3
+3352 0 9
+692 106 52
+27 4 0
+13 1 3
+14 88 0
+61 2 0
+8931 0 1
+6692 2 1
+253 19 19
+869 2 0
+196 0 2
+389 1 1
+30 1 1
+949 1 0
+6057 3 0
+4741 0 1
+7689 0 2
+2046 18 18
+215 1 0
+46885 0 2
+24138 0 2
+4037 0 1
+4047693 0 1
+9545 2 0
+11590 0 4
+1698 3 1
+18923 0 4
+1806 1 1
+44 1 1
+2581 2 0
+10620 1 0
+3804 1 0
+339 2 0
+476 1 0
+5861 5 8
+109 14 0
+901 1 1
+19 1 1
+45 0 2
+1736 0 1
+6625 0 2
+7812 0 4
+7678 0 2
+5086 3 8
+4170 1 0
+1671 0 6
+6333 16 0
+902 1 1
+44 1 1
+384 6 0
+23181 4 4
+214 0 2
+8958 4 0
+220 1 1
+49 1 1
+2783 1 0
+2641 1 0
+136 20 20
+1279 1 0
+3924 6 6
+13054 0 6
+8954 13 0
+4128 0 2
+2269 0 1
+16258 2 0
+30076 1 1
+49 1 1
+102 0 1
+8824 27 27
+1730 1 1
+47 1 1
+3339 1 0
+132 16 0
+81 0 16
+89 0 6
+6369 0 1
+541 0 1
+6288 4 0
+3814 0 2
+7260 1 0
+802 0 68
+1166 1 0
+2230 0 1
+1109 1 0
+1106 0 2
+12396 1 0
+26207 1 1
+21 1 1
+4087 16 0
+1323 7 7
+525 1 0
+4198 1 0
+4682 13 13
+890 2 0
+816 2 0
+1961 4 0
+24586 1 1
+19 1 1
+4403 0 1
+1342 0 1
+57 11 12
+2229 30 31
+1979 35 0
+10541 1 0
+9725 6 0
+2536 1 2
+20 1 1
+1541 12 0
+1130 1 1
+34 1 1
+927 1 0
+4003 1 0
+966 0 1
+149 1 0
+842 0 8
+4326 1 1
+25 1 1
+569 6 7
+664 2 2
+5695 0 1
+3074 1 0
+1539 9 3
+634 1 1
+39 1 1
+8610 1 1
+11 0 1
+345 43 43
+372 0 2
+4311 6 0
+3122 2 0
+369 0 1
+9963 10 10
+2191 1 1
+23 1 1
+1060 1 1
+19 1 1
+240 12 12
+1748 1 1
+45 1 1
+1040 1 1
+31 1 1
+7446 1 1
+25 1 1
+8379 7 7
+7325 0 3
+357 1 0
+1313 1 0
+11624 0 4
+5865 0 1
+9750 0 1
+3540 16 0
+5671 13 13
+2885 4 0
+8179 0 1
+753 1 0
+2289 49 49
+1979 2 0
+1318 0 1
+957 1 0
+825 12 12
+1110 16 0
+3735 17 17
+9997 223 53
+149 22 24
+636 1 1
+22 0 1
+42 1 1
+1634 4 4
+3380 3 0
+979 0 2
+3429 1 0
+7138 14 0
+1727 1 1
+38 1 0
+88 0 1
+630 20 20
+476 0 5
+21 0 1
+94 0 1
+42 1 0
+17 0 1
+27 0 1
+172 1 1
+37 1 1
+191 1 1
+66 1 1
+630 0 1
+261 1 1
+28 1 1
+1282 17 18
+429 0 1
+1588 1 1
+20 1 1
+1416 1 1
+33 1 1
+529 0 1
+25 0 1
+1863 0 4
+1651 1 1
+28 1 1
+11815 0 1
+26 0 1
+19 1 1
+3105 0 1
+700 0 1
+150 0 1
+68 0 1
+1420 0 6
+568 14 16
+2415 0 1
+41 1 1
+415 1 1
+33 1 1
+4521 1 1
+33 1 1
+307 1 0
+176 1 0
+3790 1 1
+86 1 1
+67 1 1
+65 0 1
+7439 1 1
+18 1 1
+16805 0 1
+1764 1 0
+3104 35 35
+3845 0 1
+3384 0 2
+17 0 18
+156 1 1
+30 1 1
+165 0 2
+1087 1 0
+953 1 0
+483 0 1
+632 1 0
+652 1 0
+8563 9 7
+1860 1 0
+398 1 0
+2219 1 1
+53 1 1
+756 1 1
+66 1 1
+69 1 1
+48 1 1
+63 1 1
+28 3 0
+1057 3 0
+63 0 3
+55 1 1
+74 3 2
+159 0 3
+92 1 1
+29 1 1
+58 3 0
+1210 9 9
+54 1 1
+27 1 1
+1374 0 2
+1775 17 2
+764 14 14
+331 16 16
+2291 3 4
+1687 1 1
+26 1 1
+2469 1 0
+3243 0 1
+3636 1 1
+24 1 1
+615 1 0
+2566 0 1
+275 5 0
+695 7 0
+9686 32 32
+3416 0 1
+1452 4 0
+214 13 13
+49 0 124
+1393 9 9
+5812 1 1
+24 1 1
+5703 0 1
+4006 1 0
+1462 3 0
+5199 2 0
+1554 0 2
+715 10 12
+1966 0 2
+2801 0 16
+618 0 1
+413 18 0
+730 1 1
+31 1 1
+4372 5 0
+10789 1 0
+2399 1 0
+6750 0 2
+1363 6 0
+6736 2 0
+4457 0 4
+7867 1 0
+3495 2 1
+7584 0 1
+2652 1 0
+1771 0 1
+14808 41015 41008
+19235 0 1
+9638 0 1
+2994 0 1
+469 3 1
+499 0 1
+12074 13 13
+2807 10 11
+715 0 2
+1627 6 6
+5099 1 0
+488 1 5
+975 0 2
+1761 0 1
+1794 5 0
+8254 3 3
+18 1 1
+3737 9 9
+1442 13 13
+212 0 10
+7712 1 1
+44 1 1
+4480 40 40
+1751 1 0
+1316 1 1
+49 1 1
+9050 4 0
+143 0 2
+2813 13 13
+1286 2857 49999
+75638 40000 50000
+1583473 0 2
+1564099 1 97463
+2933461
+
+chain 1621142 chrX 154913754 + 148570601 148611616 X 155270560 - 6466757 6507765 175
+13140 0 1
+20345 6 0
+3704 1 0
+1517 1 0
+2301
+
+chain 259772 chrX 154913754 + 75282398 75286444 X 155270560 - 79901776 79905823 6183
+1486 41 41
+41 40 40
+126 11 11
+1051 1209 1210
+41
+
+chain 192506 chrX 154913754 + 114908114 114911060 X 155270560 + 114997023 115000000 3054
+63 528 528
+60 0 16
+630 28 44
+689 16 16
+436 1 0
+495
+
+chain 188216 chrX 154913754 + 114908656 114914454 X 155270560 + 115000574 115005488 36116
+49 2721 1850
+47 8 8
+197 704 696
+2 16 0
+1155 42 43
+455 2 12
+400
+
+chain 119665 chrX 154913754 + 114906873 114908114 X 155270560 + 115003848 115005094 1024208
+1216 0 5
+25
+
+chain 29390 chrX 154913754 + 76491035 76491342 1 249250621 - 136684922 136685229 4932608
+307
+
+chain 25643 chrX 154913754 + 114911150 114911426 X 155270560 + 115005157 115005433 246321
+276
+
+chain 19821 chrX 154913754 + 114908177 114911739 X 155270560 + 114982173 114982762 1997
+479 3022 49
+61
+
+chain 15998 chrX 154913754 + 114911743 114912382 X 155270560 + 114967843 114968482 6239
+639
+
+chain 9708 chrX 154913754 + 148714470 148714905 5 180915260 - 8837105 8837560 23506322
+56 313 333
+66
+
+chain 9294 chrX 154913754 + 114906712 114906808 X 155270560 + 115005518 115005614 24447825
+96
+
+chain 6266 chrX 154913754 + 114906808 114906873 X 155270560 + 114962882 114962947 1027613
+65
+
+chain 6215 chrX 154913754 + 76426104 76426191 X 155270560 + 29934095 29934182 9535161
+87
+
+chain 5894 chrX 154913754 + 143027611 143027675 2 243199373 - 154977524 154977591 249
+15 0 3
+49
+
+chain 3277 chrX 154913754 + 76426069 76426104 1 249250621 - 60612464 60612499 19993171
+35
+
+chain 2407 chrX 154913754 + 148714814 148714839 2 243199373 + 100113459 100113484 27784968
+25
+
+chain 1984 chrX 154913754 + 76426191 76426234 8 146364022 - 27059036 27059079 21505033
+43
+
+chain 1549 chrX 154913754 + 114911087 114911150 X 155270560 + 114976136 114976199 336010
+63
+
+chain 1443 chrX 154913754 + 114913555 114913597 X 155270560 + 114984570 114984612 98822
+42
+
+chain 1245 chrX 154913754 + 148714288 148714366 4 191154276 - 133575330 133575408 22672116
+78
+
+chain 1030 chrX 154913754 + 114911060 114911082 X 155270560 + 114988042 114988064 7002
+22
+
+chain 733 chrX 154913754 + 148715982 148716070 X 155270560 - 110405878 110405966 21525610
+88
+
+chain 469 chrX 154913754 + 76426248 76426375 8 146364022 - 18567958 18568085 6841016
+127
+
+chain 293 chrX 154913754 + 148716634 148716684 2 243199373 - 107635751 107635801 26436223
+50
+
+chain 50554324 chrX_random 1719168 + 610279 1452044 X 155270560 + 76412035 77367385 75
+7124 5 6
+4742 1 1
+31 1 1
+1606 21 28
+3800 1 1
+23 1 1
+6209 1 1
+4 1 0
+22 1 0
+13 1 0
+1193 1 1
+32 1 1
+2218 0 1
+7608 6 1
+670 0 2
+1396 0 2
+1207 20 20
+5098 1 0
+1294 1 0
+119 0 1
+6626 16 16
+8221 1 0
+3722 4 0
+169 0 4
+1754 11 13
+58 0 1
+239 1 1
+75 1 1
+910 0 1
+518 7 7
+6771 0 1
+4354 26 26
+781 1 1
+28 1 1
+406 16 16
+4353 1 0
+22 100 24
+930 1 0
+33 1 1
+1226 0 1
+1278 660 1078
+3884 2 2
+22 1 1
+2022 4 0
+2593 1 0
+777 0 3
+4596 153 64
+2593 1 10
+1074 1 0
+3147 1 0
+2227 1 0
+9697 1 0
+3957 1 0
+3098 0 186786
+22519 1 0
+204 1 0
+22 1 0
+63 17 18
+9565 0 6
+6660 129 0
+58 1 0
+17671 100 83
+39 1 1
+9798 2 1
+5 0 1
+19 100 237
+1127 0 1
+4928 133 164
+8370 115 394
+3028 259 91
+9555 100 1670
+18018 6 0
+3818 1 0
+72 1 0
+15 1 0
+11 1 0
+4 1 0
+10 100 30
+18171 0 1
+18316 0 28
+22590 0 1
+2592 2 0
+8265 0 2
+4335 4 3
+14218 100 218
+8896 0 2
+5422 18 17
+1347 4 4
+83 166 0
+5120 101 153
+3114 126 148
+4567 1 0
+2511 0 1
+1289 2 0
+3129 124 175
+5332 1 0
+20 1 0
+15993 0 4
+9940 115 1562
+10856 1 1
+18 0 1
+2379 1 1
+32 74 72
+41 1 1
+3148 155 3622
+2876 621 0
+31 1 1
+2212 81729 108028
+557 0 1
+4283 1 0
+148 0 457
+722 1 1
+49 113 176
+33 2 2
+2654 1 0
+25 188 415
+1394 12 0
+5398 0 1
+28 100 19
+5509 151745 28754
+87 102 102
+66 5 5
+53 70 72
+56 201 601
+7819 256 150
+16 0 1
+6 0 1
+8001 4 0
+8135 0 1
+528 12 0
+797 100 193
+2857 496 0
+5822 153 0
+8578 1 0
+10594 1 0
+6352 3 3
+35 6 7
+50 55655 72028
+890 0 1
+72 0 1
+2125 1 1
+64 1 0
+15 1 0
+5 22 19
+12 129 67
+11 1 0
+8 0 1
+4 1 0
+16 2 2
+3637 1 1
+36 1 0
+28 1 0
+942 0 1
+231 1 1
+109 101 336
+18 11 294
+14959 0 2
+22656 3 1
+1280
+
+chain 6857177 chrX_random 1719168 + 1212241 1285856 X 155270560 + 76337041 76411192 460
+53 4 4
+3247 0 6
+51 2 0
+2014 2 0
+45 4 0
+20 4 0
+48 1 0
+5158 1 1
+29 1 1
+394 16 13
+1410 1 0
+12 1 0
+14 1 0
+7 1 0
+5 1 0
+13 1 0
+36 106 188
+1195 0 31
+133 0 4
+28 1 1
+1388 1 1
+18 1 1
+2790 0 1
+767 4 4
+49 0 1
+10 110 385
+52 0 1
+56 0 1
+4004 182 11
+23 1 1
+767 1 1
+66 1 1
+3217 2 0
+25 1 1
+4309 1 0
+26 0 1
+820 2 2
+4450 0 1
+1391 1 1
+33 0 1
+31 0 8
+3634 1 0
+1669 111 432
+10524 1 2
+8620 1 0
+2158 1 0
+1513 7 7
+4600 4 4
+2111
+
+chain 5479158 chrX_random 1719168 + 19684 169644 X 155270560 + 3753512 3953553 578
+1162 21228 9243
+742 1 0
+2200 7659 14347
+948 1 0
+4152 211 33421
+819 48 49
+92 22 22
+544 44 42
+175 0 1
+63 102 104
+246 37 37
+203 6 5
+279 27 27
+206 54 54
+394 39 40
+260 2 0
+311 16 16
+208 57 57
+349 6 6
+262 134 134
+481 0 6
+56 1 1
+868 0 5
+1387 18095 3193
+790 8 6
+1718 0 2
+3436 13 13
+241 40033 77157
+63 10 10
+425 63 0
+38963
+
+chain 5155611 chrX_random 1719168 + 1349115 1404263 X 155270560 - 77841540 77897663 609
+4514 1 1
+4 1 0
+15 0 1
+1714 142 0
+26953 1 1
+31 100 192
+4795 129 41
+2612 4 0
+3389 4 0
+5037 1 1
+22 101 1223
+13 9 8
+34 2 2
+5520
+
+chain 4548442 chrX_random 1719168 + 595876 1601165 X 155270560 - 77827311 79038577 141
+3039 114 45
+9150 2 0
+1995 422998 109473
+19795 1 0
+23 1 0
+12 111 343
+20 5 4
+13 1 1
+2240 1980 60
+2381 1 3
+44 1 0
+37 0 1
+24 100 79
+2445 100 136
+5050 0 1
+8804 4 0
+4444 704 262
+34 2 2
+12610 100 395
+4803 1 1
+22 1 1
+4171 128 46
+569 0 1
+2902 29308 112180
+236 1 0
+659 1 0
+711 1 0
+104 0 6764
+3212 4 2485
+1198 1 0
+8224 110 1
+4 0 1
+8 0 1
+21 0 1
+23 4 4
+5939 0 1
+182 101 1162
+2127 1 0
+28 100 77
+5048 2 0
+2345 1 0
+3616 100 211
+11 10 11
+1378 0 44
+1405 0 1
+1238 0 1
+575 0 20
+9423 100 122
+20 1 1
+7723 0 1
+431 0 1
+181 2 0
+5386 16 0
+866 105 61
+1365 0 1
+11613 318206 1966
+13 1 2
+40 1 1
+781 0 2
+5976 121 213
+3371 0 1
+693 1 0
+169 2337 746790
+586 1 0
+2072 1 1
+34 1 1
+58 13 13
+211 1 1
+28 1 1
+332 1 1
+31 1 1
+179 11 0
+2785 0 5
+1418 1 0
+12774 0 1
+3561 1 0
+4305 1 1
+120 1 1
+377 1 1
+68 1 1
+208 9 9
+998 15 15
+2146 0 1
+693 101 90
+36 1 1
+1743 1 1
+18 1 1
+2412 15 15
+1943 29 30
+3136 0 3
+12327 3 4
+2517
+
+chain 4126434 chrX_random 1719168 + 1485975 1530227 X 155270560 + 76291305 76335950 725
+1188 0 2
+717 1 1
+34 1 1
+1032 1 1
+42 1 1
+974 1 0
+5479 16 16
+2476 1 1
+35 1 1
+1212 3 0
+152 1 1
+46 1 1
+77 7 6
+912 1 1
+38 1 1
+4230 17 17
+617 146 545
+27 3 3
+374 1 1
+18 1 1
+3639 1 1
+122 1 1
+435 4 4
+1916 16 16
+2739 1 0
+622 16 16
+6383 2 0
+2520 35 35
+5915
+
+chain 3853214 chrX_random 1719168 + 170863 1715347 X 155270560 - 151357158 154150181 220
+101 0 61
+11 0 2
+38 0 155
+54 0 1
+34100 0 1
+12001 158233 27287
+105 0 1
+847 4191 3311
+101 25049 633
+4294 18781 8391
+120 26 27
+1173 0 1
+2374 87 87
+206 41 40
+40 7493 0
+1552 0 1
+194 0 1
+6613 4 3
+492 13807 11516
+2651 0 2
+1724 0 2
+2453 0 1
+3866 165 10497
+2912 8 0
+2305 93 94
+6287 1 0
+3225 7 7
+393 1 1
+18 1 1
+298 495 25877
+271 0 138
+31886 6 0
+14613 3 0
+9199 1105799 2318225
+448 0 73
+215 36 2
+248 14 15
+1012 1 0
+110 1 1
+211 15 16
+87 3 0
+268 10 6
+108 12 12
+74 1 1
+27 1 1
+178 1 1
+18 1 1
+1429 0 10
+168 1 1
+36 1 1
+64 1 1
+62 0 1
+129 2 0
+80 13 10
+11 3 0
+19 823 1702
+36 1 0
+605 17 17
+193 1 0
+215 12 13
+271 1 1
+18 1 1
+91 1 0
+178 4 4
+39 1 1
+233 1 1
+31 1 1
+500 1 1
+68 1 1
+325 9 9
+244 0 1
+843 1 1
+46 1 1
+202 0 1
+957 0 1
+150 1 1
+81 1 0
+6 1 1
+303 8540 16182
+59 4 0
+415 4 7
+127 38 38
+333 0 44
+16 0 252
+226 27 26
+64 4 0
+91 0 4
+56 32 32
+977 0 16
+701 1 1
+29 1 1
+1743 1 0
+676 0 2
+2780 0 16
+85 0 11
+22 1 1
+952 3 0
+470 1 0
+840 4 0
+146 0 4
+131 0 34
+39 4 0
+99 1 1
+26 0 4
+80 1 1
+1476 0 13
+977 0 2
+480 0 800
+1133 4 5
+532 1 1
+37 1 1
+207 0 117633
+2070 1 1
+30 2 0
+524 2 0
+484 0 1
+446 1 0
+1642 2 0
+63 1 1
+43 1 1
+148 12 12
+2115 0 1
+116 1 1
+182 10 10
+88 1 1
+65 0 320
+107 0 2
+2083 295 0
+1170 10932 59997
+1792 0 1
+292 6 7
+677 8 11
+1932
+
+chain 2670012 chrX_random 1719168 + 22277 129533 X 155270560 - 151420019 151525192 697
+318 0 8
+1212 7792 0
+1334 4590 634
+3132 4549 4298
+403 12 12
+889 7 7
+393 20 20
+2070 17932 14002
+179 0 1
+1042 0 1
+4330 476 475
+66 0 1
+1653 797 0
+2278 8 0
+5943 18846 26826
+69 77 81
+86 822 824
+287 1 0
+7796 1771 9789
+1118 1349 0
+2572 2 0
+4177 1 0
+2904 5 0
+881 1 1
+56 6 0
+590 1 1
+23 1 1
+262 6 6
+349 1 1
+55 1 1
+208 16 16
+311 0 2
+260 1 0
+34 5 5
+394 54 54
+206 27 27
+199
+
+chain 2529127 chrX_random 1719168 + 1458959 1485875 X 155270560 + 77160344 77187173 1079
+634 0 1
+9184 1 0
+59 1 0
+14 100 16
+21 1 0
+53 2 2
+11087 2 0
+2487 0 2
+2602 1 0
+667
+
+chain 902700 chrX_random 1719168 + 269161 291745 Y 59373566 - 58967799 59197152 4215
+4053 3 0
+293 1 1
+26 0 1
+791 0 165863
+51 243 5
+66 134 1
+42 388 5
+141 0 15
+35 2 2
+42 361 0
+256 1 0
+341 3 36
+453 301 1
+147 0 1
+278 4 4
+15 0 3
+29 1 1
+122 2 0
+148 430 0
+222 151 0
+55 0 2
+149 1 0
+687 6309 50121
+61 1 1
+43 1 1
+408 80 0
+147 11 11
+228 1 1
+48 2 2
+1372 1 1
+31 1 1
+75 1 1
+28 97 0
+263 0 1
+495 98 1
+51 1 33
+52 1 1
+51 33 1
+226 1 1
+20 4 0
+211 340 0
+179 1 0
+10 1 1
+236 341 1
+555
+
+chain 569801 chrX_random 1719168 + 1106858 1112877 X 155270560 - 78234537 78240560 9279
+4787 0 4
+1232
+
+chain 569444 chrX_random 1719168 + 1452563 1458801 X 155270560 - 78136578 78142679 9342
+609 3 13
+1692 0 8
+1539 155 0
+30 3 3
+254 9 9
+1944
+
+chain 534458 chrX_random 1719168 + 90245 170863 X 155270560 - 151402385 151465977 943
+12303 69 69
+77 86 86
+822 66146 49119
+57 3 4
+1055
+
+chain 494413 chrX_random 1719168 + 391508 439759 X 155270560 - 151446976 151536655 1213
+50 57 60
+3938 36909 78166
+87 206 206
+41 40 40
+6143 240 408
+340 6 6
+194
+
+chain 379298 chrX_random 1719168 + 415243 419212 X 155270560 - 151507548 151511517 135808
+663 12 12
+3294
+
+chain 372919 chrX_random 1719168 + 1663885 1667930 X 155270560 - 153907181 153911269 141765
+802 0 3
+83 1 1
+47 1 1
+767 17 17
+1585 0 73
+215 36 2
+248 14 15
+229
+
+chain 274258 chrX_random 1719168 + 1667930 1671196 X 155270560 - 154066175 154070218 305212
+2034 1 281
+24 1 1
+190 0 200
+632 326 623
+58
+
+chain 267510 chrX_random 1719168 + 422339 428025 X 155270560 - 151460048 151465730 1055
+1034 4 3
+2317 3 0
+2328
+
+chain 266050 chrX_random 1719168 + 27992 75212 X 155270560 - 151430977 151495459 1091
+2648 315 25719
+644 9056 5097
+1296 30530 26348
+164 1 0
+310 1720 1720
+536
+
+chain 247472 chrX_random 1719168 + 49544 52383 X 155270560 + 3800594 3803433 7089
+2766 6 6
+67
+
+chain 247318 chrX_random 1719168 + 58807 462399 X 155270560 + 3743706 3828677 987
+48 658 658
+44 238 238
+102 246 246
+37 488 488
+27 206 206
+54 394 394
+39 797 797
+57 617 617
+134 287931 26427
+60 1338 0
+1419 8746 13247
+2214 50 50
+51 31242 578
+263 4 4
+5180 1349 0
+1121 24105 7962
+467 20820 8687
+32 2 2
+3992 2 0
+898 48 49
+92 22 22
+544 44 42
+175 0 1
+63 102 104
+246 37 37
+203 6 5
+279 27 27
+206 54 54
+394 39 40
+260 2 0
+311 16 16
+208 57 57
+349 6 6
+262 25 25
+590 57 63
+881 1017 1022
+1498
+
+chain 203629 chrX_random 1719168 + 419791 421950 X 155270560 - 151464996 151467156 582605
+2107 0 1
+52
+
+chain 199106 chrX_random 1719168 + 1699808 1701947 X 155270560 - 153935858 153937997 603481
+61 1 1
+57 1 1
+1588 4 4
+59 7 7
+361
+
+chain 199089 chrX_random 1719168 + 378452 380544 X 155270560 + 3796616 3798707 602253
+1586 1 0
+505
+
+chain 187776 chrX_random 1719168 + 376353 378301 X 155270560 + 3798256 3800203 654951
+729 1 0
+1218
+
+chain 174234 chrX_random 1719168 + 1285969 1288372 X 155270560 + 77019422 77021825 343560
+1763 87 87
+102 124 124
+70 56 56
+201
+
+chain 157788 chrX_random 1719168 + 111815 113457 X 155270560 + 3753462 3755104 810742
+1642
+
+chain 154415 chrX_random 1719168 + 1055747 1057376 X 155270560 + 77369279 77370908 822932
+1629
+
+chain 134293 chrX_random 1719168 + 1708912 1710376 X 155270560 + 1185231 1187137 959481
+129 1 1
+82 1 1
+350 2 297
+68 0 147
+831
+
+chain 132265 chrX_random 1719168 + 403961 405553 X 155270560 - 151477034 151478628 31377
+436 0 2
+1156
+
+chain 90853 chrX_random 1719168 + 1707707 1708693 X 155270560 + 1353464 1354449 1404000
+164 1 0
+46 1 1
+620 1 1
+37 1 1
+115
+
+chain 74037 chrX_random 1719168 + 267762 268693 Y 59373566 - 59139189 59140054 1710353
+79 97 0
+220 1 0
+317 27 60
+128 1 0
+61
+
+chain 63811 chrX_random 1719168 + 410390 415127 X 155270560 + 3822705 3827447 11885
+2487 0 6
+1981 48 47
+221
+
+chain 61116 chrX_random 1719168 + 346359 347004 X 155270560 + 3777922 3778567 2069731
+645
+
+chain 55813 chrX_random 1719168 + 2787 3496 X 155270560 - 151499719 151505905 2274078
+50 6 6
+412 0 5477
+241
+
+chain 38577 chrX_random 1719168 + 1651263 1651671 X 155270560 - 153943757 153944164 3434500
+271 1 0
+136
+
+chain 34659 chrX_random 1719168 + 1707297 1707664 X 155270560 + 1118849 1119216 3901406
+367
+
+chain 33830 chrX_random 1719168 + 267400 267758 X 155270560 - 154819600 154819959 4017435
+54 0 1
+304
+
+chain 33594 chrX_random 1719168 + 347004 347356 X 155270560 - 151523309 151523661 4010211
+352
+
+chain 33500 chrX_random 1719168 + 290273 291150 X 155270560 - 155043354 155044230 1935940
+149 427 427
+91 1 0
+137 17 17
+55
+
+chain 33229 chrX_random 1719168 + 1452213 1452563 X 155270560 - 78136229 78136579 3954656
+350
+
+chain 31748 chrX_random 1719168 + 1656832 1657169 X 155270560 - 154080972 154081310 4345014
+118 0 1
+219
+
+chain 31047 chrX_random 1719168 + 364702 460901 X 155270560 + 3752840 3788747 1318
+48 54 53
+80 31133 470
+26 58237 28604
+46 660 660
+40 242 241
+78 0 2
+22 248 248
+33 492 491
+25 208 208
+52 400 400
+34 798 798
+56 1232 1232
+21 1 1
+34 882 887
+1017
+
+chain 26366 chrX_random 1719168 + 1717468 1717765 X 155270560 - 154599490 154599787 6355797
+65 8 8
+224
+
+chain 20775 chrX_random 1719168 + 1657225 1657446 Y 59373566 + 1138227 1138450 9855403
+101 0 2
+120
+
+chain 20767 chrX_random 1719168 + 4453 4700 X 155270560 - 151332163 151332410 9860775
+174 10 10
+63
+
+chain 20271 chrX_random 1719168 + 1698243 1698467 X 155270560 - 154161726 154161950 2868
+224
+
+chain 20189 chrX_random 1719168 + 22064 22277 X 155270560 + 3752676 3752889 10232162
+213
+
+chain 20092 chrX_random 1719168 + 410218 414905 X 155270560 + 3784106 3788794 77876
+172 4468 4469
+47
+
+chain 19894 chrX_random 1719168 + 365127 367414 X 155270560 + 3744796 3747084 92469
+246 37 37
+203 5 6
+279 27 27
+206 54 54
+394 41 39
+260 0 2
+535
+
+chain 19881 chrX_random 1719168 + 217168 217385 X 155270560 + 3913712 3913929 10410664
+217
+
+chain 19372 chrX_random 1719168 + 1704190 1704597 2 243199373 + 106598364 106598785 10983407
+91 100 114
+81 74 74
+61
+
+chain 17351 chrX_random 1719168 + 365104 366619 X 155270560 + 3783188 3784703 560009
+23 246 246
+37 487 487
+27 206 206
+54 394 394
+41
+
+chain 16176 chrX_random 1719168 + 3557 21469 X 155270560 + 3768043 3793719 20345
+896 16406 24170
+326 33 33
+130 29 29
+92
+
+chain 15865 chrX_random 1719168 + 276938 277188 Y 59373566 - 59140528 59140772 2014767
+82 6 0
+162
+
+chain 15331 chrX_random 1719168 + 367414 367617 X 155270560 + 3823924 3824127 647220
+203
+
+chain 13713 chrX_random 1719168 + 489399 489544 X 155270560 + 3712149 3712294 16431967
+145
+
+chain 12918 chrX_random 1719168 + 274951 275159 Y 59373566 - 59139058 59139278 8720139
+52 0 12
+156
+
+chain 12632 chrX_random 1719168 + 1705530 1705970 X 155270560 + 145057484 145057926 18056495
+78 288 290
+74
+
+chain 12447 chrX_random 1719168 + 1030429 1030575 5 180915260 - 168461964 168462110 18325086
+146
+
+chain 12016 chrX_random 1719168 + 1317064 1317191 X 155270560 + 77214259 77214386 18979178
+127
+
+chain 11687 chrX_random 1719168 + 278072 278210 X 155270560 - 154988343 154988492 4329206
+112 25 36
+1
+
+chain 11514 chrX_random 1719168 + 278210 278346 Y 59373566 - 59141204 59141340 4138572
+136
+
+chain 10224 chrX_random 1719168 + 1704620 1704728 19 59128983 - 37939031 37939139 22329028
+108
+
+chain 10213 chrX_random 1719168 + 277934 278654 Y 59373566 - 59141065 59141499 2702219
+138 514 228
+68
+
+chain 9983 chrX_random 1719168 + 290082 290229 X 155270560 - 155043503 155043650 2501552
+48 40 40
+59
+
+chain 9686 chrX_random 1719168 + 1671544 1671645 X 155270560 + 1359785 1359886 23561825
+101
+
+chain 8627 chrX_random 1719168 + 274506 274913 X 155270560 - 154985996 154986278 9490470
+54 20 20
+32 0 8
+10 242 109
+49
+
+chain 7400 chrX_random 1719168 + 1030281 1030397 9 141213431 + 129760930 129761046 27439238
+59 26 26
+31
+
+chain 7194 chrX_random 1719168 + 274704 274779 Y 59373566 - 59139208 59139283 27842833
+75
+
+chain 7041 chrX_random 1719168 + 129047 129334 X 155270560 - 151486292 151486579 1717
+54 206 206
+27
+
+chain 6777 chrX_random 1719168 + 275159 275252 X 155270560 - 154986140 154986238 15049098
+1 37 42
+55
+
+chain 6125 chrX_random 1719168 + 479075 479168 X 155270560 - 151461082 151461175 898
+93
+
+chain 5720 chrX_random 1719168 + 1705205 1705283 3 198022430 - 36255828 36255906 21764861
+52 21 21
+5
+
+chain 5699 chrX_random 1719168 + 57777 57859 X 155270560 + 3747892 3747974 156364
+82
+
+chain 5684 chrX_random 1719168 + 275730 275789 X 155270560 - 154985991 154986050 31480070
+59
+
+chain 5671 chrX_random 1719168 + 278678 278737 X 155270560 - 154987944 154988003 7684992
+59
+
+chain 5648 chrX_random 1719168 + 288487 288546 Y 59373566 - 59194675 59194734 31602153
+59
+
+chain 5292 chrX_random 1719168 + 1698467 1698538 X 155270560 - 154160180 154160251 1242775
+71
+
+chain 4986 chrX_random 1719168 + 1705613 1705672 7 159138663 + 43857891 43857950 19004666
+59
+
+chain 4456 chrX_random 1719168 + 1030620 1030666 X 155270560 + 76367481 76367527 34837220
+46
+
+chain 4200 chrX_random 1719168 + 65786 66804 X 155270560 + 3789104 3790122 1705
+1018
+
+chain 4147 chrX_random 1719168 + 1704281 1704341 4 191154276 - 52750556 52750615 11058024
+1 2 1
+57
+
+chain 4142 chrX_random 1719168 + 276887 276938 Y 59373566 - 59140619 59140670 3855343
+51
+
+chain 3859 chrX_random 1719168 + 291150 291190 Y 59373566 - 59196218 59196258 16097861
+40
+
+chain 3722 chrX_random 1719168 + 1703633 1706063 17 81195210 - 47362086 47364493 15646977
+109 441 439
+7 1805 1784
+68
+
+chain 3009 chrX_random 1719168 + 1705804 1705856 X 155270560 + 62632912 62632964 24180689
+52
+
+chain 2509 chrX_random 1719168 + 1708877 1708912 X 155270560 + 1109247 1109282 2078841
+35
+
+chain 2078 chrX_random 1719168 + 1706063 1706085 1 249250621 + 114909259 114909281 21967653
+22
+
+chain 1700 chrX_random 1719168 + 274379 274412 Y 59373566 - 59139235 59139268 19436247
+33
+
+chain 990 chrX_random 1719168 + 1705283 1705342 X 155270560 + 119232530 119232589 19658805
+59
+
+chain 463 chrX_random 1719168 + 1703519 1703583 X 155270560 + 65440530 65440594 26501250
+64
+
+chain 2373402471 chrY 57772954 + 0 27228749 Y 59373566 + 10000 28819361 24
+34821 50000 50000
+86563 30000 50000
+766173 50000 50000
+36556 50000 50000
+80121 90000 50000
+754004 100000 50000
+6846717 50000 50000
+276367 600000 50000
+813231 500000 3000000
+39401 400000 50000
+554624 100000 50000
+535761 1 0
+32919 1 0
+10 1 1
+12811 5 0
+18899 1 1
+121 5 4
+230478 1 0
+750 24 24
+14340 1 1
+43 1 1
+2095 1 0
+14635 9 0
+2781 1 0
+45022 6 5
+7151 1 0
+9343 0 628
+5417477 0 50006
+2175794 0 50000
+1481749 50000 50000
+4867933
+
+chain 46617811 chrY 57772954 + 57228749 57772954 Y 59373566 + 58819361 59363566 80
+98295 50000 50000
+395910
+
diff --git a/public/chainFiles/hg19toHg18.chain b/public/chainFiles/hg19toHg18.chain
new file mode 100644
index 0000000..b00e42c
--- /dev/null
+++ b/public/chainFiles/hg19toHg18.chain
@@ -0,0 +1,49040 @@
+chain 21270171362 chr1 249250621 + 10000 249233096 chr1 247249719 + 0 247199719 2
+619 137 0
+166661 50000 50000
+40302 50000 50000
+153649 50000 50000
+1098479 1 1
+47 1 1
+73 117 114
+773 1 1
+43 1 1
+864369 2 2
+51 3 0
+104 13694 13694
+104 0 3
+51 2 2
+134936 50000 50000
+1161048 150000 60000
+1440092 27273 50000
+7590365 50000 50000
+116914 100000 50000
+237250 50000 50000
+3518496 50000 50000
+12702424 150000 50000
+16145012 0 1
+7772 1 0
+4705841 0 1
+52977198 50000 50000
+157344 21065 50000
+16604841 50000 50000
+189539 150000 50000
+398739 21050000 20290000
+195588 50000 50000
+186739 150000 50000
+175055 50000 50000
+201709 100000 50000
+126477 130183 50000
+381 0 3
+315 0 2
+62 1 1
+45 1 0
+19 0 1
+8 1 1
+1158 1 0
+314 12 13
+2849 3 0
+5615 1 1
+37 1 1
+3172 6 4
+190 1 1
+34 1 1
+380 0 1
+2099 3 0
+765 2 2
+366 0 4
+1186 1 0
+460 0 1
+1242 28 28
+574 1 1
+21 1 1
+1460 1 1
+105 1 1
+701 3 0
+239 0 1
+970 11 11
+2365 1 1
+21 1 1
+384 8 8
+996 2 0
+10383 2 0
+713 0 1
+5188 1 1
+30 1 1
+1233 1 0
+132 1 1
+44 1 1
+1123 22 22
+1810 1 0
+512 1 1
+39 1 1
+1096 0 16
+743 1 0
+9028 0 1
+2506 0 6
+8446 2 0
+5505 0 3
+7541 1 0
+109864 50000 50000
+78698 50000 50000
+127263 50000 50000
+170669 50000 50000
+38311 100000 100000
+1022394 50000 50000
+281532 289973 50000
+1648 1539 0
+76 3225 3
+1018 34 34
+1716 2 0
+159 4 0
+1600 0 6
+1385 1 0
+2066 1 1
+32 1 3
+1556908 150000 50000
+185320 150000 50000
+172789 50000 50000
+220313 50000 50000
+455185 50000 50000
+22047237 1 0
+34365824 150000 50000
+259514 150000 50000
+17265625 50000 50000
+11394365 50000 50000
+13665999 150000 50000
+174886
+
+chain 3264727 chr1 249250621 + 146303299 146341166 chr16 88827254 - 19388358 19424466 890
+577 1 1
+25 1 1
+63 19 19
+840 1 1
+60 1 1
+146 8 8
+874 1 1
+17 1 1
+386 1 1
+27 1 1
+931 1 1
+19 1 1
+200 1 1
+26 1 1
+72 1 0
+39 1 1
+107 2 1
+26 1 0
+25 1 1
+146 1 1
+45 1 1
+49 0 1
+434 0 4
+21 1 1
+572 0 2
+464 1 1
+50 1 1
+628 1 1
+48 1 1
+184 1 1
+25 1 1
+330 0 3
+308 14 14
+289 1 1
+57 1 1
+709 107 107
+247 1 1
+72 1 1
+470 1 1
+36 1 1
+353 1 0
+27 1 1
+92 12 12
+1001 1 1
+39 1 1
+650 1 1
+22 1 1
+171 1 1
+21 1 1
+88 0 9
+107 36 11
+23 0 1
+29 0 26
+20 3 79
+161 11 11
+134 1 1
+89 1 1
+547 1 1
+15 1 1
+409 1 1
+36 1 1
+376 11 10
+1545 1 0
+4 0 1
+36 1 1
+373 0 1
+326 1 1
+42 17 0
+97 1 0
+187 2 0
+503 1 1
+57 1 1
+443 1 1
+35 1 1
+633 1 0
+2044 3 13
+299 1 1
+37 1 1
+1159 1 1
+39 1 1
+124 1 1
+74 1 1
+103 1 1
+55 1 1
+280 10 9
+474 0 1
+382 1 1
+31 1 1
+1812 1 1
+76 1681 0
+25 1 1
+145 1 1
+18 1 1
+1228 1 1
+31 1 1
+126 9 9
+186 2 0
+142 1 1
+25 1 0
+442 10 0
+339 0 1
+89 1 1
+21 2 0
+21 151 4
+15 1 1
+489 9 9
+311 1 1
+75 1 1
+75 1 0
+124 1 1
+114 1 1
+23 1 1
+1489 0 3
+391 1 0
+2141 10 10
+460 11 11
+422 1 1
+30 1 1
+296 8 8
+638 1 1
+38 1 1
+341
+
+chain 2374970 chr1 249250621 + 146214652 146460889 chr1 247249719 - 102316553 102503720 74
+488 1 1
+24 1 1
+971 6293 0
+994 2 0
+183 2 0
+1408 1 0
+1360 1541 0
+211 0 12
+1506 111528 93105
+421 5 6
+2973 8 8
+118 12 12
+157 10 10
+706 0 18
+26 2884 0
+127 4 1
+1518 1 1
+33 1 1
+934 9 9
+908 0 1
+126 1 0
+695 20 20
+2250 5 5
+1662 179 172
+975 1 1
+53 1 1
+62 2 2
+40 1 1
+1561 1 1
+34 1 1
+668 1 0
+1671 2 0
+480 1 1
+17 4 4
+103 0 1
+50 6 6
+230 1 1
+71 1 1
+139 1 0
+975 5 0
+180 1 1
+37 1 1
+1888 3 2
+1101 1 0
+354 64 9327
+654 1 1
+36 1 1
+888 0 2
+18 1 1
+74 1 1
+25 1 1
+81 2 0
+779 1 1
+41 0 12
+22 1 1
+436 1 6
+293 1 1
+31 1 1
+83 4 0
+694 1 1
+42 1 1
+913 0 9
+472 0 1
+253 12 12
+148 89 1
+41 89 1
+342 1 1
+72 1 1
+97 1 1
+41 1 1
+108 13 16
+280 12 12
+61 1 1
+30 0 1
+71 1 1
+42 2 2
+139 0 3
+85 5 5
+90 1 1
+39 0 1
+366 13 14
+332 0 3744
+123 1 1
+19 1 1
+264 2 0
+47 1 1
+381 3 5
+109 0 1
+521 0 1
+503 1 1
+42 0 1
+739 1 1
+77 1 1
+883 0 2
+220 0 3
+93 4 0
+12 4 0
+39 5 0
+91 1 1
+34 1 1
+562 1 1
+30 1 1
+660 13 0
+1172 16 16
+69 1 1
+32 1 1
+310 1 1
+33 1 1
+97 0 1
+38 1 1
+295 0 2
+499 1 1
+57 31 14
+607 10 10
+145 1 1
+101 1 1
+346 1 1
+30 1 1
+74 1 1
+16 1 1
+203 1 1
+36 12 0
+483 16 0
+977 1 1
+86 1 1
+66 1 1
+35 1 1
+692 16 13
+402 34 34
+287 0 5
+523 0 18
+350 4 0
+32 0 2
+108 39 45
+66 30 0
+969 0 5
+1749 5 5
+95 2 0
+5 1 0
+4 0 1
+79 0 2
+65 8 11
+63 1 1
+49 1 1
+1381 0 1
+870 17 0
+139 1 1
+89 1 1
+270 3 3
+97 1 1
+66 1 1
+50 1 1
+126 1 0
+182 1 1
+83 0 4
+125 1 1
+35 1 1
+263 1 1
+32 4 4
+202 1 0
+94 1 1
+46 1 1
+206 1 1
+56 1 1
+50 1 1
+49 1 1
+188 16 16
+589 1 1
+38 1 1
+178 0 4
+67 1 1
+421 51 0
+117 1 1
+36 1 1
+71 1 1
+74 1 1
+68 10 10
+131 3 3
+56 1 0
+52 1 1
+207 4 4
+30 1 1
+283 14 14
+93 0 4
+66 1 1
+89 7 5
+36 1 1
+79 1 1
+46 21 0
+99 1 1
+229 10 10
+100 5 0
+19 8 8
+78 1 1
+87 1 1
+125 5 5
+65 1 1
+74 3 3
+344 1 1
+24 1 1
+683 1 1
+43 6287 0
+250 15 15
+798 13 12
+267 2 1
+881 1 0
+374 10 10
+1237 1 1
+40 1 1
+620 1 1
+43 1 1
+1491 1 1
+28 1 1
+68 5 5
+413 1 2
+183 5 5
+42 1 1
+363 1 1
+26 23 0
+53 1 0
+1011 15 15
+173 4 4
+15 1 1
+801 4 4
+1197 0 10
+432 22154 19
+283 4702 22
+850 9524 0
+78 76 76
+568 10 10
+775 40 32
+274 4 0
+1120 17 17
+195
+
+chain 990444 chr1 249250621 + 2485433 2499127 chr1 247249719 - 244760735 244774429 1366
+13694
+
+chain 614409 chr1 249250621 + 249233096 249240448 chr21 46944323 + 46937133 46944296 2013
+2867 16 16
+420 9 9
+176 0 1
+1252 6 0
+1275 1 1
+25 0 344
+76 0 58
+545 484 7
+40 109 0
+51
+
+chain 498595 chr1 249250621 + 146216137 146242853 chr1 247249719 - 104315183 104389677 383
+30 657 657
+196 19 18
+134 27 27
+445 20 20
+101 9 9
+169 62 62
+116 10 10
+70 62 62
+54 26 26
+70 0 22267
+240 1539 0
+91 20 24
+246 22 22
+270 112 112
+118 143 143
+86 24 24
+184 81 81
+67 47 46
+110 83 95
+335 59 59
+139 4179 2633
+241 27 27
+273 109 109
+185 76 76
+86 24 24
+184 81 81
+26 1717 1732
+80 85 53
+151 37 37
+99 37 37
+113 20 20
+101 9 9
+169 62 62
+89 37 37
+70 62 62
+54 33 33
+382 279 5055
+291 112 112
+125 147 147
+256 382 24225
+58 106 106
+51 29 29
+422 19 19
+221 84 84
+156 29 29
+162 33 33
+80 4 4
+79 11 11
+209 29 29
+183 34 34
+116 44 44
+122 5 5
+554 41 41
+140 8 8
+161 0 1
+67 58 51
+138 10 10
+246 60 60
+124 59 60
+101 138 138
+109 161 161
+56 31 28
+163 74 74
+136 7 7
+303 34 34
+119 10 10
+339 30 30
+141 91 91
+222 107 93
+237 205 205
+134 49 49
+87 22 22
+128 87 87
+105 33 33
+52 58 58
+52 87 87
+198 158 162
+125 44 44
+82 42 42
+54 10 9
+72 27 27
+154 18 18
+186 39 39
+61 87 86
+71 38 38
+116 43 43
+268 50 50
+58 120 120
+152
+
+chain 376931 chr1 249250621 + 143880003 143901185 chr1 247249719 - 126576077 126597249 122
+127 70 71
+181 31 31
+3325 1 1
+49 1 1
+820 1 1
+75 1 1
+393 1 1
+21 1 1
+2956 3 0
+232 0 5
+77 4 4
+531 1 1
+42 5 3
+183 1 1
+19 1 1
+644 1 1
+25 1 1
+701 1 1
+21 1 1
+954 1 1
+31 1 1
+129 24 14
+650 1 1
+25 1 1
+560 0 2
+1372 1 1
+46 1 1
+1547 3 1
+883 1 0
+22 1 1
+818 1 1
+30 1 1
+1231 1 1
+34 1 1
+1758 1 1
+35 1 1
+468
+
+chain 360128 chr1 249250621 + 146427813 146438983 chr1 247249719 + 144926007 144932406 9045
+138 252 252
+1258 1540 0
+76 3256 30
+81 283 283
+87 185 185
+109 273 273
+7 19 19
+155 43 43
+91 1 0
+1185 11 11
+212 2 0
+158 2 0
+1336 64 64
+346
+
+chain 260187 chr1 249250621 + 146226436 146443808 chr1 247249719 - 100391956 100589719 716
+173 5526 775
+60 400 391
+120 18 17
+164 81 83
+26 45 45
+35 1589 1589
+29 2518 2516
+7 17 17
+56 30 30
+51 56 53
+31 163 163
+74 446 446
+34 468 468
+30 141 141
+33 624 609
+8 133 133
+64 134 134
+49 237 237
+71 316 316
+58 1199 1203
+39 219 219
+38 6697 424
+97 18 18
+77 219 219
+114 64 64
+138 183 187
+118 99 99
+89 25 31
+69 24 24
+100 30 30
+69 49 49
+54 125 125
+182 197 197
+107 156930 137139
+140 175 171
+75 164 162
+157 49 49
+69 45 45
+61 48 48
+51 61 60
+71 70 70
+108 10955 10956
+84 24 24
+75 87 87
+185 109 109
+273 22 22
+246 20 24
+49 494 19550
+70 10 10
+116 62 9592
+169 9 9
+324 83 83
+151 87 77
+90 22 22
+196 68 68
+95 5 5
+57 71 71
+196 17 17
+75 73 73
+563 83 87
+110 1555 14
+45 7990 0
+54 81 81
+184 24 24
+75 87 87
+185 109 109
+273 3222 27
+64 1605 35
+142 1567 44
+37 1539 0
+281
+
+chain 257136 chr1 249250621 + 146423276 146434218 chr1 247249719 + 144926235 144932406 9046
+68 157 157
+71 288 288
+73 563 563
+83 4962 196
+1052 19 19
+155 43 43
+91 1 0
+99 76 76
+1010 11 11
+212 2 0
+158 2 0
+1746
+
+chain 252664 chr1 249250621 + 146424776 146427813 chr1 247249719 + 144927734 144930766 96654
+1055 16 16
+124 74 74
+74 224 223
+979 11 11
+212 2 0
+158 2 0
+106
+
+chain 244411 chr1 249250621 + 146449863 146457732 chr1 247249719 + 144926007 144929115 8960
+1648 1539 0
+76 3225 3
+265 45 45
+708 34 34
+329
+
+chain 149837 chr1 249250621 + 146221841 146454623 chr1 247249719 + 146043049 146859300 923
+56 335 335
+59 4859 3299
+109 185 185
+76 5018 258
+57 409 426
+45 777 777
+84 1850 1850
+41 841 820
+47 125 126
+58 101 101
+138 2026 2026
+51 4 2
+52 297 297
+81 786 786
+33 347 347
+90 23 23
+35 125 125
+44 82 81
+42 634 634
+74 225 224
+43 268 267
+50 58 58
+120 152 152
+515 62 62
+68 41 41
+432 0 18
+180 46 46
+67 26 28
+192 26 26
+231 107 107
+67 72 67
+53 67 67
+151 171 168
+59 46 47
+86 57 54
+51 138 138
+397 18 18
+114 3 2
+182 20 20
+86 167 167
+51 48 48
+233 42 42
+89 55 55
+163 43 44
+112 70 70
+355 154 154
+174 157 641342
+145 228 228
+152 366 366
+64 1134 1135
+35 269 265
+46 15 14
+137 8 8
+70 11 11
+73 29 29
+55 63 63
+62 262 247
+77 100 100
+155 39 39
+215 72 72
+178 20 20
+64 13 13
+123 12 12
+124 127 127
+100 135495 128258
+34 14433 8189
+138 64 64
+114 219 219
+77 19 19
+96 17464 11155
+185 22232 98
+69 26 26
+54 62 62
+70 10 10
+116 62 62
+169 32 32
+211 37 37
+99 9482 37
+161 23 13
+130
+
+chain 124274 chr1 249250621 + 143871002 143921945 chr1_random 1663265 - 747928 798871 209
+9001 127 127
+70 181 181
+31 41505 41505
+28
+
+chain 121346 chr1 249250621 + 146403114 146428203 chr1 247249719 - 230466401 230485108 1747
+70 156 156
+17 25 25
+22 146 146
+152 249 249
+94 2285 2290
+63 34 34
+79 80 80
+89 48 42
+85 127 127
+68 502 495
+87 61 61
+136 127 126
+4 272 272
+43 396 396
+49 175 175
+48 183 187
+40 11298 11284
+59 5488 723
+50 98 104
+107 63 63
+54 1608 4
+83 9 9
+160
+
+chain 97594 chr1 249250621 + 146218654 146221704 chr1 247249719 - 102320562 102322071 123803
+154 24 24
+174 6 6
+1045 1614 73
+33
+
+chain 76810 chr1 249250621 + 146441138 146441951 chr1 247249719 - 102499725 102500538 1571454
+813
+
+chain 54094 chr1 249250621 + 146439071 146449863 chr1 247249719 + 144927734 144930766 9063
+156 32 32
+864 3151 76
+253 432 432
+62 196 196
+62 169 169
+32 211 211
+37 99 99
+87 4753 70
+88 2 0
+106
+
+chain 51170 chr1 249250621 + 146420674 146422968 chr1 247249719 + 144928397 144930686 91522
+82 822 821
+37 60 60
+212 196 196
+62 502 502
+83 151 149
+59 2 0
+26
+
+chain 47243 chr1 249250621 + 146249630 146253102 chr1 247249719 + 146058248 146061700 347899
+23 176 176
+41 89 89
+25 420 420
+79 245 245
+20 78 78
+29 495 490
+29 72 72
+46 158 145
+143 628 627
+53 534 533
+17 5 5
+67
+
+chain 34253 chr1 249250621 + 146404045 146461111 chr1 247249719 - 100757623 100773572 2307
+96 91 95
+87 237 237
+54 39 39
+166 170 170
+93 270 264
+54 177 172
+56 15121 8830
+27 23096 966
+26 9686 241
+71 62 62
+168 10 10
+112 7057 3813
+40
+
+chain 33489 chr1 249250621 + 146442066 146462163 chr1 247249719 + 144023055 144028915 8758
+86 162 162
+20 322 322
+153 82 82
+116 7 7
+260 4934 262
+352 142 142
+79 60 60
+57 99 99
+135 6 6
+234 31 31
+264 6949 535
+45 4229 1077
+134 1105 1106
+34
+
+chain 33218 chr1 249250621 + 146446746 146453724 chr1 247249719 + 144927655 144929867 162700
+76 4 3
+532 5285 520
+407 76 76
+465 71 71
+62
+
+chain 32794 chr1 249250621 + 146404432 146406255 chr1 247249719 - 230461418 230463242 176920
+104 280 280
+90 172 172
+62 25 26
+120 135 135
+128 18 18
+13 515 515
+161
+
+chain 26745 chr1 249250621 + 146451818 146452101 chr1 247249719 - 102499420 102499703 6165314
+283
+
+chain 24305 chr1 249250621 + 146405140 146406723 chr1_random 1663265 + 611385 612968 836039
+25 120 120
+23 14 14
+26 287 287
+50 8 8
+128 685 685
+19 35 35
+26 105 105
+32
+
+chain 22423 chr1 249250621 + 146216204 146248536 chr1 247249719 + 146043705 146710884 2213
+65 5 5
+58 95 95
+44 58 58
+67 1348 1339
+20 10 10
+32 196 196
+62 2594 1055
+96 153 153
+108 10232 605314
+55 16610 57923
+59 315 315
+50
+
+chain 21816 chr1 249250621 + 146442152 146442891 chr1 247249719 + 144927740 144928479 1347746
+148 509 509
+82
+
+chain 20351 chr1 249250621 + 146356780 146459279 chr1 247249719 - 101132456 101205064 466
+178 42398 55179
+51 39820 14441
+32 3075 0
+39 16869 2651
+37
+
+chain 17175 chr1 249250621 + 249240118 249240599 chr1 247249719 - 247249264 247249719 6645750
+53 7 10
+47 109 0
+21 6 0
+36 51 102
+5 22 73
+56 16 0
+52
+
+chain 16391 chr1 249250621 + 146446357 146448997 chr1 247249719 + 144928805 144929904 1203759
+155 2048 507
+109 112 112
+60 57 57
+99
+
+chain 14917 chr1 249250621 + 146407068 146408474 chr1 247249719 + 144010187 144011603 12383
+76 149 159
+73 240 240
+47 136 136
+39 587 587
+59
+
+chain 14732 chr1 249250621 + 104074421 104074580 chr20 62435964 - 41767962 41768121 15357748
+159
+
+chain 13179 chr1 249250621 + 146404319 146408384 chr1 247249719 + 146846894 147006750 8455
+113 104 104
+20 54 54
+39 1744 1736
+34 1903 157702
+54
+
+chain 12360 chr1 249250621 + 146216167 146250305 chr1 247249719 - 103194351 103244298 1211
+37 128 128
+95 44 44
+58 67 67
+60 5 5
+51 3345 6525
+128 0 9435
+8 6200 4617
+43 3518 3485
+37 13507 18215
+40 613 636
+46 716 718
+72 53 53
+30 240 240
+72 1522 1531
+48 233 233
+42 89 89
+36 14 14
+5 804 801
+66 696 696
+34 1307 1378
+29
+
+chain 11952 chr1 249250621 + 146445104 146445575 chr1 247249719 - 100776503 100776974 637661
+94 18 18
+359
+
+chain 11854 chr1 249250621 + 146229744 146232010 chr1 247249719 + 144747607 144749863 153009
+21 19 9
+19 736 736
+20 10 10
+32 196 196
+62 54 54
+33 556 556
+43 383 383
+82
+
+chain 10753 chr1 249250621 + 146408065 146408192 chr1 247249719 - 101190210 101190337 3832842
+127
+
+chain 10394 chr1 249250621 + 104091245 104091359 chr5 180857866 + 153305659 153305773 21933263
+114
+
+chain 10333 chr1 249250621 + 104091131 104091240 chrX 154913754 + 74963065 74963174 22062861
+109
+
+chain 9815 chr1 249250621 + 146403058 146404974 chr1 247249719 - 101191494 101193412 750328
+43 256 256
+25 136 136
+32 152 152
+35 1179 1181
+58
+
+chain 9804 chr1 249250621 + 146245618 146249581 chr1 247249719 + 16785678 16789645 248382
+32 19 19
+6 51 51
+11 80 80
+47 3688 3692
+29
+
+chain 8504 chr1 249250621 + 146408954 146409155 chr1 247249719 - 101191099 101191300 2114480
+61 111 111
+29
+
+chain 8318 chr1 249250621 + 146407418 146407505 chr1 247249719 - 102486621 102486708 14753827
+87
+
+chain 7171 chr1 249250621 + 1619987 1620086 chr1 247249719 + 1662789 1662888 1670813
+99
+
+chain 7168 chr1 249250621 + 146247532 146247756 chr1 247249719 + 144759088 144759312 2272140
+43 123 123
+58
+
+chain 6908 chr1 249250621 + 146440123 146445030 chr1 247249719 - 101203201 101205034 129817
+119 142 142
+69 4461 1387
+116
+
+chain 6650 chr1 249250621 + 146406255 146406330 chr1 247249719 - 101188413 101188487 10133477
+21 3 2
+51
+
+chain 6566 chr1 249250621 + 146445881 146445977 chr1 247249719 + 144059904 144060000 2107997
+23 21 21
+52
+
+chain 6380 chr1 249250621 + 10629 10716 chrY 57772954 - 1612 1699 6955
+87
+
+chain 5940 chr1 249250621 + 146231384 146231447 chr1 247249719 - 102320696 102320759 393064
+63
+
+chain 5684 chr1 249250621 + 146407187 146407246 chr1 247249719 - 101189341 101189400 31412390
+59
+
+chain 5452 chr1 249250621 + 146243368 146248596 chr1_random 1663265 - 1047698 1052949 2624
+34 4838 4857
+26 270 274
+60
+
+chain 5266 chr1 249250621 + 249240022 249240077 chr1 247249719 - 247249582 247249637 32667083
+55
+
+chain 5203 chr1 249250621 + 146446237 146446668 chr1 247249719 - 102500144 102500575 1674615
+120 155 155
+156
+
+chain 4958 chr1 249250621 + 146451766 146451818 chr1 247249719 + 142879884 142879936 20619966
+52
+
+chain 4944 chr1 249250621 + 104074593 104074659 chr8 146274826 - 121738108 121738174 21132898
+66
+
+chain 4456 chr1 249250621 + 146406808 146406855 chr1 247249719 - 101188965 101189012 6127414
+47
+
+chain 4404 chr1 249250621 + 146406008 146406074 chr1 247249719 - 100540708 100540774 1844606
+66
+
+chain 4255 chr1 249250621 + 146230090 146231384 chr1 247249719 - 103181490 103211127 6721
+37 1201 29544
+56
+
+chain 4244 chr1 249250621 + 146216712 146216757 chr1 247249719 - 102323372 102323417 831523
+45
+
+chain 4123 chr1 249250621 + 146421615 146421675 chr1 247249719 + 143536766 143536826 34723
+60
+
+chain 3877 chr1 249250621 + 146435532 146435575 chr1 247249719 - 101203375 101203418 141544
+43
+
+chain 3825 chr1 249250621 + 146430767 146430810 chr1 247249719 - 101203375 101203418 118474
+43
+
+chain 3528 chr1 249250621 + 146454014 146454173 chr1 247249719 - 100628659 100628818 205230
+159
+
+chain 3185 chr1 249250621 + 146406525 146406559 chr1 247249719 - 101188682 101188716 16359386
+34
+
+chain 3178 chr1 249250621 + 104074770 104074842 chr7 158821424 + 21042162 21042234 21615733
+72
+
+chain 3121 chr1 249250621 + 146445079 146445768 chr1 247249719 + 144930661 144931350 792159
+25 471 471
+193
+
+chain 3050 chr1 249250621 + 146407036 146407068 chr1 247249719 - 101189190 101189222 23011976
+32
+
+chain 2960 chr1 249250621 + 146249122 146249154 chr1 247249719 + 144760680 144760712 1406096
+32
+
+chain 2741 chr1 249250621 + 146231545 146231601 chr1 247249719 - 104345036 104345092 8679
+56
+
+chain 2464 chr1 249250621 + 146424736 146424776 chr1 247249719 + 144037261 144037301 21508852
+40
+
+chain 2405 chr1 249250621 + 249239910 249239972 chr1 247249719 - 247249327 247249389 7681464
+62
+
+chain 2390 chr1 249250621 + 249240288 249240334 chr1 247249719 - 247249596 247249642 26481552
+46
+
+chain 2344 chr1 249250621 + 146216757 146250883 chr1 247249719 - 103711249 103726499 1396
+67 32948 14063
+57 892 901
+7 127 127
+28
+
+chain 2164 chr1 249250621 + 146237300 146252192 chr1 247249719 + 16771061 16779662 20592
+30 14825 8534
+37
+
+chain 1926 chr1 249250621 + 10623 10756 chr15 100338915 - 932 978 361
+6 87 0
+40
+
+chain 1909 chr1 249250621 + 146251590 146251644 chr1 247249719 - 103917507 103917561 1304306
+54
+
+chain 1317 chr1 249250621 + 146445768 146445881 chr1 247249719 + 142919887 142920000 1148922
+113
+
+chain 1215 chr1 249250621 + 146245082 146245105 chr1 247249719 + 144762924 144762947 79987
+23
+
+chain 1154 chr1 249250621 + 146232196 146232260 chr1 247249719 + 16765963 16766027 137025
+64
+
+chain 1035 chr1 249250621 + 146367698 146367747 chr1 247249719 - 99837677 99837726 4094688
+49
+
+chain 827 chr1 249250621 + 146445037 146445075 chr1 247249719 - 102502075 102502113 153232
+38
+
+chain 691 chr1 249250621 + 146454173 146454226 chr1 247249719 - 100557283 100557336 435331
+53
+
+chain 604 chr1 249250621 + 146429501 146429541 chr1 247249719 + 147018285 147018325 1335641
+40
+
+chain 424 chr1 249250621 + 146449372 146449403 chr1 247249719 - 100776122 100776153 793932
+31
+
+chain 395 chr1 249250621 + 146448669 146448702 chr1 247249719 + 144078479 144078512 164120
+33
+
+chain 88 chr1 249250621 + 146452351 146452395 chr1 247249719 - 99890656 99890700 12702616
+44
+
+chain 71 chr1 249250621 + 146451564 146451618 chr1 247249719 - 102499166 102499220 29039078
+54
+
+chain 12431961244 chr10 135534747 + 60000 135524747 chr10 135374737 + 50000 135374737 10
+5577104 0 50006
+12337571 50000 50000
+20794160 50000 50000
+286100 3200000 2480000
+191752 50000 50000
+3830277 50000 150000
+952205 100000 150000
+263307 100000 150000
+163231 50000 150000
+989829 100000 150000
+1941874 50000 50000
+211435 50000 50000
+30112515 0 319974
+13249156 0 10
+31058956 50000 50000
+2696597 150000 50000
+4615335 50000 10000
+246123 50000 50000
+1327328 1 1
+47 1 1
+1312 0 1
+56 1 1
+190 1 1
+31 1 1
+20182 1 0
+448068
+
+chain 12415603391 chr11 135006516 + 60000 134946516 chr11 134452384 + 50000 134451988 11
+1102759 50000 16576
+49571094 307000 207000
+503352 3100000 3000000
+14395596 47395 0
+491076 304 60
+30213 182 114
+26 142 1
+27914 0 1
+20009 0 1
+19 0 1
+39 0 1
+17 1 3
+10 0 1
+1008 0 1
+95 0 1
+5126 0 15
+303 0 1
+975 4 0
+1548 1 0
+191 0 20
+40 0 1
+74 1 0
+101 0 1
+25 1 0
+6178 1 0
+1875 52561 21437
+468 1 1
+81 1 1
+2620 0 1
+1640 0 4
+3305 1 0
+3342 0 1
+17899663 50000 12000
+8549206 150000 15562
+38507167 37 39
+1282 0 174
+387 0 86
+59
+
+chain 112280 chr11 135006516 + 69774695 69777256 chr11_random 215294 - 174770 177331 705
+2561
+
+chain 3731264 chr11_gl000202_random 40103 + 0 40103 chr11_random 215294 - 0 39615 791
+14658 1036 100
+6712 6 6
+32 35 523
+27 51 11
+17546
+
+chain 12330185447 chr12 133851895 + 145739 133779461 chr12 132349534 + 16000 132289534 12
+7035084 4 0
+543 1 0
+3777 1 0
+3889 52114 73000
+6014 0 1
+6524 5 126
+29 0 13
+20974 2 0
+3965 0 3
+444 11 0
+464 0 1
+27577110 3000000 1395000
+38631945 1 0
+14544 4 0
+1700 0 1
+789 12128 250000
+1783 0 1
+1075 2 0
+1042 0 1
+1526 1 1
+27 1 1
+2320 1 0
+166 0 1
+564 1 0
+2856 2 0
+900 1 0
+1387 1 1
+33 1 1
+2139 1 1
+48 1 1
+1305 2 0
+1533 2 1
+879 1 0
+744 26 26
+858 4 0
+1089 0 6
+1113 0 12
+818 1 1
+18 0 1
+217 1 1
+36 1 1
+2002 0 1
+1025 1 0
+450 48 48
+916 0 1
+18 1 1
+4694 8 0
+142 0 4
+3656 0 2
+3403 1 1
+47 1 1
+1524 1 1
+28 1 1
+5560 48 45
+676 8 8
+810 16 16
+536 0 2
+236 0 4
+167 4 0
+1419 53 49
+4688 1 1
+38 1 1
+18576 0 5
+5285 2 0
+6486 1 1
+25 1 1
+4341 14 0
+2662 0 5
+1170 0 1
+4268 4 0
+1036 1 0
+2117 8 0
+5917 0 1
+3239 4 0
+2619 1 1
+21 1 1
+937 1 1
+38 1 1
+2412 124 139
+2648 2 0
+9314 0 2
+1986 2 2
+16 1 1
+229 1 1
+93 1 1
+895 0 12
+415 5 1
+119 1 1
+185 9 8
+458 2 0
+89 1 1
+42 1 1
+2034 1 0
+1545 2 0
+280 4 0
+97 14 14
+231 2 0
+2814 0 5
+1679 1 1
+27 1 1
+25758689 1 0
+6536665 1 0
+377270 96749 57000
+668 1 1
+20 0 1
+3348 1 1
+33 1 1
+648 1 1
+29 1 1
+3731 0 4
+1834 9 14
+1688 10 0
+3103 5 5
+1140 0 1
+1167 0 1
+985 9 9
+2897 0 1
+1625 0 9
+1101 1 0
+1358 8 0
+13065721 68352 150000
+810 0 2
+343 1 0
+1771 1 0
+2702 6 7
+1900 0 1
+705 0 6
+303 0 1
+727 1 1
+43 3 6
+490 1 1
+59 1 1
+226 1 1
+52 0 3
+465 8 0
+194 1 1
+25 0 1
+139 17 17
+1833 0 1
+81 1 1
+39 1 1
+453 0 1
+719 1 1
+47 1 1
+558 0 1
+838 1 8
+288 9 10
+741 2 5
+465 1 1
+48 1 1
+268 1 1
+26 0 1
+1337 17 0
+12 2 1
+16 1 1
+84 85 2
+917 0 1
+110 1 1
+29 1 1
+1580 1 1
+40 1 1
+683 1 1
+24 1 1
+247 1 1
+36 1 1
+1411 14 14
+149 1 0
+10091386 3 0
+296 5 0
+220 100872 45000
+972469
+
+chain 2067120 chr12 133851895 + 60245 88108 chr2 242951149 + 114046160 114069967 1234
+334 1 1
+47 1 1
+111 1 1
+20 0 13
+84 1 1
+84 7 15
+55 1 1
+28 1 1
+77 1 1
+49 1 1
+99 10 10
+345 1 1
+48 0 4
+16 2 2
+168 1 1
+160 1 1
+68 1 0
+62 1 1
+23 1 1
+144 7 7
+94 2128 0
+762 12 12
+305 1 1
+40 1 1
+385 196 196
+207 0 1
+267 1 1
+53 1 1
+58 0 12
+43 1 1
+55 4 4
+38 1 0
+361 1 0
+53 1 1
+27 1 1
+448 1 1
+18 1 1
+309 4 0
+104 1 1
+35 1 1
+394 1 1
+16 1 1
+159 1 1
+38 1 1
+413 14 14
+82 5 7
+699 0 1
+52 23 24
+1077 9 9
+492 1 0
+144 18 19
+69 1 1
+26 1 1
+689 2 0
+34 5 6
+34 1 1
+187 1 1
+65 1 1
+181 9 9
+82 1 1
+55 0 2
+310 1 1
+25 1 1
+71 1 1
+74 3 3
+64 6 6
+216 5 5
+62 1 1
+35 8 3
+803 1 0
+23 1 1
+124 1 1
+90 1 1
+300 4 0
+48 0 4
+28 1 0
+85 7 4
+63 2 0
+7 3 0
+49 1 1
+255 31 31
+462 1 1
+38 1 1
+414 1 1
+37 1 1
+304 1 1
+36 1 1
+119 16 19
+62 1 1
+26 1 1
+306 1 1
+93 1 1
+114 1 1
+141 1 1
+464 1 1
+25 1 1
+145 1 1
+21 1 1
+196 1 1
+46 1 1
+295 11 11
+255 1 1
+21 1 1
+280 1 1
+90 1 1
+413 8 8
+1039 24 24
+761 1 0
+53 1 1
+94 1 0
+25 1 1
+63 1 1
+71 2070 1
+21 2 47
+228 3 0
+17 1 1
+133 11 0
+137 1 1
+43 1 1
+90 3 3
+23 2 0
+144 1 1
+99 1 1
+349 3 3
+29 5 5
+60 0 70
+93 1 1
+21 1 1
+138 0 2
+83 1 1
+68 1 1
+166 1 1
+49 1 1
+461 1 1
+18 0 17
+26 1 1
+50 1 1
+14 0 1
+34 1 1
+370 1 1
+32 1 1
+68 14 14
+98
+
+chain 484774 chr12 133851895 + 88108 95739 chrX 154913754 + 154905409 154913416 8417
+2 1 1
+34 1 1
+80 1 1
+32 1 1
+415 1 1
+48 1 1
+73 1 1
+44 1 1
+149 13 13
+211 1 1
+26 1 1
+271 0 3
+528 1 1
+96 1 1
+507 1 1
+100 1 1
+121 37 37
+520 1 1
+34 1 1
+166 1 1
+45 1 1
+96 1 1
+87 1 1
+82 4 4
+71 1 1
+34 1 1
+132 1 1
+23 1 1
+97 1 1
+30 2 2
+109 3 3
+36 1 1
+134 2135 2017
+245 454 1029
+82 84 0
+113
+
+chain 233388 chr12 133851895 + 133837240 133840071 chr7 158821424 + 158817351 158819960 454901
+564 1 1
+52 1 0
+36 1 1
+470 1 1
+28 1 1
+359 1 1
+38 1 1
+130 5 0
+3 216 0
+97 3 2
+46 1 1
+559 1 1
+43 0 1
+78 1 1
+94
+
+chain 194103 chr12 133851895 + 62428 64518 chr14 106368585 + 64430621 64433205 634790
+748 40 40
+140 0 1
+167 0 373
+27 0 120
+968
+
+chain 49263 chr12 133851895 + 133825767 133827148 chr11 134452384 + 74280352 74281733 2582033
+188 22 24
+55 110 110
+117 297 297
+62 252 253
+116 101 98
+61
+
+chain 35717 chr12 133851895 + 133841521 133841895 chr5 180857866 - 180793287 180793661 3746803
+374
+
+chain 32957 chr12 133851895 + 133823831 133824928 chrX 154913754 - 110744397 110745491 4131553
+102 47 47
+104 308 309
+61 155 155
+59 173 169
+88
+
+chain 18331 chr12 133851895 + 133822513 133823307 chr7 158821424 + 35158939 35159735 11829157
+110 151 152
+60 413 414
+60
+
+chain 16856 chr12 133851895 + 66036 76221 chr19 63811651 - 63781390 63791585 1292
+70 1 1
+57 16 16
+51 9959 9969
+31
+
+chain 16157 chr12 133851895 + 109428208 109428485 chr2 242951149 - 225002676 225002954 13880737
+71 91 92
+115
+
+chain 11750 chr12 133851895 + 60000 60122 chr12 132349534 - 132324140 132324262 19413804
+122
+
+chain 9037 chr12 133851895 + 133826997 133827421 chr2 242951149 + 160701141 160701565 3717783
+90 61 61
+34 175 175
+64
+
+chain 8057 chr12 133851895 + 133826086 133826759 chr3 199501827 - 98694913 98695583 3241421
+56 127 126
+50 305 303
+135
+
+chain 4873 chr12 133851895 + 133822983 133823177 chr6 170899992 + 146924403 146924597 15743780
+57 73 73
+64
+
+chain 4427 chr12 133851895 + 133827536 133827658 chr3 199501827 - 37386916 37387038 7696734
+122
+
+chain 4266 chr12 133851895 + 109428325 109428370 chr8 146274826 + 102422247 102422292 23131068
+45
+
+chain 4036 chr12 133851895 + 133826320 133826456 chrX 154913754 + 144352164 144352300 4124454
+136
+
+chain 3880 chr12 133851895 + 95312 95362 chr1 247249719 - 247249339 247249389 25961870
+50
+
+chain 3693 chr12 133851895 + 63176 63216 chr6 170899992 - 141104715 141104755 640206
+40
+
+chain 3673 chr12 133851895 + 133827423 133827506 chr2 242951149 - 104106513 104106596 10382380
+83
+
+chain 3091 chr12 133851895 + 133826496 133826821 chr11 134452384 - 91473718 91474043 4183905
+58 205 205
+62
+
+chain 3057 chr12 133851895 + 133822699 133822767 chr2 242951149 + 211079534 211079602 19980130
+68
+
+chain 2758 chr12 133851895 + 133827507 133827536 chr3 199501827 - 112531647 112531676 15775673
+29
+
+chain 2377 chr12 133851895 + 133825725 133826065 chr1 247249719 + 157351310 157351652 3309912
+42 265 267
+33
+
+chain 2375 chr12 133851895 + 95368 95419 chr1 247249719 - 247249256 247249307 12772530
+51
+
+chain 2223 chr12 133851895 + 133827262 133827357 chr6 170899992 + 81976496 81976591 4176034
+95
+
+chain 2091 chr12 133851895 + 109428279 109428301 chr20 62435964 + 39979396 39979418 21613404
+22
+
+chain 1955 chr12 133851895 + 133822880 133822953 chr4 191273063 - 60412182 60412255 19166211
+73
+
+chain 1569 chr12 133851895 + 133823330 133823447 chr5 180857866 + 90128366 90128483 9408356
+117
+
+chain 1532 chr12 133851895 + 133822199 133822253 chr12 132349534 + 77527067 77527121 12101346
+54
+
+chain 1265 chr12 133851895 + 133825609 133825680 chr2 242951149 + 183532658 183532729 7750866
+71
+
+chain 1251 chr12 133851895 + 95185 95235 chr18 76117153 - 76117025 76117075 24929113
+50
+
+chain 1165 chr12 133851895 + 133826456 133826496 chrX 154913754 - 53085075 53085115 5993397
+40
+
+chain 1153 chr12 133851895 + 133824667 133824711 chr10 135374737 - 97414674 97414718 8388000
+44
+
+chain 852 chr12 133851895 + 133822443 133822508 chr5 180857866 + 49699275 49699340 23831787
+65
+
+chain 636 chr12 133851895 + 133823040 133823067 chr6 170899992 + 127619395 127619422 20859432
+27
+
+chain 615 chr12 133851895 + 133823498 133823556 chr14 106368585 - 76653675 76653733 3589163
+58
+
+chain 440 chr12 133851895 + 133827198 133827224 chr1 247249719 - 50786620 50786646 7302157
+26
+
+chain 9007882413 chr13 115169878 + 19020000 115109878 chr13 114142980 + 17918000 114127980 14
+26987167 0 1
+40753157 150000 50000
+25443670 150000 400000
+1821999 413955 384056
+369930
+
+chain 17589438 chr13 115169878 + 114456082 114639948 chr13 114142980 - 484930 668986 160
+430 0 2
+2905 4 8
+143 0 30
+612 0 4
+18 0 2
+175 1 1
+49 0 2
+2159 1 1
+27 1 1
+979 0 144
+1492 0 2
+174870
+
+chain 8359015315 chr14 107349540 + 19000000 107289540 chr14 106368585 + 18070000 106360585 15
+1081285 1 1
+43 1 1
+76 0 2
+437 1 1
+19 1 1
+440 1 0
+11 1 1
+59 15 15
+63 12 12
+70 1 0
+734 1 1
+165 4 1
+96 1 1
+46 0 1
+83 1 1
+149 4 4
+164 20 20
+63 16 15
+359 1 1
+39 1 1
+103 1 1
+76 1 1
+139 1 1
+38 1 1
+344 1 1
+65 1 0
+166 5 5
+88 1 1
+57 287 0
+59 1 1
+317 1 0
+52 1 1
+92 0 4
+651 4 4
+82 1 1
+93 1 1
+64 1 1
+24 1 1
+856 1 1
+35 1 1
+258 1 1
+17 1 1
+478 0 1
+1335 33 33
+1029 1 1
+37 1 1
+1115 4 3
+72 1 1
+643 10 10
+132 6 6
+89 2 0
+209 4 15
+77 5 5
+427 1 1
+41 1 1
+949 1 1
+16 1 1
+732 1 1
+44 0 2
+128 1 0
+91 1 1
+180 6 6
+388 6 6
+50 12 13
+275 1 1
+33 1 1
+142 1 1
+61 1 1
+560 1 1
+20 1 1
+1327 13 6
+1013 83 83
+202 4 0
+43 1 1
+352 10 10
+261 1 1
+39 1 1
+939 0 12
+1678 0 36
+159 1 1
+32 1 8
+818 6 0
+580 0 1
+931 0 1
+276 0 2
+3513 46 60
+882 0 2
+94 1 1
+49 1 1
+864 0 4
+40 1 1
+807 15 16
+416 3 0
+3345 15 15
+92 29 30
+80 1 1
+48 1 1
+2459 1 0
+646 66 66
+359 1 1
+29 0 54
+1875 0 3
+141696 1 1
+32 1 1
+8201115 0 1
+107 0 1
+2137 1 1
+39 1 1
+8848 1 0
+4806 0 1
+2075 0 1
+16612 0 1
+2385 0 3
+11506 0 8
+1353 1 0
+4596 1 0
+2073 1 2
+28 1 1
+2311 1 1
+44 1 1
+10440 4 0
+894 1 0
+1638 96 0
+41 0 9
+20 1 1
+2705 0 6
+352 1 1
+25 1 1
+742 1 0
+1048 18 2
+12085977 1 0
+14871228 0 3
+29067652 1 1
+47 1 1
+20173856 0 1292
+2548494
+
+chain 25802 chr14 107349540 + 20085579 20085848 chr8 146274826 + 118781991 118782260 6606813
+269
+
+chain 9908 chr14 107349540 + 20110215 20120217 chr22 49691432 + 14757849 14767860 97
+45 9891 9900
+66
+
+chain 8901 chr14 107349540 + 20090287 20100367 chr14 106368585 - 87815145 87825210 65
+33 9964 9949
+83
+
+chain 7700563179 chr15 102531392 + 20000000 102521392 chr15 100338915 + 18260008 100338915 16
+8448 2 6
+4086 0 1
+9569 1 1
+40 5 0
+56 1 7
+872354 40513 40506
+553 4 4
+876 40 39
+139 25 25
+1881 18 19
+499 8 8
+310 79 85
+78 26 23
+181 6 5
+569 11 11
+539 28 24
+261 22 20
+776 15 13
+62 13 13
+860 0 1
+716 0 26
+1349 167 166
+1070 23 23
+398 1 0
+177 21 5
+534 0 4
+770 24 18
+606 33 33
+1861 55 55
+2169 0 3
+558 19 20
+227 14 16
+329 5 5
+430 18 20
+620 1 0
+1112 0 2
+641 4 0
+476 47 47
+1285 1 0
+1139 49 49
+183 0 4
+1425 0 20
+186 1 0
+219 1 0
+607 44 44
+371 8 2
+507 0 2
+66 42 43
+999 4 4
+318 15 15
+1092 74 74
+808 61 61
+52 42 42
+109 51 51
+1535 0 14
+14011 0 4
+7955 1 4
+1350 0 1
+318 27 27
+600 4 0
+442 1 0
+1396 38 38
+1107 3 0
+1441 5 0
+360 49 49
+256 10 20
+497 39 39
+2129 0 4
+1242 0 2
+478 0 4
+708 92 92
+154 10 10
+1583 33 33
+1303 37 0
+100 14 14
+1138 92 109
+114 31 31
+2917 34 34
+1762 48 48
+449 0 1
+2458 1 9
+869 0 1
+534 49 49
+309 0 1
+2627 1 1
+3729 0 22
+565 1 0
+1845 0 1
+660 27 27
+68 0 1
+217 46 22
+1519 34 34
+559 32 32
+3851 0 1
+265 7 8
+224 0 4474
+444 0 1
+1651 10 11
+297 0 1
+665 0 21
+48 1 1
+1763 0 2
+245 1 1
+39 1 1
+519 1 1
+31 1 1
+2398 6 0
+749 1 49
+2072 0 4
+703 5 5
+337 0 1
+470 45 45
+1163 0 3
+1342 45 45
+140 1 0
+83 65 64
+723 38 38
+99 28 31
+92 0 1
+1218 13 0
+384 2 0
+292 41 41
+101 12 12
+576 2 0
+1907 21 21
+318 0 1
+1973 34 34
+689 51 51
+357 8 8
+2354 15 15
+2295 26 26
+2558 28 28
+571 2 0
+16 5 0
+323 1 0
+36 1 0
+5342 0 111
+1722 70 38
+272 13 13
+1284 1 0
+1128 4 4
+2189 0 1
+474 0 2
+1284 27 27
+36 6 0
+641 39 39
+381 2 0
+56 0 1
+2591 57 57
+160 121 121
+89 0 2
+316 1 0
+782 0 20
+155 1 1
+21 1 1
+601 6 0
+567 0 1
+278 1 1
+29 1 1
+89 4 0
+1737 1 1
+58 1 1
+368 24 24
+2113 24 20
+218 2 0
+18 1 1
+684 4 4
+3200 33 33
+58 18 18
+164 39 39
+296 6 6
+431 37 37
+431 47 47
+93 26 26
+216 48 48
+2779 17 0
+745 1 2
+104 61 61
+445 28 28
+356 0 1
+1484 2 1
+436 25 25
+306 57 57
+230 4 4
+843 49 50
+364 7 7
+796 28 28
+663 2 0
+93 15 0
+4378 0 1
+133 30 26
+41 2 0
+80 150 150
+925 0 3
+1882 13 13
+4513 0 1
+111 78 78
+200 0 6
+682 1 0
+200 0 3
+429 2 0
+736 20 20
+1573 121 120
+245 21 12
+1656 22 54
+616 1 2
+158 1 0
+587 41 44
+1053 6 6
+1116 36 36
+152 7 10
+448 1 0
+269024 863295 100000
+334079 50000 100000
+180557 74 0
+62 0 107
+7 2 1
+26 3 4
+4 0 1
+19 3 4
+10 42 87
+27 1 1
+202 1 1
+17 1 0
+156 1 1
+55 1 1
+111 1 0
+144 1 1
+57 1 0
+687074 50000 50000
+120648 348 0
+45585 1 0
+6994 0 1
+3398063 12354 44008
+7672 2 0
+1809 0 1
+428524 10165 101014
+43170 4 4
+1064959 5086 128966
+1021 1 0
+1710 0 1
+931 2 0
+4505 1 0
+686 2 525
+360 0 33
+130 1 1
+18 1 1
+12369 0 1014
+6233 1 0
+359485 111749 100000
+33855822 239 0
+2852112 0 1
+7040367 1 0
+2815738 1 3
+7055922 50000 60000
+363827 32 32
+104991 1 0
+203136 6050 0
+1426791 50000 60000
+13510190 5553 22012
+9194 3 0
+108 4 0
+41 1 0
+45 7 0
+2350 13 0
+5027 2 0
+534 0 1
+794 2 0
+4227 8 6
+5769 0 1
+381 0 1
+2524 2 0
+547 5 0
+1967 1 0
+1192 0 105
+1042 6 0
+3935380
+
+chain 22529558 chr15 102531392 + 21901199 22210800 chr15 100338915 + 19154576 19464222 111
+143347 1 1
+30 1 1
+2265 10 11
+297 0 1
+665 49 70
+240 39 39
+1731 41 41
+519 33 33
+339 22 22
+2037 4 0
+749 1 49
+910 38 38
+1831 3 9
+333 0 1
+470 1 1
+43 1 1
+1518 1 1
+51 1 1
+1122 1 0
+2351 19 6
+376 2 0
+1022 2 0
+1907 1 1
+19 1 1
+318 0 1
+3104 8 8
+179 1 1
+29 1 1
+3162 2 0
+2854 1 1
+26 1 1
+482 1 0
+512 1 1
+26 1 1
+571 27 16
+323 37 36
+5342 0 111
+542 40 39
+1141 64 35
+275 13 13
+503 26 26
+130 44 44
+581 4 0
+1128 4 4
+749 0 1
+1439 0 1
+474 0 16
+1270 1 1
+25 1 1
+54 11 0
+623 1 1
+37 1 1
+381 20 0
+56 0 1
+2591 1 1
+55 1 1
+160 4 4
+75 14 14
+1217 0 15
+742 59 53
+955 3 0
+1737 60 60
+391 43 43
+2071 24 20
+218 21 19
+684 4 4
+1195 4 4
+2001 1 1
+31 1 1
+58 18 18
+499 6 6
+431 1 1
+35 1 1
+431 1 1
+45 1 1
+3158 17 0
+983 0 1
+773 16 16
+1457 4 1
+767 1 1
+55 1 1
+338 10 10
+650 0 2
+123 3 4
+261 1 1
+48 1 1
+53 7 7
+776 1 1
+46 1 1
+663 2 0
+377 13 13
+4081 0 1
+159 5 0
+41 1 0
+164 1 1
+61 4 4
+925 0 3
+934 18 18
+1971 0 5
+3592 1 1
+76 1 1
+200 0 6
+682 1 0
+632 2 0
+2338 1 0
+110 1 1
+231 10 0
+1682 42 54
+616 1 2
+171 2 1
+543 1 1
+45 0 12
+2837 1 0
+441 2 0
+4958 5 5
+455 37 37
+330 22 22
+711 46 46
+184 49 49
+153 61 62
+392 11 11
+1266 8 7
+241 42 41
+198 31 31
+1064 78 78
+528 0 4
+431 1 0
+108 64 53
+358 5 5
+566 35 33
+168 1 0
+251 41 41
+880 33 33
+248 7 9
+583 3 4
+217 41 41
+117 13 14
+203 78 78
+133 44 45
+59 43 43
+129 19 19
+887 1 0
+264 30 30
+352 16 16
+719 36 35
+196 49 49
+425 4 0
+358 15 15
+151 22 22
+714 0 3
+165 41 0
+199 134 134
+504 47 47
+526 12 16
+206 39 39
+372 6 6
+224 25 25
+304 7 7
+186 90 90
+1872 0 3
+1066 7 7
+180 85 75
+63 37 37
+157 65 65
+331 3 0
+302 3 6
+213 42 45
+350 45 49
+580 42 45
+252 43 43
+337 4 0
+667 10 7
+94 9 9
+441 18 18
+124 0 1
+277 42 42
+1729 37 37
+1562 3 1
+546 15 13
+409 22 22
+312 45 45
+46 0 2
+268 14 14
+1166 35 38
+460 0 2
+74 0 1
+323 27 26
+2747 24 28
+322 10 0
+592 23 21
+161 45 45
+207 50 50
+409 22 23
+188 50 49
+396 152 151
+343 26 28
+3430 49 49
+2161 72 72
+1696 5 0
+389 50 50
+340 23 23
+169 0 3
+70 0 4
+392 0 1
+106 32 32
+2476 23 23
+1397 53 54
+2187 18 18
+489 9 9
+2018 4 0
+108 17 14
+836 5 5
+417 48 48
+358 34 34
+481 55 56
+277 48 48
+180 25 21
+356 3 0
+66 66 66
+407 28 27
+603 36 36
+1239 0 3
+194 8 8
+444 0 1
+204 35 35
+162 15 15
+418 6 5
+236 9 9
+55 52 52
+105 145 146
+57 143 143
+52
+
+chain 868538 chr15 102531392 + 21886534 21896633 chr15 100338915 + 19140000 19150000 4870
+1208 1 0
+245 165 68
+494 89 89
+824 15 15
+196 0 1
+197 50 50
+274 0 1
+1127 15 15
+230 4 0
+76 48 49
+671 0 1
+352 24 19
+117 11 11
+288 5 4
+122 0 3
+135 37 37
+265 0 2
+62 2 0
+656 0 2
+792 69 69
+142 73 73
+307 2 0
+331 0 2
+378
+
+chain 566185 chr15 102531392 + 83551634 83557670 chr8 146274826 + 129534406 129540446 9431
+549 1 1
+105 1 1
+1154 0 4
+273 6 6
+3947
+
+chain 334937 chr15 102531392 + 21896662 21900709 chr15 100338915 + 19150028 19154088 190582
+86 46 44
+567 11 9
+733 23 25
+212 2 0
+100 40 40
+155 1 0
+189 34 34
+165 42 42
+219 56 68
+259 61 62
+380 3 8
+242 13 13
+408
+
+chain 246244 chr15 102531392 + 22183221 22212114 chr15 100338915 + 19767012 19795905 936
+45 207 207
+50 619 619
+50 396 396
+152 343 343
+26 3430 3430
+49 2161 2161
+72 2090 2090
+50 1100 1100
+32 3896 3896
+53 6108 6108
+48 358 358
+34 481 481
+55 277 277
+48 180 180
+25 425 425
+66 407 407
+28 603 603
+36 2089 2089
+35 901 901
+52 105 105
+145 57 57
+143 52 52
+1314
+
+chain 136774 chr15 102531392 + 21885000 21886534 chr15 100338915 + 19138465 19140000 942717
+402 49 49
+445 0 1
+638
+
+chain 38827 chr15 102531392 + 28705151 28710237 chr15 100338915 - 73838719 73843805 82
+5086
+
+chain 19525 chr15 102531392 + 27138463 27148846 chr15_random 784346 + 739466 749849 392
+10383
+
+chain 9597 chr15 102531392 + 29116154 29116267 chr19 63811651 - 22308947 22309060 23761910
+59 4 4
+50
+
+chain 6273 chr15 102531392 + 23685556 23685849 chr15 100338915 + 21236652 21236834 12713809
+67 205 94
+21
+
+chain 4893 chr15 102531392 + 29111049 29111100 chr21 46944323 + 41885809 41885860 33898070
+51
+
+chain 3039 chr15 102531392 + 22178426 22178458 chr8 146274826 + 6100529 6100561 34349851
+32
+
+chain 2975 chr15 102531392 + 22826750 22826789 chr15 100338915 + 20381852 20381891 2718765
+39
+
+chain 2542 chr15 102531392 + 21049663 21065195 chr18 76117153 + 14510749 14526638 994
+38 2128 2130
+28 13310 13665
+28
+
+chain 1826 chr15 102531392 + 20950735 20950759 chr19 63811651 - 51273213 51273237 15159639
+24
+
+chain 1062 chr15 102531392 + 21028626 21028659 chr21 46944323 - 32992576 32992609 1118
+33
+
+chain 912 chr15 102531392 + 22826789 22826824 chr15 100338915 + 20377303 20377338 985154
+35
+
+chain 7474990131 chr16 90354753 + 60000 90294753 chr16 88827254 + 0 88822254 17
+172343 1 0
+111 0 1
+5627 1 2
+8398838 50000 17500
+25336229 150000 100000
+1112651 11100000 9800000
+42003582 50000 20000
+1855370
+
+chain 7369719958 chr17 81195210 + 0 81060651 chr17 78774742 + 0 78654742 18
+252627 1 1
+24 1 1
+41 29 0
+295 0 29
+261 0 58
+116 0 58
+94 0 29
+79 37 8
+485 59 1
+28 1 1
+76 1 233
+26 0 29
+2765 1 0
+17 2 0
+2220 18 18
+343 37 37
+457 1 1
+39 1 1
+564 16 16
+2523 9 39
+1878 56 0
+22 0 29
+1681 1 0
+414 3 0
+282 68 0
+93 10 10
+293 4 0
+3190 0 1
+2562 4 0
+1809 0 3
+84 1 1
+62 1 1
+3775 27 0
+1968 0 16
+912 2 0
+696 4 4
+1428 15 15
+290 0 1
+1779 1 0
+60 1 1
+216 1 0
+375 1 1
+41 1 0
+9221 100000 46522
+3080543 1 0
+1208216 2 0
+1370 0 2
+1279 4 0
+322 5 0
+5660 0 210
+308 22 21
+973 0 8
+2901 0 1
+8479 1 0
+4122 0 7
+3187 0 4
+571 1 0
+167 1 0
+10174 7 7
+856 1 2
+1630 0 1
+4258 1 3
+1688 0 1
+388 304 0
+672 0 1
+8495 10 0
+2272 0 1
+8297 0 1
+1500 4 1
+733 2 37
+57 17 0
+51 532 42
+2085 0 2
+52 1 1
+2913 13 14
+1309 1 0
+3991 0 3
+1939 3 0
+887 2 0
+463 0 18
+64 3 0
+2104 20 0
+557 4 0
+120 1 0
+3670 0 2
+4347 5394 0
+5332 1 0
+2505 10 4
+6776 11 14
+9573 1 0
+1136 2 0
+3754 0 1
+4588 0 1
+637 17 17
+1283 0 8
+371 1 0
+2084 0 1
+492 0 2
+519 4 0
+952 2 0
+1517 0 1
+987 0 9
+1152 10 0
+3608 2 0
+3199 39 0
+734 0 1
+646 0 2
+2211 0 1
+14829 0 1
+3473 34 1
+22 0 11
+2194 1 0
+6443 4 5
+2627353 0 1
+11581974 43 0
+31 89 0
+238782 1 0
+1830653 0 1
+419873 116477 100008
+5586 0 6
+11057 2 0
+3240 0 1
+1237 2 0
+373 1 1
+43 1 1
+558379 3000000 100000
+1823446 1 0
+2728383 1 0
+29 1 0
+138 0 1
+144 8 6
+38 2 0
+7 1 0
+18 1 1
+70935 1 0
+10 2 0
+52 31 28
+189 1 0
+41 2 2
+750363 44 44
+4038953 50039 100039
+1523967 1 1
+47 1 1
+231 0 2
+1175 0 1
+555 1 1
+49 1 1
+566 0 7
+607 0 2
+4954 1 1
+18 7 6
+567 1 0
+421 0 2
+1010 0 8
+777 3 0
+925 5 12
+318 0 1
+230 13 20
+244 1 1
+13 1 0
+42 1 1
+220 1 1
+56 1 1
+101 0 225
+1113 0 1
+17 1 1
+2614 0 4
+7108 2 0
+617 0 14
+5674 2 0
+1852 1 1
+63 1 1
+56 1 1
+25 1 1
+332 6 0
+423 5 5
+61 0 4
+108 1 1
+46 1 1
+160 2 2
+72 1 1
+162 1 1
+20 1 1
+53 1 1
+63 1 1
+112 1 1
+59 1 1
+5885 0 2
+5871 30040 159230
+925 0 5
+214 7 7
+641 17 17
+1296 46 46
+2513 69 71
+76 2 1
+57 0 50226
+1963 18 18
+2694 55 55
+6616 0 1
+5106 18 0
+2521 7 7
+49 0 10
+3440 4 0
+4179 4 0
+2749 1 0
+1125 0 8
+55 1 1
+1840 14 14
+624 0 8
+1742 0 4
+3690 4 0
+2051 1 0
+751 1 0
+2111 11 10
+3110 0 1
+682 0 1
+2795 2 5
+241 1 0
+165 3 1
+1258 1 0
+1601 0 5
+3716 1 0
+1308 1 0
+2058 0 1
+1624 1 0
+478 0 4
+9 0 6
+35 1 3
+47 1 0
+2425 0 1
+1178 4 0
+33 1 1
+415 5 5
+887 3 1
+1605 0 15
+259 0 2
+78 1 0
+4570 1 0
+322 0 1
+1801 0 2
+836 0 3
+1509 1 0
+1732 1 0
+936 6 0
+1371 0 1
+625 12 2
+5009 1 1
+75 1 0
+20 0 1
+139 1 0
+523 3 0
+11 319 0
+1368 0 1
+774 1 1
+16 1 1
+3523 119 124
+497 0 4
+174 0 9
+1317 3 0
+508 1 0
+1126 0 1
+1952 2 0
+565 0 2
+871 1 0
+1460 0 6
+55 1 0
+420 0 6
+57 1 1
+119 1 1
+427 0 1
+459 11 14
+448 1 0
+1275 7 7
+360 0 1
+73 1 1
+48 1 1
+4920 0 3
+713 1 1
+21 0 3
+6 0 3
+6 0 1
+691 1 1
+44 1 1
+1158 38 38
+446 10 9
+566 1 0
+175 4 0
+796 10 0
+810 0 1
+78 17 18
+1531 2 0
+1274 1 1
+39 1 1
+53 1 3
+202 1 0
+707 17 17
+1733 1 0
+1540 42 42
+12471 0 3
+286 1 3
+5600 0 4
+6458 1 0
+4866328 0 102000
+1870126 0 257
+590080 18 6
+26953 0 1
+6737 4 0
+5946 0 1
+2319 4 0
+1641 1 1
+27 1 1
+1237 0 1
+2698 1 1
+140 1 1
+1689 2 0
+836 30 29
+5333 0 1
+509 0 1
+224 9 9
+4983 0 6
+4981 30 30
+6913 3 13
+1039 1 0
+11605 0 1
+22064 1 0
+16612 0 8
+902 0 1
+757 0 1
+84 46 46
+489 1 0
+10979 1 1
+18 1 1
+1517 0 1
+4576 0 1
+12558 0 4
+2726 1 0
+5291 0 2
+8706 1 0
+83 0 1
+406 7 0
+87 0 38
+5531 0 1
+23971 0 1
+7855 22 54
+4095 1 0
+803 5 5
+6382 0 6
+3546 28 0
+4264 2 0
+13194 6 6
+6463 0 1
+26075 1 1
+59 1 1
+10791 7 17
+707 1 0
+210 0 1
+1655 2 0
+5301 0 1
+1930 0 1
+14632 0 2
+1043 0 1
+3607 0 3
+312 1 0
+5953 0 2
+170 17 0
+489 1 0
+5260 28 0
+888 0 10
+2461 10 10
+237 0 2
+1716 1 3
+10694 4 0
+3754 0 1
+6173 1 0
+8017 2 1
+3594 4 0
+5439 1 0
+4137 14 0
+29 15 0
+6418 1 0
+1267 0 1
+723 6 0
+1080 0 2
+3878 1 0
+7682 1 1
+44 1 1
+3135 1 0
+174853 2 1
+2008 7 7
+5657 1 0
+6496 3 0
+89 5 0
+665 1 0
+954 1 1
+44 1 1
+375 8 7
+3317 2 0
+2753 0 1
+1863 3 0
+3228 0 1
+3571 49 45
+6488 2 0
+8451 172 172
+3797 16 0
+2103 1 0
+268 23 26
+7888 0 4
+701 0 4
+2402 6 0
+37 1 1
+2943 3 2
+8420 0 1
+932 324 0
+6726 0 1
+543 3 4
+4028 0 18
+88 4 0
+2999 0 1
+530 0 1
+1153 11 11
+919 2 0
+1174 17 0
+118 16 16
+2727 0 1
+543 1 0
+783 0 1
+1374 4 0
+8619 0 20
+281 44 44
+4364 50 51
+2856 1 0
+5399 1 0
+1506 0 1
+919 6 0
+7228 0 10
+3226 0 1
+435 0 1
+4463 132 0
+9760 1 0
+2034 0 6
+7656 0 1
+198212 132 0
+11700 5 0
+7647 0 1
+9062 0 4
+8778 2 0
+7014 0 1
+1613 2 0
+790 5 7
+7433 0 1
+6482 12 12
+6798 1 0
+1422 0 1
+3454 1 1
+43 1 1
+3097 2 0
+334 18 0
+1444 0 1
+2400 0 3
+3272 1 0
+9106 0 1
+1573 1 0
+4742 0 1
+3366 0 1
+5484 1 0
+2445 5 0
+5447 8 8
+2539 1 0
+1471 1 0
+238 1 1
+16 1 1
+288 5 5
+2995 2 0
+951 1 1
+35 1 1
+279 15 16
+3534 0 6
+3513 1 0
+163 1 0
+6173 1 0
+1074 0 1
+2818 0 1
+2868 1 0
+3796 0 1
+1118 167 1
+1278267 25 25
+10747175 217 0
+3504874 1053 0
+10844 11 13
+18805 0 1
+1960834 50000 126729
+3065 0 1
+3601036 8833 90008
+34292 0 1
+376 14 14
+1447 44 0
+3080 1 1
+43 1 1
+789 0 1
+11432680 50000 153000
+1902016 4098 0
+102 21 0
+3179 6 6
+877 1 1
+49 1 1
+296 1 0
+1375 1 1
+21 1 1
+607 5 5
+98 22 0
+6811 1 1
+17 11 0
+3804 0 1
+1356 1 1
+29 1 1
+297 0 1
+9543 2 0
+3131 4 0
+860 1 0
+27346 0 1
+7553 0 2
+2834 2 0
+394 0 4
+6322 44 44
+158 0 1
+405 8 11
+1128 0 7
+271 1 1
+21 28 0
+504 0 6
+1214 31 44
+384 3 0
+521 18 18
+392 0 11
+802 1 1
+25 2 3
+51 49 1
+49 1 1
+558 1 0
+351 0 1
+2779 13 13
+114398 82124 65008
+7795 1 0
+18 1 1
+4140 0 1
+28048 1 1
+32 1 1
+4630 0 1
+4573 0 3
+357 0 2
+4812 0 1
+14372 3 0
+203 1 0
+26257 0 1
+2734 2 0
+19262 5 5
+5022 1 0
+25471 1 0
+1114538 53 0
+82 0 126
+1416 16 16
+610 0 57
+482 0 1
+148 1 1
+24 1 1
+2322 1 1
+23 0 1
+719 16 0
+20 0 16
+105 9 9
+1277 1 0
+2498 1 0
+352 0 49
+50 50 0
+21 49 0
+28 49 0
+60 47 0
+17 97 0
+901 47 0
+272 14 1104
+279 1 0
+37 12 11
+65 32 0
+18 94 0
+60
+
+chain 3227650 chr17 81195210 + 81075742 81110122 chr17_random 2617613 + 864624 914847 755
+922 0 1
+430 0 1
+763 0 1
+19745 32 32
+637 36 15873
+186 0 1
+2389 0 1
+616 0 1
+1932 12 12
+6680
+
+chain 2732964 chr17 81195210 + 36295616 36336227 chr17 78774742 - 45363365 45403960 362
+666 1 1
+114 1 1
+1777 1 1
+22 1 1
+2481 3 0
+947 3 1
+994 1 1
+26 1 1
+5327 2 0
+95 13 13
+2424 0 1
+339 2 1
+288 1 0
+1180 8 8
+1145 2 4
+1144 1 0
+322 1 0
+28 1 0
+35 1 0
+1499 0 1
+1258 7 6
+1123 0 1
+269 5 4
+1850 18 19
+188 3 0
+403 1 1
+18 1 1
+3148 1 1
+160 1 1
+105 11 0
+573 10538 10545
+33
+
+chain 1501094 chr17 81195210 + 81048174 81075742 chr17_random 2617613 + 1430075 1457643 965
+53 10174 10174
+50 21 21
+49 28 28
+49 60 60
+47 17 17
+97 901 901
+47 680 680
+32 18 18
+94 60 60
+15091
+
+chain 1197294 chr17 81195210 + 21670280 21683085 chr17_random 2617613 - 711226 724030 995
+6335 1 0
+1486 0 2
+2024 2 0
+2957
+
+chain 653269 chr17 81195210 + 66064861 66073694 chr17_random 2617613 - 926391 957193 299
+3246 4346 26315
+1241
+
+chain 307142 chr17 81195210 + 79761820 81150656 chr17_random 2617613 + 2320255 2536424 170
+87 6 8
+1077 0 1
+77 0 1
+1009 0 1
+98 0 1
+35 0 1
+131 0 1
+288 0 1
+33 1 0
+225 0 1
+279 0 1
+110 0 1
+55 0 1
+107 0 1
+202 12 15
+111 0 1
+36 0 2
+25 0 1
+202 0 1
+95 0 1
+145 1 1
+21 0 1
+222 0 1
+41 0 1
+492 4 0
+594 0 1
+179 0 1
+412 0 1
+37 0 1
+13 0 1
+34 0 1
+76 37 38
+204 27 27
+204 1 3
+8 0 5
+23 0 1
+430 0 1
+145 0 1
+271 0 1
+222 0 1
+51 0 1
+17 0 1
+23 2 4
+385 0 1
+337 0 1
+374 0 1
+140 17 22
+297 0 1
+72 5 8
+193 0 1
+8 0 1
+28 0 1
+17 0 1
+17 0 1
+445 0 1
+169 0 1
+35 37 3
+425 0 1
+41 0 1
+37 0 1
+79 0 1
+100 0 1
+127 0 1
+422 0 1
+17 1 1
+284 1 3
+56 10 12
+650 0 1
+163 0 2
+6 0 1
+36 1 1
+519 0 1
+39 0 1
+78 0 1
+216 3 5
+66 0 1
+58 0 1
+68 0 1
+292 4 0
+46 2 0
+108 2 0
+23 114 0
+830 0 1
+136 43 43
+23 32 10
+63 64 65
+380 0 1
+22 1 1
+440 0 1
+66 1 1
+17 0 1
+171 3 5
+27 1 1
+130 10 13
+128 0 1
+418 0 1
+4 1 2
+37 0 1
+29 0 1
+27 0 1
+748 0 1
+251 0 1
+219 0 1
+111 0 1
+48 0 1
+325 0 1
+296 0 1
+383 0 1
+62 0 1
+244 0 2
+248 9 11
+180 0 1
+241 0 1
+40 1 3
+6 0 1
+19 0 1
+27 0 1
+166 0 1
+78 0 1
+165 0 1
+33 0 1
+9 0 1
+172 0 1
+261 0 1
+200 16 21
+121 0 1
+37 2 4
+74 0 1
+97 3 5
+11 0 1
+51 0 1
+642 0 1
+317 11 14
+138 1324229 151143
+4948 1 0
+1850 67 60
+3859 1 0
+456 5 4
+1605 21 21
+1281 13 7
+5085 0 456
+1548 1 1
+37 1 1
+2825 1 1
+64 1 1
+1075 1 0
+721 1 0
+5566 5 22
+1136 0 1
+2390 3 0
+1347 2 0
+4617
+
+chain 266741 chr17 81195210 + 81150656 81195210 chr17_random 2617613 - 1100691 1809734 427
+1871 0 662945
+298 0 1
+6514 2 2
+45 0 1
+6237 3 5
+1230 32 32
+347 0 1
+1941 14 14
+149 0 1
+25553 59 1621
+16 63 39
+180
+
+chain 215840 chr17 81195210 + 66068832 66109867 chr17_random 2617613 + 1644335 1685356 1023
+3394 37597 37583
+44
+
+chain 30167 chr17 81195210 + 44458173 44458487 chr2 242951149 - 34181426 34181740 4632506
+314
+
+chain 29586 chr17 81195210 + 36420504 36420817 chr7 158821424 - 10371995 10372309 4828537
+136 0 1
+177
+
+chain 20882 chr17 81195210 + 56914122 56914339 chrX 154913754 + 31643322 31643539 5151267
+217
+
+chain 16484 chr17 81195210 + 44491151 44521781 chr17 78774742 + 42064051 42094670 662
+44 30454 30443
+132
+
+chain 14999 chr17 81195210 + 44428451 44428612 chr17 78774742 + 42001706 42001867 887
+161
+
+chain 12695 chr17 81195210 + 44739444 44739576 chr17 78774742 + 41877181 41877313 13974721
+132
+
+chain 12494 chr17 81195210 + 19077136 19077299 chr17 78774742 - 59726399 59726562 431
+43 31 31
+89
+
+chain 7858 chr17 81195210 + 253568 254148 chr17 78774742 + 253365 253974 1160836
+37 486 515
+57
+
+chain 5202 chr17 81195210 + 79704633 79704687 chrY 57772954 - 54321400 54321454 32857515
+54
+
+chain 5149 chr17 81195210 + 36426505 36456524 chr17 78774742 - 35824084 35853324 896
+73 1 1
+45 29858 29079
+42
+
+chain 3754 chr17 81195210 + 60419213 60419252 chr8 146274826 - 11845696 11845735 33181261
+39
+
+chain 3753 chr17 81195210 + 44413461 44413510 chr17 78774742 - 18492830 18492879 715
+49
+
+chain 3637 chr17 81195210 + 79776689 79776727 chr17_random 2617613 + 2335092 2335130 5614693
+38
+
+chain 3637 chr17 81195210 + 79776651 79776689 chr17_random 2617613 + 2335092 2335130 5614694
+38
+
+chain 3636 chr17 81195210 + 79776613 79776651 chr17_random 2617613 + 2335130 2335168 7454076
+38
+
+chain 2637 chr17 81195210 + 252694 252723 chr17 78774742 + 252810 252839 1426666
+29
+
+chain 2581 chr17 81195210 + 81166856 81166888 chr1 247249719 + 441705 441737 997
+32
+
+chain 2427 chr17 81195210 + 79772596 79772621 chr17_random 2617613 + 2331168 2331193 24392944
+25
+
+chain 1872 chr17 81195210 + 79585571 79585619 chr11 134452384 + 72960908 72960956 2849402
+48
+
+chain 790 chr17 81195210 + 36328756 36331384 chr17_random 2617613 - 1242589 1245215 133
+46 2513 2511
+69
+
+chain 170 chr17 81195210 + 34725848 34725887 chr17_random 2617613 + 1051433 1051472 428
+39
+
+chain 94559897 chr17_ctg5_hap1 1680828 + 188271 1499222 chr17 78774742 - 36776984 37845687 55
+188 30 30
+348 14 15
+235 24 24
+194 3 0
+334 40 40
+270 54 54
+61 87 84
+948 4 3
+1658 2 0
+1730 0 2
+285 0 1
+2885 1 1
+38 1 1
+2933 0 1
+1942 10 0
+375 0 1
+5094 0 1
+814 1 1
+18 1 1
+4676 8 0
+578 10 7
+467 0 1
+892 1 0
+479 48 48
+132 0 6
+61 13 15
+66 38 38
+1901 35 35
+862 7 0
+3895 1 0
+740 44 44
+313 7 6
+4916 4 4
+507 0 1
+2214 1 1
+25 0 3
+106 2 0
+40 1 1
+146 1 1
+30 1 1
+63 0 1
+192 5 5
+3242 0 2
+385 33 33
+972 12 0
+93 1 1
+3332 2 2
+71 1 1
+57 1 1
+149 0 2
+91 1 1
+219 14 14
+606 1 1
+53 1 1
+1068 0 12
+3191 29 29
+7028 1 0
+478 1 0
+2064 0 1
+408 17 21
+675 1 1
+17 1 0
+4 1 1
+3445 0 1
+158 0 2
+312 0 14
+1801 0 1
+1424 4 0
+1894 2 0
+364 6 6
+54 2 0
+47 1 1
+1105 10 1
+3088 0 1
+1176 6 0
+4141 1 1
+24 0 1
+169 71 71
+1596 1 1
+37 1 1
+2758 5 0
+2986 1 1
+20 1 1
+206 4 0
+11154 0 17
+583 0 8
+1703 0 10
+1675 1 0
+392 1 0
+6851 37 37
+2872 132 0
+446 9 0
+3437 5 5
+995 0 2
+898 1 1
+18 1 1
+128 0 1
+2151 2 0
+6413 1 1
+48 1 1
+786 0 1
+939 0 1
+258 0 4
+1247 2 0
+4742 0 1
+3520 54 51
+1220 1 1
+30 1 1
+638 1 0
+2474 1 1
+42 1 1
+266 0 16
+106 1 1
+19 1 1
+3806 328 0
+1161 1 0
+4896 0 1
+779 0 2
+543 1 0
+4979 11 11
+1670 1 0
+889 3 0
+2126 2 0
+87 0 18
+193 1 0
+3840 12 0
+3234 4 0
+2802 0 1
+873 1 0
+1288 1 5
+2202 1 1
+21 1 0
+1366 0 1
+4830 4 0
+48 1 1
+2894 1 1
+7 14 0
+43 0 4
+1003 1 1
+28 1 1
+102 3 0
+370 50 50
+830 1 3
+674 3 7
+2759 2 0
+4559 14 12
+862 1 0
+245 49 49
+1367 0 3
+428 13 41
+77 0 9
+701 1 0
+528 1 1
+31 1 1
+1397 0 2
+832 1 1
+34 2 0
+404 1 0
+142 1 1
+30 1 1
+272 2 0
+783 0 2
+4039 1 0
+449 8 0
+2647 1 0
+1730 7 1
+38 80 0
+160 5 0
+492 0 12
+1920 1 1
+117 1 1
+350 1 1
+38 1 1
+279 1 1
+40 1 1
+1367 4 0
+427 35 35
+141 46 46
+399 1 0
+1786 35 35
+697 0 1
+1104 20 20
+290 28 28
+1774 0 5
+1339 5 0
+527 1 0
+312 62 62
+199 1 1
+239 42 42
+629 1 1
+41 1 1
+298 3 3
+26 1 1
+642 1 1
+52 1 1
+206 8 0
+1930 0 1
+806 19 12
+578 10 7
+375 1 1
+44 1 1
+939 2 0
+679 10 0
+56 0 2
+73 13 13
+556 1 1
+18 1 1
+1386 1 1
+35 281 0
+106 1 1
+435 13 0
+686 2 0
+1401 0 8
+1799 1 0
+1566 0 3
+692 21 21
+1368 5 5
+150 28 28
+53 6 11
+54 50 50
+129 4 4
+550 15 0
+160 13 13
+1640 1 0
+170 31 31
+1087 124 123
+249 12 12
+407 1 1
+18 1 1
+637 13 13
+450 1 1
+30 1 1
+100 1 1
+37 1 1
+407 0 2
+2327 8 1
+107 1 1
+37 1 1
+885 1 1
+20 1 1
+134 18 18
+168 1 0
+161 6 6
+497 1 1
+16 1 1
+2755 29 29
+102 242 244
+58 8 8
+153 14 14
+711 41 41
+76 35 35
+287 93 93
+472 14 21
+608 7 8
+171 34873 0
+117 7 7
+68 10 0
+31 1 1
+95 11 11
+267 1 1
+19 1 1
+494 1 1
+26 1 1
+135 1 0
+302 1 1
+26 1 1
+349 0 1
+37 1 1
+254 1 1
+24 1 1
+550 1 0
+170 1 1
+38 1 1
+100 1 1
+31 0 1
+305 6 8
+370 0 3
+162 7 0
+39 4 4
+112 6 6
+318 1 1
+49 1 1
+135 1 1
+34 1 1
+129 1 1
+49 1 1
+620 0 1
+98 1 1
+43 1 1
+252 1 1
+37 1 1
+824 5 5
+131 9 10
+247 1 1
+20 1 1
+303 1 0
+668 1 1
+45 1 1
+316 14 14
+657 1 1
+93 1 1
+290 0 3
+148 1 1
+29 5 5
+74 1 1
+40 1 1
+1516 1 1
+57 1 1
+132 3 0
+178 1 1
+131 1 1
+127 1 1
+103 0 1
+61 1 1
+460 5 7
+90 1 1
+22 1 1
+87 1 1
+44 1 1
+85 1 3
+767 0 7
+60 1 1
+79 1 1
+31 1 1
+258 1 1
+26 0 1
+11 2 2
+140 1 1
+31 1 1
+110 1 0
+12 9 0
+776 8 8
+50 1 0
+445 1 1
+34 1 1
+278 15 15
+125 1 0
+635 18 19
+183 0 1
+75 10 10
+200 19 21
+832 14 14
+2247 6 0
+318 0 2
+180 10 0
+167 1 1
+43 1 1
+60 1 1
+43 1 1
+268 0 11
+1220 1 1
+46 5 5
+1001 16 16
+218 7 7
+142 17 0
+74 1 1
+130 1 1
+30 2 0
+588 1 1
+83 2 2
+58 25 25
+65 50 50
+873 23 23
+277 21 20
+237 3 0
+66 0 51
+145 0 1
+133 1 1
+23 1 1
+1087 3 2
+295 4 5
+57 10 8
+347 1 1
+18 1 1
+350 3 5
+259 0 1
+771 3 4
+85 1 1
+62 8 8
+224 1 1
+40 1 1
+50 0 3
+137 1 1
+199 3 3
+21 1 1
+272 0 10
+66 12 0
+27 1 1
+138 6 5
+762 1 1
+20 1 1
+324 9 9
+71 0 4
+174 5 12
+237 6 6
+57 1 6
+21 1 1
+156 0 2
+89 1 1
+140 1 1
+69 11 0
+407 0 2
+20 1 1
+131 0 2
+162 1 1
+29 1 1
+65 7 7
+1199 1 1
+68 1 1
+75 12 12
+78 3 3
+37 1 1
+499 1 1
+44 1 0
+397 1 1
+116 1 1
+147 1 0
+286 4 0
+122 31 0
+436 1 1
+27 1 1
+137 11 0
+448 40 0
+174 5 5
+148 1 0
+42 40 0
+506 850 23
+509 1 1
+61 1 1
+113 1 1
+83 1 0
+90 1 1
+229 0 1
+366 0 6
+625 0 1
+160 1 1
+43 1 1
+174 1 1
+53 1 1
+129 10 10
+205 1 1
+18 1 1
+386 1 1
+36 1 1
+775 1 1
+49 0 2
+118 10 10
+238 4 0
+801 0 5
+164 73 73
+1003 22 15
+181 1 1
+62 1 1
+1006 1 1
+25 1 1
+361 1 1
+76 21 0
+386 9 0
+224 25 34
+1276 0 4
+157 4 4
+450 1 1
+15 1 0
+36 1 1
+402 15 0
+1572 8 9
+272 3 0
+319 9 9
+673 0 724
+177 23 26
+230 2 0
+107 1 1
+80 99 99
+319 1 0
+711 0 1
+18 1 1
+674 3 0
+826 0 2
+503 1 1
+25 32 0
+42 1 1
+67 1 0
+395 19 14
+328 1 1
+69 1 1
+520 1 1
+31 1 1
+1063 1 1
+67 2 2
+55 4 0
+477 4 0
+69 0 1
+807 4 3
+26 1 1
+400 2 0
+707 5 0
+41 1 1
+200 1 1
+33 1 1
+744 1 1
+25 1 1
+224 2 0
+121 9 4
+44 1 1
+266 78 94
+522 0 1
+81 1 1
+3286 0 1
+341 1 1
+17 2 1
+445 1 1
+23 1 1
+1029 2 0
+169 1 1
+30 1 1
+577 1 0
+754 2 2
+43 1 1
+170 20 14
+365 1 1
+88 0 1
+1312 0 1
+354 1 4
+526 4 2
+1931 3 0
+650 17 17
+454 1 1
+59 2 3
+167 3 0
+1448 13 13
+69 1 1
+48 1 1
+398 1 1
+89 5 0
+33 1 1
+422 1 1
+39 0 1
+250 86 15
+1631 0 1
+20 1 1
+69 1 1
+38 1 1
+104 0 2
+30 1 1
+420 1 1
+70 1 0
+497 1 0
+68 0 14
+1402 1 1
+28 1 1
+385 4 0
+42 1 1
+245 1 1
+31 2 1
+1110 1 1
+44 1 1
+1784 1 1
+42 1 1
+194 0 1
+181 0 4
+278 14 13
+800 1 0
+160 0 2
+259 1 1
+48 1 1
+336 5 0
+49 12 0
+814 1 1
+39 1 1
+144 4 0
+618 0 4
+159 0 3
+30 1 1
+443 2 0
+140 1 1
+49 1 1
+510 1 1
+22 1 1
+1186 1 1
+45 1 1
+2488 9 0
+226 12 8
+769 1 1
+36 3 0
+1785 1 1
+40 1 1
+570 5 0
+122 7 7
+181 11 11
+539 0 8
+1090 7 7
+128 0 1
+918 0 1
+314 43 43
+173 26 25
+374 0 1
+267 43 49
+69 16 15
+531 16 16
+179 0 6
+604 2 0
+646 28 35
+276 0 1
+1116 21 21
+257 1 0
+165 56 57
+85 41 41
+939 52 52
+134 6 6
+966 5 0
+1657 1 0
+142 22 23
+301 14 0
+280 35 35
+304 3 0
+1345 4 0
+219 1 1
+93 1 1
+646 1 1
+70 1 1
+115 1 1
+25 0 2
+6 1 1
+876 0 1
+750 1 0
+1106 1 1
+44 1 1
+1136 0 1
+2705 1 1
+29 1 1
+474 1 0
+24 1 1
+517 18 17
+283 45 35
+190 6 3
+714 102 102
+1046 0 2
+2521 29 29
+123 1 0
+171 0 8
+504 5 6
+2380 0 1
+1479 53 42
+159 5 5
+248 1 1
+34 1 1
+643 2 0
+586 0 4
+1216 1 1
+30 1 1
+1308 1 1
+25 1 1
+244 0 4
+1092 11 11
+297 0 4
+776 22 22
+62 1 0
+222 0 1
+38 1 1
+808 0 7
+45 1 1
+42 2 0
+313 5 0
+1028 2 3
+366 0 2
+298 41 355
+1457 37 37
+356 49 49
+849 140 128
+155 0 4
+92 6 6
+2333 1 0
+546 1 0
+612 68 68
+259 1 0
+304 3 0
+1246 1 0
+351 22 21
+1110 14 14
+364 0 3
+349 1 1
+39 1 1
+76 0 8
+152 9 0
+283 1 0
+117 1 2
+304 1 0
+1958 19 0
+278 1 1
+109 1 1
+1942 1 1
+31 2 0
+13 1 1
+312 18 0
+151 7 0
+62 1 1
+694 1 1
+18 1 1
+163 1 1
+17 1 0
+1103 2 0
+218 1 0
+21 1 1
+372 11 11
+434 3 4
+440 4 0
+45 1 0
+402 1 1
+46 1 1
+757 1 1
+43 1 1
+96 27 81
+499 1 1
+21 1 1
+184 14 14
+307 15 16
+1265 1 1
+62 1 1
+1051 1 0
+1157 1 1
+28 2 0
+349 3 0
+606 1 1
+22 1 1
+107 0 1
+36 1 1
+499 1 1
+27 1 1
+505 0 1
+1698 6 0
+38 1 1
+924 1 1
+33 1 1
+108 0 2
+196 1 1
+25 1 0
+24 1 1
+824 6 0
+725 0 1
+917 17 0
+185 1 1
+51 4 4
+93 0 1
+351 1 1
+34 1 1
+608 10 10
+82 2 0
+27 1 1
+2343 1 1
+48 1 1
+188 9 9
+623 4 3
+603 0 6
+11 1 1
+379 1 1
+52 1 1
+157 37 20
+879 51 58
+229 14 2
+83 1 1
+70 1 0
+1849 1 1
+42 1 1
+961 1 1
+22 1 1
+219 1 1
+25 1 1
+551 0 3
+26 1 7
+250 1 1
+44 1 1
+1028 9 2
+471 1 1
+31 0 1
+574 0 323
+192 1 1
+44 1 1
+1934 168 168
+186 1 0
+197 25 0
+161 1 0
+15 6 0
+806 1 1
+18 1 1
+184 1 0
+86 1 1
+16 1 1
+183 0 1
+641 12 12
+687 0 2
+735 2 0
+45 0 6
+308 11 11
+153 1 1
+23 1 1
+143 1 1
+59 1 1
+178 28 0
+899 0 3
+1351 2 0
+168 3 0
+407 1 0
+290 2 1
+227 1 1
+48 1 1
+704 1 1
+48 1 1
+866 93 93
+536 1 5
+1481 8 11
+180 16 16
+88 6 0
+249 0 44
+37 1 1
+294 1 1
+32 0 20
+1368 1 1
+93 1 1
+1638 11 11
+303 0 1
+55 1 1
+24 1 1
+1188 1 0
+227 2 2
+45 3 0
+205 0 4
+34 0 1
+159 1 1
+24 1 1
+398 0 1
+1259 16 16
+64 2336 0
+59 1 1
+44 0 3
+25 1 1
+209 1 1
+18 1 1
+348 1 1
+30 1 1
+413 27 0
+53 1 1
+23 2 0
+25 0 4
+532 0 12
+184 1 0
+278 1 1
+29 1 1
+1186 1 1
+15 1 1
+300 12 12
+570 1 1
+43 1 1
+183 5 6
+134 1 0
+508 1 1
+30 1 1
+1074 1 1
+24 1 1
+162 8 8
+1046 1 1
+20 1 1
+817 0 3
+1128 1 1
+41 1 1
+166 27 27
+667 15 15
+967 2 0
+10 2 0
+261 1 0
+792 1 8
+153 0 3
+1788 13 22
+1089 1 0
+994 2 0
+368 0 18
+207 1 1
+39 1 1
+332 0 3
+298 5 3
+68 1 1
+44 1 1
+958 1 1
+41 1 1
+1009 0 24
+12 1 0
+118 0 1
+171 16 16
+229 8 8
+233 21 21
+71 1 1
+38 1 1
+185 1 0
+544 1 1
+64 2 0
+614 1 1
+62 1 1
+536 1 1
+143 1 1
+679 0 5
+169 0 3
+597 1 0
+654 1 0
+1270 0 11
+174 0 2
+606 1 1
+59 2 0
+153 3 4
+1186 10 11
+92 1 4
+956 4 0
+302 0 9
+199 1 1
+31 1 1
+878 31 0
+452 10 10
+988 20 15
+1054 0 1
+131 0 4
+652 2 0
+37 1 1
+142 1 1
+36 0 5
+29 0 8
+4136 1 1
+32 1 1
+701 11 11
+258 0 1
+133 7 7
+170 1 0
+372 0 1
+26 4 3
+31 1 1
+131 1 0
+29 1 0
+2657 10 10
+2046 7 0
+870 1 0
+101 16 18
+163 0 1
+526 4 3
+281 0 3
+1907 0 1
+30 0 3
+164 0 3
+132 0 1
+352 1 0
+455 1 0
+726 0 2
+107 1 1
+33 1 1
+156 2 0
+576 1 1
+16 1 0
+76 1 0
+862 11 11
+1049 1 0
+47 1 1
+69 0 3
+607 1 1
+46 1 1
+1700 0 1
+825 13 13
+813 0 1
+213 1 0
+46 1 1
+630 1 0
+683 51 52
+118 1 1
+28 1 1
+1162 1 1
+66 0 3
+472 14 0
+16 1 1
+134 1 1
+119 1 1
+1129 5 5
+149 1 1
+57 1 1
+918 1 1
+36 1 1
+752 12 12
+1962 0 238
+2372 0 15
+175 7 7
+833 1 1
+25 1 1
+315 1 1
+16 1 0
+436 15 15
+67 15 15
+1207 6 5
+732 6 0
+79 1 1
+53 1 1
+1521 5 6
+140 1 0
+3576 12 12
+479 1 1
+37 1 1
+1518 1 1
+77 1 1
+102 1 1
+26 1 1
+812 1 1
+23 1 1
+1740 0 1
+1077 1 1
+17 1 1
+885 6 6
+441 17 17
+284 1 1
+37 1 1
+107 1 1
+17 1 1
+335 1 1
+50 1 1
+120 8 7
+588 0 8
+1512 38 1
+550 45 45
+376 1 1
+63 1 1
+2111 0 1
+574 14 14
+1622 3 1
+683 23 26
+673 1 1
+45 12 0
+98 3 4
+93 20 0
+2130 10 10
+941 1 1
+24 1 1
+1362 2 0
+1696 1 1
+22 2 2
+737 1 1
+26 1 1
+922 1 1
+32 1 1
+923 7 8
+432 0 1
+152 1 1
+26 1 1
+841 0 4
+441 0 103
+1348 10 11
+589 1 1
+44 1 1
+775 8 8
+1051 0 2
+152 13 13
+572 6 6
+543 1 1
+45 1 1
+663 7 7
+802 1 0
+888 1 1
+44 1 1
+210 1 0
+111 1 1
+34 1 1
+459 0 1
+323 1 0
+1116 1 0
+27 1 1
+142 1 1
+21 1 1
+784 1 1
+37 0 4
+40 1 1
+813 1 3
+371 1 1
+25 1 1
+257 1 1
+88 1 1
+276 47 47
+192 5 9
+445 1 1
+19 1 1
+66 8 8
+205 1 1
+79 11 0
+106 1 1
+122 1 1
+2478 0 6
+89 1 1
+47 1 0
+68 1 1
+680 0 4
+1040 0 1
+424 1 1
+33 1 1
+170 0 1
+456 1 1
+66 1 1
+820 18 18
+146 11 11
+642 2 0
+28 1 1
+242 1 0
+50 0 3
+7 1 1
+301 13 13
+126 1 1
+40 1 1
+98 0 2
+202 11 11
+564 23 0
+145 10 7
+1202 1 1
+103 1 1
+459 1 1
+24 1 1
+298 1 1
+44 1 1
+1384 1 1
+31 1 1
+569 1 1
+68 1 1
+535 5 45
+575 1 1
+30 1 1
+1885 1 0
+426 3 0
+19 1 1
+136 1 0
+556 1 1
+17 1 1
+463 6 8
+803 35 35
+170 1 0
+28 1 1
+454 9 9
+450 1 1
+34 1 1
+728 12 13
+1023 0 3
+204 1 1
+33 1 1
+322 1 1
+35 5 0
+147 1 1
+6 1 0
+107 1 1
+442 1 1
+44 1 1
+407 1 0
+1683 1 5
+53 1 1
+1265 1 0
+209 1 1
+28 1 1
+92 1 1
+44 1 1
+671 1 1
+42 0 2
+39 1 1
+74 1 1
+67 1 1
+854 0 30
+676 2 0
+33 0 1
+145 1 1
+48 1 1
+261 3 0
+166 1 1
+24 0 1
+311 1 1
+76 1 1
+893 1 1
+39 1 1
+65 1 0
+1321 1 1
+31 1 1
+316 0 14
+78 9 9
+2264 1 1
+20 1 1
+777 1 2
+274 0 1
+1285 0 11
+500 1 1
+24 1 1
+107 0 3
+77 1 1
+76 1 1
+1414 5 5
+54 37 0
+421 8 8
+150 1 1
+71 1 1
+128 0 1
+514 75 0
+116 1 0
+201 1 1
+17 0 1
+1181 1 1
+30 1 1
+131 12 12
+386 0 1
+351 3 3
+6 4 0
+14 0 1
+48 1 1
+1034 0 4
+789 2 0
+76 1 1
+29 1 1
+691 1 1
+65 1 1
+1723 4 4
+22 1 1
+2576 1 3
+235 1 1
+35 1 1
+52 70 144
+15 1 3
+5 1 0
+51 1 3
+6 3 0
+6 1 0
+4 1 0
+8 0 2
+15 1 0
+8 2 1
+20 1 0
+7 130 13
+22 2 0
+22 2 0
+17 43 281
+23 6 0
+1593 1 1
+35 1 1
+171 0 1
+670 1 1
+20 1 1
+283 1 1
+24 1 1
+448 1 1
+18 1 1
+78 11 0
+46 1 1
+652 1 1
+30 1 1
+333 1 1
+56 1 1
+1209 22 44
+88 1 1
+21 1 1
+908 7 10
+114 26 26
+791 6 6
+286 1 1
+40 1 1
+623 4 0
+430 0 1
+423 8 8
+115 1 1
+23 1 1
+215 11 0
+27 0 5
+797 4 0
+95 15 15
+148 1 1
+141 2 0
+60 1 1
+692 1 0
+91 1 1
+31 1 1
+116 1 1
+24 1 1
+56 1 1
+99 3 0
+101 8 0
+273 1 1
+47 1 1
+1276 14 13
+169 1 1
+40 3 0
+119 1 1
+45 1 1
+466 1 1
+21 1 1
+572 8 8
+247 0 1
+290 0 1
+573 1 1
+27 1 1
+333 47 47
+2439 23 25
+654 1 1
+46 1 1
+78 8 8
+569 1 1
+57 1 1
+666 0 1
+502 1 1
+20 1 1
+347 9 9
+358 0 2
+13 1 1
+148 2 0
+134 1 1
+809 1 1
+47 1 1
+442 1 1
+43 1 1
+308 1 1
+54 1 1
+48 0 2
+152 5 0
+1137 1 1
+27 0 11
+575 1 0
+189 18 18
+490 25 25
+165 1 1
+26 1 1
+241 0 6
+75 1 1
+162 1 1
+1156 0 7
+248 0 4
+972 8 7
+177 0 1
+50 1 1
+1385 1 1
+30 1 1
+1048 1 1
+44 1 17
+690 6 7
+295 1 1
+36 1 1
+519 1 1
+26 1 1
+352 8 8
+204 1 1
+38 1 1
+580 7 7
+888 54 54
+183 18 18
+2465 16 16
+1454 10 10
+352 1 1
+49 1 1
+176 1 1
+32 11 11
+1717 1 1
+37 1 1
+127 1 1
+44 1 1
+275 1 1
+21 1 1
+349 9 9
+1977 1 1
+78 0 1
+8 0 1
+144 0 1
+335 46 46
+79 0 6
+10 1 1
+137 12 0
+99 1 1
+44 5 13
+31 1 1
+416 0 1
+177 0 6
+19 1 1
+372 2 2
+55 1 1
+256 0 6
+313 1 1
+43 1 1
+79 1 1
+20 1 1
+120 1 1
+38 0 8
+880 1 1
+24 1 1
+921 1 1
+40 1 1
+1358 0 4
+56 1 1
+1282 1 1
+34 1 1
+262 1 1
+43 1 1
+158 1 1
+33 1 1
+637 0 4
+1310 1 1
+26 1 1
+544 32 32
+496 1 1
+48 1 1
+3097 2 0
+145 1 1
+32 1 1
+152 0 3
+1117 1 1
+31 6 6
+416 1 1
+37 1 1
+293 0 14
+66 1 1
+48 1 1
+371 1 1
+41 1 1
+639 1 1
+49 1 1
+2092 10 13
+381 1 1
+39 5 5
+995 15 15
+165 0 12
+536 1 1
+43 1 1
+295 1 1
+35 1 1
+171 9 8
+831 20 20
+1980 12 0
+31 1 1
+389 1 1
+32 1 1
+414 20 0
+97 0 1
+835 6 0
+4305 1 1
+37 1 1
+191 1 1
+16 1 1
+227 1 1
+61 1 1
+257 1 1
+35 1 1
+946 1 1
+29 1 1
+710 1 1
+56 1 1
+534 2 0
+439 1 1
+58 1 1
+69 3 3
+43 1 1
+193 1 1
+15 1 1
+1032 1 4
+884 1 1
+30 1 1
+202 1 1
+43 1 1
+171 0 4
+163 0 1
+128 1 1
+43 1 1
+52 1 1
+20 1 1
+818 1 1
+45 1 1
+54 1 1
+42 1 1
+122 1 1
+28 1 1
+329 1 0
+163 1 1
+17 1 1
+442 1 1
+61 1 0
+695 0 1
+13 1 7
+54 1 1
+553 0 14
+360 5 5
+11641 3 7
+7822 1 0
+4105 0 8
+5193 0 1
+516 1 0
+3576 3 0
+825 1 1
+40 1 1
+738 1 1
+18 1 1
+989 0 5
+579 1 1
+19 1 1
+337 1 1
+42 55 0
+726 1 1
+99 1 2
+32 1 1
+932 1 1
+33 1 1
+234 33 33
+1101 1 1
+23 1 1
+345 0 1
+30 1 1
+111 17 17
+1395 1 0
+243 1 1
+29 4 5
+881 2 0
+465 0 1
+165 1 1
+87 1 1
+565 1 1
+10 1 1
+102 9 10
+176 1 1
+48 1 1
+499 1 1
+43 1 1
+263 0 8
+427 2 0
+75 1 1
+2053 1 1
+63 1 1
+744 32 32
+1706 1 1
+31 1 1
+829 12 0
+258 0 2
+433 1 1
+70 1 1
+137 2 0
+45 1 1
+664 11 11
+844 0 1
+440 1 1
+41 1 1
+760 1 6
+39 15 0
+757 1 1
+23 1 1
+137 1 1
+32 1 1
+246 9 9
+549 3 0
+1242 6 1
+200 1 0
+2306 1 1
+29 1 1
+197 2 0
+24 1 1
+1224 0 124
+61 1 1
+64 1 1
+3131 1 1
+116 1 1
+146 1 1
+34 1 1
+51 0 1
+805 1 1
+45 1 1
+579 15 15
+134 9 9
+1033 1 5
+147 1 1
+33 1 1
+118 29 29
+311 10 10
+1107 4 4
+3165 0 1
+122 1 1
+64 0 2
+29 1 1
+437 1 1
+39 1 1
+215 1 1
+78 1 1
+1953 3 3
+49 1 1
+745 1 1
+38 1 1
+881 0 4
+562 0 1
+956 1 1
+44 1 1
+685 1 1
+84 1 1
+380 1 1
+40 1 1
+182 0 4
+40 1 1
+877 13 13
+157 1 1
+50 1 1
+1282 0 1
+1612 17 37
+772 1 1
+70 1 1
+1866 0 2
+1406 16 15
+1398 1 0
+1112 1 1
+77 1 1
+1374 7 7
+751 5 5
+14 1 1
+239 6 6
+12 1 1
+189 0 1
+38 1 1
+144 1 1
+40 1 1
+1200 0 1
+758 0 1
+338 18 0
+15 10 0
+187 1 1
+90 1 1
+76 0 6
+611 6 131
+44 1 1
+221 5 0
+460 64 64
+488 15 15
+262 1 1
+45 1 1
+848 4 0
+75 8 8
+52 1 1
+31 1 1
+226 10 10
+437 1 1
+67 1 1
+115 1 1
+62 1 1
+60 13 13
+721 2 0
+164 1 1
+44 1 1
+395 1 1
+33 1 1
+260 13 13
+283 10 18
+600 1 1
+28 1 1
+100 18 18
+229 1 1
+47 1 1
+1672 1 1
+21 1 1
+1571 12 9
+101 1 1
+58 1 1
+706 11 11
+627 1 1
+16 1 1
+864 16 16
+200 1 1
+36 1 1
+676 1 1
+51 5 0
+2069 1 1
+32 1 1
+584 7 0
+271 1 1
+15 1 1
+435 0 1
+312 1 1
+38 0 3
+80 1 1
+32 0 12
+91 1 1
+34 1 1
+131 1 1
+35 1 1
+754 1 1
+44 2 2
+132 2 9
+174 3 1
+53 1 1
+213 2 0
+937 0 3
+720 1 1
+48 0 2
+32 12 0
+155 38 42
+692 9 2
+399 1 1
+54 0 1
+2625 1 1
+26 1 1
+584 0 5
+505 1 1
+43 1 1
+549 1 1
+23 1 1
+69 8 9
+123 1 1
+33 1 1
+651 1 1
+41 1 1
+141 4 4
+408 1 1
+30 1 1
+690 2 1
+78 4 4
+2106 8 4
+245 0 16
+802 1 1
+38 1 1
+607 1 1
+56 1 1
+358 0 1
+192 1 1
+45 1 1
+373 1 1
+82 1 1
+720 0 1
+161 1 1
+21 1 1
+187 7 6
+184 8 8
+760 6 6
+527 14 14
+94 4 4
+44 1 1
+455 7 0
+48 1 1
+89 1 1
+27 0 4
+38 1 1
+1571 1 1
+47 1 1
+81 1 1
+35 1 1
+161 4 0
+1244 0 2
+82 1 1
+67 0 4
+202 8 8
+351 9 9
+2130 1 0
+82 11 0
+397 0 1
+37 1 0
+315 1 1
+22 1 1
+1212 1 1
+60 1 1
+1847 1 1
+54 1 1
+362 7 7
+1065 3 0
+422 0 1
+3143 1 1
+33 1 1
+552 0 1
+822 1 0
+493 0 4
+26 1 1
+2435 1 1
+48 1 1
+3350 1 1
+17 1 1
+953 86 87
+509 0 1
+1811 1 1
+58 1 1
+1200 1 1
+55 4 0
+863 0 1
+284 1 1
+47 1 1
+2795 15 15
+2326 31 30
+2510 0 8
+1829 1 1
+40 1 1
+3584 58 90
+1937 29 28
+3805 14 14
+477 1 1
+25 1 1
+529 0 1
+918 1 2
+461 5 5
+102 9 10
+3603 18 18
+790 1 0
+797 881 2
+226 10 10
+52 4 4
+40 1 1
+128 5 5
+28 1 1
+50 14 11
+53 2 1
+1451 2 1
+119 1 1
+68 1 1
+164 0 2
+1257 1 1
+12 1 0
+42 1 1
+882 1 1
+47 1 1
+274 16 16
+82 1 1
+63 1 1
+100 11 11
+581 0 1
+60 1 1
+464 1 1
+29 1 0
+5 13 0
+23 1 1
+286 1 1
+38 0 2
+17 0 5
+108 6 0
+73 7 6
+105 1 1
+72 1 1
+115 1 1
+37 1 1
+86 1 1
+34 1 1
+143 28 25
+572 4 1
+114 3 0
+134 57 56
+836 0 1
+39 1 1
+1284 0 3
+858 2 1
+42 1 1
+795 1 0
+105 1 0
+343 3 0
+1040 0 3
+548 1 1
+67 1 1
+206 6 14
+830 0 1
+1490 10 10
+139 1 1
+29 0 1
+236 6 4
+217 1 1
+48 1 1
+578 0 1
+165 1 0
+59 9 9
+113 1 2
+294 0 3
+41 0 2
+126 1 1
+29 1 1
+393 7 7
+791 1 1
+51 1 0
+30 1 1
+110 21 11
+57 1 1
+64 1 1
+68 3 3
+58 1 1
+52 9 9
+63 1 1
+85 1 1
+72 1 1
+32 1 1
+315 13 13
+138 1 0
+1106 8 4
+923 12 12
+1310 1 0
+20 1 1
+307 18 15
+995 9 9
+71 1 1
+71 1 1
+85 6 1
+202 1 1
+57 1 1
+483 1 1
+57 1 2
+185 1 1
+17 1 1
+129 1 1
+34 0 2
+179 8 10
+175 1 1
+102 1 1
+154 220 220
+71 1 1
+62 1 1
+60 1 1
+164 7 7
+126 1 1
+19 1 1
+118 13 13
+126 1 1
+53 1 1
+67 4 4
+42 7 7
+54 1 1
+51 1 1
+139 13 14
+96 1 1
+19 1 1
+163 1 1
+33 1 1
+309 0 18
+38 1 1
+318 3 0
+70 4 0
+203 3 3
+30 1 1
+606 1 1
+22 1 0
+209 0 1
+520 1 0
+415 1 1
+51 1 1
+367 5 1
+16 0 8
+137 6 3
+290 0 4
+157 1 1
+79 1 1
+275 1 1
+14 4 0
+69 1 1
+215 1 1
+7 1 0
+7 1 4
+33 1 1
+169 1 1
+101 1 1
+78 1 1
+41 3 3
+364 0 2
+577 34 29
+268 60 60
+60 47 47
+133 8 8
+68 2 0
+172 2 3
+162 30 30
+186 3 8
+235 58 58
+64 16 12
+138 24 17
+112 246 235
+51 56 56
+146 18 18
+206 49 49
+267 18 18
+152 1 1
+18 1 1
+63 13 1
+235 6 5
+209 1 1
+24 4 0
+53 1 1
+73 29409 0
+126 1 1
+85 1 1
+76 3 3
+159 1 0
+29 11 11
+72 8 8
+496 9 9
+202 1 1
+90 1 1
+692 1 1
+27 1 1
+111 0 10
+89 1 1
+33 1 1
+153 3268 0
+205 0 3
+50 3 0
+605 6 6
+59 16 16
+136 1 1
+28 1 1
+417 1 1
+17 1 1
+70 10 10
+259 1 1
+37 0 1
+352 1 1
+40 1 1
+814 1 1
+80 1 1
+125 11 11
+137 1 1
+82 1 1
+408 1 1
+56 1 1
+367 1 0
+26 1 1
+390 185277 11600
+75 2 0
+81 1 1
+175 1 1
+23 1 1
+56 1 1
+37 3 0
+55 1 1
+248 3 0
+74 2 0
+139 1 1
+26 1 1
+131 1 1
+32 5 9
+246 3 5
+53 0 4
+22 5 0
+71 0 1
+255 1 1
+189 1 1
+121 1 1
+149 1 1
+65 1 1
+322 1 1
+36 17 5
+27 4 0
+39 1 1
+346 15 1
+48 0 1
+148 1 1
+57 1 1
+38 1 1
+653 1 0
+213 1 1
+35 1 1
+60 1 1
+72 1 1
+71 6 6
+76 1 1
+73 5 5
+114 1 1
+92 1 1
+145 1 1
+108 1 1
+54 0 2
+82 11 11
+303 0 4
+149 23 23
+57 1 1
+57 1 1
+485 1 1
+64 1 1
+112 1 1
+19 1 1
+226 1 1
+70 0 1
+83 1 1
+60 1 0
+28 1 1
+1629 34 1
+5621 0 12
+37 1 1
+1691 14 14
+151 10 10
+58 1 1
+91 0 2
+149 1 1
+57 1 1
+72 1 1
+932 1 1
+21 1 1
+732 1 1
+24 1 1
+438 1 1
+17 1 1
+1100 146 145
+189 18 18
+1079 1 1
+37 1 1
+69 10 1
+241 1 1
+23 1 1
+247 1 1
+48 1 1
+3441 1 1
+18 1 1
+491 0 1
+250 12 8
+108 1 1
+37 1 2
+339 1 1
+36 1 1
+1289 4 4
+406 9 9
+579 1 1
+37 1 1
+282 2 0
+6 12 0
+42 1 1
+55 1 1
+36 1 1
+396 54 54
+1355 2 0
+101 0 1
+149 1 1
+25 1 1
+611 1 1
+60 1 1
+224 20 0
+60 1 1
+398 0 2
+819 1 1
+48 1 1
+233 1 0
+459 6 6
+1131 10 10
+129 791 450
+41 119 117
+102 14 24
+16 1 1
+379 11 10
+240 1 1
+49 1 1
+203 1 1
+96 1 1
+50 896 15
+110 1 1
+59 1 1
+387 10 10
+157 1 1
+126 1 1
+60 1 1
+86 1 1
+124 1 1
+118 1 1
+160 3 1
+82 1 1
+64 0 1
+59 1 1
+235 1 1
+43 1 1
+126 45 34
+50 0 27
+37 0 2
+74 1 1
+69 13484 10061
+60 44 44
+112 244 248
+256 4076 10878
+54 1 1
+18 0 1
+10 1 1
+76 1 1
+36 1 1
+130 1 1
+25 1 1
+85 2 2
+21 1 0
+67 1 1
+32 1 1
+162 1 1
+23 1 1
+453 10 10
+396 5 0
+82 1 1
+397 0 1
+89 3 0
+40 1 1
+157 1 1
+43 0 8
+146 1 1
+38 1 1
+101 1 1
+33 7 1
+53 1 1
+41 1 1
+60 25 18
+60 1 1
+25 1 1
+80 1 1
+31 1 1
+88 8 7
+24 1 1
+417 0 1
+42 1 1
+122 1 1
+72 5 5
+88 1 1
+36 1 1
+495 14 14
+278 3 3
+48 1 1
+50 11 0
+147 1 1
+87 1 1
+67 1 1
+788 8 0
+51 1 1
+37 1 1
+107 1 1
+22 1 1
+290 1 0
+58 3 3
+804 12 12
+133 5 0
+34 0 8
+116 1 1
+592 112 115
+93 0 1
+84 1 1
+22 1 1
+188 1 1
+46 1 0
+10 1 0
+375 6 6
+117
+
+chain 13264711 chr17_ctg5_hap1 1680828 + 0 1680828 chr17 78774742 + 40740646 42268630 76
+1491 0 1
+105829 1 0
+7 1 0
+38 1 0
+39 0 3
+1127 2 0
+399 1 1
+36 1 1
+1284 2 0
+96 1 1
+18 1 1
+402 0 1
+1243 1 17
+1187 1 1
+93 2 2
+135 1 0
+1300 1 0
+970 1 1
+33 1 1
+1390 1 1
+32 0 1
+1238 11 11
+1231 1 0
+4784 7 7
+1610 0 43
+312 0 20
+4544 1 1
+80 1 1
+5233 1 1
+31 1 1
+1582 0 4
+606 1 0
+1781 1 0
+183 14 16
+1226 6 0
+3095 1 1
+81 1 1
+4769 1 0
+4452 3 3
+41 1 1
+1401 1 1
+34 1 1
+1154 1 1
+28 1 1
+2549 12 12
+2173 2 0
+2280 1 1
+38 1 3
+2217 0 1
+498 0 1
+93 1 1
+22 1 1
+1950 0 2
+66 0 2
+1228 8 5
+1593 0 1
+468 1 1
+21 0 1
+170 10 0
+794 0 8
+1870 8 2
+3575 2 2
+43 1 1
+244 13 13
+611 5 5
+4057 4 1
+721 0 1
+1373 0 3
+28 1 1
+1422 1 0
+788 2 0
+584 188 188
+30 1152 1152
+40 270 270
+53 62 62
+87 227791 12647
+23 8319 12304
+52 449 449
+41 17972 13320
+26 114 119
+50 2682 2667
+31 1087 1088
+42 10911 10903
+41 76 76
+35 287 287
+93 1272 1285
+4834 34 1
+1629 1 1
+28 0 1
+59 1 1
+83 0 1
+25 1 1
+271 1 1
+19 1 1
+112 1 1
+64 1 1
+485 1 1
+57 1 1
+57 23 23
+144 0 4
+308 11 11
+82 0 2
+54 1 1
+70 1 1
+37 1 1
+145 1 1
+92 1 1
+114 5 5
+73 1 1
+76 6 6
+71 1 1
+72 1 1
+60 1 1
+35 1 1
+208 1 0
+658 1 1
+38 1 1
+57 1 1
+148 0 1
+48 14 1
+238 1 1
+34 1 1
+72 1 1
+39 4 0
+27 17 5
+36 1 1
+322 1 1
+65 1 1
+149 1 1
+121 1 1
+189 14 14
+54 1 1
+187 0 1
+71 5 0
+22 0 4
+53 3 5
+246 5 9
+32 1 1
+131 1 1
+26 1 1
+139 2 0
+74 3 0
+248 1 1
+70 3 0
+22 1 1
+56 1 1
+23 1 1
+175 1 1
+81 2 0
+75 32 32
+220 14 13
+196 178 178
+126 28 22
+332 8 8
+98 35 35
+82 0 1
+246 10 10
+80 24 21
+105 4 4
+104 18 20
+52 22 22
+224 6 6
+62 174 173
+149 6 9
+188 4 0
+164 0 1
+157 1 1
+264 8 0
+51 0 1
+5 0 1
+5 1 0
+32 1 1
+262 1 1
+42 1 1
+59 1 1
+68 1 1
+277 1 1
+48 1 1
+52 1 1
+30 4 4
+92 1 1
+40 1 1
+164 1 1
+34 1 1
+249 5 5
+70 5 5
+145 1 1
+55 1 1
+56 0 1
+38 1 1
+96 0 3
+143 1 1
+146 1 1
+158 15 15
+775 8 0
+80 1 1
+38 1 1
+556 1 1
+44 1 1
+79 1 0
+44 1 1
+86 4 4
+121 1 1
+13 0 1
+13 1 1
+203 1 1
+44 1 1
+567 1 0
+384 1 1
+43 1 1
+576 0 2
+167 1 1
+698 1 1
+41 1 1
+207 2 0
+342 0 1
+113 1 1
+595 13 13
+666 1 1
+19 1 1
+471 1 1
+25 1 1
+327 1 1
+36 1 1
+549 0 16
+83 17 17
+149 1 1
+40 1 1
+206 1 1
+48 1 1
+96 0 1
+87 1 1
+83 1 1
+130 1 1
+350 1 1
+17 1 1
+141 1 1
+45 1 0
+210 0 4
+428 13 13
+135 1 0
+555 8 0
+29 1 1
+108 1 1
+67 1 1
+481 2 0
+575 4 4
+10 0 3
+28 1 1
+55 4 4
+125 0 9
+59 3 3
+73 8 8
+146 1 1
+203 1 1
+132 1 1
+71 48592 13305
+71 3382 3374
+25 5834 5854
+89 1 1
+9 10000 10418
+20 1 1
+40 0 4
+13 1 1
+3 602540 600615
+450 1 1
+71 1 1
+126 4 0
+131 2 2
+95 7526 7516
+28 827 819
+39 10 10
+8 19785 19984
+220 7353 7908
+33 269 269
+60 61 61
+46 547 550
+30 424 423
+57 355 353
+45 1 1
+108 46 38
+46 51 51
+56 371 371
+48 1139 1133
+154 7 7
+118 1 1
+28 1 1
+69 1 1
+80 2 1
+56 0 3
+50 1 1
+40 1 1
+47 0 1
+176 8 8
+35 1 1
+86 1 1
+19 0 7
+57 1 1
+179 1 1
+53 1 1
+64 1 1
+39 1 1
+93 2 2
+138 0 2
+402 3 5
+350 1 1
+18 1 1
+413 8 4
+297 7 0
+273 5 0
+96 1 1
+17 1 1
+241 0 1
+593 4 0
+50 1 1
+179 30 0
+8 0 2
+6 0 1
+27 6 0
+7 1 15
+77 51 25
+119 16 15
+89 1 1
+36 5 5
+156 23 23
+66 1 1
+20 1 1
+785 62 62
+118 1 1
+97 1 1
+84 1 1
+53 2 2
+141 0 12
+60 1 1
+47 1 1
+67 1 1
+61 1 1
+61 2 0
+64 1 1
+160 1 12
+1118 3 3
+54 9 31
+96 1 1
+20 1 1
+55 1 1
+23 1 1
+260 12 12
+134 13 13
+447 5 5
+659 1 1
+76 1 1
+57 1 1
+30 1 1
+150 11 0
+11 3 0
+85 1 1
+82 0 3
+128 1 1
+83 1 1
+35 0 2
+17 1 1
+157 0 1
+5 0 2
+14 3 3
+177 1 1
+32 1 1
+355 1 1
+25 1 0
+26 0 2
+77 1 1
+31 1 1
+190 1 1
+34 1 1
+77 15 15
+79 12 14
+200 17 17
+721 1 1
+35 1 1
+247 1 1
+44 1 1
+107 1 1
+52 1 1
+391 19 23
+467 18 19
+535 1 1
+30 1 1
+54 1 2
+55 3 3
+22 2 2
+348 1 1
+34 1 1
+429 4 0
+66 8 8
+298 1 1
+56 1 1
+316 5 5
+71 1 1
+11 10 0
+31 12 0
+90 1 1
+16 1 4457
+76 1 1
+48 1 1
+66 4 5
+164 1 0
+354 1 1
+46 1 1
+779 19 19
+189 1 1
+45 1 1
+477 9 9
+180 1 0
+305 1 1
+20 1 1
+247 9 10
+131 5 5
+1115 1 1
+43 1 1
+98 0 1
+27 1 1
+152 15 15
+295 1 1
+18 1 1
+110 1 1
+49 1 1
+129 1 1
+34 1 1
+93 1 1
+91 1 1
+318 6 6
+112 4 4
+31 7 0
+150 0 2
+130 1 1
+19 1 1
+747 8 8
+708 9 9
+295 0 1
+25 1 1
+320 1 1
+26 1 1
+302 1 0
+45 15 0
+14 1 1
+75 1 1
+26 1 1
+494 1 1
+19 1 1
+267 11 11
+95 1 1
+15 4 0
+84 7 7
+87 206984 212276
+34 11226 11239
+62 1 1
+82 9866 9856
+54 5848 5823
+791 41 41
+31 1 1
+47 1 1
+39 1165 1166
+864 1 1
+31 2021 2021
+8 0 8
+37 259 273
+434 1 0
+1376 9 7
+578 14 5
+814 6 5
+638 0 1
+416 1 1
+49 1 1
+5436 0 6
+3224 0 1
+352 1 1
+31 10 0
+65 60 60
+44 112 112
+244 256 256
+1152 1 0
+773 0 5
+2150 2914 2914
+7 0 1
+18 5377 5375
+112 946 946
+2705 0 2
+1072 1 1
+30 1 1
+126 0 1
+1278 0 2
+1963 1 0
+706 0 9
+89 1 29
+428 0 3
+306 0 14
+149 1 1
+22 1 1
+1153 1 0
+877 14 12
+1014 1 1
+49 1 1
+3485 1 0
+2740 1 1
+27 4 0
+238 1 1
+48 1 1
+385 6 0
+1355 1 1
+27 2 2
+1020 10 0
+2311 0 2
+646 0 2
+8446 1 0
+1582 3 4
+2031 1 0
+1347 0 4
+939 1 1
+82 1 1
+2216 0 12
+806 0 4
+3009 7 0
+73 1 1
+37 1 1
+88 79 85
+2100 2 0
+804 1 1
+31 1 1
+56 1 0
+531 0 1
+3255 0 17
+119 16 16
+2727 0 5
+1516 1 0
+88 1 1
+31 1 1
+2085 0 1
+2381 3 0
+988 0 1
+1138 2 2
+37 1 1
+3015 12 0
+3465 1 1
+30 1 1
+1220 54 43
+3519 0 1
+4735 1 0
+1246 0 4
+257 1 0
+919 0 5
+811 53 53
+5990 0 1
+369 0 4
+1080 50000 139273
+41860
+
+chain 2227376 chr17_ctg5_hap1 1680828 + 1397503 1425444 chr17 78774742 + 41665512 41694673 1168
+810 6 0
+20 1 0
+396 1 0
+77 1 1
+160 1 1
+198 18 18
+170 1 0
+835 7 0
+178 0 1
+512 1 1
+18 0 1
+91 1 1
+41 5 4
+205 1 1
+46 1 1
+313 1 0
+195 1 1
+34 1 1
+81 114 114
+158 1 1
+29 5 0
+216 7 0
+202 0 724
+357 0 2
+36 1 1
+281 25 26
+94 1 1
+45 1 0
+56 1 1
+102 5 0
+286 8 9
+1295 1 1
+110 1 1
+117 0 5
+157 16 16
+272 1 1
+26 2 0
+277 6 6
+193 4 4
+153 1 9
+20 1 1
+1068 8 4
+216 2 0
+224 9 0
+383 21 0
+79 1 1
+361 1 1
+25 1 1
+1006 1 1
+62 1 1
+60 15 15
+107 12 14
+73 0 3
+33 0 4
+890 73 73
+139 0 5
+826 5 0
+366 0 2
+187 0 2
+175 146 146
+739 20 20
+205 13 13
+355 45 45
+160 0 1
+617 0 15
+366 28 27
+202 111 110
+154 52 52
+368 997 1615
+183 2 2
+449 4 0
+108 17 0
+162 0 2
+93 1 1
+31 0 1
+149 9 9
+69 11 11
+275 1 1
+14 0 4
+120 1 1
+115 1 1
+76 2 1
+121 1 1
+72 1 1
+88 3 3
+68 1 1
+96 57 1
+229 1 1
+21 0 1
+25 2 0
+112 2 2
+84 5 0
+75 3 3
+171 66 65
+113 18 18
+348 81 73
+67 44 44
+67 16 19
+149 0 3
+72 36 36
+123 92 91
+67 297 297
+178 433 428
+365 20 20
+130 51 51
+302 17 17
+62 20 20
+316 1 0
+138 37 25
+75 5 9
+267 7 7
+118 30 30
+69 92 92
+99 42 42
+47 0 1
+113
+
+chain 1902497 chr17_ctg5_hap1 1680828 + 1349157 1369929 chr17 78774742 - 37173234 37193985 1316
+1852 2 0
+9 8 8
+283 11 0
+34 0 1
+190 1 0
+3 2 0
+457 2 0
+106 1 1
+28 1 1
+144 4 0
+2112 6 6
+1530 1 1
+27 1 1
+123 1 0
+171 0 8
+504 5 6
+2360 1 1
+19 1 0
+1463 10 0
+471 36 36
+785 32 32
+412 0 3
+1217 32 32
+1308 28 26
+1339 13 13
+311 29 33
+733 22 22
+62 2 0
+251 11 11
+799 0 7
+97 3 0
+324 4 0
+473 46 46
+459
+
+chain 1776951 chr17_ctg5_hap1 1680828 + 1329556 1349123 chr17 78774742 - 37153638 37173199 1401
+128 0 1
+918 0 1
+530 2 0
+20 1 1
+129 1 0
+249 0 1
+279 4 0
+12 4 0
+26 4 0
+614 16 16
+179 4 0
+610 2 0
+646 28 35
+276 0 1
+1341 1 0
+360 1 1
+39 1 1
+467 1 1
+23 1 1
+633 6 6
+309 1 1
+27 0 2
+627 5 0
+1032 8 8
+226 1 1
+17 1 1
+385 5 4
+125 22 23
+301 14 0
+199 1 1
+26 1 1
+53 1 1
+33 1 1
+304 3 0
+1345 0 16
+944 72 72
+115 82 91
+248 14 14
+558 0 1
+750 1 0
+1083 69 69
+1136 0 2
+82 22 16
+836 0 4
+926
+
+chain 893264 chr17_ctg5_hap1 1680828 + 1372124 1381789 chr17 78774742 - 37196506 37206183 4351
+35 1 1
+343 27 25
+861 0 10
+298 0 4
+92 6 6
+784 0 5
+2089 1 0
+940 1 0
+304 2 0
+1246 1 0
+168 2 0
+171 1 0
+32 1 1
+1110 14 14
+833 0 4
+155 1 0
+146
+
+chain 666279 chr17_ctg5_hap1 1680828 + 1381822 1393172 chr17 78774742 + 60348942 60360296 7820
+119 36 36
+84 52 49
+205 29 29
+190 52 58
+180 57 57
+51 14 14
+312 54 54
+55 16 16
+52 88 88
+203 0 5
+250 22 25
+110 147 149
+328 217 214
+84 88 88
+79 39 39
+231 67 53
+89 16 17
+62 15 15
+187 47 51
+315 45 45
+78 214 214
+360 182 184
+116 67 67
+75 70 75
+106 18 20
+98 95 95
+54 19 19
+292 76 76
+171 87 87
+338 28 28
+98 78 75
+53 77 77
+51 62 62
+118 32 32
+192 39 39
+52 62 62
+175 44 44
+195 97 97
+75 173 173
+154 50 50
+125 17 17
+71 57 59
+92 12 12
+303 164 166
+258 424 419
+69 123 123
+345 40 39
+240 14 14
+128 87 86
+73
+
+chain 416007 chr17_ctg5_hap1 1680828 + 1245181 1252036 chr17 78774742 + 60351908 60358760 108741
+51 63 63
+229 10 10
+151 43 37
+58 47 48
+62 20 20
+152 91 97
+163 9 9
+305 11 11
+75 57 57
+75 6 6
+295 59 59
+64 15 17
+160 30 30
+112 70 75
+96 28 30
+98 95 95
+54 63 63
+249 75 75
+324 49 49
+113 42 41
+69 28 28
+98 78 75
+53 77 77
+51 62 62
+342 39 39
+52 62 62
+173 28 28
+82 49 49
+82 94 94
+78 209 203
+52 122 122
+206 100 102
+341 71 71
+53 44 44
+82 29 24
+180
+
+chain 246453 chr17_ctg5_hap1 1680828 + 1237068 1240267 chr9 140273252 + 109577466 109580401 401240
+805 41 1
+100 1 1
+90 49 0
+45 176 0
+349 1 1
+67 1 50
+65 127 0
+114 1 1
+48 1 1
+139 98 1
+58 1 0
+53 1 1
+94 1 178
+186 1 1
+21 2 2
+463
+
+chain 239377 chr17_ctg5_hap1 1680828 + 1312949 1315506 chr17 78774742 - 37137002 37139560 429566
+798 1 0
+565 0 1
+1034 0 1
+159
+
+chain 228096 chr17_ctg5_hap1 1680828 + 1321688 1324178 chr17 78774742 - 37145748 37148235 477585
+1787 39 36
+563 23 23
+78
+
+chain 196783 chr17_ctg5_hap1 1680828 + 1369959 1372123 chr17 78774742 - 37194027 37196505 622087
+666 41 355
+857 1 1
+25 1 1
+573
+
+chain 176658 chr17_ctg5_hap1 1680828 + 1325052 1326989 chr17 78774742 - 37149126 37151061 719570
+150 2 0
+143 37 37
+1605
+
+chain 168141 chr17_ctg5_hap1 1680828 + 711752 714062 chr16 88827254 + 28616023 28618285 762738
+361 1 1
+33 1 1
+130 127 0
+96 1 0
+50 19 19
+119 49 0
+110 1 2
+9 48 0
+90 98 0
+72 11 325
+56 14 14
+246 40 0
+212 17 17
+299
+
+chain 154508 chr17_ctg5_hap1 1680828 + 1307063 1308700 chr17 78774742 - 37131110 37132746 835029
+145 1 0
+1491
+
+chain 148102 chr17_ctg5_hap1 1680828 + 1232106 1430374 chr17 78774742 - 18425735 18434371 621
+4 1 1
+60 1 1
+112 0 1
+97 1 1
+125 2 0
+21 2 2
+61 1 1
+74 1 1
+73 1 1
+34 1 1
+300 1 1
+38 1 1
+80 12 12
+97 8 0
+29 2 2
+185 4 0
+515 2 0
+42 4 4
+430 190939 1320
+75 1 1
+18 1 1
+338 6 6
+61 1 0
+467 12 12
+451 1 0
+100 1 1
+50 1 1
+27 1 1
+132 0 2
+233 1 1
+37 1 1
+50 0 3
+469 1 1
+37 1 1
+94 1 1
+36 1 1
+125 4 4
+132 0 2
+39 1 1
+213 12 12
+184 3 0
+52 1 1
+16 1 1
+159 1 1
+19 2 2
+686 10 10
+230 15 15
+296
+
+chain 145367 chr17_ctg5_hap1 1680828 + 1327932 1329549 chr17 78774742 - 37151994 37153631 887940
+554 56 76
+1007
+
+chain 137569 chr17_ctg5_hap1 1680828 + 1309956 1311426 chr17 78774742 - 37134002 37135486 937317
+68 0 14
+1402
+
+chain 110156 chr17_ctg5_hap1 1680828 + 1320345 1321641 chr17 78774742 - 37144406 37145701 1161060
+640 31 31
+224 12 12
+204 52 51
+133
+
+chain 108079 chr17_ctg5_hap1 1680828 + 1315884 1317028 chr17 78774742 - 37139952 37141098 1182036
+885 0 2
+259
+
+chain 107213 chr17_ctg5_hap1 1680828 + 216004 477608 chr17 78774742 - 36300720 36848371 128
+48 7751 7515
+31 3 3
+10 52129 338773
+71 29976 29992
+37 2872 2872
+132 77377 77001
+50 9950 9939
+49 15970 16004
+80 5205 5206
+35 2373 2374
+35 2111 2102
+28 13945 13928
+281 29828 29826
+34 8713 8715
+32 430 430
+178 126 126
+28 438 438
+35 1039 1039
+174
+
+chain 88256 chr17_ctg5_hap1 1680828 + 1254762 1255800 chr17 78774742 - 37066345 37067387 1434130
+467 19 23
+391 54 54
+107
+
+chain 84535 chr17_ctg5_hap1 1680828 + 1416653 1417623 chr17 78774742 - 37747883 37748853 1275488
+209 0 1
+520 1 0
+240
+
+chain 83787 chr17_ctg5_hap1 1680828 + 1255846 1256794 chr17 78774742 - 37067433 37068381 1508032
+247 37 37
+664
+
+chain 81881 chr17_ctg5_hap1 1680828 + 1394662 1395623 chr17 78774742 - 37062220 37063176 1542051
+178 0 4
+127 43 43
+207 27 18
+379
+
+chain 78522 chr17_ctg5_hap1 1680828 + 1324178 1325052 chr17 78774742 - 37148244 37149121 1606324
+554 0 3
+200 43 43
+77
+
+chain 75262 chr17_ctg5_hap1 1680828 + 1317476 1318285 chr17 78774742 - 37141533 37142347 1673849
+255 0 5
+554
+
+chain 72597 chr17_ctg5_hap1 1680828 + 1318474 1319252 chr17 78774742 - 37142532 37143313 1734349
+618 0 3
+160
+
+chain 68786 chr17_ctg5_hap1 1680828 + 1312168 1312905 chr17 78774742 - 37136222 37136958 1829107
+216 1 0
+520
+
+chain 66138 chr17_ctg5_hap1 1680828 + 458426 496420 chr17 78774742 + 60323662 60348977 381
+29 102 102
+150 0 2
+92 35229 22555
+47 1 1
+72 0 3
+361 0 1
+361 1 1
+59 1 1
+79 1 1
+12 4 0
+22 8 0
+164 1 1
+29 8 0
+22 1 1
+166 1 1
+38 1 1
+167 0 3
+68 1 1
+61 1 1
+34 0 19
+130 1 1
+61 2 2
+22 7 0
+118 7 0
+90 0 1
+162
+
+chain 63091 chr17_ctg5_hap1 1680828 + 1252401 1253149 chr17 78774742 - 37063986 37064734 1993873
+71 5 5
+316 58 58
+298
+
+chain 58162 chr17_ctg5_hap1 1680828 + 1254067 1254744 chr17 78774742 - 37065648 37066326 2166241
+55 1 2
+54 32 32
+535
+
+chain 54716 chr17_ctg5_hap1 1680828 + 1319283 1319868 chr17 78774742 - 37143347 37143930 2309300
+443 2 0
+140
+
+chain 54428 chr17_ctg5_hap1 1680828 + 1396409 1397035 chr17 78774742 - 37063962 37064589 2322100
+416 38 39
+172
+
+chain 53306 chr17_ctg5_hap1 1680828 + 1327031 1327602 chr17 78774742 - 37151103 37151673 2373745
+61 1 0
+509
+
+chain 45719 chr17_ctg5_hap1 1680828 + 1253157 1253656 chr17 78774742 - 37064742 37065237 2803981
+63 4 0
+432
+
+chain 44822 chr17_ctg5_hap1 1680828 + 1308965 1309441 chr17 78774742 - 37133014 37133490 2867866
+476
+
+chain 44716 chr17_ctg5_hap1 1680828 + 1309483 1309955 chr17 78774742 - 37133530 37134002 2875759
+472
+
+chain 42970 chr17_ctg5_hap1 1680828 + 1249019 1250432 chr17 78774742 - 37056169 37057582 957875
+28 98 98
+37 9 10
+32 53 53
+77 51 51
+55 349 348
+39 52 52
+47 9 9
+6 173 173
+28 82 82
+49 82 82
+57
+
+chain 39900 chr17_ctg5_hap1 1680828 + 1311434 1311858 chr17 78774742 - 37135495 37135919 3282293
+424
+
+chain 36548 chr17_ctg5_hap1 1680828 + 1397076 1397503 chr17 78774742 - 37727818 37728245 1867431
+351 31 31
+45
+
+chain 35186 chr17_ctg5_hap1 1680828 + 1319971 1320341 chr17 78774742 - 37144033 37144403 3815477
+370
+
+chain 32846 chr17_ctg5_hap1 1680828 + 1253692 1254040 chr17 78774742 - 37065273 37065621 4148877
+348
+
+chain 32058 chr17_ctg5_hap1 1680828 + 1394126 1394519 chr17 78774742 - 37061682 37062075 4275850
+85 42 42
+266
+
+chain 30381 chr17_ctg5_hap1 1680828 + 343779 344098 chr13 114142980 + 60207729 60208048 4580555
+319
+
+chain 29004 chr17_ctg5_hap1 1680828 + 1317078 1317414 chr17 78774742 - 37141148 37141484 5128137
+110 17 17
+209
+
+chain 28739 chr17_ctg5_hap1 1680828 + 1393298 1393613 chr17 78774742 - 37060859 37061169 5278988
+151 5 0
+159
+
+chain 28608 chr17_ctg5_hap1 1680828 + 1381941 1384110 chr17 78774742 - 37049506 37051670 737272
+33 87 87
+3 16 17
+33 205 205
+29 190 190
+52 180 180
+57 377 361
+54 123 123
+34 639 649
+57
+
+chain 27290 chr17_ctg5_hap1 1680828 + 1250687 1251236 chr17 78774742 - 37057837 37058386 1723424
+69 52 52
+122 206 206
+100
+
+chain 23334 chr17_ctg5_hap1 1680828 + 1315561 1315806 chr17 78774742 - 37139619 37139864 8092879
+245
+
+chain 22172 chr17_ctg5_hap1 1680828 + 1247931 1248795 chr17 78774742 - 37055081 37055945 1359053
+50 54 54
+63 249 249
+75 324 324
+49
+
+chain 21861 chr17_ctg5_hap1 1680828 + 1311933 1312163 chr17 78774742 - 37135987 37136217 9092092
+230
+
+chain 20267 chr17_ctg5_hap1 1680828 + 1388625 1389065 chr17 78774742 - 37056169 37056610 1819714
+28 98 98
+37 9 10
+32 53 53
+77 51 51
+55
+
+chain 19257 chr17_ctg5_hap1 1680828 + 1251577 1252102 chr17 78774742 - 37058727 37059253 2345365
+71 53 53
+44 82 82
+24 1 0
+4 180 182
+66
+
+chain 18858 chr17_ctg5_hap1 1680828 + 1395798 1396023 chr17 78774742 - 37063364 37063589 11391766
+69 17 17
+139
+
+chain 17539 chr17_ctg5_hap1 1680828 + 1306794 1306981 chr17 78774742 - 37130913 37131100 12530835
+187
+
+chain 17362 chr17_ctg5_hap1 1680828 + 1327740 1327921 chr17 78774742 - 37151802 37151983 12688794
+181
+
+chain 16114 chr17_ctg5_hap1 1680828 + 1386775 1387126 chr17 78774742 - 37054317 37054668 3847861
+129 155 155
+67
+
+chain 14712 chr17_ctg5_hap1 1680828 + 1471572 1581528 chr17 78774742 + 41752645 41862594 227
+27 72594 72528
+20 0 36
+59 37204 37227
+3 1 1
+48
+
+chain 14021 chr17_ctg5_hap1 1680828 + 1391766 1393099 chr17 78774742 - 37059329 37060660 1551546
+50 88 88
+58 1094 1092
+43
+
+chain 13718 chr17_ctg5_hap1 1680828 + 1245232 1246117 chr17 78774742 - 37052388 37053271 1534336
+63 390 390
+37 2 0
+4 339 339
+50
+
+chain 13678 chr17_ctg5_hap1 1680828 + 1387543 1388241 chr17 78774742 - 37055086 37055784 1538578
+45 365 365
+76 171 171
+41
+
+chain 13678 chr17_ctg5_hap1 1680828 + 1386064 1386301 chr17 78774742 - 37053606 37053843 4358174
+45 78 78
+49 4 4
+61
+
+chain 12960 chr17_ctg5_hap1 1680828 + 1390153 1390290 chr17 78774742 - 37057697 37057834 10954124
+137
+
+chain 12859 chr17_ctg5_hap1 1680828 + 712690 713529 chr13 114142980 - 94890835 94891950 786174
+26 1 277
+22 258 82
+37 49 0
+12 399 624
+35
+
+chain 11529 chr17_ctg5_hap1 1680828 + 1327611 1327733 chr17 78774742 - 37151673 37151795 19785711
+122
+
+chain 11334 chr17_ctg5_hap1 1680828 + 1238199 1238375 chr13 114142980 + 19251561 19251738 585429
+101 4 5
+56 1 1
+14
+
+chain 11041 chr17_ctg5_hap1 1680828 + 1384528 1384669 chr17 78774742 - 37052089 37052230 4204331
+1 58 58
+82
+
+chain 10878 chr17_ctg5_hap1 1680828 + 1393633 1393747 chr17 78774742 - 37061189 37061303 20959654
+114
+
+chain 10460 chr17_ctg5_hap1 1680828 + 1396115 1396225 chr17 78774742 - 37063682 37063792 21801362
+110
+
+chain 10352 chr17_ctg5_hap1 1680828 + 1391207 1391342 chr17 78774742 - 37058757 37058894 7784932
+37 10 12
+88
+
+chain 9842 chr17_ctg5_hap1 1680828 + 1308830 1308934 chr17 78774742 - 37132877 37132981 23170572
+104
+
+chain 9287 chr17_ctg5_hap1 1680828 + 1318326 1318424 chr17 78774742 - 37142388 37142486 24449821
+98
+
+chain 8968 chr17_ctg5_hap1 1680828 + 1389414 1389567 chr17 78774742 - 37056958 37057111 4148137
+39 52 52
+47 9 9
+6
+
+chain 8877 chr17_ctg5_hap1 1680828 + 1252246 1252339 chr17 78774742 - 37063853 37063946 25134532
+93
+
+chain 8768 chr17_ctg5_hap1 1680828 + 1393172 1393264 chr17 78774742 - 37060733 37060825 25011976
+92
+
+chain 8158 chr17_ctg5_hap1 1680828 + 1393848 1393933 chr17 78774742 - 37061404 37061489 26172124
+85
+
+chain 7594 chr17_ctg5_hap1 1680828 + 1416023 1416258 chr17 78774742 - 37747254 37747489 2219812
+29 154 154
+52
+
+chain 7515 chr17_ctg5_hap1 1680828 + 1389981 1390060 chr17 78774742 - 37057525 37057604 6485868
+79
+
+chain 7285 chr17_ctg5_hap1 1680828 + 1252152 1252228 chr17 78774742 - 37059303 37059379 27632598
+76
+
+chain 6684 chr17_ctg5_hap1 1680828 + 1308721 1308790 chr17 78774742 - 37132768 37132837 28870693
+69
+
+chain 6515 chr17_ctg5_hap1 1680828 + 1247168 1247482 chr17 78774742 - 37054317 37054631 3599890
+45 239 239
+30
+
+chain 6497 chr17_ctg5_hap1 1680828 + 1387201 1387271 chr17 78774742 - 37054743 37054813 5969263
+70
+
+chain 6494 chr17_ctg5_hap1 1680828 + 1396307 1396375 chr17 78774742 - 37063872 37063940 29322189
+68
+
+chain 6058 chr17_ctg5_hap1 1680828 + 1315820 1315884 chr17 78774742 - 37139877 37139941 30402031
+64
+
+chain 5566 chr17_ctg5_hap1 1680828 + 218263 246046 chr17 78774742 + 60300789 60329221 713
+35 27719 28368
+29
+
+chain 5502 chr17_ctg5_hap1 1680828 + 1238858 1238932 chr5 180857866 - 146515862 146515936 441292
+74
+
+chain 5265 chr17_ctg5_hap1 1680828 + 1247608 1247664 chr17 78774742 - 37054757 37054813 15861596
+56
+
+chain 5130 chr17_ctg5_hap1 1680828 + 1393995 1394049 chr17 78774742 - 37061551 37061605 33050310
+54
+
+chain 4602 chr17_ctg5_hap1 1680828 + 1415941 1415989 chr17 78774742 - 37747172 37747220 10895303
+48
+
+chain 4584 chr17_ctg5_hap1 1680828 + 1237882 1239358 chr3 199501827 + 130155920 130156866 476764
+32 1412 882
+32
+
+chain 4558 chr17_ctg5_hap1 1680828 + 1317419 1317468 chr17 78774742 - 37141484 37141533 34680290
+49
+
+chain 4268 chr17_ctg5_hap1 1680828 + 1385266 1385319 chr17 78774742 - 37052825 37052878 8381466
+53
+
+chain 4260 chr17_ctg5_hap1 1680828 + 1246721 1246766 chr17 78774742 - 37053870 37053915 4651304
+45
+
+chain 4113 chr17_ctg5_hap1 1680828 + 1390480 1390530 chr17 78774742 - 37058030 37058080 2324449
+50
+
+chain 4082 chr17_ctg5_hap1 1680828 + 1239288 1239381 chr3 199501827 + 42815100 42815194 539611
+38 32 33
+23
+
+chain 4047 chr17_ctg5_hap1 1680828 + 833483 833530 chr2 242951149 + 222576128 222576175 5745276
+47
+
+chain 4004 chr17_ctg5_hap1 1680828 + 1413149 1413191 chr17 78774742 - 37744368 37744410 15417978
+42
+
+chain 3932 chr17_ctg5_hap1 1680828 + 1246117 1246158 chr17 78774742 - 37053273 37053314 13638111
+41
+
+chain 3773 chr17_ctg5_hap1 1680828 + 1250577 1250669 chr2 242951149 + 55360621 55360713 11417907
+92
+
+chain 3751 chr17_ctg5_hap1 1680828 + 1385702 1385742 chr17 78774742 - 37053251 37053291 3400438
+40
+
+chain 3702 chr17_ctg5_hap1 1680828 + 712859 712906 chr3 199501827 - 151273341 151273388 853543
+47
+
+chain 3381 chr17_ctg5_hap1 1680828 + 713034 713083 chr1 247249719 - 160795106 160795155 805231
+49
+
+chain 3244 chr17_ctg5_hap1 1680828 + 1389742 1389776 chrX 154913754 - 110129876 110129910 25281679
+34
+
+chain 2964 chr17_ctg5_hap1 1680828 + 236048 236081 chr17 78774742 - 37041849 37041882 635
+33
+
+chain 2912 chr17_ctg5_hap1 1680828 + 448843 448913 chr17 78774742 - 36315447 36315517 1328
+70
+
+chain 2802 chr17_ctg5_hap1 1680828 + 1237022 1237068 chr18 76117153 + 50122791 50122837 616904
+46
+
+chain 2574 chr17_ctg5_hap1 1680828 + 1384829 1384856 chr17 78774742 - 37052388 37052415 20977188
+27
+
+chain 2078 chr17_ctg5_hap1 1680828 + 1250433 1250469 chr3 199501827 - 96596057 96596093 10950065
+36
+
+chain 1744 chr17_ctg5_hap1 1680828 + 1238128 1238154 chr10 135374737 + 101842906 101842932 538799
+26
+
+chain 1504 chr17_ctg5_hap1 1680828 + 1238956 1238985 chr16 88827254 + 28335851 28335880 780320
+29
+
+chain 1483 chr17_ctg5_hap1 1680828 + 1250547 1250577 chr19 63811651 + 22556112 22556142 10358829
+30
+
+chain 1204 chr17_ctg5_hap1 1680828 + 1386904 1386940 chr7 158821424 - 133749629 133749665 22723933
+36
+
+chain 996 chr17_ctg5_hap1 1680828 + 535350 535379 chr20 62435964 + 35074223 35074252 2591094
+29
+
+chain 372 chr17_ctg5_hap1 1680828 + 1421954 1423021 chr17 78774742 - 37753177 37754232 1257025
+92 67 67
+4 0 5
+235 1 1
+56 179 175
+23 17 0
+223 1 1
+102 1 5
+66
+
+chain 3524656 chr17_gl000203_random 37498 + 0 37498 chr17_random 2617613 + 1876393 1913891 829
+37498
+
+chain 7797784 chr17_gl000204_random 81310 + 0 81310 chr17_random 2617613 + 2131554 2212864 420
+81310
+
+chain 16543266 chr17_gl000205_random 174588 + 0 174588 chr17_random 2617613 + 0 174588 173
+174588
+
+chain 3927003 chr17_gl000206_random 41001 + 0 41001 chr17_random 2617613 + 2495431 2536432 754
+41001
+
+chain 7055977505 chr18 78077248 + 10000 78016181 chr18 76117153 + 0 76117153 19
+15400898 3100000 1363998
+28218587 15 15
+5329636 150000 47000
+3667310 18 0
+16406889 50000 28008
+3388467 50000 22000
+2103304 0 3
+136125 1 0
+7 1 0
+647 1 0
+1543 1 0
+25 14 8
+19 2 0
+10 7 4
+9 4 2
+663 1 0
+359 1 0
+1617
+
+chain 404699 chr18_gl000207_random 4262 + 0 4262 chr18_random 4262 + 0 4262 116705
+4262
+
+chain 5307806876 chr19 59128983 + 60000 59114839 chr19 63811651 + 11000 63806651 21
+7286004 50000 5000
+1291194 45000 0
+11772188 69160 0
+4058236 3100000 8000000
+20129228 2 0
+701 0 3
+347 1 1
+31 1 1
+1833 0 3
+1984 1 1
+47 1 1
+190 1 1
+34 1 1
+889 2 0
+1413 7 0
+2680 4 0
+375 1 0
+314 4 0
+29 1 0
+69 0 1
+3881 1 1
+40 12 0
+293 14 0
+1479 1 0
+233 1 1
+45 1 1
+1049 1 0
+1766 7 44
+220 0 3
+537 7 0
+351 8 8
+3603 1 1
+17 0 3
+697 0 1
+269 0 3
+974 5 6
+96 10 0
+1096 10 10
+1177 12 14
+1141 9 12
+1090 0 1
+175 16 0
+1063 0 4
+4780 44 44
+722 0 1
+548 2 2
+44 1 1
+424 2 2
+26 1 0
+4 0 1
+82 1 1
+59 1 1
+2087 15 0
+1499 0 1
+1754 0 2
+11209362
+
+chain 1655749 chr19 59128983 + 20505321 20523415 chr19 63811651 + 20366320 20387252 1476
+2041 4 4
+5604 0 2
+363 0 1
+2655 5 2857
+153 46 46
+705 79 83
+370 6 1
+1668 27 26
+347 21 0
+191 6 6
+369 0 2
+393 68 67
+328 0 6
+2049 1 0
+464 35 35
+96
+
+chain 207934 chr19 59128983 + 59114839 59117224 chr22 49691432 + 49588728 49591432 1471
+992 1 1
+63 1 1
+125 152 154
+174 1 1
+47 3 0
+214 5 5
+254 1 1
+67 1 1
+55 1 321
+72 14 14
+142
+
+chain 126422 chr19 59128983 + 59117224 59118680 chr10 135374737 + 135372723 135373917 1944
+177 13 13
+165 1 1
+156 1 1
+205 4 4
+93 1 1
+14 5 0
+88 1 1
+110 1 1
+52 2 1
+28 2 1
+14 255 0
+68
+
+chain 13558 chr19 59128983 + 59116021 59116173 chr2 242951149 - 128870722 128870873 1493
+33 1 0
+24 1 1
+57 1 1
+35
+
+chain 7358 chr19 59128983 + 59118906 59118983 chr21 46944323 + 46944213 46944290 27502546
+77
+
+chain 3811 chr19 59128983 + 20573506 20573546 chr19 63811651 - 43994109 43994149 26416662
+40
+
+chain 174 chr19 59128983 + 47898161 47898204 chr18 76117153 + 27836426 27836469 20429401
+43
+
+chain 8748871 chr19_gl000208_random 92689 + 0 92689 chr19_random 301858 + 0 92689 377
+92689
+
+chain 15150451 chr19_gl000209_random 159169 + 0 159169 chr19_random 301858 + 142689 301858 196
+159169
+
+chain 10110185 chr1_gl000191_random 106433 + 0 106433 chr1_random 1663265 + 1464329 1570762 316
+106433
+
+chain 32373596 chr1_gl000192_random 547496 + 48723 413485 chr16 88827254 + 69402787 69760000 100
+342 1 1
+38 1 1
+638 8 8
+750 11 11
+240 11 11
+1444 1 1
+23 1 1
+1265 0 3
+1506 1 1
+23 1 1
+114 1 1
+80 1 1
+118 1 1
+75 1 1
+311 9 9
+489 1 1
+27 168 14
+109 0 1
+340 5 0
+442 1 0
+25 1 1
+336 0 2
+672 1 1
+21 1 1
+691 1 1
+18 1 1
+144 2 2
+22 1681 0
+79 1 1
+1812 1 1
+31 1 1
+382 0 1
+474 10 9
+280 1 1
+39 0 2
+14 1 1
+103 1 1
+74 1 1
+124 1 1
+39 1 1
+471 1 1
+33 1 1
+653 1 1
+37 1 1
+94 9 10
+195 1 13
+2039 1 0
+1635 1 1
+27 1 0
+301 17 0
+42 1 1
+315 0 1
+384 1 1
+36 0 1
+8 2 0
+1541 11 10
+376 1 1
+36 1 1
+409 1 1
+15 1 1
+547 1 1
+89 1 1
+134 11 11
+161 3 79
+23 0 26
+39 0 1
+6 25 0
+14 1 1
+101 0 9
+94 1 1
+21 1 1
+171 1 1
+81 1 1
+1737 1 1
+27 1 0
+353 1 1
+36 1 1
+470 1 1
+72 1 1
+247 107 107
+709 1 1
+57 1 1
+289 14 14
+296 0 3
+342 1 1
+25 1 1
+184 1 1
+48 1 1
+628 1 1
+50 1 1
+457 0 2
+579 1 1
+21 0 4
+431 0 1
+52 1 1
+45 1 1
+146 1 1
+25 1 0
+26 2 1
+107 1 1
+39 1 0
+72 1 1
+26 1 1
+200 1 1
+19 1 1
+931 1 1
+27 1 1
+386 1 1
+17 1 1
+874 8 8
+146 1 1
+60 1 1
+840 19 19
+63 1 1
+25 1 1
+704 0 1
+721 1 1
+23 1 1
+673 29 14
+370 2 0
+25 1 1
+53 10 10
+591 1 1
+17 1 1
+124 0 1
+373 11 11
+234 12 12
+230 1 1
+31 1 1
+63 0 3
+903 27 28
+874 1 0
+290 11 12
+275 15 15
+290 3 0
+140 1 1
+36 1 1
+99 1 1
+38 1 1
+291 7 7
+1388 8 8
+1013 0 1
+2046 1 2
+423 1 1
+51 1 1
+1534 1 1
+78 1 1
+345 1 1
+37 1 1
+673 16 17
+742 1 1
+41 1 1
+545 1 1
+21 4 4
+387 5 0
+36 1 1
+420 0 28
+640 1 1
+23 1 1
+109 10 10
+1286 1 1
+37 2 2
+294 0 1
+24 1 1
+235 5 8
+223 1 1
+17 1 1
+673 1 1
+22 1 1
+685 10 10
+1762 1 0
+560 1 1
+37 1 1
+279 1 1
+73 1 3
+124 7 8
+495 0 1
+361 0 12
+63 4 0
+127 0 3
+129 0 8
+96 1 1
+34 4 0
+2212 3 0
+954 8 9
+1081 1 1
+45 1 1
+1449 62 57
+910 1 1
+33 1 1
+627 4 0
+933 1 1
+65 0 4
+196 1 1
+198 5 1
+268 1 1
+27 1 1
+994 1 1
+93 1 1
+839 1 1
+31 1 1
+798 0 25
+1007 1 1
+27 0 1
+1076 1 0
+216 0 8
+865 1 1
+61 1 1
+627 9 9
+98 1 1
+25 1 1
+1211 1 1
+61 1 1
+1142 1 1
+37 1 2
+25 1 1
+1594 1 1
+57 1 1
+310 1 1
+21 1 1
+324 3 0
+648 1 1
+44 1 1
+128 1 1
+65 1 1
+1411 1 1
+49 2 2
+563 1 1
+109 1 1
+95 1 1
+16 4 0
+869 1 1
+68 1 1
+178 1 1
+16 1 1
+952 3 0
+206 14 6
+916 10 10
+591 0 1
+240 0 8
+189 0 14
+383 10 10
+242 27 22
+393 310 0
+472 0 1
+364 0 18
+58 1 1
+27 1 1
+40 0 1
+1533 1 24
+460 1 1
+31 1 1
+637 0 5
+63 1 1
+440 8 9
+997 1 1
+25 1 1
+1009 12 12
+317 68 68
+1117 12 8
+97 1 1
+24 1 1
+413 0 1
+1417 1 1
+28 1 1
+165 1 1
+40 1 1
+1132 1 1
+22 1 1
+193 1 1
+124 1 1
+812 1 0
+3002 1 1
+48 1 1
+1345 48 48
+673 4 0
+1213 1 1
+17 1 1
+118 2 2
+33 1 1
+84 13 28
+55 1 1
+34 1 1
+105 1 1
+29 1 1
+348 0 6
+39 0 8
+826 1 1
+26 1 1
+489 25 28
+655 0 1
+179 7 13
+51 1 1
+81 1 1
+24 0 1
+1169 0 1
+178 14 15
+410 1 1
+98 1 1
+90 0 1
+81 1 1
+120 1 1
+57 1 1
+101 11 11
+98 1 1
+16 1 1
+1379 1 1
+106 1 1
+82 1 1
+30 1 1
+85 3 20
+1047 17 17
+780 1 1
+33 1 1
+431 1 1
+62 1 1
+272 1 1
+45 1 1
+363 1 1
+50 1 1
+121 8 1
+188 1 1
+56 1 1
+358 1 1
+36 1 0
+158 0 3
+44 1 0
+253 16 16
+829 1 1
+17 1 1
+78 6 6
+473 1 1
+39 1 1
+92 1 0
+87 1 1
+2589 1 0
+85 13 13
+499 16 20
+512 7 0
+47 1 1
+257 1 1
+32 1 1
+272 14 15
+559 1 1
+25 1 1
+3126 7 4
+461 1 1
+26 1 1
+323 1 1
+30 1 1
+695 0 1
+61 1 1
+178 1 1
+100 0 2095
+496 1 1
+23 1 1
+907 1 1
+35 1 1
+300 1 1
+30 1 1
+215 1 1
+43 1 1
+542 58 58
+88 1 1
+19 1 1
+327 1 1
+61 418 1
+335 0 1
+318 1 1
+45 0 3
+922 15 15
+370 1 1
+20 1 1
+69 0 20
+25 0 4
+32 1 1
+77 7 0
+45 1 1
+3019 34 0
+111 13 13
+514 11 11
+278 1 1
+35 1 1
+462 10 10
+354 0 3
+82 5 1
+366 1 1
+43 1 1
+728 1 1
+51 1 1
+609 1 1
+21 1 1
+428 28 28
+1350 5 5
+737 1 1
+23 1 1
+499 1 1
+21 1 1
+957 3 7
+324 1 2
+466 14 14
+90 8 8
+2017 1 1
+41 1 1
+58 0 2
+498 5 5
+899 1 1
+40 1 1
+62 16 16
+422 0 1
+38 1 1
+264 2 0
+67 1 1
+988 41 41
+267 1 1
+19 1 1
+1598 61 0
+309 1 1
+35 1 1
+469 0 2
+751 0 3
+2839 1 1
+42 1 1
+1760 0 2
+330 1 1
+34 1 1
+561 1 1
+30 1 1
+664 1 1
+79 1 1
+194 67 67
+518 1 1
+29 1 1
+68 1 1
+29 1 1
+615 22 21
+389 0 1
+197 30 0
+271 1 0
+448 1 1
+33 1 1
+839 14 13
+78 1 1
+20 1 1
+331 4 0
+1237 1 1
+40 1 1
+489 1 1
+44 1 0
+303 1 1
+40 1 1
+196 0 1
+129 9 8
+424 1 1
+35 1 1
+852 5 0
+105 1 1
+2114 30 30
+513 1 1
+22 1 1
+56 2 0
+704 1 1
+35 1 1
+427 1 1
+34 0 10
+42 1 0
+294 1 0
+153 9 8
+84 1 1
+45 4 4
+1521 1 1
+29 1 1
+530 1 1
+43 1 1
+894 6127 21
+161 0 4
+175 17 17
+636 12 12
+79 11 11
+69 0 1
+76 1 1
+359 1 1
+31 0 4
+67 1 1
+439 14 14
+343 0 3
+254 0 1
+189 0 1
+35 1 1
+1458 48 48
+1591 14 14
+708 8 8
+976 6 17
+637 1 1
+33 0 1
+956 1 1
+54 1 1
+135 1 1
+23 1 1
+467 1 1
+22 1 1
+87 1 0
+11 1 1
+94 4 0
+684 17 17
+344 1 1
+23 1 1
+1534 1 1
+32 4 0
+245 1 1
+44 1 1
+880 0 5
+105 1 1
+48 1 1
+2535 9 9
+129 0 12
+287 1 1
+46 1 1
+121 1 5
+158 13 14
+80 6 6
+698 5 6
+75 1 1
+43 1 1
+123 1 1
+24 2 7
+58 7 0
+2751 8 8
+528 1 1
+39 1 1
+223 1 0
+912 1 1
+39 0 1
+1215 30 30
+874 1 1
+31 1 1
+113 0 1
+511 1 1
+28 1 1
+291 1 3
+81 1 1
+109 1 1
+152 1 1
+39 10 5
+361 1 1
+31 2 0
+20 1 1
+180 1 1
+109 1 1
+324 1 1
+25 1 1
+539 1 1
+5 2 0
+61 1 1
+395 1 0
+1146 1 1
+45 1 1
+804 1 1
+95 1 1
+856 15 15
+541 322 0
+256 1 1
+23 1 1
+347 1 1
+21 1 1
+332 1 1
+71 1 1
+531 1 0
+488 1 1
+21 0 1
+74 20 19
+517 1 1
+35 1 1
+738 1 1
+41 1 1
+91 3 3
+117 1 1
+85 9 10
+200 6 0
+489 1 1
+271 10 0
+208 1 1
+46 2 2
+708 11 11
+70 1 1
+61 1 0
+88 1 1
+45 1 1
+1206 3 0
+19 1 1
+521 1 1
+25 1 1
+1518 1 1
+42 6 6
+1124 7 8
+53 1 1
+42 1 1
+825 17 17
+825 0 3
+568 1 1
+66 1 1
+394 17 17
+126 1 1
+41 1 1
+577 26 28
+367 12 11
+489 1 1
+65 1 1
+457 1 1
+16 1 1
+350 8 8
+18 4 4
+402 1 0
+103 1 0
+648 1 1
+36 1 1
+446 0 3
+61 16 16
+823 1 1
+32 1 1
+516 1 1
+111 1 1
+1091 1 1
+38 1 1
+49 1 0
+635 0 3
+14 1 1
+153 1 1
+40 1 1
+359 1 1
+35 4 4
+283 2 0
+557 1 1
+19 1 1
+293 3 4
+454 1 1
+70 1 1
+405 0 4
+1613 1 1
+26 13 15
+44 1 1
+458 13 13
+253 0 1
+1200 0 2
+244 1 4
+247 1 1
+38 1 1
+102 0 14
+710 1 1
+20 1 1
+1098 0 4
+200 2 0
+386 0 3
+683 1 1
+26 1 1
+327 4 0
+172 1 1
+311 1 1
+18 1 1
+338 28 28
+420 1 1
+29 1 1
+352 12 12
+301 1 1
+75 1 1
+205 1 0
+250 1 1
+20 1 1
+990 1 1
+20 1 1
+233 0 6
+342 5 9
+156 1 1
+30 1 1
+321 16 16
+420 11 11
+968 3 3
+15 1 1
+162 1 1
+68 1 1
+825 18 18
+153 1 1
+42 1 1
+711 1 1
+20 1 1
+269 1 0
+1414 4 3
+641 9 9
+1000 1 1
+29 1 1
+437 0 6
+45 1 1
+261 1 1
+31 0 2
+168 1 1
+26 1 1
+73 15 7
+29 4 0
+56 1 1
+126 1 1
+32 1 1
+463 6 6
+388 14 14
+1024 1 1
+54 1 1
+1019 1 1
+27 1 1
+428 3 3
+40 1 1
+86 1 1
+29 1 0
+610 6 10
+492 1 1
+28 3 3
+1202 11 11
+981 1 1
+28 1 1
+306 1 1
+39 1 1
+696 1 0
+157 1 1
+38 1 1
+170 1 1
+44 1 1
+2005 1 1
+26 1 1
+473 4 4
+491 0 1
+331 12 12
+1430 3 3
+11 0 5
+662 2 1
+494 12 13
+673 1 1
+76 1 1
+584 1 1
+36 1 1
+872 12 12
+123 1 1
+24 1 1
+540 15 15
+1309 1 1
+22 1 1
+71 15 15
+289 1 1
+38 1 1
+145 0 4
+731 3 0
+44 1 1
+2057 6 0
+446 4 0
+156 9 9
+55 0 1
+503 0 5
+38 1 1
+341 15 15
+493 1 1
+29 5 5
+1796 2 0
+1039 7 7
+444 8 8
+37 1 1
+205 0 1
+106 1 1
+386 1 1
+20 0 6
+2818 12 12
+498 15 15
+593 1 0
+203 1 1
+49 1 1
+313 1 2
+666 1 1
+46 0 2
+1360 1 0
+954 1 1
+65 1 1
+67 1 1
+33 1 1
+1062 1 1
+48 4 4
+600 16 16
+139 1 1
+29 1 1
+150 103 103
+813 1 1
+23 1 1
+775 1 1
+28 2 0
+55 13 0
+39 2 0
+17 0 1
+23 0 1
+7 11 1
+94 74 0
+163 1 1
+27 1 1
+2843 7 7
+73 4 0
+151 1 1
+22 0 1
+90 1 1
+316 15 15
+787 0 1
+405 1 1
+36 1 1
+833 2 0
+18 1 1
+1716 12 12
+78 0 1
+1860 0 1
+696 0 4
+16 1 1
+2116 3 4
+1554 1 1
+53 1 1
+1460 1 1
+25 1 1
+427 1 1
+37 1 1
+554 1 1
+36 1 1
+1626 40 40
+1079 1 1
+26 1 1
+427 2 0
+344 6 333
+1112 1 1
+19 1 1
+796 6 0
+373 1 1
+22 1 1
+787 1 0
+34 1 1
+1007 1 1
+36 2 0
+52 1 1
+945 1 0
+11 1 1
+743 1 1
+28 2 0
+1105 5 0
+45 2 0
+17 0 2
+49 1 1
+832 1 1
+33 1 1
+176 1 1
+48 0 4
+83 1 1
+91 1 1
+47 1 1
+256 1 1
+32 1 1
+1635 3 0
+175 5 1
+30 1 1
+1026 1 0
+13 1 1
+2090 20 20
+655 0 3
+628 1 1
+63 1 1
+380 1 1
+47 1 1
+2190 24 24
+149 0 2
+747 1 1
+17 0 7
+238 1048 0
+904 1 1
+78 1 1
+433 14 14
+153 1 1
+19 1 1
+561 1 1
+35 1 1
+271 2 0
+699 1 1
+53 1 1
+1273 0 1
+3111 11 11
+235 16 16
+490 3 0
+190 32 0
+83 18 19
+182 4 5
+78 0 4
+1098 1 1
+43 2 1
+1431 1 1
+35 4 4
+1822 0 6
+198 1 1
+41 1 1
+683 15 15
+1327 0 2
+18 1 1
+324 4 7
+1392 14 14
+1447
+
+chain 5080406 chr1_gl000192_random 547496 + 490457 547496 chr1 247249719 - 103949739 104006714 618
+285 2 1
+83 1 1
+1165 5 5
+59 1 1
+331 3 3
+32 1 1
+159 9 8
+140 1 1
+34 1 1
+111 1 1
+56 1 1
+419 1 1
+30 0 1
+231 16 16
+720 1 1
+47 1 1
+992 14 14
+147 1 1
+35 1 1
+270 2 2
+55 1 1
+204 1 1
+35 1 1
+189 12 12
+393 2 0
+504 2 0
+443 0 1
+181 0 6
+45 1 1
+719 1 1
+26 1 1
+723 9 9
+295 1 1
+56 1 1
+384 0 1
+516 1 0
+24 1 1
+81 0 1
+748 1 1
+47 1 1
+110 1 1
+38 82 0
+28 1 1
+526 1 1
+27 5 5
+166 8 7
+1312 0 4
+31 1 1
+230 1 1
+87 1 1
+309 13 0
+405 1 1
+33 1 0
+100 1 1
+59 1 1
+39 1 9
+184 0 4
+50 1 1
+211 4 4
+435 1 1
+55 1 1
+160 1 1
+39 1 1
+1986 1 1
+16 1 1
+117 0 1
+55 1 1
+357 0 1
+50 1 0
+368 0 20
+62 2 0
+4 2 0
+97 1 1
+121 0 1
+29 3 0
+857 36 36
+1724 0 322
+1221 1 1
+15 1 1
+135 8 8
+157 1 1
+25 0 1
+139 1 1
+36 1 1
+722 1 1
+46 1 0
+20 7 0
+862 1 0
+143 5 5
+274 1 1
+35 1 1
+355 0 1
+20 1 1
+376 1 1
+63 1 1
+199 1 1
+31 1 1
+261 0 1
+155 20 21
+52 0 1
+56 3 0
+151 23 23
+214 16 16
+105 1 1
+9 0 4
+41 1 1
+155 1 1
+77 1 1
+487 4 0
+82 1 1
+34 1 1
+275 1 1
+38 1 1
+334 1 1
+45 1 0
+4 0 4
+455 1 1
+47 1 1
+282 3 0
+74 14 14
+82 7 0
+717 1 1
+39 1 1
+197 0 4
+12 1 1
+50 17 17
+76 1 1
+38 1 1
+148 1 1
+60 1 1
+245 1 1
+18 1 1
+380 10 0
+348 1 1
+17 1 1
+515 1 1
+24 1 1
+267 5 7
+44 2 0
+25 1 1
+111 18 0
+162 1 1
+66 0 4
+109 1 1
+39 1 1
+676 16 16
+256 1 1
+48 1 1
+791 2 1
+61 1 1
+55 312 0
+281 7 7
+98 0 4
+66 1 1
+115 9 9
+678 1 1
+37 1 1
+304 1 1
+23 1 1
+283 1 1
+19 1 1
+164 10 10
+252 0 2
+131 4 4
+36 5 5
+83 1 1
+40 1 1
+361 27 20
+303 1 1
+69 1 1
+324 40 40
+72 12 0
+397 1 1
+23 1 1
+467 0 1
+418 6 6
+77 0 1
+21 1 1
+98 0 1
+21 1 1
+282 1 2
+107 22 22
+74 3 3
+47 1 1
+193 1 1
+46 1 1
+334 0 1
+78 0 1
+355 11 12
+823 1 1
+20 1 1
+173 1 1
+65 1 1
+335 0 4
+599 12 12
+143 1 1
+25 1 1
+1136 1 1
+38 1 1
+247 0 4
+30 1 1
+86 1 1
+19 1 1
+735 8 8
+679 15 15
+456 1 1
+43 1 1
+312 1 1
+94 1 1
+1047 1 1
+40 1 1
+1645 1 1
+37 1 1
+267 1 1
+55 1 1
+187 8 18
+480 1 1
+85 1 1
+537 1 1
+80 1 0
+80 0 11
+249 1 1
+24 1 1
+134 1 1
+36 1 1
+62 1 1
+81 0 2
+93 5 5
+46 1 1
+158 1 1
+36 1 1
+148 1 1
+67 1 1
+595 1 1
+30 1 1
+946 14 14
+58 1 1
+15 1 1
+321
+
+chain 2388490 chr1_gl000192_random 547496 + 0 480547 chr1 247249719 + 146071331 146197786 328
+299 0 14
+547 0 5
+291 3 3
+30 1 1
+1107 1 1
+35 1 1
+66 1 1
+86 1 1
+975 16 0
+485 12 0
+240 1 1
+16 1 1
+452 1 1
+26 2 2
+219 10 10
+607 31 14
+57 1 1
+397 1 1
+27 1 1
+69 0 2
+299 1 1
+38 0 1
+97 1 1
+33 1 1
+310 1 1
+63 1 1
+1214 11 0
+672 1 1
+30 1 1
+562 1 1
+34 1 1
+86 5 0
+36 52 0
+40 36 0
+73 0 3
+218 0 2
+885 1 1
+77 1 1
+153 1 1
+46 1 1
+538 0 1
+42 1 1
+495 0 1
+618 0 1
+406 1 1
+47 2 0
+264 1 1
+19 1 1
+112 0 3744
+343 13 14
+366 0 1
+39 1 1
+90 5 5
+72 0 3
+152 2 2
+42 1 1
+71 0 1
+30 1 1
+61 12 12
+280 0 3
+12 1 1
+101 1 1
+48 1 1
+97 1 1
+115 1 1
+299 1 1
+41 89 1
+148 7 7
+250 0 1
+1402 1 1
+69 1 0
+239 1 1
+38 1 1
+376 2 0
+96 1 1
+31 1 1
+273 0 4
+458 1 1
+22 0 12
+149 1 1
+38 0 2
+18 1 1
+443 1 0
+252 1 1
+25 1 1
+74 1 1
+18 0 1
+1535 108 9368
+354 1 0
+37 1 1
+1063 3 2
+3079 1 0
+142 1 1
+71 1 1
+230 6 6
+41 0 1
+112 4 4
+17 1 1
+478 2 0
+242 1 1
+21 1 1
+1407 1 0
+669 1 1
+34 1 1
+1561 1 1
+40 2 2
+62 1 1
+53 1 1
+975 1 1
+119 1 1
+1713 5 5
+132 0 3
+2570 1 0
+1294 9 9
+934 1 1
+33 1 1
+1518 4 1
+125 2889 0
+28 0 18
+706 10 10
+156 13 13
+1659 13 14
+1183 1 1
+49 1 1
+173 23 25
+420 364833 841
+3162 1 1
+44 1 1
+3579 1 1
+17 2 1
+30 3 0
+56 13 14
+298 1 1
+45 1 1
+388 1 1
+85 1 3
+162 2 0
+3397 3 5
+143 1 1
+19 1 1
+1299 1 1
+27 1 1
+10915 0 1
+4994 8 0
+1610 0 1
+3783 7 7
+606 4 0
+304 0 15
+143 12 14
+390 1 1
+43 0 2
+16 1 1
+231 5 0
+127 0 2
+222 2 0
+218 1 1
+45 1 1
+331 1 1
+23 1 1
+216 1 1
+21 1 1
+999 5 0
+563 1 1
+23 1 1
+305 1 1
+44 1 1
+466 2 0
+20 0 4
+234 16 21
+104 1 1
+28 1 1
+465 0 6
+137 1 3
+115 1 1
+23 1 1
+409 1 2
+762 1 1
+34 1 1
+133 1 1
+67 1 1
+1539 1 1
+24 1 1
+1362 9 2
+1632 1 1
+28 1 1
+1531 2 0
+26 1 1
+1909 10 2
+1605 1 1
+26 0 1
+834 0 1
+393 1 0
+40 1 1
+1724 1 1
+46 1 1
+588 8 8
+61 16 16
+669 1 1
+39 1 0
+1028 1 0
+21 1 1
+320 8 4
+1618 13 13
+569 18 15
+151 76 46
+2055 1 1
+35 1 1
+232 2 2
+26 1 1
+244 23 21
+54 16 16
+162 9 9
+61 1 1
+45 1 1
+72 1 1
+81 1 1
+197 1 1
+39 1 1
+300 1 1
+19 1 1
+370 9 9
+1433 1 0
+76 1 1
+21 1 1
+415 1 1
+26 1 1
+175 1 1
+9 2 0
+25 1 1
+413 1 1
+32 1 1
+299
+
+chain 551976 chr1_gl000192_random 547496 + 231797 237825 chr6 170899992 - 168530959 168536987 11545
+330 1 1
+17 2 2
+622 1 1
+19 1 1
+487 6 6
+662 1 1
+28 1 1
+1141 1 1
+84 1 1
+122 1 1
+29 1 1
+938 1 1
+49 1 1
+234 1 1
+107 1 1
+1138
+
+chain 488033 chr1_gl000192_random 547496 + 485075 510500 chr1 247249719 - 100429719 100455173 784
+56 1 1
+59 1 1
+88 1 0
+166 1 1
+42 1 1
+157 3 0
+1500 0 4
+24 1 1
+173 13 13
+537 1 1
+71 1 1
+274 1 1
+48 2 0
+29 1 1
+419 1 1
+75 1 1
+714 1 0
+919 11263 11275
+82 8662 8682
+36
+
+chain 29331 chr1_gl000192_random 547496 + 141011 141318 chr6 170899992 + 18853789 18854096 4814875
+307
+
+chain 25541 chr1_gl000192_random 547496 + 270161 270431 chr1 247249719 - 64213918 64214188 6752530
+270
+
+chain 18946 chr1_gl000192_random 547496 + 186298 186626 chr3 199501827 + 41796165 41796493 1046918
+124 44 44
+160
+
+chain 12970 chr1_gl000192_random 547496 + 526591 526726 chr14 106368585 + 78475097 78475232 7622843
+135
+
+chain 5617 chr1_gl000192_random 547496 + 185742 186466 chr4 191273063 - 143160847 143161571 1095905
+58 622 622
+44
+
+chain 2480 chr1_gl000192_random 547496 + 270431 270457 chr18 76117153 + 32169444 32169470 11367132
+26
+
+chain 2357 chr1_gl000192_random 547496 + 186676 186702 chr16 88827254 + 78288031 78288057 25120671
+26
+
+chain 2224 chr1_gl000192_random 547496 + 530486 530526 chr1_random 1663265 + 473083 473123 25958
+40
+
+chain 22466185064 chr2 243199373 + 10000 243102476 chr2 242951149 + 0 242751149 1
+1201236 0 1
+2057 1 1
+26 1 1
+4043 22 0
+82 7 101
+33 84 0
+26 1 23
+67 48 0
+176 318 0
+40 92 0
+33 0 74
+62 0 6
+22 0 118
+387 2446 0
+843 2450 0
+167 2304 0
+21342 1 1
+50 4 0
+2040 0 4
+9053 2 0
+88 3 53
+1078 0 1
+4122 1 0
+1608 28 1
+4029 0 9
+967 4547 1000
+420 27 0
+2237126 0 1
+2458 17 17
+4595 4 0
+3531 14 14
+3954 51129 50000
+1426129 160449 100025
+11087286 0 3
+773 103977 50000
+1576 0 1
+240 0 1
+318 2 0
+255 0 16
+2851 10 10
+1404 1 1
+27 1 1
+703 13 0
+375 0 1
+4783388 35000 25000
+848 0 2
+1225 0 2
+391 1 0
+3653 1 1
+28 1 1
+49 0 4
+4514 0 9
+9628 1 9
+1483 7 7
+1990 0 1
+1949 1 0
+2716230 1 0
+7799848 851 851
+38932068 5 9
+9477928 0 3
+7529698 72396 0
+1891551 294073 150000
+17672 1 0
+5792 1 0
+9017 0 266
+2944 0 1
+9388 2 0
+37828 4 0
+23436 0 4
+290931 1273578 1000000
+731068 3000000 3000000
+2558421 0 1
+1197 10 0
+685 42 46
+2309 0 1
+1332 22 23
+344 0 1
+1645 4 4
+4093 25 25
+2446 1 0
+6329 1 0
+769 0 1
+873 7 0
+1299 0 1
+8250 15 15
+4291 10626 12548
+1063 103 0
+75 0 218
+5897 1 1
+33 1 1
+9905 51 37
+1711 1 1
+45 1 1
+1597 4 4
+61 1 1
+869 13 0
+1633 15 15
+1179 3 0
+2819 0 2
+156 88 465
+100 0 25
+4753 0 8
+4903 6 6
+3847 0 2
+108126 0 145
+3542 1 0
+10276 0 1
+402 1 1
+47 1 1
+63 2 0
+583 1 1
+34 1 1
+8974 0 46
+379 1 1
+70 1 1
+2474 0 102
+1756 0 1
+8426 0 1
+11986570 151150 142000
+14207 1 1
+49 1 1
+1781 0 12
+409 1 0
+1874 1 1
+33 1 1
+4795 2 0
+3686 1 1
+15 1 1
+164 2 0
+7287 5 5
+702023 72796 150000
+69 1 0
+1598 0 1
+1340 0 1
+1030 0 4
+1166 10 10
+6406 1 1
+34 1 1
+3283 2 4
+496 1 23
+25 10 0
+40 1 1
+21282 2 1
+1406 0 44
+937 17 0
+18255 1 0
+172366 0 281526
+40517 0 406
+58864 1 2
+1843 0 2
+14994 0 1
+12992 2 0
+2571146 1 0
+35688061 108224 100000
+29671719 1 0
+39665349 1 0
+14876089 64197 20000
+401 0 3
+1831 1 1
+61 1 1
+654 11 1
+127 0 28
+116 25 29
+74 9 9
+3247 2 0
+1355 1 0
+816 1 0
+21 3 0
+526 1 1
+60 1 1
+773 1 0
+1494 1 0
+1683 1 0
+21 1 1
+596 1 0
+1582 1 0
+425 0 3
+1139 0 8
+138 144 813
+71 1 0
+385638 1 1
+219 1 1
+51 7 7
+54 15205 15205
+54 7 7
+51 1 1
+110 1 1
+5198249 0 1
+115 80 0
+60 40 0
+80 100 20
+442 1 1
+35 1 1
+119 9 129
+14 0 40
+61 1 1
+85 0 40
+1331 0 1
+1194 12 14
+1773 0 5
+1623 1 1
+25 1 1
+2422 21 22
+2315 0 1
+31 1 1
+1508 0 3
+50 0 4
+970 6 6
+7234 4 0
+1228 1 0
+1233 8 1
+4207 1 1
+41 1 1
+1715 50 50
+1532 0 2
+1714 2 0
+2299 2 0
+2143 1 1
+18 1 1
+917 1 0
+1082 1 1
+49 1 1
+9098 0 4
+5529 0 1
+3266 0 8
+894 6 0
+1440 1 1
+2095 2 0
+4179 18 13
+1785 0 1
+1674 0 6
+1217 32348 33000
+287 17 23
+40 173 0
+20 161 0
+13 66 0
+12 71 1
+12548 30000 30000
+952154 41011 25000
+1914 1 0
+225 1 1
+57 1 1
+2910 0 1
+471 1 0
+1956 1 1
+43 1 1
+991 0 92
+2863 3 0
+1838 306 0
+1006 30 0
+206 1 1
+27 0 3
+221 17 17
+1525 8 0
+413 1 1
+32 2 2
+1573 12 12
+2258676
+
+chain 8298836 chr2 243199373 + 90373613 90527957 chr2 242951149 + 90958828 91114560 236
+29837 32 32
+212 25 25
+508 90 90
+1291 33 33
+2574 1 0
+833 28 28
+2712 0 1
+805 10 5
+565 68 68
+75 69 57
+176 58 513
+63 105 105
+336 33 33
+69 1 0
+280 4 4
+111 12 12
+523 1 0
+136 55 56
+198 0 1
+630 0 1
+362 42 42
+405 30 30
+78 5 0
+125 5 0
+75 140 0
+166 49 49
+1653 30 30
+3790 5 5
+500 21 21
+577 23 23
+180 0 1
+1105 1 0
+231 4 4
+333 33 33
+852 2 0
+2709 16 16
+476 28 28
+53 33 57
+256 0 3
+900 0 1
+227 0 2
+718 0 2
+244 42 42
+302 30 30
+211 21 21
+1809 16 17
+204 33 32
+341 9 9
+176 0 5
+180 67 67
+73 39 39
+369 49 49
+52 9 15
+699 9 13
+142 0 4
+184 0 4
+248 27 26
+306 10 10
+63 20 20
+533 22 22
+432 86 85
+97 19 19
+383 19 23
+642 10 9
+156 88 88
+217 0 6
+1798 9 7
+425 0 4
+1191 0 4
+465 40 37
+671 7 7
+450 0 1
+714 31 32
+682 38 15
+230 28 1076
+95 220 261
+80 1967 0
+118 383 158
+81 28 2
+247 0 1
+181 0 1
+702 47 47
+361 39 39
+300 50 50
+195 9 9
+179 35 35
+228 0 10
+321 65 65
+233 20 20
+368 35 35
+1436 37 37
+985 5 5
+140 73 73
+1031 25 25
+957 51 51
+690 23 48
+1047 49 49
+186 1 0
+244 4 4
+166 16 16
+173 1 0
+387 51 51
+122 59 58
+141 1 0
+72 102 84
+75 203 201
+276 30 30
+367 20 20
+105 67 68
+82 0 1
+386 7 7
+68 61 61
+514 56 56
+92 91 91
+268 89 89
+200 4 4
+526 33 36
+370 10 10
+366 20 26
+1107 0 2
+130 74 74
+101 0 1
+542 32 34
+179 43 43
+151 84 84
+421 25 25
+332 1 0
+561 64 65
+1406 10 10
+161 97 88
+564 27 30
+123 29 33
+170 0 1
+183 94 94
+52 4 0
+379 83 83
+237 32 31
+187 46 46
+236 728 703
+50 1494 1865
+72 67 32
+25 1732 6535
+52 52 52
+104 647 648
+27 494 471
+23 0 137
+1 1884 302
+115 8 8
+76 3078 388
+26 200 44
+59 2295 2292
+40 1854 1861
+54 2541 2546
+27 28 27
+57 56 56
+26 2212 2216
+181 494 652
+42 2237 2213
+40 2572 2562
+36 1791 1791
+34 2776 2807
+23 7115 7113
+44 509 509
+36 664 665
+43 1891 2219
+36 256 256
+31 276 289
+42 881 1734
+67 149 144
+49 190 190
+73 357 345
+30 1074 1075
+42 1850 1850
+47 469 481
+24 2460 2482
+41 3325 3319
+32 306 296
+26
+
+chain 2305993 chr2 243199373 + 243162866 243189340 chr16 88827254 - 5000 31222 1142
+136 9 9
+870 16 16
+229 1 1
+44 1 1
+330 10 14
+243 1 1
+93 1 1
+58 1 1
+144 1 1
+62 95 95
+333 1 1
+77 1 1
+494 9 11
+230 8 8
+61 12 13
+128 14 14
+123 1 1
+68 1 1
+4208 5 1
+1989 71 0
+121 1 1
+35 1 1
+1498 59 0
+443 69 69
+237 1 1
+45 1 1
+75 1 1
+32 2 1
+20 1 1
+152 1 1
+129 0 1
+1040 1 1
+70 2 0
+128 1 1
+50 1 1
+605 9 8
+62 1 1
+155 1 1
+50 11 6
+94 1 1
+409 1 1
+34 1 1
+217 1 1
+39 1 1
+287 0 9
+102 1 1
+56 30 26
+64 108 0
+127 1 0
+373 1 1
+18 1 1
+194 1 1
+10 1 1
+98 1 1
+67 1 1
+184 1 1
+21 1 1
+86 0 1
+44 1 1
+50 15 15
+177 1 1
+72 1 1
+222 1 1
+44 1 1
+50 1 1
+46 1 1
+449 1 1
+118 1 1
+127 0 1
+242 1 1
+36 1 1
+710 4 4
+69 1 1
+87 1 1
+115 1 1
+68 17 0
+12 2 1
+14 0 12
+36 4 0
+102 1 1
+105 24 24
+131 18 18
+64 19 19
+293 1 1
+43 1 1
+134 25 25
+77 14 14
+225 1 0
+93 1 1
+363 11 11
+271 25 25
+136 1 1
+36 1 1
+102 4 4
+29 1 1
+51 2 0
+162 0 4
+61 1 0
+65 1 1
+26 4 4
+140 17 17
+336 1 1
+25 1 1
+408 16 16
+311 27 27
+90 7 7
+449 1 1
+47 1 1
+133 1 1
+62 7 7
+194 1 1
+13 3 0
+54 2 0
+28 1 1
+72 1 1
+45 1 1
+65 1 1
+23 1 1
+279 1 1
+61 1 1
+55
+
+chain 1358560 chr2 243199373 + 89890737 90543561 chr2 242951149 - 153539598 155537136 99
+8973 0 1
+939 0 1
+4351 0 2
+2413 1 1
+37 1 1
+515 1 0
+224 1 1
+22 1 1
+203 1 1
+18 1 1
+249 8 7
+830 4 0
+177 1 0
+30 1 1
+224 1 1
+75 1 1
+243 1 1
+20 0 5
+2724 0 137
+439 1 1
+35 1 1
+444 0 2
+1484 1 1
+41 1 1
+395 1 1
+40 1 1
+417 1 1
+44 1 1
+909 1 1
+32 24 14
+1057 2 2
+46 1 1
+306 1 1
+32 3 0
+269 10 10
+535 10 10
+615 1 1
+42 1 1
+1295 1 1
+21 1 1
+84 1 1
+30 0 1
+19 1 1
+434 57 57
+283 15 15
+304 12 12
+149 17 17
+1413 1 1
+32 1 1
+66 550910 1890523
+54 205 14
+64 147 86
+119 57 8
+71 27 96
+100 1265 73
+307 7 9
+182 31 30
+128 15 15
+95 61 59
+92 20 296
+50 77 75
+255 261 3338
+95 264 262
+204 53 55
+136 81 81
+173 62 57
+130 77 76
+241 35 35
+424 0 154
+42 3 3
+109 0 434
+68 0 59
+215 1 1
+47 1 1
+109 0 180
+10 4 0
+21 7 104
+33 31 37
+62 17 17
+114 1 1
+50 0 9
+117 9 0
+63 1 1
+92 1 1
+37 146 0
+49 956 0
+32 163 4
+37 619 0
+42 1 1
+108 973 20
+91 1 18
+215 19 19
+20 26 0
+124 56 0
+14 65 0
+65 1 1
+465 1 1
+45 1 0
+126 1 1
+46 1 1
+1501 1 1
+41 40 0
+58 2 5
+574 8 0
+830 0 5
+121 0 3
+26 0 2
+52 0 2
+183 54 0
+1069 1 1
+62 4 0
+23 1 1
+62 0 3
+233 0 2
+32 3 0
+1051 112 112
+56 26 26
+59 7 7
+588 17 18
+401 18 18
+472 1 0
+398 2 3
+249 181 22
+397 0 158
+97 42 42
+1302 24 2
+162 9 9
+740 40 40
+554 0 1
+1362 23 19
+249 12 12
+372 36 36
+987 1 0
+221 10 8
+394 9 9
+169 34 36
+170 1 1
+27 1 1
+61 1 0
+396 0 120
+152 1 13
+60 0 5
+12 1 1
+145 1 1
+51 1 1
+847 6 6
+420 1 1
+46 1 0
+43 1 1
+145 1 1
+41 1 1
+142 25 24
+332 14 14
+310 1 1
+91 1 1
+605 1 1
+47 1 1
+361 10 10
+183 0 5
+672 8 8
+76 17 20
+227 1 1
+86 1 1
+60 1 0
+30 5 5
+2399 1 1
+29 1 1
+547 10 17
+195 3 0
+609 3 0
+175 44 44
+292 8 8
+209 36 37
+543 39 39
+82 43 43
+235 38 38
+760 20 20
+502 8 0
+108 7 18
+66 2 0
+57 0 3
+88 36 36
+77 0 15
+94 24 24
+61 31 1532
+146 38 41
+92 82 77
+151 0 2606
+94 93 1000
+189 50 50
+234 100 94
+146 49 49
+189 74 74
+62 37 17
+258 30 30
+114 47 47
+494 96 98
+323 42 43
+106 20 20
+142 250 250
+161 7 7
+651 21 21
+492 237 249
+144 23 23
+88 48 48
+52 15 15
+201 6 0
+105 29 29
+68 18 18
+87 50 50
+227 147 147
+176 17 17
+404 9 9
+457 0 23
+392 41 41
+196 18 18
+99 77 80
+219 52 53
+156 0 7
+323 28 28
+99 43 42
+229 27 27
+156 107 103
+95 1 0
+1118 0 1
+282 41 41
+172 21 3
+104 26 0
+21 1 71
+54 6 76
+63 1 1
+58 1 1
+84 1 1
+285 1 1
+46 1 1
+320 15 15
+326 7 7
+170 1 1
+73 1 1
+214 1 1
+40 1 1
+613 1 0
+772 0 2
+424 1 1
+34 1 1
+423 1 1
+33 1 1
+1157 1 1
+43 2 2
+82 1 1
+21 1 1
+65 1 1
+62 1 1
+250 1 1
+79 1 1
+88 2 2
+79 1 1
+68 11 11
+115 1 1
+38 1 1
+63 9 0
+39 1 1
+73 1 1
+77 3 3
+55 1 1
+46 1 1
+157 1 1
+58 0 2
+92 1 1
+67 1 1
+48 1 1
+289 1 1
+40 1 0
+398 1 1
+31 1 1
+729 1 1
+72 1 1
+575 1 1
+86 1 1
+495 3 0
+472 1 1
+34 1 1
+87 1 0
+28 1 1
+441 20 0
+31 1 1
+61 1 1
+152 5 5
+774 0 1
+114 2 0
+355 0 3
+415 5 0
+76 1 1
+18 1 1
+308 1 1
+18 1 1
+226 4 4
+490 0 3
+104 1 1
+47 1 1
+542 6 6
+131 8 0
+152 49 1
+68 9 9
+198 1 1
+40 0 10
+78 1 1
+108 1 1
+73 1 1
+50
+
+chain 1317324 chr2 243199373 + 234472598 234486532 chr2 242951149 - 8801149 8815083 1658
+13934
+
+chain 1182591 chr2 243199373 + 111018489 111031067 chr2 242951149 - 132350497 132363075 1985
+750 1 0
+155 1 0
+2029 0 1
+2687 0 1
+2417 3 0
+3105 1 3
+965 35 36
+238 6 6
+185
+
+chain 907761 chr2 243199373 + 111000659 111010676 chr2 242951149 + 110060000 110070000 4064
+3405 66 54
+839 0 1
+854 33 33
+1502 180 174
+250 88 88
+1904 40 40
+856
+
+chain 864618 chr2 243199373 + 110991361 111000659 chr2 242951149 + 110050705 110060000 3488
+3987 37 37
+135 34 34
+2446 4 0
+1497 0 1
+1158
+
+chain 730598 chr2 243199373 + 111010676 111018489 chr2 242951149 + 110070000 110077815 3339
+976 16 15
+4855 0 3
+320 26 26
+1620
+
+chain 247895 chr2 243199373 + 111031067 111033745 chr2 242951149 - 131778891 131781575 150672
+814 1 1
+73 1 1
+148 0 6
+1211 4 4
+426
+
+chain 233678 chr2 243199373 + 87718206 87726480 chr2 242951149 - 151887377 151890935 691
+139 0 3
+233 4 2
+36 0 1
+291 21 13
+104 28 28
+303 26 26
+314 134 82
+86 0 1
+53 4314 721
+22 22 0
+50 389 652
+54 1133 0
+17 214 6
+79 34 60
+62 59 67
+53
+
+chain 228678 chr2 243199373 + 243159401 243162866 chr1 247249719 + 217390 220668 1312
+57 88 88
+22 186 0
+101 49 49
+417 53 54
+61 3 0
+141 0 1
+198 8 8
+852 39 39
+405 56 56
+61 27 27
+589 1 1
+51
+
+chain 207578 chr2 243199373 + 243152688 243155284 chr10 135374737 - 346 2792 2690
+533 150 0
+105 1 1
+49 1 1
+260 1 1
+69 1 1
+262 1 1
+29 1 1
+1133
+
+chain 148868 chr2 243199373 + 243155284 243160374 chr5 180857866 - 20000 25834 2103
+547 1 1
+38 1 1
+431 1 1
+24 1 1
+1389 1 1
+36 1 1
+1646 57 57
+82 0 744
+6 22 22
+186 101 101
+49 417 417
+53
+
+chain 147892 chr2 243199373 + 97920581 97932373 chr2 242951149 - 145465890 145477699 123
+1513 0 1
+2596 1 1
+36 1 1
+1383 5 1
+46 4 0
+550 1 4
+1798 7 8
+158 1 29
+18 1 1
+110 1 1
+48 1 1
+1617 7 0
+723 1063 1063
+93 1 0
+9
+
+chain 133880 chr2 243199373 + 87666489 111064157 chr2 242951149 - 130965951 132771520 53
+624 23366717 1774574
+2397 0 12
+14288 0 1
+1427 1 1
+24 1 1
+1756 10 10
+83 69 69
+698 0 21
+1910 1 1
+61 1 1
+3754 0 8
+243 1 1
+33 1 1
+320 0 1
+163 1 1
+36 1 1
+809 0 1
+1762 1 1
+49 1 1
+425
+
+chain 127176 chr2 243199373 + 5140970 5146585 chr2 242951149 - 235014747 235020583 1011815
+158 1545 1830
+107 308 308
+50 129 129
+85 163 165
+62 65 65
+282 81 63
+147 650 624
+67 138 138
+59 285 285
+76 61 62
+92 72 72
+76 266 249
+70 129 128
+83 107 102
+202
+
+chain 104115 chr2 243199373 + 87667113 87668206 chr2 242951149 + 87520624 87521717 786265
+1093
+
+chain 95484 chr2 243199373 + 87729232 87738885 chr2 242951149 + 87510347 87520000 5761
+9653
+
+chain 84057 chr2 243199373 + 90492917 90545103 chr2 242951149 - 152993866 153046874 435
+28 21223 21222
+38 2087 2087
+38 134 134
+40 246 246
+45 0 255
+13 0 572
+34 189 189
+50 234 234
+30 1029 1029
+47 494 494
+96 633 633
+250 1379 1379
+190 682 682
+29 173 173
+50 227 227
+147 1809 1804
+77 219 219
+52 479 479
+28 99 99
+43 229 229
+27 156 156
+107 16787 16788
+49 628 628
+1542
+
+chain 73315 chr2 243199373 + 87720014 87720774 chr2 242951149 - 155450797 155451557 1717423
+760
+
+chain 66981 chr2 243199373 + 1219529 1222202 chr2 242951149 + 1208584 1209647 1299817
+61 279 0
+275 1051 0
+115 843 563
+49
+
+chain 64603 chr2 243199373 + 90371566 90373613 chr2 242951149 + 90963202 90965490 370989
+76 46 46
+165 47 47
+460 75 75
+51 403 393
+63 64 364
+66 168 168
+56 68 19
+69 135 135
+35
+
+chain 46427 chr2 243199373 + 1223650 1226709 chr2 242951149 + 1208645 1209604 1438302
+140 630 0
+183 167 167
+210 1050 0
+171 420 0
+88
+
+chain 36623 chr2 243199373 + 89847430 89848295 chr5 180857866 + 153976522 153977390 3635252
+54 96 96
+262 346 349
+107
+
+chain 34396 chr2 243199373 + 87721616 87729232 chr2 242951149 + 87502993 87507825 13964
+67 36 543
+1013 77 25
+569 4 4
+189 715 6
+6 94 94
+389 54 54
+542 2531 33
+70 11 11
+68 21 21
+129 10 10
+126 0 22
+162 9 0
+89 28 26
+108 298 307
+116 64 12
+21
+
+chain 31906 chr2 243199373 + 90476997 90485104 chr2 242951149 - 155439923 155448722 818134
+65 4692 1587
+31 1167 442
+62 157 183
+65 24 24
+92 31 191
+67 10 184
+32 72 0
+76 105 36
+60 4 0
+97 52 697
+66 9 0
+169 1 23
+85 272 2102
+131 95 43
+149 89 1960
+80
+
+chain 31233 chr2 243199373 + 239788914 239789423 chr2 242951149 + 239454423 239454932 2214253
+173 20 20
+161 13 13
+66 12 12
+64
+
+chain 27639 chr2 243199373 + 243165116 243187640 chr8 146274826 + 470 67316 1215
+95 9992 9923
+69 4222 48594
+49 1 1
+58 4967 4926
+25 3019 3079
+27
+
+chain 25982 chr2 243199373 + 16340754 16341023 chr3 199501827 - 118072788 118073057 6523537
+269
+
+chain 25898 chr2 243199373 + 1220683 1220990 chr2 242951149 + 1208828 1209135 2249524
+307
+
+chain 25826 chr2 243199373 + 87728597 87729031 chr2 242951149 + 87491002 87491436 712257
+28 108 108
+298
+
+chain 25128 chr2 243199373 + 5141270 5144398 chr1 247249719 + 207689145 207692170 1456022
+66 87 87
+79 23 23
+95 979 893
+74 119 119
+116 487 487
+54 893 876
+56
+
+chain 24661 chr2 243199373 + 16273805 16274100 chr4 191273063 - 182882474 182882769 7289877
+128 26 26
+141
+
+chain 19295 chr2 243199373 + 90372486 90373577 chr2 242951149 + 90976555 90977646 1336226
+61 57 57
+56 292 292
+41 202 202
+55 193 193
+134
+
+chain 19158 chr2 243199373 + 1225400 1225680 chr2 242951149 + 1208855 1209065 11144872
+180 70 0
+30
+
+chain 18303 chr2 243199373 + 1219198 1219473 chr2 242951149 + 1208603 1208808 11853376
+134 73 3
+68
+
+chain 13465 chr2 243199373 + 16354747 16354888 chr5 180857866 + 167726962 167727103 16868271
+141
+
+chain 13298 chr2 243199373 + 89875086 89876327 chr20 62435964 + 29293186 29293377 17078580
+57 350 0
+39 320 0
+36 155 0
+6 225 0
+53
+
+chain 13261 chr2 243199373 + 1224140 1224280 chr2 242951149 + 1208645 1208785 17127371
+140
+
+chain 12749 chr2 243199373 + 5141660 5146147 chr5 180857866 - 44949635 44952639 1949230
+55 641 482
+80 490 492
+69 238 238
+34 2813 1487
+67
+
+chain 11727 chr2 243199373 + 240838559 240838726 chr2 242951149 + 240487433 240487623 18443158
+86 35 58
+46
+
+chain 11295 chr2 243199373 + 1226909 1227026 chr2 242951149 + 1209530 1209647 20202652
+117
+
+chain 11288 chr2 243199373 + 1223295 1223413 chr2 242951149 + 1208990 1209108 3139804
+118
+
+chain 10759 chr2 243199373 + 90430195 90457119 chr2 242951149 - 151338126 151363320 2584
+28 2775 2822
+30 11958 12016
+40 1843 1850
+30 5080 3227
+47 361 361
+39 312 312
+38 383 383
+35 2707 2718
+36 1130 1130
+52
+
+chain 9553 chr2 243199373 + 89869741 89871237 chrY 57772954 + 11913136 11913399 23867669
+64 1367 134
+65
+
+chain 9489 chr2 243199373 + 110253717 110253937 chr2 242951149 + 106303434 106303606 24025084
+58 106 58
+56
+
+chain 9445 chr2 243199373 + 1223971 1224070 chr2 242951149 + 1208756 1208855 24130758
+99
+
+chain 8720 chr2 243199373 + 1222223 1225291 chr2 242951149 + 1208828 1209516 2041184
+278 99 99
+79 2535 155
+77
+
+chain 8428 chr2 243199373 + 90482794 90485288 chr2 242951149 - 155439240 155441007 1572933
+56 44 44
+58 400 417
+31 1832 1088
+73
+
+chain 8213 chr2 243199373 + 87720809 87720895 chr2 242951149 + 87507349 87507434 5227216
+41 1 0
+44
+
+chain 8069 chr2 243199373 + 90483014 90484786 chr2 242951149 - 155448229 155461339 1164914
+45 110 127
+2 735 1564
+52 750 11246
+68 4 0
+6
+
+chain 7776 chr2 243199373 + 1217508 1217592 chr2 242951149 + 1207753 1207837 7243988
+84
+
+chain 7421 chr2 243199373 + 1226334 1226411 chr2 242951149 + 1209439 1209516 27381596
+77
+
+chain 7358 chr2 243199373 + 89880461 89880538 chr22 49691432 - 33895115 33895192 27502443
+77
+
+chain 7257 chr2 243199373 + 1219025 1219100 chr2 242951149 + 1208570 1208645 27695248
+75
+
+chain 7028 chr2 243199373 + 1220317 1225128 chr2 242951149 + 1208603 1209423 1749868
+42 70 0
+111 1961 0
+99 2380 420
+148
+
+chain 6973 chr2 243199373 + 1223223 1223295 chr2 242951149 + 1208568 1208640 27324023
+72
+
+chain 6924 chr2 243199373 + 1220268 1221195 chr2 242951149 + 1208974 1209200 2111755
+49 743 42
+135
+
+chain 6823 chr2 243199373 + 243161637 243162225 chr6 170899992 - 4262 4850 1512
+39 405 405
+56 61 61
+27
+
+chain 6757 chr2 243199373 + 1224280 1224350 chr2 242951149 + 1209065 1209135 28694341
+70
+
+chain 6747 chr2 243199373 + 1219799 1219869 chr2 242951149 + 1208645 1208715 25148698
+70
+
+chain 6633 chr2 243199373 + 89847849 89847926 chr14 106368585 - 28607150 28607227 5517613
+77
+
+chain 6601 chr2 243199373 + 239685120 239685200 chr2 242951149 + 239350340 239350540 24829287
+66 1 121
+13
+
+chain 6531 chr2 243199373 + 89865276 89865345 chr16 88827254 - 55053025 55053094 29215386
+69
+
+chain 6312 chr2 243199373 + 111004064 111004130 chr2 242951149 - 132336069 132336135 211650
+66
+
+chain 6255 chr2 243199373 + 1226201 1226267 chr2 242951149 + 1209586 1209652 12280449
+66
+
+chain 6049 chr2 243199373 + 89847131 89847195 chr1 247249719 + 184405152 184405216 30439720
+64
+
+chain 6014 chr2 243199373 + 89850535 89853562 chr10 135374737 - 96209116 96209251 30527518
+57 2911 19
+59
+
+chain 5970 chr2 243199373 + 87721480 87727902 chr2 242951149 + 87501266 87503920 375724
+136 1955 628
+417 2657 546
+67 36 27
+57 474 105
+64 294 290
+36 0 52
+229
+
+chain 5911 chr2 243199373 + 87725643 87726005 chr2 242951149 + 87495962 87496324 1452475
+79 29 29
+211 17 17
+26
+
+chain 5902 chr2 243199373 + 90476920 90476981 chr2 242951149 - 155440689 155440750 30819911
+61
+
+chain 5764 chr2 243199373 + 1219128 1219198 chr2 242951149 + 1208603 1208673 13156733
+70
+
+chain 5625 chr2 243199373 + 87727023 87727089 chr2 242951149 + 87494216 87494282 1840679
+66
+
+chain 5449 chr2 243199373 + 1221033 1223650 chr2 242951149 + 1208828 1209415 2333010
+27 2353 323
+237
+
+chain 5435 chr2 243199373 + 87725371 87725531 chr2 242951149 + 87487864 87488024 3394118
+65 44 44
+51
+
+chain 5351 chr2 243199373 + 243152496 243152579 chr21 46944323 - 27 110 6622
+83
+
+chain 5348 chr2 243199373 + 5153354 5153410 chr2 242951149 + 239297362 239297418 32407088
+56
+
+chain 5167 chr2 243199373 + 89830753 89830808 chr16 88827254 - 55048203 55048258 32968623
+55
+
+chain 5034 chr2 243199373 + 90484935 90484987 chr2 242951149 - 155462101 155462153 29809699
+52
+
+chain 5012 chr2 243199373 + 89872838 89872891 chr4 191273063 + 48825877 48825930 33453820
+53
+
+chain 4920 chr2 243199373 + 89890558 89890609 chr2 242951149 + 89623647 89623698 33788797
+51
+
+chain 4886 chr2 243199373 + 90477063 90477242 chr2 242951149 - 155440771 155441314 25803008
+53 75 439
+51
+
+chain 4812 chr2 243199373 + 89870406 89870457 chr4 191273063 + 48802771 48802822 34140093
+51
+
+chain 4757 chr2 243199373 + 234058786 234058836 chr13 114142980 + 90951015 90951065 34330265
+50
+
+chain 4737 chr2 243199373 + 5145834 5145884 chr3 199501827 - 155139362 155139412 33407240
+50
+
+chain 4647 chr2 243199373 + 1226779 1226827 chr2 242951149 + 1209604 1209652 34630462
+48
+
+chain 4644 chr2 243199373 + 111007822 111007876 chr2 242951149 - 132339823 132339877 533729
+54
+
+chain 4607 chr2 243199373 + 5145066 5145350 chr3 199501827 + 191348934 191349218 1967131
+93 45 45
+57 39 39
+50
+
+chain 4552 chr2 243199373 + 1219473 1219520 chr2 242951149 + 1208598 1208645 27324024
+47
+
+chain 4467 chr2 243199373 + 5146638 5146689 chr8 146274826 + 70047993 70048044 10546953
+51
+
+chain 4382 chr2 243199373 + 239685380 239685447 chr2 242951149 + 239350400 239350507 10821439
+47 0 40
+20
+
+chain 4286 chr2 243199373 + 89847926 89848007 chr18 76117153 + 56250573 56250654 7293717
+81
+
+chain 4166 chr2 243199373 + 90482850 90482893 chr2 242951149 - 155471295 155471338 33373631
+43
+
+chain 4069 chr2 243199373 + 90483640 90483682 chr2 242951149 - 155471279 155471321 32448532
+42
+
+chain 4027 chr2 243199373 + 89848079 89848577 chr11 134452384 - 130303828 130304326 4308822
+70 372 372
+56
+
+chain 3915 chr2 243199373 + 89847485 89847537 chr4 191273063 - 120181520 120181572 9841777
+52
+
+chain 3887 chr2 243199373 + 1222921 1225400 chr2 242951149 + 1208756 1209205 3355598
+176 2233 203
+70
+
+chain 3870 chr2 243199373 + 5146741 5146807 chr4 191273063 - 106282745 106282811 8233254
+2 4 4
+60
+
+chain 3851 chr2 243199373 + 243174715 243174760 chr1 247249719 + 80163 80208 1584
+45
+
+chain 3776 chr2 243199373 + 1223932 1223971 chr2 242951149 + 1208577 1208616 29100476
+39
+
+chain 3766 chr2 243199373 + 1225991 1226030 chr2 242951149 + 1209516 1209555 18014514
+39
+
+chain 3567 chr2 243199373 + 89848026 89848188 chr6 170899992 - 102513053 102513215 4544108
+53 70 70
+39
+
+chain 3456 chr2 243199373 + 87720895 87724286 chr2 242951149 + 87506634 87508855 332559
+59 4 143
+126 0 22
+162 9 0
+89 28 26
+108 1252 650
+77 1179 461
+298
+
+chain 3166 chr2 243199373 + 90482349 90482483 chr2 242951149 - 155440886 155440924 3921176
+20 96 0
+18
+
+chain 3114 chr2 243199373 + 1223097 1223130 chr2 242951149 + 1209002 1209035 21012522
+33
+
+chain 3110 chr2 243199373 + 1225750 1225960 chr2 242951149 + 1209065 1209275 3693305
+210
+
+chain 2962 chr2 243199373 + 16340723 16340754 chr16 88827254 + 56242121 56242152 7757072
+31
+
+chain 2946 chr2 243199373 + 1225580 1225611 chr2 242951149 + 1209315 1209346 16952082
+31
+
+chain 2859 chr2 243199373 + 243189340 243189373 chr2 242951149 - 213544 213577 2192
+33
+
+chain 2638 chr2 243199373 + 5146355 5146383 chr9 140273252 + 31324189 31324217 27516381
+28
+
+chain 2632 chr2 243199373 + 87721683 87721719 chr2 242951149 + 87489021 87489057 886310
+36
+
+chain 2630 chr2 243199373 + 5144933 5144985 chr19 63811651 + 23161927 23161979 24515130
+52
+
+chain 2538 chr2 243199373 + 16338477 16338504 chr3 199501827 - 154040818 154040845 35425972
+27
+
+chain 2527 chr2 243199373 + 111053817 111053884 chr2 242951149 + 110544305 110544372 1691975
+67
+
+chain 2476 chr2 243199373 + 5146689 5146741 chr2 242951149 - 88851718 88851770 6471285
+52
+
+chain 2465 chr2 243199373 + 16260450 16260476 chr14 106368585 - 56125663 56125689 35442474
+26
+
+chain 2448 chr2 243199373 + 90475509 90477186 chr2 242951149 - 155452726 155455668 5069202
+50 704 1477
+39 832 1324
+52
+
+chain 2256 chr2 243199373 + 89865421 89865445 chr4 191273063 + 48820096 48820120 35487368
+24
+
+chain 2132 chr2 243199373 + 90371525 90371566 chr2 242951149 + 90975643 90975684 3405316
+41
+
+chain 2046 chr2 243199373 + 87729180 87729211 chr2 242951149 + 87489147 87489178 2812396
+31
+
+chain 2012 chr2 243199373 + 16273933 16273955 chr11 134452384 + 22938127 22938149 7662326
+22
+
+chain 1994 chr2 243199373 + 5144152 5145822 chr11 134452384 + 133004933 133006812 2924035
+46 1530 1739
+23 20 20
+51
+
+chain 1907 chr2 243199373 + 5146585 5146633 chr1 247249719 - 174030724 174030772 3467396
+48
+
+chain 1894 chr2 243199373 + 1220990 1221013 chr2 242951149 + 1208785 1208808 13156732
+23
+
+chain 1847 chr2 243199373 + 87729147 87729180 chr2 242951149 + 87508312 87508345 2784752
+33
+
+chain 1616 chr2 243199373 + 5141194 5141259 chr4 191273063 + 140068684 140068749 14298254
+65
+
+chain 1606 chr2 243199373 + 89847307 89847375 chr6 170899992 + 54305106 54305174 19190580
+68
+
+chain 1373 chr2 243199373 + 243172974 243173045 chr8 146274826 + 8401 8472 3798112
+71
+
+chain 1350 chr2 243199373 + 87719705 87727637 chr2 242951149 + 87486442 87489057 666335
+5 4 8
+60 6231 0
+175 909 1819
+190 64 64
+294
+
+chain 1237 chr2 243199373 + 5143151 5144336 chr3 199501827 - 33955506 33956705 3724972
+50 1070 1084
+65
+
+chain 1182 chr2 243199373 + 1222834 1225214 chr2 242951149 + 1208599 1208809 9180420
+46 2248 78
+86
+
+chain 1157 chr2 243199373 + 87726368 87726988 chr2 242951149 + 87492753 87493373 434529
+59 53 53
+165 67 67
+36 57 57
+183
+
+chain 1107 chr2 243199373 + 5141765 5144570 chr1 247249719 + 5005582 5008225 2100127
+50 2701 2539
+54
+
+chain 1007 chr2 243199373 + 5142524 5142584 chr7 158821424 - 115940368 115940428 3379044
+60
+
+chain 998 chr2 243199373 + 234471343 234471369 chr18 76117153 + 53315026 53315052 2684166
+26
+
+chain 997 chr2 243199373 + 1223799 1223839 chr2 242951149 + 1209424 1209464 2284434
+40
+
+chain 932 chr2 243199373 + 87725722 87725751 chr2 242951149 + 87499077 87499106 1733344
+29
+
+chain 867 chr2 243199373 + 1226560 1226598 chr2 242951149 + 1209385 1209423 17548334
+38
+
+chain 822 chr2 243199373 + 5144726 5144801 chr2 242951149 - 76674151 76674226 3649555
+75
+
+chain 767 chr2 243199373 + 5141372 5141411 chr7 158821424 + 51905543 51905582 3310848
+39
+
+chain 651 chr2 243199373 + 5141336 5141372 chr5 180857866 - 59015526 59015562 2717102
+36
+
+chain 561 chr2 243199373 + 5140901 5140953 chr6 170899992 + 131686128 131686180 4225085
+52
+
+chain 545 chr2 243199373 + 90414124 90414152 chr7 158821424 - 94210194 94210222 18407154
+28
+
+chain 270 chr2 243199373 + 89868258 89868320 chrY 57772954 + 11916008 11916070 28746465
+62
+
+chain 5644665978 chr20 63025520 + 60000 62965520 chr20 62435964 + 8000 62435964 20
+26259569 3100000 1765661
+234339 150000 1000000
+4004088 1 0
+6459 244 0
+37810 2 0
+1044573 50000 20000
+9411883 8 2
+362 1 0
+11607353 1 0
+1301304 0 1
+31036 9 0
+1151 2 0
+1088 1 1
+29 1 1
+2509 2 0
+407 0 1
+40 1 1
+3787164 50000 27050
+71932 50000 110000
+694117 1 0
+1008033
+
+chain 3228736998 chr21 48129895 + 10697896 48119895 chr21 46944323 + 9719767 46944323 23
+490233 3150000 3050000
+19828060 1 0
+8789369 48801 0
+222468 500 500
+22014 1500 1500
+1381822 48641 0
+3438590
+
+chain 42537850 chr21 48129895 + 9411193 10647896 chr21_random 1679693 + 281005 1255172 87
+184355 489372 50000
+131056 281918 458754
+150002
+
+chain 16006699 chr21 48129895 + 9825437 10497894 chr21_random 1679693 - 0 756441 94
+158053 0 149427
+56 1 1
+500 1 1
+35 1 1
+276 1 1
+92 1 1
+413 12 12
+944 1 1
+31 1 1
+185 5 5
+93 1 1
+63 1 1
+959 0 1
+268 1 1
+33 1 1
+115 1 0
+12 0 2
+56 1 1
+99 1 1
+49 1 1
+65 1 1
+32 1 13
+425 1 1
+77 2 0
+252 0 7
+72 1 1
+96 1 1
+44 1 1
+197 7 7
+86 1 1
+32 1 1
+423 1 1
+26 1 1
+758 1 1
+77 1 1
+217 3 0
+50 1 1
+290 1 1
+112 1 1
+66 14 14
+116 18 22
+727 19 19
+140 4 0
+393 1 1
+28 1 1
+50 2 0
+38 6 1
+21 1 1
+80 1 1
+71 1 1
+179 1 1
+35 1 1
+69 1 1
+20 1 1
+216 1 1
+31 1 1
+182 1 1
+43 1 1
+97 1 1
+22 1 1
+87 1 1
+66 1 1
+72 1 1
+68 1 1
+312 1 1
+28 1 1
+478 1 1
+111 1 1
+191 1 1
+18 1 1
+98 1 2
+29 2 1
+57 1 1
+44 1 6
+74 1 1
+79 77 78
+186 1 1
+107 1 1
+202 2 2
+135 1 1
+95 0 3
+93 1 0
+48 5 0
+170 1 1
+43 1 0
+260 1 1
+23 1 1
+312 1 0
+26 1 0
+28 0 1
+87 0 10
+157 8 8
+900 1 1
+56 1 1
+235 1 1
+81 1 1
+156 1 1
+61 1 1
+156 1 1
+48 1 1
+65 12 12
+89 1 1
+158 2 2
+106 3 1
+375 0 2
+35 1 1
+73 1 1
+33 1 1
+392 2 0
+602 1 1
+66 1 1
+375 1 1
+55 1 1
+207 1 1
+25 2 2
+459 7 7
+188 1 3
+210 3 3
+28 0 4
+980 1 1
+15 1 1
+350 20 0
+636 0 4
+43 1 0
+539 63 64
+80 3 0
+142 8 7
+247 1 0
+908 1 1
+20 1 1
+128 0 1
+301 4 0
+56 2 2
+658 1 1
+34 1 1
+184 8 8
+162 0 2
+64 0 1
+80 1 1
+34 1 1
+121 1 1
+21 1 1
+374 1 1
+130 0 1
+47 1 1
+68 1 1
+35 4 0
+361 1 0
+73 1 1
+44 1 1
+392 1 1
+70 1 1
+76 1 1
+48 1 1
+216 1 1
+54 1 1
+67 4 4
+282 1 1
+44 1 1
+73 15 15
+166 4 0
+338 1 1
+27 1 1
+243 1 1
+101 1 1
+344 1 1
+51 1 1
+367 1 1
+35 0 1
+199 1 1
+18 1 1
+153 13 13
+102 0 1
+125 1 1
+49 1 1
+102 7 7
+100 18 18
+316 20 20
+151 0 2
+21 0 1
+575 1 0
+60 1 1
+60 1 1
+441 24 24
+364 1 0
+57 1 1
+158 10 10
+197 1 1
+49 1 0
+13 0 1
+5 1 1
+478 1 0
+244 22 22
+91 1 1
+80 5 5
+130 1 1
+26 1 1
+405 1 1
+51 1 1
+235 11 11
+330 1 1
+66 1 1
+85 342 17
+157 26 26
+261 1 1
+38 2 2
+824 20 20
+252 12 0
+119 1 1
+42 1 1
+1237 23 22
+103 1 1
+70 1 1
+155 1 1
+26 0 1
+80 1 1
+468 1 1
+60 1 1
+139 1 1
+53 2 2
+194 1 1
+35 1 1
+94 1 1
+56 1 1
+128 1 1
+40 1 1
+124 0 1
+54 1 1
+75 1 1
+79 1 1
+66 1 1
+82 0 1
+88 1 1
+146 0 3
+60 1 1
+67 2 2
+36 5 5
+147 1 1
+32 1 1
+185 1 1
+44 1 1
+68 40 15
+201 1 1
+37 1 1
+387 1 1
+18 1 1
+103 339913 274830
+131918
+
+chain 2365142 chr21 48129895 + 9686364 9760752 chr1 247249719 - 105115380 105189719 169
+453 1 1
+62 1 1
+312 9 9
+152 1 1
+34 1 1
+205 1 1
+109 44 0
+14 7 65
+203 5 5
+26 1 1
+70 1 1
+17 1 1
+847 1 1
+49 1 1
+99 1 1
+87 1 1
+51 1 1
+26 1 1
+374 1 1
+43 0 6
+139 1 1
+128 1 1
+54 1 1
+45 2 0
+17 1 1
+75 1 1
+59 1 1
+210 1 1
+70 1 1
+158 43 43
+56 12 12
+109 1 1
+48 5 5
+116 1 1
+49 1 1
+307 1 1
+45 1 1
+440 5 5
+106 9 9
+784 1 1
+42 1 1
+228 0 1
+114 17 17
+88 11 11
+161 1 1
+38 1 1
+825 2 2
+38 1 1
+105 22 22
+81 1 1
+29 1 1
+300 23 23
+147 1 1
+26 1 1
+164 1 1
+35 1 1
+227 6 6
+56 2 2
+109 1 1
+25 4 0
+116 15 23
+172 1 1
+40 1 1
+68 15 15
+158 7 7
+349 14 14
+133 1 1
+39 1 1
+145 12 12
+60 1 1
+43 1 1
+101 21 21
+307 1 1
+42 1 1
+93 1 1
+162 1 1
+143 1 1
+40 1 1
+54 1 1
+107 9 10
+319 1 1
+43 4 4
+200 1 1
+18 1 1
+127 1 1
+90 1 1
+250 3 3
+93 148 1
+443 0 1
+77 9 9
+295 1 1
+59 1 1
+438 31 31
+127 3 0
+88 1 1
+109 7 8
+79 14 14
+112 10 8
+114 1 1
+94 1 1
+150 10 7
+69 1 1
+110 1 1
+17 1 0
+222 0 1
+195 1 1
+16 1 0
+89 1 1
+123 38 0
+43 1 1
+83 1 1
+47 3 4
+64 0 3
+38 1 1
+268 1 1
+27 1 1
+230 17 17
+252 1 1
+24 0 3
+168 1 1
+41 5 0
+50 1 1
+212 9 9
+40 29 0
+271 1 1
+48 1 1
+124 1 1
+57 1 1
+125 16 16
+136 29 29
+157 1 1
+27 7 0
+482 10 4
+158 1 1
+62 1 1
+371 1 1
+83 1 1
+120 1 1
+45 1 1
+189 0 1
+84 1 1
+103 18 18
+494 1 1
+55 3 0
+139 1 1
+264 18 18
+75 2 3
+130 1 1
+97 1 1
+193 1 1
+25 1 1
+167 1 1
+49 1 1
+62 16 16
+65 13 13
+62 1 1
+101 1 1
+60 1 1
+50 1 1
+307 9 9
+131 13 13
+94 1 1
+78 1 1
+132 1 1
+27 1 1
+358 1 1
+21 1 1
+466 14 14
+590 1 1
+34 1 1
+242 1 1
+29 1 1
+116 1 1
+44 1 1
+117 1 1
+67 2 1
+71 1 1
+32 1 1
+506 18 18
+88 1 1
+27 1 1
+78 0 11
+215 1 1
+77 1 1
+291 1 1
+56 3 3
+126 1 1
+42 1 1
+332 9 9
+280 6 9
+641 15 15
+59 6 10
+31 1 1
+62 1 1
+40 1 1
+298 1 1
+40 1 1
+146 1 1
+66 1 0
+757 2 0
+169 1 1
+65 1 0
+285 1 1
+20 1 1
+109 1 1
+67 1 1
+68 1 1
+32 1 1
+93 4 4
+147 0 14
+646 0 1
+544 8 8
+47 1 0
+141 14 14
+678 1 0
+154 0 1
+346 1 1
+73 1 1
+232 5 5
+113 1 1
+32 2 0
+23 1 1
+92 10 10
+1121 1 1
+143 1 1
+300 1 1
+49 1 1
+392 5 5
+242 1 1
+21 1 1
+369 1 1
+67 1 1
+47 0 1
+618 23 23
+565 1 1
+140 1 1
+247 1 1
+41 1 1
+50 1 1
+18 1 1
+65 1 1
+66 1 1
+108 0 4
+158 1 1
+105 1 1
+70 1 1
+25 6 8
+77 1 1
+323 1 1
+28 1 1
+258 1 1
+47 1 1
+393 1 1
+72 1 1
+149 13 13
+142 1 0
+60 0 1
+78 4 4
+100 1 1
+51 1 1
+156 1 1
+20 1 1
+510 1 1
+22 1 0
+67 1 1
+54 1 1
+45 1 1
+133 1 1
+23 1 1
+63 1 1
+32 1 1
+349 1 1
+15 1 1
+103 1 1
+36 1 1
+119 1 1
+47 1 1
+312 4 4
+66 13 13
+357 0 76
+20 1 1
+177 1 1
+91 1 1
+52 1 1
+36 1 1
+141 10060 10099
+90 1 1
+49 1 1
+212 1 1
+20 1 1
+286 1 1
+48 2 1
+50 1 1
+67 8 8
+63 1 1
+30 1 1
+93 1 1
+48 1 1
+129 1 1
+46 1 1
+455 1 1
+46 3 0
+84 1 1
+39 0 1
+229 2 11
+79 4 4
+731 17 16
+725 8 8
+249 1 1
+78 1 1
+1065 3 0
+735 0 1
+124 10 10
+51 1 1
+35 1 1
+315 25 25
+749 6 6
+343 1 1
+29 1 1
+386 1 1
+24 1 1
+407 1 0
+73 1 1
+708 1 1
+71 0 1
+16 1 1
+92 1 1
+25 1 1
+447 14 14
+190 85 85
+60 1 1
+66 1 1
+238 1 1
+87 5 5
+118 7 7
+696 0 12
+49 1 1
+823 1 1
+77 1 1
+154 0 3
+102 12 12
+698 1 1
+21 1 1
+591 1 1
+16 1 1
+59 1 1
+27 1 1
+114 1 0
+593 1 1
+30 1 1
+1351 1 1
+17 1 1
+77 6 0
+647 1 1
+23 1 1
+235 1 1
+39 1 1
+141 1 1
+80 5 5
+181 10 11
+1091 1 1
+58 0 1
+19 1 1
+305 0 1
+429 17 17
+107 1 1
+25 1 1
+156 5 5
+22 1 1
+188
+
+chain 1441791 chr21 48129895 + 9645548 9775437 chr21_random 1679693 + 696416 826305 252
+40816 1341 1341
+44 2893 2893
+43 8663 8663
+148 1323 1323
+31 1767 1767
+38 1629 1629
+29 781 781
+29 25619 25619
+10060 6346 6346
+25 3590 3590
+85 9904 9904
+14685
+
+chain 891297 chr21 48129895 + 9995689 10034920 chr21_random 1679693 + 191774 231005 206
+77 9866 9866
+63 13134 13134
+342 157 157
+26 5919 5919
+40 750 750
+8857
+
+chain 2615495 chr21_gl000210_random 27682 + 0 27682 chr21_random 1679693 - 1650984 1679693 1058
+9933 367 719
+17272 0 675
+110
+
+chain 25569 chr21_gl000210_random 27682 + 10033 10300 chr21_random 1679693 - 1660317 1660584 5767478
+267
+
+chain 3320966530 chr22 51304566 + 16050000 51244566 chr22 49691432 + 14430000 49591432 22
+647850 150000 150000
+3661581 100000 50000
+15278437 18 0
+294 36 0
+1407 1 1
+46 1 1
+6626947 4 2
+1759 1 1
+43 1 1
+1367363 10613 11998
+7858 0 4
+809337 20 0
+6305 0 20
+6703 2669 50000
+4247674 0 10618
+1611 2719 0
+35235 131 0
+12642 0 4
+45595 9 85
+19564 506 0
+165499 7 5
+1103946 60575 16700
+644 2 0
+319796 1155 1600
+17927 15406 19700
+464629
+
+chain 11044 chr22 51304566 + 50772606 50772840 chr1 247249719 + 28744016 28744317 20648865
+55 103 170
+76
+
+chain 18404394637 chr3 198022430 + 60000 197962430 chr3 199501827 + 35000 199446827 3
+13552792 0 1
+585083 0 1
+2092 1 2
+71 0 1
+31067262 0 1
+90 1 0
+5628461 0 15
+788 1 0
+3676 0 2
+35 1 1
+4682 1 0
+1295 0 5
+437 53 42
+326 0 2
+3309 1 1
+40 1 1
+998 0 3
+3584 5 0
+930 5 7
+845 1 1
+28 2 1
+303 0 1
+507 0 5
+5088 1 0
+2185 10046 10048
+949 4 4
+35 1 1
+2874 0 1
+6717 0 1
+2823 1 0
+703 0 4
+5143 1 0
+2490 10 10
+162 7 7
+6308 0 15
+15177535 152352 260003
+2532 1 0
+1633 2 2
+24207544 3000000 4400000
+60453436 0 4
+40076813 20999 20000
+8195 1 1
+44 1 1
+1408 1 1
+33 1 1
+172 3 4
+25 1 1
+538 13 13
+173 1 1
+27 1 1
+636 1 1
+28 1 1
+470 3 3
+112 1 1
+375 1 1
+26 26 0
+115 78 0
+52 23 0
+104 26 0
+15 231 0
+56 1 1
+20 1 1
+815 16 16
+484 1 1
+49 18 0
+509 4 3
+23 1 1
+391 1 1
+44 1 1
+1278 0 4
+32 1 1
+263 4 0
+27 1 1
+2416 0 2
+3184 43 43
+1150 13 13
+736 1 1
+47 1 1
+1416 1 1
+20 1 1
+1020 1 1
+25 1 1
+482 5 0
+716 1 0
+1697 1 1
+29 1 1
+1270261 23108 27000
+40930 1 0
+17455 1 1
+28 4 4
+43 0 491
+1679 1 1
+33 7 5
+29 1 3
+54863 53 16
+7653 2 2
+29 2 2
+15 0 30
+180 0 75
+215 45 0
+360 915 0
+6188 96 0
+17 288 0
+1388 1 1
+37 1 1
+7956 0 1
+374 0 1
+2442058
+
+chain 905554 chr3 198022430 + 50925386 50935027 chr3 199501827 - 148591827 148601470 3167
+1111 0 6
+2584 0 1
+5889 6 1
+51
+
+chain 274603 chr3 198022430 + 195356374 195379482 chr3 199501827 - 629997 657219 690
+621 1 1
+42 1 1
+893 1 121
+66 1 1
+693 1 1
+27 1 1
+761 1 1
+79 2 2
+297 1 1
+40 1 1
+643 1 1
+22 1 1
+410 8 9
+110 1 1
+16 0 5
+314 3 0
+1846 4 7
+39 1 1
+420 10 9
+335 6 0
+238 0 1
+76 1 0
+310 1 2
+175 1 1
+17 1 1
+268 1 1
+46 1 1
+114 1 1
+19 1 1
+127 8 8
+30 1 1
+207 6 6
+62 9 9
+505 22 22
+160 1 1
+34 1 1
+187 1 1
+138 0 1
+844 1 1
+103 0 1
+65 3459 3402
+90 4 4
+90 42 794
+52 478 4
+78 154 154
+28 235 0
+59 1501 5454
+143 19 19
+425 7 54
+39 46 0
+75 8 8
+73 1 95
+58 1 1
+51 16 63
+140 1 1
+33 1 1
+682 1 1
+68 1 1
+147 1 1
+82 1 1
+119 33 0
+262 0 1
+54 1 0
+13 56 0
+111 5 5
+722 1 1
+19 1 1
+60 1 1
+33 1 0
+7 1 1
+108 0 2
+302 1 1
+68 1 0
+42 1 1
+50 1 1
+80 1 0
+95 1 1
+19 1 1
+119 0 1
+493 16 16
+316
+
+chain 30227 chr3 198022430 + 66156466 66156782 chr5 180857866 - 15729243 15729559 4617547
+316
+
+chain 25764 chr3 198022430 + 195503126 195503723 chr3 199501827 + 196988790 196989012 1952307
+75 360 0
+127 20 5
+15
+
+chain 19039 chr3 198022430 + 195503723 195504023 chr3 199501827 + 196988637 196988937 1894839
+300
+
+chain 11786 chr3 198022430 + 195373997 195374119 chr3 199501827 - 651916 652038 19355983
+122
+
+chain 9624 chr3 198022430 + 195503246 195503561 chr3 199501827 + 196988205 196988400 2003832
+53 137 2
+73 4 19
+48
+
+chain 7908 chr3 198022430 + 195510214 195510615 chr3 199501827 + 196993313 196993714 919394
+96 17 17
+288
+
+chain 6921 chr3 198022430 + 66275488 66275560 chr6 170899992 + 144236219 144236291 28346484
+72
+
+chain 6012 chr3 198022430 + 66274973 66275036 chr15 100338915 - 38411650 38411713 30540003
+63
+
+chain 5039 chr3 198022430 + 66276813 66276866 chr9 140273252 + 71084115 71084168 33364454
+53
+
+chain 4902 chr3 198022430 + 66152713 66152764 chr11 134452384 + 5803379 5803430 33869306
+51
+
+chain 3381 chr3 198022430 + 195371524 195371562 chr3 199501827 - 645118 645156 13662757
+38
+
+chain 3356 chr3 198022430 + 50925108 50925187 chr3 199501827 - 92152745 92152824 20266108
+79
+
+chain 2109 chr3 198022430 + 195371614 195371638 chr3 199501827 - 645161 645185 16027164
+24
+
+chain 1800 chr3 198022430 + 195503201 195503246 chr3 199501827 + 196989165 196989195 4219824
+23 17 2
+5
+
+chain 1295 chr3 198022430 + 195372257 195372308 chr3 199501827 - 2286585 2286636 21843906
+51
+
+chain 17653654354 chr4 191154276 + 10000 191029082 chr4 191273063 + 0 191263063 4
+1413146 71672 51000
+5369 6 5
+65 1 1
+67 1 1
+425 1 1
+32 1 1
+175 1 1
+34 1 1
+5092 1 1
+46 1 1
+1396 15 15
+1446 1 0
+1679 13 13
+3443 0 1
+586 1 1
+38 1 1
+18 21 0
+1582 6 0
+202 3 0
+92 0 6
+187 9 0
+4054 1 1
+71 1 1
+1413 1 83
+51 7 7
+105 7 7
+53 0 41
+81 1 42
+41 0 41
+37 0 41
+3274 1 94
+114 0 1116
+921 2 0
+935 0 55
+3639 15 15
+1167 0 3
+44 29 0
+44 0 29
+5146 1 1
+42 1 1
+3831 3 0
+23 1 1
+4171 6 6
+796 165 0
+196 99 0
+94 33 0
+183 8 6
+107 2 2
+21 2 0
+62 68 1
+32 15 14
+81 18 18
+55 1 0
+17 67 1
+188 133 0
+44 67 0
+43 35 0
+3289 18 18
+298 1 0
+373 1 0
+2965 1 1
+30 23 0
+1718 38 0
+98 38 0
+53 44 7
+116 0 77
+272 1 1
+70 1 1
+1591 49 49
+360 33 23
+2400 1 1
+94 1 1
+6002 1 1
+16 1 1
+776 0 1
+324 46 46
+433 0 51
+53 27 1
+2181 4 1
+57 1 1
+1969 0 10
+4188 11 11
+1595 18 0
+2050 109 0
+4319 7 0
+50 4 0
+1464 1 3
+4156 0 2
+5455 2 3
+129 4 4
+9082 1 0
+786 20 20
+1506 1 0
+252 7 8
+17512 1 50
+56 0 1
+2474 52 69
+75 30 0
+61 0 16
+11 0 15
+41 1 1
+133 0 16
+79 17 0
+16 29 0
+3375 1 0
+969 4 0
+1623 11 11
+1065 3 0
+2934 0 8
+2323 181 0
+2290 0 1
+1641 1 6
+1955 1 0
+68 1 1
+347 1 1
+40 1 1
+1553 0 6
+678 16 16
+92 33 0
+390 0 4
+1147 1 0
+1948 4 4
+4296 1 1
+16 1 1
+955 1 1
+47 1 1
+1555 0 1
+2251509 0 81122
+171 1 1
+48 1 1
+718 0 1
+2789 1 1
+27 1 1
+1601 0 4
+1907 2 0
+31 1 5
+16 0 4
+76 2 0
+13 4 0
+27 1 0
+12 1 9
+1772 6 0
+22 1 1
+946 1 1
+24 1 1
+1245 0 1
+3231 1 1
+41 1 1
+736 4 4
+912 1 1
+18 1 1
+11270 0 3
+2704 1 1
+41 1 1
+1812 6 5
+1477 11 0
+1744 6 6
+2039 0 4
+2188 1 1
+48 1 1
+1704 1 1
+73 1 1
+2265 12 12
+553 1 1
+49 1 1
+67 1 1
+33 1 1
+3935 0 5
+15 0 1
+780 1 0
+1260 1 0
+4204 25 0
+862 14 14
+7114 1 1
+70 1 1
+169 1 0
+43 1 1
+145 1 1
+39 3 0
+8 1 1
+753 1 0
+1535 41 41
+679 1 1
+21 1 1
+1605 1 1
+19 1 2
+392 1 1
+29 0 1
+3673 0 1
+145 14 14
+39 1 0
+1246 1 0
+2302 0 1
+1554 9 9
+4537 1 0
+1064 0 2
+2051 0 1
+1130 2 0
+164 0 1
+1972 1 0
+18 3 3
+2597 1 1
+46 3 3
+196 1 1
+17 1 1
+60 4 4
+187 4 4
+46 1 1
+692 0 1
+3382 41 41
+497 3 3
+15 1 1
+486 14 14
+1709 0 8
+169 0 1
+597 1 1
+18 7 0
+3423937 1 0
+1295496 1 1
+26 1 1
+760 591802 150000
+22468468 1 1
+27 1 1
+2592 2 0
+33 1 1
+2065 0 3
+1050 11 11
+1046 9 3
+3263 0 1
+906 0 1
+1643 0 6
+1181 1 0
+475 5 0
+2522 0 4
+407 1 0
+517 77 77
+1122 36199 70999
+976587 26528 59000
+7703 4 0
+4545 9 9
+4740 1 0
+1862 0 1
+3316 3 7
+51 14 14
+1066 1 0
+1795 0 1
+569 0 1
+2895 1 1
+39 1 1
+461 0 3
+3168 6 6
+2197 0 1
+6774 2 0
+2504 2 0
+1247 1 1
+45 1 1
+2415 17 17
+4792 36 36
+3387 20 20
+272 10 10
+420 1 1
+34 1 1
+7961 0 4
+1973 1 1
+45 0 1
+529 0 1
+603 1 0
+18 1 1
+606 4 0
+65 1 25
+41 0 8
+517 1 0
+1400 41 38
+3786 1 0
+228 0 3
+1026 1 1
+49 1 1
+3336 3 0
+951 1 1
+77 1 2
+441 2 1
+1833 9 9
+301 5 5
+2787 17 17
+1747 0 1
+3040 9 2
+81 10 10
+86 0 2
+2113 45 45
+7352791 1606 20000
+1651 0 2
+45 16 0
+13956 8 0
+1947 3 0
+1255 1 1
+38 1 0
+1778 4 0
+22 1 0
+1045 0 6
+1327 1 0
+5775 1 1
+18 1 1
+1933 0 1
+1716 13 13
+255 0 1
+124 3 0
+792 5 0
+1521 1 1
+64 1 1
+9005617 150000 150000
+171176 3000000 3000000
+7074452 62111 50000
+5257 1 0
+2845 0 2
+1387 1 0
+114 0 1
+2385 4 0
+65 6 6
+62 0 4
+18 1 0
+100 51 0
+9781577 0 351994
+1903288 0 184275
+3925704 13 13
+435 1 1
+21 1 1
+838 1 0
+281 35 35
+491 6 6
+74 1 1
+43 1 1
+652 29839 30000
+13847966 1 0
+14069801 0 2
+8504 1 0
+32265 0 8
+12730 2 0
+35327 14 12
+1503 0 1
+1334 0 1
+759 1 0
+10036 1 7
+9912 17 18
+2523 0 1
+1321 1 0
+8984 0 2
+5505 20 20
+9694 6 6
+22003 0 9
+578 1 0
+5166 0 2
+92208 5 2
+8 0 1
+5 2 0
+110 0 4
+848 7 6
+2247 1 3
+3770 1 0
+5719 2 0
+2511 1 0
+1557 1 0
+5812 1 0
+3607 1 0
+7405 0 1
+11075 1 0
+2794 0 1
+2340 0 1
+429 1 0
+233 27 27
+262 0 2
+2397 0 5
+371 0 11
+1376 0 1
+2416 0 8
+210 1 1
+20 1 1
+5104 1 1
+20 1 1
+525 0 2
+836 1 0
+2094 0 1
+2213 0 3
+327 6 9
+1711 45 45
+837 1 1
+57 1 1
+1618 1 0
+1400 0 4
+254 2 0
+93 0 10
+755 6 0
+192 1 0
+2378 1 0
+1753 0 3
+644 14 14
+1244 4 0
+30 1 1
+1136 14 14
+2450 0 4
+3624 3 31
+456 14 14
+1076 8 7
+68 1 1
+20 1 1
+145 1 1
+68 0 1
+12 1 0
+10 1 0
+11 0 1
+35 0 1
+5 1 0
+11 2 1
+32 7 6
+35 0 1
+8722 0 1
+888 4 0
+456 0 3
+45 1 0
+151 13 13
+756 1 0
+203 7 8
+140 1 1
+20 1 1
+308 0 5
+1020 1 0
+1258 1 0
+160 2 0
+1411 1 1
+22 1 1
+1180 12 12
+4521 2 0
+1153 0 27
+4956 0 3
+1392 1 1
+47 1 1
+3854 1 2
+130 0 1
+2633 0 2
+3030 1 0
+2343 1 0
+1748 45 0
+731 0 2
+1336 11 9
+3899 6 0
+436 0 1
+981 1 0
+1326 1 0
+382 0 4
+1081 0 10
+81 1 1
+142 2 0
+5976 1 1
+26 1 1
+377 22 22
+86 1 0
+55 1 1
+93 1 1
+374 4 0
+38 6 0
+3944 0 347
+1034 1 1
+27 1 1
+60 0 2
+2581 0 3
+3882 4 0
+1790 1 0
+20 1 1
+356 0 1
+4244 5 5
+36 1 1
+2232 2 2
+42 1 1
+4462 2 0
+1611 0 1
+1290 2 0
+110 0 1
+1466 1 0
+357 0 3
+850 0 12
+13547766 1 0
+3724943 0 2
+46473408 1 0
+1696 1 1
+28 1 1
+1629 4 0
+666 0 4
+13464 12874 30000
+8520008 0 2
+1107 1 1
+15 1 1
+1892 4 0
+6798 2 0
+1793 1 1
+25 3 0
+421 0 389
+787 0 2
+545 2 0
+54 0 1
+143 1 1
+39 1 1
+89 1 1
+29 0 1
+171 1 1
+46 0 1
+192 1 1
+33 1 1
+336 18 18
+2226 1 0
+107 1 1
+29 1 1
+218 0 1
+175 5 6
+1407 1 1
+52 1 1
+8851 0 1
+14427 0 4
+1737 0 22
+5806 0 1
+1115 1 1
+29 2 0
+3395 1 0
+386 38 38
+2740 2 0
+522 0 1
+24 1 1
+658 0 4
+5724 9 9
+1209 1 0
+5380 0 1
+97 0 1
+853 0 4
+79 11 5
+2728 7 6
+3754 13 17
+1363 0 1
+1025 0 1
+1811 1 0
+7507 4 0
+1184 0 3
+763 0 1
+797 0 3
+293 0 2
+2488 1 0
+335 1 0
+9959 0 1
+3255 0 1
+1322 1 0
+8118 0 2
+3326 0 2
+632 0 1
+63 5 0
+1886 12 12
+1110 1 0
+9582 1 0
+14742673 3013 0
+39686
+
+chain 9245037 chr4 191154276 + 8829368 8925617 chr4_random 842648 + 239789 336038 353
+96249
+
+chain 1255876 chr4 191154276 + 9214880 9257600 chr4 191273063 + 8933741 8943231 721
+156 22 22
+1030 14 14
+303 27 27
+166 4935 184
+220 23 24
+72 54 54
+771 13 13
+270 4744 0
+2627 17 17
+289 4743 0
+890 4745 0
+772 9500 0
+268 4749 1
+266 11 11
+1023
+
+chain 912330 chr4 191154276 + 9211690 9265763 chr4 191273063 + 8940042 8979863 947
+75 220 220
+51 122 122
+54 54 54
+51 167 167
+180 47 47
+70 24 24
+94 37 37
+257 59 59
+316 11 11
+163 60 60
+53 61 61
+95 21 21
+109 24 24
+217 32 32
+186 47 47
+233 1926 1924
+88 13 13
+123 125 126
+1453 4747 0
+2227 0 1
+278 535 535
+213 87 87
+92 7 7
+755 18715 9222
+268 6439 6434
+1089 14 14
+243 9 9
+78 4 4
+157 214 209
+200 23 24
+72 5972 5972
+655 413 413
+1441 14 14
+243 9 9
+78 4 4
+157 213 209
+200 23 24
+72 54 54
+771 13 13
+119 17 17
+221
+
+chain 676976 chr4 191154276 + 191033807 191044200 chr4 191273063 - 191263147 191273063 1558
+68 4 0
+34 1 1
+323 3 3
+31 1 1
+807 1 1
+26 1 1
+526 2 3
+34 1 0
+704 1 0
+6 1 0
+240 1 0
+237 2 0
+8 1 1
+371 10 0
+264 1 0
+205 1 1
+57 1 0
+601 1 1
+15 1 1
+1214 4 8
+1661 3 0
+94 1 1
+50 1 1
+355 15 15
+638 1 1
+54 1 1
+54 8 9
+323 67 9
+85 0 1
+96 1 1
+58 1 1
+35 1 0
+31 1 1
+86 1 1
+30 1 1
+76 1 1
+40 1 1
+121 282 27
+49 53 0
+63 92 0
+52
+
+chain 512088 chr4 191154276 + 8956990 9037962 chr4 191273063 + 9100119 9179836 26299
+71 118 113
+60 152 152
+88 33 33
+136 71 71
+85 43 43
+87 66 66
+92 87 87
+88 187 185
+156 1 81
+67 128 129
+76 143 143
+50 44 44
+212 52 52
+64 13 16
+267 79 79
+284 58 58
+51 76 76
+51 94 91
+55 77 77
+95 15 15
+74 251 251
+116 107 28
+64 188 188
+77 4 4
+113 11 11
+62 44 44
+102 237 237
+154 79 79
+58 86 86
+53 39 39
+50 36 35
+412 36 36
+75 225 225
+313 30 30
+54 84 83
+69 156 147
+104 89 77
+54 162 162
+226 16 16
+95 26 26
+60 14 14
+59 8 8
+120 7 7
+162 67 67
+65 210 210
+112 204 203
+63 53 53
+50 140 139
+127 143 143
+149 97 97
+88 61282 60044
+56 370 381
+50 56 56
+84 370 368
+52 288 288
+54 25 25
+72 923 933
+55 768 765
+68 70 70
+52 196 196
+62 305 305
+50 43 43
+129 114 114
+53 66 65
+116 411 423
+58 314 324
+68 0 1
+123 0 1
+53 58 59
+116 401 399
+539 6 0
+397 18 18
+60 211 211
+55 175 175
+63 553 556
+55 10 10
+53 1024 1003
+58 34 34
+81 43 43
+75 9 9
+51 1 0
+69
+
+chain 476298 chr4 191154276 + 9230645 9271936 chr4 191273063 + 8940012 8967053 893
+192 87 88
+429 187 187
+754 4750 6
+744 23 25
+2003 14 14
+246 42 42
+74 48 48
+71 104 104
+291 226 226
+81 4533 4529
+47 562 562
+111 285 285
+89 35 35
+2637 17 17
+240 9 9
+78 4 4
+157 215 209
+179 17 17
+100 4802 54
+343 13 13
+785 10920 6171
+1114 17 17
+243 6 6
+58 2 1
+272 1 0
+404 10 10
+1194 31 31
+266 11 11
+770 21 21
+327
+
+chain 377656 chr4 191154276 + 9257600 9267189 chr4 191273063 + 8933740 8938580 708
+1209 17 17
+571 1 0
+1617 4779 31
+1395
+
+chain 310844 chr4 191154276 + 9241835 9252105 chr4 191273063 + 8941714 8947231 850
+2726 14 14
+243 9 9
+78 4 4
+157 213 211
+265 85 85
+524 4751 0
+379 283 283
+539
+
+chain 275688 chr4 191154276 + 190986479 190989396 chr4 191273063 + 191223755 191226674 1129
+58 2 0
+265 1 0
+205 0 1
+208 4 5
+205 1 0
+122 55 53
+54 0 1
+411 25 25
+282 1 0
+419 14 20
+585
+
+chain 164691 chr4 191154276 + 9225860 9240813 chr4 191273063 + 8954210 8973910 1376
+232 87 87
+216 5946 5946
+93 12 12
+116 46 46
+231 32 32
+884 2511 7257
+718 3769 3770
+60
+
+chain 136190 chr4 191154276 + 9219745 9221340 chr4 191273063 + 8971822 8973417 7780
+1090 14 14
+243 9 9
+78 80 80
+81
+
+chain 127110 chr4 191154276 + 9223074 9241806 chr4 191273063 + 8960913 8979648 1585
+266 11 11
+4 10400 10401
+206 20 21
+668 26 27
+395 17 17
+14 6682 6682
+23
+
+chain 113888 chr4 191154276 + 59794841 59796661 chr7 158821424 + 43068053 43069865 1124766
+203 13 13
+161 140 141
+116 42 42
+240 178 178
+142 63 63
+254 11 11
+90 67 58
+100
+
+chain 91306 chr4 191154276 + 9218608 9227700 chr4 191273063 + 8961194 8975031 2525
+1019 3329 8072
+118 4492 4494
+89 35 35
+10
+
+chain 70288 chr4 191154276 + 9018276 9021043 chr11 134452384 - 130908986 130911761 1790585
+117 359 362
+150 330 330
+55 237 237
+99 73 73
+100 253 253
+70 73 78
+137 311 312
+72 249 248
+82
+
+chain 69967 chr4 191154276 + 8969559 8971297 chr11 134452384 - 66940622 66942298 1798470
+59 244 176
+78 49 49
+76 0 4
+72 217 218
+85 102 102
+264 12 12
+52 246 247
+66 24 24
+92
+
+chain 66013 chr4 191154276 + 9271936 9272654 chr4 191273063 + 8948073 8948792 572417
+692 0 1
+26
+
+chain 45624 chr4 191154276 + 9079872 9084019 chr4 191273063 - 187198263 187202501 2810559
+137 1640 1673
+114 79 83
+52 281 281
+64 700 698
+99 226 253
+83 576 605
+96
+
+chain 42774 chr4 191154276 + 9272654 9274373 chr4 191273063 + 8958282 8960000 1428
+395 17 17
+243 6 6
+329 3 2
+726
+
+chain 41852 chr4 191154276 + 9086638 9087081 chr1 247249719 - 105679719 105680162 3102182
+443
+
+chain 32596 chr4 191154276 + 9003477 9005348 chr8 146274826 + 6937943 6939835 4188535
+92 357 358
+96 443 443
+52 521 541
+122 129 129
+59
+
+chain 27953 chr4 191154276 + 9001038 9001387 chr11 134452384 - 130891915 130892264 5650797
+153 24 24
+85 11 11
+76
+
+chain 25460 chr4 191154276 + 1547039 1548332 chr4 191273063 + 1517808 1518962 1406869
+132 196 194
+8 33 0
+58 94 94
+33 400 430
+53 219 85
+67
+
+chain 23919 chr4 191154276 + 9060276 9060815 chrX 154913754 - 61464264 61464816 7738233
+150 249 262
+51 8 8
+81
+
+chain 23663 chr4 191154276 + 9250380 9252971 chr4 191273063 + 8954996 8957588 1596
+343 1382 1382
+494 21 21
+330 20 21
+1
+
+chain 23348 chr4 191154276 + 8954155 8955149 chr13 114142980 + 67377165 67378170 8084807
+108 119 119
+58 448 459
+78 128 128
+55
+
+chain 23051 chr4 191154276 + 9178657 9179321 chr8 146274826 - 138181840 138182484 8260527
+67 301 281
+58 86 86
+152
+
+chain 21854 chr4 191154276 + 9064978 9065877 chr1 247249719 + 159299736 159300622 9096955
+140 389 376
+61 239 239
+70
+
+chain 20302 chr4 191154276 + 59794670 59795934 chr19 63811651 - 51831683 51832948 1313667
+101 447 447
+6 69 70
+65 116 116
+17 4 4
+21 351 351
+67
+
+chain 19591 chr4 191154276 + 9123525 9124535 chr8 146274826 - 133912952 133913964 10789494
+68 696 699
+88 66 65
+92
+
+chain 17609 chr4 191154276 + 9152849 9153208 chr8 146274826 - 133934464 133934826 12466518
+149 157 160
+53
+
+chain 17420 chr4 191154276 + 9097653 9099623 chr11 134452384 - 51628045 51630034 12637575
+61 831 818
+58 894 926
+126
+
+chain 17154 chr4 191154276 + 8944061 8944687 chr3 199501827 - 68270290 68270918 12891537
+94 361 363
+56 52 52
+63
+
+chain 16449 chr4 191154276 + 9179756 9180625 chr8 146274826 + 7630543 7631403 13585678
+50 232 222
+54 427 428
+106
+
+chain 16159 chr4 191154276 + 9066614 9068459 chr16 88827254 - 83675354 83677175 13878826
+62 1020 1018
+99 597 575
+67
+
+chain 16115 chr4 191154276 + 9109381 9109952 chr21 46944323 + 28460282 28460853 13923553
+84 119 119
+62 249 249
+57
+
+chain 15306 chr4 191154276 + 8980490 8981996 chr4 191273063 - 187061282 187061823 14745791
+66 1267 302
+72 36 36
+65
+
+chain 15299 chr4 191154276 + 9056645 9056806 chr7 158821424 - 61471183 61471344 14752363
+161
+
+chain 14776 chr4 191154276 + 8950227 8950452 chr10 135374737 - 120304145 120304370 15312555
+84 55 55
+86
+
+chain 14403 chr4 191154276 + 9126194 9127408 chr5 180857866 - 26856190 26857401 15732261
+94 264 256
+54 752 757
+50
+
+chain 14224 chr4 191154276 + 8969618 8970298 chr11 134452384 - 67220551 67221216 1931088
+4 94 93
+78 397 383
+107
+
+chain 14155 chr4 191154276 + 9145781 9146043 chrX 154913754 - 45908091 45908403 16013758
+81 98 148
+83
+
+chain 14099 chr4 191154276 + 9060197 9060675 chr3 199501827 + 53477967 53478452 7798477
+58 172 171
+90 137 145
+21
+
+chain 13997 chr4 191154276 + 9005833 9006439 chr8 146274826 - 139204211 139204817 16201090
+60 438 438
+108
+
+chain 13823 chr4 191154276 + 8945988 8946280 chr4 191273063 + 9373057 9373350 16411372
+60 133 134
+99
+
+chain 13439 chr4 191154276 + 8975637 8975779 chr3 199501827 + 126919507 126919649 16900342
+142
+
+chain 12765 chr4 191154276 + 9077064 9077200 chr1 247249719 - 177698311 177698447 17836871
+136
+
+chain 12497 chr4 191154276 + 8950452 8951505 chr4 191273063 - 187091946 187092996 17010995
+3 953 950
+97
+
+chain 12348 chr4 191154276 + 8983189 8983604 chr8 146274826 - 138673776 138674197 18460871
+61 268 274
+86
+
+chain 11880 chr4 191154276 + 8972496 8973020 chr14 106368585 - 55089898 55090495 19186930
+61 378 451
+85
+
+chain 11818 chr4 191154276 + 9096126 9096305 chr11 134452384 - 67086036 67086266 19295429
+55 42 93
+82
+
+chain 11496 chr4 191154276 + 8948423 8949198 chr12 132349534 + 50778185 50778960 19846856
+94 629 629
+52
+
+chain 11391 chr4 191154276 + 8947143 8947401 chr8 146274826 - 134472454 134472711 20027902
+53 123 122
+82
+
+chain 11111 chr4 191154276 + 9107828 9107946 chr16 88827254 + 2897686 2897804 20531108
+118
+
+chain 10916 chr4 191154276 + 9261701 9262066 chr4 191273063 + 8952078 8952443 1072
+365
+
+chain 10832 chr4 191154276 + 8994164 8994326 chr6 170899992 - 100664994 100665156 21051510
+55 36 36
+71
+
+chain 10756 chr4 191154276 + 8943247 8943361 chr4 191273063 + 9116977 9117091 21193988
+114
+
+chain 10679 chr4 191154276 + 191030273 191030443 chr3 199501827 + 127002379 127002551 21342971
+68 44 46
+58
+
+chain 10668 chr4 191154276 + 1582572 1582681 chr4 191273063 + 1552756 1552865 12282737
+109
+
+chain 10529 chr4 191154276 + 191032229 191032410 chr11 134452384 + 3430296 3430477 21654608
+64 55 55
+62
+
+chain 10273 chr4 191154276 + 9096703 9097008 chr3 199501827 + 187858881 187859186 22199926
+64 181 181
+60
+
+chain 10137 chr4 191154276 + 9099965 9100095 chr6 170899992 - 166526436 166526567 22497437
+61 12 13
+57
+
+chain 10052 chr4 191154276 + 9066676 9066805 chr10 135374737 - 108696851 108696974 16846521
+41 9 9
+20 6 0
+53
+
+chain 9949 chr4 191154276 + 8999157 8999260 chr6 170899992 + 1823421 1823524 22925909
+103
+
+chain 9823 chr4 191154276 + 9071238 9072065 chr19 63811651 - 22299002 22299820 23218142
+65 697 688
+65
+
+chain 9746 chr4 191154276 + 8950613 8951219 chr7 158821424 - 151976579 151977185 23399634
+66 481 481
+59
+
+chain 9713 chr4 191154276 + 9012936 9013126 chrX 154913754 + 119487462 119487653 23485630
+58 74 75
+58
+
+chain 9679 chr4 191154276 + 9083038 9083589 chr12 132349534 + 77527128 77527707 10056562
+24 185 212
+17 262 263
+63
+
+chain 9579 chr4 191154276 + 9105290 9105637 chr8 146274826 - 6609 6954 23801877
+63 229 227
+55
+
+chain 9552 chr4 191154276 + 8956536 8957179 chr8 146274826 - 139187457 139188099 13944787
+92 234 234
+51 240 239
+26
+
+chain 9532 chr4 191154276 + 8978497 8978597 chr21 46944323 - 3695413 3695513 23932747
+100
+
+chain 9412 chr4 191154276 + 9108273 9108605 chr2 242951149 + 34780701 34781033 24211634
+61 216 216
+55
+
+chain 9361 chr4 191154276 + 9207159 9207725 chr7 158821424 + 92958588 92959148 24306771
+65 445 439
+56
+
+chain 9304 chr4 191154276 + 8946418 8946780 chr13 114142980 + 45938942 45939304 24422281
+63 247 247
+52
+
+chain 9136 chr4 191154276 + 9129485 9129655 chr1 247249719 - 82404984 82405154 24736407
+59 59 59
+52
+
+chain 9105 chr4 191154276 + 8982741 8983189 chr10 135374737 - 120304868 120305301 22041837
+59 380 365
+9
+
+chain 8777 chr4 191154276 + 9118310 9118402 chr11 134452384 - 67092191 67092283 25280535
+92
+
+chain 8617 chr4 191154276 + 59794359 59794524 chrX 154913754 + 69736929 69737094 2995761
+75 86 86
+4
+
+chain 8389 chr4 191154276 + 9219628 9219725 chr4 191273063 + 8933741 8933838 871949
+97
+
+chain 8260 chr4 191154276 + 8989895 8989983 chr4 191273063 + 9362532 9362620 26013719
+88
+
+chain 8131 chr4 191154276 + 9102626 9102711 chr4 191273063 - 187087880 187087965 26219988
+85
+
+chain 7754 chr4 191154276 + 190986383 190986479 chr10 135374737 + 135327923 135328019 562
+96
+
+chain 7688 chr4 191154276 + 8999849 9001530 chr8 146274826 + 7459813 7461495 7287525
+76 15 15
+50 236 236
+59 1157 1158
+88
+
+chain 7445 chr4 191154276 + 1642823 1642928 chr4 191273063 + 1612696 1612801 10569689
+105
+
+chain 7390 chr4 191154276 + 9235101 9235376 chr4 191273063 + 8934980 8935255 884
+275
+
+chain 6985 chr4 191154276 + 9132536 9132609 chr10 135374737 + 82556085 82556158 28236044
+73
+
+chain 6957 chr4 191154276 + 9079830 9084724 chr8 146274826 - 133860764 133864463 3584848
+42 1125 1126
+68 534 536
+50 1109 1111
+56 1741 541
+169
+
+chain 6924 chr4 191154276 + 9086283 9086357 chr3 199501827 + 28200221 28200295 17749225
+74
+
+chain 6522 chr4 191154276 + 59794524 59794670 chr4 191273063 + 131104023 131104168 2551460
+51 42 41
+53
+
+chain 6459 chr4 191154276 + 191029213 191029282 chr11 134452384 - 63299390 63299459 29377341
+69
+
+chain 6349 chr4 191154276 + 8971797 8971864 chr9 140273252 + 68477506 68477573 29649127
+67
+
+chain 6310 chr4 191154276 + 1548554 1548645 chr4 191273063 + 1518821 1518912 10939184
+91
+
+chain 6297 chr4 191154276 + 59793454 59794143 chr3 199501827 - 40571037 40571724 2330420
+79 562 560
+48
+
+chain 6221 chr4 191154276 + 9064020 9064085 chr16 88827254 - 83673859 83673924 29990023
+65
+
+chain 6094 chr4 191154276 + 9110081 9110145 chr1 247249719 + 181849295 181849359 30306899
+64
+
+chain 6086 chr4 191154276 + 191030472 191030537 chr11 134452384 - 75925756 75925821 30317869
+65
+
+chain 5966 chr4 191154276 + 9104473 9104535 chr11 134452384 + 71003965 71004027 30644952
+62
+
+chain 5912 chr4 191154276 + 8947661 8947723 chr9 140273252 - 2802727 2802789 30796182
+62
+
+chain 5903 chr4 191154276 + 9101296 9101358 chr4 191273063 + 9087606 9087668 30814689
+62
+
+chain 5842 chr4 191154276 + 9036574 9036668 chr4 191273063 - 85960898 85960992 17872768
+94
+
+chain 5712 chr4 191154276 + 9132160 9132220 chr12 132349534 + 8264132 8264192 31330015
+60
+
+chain 5710 chr4 191154276 + 191042876 191042934 chr4 191273063 - 191272139 191272197 15878613
+58
+
+chain 5622 chr4 191154276 + 9070424 9070484 chr3 199501827 - 68123367 68123427 31584493
+60
+
+chain 5594 chr4 191154276 + 1547006 1547408 chr4 191273063 + 1517841 1518435 2949224
+33 336 530
+7 8 6
+18
+
+chain 5494 chr4 191154276 + 8989383 8989441 chr10 135374737 + 82555871 82555929 31956576
+58
+
+chain 5493 chr4 191154276 + 9123841 9123899 chr3 199501827 - 55547554 55547612 22296298
+58
+
+chain 5485 chr4 191154276 + 9108193 9108251 chr17 78774742 + 49845783 49845841 31992260
+58
+
+chain 5354 chr4 191154276 + 9123785 9123841 chr19 63811651 + 46743056 46743112 26997396
+56
+
+chain 5287 chr4 191154276 + 191044097 191044231 chr11 134452384 + 134452193 134452328 8509115
+51 52 53
+31
+
+chain 5247 chr4 191154276 + 1642928 1642982 chr4 191273063 + 1612682 1612736 32710536
+54
+
+chain 5146 chr4 191154276 + 9109529 9109584 chr3 199501827 + 191350023 191350078 20827932
+55
+
+chain 5102 chr4 191154276 + 9012475 9012528 chr7 158821424 - 61434988 61435041 33179954
+53
+
+chain 4979 chr4 191154276 + 59793133 59793454 chr14 106368585 + 47992116 47992437 1636209
+52 1 1
+72 116 116
+45 1 1
+34
+
+chain 4919 chr4 191154276 + 59793533 59793585 chr1 247249719 + 177132715 177132767 25644257
+52
+
+chain 4894 chr4 191154276 + 8980336 8980388 chr8 146274826 - 134343460 134343512 33871905
+52
+
+chain 4776 chr4 191154276 + 59793593 59793649 chr8 146274826 + 78720544 78720600 25267381
+56
+
+chain 4646 chr4 191154276 + 9032086 9032149 chr11 134452384 - 67001981 67002044 11075042
+63
+
+chain 4523 chr4 191154276 + 9083642 9083690 chr4 191273063 + 9229696 9229744 33561479
+48
+
+chain 4481 chr4 191154276 + 9110034 9110081 chr1 247249719 + 117212387 117212434 31311635
+47
+
+chain 4466 chr4 191154276 + 8975249 8975296 chr4 191273063 + 9087559 9087606 34734206
+47
+
+chain 4380 chr4 191154276 + 9065601 9065685 chr14 106368585 - 65288844 65288928 12690014
+84
+
+chain 4316 chr4 191154276 + 8994219 8994386 chr9 140273252 - 20618312 20618467 21123765
+25 83 71
+59
+
+chain 4224 chr4 191154276 + 1548697 1548764 chr4 191273063 + 1518798 1518831 14337246
+14 34 0
+19
+
+chain 4196 chr4 191154276 + 59793649 59793759 chr3 199501827 - 110817223 110817333 10064550
+110
+
+chain 4174 chr4 191154276 + 9006462 9006529 chr3 199501827 - 68301162 68301229 17546615
+67
+
+chain 4160 chr4 191154276 + 9087190 9087234 chr3 199501827 + 69469088 69469132 19451262
+44
+
+chain 4035 chr4 191154276 + 59793991 59794095 chr4 191273063 - 43511377 43511481 1601554
+104
+
+chain 3949 chr4 191154276 + 59793891 59793960 chr7 158821424 - 5091499 5091568 15707336
+69
+
+chain 3917 chr4 191154276 + 59794575 59794617 chr19 63811651 + 46686810 46686852 11955254
+42
+
+chain 3916 chr4 191154276 + 9180332 9180405 chr8 146274826 + 7130141 7130214 14314247
+73
+
+chain 3790 chr4 191154276 + 9231440 9231540 chr4 191273063 + 8950300 8950400 218917
+92 7 7
+1
+
+chain 3686 chr4 191154276 + 59793772 59793811 chr15 100338915 + 77825223 77825262 17426618
+39
+
+chain 3659 chr4 191154276 + 9096554 9096861 chr3 199501827 - 6400721 6401028 23757316
+67 190 190
+50
+
+chain 3657 chr4 191154276 + 59794470 59794516 chr6 170899992 - 3232006 3232052 26376367
+46
+
+chain 3647 chr4 191154276 + 1557695 1557733 chr4 191273063 + 1527878 1527916 12331685
+38
+
+chain 3642 chr4 191154276 + 9109808 9109863 chr6 170899992 - 83529676 83529731 23755843
+55
+
+chain 3437 chr4 191154276 + 9178724 9179540 chr12 132349534 + 34224690 34225504 10931865
+32 667 665
+117
+
+chain 3342 chr4 191154276 + 9274373 9274605 chr4 191273063 + 8969490 8969722 4902
+232
+
+chain 3310 chr4 191154276 + 8971045 8971455 chr9 140273252 - 10330739 10331149 20511421
+70 288 288
+52
+
+chain 3302 chr4 191154276 + 1548711 1548745 chr4 191273063 + 1518614 1518648 32145222
+34
+
+chain 3283 chr4 191154276 + 9102560 9102594 chr10 135374737 - 120311822 120311856 35225233
+34
+
+chain 3261 chr4 191154276 + 8994091 8994458 chr8 146274826 + 9742146 9742512 23065618
+62 246 245
+59
+
+chain 3172 chr4 191154276 + 59794789 59794841 chr3 199501827 - 24852035 24852087 14612523
+52
+
+chain 3108 chr4 191154276 + 9060565 9060615 chr13 114142980 - 41995201 41995251 9632166
+50
+
+chain 3078 chr4 191154276 + 1548520 1548554 chr4 191273063 + 1518360 1518394 5794973
+34
+
+chain 3017 chr4 191154276 + 9065206 9065807 chr10 135374737 + 117208692 117209275 9578047
+65 480 462
+56
+
+chain 2924 chr4 191154276 + 59795756 59795800 chr5 180857866 + 175080369 175080413 1478283
+44
+
+chain 2887 chr4 191154276 + 59793960 59793991 chr2 242951149 - 7484272 7484303 15380677
+31
+
+chain 2846 chr4 191154276 + 9001603 9001654 chr8 146274826 - 133764474 133764525 19750221
+51
+
+chain 2767 chr4 191154276 + 8957324 8957381 chr4 191273063 + 9129618 9129675 15542671
+57
+
+chain 2754 chr4 191154276 + 9087109 9087190 chr6 170899992 + 92706078 92706159 16313416
+81
+
+chain 2673 chr4 191154276 + 9065350 9065411 chr1 247249719 - 53009045 53009106 13821618
+61
+
+chain 2622 chr4 191154276 + 59793258 59793374 chr14 106368585 + 42536813 42536929 1616879
+116
+
+chain 2598 chr4 191154276 + 59795229 59795281 chr6 170899992 + 57310821 57310873 1524793
+52
+
+chain 2565 chr4 191154276 + 190987578 190987605 chr4 191273063 + 191231440 191231467 2372
+27
+
+chain 2557 chr4 191154276 + 9066521 9067027 chr12 132349534 + 72855206 72855711 22561893
+55 378 377
+73
+
+chain 2500 chr4 191154276 + 9083457 9083524 chr8 146274826 + 32149594 32149661 28386486
+67
+
+chain 2474 chr4 191154276 + 1651689 1651722 chr4 191273063 + 1621541 1621574 19254204
+33
+
+chain 2389 chr4 191154276 + 9036810 9036873 chr2 242951149 - 1691358 1691421 23135357
+63
+
+chain 2338 chr4 191154276 + 59796505 59796540 chr17 78774742 + 47057876 47057911 2877115
+35
+
+chain 2291 chr4 191154276 + 9216761 9217155 chr8 146274826 - 133997030 133997425 4114277
+45 320 321
+29
+
+chain 2265 chr4 191154276 + 9065418 9065482 chr9 140273252 + 44106224 44106288 9767431
+64
+
+chain 2116 chr4 191154276 + 8944155 8944177 chr3 199501827 + 126918676 126918698 25172225
+22
+
+chain 2099 chr4 191154276 + 9099268 9099290 chr2 242951149 + 169698626 169698648 26708137
+22
+
+chain 2025 chr4 191154276 + 9097343 9097409 chr3 199501827 + 179409375 179409441 24047564
+66
+
+chain 2003 chr4 191154276 + 9108252 9108273 chr2 242951149 - 190846639 190846660 24998179
+21
+
+chain 1997 chr4 191154276 + 9146164 9146218 chr15 100338915 - 2487154 2487208 24249848
+54
+
+chain 1870 chr4 191154276 + 190988070 190988095 chr10 135374737 + 135329605 135329630 1377
+25
+
+chain 1826 chr4 191154276 + 8957935 8957992 chr4 191273063 + 9362404 9362461 11066413
+57
+
+chain 1826 chr4 191154276 + 9097476 9098043 chr12 132349534 - 122338357 122338925 15828070
+57 424 425
+86
+
+chain 1767 chr4 191154276 + 8990059 8990106 chr1 247249719 + 148949220 148949267 26452494
+47
+
+chain 1744 chr4 191154276 + 59793037 59793133 chr3 199501827 + 30427927 30428023 1883621
+96
+
+chain 1736 chr4 191154276 + 9086392 9087109 chr4 191273063 - 127153063 127153784 14070511
+50 639 643
+28
+
+chain 1668 chr4 191154276 + 9124660 9124729 chr4 191273063 + 9269820 9269889 23245150
+69
+
+chain 1556 chr4 191154276 + 9060815 9060839 chr10 135374737 - 108080722 108080746 12503169
+24
+
+chain 1546 chr4 191154276 + 9180153 9180207 chr8 146274826 - 138844855 138844909 16808195
+54
+
+chain 1517 chr4 191154276 + 59794322 59794359 chr11 134452384 - 119842384 119842421 16271509
+37
+
+chain 1488 chr4 191154276 + 59796097 59796124 chr9 140273252 + 9925299 9925326 2265670
+27
+
+chain 1436 chr4 191154276 + 191043722 191043759 chr1 247249719 - 247249574 247249611 18645625
+37
+
+chain 1374 chr4 191154276 + 9065276 9065337 chr1 247249719 - 201083821 201083882 10540800
+61
+
+chain 1348 chr4 191154276 + 9109064 9109144 chr2 242951149 - 126292213 126292293 15140626
+80
+
+chain 1343 chr4 191154276 + 9146043 9146068 chr18 76117153 + 30068723 30068748 16305066
+25
+
+chain 1292 chr4 191154276 + 9123899 9123951 chr4 191273063 - 148574019 148574071 20863102
+52
+
+chain 1290 chr4 191154276 + 9179321 9179368 chr11 134452384 + 3426025 3426072 10983647
+47
+
+chain 1231 chr4 191154276 + 59794434 59794461 chr5 180857866 + 147382264 147382291 9387523
+27
+
+chain 1177 chr4 191154276 + 9065884 9065939 chr9 140273252 - 70318092 70318147 10006368
+55
+
+chain 1097 chr4 191154276 + 9086357 9086392 chr1 247249719 - 129588705 129588740 16923174
+35
+
+chain 1085 chr4 191154276 + 9066380 9066450 chr13 114142980 + 68490318 68490388 22728993
+70
+
+chain 1083 chr4 191154276 + 9032737 9032804 chr13 114142980 + 26049760 26049827 24893033
+67
+
+chain 1011 chr4 191154276 + 9067073 9067124 chr10 135374737 - 108679092 108679143 23379890
+51
+
+chain 996 chr4 191154276 + 8971509 8971561 chr12 132349534 + 31168410 31168462 23661941
+52
+
+chain 963 chr4 191154276 + 9066836 9066890 chr1 247249719 - 151454542 151454596 25048936
+54
+
+chain 958 chr4 191154276 + 9145173 9145232 chr1 247249719 - 217919030 217919089 20381976
+59
+
+chain 937 chr4 191154276 + 8958092 8958125 chr11 134452384 + 67446107 67446140 12651114
+33
+
+chain 917 chr4 191154276 + 9146455 9146505 chr8 146274826 + 19957787 19957837 24577235
+50
+
+chain 910 chr4 191154276 + 9097602 9098317 chr2 242951149 - 190844271 190844995 14887788
+50 595 604
+70
+
+chain 894 chr4 191154276 + 9109146 9109219 chrX 154913754 - 13573867 13573940 23078019
+73
+
+chain 878 chr4 191154276 + 9178986 9179012 chr2 242951149 - 137542666 137542692 11507142
+26
+
+chain 871 chr4 191154276 + 9082368 9082425 chr3 199501827 - 78731030 78731087 22332859
+57
+
+chain 858 chr4 191154276 + 9098043 9099355 chr5 180857866 - 58871729 58873086 24126323
+56 1191 1236
+65
+
+chain 777 chr4 191154276 + 8955354 8955423 chr3 199501827 - 68281758 68281827 15856837
+69
+
+chain 715 chr4 191154276 + 191033511 191033568 chr7 158821424 + 30724536 30724593 23744345
+57
+
+chain 650 chr4 191154276 + 9126884 9126934 chr3 199501827 + 102896742 102896792 23688110
+50
+
+chain 507 chr4 191154276 + 59793857 59793890 chr8 146274826 + 107120151 107120184 20878932
+33
+
+chain 468 chr4 191154276 + 40297344 40297404 chr4 191273063 + 39972706 39972766 25333266
+60
+
+chain 438 chr4 191154276 + 9098988 9099041 chr4 191273063 - 56600577 56600630 25949595
+53
+
+chain 368 chr4 191154276 + 191031439 191031496 chr19 63811651 - 43557899 43557956 26568315
+57
+
+chain 315 chr4 191154276 + 8972631 8972682 chr12 132349534 - 123858147 123858198 26303923
+51
+
+chain 268 chr4 191154276 + 59793813 59793857 chr13 114142980 - 20847506 20847550 12435901
+44
+
+chain 209 chr4 191154276 + 9096427 9096486 chr3 199501827 - 25140168 25140227 30710814
+59
+
+chain 54948874 chr4_ctg9_hap1 590426 + 0 590426 chr4 191273063 + 68852671 69912764 73
+1837 0 2
+151607 0 469345
+122242 3 1
+4137 1 1
+70 1 1
+5254 0 2
+2782 48 48
+1074 0 2
+2825 0 5
+2047 2 0
+6949 1 1
+41 1 1
+232 0 1
+1965 12 0
+694 1 1
+22 1 0
+945 14 14
+416 1 1
+36 2 0
+75 1 1
+21 1 0
+52 1 1
+41 1 1
+144 1 1
+87 1 1
+71 1 1
+35 1 1
+145 0 1
+503 1 1
+88 1 1
+99 1 1
+30 1 1
+293 0 5
+360 19 19
+380 1 1
+23 1 1
+209 36 36
+557 10 10
+820 1 1
+38 1 1
+868 0 2
+227 0 353
+5432 0 1
+1459 1 0
+210 20 20
+125 8 0
+5 32 0
+65 0 2
+10 23 5
+240 0 1
+233 14 14
+1076 14 14
+100 1 1
+28 1 1
+199 0 1
+287 1 1
+36 1 0
+17 1 1
+132 1 1
+25 1 1
+193 1 0
+305 0 28
+50 0 1
+544 1 1
+40 4 0
+794 15 15
+179 1 1
+72 1 1
+142 1 1
+65 1 1
+364 0 1
+335 0 1
+52 4 4
+48 1 1
+934 1 1
+50 0 1
+44 1 1
+1074 1 1
+22 1 1
+286 4 0
+33 1 1
+303 1 1
+5 0 1
+63 1 1
+972 1 1
+69 1 1
+602 1 1
+25 1 1
+2469 5 5
+1033 1 1
+63 1 1
+233 0 3
+311 1 1
+29 1 1
+881 6 6
+123 15 16
+283 1 1
+39 1 1
+57 5 0
+613 1 1
+42 1 1
+1598 0 2
+730 1 1
+47 1 1
+459 1 1
+25 1 1
+775 7 7
+534 0 1
+1090 5 5
+375 1 1
+62 1 1
+133 15 15
+700 1 1
+36 4 0
+365 9 9
+468 1 1
+45 1 1
+1356 16 16
+422 1 0
+55 0 2
+7890 1 1
+30 1 1
+1445 1 1
+27 1 1
+96 4 0
+2114 10 11
+1940 2 0
+1687 1 1
+40 1 1
+1679 1 0
+734 0 1
+480 1 0
+7344 1 0
+3930 17 17
+1001 0 8
+216373
+
+chain 4430 chr4_ctg9_hap1 590426 + 287934 287982 chr4 191273063 + 69257952 69258000 221
+48
+
+chain 18001815 chr4_gl000193_random 189789 + 0 189789 chr4_random 842648 + 0 189789 149
+189789
+
+chain 18169122 chr4_gl000194_random 191469 + 0 191469 chr4_random 842648 + 440032 631501 148
+191469
+
+chain 16792065298 chr5 180915260 + 10000 180905260 chr5 180857866 + 63000 180837866 5
+17520657 50017 11
+356 84 84
+496 0 3434
+735 75 1475
+628 25 3459
+51 50 3484
+3427 1 1
+39 3 3437
+577 8 8
+167 44 1713
+23 0 3434
+1184 1 0
+46 1 0
+5 1 0
+266 1 1
+21 1 1
+763 16 16
+422 1 1
+29 1 1
+5243 1 1
+37 1 1
+978 1 1
+21 1 1
+116 16 3450
+1792 146 16585
+3079 0 1
+7857 9770 0
+1026 636 1
+7461 1 0
+23769 0 51
+4034 1 0
+20571 1 0
+9135 2 0
+6885 3 2
+110 0 3
+816 3 2
+2296 34 0
+7499 2 0
+2917 1 0
+652 1 1
+37 1 1
+657 1 1
+22 1 1
+419 4 3
+3580 1 1
+29 1 1
+274 35 11
+833 1 0
+1908 0 3038
+10504 1 1
+27 0 2
+784 6 0
+127 0 10
+668 1 1
+28 1 1
+2464 0 4
+182 2 0
+1650 1 1
+39 1 1
+2433 0 1
+720 1 1
+40 1 1
+772 1 1
+32 1 1
+353 1 1
+17 1 1
+1776 1 0
+6082 0 3
+2669 10 12
+2857 1 1
+35 1 1
+982 1 1
+173 1 1
+4115 1 1
+49 1 1
+702 1 1
+33 1 1
+2927 2 1
+1472 0 17
+1346 1 1
+35 1 1
+2068 1 1
+40 1 1
+828 1 1
+36 0 2
+317 0 8
+893 1 1
+33 0 1
+8145 4 0
+28632197 3000000 3000000
+12470071 1 0
+29760415 50000 40000
+5878002 20845 23000
+4521 0 1
+676 6 6
+5928 1 0
+372 1 1
+47 1 1
+6801 2 3
+639 1 0
+871 4 3
+11530 4 0
+22966 1 0
+15447 1 0
+53856 2 0
+15988 2 0
+906887 1 0
+8 2 2
+40152828 47715 0
+3526228 1 0
+1604 0 10
+12778810 51715 4100
+15152690 0 27
+1852098 0 1
+8710030
+
+chain 78758 chr5 180915260 + 17610410 17613099 chr5 180857866 + 17647305 17649997 1601642
+85 49 49
+57 201 201
+189 17 17
+78 77 77
+75 178 181
+116 179 179
+91 8 8
+51 298 300
+51 664 662
+64 26 26
+135
+
+chain 31383 chr5 180915260 + 97574240 97575427 chr4 191273063 - 170991967 170993160 4391624
+188 108 110
+89 705 709
+97
+
+chain 22831 chr5 180915260 + 97580590 97581374 chr2 242951149 - 86243998 86244777 8407693
+68 180 179
+95 326 322
+115
+
+chain 16108 chr5 180915260 + 97571166 97571372 chr3 199501827 + 12403992 12404198 13932022
+51 22 22
+133
+
+chain 10260 chr5 180915260 + 97573380 97573866 chrX 154913754 + 72466087 72466572 22227065
+67 357 356
+62
+
+chain 9281 chr5 180915260 + 97573916 97574127 chr3 199501827 - 17931346 17931561 24462523
+61 98 102
+52
+
+chain 8534 chr5 180915260 + 17581030 17583073 chr5 180857866 + 17608062 17614939 1974
+70 1948 6782
+25
+
+chain 7377 chr5 180915260 + 17614165 17614243 chr8 146274826 + 118652818 118652896 27454171
+78
+
+chain 7140 chr5 180915260 + 97574682 97574775 chr9 140273252 + 18188007 18188100 13076039
+11 6 6
+76
+
+chain 6854 chr5 180915260 + 97574980 97575063 chr2 242951149 + 163688921 163689004 19449593
+83
+
+chain 6104 chr5 180915260 + 97573580 97573645 chrX 154913754 + 86697567 86697632 30283885
+65
+
+chain 5931 chr5 180915260 + 97571838 97571901 chr11 134452384 + 21528921 21528984 30747470
+63
+
+chain 5358 chr5 180915260 + 97565266 97565323 chr3 199501827 + 123413571 123413628 32371600
+57
+
+chain 5211 chr5 180915260 + 97574626 97575600 chr2 242951149 - 205065194 205066172 4657168
+56 746 750
+172
+
+chain 4836 chr5 180915260 + 97570927 97570987 chr12 132349534 + 79028695 79028755 21429371
+60
+
+chain 3976 chr5 180915260 + 97580463 97580554 chrX 154913754 + 120621333 120621424 19038460
+91
+
+chain 3896 chr5 180915260 + 17583124 17583167 chr5 180857866 + 17601254 17601297 1526
+43
+
+chain 3528 chr5 180915260 + 97573879 97573916 chr4 191273063 - 42047288 42047325 31874217
+37
+
+chain 3107 chr5 180915260 + 97574479 97575651 chr2 242951149 + 88874356 88875531 4418505
+53 767 770
+31 271 271
+50
+
+chain 3026 chr5 180915260 + 97580178 97580228 chr15 100338915 - 8217824 8217874 19735797
+50
+
+chain 2922 chr5 180915260 + 97575231 97575262 chr5 180857866 - 151978291 151978322 11789776
+31
+
+chain 2640 chr5 180915260 + 97575132 97575230 chr6 170899992 - 85176442 85176540 6161475
+98
+
+chain 2605 chr5 180915260 + 97580235 97580338 chr6 170899992 - 161277959 161278062 12089137
+103
+
+chain 2572 chr5 180915260 + 97580955 97581020 chr4 191273063 + 75087136 75087201 9159879
+65
+
+chain 2511 chr5 180915260 + 97573039 97573123 chr5 180857866 + 96582581 96582665 20564544
+84
+
+chain 2425 chr5 180915260 + 97580778 97580807 chr7 158821424 + 56235832 56235861 15947917
+29
+
+chain 2390 chr5 180915260 + 97580658 97580706 chr6 170899992 + 77924350 77924398 14557662
+48
+
+chain 2360 chr5 180915260 + 97575070 97575127 chr15 100338915 - 65496060 65496117 11267266
+57
+
+chain 2316 chr5 180915260 + 97574862 97574967 chr5 180857866 + 122822031 122822136 6403532
+105
+
+chain 2262 chr5 180915260 + 97575262 97575299 chr5 180857866 + 117084659 117084696 9926189
+37
+
+chain 2258 chr5 180915260 + 97570996 97571059 chr6 170899992 + 98788934 98788997 20073703
+63
+
+chain 2234 chr5 180915260 + 97575771 97575825 chr15 100338915 + 19192799 19192853 13777203
+54
+
+chain 2112 chr5 180915260 + 17598551 17598575 chr5 180857866 + 17621050 17621074 2441
+24
+
+chain 2082 chr5 180915260 + 97581410 97581440 chr5 180857866 - 81177483 81177513 18145628
+30
+
+chain 2013 chr5 180915260 + 97574428 97574456 chr6 170899992 + 12662047 12662075 5707452
+28
+
+chain 1804 chr5 180915260 + 97574815 97574862 chr7 158821424 + 102470537 102470584 21213680
+47
+
+chain 1676 chr5 180915260 + 97571668 97571723 chr9 140273252 - 49451145 49451200 15925569
+55
+
+chain 1630 chr5 180915260 + 97575847 97575921 chr14 106368585 + 65599248 65599322 16554081
+74
+
+chain 1394 chr5 180915260 + 17611593 17611672 chr5 180857866 - 163271537 163271616 20711197
+79
+
+chain 1250 chr5 180915260 + 97570872 97570926 chrX 154913754 + 128632888 128632942 22138126
+54
+
+chain 1212 chr5 180915260 + 17598429 17598472 chr5 180857866 - 163276581 163276624 866388
+43
+
+chain 683 chr5 180915260 + 97570493 97570549 chr4 191273063 + 125149085 125149141 22694892
+56
+
+chain 625 chr5 180915260 + 97572119 97572183 chr5 180857866 - 153619225 153619289 25061319
+64
+
+chain 466 chr5 180915260 + 97569261 97569351 chr7 158821424 - 120247996 120248086 22482305
+90
+
+chain 395 chr5 180915260 + 97572751 97572804 chr2 242951149 - 47300723 47300776 19687839
+53
+
+chain 15799169383 chr6 171115067 + 60000 171055067 chr6 170899992 + 5000 170896992 6
+1297281 1 0
+7806968 0 162987
+4013154 9 0
+261 13 15
+18786172 17 17
+439 16 16
+59 5 4
+32202 17 17
+439 16 16
+59 4 5
+15403 1 0
+13914169 4 0
+112 1 1
+17 1 1
+415 12 0
+105 6 3
+12160281 50000 50000
+642507 3100000 3050000
+248423 50000 50000
+2918791 1238 0
+9427508 4 4
+162 12 12
+2193 22 22
+293 1 1
+30 1 1
+845 1 0
+45 1 1
+9769 2 0
+6058 1 1
+24 1 1
+2223 1 1
+24 1 1
+182 12 12
+284 1 1
+20 1 1
+1035 7 36
+1007 1 1
+27 1 1
+3279 1 1
+44 0 1
+3012 1 0
+545 17 17
+2562 0 1
+251 0 1
+935 8 0
+37 1 1
+566 6 0
+1483 2 0
+1960 1 0
+4564 1 1
+25 1 1
+832 0 1
+801 8 8
+1131 1 1
+58 5 1
+6177 0 1
+3712 1 0
+2185 1 1
+35 1 1
+710 2 2
+78 1 1
+2201 1 1
+30 1 1
+283 1 1
+30 1 1
+448 1 0
+74814 2 2
+197 8 0
+2508456 1 0
+4641788 5 5
+37 1 1
+8503609 0 2
+5363169 150000 200000
+6040303 1 1
+36 1 0
+2020 1 1
+46 1 1
+1559 1 1
+72 1 1
+1098 1 1
+29 1 1
+264 7 7
+580 0 1
+30 1 1
+536 1 1
+41 1 1
+5663 1 0
+438 5 3
+354 1 1
+18 1 1
+9613 14 13
+1400 1 0
+176 0 2
+2742 1 0
+1968 0 1
+754 1 0
+4237 0 1
+2388 1 1
+31 1 0
+3385 0 1
+2004 8 0
+3395 0 3
+32 1 1
+4109 0 1
+1058 20 0
+1608 1 0
+17198424 17 26
+7835 0 1
+16317 11 0
+6277 64993 0
+6787989 0 1
+149 4 0
+949 4 0
+242 0 1
+28418215 1 1
+21 1 0
+3116903 171704 50000
+1939305 1 1
+19 0 2
+8192274 4 4
+122 0 2
+1127 1 0
+1102 75 0
+21 8 5
+30 29 0
+27 6 3
+62 52 0
+42 195105 18125
+950946 1 1
+51 157 1
+107 255 0
+714 513 0
+1285155 50000 150000
+725095
+
+chain 12021668 chr6 171115067 + 157540957 157712661 chr6_random 1875562 + 1435107 1512777 78
+18510 50000 5628
+31833 50000 338
+21361
+
+chain 8743144 chr6 171115067 + 167847224 167942073 chr6_random 1875562 - 1720470 1850468 378
+12768 1 1
+28 0 1
+17496 12 0
+7219 1 1
+29 1 1
+4716 0 1
+1645 0 4
+6037 1 1
+33 94 125
+10 3 3
+5171 1 0
+4453 734 36650
+3575 1 1
+26 1 1
+4697 13 13
+958 0 2
+228 0 2
+2465 13 13
+142 1 1
+15 1 0
+33 937 104
+94 0 1
+125 16 0
+5319 48 103
+897 0 3
+1130 0 3
+187 8 7
+67 26 25
+5876 1 1
+47 1 1
+1955 14 7
+575 36 36
+641 0 2
+1143 5 5
+3079
+
+chain 27931 chr6 171115067 + 168993335 168994451 chr6 170899992 + 168736232 168737615 1527785
+96 36 36
+16 0 51
+107 739 901
+51 0 54
+71
+
+chain 17101 chr6 171115067 + 119158013 119159004 chr8 146274826 + 76280127 76281098 12940826
+78 146 105
+78 622 643
+67
+
+chain 14766 chr6 171115067 + 119189669 119190286 chr7 158821424 - 68703788 68704409 15321990
+54 439 443
+124
+
+chain 13062 chr6 171115067 + 168994482 168994817 chr6 170899992 + 168736716 168737003 1274096
+205 50 2
+80
+
+chain 12205 chr6 171115067 + 119155128 119155329 chr8 146274826 - 70047959 70048173 18676577
+72 59 72
+70
+
+chain 11124 chr6 171115067 + 168993071 168993228 chr6 170899992 + 168736229 168736638 2160304
+29 1 52
+50 25 226
+52
+
+chain 10673 chr6 171115067 + 119159180 119160231 chr10 135374737 - 59595554 59596042 21356650
+62 913 350
+76
+
+chain 10669 chr6 171115067 + 119157022 119157134 chr14 106368585 + 59942933 59943045 21369163
+112
+
+chain 9554 chr6 171115067 + 119189632 119189818 chrX 154913754 + 133155010 133155200 16872824
+37 54 54
+12 31 35
+52
+
+chain 7928 chr6 171115067 + 167846995 167847141 chr6_random 1875562 + 628575 628698 120
+41 26 0
+57 0 3
+22
+
+chain 7384 chr6 171115067 + 167920474 167920550 chr6_random 1875562 - 1829156 1829232 27447594
+76
+
+chain 7241 chr6 171115067 + 119190390 119190581 chr13 114142980 + 101174758 101174949 23777400
+2 136 136
+53
+
+chain 6904 chr6 171115067 + 119156272 119156345 chr11 134452384 - 108078565 108078638 28375374
+73
+
+chain 6531 chr6 171115067 + 119159999 119160068 chr4 191273063 - 87162214 87162283 29199925
+69
+
+chain 5948 chr6 171115067 + 119160915 119160977 chrX 154913754 - 59556739 59556801 30709264
+62
+
+chain 5818 chr6 171115067 + 119158407 119158509 chr18 76117153 + 30261305 30261403 24322730
+1 51 47
+50
+
+chain 5749 chr6 171115067 + 119155939 119156000 chr6 170899992 + 92063509 92063570 31228902
+61
+
+chain 5103 chr6 171115067 + 119189831 119189885 chrX 154913754 - 76833525 76833579 33162260
+54
+
+chain 5032 chr6 171115067 + 119156645 119156719 chrX 154913754 + 87420725 87420799 20704812
+74
+
+chain 5002 chr6 171115067 + 119160862 119160914 chrX 154913754 + 56955255 56955307 33524497
+52
+
+chain 4995 chr6 171115067 + 168994451 168994737 chr6 170899992 + 168737201 168737385 2349016
+31 205 103
+50
+
+chain 4921 chr6 171115067 + 119156041 119156093 chr9 140273252 + 81227536 81227588 33775667
+52
+
+chain 4912 chr6 171115067 + 119160087 119160139 chr5 180857866 + 63815067 63815119 33803556
+52
+
+chain 3597 chr6 171115067 + 119157136 119157361 chr2 242951149 + 31758724 31758949 14786968
+84 78 78
+63
+
+chain 3223 chr6 171115067 + 119156854 119156913 chr15 100338915 - 54365651 54365710 24573102
+59
+
+chain 3204 chr6 171115067 + 119155364 119155420 chr6 170899992 - 73613724 73613780 24603360
+56
+
+chain 2966 chr6 171115067 + 119156499 119156577 chrX 154913754 - 137505405 137505483 21485501
+78
+
+chain 2728 chr6 171115067 + 119159004 119159033 chr3 199501827 - 198198433 198198462 28454448
+29
+
+chain 2528 chr6 171115067 + 119156618 119156645 chr11 134452384 + 82352593 82352620 34284540
+27
+
+chain 2454 chr6 171115067 + 119155233 119155259 chr9 140273252 + 122001720 122001746 35057240
+26
+
+chain 2315 chr6 171115067 + 119156723 119156806 chr4 191273063 + 116661391 116661474 16361102
+83
+
+chain 2146 chr6 171115067 + 119158341 119158407 chr6 170899992 + 115819766 115819832 17078055
+66
+
+chain 1866 chr6 171115067 + 119190053 119190120 chr5 180857866 + 56063062 56063129 22879278
+67
+
+chain 1656 chr6 171115067 + 119158523 119158602 chr11 134452384 + 2473635 2473714 18654554
+79
+
+chain 1624 chr6 171115067 + 119189898 119189948 chr4 191273063 - 66123378 66123428 24040914
+50
+
+chain 1451 chr6 171115067 + 119158163 119158229 chr15 100338915 - 64161282 64161348 22109122
+66
+
+chain 1209 chr6 171115067 + 168994304 168994329 chr6 170899992 + 168736283 168736308 2117199
+25
+
+chain 1198 chr6 171115067 + 119156176 119156250 chr5 180857866 + 3717928 3718002 22194292
+74
+
+chain 980 chr6 171115067 + 119158602 119158634 chr8 146274826 + 104450758 104450790 18747323
+32
+
+chain 943 chr6 171115067 + 119157563 119157614 chr2 242951149 + 163020248 163020299 23359839
+51
+
+chain 785 chr6 171115067 + 119156425 119156485 chr17 78774742 - 29484860 29484920 22136428
+60
+
+chain 779 chr6 171115067 + 119190333 119190390 chr3 199501827 - 104453282 104453339 22453017
+57
+
+chain 696 chr6 171115067 + 119158674 119158726 chr6 170899992 - 83894386 83894438 23403881
+52
+
+chain 689 chr6 171115067 + 119157650 119157707 chrX 154913754 + 101935638 101935695 24716105
+57
+
+chain 360 chr6 171115067 + 119160319 119160372 chr3 199501827 - 158113258 158113311 26359861
+53
+
+chain 282 chr6 171115067 + 119159242 119159272 chr19 63811651 + 46835118 46835148 25343818
+30
+
+chain 202629822 chr6_apd_hap1 4622290 + 0 4622290 chr6 170899992 + 28804582 33443471 49
+932 3 0
+804 0 1
+2406 2 0
+178370 1 0
+25289 44253 44253
+3450 0 1
+345 1 0
+3096 39 0
+16669 1 0
+48609 0 2
+2804 29384 29384
+14756 7 0
+1489 1 1
+72 1 1
+2260 0 2
+7033 0 8
+3588 0 1
+9760 32 32
+9786 0 1
+1324 0 2
+5438 5 0
+2061 2 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4746 9 9
+4767 7 7
+1225 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+249 43 43
+1178 0 4
+685 8 0
+48 4 0
+1144 87598 87598
+5106 2 0
+1514 0 1
+3116 0 1
+3278 1 1
+21 1 1
+1738 0 1
+8576 19 0
+8020 1 0
+2049 1 0
+518 13 11
+1704 1 1
+117 1 1
+1448 10 0
+4403 9 9
+2265 1 0
+8656 104192 104192
+1686 0 2
+5376 0 1
+19253 1 0
+7884 1 0
+21 0 6
+4451 1 0
+27910 1 0
+9946 0 1
+11233 1 1
+32 1 1
+2238 1 1
+20 1 1
+3659 22 16
+1218 1 0
+1638 6 6
+228 1 1
+45 1 1
+2048 0 2
+462 1 0
+20759 1 0
+3778 2 1
+1268 1 0
+1511 1 1
+42 2 0
+24 1 1
+4119 22 0
+1757 1 0
+1527 1 1
+29 1 1
+1886 1 0
+6666 0 4
+1349 0 4
+1102 10 8
+1463 34 31
+168 1 1
+21 1 1
+304 1 1
+31 1 1
+549 1 0
+5745 1 0
+5097 0 1
+534 1 1
+17 1 1
+2233 1 1
+37 1 1
+3328 0 1
+4783 6 0
+3323 0 3
+965 1 0
+1234 28 0
+1194 1 0
+1855 18 18
+1024 0 1
+5932 1 0
+5395 9 9
+2759 0 10
+618 5 0
+667 0 8
+580 0 1
+109 1 1
+326 1 0
+9436 5 0
+6164 0 1
+1064 0 6
+1374 2 0
+3637 1 1
+32 1 1
+145 1 0
+1245 2 0
+1736 1 1
+29 1 1
+1656 1 5
+712 10 11
+502 0 1
+3670 1 0
+740 0 1
+1693 0 1
+6497 0 2
+2700 1 0
+198 1 3
+141 0 1
+1108 0 2
+1448 1 0
+947 31 31
+8047 4 0
+842 19167 19167
+101 1 0
+11 4 0
+297 0 24
+337 11 0
+134 1 1
+694 3 0
+72 1 1
+144 128 128
+169 2 0
+1011 1 0
+107 1 1
+1280 1 1
+73 1 1
+84 25 25
+287 1 1
+26 1 1
+139 1 1
+41 1 1
+440 4 0
+130 12 12
+435 18 0
+85 1 1
+28 1 1
+73 59397 59260
+107 0 32
+23 1 1
+116 1 1
+30 1 1
+503 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 4
+711 7 7
+89 1 0
+291 1 0
+167 1 1
+24 1 1
+167 6 6
+171 17 17
+681 1 1
+43 1 1
+538 1 1
+44 1 1
+537 16 16
+180 6 6
+778 2 2
+44 1 1
+168 0 7
+211 1 1
+42 1 1
+1253 1 1
+29 1 1
+320 1 1
+36 2 2
+55 1 2
+228 1 1
+17 1 1
+213 1 1
+35 1 1
+553 8 8
+386 1 1
+26 1 1
+540 1 1
+31 1 1
+65 0 1
+625 12 12
+313 0 1
+52 1 1
+22 1 1
+583 1 1
+49 1 1
+1499 3 0
+729 1 1
+40 1 1
+67 1 1
+19 11 0
+323 19 19
+787 1 1
+36 1 1
+553 8 8
+997 16 15
+157 1 1
+31 2 2
+204 18 19
+487 1 1
+29 1 1
+374 1 1
+67 1 1
+720 13 13
+266 10 10
+330 16 14
+413 1 1
+44 1 1
+78 6 6
+181 2 2
+36 1 1
+397 1 1
+20 1 1
+311 1 1
+48 2 2
+1746 4 4
+35 1 1
+194 10 10
+310 1 1
+51 1 1
+84 1 1
+101 1 1
+521 1 1
+23 1 1
+220 73 73
+1046 15 15
+216 1 1
+21 1 1
+51 1 1
+49 1 1
+527 17 17
+340 12 11
+1025 1 0
+2572 1 1
+29 1 1
+397 2 5
+668 13 13
+541 1 1
+59 0 2
+6 1 1
+122 14 14
+51 1 1
+46 1 1
+429 0 21
+136 1 1
+12 1 1
+66 16 16
+456 37 34
+371 7 7
+48 1 1
+194 10 10
+108 1 1
+60 1 1
+122 49 50
+238 1 1
+32 0 1
+100 1 0
+72 1 0
+390 1 1
+38 1 1
+144 1 1
+27 0 4
+184 21 228
+49 1 1
+608 0 1
+152 1 1
+31 1 1
+281 8 8
+337 1 1
+45 1 1
+222 1 1
+20 1 1
+380 1 0
+44 1 1
+368 1 1
+72 1 1
+502 36 18
+63 1 1
+43 0 4
+136 1 1
+42 1 1
+80 4 4
+35 1 0
+89 1 1
+24 0 5
+829 13 13
+102 14 0
+233 1 1
+42 0 3
+85 0 1
+400 1 1
+40 1 1
+538 25 25
+174 1 1
+20 1 1
+705 1 1
+26 2 2
+614 1 1
+44 1 1
+509 1 1
+32 1 1
+224 1 1
+42 1 1
+99 38 38
+610 5 5
+804 1 1
+29 1 1
+166 1 1
+43 1 1
+233 1 1
+44 1 1
+620 8 8
+133 1 1
+31 1 1
+165 1 1
+29 1 1
+1249 1 1
+26 4 0
+56 1 1
+67 1 1
+716 1 1
+46 0 1
+16 1 1
+174 1 1
+96 1 1
+141 1 1
+39 0 4
+263 1 1
+18 1 1
+259 4 4
+38 1 1
+104 1 1
+40 1 0
+248 1 1
+18 1 1
+238 1 1
+32 1 1
+70 0 2
+16 1 1
+818 1 1
+22 4 4
+1641 1 1
+46 1 1
+53 1 0
+38 1 1
+373 38443 100035
+112 1 1
+39 1 1
+330 1 1
+24 1 1
+197 1 1
+69 1 1
+116 3 0
+161 1 1
+38 1 1
+753 1 1
+57 3 3
+145 1 1
+121 1 1
+300 1 1
+147 1 1
+379 1 1
+55 2 2
+65 1 1
+32 1 1
+1008 1 1
+24 1 1
+159 18 18
+659 1 1
+76 0 2
+77 1 3
+65 1 1
+84 1 0
+119 1 1
+15 1 1
+247 4 0
+372 1 0
+1633 1 1
+16 1 1
+456 7 7
+114 1 1
+102 1 1
+109 4 0
+61 2 2
+80 1 1
+47 1 1
+168 1 1
+31 1 1
+269 2 2
+42 1 1
+626 2 2
+14 1 1
+76 8356 10147
+66 2 2
+80 0 41
+12 1 1
+158 1 0
+92 1 0
+254 1 1
+43 1 1
+846 6 149
+84 1 1
+29 3 3
+315 17 17
+482 1 1
+29 3 3
+278 1 1
+73 1 1
+2767 1 1
+34 1 1
+192 1 1
+33 1 0
+168 6 0
+276 10 10
+344 1 1
+49 1 1
+109 1 1
+35 3 3
+561 24 27
+923 1 1
+102 1 1
+75 14 14
+266 1 1
+80 2 2
+185 1 0
+1035 1 1
+23 1 1
+417 10 10
+97 1 1
+94 1 1
+492 1 1
+37 5 5
+1429 1 1
+19 1 1
+839 1 1
+96 1 1
+1279 4 0
+683 1 1
+49 1 1
+514 1 1
+28 4 4
+2302 1 1
+42 1 1
+537 2 21
+1555 1 1
+42 0 1
+14 4 4
+86 1 1
+62 1 1
+515 5 1
+330 0 1
+159 0 22
+3841 1 0
+3862 16 16
+1187 12 12
+97 0 3
+748 24594 24594
+686 1 0
+11541 1 0
+1843 0 4
+1157 16 16
+7354 19 0
+741 0 1
+8053 1 0
+4449 21 21
+649 1 0
+2913 0 1
+381 332 0
+3533 31 31
+2502 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3870 0 1
+36 13 0
+1894 1 1
+40 0 4
+1137 2 0
+211 2 0
+345 1 0
+592 4 4
+1043 4 0
+686 14 0
+1032 0 1
+9035 0 4
+167 0 2
+23964 0 3
+1760 3 0
+3371 1 1
+23 1 1
+321 5 0
+644 8 0
+47 1 1
+322 1 1
+145 1 1
+1551 11 15
+355 0 1
+1831 4 0
+1779 1 1
+27 1 1
+199 43 55
+767 9786 9786
+338 0 1
+1002 0 1
+7912 4 0
+4977 0 1
+9275 2953 2950
+21511 0 1
+4385 0 7
+881 0 8
+17594 0 20
+2417 1 0
+998 0 10
+4239 7 0
+4845 0 2
+95 28 23
+10921 1 1
+40 1 1
+4759 0 6
+12084 0 3
+3052 0 4
+2989 1 0
+13523 1 3
+3050 104591 33135
+2281 0 7
+377 3 0
+7256 3 0
+419 2 0
+10674 0 17
+5362 16440 16440
+408 1 0
+3061 2 0
+5818 1 0
+2415 11 9
+2056 0 1
+955 4 0
+17260 1 0
+9557 0 2
+5358 0 1
+11548 13 13
+2604 2 0
+57496 1 1
+29 1 1
+6617 19 0
+12369 49753 49753
+608 0 5
+1926 1 1
+40 1 1
+330 3 0
+2327 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+713 0 8
+54 3 0
+1027 3 0
+428 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+8189 4 5
+36 1 1
+99 2 0
+700 0 3
+150 0 1
+750 0 3
+40 1 1
+3179 2 0
+473 0 2
+2032 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+5394 103872 103871
+16267 1 0
+18633 0 1
+920 0 1
+6820 1 0
+1376 1 2
+1931 33 33
+2376 0 1
+12415 1 1
+51 0 1
+9375 0 1
+323 1 0
+1715 154558 154558
+4522 85167 85167
+6234 0 3
+4009 0 5
+6425 2 0
+1119 2 0
+17 8 0
+2256 0 1
+3209 15 8
+2436 0 14
+1040 1 1
+52 1 1
+6972 1 0
+2357 0 1
+29 1 1
+262 1 0
+72 1 1
+45 1 1
+57 17 17
+1390 0 16
+328 312 0
+65 1 1
+217 10 10
+925 0 33
+1490 1 0
+35 1 1
+226 0 3
+805 1 1
+46 1 1
+192 1 1
+56 1 1
+245 1 1
+61 1 1
+198 4 0
+82 2 2
+29 1 1
+57 0 2
+320 1 1
+22 1 1
+267 5 0
+427 1 0
+17 1 1
+425 1 1
+34 1 1
+565 10 10
+432 9 0
+55 1 1
+90 1 1
+140 1 1
+83 1 1
+1035 1 1
+33 1 1
+144 4 4
+38 1 1
+171 1 1
+35 3 3
+161 6 6
+731 7 3
+1216 25 0
+52 0 1
+419 2 0
+87 1 1
+54 1 1
+4713 30 0
+791 3 0
+2849 1 1
+33 1 1
+6790 1 1
+67 4 4
+39 2 0
+251 1 1
+37 1 1
+826 3715 901
+205 2 0
+946 1 1
+30 1 1
+613 5 2
+128 29 29
+802 0 89
+1600 0 6
+2155 1 0
+1164 1 0
+1310 1 0
+2327 1 1
+42 1 1
+2266 1 0
+21451 401282 401282
+2475 1 1
+58 1 1
+375 25 27
+9941 0 1
+6798 0 19
+5779 11 10
+21042 0 1
+13887 36782 36752
+28930 1 1
+19 1 1
+1494 7 0
+148 15 0
+2797 0 2
+329 10 0
+2475 142825 142825
+382 4 0
+707 0 1
+12092 0 1
+2431 1 0
+158 0 1
+281 1 0
+1573 0 1
+11079 1 0
+6938 0 1
+14766 1 0
+4187 10 0
+11099 3 0
+9487 0 6
+467 1 0
+2143 1 0
+697 1 1
+25 0 6
+58 8 8
+1733 0 1
+259 2 0
+295 1 0
+128 0 1
+3052 0 1
+1419 13507 13507
+201 13 12
+15310 1 1
+26 1 1
+461 1 1
+33 0 2
+16 1 1
+649 1 1
+48 1 1
+818 1 1
+21 1 1
+424 1 1
+25 1 1
+632 1 1
+39 1 1
+310 1 1
+27 1 1
+616 1 0
+17240 4 0
+3936 3 0
+2976 174972 174972
+5315 0 20
+2124 0 1
+7445 45267 45267
+361 0 2
+1466 1 0
+6628 1 1
+110 0 1
+1422 0 1
+324 1 0
+1825 1 0
+311 0 1
+6568 1 0
+5228 1 0
+2273 2 1
+6123 1 0
+18640 29 29
+1283 0 3
+11560 6 6
+708 15 14
+1887 10 0
+509 1 0
+1581 1 1
+46 1 1
+811 1 1
+31 0 1
+1557 43 43
+1172 1 1
+18 1 1
+67 1 0
+2081 0 2
+373 0 4
+538 103035 103035
+2665 46 46
+554 0 21
+4473 2 3
+921 1 1
+47 1 1
+2605 9 3
+50 1 1
+178 1 1
+26 1 1
+316 0 2
+1120 4 0
+177 1 2
+960 1 1
+65 1 1
+964 4 4
+783 8 8
+61 34 13
+121 1 1
+22 1 0
+118 1 1
+49 4 4
+281 1 1
+27 1 1
+958 0 1
+107 1 1
+31 1 1
+171 14 14
+302 0 13
+33 1 1
+108 0 4
+98 1 1
+53 1 1
+986 1 1
+37 2 0
+1829 1 1
+38 1 1
+440 1 1
+82 3 4
+647 45 45
+660 1 1
+28 1 1
+1993 0 1
+373 19 19
+835 1 1
+42 1 1
+635 0 5
+307 1 1
+36 1 0
+1055 1 1
+43 1 1
+475 1 0
+60 1 1
+127 1 1
+509 1 1
+71 1 1
+485 1 0
+26 1 1
+531 1 1
+18 1 1
+551 1 1
+18 1 1
+884 5 5
+147 53 60
+527 1 1
+26 2 2
+322 0 17
+32 2 2
+85 1 1
+45 1 1
+625 0 323
+540 0 1
+43 1 1
+266 0 2
+228 1 1
+42 1 1
+283 1 1
+92 1 1
+381 1 1
+40 1 1
+1906 0 4
+3495 0 4
+561 36 36
+370 1 1
+76 1 1
+1824 3653 3651
+214 0 2
+499 1 0
+937 1 1
+45 1 1
+421 6 0
+87 22 22
+1254 1 1
+36 0 1
+357 18 18
+391 0 1
+451 1 0
+105 1 1
+47 1 0
+255 6 6
+739 3 0
+386 1 1
+33 1 1
+281 4 0
+481 2 0
+495 1 1
+42 4 0
+219 0 1
+408 1 1
+23 1 1
+283 1 1
+25 0 1
+541 1 0
+88 2 0
+216 1 1
+29 1 1
+457 1 0
+331 7 19
+181 15 15
+228 1 0
+4 2 0
+324 0 1
+3063 0 2
+11850 0 12
+839 0 1
+14260 0 2
+9658 4 3
+2813 12 12
+782 39571 39571
+1619 2 0
+164 8 1
+655 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+516 1 1
+19 1 1
+1243 2 0
+742 1 1
+40 1 1
+3755 3 0
+13 1 1
+3819 0 1
+10010 1 0
+3051 1 1
+46 3322 3320
+1751 1 1
+103 1 2
+74 1 1
+93 1 0
+22 1 1
+149 4 0
+94 1 1
+31 7 0
+74 1 1
+275 1 0
+99 221094 247530
+272 5 5
+243 1 1
+84 1 1
+98 1 1
+50 5 5
+77 1 1
+74 1 1
+20 0 1
+143 1 1
+45 0 1
+4 1 1
+1088 1 1
+35 1 1
+320 1 1
+22 1 1
+275 1 1
+47 1 1
+370 19 19
+119 1 6
+51 1 1
+21 1 1
+244 0 1
+345 1 1
+24 1 1
+181 1 1
+61 3 3
+542 1 1
+16 1 1
+312 1 0
+353 4 3
+279 323 0
+86 1 1
+49 1 1
+342 1 1
+44 0 2
+222 1 1
+37 1 1
+588 8 8
+593 2 2
+44 1 1
+359 1 1
+25 1 1
+1612 14 14
+428 1 0
+2510 1 0
+5051 0 1
+1489 9 9
+3292 1 0
+1449 1 1
+21 1 1
+6768 1 0
+706 2 0
+6662 1 1
+30 1 1
+228 1 1
+28 0 2
+300 5 5
+887 1 1
+23 1 1
+104 9625 10000
+107 1 1
+47 0 1
+63 1 1
+114 1 1
+219 1 1
+63 9 9
+35 1 1
+290 0 4
+45 0 1
+54 0 1
+40 1 3
+21 6 6
+54 1 1
+41 1 1
+155 1 1
+29 1 1
+220 1 1
+27 1 1
+611 1 1
+163 1 1
+134 1 1
+16 1 0
+5 1 1
+151 15 15
+138 2 2
+27 1 1
+73 2 2
+97 1 1
+204 1 1
+47 1 1
+84 1 1
+74 2 2
+381 20 20
+425 1 1
+21 1 1
+71 1 1
+28 1 1
+245 25 22
+71 1 1
+93 1 0
+82 1 1
+129 1 1
+26 1 1
+294 16 16
+1139 0 1
+1588 0 1
+51 9 9
+60 26 25
+312 15 11
+1008 17 17
+85 1 1
+49 1 1
+702 1 0
+87 1 1
+37 1 1
+859 8 8
+296 4 4
+105 0 4
+43 1 1
+67 10 7
+2839 3 0
+1283 1 1
+67 0 1
+32 2 0
+61 1 1
+140 15 15
+1047 1 1
+38 1 1
+87 1 1
+24 5 4
+1291 1 1
+49 1 1
+421 0 1
+75 1 1
+78 1 1
+243 1 0
+33 1 1
+116 19 19
+65 0 1
+238 0 1
+179 2 1
+67 1 1
+60 1 1
+32 1 1
+677 4 6
+83 314 0
+334 1 0
+1018 5 5
+127 1 1
+83 1 1
+347 0 2
+111 1 1
+30 1 1
+66 1 1
+38 1 1
+218 8 8
+754 1 1
+65 1 1
+182 1 1
+21 1 1
+285 1 1
+75 1 1
+147 6 0
+65 1 1
+42 1 1
+380 1 1
+84 2 0
+88 1 1
+25 1 1
+210 1 1
+17 1 1
+136 6 5
+108 1 1
+40 1 0
+50 1 1
+111 1 0
+21 0 1066
+119 0 1
+2641 1 1
+22 1 1
+689 1 1
+41 1 1
+1415 1 1
+29 1 1
+2252 1 1
+19 1 1
+1524 0 10
+2104 0 1
+511 2 0
+1696 26 8
+2593 0 177
+338 1 1
+37 2 2
+395 10 0
+67 1 1
+131 1 1
+31 1 1
+386 1 1
+42 1 1
+372 1 1
+48 1 1
+8705 0 3
+330 9 9
+600 2 0
+261 8 8
+9909 0 2
+2337 2 0
+2567 1 1
+26 1 1
+561 1 1
+48 1 1
+2440 1 1
+30 1 1
+1289 0 1
+162 1 0
+730 0 3
+658 1 0
+25 1 1
+1027 1 1
+43 1 1
+472 0 1
+219 1 1
+20 1 1
+495 1 0
+6 2 0
+1007 0 1
+169 0 10
+33 1 1
+266 11 11
+752 1 1
+30 1 1
+438 1 1
+39 1 1
+511 0 1
+1247 1 0
+1055 1 0
+491 1 0
+108 1 1
+48 1 1
+1324 0 1
+143 1 1
+40 1 1
+679 1 1
+45 1 1
+1036 0 2
+58 1 1
+46 1 1
+229 16 16
+149 10 10
+94 1 1
+63 1 1
+222 1 0
+55 1 1
+115 5 1
+219 15 15
+692 28 28
+159 1 1
+41 1 1
+211 1 0
+20 1 1
+1099 0 4
+155 6 0
+178 13 15
+32 1 1
+953 1 1
+47 1 1
+174 1 1
+22 1 1
+401 0 13
+588 5 21
+130 1 1
+157 4 4
+86 1 1
+29 0 2
+67 3 0
+641 0 1
+571 0 1
+250 1 1
+34 1 1
+255 0 2
+572 12 12
+275 6 1
+974 0 1
+578 12 12
+612 1 1
+43 1 1
+56 0 7
+1170 0 1
+1236 0 4
+2118 5 0
+1090 0 2
+4424 1 1
+34 1 1
+4897 8 0
+2112 0 1
+2874 1 1
+21 1 1
+442 22 22
+805 0 1
+3476 16 0
+7063 0 1
+65 3 0
+4293 0 1
+3181 0 4
+9515 5 1
+172 1 1
+49 1 1
+320 1 1
+34 1 1
+10677 2 0
+4856 3 0
+6082 1 0
+955 0 1
+1720 6 0
+17 1 0
+8156 53709 53709
+819 9 0
+1244 1 1
+32 5 5
+2063 14 0
+357 3 0
+321 46 46
+873 1 1
+47 1 1
+1156 10 9
+1180 29 25
+247 9 9
+1870 0 1
+17 1 0
+366 7 7
+101 0 1
+134 8 8
+1654 0 4
+8741 1 1
+24 1 1
+991 0 210
+20 2 0
+906 13 13
+478 1 1
+21 1 1
+812 88 88
+2215 16 16
+1485 1 1
+18 1 1
+883 1 1
+20 1 1
+1354 1 1
+28 1 1
+283 5 5
+640 1 1
+40 1 1
+560 1 1
+42 1 1
+1144 19 19
+57 1 1
+21 1 1
+216 1 1
+109 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 40 40
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 5 5
+23 1 1
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+427 1 1
+115 1 1
+232 1 1
+94 1 1
+809 1 0
+2261 16 15
+1824 1 0
+1990 1 0
+9965 0 18
+2951 6 0
+798 1 1
+30 1 1
+159 1 1
+124 1 1
+661 1 1
+31 1 1
+2632 4 4
+4024 0 16
+9373 7 7
+8626 0 1
+316 0 26
+10715 6 6
+110 1 1
+25 0 1
+7753 1 1
+30 0 1
+4078 0 2
+5144 1 1
+36 1 1
+69 1 1
+21 1 1
+135 1 1
+85 1 1
+125 3 4
+128 5 5
+24 1 1
+91 1 1
+61 15 0
+69 1 1
+78 0 19
+64 1 1
+138 1 1
+31 1 1
+510 18 7
+161 1 1
+30 1 1
+119 1 1
+26 1 1
+291 2 1
+143 1 1
+29 1 1
+293 1 1
+158 4 4
+87 32 32
+778 1 1
+58 0 1
+127 1 1
+75 28 0
+26 0 2
+204 207869 207869
+1739 1 0
+702 0 1
+5133 0 2
+3096 1 0
+315 1 0
+490 0 1
+2588 3 0
+1013 0 1
+3659 1 0
+2412 1 2
+2723 4 0
+523
+
+chain 80965 chr6_apd_hap1 4622290 + 2323391 2324248 chr6 170899992 - 139781917 139782778 1559018
+341 0 4
+516
+
+chain 30899 chr6_apd_hap1 4622290 + 1238363 1238687 chr13 114142980 + 81787211 81787535 4477038
+324
+
+chain 29563 chr6_apd_hap1 4622290 + 3995951 3996260 chr1 247249719 - 75038034 75038343 4838475
+309
+
+chain 28633 chr6_apd_hap1 4622290 + 2292529 2292831 chr7 158821424 - 147037095 147037398 5180885
+171 0 1
+131
+
+chain 28481 chr6_apd_hap1 4622290 + 4061349 4061647 chr17 78774742 + 29063769 29064067 5407270
+298
+
+chain 23990 chr6_apd_hap1 4622290 + 1105022 1105798 chr7 158821424 - 51137320 51138262 7695539
+178 101 101
+72 385 551
+40
+
+chain 15671 chr6_apd_hap1 4622290 + 1097871 1099106 chr6 170899992 - 139552636 139553881 14365447
+56 408 416
+54 620 622
+97
+
+chain 15338 chr6_apd_hap1 4622290 + 4034892 4035065 chr1 247249719 - 181871461 181871634 14713407
+25 1 0
+58 0 1
+89
+
+chain 13894 chr6_apd_hap1 4622290 + 1139363 1141753 chr6 170899992 + 30021566 30022999 16323533
+75 1920 964
+70 255 254
+70
+
+chain 11891 chr6_apd_hap1 4622290 + 3988844 3989392 chrX 154913754 + 64750681 64751228 19168306
+89 401 400
+58
+
+chain 11819 chr6_apd_hap1 4622290 + 1140317 1140448 chr19 63811651 + 15986621 15986752 19293908
+131
+
+chain 11746 chr6_apd_hap1 4622290 + 1091182 1091330 chr7 158821424 - 7754727 7754875 19419742
+54 14 14
+80
+
+chain 9888 chr6_apd_hap1 4622290 + 4031953 4032128 chr8 146274826 + 50466266 50466441 23070160
+60 56 56
+59
+
+chain 9560 chr6_apd_hap1 4622290 + 1092932 1093033 chr6 170899992 - 141000133 141000234 23851264
+101
+
+chain 7776 chr6_apd_hap1 4622290 + 4298814 4298901 chr8 146274826 + 14484871 14484958 2851549
+87
+
+chain 6175 chr6_apd_hap1 4622290 + 1094444 1094508 chr6 170899992 + 30079296 30079360 30094026
+64
+
+chain 6113 chr6_apd_hap1 4622290 + 3989871 3989936 chrX 154913754 - 39339630 39339695 30268027
+65
+
+chain 5831 chr6_apd_hap1 4622290 + 3989150 3989212 chr2 242951149 + 73586935 73586997 31012834
+62
+
+chain 5731 chr6_apd_hap1 4622290 + 1104489 1104550 chr6 170899992 + 29872087 29872148 31286972
+61
+
+chain 5730 chr6_apd_hap1 4622290 + 1107647 1107707 chr6 170899992 + 29878483 29878543 31293431
+60
+
+chain 5676 chr6_apd_hap1 4622290 + 1093802 1093862 chr8 146274826 - 42258664 42258724 31433499
+60
+
+chain 5492 chr6_apd_hap1 4622290 + 4034227 4034285 chr22 49691432 - 27111287 27111345 17799541
+58
+
+chain 5339 chr6_apd_hap1 4622290 + 3987866 3987922 chr2 242951149 + 186720203 186720259 32420506
+56
+
+chain 5203 chr6_apd_hap1 4622290 + 3989590 3989645 chr5 180857866 + 19136434 19136489 32834289
+55
+
+chain 4712 chr6_apd_hap1 4622290 + 4038649 4038699 chr4 191273063 + 53804403 53804453 34512110
+50
+
+chain 4392 chr6_apd_hap1 4622290 + 1105241 1105300 chr7 158821424 - 126060926 126060985 9905437
+59
+
+chain 2852 chr6_apd_hap1 4622290 + 4034783 4034846 chr15 100338915 + 44177073 44177136 17837211
+63
+
+chain 2740 chr6_apd_hap1 4622290 + 3988933 3988962 chr7 158821424 + 83092272 83092301 22772951
+29
+
+chain 2440 chr6_apd_hap1 4622290 + 3988349 3988416 chr3 199501827 + 102678562 102678629 22367094
+67
+
+chain 2360 chr6_apd_hap1 4622290 + 4034867 4034892 chr4 191273063 - 72949130 72949155 34483441
+25
+
+chain 2247 chr6_apd_hap1 4622290 + 4033024 4033048 chr20 62435964 - 19518135 19518159 35490184
+24
+
+chain 2194 chr6_apd_hap1 4622290 + 1105201 1105241 chrX 154913754 - 101365357 101365397 11073770
+40
+
+chain 2146 chr6_apd_hap1 4622290 + 1091395 1091456 chr12 132349534 + 104221177 104221238 23825288
+61
+
+chain 2000 chr6_apd_hap1 4622290 + 1105373 1105406 chr4 191273063 + 153905795 153905828 8127683
+33
+
+chain 1977 chr6_apd_hap1 4622290 + 3989088 3989138 chr18 76117153 - 10057795 10057845 19617710
+50
+
+chain 1946 chr6_apd_hap1 4622290 + 1105615 1105690 chr1 247249719 - 137852311 137852386 12720712
+75
+
+chain 1584 chr6_apd_hap1 4622290 + 1105480 1105544 chr1 247249719 - 24894387 24894451 17598706
+64
+
+chain 1098 chr6_apd_hap1 4622290 + 4034150 4034227 chr3 199501827 + 101474041 101474118 17425868
+77
+
+chain 917 chr6_apd_hap1 4622290 + 4034367 4034423 chr8 146274826 + 48207051 48207107 19960483
+56
+
+chain 847 chr6_apd_hap1 4622290 + 3988270 3988330 chr20 62435964 - 51574691 51574751 25106564
+60
+
+chain 754 chr6_apd_hap1 4622290 + 3988131 3988185 chr6 170899992 + 30241568 30241622 20370721
+54
+
+chain 747 chr6_apd_hap1 4622290 + 1105904 1105968 chr12 132349534 + 55464534 55464598 20643869
+64
+
+chain 716 chr6_apd_hap1 4622290 + 3989517 3989569 chr16 88827254 - 38714794 38714846 22851158
+52
+
+chain 604 chr6_apd_hap1 4622290 + 1105798 1105824 chrX 154913754 - 101148638 101148664 11583040
+26
+
+chain 420574415 chr6_cox_hap2 4795371 + 0 4795371 chr6 170899992 + 28585775 33459520 26
+95659 1 0
+2669 19 19
+7247 1 2
+1704 0 4
+1513 0 2
+49 2 0
+2160 0 5
+672 1 1
+38 1 1
+1384 1 0
+1685 1 1
+30 1 1
+2421 1 1
+42 1 1
+830 1 1
+41 1 1
+1630 0 1
+7458 1 0
+691 0 1
+525 0 1
+79 1 1
+29 1 1
+2055 1 1
+16 0 24
+1867 5 7
+786 0 2
+280 0 1
+227 2 0
+6678 1 0
+4401 1 0
+210 1 0
+3193 2 0
+3619 0 1
+2414 0 2
+5387 0 3
+2927 0 1
+3304 0 1
+440 0 5
+415 0 9
+3597 1 1
+48 1 1
+3412 1 1
+46 1 1
+3604 4 4
+1063 1 1
+36 1 1
+6311 0 1
+35 0 8
+393 0 1
+477 1 1
+37 1 1
+2459 2 0
+517 0 12
+318 0 1
+1010 7 6
+2103 0 1
+5171 0 8
+1483 1 0
+3813 888 0
+4675 0 2
+5620 1 0
+2017 1 0
+3363 0 5
+1197 0 3
+3208 1 0
+1928 1 0
+174 6 0
+780 1 3
+443 14 0
+3079 0 5
+1993 0 3
+1089 1 1
+58 1 1
+80 0 8
+256 2 0
+2473 37 43
+752 0 2
+33 0 2
+825 0 1
+787 1 1
+37 1 1
+1168 16 0
+377 5 1
+27 1 1
+2161 2 0
+2324 1 0
+1757 6 6
+205 4 0
+203 7 7
+107 1 1
+28 1 1
+100 4 4
+258 5 0
+659 1 0
+3805 5 8
+1486 4 4
+213 39 43
+4429 0 2
+1199 13 13
+5814 18 6
+2970 0 1
+813 0 17
+920 2 0
+3820 1 3
+130 21 9
+1913 0 14
+1800 0 1
+1255 2 0
+1466 4 0
+747 0 1
+124 2 0
+2108 1 0
+169 0 26
+593 1 0
+632 5 0
+2711 0 4
+1042 0 1
+34 1 1
+1025 2 0
+27 4 18
+81 1 33
+33 0 1
+6 0 76
+3950 1 0
+86 1 1
+12 1 1
+2947 0 1
+1160 1 0
+2046 3 0
+720 1 0
+1341 1 0
+10205 0 5
+1265 1 0
+10 1 1
+1278 5 6
+340 9 9
+50 0 32
+96 16 18
+605 4 0
+1072 12 12
+950 11 7
+5137 0 1
+2711 1 0
+676 0 1
+2904 1 1
+30 1 1
+851 0 1
+1410 0 1
+394 1 1
+57 1 1
+1561 0 2
+14360 1 1
+42 1 1
+269 1 0
+284 3 3
+24 1 0
+2796 0 5
+2451 28 0
+2251 1 1
+32 1 0
+10 0 4
+24 1 1
+694 0 2
+3475 0 1
+2008 1 1
+49 1 1
+475 1 1
+28 1 1
+259 160 0
+1854 5 4
+1621 3 0
+1791 1 0
+316 0 2
+1169 0 1
+2549 1 0
+2941 1 1
+34 1 1
+243 9 0
+5157 0 2
+1748 0 8
+472 4 0
+2470 0 4
+402 1 0
+643 2 0
+748 0 2
+859 1 0
+409 2 0
+267 0 2
+322 0 4
+155 1 0
+9957 0 4
+1440 4 4
+127 1 0
+1085 1 0
+131 1 0
+767 1 0
+1160 21 21
+1294 1 0
+712 1 0
+1819 2 1
+464 1 0
+6944 0 4261
+55 0 7
+1235 0 3
+702 0 24
+2847 0 1
+2428 3 0
+7517 0 1
+3204 1 0
+611 1 0
+7104 1 0
+4959 14 14
+2827 1 0
+9421 82 25
+2434 43 43
+1951 8 0
+8136 0 2
+344 1 0
+4216 1 0
+810 0 5
+4443 1 0
+10291 10 0
+7265 5 0
+7041 1 0
+6007 1 0
+8185 4 0
+4961 0 3
+13564 0 1
+1475 0 2
+105 0 10
+10104 2 0
+3073 1 0
+3715 8 0
+13731 0 2
+837 61 1
+9404 0 1
+6068 7 0
+916 0 4
+569 1 1
+72 1 1
+2260 0 2
+7036 4 0
+3591 0 3
+713 4 0
+10388 0 2
+8475 0 1
+1324 0 2
+5438 5 0
+156 1 1
+44 0 1
+21501 7 7
+3359 16 16
+2138 0 5
+4406 11 11
+1525 1 1
+28 1 1
+2159 16 0
+48 4 0
+3030 0 1
+5717 10 0
+6594 2 0
+1954 1 0
+4 1 0
+3599 1 0
+7515 4 0
+979 0 2
+1990 0 10
+123 1 1
+27 1 1
+1255 0 2
+2769 5 5
+727 1 1
+26 3 3
+785 0 1
+24359 1 0
+5978 5 5
+66 1 1
+46 1 1
+18539 1 0
+7732 2 0
+652 0 1
+861 0 1
+11988 0 1
+3515 3 0
+19 18 0
+539 0 1
+655 2 0
+10586 2 0
+2385 0 1
+2979 10 10
+4600 1 0
+29834 1 1
+27 1 1
+1216 1 0
+1323 1 0
+673 0 3
+20031 0 3
+2841 13 0
+1841 4 0
+6446 1 0
+11727 0 1
+8427 17 17
+2864 0 143
+4107 0 8
+748 0 2
+3417 1 1
+32 1 1
+18799 0 2
+21810 1 1
+34 1 1
+2784 2 0
+7864 2 0
+4498 0 1
+49089 1 1
+32 1 1
+509 1 1
+37 1 1
+5371 22 16
+389 1 1
+21 1 1
+806 1 0
+1638 6 6
+228 1 1
+45 1 1
+2068 6 3
+441 1 0
+2338 1 0
+1948 1 1
+26 1 1
+214 0 1
+6118 1 1
+31 1 1
+2382 5 5
+4335 1 1
+39 1 1
+4561 1 1
+38 1 1
+2199 1 1
+49 1 1
+243 19 6
+2779 1 1
+37 2 0
+24 1 1
+1966 3 0
+233 1 1
+29 1 1
+13756 0 4
+3956 4 1
+46569 1 0
+18985 0 8
+1384 3 1
+85 1 0
+3539 1 1
+32 1 1
+145 1 0
+1245 2 0
+1736 1 1
+29 1 1
+1656 1 5
+712 10 11
+502 0 1
+3670 1 0
+740 0 1
+1693 0 1
+6497 0 2
+2898 1 3
+141 0 1
+1108 0 2
+1448 1 0
+947 31 31
+362 0 1
+7684 8 0
+2880 1 2
+30 8 0
+896 21 3
+395 1 1
+37 3 0
+23 1 2
+1210 18 0
+65 1 1
+20 1 1
+791 0 4
+389 1 0
+809 1 1
+55 0 7
+428 1 1
+17 1 1
+239 1 1
+20 1 1
+69 1 1
+37 1 1
+955 1 0
+839 0 1
+165 1 0
+3867 0 5
+70 1 1
+27 1 1
+899 1 2
+107 1 0
+1457 1 0
+763 12 5
+35 1 1
+1417 10 10
+121 1 1
+38 0 3
+377 1 0
+505 1 0
+11 4 0
+297 0 24
+337 11 0
+134 1 1
+694 3 0
+72 1 1
+144 128 128
+169 2 0
+1011 1 0
+107 1 1
+1280 1 1
+73 1 1
+84 25 25
+287 1 1
+26 1 1
+139 1 1
+41 1 1
+440 4 0
+130 12 12
+435 21 0
+85 1 1
+28 1 1
+73 1 1
+115 5 1
+70 1 2
+52 2 0
+157 30 30
+554 2 2
+128 1 5
+68 1 1
+44 1 1
+125 0 1
+57 1 1
+308 0 7
+15 1 1
+725 9 0
+60 1 1
+180 1 1
+55 1 1
+61 1 1
+23 1 0
+5 1 2
+88 1 1
+56 1 1
+433 2 0
+84 1 1
+66 1 1
+182 12 12
+216 1 1
+94 1 1
+561 1 1
+16 1 1
+113 1 1
+86 1 1
+148 2 0
+75 2 0
+77 1 21
+209 3 8
+99 31 31
+244 1 0
+173 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+327 1 1
+54 5 5
+929 1 1
+21 1 1
+97 1 1
+28 0 3
+830 0 2
+68 1 1
+525 0 1
+2081 1 1
+41 1 1
+165 3 3
+46 1 0
+378 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 1 1
+39 1 1
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+240 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+321 1 1
+63 1 1
+504 18 18
+662 1 1
+74 1 1
+248 1 1
+34 1 1
+1507 0 10
+1051 0 2611
+560 3 3
+23 1 1
+1631 0 15
+78 4 0
+160 0 21
+3764 0 4
+1358 0 1
+1773 1 1
+43 1 1
+1263 1 1
+39 1 1
+183 0 16
+3001 40 40
+1056 10 0
+1261 1 1
+20 1 1
+137 1 0
+2351 1 1
+43 1 1
+1010 0 4
+536 1 1
+38 1 1
+381 0 1
+888 19 19
+1521 1 1
+27 1 1
+161 1 1
+46 1 1
+2659 2 0
+533 10 0
+441 1 12
+1684 1 1
+26 3 4
+879 16 16
+514 0 2
+58 1 1
+117 1 1
+24 1 1
+207 1 0
+38 1 1
+730 1 1
+39 1 1
+573 0 4
+37 1 1
+144 8 8
+1036 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+317 0 3
+1256 0 2
+332 1 1
+21 1 1
+193 8 28
+30 1 1
+79 1 1
+29 1 1
+536 1 0
+611 1 1
+25 1 1
+399 4 4
+118 0 32
+23 1 1
+116 1 1
+30 1 1
+503 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 4
+711 7 7
+89 1 0
+291 1 0
+167 1 1
+24 1 1
+167 6 6
+171 17 17
+681 1 1
+43 1 1
+538 1 1
+44 1 1
+537 16 16
+180 6 6
+778 2 2
+44 1 1
+168 0 7
+211 1 1
+42 1 1
+1253 1 1
+29 1 1
+320 1 1
+36 2 2
+55 1 2
+460 1 1
+35 1 1
+553 8 8
+386 1 1
+26 1 1
+540 1 1
+31 1 1
+65 0 1
+625 12 12
+313 0 1
+52 1 1
+22 1 1
+583 1 1
+49 1 1
+1499 3 0
+770 1 1
+87 11 0
+323 19 19
+787 1 1
+36 1 1
+553 8 8
+997 16 15
+157 1 1
+31 2 2
+204 18 19
+487 1 1
+29 1 1
+374 1 1
+67 1 1
+720 13 13
+266 10 10
+330 16 14
+413 1 1
+44 1 1
+78 6 6
+181 2 2
+36 1 1
+397 1 1
+20 1 1
+311 1 1
+48 2 2
+1746 4 4
+35 1 1
+194 10 10
+310 1 1
+51 1 1
+136 1 1
+49 1 1
+521 1 1
+23 1 1
+220 73 73
+735 3 3
+123 1 1
+184 15 15
+216 1 1
+21 1 1
+51 1 1
+49 1 1
+527 17 17
+340 12 11
+1025 1 0
+2572 1 1
+29 1 1
+397 2 5
+668 13 13
+541 1 1
+59 0 2
+6 1 1
+122 14 14
+51 1 1
+46 1 1
+429 0 21
+136 1 1
+12 1 1
+66 16 16
+456 37 34
+371 7 7
+48 1 1
+194 10 10
+108 1 1
+60 1 1
+122 49 50
+238 1 1
+32 0 1
+100 1 0
+72 1 0
+390 1 1
+38 1 1
+144 1 1
+27 0 4
+184 21 228
+49 1 1
+608 0 1
+152 1 1
+31 1 1
+281 8 8
+337 1 1
+45 1 1
+222 1 1
+20 1 1
+380 1 0
+44 1 1
+368 1 1
+72 1 1
+502 36 18
+63 1 1
+43 0 4
+136 1 1
+42 1 1
+80 4 4
+35 1 0
+89 1 1
+24 0 5
+829 13 13
+102 14 0
+233 1 1
+42 0 3
+85 0 1
+400 1 1
+40 1 1
+538 25 25
+174 1 1
+20 1 1
+705 1 1
+26 2 2
+614 1 1
+44 1 1
+509 1 1
+32 1 1
+224 1 1
+42 1 1
+99 38 38
+610 5 5
+804 1 1
+29 1 1
+166 1 1
+43 1 1
+233 1 1
+44 1 1
+620 8 8
+133 1 1
+31 1 1
+165 1 1
+29 1 1
+1249 1 1
+26 4 0
+56 1 1
+67 1 1
+716 1 1
+46 0 1
+16 1 1
+174 1 1
+96 1 1
+141 1 1
+39 0 4
+263 1 1
+18 1 1
+259 4 4
+38 1 1
+104 1 1
+40 1 0
+248 1 1
+18 1 1
+238 1 1
+32 1 1
+70 0 2
+16 1 1
+818 1 1
+22 4 4
+1641 1 1
+46 1 1
+53 1 0
+38 1 1
+373 62 62
+1149 0 2
+19 1 1
+1653 4 4
+42 1 1
+218 12 12
+363 1 1
+24 1 1
+457 10 10
+414 13 13
+825 1 1
+41 1 1
+492 0 8
+1370 1 1
+18 1 1
+1145 6 4
+880 1 1
+35 1 1
+236 1 1
+67 1 1
+298 0 1
+147 14 14
+312 11 11
+613 1 1
+62 1 1
+340 1 1
+22 1 1
+1057 1 1
+57 1 1
+358 1 1
+128 1 1
+146 10 10
+490 1 1
+20 1 1
+62 1 1
+88 1 1
+293 1 1
+28 1 0
+20 1 1
+83 0 1
+90 1 1
+312 1 1
+44 1 1
+1213 1 1
+51 1 1
+467 1 1
+39 1 1
+122 14 0
+35 1 1
+485 14 14
+110 13 0
+127 1 1
+7112 0 8
+45 4 0
+3276 0 2
+28 1 1
+2195 17 16
+1325 18 18
+1304 3727 0
+299 0 248
+2603 2 0
+160 1 1
+34 1 1
+631 1 1
+40 1 3
+38 1 1
+332 17 17
+231 14 14
+202 1 1
+199 1 1
+71 1 1
+42 1 0
+53 11 10
+83 1 1
+31 1 1
+135 1 1
+50 3 0
+32 1 1
+194 1 1
+45 1 1
+143 1 1
+78 1 1
+193 6 0
+40 1 1
+432 1 1
+17 1 1
+429 3 6
+58 236 236
+57 1 1
+51 2 2
+278 1 1
+49 1 1
+77 11 11
+120 0 4
+139 1 1
+30 2 2
+205 4 4
+131 1 1
+22 1 1
+251 1 1
+34 1 1
+175 1 1
+36 1 1
+239 1 1
+32 5 5
+63 1 1
+27 1 1
+78 1 1
+19 1 1
+209 1 1
+143 1 13
+176 0 1
+7 0 8
+375 0 1
+62 1 1
+129 2 2
+135 1 1
+88 8 0
+90 6 8
+796 2 0
+1219 1 1
+34 1 1
+833 1 1
+46 1 1
+74 1 1
+45 1 1
+95 1 1
+29 1 1
+298 0 3
+47 1 1
+311 1 1
+58 1 1
+349 9 9
+214 1 1
+37 3 0
+413 11 11
+54 1 1
+97 1 1
+137 0 2
+95 1 1
+257 3 0
+35 1 1
+66 1 1
+47 1 1
+104 7 7
+220 17 17
+207 44327 50000
+112 1 1
+39 1 1
+330 1 1
+24 1 1
+197 1 1
+69 1 1
+116 3 0
+161 1 1
+38 1 1
+753 1 1
+57 3 3
+145 1 1
+121 1 1
+300 1 1
+147 1 1
+379 1 1
+55 2 2
+65 1 1
+32 1 1
+1008 1 1
+24 1 1
+159 18 18
+659 1 1
+76 0 2
+77 1 3
+65 1 1
+84 1 0
+119 1 1
+15 1 1
+247 4 0
+372 1 0
+1633 1 1
+16 1 1
+456 7 7
+114 1 1
+102 1 1
+109 4 0
+61 2 2
+80 1 1
+47 1 1
+168 1 1
+31 1 1
+269 2 2
+42 1 1
+626 2 2
+14 1 1
+76 8356 10147
+66 2 2
+80 0 41
+12 1 1
+158 1 0
+92 2 0
+254 1 1
+43 1 1
+846 6 149
+84 1 1
+29 3 3
+315 17 17
+482 1 1
+29 3 3
+278 1 1
+73 1 1
+2767 1 1
+34 1 1
+192 1 1
+33 1 0
+168 6 0
+276 10 10
+344 1 1
+49 1 1
+109 1 1
+35 3 3
+561 24 27
+923 1 1
+102 1 1
+75 14 14
+266 1 1
+80 2 2
+185 1 0
+1035 1 1
+23 1 1
+417 10 10
+97 1 1
+94 1 1
+492 1 1
+37 5 5
+1429 1 1
+19 1 1
+839 1 1
+96 1 1
+1279 4 0
+683 1 1
+49 1 1
+514 1 1
+28 4 4
+2302 1 1
+42 1 1
+537 2 21
+1555 1 1
+42 0 1
+14 4 4
+86 1 1
+62 1 1
+515 5 1
+330 0 1
+159 0 22
+3841 1 0
+3862 16 16
+1187 12 12
+97 0 3
+772 1 1
+21 2 1
+1058 0 2
+349 2 0
+1080 6 0
+11 1 3
+53 0 2
+14 1 1
+1035 1 1
+85 1 1
+69 1 1
+27 1 1
+547 7 7
+195 1 1
+41 1 1
+395 1 1
+35 1 1
+73 0 1
+71 1 1
+557 3 3
+30 1 1
+66 1 1
+25 1 1
+1332 0 2
+26 2 0
+10 1 15
+36 1 1
+196 1 1
+40 1 1
+141 1 1
+76 1 1
+1480 1 3
+347 1 1
+26 1 1
+231 1 1
+82 3 3
+69 3 0
+441 16 16
+147 1 1
+21 1 1
+3565 0 3
+877 2 0
+1036 1 1
+47 2 1
+3761 12 0
+5345 1 0
+11541 1 0
+1843 0 4
+1157 16 16
+7354 19 0
+741 0 1
+8053 1 0
+4449 21 21
+649 1 0
+2913 0 1
+381 331 0
+3533 31 31
+2502 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3870 0 1
+36 13 0
+1894 1 1
+40 0 4
+1137 6 0
+211 2 0
+345 1 0
+592 4 4
+1043 4 0
+686 14 0
+1032 0 1
+9035 0 4
+167 0 2
+23964 0 3
+1470 0 1
+289 3 0
+4343 1 0
+2026 8 0
+430 0 1
+631 1 1
+21 1 1
+479 0 1
+697 4 0
+1779 1 1
+27 1 1
+196 4 0
+58 8 0
+2881 1 1
+39 1 1
+120 1 2
+24 1 1
+556 1 0
+393 6 6
+3090 1 1
+43 1 1
+1246 1 0
+294 1 1
+27 1 1
+374 3 3
+144 1 1
+190 1 6
+750 1 0
+695 2 0
+1003 11 0
+1956 0 4
+1235 19 19
+1483 11 11
+453 1 0
+536 1 1
+43 1 1
+57 1 0
+21 7 0
+3892 0 1
+3177 0 1
+8990 0 2
+2267 1 1
+35 1 0
+2850 4 0
+1273 0 2
+5863 1 0
+9593 1 1
+81 1 1
+2777 0 2
+5272 0 8
+11548 2 0
+6086 0 1
+109 1 1
+2286 0 1
+997 0 18
+3344 1 1
+40 1 1
+842 28 24
+1584 1 0
+1582 0 1
+1670 3 25
+17 0 4
+16 2 0
+6 12 0
+49 1 1
+538 1 1
+26 1 1
+5879 2 4
+2513 0 1
+346 8 8
+222 16 16
+103 1 0
+198 1 3
+539 1 1
+47 1 1
+1154 0 1
+3737 1 2
+370 2 0
+1178 1 1
+78 1 1
+47 0 1
+518 6 0
+646 13 13
+469 1 0
+1072 1 4
+858 1 0
+3674 1 0
+282 1 0
+597 0 6
+505 4 4
+183 1 1
+43 1 1
+1294 1 1
+40 1 1
+572 0 4
+464 0 4
+1886 2 0
+548 1 0
+1300 0 3
+1839 2 0
+189 1 1
+49 1 1
+1253 1 1
+43 1 0
+498 1 1
+45 4 0
+3538 0 1
+1582 31 31
+376 14 14
+1332 2 0
+3586 1 0
+989 1 2
+447 0 4
+40 1 1
+2445 16 17
+291 1 3
+7 1 0
+11 0 1
+41 1 1
+94 1 1
+49 1 1
+1515 6 0
+603 13 13
+163 1 1
+45 1 1
+2050 11 11
+1126 1 1
+16 1 1
+391 1 1
+19 0 1
+932 1 0
+42 1 1
+751 1 0
+287 1 1
+42 1 1
+464 0 4
+4069 5 5
+153 1 0
+514 2 0
+1093 1 1
+41 1 1
+1746 4 4
+1351 1 1
+38 1 1
+1213 0 72
+168 18 18
+146 7 7
+293 1 1
+61 0 1
+43 1 1
+236 1 0
+35 1 1
+152 14 14
+240 13 13
+523 0 4
+809 4 0
+155 1 1
+44 1 1
+1068 1 1
+93 1 1
+209 15 15
+1331 0 3
+3912 0 1
+6624 0 4
+375 0 1
+7255 5 0
+419 2 0
+293 1 0
+10397 5 24
+11095 0 1
+1770 4 0
+374 0 4
+7714 1 0
+1229 7 6
+3055 1 0
+5818 1 0
+2415 11 9
+2056 0 1
+955 4 0
+3907 0 2
+16936 0 1
+1044 1 0
+2392 0 1
+158 2 1
+199 0 1
+75 6 6
+2094 8 0
+649 2 0
+373 1 1
+39 1 1
+2287 1 0
+15 1 0
+1995 0 2
+818 4 0
+676 0 1
+3171 8 0
+170 0 3
+459 1 1
+37 1 1
+336 1 0
+206 1 1
+26 1 1
+224 15 15
+308 2 1
+82 1 1
+23 1 1
+562 1 1
+80 1 1
+241 0 8
+1530 1 1
+20 1 1
+1372 1 1
+44 1 1
+427 1 1
+20 1 1
+651 105 81
+221 1 1
+45 1 1
+1747 1 1
+27 1 1
+179 1 1
+70 1 1
+173 1 1
+84 0 36
+1864 1 1
+41 1 1
+44 9 0
+1028 1 0
+85 1 1
+21 1 1
+474 1 3
+256 1 1
+31 1 1
+653 1 1
+18 1 1
+62 1 1
+19 1 1
+997 1 1
+22 1 1
+326 1 0
+505 5 4
+386 0 7
+466 13 13
+870 11 12
+134 15 15
+248 0 2
+2281 1 1
+79 1 1
+56 9 6
+528 1 1
+68 1 1
+802 1 0
+290 1 1
+38 1 1
+185 1 1
+61 1 1
+944 1 1
+22 1 1
+835 1 1
+66 1 1
+890 0 1
+3503 6 6
+231 0 1
+2136 1 0
+999 1 0
+5220 3 4
+830 1 1
+24 1 1
+1209 1 1
+38 1 1
+7077 1 0
+2939 1 0
+3511 47 47
+401 0 2
+3746 0 2
+1011 1 1
+34 1 1
+7443 0 1
+688 2 0
+574 1 1
+29 1 1
+1785 2 0
+16 20 0
+4073 2 0
+136 79 79
+528 27 0
+253 0 1
+204 1 0
+129 2 0
+811 1 1
+38 1 1
+2347 52 0
+4634 1 0
+856 14 14
+1052 1 1
+28 1 1
+1255 1 1
+36 1 1
+97 0 1
+58 1 1
+1708 1 1
+48 1 1
+958 13 0
+3371 1 1
+37 1 1
+4267 0 15
+1059 0 1
+272 0 20
+168 2 0
+26 4 32
+4090 0 2
+3269 1 1
+17 1 2
+1378 1 0
+1443 0 1
+6206 1 0
+2318 0 1
+7695 2 0
+396 22 12
+918 0 1
+1818 0 1
+28 1 1
+492 1 1
+33 1 1
+326 1 1
+80 1 1
+288 8 17
+2671 0 1
+1099 0 1
+144 1 1
+29 0 1
+2098 0 2
+24 4 0
+1207 4 4
+45 1 1
+757 0 5
+1926 1 1
+40 1 1
+2657 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+713 0 4
+58 1 0
+1027 3 0
+428 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+8189 4 5
+36 1 1
+102 2 0
+14 1 1
+682 0 6
+147 0 1
+750 0 3
+40 1 1
+2428 0 1
+750 2 0
+473 0 2
+2032 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+11881 1 1
+30 1 1
+4383 2 0
+10078 0 1
+906 2 0
+887 1 1
+80 1 1
+2210 1 0
+905 0 1
+1037 1 0
+5866 0 2
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 4 0
+700 1 1
+2469 1 0
+1751 0 1
+910 2 0
+691 0 1
+32873 0 1
+1722 0 1
+17575 0 8
+1369 29 0
+494 2 0
+4432 0 1
+34617 0 1
+920 0 1
+4586 0 2
+2232 1 0
+5718 0 1
+12415 1 1
+51 0 1
+7997 0 2
+1700 1 0
+2697 1 0
+2561 2 0
+1544 0 6
+1613 3 7
+37 9 1
+2113 1 0
+7174 0 34
+7914 1 1
+35 1 1
+5308 1 0
+2303 2 1
+423 7 7
+590 1 0
+24 1 1
+165 6 0
+896 33 33
+1919 13 13
+64 0 1
+28 1 1
+723 0 4
+2868 0 1
+731 1 1
+60 1 1
+1012 3 0
+1744 1 1
+78 1 1
+61 1 0
+2362 11 11
+399 1 0
+1494 16 16
+128 24 24
+530 1 1
+35 1 1
+5276 1 0
+415 0 1
+580 1 2
+1450 22 23
+816 1 0
+1953 1 0
+881 10 1
+885 8 14
+183 14 14
+1319 1 1
+94 1 1
+419 3 3
+26 1 1
+56 1 0
+69 1 0
+117 1 1
+120 1 1
+42 1 1
+834 125 127
+956 3 0
+664 1 1
+41 1 1
+716 4 0
+1731 8 8
+4228 0 1
+5694 3 0
+4493 0 1
+1373 20 20
+1263 1 0
+3029 4 0
+5702 7 6
+150 2 0
+5972 0 2
+840 0 2
+55 1 1
+28 1 1
+2949 5 6
+4343 6 0
+1663 4 0
+150 1 0
+3128 1 0
+1449 3 0
+1534 1 0
+489 1 0
+431 0 4
+299 2 0
+5082 9 0
+156 1 1
+256 0 1
+992 14 16
+4924 0 1
+6655 1 0
+349 8 7
+762 1 1
+29 0 3
+1434 0 1
+1267 0 1
+587 1 1
+22 0 1
+894 28 0
+1343 2 0
+2256 0 1
+4332 0 4
+22 1 1
+5069 33 33
+7313 12 10
+10485 0 1
+1429 0 12
+625 1 7
+1224 0 10
+1680 4 0
+9061 0 8
+2544 0 140
+5451 33 33
+3754 0 1
+1575 0 3
+1775 1 1
+31 1 1
+1200 1 0
+32 0 3
+790 0 8
+42 0 2
+599 1 1
+22 1 1
+5338 2 0
+1998 0 5
+146 0 4
+12031 0 1
+1993 0 1
+706 2 0
+2735 0 1
+3859 0 4
+1304 47 47
+3494 0 2
+268 2 0
+827 4 4
+1063 6 6
+7834 2 0
+3195 0 1
+4012 10 0
+6429 0 2
+308 0 1
+808 1 0
+17 8 0
+5472 19 2
+2436 0 14
+820 9 9
+2643 1 1
+32 1 1
+1189 1 0
+5710 0 3
+308 1 0
+3028 14 14
+1888 0 1
+4308 1 0
+946 82 0
+1790 0 2
+1218 25 0
+52 0 1
+1271 1 1
+33 1 1
+4760 1 0
+4924 0 1
+4817 4 4
+39 1 0
+1116 3715 901
+205 1 0
+1591 5 2
+128 29 29
+802 0 89
+1600 0 6
+2175 0 5
+606 14 14
+519 1 0
+540 1 1
+40 1 1
+568 2 0
+458 1 1
+41 1 1
+1106 24 62
+818 1 1
+42 1 1
+2266 1 0
+14059 0 4
+5030 1 0
+12630 0 3
+84 9 9
+129 13 18
+564 10 15
+154 1 0
+438 10 10
+38 0 5
+98 11 9
+2034 1 1
+25 1 1
+73 10 10
+70 5 5
+132 1 1
+52 1 1
+599 1 1
+46 1 1
+279 1 1
+18 1 1
+239 3 0
+383 6 0
+224 0 1
+321 15 0
+1783 1 1
+18 3 0
+575 16 16
+60 1 1
+16 1 1
+970 1 1
+24 1 1
+424 3 0
+41 1 1
+57 8 8
+285 2 0
+672 1 1
+44 1 4
+103 0 1
+148 1 1
+49 3 0
+146 5 11
+91 1 1
+79 1 1
+94 1 1
+101 1 1
+88 16 16
+117 1 1
+15 1 1
+58 1 1
+93 1 1
+466 1 1
+44 1 1
+160 1 1
+23 1 1
+481 14 14
+181 4 4
+72 1 1
+25 1 1
+82 7 12
+4 0 1
+11 1 4
+20 0 5
+92 1 1
+56 10 0
+80 1 1
+141 2 0
+60 1 1
+372 0 2
+784 1 1
+85 1 1
+109 1 1
+16 1 1
+57 1 1
+92 3 1
+23 1 0
+26 1 1
+74 1 1
+33 1 1
+176 1 1
+25 2 2
+193 42 43
+377 0 5
+249 1 1
+69 1 1
+98 1 1
+70 1 1
+55 1 1
+143 1 1
+438 1 1
+64 1 1
+53 4 0
+127 3 0
+75 5 5
+45 1 1
+197 1 1
+27 1 1
+116 13 13
+218 15 20
+1107 16 19
+73 1 1
+25 1 1
+199 1 1
+60 1 1
+994 1 1
+43 0 1
+18 1 1
+1215 18 18
+340 1 1
+34 1 1
+2783 1 1
+29 1 1
+475 82 82
+166 10 10
+87 1 1
+18 1 1
+171 7 7
+427 1 1
+21 1 1
+2011 0 3
+17 1 1
+1412 1 1
+24 1 1
+214 8 4
+228 1 1
+34 1 1
+410 16 16
+185 1 1
+24 1 0
+164 0 1
+222 1 1
+25 1 1
+297 10 10
+1171 1 0
+3343 1 0
+11 1 1
+2502 1 1
+23 1 1
+44 12 0
+2856 0 1
+148 1 1
+36 1 1
+993 2 0
+1251 2 0
+6619 14 14
+1014 4 0
+134 2 9
+818 1 0
+61 1 7
+563 46 0
+78 5 5
+1677 1 1
+49 1 1
+399 1 1
+32 1 1
+790 27 27
+104 1 1
+75 1 1
+1638 1 1
+16 1 1
+92 1 1
+44 1 1
+276 0 13
+1020 1 1
+35 1 1
+389 14 14
+256 1 0
+38 1 3
+631 1 1
+40 1 1
+2356 1 1
+82 2 0
+1300 0 5
+511 0 2
+605 1 1
+17 1 1
+880 12 0
+1689 4 0
+2492 1 1
+39 1 1
+641 16 16
+682 0 5
+669 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+498 3 0
+321 0 1
+281 3 0
+450 1 1
+34 1 1
+498 1 1
+28 2 1
+280 0 2
+648 1 1
+47 1 1
+1002 4 0
+120 1 1
+1538 0 1
+75 1 1
+37 1 1
+517 1 1
+79 4 4
+60 18 18
+2075 1 1
+19 1 1
+2429 1 1
+21 1 1
+107 1 0
+2786 0 2
+31 5 5
+1973 12 0
+3118 1 0
+246 0 1
+33 1 1
+6752 1 0
+822 2 9
+606 1 1
+18 1 1
+3920 1 1
+37 0 2
+4497 10 13
+2451 1 1
+16 3 0
+1843 0 4
+3780 3 0
+850 0 1
+2774 0 3
+2065 0 1
+20 1 1
+1400 1 0
+3243 0 15
+1336 5 0
+618 7 7
+1507 8 7
+379 44 43
+2184 0 1
+304 0 2
+19 0 1
+101 1 1
+417 3 3
+22 1 1
+672 4 4
+221 1 1
+161 5 0
+17 1 1
+72 1 0
+106 1 1
+463 1 1
+94 1 1
+138 3 4
+185 1 1
+29 1 1
+220 15 15
+167 1 1
+32 1 1
+93 1 3
+217 1 1
+23 1 1
+137 9 9
+62 0 3
+353 1 1
+27 1 1
+117 9 9
+421 1 1
+47 1 1
+124 0 1
+997 6 0
+54 5 5
+764 1 1
+45 1 1
+1431 7 7
+387 6 6
+1103 0 36
+767 1 1
+31 1 3
+208 5 5
+1610 1 1
+23 1 1
+779 0 8
+324 0 2
+45 1 1
+264 0 3
+45 1 1
+250 1 1
+18 1 1
+517 33 0
+117 1 1
+42 1 1
+550 1 1
+20 1 1
+671 1 1
+68 1 1
+89 1 1
+104 1 1
+172 0 1
+124 0 1
+524 0 1500
+464 5 5
+32 1 0
+171 1 1
+19 1 1
+67 1 1
+22 1 1
+654 1 1
+25 1 1
+68 1 1
+21 4 0
+1588 1 1
+66 1 1
+401 0 1
+186 1 1
+21 1 1
+168 0 1
+686 3 0
+19 1 1
+127 1 1
+29 1 1
+234 1 1
+30 1 1
+141 0 2
+33 1 1
+673 1 1
+89 1 1
+161 16 16
+504 1 1
+192 0 3
+105 1 1
+286 1 1
+101 15 16
+158 8 0
+57 1 1
+332 2 2
+35 1 1
+371 1 1
+55 1 1
+86 1 1
+29 1 1
+196 1 1
+44 1 0
+52 10019 10030
+89 1 1
+35 1 1
+153 1 0
+37 35 6
+68 1 1
+69 3 3
+78 28 28
+85 1 1
+148 1 1
+248 1 1
+77 1 1
+61 1 1
+55 1 1
+82 1 1
+41 2 2
+113 1 1
+59 1 1
+417 5 5
+65 1 1
+55 1 1
+212 0 14
+40 1 1
+112 1 1
+22 0 2
+47 1 1
+75 1 1
+208 5 5
+55 1 1
+78 1 1
+136 13 13
+93 3 0
+140 1 2
+46 1 1
+78 6 6
+52 1 1
+51 1 1
+97 1 1
+107 1 1
+5453 1 1
+40 1 1
+327 1 1
+24 1 1
+172 2 2
+27 11 15
+381 10 11
+376 1 1
+45 1 1
+121 1 1
+62 1 1
+289 1 1
+26 1 1
+191 1 1
+20 11 11
+425 1 1
+37 1 1
+296 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+306 1 1
+24 1 1
+1299 1 1
+47 1 1
+2026 1 1
+20 1 1
+133 1 0
+9803 0 4
+15871 3 0
+2464 1 1
+24 1 1
+879 1 1
+73 1 1
+89 1 1
+42 1 1
+108 1 1
+43 0 1
+26 1 1
+511 5 6
+605 1 1
+47 1 1
+73 1 1
+62 1 1
+1928 19438 20008
+56 5 5
+237 1 1
+141 1 1
+92 1 1
+154 7 7
+3208 1 1
+33 1 1
+671 1 1
+21 1 1
+955 0 3
+130 1 1
+26 1 1
+288 8 8
+218 0 3
+1076 8 0
+609 1 0
+55 2 1
+242 1 1
+23 1 1
+834 1 1
+112 1 1
+67 1 1
+43 1 1
+86 1 1
+30 1 1
+73 13 13
+88 11 11
+145 13 13
+63 1 1
+62 1 1
+59 51 50
+432 1 1
+45 1 1
+68 1 1
+48 1 1
+64 9 9
+299 14 14
+169 10 10
+69 2 2
+85 1 1
+207 6 6
+85 1 1
+44 3 3
+181 11 11
+55 13 13
+258 1 1
+103 1 1
+298 7 7
+268 1 1
+16 1 1
+66 1 1
+97 16 0
+322 1 1
+58 1 1
+55 1 1
+77 1 1
+186 1 1
+55 1 1
+218 1 1
+153 1 1
+53 1 1
+98 1 1
+371 1 1
+303 3 3
+63 1 1
+303 1 1
+121 0 2
+55 8 8
+208 1 1
+26 1 1
+447 6 6
+76 1 1
+46 1 1
+782 12 12
+230 1 1
+67 1 1
+60 1 1
+80 1 1
+170 3 0
+53 1 1
+31 1 1
+317 2 2
+66 1 1
+228 1 1
+23 1 1
+1612 1 1
+21 1 1
+261 1 1
+99 1 1
+128 1 1
+15 1 1
+77 9 9
+618 8 8
+84 4 6
+438 1 1
+140 1 1
+158 4 3
+277 12 12
+165 4 4
+36 1 1
+253 1 1
+59 1 1
+910 0 1
+915 4 5
+276 15 15
+682 1 1
+28 1 1
+1483 13 13
+203 1 0
+52 1 1
+48 1 1
+229 12 12
+166 1 1
+39 1 1
+194 1 1
+24 1 1
+251 8 8
+619 0 4
+15 1 1
+690 84 85
+463 1 1
+30 1 1
+449 1 1
+54 1 1
+58 5 5
+979 1 0
+318 1 1
+28 1 1
+898 10 10
+100 1 1
+22 1 1
+446 1 1
+74 1 1
+273 1 1
+19 1 1
+333 1 1
+44 1 1
+220 1 1
+56 2 0
+209 1 1
+70 1 1
+223 0 20
+220 1 1
+31 1 1
+56 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+195 1 1
+46 1 1
+184 1 1
+60 0 4
+76 0 4
+53 3 1
+43 1 1
+153 1 1
+53 1 1
+195 6 0
+60 1 1
+278 1 0
+42 1 1
+341 13 13
+262 4 4
+67 1 1
+32 1 0
+28 1 1
+287 7 7
+318 1 1
+78 1 1
+157 1 1
+19 1 1
+64 1 2
+31 1 1
+52 1 1
+51 1 1
+77 10280 10270
+101 8 8
+4653 1 1
+38 1 1
+817 2 0
+256 1 1
+27 1 1
+339 1 1
+48 1 1
+54 10 10
+1393 3 0
+1491 2 0
+1983 16 0
+167 0 4
+3886 7 8
+535 1 1
+16 1 1
+1555 3 0
+3131 1 1
+17 1 1
+4196 1 0
+14974 0 1
+3514 0 4
+29 1 1
+123 0 2
+27 11 0
+35 0 50
+43 2 0
+55 6 100
+96 11 0
+22 67 0
+49 13 0
+20 0 2
+19 2 0
+22 4 156
+57 156 3
+61 0 2
+29 20 0
+42 11 0
+21 2 0
+50 4 6
+31 1 3
+23 1 53
+25 0 32
+66 1 55
+11 0 2
+13 0 41
+68 1 42
+23 1 3
+12 2 0
+17 1 29
+51 17 13
+18 2 0
+28 2 0
+26 2 0
+158 1 25
+96 0 28
+51 1 29
+79 254 0
+53 21 0
+5064 0 2
+7569 2 0
+2189 0 1
+85 1 1
+31 0 4
+399 14 14
+408 0 1
+681 0 5
+184 1 1
+20 1 1
+64 1 1
+29 1 0
+9 2 0
+442 4 0
+342 1 1
+24 1 1
+131 1 1
+198 1 1
+370 0 1
+34 1 1
+447 21 20
+259 1 1
+23 0 1
+121 2 0
+2257 1 1
+22 1 1
+811 1 1
+27 1 1
+744 0 5
+843 0 2889
+55 0 88
+1189 0 2
+2274 1 0
+752 4 0
+164 1 1
+55 1 1
+1726 1 1
+57 1 1
+3578 1 1
+34 1 1
+1446 1 0
+460 1 1
+31 0 1
+6 1 1
+163 1 1
+22 1 1
+81 1 1
+27 1 1
+548 1 1
+61 1 1
+1169 1 1
+41 1 1
+6471 1 1
+62 1 1
+530 17 17
+394 1 1
+40 7 0
+57 12 12
+69 2 2
+39 1 1
+70 1 1
+22 0 3
+2307 1 1
+30 1 1
+411 1 1
+104 1 1
+375 26 27
+1218 1 1
+35 1 1
+85 1 1
+20 6 0
+687 1 1
+34 1 1
+268 13 13
+74 1 1
+47 2 0
+51 69 69
+73 1 1
+48 1 1
+218 1 1
+42 1 1
+197 1 1
+41 1 1
+313 1 1
+40 1 1
+476 1 1
+29 1 1
+185 1 1
+35 1 1
+594 1 1
+24 1 1
+220 26 0
+245 0 1
+261 13 13
+89 1 1
+90 1 1
+224 1 1
+201 1 1
+306 1 1
+29 5 5
+121 1 1
+31 1 1
+109 1 1
+25 1 1
+168 1 1
+19 1 1
+93 12 11
+132 1 0
+113 1 1
+30 1 1
+56 9 9
+300 1 1
+50 2 2
+96 1 1
+43 1 1
+76 1 1
+44 1 1
+197 1 1
+91 7 1
+119 0 9
+392 5 5
+89 1 1
+428 11 11
+260 1 1
+23 1 0
+10 1 1
+70 1 1
+65 2 0
+16 0 19
+28 1 1
+208 1 1
+70 1 1
+149 0 3
+243 1 1
+55 1 1
+63 17 17
+1208 1 1
+98 1 1
+162 1 1
+45 1 1
+148 70 70
+209 4 4
+1242 1 1
+42 5 0
+87 1 1
+522 0 3
+305 0 1
+1379 0 2
+390 0 15
+72 1 1
+16 1 1
+270 1 0
+280 7 7
+2763 20 20
+674 10 10
+1375 14 0
+294 143 141
+629 16 16
+54 4 4
+680 16 16
+395 1 1
+42 1 1
+1763 1 1
+46 1 1
+282 1 1
+39 1 1
+860 1 1
+26 1 1
+745 0 2
+2081 2 0
+817 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+132 5 0
+555 1 1
+65 1 1
+550 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+15 1 5
+1404 0 1
+450 4 0
+626 1 0
+304 1 1
+39 1 1
+564 1 1
+45 1 1
+303 2 0
+409 1 1
+18 1 0
+858 2 0
+2168 0 1
+54 22 22
+524 0 1
+410 10 10
+106 1 14
+2419 18 14
+64 1 1
+31 1 1
+185 0 5
+1646 1 1
+20 1 1
+227 1 1
+37 1 1
+500 1 0
+136 3 4
+8239 1 1
+23 1 1
+1114 0 2
+688 0 1
+901 18 18
+4781 0 4
+815 0 1
+5069 0 5
+415 0 2
+352 0 1
+1085 11 11
+1099 0 1
+991 0 1
+845 1 1
+32 0 2
+5751 0 3
+1553 1 1
+60 1 1
+278 0 1
+30 1 1
+1855 0 2
+958 0 1
+66 0 16
+2109 0 2
+1265 0 1
+17312 0 4
+1875 0 1
+2157 1 0
+915 0 6
+4940 1 0
+2649 0 1
+3322 11 9
+2276 14 0
+3128 0 4
+3496 1 0
+966 0 1
+120 4 4
+3473 1 0
+1647 0 3
+1182 1 0
+654 0 3
+2049 1 0
+6838 1 1
+39 1 1
+186 1 0
+2718 1 1
+30 1 1
+160 11 11
+4954 0 1
+420 1 1
+123 1 1
+156 0 4
+219 4 0
+195 1 0
+4402 2 0
+4295 1 0
+4695 0 1
+30 1 1
+6025 1 0
+4179 1 0
+19834 0 1
+11605 0 1
+4121 2 0
+2863 0 2
+4890 1 0
+5576 0 6
+4104 4 0
+19858 4 0
+1616 0 3
+1647 4 1
+36 0 12
+2213 0 14
+414 0 1
+3338 0 3
+678 3 4
+292 2 0
+1922 0 1
+913 0 1
+2720 1 0
+1111 3 0
+2589 0 8
+9425 1 0
+1403 0 2
+1964 0 12
+4433 0 1
+1569 0 1
+89 46 46
+7074 1 1
+41 1 1
+2257 1 0
+3001 0 1
+1845 1 0
+1593 0 1
+497 0 2
+6109 0 1
+2019 2 0
+921 0 1
+241 1 0
+4348 72 72
+1053 1 0
+2213 2 0
+1974 8 0
+4952 0 1
+6146 2 0
+953 1 0
+4141 0 1
+4244 5 0
+152 0 2
+209 0 1
+2400 0 10
+785 2 0
+1733 0 1
+554 1 0
+128 0 2
+3051 0 1
+5221 17 17
+3339 0 1
+1503 0 1
+1705 0 3
+2052 17 17
+998 177 0
+2804 1 0
+1925 1 0
+5635 17 17
+3563 0 1
+971 8 0
+36021 1 0
+8016 29 27
+3890 0 1
+67913 1 1
+18 1 6368
+73 1 1
+3119 23 23
+7239 0 32738
+4295 1 1
+19 1 1
+6198 1 0
+16668 1 1
+20 1 1
+5638 5 0
+47 12 0
+11313 0 1
+1769 0 1
+8355 0 3
+4114 0 2
+1403 1 0
+5140 0 1
+490 0 1
+219 1 0
+3483 1 0
+8939 1 1
+44 1 1
+10813 0 2
+7480 2 0
+617 1 0
+1464 0 1
+500 0 2
+1466 1 0
+527 5 0
+3593 0 1
+374 0 1
+3666 0 1
+2149 1 0
+311 2 0
+6570 1 0
+962 1 0
+23 1 1
+2647 4 0
+588 1 1
+21 1 1
+3256 28 20
+870 0 1
+644 1 0
+602 2 1
+3730 1 1
+45 1 1
+12848 7 7
+5994 29 29
+1283 0 3
+8057 1 1
+63 1 1
+4166 1 0
+1887 10 0
+2949 1 1
+31 0 1
+669 1 0
+888 43 43
+1259 2 0
+2081 0 2
+373 0 6
+421 4 4
+1460 0 1
+1699 0 8
+2882 2 0
+147 0 1
+1656 1 1
+27 1 1
+1828 0 2
+4066 0 3
+34 1 1
+361 17 17
+1254 6 0
+1643 0 2
+2542 0 1
+848 2 1
+2117 0 2
+119 1 1
+44 1 1
+1104 0 1
+415 0 12
+634 18 1
+377 6 7
+227 6 0
+449 13 13
+895 0 17
+457 18 18
+663 0 3
+382 1 1
+26 1 1
+135 0 1
+105 1 1
+25 1 1
+620 2 0
+290 5 5
+375 1 1
+30 0 4
+98 1 0
+20 17 4
+3824 28 0
+39 4 0
+28 4 0
+44 4 0
+1898 9 9
+221 0 2
+10522 30 0
+783 1 1
+59 1 1
+94 1 1
+21 1 1
+491 1 1
+49 1 1
+289 2 0
+120 0 1
+37 1 1
+112 1 1
+21 1 1
+183 16 16
+73 2 0
+1007 1 1
+38 0 1
+79 1 1
+48 1 1
+561 1 1
+29 1 1
+145 5 5
+576 12 12
+834 1 0
+846 5 7
+34 1 1
+417 0 1
+65 1 1
+40 1 1
+110 1 1
+47 1 1
+351 1 1
+69 1 1
+53 1 1
+91 1 1
+260 1 1
+36 0 1
+604 1 0
+169 0 1
+2118 1 1
+34 1 1
+147 1 1
+213 1 1
+67 1 1
+31 1 1
+566 1 0
+17 1 1
+763 1 1
+34 1 1
+671 5 0
+41 2 2
+98 0 1
+449 0 2
+61 1 1
+38 1 1
+202 1 1
+44 1 1
+190 1 0
+46 4 4
+51 0 4
+476 1 1
+17 1 1
+212 1 1
+26 1 1
+485 1 1
+25 1 1
+263 1 1
+26 1 1
+1327 4 0
+44 1 0
+2397 1 1
+44 1 1
+4146 14 14
+901 0 1
+3504 1 0
+1125 1 0
+254 1 0
+427 0 1
+30 1 1
+111 0 2
+52 0 8
+528 44 0
+969 1 1
+10 1 0
+28 1 1
+140 1 1
+43 1 1
+1989 2 1
+598 1 1
+87 0 4
+124 1 0
+4840 1 1
+28 7 4
+505 0 2
+24 1 1
+5134 4 0
+543 1 0
+18 1 1
+97 1 1
+29 1 3
+101 6 0
+148 13 7
+1346 0 1
+128 7 0
+49 0 1
+876 2 0
+286 5 5
+184 0 1
+84 5 5
+365 9 9
+981 1 1
+11 1 1
+734 4 0
+563 4 0
+244 9 9
+379 1 1
+17 1 1
+49 2 0
+95 1 1
+30 1 1
+147 1 1
+37 0 6
+340 1 2
+58 1 1
+332 0 2
+233 6 9
+156 0 1
+26 1 1
+439 4 0
+34 0 2
+508 5 0
+96 1 1
+34 1 1
+1267 15 15
+638 1 1
+24 4 5
+1055 13 13
+135 0 1
+194 63 63
+384 6 6
+2756 1 1
+19 1 1
+99 15 15
+1754 2 3
+2238 1 1
+31 1 1
+3002 4 0
+2156 15 15
+855 14 13
+442 5 5
+2022 6 6
+506 0 2
+1110 0 1
+2578 0 2
+4864 1 1
+36 1 0
+3187 1 1
+16 1 1
+184 1 1
+18 1 1
+1607 53 60
+527 1 1
+39 1 1
+653 3 0
+227 1 1
+18 1 1
+102 7 7
+109 0 323
+91 1 0
+124 0 15
+621 0 4
+553 12 12
+463 1 1
+40 1 1
+372 1 1
+25 1 1
+188 12 12
+357 0 1
+250 0 5
+4193 0 4
+967 1 1
+76 1 1
+3236 4 4
+529 7 7
+246 4 0
+160 1 1
+34 0 3
+1469 0 2
+499 1 0
+937 1 1
+45 1 1
+421 6 0
+2127 0 1
+491 1 0
+80 1 1
+72 2 0
+255 6 6
+728 14 11
+702 3 0
+290 0 2
+210 19 1
+473 1 1
+42 4 0
+219 0 1
+348 1 1
+83 1 1
+851 0 16
+72 13 0
+246 1 1
+47 4 0
+410 1 0
+93 0 12
+225 0 16
+428 1 0
+4 6 0
+324 0 1
+3060 0 16
+1305 1 1
+29 1 1
+3094 0 7
+600 0 2
+5495 1 1
+47 1 1
+1247 9 21
+35 6 0
+4350 1 1
+15 1 1
+2011 6 14
+8378 2 0
+295 0 17
+4583 1 0
+4132 0 4
+924 4 3
+1751 0 2
+1060 12 12
+380 0 2
+425 8 0
+84 0 1
+244 1 1
+28 1 1
+221 4 0
+348 1 1
+37 11 11
+50 1 1
+180 1 1
+348 1 1
+20 1 1
+1714 1 1
+79 1 1
+729 1 1
+44 1 0
+78 1 1
+112 1 1
+23 1 1
+55 9 9
+1044 1 1
+27 1 1
+494 1 1
+32 1 1
+237 1 1
+27 1 1
+1839 7 1
+710 8 0
+185 0 2
+966 1 0
+13 15 1
+251 1 1
+47 1 1
+285 1 1
+103 1 1
+977 1 1
+41 1 0
+97 1 1
+131 1 0
+307 1 1
+47 1 1
+1070 1 1
+69 1 1
+382 0 1
+167 1 1
+35 1 1
+161 1 1
+30 1 1
+1068 18 0
+1173 1 1
+32 1 1
+59 1 1
+12 1 0
+18 1 1
+55 0 22
+72 1 1
+2806 1 1
+15 1 1
+1395 1 0
+157 13 0
+536 8 8
+101 1 1
+21 1 1
+147 8 8
+638 1 1
+18 1 1
+183 15 15
+990 0 12
+21 1 1
+145 0 1
+332 1 1
+31 1 1
+231 22 5
+39 1 1
+414 9 9
+93 1 1
+63 1 1
+739 0 2
+632 1 1
+74 1 1
+138 5 5
+128 0 1
+294 1 1
+45 1 1
+679 6 6
+1773 0 34
+543 27 27
+1608 5 0
+219 1 1
+134 0 3
+164 0 1
+357 1 1
+28 1 1
+670 7 9
+270 0 1
+891 13 33
+257 4 0
+80 0 4
+130 2 0
+3772 1 1
+44 1 1
+2256 0 1
+80 12 0
+5544 1 0
+428 13 13
+77 4 4
+63 1 1
+64 13 19
+906 1 1
+84 1 1
+290 1 1
+41 1 1
+144 15 15
+238 3 0
+61 1 1
+31 1 1
+189 10245 10222
+107 11 11
+93 1 1
+30 7 5
+242 0 1
+171 1 1
+29 1 1
+218 0 9
+241 1 1
+55 4 4
+88 1 1
+99 1 1
+57 0 1
+523 12 16
+399 1 1
+50 1 1
+389 1 1
+71 4 4
+173 12 12
+92 1 1
+20 1 1
+132 0 5
+15 1 1
+75 1 1
+26 5 5
+119 11 11
+542 1 1
+23 2 2
+254 1 1
+34 1 1
+172 1 1
+45 1 1
+95 11 11
+127 23 23
+64 1 1
+95 1 1
+390 1 1
+52 1 1
+170 1 1
+16 5 0
+30 1 1
+599 1 1
+119 1 1
+85 1 1
+75 1 1
+286 4 4
+61 1 1
+286 9 9
+429 1 1
+21 1 1
+53 1 1
+44 1 1
+130 1 1
+30 1 1
+190 2 2
+127 1 1
+96 4 4
+112 1 1
+105 5 5
+19 3659 4
+244 10 11
+69 1 1
+29 1 1
+281 1 1
+38 1 1
+212 1 1
+36 1 1
+79 1 1
+29 3 3
+125 161746 190163
+3115 0 1
+152 1 1
+1518 1 1
+88 1 1
+4502 0 1
+46 1 1
+800 4 4
+23 1 1
+1305 2 0
+136 0 1
+4941 0 1
+547 0 1
+70 8 8
+293 1 1
+35 1 1
+1165 4 0
+6662 1 1
+121 1 1
+92 0 8
+214 1 1
+35 1 1
+108 1 0
+1063 0 1
+1017 1 1
+20 0 6
+1725 0 1
+134 68 67
+349 1 1
+24 0 1
+1562 1 1
+31 1 1
+2513 0 1
+73 36 36
+305 1 1
+27 1 1
+543 1 1
+47 4 28
+4387 20057 20086
+272 5 5
+243 1 1
+84 1 1
+98 1 1
+50 5 5
+77 1 1
+74 1 1
+20 0 1
+143 1 1
+45 0 1
+4 1 1
+1088 1 1
+35 1 1
+320 1 1
+22 1 1
+275 1 1
+47 1 1
+370 19 19
+119 1 6
+51 1 1
+21 1 1
+244 0 1
+345 1 1
+24 1 1
+181 1 1
+61 3 3
+542 1 1
+16 1 1
+312 1 0
+353 4 3
+279 323 0
+86 1 1
+49 1 1
+342 1 1
+44 0 2
+222 1 1
+37 1 1
+588 8 8
+593 2 2
+44 1 1
+359 1 1
+25 1 1
+2054 1 0
+2510 1 0
+5051 0 1
+1489 9 9
+3292 1 0
+1449 1 1
+21 1 1
+6768 1 0
+706 2 0
+7107 1 1
+38 1 1
+1127 73 73
+435 1 1
+60 1 1
+325 0 1
+254 1 1
+43 1 1
+210 1 1
+7 1 0
+47 1 1
+130 4 4
+34 1 1
+208 1 1
+39 2 2
+526 1 1
+36 1 1
+99 9 7
+20 1 1
+73 1 1
+62 1 1
+425 1 1
+43 1 1
+811 1 1
+38 1 1
+362 1 1
+49 1 1
+109 1 1
+19 1 1
+79 1 1
+29 0 1
+26 1 1
+252 1 1
+75 1 1
+441 1 1
+66 1 1
+389 13 13
+67 7 7
+1185 0 311
+64 6 6
+667 1 1
+38 1 1
+79 1 0
+553 1 1
+30 1 1
+433 1 1
+16 3 0
+1133 12 12
+262 5 5
+276 1 0
+960 14 14
+272 1 1
+41 1 1
+196 1 0
+1424 18 19
+314 1 1
+22 1 1
+345 1 1
+23 3 0
+245 1 1
+78 1 1
+77 1 1
+779 1 1
+32 1 1
+247 1 1
+48 1 1
+778 2 0
+226 1 1
+61 1 1
+861 0 1
+51 9 9
+397 1 1
+12 4 0
+46 1 1
+602 1 1
+35 1 1
+422 1 1
+49 1 1
+789 1 1
+37 1 1
+268 0 2
+589 8 8
+366 1 1
+6 0 7
+5 0 1
+66 1 1
+1584 2 7
+19 1 1
+417 1 1
+37 1 1
+812 1 1
+33 3 0
+1351 18 18
+2186 1 1
+86 1 1
+1433 59 59
+65 0 1
+238 0 1
+171 1 1
+7 2 1
+67 1 1
+596 1 1
+29 1 1
+144 4 6
+417 1 0
+88 1 1
+24 1 1
+390 18 18
+496 14 21
+145 1 1
+46 1 1
+310 1 1
+35 1 1
+214 1 1
+38 1 1
+206 1 1
+37 1 0
+240 1 1
+32 1 1
+469 1 1
+32 1 1
+208 1 1
+21 1 1
+343 1 1
+17 1 1
+88 1 1
+58 6 0
+169 1 1
+22 1 1
+162 0 1
+196 0 2
+500 6 5
+108 1 1
+40 2 0
+50 1 1
+111 1 0
+21 0 1066
+335 1 1
+44 1 1
+11005 0 1
+6280 1 1
+48 1 1
+1173 1 1
+19 1 1
+2664 0 1
+351 1 0
+1059 14 14
+593 0 1
+869 16 16
+23065 2 0
+2197 0 1
+949 0 1
+15048 0 1
+606 1 0
+7820 0 4
+14669 1 0
+14708 0 1
+16326 0 1
+710 2 0
+194 1 1
+49 1 1
+262 0 1
+92 1 1
+10677 2 0
+4856 3 0
+7447 6 6
+421 1 0
+884 6 0
+17 1 0
+3075 1 0
+14671 3 1
+3762 2 0
+601 2 0
+2461 0 2
+5154 1 0
+1604 0 16
+3589 0 1
+1488 1 0
+1196 0 2
+683 0 1
+1218 1 0
+221 1 1
+22 1 1
+296 4 4
+1456 23 41
+880 1 12
+2490 1 0
+151 1 1
+33 1 1
+2809 4 4
+3645 1 1
+17 1 1
+3496 2 0
+154 1 1
+29 1 1
+158 0 1
+5981 1 1
+32 1 1
+1041 0 2
+174 9 0
+1383 0 1
+389 1 2
+1570 2 0
+3993 4 0
+4576 1 1
+45 1 1
+182 8 8
+2203 20 24
+2009 1 1
+39 1 1
+489 1 1
+17 1 1
+628 1 1
+124 1 1
+1607 1 1
+23 1 1
+1021 0 8
+1249 0 20
+46 0 32
+46 6 0
+24 0 10
+7679 1 1
+44 1 1
+580 1 1
+28 1 1
+264 1 1
+65 0 1
+15 1 1
+2371 19 19
+57 1 1
+21 1 1
+231 1 1
+94 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 40 40
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 29 29
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+270 1 1
+272 1 1
+232 1 1
+94 1 1
+3189 0 176
+834 0 35
+303 0 51
+321 1 0
+17170 0 1
+321 1 1
+25 1 1
+679 1 1
+33 1 1
+990 11 11
+131 8 8
+79 9 9
+1284 5 5
+537 6 6
+127 1 1
+28 1 1
+145 1 1
+47 1 1
+399 4 4
+35 1 1
+143 1 1
+39 1 1
+53 9 9
+61 1 1
+95 12 22
+86 1 0
+71 5 0
+11 1 1
+58 8490 8674
+113 1403 1307
+491 1 1
+32 1 1
+85 1 1
+41 1 1
+480 1 1
+74 2 2
+1108 59 0
+70 10 10
+325 11 11
+879 1 1
+34 1 1
+524 1 1
+25 1 1
+202 17 17
+1154 1 1
+26 1 1
+89 17 17
+87 1 1
+39 1 1
+950 1 1
+15 2 2
+51 1 1
+81 1 1
+180 1 0
+187 1 1
+37 1 1
+467 1 1
+19 1 1
+755 0 2
+81 3 1
+16 1 1
+67 6 6
+84 1 1
+37 2 0
+31 0 28
+15 0 37
+266 14 14
+372 1 1
+68 1 1
+205 40 40
+217 1 1
+46 1 1
+563 19 0
+217 9 9
+363 1 1
+22 1 1
+884 1 1
+40 1 1
+179 1 1
+42 1 1
+94 6 6
+922 1 1
+30 1 1
+481 0 3
+7925 15 11
+333 5 0
+1235 6 6
+355 1 1
+27 1 1
+515 1 0
+1077 11 0
+1521 1 0
+38 1 1
+119 1 1
+58 1 1
+63 4 3
+385 1 1
+49 1 1
+77 20 22
+111 11 11
+190 2 2
+45 1 1
+373 1 1
+47 1 1
+77 10 10
+186 1 1
+24 1 1
+965 27 27
+148 1 0
+214 1 1
+34 1 1
+89 1 1
+36 1 1
+288 0 1
+544 0 331
+320 1 0
+199 1 1
+16 1 1
+112 1 1
+29 1 1
+808 0 3
+45 1 1
+240 1 1
+38 1 1
+59 1 1
+68 1 1
+52 1 1
+98 1 1
+166 7 7
+698 1 1
+68 1 1
+165 0 1
+114 1 1
+92 0 1
+14 1 1
+215 1 1
+81 1 1
+792 1 1
+31 1 1
+54 1 1
+44 1 1
+179 1 1
+26 1 1
+200 1 1
+30 1 1
+639 7 7
+505 0 1
+18 0 1
+21 1 1
+549 12 0
+19 1 1
+1413 19 19
+752 1 0
+840 1 1
+69 1 1
+966 21 21
+33 12 0
+56 1 1
+94 1 1
+237 11 9
+189 1 1
+47 1 1
+318 3 0
+80 16 16
+67 1 2
+11 5 0
+32 1 1
+126 1 1
+146 1 1
+104 6 5
+56 1 1
+68 1 1
+417 12 13
+636 0 2
+30 1 1
+694 0 4
+95 1 1
+28 1 1
+1358 1 1
+19 1 1
+68 1 1
+97 1 1
+493 1 7
+158 2 0
+42 6 0
+59 1 1
+314 14 14
+94 1 1
+64 1 1
+637 1 1
+21 1 1
+144 2 1
+229 11 5
+410 1 1
+96 1 1
+272 1 1
+22 1 1
+118 1 1
+44 1 1
+96 1 1
+48 1 1
+414 22 22
+373 13 13
+554 1 1
+87 10 0
+313 1 1
+37 1 1
+122 17 18
+179 1 1
+40 1 1
+591 8 8
+129 1 0
+70 1 1
+71 1 0
+73 10 6
+12 1 1
+203 0 6
+24 2 0
+45 4 0
+46 1 1
+186 9 9
+87 1 1
+28 1 1
+3625 0 1
+233 1 1
+532 0 2
+696 2 0
+555 1 7
+287 1 1
+30 0 3
+946 0 1
+88 1 1
+60 12 0
+12546 1 1
+37 1 0
+2071 0 1
+3270 4 5
+24668 0 2
+6212 1 1
+26 1 1
+816 0 4
+8244 26 26
+5332 18 15
+2375 2 0
+1957 2 0
+2394 6 0
+1561 0 1
+2805 4 0
+12333 8 0
+835 0 1
+391 35 62
+12156 0 18
+6903 2 0
+21807 3 0
+1588 1 0
+2605 1 1
+23 1 1
+11252 8 0
+298 6 7
+946 2 0
+232 0 1
+501 1 0
+4748 0 4
+770 0 7
+914 0 1
+295 1 0
+214 3 0
+121 0 1
+784 0 1
+2512 0 1
+1205 21 21
+3250 3 0
+926 0 1
+189 2 0
+3543 2 0
+893 1 1
+46 1 1
+1296 0 1
+153 0 1
+336 5 0
+228 1 1
+45 1 1
+207 3 0
+322 0 1
+658 1 0
+1516 3 0
+1025 0 13
+1518 0 1
+591 10 10
+3384 0 2
+182 12 0
+328 1 0
+301 0 1
+994 1 1
+18 0 6
+1743 0 1
+2350 22 23
+1548 0 7
+1976 1 0
+199 0 1
+5922 12 12
+873 0 3
+3080 12 8
+322 1 0
+490 1 0
+3602 1 0
+482 1 0
+3178 1 0
+5157 0 10
+753 0 1
+885 20 0
+1746 10 0
+4045 6 1
+3520 5 13
+2048 0 1
+3529
+
+chain 323865 chr6_cox_hap2 4795371 + 1330645 1334316 chr12 132349534 - 750935 772711 208090
+2772 0 815
+201 0 17291
+643 1 0
+54
+
+chain 80740 chr6_cox_hap2 4795371 + 2523432 2524289 chr6 170899992 - 139781917 139782778 1563239
+341 0 4
+516
+
+chain 70254 chr6_cox_hap2 4795371 + 4067974 4068737 chr9 140273252 + 98508948 98509710 1791394
+611 16 15
+136
+
+chain 49863 chr6_cox_hap2 4795371 + 2736707 2740201 chr12 132349534 + 103307685 103311177 2548369
+99 961 960
+121 35 35
+77 287 287
+76 473 472
+80 230 229
+64 37 37
+96 796 797
+62
+
+chain 42593 chr6_cox_hap2 4795371 + 3906996 3908960 chrX 154913754 - 144265701 144267664 3039954
+86 125 125
+67 358 358
+186 154 154
+98 734 733
+51 48 48
+57
+
+chain 34258 chr6_cox_hap2 4795371 + 2809588 2810007 chrX 154913754 - 17721461 17721874 3940368
+73 15 15
+155 1 1
+20 6 0
+17 1 1
+131
+
+chain 30865 chr6_cox_hap2 4795371 + 4059866 4060385 chr6 170899992 + 32821259 32821748 4483190
+73 89 59
+184 77 77
+96
+
+chain 30808 chr6_cox_hap2 4795371 + 1510229 1510552 chr13 114142980 + 81787211 81787534 4493802
+323
+
+chain 29563 chr6_cox_hap2 4795371 + 4153575 4153884 chr1 247249719 - 75038034 75038343 4838476
+309
+
+chain 29490 chr6_cox_hap2 4795371 + 3951720 3952028 chr20 62435964 - 21243992 21244300 4870682
+308
+
+chain 27083 chr6_cox_hap2 4795371 + 3906819 3907206 chr15 100338915 - 11358130 11358517 3142845
+177 86 86
+124
+
+chain 23990 chr6_cox_hap2 4795371 + 1376886 1377662 chr7 158821424 - 51137320 51138262 7695540
+178 101 101
+72 385 551
+40
+
+chain 17935 chr6_cox_hap2 4795371 + 3928197 3929285 chr6 170899992 + 32648139 32649803 12171469
+63 855 1431
+170
+
+chain 17763 chr6_cox_hap2 4795371 + 3903740 3903944 chr6 170899992 - 2126149 2126361 12324873
+52 0 8
+26 2 2
+124
+
+chain 17461 chr6_cox_hap2 4795371 + 3908117 3908804 chr7 158821424 + 50608340 50609026 3099178
+57 90 88
+74 250 251
+108 69 69
+39
+
+chain 17263 chr6_cox_hap2 4795371 + 3953714 3953921 chr4 191273063 + 3978296 3978500 12788147
+50 3 0
+26 4 4
+124
+
+chain 16515 chr6_cox_hap2 4795371 + 3904181 3904724 chr8 146274826 - 138245724 138246268 13519146
+75 324 325
+78 15 15
+51
+
+chain 16283 chr6_cox_hap2 4795371 + 3331225 3331402 chr2 242951149 + 128261675 128261851 587006
+28 2 1
+147
+
+chain 15874 chr6_cox_hap2 4795371 + 2807758 2808190 chr6 170899992 + 31412763 31413204 14155918
+58 158 158
+72 76 85
+68
+
+chain 15671 chr6_cox_hap2 4795371 + 1369735 1370970 chr6 170899992 - 139552636 139553881 14365445
+56 408 416
+54 620 622
+97
+
+chain 15351 chr6_cox_hap2 4795371 + 2854893 2855094 chr11 134452384 + 74426248 74426449 14701290
+99 26 26
+76
+
+chain 15299 chr6_cox_hap2 4795371 + 2737173 2739469 chr4 191273063 + 161293453 161295747 2664175
+134 30 30
+77 352 352
+1 899 896
+68 663 664
+72
+
+chain 15059 chr6_cox_hap2 4795371 + 3958379 3959329 chr11 134452384 - 110535166 110536123 15004208
+57 287 282
+82 464 476
+60
+
+chain 14920 chr6_cox_hap2 4795371 + 2854607 2854845 chr12 132349534 + 55181251 55181530 15152322
+65 69 110
+104
+
+chain 14553 chr6_cox_hap2 4795371 + 4145755 4147026 chr20 62435964 - 45982841 45983887 15553025
+59 654 439
+82 417 407
+59
+
+chain 14203 chr6_cox_hap2 4795371 + 4064060 4064210 chr6 170899992 - 148625201 148625351 15961753
+150
+
+chain 14065 chr6_cox_hap2 4795371 + 3965480 3965632 chr6 170899992 - 138279004 138279156 16120854
+152
+
+chain 13894 chr6_cox_hap2 4795371 + 1411227 1413617 chr6 170899992 + 30021566 30022999 16323534
+75 1920 964
+70 255 254
+70
+
+chain 13590 chr6_cox_hap2 4795371 + 4063892 4064036 chr2 242951149 + 178053314 178053458 16703151
+144
+
+chain 13480 chr6_cox_hap2 4795371 + 1351610 1352327 chr6 170899992 + 29984509 29985227 16847522
+104 551 552
+62
+
+chain 13240 chr6_cox_hap2 4795371 + 3973235 3974493 chr6 170899992 + 32656086 32657213 17156367
+52 422 421
+78 652 522
+54
+
+chain 12556 chr6_cox_hap2 4795371 + 1412173 1412312 chr2 242951149 - 184047846 184047985 18149165
+139
+
+chain 12225 chr6_cox_hap2 4795371 + 3953994 3954124 chr13 114142980 - 45055283 45055413 18644548
+130
+
+chain 12178 chr6_cox_hap2 4795371 + 4035942 4036108 chr14 106368585 - 58343221 58343386 18718227
+55 26 25
+85
+
+chain 11746 chr6_cox_hap2 4795371 + 1363046 1363194 chr7 158821424 - 7754727 7754875 19419744
+54 14 14
+80
+
+chain 11718 chr6_cox_hap2 4795371 + 363030 363190 chr13 114142980 + 52924211 52924330 7321463
+62 41 0
+40 13 13
+4
+
+chain 11256 chr6_cox_hap2 4795371 + 4009517 4011696 chr6 170899992 + 32547334 32549511 20265569
+52 1710 1710
+59 270 268
+88
+
+chain 11034 chr6_cox_hap2 4795371 + 3906701 3906819 chr11 134452384 - 106076910 106077028 5031217
+118
+
+chain 10867 chr6_cox_hap2 4795371 + 2744958 2745115 chr6 170899992 - 132294381 132294544 20980270
+55 29 35
+73
+
+chain 10852 chr6_cox_hap2 4795371 + 2854438 2854554 chr15 100338915 - 60167597 60167713 16273329
+116
+
+chain 10738 chr6_cox_hap2 4795371 + 3960011 3960132 chr10 135374737 + 59270705 59270823 21232182
+61 3 0
+57
+
+chain 10631 chr6_cox_hap2 4795371 + 4504746 4504857 chr6 170899992 + 33168511 33168622 21069572
+111
+
+chain 10496 chr6_cox_hap2 4795371 + 3956062 3956172 chr1 247249719 - 172266041 172266151 21720779
+110
+
+chain 10389 chr6_cox_hap2 4795371 + 2738194 2739397 chr3 199501827 - 153335243 153336431 2813504
+77 463 461
+101 221 221
+81 230 217
+30
+
+chain 9881 chr6_cox_hap2 4795371 + 2797497 2798047 chr6 170899992 + 31313427 31313987 23083507
+72 423 433
+55
+
+chain 9755 chr6_cox_hap2 4795371 + 4085166 4085466 chr6 170899992 + 162410099 162410399 23379361
+65 181 181
+54
+
+chain 9455 chr6_cox_hap2 4795371 + 3955446 3955651 chr6 170899992 + 32576901 32577113 24108453
+54 91 98
+60
+
+chain 9090 chr6_cox_hap2 4795371 + 2744204 2744314 chr3 199501827 - 94209663 94209773 24799752
+53 4 4
+53
+
+chain 9032 chr6_cox_hap2 4795371 + 4005585 4007249 chr6 170899992 + 32600177 32601830 24897713
+61 1516 1505
+87
+
+chain 8805 chr6_cox_hap2 4795371 + 4070123 4070583 chr6 170899992 + 32730844 32731277 25222810
+56 347 320
+57
+
+chain 8241 chr6_cox_hap2 4795371 + 4030549 4030636 chr6 170899992 + 65319659 65319746 26041488
+87
+
+chain 7395 chr6_cox_hap2 4795371 + 3960355 3960433 chr12 132349534 + 58155129 58155207 27414638
+78
+
+chain 7276 chr6_cox_hap2 4795371 + 4034939 4035015 chr6 170899992 - 67344251 67344327 27653179
+76
+
+chain 7068 chr6_cox_hap2 4795371 + 3976155 3976230 chr3 199501827 - 153055114 153055189 28061906
+75
+
+chain 6977 chr6_cox_hap2 4795371 + 3979195 3979269 chr3 199501827 - 153056804 153056878 28244736
+74
+
+chain 6795 chr6_cox_hap2 4795371 + 2799999 2800071 chr6 170899992 + 31318116 31318188 28604513
+72
+
+chain 6742 chr6_cox_hap2 4795371 + 3906310 3906388 chr13 114142980 - 44754607 44754685 6636725
+47 2 2
+29
+
+chain 6584 chr6_cox_hap2 4795371 + 3989668 3989736 chr6 170899992 + 32559900 32559968 29100412
+68
+
+chain 6522 chr6_cox_hap2 4795371 + 4087338 4087407 chr15 100338915 + 41279078 41279147 29241043
+69
+
+chain 6495 chr6_cox_hap2 4795371 + 4147491 4147560 chr3 199501827 + 170919021 170919090 29304086
+69
+
+chain 6422 chr6_cox_hap2 4795371 + 4077507 4077575 chr6 170899992 + 32836685 32836753 29490822
+68
+
+chain 6368 chr6_cox_hap2 4795371 + 4147386 4147454 chr14 106368585 + 45132269 45132337 29601986
+68
+
+chain 6249 chr6_cox_hap2 4795371 + 2736394 2736460 chr4 191273063 - 25496702 25496768 29900240
+66
+
+chain 5885 chr6_cox_hap2 4795371 + 4087248 4087310 chr1 247249719 - 180983801 180983863 30853903
+62
+
+chain 5792 chr6_cox_hap2 4795371 + 4036108 4036169 chr10 135374737 - 103149812 103149873 26755013
+61
+
+chain 5767 chr6_cox_hap2 4795371 + 4085838 4085899 chr6 170899992 + 75566512 75566573 31174158
+61
+
+chain 5767 chr6_cox_hap2 4795371 + 4147632 4147693 chr2 242951149 - 84322530 84322591 31176268
+61
+
+chain 5731 chr6_cox_hap2 4795371 + 1376353 1376414 chr6 170899992 + 29872087 29872148 31286976
+61
+
+chain 5730 chr6_cox_hap2 4795371 + 1379511 1379571 chr6 170899992 + 29878483 29878543 31293433
+60
+
+chain 5576 chr6_cox_hap2 4795371 + 1365664 1365723 chr18 76117153 - 3609354 3609413 31727123
+59
+
+chain 5458 chr6_cox_hap2 4795371 + 4048500 4048558 chr16 88827254 + 47978524 47978582 32101537
+58
+
+chain 5403 chr6_cox_hap2 4795371 + 3960992 3961049 chr8 146274826 - 83195522 83195579 32234296
+57
+
+chain 5339 chr6_cox_hap2 4795371 + 4145490 4145546 chr3 199501827 + 495644 495700 32419958
+56
+
+chain 5275 chr6_cox_hap2 4795371 + 4086549 4086604 chr8 146274826 - 2308124 2308179 32643336
+55
+
+chain 5206 chr6_cox_hap2 4795371 + 3904515 3904580 chr1 247249719 - 87949826 87949891 19914856
+50 10 10
+5
+
+chain 5193 chr6_cox_hap2 4795371 + 4086093 4086147 chr5 180857866 + 130110350 130110404 32896485
+54
+
+chain 5184 chr6_cox_hap2 4795371 + 4084818 4084872 chrX 154913754 + 10188597 10188651 32929250
+54
+
+chain 5094 chr6_cox_hap2 4795371 + 4048238 4048292 chr6 170899992 + 68023473 68023527 33192695
+54
+
+chain 5067 chr6_cox_hap2 4795371 + 2804796 2804850 chr19 63811651 - 42284679 42284733 33279532
+54
+
+chain 5066 chr6_cox_hap2 4795371 + 1412096 1412149 chr21 46944323 - 1867343 1867396 33290791
+53
+
+chain 5020 chr6_cox_hap2 4795371 + 1409379 1409431 chr6 170899992 + 29800663 29800715 33444450
+52
+
+chain 4959 chr6_cox_hap2 4795371 + 3956009 3956062 chr18 76117153 + 5080594 5080647 22154822
+53
+
+chain 4930 chr6_cox_hap2 4795371 + 3957989 3958041 chrX 154913754 - 4434310 4434362 33717677
+52
+
+chain 4885 chr6_cox_hap2 4795371 + 2804443 2804495 chr5 180857866 - 162979708 162979760 33920646
+52
+
+chain 4847 chr6_cox_hap2 4795371 + 4047956 4048006 chr8 146274826 + 123332061 123332111 34011268
+50
+
+chain 4821 chr6_cox_hap2 4795371 + 3998874 3998925 chr6 170899992 - 10896638 10896689 34121637
+51
+
+chain 4712 chr6_cox_hap2 4795371 + 1364779 1364829 chr8 146274826 + 57925971 57926021 34511278
+50
+
+chain 4712 chr6_cox_hap2 4795371 + 4048918 4048968 chrX 154913754 + 54878538 54878588 34513604
+50
+
+chain 4392 chr6_cox_hap2 4795371 + 1377105 1377164 chr7 158821424 - 126060926 126060985 9905438
+59
+
+chain 4221 chr6_cox_hap2 4795371 + 2501082 2501164 chr14 106368585 + 74531432 74531592 4607333
+28 0 78
+54
+
+chain 4156 chr6_cox_hap2 4795371 + 3908195 3908241 chr2 242951149 - 7598530 7598576 17599965
+46
+
+chain 3903 chr6_cox_hap2 4795371 + 2908687 2909998 chr13 114142980 - 41461917 41462061 3840414
+7 46 0
+24 11 0
+33 1102 5
+19 13 0
+56
+
+chain 3865 chr6_cox_hap2 4795371 + 3903984 3904315 chr6 170899992 - 96557211 96557546 20806006
+67 210 214
+54
+
+chain 3734 chr6_cox_hap2 4795371 + 4145889 4145954 chr6 170899992 + 80018577 80018642 19955866
+65
+
+chain 3639 chr6_cox_hap2 4795371 + 3954124 3954162 chr3 199501827 + 102893836 102893874 20360982
+38
+
+chain 3394 chr6_cox_hap2 4795371 + 3959975 3960011 chrX 154913754 - 4438295 4438331 28244218
+36
+
+chain 3053 chr6_cox_hap2 4795371 + 4085231 4085263 chr2 242951149 + 38036198 38036230 24698963
+32
+
+chain 2845 chr6_cox_hap2 4795371 + 2736677 2736707 chr3 199501827 - 158108130 158108160 26771662
+30
+
+chain 2771 chr6_cox_hap2 4795371 + 2403948 2403980 chr16 88827254 + 61371572 61371604 11881973
+32
+
+chain 2645 chr6_cox_hap2 4795371 + 3954296 3954371 chr19 63811651 - 40112981 40113056 21687958
+75
+
+chain 2587 chr6_cox_hap2 4795371 + 2737535 2737662 chr15 100338915 + 91973389 91973516 3332233
+127
+
+chain 2561 chr6_cox_hap2 4795371 + 363092 363133 chr6 170899992 + 20352681 20352722 12577879
+41
+
+chain 2518 chr6_cox_hap2 4795371 + 4085322 4085377 chr16 88827254 - 20600134 20600189 24262923
+55
+
+chain 2470 chr6_cox_hap2 4795371 + 2809473 2809523 chr1 247249719 + 111577816 111577866 7596664
+50
+
+chain 2411 chr6_cox_hap2 4795371 + 3932607 3932633 chr1 247249719 - 51484714 51484740 35456234
+26
+
+chain 2403 chr6_cox_hap2 4795371 + 3907493 3907603 chr2 242951149 + 38214752 38214862 4277847
+110
+
+chain 2400 chr6_cox_hap2 4795371 + 2741593 2741618 chr4 191273063 + 159509242 159509267 32929303
+25
+
+chain 2393 chr6_cox_hap2 4795371 + 4068737 4068764 chrX 154913754 - 92588093 92588120 1797125
+27
+
+chain 2375 chr6_cox_hap2 4795371 + 3904076 3904137 chr11 134452384 - 60265228 60265289 23423532
+61
+
+chain 2319 chr6_cox_hap2 4795371 + 2964304 2964330 chr6 170899992 + 31465639 31465665 3286069
+26
+
+chain 2194 chr6_cox_hap2 4795371 + 1377065 1377105 chrX 154913754 - 101365357 101365397 11073776
+40
+
+chain 2146 chr6_cox_hap2 4795371 + 1363259 1363320 chr12 132349534 + 104221177 104221238 23825280
+61
+
+chain 2104 chr6_cox_hap2 4795371 + 4036001 4036023 chr6 170899992 - 77175689 77175711 26219289
+22
+
+chain 2011 chr6_cox_hap2 4795371 + 4029977 4029999 chrX 154913754 + 85587943 85587965 35529089
+22
+
+chain 2000 chr6_cox_hap2 4795371 + 1377237 1377270 chr4 191273063 + 153905795 153905828 8127681
+33
+
+chain 1991 chr6_cox_hap2 4795371 + 2908808 2908838 chr4 191273063 - 29946315 29946345 15287751
+30
+
+chain 1988 chr6_cox_hap2 4795371 + 3958152 3958211 chr1 247249719 + 152912877 152912936 23823437
+59
+
+chain 1918 chr6_cox_hap2 4795371 + 2736976 2737099 chr5 180857866 + 51070203 51070326 3385212
+123
+
+chain 1873 chr6_cox_hap2 4795371 + 3906133 3906260 chr5 180857866 - 144904464 144904591 3580450
+127
+
+chain 1857 chr6_cox_hap2 4795371 + 4071868 4075383 chr6 170899992 + 32830794 32834943 29519981
+61 2506 2690
+85 515 965
+52 103 103
+193
+
+chain 1825 chr6_cox_hap2 4795371 + 3906512 3906555 chr4 191273063 - 47717007 47717050 17204973
+43
+
+chain 1793 chr6_cox_hap2 4795371 + 3907342 3908508 chr2 242951149 + 97580469 97581638 5600825
+48 1090 1093
+28
+
+chain 1708 chr6_cox_hap2 4795371 + 3906388 3906482 chr7 158821424 + 109077307 109077401 4717797
+94
+
+chain 1690 chr6_cox_hap2 4795371 + 4147205 4147262 chr11 134452384 - 120264308 120264365 24918209
+57
+
+chain 1584 chr6_cox_hap2 4795371 + 1377344 1377408 chr1 247249719 - 24894387 24894451 17598707
+64
+
+chain 1503 chr6_cox_hap2 4795371 + 2736094 2736140 chr13 114142980 - 72925076 72925122 23344710
+46
+
+chain 1489 chr6_cox_hap2 4795371 + 2908702 2910078 chrX 154913754 - 101842157 101842924 6540871
+27 1297 452
+2 0 236
+50
+
+chain 1456 chr6_cox_hap2 4795371 + 3908424 3908476 chr14 106368585 + 47951043 47951095 9313420
+52
+
+chain 1455 chr6_cox_hap2 4795371 + 2738121 2739528 chr6 170899992 - 65542196 65543586 3697883
+64 1285 1268
+58
+
+chain 1368 chr6_cox_hap2 4795371 + 1377482 1377548 chr11 134452384 + 118435255 118435321 13435147
+66
+
+chain 1368 chr6_cox_hap2 4795371 + 4145973 4146044 chr5 180857866 - 127160909 127160980 20267229
+71
+
+chain 1324 chr6_cox_hap2 4795371 + 3907899 3907958 chr1 247249719 + 29601245 29601304 5732716
+59
+
+chain 1278 chr6_cox_hap2 4795371 + 3908508 3908575 chr15 100338915 + 89926442 89926509 4006770
+67
+
+chain 1265 chr6_cox_hap2 4795371 + 3904331 3904385 chr4 191273063 - 113978359 113978413 18680359
+54
+
+chain 1224 chr6_cox_hap2 4795371 + 2740399 2740456 chr4 191273063 - 135903806 135903863 24465805
+57
+
+chain 1167 chr6_cox_hap2 4795371 + 3908344 3908402 chr4 191273063 + 111464967 111465025 3502724
+58
+
+chain 1054 chr6_cox_hap2 4795371 + 3907390 3907440 chr10 135374737 + 6453196 6453246 3643427
+50
+
+chain 1002 chr6_cox_hap2 4795371 + 2736140 2736200 chr1 247249719 - 71169048 71169108 10800621
+60
+
+chain 988 chr6_cox_hap2 4795371 + 2739771 2739829 chr15 100338915 - 47558730 47558788 2837698
+58
+
+chain 983 chr6_cox_hap2 4795371 + 2737443 2737516 chr11 134452384 - 130067201 130067274 24083146
+73
+
+chain 952 chr6_cox_hap2 4795371 + 2735975 2736093 chr12 132349534 - 67686596 67686714 8250173
+118
+
+chain 919 chr6_cox_hap2 4795371 + 2740748 2740808 chr4 191273063 + 44807134 44807194 22381054
+60
+
+chain 915 chr6_cox_hap2 4795371 + 2736903 2736961 chr18 76117153 + 57868323 57868381 3224910
+58
+
+chain 912 chr6_cox_hap2 4795371 + 2740082 2740112 chr7 158821424 + 107644178 107644208 21981894
+30
+
+chain 876 chr6_cox_hap2 4795371 + 2739742 2739771 chr1 247249719 - 197271642 197271671 12596898
+29
+
+chain 869 chr6_cox_hap2 4795371 + 3907293 3907342 chr10 135374737 + 5116762 5116811 5781535
+49
+
+chain 859 chr6_cox_hap2 4795371 + 2736813 2741147 chr15 100338915 + 18498519 18502823 4451069
+52 4214 4184
+68
+
+chain 858 chr6_cox_hap2 4795371 + 2739831 2739865 chr7 158821424 - 148280259 148280293 6691657
+34
+
+chain 832 chr6_cox_hap2 4795371 + 3906555 3906608 chr11 134452384 - 48407690 48407743 4638931
+53
+
+chain 819 chr6_cox_hap2 4795371 + 3906260 3906310 chr9 140273252 + 32202289 32202339 4057214
+50
+
+chain 781 chr6_cox_hap2 4795371 + 2736320 2736393 chr5 180857866 - 50968960 50969033 9780107
+73
+
+chain 771 chr6_cox_hap2 4795371 + 3907818 3907850 chr10 135374737 - 103151561 103151593 7179825
+32
+
+chain 761 chr6_cox_hap2 4795371 + 2736552 2736619 chr2 242951149 - 140069145 140069212 14744509
+67
+
+chain 747 chr6_cox_hap2 4795371 + 1377768 1377832 chr12 132349534 + 55464534 55464598 20643860
+64
+
+chain 734 chr6_cox_hap2 4795371 + 2739880 2739936 chr3 199501827 - 145206053 145206109 3741906
+56
+
+chain 734 chr6_cox_hap2 4795371 + 2735396 2736320 chr8 146274826 - 112931559 112932176 13565225
+68 769 462
+87
+
+chain 718 chr6_cox_hap2 4795371 + 2740828 2740883 chr9 140273252 - 49339912 49339967 23555332
+55
+
+chain 716 chr6_cox_hap2 4795371 + 4147141 4147193 chr16 88827254 - 38714794 38714846 22851159
+52
+
+chain 709 chr6_cox_hap2 4795371 + 2739652 2739702 chr11 134452384 - 107252690 107252740 6149448
+50
+
+chain 685 chr6_cox_hap2 4795371 + 2738531 2738584 chrX 154913754 - 2978832 2978885 8357317
+53
+
+chain 604 chr6_cox_hap2 4795371 + 1377662 1377688 chrX 154913754 - 101148638 101148664 11583046
+26
+
+chain 566 chr6_cox_hap2 4795371 + 2740606 2740665 chr2 242951149 + 168011719 168011778 5902375
+59
+
+chain 547 chr6_cox_hap2 4795371 + 2740492 2740542 chr11 134452384 - 79794459 79794509 15991276
+50
+
+chain 544 chr6_cox_hap2 4795371 + 2738003 2738054 chr13 114142980 + 104410064 104410115 4879951
+51
+
+chain 541 chr6_cox_hap2 4795371 + 2738408 2738434 chr2 242951149 - 229173591 229173617 17449766
+26
+
+chain 532 chr6_cox_hap2 4795371 + 2740024 2740082 chr9 140273252 - 118104609 118104667 4462652
+58
+
+chain 525 chr6_cox_hap2 4795371 + 3966448 3966514 chr6 170899992 + 32582000 32582066 26144539
+66
+
+chain 497 chr6_cox_hap2 4795371 + 2738584 2738618 chr12 132349534 + 9890463 9890497 23880878
+34
+
+chain 493 chr6_cox_hap2 4795371 + 2739023 2739056 chr22 49691432 + 27063354 27063387 3888752
+33
+
+chain 395 chr6_cox_hap2 4795371 + 2909998 2910026 chrX 154913754 - 101842939 101842967 6370567
+28
+
+chain 367 chr6_cox_hap2 4795371 + 2735248 2735298 chrX 154913754 + 118995097 118995147 25845816
+50
+
+chain 290 chr6_cox_hap2 4795371 + 2741541 2741593 chr1 247249719 - 204952078 204952130 18508596
+52
+
+chain 288 chr6_cox_hap2 4795371 + 3906008 3906069 chr4 191273063 - 55159498 55159559 26293742
+61
+
+chain 182 chr6_cox_hap2 4795371 + 3905895 3905941 chr9 140273252 + 29711555 29711601 32244349
+46
+
+chain 172 chr6_cox_hap2 4795371 + 4087589 4087640 chr1 247249719 - 204983626 204983677 25877235
+51
+
+chain 361837920 chr6_dbb_hap3 4610396 + 0 4610396 chr6 170899992 + 28804582 33437054 36
+932 3 0
+804 0 1
+2406 2 0
+9637 0 1
+2736 6 0
+4013 2 0
+6498 4 0
+6886 0 4
+15284 1 0
+937 0 8
+13552 0 2
+3960 0 2
+2111 0 2
+41 19 0
+8992 0 4
+59229 107905 107904
+87624 0 1
+5902 0 1
+31697 7 0
+1489 1 1
+72 1 1
+2260 0 2
+7033 0 4
+3592 0 1
+19578 0 1
+1324 0 2
+5438 5 0
+2061 1 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4746 9 9
+4767 7 7
+1225 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+249 43 43
+1178 0 4
+685 8 0
+48 4 0
+1701 1 1
+43 5 5
+862 18 18
+58 1 1
+66 1 1
+420 1 1
+44 1 1
+680 4 4
+1675 1 1
+83 1 1
+3082 4 0
+5467 1 1
+27 0 1
+1099 12 0
+627 12 12
+1317 6 1
+129 1 1
+25 1 1
+1397 15 15
+810 1 1
+27 1 1
+1192 3 0
+7515 4 0
+979 0 3
+3406 0 2
+3501 1 1
+26 1 1
+787 0 1
+1416 3 1
+22815 4 4
+126 1 0
+38 1 1
+140 1 0
+999 0 17
+56 0 15
+15438 4 0
+6165 0 1
+1768 1 0
+7727 1 0
+1514 0 1
+3116 0 1
+3278 1 1
+21 1 1
+1738 0 1
+8576 19 0
+8020 1 0
+2049 1 0
+518 13 11
+1704 1 1
+117 1 1
+1448 10 0
+4403 9 9
+2265 1 0
+25400 9 9
+4420 1 1
+32 1 1
+2539 1 0
+9981 17923 17922
+148 1 1
+25 1 1
+1461 4 1
+1402 0 1
+3961 0 3
+58 1 1
+112 1 1
+1419 1 1
+34 0 1
+2697 0 2
+40 1 1
+2168 0 1
+1019 0 2
+1099 0 4
+40 1 1
+1374 11 0
+31 1 1
+189 1 1
+26 1 1
+327 1 1
+38 1 1
+177 11 11
+303 1 1
+34 1 1
+1438 1 1
+46 1 1
+727 1 1
+26 1 1
+2373 5 0
+321 1 0
+933 17 17
+82 9 9
+2773 0 143
+80 1 1
+25 1 1
+467 1 1
+27 1 1
+143 1 1
+47 4 4
+1194 10 10
+1455 1 1
+33 1 1
+601 1 1
+46 0 4
+694 1 3
+91 1 1
+59 1 1
+167 6 6
+113 1 1
+31 1 1
+1181 0 1
+422 15 0
+36 1 1
+2219 1 1
+35 1 1
+2116 0 1
+8249 0 3
+1120 1 0
+870 16 0
+5547 0 2
+5376 0 6
+2275 1 1
+43 1 1
+78 4 4
+24710 1 0
+64762 6 3
+441 1 0
+2338 1 0
+1948 1 1
+26 1 1
+214 0 1
+6118 1 1
+31 1 1
+2382 5 5
+4335 1 1
+39 1 1
+4561 1 1
+38 1 1
+2199 1 1
+49 1 1
+243 17 6
+2779 1 1
+37 2 0
+24 1 1
+1966 3 0
+233 1 1
+29 1 1
+17718 6 0
+46568 1 0
+18985 0 2
+1833 3 4
+5288 0 9
+2728 1 5
+722 0 1
+502 0 1
+1025 0 1
+134 14 0
+4944 0 1
+319 1 0
+6178 0 1
+2880 1 1
+17 0 2
+143 0 1
+1775 1 0
+2123 0 1
+2715 1 0
+4921 1 1
+47 4 0
+2882 1 0
+1362 1 0
+1233 0 8
+2134 0 1
+1042 0 1
+163 1 1
+45 1 1
+50 2 0
+64 1 1
+48 1 1
+380 0 1
+30 1 0
+30 1 1
+61 1 1
+22 1 1
+691 0 2
+84 1 1
+230 1 1
+37 3 1
+162 1 1
+194 2 0
+36 1 1
+242 9 9
+697 33 33
+1202 1 1
+16 1 1
+528 1 1
+20 1 1
+131 9 9
+369 0 5
+76 1 1
+21 1 1
+439 15 15
+2779 1 0
+1597 24 28
+59 12 12
+307 1 0
+516 1 0
+286 11 33
+339 5 0
+570 1 1
+37 1 1
+220 1 0
+72 1 1
+144 1 1
+48 1 1
+247 2 0
+174 9 10
+816 1 0
+940 1 1
+45 1 1
+91 3 3
+71 1 1
+291 14 14
+100 1 1
+23 1 1
+452 3 3
+229 1 1
+252 0 1
+129 15 15
+432 10 0
+85 1 1
+28 1 1
+189 2 1
+71 1 1
+52 8 0
+810 2 2
+63 1 1
+378 1 1
+26 1 1
+187 31 36
+966 1 1
+25 1 1
+91 12 12
+125 1 1
+38 1 1
+433 2 0
+596 1 1
+48 1 1
+465 4 4
+64 1 1
+20 1 1
+525 5 5
+237 3 8
+99 31 31
+53 11 0
+364 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+67 16 16
+244 1 1
+54 5 5
+929 1 1
+21 1 1
+126 0 3
+830 1 11
+59 1 1
+537 0 2
+24 1 1
+745 15 15
+810 1 0
+425 1 1
+89 1 1
+592 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 1 1
+39 1 1
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+155 156 0
+34 1 1
+50 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+345 1 1
+39 1 1
+504 18 18
+596 12 12
+54 1 1
+158 1 1
+164 1 1
+34 1 1
+626 15 15
+866 0 10
+1051 0 2611
+680 0 1
+1537 0 18
+75 1 0
+145 6 0
+9 39 0
+107 0 18
+23 1 1
+1927 13 13
+1702 2 0
+3694 1 1
+18 1 1
+958 39 47
+246 2 0
+146 1 1
+49 1 1
+410 1 0
+667 1 1
+38 1 1
+362 7 1
+159 2 0
+515 2 0
+1026 1 1
+29 1 1
+249 0 6
+129 1 1
+33 4 0
+10 1 5
+1236 1 1
+20 1 1
+138 10 9
+448 0 3
+660 1 1
+28 1 1
+83 1 1
+51 1 1
+2659 1 1
+38 1 1
+424 0 1
+70 1 1
+694 1 1
+19 1 1
+105 1 1
+26 1 1
+1472 1 1
+21 1 1
+491 5 5
+163 15 15
+2194 2 0
+533 2 0
+441 1 7
+1689 1 1
+26 3 4
+879 16 16
+514 0 2
+58 1 1
+350 1 0
+769 1 1
+39 1 1
+573 0 4
+37 1 1
+144 8 8
+1036 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+169 62 63
+74 11 15
+1255 0 2
+332 1 1
+21 1 1
+193 8 24
+34 1 1
+79 1 1
+29 1 1
+536 1 0
+308 0 1
+850 0 32
+23 1 1
+651 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 2
+713 7 7
+89 1 0
+293 9 8
+125 1 1
+31 1 1
+192 6 6
+171 17 17
+681 1 1
+43 1 1
+514 1 1
+68 1 1
+537 1 1
+35 1 1
+159 6 6
+778 17 17
+198 0 7
+105 1 1
+40 1 1
+95 13 13
+247 1 1
+19 1 1
+2044 7 8
+2512 0 15
+2982 4 0
+3135 1 2
+1698 13 13
+15862 0 1
+925 0 183
+36 16 1
+18 0 1
+25 1 1
+7717 1 1
+40 1 1
+758 1 1
+46 1 1
+5530 11 9
+3326 1 1
+37 1 1
+6743 0 4
+7923 1 1
+26 5 5
+3475 26 0
+8 1 1
+566 4 0
+141 0 1
+2078 24 24
+2759 0 4
+1659 4 0
+52 4 0
+3265 0 2
+2235 17 16
+2946 0 372
+2644 31 31
+92 1 1
+35 1 1
+705 323 0
+3157 40 40
+718 0 4
+787 1 1
+34 1 1
+927 4 4
+72 1 1
+2414 0 1
+993 1 1
+31 1 1
+1514 1 1
+29 1 1
+1109 1 1
+44 1 1
+208 4 1
+1022 11767 11699
+85 98 98
+60 2515 8169
+103 11 11
+41 1 1
+72 4 4
+76 1 1
+70 5 5
+83 1 1
+117 1 1
+130 1 1
+44 1 1
+414 1 1
+152 1 0
+218 1 1
+161 1 0
+120 14 14
+145 1 1
+49 4 4
+72 1 1
+53 19 19
+111 2 2
+32 3 3
+553 0 2
+336 12 12
+54 24 24
+171 0 6
+90 1 1
+28 1 1
+142 16 16
+36 1 1
+428 1 1
+16 1 1
+338 1 1
+31 1 1
+294 1 1
+92 0 1
+129 13 14
+602 1 1
+112 1 1
+247 1 1
+80 1 1
+173 1 1
+44 1 5
+497 1 1
+38 1 1
+98 1 1
+130 1 1
+319 1 1
+16 1 1
+59 1 1
+82 1 1
+141 1 1
+23 1 1
+241 1 1
+26 1 1
+184 0 3
+19 1 1
+510 1 1
+36 1 1
+162 2 2
+15 1 1
+145 1 1
+28 1 1
+120 0 3
+93 1 2
+24 0 9
+169 12 0
+292 9911 10000
+401 1 1
+27 1 1
+296 1 1
+120 1 1
+357 1 1
+107 2 0
+31 1 1
+83 89 0
+194 1 1
+33 1 1
+230 1 1
+142 5 5
+108 1 1
+36 1 1
+287 1 1
+19 1 1
+104 1 1
+31 1 1
+144 1 1
+212 1 1
+452 5 6
+148 1 1
+70 1 1
+137 3 3
+67 1 1
+73 22 22
+115 12 12
+142 5 5
+269 15 15
+102 6 6
+93 1 1
+82 1 1
+170 1 1
+22 1 1
+504 2 2
+60 1 1
+150 1 1
+31 1 1
+90 1 1
+15 1 0
+258 6 7
+85 1 1
+77 1 1
+123 2 2
+67 0 1
+56 2 2
+25 1 1
+71 1 1
+28 2 2
+50 1 1
+85 2 2
+66 6 6
+186 1 1
+20 1 1
+67 1 1
+25 1 1
+227 2 2
+155 1 1
+777 1 1
+33 1 2
+26 6 6
+474 1 1
+36 1 1
+151 1 1
+29 1 1
+120 1 1
+23 1 1
+736 17 17
+112 1 1
+39 1 1
+553 1 1
+69 1 1
+116 2 0
+161 1 1
+86 1 1
+705 1 1
+57 3 3
+145 1 1
+204 1 1
+88 1 1
+35 1 1
+92 1 1
+147 1 1
+149 20 20
+210 1 1
+55 2 2
+65 1 1
+32 1 1
+1008 1 1
+24 1 1
+159 18 18
+391 0 1
+327 17 19
+77 1 3
+65 1 1
+84 1 0
+392 2 0
+363 1 0
+1024 0 1
+480 9 9
+119 1 1
+72 1 1
+400 1 1
+46 1 1
+288 11 7
+53 1 1
+80 1 1
+37 1 1
+129 1 1
+80 1 1
+252 4 4
+86 0 1
+129 3 3
+67 1 1
+123 9 9
+199 2 2
+80 1 1
+114 28369 30000
+51 5 5
+45 1 1
+53 1 1
+37 1 1
+81 1 1
+369 1 1
+72 15 15
+98 1 1
+53 0 8
+67 2 0
+41 1 1
+92 1 1
+20 1 1
+283 6 6
+70 7 7
+50 1 1
+25 1 1
+225 5 1
+31 1 1
+449 2 1
+10 1 23
+64 4 4
+3770 1 0
+3862 16 16
+1187 12 12
+97 0 3
+772 1 1
+21 2 1
+1058 0 2
+349 2 0
+1080 18 14
+53 15 17
+1035 1 1
+85 1 1
+69 1 1
+27 1 1
+547 7 7
+195 1 1
+41 1 1
+395 1 1
+35 1 1
+73 0 1
+71 1 1
+557 3 3
+30 1 1
+66 1 1
+25 1 1
+1332 0 2
+26 2 0
+10 1 15
+36 1 1
+196 1 1
+40 1 1
+141 1 1
+76 1 1
+1480 1 3
+347 1 1
+26 1 1
+231 1 1
+82 3 3
+69 3 0
+441 16 16
+147 1 1
+21 1 1
+3565 0 6
+874 2 0
+1036 1 1
+47 3 1
+3761 12 0
+5345 1 0
+11541 1 0
+1843 0 4
+1157 16 16
+7354 19 0
+741 0 1
+8053 1 0
+4449 21 21
+649 1 0
+2913 0 1
+381 332 0
+3533 31 31
+2502 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3870 0 1
+36 13 0
+1894 1 1
+40 0 4
+1348 2 0
+345 1 0
+592 4 4
+1043 4 0
+686 14 0
+1032 0 1
+9035 0 4
+167 0 2
+13644 6258 6257
+4063 0 3
+1760 3 0
+3371 1 1
+23 1 1
+321 5 0
+644 8 0
+47 1 1
+322 1 1
+145 1 1
+1551 11 15
+355 0 1
+1831 4 0
+1779 1 1
+27 1 1
+199 43 55
+2881 1 1
+39 1 1
+120 1 2
+24 1 1
+556 1 0
+393 6 6
+4381 1 0
+524 1 1
+20 1 1
+151 3 3
+144 1 1
+189 1 7
+1445 0 1
+1002 0 1
+7912 4 0
+4977 0 1
+10485 1 1
+48 1 1
+724 1 1
+51 5 0
+39 1 1
+6830 0 1
+15554 0 1
+4385 0 7
+881 0 8
+17594 0 20
+2417 1 0
+998 0 10
+4239 7 0
+4845 0 2
+95 28 23
+10921 1 1
+40 1 1
+4759 0 6
+12084 0 3
+3052 0 4
+2989 1 0
+13523 1 3
+16170 1 0
+11761 0 6
+1158 3 0
+2751 0 6
+1294 1 1
+43 1 1
+5275 0 7
+377 3 0
+7256 3 0
+419 2 0
+10674 0 17
+10821 0 1
+296 0 1
+1770 2 0
+374 0 3
+7469 0 4
+1471 1 0
+3061 2 0
+5818 1 0
+2415 11 9
+2056 0 1
+955 4 0
+17260 1 0
+9557 0 2
+5358 0 1
+11538 4 0
+2627 2 0
+57496 1 1
+29 1 1
+6617 19 0
+254 0 1
+14267 2 0
+9045 3 1
+174 2 0
+4155 1 0
+1153 1 0
+1289 0 40
+12155 0 4
+7692 2 0
+396 22 12
+918 0 1
+1818 0 1
+28 1 1
+492 1 1
+33 1 1
+326 1 1
+80 1 1
+288 8 17
+2671 0 1
+1099 0 1
+144 1 1
+29 0 1
+2098 0 2
+24 3 0
+1207 4 4
+45 1 1
+757 0 5
+1926 1 1
+40 1 1
+330 3 0
+340 1 1
+43 1 1
+1942 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+754 0 4
+17 3 0
+1027 3 0
+428 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+8189 4 5
+36 1 1
+99 2 0
+700 0 4
+149 0 1
+750 0 3
+40 1 1
+3179 2 0
+473 0 2
+2032 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+11881 1 1
+30 1 1
+4383 3 0
+9930 1 1
+56 510 509
+518 8 5
+853 1 1
+80 1 1
+2210 1 0
+905 0 1
+1037 2 0
+5866 0 2
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 2 0
+700 1 1
+1970 0 1
+498 1 0
+1751 0 1
+910 2 0
+691 0 1
+32873 0 1
+19298 0 6
+1371 29 0
+494 2 0
+39050 0 1
+920 0 1
+6820 1 0
+1376 1 2
+1931 33 33
+2376 0 1
+12415 1 1
+51 0 1
+9375 0 1
+323 1 0
+2697 1 0
+15090 120 0
+7116 1 0
+2469 1 0
+5977 2 1
+4888 0 4
+4674 1 0
+2044 1 0
+2153 0 1
+1964 5 5
+2153 1 1
+41 1 1
+774 0 2
+2623 1 1
+81 1 1
+335 2 2
+59 1 1
+335 0 3
+533 2 0
+45 4 0
+986 2 0
+13 1 1
+450 28 27
+295 1 0
+202 1 1
+27 1 1
+70 312 0
+218 1 0
+51 1 1
+31 1 1
+428 0 1
+28 1 1
+118 1 1
+24 1 18
+34 1 1
+75 1 1
+43 2 2
+73 1 1
+29 1 1
+246 1 1
+42 1 1
+409 4 4
+1168 10 1
+310 1 1
+49 1 1
+3002 1 1
+38 1 1
+789 0 1
+63 9 9
+2434 0 8
+980 0 2
+749 8 8
+528 1 1
+24 1 1
+1646 15 15
+528 1 1
+16 1 1
+1402 1 1
+23 1 1
+67 7 0
+35 2 0
+7 0 2
+221 1 1
+45 1 1
+259 1 1
+47 1 1
+384 1 1
+47 1 1
+330 0 4
+490 1 1
+33 1 1
+1841 1 1
+52 0 2
+6 11 0
+193 1 1
+47 1 1
+164 3 7
+31 0 1
+291 1 1
+15 1 1
+877 4 0
+30 1 1
+194 6 0
+93 4 4
+1004 1 1
+20 1 1
+345 1 1
+43 1 1
+365 0 1
+388 1 1
+27 1 1
+253 9 9
+390 1 0
+118 0 1
+170 4 0
+915 1 0
+352 0 4
+520 1 1
+29 20 0
+1167 1 1
+45 1 1
+213 8 0
+51 1 1
+107 10 11
+134 2 0
+228 103 1
+51 2 1
+68 1 1
+59 1 1
+195 1 161
+13 1 1
+553 2 2
+36 1 1
+143 1 0
+1874 4 0
+519 0 1
+476 1 0
+1530 0 1
+1126 2 0
+831 1 1
+40 1 1
+1131 88 87
+2063 0 2
+1950 1 1
+32 1 1
+2217 2 1
+661 0 2
+1239 0 1
+64 1 1
+33 1 1
+13968 0 1
+1222 2 0
+5082 10 0
+413 0 1
+986 23 22
+1194 2527 2526
+12324 0 2
+893 8 0
+1343 2 0
+5784 9 9
+770 12 0
+1044 2 0
+2231 1 1
+48 1 1
+557 0 1
+7497 8 8
+1051 16 0
+49 1 1
+10474 0 3
+1427 1 0
+670 1 3
+766 1 1
+32 1 1
+395 0 9
+170 1 0
+792 2 0
+286 1 0
+117 11 12
+283 26 21
+277 0 2
+48 1 1
+124 1 1
+34 2 1
+316 1 1
+41 1 1
+8214 0 8
+368 2 0
+4 4 0
+3535 17 0
+4228 33 33
+945 0 1
+562 0 1
+1440 0 1
+804 0 11
+1565 0 3
+3008 1 0
+31 1 1
+800 21 17
+650 1 1
+30 1 1
+82 13 13
+5212 1 0
+2003 1 2
+12179 0 1
+2700 2 0
+2735 0 1
+4202 0 3
+4503 1 0
+270 1 0
+12929 0 3
+4009 0 5
+6425 2 0
+310 1 0
+809 2 0
+17 8 0
+2256 0 1
+3207 17 10
+2436 0 14
+1040 1 1
+52 1 1
+6972 1 0
+2357 0 1
+29 1 1
+262 1 0
+72 1 1
+45 1 1
+57 17 17
+1390 0 16
+328 312 0
+65 1 1
+217 10 10
+925 0 33
+1490 1 0
+35 1 1
+226 0 3
+805 1 1
+46 1 1
+192 1 1
+56 1 1
+245 1 1
+61 1 1
+198 4 0
+82 2 2
+29 1 1
+57 0 2
+320 1 1
+22 1 1
+267 5 0
+427 1 0
+17 1 1
+425 1 1
+34 1 1
+565 10 10
+432 10 0
+55 1 1
+90 1 1
+140 1 1
+83 1 1
+1035 1 1
+33 1 1
+144 4 4
+38 1 1
+171 1 1
+35 3 3
+161 6 6
+731 7 3
+1216 25 0
+52 0 1
+419 2 0
+87 8 8
+757 1 1
+67 1 1
+3935 30 0
+791 3 0
+2849 1 1
+33 1 1
+6790 1 1
+67 4 4
+39 2 0
+251 1 1
+37 1 1
+826 3715 901
+205 2 0
+946 1 1
+30 1 1
+613 5 2
+128 29 29
+802 0 89
+1600 0 6
+2112 1 1
+42 1 0
+1164 1 0
+1310 1 0
+1501 0 4
+822 1 1
+42 1 1
+2266 1 0
+25235 0 1
+6697 1 0
+766 1 0
+4188 0 2
+2710 1 1
+17 1 1
+1924 0 7
+5868 1 1
+22 1 1
+2394 0 4
+125 3 0
+718 1 0
+8414 1 1
+49 1 1
+146 1 1
+61 1 1
+116 1 1
+41 1 1
+137 1 1
+30 1 1
+158 9 9
+136 10 13
+1733 17 17
+1053 4 4
+228 1 1
+34 1 1
+355 1 1
+113 1 1
+330 0 1
+222 1 1
+25 1 1
+267 1 1
+38 1 1
+709 2 0
+1448 0 1
+152 1 1
+46 1 1
+237 1 1
+20 1 1
+195 21 21
+88 1 1
+33 1 1
+211 1 1
+65 1 1
+516 58 58
+491 7 7
+208 13 12
+558 2 2
+28 1 1
+125 4 4
+634 1 1
+33 1 1
+159 0 1
+318 1 0
+370 5 5
+80 1 1
+250 0 3
+78 1 1
+45 1 1
+130 3 1
+22 0 1
+180 1 1
+90 1 1
+633 1 1
+36 0 1
+388 0 1
+861 1 1
+103 1 1
+274 16 18
+170 30 30
+796 0 1
+167 0 1
+871 1 1
+27 1 1
+32 0 8
+831 0 13
+90 1 1
+527 1 1
+125 1 1
+1050 10 10
+624 16 16
+1093 5 5
+48 1 0
+168 30 34
+1315 1 1
+33 1 1
+303 1 1
+36 1 1
+601 14 14
+1014 4 0
+134 2 9
+818 1 0
+61 1 7
+641 5 5
+1677 1 1
+49 1 1
+346 87 87
+790 27 27
+104 1 1
+75 1 1
+1638 1 1
+16 1 1
+92 1 1
+44 1 1
+276 0 13
+1020 1 1
+35 1 1
+389 14 14
+256 1 0
+38 1 3
+106 1 1
+21 1 1
+502 1 1
+40 1 1
+2356 1 1
+82 2 0
+1300 0 5
+511 0 2
+605 1 1
+17 1 1
+880 13 0
+1689 4 0
+2492 1 1
+39 1 1
+641 16 16
+682 0 5
+669 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+501 4 1
+317 0 1
+281 3 0
+450 1 1
+34 1 1
+498 1 1
+28 2 1
+280 0 2
+648 1 1
+47 1 1
+1002 4 0
+120 1 1
+1538 0 1
+75 1 1
+37 1 1
+517 1 1
+79 4 4
+60 18 18
+2075 1 1
+19 1 1
+2429 1 1
+21 1 1
+107 1 0
+2786 0 2
+33 3 3
+1973 8 0
+3118 1 0
+246 0 1
+33 1 1
+1333 9 9
+5410 1 0
+822 2 9
+606 1 1
+18 1 1
+3920 1 1
+37 0 2
+4497 10 13
+2468 2 0
+1510 1 1
+23 1 1
+308 0 4
+3780 3 0
+850 0 1
+2774 0 3
+3487 1 0
+3243 0 15
+1336 5 0
+618 7 7
+1507 8 7
+379 44 43
+2184 0 1
+304 0 2
+19 0 1
+101 1 1
+417 3 3
+22 1 1
+672 4 4
+31 1 1
+150 1 1
+38 1 1
+161 5 0
+17 1 1
+72 1 0
+106 1 1
+463 1 1
+236 0 2
+184 1 1
+29 1 1
+220 15 15
+167 1 1
+32 1 1
+93 1 3
+217 1 1
+23 1 1
+137 9 9
+62 0 3
+353 1 1
+27 1 1
+117 9 9
+421 1 1
+47 1 1
+124 0 1
+997 6 0
+54 5 5
+764 1 1
+45 1 1
+1431 7 7
+387 6 6
+1103 0 44
+759 1 1
+31 1 3
+208 5 5
+1610 1 1
+23 1 1
+779 0 8
+311 0 3
+322 0 3
+45 1 1
+250 1 1
+18 1 1
+517 29 0
+117 1 1
+42 1 1
+550 1 1
+20 1 1
+671 1 1
+68 1 1
+89 1 1
+104 1 1
+172 0 1
+124 0 1
+522 0 1500
+466 5 5
+32 1 0
+171 1 1
+19 1 1
+67 1 1
+22 1 1
+654 1 1
+25 1 1
+68 1 1
+21 4 0
+1588 1 1
+66 1 1
+401 0 1
+186 1 1
+21 1 1
+168 0 1
+686 3 0
+19 1 1
+127 1 1
+29 1 1
+234 1 1
+30 1 1
+141 0 2
+33 1 1
+673 1 1
+89 1 1
+161 16 16
+504 1 1
+192 0 3
+105 1 1
+286 1 1
+101 15 16
+158 8 0
+57 1 1
+332 2 2
+35 1 1
+371 1 1
+55 1 1
+86 1 1
+29 1 1
+196 1 1
+44 1 0
+52 19995 20030
+60 8 8
+50 0 3
+129 1 1
+281 1 1
+30 1 1
+109 1 1
+35 1 1
+113 1 1
+34 1 1
+734 1 1
+44 1 1
+106 1 1
+62 1 1
+140 1 1
+76 1 0
+34 1 1
+98 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 1 1
+55 1 1
+1470 0 7
+258 1 1
+48 1 1
+1807 6 6
+63 1 1
+32 1 1
+346 18 18
+9596 12 0
+3853 9 9
+317 4 4
+30 1 1
+71 1 1
+60 1 1
+103 10 10
+71 2 0
+30 1 1
+312 5 0
+170 13 13
+55 2 2
+58 1 0
+30 1 1
+189 37 38
+827 0 17
+26 1 1
+1461 1 1
+24 1 1
+2968 22 22
+137 12 14
+889 11 11
+4010 0 6
+1377 1 1
+34 1 1
+312 1 1
+16 1 1
+715 1 1
+24 1 1
+930 1 1
+22 1 1
+89 1 1
+42 1 1
+108 44 45
+228 149088 159295
+108 1 1
+41 1 1
+11025 4 4
+1194 1 1
+59 1 1
+128 1 0
+1177 82 82
+60 1 1
+48 1 1
+501 19 19
+336 1 1
+42 1 1
+176 4 4
+469 1 1
+35 1 1
+270 1 1
+33 1 1
+289 1 1
+24 1 1
+226 64 0
+42 1 1
+651 1 1
+39 1 1
+123 1 1
+35 1 0
+294 1 1
+32 18 4
+351 1 1
+39 1 1
+135 1 1
+46 1 1
+121 1 1
+19 1 1
+755 4 4
+70 1 1
+456 39 36
+82 1 1
+48 1 1
+441 1 1
+70 1 1
+381 1 1
+46 1 1
+239 1 1
+30 1 1
+87 1 1
+102 3 4
+34 1 1
+488 12 12
+1059 1 1
+45 1 1
+705 1 1
+21 1 1
+107 111 111
+432 3 0
+460 4 4
+1212 0 2
+306 0 1
+1446 19 19
+299 7 33
+78 195 6
+66 1 1
+135 12 12
+778 1 0
+773 1 1
+45 1 1
+253 6 6
+823 1 1
+22 1 1
+2476 10 0
+294 28 10
+307 3 11
+65 0 4
+40 1 1
+4535 1 1
+26 1 1
+371 0 2
+3510 1 1
+16 1 1
+189 1 1
+19 1 1
+814 0 1
+2785 6 1
+1424 0 1
+934 1 1
+49 1 1
+1350 1 0
+384 1 1
+24 1 1
+3117 10 10
+518 0 1
+523 0 16
+243 10 10
+2167 18 14
+64 1 1
+31 1 1
+185 0 4
+1647 1 1
+20 1 1
+227 1 1
+37 1 1
+636 3 4
+8239 1 1
+23 1 1
+1114 0 2
+1590 18 18
+4781 0 4
+815 0 1
+5069 0 5
+415 0 1
+3541 0 1
+878 0 1
+5752 0 2
+1502 0 1
+51 1 1
+60 1 1
+278 0 1
+19 1 1
+1164 11 11
+691 0 2
+960 1 0
+63 0 18
+2109 0 2
+1265 0 1
+1642 2 0
+10831 4 2
+188 0 1
+1650 1 0
+40 1 1
+2962 2 0
+48 1 1
+4899 6 0
+4945 1 0
+60 4 0
+964 0 1
+918 1 0
+706 0 3
+349 1 0
+1673 0 1
+1909 11 11
+1662 15 0
+720 0 1
+2076 0 2
+329 14 0
+3605 0 3
+853 5 6
+3597 1 0
+378 0 1
+969 2 0
+299 0 1
+874 0 4
+663 6 0
+297 0 3
+2049 0 3
+878 11 11
+93 43 43
+13912 0 1
+398 1 1
+145 1 1
+512 16 16
+3139 0 4
+1305 7 0
+3045 1 0
+4179 1 1
+37 1 1
+1336 4 0
+13736 1 0
+11145 1 0
+3867 1 0
+1713 0 1
+2721 0 9
+8875 0 2
+4120 2 0
+13331 0 2
+15149 0 1
+8815 2 0
+1617 0 1
+1686 4 0
+2225 4 0
+7008 1 0
+4374 0 1
+2620 4 0
+43394 1 0
+10823 4 0
+25730 0 1
+554 1 0
+128 0 1
+8274 17 17
+22100 0 4
+40775 1 0
+5693 29 27
+170 1 0
+3528 0 1
+191 1 2
+117 2 0
+2275 1 0
+12676 1 1
+20 1 1
+5364 1 0
+1275 0 2
+3331 1 0
+310 1 0
+13645 0 5
+14860 1 1
+38 1 1
+3605 0 1
+2898 0 1
+10662 1 0
+8241 17 17
+439 16 16
+59 5 4
+7707 1 0
+3007 1 1
+40 1 1
+1569 1 1
+30 1 1
+163 11 11
+8253 35 6402
+5016 17 17
+439 16 16
+59 4 5
+9184 1 1
+19 1 1
+2941 1 1
+105 1 1
+803 5 4
+1011 1 1
+43 1 1
+705 8 8
+574 1 0
+7691 1 0
+5183 0 2
+9452 5 0
+45 0 8
+4438 1 0
+6869 1 0
+1770 0 1
+4094 0 12
+4249 0 3
+4114 0 1
+1404 0 1
+1229 0 2
+3129 0 10
+769 0 2
+709 1 0
+161 0 1
+969 0 1
+1492 0 7
+655 8 8
+251 0 2
+234 1 0
+19500 0 2
+8097 1 0
+1243 0 4
+718 0 2
+1466 1 0
+527 1 0
+3294 1 0
+299 0 1
+374 1 0
+107 1 1
+21 1 1
+2114 0 1
+1422 0 1
+2149 1 0
+311 2 0
+2025 1 1
+36 1 1
+4504 2 0
+3636 10 0
+588 1 1
+21 1 1
+3237 15 0
+39 6 0
+547 74304 74303
+1020 0 3
+747 0 1
+1011 1 1
+43 1 1
+3164 1 0
+1681 0 2
+473 1 5
+107 4 0
+719 0 1
+1154 9 9
+221 0 2
+9332 1 0
+1190 30 0
+783 1 1
+59 1 1
+94 1 1
+21 1 1
+430 11 11
+50 1 1
+49 1 1
+289 3 0
+120 0 1
+37 1 1
+112 1 1
+21 1 1
+183 16 16
+73 2 0
+1007 1 1
+38 0 1
+79 1 1
+48 1 1
+561 1 1
+29 1 1
+145 5 5
+576 12 12
+834 1 0
+846 5 7
+34 1 1
+483 1 1
+40 1 1
+110 7 7
+393 1 1
+215 1 1
+260 1 1
+36 0 1
+604 1 0
+169 0 1
+2118 1 1
+34 1 1
+147 1 1
+213 1 1
+67 1 1
+31 1 1
+566 1 0
+17 1 1
+210 0 2
+551 1 1
+34 1 1
+685 0 3
+24 2 2
+98 0 1
+449 0 2
+61 1 1
+38 1 1
+202 1 1
+44 1 1
+190 1 0
+46 4 4
+51 0 4
+476 1 1
+17 1 1
+82 1 1
+46 1 1
+82 1 1
+26 1 1
+485 1 1
+25 1 1
+263 1 1
+26 1 1
+1327 4 0
+44 1 0
+2397 1 1
+44 1 1
+928 4 0
+3218 14 14
+4406 1 0
+1125 1 0
+254 1 0
+427 0 1
+30 1 1
+111 0 2
+586 17 1
+970 1 1
+10 1 0
+28 1 1
+140 1 1
+43 1 1
+1327 1 1
+24 1 1
+636 2 1
+598 1 1
+44 1 1
+170 1 0
+4840 1 1
+28 11 7
+485 0 1
+263 0 2
+4912 4 0
+543 1 0
+18 1 1
+127 1 2
+102 6 0
+148 16 7
+1346 0 1
+128 7 0
+49 0 1
+876 1 0
+286 5 5
+184 0 1
+84 5 5
+365 9 9
+981 1 1
+11 1 1
+734 4 0
+563 4 0
+632 1 1
+17 1 1
+49 1 0
+95 1 1
+30 1 1
+147 1 1
+37 0 6
+340 1 2
+58 1 1
+112 0 1
+219 0 2
+231 0 3
+164 0 1
+26 1 1
+439 4 0
+34 0 2
+508 3 0
+96 1 1
+34 1 1
+829 1 1
+31 1 1
+405 15 15
+663 4 5
+1055 13 13
+135 0 1
+194 63 63
+384 6 6
+2756 1 1
+19 1 1
+1868 2 3
+2238 1 1
+31 1 1
+3002 4 0
+1116 1 1
+22 1 1
+1016 15 15
+855 15 13
+442 5 5
+2022 6 6
+506 0 2
+1110 0 1
+7396 1 1
+84 1 0
+3187 1 1
+16 1 1
+184 1 1
+18 1 1
+1607 53 60
+527 1 1
+39 1 1
+288 0 1
+364 3 0
+227 1 1
+18 1 1
+218 0 323
+91 1 0
+124 0 15
+621 0 4
+553 8 8
+467 1 1
+40 1 1
+372 1 1
+25 1 1
+188 12 12
+357 0 1
+250 0 5
+4193 0 4
+597 49 49
+321 1 1
+76 1 1
+2040 11 10
+1137 1 1
+48 4 4
+529 7 7
+246 4 0
+160 1 1
+34 0 3
+1469 0 2
+241 1 1
+17 1 1
+239 1 0
+937 1 1
+45 1 1
+421 6 0
+2127 0 1
+491 1 0
+80 1 1
+72 2 0
+255 6 6
+739 3 0
+702 5 0
+290 0 2
+210 5 1
+473 1 1
+42 4 0
+219 0 1
+348 1 1
+83 1 1
+851 0 16
+72 14 0
+246 1 1
+47 4 0
+410 1 0
+93 0 12
+225 0 14
+430 1 0
+4 6 0
+324 0 1
+939 1 1
+27 1 1
+142 1 1
+37 1 1
+1246 1 1
+44 1 1
+445 0 4
+173 0 2
+10545 1 1
+47 1 1
+1247 37 55
+805 1 0
+3789 1 1
+35 1 1
+1731 30 30
+2105 1 1
+30 1 1
+6075 1 0
+462 0 15
+4585 1 0
+3297 1 1
+49 1 1
+606 1 1
+48 1 1
+123 5 9
+109 1 31
+44 10 781
+77 2 0
+114 1 1
+62 1 1
+106 1 1
+268 18 4
+1079 0 2
+381 4 4
+106 1 1
+376 1 0
+1011 8 0
+584 5 0
+7537 7 0
+736 13 3
+2095 1 1
+45 1 1
+12786 0 11
+43 1 1
+720 5 7
+1358 0 2
+3813 19986 20000
+486 1 1
+46 1 1
+412 1 1
+23 1 0
+174 1 1
+24 1 1
+83 15 15
+363 1 1
+91 1 1
+51 17 17
+315 20 20
+199 13 13
+976 1 1
+39 0 3
+161 14 15
+127 16 16
+517 1 1
+81 1 1
+218 28 28
+124 1 1
+68 0 22
+252 1 1
+36 1 1
+784 0 1
+175 1 0
+148 1 1
+83 1 1
+469 1 1
+69 1 1
+245 1 1
+90 4 4
+1034 15 15
+69 1 1
+33 1 1
+174 1 1
+56 1 1
+169 1 0
+201 1 1
+30 1 1
+58 1 1
+38 1 1
+91 1 1
+98 4 4
+65 1 1
+19 2 0
+104 6 5
+25 1 1
+218 1 1
+37 1 1
+343 153809 150023
+66 8 8
+36 0 11
+62 1 1
+107 1 1
+68 3 130
+66 4 4
+50 21 21
+98 1 1
+127 1 0
+192 1 1
+71 1 1
+52 1 1
+200 1 1
+97 4 4
+85 5 5
+448 1 1
+97 11 11
+171 1 1
+61 1 1
+37 1 1
+156 3 0
+63 0 3
+155 3 0
+32 2 0
+232 1 1
+33 1 1
+175 2 0
+131 6 6
+1409 0 3
+222 1 1
+23 0 1
+1470 1 1
+21 1 1
+460 1 1
+71 1 1
+394 2 8
+37 1 1
+90 1 1
+43 1 1
+650 1 1
+34 1 1
+839 0 1
+431 1 1
+36 1 1
+284 60066 60160
+93 1 1
+75 808 0
+46 1 1
+221 1 1
+213 8 0
+63 1 1
+60 17 17
+53 1 1
+29 1 1
+68 8 8
+62 9 9
+51 1 1
+85 1 1
+101 1 1
+54 2 2
+116 1 1
+66 1 1
+182 1 0
+37 1 1
+134 14 14
+117 1 1
+45 1 1
+120 1 1
+47 1 1
+342 1 1
+46 1 1
+237 12 12
+107 8 8
+754 1 0
+880 1 1
+16 1 1
+741 1 1
+47 0 1
+19 2 2
+165 0 21
+26 1 1
+183 13 13
+72 1 1
+23 1 0
+268 14 14
+320 1 1
+55 1 1
+414 5 5
+172 0 1
+620 1 1
+18 1 1
+190 1 1
+20 0 8
+849 1 1
+29 1 1
+978 30213 30058
+159 1 1
+36 1 1
+107 1 1
+176 1 1
+154 0 5
+91 1 1
+54 1 1
+77 1 1
+239 1 1
+50 1 1
+128 1 1
+40 1 1
+62 1 0
+111 11 11
+734 1 1
+31 1 1
+215 1 1
+108 1 1
+259 1 1
+79 1 1
+80 1 1
+47 3 1
+40 1 1
+54 1 1
+46 1 1
+118 9 9
+98 1 0
+5 11 4
+23 0 7
+84 1 1
+84 2 2
+6 0 1
+6 1 0
+110 0 7
+537 1 1
+96 1 1
+441 1 1
+101 1 1
+242 14 14
+255 16 16
+142 1 0
+345 10 10
+54 1 1
+26 1 1
+108 1 1
+83 1 1
+128 1 1
+36 1 1
+231 1 1
+37 1 1
+534 1 1
+60 1 1
+804 0 3
+43 1 1
+148 1 1
+25 1 1
+69 10 10
+76 5 5
+37 1 1
+66 0 2
+192 1 1
+60 3 0
+19 1 1
+1149 1 1
+18 1 1
+77 1 1
+22 3 0
+42 1 1
+136 1 1
+78 2 0
+1712 8 9
+548 1 1
+50 1 1
+177 1 0
+410 1 1
+42 1 1
+422 10 10
+963 4 4
+329 1 9
+648 5 1
+117 1 1
+27 1 1
+574 1 0
+507 1 1
+39 1 1
+294 3 2
+549 1 1
+22 1 1
+74 0 1
+98 1 1
+65 3 3
+230 1 1
+18 1 0
+33 1 1
+51 1 1
+24 1 1
+811 1 1
+59 0 2
+8 1 1
+80 9 9
+437 14 14
+57 4 4
+588 15 15
+305 1 1
+17 1 1
+135 1 1
+50 1 1
+59 16 16
+129 1 1
+25 2 0
+12 1 1
+106 1 1
+31 1 1
+350 1 1
+47 1 1
+340 1 1
+65 1 1
+478 2 0
+714 8 7
+95 2 2
+52 2 1
+1129 1 1
+34 1 1
+1715 1 1
+87 1 1
+692 1 1
+47 0 1
+75 1 1
+2155 10 10
+1407 0 2
+202 1 1
+22 1 1
+186 1 1
+34 1 1
+264 1 0
+185 1 1
+24 1 0
+98 0 2
+258 8 14
+967 1 1
+37 3 3
+502 1 1
+22 1 1
+75 0 3
+163 1 1
+40 1 1
+638 0 3
+150 1 1
+11 0 1
+29 1 1
+125 1 1
+78 1 1
+115 8 0
+195 14 14
+1413 18 19
+1471 1 1
+30 1 1
+228 1 1
+28 0 2
+1142 1 1
+73 1 1
+104 73 73
+435 1 1
+37 1 3
+601 1 1
+43 1 1
+181 14 0
+37 1 0
+52 1 1
+125 4 4
+34 1 1
+208 1 1
+39 2 2
+418 1 1
+25 1 1
+81 1 1
+36 1 1
+99 6 7
+20 1 1
+73 1 1
+62 1 1
+103 1 1
+34 1 1
+772 0 1
+369 1 1
+29 0 2
+220 1 1
+89 1 1
+58 2 2
+103 1 1
+55 1 1
+19 1 1
+79 1 1
+29 0 1
+26 1 1
+252 1 1
+75 1 1
+467 1 1
+40 1 1
+389 13 13
+67 7 7
+1185 0 311
+64 6 6
+667 1 1
+38 1 1
+79 1 0
+517 1 1
+66 1 1
+450 3 0
+1133 12 12
+543 2 0
+960 14 14
+272 1 1
+41 1 1
+196 1 0
+1424 18 19
+271 1 1
+65 1 1
+345 1 1
+23 3 0
+116 3 3
+86 1 1
+39 1 1
+129 1 1
+26 1 1
+779 1 1
+32 1 1
+247 1 1
+48 1 1
+379 1 1
+18 1 1
+379 1 0
+226 1 1
+61 1 1
+861 0 1
+51 9 9
+397 1 1
+12 4 0
+46 1 1
+602 1 1
+35 1 1
+422 1 1
+49 1 1
+789 1 1
+37 1 1
+859 8 8
+378 0 4
+703 0 4
+2277 3 0
+1334 1 1
+10 0 1
+38 2 0
+61 1 1
+140 15 15
+1047 1 1
+38 1 1
+87 1 1
+24 5 4
+1291 1 1
+49 1 1
+307 14 14
+100 0 1
+75 1 1
+78 1 1
+243 1 0
+33 1 1
+116 19 19
+65 0 1
+238 0 1
+179 2 1
+67 1 1
+60 1 1
+32 1 1
+677 4 6
+83 318 0
+334 1 0
+1018 5 5
+559 0 2
+111 1 1
+30 1 1
+66 1 1
+38 1 1
+218 8 8
+754 1 1
+65 1 1
+182 1 1
+21 1 1
+285 1 1
+75 1 1
+147 6 0
+65 1 1
+42 1 1
+380 1 1
+84 6 0
+88 1 1
+25 1 1
+365 6 5
+108 1 1
+40 1 0
+50 1 1
+111 1 0
+21 0 1066
+119 0 1
+2641 1 1
+22 1 1
+2147 1 1
+29 1 1
+2252 1 1
+19 1 1
+1650 6 6
+1982 0 2
+2213 23 1
+2593 0 177
+338 1 1
+37 2 2
+395 10 0
+67 1 1
+131 1 1
+31 1 1
+386 1 1
+42 1 1
+372 1 1
+48 1 1
+3858 0 1
+351 1 0
+2536 16 16
+253 1 1
+16 1 1
+308 3 3
+52 1 1
+1308 0 3
+330 9 9
+600 2 0
+261 8 8
+9909 0 2
+2337 2 0
+3769 1 0
+1505 0 1
+4327 1 1
+15 1 1
+241 0 1
+230 1 0
+5263 1 0
+1386 0 41
+119 1 0
+4323 0 1
+54 1 1
+116 0 4
+1354 1 0
+1161 20 21
+1946 0 1
+584 0 2
+3100 1 0
+3491 1 0
+461 1 0
+762 0 8
+14669 1 0
+7644 6 0
+10539 4 0
+24841 1 0
+4856 3 0
+6082 2 0
+955 0 2
+1622 20422 20421
+76 0 3
+1724 2 0
+1173 1 0
+1783 1 1
+41 1 1
+4618 1 0
+232 0 2
+4975 2 0
+1487 15 14
+1184 2 0
+342 16 15
+328 0 3
+570 1 0
+995 1 0
+192 4 4
+1434 4 0
+62 1 1
+3531 2 3
+2846 1 1
+17 1 1
+704 0 1
+4801 1 0
+1417 0 4
+50 3 0
+165 0 1
+7575 9 0
+7359 11 0
+14219 0 2
+50 24 10
+38 2 0
+42 0 24
+24 0 18
+8297 1 1
+28 1 1
+264 1 1
+65 0 1
+15 1 1
+2371 19 19
+57 1 1
+21 1 1
+231 1 1
+94 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 40 40
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 5 5
+23 1 1
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+427 1 1
+115 1 1
+28630 0 8
+18331 0 26
+1830 22668 22667
+16645 4 0
+4458 0 2
+2318 1 1
+24 1 1
+2089 0 1
+68717 1 0
+8718 4 0
+12333 12 0
+835 0 1
+391 58 61
+12157 1 0
+5577 1 0
+23151 3 0
+1588 1 0
+2605 1 1
+23 1 1
+11252 8 0
+298 6 7
+946 2 0
+232 0 1
+501 1 0
+4748 0 4
+770 0 7
+914 0 1
+295 1 0
+214 2 0
+121 0 1
+784 0 1
+2512 0 1
+1205 21 21
+3250 1 0
+926 0 1
+189 2 0
+3543 2 0
+893 1 1
+46 1 1
+1296 0 1
+153 0 2
+335 5 0
+187 1 1
+86 1 1
+207 3 0
+322 0 1
+658 1 0
+1516 3 0
+1025 0 13
+1518 0 1
+591 10 10
+3384 0 2
+182 12 0
+328 1 0
+301 0 1
+994 1 1
+18 0 6
+1743 0 1
+2350 22 23
+1548 0 7
+1976 1 0
+199 0 1
+3290 1 1
+28 1 1
+2602 12 12
+873 0 3
+3080 12 8
+322 1 0
+490 1 0
+4084 1 0
+2421
+
+chain 584308 chr6_dbb_hap3 4610396 + 3832023 3871403 chr5 180857866 - 25428915 25436336 9077
+107 1 1
+69 1 1
+306 1 1
+71 1 1
+121 1 1
+88 1 1
+96 12 1
+257 1 1
+92 32139 188
+68 1 0
+39 1 1
+136 4 4
+14 1 1
+82 1 1
+80 1 1
+217 1 1
+28 0 4
+34 1 1
+114 1 1
+29 2 2
+1703 4 4
+315 13 13
+184 1 1
+31 1 1
+789 1 1
+47 5 5
+415 8 8
+85 13 13
+985 1 1
+142 1 1
+205 1 1
+35 1 1
+174
+
+chain 148040 chr6_dbb_hap3 4610396 + 3896754 3898327 chr9 140273252 + 114315581 114318014 872071
+803 1 1
+32 0 453
+67 2 409
+668
+
+chain 80965 chr6_dbb_hap3 4610396 + 2305865 2306722 chr6 170899992 - 139781917 139782778 1559016
+341 0 4
+516
+
+chain 59035 chr6_dbb_hap3 4610396 + 3814253 3815703 chr1 247249719 + 235898881 235900160 2133080
+173 33 33
+70 99 102
+68 14 14
+66 427 253
+104 96 96
+78 80 80
+142
+
+chain 56303 chr6_dbb_hap3 4610396 + 3895098 3898571 chr8 146274826 - 53671532 53672205 16841
+99 13 14
+38 12 0
+6 3 15
+341 2802 1
+101 1 1
+57
+
+chain 51533 chr6_dbb_hap3 4610396 + 2519888 2521822 chr1 247249719 + 7396445 7398379 2460894
+102 170 170
+98 761 760
+135 79 79
+58 214 214
+173 73 74
+71
+
+chain 35778 chr6_dbb_hap3 4610396 + 1195644 1199573 chr6 170899992 + 29950082 29959351 3739128
+53 1042 1027
+90 511 191
+90 460 6138
+153 336 337
+77 683 679
+78 267 267
+89
+
+chain 29930 chr6_dbb_hap3 4610396 + 1291857 1292168 chr10 135374737 + 129836562 129836873 4701711
+311
+
+chain 29904 chr6_dbb_hap3 4610396 + 1119153 1119465 chr7 158821424 + 38479558 38479870 4710596
+312
+
+chain 29422 chr6_dbb_hap3 4610396 + 2048496 2048802 chr6 170899992 + 69396184 69396490 4710630
+306
+
+chain 29265 chr6_dbb_hap3 4610396 + 2582091 2582592 chr2 242951149 + 112146990 112147493 4980566
+65 94 96
+54 27 27
+152 33 33
+76
+
+chain 28976 chr6_dbb_hap3 4610396 + 4055704 4056006 chr2 242951149 - 177193633 177193935 5141771
+302
+
+chain 28679 chr6_dbb_hap3 4610396 + 2275002 2275314 chr3 199501827 - 86469460 86469765 4692119
+171 7 0
+134
+
+chain 26875 chr6_dbb_hap3 4610396 + 2605062 2605840 chr6 170899992 + 31342625 31343398 6110200
+75 247 243
+74 12 16
+72 194 189
+104
+
+chain 23264 chr6_dbb_hap3 4610396 + 3891437 3892382 chr6 170899992 + 32821586 32822354 8135396
+218 677 500
+50
+
+chain 23054 chr6_dbb_hap3 4610396 + 3970815 3971054 chr3 199501827 - 39984613 39984852 8258949
+239
+
+chain 22312 chr6_dbb_hap3 4610396 + 1158170 1158946 chr7 158821424 - 51137320 51138262 8787332
+90 9 9
+79 101 101
+72 385 551
+40
+
+chain 21919 chr6_dbb_hap3 4610396 + 3896060 3896302 chrX 154913754 - 82335943 82336185 9052373
+242
+
+chain 19800 chr6_dbb_hap3 4610396 + 3895610 3895845 chr7 158821424 - 34919795 34920030 7485763
+5 1 1
+87 3 3
+71 1 1
+67
+
+chain 19015 chr6_dbb_hap3 4610396 + 3943955 3944187 chr11 134452384 + 111558067 111558299 11259777
+149 20 20
+63
+
+chain 18237 chr6_dbb_hap3 4610396 + 2595793 2596391 chr13 114142980 + 51183720 51184326 11909510
+52 119 119
+108 253 261
+66
+
+chain 17641 chr6_dbb_hap3 4610396 + 3836782 3837025 chrX 154913754 + 35042287 35042530 12436913
+99 43 43
+101
+
+chain 17270 chr6_dbb_hap3 4610396 + 3918499 3918707 chr10 135374737 - 70196080 70196288 12781659
+86 2 2
+48 5 5
+67
+
+chain 16865 chr6_dbb_hap3 4610396 + 3983463 3983966 chrX 154913754 + 8861421 8861925 13172813
+68 216 217
+63 77 77
+79
+
+chain 16634 chr6_dbb_hap3 4610396 + 3895901 3896503 chr2 242951149 + 35312811 35313413 7601022
+134 363 363
+105
+
+chain 13803 chr6_dbb_hap3 4610396 + 3796429 3796972 chr2 242951149 - 211383777 211384322 16433564
+114 376 378
+53
+
+chain 13479 chr6_dbb_hap3 4610396 + 1132829 1133547 chr6 170899992 + 29984509 29985227 16848878
+104 552 552
+62
+
+chain 13400 chr6_dbb_hap3 4610396 + 3837061 3837652 chr1 247249719 + 76199329 76199914 13528533
+72 466 460
+53
+
+chain 13024 chr6_dbb_hap3 4610396 + 983805 983941 chr11 134452384 - 45905925 45906061 17454496
+136
+
+chain 12671 chr6_dbb_hap3 4610396 + 3940526 3940660 chrX 154913754 - 65797896 65798030 17982412
+134
+
+chain 12198 chr6_dbb_hap3 4610396 + 3795847 3796096 chr7 158821424 + 40936078 40936329 18688113
+94 105 107
+50
+
+chain 11398 chr6_dbb_hap3 4610396 + 2592168 2592321 chr6 170899992 - 161606914 161607067 20013435
+64 22 22
+67
+
+chain 11324 chr6_dbb_hap3 4610396 + 3938144 3938291 chr6 170899992 - 138135992 138136139 20148164
+68 15 15
+64
+
+chain 10873 chr6_dbb_hap3 4610396 + 1193470 1193591 chr19 63811651 + 15986631 15986752 20965589
+121
+
+chain 10867 chr6_dbb_hap3 4610396 + 2527311 2527468 chr6 170899992 - 132294381 132294544 20980273
+55 29 35
+73
+
+chain 10755 chr6_dbb_hap3 4610396 + 2751799 2751912 chrX 154913754 - 134479310 134479423 11323978
+113
+
+chain 10634 chr6_dbb_hap3 4610396 + 3919991 3920105 chr5 180857866 + 34801263 34801377 21438493
+114
+
+chain 10332 chr6_dbb_hap3 4610396 + 3984189 3984438 chr18 76117153 - 27021129 27021380 22068171
+57 124 126
+68
+
+chain 10015 chr6_dbb_hap3 4610396 + 3921148 3921283 chr14 106368585 + 84133812 84133947 22772205
+59 19 19
+57
+
+chain 9987 chr6_dbb_hap3 4610396 + 3796659 3796919 chr12 132349534 + 56701652 56701911 19406222
+70 165 164
+25
+
+chain 9750 chr6_dbb_hap3 4610396 + 2598300 2598402 chr6 170899992 + 31328563 31328665 23393690
+102
+
+chain 9528 chr6_dbb_hap3 4610396 + 1160418 1160855 chr6 170899992 + 29878108 29878543 23937745
+59 318 316
+60
+
+chain 9496 chr6_dbb_hap3 4610396 + 3698327 3698427 chr11 134452384 - 102104468 102104568 24009659
+100
+
+chain 9090 chr6_dbb_hap3 4610396 + 2526557 2526667 chr3 199501827 - 94209663 94209773 24799755
+53 4 4
+53
+
+chain 9042 chr6_dbb_hap3 4610396 + 3982887 3983463 chrX 154913754 - 39105241 39105605 22912000
+59 507 295
+10
+
+chain 8509 chr6_dbb_hap3 4610396 + 3919900 3919991 chr9 140273252 - 54900636 54900727 21580039
+91
+
+chain 7414 chr6_dbb_hap3 4610396 + 3922665 3922744 chr6 170899992 - 151548315 151548394 27385131
+79
+
+chain 7276 chr6_dbb_hap3 4610396 + 3860392 3860468 chr6 170899992 - 67344251 67344327 27653182
+76
+
+chain 7202 chr6_dbb_hap3 4610396 + 3830969 3832020 chr3 199501827 + 106790123 106791174 346924
+69 5 5
+109 2 2
+142 1 1
+77 1 1
+51 1 0
+194 0 1
+399
+
+chain 6804 chr6_dbb_hap3 4610396 + 3735469 3735541 chr6 170899992 + 32582474 32582546 28581342
+72
+
+chain 6776 chr6_dbb_hap3 4610396 + 3900841 3908708 chr6 170899992 + 32827127 32834907 28655646
+50 4318 3617
+61 2532 2695
+93 658 1109
+155
+
+chain 6739 chr6_dbb_hap3 4610396 + 3920547 3920617 chr6 170899992 + 53525586 53525656 28727012
+70
+
+chain 6718 chr6_dbb_hap3 4610396 + 3983858 3984010 chr15 100338915 - 66378648 66378800 16209113
+29 79 79
+44
+
+chain 6712 chr6_dbb_hap3 4610396 + 2536742 2536812 chr6 170899992 - 140565854 140565924 28801697
+70
+
+chain 6657 chr6_dbb_hap3 4610396 + 3814584 3815561 chr4 191273063 - 103136563 103137365 2286737
+44 251 76
+51 551 551
+20 37 37
+23
+
+chain 6566 chr6_dbb_hap3 4610396 + 1190938 1191006 chr6 170899992 + 30567038 30567106 29137401
+68
+
+chain 6566 chr6_dbb_hap3 4610396 + 3835601 3835669 chr6 170899992 + 32665461 32665529 29137402
+68
+
+chain 6459 chr6_dbb_hap3 4610396 + 3795625 3795694 chr11 134452384 + 89638894 89638963 29378141
+69
+
+chain 6457 chr6_dbb_hap3 4610396 + 1205138 1205205 chr6 170899992 + 30336816 30336883 29393793
+67
+
+chain 6404 chr6_dbb_hap3 4610396 + 3984475 3984543 chr7 158821424 + 141217888 141217956 29535627
+68
+
+chain 6112 chr6_dbb_hap3 4610396 + 3700406 3700470 chr18 76117153 - 19156586 19156650 30278938
+64
+
+chain 6077 chr6_dbb_hap3 4610396 + 3828852 3828917 chr6 170899992 + 32661358 32661423 30333820
+65
+
+chain 6003 chr6_dbb_hap3 4610396 + 2599299 2599362 chr6 170899992 + 31329552 31329615 30561641
+63
+
+chain 5676 chr6_dbb_hap3 4610396 + 2522554 2523018 chr1 247249719 + 71360098 71360557 7933597
+8 394 389
+62
+
+chain 5420 chr6_dbb_hap3 4610396 + 1191387 1191443 chr6 170899992 + 29965652 29965708 32189291
+56
+
+chain 5384 chr6_dbb_hap3 4610396 + 3920366 3920422 chr5 180857866 + 130110350 130110406 32314816
+56
+
+chain 5365 chr6_dbb_hap3 4610396 + 1189212 1189267 chr6 170899992 + 30335396 30335451 32370613
+55
+
+chain 5349 chr6_dbb_hap3 4610396 + 1146055 1146112 chr1 247249719 + 172045890 172045947 32394662
+57
+
+chain 5348 chr6_dbb_hap3 4610396 + 3704305 3704361 chr13 114142980 - 61076835 61076891 32406029
+56
+
+chain 5312 chr6_dbb_hap3 4610396 + 3955463 3955519 chr2 242951149 - 134958526 134958582 32494768
+56
+
+chain 5202 chr6_dbb_hap3 4610396 + 3920808 3920862 chr12 132349534 + 102926992 102927046 32856661
+54
+
+chain 5194 chr6_dbb_hap3 4610396 + 2522678 2522733 chr2 242951149 + 136412357 136412412 32870828
+55
+
+chain 5157 chr6_dbb_hap3 4610396 + 3919474 3919528 chr18 76117153 - 75578306 75578360 33003263
+54
+
+chain 5129 chr6_dbb_hap3 4610396 + 3699000 3699053 chr5 180857866 + 132341386 132341439 33069683
+53
+
+chain 5112 chr6_dbb_hap3 4610396 + 3702291 3702345 chr21 46944323 - 8455162 8455216 33113520
+54
+
+chain 5085 chr6_dbb_hap3 4610396 + 3943091 3943145 chrX 154913754 - 38541067 38541121 33235366
+54
+
+chain 5066 chr6_dbb_hap3 4610396 + 1193375 1193428 chr21 46944323 - 1867343 1867396 33290795
+53
+
+chain 5058 chr6_dbb_hap3 4610396 + 3934514 3934568 chr11 134452384 + 35678810 35678864 33301897
+54
+
+chain 4994 chr6_dbb_hap3 4610396 + 3795260 3795313 chr12 132349534 + 29061661 29061714 33541955
+53
+
+chain 4994 chr6_dbb_hap3 4610396 + 3796133 3796186 chr4 191273063 + 58121526 58121579 33542099
+53
+
+chain 4976 chr6_dbb_hap3 4610396 + 3794848 3794901 chrX 154913754 - 55960756 55960809 33594824
+53
+
+chain 4966 chr6_dbb_hap3 4610396 + 3797697 3797749 chr2 242951149 - 82237285 82237337 33630342
+52
+
+chain 4930 chr6_dbb_hap3 4610396 + 3702504 3702556 chr9 140273252 + 93086155 93086207 33718599
+52
+
+chain 4923 chr6_dbb_hap3 4610396 + 1158348 1158410 chr9 140273252 - 102391777 102391839 11227004
+62
+
+chain 4922 chr6_dbb_hap3 4610396 + 3834682 3834735 chr6 170899992 + 32548301 32548354 33750858
+53
+
+chain 4921 chr6_dbb_hap3 4610396 + 3919158 3919210 chrX 154913754 - 85139489 85139541 33755277
+52
+
+chain 4914 chr6_dbb_hap3 4610396 + 2519587 2519639 chrX 154913754 + 7895883 7895935 17698100
+52
+
+chain 4895 chr6_dbb_hap3 4610396 + 3971054 3971105 chr9 140273252 + 7362065 7362116 8474619
+51
+
+chain 4839 chr6_dbb_hap3 4610396 + 2523181 2523232 chr1 247249719 - 83322643 83322694 34042185
+51
+
+chain 4829 chr6_dbb_hap3 4610396 + 1205662 1205712 chr6 170899992 + 30567298 30567348 34088050
+50
+
+chain 4821 chr6_dbb_hap3 4610396 + 3921606 3921657 chr19 63811651 + 44797095 44797146 34119671
+51
+
+chain 4821 chr6_dbb_hap3 4610396 + 3795725 3795776 chr6 170899992 - 89445109 89445160 34121660
+51
+
+chain 4812 chr6_dbb_hap3 4610396 + 3797020 3797071 chr9 140273252 - 60383600 60383651 34150921
+51
+
+chain 4802 chr6_dbb_hap3 4610396 + 3704401 3704451 chr4 191273063 - 155219143 155219193 34221295
+50
+
+chain 4766 chr6_dbb_hap3 4610396 + 3700117 3700167 chr9 140273252 + 86874856 86874906 34319112
+50
+
+chain 4694 chr6_dbb_hap3 4610396 + 3910535 3910585 chr6 170899992 + 32836714 32836764 34581613
+50
+
+chain 4630 chr6_dbb_hap3 4610396 + 2519306 2519455 chrX 154913754 - 130647735 130647884 4467919
+8 13 13
+128
+
+chain 4435 chr6_dbb_hap3 4610396 + 2521889 2521945 chr1 247249719 + 68329905 68329961 24341076
+56
+
+chain 4406 chr6_dbb_hap3 4610396 + 3836685 3836748 chr12 132349534 + 83019068 83019131 17889506
+63
+
+chain 4295 chr6_dbb_hap3 4610396 + 2518454 2518508 chr13 114142980 + 40947099 40947153 23509760
+54
+
+chain 4259 chr6_dbb_hap3 4610396 + 2520658 2522182 chr1 247249719 + 175639486 175641011 2690506
+58 695 694
+59 250 251
+31 373 374
+58
+
+chain 4202 chr6_dbb_hap3 4610396 + 2519814 2519869 chr3 199501827 + 157792092 157792147 19123443
+55
+
+chain 4148 chr6_dbb_hap3 4610396 + 2596230 2596277 chr7 158821424 - 75232531 75232578 15855534
+47
+
+chain 3884 chr6_dbb_hap3 4610396 + 2596391 2596432 chr8 146274826 + 74136425 74136466 15736555
+41
+
+chain 3783 chr6_dbb_hap3 4610396 + 2595924 2595964 chr2 242951149 - 166645324 166645364 18114608
+40
+
+chain 3633 chr6_dbb_hap3 4610396 + 2595546 2596150 chr14 106368585 - 51104394 51104979 12640292
+71 478 459
+55
+
+chain 3600 chr6_dbb_hap3 4610396 + 3984599 3984637 chr2 242951149 + 129304609 129304647 25766382
+38
+
+chain 3466 chr6_dbb_hap3 4610396 + 3944209 3944269 chr5 180857866 - 165236686 165236746 13055377
+60
+
+chain 3427 chr6_dbb_hap3 4610396 + 2595867 2595923 chrX 154913754 - 74451128 74451184 24425971
+56
+
+chain 3366 chr6_dbb_hap3 4610396 + 3697430 3697469 chr7 158821424 - 31427441 31427480 35195573
+39
+
+chain 3356 chr6_dbb_hap3 4610396 + 2596277 2596325 chr6 170899992 + 67193869 67193917 14667051
+48
+
+chain 3333 chr6_dbb_hap3 4610396 + 3796616 3796658 chr6 170899992 + 112361298 112361340 25801948
+42
+
+chain 3275 chr6_dbb_hap3 4610396 + 1138782 1138817 chr6 170899992 + 29990315 29990350 35226052
+35
+
+chain 3219 chr6_dbb_hap3 4610396 + 2595512 2595546 chr15 100338915 + 54012038 54012072 22943633
+34
+
+chain 3113 chr6_dbb_hap3 4610396 + 2519060 2522554 chr12 132349534 + 103307685 103311177 2899166
+99 961 960
+40 1029 1028
+44 1259 1259
+62
+
+chain 2845 chr6_dbb_hap3 4610396 + 2519030 2519060 chr3 199501827 - 158108130 158108160 26771667
+30
+
+chain 2771 chr6_dbb_hap3 4610396 + 2186148 2186180 chr16 88827254 + 61371572 61371604 11881974
+32
+
+chain 2656 chr6_dbb_hap3 4610396 + 3920105 3920152 chr1 247249719 + 97086811 97086858 21929674
+47
+
+chain 2634 chr6_dbb_hap3 4610396 + 3702345 3702373 chr4 191273063 - 9754971 9754999 34558482
+28
+
+chain 2599 chr6_dbb_hap3 4610396 + 1158410 1158448 chr7 158821424 - 126060947 126060985 11258553
+38
+
+chain 2560 chr6_dbb_hap3 4610396 + 3796543 3796570 chr9 140273252 + 82550760 82550787 23127746
+27
+
+chain 2433 chr6_dbb_hap3 4610396 + 3814163 3814213 chr5 180857866 - 58683848 58683898 14264874
+50
+
+chain 2422 chr6_dbb_hap3 4610396 + 3815331 3815377 chr6 170899992 + 32052376 32052422 9201222
+46
+
+chain 2386 chr6_dbb_hap3 4610396 + 3944336 3944393 chr4 191273063 + 105171966 105172023 11828581
+57
+
+chain 2350 chr6_dbb_hap3 4610396 + 1144323 1144351 chr9 140273252 + 98495373 98495401 22648902
+28
+
+chain 2334 chr6_dbb_hap3 4610396 + 1197501 1197553 chr1 247249719 + 48751712 48751764 24363112
+52
+
+chain 2326 chr6_dbb_hap3 4610396 + 3944285 3944315 chr5 180857866 - 104226614 104226644 17910212
+30
+
+chain 2262 chr6_dbb_hap3 4610396 + 1158146 1158170 chr19 63811651 - 5696072 5696096 21221760
+24
+
+chain 2258 chr6_dbb_hap3 4610396 + 2582592 2582621 chr10 135374737 - 49445077 49445106 7325456
+29
+
+chain 2252 chr6_dbb_hap3 4610396 + 3944437 3944463 chr1 247249719 - 9396437 9396463 17746619
+26
+
+chain 2238 chr6_dbb_hap3 4610396 + 3984543 3984572 chr8 146274826 + 40415013 40415042 30916283
+1 3 0
+5 0 3
+20
+
+chain 2198 chr6_dbb_hap3 4610396 + 3591295 3591318 chrX 154913754 - 138619630 138619653 32682302
+23
+
+chain 2171 chr6_dbb_hap3 4610396 + 3944636 3944659 chr5 180857866 - 116975655 116975678 23231315
+23
+
+chain 2164 chr6_dbb_hap3 4610396 + 2581904 2581960 chr15 100338915 + 41094361 41094417 6236685
+56
+
+chain 2136 chr6_dbb_hap3 4610396 + 2582305 2582331 chrX 154913754 + 74544454 74544480 5553867
+24 1 1
+1
+
+chain 2131 chr6_dbb_hap3 4610396 + 3895846 3896559 chr7 158821424 + 107074762 107075475 8294701
+30 628 628
+55
+
+chain 2073 chr6_dbb_hap3 4610396 + 1158564 1158618 chr1 247249719 + 222604152 222604206 12884992
+54
+
+chain 2063 chr6_dbb_hap3 4610396 + 2527468 2527490 chr10 135374737 + 5170837 5170859 26024714
+22
+
+chain 2035 chr6_dbb_hap3 4610396 + 3944660 3944732 chr8 146274826 + 40414891 40414930 35524999
+20 2 0
+3 8 0
+5 23 0
+11
+
+chain 1939 chr6_dbb_hap3 4610396 + 1197585 1197647 chr4_random 842648 + 579429 579491 24056746
+62
+
+chain 1911 chr6_dbb_hap3 4610396 + 3796202 3796275 chr20 62435964 - 40308436 40308509 20356789
+73
+
+chain 1856 chr6_dbb_hap3 4610396 + 1158521 1158554 chr4 191273063 + 153905795 153905828 9266240
+33
+
+chain 1843 chr6_dbb_hap3 4610396 + 2520547 2520624 chr3 199501827 - 153335243 153335320 2775919
+77
+
+chain 1791 chr6_dbb_hap3 4610396 + 3814944 3814997 chr2 242951149 + 15669060 15669113 2773805
+53
+
+chain 1791 chr6_dbb_hap3 4610396 + 3896327 3896371 chr3 199501827 - 21590873 21590917 16297046
+44
+
+chain 1748 chr6_dbb_hap3 4610396 + 3896647 3898412 chr12 132349534 + 37486950 37487098 8651766
+20 2 0
+53 1616 1
+74
+
+chain 1729 chr6_dbb_hap3 4610396 + 2592021 2592074 chr14 106368585 - 49465840 49465893 23309002
+53
+
+chain 1667 chr6_dbb_hap3 4610396 + 2519690 2519769 chr4 191273063 + 150810923 150811002 4477040
+79
+
+chain 1644 chr6_dbb_hap3 4610396 + 3795469 3795533 chr5 180857866 - 17624826 17624890 19426880
+64
+
+chain 1588 chr6_dbb_hap3 4610396 + 2519256 2520761 chr7 158821424 + 116147190 116148689 3019444
+50 1410 1404
+45
+
+chain 1514 chr6_dbb_hap3 4610396 + 1158618 1158676 chr13 114142980 - 5380936 5380994 10250152
+58
+
+chain 1507 chr6_dbb_hap3 4610396 + 2519507 2519587 chr4 191273063 + 139055274 139055354 16166689
+80
+
+chain 1497 chr6_dbb_hap3 4610396 + 2596436 2596504 chr13 114142980 - 63160902 63160970 14379683
+68
+
+chain 1378 chr6_dbb_hap3 4610396 + 2518320 2518446 chr9 140273252 + 106017756 106017882 9913209
+126
+
+chain 1359 chr6_dbb_hap3 4610396 + 1158766 1158832 chr11 134452384 + 118435255 118435321 13536573
+66
+
+chain 1326 chr6_dbb_hap3 4610396 + 2518769 2518884 chr2 242951149 - 193553846 193553961 4392729
+115
+
+chain 1279 chr6_dbb_hap3 4610396 + 3895876 3895901 chr5 180857866 - 141473608 141473633 7934834
+25
+
+chain 1261 chr6_dbb_hap3 4610396 + 2595748 2595793 chr7 158821424 - 113148258 113148303 12073479
+45
+
+chain 1252 chr6_dbb_hap3 4610396 + 3944555 3944605 chr10 135374737 + 81711914 81711964 14060366
+50
+
+chain 1247 chr6_dbb_hap3 4610396 + 3837297 3837358 chrY 57772954 + 10103368 10103429 19375318
+61
+
+chain 1238 chr6_dbb_hap3 4610396 + 1193115 1193174 chr8 146274826 - 84904941 84905000 22834115
+59
+
+chain 1229 chr6_dbb_hap3 4610396 + 3797090 3797164 chr7 158821424 - 63976160 63976234 19674520
+74
+
+chain 1211 chr6_dbb_hap3 4610396 + 2596569 2596648 chr11 134452384 + 125240934 125241013 21730841
+79
+
+chain 1198 chr6_dbb_hap3 4610396 + 3983120 3983171 chrX 154913754 - 112657474 112657525 22999394
+51
+
+chain 1198 chr6_dbb_hap3 4610396 + 2520259 2520315 chr1 247249719 - 41799264 41799320 23684518
+56
+
+chain 1160 chr6_dbb_hap3 4610396 + 2522055 2522083 chrX 154913754 + 56853117 56853145 21155197
+28
+
+chain 1156 chr6_dbb_hap3 4610396 + 3814529 3814567 chr1 247249719 - 95427068 95427106 3236426
+38
+
+chain 1115 chr6_dbb_hap3 4610396 + 2519770 2519814 chr17 78774742 - 18978582 18978626 19145840
+44
+
+chain 1092 chr6_dbb_hap3 4610396 + 3815720 3815773 chr6 170899992 + 33136473 33136526 4404150
+53
+
+chain 1080 chr6_dbb_hap3 4610396 + 3982965 3983026 chr4 191273063 + 91007246 91007307 23248893
+61
+
+chain 1070 chr6_dbb_hap3 4610396 + 3983531 3983571 chr13 114142980 + 78421238 78421278 18216872
+40
+
+chain 1033 chr6_dbb_hap3 4610396 + 3797495 3797589 chr2 242951149 - 222175668 222175762 18472154
+94
+
+chain 1021 chr6_dbb_hap3 4610396 + 3944605 3944636 chr3 199501827 + 41781985 41782016 21488147
+31
+
+chain 961 chr6_dbb_hap3 4610396 + 2591988 2592021 chr6 170899992 + 31311499 31311532 23940424
+33
+
+chain 912 chr6_dbb_hap3 4610396 + 2522218 2522277 chr5 180857866 - 20904100 20904159 3597825
+59
+
+chain 912 chr6_dbb_hap3 4610396 + 2522435 2522465 chr7 158821424 + 107644178 107644208 21981895
+30
+
+chain 892 chr6_dbb_hap3 4610396 + 3815177 3815203 chr1 247249719 - 223546777 223546803 2552155
+26
+
+chain 886 chr6_dbb_hap3 4610396 + 2518921 2518972 chrX 154913754 - 65002049 65002100 8335918
+51
+
+chain 881 chr6_dbb_hap3 4610396 + 2521831 2521881 chr4 191273063 + 5547185 5547235 3823174
+50
+
+chain 876 chr6_dbb_hap3 4610396 + 2522095 2522124 chr1 247249719 - 197271642 197271671 12596899
+29
+
+chain 858 chr6_dbb_hap3 4610396 + 2522184 2522218 chr7 158821424 - 148280259 148280293 6691658
+34
+
+chain 850 chr6_dbb_hap3 4610396 + 3815307 3815331 chr11 134452384 + 75267105 75267129 2466745
+24
+
+chain 846 chr6_dbb_hap3 4610396 + 3896560 3896615 chr1 247249719 - 102242947 102243002 13724822
+55
+
+chain 818 chr6_dbb_hap3 4610396 + 3815047 3815103 chr9 140273252 - 13362556 13362612 11609524
+56
+
+chain 787 chr6_dbb_hap3 4610396 + 2522005 2522055 chr2 242951149 + 76860552 76860602 3963281
+50
+
+chain 742 chr6_dbb_hap3 4610396 + 2520888 2520940 chr10 135374737 + 51611354 51611406 20534291
+52
+
+chain 740 chr6_dbb_hap3 4610396 + 1159052 1159116 chr12 132349534 + 55464534 55464598 20832677
+64
+
+chain 734 chr6_dbb_hap3 4610396 + 2517749 2518673 chr8 146274826 - 112931559 112932176 13565224
+68 769 462
+87
+
+chain 717 chr6_dbb_hap3 4610396 + 3984125 3984177 chr16 88827254 - 38714794 38714846 22849175
+52
+
+chain 688 chr6_dbb_hap3 4610396 + 2519167 2519218 chr12 132349534 - 101137563 101137614 3748471
+51
+
+chain 684 chr6_dbb_hap3 4610396 + 2522743 2522826 chr1 247249719 + 68246247 68246330 16550290
+83
+
+chain 681 chr6_dbb_hap3 4610396 + 3982752 3982809 chr8 146274826 - 64029404 64029461 24731945
+57
+
+chain 668 chr6_dbb_hap3 4610396 + 3714611 3714639 chr13 114142980 + 25366313 25366341 2606938
+28
+
+chain 661 chr6_dbb_hap3 4610396 + 2523098 2523163 chr5 180857866 + 99923773 99923838 9614006
+65
+
+chain 654 chr6_dbb_hap3 4610396 + 1158946 1158972 chr4 191273063 - 137719796 137719822 10317120
+26
+
+chain 638 chr6_dbb_hap3 4610396 + 3795059 3795115 chr1 247249719 - 190736869 190736925 22996754
+56
+
+chain 603 chr6_dbb_hap3 4610396 + 3896371 3896398 chr6 170899992 + 38375889 38375916 7901672
+27
+
+chain 602 chr6_dbb_hap3 4610396 + 2519990 2520031 chr6 170899992 - 100068900 100068941 3263990
+41
+
+chain 571 chr6_dbb_hap3 4610396 + 2518673 2518747 chr3 199501827 + 50931043 50931117 15282719
+74
+
+chain 547 chr6_dbb_hap3 4610396 + 2522845 2522895 chr11 134452384 - 79794459 79794509 15991277
+50
+
+chain 544 chr6_dbb_hap3 4610396 + 2520356 2520407 chr13 114142980 + 104410064 104410115 4879952
+51
+
+chain 461 chr6_dbb_hap3 4610396 + 2522377 2522435 chr9 140273252 - 118104609 118104667 6129577
+58
+
+chain 447 chr6_dbb_hap3 4610396 + 2517845 2517905 chr8 146274826 - 66271750 66271810 23464585
+60
+
+chain 423 chr6_dbb_hap3 4610396 + 2520499 2520535 chr16 88827254 - 23736388 23736424 4641188
+36
+
+chain 407 chr6_dbb_hap3 4610396 + 3833249 3833277 chr11 134452384 + 92791982 92792010 9335
+28
+
+chain 395 chr6_dbb_hap3 4610396 + 3896615 3896647 chr10 135374737 - 43610926 43610958 15449290
+32
+
+chain 363 chr6_dbb_hap3 4610396 + 2522305 2522360 chr2 242951149 + 137419466 137419521 26505689
+55
+
+chain 350 chr6_dbb_hap3 4610396 + 2523417 2523489 chr15 100338915 + 97778900 97778972 9309023
+72
+
+chain 312 chr6_dbb_hap3 4610396 + 2520407 2520446 chr10 135374737 - 80033072 80033111 12533916
+39
+
+chain 290 chr6_dbb_hap3 4610396 + 2523894 2523946 chr1 247249719 - 204952078 204952130 18508597
+52
+
+chain 258 chr6_dbb_hap3 4610396 + 2518973 2519027 chr2 242951149 + 129418481 129418535 12872927
+54
+
+chain 235 chr6_dbb_hap3 4610396 + 3982484 3982540 chr21 46944323 + 15992125 15992181 26051708
+56
+
+chain 337820870 chr6_mann_hap4 4683263 + 0 4683263 chr6 170899992 + 28804582 33333955 39
+932 3 0
+804 0 1
+2406 2 0
+141275 1 0
+429 38391 38391
+17722 4 0
+12815 0 1
+28140 1 3
+12586 0 1
+9819 0 1
+69013 0 1
+22684 1 0
+14147 7 0
+1489 1 1
+72 1 1
+2260 0 2
+7033 0 4
+13929 13 14
+9228 0 1
+1324 0 3
+5437 5 0
+2061 1 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4746 9 9
+4767 7 7
+1169 1 1
+55 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+249 43 43
+1178 0 4
+685 8 0
+48 8 0
+1701 1 1
+43 5 5
+862 18 18
+58 1 1
+66 1 1
+420 1 1
+44 1 1
+680 4 4
+1675 1 1
+83 1 1
+3082 4 0
+5467 1 1
+27 0 1
+1099 16 0
+627 12 12
+1317 6 1
+129 1 1
+25 1 1
+1397 15 15
+810 1 1
+27 1 1
+1192 2 0
+7515 4 0
+979 0 4
+3405 0 2
+3501 1 1
+26 1 1
+787 0 1
+1416 3 1
+22815 4 4
+126 1 0
+38 1 1
+140 1 0
+999 0 17
+56 0 15
+15438 4 0
+6165 0 1
+1768 1 0
+7727 2 0
+1514 0 1
+3116 0 1
+3278 1 1
+21 1 1
+1738 0 1
+8576 19 0
+1877 15 15
+6128 1 0
+2049 1 0
+518 13 11
+1704 1 1
+117 1 1
+1448 10 0
+1521 0 4
+2878 9 9
+2265 1 0
+25400 9 9
+4420 1 1
+32 1 1
+2539 1 0
+18012 1 1
+42 1 1
+2651 0 3
+2544 0 318
+1507 1 0
+313 4 0
+2659 1 1
+25 1 1
+1461 4 1
+1402 0 1
+3961 0 3
+58 1 1
+112 1 1
+1419 1 1
+34 0 1
+2697 0 2
+40 1 1
+2168 0 1
+1019 0 2
+1099 0 4
+40 1 1
+1374 11 0
+31 1 1
+189 1 1
+26 1 1
+327 1 1
+38 1 1
+177 11 11
+303 1 1
+34 1 1
+5868 17 17
+2864 0 143
+4107 0 4
+752 0 2
+10360 0 1
+37 1 1
+11851 0 2
+5376 0 1
+19253 0 6
+7878 1 0
+21 0 6
+4451 1 0
+27910 1 0
+9946 0 1
+11233 1 1
+32 1 1
+366 1 1
+38 1 1
+1832 1 1
+20 1 1
+3659 22 16
+1218 1 0
+1638 6 6
+228 1 1
+45 1 1
+2048 0 2
+462 1 0
+20759 1 0
+3778 2 1
+1268 1 0
+1511 1 1
+42 2 0
+24 1 1
+4119 22 0
+1757 1 0
+1527 1 1
+29 1 1
+1886 1 0
+6666 0 4
+2358 1 1
+23 1 1
+1549 12 0
+36 12 0
+484 1 1
+31 1 1
+549 3 0
+5745 1 0
+19358 0 3
+12224 1 0
+34 1 1
+3228 11 16
+250 1 1
+17 1 1
+1482 0 1
+1280 1 0
+103 1 1
+29 1 1
+68 4 4
+1493 1 1
+49 1 1
+102 4 0
+287 1 1
+21 3 0
+273 1 1
+43 9 1
+667 0 8
+138 1 1
+20 1 1
+255 0 2
+67 1 1
+33 1 1
+62 1 0
+118 0 5
+313 0 3
+2354 0 28
+1203 0 3
+3975 1 1
+44 1 1
+4899 3 0
+2101 2 0
+363 1 1
+49 1 1
+1639 0 30
+248 46 46
+1068 4 1
+85 1 0
+357 3 4
+5288 0 9
+2728 1 5
+722 0 1
+502 0 1
+1025 0 1
+134 12 0
+4944 0 1
+319 1 0
+1314 5 6
+4858 0 1
+2923 1 3
+117 0 1
+1775 1 0
+2123 0 1
+2715 1 0
+4921 1 1
+17 1 1
+4273 1 0
+1233 0 8
+2134 0 1
+1042 0 1
+163 1 1
+45 1 1
+50 2 0
+64 1 1
+48 1 1
+379 0 3
+29 1 0
+30 1 1
+61 1 1
+22 1 1
+691 5 7
+310 1 1
+37 3 1
+225 1 1
+131 2 0
+36 1 1
+242 9 9
+697 33 33
+1202 1 1
+16 1 1
+528 1 1
+20 1 1
+509 0 5
+76 1 1
+21 1 1
+439 15 15
+2778 2 1
+1597 24 28
+59 12 12
+307 1 0
+516 1 0
+286 11 33
+339 5 0
+570 1 1
+37 1 1
+220 1 0
+72 1 1
+144 1 1
+48 1 1
+247 2 0
+174 9 10
+816 1 0
+940 1 1
+45 1 1
+91 3 3
+71 1 1
+291 14 14
+100 1 1
+23 1 1
+452 3 3
+85 1 1
+65 1 1
+77 1 1
+252 0 1
+129 15 15
+432 14 0
+85 1 1
+28 1 1
+189 2 1
+71 1 1
+52 8 0
+810 2 2
+63 1 1
+378 1 1
+26 1 1
+187 31 36
+966 1 1
+25 1 1
+72 1 1
+29 1 1
+125 1 1
+38 1 1
+433 2 0
+596 1 1
+48 1 1
+465 4 4
+64 1 1
+20 1 1
+525 5 5
+237 3 8
+99 31 31
+53 11 0
+364 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+67 16 16
+244 1 1
+54 5 5
+929 1 1
+21 1 1
+126 0 3
+830 1 11
+59 1 1
+537 0 2
+24 1 1
+745 15 15
+810 1 0
+425 1 1
+89 1 1
+592 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 1 1
+39 1 1
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+155 154 0
+34 1 1
+50 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+345 1 1
+39 1 1
+504 18 18
+596 12 12
+54 1 1
+158 1 1
+164 1 1
+34 1 1
+626 15 15
+866 0 10
+1051 0 2611
+680 0 1
+1537 0 18
+75 1 0
+145 60 0
+122 0 12
+23 1 1
+1927 13 13
+1702 2 0
+3694 1 1
+18 1 1
+958 43 47
+246 2 0
+146 1 1
+49 1 1
+410 1 0
+667 1 1
+38 1 1
+362 7 1
+159 3 0
+515 2 0
+1026 1 1
+29 1 1
+249 0 6
+129 1 1
+33 4 0
+9 0 6
+1236 1 1
+20 1 1
+138 10 9
+448 0 3
+660 1 1
+28 1 1
+83 1 1
+51 1 1
+2659 1 1
+38 1 1
+424 0 1
+70 1 1
+820 1 1
+26 1 1
+1472 1 1
+21 1 1
+491 5 5
+163 15 15
+2194 2 0
+533 6 0
+441 1 7
+1689 1 1
+26 3 4
+879 16 16
+75 10 10
+429 0 2
+58 1 1
+350 1 0
+769 1 1
+39 1 1
+573 0 4
+37 1 1
+144 8 8
+1036 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+169 147 153
+1254 0 2
+332 1 1
+21 1 1
+193 8 24
+34 1 1
+79 1 1
+29 1 1
+536 1 0
+308 0 1
+850 0 32
+23 1 1
+651 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 1
+714 7 7
+89 1 0
+293 9 8
+125 1 1
+31 1 1
+192 6 6
+171 17 17
+681 1 1
+43 1 1
+514 1 1
+68 1 1
+537 1 1
+35 1 1
+159 6 6
+179 1 1
+37 1 1
+560 17 17
+198 0 7
+105 1 1
+40 1 1
+95 13 13
+247 1 1
+19 1 1
+2044 7 8
+2512 0 15
+2982 4 0
+342 41 41
+2752 1 2
+1698 13 13
+4264 0 4
+12512 105 53
+7 0 5
+29 5 129
+49 1 1
+7717 1 1
+40 1 1
+4564 1 1
+45 1 1
+2289 1 1
+41 1 1
+1994 0 1
+733 1 1
+37 1 1
+5170 1 1
+22 1 1
+718 0 3
+828 0 8
+2128 11 11
+5142 0 1
+4144 18 0
+8 1 1
+4824 12 12
+727 6 16
+1705 4 0
+3265 0 2
+2235 18 16
+2946 0 372
+2644 31 31
+3991 40 40
+559 1 1
+28 1 1
+129 0 4
+787 1 1
+34 1 1
+927 4 4
+123 0 4
+6 1 1
+2353 0 1
+331 1 1
+27 1 1
+633 1 1
+31 1 1
+1147 1 0
+1507 1 1
+44 1 1
+166 1 1
+41 3 1
+1022 34253 40039
+275 1 1
+38 1 1
+1307 1 1
+26 1 1
+1467 1 1
+27 1 1
+568 11 11
+693 1 1
+26 1 1
+297 11 11
+183 1 1
+40 1 1
+589 1 1
+26 1 1
+838 1 1
+44 0 1
+877 1 1
+39 1 1
+347 1 1
+36 1 1
+1288 10 10
+731 2 1
+75 3 3
+91 171 171
+553 1 1
+61 1 1
+70 1 1
+53 0 2
+315 1 1
+29 1 1
+581 1 1
+82 1 1
+605 9 9
+691 2 2
+72 1 1
+55 1 1
+45 1 1
+196 4 4
+123 0 1
+40 1 1
+183 23 23
+183 1 1
+67 1 1
+304 1 1
+108 1 1
+165 1 1
+72 1 1
+167 1 1
+59 0 1
+10 3 1
+21 82 2
+58 0 2
+69 1 1
+25 1 1
+57 2 1
+107 2 2
+93 1 1
+194 0 3
+120 7 4
+431 1 1
+78 1 1
+84 0 1
+74 1 1
+52 13 13
+158 5 7
+434 0 1
+295 16 16
+290 1 1
+26 1 1
+373 1 1
+46 1 1
+94 1 1
+81 1 1
+109 4 0
+61 2 2
+80 1 1
+47 1 1
+168 1 1
+31 1 1
+269 2 2
+42 1 1
+322 2 2
+36 1 1
+265 2 2
+14 1 1
+76 7762 9566
+315 55 55
+67 36167 30035
+308 1 1
+49 1 1
+219 0 1
+87 7 5
+223 10 8
+235 11 11
+772 0 2
+187 2 1
+1058 0 2
+349 0 1
+264 1 1
+43 1 1
+781 3 1
+55 0 2
+13 0 4
+1077 1 1
+48 1 1
+62 1 1
+27 1 1
+1270 1 1
+44 1 1
+2070 3 1
+27 1 7
+251 1 1
+40 1 1
+130 1 1
+41 4 4
+478 1 1
+30 1 1
+162 11 11
+209 10 0
+150 1 1
+36 0 2
+31 1 1
+55 1 1
+51 1 1
+221 8 13
+418 1 1
+26 1 1
+386 3 0
+549 1 1
+76 1 1
+67 1 1
+25 3 3
+777 1 1
+17 1 1
+970 3 8
+714 1 1
+25 1 1
+192 1 1
+236 1 1
+524 0 12
+51 10 9
+664 1 1
+29 1 1
+62 1 1
+50 2 0
+119 1 1
+10 0 2
+19 4 6
+117 1 1
+69 1 1
+731 1 0
+3768 9 1
+1328 0 1
+6188 1 1
+43 1 1
+7157 4 0
+2168 1 0
+10374 19 0
+742 2 3
+4846 0 1
+3203 1 0
+2662 1 1
+27 1 1
+3920 1 1
+47 1 1
+2081 1 0
+377 1 0
+172 0 1
+5189 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3902 17 4
+310 0 5
+2762 0 10
+201 2 0
+345 1 0
+594 0 2
+1043 10 0
+1426 0 9
+17 1 1
+265 0 1
+6069 0 3
+2963 0 3
+168 0 3
+194 2 1
+4260 1 0
+19508 0 1
+1762 0 3
+4356 0 4
+401 1 0
+1148 1 1
+28 0 11
+847 0 1
+1133 0 1
+1143 1 1
+20 1 1
+1533 0 8
+128 0 4
+2963 0 1
+25 1 1
+5336 1 0
+322 6 6
+196 1 1
+20 1 1
+151 3 3
+87 1 1
+246 1 7
+368 1 1
+26 1 1
+1049 0 1
+1002 0 1
+7912 4 0
+3532 50004 0
+1445 0 1
+10485 1 1
+48 1 1
+724 1 1
+51 5 0
+39 1 1
+22385 0 1
+4385 0 7
+881 0 12
+11532 13 12
+409 0 1
+3492 0 2
+2158 0 25
+109 1 1
+3284 0 19
+2586 2 0
+757 1 1
+22 1 1
+860 29 24
+1584 1 0
+1598 1 2
+1653 3 25
+17 0 4
+16 2 0
+6 10 0
+40 1 0
+10 6 0
+6448 0 1
+2513 0 1
+576 16 16
+103 1 0
+198 1 3
+539 1 1
+47 1 1
+158 2 0
+996 0 1
+3736 1 3
+371 1 3
+1174 1 1
+56 1 1
+69 0 1
+518 6 0
+646 13 13
+469 1 0
+1072 1 4
+911 1 1
+16 1 1
+3603 1 0
+282 1 0
+597 0 6
+496 13 13
+183 1 1
+43 1 1
+1294 1 1
+40 1 1
+572 0 5
+463 0 4
+1886 1 0
+548 1 0
+1300 0 3
+1839 2 0
+189 1 1
+49 1 1
+1253 1 1
+43 1 0
+498 1 1
+45 4 0
+3538 0 1
+1582 31 31
+376 14 14
+867 3 4
+253 1 1
+34 1 1
+172 2 0
+1094 0 1
+281 1 1
+49 1 1
+397 1 1
+43 1 1
+1082 1 1
+26 1 1
+1030 1 1
+24 0 419
+125 2 0
+709 1 1
+36 1 1
+393 1 1
+21 1 1
+1773 16 17
+181 12 12
+98 1 4
+6 1 0
+53 1 1
+94 1 1
+49 1 1
+1495 10 0
+623 13 13
+163 1 1
+45 1 1
+2050 11 11
+2452 1 1
+42 1 0
+35 1 1
+751 1 0
+287 1 1
+60 1 1
+446 0 4
+2620 8 7
+1442 5 5
+153 1 0
+514 2 0
+3349 1 1
+23 0 1
+12 1 1
+296 8 9
+291 1 1
+21 1 0
+245 2 2
+24 1 1
+150 1 1
+46 1 1
+325 1 1
+38 1 1
+52 6 9
+154 1 1
+42 1 1
+942 1 1
+36 1 1
+5168 0 3
+2172 1 0
+1740 0 8
+4919 1 0
+1388 4 0
+310 0 9
+370 22 0
+503 0 3
+6750 8 0
+419 2 0
+945 0 4
+3485 5 1
+789 0 1
+1882 45 44
+1047 1 1
+60 1 1
+2432 0 15
+16 1 1
+5898 0 1
+2260 1 0
+2629 0 5
+55 1 1
+28 1 1
+1978 1 0
+374 0 5
+7713 1 0
+1229 1 0
+708 2 0
+84 5 0
+2071 1 1
+23 1 0
+174 5 0
+1776 0 9
+15 6 11
+4007 1 0
+2414 12 10
+2056 0 1
+955 4 0
+9566 1 0
+1267 2 0
+1646 2 2
+30 1 1
+4770 7 6
+150 14 14
+9365 0 2
+5358 0 1
+4837 1 0
+6701 4 0
+66771 0 2
+54634 0 2
+8292 0 4
+7941 0 8
+7495 1 0
+5591 4 0
+4127 1 0
+473 1 0
+6435 1 0
+53744 1 0
+6522 0 1
+48591 18 23
+4935 29 0
+40465 0 1
+12538 0 1
+24928 8701 8701
+6291 0 10
+15586 2 1
+56398 4 0
+5858 1 0
+5972 0 2
+2081 0 1
+12533 1 0
+25305 0 1
+2237 0 2
+18999 0 4
+13824 0 2
+11096 2 0
+10773 0 1
+804 1 0
+5431 31 34
+598 1 1
+22 1 1
+2240 24813 24813
+1765 0 4
+4845 0 3
+448 1 1
+22 1 1
+2215 1 1
+32 1 1
+2413 14 14
+142 1 0
+789 1 1
+45 1 1
+154 1 1
+25 1 1
+465 1 1
+45 6 4
+541 1 1
+42 1 1
+1339 5 6
+391 1 1
+20 0 1
+251 1 1
+22 1 1
+561 0 2
+78 3 0
+1718 1 1
+12 1 1
+1042 1 1
+38 0 1
+301 14 0
+222 10 10
+436 10 10
+1564 1 1
+17 1 1
+1752 5 0
+1561 135 0
+58 0 45
+212 90 0
+42 2 2
+43 1 1
+152 0 270
+54 180 0
+2130 12 12
+1630 1 1
+26 1 1
+189 0 14
+296 2 0
+809 2 0
+17 16 0
+665 0 40
+236 1 1
+44 1 1
+352 1 1
+25 1 1
+316 14442 14257
+51 2 0
+58 1 1
+107 1 1
+150 14 14
+522 1 1
+28 1 1
+945 4 4
+34 1 1
+472 0 2
+203 0 1
+281 1 1
+46 1 1
+1130 1 0
+232 17 17
+510 1 1
+33 1 1
+62 10 10
+1501 1 1
+20 1 1
+573 1 1
+29 1 1
+928 0 3
+304 1 1
+41 1 1
+160 1 1
+58 1 1
+656 1 1
+40 4 0
+108 6 6
+321 1 1
+14 0 16
+91 1 1
+184 1 1
+43 8 3
+180 1 1
+68 1 1
+144 1 1
+27 1 0
+17 1 1
+212 0 1
+212 1 1
+34 1 1
+115 1 1
+41 1 1
+407 10 10
+200 1 1
+44 2 0
+187 3 0
+146 1 1
+17 1 1
+122 4 4
+73 1 0
+56 1 1
+155 1 17
+80 15 15
+458 1 1
+16 3 3
+343 1 1
+111 1 1
+201 14 14
+157 12 12
+346 0 2
+382 4 0
+35 1 1
+937 0 1
+246 25 0
+52 0 1
+419 0 1
+165 1 0
+75 24 3
+297 1 1
+38 1 1
+271 1 1
+33 1 1
+4777 4 2
+43 3 0
+1254 0 1
+16 1 1
+1411 0 4
+424 1 1
+51 1 1
+113 1 1
+34 1 1
+344 9 9
+15845 1 0
+2814 1 5
+2389 0 4
+3883 0 1
+10926 0 4
+17866 4 10
+744 1 0
+564 2 0
+16701 3 0
+7721 11 0
+1411 1 1
+49 1 1
+146 1 1
+61 1 1
+116 1 1
+41 1 1
+137 1 1
+30 1 1
+158 9 9
+136 10 13
+973 6 6
+547 1 1
+41 1 1
+164 17 17
+137 1 1
+68 1 1
+846 4 4
+228 1 1
+34 1 1
+355 1 1
+113 1 1
+330 0 1
+222 1 1
+25 1 1
+267 1 1
+38 1 1
+716 2 0
+23 1 1
+1417 0 1
+152 1 1
+46 1 1
+237 1 1
+20 1 1
+211 5 5
+88 1 1
+33 1 1
+211 1 1
+65 1 1
+516 58 58
+491 7 7
+208 13 12
+558 2 2
+28 1 1
+125 4 4
+1853 12 0
+845 6 6
+2005 0 1
+148 1 1
+36 1 1
+993 1 0
+3580 10 10
+1203 1 0
+530 5 5
+216 1 1
+32 1 1
+312 1 1
+44 1 1
+1934 14 14
+1149 0 8
+835 1 1
+29 0 2
+2323 1 1
+18 1 1
+1273 27 27
+104 1 1
+21 1 1
+1520 1 1
+23 1 1
+147 1 1
+16 1 1
+429 8 16
+1419 23 23
+256 1 0
+39 1 2
+106 1 1
+21 1 1
+501 2 2
+40 1 1
+2249 1 1
+19 1 1
+86 1 1
+82 0 1
+180 14 1
+1272 17 17
+345 0 2
+1504 14 0
+1689 4 0
+3174 16 16
+607 4 34
+41 0 5
+669 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+466 1 1
+31 3 0
+321 0 1
+281 3 0
+450 1 1
+34 1 1
+498 1 1
+28 2 1
+280 0 1
+649 1 1
+47 1 1
+1002 4 0
+120 1 1
+533 7 7
+998 0 1
+75 1 1
+37 1 1
+473 1 0
+44 1 1
+64 19 19
+60 18 18
+2075 1 1
+51 1 1
+779 0 1
+1286 0 2
+271 1 1
+57 1 1
+129 4 0
+87 1 1
+160 1 1
+49 1 1
+147 18 14
+128 4 4
+34 1 1
+865 4 0
+160 1 1
+35 1 1
+1119 1 1
+13 0 3
+242 1 1
+23 1 1
+1705 0 4
+103 0 1
+1117 2 0
+67 1 1
+1825 0 1
+855 8 0
+1368 3 0
+320 1 1
+19 1 1
+100 1 1
+28 1 1
+97 1 1
+15 1 1
+442 1 1
+189 0 2
+5 1 1
+1520 1 1
+28 1 1
+367 4 0
+267 13 13
+175 1 0
+225 1 1
+45 1 1
+859 1 1
+80 2 0
+38 0 2
+318 8 7
+50 1 1
+29 1 1
+376 4 9
+548 1 1
+57 1 1
+665 4 0
+146 30562 30549
+225 2 2
+49 1 1
+129 1 1
+20 1 1
+757 9 9
+151 1 1
+49 1 1
+282 0 2
+128 0 1
+174 15 18
+175 1 1
+16 1 1
+332 1 1
+22 1 1
+554 0 1
+120 1 1
+31 1 1
+351 5 0
+80 1 0
+76 1 1
+39 1 1
+1447 1 0
+1072 1 1
+43 0 4
+43 1 1
+393 0 1
+1820 6 6
+457 1 1
+18 1 1
+87 1 1
+30 1 1
+861 1 1
+20 1 1
+1057 23 23
+416 0 16
+787 1 1
+17 1 2
+37 1 1
+1675 1 1
+27 1 1
+901 0 8
+47 1 1
+274 0 3
+75 0 1
+234 0 3
+45 1 1
+250 1 1
+18 1 1
+517 33 0
+117 1 1
+55 1 1
+537 1 1
+20 1 1
+671 1 1
+68 1 1
+89 1 1
+104 1 1
+172 0 1
+124 0 1
+522 0 1500
+466 5 5
+32 1 0
+171 1 1
+19 1 1
+67 1 1
+22 1 1
+654 1 1
+25 1 1
+68 1 1
+21 4 0
+1588 1 1
+66 1 1
+401 0 1
+186 1 1
+21 1 1
+168 0 1
+601 1 1
+29 1 1
+36 4 0
+37 1 1
+127 1 1
+29 1 1
+404 0 2
+710 1 1
+89 1 1
+161 16 16
+405 1 1
+39 3 3
+56 1 1
+192 0 4
+104 1 1
+89 1 1
+64 1 1
+102 1 1
+130 15 16
+158 8 0
+57 1 1
+731 1 1
+57 1 1
+321 1 1
+44 3 0
+52 19987 20030
+60 8 8
+133 1 1
+48 1 1
+287 1 1
+24 1 1
+1273 1 1
+24 1 1
+86 1 1
+76 1 0
+20 1 1
+112 1 1
+149 1 1
+284 1 1
+37 1 1
+559 10 10
+136 1 12
+106 12 12
+3153 1 1
+34 1 1
+453 1 1
+63 1 1
+645 0 2
+50 1 0
+712 1 1
+35 1 1
+158 1 1
+52 1 1
+123 1 1
+45 0 1
+32 1 1
+253 1 1
+48 1 1
+101 16 16
+64 1 1
+124 1 1
+1429 13 13
+196 0 1
+1629 1 1
+39 0 1
+30 1 1
+514 1 1
+32 0 3
+3600 1 13
+1047 1 1
+43 1 1
+55 14 14
+853 12 12
+2313 13 13
+537 6 0
+1430 1 1
+48 1 1
+400 1 1
+100 1 1
+148 19 19
+152 1 1
+25 1 1
+70 1 1
+102 1 1
+158 1 1
+56 2 2
+57 1 1
+10 5 10
+24 2 0
+71 1 1
+54 1 1
+73 1 1
+85 1 1
+105 1 1
+117 2 2
+29 1 1
+92 2 2
+42 0 1
+154 1 1
+10 1 0
+47 4 5
+35 1 1
+56 1 1
+64 3 3
+67 5 5
+72 1 1
+60 1 1
+45 1 1
+82 1 1
+95 2 2
+161 1 1
+301 1 1
+67 1 0
+430 1 1
+105 10 10
+38 0 4
+386 11 11
+101 3 2
+117 0 2
+77 1 1
+481 0 1
+68 1 1
+81 1 1
+467 1 1
+34 1 1
+359 1 1
+35 1 1
+2283 1 1
+26 1 1
+506 19 0
+51 0 1
+166 1 1
+65 1 0
+211 0 17
+410 3 0
+622 0 1
+143 1 1
+22 1 1
+150 2 2
+49 1 1
+312 1 1
+16 1 1
+715 1 1
+24 1 1
+896 1 1
+33 1 1
+308 22 28
+78 1 1
+144 1 1
+733 0 1
+212 1 1
+40 1 1
+1233 1 1
+48 1 1
+741 49699 50070
+885 1 1
+113 1 1
+141 2 0
+842 1 0
+1507 1 1
+40 1 1
+279 0 1
+724 1 1
+15 1 1
+252 1 1
+29 2 0
+229 1 1
+50 3 3
+221 7 7
+216 1 1
+36 5 5
+64 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+195 1 1
+46 1 1
+245 0 4
+70 1 1
+62 4 1
+43 1 1
+153 1 1
+93 1 1
+85 1 1
+68 5 0
+47 2 2
+291 1 0
+42 1 1
+341 13 13
+262 4 4
+67 1 1
+32 1 0
+28 1 1
+612 1 1
+123 1 1
+112 1 1
+19 1 4
+61 1 2
+136 1 1
+83 1 1
+78 1 1
+61 288 288
+119 1 1
+158 1 1
+146 1 1
+28 1 1
+372 1 1
+18 0 4
+44 1 1
+120 7 7
+73 1 4
+42 1 1
+52 1 1
+24 1 1
+143 1 1
+34 1 1
+376 1 1
+26 1 1
+243 1 1
+41 1 1
+53 1 1
+35 5 5
+101 1 1
+20 1 1
+114 1 1
+43 1 1
+184 4 8
+650 23 23
+192 1 1
+44 1 0
+103 1 1
+202 2 2
+33 1 1
+51 1 1
+26 1 1
+277 3 0
+19 1 1
+263 2 2
+49 1 1
+63 1 1
+200 1 1
+320 4 12
+10 2 0
+11 8 1
+26 1 1
+86 13 13
+15 1 1
+3255 1 1
+52 1 1
+159 1 1
+88 1 0
+118 1 1
+172 1 1
+26 1 1
+69 1 1
+95 1 1
+124 1 1
+30 1 1
+216 41 41
+51 5 5
+123 1 1
+53 1 1
+110 1 1
+307 1 1
+101 1 1
+53 15 15
+127 2 2
+65 1 1
+553 1 1
+45 1 1
+52 0 1
+99 4 4
+1538 1 1
+31 1 1
+930 7 3
+472 13 13
+606 1 1
+38 1 1
+230 10 0
+30 6 0
+35 0 22
+168 1 1
+55 1 1
+309 2 3
+58 1 1
+44 1 1
+333 1 1
+81 3 3
+77 1 1
+140 1 1
+136 1 1
+40 5 5
+160 1 1
+21 5 5
+253 1 1
+37 1 1
+104 3 0
+867 14 15
+178 1 1
+94 1 1
+254 0 1
+101 0 5
+17 1 1
+528 1 1
+42 1 1
+261 1 1
+19 3 3
+83 10 10
+114 1 1
+194 1 1
+19 1 1
+286 1 1
+38 1 1
+295 0 4
+35 10 0
+205 0 2
+29 1 1
+178 1 1
+31 1 1
+57 1 1
+76 1 1
+228 1 1
+28 1 1
+101 1 1
+109 0 1
+93 0 2
+46 1 1
+109 1 1
+33 1 1
+932 12 12
+1047 1 1
+26 1 1
+699 0 8
+35 1 1
+472 1 1
+43 1 1
+242 1 1
+28 1 1
+385 1 1
+91 1 1
+805 0 2
+4744 3 2
+1144 0 1
+1453 0 1
+934 1 1
+28 3 7
+155 0 1
+840 18 18
+346 1 1
+25 1 1
+1020 2 0
+260 1 1
+26 1 1
+357 1 1
+44 1 1
+639 1 1
+26 1 1
+3965 1 1
+40 1 1
+194 1 0
+279 1 1
+18 1 1
+277 0 2
+1883 0 1
+31 1 1
+1925 1 0
+2650 16 16
+2463 117 0
+67 8 17
+77 0 2
+55 17 17
+60 24 0
+126 0 64
+26 0 7
+19 0 7
+38 18 0
+40 40 0
+49 0 124
+32 15 8
+22 43 4
+36 1 614
+68 1 1
+7 0 2
+17 2 0
+7 0 2
+17 2 0
+20 0 2
+76 41 13
+71 60 21
+122 0 73
+72 28 0
+117 11 35
+24 13 0
+56 19 0
+3413 6 0
+9102 0 1
+87 0 2
+2219 0 1
+85 1 1
+31 0 4
+399 14 14
+408 0 1
+148 0 1
+807 1 1
+28 1 0
+452 4 0
+499 1 1
+25 1 1
+1037 1 0
+1066 1 1
+102 1 1
+1111 1 1
+47 1 1
+291 1 1
+49 1 1
+1195 1 1
+46 1 1
+370 1 1
+56 1 1
+142 1 1
+54 1 1
+538 0 1
+46 1 2890
+74 9 97
+1161 0 1
+1161 1 1
+23 1 1
+189 1 1
+43 1 1
+855 1 0
+353 8 0
+751 42950 42933
+383 0 4
+40 1 1
+3304 1 1
+46 1 1
+282 1 1
+39 1 1
+698 1 1
+20 1 1
+140 1 1
+26 1 1
+745 0 2
+2081 1 0
+817 4 4
+206 1 1
+44 1 1
+168 1 1
+20 1 1
+164 1 0
+21 1 1
+648 1 0
+912 6 0
+55 0 1
+1116 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+16 1 4
+1404 0 1
+450 4 0
+612 15 14
+304 1 1
+39 1 1
+564 1 1
+45 1 1
+303 2 0
+409 1 1
+18 1 0
+858 2 0
+2168 0 1
+54 22 22
+524 0 1
+523 0 12
+2424 18 14
+64 1 1
+31 1 1
+185 0 4
+657 10 10
+980 1 1
+20 1 1
+227 1 1
+37 1 1
+636 3 4
+3780 0 1
+4458 1 1
+23 1 1
+1114 1 3
+696 16 32
+861 18 18
+4781 0 4
+815 0 1
+9910 0 1
+10538 0 6
+25675 0 6
+10912 9 10
+824 0 1
+1450 11 0
+403 0 1
+154 1 1
+34 1 1
+146 1 0
+26 1 1
+2361 0 2
+775 8460 8460
+474 0 1
+1838 0 3
+2049 3 0
+14940 0 1
+398 17 17
+3797 0 4
+1305 10 0
+15047 1 0
+20201 1 0
+3812 0 1
+11605 0 1
+4121 2 0
+7755 1 0
+2661 3 1
+138 1 0
+2776 0 2
+4108 0 4
+8944 1 0
+10910 4 0
+1616 0 1
+1645 4 5
+36 0 2
+2223 0 16
+4729 10 0
+1921 0 1
+913 0 1
+2531 89346 89346
+3450 17 17
+3339 0 1
+3130 0 1
+2106 1 1
+42 1 1
+382 1 0
+616 178 0
+9555 52932 52932
+383 0 1
+2529 19 19
+10441 0 1
+24 1 1
+246 0 4
+1724 1 1
+37 1 1
+141 11 11
+103 1 128
+292 1 1
+20 1 1
+67 0 117
+30 1 1
+2771 0 3
+1487 0 3
+251 1 0
+1263 18 12
+888 1 1
+20 1 1
+2423 10 0
+1337 10 10
+6619 2 0
+982 113131 113131
+3241 16 0
+10939 12 0
+2143 0 1
+8355 0 3
+4114 0 1
+1404 0 1
+5850 1 0
+1691 38609 38609
+338 6 6
+2331 0 1
+2149 1 0
+10496 17 35
+3831 1 0
+8737 0 3
+16043 29 29
+1283 0 3
+8057 1 1
+63 1 1
+6053 5 0
+4539 43 43
+1259 2 0
+1628 5 5
+448 0 1
+374 0 1
+3431 1 0
+3049 32 0
+147 0 1
+1181 10 15
+206 3 4
+613 0 1
+1815 1 1
+18 1 1
+3726 0 3
+34 1 1
+361 17 17
+1252 0 3
+1642 1 0
+374 1 1
+19 1 1
+316 1 0
+13 2 0
+712 12 12
+204 1 1
+60 1 1
+843 1 3
+705 7 7
+72 1 1
+29 0 2
+332 0 1
+136 1 1
+1071 3 0
+548 1 1
+45 3 0
+121 1 1
+24 1 1
+262 16 16
+846 0 4
+412 0 2
+644 0 1
+26 1 1
+75 1 1
+32 1 1
+247 0 1
+174 1 2
+77 3 0
+113 0 1
+79 44 44
+186 0 14
+80 1 1
+813 0 9
+465 1 1
+60 1 1
+217 0 2
+400 0 3
+367 1 1
+37 1 1
+245 1 1
+25 1 1
+469 0 8
+857 17 18
+278 0 1
+1507 3 0
+1681 0 2
+429 4 0
+148 17 5
+278 4362 4362
+3670 16 16
+108 1 2
+197 1 1
+20 1 1
+367 20 19
+488 0 4
+1457 2 1
+205 5 5
+11 1 1
+213 20 15
+1190 30 0
+35 1 1
+1742 1 0
+123 1 0
+4678 0 2
+5739 0 1
+1167 0 1
+1767 1 0
+253 15 15
+5582 1 21
+8987 1 0
+2138 3 2
+2203 2 1
+5654 1 1
+24 3 3
+3229 0 1
+3385 4 4
+6989 1 0
+1294 4 0
+9088 2 3
+2270 1 1
+32 1 1
+6293 1 1
+26 1 1
+2668 4 0
+7792 1 0
+7099 2 0
+1639 1 0
+13217 0 2
+6668 0 2
+2319 1 0
+1034 0 6
+430 1 0
+1276 1 1
+27 1 1
+142 3 3
+35 1 1
+1211 1 1
+34 1 1
+664 0 10
+59 1 1
+78 1 1
+1519 1 1
+27 1 1
+154 14 14
+2525 0 4
+79 1 1
+145 1 1
+63 1 1
+70 1 1
+21 1 1
+695 1 1
+41 2 2
+564 1 1
+46 1 1
+279 4 0
+38 5 5
+201 22 22
+1020 1 1
+25 1 1
+2253 32 32
+545 1 1
+27 1 0
+54 15 16
+363 0 1
+845 0 2
+60 7 0
+787 2 0
+3691 1 0
+1843 1 1
+45 1 0
+11 1 2
+3499 1 1
+27 1 1
+970 0 1
+76 0 2
+1804 2 0
+1079 1 1
+17 1 1
+639 3 5
+73 1 1
+13 13 0
+66 1 1
+96 0 1
+294 14 0
+4554 0 1
+53 9 6
+691 0 1
+989 1 1
+143 1 1
+223 0 2
+95 1 1
+1136 1 1
+49 1 1
+606 1 1
+48 1 1
+128 0 4
+109 1 31
+44 10 781
+62 4 0
+129 1 1
+62 1 1
+106 1 1
+268 18 4
+125 1 1
+43 1 1
+909 0 2
+381 4 4
+74 1 1
+408 1 0
+1011 8 0
+8833 1 1
+23 6 19
+6628 1 1
+28 1 1
+4872 20 20
+692 1 0
+2650 0 4
+194 0 1
+596 5 6
+1359 0 1
+1572 7 7
+299 1 1
+49 1 1
+803 1 1
+93 1 1
+797 14 14
+433 8 0
+108 11 11
+140 1 1
+40 1 1
+470 1 1
+42 1 1
+1192 4 4
+129 1 1
+123 2 0
+95 1 1
+82 3 0
+664 1 1
+77 1 1
+57 1 1
+62 1 1
+473 2 0
+262 6 0
+45 1 1
+63 2 0
+39 1 1
+267 0 1
+197 2 104
+87 111 0
+122 0 7
+88 0 4
+86 1 1
+21 6 0
+563 14 14
+324 1 0
+205 1 1
+17 1 1
+426 17 17
+52 0 1
+201 4 0
+14 1 1
+1080 1 1
+24 1 1
+91 24 24
+279 9 8
+55 1 1
+32 1 1
+121 1 1
+62 1 1
+80 1 1
+72 1 1
+2217 2 0
+820 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+1780 2 0
+742 1 1
+40 1 1
+272 1 1
+52 1 1
+1187 1 1
+23 1 1
+254 1 1
+60 1 1
+176 3 6
+463 1 1
+36 1 1
+797 1 1
+22 1 1
+395 5 2
+61 1 1
+31 3 3
+226 1 1
+59 1 1
+581 1 1
+46 1 1
+412 1 1
+23 1 0
+174 1 1
+24 1 1
+83 15 15
+363 1 1
+91 1 1
+383 20 20
+90 1 1
+44 1 1
+63 13 13
+976 1 1
+29 1 0
+10 0 3
+161 14 15
+127 16 16
+517 1 1
+81 1 1
+218 28 28
+124 1 1
+68 0 22
+399 7 7
+668 0 1
+175 1 0
+1018 1 1
+90 4 4
+1034 15 15
+69 1 1
+33 1 1
+174 1 1
+56 1 1
+169 1 0
+201 1 1
+30 1 1
+58 1 1
+38 1 1
+91 1 1
+98 4 4
+65 1 1
+19 2 0
+104 6 5
+25 1 1
+218 1 1
+37 1 1
+343 264243 150023
+66 8 8
+36 0 11
+62 1 1
+107 1 1
+68 3 130
+66 4 4
+50 21 21
+98 1 1
+127 1 0
+192 1 1
+71 1 1
+52 1 1
+200 1 1
+97 4 4
+85 5 5
+448 1 1
+97 11 11
+171 1 1
+61 1 1
+37 1 1
+156 3 0
+63 0 3
+155 3 0
+32 2 0
+232 1 1
+33 1 1
+175 2 0
+131 6 6
+1409 0 3
+222 1 1
+23 0 1
+1470 1 1
+21 1 1
+460 1 1
+71 1 1
+394 2 8
+37 1 1
+90 1 1
+43 1 1
+650 1 1
+34 1 1
+839 0 1
+431 1 1
+36 1 1
+284 51277 50054
+255 1 1
+80 5 5
+71 1 1
+48 3 3
+65 1 1
+83 1 1
+292 1 1
+33 1 1
+421 1 1
+74 1 0
+151 8 0
+65 1 1
+70 0 2
+58 0 8
+157 1 1
+64 1 1
+66 2 1
+97 1 1
+54 1 1
+46 0 1
+20 1 1
+210 16 16
+270 1 1
+46 1 1
+202 1 1
+22 1 1
+309 1 1
+25 0 1
+174 10 10
+305 1 1
+40 1 1
+75 32 30
+150 1 0
+17 1 1
+69 2 2
+27 1 1
+38 6 0
+49 5 3
+255 1 1
+43 1 1
+90 1 1
+74 1 1
+364 1 1
+23 3 3
+69 1 1
+22 2 0
+78 1 1
+29 1 0
+96 1 1
+56 8 0
+87 5 10
+85 2 2
+39 1 1
+87 314 0
+364 1 1
+64 1 1
+201 0 4
+42 0 1
+56 5 9
+62 0 5
+45 1 1
+109 25 25
+314 1 2
+16 0 2
+45 1 1
+103 17 17
+84 8 8
+294 17 17
+527 10 10
+435 4 0
+91 0 4
+387 10 10
+312 1 1
+43 1 1
+181 1 0
+1737 2 3
+50 1 1
+140 1 1
+33 1 0
+113 7 7
+353 6 6
+794 8 8
+510 1 1
+18 1 1
+124 1 1
+19 8 4
+76 1 0
+880 1 1
+16 1 1
+491 1 1
+49 1 1
+239 1 1
+7 0 1
+67 1 1
+114 0 25
+26 1 1
+183 13 13
+72 1 1
+26 1 0
+42 1 1
+222 14 14
+320 1 1
+55 1 1
+414 6 5
+1003 1 1
+20 0 8
+849 1 1
+29 1 1
+978 29539 30058
+159 1 1
+36 1 1
+107 1 1
+176 1 1
+154 0 5
+91 1 1
+54 1 1
+77 1 1
+238 2 2
+50 1 1
+1421 1 1
+23 1 1
+216 1 1
+122 1 1
+86 1 1
+41 3 1
+336 7 7
+41 9 0
+107 1 1
+90 1 3
+6 1 0
+84 1 1
+213 1 1
+26 1 1
+138 1 1
+25 1 1
+206 1 1
+36 3 3
+37 7 0
+500 1 1
+52 1 1
+52 1 1
+48 1 1
+186 1 1
+66 1 1
+141 1 1
+66 6 6
+72 1 0
+69 1 1
+100 10 10
+160 1 0
+64 7 7
+89 1 1
+123 1 1
+128 1 1
+36 1 1
+231 1 1
+61 1 1
+564 8 8
+593 1 1
+45 1 1
+163 1 0
+196 8 8
+97 1 1
+118 1 1
+67 0 1
+192 1 1
+60 3 0
+19 1 1
+1149 1 1
+18 1 1
+77 1 1
+32 2 0
+32 1 1
+136 1 1
+78 2 0
+162 4 0
+41 1 1
+351 13 13
+1634 2 0
+229 8 8
+59 11 0
+410 1 1
+76 1 1
+180 1 1
+92 1 1
+270 1 1
+40 1 1
+92 1 1
+53 1 1
+227 1 1
+42 1 1
+357 4 4
+23 1 1
+94 1 0
+200 6 0
+201 7 7
+70 5 13
+57 4 0
+35 1 1
+206 1 1
+76 2 2
+651 1 1
+68 4 0
+73 1 1
+49 4 0
+37 1 1
+145 2 2
+78 2 2
+108 12 12
+52 1 1
+35 1 1
+242 1 3
+76 2 2
+50 12 12
+70 1 1
+33 0 2
+57 1 1
+64 15 15
+168 1 1
+22 1 1
+66 2 2
+6 0 1
+24 1 1
+73 0 2
+64 1 1
+177 2 0
+19 4 0
+55 1 0
+33 1 1
+51 1 1
+122 1 1
+296 1 1
+85 1 1
+109 1 1
+64 1 1
+155 1 1
+58 0 2
+72 1 1
+25 1 1
+128 1 1
+45 2 0
+334 4 4
+106 1 1
+25 1 1
+64 1 1
+21 1 1
+368 15 15
+734 2 0
+701 15 15
+71 1 1
+41 1 1
+77 1 1
+56 1 1
+478 2 0
+714 8 7
+95 2 2
+52 2 1
+1129 1 1
+34 1 1
+1715 1 1
+87 1 1
+692 1 1
+47 0 1
+75 1 1
+2155 10 10
+1265 1 1
+46 1 1
+298 1 1
+22 1 1
+186 1 1
+34 1 1
+202 1 1
+61 1 0
+185 1 1
+24 1 0
+98 0 2
+258 8 14
+967 1 1
+15 1 1
+625 1 0
+1362 0 4
+23365 4 0
+6220 3 0
+1351 18 18
+11498 8145 8145
+3307 0 1
+13671 3 3
+52 1 1
+1308 2 0
+942 0 1
+17790 1 0
+4586 0 1
+949 0 2
+15047 0 1
+606 3 0
+7820 0 4
+22313 6 0
+10539 12 0
+4836 0 1
+8726 2 0
+194 1 1
+49 1 1
+15889 3 0
+2693 0 2
+2787 56 56
+544 0 1
+2673 26 19
+3075 2 0
+4230 8 0
+879 0 1
+9534 0 4
+23 1 1
+599 0 1
+317 1 0
+2844 27 31
+571 2 0
+3158 0 4
+4455 2 0
+1609 0 7
+61 1 1
+66 1 1
+343 7 0
+25 1 1
+246 0 1
+15 1 1
+943 2 0
+136 8 7
+589 1 1
+84 1 1
+280 17 15
+680 15 15
+81 0 3
+1484 12 28
+1016 1 1
+45 1 0
+108 0 10
+675 4 0
+1568 0 1
+191 4 4
+1484 9 13
+3530 2 4
+2846 1 1
+17 1 1
+704 0 1
+4801 1 0
+1417 0 4
+50 3 0
+165 0 1
+4044 39283 39283
+854 1 1
+47 1 1
+479 1 0
+137 0 3
+1456 10 13
+63 1 1
+37 1 1
+261 0 2
+109 1 1
+50 1 1
+56 129 1
+88 1 0
+44 1 1
+54 1 1
+56 1 50
+58 50 1
+54 277 1
+44 1 1
+297 0 39
+142 1 1
+85 1 1
+124 16 16
+58 3 15
+677 1 0
+1333 2 0
+13591 6 0
+1050 1 1
+46 1 1
+678 1 1
+31 1 1
+2632 4 4
+37 1 1
+22341 32 30
+10811 1 1
+25 0 1
+129 62 62
+226 1 1
+40 1 1
+159 4 4
+37 4 4
+179 1 1
+51 1 1
+103 2 0
+108 1 1
+79 1 1
+25 1 1
+58 1 1
+12 1 1
+275 14 0
+80 1 1
+83 1 1
+24 1 1
+59 1 0
+91 1 1
+65 1 1
+67 1 1
+136 4 0
+68 8 0
+331 5 0
+40 1 1
+110 10 6
+64 1 1
+368 1 1
+22 1 1
+509 1 1
+89 1 1
+926 1 0
+959 1 1
+44 1 1
+72 11 0
+47 1 1
+361 1 1
+37 1 1
+2204 2 2
+45 1 1
+1117 18 18
+141 1 1
+47 1 1
+148 1 1
+75 1 1
+107 57 56
+146 3 2
+249 1 1
+146 1 1
+94 1 1
+34 1 1
+700 0 331
+21 1 1
+73 1 1
+49 1 1
+356 1 1
+16 1 1
+112 1 1
+36 9 0
+515 1 1
+27 2 2
+192 1 1
+53 0 14
+82 1 1
+302 1 1
+68 1 1
+52 12 12
+52 1 1
+34 1 1
+166 7 7
+384 1 1
+31 1 1
+281 1 1
+57 1 1
+176 0 1
+1625 1 1
+26 1 1
+369 1 1
+21 1 1
+86 1 1
+134 1 1
+215 1 1
+214 15 1
+50 2 2
+26 1 1
+78 0 19
+64 1 1
+126 1 1
+43 1 1
+433 1 1
+76 0 1
+6 12 0
+52 1 1
+108 1 1
+87 1 1
+62 1 1
+26 1 1
+291 2 1
+143 1 1
+29 1 1
+56 12 12
+230 1 1
+153 4 4
+87 32 32
+584 12 12
+227 1 0
+1931 4 0
+836 1 1
+68 1 1
+205 24 19
+816 1 2
+1932 0 7
+1732 13 0
+257 4 0
+1441 1 0
+111 6 0
+1505 1 1
+42 0 1
+373 13 13
+565 1 1
+76 1 0
+1881 0 4
+68 4 0
+43 0 4
+2201 8 8
+3726 3 0
+339 15 11
+249 1 1
+35 1 1
+250 1 1
+38 1 1
+359 11 12
+109 1 1
+43 18 0
+822 1 1
+53 1 1
+325 15 15
+123 1 1
+42 6 6
+240 1 1
+44 1 1
+438 7 7
+142 2 0
+1004 0 1
+9275 1 1
+37 1 0
+2071 0 1
+10399 0 1
+12513 2 1
+11243 1 1
+26 1 1
+816 4 0
+8248 26 26
+7722 2 0
+1594 1 0
+363 5 0
+2394 0 2
+4361 43 41
+12296 4 0
+835 0 1
+391 34 61
+12157 0 18
+1719
+
+chain 576814 chr6_mann_hap4 4683263 + 1212600 1230600 chr10 135374737 - 28241612 28250801 9180
+481 1 1
+46 1 1
+3015 1 1
+93 1 1
+2394 11402 2623
+68 26 25
+5 0 2
+124 0 1
+62 39 3
+39 3 5
+199
+
+chain 536760 chr6_mann_hap4 4683263 + 4039899 4045825 chr5 180857866 + 39823592 39829519 16844
+294 1 1
+54 1 1
+302 0 1
+93 1 1
+29 2 2
+134 1 1
+55 1 1
+603 13 13
+1215 13 13
+1780 1 1
+42 1 1
+233 1 1
+94 1 1
+485 1 1
+173 1 1
+76 1 1
+24 1 1
+71 1 1
+44 1 1
+82
+
+chain 146874 chr6_mann_hap4 4683263 + 4071169 4072762 chr6 170899992 + 134026872 134029045 878977
+503 1 1
+42 1 1
+274 1 1
+24 0 1
+48 1 0
+10 0 1
+42 0 579
+646
+
+chain 102870 chr6_mann_hap4 4683263 + 3889360 3891944 chr7 158821424 + 116952571 116956379 1238703
+117 2 2
+40 1 1
+56 1 1
+110 1 1
+92 1 1
+113 2 2
+63 1 1
+85 102 1326
+64 26 26
+95 124 124
+108 355 355
+211 690 690
+124
+
+chain 88220 chr6_mann_hap4 4683263 + 4099145 4105339 chr12 132349534 - 75332582 75341961 1434691
+65 33 33
+177 10 15
+106 4900 8080
+86 4 4
+267 1 1
+40 1 1
+504
+
+chain 82095 chr6_mann_hap4 4683263 + 3946479 3947465 chr2 242951149 - 63941857 63946734 1538129
+173 0 3890
+317 1 1
+39 1 1
+234 0 4
+116 1 1
+18 3 0
+83
+
+chain 77658 chr6_mann_hap4 4683263 + 3855504 3856400 chrX 154913754 + 120225651 120226547 1623639
+896
+
+chain 47748 chr6_mann_hap4 4683263 + 3888321 3890147 chrX 154913754 + 47530376 47536125 1299062
+73 10 10
+52 18 17
+100 64 64
+53 6 6
+131 99 99
+213 51 51
+144 732 4656
+80
+
+chain 47213 chr6_mann_hap4 4683263 + 3989872 3990794 chr5 180857866 + 134244858 134245983 2704506
+144 28 28
+67 90 94
+193 60 61
+52 141 339
+53 41 41
+53
+
+chain 46978 chr6_mann_hap4 4683263 + 2571063 2572874 chr3 199501827 - 190558999 190560805 2719824
+64 48 48
+112 161 161
+89 220 218
+60 475 474
+84 303 301
+99 9 9
+87
+
+chain 44341 chr6_mann_hap4 4683263 + 3927110 3927612 chrX 154913754 - 52960373 52960875 2903522
+147 1 1
+78 1 1
+160 1 1
+114
+
+chain 44107 chr6_mann_hap4 4683263 + 3835941 3836978 chr5 180857866 + 173373371 173375321 2921175
+63 100 100
+147 427 1340
+300
+
+chain 39461 chr6_mann_hap4 4683263 + 4070547 4070992 chr9 140273252 + 112733643 112734088 3326103
+238 2 2
+149 1 1
+55
+
+chain 35818 chr6_mann_hap4 4683263 + 3871024 3871462 chr17 78774742 - 29841443 29841854 3734139
+50 1 1
+51 12 0
+240 15 0
+69
+
+chain 30934 chr6_mann_hap4 4683263 + 2643294 2643706 chr7 158821424 + 2168309 2168721 4470814
+207 3 3
+37 1 1
+54 50 50
+60
+
+chain 26090 chr6_mann_hap4 4683263 + 1150980 1153720 chr6 170899992 + 30003398 30007118 6475487
+62 70 70
+76 766 798
+93 658 655
+52 786 1737
+53 61 61
+63
+
+chain 23990 chr6_mann_hap4 4683263 + 1157427 1158203 chr7 158821424 - 51137320 51138262 7695541
+178 101 101
+72 385 551
+40
+
+chain 23264 chr6_mann_hap4 4683263 + 4065870 4066815 chr6 170899992 + 32821586 32822354 8135397
+218 677 500
+50
+
+chain 21807 chr6_mann_hap4 4683263 + 2512201 2512573 chrX 154913754 - 34520894 34521266 9125800
+131 125 125
+116
+
+chain 20350 chr6_mann_hap4 4683263 + 2657077 2657501 chr7 158821424 - 21000102 21000525 10170609
+90 41 41
+55 140 139
+98
+
+chain 20145 chr6_mann_hap4 4683263 + 4080253 4081781 chr7 158821424 + 28844408 28845333 2477233
+50 75 74
+83 106 109
+74 174 246
+103 816 139
+47
+
+chain 19089 chr6_mann_hap4 4683263 + 3856636 3856946 chr6 170899992 - 57258123 57258433 11200200
+55 51 51
+66 32 32
+106
+
+chain 17641 chr6_mann_hap4 4683263 + 4011215 4011458 chrX 154913754 + 35042287 35042530 12436915
+99 43 43
+101
+
+chain 16962 chr6_mann_hap4 4683263 + 2570543 2573577 chr6 170899992 - 142198254 142201285 2740643
+52 14 14
+92 178 178
+78 1931 1927
+60 60 61
+102 387 387
+80
+
+chain 16215 chr6_mann_hap4 4683263 + 3951844 3952907 chr6 170899992 + 32656500 32657559 13820716
+58 826 822
+72 27 27
+80
+
+chain 16190 chr6_mann_hap4 4683263 + 3164538 3164716 chr2 242951149 + 128261675 128261851 597537
+28 10 8
+140
+
+chain 16086 chr6_mann_hap4 4683263 + 4006818 4007634 chr1 247249719 - 180906629 180907434 2580692
+2 123 123
+47 104 104
+70 400 389
+70
+
+chain 15557 chr6_mann_hap4 4683263 + 4157319 4158144 chr7 158821424 + 130132312 130132930 14485178
+71 636 429
+118
+
+chain 15452 chr6_mann_hap4 4683263 + 3929430 3929596 chrX 154913754 + 67920599 67920765 14594392
+166
+
+chain 14605 chr6_mann_hap4 4683263 + 4069695 4069910 chr5 180857866 + 98319067 98319283 15498993
+64 48 49
+103
+
+chain 14320 chr6_mann_hap4 4683263 + 3970754 3970920 chr5 180857866 + 46013667 46013833 15829593
+166
+
+chain 13359 chr6_mann_hap4 4683263 + 4006581 4006818 chr5 180857866 - 39455571 39455808 2075146
+237
+
+chain 13048 chr6_mann_hap4 4683263 + 3971467 3971895 chr2 242951149 + 206984071 206984490 17422560
+94 272 263
+62
+
+chain 13024 chr6_mann_hap4 4683263 + 983409 983545 chr11 134452384 - 45905925 45906061 17454497
+136
+
+chain 12983 chr6_mann_hap4 4683263 + 3892428 3892585 chr15 100338915 + 59852230 59852387 17511267
+67 7 7
+83
+
+chain 12686 chr6_mann_hap4 4683263 + 3839048 3839184 chr6 170899992 - 138278996 138279132 17957207
+136
+
+chain 12556 chr6_mann_hap4 4683263 + 1192697 1192836 chr2 242951149 - 184047846 184047985 18149168
+139
+
+chain 12476 chr6_mann_hap4 4683263 + 3826791 3826924 chr6 170899992 + 32549390 32549523 18269668
+133
+
+chain 12434 chr6_mann_hap4 4683263 + 3808825 3809130 chr7 158821424 - 76714202 76714512 18331176
+70 158 163
+77
+
+chain 12179 chr6_mann_hap4 4683263 + 3831748 3831876 chr6 170899992 + 32566069 32566197 18716372
+128
+
+chain 12137 chr6_mann_hap4 4683263 + 3872720 3873131 chr7 158821424 + 90920405 90920810 18779045
+54 266 260
+91
+
+chain 12051 chr6_mann_hap4 4683263 + 1151414 1151573 chr6 170899992 + 30566919 30567079 18913589
+81 23 24
+55
+
+chain 11900 chr6_mann_hap4 4683263 + 3926391 3926689 chr5 180857866 - 150002482 150002780 2916742
+72 52 52
+94 24 24
+56
+
+chain 11872 chr6_mann_hap4 4683263 + 1146859 1148064 chr6 170899992 + 29900614 29901492 19205041
+65 1050 723
+90
+
+chain 11746 chr6_mann_hap4 4683263 + 1143598 1143746 chr7 158821424 - 7754727 7754875 19419747
+54 14 14
+80
+
+chain 11745 chr6_mann_hap4 4683263 + 1218680 1218806 chr10 135374737 - 135314271 135314397 19420295
+126
+
+chain 11699 chr6_mann_hap4 4683263 + 1229899 1230035 chr10 135374737 + 90412720 90412856 14918390
+117 3 3
+16
+
+chain 11593 chr6_mann_hap4 4683263 + 3807962 3808085 chr1 247249719 - 238369051 238369174 19677684
+123
+
+chain 11428 chr6_mann_hap4 4683263 + 3972086 3972349 chr9 140273252 + 73803510 73803773 19960546
+86 127 127
+50
+
+chain 11397 chr6_mann_hap4 4683263 + 3965743 3966049 chr6 170899992 + 32661358 32661660 20018576
+64 168 164
+74
+
+chain 11122 chr6_mann_hap4 4683263 + 1203623 1204440 chr6 170899992 - 139553083 139553887 20511870
+77 676 663
+64
+
+chain 11075 chr6_mann_hap4 4683263 + 3824678 3824943 chrX 154913754 - 91757488 91757751 20592182
+66 132 130
+67
+
+chain 11034 chr6_mann_hap4 4683263 + 2653282 2653431 chr6 170899992 - 161606914 161607063 20670487
+64 22 22
+63
+
+chain 10867 chr6_mann_hap4 4683263 + 2578599 2578756 chr6 170899992 - 132294381 132294544 20980274
+55 29 35
+73
+
+chain 10661 chr6_mann_hap4 4683263 + 4070344 4070547 chr9 140273252 + 21133799 21134002 3998059
+43 83 83
+77
+
+chain 10522 chr6_mann_hap4 4683263 + 3881310 3881592 chr6 170899992 + 32650612 32650898 21668160
+51 155 159
+76
+
+chain 10446 chr6_mann_hap4 4683263 + 3833364 3833476 chr10 135374737 + 116791472 116791584 21828222
+112
+
+chain 10440 chr6_mann_hap4 4683263 + 3811691 3811821 chr3 199501827 - 53390365 53390495 21843018
+67 9 9
+54
+
+chain 10424 chr6_mann_hap4 4683263 + 1196400 1196662 chr1 247249719 - 93388912 93389184 21873906
+71 137 147
+54
+
+chain 10120 chr6_mann_hap4 4683263 + 4070282 4070470 chr7 158821424 - 148539669 148539857 3454343
+62 43 43
+83
+
+chain 10097 chr6_mann_hap4 4683263 + 3811321 3811557 chr6 170899992 - 10896454 10896689 22596969
+52 115 114
+69
+
+chain 10000 chr6_mann_hap4 4683263 + 4096293 4096805 chr2 242951149 - 75663422 75663931 22813441
+66 387 384
+59
+
+chain 9988 chr6_mann_hap4 4683263 + 3809787 3810216 chr10 135374737 - 44216709 44217139 22840112
+60 305 306
+64
+
+chain 9977 chr6_mann_hap4 4683263 + 4081621 4081734 chr6 170899992 - 39392888 39393001 3205407
+113
+
+chain 9923 chr6_mann_hap4 4683263 + 1132190 1132294 chr6 170899992 + 29984509 29984613 22990369
+104
+
+chain 9759 chr6_mann_hap4 4683263 + 3834344 3834498 chr10 135374737 + 105999092 105999246 23372649
+62 39 39
+53
+
+chain 9755 chr6_mann_hap4 4683263 + 3833117 3833361 chrX 154913754 - 4438295 4438540 23379344
+56 126 127
+62
+
+chain 9686 chr6_mann_hap4 4683263 + 3810435 3810616 chr18 76117153 - 71040520 71040702 23549061
+65 65 66
+51
+
+chain 9627 chr6_mann_hap4 4683263 + 3972992 3973194 chr2 242951149 + 230690248 230690450 23687186
+65 86 86
+51
+
+chain 9614 chr6_mann_hap4 4683263 + 2669709 2670446 chr6 170899992 - 140934793 140935541 23727233
+66 613 624
+58
+
+chain 9599 chr6_mann_hap4 4683263 + 4070139 4070248 chr11 134452384 + 56073710 56073819 11992436
+109
+
+chain 9564 chr6_mann_hap4 4683263 + 3827056 3827221 chr6 170899992 + 32549657 32549823 23841399
+59 50 51
+56
+
+chain 9528 chr6_mann_hap4 4683263 + 1159675 1160112 chr6 170899992 + 29878108 29878543 23937749
+59 318 316
+60
+
+chain 9459 chr6_mann_hap4 4683263 + 4095177 4095476 chr6 170899992 + 162410099 162410399 24103461
+60 183 184
+56
+
+chain 9368 chr6_mann_hap4 4683263 + 3972521 3972756 chr12 132349534 - 95011118 95011354 24299159
+63 120 121
+52
+
+chain 9354 chr6_mann_hap4 4683263 + 3870808 3870942 chr6 170899992 + 119226702 119226836 9825430
+89 20 20
+25
+
+chain 9352 chr6_mann_hap4 4683263 + 3873416 3873994 chr1 247249719 - 127730766 127731350 24325058
+63 457 463
+58
+
+chain 9220 chr6_mann_hap4 4683263 + 3811888 3812097 chr14 106368585 - 26360313 26360419 24589598
+77 103 0
+29
+
+chain 9090 chr6_mann_hap4 4683263 + 2577845 2577955 chr3 199501827 - 94209663 94209773 24799757
+53 4 4
+53
+
+chain 8867 chr6_mann_hap4 4683263 + 2303270 2303362 chr6 170899992 + 31062348 31062440 25148412
+92
+
+chain 8658 chr6_mann_hap4 4683263 + 3940022 3940112 chr6 170899992 + 32624355 32624445 25451087
+90
+
+chain 8423 chr6_mann_hap4 4683263 + 4072785 4072907 chr8 146274826 - 73050790 73050912 14363914
+122
+
+chain 8057 chr6_mann_hap4 4683263 + 3926870 3927000 chr16 88827254 + 18531944 18532074 3198196
+130
+
+chain 7759 chr6_mann_hap4 4683263 + 2673921 2674003 chr6 170899992 + 31350450 31350532 26801069
+82
+
+chain 7673 chr6_mann_hap4 4683263 + 2657501 2657610 chr6 170899992 + 83069844 83069953 14556403
+4 44 44
+61
+
+chain 7642 chr6_mann_hap4 4683263 + 3888828 3890773 chr8 146274826 - 66025745 66026665 1359052
+97 215 215
+31 1 1
+19 1532 507
+50
+
+chain 7574 chr6_mann_hap4 4683263 + 4484512 4485183 chr20 62435964 + 45587686 45587880 2535008
+51 481 51
+16 61 14
+62
+
+chain 7541 chr6_mann_hap4 4683263 + 2688373 2688460 chr9 140273252 - 10289268 10289355 15645101
+13 6 6
+68
+
+chain 7487 chr6_mann_hap4 4683263 + 2574042 2574244 chr12 132349534 - 40641236 40641438 23940543
+56 141 141
+5
+
+chain 7440 chr6_mann_hap4 4683263 + 3850580 3850658 chrX 154913754 - 39741290 39741368 27355538
+78
+
+chain 7404 chr6_mann_hap4 4683263 + 3850662 3850740 chr11 134452384 + 35675434 35675512 27404541
+78
+
+chain 7364 chr6_mann_hap4 4683263 + 4081165 4082062 chr1 247249719 + 33290703 33291601 1419850
+50 1 0
+53 86 88
+56 370 370
+160 42 42
+79
+
+chain 7276 chr6_mann_hap4 4683263 + 4034825 4034901 chr6 170899992 - 67344251 67344327 27653184
+76
+
+chain 7232 chr6_mann_hap4 4683263 + 3936821 3936898 chr6 170899992 + 32620027 32620104 27728489
+77
+
+chain 7204 chr6_mann_hap4 4683263 + 3963650 3963727 chr13 114142980 + 48271341 48271418 27789281
+77
+
+chain 7199 chr6_mann_hap4 4683263 + 4005404 4006455 chr3 199501827 + 106790123 106791174 347314
+69 5 5
+109 2 2
+142 1 1
+77 1 1
+51 1 0
+194 0 1
+399
+
+chain 7168 chr6_mann_hap4 4683263 + 4101507 4101583 chr12 132349534 + 30936505 30936581 27864404
+76
+
+chain 7077 chr6_mann_hap4 4683263 + 3870942 3871024 chr3 199501827 - 45186978 45187059 5450943
+68 1 0
+13
+
+chain 7012 chr6_mann_hap4 4683263 + 4115371 4115645 chr5 180857866 - 50439772 50440046 4370271
+130 8 8
+64 1 1
+71
+
+chain 6949 chr6_mann_hap4 4683263 + 3795791 3795864 chr6 170899992 + 32549387 32549460 28300222
+73
+
+chain 6804 chr6_mann_hap4 4683263 + 3799462 3799534 chr6 170899992 + 32582474 32582546 28581367
+72
+
+chain 6732 chr6_mann_hap4 4683263 + 2675578 2675667 chr18 76117153 - 11487790 11487879 28728624
+29 7 7
+53
+
+chain 6712 chr6_mann_hap4 4683263 + 2588030 2588100 chr6 170899992 - 140565854 140565924 28801698
+70
+
+chain 6680 chr6_mann_hap4 4683263 + 4075286 4087765 chr6 170899992 + 32827127 32836923 21175981
+50 4327 3617
+61 4734 2690
+85 515 965
+52 119 119
+177 2121 1742
+68 118 118
+52
+
+chain 6622 chr6_mann_hap4 4683263 + 3824747 3824817 chr11 134452384 + 57802002 57802072 28988414
+70
+
+chain 6586 chr6_mann_hap4 4683263 + 2674213 2674283 chr6 170899992 - 140567268 140567338 29088341
+70
+
+chain 6584 chr6_mann_hap4 4683263 + 3990111 3990185 chr18 76117153 - 4274607 4274681 4481991
+74
+
+chain 6566 chr6_mann_hap4 4683263 + 4010034 4010102 chr6 170899992 + 32665461 32665529 29137405
+68
+
+chain 6513 chr6_mann_hap4 4683263 + 4099018 4099087 chr12 132349534 + 47073126 47073195 29262419
+69
+
+chain 6495 chr6_mann_hap4 4683263 + 4159049 4159118 chr5 180857866 + 76445848 76445917 29303918
+69
+
+chain 6436 chr6_mann_hap4 4683263 + 3871527 3871805 chr7 158821424 + 110932926 110933204 10468972
+57 171 171
+50
+
+chain 6411 chr6_mann_hap4 4683263 + 4039821 4039893 chr7 158821424 + 30445389 30445461 17285
+72
+
+chain 6359 chr6_mann_hap4 4683263 + 3869372 3869440 chr6 170899992 + 32566306 32566374 29618338
+68
+
+chain 6271 chr6_mann_hap4 4683263 + 3932457 3932523 chr18 76117153 + 11207587 11207653 29843873
+66
+
+chain 6221 chr6_mann_hap4 4683263 + 4094828 4094893 chr13 114142980 + 50378597 50378662 29991830
+65
+
+chain 6213 chr6_mann_hap4 4683263 + 1229662 1229728 chrX 154913754 + 137911239 137911305 30001477
+66
+
+chain 6203 chr6_mann_hap4 4683263 + 3873624 3873689 chr10 135374737 + 5090148 5090213 30033078
+65
+
+chain 6176 chr6_mann_hap4 4683263 + 4099536 4099611 chr11 134452384 - 71399807 71399882 3438338
+75
+
+chain 6158 chr6_mann_hap4 4683263 + 3877219 3877284 chr8 146274826 + 95080661 95080726 30127968
+65
+
+chain 6140 chr6_mann_hap4 4683263 + 4095848 4095913 chr6 170899992 - 34774251 34774316 30199403
+65
+
+chain 6109 chr6_mann_hap4 4683263 + 3890332 3891494 chr3 199501827 - 173189040 173190202 2018297
+14 5 5
+73 23 23
+9 985 985
+53
+
+chain 6085 chr6_mann_hap4 4683263 + 3815553 3815617 chr6 170899992 - 55240220 55240284 30326057
+64
+
+chain 6021 chr6_mann_hap4 4683263 + 4094914 4094977 chr10 135374737 - 117721859 117721922 30522771
+63
+
+chain 5976 chr6_mann_hap4 4683263 + 2676901 2676964 chr6 170899992 + 31358648 31358711 30614230
+63
+
+chain 5949 chr6_mann_hap4 4683263 + 3824409 3824472 chr7 158821424 + 26639264 26639327 30690415
+63
+
+chain 5940 chr6_mann_hap4 4683263 + 3886792 3886855 chr2 242951149 - 15301589 15301652 30719367
+63
+
+chain 5911 chr6_mann_hap4 4683263 + 3951381 3951442 chrX 154913754 - 11371530 11371591 30799839
+61
+
+chain 5847 chr6_mann_hap4 4683263 + 4105339 4105404 chr17 78774742 - 73855979 73856044 1451430
+65
+
+chain 5813 chr6_mann_hap4 4683263 + 3850423 3850485 chr1 247249719 + 47323960 47324022 31053357
+62
+
+chain 5712 chr6_mann_hap4 4683263 + 3809370 3809430 chr12 132349534 - 114271713 114271773 31330278
+60
+
+chain 5702 chr6_mann_hap4 4683263 + 3970106 3970165 chr6 170899992 + 32605878 32605937 31357679
+59
+
+chain 5680 chr6_mann_hap4 4683263 + 2302831 2302921 chr6 170899992 + 31062944 31063124 23617653
+33 39 129
+18
+
+chain 5655 chr6_mann_hap4 4683263 + 3855204 3855371 chrX 154913754 + 81246238 81246422 14247867
+57 109 126
+1
+
+chain 5594 chr6_mann_hap4 4683263 + 3796059 3796118 chr6 170899992 + 32549657 32549716 31663072
+59
+
+chain 5594 chr6_mann_hap4 4683263 + 3893458 3893517 chr1 247249719 - 146336256 146336315 31665010
+59
+
+chain 5512 chr6_mann_hap4 4683263 + 3824164 3824222 chr7 158821424 + 45670922 45670980 31905208
+58
+
+chain 5502 chr6_mann_hap4 4683263 + 3808491 3808548 chr1 247249719 - 79348621 79348678 31943034
+57
+
+chain 5494 chr6_mann_hap4 4683263 + 4130703 4130761 chr5 180857866 - 119300515 119300573 31945207
+58
+
+chain 5494 chr6_mann_hap4 4683263 + 3808247 3808305 chr4 191273063 - 5377020 5377078 31946828
+58
+
+chain 5476 chr6_mann_hap4 4683263 + 2311526 2311584 chrX 154913754 + 154691014 154691072 32018635
+58
+
+chain 5448 chr6_mann_hap4 4683263 + 1152324 1152381 chr6 170899992 + 29906136 29906193 32122349
+57
+
+chain 5435 chr6_mann_hap4 4683263 + 4007164 4007322 chr6 170899992 - 63943483 63943641 1906371
+158
+
+chain 5402 chr6_mann_hap4 4683263 + 1156066 1156122 chr10 135374737 + 63402064 63402120 32243879
+56
+
+chain 5394 chr6_mann_hap4 4683263 + 3972634 3972691 chr9 140273252 - 60383594 60383651 32250416
+57
+
+chain 5385 chr6_mann_hap4 4683263 + 4130844 4130901 chr6 170899992 - 83909587 83909644 32298057
+57
+
+chain 5367 chr6_mann_hap4 4683263 + 2578199 2578256 chr18 76117153 + 1134159 1134216 32358571
+57
+
+chain 5330 chr6_mann_hap4 4683263 + 3931278 3931334 chr6 170899992 + 32568311 32568367 32437916
+56
+
+chain 5276 chr6_mann_hap4 4683263 + 4098513 4098569 chr12 132349534 + 40414598 40414654 32640380
+56
+
+chain 5229 chr6_mann_hap4 4683263 + 2586412 2586466 chr6 170899992 - 140897459 140897513 32754405
+54
+
+chain 5211 chr6_mann_hap4 4683263 + 3836033 3836093 chr18 76117153 - 36956615 36956675 5572697
+38 15 15
+7
+
+chain 5158 chr6_mann_hap4 4683263 + 3970466 3970521 chr10 135374737 - 40576729 40576784 32990090
+55
+
+chain 5146 chr6_mann_hap4 4683263 + 3856405 3856719 chr8 146274826 + 48564292 48564606 15853984
+85 201 201
+28
+
+chain 5121 chr6_mann_hap4 4683263 + 3811628 3811682 chr10 135374737 - 125001214 125001268 33093899
+54
+
+chain 5103 chr6_mann_hap4 4683263 + 1145020 1145074 chr6 170899992 + 76955761 76955815 33170027
+54
+
+chain 5103 chr6_mann_hap4 4683263 + 2640619 2640673 chr4 191273063 + 102542252 102542306 33171908
+54
+
+chain 5085 chr6_mann_hap4 4683263 + 4098430 4098484 chrX 154913754 - 140611616 140611670 33235342
+54
+
+chain 5066 chr6_mann_hap4 4683263 + 1192620 1192673 chr21 46944323 - 1867343 1867396 33290792
+53
+
+chain 5062 chr6_mann_hap4 4683263 + 2570759 2570813 chr8 146274826 - 12544502 12544556 11634211
+54
+
+chain 5031 chr6_mann_hap4 4683263 + 3825550 3825604 chr11 134452384 + 134387408 134387462 33376435
+54
+
+chain 5030 chr6_mann_hap4 4683263 + 4130785 4130838 chr15 100338915 + 69519076 69519129 33389328
+53
+
+chain 5021 chr6_mann_hap4 4683263 + 2574130 2574183 chrX 154913754 + 36345885 36345938 33439867
+53
+
+chain 5020 chr6_mann_hap4 4683263 + 4060907 4060959 chr3 199501827 + 48220698 48220750 33444406
+52
+
+chain 5012 chr6_mann_hap4 4683263 + 3951677 3951730 chr6 170899992 + 32629462 32629515 33454256
+53
+
+chain 5003 chr6_mann_hap4 4683263 + 4102005 4102058 chr5 180857866 + 152654188 152654241 33499797
+53
+
+chain 5003 chr6_mann_hap4 4683263 + 1229462 1229515 chr19 63811651 - 15372469 15372522 33501003
+53
+
+chain 4985 chr6_mann_hap4 4683263 + 2640409 2640462 chr16 88827254 - 40848691 40848744 33578669
+53
+
+chain 4971 chr6_mann_hap4 4683263 + 2512062 2512133 chr4 191273063 - 56892114 56892185 10839773
+71
+
+chain 4967 chr6_mann_hap4 4683263 + 3825268 3825321 chr3 199501827 + 186460138 186460191 33617850
+53
+
+chain 4957 chr6_mann_hap4 4683263 + 3885923 3885975 chrX 154913754 + 147065533 147065585 33651269
+52
+
+chain 4957 chr6_mann_hap4 4683263 + 2575182 2575234 chr9 140273252 - 31866047 31866099 33651494
+52
+
+chain 4948 chr6_mann_hap4 4683263 + 4100717 4100769 chr1 247249719 - 35792193 35792245 33679191
+52
+
+chain 4948 chr6_mann_hap4 4683263 + 2574667 2574719 chr8 146274826 - 9857366 9857418 33680602
+52
+
+chain 4922 chr6_mann_hap4 4683263 + 4009115 4009168 chr6 170899992 + 32548301 32548354 33750859
+53
+
+chain 4903 chr6_mann_hap4 4683263 + 3850504 3850556 chr10 135374737 - 57466002 57466054 33851105
+52
+
+chain 4903 chr6_mann_hap4 4683263 + 4012033 4012085 chr10 135374737 + 117209347 117209399 33851122
+52
+
+chain 4863 chr6_mann_hap4 4683263 + 4069590 4069643 chr17 78774742 + 14392768 14392821 28434808
+53
+
+chain 4829 chr6_mann_hap4 4683263 + 1204441 1204491 chr6 170899992 + 29800923 29800973 34088054
+50
+
+chain 4821 chr6_mann_hap4 4683263 + 4157686 4157737 chrX 154913754 - 88293005 88293056 34119905
+51
+
+chain 4821 chr6_mann_hap4 4683263 + 3816946 3816997 chrX 154913754 + 135859174 135859225 34119936
+51
+
+chain 4812 chr6_mann_hap4 4683263 + 1190701 1190752 chr6 170899992 + 30567861 30567912 34152526
+51
+
+chain 4784 chr6_mann_hap4 4683263 + 3932557 3932607 chr3 199501827 + 84648995 84649045 34278095
+50
+
+chain 4758 chr6_mann_hap4 4683263 + 4095126 4095177 chr11 134452384 + 59226474 59226525 34323839
+51
+
+chain 4757 chr6_mann_hap4 4683263 + 2310474 2310524 chr11 134452384 + 7692440 7692490 34342561
+50
+
+chain 4739 chr6_mann_hap4 4683263 + 2310303 2310353 chr18 76117153 + 71840104 71840154 34400727
+50
+
+chain 4730 chr6_mann_hap4 4683263 + 3787434 3787484 chr4 191273063 - 37377714 37377764 34442427
+50
+
+chain 4712 chr6_mann_hap4 4683263 + 1146218 1146268 chr14 106368585 - 81295539 81295589 34510763
+50
+
+chain 4703 chr6_mann_hap4 4683263 + 2675065 2675115 chr8 146274826 + 89610032 89610082 34558303
+50
+
+chain 4685 chr6_mann_hap4 4683263 + 1229409 1229459 chrX 154913754 - 17497814 17497864 34590611
+50
+
+chain 4676 chr6_mann_hap4 4683263 + 3971574 3971624 chr8 146274826 + 69479304 69479354 34603338
+50
+
+chain 4606 chr6_mann_hap4 4683263 + 4016520 4016570 chr5 180857866 - 14463729 14463779 34659648
+50
+
+chain 4600 chr6_mann_hap4 4683263 + 2569984 2570033 chr12 132349534 - 4862576 4862625 22913313
+49
+
+chain 4530 chr6_mann_hap4 4683263 + 3886656 3886704 chr13 114142980 - 22170853 22170901 34701009
+48
+
+chain 4406 chr6_mann_hap4 4683263 + 4011118 4011181 chr12 132349534 + 83019068 83019131 17889504
+63
+
+chain 4392 chr6_mann_hap4 4683263 + 1157646 1157705 chr7 158821424 - 126060926 126060985 9905440
+59
+
+chain 4358 chr6_mann_hap4 4683263 + 3963545 3963592 chr4 191273063 + 98116240 98116287 34788627
+47
+
+chain 4338 chr6_mann_hap4 4683263 + 2302495 2302540 chr6 170899992 + 31062473 31062518 34812241
+45
+
+chain 4205 chr6_mann_hap4 4683263 + 2570813 2571448 chr4 191273063 + 161293453 161294088 2765734
+66 98 98
+77 6 6
+3 343 343
+42
+
+chain 4169 chr6_mann_hap4 4683263 + 4069643 4069694 chrX 154913754 + 84821116 84821167 24393818
+51
+
+chain 4167 chr6_mann_hap4 4683263 + 3838733 3838778 chr16 88827254 - 62536028 62536073 34880256
+45
+
+chain 4152 chr6_mann_hap4 4683263 + 3836004 3836104 chr19 63811651 + 19808105 19808205 3095372
+29 60 60
+11
+
+chain 4047 chr6_mann_hap4 4683263 + 3972236 3972287 chr6 170899992 + 112361298 112361349 25801950
+42 5 5
+4
+
+chain 3949 chr6_mann_hap4 4683263 + 2688555 2688633 chr19 63811651 + 60123016 60123094 19419643
+78
+
+chain 3938 chr6_mann_hap4 4683263 + 3812129 3812170 chr12 132349534 + 106783136 106783177 34996469
+41
+
+chain 3933 chr6_mann_hap4 4683263 + 2511488 2511645 chr1 247249719 - 10334654 10334811 9926759
+99 7 7
+51
+
+chain 3926 chr6_mann_hap4 4683263 + 4006888 4006943 chr9 140273252 - 21404336 21404391 4875740
+55
+
+chain 3812 chr6_mann_hap4 4683263 + 4007464 4007564 chr3 199501827 + 15208966 15209066 3047556
+56 42 42
+2
+
+chain 3783 chr6_mann_hap4 4683263 + 2657037 2657077 chr2 242951149 - 166645324 166645364 18114610
+40
+
+chain 3746 chr6_mann_hap4 4683263 + 3833193 3833245 chr3 199501827 + 114553026 114553078 23981702
+52
+
+chain 3734 chr6_mann_hap4 4683263 + 4157453 4157518 chr6 170899992 + 80018577 80018642 19955867
+65
+
+chain 3720 chr6_mann_hap4 4683263 + 4102548 4102587 chr5 180857866 - 28755460 28755499 35075682
+39
+
+chain 3600 chr6_mann_hap4 4683263 + 4159173 4159211 chr2 242951149 + 129304609 129304647 25766361
+38
+
+chain 3592 chr6_mann_hap4 4683263 + 3870724 3870762 chr3 199501827 - 38712743 38712781 26080747
+38
+
+chain 3526 chr6_mann_hap4 4683263 + 1196363 1196400 chr3 199501827 + 179624737 179624774 21949405
+37
+
+chain 3503 chr6_mann_hap4 4683263 + 3972049 3972086 chrX 154913754 + 6516305 6516342 20940830
+37
+
+chain 3405 chr6_mann_hap4 4683263 + 3888574 3888637 chr12 132349534 - 63727404 63727467 1360984
+63
+
+chain 3368 chr6_mann_hap4 4683263 + 3807881 3807940 chr10 135374737 - 122033518 122033577 24304357
+59
+
+chain 3334 chr6_mann_hap4 4683263 + 3942243 3942283 chr16 88827254 - 56809950 56809989 35201127
+19 1 0
+20
+
+chain 3303 chr6_mann_hap4 4683263 + 3972756 3972791 chr1 247249719 + 73729369 73729404 27153556
+35
+
+chain 3293 chr6_mann_hap4 4683263 + 4158373 4158408 chr7 158821424 - 26273345 26273380 30505739
+35
+
+chain 3293 chr6_mann_hap4 4683263 + 3825694 3825729 chr16 88827254 - 56536304 56536339 35220873
+35
+
+chain 3290 chr6_mann_hap4 4683263 + 2574386 2574448 chr8 146274826 + 34715687 34715749 20565863
+62
+
+chain 3284 chr6_mann_hap4 4683263 + 3962434 3962469 chr7 158821424 - 75715212 75715247 35222192
+35
+
+chain 3275 chr6_mann_hap4 4683263 + 1138144 1138179 chr6 170899992 + 29990315 29990350 35226053
+35
+
+chain 3266 chr6_mann_hap4 4683263 + 3971216 3971273 chr3 199501827 - 22333077 22333134 22107564
+57
+
+chain 3253 chr6_mann_hap4 4683263 + 4099622 4099676 chr19 63811651 + 42514641 42514695 4288250
+54
+
+chain 3205 chr6_mann_hap4 4683263 + 4070992 4071055 chr1 247249719 + 196464086 196464149 10251011
+63
+
+chain 3203 chr6_mann_hap4 4683263 + 3824817 3824851 chr3 199501827 - 28583100 28583134 30999626
+34
+
+chain 3180 chr6_mann_hap4 4683263 + 3893634 3893669 chr18 76117153 - 75290002 75290037 35254886
+35
+
+chain 3155 chr6_mann_hap4 4683263 + 4006480 4006566 chr8 146274826 - 94420792 94420878 3680803
+86
+
+chain 3107 chr6_mann_hap4 4683263 + 3887907 3887940 chr2 242951149 + 18209140 18209173 23522185
+33
+
+chain 3079 chr6_mann_hap4 4683263 + 2571537 2573841 chr6 170899992 + 126959071 126961365 3502977
+2 117 114
+67 2060 2053
+58
+
+chain 3064 chr6_mann_hap4 4683263 + 2303363 2303395 chr6 170899992 + 31062756 31062788 33922186
+32
+
+chain 3031 chr6_mann_hap4 4683263 + 3886413 3886445 chr2 242951149 + 186256011 186256043 29433855
+32
+
+chain 3016 chr6_mann_hap4 4683263 + 2311494 2311526 chrX 154913754 + 79124038 79124070 32077336
+32
+
+chain 2979 chr6_mann_hap4 4683263 + 3855470 3855504 chr3 199501827 + 4042271 4042305 1799588
+34
+
+chain 2964 chr6_mann_hap4 4683263 + 1196678 1196709 chrX 154913754 + 72461549 72461580 26677785
+31
+
+chain 2956 chr6_mann_hap4 4683263 + 3866093 3866129 chr1 247249719 - 141171387 141171423 35318155
+36
+
+chain 2906 chr6_mann_hap4 4683263 + 3932526 3932557 chr9 140273252 + 22587602 22587633 35284164
+31
+
+chain 2906 chr6_mann_hap4 4683263 + 3886745 3886778 chr8 146274826 - 118435747 118435780 35339754
+33
+
+chain 2872 chr6_mann_hap4 4683263 + 3971341 3971392 chr12 132349534 + 117591668 117591719 18400010
+51
+
+chain 2863 chr6_mann_hap4 4683263 + 2569913 2569984 chrX 154913754 + 15788619 15788690 15376547
+71
+
+chain 2850 chr6_mann_hap4 4683263 + 3872455 3872908 chr4 191273063 + 173531459 173531912 22440020
+66 326 326
+61
+
+chain 2847 chr6_mann_hap4 4683263 + 3886091 3886121 chr14 106368585 + 78698582 78698612 35350318
+30
+
+chain 2843 chr6_mann_hap4 4683263 + 4080743 4081595 chr9 140273252 + 76002383 76002587 2839818
+50 737 89
+65
+
+chain 2810 chr6_mann_hap4 4683263 + 3944503 3944532 chr1 247249719 - 39748406 39748435 35362931
+29
+
+chain 2797 chr6_mann_hap4 4683263 + 4484961 4485121 chr19 63811651 - 12967948 12968184 2658963
+29 70 70
+17 13 89
+31
+
+chain 2786 chr6_mann_hap4 4683263 + 3891682 3891777 chrX 154913754 - 85953788 85953883 2307593
+61 1 1
+33
+
+chain 2782 chr6_mann_hap4 4683263 + 2656861 2656923 chr8 146274826 - 144762871 144762933 15570304
+62
+
+chain 2778 chr6_mann_hap4 4683263 + 4115342 4115371 chr5 180857866 - 91122400 91122429 5117904
+29
+
+chain 2753 chr6_mann_hap4 4683263 + 1196549 1196608 chr12 132349534 + 50414483 50414542 22637630
+59
+
+chain 2740 chr6_mann_hap4 4683263 + 3887725 3887787 chr5 180857866 + 121612373 121612435 20400020
+62
+
+chain 2671 chr6_mann_hap4 4683263 + 2578539 2578598 chr9 140273252 - 60326471 60326530 21074054
+59
+
+chain 2624 chr6_mann_hap4 4683263 + 2643215 2643265 chr12 132349534 - 76880491 76880541 6796930
+50
+
+chain 2617 chr6_mann_hap4 4683263 + 4484579 4484636 chr11 134452384 - 70226060 70226117 2741353
+57
+
+chain 2617 chr6_mann_hap4 4683263 + 3951354 3951381 chrX 154913754 + 30529839 30529866 35092612
+27
+
+chain 2616 chr6_mann_hap4 4683263 + 3927817 3927913 chr6 170899992 - 159168046 159168142 3467812
+96
+
+chain 2596 chr6_mann_hap4 4683263 + 3973087 3973114 chr3 199501827 + 56590732 56590759 32896512
+27
+
+chain 2531 chr6_mann_hap4 4683263 + 3971895 3971925 chr3 199501827 + 180701028 180701058 25637788
+30
+
+chain 2466 chr6_mann_hap4 4683263 + 3824382 3824409 chr3 199501827 - 192093673 192093700 31748081
+27
+
+chain 2451 chr6_mann_hap4 4683263 + 3971666 3971716 chr2 242951149 + 181100921 181100971 18669842
+50
+
+chain 2440 chr6_mann_hap4 4683263 + 2572049 2572075 chr12 132349534 - 35755450 35755476 32394235
+26
+
+chain 2374 chr6_mann_hap4 4683263 + 3950266 3950291 chr1 247249719 - 157289487 157289512 35464629
+25
+
+chain 2364 chr6_mann_hap4 4683263 + 3819663 3819687 chr11 134452384 - 104747367 104747391 35468112
+24
+
+chain 2345 chr6_mann_hap4 4683263 + 2657279 2657339 chr9 140273252 + 101754649 101754709 22265309
+60
+
+chain 2313 chr6_mann_hap4 4683263 + 3890591 3890665 chr6 170899992 + 55285173 55285247 1894941
+74
+
+chain 2296 chr6_mann_hap4 4683263 + 2570274 2570347 chr10 135374737 + 81973802 81973875 17155090
+73
+
+chain 2290 chr6_mann_hap4 4683263 + 1157821 1157878 chr1 247249719 + 222604152 222604209 12152480
+57
+
+chain 2274 chr6_mann_hap4 4683263 + 3934768 3934792 chr3 199501827 + 107081622 107081646 35482673
+24
+
+chain 2265 chr6_mann_hap4 4683263 + 3887959 3887983 chrX 154913754 - 124439583 124439607 35484926
+24
+
+chain 2258 chr6_mann_hap4 4683263 + 3824852 3824876 chrX 154913754 - 132191215 132191239 25992080
+24
+
+chain 2257 chr6_mann_hap4 4683263 + 4006990 4007066 chr6 170899992 - 104582331 104582407 2576654
+76
+
+chain 2255 chr6_mann_hap4 4683263 + 4159118 4159146 chr8 146274826 + 40415014 40415042 30252789
+28
+
+chain 2253 chr6_mann_hap4 4683263 + 2653160 2653184 chr2 242951149 + 186158239 186158263 32681827
+24
+
+chain 2249 chr6_mann_hap4 4683263 + 4006455 4006480 chr5 180857866 - 144759522 144759547 4178637
+25
+
+chain 2214 chr6_mann_hap4 4683263 + 3971284 3971340 chr11 134452384 + 87181255 87181311 21919084
+56
+
+chain 2211 chr6_mann_hap4 4683263 + 3809943 3809993 chr20 62435964 - 30230318 30230368 23880964
+50
+
+chain 2210 chr6_mann_hap4 4683263 + 3835038 3835061 chr1 247249719 + 53077746 53077769 35492698
+23
+
+chain 2194 chr6_mann_hap4 4683263 + 1157606 1157646 chrX 154913754 - 101365357 101365397 11073773
+40
+
+chain 2181 chr6_mann_hap4 4683263 + 4081491 4081530 chrX 154913754 - 85175003 85175042 4116465
+39
+
+chain 2160 chr6_mann_hap4 4683263 + 3942219 3942243 chr1 247249719 - 214605983 214606007 35201144
+24
+
+chain 2156 chr6_mann_hap4 4683263 + 1145077 1145100 chr1 247249719 + 41331153 41331176 35506781
+23
+
+chain 2149 chr6_mann_hap4 4683263 + 4099822 4099870 chr9 140273252 + 102195866 102195914 4118428
+48
+
+chain 2146 chr6_mann_hap4 4683263 + 1143811 1143872 chr12 132349534 + 104221177 104221238 23825289
+61
+
+chain 2141 chr6_mann_hap4 4683263 + 4081286 4081346 chr20 62435964 - 10135341 10135401 5446947
+60
+
+chain 2127 chr6_mann_hap4 4683263 + 4045825 4045849 chr6 170899992 + 156402969 156402993 17746
+24
+
+chain 2123 chr6_mann_hap4 4683263 + 4007634 4007684 chr1 247249719 - 1324986 1325036 2693877
+50
+
+chain 2120 chr6_mann_hap4 4683263 + 3892019 3892104 chr14 106368585 + 35729289 35729374 2483709
+85
+
+chain 2099 chr6_mann_hap4 4683263 + 1196341 1196363 chr8 146274826 + 94956096 94956118 22553599
+22
+
+chain 2075 chr6_mann_hap4 4683263 + 4011497 4011566 chr6 170899992 - 138358121 138358190 21792053
+69
+
+chain 2039 chr6_mann_hap4 4683263 + 2571934 2572049 chr7 158821424 + 116148574 116148689 3252915
+115
+
+chain 2027 chr6_mann_hap4 4683263 + 3809848 3810361 chr5 180857866 - 108598115 108598712 24999557
+55 397 481
+61
+
+chain 2014 chr6_mann_hap4 4683263 + 4099976 4100031 chr3 199501827 + 188094551 188094606 22317615
+55
+
+chain 2010 chr6_mann_hap4 4683263 + 3935813 3935834 chrX 154913754 + 30529615 30529636 35529704
+21
+
+chain 2000 chr6_mann_hap4 4683263 + 1157778 1157811 chr4 191273063 + 153905795 153905828 8127682
+33
+
+chain 2000 chr6_mann_hap4 4683263 + 4158272 4158321 chr6 170899992 - 39092714 39092763 20395916
+49
+
+chain 1976 chr6_mann_hap4 4683263 + 1229873 1229899 chr9 140273252 + 92917708 92917734 26443005
+26
+
+chain 1931 chr6_mann_hap4 4683263 + 3926709 3926764 chr3 199501827 + 181243093 181243148 3766615
+55
+
+chain 1921 chr6_mann_hap4 4683263 + 4158321 4158373 chr11 134452384 + 132133410 132133462 17748702
+52
+
+chain 1919 chr6_mann_hap4 4683263 + 2511945 2511997 chr4 191273063 + 131153712 131153764 15450947
+52
+
+chain 1907 chr6_mann_hap4 4683263 + 2572521 2573169 chr12 132349534 - 49839290 49839926 3124499
+58 540 528
+50
+
+chain 1805 chr6_mann_hap4 4683263 + 3891144 3891220 chrX 154913754 + 107411806 107411882 2933427
+76
+
+chain 1798 chr6_mann_hap4 4683263 + 3870776 3870808 chr5 180857866 + 161128758 161128790 11651368
+32
+
+chain 1772 chr6_mann_hap4 4683263 + 4007367 4007430 chr16 88827254 - 2018363 2018426 2212652
+63
+
+chain 1763 chr6_mann_hap4 4683263 + 4080494 4080567 chr14 106368585 - 71004341 71004414 2917022
+73
+
+chain 1747 chr6_mann_hap4 4683263 + 2573669 2574306 chr1 247249719 + 71359925 71360557 7388765
+54 521 516
+62
+
+chain 1746 chr6_mann_hap4 4683263 + 3990700 3990741 chr6 170899992 + 88517978 88518019 3345644
+17 14 14
+10
+
+chain 1730 chr6_mann_hap4 4683263 + 2653102 2653160 chr15 100338915 + 50804927 50804985 23248991
+58
+
+chain 1696 chr6_mann_hap4 4683263 + 4006820 4006866 chrX 154913754 - 37494215 37494261 4107897
+46
+
+chain 1694 chr6_mann_hap4 4683263 + 4099748 4099799 chr1 247249719 + 46568424 46568475 18602659
+51
+
+chain 1690 chr6_mann_hap4 4683263 + 4158763 4158820 chr11 134452384 - 120264308 120264365 24918211
+57
+
+chain 1684 chr6_mann_hap4 4683263 + 3891607 3891668 chr9 140273252 - 45892574 45892635 2466690
+61
+
+chain 1664 chr6_mann_hap4 4683263 + 2656660 2656721 chr14 106368585 - 51104394 51104455 13584343
+61
+
+chain 1636 chr6_mann_hap4 4683263 + 3926463 3926504 chr15 100338915 - 30465019 30465060 3027934
+41
+
+chain 1600 chr6_mann_hap4 4683263 + 3973114 3973143 chr13 114142980 - 18785120 18785149 24380543
+29
+
+chain 1599 chr6_mann_hap4 4683263 + 3971096 3971159 chr8 146274826 + 126278291 126278354 19925893
+63
+
+chain 1591 chr6_mann_hap4 4683263 + 2511679 2511736 chr12 132349534 + 73083054 73083111 11729778
+57
+
+chain 1570 chr6_mann_hap4 4683263 + 4158461 4158521 chr12 132349534 + 40906087 40906147 15863002
+60
+
+chain 1569 chr6_mann_hap4 4683263 + 2569611 2569737 chr1 247249719 + 93626635 93626761 9616359
+126
+
+chain 1566 chr6_mann_hap4 4683263 + 3927068 3927110 chr4 191273063 - 20598961 20599003 3502725
+42
+
+chain 1557 chr6_mann_hap4 4683263 + 3927759 3927810 chrX 154913754 + 117055564 117055615 4598072
+51
+
+chain 1477 chr6_mann_hap4 4683263 + 3891945 3892006 chr10 135374737 + 87524787 87524848 2722375
+61
+
+chain 1473 chr6_mann_hap4 4683263 + 4080991 4081045 chr17 78774742 + 33000128 33000182 3754636
+54
+
+chain 1460 chr6_mann_hap4 4683263 + 3890832 3890888 chr8 146274826 + 57494812 57494868 2709746
+56
+
+chain 1455 chr6_mann_hap4 4683263 + 4007066 4007094 chr6 170899992 - 11011124 11011152 3343257
+28
+
+chain 1453 chr6_mann_hap4 4683263 + 3891391 3891437 chr8 146274826 + 51746327 51746373 3488858
+46
+
+chain 1424 chr6_mann_hap4 4683263 + 2571563 2571641 chr9 140273252 - 113447512 113447590 4199477
+78
+
+chain 1424 chr6_mann_hap4 4683263 + 3871462 3871507 chr1 247249719 - 200018115 200018160 11574863
+45
+
+chain 1406 chr6_mann_hap4 4683263 + 3890773 3890831 chr4 191273063 + 55621101 55621159 1970745
+58
+
+chain 1406 chr6_mann_hap4 4683263 + 4158521 4158575 chr1 247249719 + 49943386 49943440 15855508
+54
+
+chain 1397 chr6_mann_hap4 4683263 + 3890211 3890236 chr10 135374737 - 71340044 71340069 2299991
+25
+
+chain 1392 chr6_mann_hap4 4683263 + 3971636 3971666 chr3 199501827 - 51819316 51819346 23522768
+30
+
+chain 1373 chr6_mann_hap4 4683263 + 2511768 2511834 chr5 180857866 + 26360477 26360543 20230569
+66
+
+chain 1361 chr6_mann_hap4 4683263 + 4070248 4070282 chr4 191273063 + 53456808 53456842 4749510
+34
+
+chain 1354 chr6_mann_hap4 4683263 + 1158001 1158055 chr4 191273063 + 534307 534361 14280054
+54
+
+chain 1345 chr6_mann_hap4 4683263 + 3855264 3855317 chrX 154913754 + 62583130 62583183 22642552
+53
+
+chain 1311 chr6_mann_hap4 4683263 + 3990016 3990044 chr12 132349534 - 10940806 10940834 3119062
+28
+
+chain 1285 chr6_mann_hap4 4683263 + 2741741 2741814 chrX 154913754 - 101841552 101841726 4764485
+55 2 103
+16
+
+chain 1271 chr6_mann_hap4 4683263 + 4485264 4485308 chr2 242951149 + 42686810 42686854 6287037
+44
+
+chain 1232 chr6_mann_hap4 4683263 + 3891286 3891326 chr4 191273063 + 121886954 121886994 3320472
+40
+
+chain 1228 chr6_mann_hap4 4683263 + 4081088 4081138 chr7 158821424 + 22807318 22807368 2860523
+50
+
+chain 1216 chr6_mann_hap4 4683263 + 3886222 3886374 chr6 170899992 + 81566192 81566344 3344709
+59 17 17
+76
+
+chain 1200 chr6_mann_hap4 4683263 + 4080922 4080972 chrX 154913754 - 78005269 78005319 2937486
+50
+
+chain 1196 chr6_mann_hap4 4683263 + 2642964 2643022 chr13 114142980 - 87864434 87864492 20517842
+58
+
+chain 1192 chr6_mann_hap4 4683263 + 3871650 3871705 chr15 100338915 - 25838674 25838729 13558940
+55
+
+chain 1173 chr6_mann_hap4 4683263 + 3856498 3856532 chr11 134452384 - 32778066 32778100 22709110
+34
+
+chain 1168 chr6_mann_hap4 4683263 + 3891494 3891535 chr15 100338915 + 80079703 80079744 3327446
+41
+
+chain 1163 chr6_mann_hap4 4683263 + 3926838 3926870 chr6 170899992 + 66742660 66742692 3612231
+32
+
+chain 1163 chr6_mann_hap4 4683263 + 3887419 3887473 chrX 154913754 + 89074833 89074887 25104537
+54
+
+chain 1160 chr6_mann_hap4 4683263 + 2573343 2573371 chrX 154913754 + 56853117 56853145 21155199
+28
+
+chain 1149 chr6_mann_hap4 4683263 + 3856532 3856615 chr10 135374737 + 110407978 110408061 14842132
+83
+
+chain 1128 chr6_mann_hap4 4683263 + 2742956 2742992 chr13 114142980 - 41462025 41462061 4150569
+36
+
+chain 1122 chr6_mann_hap4 4683263 + 4080072 4080135 chr19 63811651 + 62685625 62685688 7787530
+63
+
+chain 1120 chr6_mann_hap4 4683263 + 3927728 3927759 chr20 62435964 + 16923180 16923211 7977510
+31
+
+chain 1120 chr6_mann_hap4 4683263 + 3887060 3887131 chr11 134452384 - 72766723 72766794 12188515
+71
+
+chain 1113 chr6_mann_hap4 4683263 + 2570192 2570259 chr2 242951149 - 140069145 140069212 8748780
+67
+
+chain 1096 chr6_mann_hap4 4683263 + 2643706 2643734 chr15 100338915 + 86869156 86869184 12823891
+28
+
+chain 1076 chr6_mann_hap4 4683263 + 3892300 3892346 chr11 134452384 + 14828539 14828585 2361427
+46
+
+chain 1041 chr6_mann_hap4 4683263 + 4080135 4080193 chr6 170899992 - 117620920 117620978 4257272
+58
+
+chain 1023 chr6_mann_hap4 4683263 + 4007334 4007366 chr9 140273252 + 86970417 86970449 7865338
+32
+
+chain 1010 chr6_mann_hap4 4683263 + 4082082 4082129 chr3 199501827 + 184810220 184810267 11973355
+47
+
+chain 998 chr6_mann_hap4 4683263 + 3886377 3886573 chrX 154913754 - 91757557 91757751 5295832
+36 35 33
+55 3 3
+67
+
+chain 990 chr6_mann_hap4 4683263 + 4007430 4007464 chr4 191273063 + 5326352 5326386 2516557
+34
+
+chain 984 chr6_mann_hap4 4683263 + 4072955 4073012 chr5 180857866 - 58582170 58582227 6154457
+57
+
+chain 967 chr6_mann_hap4 4683263 + 2573177 2573236 chr6 170899992 + 103362020 103362079 14394857
+59
+
+chain 965 chr6_mann_hap4 4683263 + 3891326 3891365 chr9 140273252 + 71286813 71286852 2824412
+39
+
+chain 945 chr6_mann_hap4 4683263 + 3694820 3694851 chr14 106368585 - 6650576 6650607 2401116
+31
+
+chain 927 chr6_mann_hap4 4683263 + 2572422 2572476 chr15 100338915 - 47557741 47557795 3382810
+54
+
+chain 920 chr6_mann_hap4 4683263 + 1157878 1157917 chr16 88827254 - 23604715 23604754 19693069
+39
+
+chain 898 chr6_mann_hap4 4683263 + 4081045 4081072 chr22 49691432 - 26647849 26647876 3840718
+27
+
+chain 895 chr6_mann_hap4 4683263 + 3891777 3891813 chr14 106368585 - 61283307 61283343 2761593
+36
+
+chain 893 chr6_mann_hap4 4683263 + 2570451 2570505 chr3 199501827 + 23577885 23577939 11107673
+54
+
+chain 890 chr6_mann_hap4 4683263 + 3892242 3892300 chr1 247249719 - 65356530 65356588 2061731
+58
+
+chain 880 chr6_mann_hap4 4683263 + 2570034 2570140 chr20 62435964 - 37396821 37396927 8091728
+106
+
+chain 869 chr6_mann_hap4 4683263 + 3887839 3887907 chr6 170899992 + 169492007 169492075 20963963
+68
+
+chain 868 chr6_mann_hap4 4683263 + 3891249 3891286 chrX 154913754 - 77282087 77282124 4725533
+37
+
+chain 836 chr6_mann_hap4 4683263 + 3890695 3890723 chrX 154913754 + 120843366 120843394 2304611
+28
+
+chain 836 chr6_mann_hap4 4683263 + 2570399 2570451 chr6 170899992 - 98122344 98122396 3449700
+52
+
+chain 827 chr6_mann_hap4 4683263 + 3855371 3855442 chr15 100338915 - 22701000 22701071 11814601
+71
+
+chain 815 chr6_mann_hap4 4683263 + 2572376 2572422 chr8 146274826 - 36260073 36260119 3779418
+46
+
+chain 812 chr6_mann_hap4 4683263 + 2571127 2571156 chr4 191273063 + 177039024 177039053 12879824
+29
+
+chain 785 chr6_mann_hap4 4683263 + 2569744 2569799 chr10 135374737 - 48892377 48892432 10678423
+55
+
+chain 771 chr6_mann_hap4 4683263 + 2573374 2573466 chr4 191273063 - 179199127 179199219 9189435
+92
+
+chain 767 chr6_mann_hap4 4683263 + 2511738 2511768 chr12 132349534 + 6687829 6687859 23736981
+30
+
+chain 753 chr6_mann_hap4 4683263 + 3873530 3873605 chr13 114142980 + 107345301 107345376 25181199
+75
+
+chain 746 chr6_mann_hap4 4683263 + 2572477 2572521 chrX 154913754 + 101830803 101830847 3498092
+44
+
+chain 715 chr6_mann_hap4 4683263 + 3891220 3891248 chr1 247249719 - 137161636 137161664 4268110
+28
+
+chain 711 chr6_mann_hap4 4683263 + 3892346 3892371 chr5 180857866 - 112926636 112926661 14369717
+25
+
+chain 705 chr6_mann_hap4 4683263 + 3891557 3891590 chr20 62435964 + 38686583 38686616 3341082
+33
+
+chain 701 chr6_mann_hap4 4683263 + 4158699 4158752 chr6 170899992 + 104136271 104136324 24904048
+53
+
+chain 698 chr6_mann_hap4 4683263 + 3885778 3885835 chrX 154913754 - 89052462 89052519 24703469
+57
+
+chain 694 chr6_mann_hap4 4683263 + 3890564 3890590 chr20 62435964 + 53857851 53857877 2569420
+26
+
+chain 686 chr6_mann_hap4 4683263 + 4080461 4080493 chr9 140273252 + 6612523 6612555 3647698
+32
+
+chain 684 chr6_mann_hap4 4683263 + 2569065 2569115 chr10 135374737 + 37248665 37248715 24627179
+50
+
+chain 630 chr6_mann_hap4 4683263 + 3887534 3887605 chr7 158821424 + 132658309 132658380 10507147
+71
+
+chain 626 chr6_mann_hap4 4683263 + 2571287 2571318 chr20 62435964 - 10143997 10144028 3304786
+31
+
+chain 604 chr6_mann_hap4 4683263 + 1158203 1158229 chrX 154913754 - 101148638 101148664 11583043
+26
+
+chain 598 chr6_mann_hap4 4683263 + 2573593 2573648 chr4 191273063 - 105845249 105845304 24500343
+55
+
+chain 587 chr6_mann_hap4 4683263 + 4081958 4081983 chr17 78774742 + 38379379 38379404 3048972
+25
+
+chain 582 chr6_mann_hap4 4683263 + 1229585 1229648 chrX 154913754 - 143767987 143768050 25106055
+63
+
+chain 511 chr6_mann_hap4 4683263 + 1158055 1158090 chr3 199501827 + 56593596 56593631 24560538
+35
+
+chain 500 chr6_mann_hap4 4683263 + 3810617 3810668 chr2 242951149 - 179547194 179547245 25332432
+51
+
+chain 484 chr6_mann_hap4 4683263 + 3874010 3874062 chr2 242951149 - 202196458 202196510 23986516
+52
+
+chain 477 chr6_mann_hap4 4683263 + 4080303 4080328 chr1 247249719 + 23702472 23702497 3860771
+25
+
+chain 433 chr6_mann_hap4 4683263 + 3970685 3970735 chr12 132349534 + 80047789 80047839 27634717
+50
+
+chain 409 chr6_mann_hap4 4683263 + 2572208 2572259 chr12 132349534 + 9890446 9890497 14217469
+51
+
+chain 405 chr6_mann_hap4 4683263 + 3838348 3838386 chr6 170899992 + 85325597 85325635 11867781
+38
+
+chain 400 chr6_mann_hap4 4683263 + 2570347 2570381 chr20 62435964 + 18791073 18791107 4207227
+34
+
+chain 399 chr6_mann_hap4 4683263 + 3891365 3891391 chr14 106368585 - 67199393 67199419 2293377
+26
+
+chain 392 chr6_mann_hap4 4683263 + 2573293 2573343 chr7 158821424 + 83182800 83182850 10714169
+50
+
+chain 389 chr6_mann_hap4 4683263 + 2574727 2574788 chr5 180857866 + 78276420 78276481 6835510
+61
+
+chain 320 chr6_mann_hap4 4683263 + 2572172 2572208 chrX 154913754 - 2978832 2978868 15103888
+36
+
+chain 315 chr6_mann_hap4 4683263 + 2572091 2572150 chr12 132349534 + 56700130 56700189 16626895
+59
+
+chain 314 chr6_mann_hap4 4683263 + 3838291 3838335 chr7 158821424 + 152689672 152689716 19362320
+44
+
+chain 313 chr6_mann_hap4 4683263 + 3838601 3838636 chr8 146274826 + 137657008 137657043 12505292
+35
+
+chain 281 chr6_mann_hap4 4683263 + 2568901 2568956 chr11 134452384 - 27880406 27880461 26521414
+55
+
+chain 157 chr6_mann_hap4 4683263 + 4157054 4157110 chr2 242951149 - 84321569 84321625 30149802
+56
+
+chain 327477534 chr6_mcf_hap5 4833398 + 0 4833398 chr6 170899992 + 28804582 33467620 43
+932 3 0
+804 0 1
+2406 2 0
+88370 0 6
+2011 17 17
+871 93 85
+100 12 14
+2623 33 29
+3737 1 1
+39 1 1
+3903 2 0
+844 0 1
+5198 0 1
+2452 0 1
+14547 0 1
+603 2 0
+4648 0 3
+887 2902 2902
+668 1 0
+3862 0 6
+1025 160 0
+3444 3 0
+1791 1 0
+2207 0 3
+1827 1 0
+3220 9 0
+5157 0 4
+1394 1 0
+279 0 2
+71 0 4
+163 1 1
+31 1 1
+280 8 0
+1059 0 2
+1373 40 40
+402 1 0
+642 1 3
+746 0 2
+1268 2 0
+267 0 1
+1868 1 1
+44 1 1
+8066 7328 7328
+1695 2 1
+4264 0 1
+3195 0 2
+2504 39 38
+70 1 1
+1649 1 0
+953 0 1
+295 1 1
+32 0 6
+661 4 0
+5298 1 0
+1243 1 0
+122 0 1
+6151 2 0
+1123 0 9
+2073 1 0
+611 1 0
+1053 5 5
+71 0 3
+562 11 11
+8681 53599 53599
+1476 0 3
+3442 1 1
+61 1 1
+472 1 0
+1606 1 0
+2825 1 1
+15 1 1
+2498 1 0
+1445 2 0
+3490 0 1
+31 1 1
+4168 1 0
+4249 0 3
+27 0 1
+660 1 3
+1336 2 1
+3805 1 1
+20 1 1
+2330 0 4
+782 0 3
+3397 0 3
+46 1 2
+2599 7 0
+167 0 1
+670 8 0
+686 13 15
+1313 1 1
+41 1 1
+5555 1 1
+31 1 1
+5562 0 11
+82 1 1
+1227 0 1
+1556 1 0
+817 2 0
+22 8 0
+11441 0 4
+2264 0 2
+2164 0 6
+5363 1 1
+20 1 1
+45 1 0
+1351 1 0
+1292 0 2
+6063 8 1
+3826 10 0
+7034 0 8
+1703 6 6
+72 20447 20447
+2264 0 3
+5437 5 0
+3414 35 35
+12896 0 4
+3018 1 1
+24 1 1
+2310 7 7
+11460 1 1
+28 1 1
+2157 0 4
+46 8 0
+8748 6 0
+8539 1 0
+753 1 2
+651 8 8
+7720 1 0
+2972 1 0
+6912 1 1
+26 1 1
+7721 68853 68853
+7209 1 0
+313 21 0
+2014 2 0
+631 1 1
+120 1 1
+1202 1 1
+84 0 1
+1481 10 0
+785 34 0
+493 0 2
+283 11 1
+513 67 67
+212 16 16
+1192 0 1
+3112 1 0
+25400 9 9
+6993 1 0
+675 1 0
+20032 0 3
+2544 0 318
+1507 2 0
+313 4 0
+2659 1 1
+25 1 1
+1461 4 1
+364 1 1
+33 1 1
+1003 0 1
+1656 1 1
+42 1 1
+3874 2 0
+149 0 1
+6897 0 3
+40 1 1
+1374 1 0
+5757 5 0
+1254 17 17
+2864 0 143
+4107 0 6
+5270 8989 8989
+14121 1 0
+19254 2 0
+7864 2 0
+635 1 0
+39010 1 0
+13943 1 1
+32 1 1
+509 1 1
+73 1 1
+5335 22 16
+1218 1 0
+1638 6 6
+228 1 1
+45 1 1
+2048 0 1
+463 1 0
+24243 1 1
+19 1 1
+7240 22 0
+3284 1 1
+29 1 1
+8552 0 4
+3962 7 16
+474 1 1
+31 1 1
+549 2 0
+5745 1 0
+5097 1 0
+34650 0 1
+16931 0 1
+2053 1 7
+1384 3 1
+442 3 4
+1804 1 1
+101 1 1
+1465 2 0
+1230 2 0
+3399 0 8
+743 0 1
+502 0 1
+732 0 1
+5371 0 1
+1633 6 5
+4859 0 1
+3043 0 1
+1108 0 2
+1448 1 0
+2959 10 10
+6054 0 4
+1927 18 24
+890 1 1
+16 1 0
+2617 2 0
+4921 1 0
+570 2 0
+8231 1 1
+25 1 0
+1193 0 11
+350 0 1
+4470 1 1
+41 1 1
+942 4 5
+1892 0 5
+15 1 1
+2144 1 1
+194 1 1
+938 0 1
+141 5 5
+237 3 8
+99 31 31
+53 11 0
+364 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+67 16 16
+244 1 1
+54 5 5
+929 1 1
+21 1 1
+126 0 3
+830 0 14
+56 1 1
+525 0 2
+782 15 15
+810 1 0
+272 8 8
+145 1 1
+89 1 1
+592 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 1 1
+39 1 1
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+240 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+345 1 1
+39 1 1
+504 18 18
+662 1 1
+74 1 1
+248 1 1
+34 1 1
+1507 0 10
+1051 0 2611
+680 0 1
+1537 0 19
+74 1 0
+137 50 11
+112 0 18
+24 1 1
+1927 13 13
+1082 15046 15046
+185 0 1
+70 1 1
+2835 4 4
+163 15 15
+685 0 1
+1508 1 0
+533 14 0
+441 0 13
+2121 1 1
+40 1 1
+2754 0 4
+37 1 1
+144 8 8
+1040 2 0
+28 1 1
+229 12 12
+201 13 13
+169 19 20
+118 10 12
+1257 0 2
+243 16 16
+73 1 1
+21 1 1
+201 0 14
+116 1 1
+29 1 1
+536 1 0
+1159 0 32
+23 1 1
+674 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 2
+713 7 7
+89 1 0
+293 9 8
+350 6 6
+145 1 1
+41 1 1
+681 1 1
+43 1 1
+1121 16 16
+964 17 17
+198 0 7
+105 1 1
+40 1 1
+95 13 13
+247 1 1
+19 1 1
+2044 7 8
+2512 0 15
+2982 4 0
+3135 1 2
+1698 13 13
+15862 0 1
+925 0 191
+23 15 1
+23 0 1
+25 1 1
+7717 1 1
+40 1 1
+758 1 1
+46 1 1
+5530 11 9
+3326 1 1
+37 1 1
+2148 2 1
+4594 0 4
+7923 1 1
+26 5 5
+3475 24 0
+8 1 1
+566 4 0
+141 0 1
+2078 24 24
+171 18 18
+2570 0 6
+1709 4 0
+3265 0 2
+2235 17 16
+2946 0 372
+2644 31 31
+92 1 1
+35 1 1
+705 321 0
+3157 40 40
+718 0 4
+787 1 1
+34 1 1
+927 4 4
+103 0 8
+2376 0 1
+993 1 1
+31 1 1
+2654 1 1
+44 1 1
+208 4 1
+1022 11763 11699
+85 98 98
+60 2515 8169
+103 11 11
+41 1 1
+72 4 4
+76 1 1
+70 5 5
+83 1 1
+117 1 1
+130 1 1
+44 1 1
+414 1 1
+152 1 0
+218 1 1
+161 1 0
+120 14 14
+145 1 1
+49 4 4
+72 1 1
+53 19 19
+111 2 2
+32 3 3
+554 0 1
+336 12 12
+54 24 24
+171 0 6
+90 1 1
+28 1 1
+142 16 16
+36 1 1
+428 1 1
+16 1 1
+338 1 1
+31 1 1
+294 1 1
+92 0 1
+129 13 14
+602 1 1
+112 1 1
+247 1 1
+80 1 1
+173 1 1
+44 1 5
+497 1 1
+38 1 1
+98 1 1
+130 1 1
+319 1 1
+16 1 1
+59 1 1
+82 1 1
+141 1 1
+23 1 1
+241 1 1
+26 1 1
+109 3 3
+72 0 3
+19 1 1
+510 1 1
+36 1 1
+162 2 2
+15 1 1
+145 1 1
+28 1 1
+120 0 3
+93 1 2
+24 0 9
+169 12 0
+292 9911 10000
+401 1 1
+27 1 1
+296 1 1
+120 1 1
+357 1 1
+107 2 0
+31 1 1
+83 89 0
+194 1 1
+33 1 1
+230 1 1
+142 5 5
+108 1 1
+36 1 1
+287 1 1
+19 1 1
+104 1 1
+31 1 1
+144 1 1
+212 1 1
+452 5 6
+148 1 1
+70 1 1
+137 3 3
+67 1 1
+73 22 22
+115 12 12
+142 5 5
+269 15 15
+102 6 6
+93 1 1
+82 1 1
+170 1 1
+22 1 1
+504 2 2
+60 1 1
+150 1 1
+31 1 1
+90 1 1
+15 1 0
+258 6 7
+85 1 1
+77 1 1
+123 2 2
+67 0 1
+56 2 2
+25 1 1
+71 1 1
+28 2 2
+50 1 1
+85 2 2
+66 6 6
+186 1 1
+20 1 1
+67 1 1
+25 1 1
+227 2 2
+155 1 1
+777 1 1
+33 1 2
+26 6 6
+474 1 1
+36 1 1
+151 1 1
+29 1 1
+120 1 1
+23 1 1
+736 127279 40017
+51 5 5
+45 1 1
+53 1 1
+37 1 1
+81 1 1
+369 1 1
+72 15 15
+98 1 1
+53 0 8
+67 2 0
+41 1 1
+92 1 1
+20 1 1
+283 6 6
+70 7 7
+50 1 1
+25 1 1
+225 5 1
+31 1 1
+449 2 1
+10 1 23
+64 4 4
+832 1 0
+492 1 0
+587 0 15
+1821 1 1
+22 1 0
+36 1 1
+73 1 1
+38 1 1
+318 1 1
+20 1 1
+176 13 13
+216 1 1
+17 1 1
+515 0 1
+704 0 4
+153 1 1
+44 1 1
+538 1 1
+30 1 1
+411 0 8
+419 1 1
+34 1 1
+66 15 15
+308 1 1
+49 1 1
+484 1 1
+50 10 8
+1019 17 5
+132 1 1
+50 2 1
+38 1 1
+736 0 1
+50 1 1
+50 1 1
+23 2 1
+156 0 1
+385 15 15
+207 1 1
+92 1 1
+415 1 1
+43 1 1
+52 5 5
+223 2 0
+31 4 0
+17 3 27
+88 13 1
+308 1 1
+43 2 2
+186 0 4
+153 1 1
+69 0 3
+14 1 1
+159 1 1
+92 1 1
+62 1 1
+27 1 1
+443 10 10
+77 1 1
+51 1 1
+604 1 1
+35 1 1
+703 1 1
+32 1 1
+1452 4 0
+259 1 1
+40 1 1
+130 1 1
+87 1 1
+164 105 105
+64 14 15
+87 1 1
+30 1 1
+123 2 2
+91 0 3
+95 1 1
+67 10 0
+631 1 3
+315 1 1
+31 1 1
+315 1 1
+25 3 3
+80 3 0
+45 1 1
+511 1 1
+57 1 1
+3565 0 12
+39 0 1
+5674 16 0
+1327 0 1
+7941 1 1
+26 1 1
+13472 1 1
+48 1 1
+4441 19 0
+741 0 1
+8053 0 1
+3976 1 0
+10503 0 1
+5525 0 2
+306 1 0
+3902 17 4
+3077 0 4
+207 2 0
+1984 8 0
+686 2 0
+10068 0 3
+32266 0 2
+428 0 1
+3832 0 12
+8454 1 0
+524 1 1
+59 1 1
+112 3 3
+50 1 1
+267 0 4
+1464 2 0
+1003 0 1
+4062 1 0
+3850 4 0
+4977 0 1
+2718 1 0
+1588 1 1
+30 4 0
+879 0 1
+1332 18 12
+1688 4 4
+88 1 1
+439 2 0
+209 1 0
+1322 54 54
+893 1 1
+49 1 2
+1773 1 1
+24 1 1
+540 1 1
+41 1 1
+460 1 7
+165 1 1
+45 1 1
+903 1 2
+140 0 1
+36 1 1
+2019 0 1
+657 1 1
+48 1 0
+1329 0 1
+268 1 1
+47 1 1
+336 1 1
+25 2 0
+43 1 1
+1484 1 1
+53 1 1
+1151 1 1
+42 1 1
+1870 1 1
+24 5 5
+853 0 3
+23 0 1
+326 9 9
+131 9 9
+623 0 3
+34 1 1
+809 1 1
+36 1 1
+690 2 0
+44 1 1
+285 8 7
+455 1 1
+32 1 1
+102 1 1
+47 1 1
+4338 0 1
+5273 0 4
+11552 1 0
+409 16 17
+3476 0 1
+2160 0 24
+109 1 1
+3284 0 19
+2586 2 0
+757 1 1
+22 1 1
+860 17 24
+1584 1 0
+1582 0 2
+117 1 0
+1552 3 25
+17 0 4
+16 2 0
+6 10 0
+40 9 0
+10 8 0
+10605 1 0
+4733 1 3
+370 2 0
+1305 0 1
+518 6 0
+646 13 13
+469 1 0
+1072 1 4
+404 163747 163747
+942 4 0
+68 13 1
+2539 25 19
+1982 6 0
+5362 0 9
+10293 1 1
+98 1 1
+1006 1 1
+44 1 1
+518 1 1
+26 0 4
+185 0 1
+30 1 0
+19 1 1
+599 1 1
+22 1 1
+218 1 1
+49 1 1
+362 0 1
+852 0 2
+1066 0 2
+811 21 21
+1434 1 1
+27 1 1
+2116 1 1
+25 1 1
+82 7 7
+625 0 1
+1756 4 4
+93 1 1
+26 1 1
+320 0 3
+2150 1 1
+41 1 1
+1091 2 1
+8378 0 1
+2212 0 2
+671 1 0
+4088 1 1
+34 1 1
+2520 0 1
+1933 4 3
+2567 0 5
+1677 1 1
+29 1 1
+1829 12 0
+4788 13 0
+253 2 1
+204 0 1
+128 1 0
+4271 0 1
+6896 0 1
+2766 1 0
+2234 1 1
+52 1 1
+1098 1 1
+37 1 1
+3385 22337 22337
+10967 0 4
+6064 0 1
+10170 0 8
+17213 1 0
+6908 1 0
+328 1 0
+53416 3 2
+4463 1 0
+2057 0 1
+15162 1 0
+25886 3 1
+12500 29 0
+4926 0 1
+9038 0 1
+26499 0 1
+12538 0 1
+34918 97959 97959
+758 4 0
+150 1 0
+3128 1 0
+1300 0 1
+148 1 0
+1534 0 1
+488 0 1
+429 3 5
+299 2 0
+427 7 7
+1914 14 14
+1556 1 1
+28 1 1
+1138 78 0
+409 0 1
+985 22 23
+2430 1 0
+190 8 8
+2034 3 1
+5337 42 42
+1017 1 1
+34 1 1
+485 1 0
+348 7 0
+770 1 1
+8 1 0
+22 0 13
+64 1 1
+1358 0 1
+302 0 1
+964 0 1
+610 0 1
+906 12 0
+1331 0 8
+1784 0 1
+463 0 1
+4305 0 4
+1041 1 0
+11424 3 1
+530 10174 10174
+1857 0 1
+1230 0 8
+1682 5 0
+9069 0 8
+25 1 1
+330 5 5
+76 0 1
+1306 1 1
+46 1 1
+134 19 23
+1467 1 1
+32 1 1
+449 17 0
+367 9 9
+3525 12 10
+105 7 4
+208 33 33
+1171 1 1
+24 1 1
+1156 9 13
+841 3 3
+28 1 1
+515 0 17
+1559 0 4
+1045 9 9
+1953 1 0
+31 1 1
+843 0 1
+2174 1 0
+3788 1 0
+6017 1 0
+5658 4797 4797
+413 2 0
+2735 0 1
+941 4 0
+7767 0 1
+17211 5 0
+7531 0 1
+5505 1 2
+3443 0 2
+24240 1 1
+33 1 1
+4777 4 2
+43 3 0
+1254 0 1
+16 1 1
+1411 0 4
+424 1 1
+51 1 1
+113 1 1
+34 1 1
+344 9 9
+15845 1 0
+1155 1 0
+1648 0 16
+2071 0 9
+25450 1 0
+7543 4 10
+744 1 0
+564 2 0
+16701 3 0
+9132 1 1
+49 1 1
+146 1 1
+61 1 1
+116 1 1
+41 1 1
+137 1 1
+30 1 1
+158 9 9
+136 10 13
+973 6 6
+547 1 1
+41 1 1
+164 17 17
+1053 4 4
+228 1 1
+34 1 1
+355 1 1
+113 1 1
+330 0 1
+222 1 1
+25 1 1
+267 1 1
+38 1 1
+709 2 0
+1448 0 1
+152 1 1
+46 1 1
+237 1 1
+20 1 1
+211 5 5
+88 1 1
+33 1 1
+211 1 1
+65 1 1
+516 58 58
+491 7 7
+208 13 12
+558 2 2
+28 1 1
+125 4 4
+1853 21 0
+845 6 6
+2005 0 1
+148 1 1
+36 1 1
+993 1 0
+3580 10 10
+1203 1 0
+530 5 5
+216 1 1
+32 1 1
+312 1 1
+44 1 1
+1934 14 14
+1149 0 8
+835 1 1
+29 0 1
+2324 1 1
+18 1 1
+1273 27 27
+104 1 1
+21 1 1
+53 8 8
+1631 1 1
+16 1 1
+429 8 16
+1419 23 23
+256 1 0
+40 1 1
+106 1 1
+21 1 1
+501 2 2
+40 1 1
+2249 1 1
+189 0 1
+180 14 1
+1272 17 17
+345 0 2
+1504 14 0
+1689 4 0
+3174 16 16
+607 4 34
+41 0 5
+669 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+466 1 1
+31 3 0
+321 0 1
+281 3 0
+450 1 1
+34 1 1
+498 1 1
+28 2 1
+280 0 1
+649 1 1
+47 1 1
+1002 4 0
+120 1 1
+533 7 7
+998 0 1
+75 1 1
+37 1 1
+582 19 19
+60 18 18
+4194 0 2
+216 1 1
+112 1 1
+129 4 0
+87 1 1
+160 1 1
+49 1 1
+147 18 14
+128 1 1
+37 1 1
+865 4 0
+160 1 1
+35 1 1
+1119 1 1
+13 0 3
+242 1 1
+23 1 1
+1705 0 4
+103 0 1
+1117 2 0
+67 1 1
+1825 0 1
+855 8 0
+1368 3 0
+320 1 1
+149 1 1
+97 1 1
+15 1 1
+371 1 1
+165 1 1
+61 1 1
+32 0 2
+5 1 1
+1520 1 1
+28 1 1
+367 4 0
+267 13 13
+175 1 0
+225 1 1
+45 1 1
+797 1 1
+142 1 0
+38 0 2
+318 8 7
+50 1 1
+29 1 1
+376 4 9
+548 1 1
+57 1 1
+665 4 0
+1690 17 17
+208 6 6
+398 13 13
+63 1 1
+80 1 1
+57 1 1
+61 1 1
+170 1 1
+56 1 1
+93 1 1
+106 1 1
+41 1 1
+68 12 7
+13 4 0
+68 1 1
+76 1 1
+658 11 11
+447 4 4
+385 1 1
+35 1 1
+108 1 1
+37 4 0
+304 1 1
+70 1 0
+1242 12 12
+371 50 8
+386 2 0
+29 1 1
+204 1 1
+80 1 1
+112 12 11
+315 7 7
+97 0 2
+1756 1 1
+38 1 1
+106 23 23
+125 20 0
+1226 1 0
+16 5 0
+21 1 1
+235 10 10
+181 1 1
+72 1 1
+51 5 1
+43 5 7
+485 7 7
+127 1 1
+140 1 1
+105 5 6
+18 1 1
+88 1 1
+190 1 1
+68 10 10
+323 1 1
+59 4 0
+1507 3 0
+123 1 1
+73 1 1
+137 16 16
+132 1 1
+131 2 0
+5 0 3
+76 1 1
+40 1 1
+273 9 10
+172 1 1
+76 1 1
+98 1 1
+57 1 1
+54 1 0
+16 1 1
+66 1 1
+36 1 1
+120 1 1
+77 0 1
+34 1 1
+102 1 1
+41 1 1
+126 6 7
+1059 0 1
+1067 0 12
+1292 1 0
+744 0 4
+990 2 2
+58 1 1
+45 0 1
+308 1 1
+49 0 1
+21 1 1
+700 1 0
+973 2 0
+548 0 2
+982 10 0
+242 1 1
+38 1 1
+1067 3 0
+618 7 7
+1893 44 43
+731 2 2
+49 1 1
+908 9 9
+484 0 2
+128 0 1
+174 15 18
+175 1 1
+16 1 1
+332 1 1
+22 1 1
+554 0 1
+120 1 1
+31 1 1
+351 5 0
+80 1 0
+76 1 1
+39 1 1
+1447 1 0
+1072 1 1
+43 0 4
+43 1 1
+393 0 1
+1820 6 6
+457 1 1
+18 1 1
+87 1 1
+30 1 1
+861 1 1
+20 1 1
+1057 23 23
+416 0 24
+779 1 1
+17 1 2
+37 1 1
+1675 1 1
+27 1 1
+901 0 8
+47 1 1
+262 0 3
+57 1 1
+29 0 1
+234 0 3
+45 1 1
+250 1 1
+18 1 1
+517 33 0
+117 1 1
+55 1 1
+537 1 1
+20 1 1
+671 1 1
+68 1 1
+89 1 1
+104 1 1
+172 0 1
+124 0 1
+522 0 1500
+466 5 5
+32 1 0
+171 1 1
+19 1 1
+67 1 1
+22 1 1
+654 1 1
+25 1 1
+68 1 1
+21 4 0
+1588 1 1
+66 1 1
+401 0 1
+186 1 1
+21 1 1
+168 0 1
+601 1 1
+29 1 1
+36 4 0
+37 1 1
+127 1 1
+29 1 1
+404 0 2
+710 1 1
+89 1 1
+161 16 16
+405 1 1
+39 3 3
+56 1 1
+82 1 1
+71 1 1
+37 0 4
+104 1 1
+89 1 1
+64 1 1
+102 1 1
+130 15 16
+158 8 0
+57 1 1
+731 1 1
+65 1 1
+313 1 1
+44 1 0
+52 20006 20030
+60 8 8
+61 1 1
+120 1 1
+366 1 1
+55 1 1
+121 1 1
+62 1 1
+127 1 1
+18 1 1
+142 1 1
+26 1 1
+149 1 1
+62 11 11
+550 1 1
+76 1 0
+20 1 1
+112 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+1631 1 1
+47 1 1
+244 3 3
+22 3 3
+1486 0 3
+196 6 6
+63 1 1
+70 1 1
+325 14 19
+220 0 1
+773 1 1
+35 1 1
+153 1 1
+57 1 1
+123 1 1
+45 0 1
+15 1 1
+270 1 1
+48 1 1
+101 16 16
+64 1 1
+124 1 1
+1429 25 25
+184 0 1
+4315 4 4
+1530 4 0
+1062 1 1
+43 1 1
+55 14 14
+853 12 12
+2313 13 13
+537 9 0
+1430 1 1
+48 1 1
+400 1 1
+100 1 1
+148 19 19
+152 1 1
+25 1 1
+70 1 1
+102 1 1
+158 1 1
+56 2 2
+57 1 1
+10 5 10
+24 2 0
+71 1 1
+54 1 1
+73 1 1
+85 1 1
+105 1 1
+117 2 2
+29 1 1
+92 2 2
+42 0 1
+154 1 1
+10 1 0
+47 4 5
+35 1 1
+56 1 1
+64 3 3
+67 5 5
+72 1 1
+60 1 1
+45 1 1
+82 1 1
+95 2 2
+161 1 1
+301 1 1
+67 1 0
+430 1 1
+105 10 10
+38 0 4
+386 11 11
+101 3 2
+117 0 2
+77 1 1
+481 0 2
+67 1 1
+45 1 1
+503 1 1
+34 1 1
+359 1 1
+35 1 1
+534 11 11
+1738 1 1
+26 1 1
+506 19 0
+356 1 1
+138 0 3
+1403 13 13
+1045 1 1
+24 1 1
+879 1 1
+73 1 1
+89 1 1
+42 1 1
+108 1 1
+19 1 5
+41 0 1
+4 1 1
+511 5 6
+605 1 1
+47 1 1
+73 1 1
+62 1 1
+1912 49303 50027
+638 99452 99452
+4150 1 1
+31 0 1
+6 1 1
+163 1 1
+22 1 1
+81 1 1
+27 1 1
+548 1 1
+61 1 1
+1169 1 1
+41 1 1
+6471 1 1
+62 1 1
+530 17 17
+394 1 1
+40 7 0
+57 12 12
+69 2 2
+39 1 1
+70 1 1
+22 0 3
+2796 1 1
+58 1 1
+375 25 27
+1218 1 1
+35 1 1
+85 1 1
+20 6 0
+687 1 1
+34 1 1
+355 1 1
+47 1 0
+51 69 69
+73 1 1
+48 1 1
+218 1 1
+42 1 1
+197 1 1
+41 1 1
+313 1 1
+40 1 1
+476 1 1
+29 1 1
+185 1 1
+35 1 1
+594 1 1
+24 1 1
+219 2 0
+246 0 1
+261 4 4
+43 1 1
+54 1 1
+130 1 1
+184 1 1
+201 1 1
+306 1 1
+29 5 5
+121 1 1
+31 1 1
+109 1 1
+25 1 1
+168 1 1
+19 1 1
+104 1 0
+132 1 0
+113 1 1
+30 1 1
+56 9 9
+300 1 1
+50 2 2
+96 1 1
+43 1 1
+76 1 1
+44 1 1
+197 1 1
+38 2 1
+52 0 2
+18 1 1
+99 0 9
+392 5 5
+89 1 1
+399 1 1
+35 3 4
+260 1 1
+23 1 0
+10 1 1
+70 1 1
+65 2 0
+17 0 18
+28 1 1
+208 1 1
+70 1 1
+149 0 3
+243 1 1
+55 1 1
+63 17 17
+1208 1 1
+98 1 1
+58 1 1
+43 1 1
+59 1 1
+45 1 1
+148 70 70
+209 4 4
+1242 1 1
+42 5 0
+87 1 1
+522 0 3
+305 0 1
+1379 0 2
+390 0 15
+72 1 1
+16 1 1
+270 1 0
+280 7 7
+2763 20 20
+674 10 10
+1375 8 0
+294 142 141
+145 1 1
+35 1 1
+447 16 16
+54 4 4
+680 16 16
+1123 4 4
+1075 1 1
+46 1 1
+282 1 1
+39 1 1
+860 1 1
+26 1 1
+745 0 2
+2081 2 0
+817 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+135 5 0
+1169 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+16 1 4
+1404 0 1
+450 4 0
+626 1 0
+304 1 1
+39 1 1
+564 1 1
+45 1 1
+303 2 0
+409 1 1
+18 1 0
+858 3 0
+2168 0 1
+54 22 22
+220 1 1
+48 1 1
+254 0 1
+523 0 13
+2423 18 14
+64 1 1
+30 2 2
+185 0 4
+966 16 16
+123 11 11
+531 1 1
+20 1 1
+227 1 1
+37 1 1
+636 3 4
+8239 1 1
+23 1 1
+1114 0 2
+688 0 1
+901 18 18
+4781 0 4
+815 0 1
+5069 0 5
+415 0 1
+353 0 1
+1087 9 9
+108 30 30
+144 1 0
+817 1 0
+194 10 10
+460 0 1
+327 0 1
+878 0 1
+854 0 1
+4897 0 2
+1554 1 1
+60 1 1
+278 0 1
+19 1 1
+1866 0 1
+961 0 3
+60 0 18
+2122 0 2
+19 1 1
+1232 0 2
+1641 2 0
+10831 3 2
+188 0 1
+1650 3 6
+2842 0 4
+146 2 0
+4952 0 2
+4944 1 0
+1024 0 1
+803 11423 11423
+1739 0 4
+852 5 6
+1925 15 15
+1657 1 0
+378 0 2
+968 1 0
+1174 0 4
+663 6 0
+297 0 3
+2049 0 5
+876 11 11
+12081 1 1
+33 1 1
+1932 0 1
+398 1 1
+145 1 1
+3667 0 4
+1305 0 10
+3035 1 0
+5554 6 0
+42067 0 1
+4121 2 0
+13331 4 0
+2404 8 8
+1698 0 2
+19856 4 0
+1616 0 1
+1686 0 2
+2223 0 4
+4741 12 0
+1921 0 1
+913 0 1
+3801 0 1
+2620 8 0
+12800 0 1
+2431 1 0
+158 0 1
+281 1 0
+12653 1 0
+6938 0 1
+14766 1 0
+1654 34221 34221
+3000 17 17
+689 0 3
+62 1 0
+5716 1 0
+456 1 0
+2077 2 0
+616 178 0
+14916 0 4
+672 1 1
+26 1 1
+461 1 1
+33 0 2
+16 1 1
+649 1 1
+48 1 1
+818 1 1
+21 1 1
+424 1 1
+25 1 1
+632 1 1
+39 1 1
+310 1 1
+27 1 1
+616 1 0
+17240 4 0
+3936 3 0
+3834 2 0
+426 1 0
+5704 1 1
+43 1 0
+622 0 1
+167 0 5
+1968 0 3
+258 2 0
+4089 1 0
+903 29 27
+1088 7 6
+290 3 3
+117 13 0
+2194 0 1
+191 0 1
+118 1 0
+2013 1 0
+7453 1 0
+3382 0 1
+1544 0 1
+634 0 49
+5260 0 1
+4607 1 0
+32465 1 0
+1323 1 0
+39 0 1
+5117 27143 27143
+480 9 9
+746 11 11
+29289 0 3
+99 1 1
+19 1 1
+259 1 1
+57 1 1
+105 0 1
+2134 9 9
+2299 1 1
+43 1 1
+1287 1 0
+22328 5 0
+47 8 0
+4444 2 0
+6495 0 16
+2128 0 1
+8355 0 3
+4114 0 1
+1404 0 1
+5139 0 2
+1840 2 0
+1214 6 6
+273 0 7
+653 10 10
+189 1 0
+27280 0 2
+615 1 0
+1600 0 1
+364 0 2
+1466 1 0
+6628 1 1
+110 0 1
+1422 0 1
+324 1 0
+173 0 1
+1651 1 0
+311 0 1
+10202 4 0
+3867 9 7
+19808 0 2
+4947 29 29
+1283 0 3
+14175 10 0
+29 1 1
+4509 43 43
+1259 1 0
+2089 1 2
+365 0 2
+3430 1 0
+159 0 4
+2886 28 0
+147 0 1
+1181 10 15
+206 3 4
+208 1 1
+25 1 1
+2194 1 1
+18 1 1
+3726 0 3
+34 1 1
+361 17 17
+6271 1 0
+4854 0 1
+1587 0 1
+9534 1 1
+50 1 0
+1082 1 1
+42 1 1
+639 1 0
+145 13 15
+557 11 11
+53 1 1
+61 1 1
+454 1 1
+26 1 1
+1053 1 1
+60 1 1
+51 1 1
+26 1 0
+102 1 1
+67 1 1
+71 1 1
+134 1 1
+85 1 1
+607 36 0
+58 1 1
+1266 2 0
+480 14 21
+1459 2 1
+435 15 17
+224 57380 57335
+2665 46 46
+554 0 21
+4473 2 3
+921 1 1
+47 1 1
+2605 9 3
+50 1 1
+178 1 1
+26 1 1
+316 0 2
+1120 4 0
+177 1 2
+1991 4 4
+783 8 8
+61 34 13
+121 1 1
+22 1 0
+118 1 1
+49 4 4
+217 1 1
+91 1 1
+958 0 1
+107 1 1
+31 1 1
+171 14 14
+302 0 13
+33 1 1
+108 0 4
+98 1 1
+53 1 1
+457 2 0
+529 1 1
+37 2 0
+1829 1 1
+38 1 1
+440 1 1
+82 3 4
+647 45 45
+660 1 1
+28 1 1
+1993 0 1
+373 19 19
+835 1 1
+42 1 1
+947 1 1
+36 1 0
+1055 1 1
+43 1 1
+475 1 0
+60 1 1
+127 1 1
+509 1 1
+71 1 1
+485 1 0
+26 1 1
+531 1 1
+18 1 1
+551 1 1
+18 1 1
+884 5 5
+147 53 60
+527 1 1
+26 2 2
+322 0 17
+32 2 2
+85 1 1
+45 1 1
+625 0 323
+540 0 1
+43 1 1
+266 0 2
+228 1 1
+42 1 1
+283 1 1
+92 1 1
+381 1 1
+40 1 1
+1906 0 4
+3495 0 4
+967 1 1
+76 1 1
+3236 4 4
+529 7 7
+246 4 0
+38 1 1
+156 0 6
+1466 0 2
+499 1 0
+937 1 1
+45 1 1
+421 6 0
+87 22 22
+1254 1 1
+36 0 1
+357 18 18
+391 0 1
+451 1 0
+105 1 1
+47 1 0
+255 6 6
+739 3 0
+386 1 1
+33 1 1
+281 5 0
+481 2 0
+495 1 1
+42 4 0
+219 0 1
+408 1 1
+23 1 1
+283 1 1
+25 0 1
+541 1 0
+88 2 0
+216 1 1
+29 1 1
+457 1 0
+331 9 3
+197 15 15
+228 1 0
+4 2 0
+333 0 1
+19 1 1
+1081 3 3
+35 1 1
+1211 1 1
+34 1 1
+667 0 2
+64 1 1
+78 1 1
+1519 1 1
+27 1 1
+154 14 14
+1090 1 1
+40 0 3
+35 1 1
+1355 0 4
+79 1 1
+145 1 1
+63 1 1
+70 1 1
+21 1 1
+695 1 1
+41 2 2
+564 1 1
+46 1 1
+279 4 0
+38 5 5
+3523 32 32
+545 1 1
+27 1 0
+54 15 16
+1212 0 14
+34 0 11
+787 2 0
+3691 1 0
+1843 1 1
+45 1 0
+11 1 2
+3499 1 1
+27 1 1
+1047 0 2
+1804 2 0
+1079 1 1
+17 1 1
+639 3 5
+73 1 1
+13 13 0
+66 1 1
+391 0 7
+4547 0 1
+53 9 6
+691 0 1
+989 1 1
+143 1 1
+223 0 2
+95 1 1
+1000 1 1
+41 1 1
+93 1 1
+49 1 1
+606 1 1
+48 1 1
+128 0 4
+109 1 31
+44 10 781
+62 4 0
+129 1 1
+62 1 1
+106 1 1
+247 1 1
+20 18 4
+125 1 1
+43 1 1
+909 0 2
+381 4 4
+74 1 1
+408 1 0
+1595 5 0
+3690 1 1
+64 1 1
+754 0 4
+1877 1 1
+49 1 1
+1095 11 0
+732 0 27
+3070 2 0
+1879 0 1
+572 0 8
+215 1 1
+58 1 1
+301 1 1
+42 1 1
+265 24 0
+209 11 11
+953 1 1
+42 0 5
+58 1 0
+95 1 0
+210 1 1
+27 1 1
+882 1 1
+17 1 1
+751 0 1
+24 1 1
+351 1 1
+43 3 3
+565 1 1
+15 1 1
+150 27 27
+94 1 0
+323 1 1
+23 1 1
+221 7 7
+705 15 0
+631 2 0
+64 1 1
+1577 1 1
+21 0 1
+354 0 10
+188 0 1
+283 1 1
+48 1 1
+227 1 1
+40 0 3
+1357 0 2
+1571 7 7
+1153 1 1
+93 1 1
+797 14 14
+433 8 0
+108 11 11
+140 1 1
+40 1 1
+470 1 1
+42 1 1
+1106 0 2
+84 4 4
+129 1 1
+123 1 0
+95 1 1
+82 0 3
+661 1 1
+77 1 1
+57 1 1
+62 1 1
+473 2 0
+262 6 0
+45 1 1
+49 3 0
+321 0 1
+197 2 104
+202 0 10
+92 0 4
+108 6 0
+563 14 14
+324 1 0
+205 1 1
+17 1 1
+495 0 1
+201 4 0
+14 1 1
+1080 1 1
+24 1 1
+91 24 24
+279 1 1
+95 1 1
+121 1 1
+62 1 1
+2371 1 0
+164 9 1
+655 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+1780 2 0
+742 1 1
+40 1 1
+272 1 1
+52 1 1
+1187 1 1
+23 1 1
+254 1 1
+60 1 1
+176 3 6
+463 1 1
+36 1 1
+797 1 1
+22 1 1
+395 5 2
+61 1 1
+31 3 3
+226 1 1
+59 1 1
+581 1 1
+46 1 1
+412 1 1
+23 1 0
+74 1 1
+17 1 1
+81 1 1
+24 1 1
+83 15 15
+363 1 1
+91 1 1
+383 20 20
+199 13 13
+976 1 1
+39 0 3
+161 14 15
+127 16 16
+517 1 1
+132 1 1
+167 28 28
+124 1 1
+68 0 22
+1074 0 1
+175 1 0
+1018 1 1
+90 4 4
+1034 15 15
+69 1 1
+33 1 1
+174 1 1
+56 1 1
+169 1 0
+201 1 1
+30 1 1
+58 1 1
+38 1 1
+91 1 1
+98 4 4
+65 1 1
+19 2 0
+104 6 5
+25 1 1
+218 1 1
+37 1 1
+343 110361 150022
+67 8 8
+36 0 11
+62 1 1
+107 1 1
+68 3 130
+66 4 4
+50 22 21
+98 1 1
+127 1 0
+192 1 1
+71 1 1
+52 1 1
+200 1 1
+307 0 1
+331 1 1
+97 11 11
+171 1 1
+61 1 1
+37 1 1
+156 3 0
+63 0 3
+155 4 1
+31 2 0
+232 1 1
+33 1 1
+175 2 0
+131 6 6
+1409 0 3
+180 1 1
+65 0 1
+703 1 1
+19 1 1
+254 1 1
+22 1 1
+424 1 1
+65 1 1
+532 1 1
+48 1 1
+347 0 12
+578 16 17
+965 1 1
+45 1 1
+893 57505 60106
+93 1 1
+75 808 0
+46 1 1
+221 1 1
+213 8 0
+63 1 1
+60 17 17
+53 1 1
+29 1 1
+68 8 8
+62 9 9
+51 1 1
+85 1 1
+101 1 1
+54 2 2
+116 1 1
+66 1 1
+182 1 0
+37 1 1
+134 14 14
+117 1 1
+45 1 1
+120 1 1
+47 1 1
+342 1 1
+46 1 1
+237 12 12
+107 8 8
+754 1 0
+880 1 1
+16 1 1
+491 1 1
+49 1 1
+192 1 1
+54 0 1
+19 2 2
+165 0 21
+26 1 1
+183 13 13
+72 1 1
+23 1 0
+268 14 14
+320 1 1
+55 1 1
+414 5 5
+172 0 1
+620 1 1
+18 1 1
+190 1 1
+20 0 8
+849 1 1
+29 1 1
+978 30198 30058
+159 1 1
+36 1 1
+107 1 1
+176 1 1
+154 0 5
+91 1 1
+54 1 1
+77 1 1
+239 1 1
+50 1 1
+128 1 1
+40 1 1
+173 11 11
+734 1 1
+31 1 1
+215 1 1
+108 1 1
+259 1 1
+79 1 1
+80 1 1
+47 3 1
+40 1 1
+54 1 1
+46 1 1
+118 9 9
+98 1 0
+5 11 4
+23 0 7
+84 1 1
+84 2 2
+6 0 1
+6 1 0
+110 0 7
+537 1 1
+96 1 1
+441 1 1
+101 1 1
+242 14 14
+255 16 16
+142 1 0
+345 10 10
+54 1 1
+26 1 1
+108 1 1
+83 1 1
+128 1 1
+36 1 1
+231 1 1
+37 1 1
+534 1 1
+60 1 1
+804 0 3
+43 1 1
+148 1 1
+25 1 1
+69 10 10
+76 5 5
+37 1 1
+66 0 2
+192 1 1
+60 3 0
+19 1 1
+1149 1 1
+18 1 1
+77 1 1
+32 2 0
+32 1 1
+136 1 1
+78 2 0
+1680 1 1
+39 0 1
+548 1 1
+50 1 1
+177 2 0
+340 1 1
+112 1 1
+422 10 10
+963 4 4
+329 1 9
+648 5 1
+117 1 1
+27 1 1
+574 1 0
+507 1 1
+39 1 1
+294 3 2
+549 1 1
+22 1 1
+74 0 1
+98 1 1
+65 3 3
+230 1 1
+18 1 0
+33 1 1
+51 1 1
+24 1 1
+811 1 1
+59 0 2
+8 1 1
+80 9 9
+437 14 14
+57 4 4
+588 15 15
+305 1 1
+17 1 1
+135 1 1
+50 1 1
+59 16 16
+129 1 1
+25 2 0
+12 1 1
+106 1 1
+31 1 1
+350 1 1
+47 1 1
+340 1 1
+65 1 1
+478 2 0
+714 8 7
+95 2 2
+52 2 1
+1129 1 1
+34 1 1
+1715 1 1
+87 1 1
+692 1 1
+47 0 1
+75 1 1
+2155 10 10
+1611 1 1
+22 1 1
+186 1 1
+34 1 1
+98 1 1
+47 1 1
+117 1 0
+185 1 1
+24 1 0
+98 0 2
+258 8 14
+967 1 1
+37 3 3
+502 1 1
+22 1 1
+75 0 3
+163 1 1
+40 1 1
+638 0 3
+150 1 1
+11 0 1
+29 1 1
+125 1 1
+78 1 1
+115 8 0
+1622 18 19
+1471 1 1
+30 1 1
+1580 73 73
+435 1 1
+60 1 1
+325 0 1
+254 1 1
+43 1 1
+181 14 0
+37 1 0
+47 1 1
+130 4 4
+34 1 1
+208 1 1
+39 2 2
+526 1 1
+36 1 1
+99 9 7
+20 1 1
+73 1 1
+62 1 1
+425 1 1
+43 1 1
+811 1 1
+38 1 1
+362 1 1
+49 1 1
+109 1 1
+19 1 1
+79 1 1
+29 0 1
+26 1 1
+252 1 1
+75 1 1
+467 1 1
+40 1 1
+389 13 13
+57 17 17
+544 1 1
+42 1 1
+597 0 311
+64 6 6
+568 1 1
+35 1 1
+62 1 1
+38 1 1
+79 1 0
+553 1 1
+30 1 1
+433 1 1
+16 3 0
+1133 12 12
+1503 14 14
+272 1 1
+41 1 1
+196 1 0
+571 1 1
+38 1 1
+813 18 19
+314 1 1
+22 1 1
+345 1 1
+23 3 0
+245 1 1
+129 1 1
+26 1 1
+435 1 1
+16 0 4
+323 1 1
+32 1 1
+247 1 1
+48 1 1
+778 2 0
+226 1 1
+61 1 1
+861 3 0
+471 4 0
+6220 3 0
+1351 18 18
+1560 1 0
+8099 1 0
+7388 0 5
+5386 0 1
+511 0 1
+599 0 6
+10541 11 21
+1909 16 16
+253 1 1
+16 1 1
+308 3 3
+27 1 1
+1333 0 3
+330 9 9
+600 2 0
+261 8 8
+5249 47 47
+4613 0 2
+2337 2 0
+2567 1 1
+26 1 1
+561 1 1
+48 1 1
+2440 1 1
+30 1 1
+1289 0 1
+162 1 0
+730 0 3
+663 1 0
+20 1 1
+1027 1 1
+43 1 1
+472 0 1
+219 1 1
+20 1 1
+495 1 0
+6 2 0
+1007 0 1
+169 0 10
+33 1 1
+1029 1 1
+30 1 1
+438 1 1
+39 1 1
+511 0 1
+1247 1 0
+1055 1 0
+491 1 0
+108 1 1
+48 1 1
+1324 0 1
+143 1 1
+40 1 1
+679 1 1
+45 1 1
+1036 0 1
+59 1 1
+46 1 1
+229 16 16
+149 10 10
+94 1 1
+63 1 1
+222 2 0
+55 1 1
+115 1 1
+219 15 15
+692 28 28
+159 1 1
+41 1 1
+211 1 0
+20 1 1
+1099 0 4
+28 13 12
+32 1 1
+60 1 1
+21 6 0
+178 13 15
+32 1 1
+953 1 1
+47 1 1
+174 1 1
+22 1 1
+401 0 13
+588 5 21
+288 4 4
+86 1 1
+29 0 2
+67 3 0
+641 0 1
+571 0 1
+250 1 1
+34 1 1
+255 0 2
+572 12 12
+275 6 1
+974 0 1
+578 12 12
+612 1 1
+43 1 1
+56 0 7
+1170 0 1
+477 4 3
+282 8 8
+466 0 4
+2118 5 0
+1090 0 2
+4424 1 1
+34 1 1
+4897 8 0
+2112 0 1
+2874 1 1
+21 1 1
+442 22 22
+805 0 1
+3476 10 0
+7129 3 0
+7475 0 4
+9494 2 0
+194 1 1
+49 1 1
+1349 22 22
+9662 2 0
+4856 3 0
+7447 6 6
+421 1 0
+884 6 0
+17 1 0
+3075 1 0
+14671 3 1
+3762 2 0
+601 2 0
+57 17921 17921
+1415 0 8
+42791 2 0
+100 2 0
+50 2 0
+13955 1 1
+272 1 1
+1137 1 0
+2261 16 15
+1824 1 0
+1990 1 0
+9965 0 18
+2951 6 0
+798 1 1
+30 1 1
+159 1 1
+124 1 1
+661 1 1
+31 1 1
+2632 4 4
+4024 0 16
+9373 7 7
+8626 0 1
+316 0 26
+10715 6 6
+110 1 1
+25 0 1
+3506 172081 34208
+1156 1 1
+161 1 1
+532 1 0
+698 2 0
+549 1 13
+287 1 1
+32 1 1
+1073 1 1
+22 6 0
+1829 3 923
+21 1 1
+721 1 1
+16 1 1
+1033 0 1
+10108 0 1
+10399 0 1
+14490 0 2
+3051 0 1
+6213 1 1
+26 1 1
+9064 26 26
+7722 3 0
+1957 2 0
+2288 1 0
+4470 0 4
+2115 1 0
+621 1 0
+563 0 2
+68 13 30
+160 18 19
+1807 0 2
+291 0 1
+2273 7 0
+2089 2 0
+479 1 0
+657 0 1
+772 4 0
+384 98 54
+779 0 2
+390 62 73
+1595 2 0
+1317 2 0
+5358 0 3
+2273 0 1
+597 0 8
+993 0 26
+1897 1 0
+76 0 1
+966 1 0
+2611 2 0
+1374 20 0
+831 33 33
+1574 0 2
+5096 0 3
+2404 1 1
+33 1 1
+507 4 0
+6366 0 25
+1550 0 5
+25133 1 0
+2111 0 1
+630 0 1
+784 0 1
+6989 1 0
+1116 0 1
+6270 0 1
+9520 1 0
+184 2 0
+328 1 0
+1089 1 0
+6600 0 1
+2450 1 0
+702 0 1
+5133 0 2
+3096 1 0
+315 1 0
+490 0 1
+684 9 9
+1895 3 0
+1013 0 1
+3659 1 0
+2412 1 2
+2723 4 0
+761 1 0
+22 0 1
+885 20 0
+5236 1 0
+2186 0 4
+1852 0 12
+991 0 1
+1091 0 1
+1006 1 0
+1699 0 1
+1682 1 0
+3693 1 0
+752 3 1
+497 5 6
+2292
+
+chain 61057 chr6_mcf_hap5 4833398 + 3953063 3953737 chr5 180857866 - 98127116 98127790 2061247
+526 1 1
+147
+
+chain 45613 chr6_mcf_hap5 4833398 + 2604717 2606756 chrX 154913754 + 17160000 17162038 2811400
+57 320 319
+92 373 373
+91 278 277
+94 320 320
+74 118 118
+78 42 43
+102
+
+chain 37022 chr6_mcf_hap5 4833398 + 2676816 2677228 chr7 158821424 + 107683864 107684276 3588094
+68 1 1
+54 1 1
+288
+
+chain 29722 chr6_mcf_hap5 4833398 + 1118803 1119113 chr7 158821424 + 38479558 38479868 4774007
+310
+
+chain 28137 chr6_mcf_hap5 4833398 + 3872548 3872872 chr18 76117153 - 36956533 36956857 5572699
+120 15 15
+189
+
+chain 28017 chr6_mcf_hap5 4833398 + 4025444 4025737 chr3 199501827 - 39984613 39984906 5625287
+293
+
+chain 26200 chr6_mcf_hap5 4833398 + 3998590 3999326 chr11 134452384 + 59999264 60000000 6424852
+154 126 126
+50 51 51
+57 235 235
+63
+
+chain 24804 chr6_mcf_hap5 4833398 + 1157807 1158609 chr7 158821424 - 51137320 51138288 7188387
+90 9 9
+79 101 101
+72 385 551
+66
+
+chain 21727 chr6_mcf_hap5 4833398 + 2690400 2690887 chr7 158821424 + 97232934 97233614 9179962
+159 171 400
+51 53 17
+53
+
+chain 21165 chr6_mcf_hap5 4833398 + 3891845 3892417 chr2 242951149 + 148617877 148618443 9563049
+63 162 156
+73 154 154
+120
+
+chain 20574 chr6_mcf_hap5 4833398 + 3328381 3329672 chr6 170899992 + 32089252 32090543 23930
+1291
+
+chain 19063 chr6_mcf_hap5 4833398 + 3948619 3949559 chr6 170899992 + 32821586 32822354 11222040
+175 715 543
+50
+
+chain 17270 chr6_mcf_hap5 4833398 + 3973147 3973355 chr10 135374737 - 70196080 70196288 12781660
+86 2 2
+48 5 5
+67
+
+chain 16223 chr6_mcf_hap5 4833398 + 3893015 3893224 chrX 154913754 - 4338266 4338475 13813426
+77 26 26
+106
+
+chain 15776 chr6_mcf_hap5 4833398 + 3956381 3966455 chr6 170899992 + 32827127 32836991 14253206
+50 4318 3617
+61 2558 2719
+69 660 1109
+229 767 762
+55 1248 1134
+59
+
+chain 15767 chr6_mcf_hap5 4833398 + 3201357 3201535 chr19 63811651 - 18495043 18495221 597719
+59 1 1
+45 1 1
+72
+
+chain 15397 chr6_mcf_hap5 4833398 + 4023860 4024020 chr7 158821424 + 63574132 63574292 14648759
+160
+
+chain 14519 chr6_mcf_hap5 4833398 + 3953825 3954073 chr3 199501827 + 161525390 161525638 4654449
+168 65 65
+15
+
+chain 14389 chr6_mcf_hap5 4833398 + 3863245 3863650 chr6 170899992 + 32665471 32665876 15746939
+57 86 85
+55 139 140
+68
+
+chain 13989 chr6_mcf_hap5 4833398 + 4038478 4038630 chr15 100338915 - 66378648 66378800 16209114
+152
+
+chain 13654 chr6_mcf_hap5 4833398 + 143599 143759 chr18 76117153 - 3498140 3498418 7857182
+83 1 1
+24 4 122
+48
+
+chain 12613 chr6_mcf_hap5 4833398 + 3848362 3848586 chr7 158821424 + 82112728 82112976 18070517
+51 77 101
+96
+
+chain 12612 chr6_mcf_hap5 4833398 + 3974617 3974791 chr6 170899992 - 53320727 53320901 18071926
+52 29 29
+93
+
+chain 12358 chr6_mcf_hap5 4833398 + 3995163 3995295 chr3 199501827 - 96522027 96522159 18443506
+132
+
+chain 12272 chr6_mcf_hap5 4833398 + 2612337 2612493 chrX 154913754 + 154847615 154847763 18572107
+71 1 1
+25 8 0
+51
+
+chain 12186 chr6_mcf_hap5 4833398 + 4038990 4039164 chr8 146274826 + 100984503 100984677 18706381
+68 32 32
+74
+
+chain 11876 chr6_mcf_hap5 4833398 + 2675238 2675454 chr6 170899992 + 31412979 31413204 19200916
+72 76 85
+68
+
+chain 11593 chr6_mcf_hap5 4833398 + 3844564 3844687 chr1 247249719 - 238369051 238369174 19677685
+123
+
+chain 11398 chr6_mcf_hap5 4833398 + 2686795 2686948 chr6 170899992 - 161606914 161607067 20013430
+64 22 22
+67
+
+chain 11324 chr6_mcf_hap5 4833398 + 3992779 3992926 chr6 170899992 - 138135992 138136139 20148163
+68 15 15
+64
+
+chain 10446 chr6_mcf_hap5 4833398 + 3869965 3870077 chr10 135374737 + 116791472 116791584 21828223
+112
+
+chain 9923 chr6_mcf_hap5 4833398 + 1132469 1132573 chr6 170899992 + 29984509 29984613 22990373
+104
+
+chain 9881 chr6_mcf_hap5 4833398 + 2664761 2665311 chr6 170899992 + 31313427 31313987 23083508
+72 423 433
+55
+
+chain 9817 chr6_mcf_hap5 4833398 + 3847924 3848156 chr8 146274826 + 42542364 42542493 23227154
+51 115 12
+66
+
+chain 9806 chr6_mcf_hap5 4833398 + 3846392 3846808 chr9 140273252 + 87960114 87960526 23254845
+57 294 290
+65
+
+chain 9661 chr6_mcf_hap5 4833398 + 3952556 3954131 chr6 170899992 + 104209491 104209913 3704454
+364 1153 0
+58
+
+chain 9564 chr6_mcf_hap5 4833398 + 3863653 3863818 chr6 170899992 + 32549657 32549823 23841400
+59 50 51
+56
+
+chain 9560 chr6_mcf_hap5 4833398 + 1145708 1145809 chr6 170899992 - 141000133 141000234 23851242
+101
+
+chain 9528 chr6_mcf_hap5 4833398 + 1160055 1160492 chr6 170899992 + 29878108 29878543 23937752
+59 318 316
+60
+
+chain 9472 chr6_mcf_hap5 4833398 + 3845655 3846032 chr1 247249719 - 150861000 150861377 24067468
+58 259 259
+60
+
+chain 9229 chr6_mcf_hap5 4833398 + 1293933 1294239 chr6 170899992 + 30567017 30567348 24575632
+62 194 219
+50
+
+chain 9124 chr6_mcf_hap5 4833398 + 3952955 3953063 chr3 199501827 + 1828344 1828452 9077956
+37 5 5
+66
+
+chain 9090 chr6_mcf_hap5 4833398 + 2611491 2611601 chr3 199501827 - 94209663 94209773 24799758
+53 4 4
+53
+
+chain 8464 chr6_mcf_hap5 4833398 + 2604519 2607426 chr2 242951149 + 56633977 56636883 3022124
+85 222 222
+134 2098 2097
+59 305 305
+4
+
+chain 8278 chr6_mcf_hap5 4833398 + 3861449 3861537 chr6 170899992 + 109538171 109538259 25991766
+88
+
+chain 8104 chr6_mcf_hap5 4833398 + 2618687 2620101 chr6 170899992 - 140880008 140881409 26266194
+74 1287 1274
+53
+
+chain 7774 chr6_mcf_hap5 4833398 + 2606022 2606534 chr1 247249719 + 7397644 7398156 2978583
+66 79 79
+58 214 214
+95
+
+chain 7592 chr6_mcf_hap5 4833398 + 3998745 3998829 chr8 146274826 + 68214220 68214304 9264343
+84
+
+chain 7141 chr6_mcf_hap5 4833398 + 3891766 3891845 chr12 132349534 + 113006300 113006379 12958594
+79
+
+chain 7041 chr6_mcf_hap5 4833398 + 3977312 3977387 chr4 191273063 + 139492368 139492443 28109801
+75
+
+chain 6949 chr6_mcf_hap5 4833398 + 3832393 3832466 chr6 170899992 + 32549387 32549460 28300224
+73
+
+chain 6795 chr6_mcf_hap5 4833398 + 2667263 2667335 chr6 170899992 + 31318116 31318188 28604524
+72
+
+chain 6658 chr6_mcf_hap5 4833398 + 3886931 3887001 chr5 180857866 - 20421148 20421218 28921167
+70
+
+chain 6650 chr6_mcf_hap5 4833398 + 3892813 3892896 chr11 134452384 - 10112929 10113012 19771549
+83
+
+chain 6648 chr6_mcf_hap5 4833398 + 3975186 3975255 chr12 132349534 - 72343253 72343322 28941661
+69
+
+chain 6613 chr6_mcf_hap5 4833398 + 3860999 3861069 chr1 247249719 + 37577726 37577796 29019074
+70
+
+chain 6545 chr6_mcf_hap5 4833398 + 3974547 3974617 chr9 140273252 - 54900636 54900706 21580040
+70
+
+chain 6522 chr6_mcf_hap5 4833398 + 3976253 3976322 chr15 100338915 + 41279078 41279147 29241047
+69
+
+chain 6504 chr6_mcf_hap5 4833398 + 3997726 3997795 chrX 154913754 - 101090292 101090361 29284261
+69
+
+chain 6494 chr6_mcf_hap5 4833398 + 2693655 2693723 chr6 170899992 + 30480336 30480404 29322144
+68
+
+chain 6459 chr6_mcf_hap5 4833398 + 2707667 2707736 chr6 170899992 + 31350859 31350928 29378028
+69
+
+chain 6376 chr6_mcf_hap5 4833398 + 3878588 3878655 chr1 247249719 - 291603 291670 29590708
+67
+
+chain 6368 chr6_mcf_hap5 4833398 + 2612245 2612337 chr6 170899992 - 132294381 132294479 20980271
+55 29 35
+8
+
+chain 6240 chr6_mcf_hap5 4833398 + 3861275 3861341 chr7 158821424 + 89136765 89136831 29917654
+66
+
+chain 6086 chr6_mcf_hap5 4833398 + 3886692 3886757 chr11 134452384 + 38517427 38517492 30319385
+65
+
+chain 5976 chr6_mcf_hap5 4833398 + 2710238 2710301 chr6 170899992 + 31358648 31358711 30614233
+63
+
+chain 5852 chr6_mcf_hap5 4833398 + 3892417 3892480 chr15 100338915 - 42450883 42450946 16059711
+63
+
+chain 5666 chr6_mcf_hap5 4833398 + 2692721 2692780 chr6 170899992 + 31328563 31328622 31482266
+59
+
+chain 5512 chr6_mcf_hap5 4833398 + 3860761 3860819 chr7 158821424 + 45670922 45670980 31905209
+58
+
+chain 5511 chr6_mcf_hap5 4833398 + 3953994 3954057 chr10 135374737 + 9454041 9454104 5673198
+63
+
+chain 5494 chr6_mcf_hap5 4833398 + 4010098 4010156 chr12 132349534 + 106784665 106784723 31946442
+58
+
+chain 5381 chr6_mcf_hap5 4833398 + 3848293 3848360 chr3 199501827 - 53390365 53390432 21843019
+67
+
+chain 5267 chr6_mcf_hap5 4833398 + 3861386 3861442 chr11 134452384 - 52779924 52779980 32661477
+56
+
+chain 5202 chr6_mcf_hap5 4833398 + 3975455 3975509 chr5 180857866 - 172710630 172710684 32856943
+54
+
+chain 5103 chr6_mcf_hap5 4833398 + 1145380 1145434 chr6 170899992 + 76955761 76955815 33170037
+54
+
+chain 5030 chr6_mcf_hap5 4833398 + 4010180 4010233 chr15 100338915 + 69519076 69519129 33389330
+53
+
+chain 5012 chr6_mcf_hap5 4833398 + 2695933 2695986 chr6 170899992 + 30481807 30481860 33454260
+53
+
+chain 4957 chr6_mcf_hap5 4833398 + 2608828 2608880 chr7 158821424 + 132662537 132662589 33651030
+52
+
+chain 4923 chr6_mcf_hap5 4833398 + 1157985 1158047 chr9 140273252 - 102391777 102391839 11227007
+62
+
+chain 4903 chr6_mcf_hap5 4833398 + 3886776 3886828 chrX 154913754 + 93227263 93227315 33852040
+52
+
+chain 4884 chr6_mcf_hap5 4833398 + 2690887 2690940 chr7 158821424 + 8665709 8665762 23124552
+53
+
+chain 4830 chr6_mcf_hap5 4833398 + 3870967 3871018 chr7 158821424 + 82104686 82104737 34087624
+51
+
+chain 4730 chr6_mcf_hap5 4833398 + 4037119 4037169 chr10 135374737 + 93200055 93200105 34443435
+50
+
+chain 4636 chr6_mcf_hap5 4833398 + 3953764 3953825 chr15 100338915 + 36217680 36217741 14854688
+61
+
+chain 4082 chr6_mcf_hap5 4833398 + 3861341 3861384 chr2 242951149 - 201903615 201903658 30854026
+43
+
+chain 3962 chr6_mcf_hap5 4833398 + 2605054 2607488 chr12 132349534 + 103308744 103311177 2987803
+40 116 116
+77 836 835
+44 1259 1259
+62
+
+chain 3938 chr6_mcf_hap5 4833398 + 3848731 3848772 chr12 132349534 + 106783136 106783177 34996470
+41
+
+chain 3860 chr6_mcf_hap5 4833398 + 3952301 3952346 chr3 199501827 + 112943878 112943923 15335435
+45
+
+chain 3596 chr6_mcf_hap5 4833398 + 3844515 3844564 chr19 63811651 + 37876836 37876885 21722630
+49
+
+chain 3519 chr6_mcf_hap5 4833398 + 3892776 3892813 chr10 135374737 + 82581588 82581625 28921113
+37
+
+chain 3457 chr6_mcf_hap5 4833398 + 3892907 3892997 chr5 180857866 + 79763558 79763648 18723404
+90
+
+chain 3302 chr6_mcf_hap5 4833398 + 2677228 2677268 chrX 154913754 - 17721831 17721871 3601717
+40
+
+chain 3266 chr6_mcf_hap5 4833398 + 3862147 3862182 chr9 140273252 + 83968215 83968250 35227644
+35
+
+chain 3215 chr6_mcf_hap5 4833398 + 2690311 2690345 chr13 114142980 - 34852829 34852863 33454154
+34
+
+chain 3191 chr6_mcf_hap5 4833398 + 2608477 2608530 chr16 88827254 + 57584329 57584382 22020535
+53
+
+chain 2914 chr6_mcf_hap5 4833398 + 3891647 3891703 chrX 154913754 + 119403135 119403191 11929641
+56
+
+chain 2795 chr6_mcf_hap5 4833398 + 3892480 3892522 chr15 100338915 + 56426321 56426363 16223719
+42
+
+chain 2771 chr6_mcf_hap5 4833398 + 2273985 2274017 chr16 88827254 + 61371572 61371604 11881975
+32
+
+chain 2705 chr6_mcf_hap5 4833398 + 3974669 3974698 chr5 180857866 + 34801294 34801323 21438495
+29
+
+chain 2671 chr6_mcf_hap5 4833398 + 2612185 2612244 chr9 140273252 - 60326471 60326530 21074056
+59
+
+chain 2599 chr6_mcf_hap5 4833398 + 1158047 1158085 chr7 158821424 - 126060947 126060985 11258554
+38
+
+chain 2590 chr6_mcf_hap5 4833398 + 3892269 3892297 chr5 180857866 - 137356848 137356876 18664742
+28
+
+chain 2589 chr6_mcf_hap5 4833398 + 3891454 3891482 chr11 134452384 - 49993356 49993384 29810036
+28
+
+chain 2555 chr6_mcf_hap5 4833398 + 2690245 2690311 chr18 76117153 + 25734423 25734489 18753960
+66
+
+chain 2509 chr6_mcf_hap5 4833398 + 2605481 2605558 chr3 199501827 - 153335243 153335320 3148850
+77
+
+chain 2466 chr6_mcf_hap5 4833398 + 2605403 2605466 chr2 242951149 + 186971340 186971403 6103613
+63
+
+chain 2459 chr6_mcf_hap5 4833398 + 3974791 3974822 chr14 106368585 + 48563076 48563107 22466897
+31
+
+chain 2459 chr6_mcf_hap5 4833398 + 3780767 3780793 chr17 78774742 - 42818294 42818320 32009757
+26
+
+chain 2427 chr6_mcf_hap5 4833398 + 2690989 2691048 chr3 199501827 - 193383909 193383968 24279045
+59
+
+chain 2365 chr6_mcf_hap5 4833398 + 4038809 4038866 chrX 154913754 + 103588329 103588386 22063660
+57
+
+chain 2350 chr6_mcf_hap5 4833398 + 1143959 1143987 chr9 140273252 + 98495373 98495401 22648903
+28
+
+chain 2348 chr6_mcf_hap5 4833398 + 2602541 2602596 chr7 158821424 + 35337254 35337309 23750584
+55
+
+chain 2343 chr6_mcf_hap5 4833398 + 3952502 3952527 chr11 134452384 - 60697549 60697574 22749508
+25
+
+chain 2320 chr6_mcf_hap5 4833398 + 4019609 4019634 chr19 63811651 - 56872967 56872992 35475512
+25
+
+chain 2317 chr6_mcf_hap5 4833398 + 2604190 2604320 chr15 100338915 - 72843171 72843301 3140919
+130
+
+chain 2262 chr6_mcf_hap5 4833398 + 1157783 1157807 chr19 63811651 - 5696072 5696096 21221761
+24
+
+chain 2188 chr6_mcf_hap5 4833398 + 1158201 1158258 chr1 247249719 + 222604152 222604209 12884993
+57
+
+chain 2183 chr6_mcf_hap5 4833398 + 3892590 3892636 chr7 158821424 + 113918927 113918973 16141801
+46
+
+chain 2172 chr6_mcf_hap5 4833398 + 3845632 3845655 chr3 199501827 + 38460301 38460324 24137330
+23
+
+chain 2171 chr6_mcf_hap5 4833398 + 3892683 3892706 chr13 114142980 - 13381431 13381454 25956368
+23
+
+chain 2132 chr6_mcf_hap5 4833398 + 2603254 2603380 chr1 247249719 + 93626635 93626761 5313263
+126
+
+chain 1996 chr6_mcf_hap5 4833398 + 2607152 2607223 chr3 199501827 + 178864208 178864279 4788720
+71
+
+chain 1952 chr6_mcf_hap5 4833398 + 3999028 3999070 chr2 242951149 - 218681061 218681103 8791220
+42
+
+chain 1946 chr6_mcf_hap5 4833398 + 1158400 1158475 chr1_random 1663265 - 1644029 1644104 12720667
+75
+
+chain 1930 chr6_mcf_hap5 4833398 + 3891482 3891539 chrX 154913754 + 81246238 81246295 14247869
+57
+
+chain 1927 chr6_mcf_hap5 4833398 + 2690365 2690400 chr7 158821424 - 109806767 109806802 24526345
+35
+
+chain 1921 chr6_mcf_hap5 4833398 + 4038367 4038423 chr11 134452384 - 48517870 48517926 18924823
+56
+
+chain 1856 chr6_mcf_hap5 4833398 + 1158158 1158191 chr4 191273063 + 153905795 153905828 9266241
+33
+
+chain 1833 chr6_mcf_hap5 4833398 + 2606939 2606989 chr9 140273252 + 84578242 84578292 7882125
+50
+
+chain 1827 chr6_mcf_hap5 4833398 + 3844483 3844515 chr10 135374737 - 122033518 122033550 24304365
+32
+
+chain 1796 chr6_mcf_hap5 4833398 + 2603994 2604348 chrX 154913754 + 100577502 100577856 3969599
+99 227 227
+28
+
+chain 1766 chr6_mcf_hap5 4833398 + 2690182 2690238 chr4 191273063 - 32209724 32209780 19175813
+56
+
+chain 1695 chr6_mcf_hap5 4833398 + 2604644 2604717 chr5 180857866 + 63682850 63682923 4402620
+59 4 4
+10
+
+chain 1651 chr6_mcf_hap5 4833398 + 3892522 3892590 chr11 134452384 + 18101372 18101440 12538366
+68
+
+chain 1629 chr6_mcf_hap5 4833398 + 4038630 4038657 chr2 242951149 - 84022333 84022360 21351212
+27
+
+chain 1606 chr6_mcf_hap5 4833398 + 3869684 3869743 chr4 191273063 - 166421863 166421922 24717461
+59
+
+chain 1597 chr6_mcf_hap5 4833398 + 3845427 3846126 chrX 154913754 - 128485360 128486059 24583609
+70 578 578
+51
+
+chain 1587 chr6_mcf_hap5 4833398 + 4039212 4039257 chr14 106368585 + 80426596 80426641 23776282
+45
+
+chain 1583 chr6_mcf_hap5 4833398 + 2676737 2676787 chr8 146274826 - 103361273 103361323 22022004
+50
+
+chain 1578 chr6_mcf_hap5 4833398 + 2686639 2686691 chr2 242951149 + 183623425 183623477 24278977
+52
+
+chain 1568 chr6_mcf_hap5 4833398 + 3998920 3998948 chr16 88827254 - 17543433 17543461 11021050
+28
+
+chain 1537 chr6_mcf_hap5 4833398 + 3999190 3999240 chr5 180857866 + 49878691 49878741 10672840
+50
+
+chain 1433 chr6_mcf_hap5 4833398 + 3999082 3999106 chr2 242951149 - 185977428 185977452 16089470
+24
+
+chain 1432 chr6_mcf_hap5 4833398 + 2607885 2607952 chr4 191273063 - 25455517 25455584 19723766
+67
+
+chain 1386 chr6_mcf_hap5 4833398 + 4037584 4037655 chr5 180857866 - 127160909 127160980 20252959
+71
+
+chain 1383 chr6_mcf_hap5 4833398 + 3892706 3892771 chr14 106368585 - 49729815 49729880 20850419
+65
+
+chain 1324 chr6_mcf_hap5 4833398 + 4038089 4038139 chr11 134452384 - 110737438 110737488 16281354
+50
+
+chain 1320 chr6_mcf_hap5 4833398 + 2607682 2607744 chr3 199501827 - 89080446 89080508 24774355
+62
+
+chain 1310 chr6_mcf_hap5 4833398 + 3891543 3891595 chrX 154913754 + 62583131 62583183 22867198
+52
+
+chain 1254 chr6_mcf_hap5 4833398 + 2605313 2605381 chr9 140273252 + 222427 222495 3502715
+68
+
+chain 1253 chr6_mcf_hap5 4833398 + 4038318 4038354 chr6 170899992 - 39092714 39092750 23906153
+36
+
+chain 1143 chr6_mcf_hap5 4833398 + 3998844 3998870 chr1 247249719 + 180123990 180124016 10456151
+26
+
+chain 1071 chr6_mcf_hap5 4833398 + 2603839 2603906 chr12 132349534 + 77415638 77415705 9437719
+67
+
+chain 1059 chr6_mcf_hap5 4833398 + 3952346 3952428 chr17 78774742 - 53522383 53522465 12152498
+82
+
+chain 1040 chr6_mcf_hap5 4833398 + 2603731 2603788 chr5 180857866 - 146041571 146041628 6664547
+57
+
+chain 1025 chr6_mcf_hap5 4833398 + 3892143 3892170 chr2 242951149 - 81435622 81435649 19840221
+27
+
+chain 1003 chr6_mcf_hap5 4833398 + 3731571 3731602 chr2 242951149 - 44758448 44758479 2126761
+31
+
+chain 978 chr6_mcf_hap5 4833398 + 1158258 1158286 chr6 170899992 - 112879191 112879219 17119903
+28
+
+chain 958 chr6_mcf_hap5 4833398 + 2606823 2606882 chr18 76117153 + 12161176 12161235 15243828
+59
+
+chain 919 chr6_mcf_hap5 4833398 + 2608035 2608095 chr4 191273063 + 44807134 44807194 22381057
+60
+
+chain 910 chr6_mcf_hap5 4833398 + 2604348 2604389 chrX 154913754 - 130647843 130647884 6306827
+41
+
+chain 899 chr6_mcf_hap5 4833398 + 3952444 3952502 chr9 140273252 + 66213924 66213982 10448615
+58
+
+chain 889 chr6_mcf_hap5 4833398 + 1158286 1158322 chr1 247249719 - 24894408 24894444 17913365
+36
+
+chain 857 chr6_mcf_hap5 4833398 + 4037505 4037565 chr20 62435964 - 51574691 51574751 25098794
+60
+
+chain 841 chr6_mcf_hap5 4833398 + 2603443 2603495 chr20 62435964 - 59823019 59823071 21526397
+52
+
+chain 825 chr6_mcf_hap5 4833398 + 2604460 2604519 chr7 158821424 + 140056560 140056619 5253720
+59
+
+chain 798 chr6_mcf_hap5 4833398 + 3846536 3846592 chr1 247249719 - 94337351 94337407 25194613
+56
+
+chain 791 chr6_mcf_hap5 4833398 + 2606765 2606815 chr2 242951149 + 171191285 171191335 4492406
+50
+
+chain 774 chr6_mcf_hap5 4833398 + 4038161 4038190 chr13 114142980 + 78421249 78421278 18219143
+29
+
+chain 760 chr6_mcf_hap5 4833398 + 2605737 2605796 chr12 132349534 + 56700130 56700189 25330835
+59
+
+chain 740 chr6_mcf_hap5 4833398 + 1158689 1158753 chr12 132349534 + 55464534 55464598 20832675
+64
+
+chain 725 chr6_mcf_hap5 4833398 + 2603907 2603961 chr2 242951149 + 129418481 129418535 15959343
+54
+
+chain 718 chr6_mcf_hap5 4833398 + 2608115 2608170 chr9 140273252 - 49339912 49339967 23555333
+55
+
+chain 716 chr6_mcf_hap5 4833398 + 4038745 4038797 chr16 88827254 - 38714794 38714846 22851160
+52
+
+chain 700 chr6_mcf_hap5 4833398 + 2604093 2604149 chr1 247249719 + 47033162 47033218 11748494
+56
+
+chain 697 chr6_mcf_hap5 4833398 + 2606088 2606122 chr18 76117153 + 57870219 57870253 3091588
+34
+
+chain 684 chr6_mcf_hap5 4833398 + 2603585 2603653 chrX 154913754 - 140171184 140171252 5395481
+68
+
+chain 681 chr6_mcf_hap5 4833398 + 4037371 4037428 chr8 146274826 - 64029404 64029461 24731946
+57
+
+chain 668 chr6_mcf_hap5 4833398 + 3815206 3815234 chr13 114142980 + 25366313 25366341 2606939
+28
+
+chain 607 chr6_mcf_hap5 4833398 + 2608345 2608426 chr12 132349534 + 61847837 61847918 15157322
+81
+
+chain 554 chr6_mcf_hap5 4833398 + 2607118 2607152 chr6 170899992 + 75108555 75108589 7134095
+34
+
+chain 547 chr6_mcf_hap5 4833398 + 2607779 2607829 chr11 134452384 - 79794459 79794509 15991278
+50
+
+chain 541 chr6_mcf_hap5 4833398 + 2605695 2605721 chr2 242951149 - 229173591 229173617 17449769
+26
+
+chain 537 chr6_mcf_hap5 4833398 + 2602778 2602824 chr20 62435964 + 38578434 38578480 23803873
+46
+
+chain 487 chr6_mcf_hap5 4833398 + 2603535 2603585 chr18 76117153 - 44468395 44468445 11618572
+50
+
+chain 479 chr6_mcf_hap5 4833398 + 3847219 3847270 chr8 146274826 - 91739126 91739177 25862760
+51
+
+chain 461 chr6_mcf_hap5 4833398 + 2607311 2607369 chr9 140273252 - 118104609 118104667 6129578
+58
+
+chain 456 chr6_mcf_hap5 4833398 + 2605822 2605854 chr10 135374737 + 51611354 51611386 20534292
+32
+
+chain 442 chr6_mcf_hap5 4833398 + 2602717 2602778 chr4 191273063 - 135500139 135500200 15116367
+61
+
+chain 412 chr6_mcf_hap5 4833398 + 2605854 2605905 chr12 132349534 + 9890446 9890497 14104676
+51
+
+chain 263 chr6_mcf_hap5 4833398 + 2604406 2604441 chr6 170899992 + 111492261 111492296 25439357
+35
+
+chain 227 chr6_mcf_hap5 4833398 + 2621672 2621728 chr6 170899992 - 140565854 140565910 28646895
+56
+
+chain 373682699 chr6_qbl_hap6 4611984 + 0 4611984 chr6 170899992 + 28804582 33487728 31
+932 3 0
+804 0 1
+2406 2 0
+210632 0 1
+14475 0 1
+6819 1 0
+6845 1 3
+6188 0 1
+6397 0 1
+345 1 0
+68374 2 0
+46946 7 0
+1489 1 1
+72 1 1
+2260 0 2
+10629 0 1
+19578 0 1
+1324 0 2
+5438 5 0
+2061 1 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4746 9 9
+4767 7 7
+1169 1 1
+55 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+249 43 43
+1178 0 4
+685 8 0
+48 4 0
+1701 1 1
+43 5 5
+862 18 18
+58 1 1
+66 1 1
+420 1 1
+44 1 1
+680 4 4
+1675 1 1
+83 1 1
+3082 4 0
+5467 1 1
+27 0 1
+1099 16 0
+627 12 12
+1317 6 1
+129 1 1
+25 1 1
+1397 15 15
+810 1 1
+27 1 1
+1192 2 0
+7515 4 0
+979 0 3
+3406 0 2
+2340 1 1
+20 1 1
+1139 1 1
+26 1 1
+787 0 1
+1416 3 1
+22815 4 4
+126 1 0
+38 1 1
+140 1 0
+999 0 17
+56 0 15
+11759 163412 163534
+9134 0 2
+5376 0 1
+19253 1 0
+7884 1 0
+21 0 6
+4451 1 0
+27910 1 0
+9946 0 1
+11233 1 1
+32 1 1
+2238 1 1
+20 1 1
+3659 22 16
+1218 1 0
+1638 6 6
+228 1 1
+45 1 1
+2048 0 3
+461 1 0
+20759 1 0
+3778 2 1
+1268 1 0
+1511 1 1
+42 2 0
+24 1 1
+4119 22 0
+1757 1 0
+1527 1 1
+29 1 1
+1886 1 0
+10628 12 0
+46568 1 0
+18985 0 10
+1825 3 4
+5288 0 9
+2728 1 5
+722 0 1
+502 0 1
+1025 0 1
+134 14 0
+4944 0 1
+319 1 0
+6178 0 1
+2898 0 2
+143 0 1
+1775 1 0
+2123 0 1
+2715 1 0
+4921 1 1
+47 4 0
+2882 1 0
+1362 1 0
+1233 0 8
+2134 0 1
+1042 0 1
+163 1 1
+45 1 1
+50 2 0
+64 1 1
+48 1 1
+380 0 1
+30 1 0
+30 1 1
+61 1 1
+22 1 1
+691 5 7
+310 1 1
+37 3 1
+162 1 1
+194 2 0
+36 1 1
+242 9 9
+697 33 33
+1202 1 1
+16 1 1
+528 1 1
+20 1 1
+509 0 5
+76 1 1
+21 1 1
+439 15 15
+2779 1 0
+1597 24 28
+59 12 12
+307 1 0
+516 1 0
+286 11 33
+339 5 0
+570 1 1
+37 1 1
+220 1 0
+72 1 1
+144 1 1
+48 1 1
+247 2 0
+174 9 10
+816 1 0
+940 1 1
+45 1 1
+91 3 3
+71 1 1
+291 14 14
+100 1 1
+23 1 1
+452 3 3
+229 1 1
+252 0 1
+129 15 15
+432 10 0
+85 1 1
+28 1 1
+189 2 1
+71 1 1
+52 8 0
+810 2 2
+63 1 1
+378 1 1
+26 1 1
+187 31 36
+966 1 1
+25 1 1
+91 12 12
+125 1 1
+38 1 1
+433 2 0
+596 1 1
+48 1 1
+465 4 4
+64 1 1
+20 1 1
+525 5 5
+237 3 8
+99 31 31
+53 11 0
+364 4 3
+201 1 1
+42 1 1
+56 1 1
+115 1 0
+67 16 16
+244 1 1
+54 5 5
+929 1 1
+21 1 1
+126 0 3
+830 1 11
+59 1 1
+537 0 2
+24 1 1
+745 15 15
+810 1 0
+425 1 1
+89 1 1
+592 1 1
+49 1 1
+352 0 1
+142 1 1
+30 1 1
+95 1 1
+45 1 1
+227 1 1
+53 1 1
+130 1 1
+18 1 1
+138 1 1
+90 1 1
+129 1 1
+39 1 1
+50 1 1
+79 1 1
+117 1 1
+31 1 1
+155 155 0
+34 1 1
+50 5 5
+57 1 1
+152 1 1
+30 1 1
+177 5 5
+345 1 1
+39 1 1
+504 18 18
+596 12 12
+54 1 1
+158 1 1
+164 1 1
+34 1 1
+626 15 15
+866 0 10
+1051 0 2611
+680 0 1
+1537 0 18
+75 1 0
+147 52 1
+119 0 12
+23 1 1
+1927 13 13
+1702 2 0
+3694 1 1
+18 1 1
+958 43 47
+246 2 0
+146 1 1
+49 1 1
+410 1 0
+667 1 1
+38 1 1
+362 7 1
+159 2 0
+515 2 0
+1026 1 1
+29 1 1
+249 0 6
+129 1 1
+33 4 0
+10 1 5
+1236 1 1
+20 1 1
+138 10 9
+448 0 3
+660 1 1
+28 1 1
+83 1 1
+51 1 1
+2659 1 1
+38 1 1
+424 0 1
+70 1 1
+820 1 1
+26 1 1
+1472 1 1
+21 1 1
+491 5 5
+163 15 15
+2194 2 0
+533 6 0
+441 1 7
+1689 1 1
+26 3 4
+879 16 16
+514 0 2
+58 1 1
+350 1 0
+769 1 1
+39 1 1
+573 0 4
+37 1 1
+144 8 8
+668 1 1
+22 1 1
+344 2 0
+262 2 2
+38 0 1
+70 18 18
+84 11 13
+169 62 63
+74 11 15
+1255 0 2
+332 1 1
+21 1 1
+193 8 24
+34 1 1
+79 1 1
+29 1 1
+536 1 0
+308 0 1
+850 0 32
+23 1 1
+651 1 1
+22 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 0 2
+713 7 7
+89 1 0
+293 9 8
+125 1 1
+31 1 1
+192 6 6
+171 17 17
+681 1 1
+43 1 1
+514 1 1
+68 1 1
+537 1 1
+35 1 1
+159 6 6
+778 2 2
+44 1 1
+168 0 7
+211 1 1
+42 1 1
+1253 1 1
+29 1 1
+320 1 1
+36 2 2
+55 1 2
+108 1 1
+33 1 1
+317 1 1
+35 1 1
+553 8 8
+386 1 1
+26 1 1
+540 1 1
+31 1 1
+65 0 1
+625 12 12
+313 0 1
+52 1 1
+22 1 1
+583 1 1
+49 1 1
+1499 3 0
+838 1 1
+19 12 0
+1129 1 1
+36 1 1
+553 8 8
+109 1 1
+45 1 1
+841 16 15
+157 1 1
+31 2 2
+204 18 19
+487 1 1
+29 1 1
+374 1 1
+67 1 1
+720 13 13
+266 10 10
+330 16 14
+413 1 1
+44 1 1
+78 6 6
+181 2 2
+36 1 1
+397 1 1
+20 1 1
+311 1 1
+48 2 2
+1495 1 1
+33 1 1
+216 4 4
+35 1 1
+194 10 10
+310 1 1
+51 1 1
+84 1 1
+101 1 1
+521 1 1
+23 1 1
+242 51 51
+600 1 1
+31 1 1
+413 15 15
+290 1 1
+49 1 1
+527 17 17
+340 12 11
+1025 1 0
+2572 1 1
+29 1 1
+397 2 5
+668 13 13
+541 1 1
+59 0 2
+6 1 1
+122 14 14
+51 1 1
+46 1 1
+187 1 1
+76 1 1
+164 0 21
+136 1 1
+12 1 1
+66 16 16
+456 37 34
+371 7 7
+48 1 1
+194 10 10
+108 1 1
+60 1 1
+122 49 50
+238 1 1
+32 0 1
+100 1 0
+72 1 0
+390 1 1
+38 1 1
+144 1 1
+27 0 4
+184 21 228
+49 1 1
+608 0 1
+152 1 1
+31 1 1
+281 8 8
+337 1 1
+45 1 1
+222 1 1
+54 1 1
+346 1 0
+44 1 1
+368 1 1
+72 1 1
+502 36 18
+63 1 1
+43 0 4
+136 1 1
+42 1 1
+80 4 4
+35 1 0
+89 1 1
+24 0 5
+829 13 13
+73 1 1
+28 14 0
+233 1 1
+42 0 3
+85 0 1
+400 1 1
+40 1 1
+538 25 25
+174 1 1
+20 1 1
+705 1 1
+26 2 2
+614 1 1
+44 1 1
+793 1 1
+16 1 1
+99 38 38
+610 5 5
+804 1 1
+29 1 1
+166 1 1
+43 1 1
+233 1 1
+44 1 1
+507 0 3
+110 8 8
+133 1 1
+31 1 1
+165 1 1
+29 1 1
+1249 1 1
+26 4 0
+56 1 1
+67 1 1
+716 1 1
+46 0 1
+16 1 1
+174 1 1
+96 1 1
+141 1 1
+39 0 4
+263 1 1
+18 1 1
+259 4 4
+38 1 1
+104 1 1
+40 1 0
+248 1 1
+18 1 1
+238 1 1
+32 1 1
+70 0 2
+16 1 1
+818 1 1
+22 4 4
+492 4 4
+1145 1 1
+46 1 1
+53 1 0
+38 1 1
+373 62 62
+1149 0 1
+20 1 1
+1294 1 1
+41 1 1
+316 4 4
+42 1 1
+218 12 12
+363 1 1
+24 1 1
+457 10 10
+414 13 13
+825 1 1
+41 1 1
+492 0 4
+1374 1 1
+18 1 1
+1145 6 4
+880 1 1
+35 1 1
+236 1 1
+67 1 1
+298 0 1
+147 14 14
+312 11 11
+613 1 1
+62 1 1
+340 1 1
+22 1 1
+1057 1 1
+57 1 1
+358 1 1
+128 1 1
+146 10 10
+490 1 1
+20 1 1
+62 1 1
+88 1 1
+293 1 1
+28 1 0
+20 1 1
+83 0 1
+90 1 1
+312 1 1
+44 1 1
+1213 1 1
+51 1 1
+467 1 1
+39 1 1
+122 14 0
+35 1 1
+485 14 14
+110 12 0
+127 1 1
+5450 0 5
+1699 9 9
+3278 0 2
+28 1 1
+2195 18 16
+521 1 1
+18 1 1
+784 18 18
+1603 0 248
+9302 4 4
+72 1 1
+30 0 2
+2359 1 1
+22 0 1
+1244 7 7
+922 2 0
+1507 1 1
+44 1 1
+208 6 1
+1022 34244 40039
+401 1 1
+27 1 1
+369 1 1
+47 1 1
+256 1 1
+27 1 1
+72 1 1
+107 2 0
+21 1 1
+93 89 0
+194 1 1
+33 1 1
+230 1 1
+142 5 5
+108 1 1
+99 1 1
+349 1 1
+31 1 1
+144 1 1
+155 1 1
+56 1 1
+46 1 1
+405 5 6
+148 1 1
+70 1 1
+137 3 3
+67 1 1
+73 22 22
+115 12 12
+142 5 5
+269 15 15
+102 6 6
+93 30 30
+224 1 1
+22 1 1
+459 1 1
+106 1 1
+150 1 1
+50 1 1
+71 1 1
+15 1 0
+258 6 7
+117 1 1
+45 1 1
+123 2 2
+49 1 1
+173 1 1
+28 2 2
+50 1 1
+158 1 1
+186 1 1
+20 1 1
+67 1 1
+25 1 1
+227 2 2
+155 1 1
+777 1 1
+33 1 2
+26 6 6
+474 1 1
+36 1 1
+151 1 1
+29 1 1
+120 1 1
+23 1 1
+736 17 17
+112 1 1
+39 1 1
+553 1 1
+69 1 1
+116 1 0
+1618 9 9
+820 11 11
+173 0 8
+405 9 9
+196 1 1
+26 1 1
+173 1 1
+27 5 1
+42 1 1
+676 17 19
+77 1 3
+65 16 16
+69 1 0
+277 1 1
+44 1 1
+72 0 3
+70 1 1
+54 1 1
+240 1 0
+31 1 1
+1192 18 19
+454 28 28
+373 1 1
+46 1 1
+1565 1 1
+53 2 2
+543 1 1
+38 1 1
+985 1 1
+27 0 1
+8 1 1
+158 0 38
+656 1 1
+104 1 1
+771 1 1
+21 1 1
+398 1 1
+16 1 2
+163 4 3
+94 1 1
+44 1 1
+172 1 0
+122 5 5
+193 16 16
+535 2 2
+17 1 0
+93 1 1
+580 1 1
+91 1 1
+141 1 1
+79 1 1
+80 13 13
+165 1 1
+129 1 1
+114 1 1
+30 1 1
+83 1 1
+35 1 1
+126 16 16
+270 0 1
+111 9 9
+151 1 1
+118 1 1
+253 1 1
+45 20456 22239
+51 5 5
+45 1 1
+53 1 1
+37 1 1
+157 1 1
+279 1 1
+233 1 1
+19 0 8
+67 2 0
+41 1 1
+102 12 12
+275 14 14
+70 1 1
+82 2 2
+224 5 1
+490 0 22
+3841 1 0
+3216 1 1
+42 1 1
+1914 0 3
+616 11 12
+144 1 1
+21 2 1
+775 1 1
+50 1 1
+50 2 2
+96 2 2
+1522 4 0
+58 0 2
+1099 1 1
+42 1 1
+3502 0 6
+255 1 1
+40 1 1
+150 0 4
+18 1 1
+589 1 1
+37 1 1
+539 5 5
+354 1 3
+128 1 1
+58 1 1
+159 1 1
+5 2 0
+21 1 1
+231 1 1
+82 3 3
+69 3 0
+549 1 1
+69 1 1
+74 9 9
+126 1 1
+47 1 1
+614 9 9
+138 1 1
+29 1 1
+681 1 1
+49 1 1
+67 1 1
+19 4 9
+234 1 1
+93 1 1
+60 4 4
+96 4 4
+76 1 1
+169 1 1
+50 1 1
+54 1 1
+312 1 1
+130 1 1
+44 1 1
+69 1 1
+80 1 1
+76 1 1
+41 1 1
+89 0 6
+45 1 0
+363 1 1
+42 1 1
+295 1 1
+43 1 1
+83 6 0
+52 0 2
+1228 1 1
+34 1 1
+3527 20 0
+1768 2 1
+2467 0 2
+101 10 0
+129 1 1
+37 1 1
+121 1 1
+25 1 1
+161 1 0
+97 1 1
+124 1 0
+178 1 1
+34 1 1
+54 1 1
+38 1 2
+670 1 1
+45 1 1
+874 1 1
+40 1 1
+59 0 1
+59 4 4
+316 1 1
+178 1 1
+103 1 1
+61 1 1
+220 63 63
+296 1 1
+33 1 1
+185 12 12
+269 1 1
+84 1 1
+864 15 15
+241 1 0
+79 3 3
+161 1 1
+48 1 1
+539 1 1
+44 1 1
+357 1 1
+37 1 1
+436 1 1
+59 1 1
+71 1 1
+261 1 1
+289 1 1
+47 1 1
+95 12 12
+97 4 4
+27 1 1
+100 1 1
+16 1 1
+101 1 1
+33 1 2
+481 1 1
+42 1 1
+206 7 7
+56 12 12
+179 10 10
+80 1 1
+41 1 1
+251 1 1
+306 1 1
+80 2 0
+4 94 0
+433 1 1
+23 1 1
+107 1 0
+265 1 1
+49 1 1
+282 1 1
+43 1 1
+865 7 7
+60 1 0
+108 1 1
+24 1 1
+134 1 1
+32 1 0
+158 0 2
+1040 1 1
+42 1 1
+737 1 0
+790 1 1
+9 2 1
+11 1 1
+129 1 1
+23 1 1
+894 1 1
+43 3 3
+854 1 1
+23 0 1
+23 2 0
+26 1 1
+395 0 15
+403 5 5
+14 1 1
+2454 1 1
+76 1 1
+170 1 1
+18 1 1
+574 4 0
+291 1 1
+47 1 1
+786 19 0
+88 10 11
+48 1 1
+58 1 1
+28 1 1
+504 0 2
+1276 1 1
+28 1 1
+975 1 0
+3231 1 0
+865 1 1
+39 1 1
+1604 1 1
+56 9 0
+1037 0 1
+510 1 1
+49 1 1
+1253 1 1
+19 1 1
+1078 3 0
+221 1 1
+21 1 0
+899 0 4
+466 1 1
+38 1 1
+297 0 3
+730 19 6
+1043 1 1
+49 1 1
+273 0 1
+708 1 0
+364 14 13
+58 1 1
+74 1 1
+2563 4 0
+531 1 1
+19 1 1
+1944 5 0
+163 6 7
+1206 0 2
+718 1 1
+41 7 0
+1795 13 13
+1390 1 0
+2933 0 16
+540 1 1
+14 1 1
+167 1 0
+897 17 4
+1208 1 0
+1307 1 1
+20 1 1
+540 0 10
+203 2 0
+44 1 1
+298 1 0
+87 11 10
+491 14 8
+991 1 1
+74 6 0
+179 1 1
+34 1 1
+448 10 0
+1688 102 81
+131 1 1
+49 2 1
+2161 30 30
+203 1 0
+89 1 0
+492 1 1
+30 1 1
+1212 3 0
+990 1 1
+38 1 1
+780 1 0
+191 1 1
+47 6 6
+393 1 1
+41 1 1
+259 1 0
+941 1 1
+20 1 1
+185 0 6
+165 0 16
+420 3 1
+130 1 1
+31 1 1
+253 18 18
+720 16 18
+1257 3 0
+986 0 4
+3311 1 1
+26 1 1
+556 0 4
+120 0 1
+1273 1 1
+20 1 1
+4311 0 3
+15 1 1
+2531 17 17
+3334 5 5
+295 1 1
+45 1 1
+94 1 1
+85 0 1
+1603 16 16
+489 1 1
+34 1 1
+1436 1 1
+47 1 1
+273 7 0
+153 0 5
+283 12 12
+619 1 1
+36 0 4
+225 1 1
+23 1 1
+553 5 0
+2334 1 1
+49 1 1
+350 1 1
+31 1 1
+1436 1 1
+46 1 1
+91 4 19
+468 0 1
+46 1 1
+923 37 37
+531 0 4
+426 0 1
+1144 1 2
+1131 1 1
+20 1 1
+1533 16 0
+3103 0 1
+25 1 1
+4034 12 12
+346 0 1
+943 1 0
+524 1 1
+20 1 1
+151 3 3
+144 1 1
+189 1 7
+750 1 0
+695 1 0
+1003 0 2
+9710 0 1
+3177 0 1
+8990 0 1
+2268 1 1
+35 0 10
+8205 1 0
+3193 1 1
+76 1 1
+10955 0 1
+22875 0 20
+2417 1 0
+998 0 13
+4236 8 0
+4845 0 2
+64 40 34
+10941 1 1
+40 1 1
+4759 0 6
+12084 0 3
+3052 0 4
+2989 1 0
+13523 1 3
+16170 1 0
+11761 0 3
+3912 3 0
+6620 0 7
+7633 3 0
+419 2 0
+10690 5 24
+10798 0 1
+296 0 1
+1770 4 0
+374 0 4
+230 16 16
+7468 1 0
+1229 1 0
+3061 1 0
+5818 1 0
+2415 12 9
+2056 0 1
+955 4 0
+20022 0 1
+4418 2 1
+2375 0 4
+2086 1 1
+32 1 1
+1225 1 0
+857 2 0
+1154 0 1
+4667 1 0
+170 0 3
+2376 0 1
+503 37 37
+2259 10 10
+1512 4 0
+68 9 1
+2170 1 1
+47 1 1
+318 2 0
+19 0 6
+14527 1 1
+33 1 1
+3080 1 1
+23 1 1
+1645 6 6
+231 0 1
+2136 2 0
+6222 0 1
+830 1 1
+24 1 1
+8326 1 0
+2939 1 0
+3959 0 2
+3746 0 2
+1011 1 1
+34 1 1
+7443 0 1
+688 2 0
+574 1 1
+29 1 1
+1799 13 1
+4074 2 0
+136 79 79
+528 19 0
+253 0 1
+204 1 0
+129 2 0
+811 1 1
+38 1 1
+2347 52 0
+4634 1 0
+856 14 14
+159 34 38
+855 1 1
+28 1 1
+1255 1 1
+36 1 1
+97 0 1
+58 1 1
+1708 1 1
+48 1 1
+958 15 0
+3371 1 1
+37 1 1
+4267 0 13
+1061 0 1
+272 0 26
+8 1 15
+25 0 2
+112 2 0
+26 4 32
+4090 0 1
+3270 1 1
+17 1 1
+2822 0 1
+6206 1 0
+2318 0 2
+1504 0 1
+6189 3 0
+396 22 12
+918 0 1
+2340 1 1
+33 1 1
+326 1 1
+80 1 1
+205 3 2
+81 8 17
+2671 0 1
+1099 0 1
+144 1 1
+29 0 1
+2097 0 3
+24 3 0
+1207 4 4
+45 1 1
+757 0 5
+1926 1 1
+40 1 1
+2657 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+754 0 4
+17 3 0
+1027 3 0
+428 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+6611 0 3
+1575 4 5
+36 1 1
+99 2 0
+700 0 2
+151 0 1
+467 11 11
+272 0 3
+40 1 1
+2428 0 1
+750 2 0
+473 0 2
+421 1 1
+34 1 1
+1575 1 0
+3841 1 0
+560 1 0
+1108 1 0
+8087 1 0
+11881 1 1
+30 1 1
+4406 2 0
+183 1 1
+9871 0 1
+906 3 0
+887 1 1
+80 1 1
+3115 0 1
+1037 1 0
+5866 0 2
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 3 0
+700 1 1
+2469 1 0
+1751 0 1
+910 3 0
+691 0 1
+5793 0 1
+26407 1 0
+672 0 1
+19269 1 1
+28 0 6
+1371 29 0
+494 2 0
+20417 1 0
+18633 0 1
+601 1 0
+319 0 1
+6820 1 0
+5718 0 2
+17894 1 0
+4272 1 0
+4967 3 1
+290 1 0
+2447 1 0
+740 1 9
+9299 0 18
+7427 1 0
+8151 2 1
+673 1 0
+3453 0 1
+149 0 1
+611 0 4
+4669 0 4
+176 1 1
+3229 0 1
+1092 2 0
+159 1 0
+4480 0 2
+4019 0 1
+1451 22 23
+816 1 0
+8701 1 1
+23 1 1
+1796 2 0
+5015 6 1
+1383 8 0
+2368 1 1
+31 1 0
+1883 3 0
+335 0 1
+4157 0 1
+561 4 0
+1538 1 1
+61 0 1
+159 0 2
+3362 4 0
+3333 1 1
+46 1 1
+2321 7 6
+150 1 0
+5972 0 2
+840 0 2
+55 1 1
+28 1 1
+1154 0 2
+650 0 4
+30 0 4
+1100 10 11
+4343 6 0
+1663 4 0
+150 1 0
+3128 1 0
+1449 1 0
+2023 0 1
+428 3 6
+299 2 0
+427 7 7
+1914 14 14
+1273 7 7
+1444 72 0
+423 0 4
+969 23 22
+2430 1 0
+190 8 8
+2034 3 1
+5337 42 42
+1017 1 1
+34 1 1
+485 1 0
+348 7 0
+770 1 1
+28 0 13
+1425 0 1
+302 0 1
+659 12 12
+293 0 1
+610 0 1
+906 12 0
+1331 0 6
+1686 26 26
+74 0 1
+463 0 1
+4305 0 4
+1041 1 0
+11424 3 1
+13797 0 8
+166 0 1
+1510 5 0
+9069 0 8
+25 1 1
+332 5 3
+76 0 1
+1306 1 1
+46 1 1
+134 19 23
+1467 1 1
+32 1 1
+449 17 0
+367 9 9
+3525 12 10
+91 3 0
+226 33 33
+1171 1 1
+24 1 1
+1156 9 13
+843 1 1
+28 1 1
+515 0 17
+1559 0 4
+1045 9 9
+1953 1 0
+31 1 1
+843 0 1
+2174 1 0
+3788 1 0
+2001 0 1
+2400 0 1
+1614 1 0
+8167 0 1
+2700 2 0
+2735 0 1
+8708 0 3
+448 1 1
+22 1 1
+2215 1 1
+32 1 1
+2413 14 14
+142 1 0
+789 1 1
+45 1 1
+154 1 1
+25 1 1
+465 1 1
+45 6 4
+541 1 1
+42 1 1
+1339 5 6
+391 1 1
+20 0 1
+251 1 1
+22 1 1
+561 0 2
+78 3 0
+1718 1 1
+12 1 1
+1042 1 1
+38 1 1
+301 14 0
+222 10 10
+436 10 10
+1564 1 1
+17 1 1
+1752 20 0
+1561 135 0
+58 0 45
+245 101 11
+46 90 0
+150 0 270
+54 180 0
+2130 12 12
+1630 1 1
+26 1 1
+189 0 14
+296 2 0
+809 2 0
+17 20 0
+665 0 40
+236 1 1
+44 1 1
+352 1 1
+25 1 1
+554 6 6
+850 1 1
+33 1 1
+809 3 13
+1832 7 9
+468 1 1
+21 1 1
+951 1 1
+22 1 1
+219 17 18
+733 0 14
+215 2 2
+36 1 1
+301 1 1
+22 1 1
+241 1 1
+52 0 1
+47 1 1
+72 1 1
+109 1 1
+129 1 1
+28 1 1
+174 8 8
+683 3 0
+1190 285 0
+439 13 13
+927 12 0
+557 17 17
+932 3 1
+27 1 1
+166 1 1
+19 1 1
+406 1 1
+48 3 3
+137 1 0
+161 6 6
+884 2 0
+58 1 1
+107 1 1
+150 14 14
+522 1 1
+28 1 1
+945 4 4
+34 1 1
+472 0 2
+203 0 1
+281 1 1
+46 1 1
+1130 1 0
+232 17 17
+510 1 1
+33 1 1
+62 10 10
+1501 1 1
+20 1 1
+573 1 1
+29 1 1
+928 0 3
+304 1 1
+41 1 1
+160 1 1
+58 1 1
+656 1 1
+40 4 0
+108 6 6
+321 1 1
+14 0 16
+91 1 1
+184 1 1
+43 8 3
+180 1 1
+68 1 1
+144 1 1
+27 1 0
+17 1 1
+212 0 1
+212 1 1
+34 1 1
+115 1 1
+41 1 1
+407 10 10
+200 1 1
+44 2 0
+187 2 0
+146 1 1
+17 1 1
+122 4 4
+73 1 0
+56 1 1
+155 1 17
+80 15 15
+458 1 1
+16 3 3
+343 1 1
+111 1 1
+201 14 14
+157 12 12
+346 0 2
+382 4 0
+35 1 1
+937 0 1
+246 25 0
+52 0 1
+419 0 1
+165 1 0
+75 24 3
+297 1 1
+38 1 1
+5066 1 0
+4922 7 9
+2488 14 14
+2241 1 1
+67 4 4
+39 1 0
+547 1 1
+43 1 1
+524 3715 901
+1796 4 2
+128 29 29
+415 1 1
+18 1 1
+367 0 89
+1600 0 6
+2175 0 5
+606 14 14
+519 1 0
+540 1 1
+40 1 1
+568 2 0
+165 1 2
+31 1 1
+259 1 1
+41 1 1
+1106 40 62
+818 1 1
+42 1 1
+565 1 1
+44 1 1
+571 10 8
+61 1 1
+28 1 1
+233 2 0
+33 28 0
+53 1 1
+37 1 1
+75 0 396
+156 1 0
+473 0 4
+421 1 1
+35 1 1
+2132 1 1
+80 0 2
+544 9 9
+152 2 1
+33 1 1
+2977 0 1
+164 22 0
+149 1 0
+534 1 1
+36 1 1
+113 1 1
+15 1 1
+661 1 1
+48 1 1
+1987 1 0
+34 1 1
+444 1 1
+45 1 1
+65 1 1
+67 1 1
+210 1 1
+68 1 1
+55 1 1
+47 1 1
+169 1 1
+64 1 1
+109 0 6
+77 2 32
+6 0 5
+67 0 1
+7 16 0
+51 12 0
+36 0 12
+700 1 1
+33 1 0
+49 0 2
+450 0 1
+98 4 0
+489 32 0
+63 5 1
+78 7 7
+538 17 17
+1269 1 0
+841 1 1
+43 1 1
+1257 49 49
+698 1 1
+41 1 1
+86 0 4
+5 1 0
+36 1 1
+573 2 1
+297 1 0
+85 1 1
+30 1 1
+1041 1 0
+12 1 1
+392 33 12
+515 5 6
+583 1 1
+33 1 1
+616 16 16
+1052 0 11
+39 1 1
+184 1 1
+67 1 1
+102 7 7
+58 0 1
+307 1 1
+56 0 3
+918 2 0
+1295 0 1
+832 1 1
+28 1 1
+272 1 1
+82 1 1
+56 1 0
+976 6 6
+2015 0 3
+84 9 9
+130 13 17
+564 10 15
+154 1 0
+438 10 10
+38 0 5
+2141 1 1
+25 1 1
+73 10 10
+70 5 5
+132 1 1
+52 1 1
+599 1 1
+46 1 1
+279 1 1
+18 1 1
+239 2 0
+383 6 0
+224 0 1
+321 3 0
+8 16 0
+1775 1 1
+18 2 0
+575 16 16
+60 1 1
+16 1 1
+1247 2 0
+173 3 0
+41 1 1
+57 8 8
+285 2 0
+672 1 1
+44 1 1
+106 0 1
+148 1 1
+49 3 0
+146 5 11
+91 1 1
+79 1 1
+94 1 1
+101 1 1
+88 16 16
+117 1 1
+15 1 1
+58 1 1
+93 1 1
+140 1 0
+326 1 1
+44 1 1
+160 1 1
+23 1 1
+481 14 14
+181 4 4
+72 1 1
+25 1 1
+88 1 3
+36 0 12
+92 1 1
+56 10 0
+13 0 1
+66 1 1
+141 2 0
+65 1 1
+367 0 2
+610 1 1
+22 1 1
+150 1 1
+85 1 1
+109 1 1
+167 3 1
+23 1 0
+26 1 1
+74 1 1
+33 1 1
+176 1 1
+25 2 2
+193 42 43
+377 0 5
+249 1 1
+69 1 1
+98 1 1
+62 1 1
+62 1 2
+74 0 1
+68 1 1
+438 1 1
+64 1 1
+47 0 8
+125 3 0
+75 5 5
+45 1 1
+197 1 1
+27 1 1
+116 13 13
+218 15 20
+1107 16 19
+73 1 1
+25 1 1
+199 1 1
+60 1 1
+994 1 1
+43 0 1
+18 1 1
+1215 18 18
+340 1 1
+34 1 1
+1358 8 8
+1726 4 4
+193 82 82
+263 1 1
+18 1 1
+411 19 19
+175 1 1
+49 1 1
+146 1 1
+61 1 1
+116 1 1
+41 1 1
+137 1 1
+30 1 1
+158 9 9
+136 10 13
+349 8 8
+468 1 1
+44 1 1
+862 17 17
+813 1 1
+24 1 1
+214 10 4
+228 1 1
+34 1 1
+101 12 12
+242 1 1
+69 1 1
+185 1 1
+24 1 0
+164 0 1
+222 1 1
+25 1 1
+297 10 10
+1171 1 0
+182 1 1
+35 1 1
+2335 83 83
+491 7 7
+208 13 12
+298 1 1
+65 1 1
+193 2 2
+28 1 1
+125 4 4
+95 7 7
+566 1 1
+40 1 1
+118 0 1
+318 1 0
+374 1 1
+58 1 1
+143 1 1
+74 1 1
+53 21 0
+81 1 1
+45 1 1
+138 15 16
+180 1 1
+62 1 1
+661 1 1
+48 1 1
+1463 1 0
+156 0 1
+148 1 1
+19 1 0
+17 1 1
+1927 4 0
+1469 14 14
+466 0 1
+3098 0 1
+1141 2 3
+743 14 14
+79 1 1
+22 1 1
+362 0 1
+682 16 9
+275 0 4
+462 1 1
+76 1 0
+47 1 0
+13 0 8
+331 0 4
+130 1 1
+31 0 3
+1554 1 1
+43 1 1
+224 1 1
+49 1 1
+159 3 0
+1064 27 27
+104 1 1
+21 1 1
+222 2 2
+49 1 1
+1397 1 1
+37 1 1
+414 0 2
+695 1 1
+31 1 1
+742 1 1
+21 1 1
+230 3 2
+42 1 1
+68 1 1
+37 1 1
+703 0 3
+2216 1 1
+82 1 0
+1430 1 1
+23 1 1
+1867 13 0
+35 1 1
+137 16 16
+1500 4 0
+4546 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+498 3 0
+321 0 1
+281 3 0
+414 1 1
+70 1 1
+284 1 0
+214 1 1
+28 1 1
+280 1 0
+650 1 1
+47 1 1
+1030 1 1
+91 1 1
+6520 5 5
+478 1 0
+76 1 1
+2771 0 3
+1930 0 4
+2915 1 1
+20 1 1
+413 1 0
+1844 11 11
+133 0 6
+569 10 10
+110 12 12
+184 0 3
+228 1 1
+43 2 2
+51 14 13
+1499 1 0
+12 1 1
+378 1 1
+49 1 1
+424 1 0
+1131 1 1
+80 0 1
+821 2 9
+311 1 6
+247 1 1
+86 1 1
+1850 1 1
+26 1 1
+498 1 1
+34 1 1
+688 5 9
+44 1 1
+369 1 1
+69 1 1
+156 2 0
+83 1 1
+128 1 1
+50 9 9
+249 1 1
+70 0 1
+624 2 0
+74 2 1
+300 1 1
+26 1 1
+240 4 0
+1705 1 1
+52 1 1
+231 29 24
+378 2 0
+236 1 1
+76 1 1
+116 9 12
+380 0 6
+43 1 1
+384 15 15
+1414 5 0
+225 0 2
+1234 1 0
+29 1 1
+235 10 10
+227 1 1
+77 4 0
+43 5 9
+485 7 7
+380 10 0
+46 1 0
+90 1 1
+161 1 1
+401 1 1
+58 1 1
+2127 3 0
+186 20 20
+323 5 5
+47 1 1
+236 1 1
+31 0 2
+1692 13 14
+202 0 3
+77 1 1
+44 1 1
+411 12 11
+317 0 2
+599 39 39
+391 1 0
+273 1 0
+744 0 4
+703 1 1
+20 1 1
+198 3 0
+158 1 1
+14 4 0
+27 12 0
+282 1 1
+32 4 0
+740 1 0
+327 1 1
+105 1 1
+146 16 16
+101 1 0
+21 1 1
+232 1 1
+33 2 0
+12 1 1
+189 1 1
+30 2 2
+544 1 1
+153 1 1
+586 5 0
+1351 21 0
+446 1 1
+32 1 1
+136 7 7
+1147 12 12
+734 44 43
+701 1 1
+29 2 2
+154 12 12
+191 1 1
+55 1 1
+28 0 1142
+172 15 18
+525 1 1
+22 1 1
+355 10 10
+50 0 8
+252 1 1
+31 1 1
+354 6 5
+148 15 15
+407 1 1
+42 1 1
+275 0 1
+737 5 9
+1432 1 1
+39 1 1
+84 0 2
+77 7 7
+919 7 1
+815 1 1
+45 1 1
+487 1 1
+66 1 1
+2379 0 24
+779 1 1
+18 1 0
+2653 4 0
+34 1 1
+191 1 1
+35 1 1
+1174 12 0
+2497 25 1525
+447 8 0
+3268 1 0
+946 1 0
+2277 0 2
+1446 1 1
+77 1 1
+313 1 1
+44 1 0
+52 19983 20030
+61 7 7
+61 1 1
+120 1 1
+366 1 1
+55 1 1
+121 1 1
+62 1 1
+78 1 1
+48 1 1
+161 1 1
+26 1 1
+191 1 1
+20 11 11
+550 1 1
+76 1 0
+20 1 1
+112 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+83 1 1
+46 1 1
+1500 1 1
+81 1 1
+210 1 1
+26 1 1
+713 1 1
+48 1 1
+723 0 3
+196 6 6
+62 2 2
+32 1 1
+606 1 2
+357 1 1
+38 292 0
+589 1 1
+30 1 1
+714 8 8
+639 1 1
+20 1 1
+1068 0 1
+571 1 1
+49 1 1
+436 0 1
+609 0 2
+30 1 1
+66 0 1
+349 11 11
+65 1 1
+40 1 1
+717 0 3
+299 1 1
+29 1 1
+724 1 0
+275 1 1
+33 1 1
+318 0 3
+279 1 1
+28 1 1
+389 1 0
+548 0 8
+330 1 1
+47 1 1
+170 1 1
+47 1 1
+519 14 14
+841 24 24
+732 1 1
+29 3 3
+688 2 2
+23 0 1
+94 14 14
+726 13 13
+508 0 12
+21 6 0
+69 1 1
+37 1 1
+590 1 1
+59 1 1
+89 11 11
+164 1 1
+58 1 1
+1709 18 18
+520 1 1
+27 1 1
+683 10 10
+814 1 1
+26 1 1
+350 1 1
+39 1 1
+132 6 6
+439 1 1
+38 41 6
+15 0 1
+5 4 11
+81 1 1
+19 0 2
+167 1 1
+90 0 2
+85 1 1
+78 1 1
+87 19 2
+53 23 0
+255 0 1
+211 1 1
+54 1 1
+206 0 1
+60 35 33
+279 1 1
+76 179 180
+90 1 1
+119 3 0
+19 1 1
+60 1 1
+347 0 4
+30 2 2
+68 1 1
+78 1 1
+298 5 5
+67 1 1
+99 1 1
+97 1 1
+74 1 1
+52 1 1
+44 1 1
+65 1 4
+349 14 14
+109 1 1
+159 2 2
+214 9 9
+97 1 1
+73 1 1
+58 1 1
+42 1 1
+133 1 1
+99 0 10
+124 12 12
+281 3 0
+940 2 2
+49 1 1
+303 1 1
+25 1 1
+309 15 22
+384 1 1
+24 1 1
+896 1 1
+56 1 1
+168 0 19
+54 0 6
+60 0 1
+13 1 1
+502 1 1
+4 0 1
+23 1 1
+581 1 1
+47 1 1
+122 15 15
+3352 1 1
+23 1 1
+873 4 4
+887 1 0
+1827 1 0
+216 6 6
+805 2 0
+874 0 8
+2266 1 1
+47 1 1
+736 25 29
+86 1 1
+19 1 1
+1794 9 9
+271 0 1
+2266 1 1
+34 1 1
+916 0 1
+21 1 1
+108 21 21
+141 1 1
+27 1 1
+406 3 0
+3830 59 59
+61 1 1
+38 1 1
+128 2 2
+56 1 1
+72 0 1
+96 1 1
+22 1 1
+169 7 7
+511 1 1
+38 1 1
+1070 1 1
+90 1 1
+50 1 1
+41 1 0
+30 1 1
+659 12 12
+701 1 1
+33 1 1
+569 15 15
+70 1 1
+38 1 1
+955 0 3
+130 1 1
+63 1 1
+251 8 8
+191 1 1
+26 0 3
+187 1 0
+916 5 1
+70 13 13
+498 1 0
+55 0 1
+242 25 25
+237 1 1
+20 0 1
+61 1 1
+203 6 6
+262 1 1
+154 1 1
+104 1 1
+20 1 1
+156 1 1
+32 1 1
+88 17 17
+139 13 13
+148 20091 20061
+944 1 1
+126 1 1
+81 6 6
+41 3 0
+641 1 1
+92 1 0
+113 1 1
+39 1 1
+671 1 1
+28 1 1
+123 1 1
+59 1 1
+210 1 1
+17 1 1
+168 15 14
+494 1 0
+22 1 1
+484 18 18
+376 1 1
+114 2 0
+67 1 1
+10 1 1
+109 1 1
+165 1 1
+149 6 6
+234 1 1
+19 5 5
+64 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+168 1 1
+73 1 1
+194 1 1
+50 0 4
+37 1 1
+95 3 1
+43 1 1
+153 1 1
+83 1 1
+55 1 1
+39 1 1
+70 7 0
+59 7 7
+75 1 1
+84 2 2
+110 1 0
+42 1 1
+341 13 13
+262 4 4
+67 1 1
+32 1 0
+38 1 1
+277 7 7
+318 1 1
+145 1 1
+90 1 1
+19 4 4
+61 1 2
+31 1 1
+52 1 1
+214 1 1
+61 10083 10104
+701 2 0
+4080 1 1
+38 1 1
+837 0 64
+172 1 1
+55 1 1
+1818 2 0
+1143 13 13
+335 1 0
+1944 5 0
+39 6 0
+4057 3 8
+9465 5 4
+301 19 1
+191 84 0
+427 1 1
+29 0 4
+157 4 5
+296 21 18
+158 2 2
+36 1 1
+539 13 13
+399 1 1
+46 1 1
+348 1 1
+49 1 1
+268 1 0
+66 0 4
+178 2 2
+107 1 1
+133 5 5
+355 1 1
+30 1 1
+346 1 1
+29 1 1
+161 1 1
+38 1 1
+121 4 4
+55 8 8
+67 7 7
+318 17 17
+259 1 1
+94 1 1
+80 1 1
+35 1 1
+260 1 1
+81 1 1
+106 1 1
+58 1 2
+55 1 1
+245 3 0
+2052 1 1
+40 1 1
+174 20 22
+574 0 2
+414 1 0
+234 0 1
+425 51224 51060
+13549 39 40
+2617 0 2
+884 1 1
+19 1 1
+676 1 1
+63 1 1
+3138 0 3
+3038 5 2
+132 10 6
+136 18 13
+363 1 1
+89 1 1
+382 1 1
+29 1 1
+58 8 7
+297 4 0
+66 1 1
+93 2 0
+145 1 1
+31 5 5
+576 1 1
+89 1 1
+1256 0 12
+67 1 1
+193 2 2
+23 1 1
+51 1 0
+727 1 0
+1148 12 12
+837 1 1
+77 1 1
+941 10 10
+776 19 19
+300 1 1
+24 1 1
+256 1 7
+93 1 1
+191 174 172
+563 1 1
+104 4 4
+2898 1 1
+46 1 1
+282 1 1
+39 1 1
+204 2 2
+22 1 1
+469 1 1
+20 1 1
+140 1 1
+26 1 1
+745 0 2
+539 0 6
+1536 1 0
+817 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+132 5 0
+555 1 1
+42 1 1
+573 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+15 1 5
+1404 0 1
+934 1 1
+49 1 1
+1350 1 0
+384 1 1
+24 1 1
+3117 10 10
+1042 0 15
+244 10 10
+2167 18 14
+64 1 1
+31 1 1
+185 0 4
+1647 1 1
+20 1 1
+227 1 1
+37 1 1
+636 3 4
+5590 1 1
+39 1 1
+461 0 2
+2145 1 1
+23 1 1
+1114 0 2
+688 0 1
+901 18 18
+4781 0 4
+815 0 1
+5069 0 5
+415 0 1
+2743 1 1
+78 1 1
+390 1 0
+328 0 1
+878 0 1
+5752 0 2
+1554 1 1
+60 1 1
+278 0 1
+19 1 1
+1164 11 11
+691 0 2
+960 1 0
+62 0 20
+2108 0 2
+1265 0 1
+1642 2 0
+3584 2 0
+12086 2 0
+3766 0 2
+1209 1 7
+3466 1 0
+1448 1 0
+1943 0 1
+698 0 8
+1166 1 1
+34 1 1
+2120 11 9
+540 1 0
+1736 14 0
+3128 0 2
+4464 0 1
+120 4 4
+3473 1 0
+378 1 0
+1269 0 3
+1182 1 0
+654 0 3
+2049 1 0
+6838 1 1
+69 0 3
+154 1 0
+2718 1 1
+30 1 1
+160 11 11
+4954 0 1
+420 1 1
+123 1 1
+156 0 4
+219 4 0
+195 1 0
+4402 3 0
+3045 0 1
+1249 1 0
+3522 0 10
+812 8 0
+346 0 1
+8538 5 0
+455 1 0
+119 0 1
+1127 1 0
+10948 1 0
+833 0 1
+4251 1 0
+8 1 1
+2079 0 1
+1735 8 12
+1612 0 1
+1373 5 0
+8585 7 0
+64 1 1
+3799 1 0
+258 2 0
+899 1 0
+1362 8 9
+593 0 2
+3351 2 0
+618 0 4
+905 2 15
+2797 1 0
+2776 2 0
+4110 0 6
+4466 18 18
+2267 0 4
+134 1 0
+12963 8 0
+1616 0 2
+1685 2 0
+2225 2 0
+428 0 1
+3338 0 3
+677 4 6
+325 11 1
+1887 0 1
+913 0 1
+997 5 5
+2814 17 15
+1389 1 0
+1200 0 4
+2495 1 0
+3921 26431 26426
+2419 0 1
+6110 0 1
+1370 0 1
+3085 1 0
+3568 1 1
+24 0 9
+597 1 0
+2642 1 0
+1545 10 0
+4952 0 1
+6146 2 0
+1452 1 0
+2967 1 0
+4920 5 0
+147 4 5
+850 1 0
+1875 1 0
+695 3 1
+1719 0 1
+259 0 1
+294 1 0
+128 0 2
+3051 0 1
+908 0 4
+3399 0 1
+909 17 17
+3747 1 0
+3179 1 0
+411 1 1
+44 1 1
+174 1 0
+1047 17 17
+998 178 0
+671 0 40
+2093 1 0
+313 0 1
+7168 78 78
+335 1 0
+3245 1 0
+972 0 4
+4085 2 0
+346 1 1
+45 1 1
+368 1 0
+26 1 1
+8444 0 1
+17044 1 0
+2795 2 0
+2860 1 0
+622 0 1
+167 0 5
+1968 0 2
+259 2 0
+4992 29 27
+170 1 0
+3528 0 1
+191 1 2
+117 2 0
+2275 1 0
+12676 1 1
+20 1 1
+9972 1 0
+13955 0 5
+19867 1 0
+5866 0 32737
+3746 1 0
+20549 1 1
+19 1 1
+970 8 8
+5220 1 0
+15573 0 1
+6799 0 16
+3350 0 1
+7574 0 12
+2132 0 1
+7228 52793 52800
+2675 0 1
+2149 1 0
+6880 0 2
+960 0 1
+23 1 1
+2646 2 0
+3867 5 0
+24765 29 29
+1283 0 3
+3174 1 0
+8183 0 1
+2817 10 0
+4539 43 43
+1259 1 0
+2081 0 1
+374 0 2
+3589 0 4
+13928 3 0
+773 7 7
+175 1 1
+79 1 1
+400 12 12
+1096 0 4
+717 7 7
+52 1 1
+68 5 1
+2117 0 3
+130 14 14
+1124 0 3
+413 0 4
+643 3 0
+58 1 1
+127 1 1
+208 0 2
+45 1 1
+168 3 0
+136 3 4
+79 44 44
+170 1 1
+25 0 3
+63 1 1
+417 0 2
+412 0 16
+737 4 0
+402 2 0
+654 1 1
+42 1 1
+75 1 1
+64 1 1
+938 1 1
+53 1 1
+1987 4 0
+576 0 1
+29 2 2
+715 1 1
+36 1 1
+767 4 40
+44 1 5
+43 49 5
+709 21 21
+1147 9 9
+22 1 1
+195 7 4
+659 3 0
+27 1 1
+637 1 1
+42 1 1
+531 1 1
+67 1 1
+39 1 0
+717 11 11
+53 1 1
+61 1 1
+1535 1 1
+89 0 1
+49 1 0
+102 1 1
+67 1 1
+76 1 1
+129 1 1
+85 1 1
+607 10 0
+12 137 1
+41 1 1
+1043 1 1
+22 1 1
+203 3 0
+480 14 21
+1459 2 1
+435 15 17
+1188 30 0
+1778 1 0
+120 0 3
+3797 1 0
+887 1 1
+58 1 1
+2264 0 1
+2456 4 0
+954 0 4
+1847 0 1
+5929 20 20
+984 14 0
+2112 1 0
+2013 1 0
+4884 1 0
+1160 16 0
+733 7 7
+238 3 2
+2203 2 1
+5654 1 1
+28 5 10
+482 0 1
+2970 0 4
+2892 0 1
+251 1 7
+1346 1 0
+877 0 4
+3583 0 1
+1178 0 1
+1293 0 2
+491 2 0
+3501 46 46
+3256 1 1
+22 1 1
+2218 1 1
+44 1 1
+4780 4 0
+3026 14 13
+442 5 5
+2022 6 6
+546 2 0
+31 1 1
+8485 1 1
+36 1 0
+1575 1 0
+1329 1 1
+35 1 0
+247 1 1
+16 1 1
+184 1 1
+18 1 1
+1607 53 60
+527 1 1
+39 1 1
+653 3 0
+227 1 1
+18 1 1
+218 0 323
+91 1 0
+124 0 15
+621 0 2
+555 8 8
+467 1 1
+40 1 1
+372 1 1
+25 1 1
+188 12 12
+357 0 2
+2389 1 1
+22 1 1
+2579 0 5
+461 1 1
+36 1 1
+1584 1 1
+26 1 0
+429 1 0
+33 1 1
+1071 0 4
+1068 9 0
+1472 0 2
+1859 1 1
+61 2 0
+9 1 1
+337 1 1
+46 1 1
+416 1 1
+42 1 1
+1060 25 25
+170 0 2
+628 17 15
+587 15 15
+398 3 0
+696 6 9
+287 10 0
+191 0 2
+493 1 1
+42 4 0
+219 0 1
+408 1 1
+23 1 1
+283 1 1
+21 1 1
+633 2 0
+241 6 6
+457 1 0
+330 0 16
+428 1 0
+4 6 0
+324 0 1
+3063 0 2
+9960 39 40
+1850 0 6
+6431 0 1
+8674 0 4
+4595 11 0
+5064 2 0
+2813 12 12
+1391 5 0
+3690 1 1
+64 1 1
+2635 1 1
+49 1 1
+69 1 1
+15 1 1
+1009 8 0
+735 0 20
+3074 2 0
+1879 0 1
+572 0 8
+576 1 1
+42 1 1
+265 24 0
+209 11 11
+953 1 1
+42 0 5
+58 1 0
+95 1 0
+1121 1 1
+17 1 1
+751 0 1
+24 1 1
+351 1 1
+43 3 3
+565 1 1
+15 1 1
+150 27 27
+94 1 0
+323 1 1
+23 1 1
+221 7 7
+705 9 0
+631 2 0
+64 1 1
+1577 1 1
+21 0 1
+371 7 21
+160 0 1
+283 1 1
+48 1 1
+227 1 1
+40 0 1
+1359 0 2
+836 13 13
+722 7 7
+1153 1 1
+93 1 1
+797 14 14
+433 8 0
+108 11 11
+140 1 1
+40 1 1
+470 1 1
+42 1 1
+1106 0 1
+85 4 4
+129 1 1
+123 1 0
+95 1 1
+104 6 1
+641 1 1
+77 1 1
+57 1 1
+62 1 1
+473 2 0
+262 6 0
+45 1 1
+63 2 0
+39 1 1
+267 0 1
+197 2 104
+87 111 0
+122 0 7
+88 0 4
+108 5 0
+563 14 14
+324 1 0
+205 1 1
+17 1 1
+495 0 1
+201 4 0
+14 1 1
+887 1 1
+58 1 1
+133 1 1
+24 1 1
+91 24 24
+342 1 1
+32 1 1
+121 1 1
+62 1 1
+2371 2 0
+164 8 1
+655 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+1780 2 0
+742 1 1
+40 1 1
+2014 1 0
+1741 3 0
+3833 0 1
+16381 3 3
+25 1 1
+234 161226 190028
+3106 0 1
+1680 1 1
+88 1 1
+4502 0 1
+46 1 1
+800 4 4
+23 1 1
+1305 2 0
+136 0 1
+4941 0 1
+547 0 1
+70 8 8
+293 1 1
+35 1 1
+1165 4 0
+6662 1 1
+46 1 1
+167 0 8
+214 1 1
+35 1 1
+108 1 0
+1063 0 1
+1017 1 1
+20 0 6
+1725 0 1
+134 68 67
+349 1 1
+24 0 1
+1562 1 1
+31 1 1
+2513 0 1
+73 36 36
+305 1 1
+27 1 1
+543 1 1
+47 4 28
+4387 20058 20058
+159 1 1
+36 1 1
+107 1 1
+176 1 1
+154 0 5
+91 1 1
+54 1 1
+77 1 1
+238 2 2
+50 1 1
+1421 1 1
+23 1 1
+216 1 1
+122 1 1
+86 1 1
+41 3 1
+336 7 7
+41 9 0
+107 1 1
+90 8 9
+53 1 1
+30 1 1
+213 1 1
+26 1 1
+138 1 1
+25 1 1
+206 1 1
+36 3 3
+37 7 0
+500 1 1
+52 1 1
+52 1 1
+48 1 1
+395 1 1
+66 6 6
+72 1 0
+69 1 1
+100 10 10
+160 1 0
+64 7 7
+89 1 1
+123 1 1
+128 1 1
+36 1 1
+231 1 1
+61 1 1
+564 8 8
+593 1 1
+45 1 1
+163 1 0
+196 8 8
+174 5 5
+37 1 1
+67 0 1
+192 1 1
+60 3 0
+19 1 1
+1149 1 1
+18 1 1
+77 1 1
+32 2 0
+32 1 1
+136 1 1
+78 2 0
+162 4 0
+41 1 1
+351 13 13
+1634 2 0
+229 8 8
+57 13 2
+410 1 1
+76 1 1
+180 1 1
+92 1 1
+270 1 1
+40 1 1
+92 1 1
+53 1 1
+227 1 1
+42 1 1
+357 4 4
+23 1 1
+94 1 0
+200 6 0
+201 7 7
+70 5 13
+57 4 0
+35 1 1
+206 1 1
+76 2 2
+651 1 1
+68 4 0
+73 1 1
+49 4 0
+37 1 1
+145 2 2
+78 2 2
+108 12 12
+52 1 1
+35 1 1
+242 1 3
+76 2 2
+50 12 12
+70 1 1
+33 0 2
+57 1 1
+64 15 15
+168 1 1
+22 1 1
+66 2 2
+6 0 1
+24 1 1
+73 0 2
+64 1 1
+177 2 0
+19 4 0
+55 1 0
+33 1 1
+51 1 1
+122 1 1
+296 1 1
+85 1 1
+109 1 1
+64 1 1
+155 1 1
+58 0 2
+72 1 1
+25 1 1
+128 1 1
+45 2 0
+334 4 4
+106 1 1
+25 1 1
+64 1 1
+21 1 1
+368 15 15
+734 2 0
+701 15 15
+71 1 1
+41 1 1
+77 1 1
+56 1 1
+478 2 0
+714 8 7
+95 2 2
+50 4 3
+1129 1 1
+34 1 1
+1715 1 1
+87 1 1
+692 1 1
+47 0 1
+75 1 1
+2155 10 10
+1265 1 1
+46 1 1
+298 1 1
+22 1 1
+186 1 1
+34 1 1
+202 1 1
+61 1 0
+185 1 1
+24 1 0
+98 0 2
+258 8 14
+967 1 1
+15 1 1
+625 1 0
+1362 0 4
+23365 4 0
+246 26975 26986
+3307 0 1
+13671 3 3
+52 1 1
+1308 2 0
+942 0 1
+17790 1 0
+4586 0 1
+949 0 2
+15047 0 1
+606 2 0
+7820 0 4
+22313 16 0
+10539 8 0
+4836 0 1
+8726 2 0
+194 1 1
+49 1 1
+320 1 1
+34 1 1
+6813 0 1
+8719 3 0
+5482 46 46
+1509 1 0
+721 0 1
+999 6 0
+17 1 0
+3075 5 0
+593 13 11
+4505 1 0
+9535 0 4
+23 0 2
+23 2 0
+513 0 3
+377 1 0
+2627 0 2
+16 0 1
+211 18 18
+571 2 0
+7617 0 1
+1607 1 0
+69 1 1
+66 1 1
+275 1 1
+67 7 0
+25 1 1
+1206 1 0
+136 8 7
+612 1 1
+61 1 1
+740 0 2
+233 1 1
+95 0 4
+1483 13 28
+1062 1 0
+108 4 0
+685 0 2
+1566 1 0
+192 4 4
+1452 9 45
+1514 1 1
+46 1 1
+1969 0 1
+35 1 1
+1094 1 0
+618 1 1
+43 1 1
+6580 1 0
+1636 5 0
+6325 1 1
+32 1 1
+1041 0 2
+174 9 0
+4023 14 14
+8106 8 8
+2203 10 8
+2025 1 1
+39 1 1
+907 4 4
+225 1 1
+124 1 1
+3928 0 22
+38 2 0
+44 18 0
+46 0 6
+61 0 1
+3653 6 0
+34 1 1
+4559 1 1
+28 1 1
+283 5 5
+1951 1 1
+34 1 1
+443 19 19
+57 1 1
+21 1 1
+231 1 1
+94 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 40 40
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 5 5
+23 1 1
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+339 1 1
+56 0 5
+142 1 1
+232 1 1
+43 1 1
+332 1 1
+47 1 1
+479 1 0
+137 0 3
+1456 10 13
+63 1 1
+37 1 1
+261 0 2
+109 1 1
+50 1 1
+56 129 1
+88 1 0
+44 1 1
+54 1 1
+56 1 50
+58 50 1
+54 277 1
+44 1 1
+297 0 39
+142 1 1
+85 1 1
+124 16 16
+58 3 15
+677 1 0
+1333 2 0
+13591 6 0
+989 1 1
+107 1 1
+678 1 1
+31 1 1
+2571 5 5
+56 2 2
+39 1 1
+3986 0 4
+18351 32 30
+10811 1 1
+25 0 1
+129 62 62
+226 1 1
+40 1 1
+159 4 4
+37 4 4
+179 1 1
+51 1 1
+103 2 0
+108 1 1
+79 1 1
+25 1 1
+58 1 1
+12 1 1
+275 14 0
+80 1 1
+83 1 1
+24 1 1
+59 1 0
+91 1 1
+65 1 1
+67 1 1
+136 4 0
+68 8 0
+331 5 0
+40 1 1
+110 10 6
+64 1 1
+368 1 1
+22 1 1
+509 1 1
+89 1 1
+926 1 0
+959 1 1
+44 1 1
+72 11 0
+47 1 1
+361 1 1
+37 1 1
+2204 2 2
+45 1 1
+1117 18 18
+141 1 1
+47 1 1
+148 1 1
+75 1 1
+107 57 56
+146 3 2
+249 1 1
+146 1 1
+94 1 1
+34 1 1
+700 0 331
+21 1 1
+73 1 1
+49 1 1
+356 1 1
+16 1 1
+112 1 1
+36 9 0
+515 1 1
+27 2 2
+192 1 1
+53 0 14
+82 1 1
+302 1 1
+68 1 1
+52 12 12
+52 1 1
+34 1 1
+166 7 7
+384 1 1
+31 1 1
+281 1 1
+57 1 1
+176 0 1
+1625 1 1
+26 1 1
+369 1 1
+21 1 1
+86 1 1
+134 1 1
+215 1 1
+214 15 1
+50 2 2
+26 1 1
+78 0 19
+64 1 1
+126 1 1
+43 1 1
+433 1 1
+76 0 1
+6 12 0
+52 1 1
+108 1 1
+87 1 1
+62 1 1
+26 1 1
+291 2 1
+143 1 1
+29 1 1
+56 12 12
+230 1 1
+153 4 4
+87 32 32
+584 12 12
+227 1 0
+1931 4 0
+836 1 1
+68 1 1
+205 24 19
+816 1 2
+1932 0 7
+1732 13 0
+257 4 0
+1441 1 0
+111 6 0
+1505 1 1
+42 0 1
+373 13 13
+565 1 1
+76 1 0
+1881 0 4
+68 4 0
+43 0 4
+2201 8 8
+3726 3 0
+339 15 11
+249 1 1
+35 1 1
+250 1 1
+38 1 1
+359 11 12
+109 1 1
+43 18 0
+822 1 1
+53 1 1
+325 15 15
+123 1 1
+42 6 6
+240 1 1
+44 1 1
+438 7 7
+142 2 0
+1004 0 1
+9275 1 1
+37 1 0
+2071 0 1
+10399 0 1
+12513 2 1
+11243 1 1
+26 1 1
+816 4 0
+8248 26 26
+7722 2 0
+1594 1 0
+363 5 0
+6757 47 41
+2700 1 0
+823 18 19
+1807 0 2
+2565 11 0
+2089 0 2
+477 1 0
+657 0 1
+776 0 20
+365 82 49
+779 0 1
+391 35 73
+441 0 2
+1152 0 2
+1315 1 0
+5352 6 8
+902 0 1
+2154 1 1
+36 1 1
+109 0 1
+668 6 0
+1923 0 1
+91 3 2
+3560 1 0
+1235 1 0
+139 26 0
+831 3 3
+6547 1 0
+155 0 14
+2393 1 1
+33 1 1
+507 4 0
+1337 0 1
+9954 3 0
+1588 1 0
+2605 1 1
+23 1 1
+3000 0 3
+8249 8 0
+912 0 1
+338 2 0
+734 1 0
+4332 1 0
+416 0 4
+1691 0 1
+295 1 0
+214 2 0
+121 0 1
+784 0 1
+2512 0 1
+1205 21 21
+3239 12 11
+926 1 0
+190 1 0
+5780 0 1
+490 5 0
+228 1 1
+45 1 1
+207 3 0
+322 0 1
+633 1 1
+24 1 0
+1516 5 0
+1025 0 13
+1518 0 1
+591 10 10
+1061 1 0
+1371 1 1
+22 1 1
+928 0 2
+182 8 0
+328 1 0
+301 0 1
+994 1 1
+18 0 6
+1743 0 1
+2350 22 23
+1548 0 2
+1498 8 6
+7484 0 3
+2988 7 7
+93 2 0
+322 1 0
+280 1 1
+49 1 1
+2114 16 17
+617 0 1
+1012 0 1
+495 1 0
+29 1 1
+3134 1 0
+1837 0 4
+4079 0 1
+905 8 0
+5764 0 1
+3493 0 20
+1174 0 1
+900 0 1
+1006 1 0
+1699 0 1
+1682 1 0
+688 1 1
+21 1 1
+3349 0 1
+384 3 1
+3616 3 0
+748 0 1
+3001 0 10
+541 1 0
+286 1 1
+22 0 1
+250 1 1
+27 1 1
+898 1 0
+1161 0 2
+2067 0 1
+8000 0 12
+857 29 0
+1399
+
+chain 80965 chr6_qbl_hap6 4611984 + 2304864 2305721 chr6 170899992 - 139781917 139782778 1559017
+341 0 4
+516
+
+chain 72788 chr6_qbl_hap6 4611984 + 3854428 3855228 chr11 134452384 + 117706218 117707111 1729754
+615 13 107
+119 2 1
+51
+
+chain 45972 chr6_qbl_hap6 4611984 + 2517561 2519479 chr10 135374737 + 90380381 90382315 2786707
+110 146 146
+63 324 322
+53 379 396
+81 331 331
+99 110 110
+78 40 41
+104
+
+chain 30865 chr6_qbl_hap6 4611984 + 3846325 3846844 chr6 170899992 + 32821259 32821748 4483191
+73 89 59
+184 77 77
+96
+
+chain 26769 chr6_qbl_hap6 4611984 + 2264712 2264997 chr1 247249719 - 83196058 83196343 6075821
+285
+
+chain 22241 chr6_qbl_hap6 4611984 + 1157838 1158189 chr4 191273063 + 37186911 37187262 8835264
+178 101 101
+72
+
+chain 17263 chr6_qbl_hap6 4611984 + 3740215 3740422 chr4 191273063 + 3978296 3978500 12788148
+50 3 0
+26 4 4
+124
+
+chain 16745 chr6_qbl_hap6 4611984 + 2635745 2635946 chr11 134452384 + 74426248 74426449 13289834
+113 12 12
+76
+
+chain 16124 chr6_qbl_hap6 4611984 + 3115310 3115488 chr2 242951149 + 128261675 128261851 618783
+28 10 8
+140
+
+chain 15557 chr6_qbl_hap6 4611984 + 3932244 3933069 chr7 158821424 + 130132312 130132930 14485186
+71 636 429
+118
+
+chain 14855 chr6_qbl_hap6 4611984 + 3933226 3933509 chr9 140273252 - 14741363 14741645 15225313
+54 109 108
+120
+
+chain 14065 chr6_qbl_hap6 4611984 + 3751984 3752136 chr6 170899992 - 138279004 138279156 16120856
+152
+
+chain 13590 chr6_qbl_hap6 4611984 + 3850351 3850495 chr2 242951149 + 178053314 178053458 16703161
+144
+
+chain 13364 chr6_qbl_hap6 4611984 + 3822393 3822546 chr3 199501827 + 102278307 102278460 16996123
+67 1 1
+85
+
+chain 13024 chr6_qbl_hap6 4611984 + 983771 983907 chr11 134452384 - 45905925 45906061 17454498
+136
+
+chain 12452 chr6_qbl_hap6 4611984 + 4259490 4260232 chr12 132349534 + 123152186 123152605 1903988
+57 408 105
+14 32 63
+45 0 78
+44 129 0
+13
+
+chain 12361 chr6_qbl_hap6 4611984 + 1196738 1196868 chr1 247249719 + 48758029 48758159 18440544
+130
+
+chain 12272 chr6_qbl_hap6 4611984 + 2525057 2525213 chrX 154913754 + 154847615 154847763 18572106
+71 1 1
+25 8 0
+51
+
+chain 12201 chr6_qbl_hap6 4611984 + 1151149 1151920 chr6 170899992 - 139553108 139553881 18681505
+54 620 622
+97
+
+chain 11746 chr6_qbl_hap6 4611984 + 1143997 1144145 chr7 158821424 - 7754727 7754875 19419749
+54 14 14
+80
+
+chain 11418 chr6_qbl_hap6 4611984 + 3733988 3734369 chr6 170899992 + 32605989 32606372 19978843
+55 244 246
+82
+
+chain 11340 chr6_qbl_hap6 4611984 + 3744880 3745292 chr11 134452384 + 42855603 42856006 20116653
+57 275 266
+80
+
+chain 11205 chr6_qbl_hap6 4611984 + 3740546 3740663 chr3 199501827 + 102893757 102893874 20360983
+117
+
+chain 10738 chr6_qbl_hap6 4611984 + 3746512 3746633 chr10 135374737 + 59270705 59270823 21232184
+61 3 0
+57
+
+chain 10686 chr6_qbl_hap6 4611984 + 2524205 2524726 chr18 76117153 + 11332173 11332695 21332094
+80 388 389
+53
+
+chain 10567 chr6_qbl_hap6 4611984 + 3783253 3785836 chr6 170899992 + 32627140 32629242 21577879
+86 1741 1742
+57 646 164
+53
+
+chain 10496 chr6_qbl_hap6 4611984 + 3742563 3742673 chr1 247249719 - 172266041 172266151 21720781
+110
+
+chain 10342 chr6_qbl_hap6 4611984 + 3760212 3760942 chr6 170899992 + 32656559 32657213 22046794
+78 598 522
+54
+
+chain 10139 chr6_qbl_hap6 4611984 + 1198462 1198648 chr16 88827254 + 79406655 79406844 22494560
+65 65 68
+56
+
+chain 9962 chr6_qbl_hap6 4611984 + 3745365 3745830 chr4 191273063 - 17741127 17741604 22894345
+65 340 352
+60
+
+chain 9923 chr6_qbl_hap6 4611984 + 1132589 1132693 chr6 170899992 + 29984509 29984613 22990380
+104
+
+chain 9560 chr6_qbl_hap6 4611984 + 1145748 1145849 chr6 170899992 - 141000133 141000234 23851260
+101
+
+chain 9413 chr6_qbl_hap6 4611984 + 2517880 2518811 chr3 199501827 - 190559447 190560375 2816976
+26 220 218
+60 531 530
+94
+
+chain 9385 chr6_qbl_hap6 4611984 + 3871626 3871831 chr16 88827254 - 20600009 20600189 24262926
+58 92 67
+55
+
+chain 9214 chr6_qbl_hap6 4611984 + 1148380 1148477 chr6 170899992 + 29866137 29866234 24599827
+97
+
+chain 9032 chr6_qbl_hap6 4611984 + 3792044 3793708 chr6 170899992 + 32600177 32601830 24897719
+61 1516 1505
+87
+
+chain 8560 chr6_qbl_hap6 4611984 + 1158286 1158614 chr13 114142980 - 5380936 5381417 10250153
+58 237 390
+33
+
+chain 8241 chr6_qbl_hap6 4611984 + 3817008 3817095 chr6 170899992 + 65319659 65319746 26041518
+87
+
+chain 7487 chr6_qbl_hap6 4611984 + 3850495 3850589 chr16 88827254 + 12353631 12353725 21356530
+23 11 11
+60
+
+chain 7405 chr6_qbl_hap6 4611984 + 3933869 3933948 chr6 170899992 + 125781203 125781282 27398065
+79
+
+chain 7276 chr6_qbl_hap6 4611984 + 3821398 3821474 chr6 170899992 - 67344251 67344327 27653186
+76
+
+chain 7270 chr6_qbl_hap6 4611984 + 2635437 2635524 chr9 140273252 - 10289268 10289355 16248608
+13 11 11
+63
+
+chain 7204 chr6_qbl_hap6 4611984 + 3822572 3822648 chr7 158821424 - 147092048 147092124 27788942
+76
+
+chain 6530 chr6_qbl_hap6 4611984 + 3872997 3873065 chr8 146274826 + 43408268 43408336 29217082
+68
+
+chain 6522 chr6_qbl_hap6 4611984 + 3873792 3873861 chr15 100338915 + 41279078 41279147 29241048
+69
+
+chain 6486 chr6_qbl_hap6 4611984 + 3835377 3835446 chr4 191273063 - 136771275 136771344 29334522
+69
+
+chain 6459 chr6_qbl_hap6 4611984 + 2621390 2621459 chr6 170899992 + 31350859 31350928 29378034
+69
+
+chain 6457 chr6_qbl_hap6 4611984 + 1204555 1204622 chr6 170899992 + 30336816 30336883 29393800
+67
+
+chain 6422 chr6_qbl_hap6 4611984 + 3863961 3864029 chr6 170899992 + 32836685 32836753 29490928
+68
+
+chain 6404 chr6_qbl_hap6 4611984 + 3933974 3934042 chr7 158821424 + 141217888 141217956 29535655
+68
+
+chain 6368 chr6_qbl_hap6 4611984 + 2524965 2525057 chr6 170899992 - 132294381 132294479 20980275
+55 29 35
+8
+
+chain 6276 chr6_qbl_hap6 4611984 + 3873712 3873778 chrX 154913754 + 50967168 50967234 29833134
+66
+
+chain 5979 chr6_qbl_hap6 4611984 + 3850589 3850678 chr7 158821424 + 47749290 47749379 21749072
+4 34 34
+51
+
+chain 5976 chr6_qbl_hap6 4611984 + 2623961 2624024 chr6 170899992 + 31358648 31358711 30614264
+63
+
+chain 5908 chr6_qbl_hap6 4611984 + 1197012 1197085 chr19 63811651 - 42248237 42248310 20723418
+73
+
+chain 5877 chr6_qbl_hap6 4611984 + 3715034 3715097 chr6 170899992 + 32648139 32648202 30861180
+63
+
+chain 5767 chr6_qbl_hap6 4611984 + 3872292 3872353 chr6 170899992 + 75566512 75566573 31174250
+61
+
+chain 5730 chr6_qbl_hap6 4611984 + 1160462 1160522 chr6 170899992 + 29878483 29878543 31293472
+60
+
+chain 5694 chr6_qbl_hap6 4611984 + 3933682 3933742 chr5 180857866 - 92908144 92908204 31375044
+60
+
+chain 5621 chr6_qbl_hap6 4611984 + 1160085 1160144 chr6 170899992 + 29878108 29878167 31597733
+59
+
+chain 5594 chr6_qbl_hap6 4611984 + 2515502 2515561 chrX 154913754 - 63050736 63050795 31662666
+59
+
+chain 5458 chr6_qbl_hap6 4611984 + 3834959 3835017 chr16 88827254 + 47978524 47978582 32101539
+58
+
+chain 5276 chr6_qbl_hap6 4611984 + 3754169 3754225 chr6 170899992 + 32648605 32648661 32642677
+56
+
+chain 5193 chr6_qbl_hap6 4611984 + 3872547 3872601 chr5 180857866 + 130110350 130110404 32896488
+54
+
+chain 5176 chr6_qbl_hap6 4611984 + 1146649 1146704 chr14 106368585 + 78419238 78419293 32952450
+55
+
+chain 5094 chr6_qbl_hap6 4611984 + 3834697 3834751 chr6 170899992 + 68023473 68023527 33192803
+54
+
+chain 4984 chr6_qbl_hap6 4611984 + 3871272 3871324 chr1 247249719 - 76982562 76982614 33591211
+52
+
+chain 4959 chr6_qbl_hap6 4611984 + 3742510 3742563 chr18 76117153 + 5080594 5080647 22154819
+53
+
+chain 4930 chr6_qbl_hap6 4611984 + 3744490 3744542 chrX 154913754 - 4434310 4434362 33717622
+52
+
+chain 4923 chr6_qbl_hap6 4611984 + 1158016 1158078 chr9 140273252 - 102391777 102391839 11227006
+62
+
+chain 4829 chr6_qbl_hap6 4611984 + 1205079 1205129 chr6 170899992 + 30567298 30567348 34088060
+50
+
+chain 4815 chr6_qbl_hap6 4611984 + 2517906 2519257 chr1 247249719 + 7396807 7398156 2855562
+25 959 957
+58 214 214
+95
+
+chain 4391 chr6_qbl_hap6 4611984 + 4260111 4260156 chrX 154913754 - 99121082 99121127 30173418
+45
+
+chain 4349 chr6_qbl_hap6 4611984 + 2517042 2517321 chr5 180857866 + 51070260 51070539 3385343
+66 110 110
+103
+
+chain 4295 chr6_qbl_hap6 4611984 + 2516110 2516164 chr13 114142980 + 40947099 40947153 23509762
+54
+
+chain 3734 chr6_qbl_hap6 4611984 + 3932378 3932443 chr6 170899992 + 80018577 80018642 19955879
+65
+
+chain 3600 chr6_qbl_hap6 4611984 + 3934098 3934136 chr2 242951149 + 129304609 129304647 25766390
+38
+
+chain 3399 chr6_qbl_hap6 4611984 + 1196935 1197002 chr12 132349534 + 50414483 50414550 19205048
+67
+
+chain 3394 chr6_qbl_hap6 4611984 + 3746476 3746512 chrX 154913754 - 4438295 4438331 28244178
+36
+
+chain 3148 chr6_qbl_hap6 4611984 + 3871684 3871717 chr2 242951149 + 38036197 38036230 24698966
+33
+
+chain 2975 chr6_qbl_hap6 4611984 + 2524285 2524321 chr3 199501827 - 94209737 94209773 24799760
+36
+
+chain 2972 chr6_qbl_hap6 4611984 + 1151921 1151961 chr6 170899992 + 30567024 30567064 20739259
+40
+
+chain 2845 chr6_qbl_hap6 4611984 + 2516686 2516716 chr3 199501827 - 158108130 158108160 26771673
+30
+
+chain 2771 chr6_qbl_hap6 4611984 + 2185017 2185049 chr16 88827254 + 61371572 61371604 11881976
+32
+
+chain 2691 chr6_qbl_hap6 4611984 + 3933197 3933226 chr3 199501827 - 121608742 121608771 23862843
+29
+
+chain 2671 chr6_qbl_hap6 4611984 + 2524905 2524964 chr9 140273252 - 60326471 60326530 21074055
+59
+
+chain 2645 chr6_qbl_hap6 4611984 + 3740797 3740872 chr19 63811651 - 40112981 40113056 21687959
+75
+
+chain 2599 chr6_qbl_hap6 4611984 + 1158078 1158116 chr7 158821424 - 126060947 126060985 11258555
+38
+
+chain 2365 chr6_qbl_hap6 4611984 + 3662868 3662893 chr9 140273252 - 56082033 56082058 25372966
+25
+
+chain 2302 chr6_qbl_hap6 4611984 + 2518282 2518373 chrX 154913754 + 17160841 17160932 3083108
+91
+
+chain 2226 chr6_qbl_hap6 4611984 + 2516716 2520208 chr12 132349534 + 103307685 103311177 3426888
+99 961 960
+41 2329 2330
+62
+
+chain 2196 chr6_qbl_hap6 4611984 + 3573229 3573252 chr8 146274826 - 36256974 36256997 29790670
+23
+
+chain 2146 chr6_qbl_hap6 4611984 + 1144210 1144271 chr12 132349534 + 104221177 104221238 23825291
+61
+
+chain 2027 chr6_qbl_hap6 4611984 + 2518845 2519837 chr4 191273063 + 75333400 75334396 3306565
+44 889 893
+59
+
+chain 2011 chr6_qbl_hap6 4611984 + 3750379 3750401 chr12 132349534 - 27555073 27555095 35529087
+22
+
+chain 2003 chr6_qbl_hap6 4611984 + 1715012 1715046 chr6 170899992 + 30558380 30558414 2034666
+34
+
+chain 1988 chr6_qbl_hap6 4611984 + 3744653 3744712 chr1 247249719 + 152912877 152912936 23823439
+59
+
+chain 1906 chr6_qbl_hap6 4611984 + 2517426 2517496 chr17 78774742 - 18978582 18978652 12332136
+70
+
+chain 1860 chr6_qbl_hap6 4611984 + 1158233 1158283 chr8 146274826 + 68242167 68242217 13480681
+50
+
+chain 1860 chr6_qbl_hap6 4611984 + 3858322 3861837 chr6 170899992 + 32830794 32834943 29475612
+61 2506 2690
+85 515 965
+52 103 103
+193
+
+chain 1658 chr6_qbl_hap6 4611984 + 1158189 1158222 chr4 191273063 + 153905795 153905828 11042895
+33
+
+chain 1451 chr6_qbl_hap6 4611984 + 2516912 2518845 chr18 76117153 + 57868323 57870253 3225031
+58 1841 1838
+34
+
+chain 1444 chr6_qbl_hap6 4611984 + 2517346 2518418 chr3 199501827 + 26257399 26258470 3460386
+77 968 967
+27
+
+chain 1437 chr6_qbl_hap6 4611984 + 2517932 2518010 chr9 140273252 - 113447512 113447590 4152331
+78
+
+chain 1395 chr6_qbl_hap6 4611984 + 2517496 2517525 chr4 191273063 + 177039024 177039053 17309502
+29
+
+chain 1388 chr6_qbl_hap6 4611984 + 4260176 4260219 chr19 63811651 - 48476446 48476489 2785288
+43
+
+chain 1332 chr6_qbl_hap6 4611984 + 3612848 3612887 chr2 242951149 - 44758440 44758479 1994605
+39
+
+chain 1326 chr6_qbl_hap6 4611984 + 2516425 2516540 chr2 242951149 - 193553846 193553961 4393012
+115
+
+chain 1313 chr6_qbl_hap6 4611984 + 4259851 4259901 chr1 247249719 - 36229834 36229933 2748513
+7 14 63
+29
+
+chain 1148 chr6_qbl_hap6 4611984 + 4259442 4259473 chr8 146274826 + 89694 89724 9819782
+12 1 0
+18
+
+chain 1111 chr6_qbl_hap6 4611984 + 1158412 1158466 chr19 63811651 - 5696793 5696847 17027637
+54
+
+chain 1071 chr6_qbl_hap6 4611984 + 2516561 2516628 chr12 132349534 + 77415638 77415705 9437720
+67
+
+chain 1001 chr6_qbl_hap6 4611984 + 4259418 4259442 chr1 247249719 + 40151331 40151355 3139135
+24
+
+chain 975 chr6_qbl_hap6 4611984 + 2516971 2517042 chr1 247249719 + 183489007 183489078 3337949
+71
+
+chain 917 chr6_qbl_hap6 4611984 + 2518025 2518086 chr8 146274826 - 9314035 9314096 4594958
+61
+
+chain 884 chr6_qbl_hap6 4611984 + 2519749 2519778 chr1 247249719 - 197271642 197271671 12501548
+29
+
+chain 844 chr6_qbl_hap6 4611984 + 2520091 2520119 chr7 158821424 + 107644180 107644208 22181631
+28
+
+chain 841 chr6_qbl_hap6 4611984 + 2516165 2516217 chr20 62435964 - 59823019 59823071 21526398
+52
+
+chain 836 chr6_qbl_hap6 4611984 + 4259969 4260001 chr3 199501827 + 123981761 123981793 2757122
+32
+
+chain 835 chr6_qbl_hap6 4611984 + 2519837 2519906 chr4 191273063 + 99162526 99162595 6917305
+69
+
+chain 764 chr6_qbl_hap6 4611984 + 1158466 1158505 chr14 106368585 - 57011112 57011151 17388689
+39
+
+chain 760 chr6_qbl_hap6 4611984 + 2520610 2520672 chr1 247249719 + 71360495 71360557 7931067
+62
+
+chain 760 chr6_qbl_hap6 4611984 + 2518460 2518519 chr12 132349534 + 56700130 56700189 25330836
+59
+
+chain 746 chr6_qbl_hap6 4611984 + 2519488 2519538 chr22 49691432 + 27063810 27063860 3889151
+50
+
+chain 745 chr6_qbl_hap6 4611984 + 2516014 2516077 chr6 170899992 + 44660392 44660455 3181879
+63
+
+chain 740 chr6_qbl_hap6 4611984 + 1158720 1158784 chr12 132349534 + 55464534 55464598 20832676
+64
+
+chain 718 chr6_qbl_hap6 4611984 + 2520835 2520890 chr9 140273252 - 49339912 49339967 23555331
+55
+
+chain 716 chr6_qbl_hap6 4611984 + 3933624 3933676 chr16 88827254 - 38714794 38714846 22851161
+52
+
+chain 710 chr6_qbl_hap6 4611984 + 2519659 2519709 chr11 134452384 - 107252690 107252740 6149242
+50
+
+chain 706 chr6_qbl_hap6 4611984 + 2516328 2516399 chr18 76117153 + 57376973 57377044 7676567
+71
+
+chain 700 chr6_qbl_hap6 4611984 + 2516815 2516871 chr1 247249719 + 47033162 47033218 11749470
+56
+
+chain 685 chr6_qbl_hap6 4611984 + 2520397 2520480 chr1 247249719 + 68246247 68246330 16545799
+83
+
+chain 662 chr6_qbl_hap6 4611984 + 2520752 2520817 chr5 180857866 + 99923773 99923838 9608666
+65
+
+chain 654 chr6_qbl_hap6 4611984 + 1158614 1158640 chr4 191273063 - 137719796 137719822 10317123
+26
+
+chain 604 chr6_qbl_hap6 4611984 + 2520031 2520091 chr8 146274826 - 111755913 111755973 4980877
+60
+
+chain 569 chr6_qbl_hap6 4611984 + 2515445 2515500 chr12 132349534 - 4861980 4862035 16127490
+55
+
+chain 521 chr6_qbl_hap6 4611984 + 2517182 2517218 chr15 100338915 - 47556137 47556173 3431041
+36
+
+chain 465 chr6_qbl_hap6 4611984 + 2518541 2518594 chrX 154913754 - 2978832 2978885 15318329
+53
+
+chain 465 chr6_qbl_hap6 4611984 + 2515257 2515307 chr13 114142980 + 94087883 94087933 15752176
+50
+
+chain 431 chr6_qbl_hap6 4611984 + 2516292 2516328 chrX 154913754 + 109116067 109116103 11044816
+36
+
+chain 377 chr6_qbl_hap6 4611984 + 2521082 2521150 chrX 154913754 - 100727898 100727966 10456810
+68
+
+chain 364 chr6_qbl_hap6 4611984 + 2519959 2520014 chr2 242951149 + 137419466 137419521 26497561
+55
+
+chain 357 chr6_qbl_hap6 4611984 + 2516242 2516292 chr3 199501827 + 59182343 59182393 15538406
+50
+
+chain 252 chr6_qbl_hap6 4611984 + 2519906 2519943 chr10 135374737 + 69013226 69013263 15789370
+37
+
+chain 172 chr6_qbl_hap6 4611984 + 3874043 3874094 chr1 247249719 - 204983626 204983677 25877237
+51
+
+chain 126 chr6_qbl_hap6 4611984 + 2521548 2521600 chr16 88827254 - 42325840 42325892 26081164
+52
+
+chain 345833726 chr6_ssto_hap7 4928567 + 0 4928567 chr6 170899992 + 28767121 33556332 37
+43705 3 0
+396 1 1
+36 1 1
+327 0 2
+458 8 0
+6175 1 1
+58 1 1
+80 0 7
+257 2 0
+2504 0 12
+1614 0 1
+1985 6 0
+370 1 0
+2206 2 0
+4292 4 0
+5173 33 8
+1486 4 4
+213 2 2
+71 0 1
+437 0 1
+897 1 1
+34 1 1
+10055 18 6
+2970 0 1
+813 0 15
+922 0 20
+1095 1 1
+43 1 1
+1829 0 1
+2885 0 10
+5273 0 1
+108 2 0
+571 0 3
+2338 1 0
+934 1 0
+2409 0 8
+2132 54 16
+77 1 52
+38 0 59
+40 0 2
+3908 1 0
+3045 2 4
+758 0 1
+174 15 15
+211 1 0
+608 0 4
+1434 2 0
+2061 2 0
+10205 0 6
+2011 17 17
+871 89 85
+91 0 2
+2644 33 29
+3737 1 1
+39 1 1
+1512 1 0
+2391 2 0
+844 0 1
+5198 0 1
+17000 0 1
+603 2 0
+4648 0 3
+2281 1 0
+38 1 1
+334 1 1
+41 1 1
+1760 1 0
+3862 0 6
+1025 160 0
+3444 3 0
+282 0 1
+1508 1 0
+2207 0 3
+1827 1 0
+3220 9 0
+5157 0 4
+1394 1 0
+279 0 2
+71 0 4
+163 1 1
+31 1 1
+280 8 0
+1059 0 2
+1409 0 4
+402 1 0
+643 0 2
+746 0 2
+1268 2 0
+267 0 1
+1868 1 1
+44 1 1
+8525 0 4
+1440 4 4
+127 0 6
+204 1 2
+873 1 0
+131 2 0
+3954 0 1
+1818 2 1
+4264 0 1
+3195 0 2
+2446 1 1
+70 26 25
+70 1 1
+1649 1 0
+953 0 1
+295 1 1
+32 0 6
+661 8 0
+5298 1 0
+1365 0 1
+6151 2 0
+1123 0 9
+2073 1 0
+611 1 0
+1129 0 3
+562 11 11
+9680 4 4
+316 19 19
+831 2 0
+3215 1 0
+1710 0 1
+2693 0 3
+4148 82 25
+807 0 1
+85 1 1
+114 1 1
+489 10 0
+936 43 43
+6001 0 1
+3807 5 0
+191 14 14
+73 0 1
+345 2 0
+3436 3 0
+780 1 0
+6 1 0
+2268 0 1
+569 5 5
+1359 2 1
+1049 3 0
+371 1 0
+5832 1 1
+13 1 1
+4064 0 105
+776 3 2
+1696 1 1
+34 1 1
+5830 0 3
+3442 1 1
+61 1 1
+472 1 0
+22361 20 19
+3288 0 3
+10522 4 0
+16901 2 0
+30045 7 0
+1489 1 1
+72 1 1
+2260 0 2
+7033 0 4
+3592 0 1
+11101 0 1
+8476 0 1
+1324 0 2
+5438 5 0
+2061 1 0
+3982 6 6
+1725 0 1
+3153 1 0
+18 1 0
+18 1 0
+2026 1 0
+4175 10 10
+4746 9 9
+4767 7 7
+1225 1 0
+8 1 1
+151 1 2
+5079 1 1
+28 1 1
+249 43 43
+1178 0 4
+685 12 0
+48 8 0
+1701 1 1
+43 5 5
+862 18 18
+58 1 1
+66 1 1
+420 1 1
+44 1 1
+680 4 4
+1675 1 1
+83 1 1
+3082 4 0
+5467 1 1
+27 0 1
+1099 16 0
+627 12 12
+1317 6 1
+129 1 1
+25 1 1
+1397 15 15
+810 1 1
+27 1 1
+1192 2 0
+7515 4 0
+979 0 3
+3406 0 2
+1730 11 11
+1760 1 1
+26 1 1
+787 0 1
+1416 3 1
+22815 4 4
+126 1 0
+38 1 1
+140 1 0
+1072 0 15
+15438 4 0
+6165 0 1
+1768 1 0
+7727 2 0
+1514 0 1
+3116 0 1
+3278 1 1
+21 1 1
+1738 0 1
+8576 19 0
+8020 1 0
+2049 1 0
+528 3 1
+1704 1 1
+117 1 1
+1448 10 0
+4403 9 9
+1142 9 9
+1114 1 0
+1382 1 1
+32 1 1
+1519 11 11
+2877 0 2
+1221 0 1
+1974 4 0
+71 32 24
+565 1 0
+1447 1 0
+1362 0 4
+4579 0 1
+3278 0 1
+2020 1 1
+31 1 1
+673 1 0
+2321 9 9
+155 1 1
+18 1 1
+1427 1 0
+4008 1 1
+59 2 0
+1998 11 0
+942 1 1
+39 1 1
+2252 1 0
+6944 0 4
+342 1 1
+16 1 1
+4918 1 1
+30 1 1
+1530 0 1
+313 1 1
+59 1 1
+1737 1 1
+34 1 1
+852 9 12
+1814 0 5
+742 0 318
+10 1 1
+484 0 2
+993 0 1
+312 4 0
+23 1 1
+476 0 1
+195 2 0
+1963 1 1
+25 1 1
+1942 1 1
+26 0 1
+13516 0 3
+40 1 1
+1374 20 0
+31 1 1
+189 1 1
+26 1 1
+327 1 1
+38 1 1
+177 11 11
+709 1 1
+38 1 1
+1803 1 1
+26 1 1
+2373 5 0
+321 1 0
+933 17 17
+82 9 9
+2773 0 143
+80 1 1
+25 1 1
+467 1 1
+27 1 1
+143 1 1
+47 1 1
+1197 10 10
+1455 1 1
+33 1 1
+601 1 1
+48 0 2
+694 1 4
+132 1 1
+17 1 1
+167 6 6
+113 1 1
+31 1 1
+1181 0 1
+422 15 0
+36 1 1
+2219 1 1
+35 1 1
+2116 0 1
+15789 0 2
+24630 1 0
+7864 1 0
+13424 0 2
+12333 1 1
+41 1 1
+33759 6 0
+3090 1 1
+41 1 1
+2048 0 2
+462 1 0
+31504 22 0
+880 79442 79440
+1063 1 7
+1384 4 1
+85 1 0
+357 3 4
+9255 0 1
+6104 0 1
+6497 0 1
+713 0 4
+2181 2 0
+145 0 1
+1108 0 2
+1448 1 0
+1835 1 0
+4207 1 0
+5843 0 1
+1398 0 1
+5972 1 0
+7345 4 0
+2841 1 0
+361 1 0
+5438 0 1
+1889 0 3
+1737 2 0
+5252 2 0
+9241 0 10
+575 1 1
+30 2 2
+78 1 1
+49 1 1
+294 1 1
+37 1 2612
+385 17 17
+259 0 1
+107 32 32
+72 1 1
+29 1 1
+123 1 1
+121 1 1
+435 1 0
+32 1 1
+255 1 1
+52 1 1
+201 1 1
+59 0 2
+9 0 21
+72 0 2
+141 5 137
+425 1 1
+42 1 1
+572 1 1
+30 1 1
+560 1 1
+28 1 1
+98 0 12
+18 0 15
+144 13 13
+1410 1 0
+291 0 4
+1637 0 1
+231 1 1
+35 1 1
+2158 1 1
+21 1 1
+581 59 48
+181 4 0
+65 0 4
+603 3 0
+591 1 1
+23 1 1
+51 1 1
+38 1 1
+362 1 1
+44 1 1
+1935 0 2
+165 13 19
+1394 8 7
+450 7 0
+483 1 1
+27 1 1
+264 1 1
+51 1 1
+355 1 1
+45 1 1
+1717 0 4
+80 1 1
+18 1 0
+437 1 1
+38 1 1
+454 1 1
+40 1 1
+2320 1 1
+21 1 1
+161 1 1
+37 1 1
+1424 1 1
+48 1 1
+392 1 1
+35 1 1
+147 4 4
+436 1 1
+28 4 5
+144 3 0
+533 0 4
+437 1 9
+1714 0 1
+31 0 1
+850 16 16
+515 0 1
+58 1 1
+142 1 1
+33 1 1
+173 1 0
+753 1 1
+55 1 1
+573 0 4
+37 1 1
+144 8 8
+1004 0 4
+28 2 0
+153 15 15
+94 12 12
+201 12 13
+169 19 20
+118 10 15
+1254 0 2
+243 16 16
+73 1 1
+21 1 1
+196 0 28
+36 2 0
+18 1 1
+52 1 1
+29 1 1
+162 2 1
+373 1 0
+1159 0 32
+23 1 1
+674 0 3
+136 1 1
+48 1 1
+330 9 9
+1108 1 1
+98 1 1
+582 1 0
+715 7 7
+89 1 0
+115 1 1
+31 1 1
+145 9 8
+350 6 6
+145 1 1
+41 1 1
+681 1 1
+43 1 1
+518 1 1
+19 1 1
+582 16 16
+180 6 6
+993 0 7
+9811 1 1
+27 1 1
+1374 1 0
+1705 13 13
+4591 1 1
+9 1 1
+5418 1 0
+5474 33 33
+1261 74 190
+19692 5 1
+1674 4 4
+42 1 1
+593 1 1
+24 1 1
+457 10 10
+414 13 13
+825 1 1
+41 1 1
+492 0 8
+1196 1 1
+23 1 1
+149 1 1
+18 1 1
+1145 6 4
+880 1 1
+35 1 1
+236 1 1
+67 1 1
+298 0 1
+147 14 14
+312 11 11
+99 1 1
+43 1 1
+469 1 1
+62 1 1
+288 0 1
+51 1 1
+22 1 1
+204 1 1
+39 1 1
+812 1 1
+57 1 1
+358 1 1
+128 1 1
+146 10 10
+490 1 1
+20 1 1
+62 1 1
+88 1 1
+135 1 1
+47 1 1
+109 1 1
+28 1 0
+20 1 1
+83 0 1
+90 1 1
+312 1 1
+44 1 1
+1213 1 1
+51 1 1
+473 1 1
+33 1 1
+122 14 0
+35 1 1
+485 14 14
+110 9 0
+127 1 1
+746 1 1
+40 1 1
+50 1 0
+1765 5 5
+773 1 2
+48 1 0
+1699 1 0
+293 1 1
+33 13 0
+7 7 27
+303 1 1
+16 1 1
+289 1 1
+23 1 1
+217 1 1
+42 1 1
+320 1 1
+44 1 1
+298 1 1
+7 4 0
+32 0 7
+14 1 0
+6 5 37
+272 6 0
+1071 8 8
+143 10 10
+522 8 13
+85 1 1
+49 0 1
+90 1 1
+85 1 1
+89 1 1
+568 1 0
+265 0 2
+501 1 1
+36 1 1
+330 0 1
+1365 23 16
+81 1 1
+36 1 1
+184 0 1
+465 1 1
+26 1 1
+139 1 1
+87 0 3
+298 1 1
+45 1 1
+118 1 1
+44 1 1
+1277 6 4
+129 0 496
+233 1 1
+73 1 1
+1947 0 4
+265 1 1
+25 1 1
+200 6 6
+93 1 1
+34 2 2
+98 3 0
+1010 15 15
+366 1 0
+610 1 1
+21 1 1
+422 6 0
+358 1 1
+51 1 1
+700 40 40
+127 1 1
+51 2 2
+395 13 13
+148 0 5
+119 1 1
+103 1 1
+268 1 1
+22 1 1
+251 1 1
+34 1 1
+175 1 1
+36 1 1
+239 1 1
+32 5 5
+63 1 1
+126 1 1
+209 1 1
+143 1 13
+175 7 17
+393 1 1
+44 1 1
+129 1 1
+84 1 1
+140 8 0
+90 6 8
+450 1 1
+25 1 1
+265 1 1
+35 0 1
+17 2 0
+428 1 1
+92 1 1
+697 1 1
+34 1 1
+955 1 1
+45 1 1
+95 1 1
+29 1 1
+660 1 1
+18 1 1
+389 9 9
+252 3 0
+284 1 1
+38 1 1
+81 9 9
+90 1 1
+71 1 1
+132 0 6
+96 1 1
+257 3 0
+56 1 1
+159 1 1
+44 1 1
+409 34254 40035
+275 1 1
+38 1 1
+1307 1 1
+26 1 1
+1467 1 1
+27 1 1
+568 11 11
+693 1 1
+47 1 1
+276 11 11
+183 1 1
+40 1 1
+589 1 1
+26 1 1
+4216 2 1
+170 17 17
+893 2 0
+24 1 1
+2666 4 4
+545 1 1
+76 1 1
+163 4 0
+141 1 1
+108 1 1
+165 1 1
+72 1 1
+167 1 1
+33 0 1
+42 0 2
+83 0 2
+60 1 1
+84 1 0
+383 2 0
+736 15 15
+770 13 13
+76 14 14
+410 1 1
+43 1 1
+542 1 1
+81 1 1
+111 8 4
+137 1 1
+37 1 1
+127 1 1
+34 0 3
+45 1 1
+269 2 2
+126 1 1
+259 26 26
+257 2 2
+14 1 1
+114 5483 21566
+75 1919 964
+70 30518 17325
+308 1 1
+49 1 1
+285 29 27
+223 10 8
+230 1 2
+69 12 12
+705 0 2
+187 2 1
+402 1 0
+656 0 2
+614 1 1
+43 1 1
+781 3 1
+55 13 19
+1083 5 5
+38 1 1
+62 1 1
+80 1 1
+1217 1 1
+44 1 1
+2070 27 27
+259 1 1
+40 1 1
+115 1 1
+56 4 4
+478 1 1
+30 1 1
+162 11 11
+209 10 0
+150 1 1
+36 0 2
+31 1 1
+55 1 1
+51 1 1
+221 8 13
+386 1 1
+58 1 1
+397 3 0
+45 1 1
+547 1 1
+21 1 1
+4446 4 0
+1282 1 1
+44 1 1
+8862 1 0
+4998 10 10
+6533 1 0
+1116 28 28
+9230 19 0
+741 0 1
+2695 0 1
+5382 1 0
+4424 21 21
+3562 0 1
+381 1072 0
+6066 0 1
+1968 7 0
+3198 1 0
+667 1 0
+3902 17 4
+1895 1 1
+40 0 4
+1137 0 6
+205 2 0
+345 1 0
+1639 8 0
+686 5 0
+1032 0 1
+9206 0 4
+1574 1 0
+22388 1 0
+1656 2 0
+118 1 5
+4748 1 0
+2035 0 1
+1151 5 6
+1120 1 1
+20 1 1
+1533 16 0
+3103 0 1
+25 1 1
+2642 1 1
+43 0 3
+1703 0 1
+409 7 7
+527 1 0
+524 1 1
+59 1 1
+112 3 3
+50 1 1
+267 0 7
+286 14 14
+1161 2 0
+1003 0 1
+4062 1 0
+3850 4 0
+4977 0 1
+2718 1 0
+1588 1 1
+30 4 0
+879 0 1
+1332 18 12
+1688 4 4
+88 1 1
+439 2 0
+209 1 0
+1322 54 54
+893 1 1
+49 1 2
+1773 1 1
+24 1 1
+540 1 1
+41 1 1
+460 1 7
+165 1 1
+45 1 1
+903 1 2
+140 0 1
+36 1 1
+2019 0 1
+657 1 1
+48 1 0
+1329 0 1
+268 1 1
+47 1 1
+336 1 1
+25 2 0
+43 1 1
+1484 1 1
+53 1 1
+1151 1 1
+42 1 1
+1870 1 1
+24 5 5
+853 0 3
+23 0 1
+326 9 9
+131 9 9
+623 0 3
+34 1 1
+809 1 1
+36 1 1
+690 2 0
+44 1 1
+285 8 7
+455 1 1
+32 1 1
+102 1 1
+47 1 1
+4338 0 1
+5275 4 0
+11554 1 0
+409 16 17
+3476 0 1
+2160 0 24
+109 1 1
+3284 0 19
+2586 2 0
+757 1 1
+22 1 1
+860 17 24
+1584 1 0
+1582 0 2
+117 1 0
+1552 3 25
+17 0 4
+20 14 0
+42 9 0
+10 6 0
+10605 1 0
+4733 1 3
+371 4 0
+1177 1 1
+85 1 1
+40 0 1
+518 6 0
+646 13 13
+469 1 0
+1072 1 4
+565 1 1
+44 1 1
+3082 1 0
+839 1 0
+282 1 0
+597 0 6
+505 4 4
+45 1 1
+137 1 1
+43 1 1
+1294 1 1
+40 1 1
+572 0 5
+463 0 4
+1886 1 0
+548 1 0
+1300 0 3
+1839 2 0
+189 1 1
+49 1 1
+1253 1 1
+43 1 0
+498 1 1
+45 4 0
+3538 0 1
+1582 31 31
+376 14 14
+867 3 4
+253 1 1
+34 1 1
+172 2 0
+1094 0 1
+2856 1 1
+82 0 419
+125 3 0
+709 1 1
+36 1 1
+2189 16 17
+181 1 1
+109 0 1
+8 0 1
+53 1 1
+94 1 1
+49 1 1
+1495 15 0
+623 13 13
+163 1 1
+45 1 1
+2050 11 11
+474 1 1
+29 1 1
+1947 1 1
+42 1 0
+35 1 1
+751 1 0
+287 1 1
+60 1 1
+446 0 4
+2620 8 7
+1600 1 0
+11761 0 12
+3903 0 5
+4922 0 1
+1697 9 0
+379 0 1
+16104 1 0
+2244 0 14
+1780 1 1
+32 1 1
+9010 0 1
+296 0 1
+9862 0 1
+10107 1 0
+2415 11 9
+29829 0 12
+5348 0 1
+4837 0 1
+461 1 1
+37 1 1
+6200 4 0
+68 13 1
+2539 25 19
+1982 3 0
+5200 1 0
+162 0 9
+11963 1 1
+26 0 4
+206 1 0
+652 1 1
+27 1 1
+150 1 0
+1774 1 1
+18 1 1
+1410 4 4
+323 1 1
+64 5 5
+126 1 1
+28 1 1
+318 16 16
+579 1 1
+35 1 1
+206 1 1
+32 1 1
+50 1 1
+16 1 1
+279 1 1
+52 1 1
+167 16 16
+135 8 8
+802 1 1
+21 1 1
+278 1 1
+35 1 1
+663 1 1
+57 0 3
+29 1 0
+792 7 7
+111 1 1
+25 1 1
+387 1 1
+37 1 1
+55 1 1
+23 1 1
+623 1 1
+46 1 1
+494 1 1
+84 1 1
+276 0 2
+83 7 8
+114 1 1
+52 1 1
+48 0 1
+440 0 5
+101 1 1
+73 1 1
+329 0 2
+84 1 1
+41 1 1
+162 1 1
+29 1 1
+658 1 1
+28 1 1
+246 1 0
+155 28 28
+263 16 16
+1316 1 1
+29 1 1
+92 1 1
+30 1 1
+517 1 1
+23 1 1
+161 7 7
+668 1 1
+56 1 1
+761 1 1
+29 1 1
+276 16 16
+305 1 0
+546 3 5
+77 2 2
+45 0 2
+76 0 7
+18 1 1
+969 7 7
+84 0 3
+208 1 1
+25 1 1
+670 1 0
+179 0 1
+294 6 6
+578 1 1
+176 1 1
+216 1 1
+19 1 1
+142 4 4
+201 1 1
+34 1 1
+63 1 1
+49 1 1
+136 1 1
+112 0 1
+58 1 1
+46 1 0
+26 1 1
+80 0 3
+142 22576 22570
+400 1 1
+29 1 1
+982 0 2
+559 1 1
+59 1 1
+367 6 6
+288 1 1
+49 1 1
+193 1 1
+45 1 1
+183 16 16
+651 0 1
+136 1 1
+89 1 1
+341 14 14
+90 1 1
+151 1 1
+196 1 1
+66 1 1
+118 1 1
+55 1 1
+305 1 1
+81 1 1
+178 1 1
+18 1 1
+138 1 1
+103 1 1
+161 1 1
+27 1 1
+477 21 21
+417 2 2
+60 1 1
+51 1 1
+25 2 2
+231 1 1
+9 0 1
+24 1 1
+759 14 14
+107 1 1
+99 7 7
+236 1 1
+35 1 1
+121 1 1
+24 1 1
+92 0 2
+43 1 1
+68 1 1
+110 2 2
+52 1 1
+30 1 1
+201 1 1
+70 2 0
+99 1 1
+54 10 10
+125 0 1
+7 1 1
+132 18 25
+235 1 2
+189 1 1
+21 1 1
+278 1 1
+22 1 3
+22 1 1
+801 1 1
+51 1 1
+265 1 1
+84 1 1
+350 15 15
+259 1 0
+5 18 0
+368 1 1
+30 1 1
+840 1 1
+33 1 1
+490 1 1
+64 1 1
+1540 1 1
+37 1 1
+3927 1 1
+22 1 1
+316 0 5
+1069 0 2
+277 0 2
+69 14 0
+19 0 2
+31 2 0
+17 4 92
+2837 1 1
+197 2419 0
+840 1 1
+45 1 1
+176 1 0
+277 1 0
+1541 1 1
+17 1 1
+1434 18 22
+322 1 0
+193 0 1
+366 0 1
+493 1 0
+378 1 0
+1065 0 1
+4782 1 0
+656 13 13
+705 1 1
+49 0 3
+2315 0 3
+7693 2 0
+396 22 12
+918 0 1
+1126 0 4
+1210 1 1
+33 1 1
+326 1 1
+80 1 1
+288 8 17
+2671 0 1
+1244 1 1
+29 0 1
+2098 0 2
+24 4 0
+1207 4 4
+45 1 1
+175 34 34
+548 0 5
+1926 1 1
+40 1 1
+2657 0 1
+414 1 0
+61 0 1
+235 0 2
+2087 0 1
+713 0 4
+58 3 0
+1041 3 0
+36 1 1
+377 1 1
+17 1 1
+948 1 1
+41 1 1
+458 1 1
+21 1 1
+1055 0 1
+8168 1 1
+5 0 2
+18 1 0
+36 1 1
+99 2 0
+700 0 5
+148 0 1
+750 0 3
+40 1 1
+2428 0 1
+750 2 0
+473 0 2
+2032 1 0
+1184 2260 2258
+399 1 0
+560 1 0
+1108 1 0
+8087 1 0
+4298 0 2
+7581 1 1
+30 1 1
+4383 2 0
+10078 0 1
+906 4 0
+887 1 1
+80 1 1
+2210 1 0
+905 0 1
+1037 1 0
+5867 0 1
+18 1 1
+582 0 5
+2828 1 0
+847 1 0
+1996 1 0
+700 1 1
+4220 0 1
+910 2 0
+687 0 1
+32877 1 0
+19299 0 8
+1369 29 0
+494 2 0
+6182 1 0
+12 1 1
+23175 14263 14261
+152 1 0
+8727 0 1
+9606 1 0
+15258 1 0
+5758 8 0
+3591 1 0
+5707 0 28
+6100 34700 34698
+298 0 1
+28 1 1
+118 1 1
+24 1 18
+34 1 1
+75 1 1
+43 2 2
+73 1 1
+29 1 1
+246 1 1
+42 1 1
+409 4 4
+1168 10 1
+310 1 1
+49 1 1
+3002 1 1
+38 1 1
+789 0 1
+63 9 9
+2434 0 8
+980 0 2
+749 8 8
+528 1 1
+24 1 1
+1646 15 15
+528 1 1
+16 1 1
+165 12467 12465
+758 1 1
+45 1 1
+213 8 0
+51 1 1
+107 10 11
+134 2 0
+228 103 1
+51 2 1
+68 1 1
+59 1 1
+195 1 161
+13 1 1
+553 2 2
+36 1 1
+143 1 0
+1874 4 0
+519 0 1
+476 1 0
+1530 0 1
+1126 2 0
+831 1 1
+40 1 1
+1131 88 87
+598 1 1
+41 1 1
+1422 0 2
+1950 1 1
+32 1 1
+2037 0 2
+178 2 1
+7938 164527 164525
+7881 0 3
+162 1 1
+39 0 1
+281 1 1
+46 1 1
+1703 1 0
+1253 1 1
+48 1 1
+538 0 2
+576 1 1
+21 1 1
+561 1 0
+3867 10 10
+200 1 1
+29 1 1
+201 2 0
+508 11 11
+1281 1 1
+35 1 1
+299 0 1
+588 1 0
+1231 25 0
+52 0 1
+419 1 0
+1601 6 6
+4040 2 0
+4924 0 1
+4749 1 1
+67 4 4
+39 1 0
+1116 3715 901
+205 2 0
+1591 5 2
+128 29 29
+802 0 89
+1600 0 6
+2177 0 3
+606 14 14
+519 1 0
+540 1 1
+40 1 1
+568 2 0
+458 1 1
+41 1 1
+1105 5 0
+58 1 5
+30 1 1
+558 1 0
+229 1 1
+42 1 1
+610 1 1
+115 1 1
+214 12 12
+237 9 7
+279 1 1
+49 0 2
+13 5 11
+86 1 1
+627 1 0
+473 0 4
+974 7 7
+717 1 1
+19 1 1
+531 1 1
+47 1 1
+372 0 2
+703 0 1
+35 1 1
+53 1 1
+46 1 1
+1322 0 1
+45 1 1
+148 1 1
+19 1 1
+1293 1 1
+44 0 1
+158 0 2
+153 1 0
+1027 21 21
+315 1 1
+48 1 1
+647 0 1
+104 1 1
+31 1 1
+1332 1 1
+63 5 5
+392 5 5
+127 5 5
+68 8 8
+66 1 1
+172 1 1
+156 1 1
+77 1 1
+192 1 1
+25 0 23
+57 0 24
+39 6 0
+34 1 1
+713 1 1
+33 1 0
+507 2 3
+90 4 0
+489 40 0
+63 5 1
+623 17 17
+353 14 14
+1743 1 1
+43 1 1
+1257 49 49
+698 1 1
+41 1 1
+109 1 0
+22 1 1
+288 1 1
+16 1 1
+267 2 1
+175 0 1
+121 1 0
+1158 2 0
+12 1 1
+392 29 12
+515 5 6
+583 1 1
+33 1 1
+616 16 16
+1050 0 10
+42 1 1
+184 1 1
+67 1 1
+102 7 7
+58 0 1
+307 1 1
+36 4 0
+20 24 0
+921 1 0
+913 1 0
+304 0 1
+77 0 1
+756 106 106
+272 1 1
+82 1 1
+56 2 0
+367 4 7
+602 6 6
+2102 9 9
+96 1 1
+45 0 5
+564 10 15
+154 1 0
+438 10 10
+38 0 5
+94 9 13
+2034 1 1
+25 1 1
+73 10 10
+70 5 5
+132 1 1
+52 1 1
+599 1 1
+46 1 1
+279 1 1
+18 1 1
+622 6 0
+224 0 1
+321 16 0
+1783 1 1
+18 2 0
+575 16 16
+60 1 1
+16 1 1
+609 1 1
+28 1 1
+781 3 0
+41 1 1
+57 8 8
+285 2 0
+717 1 1
+85 1 1
+402 0 4
+23 1 1
+64 1 1
+56 1 1
+1387 0 1
+972 4 1
+2390 1 2
+120 0 4
+11 1 1
+652 2 86
+42 0 1
+85 0 1
+22 1 1
+323 1 1
+39 1 1
+185 1 1
+53 4 0
+127 3 0
+703 2 0
+15 1 0
+619 1 1
+45 1 1
+442 16 19
+73 1 1
+25 1 1
+194 1 1
+65 1 1
+129 1 0
+201 49946 49944
+3358 1 1
+25 1 1
+1926 1 1
+39 4 3
+1037 1 1
+40 2 0
+890 6 0
+41 2 0
+498 3 0
+321 0 1
+281 3 0
+414 1 1
+70 1 1
+284 1 0
+214 1 1
+28 1 1
+930 1 1
+47 1 1
+1030 1 1
+91 1 1
+1538 0 1
+3268 1 0
+2180 1 0
+2256 14 14
+594 0 3
+1930 0 4
+3114 1 0
+3833 1 1
+32 1 1
+1073 0 1
+2092 1 0
+38 1 0
+327 2 0
+460 0 6
+8619 0 1
+463 10 12
+315 7 7
+1903 1 1
+18 5 0
+227 5 0
+162 1 1
+28 1 0
+1043 1 0
+29 1 1
+334 1 1
+37 1 1
+177 4 0
+46 0 1
+4 2 2
+484 7 7
+230 1 1
+37 1 1
+81 0 6
+160 1 1
+206 1 1
+356 6 6
+54 1 0
+1704 1 1
+85 1 1
+51 13 13
+207 1 1
+57 2 0
+20 4 7
+59 1 1
+40 1 1
+80 5 5
+16 1 1
+169 12 12
+125 5 5
+119 1 1
+98 1 1
+458 1 1
+26 1 1
+1064 1 1
+30 1 1
+227 0 14
+264 1 1
+44 1 1
+422 1 0
+317 0 6
+282 9 9
+762 8 8
+237 1 0
+199 0 1
+47 1 1
+496 0 3
+1097 4 0
+188 11 11
+143 5 0
+740 1 0
+558 1 1
+36 1 1
+98 1 1
+23 1 1
+232 1 1
+21 0 1
+244 1 1
+35 1 1
+620 1 1
+56 1 1
+470 1 1
+16 1 1
+540 1 1
+42 1 1
+90 1 1
+32 1 1
+110 2 0
+609 12 6
+17 5 1
+21 1 1
+352 2 0
+56 1 1
+175 1 1
+769 1 1
+78 1 1
+87 6 6
+586 0 1
+51 1 1
+92 1 1
+23 1 1
+195 73 72
+619 1 0
+53 1 1
+29 2 2
+357 1 1
+84 1 0
+516 1 1
+41 1 1
+107 11 11
+323 22 25
+114 1 0
+1881 2 0
+1560 2 0
+5260 6 0
+1103 0 4
+832 2 1
+2627 3 11
+34 1 1
+599 0 3
+65 1 1
+230 1 1
+18 1 1
+484 24 0
+150 1 1
+42 1 1
+184 1 1
+8 0 1
+27 1 1
+320 9 9
+376 1 1
+48 1 1
+266 1 1
+44 1 1
+113 1 1
+104 1 1
+297 0 1
+522 0 1500
+471 4 0
+32 1 0
+124 1 1
+46 1 1
+784 8 8
+68 1 1
+21 4 0
+193 7 7
+457 1 1
+23 1 1
+906 1 1
+78 1 1
+385 4 5
+344 1 1
+32 1 0
+669 6 0
+37 1 1
+127 1 1
+29 1 1
+60 5 5
+48 1 1
+290 0 2
+1482 1 1
+39 1 1
+114 1 1
+37 0 4
+104 1 1
+257 1 1
+130 15 16
+158 8 0
+57 1 1
+332 2 2
+35 1 1
+197 1 1
+44 1 1
+106 1 1
+77 1 1
+313 1 1
+44 1 0
+52 19983 20030
+61 7 7
+61 1 1
+120 1 1
+366 1 1
+55 1 1
+121 1 1
+62 1 1
+78 1 1
+48 1 1
+161 1 1
+26 1 1
+191 1 1
+20 11 11
+550 1 1
+76 1 0
+20 1 1
+112 1 1
+149 1 1
+284 1 1
+37 1 1
+705 1 12
+106 12 12
+83 1 1
+46 1 1
+1500 1 1
+81 1 1
+210 1 1
+26 1 1
+713 1 1
+48 1 1
+723 0 3
+196 6 6
+62 2 2
+32 1 1
+606 1 2
+357 1 1
+38 292 0
+589 1 1
+30 1 1
+714 8 8
+639 1 1
+20 1 1
+1068 0 1
+571 1 1
+49 1 1
+436 0 1
+609 0 2
+30 1 1
+66 0 1
+349 11 11
+65 1 1
+40 1 1
+717 0 3
+299 1 1
+29 1 1
+724 1 0
+275 1 1
+33 1 1
+318 0 3
+279 1 1
+28 1 1
+389 1 0
+548 0 8
+330 1 1
+47 1 1
+170 1 1
+47 1 1
+519 14 14
+841 24 24
+732 1 1
+29 3 3
+688 2 2
+23 0 1
+94 14 14
+726 13 13
+508 0 12
+21 6 0
+69 1 1
+37 1 1
+590 1 1
+59 1 1
+89 11 11
+164 1 1
+58 1 1
+1709 18 18
+520 1 1
+27 1 1
+683 10 10
+814 1 1
+26 1 1
+350 1 1
+39 1 1
+132 6 6
+439 1 1
+38 41 6
+15 0 1
+5 4 11
+81 1 1
+19 0 2
+167 1 1
+90 0 2
+85 1 1
+78 1 1
+87 19 2
+53 23 0
+255 0 1
+211 1 1
+54 1 1
+206 0 1
+60 35 33
+279 1 1
+76 179 180
+90 1 1
+119 3 0
+19 1 1
+60 1 1
+347 0 4
+30 2 2
+68 1 1
+78 1 1
+298 5 5
+67 1 1
+99 1 1
+97 1 1
+74 1 1
+52 1 1
+44 1 1
+65 1 4
+349 14 14
+109 1 1
+159 2 2
+214 9 9
+97 1 1
+73 1 1
+58 1 1
+42 1 1
+133 1 1
+99 0 10
+124 12 12
+281 3 0
+940 2 2
+49 1 1
+303 1 1
+25 1 1
+309 15 22
+384 1 1
+24 1 1
+896 1 1
+56 1 1
+168 0 19
+54 6 14
+66 1 1
+502 1 1
+4 0 1
+23 1 1
+581 1 1
+47 1 1
+122 15 15
+3352 1 1
+23 1 1
+873 4 4
+887 1 0
+1827 1 0
+216 6 6
+805 2 0
+874 8 0
+2274 1 1
+47 1 1
+736 25 29
+86 1 1
+19 1 1
+1794 9 9
+271 0 1
+2266 1 1
+34 1 1
+916 0 1
+21 1 1
+108 21 21
+141 1 1
+27 1 1
+406 3 0
+3830 59 59
+61 1 1
+38 1 1
+128 2 2
+56 1 1
+72 0 1
+96 1 1
+22 1 1
+169 7 7
+511 1 1
+38 1 1
+1070 1 1
+90 1 1
+50 1 1
+41 1 0
+30 1 1
+659 12 12
+701 1 1
+33 1 1
+569 15 15
+70 1 1
+38 1 1
+955 0 3
+130 1 1
+63 1 1
+251 8 8
+191 1 1
+26 0 3
+187 1 0
+916 5 1
+70 13 13
+498 1 0
+55 0 1
+242 25 25
+237 1 1
+20 0 1
+61 1 1
+203 6 6
+262 1 1
+154 1 1
+104 1 1
+20 1 1
+156 1 1
+32 1 1
+88 17 17
+139 13 13
+148 20156 20120
+885 1 1
+113 1 1
+141 2 0
+842 1 0
+1246 1 1
+29 1 1
+898 1 1
+19 1 1
+333 1 1
+44 1 1
+220 1 1
+56 2 0
+209 1 1
+70 1 1
+223 0 20
+182 1 1
+69 1 1
+56 1 1
+111 1 1
+220 1 1
+89 1 1
+119 1 1
+113 2 0
+195 1 1
+46 1 1
+101 8 8
+85 1 1
+50 0 4
+76 0 4
+53 3 1
+43 1 1
+153 1 1
+53 1 1
+195 6 0
+60 1 1
+278 1 0
+42 1 1
+298 1 1
+54 1 1
+262 4 4
+67 1 1
+32 1 0
+28 1 1
+612 1 1
+78 1 1
+157 1 1
+19 1 1
+64 1 2
+31 1 1
+52 1 1
+51 1 1
+77 10295 10251
+91 1 1
+35 1 1
+5232 1 1
+47 1 1
+295 2 0
+2065 2 0
+1143 13 13
+335 2 0
+1944 4 0
+39 6 0
+4057 5 8
+535 1 1
+16 1 1
+1555 0 1
+3130 1 1
+17 1 1
+4196 1 0
+14974 0 1
+3667 2 6
+42 22 0
+63 2 0
+15 2 0
+61 0 160
+66 1 14
+70 2 0
+25 44 4
+49 6 77
+18 0 6
+24 0 2
+57 143 3
+61 0 2
+29 20 0
+37 0 2
+29 0 74
+58 1 29
+34 1 5
+21 31 0
+12 0 65
+62 11 0
+5 0 41
+68 1 42
+23 1 3
+12 2 0
+17 1 29
+51 29 1
+6 2 0
+25 53 1
+52 2 0
+125 19 58
+124 41 0
+51 49 29
+79 89 0
+53 21 0
+5064 0 2
+6897 1 1
+38 1 1
+2821 0 1
+85 1 1
+31 0 4
+399 14 14
+408 0 1
+956 1 1
+29 1 0
+9 2 0
+442 4 0
+342 1 1
+24 1 1
+131 1 1
+198 1 1
+370 0 1
+34 1 1
+447 21 20
+259 1 1
+23 0 1
+121 2 0
+2257 1 1
+22 1 1
+811 1 1
+27 1 1
+484 0 1
+259 0 5
+843 0 2889
+55 0 88
+1189 2 0
+2276 1 0
+353 8 0
+7126 0 1
+798 1 1
+31 0 1
+6 1 1
+268 1 1
+27 1 1
+131 0 2
+47 1 1
+367 1 1
+61 1 1
+84 14 14
+173 15 15
+883 1 1
+41 1 1
+1356 1 1
+134 1 1
+62 1 1
+18 1 1
+644 1 1
+17 1 1
+297 15 14
+1015 26 26
+1532 4 0
+16 1 1
+183 1 0
+2792 12 12
+2660 0 2
+254 1 2
+1369 1 0
+342 0 1
+49 1 1
+733 0 1
+50 82 82
+60 1 1
+48 1 1
+1488 1 0
+97 1 1
+84 6 6
+214 1 1
+37 1 1
+222 1 1
+53 1 1
+220 58 0
+238 0 3
+459 1 1
+39 1 1
+222 1 1
+67 1 1
+280 1 1
+45 0 16
+208 1 1
+39 1 1
+135 1 1
+46 1 1
+121 1 1
+19 1 1
+349 1 1
+30 1 1
+56 1 1
+23 1 1
+283 1 1
+51 2 2
+217 1 1
+44 1 1
+92 1 1
+36 1 1
+67 1 1
+38 3 1
+23 4 0
+598 1 1
+45 1 1
+663 1 1
+59 1 0
+10 1 1
+70 1 1
+65 2 0
+11 0 16
+36 1 1
+342 17 17
+70 0 3
+243 1 1
+55 1 1
+63 17 17
+2165 5 2
+132 10 6
+136 18 13
+363 1 1
+89 1 1
+382 1 1
+29 1 1
+58 8 7
+297 4 0
+66 1 1
+93 1 0
+145 1 1
+31 5 5
+576 1 1
+89 1 1
+811 16 16
+428 0 13
+67 1 1
+193 2 2
+23 1 1
+51 1 0
+727 1 0
+1148 12 12
+837 1 1
+77 1 1
+941 10 10
+776 19 19
+300 1 1
+24 1 1
+256 1 7
+93 1 1
+188 17 13
+117 1 1
+43 1 1
+563 1 1
+104 4 4
+2898 1 1
+46 1 1
+282 1 1
+39 1 1
+698 1 1
+20 1 1
+140 1 1
+26 1 1
+745 0 2
+541 6 0
+1540 1 0
+781 1 1
+35 4 4
+202 1 1
+48 1 1
+168 1 1
+53 1 1
+379 10 10
+1178 14 14
+132 5 0
+555 1 1
+42 1 1
+573 1 1
+21 1 1
+462 1 1
+43 1 1
+121 1 1
+48 0 3
+13 1 7
+8319 1 0
+21899 0 1
+8703 0 1
+1206 0 1
+13954 0 1
+12475 1 0
+6716 0 1
+3072 0 4
+7591 0 1
+3322 9 10
+539 1 0
+1736 14 0
+3128 0 2
+4464 0 1
+120 4 4
+3473 1 0
+378 1 0
+576 5 9
+684 0 3
+1182 1 0
+654 0 3
+2049 1 0
+6838 1 1
+39 1 1
+186 1 0
+2718 1 1
+30 1 1
+160 11 11
+4954 0 1
+420 1 1
+123 1 1
+156 0 4
+219 4 0
+195 1 0
+4402 3 0
+3045 0 1
+1249 1 0
+3522 0 10
+808 5 1
+349 0 1
+8538 5 0
+455 1 0
+119 0 1
+1127 1 0
+276 1 0
+10672 1 0
+833 0 1
+4251 1 0
+8 1 1
+2079 0 1
+1736 8 11
+1612 0 1
+1373 5 0
+2438 4 0
+6147 7 0
+64 1 1
+3799 1 0
+258 2 0
+899 1 0
+1362 8 9
+593 0 2
+3351 2 0
+618 0 4
+917 0 3
+2797 2 0
+2776 2 0
+23968 6 0
+1616 0 1
+1686 0 4
+2221 0 8
+252 14783 14780
+11763 0 1
+2431 1 0
+158 0 1
+281 1 0
+1573 0 1
+11079 1 0
+6938 0 1
+4376 61201 59265
+14552 0 4
+672 1 1
+26 1 1
+461 1 1
+33 0 2
+16 1 1
+649 1 1
+48 1 1
+818 1 1
+21 1 1
+424 1 1
+25 1 1
+632 1 1
+39 1 1
+310 1 1
+27 1 1
+616 1 0
+17043 23170 23168
+104 7 6
+290 3 3
+117 13 0
+2194 0 1
+191 0 1
+118 1 0
+1283 7 7
+723 1 0
+7453 1 0
+3382 0 1
+2179 0 49
+5260 0 1
+4607 1 0
+32465 1 0
+1362 0 1
+20971 5 4
+11765 9 9
+746 11 11
+19671 17 17
+439 16 16
+9146 0 3
+99 1 1
+19 1 1
+259 1 1
+57 1 1
+202 1 1
+27 1 1
+2009 9 9
+2299 1 1
+43 1 1
+1287 1 0
+22328 5 0
+47 12 0
+1295 77056 62052
+228 0 2
+615 1 0
+1965 0 2
+1466 1 0
+3821 0 1
+2806 1 1
+110 0 1
+1422 0 1
+324 1 0
+1825 1 0
+311 0 1
+11796 1 0
+2273 2 1
+6123 1 0
+18640 29 29
+1283 0 3
+167 1 0
+11393 6 6
+708 15 14
+1887 10 0
+509 1 0
+1581 1 1
+46 1 1
+811 1 1
+31 0 1
+1557 43 43
+1172 1 1
+18 1 1
+67 1 0
+2081 0 2
+373 0 4
+1829 1 1
+56 0 1
+1700 0 4
+2886 2 0
+14416 1 0
+2137 1 0
+2717 0 1
+1587 0 1
+7106 8 0
+2428 1 1
+50 1 0
+1082 1 1
+42 1 1
+639 1 0
+717 11 11
+53 1 1
+61 1 1
+454 1 1
+26 1 1
+1053 1 1
+60 1 1
+51 1 1
+26 1 0
+102 1 1
+67 1 1
+71 1 1
+134 1 1
+85 1 1
+607 36 0
+58 1 1
+1266 2 0
+480 14 21
+1459 2 1
+435 15 17
+1204 30 0
+1762 2 0
+123 1 0
+3025 0 1
+771 1 0
+3211 0 1
+3410 13 0
+1260 1 0
+591 0 1
+1107 15 15
+5811 0 22
+4103 0 2
+4882 1 0
+2138 3 2
+2203 2 1
+2338 1 0
+3316 1 1
+27 2 0
+6360 0 1
+251 19 7
+6605 1 1
+23 2 0
+360 0 2
+1292 0 2
+3992 46 46
+554 0 21
+4473 2 3
+921 1 1
+47 1 1
+2605 9 3
+50 1 1
+178 1 1
+26 1 1
+316 0 2
+1120 4 0
+177 1 2
+960 1 1
+65 1 1
+964 4 4
+783 8 8
+61 34 13
+121 1 1
+22 1 0
+118 1 1
+49 4 4
+281 1 1
+27 1 1
+958 0 1
+107 1 1
+31 1 1
+171 14 14
+302 0 13
+33 1 1
+108 0 4
+98 1 1
+53 1 1
+457 2 0
+529 1 1
+37 2 0
+1829 1 1
+38 1 1
+440 1 1
+82 3 4
+647 45 45
+660 1 1
+28 1 1
+1993 0 1
+373 19 19
+835 1 1
+42 1 1
+947 1 1
+36 1 0
+1055 1 1
+43 1 1
+475 1 0
+60 1 1
+127 1 1
+509 1 1
+71 1 1
+485 1 0
+26 1 1
+531 1 1
+18 1 1
+551 1 1
+18 1 1
+884 5 5
+147 53 60
+527 1 1
+26 2 2
+322 0 17
+32 2 2
+85 1 1
+45 1 1
+625 0 323
+540 0 1
+43 1 1
+266 0 2
+228 1 1
+42 1 1
+283 1 1
+92 1 1
+381 1 1
+40 1 1
+1906 0 4
+3495 0 4
+967 1 1
+76 1 1
+3236 4 4
+529 7 7
+246 4 0
+38 1 1
+156 0 6
+1466 0 2
+499 1 0
+937 1 1
+45 1 1
+421 6 0
+87 22 22
+1254 1 1
+36 0 1
+357 18 18
+391 0 1
+451 1 0
+105 1 1
+47 1 0
+255 6 6
+739 3 0
+386 1 1
+33 1 1
+281 4 0
+481 2 0
+495 1 1
+42 4 0
+219 0 1
+408 1 1
+23 1 1
+283 1 1
+25 0 1
+541 1 0
+88 2 0
+216 1 1
+29 1 1
+457 1 0
+331 9 1
+199 15 15
+228 1 0
+4 2 0
+333 0 1
+19 1 1
+910 1 1
+27 1 1
+142 3 3
+35 1 1
+1211 1 1
+34 1 1
+667 0 2
+64 1 1
+78 1 1
+1519 1 1
+27 1 1
+154 14 14
+1090 1 1
+40 0 3
+35 1 1
+1355 0 4
+79 1 1
+145 1 1
+63 1 1
+70 1 1
+21 1 1
+695 1 1
+41 2 2
+564 1 1
+46 1 1
+279 4 0
+38 5 5
+3523 32 32
+545 1 1
+27 1 0
+54 15 16
+1212 0 14
+34 0 11
+787 2 0
+3691 1 0
+1843 1 1
+45 1 0
+11 1 2
+3499 1 1
+27 1 1
+1047 0 2
+1804 2 0
+1079 1 1
+17 1 1
+639 3 5
+73 1 1
+13 13 0
+66 1 1
+391 0 7
+4547 0 1
+53 9 6
+691 0 1
+989 1 1
+143 1 1
+223 0 2
+95 1 1
+1000 1 1
+41 1 1
+93 1 1
+49 1 1
+606 1 1
+48 1 1
+128 0 4
+109 1 31
+44 10 781
+62 4 0
+129 1 1
+62 1 1
+106 1 1
+247 1 1
+20 18 4
+125 1 1
+43 1 1
+909 0 2
+381 4 4
+74 1 1
+408 1 0
+1595 5 0
+3690 1 1
+64 1 1
+754 0 4
+1877 1 1
+49 1 1
+1095 11 0
+734 0 23
+3072 2 0
+1879 0 1
+572 0 8
+215 1 1
+58 1 1
+301 1 1
+42 1 1
+265 24 0
+209 11 11
+953 1 1
+42 0 5
+58 1 0
+95 1 0
+210 1 1
+27 1 1
+882 1 1
+17 1 1
+751 0 1
+24 1 1
+351 1 1
+43 3 3
+565 1 1
+15 1 1
+150 27 27
+94 1 0
+323 1 1
+23 1 1
+221 7 7
+705 15 0
+631 2 0
+64 1 1
+1577 1 1
+21 0 1
+354 0 9
+189 0 1
+283 1 1
+48 1 1
+227 1 1
+40 0 3
+1357 0 2
+1571 7 7
+1153 1 1
+93 1 1
+797 14 14
+433 8 0
+108 11 11
+140 1 1
+40 1 1
+470 1 1
+42 1 1
+1106 0 2
+84 4 4
+129 1 1
+123 1 0
+95 1 1
+82 0 3
+661 1 1
+77 1 1
+57 1 1
+62 1 1
+473 2 0
+262 6 0
+45 1 1
+49 3 0
+321 0 1
+197 2 104
+87 222 0
+115 0 10
+92 0 4
+108 6 0
+563 14 14
+324 1 0
+205 1 1
+17 1 1
+495 0 1
+201 4 0
+14 1 1
+1080 1 1
+24 1 1
+91 24 24
+279 1 1
+95 1 1
+121 1 1
+62 1 1
+2371 1 0
+164 9 1
+655 1 1
+30 1 1
+271 1 1
+47 1 1
+609 1 0
+1780 2 0
+742 1 1
+40 1 1
+272 1 1
+52 1 1
+1187 1 1
+23 1 1
+254 1 1
+60 1 1
+176 3 6
+463 1 1
+36 1 1
+797 1 1
+22 1 1
+395 5 2
+61 1 1
+31 3 3
+226 1 1
+59 1 1
+581 1 1
+46 1 1
+412 1 1
+23 1 0
+74 1 1
+17 1 1
+81 1 1
+24 1 1
+83 15 15
+363 1 1
+91 1 1
+383 20 20
+199 13 13
+976 1 1
+39 0 3
+161 14 15
+127 16 16
+517 1 1
+132 1 1
+167 28 28
+124 1 1
+68 0 22
+1074 0 1
+175 1 0
+1018 1 1
+90 4 4
+1034 15 15
+69 1 1
+33 1 1
+174 1 1
+56 1 1
+169 1 0
+201 1 1
+30 1 1
+58 1 1
+38 1 1
+91 1 1
+98 4 4
+65 1 1
+19 2 0
+104 6 5
+25 1 1
+218 1 1
+37 1 1
+343 236832 150022
+67 8 8
+36 0 11
+62 1 1
+107 1 1
+68 3 130
+66 4 4
+50 21 21
+98 1 1
+127 1 0
+192 1 1
+71 1 1
+52 1 1
+200 1 1
+307 0 1
+331 1 1
+97 11 11
+171 1 1
+61 1 1
+37 1 1
+156 3 0
+63 0 3
+155 4 1
+31 2 0
+232 1 1
+33 1 1
+175 2 0
+131 6 6
+1409 0 3
+180 1 1
+65 0 1
+703 1 1
+19 1 1
+702 1 1
+65 1 1
+532 1 1
+48 1 1
+347 0 12
+578 16 17
+965 1 1
+45 1 1
+893 78201 80000
+406 1 1
+22 1 1
+462 1 1
+139 1 1
+154 1 0
+37 1 9
+11 2 0
+22 2 0
+14 46 22
+320 1 1
+117 1 1
+493 1 1
+129 1 1
+243 27 30
+170 1 1
+125 3 3
+2476 4 0
+27525 1 0
+2162 0 2
+2887 0 1
+17286 4 0
+22898 0 1
+51 9 9
+60 26 25
+312 15 11
+1008 17 17
+85 1 1
+49 1 1
+702 1 0
+87 1 1
+37 1 1
+859 8 8
+296 4 4
+105 0 4
+43 1 1
+67 10 7
+2839 3 0
+1283 1 1
+67 0 1
+32 2 0
+61 1 1
+140 15 15
+1047 1 1
+38 1 1
+87 1 1
+24 5 4
+1291 1 1
+49 1 1
+421 0 1
+75 1 1
+78 1 1
+243 1 0
+33 1 1
+116 19 19
+65 0 1
+238 0 1
+179 2 1
+67 1 1
+60 1 1
+32 1 1
+677 4 6
+83 314 0
+334 1 0
+1018 5 5
+127 1 1
+83 1 1
+347 0 2
+111 1 1
+30 1 1
+66 1 1
+38 1 1
+218 8 8
+754 1 1
+65 1 1
+182 1 1
+21 1 1
+285 1 1
+75 1 1
+147 6 0
+65 1 1
+42 1 1
+380 1 1
+84 2 0
+88 1 1
+25 1 1
+210 1 1
+17 1 1
+136 6 5
+108 1 1
+40 1 0
+50 1 1
+111 1 0
+21 0 1066
+119 0 1
+2641 1 1
+22 1 1
+689 1 1
+41 1 1
+1415 1 1
+29 1 1
+2252 1 1
+19 1 1
+1524 0 10
+2104 0 1
+511 2 0
+1696 26 8
+2593 0 177
+338 1 1
+37 2 2
+395 10 0
+67 1 1
+131 1 1
+31 1 1
+386 1 1
+42 1 1
+372 1 1
+48 1 1
+8705 0 4
+329 9 9
+600 2 0
+261 8 8
+9909 0 2
+2337 2 0
+2567 1 1
+26 1 1
+561 1 1
+48 1 1
+2440 1 1
+30 1 1
+1289 0 1
+162 1 0
+730 0 3
+658 1 0
+25 1 1
+1027 1 1
+43 1 1
+472 0 1
+219 1 1
+20 1 1
+495 1 0
+6 2 0
+1007 0 1
+169 0 10
+33 1 1
+266 11 11
+752 1 1
+30 1 1
+438 1 1
+39 1 1
+511 0 1
+1247 1 0
+1055 1 0
+491 1 0
+108 1 1
+48 1 1
+1324 0 1
+143 1 1
+40 1 1
+679 1 1
+45 1 1
+1036 0 2
+58 1 1
+46 1 1
+229 16 16
+149 10 10
+94 1 1
+63 1 1
+222 2 0
+55 1 1
+115 5 1
+219 15 15
+692 28 28
+159 1 1
+41 1 1
+211 1 0
+20 1 1
+1099 0 4
+155 6 0
+178 13 15
+32 1 1
+953 1 1
+47 1 1
+174 1 1
+22 1 1
+402 0 12
+588 5 21
+288 4 4
+86 1 1
+29 0 2
+67 3 0
+641 0 1
+571 0 1
+250 1 1
+34 1 1
+255 0 2
+572 12 12
+275 6 1
+974 0 1
+578 12 12
+612 1 1
+43 1 1
+56 0 7
+1170 0 1
+1242 0 8
+2108 5 0
+1090 0 2
+4424 1 1
+34 1 1
+4897 8 0
+1998 2 0
+114 0 1
+2874 1 1
+21 1 1
+442 22 22
+805 0 1
+3476 16 0
+7063 0 1
+65 3 0
+7475 0 4
+9515 5 1
+172 1 1
+49 1 1
+1349 22 22
+9662 2 0
+4856 3 0
+7447 6 6
+421 1 0
+884 6 0
+17 1 0
+3075 1 0
+11403 50004 0
+1397 12 12
+1859 3 1
+3762 2 0
+601 2 0
+7617 1 0
+1604 0 16
+3589 0 1
+1487 2 1
+1196 0 20
+2233 1 0
+192 4 4
+1470 9 27
+880 1 12
+2490 1 0
+151 1 1
+33 1 1
+2191 1 1
+47 1 1
+572 1 1
+17 1 1
+512 1 1
+83 1 1
+107 0 1
+4191 1 1
+36 1 1
+1530 1 1
+23 1 1
+311 0 4
+47 1 1
+141 2 0
+73 1 1
+330 1 1
+54 0 1
+32 0 1
+210 4 0
+219 1 0
+24 1 1
+425 1 1
+34 2 2
+1227 11 11
+2454 1 1
+36 1 1
+1368 1 1
+39 1 1
+134 1 1
+28 1 1
+123 1 1
+46 4 4
+839 9 0
+1244 1 1
+32 5 5
+2063 12 0
+357 3 0
+321 46 46
+873 1 1
+47 1 1
+1156 10 9
+1180 9 1
+271 9 9
+1870 0 1
+17 1 0
+366 7 7
+101 0 1
+134 8 8
+1654 0 4
+8741 1 1
+24 1 1
+1003 0 186
+12 0 20
+906 13 13
+1313 241 241
+2062 16 16
+1485 1 1
+18 1 1
+883 1 1
+20 1 1
+1354 1 1
+28 1 1
+283 5 5
+640 1 1
+40 1 1
+560 1 1
+42 1 1
+1144 19 19
+57 1 1
+21 1 1
+216 1 1
+109 1 1
+105 1 1
+208 5 5
+124 1 1
+112 3 3
+207 40 40
+244 1 1
+60 1 1
+98 1 1
+50 1 1
+256 5 5
+23 1 1
+157 1 1
+33 1 1
+143 1 1
+59 1 1
+51 1 1
+45 1 0
+73 1 1
+81 1 1
+5071 0 35
+42407 0 26
+13084 15 11
+333 5 0
+1235 6 6
+899 1 0
+1077 11 0
+1521 1 0
+38 1 1
+135 1 1
+42 1 1
+63 4 3
+385 1 1
+49 1 1
+77 20 22
+111 11 11
+190 2 2
+45 1 1
+373 1 1
+47 1 1
+77 10 10
+186 1 1
+24 1 1
+855 1 0
+23 1 1
+86 27 27
+148 1 0
+249 1 1
+22 1 1
+88 1 1
+31 1 1
+816 0 331
+433 1 1
+31 1 1
+53 1 1
+27 1 1
+101 1 1
+29 1 1
+406 1 1
+43 1 1
+306 1 1
+25 0 5
+68 1 1
+727 7 7
+237 1 1
+65 1 1
+178 1 1
+52 1 1
+667 1 1
+17 1 1
+359 1 1
+22 1 1
+1244 1 1
+36 1 1
+1349 29808 29806
+7637 1 1
+37 1 1
+1019 0 1
+10399 0 1
+10494 21750 21748
+607 26 26
+5347 2 0
+2375 3 0
+1594 1 0
+363 4 0
+2394 2 0
+3590 0 2
+2891 1 0
+621 1 0
+563 0 2
+85 0 13
+160 18 19
+1807 0 2
+291 0 1
+2273 8 0
+2568 1 0
+657 0 1
+772 4 0
+377 8 0
+62 52 0
+778 0 1
+391 62 72
+1596 2 0
+1317 2 0
+5358 0 3
+2273 0 1
+597 0 8
+993 0 26
+1897 1 0
+76 0 1
+966 1 0
+2611 2 0
+1374 18 0
+831 33 33
+1574 0 2
+306 0 1
+4789 0 3
+2404 1 1
+33 1 1
+507 4 0
+1627 50858 50856
+7863 53819 53813
+259 1 0
+752 3 1
+497 5 6
+3113 3 0
+748 1 0
+3002 0 1
+836 1 1
+22 1 0
+251 1 1
+27 1 1
+4128 0 1
+8869 29 0
+4065 0 2
+19869 0 1
+564 1 0
+4734 1 1
+36 1 1
+5630 1 0
+339 0 3
+1029 12 12
+15996 0 3
+1380 6 6
+57 0 1
+6265 14 14
+127 1 1
+21 1 1
+1709 1 1
+131 1 1
+64 9 9
+67 0 2
+290 23 22
+456 1 0
+587 0 1
+1610 0 2
+1243 1 0
+26 1 1
+2049 0 1
+1091 0 21
+357 11 14
+90
+
+chain 125812 chr6_ssto_hap7 4928567 + 3907506 3911494 chr4 191273063 + 128070000 128074446 1022492
+87 39 39
+217 93 93
+54 128 128
+101 185 185
+82 24 24
+306 274 274
+86 19 19
+109 42 42
+79 311 313
+96 87 87
+72 74 530
+57 170 170
+64 268 268
+56 709 709
+99
+
+chain 123442 chr6_ssto_hap7 4928567 + 3929629 3931354 chr2 242951149 - 63927014 63946734 1041108
+108 1 1
+44 0 2
+39 0 554
+170 0 2655
+81 3 3007
+63 15 1052
+119 0 1562
+96 0 5290
+67 9 9
+97 0 3890
+317 1 1
+39 1 1
+234 0 4
+116 1 1
+18 3 0
+83
+
+chain 92865 chr6_ssto_hap7 4928567 + 3892702 3894943 chr5 180857866 - 117045391 117059708 1366079
+75 6 6
+69 60 59
+68 1 0
+272 118 118
+148 29 29
+50 4 4
+75 91 91
+79 11 11
+52 94 94
+155 362 12440
+253 93 93
+76
+
+chain 86945 chr6_ssto_hap7 4928567 + 4078541 4079510 chr17 78774742 - 73855076 73856044 1454888
+79 12 12
+357 1 1
+20 1 1
+121 1 0
+377
+
+chain 80740 chr6_ssto_hap7 4928567 + 2343665 2344522 chr6 170899992 - 139781917 139782778 1563240
+341 0 4
+516
+
+chain 52870 chr6_ssto_hap7 4928567 + 2557772 2559707 chr1 247249719 + 7396445 7398379 2394598
+102 170 170
+115 745 743
+132 82 82
+58 214 214
+173 73 74
+71
+
+chain 47213 chr6_ssto_hap7 4928567 + 3973739 3974661 chr5 180857866 + 134244858 134245983 2704507
+144 28 28
+67 90 94
+193 60 61
+52 141 339
+53 41 41
+53
+
+chain 45302 chr6_ssto_hap7 4928567 + 4047815 4048319 chr5 180857866 - 98127286 98127790 2833261
+202 1 1
+153 1 1
+147
+
+chain 41978 chr6_ssto_hap7 4928567 + 1328154 1328662 chr6 170899992 + 30106460 30106967 3091365
+343 49 48
+116
+
+chain 40676 chr6_ssto_hap7 4928567 + 3875056 3875551 chr11 134452384 - 84966990 84967480 3207740
+246 1 1
+93 33 28
+122
+
+chain 35112 chr6_ssto_hap7 4928567 + 3906419 3911395 chr6 170899992 - 169520190 169525607 1043651
+51 464 464
+53 202 202
+87 154 151
+74 492 483
+28 798 798
+12 65 65
+50 80 80
+67 619 621
+27 1627 2078
+26
+
+chain 32670 chr6_ssto_hap7 4928567 + 3859757 3860527 chrX 154913754 + 119403135 119403904 4176412
+56 142 141
+152 178 178
+66 56 56
+120
+
+chain 29091 chr6_ssto_hap7 4928567 + 3895286 3896158 chr11 134452384 + 7157531 7158401 1526824
+161 614 612
+97
+
+chain 28481 chr6_ssto_hap7 4928567 + 4205119 4205417 chr17 78774742 + 29063769 29064067 5407271
+298
+
+chain 27018 chr6_ssto_hap7 4928567 + 3840659 3840971 chr18 76117153 - 36956533 36956845 6049052
+120 15 15
+177
+
+chain 25604 chr6_ssto_hap7 4928567 + 3994310 3994584 chr15 100338915 - 55375038 55375312 6715162
+274
+
+chain 23990 chr6_ssto_hap7 4928567 + 1194494 1195270 chr7 158821424 - 51137320 51138262 7695545
+178 101 101
+72 385 551
+40
+
+chain 23269 chr6_ssto_hap7 4928567 + 4043201 4044141 chr6 170899992 + 32821586 32822354 8132442
+218 672 500
+50
+
+chain 22259 chr6_ssto_hap7 4928567 + 1328662 1328894 chr10 135374737 + 129836641 129836873 8045146
+232
+
+chain 21089 chr6_ssto_hap7 4928567 + 3982819 3983044 chr14 106368585 + 105956394 105956619 9616367
+225
+
+chain 21066 chr6_ssto_hap7 4928567 + 4492538 4492777 chr8 146274826 + 14484871 14485110 2051461
+239
+
+chain 19470 chr6_ssto_hap7 4928567 + 3875397 3875736 chrX 154913754 - 111580561 111580900 4149836
+32 122 122
+185
+
+chain 19015 chr6_ssto_hap7 4928567 + 4093694 4093926 chr11 134452384 + 111558067 111558299 11259779
+149 20 20
+63
+
+chain 18910 chr6_ssto_hap7 4928567 + 3979875 3980839 chr6 170899992 + 32656485 32657452 11346766
+153 738 741
+73
+
+chain 18705 chr6_ssto_hap7 4928567 + 4047429 4047645 chr3 199501827 + 1828236 1828452 4490189
+145 5 5
+66
+
+chain 15452 chr6_ssto_hap7 4928567 + 3913430 3913596 chrX 154913754 + 67920599 67920765 14594390
+166
+
+chain 15351 chr6_ssto_hap7 4928567 + 2675966 2676167 chr11 134452384 + 74426248 74426449 14701293
+99 26 26
+76
+
+chain 15233 chr6_ssto_hap7 4928567 + 4047645 4047815 chr9 140273252 + 78741245 78741415 2998928
+170
+
+chain 15018 chr6_ssto_hap7 4928567 + 1260636 1260812 chr10 135374737 + 90412720 90412896 15044285
+117 3 3
+56
+
+chain 13654 chr6_ssto_hap7 4928567 + 180964 181124 chr18 76117153 - 3498140 3498418 7857183
+83 1 1
+24 4 122
+48
+
+chain 13627 chr6_ssto_hap7 4928567 + 3831356 3831761 chr6 170899992 + 32665471 32665876 16657612
+57 86 85
+47 147 148
+68
+
+chain 13048 chr6_ssto_hap7 4928567 + 3955374 3955802 chr2 242951149 + 206984071 206984490 17422582
+94 272 263
+62
+
+chain 12923 chr6_ssto_hap7 4928567 + 3954673 3954823 chr18 76117153 - 36956845 36956995 17596042
+150
+
+chain 12671 chr6_ssto_hap7 4928567 + 4090259 4090393 chrX 154913754 - 65797896 65798030 17982401
+134
+
+chain 12395 chr6_ssto_hap7 4928567 + 3983294 3983607 chrX 154913754 - 110185784 110186095 13720297
+4 222 220
+87
+
+chain 12272 chr6_ssto_hap7 4928567 + 2565285 2565441 chrX 154913754 + 154847615 154847763 18572104
+71 1 1
+25 8 0
+51
+
+chain 12207 chr6_ssto_hap7 4928567 + 3955802 3957116 chr4 191273063 - 84720316 84722799 17649000
+5 186 1341
+68 1003 1017
+52
+
+chain 12179 chr6_ssto_hap7 4928567 + 3836462 3836590 chr6 170899992 + 32566069 32566197 18716373
+128
+
+chain 12178 chr6_ssto_hap7 4928567 + 4018814 4018980 chr14 106368585 - 58343221 58343386 18718222
+55 26 25
+85
+
+chain 12137 chr6_ssto_hap7 4928567 + 3877094 3877505 chr7 158821424 + 90920405 90920810 18779047
+54 266 260
+91
+
+chain 11985 chr6_ssto_hap7 4928567 + 3892853 3894867 chr3 199501827 - 92708356 92711059 1441087
+59 394 394
+65 307 307
+90 391 391
+54 622 1311
+32
+
+chain 11952 chr6_ssto_hap7 4928567 + 4105293 4105419 chr4 191273063 - 72853862 72853988 19072608
+126
+
+chain 11593 chr6_ssto_hap7 4928567 + 3812675 3812798 chr1 247249719 - 238369051 238369174 19677686
+123
+
+chain 11535 chr6_ssto_hap7 4928567 + 1260812 1261322 chr1 247249719 - 129350638 129351114 18024798
+7 405 371
+98
+
+chain 11457 chr6_ssto_hap7 4928567 + 3994790 3994923 chr3 199501827 - 53316844 53316977 14718915
+32 6 6
+95
+
+chain 11393 chr6_ssto_hap7 4928567 + 4065042 4065262 chr10 135374737 - 122210308 122210526 20025571
+60 86 84
+74
+
+chain 11122 chr6_ssto_hap7 4928567 + 1240573 1241390 chr6 170899992 - 139553083 139553887 20511868
+77 676 663
+64
+
+chain 10873 chr6_ssto_hap7 4928567 + 1229721 1229842 chr19 63811651 + 15986631 15986752 20965590
+121
+
+chain 10852 chr6_ssto_hap7 4928567 + 2675511 2675627 chr15 100338915 - 60167597 60167713 16273330
+116
+
+chain 10686 chr6_ssto_hap7 4928567 + 2564433 2564954 chr18 76117153 + 11332173 11332695 21332096
+80 388 389
+53
+
+chain 10631 chr6_ssto_hap7 4928567 + 3935233 3935343 chr12 132349534 - 69483966 69484076 21446055
+110
+
+chain 10605 chr6_ssto_hap7 4928567 + 1188476 1188620 chr6 170899992 + 30566919 30567064 21497459
+81 23 24
+40
+
+chain 10522 chr6_ssto_hap7 4928567 + 3885687 3885969 chr6 170899992 + 32650612 32650898 21668161
+51 155 159
+76
+
+chain 10487 chr6_ssto_hap7 4928567 + 3763802 3763912 chr6 170899992 + 32525095 32525205 21738406
+110
+
+chain 10446 chr6_ssto_hap7 4928567 + 3838076 3838188 chr10 135374737 + 116791472 116791584 21828224
+112
+
+chain 10440 chr6_ssto_hap7 4928567 + 3816404 3816534 chr3 199501827 - 53390365 53390495 21843020
+67 9 9
+54
+
+chain 10424 chr6_ssto_hap7 4928567 + 1233358 1233620 chr1 247249719 - 93388912 93389184 21873908
+71 137 147
+54
+
+chain 10414 chr6_ssto_hap7 4928567 + 3814490 3814706 chr20 62435964 - 30230151 30230368 21892854
+65 92 93
+59
+
+chain 10301 chr6_ssto_hap7 4928567 + 3898517 3899557 chr6 170899992 + 32656523 32657565 22135092
+82 902 904
+56
+
+chain 10251 chr6_ssto_hap7 4928567 + 3994584 3994790 chr1 247249719 - 4492483 4492689 9976242
+1 153 153
+52
+
+chain 10098 chr6_ssto_hap7 4928567 + 3860255 3860748 chr12 132349534 - 132021867 132022360 5505364
+30 66 66
+56 251 251
+90
+
+chain 10097 chr6_ssto_hap7 4928567 + 3816034 3816270 chr6 170899992 - 10896454 10896689 22596963
+52 115 114
+69
+
+chain 10009 chr6_ssto_hap7 4928567 + 1180658 1180788 chr7 158821424 - 7754727 7754857 22790797
+54 14 14
+62
+
+chain 9863 chr6_ssto_hap7 4928567 + 4074075 4074200 chr1 247249719 + 10410145 10410270 23122655
+62 11 11
+52
+
+chain 9833 chr6_ssto_hap7 4928567 + 1235234 1235338 chr6 170899992 - 141000130 141000234 23192992
+104
+
+chain 9829 chr6_ssto_hap7 4928567 + 3815276 3815381 chr2 242951149 - 95164602 95164707 23200543
+105
+
+chain 9703 chr6_ssto_hap7 4928567 + 4070399 4070911 chr2 242951149 - 75663422 75663931 23509887
+63 390 387
+59
+
+chain 9614 chr6_ssto_hap7 4928567 + 2657013 2657750 chr6 170899992 - 140934793 140935541 23727231
+66 613 624
+58
+
+chain 9528 chr6_ssto_hap7 4928567 + 1196742 1197179 chr6 170899992 + 29878108 29878543 23937753
+59 318 316
+60
+
+chain 9448 chr6_ssto_hap7 4928567 + 4048489 4048611 chr8 146274826 - 73050790 73050912 12492975
+122
+
+chain 9438 chr6_ssto_hap7 4928567 + 3910395 3911369 chr15 100338915 - 30464954 30465929 1082363
+106 42 42
+63 674 675
+89
+
+chain 9407 chr6_ssto_hap7 4928567 + 3856752 3857141 chr6 170899992 + 32635022 32635416 24217249
+67 271 276
+51
+
+chain 9325 chr6_ssto_hap7 4928567 + 3877913 3878051 chr5 180857866 - 41992384 41992522 24382359
+55 28 28
+55
+
+chain 9223 chr6_ssto_hap7 4928567 + 4072536 4072675 chr3 199501827 + 115197797 115197935 24583947
+54 29 28
+56
+
+chain 8918 chr6_ssto_hap7 4928567 + 3893253 3894424 chr9 140273252 - 41262761 41263931 1574906
+43 979 978
+149
+
+chain 8559 chr6_ssto_hap7 4928567 + 1185037 1185127 chr6 170899992 + 29901402 29901492 25589405
+90
+
+chain 8551 chr6_ssto_hap7 4928567 + 3829560 3829651 chrX 154913754 + 101188135 101188226 25594732
+91
+
+chain 8473 chr6_ssto_hap7 4928567 + 3956061 3956256 chr9 140273252 + 73803578 73803773 19960547
+18 127 127
+50
+
+chain 8431 chr6_ssto_hap7 4928567 + 4017811 4017899 chr6 170899992 - 67344251 67344339 25766641
+88
+
+chain 8320 chr6_ssto_hap7 4928567 + 4046958 4047055 chr3 199501827 + 112943953 112944050 15335436
+35 7 7
+55
+
+chain 8195 chr6_ssto_hap7 4928567 + 1189357 1189443 chr6 170899992 + 29906107 29906193 26123218
+86
+
+chain 7977 chr6_ssto_hap7 4928567 + 3854972 3855056 chr3 199501827 - 65120650 65120734 26447349
+84
+
+chain 7864 chr6_ssto_hap7 4928567 + 3956899 3957064 chr2 242951149 + 230690248 230690413 23687196
+65 86 86
+14
+
+chain 7746 chr6_ssto_hap7 4928567 + 4069960 4070399 chr1 247249719 + 17543299 17543737 25591741
+58 375 374
+6
+
+chain 7672 chr6_ssto_hap7 4928567 + 3894447 3895071 chr11 134452384 + 90348791 90349415 1473761
+74 253 253
+37 159 159
+101
+
+chain 7498 chr6_ssto_hap7 4928567 + 3878051 3879311 chr1 247249719 + 173341048 173342322 26722357
+5 1190 1204
+65
+
+chain 7331 chr6_ssto_hap7 4928567 + 4098258 4098335 chr16 88827254 - 31115279 31115356 27543534
+77
+
+chain 7232 chr6_ssto_hap7 4928567 + 3920814 3920891 chr6 170899992 + 32620027 32620104 27728494
+77
+
+chain 7168 chr6_ssto_hap7 4928567 + 4075613 4075689 chr1 247249719 - 67121697 67121773 27863207
+76
+
+chain 7154 chr6_ssto_hap7 4928567 + 3982483 3982643 chrX 154913754 + 57427313 57427473 11452806
+160
+
+chain 6975 chr6_ssto_hap7 4928567 + 1189014 1189086 chr6 170899992 + 29905761 29905833 28257011
+72
+
+chain 6949 chr6_ssto_hap7 4928567 + 3816604 3816677 chr8 146274826 - 83195506 83195579 28299872
+73
+
+chain 6859 chr6_ssto_hap7 4928567 + 3943496 3943569 chr6 170899992 + 32632193 32632266 28469740
+73
+
+chain 6788 chr6_ssto_hap7 4928567 + 4050963 4058824 chr6 170899992 + 32827127 32834907 28622110
+50 4319 3617
+61 2525 2695
+93 658 1109
+155
+
+chain 6731 chr6_ssto_hap7 4928567 + 1724741 1724812 chrX 154913754 + 77548522 77548593 28736593
+71
+
+chain 6723 chr6_ssto_hap7 4928567 + 3873757 3873829 chr6 170899992 + 32566306 32566378 28747170
+72
+
+chain 6686 chr6_ssto_hap7 4928567 + 1260394 1260465 chr10 135374737 - 59340781 59340852 28859379
+71
+
+chain 6665 chr6_ssto_hap7 4928567 + 3154699 3154769 chr19 63811651 - 18495515 18495585 1124045
+70
+
+chain 6650 chr6_ssto_hap7 4928567 + 3860923 3861067 chr11 134452384 - 10112929 10113073 19771550
+33 61 61
+50
+
+chain 6622 chr6_ssto_hap7 4928567 + 3829455 3829525 chr2 242951149 - 225543946 225544016 28987379
+70
+
+chain 6618 chr6_ssto_hap7 4928567 + 3895820 3896010 chr13 114142980 + 101977588 101977777 1936459
+53 63 62
+74
+
+chain 6613 chr6_ssto_hap7 4928567 + 3829110 3829180 chrX 154913754 + 79202976 79203046 29019460
+70
+
+chain 6584 chr6_ssto_hap7 4928567 + 3973978 3974052 chr18 76117153 - 4274607 4274681 4481992
+74
+
+chain 6521 chr6_ssto_hap7 4928567 + 3924035 3924103 chr6 170899992 + 32624377 32624445 29251175
+68
+
+chain 6513 chr6_ssto_hap7 4928567 + 4073124 4073193 chr12 132349534 + 47073126 47073195 29262428
+69
+
+chain 6459 chr6_ssto_hap7 4928567 + 2661634 2661703 chr6 170899992 + 31350859 31350928 29378029
+69
+
+chain 6412 chr6_ssto_hap7 4928567 + 3941116 3941183 chr5 180857866 - 156512753 156512820 29524988
+67
+
+chain 6368 chr6_ssto_hap7 4928567 + 2565193 2565285 chr6 170899992 - 132294381 132294479 20980272
+55 29 35
+8
+
+chain 6368 chr6_ssto_hap7 4928567 + 4074498 4074566 chr21 46944323 + 22987814 22987882 29601883
+68
+
+chain 6359 chr6_ssto_hap7 4928567 + 3988556 3988624 chr6 170899992 + 32661355 32661423 29618339
+68
+
+chain 6278 chr6_ssto_hap7 4928567 + 3866522 3866590 chr6 170899992 + 32559120 32559188 29828351
+68
+
+chain 6275 chr6_ssto_hap7 4928567 + 1183919 1183984 chr6 170899992 + 29900614 29900679 29842805
+65
+
+chain 6265 chr6_ssto_hap7 4928567 + 3855056 3855122 chr11 134452384 + 35675446 35675512 27404543
+66
+
+chain 6240 chr6_ssto_hap7 4928567 + 3829386 3829452 chr7 158821424 + 89136765 89136831 29917662
+66
+
+chain 6231 chr6_ssto_hap7 4928567 + 4071456 4071522 chr15 100338915 + 41279078 41279144 29959209
+66
+
+chain 6221 chr6_ssto_hap7 4928567 + 4068934 4068999 chr5 180857866 + 81769172 81769237 29991772
+65
+
+chain 6158 chr6_ssto_hap7 4928567 + 3881593 3881658 chr8 146274826 + 95080661 95080726 30127973
+65
+
+chain 6116 chr6_ssto_hap7 4928567 + 3859885 3859954 chr6 170899992 - 133628666 133628735 10717008
+69
+
+chain 6039 chr6_ssto_hap7 4928567 + 3985075 3985138 chr6 170899992 + 32660531 32660594 30469869
+63
+
+chain 5986 chr6_ssto_hap7 4928567 + 4018730 4018794 chr1 247249719 - 129681820 129681884 30582101
+64
+
+chain 5986 chr6_ssto_hap7 4928567 + 3949638 3949702 chr6 170899992 + 32601206 32601270 30582240
+64
+
+chain 5977 chr6_ssto_hap7 4928567 + 3861125 3861202 chrX 154913754 - 4338266 4338343 13813425
+77
+
+chain 5976 chr6_ssto_hap7 4928567 + 2664206 2664269 chr6 170899992 + 31358648 31358711 30614237
+63
+
+chain 5958 chr6_ssto_hap7 4928567 + 3891447 3891510 chr2 242951149 + 38038620 38038683 30678163
+63
+
+chain 5912 chr6_ssto_hap7 4928567 + 3875752 3875836 chr7 158821424 - 35299548 35299632 7605861
+84
+
+chain 5886 chr6_ssto_hap7 4928567 + 1725643 1725706 chr4 191273063 - 86591247 86591310 30840494
+63
+
+chain 5792 chr6_ssto_hap7 4928567 + 4018980 4019041 chr10 135374737 - 103149812 103149873 26755020
+61
+
+chain 5742 chr6_ssto_hap7 4928567 + 3983333 3983412 chr5 180857866 + 128901198 128901277 14868038
+79
+
+chain 5702 chr6_ssto_hap7 4928567 + 3954013 3954072 chr6 170899992 + 32605878 32605937 31357680
+59
+
+chain 5594 chr6_ssto_hap7 4928567 + 4069284 4069343 chr3 199501827 - 15131518 15131577 31663339
+59
+
+chain 5502 chr6_ssto_hap7 4928567 + 3813204 3813261 chr1 247249719 - 79348621 79348678 31943035
+57
+
+chain 5348 chr6_ssto_hap7 4928567 + 4071259 4071315 chr3 199501827 + 160253017 160253073 32406182
+56
+
+chain 5330 chr6_ssto_hap7 4928567 + 3915278 3915334 chr6 170899992 + 32568311 32568367 32437918
+56
+
+chain 5330 chr6_ssto_hap7 4928567 + 2561771 2561827 chr9 140273252 - 28635638 28635694 32438181
+56
+
+chain 5304 chr6_ssto_hap7 4928567 + 4073642 4073717 chr11 134452384 - 71399807 71399882 4131480
+75
+
+chain 5230 chr6_ssto_hap7 4928567 + 3820271 3820326 chrX 154913754 - 97033891 97033946 32742019
+55
+
+chain 5203 chr6_ssto_hap7 4928567 + 4076111 4076166 chr5 180857866 + 152654188 152654243 32834294
+55
+
+chain 5185 chr6_ssto_hap7 4928567 + 4075517 4075572 chr1 247249719 + 155449681 155449736 32900354
+55
+
+chain 5152 chr6_ssto_hap7 4928567 + 3860576 3860657 chr6 170899992 + 32435407 32435488 15981349
+81
+
+chain 5151 chr6_ssto_hap7 4928567 + 3860169 3860251 chr10 135374737 - 104426563 104426645 8666574
+82
+
+chain 5139 chr6_ssto_hap7 4928567 + 4018355 4018409 chr4 191273063 + 178947604 178947658 33042950
+54
+
+chain 5132 chr6_ssto_hap7 4928567 + 3876113 3876181 chr3 199501827 + 30016279 30016347 19245837
+68
+
+chain 5130 chr6_ssto_hap7 4928567 + 3954272 3954326 chr6 170899992 + 32549431 32549485 33050033
+54
+
+chain 5103 chr6_ssto_hap7 4928567 + 1182080 1182134 chr6 170899992 + 76955761 76955815 33170047
+54
+
+chain 5094 chr6_ssto_hap7 4928567 + 1724204 1724258 chr7 158821424 + 103641158 103641212 33192903
+54
+
+chain 5085 chr6_ssto_hap7 4928567 + 1328098 1328151 chr10 135374737 + 129836820 129836873 10408987
+53
+
+chain 5085 chr6_ssto_hap7 4928567 + 4092830 4092884 chrX 154913754 - 38541067 38541121 33235347
+54
+
+chain 5066 chr6_ssto_hap7 4928567 + 1229626 1229679 chr21 46944323 - 1867343 1867396 33290794
+53
+
+chain 5031 chr6_ssto_hap7 4928567 + 3830258 3830312 chr11 134452384 + 134387408 134387462 33376437
+54
+
+chain 5021 chr6_ssto_hap7 4928567 + 3819996 3820049 chr12 132349534 - 47076480 47076533 33436792
+53
+
+chain 5018 chr6_ssto_hap7 4928567 + 4073251 4073642 chr3 199501827 - 85266868 85267256 1587398
+65 97 89
+113 2 7
+114
+
+chain 5003 chr6_ssto_hap7 4928567 + 3830053 3830106 chr1 247249719 - 154726869 154726922 33499615
+53
+
+chain 5003 chr6_ssto_hap7 4928567 + 4072679 4072732 chr16 88827254 + 14169487 14169540 33499780
+53
+
+chain 4994 chr6_ssto_hap7 4928567 + 3891033 3891086 chr21 46944323 - 10747178 10747231 33543756
+53
+
+chain 4967 chr6_ssto_hap7 4928567 + 3832675 3832728 chr6 170899992 + 32558903 32558956 33617414
+53
+
+chain 4965 chr6_ssto_hap7 4928567 + 2731195 2731249 chr6 170899992 + 31505531 31505585 32711054
+54
+
+chain 4948 chr6_ssto_hap7 4928567 + 4074823 4074875 chr4 191273063 - 118568999 118569051 33679640
+52
+
+chain 4921 chr6_ssto_hap7 4928567 + 3956534 3956586 chr1 247249719 + 94607233 94607285 33754873
+52
+
+chain 4903 chr6_ssto_hap7 4928567 + 3854886 3854938 chr7 158821424 + 104157517 104157569 33851522
+52
+
+chain 4893 chr6_ssto_hap7 4928567 + 3982754 3982817 chr22 49691432 + 37111300 37111363 16902914
+63
+
+chain 4873 chr6_ssto_hap7 4928567 + 3911814 3911922 chr18 76117153 - 50730715 50730823 6267534
+108
+
+chain 4830 chr6_ssto_hap7 4928567 + 3900138 3900189 chr6 170899992 + 32631274 32631325 34086153
+51
+
+chain 4830 chr6_ssto_hap7 4928567 + 3839078 3839129 chr7 158821424 + 82104686 82104737 34087626
+51
+
+chain 4829 chr6_ssto_hap7 4928567 + 1241391 1241441 chr6 170899992 + 29800923 29800973 34088055
+50
+
+chain 4821 chr6_ssto_hap7 4928567 + 2662906 2662957 chr3 199501827 - 33183122 33183173 34119642
+51
+
+chain 4775 chr6_ssto_hap7 4928567 + 2648374 2648424 chr6 170899992 + 31537299 31537349 34295026
+50
+
+chain 4758 chr6_ssto_hap7 4928567 + 4069230 4069281 chr12 132349534 + 47071874 47071925 34323771
+51
+
+chain 4757 chr6_ssto_hap7 4928567 + 3952724 3952774 chr6 170899992 + 32548169 32548219 34341756
+50
+
+chain 4730 chr6_ssto_hap7 4928567 + 3994932 3994982 chrX 154913754 + 47978704 47978754 34444069
+50
+
+chain 4716 chr6_ssto_hap7 4928567 + 4048342 4048408 chr3 199501827 - 34165769 34165835 12625077
+66
+
+chain 4703 chr6_ssto_hap7 4928567 + 2662371 2662421 chr19 63811651 + 65370 65420 34557514
+50
+
+chain 4694 chr6_ssto_hap7 4928567 + 4060651 4060701 chr6 170899992 + 32836714 32836764 34581664
+50
+
+chain 4679 chr6_ssto_hap7 4928567 + 3906823 3908410 chr10 135374737 + 93253585 93255039 1065758
+52 974 846
+68 463 458
+30
+
+chain 4568 chr6_ssto_hap7 4928567 + 1261137 1261199 chrX 154913754 - 132036612 132036674 19096001
+62
+
+chain 4552 chr6_ssto_hap7 4928567 + 3860527 3860576 chr15 100338915 - 42450883 42450932 16059710
+49
+
+chain 4547 chr6_ssto_hap7 4928567 + 2556944 2560436 chr12 132349534 + 103307685 103311177 2570686
+99 961 960
+40 481 480
+76 473 472
+44 1256 1259
+62
+
+chain 4462 chr6_ssto_hap7 4928567 + 2729793 2731102 chr13 114142980 - 41461751 41462033 3580573
+3 13 0
+61 0 13
+33 683 3
+44 2 0
+7 414 58
+20 0 11
+29
+
+chain 4428 chr6_ssto_hap7 4928567 + 4094024 4094075 chr14 106368585 + 31457415 31457466 15616811
+28 1 1
+22
+
+chain 4397 chr6_ssto_hap7 4928567 + 4073349 4073413 chr11 134452384 - 124082096 124082160 4425866
+64
+
+chain 4392 chr6_ssto_hap7 4928567 + 1194713 1194772 chr7 158821424 - 126060926 126060985 9905441
+59
+
+chain 4342 chr6_ssto_hap7 4928567 + 4094294 4094398 chr5 180857866 - 116975574 116975678 23231318
+23 58 58
+23
+
+chain 4295 chr6_ssto_hap7 4928567 + 2556338 2556392 chr13 114142980 + 40947099 40947153 23509763
+54
+
+chain 4294 chr6_ssto_hap7 4928567 + 1260590 1260636 chr12 132349534 - 115571292 115571338 21618938
+46
+
+chain 4197 chr6_ssto_hap7 4928567 + 4047303 4047429 chr5 180857866 + 138042715 138042841 4048116
+126
+
+chain 4074 chr6_ssto_hap7 4928567 + 3895452 3896721 chr2 242951149 - 163460907 163462170 1597366
+57 1112 1106
+100
+
+chain 4047 chr6_ssto_hap7 4928567 + 1227212 1227254 chr6 170899992 + 30567064 30567106 34943638
+42
+
+chain 4028 chr6_ssto_hap7 4928567 + 2557654 2557724 chr8 146274826 - 45767632 45767702 6509640
+70
+
+chain 3802 chr6_ssto_hap7 4928567 + 3983413 3983485 chr9 140273252 - 109331781 109331853 15187387
+72
+
+chain 3788 chr6_ssto_hap7 4928567 + 3983607 3983647 chr5 180857866 + 163886600 163886640 18371448
+40
+
+chain 3783 chr6_ssto_hap7 4928567 + 3861067 3861107 chr8 146274826 + 47663219 47663259 26644949
+40
+
+chain 3780 chr6_ssto_hap7 4928567 + 1260148 1260195 chr3 199501827 + 129107515 129107562 25050682
+47
+
+chain 3771 chr6_ssto_hap7 4928567 + 3910850 3910969 chr11 134452384 + 91939775 91939894 1347783
+119
+
+chain 3720 chr6_ssto_hap7 4928567 + 4076654 4076693 chr5 180857866 - 28755460 28755499 35075689
+39
+
+chain 3674 chr6_ssto_hap7 4928567 + 1327942 1328098 chr13 114142980 - 16623521 16623677 9556113
+156
+
+chain 3526 chr6_ssto_hap7 4928567 + 1233321 1233358 chr3 199501827 + 179624737 179624774 21949411
+37
+
+chain 3523 chr6_ssto_hap7 4928567 + 3861357 3861409 chrX 154913754 - 71079157 71079209 23377911
+52
+
+chain 3519 chr6_ssto_hap7 4928567 + 3860886 3860923 chr10 135374737 + 82581588 82581625 28921115
+37
+
+chain 3516 chr6_ssto_hap7 4928567 + 3983122 3983159 chr14 106368585 + 44215304 44215341 21050502
+37
+
+chain 3503 chr6_ssto_hap7 4928567 + 3955956 3955993 chrX 154913754 + 6516305 6516342 20940822
+37
+
+chain 3500 chr6_ssto_hap7 4928567 + 3911536 3911575 chr13 114142980 + 94757263 94757302 7214953
+39
+
+chain 3483 chr6_ssto_hap7 4928567 + 4093962 4094024 chr18 76117153 - 13046880 13046942 11655771
+62
+
+chain 3478 chr6_ssto_hap7 4928567 + 3815148 3815213 chr18 76117153 - 71040520 71040585 23549077
+65
+
+chain 3458 chr6_ssto_hap7 4928567 + 3983209 3983294 chr8 146274826 - 67597789 67597874 12879815
+85
+
+chain 3397 chr6_ssto_hap7 4928567 + 4048453 4048489 chr17 78774742 - 56852494 56852530 15165556
+36
+
+chain 3368 chr6_ssto_hap7 4928567 + 3812594 3812653 chr10 135374737 - 122033518 122033577 24304367
+59
+
+chain 3327 chr6_ssto_hap7 4928567 + 1327907 1327942 chr2 242951149 - 102468165 102468200 11981936
+35
+
+chain 3310 chr6_ssto_hap7 4928567 + 3973883 3974608 chr4 191273063 + 16003477 16004520 2930244
+28 656 974
+41
+
+chain 3301 chr6_ssto_hap7 4928567 + 2558188 2558238 chr3 199501827 + 116399611 116399661 15972636
+50
+
+chain 3279 chr6_ssto_hap7 4928567 + 2675861 2675917 chrX 154913754 + 134744376 134744432 23888160
+56
+
+chain 3275 chr6_ssto_hap7 4928567 + 1175210 1175245 chr6 170899992 + 29990315 29990350 35226054
+35
+
+chain 3266 chr6_ssto_hap7 4928567 + 3955123 3955180 chr3 199501827 - 22333077 22333134 22107567
+57
+
+chain 3198 chr6_ssto_hap7 4928567 + 3983298 3983333 chr9 140273252 - 16426927 16426962 15083539
+35
+
+chain 3194 chr6_ssto_hap7 4928567 + 3955248 3955303 chr12 132349534 + 117591668 117591723 17819023
+55
+
+chain 3180 chr6_ssto_hap7 4928567 + 3983045 3983105 chr5 180857866 - 166783333 166783393 16589034
+60
+
+chain 3166 chr6_ssto_hap7 4928567 + 3843125 3843159 chr4 191273063 + 105842978 105843012 35258022
+34
+
+chain 3121 chr6_ssto_hap7 4928567 + 3896015 3896048 chr12 132349534 + 40503685 40503718 34691345
+33
+
+chain 3047 chr6_ssto_hap7 4928567 + 3816677 3816709 chr10 135374737 - 66254665 66254697 30311304
+32
+
+chain 3032 chr6_ssto_hap7 4928567 + 4105261 4105293 chr8 146274826 - 64365138 64365170 21873611
+32
+
+chain 3023 chr6_ssto_hap7 4928567 + 4076166 4076198 chr7 158821424 - 25244743 25244775 33809340
+32
+
+chain 3020 chr6_ssto_hap7 4928567 + 3860793 3860825 chr14 106368585 - 87125958 87125990 25956389
+32
+
+chain 3015 chr6_ssto_hap7 4928567 + 3983163 3983195 chr3 199501827 + 120260171 120260203 17223389
+32
+
+chain 2990 chr6_ssto_hap7 4928567 + 3896241 3896359 chr13 114142980 + 83437980 83438098 1629523
+118
+
+chain 2988 chr6_ssto_hap7 4928567 + 3982643 3982709 chr1 247249719 + 240403964 240404030 13152492
+66
+
+chain 2975 chr6_ssto_hap7 4928567 + 2564513 2564549 chr3 199501827 - 94209737 94209773 24799761
+36
+
+chain 2970 chr6_ssto_hap7 4928567 + 4070462 4070493 chr3 199501827 - 179622086 179622117 31254285
+31
+
+chain 2964 chr6_ssto_hap7 4928567 + 3891798 3891851 chr5 180857866 + 101832950 101833003 21914612
+53
+
+chain 2888 chr6_ssto_hap7 4928567 + 4065158 4065188 chr19 63811651 - 5427097 5427127 31160360
+30
+
+chain 2845 chr6_ssto_hap7 4928567 + 2556914 2556944 chr3 199501827 - 158108130 158108160 26771676
+30
+
+chain 2753 chr6_ssto_hap7 4928567 + 1233507 1233566 chr12 132349534 + 50414483 50414542 22637631
+59
+
+chain 2740 chr6_ssto_hap7 4928567 + 3892104 3892166 chr5 180857866 + 121612373 121612435 20400021
+62
+
+chain 2698 chr6_ssto_hap7 4928567 + 3907323 3908062 chr7 158821424 + 92810174 92810913 1211789
+52 649 649
+38
+
+chain 2671 chr6_ssto_hap7 4928567 + 2565133 2565192 chr9 140273252 - 60326471 60326530 21074057
+59
+
+chain 2634 chr6_ssto_hap7 4928567 + 3829525 3829553 chr11 134452384 - 52779952 52779980 32661482
+28
+
+chain 2606 chr6_ssto_hap7 4928567 + 4048612 4048640 chr10 135374737 - 125708744 125708772 21482387
+28
+
+chain 2596 chr6_ssto_hap7 4928567 + 3956994 3957021 chr3 199501827 + 56590732 56590759 32896514
+27
+
+chain 2579 chr6_ssto_hap7 4928567 + 2557143 2557298 chr6 170899992 - 49784063 49784218 3056426
+155
+
+chain 2576 chr6_ssto_hap7 4928567 + 3895108 3895185 chr6 170899992 + 169119449 169119526 1708984
+77
+
+chain 2565 chr6_ssto_hap7 4928567 + 3829029 3829056 chr12 132349534 - 5427347 5427374 35416045
+27
+
+chain 2538 chr6_ssto_hap7 4928567 + 4095308 4095335 chrX 154913754 - 17724530 17724557 35428225
+27
+
+chain 2483 chr6_ssto_hap7 4928567 + 2785408 2785434 chr6 170899992 + 31465639 31465665 7427670
+26
+
+chain 2481 chr6_ssto_hap7 4928567 + 2556543 2556631 chr3 199501827 + 50931029 50931117 15954243
+88
+
+chain 2458 chr6_ssto_hap7 4928567 + 3955303 3955329 chr2 242951149 + 162131406 162131432 29918335
+26
+
+chain 2454 chr6_ssto_hap7 4928567 + 4073316 4073349 chr4 191273063 + 122379593 122379626 9286528
+33
+
+chain 2452 chr6_ssto_hap7 4928567 + 3955573 3955623 chr15 100338915 - 6219909 6219959 18667645
+50
+
+chain 2424 chr6_ssto_hap7 4928567 + 235781 235807 chr6 170899992 - 141897118 141897144 13814892
+26
+
+chain 2387 chr6_ssto_hap7 4928567 + 3979548 3981344 chr6 170899992 + 32629287 32631086 11569193
+64 1054 1061
+59 8 8
+33 512 508
+66
+
+chain 2367 chr6_ssto_hap7 4928567 + 3861203 3861228 chr5 180857866 - 25449026 25449051 27433905
+25
+
+chain 2364 chr6_ssto_hap7 4928567 + 3896486 3896567 chr12 132349534 - 118913454 118913535 1891796
+81
+
+chain 2348 chr6_ssto_hap7 4928567 + 2555491 2555546 chr7 158821424 + 35337254 35337309 23750585
+55
+
+chain 2343 chr6_ssto_hap7 4928567 + 3895509 3895593 chr5 180857866 + 145974017 145974101 2481028
+84
+
+chain 2329 chr6_ssto_hap7 4928567 + 3908230 3908283 chr14 106368585 - 66110025 66110078 1963434
+53
+
+chain 2303 chr6_ssto_hap7 4928567 + 3910235 3910298 chr9 140273252 + 106520457 106520520 13548409
+63
+
+chain 2290 chr6_ssto_hap7 4928567 + 1194888 1194945 chr1 247249719 + 222604152 222604209 12152481
+57
+
+chain 2264 chr6_ssto_hap7 4928567 + 4094107 4094165 chr6 170899992 - 103114933 103114991 11782722
+58
+
+chain 2239 chr6_ssto_hap7 4928567 + 3859859 3859885 chr10 135374737 - 31460228 31460254 11102876
+26
+
+chain 2227 chr6_ssto_hap7 4928567 + 3896386 3896483 chr3 199501827 + 28081389 28081486 2734455
+97
+
+chain 2194 chr6_ssto_hap7 4928567 + 1194673 1194713 chrX 154913754 - 101365357 101365397 11073774
+40
+
+chain 2194 chr6_ssto_hap7 4928567 + 3911725 3911783 chr20 62435964 + 16923180 16923238 16666656
+58
+
+chain 2183 chr6_ssto_hap7 4928567 + 3982709 3982750 chrX 154913754 + 100681659 100681700 16994110
+41
+
+chain 2146 chr6_ssto_hap7 4928567 + 1180871 1180932 chr12 132349534 + 104221177 104221238 23825292
+61
+
+chain 2099 chr6_ssto_hap7 4928567 + 1233299 1233321 chr8 146274826 + 94956096 94956118 22553602
+22
+
+chain 2073 chr6_ssto_hap7 4928567 + 3956611 3956663 chr12 132349534 - 95011302 95011354 24299162
+52
+
+chain 2037 chr6_ssto_hap7 4928567 + 3907120 3907174 chr16 88827254 + 61739431 61739485 9206264
+54
+
+chain 1971 chr6_ssto_hap7 4928567 + 1260864 1260916 chr6 170899992 - 43699516 43699568 21479541
+52
+
+chain 1962 chr6_ssto_hap7 4928567 + 3860956 3861008 chr2 242951149 - 71012239 71012291 15891024
+52
+
+chain 1959 chr6_ssto_hap7 4928567 + 4047151 4047237 chr9 140273252 + 88182498 88182584 7672012
+86
+
+chain 1911 chr6_ssto_hap7 4928567 + 4094317 4094375 chr3 199501827 + 41781958 41782016 21488153
+58
+
+chain 1911 chr6_ssto_hap7 4928567 + 1260320 1260381 chr10 135374737 - 106297874 106297935 24479059
+61
+
+chain 1874 chr6_ssto_hap7 4928567 + 2557724 2557753 chr7 158821424 + 91452357 91452386 16326510
+29
+
+chain 1780 chr6_ssto_hap7 4928567 + 3910029 3910068 chr14 106368585 - 82341010 82341049 3087250
+39
+
+chain 1777 chr6_ssto_hap7 4928567 + 2675677 2675732 chr16 88827254 + 88260921 88260976 23365193
+55
+
+chain 1697 chr6_ssto_hap7 4928567 + 2559283 2559636 chr4 191273063 - 69388564 69388918 2817550
+72 250 251
+31
+
+chain 1664 chr6_ssto_hap7 4928567 + 3911192 3911255 chr5 180857866 - 81785123 81785186 3114861
+63
+
+chain 1653 chr6_ssto_hap7 4928567 + 2560066 2560131 chr7 158821424 - 148280259 148280324 6636035
+65
+
+chain 1644 chr6_ssto_hap7 4928567 + 3910172 3910234 chrX 154913754 - 124216188 124216250 1928091
+62
+
+chain 1640 chr6_ssto_hap7 4928567 + 3906670 3906720 chr3 199501827 - 110018776 110018826 1171918
+50
+
+chain 1620 chr6_ssto_hap7 4928567 + 4048655 4048716 chr11 134452384 - 43500788 43500849 9791170
+61
+
+chain 1606 chr6_ssto_hap7 4928567 + 3837795 3837854 chr4 191273063 - 166421863 166421922 24717464
+59
+
+chain 1605 chr6_ssto_hap7 4928567 + 3875836 3875881 chr1 247249719 - 200018115 200018160 9990642
+45
+
+chain 1600 chr6_ssto_hap7 4928567 + 3957021 3957050 chr13 114142980 - 18785120 18785149 24380544
+29
+
+chain 1599 chr6_ssto_hap7 4928567 + 3955003 3955066 chr8 146274826 + 126278291 126278354 19925896
+63
+
+chain 1576 chr6_ssto_hap7 4928567 + 3910706 3910761 chr3 199501827 + 169002538 169002593 7318777
+55
+
+chain 1576 chr6_ssto_hap7 4928567 + 3876008 3876074 chr21 46944323 + 28977016 28977082 11761970
+66
+
+chain 1567 chr6_ssto_hap7 4928567 + 3909838 3909895 chr12 132349534 + 31210742 31210799 2955344
+57
+
+chain 1566 chr6_ssto_hap7 4928567 + 3893961 3894004 chr5 180857866 - 2394787 2394830 2003043
+43
+
+chain 1548 chr6_ssto_hap7 4928567 + 2556653 2556768 chr2 242951149 - 193553846 193553961 3498208
+115
+
+chain 1539 chr6_ssto_hap7 4928567 + 3891177 3891234 chr1 247249719 - 78251618 78251675 24446661
+57
+
+chain 1535 chr6_ssto_hap7 4928567 + 3911107 3911157 chr1 247249719 - 72372939 72372989 9173856
+50
+
+chain 1534 chr6_ssto_hap7 4928567 + 4094211 4094262 chrX 154913754 - 868272 868323 12957412
+51
+
+chain 1513 chr6_ssto_hap7 4928567 + 3906987 3907031 chr5 180857866 - 10434692 10434736 1299581
+44
+
+chain 1493 chr6_ssto_hap7 4928567 + 2556789 2556856 chr13 114142980 + 99769649 99769716 4762882
+67
+
+chain 1490 chr6_ssto_hap7 4928567 + 3814865 3814929 chr10 135374737 - 44217075 44217139 22840138
+64
+
+chain 1482 chr6_ssto_hap7 4928567 + 3909632 3909684 chr11 134452384 + 100031701 100031753 1214591
+52
+
+chain 1453 chr6_ssto_hap7 4928567 + 1327842 1327906 chr7 158821424 + 38479547 38479611 8534629
+64
+
+chain 1406 chr6_ssto_hap7 4928567 + 3909452 3909505 chr2 242951149 - 92980714 92980767 1301647
+53
+
+chain 1403 chr6_ssto_hap7 4928567 + 3860825 3860881 chr2 242951149 + 213976883 213976939 18753925
+56
+
+chain 1392 chr6_ssto_hap7 4928567 + 3955543 3955573 chr3 199501827 - 51819316 51819346 23522770
+30
+
+chain 1378 chr6_ssto_hap7 4928567 + 2556204 2556330 chr9 140273252 + 106017756 106017882 9913210
+126
+
+chain 1352 chr6_ssto_hap7 4928567 + 4047237 4047285 chr4 191273063 - 68812874 68812922 21085894
+48
+
+chain 1344 chr6_ssto_hap7 4928567 + 3893519 3893548 chr4 191273063 + 75333241 75333270 1578953
+29
+
+chain 1342 chr6_ssto_hap7 4928567 + 2557427 2557573 chr1 247249719 + 169787922 169788068 14592994
+146
+
+chain 1328 chr6_ssto_hap7 4928567 + 3895210 3895266 chr1 247249719 - 722390 722446 2029679
+56
+
+chain 1323 chr6_ssto_hap7 4928567 + 3815012 3815074 chrY 57772954 + 15217299 15217361 24773594
+62
+
+chain 1317 chr6_ssto_hap7 4928567 + 2559037 2559074 chr2 242951149 - 160628689 160628726 4907065
+37
+
+chain 1310 chr6_ssto_hap7 4928567 + 3859653 3859705 chrX 154913754 + 62583131 62583183 22867194
+52
+
+chain 1305 chr6_ssto_hap7 4928567 + 1233633 1233684 chr10 135374737 - 7751536 7751587 24635136
+51
+
+chain 1291 chr6_ssto_hap7 4928567 + 3908834 3908875 chr4 191273063 - 115939442 115939483 1333239
+41
+
+chain 1287 chr6_ssto_hap7 4928567 + 3909608 3909632 chr5 180857866 + 103723323 103723347 7290377
+24
+
+chain 1280 chr6_ssto_hap7 4928567 + 3895766 3895816 chr8 146274826 + 51746323 51746373 2903032
+50
+
+chain 1274 chr6_ssto_hap7 4928567 + 2557298 2557339 chrX 154913754 - 130647843 130647884 4467918
+41
+
+chain 1257 chr6_ssto_hap7 4928567 + 2558435 2558509 chr10 135374737 + 60854508 60854582 4145356
+74
+
+chain 1250 chr6_ssto_hap7 4928567 + 4094075 4094107 chr12 132349534 + 74093056 74093088 12787103
+32
+
+chain 1238 chr6_ssto_hap7 4928567 + 1229366 1229425 chr8 146274826 - 84904941 84905000 22834116
+59
+
+chain 1235 chr6_ssto_hap7 4928567 + 3861228 3861334 chr15 100338915 - 22701786 22701892 11814602
+106
+
+chain 1193 chr6_ssto_hap7 4928567 + 3906339 3906392 chr6 170899992 + 117066655 117066708 1525034
+53
+
+chain 1176 chr6_ssto_hap7 4928567 + 3909895 3909925 chr8 146274826 - 24546743 24546773 1399929
+30
+
+chain 1144 chr6_ssto_hap7 4928567 + 3892335 3892388 chrX 154913754 - 80891112 80891165 18462511
+53
+
+chain 1143 chr6_ssto_hap7 4928567 + 3876074 3876097 chr4 191273063 - 150305688 150305711 12943108
+23
+
+chain 1107 chr6_ssto_hap7 4928567 + 3890850 3890949 chr11 134452384 - 72766127 72766226 17974034
+99
+
+chain 1099 chr6_ssto_hap7 4928567 + 2557592 2557651 chr14 106368585 + 52836717 52836776 3332437
+59
+
+chain 1093 chr6_ssto_hap7 4928567 + 2560006 2560065 chr11 134452384 + 32923634 32923693 3048042
+59
+
+chain 1080 chr6_ssto_hap7 4928567 + 4073853 4073903 chr19 63811651 - 3657843 3657893 23666214
+50
+
+chain 1031 chr6_ssto_hap7 4928567 + 3910512 3910543 chr8 146274826 + 76357761 76357792 1122615
+31
+
+chain 1019 chr6_ssto_hap7 4928567 + 3956446 3956499 chr2 242951149 - 47303049 47303102 21955737
+53
+
+chain 1013 chr6_ssto_hap7 4928567 + 3876829 3876895 chr5 180857866 - 104615327 104615393 22955784
+66
+
+chain 1003 chr6_ssto_hap7 4928567 + 3699456 3699487 chr2 242951149 - 44758448 44758479 2126762
+31
+
+chain 980 chr6_ssto_hap7 4928567 + 1260084 1260145 chrX 154913754 - 382349 382410 22927465
+61
+
+chain 926 chr6_ssto_hap7 4928567 + 3896721 3896750 chr5 180857866 - 112926632 112926661 13782082
+29
+
+chain 919 chr6_ssto_hap7 4928567 + 2560983 2561043 chr4 191273063 + 44807134 44807194 22381059
+60
+
+chain 917 chr6_ssto_hap7 4928567 + 3906720 3906770 chr1 247249719 - 157593440 157593490 1436049
+50
+
+chain 909 chr6_ssto_hap7 4928567 + 3909310 3909343 chr3 199501827 + 106500697 106500730 2326646
+33
+
+chain 904 chr6_ssto_hap7 4928567 + 2560317 2560347 chr7 158821424 + 107644178 107644208 22181612
+30
+
+chain 884 chr6_ssto_hap7 4928567 + 2559977 2560006 chr1 247249719 - 197271642 197271671 12501549
+29
+
+chain 879 chr6_ssto_hap7 4928567 + 3814083 3814143 chr2 242951149 + 8957980 8958040 24745704
+60
+
+chain 871 chr6_ssto_hap7 4928567 + 3908354 3908380 chr5 180857866 - 86285693 86285719 1813846
+26
+
+chain 854 chr6_ssto_hap7 4928567 + 2559716 2559766 chr4 191273063 + 5547185 5547235 3968222
+50
+
+chain 842 chr6_ssto_hap7 4928567 + 3909997 3910029 chr12 132349534 + 65262069 65262101 1358106
+32
+
+chain 834 chr6_ssto_hap7 4928567 + 2558357 2558414 chr5 180857866 - 149870489 149870546 4554917
+57
+
+chain 818 chr6_ssto_hap7 4928567 + 3895593 3895627 chr1 247249719 - 137161630 137161664 3053056
+34
+
+chain 805 chr6_ssto_hap7 4928567 + 4046900 4046958 chr3 199501827 - 135889823 135889881 13048217
+58
+
+chain 792 chr6_ssto_hap7 4928567 + 2556476 2556543 chrX 154913754 - 448312 448379 10955677
+67
+
+chain 788 chr6_ssto_hap7 4928567 + 2557050 2557102 chr9 140273252 - 129331917 129331969 3471854
+52
+
+chain 766 chr6_ssto_hap7 4928567 + 3895074 3895108 chrX 154913754 - 143143280 143143314 1988289
+34
+
+chain 764 chr6_ssto_hap7 4928567 + 3911494 3911520 chr5 180857866 - 28611213 28611239 1520834
+26
+
+chain 760 chr6_ssto_hap7 4928567 + 3891913 3891984 chr7 158821424 + 132658309 132658380 7665022
+71
+
+chain 760 chr6_ssto_hap7 4928567 + 2558688 2558747 chr12 132349534 + 56700130 56700189 25330837
+59
+
+chain 751 chr6_ssto_hap7 4928567 + 3908062 3908116 chrX 154913754 - 27278752 27278806 23595528
+54
+
+chain 750 chr6_ssto_hap7 4928567 + 2558241 2558292 chr3 199501827 - 21470788 21470839 4018903
+51
+
+chain 747 chr6_ssto_hap7 4928567 + 1195376 1195440 chr12 132349534 + 55464534 55464598 20643872
+64
+
+chain 741 chr6_ssto_hap7 4928567 + 2558773 2558825 chr10 135374737 + 51611354 51611406 20535555
+52
+
+chain 725 chr6_ssto_hap7 4928567 + 2556857 2556911 chr2 242951149 + 129418481 129418535 15959344
+54
+
+chain 718 chr6_ssto_hap7 4928567 + 3906470 3906504 chr13 114142980 + 74008819 74008853 1439498
+34
+
+chain 683 chr6_ssto_hap7 4928567 + 4094187 4094211 chr12 132349534 - 78902290 78902314 13929920
+24
+
+chain 678 chr6_ssto_hap7 4928567 + 2557391 2557427 chr4 191273063 + 139055274 139055310 16166693
+36
+
+chain 667 chr6_ssto_hap7 4928567 + 2560843 2560917 chr5 180857866 - 57070089 57070163 4646233
+74
+
+chain 646 chr6_ssto_hap7 4928567 + 2558159 2558188 chr1 247249719 - 41799280 41799309 22422429
+29
+
+chain 632 chr6_ssto_hap7 4928567 + 3892229 3892286 chr5 180857866 + 40599364 40599421 14690520
+57
+
+chain 624 chr6_ssto_hap7 4928567 + 2558292 2558324 chr9 140273252 + 222455 222487 4174075
+32
+
+chain 617 chr6_ssto_hap7 4928567 + 3894943 3894969 chr9 140273252 - 67269827 67269853 2340131
+26
+
+chain 612 chr6_ssto_hap7 4928567 + 1195270 1195296 chr2 242951149 + 158875930 158875956 11360379
+26
+
+chain 602 chr6_ssto_hap7 4928567 + 3896359 3896385 chr2 242951149 + 96414192 96414218 2435436
+26
+
+chain 600 chr6_ssto_hap7 4928567 + 2560187 2560242 chr4 191273063 - 105845249 105845304 24497060
+55
+
+chain 588 chr6_ssto_hap7 4928567 + 3911575 3911637 chr9 140273252 + 26038500 26038562 6400007
+62
+
+chain 588 chr6_ssto_hap7 4928567 + 3911157 3911192 chr2 242951149 - 186209425 186209460 7977621
+35
+
+chain 537 chr6_ssto_hap7 4928567 + 3890472 3890554 chr20 62435964 + 39823688 39823770 23049583
+82
+
+chain 533 chr6_ssto_hap7 4928567 + 2560261 2560317 chr7 158821424 + 35749861 35749917 7559420
+56
+
+chain 506 chr6_ssto_hap7 4928567 + 1194845 1194871 chr17 78774742 + 16156064 16156090 14435127
+26
+
+chain 492 chr6_ssto_hap7 4928567 + 2561299 2561367 chr13 114142980 - 65973713 65973781 6503172
+68
+
+chain 482 chr6_ssto_hap7 4928567 + 3909557 3909588 chr4 191273063 + 109100594 109100625 25171244
+31
+
+chain 475 chr6_ssto_hap7 4928567 + 3910969 3910996 chr2 242951149 + 170022712 170022739 3066592
+27
+
+chain 474 chr6_ssto_hap7 4928567 + 2555667 2555728 chr3 199501827 + 34096453 34096514 5935624
+61
+
+chain 454 chr6_ssto_hap7 4928567 + 3783318 3783345 chr7 158821424 + 43780404 43780431 3672784
+27
+
+chain 453 chr6_ssto_hap7 4928567 + 2558825 2558856 chr12 132349534 + 9890466 9890497 23880886
+31
+
+chain 435 chr6_ssto_hap7 4928567 + 3813557 3813608 chrX 154913754 + 70635923 70635974 25591729
+51
+
+chain 433 chr6_ssto_hap7 4928567 + 3954592 3954642 chr12 132349534 + 80047789 80047839 27634718
+50
+
+chain 421 chr6_ssto_hap7 4928567 + 3906299 3906339 chr6 170899992 - 100687874 100687914 2311527
+40
+
+chain 415 chr6_ssto_hap7 4928567 + 4047055 4047086 chr2 242951149 - 64586829 64586860 16220906
+31
+
+chain 395 chr6_ssto_hap7 4928567 + 3877505 3877535 chr2 242951149 - 195767137 195767167 24444969
+30
+
+chain 389 chr6_ssto_hap7 4928567 + 2560634 2560691 chr4 191273063 - 135903806 135903863 10538130
+57
+
+chain 364 chr6_ssto_hap7 4928567 + 3892286 3892319 chr2 242951149 + 18209140 18209173 14942259
+33
+
+chain 312 chr6_ssto_hap7 4928567 + 2559887 2559937 chr6 170899992 + 118230705 118230755 8173852
+50
+
+chain 289 chr6_ssto_hap7 4928567 + 2561063 2561118 chr9 140273252 - 49339912 49339967 9048484
+55
+
+chain 276 chr6_ssto_hap7 4928567 + 3878310 3878371 chr4 191273063 - 5378508 5378569 28215176
+61
+
+chain 273 chr6_ssto_hap7 4928567 + 2560131 2560171 chr10 135374737 + 69013223 69013263 15789387
+40
+
+chain 167 chr6_ssto_hap7 4928567 + 3908301 3908353 chr3 199501827 + 163583012 163583064 2366456
+52
+
+chain 14618488008 chr7 159138663 + 10238 159128663 chr7 158821424 + 102995 158821424 7
+973 0 5
+3912 2 0
+1234 0 4
+51 6 0
+70 1 1
+24 0 1
+147 0 8
+12 1 170
+47 1 1
+246 6 0
+99 4 4
+807 0 3
+2546 0 63
+44 0 2527
+1373 1 0
+2109 456 0
+1153 1 0
+791 1 1
+49 1 0
+4175 18 26
+4318 11 11
+514 0 12
+2511 1 0
+1697 6 6
+192827 278557 150000
+5682433 40 39
+42007910 35970 40000
+2048 3 3
+2320 16 7
+17699 4 0
+5248 0 4
+2088411 1 1
+47 1 1
+4565 1 0
+7116 1 0
+2706 43050 40000
+6577293 13552 50000
+1052855 3000000 3000000
+256182 416507 50000
+190137 50000 50000
+5722629 1 0
+23 1 1
+239 1 1
+59 2 2
+138 1 1
+34 1 1
+206 3 1
+18 0 1
+410 1 1
+72 1 1
+199 1 1
+62 5 5
+120 0 1
+468 1 1
+32 1 1
+264 1 1
+23 1 1
+1459 4 4
+107 1 1
+42 0 1
+14 1 1
+201 1 1
+46 1 1
+268 20 20
+303 1 2
+866 4 0
+76 3 3
+63 1 1
+74 0 1
+25 1 1
+66 1 1
+34 2 0
+180 36 35
+93 1 1
+41 1 1
+70 1 1
+49 1 1
+63 1 1
+57 1 1
+383 1 1
+133 1 1
+87 1 1
+38 4 4
+50 1 0
+46 6 5
+136 11 11
+200 1 1
+64 5 18
+263 1 1
+32 3 3
+152 16 16
+567 0 1
+322 0 3
+1258 1 0
+504 0 4
+1142 10 11
+537 12 12
+1418 1 1
+47 1 0
+164 7 7
+113 0 5
+59 2 2
+72 1 1
+20 1 1
+380 3 3
+41 0 3
+5 2 2
+921 1 1
+34 1 1
+1607 2 2
+73 0 66
+45 0 14
+169 1 1
+53 1 1
+3195 1 1
+23 1 1
+2115 14 0
+9872 0 1
+1204 13 13
+416 0 1
+2298 0 319
+6918 10 0
+184 0 24
+2932 0 4
+1394 12 0
+1853 0 5
+3442 1 0
+469 0 3
+771 12 15
+497 1 1
+65 1 1
+1210 2 0
+4131 10 10
+1198 0 1
+718 1 1
+21 1 1
+3668 0 1
+874 1 1
+25 1 1
+2444 1 0
+1867 1 1
+29 1 1
+1660 1 0
+1233 6 0
+783 0 1
+705 3 0
+3577 0 1
+365 0 1
+3389 4 8
+2652 3 0
+664 1 0
+169 9 10
+138 1 0
+8038 56 0
+109 0 196
+522 35 0
+3003 1 1
+40 1 1
+1065 0 4
+634 1 0
+51 30 0
+66 1 9
+3081 0 2
+806 1 0
+21 1 1
+3901 27 26
+843 1 0
+6916420 50000 250000
+25789109 51216 0
+1399988 0 1
+3623 212 0
+38 1 1
+210 29 33
+1318 0 16
+2190 0 1
+145 1 0
+1388 7 7
+2240 14 14
+771 1 1
+34 1 1
+92 1 1
+39 1 1
+505 0 1
+66 1 1
+49 1 1
+159 0 1
+78 0 2
+2 0 1
+13 0 2
+7 0 1
+28 0 1
+27 5 468
+2022 0 1
+1796 7 7
+61 1 1
+20 1 1
+4560 0 3
+157730 0 1
+194 14 14
+650 12 0
+669 74 74
+820 5 0
+277 32 60
+69 5 0
+1345 0 8
+652 0 84
+118 4 0
+498 1 0
+3187 1 1
+43 1 1
+1476 3 0
+2101 0 5
+788 6 6
+872 6 0
+691 202 205
+155 33 33
+4610 7 5
+521 0 10
+2773 1 1
+38 1 1
+627 1 1
+41 1 1
+1424 1 0
+2554 8 8
+45 7 0
+614 1 1
+32 0 3
+2693 1 0
+1029 2 0
+151 1 0
+1753 21 0
+370 3 2
+969 1 0
+452 0 1
+3035 42 42
+704 2 0
+2472 6 0
+238 0 1
+1442 43 43
+126 1 0
+795 1 0
+1191 0 1
+171 16 17
+724 27 28
+2966 1 1
+38 3 1
+359 0 2
+199 1 1
+17 1 1
+1969 0 1
+251 1 0
+729 1 0
+992 1 1
+25 1 1
+203 0 4
+3211 2 0
+1006 10 8
+1571 10 10
+756 38 37
+433 1 0
+672 3 0
+4460 25 182
+5551 19 23
+942 9 10
+3433 1 2
+24 1 1
+4262 0 13
+661 0 2
+167 0 8
+3474 66 61
+162 2 0
+778 34 34
+158 1 0
+1167 1 0
+684 1 0
+878 39 39
+2012 1 0
+345 1 1
+50 1 1
+626 2 0
+27874083 136705 0
+2495 2 0
+1000 0 8
+14695 0 1
+4456 0 1
+2977 0 1
+9065130 29055 25000
+2369 0 1
+12174 20 18
+878 4 0
+5247 12 0
+3482 0 2
+6766 1 0
+2469878 1 0
+835 1 0
+2471 13 13
+751 0 8
+2241 1 0
+12 1 1
+8394 0 1
+47 1 1
+903 1 0
+5537 1 0
+269 0 1
+7114 1 1
+30 1 1
+2412 1 0
+2442 21 21
+91 1 1
+37 1 1
+96 1 1
+22 1 1
+246 1 1
+23 1 1
+241 25 25
+569 1 1
+27 1 1
+1624 0 1
+112 3 3
+45 1 1
+384 13 13
+70 0 1
+658 1 1
+20 1 1
+176 0 1
+307 19 19
+428 1 1
+19 1 1
+87 1 1
+30 1 1
+140 0 1
+292 0 2
+1492 0 1
+302 2 0
+364 1 1
+35 1 1
+1956 1 0
+728 57 57
+8010 0 1
+488 0 1
+2056 8 18
+1286 1 1
+27 1 1
+731 0 1
+1423 7 0
+2010 1 1
+19 1 1
+3925 37 37
+2438 4 0
+80 1 1
+4505 0 13
+933 12 0
+1250 1 0
+1313 0 1
+2610 1 0
+2398 1 0
+453 0 1
+346 14 14
+83 0 1
+24 1 0
+83 12 12
+277 1 0
+45 0 1
+811 0 2
+164 1 0
+104 1 0
+32 1 1
+1386 14 0
+306 1 1
+43 1 1
+2765 1 0
+1819 1 0
+1480 1 1
+24 1 1
+276 1 0
+21 1 0
+119 11 39
+542 1 1
+63 1 1
+180 1 0
+2456 0 1
+392 62 62
+601 0 1
+1166 0 2
+784 4 0
+170 0 1
+939 0 6
+5597 15 15
+1253 1 0
+3336 18 0
+1851 0 9
+45 1 1
+4794 1 0
+1387 0 2
+1460 0 1
+204 5 0
+1506 1 0
+2621 0 1
+6620 1 0
+34 1 1
+249 0 1
+1443 10 0
+242 1 0
+368 9 1
+257 0 4
+1588 0 6
+1544 1 0
+4189 0 120
+354 278046 312446
+3728 1 0
+3127 9 10
+4861 4 0
+5649 0 1
+2011 1 0
+14914 1467 42
+20955 1 0
+2075 1 2
+5546 0 1
+2168 0 4
+1266 0 1
+4124 1 1
+46 1 1
+54 1 1
+43 0 15
+780 1 1
+25 1 1
+497 1 0
+46 1 1
+770 41 40
+5701 1 0
+4251 8 8
+2739 1 0
+2002 3 0
+7160 1 1
+24 1 1
+479 0 2
+1872 1 0
+1192 0 1
+371 0 2
+31 1 1
+572 16 16
+1725 16 16
+588 1 1
+90 1 1
+2483 19 3
+187 1 0
+20 1 1
+3673 1 1
+27 0 4
+3021 0 1
+1323 6 19
+498 13 13
+1618 0 2
+5282 1 0
+720 8 0
+2993 0 1
+2822 2 0
+1396 1 1
+48 1 1
+8723 0 5
+291 1 1
+25 1 1
+116 1 0
+2809 1 1
+27 1 1
+224 1 1
+48 1 1
+292 2 0
+400 1 0
+754 1 1
+19 1 1
+4225 1 1
+28 1 1
+801 0 1
+671 1 1
+17 1 1
+390 1 1
+28 1 1
+84 7 7
+568 1 1
+56 1 1
+499 8 7
+266 1 1
+31 1 1
+518 18 18
+164 1 1
+50 1 1
+162 1 1
+60 1 1
+702 1 1
+28 1 1
+146 17 18
+517 1 1
+24 1 1
+799 1 1
+22 5 5
+107 5 5
+277 9 9
+272 1 1
+48 1 1
+77 1 1
+67 1 1
+1548 1 1
+40 1 1
+763 1 1
+42 1 1
+541 8 8
+88 1 1
+77 1 1
+233 11 11
+311 1 1
+22 1 1
+147 8 1
+504 1 1
+26 1 1
+996 3615 24049
+1687 0 1
+1174 1 0
+70 1 1
+1100 18 10143
+2722 1 0
+2957 1 1
+32 1 1
+9585 1 0
+1350 1 0
+473 1 0
+675 1 0
+1435 1 0
+805463 79189 0
+10872697 100000 100000
+721570 1 1
+19 1 1
+816 1 1
+44 1 1
+572 6 8
+2021 4 0
+1001 0 2
+3757 0 1
+5942 2 2
+70 1 1
+100 7 7
+395 17188 80000
+1010 1 1
+45 1 1
+1486 18 18
+173 145 1
+139 65 1
+41 16 0
+32 368 0
+44 2 50
+40 1 1
+95 52 4
+60 8 39
+12 0 16
+93 0 16
+1591 1 0
+897 13 13
+28 3 3
+2454 1 1
+44 1 1
+305 468 0
+2026 1 1
+45 1 1
+1273 3 11
+1717 0 1
+1575 4 0
+14 1 1
+2428 0 36
+50 10 154
+247 185 6
+2096 11 13
+192 1 1
+48 1 1
+130 1 1
+22 1 1
+970 1 1
+22 0 4
+76 14 0
+118 58 64
+107 1 0
+12 1 1
+53 5 15
+48 1 1
+47 2 0
+114 16 18
+363 1 1
+43 1 1
+559 1 1
+32 1 1
+3980007
+
+chain 16700437 chr7 159138663 + 142098195 142276197 chr7 158821424 - 16919205 17097543 171
+6297 1 0
+171 1 0
+4869 1 1
+24 0 1
+6208 0 1
+135 1 0
+1978 1 0
+764 1 1
+45 0 2
+1984 0 1
+1628 1 0
+733 1 1
+38 1 0
+137 7 7
+17 1 1
+259 1 0
+1200 1 0
+2193 4 4
+1781 0 1
+3387 1 1
+25 1 1
+125 1 1
+17 1 1
+3811 5 5
+556 0 1
+1846 5 0
+1322 1 1
+40 1 1
+228 0 1
+3477 1 1
+31 1 1
+3722 1 1
+73 1 1
+3052 66 66
+2542 15 15
+3103 0 2
+112 0 2
+1066 1 1
+59 1 0
+719 1 0
+203 1 0
+127 1 0
+30 1 0
+32 1 1
+366 0 4
+27 1 1
+2155 1 1
+41 1 1
+790 0 1
+403 1 1
+27 1 1
+648 7 7
+48 2 0
+78 2 2
+1052 4 4
+855 1 1
+68 1 1
+2428 9 0
+919 1 1
+22 1 1
+366 1 1
+36 1 1
+269 7 7
+4018 6 6
+1168 0 1
+3409 0 1
+1503 3 0
+2680 1 1
+37 1 1
+727 1 1
+28 0 5
+9 0 3
+5 0 2
+4 9 0
+13 1 1
+1801 0 3
+98 14 14
+2789 4 0
+5562 1 0
+2380 1 1
+23 1 1
+160 1 1
+57 1 1
+2413 19 19
+1704 0 1
+67 0 1
+68 1 1
+45 1 1
+176 9 9
+973 1 1
+31 3 3
+167 4 4
+334 13 13
+584 11 11
+206 16 16
+1218 1 1
+29 1 1
+234 1 1
+45 0 2
+1027 0 1
+559 10 11
+367 0 2
+8269 0 2
+4195 1 1
+62 1 1
+2896 13 13
+524 5 5
+411 1 1
+53 1 1
+126 1 1
+36 1 1
+806 1 1
+43 2 0
+1905 2 0
+414 1 1
+25 1 1
+2396 1 0
+12 1 0
+23 0 1
+10 0 1
+4 0 1
+60 0 1
+25 1 1
+1387 0 4
+3461 0 2
+1026 0 2
+821 1 1
+21 1 0
+612 1 1
+31 1 1
+1053 1 0
+2080 17 17
+9739 5 12
+17 7 0
+878 1 1
+19 1 0
+53 1 1
+839 26 26
+522 1 1
+49 1 1
+539 1 1
+25 1 1
+669 1 1
+42 1 1
+134 7 7
+1145 1 0
+2731 1 0
+590 4 0
+41 0 1
+7853 0 4
+830 0 2
+1742 2 0
+640 1 1
+34 0 2
+298 1 0
+3598 1 0
+1522 1 339
+115 18 18
+887 1 1
+69 1 1
+1662
+
+chain 1755125 chr7 159138663 + 143318748 143347897 chr7 158821424 - 15657394 15686558 532
+923 0 15
+1431 698 698
+3421 10 12
+405 1 1
+16 1 1
+5116 1 1
+27 1 1
+334 1 1
+15 1 0
+724 13 13
+109 0 2
+1784 1 0
+1588 1 1
+43 1 1
+908 9684 9682
+464 445 445
+982
+
+chain 939937 chr7 159138663 + 61402791 61412791 chr7 158821424 + 61280000 61290000 3137
+10000
+
+chain 921443 chr7 159138663 + 61382791 61392786 chr7 158821424 + 61260000 61269994 3741
+1722 1 0
+433 30 30
+1603 4 4
+4846 27 27
+478 19 19
+584 36 36
+212
+
+chain 898631 chr7 159138663 + 61392792 61402791 chr7 158821424 + 61270000 61280000 4251
+316 76 76
+3924 49 49
+2708 28 28
+1134 174 174
+156 40 41
+1394
+
+chain 896117 chr7 159138663 + 61422788 61432614 chr7 158821424 + 61300000 61310000 4294
+1207 50 50
+1637 22 22
+347 30 30
+983 48 48
+2562 0 172
+1941 14 14
+487 39 41
+459
+
+chain 881174 chr7 159138663 + 61412791 61422788 chr7 158821424 + 61290000 61300000 4600
+2588 34 34
+299 23 23
+1680 4 6
+286 395 396
+256 39 39
+220 18 18
+675 16 16
+3464
+
+chain 807485 chr7 159138663 + 61372814 61382791 chr7 158821424 + 61250000 61260000 5800
+91 75 75
+308 91 91
+99 88 88
+175 43 43
+577 65 65
+289 17 17
+186 21 21
+119 72 72
+80 98 98
+114 2 1
+115 51 51
+319 90 97
+54 49 50
+590 135 136
+749 1 0
+467 41 41
+153 21 21
+97 102 118
+935 19 19
+3186 43 43
+150
+
+chain 475263 chr7 159138663 + 143336322 143346915 chr7 158821424 - 15765291 15775883 242
+2017 14 14
+1214 1 1
+32 1 1
+3171 0 8
+760 1 1
+49 1 1
+68 10 10
+1210 1 1
+39 1 1
+60 18 9
+568 4 4
+357 12 12
+75 512 512
+397
+
+chain 413572 chr7 159138663 + 61432614 61437066 chr7 158821424 + 61310000 61314455 110492
+105 12 12
+1311 18 21
+3006
+
+chain 327362 chr7 159138663 + 130261501 130267755 chr7 158821424 - 80118425 80124354 202501
+81 547 220
+108 98 98
+188 35 35
+305 168 168
+59 47 46
+67 25 25
+301 6 6
+107 44 44
+133 23 23
+174 0 4
+110 27 27
+188 31 31
+86 62 62
+284 66 66
+205 34 34
+171 16 16
+85 35 35
+152 206 205
+64 33 33
+71 76 76
+129 26 26
+52 79 80
+203 92 92
+193 64 64
+113 490 490
+131 98 97
+66
+
+chain 116757 chr7 159138663 + 56987924 57001476 chr7 158821424 - 96066875 96080423 71
+182 4 0
+366 2 0
+47 6 0
+1290 7 1
+317 25 25
+90 14 15
+195 1 6
+96 1 1
+280 1 1
+59 1 1
+435 1 1
+51 1 1
+1067 22 22
+3594 0 1
+645 0 1
+507 7 7
+1383 0 6
+531 0 1
+1396 1 0
+927
+
+chain 94083 chr7 159138663 + 61667110 61669673 chr9 140273252 - 71180528 71183093 1349166
+123 22 22
+57 154 154
+93 530 532
+407 16 16
+95 28 28
+72 290 290
+83 43 43
+61 266 266
+77 77 77
+69
+
+chain 75094 chr7 159138663 + 433321 434167 chr14 106368585 - 82907729 82908574 1677524
+115 1 1
+30 1 0
+335 22 22
+342
+
+chain 74694 chr7 159138663 + 61674373 61676412 chr2 242951149 + 91627954 91629996 1686429
+59 154 155
+210 438 438
+221 259 259
+81 77 77
+52 201 203
+222 15 15
+50
+
+chain 54428 chr7 159138663 + 61360568 61361523 chr9 140273252 + 69464390 69465353 2322078
+76 100 105
+56 176 179
+432 51 51
+64
+
+chain 45723 chr7 159138663 + 100554977 100556023 chr7 158821424 + 100392913 100393963 2803709
+153 225 232
+246 8 8
+74 288 285
+52
+
+chain 42415 chr7 159138663 + 130262863 130266857 chr20 62435964 + 18530662 18534660 203154
+65 162 162
+47 67 67
+25 425 425
+33 1127 1130
+57 206 206
+33 274 274
+33 152 152
+121 149 149
+33 83 83
+64 129 129
+26 335 336
+91 194 194
+63
+
+chain 34286 chr7 159138663 + 61670163 61670988 chr1 247249719 - 187008143 187008914 3936433
+177 89 89
+59 338 284
+162
+
+chain 30309 chr7 159138663 + 61417768 61418394 chr15 100338915 + 53005912 53006538 319980
+332 256 256
+38
+
+chain 29619 chr7 159138663 + 130261638 130262129 chr18 76117153 - 20889181 20889344 211760
+82 389 61
+20
+
+chain 28749 chr7 159138663 + 102187071 102200348 chr7 158821424 + 102073398 102086671 912
+74 1102 1102
+32 11867 11863
+202
+
+chain 27540 chr7 159138663 + 61526936 61527567 chr17 78774742 - 13987513 13988140 5824140
+131 255 251
+90 52 52
+103
+
+chain 25455 chr7 159138663 + 61658206 61658677 chr21 46944323 + 31224827 31225297 6797318
+187 186 185
+98
+
+chain 25398 chr7 159138663 + 130275431 130276578 chrX 154913754 + 99697151 99697788 219009
+66 77 207
+69 353 1
+53 369 81
+54 49 49
+57
+
+chain 24368 chr7 159138663 + 61663982 61664383 chr7 158821424 - 97410910 97411311 7475570
+54 99 99
+67 16 16
+165
+
+chain 23018 chr7 159138663 + 61372081 61372809 chr7 158821424 + 61249436 61249995 8282044
+79 92 92
+52 313 144
+58 34 34
+100
+
+chain 22330 chr7 159138663 + 61674796 61675234 chr16 88827254 - 56087354 56087792 5126597
+69 100 100
+51 129 129
+89
+
+chain 22048 chr7 159138663 + 61583753 61648197 chr7 158821424 - 97506969 97571424 1587
+3024 0 1
+5860 1 1
+34 1 1
+1210 1 1
+46 1 1
+1360 1 1
+20 1 1
+6247 7 7
+2011 22 23
+15979 1 1
+20 0 1
+39 1 1
+156 1 1
+79 1 1
+1227 1 1
+26 1 1
+201 17 17
+6321 11 11
+106 2 2
+66 33 33
+316 6 6
+832 1 1
+17 1 1
+478 1 1
+25 1 1
+4306 14 0
+14 1 1
+525 4 4
+1603 1 1
+28 1 1
+433 1 0
+1365 1 1
+35 1 1
+3699 1 1
+17 1 1
+962 0 16
+124 1 1
+221 1 1
+50 1 1
+446 1 0
+788 0 1
+38 1 1
+470 14 14
+173 1 1
+48 0 1
+54 1 1
+71 0 7
+17 1 1
+319 1 1
+49 1 1
+115 2 1
+167 1 1
+41 3 3
+80 1 1
+70 1 1
+119 1 1
+19 1 1
+186 17 17
+347 7 7
+549 1 1
+69 1 1
+175 1 1
+55 1 1
+101 1 1
+118 2 2
+307 1 1
+73 1 1
+91
+
+chain 20717 chr7 159138663 + 61531674 61531894 chrY 57772954 + 23149505 23149725 9889131
+220
+
+chain 20603 chr7 159138663 + 61525953 61526232 chr8 146274826 + 92437703 92437982 9974457
+114 48 48
+117
+
+chain 20209 chr7 159138663 + 61534129 61534693 chr5 180857866 - 39454690 39455254 10284708
+41 129 129
+72 189 189
+133
+
+chain 19256 chr7 159138663 + 10000 10238 chr11 134452384 - 108 510 10867298
+115 1 145
+57 3 0
+12 3 26
+47
+
+chain 17549 chr7 159138663 + 23954 24387 chr3 199501827 - 125819 126212 1017
+61 27 17
+87 27 17
+87 27 17
+87 27 17
+3
+
+chain 17511 chr7 159138663 + 61459516 61459775 chr3 199501827 + 156410667 156410926 12559831
+104 60 60
+95
+
+chain 17423 chr7 159138663 + 130286013 130286315 chr3 199501827 + 134941335 134941641 12635149
+64 74 78
+72 18 18
+74
+
+chain 17216 chr7 159138663 + 61561042 61561226 chr18 76117153 + 1344411 1344595 12834816
+184
+
+chain 15818 chr7 159138663 + 130258842 130259235 chr20 62435964 - 56174662 56175052 14212289
+60 144 139
+68 52 54
+69
+
+chain 15803 chr7 159138663 + 434188 434399 chr9 140273252 - 53303336 53303547 1693631
+211
+
+chain 15460 chr7 159138663 + 61363520 61363685 chr14 106368585 + 46013452 46013617 14586403
+165
+
+chain 15455 chr7 159138663 + 61533249 61533413 chr10 135374737 - 122138066 122138230 14591550
+164
+
+chain 14801 chr7 159138663 + 61526597 61527118 chr11 134452384 + 128715236 128715756 6490404
+89 98 98
+58 225 224
+51
+
+chain 14577 chr7 159138663 + 61459836 61459991 chr2 242951149 - 172428837 172428992 15528208
+155
+
+chain 14381 chr7 159138663 + 61532809 61533249 chr5 180857866 - 128913075 128913510 15277847
+110 278 273
+52
+
+chain 14182 chr7 159138663 + 61362349 61362804 chr1 247249719 - 101935287 101935742 15983329
+55 287 287
+113
+
+chain 13384 chr7 159138663 + 130261760 130262050 chr18 76117153 - 65538588 65538878 302793
+128 17 17
+145
+
+chain 12863 chr7 159138663 + 61659684 61659821 chr18 76117153 + 15161457 15161594 17682773
+137
+
+chain 12713 chr7 159138663 + 130268588 130270221 chr7 158821424 - 62883278 62884905 17912238
+74 1316 1311
+67 121 120
+55
+
+chain 12498 chr7 159138663 + 61527567 61527825 chr2 242951149 - 136022598 136022856 13034573
+7 155 155
+96
+
+chain 12424 chr7 159138663 + 61560835 61560980 chr21 46944323 - 5411573 5411718 18347201
+82 1 1
+62
+
+chain 11917 chr7 159138663 + 130274671 130277102 chr2 242951149 + 85567844 85569506 1111973
+198 73 73
+65 403 530
+21 111 209
+32 1149 157
+77 81 81
+50 6 4
+165
+
+chain 11414 chr7 159138663 + 61446485 61446604 chr8 146274826 - 97728756 97728875 19987436
+119
+
+chain 11204 chr7 159138663 + 323186 323319 chr13 114142980 - 47557127 47557260 20361650
+67 7 7
+59
+
+chain 11191 chr7 159138663 + 61533547 61533688 chr10 135374737 + 121736617 121736758 14568606
+63 20 20
+58
+
+chain 11162 chr7 159138663 + 143321102 143321761 chr7 158821424 + 143031254 143031913 1465
+659
+
+chain 11033 chr7 159138663 + 155133717 155133867 chr7 158821424 + 154826660 154826810 3228542
+150
+
+chain 10743 chr7 159138663 + 130272956 130273070 chr20 62435964 - 54784771 54784885 21217928
+114
+
+chain 10697 chr7 159138663 + 61363082 61363210 chr8 146274826 + 114533399 114533527 21308454
+63 1 1
+64
+
+chain 10686 chr7 159138663 + 130276049 130276418 chr5 180857866 - 110000669 110000947 1711166
+8 218 161
+54 34 0
+55
+
+chain 10550 chr7 159138663 + 61534371 61534497 chr2 242951149 - 102597516 102597642 13706867
+22 1 1
+103
+
+chain 10502 chr7 159138663 + 61658058 61658206 chr3 199501827 - 100394760 100394909 7999945
+74 51 52
+23
+
+chain 9908 chr7 159138663 + 155127373 155127651 chr7 158821424 + 154820991 154821604 23020589
+62 155 490
+61
+
+chain 9705 chr7 159138663 + 130254993 130255333 chr5 180857866 - 86134908 86135248 23505792
+58 220 220
+62
+
+chain 9691 chr7 159138663 + 61363878 61364175 chr6 170899992 - 83481581 83481894 23533804
+52 178 194
+67
+
+chain 9557 chr7 159138663 + 130275060 130277190 chr4 191273063 + 57733996 57734920 1639272
+2 161 201
+75 1804 558
+40 10 10
+38
+
+chain 9406 chr7 159138663 + 61531909 61532009 chr3 199501827 - 114948547 114948647 24221847
+100
+
+chain 9378 chr7 159138663 + 61670488 61670618 chr1 247249719 + 166585217 166585347 4198164
+130
+
+chain 9215 chr7 159138663 + 61369893 61370445 chr20 62435964 + 26207014 26207215 24594255
+60 436 85
+56
+
+chain 8793 chr7 159138663 + 61533688 61534015 chr8 146274826 + 132629025 132629349 11801047
+54 54 51
+58 97 97
+64
+
+chain 8578 chr7 159138663 + 61650566 61651111 chr20 62435964 - 36228749 36228943 25570183
+56 436 85
+53
+
+chain 8304 chr7 159138663 + 61532721 61532809 chr5 180857866 - 33354116 33354204 19653256
+88
+
+chain 8273 chr7 159138663 + 61375213 61375308 chr10 135374737 - 99567310 99567405 2885342
+95
+
+chain 7707 chr7 159138663 + 61670340 61670429 chr11 134452384 + 5653851 5653940 4693035
+89
+
+chain 7687 chr7 159138663 + 61362996 61363078 chr1 247249719 - 62796192 62796274 26921084
+82
+
+chain 7328 chr7 159138663 + 130260449 130260631 chr6 170899992 + 18975635 18975819 23797357
+8 121 123
+53
+
+chain 7084 chr7 159138663 + 155107000 155107125 chr8 146274826 + 127792382 127792507 21399384
+5 63 63
+57
+
+chain 6750 chr7 159138663 + 130268276 130268348 chr9 140273252 + 6309168 6309240 28699203
+72
+
+chain 6727 chr7 159138663 + 61364306 61364811 chr19 63811651 + 24391898 24393602 28746452
+47 400 1599
+58
+
+chain 6689 chr7 159138663 + 130262523 130267689 chr14 106368585 - 15396362 15401535 205901
+35 1928 1932
+35 3110 3113
+58
+
+chain 6657 chr7 159138663 + 130262248 130266269 chr20 62435964 - 53906684 53910704 204336
+68 3910 3909
+43
+
+chain 6632 chr7 159138663 + 61362621 61362691 chr14 106368585 - 25756639 25756709 18227251
+70
+
+chain 6604 chr7 159138663 + 61516196 61516266 chr14 106368585 + 18700177 18700247 29040667
+70
+
+chain 6561 chr7 159138663 + 61362487 61362621 chr5 180857866 - 77495083 77495217 25581093
+60 70 70
+4
+
+chain 6504 chr7 159138663 + 61563734 61563803 chr14 106368585 + 18700333 18700402 29292943
+69
+
+chain 6504 chr7 159138663 + 61457014 61457083 chr14 106368585 + 19014991 19015060 29292944
+69
+
+chain 6486 chr7 159138663 + 61439583 61439652 chr7 158821424 + 61677724 61677793 29330266
+69
+
+chain 6486 chr7 159138663 + 61453269 61453338 chr11 134452384 + 54672038 54672107 29330599
+69
+
+chain 6415 chr7 159138663 + 130266970 130267081 chr2 242951149 - 44689835 44689946 206027
+111
+
+chain 6395 chr7 159138663 + 61581171 61581239 chr12 132349534 + 36481345 36481413 29552558
+68
+
+chain 6295 chr7 159138663 + 130268491 130268558 chr12 132349534 - 16670768 16670835 29797454
+67
+
+chain 6222 chr7 159138663 + 61516757 61516823 chr7 158821424 - 100865546 100865612 29971261
+66
+
+chain 6149 chr7 159138663 + 61518444 61518509 chr9 140273252 - 73547747 73547812 30146556
+65
+
+chain 6147 chr7 159138663 + 61360661 61361459 chr1 247249719 - 99965931 99966729 2490905
+65 694 694
+39
+
+chain 6131 chr7 159138663 + 61545392 61545457 chr9 140273252 - 71283139 71283204 30224431
+65
+
+chain 6031 chr7 159138663 + 61649702 61649766 chr8 146274826 - 102385209 102385273 30479392
+64
+
+chain 5940 chr7 159138663 + 61567501 61567564 chr11 134452384 - 79723078 79723141 30715303
+63
+
+chain 5895 chr7 159138663 + 130261352 130261415 chr12 132349534 - 16670326 16670389 30822868
+63
+
+chain 5890 chr7 159138663 + 130272150 130272376 chr5 180857866 - 150003108 150003332 287879
+73 71 69
+82
+
+chain 5831 chr7 159138663 + 61540614 61540676 chr20 62435964 + 26207004 26207066 31016062
+62
+
+chain 5822 chr7 159138663 + 61534741 61534803 chr2 242951149 + 182601389 182601451 31037299
+62
+
+chain 5767 chr7 159138663 + 61657263 61657324 chrX 154913754 + 145511099 145511160 31173265
+61
+
+chain 5740 chr7 159138663 + 61561871 61561932 chrX 154913754 + 61825831 61825892 31255925
+61
+
+chain 5707 chr7 159138663 + 155133639 155133717 chr7 158821424 + 154826660 154826738 3248987
+78
+
+chain 5671 chr7 159138663 + 130267178 130267274 chr3 199501827 + 136865539 136865635 212140
+96
+
+chain 5649 chr7 159138663 + 61510793 61510853 chr14 106368585 + 18700200 18700260 31523979
+60
+
+chain 5614 chr7 159138663 + 61459620 61459680 chr8 146274826 + 85828676 85828736 12834914
+60
+
+chain 5505 chr7 159138663 + 130286091 130286151 chr11 134452384 + 126327988 126328048 18815467
+60
+
+chain 5376 chr7 159138663 + 61368713 61368770 chr5 180857866 - 134492854 134492911 32331066
+57
+
+chain 5358 chr7 159138663 + 130272706 130272763 chr4 191273063 - 62601703 62601760 32378845
+57
+
+chain 5239 chr7 159138663 + 61375927 61375982 chr3 199501827 + 176568366 176568421 32719676
+55
+
+chain 5238 chr7 159138663 + 155133561 155133639 chr7 158821424 + 154826660 154826738 3316763
+78
+
+chain 5212 chr7 159138663 + 48202742 48202797 chrY 57772954 + 8140437 8140492 32786933
+55
+
+chain 5203 chr7 159138663 + 61362897 61362952 chr2 242951149 - 204521553 204521608 32840726
+55
+
+chain 5203 chr7 159138663 + 61514738 61514793 chr3 199501827 - 109094736 109094791 32841435
+55
+
+chain 5196 chr7 159138663 + 102270836 102270891 chr7 158821424 + 101958735 101958790 2864
+55
+
+chain 5085 chr7 159138663 + 61522548 61522602 chr11 134452384 - 85760698 85760752 33224588
+54
+
+chain 5081 chr7 159138663 + 61542952 61543361 chrX 154913754 - 96402533 96402599 33252017
+22 343 0
+44
+
+chain 5076 chr7 159138663 + 61566776 61566830 chrX 154913754 + 58536057 58536111 33266851
+54
+
+chain 5003 chr7 159138663 + 321166 321219 chr9 140273252 + 26769862 26769915 33490833
+53
+
+chain 4985 chr7 159138663 + 61511756 61511809 chrX 154913754 + 58510881 58510934 33583214
+53
+
+chain 4976 chr7 159138663 + 61453966 61454019 chr11 134452384 + 48695047 48695100 33600288
+53
+
+chain 4976 chr7 159138663 + 61579973 61580026 chr12 132349534 + 36420396 36420449 33600992
+53
+
+chain 4967 chr7 159138663 + 61528283 61528336 chr2 242951149 - 102597577 102597630 33622422
+53
+
+chain 4930 chr7 159138663 + 61528065 61528117 chr11 134452384 - 85701922 85701974 33735561
+52
+
+chain 4921 chr7 159138663 + 61566142 61566194 chr3 199501827 - 104503080 104503132 33762259
+52
+
+chain 4903 chr7 159138663 + 61364673 61364725 chr9 140273252 + 69253479 69253531 33844300
+52
+
+chain 4894 chr7 159138663 + 61535225 61535277 chrX 154913754 + 61822223 61822275 33894839
+52
+
+chain 4894 chr7 159138663 + 61555289 61555341 chrX 154913754 - 93093366 93093418 33894887
+52
+
+chain 4894 chr7 159138663 + 61367691 61367743 chr11 134452384 + 48824621 48824673 33895037
+52
+
+chain 4876 chr7 159138663 + 61446263 61446315 chr11 134452384 + 54670005 54670057 33929755
+52
+
+chain 4860 chr7 159138663 + 61671055 61671121 chr6 170899992 - 77150208 77150274 16663217
+66
+
+chain 4803 chr7 159138663 + 61582505 61582556 chr5 180857866 + 46128392 46128443 34201035
+51
+
+chain 4803 chr7 159138663 + 61548133 61548184 chr5 180857866 - 134730739 134730790 34201101
+51
+
+chain 4803 chr7 159138663 + 61656299 61656350 chr8 146274826 - 102385679 102385730 34201707
+51
+
+chain 4803 chr7 159138663 + 61371246 61371297 chr20 62435964 + 26207164 26207215 34201851
+51
+
+chain 4803 chr7 159138663 + 61538491 61538542 chrX 154913754 + 61822744 61822795 34202106
+51
+
+chain 4803 chr7 159138663 + 61550591 61550642 chrX 154913754 - 96402828 96402879 34202170
+51
+
+chain 4794 chr7 159138663 + 61568385 61568436 chr12 132349534 - 30627763 30627814 34229426
+51
+
+chain 4794 chr7 159138663 + 61560404 61560455 chrX 154913754 + 58511165 58511216 34229878
+51
+
+chain 4785 chr7 159138663 + 61555628 61555679 chr5 180857866 + 49580248 49580299 34261015
+51
+
+chain 4757 chr7 159138663 + 155127495 155127545 chr7 158821424 + 154820841 154820891 34330191
+50
+
+chain 4745 chr7 159138663 + 61527127 61527200 chr1 247249719 - 196249350 196249423 12580328
+73
+
+chain 4730 chr7 159138663 + 61454627 61454677 chrX 154913754 - 93091546 93091596 34451023
+50
+
+chain 4721 chr7 159138663 + 61547785 61547835 chr14 106368585 + 19015139 19015189 34474345
+50
+
+chain 4712 chr7 159138663 + 61542078 61542128 chr7 158821424 - 97143221 97143271 34536293
+50
+
+chain 4712 chr7 159138663 + 61650232 61650282 chr7 158821424 + 61292872 61292922 34536325
+50
+
+chain 4712 chr7 159138663 + 61447406 61447456 chr12 132349534 - 95867613 95867663 34536696
+50
+
+chain 4712 chr7 159138663 + 61573362 61573412 chr11 134452384 - 79778078 79778128 34537090
+50
+
+chain 4694 chr7 159138663 + 61361784 61361834 chr20 62435964 + 26208957 26209007 34582417
+50
+
+chain 4533 chr7 159138663 + 61657325 61657373 chr14 106368585 - 60354968 60355016 14458107
+48
+
+chain 4330 chr7 159138663 + 61571756 61571802 chrX 154913754 + 58511174 58511220 34815702
+46
+
+chain 4322 chr7 159138663 + 61527200 61527268 chr1 247249719 + 66112503 66112571 10645536
+68
+
+chain 4309 chr7 159138663 + 130262963 130263031 chr20 62435964 + 59813 59881 233275
+68
+
+chain 4243 chr7 159138663 + 130267293 130267390 chr15 100338915 - 46124324 46124421 430805
+97
+
+chain 4225 chr7 159138663 + 130272413 130272571 chr3 199501827 - 60665919 60666077 310359
+158
+
+chain 4225 chr7 159138663 + 130275130 130275387 chr10 135374737 + 61126513 61126771 1703431
+71 112 113
+74
+
+chain 4135 chr7 159138663 + 61657814 61657864 chr4 191273063 - 103880681 103880731 24177091
+50
+
+chain 4106 chr7 159138663 + 130265690 130265763 chr2 242951149 + 45160326 45160399 259070
+73
+
+chain 4049 chr7 159138663 + 61417706 61417751 chr19 63811651 + 35324192 35324237 995629
+45
+
+chain 4036 chr7 159138663 + 102224324 102224366 chr7 158821424 + 102110621 102110663 1050243
+42
+
+chain 3993 chr7 159138663 + 130270112 130270163 chr3 199501827 - 142320121 142320172 24066397
+51
+
+chain 3975 chr7 159138663 + 130269077 130269119 chr8 146274826 + 76339197 76339239 33761016
+42
+
+chain 3893 chr7 159138663 + 61535529 61535570 chr9_random 1146434 - 229264 229305 35008771
+41
+
+chain 3839 chr7 159138663 + 61659187 61659228 chr7 158821424 - 97183039 97183080 35036445
+41
+
+chain 3820 chr7 159138663 + 143397897 143397937 chr7 158821424 - 15657354 15657394 1380183
+40
+
+chain 3770 chr7 159138663 + 130272223 130272265 chr7 158821424 - 144399150 144399192 18136384
+42
+
+chain 3724 chr7 159138663 + 61669828 61671669 chr18 76117153 - 60916397 60916965 5934170
+170 1399 126
+50 156 156
+66
+
+chain 3694 chr7 159138663 + 130276177 130276253 chrX 154913754 + 40955942 40956018 2422661
+76
+
+chain 3685 chr7 159138663 + 102274757 102274796 chr7 158821424 + 101962659 101962698 2923
+39
+
+chain 3592 chr7 159138663 + 102246649 102246687 chr7 158821424 + 101934491 101934529 2920
+38
+
+chain 3540 chr7 159138663 + 61670988 61671026 chr1 247249719 - 1293349 1293387 6950988
+38
+
+chain 3536 chr7 159138663 + 155127890 155127927 chr7 158821424 + 154820516 154820553 31559480
+37
+
+chain 3498 chr7 159138663 + 61668816 61668875 chr21_random 1679693 + 339817 339876 2744470
+59
+
+chain 3321 chr7 159138663 + 130259738 130259803 chr5 180857866 + 117134963 117135028 22545496
+65
+
+chain 3254 chr7 159138663 + 155127171 155127205 chr7 158821424 + 154821284 154821318 30495954
+34
+
+chain 3179 chr7 159138663 + 61671122 61671197 chr3 199501827 + 3741295 3741370 21259213
+75
+
+chain 3139 chr7 159138663 + 61669998 61670032 chr7 158821424 - 73313700 73313734 35261607
+34
+
+chain 3136 chr7 159138663 + 155133873 155133906 chr7 158821424 + 154826660 154826693 3164897
+33
+
+chain 3128 chr7 159138663 + 61657490 61657523 chr14 106368585 + 19500965 19500998 15505654
+33
+
+chain 3124 chr7 159138663 + 61362864 61362897 chr13 114142980 - 56785908 56785941 33122705
+33
+
+chain 3114 chr7 159138663 + 61363362 61363395 chr11 134452384 + 38920746 38920779 30450202
+33
+
+chain 3035 chr7 159138663 + 130267390 130267459 chr5 180857866 + 148307658 148307727 349562
+69
+
+chain 3005 chr7 159138663 + 130258675 130258738 chr3 199501827 - 66319298 66319361 23438786
+63
+
+chain 2998 chr7 159138663 + 61670741 61670826 chr2 242951149 - 144372974 144373059 5019535
+68 11 11
+6
+
+chain 2929 chr7 159138663 + 61366904 61366935 chr9 140273252 + 69000834 69000865 35330365
+31
+
+chain 2883 chr7 159138663 + 130274908 130276723 chr12 132349534 - 84232022 84233270 1810563
+34 1716 687
+63 1 463
+1
+
+chain 2844 chr7 159138663 + 61525923 61525953 chr11 134452384 + 42874872 42874902 16620335
+30
+
+chain 2837 chr7 159138663 + 155133483 155133522 chr7 158821424 + 154826738 154826777 5314872
+39
+
+chain 2752 chr7 159138663 + 130270309 130270363 chr15 100338915 - 53351487 53351541 22720352
+54
+
+chain 2749 chr7 159138663 + 61657932 61657999 chr9 140273252 + 120725102 120725169 13790105
+67
+
+chain 2677 chr7 159138663 + 61657615 61657668 chr2 242951149 - 80490248 80490301 14907722
+53
+
+chain 2675 chr7 159138663 + 61657868 61657928 chr14 106368585 - 67199431 67199491 8049700
+60
+
+chain 2656 chr7 159138663 + 61658132 61658174 chr14 106368585 - 39618235 39618277 11504442
+42
+
+chain 2625 chr7 159138663 + 61376053 61376101 chr2 242951149 - 165273826 165273874 3000213
+48
+
+chain 2574 chr7 159138663 + 130285941 130286005 chr3 199501827 + 177805790 177805854 20115306
+64
+
+chain 2555 chr7 159138663 + 61657373 61657490 chr10 135374737 + 110991454 110991571 9489838
+117
+
+chain 2533 chr7 159138663 + 130255333 130255360 chr5 180857866 + 110504974 110505001 34260994
+27
+
+chain 2525 chr7 159138663 + 155133522 155133561 chr7 158821424 + 154826699 154826738 3760022
+39
+
+chain 2511 chr7 159138663 + 130261431 130261481 chr6 170899992 - 80902268 80902318 240832
+50
+
+chain 2491 chr7 159138663 + 130275062 130277276 chr7 158821424 + 139777825 139778654 1647744
+34 1723 339
+29 404 403
+24
+
+chain 2465 chr7 159138663 + 102229230 102229256 chr7 158821424 + 101917063 101917089 2852
+26
+
+chain 2367 chr7 159138663 + 61656836 61656861 chr8 146274826 - 114798799 114798824 27799318
+25
+
+chain 2262 chr7 159138663 + 61363303 61363362 chr15 100338915 - 25052381 25052440 19971588
+59
+
+chain 2184 chr7 159138663 + 61360913 61360944 chr16 88827254 + 45047397 45047428 3009512
+31
+
+chain 2183 chr7 159138663 + 61655805 61655828 chr8 146274826 - 102376418 102376441 35497387
+23
+
+chain 2181 chr7 159138663 + 61362804 61362827 chr8 146274826 - 64142945 64142968 28339747
+23
+
+chain 2177 chr7 159138663 + 61363497 61363520 chr15 100338915 - 57516283 57516306 24810342
+23
+
+chain 2111 chr7 159138663 + 102252256 102252279 chr7 158821424 + 101940282 101940305 3979
+23
+
+chain 2085 chr7 159138663 + 61668033 61668084 chr9 140273252 + 42719058 42719109 1926685
+51
+
+chain 2073 chr7 159138663 + 130274605 130277252 chr2 242951149 - 168073547 168075372 1534321
+53 350 351
+52 688 693
+76 1025 208
+32 309 298
+62
+
+chain 2067 chr7 159138663 + 155127207 155127236 chr7 158821424 + 154821033 154821062 24052540
+29
+
+chain 2049 chr7 159138663 + 130259609 130260449 chr2 242951149 + 217320568 217321411 19749334
+52 691 694
+97
+
+chain 1867 chr7 159138663 + 61360944 61360976 chr1 247249719 + 146935382 146935414 2538402
+32
+
+chain 1866 chr7 159138663 + 130286570 130286642 chr8 146274826 + 120193638 120193710 13784733
+72
+
+chain 1860 chr7 159138663 + 130271889 130271917 chr3 199501827 + 158050218 158050246 8145167
+28
+
+chain 1834 chr7 159138663 + 130267107 130267162 chr2 242951149 - 74722759 74722814 2183237
+55
+
+chain 1810 chr7 159138663 + 434399 434426 chr8 146274826 + 50019771 50019798 1840028
+27
+
+chain 1807 chr7 159138663 + 61459483 61459516 chr20 62435964 - 10907955 10907988 13772492
+33
+
+chain 1749 chr7 159138663 + 61534521 61534560 chr8 146274826 - 57707270 57707309 18613209
+39
+
+chain 1741 chr7 159138663 + 130275927 130275994 chr3 199501827 - 85253648 85253715 1907688
+67
+
+chain 1725 chr7 159138663 + 130286346 130286404 chr5 180857866 - 156929708 156929766 24410167
+58
+
+chain 1675 chr7 159138663 + 61360800 61360833 chr2 242951149 - 151940057 151940090 10244640
+33
+
+chain 1649 chr7 159138663 + 61527639 61527689 chr10 135374737 - 21832678 21832728 15020107
+50
+
+chain 1626 chr7 159138663 + 61525699 61525759 chr5 180857866 + 119849560 119849620 22270263
+60
+
+chain 1538 chr7 159138663 + 130271917 130271979 chrX 154913754 + 106499092 106499154 335529
+62
+
+chain 1512 chr7 159138663 + 130270436 130270487 chr7 158821424 + 123638895 123638946 23964536
+51
+
+chain 1449 chr7 159138663 + 61671198 61671257 chr11 134452384 + 48551200 48551259 6005368
+59
+
+chain 1444 chr7 159138663 + 130272046 130272150 chr5 180857866 - 107650838 107650942 1109190
+41 46 46
+17
+
+chain 1406 chr7 159138663 + 130268385 130269191 chr13 114142980 + 104373808 104374629 24734362
+65 682 697
+59
+
+chain 1391 chr7 159138663 + 130271979 130272046 chr12 132349534 + 128856107 128856174 572332
+67
+
+chain 1342 chr7 159138663 + 130255652 130255716 chr6 170899992 - 118498216 118498280 24733557
+64
+
+chain 1277 chr7 159138663 + 61525407 61525458 chr14 106368585 - 54569941 54569992 25208354
+51
+
+chain 1239 chr7 159138663 + 61657050 61657132 chr1 247249719 + 60704689 60704771 10216239
+82
+
+chain 1222 chr7 159138663 + 24387 24410 chr9 140273252 - 34976 34999 792
+23
+
+chain 1201 chr7 159138663 + 130267591 130267617 chr3 199501827 - 22519451 22519477 371093
+26
+
+chain 1176 chr7 159138663 + 61533413 61533439 chr9 140273252 + 78066621 78066647 21815254
+26
+
+chain 1159 chr7 159138663 + 130255953 130256003 chr18 76117153 + 30232927 30232977 26680295
+50
+
+chain 1143 chr7 159138663 + 130272637 130272705 chr4 191273063 - 164951872 164951940 23193314
+68
+
+chain 1120 chr7 159138663 + 130267081 130267107 chr4 191273063 + 53894987 53895013 453066
+26
+
+chain 1090 chr7 159138663 + 61375539 61375583 chr16 88827254 - 2017000 2017044 2867569
+44
+
+chain 967 chr7 159138663 + 61363930 61363960 chr5 180857866 - 77417997 77418027 26429199
+30
+
+chain 922 chr7 159138663 + 130269744 130269794 chr6 170899992 - 168370205 168370255 24919326
+50
+
+chain 916 chr7 159138663 + 130272376 130272413 chr7 158821424 - 119807072 119807109 361270
+37
+
+chain 903 chr7 159138663 + 130274518 130274571 chr18 76117153 + 7087852 7087905 2747041
+53
+
+chain 875 chr7 159138663 + 61656861 61656912 chr1 247249719 - 3737712 3737763 19994037
+51
+
+chain 825 chr7 159138663 + 130276127 130276177 chr9 140273252 + 78760365 78760415 3856900
+50
+
+chain 821 chr7 159138663 + 61657151 61657205 chr18 76117153 - 50729761 50729815 10763263
+54
+
+chain 764 chr7 159138663 + 155106965 155107000 chr2 242951149 - 97843675 97843710 19287766
+35
+
+chain 760 chr7 159138663 + 130260179 130260244 chr15 100338915 - 29035916 29035981 5017751
+65
+
+chain 738 chr7 159138663 + 61528144 61528186 chr5 180857866 + 37689556 37689598 26578239
+42
+
+chain 665 chr7 159138663 + 61657587 61657615 chr4 191273063 - 56344538 56344566 26451583
+28
+
+chain 506 chr7 159138663 + 130259438 130259491 chr7 158821424 - 81365049 81365102 23441660
+53
+
+chain 492 chr7 159138663 + 130276335 130276363 chr8 146274826 - 17074751 17074779 8865204
+28
+
+chain 466 chr7 159138663 + 130268939 130269012 chr2 242951149 - 225017173 225017246 26097376
+73
+
+chain 388 chr7 159138663 + 130271813 130271889 chr3 199501827 + 120370918 120370994 4694596
+76
+
+chain 379 chr7 159138663 + 130275097 130275130 chr3 199501827 + 9586745 9586778 4580558
+33
+
+chain 379 chr7 159138663 + 61363702 61363740 chr5 180857866 - 91082220 91082258 29303651
+38
+
+chain 348 chr7 159138663 + 102200504 102200535 chr7 158821424 - 57045045 57045076 1079
+31
+
+chain 17312866 chr7_gl000195_random 182896 + 0 182896 chr7_random 549659 + 162804 345700 162
+182896
+
+chain 13484003737 chr8 146364022 + 10000 146304022 chr8 146274826 + 0 146274826 9
+930417 1243 1
+52 10 10
+91 972 0
+54 54 0
+281 324 0
+289 1 0
+2323216 0 1
+3352649 0 2
+854996 50000 100000
+3399023 1 1
+46 1 1
+13965 1 1
+30 1 1
+121189 1 1
+35 1 1
+283700 1 0
+719291 93054 100016
+1155 2 0
+755 26 26
+980 21 21
+1479 422 422
+3229 0 1
+1937 1 1
+17 1 1
+322 0 1
+1758 0 2
+1141 1 0
+956 48 48
+1765 1 0
+543 25 25
+7047 15 15
+1029 1 1
+28 1 1
+314 1 1
+46 1 1
+164 1 1
+25 1 1
+5130707 1 0
+1288 1 0
+446 1 1
+80 1 1
+2123 4 4
+2514 0 3
+545 0 9
+527 1 1
+18 1 1
+256 9 9
+79 1 1
+40 1 1
+148 2 0
+2236 27 0
+953 1 1
+20 1 1
+2487 1 1
+113 1 1
+73 13 13
+365 10 10
+151 1 1
+32 0 3
+26 1 1
+1480 1 1
+29 1 1
+621 1 1
+28 1 1
+701 9 9
+362 1 1
+19 1 1
+691 1 1
+45 0 6
+46 1 1
+513 11 12
+382 1 1
+22 1 1
+111 1 1
+36 1 1
+337 1 1
+42 1 1
+602 0 2
+36 1 1
+475 1 1
+23 1 0
+32 3 4
+65 1 1
+59 1 1
+688 1 1
+22 1 1
+1473 1 1
+36 1 1
+372 1 1
+16 6 6
+640 25 25
+940 1 1
+38 1 1
+816 1 1
+17 0 1
+374 1 1
+17 1 1
+48 0 1
+82 1 1
+45 1 1
+263 1 1
+23 1 1
+204 1 1
+39 1 1
+2341 1 0
+2989 1 0
+9 1 0
+811 8 8
+741 2 0
+337 1 1
+25 4 4
+763 1 1
+19 1 1
+343 1 1
+31 1 1
+1953 1 1
+74 1 1
+67 1 1
+18 4 4
+73 1 1
+31 1 1
+114 1 11
+87 1 1
+65 1 1
+125 9 9
+378 0 1
+47 1 1
+90 1 1
+96 0 1
+176 7 13
+696 1 0
+6184 13 13
+830 13 13
+128 1 1
+37 1 1
+136 0 1
+66 6 5
+870 0 1
+4877 1 0
+585 7 3
+1728 0 1
+33 1 1
+465 1 1
+68 1 1
+581 0 6
+2088 0 1
+304 1 0
+2674 1 1
+28 0 1
+54 8 8
+846 1 0
+1409 16 16
+559 1 0
+401 5 0
+17 1 5
+29 1 1
+4051 1 1
+10 1 0
+43 1 1
+385 1 1
+35 1 1
+101 11 11
+602 0 1
+491 16 14
+1366 19 19
+321 1 1
+49 1 1
+546 1 1
+25 1 1
+1333 28 28
+1207 1 1
+51 0 4
+159 1 0
+1040 1 0
+1682 4 0
+34 0 8
+867 1 1
+17 1 1
+587 1 1
+21 1 1
+904 1 0
+261 1 0
+1151 2 0
+2325 5 5
+5415 3 0
+1545 0 1
+428 4 4
+1950 0 2
+1073 1 0
+3658 86 0
+1278 1 1
+79 1 1
+6656 12 12
+1550 18 0
+5832 0 1
+4835 10 10
+1719 1 1
+84 1 1
+848 2 0
+236 1 1
+42 1 1
+1286 0 12
+35 1 1
+820 1 1
+22 0 1
+63 22 0
+167 23 23
+315 8 8
+983 0 6
+539 14 14
+863 2 0
+27 1 1
+204 14 14
+163 4 4
+290 1 1
+59 1 1
+842 2 0
+2044 1 1
+90 1 0
+3434 3 0
+356 1 0
+873 1 0
+864 1 25
+630 7 12
+62 1 1
+88 1 1
+76 11 11
+1366 17 17
+156 4 4
+244 18 4
+505 0 1
+109 1 1
+230 1 1
+107 3 4
+150 1 1
+83 5 5
+70 1 1
+33 0 1
+142 1 1
+626 6 5
+274 10 10
+128 1 1
+35 1 1
+216 1 1
+44 1 1
+312 18 18
+1496 7 8
+451 1 0
+212 14 14
+629 1 1
+20 1 1
+350 1 1
+62 1 1
+617 10 10
+845 1 1
+58 1 1
+2189 1 1
+147 1 1
+475 1 1
+27 1 1
+278 1 1
+17 1 1
+994 1 1
+40 1 1
+219 5 5
+26 1 1
+900 1 1
+29 0 1
+26 1 1
+484 16 15
+61 9 9
+114 26 21
+801 1 1
+33 1 1
+465 32 32
+63 1 1
+37 1 1
+80 14 14
+211 1 1
+43 1 1
+156 1 1
+20 1 1
+685 1 1
+67 0 4
+711 1 1
+38 1 1
+402 7 7
+1045 1 1
+37 1 1
+4035 9 9
+247 0 4
+4146274 5734 17400
+330366 1 0
+2346742 55 0
+413177 0 3
+450 0 1
+9436 1 3
+7044 0 4
+2886 0 1
+635 0 1
+16567 0 1
+6918 0 1
+9285 0 1
+14909 0 8
+12879 0 2
+3330 0 2
+2673376 0 2
+2173174 7 7
+29817 2485 66108
+6473782 5 5
+39 1 1
+9574 2 0
+5879 1 1
+29 1 1
+6139 0 1
+2354 1 1
+28 1 1
+91 1 1
+23 0 1
+62 1 1
+142 15 16
+54 1 1
+22 3 3
+1479 4 4
+221 4 4
+132 0 1
+574 11 11
+23 0 1
+604 1 1
+44 1 1
+899 0 1
+70 10 12
+13561 1 1
+44 1 1
+4476 4 4
+799 25 26
+1466 18 18
+17896 0 4
+1668 0 1
+4250 1 1
+44 1 0
+4 1 0
+11 1 1
+4956 1 1
+18 0 1
+39 2 3
+4990 1 1
+47 13 13
+68 0 4
+9730 0 1
+355 1 0
+2186 1 1
+37 1 1
+6111 3 3
+100 4 4
+68 1 1
+43 1 1
+1126 7 5
+5520 8 8
+2316 1 1
+181 6 6
+50 1 1
+29 0 1
+83 1 1
+1073 150 154
+100 398 0
+141 1 1
+25272 1 0
+2132 4 0
+2522 1 1
+48 1 1
+1498528 1 0
+6044582 3000000 3000008
+1291149 16655 60038
+3837 0 3
+811 0 1
+2567 0 1
+7375465 1 0
+10 0 1
+42062 0 1
+19604621 0 1
+10692667 0 1
+110 1 0
+3577 3 0
+907 1 1
+18 1 1
+528 1 1
+50 1 1
+317 1 1
+64 251 535
+21 1 0
+140 1 0
+70 0 1
+77 10 9
+227 0 1
+142 5 5
+57 14 14
+43 1 1
+31034 99683 124100
+2301 2 0
+44 0 2
+568015 186612 87300
+355 5 5
+1916 3085 0
+924 4 0
+339 211 211
+963 14 15
+1157 12194 0
+242 23 23
+56 15 15
+405 20 20
+955 49 49
+1347 1 1
+2289 51 51
+555 253 253
+1723 77 77
+396 13 13
+112 3085 0
+3945 0 1
+209 23 23
+69 22 22
+81 20 20
+696 20 20
+58 69 69
+100 13 13
+326 137 137
+151 35 35
+1804 37 37
+1548 26 26
+324 23 23
+1932 17 17
+111 47 47
+128 16 16
+78 30 30
+1022 10 6
+78 0 1
+342 31 31
+86 23 23
+1580 255 255
+170 10 10
+398 23 23
+419 20 20
+955 55 55
+1139 11 11
+1925 276 0
+223 1 1
+56 1 1
+702 5 5
+17 3 3
+1030 1 1
+21 1 1
+363 1 1
+30 1 1
+785 16 16
+78 13 13
+1036 4 0
+482 68 68
+1069 10 10
+321 200 200
+434 43 43
+798 20 20
+56 25 25
+1007 5 5
+1198 24 24
+689 0 3
+743 32 32
+817 43 43
+574 11 11
+760 69 69
+1229 32 32
+272 29 29
+106 97 97
+1309 46 46
+850 4 4
+777 62 62
+86 36 36
+374 93 93
+2076 31 31
+195 56 56
+379 80 80
+64 11 11
+191 18 18
+1051 13 13
+52 119 113
+1347 1 1
+25 1 1
+3451 188 0
+3097 9 0
+2715 0 1
+11829 3 0
+6000 0 28
+10729 1 0
+3770769 0 1
+62 0 1
+22 0 1
+827 0 1
+1485 0 1
+242 1 0
+7142 0 1
+4029 3 3
+69 1 1
+15865 0 1
+83461 0 4
+5978 0 9
+2661 0 1
+1483 0 1
+15868 0 4
+17798 0 1
+2649 0 1
+3627 0 1
+4789 0 1
+9541 0 1
+6844 0 1
+3187 0 2
+411 0 14
+3056 0 4
+19776 0 3
+29085 1 0
+745 0 2
+11453 0 2
+16739 0 1
+14697 0 1
+8539 0 1
+25514443 0 1
+17680 1 0
+55359 1 0
+58 13 11
+5 1 0
+6 1 0
+5 1 0
+22 0 1
+4 1 3
+1515 0 1
+1111 0 1
+5736 6 6
+66213 0 1
+68 1 1
+24 7 6
+43 1 1
+33414 7 7
+22 1 1
+12288 22 22
+7002 1 0
+8588 1 1
+31 1 1
+15969 1 1
+32 1 1
+27034 1 1
+42 1 1
+3352 1 0
+15009 0 1
+20433 18 18
+32141 8 9
+116 41 41
+4920 0 1
+33364 0 1
+11160 1 0
+15 1 0
+28423 0 1
+43835 1 1
+24 2 4
+269244 4 4
+37 1 1
+17193 3 4
+53 11 12
+23 1 2
+7 1 1
+37978 9 9
+37743 1 1
+35 3 3
+26636 1 1
+17 1 1
+8728292 0 1
+16734777 71275 0
+657026 2 0
+2911 2 0
+1941 1 1
+35 1 1
+835 1 1
+116 1 1
+399 1 1
+101 0 1
+194 2 1
+450 0 1
+825 1 1
+73 1 1
+156 1 1
+58 1 1
+50 5 5
+153 11 11
+189 5 5
+233 1 1
+83 1 1
+642 1 0
+1380 1 1
+17 1 1
+315 1 1
+26 1 1
+789 901 0
+73 1 1
+45 1 1
+535 1 1
+34 1 1
+2007 7 7
+159 1 1
+26 1 1
+6362 13 13
+504325 25635 100008
+420771 232 0
+287688 104 0
+65 364 0
+183 55 0
+93 1 1
+46 1 1
+4002 1 1
+24 1 1
+190 0 147
+65 2 1
+8 0 1
+39 2 591
+306 50 0
+1938 1 0
+578 0 684
+291 1 0
+572289 108288 7108
+480202 0 1
+11866 6 6
+26917 1 0
+6097 15 15
+3074 1 0
+12292 1 0
+2209 1 0
+7358 1 0
+321393
+
+chain 2607822 chr8 146364022 + 12061935 12091854 chr8 146274826 + 12348580 12378713 990
+895 20 0
+1391 22 21
+53 88 0
+99 36 0
+9 0 346
+255 0 44
+496 1 0
+1013 0 4
+1698 1 0
+1054 37 37
+915 52 54
+2295 9 9
+123 1 0
+1295 162 162
+2903 50 50
+913 24 24
+2382 1 0
+299 85 85
+61 27 16
+1351 37 37
+974 4 4
+571 1 0
+530 11 0
+572 18 18
+76 4 4
+398 0 2
+54 31 31
+115 37 37
+125 364 364
+70 47 47
+56 8 8
+979 57 57
+248 50 50
+65 100 100
+82 1 0
+428 34 34
+51 6 0
+156 66 66
+257 132 132
+56 49 49
+91 19 19
+67 38 37
+142 6 6
+249 17 17
+123 104 104
+190 36 37
+355 5 1
+161 1 0
+89 48 48
+62 38 38
+136 67 67
+839
+
+chain 2498503 chr8 146364022 + 86726531 86754632 chr8 146274826 - 59364826 59419953 1092
+268 2 2
+114 6 0
+49 13 13
+1051 18 18
+117 8 3
+81 1 1
+64 4 4
+73 3 3
+379 1 1
+54 1 1
+183 13 13
+374 1 1
+43 1 1
+874 2 2
+22 1 1
+56 20 20
+712 1 1
+91 1 1
+374 1 1
+73 1 1
+88 21 21
+83 1 1
+27 1 1
+302 29 29
+1591 1 1
+27 4 0
+1250 1 1
+20 1 1
+2246 10 9115
+1002 49 49
+314 4 4
+116 32 32
+363 23 23
+1050 13 13
+119 0 8829
+1050 16 16
+1869 31 31
+119 0 9106
+593 13 13
+396 77 77
+1017 32 32
+888 39 39
+2895 1 1
+964 43 43
+1769 15 15
+292 35 35
+97 5 5
+313 13 13
+248 40 40
+435 10 11
+129 6 6
+712
+
+chain 1152177 chr8 146364022 + 142754466 142766515 chr8 146274826 + 142956164 142968213 2035
+12049
+
+chain 1081960 chr8 146364022 + 86772301 86823828 chr8 146274826 + 86857153 86905309 683
+56 15 15
+405 21 21
+1003 383 383
+837 0 1
+126 1 1
+531 1 0
+794 1 0
+73 32 32
+817 43 43
+214 432 432
+212 114 114
+373 28 28
+159 32 32
+832 44 44
+217 192 192
+330 927 923
+88 39 40
+1839 279 279
+283 13 13
+143 1716 1717
+49 3637 3637
+51 555 555
+97 1 1
+21 1 1
+133 1723 1723
+13 16 16
+48 8749 5664
+69 439 439
+62 43 43
+32 151 151
+35 1804 1804
+37 1548 1272
+26 2407 2407
+32 1719 1716
+31 1784 1784
+160 1995 1995
+55 3075 3075
+276 4870 4866
+68 1429 1429
+83 21 21
+67 434 434
+36
+
+chain 801068 chr8 146364022 + 145324300 145332588 chr8 146274826 + 145464193 145472508 5275
+3979 8 0
+2057 0 35
+2244
+
+chain 744541 chr8 146364022 + 86754632 86807992 chr8 146274826 + 86857851 86901670 688
+637 20 20
+440 88 88
+964 1 1
+2289 52 52
+554 1 1
+37 1 1
+1606 46 43
+288 6565 395
+203 3612 3608
+265 1500 1501
+278 1 1
+104 3213 3212
+43 214 214
+138 26 26
+268 212 212
+80 594 594
+32 832 832
+34 227 227
+16 27 27
+149 330 330
+33 21 21
+873 88 85
+39 1839 1839
+229 17 17
+33 9021 8745
+425 14725 11640
+30
+
+chain 657279 chr8 146364022 + 12141854 12149156 chr8 146274826 + 11932698 11940000 7963
+232 8 8
+466 34 34
+801 48 48
+815 68 68
+1203 29 29
+407 31 31
+467 26 26
+1146 18 18
+1503
+
+chain 521724 chr8 146364022 + 12149156 12156927 chr8 146274826 + 11940000 11947772 4417
+2168 0 1
+503 25 25
+153 202 202
+106 107 107
+851 39 39
+1679 1912 1912
+26
+
+chain 511532 chr8 146364022 + 142816515 142822092 chr8 146274826 + 142814667 142820000 26584
+2797 244 0
+2536
+
+chain 345755 chr8 146364022 + 142822092 142825705 chr8 146274826 + 142820000 142823612 174979
+3531 1 0
+81
+
+chain 305790 chr8 146364022 + 86765339 86795897 chr8 146274826 + 86865470 86901765 930
+477 0 9106
+123 31 31
+1705 14 14
+503 14 14
+15 1470 1466
+91 31 31
+52 35 35
+2 7890 7613
+26 560 560
+34 16750 13662
+405 127 127
+203
+
+chain 137107 chr8 146364022 + 85964683 85966170 chr8 146274826 + 86036733 86038220 940425
+1283 19 19
+185
+
+chain 118247 chr8 146364022 + 86759071 86769900 chr8 146274826 + 86874481 86903237 1649
+52 2533 2530
+13 16 16
+1046 0 8829
+123 13 13
+196 2878 11983
+29 3812 3808
+31 52 52
+35
+
+chain 109647 chr8 146364022 + 21624541 21625686 chr8_random 943810 + 516200 517342 1758
+687 1 0
+241 2 0
+214
+
+chain 97713 chr8 146364022 + 86793362 86840444 chr8 146274826 + 86862935 86885634 1255
+1752 44 44
+4 38618 14235
+46 1631 1631
+62 86 86
+36 374 374
+93 2302 2302
+56 379 379
+80 1400 1400
+119
+
+chain 85095 chr8 146364022 + 85924850 85927320 chr2 242951149 - 28701067 28703532 1485529
+52 143 142
+173 208 208
+107 181 181
+68 70 66
+129 101 101
+183 373 373
+87 163 163
+164 198 198
+70
+
+chain 67060 chr8 146364022 + 144032710 144033413 chr8_random 943810 + 583131 583834 1875893
+703
+
+chain 47407 chr8 146364022 + 85907218 85908847 chr10 135374737 - 19950497 19952126 2691979
+115 531 531
+182 240 240
+64 202 202
+122 22 22
+52 45 45
+54
+
+chain 45318 chr8 146364022 + 85909407 85911400 chr3 199501827 - 58732681 58734687 2832173
+138 151 157
+53 129 125
+171 674 685
+80 116 116
+82 347 347
+52
+
+chain 43260 chr8 146364022 + 12069066 12090712 chr8 146274826 - 138168279 138189929 1162
+37 915 915
+52 6789 6802
+48 3620 3620
+85 61 59
+27 1351 1348
+5 1 1
+30 3223 3218
+22 115 115
+37 465 465
+24 3764 3760
+90 837 842
+48
+
+chain 38958 chr8 146364022 + 12159413 12159829 chr8 146274826 + 11950258 11950674 3228
+416
+
+chain 38127 chr8 146364022 + 86726451 86753339 chr8 146274826 - 59376930 59524482 1121
+80 11856 20676
+48 435 435
+32 4503 13609
+31 1121 10227
+77 1017 94649
+32 888 888
+39 3860 3860
+15 1 1
+26 2078 2078
+33 678 678
+38
+
+chain 31437 chr8 146364022 + 85955665 85955994 chr3 199501827 - 6162711 6163040 4382021
+329
+
+chain 30755 chr8 146364022 + 85915208 85915710 chr8 146274826 - 4216734 4217241 4503764
+255 160 165
+87
+
+chain 27896 chr8 146364022 + 940417 941596 chr8 146274826 + 930633 930948 5586021
+100 54 0
+108 810 0
+107
+
+chain 26413 chr8 146364022 + 85978864 85981144 chr9 140273252 - 40203469 40205589 6324943
+79 1134 635
+70 83 416
+56 207 205
+56 22 22
+63 455 463
+55
+
+chain 25390 chr8 146364022 + 85975200 85975766 chr6 170899992 - 89617888 89618457 6830715
+67 141 143
+50 38 39
+54 78 78
+138
+
+chain 20285 chr8 146364022 + 85975766 85977415 chr3 199501827 - 82189783 82191451 9116338
+8 700 763
+50 465 465
+54 309 265
+63
+
+chain 20226 chr8 146364022 + 85979170 85979799 chr3 199501827 - 161413320 161413963 10270718
+61 394 408
+174
+
+chain 20141 chr8 146364022 + 12151827 12152420 chr8 146274826 + 11902715 11903309 638255
+25 153 154
+202 106 106
+107
+
+chain 19400 chr8 146364022 + 85925267 85925628 chr10 135374737 + 135080720 135081080 3597149
+102 2 1
+54 131 131
+72
+
+chain 18915 chr8 146364022 + 942460 942893 chr8 146274826 + 930516 930733 3835109
+63 162 0
+46 108 54
+54
+
+chain 18062 chr8 146364022 + 942088 942460 chr8 146274826 + 930684 930948 5250846
+157 108 0
+107
+
+chain 17886 chr8 146364022 + 943174 943431 chr8 146274826 + 930690 930893 4105167
+149 55 1
+53
+
+chain 15443 chr8 146364022 + 941596 942029 chr8 146274826 + 930516 930841 4827909
+64 207 153
+65 54 0
+43
+
+chain 14855 chr8 146364022 + 85924497 85927134 chrX 154913754 + 50874366 50877002 1910511
+90 57 57
+50 108 108
+48 52 52
+79 801 801
+50 953 952
+50 236 236
+63
+
+chain 12854 chr8 146364022 + 144743895 144744094 chr8 146274826 + 144814885 144815084 3961669
+199
+
+chain 12042 chr8 146364022 + 85907589 85907864 chr4 191273063 + 22500316 22500591 2841396
+81 177 177
+17
+
+chain 11713 chr8 146364022 + 36265496 36265620 chr7 158821424 - 150143040 150143164 19315609
+124
+
+chain 10744 chr8 146364022 + 85909592 85910073 chr4 191273063 - 317022 317498 3271263
+71 86 86
+68 232 227
+24
+
+chain 10295 chr8 146364022 + 85917935 85918395 chr16 88827254 - 19324120 19324578 22152835
+60 331 329
+69
+
+chain 9964 chr8 146364022 + 85927135 85927250 chr3 199501827 - 159900532 159900647 3087651
+115
+
+chain 9833 chr8 146364022 + 85908046 85908504 chr8 146274826 - 114124165 114124623 2795681
+56 59 59
+58 162 162
+123
+
+chain 9709 chr8 146364022 + 943330 943485 chr8 146274826 + 930684 930839 15332741
+48 53 53
+54
+
+chain 9657 chr8 146364022 + 86004292 86004501 chrX 154913754 + 27575363 27575573 23616431
+52 93 94
+64
+
+chain 9406 chr8 146364022 + 85945093 85945452 chr12 132349534 + 8944725 8945099 24220725
+61 243 258
+55
+
+chain 9151 chr8 146364022 + 85910121 85910218 chr10 135374737 - 38564811 38564908 24713323
+97
+
+chain 8406 chr8 146364022 + 85924386 85924476 chr5 180857866 + 127114677 127114767 25803856
+90
+
+chain 7367 chr8 146364022 + 85911400 85911623 chrX 154913754 - 44623158 44623382 4824008
+72 91 92
+60
+
+chain 7214 chr8 146364022 + 85983029 85983106 chr3 199501827 + 182981094 182981171 27755476
+77
+
+chain 7178 chr8 146364022 + 85926461 85926638 chr7 158821424 + 131250991 131251168 8959140
+97 79 79
+1
+
+chain 6913 chr8 146364022 + 85946010 85946083 chr5 180857866 - 76444763 76444836 28360557
+73
+
+chain 6866 chr8 146364022 + 85981016 85981089 chr3 199501827 - 137848275 137848348 18929141
+73
+
+chain 6722 chr8 146364022 + 85915749 85915820 chr6 170899992 - 41858720 41858791 28750065
+71
+
+chain 6523 chr8 146364022 + 85874468 85874538 chr6 170899992 + 80165568 80165638 29222062
+70
+
+chain 6284 chr8 146364022 + 48138290 48138355 chr12 132349534 - 99530740 99530805 29826800
+65
+
+chain 6255 chr8 146364022 + 86830665 86832268 chr8 146274826 + 86851473 86853076 5870
+41 1533 1533
+29
+
+chain 6230 chr8 146364022 + 143494784 143494849 chr8 146274826 + 143492621 143492686 29969115
+65
+
+chain 5949 chr8 146364022 + 85946624 85946687 chr7 158821424 - 150469376 150469439 30705065
+63
+
+chain 5930 chr8 146364022 + 86000088 86000150 chr4 191273063 - 114595117 114595179 30759641
+62
+
+chain 5722 chr8 146364022 + 85909210 85909271 chr4 191273063 - 32715229 32715290 31306692
+61
+
+chain 5681 chr8 146364022 + 85907187 85907519 chr7 158821424 - 141596962 141597294 3108677
+31 137 137
+3 85 85
+76
+
+chain 5594 chr8 146364022 + 85966181 85966240 chr2 242951149 + 129692100 129692159 31643052
+59
+
+chain 5348 chr8 146364022 + 85946168 85946224 chrX 154913754 + 22697258 22697314 32405249
+56
+
+chain 5330 chr8 146364022 + 85945000 85945056 chrX 154913754 - 56717679 56717735 32442268
+56
+
+chain 5292 chr8 146364022 + 85926370 85926785 chr12 132349534 + 42776733 42777148 2271290
+75 280 280
+14 27 27
+19
+
+chain 5194 chr8 146364022 + 85992019 85992074 chr17_random 2617613 - 1345968 1346023 32873362
+55
+
+chain 5161 chr8 146364022 + 941932 941986 chr8 146274826 + 930312 930366 21107216
+54
+
+chain 5012 chr8 146364022 + 85946286 85946339 chr1 247249719 - 150482359 150482412 33477745
+53
+
+chain 4929 chr8 146364022 + 941384 941435 chr8 146274826 + 930304 930355 33748771
+51
+
+chain 4927 chr8 146364022 + 85874401 85874458 chr12 132349534 + 21319375 21319432 33750711
+57
+
+chain 4920 chr8 146364022 + 85945525 85945576 chr10 135374737 + 87468307 87468358 33788347
+51
+
+chain 4810 chr8 146364022 + 942523 942621 chr8 146274826 + 930741 930839 7547023
+98
+
+chain 4803 chr8 146364022 + 85970009 85970060 chr11 134452384 + 10157776 10157827 34198727
+51
+
+chain 4793 chr8 146364022 + 85975065 85975115 chr21 46944323 - 30257577 30257627 34245350
+50
+
+chain 4738 chr8 146364022 + 942303 942352 chr8 146274826 + 930521 930570 34412340
+49
+
+chain 4461 chr8 146364022 + 85910862 85910919 chrX 154913754 + 151305652 151305709 4935543
+57
+
+chain 4271 chr8 146364022 + 86793237 86793293 chr8 146274826 + 86902190 86902246 1452514
+56
+
+chain 4178 chr8 146364022 + 85915489 85915539 chr3 199501827 + 132299011 132299061 5319224
+50
+
+chain 4079 chr8 146364022 + 85926268 85926343 chr2 242951149 - 211437807 211437882 2547607
+75
+
+chain 3965 chr8 146364022 + 85910617 85910659 chr5 180857866 + 105218926 105218968 18292131
+42
+
+chain 3826 chr8 146364022 + 85911256 85911310 chr7 158821424 + 49570162 49570216 23840400
+54
+
+chain 3809 chr8 146364022 + 86829249 86829292 chr8 146274826 + 86874439 86874482 7328
+43
+
+chain 3796 chr8 146364022 + 85928889 85929141 chrX 154913754 + 121492736 121492988 2565989
+99 40 40
+113
+
+chain 3755 chr8 146364022 + 85925629 85925714 chr5 180857866 + 141403818 141403903 2005326
+54 23 23
+8
+
+chain 3680 chr8 146364022 + 36265255 36265294 chr21 46944323 - 8931342 8931381 34138292
+39
+
+chain 3466 chr8 146364022 + 85917822 85917882 chr11 134452384 - 107659023 107659083 22827264
+60
+
+chain 3460 chr8 146364022 + 85925991 85926082 chr19 63811651 + 46688677 46688768 2544872
+91
+
+chain 3412 chr8 146364022 + 85981195 85981250 chr12 132349534 - 23016451 23016506 20760996
+55
+
+chain 3378 chr8 146364022 + 144744318 144744353 chr8 146274826 + 144814727 144814762 26884487
+35
+
+chain 3372 chr8 146364022 + 12064503 12064539 chr8 146274826 + 12351001 12351037 28926895
+36
+
+chain 3336 chr8 146364022 + 85910527 85910617 chr6 170899992 + 121091189 121091279 5885029
+90
+
+chain 3306 chr8 146364022 + 85975140 85975200 chr5 180857866 - 14200316 14200376 14215921
+60
+
+chain 3123 chr8 146364022 + 144455804 144455869 chr8 146274826 + 144526757 144526822 16634618
+65
+
+chain 3122 chr8 146364022 + 85910073 85910106 chr10 135374737 + 91515201 91515234 27999029
+33
+
+chain 2973 chr8 146364022 + 85975297 85975339 chr11 134452384 + 70894433 70894475 12515399
+42
+
+chain 2846 chr8 146364022 + 85980398 85980477 chr6 170899992 + 12780268 12780347 14041671
+79
+
+chain 2664 chr8 146364022 + 85980653 85980843 chr13 114142980 + 79661332 79661527 13462115
+54 70 75
+66
+
+chain 2542 chr8 146364022 + 86811232 86811259 chr8 146274826 + 86750599 86750626 581042
+27
+
+chain 2408 chr8 146364022 + 86780113 86780140 chr8 146274826 + 86901259 86901286 3284
+27
+
+chain 2361 chr8 146364022 + 86795114 86795665 chr8_random 943810 - 353250 353801 88303
+34 419 419
+98
+
+chain 2314 chr8 146364022 + 85909329 85909403 chr5 180857866 - 126448590 126448664 8133335
+74
+
+chain 2312 chr8 146364022 + 85964546 85964619 chr5 180857866 - 22206487 22206560 13216855
+73
+
+chain 2306 chr8 146364022 + 85909062 85909878 chr5 180857866 - 76491094 76491924 7171448
+57 726 740
+33
+
+chain 2277 chr8 146364022 + 85945069 85945093 chr2 242951149 - 76417863 76417887 30610067
+24
+
+chain 2276 chr8 146364022 + 85915156 85915196 chr9 140273252 + 96271703 96271743 9134049
+40
+
+chain 2255 chr8 146364022 + 12171549 12171574 chr8 146274826 + 11962388 11962413 4339
+25
+
+chain 2213 chr8 146364022 + 85976678 85976734 chr10 135374737 + 107478570 107478626 23840391
+56
+
+chain 2193 chr8 146364022 + 85909817 85909844 chr1 247249719 - 204777828 204777855 6141044
+27
+
+chain 2188 chr8 146364022 + 85915463 85915489 chr4 191273063 + 117566433 117566459 5547542
+26
+
+chain 2086 chr8 146364022 + 85907670 85907692 chr9 140273252 + 84577624 84577646 25068333
+22
+
+chain 2042 chr8 146364022 + 85906786 85906876 chr1 247249719 - 187757137 187757227 3120497
+90
+
+chain 2008 chr8 146364022 + 85975339 85978010 chr12 132349534 - 60955403 60957663 7657094
+69 2448 2037
+58 20 20
+76
+
+chain 1976 chr8 146364022 + 85910386 85910476 chr11 134452384 + 108691426 108691516 10944711
+90
+
+chain 1915 chr8 146364022 + 85915895 85915946 chr2 242951149 - 57258601 57258652 18793758
+51
+
+chain 1706 chr8 146364022 + 85926558 85926608 chr20 62435964 + 52983902 52983952 9284939
+50
+
+chain 1666 chr8 146364022 + 85915539 85915568 chr3 199501827 - 58686941 58686970 11643280
+29
+
+chain 1625 chr8 146364022 + 85977632 85977856 chr3 199501827 - 45071352 45071581 10048168
+62 161 166
+1
+
+chain 1603 chr8 146364022 + 36265620 36265653 chr4 191273063 + 189716401 189716434 1596951
+33
+
+chain 1586 chr8 146364022 + 86793293 86793362 chr8_random 943810 + 582217 582286 150907
+69
+
+chain 1585 chr8 146364022 + 85907040 85907092 chr7 158821424 + 38674874 38674926 25744726
+52
+
+chain 1584 chr8 146364022 + 85964393 85964443 chr1 247249719 - 57954630 57954680 20174423
+50
+
+chain 1470 chr8 146364022 + 85911121 85911160 chr15 100338915 + 92120615 92120654 21684489
+39
+
+chain 1463 chr8 146364022 + 942731 942785 chr8 146274826 + 930679 930733 5019737
+54
+
+chain 1440 chr8 146364022 + 85911043 85911098 chr1 247249719 - 141715465 141715520 4313974
+55
+
+chain 1426 chr8 146364022 + 85978253 85978320 chr2 242951149 - 208172805 208172872 22624190
+67
+
+chain 1403 chr8 146364022 + 85928837 85929028 chr18 76117153 + 39707440 39707631 2816562
+52 99 99
+40
+
+chain 1344 chr8 146364022 + 85907124 85907170 chr12 132349534 + 45103963 45104009 16171151
+46
+
+chain 1332 chr8 146364022 + 85927450 85927503 chr1 247249719 - 29234742 29234795 3133635
+53
+
+chain 1287 chr8 146364022 + 85907361 85907411 chr1 247249719 - 78547145 78547195 4245040
+50
+
+chain 1276 chr8 146364022 + 85927323 85927376 chr4 191273063 - 93337200 93337253 2720957
+53
+
+chain 1269 chr8 146364022 + 85908257 85908286 chr9 140273252 - 124490379 124490408 3695355
+29
+
+chain 1238 chr8 146364022 + 85978601 85978678 chr9 140273252 - 23294193 23294270 19053025
+77
+
+chain 1193 chr8 146364022 + 144455743 144455792 chr8 146274826 + 144526504 144526553 26679478
+49
+
+chain 1175 chr8 146364022 + 12087452 12087488 chr11 134452384 - 63301652 63301688 1994288
+36
+
+chain 1137 chr8 146364022 + 85909119 85909164 chr2 242951149 + 35848313 35848358 13461114
+45
+
+chain 1067 chr8 146364022 + 86832385 86832437 chr8_random 943810 - 358237 358289 86749
+52
+
+chain 1048 chr8 146364022 + 86824709 86824734 chr8 146274826 + 86857705 86857730 2636
+25
+
+chain 1045 chr8 146364022 + 85911001 85911043 chr15 100338915 - 40210675 40210717 4055996
+42
+
+chain 1028 chr8 146364022 + 85910323 85910373 chr4 191273063 + 26203887 26203937 5050480
+50
+
+chain 1020 chr8 146364022 + 85924694 85924736 chr3 199501827 + 1701599 1701641 4262142
+42
+
+chain 1005 chr8 146364022 + 85977261 85977320 chr10 135374737 + 45388722 45388781 14596230
+59
+
+chain 998 chr8 146364022 + 85908847 85908872 chr4 191273063 + 183519567 183519592 8543079
+25
+
+chain 985 chr8 146364022 + 85918576 85918627 chr3 199501827 - 21820872 21820923 24828426
+51
+
+chain 981 chr8 146364022 + 144744094 144744133 chr8 146274826 + 144814821 144814860 14840226
+39
+
+chain 922 chr8 146364022 + 85918981 85919046 chrX 154913754 - 100261670 100261735 22334691
+65
+
+chain 912 chr8 146364022 + 85964449 85964513 chr6 170899992 + 131272389 131272453 24950513
+64
+
+chain 888 chr8 146364022 + 85915710 85915739 chr9 140273252 + 12069456 12069485 13568361
+29
+
+chain 867 chr8 146364022 + 85976220 85976271 chrX 154913754 - 36573362 36573413 23586363
+51
+
+chain 857 chr8 146364022 + 86832445 86832471 chr8 146274826 + 86747431 86747457 7742
+26
+
+chain 802 chr8 146364022 + 85978516 85978572 chr3 199501827 + 80520031 80520087 22639668
+56
+
+chain 801 chr8 146364022 + 85911160 85911249 chr16 88827254 + 31611661 31611750 16482423
+89
+
+chain 785 chr8 146364022 + 85917259 85917324 chr5 180857866 - 163179499 163179564 25049793
+65
+
+chain 721 chr8 146364022 + 85926739 85926765 chr18 76117153 + 15364211 15364237 2792298
+26
+
+chain 647 chr8 146364022 + 85918645 85918703 chr11 134452384 - 90657004 90657062 25582649
+58
+
+chain 612 chr8 146364022 + 941818 941867 chr8 146274826 + 930360 930409 12502809
+49
+
+chain 596 chr8 146364022 + 85976593 85979111 chrX 154913754 - 42670843 42673368 13030869
+53 2388 2395
+77
+
+chain 568 chr8 146364022 + 85966335 85966385 chrX 154913754 + 36275879 36275929 27751459
+50
+
+chain 474 chr8 146364022 + 85917714 85917772 chr1 247249719 + 62707004 62707062 26279221
+58
+
+chain 396 chr8 146364022 + 85977502 85977572 chrX 154913754 - 138803117 138803187 17501406
+70
+
+chain 369 chr8 146364022 + 85976646 85976678 chr7 158821424 + 51906674 51906706 15299893
+32
+
+chain 360 chr8 146364022 + 85980297 85980349 chr12 132349534 - 124024481 124024533 24774043
+52
+
+chain 337 chr8 146364022 + 85981293 85981372 chr1 247249719 - 152445011 152445090 12777550
+79
+
+chain 328 chr8 146364022 + 85976447 85976474 chr2 242951149 - 99982783 99982810 22051776
+27
+
+chain 310 chr8 146364022 + 85976849 85976905 chr3 199501827 - 69459686 69459742 25770085
+56
+
+chain 286 chr8 146364022 + 85979114 85979170 chr7 158821424 - 11181572 11181628 19756881
+56
+
+chain 232 chr8 146364022 + 85978010 85978057 chr1 247249719 + 108819891 108819938 19586297
+47
+
+chain 3680035 chr8_gl000196_random 38914 + 0 38914 chr8_random 943810 + 643258 682172 798
+38914
+
+chain 3554032 chr8_gl000197_random 37175 + 0 37175 chr8_random 943810 + 493047 530222 826
+37175
+
+chain 11336430536 chr9 141213431 + 10000 141153431 chr9 140273252 + 0 140273252 13
+189075 17 17
+39464594 50000 50000
+261110 50000 50000
+208233 50000 50000
+142805 50000 50000
+464507 50000 50000
+152873 50000 50000
+172579 50000 50000
+799200 4 0
+398958 50000 50000
+549743 100000 50000
+632871 50000 50000
+680077 50000 50000
+181647 50000 50000
+291910 100000 50000
+465318 50000 50000
+350909 50000 50000
+194609 100000 50000
+370337 176 0
+128581 100047 50047
+157499 18150000 18100000
+450681 50000 50000
+223855 50000 50000
+162441 50000 50000
+159539 50000 50000
+199148 50000 50000
+194491 100000 50000
+158462 150000 50000
+471702 150000 50000
+376183 150000 50000
+174765 150000 50000
+289439 50000 50000
+682157 50000 50000
+158187 100000 50000
+187806 50000 50000
+178933 100000 50000
+21507948 100000 50000
+85380 150000 50000
+834971 0 1
+39559293 150000 100000
+3818133 50000 200000
+2075804 50000 30000
+1936434
+
+chain 1179 chr9 141213431 + 46931376 46931552 chr9 140273252 - 98415895 98416071 50
+176
+
+chain 443 chr9 141213431 + 47160133 47160180 chr9 140273252 - 72994158 72994205 112
+47
+
+chain 8504653 chr9_gl000198_random 90085 + 0 90085 chr9_random 1146434 + 526031 616116 387
+90085
+
+chain 10524551 chr9_gl000199_random 169874 + 0 146316 chr9_random 1146434 + 903151 1075994 305
+35956 981 11726
+149 118 118
+212 21 21
+101 50 50
+98 0 8841
+196 126 126
+211 19 19
+115 44 44
+76 72 72
+100 9 9
+92 107 107
+86 1193 169
+50 168 18105
+488 0 1
+10599 1 1
+42 1 0
+8869 101 101
+10239 51 51
+179 500 502
+1131 0 1
+12346 0 18932
+463 15 15
+739 1 1
+64 1 1
+2323 0 1
+755 1 1
+188 1 1
+245 0 2
+10316 4 5
+18 1 1
+8496 15 15
+1065 3 3
+49 1 1
+67 1 1
+24 1 1
+150 15 15
+2700 5110 0
+46 11735 0
+376 5 5
+2019 342 0
+1220 1192 0
+221 37 37
+60 21 21
+334 6678 50
+235 1381 27
+52 2571 21
+62
+
+chain 3014585 chr9_gl000199_random 169874 + 136786 169869 chr9_random 1146434 + 939452 971857 944
+79 683 6
+4467 235 235
+1381 52 52
+786 1 1
+38 1 0
+29 1 1
+1715 62 62
+1332 14 14
+6821 1 1
+55 1 1
+15329
+
+chain 306268 chr9_gl000199_random 169874 + 114056 136743 chr9_random 1146434 + 1030711 1052467 1210
+785 60 60
+2828 46 46
+527 6 352
+63 378 378
+514 181 181
+824 72 72
+329 1 1
+35 1 1
+68 1 1
+37 1 1
+3228 135 132
+81 325 325
+52 391 391
+60 10252 2341
+243 179 691
+73 42 42
+155 0 1190
+24 0 1871
+442 0 3064
+2 95 95
+151
+
+chain 178734 chr9_gl000199_random 169874 + 38939 136592 chr9_random 1146434 + 940083 990000 1006
+27 31954 13752
+34 77 77
+166 43 43
+110 68 68
+2 41253 31459
+196 349 7
+48 5105 0
+83 14 14
+62 11 11
+208 514 2
+181 824 144
+72 3917 172
+325 52 52
+391 9096 1608
+467 1909 41
+95
+
+chain 108146 chr9_gl000199_random 169874 + 35956 37588 chr9_random 1146434 + 1073965 1075597 311529
+981 149 149
+118 334 334
+50
+
+chain 94079 chr9_gl000199_random 169874 + 125187 127738 chr9_random 1146434 + 934627 937178 173754
+2551
+
+chain 56396 chr9_gl000199_random 169874 + 38488 39821 chr9_random 1146434 + 1072584 1073917 324037
+57 225 225
+83 113 113
+855
+
+chain 37331 chr9_gl000199_random 169874 + 127738 129141 chr9_random 1146434 + 1073395 1074798 197032
+1403
+
+chain 15154 chr9_gl000199_random 169874 + 133472 133633 chr9_random 1146434 - 103942 104103 2035052
+161
+
+chain 14222 chr9_gl000199_random 169874 + 39821 40265 chr9_random 1146434 + 982531 990446 140426
+290 71 7542
+83
+
+chain 13688 chr9_gl000199_random 169874 + 112619 134922 chr9_random 1146434 + 997840 1005340 1760
+54 480 138
+65 48 48
+86 0 1
+62 27 27
+193 20460 5998
+27 467 467
+2 15 15
+59 221 221
+37
+
+chain 12407 chr9_gl000199_random 169874 + 60350 137506 chr9_random 1146434 + 944493 957004 1913
+35 10569 695
+47 196 196
+40 113 113
+68 62256 9695
+367 1799 779
+34 1232 42
+400
+
+chain 5910 chr9_gl000199_random 169874 + 112953 113153 chr9_random 1146434 + 1036251 1036451 100700
+200
+
+chain 4997 chr9_gl000199_random 169874 + 124080 124135 chr9_random 1146434 + 959057 959112 19926960
+55
+
+chain 4162 chr9_gl000199_random 169874 + 113634 113846 chr9_random 1146434 + 995454 995665 201802
+27 40 39
+145
+
+chain 3441 chr9_gl000199_random 169874 + 37915 38008 chr9_random 1146434 + 950621 950714 48386
+93
+
+chain 3360 chr9_gl000199_random 169874 + 129226 129424 chr9_random 1146434 + 996412 996610 9342
+198
+
+chain 3255 chr9_gl000199_random 169874 + 70690 70741 chr9_random 1146434 + 1012726 1012777 23586
+51
+
+chain 3031 chr9_gl000199_random 169874 + 112869 137060 chr9_random 1146434 + 964682 969139 3960
+84 23929 4195
+178
+
+chain 2784 chr9_gl000199_random 169874 + 60406 60450 chr9_random 1146434 + 1000736 1000780 8481
+44
+
+chain 2406 chr9_gl000199_random 169874 + 38361 40328 chr9_random 1146434 + 940183 941126 6867
+36 1868 844
+63
+
+chain 2091 chr9_gl000199_random 169874 + 135580 135759 chr9_random 1146434 + 1043989 1044168 130849
+179
+
+chain 1790 chr9_gl000199_random 169874 + 113899 113969 chr9 140273252 - 71272426 71272496 22178754
+70
+
+chain 1047 chr9_gl000199_random 169874 + 114872 114901 chr9_random 1146434 + 1035274 1035303 118930
+29
+
+chain 1014 chr9_gl000199_random 169874 + 129141 129510 chr9_random 1146434 + 949663 949862 115384
+82 201 31
+86
+
+chain 827 chr9_gl000199_random 169874 + 125159 125187 chr9 140273252 - 71272290 71272318 10194134
+28
+
+chain 754 chr9_gl000199_random 169874 + 136743 136786 chr9_random 1146434 - 170925 170968 528799
+43
+
+chain 683 chr9_gl000199_random 169874 + 134041 134094 chr9_random 1146434 + 1025518 1025571 412663
+53
+
+chain 494 chr9_gl000199_random 169874 + 71001 71031 chr9_random 1146434 + 983095 983125 1059560
+30
+
+chain 444 chr9_gl000199_random 169874 + 133651 133674 chr9_random 1146434 + 1066888 1066911 84972
+23
+
+chain 309 chr9_gl000199_random 169874 + 137506 137547 chr9_random 1146434 + 967717 967758 659942
+41
+
+chain 254 chr9_gl000199_random 169874 + 125119 125159 chr9_random 1146434 + 1071966 1072006 1499804
+40
+
+chain 241 chr9_gl000199_random 169874 + 137060 137086 chr9_random 1146434 + 965055 965081 39489
+26
+
+chain 190 chr9_gl000199_random 169874 + 124136 124176 chr9_random 1146434 + 947206 947246 772655
+40
+
+chain 17692629 chr9_gl000200_random 187035 + 0 187035 chr9_random 1146434 + 666116 853151 157
+187035
+
+chain 3482851 chr9_gl000201_random 36148 + 0 36148 chr9_random 1146434 + 0 36148 835
+36148
+
+chain 1574309 chrM 16571 + 0 16571 chrM 16571 + 0 16571 1542
+16571
+
+chain 15737781 chrUn_gl000211 166566 + 0 166566 chr22_random 257318 + 90752 257318 187
+166566
+
+chain 17750502 chrUn_gl000212 186858 + 0 186858 chr13_random 186858 + 0 186858 154
+186858
+
+chain 15269201 chrUn_gl000213 164239 + 0 164239 chr21 46944323 - 32900547 33064909 192
+4659 1 0
+8525 1 0
+592 12 11
+2258 2 0
+942 18 18
+7633 0 33
+6726 1 1
+49 4 4
+119 1 1
+127 6 0
+114 1 1
+1963 1 1
+856 0 1
+2836 1 0
+20 0 1
+262 6 6
+128 1 1
+22 1 1
+8105 14 0
+16 4 0
+1875 0 1
+8447 4 0
+157 10 10
+2207 0 1
+2729 0 2
+9463 1 0
+239 1 0
+17 2 0
+1990 3 0
+7559 3 2
+1342 1 1
+73 1 1
+1095 9 9
+57 1 1
+80 1 1
+290 16 16
+79 9 9
+151 4 4
+728 4 0
+580 4 0
+160 8 8
+184 1 1
+21 1 1
+3074 12 10
+471 6 6
+698 11 11
+338 0 3
+205 0 28
+1909 0 10
+508 1 1
+31 1 1
+847 1 2
+271 0 4
+337 1 1
+31 3 0
+355 1 1
+61 1 1
+237 1 1
+60 24 0
+307 0 4
+941 1 1
+37 5 0
+338 31 24
+563 0 644
+637 12 12
+369 1 1
+26 1 1
+136 630 0
+374 1 1
+31 1 1
+375 1 1
+48 1 1
+2210 1 1
+35 0 1
+1039 19 1
+53 1 1
+270 8 6
+337 1 1
+40 1 1
+2174 6 6
+841 1 1
+29 1 1
+1975 0 10
+37 1 1
+703 0 60
+223 15 15
+1844 0 4
+394 3 0
+63 1 1
+34 1 1
+121 1 1
+25 4 10
+12 12 0
+2694 8 8
+100 2 0
+2952 1 1
+27 1 1
+1508 0 4
+2169 16 16
+48 1 0
+894 9 9
+310 0 1
+2288 0 2
+4522 0 4
+32 1 1
+3231 0 6
+2045 1 1
+44 1 1
+955 9 9
+345 6 6
+129 1 1
+19 1 1
+167 1 0
+333 2 0
+716 22 22
+1384 1 0
+189 1 1
+23 0 28
+1452 1 1
+28 1 1
+1661 1 4
+496 18 17
+141 1 1
+44 1 1
+1971 1 6
+103 1 1
+47 1 1
+662 6 0
+318 0 5
+935 1 1
+47 1 1
+220 1 1
+36 1 1
+815 1 0
+49 1 0
+224 3 4
+86 1 1
+47 1 1
+683 2 2
+42 1 1
+1493 0 1
+373 0 1
+454 0 2
+179 0 12
+639 0 5
+616 66 81
+613 0 1
+198 8 11
+1412 4 0
+604 4 0
+1065 5 0
+3599 1 1
+44 1 1
+311 4 0
+302 1 0
+1762 31 31
+555
+
+chain 19447 chrUn_gl000213 164239 + 98731 98946 chr21 46944323 - 32999281 32999496 6410578
+102 6 6
+107
+
+chain 5115 chrUn_gl000213 164239 + 98535 98731 chr15 100338915 + 19297082 19297917 3190124
+68 49 688
+79
+
+chain 918427 chrUn_gl000214 137718 + 80069 90748 chr1 247249719 - 105489797 105500468 3815
+119 1 1
+25 1 1
+201 5 5
+65 5 5
+139 1 1
+69 1 1
+150 1 1
+67 4 4
+380 6 0
+73 10 10
+167 10 10
+63 1 1
+23 1 1
+369 4 4
+43 1 1
+235 1 1
+83 6 6
+99 1 1
+91 1 1
+116 14 14
+488 3 3
+47 1 0
+11 1 1
+216 1 1
+23 1 1
+84 1 1
+71 1 1
+549 1 1
+22 1 1
+146 1 1
+102 1 1
+104 1 1
+80 1 1
+59 1 1
+19 1 1
+402 1 1
+39 1 1
+284 1 1
+33 1 1
+161 4 4
+34 1 1
+125 1 1
+20 1 1
+472 1 1
+19 1 1
+228 23 23
+425 1 1
+99 1 1
+266 1 1
+42 1 1
+54 1 1
+62 1 1
+228 4 2
+85 6 6
+68 1 1
+242 1 1
+167 1 1
+33 1 1
+133 24 24
+773 7 7
+379 0 1
+218 62 62
+81 1 1
+37 1 1
+364 1 1
+29 1 1
+234
+
+chain 143213 chrUn_gl000214 137718 + 129234 137707 chr4 191273063 - 142244722 142253930 901087
+227 142 142
+52 32 32
+60 159 159
+56 5 5
+135 69 69
+183 83 83
+78 152 152
+70 161 161
+102 13 13
+186 9 9
+127 123 123
+78 241 241
+116 4845 5724
+91 242 98
+110 65 65
+64 13 13
+72 181 181
+131
+
+chain 112581 chrUn_gl000214 137718 + 116800 119267 chr4 191273063 + 48987510 48989977 1137439
+144 225 225
+135 141 141
+87 10 10
+130 173 173
+90 147 147
+57 103 103
+70 22 22
+84 50 50
+113 26 26
+103 37 37
+69 102 102
+127 4 4
+58 73 73
+87
+
+chain 35731 chrUn_gl000214 137718 + 49713 50123 chr21_random 1679693 + 637667 638077 3744988
+55 5 5
+34 1 1
+315
+
+chain 33173 chrUn_gl000214 137718 + 125487 134177 chr1 247249719 - 105123947 105126634 1162767
+65 110 110
+58 32 32
+395 7 7
+90 6069 74
+68 8 0
+64 36 36
+114 56 56
+54 63 63
+58 137 137
+182 277 277
+54 21 21
+122 248 248
+52 190 190
+60
+
+chain 26395 chrUn_gl000214 137718 + 40302 40606 chr1 247249719 - 18749005 18749307 6333362
+57 1 0
+75 1 0
+112 1 1
+57
+
+chain 25884 chrUn_gl000214 137718 + 126321 126850 chr21_random 1679693 + 746615 747120 6569895
+87 97 73
+114 5 5
+50 118 118
+58
+
+chain 25524 chrUn_gl000214 137718 + 41463 41766 chr9 140273252 - 40046622 40046925 6760130
+54 7 7
+122 4 4
+116
+
+chain 25177 chrUn_gl000214 137718 + 122978 125190 chr21_random 1679693 - 928041 930254 1258444
+118 228 229
+72 288 288
+139 44 44
+185 600 600
+136 37 37
+126 58 58
+181
+
+chain 23478 chrUn_gl000214 137718 + 136191 136535 chr4 191273063 + 48976406 48976750 8004925
+183 83 83
+78
+
+chain 20443 chrUn_gl000214 137718 + 41766 42878 chr3 199501827 + 629423 630533 8757399
+9 908 906
+118 25 25
+52
+
+chain 20379 chrUn_gl000214 137718 + 135162 135774 chr21_random 1679693 - 927923 928535 1491304
+50 44 44
+225 152 152
+141
+
+chain 18931 chrUn_gl000214 137718 + 44528 44730 chr10 135374737 - 38544783 38544985 11331455
+202
+
+chain 18826 chrUn_gl000214 137718 + 43343 43562 chr2 242951149 - 53551644 53551863 11416331
+110 1 1
+31 1 1
+76
+
+chain 18670 chrUn_gl000214 137718 + 90865 91063 chr1 247249719 - 105065042 105065240 11545618
+198
+
+chain 17773 chrUn_gl000214 137718 + 131919 132224 chr1 247249719 - 105124387 105124692 2973977
+225 10 10
+70
+
+chain 16259 chrUn_gl000214 137718 + 112825 112997 chr2 242951149 + 132826168 132826340 13778307
+172
+
+chain 16179 chrUn_gl000214 137718 + 117367 119564 chr1 247249719 + 142120582 142122781 1230197
+57 994 995
+43 121 121
+25 103 103
+37 69 69
+76 567 568
+105
+
+chain 14745 chrUn_gl000214 137718 + 40137 40293 chr18 76117153 + 36159000 36159156 15342897
+156
+
+chain 14511 chrUn_gl000214 137718 + 35480 35726 chr21_random 1679693 + 599809 599984 15605110
+107 80 9
+59
+
+chain 13694 chrUn_gl000214 137718 + 21320 21487 chrX 154913754 - 125740203 125740370 16565517
+81 11 11
+75
+
+chain 13486 chrUn_gl000214 137718 + 6106 6250 chr5 180857866 + 84443323 84443467 16839883
+144
+
+chain 13485 chrUn_gl000214 137718 + 18381 18548 chrX 154913754 + 88818181 88818344 16841154
+59 4 0
+49 4 4
+51
+
+chain 12687 chrUn_gl000214 137718 + 41058 41208 chr4 191273063 - 138230980 138231130 9286530
+62 5 5
+83
+
+chain 12516 chrUn_gl000214 137718 + 121124 121344 chr4 191273063 + 48979662 48979882 18214722
+66 74 74
+80
+
+chain 12053 chrUn_gl000214 137718 + 40633 40761 chrX 154913754 + 112045399 112045527 18908316
+128
+
+chain 11633 chrUn_gl000214 137718 + 43977 44114 chr4 191273063 - 11125034 11125171 12115615
+68 9 9
+60
+
+chain 11343 chrUn_gl000214 137718 + 39886 40006 chr13 114142980 + 66998338 66998458 20107936
+120
+
+chain 10884 chrUn_gl000214 137718 + 18108 18254 chr7 158821424 - 131367688 131367833 20945231
+55 19 18
+72
+
+chain 10521 chrUn_gl000214 137718 + 42241 42602 chr8 146274826 - 25959812 25960177 13454333
+84 222 226
+55
+
+chain 10411 chrUn_gl000214 137718 + 45055 45186 chr20 62435964 + 7050253 7050384 21896014
+54 12 12
+65
+
+chain 10343 chrUn_gl000214 137718 + 8804 8914 chrY 57772954 + 22287260 22287370 22043563
+110
+
+chain 9757 chrUn_gl000214 137718 + 19458 19875 chr3 199501827 - 187590477 187590901 23376485
+52 295 302
+70
+
+chain 9700 chrUn_gl000214 137718 + 39692 39809 chrX 154913754 - 41279737 41279854 23514677
+52 4 4
+61
+
+chain 9578 chrUn_gl000214 137718 + 45502 45617 chrX 154913754 + 43420636 43420751 23808291
+55 5 5
+55
+
+chain 7894 chrUn_gl000214 137718 + 124390 125487 chr4 191273063 - 142252912 142254012 6167993
+130 754 757
+69 123 123
+21
+
+chain 7612 chrUn_gl000214 137718 + 129655 137576 chr1 247249719 + 142120436 142122192 1126110
+32 89 89
+59 44 44
+27 862 716
+54 6116 97
+123 138 138
+47 149 149
+97 35 35
+49
+
+chain 7146 chrUn_gl000214 137718 + 43209 43286 chr18 76117153 - 9582204 9582281 16185526
+77
+
+chain 6775 chrUn_gl000214 137718 + 131335 131918 chr4 191273063 - 142062211 142062794 1233528
+62 218 218
+89 189 189
+25
+
+chain 6321 chrUn_gl000214 137718 + 44440 44513 chr1 247249719 + 157810312 157810385 13757396
+56 5 5
+12
+
+chain 5727 chrUn_gl000214 137718 + 119564 119897 chr4 191273063 - 142062730 142063063 7342832
+77 196 196
+60
+
+chain 5584 chrUn_gl000214 137718 + 136603 136661 chr4 191273063 + 48976819 48976877 31707162
+58
+
+chain 5192 chrUn_gl000214 137718 + 41407 41463 chr4 191273063 + 95935104 95935160 21196855
+56
+
+chain 4895 chrUn_gl000214 137718 + 6041 6105 chr11 134452384 + 65843917 65843981 20155275
+64
+
+chain 4869 chrUn_gl000214 137718 + 43083 43135 chr9 140273252 - 106613347 106613399 21934699
+52
+
+chain 4480 chrUn_gl000214 137718 + 42602 42659 chr7 158821424 - 39929511 39929568 12681275
+57
+
+chain 4078 chrUn_gl000214 137718 + 41235 41291 chrX 154913754 - 134405062 134405118 18412789
+56
+
+chain 4015 chrUn_gl000214 137718 + 42902 42960 chr10 135374737 + 54220968 54221026 24474909
+58
+
+chain 3895 chrUn_gl000214 137718 + 40957 41057 chr14 106368585 + 31140172 31140272 6582169
+100
+
+chain 3738 chrUn_gl000214 137718 + 42125 42173 chrX 154913754 + 103679820 103679868 22522957
+48
+
+chain 3537 chrUn_gl000214 137718 + 136028 136122 chr4 191273063 + 48976243 48976337 4189785
+94
+
+chain 3097 chrUn_gl000214 137718 + 17979 18039 chrX 154913754 - 102020287 102020347 24003938
+60
+
+chain 2977 chrUn_gl000214 137718 + 126408 126469 chr1 247249719 - 105124849 105124910 6601664
+61
+
+chain 2968 chrUn_gl000214 137718 + 41775 41809 chr8 146274826 + 100416036 100416070 11606659
+34
+
+chain 2831 chrUn_gl000214 137718 + 137492 137527 chr4 191273063 + 48977417 48977452 2940885
+17 9 9
+9
+
+chain 2572 chrUn_gl000214 137718 + 44291 44369 chr11 134452384 - 117952414 117952492 17845944
+78
+
+chain 2345 chrUn_gl000214 137718 + 42033 42103 chr4 191273063 - 122527078 122527148 13059103
+70
+
+chain 2276 chrUn_gl000214 137718 + 43135 43209 chr1 247249719 + 86869873 86869947 13860931
+74
+
+chain 1770 chrUn_gl000214 137718 + 44144 44227 chr3 199501827 + 24100092 24100175 18271654
+83
+
+chain 1506 chrUn_gl000214 137718 + 36174 36256 chr1 247249719 - 105422371 105422453 16376759
+82
+
+chain 1502 chrUn_gl000214 137718 + 43875 43977 chr9 140273252 + 102510935 102511037 11228177
+102
+
+chain 1456 chrUn_gl000214 137718 + 130737 130768 chr21_random 1679693 - 929809 929840 22601085
+31
+
+chain 1365 chrUn_gl000214 137718 + 125246 125274 chr21_random 1679693 - 930310 930338 15151243
+28
+
+chain 1098 chrUn_gl000214 137718 + 42962 43013 chr6 170899992 - 83239423 83239474 24355258
+51
+
+chain 931 chrUn_gl000214 137718 + 41878 41928 chr11 134452384 - 41659375 41659425 15038916
+50
+
+chain 888 chrUn_gl000214 137718 + 45207 45259 chr11 134452384 + 93610909 93610961 21407350
+52
+
+chain 856 chrUn_gl000214 137718 + 119897 119930 chr19 63811651 - 14205840 14205873 23032647
+33
+
+chain 766 chrUn_gl000214 137718 + 127016 127090 chr19 63811651 - 14200495 14200569 19831992
+74
+
+chain 676 chrUn_gl000214 137718 + 18987 19049 chr11 134452384 + 106173710 106173772 23556763
+62
+
+chain 650 chrUn_gl000214 137718 + 132603 132659 chr21_random 1679693 + 746889 746945 1349757
+56
+
+chain 423 chrUn_gl000214 137718 + 20746 20796 chr2 242951149 - 226029097 226029147 25845790
+50
+
+chain 16237347 chrUn_gl000215 172545 + 28 172526 chr21 46944323 + 13950000 14122426 177
+3255 0 4
+29034 1 0
+5104 4 0
+10299 0 8
+14263 11 11
+94 6 0
+113 107 1
+75 1 1
+91 1 1
+24 1 1
+6681 0 33
+907 41 41
+7674 2 0
+2274 12 11
+563 0 1
+8540 1 0
+12525 1 1
+36 1 1
+25408 0 12
+3782 0 2
+694 85 67
+996 1 3
+1425 12 12
+1827 1 1
+21 1 1
+941 13 13
+2073 0 8
+28 1 1
+506 0 2
+1227 1 0
+1108 2 2
+28 1 1
+396 1 0
+253 14 14
+184 1 1
+49 1 1
+2962 1 1
+45 4 0
+1510 19 19
+2709 25 25
+1068 0 4
+836 1 0
+1871 0 1
+579 4 0
+60 14 14
+2466 27 27
+1450 1 0
+19 1 1
+618 6 6
+2880 1 0
+450 0 2
+27 0 4
+4576 1 1
+20 1 1
+789 0 1
+721 14 14
+1438 35 31
+1381 1 1
+18 1 1
+73 12 12
+195 1 1
+35 1 1
+708
+
+chain 40526 chrUn_gl000216 172294 + 149263 155793 chr18 76117153 - 76016375 76018189 3221814
+113 325 326
+78 431 292
+71 14 14
+107 786 375
+37 69 0
+81 2953 216
+58 1361 0
+46
+
+chain 27660 chrUn_gl000216 172294 + 75671 76099 chr20 62435964 - 33142597 33142960 5774439
+63 0 10
+32 5 0
+14 10 0
+50 35 0
+20 10 0
+56 5 0
+53 21 11
+54
+
+chain 27279 chrUn_gl000216 172294 + 130292 130617 chrX 154913754 + 63390360 63390685 5931924
+69 12 12
+78 1 1
+165
+
+chain 17860 chrUn_gl000216 172294 + 130000 130214 chr4 191273063 + 73778471 73778685 12240737
+58 12 12
+144
+
+chain 16947 chrUn_gl000216 172294 + 147288 147775 chr18 76117153 - 76016450 76016937 13094679
+76 288 288
+123
+
+chain 13816 chrUn_gl000216 172294 + 129031 129176 chr8 146274826 - 38602125 38602270 16419487
+145
+
+chain 12180 chrUn_gl000216 172294 + 145189 145506 chrY 57772954 + 11928279 11928596 18712695
+46 95 95
+51 66 66
+59
+
+chain 11701 chrUn_gl000216 172294 + 158739 158864 chr18 76117153 + 99277 99402 19495084
+125
+
+chain 11637 chrUn_gl000216 172294 + 171754 172194 chrY 57772954 + 11932706 11933147 19600583
+53 299 300
+88
+
+chain 11521 chrUn_gl000216 172294 + 129787 129947 chr6 170899992 + 5983639 5983799 19799726
+64 26 26
+70
+
+chain 10625 chrUn_gl000216 172294 + 164963 165111 chr18 76117153 + 100265 100413 21456050
+73 25 25
+50
+
+chain 10470 chrUn_gl000216 172294 + 131591 131702 chrX 154913754 + 36583233 36583344 21778508
+111
+
+chain 10288 chrUn_gl000216 172294 + 131963 132072 chr3 199501827 - 99262429 99262538 22162166
+109
+
+chain 9778 chrUn_gl000216 172294 + 141853 142019 chr18 76117153 - 76016600 76016834 23327029
+64 49 117
+53
+
+chain 9609 chrUn_gl000216 172294 + 135933 137341 chrY 57772954 + 11926871 11928279 23735609
+56 647 1260
+56 613 0
+36
+
+chain 9489 chrUn_gl000216 172294 + 169302 169609 chrY 57772954 + 11921023 11921330 24024953
+52 191 191
+64
+
+chain 9460 chrUn_gl000216 172294 + 132170 132290 chrY 57772954 + 11935643 11935763 24098583
+50 10 10
+60
+
+chain 9059 chrUn_gl000216 172294 + 169179 169274 chrY 57772954 - 366511 366606 24861253
+95
+
+chain 8863 chrUn_gl000216 172294 + 133271 135681 chrY 57772954 - 372628 372853 25150456
+61 2277 92
+72
+
+chain 8329 chrUn_gl000216 172294 + 1479 1877 chr4 191273063 - 141929935 141931620 25915977
+67 278 1565
+53
+
+chain 8155 chrUn_gl000216 172294 + 150573 151188 chrY 57772954 - 377413 378366 22301630
+51 559 897
+5
+
+chain 8086 chrUn_gl000216 172294 + 168370 168455 chr18 76117153 - 76017788 76017873 26288571
+85
+
+chain 7777 chrUn_gl000216 172294 + 34186 34268 chr1 247249719 - 24981278 24981360 26771397
+82
+
+chain 6822 chrUn_gl000216 172294 + 132393 132465 chrY 57772954 - 376390 376462 28544596
+72
+
+chain 6622 chrUn_gl000216 172294 + 9240 9310 chr10 135374737 + 41683434 41683504 28988878
+70
+
+chain 6573 chrUn_gl000216 172294 + 130631 130733 chr5 180857866 - 72032622 72032724 12023329
+102
+
+chain 6476 chrUn_gl000216 172294 + 146529 146597 chr18 76117153 - 76017808 76017876 29355811
+68
+
+chain 6422 chrUn_gl000216 172294 + 8523 8591 chr4 191273063 + 48829234 48829302 29489285
+68
+
+chain 6384 chrUn_gl000216 172294 + 148442 148586 chrY 57772954 - 378355 378430 29582296
+29 69 0
+46
+
+chain 6003 chrUn_gl000216 172294 + 133483 133546 chrY 57772954 - 370776 370839 30561430
+63
+
+chain 5985 chrUn_gl000216 172294 + 11844 11907 chr4 191273063 + 48811176 48811239 30589131
+63
+
+chain 5885 chrUn_gl000216 172294 + 151788 151850 chrY 57772954 - 366263 366325 30854068
+62
+
+chain 5721 chrUn_gl000216 172294 + 136853 136913 chrY 57772954 - 372235 372295 31317120
+60
+
+chain 5667 chrUn_gl000216 172294 + 19071 19131 chr4 191273063 + 48811263 48811323 31460984
+60
+
+chain 5339 chrUn_gl000216 172294 + 145664 145720 chrY 57772954 + 11941006 11941062 32420221
+56
+
+chain 5322 chrUn_gl000216 172294 + 130963 131035 chr5 180857866 - 36043748 36043820 20305124
+72
+
+chain 5257 chrUn_gl000216 172294 + 158216 158271 chr18 76117153 + 96100 96155 32682417
+55
+
+chain 5221 chrUn_gl000216 172294 + 7155 7210 chr4 191273063 + 48836505 48836560 32772522
+55
+
+chain 5121 chrUn_gl000216 172294 + 15141 15195 chr4 191273063 + 48847759 48847813 33093239
+54
+
+chain 5012 chrUn_gl000216 172294 + 26593 26646 chr21 46944323 - 37095349 37095402 33456608
+53
+
+chain 4930 chrUn_gl000216 172294 + 37276 37328 chr1 247249719 - 24981705 24981757 33717061
+52
+
+chain 4884 chrUn_gl000216 172294 + 137193 137244 chrY 57772954 - 377416 377467 33922210
+51
+
+chain 4821 chrUn_gl000216 172294 + 20849 20900 chr20 62435964 - 33142732 33142783 34122269
+51
+
+chain 4766 chrUn_gl000216 172294 + 152958 153008 chr18 76117153 - 76017195 76017245 34319410
+50
+
+chain 4757 chrUn_gl000216 172294 + 155624 155674 chr18 76117153 - 76018020 76018070 34342345
+50
+
+chain 2863 chrUn_gl000216 172294 + 172194 172224 chrY 57772954 + 11925069 11925099 19922357
+30
+
+chain 2829 chrUn_gl000216 172294 + 131145 131290 chr12 132349534 + 50244945 50245090 12112131
+51 88 88
+6
+
+chain 2529 chrUn_gl000216 172294 + 129176 129203 chr9 140273252 - 119219512 119219539 22134781
+27
+
+chain 2341 chrUn_gl000216 172294 + 131196 131233 chr3 199501827 - 98572452 98572489 18288091
+37
+
+chain 2151 chrUn_gl000216 172294 + 131290 131397 chr7 158821424 - 127191925 127192032 12067691
+107
+
+chain 2108 chrUn_gl000216 172294 + 149377 153105 chrY 57772954 + 11933439 11934497 20496839
+67 3022 286
+50 506 572
+83
+
+chain 1614 chrUn_gl000216 172294 + 130868 130925 chr3 199501827 - 79251115 79251172 16953843
+57
+
+chain 1538 chrUn_gl000216 172294 + 76099 76129 chr21 46944323 - 37102976 37103006 11762953
+30
+
+chain 694 chrUn_gl000216 172294 + 135555 135593 chrY 57772954 - 377637 377675 25976788
+38
+
+chain 532 chrUn_gl000216 172294 + 153980 155370 chrY 57772954 - 378352 378449 22847936
+39 1293 0
+58
+
+chain 454 chrUn_gl000216 172294 + 863 915 chr4 191273063 + 48799453 48799505 31198348
+52
+
+chain 383 chrUn_gl000216 172294 + 153157 153210 chr18 76117153 - 76017394 76017447 29745290
+53
+
+chain 174 chrUn_gl000216 172294 + 138050 138103 chrY 57772954 + 11945950 11946003 28091780
+53
+
+chain 99 chrUn_gl000216 172294 + 11396 11447 chr20 62435964 - 33142766 33142817 31359773
+51
+
+chain 13777792 chrUn_gl000217 172149 + 23665 172149 chr21_random 1679693 - 1239693 1388121 218
+366 17 17
+766 1 0
+21 0 8
+60 2 0
+3460 4 0
+2511 2 0
+113 1 0
+1145 0 1
+931 1 1
+37 1 1
+107 13 13
+4657 1 1
+48 1 1
+2113 0 1
+574 10 0
+111 1 0
+49 1 1
+1025 3 0
+497 0 11
+154 5 0
+640 0 6
+1684 0 16
+300 1 0
+1527 0 6
+147 1 0
+718 18 0
+30 1 1
+1243 1 1
+16 1 1
+162 28 0
+401 0 11
+281 1 1
+27 1 1
+892 1 0
+45 1 1
+2501 0 26
+74 115 11
+2278 8 8
+1028 0 1
+756 7 7
+1386 1 0
+3286 40 0
+504 1 0
+989 1 1
+24 1 1
+123 36 37
+2057 0 26
+72 2 0
+945 1 1
+22 1 1
+1558 1 1
+43 2 0
+2083 22 0
+462 0 1
+86 1 1
+37 1 1
+1415 0 1
+22 0 1
+1139 24 25
+1775 11 11
+2714 1 1
+41 1 1
+4780 0 1
+352 1 1
+25 1 1
+171 1 0
+514 1 0
+2199 1 1
+48 1 1
+262 3 1
+2426 0 1
+502 0 2
+1043 1 1
+49 1 0
+3147 0 3
+4432 1 1
+17 1 1
+2420 1 0
+43 1 1
+1809 1 0
+15 1 1
+1710 0 34
+61 36 0
+119 0 2
+4683 1 1
+44 1 1
+58 23 0
+44 0 104
+50 98 0
+43 1 1
+214 1 41
+29 0 1
+4 6 13
+39 0 105
+122 1 1
+31 17 1
+69 234 6
+48 1 17
+40 1 1
+1306 2 0
+3089 0 1
+2059 1 1
+32 1 1
+137 1 4
+584 1 0
+2518 1 0
+480 0 4
+6 2 0
+22 8 0
+177 1 1
+29 1 1
+6728 0 1
+1945 0 2
+8972 11 11
+806 1 3
+3054 0 3
+649 0 4
+1956 1 3
+795 1 0
+16 1 1
+1498 1 1
+28 1 1
+3012 5 0
+238 0 5
+220 0 5
+441 0 31
+141 10 0
+57 5 0
+1652 1 0
+233 1 0
+855 1 0
+845 38 0
+395 0 38
+182 22 0
+494 0 139
+1699 1 1
+42 0 1
+2261 1 1
+33 1 1
+3400 1 1
+41 1 1
+2247 0 2
+46 4 0
+34 0 14
+1049 1 13
+223 1 1
+49 1 1
+746 1 1
+36 1 1
+3491 0 1
+528
+
+chain 29979 chrUn_gl000217 172149 + 0 388 chr9 140273252 - 70842853 70843241 4686196
+80 39 39
+172 1 1
+24 1 1
+71
+
+chain 18989 chrUn_gl000217 172149 + 8221 8418 chr12 132349534 - 39661230 39661427 11281819
+197
+
+chain 10175 chrUn_gl000217 172149 + 14880 15009 chr19 63811651 + 45504623 45504752 22420709
+57 12 12
+60
+
+chain 3003 chrUn_gl000217 172149 + 63765 63801 chr6 170899992 + 56559189 56559225 3519131
+36
+
+chain 15268007 chrUn_gl000218 161147 + 0 161147 chr4_random 842648 + 681501 842648 193
+161147
+
+chain 274326 chrUn_gl000219 179198 + 111203 114251 chr8 146274826 - 136639851 136643413 309026
+102 1 1
+45 1 1
+484 9 9
+416 19 537
+171 4 0
+45 1 1
+189 7 7
+1328 1 1
+25 1 1
+199
+
+chain 235925 chrUn_gl000219 179198 + 35758 40113 chr15 100338915 - 47328984 47333335 444051
+127 1 1
+284 1 1
+140 1 1
+133 1 1
+73 1 1
+89 1 1
+75 13 8
+90 1 1
+92 1 1
+53 1 1
+73 1 1
+71 137 137
+163 8 8
+63 55 55
+141 31 31
+188 97 97
+60 103 103
+177 192 193
+314 188 188
+58 236 236
+75 260 260
+62 155 155
+105 29 29
+135
+
+chain 46161 chrUn_gl000219 179198 + 66272 68851 chrX 154913754 - 104037210 104039793 2773810
+120 238 238
+52 281 281
+59 653 657
+101 247 247
+106 343 343
+50 27 27
+62 173 173
+67
+
+chain 39536 chrUn_gl000219 179198 + 161917 162706 chr3 199501827 + 46165513 46166302 3318717
+67 218 218
+170 33 33
+104 60 60
+51 4 4
+82
+
+chain 37284 chrUn_gl000219 179198 + 19843 20929 chr8 146274826 + 98123209 98124295 3557690
+51 99 100
+128 134 134
+52 226 225
+160 168 168
+68
+
+chain 28967 chrUn_gl000219 179198 + 161273 161605 chr11 134452384 - 120964606 120964939 5150829
+171 2 3
+60 3 3
+96
+
+chain 28762 chrUn_gl000219 179198 + 6734 7878 chr3 199501827 - 92709198 92710343 5264432
+50 316 316
+83 67 67
+64 228 228
+51 85 86
+50 65 65
+85
+
+chain 21234 chrUn_gl000219 179198 + 175633 175875 chr1 247249719 - 2003467 2003709 9514914
+86 1 1
+40 1 1
+114
+
+chain 19234 chrUn_gl000219 179198 + 161066 161917 chr3 199501827 - 120235323 120237534 3582834
+110 737 2097
+4
+
+chain 14579 chrUn_gl000219 179198 + 21180 21751 chr1 247249719 - 137161846 137162418 6911796
+101 255 256
+2 163 163
+50
+
+chain 14519 chrUn_gl000219 179198 + 21064 21625 chr8 146274826 - 24167411 24167976 5552170
+59 415 419
+87
+
+chain 12254 chrUn_gl000219 179198 + 20707 20861 chr10 135374737 - 130087649 130087801 7386312
+11 3 1
+47 1 0
+4 0 1
+88
+
+chain 9835 chrUn_gl000219 179198 + 175209 175553 chr1 247249719 + 75620763 75621106 11122143
+78 179 178
+87
+
+chain 9013 chrUn_gl000219 179198 + 69512 69754 chr7 158821424 - 49488455 49488697 24923378
+57 133 133
+52
+
+chain 8698 chrUn_gl000219 179198 + 38816 38977 chr2 242951149 + 197483269 197483430 445169
+50 27 27
+84
+
+chain 7558 chrUn_gl000219 179198 + 37648 39844 chr4 191273063 - 67477312 67479509 573905
+31 2054 2055
+111
+
+chain 7043 chrUn_gl000219 179198 + 7883 7996 chrX 154913754 + 69120337 69120450 10599908
+113
+
+chain 6948 chrUn_gl000219 179198 + 21437 21525 chr10 135374737 - 55879531 55879619 9852807
+88
+
+chain 6886 chrUn_gl000219 179198 + 69191 69264 chrX 154913754 - 102980817 102980890 28429791
+73
+
+chain 6839 chrUn_gl000219 179198 + 21356 21436 chr11 134452384 + 41149119 41149199 10517795
+80
+
+chain 6788 chrUn_gl000219 179198 + 67776 67858 chr1 247249719 - 168765537 168765619 14909693
+1 2 2
+79
+
+chain 6785 chrUn_gl000219 179198 + 65376 65449 chr6 170899992 - 64502886 64502959 18163056
+73
+
+chain 6479 chrUn_gl000219 179198 + 35525 35758 chr13 114142980 - 61572553 61572786 1009673
+94 1 1
+129 2 2
+7
+
+chain 6180 chrUn_gl000219 179198 + 161178 161256 chr16 88827254 + 48470284 48470362 9569492
+78
+
+chain 5767 chrUn_gl000219 179198 + 65835 65896 chr1 247249719 + 223356684 223356745 31174397
+61
+
+chain 5622 chrUn_gl000219 179198 + 64700 64760 chr20 62435964 - 34176164 34176224 31585501
+60
+
+chain 4453 chrUn_gl000219 179198 + 175305 175363 chr7 158821424 - 154223466 154223524 19289607
+58
+
+chain 4398 chrUn_gl000219 179198 + 39190 39280 chr3 199501827 - 39205036 39205126 641764
+90
+
+chain 4168 chrUn_gl000219 179198 + 39128 39178 chrX 154913754 + 101254041 101254091 4762602
+50
+
+chain 4142 chrUn_gl000219 179198 + 160731 161020 chr7 158821424 + 108154685 108154975 5568871
+69 147 148
+73
+
+chain 4059 chrUn_gl000219 179198 + 39531 39627 chrY 57772954 + 3377002 3377098 1049766
+96
+
+chain 3905 chrUn_gl000219 179198 + 39425 39515 chr4 191273063 - 20599126 20599216 1025664
+90
+
+chain 3833 chrUn_gl000219 179198 + 19916 19966 chr11 134452384 - 24481539 24481589 14324455
+50
+
+chain 3723 chrUn_gl000219 179198 + 21281 21353 chr8 146274826 + 142341809 142341882 8036105
+11 0 1
+61
+
+chain 3631 chrUn_gl000219 179198 + 7185 7231 chr4 191273063 - 60113302 60113348 10096087
+46
+
+chain 3560 chrUn_gl000219 179198 + 35297 35440 chrX 154913754 + 31459857 31460000 1356163
+59 9 9
+75
+
+chain 3418 chrUn_gl000219 179198 + 74680 74734 chr2 242951149 + 159856161 159856226 35171835
+17 0 12
+9 2 1
+26
+
+chain 3363 chrUn_gl000219 179198 + 65597 65637 chr10 135374737 + 67903510 67903550 17680942
+40
+
+chain 3281 chrUn_gl000219 179198 + 38411 38486 chr18 76117153 + 65271563 65271638 907991
+75
+
+chain 3262 chrUn_gl000219 179198 + 162509 162544 chrX 154913754 - 14195886 14195921 20233062
+35
+
+chain 3092 chrUn_gl000219 179198 + 161605 161689 chr2 242951149 - 35465049 35465133 8792079
+19 6 6
+59
+
+chain 3074 chrUn_gl000219 179198 + 8990 9025 chr5 180857866 - 164468813 164468848 19527162
+35
+
+chain 3012 chrUn_gl000219 179198 + 38101 39406 chr14 106368585 - 62185839 62187145 783679
+26 1240 1241
+39
+
+chain 2934 chrUn_gl000219 179198 + 161840 161913 chr5 180857866 + 13471789 13471862 3866284
+73
+
+chain 2839 chrUn_gl000219 179198 + 34989 35118 chr8 146274826 + 40409778 40409907 1133484
+56 12 12
+61
+
+chain 2727 chrUn_gl000219 179198 + 21634 21700 chr14 106368585 - 78516623 78516689 9118599
+66
+
+chain 2697 chrUn_gl000219 179198 + 68852 68888 chr5 180857866 + 9312654 9312690 14610628
+36
+
+chain 2584 chrUn_gl000219 179198 + 35177 35274 chr3 199501827 + 147129328 147129425 4467916
+97
+
+chain 2547 chrUn_gl000219 179198 + 161690 161789 chr5 180857866 + 112830789 112830888 9276265
+99
+
+chain 2541 chrUn_gl000219 179198 + 162131 162175 chr12 132349534 + 54242993 54243037 9307702
+44
+
+chain 2485 chrUn_gl000219 179198 + 66217 68255 chr3 199501827 - 72358479 72360521 2866668
+55 1368 1372
+35 524 524
+56
+
+chain 2353 chrUn_gl000219 179198 + 38305 38360 chr8 146274826 - 49639359 49639414 1034303
+55
+
+chain 2230 chrUn_gl000219 179198 + 19408 19487 chr7 158821424 - 133365577 133365656 10769161
+79
+
+chain 2205 chrUn_gl000219 179198 + 37167 37218 chr2 242951149 - 113063084 113063135 1010147
+51
+
+chain 2136 chrUn_gl000219 179198 + 65993 67374 chr8 146274826 - 58386388 58387767 6969587
+99 1231 1229
+51
+
+chain 2065 chrUn_gl000219 179198 + 7314 7369 chr14 106368585 + 55554421 55554476 5303485
+55
+
+chain 1985 chrUn_gl000219 179198 + 5703 5757 chr4 191273063 - 94652192 94652246 23958560
+54
+
+chain 1979 chrUn_gl000219 179198 + 66506 66565 chr7 158821424 + 94546370 94546429 13229356
+59
+
+chain 1960 chrUn_gl000219 179198 + 8700 8761 chrY 57772954 + 20614456 20614517 21829859
+61
+
+chain 1888 chrUn_gl000219 179198 + 38366 38411 chr2 242951149 - 129971519 129971564 1057646
+45
+
+chain 1811 chrUn_gl000219 179198 + 160836 160864 chr22 49691432 - 22795768 22795796 23819908
+28
+
+chain 1737 chrUn_gl000219 179198 + 20319 20358 chrX 154913754 + 73928334 73928373 13243726
+39
+
+chain 1736 chrUn_gl000219 179198 + 19558 19630 chr12 132349534 - 63652443 63652515 6467659
+72
+
+chain 1682 chrUn_gl000219 179198 + 39076 39116 chr3 199501827 + 15208154 15208194 1287150
+40
+
+chain 1666 chrUn_gl000219 179198 + 38024 38063 chr1 247249719 - 83040882 83040921 867179
+39
+
+chain 1646 chrUn_gl000219 179198 + 37115 37153 chr15 100338915 - 50839190 50839228 850747
+38
+
+chain 1585 chrUn_gl000219 179198 + 67541 68190 chr8 146274826 - 129698985 129699635 3519578
+54 538 539
+57
+
+chain 1568 chrUn_gl000219 179198 + 21824 21882 chr4 191273063 + 144137347 144137405 18944021
+58
+
+chain 1525 chrUn_gl000219 179198 + 6513 6565 chr8 146274826 - 33560291 33560343 10738256
+52
+
+chain 1509 chrUn_gl000219 179198 + 162035 162086 chr3 199501827 + 35122783 35122834 10573790
+51
+
+chain 1485 chrUn_gl000219 179198 + 160887 160939 chr4 191273063 + 75861307 75861359 9708390
+52
+
+chain 1479 chrUn_gl000219 179198 + 65726 65767 chrX 154913754 - 87810259 87810300 15949912
+41
+
+chain 1467 chrUn_gl000219 179198 + 39689 39722 chrX 154913754 + 69240387 69240420 781473
+33
+
+chain 1461 chrUn_gl000219 179198 + 67280 67323 chr10 135374737 - 66201225 66201268 13894764
+43
+
+chain 1450 chrUn_gl000219 179198 + 67375 67437 chr5 180857866 + 57384861 57384923 6350454
+62
+
+chain 1396 chrUn_gl000219 179198 + 67210 67264 chr9 140273252 - 22551031 22551085 6094817
+54
+
+chain 1389 chrUn_gl000219 179198 + 66392 68784 chr1 247249719 + 65797848 65800245 3034140
+29 2307 2312
+56
+
+chain 1366 chrUn_gl000219 179198 + 20143 20198 chr4 191273063 - 69480908 69480963 5880463
+55
+
+chain 1339 chrUn_gl000219 179198 + 162175 162202 chr1 247249719 - 74777177 74777204 3339890
+27
+
+chain 1337 chrUn_gl000219 179198 + 68329 68386 chr10 135374737 - 97276986 97277043 13905473
+57
+
+chain 1334 chrUn_gl000219 179198 + 39950 39978 chr8 146274826 - 60735711 60735739 964260
+28
+
+chain 1215 chrUn_gl000219 179198 + 19784 19836 chr1 247249719 - 212757024 212757076 9451024
+52
+
+chain 1204 chrUn_gl000219 179198 + 9400 9453 chr2 242951149 - 221538709 221538762 17248558
+53
+
+chain 1196 chrUn_gl000219 179198 + 65543 65596 chrX 154913754 - 74732188 74732241 11122165
+53
+
+chain 1136 chrUn_gl000219 179198 + 160693 160717 chr2 242951149 + 96004141 96004165 19597584
+24
+
+chain 1088 chrUn_gl000219 179198 + 19507 19558 chr9 140273252 + 124212712 124212763 4480835
+51
+
+chain 1079 chrUn_gl000219 179198 + 37482 37507 chr4 191273063 - 92702671 92702696 10491706
+25
+
+chain 1063 chrUn_gl000219 179198 + 6670 6734 chr3 199501827 + 6965033 6965097 10403549
+64
+
+chain 1052 chrUn_gl000219 179198 + 19721 19774 chr1 247249719 + 112545490 112545543 7413376
+53
+
+chain 1038 chrUn_gl000219 179198 + 160800 160824 chrX 154913754 + 84200659 84200683 17773754
+24
+
+chain 979 chrUn_gl000219 179198 + 67437 67498 chr12 132349534 + 127544420 127544481 8975114
+61
+
+chain 882 chrUn_gl000219 179198 + 68888 68940 chr2 242951149 + 41597257 41597309 8629613
+52
+
+chain 862 chrUn_gl000219 179198 + 34692 34749 chr7 158821424 + 91057493 91057550 3914497
+57
+
+chain 862 chrUn_gl000219 179198 + 19258 19321 chr17 78774742 + 11706793 11706856 10608405
+63
+
+chain 836 chrUn_gl000219 179198 + 6404 6488 chrX_random 1719168 - 557556 557640 15714908
+84
+
+chain 826 chrUn_gl000219 179198 + 6064 6121 chr4 191273063 + 114632432 114632489 6389008
+57
+
+chain 786 chrUn_gl000219 179198 + 19327 19383 chr4 191273063 + 95451114 95451170 8391346
+56
+
+chain 781 chrUn_gl000219 179198 + 66882 66938 chr15 100338915 + 35480475 35480531 9740616
+56
+
+chain 780 chrUn_gl000219 179198 + 5491 5548 chr19 63811651 + 45237769 45237826 8205599
+57
+
+chain 773 chrUn_gl000219 179198 + 18906 18956 chr5 180857866 - 161656026 161656076 5757214
+50
+
+chain 756 chrUn_gl000219 179198 + 5561 5620 chr8 146274826 - 76452822 76452881 8679584
+59
+
+chain 744 chrUn_gl000219 179198 + 8892 8945 chr18 76117153 + 27187323 27187376 6534410
+53
+
+chain 702 chrUn_gl000219 179198 + 67866 67921 chr11 134452384 - 45331858 45331913 4032419
+55
+
+chain 658 chrUn_gl000219 179198 + 65665 65726 chr11 134452384 - 71401302 71401363 8693276
+61
+
+chain 610 chrUn_gl000219 179198 + 68611 68641 chr6 170899992 - 104159480 104159510 6224934
+30
+
+chain 600 chrUn_gl000219 179198 + 34306 34379 chr9 140273252 + 67999140 67999213 8057147
+73
+
+chain 566 chrUn_gl000219 179198 + 68393 68455 chr13 114142980 + 104410587 104410649 8663433
+62
+
+chain 556 chrUn_gl000219 179198 + 66682 66718 chr4 191273063 - 23557773 23557809 3204114
+36
+
+chain 543 chrUn_gl000219 179198 + 66718 66743 chr4 191273063 + 67612053 67612078 7944900
+25
+
+chain 543 chrUn_gl000219 179198 + 8373 8450 chr1 247249719 - 76782344 76782421 23880934
+77
+
+chain 532 chrUn_gl000219 179198 + 6121 6161 chr13 114142980 - 84408205 84408245 7620044
+40
+
+chain 531 chrUn_gl000219 179198 + 66743 66797 chr3 199501827 - 142542844 142542898 11924432
+54
+
+chain 522 chrUn_gl000219 179198 + 7996 8024 chr12 132349534 + 73188186 73188214 12754595
+28
+
+chain 500 chrUn_gl000219 179198 + 67110 67168 chr5 180857866 + 134363242 134363300 15867098
+58
+
+chain 485 chrUn_gl000219 179198 + 69293 69355 chr1 247249719 + 99641891 99641953 7463394
+62
+
+chain 483 chrUn_gl000219 179198 + 66186 66217 chrX 154913754 - 138658729 138658760 7191935
+31
+
+chain 477 chrUn_gl000219 179198 + 19687 19721 chr7 158821424 + 45385787 45385821 16982489
+34
+
+chain 474 chrUn_gl000219 179198 + 8598 8650 chrX 154913754 - 113360025 113360077 16003052
+52
+
+chain 421 chrUn_gl000219 179198 + 65449 65511 chr1 247249719 + 187704570 187704632 12170451
+62
+
+chain 402 chrUn_gl000219 179198 + 8487 8537 chr8 146274826 - 79772642 79772692 15615542
+50
+
+chain 400 chrUn_gl000219 179198 + 67611 67640 chr1 247249719 - 149721975 149722004 3673241
+29
+
+chain 357 chrUn_gl000219 179198 + 8945 8990 chr3 199501827 - 164258935 164258980 15296887
+45
+
+chain 325 chrUn_gl000219 179198 + 66571 66608 chr6 170899992 - 28562683 28562720 10433787
+37
+
+chain 267 chrUn_gl000219 179198 + 66437 66493 chr8 146274826 + 91475861 91475917 20384527
+56
+
+chain 259 chrUn_gl000219 179198 + 68682 68710 chr11 134452384 - 28278838 28278866 23153636
+28
+
+chain 207038 chrUn_gl000220 161802 + 151486 153627 chr21_random 1679693 - 0 2145 573346
+1058 0 1
+394 0 4
+106 1 0
+582
+
+chain 207038 chrUn_gl000220 161802 + 107514 109655 chr21_random 1679693 - 0 2145 573347
+1058 0 1
+394 0 4
+106 1 0
+582
+
+chain 69503 chrUn_gl000220 161802 + 67389 69230 chr2 242951149 + 25799043 25800417 1810371
+218 1 1
+72 2 2
+113 1024 551
+85 19 19
+226 0 6
+81
+
+chain 31351 chrUn_gl000220 161802 + 117547 117875 chr1 247249719 - 155624021 155624349 4397311
+328
+
+chain 29427 chrUn_gl000220 161802 + 67361 68249 chr1 247249719 - 87588997 87589612 2331939
+28 406 406
+54 1 1
+64 273 0
+62
+
+chain 27049 chrUn_gl000220 161802 + 161519 161802 chr1 247249719 - 155624021 155624304 6035035
+283
+
+chain 25088 chrUn_gl000220 161802 + 36919 37185 chr1 247249719 - 45093231 45093497 6989949
+266
+
+chain 24729 chrUn_gl000220 161802 + 117030 117449 chrX 154913754 + 108184031 108184449 7237839
+197 142 141
+80
+
+chain 20499 chrUn_gl000220 161802 + 65633 66956 chr8 146274826 - 2314439 2315749 10054888
+157 1045 1032
+53 13 13
+55
+
+chain 20386 chrUn_gl000220 161802 + 75253 75471 chr11 134452384 + 26865999 26866217 10139728
+218
+
+chain 17914 chrUn_gl000220 161802 + 106337 107514 chr20 62435964 - 36297925 36299106 11745937
+55 875 884
+91 103 98
+53
+
+chain 17680 chrUn_gl000220 161802 + 84353 85836 chr15 100338915 + 87980076 87981560 12400789
+131 384 386
+57 861 860
+50
+
+chain 16118 chrUn_gl000220 161802 + 159904 160089 chr5 180857866 + 71182513 71182698 13920446
+124 8 8
+53
+
+chain 16118 chrUn_gl000220 161802 + 115932 116117 chr5 180857866 + 71182513 71182698 13920447
+124 8 8
+53
+
+chain 15578 chrUn_gl000220 161802 + 85289 85786 chr10 135374737 - 97997712 97998207 12517238
+97 354 352
+46
+
+chain 14161 chrUn_gl000220 161802 + 154326 154474 chr12 132349534 + 20595624 20595772 16008128
+148
+
+chain 14161 chrUn_gl000220 161802 + 110354 110502 chr12 132349534 + 20595624 20595772 16008129
+148
+
+chain 13476 chrUn_gl000220 161802 + 149534 149686 chr1 247249719 + 154452993 154453145 16852628
+91 5 5
+56
+
+chain 13476 chrUn_gl000220 161802 + 105562 105714 chr1 247249719 + 154452993 154453145 16852629
+91 5 5
+56
+
+chain 13074 chrUn_gl000220 161802 + 75664 75872 chr5 180857866 + 148307676 148307883 12475568
+65 80 79
+63
+
+chain 12291 chrUn_gl000220 161802 + 109957 110143 chr2 242951149 - 110221779 110221963 18542579
+61 44 42
+81
+
+chain 11141 chrUn_gl000220 161802 + 65790 65916 chr6 170899992 - 125538722 125538849 11778575
+19 0 1
+11 1 1
+95
+
+chain 11117 chrUn_gl000220 161802 + 113673 113902 chr11 134452384 + 84872723 84872926 20519201
+78 99 73
+52
+
+chain 10468 chrUn_gl000220 161802 + 30468 30675 chr1 247249719 + 43344900 43345108 21782937
+53 83 84
+71
+
+chain 10467 chrUn_gl000220 161802 + 122720 122828 chr16 88827254 - 74338770 74338878 21787089
+108
+
+chain 10454 chrUn_gl000220 161802 + 159242 159370 chr19 63811651 + 40758345 40758473 21809803
+64 8 8
+56
+
+chain 10022 chrUn_gl000220 161802 + 109687 109957 chr16 88827254 + 33870609 33870877 21321955
+66 160 158
+44
+
+chain 9617 chrUn_gl000220 161802 + 65083 65225 chr6 170899992 - 64517981 64518123 23713679
+59 28 28
+55
+
+chain 9067 chrUn_gl000220 161802 + 65995 66091 chr5 180857866 - 61890711 61890807 15044279
+96
+
+chain 8090 chrUn_gl000220 161802 + 66643 66751 chrX 154913754 + 93027353 93027460 18331310
+57 8 8
+30 1 0
+12
+
+chain 7895 chrUn_gl000220 161802 + 83808 83891 chr8 146274826 - 74499810 74499893 26574027
+83
+
+chain 7508 chrUn_gl000220 161802 + 130266 131540 chr16 88827254 + 33860661 33862774 27224265
+76 1140 1979
+58
+
+chain 6793 chrUn_gl000220 161802 + 85386 85459 chr4 191273063 - 132701421 132701494 16466620
+73
+
+chain 6622 chrUn_gl000220 161802 + 69230 69303 chr7 158821424 + 72850229 72850302 6119994
+73
+
+chain 6240 chrUn_gl000220 161802 + 117008 117283 chr8 146274826 - 75509656 75509931 8997966
+22 197 197
+56
+
+chain 6018 chrUn_gl000220 161802 + 66770 66835 chr7 158821424 + 124008505 124008570 12829512
+65
+
+chain 5720 chrUn_gl000220 161802 + 75185 75250 chr19 63811651 + 15679634 15679699 12473683
+65
+
+chain 4703 chrUn_gl000220 161802 + 23204 23254 chr5 180857866 + 95719433 95719483 34557350
+50
+
+chain 4701 chrUn_gl000220 161802 + 84689 84759 chr7 158821424 - 101943693 101943763 18053161
+10 42 42
+18
+
+chain 4653 chrUn_gl000220 161802 + 75476 75531 chr2 242951149 + 164831342 164831397 18833276
+55
+
+chain 4071 chrUn_gl000220 161802 + 75577 75664 chr7 158821424 + 127724988 127725075 11086017
+87
+
+chain 3907 chrUn_gl000220 161802 + 84699 84740 chr8 146274826 - 59752347 59752388 23243247
+41
+
+chain 3445 chrUn_gl000220 161802 + 84526 84576 chr7 158821424 - 54802302 54802352 16133139
+50
+
+chain 3298 chrUn_gl000220 161802 + 84484 84519 chr4 191273063 + 150269733 150269768 14985224
+35
+
+chain 3145 chrUn_gl000220 161802 + 68319 68372 chr3 199501827 - 131923719 131923772 22478960
+53
+
+chain 2432 chrUn_gl000220 161802 + 68042 68092 chrX 154913754 - 83094892 83094942 21808406
+50
+
+chain 2258 chrUn_gl000220 161802 + 85510 85565 chr1 247249719 - 82513050 82513105 16301029
+55
+
+chain 1955 chrUn_gl000220 161802 + 67950 68004 chr10 135374737 - 36348792 36348846 20124747
+54
+
+chain 1529 chrUn_gl000220 161802 + 84950 85016 chr15 100338915 + 47627030 47627096 15111622
+66
+
+chain 994 chrUn_gl000220 161802 + 68645 68697 chr6 170899992 - 81185693 81185745 23384366
+52
+
+chain 895 chrUn_gl000220 161802 + 75776 75809 chrX 154913754 - 34420755 34420788 14557377
+33
+
+chain 866 chrUn_gl000220 161802 + 65932 65995 chr12 132349534 - 68316854 68316917 13749883
+63
+
+chain 724 chrUn_gl000220 161802 + 83556 83614 chrX 154913754 - 81676829 81676887 19557019
+58
+
+chain 624 chrUn_gl000220 161802 + 83438 83493 chr11 134452384 + 91542956 91543011 19738951
+55
+
+chain 591 chrUn_gl000220 161802 + 84637 84689 chr12 132349534 - 49421504 49421556 13261533
+52
+
+chain 561 chrUn_gl000220 161802 + 84759 84817 chr6_random 1875562 - 1459651 1459709 15884202
+58
+
+chain 14216718 chrUn_gl000221 155397 + 0 155355 chr1 247249719 + 141752984 141907993 211
+623 1 1
+49 1 1
+619 1 1
+34 1 1
+307 1 1
+31 1 1
+1912 1 1
+41 1 1
+994 1 1
+23 1 1
+1203 0 1
+1157 57 60
+181 1 1
+26 1 1
+643 1 2
+61 1 1
+43 1 1
+300 6 6
+241 11 11
+1194 8 8
+173 1 1
+31 1 1
+1099 13 13
+321 0 3
+456 23 24
+402 1 1
+28 1 1
+533 0 3
+476 2 0
+870 1 1
+47 1 1
+1339 4 4
+25 1 1
+474 0 1
+869 34 34
+615 1 1
+18 1 1
+1449 1 1
+47 1 1
+60 11 11
+465 8 8
+54 6 0
+164 11 11
+546 15 15
+172 1 0
+1686 0 1
+987 1 1
+38 1 1
+2146 1 1
+29 1 1
+645 1 1
+19 1 1
+804 10 10
+2676 0 1
+430 1 1
+48 1 1
+1099 1 1
+39 1 1
+127 0 1
+450 0 1
+22 1 1
+1754 1 1
+38 1 1
+152 3 0
+1066 1 1
+41 1 1
+3598 1 1
+17 1 1
+363 4 4
+63 504 9
+154 1 1
+15 1 1
+574 1 1
+43 1 1
+515 1 1
+31 1 1
+99 0 8
+378 1 1
+25 1 1
+477 1 1
+19 1 1
+466 1 1
+70 5 5
+79 1 1
+108 1 1
+210 1 1
+156 1 1
+265 7 7
+64 1 1
+98 1 1
+114 1 1
+39 1 1
+363 5 5
+28 1 1
+2637 1 1
+35 1 1
+702 1 1
+15 1 1
+122 30 30
+60 20 19
+194 1 1
+44 1 1
+1196 4 3
+141 1 1
+49 1 1
+274 2 0
+235 3 0
+152 9 9
+258 1 1
+34 1 0
+45 1 1
+370 1 1
+27 1 1
+235 10 0
+378 1 1
+17 1 0
+4 7 4
+437 15 16
+291 12 12
+101 1 1
+29 0 1
+219 0 1
+90 0 1
+164 1 1
+35 1 0
+916 1 1
+44 1 1
+54 29 25
+111 1 1
+31 1 1
+199 2 0
+360 2 0
+533 7 7
+281 14 14
+1751 1 1
+16 1 1
+136 1 0
+513 1 0
+216 2 0
+694 1 1
+30 1 1
+136 1 1
+34 1 1
+640 1 0
+17 1 0
+910 5 5
+36 4 4
+1047 1 1
+91 1 1
+1268 1 1
+49 4 4
+2141 1 1
+78 1 1
+309 1 1
+19 1 1
+116 1 1
+51 1 1
+282 4 4
+626 14 14
+2635 2 2
+37 1 1
+1324 1 1
+111 1 1
+332 1 1
+40 1 1
+1585 0 1
+1044 0 1
+456 1 1
+56 1 1
+733 0 37
+398 1 1
+24 1 1
+941 0 1
+533 1 1
+46 1 1
+425 1 1
+29 1 1
+209 1 1
+656 14 14
+2193 0 1
+340 0 1
+1318 1 1
+29 1 1
+734 13 0
+736 2 0
+395 0 1
+543 1 0
+449 2 0
+2005 1 1
+29 1 1
+748 0 1
+1298 1 1
+18 1 1
+1823 1 1
+26 1 1
+735 16 16
+1067 1 1
+20 1 1
+205 1 1
+36 1 1
+1358 0 1
+938 1 1
+87 1 1
+1100 1 1
+30 1 0
+2470 0 16
+317 10 0
+1289 5 5
+78 1 1
+1424 0 2
+656 2 2
+32 2 1
+223 0 1
+71 1 1
+289 1 0
+15 1 1
+104 1 1
+147 0 2
+15 1 1
+187 1 1
+50 1 1
+56 1 1
+31 3 3
+103 1 1
+130 1 1
+58 10 76
+99 3 3
+352 1 1
+72 1 1
+49 1 1
+105 1 1
+71 2 2
+120 1 1
+152 1 1
+87 15 84
+27 1 0
+5 1 1
+779 1 1
+42 1 1
+351 1 1
+45 1 1
+74 1 1
+46 1 1
+583 9 9
+3745 27 27
+500 0 2
+56 8 0
+105 4 4
+54 3 3
+39 1 1
+111 5 5
+2408 0 3
+1986 0 1
+4003 1 1
+38 1 1
+2084 1 1
+88 1 1
+1007 10 0
+1048 0 1
+180 6 6
+1628 0 1
+1953 1 0
+1428 1 1
+44 1 1
+475 11 11
+551 0 3
+702 2 1
+137 0 6
+829 6 6
+1463 1 1
+30 1 1
+155 1 1
+23 1 1
+1026 7 7
+987 1 1
+48 1 1
+94 1 1
+45 1 1
+706 1 1
+28 1 1
+1055 1 1
+26 1 1
+71 1 1
+53 1 1
+2245 1 1
+22 1 1
+328 1 1
+16 1 1
+1264 1 1
+33 1 1
+247 0 1
+2369 11 11
+105 11 11
+665 0 1
+27 1 1
+379 4 0
+1936 4 3
+441 1 1
+28 1 1
+736 0 5
+248 1 1
+55 1 1
+853 1 0
+415 1 1
+63 2 0
+7 1 2
+49 1 1
+324 1 1
+25 1 1
+2107 0 4
+431 9 9
+204 1 1
+25 1 1
+93 1 1
+46 1 1
+425 1 0
+321 12 12
+266
+
+chain 55879 chrUn_gl000221 155397 + 39022 155397 chr21_random 1679693 - 1044434 1160777 269
+504 7942 7889
+30 63609 63627
+27 44221 44224
+42
+
+chain 7421 chrUn_gl000221 155397 + 7003 17005 chr1 247249719 + 142211716 142221729 942
+52 9916 9927
+34
+
+chain 17470138 chrUn_gl000222 186861 + 0 186861 chr3 199501827 - 123616420 123803195 161
+1250 0 4
+3271 1 1
+48 1 1
+748 1 1
+29 1 1
+336 0 1
+397 14 15
+315 1 1
+47 1 1
+76 1 1
+49 1 1
+1417 5 0
+399 2 1
+112 1 1
+20 1 1
+667 0 3
+1357 1 1
+24 1 1
+409 1 0
+9 1 1
+173 0 1
+36 1 1
+1372 1 0
+369 9 10
+484 0 4
+411 21 25
+242 1 0
+833 14 14
+895 0 9
+1067 0 3
+87 1 1
+33 1 1
+52 1 1
+35 1 1
+564 3 2
+80 9 9
+77 3 0
+126 120 0
+626 1 1
+84 0 5
+30 1 1
+337 0 8
+384 1 1
+30 0 1
+153 0 1
+16 1 1
+52 6 0
+185 1 2
+111 4 4
+54 1 1
+29 1 1
+479 1 0
+23 1 1
+1089 1 1
+21 1 1
+194 1 1
+20 1 0
+1217 0 1
+728 1 0
+497 120 0
+130 1 1
+45 1 1
+364 0 3
+2459 4 4
+883 5 4
+785 14 14
+1180 5 0
+420 1 1
+39 0 4
+13 1 1
+60 16 16
+592 11 14
+246 0 1
+520 1 1
+19 1 1
+843 1 1
+33 1 1
+462 0 9
+24 1 1
+661 3 0
+22 1 1
+1102 6 6
+2016 1 0
+106 1 1
+40 0 1
+2177 1 1
+39 1 1
+806 0 4
+412 1 0
+317 0 2
+775 0 4
+289 1 1
+22 1 1
+920 1 1
+72 0 5
+58 1 1
+345 1 1
+22 1 1
+302 2 2
+84 1 1
+210 8 8
+98 3 1
+673 1 1
+33 1 1
+299 4 0
+1477 4 4
+475 1 1
+46 1 1
+369 13 13
+60 1 1
+37 1 1
+260 1 0
+274 6 0
+1598 1 1
+28 1 1
+2138 16 16
+793 1 0
+142 1 1
+18 1 0
+1920 0 1
+164 6 0
+859 1 1
+49 1 0
+333 2 0
+1437 1 1
+32 1 1
+243 4 5
+719 0 1
+39 1 1
+861 1 1
+41 1 1
+812 1 1
+46 9 8
+145 1 1
+50 1 1
+552 2 2
+27 0 3
+477 1 1
+41 1 1
+307 1 1
+67 1 1
+283 1 1
+27 1 1
+151 0 1
+21 1 1
+128 1 0
+42 1 1
+415 0 110
+781 2 2
+44 1 1
+176 2 2
+21 1 1
+181 4 0
+440 47 47
+326 1 1
+27 1 1
+228 1 1
+36 1 1
+138 12 12
+3038 11 11
+3781 0 1
+1856 0 58
+1813 1 0
+3776 21 0
+1096 8 0
+9578 0 4
+924 0 1
+662 1 0
+942 1 0
+1709 8 8
+167 1 0
+6850 0 6
+58 1 1
+5315 1 1
+22 1 1
+2377 1 0
+3702 1 1
+17 1 1
+1405 1 0
+38 3 0
+10654 0 1
+35 1 1
+3464 0 1
+424 12 12
+6848 13 13
+444 0 5
+1121 0 10
+3015 11 10
+5936 1 1
+45 1 1
+134 1 1
+33 1 1
+913 1 1
+33 1 1
+7377 1 1
+26 1 1
+2213 3 0
+1310 19 16
+1028 1 1
+30 1 1
+1346 0 1
+3453 23 23
+2511 0 2
+2170 1 0
+5294 16 17
+1031 0 1
+5779 30 0
+4540
+
+chain 4695 chrUn_gl000222 186861 + 24563 24635 chr3 199501827 - 123640889 123640961 14387967
+72
+
+chain 1361 chrUn_gl000222 186861 + 182291 182321 chr3 199501827 - 123798570 123798600 19416990
+30
+
+chain 17090000 chrUn_gl000223 180455 + 8 180455 chr12 132349534 - 156807 337156 167
+1699 1 0
+921 0 1
+476 0 3
+2781 5 0
+2337 0 4
+2044 1 1
+52 1 1
+99 4 0
+3342 10 10
+76207 0 1
+61652 112 0
+5333 2 15
+2060 0 1
+6964 2 2
+29 1 1
+4046 1 1
+74 0 2
+1140 1 1
+45 1 0
+610 2 0
+5062 1 0
+917 0 3
+2412
+
+chain 149624 chrUn_gl000224 179693 + 16452 19204 chr21_random 1679693 - 927993 930745 862809
+59 44 44
+122 26 26
+66 78 78
+132 53 53
+52 89 89
+402 80 80
+70 427 427
+293 109 109
+159 56 56
+159 73 73
+203
+
+chain 136876 chrUn_gl000224 179693 + 10143 12844 chr21_random 1679693 - 927993 930694 942020
+59 44 44
+122 243 243
+59 53 53
+52 89 89
+402 291 291
+56 138 138
+69 23 23
+293 109 109
+159 56 56
+159 73 73
+152
+
+chain 125386 chrUn_gl000224 179693 + 4608 7033 chr4 191273063 - 142060444 142063015 1025800
+181 62 62
+67 290 436
+77 128 128
+226 170 170
+58 50 50
+165 20 20
+83 29 29
+137 31 31
+189 59 59
+173 72 72
+64 43 43
+51
+
+chain 115319 chrUn_gl000224 179693 + 12844 15391 chr1 247249719 - 105124090 105126655 1054758
+4 101 101
+115 120 120
+83 6 6
+88 7 7
+90 138 143
+213 56 56
+54 27 27
+110 76 76
+135 22 22
+85 408 408
+51 98 112
+51 71 70
+151 97 97
+90
+
+chain 114018 chrUn_gl000224 179693 + 0 2892 chr4 191273063 - 142260101 142263001 1123540
+55 9 9
+211 93 93
+53 8 8
+62 480 490
+69 30 30
+169 1 0
+59 374 374
+170 104 104
+66 127 127
+67 134 134
+53 28 28
+127 117 117
+109 4 4
+55 1 0
+57
+
+chain 36836 chrUn_gl000224 179693 + 6824 7667 chr1 247249719 - 105124398 105125248 1790194
+51 165 165
+90 136 143
+213 56 56
+54 27 27
+51
+
+chain 33992 chrUn_gl000224 179693 + 112940 113352 chrX 154913754 - 88823320 88823732 3977820
+120 1 1
+31 1 1
+187 19 19
+53
+
+chain 18992 chrUn_gl000224 179693 + 17725 19327 chr4 191273063 - 142245973 142247284 981259
+45 153 153
+54 736 445
+17 9 9
+9 181 181
+60 269 269
+69
+
+chain 18703 chrUn_gl000224 179693 + 36684 37079 chr4 191273063 - 141982606 141983001 11515138
+60 182 182
+153
+
+chain 18089 chrUn_gl000224 179693 + 111527 111723 chr9 140273252 - 128738409 128738605 12039465
+196
+
+chain 15842 chrUn_gl000224 179693 + 43681 43852 chr5 180857866 + 121997129 121997300 14188216
+171
+
+chain 14214 chrUn_gl000224 179693 + 491 737 chr4 191273063 - 142062769 142063015 3040816
+16 72 72
+64 43 43
+51
+
+chain 12738 chrUn_gl000224 179693 + 10425 11345 chr1 247249719 + 142120275 142121196 1008989
+81 89 89
+16 667 668
+67
+
+chain 12408 chrUn_gl000224 179693 + 111770 111902 chr13 114142980 + 92814175 92814307 18368674
+132
+
+chain 11212 chrUn_gl000224 179693 + 19478 19617 chr21_random 1679693 + 1399634 1399773 20347362
+79 8 8
+52
+
+chain 11202 chrUn_gl000224 179693 + 112010 112131 chr2 242951149 - 63390730 63390851 20364580
+121
+
+chain 10961 chrUn_gl000224 179693 + 113403 113519 chr15 100338915 + 33416357 33416473 20796127
+116
+
+chain 10599 chrUn_gl000224 179693 + 45499 45614 chr4 191273063 - 16476018 16476133 21505928
+115
+
+chain 10461 chrUn_gl000224 179693 + 5286 5406 chr4 191273063 - 142252631 142253042 21797237
+48 0 291
+72
+
+chain 9625 chrUn_gl000224 179693 + 45086 45377 chr7 158821424 + 147179139 147179431 23689916
+56 173 174
+62
+
+chain 8966 chrUn_gl000224 179693 + 43852 44339 chr6 170899992 - 123605243 123606037 22200679
+5 424 731
+58
+
+chain 8686 chrUn_gl000224 179693 + 150637 150728 chr17_random 2617613 - 2481086 2481177 25413154
+91
+
+chain 8418 chrUn_gl000224 179693 + 113901 114092 chr1 247249719 + 51102379 51102577 12937085
+62 97 104
+32
+
+chain 7836 chrUn_gl000224 179693 + 113729 114060 chr15 100338915 + 29700006 29700343 12648008
+52 182 188
+97
+
+chain 7180 chrUn_gl000224 179693 + 111450 111527 chr20 62435964 + 7228195 7228272 16795381
+77
+
+chain 6302 chrUn_gl000224 179693 + 16769 18129 chr1 247249719 + 142120310 142121524 963429
+46 1235 1089
+79
+
+chain 6103 chrUn_gl000224 179693 + 42952 43016 chr3 199501827 - 123620077 123620141 30294157
+64
+
+chain 5895 chrUn_gl000224 179693 + 2013 2591 chr1 247249719 - 105125890 105126468 2699632
+97 439 439
+42
+
+chain 5875 chrUn_gl000224 179693 + 112823 112897 chr5 180857866 + 101476275 101476349 19139195
+74
+
+chain 5761 chrUn_gl000224 179693 + 112501 112575 chr5 180857866 - 18785409 18785483 18767594
+74
+
+chain 5594 chrUn_gl000224 179693 + 14410 14469 chr2 242951149 + 132757818 132757877 31664825
+59
+
+chain 5426 chrUn_gl000224 179693 + 112319 112377 chrX 154913754 + 51601613 51601671 20663092
+58
+
+chain 5157 chrUn_gl000224 179693 + 36781 36835 chr3 199501827 - 123619604 123619658 33003364
+54
+
+chain 4848 chrUn_gl000224 179693 + 38244 38295 chr17_random 2617613 - 2478551 2478602 33999646
+51
+
+chain 4029 chrUn_gl000224 179693 + 112591 112679 chr5 180857866 + 175637665 175637753 5293308
+88
+
+chain 3738 chrUn_gl000224 179693 + 13809 15505 chr21_random 1679693 + 746889 748597 1305848
+56 1588 1600
+52
+
+chain 3444 chrUn_gl000224 179693 + 17845 17922 chr4 191273063 - 142061190 142061267 1001031
+77
+
+chain 2897 chrUn_gl000224 179693 + 17977 18049 chr4 191273063 - 142253123 142253195 6314050
+72
+
+chain 2788 chrUn_gl000224 179693 + 7479 7535 chr21_random 1679693 + 746889 746945 1938894
+56
+
+chain 2567 chrUn_gl000224 179693 + 112204 112294 chr11 134452384 - 41661604 41661694 17596092
+90
+
+chain 2514 chrUn_gl000224 179693 + 112910 112940 chr7 158821424 - 149074801 149074831 4457011
+30
+
+chain 2362 chrUn_gl000224 179693 + 112294 112319 chr6 170899992 + 161846864 161846889 20635445
+25
+
+chain 2067 chrUn_gl000224 179693 + 113791 113854 chr10 135374737 - 12705669 12705732 4536722
+63
+
+chain 2066 chrUn_gl000224 179693 + 12137 18504 chr4 191273063 + 48989335 49001828 975845
+58 6251 12377
+58
+
+chain 1330 chrUn_gl000224 179693 + 113854 113878 chr5 180857866 - 104048317 104048341 15104584
+24
+
+chain 1281 chrUn_gl000224 179693 + 13065 13119 chr2 242951149 + 132762412 132762466 24130660
+54
+
+chain 1137 chrUn_gl000224 179693 + 4993 5088 chr21_random 1679693 - 929171 929266 9927235
+95
+
+chain 848 chrUn_gl000224 179693 + 1580 1641 chr19 63811651 - 14200495 14200556 15170632
+61
+
+chain 531 chrUn_gl000224 179693 + 111324 111398 chrX 154913754 + 45796753 45796827 23841494
+74
+
+chain 30238 chrUn_gl000225 211173 + 3384 6975 chr18 76117153 - 76016439 76019286 4615508
+88 182 182
+34 2463 1785
+83 385 319
+50 111 111
+195
+
+chain 23455 chrUn_gl000225 211173 + 60973 61217 chr12 132349534 - 101518303 101518547 8018503
+244
+
+chain 20111 chrUn_gl000225 211173 + 166962 167202 chrY 57772954 - 350039 350279 10363809
+137 15 15
+88
+
+chain 18512 chrUn_gl000225 211173 + 25429 25744 chrY 57772954 - 45830615 45830930 11677619
+72 105 105
+138
+
+chain 17348 chrUn_gl000225 211173 + 69995 70696 chr18 76117153 + 100273 101110 12705104
+54 377 445
+95 106 174
+69
+
+chain 16827 chrUn_gl000225 211173 + 145466 146389 chr12 132349534 - 82104353 82105276 13209656
+90 95 95
+78 609 609
+51
+
+chain 16532 chrUn_gl000225 211173 + 6975 7480 chrY 57772954 + 11929182 11929688 9693145
+6 195 195
+56 193 194
+55
+
+chain 14751 chrUn_gl000225 211173 + 146689 146847 chr12 132349534 + 39722955 39723113 15337789
+158
+
+chain 14284 chrUn_gl000225 211173 + 109330 111760 chrY 57772954 + 11933408 11933865 15870073
+76 260 260
+66 1973 0
+55
+
+chain 14255 chrUn_gl000225 211173 + 98785 99342 chr18 76117153 + 100216 100772 15900410
+38 387 386
+132
+
+chain 13725 chrUn_gl000225 211173 + 126918 127062 chr18 76117153 + 100627 100771 16530918
+144
+
+chain 13602 chrUn_gl000225 211173 + 147672 147817 chr8 146274826 + 107672556 107672701 16687743
+145
+
+chain 12515 chrUn_gl000225 211173 + 44909 48118 chrY 57772954 + 11932705 11933485 18215669
+61 2725 295
+67 280 281
+76
+
+chain 11840 chrUn_gl000225 211173 + 21194 21753 chrY 57772954 - 366515 367006 19262147
+78 414 346
+67
+
+chain 11658 chrUn_gl000225 211173 + 205576 205759 chr2 242951149 - 95682635 95682818 19568742
+65 47 47
+71
+
+chain 11142 chrUn_gl000225 211173 + 75498 75615 chrY 57772954 - 45851825 45851942 20475254
+117
+
+chain 10869 chrUn_gl000225 211173 + 51801 51915 chr18 76117153 - 76020289 76020403 20977270
+114
+
+chain 10758 chrUn_gl000225 211173 + 209713 209913 chr4 191273063 + 39081959 39082160 21190890
+74 74 75
+52
+
+chain 10616 chrUn_gl000225 211173 + 146389 146556 chr5 180857866 - 159454687 159454854 16369709
+43 58 58
+66
+
+chain 10035 chrUn_gl000225 211173 + 171673 171813 chr8 146274826 - 67038436 67038576 22726539
+51 22 22
+67
+
+chain 9917 chrUn_gl000225 211173 + 144822 145109 chr5 180857866 + 8336803 8337089 22999312
+67 165 164
+55
+
+chain 9896 chrUn_gl000225 211173 + 62060 62164 chr18 76117153 + 100627 100731 23055661
+104
+
+chain 9807 chrUn_gl000225 211173 + 137863 140640 chrY 57772954 - 45826954 45827260 23254439
+47 2048 0
+54 576 153
+52
+
+chain 8932 chrUn_gl000225 211173 + 69636 69730 chrY 57772954 - 45829605 45829699 25046033
+94
+
+chain 8413 chrUn_gl000225 211173 + 85100 85188 chrY 57772954 - 45832076 45832164 25801593
+88
+
+chain 8359 chrUn_gl000225 211173 + 142638 142726 chrY 57772954 + 57394412 57394500 25874101
+88
+
+chain 8122 chrUn_gl000225 211173 + 119411 119496 chr18 76117153 + 100254 100339 26237196
+85
+
+chain 8086 chrUn_gl000225 211173 + 55593 55678 chr18 76117153 - 76016415 76016500 26288572
+85
+
+chain 7431 chrUn_gl000225 211173 + 23911 23989 chrY 57772954 - 45832097 45832175 27364689
+78
+
+chain 7085 chrUn_gl000225 211173 + 97023 98440 chrY 57772954 - 45830811 45832294 28041027
+71 1296 1362
+50
+
+chain 7083 chrUn_gl000225 211173 + 18039 19438 chrY 57772954 - 366566 367008 28041757
+40 1295 338
+64
+
+chain 6978 chrUn_gl000225 211173 + 146217 146291 chr8 146274826 - 115673008 115673082 20162064
+74
+
+chain 6840 chrUn_gl000225 211173 + 144371 144443 chr18 76117153 + 100407 100479 28513456
+72
+
+chain 6667 chrUn_gl000225 211173 + 66486 66556 chrY 57772954 - 45828773 45828843 28907810
+70
+
+chain 6303 chrUn_gl000225 211173 + 137 203 chrY 57772954 - 45847922 45847988 29790939
+66
+
+chain 6276 chrUn_gl000225 211173 + 106597 106663 chr18 76117153 - 76016724 76016790 29833436
+66
+
+chain 6212 chrUn_gl000225 211173 + 69391 69456 chrY 57772954 - 45832092 45832157 30018585
+65
+
+chain 6148 chrUn_gl000225 211173 + 11132 11196 chrY 57772954 + 11939704 11939768 30172463
+64
+
+chain 6094 chrUn_gl000225 211173 + 68190 68254 chrY 57772954 + 57406356 57406420 30311205
+64
+
+chain 6058 chrUn_gl000225 211173 + 127450 127514 chrY 57772954 - 45844945 45845009 30402909
+64
+
+chain 6003 chrUn_gl000225 211173 + 143303 143366 chrY 57772954 + 57402115 57402178 30561429
+63
+
+chain 5903 chrUn_gl000225 211173 + 139264 139326 chrY 57772954 - 45844705 45844767 30818028
+62
+
+chain 5884 chrUn_gl000225 211173 + 104096 104157 chr18 76117153 + 102216 102277 30859822
+61
+
+chain 5803 chrUn_gl000225 211173 + 103301 103362 chr18 76117153 + 99316 99377 31083648
+61
+
+chain 5794 chrUn_gl000225 211173 + 26451 26512 chrY 57772954 - 45851626 45851687 31099284
+61
+
+chain 5721 chrUn_gl000225 211173 + 139049 139109 chrY 57772954 + 57400659 57400719 31317119
+60
+
+chain 5684 chrUn_gl000225 211173 + 146628 146689 chr1 247249719 - 54812307 54812368 16334743
+61
+
+chain 5630 chrUn_gl000225 211173 + 92437 92496 chr18 76117153 + 98445 98504 31574579
+59
+
+chain 5539 chrUn_gl000225 211173 + 140791 140849 chrY 57772954 + 57392905 57392963 31849395
+58
+
+chain 5539 chrUn_gl000225 211173 + 4266 4324 chrY 57772954 + 11928245 11928303 31849396
+58
+
+chain 5521 chrUn_gl000225 211173 + 40432 40490 chrY 57772954 - 370968 371026 31891738
+58
+
+chain 5438 chrUn_gl000225 211173 + 36214 36270 chrY 57772954 + 11930450 11930506 32145366
+56
+
+chain 5339 chrUn_gl000225 211173 + 74478 74534 chrY 57772954 - 45832726 45832782 32420219
+56
+
+chain 5339 chrUn_gl000225 211173 + 28866 28922 chrY 57772954 - 45832726 45832782 32420220
+56
+
+chain 5321 chrUn_gl000225 211173 + 77215 77271 chrY 57772954 - 45830350 45830406 32462996
+56
+
+chain 5248 chrUn_gl000225 211173 + 101556 101611 chrY 57772954 - 45844698 45844753 32703748
+55
+
+chain 5182 chrUn_gl000225 211173 + 145986 146041 chr9 140273252 + 120936021 120936076 15500236
+55
+
+chain 5139 chrUn_gl000225 211173 + 133143 133197 chrY 57772954 - 45844651 45844705 33042666
+54
+
+chain 5074 chrUn_gl000225 211173 + 44289 44341 chr18 76117153 - 76014945 76014997 33275500
+52
+
+chain 5048 chrUn_gl000225 211173 + 121427 121480 chrY 57772954 - 45831892 45831945 33345462
+53
+
+chain 5048 chrUn_gl000225 211173 + 133955 134008 chr18 76117153 + 100319 100372 33345768
+53
+
+chain 4966 chrUn_gl000225 211173 + 41802 41854 chr18 76117153 - 76019839 76019891 33630431
+52
+
+chain 4957 chrUn_gl000225 211173 + 75225 75277 chrY 57772954 + 57406623 57406675 33650989
+52
+
+chain 4953 chrUn_gl000225 211173 + 145598 145651 chr12 132349534 + 53460575 53460628 18762227
+53
+
+chain 4857 chrUn_gl000225 211173 + 102498 102549 chrY 57772954 - 45844483 45844534 33969906
+51
+
+chain 4802 chrUn_gl000225 211173 + 22297 22347 chr18 76117153 - 76019708 76019758 34221217
+50
+
+chain 4766 chrUn_gl000225 211173 + 81781 81831 chrY 57772954 - 45844484 45844534 34318861
+50
+
+chain 4730 chrUn_gl000225 211173 + 116183 116233 chrY 57772954 - 45830882 45830932 34441464
+50
+
+chain 4684 chrUn_gl000225 211173 + 16126 16175 chr18 76117153 - 76016743 76016792 34599346
+49
+
+chain 4593 chrUn_gl000225 211173 + 106022 106070 chrY 57772954 + 11933099 11933147 34665488
+48
+
+chain 4475 chrUn_gl000225 211173 + 6365 6412 chrY 57772954 - 366519 366566 34731069
+47
+
+chain 4436 chrUn_gl000225 211173 + 146291 146338 chr11 134452384 + 56488704 56488751 17449786
+47
+
+chain 3836 chrUn_gl000225 211173 + 145834 145884 chr5 180857866 + 144814068 144814118 22871561
+50
+
+chain 3811 chrUn_gl000225 211173 + 55287 55327 chrY 57772954 + 11933059 11933099 35041388
+40
+
+chain 3584 chrUn_gl000225 211173 + 145220 145258 chrX 154913754 - 118330483 118330521 21778509
+38
+
+chain 3107 chrUn_gl000225 211173 + 145429 145466 chr16 88827254 + 32289765 32289802 21377803
+37
+
+chain 3086 chrUn_gl000225 211173 + 145167 145986 chr10 135374737 + 122669077 122669897 13514114
+53 666 667
+100
+
+chain 2556 chrUn_gl000225 211173 + 117483 117510 chrY 57772954 - 45844918 45844945 35420092
+27
+
+chain 2529 chrUn_gl000225 211173 + 147645 147672 chr9 140273252 + 21053713 21053740 22333825
+27
+
+chain 2173 chrUn_gl000225 211173 + 146432 146455 chrX 154913754 - 151862289 151862312 20635516
+23
+
+chain 1176 chrUn_gl000225 211173 + 24983 25041 chrY 57772954 + 57406385 57406443 21696161
+58
+
+chain 970 chrUn_gl000225 211173 + 65774 66239 chr10 135374737 - 23380 24256 23288653
+57 372 783
+36
+
+chain 296 chrUn_gl000225 211173 + 124568 124644 chr18 76117153 + 100627 100703 23494333
+76
+
+chain 11961323 chrUn_gl000227 128374 + 0 128374 chr6 170899992 + 19668 147274 264
+1643 0 1
+255 1 1
+40 1 0
+61 4 4
+343 1 1
+168 1 1
+211 1 1
+18 1 1
+525 0 4
+549 1 1
+22 1 1
+440 16 16
+122 14 17
+167 4 4
+205 4 0
+98 1 1
+164 8 9
+585 0 1
+1278 1 1
+26 1 1
+2038 1 1
+17 1 1
+1741 15 15
+917 1 1
+26 1 1
+1021 0 1
+1314 77 0
+306 0 1
+109 0 153
+152 79 2
+199 153 0
+146 1 1
+49 1 1
+144 385 0
+4558 1 0
+5544 4 3
+2373 1 1
+40 1 0
+14638 6 0
+5386 0 1
+1491 2 0
+1835 20 20
+1481 0 4
+5348 0 1
+135 0 2
+2128 35 35
+4707 0 1
+1696 0 1
+893 1 1
+47 1 1
+766 1 1
+49 1 1
+542 1 1
+28 2 0
+334 1 1
+31 1 1
+1092 0 1
+803 1 0
+1815 6 0
+25 134 0
+37 79 0
+7668 1 0
+603 1 1
+28 1 1
+1020 0 1
+3033 0 2
+619 7 7
+1434 1 0
+1954 1 0
+9909 1 0
+1155 1 1
+36 1 1
+327 7 7
+133 4 0
+1499 0 2
+96 1 0
+3257 11 0
+46 1 1
+207 1 1
+20 1 1
+2919 18 18
+765 4 4
+1829 0 1
+1864 5 5
+123 15 15
+13751
+
+chain 49410 chrUn_gl000227 128374 + 14106 15875 chr8 146274826 + 86449 88144 529
+45 569 417
+43 288 289
+64 1 1
+12 362 363
+150 18 18
+153 1 77
+63
+
+chain 13413 chrUn_gl000227 128374 + 14996 15149 chr19 63811651 + 91181 91257 491
+55 77 0
+21
+
+chain 5337 chrUn_gl000227 128374 + 73853 73996 chr1 247249719 + 231 416 19004415
+27 66 108
+50
+
+chain 5015 chrUn_gl000227 128374 + 14074 14797 chr1 247249719 - 246873620 246874345 559
+32 658 660
+33
+
+chain 2271 chrUn_gl000227 128374 + 73917 73946 chr15 100338915 - 29 58 23118832
+29
+
+chain 8904085 chrUn_gl000228 129120 + 0 98333 chr4 191273063 + 191152836 191248399 371
+1288 1 1
+65 1 1
+695 1 1
+24 1 0
+6 1 1
+50 0 312
+260 1 1
+46 1 1
+993 1 0
+2168 1 1
+31 1 1
+3958 0 4
+257 0 18
+9 1 1
+267 3 3
+16 1 1
+1441 0 4
+68 0 1
+1387 0 2
+3469 11 11
+3245 1 0
+777 1 1
+25 1 1
+597 2 0
+30 1 1
+1792 1 1
+34 1 1
+543 0 1
+98 1 1
+25 1 1
+1024 8 0
+2103 1 1
+1898 0 12
+71 10 11
+1335 0 2
+7908 172 0
+4213 0 1
+4548 43 43
+334 0 1
+381 3 3
+46 1 1
+1201 1 1
+25 0 2
+1296 0 1
+526 4 0
+459 1 1
+56 1 1
+2023 2 2
+35 1 1
+1479 0 142
+2019 0 1
+370 8 8
+1586 1 0
+337 0 1
+921 2 0
+84 1 1
+22 1 0
+8 1 2
+206 0 4
+799 1 1
+18 0 1
+223 0 1
+295 1 70
+43 0 1
+72 68 0
+41 1 1
+90 4 4
+1051 1 1
+32 1 1
+182 7 7
+225 3 3
+22 1 1
+1660 0 1
+357 8 8
+101 13 13
+198 7 7
+412 1 0
+4 0 1
+19 1 0
+137 6 7
+361 0 2
+1716 1 0
+511 0 1
+91 0 1
+954 3024 0
+365 13 13
+1256 1 1
+74 1 1
+256 1 1
+68 1 1
+671 5 0
+144 4 0
+2140 1 1
+44 4 0
+223 1 1
+23 1 1
+716 5 0
+144 4 0
+2080 109 105
+223 70 70
+671 5 0
+144 4 0
+2140 16 16
+982 16 14
+148 4 0
+1095 66 60
+945 50 50
+996 2 0
+148 4 0
+2080 109 105
+964 5 0
+144 4 0
+2106 50 50
+996 2 0
+148 4 0
+2106 50 50
+242
+
+chain 2215952 chrUn_gl000228 129120 + 46991 129120 chr10 135374737 + 135304834 135360693 463
+43 23181 23046
+6 90 90
+334 6 0
+395 27 27
+494 145 149
+426 19 19
+480 1 11
+131 1 1
+19 4 0
+120 1 1
+35 1 1
+289 8247 8248
+26 0 8
+78 17650 1111
+121 3307 1
+35 1 1
+1001 6 0
+395 1 1
+25 1 1
+494 1 1
+26 0 8
+78 4 0
+35 1 1
+426 1 1
+17 1 1
+480 1 11
+131 1 1
+19 4 0
+120 1 1
+35 1 1
+1001 6 0
+395 1 1
+25 1 1
+494 1 1
+26 0 8
+78 4 0
+35 1 1
+426 1 1
+17 1 1
+474 10 9
+128 1 1
+19 4 0
+120 1 1
+35 1 1
+1001 6 0
+395 1 1
+25 1 1
+376 3306 0
+74 1 1
+83 1 1
+60 1 1
+52 1 1
+55 1 1
+32 1 1
+360 1 1
+88 1 1
+180 27 27
+1282 2251 0
+30 545 0
+105 1 1
+46 136 0
+1176 1 1
+47 18 0
+18 18 0
+55 18 0
+793 1 1
+28 1 1
+581 1 0
+4074 2 1
+2446
+
+chain 254528 chrUn_gl000228 129120 + 88123 111265 chr4 191273063 + 191234920 191248107 1604
+34 10176 3552
+754 2 0
+148 124 120
+1960 109 105
+964 5 0
+144 4 0
+121 8453 5141
+144
+
+chain 164891 chrUn_gl000228 129120 + 101397 114404 chr4 191273063 + 191238264 191247940 1939
+33 9885 6560
+996 2 0
+148 4 0
+1939
+
+chain 40159 chrUn_gl000228 129120 + 70221 91512 chr4 191273063 + 191223665 191244890 1141
+90 735 735
+27 570 570
+69 10105 10070
+70 5225 5207
+66 4225 4212
+26 50 50
+33
+
+chain 6229 chrUn_gl000228 129120 + 38164 38230 chr4 191273063 + 191191215 191191281 15369017
+66
+
+chain 5671 chrUn_gl000228 129120 + 71567 71627 chr4 191273063 + 191228308 191228368 1250
+60
+
+chain 3930 chrUn_gl000228 129120 + 118712 119504 chr18 76117153 - 76020078 76020393 13741639
+85 601 124
+106
+
+chain 1375 chrUn_gl000228 129120 + 91429 91463 chr4 191273063 + 191234920 191234954 1972
+34
+
+chain 1278 chrUn_gl000228 129120 + 101321 101347 chr4 191273063 + 191244781 191244807 2333
+26
+
+chain 1170 chrUn_gl000228 129120 + 94735 94769 chr4 191273063 + 191234920 191234954 2163
+34
+
+chain 1124 chrUn_gl000228 129120 + 98041 98075 chr4 191273063 + 191234920 191234954 26578
+34
+
+chain 919 chrUn_gl000228 129120 + 101347 101381 chr4 191273063 + 191234920 191234954 6339
+34
+
+chain 827 chrUn_gl000228 129120 + 111265 111299 chr4 191273063 + 191234920 191234954 87434
+34
+
+chain 12702 chrUn_gl000229 19913 + 412 548 chrX 154913754 - 39233529 39233665 17935142
+136
+
+chain 5098 chrUn_gl000229 19913 + 301 375 chr7 158821424 - 9920014 9920088 18279747
+74
+
+chain 15401 chrUn_gl000230 43691 + 29842 30067 chr20 62435964 - 41024366 41024591 14643913
+125 46 46
+54
+
+chain 12153 chrUn_gl000230 43691 + 28959 29088 chr10 135374737 - 34208037 34208166 18757529
+129
+
+chain 12020 chrUn_gl000230 43691 + 8092 8221 chrX 154913754 - 124835983 124836112 18957002
+129
+
+chain 10060 chrUn_gl000230 43691 + 30261 30455 chr3 199501827 - 88301345 88301539 22679433
+66 74 74
+54
+
+chain 7157 chrUn_gl000230 43691 + 30067 30154 chr2 242951149 + 86047836 86047923 19665405
+3 7 7
+77
+
+chain 24015 chrUn_gl000231 27386 + 4654 6337 chr5 180857866 + 70288528 70290201 7680780
+118 1377 1367
+188
+
+chain 18946 chrUn_gl000231 27386 + 6337 7360 chr5 180857866 - 104048753 104049775 8708063
+12 704 704
+72 144 143
+91
+
+chain 16625 chrUn_gl000231 27386 + 2163 2336 chr10 135374737 - 36902825 36902998 13411217
+173
+
+chain 16014 chrUn_gl000231 27386 + 5036 5206 chrX 154913754 + 20633055 20633225 14022851
+170
+
+chain 12702 chrUn_gl000231 27386 + 25798 25934 chrX 154913754 - 39233529 39233665 17935131
+136
+
+chain 12391 chrUn_gl000231 27386 + 23126 23294 chr11 134452384 + 50262817 50262985 18392381
+50 25 25
+93
+
+chain 12273 chrUn_gl000231 27386 + 3627 3759 chr1 247249719 - 155709229 155709361 18571004
+132
+
+chain 11334 chrUn_gl000231 27386 + 4172 4292 chr9 140273252 + 21364524 21364644 20124920
+120
+
+chain 10621 chrUn_gl000231 27386 + 8382 8524 chr4 191273063 + 136252211 136252355 21465956
+54 20 22
+68
+
+chain 10028 chrUn_gl000231 27386 + 22560 22688 chr10 135374737 + 99449647 99449775 22748041
+55 11 11
+62
+
+chain 9550 chrUn_gl000231 27386 + 3054 3241 chr11 134452384 + 46467217 46467406 23880867
+57 73 75
+57
+
+chain 9277 chrUn_gl000231 27386 + 7360 7468 chr2 242951149 - 156204992 156205100 12158462
+56 1 1
+51
+
+chain 8841 chrUn_gl000231 27386 + 25683 25776 chr5 180857866 - 144622856 144622949 25181714
+93
+
+chain 6713 chrUn_gl000231 27386 + 4772 4844 chr5 180857866 + 161861178 161861250 12370362
+72
+
+chain 5312 chrUn_gl000231 27386 + 6933 6989 chr2 242951149 + 51579869 51579925 20211932
+56
+
+chain 5053 chrUn_gl000231 27386 + 6349 6408 chr3 199501827 + 110713055 110713114 8874439
+59
+
+chain 3623 chrUn_gl000231 27386 + 5878 5917 chr8 146274826 - 130943147 130943186 24063221
+39
+
+chain 3087 chrUn_gl000231 27386 + 4499 4564 chr5 180857866 - 151976801 151976866 22766591
+65
+
+chain 2462 chrUn_gl000231 27386 + 23294 23322 chr5 180857866 - 140993746 140993774 21430514
+28
+
+chain 2380 chrUn_gl000231 27386 + 6863 7736 chrX 154913754 + 74323412 74324284 13413701
+70 748 747
+55
+
+chain 1938 chrUn_gl000231 27386 + 6415 7249 chr11 134452384 - 85742217 85743051 12694925
+59 715 715
+60
+
+chain 1209 chrUn_gl000231 27386 + 5917 6017 chr14 106368585 - 47277371 47277471 12257740
+100
+
+chain 575 chrUn_gl000231 27386 + 5818 5878 chr10 135374737 + 22451146 22451206 15305599
+60
+
+chain 354 chrUn_gl000231 27386 + 8607 8658 chr12 132349534 + 50248139 50248190 23666106
+51
+
+chain 55981 chrUn_gl000232 40652 + 2672 3286 chr1 247249719 + 29558771 29559386 2254424
+370 0 4
+68 3 0
+173
+
+chain 30625 chrUn_gl000232 40652 + 2331 2672 chrY 57772954 - 44046862 44047204 2487561
+217 1 1
+106 0 1
+17
+
+chain 14972 chrUn_gl000232 40652 + 34329 34487 chrX 154913754 + 113699598 113699756 15100139
+158
+
+chain 13390 chrUn_gl000232 40652 + 34068 34210 chr20 62435964 + 22916565 22916707 16960157
+142
+
+chain 12645 chrUn_gl000232 40652 + 33771 33906 chr14 106368585 - 63812125 63812260 18020773
+135
+
+chain 10324 chrUn_gl000232 40652 + 33919 34028 chr6 170899992 - 74634926 74635035 22085896
+109
+
+chain 3584 chrUn_gl000232 40652 + 34210 34248 chrX 154913754 - 70416101 70416139 23473516
+38
+
+chain 52638 chrUn_gl000233 45941 + 802 3019 chr12 132349534 + 50244492 50249723 2405861
+98 46 46
+53 1005 4019
+127 111 110
+54 26 26
+50 78 79
+98 98 98
+201 114 114
+58
+
+chain 27263 chrUn_gl000233 45941 + 999 1823 chr10 135374737 - 12704868 12705692 5123253
+41 437 437
+167 94 94
+85
+
+chain 26029 chrUn_gl000233 45941 + 396 699 chr5 180857866 - 24413022 24413325 6500883
+125 1 1
+95 4 4
+78
+
+chain 17811 chrUn_gl000233 45941 + 38826 39439 chr5 180857866 + 131253656 131254277 12283916
+54 333 341
+69 57 57
+100
+
+chain 13316 chrUn_gl000233 45941 + 3397 4215 chr1 247249719 + 164486340 164487158 3912391
+74 253 253
+51 378 378
+62
+
+chain 12153 chrUn_gl000233 45941 + 40193 40322 chr10 135374737 + 101166571 101166700 18757528
+129
+
+chain 10603 chrUn_gl000233 45941 + 723 943 chrX 154913754 - 28357792 28358012 5819450
+79 98 98
+4 1 1
+38
+
+chain 10115 chrUn_gl000233 45941 + 229 336 chr16 88827254 - 77406522 77406629 22552939
+107
+
+chain 10011 chrUn_gl000233 45941 + 39757 39898 chr3 199501827 - 59132119 59132260 22787689
+54 23 23
+64
+
+chain 9607 chrUn_gl000233 45941 + 40007 40142 chr6 170899992 + 77925734 77925869 23736932
+53 22 22
+60
+
+chain 8580 chrUn_gl000233 45941 + 2847 2960 chr3 199501827 + 21585914 21586027 3712717
+12 37 37
+64
+
+chain 8195 chrUn_gl000233 45941 + 1041 1127 chr2 242951149 - 119093538 119093624 26123131
+86
+
+chain 7332 chrUn_gl000233 45941 + 23927 24005 chr21_random 1679693 + 1414162 1414240 27537185
+78
+
+chain 7075 chrUn_gl000233 45941 + 39127 39213 chr2 242951149 - 156903226 156903312 19665406
+77 7 7
+2
+
+chain 6404 chrUn_gl000233 45941 + 24027 24095 chrY 57772954 - 45969314 45969382 29536962
+68
+
+chain 5994 chrUn_gl000233 45941 + 27720 27783 chr21_random 1679693 + 736671 736734 30572390
+63
+
+chain 5521 chrUn_gl000233 45941 + 35462 35520 chr1 247249719 + 141994539 141994597 31891728
+58
+
+chain 5421 chrUn_gl000233 45941 + 28860 28917 chrY 57772954 - 45972382 45972439 32185620
+57
+
+chain 5057 chrUn_gl000233 45941 + 42227 42280 chr21_random 1679693 + 1416441 1416494 33306944
+53
+
+chain 4977 chrUn_gl000233 45941 + 1660 1713 chr4 191273063 + 44000159 44000212 13885847
+53
+
+chain 4794 chrUn_gl000233 45941 + 1831 1882 chr3 199501827 + 28976359 28976410 34225448
+51
+
+chain 4402 chrUn_gl000233 45941 + 1908 1964 chr13 114142980 + 80218714 80218770 15308796
+56
+
+chain 2915 chrUn_gl000233 45941 + 2179 2231 chrX 154913754 - 85677566 85677618 5760053
+52
+
+chain 2427 chrUn_gl000233 45941 + 2296 2322 chr19 63811651 + 22356620 22356646 20880110
+26
+
+chain 2315 chrUn_gl000233 45941 + 3684 3890 chr3 199501827 - 103452931 103453137 5210342
+40 106 106
+60
+
+chain 2208 chrUn_gl000233 45941 + 2131 2646 chr1 247249719 - 90778455 90778971 3568552
+48 399 400
+51 14 14
+3
+
+chain 1953 chrUn_gl000233 45941 + 38960 39031 chr5 180857866 - 170798397 170798468 22477108
+71
+
+chain 1946 chrUn_gl000233 45941 + 39721 39757 chr4 191273063 + 150118550 150118586 24103400
+36
+
+chain 1711 chrUn_gl000233 45941 + 39314 39339 chr20 62435964 + 21411473 21411498 14643912
+25
+
+chain 1675 chrUn_gl000233 45941 + 40142 40172 chr2 242951149 + 189896983 189897013 24596006
+30
+
+chain 1565 chrUn_gl000233 45941 + 363 396 chr12 132349534 + 84953855 84953888 22905876
+33
+
+chain 1086 chrUn_gl000233 45941 + 38662 38716 chr5 180857866 - 112830741 112830795 14413069
+54
+
+chain 921 chrUn_gl000233 45941 + 38880 38926 chr2 242951149 - 186445721 186445767 19984811
+46
+
+chain 665 chrUn_gl000233 45941 + 38435 38508 chr7 158821424 - 45635266 45635339 24997339
+73
+
+chain 567 chrUn_gl000233 45941 + 4533 4589 chr4 191273063 - 120708136 120708192 24665208
+56
+
+chain 30885 chrUn_gl000234 40531 + 20770 21098 chrX 154913754 - 26469860 26470188 4479555
+328
+
+chain 18772 chrUn_gl000234 40531 + 29542 30847 chr2 242951149 + 66700377 66701693 11461281
+64 220 219
+130 836 848
+55
+
+chain 13381 chrUn_gl000234 40531 + 28891 29033 chr18 76117153 - 28506207 28506349 16971585
+142
+
+chain 13011 chrUn_gl000234 40531 + 32848 33004 chr21 46944323 - 3527568 3527724 17471551
+76 8 8
+72
+
+chain 12758 chrUn_gl000234 40531 + 27971 28107 chr9 140273252 + 40275857 40275993 17847477
+136
+
+chain 12298 chrUn_gl000234 40531 + 28202 28332 chr17 78774742 - 28650231 28650361 18533743
+130
+
+chain 9791 chrUn_gl000234 40531 + 31998 32458 chr4 191273063 + 52500251 52500712 23294807
+66 336 337
+58
+
+chain 9445 chrUn_gl000234 40531 + 21230 21331 chr5 180857866 + 160948764 160948865 16866863
+101
+
+chain 9406 chrUn_gl000234 40531 + 8297 8397 chr11 134452384 + 7899462 7899562 24219742
+100
+
+chain 6549 chrUn_gl000234 40531 + 28360 28429 chr3 199501827 - 77716231 77716300 29160148
+69
+
+chain 6432 chrUn_gl000234 40531 + 29956 30025 chr9 140273252 - 130605711 130605780 11645810
+69
+
+chain 5827 chrUn_gl000234 40531 + 29314 29391 chr4 191273063 + 65542826 65542903 22318479
+51 16 16
+10
+
+chain 5276 chrUn_gl000234 40531 + 28653 28709 chr11 134452384 + 42875218 42875274 32641801
+56
+
+chain 4982 chrUn_gl000234 40531 + 30259 30327 chr14 106368585 + 25312855 25312923 19084936
+68
+
+chain 4894 chrUn_gl000234 40531 + 31773 31825 chr12 132349534 + 50249715 50249767 33891551
+52
+
+chain 4820 chrUn_gl000234 40531 + 29245 29296 chr14 106368585 - 60597784 60597835 15880947
+51
+
+chain 4045 chrUn_gl000234 40531 + 29485 29542 chr4 191273063 + 52727852 52727909 20475295
+29 27 27
+1
+
+chain 4004 chrUn_gl000234 40531 + 32772 32822 chr11 134452384 + 25701880 25701930 20350535
+50
+
+chain 3827 chrUn_gl000234 40531 + 28796 28856 chr4 191273063 - 132749043 132749103 24150596
+60
+
+chain 3767 chrUn_gl000234 40531 + 29621 29672 chr4 191273063 + 109408128 109408179 23756830
+51
+
+chain 3326 chrUn_gl000234 40531 + 28132 28194 chr11 134452384 - 79489503 79489565 19687374
+62
+
+chain 3219 chrUn_gl000234 40531 + 21331 21396 chr1 247249719 + 86010808 86010873 5256643
+65
+
+chain 3215 chrUn_gl000234 40531 + 29391 30409 chr8 146274826 + 121721424 121722437 11517523
+94 843 838
+81
+
+chain 2086 chrUn_gl000234 40531 + 20746 20770 chr3 199501827 + 2077213 2077237 10890452
+24
+
+chain 1294 chrUn_gl000234 40531 + 30170 30235 chr5 180857866 + 175635483 175635548 13040504
+65
+
+chain 1179 chrUn_gl000234 40531 + 29160 29245 chr12 132349534 - 94862097 94862182 15299249
+85
+
+chain 30892 chrUn_gl000235 34474 + 10284 10636 chrX 154913754 - 137753964 137754316 4478171
+63 1 1
+187 1 1
+100
+
+chain 28245 chrUn_gl000235 34474 + 6990 7286 chr1 247249719 - 201110718 201111014 5523327
+296
+
+chain 15633 chrUn_gl000235 34474 + 10772 10939 chrX 154913754 + 111228690 111228857 14403755
+167
+
+chain 15123 chrUn_gl000235 34474 + 11327 11488 chr2 242951149 - 221981770 221981931 14935235
+161
+
+chain 15020 chrUn_gl000235 34474 + 8981 9146 chrX 154913754 + 150122103 150122269 15041806
+50 0 1
+115
+
+chain 14740 chrUn_gl000235 34474 + 10108 10284 chr1 247249719 - 105280685 105280865 6177884
+93 11 15
+68 3 3
+1
+
+chain 14088 chrUn_gl000235 34474 + 24168 24356 chrX 154913754 + 151092975 151093164 16094556
+70 28 29
+90
+
+chain 13398 chrUn_gl000235 34474 + 8127 8288 chr19 63811651 + 57248305 57248465 16951668
+53 1 0
+22 4 4
+81
+
+chain 11780 chrUn_gl000235 34474 + 9511 9636 chr4 191273063 - 168773683 168773808 19365753
+125
+
+chain 11069 chrUn_gl000235 34474 + 356 472 chrY 57772954 - 45847823 45847939 20603157
+116
+
+chain 10033 chrUn_gl000235 34474 + 11631 11737 chr1 247249719 + 193278857 193278963 22733668
+106
+
+chain 9778 chrUn_gl000235 34474 + 9888 9991 chr12 132349534 - 43209673 43209776 23326812
+103
+
+chain 8409 chrUn_gl000235 34474 + 11238 11327 chr2 242951149 - 175961361 175961450 14938980
+89
+
+chain 7852 chrUn_gl000235 34474 + 10013 10108 chr6 170899992 - 132065708 132065803 19855689
+76 7 7
+12
+
+chain 6783 chrUn_gl000235 34474 + 11488 11562 chr6 170899992 - 86591617 86591691 15132212
+74
+
+chain 5385 chrUn_gl000235 34474 + 11562 11620 chr5 180857866 + 115696160 115696218 18047359
+58
+
+chain 2922 chrUn_gl000235 34474 + 11207 11238 chrX 154913754 - 92875478 92875509 23049192
+31
+
+chain 2825 chrUn_gl000235 34474 + 10636 10670 chr12 132349534 - 101871456 101871490 12092770
+34
+
+chain 2162 chrUn_gl000235 34474 + 6967 6990 chr2 242951149 - 129587776 129587799 9249038
+23
+
+chain 1547 chrUn_gl000235 34474 + 7820 7881 chr12 132349534 + 82509454 82509515 19217212
+61
+
+chain 923 chrUn_gl000235 34474 + 7388 7458 chr11 134452384 + 54653442 54653512 19210883
+70
+
+chain 719 chrUn_gl000235 34474 + 8037 8087 chr5 180857866 - 7479901 7479951 22691815
+50
+
+chain 508 chrUn_gl000235 34474 + 9360 9418 chr10 135374737 + 96904139 96904197 25463139
+58
+
+chain 3900762 chrUn_gl000236 41934 + 0 41934 chr22 49691432 + 15341912 15383621 761
+910 1 1
+44 1 1
+601 16 16
+51 24 24
+382 118 108
+316 0 158
+302 1 1
+33 1 1
+1588 1 1
+18 1 1
+15101 0 1
+1338 0 39
+4044 417 7
+5600 2 0
+8329 1 0
+2693
+
+chain 39503 chrUn_gl000236 41934 + 24892 25309 chr22 49691432 + 15365763 15366180 3274701
+417
+
+chain 2040494 chrUn_gl000237 45867 + 12002 45867 chr21 46944323 + 10130092 10164119 1248
+88 1 1
+65 1 1
+74 5 15
+34 1 1
+139 1 1
+26 0 1
+241 1 1
+50 0 1
+91 1 1
+194 1 1
+29 1 1
+59 13 13
+54 1 1
+75 1 1
+89 1 1
+230 1 1
+59 3 3
+74 1 1
+199 1 1
+54 1 1
+488 1 16
+78 1 1
+75 1 1
+151 1 1
+93 1 1
+323 18 18
+327 1 1
+52 1 1
+853 1 1
+54 1 1
+409 1 1
+16 1 1
+42 0 1
+336 1 1
+61 1 1
+326 12 12
+295 1 0
+10 1 1
+201 3 1
+316 1 1
+15 1 1
+121 11 11
+574 1 1
+36 0 1
+40 1 1
+80 9 6
+383 4 0
+81 17 17
+172 0 4
+104 2 0
+542 1 0
+249 1 1
+48 1 1
+357 0 20
+81 0 4
+218 0 4
+46 4 0
+31 7 7
+58 4 0
+53 21 21
+2520 14 16
+343 0 1
+641 1 1
+40 0 1
+106 1 1
+353 0 49
+582 1 1
+108 0 3
+12 15 0
+14 3 18
+64 1 1
+37 1 1
+64 1 1
+27 1 1
+239 6 7
+69 2 4
+61 2 2
+29 3 3
+125 1 1
+20 1 1
+164 1 1
+98 1 1
+76 1 1
+33 1 1
+94 84 66
+45 3 0
+14 0 12
+28 3 0
+7 66 0
+56 12 0
+121 1 1
+139 1 1
+253 5 5
+79 3 0
+227 1 1
+115 1 1
+101 0 1
+116 3 3
+33 5 14
+140 1 1
+61 0 3
+70 0 1
+97 0 13
+150 1 1
+50 1 1
+52 3 3
+116 5 5
+114 1 1
+20 1 1
+94 8 8
+82 3 3
+70 1 1
+62 0 1
+20 1 1
+181 1 1
+122 0 130
+79 1 1
+27 103 0
+63 0 104
+146 52 0
+58 1 1
+74 1 1
+54 0 26
+66 3036 1025
+74 6289 8520
+54 654 456
+65 1 1
+25 1 1
+394 10 10
+48 0 1
+244 1 1
+44 1 1
+103 0 1
+74 1 1
+56 4 4
+94 1 1
+452 1 1
+33 1 1
+158 1 1
+63 1 1
+64 7 12
+33 11 11
+295 2 0
+560 1 1
+45 1 1
+1120 4 0
+97
+
+chain 3720276 chrUn_gl000238 39939 + 0 39939 chr22 49691432 - 34115067 34154863 793
+2039 8 12
+1016 5 5
+4821 1 0
+921 2 1
+890 0 1
+423 0 2
+3925 1 1
+72 1 1
+67 1 1
+148 1 1
+74 167 5
+60 1 1
+50 13 13
+3576 1 1
+54 1 1
+575 1 1
+26 1 1
+165 1 1
+46 1 1
+1550 1 1
+35 1 1
+3673 0 14
+2364 11 11
+568 0 3
+2927 4 0
+4923 1 0
+11 1 1
+988 0 1
+81 4 0
+545 1 1
+20 0 1
+1072 0 2
+750 7 7
+640 0 2
+606
+
+chain 2054582 chrUn_gl000239 33824 + 0 33798 chr21 46944323 + 10136554 10170496 1239
+77 1 1
+15 1 1
+121 11 11
+574 1 1
+36 0 1
+40 1 1
+80 9 6
+383 4 0
+81 17 17
+172 0 4
+104 2 0
+542 1 0
+249 1 1
+48 1 1
+357 0 20
+81 0 4
+218 0 4
+46 4 0
+31 7 7
+58 4 0
+53 21 21
+2520 14 16
+343 0 1
+641 1 1
+40 0 1
+106 1 1
+353 0 49
+582 1 1
+108 0 3
+12 15 0
+14 3 18
+64 1 1
+37 1 1
+64 1 1
+27 1 1
+239 6 7
+69 2 4
+61 2 2
+29 3 3
+125 1 1
+20 1 1
+164 1 1
+98 1 1
+76 1 1
+33 1 1
+94 84 66
+45 3 0
+14 0 12
+28 3 0
+7 66 0
+56 18 0
+121 1 1
+139 1 1
+253 5 5
+79 3 0
+227 1 1
+115 1 1
+101 0 1
+116 3 3
+33 5 14
+140 1 1
+61 0 3
+70 0 1
+97 0 13
+150 1 1
+50 1 1
+52 3 3
+116 5 5
+114 1 1
+20 1 1
+94 8 8
+82 3 3
+70 1 1
+62 0 1
+20 1 1
+181 1 1
+122 0 130
+79 1 1
+27 103 0
+63 0 104
+146 52 0
+58 1 1
+74 1 1
+54 0 26
+66 10199 10221
+394 10 10
+48 0 1
+244 1 1
+44 1 1
+103 0 1
+131 4 4
+94 1 1
+452 1 1
+33 1 1
+158 1 1
+63 1 1
+64 7 12
+33 11 11
+295 2 0
+560 1 1
+45 1 1
+1120 4 0
+137 4 0
+672 0 4
+1808 0 14
+3268 1 0
+571
+
+chain 3684438 chrUn_gl000240 41933 + 27 41933 chr4 191273063 - 142375113 142417352 796
+132 1 1
+44 1 1
+295 1 1
+24 1 1
+488 1 1
+52 1 1
+33 0 48
+279 7 7
+772 1 1
+16 1 1
+244 4 4
+486 0 4
+29 1 1
+375 0 48
+45 1 1
+61 0 48
+516 55 7
+557 1 1
+48 1 1
+61 1 1
+33 1 1
+195 1 1
+32 1 1
+304 1 1
+58 1 1
+428 3 0
+350 1 0
+477 15 12
+413 1 1
+46 1 1
+66 19 19
+257 1 1
+80 1 1
+180 1 1
+18 1 1
+92 1 1
+61 1 1
+80 25 25
+574 1 1
+33 1 1
+124 10 10
+1336 7 7
+113 1 1
+170 1 1
+22 0 4
+173 1 1
+21 1 1
+198 1 0
+62 1 1
+269 10 10
+109 1 3
+136 1 1
+38 1 0
+26 1 1
+514 1 1
+68 0 1
+76 0 1
+712 1 0
+9 0 1
+38 1 1
+53 1 1
+21 1 1
+369 1 0
+243 1 1
+28 1 1
+111 0 5
+186 1 1
+117 1 1
+29 0 5
+343 1 0
+77 1 1
+23 1 1
+69 1 1
+41 1 1
+237 11 11
+518 1 1
+79 1 1
+332 1 1
+70 1 1
+610 1 1
+27 1 1
+86 22 24
+793 1 1
+48 1 1
+80 1 1
+85 1 1
+366 38 38
+1127 1 1
+42 1 1
+607 9 9
+69 0 3
+45 0 1
+77 1 1
+30 5 5
+797 1 1
+49 1 1
+152 14 14
+65 13 13
+79 1 1
+37 1 1
+129 4 4
+192 1 1
+28 1 1
+124 17 17
+518 1 1
+99 1 1
+308 16 16
+70 1 1
+134 1 1
+69 1 1
+34 1 1
+162 1 1
+61 1 1
+405 1 1
+45 2 2
+183 1 1
+60 1 1
+227 4 4
+72 1 1
+190 1 1
+30 1 1
+387 1 1
+37 1 1
+553 1 1
+20 0 1
+58 1 1
+23 1 1
+72 5 4
+27 1 1
+322 0 7
+46 1 1
+83 1 1
+16 1 1
+60 1 1
+204 1 1
+895 8 8
+191 1 1
+44 1 1
+378 86 86
+148 9 9
+123 1 1
+48 1 1
+292 7 7
+106 1 1
+16 1 1
+350 15 15
+66 1 1
+43 1 0
+684 1 1
+74 1 1
+97 1 1
+66 1 1
+144 1 1
+45 1 1
+64 1 1
+24 1 1
+131 0 1
+30 1 1
+104 14 14
+228 1 1
+69 1 1
+247 1 0
+50 1 1
+54 1 1
+26 3 0
+73 2 0
+181 1 1
+18 1 1
+185 6 6
+280 1 0
+435 1 1
+40 0 10
+14 1 1
+52 1 1
+85 2 1
+27 1 1
+625 1 1
+15 1 1
+237 1 1
+26 1 1
+349 0 1
+51 1 1
+488 0 175
+143 36 0
+83 0 74
+38 1 1
+58 1 1
+51 2 2
+57 1 1
+144 1 1
+131 17 17
+487 1 1
+83 1 1
+137 12 12
+419 1 1
+24 1 1
+97 12 12
+64 18 18
+310 1 1
+31 1 1
+186 1 1
+36 1 1
+316 10 11
+301 1 1
+176 1 1
+599 4 0
+63 1 1
+511 11 11
+79 1 1
+44 3 3
+51 1 1
+116 1 1
+146 1 1
+135 2 2
+216 1 0
+21 1 1
+227 1 1
+58 1 1
+883 1 1
+62 1 1
+375 0 1
+366
+
+chain 6945 chrUn_gl000240 41933 + 0 3993 chr4 191273063 + 49288042 49296423 8111
+27 3912 8300
+54
+
+chain 3230 chrUn_gl000240 41933 + 27771 27827 chr3_random 749256 - 628862 628918 7525302
+56
+
+chain 28578 chrUn_gl000241 42152 + 7510 7836 chr10 135374737 - 24528620 24528946 5359884
+111 1 1
+117 1 1
+96
+
+chain 20691 chrUn_gl000241 42152 + 6884 7123 chr10 135374737 + 90379126 90379365 9909152
+113 1 1
+27 1 1
+97
+
+chain 19954 chrUn_gl000241 42152 + 8113 8344 chr11 134452384 + 17008798 17009029 10487677
+119 1 1
+24 1 1
+86
+
+chain 18714 chrUn_gl000241 42152 + 6396 7510 chr11 134452384 - 41660838 41661948 7928017
+55 850 846
+81 125 125
+3
+
+chain 18427 chrUn_gl000241 42152 + 6233 6498 chrX 154913754 + 121132265 121132530 8141535
+145 8 8
+10 55 55
+47
+
+chain 15897 chrUn_gl000241 42152 + 8957 9127 chr13 114142980 - 60623878 60624048 14134116
+170
+
+chain 13800 chrUn_gl000241 42152 + 6632 6782 chr2 242951149 + 123256405 123256555 16436015
+150
+
+chain 7239 chrUn_gl000241 42152 + 7836 7932 chr5 180857866 + 56109789 56109885 15641960
+1 26 26
+69
+
+chain 6771 chrUn_gl000241 42152 + 7140 7224 chr3 199501827 - 172585013 172585097 14071569
+84
+
+chain 4980 chrUn_gl000241 42152 + 6505 6564 chr9 140273252 - 115026189 115026248 16703028
+59
+
+chain 4801 chrUn_gl000241 42152 + 8656 8714 chr6 170899992 + 62873357 62873415 24154704
+58
+
+chain 4757 chrUn_gl000241 42152 + 6569 6626 chr3 199501827 - 23594171 23594228 19385889
+57
+
+chain 3592 chrUn_gl000241 42152 + 6075 6113 chr5 180857866 + 41171487 41171525 22768222
+38
+
+chain 2241 chrUn_gl000241 42152 + 6207 6233 chr5 180857866 - 32390164 32390190 11097341
+26
+
+chain 1486 chrUn_gl000241 42152 + 6113 6164 chr12 132349534 - 4193660 4193711 21729418
+51
+
+chain 1297 chrUn_gl000241 42152 + 6024 6075 chr6 170899992 + 73104104 73104155 18904124
+51
+
+chain 1062 chrUn_gl000241 42152 + 8600 8652 chr11 134452384 - 41655227 41655279 14169249
+52
+
+chain 4122233 chrUn_gl000242 43523 + 0 43523 chr22 49691432 + 23741157 23784637 726
+37 0 1
+501 0 1
+108 3 0
+187 0 1
+1121 1 1
+20 1 1
+1027 1 1
+34 1 1
+52 0 1
+765 0 4
+610 1 1
+19 0 1
+4259 1 0
+1146 31 0
+6060 1 1
+22 1 1
+2400 5 0
+8889 3 0
+179 0 1
+1992 0 1
+1767 16 0
+568 0 2
+178 0 2
+2610 4 0
+1173 1 0
+3097 0 2
+1764 0 6
+1838 2 0
+1027
+
+chain 4053524 chrUn_gl000243 43341 + 0 43341 chr21_random 1679693 + 729451 772721 736
+1181 1 1
+44 1 1
+164 1 1
+68 1 1
+111 1 1
+38 0 1
+6062 1 1
+22 3 3
+1372 1 1
+42 14 0
+910 1 1
+31 1 1
+463 28 28
+3921 1 0
+409 1 0
+1228 13 13
+561 1 1
+22 1 1
+527 4 0
+1153 1 1
+35 1 1
+2127 15 15
+1821 1 0
+407 0 1
+391 0 6
+613 1 1
+28 1 1
+191 36 0
+25 0 2
+13 0 2
+41 9 15
+922 16 16
+114 1 0
+479 29 0
+1850 1 0
+1511 0 3
+355 1 1
+48 1 1
+3880 1 1
+29 1 1
+1605 1 1
+47 1 1
+1485 1 1
+34 1 1
+907 8 8
+532 0 1
+1067 1 0
+1245 1 0
+2731 4 4
+31 3 0
+236
+
+chain 2844 chrUn_gl000243 43341 + 25693 25722 chr22_random 257318 + 139119 139148 22581207
+29
+
+chain 3756669 chrUn_gl000244 39929 + 8 39929 chr22 49691432 - 35197541 35237456 785
+890 0 2
+6963 1 0
+6036 101 101
+1666 0 1
+212 0 5
+237 1 0
+873 1 0
+227 3 0
+42 1 1
+4812 1 1
+36 1 1
+6217 2 0
+192 4 0
+249 1 0
+4665 0 5
+662 30 34
+257 12 12
+841 10 0
+4675
+
+chain 11637 chrUn_gl000244 39929 + 13898 34133 chr14 106368585 + 18813314 18833199 821
+26 1 1
+73 20106 19756
+29
+
+chain 3438216 chrUn_gl000245 36651 + 0 36651 chr1 247249719 - 105352682 105389363 845
+12574 2 0
+842 0 2
+6285 0 1
+6019 0 21
+4218 0 3
+2704 0 4
+81 0 1
+1294 1 1
+47 1 1
+1004 1 1
+21 1 1
+73 16 16
+108 1 1
+32 1 1
+1325
+
+chain 3563345 chrUn_gl000246 38154 + 0 38154 chr22 49691432 - 34033100 34071273 824
+1862 1 1
+45 1 1
+3608 0 3
+107 1 15
+848 1 1
+43 1 0
+337 1 1
+35 1 1
+176 0 2
+91 3 4
+2683 0 1
+1321 18 2
+519 1 1
+27 1 1
+472 1 1
+44 1 1
+2452 0 8
+253 1 1
+21 1 1
+48 8 0
+6372 1 1
+38 1 0
+33 1 1
+777 0 1
+139 0 3
+2402 0 2
+3053 1 1
+46 1 1
+198 4 4
+27 1 1
+1883 0 9
+1592 0 4
+320 0 1
+1542 11 11
+412 12 12
+1421 4 0
+2828
+
+chain 3430032 chrUn_gl000247 36422 + 0 36422 chr1 247249719 + 142267104 142303524 847
+151 8 8
+412 1 0
+642 0 1
+3260 12 12
+7577 0 1
+311 3 0
+2665 4 0
+3223 0 1
+437 0 1
+726 0 2
+340 1 0
+1345 1 0
+1511 0 2
+890 1 1
+29 1 1
+2699 1 1
+41 0 2
+1893 1 1
+49 1 1
+5180 1 0
+296 0 4
+573 1 0
+35 1 1
+1170 4 0
+925
+
+chain 3751823 chrUn_gl000248 39786 + 0 39786 chr22 49691432 + 31380700 31420473 786
+9870 4 0
+430 0 3
+13 1 1
+275 3 3
+48 0 1
+149 0 4
+854 1 0
+15 1 0
+1499 1 0
+3772 2 0
+2363 16 16
+1406 10 10
+813 1 0
+269 0 1
+2137 0 3
+379 0 1
+286 1 0
+504 7 0
+2925 1 0
+41 1 1
+1183 25 25
+1285 0 1
+1290 0 1
+93 5 4
+521 1 0
+239 1 0
+304 1 0
+202 1 0
+774 1 0
+3448 1 1
+29 1 1
+565 1 0
+303 2 0
+1412
+
+chain 3662710 chrUn_gl000249 38502 + 0 38502 chr22 49691432 + 26547108 26585613 801
+1207 1 0
+15053 0 12
+44 8 0
+22189
+
+chain 14267284136 chrX 155270560 + 60000 155260560 chrX 154913754 + 0 154913754 8
+34821 50000 50000
+86563 50000 30000
+766173 50000 50000
+36556 50000 50000
+80121 50000 90000
+754004 50000 100000
+5505644 50000 0
+3064790 50079 0
+26309505 50000 25000
+201176 8 0
+7416 0 2
+53134 8 0
+3073 0 12
+21097 0 2
+60831 2 0
+57728 0 20
+54336 0 1
+31675 0 4
+9987 4 0
+12108 0 4
+11225906 0 2000
+356252 50059 50059
+77342 1 1
+17 1 1
+94 0 3
+266 10 10
+113 1 1
+21 1 1
+5400 0 5
+4996 7 15
+3222 5 1
+6456 1 0
+1476 5 5
+2100 1 1
+40 1 1
+1316 0 1
+2446 1 0
+1555 0 2
+11220 1 0
+2639 1 0
+5190 0 4
+79 8 0
+5086 0 1
+2663 1 0
+9149 7 8
+1851 0 1
+9081 0 1
+7248 25 0
+208 28 0
+25 2 0
+15 83 0
+17 116 4
+2536 0 1
+1394 0 6
+12550 0 42
+822 4 0
+30578 1 0
+3711 4 0
+3637 1 0
+11945 0 1
+20204 0 1
+4172 8 0
+5679 1 0
+23827 0 2
+54817 0 1
+657 0 1
+342931 50000 180000
+2052068 27 1
+5375 2 0
+46 0 2
+6489 0 1
+7175 2 0
+1239 2 0
+4301 0 4
+27254 0 1
+4244 0 2
+717 0 2
+260 0 6
+26075 1 0
+236464 50000 50000
+6136098 3100000 3000000
+13518993 1 0
+449 1 0
+4535 4 0
+755 1 0
+1102 1 0
+24 1 1
+107 2 0
+3470 0 1
+1108 1 0
+4775 1 0
+8628 1 1
+46 1 1
+1072 1 1
+44 1 1
+292 4 5
+9091 4 4
+2218 4 4
+705 5 1
+452 0 1
+332 0 1
+1801 7 1
+3960 1 0
+2007 1 0
+3337 1 0
+2093 1 0
+407 310 0
+6130 1 1
+36 1 1
+1697 1 0
+97 13 0
+7624 1 1
+19 1 1
+3806 24 24
+3103 1 0
+779 7 7
+721 1 1
+43 1 1
+1626 0 1
+6146 0 2
+150 1 1
+47 1 1
+2172 0 2
+398 1 1
+31 1 1
+1334 16 16
+1663 1 1
+18 1 1
+2105 1 0
+9 1 1
+1409 1 1
+33 1 1
+1753 1 0
+408 0 1
+1916 1 0
+1928 0 12
+3800 1 1
+15 1 1
+2921 0 1
+4597 0 2
+486 6 0
+308 24 24
+1056 1 1
+44 1 1
+186 1 1
+46 1 1
+3037 0 1
+2301 0 3
+3876 1 1
+22 1 1
+1724 1 0
+3733 1 0
+627 1 0
+250 0 1
+194 1 1
+26 1 1
+20797 10 10
+2445 0 1
+1733 2 0
+1001 0 12
+4394 9 9
+4052 9 10
+670 1 1
+96 0 6
+26 1269 1568
+28 3 2
+10 1486 1188
+25 6 0
+18 1 1
+62 17 17
+77 1 0
+4949 10 10
+4690 1 0
+7343 0 1
+1248 0 1
+1259 0 1
+1347 4 0
+1532 0 1
+3797 16 16
+807 0 1
+2427 0 1
+48 1 0
+287 0 1
+611353 1 0
+1041 0 6
+371 1 0
+227 1 0
+2806 0 1
+36 1 1
+234 1 1
+23 1 1
+584 0 1
+22241 1 1
+65 1 1
+4605 1 0
+2337 20 0
+2119 1 0
+6170 13 9
+10665 1 0
+14631 0 1
+5359 0 4
+4004 0 1
+3182 0 11
+3897 16 14
+2551 0 1
+1824 0 1
+5274 1 1
+41 1 1
+4309 1 0
+3827 1 0
+4594 1 0
+65 1 1
+1170 1 1
+42 4 4
+214 1 0
+5228 1 0
+553 0 1
+6270 1 1
+12 1 1
+2849 12 13
+156 2 0
+8820 1 1
+41 1 1
+472 1 1
+65 1 0
+8 1 1
+1162 0 1
+565 1 1
+48 1 1
+536 1 2
+766 2 0
+4520 1 0
+1574 0 1
+503 1 0
+2558 1 0
+250061 7 7
+9650 18 18
+3208 1 1
+25 1 0
+744 0 2
+2994 1 1
+33 1 1
+1331 0 1
+87 19 19
+1935 5 0
+7 6 0
+1292 1 1
+35 1 1
+2485 1 1
+35 1 1
+4184 23 23
+13077 8 15
+671 4 0
+428 1 0
+4736 0 1
+3849 1 0
+6745 16 16
+2344 1 1
+41 1 1
+7917 1 0
+3876 1 1
+75 1 1
+1429 7 7
+11933 1 1
+28 1 1
+409 1 0
+11 1 1
+1223 12 12
+5354 1 0
+1255 6 0
+851 1 1
+45 1 1
+144 1 1
+47 5 5
+5929 0 4
+422 1 0
+2949 6 0
+193 1 1
+319 4 4
+3592 33 33
+3115 3 1
+1074 0 1
+2465 1 1
+40 1 1
+640 0 2
+550 1 1
+32 1 1
+4096 1 1
+29 1 1
+949 6 6
+6258 0 1
+3957 0 1
+19608 1 1
+48 1 1
+234 1 0
+16874 11 11
+1018 0 321
+2624 0 1
+4553 3 0
+491 6 0
+7496 1 1
+10 10 0
+76 4 0
+3314 1 1
+32 1 1
+5217 0 1
+3540 0 1
+1254 48 48
+1124 18 0
+3109 8 8
+3248 0 1
+1946 1 1
+48 1 1
+9620 2 0
+31242 50000 20000
+36075685 0 3
+36004 1 1
+27 1 1
+5196 1 0
+293 2 0
+13307 3 0
+2420 0 6
+1863 2 0
+2911 1 0
+3233 0 2
+66 0 1
+2375 0 10
+4894 0 1
+745 0 1
+3897 13 0
+4430 1 1
+48 1 4
+20 2 0
+279 2 0
+33 1 1
+48 0 1
+387 8 8
+692 1 0
+375 0 3
+380 23 23
+1289 1 1
+29 1 1
+12336 331 0
+852 0 4
+48 4 0
+4350 1 1
+59 1 1
+4306 5 0
+129 0 2
+3001 1 0
+1332 5 8
+23273 1 0
+30174 39 27
+337 3 0
+2838 0 1
+1614 9 0
+313 1 0
+82 0 4
+173 1 1
+25 1 1
+4912 39 0
+1863 1 0
+2931 0 1
+3134 3 0
+390880 1 0
+7199 0 1
+305 0 2
+1811 0 2
+5449 3 0
+7443 2 0
+2171 1 1
+27 1 1
+2668 2 0
+2180 1 0
+1170 9 0
+1450 16 16
+3080 0 1
+11157 0 1
+678 1 1
+28 1 1
+698 0 1
+112 0 1
+1831 0 3
+14327 0 2
+2247 3 0
+380 1 1
+28 1 1
+1265 21 19
+7184 2 3
+4225 14 9
+1002 1 0
+3854 0 4
+2535 1 1
+30 1 1
+794 0 1
+25 1 1
+76140 50000 70000
+1432750 0 7772
+681872 50000 20000
+4278742 56347 0
+12021233 1 0
+8 0 1
+1775 0 1
+1468 1 1
+51 14 16
+6 1 0
+6 1 0
+11 5 4
+7 1 0
+4 1 0
+75 2 1
+26 0 1
+16 1 0
+9 1 0
+19 2 0
+22 0 1
+9 1 0
+5 3 1
+14 7 6
+38 0 1
+26 1 1
+62 40 39
+1687 1 0
+54 1 0
+8528 1 0
+2722 1 0
+6240 1 0
+33 1 0
+121285 0 1
+6 1 0
+35 0 1
+1381 1 0
+5368 0 1
+3079 1 0
+10863441 4 0
+1799 1 1
+24 1 1
+334 0 1
+4960 0 17
+1160 1 1
+34 1 1
+6153 0 3
+1346 0 4
+103 0 4
+168 27 27
+2640 12 12
+304 16 0
+719 1 0
+3286 0 1
+10182 9 0
+804 1 1
+28 1 1
+749 1 0
+3387 1 1
+47 1 1
+482 1 0
+455 15 15
+719 1 1
+18 1 1
+2074 1 0
+1349 4 0
+3927 1 1
+18 1 1
+907 1 0
+2972 0 2
+115 1 1
+37 1 1
+4428 0 1
+1120 0 1
+4055 0 5
+2929 0 3
+3590 1 1
+47 1 1
+62 0 1
+947 1 1
+45 1 1
+1639 1 1
+32 1 1
+1076 1 0
+3996 0 4
+686 41 41
+7238 0 1
+1733 0 1
+1451 2 0
+617 0 1
+4375 1 0
+2194 15 16
+349 1 1
+27 1 1
+8237 0 1
+499 1 1
+37 2 2
+968 0 1
+34 1 1
+6337 1 1
+18 1 1
+8162 1 1
+21 0 5
+7668 45 45
+1562 0 1
+6017 5 5
+3872 0 8
+5421 0 1
+532 7 6
+5673 4 0
+1542 0 4
+890 1 3
+2561 0 1
+1692 0 1
+1142 1 1
+32 1 1
+503 1 2
+123 1 1
+75 1 1
+2322 0 1
+201 0 1
+40 3 3
+149 0 3
+1441 1 1
+40 1 1
+159 0 2
+1278 1 1
+33 1 1
+221 1 0
+31 1 1
+161 10 9
+1890 1 0
+132 1 1
+37 1 1
+514 23 17
+1373 0 4
+907 17 17
+714 31 30
+55 1 1
+24 1 1
+1038 0 2
+95 5 1
+1094 1 1
+170 1 1
+844 3 0
+369 1 1
+39 1 1
+650 1 1
+41 1 1
+176 1 1
+10 1 1
+688 0 1
+7637 0 4
+2653 1 1
+26 4 0
+46 1 1
+727 0 8
+2197 1 0
+13466 1 0
+3510 2 0
+2147 1 1
+44 3 0
+1320 11 11
+213 4 0
+102 0 1
+3239 1 0
+1492 0 3
+107 1 1
+35 14 0
+2391 1 1
+39 2 0
+436 0 4
+2271 0 8
+6868 3 0
+7183 1 0
+5104 3 0
+182 0 1
+3131 1 1
+31 0 1
+14 1 1
+59 0 1
+373 1 1
+42 1 1
+235 13 13
+1608 5 0
+152 1 1
+106 1 1
+783 34 34
+1633 1 1
+29 0 3
+821 1 1
+24 1 1
+1178 1 1
+33 1 1
+328 1 1
+27 1 1
+5682 1 0
+11 1 5
+146398 50000 30000
+59809 2 0
+3389 1 1
+37 1 1
+11606 1 0
+1597 1 0
+618 1 1
+47 1 1
+2698 1 0
+826 5 5
+33 2 0
+2560 14 0
+98 3 0
+1287 1 0
+7600 1 0
+9897 8 0
+7157 1 0
+32 1 1
+1698 1 0
+754 0 2
+6787 1 0
+584 2 0
+1107 1 1
+40 1 1
+365 1 1
+35 1 1
+400 8 0
+11443 1 0
+1973 1 0
+497 46 46
+657 1 0
+716 1 1
+25 1 1
+1570 2 0
+433 0 2
+905 2 0
+94 1 1
+28 1 1
+2490 1 1
+16 1 1
+5054 1 9
+2184 2 0
+2955 21 23
+794 0 1
+1563 1 1
+20 1 1
+1627 0 11
+1676 0 2
+1527 1 0
+676 1 1
+29 1 1
+1245 1 1
+34 1 0
+1192 7 0
+27 1 0
+1940 0 1
+3421 2 0
+17 1 1
+774 30 0
+97 6 6
+59 26 12
+840 1 1
+19 1 1
+2036 13 1
+26 14 0
+1114 1 0
+25 1 1
+380 0 16
+160 1 1
+17 1 1
+1151 4 0
+699 0 1
+29 2 0
+409 1 1
+49 1 1
+1240 1 1
+37 3 3
+2248 1 0
+1828 1 0
+1997 5 1
+4640 4 4
+4555 0 2
+149 0 52
+619 2 2
+16 1 1
+83 22 0
+56 57 1
+2531 0 8
+4250 1 1
+15 1 1
+2203 0 4
+1665 0 10
+415 2 0
+395 19 18
+15708 0 1
+161 4 0
+79 14 0
+543 1 1
+42 1 1
+3261 18 18
+139 46 46
+403 1 1
+18 1 1
+5405 1 0
+1104 1 1
+53 1 1
+392 1 1
+55 3 3
+3352 9 0
+692 1 9
+8 4 0
+27 3 97
+39 3 1
+21 3 51
+61 0 2
+8931 1 0
+6692 1 2
+1141 0 2
+196 2 0
+389 1 1
+30 1 1
+949 0 1
+6057 0 3
+4741 1 0
+7689 2 0
+2046 18 18
+215 0 1
+46885 2 0
+24138 2 0
+4037 1 0
+4047693 1 0
+9545 0 2
+11590 4 0
+1698 1 3
+13506 37 37
+5380 4 0
+1806 1 1
+44 1 1
+2581 0 2
+10620 0 1
+3804 0 1
+339 0 2
+476 0 1
+5861 8 5
+109 0 14
+901 1 1
+19 1 1
+45 2 0
+1736 1 0
+6625 2 0
+7812 4 0
+7678 2 0
+5068 4 0
+21 1 0
+4170 0 1
+1671 6 0
+6333 0 16
+902 1 1
+44 1 1
+384 0 6
+23418 2 0
+36 1 1
+8900 0 4
+222 1 1
+49 1 1
+2783 0 1
+2641 0 1
+136 20 20
+1279 0 1
+3924 6 6
+13054 6 0
+8965 23 36
+4094 2 0
+2269 1 0
+13621 16 16
+2621 0 2
+30076 1 1
+49 1 1
+102 1 0
+8824 1 1
+25 1 1
+1730 1 1
+47 1 1
+3339 0 1
+131 0 16
+83 16 0
+89 6 0
+2826 33 33
+3509 1 0
+541 1 0
+6288 0 4
+3814 2 0
+7260 0 1
+806 68 0
+1162 0 1
+2230 1 0
+1109 0 1
+1106 2 0
+12396 0 1
+26207 1 1
+21 1 1
+3541 18 18
+525 0 16
+1326 7 7
+525 0 1
+4198 0 1
+4682 13 13
+890 0 2
+816 0 2
+1961 0 4
+24586 1 1
+19 1 1
+4403 1 0
+1342 1 0
+57 12 11
+2225 1 0
+2011 0 35
+10543 0 1
+9766 6 12
+2489 2 1
+20 1 1
+1541 0 12
+1130 1 1
+34 1 1
+927 0 1
+4003 0 1
+966 1 0
+149 0 1
+844 8 0
+4324 1 1
+25 1 1
+569 7 6
+6361 1 0
+3074 0 1
+1539 3 9
+634 1 1
+39 1 1
+8610 13 12
+760 2 0
+4311 0 6
+3122 0 2
+369 1 0
+9963 10 10
+2191 1 1
+23 1 1
+1060 1 1
+19 1 1
+240 12 12
+1748 1 1
+45 1 1
+1040 1 1
+31 1 1
+7446 1 1
+25 1 1
+8379 7 7
+7325 3 0
+357 0 1
+1313 0 1
+11627 4 0
+5862 1 0
+9750 1 0
+3539 0 16
+5672 13 13
+2885 0 4
+8179 1 0
+753 0 1
+4317 0 2
+1318 1 0
+957 0 1
+825 12 12
+1109 0 16
+3736 17 17
+2236 8 8
+7791 15 185
+149 1 1
+21 2 0
+636 1 1
+22 1 0
+42 1 1
+1634 4 4
+3380 0 3
+979 2 0
+3429 0 1
+7132 0 14
+1733 1 1
+38 0 1
+88 1 0
+630 6 6
+489 5 0
+22 1 0
+94 1 0
+42 0 1
+17 1 0
+27 1 0
+172 1 1
+37 1 1
+191 1 1
+66 1 1
+630 1 0
+261 30 30
+1282 1 0
+16 1 1
+429 1 0
+1588 1 1
+20 1 1
+1416 1 1
+33 1 1
+529 1 0
+25 1 0
+1863 4 0
+1651 1 1
+28 1 1
+11815 1 0
+26 1 0
+19 1 1
+3105 1 0
+700 1 0
+150 1 0
+68 1 0
+1421 6 0
+567 1 0
+14 1 0
+2415 1 0
+41 1 1
+415 1 1
+33 1 1
+4521 1 1
+33 1 1
+307 0 1
+176 0 1
+3790 1 1
+86 1 1
+67 1 1
+65 1 0
+7439 1 1
+18 1 1
+16805 1 0
+1764 0 1
+6984 1 0
+3401 20 0
+156 1 1
+30 1 1
+165 2 0
+1087 0 1
+953 0 1
+483 1 0
+632 0 1
+652 0 1
+8559 0 2
+1871 0 1
+398 0 1
+2219 1 1
+53 1 1
+756 1 1
+66 1 1
+69 1 1
+48 1 1
+63 1 1
+28 0 3
+1057 0 3
+63 3 0
+55 1 1
+74 2 3
+159 3 0
+92 1 1
+29 1 1
+58 0 3
+1210 9 9
+54 1 1
+27 1 1
+1374 2 0
+1775 2 17
+764 14 14
+331 16 16
+2291 4 3
+1687 1 1
+26 1 1
+2469 0 1
+3243 1 0
+3636 1 1
+24 1 1
+615 0 1
+2566 1 0
+275 0 5
+690 0 7
+13139 1 0
+1452 0 4
+214 13 13
+61 124 0
+1381 9 9
+5812 1 1
+24 1 1
+5703 1 0
+3992 14 15
+1462 0 3
+5199 0 2
+1554 2 0
+715 12 10
+1966 2 0
+2808 16 0
+611 1 0
+406 0 18
+737 1 1
+31 1 1
+4372 0 5
+10789 0 1
+2399 0 1
+6750 2 0
+96 48 48
+1219 0 6
+6736 0 2
+4457 4 0
+7867 0 1
+3495 1 2
+6215 12 12
+1357 1 0
+2652 0 1
+1771 1 0
+14207 41609 41616
+18338 46 46
+851 1 0
+9638 1 0
+2994 1 0
+469 1 3
+499 1 0
+12074 13 13
+2807 11 10
+715 2 0
+1627 6 6
+5099 0 1
+488 5 1
+975 2 0
+1730 32 31
+1791 0 5
+8135 38 38
+84 3 3
+18 1 1
+3737 9 9
+1442 13 13
+212 10 0
+7712 1 1
+44 1 1
+6271 0 1
+1316 1 1
+49 1 1
+9052 28 32
+113 2 0
+2813 13 13
+1285 50000 2858
+75638 50000 40000
+1583473 2 0
+1564100 97462 0
+2933461
+
+chain 4369679 chrX 155270560 + 152229637 152277099 chrX 154913754 + 151980294 152116665 696
+7131 26 26
+1319 1 0
+10288 0 88910
+2852 19 19
+3721 0 1
+13270 1 0
+8834
+
+chain 2629454 chrX 155270560 + 120011032 120067379 chrX 154913754 + 119895063 119899921 647
+714 51489 0
+4144
+
+chain 1494650 chrX 155270560 + 148762194 148872193 chrX 154913754 - 6301537 6445444 168
+2899 0 1
+1499 0 1
+3725 0 6
+20333 1 0
+13152 18338 18338
+46 40010 73911
+32 9926 9926
+38
+
+chain 260907 chrX 155270560 + 75365988 75368784 chrX 154913754 - 79628560 79631356 2215
+1269 41 41
+1486
+
+chain 138004 chrX 155270560 + 120011746 120013199 chrX 154913754 + 119920102 119921555 138939
+1453
+
+chain 29712 chrX 155270560 + 112877029 112877338 chr12 132349534 + 121720730 121721039 4776951
+309
+
+chain 29117 chrX 155270560 + 75253866 75254170 chr12 132349534 - 49782819 49783123 5064709
+304
+
+chain 10575 chrX 155270560 + 143182285 143275757 chr2 242951149 - 154930543 155024664 254
+41 49992 50582
+45 43365 43424
+29
+
+chain 3572 chrX 155270560 + 148224541 148224579 chrX 154913754 + 148032219 148032257 5503764
+38
+
+chain 3404 chrX 155270560 + 120013199 120013235 chrX 154913754 + 119931276 119931312 297576
+36
+
+chain 3363 chrX 155270560 + 49293018 49293056 chrX 154913754 + 49218184 49218222 1450
+38
+
+chain 2275 chrX 155270560 + 152236768 152236794 chrX 154913754 - 2913071 2913097 1916
+26
+
+chain 2111 chrX 155270560 + 143122309 143122332 chr17 78774742 - 16413594 16413617 6765736
+23
+
+chain 2063 chrX 155270560 + 148224511 148224541 chrX 154913754 + 148032257 148032287 9904071
+30
+
+chain 1738 chrX 155270560 + 76513595 76513628 chrX_random 1719168 + 711492 711525 75
+33
+
+chain 1275 chrX 155270560 + 148522048 148522077 chr11 134452384 + 59964168 59964197 432609
+29
+
+chain 391 chrX 155270560 + 112955240 112955279 chr3 199501827 - 80088461 80088500 4668596
+20 4 4
+15
+
+chain 2373403023 chrY 59373566 + 10000 28819361 chrY 57772954 + 0 27228749 24
+34821 50000 50000
+86563 50000 30000
+766173 50000 50000
+36556 50000 50000
+80121 50000 90000
+754004 50000 100000
+6846717 50000 50000
+276367 50000 600000
+813231 3000000 500000
+39401 50000 400000
+554624 50000 100000
+535761 0 1
+32919 11 12
+12810 0 5
+18900 1 1
+121 4 5
+230478 0 1
+750 1 1
+22 1 1
+14340 1 1
+43 1 1
+2095 0 1
+14635 0 9
+2781 0 1
+45022 5 6
+7151 0 1
+9344 628 0
+5417479 50006 0
+2175791 50000 0
+1481749 50000 50000
+4867933
+
+chain 46617811 chrY 59373566 + 58819361 59363566 chrY 57772954 + 57228749 57772954 80
+98295 50000 50000
+395910
+
+chain 9624 chrY 59373566 + 14725909 14726162 chrX 154913754 + 99410441 99410697 23695076
+50 136 139
+67
+
diff --git a/public/chainFiles/makeChains.py b/public/chainFiles/makeChains.py
new file mode 100644
index 0000000..114b9a2
--- /dev/null
+++ b/public/chainFiles/makeChains.py
@@ -0,0 +1,50 @@
+#!/bin/tcsh
+import os.path
+import sys
+from optparse import OptionParser
+from itertools import *
+
+def main():
+ global OPTIONS
+ usage = "usage: %prog [options] mode hg19Tohg18.chain"
+ parser = OptionParser(usage=usage)
+
+# parser.add_option("-D", "--delete_while_archiving", dest="reallyDeleteInArchiveMode",
+# action='store_true', default=False,
+# help="if provided, we'll actually delete records when running in archive mode")
+
+ (OPTIONS, args) = parser.parse_args()
+ if len(args) != 1:
+ parser.error("Requires exact 1 chain to analyze")
+
+ hg192hg18 = args[0]
+
+ writeChain(hg192hg18, "b37tohg18.chain", lambda x: hg2b(x, 2))
+ writeChain(hg192hg18, "b37tob36.chain", lambda x: hg2b(hg2b(x, 2), 7))
+
+HG2BCONTIG = dict()
+for c in range(1, 23) + ["X", "Y"]:
+ HG2BCONTIG["chr" + str(c)] = str(c)
+HG2BCONTIG["chrM"] = "MT"
+
+def hg2b(line, pos):
+ parts = line.split()
+ if len(parts) > pos and "chr" in parts[pos]:
+ if parts[pos] in HG2BCONTIG:
+ parts[pos] = HG2BCONTIG[parts[pos]]
+ else:
+ print 'Skipping ', parts[pos]
+ return "\t".join(parts)
+
+def writeChain(inFile, outFile, transform):
+ out = open(outFile, "w")
+ for line in open(inFile):
+ newLine = transform(line)
+ #print 'newline', newLine
+ if newLine != None:
+ out.write(newLine)
+ out.write("\n")
+ out.close()
+
+if __name__ == "__main__":
+ main()
diff --git a/public/doc/Ant_Help.tex b/public/doc/Ant_Help.tex
new file mode 100644
index 0000000..e119843
--- /dev/null
+++ b/public/doc/Ant_Help.tex
@@ -0,0 +1,9 @@
+\begin{description}
+ \item[compile] Compiles all java code in the source tree. Places generated classes in the build directory.
+ \item[dist] Generates jar files, suitable for running via java -jar {YOUR\_JAR}. Places resulting jars in the dist subdirectory.
+ \item[resolve] Resolves third-party dependencies. Downloads all third-party dependencies to the lib directory.
+ \item[javadoc] Generates javadoc for the source tree. Places javadoc in the javadoc directory.
+ \item[clean] Removes artifacts from old compilations / distributions.
+\end{description}
+View all available ant targets by running 'ant -projecthelp' in the directory containing build.xml.
+
diff --git a/public/doc/GATK_Coding_Standards.pdf b/public/doc/GATK_Coding_Standards.pdf
new file mode 100644
index 0000000..81148bd
Binary files /dev/null and b/public/doc/GATK_Coding_Standards.pdf differ
diff --git a/public/doc/GATK_Coding_Standards.tex b/public/doc/GATK_Coding_Standards.tex
new file mode 100644
index 0000000..42b6830
--- /dev/null
+++ b/public/doc/GATK_Coding_Standards.tex
@@ -0,0 +1,288 @@
+\documentclass[9pt]{report}
+\usepackage{fullpage}
+\usepackage{listings}
+\begin{document}
+
+\title{Genome Analysis Toolkit Coding Standards for Java}
+\author{Genome Analysis Software Engineering}
+\date{\today}
+\maketitle
+\tableofcontents
+
+\chapter{Overview}
+
+\section{Credit}
+The majority of text in this document is verbatim from the production informatics coding standard document, produced by Ted Sharpe and the production
+informatics team here at the Broad Institute. They deserve all the credit for the insights in this document, and if you feel so inclined please share statements
+of gratitude with them.
+
+\section{Summary}
+This document is an attempt to describe a brief and minimal set of standards for Java code for use by production informatics projects at the Broad. The goal of the standards is to allow programmers to be innovative and expressive, while allowing their peers a vague hope of maintaining and extending their output. This document describes a set of arbitrary standards for naming and documentation based on industry-standard practices, and a set of �good practices� guidelines intended to imp [...]
+\pagebreak
+\section{Cheat Sheet}
+\begin{table}[htdp]
+\caption{default}
+\begin{center}
+\begin{tabular}{l p{4.5cm} r}
+Type & Style & Example \\ \hline
+Function names & uppercase words, with the first word lowercase & \texttt{convertToParser} \\
+Package names & lowercase, with specific functional encapsulation for each class & \texttt{org.broadinstitute.sting.gatk}\\
+Variable names & uppercase words, with the first word lowercase & \texttt{resetCounter} \\
+Class names & uppercase words representing a noun & \texttt{TraversalEngine} \\
+Interface names & the same as class names, no 'i' before the name & \texttt{GenomeEngine} \\
+Tab length & 4 spaces & \\
+
+\end{tabular}
+\end{center}
+\label{default}
+\end{table}%
+
+
+
+\chapter{Naming}
+Choosing names is among the more arduous tasks in programming. There is constant contention between creativity�finding the mot juste�and following fashion so as to more easily allow names to be guessed; and a tug between being concise�if only to save typing�and being verbose so as to provide greater explicitness. Expending the time necessary to create a really good name conflicts with the programmer�s appropriate desire to get on with the job and get something done.
+Unfortunately, naming has a great impact on the maintainability of the code, and despite its being a somewhat fussy and fusty topic, a few guidelines are appropriate. If the standards document is well crafted it will free the programmer from some of the arbitrary decision-making that, when inconsistent, detracts from the intelligibility of the code, while allowing the programmer to focus on the semantics of the name.
+
+\section{Package Naming}
+Package names should be all lower case, and should begin with: \\ \\
+\texttt{org.broadinstitute.sting}\\ \\
+To this add the product name (e.g., basecaller), and subdivide packages according to functionality below that. Put all classes in a package (to allow for more easily understood dependency trees, and to allow reuse via a CLASSPATH of reasonable length).\\
+
+\lstset{language=Java, caption=Good Package Names, frame=leftline, label=PackageNames,basicstyle=\small}
+\lstset{tabsize=4}
+\begin{lstlisting}
+
+package org.broadinstitute.gatk.tools.walkers.basecalller.basecallerEngine; // Good
+package org.broadinstitute.gatk.tools.walkers.baseCallingStuff; // Bad
+package myBaseCaller; // Unacceptable
+
+\end{lstlisting}
+
+
+\subsection{Good practices} Try to organize packages so that the dependency tree isn�t total spaghetti. Ideally, there should be a hierarchy among the packages so that, for example, the web support classes are in one package, and don�t know anything about database access, and the database access classes are in another package, and don�t know anything about web support. Something that knows about both (a package that supports servlet development, for example) should be in a separate pa [...]
+
+\section{Interface Naming}
+Interfaces require no special naming convention to distinguish them from classes. (See the Class naming conventions below.) The presumption is that most of the types that you are passing around are, in fact, abstract types that don�t lock you into a particular implementation: elaborate decoration of interface names is therefore unnecessary and undesirable. Distinguish the implementation class names instead (since they should be repeated far less often throughout the code than the nam [...]
+\lstset{language=Java, caption=Good Interface Names, frame=leftline, label=InterfaceNames,basicstyle=\small}
+\lstset{tabsize=4}
+\begin{lstlisting}
+
+interface DatabaseBinder // OK
+interface ITagFactory // not as good
+
+\end{lstlisting}
+
+
+Some people like to reserve �able or �ible names for interfaces (e.g., Cloneable, Comparable, or Runnable). This is especially useful for mix-in interfaces, where the interface describes a capability that can be shared among otherwise disparate types of objects. Not all interfaces fall into this pattern, however, and you needn�t be concerned if your interface seems to want to have a noun as its name, rather than forcing it into the verb-able mold.
+\subsection{Good practices}
+ Expending the time necessary to abstract common behavior from a set of related classes is probably the single most important thing you can do to improve the extensibility and adaptability of your code. Use interfaces to describe the common behavior so that you don�t force your clients to use particular implementations.
+In all cases, the methods of the interface describe the complete repertoire of behaviors necessary to be an object of the type named by the interface. So check your name to see if it describes something possessing the interface�s set of behaviors, and check your methods to see if that�s what something by that name should be able to do. Ruthlessly eliminate any inconsistencies.
+
+\section{Class Naming}
+Naming: Use mixed-case names, capitalizing the first character of each word. Avoid overly short, and overly common names, and overly long, verbose names. If there is doubt about whether the components of a name are separate words, use less capitalization rather than more. (E.g, Timezone, not TimeZone. Barcode, not BarCode.) You are aiming to capitalize each concept, not each morpheme. A primary interface name is a good prefix for a class name. A package name is not a good prefix. [...]
+Don�t abbreviate any of the words in a class name. It�s just too hard to remember, and too likely to introduce inconsistency. You may, however, use very common acronyms as if they were a word. For example, StructuredQueryLanguageHelper would be quite ridiculous�SQL is a common acronym, and the class should be called SqlHelper (note the lower case ql).
+Class names must be nouns.
+\lstset{language=Java, caption=Good Class Names, frame=leftline, label=ClassNames,basicstyle=\small}
+\lstset{tabsize=4}
+\begin{lstlisting}
+
+class FormModule // OK
+class SOExecutor // not very good � obscure abbreviations
+class State // not good � too vague, ambiguous, and common
+
+\end{lstlisting}
+
+\subsection{Good practices}
+A class should model a clear concept. If you can�t explain the concept behind a class in a sentence or two, there is probably something wrong. (And if your sentence or two seems to require extensive use of the word �or� you can be certain that you have a problem.)
+
+\section{Field and Variable Naming}
+Use mixed case names, capitalizing the first character of each word except the first. Constants may be all upper case, using underscores to separate words.
+Idiosyncratic abbreviations are acceptable for variable and field names, because their scope is very limited. (This is because you won�t be using any public fields: see below.)
+Public constants should follow the semantic rules already specified for classes: not too short, not too long, no cryptic abbreviations. Remember that your clients will qualify the name of the constant with the class name, so overly common words are not so much of a problem as for class names.
+
+\subsection{Good practices}
+ No non-final public fields. Ever. Period. You know why. (But just to be tediously explicit, we�ll go on a bit about it.) Just when you think you�ve got a totally passive data-bearing object that might just as well be a C-language struct as a Java class, and you reckon you�ll just make its fields public, you�ll figure out that it needs behavior. It needs to be persistent, and has to keep track of whether it�s been dirtied or not. Or it needs a new field that is dependent in some w [...]
+Sacks of data are so boring�objects long to have behavior.
+Note that public members of private, nested classes aren�t really public at all, and so they�re perfectly fine. (This allows you to create struct-like objects for internal use within a class.)
+Be careful about static objects (whether public or private, final or not): they get created when the class is loaded and there is no easy way to handle complex dependencies among them that might require some particular loading order. It�s best to keep them very simple�for example, creating tiny immutable static objects to simulate C++-style enumerations is completely appropriate.
+Experience has shown that distinguishing the names of instance fields, class (i.e., static) fields, and constants from each other and from temporaries (i.e., stack frame variables, whether declared in a local block or passed as arguments) is enormously helpful in quickly comprehending a method: It�s good to know at a glance how the code is affecting the state of the object (instance fields) or of all the objects in the class (class fields) without having to study the entire class to lea [...]
+Overly short variable names, especially one-character names, and names that are common words, or parts of common words, are a problem for programmers who use editors with a limited understanding of Java�s syntax. Using iii as a for-loop index instead of i doesn�t really take much extra time, and it makes it a great deal easier to find all the places where the variable is used.
+\lstset{language=Java, caption=Good Variable Names, frame=leftline, label=VarNames,basicstyle=\small}
+\lstset{tabsize=4}
+\begin{lstlisting}
+
+private static Section gHeader; // class member
+private URL mMyURL; // instance member
+String wfQName; // local � ugly, but who cares?
+for ( int i = 0; i < k; ++i ) // Please, don�t.
+int iii; // Thank you.
+\end{lstlisting}
+
+
+\section{Method Naming}
+Use mixed case names, capitalizing the first character of each word except for the first. The first, uncapitalized word should be a verb. Uncomplicated, local fetchers and modifiers of independent state ought to use get and set as their first word. Getters for boolean values can use is, has, or can instead of get. (Conversely, a method that causes the lights to dim over a several square block area should not be called getFoo. Merely to name it fetchFoo instead appropriately hints th [...]
+It�s especially important that you don�t use obscure abbreviations or leave the vowels out of words in method names: they�re too hard to remember. Common acronyms, treated as if they were words, are fine. It�s quite helpful if the name of the method is pronounceable, and spelled as it�s pronounced.
+\subsection{Good practices}
+Methods that have more lines than can fit on the screen all at once are much harder to understand than those that don�t. Ditto for methods that have numerous lines that must be wrapped due to their length. Some suggest that each method can have at most one looping control structure. That doesn�t always work in practice, but you get the gist.
+Following strict structured programming rules is usually an aid to comprehension. (This might not be true if doing so requires you to use a complicated set of flags to control the flow.) If you feel that a continue, labelled break, or early return is less confusing than the structured alternatives, provide a comment to call attention to the easily overlooked, one- or two-token statement that breaks the rules of structured programming.
+
+\lstset{language=Java, caption=Good Method Names, frame=leftline, label=MethodNames,basicstyle=\small}
+\lstset{tabsize=4}
+\begin{lstlisting}
+
+while ( itr.hasNext() )
+{
+ if ( "foo".equals((String)itr.next()) )
+ {
+ return; // HEY! There�s an early return, here.
+ }
+}
+
+\end{lstlisting}
+
+A method should do one job. And, as stated earlier for classes, you ought to be able to describe that job in a crisp sentence or two. After you�ve done so, type it in as javadoc.
+Take switches and long series of if / else if blocks as a warning sign that polymorphism might have served you better.
+Methods with more than a very few parameters are difficult to use. If you have a method with more than three or four parameters you might consider passing an object instead. If you have more than seven, you definitely need to do something else.
+There is a delicate balance to strike between sanity-checking every argument passed to every method and never testing your inputs at all. Too much checking chews into performance, too little means the code will not be robust. Here are two criteria for achieving a happy medium:
+Arguments that are not used directly by the method, but simply passed through to lower layers need not be checked. Arguments that are used directly by the method ought to be checked, especially if the consequence of not checking them will be something completely uninformative like a NullPointerException. You cannot assume that it will be easy to produce a stack trace to home in on what code is producing the exception, and so the exception�s message must serve that purpose.
+The second criterion is to ask whether the consequences of passing bad arguments will be felt immediately or whether doing so will deploy a delayed-action time bomb. For example, passing a null object that gets saved as a part of the object�s state (even if it�s not used directly within the method that received it) may put a na�ve object into an unstable state that may not reveal itself until much later in the program�s execution. This can be the very devil to debug. Your goal is to m [...]
+
+
+
+\chapter{Layout}
+\section{File Template}
+Begin each file with the following bit of rote material. Just cut and paste it into your IDE so that it becomes the first few lines of every source file:
+\lstset{language=Java, caption=A Good Code Header, frame=leftline, label=Header,basicstyle=\small}
+\lstset{tabsize=4}
+\begin{lstlisting}
+/*
+ * $Id$
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+\end{lstlisting}
+
+\section{Documentation}
+
+All classes must have the following, minimum level of javadoc:
+\lstset{language=Java, caption=Javadoc Class Style, frame=leftline, label=GoodJavadoc,basicstyle=\small}
+\lstset{tabsize=4}
+\begin{lstlisting}
+/**
+ * One crisp, informative sentence or noun phrase that explains
+ * the concept modeled by the class.
+ *
+ * This class is [<em>not</em>] thread safe [because it is immutable].
+ *
+ * @author I. M. Coder
+ * @version $Revision$
+ */
+class CrispConcept
+{
+ public static final String ID = "$Id$";
+\end{lstlisting}
+
+
+You are encouraged to provide as much explanatory material as you feel is helpful following that first, summary sentence. Information on algorithms and other information that will help a client make appropriate use of the class is particularly welcome. (But see Stateful Interfaces, and Rules for Use, below.)
+Tell us whether your class is thread-safe or not. Thread safety due to immutability is particularly well worth mentioning. (It may warn a maintenance programmer off adding the set methods that you apparently forgot to provide.)
+All methods must have the following, minimum level of javadoc:
+\lstset{language=Java, caption=Good Method Javadoc, frame=leftline, label=MethodJavadoc,basicstyle=\small}
+\lstset{tabsize=4}
+\begin{lstlisting}
+/**
+ * One crisp, informative sentence or noun phrase that explains
+ * what the method does.
+ *
+ * @param parm1 Parm1 selects the widget to be frobnicated. Cannot be null.
+ * @param parm2 Parm2 specifies the type of frobnication to apply.
+ * @return The frobnicated widget.
+ * @throws FrobnicationException Thrown if widget isn�t frobnicable.
+ */
+\end{lstlisting}
+For each parameter of reference type, tell us whether the reference may be null.
+\section{Imports}
+There is a balance between trying to maintain lengthy lists of classes imported one-by-one on the one hand, and importing many packages wholesale using an asterisk on the other. It shouldn�t often be a big problem: there are exceptions, but a class that makes use of dozens of other classes may be trying to tell you that it needs some redesign. The suggestion is to import classes explicitly from packages we have written�especially those under active development. Also import explicitly [...]
+\section{Order of Class Members}
+Classes should be laid out consistently. You may put the member fields at either the bottom or the top, but you must not sprinkle them throughout.
+There is an argument that a class ought to be ordered with its public constants and constructors at the very top, its public methods next, and its internal stuff last, since that concentrates at the very top what a programmer needs to know to make use of the class. This isn�t obligatory, but you may wish to give it some consideration.
+Nested classes go at the very bottom, after everything else.
+\section{Make �em Pretty}
+Use four space tabs. Don�t omit braces around single statements. Line things up so that it�s clear what things are on the same level. Give us enough white space to make it pretty.
+
+
+\chapter{Design Considerations}
+If you�re doing things right (and the DoD doesn�t) design isn�t a distinct phase that ends when coding begins. Ideally, you�ll develop a comprehensive, top-down design before you begin coding. This may take more than one napkin. Even so, you�ll face many decisions about implementation details that are not completely specified by the overall design. In other words, it�s inevitable that you�ll be doing design while you code. What follows are some coding standards for you to consider w [...]
+\section{Encapsulation}
+With very rare exception, all fields�both instance members and static members�should be private. Protected and default (i.e., package-scoped) access is like public access, only less so. (Making a change in such a field still requires you to locate and analyze use of the field in indefinitely many files: for public fields you need to look everywhere, for protected fields you need only scan everything that extends you, and for default-access fields, you need only scan everything in the [...]
+Always use the most restrictive permission consistent with the design of your class. Don�t make all of your internal methods protected in the vain hope that someday, some extending class might need to tweak your internal state, and you�ll make it easy.
+Similarly, don�t provide a getter and setter for every piece of your internal state: the goal is to meet the contract of the interfaces you implement, and to hide the details of how you do it. Even the most legitimately passive of objects�the model objects you�ve just hauled out of the relational database�will likely have private, internal state that should not be exposed directly to clients. (Check out all the hidden state in EJB entity beans, for example.)
+\section{Is-A versus Has-A}
+A subclass and its superclass have an Is-A (or specialization-generalization) relationship. A class and a component of that class have a Has-A (or containment) relationship. If you have a crisp, clear idea of what kind of things two classes represent, then simply saying to yourself �Thing A is a (special kind of a) Thing B�, and �Thing A has a Thing B (as one of its parts)�, will often make it clear what the relationship should be: one of the two sentences may sound very odd. �A Dog [...]
+\section{Redundant data}
+If you have only one copy of a given datum, it will be either right or wrong, but it won�t be inconsistent with other data. Guaranteeing consistency is a great deal more complex than guaranteeing accuracy. Checking for and maintaining consistency among multiple copies of a datum often robs you of the efficiency you hoped to gain by the denormalization; not checking for and not maintaining consistency is a very frequent source of hard-to-fix bugs, and weird, unreliable program behavior.
+\section{Exceptions}
+Exceptions handle, well, exceptional conditions. Properly used, they provide a last-gasp attempt to allow a robust program to clean-up and recover from catastrophic situations. Exceptions should not be thrown frequently, certainly not as a part of the normal, expected flow of a program. Do not use them as a nifty hack for implementing non-local transfer of control. (Exceptions are far more expensive than normal returns, so the performance wizards won�t be tempted to do this, anyway. [...]
+RuntimeExceptions are for even more rare, more catastrophic situations from which recovery is unlikely, at best.
+In code which will be called by general clients outside your package, catch and re-throw exceptions from the lower layers of code on which you depend to give a more package-oriented explanation of the bad thing that happened. However, preserve information when you do this: Wrap the original exception in a new exception that supplements rather than replaces the original message. And respond to all flavors of printStackTrace with the nested exception�s stack trace (i.e., delegate these [...]
+Never create exceptions with null messages.
+\section{Recovering External Resources}
+Java frees you from having to worry about memory as a resource. (Well, it reduces the worry, anyway.) Therefore you should have oodles of time left over to make certain that you free other resources when you�re done with them. Two key external resources that you must make certain to release are open streams (which chew up a precious operating system file handle), and database connections (which chew up precious DBMS memory). The only really reliable way to make certain that these res [...]
+Try to avoid designs that require a class to maintain an open stream. One technique is to use an event-driven model to turn the file processing upside down: you can still have a nicely modular and reusable class while processing the file within the scope of a single block by using Listeners.
+\section{Stateful Interfaces and Rules for Use}
+Good interfaces are concise, comprehensive, and orthogonal. Concise means that there are no superfluous operations that don�t seem to fit the underlying abstraction, and that there is one good way of accomplishing a given end, not a variety of ways from which you must choose. Comprehensive means that everything you might need to do in manipulating the object has been provided for. And orthogonal means that each method does something independent, and that any method can be called at an [...]
+Poor interfaces are cluttered with Rules for Use. If you are lucky, these rules are made explicit in documentation: Be sure to call this method before calling that one, but never call this method if you�ve ever called that one, and do, please, remember to call this one when you�re all done. Needless to say, these interfaces are very difficult for clients to use correctly.
+One particularly common form of this blight is the Stateful Interface: the object has a lifecycle, and certain methods are appropriate only when the object is in some particular phase of the lifecycle. For a simple example, read the javadoc for the java.sql.CallableStatement class. It describes how you must call registerOutputParameter before calling execute, how, for maximum portability, you should not call getMoreResults if you have called any of the getOutputParameter methods, and [...]
+If you can�t seem to work out how to avoid Rules for Use on your interfaces, you must at the very least make sure that each method call detects misuse, and throws an appropriate exception or does something other than trash your internal state. Every public method, if it affects object state at all, must transform the object from one valid, consistent state to another valid, consistent state.
+If you need some ego-incentive to motivate you, consider this: Hard-to-use, hard-to-understand, hard-to-maintain code is quickly replaced after you cease to maintain it. What kind of legacy is that?
+Sometimes you can see several distinct patterns of use among the clients of an interface: they might be telling you that you need to re-factor the interface into two separate interfaces.
+\section{Multithreading}
+Making your implementations thread-safe is a enormously complex issue. Unfortunately, almost all of us are doing some work in multi-threaded environments (writing servlets, for example), and it's an issue that we are forced to confront.
+If you haven�t examined the issue for one of the classes you�ve implemented (either because you don�t anticipate its being used in a multi-threaded environment, or because the whole thing makes your brain ache), please provide a javadoc comment for the class indicating that it is not thread-safe. If you�re not sure, it�s not safe!
+Don�t just synchronize every method. Synchronization is far too expensive to use carelessly. (Less so than it used to be, but still expensive. And it doesn�t resolve all multi-threading issues, anyway.)
+One way of beginning to address the issue of thread-safety is to understand what doesn�t need any special thread-safety code, and try to produce as much of that as you can. Here are a couple of quick tips.
+Objects that can be seen only by a single thread are immune from the issue: If the only references to an object are from local variables�that is, if a reference to the object is never stored in an instance or static field�it will be visible only from the thread that creates it.
+Immutable objects are automatically thread-safe. If you can�t change it, you can�t see it in an inconsistent, intermediate state.
+\section{Canonical methods}
+Most simple classes either do or are. In the EJB environment session beans are the do classes, and entity beans are the are classes. In the model-view-controller paradigm, model objects are the are objects, controllers are the do objects, and views are mostly are, but typically also have a little bit of do flavor. So, you see, it does depend on what your definition of is is.
+The point of the distinction is that most of the are classes, those often immutable little bags of independent state, usually need to override equals and hashCode to behave properly. You must implement these basic object operations in each of your passive, data-bearing classes; you may wish (or need) to implement them in the others.
+The ares are typically more useful when Comparable�implementing that interface allows you to put them into sorted Collections�so you ought to consider that next.
+Being Cloneable and Serializable usually come for free (no code to write), so throw those into the mix, too, unless there�s a compelling reason not to. An example of a reason not to might be that you need to maintain uniqueness at a level of abstraction higher than object identity�you don�t want to allow clients to make copies.
+\section{Performance}
+Your overall design�your selection of algorithms and data structures, for example�has a far greater impact on performance than any little hacks you can apply while implementing the code. So design for performance, and implement for clarity.
+Nonetheless, the java compiler that most of us use can use a little help in doing optimization. Don�t expect order-of-magnitude performance gains�you�ll get those by designing away I/O, replacing searches with hashes, etc.�these are percentage point tweaks.
+Move invariant code out of loops. For example, many for loops can calculate their terminating condition once, before the loop starts, rather than at each iteration through the loop.
+\lstset{language=Java, caption=Improvements to loops, frame=leftline, label=loopInprovements,basicstyle=\small}
+\lstset{tabsize=4}
+\begin{lstlisting}
+for ( int iii = 0; iii < str.length(); ++iii ) // bad
+
+int nnn = str.length();
+for ( int iii = 0; iii < nnn; ++iii ) // good
+\end{lstlisting}
+Strength reduction: do a simple calculation to update the value of some variable using the value it has from a previous trip through a loop, rather than from scratch each time.
+\lstset{language=Java, caption=Good looping practices, frame=leftline, label=loopPractices,basicstyle=\small}
+\lstset{tabsize=4}
+\begin{lstlisting}
+for ( int iii = 0; iii < nnn; ++iii ) // bad
+{
+ double val = pow( 2., iii );
+ . . .
+}
+
+double val = 1.;
+for ( int iii = 0; iii < nnn; ++iii ) // good
+{
+ . . .
+ val *= 2.;
+}
+\end{lstlisting}
+Avoid some performance dogs in the SDK: Use the underlying Stream classes rather than Readers when appropriate. Use the newer, non-synchronized collection classes rather than Vector and Hashtable.
+Penalties
+Code that fails to follow these guidelines will be posted around the MIT campus, along with the author�s email address and an urgent request for comments.
+
+\end{document}
\ No newline at end of file
diff --git a/public/doc/README b/public/doc/README
new file mode 100644
index 0000000..e70ced0
--- /dev/null
+++ b/public/doc/README
@@ -0,0 +1,86 @@
+The Genome Analysis Toolkit (GATK)
+Copyright (c) 2009 The Broad Institute
+
+Overview
+--------
+The Genome Analysis Toolkit (GATK) is a structured programming
+framework designed to enable rapid development of efficient and robust
+analysis tools for next-generation DNA sequencers. The GATK solves
+the data management challenge by separating data access patterns from
+analysis algorithms, using the functional programming philosophy of
+Map/Reduce. Consequently, the GATK is structured into data traversals
+and data walkers that interact through a programming contract in which
+the traversal provides a series of units of data to the walker, and
+the walker consumes each datum to generate an output for each datum.
+Because many tools to analyze next-generation sequencing data access
+the data in a very similar way, the GATK can provide a small but
+nearly comprehensive set of traversal types that satisfying the data
+access needs of the majority of analysis tools. For example,
+traversals "by each sequencer read" and "by every read covering
+each locus in a genome" are common throughout many tools such as
+counting reads, building base quality histograms, reporting average
+coverage of the genome, and calling SNPs. The small number of these
+traversals, shared among many tools enables the core GATK development
+team to optimize such traversals for correctness, stability, CPU
+performance, memory footprint, and in many cases to even automatically
+parallelize calculations. Moreover, since the traversal engine
+encapsulates the complexity of efficiently accessing the
+next-generation sequencing data, researchers and developers are free
+to focus on their specific analysis algorithms. This not only vastly
+improves productivity of the developers, who can quickly write new
+analyses, but also results in tools that are efficient and robust and
+can benefit from improvement to a common data management engine.
+
+Capabilities
+------------
+The GenomeAnalysisTK development environment is currently provided as
+a platform-independent Java programming language library. The core
+system works with the nascent standard Sequence Alignment/Map (SAM)
+format to represent reads using a production-quality SAM library
+developed at the Broad. The system can access a variety of metadata
+files such as dbSNP, Hapmap, RefSeq as well as work with genotype and
+SNP files in GLF, Geli, and other common formats. The core system
+handles read data from Illumina/Solexa, SOLiD, and Roche/454. The
+current GATK engine can process all of the 1000 genomes data
+representing ~5Tb of data from these three technologies produced from
+multiple sequencing centers and aligned to the human reference genome
+with multiple aligners. The GATK currently provides traversals by
+each read (ByRead traversal), by all reads covering each locus in the
+genome (ByLoci traversal), and by all reads within pre-specified
+intervals on the genome (ByWindow traversal).
+
+Dependencies
+------------
+The GATK relies on a Java 6-compatible JRE. At the time of this writing,
+the GATK team tests with Sun JRE version 1.6.0_12-b04. Additionally, the
+GATK requires as inputs a sorted, indexed BAM file containing aligned reads
+and a fasta-format reference with associated dictionary file (.dict)and
+index (.fasta.fai).
+
+Instructions for preparing input files are available here:
+
+http://www.broadinstitute.org/gatk/guide/article?id=1204
+
+The bundled 'resources' directory contains an example BAM and fasta.
+
+Getting Started
+---------------
+The GATK is distributed with a few standard analyses, including PrintReads,
+Pileup, and DepthOfCoverage. More information on the included walkers is
+available here:
+
+http://www.broadinstitute.org/gatk/gatkdocs
+
+To print the reads of the included sample data, untar the package into
+the GenomeAnalysisTK directory and run the following command:
+
+java -jar GenomeAnalysisTK/GenomeAnalysisTK.jar \
+ -T PrintReads \
+ -R GenomeAnalysisTK/resources/exampleFASTA.fasta \
+ -I GenomeAnalysisTK/resources/exampleBAM.bam
+
+Support
+-------
+Documentation for the GATK is available at http://www.broadinstitute.org/gatk/guide.
+For help using the GATK, developing analyses with the GATK, bug reports,
+or feature requests, please visit our support forum at http://gatkforums.broadinstitute.org/
diff --git a/public/external-example/pom.xml b/public/external-example/pom.xml
new file mode 100644
index 0000000..5065805
--- /dev/null
+++ b/public/external-example/pom.xml
@@ -0,0 +1,272 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!-- Properties for your assembly -->
+ <groupId>org.mycompany.app</groupId>
+ <artifactId>external-example</artifactId>
+ <packaging>jar</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <name>External Example</name>
+
+ <properties>
+ <gatk.version>3.3</gatk.version>
+ <!--
+ gatk.basedir property must point to your checkout of GATK/GATK until we can get all the
+ dependencies out of the committed gatk repo and into central.
+ The installed pom for gatk-root looks for this property.
+ Alternatively, one can install all the gatk files into their local ~/.m2/repository repo.
+ http://maven.apache.org/plugins/maven-install-plugin/examples/custom-pom-installation.html
+ -->
+ <gatk.basedir>../..</gatk.basedir>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <maven.build.timestamp.format>yyyy/MM/dd HH:mm:ss</maven.build.timestamp.format>
+
+ <!-- NOTE: Currently the testing infrastructure for walkers does not support running outside the Broad. -->
+ <gatk.committests.skipped>true</gatk.committests.skipped>
+ <gatk.unittests.skipped>${gatk.committests.skipped}</gatk.unittests.skipped>
+ <gatk.integrationtests.skipped>${gatk.committests.skipped}</gatk.integrationtests.skipped>
+
+ <!-- This flag is used by the package tests to disable re-shading -->
+ <gatk.unpack.phase>process-resources</gatk.unpack.phase>
+ <gatk.shade.phase>package</gatk.shade.phase>
+ </properties>
+
+ <repositories>
+ <repository>
+ <id>gatk.public.repo.local</id>
+ <name>GATK Public Local Repository</name>
+ <url>file:${gatk.basedir}/public/repo</url>
+ </repository>
+ </repositories>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-tools-public</artifactId>
+ <version>${gatk.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-tools-public</artifactId>
+ <version>${gatk.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>6.8</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+
+ <!-- Copy test resources to your classes directory -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.8</version>
+ <executions>
+ <execution>
+ <id>unpack</id>
+ <phase>${gatk.unpack.phase}</phase>
+ <goals>
+ <goal>unpack</goal>
+ </goals>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-engine</artifactId>
+ <version>${gatk.version}</version>
+ <classifier>example-resources</classifier>
+ <type>tar.bz2</type>
+ <outputDirectory>${project.build.outputDirectory}</outputDirectory>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Generate help text -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.9.1</version>
+ <executions>
+ <execution>
+ <id>extract-resource-bundle</id>
+ <goals>
+ <goal>javadoc</goal>
+ </goals>
+ <phase>prepare-package</phase>
+ <configuration>
+ <doclet>org.broadinstitute.gatk.utils.help.ResourceBundleExtractorDoclet</doclet>
+ <!-- Required as doclet uses reflection to access classes for documentation, instead of source java-->
+ <docletPath>${project.build.outputDirectory}</docletPath>
+ <docletArtifact>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <!-- TODO: THIS IS SUPPOSED TO BE GATK-UTILS! -->
+ <artifactId>gatk-tools-public</artifactId>
+ <version>${gatk.version}</version>
+ </docletArtifact>
+ <maxmemory>2g</maxmemory>
+ <useStandardDocletOptions>false</useStandardDocletOptions>
+ <quiet>true</quiet>
+ <additionalparam>-build-timestamp "${maven.build.timestamp}" -absolute-version "${project.version}" -out ${project.build.outputDirectory}/GATKText.properties</additionalparam>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Create packaged jar, containing only your walker and required classes -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.1</version>
+ <executions>
+ <execution>
+ <phase>${gatk.shade.phase}</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <minimizeJar>true</minimizeJar>
+ <!-- Explicitly include classes loaded via reflection from artifacts below -->
+ <filters>
+ <filter>
+ <artifact>commons-logging:commons-logging</artifact>
+ <includes>
+ <include>**</include>
+ </includes>
+ </filter>
+ <filter>
+ <artifact>samtools:htsjdk</artifact>
+ <includes>
+ <include>**</include>
+ </includes>
+ </filter>
+ </filters>
+ <!-- Stop shade from trying to unzip these indirect dependencies -->
+ <artifactSet>
+ <excludes>
+ <exclude>org.broadinstitute.gatk:gsalib:tar.gz:*</exclude>
+ <exclude>org.broadinstitute.gatk:*:tar.bz2:example-resources</exclude>
+ </excludes>
+ </artifactSet>
+ <transformers>
+ <!-- Set the main class to the GATK -->
+ <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+ <mainClass>org.broadinstitute.gatk.engine.CommandLineGATK</mainClass>
+ </transformer>
+ <!-- Include and append to the existing gatk help text in GATKText.properties -->
+ <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+ <resource>GATKText.properties</resource>
+ </transformer>
+ </transformers>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- surefire runs fast, small (aka unit) tests -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.16</version>
+ <configuration>
+ <!-- See explicit executions below -->
+ <skip>true</skip>
+ <failIfNoTests>false</failIfNoTests>
+ <!-- Pass various system properties -->
+ <systemPropertyVariables>
+ <gatkdir>${gatk.basedir}</gatkdir>
+ <java.io.tmpdir>${java.io.tmpdir}</java.io.tmpdir>
+ </systemPropertyVariables>
+ </configuration>
+ <executions>
+ <!-- Disable maven default execution -->
+ <execution>
+ <id>default-test</id>
+ <phase>none</phase>
+ </execution>
+ <execution>
+ <id>unit-tests</id>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <skip>${gatk.unittests.skipped}</skip>
+ <includes>
+ <include>**/*UnitTest.class</include>
+ </includes>
+ <systemPropertyVariables>
+ <testType>unit</testType>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- failsafe runs all other tests that may take longer, and may require pre/post test setup and teardown -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.16</version>
+ <configuration>
+ <!-- See explicit executions below -->
+ <skip>true</skip>
+ <failIfNoTests>false</failIfNoTests>
+ <!-- Pass various system properties -->
+ <systemPropertyVariables>
+ <gatkdir>${gatk.basedir}</gatkdir>
+ <java.io.tmpdir>${java.io.tmpdir}</java.io.tmpdir>
+ </systemPropertyVariables>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-tests</id>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <!-- run integration tests -->
+ <configuration>
+ <skip>${gatk.integrationtests.skipped}</skip>
+ <includes>
+ <include>**/*IntegrationTest.class</include>
+ </includes>
+ <systemPropertyVariables>
+ <testType>integrationtest</testType>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>packagetests-enabled</id>
+ <activation>
+ <property>
+ <name>gatk.packagetests.enabled</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <properties>
+ <gatk.jar.phase>none</gatk.jar.phase>
+ <gatk.unpack.phase>none</gatk.unpack.phase>
+ <gatk.shade.phase>none</gatk.shade.phase>
+ </properties>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/public/external-example/src/main/java/org/mycompany/app/MyExampleWalker.java b/public/external-example/src/main/java/org/mycompany/app/MyExampleWalker.java
new file mode 100644
index 0000000..1834c4a
--- /dev/null
+++ b/public/external-example/src/main/java/org/mycompany/app/MyExampleWalker.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.mycompany.app;
+
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.LocusWalker;
+
+import java.io.PrintStream;
+
+/**
+ * An example walker that looks surprisingly like CountLoci.
+ */
+public class MyExampleWalker extends LocusWalker<Integer, Long> {
+ @Output
+ PrintStream out;
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ return 1;
+ }
+
+ public Long reduceInit() { return 0l; }
+
+ public Long reduce(Integer value, Long sum) {
+ return value + sum;
+ }
+
+ public void onTraversalDone( Long c ) {
+ out.println(c);
+ }
+}
diff --git a/public/external-example/src/test/java/org/mycompany/app/MyExampleWalkerIntegrationTest.java b/public/external-example/src/test/java/org/mycompany/app/MyExampleWalkerIntegrationTest.java
new file mode 100644
index 0000000..ee625a4
--- /dev/null
+++ b/public/external-example/src/test/java/org/mycompany/app/MyExampleWalkerIntegrationTest.java
@@ -0,0 +1,54 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.mycompany.app;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.MissingResourceException;
+
+/**
+ * NOTE: Currently the testing infrastructure for walkers does not support running outside the Broad.
+ */
+public class MyExampleWalkerIntegrationTest extends WalkerTest {
+ @Test
+ public void testMyExampleWalker() throws URISyntaxException {
+ String gatk_args = String.format("-T MyExampleWalker -I %s -R %s", getResource("/exampleBAM.bam"), getResource("/exampleFASTA.fasta"));
+ WalkerTestSpec spec = new WalkerTestSpec(gatk_args, Collections.<String>emptyList());
+ executeTest("Testing count on the example bam", spec);
+ }
+
+ private File getResource(String path) throws URISyntaxException {
+ URL resourceUrl = getClass().getResource(path);
+ if (resourceUrl == null)
+ throw new MissingResourceException("Resource not found: " + path, getClass().getSimpleName(), path);
+ return new File(resourceUrl.toURI());
+ }
+}
diff --git a/public/external-example/src/test/java/org/mycompany/app/MyExampleWalkerUnitTest.java b/public/external-example/src/test/java/org/mycompany/app/MyExampleWalkerUnitTest.java
new file mode 100644
index 0000000..56335f1
--- /dev/null
+++ b/public/external-example/src/test/java/org/mycompany/app/MyExampleWalkerUnitTest.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.mycompany.app;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * NOTE: Currently the testing infrastructure for walkers does not support running outside the Broad.
+ */
+public class MyExampleWalkerUnitTest extends BaseTest {
+ @Test
+ public void testMyExampleWalker() {
+ MyExampleWalker walker = new MyExampleWalker();
+ Assert.assertEquals((long)walker.reduce(1, 1L), 2L);
+ }
+}
diff --git a/public/gatk-engine/pom.xml b/public/gatk-engine/pom.xml
new file mode 100644
index 0000000..15ba06e
--- /dev/null
+++ b/public/gatk-engine/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-aggregator</artifactId>
+ <version>3.3</version>
+ <relativePath>../..</relativePath>
+ </parent>
+
+ <artifactId>gatk-engine</artifactId>
+ <packaging>jar</packaging>
+ <name>GATK Engine</name>
+
+ <properties>
+ <gatk.basedir>${project.basedir}/../..</gatk.basedir>
+ <gatk.packagetests.artifactId>gatk-package-distribution</gatk.packagetests.artifactId>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.caliper</groupId>
+ <artifactId>caliper</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>example-resources</id>
+ <phase>${gatk.generate-resources.phase}</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-resource-bundle-log4j</id>
+ <phase>prepare-package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <!--
+ TODO: Refactor ResourceBundleExtractorDoclet.isWalker() and move the RBED to utils.
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>extract-resource-bundle</id>
+ <phase>prepare-package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>package-unittests</id>
+ </execution>
+ <execution>
+ <id>package-integrationtests</id>
+ </execution>
+ <execution>
+ <id>package-largescaletests</id>
+ </execution>
+ <execution>
+ <id>package-knowledgebasetests</id>
+ </execution>
+ <execution>
+ <id>package-queuetests</id>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/public/gatk-engine/src/main/assembly/example-resources.xml b/public/gatk-engine/src/main/assembly/example-resources.xml
new file mode 100644
index 0000000..5a5fc66
--- /dev/null
+++ b/public/gatk-engine/src/main/assembly/example-resources.xml
@@ -0,0 +1,37 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>example-resources</id>
+ <formats>
+ <format>tar.bz2</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>${project.build.sourceDirectory}/org/broadinstitute/gatk/gatk/walkers/qc</directory>
+ <outputDirectory>.</outputDirectory>
+ <includes>
+ <include>Pileup.java</include>
+ <include>CountLoci.java</include>
+ <include>CountReads.java</include>
+ <include>CheckPileup.java</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.build.sourceDirectory}/org/broadinstitute/gatk/gatk/walkers/readutils</directory>
+ <outputDirectory>.</outputDirectory>
+ <includes>
+ <include>PrintReads.java</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>src/test/resources</directory>
+ <outputDirectory>.</outputDirectory>
+ <includes>
+ <include>exampleBAM.bam</include>
+ <include>exampleBAM.bam.bai</include>
+ <include>exampleFASTA.fasta</include>
+ <include>exampleFASTA.fasta.fai</include>
+ <include>exampleFASTA.dict</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/ReadMetrics.java b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/ReadMetrics.java
new file mode 100644
index 0000000..0f00bd6
--- /dev/null
+++ b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/ReadMetrics.java
@@ -0,0 +1,121 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import htsjdk.samtools.filter.SamRecordFilter;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Holds a bunch of basic information about the traversal.
+ */
+public class ReadMetrics implements Cloneable {
+ // Number of records (loci, reads) we've processed
+ private long nRecords;
+ // How many reads have we processed, along with those skipped for various reasons
+ private long nReads;
+
+ // keep track of filtered records by filter type (class)
+ private Map<String, Long> filterCounter = new HashMap<>();
+
+ /**
+ * Combines these metrics with a set of other metrics, storing the results in this class.
+ * @param metrics The metrics to fold into this class.
+ */
+ public synchronized void incrementMetrics(ReadMetrics metrics) {
+ nRecords += metrics.nRecords;
+ nReads += metrics.nReads;
+ for(Map.Entry<String, Long> counterEntry: metrics.filterCounter.entrySet()) {
+ final String counterType = counterEntry.getKey();
+ final long newValue = (filterCounter.containsKey(counterType) ? filterCounter.get(counterType) : 0) + counterEntry.getValue();
+ filterCounter.put(counterType, newValue);
+ }
+ }
+
+ /**
+ * Create a copy of the given read metrics.
+ * @return a non-null clone
+ */
+ public ReadMetrics clone() {
+ ReadMetrics newMetrics;
+ try {
+ newMetrics = (ReadMetrics)super.clone();
+ }
+ catch(CloneNotSupportedException ex) {
+ throw new ReviewedGATKException("Unable to clone runtime metrics",ex);
+ }
+ newMetrics.nRecords = nRecords;
+ newMetrics.nReads = nReads;
+ newMetrics.filterCounter = new HashMap<>(filterCounter);
+
+ return newMetrics;
+ }
+
+
+ public void setFilterCount(final String filter, final long count) {
+ filterCounter.put(filter, count);
+ }
+
+ public Map<String,Long> getCountsByFilter() {
+ return new TreeMap<>(filterCounter);
+ }
+
+ /**
+ * Gets the number of 'iterations' (one call of filter/map/reduce sequence) performed.
+ * @return The number of iterations completed.
+ */
+ public long getNumIterations() {
+ return nRecords;
+ }
+
+ /**
+ * Increments the number of 'iterations' (one call of filter/map/reduce sequence) completed.
+ */
+ public void incrementNumIterations(final long by) {
+ nRecords += by;
+ }
+
+ /**
+ * Increments the number of 'iterations' (one call of filter/map/reduce sequence) completed.
+ */
+ public void incrementNumIterations() {
+ incrementNumIterations(1);
+ }
+
+ public long getNumReadsSeen() {
+ return nReads;
+ }
+
+ /**
+ * Increments the number of reads seen in the course of this run.
+ */
+ public void incrementNumReadsSeen() {
+ nReads++;
+ }
+}
diff --git a/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/package-info.java b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/package-info.java
new file mode 100644
index 0000000..bd34a17
--- /dev/null
+++ b/public/gatk-engine/src/main/java/org/broadinstitute/gatk/engine/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
\ No newline at end of file
diff --git a/public/gatk-engine/src/test/resources/exampleBAM.bam b/public/gatk-engine/src/test/resources/exampleBAM.bam
new file mode 100644
index 0000000..319dd1a
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleBAM.bam differ
diff --git a/public/gatk-engine/src/test/resources/exampleBAM.bam.bai b/public/gatk-engine/src/test/resources/exampleBAM.bam.bai
new file mode 100644
index 0000000..052ac61
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleBAM.bam.bai differ
diff --git a/public/gatk-engine/src/test/resources/exampleBAM.simple.bai b/public/gatk-engine/src/test/resources/exampleBAM.simple.bai
new file mode 100644
index 0000000..2d8268b
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleBAM.simple.bai differ
diff --git a/public/gatk-engine/src/test/resources/exampleBAM.simple.bam b/public/gatk-engine/src/test/resources/exampleBAM.simple.bam
new file mode 100644
index 0000000..c3eb7ae
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleBAM.simple.bam differ
diff --git a/public/gatk-engine/src/test/resources/exampleDBSNP.vcf b/public/gatk-engine/src/test/resources/exampleDBSNP.vcf
new file mode 100644
index 0000000..9e7e96f
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleDBSNP.vcf
@@ -0,0 +1,282 @@
+##fileformat=VCFv4.1
+##FILTER=<ID=NC,Description="Inconsistent Genotype Submission For At Least One Sample">
+##INFO=<ID=AF,Number=.,Type=Float,Description="Allele Frequency, for each ALT allele, in the same order as listed">
+##INFO=<ID=ASP,Number=0,Type=Flag,Description="Is Assembly specific. This is set if the variant only maps to one assembly">
+##INFO=<ID=ASS,Number=0,Type=Flag,Description="In acceptor splice site FxnCode = 73">
+##INFO=<ID=CDA,Number=0,Type=Flag,Description="Variation is interrogated in a clinical diagnostic assay">
+##INFO=<ID=CFL,Number=0,Type=Flag,Description="Has Assembly conflict. This is for weight 1 and 2 variant that maps to different chromosomes on different assemblies.">
+##INFO=<ID=CLN,Number=0,Type=Flag,Description="Variant is Clinical(LSDB,OMIM,TPA,Diagnostic)">
+##INFO=<ID=DSS,Number=0,Type=Flag,Description="In donor splice-site FxnCode = 75">
+##INFO=<ID=G5,Number=0,Type=Flag,Description=">5% minor allele frequency in 1+ populations">
+##INFO=<ID=G5A,Number=0,Type=Flag,Description=">5% minor allele frequency in each and all populations">
+##INFO=<ID=GCF,Number=0,Type=Flag,Description="Has Genotype Conflict Same (rs, ind), different genotype. N/N is not included.">
+##INFO=<ID=GENEINFO,Number=1,Type=String,Description="Pairs each of gene symbol:gene id. The gene symbol and id are delimited by a colon (:) and each pair is delimited by a vertical bar (|)">
+##INFO=<ID=GMAF,Number=1,Type=Float,Description="Global Minor Allele Frequency [0, 0.5]; global population is 1000GenomesProject phase 1 genotype data from 629 individuals, released in the 08-04-2010 dataset">
+##INFO=<ID=GNO,Number=0,Type=Flag,Description="Genotypes available. The variant has individual genotype (in SubInd table).">
+##INFO=<ID=HD,Number=0,Type=Flag,Description="Marker is on high density genotyping kit (50K density or greater). The variant may have phenotype associations present in dbGaP.">
+##INFO=<ID=INT,Number=0,Type=Flag,Description="In Intron FxnCode = 6">
+##INFO=<ID=KGPROD,Number=0,Type=Flag,Description="1000 Genome production phase">
+##INFO=<ID=KGPilot1,Number=0,Type=Flag,Description="1000 Genome discovery(pilot1) 2009">
+##INFO=<ID=KGPilot123,Number=0,Type=Flag,Description="1000 Genome discovery all pilots 2010(1,2,3)">
+##INFO=<ID=KGVAL,Number=0,Type=Flag,Description="1000 Genome validated by second method">
+##INFO=<ID=LSD,Number=0,Type=Flag,Description="Submitted from a locus-specific database">
+##INFO=<ID=MTP,Number=0,Type=Flag,Description="Microattribution/third-party annotation(TPA:GWAS,PAGE)">
+##INFO=<ID=MUT,Number=0,Type=Flag,Description="Is mutation (journal citation, explicit fact): a low frequency variation that is cited in journal and other reputable sources">
+##INFO=<ID=NOC,Number=0,Type=Flag,Description="Contig allele not present in variant allele list. The reference sequence allele at the mapped position is not present in the variant allele list, adjusted for orientation.">
+##INFO=<ID=NOV,Number=0,Type=Flag,Description="Rs cluster has non-overlapping allele sets. True when rs set has more than 2 alleles from different submissions and these sets share no alleles in common.">
+##INFO=<ID=NS,Number=1,Type=Integer,Description="Number of Samples With Data">
+##INFO=<ID=NSF,Number=0,Type=Flag,Description="Has non-synonymous frameshift A coding region variation where one allele in the set changes all downstream amino acids. FxnClass = 44">
+##INFO=<ID=NSM,Number=0,Type=Flag,Description="Has non-synonymous missense A coding region variation where one allele in the set changes protein peptide. FxnClass = 42">
+##INFO=<ID=NSN,Number=0,Type=Flag,Description="Has non-synonymous nonsense A coding region variation where one allele in the set changes to STOP codon (TER). FxnClass = 41">
+##INFO=<ID=OM,Number=0,Type=Flag,Description="Has OMIM/OMIA">
+##INFO=<ID=OTH,Number=0,Type=Flag,Description="Has other variant with exactly the same set of mapped positions on NCBI refernce assembly.">
+##INFO=<ID=PH1,Number=0,Type=Flag,Description="Phase 1 genotyped: filtered, non-redundant">
+##INFO=<ID=PH2,Number=0,Type=Flag,Description="Phase 2 genotyped: filtered, non-redundant">
+##INFO=<ID=PH3,Number=0,Type=Flag,Description="Phase 3 genotyped: filtered, non-redundant">
+##INFO=<ID=PM,Number=0,Type=Flag,Description="Variant is Precious(Clinical,Pubmed Cited)">
+##INFO=<ID=PMC,Number=0,Type=Flag,Description="Links exist to PubMed Central article">
+##INFO=<ID=R3,Number=0,Type=Flag,Description="In 3' gene region FxnCode = 13">
+##INFO=<ID=R5,Number=0,Type=Flag,Description="In 5' gene region FxnCode = 15">
+##INFO=<ID=REF,Number=0,Type=Flag,Description="Has reference A coding region variation where one allele in the set is identical to the reference sequence. FxnCode = 8">
+##INFO=<ID=RSPOS,Number=1,Type=Integer,Description="Chr position reported in dbSNP">
+##INFO=<ID=RV,Number=0,Type=Flag,Description="RS orientation is reversed">
+##INFO=<ID=S3D,Number=0,Type=Flag,Description="Has 3D structure - SNP3D table">
+##INFO=<ID=SAO,Number=1,Type=Integer,Description="Variant Allele Origin: 0 - unspecified, 1 - Germline, 2 - Somatic, 3 - Both">
+##INFO=<ID=SCS,Number=1,Type=Integer,Description="Variant Clinical Significance, 0 - unknown, 1 - untested, 2 - non-pathogenic, 3 - probable-non-pathogenic, 4 - probable-pathogenic, 5 - pathogenic, 6 - drug-response, 7 - histocompatibility, 255 - other">
+##INFO=<ID=SLO,Number=0,Type=Flag,Description="Has SubmitterLinkOut - From SNP->SubSNP->Batch.link_out">
+##INFO=<ID=SSR,Number=1,Type=Integer,Description="Variant Suspect Reason Code, 0 - unspecified, 1 - Paralog, 2 - byEST, 3 - Para_EST, 4 - oldAlign, 5 - other">
+##INFO=<ID=SYN,Number=0,Type=Flag,Description="Has synonymous A coding region variation where one allele in the set does not change the encoded amino acid. FxnCode = 3">
+##INFO=<ID=TPA,Number=0,Type=Flag,Description="Provisional Third Party Annotation(TPA) (currently rs from PHARMGKB who will give phenotype data)">
+##INFO=<ID=U3,Number=0,Type=Flag,Description="In 3' UTR Location is in an untranslated region (UTR). FxnCode = 53">
+##INFO=<ID=U5,Number=0,Type=Flag,Description="In 5' UTR Location is in an untranslated region (UTR). FxnCode = 55">
+##INFO=<ID=VC,Number=1,Type=String,Description="Variation Class">
+##INFO=<ID=VLD,Number=0,Type=Flag,Description="Is Validated. This bit is set if the variant has 2+ minor allele count based on frequency or genotype data.">
+##INFO=<ID=VP,Number=1,Type=String,Description="Variation Property">
+##INFO=<ID=WGT,Number=1,Type=Integer,Description="Weight, 00 - unmapped, 1 - weight 1, 2 - weight 2, 3 - weight 3 or more">
+##INFO=<ID=WTD,Number=0,Type=Flag,Description="Is Withdrawn by submitter If one member ss is withdrawn by submitter, then this bit is set. If all member ss' are withdrawn, then the rs is deleted to SNPHistory">
+##INFO=<ID=dbSNPBuildID,Number=1,Type=Integer,Description="First dbSNP Build for RS">
+##LeftAlignVariants="analysis_type=LeftAlignVariants input_file=[] read_buffer_size=null phone_home=STANDARD read_filter=[] intervals=null excludeIntervals=null interval_set_rule=UNION interval_merging=ALL reference_sequence=/humgen/gsa-hpprojects/GATK/bundle/current/b37/human_g1k_v37.fasta rodBind=[] nonDeterministicRandomSeed=false downsampling_type=BY_SAMPLE downsample_to_fraction=null downsample_to_coverage=1000 baq=OFF baqGapOpenPenalty=40.0 performanceLog=null useOriginalQualities= [...]
+##contig=<ID=chr1,length=249250621,assembly=b37>
+##phasing=partial
+##reference=GRCh37.3
+##reference=file:///humgen/gsa-hpprojects/GATK/bundle/current/b37/human_g1k_v37.fasta
+##source=dbSNP
+##variationPropertyDocumentationUrl=ftp://ftp.ncbi.nlm.nih.gov/snp/specs/dbSNP_BitField_latest.pdf
+#CHROM POS ID REF ALT QUAL FILTER INFO
+chr1 10144 rs144773400 TA T . PASS ASP;RSPOS=10145;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=134
+chr1 10228 rs143255646 TA T . PASS ASP;RSPOS=10229;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=134
+chr1 10234 rs145599635 C T . PASS ASP;RSPOS=10234;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 10248 rs148908337 A T . PASS ASP;RSPOS=10248;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 10254 rs140194106 TA T . PASS ASP;RSPOS=10255;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=134
+chr1 10291 rs145427775 C T . PASS ASP;RSPOS=10291;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 10327 rs112750067 T C . PASS ASP;GENEINFO=LOC100652771:100652771;RSPOS=10327;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=132
+chr1 10329 rs150969722 AC A . PASS ASP;RSPOS=10330;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=134
+chr1 10351 rs145072688 CTA C,CA . PASS ASP;RSPOS=10352;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=134
+chr1 10382 rs147093981 AAC A,AC . PASS ASP;RSPOS=10383;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=134
+chr1 10433 rs56289060 A AC . PASS ASP;GENEINFO=LOC100652771:100652771;RSPOS=10433;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 10439 rs112766696 AC A . PASS ASP;GENEINFO=LOC100652771:100652771;GNO;RSPOS=10440;SAO=0;SLO;SSR=0;VC=DIV;VP=050100000004000100000200;WGT=0;dbSNPBuildID=132
+chr1 10439 rs138941843 AC A . PASS ASP;RSPOS=10440;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=134
+chr1 10440 rs112155239 C A . PASS ASP;GENEINFO=LOC100652771:100652771;RSPOS=10440;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=132
+chr1 10492 rs55998931 C T . PASS ASP;GENEINFO=LOC100652771:100652771;GMAF=0.0617001828153565;RSPOS=10492;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004040000000100;WGT=0;dbSNPBuildID=129
+chr1 10519 rs62636508 G C . PASS ASP;GENEINFO=LOC100652771:100652771;RSPOS=10519;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=129
+chr1 10583 rs58108140 G A . PASS ASP;GENEINFO=LOC100652771:100652771;GMAF=0.270566727605119;KGPilot123;RSPOS=10583;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004040010000100;WGT=0;dbSNPBuildID=129
+chr1 10611 rs189107123 C G . PASS KGPilot123;RSPOS=10611;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 10828 rs10218492 G A . PASS ASP;GENEINFO=LOC100652771:100652771;RSPOS=10828;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=119
+chr1 10904 rs10218493 G A . PASS ASP;GENEINFO=LOC100652771:100652771;GNO;RSPOS=10904;SAO=0;SSR=0;VC=SNV;VP=050000000004000100000100;WGT=0;dbSNPBuildID=119
+chr1 10927 rs10218527 A G . PASS ASP;GENEINFO=LOC100652771:100652771;RSPOS=10927;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=119
+chr1 10938 rs28853987 G A . PASS ASP;GENEINFO=LOC100652771:100652771;RSPOS=10938;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=125
+chr1 11014 rs28484712 G A . PASS ASP;GENEINFO=LOC100652771:100652771;RSPOS=11014;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=125
+chr1 11022 rs28775022 G A . PASS ASP;GENEINFO=LOC100652771:100652771;RSPOS=11022;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=125
+chr1 11081 rs10218495 G T . PASS CFL;GENEINFO=LOC100652771:100652771;GNO;RSPOS=11081;SAO=0;SSR=0;VC=SNV;VP=050000000008000100000100;WGT=0;dbSNPBuildID=119
+chr1 11863 rs187669455 C A . PASS RSPOS=11863;SAO=0;SSR=0;VC=SNV;VP=050000000000000000000100;WGT=0;dbSNPBuildID=135
+chr1 13302 rs180734498 C T . PASS KGPilot123;RSPOS=13302;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 13327 rs144762171 G C . PASS ASP;KGPilot123;RSPOS=13327;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 13684 rs71260404 C T . PASS GENEINFO=LOC100652771:100652771;GNO;RSPOS=13684;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000000000100000100;WGT=0;dbSNPBuildID=130
+chr1 13980 rs151276478 T C . PASS ASP;KGPilot123;RSPOS=13980;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 14889 rs142444908 G A . PASS ASP;RSPOS=14889;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 14907 rs79585140 A G . PASS GNO;RSPOS=14907;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000000040100000100;WGT=0;dbSNPBuildID=131
+chr1 14930 rs75454623 A G . PASS GNO;RSPOS=14930;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000000040100000100;WGT=0;dbSNPBuildID=131
+chr1 14976 rs71252251 G A . PASS ASP;GNO;RSPOS=14976;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000004000100000100;WGT=0;dbSNPBuildID=130
+chr1 15061 rs71268703 T TG . PASS ASP;GNO;RSPOS=15061;RV;SAO=0;SLO;SSR=0;VC=DIV;VP=050100000004000100000200;WGT=0;dbSNPBuildID=130
+chr1 15118 rs71252250 A G . PASS ASP;GNO;RSPOS=15118;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000004000100000100;WGT=0;dbSNPBuildID=130
+chr1 15211 rs144718396 T G . PASS ASP;RSPOS=15211;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 15211 rs78601809 T G . PASS ASP;GNO;RSPOS=15211;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004040100000100;WGT=0;dbSNPBuildID=131
+chr1 16257 rs78588380 G C . PASS ASP;GNO;RSPOS=16257;SAO=0;SSR=0;VC=SNV;VP=050000000004000100000100;WGT=0;dbSNPBuildID=131
+chr1 16378 rs148220436 T C . PASS ASP;RSPOS=16378;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 16495 rs141130360 G C . PASS ASP;RSPOS=16495;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 16497 rs150723783 A G . PASS ASP;RSPOS=16497;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 17519 rs192890528 G T . PASS RSPOS=17519;SAO=0;SSR=0;VC=SNV;VP=050000000000000000000100;WGT=0;dbSNPBuildID=135
+chr1 19226 rs138930629 T A . PASS ASP;RSPOS=19226;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 20141 rs56336884 G A . PASS HD;RSPOS=20141;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000000000400000100;WGT=0;dbSNPBuildID=129
+chr1 20144 rs143346096 G A . PASS ASP;RSPOS=20144;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 20206 rs71262675 C T . PASS GNO;RSPOS=20206;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000000000100000100;WGT=0;dbSNPBuildID=130
+chr1 20245 rs71262674 G A . PASS GMAF=0.256398537477148;GNO;RSPOS=20245;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000000000100000100;WGT=0;dbSNPBuildID=130
+chr1 20304 rs71262673 G C . PASS GMAF=0.338208409506399;GNO;RSPOS=20304;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000000000100000100;WGT=0;dbSNPBuildID=130
+chr1 26999 rs147506580 A G . PASS ASP;RSPOS=26999;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 29436 rs2462493 G A . PASS GNO;RSPOS=29436;SAO=0;SSR=0;VC=SNV;VP=050000000000000100000100;WGT=0;dbSNPBuildID=100
+chr1 30923 rs140337953 G T . PASS ASP;KGPilot123;RSPOS=30923;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 33487 rs77459554 C T . PASS ASP;GNO;RSPOS=33487;SAO=0;SSR=0;VC=SNV;VP=050000000004000100000100;WGT=0;dbSNPBuildID=131
+chr1 33495 rs75468675 C T . PASS ASP;GNO;RSPOS=33495;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004040100000100;WGT=0;dbSNPBuildID=131
+chr1 33505 rs75627161 T C . PASS ASP;GNO;RSPOS=33505;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004040100000100;WGT=0;dbSNPBuildID=131
+chr1 33508 rs75609629 A T . PASS ASP;GNO;RSPOS=33508;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004040100000100;WGT=0;dbSNPBuildID=131
+chr1 33521 rs76098219 T A . PASS GNO;RSPOS=33521;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000000040100000100;WGT=0;dbSNPBuildID=131
+chr1 33593 rs557585 G A . PASS RSPOS=33593;SAO=0;SSR=0;VC=SNV;VP=050000000000000000000100;WGT=0;dbSNPBuildID=83
+chr1 33648 rs62028204 G T . PASS RSPOS=33648;RV;SAO=0;SSR=0;VC=SNV;VP=050000000000000000000100;WGT=0;dbSNPBuildID=129
+chr1 33656 rs113821789 T C . PASS RSPOS=33656;RV;SAO=0;SSR=0;VC=SNV;VP=050000000000000000000100;WGT=0;dbSNPBuildID=132
+chr1 51476 rs187298206 T C . PASS KGPilot123;RSPOS=51476;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 51479 rs116400033 T A . PASS ASP;G5;G5A;GMAF=0.113802559414991;KGPilot123;RSPOS=51479;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004070010000100;WGT=0;dbSNPBuildID=132
+chr1 51803 rs62637812 T C . PASS GMAF=0.468921389396709;RSPOS=51803;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000000040000000100;WGT=0;dbSNPBuildID=129
+chr1 51898 rs76402894 C A . PASS GMAF=0.0731261425959781;GNO;RSPOS=51898;SAO=0;SSR=0;VC=SNV;VP=050000000000000100000100;WGT=0;dbSNPBuildID=131
+chr1 51914 rs190452223 T G . PASS KGPilot123;RSPOS=51914;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 51928 rs78732933 G A . PASS GNO;RSPOS=51928;SAO=0;SSR=0;VC=SNV;VP=050000000000000100000100;WGT=0;dbSNPBuildID=131
+chr1 51935 rs181754315 C T . PASS KGPilot123;RSPOS=51935;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 51954 rs185832753 G C . PASS KGPilot123;RSPOS=51954;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 52058 rs62637813 G C . PASS GMAF=0.0342778793418647;KGPilot123;RSPOS=52058;SAO=0;SSR=1;VC=SNV;VLD;VP=050000000000040010000140;WGT=0;dbSNPBuildID=129
+chr1 52144 rs190291950 T A . PASS KGPilot123;RSPOS=52144;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 52238 rs150021059 T G . PASS ASP;KGPilot123;RSPOS=52238;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 54353 rs140052487 C A . PASS ASP;KGPilot123;RSPOS=54353;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 54421 rs146477069 A G . PASS ASP;KGPilot123;RSPOS=54421;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 54490 rs141149254 G A . PASS ASP;KGPilot123;RSPOS=54490;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 54676 rs2462492 C T . PASS ASP;GMAF=0.191956124314442;GNO;HD;KGPilot123;RSPOS=54676;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004040510000100;WGT=0;dbSNPBuildID=100
+chr1 54753 rs143174675 T G . PASS ASP;KGPilot123;RSPOS=54753;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 54788 rs59861892 CC C,CCT . PASS ASP;RSPOS=54789;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 54795 rs58014817 T A . PASS ASP;RSPOS=54795;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=129
+chr1 55164 rs3091274 C A . PASS G5;G5A;GMAF=0.145338208409506;GNO;KGPilot123;RSPOS=55164;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000000030110000100;WGT=0;dbSNPBuildID=103
+chr1 55299 rs10399749 C T . PASS G5;G5A;GMAF=0.278793418647166;GNO;KGPilot123;PH2;RSPOS=55299;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000000030112000100;WGT=0;dbSNPBuildID=119
+chr1 55302 rs3091273 C T . PASS RSPOS=55302;SAO=0;SSR=0;VC=SNV;VP=050000000000000000000100;WGT=0;dbSNPBuildID=103
+chr1 55313 rs182462964 A T . PASS KGPilot123;RSPOS=55313;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 55322 rs3107974 C T . PASS RSPOS=55322;SAO=0;SSR=0;VC=SNV;VP=050000000000000000000100;WGT=0;dbSNPBuildID=103
+chr1 55326 rs3107975 T C . PASS GNO;HD;KGPilot123;RSPOS=55326;SAO=0;SSR=0;VC=SNV;VP=050000000000000510000100;WGT=0;dbSNPBuildID=103
+chr1 55330 rs185215913 G A . PASS KGPilot123;RSPOS=55330;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 55367 rs190850374 G A . PASS KGPilot123;RSPOS=55367;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 55388 rs182711216 C T . PASS KGPilot123;RSPOS=55388;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 55394 rs2949420 T A . PASS GNO;KGPilot123;PH2;RSPOS=55394;SAO=0;SSR=0;VC=SNV;VP=050000000000000112000100;WGT=0;dbSNPBuildID=101
+chr1 55416 rs193242050 G A . PASS KGPilot123;RSPOS=55416;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 55427 rs183189405 T C . PASS KGPilot123;RSPOS=55427;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 55545 rs28396308 C T . PASS GNO;RSPOS=55545;SAO=0;SSR=0;VC=SNV;VP=050000000000000100000100;WGT=0;dbSNPBuildID=125
+chr1 55816 rs187434873 G A . PASS KGPilot123;RSPOS=55816;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 55850 rs191890754 C G . PASS KGPilot123;RSPOS=55850;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 55852 rs184233019 G C . PASS KGPilot123;RSPOS=55852;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 56644 rs143342222 A C . PASS ASP;KGPilot123;RSPOS=56644;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 57952 rs189727433 A C . PASS KGPilot123;RSPOS=57952;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 58771 rs140128481 T C . PASS ASP;RSPOS=58771;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 58814 rs114420996 G A . PASS ASP;G5;GMAF=0.0982632541133455;KGPilot123;RSPOS=58814;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004050010000100;WGT=0;dbSNPBuildID=132
+chr1 59040 rs149755937 T C . PASS ASP;KGPilot123;RSPOS=59040;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 60718 rs78395614 G A . PASS CFL;GNO;RSPOS=60718;SAO=0;SSR=0;VC=SNV;VP=050000000008000100000100;WGT=0;dbSNPBuildID=131
+chr1 60726 rs192328835 C A . PASS KGPilot123;RSPOS=60726;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 60791 rs76199781 A G . PASS CFL;GNO;RSPOS=60791;SAO=0;SSR=0;VC=SNV;VP=050000000008000100000100;WGT=0;dbSNPBuildID=131
+chr1 61442 rs74970982 A G . PASS CFL;GMAF=0.076782449725777;GNO;KGPilot123;RSPOS=61442;SAO=0;SSR=0;VC=SNV;VP=050000000008000110000100;WGT=0;dbSNPBuildID=131
+chr1 61462 rs56992750 T A . PASS CFL;G5;G5A;GMAF=0.0383912248628885;GNO;KGPilot123;RSPOS=61462;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000008030110000100;WGT=0;dbSNPBuildID=129
+chr1 61480 rs75526266 G C . PASS CFL;GNO;RSPOS=61480;SAO=0;SSR=0;VC=SNV;VP=050000000008000100000100;WGT=0;dbSNPBuildID=131
+chr1 61499 rs75719746 G A . PASS CFL;GNO;RSPOS=61499;SAO=0;SSR=0;VC=SNV;VP=050000000008000100000100;WGT=0;dbSNPBuildID=131
+chr1 61743 rs184286948 G C . PASS KGPilot123;RSPOS=61743;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 61920 rs62637820 G A . PASS CFL;GMAF=0.0255941499085923;RSPOS=61920;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000008040000000100;WGT=0;dbSNPBuildID=129
+chr1 61987 rs76735897 A G . PASS CFL;GMAF=0.292961608775137;GNO;KGPilot123;RSPOS=61987;SAO=0;SSR=0;VC=SNV;VP=050000000008000110000100;WGT=0;dbSNPBuildID=131
+chr1 61989 rs77573425 G C . PASS CFL;GMAF=0.309414990859232;GNO;KGPilot123;RSPOS=61989;SAO=0;SSR=0;VC=SNV;VP=050000000008000110000100;WGT=0;dbSNPBuildID=131
+chr1 61993 rs190553843 C T . PASS KGPilot123;RSPOS=61993;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 62156 rs181864839 C T . PASS KGPilot123;RSPOS=62156;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 62157 rs10399597 G A . PASS CFL;GMAF=0.00228519195612431;KGPilot123;RSPOS=62157;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000008040010000100;WGT=0;dbSNPBuildID=119
+chr1 62162 rs140556834 G A . PASS ASP;KGPilot123;RSPOS=62162;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 62203 rs28402963 T C . PASS CFL;KGPilot123;RSPOS=62203;SAO=0;SSR=0;VC=SNV;VP=050000000008000010000100;WGT=0;dbSNPBuildID=125
+chr1 62271 rs28599927 A G . PASS CFL;GMAF=0.138482632541133;RSPOS=62271;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000008040000000100;WGT=0;dbSNPBuildID=125
+chr1 63268 rs75478250 T C . PASS CFL;GNO;RSPOS=63268;SAO=0;SSR=0;VC=SNV;VP=050000000008000100000100;WGT=0;dbSNPBuildID=131
+chr1 63276 rs185977555 G A . PASS KGPilot123;RSPOS=63276;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 63297 rs188886746 G A . PASS KGPilot123;RSPOS=63297;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 63671 rs116440577 G A . PASS ASP;G5;GMAF=0.170018281535649;KGPilot123;RSPOS=63671;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004050010000100;WGT=0;dbSNPBuildID=132
+chr1 63737 rs77426996 TACT T,TCTA . PASS CFL;RSPOS=63738;SAO=0;SSR=0;VC=DIV;VP=050000000008000000000200;WGT=0;dbSNPBuildID=131
+chr1 64649 rs181431124 A C . PASS KGPilot123;RSPOS=64649;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 66008 rs2691286 C G . PASS CFL;GNO;RSPOS=66008;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000008000100000100;WGT=0;dbSNPBuildID=100
+chr1 66162 rs62639105 A T . PASS CFL;GMAF=0.320383912248629;GNO;KGPilot123;RSPOS=66162;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000008000110000100;WGT=0;dbSNPBuildID=129
+chr1 66176 rs28552463 T A . PASS CFL;GMAF=0.0484460694698355;KGPilot123;RSPOS=66176;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000008040010000100;WGT=0;dbSNPBuildID=125
+chr1 66219 rs181028663 A T . PASS KGPilot123;RSPOS=66219;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 66238 rs113961546 T A . PASS CFL;GNO;RSPOS=66238;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000008000100000100;WGT=0;dbSNPBuildID=132
+chr1 66314 rs28534012 T A . PASS CFL;RSPOS=66314;SAO=0;SSR=0;VC=SNV;VP=050000000008000000000100;WGT=0;dbSNPBuildID=125
+chr1 66331 rs186063952 A C . PASS KGPilot123;RSPOS=66331;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 66334 rs28464214 T A . PASS CFL;RSPOS=66334;SAO=0;SSR=0;VC=SNV;VP=050000000008000000000100;WGT=0;dbSNPBuildID=125
+chr1 66442 rs192044252 T A . PASS KGPilot123;RSPOS=66442;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 66457 rs13328655 T A . PASS CFL;GMAF=0.0795246800731261;KGPilot123;RSPOS=66457;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000008040010000100;WGT=0;dbSNPBuildID=121
+chr1 66503 rs112350669 T A . PASS CFL;RSPOS=66503;SAO=0;SSR=0;VC=SNV;VP=050000000008000000000100;WGT=0;dbSNPBuildID=132
+chr1 66507 rs12401368 T A . PASS CFL;GMAF=0.479890310786106;KGPilot123;RSPOS=66507;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000008040010000100;WGT=0;dbSNPBuildID=120
+chr1 66651 rs2257270 A T . PASS CFL;GNO;RSPOS=66651;SAO=0;SSR=0;VC=SNV;VP=050000000008000100000100;WGT=0;dbSNPBuildID=100
+chr1 67179 rs149952626 C G . PASS ASP;KGPilot123;RSPOS=67179;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 67181 rs77662731 A G . PASS ASP;G5;G5A;GENEINFO=OR4F5:79501;GMAF=0.0470749542961609;GNO;KGPilot123;RSPOS=67181;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004070110000100;WGT=0;dbSNPBuildID=131
+chr1 67223 rs78676975 C A . PASS ASP;GENEINFO=OR4F5:79501;GNO;RSPOS=67223;SAO=0;SSR=0;VC=SNV;VP=050000000004000100000100;WGT=0;dbSNPBuildID=131
+chr1 69428 rs140739101 T G . PASS ASP;RSPOS=69428;S3D;SAO=0;SSR=0;VC=SNV;VLD;VP=050200000004040000000100;WGT=0;dbSNPBuildID=134
+chr1 69453 rs142004627 G A . PASS ASP;RSPOS=69453;S3D;SAO=0;SSR=0;VC=SNV;VP=050200000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 69476 rs148502021 T C . PASS ASP;RSPOS=69476;S3D;SAO=0;SSR=0;VC=SNV;VLD;VP=050200000004040000000100;WGT=0;dbSNPBuildID=134
+chr1 69496 rs150690004 G A . PASS ASP;RSPOS=69496;S3D;SAO=0;SSR=0;VC=SNV;VLD;VP=050200000004040000000100;WGT=0;dbSNPBuildID=134
+chr1 69511 rs75062661 A G . PASS GENEINFO=OR4F5:79501;GMAF=0.193784277879342;GNO;KGPilot123;RSPOS=69511;S3D;SAO=0;SSR=0;VC=SNV;VP=050200000000000110000100;WGT=0;dbSNPBuildID=131
+chr1 69534 rs190717287 T C . PASS KGPilot123;RSPOS=69534;S3D;SAO=0;SSR=0;VC=SNV;VP=050200000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 69552 rs55874132 G C . PASS GENEINFO=OR4F5:79501;HD;RSPOS=69552;S3D;SAO=0;SLO;SSR=0;VC=SNV;VLD;VP=050300000000040400000100;WGT=0;dbSNPBuildID=129
+chr1 69590 rs141776804 T A . PASS ASP;RSPOS=69590;S3D;SAO=0;SSR=0;VC=SNV;VP=050200000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 69594 rs144967600 T C . PASS ASP;RSPOS=69594;S3D;SAO=0;SSR=0;VC=SNV;VP=050200000004000000000100;WGT=0;dbSNPBuildID=134
+chr1 72148 rs182862337 C T . PASS KGPilot123;RSPOS=72148;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 73841 rs143773730 C T . PASS ASP;KGPilot123;RSPOS=73841;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 74651 rs62641291 G A . PASS RSPOS=74651;SAO=0;SSR=0;VC=SNV;VP=050000000000000000000100;WGT=0;dbSNPBuildID=129
+chr1 74681 rs13328683 G T . PASS CFL;GMAF=0.286106032906764;RSPOS=74681;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000008040000000100;WGT=0;dbSNPBuildID=121
+chr1 74709 rs62641292 T A . PASS CFL;RSPOS=74709;SAO=0;SSR=0;VC=SNV;VP=050000000008000000000100;WGT=0;dbSNPBuildID=129
+chr1 74771 rs13328675 A G . PASS CFL;RSPOS=74771;SAO=0;SSR=0;VC=SNV;VP=050000000008000000000100;WGT=0;dbSNPBuildID=121
+chr1 74790 rs13328700 C G . PASS CFL;RSPOS=74790;SAO=0;SSR=0;VC=SNV;VP=050000000008000000000100;WGT=0;dbSNPBuildID=121
+chr1 74792 rs13328684 G A . PASS CFL;RSPOS=74792;SAO=0;SSR=0;VC=SNV;VP=050000000008000000000100;WGT=0;dbSNPBuildID=121
+chr1 77462 rs188023513 G A . PASS KGPilot123;RSPOS=77462;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 77470 rs192898053 T C . PASS KGPilot123;RSPOS=77470;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 77874 rs184538873 G A . PASS KGPilot123;RSPOS=77874;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 77961 rs78385339 G A . PASS GMAF=0.125685557586837;KGPilot123;RSPOS=77961;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000000040010000100;WGT=0;dbSNPBuildID=131
+chr1 79033 rs62641298 A G . PASS GMAF=0.438299817184644;GNO;HD;KGPilot123;RSPOS=79033;SAO=0;SSR=0;VC=SNV;VP=050000000000000510000100;WGT=0;dbSNPBuildID=129
+chr1 79050 rs62641299 G T . PASS GMAF=0.224405850091408;GNO;KGPilot123;RSPOS=79050;SAO=0;SSR=0;VC=SNV;VP=050000000000000110000100;WGT=0;dbSNPBuildID=129
+chr1 79137 rs143777184 A T . PASS ASP;KGPilot123;RSPOS=79137;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 79417 rs184768190 C T . PASS KGPilot123;RSPOS=79417;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 79418 rs2691296 G C . PASS GMAF=0.0178244972577697;RSPOS=79418;RV;SAO=0;SLO;SSR=0;VC=SNV;VLD;VP=050100000000040000000100;WGT=0;dbSNPBuildID=100
+chr1 79538 rs2691295 C T . PASS RSPOS=79538;RV;SAO=0;SSR=0;VC=SNV;VP=050000000000000000000100;WGT=0;dbSNPBuildID=100
+chr1 79772 rs147215883 C G . PASS ASP;KGPilot123;RSPOS=79772;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 79872 rs189224661 T G . PASS KGPilot123;RSPOS=79872;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 80323 rs3942603 G C . PASS CFL;GNO;RSPOS=80323;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000008000100000100;WGT=0;dbSNPBuildID=108
+chr1 80386 rs3878915 C A . PASS GMAF=0.0118829981718464;RSPOS=80386;RV;SAO=0;SLO;SSR=0;VC=SNV;VLD;VP=050100000000040000000100;WGT=0;dbSNPBuildID=108
+chr1 80454 rs144226842 G C . PASS ASP;KGPilot123;RSPOS=80454;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 81836 rs2259560 A T . PASS ASP;GNO;RSPOS=81836;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000004000100000100;WGT=0;dbSNPBuildID=100
+chr1 81949 rs181567186 T C . PASS KGPilot123;RSPOS=81949;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 81962 rs4030308 T TAA . PASS ASP;RSPOS=81962;RV;SAO=0;SLO;SSR=0;VC=DIV;VP=050100000004000000000200;WGT=0;dbSNPBuildID=108
+chr1 82102 rs4030307 C T . PASS ASP;RSPOS=82102;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000004000000000100;WGT=0;dbSNPBuildID=108
+chr1 82103 rs2020400 T C . PASS ASP;RSPOS=82103;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000004000000000100;WGT=0;dbSNPBuildID=92
+chr1 82126 rs1815133 C T . PASS ASP;RSPOS=82126;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000004000000000100;WGT=0;dbSNPBuildID=92
+chr1 82133 rs4030306 CA C,CAAAAAAAAAAAAAAA . PASS ASP;RSPOS=82136;RV;SAO=0;SLO;SSR=0;VC=DIV;VP=050100000004000000000200;WGT=0;dbSNPBuildID=108
+chr1 82154 rs4477212 A G . PASS ASP;HD;RSPOS=82154;SAO=0;SSR=0;VC=SNV;VP=050000000004000400000100;WGT=0;dbSNPBuildID=111
+chr1 82162 rs1815132 C A . PASS ASP;GMAF=0.0351919561243144;GNO;RSPOS=82162;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000004000100000100;WGT=0;dbSNPBuildID=92
+chr1 82163 rs139113303 G A . PASS ASP;KGPilot123;RSPOS=82163;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 82196 rs112844054 A T . PASS ASP;RSPOS=82196;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=132
+chr1 82249 rs1851945 A G . PASS ASP;GMAF=0.0452468007312614;KGPilot123;RSPOS=82249;RV;SAO=0;SLO;SSR=0;VC=SNV;VLD;VP=050100000004040010000100;WGT=0;dbSNPBuildID=92
+chr1 82282 rs3871775 G A . PASS ASP;RSPOS=82282;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000004000000000100;WGT=0;dbSNPBuildID=108
+chr1 82303 rs3871776 T C . PASS ASP;RSPOS=82303;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000004000000000100;WGT=0;dbSNPBuildID=108
+chr1 82316 rs4030305 A C . PASS ASP;GNO;RSPOS=82316;RV;SAO=0;SLO;SSR=0;VC=SNV;VP=050100000004000100000100;WGT=0;dbSNPBuildID=108
+chr1 82609 rs149189449 C G . PASS ASP;KGPilot123;RSPOS=82609;SAO=0;SSR=0;VC=SNV;VP=050000000004000010000100;WGT=0;dbSNPBuildID=134
+chr1 82676 rs185237834 T G . PASS KGPilot123;RSPOS=82676;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 82734 rs4030331 T C . PASS ASP;GMAF=0.261882998171846;KGPilot123;RSPOS=82734;RV;SAO=0;SLO;SSR=0;VC=SNV;VLD;VP=050100000004040010000100;WGT=0;dbSNPBuildID=108
+chr1 82957 rs189774606 C T . PASS KGPilot123;RSPOS=82957;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 83084 rs181193408 T A . PASS KGPilot123;RSPOS=83084;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 83088 rs186081601 G C . PASS KGPilot123;RSPOS=83088;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 83107 rs4405097 G C . PASS ASP;RSPOS=83107;SAO=0;SSR=0;VC=SNV;VP=050000000004000000000100;WGT=0;dbSNPBuildID=111
+chr1 83119 rs4030324 AA A,ATAAC . PASS ASP;RSPOS=83120;RV;SAO=0;SLO;SSR=0;VC=DIV;VP=050100000004000000000200;WGT=0;dbSNPBuildID=108
+chr1 83771 rs189906733 T G . PASS KGPilot123;RSPOS=83771;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 83786 rs58520670 T TA . PASS ASP;RSPOS=83794;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 83815 rs58857344 GAGAA G . PASS ASP;RSPOS=83827;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 83826 rs71281475 AAAGA A,AAA . PASS ASP;GNO;RSPOS=83827;RV;SAO=0;SLO;SSR=0;VC=DIV;VP=050100000004000100000200;WGT=0;dbSNPBuildID=130
+chr1 83855 rs59596480 GAA G . PASS ASP;RSPOS=83857;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 83872 rs59556914 AA A,AAGA . PASS ASP;RSPOS=83873;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 83884 rs59586754 GAAA G . PASS ASP;RSPOS=83885;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 83897 rs61330047 GAA G . PASS ASP;RSPOS=83899;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 83901 rs58254183 GAAAGAA G . PASS ASP;RSPOS=83903;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 83921 rs61338823 GAA G . PASS ASP;RSPOS=83923;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 83930 rs71281474 AG A,AGA . PASS ASP;GNO;RSPOS=83931;RV;SAO=0;SLO;SSR=0;VC=DIV;VP=050100000004000100000200;WGT=0;dbSNPBuildID=130
+chr1 83934 rs59235392 AG A,AGAAA . PASS ASP;RSPOS=83935;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 83977 rs180759811 A G . PASS KGPilot123;RSPOS=83977;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 84002 rs28850140 G A . PASS ASP;GMAF=0.138939670932358;KGPilot123;RSPOS=84002;SAO=0;SSR=0;VC=SNV;VLD;VP=050000000004040010000100;WGT=0;dbSNPBuildID=125
+chr1 84010 rs186443818 G A . PASS KGPilot123;RSPOS=84010;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 84018 rs61352176 GAA G . PASS ASP;RSPOS=84020;SAO=0;SSR=0;VC=DIV;VP=050000000004000000000200;WGT=0;dbSNPBuildID=129
+chr1 84079 rs190867312 T C . PASS KGPilot123;RSPOS=84079;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 84139 rs183605470 A T . PASS KGPilot123;RSPOS=84139;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 84156 rs188652299 A C . PASS KGPilot123;RSPOS=84156;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 84244 rs191297051 A C . PASS KGPilot123;RSPOS=84244;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 84295 rs183209871 G A . PASS KGPilot123;RSPOS=84295;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 84346 rs187855973 T C . PASS KGPilot123;RSPOS=84346;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 84453 rs191379015 C G . PASS KGPilot123;RSPOS=84453;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
+chr1 84705 rs183470350 T G . PASS KGPilot123;RSPOS=84705;SAO=0;SSR=0;VC=SNV;VP=050000000000000010000100;WGT=0;dbSNPBuildID=135
diff --git a/public/gatk-engine/src/test/resources/exampleDBSNP.vcf.idx b/public/gatk-engine/src/test/resources/exampleDBSNP.vcf.idx
new file mode 100644
index 0000000..7239e36
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleDBSNP.vcf.idx differ
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA-3contigs.fasta b/public/gatk-engine/src/test/resources/exampleFASTA-3contigs.fasta
new file mode 100644
index 0000000..cc31f38
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleFASTA-3contigs.fasta
@@ -0,0 +1,24 @@
+>chr1
+AAAAA
+AAAAA
+AAAAA
+AA
+
+
+>chr2
+BBBBBBB
+BBBBBBB
+BBBBBBB
+
+>chr3
+CCCCCCCCCC
+CCCCCCCCCC
+CCCCCCCCCC
+CCCCCCCCCC
+CCCCCCCCCC
+CCCCCCCCCC
+CCCCCCCCCC
+CCCCCCCCCC
+CCCCCCCCCC
+CCCCCCCCCC
+
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA-combined.fasta b/public/gatk-engine/src/test/resources/exampleFASTA-combined.fasta
new file mode 100644
index 0000000..4bfa409
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleFASTA-combined.fasta
@@ -0,0 +1,1675 @@
+>chr1
+taaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccc
+taaccctaaccctaaccctaaccctaaccctaaccctaaccctaacccaaccctaaccct
+aaccctaaccctaaccctaaccctaacccctaaccctaaccctaaccctaaccctaacct
+aaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaacccctaaccc
+taaccctaaaccctaaaccctaaccctaaccctaaccctaaccctaaccccaaccccaac
+cccaaccccaaccccaaccccaaccctaacccctaaccctaaccctaaccctaccctaac
+cctaaccctaaccctaaccctaaccctaacccctaacccctaaccctaaccctaacccta
+accctaaccctaaccctaacccctaaccctaaccctaaccctaaccctcgcggtaccctc
+agccggcccgcccgcccgggtctgacctgaggagaactgtgctccgccttcagagtacca
+ccgaaatctgtgcagaggacaacgcagctccgccctcgcggtgctctccgggtctgtgct
+gaggagaacgcaactccgccggcgcaggcgcagagaggcgcgccgcgccggcgcaggcgc
+agacacatgctagcgcgtcggggtggaggcgtggcgcaggcgcagagaggcgcgccgcgc
+cggcgcaggcgcagagacacatgctaccgcgtccaggggtggaggcgtggcgcaggcgca
+gagaggcgcaccgcgccggcgcaggcgcagagacacatgctagcgcgtccaggggtggag
+gcgtggcgcaggcgcagagacgcaagcctacgggcgggggttgggggggcgtgtgttgca
+ggagcaaagtcgcacggcgccgggctggggcggggggagggtggcgccgtgcacgcgcag
+aaactcacgtcacggtggcgcggcgcagagacgggtagaacctcagtaatccgaaaagcc
+gggatcgaccgccccttgcttgcagccgggcactacaggacccgcttgctcacggtgctg
+tgccagggcgccccctgctggcgactagggcaactgcagggctctcttgcttagagtggt
+ggccagcgccccctgctggcgccggggcactgcagggccctcttgcttactgtatagtgg
+tggcacgccgcctgctggcagctagggacattgcagggtcctcttgctcaaggtgtagtg
+gcagcacgcccacctgctggcagctggggacactgccgggccctcttgctCCAACAGTAC
+TGGCGGATTATAGGGAAACACCCGGAGcatatgctgtttggtctcagtagactcctaaat
+atgggattcctgggtttaaaagtaaaaaataaatatgtttaatttgtgaactgattacca
+tcagaattgtactgttctgtatcccaccagcaatgtctaggaatgcctgtttctccacaa
+agtgtttacttttggatttttgccagtctaacaggtgaAGccctggagattcttattagt
+gatttgggctggggcctggccatgtgtatttttttaaatttccactgatgattttgctgc
+atggccggtgttgagaatgactgCGCAAATTTGCCGGATTTCCTTTGCTGTTCCTGCATG
+TAGTTTAAACGAGATTGCCAGCACCGGGTATCATTCACCATTTTTCTTTTCGTTAACTTG
+CCGTCAGCCTTTTCTTTGACCTCTTCTTTCTGTTCATGTGTATTTGCTGTCTCTTAGCCC
+AGACTTCCCGTGTCCTTTCCACCGGGCCTTTGAGAGGTCACAGGGTCTTGATGCTGTGGT
+CTTCATCTGCAGGTGTCTGACTTCCAGCAACTGCTGGCCTGTGCCAGGGTGCAAGCTGAG
+CACTGGAGTGGAGTTTTCCTGTGGAGAGGAGCCATGCCTAGAGTGGGATGGGCCATTGTT
+CATCTTCTGGCCCCTGTTGTCTGCATGTAACTTAATACCACAACCAGGCATAGGGGAAAG
+ATTGGAGGAAAGATGAGTGAGAGCATCAACTTCTCTCACAACCTAGGCCAGTAAGTAGTG
+CTTGTGCTCATCTCCTTGGCTGTGATACGTGGCCGGCCCTCGCTCCAGCAGCTGGACCCC
+TACCTGCCGTCTGCTGCCATCGGAGCCCAAAGCCGGGCTGTGACTGCTCAGACCAGCCGG
+CTGGAGGGAGGGGCTCAGCAGGTCTGGCTTTGGCCCTGGGAGAGCAGGTGGAAGATCAGG
+CAGGCCATCGCTGCCACAGAACCCAGTGGATTGGCCTAGGTGGGATCTCTGAGCTCAACA
+AGCCCTCTCTGGGTGGTAGGTGCAGAGACGGGAGGGGCAGAGCCGCAGGCACAGCCAAGA
+GGGCTGAAGAAATGGTAGAACGGAGCAGCTGGTGATGTGTGGGCCCACCGGCCCCAGGCT
+CCTGTCTCCCCCCAGGTGTGTGGTGATGCCAGGCATGCCCTTCCCCAGCATCAGGTCTCC
+AGAGCTGCAGAAGACGACGGCCGACTTGGATCACACTCTTGTGAGTGTCCCCAGTGTTGC
+AGAGGTGAGAGGAGAGTAGACAGTGAGTGGGAGTGGCGTCGCCCCTAGGGCTCTACGGGG
+CCGGCGTCTCCTGTCTCCTGGAGAGGCTTCGATGCCCCTCCACACCCTCTTGATCTTCCC
+TGTGATGTCATCTGGAGCCCTGCTGCTTGCGGTGGCCTATAAAGCCTCCTAGTCTGGCTC
+CAAGGCCTGGCAGAGTCTTTCCCAGGGAAAGCTACAAGCAGCAAACAGTCTGCATGGGTC
+ATCCCCTTCACTCCCAGCTCAGAGCCCAGGCCAGGGGCCCCCAAGAAAGGCTCTGGTGGA
+GAACCTGTGCATGAAGGCTGTCAACCAGTCCATAGGCAAGCCTGGCTGCCTCCAGCTGGG
+TCGACAGACAGGGGCTGGAGAAGGGGAGAAGAGGAAAGTGAGGTTGCCTGCCCTGTCTCC
+TACCTGAGGCTGAGGAAGGAGAAGGGGATGCACTGTTGGGGAGGCAGCTGTAACTCAAAG
+CCTTAGCCTCTGTTCCCACGAAGGCAGGGCCATCAGGCACCAAAGGGATTCTGCCAGCAT
+AGTGCTCCTGGACCAGTGATACACCCGGCACCCTGTCCTGGACACGCTGTTGGCCTGGAT
+CTGAGCCCTGGTGGAGGTCAAAGCCACCTTTGGTTCTGCCATTGCTGCTGTGTGGAAGTT
+CACTCCTGCCTTTTCCTTTCCCTAGAGCCTCCACCACCCCGAGATCACATTTCTCACTGC
+CTTTTGTCTGCCCAGTTTCACCAGAAGTAGGCCTCTTCCTGACAGGCAGCTGCACCACTG
+CCTGGCGCTGTGCCCTTCCTTTGCTCTGCCCGCTGGAGACGGTGTTTGTCATGGGCCTGG
+TCTGCAGGGATCCTGCTACAAAGGTGAAACCCAGGAGAGTGTGGAGTCCAGAGTGTTGCC
+AGGACCCAGGCACAGGCATTAGTGCCCGTTGGAGAAAACAGGGGAATCCCGAAGAAATGG
+TGGGTCCTGGCCATCCGTGAGATCTTCCCAGGGCAGCTCCCCTCTGTGGAATCCAATCTG
+TCTTCCATCCTGCGTGGCCGAGGGCCAGGCTTCTCACTGGGCCTCTGCAGGAGGCTGCCA
+TTTGTCCTGCCCACCTTCTTAGAAGCGAGACGGAGCAGACCCATCTGCTACTGCCCTTTC
+TATAATAACTAAAGTTAGCTGCCCTGGACTATTCACCCCCTAGTCTCAATTTAAGAAGAT
+CCCCATGGCCACAGGGCCCCTGCCTGGGGGCTTGTCACCTCCCCCACCTTCTTCCTGAGT
+CATTCCTGCAGCCTTGCTCCCTAACCTGCCCCACAGCCTTGCCTGGATTTCTATCTCCCT
+GGCTTGGTGCCAGTTCCTCCAAGTCGATGGCACCTCCCTCCCTCTCAACCACTTGAGCAA
+ACTCCAAGACATCTTCTACCCCAACACCAGCAATTGTGCCAAGGGCCATTAGGCTCTCAG
+CATGACTATTTTTAGAGACCCCGTGTCTGTCACTGAAACCTTTTTTGTGGGAGACTATTC
+CTCCCATCTGCAACAGCTGCCCCTGCTGACTGCCCTTCTCTCCTCCCTCTCATCCCAGAG
+AAACAGGTCAGCTGGGAGCTTCTGCCCCCACTGCCTAGGGACCAACAGGGGCAGGAGGCA
+GTCACTGACCCCGAGACGTTTGCATCCTGCACAGCTAGAGATCCTTTATTAAAAGCACAC
+TGTTGGTTTCTGCTCAGTTCTTTATTGATTGGTGTGCCGTTTTCTCTGGAAGCCTCTTAA
+GAACACAGTGGCGCAGGCTGGGTGGAGCCGTCCCCCCATGGAGCACAGGCAGACAGAAGT
+CCCCGCCCCAGCTGTGTGGCCTCAAGCCAGCCTTCCGCTCCTTGAAGCTGGTCTCCACAC
+AGTGCTGGTTCCGTCACCCCCTCCCAAGGAAGTAGGTCTGAGCAGCTTGTCCTGGCTGTG
+TCCATGTCAGAGCAACGGCCCAAGTCTGGGTCTGGGGGGGAAGGTGTCATGGAGCCCCCT
+ACGATTCCCAGTCGTCCTCGTCCTCCTCTGCCTGTGGCTGCTGCGGTGGCGGCAGAGGAG
+GGATGGAGTCTGACACGCGGGCAAAGGCTCCTCCGGGCCCCTCACCAGCCCCAGGTCCTT
+TCCCAGAGATGCCTGGAGGGAAAAGGCTGAGTGAGGGTGGTTGGTGGGAAACCCTGGTTC
+CCCCAGCCCCCGGAGACTTAAATACAGGAAGAAAAAGGCAGGACAGAATTACAAGGTGCT
+GGCCCAGGGCGGGCAGCGGCCCTGCCTCCTACCCTTGCGCCTCATGACCAGCTTGTTGAA
+GAGATCCGACATCAAGTGCCCACCTTGGCTCGTGGCTCTCACTGCAACGGGAAAGCCACA
+GACTGGGGTGAAGAGTTCAGTCACATGCGACCGGTGACTCCCTGTCCCCACCCCCATGAC
+ACTCCCCAGCCCTCCAAGGCCACTGTGTTTCCCAGTTAGCTCAGAGCCTCAGTCGATCCC
+TGACCCAGCACCGGGCACTGATGAGACAGCGGCTGTTTGAGGAGCCACCTCCCAGCCACC
+TCGGGGCCAGGGCCAGGGTGTGCAGCAccactgtacaatggggaaactggcccagagagg
+tgaggcagcttgcctggggtcacagagcaaggcaaaagcagcgctgggtacaagctcaAA
+ACCATAGTGCCCAGGGCACTGCCGCTGCAGGCGCAGGCATCGCATCACACCAGTGTCTGC
+GTTCACAGCAGGCATCATCAGTAGCCTCCAGAGGCCTCAGGTCCAGTCTCTAAAAATATC
+TCAGGAGGCTGCAGTGGCTGACCATTGCCTTGGACCGCTCTTGGCAGTCGAAGAAGATTC
+TCCTGTCAGTTTGAGCTGGGTGAGCTTAGAGAGGAAAGCTCCACTATGGCTCCCAAACCA
+GGAAGGAGCCATAGCCCAGGCAGGAGGGCTGAGGACCTCTGGTGGCGGCCCAGGGCTTCC
+AGCATGTGCCCTAGGGGAAGCAGGGGCCAGCTGGCAAGAGCAGGGGGTGGGCAGAAAGCA
+CCCGGTGGACTCAGGGCTGGAGGGGAGGAGGCGATCTTGCCCAAGGCCCTCCGACTGCAA
+GCTCCAGGGCCCGCTCACCTTGCTCCTGCTCCTTCTGCTGCTGCTTCTCCAGCTTTCGCT
+CCTTCATGCTGCGCAGCTTGGCCTTGCCGATGCCCCCAGCTTGGCGGATGGACTCTAGCA
+GAGTGGCCAGCCACCGGAGGGGTCAACCACTTCCCTGGGAGCTCCCTGGACTGGAGCCGG
+GAGGTGGGGAACAGGGCAAGGAGGAAAGGCTGCTCAGGCAGGGCTGGGGAAGCTTACTGT
+GTCCAAGAGCCTGCTGGGAGGGAAGTCACCTCCCCTCAAACGAGGAGCCCTGCGCTGGGG
+AGGCCGGACCTTTGGAGACTGTGTGTGGGGGCCTGGGCACTGACTTCTGCAACCACCTGA
+GCGCGGGCATCCTGTGTGCAGATACTCCCTGCTTCCTCTCTAGCCCCCACCCTGCAGAGC
+TGGACCCCTGAGCTAGCCATGCTCTGACAGTCTCAGTTGCACACACGAGCCAGCAGAGGG
+GTTTTGTGCCACTTCTGGATGCTAGGGTTACACTGGGAGACACAGCAGTGAAGCTGAAAT
+GAAAAATGTGTTGCTGTAGTTTGTTATTAGACCCCTTCTTTCCATTGGTTTAATTAGGAA
+TGGGGAACCCAGAGCCTCACTTGTTCAGGCTCCCTCTGCCCTAGAAGTGAGAAGTCCAGA
+GCTCTACAGTTTGAAAACCACTATTTTATGAACCAAGTAGAACAAGATATTTGAAATGGA
+AACTATTCAAAAAATTGAGAATTTCTGACCACTTAACAAACCCACAGAAAATCCACCCGA
+GTGCACTGAGCACGCCAGAAATCAGGTGGCCTCAAAGAGCTGCTCCCACCTGAAGGAGAC
+GCGCTGCTGCTGCTGTCGTCCTGCCTGGCGCCTTGGCCTACAGGGGCCGCGGTTGAGGGT
+GGGAGTGGGGGTGCACTGGCCAGCACCTCAGGAGCtgggggtggtggtgggggcggtggg
+ggtggtgttagtACCCCATCTTGTAGGTCTGAAACACAAAGTGTGGGGTGTCTAGGGAAG
+AAGGTGTGTGACCAGGGAGGTCCCCGGCCCAGCTCCCATCCCAGAACCCAGCTCACCTAC
+CTTGAGAGGCTCGGCTACCTCAGTGTGGAAGGTGGGCAGTTCTGGAATGGTGCCAGGGGC
+AGAGGGGGCAATGCCGGGGCCCAGGTCGGCAATGTACATGAGGTCGTTGGCAATGCCGGG
+CAGGTCAGGCAGGTAGGATGGAACATCAATCTCAGGCACCTGGCCCAGGTCTGGCACATA
+GAAGTAGTTCTCTGGGACCTGCAAGATTAGGCAGGGACATGTGAGAGGTGACAGGGACCT
+GCAGGGGCAGCCAACAAGACCTTGTGTGCACCTCCCATGGGTGGAATAAGGGGCCCAACA
+GCCTTGACTGGAGAGGAGCTCTGGCAAGGCCCTGGGCCACTGCACCTGTCTCCACCTCTG
+TCCCACCCCTCCCACCTGCTGTTCCAGCTGCTCTCTCTTGCTGATGGACAAGGGGGCATC
+AAACAGCTTCTCCTCTGTCTCTGCCCCCAGCATCACATGGGTCTTTGTTACAGCACCAGC
+CAGGGGGTCCAGGAAGACATACTTCTTCTACCTACAGAGGCGACATGGGGGTCAGGCAAG
+CTGACACCCGCTGTCCTGAGCCCATGTTCCTCTCCCACATCATCAGGGGCACAGCGTGCA
+CTGTGGGGTCCCAGGCCTCCCGAGCCGAGCCACCCGTCACCCCCTGGCTCCTGGCCTATG
+TGCTGTACCTGTGTCTGATGCCCTGGGTCCCCACTAAGCCAGGCCGGGCCTCCCGCCCAC
+ACCCCTCGGCCCTGCCCTCTGGCCATACAGGTTCTCGGTGGTGTTGAAGAGCAGCAAGGA
+GCTGACAGAGCTGATGTTGCTGGGAAGACCCCCAAGTCCCTCTTCTGCATCGTCCTCGGG
+CTCCGGCTTGGTGCTCACGCACACAGGAAAGTCCTTCAGCTTCTCCTGAGAGGGCCAGGA
+TGGCCAAGGGATGGTGAATATTTGGTGCTGGGCCTAATCAGCTGCCATCCCATCCCAGTC
+AGCCTCCTCTGGGGGACAGAACCCTATGGTGGCCCCGGCTCCTCCCCAGTATCCAGTCCT
+CCTGGTGTGTGACAGGCTATATGCGCGGCCAGCAGACCTGCAGGGCCCGCTCGTCCAGGG
+GGCGGTGCTTGCTCTGGATCCTGTGGCGGGGGCGTCTCTGCAGGCCAGGGTCCTGGGCGC
+CCGTGAAGATGGAGCCATATTCCTGCAGGCGCCCTGGAGCAGGGTACTTGGCACTGGAGA
+ACACCTGTGGACACAGGGACAAGTCTGAGGGGGCCCCAAGAGGCTCAGAGGGCTAGGATT
+GCTTGGCAGGAGAGGGTGGAGTTGGAAGCCTGGGCGAGAAGAAAGCTCAAGGTACAGGTG
+GGCAGCAGGGCAGAGACTGGGCAGCCTCAGAGGCACGGGGAAATGGAGGGACTGCCCAGT
+AGCCTCAGGACACAGGGGTATGGGGACTACCTTGATGGCCTTCTTGCTGCCCTTGATCTT
+CTCAATCTTGGCCTGGGCCAAGGAGACCTTCTCTCCAATGGCCTGCACCTGGCTCCGGCT
+CTGCTCTACCTGCTGGGAGATCCTGCCATGGAGAAGATCACAGAGGCTGGGCTGCTCCCC
+ACCCTCTGCACACCTCCTGCTTCTAACAGCAGAGCTGCCAGGCCAGGCCCTCAGGCAAGG
+GCTCTGAAGTCAGGGTCACCTACTTGCCAGGGCCGATCTTGGTGCCATCCAGGGGGCCTC
+TACAAGGATAATCTGACCTGCAGGGTCGAGGAGTTGACGGTGCTGAGTTCCCTGCACTCT
+CAGTAGGGACAGGCCCTATGCTGCCACCTGTACATGCTATCTGAAGGACAGCCTCCAGGG
+CACACAGAGGATGGTATTTACACATGCACACATGGCTACTGATGGGGCAAGCACTTCACA
+ACCCCTCATGATCACGTGCAGCAGACAATGTGGCCTCTGCAGAGGGGGAACGGAGACCGG
+AGGCTGAGACTGGCAAGGCTGGACCTGAGTGTCGTCACCTAAATTCAGACGGGGAACTGC
+CCCTGCACATACTGAACGGCTCACTGAGCAAACCCCGAGTCCCGACCACCGCCTCAGTGT
+GGTCTAGCTcctcacctgcttccatcctccctggtgcggggtgggcccagtgatatcagc
+tgcctgctgttccccagatgtgccaagtgcattcttgtgtgcttgcatctcatggaacgc
+catttccccagacatccctgtggctggctcctGATGCCCGAGGCCCAAGTGTCTGATGCT
+TTAAGGCACATCACCCCACTCATGCTTTTCCATGTTCTTTGGCCGCAGCAAGGCCGCTCT
+CACTGCAAAGTTAACTCTGATGCGTGTGTAACACAACATCCTCCTCCCAGTCGCCCCTGT
+AGCTCCCCTACCTCCAAGAGCCCAGCCCTTGCCCACAGGGCCACACTCCACGTGCAGAGC
+AGCCTCAGCACTCACCGGGCACGAGCGAGCCTGTGTGGTGCGCAGGGATGAGAAGGCAGA
+GGCGCGACTGGGGTTCATGAGGAAGGGCAGGAGGAGGGTGTGGGATGGTGGAGGGGTTTG
+AGAAGGCAGAGGCGCGACTGGGGTTCATGAGGAAAGGGAGGGGGAGGATGTGGGATGGTG
+GAGGGGCTGCAGACTCTGGGCTAGGGAAAGCTGGGATGTCTCTAAAGGTTGGAATGAATG
+GCCTAGAATCCGACCCAATAAGCCAAAGCCACTTCCACCAACGTTAGAAGGCCTTGGCCC
+CCAGAGAGCCAATTTCACAATCCAGAAGTCCCCGTGCCCTAAAGGGTCTGCCCTGATTAC
+TCCTGGCTCCTTGTGTGCAGGGGGCTCAGGCATGGCAGGGCTGGGAGTACCAGCAGGCAC
+TCAAGCGGCTTAAGTGTTCCATGACAGACTGGTATGAAGGTGGCCACAATTCAGAAAGAA
+AAAAGAAGAGCACCATCTCCTTCCAGTGAGGAAGCGGGACCACCACCCAGCGTGTGCTCC
+ATCTTTTCTGGCTGGGGAGAGGCCTTCATCTGCTGTAAAGGGTCCTCCAGCACAAGCTGT
+CTTAATTGACCCTAGTTCCCAGGGCAGCCTCGTTCTGCCTTGGGTGCTGACACGACCTTC
+GGTAGGTGCATAAGCTCTGCATTCGAGGTCcacaggggcagtgggagggaactgagactg
+gggagggacaaaggctgctctgtcctggtgctcccacaaaggagaagggctgatcactca
+aagttgcgaacaccaagctcaacaatgagccctggaaaatttctggaatggattattaaa
+cagagagtctgtaagcacttagaaaaggccgcggtgagtcccaggggccagcactgctcg
+aaatgtacagcatttctctttgtaacaggattattagcctgctgtgcccggggaaaacat
+gcagcacagtgcatctcgagtcagcaggattttgacggcttctaacaaaatcttgtagac
+aagatggagctatgggggttggaggagagaacatataggaaaaatcagagccaaatgaac
+cacagccccaaagggcacagttgaacaatggactgattccagccttgcacggagggatct
+ggcagagtccatccagttcattcaacacctggttagaaaactggggccagcacacagggg
+aagggtaagctggtttcatgatcgaatcaaggctcagacaatttttaaaggccagagggt
+agactgcaatcaccaagatgaaatttacaaggaacaaatgtgaagcccaacatttaggtt
+ttaaaaatcaagcgtataaatacagaaggtggagggaacttgctttagacacagttcagg
+tgaagaaagacctggaaacttctgttaactataagctcagtaggggctaaaagcatgtta
+atcggcataaaaaggcaatgagatcttaggGCACACAGCTCCCCGCCCCTCTTCTGCCCT
+TCATCCTTCTTTCAATCAGCAGGGACCGTGCACTCTCTTGGAGCCACCACAGAAAACAGA
+GGTGCATCCAGCACCACAGAAAACAGAGCCACCACAGAAAACAGAGGGTGACTGTCATCC
+CCTCCAGTCTCTGCACACTCCCAGCTGCAGCAGAGCAGGAGGAGAGAGCACAGCCTGCAA
+TGCTAATTTGCCAGGAGCTCACCTGCCTGCGTCACTGGGCACAGACGCCAGTGAGGCCAG
+AGGCCGGGCTGTGCTGGGGCCTGAGCCGGGTGGTGGGGAGAGAGTCTCTCCCCTGCCCCT
+GTCTCTTCCGTGCAGGAGGAGCATGTTTAAGGGGACGGGTTCAAAGCTGGTCACATCCCC
+ACCGAAAAAGCCCATGGACAACGAAAAGCCCACTAGCTTGTCCAGTGCCACAGGAGGGGC
+AAGTGGAGGAGGAGAGGTGGCGGTGCTCCCCACTCCACTGCCAGTCGTCACTGGCTCTCC
+CTTCCCTTCATCCTCGTTCCCTATCTGTCACCATTTCCTGTCGTCGTTTCCTCTGAATGT
+CTCACCCTGCCCTCCCTGCTTGCAAGTCCCCTGTCTGTAGCCTCACCCCTGTCGTATCCT
+GACTACAATAACAGCTTCTGGGTGTCCCTGGCATCCACTCTCTCTCCCTTCTTGTCCCTT
+CCGTGACGGATGCCTGAGGAACCTTCCCCAAACTCTTCTGTCCCATCCCTGCCCTGCTCA
+AAATCCAATCACAGCTCCCTAACACGCCTGAATCAACTTGAAGTCCTGTCTTGAGTAATC
+CGTGGGCCCTAACTCACTCATCCCAACTCTTCACTCACTGCCCTGCCCCACACCCTGCCA
+GGGAGCCTCCCGTGGCACCGTGGGGACACAAAGGAACCAGGGCAAAGCTCCCTCAGCCCC
+ATTCAAAGAGGCCTGGCCCACAGGCTCACGGAAAGTCAGCCTCTCATGCCCCGAGAGCTG
+AGTGCAAGGGAGAGGCAGCGCTGTCTGTGCTTCCCATGCAGAAGCACCCCCCTCCCACCC
+CTGTGCAGGCCGGCCTTCGCGGCAGACCACCATACACCACGTTCCAAGCCACACTGAGGC
+CTCCCTCCAAGCCTGCAGCCCCCATTTCCAGACCCTGCCAGGGCAACCTGCATATCCACC
+TCCCTACCCTGCCCCCCTCTTCCAGGAGTCTGCCCTATGTGGAGTAAGCACgtggttttc
+ctcttcagcaactatttcctttttactcaagcaatggccccatttcccttggggaatcca
+tctctctcgcaggcttagtcccagagcttcaggtggggctgcccacagagctcctcagtc
+taagccaagtggtgtgtcatagtcccctggccccattaatggattctgggatagacatga
+ggaccaagccaggTGGGATGAGTGAGTGTGGCTTCTGGAGGAAGTGGGGACACAGGACAG
+CATTCTTTCCTGCTGGACCTGACCCTGTGTCATGTCACCTTGCTACCACGAGAGCATGGC
+CTGTCTGGGAATGCAGCCAGACCCAAAGAAGCAAACTGACATGGAAGGAAAGCAAAACCA
+GGCCCTGAGGACATCATTTTAGCCCTTACTCCGAAGGCTGCTCTACTGATTGGTTAATTT
+TTGCTTAGCTTGGTCTGGGGAGTTCTGACAGGCGTGCCACCAATTCTTACCGATTTCTCT
+CCACTCTAGACCCTGAGAAGCCCACGCGGTTCATGCTAGCAATTAACAATCAATCTCGCC
+CTATGTGTTCCCATTCCAGCCTCTAGGACACAGTGGCAGCCACATAATTGGTATCTCTTA
+AGGTCCAGCACGAGGTGGAGCACATGGTGGAGAGACAGATGCAGTGACCTGGAACCCAGG
+AGTGAGGGAGCCAGGACTCAGGCCCAAGGCTCCTGAGAGGCATCTGGCCCTCCCTGCGCT
+GTGCCAGCAGCTTGGAGAACCCACACTCAATGAACGCAGCACTCCACTACCCAGGAAATG
+CCTTCCTGCCCTCTCCTCATCCCATCCCTGGGCAGGGGACATGCAACTGTCTACAAGGTG
+CCAAGTACCAGGACAGGAAAGGAAAGACGCCAAAAATCCAGCGCTGCCCTCAGAGAAGGG
+CAACCACGCAGTCCCCATCTTGGCAAGGAAACACAATTTCCGAGGGAATGGTTTTGGCCT
+CCATTCTAAGTGCTGGACATGGGGTGGCCATAATCTGGAGCTGATGGCTCTTAAAGACCT
+GCATCCTCTTCCCTAGGTGTCCCTCGGGCACATTTAGCACAAAGATAAGCACAAAAGGTG
+CATCCAGCACTTTGTTACTATTGGTGGCAGGTTTATGAATGGCAACCAAAGGCAGTGTAC
+GGGTCAAGATTATCAACAGGGAAGAGATagcatttcctgaaggcttcctaggtgccaggc
+actgttccattcctttgcatgttttgattaatttaatatttaaaataattctaccaggaa
+gctaccattattaccacaacttcacaaatgagaacaccgaggcttagaggggttgggttg
+cccaaggttacagaggaagaaaacaggggagctggatctgagccaaggcatcaactccaa
+ggtAACCCCTCAGTCACTTCACTGTGTGTCCCCTGGTTACTGGGACATTCTTGACAAACT
+CGGGGCAAGCCGGTGAGTCAGTGGGGGAGGACTTTCAGGAAGAGGTGGGTTCCCAGTTGG
+TGACAGAAGAGGAGGCTGCAAAGTGAAGGAGCAGGGGCTCCAGGTCTGGCGACAACCAGG
+GAAGGGACAGGGCAGGGATGGCTTGGACCACGAGAGGCACCTGAGTCAGGCAGTCACATA
+CTTCCCACTGGGGTCTACCATGTGAGGCATGGTGTGGGATCCTGGGAAGGAGACCAAGCC
+TCATTTCAGTTTGCTTATGGCCAAAGACAGGACCTGTGTACCCGACAACCCCTGGGACCT
+TTACCAAAAAAAGAGCAAACACCATTCACTCACTCATGTTAGATAAACACTGAGTGAAGT
+CACTGGAGCCCAAGGACTGTGCGAGGTCAGCACTGCCAATACAAGAAGCTGCAGCCCTCC
+AGCTCGCctccctcaatggccactccgtgctccagccatgctggcttccttttaggtcct
+ccacctccaggctgtagttcatgtgcttctttctggaatgttcttcccaacctacccact
+caaccctcagactttaccataaatgtcatttcctcacgtctgccttccctgacctgagac
+caagccaggCTTCCCATGACGAGCCTCACAGTACCCCATCTCCCCTGAACAGATGCAGTA
+ATAACCTACATAACccggggccatgatctatggctttgaatcctggctctgtcactaggc
+caggtctctcagcccttctgtgcctcagtttcctcatctataaaatgagatgacggcagt
+gcctgctcatgaagtgtgagttaatgcactcaaatcaatggttgtgcacggtttatatga
+atattagtgattaCAAAATATTATCAatagaccttgtcacaactgttattgaagaactaa
+tcatctattgcttatttaggtctttctctcctgccagaatgtgcgctccaggtggagagg
+tatgttgccttatccgtggctggatatatagagattcccacactgccttgcacacgagca
+ctgctgggtaaatatttgttggctgcaggaaAACGTGAAGGAATAGGCCCTCCAATGGGA
+GGAAAAGCATGAGTTGTGAGAGCAGAGCCACCACAGGAAACCAGGAGGCTAAGTGGGGTG
+GAAGGGAGTGAGCTCTCGGACTCCCAGGAGTAAAAGCTTCCAAGTTGGGCTCTCACTTCA
+GCCCCTCCCACACAGGGAAGCCAGATGGGTTCCCCAGGACCGGGATTCCCCAAGGGGGCT
+GCTCCCAGAGGGTGTGTTGCTGGGATTGCCCAGGACAGGGATGGCCCTCTCATCAGGTGG
+GGGTGAGTGGCAGCACCCACCTGCTGAAGATGTCTCCAGAGACCTTCTGCAGGTACTGCA
+GGGCATCCGCCATCTGCTGGACGGCCTCCTCTCGCCGCAGGTCTGGCTGGATGAAGGGCA
+CGGCATAGGTCTGACCTGCCAGGGAGTGCTGCATCCTCACAGGAGTCATGGTGCCTGTGG
+GTCGGAGCCGGAGCGTCAGAGCCACCCACGACCACCGGCACGCCCCCACCACAGGGCAGC
+GTGGTGTTGAGACAACACAGCCCTCATCCCAACTATGCACATAGCTTCAGCCTGCACAGA
+TAGGGGAGTAGGGGACAGAGCATTTGCTGAGAGGCCAGGAGCGCATAGATGGGACTCTGC
+TGATGCCTGCTGAGTGAATGAGGGAAAGGGCAGGGCCCGGGACTGGGGAATCTGTAGGGT
+CAATGGAGGAGTTCAGAGAAGGTGCAACATTTCTGACCCCCTACAAGGTGCTTGCTACCT
+GCCAGGCACCCTTTCCATACCTTGTCTCAGTTCAGCTCCCCACCTTGGATAAACAAGAAA
+CCTTGGTTGCAGAGGAAAAAAGAGGCTGGAAACAAAGGGGTAGAAATGGGGTAGCAGGGG
+AGATTGCCTGATCAACTGCCAAATGGTACACAGTTCTGGAAAAGCACAAAAAATGTGCAC
+ACACGGGTTCTTCCCACTTTAACCCCTGAGGAATCTGAGGCCTGCTCCTGAAACAGACTG
+GGCAGTGGCTAGTGACTCTAGGTATAGGAGTATCCAGCCCTGCTCACCCAGGCTAGAGCT
+TAGGGGGACAAGAGGAAAGAGGTGCCTGTGGGGGTGGAGGACAGGAAGGAAAAACACTCC
+TGGAATTGCAAAGTGAGGGCAGAGTCTATTTATATTGGGTTTAATTAACTCCTCTCCCTG
+GTGCCACTAAAGCAGCAATCACACTGCAGACAGCACTGATTTGATTGGCAAGAGATGCAC
+CAGGCAGAATATTAAGGGACCAGGCCCCTATAAATAGGCCTAATCACAGCCCCTCACTGG
+AAAATGGTAAGGAAGACATTAATCAGGCCTGGCACTGTGCCCTAGACCTGCTCCCCTAGG
+CACTACAGTGGGGCCCTTGGTTGCAACACAAGTAGGTAGGGATGGATGAGTGTGGCATGA
+AGGGCCTAGGAGATTTCACTTGGGTTTAAAATGCTGTGACCTTGAGTAAGTTGCCGTCTC
+TGAATCTGATCCTTTCGATTTCCCATTCTCCAAACTGAGAACTAGCACTGCTGAGACGTG
+GTTATTTCCAATAATAATTTGTATATTTTACATAACGCACCACACCAACATCTTCACCCA
+GTTGGAGCCTACTCCTTTGCTCCCGCTGCTGGCTTCCCCAGCCCTCCCTTCTGCCCTCCT
+CAGGCCAGCACTTTTCAGTGAGTTCCTCCTTTGCATACAGGCTTTCCAGATCTGTACTTG
+CCTTGAATACTCATCAGAGCCCAGGAGTTACTCCTCACCTCCCACTTATTTTTCCTCCCA
+TCAAATAACTAAAGCATGGCCAGCTGATGCCCAGCCAACTGAGAAACCCAACCCTCTGAG
+ACCAGCACACCCCTTTCAAGCATGTTCCTCCCTCCCCTTCTTTGTATTTATACTGATGCA
+AGTTTGCTGGCTGTcctaacttatttctgtgcctcagttctcccatatgtaagatcacaa
+agggggtaaagaTGCAAGATATTTCCTGTGCACATCTTCAGATGAATTTCTTGTTAGTGT
+GTGTGTGTTTGCTCACACATATGCGTGAAAGAAGAGTACATACACAGATCTCCTCAAAAA
+GGAGGCAGCAAGCCCGTTCAAGAATGGGACTGAATACACCTGATGAGTGGTTTACTTTCT
+GTCTGCAAACATCTACTGATCATCTGTTAGGTGCAGGCCATGATCACAACAAAGACGAAT
+AAGACACTACACTAGCCAGGGAGAGTCTCAAAAACAACTAAACTCAAATTAAATTCATTC
+TACTCCAGTCATGGGTACAAAGCTAAGGAGTGACAAATCCCTCTTGGAGTTAGGGGAGTC
+AGGAAAAAGCTCTTAGCAGAATGTGTGCCTCTCggccgggcgcagcggctcacgcctgta
+atcccagcactttgggaggcgaaggcaggcagatcacctgaggtcgggagttcgagacca
+gtctgaccaacatggtgaaactccatctctactaaaaatacaaaattagccaggcgtggt
+ggtgcatgcctgtaatccccgctactcgggaggctgaggaaggagaatcacttgaaccag
+gaaggtggaggttgcagtgtgccaagatcgcgccatggcactccagcctaggcaacgagg
+gtgaaCCAGGTCCAGGAAGAAGGTGCAAAGACAGCATTCCAGGTAAAAGAAACAGCTTGA
+ACAAAAAGTGTGTAGGGGAACCGCAAGCGGTCTTGAGTGCTGAGGGTACAATCATCCTTG
+GGGAAGTACTAGAAGAAAGAATGATAAACAGAGGCCAGTTTGTTAAAAACACTCAAAATT
+AAAGCTAGGAGTTTGGACTTGTGGCAGGAATgaaatccttagacctgtgctgtccaatat
+ggtagccaccaggcacatgcagccactgagcacttgaaatgtggatagtctgaattgaga
+tgtgccataagtgtaaaatatgcaccaaatttcaaaggctagaaaaaaagaatgtaaaat
+atcttattattttatattgattacgtgctaaaataaccatatttgggatatactggattt
+taaaaatatatcactaatttcatctgtttctttttacttttAGAAATCACATATGTGACT
+TAAATATTTCTTTTCTTTTTCTTTCCTCTCACTCAGCGTCCTGTGATTCCAAAGAAATGA
+GTCTCTGCTGTTTTTGGGCAGCAGATATCCTAGAATGGACTCTGACCTAAGCATCAAAAT
+TAATCATCATAACGTTATCATTTTATGGCCCCTTCTTCCTATATCTGGTAGCTTTTAAAT
+GATGACCATGTAGATAATCTTTATTGTCCCTCTTTCAGCAGACGGTATTTTCTTATGCTA
+CAGTATGACTGCTAATAATACCTACACATGTTAGAACCATTCTGACTCCTCAAGAatctc
+atttaactcttattatcagtgaatttatcatcatcccctattttacataaggaaatgggg
+ttagaaagaccaaataacattttttcaacatcaaaacactagcttgagatcaagcccaga
+cttggatctgtcgtctgaattccaagctttttgttatttattgatatgttttgttgtTTT
+CATGCAATAATGCAAATCTTAGCCCAAACATTTTGTTAGTAGTACCAACTGTAAGTCACC
+TTATCTTCATACTTTGTCTTTATGTAAACCTAAATTAGATCTGTTTTTGATACTGAGGGA
+AAAACAAGGGAATctaacactaaccagcccgtagtgtgtggtcaacactttcgttacttt
+agtatacatcaccccaattgtttgtcttcaccacacactttggagttaggtagtagtatc
+tatttttacaaataagaaaacccaggcacaaaggggttgattagcAATTATCTTTTGAAA
+AGCCTGTAGTTGCTCATCTGAAGAAGTGACGGACCACCTCTTATTTAGTGGACAGACAGT
+AACTAGTTGAGAAGACAGGGGATTTTGTTGGCGGAAAAAAAAATTTATCAAAAGTCGTCT
+TCTATCAGGGAGTTTTATGAGAAACCCTAGCTCCTCAGTTCCACAGTGGGTAACTGTAAT
+TCATTCTAGGTCTGCGATATTTCCTGCCTATCCATTTTGTTAACTCTTCAATGCATTCCA
+CAAATACCTAAGTATTCTTTAATAATGGTGGTTTTTTTTTTTTTTTGCATCTATGAAGTT
+TTTTCAAATTCTTTTTAAGTGACAAAACTTGTACATGTGTATCGCTCAATATTTCTAGTC
+GACAGCACTGCTTTCGAGAATGTAAACCGTGCACTCCCAGGAAAATGCAGACACAGCACG
+CCTCTTTGGGACCGCGGTTTATACTTTCGAAGTGCTCGGAGCCCTTCCTCCAGACCGTTC
+TCCCACACCCCGCTCCAGGGTCTCTCCCGGAGTTACAAGCCTCGCTGTAGGCCCCGGGAA
+CCCAACGCGGTGTCAGAGAAGTGGGGTCCCCTACGAGGGACCAGGAGCTCCGGGCGGGCA
+GCAGCTGCGGAAGAGCCGCGCGAGGCTTCCCAGAACCCGGCAGGGGCGGGAAGACGCAGG
+AGTGGGGAGGCGGAACCGGGACCCCGCAGAGCCCGGGTCCCTGCGCCCCACAAGCCTTGG
+CTTCCCTGCTAGGGCCGGGCAAGGCCGGGTGCAGGGCGCGGCTCCAGGGAGGAAGCTCCG
+GGGCGAGCCCAAGACGCCTCCCGGGCGGTCGGGGCCCAGCGGCGGCGTTCGCAGTGGAGC
+CGGGCACCGGGCAGCGGCCGCGGAACACCAGCTTGGCGCAGGCTTCTCGGTCAGGAACGG
+TCCCGGGCCTCCCGCCCGCCTCCCTCCAGCCCCTCCGGGTCCCCTACTTCGCCCCGCCAG
+GCCCCCACGACCCTACTTCCCGCGGCCCCGGACGCCTCCTCACCTGCGAGCCGCCCTCCC
+GGAAGCTCCCGCCGCCGCTTCCGCTCTGCCGGAGCCGCTGGGTCCTAGCCCCGCCGCCCC
+CAGTCCGCCCGCGCCTCCGGGTCCTAACGCCGCCGCTCGCCCTCCACTGCGCCCTCCCCG
+AGCGCGGCTCCAGGACCCCGTCGACCCGGAGCGCTGTCCTGTCGGGCCGAGTCGCGGGCC
+TGGGCACGGAACTCACGCTCACTCCGAGCTCCCGACGTGCACACGGCTCCCATGCGTTGT
+CTTCCGAGCGTCAGGCCGCCCCTACCCGTGCTTTCTGCTCTGCAGACCCTCTTCCTAGAC
+CTCCGTCCTTTGTCCCATCGCTGCCTTCCCCTCAAGCTCAGGGCCAAGCTGTCCGCCAAC
+CTCGGCTCCTCCGGGCAGCCCTCGCCCGGGGTGCGCCCCGGGGCAGGACCCCCAGCCCAC
+GCCCAGGGCCCGCCCCTGCCCTCCAGCCCTACGCCTTGACCCGCTTTCCTGCGTCTCTCA
+GCCTACCTGACCTTGTCTTTACCTCTGTGGGCAGCTCCCTTGTGATCTGCTTAGTTCCCA
+CCCCCCTTTAAGAATTCAATAGAGaagccagacgcaaaactacagatatcgtatgagtcc
+agttttgtgaagtgcctagaatagtcaaaattcacagagacagaagcagtggtcgccagg
+aatggggaagcaaggcggagttgggcagctcgtgttcaatgggtagagtttcaggctggg
+gtgatggaagggtgctggaaatgagtggtagtgatggcggcacaacagtgtgaatctact
+taatcccactgaactgtatgctgaaaaatggtttagacggtgaattttaggttatgtatg
+ttttaccacaatttttaaaaaGCTAGTGAAAAGCTGGTAAAAAGAAAGAAAAGAGGCTTT
+TTTAAAAAGTTAAATATATAAAAAGAGCATCATCAGTCCAAAGTCCAGCAGTTGTCCCTC
+CTGGAATCCGTTGGCTTGCCTCCGGCATTTTTGGCCCTTGCCTTTtagggttgccagatt
+aaaagacaggatgcccagctagtttgaattttagataaacaacgaataatttcgtagcat
+aaatatgtcccaagcttagtttgggacatacttatgctaaaaaacattattggttgttta
+tctgagattcagaattaagcattttatattttatttgctgcctctggccaccctaCTCTC
+TTCCTAACACTCTCTCCCTCTCCCAGTTTTGTCCGCCTTCCCTGCCTCCTCTTCTGGGGG
+AGTTAGATCGAGTTGTAACAAGAACATGCCACTGTCTCGCTGGCTGCAGCGTGTGGTCCC
+CTTACCAGAGGTAAAGAAGAGATGGATCTCCACTCAtgttgtagacagaatgtttatgtc
+ctctccaaatgcttatgttgaaaccctaacccctaatgtgatggtatgtggagatgggcc
+tttggtaggtaattacggttagatgaggtcatggggtggggccctcattatagatctggt
+aagaaaagagaGCATTGtctctgtgtctccctctctctctctctctctctctctcatttc
+tctctatctcatttctctctctctcgctatctcatttttctctctctctctttctctcct
+ctgtcttttcccaccaagtgaggatgcgaagagaaggtggctgtctgcaaaccaggaaga
+gagccctcaccgggaacccgtccagctgccaccttgaacttggacttccaagcctccaga
+actgtgagggataaatgtatgattttaaagtcgcccagtgtgtggtattttgttttgact
+aatacaaCCTGAAAACATTTTCCCCTCACTCCACCTGAGCAATATCTGAGTGGCTTAAGG
+TACTCAGGACACAACAAAGGAGAAATGTCCCATGCACAAGGTGCACCCATGCCTGGGTAA
+AGCAGCCTGGCACAGAGGGAAGCACACAGGCTCAGggatctgctattcattctttgtgtg
+accctgggcaagccatgaatggagcttcagtcaccccatttgtaatgggatttaattgtg
+cttgccctgcctccttttgagggctgtagagaaaagatgtcaaagtattttgtaATCTgg
+ctgggcgtggtggctcatgcctgtaatcctagcactttggtaggctgacgcgagaggact
+gcttgagcccaagagtttgagatcagcctgggcaatattgtgagattccatctctacaaa
+aataaaataaaatagccagtcatggtgtcacacacctgtagtcccagctacatgggaggc
+tgaggcgggaggatcacttgagcttgggagatcgaggctgcagtgagctatgattgtacc
+actgcactccaggctgggcgacagagagagaccctgtctcagaaaaaaaaaaaaaaGTAC
+TTTGTAATCTGTAAGGTTTATTTCAACACACACAAAAAAAGTGTATATGCTCCACGATGC
+CTGTGAATATACACACACACCACATCATATACCAAGCCTGGCTGTGTCTTCTCACAAATG
+CACTGCTAGGCACCACCCCCAGTTCTAGAATCACACCAGCCAGTTCACCCTCCAGATGGT
+TCACCCTCAACTTCATAAAAGTTCCCTACCTAATCTACTGACAGGCTCATCCCCGACCTA
+ATTTTAAAGATTTCCTAGGAGCTGCAGTGGGAATCCTGGACCTCAGCCTGGACAAAGAAC
+AGCTGCAGGTCATTCTCATGTGTGGACACAGAAGCTCTGCCTGCCTTTGCTGGCCAGCTG
+GGCTGAGCGGGCCTGGGAATTAAGGCTGCAGGGTTGGTCCCAGGCAGTCTTGCTGAAGCT
+TGCCACATCCCCCAGCCTCCTGGATTTGCCAGGATCCAAGAGCATGGACTTTAGGAATTC
+CTGGTGGAGGAGTGAAGAAAATGTGACAGGGTGTCCTAAGCCCCGATCTACAGGAAGAAA
+ACTGGAAATAAGACTGAGGACTTAGTTTAAGATGTTCCTACTCAGCCTCTAGCTTTTGTG
+CTACAGTTCTGGGAACAGACTCCTCTCTCCTGAAAACCACTTCCCTCCGCAGCATTAGAT
+TTCACCAAGATGTCTTGCTTGTGGGAAAGACTTCCAAGGATGCCTGGAGAGAGGAGGATG
+GAAATGTCCTGCTCTCTAAACAGATAGACAGATGCAGCCAGACAGAAAATAGTTTATCTT
+GCTGAGGTTTCTAATGTATTTGAAAGAGGCCTGGGTCTAGAAGTCTACCCAGAGGGCTCT
+GTGTTGTGCACGCAAAGATAAGAACCTTCCCTGTGGGAGTTCCAGAGCCAGTTTTCATAA
+ACACCCATCGGTGACTGTGTTCAGAGTGAGTTCACACCATCCTGACCTGCCCTGAGTTAG
+ACCTTACATGGTCTTCCTCCTCTAGGAAGCCTCTGCAGCCCAGGAACCTCCCCTTATCGG
+AAATGAACAGCATTTGAAGCTTCACCAGACAGACCAGACAGCTTAGCCCTCGTGTTGTGC
+CATGTGGGTTGTTCTCTGAGAGGcaggagagcatagtggttactaggaagggaaggactt
+tgggactagactgcctcggctggagtcctctttctgcttcatagccacgtgatcctaggc
+atgttacctgtgcctcagttttcactctgtcaatatgtaataactgaatctgtctttgtg
+gtgaggattcagtgagttaacatatttgaagtgcttaaaaATGAGGCTTGtgtccataga
+ttaatgagtgaatacacaaatggtgatatggacatacagtggagtattagtcataaaaag
+gaaggcagagctgatccatggcaccatgtgacagaacctcaaaagcattaggttaagtgg
+aagaagccagacacaggtcacctattgtgtaattccatttataggaaatatacagaatat
+gtaaatccgtggagaaagaaagccgatttccaggggctaaggggaggggagaatgggaag
+tggctgcttcatgggtacaaggtttcattttgagctgatgaaaatgttttggaactacat
+agagatagtgttggcacaacatggtgaatgtactgaatgccactgattgttcaatttaaa
+atggtcaaacttatatgaatttcacctccattaaaaaaaAAAAAAAAGgaccagatgtgg
+ttgctcacacccataatcccaacactttggaaAAAGGTGAAAGTTTTTTTTtcttttttt
+ttttatatacttaagttctagggtacatgtgcataatgtgcaggttggatacatagatat
+gcgtgtgccatgttggtttgctgcacccatcaacttgtcatttacattaggtatttcttc
+taatgctatccctcccccagccccccacccactgacaggccccagtgtatgatgttctct
+gccccatgtccaagcgttctcattgttcaattcccacctgtgagtgagaacatgcagtgt
+ttggttttctgtctttgtgatagtttgctcagaatgatggtttccagcttcatccatgtc
+cctgcaaaggacatgaactcatcctttttaatggctgcatagtatcccatggtatatatg
+tgccacattctcttaatccagtctgtcattgatggacatttgggttggttcaaagtcttt
+gctattgtgaatactgccacaataaacatacatgtgcatgtgtctttatagtagcacgat
+ttataatcctttgggtatatacccTAAGACctgggacgcatttaaagcagtgtgtaaaga
+gacatttatagcactaaatgcccacaagagaCCTCTGCCTGAGAACGTGGGTTTCAGCCT
+AAGAGTTGTAATATGTGTGCCCATTCACAGGTGCTGCATCAGAGTCCCAGGTGGGAAGAA
+GGCAAGCATACACAAAAATGGTAAaaggcagaaaggagcccagtctcgttctttttaaga
+agttttcctaagaatctccacccagcgacttgctctcacatcttcttggccagcactgga
+ccacacaactccttctagatacagaggagTCCTAGGATTCTATGAGAAAGAAGGGGAGGG
+TGGGCAAAGGGCAGCCAGCTGTGCAGCATCTGCTGGAGACACCTAACCCTTGGTGGAGGG
+GTTGTGGTGCTGGgagaaggctttctggacggtgtgacagcagagataaacttaaaggcc
+aagtaggagttaccctggtgaagcagggcagggttacaagcattccagcaacatgaagca
+gcaGGAGtgttttaattaaaagaaggcagttgctgtaaccaactataaacaaataaaggc
+ttaaacacaatggaagtttatttctcactaagggaacatccaaatccatgatactttaag
+tcagggacccaggttcctcccatctatggttctgccatcactaatctgggtcttccacaa
+ttgccgtgctccttggaggtgggaagagcaggcggaggacacgtgggaggttttagggac
+aagcctggaggcagcatgcgtcactcccatgcagagtccattggccaatgctggctccga
+tggccacatctcactgcaggggcagctgggaaatacagtctggctgtctacccaggagga
+agagcagccagtttctgctgCTGATGATCAGGAGGTGGAGAAAATGTTCAGTCAGGCAGG
+GAGTGGGAATAGACAAGACCACAAGCAGCTTGGTGCCTCTGAAAGGGAGAGGGGTGGAGG
+GGAGACTAGAGAGGTGGGTAGGAATACTGGATTCCACTGACCACGTGCTGGATGTCACGC
+TTAGCCCTCCTGCTCTGTGCCGGGTTAGGCACCTGGTGTTTTACGTACATAATCTCAATT
+CTGTGAGGGCATCCGACCTGTGGGAAAAGAGCTGTTTGTTTCAAATGCCAGTCCTGCTTC
+CTAACAAGTGTTTAGAGCTTAATCGTGTTCAAAAtacatatacaatgtttaatacttaca
+agaatttggtggggaaaatattaccatctttcccttttgtgattggagaaaaatgaggct
+ttgaagggtttaagaacttgcccaaggtcggccaggtgcagtggctcatgtctataatcc
+caacactttgggaggctgaggtgggaggatcgcttgaggccaggagttcaagaccagcct
+gagcaacatagtgagactttgtctctataaaaaataaataaataaataaaaaCAACTTGT
+CCAAGGTCAGACAGGCAGCCTCTTAGTAAGCACACATATCCTCTATATTATACTACCTCT
+CATGGAGGATCTCCTGTGTTCTACAAATAGTCTGGACTTGAGCCAGAATGTGTTATAATC
+CTGGGATCACGGCCAGTGGGCTTAGAAGAAGCCATCTCTTTCTCATGCCAAGATGAGGCT
+CCCCCAGATTTGCTCAGACTTACCTATAGTCAGCAGCATCGGGGGTCAGGAAAGACTTCA
+CGAAGCCATAAATGCATCCTTCTCGGGGCAGCACCTGGCTCTCCCAGGTGAGAGAGGACT
+CCATTTTCACAGGCAGGCGTGGGAGCTTCAGCACCCATCTCTGGGCCCAGAATGACCCAC
+TGGAGACCTTACAGCTCTCCTGTCACCCCCAATTCCTGCCCCCTCTGCAGCCTTGGAGGA
+GAATGGAGCTGAAGGGCCTGCCCTCTGTAGGGTGAGAAAGGGAGGCTAAAGCCTGGTGCC
+CACTGCCCTGGCTGCTCCGCATTGCAGGAGCTGCGCCCTTCCTTTCCTGGCACAGGGTCC
+ACAGCCCCGAAACCCCGTTGTGTGGGAGCTGGGCACAGGGCAGCAGGACTAATCCTTGGA
+ACAGCTCAGGGAGGATTATCCCAGCCACTGTCAGCAGCGGTGCAGCTGGCTCATTCCCAT
+ATAGGGGGAGGCCAGAGCCAGGGGCCTGCCACAAGTTGGAAGGCTGGGGAAGGGGAGGCC
+AGCAGAGGTGTCCTGGCTGTGGGTGGCTCTGAGGGGGCTCTCAGGGGTGGGGCTAAATCT
+CAGGGGCAGGATTATGTAAATCAAACCAATTCTAGCCACAGATTTAAAGTTTGGAAAAAA
+AAAAAAACCCAGCCTGGCGGAAAGAATTTAAATTATAAAAACTTAGAAGTATGGAATGTG
+AAATCATCCTGTAGGTGCTTATTTAACAACGAAATCATCCCGACACAATGAGCCATATGT
+GAAAAGTCATCCTTCCCCAACACATCCCCCAACAGGCACTCCTCAAGCCTCTCCCACCCA
+AGTGCTGGCATCCTCCCTGTCCTGCTTCACCTGAGACACCCCTTGTCTCATTAGACATGC
+AACTACGGGAGGGGTGACAGGAAGACAAGACACTATTTCCTCAGGCCCAGTTTGGTGTGG
+GGAGAAAGCCTCCTGATCCTGAAAGCAAGAATTTGACCAGAGCAGAAGTAATCAGTATGC
+AGATTGATTCTGTGGTATGTTAATGTTTATGCATAGATTATGAGGACCAGGTGAAAAGTG
+GGCCAGGGGAGCCAGATGTGTGTGTGAGTCATGGGTGGCTGAGATGAGGACAGGAGGGAA
+ACTGGTTTGGAGGGTGCTGGCGATGGGGTGGGGGTGCCAGGAGGAAGGGAGGCTAGTTGT
+TTGAATGTCTGCATGAAAAAGCGGACGACAGCGGGGTCTGGGTGAATTCGGGCAACCATT
+TGGACCGTGGAGAAAACTGCCTGCGTGCGGCTGAGGACCTGCACTATTAATTTGTTTTTT
+AGCTAAGGCAAAGATAAATATAAAAACtgatactccacccagttaccagaaaacatttag
+gtatgtgtgagacaacttgggtatgtgaacctaccttttcaatgtaaattcagtgaaatc
+taagtgcagatcccatatttccaataaaaaggtaacatccaaactcagatgtcctatgag
+tataaaatacacaaagatcttctggacttagtatgaaaagggattttttttttgtcaggt
+acctcactagttatttttaaaataggattgcatgttgaaatgataatcttttggatatat
+tgggttaaataaatttattattaaagttaatttcacttaaaaatgtttaatgtagctact
+agaaattttaaaattaagcatgttgctcaccttatgtttctattggacggctctCTCTAG
+ATACAAAGGCTGCCAAGAGGGACCTCACTCTAGCTTCAGGGAGAAGAGAGGAATTAGCAA
+GGCCAAGCAGAGGCTCCTGAGGGCAGGGCCAAGGGCGGCTTGGTGGGGTGGGGATGGGAT
+GCACAGAGATAACTCCAACCCTTAAGAAGGTGTTTCCTAGAGCAGGCTGTGACCTGTCAG
+TTTATATACTGAGGCTTAGGAGCCTCTTGGATGCCCCCAGATCTGCACCCCTGAATTGCC
+CTGTGCCCCTGCCGTCTTTGTTCCTGTGCTGGCATAGTGGTCTCACCTCCGGCAGtatca
+ccaccactgggcacaagcttctccagcacagcaactgtgtcttatttctccttgtactcc
+cagtgttcacaccatgctgcactcacagaagactcttcgttgatattttgtggacagaga
+gaatGCCTGTGAGAGTGGGCTGAAGTGTGCGTTGGGCTCCAGAGACCTTAAGGAGGGGAG
+ACCAGGTCCTGAGTAAAGTTGAAGGGGAGGGGCTGAGTCCTGCTAGCCAGGAGTCTCATC
+CCCTGGGGAAGTTCCAGGGACCCCTCAGAAGTGCAAGGGGACGGTGTTAGTGTTAGTCCA
+GTAACACAGCCCAGAGCCTGCcttccacgtgggtttgacaggagcctcctaactgctctt
+ctgcttccatttttgccccttcagtctattctcaacagggaagccagaggcatccttaac
+catgtcagatcatgtggctcctcagctcaaagccTCATCTCAGAGGAAAGCTCTGGTCCC
+TTAGAAATGGCCCAAGTGGTGACAGACAGACTCTAAGGtgagcagactgttgctagatat
+ctgggctcggaggactcgccactgctcaaaggcagtgaggattttcgcactagaagctgg
+aggacagggatccttgttaggtaggagcagaaagcttagaaaagtggtctcctgcagtta
+cgtggcaaacacatcatgtaagtgataaattgggtatgcagttgaggagatttccaagta
+aaatgttgaggatgctgcctggtttcttcttactgcttataatatagtgtgagagaagag
+agataaattgagaaagagactggtttttaaactgttaaaattgaatcaggacttgatgat
+tttgaaaattgtcagtctccccacatggaaaaagatgctgaaattaacaaatggcttctg
+agcatgtggcatagggtgtaactgtacagtcttttgtgattatgcataaagatcaaagga
+tgggagtagcaatgagtcacacagaggtctgttgcaagagattacaagggtgtaccatgc
+agaacctctccaccaaaccttagggcccttgggaagcttcagtgagttaccctgggggcc
+atcttggcaggagctgaaggtagaaaggtagagtttatctctaaaagattcatgggtatg
+gctcttgacaaatcgactatgagccccaccgaaacccacagaggacaggcaaagggtttg
+ggaaagctgtttcacccacagtgctggcagattggtctgtaggggacagagtgcaaaatg
+aaagaagactgtcagagaccccaaactctgctgtcaagaagaaggctgataaaactactt
+ggctgcaaacacgtggatctttcgtgagaaaagaaggatgacccagaggcagaagcccag
+aaggcagagccaagagacatggaatcttcccacatcttaaaacctgtttagggaacacca
+gcatctgtccagctggatttcagaaccaccattccttcatccttcccctgctgcctcttt
+ctgaacagcaatgtctcaagctttacccaccattgtgtgttgcatatgtagggggcagat
+agcttgtatctttagttttccagatcagaggaacatccaaagaaatctgttctacaccta
+aacccgatttagatgagattcgggactgtgagcatgaagggatctcaagaggggtgaatg
+tgttttgcatgcacaagggacaggagtcttggggacagaggacaggctgtggtggcagat
+actaaggtgacccccacaacccccacctctgccattcacacccttgaataatccccttct
+ctggttgtaagcagaacctgtggcttgcttatgaaggaggcggtatatatgtgattcatg
+tactgatcatattgtataagatcactggctggatgcagtggctcgtgcctgtaatcccaa
+cactttgggaggctgaggcgggtggatcacctgaggtcaggagttcgagaccaggctggc
+caacatggcaaaaccccgcctctactaaaaatacaaaaattagccaggcatagtggtgca
+cgcctgtaatcacagctactcaagaggctgaagcaggagaattgcttgaactcaggaggt
+ggaggtggcagtgagccaagatcgtgccactgcactccagcctcagtgacagagcgagac
+tctgtctcaaaaaataaataaataaaatgttaagatcataacctgtctttctggggactc
+tctcttgacgcctttgaagaagcaggctgccatgttgcaagctgcctcatggaggggatc
+agctgcgaggagctaagagccccctccagtcgatgctcaccaggaagctgaggtcttgtg
+tccagcaccctgcatagaactgaatgctgccatgtgagcttggaagcagagccatccaca
+cagctgagccctagatgagaacccagtgctggctgacaccctgatggcaccttacagagg
+accagttaggctgtgccaactcctgacctgcagaagctggggaacactgggtcgtatttg
+cagctgctggatttgtgggaatttgtcacacagcaatTGGGAGTCACACAGCCTGTGACG
+CCCCAACAATCCACAcctcctgcatctccctgccttcacttcctagcacactgccctgac
+tccctctgccgcagccacgctggccctctgctgttcttcgaagccaccagggctgcattg
+gctcccagcctttgctctcactgctttctcctcctagagagcccttcctgcatgtatatg
+tttgactcactcccttgcctccttcagacttgtacttaaaaatctcagtaagcatttccc
+tggctacccttttaaaaattgcaacccacttccatccccatccccaacatgccatatttc
+ctttcttcttcttccttcttcctttttttttttttttttttgacacaggttctctgtcac
+ccagcctggagtgcagtgacatgatctcggctcactgcaacctctgcctcccCAGGCAag
+aaaaggggaggatgccaataaaggatgcattgatttgtatttactacagtggacatcaag
+ggcacattcttgctgtggccatcaagagactgtataaattctatgacttgtagttgtccc
+acttaagaaacaaagaagctgtgcatttctttactggtctagagctgctctagggcattt
+tctctacagcaattctaggtttccccaccttgtgagtttagctttttctatattcaaaga
+aaagtcctcagccagagattctcaggagcttatagaacaatccaaactcttgggaatatt
+aagtggagaggggtacgtgcaagacaccaacagcACTAGAAACAGTCCACATCTTTCCAT
+GCGTGGAGGAGTTTATGCTCTATGTGAGTTCACTCCATCATTAATTCTTCAAACACAAGA
+GTGTTAAAGGAACAAGAGTTAATGGGTCCTGTCATTACACTTGTTCCCAGGATGACATTC
+TTCATCTTCCTCTTCTACAACCTGTTCTATATTCCCCTCATGTTTATCCAGTGCTTCTGC
+TAGTCTAGTTCACTTCCAAAGACCCATGATTACCATGGCCCTGTCAGGCTGTAATTGCTG
+CAATTTCCAATTTACAATTGTCATCATCTATGGTTGATAAAGgtatagcaatatttctat
+ttcctcatgataatgaaggtcaattacaactgccagtataataacttatttctttgtctg
+ccaacctacatacacaaggaagccaaaatgacagggagctactaaaactttattcttatt
+ggaatgcttactatgtacccagaagaagcattctccctactccagcagagcttaatgctg
+taggtccaggaagctcaaattctccaagggagttttagtgagaggagccactctcaccct
+ctgcccttggtttacaaacctgtatattctaggacccaatatcttacaatgtccattggt
+tcaaagtataacatgttaaagcacagagccccaactctgaaaagtaccatccctaaattg
+gcatttagttgcacctttatatccacctttaaaagaaatatcttttaatgttctatcaga
+ctgatagattctgtttaatatagtatattatagcaccagtggatcatttggttgtatgca
+tattattgtaccttctctgctacaaaatatattcctttgtcctaaggtgtgttacaaaga
+acattaggcattctatgcatctttggatagtttaatggccaagacattgatggcaggaga
+gtcaaagccacaggtggaaaacacatttatcccagtaagaacaaattgctattcttccac
+tgtagagagggtaaacaatgtgccattacgttgccaattgaatgcctcaatcatgtcaag
+ggctgaacatctatgactgtttctgaaaggtcaaacattcaacagaggctgtagctagaa
+ctgccttaatgataagagatcatgctgaattacccatgcaaaaccttaatacttgacact
+tatcactactttattcaagagcctattgtgcaagcataagtggctgagTCAGGTTCTCAA
+CTCTGCTCATTAATACTATGCTTGGAGTATACAGTAAGATAAGAAACATAAATAAGAAGT
+GTACATTTGTTTCTTCCTGTTTTCTTCTGGCTATTGGATCAATTACATCCCATCTTAAGC
+TGACCCCTGTGTAATTAATCAATATCCGTTTTAAGCAGCAATCCATAGTTGTGCAGAAAT
+TAGAAAACTGACCCACACAGAAAAACTAATTGTGAGAACCAATATTATACTAAATTCATT
+TGACAATTCTCAGCAAAGTGCTGGGTTGATCTCTATTTACGCTTTTCTTAAACACACAAA
+ATACAAAAGTTAACCCATATGGAATGCAATGGAGGAAATCAATGACATATCAGATCTAGA
+AACTAATCAATTAGCAATCAGGAAGGAGTTGTGGTAGGAAGTCTGTGCTGTTGAATGTAC
+ACTAATCAATGATTCCTTAAATTATTCACAATAAAAAAAAAGATTAGAATAGTTTTTTTA
+AAAAAAAAGCCCAGAAACTAATCTAAGTTTTGTCTGGTAATAAAGGTATATTTTCAAAAG
+AGAGGTAAATAGATCCACATACTGTGGAGGGAATAAAATACTTTTTGAAAAACAAACAAC
+AAGTTGGATTTTTAGACACATAGAAATTGAATATGTACATTTATAAATATTTTTGGATTG
+AACTATTTCAAAATTATACCATAAAATAACTTGTAAAAATGTAGGCAAAATGTATATAAT
+TATGGCATGAGGTATGCAACTTTAGGCAAGGAAGCAAAAGCAGAAACCATGAAAAAAGTC
+TAAATTTTACCATATTGAATTTAAATTTTCAAAAACAAAAATAAAGACAAAGTGGGAAAA
+ATATGTATGCTTCATGTGTGACAAGCCACTGATACCTATTAAATATGAAGAATATTATAA
+ATCATATCAATAACCACAACATTCAAGCTGTCAGTTTGAATAGACaatgtaaatgacaaa
+actacatactcaacaagataacagcaaaccagcttcgacagcacgttaaaggggtcatac
+aacataatcgagtagaatttatctctgagatgcaagaatggttcaaaatatggaaaccaa
+taaatgtgatatgccacactaacagaataaaaaataaaaatcatattatcatctcaatag
+atgcagaaaaagcattaacaaaagtaaacattctttcataataagacatcagataaaaca
+aattaggaatagaaggaatgtaccgcaacacaataaaggccatatataacaagcccacag
+ctaacatcataatagtaaaatcatcacactggtaaaaaaaatgaaagcttttcctctaag
+gtcagaaataatataaaggttcccactcttgctatttctattccatatcgtactaaaagt
+cctagccaggacaattagacaaaataaaaataaaaacacccaaattggaaagatagaagc
+aaacttttctgtttacagataacataatcttatatgtagaaaccccttaaaacttcagca
+aaaaaaaaaaaaaaactacagagctagtaaattcagtgaagttgcagaatacaaaatcaa
+catacaaaaatcagtagtgtctctatacactaataaggacttaacagagaaagaagttaa
+gaaaacaataccactaacaatagaatccaaaaaataaaatacttaggaataaattttacc
+aaacatctgtacactaaaaactataaaacattgaaaaaagaagttgaataagacacatat
+aaatagaaagctatctcatgttaatagattagaaaaagtaatattgttaagatgtcctca
+ctacttaaagcaatttatagatctaatgcatttattgcaatctcttcaaaatcccaaagg
+tatttttgacagaaataaaaaaaaaattctaaaatatgcatgaaaccacaaaagactgtg
+aatagctaaagcaatcttgagcaagatgaacaacactggaagcatcacactaccttattt
+caaaatctactacaaagctatagtgatcaaagcaacatgatactgtcataaaaacacaca
+gataaacctatggaatggaataaagagcacagaaataagtccacacatttacattcaatt
+gattttcaacaacaatgtcaagaagacaatggggaaaagacaatctcttcaataaatgat
+gctggaaaaactatatatccacatgcagaagaatgcagttgaatcctgatttcataccat
+atgcaaaattcaactggaaatggattaaatacaaatttaaaacatgaaatggtataacta
+ttagaacaaaacatagaaaatattcttcctgacattggtttgggccatcatttttctgat
+atgactctaaaagcacaggcaaaaaaagaaaaaatagacaaatgagactatgccaaatta
+aaaaatttctaacaacaaaagaaacgatcaatagagtgaaaaagataacctcttgaatgg
+gagaaatatttgcaaactactcatccaaccggggattgatatccagaatatacaagtaac
+acaaatatgtcaaaagtaaaataaataaataaataaataaataaataaattaaataaatt
+atttaaaaatcggcagaggacaggaatagacatttctcaggagacaacatacaaagggcc
+acagatacatcaaaaaatgctcaacatcactatttgtcagggaagtactaattaaaacca
+aaatgagatgtcccctcaaacctgttagaatggctattatcaaaaagatgaaagatagca
+actatcagagaggatgatagaaaagggaacccttgcatcatgtacaaattaaaaatagaa
+ctatcacatgatccaagaatcctacttctgggtatatagccaaaggaattgaaatcaata
+tgtcaaagggatatctgcactcctatgttattgcagcatgttcacaatggccaagatata
+gaatcaacctaactgttcatagacagatgaatggataaatgaaatgtgatatggaaaatt
+attcagccttaaaaacagtaggaaattctgtcatttgagacaacgtggatgaacctagag
+gacattaagctaagtgaaataagctagacacagaaagacaaatattgcatgatctcactt
+agaatctaaaaaatctgaactcatagaagcagagaatagtatgatggttactagggttat
+ctggcagggagaggatgaggaaatgggacattgttaataaaaggaaaaaaattcaattag
+taggattacattcaggggacccaatatacgacatgttgactgtaattaataatgtattgt
+atgcttgaaaattgctaatacagtatattgtaaatgttaatatgaggtaatatatgtgtt
+aattaacttgatttattcattcaacaacatacacatatattaaaacatcacactgtattc
+cacaaatatatataatttttgtcaattaaaaaaTAATTTTTAAAAATGAGAAACAAAAAA
+GCTGACATTTTCAGATTAAAAAAATTATACAGAAGAATTAATTCATTAAAGTAAAAACAA
+ATGTGGGAAAATGGTTTTTAAATATAATTTAAACCAAATTTAAAATAAGCATATaaagac
+tatggacaaaacaagaaatccaaataaaaaataaacatatgaagaatattcaaactcact
+ttttatcaaagaaatgtaaattTTAAAATATAGCATTGCTATTGTGTTTTCATAAATAAT
+AATATATCATGGATGAGCCTGTGAGGAAACAGACACTCATACTCTGCAAAGCAATGACTA
+Agataattatgtcagatcatgaattacgttaattagcttgatggtggtcactgtttcacg
+ataaatatacatatgtatcaaaacatcacattacacaccataaagatatataacttgtta
+tCAAAAAGAAATATAGCAGttaaaatttaaaatttttaaaaaaCGTCTTTTTGAGGTTCG
+TACCTCACTTAAGTCACACTGTTCAAAATATTCATGCACTCATTTCTCTCATTCATGTGT
+TAATGTACAGGGTACGGGCCACTATAAATTCCTTCAGCAACTGGAAAGGAAACTTTATGT
+ACTGAGTGCTCAGAGTTGTATTAACTTTTTTTTTTTTTtgagcagcagcaagatttattg
+tgaagagtgaaagaacaaagcttccacagtgtggaaggggacccgagcggtttgccCAGT
+TGTATTAACTTCTAATTCAACACTTTAAGATTCTTAGCATTATTGCAGACAACATcagct
+tcacaagtgtgtgtcctgtgcagttgaacaagatcccacacttaaaaggatcctacactt
+tttttaatgctctgctgtttctgccttgaaattcttaacaatttttttaaccaaagtcct
+cacaaattcagtttacattagccctgcaatcatgtagacatcctgATTCCAGACAATGTG
+TCTGGAGGCAGGGTTTACAGGACTTCAAGAACCTTACCTTCTCAACTTTCATCTGCATCT
+TTACTCCCAACTATATATGAAGATGATGAAGATAGATATGGATGGTGCTTCTACCATACC
+CTCTTCCTCTGCCAAACTTCCTTGATCTAGGATAAggtcagtaaacttcttccgtaaaag
+gccaaaagtaaatattataggctctacaggccctagagtgtctgtcataactactcaact
+cttattgtagcataaaaactgtcaacagacaatacagaaacaaatgagtgtgactgggtt
+ccagtgaaactttatttacaaaagatttgtcccatgagtcaaatttaccacctccAGATC
+TAGAGAAACAGTTTTGAGCCCTTTTATTTTGCTCAACAGTTAAGCATGGCTCCATGTCCC
+TTATATTTAGTCAGAACTCGGTATGTTTTAAGGAAAGAATGGTTACACGAAGACATACAT
+TCATTCATTTATACAACACATTTTCAGTGTTGAATGATAAATTTTGGAATAGTTAACAGA
+TGATAAAAGTGTTGTTTTCAGTCATCCCTATCCAATGAAGTAAAAAAAAAAGTGTTGAAT
+GGGAAGAAATCAAGAATAGTTATACGAATATCACCATTGCATTAAAGCTCTCTTCCTTGT
+TTCTAAAAGAATATCTTGACACACATTAAGCTCACTGACCCCCACACCATGAATGAGGGC
+ATCTTCAACAATGGTGGATGACGTCTTAGTTTCCCTCAACTCAGTTAATCTAAGTAAGCT
+CATGGTATCACTTTCCTGTCCTAGAGGGAACATATTTCCTGCATTTTTCTTTTTTTCCTT
+ACTTTCCATCACCAAGTAACTCTTCTGATATTTTTTCTCTTGAGAAAATTAATATGACTC
+ATAGATCTGGTTCCCAAGAGAAATCAATGGAGGCCTGGTTACAAGGATCTAAGAAGCATC
+AATGGGTCACTAACATCTAGTGGTACTAATTAACTCTGTTAATCATTGGGAAGAAAATGT
+ATATATACTTTTGTCTTGGAGCTGATTCTACTAGAAAGCAGAAATCAAAATGATCAGTTT
+CCCAGTGTCACTACTGCACACCCTGGAACAGAACAGGTAGGTCAGAAAAACGCTCCCAAA
+GTTTAGCAATGTCAAGGCAATCTCTCTCTTCTTACATTTCCCTTCAACCTTCTATCTCCT
+CCACTTTTCTGTTTTCCTCCTATCTCCAATTATTTCAATCCTCAGAGCATTATTCTTACA
+ATCTTAATCACTAAATTATATTACACCCGTTAAAGGAGAGATTTCTAAATGCATTGACAT
+TTGTACTGTCTCTCTTTGGAGAATTAGTATTATAAGGATCTGTTATCTCTTGTCACCTTC
+CTTATGTCATATGATATGTCACATTTCCCACTGCGGAGACCAAACATGTTCACATCGTGT
+GCGTTCCATTTTCCTAATGGAAAGTGGGGGGAAGTGATTTTCTGTCCTCATATAGAGAAT
+GCTGGGGCCATTCCCTCTGTATGCCATATTTGATAAAGCATTTGATAATCTTAGTCAATG
+CCTGGGCCAAGAATTAAAGGGGTAATTATCAGAATGAAAATGGTTTAATGAAACTGTGTC
+TATCAGTTCTGAAAAGGGCCTCTATCACAATGAACTAAGGTAGTTATGAATAGAGCTAAa
+acttaggcaacaccatcctggacataggaacgggcaaagatttcatgacaaagacacgga
+aaccaatcacaacaaaagcaaaaattgagaagtggaatctaataaaacaatagcttctgc
+acagcaaaagaagctaccaacaaagtaaacagacaacctacagaatgggagaaaatattt
+gccaactgtaagtctgacaaaaatctaatatctggcagctataaggaacttaaatttaca
+agacaaaaacaaccccattaaaaagtgggcaaagaacatgaatagacactctcaaaagaa
+gatatacatatggttaacaagcatatgaaaaaaaagctcaatatactgagcattagagaa
+atgcaaatcaaaaccatattgagatatcatctcataccaggcagaatggctattattaaa
+aagtcaaaaataacagatatcggtgaggttacagagaaaagggaacacttatacactgtt
+ggtgggactgtaaattatttcaaccattgtggaaagcagtatgggatggcgattcctcaa
+aaagccaaaaacagaactatcattcaacccagcaattccattactgggtatatacccaga
+agaatataaatcgttctaccataaagacgcatgcatgagaatgttcattgcagcactact
+cacaatagcagagacatggaatcaacttaaatgcccatcagtaacagactggataaagaa
+agtgtggtacagatacaccgtggattactatgcagccataaaaaagaacaagatcatgtc
+tttgacaggaacatggatggagctggaggctactatccttagcaagctaaggcaggaaca
+gaaatccaaataccgcatgttctcacttatgagcgtgagataaatgatgagaacttgtaa
+acacaaagaaggaaacaacaggcagtggggtctacttgaggacgacgggaagagggagag
+gagcagaaaagataactactgactaccgggcgctacctgggggatgaaacaatctgtaca
+acgaacccccaggacatgagtttacctatgtaacaaaccttcacgtgtacccccgaacct
+aaaataaaagtcaaaaagaaaAAGAAAAAAAGAAAAATCCATGCATATGATACATCAGTT
+AACAAGGCACTGGTGAAATTAATTTTAAGTATTATTGTCTCTTTGTGTTTTTGGTCTCAG
+AAAAGTTACGATTTCCCTTAGTTCCTTAGGGCAGAGAGAATCTTCAATCACTGAAGTCAG
+GAGACACACATTCTATCTGATTTTCTACATTATCTGTTTGAAAAGGTTACCCACTTATTA
+GTGTTAAAGCCAAGATATCCAGCAAGGATAGCAACCAACTCTTAAGGTACTCTCCCTTAG
+GAGGATTCCTGATTCTTTAATGTTTTCTAAAAAAGCAAAACAAACAAACAAACAAAACAA
+AACACTAAATGTTTTCTCTTTCAACTTATTTGAATACACTCTTTTCTCACTGCTCTGAGC
+ATGAATTCAATATTTCAGGGCAAACTAACTGAATGTTAGAACCAACTCCTGATAAGTCTT
+GAACAAAAGATAGGATCCTCTATAAACAGGTTAATCGCCACGACATAGTAGTATTTAGAG
+TTACTAGTAAGCCTGATGCCACTACACAATTCTAGCTTTTCTCTTTAGGATGATTGTTTC
+ATTCAGTCTTATCTCTTTTAGAAAACATAGGaaaaaattatttaataataaaatttaatt
+GGCAAAATGAAGGTATGGCTTATAAGAGTGTTTTCCTATTGTTTTCAGTGTAGGACTCAC
+TGTTCTAAATAACTGGGACACCCAAGGATTCTGTAAAATGCCATCCAGTTATCATTTATA
+TTCCCTAACTCAAAATTCATTCACATGTATTCATTTTTTTCTAAACAAATTAGCATGTAG
+AATTCTGGTTAAAATTTGGCATAGAACACCCGGGTATTTTTTCATAATGCACCCAATAAC
+TGTCATTCACTAATTGAGAATGGTGATTTAACAAAGGATAATAAAGTTATGAAACCAATG
+CCACAAAACATCTGTCTCTAACTGgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtAAGA
+GGGAGAGAGAGAAAATTTCACTCCCTCCATAAATCTCACAGTATTCTTTTCTTtttcctt
+tcctttccttgctcttctttctctcctattgctttcctttcatttccttCTCATAAAAGA
+AAAATAACAATATAGAAAATAACAAAATATAGATGGTCAACCTTTTTAATATTAAGGTTA
+CCTAAAATGCCATTATCCAAAGTGGTTCTCTAGAGATGCTGATGTATATACTTACATATT
+TTACAGTGTATTCAAATAAAGAGTATATTACATAAGACATATCCTTTTGTAACCAACTTT
+TGTCATTAACAATTTACTGGACTTGTCAACAAACCTAAATCTGTATCGTCTATAATGGCT
+ACGTTCATTTTGGTATGAATCTTAATTACCCCTTTCTGCATTATTTAATGATTTTCTCAT
+ATGTCACTCTTAAATGTACTTCTAATTTTTCACTTTACATCACATAATGAATGGATCCAA
+ATATGTTATGGATAGATATCTTCAAACTTTCTACTTACAAGTAGTGATAATAACAGATGT
+TCTCTCTAAAGTGTAGTTGGTATCAATTTTACTGACCTTTAAAAATATCTTAATGGGACA
+AAGTTCAAATATTTGATGACCAGCTATCGTGACCTTTATCTCTGTGGCTCTGTGGGCCTG
+TAGTTTTTACGTGCTTTTAGTGTATCATGATTAAATATTTTGTTTTAGTAAAGACACCAT
+TATTTCCCAACTTCATATTCAAATTGTCAAAGGTATTAATCCTAGAGCAGAACTCTCAAA
+AGCACCAACTCTGATTCCTAACAAAGCATGGAAAAGCCCTCTCTCTGAGTTTCAGATACT
+CTTTTTTGTGGGGGTTGAGTTTCACTTTATTTAAAGTGAGTCTTAATCCTCCAACAAGTC
+AACAAGTGATTGGCTGGAATCACACGTATTGGAAAACCAGCGGAAGAGTAAGTCTTTGTA
+TTTTATGCTACTGTACCTCTGGGATTAATTGCTCTTTCCCTCATTGGCCAGTCACTCTTA
+GTGTGTGATTAATGCCTGAGACTGTGTGAAGTAAGAGATGGATCAGAggccgggcgcggg
+ggctcgcgcctgtcatcccagcactttgggaggccgaggcgggcggatcacgaggtcagg
+agatcgagaccatcctggctaacacggggaaaccccgtctccactaaaaatacaaaaagt
+tagccgggcgcggtggcgggcgcctgcggtcccagctgctggggaggccgaggcgggagc
+atggcgggaaccgggaggcggagcctgcagtgagccgagatggcgccaccgcactccagc
+ctgggcgacccagcgagactccgcctcaaaaaaaaaaaaagaaGATTGATCAGAGAGTAC
+CTCCCCTAAGGGTACATGCAGATAAATACAGTTAAGGCGATTAACATTTCAAATACGGTG
+ACTGTTTCTTACGTGGACGACGTTGTGTTGAACATGGGTGAGTAAGACTGAAGCAGCCGT
+AATTACTGCACGATGCGCATGGTAAAGAAGCACTCCGTTAGGGAAATTATATTCTTTGCC
+CCTCTAATCCTTCACTCCACCTGCCATATTCCCACATGATTTTTTTCTTTGCTGTTCTTG
+TCTAATTGttattaataattaataaataaCTTATGATCTAATTGTTATTAATAATAACTT
+ATCATCACATGatttattaataaattaataaataacttattatCACCGCATTTCCCCAAT
+TCATTTATCTTTCTTTCATTTTCTCTCTTTGTGTGTTTTCTGTCTTCATATTTCAGCACT
+TGCCACATATTTCCCACAAAATCATTTATGGTCAAACAACACTTCAACGTGTAGCATTTG
+TATTTCTCAATTCTTCCTCACTTTCTTCCTTCAGAATACTAAAGCTTCTTCTCTACTGAC
+TGAGTCAATGGCCAATGGATAGAGTAAATAATTCTGCGGTATCTAAATTTGTATTGATTG
+GACTTTCAAGCTCTTGGGAGATGCATCTTTTTCTTTTTTGGTTCTTCTCTGTGTTCTACA
+TGGGAATTATCCTGGAAAATCTCTTCATTGTGTTCACAGTAATTATTGACTCTCATTTAA
+ATTCCCCAGGTACTGCCTACTGGCCAACATTTATCTTCTTGATCTGGGTCTTCTCCTACA
+GTTCTGACTTTTTCACTAACTGCAGCATCATTTCTTTTCCAAGATGCATCATACAGATAT
+TTTTCATTTGTGTCATGCGTAAAAATTGAGATGGTGCTGCTCATAACCATGGCATAGAGC
+AGGTACACTGCCAATCTGTAAGCCTCCCCATTACCTGACCACAATGAACCCCAAAATGTG
+TGTTTCCTTTGTTGGAGGCATCCTGGATAGTCAGGATAATCCATGCTGTATCTCAGTTTG
+TTTTTGCCATAAACTTGCCTTTTTGTGGCCCTAATAGAGTAGGTAGTTTTCACTGTGATT
+TTCCTTATGTCATGAAACTTGCTTGTGTAGACACTTACAAACTAGAGGTTGTAGTCACTG
+CTAACAGTGGGCTTATATCCATAGCTACCTGTTTCTTATTAATAATATCCTATATTTTCA
+TTTCGGTAACCGTCTAGAATCCTTCTTCAGGAGACTTATCTAAAGCATTTGTGTCATGTT
+AGATCACATCACAGTAGGGATTTTGTTTTTTATGCCATGTATATTTCTGTATGTGTAGCC
+TTTGCCTAAAACAACACATGATTAATATTTGTTCATTGTTCCTTTTGCTATCACCCCTGT
+CTAGGATCTACACATTAAGAAACAAAGACATGAACGTCTCCATGGAAAGACTGGGAAAAT
+GGATTGCAGGTTCTAGCAGGATGTCATAATAAATGGTGCATATCCAGAGTGCAAGATGAT
+TCAGTCTCACCAAGAACACTGAAAGTCACATGGCTACCAGCATTATTGTGATAAGAACTA
+CTATTTTGGGAGATAGTTTAGCAAAGGTGCCATGTAGAAATTGATTAAGTCAGAGGTATC
+TTTAACTTGCCACCACAGAGAAGAGATTAATTTCATATACTTCCATTGAGAAGAGAGATA
+AGAATACAAAACCAAGCTGATTTGCAGGAGTAAACTTGATATTCAAATACTATTTCCTGA
+ATGACATTTTCTGAGACATGCTAATTGTAATTACTTTCAGCTTCAAAACATAATAAATTT
+ATCTCATAGTAAGCATATAGATGGAATAAATAAAATGTGAACTTAGGtaaattataaatt
+aataaagtatatttttaaaatttCCATTTTAATTTCTGTTTAAATTAGAATAAGAAACAA
+AAACAACTATGTAATACGTGTGCAAAGCCCTGAACTGAGATTTGACTTTACCTTGAGCTT
+TGTCAGTTTACGATGCTATTTCAGTTTTGTGCTCAGATTTGAGTGATTGCAGGAAGAGAA
+TAAATTTCTTTAATGCTGTCAAGACTTTAAATAGATACAGACAGAGCATTTTCACTTTTT
+CCTACATCTCTATTATTCTAAAAATGAGAACATTCCAAAAGTCAACCATCCAAGTTTATT
+CTAAATAGATGTGTAGAAATAACAGTTGTTTCACAGGAGACTAATCGCCCAAGGATATGT
+GTTTAGAGGTACTGGTTTCTTAAATAAGGTTTTCTAGTCAGGCAAAAGATTCCCTGGAGC
+TTATGCATCTGTGGTTGATATTTTGGGATAAGAATAAAGCTAGAAATGGTGAGGCATATT
+CAATTTCATTGAAGATTTCTGCATTCAAAATAAAAACTCTATTGAAGTTACACATACTTT
+TTTCATGTATTTGTTTCTACTGCTTTGTAAATTATAACAGCTCAATTAAGAGAAACCGTA
+CCTATGCTATTTTGTCCTGTGATTCTCCAAGAACCTTCCTAAGTTATTCTACTTAATTGC
+TTTATCACTCATATGAATGGGAATTTCTTCTCTTAATTGCTGCTAATctcccccatcttc
+aaatactctaccgggcttctggaacaccacagcttcctggctttttctcctacctcctgg
+gcaagtccttccctgtgtcttttgttgagtgttcctcatctgcttaactaccaatcaacc
+tattgcccctaatttgatctttggcctgttttcacttagattctatccctacgtatcacc
+cattcccacagctttaatcaccatctaaacactaggggctctcaaaccttgtatttttct
+ttctttctttctttctttctttctttctttctttctttctttctttctttctttcttcct
+ccttttctttccttttctttctttcattctttctttcttttttaaggggcagggtctcac
+tatgttgctgaggctggtctcaaactcctgacctcaagcaatctgtctgcttcagcctcc
+caagtagctgagaatacagggacaagccattgcacctgaccctggtactatttcttgagt
+tcctgatccacagatctaacctcctactttcctggatgccacacaagatcttccactcaa
+caagtctgcaactaaactagccttcctcttttcaaacctactcttctttcagtgttctca
+gtcacaataatttgtaccaactagttacctagttgcacaacccaaaatctgggaaaaata
+atagatttctttctccatagtacccccaaatcaataaatcatcaagtcttattctacctt
+ccaaagagccttacatatgttcctttattttcatctgtaacaccactattcctgtctaag
+cctacctatgtcatttttggaagagaatatagtcacctatgcgaccttcccacttaaaat
+cctactatttacgcttcagtaaaagaaaaaaaatttttaatctaagtatgtaattctttt
+gctgaagacacttcacttgcttctgtgcccttaaactggtatgttatcatggtatagtag
+gccatccaagacctggcttccttcctttttttcagtctcagagaataacatactctttcc
+ctgcaactccagatccaatttggttttcttttacttgcctggaaactccaaaatctatca
+actctggggctttccactagctaatcattttgtatacaatatttgtccttcATGTTTTGC
+CTCTTAACATCTCAGCTTTCAGTTTCATCATTTTACCAGGGAGGCCTCCCAGAACCTGAG
+TCCAGAAGAGTTCCTTCCATTGTATATTCCTCTAGCACTACCTATTACCTCTTTTGTAAG
+ACTAACAGCCCTCAAAATTTTTCATTCAGTGATGTCTTCCTCATTGCATTTTAAGTTCAA
+CATGAGCAGGACTTTGTCGTGTTCACCTCTATCACATCATAAATATAGCAAACAGTAAAA
+CTATTGCAACATGACTAATGTATTGAACGATGCTTCAGCTTTCTTCTTACGTTCAATCAC
+AGGTCATATGACTAAAGAACTTCCTTTTTAATCTCCTTTTCTATTCTCAATTAATTTCTT
+CTGCCTGCATCACCTCAAGTCTCTGGGGTGAAATCCACTAATGAATTCCTTTTGCAGCTT
+AAGCCAATTCCAATCTTGAGCCAATCTCAGGTGAAGAAGCCTGTAAATTATCACTCTCAG
+TCCTCTCTTGTACTACTAGGTCTCATGAACTCTTCATTAACAACTCCAGCTTCTCTGTTA
+GCCCAAAAGCCTTTTGCTGCCTAGAAAACCCATGATTCATGCCTCAGGAAACAGCCTTCA
+AATCACAACATGTTCTGTATCTGGCTGGCCAACTCCCTGCAACTTATTTCTGCCTAGATT
+CTCCCTCATTCATTTCAATACGCTGTTCGGCCTGCTACCCCAGTTTCCCACTTAGAACAA
+TGGCACACAGGACAGGAGCACATTGGCACATCAGAATGACTTATGTACTGCTCATTGTGT
+TGCAGAAGAGACCTCTGTGGGGGCAATAGAACAGATTTTCCTCTCACGTCACTGTAGTTG
+TGGTTTCCCTAAGCACCTACACTGTTTCACCTCATCTTAGGTAGACAATAATCCATGTAA
+CTGACTGTGTATCCTAATTTTAAAAAATATTTCTGCCCACATTATTCTGCAGTTTTTATC
+TTGCTTACGTATTTTTGGAATGTTACTATTTTTCAAAAATTAATTTGGGATCAACCAACA
+CTTCTTATTCTGCTGCTGTTCTAGAGAAAATCATTTTCCTCATTTCTGAACAAGAGAAAA
+TGAAATACAGCTCTAAACAAATGCCACTGTAAACCAAGGTGGAGCCTTTGCACTTTCAGG
+CCACCATGATAACCTGGAGATTAGATTTTTCTGTGTCTTTATATCAATAATAAAGCCAAG
+CTTCTCCAGGGGTATCCACTAGGCTTGTCTCAATGGCTCAATACAGGTCCTTTTGTGAAT
+GATTACCTCACCCTCATGGAAACACACTCTTGTTACAGAAACTCAGAATGATTCTATTTT
+TTCTTTTATATTTGTATATGTTTTTCCAATACCTCTGAAAAAACTGATCCAAAAAAAATA
+CAAATTTTAATTGTAGCCAGTCAATTCAGGAAGGATAAAGGTCAAAAACTTTCAAAGAAA
+CCTTCAGCCCCAACACACTAAACTTTGGGAGCACAGGTTGGCATCCAGAGGTAAACATTT
+GCTATAACTGATAACAGGAGAAGGATCCATTTATTCACCTGTTATCAATTACAGGCATTG
+TATTTAAAGATCAGATGTTTTATATTTATTTCTTCAAATTTCATTCATGGTGCCATAAGT
+GAAGGTATCTCTGTCCACCCTGAATATATTTTCACTCCCTCATCTCAGTCATTCCGAACA
+ATTCACACACTAAGATTACCCATGCTAAATGGGGATTCTTTTTTACTAGCCAATGTAGTA
+CCTCAAATCCTTCCTTCCCTCCCCCTATTTCATCAGCAGGCAATTCTTTTGATACTTTTG
+TCAAGGGGAAATTGTGTGACTCAGAGATCTAGTCCCCAAGAGAAACTAATAATGGGCTGG
+GTATTGTCTGTCTCAGCAGCATCAGTGGGTCCCTCTCCTGTGCAGCTAATTAGCTTCCTT
+TCCAATATGAAGAATCTTATATATAGCTTTGTCTTTGGGGTATTACATAAATGAAGATTA
+AGCTATCTGAATTTCTCCTTCTCCTAAAAATGCACATCCTATGACTGAAAAGACAGGTAA
+AAGAGATGCTTTTAATTACAAAACTTTCCCTGTCGTGGTTGCTTCTCTCTATCCTTCTAA
+ACTCCCTTTCAATTTCTTCTCTTCTGTAACATATTTGTGCCCAAAATCTTCTGCTTTCTG
+AAATATTTTATCTTTTTCTTCCACACTATCTCTTATTTTCCAATTTTAATCATTAAATTA
+TATTATGTCTTATAAAACTAATCCCACATATAAACCCCTATGATAATTTCAGTTTGTCCC
+TAGTATGAAGTTCTTTAAAGATGTGTAGTTTTCTAACTTTCATGCTCTCCAATTAATTAT
+AAACTTCATTTTCCACTCTGAAAAGGAGATGTCTGATCTCAGCTATTTCCATCCTATTTG
+AAAACCAGATTTAGTTTTAAACCAGAGGAAGGGAATCTCAAGTCTTTACCTCCCACAGTC
+TGGTGTGATTCTCTCTCTTTTGGTATTACCTTCCTCCACATTGGAACACTCCAGCCAATG
+CATAGGCTGAGAGGCTATCTCAGATTCAGAAAGATTTGGCCTCATCCCAGGGGAGGGTAC
+AGAGGAGCTGATGACTATGAATTCTGAAATGGAACTGTTCCAGGTTGAAGAAATAAGAAA
+GGGAATTGGGAAGAGCAATGCCCAGTGAAAAAGAAGAAATAATATTTTAGGAAGTGAATG
+CTAATTTTATTTTAAACAAAATAAGAACTCAAGGAATAAGAGGGTTCTTCCAATAGGTTA
+GAGTGATCCTGTCAAACATATATGCTTCTAGATTTTTTTAAAGACTGTTTCTACTAAGAA
+AGCATAGACCGCTATTGAGAAAGATCATTAAACTGGAATTTAGGAGGTCTGCCTTCTGAT
+TCTGACTTCTTGAATGTATTGTTAGCCATTTAACCACACTGTGTTGTTTCTCATTCTACC
+TGTAGAATCTCAAAGTTCTTTCCCACTTCTATACAAAACTATAATTCTGAACATCCTTTT
+TGTTTAATATAAGTCTGCATTTCCTGTTTGAAGATATGTGTCCCAGACCCTAAATGACTG
+ACAAATTTTAAATCTCCAATAGGAAAGATGACAAACTCTATGGAAACTTGGCTTCTGAAG
+AACTCCTAGAAGCTTTCCAAAGTCATCAGTGTTTCCTAAGAAGGCAGAGAAATCAAACAC
+ATGGTCTTTTCCTCCAGACAAGCTCCTTTGGGTCATCAGGATTTCTTCAACAATAAAATG
+TAATAATTCCAAATGTTTGTAACAGAATGGGTAGGACTTTCTTCACTTATTTAAATACTC
+CCTTTTTTATGCAACTGAGTTTTCATCAACAAGTACAAGCTTGTGAAGGAGTACTTTAAA
+ATGCAATTTCTCTCTATTTTTGTGGGGGCTAATATTTTATTTCTCATATTGACAATTTAT
+TATGCTGTTTTTAAAAAGttcattcatcaagtatttcttgagctttttctatgagacagg
+cactgttttaggcaagtaattatgcactgaacaatgcaaaaagtttccctgcactcatgg
+actttaattttaCATTTATGAAAAGCTACAAATATTAGAATAAGTAAAATACTGCCTGGA
+GGCTAAAGCATATTTTGATCACTTATTCCCTAATTCTTTTAGAAGAGAACTCACCTGTCG
+GTTAGCTGAACCACTGCCAGTGATATCCAACTATACATTCAATCCCACCATACCTCATTA
+TCACACCTATTCACTCACAAGCTTAAACTCTTAACTTTTCTCCACATATCAGTGACTATT
+TCCTACAGCTTTTCTTTTACTTTCCATGTTTGCAGTGACAATATACATAAACAGTGTATG
+AAAACTCAAGTAAAATCTACTCTCTCAGGTGTTCATAATGTATCAATGTATATTGCTTTA
+AGCCTGAAGGTAACCTAAGTAAAGATGTACCATGTTCCACCAATGCTTCTTTTGATCATC
+ATTTTATCCTGTTTTTTCTTTAGGATTCTTTCTTATTCCTTCCCCTGACCCTTCTTTTAT
+TCTCCAAATTTCTTTCCAATTCATCTTTGTTCTTCCCTTTCCTTTTTACTCTCTTTAAAC
+ATTCTATGGACTCTGCCTCCTTCACACTGATATTGAACGCCCATAGTTTCATATTTTGGA
+TTGCGATTGTTTTATTTTAAAATGGCAAATGTTCATGTTATAAAGAGAATTTTTCAGTCT
+TTAGACTAATAGGTTCATGTAGTTTGGGATTTTCCTCTTTAAGAAAATTAATTATCACTC
+ACACTCCAAGACAAACACCATTTCAGTAGCAATATGAATTTCAGTAGTAATAGGAATCTC
+CAAATATGACAAAGTAATTCAGACATTAATTGCTTTTGTTTTGGAATTGCTCTTATAAGA
+TGAAATATCACTTTCATGATGAGAGTCCTAGAGTGCTTGGTTTATATATTGTATCTTAGT
+TTTAACAGGATAAAACACTTGATCCTAAGCAGTAAACATGATTCTTCAGCTTCAACTTCA
+TTTCTTTATAAATAACTATTTATGAATTGGTGTTGAGCTTAGTAAGTCACCAAACACCTT
+CTGCTCAGCAGCATAAAGGACATTTCCATGAAACCTCCCAGGGATAATCTTATTTACTCT
+ATAATGTTTCCCGGGTTCAATTCCTCTCCCAAAATTCTTTGTTCTTAAGCCCCTATGATC
+TGGGTGATCTAAATATGGGTAAGAAGTCCAGGGATAGCACTATGAATGAAGTGAAAATAG
+TAAAACATAGTTAAAAATGTAcagatgctctctgacttataatagggttacgtcctgata
+aatccatcataagtcaaaaatgcatttaatattcctaatgtacctcacatcatagtttgg
+cctagcctaccttaaatgtgctcagaacactttcattagcttatataagatcacctaata
+caaagcctattttataataaaatattgaatagctcacgtaatatactgactactatactc
+aagtacagtttcttctgaatgcatgtcactttctcaccattgtaaagtcaaacaattata
+agtcaaactatcacaagccagggaccatcCATATGTATTTCATTCAGAAAATGCTGGAAA
+GAGCATTTCGGAGAATATCTAGATGAGAGAAGGTAGAAAGCCATGCACAAATTCACTGAG
+AGTTTAAAAAAATACATGCATATTGTGGAGATAGAAATCAAATCTATTTGTCTCCATCTG
+CTGTATTCTTCCCAAAATATTATCTCTTCTTATCCCATTGTACTATATTGCATTTCTTTG
+ACCATTTATTGTGTATCTCTTAATATTTCCCACTTCATCATTACTAACCTCACTCACTCT
+GAACTTGATGAGAGCACCTGAGCATTAATTTTTCTTATAATTATTTAATGATTACCAGAA
+TTCGTTCAGTATGGCCAGCTCTGGTCAAAGTGAGGCAGGCAAGATGCTTTGTCAACTGCC
+TGGATGGAATGTCTCAAAAGGTTTCCATTTCATGGTAGCATTATGCAAAGTTCAAGACGT
+TTAATCAAGACCCTTCACTTACTTAACTATACCTCCTTGAGAATCCCATCTATGAAAAAA
+TTCTAGTCATTATAAAAATGATTGATTAAATGAGGGAAGTAGTAGAGTTCTTCATTTCTT
+TAGTTGGTTTAGTCTCCTATGAGTCAATCCTATTTTCAAAATTCTTAATAAACCATTTAT
+TCCTTCAACTTTCTATGCCATTTGATGTTTTGTAAAAAAAAAAATATAATATGTATACAA
+AAAGATATTTCAAAATCTAGAAAGAGAGCTTTAGAGCTTTGTAAAGCTCTTTTAAAAATC
+AAAAACAACTACTGTTAATTAACATGTTGTACTATGCAATTTGTTTACCATTATTACTCT
+TGGTATTTTTAAGAAAAGTCTTTCCATTGTTATTATAAATGCTTCTATTGATATTTATTT
+TAATAACTGTTATTACAGTCCGTCATGTACATACACTATACTTAAACCTAATGTTTGGTA
+TTTAAATCGTTTCAAGATTTTATCACTGTCAACAAAGTATGATGAATATTTTTATGCTGA
+AAACTTCTGTAAAAatagaattccaagagtattattgcaccaaaaggcatggacttaaaa
+ttcttgatacatgatttcaaaatattttctttaaggtttgaatcagtctatattccctcc
+agcagcgtataaaagtgccaatttctctgatccttaGCCAGTTTGGGTAATAATAATTGT
+AAAACttttttttctttttttttgagacagagtctccctctgtcgccaggctgaagtgca
+gtggcgcaatctcggctcactgcaacctccgcctcccggggtcaagctattctcctgcct
+cagcctcccaagtagctgggactacaggcatgcaccaccatgcccagctaatttttgtta
+tttttagtagagatggagtttccccatgttggacaggatggtctcgatctcttgacctcg
+tgatccaccctcctcggcctcccaaagtgctgggataacaggcgtgaacaaccatgcccg
+gccTGTAAAACTTTTTCCTAATTTAACAGAAAAATAATAGTATTATATTTTATCATATTT
+CTTTGATTTCTAAGacacacatacacacacacacacacaTATCTGTATATACAAATACAC
+GTATAGCTTACATTTTAATTCTTCATTTCATTTGTTCATTTATTAGGTCTTGGAGATTTT
+GTGAAACTGTTTAAATTCTTTTTTATACTATGAAGATATCAACCTTTTGTCTCTACAGCA
+TTTCAAATTCAAGTATGATTCACGTGTTGGTTTGGGGTAGATCATTATAGGCACATGTAG
+GAAACAGCTTTCAGAGATGCCTTAACCGTAATTATGCATTTGTATTCTAATTTTTATTTA
+ATGTTATTATTGATTGCATTTTTAAAGATTCTGTATTTTTTAAACCATTTATTTGTATAT
+GTTGGTATACAATCTTGCCATTTTCTGGGATTTCATATTTCCTTATTTTTGTTTTTTACC
+TTTTTTGGCTTGAATTTTTTGAGTTTTTATGCATTCTTTTCCAGTTTCTTAAGATGCTAA
+TAAGTTCATGTATTTGAGCAATTGAGAACATTTAAAGCAATAGACTGCCTCTGAGCACAG
+CTTTGTCCATATTACATTAACCTTTTATACCCTGGGTTCCCACTAGTTTTTAAATAATCT
+ACTATCAAATAAAAGATTTGTTAATAATAAATTTTAAATCATTAACACTTAACGCATTAT
+TTTCAGTCACACTAAGTTGATTCCTTCGTTTCTTTCAGGTTGCTTCAGAGTCTTCCCTTC
+TATCTGATTCAGTGGACCAAGTAAATGACTCTCTGGTAACAGAATTTGTATTACTTGGAC
+TTGCACAATCCTTGGAAATGCAGTTTTTCCTTTTTCTCTTCTTCTCTTTATTCTATGTGG
+GAATTATCCTGGGAAAACTCTTCATTGTGTTCACAGTGATCTTTGATCCTCACTTACACT
+CCCCCATGTATATTCTGCTGGCCAACCTATCGCTCATTGACTTGAGCCTTTCATCTACCA
+CAGTTCCTAGGTTGATCTACGATCTTTTTACTGATTGTAAAGTTATTTCCTTCCATAATT
+GCATGATACAAAAGTTCTTTATCCATGTTATGGGAGGAGTTGAAATGGTGCTGCTGATAG
+TCATGGCATATGATAGGTACACTGCGATCTGCAAGCCTCTCCACTATCCAACTATTATGA
+ATCCCAAAATGTGCATGTTTTTGGTAGCAGCAGCTTGGGTCATTGGGGTGATTCATGCTA
+TGTCTCAGTTTGTTTTTGTCATAAATTTACCCTTCTGTGGCCCTAATAATGTGGGGAGCT
+TTTATTGTGATTTTCCTCGGGTTATTAAACTTGCATGCATGGACACTTATGGGCTAGAAT
+TTGTGGTCACTGCCAACAGTGGATTCATATCGATGGGCACCTTCTTTTTCTTAATTGTAT
+CATACATTTTTATTCTGGTCACTGTCCAACGACATTCCTCAAATGATTTATCCAAAGCAT
+TCTTCACTTCGTCGGCTCACATCACCGTAGTGGTTTTGTTTTTTGCTCCATGCATGTTTC
+TCTACGTGTGGCCTTTCCCTACTAAGTCATTGGATAAATTTTTTGCCATCATGAACTTTG
+TTGTCACCCCTGTCGTAAATCCTGCCATCTATACTTTAAGGAACAAAGATATGAAGTTTG
+CAATGAGAAGGCTGAATCAACATATTTTAAATTCTATGGAGACGACATAACACATTTGGT
+TGATGAGAGCACAGGATAAATGCCATGGACCATCAAGACTCCTGTGATCACCATGATCAC
+TATGGAACGCGCACATTTTTAGTATTGCCTGAAAAAACTGAAAAATCTGCAAAAAGGATG
+CATTAAATCTAAGAATTGTATTTCAGATAAAGTTGCAACATTTTTTGTTAATCATAAAAA
+GTATATATTTCTATCTAATGTGTGTATCTAATTAACAGCAATGACTACCTTTAATTTTGA
+TGTAGTTATTTTATATCTGTATATAAGCACATACACATATATATGACCTAGGTTTATTTA
+TCAGTATTTTTATGCTGATAATAAGCATCACTGGAAATTAATTTTCTTATGGAAATTATG
+TGGATCCAATGGATAAAATATGAGTTTATATAAATTAGTAAATGCCAAAATCAAGGAAGA
+AACAATTTTTATTTTAATTGTACTTTAAGTTAGATAAATGGTAAGGTCAACAGCTTGTTA
+CAACCCTTAAGTATTATTTTCAGGCTGATTGTCAATATGTTTTGTACAatgttctcactt
+ataggtgggaattgaacaatgagaacacatggacacaggaaggggaacatcacacaccgg
+ggcctgttgtggggtggggggaagggggagggatagcattaggagatataactagtgtta
+aatgacgagttaatgggtgcagcacacccacatggcacatgtatacatatgtaactaacc
+tgcacattgtgcacatgtaccctagaacttaaagtataataaaaaaaaaTAGACTCTAGT
+ACTCTGTATTATGCAAAATTTGTCTATGTTACACTTTTTTAACAACACAATCCTATTGCC
+CTTGAAATCTTCTTCAAAGCATTTCTCGAGTCACTCTTAAAAAGCATCTACAACCTAAAA
+GTATAGGAAGAGATTTATTTCCTGGAGAAGAGACCCCATTGAGATCTTAAAAGCACATTT
+AATGTGCCTGTGCTTAACTTAAGGTGCTTAGGACAAAGAAGGCGATTGACATCTTTCAGG
+TAAAACCTGGTAAGTTTGGTGGTCAAGGAACACAACTGAGACATCACTTGGATGTATTCC
+TATGACTATTTTAAGAAACATAAATTGTGGTGACTCACTCAGCTCACTTTTAACTACTGC
+ATGGTAATTAAAGATGCAAAATAAAATAAGTTACAAGAAGTGAGGTTTTTTATTGGTTAA
+AGCAATTTTTCTATATTTTCTCCGCAAGTTGGTCATAAAAGTTCTAAGCATTCCTCTTTT
+TATAAAATCGAAGCATTATTACTTACTCTCTTGTTAACCTATCTGGATTTTAATTTTGTA
+ACTTTATTATATTTGTTTTGCTGTGATTCTTTAAAAAGCACCTTTAGACTCAGTGAGATA
+GCAAAAATATCCAAATAGGCCAAAAAATTGTGGCAATGTCCTCTCACTCAGGAAAATTCT
+GTGTGTTTTCTCTAATGGCCAAGGGAAAACTTGTGAGACTATAAAAGTTAGTCTCAGTAC
+ACAAAGCTCAGACTGGCTATTCCCAGATCTCTTCAGGTACATCTAGTCCATTCATAAAGG
+GCTTTTAATTAACCAAGTGGTTTACTAAAAAGGACAATTCACTACATATTATTCTCTTAC
+AGTTTTTATGCCTCATTCTGTGAAAATTGCTGTAGTCTCTTCCAGTTATGAAGAAGGTAG
+GTGGAAACAAAGACAAAACACATATATTAGAAGAATGAATGAAATTGTAGCATTTTATTG
+ACAATGAGATGGTTCTATTAGTAGGAATCTATTCTGCATAATTCCATTTTGTGTTTACCT
+TCTGGAAAAATGAAAGGATTCTGTATGGTTAACTTAAATACTTAGAGAAATTAATATGAA
+TAATGTTAGCAAGAATAACCCTTGTTATAAGTATTATGCTGGCAACAATTGTCGAGTCCT
+CCTCCTCACTCTTCTGGGCTAATTTGTTCTTTTCTCCCCATTTAATAGTCCTTTTCCCCA
+TCTTTCCCCAGGTCCGGTGTTTTCTTACCCACCTCCTTCCCTCCTTTTTATAATACCAGT
+GAAACTTGGTTTGGAGCATTTCTTTCACATAAAGGTACAaatcatactgctagagttgtg
+aggatttttacagcttttgaaagaataaactcattttaaaaacaggaaagctaaggccca
+gagatttttaaatgatattcccatgatcacactgtgaatttgtgccagaacccaaatgcc
+tactcccatctcactgaGACTTACTATAAGGACATAAGGCatttatatatatatatatta
+tatatactatatatttatatatattacatattatatatataatatatattatataatata
+tattatattatataatatataatataaatataatataaattatattatataatatataat
+ataaatataatataaattatataaatataatatatattttattatataatataatatata
+ttatataaatataatatataaattatataatataatatatattatataatataatatatt
+ttattatataaatatatattatattatataatatatattttattatataatatatattat
+atatttatagaatataatatatattttattatataatatatattatataatatatattat
+atttatatataacatatattattatataaaatatgtataatatatattatataaatatat
+ttatatattatataaatatatatattatatataatTCTAATGGTTGAATTCCAAGAATAA
+TCTATGGCATGAAAGATTTTACCTGTCAACAGTGGCTGGCTCTTCATGGTTGCTACAATG
+AGTGTGTAAGATTCTGAAGGACTCCTTTAATAAGCCTAAACTTAATGTTCAACTTAGAAT
+AAATACAATTCTTCTAATTTTTTTTGAATAATTTTTAAAAAGTCAGAAATGAGCTTTGAA
+AGAATTATGGTGGTGAAGGATCCCCTCAGCAGCACAAATTCAGGAGAGAGATGTCTTAAC
+TACGTTAGCAAGAAATTCCTTTTGCTAAAGAATAGCATTCCTGAATTCTTACTAACAGCC
+ATGATAGAAAGTCTTTTGCTACAGATGAGAACCCTCGGGTCAACCTCATCCTTGGCATAT
+TTCATGTGAAGATATAACTTCAAGATTGTCCTTGCCTATCAATGAAATGAATTAATTTTA
+TGTCAATGCATATTTAAGGTCTATTCTAAATTGCACACTTTGATTCAAAAGAAACAGTCC
+AACCAACCAGTCAGGACAGAAATTATCTCACAATAAAAATCCTATCGTTTGTACTGTCAA
+TGATTAGTATGATTATATTTATTACCGTGCTAAGCAGAAGAGAAATGAAGTGAATGTTCA
+TGATTTATTCCACTATTAGACTTCTCTTTATTCTTAAAAATATTTAAGATCACTAAATTT
+TTATAGGACTTTAAAAACAGTAATGTGCTGCTTTGAGTGTGTAGGACTAAGAAATGGGAT
+TCAGAGTAGTAAAGAGAAAAGTGGAATTTCCAAGCACTATGAATTACTGTTCTTTAAAAA
+ACAGCAAAAATCAAATAACAGTATTCCTCCAAAAAAGATGGCAAGTGTAAACTCTATACC
+TTCATGTCTCCCGTGGAATGTTAGTGATCAATTTCCACTTCTCTCTTTTACATCTTACTT
+GCCCATTAACTCTTATACCTAATCCAAAGATTGTTAATATGGCTATGTCTCACTTTCAGG
+ACACCTTTTATTTGTTACTTCTCTTCACTGCAAAACTTCTTGAAACAGTACTTATTTTCT
+CTCCTCCATACACAATTGAAATGGCTCTCAACTCATGCCCAGAAGTCAGTGTTCAGTCTC
+TCACCTGGCAGATAGCAACTTACAAAGATGCCCCAACAATACCTCCTTGTGTCTAGACAG
+TCATCATTATCCTTTACCTTTTTCTGTATTTATTTCTGCTCCTAAAAGGGATCTCTATGT
+AAAGTATTGTTATACTAGTGCTTGTTATAATTATTATCAGAGTTAAAGCCATCACAATGT
+TCCCAATTACTTAAAGACATTGGAATAACATTTTTTTTATTTTCCACATCTTGCCAAAAA
+ATATTTTGTTATCAGTACCTTaataatggctattatatattgaccattactatttgctag
+aaaatttatatacctggtcgtatccaatcctcacagaacttctataaagttgtgctatta
+tcacctatattttccagatgtggccgtaagactgaaatcacttaggtgacttgtctaagg
+tcattcagatacatagtagataacccaggatttgaacacaggcctcctagcacacaagct
+catatcttaactactttaatacgttgctcGATGGGATCTTACAGGTCTTCATTCACCCCT
+TTCCTGCTCACACAACCACAACCTGCAGCTATTACCTATTGTTAGGCTTAAAATAATTAC
+TTGGCTTCATTTCCAAGCTCCCTCCCTTCCAATTCACATTGAGTCCAGAGCTAAATTAAA
+CAATCATTCAAAATTTTTCAGTAGTTCTTGTCTCTATAATAAAACAGAAATGCTTTAGAA
+AGCATTCCAAAATCTCTTACCAGTTTTATCTCCTATGAAAGTCCTTCACactttctctca
+tttaaactttattgcattttcctcactttttctcacttcacttttgaattccctattctt
+ttatcctctgttaatttttaagtattatatttgtgatattattttttctttttttctatt
+ttttatctttcatttcattttggcctatttttttctcttAAGAACTTTAATATCACCAAA
+TAACATGTGTGCTACAAACTGTTTTGTAGTTCAAAGAAAAAGGAGATAAACATAGAGTTA
+TGGCATAGACTTAATCTGGCAGAGAGACAAGCATAAATAATGGTATTTTATATTAGGAAT
+AAACCTAACATTAATGGAGACACTGAGAAGCCGAGATAACTGAATTATAAGGCATAGCCA
+GGGAAGTAGTGCGAGATAGAATTATGATCTTGTTGAATTCTGAATGTCTTTAAGTAATAG
+ATTATAGAAAGTCACTGTAAGAGTGAGCAGAATGATATAAAATGAGGCTTTGAATTTGAA
+TATAATAATTCTGACTTCCTTCTCCTTCTCTTCTTCAAGGTAACTGCAGAGGCTATTTCC
+TGGAATGAATCAACGAGTGAAACGAATAACTCTATGGTGACTGAATTCATTTTTCTGGGT
+CTCTCTGATTCTCAGGAACTCCAGACCTTCCTATTTATGTTGTTTTTTGTATTCTATGGA
+GGAATCGTGTTTGGAAACCTTCTTATTGTCATAACAGTGGTATCTGACTCCCACCTTCAC
+TCTCCCATGTACTTCCTGCTAGCCAACCTCTCACTCATTGATCTGTCTCTGTCTTCAGTC
+ACAGCCCCCAAGATGATTACTGACTTTTTCAGCCAGCGCAAAGTCATCTCTTTCAAGGGC
+TGCCTTGTTCAGATATTTCTCCTTCACTTCTTTGGTGGGAGTGAGATGGTGATCCTCATA
+GCCATGGGCTTTGACAGATATATAGCAATATGCAAGCCCCTACACTACACTACAATTATG
+TGTGGCAACGCATGTGTCGGCATTATGGCTGTCACATGGGGAATTGGCTTTCTCCATTCG
+GTGAGCCAGTTGGCGTTTGCCGTGCACTTACTCTTCTGTGGTCCCAATGAGGTCGATAGT
+TTTTATTGTGACCTTCCTAGGGTAATCAAACTTGCCTGTACAGATACCTACAGGCTAGAT
+ATTATGGTCATTGCTAACAGTGGTGTGCTCACTGTGTGTTCTTTTGTTCTTCTAATCATC
+TCATACACTATCATCCTAATGACCATCCAGCATCGCCCTTTAGATAAGTCGTCCAAAGCT
+CTGTCCACTTTGACTGCTCACATTACAGTAGTTCTTTTGTTCTTTGGACCATGTGTCTTT
+ATTTATGCCTGGCCATTCCCCATCAAGTCATTAGATAAATTCCTTGCTGTATTTTATTCT
+GTGATCACCCCTCTCTTGAACCCAATTATATACACACTGAGGAACAAAGACATGAAGACG
+GCAATAAGACAGCTGAGAAAATGGGATGCACATTCTAGTGTAAAGTTTTAGATCTTATAT
+AACTGTGAGATTAATCTCAGATAATGACACAAAATATAGTGAAGTTGGTAAGTTATTTAG
+TAAAGCTCATGAAAATTGTGCCCTCCATTCCCATATAATTTAGTAATTGTCTAGGAACTT
+CCACATACATTGCCTCAATTTATCTTTCAACAACTTGTGTGTTATATTTTGGAATACAGA
+TACAAAGTTATTATGCTTTCAAAATATTCTTTTGCTAATTCTTAGAACAAAGAAAGGCAT
+AAATATATTAGTATTTGTGTACACCTGTTCCTTCCTGTGTGACCCTAAGTTTAGTAGAAG
+AAAGGAGAGAAAATATAGCCTAGCttataaatttaaaaaaaaatttatttGGTCCATTTT
+GTGAAAAACATAAAAAAAGAACTGTCACATCTTAATTTAAAAAATATATGCTTAGTGGTA
+AGGAGATATATGTCAACTTTTAAGAGGTTGAAAAACAAACGCCTCCCATTATAAGTTTAT
+ACTTCACCTCCCACCACTATAACAACCCAGAATCCATGAGGGCATTATCAGGAGTGAGTG
+GAAGAGTAAGTTTGCCAATGTGAAATGTGCCTTCTAGGTCCTAGACGTCTGTGGTATAAC
+TGCTCATAAGCAGTAGAAAGAATTTAGAGGGATCCAGGCTCTCATCACGTTGGCACAAAG
+TATATTACTTGGATCCATCTATGTCATTTTCCATGGTTAATGTTTaaaagcacaggcttt
+aaagtaaaaaacaaagagctggattcaactctactgactcttattaatcatgattttggg
+cacattacgtagctttcatgagctttagtttctacatttataaacaggagattataccta
+ttatgcatggttattatgaaggaaaatgacaaaatagatataaatcaaatagcccacttc
+gagacatattaagcatgaataaacattagatactattaAAATCCTATATATTAACAAAGC
+CAAAAGTTTCAAACTTTACTTTTTCCCAACATTCTTGTGAAATATGACACATCCCAATCT
+TAACAGATGCTCATTTGGGATACTGTACTTGTGAGTGGAAGTGTGTATATTTGTGTGCAA
+GTGTGTACTCATATACTTCCACCTTACCACCCTAGAAAGGCATGATGAAAATTTAAGATA
+GAAGGAAAATATAAATTGAAAAAAAAAAACCTTAACAAATGATTCTGACAAATATCTTCT
+CTTTCCAGGGAGAATCACTGAGCCAGAATAAAATTGAACACTAAATATTCTAAGAAAAAA
+GGAATCTAGTTTGTCAAAATGTGACTTGAATTAATAGATAAGGAGAGTCAGATGATAAGA
+GGGTCAAAATTATGTTTATCTTAGGAAAAGTAGAATAGAAAATTTATAAGCAGATTAAAA
+ACACATAATAAAAGTAGTAAATAATAATGACAGTATCTCAAATcagtgcaggggggaaag
+gcctactaatgtgatggtgggataattggatagcaatatgggaaaagatatatttaattt
+atttgctacaccaaatgccaggacaatctctaagtgaattcaagacataactcttttttc
+aaaaaaactatgcaaatattaaaagaaaacaagttaatgtttttataatctatgaatatg
+gtaaagatGGATAACATTGACTATCAAATTAATTTTTAATGCGTAATAAAACTATGAGAA
+AATTTAAAAGTGAGAAGAAACTACTTGTAACTCACATAATAGActagtacttctaacaca
+tagggaacttctaaaacaaaacccaaaatattaataggaaaatgggcaaaacagttaaac
+ttacagttcataCATAAGGAGAATCAGTCTTTTTTTTTTTTTTTACAGTTGTAGGCAGAA
+AACTTTTATTTTTCATTTATTTGTAAAATTTACCCCTAATTTATTCATAATTCATTTAAC
+TGCTAAGGGCATTAATGTGTACAACGCCATGGGAGAAACCAGTATATTCAGAATTTCTCC
+TGAAATTTGACCAGAAGTTATGGGCATCCCTCCCCTGGGAAGGAGGCAGGCAGAAAAGTT
+TGGAATCTATGTAGTAAAATATGTTACTCTTTtatatatatacatatatgtgtgtatatg
+tgtatatatatatacacacatatatacatacatacatacatacatatTATCTGAATTAGG
+CCTGGTCttttttaatactttaagttctgggatacatgtgcagaatgtacaggtttgtta
+cacaggtatacacctgccatggttgtttgctgcacccatcaactcaccatctacattagg
+tatttctcctaacgttatccctctccttgcctcccacctcccgacaggccctggtgtgtg
+atattcccttccctgtgcccatatgttctcattggtcaactcccatttatgagtgagaac
+atgcggtgtttggttttctgttcttgtgttagtttgcggagaatgatggtttccagcttc
+atccatgtccctgcaaaggacatgaactcattcttttttatggctgcaagaaatgcaaat
+caaaaccacaatgagatgccatctcacaccagttagaatggcaatcattaaaaagtcagg
+aaacaatagatgctggagaggatgtggagaaataggaatgcttttacactgttggtggga
+gcgtacattagttcaaccattgtggaagacagtgtggtgtttcctcaaggatctaaaact
+agaaataccatttgacccagcaatcccattactgggtatatacccaaacgattgtaagtc
+attctactacaaagacacatgcacaggtatgtttattgcagcactattcacaatagggaa
+gacttggaaccaacccaaatgcccgtcaatgttagactagataaaatgtggcacatagac
+CTGGTCTTAAAATCAAGAACAGAGATTGTTACTTTTACATCCATTCCTAATTGATAAACC
+ATTCAGTTATACCACATCTTAGCTTCTGGACTACAATGACCATATTTGGGGttttctttc
+taatttcattataggttcagagggtacatgtgcaggtttgagacaaaggtatattgcatg
+atactaaggtttggagtacaaatgattccacctcccaggtagcaagaataatacccaata
+tgtagtttttcaactctttcccctcttcctccatcctccctctgctactctgtggtgtct
+gtttttctcatctttatgtccatgtgtactcgatgtttagctcccccttgttaggtgaga
+acatgtggtatttggttttctgtttcagtgttaattcacttaggataatggcctccaact
+gcattcatgctgctgcaaaggatgtgactttcttcttattagctgcatatattttgtggt
+ggatttgtaccacatttactttatctagtccaaagttgttgggcacccaggtggattcca
+tgtctttgctattgtgaatagcactgggacaacccatacaagttcatgtgtctttttggt
+aaaacaatgtattttcctttgggcatatatgcggtgatggaattgctggatcgagtggta
+gtttaactcttagttctttgagaaatccccagactgttctccacagtggctggactaagt
+tgcattcccaccagcagtgtagaagtgttccccattctctgtagcctcaccagcacatgt
+tAAACTATCTttaaatatatgaaaaaaatgttcaagtctctcagattaagatgcatgcaa
+agtaaaatgatacttaaatatcagttctaacctataaaatatcaaatatctgacctcaat
+atttgataatccaacctgttgatgaagctgtagagagaggcaccctTtttttttttttta
+attatactttaagttttagggtacatgtgcaccttgtgcaggttagttacatatgtatac
+atgtgccatgctggtgcgctgaacccactaactcgtcatctagcattaggtatatctccc
+aatgctatccctcccccctccccccaccccacaacagtccccagagtgtgatattcccct
+tcctgtgtccatgtgatctcattgttcacttcccacctatgagtgagaatatgcggtgtt
+tggttttttgttcttgcgatagtttactgagaatgatgatttccagtttcatccatgtcc
+ctacaaaggacatgaactcatcattttttatggctgcatagtattccatggtgtatatgt
+gccacattttcttaatccagtctatcattgttggacatttgggttggttccaagtctttg
+ctattgtgaataatgccgcaataaacatacgtgtgcatgtgtctttatagcagcatgatt
+tatagtcctttgggtatatacccagtaatgggatggctgggtcaaatggtatttccagtt
+cgagatccctgaggaatcgccacactgacttccacaatggttgaactagtttacagtccc
+accaacagtgtaaaagtgttcctatttctccacatcctctccagcacctgttgtttcctg
+actttttaatgattgccattctaactggtgtgagatgatatctcattgtggttttgattt
+gcatttctctgatggccagtgatgatgagcattttttcatgtgttttttggctgcataga
+tgtcttcttttgagaagtgtctgttcatgtccttcgcccacttgttgatggggttgtttg
+tttttttcttgtaaatttgtttgagttcattgtagattctggatattagccctttgtcag
+atgagtaggttgcaaaaattttctcccattttctgggttgcctgttcactctgatggtag
+tttcttttgctgtgcagaagctctttagtttaattagatcccatttgtcaattttgtctt
+ttgttgccattgcttttgTCccaccgatcccacagaaatacaaactaccatcagagaata
+ctacaaacacctctacgcaaataaactagaaaatctagaagaaatggataaattcctgga
+cacatacactctcccaagcctaaaccaggaagaagttgaatctctgaatagaccaataac
+agaagctgaaattgtggcaataatcaatagcttaccaaccaaaaagagtccaggaccaga
+tggattcacagccgaattctaccagaggtacaaggaggaactggtaccattccttctgaa
+actattccaatcaatagaaaaagagggagtcctccctaactcattttatgaggccagcat
+cattctgataccaaagccaggcagagacacaacaaaaaaagagaattttagaccaatatc
+cttgatgaacattgatgcaaaaatcctcaataaaatactggcaaaacgaatccagcagca
+catcaaaaagcttatccaccaagatcaagtgggcttcatccctgggatgcaaggctggtt
+caatatacgcaaatcaataaatgtaatccagcatataaacagagccaaagacaaaaacca
+catgattatctcaatagatgcagaaaaggcctttgacaaaattcaacaacccttcatgct
+aaaaactctcaataaattaggtattgatgggacgtatttcaaaataataagagctatcta
+tgacaaacccacagccaatatcatactgaatgggcaaaaactggaagcattccctttgaa
+aactggcacaagacagggatgccctctctcaccactcctattcaacatagtgttggaagt
+tctggccagggcaattaggcaggagaaggaaataaagggtattcagttaggaaaagagga
+agtcaaattgtccctgtttgcagacgacatgattgtatatctagaaaaccccattgtctc
+agcccaaaatcttcctaagctgataagcaacttcagcaaagtctcaggatacaaaatcaa
+tgtacaaaaatcacaagcattcttatacaccaacaacagacaaacagagagccaaaccat
+gagtgaactcccattcacaattgtttcaaagagaataaaatacctaggaatccaacttac
+aagggacgtgaaggacctcttcaaggagaactacaaatcactgctcaaggaaataaaaga
+ggatacaaagaaatggaagaacattccatgctcatgggtaggaagaatcaatatcgtgaa
+aatggccatactgcccaaggtaatttacagattcaatgccatccccatcaagctaccaat
+gactttcttcacagaattggaaaaaactactttaaagttcatatggaaccaaaaaagagc
+ctgcattgccaagtcaatcctaagccaaaagaacaaagctggaggcatcacgctacctga
+cttcaaactatacgacaaggctacagtaaccaaaacagcatggtactggtaccaaaacag
+agatatagatcaatggaacagaacagagccctcagaaataatgccgcatatctacaacta
+tctgatctttgacaaacctgagaaaaacaagcaatggggaaaggattccctatttaataa
+atggtgctgggaaaactggctagccatatgtagaaagctgaaactggatcccttccttac
+accttatacaaaaatcaattcaagatggattaaagacttaaacgttagacctcaaaccat
+aaaaaccctagaagaaaacctaggctttaccattcaggacataggcatgggcaaggactt
+catgtctaaaacaccgagagaggcactcttatgcattgttggtgagaatacaaaatggta
+caactcttggcaatatcttaaaaaatttacatggtactgacttttggtctagcaatccta
+cttctatcctaaagatatattggcaaaaatacaaaataattgatgcactcaagtctattc
+attgaagcattgtttttcatagtaaacggaaagtaggccgggcgtggtggctcatgcctg
+tgatcccagcattttgggaggctgaggcgggcagatcacttgaggccaggaattcaagac
+cagcgtggctaacatggcgaaaccccatctctaccaaaaatacaaaaattagctgggcgt
+ggtggtgcacacttgtaattccagctacttgagaggctgaggtgggaggatcgcttgaac
+ctgggaggcagaagtttcagtgagcccagaacgtgcctctgcactccagccaggatgaca
+gagcaagactccatctcaaaaaaaaaaaaaaaaaaaaaggaaaataaccaaatgacaatt
+agtgagtactacttgcaaaacttgtacgcaatagagtatgaagcaactataaaatgagag
+agaaatatctccaaatactactctaaagtaatctacaaggtataccttaactgaaaagaa
+acaaaaaagtgacaccagaatgctatttttatgttaaaacagggataaataCATTGGATT
+TACATGCatatataagtatatattttataaatgtttaaataaGCATACTTAAAATGGCAA
+AAACGTAATACATATATAATTTTCTTATGGCAGGAGGAGGAAACAGGGCAAGGCACAGGG
+ATAAAAGTTATTCTGAATACATCTTATTTTATATTTTTGACTTTGAAATCCTGTAGCTGT
+TTTATGTAATATAAAAATGTAATTAAATTAACAGAAAAAAATTACAACTGCTAAAAATCA
+AGATCTGGCATTTTAATTAAGTTATAAAACATCGGAGAAAAGAATTGTTTCATGGGACAC
+TAACATACAGACAAATTCATTTGGAACCCAATGAATTAATGGGCCTAAGATAACAACCAA
+TAGAAGCTAAAATGACGAATAACTGTTTCAGAAGAAAACATATATGGAATGAATCAGCTG
+AAAATACCTGAACCTACTGATCAATTTTTATATCACATGAAGTGAATACACATAAAGTAT
+AATATGGAGCACATAGAACCAACTAGAAATGAGCCTAATTGTTAAATATTCTCTATTTTA
+TGAcaatatacaggaaatatgtcgaagagagaaacatgcaagaacaccgtagggtttaat
+aagataatcacaaggtatggaatattcaacaggatgagtatcctggattattcagcaaat
+acacagagctaaaaagcaggagaaaggaattcatatatatttttaaaaactaaaaagata
+tattagctgatgcaactttgaaacttctttagatcctgattcaaatagagcaaatttaac
+aaatatatttgaaactattaaaataatttaaaaatgaccaagtatttgattatatcaaat
+atagacaataataaccttgaatgtacatggattaaatgtccacttaGGggctgggtgtgg
+tggctcatgactataattccagcactttgggaggccaaggcagaaggattgcttgaggtc
+agaggttcaagtgcagcctggtcaacacagtgaaaccctatctctacaaaaaacaaacaa
+aaataaaaaaTTAACtaattttaaaaaatatatatttCTTCtaaattctccacctgaaag
+atatagactgactgaatgaattttaactatgatctgactatgtgcttccctgaacaaatg
+cactttacctgtaaaacacatattaactaaaagaaaagagatggaaaaaggtattccatg
+aacagaaaccaaaatgagtaggagtagctatacttctgtcagacaaaacagactttaagt
+caaaactagctttagaaaaaagacaaaaatgcttattatacaacgataaaggaatcaatc
+cagaaagaggatataacaattttaaatatatatgcagccaacactggagcagccagattc
+ataaagcaaatactactagatcaaaacagagaggtagactcaaatataataatagtgaag
+gacttcaacaccccactttcagcattaaacagatcatctaataagaaaaccaatctcgca
+gccctcaccctggagagtccacaggtaccaggggttggtctgaacccccagcacagagca
+cctgcctcacagaagagtggctgcatttttcttcctgcagttttcagtcctcacttctcc
+ttaccaagcagggccacctggcctgggactccggtacaactaccctgccccccacctgac
+gacttcaataagaagtagcccagcatttctccaaggaggaaataccagagtcaattcaca
+accactgcaattgcagtggtaccaccataacagcccttgggctgcagaaggaactaagag
+tctagtcactacagtggcaccttcagcacaccacagccaccatacagagaggaatccagc
+cccctcccctgggaacccccaccacccactccaccaggcacagcacccagctcataactg
+cagatcagttgccccacccacagctgagcttacctactggcagtggcccagactttccct
+agggagaggctcccagaggcaaacggcagcctctctgcccgtgtcacagcagcagttcta
+tccatgctgtcctcaggcttggaaagaaacaaagcgcctgaaggctgcacctgaacttac
+agcatgccacagttcccatatggagaggagaccagtctctcctcccagtgagccctaaac
+cccctgatccccaacaagcagagccctaacctcacaccagcagtacagctgccccatccc
+ccaggctgaacattcccagtaatagcagctccacctggagatggaacccccagggtcaac
+taaaagcccctctgccactgcctctacagtggtactacccctgctacccttgaactaaca
+aaggagcaaagaccccagtgctttatccacacctccaacaagctgcagtcgaccacaaag
+aagaaacacgtctgtctcccatgggtcctacccacaccccctgctgttcaccatggatga
+tagagtcaacagtgtgaaaacgaccatactgccaaaagcaacctacaaattcaatgcaat
+tcccatcaaaataccaccatcattcttcacagaactagaaaaaacaaggctaaaattcac
+atggaaccaaaaaagagcccacatagccaaagcaagactaagcaaaaagaataaatctag
+aggcatcacattactcgacttcaaactatactataaggccatagtcaccaaaacagcatg
+gtactggtataaaaataggcatatagaccaatggaatagaataaagaacccagaaataaa
+gccaaatactttcagccaactgatctttgacaaagcaagcaaaaacataaagtggggaaa
+ggacaccctattcaacaaatggtgctggtataattggcaagccacatgtagaagaatgca
+actggatcctcatctctcaccttataaacaaatcaactcaagatggttcacagacttaaa
+tctaagacctgaaaccataaaaattctagaagataagattggaaaaacccttctagacat
+tggcttaggcaaagacttcacaatcaagaacccaaaagcaaacacaacaaaacaaagata
+aatagatgggacttaattaaactgaaagccttctgcacatcaaaataaataatcagcaga
+gtaaacagacaacccacagagtgggagaaaatcttcacaaactatgcatccaacagagga
+ctaatatccagaatctacaaagaattggaacaaatcagcaagaaaaaaaaccaaacaCAA
+GGATGACAGTGGAAATACAAAAACAAGACATAAATATTCTGAATAGTGATAATAAAACAG
+TGCATACCAGAATAcaaactgtttccaagttacaatggttcaaccatttttcagctttat
+ggtggtgtgaaagtgatatccattcattagaaaccatgctccaggatgggcgcagtgggt
+cacgcctgtaatcctagcactttgggaggccgaggagggcggatcacaaggtcaagagat
+caagaccatcctggccaacatggtgaaaccccgtctctcctaaaaatacaaaaattagct
+gggcattgtggtgcgtgcctgtaatcccagctattcgggaggctgaggcaggagaatcac
+ttgaaccagggagtcggaggtgttgcagtgagccgagatcgtgccactgcctccagcctg
+gcaacagagtgagactccatctcaaaaaaaagaaagaaaccctactccgaattttgaatt
+ttgatattttcctggactaccaatatgtggcacaatgctctctcacaatgttgtgcaaca
+gcggtgagctgcagcttccagtcagctaaatgataataaaggtagataatccatcttgat
+atcttcctgaagaacataatgcctgcctaccatcaacaggcatcaatactttctaccagc
+tattctcaaccctcatgatcggaagagacagagactgactgtgtcaaagtattagtccca
+tcattcagcaattaactttagctcaatgcttcaaaaattcttcaggccctgtgtaatttc
+agctacgtacattaatgatgagtacccatacaaccattctgtttcttattttcagtacca
+tatttaataaatatcagttattcaatactttatttagacattttgttagattattttgac
+caactgaagtctaatctaaatgttctgagcatgttcaaagtaagctaggccaacctataa
+ttttcggtgtgctaaatgcatttttaacttatgatattttcagtttacgggggtttgttg
+agacataacttcatcatacatcaaggagcatctgTAtatgggatatagttaaagcagtga
+tcagaggaaaatctatagccttaacacatttattaataaaagtgtaggaattaaattatc
+agctgaaaaatgtaaaaagtatctaaaagagtaagcagaaagtacaagaaagaacccaaa
+gtagaaaaaagtgaaaattaataaaataagaagccaaaaaacagatcaaatcagtaaacc
+aaaaatcttgttctttaaacaaatcaacaaagttgacaaaaaaattagatcttttaatca
+tgaataaaaaaaagagaaagcacaaaaatgaataaggaatggtgagagaaataactattg
+ataatcagcaaataaaaaatcattaaaaacaatgttgttcacatctatgaaaaacattga
+aagctagagggaatgggtaattttctagaaaaatacaattcaccacaactgacttcaaaa
+aaaaaaaaaaaaAAAAAGAAGTACCGCACTTATGTGAGCAATTTCCATAGAGAAATACAG
+TTGTCATGGAATTATAACACACACACAAACACTAGGTTTAGATGTTTTCACAGAGAATTC
+CACCAAACCTTTAGAAATCAGATCGTCCAaaggcaaattaacaactctcagccatttgag
+gcaaaatattacaattgaggcaagatatactgtactgaaaacttgaggaaaaagcaggag
+agaaagttcctttgggaaattcgaatactcaaaagtgcttacatacaatgaaaaatttgg
+aaatccataagcatggccaaggtgggacacatgctcagaaaaggcctgagaagacactaa
+taactcacctttagtaattcctaggctcacagcaagaaaaaatgaaggctaaggcagaat
+tatatatggctccgctaagtgttgagggagccccaatacagagtcagtaagcaaagtctg
+ggagaagtttttcatatttttttctttcttggctccttgcagtcaaggaaatcattttta
+aatcactaaatgctaaatgaacacaagctaaaggaaccgagccttcaaacatcaaatata
+aaaaagaatgcagatattacaaaaccagtttacaaaagttactaaacaaataaaaactac
+atcccacagtgggtaacaaaaataaccttgaagaagggaaaaatttggtttccagaataa
+acacattataatatccaaaatgtccagttttcaacaaaaattaagaagcatgcaaataaa
+cacaaaactatggcccatttacagaagaaataaatgagactctccctgagtaagcagata
+ttgaaaatattagacaaaaactttatataactgtcttaaataaacttaaagagctaaaga
+aacccaagagaatgacatataaataaataagaaatatgaatttttttaaaggtacaaaaa
+aattctgaggctgaaaagtacaataagtaaaaagttactttttacttagggttccaatag
+aagatttgagcagctggaaaaaagaatcagtgaacttgatagatcaaatgaaatgattca
+gtctgaagagcaggaaaatgaaagaatgacaacaaaaaagaatagagcctaaagacctgt
+gtaacaacatcaagaatgcctacatacagaatcctggtggggagtgaggggcaggaagac
+tatttgaagaaatgtgtttgaaagcttcccaaatttcactaaaaacaaatatatacattc
+aaaaagctcagtgaacttcatcaaggaaatatacaaagatattcacaccaagacacacta
+tgtttcaaattgtcaaaaggcaaagcgaatgtttgaaagcagcaagagaaaggcaacgcg
+tcatttacaaaggatcctcaataagtttgacagcagatagtgcattataagccatggatg
+ccagaagagcttaggaaaaaggcaacgcgtcatttacaaaggatcctcagtaagtttgac
+agcagagagctcattataaaccatgggtgccagaagagcttaggatgacattttaaagtt
+ctgaaagaaaaaaacactgtcaaccaaaaattctataacttggaagatgccccttcaagt
+attaaggataaattacacattcccagattaaaaaaaagaaagagagagagagagaaagag
+aaagaaagaaagagaaagaaagaaagaaagaaagaaagaaagaaagaaagaaagaagaga
+aagaaagaaagaagaaagagaaagaaagaaagaaagagagagagaaagagagagaaagaa
+aaagaaggaaagaaagaaagaaagaaaaaagaaagaaaaagaaagaaagaaagaaagaaa
+gaaagaaagaaagaaagaaagaaagaaagaaagaaagaaagaaaagcaagcaagctttaa
+aagttcatgtttggtaggctgtacttcaagatacacttttaaaaaaaagactccttcaga
+tacaaactaaaaaacactagaaagtaactcaaaaccacataaagaaataactccagtaaa
+gataactacataggtaaatataaaagcaattatcacattttttgtaagtcttttttaata
+ttctatatgttttaaaacaaatgtgtaaaataatgactataaatctatgttaatgaagca
+tgatgtatacagatgtggtttgtgaaattaccaacataaagaaattcataggaaactaaa
+taataatagagattttgtatactattgaagttgtttcaatttactctaaattgttccaaa
+ttaagaatgttaattgtaaatccccatggtaaccactaagttaatatcttttgaaaatac
+agaaaaggaaagcacagggtaaacacagtgatatgctacaaaatagcaactaaacacaaa
+agaaggcgataattgaggaaattaggaacaaaggaggtataagacatacagaaaacaaaa
+gcaaaatggtaggagtaagcccctctttatcagtaattacattaaatacaaatgaattaa
+actctccaatccaaagaaagagattaacagaatggattttttaaaaatgatccaactata
+ttgtccacaagatactcactttagatcaaaatacacaatgagttgaaatgaaaggatggg
+agaaaatattccatgtaagtaataaccaaaggagatctgaggcaaatatacttatatcag
+acaaaatagactttaagtcaaaaactgttacaaaatacaaagaacagtatatattgattt
+caaaattaattaagaagatataacaattataaatatatgtacaccaactaacagggctcc
+aaaatatataatgtaaccattgagagaattaaagggagagacagacaattccacgaaaat
+tgttgggcatttgaaaacccaactttaaataaaagataaaacatctagagcaaatatcaa
+gggaggaattagaggatttgaataaaactataagcaataactatagataacacttctctc
+aaaaactgcagagtacacattcttctcaagtgaacatggaacattctccagcacagatga
+tatgttaggccataagataagctcaataaacttaaaaagattgaaatcatgcaaagtatc
+ttcactggccacaatggaatgaaataagatatcaataacaaaagaaaaactagaaaattt
+acaaatatttggaaattaaacaacacagtatttaccaaccaatgaatcaaagaacaaatc
+atgagggaaattagaaaatgtttagagacgattgaaaacaaatatataacaagatgggtg
+tgatatatcaaaagcagtgctcagagttgtaacacctacattttaaaaaagaaacatgtc
+aaatcaataaccaaactttactcaataaaccgtaaaaggaagagcaaacaaaatccagag
+ctagcagaaggaaggaaatgaagattagagcagagataaatgaaattgagaattaaaaaa
+ttatacagagatcaacaaaattaaaagttggttcttttaaaatatcaataaaattaatat
+acttttacatagactaagcaaaacatctctattcagctgactttttttacaagggagcca
+acattattcagtggggaataatagctttttcaacaaaaagtgctgggaatactgaatatt
+catatgcaaaaaaaatgaagctggacccctacctcacattatatacaaaatctagattgg
+atcaataatgtaaatataagagtgaaaaccatacatgcttagaagaaaacatggaaataa
+aacattgctgtggattggcaatgcgttcttagataatacaccaaaaatacaagcatgaaa
+caaacaaatGCAGCCAAAATGTACCAGAATCTGAAAACATCTATTATCTATGAAGAATTA
+GAGGGGAATTTGGTGAAAGAAATatgggagaatgggacattgctctgtgaatgcttttgt
+gcataattgtacatttttaattaagttaatcttttacactctcaaagtgtgatattaagc
+aagcaaagataagttattacaagactctaaaaccgaatgcaatgagaaacaagtgaatcc
+aaatatatttcaaatgaatgaatgacataatcaaacttaaggggaaaataataattaatc
+tgattaatttttgactgttcttttagttcaaattgacttttgaacatacttggactacat
+accattgcttgaaaaaataaaatatctgcaaaaaattattaaatcttcatgataggcttt
+tttctttttatattagtataaatataacaattctgaaacaaatgtatgtgcattgtaaga
+ttaagccaatgagtaaatattaatatatttgtattgctagaaccccagattctcactgtg
+aaaggacagagatacagatatggaataagacaaggaaagaagcagcccactgagttacat
+tagaatcagtattatcaacataaaTATGCAATGTGCTCTCTCACATGCTCTTTCCTTCTC
+TTAAAAAAATATAATATGGACATATTATATATTATATGCATAGACACACGTGTGTCTATA
+CATATCCTATCTATACATATTGAGGATTAACAGGTGCTAGTAGAAAATATTAACTTTCTT
+TGTATTAACAGGTGTTAGTAGAAAGTAGTAGTAGGTGCTAAGATAAAAGCCATAATTAAA
+cctcctggtgaatgaacacaccatcacctacaatcttaccaaaaatagaatcaagcacgt
+gtcctagtcaaacctctggattcaactgtcatttggataaaacgcaaaggatagtgaaaa
+tgtcgatcttcactgagagtctaaccagcaaatttcacagtgtggacatcaagtgacaaa
+aatcccaaatttttcaacaaatatattgtatgggaaagaaaactttgaaaagaaacctgt
+atgttagaagagattttaaaaacatgacaaATGAAAAAAAATGGGCAAGACTAAAACTTT
+TAAAAAAGtttgagacagggtctcactctgtcacccaggctggagtgcagtggtgtgacc
+atggctcactgtggcctcaacctcctggctcaagtgatcctaccacctcagtcttccatg
+tagctgggactacagctgcgtgccaccacatctggctcatttttttttcttttttaagta
+gagacggggacttgctatgttgcccaggctagtctcaaactcctaagcacaagcgatcct
+cccgcctcggcccctgaaagtgctgggattgcaggcatgagccaccacacccggccAAAA
+GTTGCTTTTGAGGAGTTATTGCTGTGTGGATGTGATATAACCCTTTCTGTCATCTCTTCA
+CAAAACTTTCTGTAAAACATAAAAATCACCTGGACCTTCAGAGATGAGTTTGtttatttt
+tttattttttaaaaaattGCTAATTTACAGAACATGGAGATGAGTATGTTTTGAAGGCTT
+GGAAGCATGCAAGTGGGAGAAGAAAGGAGTCAGCTACATTCTGGCTGTGTGCAGAGGCAG
+GTCACTGTGGTGGGAGTGTTCCTGTTTCATGGACTCTGCAAATCGCAATGCTTGGCATGG
+CCTCCCGACCCTGATGGCAGAGAAGCAAACACCAGTCGGAGAGCTGGGGTCCTCCCAGCC
+CTCTTGGCCCTGTGGCCAATTTTTTCTTCAATAGCCTCATAAAATCACATTATTTGAGTG
+CCCATGGCTCCAAAACAAGCAGGGATGCCCATGGACCCTGATTATCCATTGTCACCCTTC
+CCTCCAAACAGCCACCTCTCCCCTGGAGACAGCCCCATACTCCACTCAGACCTGTGCACT
+TTCTGGTATCCTTGTCACCTGCTTTTTATGTCTCATTTTACAAACACCAAATTGGAAGAC
+AGCAGGAGCTGCCCCATAATACCAGTAAAGTGAGAAGCAGAGATAAACTAGTCCTAGACA
+GCCGACTCATGTTGGGGGCAGCCCACTCACAGTGGCCCTGACCCAACTCTGACTAGAGGC
+CACTTGctctcaacaccagggtgctcaatggcccgtcctggtactctgctcttctctctc
+caccttcgctttcctgcaatctatgcagcctgtgactccatccatgggctagtgaccccc
+agaccttctcctgggaccacaggcctgtgtctctatctgctgctcaatacctcccctcga
+acatccatggctaaaactgagctcctgatactctctccctacccgcttctctgtggattc
+cccacctccgcgaaggacagcttcatcctttcagctactcaggccagaagattgaagtca
+tctccttctccaggaaatcgtattgagggagctacaaatatccaaaatccgatcgcttct
+cctccactacacccgaggcccgccacccatttttgcctgaattgctgcagcagcctccta
+accgatctctgctttcacgtgggcacctcagttttttccagaacaacaaccagagagatc
+tgctcacacccaagtcagaccaggttactcctctgctctcatagcatttggaggaaaacc
+cagagtgctcgtgttggccggcagagccggcccccatctcctctgacctcctccccacct
+cttgccctcagcacccagagtgctcgtgacggccagcagagccagcctccatctcctctg
+acctcccacctctcgccctcagcaccCAGAGTGCTCGTGTTGGCCAGCAAAGCCGGCCCC
+CATCTCCTCTGACCTCCCACCTCTCGCCCTCTGCACCCAGAGTGCTCGTGACGGCCAGCA
+GAGCCGGcccccatctcctctgacctcccacctctctccctcagctagtcctcgaacatg
+tctgatgtggtcccaccttgggacccacattgctactcctctgcctgtaggggtacccac
+agttatccacacagttcactcctgtctttcaggtctttgtgcaaatatcaccttctcagt
+ggagacTACaccttcaggacttaggctgtgcctggcacatagtaggtgctcagtagacac
+tggttgtaggaaggaatCTACAGGTTGAAATAAGGAGATCATTTCCCTGAGGTTCCGAAG
+CTCATATTTACTCACCATTTGTTGTTTACTGCTAATATTGAGCACTATCAGTAAAATACA
+TAAAACCCtttgccaatccaggaagtgaaaatgacactttactgttttagtttgcatttc
+tctgcttacaaatggattacacgcattttcatgtgctgttggctacttATTCATTCAGAA
+AACATACTAAGTGCTGGCTCTTTTTCATGTCCTTTATCAAGTTTGGATCATGTCATTTGC
+TGTTTTCTTTCTGATGTAAACTCTCAAAGTTTGAAGGGTATTGTCTTTTCCTGACACATA
+CGTTGTAAATAATTTTCTGGCTTACATTTTGACTTTTAATTTCATTCACGATGTTTTTAA
+TGAATAATTTTAATTTTTATGAATGCAAGTTAAAATAATTCTTTCATTGTGGTTTCTGAC
+ATGTCATGCCAATAAGGGTCTTCTCCTCCAAGAGCACAGAAATATTTGCCAATACTGTCC
+TTAAAATCGGTCACAGTTTCATTTTTTATATATGCATTTTACTTCAATTGGGGCTTCATT
+TTACTGGCCCTATTTGAAGCAAGTTTCTCAGTTAATTCTTTTCTCAAAGTGCTAAGTATG
+GTAGATTGCAAACATAAGTGGCCACATAATACTCCCACCTCctttgcctcctctcccagg
+aggagatagcctccatctttccactccttaatctgggcttggccaagtgacttacactgg
+ccaatgggatattaacaagtctgatgtgcacagaggctgtagaatgtgcactggggcttg
+gtctctcttgctgccctggagaccagctgccCCACGAAGGAAACAGAGCCAACCTGCTGC
+TTCCTGGGGGGAGACAGTCCCTCAGTCCCTCTGTCTCTGCCAATCAGTTAACCTGCTGCT
+TCCTGGAGGAAGACAGTCCCTCAGTCCCTCTGTCTCTGCCAACCAGTTAACCTGCTGCTT
+CCTGGAGGAAGACAGTCCCTCAGTCCCTCTGTCTCTGCCAACCAGTTAACCTGCTGCTTC
+ATGGAGGAAGACAGTCCCTCAGTCCCTCTGTCTCTGCCAACCAGTTAACCTGCTGCTTCC
+TGGAGGAAGACAGTCCCTCTGTCCCTCTGTCTCTGCCAACCAGTTAACCTGCTGCTTCCT
+GGAGGAAGACAGTCCCTCTGTCCCTCTGTCTCTGCCAACCAGTTAACCTGCTGCTTCCTG
+GAGGAAGACAGTCACTCTGTCTCTGCcaacccagttgaccgcagacatgcaggtctgctc
+aggtaagaccagcacagtccctgccctgtgagccaaaccaaatggtccagccacagaatc
+gtgagcaaataagtgatgcttaagtcactaagatttgggCAAAAGCTGAGCATTTATCCC
+AATCCCAATACTGTTTGTCCTTCTGTTTATCTGTCTGTCCTTCTCTGCTCATTTAAAATG
+CCCCCACTGCATCTAGTACATTTTTATAGGATCAGGGATCTGCTCTTGGATTTATGTCAT
+GTTCCCACCTCGAGGCAGCTTTGTAAGCTTCTGAGCACTTCCCAATTCCGGGTGACTTCA
+GGCGCTGGGAGGCCTGTGCATCAGCTGCTGCTGTCTGTAGCTGAGTTCCTTCACCCCTCT
+GCTGTCCTCAGCTCCTTCGCCCCTGGGCCTCAGGAAATCAATGTCATGCTGACATCACTC
+TAGATCTAAAACTTGGGTTCTTGgaccaggtgcggtggctcacatctgtaatcccagcaa
+tttgggaggccgaggcgggtggatcacaaggtcaggagatcaagacgatcctggctaaca
+cggtgaaaccccgtctctactaaaaatacaaaaaaattagccgggtttggtggcaggtgc
+ctgtagccccagctacttgggaggctgaagcaggagaatggcgtgaacctgggaggtgga
+gctggcagtgagccaagatcacgccactgcactccagactgggagagagagcgagacttt
+ctcaaaaaaaaaaaaaTCTTAGGTTCTTGGATGTTCGGGAAAGGGGGTTATTATCTAGAA
+TCCTTGAAGCGCCCCCAAGGGCATCTTCTCAAAGTTGGATGTGTGCATTTTCCTGAGAGG
+AAAGCTTTCCCACATTATACAGCTTCTGAAAGGGTTGCTTGACCCACAGATGTGAAGCTG
+AGGCTGAAGGAGACTGATGTGGTTTCTCCTCAGTTTCTCTGTGTGGCACCAGGTGGCAGC
+AGAGGTCAGCAAGGCAAACCCGAGCCCAGGGATGCGGGGTGGGGGCAGGTACATCCTCTC
+TTGAGCTACAGCAGATTAACTCTGTTCTGTTTCATTGTGGTTGTTTAGTTTGCGTTTTTT
+TTTCTCCAACTTTGTGCTTCATCGGGAAAAGCTTTGGATCACAATTCCCAGtgctgaaga
+aaaggccaaactctggaaaaaatttgaatattttgagccaaatgtgaggaccacaacctg
+tgagaacggaaaataaatcctgggaccccagactcactaagccaaagggaaaagccaagc
+tgggaactggcttatgcaaacctgcttcccatctggttcctaaataagatagctattaca
+caaagacaaaaaagctacatccctgcctctacctccatcgcatgcaaaatgtgtattcag
+tgaacgctgaccaaagacagaagaatgcaaccatttgcctctgatttacccacacccatt
+ttttccacttcttcccctttccccaatacccgcacttttcccctttacttactgaggtcc
+ccagacaacctttgggaaaagcacggaccacagtttttcctgtggttctctgttcttttc
+tcaggtgtgtccttaaccttgcaaatagatttcttgaaatgattgagactcaccttggtt
+gtgttctttgattAGTgcctgtgacgcagcttcaggaggtcctgagaacgtgtgcacagt
+ttagtcggcagaaacttagggaaatgtaagaccaccatcagcacataggagttctgcatt
+ggtttggtctgcattggtttggtctggaaggaggaaaattcaaagtaatggggcttacag
+gtcatagatagattcaaagattttctgattgtcaattggttgaaagaattattatctaca
+gacctgctatcaatagaaaggagagtctgggttaagataagagactgtggagaccGTGCA
+TAGTTGCTTCCTGATCAGCTCTTTATTTGATTGAGAGTGAGGCAGGGAAGATTAGAGGGA
+AGCTTACAGTGGAATTCAGGGCTGAGGCTGCTATTCTTTTGCTCCTTGTAACTTCCTACA
+GTGTTGTCAGCATCCACATACTTCTCTGTGGGGTTggtctcagagccaggttaccttgtc
+ttaggtccagtggcaccctgactggcttggtgtccttgaacaagttacctaacctctcca
+aacctcagtccctcagttgtaaaattaaaaaaaaaaaaaagaagaagaagagtacctact
+gtatagcattgatttgaagattgaatgagctggtattatacaacgtttagaagcagtgcc
+tgacacgcaaaaggctctcaacaaatACTATCCTTTACTAATATCCTGTGTGTCTGTATC
+AGAGCTGGTGGGGTGGAGGGACAGAAACAAGTGGGAGAAGGTaaagagatggacaaatga
+tctctaaagtctctctggcactaacaCAATTCTTTATTATGTGTTTTGTCTGGCTCTTTA
+TATTGATAGCTGTTCCAGAGGCAATCAATAGCTATTAGTCGGTTTTATTCTTATTTTTCT
+GTCTGATCTTACAGGGGAGCAAACTGTGGCAAAGTATGAACTTACTTCTCAGGAAATTAA
+CCATTATATTGGCAATCACTGTGATTATTTGAACTTCAGCGTCTGGACAAATTTAGTCAC
+ATGAAATACAGAAGAGAGATTTCTCATGGTTAAAACGAAGCTCTCTTTATTTGCTTCTGC
+TAATTAAAAAATCAGAGCTAAAGATACTTAAACACTACAGTTAAAATGCCATGGTTGTCT
+ATTGGCTTAACGAATTCTCTTATGAAATCAACTCTAAAATGCTATCCATCATAAATCATG
+AAACGCAATTTTTCTTATTCTCTTTAGAGCTTTACAATTCATCTTAAAGACCAGTGTTTA
+CACTCTCTTCTGTAGGTTGTACAATAACTTTTGGCGAGAAAAAATAAAAGTCTGGCTTTC
+TGACTCATAGGTGTGTTCCCTTTAACAGAAAAAGAAAATATGTCCTCTTTAAAACTGATG
+ATCATTGGTCACCTCAATTTTATTGAAGTTCACTTCTGACCTCTTTAGATGTAGTTCTCT
+ACATAAAACTGCCCAACAGAATTCTCTGTCTGAATGTCTCCTCCACAAACAAAATTTTAA
+GAACTAAAATTATCATCTTTCCTTCCAAATATGCTCTCCCTATGTCCCCAGGGCTCTCCA
+TGTGTAGAGCTGAGACCATTTGCCACTCAGTTTCCTCACCCAATTAATTACAAGTCCCAA
+CAATTTTCCGGtttttttgtttttgtttttgtttttagacggagtcttgctctgtcacca
+ggctggtgtgcggtggtgcaatctcagctcactgcaacctccgctgcctgtgttcaagcg
+attctcctgcctcagcttcccaagtagctgggattataggtgtgtgccactacatccaga
+taatttttgtatttttagtagagaggggatttcaccatattggcccagatgatctcaatc
+tcttgacctcatgatctgcccaccttggcctcccaaagtgctgggattacaggtgtgagc
+cgccatccctggccCAGTTTTGCCTTTTTAACATCCCTCAGCTCTTCAAATCCATTTTCT
+cttctctaacacctccccattccccagctcgtaatgaactcgtaagtagattactacaat
+cacctcccaaatggtcttcctggctccatcagccttgtgaccttcaagttcattttccac
+atggatgtcagagtaactttctaaaatgaaaatctgaccacgttactctcttgcctaaat
+ccgcctatggccgctgttaggatcaagtctaaactcccgaccctggaacatcaggtcttc
+gtgctctgttcactgcttctctacctcacctgcaaccaACACCACTCCCACATCCATATG
+CTGCTCACCGTGTATCAACATGAACAGGAGGTGGGTGTTTCAGTCCCCAGGAAGACACTG
+GGCCTTTTCAATCATCTACTGCTGTGTAATAACCACCCCGCAAACTGACCACATGATTTC
+ATTTTGCAAGGGTTCCTTCCTTgggctgtgttcagcaaaagggtttactgagctggcagg
+tccaagatggcctcactcacaggactggctgttgatgggagccttgatgctcttgggctc
+accccttatcctccagtaggttagagcttcttacagtggtttcaggcagcatctgaagac
+agtaaaagcagaagctccaaggcttcttacattctagcctggaaaatcacatcacattgc
+ttccttcatatttttttggcaaatcaggttgcaaggcttgcccagattagggtaaagagg
+caaagaggctccttttcttTTCttttctttttttttttttttttttttttgagtcagaat
+ctcgctctgttgcccaggctggagtgcagtggtgcaatctaggctcactgcaagctctgc
+ctcctgggttcacgtcattctcctgcctcaggctcccaagtagctgagactacaggcacc
+taccaccacgcctggctaatttttttttattttttattttttagtagagactgtgtttca
+ctgtgttagccaggatggtctccatctcctgacctcgtgatccTTGCAAAGGGACATGCA
+GACCACATTAGTGAGAATATGTGCCTGTATTTTGCAATCTGTAACATGGGCATAAACTAA
+ATGTTTTCCAAAGGGAATAGGGCAAAACAAAAAGGACCTTGACCACTCCTTGGCCCTGAA
+TAAATCCAGGAAGCCTAAGAGTATGACTATCCTGAGGTAGAAAGAGGGTCACATGCTGGA
+TAAGAGGTACCTGGGCTCTCCACTTACAAGAAGAGAGCATGGTTACATTTATAATCACCA
+TTCCCAACATGCTGTGAGTGCAGGCAGCTACCAGGAGGAGAACAAAGGAAATAACCAGGA
+CACTCATCTCTAAACCTGTTAATTTAATCACACGGAACACTTCTATTTAAAATTCCCGAG
+AGTTAAGATGTAAGAATGCTTATCAAGGTAAATGCTGTTCACACTGCTTGGAGTGTCAGG
+CCTAGATCTCTATCCATCAGAaacaacaatatcaataacaacaacagcaacaTGATGATG
+GGGCAATTTCTTAAAAGCACCATGTATTTTATCGATACATGTCCGTTGCAGAAAATCCAG
+GTGAATCCAAAGAAGAAATAAATGTCTTCCACAATCCCATAGCCCAGAGCTAACTAACCA
+CTATAAAGAACCCAGCGTGGTTTTAACTAATGGATCAAAAGATGCTCATCAAAGGCTCTG
+AGCTTTCCTGAGTGCTAACAGGAAACATCCAGCATCACTGGTCTCTCCAAGGCTGCAGGT
+GTCTTTGCCCATAGTGCCTGTTTTGTGTCAGGGAAAGAATCAACCTGGGAGCCAAGCCCA
+GGAATCAGGATGACCAAGACATACTGCACAAGGAGGGAACAAACCCATCCAAGGACACTC
+AAGGACAAATCAAGCAAATGAATTTAAGGGAGACGTGCTCATGGTCTGCTTTGCTGCTCA
+GCATGGCTGGGAGGCACAGTGGAAGATCATGCATCCTGCCCCTGGGACTCCTCTGCCAGA
+GCCTGAGAGCTTTCTCCTGCCCACAGGCTAGGGGTAGGGCAGTTGGAATTGATCCATGCC
+TTCTAGCTAGACTGTGGGTCCCCTCAGTCTTGGGCATGGTGACAGCCCAGCATCAGACAG
+AGGTCAGTATCAAACTAGAAAATTTAATAAATACTGTCAGATTTGTAGACCCAAGAAAAT
+ATAAACTGCCAATCACGGAGGAAAAAAATCTCTCAATGATCTTATCTTTATATGATTCCC
+TTGCTGCCTGGAGATTGACATTTCCTTGGGGATAATCTGGTCATAGGATTGGTGAAGGTG
+GAAGGGAGGCAACCTCCAAAGGTGGGGCCCTCTGCTCACCTGGGACAGGGAGGGCCTGAG
+GTAGGTGTCTGTGTGGGCTGGGGAGGAGGATGGGAGCAGTGCTTCTAGATGTTTCCACTT
+TCTCCTCATTAGATAATAACGAATGGGTGATTTCCCTAGTCACTGCAGTGTGAGGAAATC
+TACAAAATTAATTTCACAATACGCTTTACAGGATAGGTGGAGAAACACATGAAGTACAAC
+TGCAGTGGGTTATAAAAAACGGCCTTTCGAGTTGAGCAATAAATTCGTTCAAGCAGCCAT
+TCTGAAGGACAAACTGGCTCTGTATTTAAGAGGGGCATTCCAGCACTTCTCTAGCCACTG
+GGTTGACAATGACTCACCAAAGCCTCTGGTAGCCACCACAGGACACCCAGAGCATATGTT
+TTAAAGCTGAACACCAAACTGCGGACTTCGGGAGTAAGTGAACTGACTGGTTTTTATTTT
+GTTTTACTGCTTTTAACATTACAGTAACTGTTACAGGTTCCAGCAGGCTAACTGGGTGGA
+AATGAGTTTGGTTTCACTTAGTCTCTCTAAAGAGAAAGCAAGTCGGTAGACTAATACCTA
+ATAAAAGCAAAGCTGCCAACAATTGAAATTGCCTAGGCTGCTCTGTGTGTCCCACAtgca
+tgggtgtgggtgccagtgtgtgtgcgtgtgtgcatgcatgtgcatgtgtgtTGGGATAGA
+GTGGTAAGAAAATGGGAAATAATAAGAATGTTCAGTCCATAGCCCTTCATTATAAAAAGG
+TGAGCTGTAATAAATACTAGTGCCACATTTAGCCAAAACTTTACTCCAGCCAAAGGTGAT
+ATTTTCATGATAACATCCTGTGATTGCTTTGTTCTTCGTCTTTTATGTTCTTCCTAGATG
+GGCTCAGAACATACAAGAATTAAGTACACATCTTATTTTCCAGTGATAATGCTACCGGCA
+AATTCTGTTGTTTGTATAAACATCAGCCATGTTTATATAACTAAACTAGTGTTTTGTTTT
+GTCAATTCAGCAAGAAATTAGACCAAATGGTGGCTTAATGCTGCATTGATTTGGCTATCA
+ATTTGTTTTCACTTTTCTGCAAAATAATTAATACATTATTAAATTGAATTGTGCTGATGC
+CACAGTTGTTCTTATCTCAAGTGTCTTAAAATTCATTTAATTTGTTTTTCCTTTGGTTTC
+ATTATTCAAATTTTAACTTCAGTTCTCAAGATTTTATCTGATGGAAGAGATGGAGTCCAT
+TACTAAGGACTCCATTGTGCTCCATCATGCCAGAGTTGTAAAATAGATCTTTTAAAGGAA
+ATTTACTGTGATTTTTTTTCTATTTAAGAGCTTCCTCTCCAGTTGAGCATGTAAGAAAAT
+TATACCAGGAGAATACAGTAAACTCTATGAGGCAAGCTATAAACATGTAGCATTGTGATT
+AGGGctggttctccttctagagacatggtaggattgcaatttcataccatccttgaagtt
+agagagagccacgtgactcatttagccaatgaactgtgagcagaatgacatgtcacttcc
+agctgaagctttaaCAATCTGAGAGACATTCATACATTTTCCATGTGCTGTAGCCTTATA
+CCCAAAGCCTGGGTCCCAAGTGACCATGACAGGCAGAGCTCCCTGttgagccacagagat
+ttagagaatggctgttaacacagcataatccagcccatcctgactaatCTGATATTAACA
+TGTATAATAAAGAATTCTATCAATGCTGAGGGAAGATGACTAGTTAAGGTCCTAGGTTGC
+AAGTCTCAAAACCTCTTCTAAGGATTGTAGACAGGAAATTAAATGACTTCTAGTCCCTAG
+AGTTCCCAATCTCCTACCATCCCATCCTAATATGACAGAAGTAATTCCTGAGTTGCTTCT
+GAAACCAGAGCTTCCCTCAGAACCCTTAGCCTGCCAGATGGCTTCTTGGAGAGCCCTCAC
+TCACTTTTCTCCTTCTGCTATTGCTGCTCATTCATTCCAGTTTTTAAAAATTCATCTTTA
+TCCAGGAACCTCGCTTCTAGAAAAGTCATACAGGTGCTTCCAGGAGGCTACATGGGCACC
+CATATTTTTCTAGCCACTTTCATTAGACCAATGCAGCAGAGAAGAAAAGCCTCAATAATT
+ATTATGACATGGCATGTTAGGATACCAAGTAAATTGCATTTGTAAAATGTGATTTTCTGT
+TGGTGTTCACTTCAGCTCTACTGACATTTGGTAAGTATTATTGACTGACTGACTAACTAA
+TGTGGTCATTAGTCTTCATAAAGAAAGGCTCTCTACAAAAACGGAGGGATGCCCTTTTTC
+TGGCATTTAATACGTAAGAAATTGCCTCCAATAGAAACCAGAGTTGCCTGATTACTATCA
+GCACAGGAGAAATGTATTAATGTGCCTTTCTAGTAACAGGTTTTTAGAAAGTCAAATATA
+AACAAATCTGTCTATTTGTGTGTGTGCATGTGGTAGTGGGGAGGGAAGAAAAAAGGAGGG
+GGAGAGAAAGAGAAATAAGAACCAAGTTTATTATACTGTATTCAGGGGGAAAAAATTTTC
+CCAAGGTCCTAACAGAAGAGCAAAGTGCCACTGTCAATAGCCTCAGTAGTGTTAGGGTTG
+CTtttatttatttatttatttatttatttatttatttatttatttttccttttttttctt
+tctctttttttcttcttttttttttcttttctttcttttttttttttttttttttttttg
+gacagagtctcacactgtcacctgggctggagtgcattggtgcaatctcgactcactgca
+acttctgcctcccaggttcaagtgattctcctgcctcagccgcccaagtagctgggatta
+caggtgtctgccaccgtgcctagctaatttttttgtatttttagtagagatgaggtttca
+ctatgttggccaggctggtctcaaactcctgacctcatgatccacccacgttggcctccc
+aaagtgctgggattacaggcgtgagccaccgcccctggccAGGATTGCTTTTACAGCCAG
+TCTTCAGGTGCCCACTGTAGGAACAATGTCATTTAACCCTCGGGATTATTCTGTGCCAAA
+TATGGATAATGACTAATATCCAACACAGATATTCTCAGCTCAGAAGAGCAATTAGCAAAT
+TCATAAATTAAGTGCTTGCTTCCTCTTTAGTCAAATACAAACGTTTGTTAAAAGATATTA
+TTTTGCTTTACACTTTTTCTCTCAGAAATAAGCAGATGCTTGAATTCCCACAGTGCTGCT
+TGAGCCTCACACCATGTCATCCTGCCAGGCACCCAGATCCAGTTCTAGAGTTTCACATGA
+TCGTGAgtgttggttaataagtcaatgtgaactgggaggggagatttttcaggagtgcca
+cagggctctccctttaatcACATACACTCCCTGCTTTCATTGGAAAGTGTATAATGATGT
+CAGAGTGCCCCAGAATGGAGCTAGTTGGAAGACTGCCGTCATAGGGATGCCTTAGTGAAT
+TAATAAGGTTTTAATTTCTGGCTCTCAACTTTGTAGATGTAAAAGTTGATTTATCAATAT
+GTGAGAAAGGATGAATCTTTCTGAAGGTTATGTCATCACACTCACTAAGCACACAGAGAA
+TAATGTCTAGAATCTGAGTGCCATGTTATCAAATTGTACTGAGACTCTTGCAGTCACACA
+GGCTGACATGTAAGCATCGCCATGCCTAGTACAGACTCTCCCTGCAGATGAAATTATATG
+GGATGCTAAATTATAATGAGAACAATGTTTGGTGAGCCAAAACTACAACAAGGGAAGCTA
+ATTGGATGAATTTATAAAAATATGCCTCAGCCAAAATAGCTTAATTCACTCTCCCTTATC
+ATAAGGATAATCTTGCCTAAAGGGACAGTAATATTAAAGACACTAGGAATAACCTCTGTA
+CTTTGGACAGTAGACCTGCATAGCCCATTAGGCCTCAATGAAGTCTTATGCAAGACCAGA
+AGCCAATTTGCCATTTAAGGTGATTCTCCATGTTTCTGCTCTAACTGTGCTTCACAATAC
+TCAAAACACTAAATCAGGATGTTTCCTGGAGTTCAGGGAGCTGTCCGTGTTACTGAGCAG
+TTCTCAGCAACACAAAGATCCTACTGACTCCTCATCAGACTTCTTTCTCACTGGAATTTT
+ACACCTGGGCTGTTAACACCAGGCCAGGTCAAATTCAAAGGAGAGAAAAAAGCTCATTAT
+GAAGGGTAAAATCCAAAACACTGTGCATAAAGATATGGCACAATTTTTATACATAAAGAT
+TTCATAAAACCAAAGCATCAGGAAATGAAAAGAGATACAGAAAGAAAAATGATGGTAAAT
+GAGACATTAATTTACCCTTCTAATCTCTATCACAGCAAAAAGATAATTAAAAAATCTATA
+TGAGGACCACAAAATACACAAAAATTATGTAGCAAAGCCTATAGCCTGAAAAAGTAAACA
+TTGAAATTTGTATGTCCATAAAATGTTTACAAAATTCAGTACATATTACACACCCCACCC
+TAAAAACATCTAAGCAAAGTAGAGAATGTAGAAATGCTACAGATTATATTCTCTGATTAT
+GACACAACAAAACTAGAAATTACAGCATGGAAATTTAAAAGCTTTCTCTTAAATAATTCT
+ATGTCAAAAAGAAATCCAggccgggtacagtggctcatgcctgtaattccagtactttgg
+gaggccaaggtgggcaggtcacttgaggtcagcagttcaagaccagcctcgtcaacatgg
+taacaccctgtctctactaaaaatacaaaaattagctgggcctggtggctcatgcctgta
+atcccagctacttaggaggctgaggcaggagaattccttgaacccagaaggtggaggttg
+cagtgagctgagattgcaccactgcactccagcctaggtgacacagcaagactctgtcaa
+aaaaaaaaaaagaaaTCCAAATAAAATTTCCAGAATATGTGGAAAATAGTGACAATAAAA
+ATATTAcacatgtgtaatcccagcattttgagatgccaaggtggcaggatcacttgagac
+caggagttcgcaaccagcctggacaacatagggagactccatctccacacacgccaaaaa
+aaattttaaatagccaggtatagtggtacttcctgtaatcccatctacttgggaggctaa
+ggtgggagaatcacccaacctcaggagttcagggcttcagcaagccatgatcatatcact
+gcactccagcctcagcaacagagcaagatcctatctcaaaaaaaaaaaaaaaaTCACATG
+TGGGAAATAGCTATAGCACAAtaaaaataaatgtattaagtatgaacaacaaaaaagcta
+gtaaaggttgaacaacaactatccttaggaaagtggaaataatgtattaataaatatgaa
+agcaggctagccacggtgactcacatctgtaatcccagcactttgggaggctgaggcagg
+cagatcacctgaggtcaggagttccagaccagcctggccaacatggtgaaatcttgtctc
+tcctacaaatacaaaaactagccaggcttggttgtgcactcctgtaattcgagctacttg
+ggaggctgaggcaggagaatctcttgaacctgagaggcagaggttgcagtgagccaagat
+catgccactgcactccagctggggcaacagagtgacactccatctcaaaataaataaata
+agaaagcagaaactaataaactagaaaacagaaacatagaactaatttataaatcaaagc
+actatgccttgaaaagaGGGAGAAAAATTGTGAATTAAGGAAGGGAAGAGATGGTTGGAG
+AGGAGGTGGGAGAAGGCAGAGATAATTGAAGGAGCAAAAGCATCTGGAGAAGCAAAGCCA
+CTGAAAGATGAACAGGGCTCTGAAAGAGATGCTTGACTGCTATCTTTTCAAATGACTGCA
+GTTCCCAGTGACATCATTTTTCTCCTCCCTGGAAGTCTGAGGGGCAGTTCACTTATCTCC
+TCCCCTCCCCTACTCCTCACCCCACACTCAAAACCTGTCTATGCTCCTTTCATTCTCATA
+TGACAGATTTCAGATGGCATTCTTATTTCCCTGATTTCTTTTTGAGATAGCTTGCATTTC
+CCTCCTCTATataaagccaccgtttatcaaatgcctacatggaccaagcagtccacaagg
+gcttcacagacagttttactaaactcatgccaaaactttcaggttttatacctaccttat
+agataaagaaattgaagcttatagagtttaagtaatgttcccaaagcctcgtggctagta
+attcaaacctaatttctgcctactccaaagtctatttttccttatgatactctactgcct
+ctcCAtggataaagacagagatcacatattaataaaatttgcacaaagtcggcaaattgt
+tgaaagggaaggctaagatgattaataaaatcaagagccagatgatctcaacaacctgaa
+ataactggctgacaaccaatttgaataactccctgcgggtgaagttcaaagtactatttg
+ggtttttttttaaagtttggctgggtgcagcggctcacgcctgtaatccaagcacttagg
+gaagccaaggtgggcagatcatgaagtcaggagttgaagaccagcccggtcaacatggtg
+aaaccccatctctactaaaaataaaaaattagccgggcctgctggtggatgcctgtagtc
+ccagctactcgggaggctaaggcaggagaatcgcttgaacccaggaggtggaggttgcag
+ggagccgagatcgcaccactgcactccagcctgggcgacagagcgagattccgtctcaaa
+aagtaaaataaaataaaataaaaAATAAAAgtttgatatattcagaatcagggaggtctg
+ttgggtgcagttcatttgaaaaattcctcagcattttagtGATCTGTATGGTCCCTCtat
+ctgtcagggtcctagcaggaaattgttgcactctcaaaggattaagcagaaagagtttaa
+tgaagggtctctttccagggttaagggaactgctagggtttggatatttgaccactccaa
+actcatgttgaaatgtgatccccattgttggaggtggggcctaatgggaggtgttttggt
+cctgagtgtggacctctcacgaatgtcttggtgccatccaagtgagttcttgctcgctct
+tttttttctttttgagatgtagtttcactcttgctgcccaggttggaatgtagtggtgcg
+atcttggctcactgcaacatccacctcacgggttcaacccattctcctgtgtcagcctcc
+agagtagctaggattacaggtgcccaccactatgcccagctaatttttggtatttttagt
+agagacggggtttcaccatgttggccaggctggtctcaaactcctgacctcaggtgatac
+acctgcctcggcctcccaaagtgctgggattacaggtgtgagccaccatgcctacctagt
+tctagctctcttaattcccacaagagctggttgttaacaagagcctggcacaaacccctc
+tctctcgccacgtgatctctgcacatgccagcttcccttccccttctgccatgagtggaa
+acagcctaacgccctcaccagaagcaaatggtggcaccatgcttcttgcacaccttcaga
+actgtgagccaaataaacctctcttctttaaaattattcagcctctggtattcctttata
+acaacacacacacacacacacacacacatacacacacacgcaaaagcagactaaaacagg
+aactaattagaaatggtgatgcaccgagggattggcaCCGAGGCTCCCCAACAGGAACTG
+AGGTCATGGATAGAAGGACACATTCATGTTATTTTTTTCTAATGGTTAAGTAATTATTTG
+ctcttactctcaaaatttctgccaaggcctcccatggaccaaactcaactagaatctagg
+aagcagagaacctgagtgttgcattcagcagaagtcagcttcctagggaatcttgcagga
+agggtgaaggtagagaatctggtggggaagcaagcaaatgcccatcacaTGCACTTTCCT
+ccaacagagcgactcagatgctataaaacttgctaacacagtctcagggtctgatcacag
+taacatacaatccaggttttaatcatcagaaatcacagtcctattgtcttctgcacagac
+ccaaacacacttggaggtcatgttcaatatgaatacctcacagagaaggaaatttacacg
+cgagaagtacatctgcagaaagccagctggcatgtcaaccattcaaaaactcagggtgtt
+ctggataaagaagactcaggaagacaagtatgaagcataatctgtgacattccatgcggc
+agacattagacacatacaagagagttgttggaaagcggaatttatcttcatataaacaac
+actgagctaaatctcaatatttcagatctctagaactatccatcagtgaaatggattgca
+aatacaaagagtaataccatgtcacttaagaatagaatcatggacgaggctgccacctgc
+tgttgggggccactgcagaagaaattccagaacactggactggagagcacctcactttcc
+ttacagctctaagtttctgACTCAGTGACCTGATTCACTACCATATACACAAAGACCCAC
+TTACACAAATGACTGTTCTTCACACTAGGCCCATGGAGACAGGGATAAAATTCTGAATTT
+GCTCAGATACCTTCTCCGCTACTGACATCTAGGCATTACACAATTCATCTCTTCATATTT
+AACCTTTGAAGTTTGCTACTTCTCAGAGAGACTAATGAGTAGTGAGCAAATATCCTGAAG
+CTGAGAATGCTTCTACCTCCTCTCAAAACAACGGAATATTCATCAAAACACAGCAGTTCT
+GCACTTAACTTTAGGCCTTTTCTAACACCTTGTTTCTTGGCAGTAACTGTGGCCAGAATA
+GCTCTTTCCACAGATAAAGGACCTTTTGAAAGGATAGGGTCTCTAGATAGAAAAGCAAAT
+GCCTCATTCCAGAAGGTCTTCAAGAAGAAAATGTTGTGGTGATAACAAACATAACTGATT
+ATAATCTATTCTGTGAAAAAAGCTTATGAAACAGTAGATGTGTGTATCTAGTACATAAGA
+GCTGAATGTCAATATATATATAGATATATACacacactcaaataaataatagttatctct
+aactagagaaattctagttgccttatattttcttctttttccttactatattttctacaa
+taaacatgtgtttttaacaagaaaaGTCTTTTCTGGTGTGCTTTTTAATTTTCTTTGTTT
+AAGTGAGAGTGAGGCTACATAACTACATGGCTAGGTAGACTTTTAGAAAACTTGGCTGCT
+CTAGAAAATTGACATATCCTGATTTCTTCCATAGCTTGGATCTTGACCTAGAGGGAAATA
+TAAAAGTGTTGACTTGAACCTGAGGGGTGCCATTTTCACTGCTGAAGTAGTTTCATGGAT
+CATGAATTGGAGAAATGACTTCAGCAACATGGGTGTTAAAATCAGAAAGCACAAGTGACC
+CACAACAGATGATGGAGAACAAAGAGCAAGCTGGGAAAGCAGTGGCCTTTAATACAGAAA
+AGAAGAAGTATAGCCACAATAAATATTAGGCAGACAGCAGTTCAGCAGTTTATACTATTA
+AGCTGTTGTTTAGGGGAATAGTAAACTGACATGACCCTTGAGGTAGGTATATATAGGTAA
+ATTCTATGTGTCCCTTGAAATAGGTGTATGACACAACTTCTGGCATCTACATGGATTTGG
+TCACTCTAAAGTAGCCATGAGGCTTAAGATAGTTCAGCTGTTTGGGGATAAGTTAAATCA
+TTTGCCATTGTCTTTCTGCAATTTGCATATCCTACAGTTATCATTGCCATTACTGAATGG
+CACAGAGAAAAATTCTGGTCTAAAGTGGTTCTCAAACCTGGTtgctggagggccaccctc
+agtgatgatgatttaatctgtagaagaatagaacattgatagtttttatatatctccagg
+taattttaatatataactggggtgagaatcattgACATAATTGTAACAGGATAATATTCA
+GGAAATATGGAGATAAATAATTTTCTTCTCGACATTAAAAAAATCTAATAAAAAGTTTTA
+TGTTTTCCCCTAACTCAGGGTCATCAGCCTTCAAGCTTCAGTCTCTGTGTGTTCACAGGT
+GCTGTAAACACACGCATCACTACTAATATCCCACTTCAGTGCTATTGCTGCTCCCAAAAC
+TCCAGGTATTTTTAACCTTATAAACCTCCAGAATAATGAGACCACTGGGTTCAGTAAATT
+GCTTTGTTTTGAAGCACTATTAGACAAAGTGGGAGACTAGAAGATAAATCTGTCAATGAC
+ATGTCCTTTAAGACTACTTAGATTTTGTTGAATTTGTGGATCATTCCTTACTTGAGCAAA
+TGGTAAATTAACTCTCTCTTTTCTCTCTCTCTCTAGCTGGCACACTTTTTCCAGTAGCCA
+TTCTACTTGGTATGCTTACTTATCAGCTGTCCTCCAGGGGCCTCACATTAGATGTTTCTC
+TGACTAACCAAACATGACACACAGCTGAAGTCAGAAAAACCAGATTGATAATTTCACTCA
+AACTATTTTCCTTCATTCTAACAATTTACTGGAGTACACAATTGTGACTATTTTTAGCCA
+TAGGAACTCATAGAAAGACCAACTTCATTAGACCTACAAAATCGAATTGTGTAACAGTAT
+ATGCAGTATGTGTAGGAATAAAAAGCATTTCTCAAATATGCAGTACTGGATTTTGCAAAA
+GCACCTTACACTTAGCTATAAAGGAGTGGAAAACACAAAGATGAGTAACTGCACTTTTCA
+AAAGACTAGAGCTATACCAATAATACAAAGGTGTAAACAAATAATGATGAGATGACAAAG
+GCTGAGTGTTTTCTATTTGGAAGCTATGTTGTTGAGTTATTTATGTATATAATTTCATGC
+AATCTTCATGTTATGGGGATGTTctaatccactgtgactctgtccttaaataaaagggag
+atttggacatagagagaggcacacggggaggatgccatatgagaattgacactgtgctgt
+cacaagccaaggaactactggaaggagagaaagaggactggaacagttccttccttagca
+ccttttcaggcagcctagccctgccagcttcttgatctggacttctcacctctagaattg
+tgaggcaataaatctctgttgcttaagttacccagtttgtggtaccttattacaggagcc
+ctaggaaaataattcaTTATataatctgctaaggtagatatgatcattgtctccaatttc
+catatgaagaaactatgcctcaggcattgtgtcagttgtccaaaatcatacattcctgac
+tcacttcaatgaattcttcattcagcaaaatttttaaggtaccttaaaaaaattatgtta
+actcttagggccttgctttaaagcttcaatgggcttttcctttgcaaagaataaaatcct
+aatacttaagcatagctctctttcctggctatgtttctgacatcctcttgtaccatgctc
+ctccttaatcattctgaggttacatcttaagtcctttccccttgccattcccacttcttg
+gaatactttcccatcaactcttcaaagaactgccttctttaagtatttggtctcagttcc
+aatgtcacttccctgtaaaagcttcctggccatcaagccttctttacacactctatttta
+ttttttcatggttcctataacaacctaatatattctcaattgattaactgttttgctgaa
+tactgccttccataagaatggaaagaaaacatggccaggtgcagtggctcacacctgtaa
+tcccaccacttcaggaggctgaggcaacatggcaaaaccttctcttcaaaaaatttttta
+aaagttagctggatgttgtggaggcaagaggatcacttgaggatcacttgagtccatgag
+gtcaaggctgcagtgagtcatgtttgcaccactgcactctagcctaggtgacagagctag
+tcactatcaaaaaaaaaaaaaaaagaatggagagaatgctacatgagagaaaggatctta
+tctatcatgttcacctcccaagaggtgaacatatcccccaaagcctgatagagagaagat
+gctcattaatatttaatgcatgaCCATGTGCAGACTTGGGAGGAAAAATATGCCTCAGCC
+TATCAATATTGGATCCTTAATAAACAAGGATGTTTCTGCATCATTTCCCCACAACACCGA
+ACAAGTGTGGCTCACTGTGGATGTTTAAGCAAATGCATTGTTTTTCCAGTTATATATCTG
+GTAGAGATGAGGCCATTGATAGGAATGGGAAGACGATCTCCTTTTATTTTGATGACCCAG
+CATGGCTGAACACTCAGTGACTACCACTGCACTTTGTTGTACTTTCAGCATTAGAGATGC
+CAGCCCTGTAGGATATAAAACAGGAACATCTAGTCCTCAATTATATTCAGAATTACTCAA
+GTCTTAGAAGCACCACTTGTCTTTTTTCAAGGGAGAGAAATGCTCAAGTGATGGGCTGAA
+GTGAAGGGAGGGAGTCACTCACTTGAACGGTTCCCTTAGGCTGTGTGGATGCAAACAGCA
+TTAGACAATGACACTGACAGTGGGAAATGCACTGGAGACGATGACTGGCAAAGCCCTCCT
+TTTCTCCCCATCCACTATAGATACTGACAGCAAAGGGTTTGTCACAATGACAACTATACA
+CTCCCAATATCACAGAAGAAGGAGGAATAAAAGGGTATATTATGAGTGACTGAAGTTTAG
+AATAAATTAATAAATATTATGTCCCTCATCCATAGAAACCACAAAGGTCTAGTAAGGCTA
+AGGATATAACAAGAAAATAATATGAATATTTGCTTCCCCTTCCTAGTGTAATAGAGTAAG
+TTACAAATGGCTTCAGGAAGGGGAGAGAGGAAGAAGAGTGGATGAGATACGTAAGAGTGC
+TTGAGGGCTAATTTTATGAAAGCTTTGGGAAGTTTTAAGAAAAAGAAAAGCTATTTTTCA
+AGGTACAtgtgtgtatgcgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgAAA
+GACAGAAGAAAGAGGGAGACCTTAGAAGACTATGAGACACTAAGAGAAAAATTAAGGTAA
+AAAAGACACACACTTAGAAAAACACACATAGGGAGGAGGGAGGAGGTTAAGACATTTTAC
+TATGTGCTGTGAATGGAAACTACAAACCATTTTTGATatatgcaatatatatacatatat
+acacacatatacatatGTATTTAAATATTTAAATTACAttttctctttttttagagatat
+ggtttcactatgtcactctgcccaggctgcagtacagtggttgttcacagtcatgatcat
+agcacattatagccttgaactcctgggctcaagcaaccctcctgtattagtctccccagt
+agttgggattactagcatatgccaccatgtccACCTTTATGCTTTTTAAAGTGAAAAACC
+ATACTAAGAATGAGGCAGCTCAACTTAATAATAAAAACATTTCAAATGtaaagaaattta
+caaaagaaaaacaatcaaccccattaaaattgggcaaagg
+>chr2
+AAAAAAA
+AAAAAAA
+DDDDDDD
+CCCCCCC
+D
+
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA-windows.fasta b/public/gatk-engine/src/test/resources/exampleFASTA-windows.fasta
new file mode 100644
index 0000000..92e642f
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleFASTA-windows.fasta
@@ -0,0 +1,7 @@
+>chr2
+AAAAAAA
+AAAAAAA
+DDDDDDD
+CCCCCCC
+D
+
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA.dict b/public/gatk-engine/src/test/resources/exampleFASTA.dict
new file mode 100644
index 0000000..3887c5e
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleFASTA.dict
@@ -0,0 +1,2 @@
+ at HD VN:1.0 SO:unsorted
+ at SQ SN:chr1 LN:100000 UR:file:/humgen/gsa-scr1/hanna/src/StingWorking/exampleFASTA.fasta M5:b52f0a0422e9544b50ac1f9d2775dc23
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA.fasta b/public/gatk-engine/src/test/resources/exampleFASTA.fasta
new file mode 100644
index 0000000..2f5d1dc
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleFASTA.fasta
@@ -0,0 +1,1668 @@
+>chr1
+taaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccc
+taaccctaaccctaaccctaaccctaaccctaaccctaaccctaacccaaccctaaccct
+aaccctaaccctaaccctaaccctaacccctaaccctaaccctaaccctaaccctaacct
+aaccctaaccctaaccctaaccctaaccctaaccctaaccctaaccctaacccctaaccc
+taaccctaaaccctaaaccctaaccctaaccctaaccctaaccctaaccccaaccccaac
+cccaaccccaaccccaaccccaaccctaacccctaaccctaaccctaaccctaccctaac
+cctaaccctaaccctaaccctaaccctaacccctaacccctaaccctaaccctaacccta
+accctaaccctaaccctaacccctaaccctaaccctaaccctaaccctcgcggtaccctc
+agccggcccgcccgcccgggtctgacctgaggagaactgtgctccgccttcagagtacca
+ccgaaatctgtgcagaggacaacgcagctccgccctcgcggtgctctccgggtctgtgct
+gaggagaacgcaactccgccggcgcaggcgcagagaggcgcgccgcgccggcgcaggcgc
+agacacatgctagcgcgtcggggtggaggcgtggcgcaggcgcagagaggcgcgccgcgc
+cggcgcaggcgcagagacacatgctaccgcgtccaggggtggaggcgtggcgcaggcgca
+gagaggcgcaccgcgccggcgcaggcgcagagacacatgctagcgcgtccaggggtggag
+gcgtggcgcaggcgcagagacgcaagcctacgggcgggggttgggggggcgtgtgttgca
+ggagcaaagtcgcacggcgccgggctggggcggggggagggtggcgccgtgcacgcgcag
+aaactcacgtcacggtggcgcggcgcagagacgggtagaacctcagtaatccgaaaagcc
+gggatcgaccgccccttgcttgcagccgggcactacaggacccgcttgctcacggtgctg
+tgccagggcgccccctgctggcgactagggcaactgcagggctctcttgcttagagtggt
+ggccagcgccccctgctggcgccggggcactgcagggccctcttgcttactgtatagtgg
+tggcacgccgcctgctggcagctagggacattgcagggtcctcttgctcaaggtgtagtg
+gcagcacgcccacctgctggcagctggggacactgccgggccctcttgctCCAACAGTAC
+TGGCGGATTATAGGGAAACACCCGGAGcatatgctgtttggtctcagtagactcctaaat
+atgggattcctgggtttaaaagtaaaaaataaatatgtttaatttgtgaactgattacca
+tcagaattgtactgttctgtatcccaccagcaatgtctaggaatgcctgtttctccacaa
+agtgtttacttttggatttttgccagtctaacaggtgaAGccctggagattcttattagt
+gatttgggctggggcctggccatgtgtatttttttaaatttccactgatgattttgctgc
+atggccggtgttgagaatgactgCGCAAATTTGCCGGATTTCCTTTGCTGTTCCTGCATG
+TAGTTTAAACGAGATTGCCAGCACCGGGTATCATTCACCATTTTTCTTTTCGTTAACTTG
+CCGTCAGCCTTTTCTTTGACCTCTTCTTTCTGTTCATGTGTATTTGCTGTCTCTTAGCCC
+AGACTTCCCGTGTCCTTTCCACCGGGCCTTTGAGAGGTCACAGGGTCTTGATGCTGTGGT
+CTTCATCTGCAGGTGTCTGACTTCCAGCAACTGCTGGCCTGTGCCAGGGTGCAAGCTGAG
+CACTGGAGTGGAGTTTTCCTGTGGAGAGGAGCCATGCCTAGAGTGGGATGGGCCATTGTT
+CATCTTCTGGCCCCTGTTGTCTGCATGTAACTTAATACCACAACCAGGCATAGGGGAAAG
+ATTGGAGGAAAGATGAGTGAGAGCATCAACTTCTCTCACAACCTAGGCCAGTAAGTAGTG
+CTTGTGCTCATCTCCTTGGCTGTGATACGTGGCCGGCCCTCGCTCCAGCAGCTGGACCCC
+TACCTGCCGTCTGCTGCCATCGGAGCCCAAAGCCGGGCTGTGACTGCTCAGACCAGCCGG
+CTGGAGGGAGGGGCTCAGCAGGTCTGGCTTTGGCCCTGGGAGAGCAGGTGGAAGATCAGG
+CAGGCCATCGCTGCCACAGAACCCAGTGGATTGGCCTAGGTGGGATCTCTGAGCTCAACA
+AGCCCTCTCTGGGTGGTAGGTGCAGAGACGGGAGGGGCAGAGCCGCAGGCACAGCCAAGA
+GGGCTGAAGAAATGGTAGAACGGAGCAGCTGGTGATGTGTGGGCCCACCGGCCCCAGGCT
+CCTGTCTCCCCCCAGGTGTGTGGTGATGCCAGGCATGCCCTTCCCCAGCATCAGGTCTCC
+AGAGCTGCAGAAGACGACGGCCGACTTGGATCACACTCTTGTGAGTGTCCCCAGTGTTGC
+AGAGGTGAGAGGAGAGTAGACAGTGAGTGGGAGTGGCGTCGCCCCTAGGGCTCTACGGGG
+CCGGCGTCTCCTGTCTCCTGGAGAGGCTTCGATGCCCCTCCACACCCTCTTGATCTTCCC
+TGTGATGTCATCTGGAGCCCTGCTGCTTGCGGTGGCCTATAAAGCCTCCTAGTCTGGCTC
+CAAGGCCTGGCAGAGTCTTTCCCAGGGAAAGCTACAAGCAGCAAACAGTCTGCATGGGTC
+ATCCCCTTCACTCCCAGCTCAGAGCCCAGGCCAGGGGCCCCCAAGAAAGGCTCTGGTGGA
+GAACCTGTGCATGAAGGCTGTCAACCAGTCCATAGGCAAGCCTGGCTGCCTCCAGCTGGG
+TCGACAGACAGGGGCTGGAGAAGGGGAGAAGAGGAAAGTGAGGTTGCCTGCCCTGTCTCC
+TACCTGAGGCTGAGGAAGGAGAAGGGGATGCACTGTTGGGGAGGCAGCTGTAACTCAAAG
+CCTTAGCCTCTGTTCCCACGAAGGCAGGGCCATCAGGCACCAAAGGGATTCTGCCAGCAT
+AGTGCTCCTGGACCAGTGATACACCCGGCACCCTGTCCTGGACACGCTGTTGGCCTGGAT
+CTGAGCCCTGGTGGAGGTCAAAGCCACCTTTGGTTCTGCCATTGCTGCTGTGTGGAAGTT
+CACTCCTGCCTTTTCCTTTCCCTAGAGCCTCCACCACCCCGAGATCACATTTCTCACTGC
+CTTTTGTCTGCCCAGTTTCACCAGAAGTAGGCCTCTTCCTGACAGGCAGCTGCACCACTG
+CCTGGCGCTGTGCCCTTCCTTTGCTCTGCCCGCTGGAGACGGTGTTTGTCATGGGCCTGG
+TCTGCAGGGATCCTGCTACAAAGGTGAAACCCAGGAGAGTGTGGAGTCCAGAGTGTTGCC
+AGGACCCAGGCACAGGCATTAGTGCCCGTTGGAGAAAACAGGGGAATCCCGAAGAAATGG
+TGGGTCCTGGCCATCCGTGAGATCTTCCCAGGGCAGCTCCCCTCTGTGGAATCCAATCTG
+TCTTCCATCCTGCGTGGCCGAGGGCCAGGCTTCTCACTGGGCCTCTGCAGGAGGCTGCCA
+TTTGTCCTGCCCACCTTCTTAGAAGCGAGACGGAGCAGACCCATCTGCTACTGCCCTTTC
+TATAATAACTAAAGTTAGCTGCCCTGGACTATTCACCCCCTAGTCTCAATTTAAGAAGAT
+CCCCATGGCCACAGGGCCCCTGCCTGGGGGCTTGTCACCTCCCCCACCTTCTTCCTGAGT
+CATTCCTGCAGCCTTGCTCCCTAACCTGCCCCACAGCCTTGCCTGGATTTCTATCTCCCT
+GGCTTGGTGCCAGTTCCTCCAAGTCGATGGCACCTCCCTCCCTCTCAACCACTTGAGCAA
+ACTCCAAGACATCTTCTACCCCAACACCAGCAATTGTGCCAAGGGCCATTAGGCTCTCAG
+CATGACTATTTTTAGAGACCCCGTGTCTGTCACTGAAACCTTTTTTGTGGGAGACTATTC
+CTCCCATCTGCAACAGCTGCCCCTGCTGACTGCCCTTCTCTCCTCCCTCTCATCCCAGAG
+AAACAGGTCAGCTGGGAGCTTCTGCCCCCACTGCCTAGGGACCAACAGGGGCAGGAGGCA
+GTCACTGACCCCGAGACGTTTGCATCCTGCACAGCTAGAGATCCTTTATTAAAAGCACAC
+TGTTGGTTTCTGCTCAGTTCTTTATTGATTGGTGTGCCGTTTTCTCTGGAAGCCTCTTAA
+GAACACAGTGGCGCAGGCTGGGTGGAGCCGTCCCCCCATGGAGCACAGGCAGACAGAAGT
+CCCCGCCCCAGCTGTGTGGCCTCAAGCCAGCCTTCCGCTCCTTGAAGCTGGTCTCCACAC
+AGTGCTGGTTCCGTCACCCCCTCCCAAGGAAGTAGGTCTGAGCAGCTTGTCCTGGCTGTG
+TCCATGTCAGAGCAACGGCCCAAGTCTGGGTCTGGGGGGGAAGGTGTCATGGAGCCCCCT
+ACGATTCCCAGTCGTCCTCGTCCTCCTCTGCCTGTGGCTGCTGCGGTGGCGGCAGAGGAG
+GGATGGAGTCTGACACGCGGGCAAAGGCTCCTCCGGGCCCCTCACCAGCCCCAGGTCCTT
+TCCCAGAGATGCCTGGAGGGAAAAGGCTGAGTGAGGGTGGTTGGTGGGAAACCCTGGTTC
+CCCCAGCCCCCGGAGACTTAAATACAGGAAGAAAAAGGCAGGACAGAATTACAAGGTGCT
+GGCCCAGGGCGGGCAGCGGCCCTGCCTCCTACCCTTGCGCCTCATGACCAGCTTGTTGAA
+GAGATCCGACATCAAGTGCCCACCTTGGCTCGTGGCTCTCACTGCAACGGGAAAGCCACA
+GACTGGGGTGAAGAGTTCAGTCACATGCGACCGGTGACTCCCTGTCCCCACCCCCATGAC
+ACTCCCCAGCCCTCCAAGGCCACTGTGTTTCCCAGTTAGCTCAGAGCCTCAGTCGATCCC
+TGACCCAGCACCGGGCACTGATGAGACAGCGGCTGTTTGAGGAGCCACCTCCCAGCCACC
+TCGGGGCCAGGGCCAGGGTGTGCAGCAccactgtacaatggggaaactggcccagagagg
+tgaggcagcttgcctggggtcacagagcaaggcaaaagcagcgctgggtacaagctcaAA
+ACCATAGTGCCCAGGGCACTGCCGCTGCAGGCGCAGGCATCGCATCACACCAGTGTCTGC
+GTTCACAGCAGGCATCATCAGTAGCCTCCAGAGGCCTCAGGTCCAGTCTCTAAAAATATC
+TCAGGAGGCTGCAGTGGCTGACCATTGCCTTGGACCGCTCTTGGCAGTCGAAGAAGATTC
+TCCTGTCAGTTTGAGCTGGGTGAGCTTAGAGAGGAAAGCTCCACTATGGCTCCCAAACCA
+GGAAGGAGCCATAGCCCAGGCAGGAGGGCTGAGGACCTCTGGTGGCGGCCCAGGGCTTCC
+AGCATGTGCCCTAGGGGAAGCAGGGGCCAGCTGGCAAGAGCAGGGGGTGGGCAGAAAGCA
+CCCGGTGGACTCAGGGCTGGAGGGGAGGAGGCGATCTTGCCCAAGGCCCTCCGACTGCAA
+GCTCCAGGGCCCGCTCACCTTGCTCCTGCTCCTTCTGCTGCTGCTTCTCCAGCTTTCGCT
+CCTTCATGCTGCGCAGCTTGGCCTTGCCGATGCCCCCAGCTTGGCGGATGGACTCTAGCA
+GAGTGGCCAGCCACCGGAGGGGTCAACCACTTCCCTGGGAGCTCCCTGGACTGGAGCCGG
+GAGGTGGGGAACAGGGCAAGGAGGAAAGGCTGCTCAGGCAGGGCTGGGGAAGCTTACTGT
+GTCCAAGAGCCTGCTGGGAGGGAAGTCACCTCCCCTCAAACGAGGAGCCCTGCGCTGGGG
+AGGCCGGACCTTTGGAGACTGTGTGTGGGGGCCTGGGCACTGACTTCTGCAACCACCTGA
+GCGCGGGCATCCTGTGTGCAGATACTCCCTGCTTCCTCTCTAGCCCCCACCCTGCAGAGC
+TGGACCCCTGAGCTAGCCATGCTCTGACAGTCTCAGTTGCACACACGAGCCAGCAGAGGG
+GTTTTGTGCCACTTCTGGATGCTAGGGTTACACTGGGAGACACAGCAGTGAAGCTGAAAT
+GAAAAATGTGTTGCTGTAGTTTGTTATTAGACCCCTTCTTTCCATTGGTTTAATTAGGAA
+TGGGGAACCCAGAGCCTCACTTGTTCAGGCTCCCTCTGCCCTAGAAGTGAGAAGTCCAGA
+GCTCTACAGTTTGAAAACCACTATTTTATGAACCAAGTAGAACAAGATATTTGAAATGGA
+AACTATTCAAAAAATTGAGAATTTCTGACCACTTAACAAACCCACAGAAAATCCACCCGA
+GTGCACTGAGCACGCCAGAAATCAGGTGGCCTCAAAGAGCTGCTCCCACCTGAAGGAGAC
+GCGCTGCTGCTGCTGTCGTCCTGCCTGGCGCCTTGGCCTACAGGGGCCGCGGTTGAGGGT
+GGGAGTGGGGGTGCACTGGCCAGCACCTCAGGAGCtgggggtggtggtgggggcggtggg
+ggtggtgttagtACCCCATCTTGTAGGTCTGAAACACAAAGTGTGGGGTGTCTAGGGAAG
+AAGGTGTGTGACCAGGGAGGTCCCCGGCCCAGCTCCCATCCCAGAACCCAGCTCACCTAC
+CTTGAGAGGCTCGGCTACCTCAGTGTGGAAGGTGGGCAGTTCTGGAATGGTGCCAGGGGC
+AGAGGGGGCAATGCCGGGGCCCAGGTCGGCAATGTACATGAGGTCGTTGGCAATGCCGGG
+CAGGTCAGGCAGGTAGGATGGAACATCAATCTCAGGCACCTGGCCCAGGTCTGGCACATA
+GAAGTAGTTCTCTGGGACCTGCAAGATTAGGCAGGGACATGTGAGAGGTGACAGGGACCT
+GCAGGGGCAGCCAACAAGACCTTGTGTGCACCTCCCATGGGTGGAATAAGGGGCCCAACA
+GCCTTGACTGGAGAGGAGCTCTGGCAAGGCCCTGGGCCACTGCACCTGTCTCCACCTCTG
+TCCCACCCCTCCCACCTGCTGTTCCAGCTGCTCTCTCTTGCTGATGGACAAGGGGGCATC
+AAACAGCTTCTCCTCTGTCTCTGCCCCCAGCATCACATGGGTCTTTGTTACAGCACCAGC
+CAGGGGGTCCAGGAAGACATACTTCTTCTACCTACAGAGGCGACATGGGGGTCAGGCAAG
+CTGACACCCGCTGTCCTGAGCCCATGTTCCTCTCCCACATCATCAGGGGCACAGCGTGCA
+CTGTGGGGTCCCAGGCCTCCCGAGCCGAGCCACCCGTCACCCCCTGGCTCCTGGCCTATG
+TGCTGTACCTGTGTCTGATGCCCTGGGTCCCCACTAAGCCAGGCCGGGCCTCCCGCCCAC
+ACCCCTCGGCCCTGCCCTCTGGCCATACAGGTTCTCGGTGGTGTTGAAGAGCAGCAAGGA
+GCTGACAGAGCTGATGTTGCTGGGAAGACCCCCAAGTCCCTCTTCTGCATCGTCCTCGGG
+CTCCGGCTTGGTGCTCACGCACACAGGAAAGTCCTTCAGCTTCTCCTGAGAGGGCCAGGA
+TGGCCAAGGGATGGTGAATATTTGGTGCTGGGCCTAATCAGCTGCCATCCCATCCCAGTC
+AGCCTCCTCTGGGGGACAGAACCCTATGGTGGCCCCGGCTCCTCCCCAGTATCCAGTCCT
+CCTGGTGTGTGACAGGCTATATGCGCGGCCAGCAGACCTGCAGGGCCCGCTCGTCCAGGG
+GGCGGTGCTTGCTCTGGATCCTGTGGCGGGGGCGTCTCTGCAGGCCAGGGTCCTGGGCGC
+CCGTGAAGATGGAGCCATATTCCTGCAGGCGCCCTGGAGCAGGGTACTTGGCACTGGAGA
+ACACCTGTGGACACAGGGACAAGTCTGAGGGGGCCCCAAGAGGCTCAGAGGGCTAGGATT
+GCTTGGCAGGAGAGGGTGGAGTTGGAAGCCTGGGCGAGAAGAAAGCTCAAGGTACAGGTG
+GGCAGCAGGGCAGAGACTGGGCAGCCTCAGAGGCACGGGGAAATGGAGGGACTGCCCAGT
+AGCCTCAGGACACAGGGGTATGGGGACTACCTTGATGGCCTTCTTGCTGCCCTTGATCTT
+CTCAATCTTGGCCTGGGCCAAGGAGACCTTCTCTCCAATGGCCTGCACCTGGCTCCGGCT
+CTGCTCTACCTGCTGGGAGATCCTGCCATGGAGAAGATCACAGAGGCTGGGCTGCTCCCC
+ACCCTCTGCACACCTCCTGCTTCTAACAGCAGAGCTGCCAGGCCAGGCCCTCAGGCAAGG
+GCTCTGAAGTCAGGGTCACCTACTTGCCAGGGCCGATCTTGGTGCCATCCAGGGGGCCTC
+TACAAGGATAATCTGACCTGCAGGGTCGAGGAGTTGACGGTGCTGAGTTCCCTGCACTCT
+CAGTAGGGACAGGCCCTATGCTGCCACCTGTACATGCTATCTGAAGGACAGCCTCCAGGG
+CACACAGAGGATGGTATTTACACATGCACACATGGCTACTGATGGGGCAAGCACTTCACA
+ACCCCTCATGATCACGTGCAGCAGACAATGTGGCCTCTGCAGAGGGGGAACGGAGACCGG
+AGGCTGAGACTGGCAAGGCTGGACCTGAGTGTCGTCACCTAAATTCAGACGGGGAACTGC
+CCCTGCACATACTGAACGGCTCACTGAGCAAACCCCGAGTCCCGACCACCGCCTCAGTGT
+GGTCTAGCTcctcacctgcttccatcctccctggtgcggggtgggcccagtgatatcagc
+tgcctgctgttccccagatgtgccaagtgcattcttgtgtgcttgcatctcatggaacgc
+catttccccagacatccctgtggctggctcctGATGCCCGAGGCCCAAGTGTCTGATGCT
+TTAAGGCACATCACCCCACTCATGCTTTTCCATGTTCTTTGGCCGCAGCAAGGCCGCTCT
+CACTGCAAAGTTAACTCTGATGCGTGTGTAACACAACATCCTCCTCCCAGTCGCCCCTGT
+AGCTCCCCTACCTCCAAGAGCCCAGCCCTTGCCCACAGGGCCACACTCCACGTGCAGAGC
+AGCCTCAGCACTCACCGGGCACGAGCGAGCCTGTGTGGTGCGCAGGGATGAGAAGGCAGA
+GGCGCGACTGGGGTTCATGAGGAAGGGCAGGAGGAGGGTGTGGGATGGTGGAGGGGTTTG
+AGAAGGCAGAGGCGCGACTGGGGTTCATGAGGAAAGGGAGGGGGAGGATGTGGGATGGTG
+GAGGGGCTGCAGACTCTGGGCTAGGGAAAGCTGGGATGTCTCTAAAGGTTGGAATGAATG
+GCCTAGAATCCGACCCAATAAGCCAAAGCCACTTCCACCAACGTTAGAAGGCCTTGGCCC
+CCAGAGAGCCAATTTCACAATCCAGAAGTCCCCGTGCCCTAAAGGGTCTGCCCTGATTAC
+TCCTGGCTCCTTGTGTGCAGGGGGCTCAGGCATGGCAGGGCTGGGAGTACCAGCAGGCAC
+TCAAGCGGCTTAAGTGTTCCATGACAGACTGGTATGAAGGTGGCCACAATTCAGAAAGAA
+AAAAGAAGAGCACCATCTCCTTCCAGTGAGGAAGCGGGACCACCACCCAGCGTGTGCTCC
+ATCTTTTCTGGCTGGGGAGAGGCCTTCATCTGCTGTAAAGGGTCCTCCAGCACAAGCTGT
+CTTAATTGACCCTAGTTCCCAGGGCAGCCTCGTTCTGCCTTGGGTGCTGACACGACCTTC
+GGTAGGTGCATAAGCTCTGCATTCGAGGTCcacaggggcagtgggagggaactgagactg
+gggagggacaaaggctgctctgtcctggtgctcccacaaaggagaagggctgatcactca
+aagttgcgaacaccaagctcaacaatgagccctggaaaatttctggaatggattattaaa
+cagagagtctgtaagcacttagaaaaggccgcggtgagtcccaggggccagcactgctcg
+aaatgtacagcatttctctttgtaacaggattattagcctgctgtgcccggggaaaacat
+gcagcacagtgcatctcgagtcagcaggattttgacggcttctaacaaaatcttgtagac
+aagatggagctatgggggttggaggagagaacatataggaaaaatcagagccaaatgaac
+cacagccccaaagggcacagttgaacaatggactgattccagccttgcacggagggatct
+ggcagagtccatccagttcattcaacacctggttagaaaactggggccagcacacagggg
+aagggtaagctggtttcatgatcgaatcaaggctcagacaatttttaaaggccagagggt
+agactgcaatcaccaagatgaaatttacaaggaacaaatgtgaagcccaacatttaggtt
+ttaaaaatcaagcgtataaatacagaaggtggagggaacttgctttagacacagttcagg
+tgaagaaagacctggaaacttctgttaactataagctcagtaggggctaaaagcatgtta
+atcggcataaaaaggcaatgagatcttaggGCACACAGCTCCCCGCCCCTCTTCTGCCCT
+TCATCCTTCTTTCAATCAGCAGGGACCGTGCACTCTCTTGGAGCCACCACAGAAAACAGA
+GGTGCATCCAGCACCACAGAAAACAGAGCCACCACAGAAAACAGAGGGTGACTGTCATCC
+CCTCCAGTCTCTGCACACTCCCAGCTGCAGCAGAGCAGGAGGAGAGAGCACAGCCTGCAA
+TGCTAATTTGCCAGGAGCTCACCTGCCTGCGTCACTGGGCACAGACGCCAGTGAGGCCAG
+AGGCCGGGCTGTGCTGGGGCCTGAGCCGGGTGGTGGGGAGAGAGTCTCTCCCCTGCCCCT
+GTCTCTTCCGTGCAGGAGGAGCATGTTTAAGGGGACGGGTTCAAAGCTGGTCACATCCCC
+ACCGAAAAAGCCCATGGACAACGAAAAGCCCACTAGCTTGTCCAGTGCCACAGGAGGGGC
+AAGTGGAGGAGGAGAGGTGGCGGTGCTCCCCACTCCACTGCCAGTCGTCACTGGCTCTCC
+CTTCCCTTCATCCTCGTTCCCTATCTGTCACCATTTCCTGTCGTCGTTTCCTCTGAATGT
+CTCACCCTGCCCTCCCTGCTTGCAAGTCCCCTGTCTGTAGCCTCACCCCTGTCGTATCCT
+GACTACAATAACAGCTTCTGGGTGTCCCTGGCATCCACTCTCTCTCCCTTCTTGTCCCTT
+CCGTGACGGATGCCTGAGGAACCTTCCCCAAACTCTTCTGTCCCATCCCTGCCCTGCTCA
+AAATCCAATCACAGCTCCCTAACACGCCTGAATCAACTTGAAGTCCTGTCTTGAGTAATC
+CGTGGGCCCTAACTCACTCATCCCAACTCTTCACTCACTGCCCTGCCCCACACCCTGCCA
+GGGAGCCTCCCGTGGCACCGTGGGGACACAAAGGAACCAGGGCAAAGCTCCCTCAGCCCC
+ATTCAAAGAGGCCTGGCCCACAGGCTCACGGAAAGTCAGCCTCTCATGCCCCGAGAGCTG
+AGTGCAAGGGAGAGGCAGCGCTGTCTGTGCTTCCCATGCAGAAGCACCCCCCTCCCACCC
+CTGTGCAGGCCGGCCTTCGCGGCAGACCACCATACACCACGTTCCAAGCCACACTGAGGC
+CTCCCTCCAAGCCTGCAGCCCCCATTTCCAGACCCTGCCAGGGCAACCTGCATATCCACC
+TCCCTACCCTGCCCCCCTCTTCCAGGAGTCTGCCCTATGTGGAGTAAGCACgtggttttc
+ctcttcagcaactatttcctttttactcaagcaatggccccatttcccttggggaatcca
+tctctctcgcaggcttagtcccagagcttcaggtggggctgcccacagagctcctcagtc
+taagccaagtggtgtgtcatagtcccctggccccattaatggattctgggatagacatga
+ggaccaagccaggTGGGATGAGTGAGTGTGGCTTCTGGAGGAAGTGGGGACACAGGACAG
+CATTCTTTCCTGCTGGACCTGACCCTGTGTCATGTCACCTTGCTACCACGAGAGCATGGC
+CTGTCTGGGAATGCAGCCAGACCCAAAGAAGCAAACTGACATGGAAGGAAAGCAAAACCA
+GGCCCTGAGGACATCATTTTAGCCCTTACTCCGAAGGCTGCTCTACTGATTGGTTAATTT
+TTGCTTAGCTTGGTCTGGGGAGTTCTGACAGGCGTGCCACCAATTCTTACCGATTTCTCT
+CCACTCTAGACCCTGAGAAGCCCACGCGGTTCATGCTAGCAATTAACAATCAATCTCGCC
+CTATGTGTTCCCATTCCAGCCTCTAGGACACAGTGGCAGCCACATAATTGGTATCTCTTA
+AGGTCCAGCACGAGGTGGAGCACATGGTGGAGAGACAGATGCAGTGACCTGGAACCCAGG
+AGTGAGGGAGCCAGGACTCAGGCCCAAGGCTCCTGAGAGGCATCTGGCCCTCCCTGCGCT
+GTGCCAGCAGCTTGGAGAACCCACACTCAATGAACGCAGCACTCCACTACCCAGGAAATG
+CCTTCCTGCCCTCTCCTCATCCCATCCCTGGGCAGGGGACATGCAACTGTCTACAAGGTG
+CCAAGTACCAGGACAGGAAAGGAAAGACGCCAAAAATCCAGCGCTGCCCTCAGAGAAGGG
+CAACCACGCAGTCCCCATCTTGGCAAGGAAACACAATTTCCGAGGGAATGGTTTTGGCCT
+CCATTCTAAGTGCTGGACATGGGGTGGCCATAATCTGGAGCTGATGGCTCTTAAAGACCT
+GCATCCTCTTCCCTAGGTGTCCCTCGGGCACATTTAGCACAAAGATAAGCACAAAAGGTG
+CATCCAGCACTTTGTTACTATTGGTGGCAGGTTTATGAATGGCAACCAAAGGCAGTGTAC
+GGGTCAAGATTATCAACAGGGAAGAGATagcatttcctgaaggcttcctaggtgccaggc
+actgttccattcctttgcatgttttgattaatttaatatttaaaataattctaccaggaa
+gctaccattattaccacaacttcacaaatgagaacaccgaggcttagaggggttgggttg
+cccaaggttacagaggaagaaaacaggggagctggatctgagccaaggcatcaactccaa
+ggtAACCCCTCAGTCACTTCACTGTGTGTCCCCTGGTTACTGGGACATTCTTGACAAACT
+CGGGGCAAGCCGGTGAGTCAGTGGGGGAGGACTTTCAGGAAGAGGTGGGTTCCCAGTTGG
+TGACAGAAGAGGAGGCTGCAAAGTGAAGGAGCAGGGGCTCCAGGTCTGGCGACAACCAGG
+GAAGGGACAGGGCAGGGATGGCTTGGACCACGAGAGGCACCTGAGTCAGGCAGTCACATA
+CTTCCCACTGGGGTCTACCATGTGAGGCATGGTGTGGGATCCTGGGAAGGAGACCAAGCC
+TCATTTCAGTTTGCTTATGGCCAAAGACAGGACCTGTGTACCCGACAACCCCTGGGACCT
+TTACCAAAAAAAGAGCAAACACCATTCACTCACTCATGTTAGATAAACACTGAGTGAAGT
+CACTGGAGCCCAAGGACTGTGCGAGGTCAGCACTGCCAATACAAGAAGCTGCAGCCCTCC
+AGCTCGCctccctcaatggccactccgtgctccagccatgctggcttccttttaggtcct
+ccacctccaggctgtagttcatgtgcttctttctggaatgttcttcccaacctacccact
+caaccctcagactttaccataaatgtcatttcctcacgtctgccttccctgacctgagac
+caagccaggCTTCCCATGACGAGCCTCACAGTACCCCATCTCCCCTGAACAGATGCAGTA
+ATAACCTACATAACccggggccatgatctatggctttgaatcctggctctgtcactaggc
+caggtctctcagcccttctgtgcctcagtttcctcatctataaaatgagatgacggcagt
+gcctgctcatgaagtgtgagttaatgcactcaaatcaatggttgtgcacggtttatatga
+atattagtgattaCAAAATATTATCAatagaccttgtcacaactgttattgaagaactaa
+tcatctattgcttatttaggtctttctctcctgccagaatgtgcgctccaggtggagagg
+tatgttgccttatccgtggctggatatatagagattcccacactgccttgcacacgagca
+ctgctgggtaaatatttgttggctgcaggaaAACGTGAAGGAATAGGCCCTCCAATGGGA
+GGAAAAGCATGAGTTGTGAGAGCAGAGCCACCACAGGAAACCAGGAGGCTAAGTGGGGTG
+GAAGGGAGTGAGCTCTCGGACTCCCAGGAGTAAAAGCTTCCAAGTTGGGCTCTCACTTCA
+GCCCCTCCCACACAGGGAAGCCAGATGGGTTCCCCAGGACCGGGATTCCCCAAGGGGGCT
+GCTCCCAGAGGGTGTGTTGCTGGGATTGCCCAGGACAGGGATGGCCCTCTCATCAGGTGG
+GGGTGAGTGGCAGCACCCACCTGCTGAAGATGTCTCCAGAGACCTTCTGCAGGTACTGCA
+GGGCATCCGCCATCTGCTGGACGGCCTCCTCTCGCCGCAGGTCTGGCTGGATGAAGGGCA
+CGGCATAGGTCTGACCTGCCAGGGAGTGCTGCATCCTCACAGGAGTCATGGTGCCTGTGG
+GTCGGAGCCGGAGCGTCAGAGCCACCCACGACCACCGGCACGCCCCCACCACAGGGCAGC
+GTGGTGTTGAGACAACACAGCCCTCATCCCAACTATGCACATAGCTTCAGCCTGCACAGA
+TAGGGGAGTAGGGGACAGAGCATTTGCTGAGAGGCCAGGAGCGCATAGATGGGACTCTGC
+TGATGCCTGCTGAGTGAATGAGGGAAAGGGCAGGGCCCGGGACTGGGGAATCTGTAGGGT
+CAATGGAGGAGTTCAGAGAAGGTGCAACATTTCTGACCCCCTACAAGGTGCTTGCTACCT
+GCCAGGCACCCTTTCCATACCTTGTCTCAGTTCAGCTCCCCACCTTGGATAAACAAGAAA
+CCTTGGTTGCAGAGGAAAAAAGAGGCTGGAAACAAAGGGGTAGAAATGGGGTAGCAGGGG
+AGATTGCCTGATCAACTGCCAAATGGTACACAGTTCTGGAAAAGCACAAAAAATGTGCAC
+ACACGGGTTCTTCCCACTTTAACCCCTGAGGAATCTGAGGCCTGCTCCTGAAACAGACTG
+GGCAGTGGCTAGTGACTCTAGGTATAGGAGTATCCAGCCCTGCTCACCCAGGCTAGAGCT
+TAGGGGGACAAGAGGAAAGAGGTGCCTGTGGGGGTGGAGGACAGGAAGGAAAAACACTCC
+TGGAATTGCAAAGTGAGGGCAGAGTCTATTTATATTGGGTTTAATTAACTCCTCTCCCTG
+GTGCCACTAAAGCAGCAATCACACTGCAGACAGCACTGATTTGATTGGCAAGAGATGCAC
+CAGGCAGAATATTAAGGGACCAGGCCCCTATAAATAGGCCTAATCACAGCCCCTCACTGG
+AAAATGGTAAGGAAGACATTAATCAGGCCTGGCACTGTGCCCTAGACCTGCTCCCCTAGG
+CACTACAGTGGGGCCCTTGGTTGCAACACAAGTAGGTAGGGATGGATGAGTGTGGCATGA
+AGGGCCTAGGAGATTTCACTTGGGTTTAAAATGCTGTGACCTTGAGTAAGTTGCCGTCTC
+TGAATCTGATCCTTTCGATTTCCCATTCTCCAAACTGAGAACTAGCACTGCTGAGACGTG
+GTTATTTCCAATAATAATTTGTATATTTTACATAACGCACCACACCAACATCTTCACCCA
+GTTGGAGCCTACTCCTTTGCTCCCGCTGCTGGCTTCCCCAGCCCTCCCTTCTGCCCTCCT
+CAGGCCAGCACTTTTCAGTGAGTTCCTCCTTTGCATACAGGCTTTCCAGATCTGTACTTG
+CCTTGAATACTCATCAGAGCCCAGGAGTTACTCCTCACCTCCCACTTATTTTTCCTCCCA
+TCAAATAACTAAAGCATGGCCAGCTGATGCCCAGCCAACTGAGAAACCCAACCCTCTGAG
+ACCAGCACACCCCTTTCAAGCATGTTCCTCCCTCCCCTTCTTTGTATTTATACTGATGCA
+AGTTTGCTGGCTGTcctaacttatttctgtgcctcagttctcccatatgtaagatcacaa
+agggggtaaagaTGCAAGATATTTCCTGTGCACATCTTCAGATGAATTTCTTGTTAGTGT
+GTGTGTGTTTGCTCACACATATGCGTGAAAGAAGAGTACATACACAGATCTCCTCAAAAA
+GGAGGCAGCAAGCCCGTTCAAGAATGGGACTGAATACACCTGATGAGTGGTTTACTTTCT
+GTCTGCAAACATCTACTGATCATCTGTTAGGTGCAGGCCATGATCACAACAAAGACGAAT
+AAGACACTACACTAGCCAGGGAGAGTCTCAAAAACAACTAAACTCAAATTAAATTCATTC
+TACTCCAGTCATGGGTACAAAGCTAAGGAGTGACAAATCCCTCTTGGAGTTAGGGGAGTC
+AGGAAAAAGCTCTTAGCAGAATGTGTGCCTCTCggccgggcgcagcggctcacgcctgta
+atcccagcactttgggaggcgaaggcaggcagatcacctgaggtcgggagttcgagacca
+gtctgaccaacatggtgaaactccatctctactaaaaatacaaaattagccaggcgtggt
+ggtgcatgcctgtaatccccgctactcgggaggctgaggaaggagaatcacttgaaccag
+gaaggtggaggttgcagtgtgccaagatcgcgccatggcactccagcctaggcaacgagg
+gtgaaCCAGGTCCAGGAAGAAGGTGCAAAGACAGCATTCCAGGTAAAAGAAACAGCTTGA
+ACAAAAAGTGTGTAGGGGAACCGCAAGCGGTCTTGAGTGCTGAGGGTACAATCATCCTTG
+GGGAAGTACTAGAAGAAAGAATGATAAACAGAGGCCAGTTTGTTAAAAACACTCAAAATT
+AAAGCTAGGAGTTTGGACTTGTGGCAGGAATgaaatccttagacctgtgctgtccaatat
+ggtagccaccaggcacatgcagccactgagcacttgaaatgtggatagtctgaattgaga
+tgtgccataagtgtaaaatatgcaccaaatttcaaaggctagaaaaaaagaatgtaaaat
+atcttattattttatattgattacgtgctaaaataaccatatttgggatatactggattt
+taaaaatatatcactaatttcatctgtttctttttacttttAGAAATCACATATGTGACT
+TAAATATTTCTTTTCTTTTTCTTTCCTCTCACTCAGCGTCCTGTGATTCCAAAGAAATGA
+GTCTCTGCTGTTTTTGGGCAGCAGATATCCTAGAATGGACTCTGACCTAAGCATCAAAAT
+TAATCATCATAACGTTATCATTTTATGGCCCCTTCTTCCTATATCTGGTAGCTTTTAAAT
+GATGACCATGTAGATAATCTTTATTGTCCCTCTTTCAGCAGACGGTATTTTCTTATGCTA
+CAGTATGACTGCTAATAATACCTACACATGTTAGAACCATTCTGACTCCTCAAGAatctc
+atttaactcttattatcagtgaatttatcatcatcccctattttacataaggaaatgggg
+ttagaaagaccaaataacattttttcaacatcaaaacactagcttgagatcaagcccaga
+cttggatctgtcgtctgaattccaagctttttgttatttattgatatgttttgttgtTTT
+CATGCAATAATGCAAATCTTAGCCCAAACATTTTGTTAGTAGTACCAACTGTAAGTCACC
+TTATCTTCATACTTTGTCTTTATGTAAACCTAAATTAGATCTGTTTTTGATACTGAGGGA
+AAAACAAGGGAATctaacactaaccagcccgtagtgtgtggtcaacactttcgttacttt
+agtatacatcaccccaattgtttgtcttcaccacacactttggagttaggtagtagtatc
+tatttttacaaataagaaaacccaggcacaaaggggttgattagcAATTATCTTTTGAAA
+AGCCTGTAGTTGCTCATCTGAAGAAGTGACGGACCACCTCTTATTTAGTGGACAGACAGT
+AACTAGTTGAGAAGACAGGGGATTTTGTTGGCGGAAAAAAAAATTTATCAAAAGTCGTCT
+TCTATCAGGGAGTTTTATGAGAAACCCTAGCTCCTCAGTTCCACAGTGGGTAACTGTAAT
+TCATTCTAGGTCTGCGATATTTCCTGCCTATCCATTTTGTTAACTCTTCAATGCATTCCA
+CAAATACCTAAGTATTCTTTAATAATGGTGGTTTTTTTTTTTTTTTGCATCTATGAAGTT
+TTTTCAAATTCTTTTTAAGTGACAAAACTTGTACATGTGTATCGCTCAATATTTCTAGTC
+GACAGCACTGCTTTCGAGAATGTAAACCGTGCACTCCCAGGAAAATGCAGACACAGCACG
+CCTCTTTGGGACCGCGGTTTATACTTTCGAAGTGCTCGGAGCCCTTCCTCCAGACCGTTC
+TCCCACACCCCGCTCCAGGGTCTCTCCCGGAGTTACAAGCCTCGCTGTAGGCCCCGGGAA
+CCCAACGCGGTGTCAGAGAAGTGGGGTCCCCTACGAGGGACCAGGAGCTCCGGGCGGGCA
+GCAGCTGCGGAAGAGCCGCGCGAGGCTTCCCAGAACCCGGCAGGGGCGGGAAGACGCAGG
+AGTGGGGAGGCGGAACCGGGACCCCGCAGAGCCCGGGTCCCTGCGCCCCACAAGCCTTGG
+CTTCCCTGCTAGGGCCGGGCAAGGCCGGGTGCAGGGCGCGGCTCCAGGGAGGAAGCTCCG
+GGGCGAGCCCAAGACGCCTCCCGGGCGGTCGGGGCCCAGCGGCGGCGTTCGCAGTGGAGC
+CGGGCACCGGGCAGCGGCCGCGGAACACCAGCTTGGCGCAGGCTTCTCGGTCAGGAACGG
+TCCCGGGCCTCCCGCCCGCCTCCCTCCAGCCCCTCCGGGTCCCCTACTTCGCCCCGCCAG
+GCCCCCACGACCCTACTTCCCGCGGCCCCGGACGCCTCCTCACCTGCGAGCCGCCCTCCC
+GGAAGCTCCCGCCGCCGCTTCCGCTCTGCCGGAGCCGCTGGGTCCTAGCCCCGCCGCCCC
+CAGTCCGCCCGCGCCTCCGGGTCCTAACGCCGCCGCTCGCCCTCCACTGCGCCCTCCCCG
+AGCGCGGCTCCAGGACCCCGTCGACCCGGAGCGCTGTCCTGTCGGGCCGAGTCGCGGGCC
+TGGGCACGGAACTCACGCTCACTCCGAGCTCCCGACGTGCACACGGCTCCCATGCGTTGT
+CTTCCGAGCGTCAGGCCGCCCCTACCCGTGCTTTCTGCTCTGCAGACCCTCTTCCTAGAC
+CTCCGTCCTTTGTCCCATCGCTGCCTTCCCCTCAAGCTCAGGGCCAAGCTGTCCGCCAAC
+CTCGGCTCCTCCGGGCAGCCCTCGCCCGGGGTGCGCCCCGGGGCAGGACCCCCAGCCCAC
+GCCCAGGGCCCGCCCCTGCCCTCCAGCCCTACGCCTTGACCCGCTTTCCTGCGTCTCTCA
+GCCTACCTGACCTTGTCTTTACCTCTGTGGGCAGCTCCCTTGTGATCTGCTTAGTTCCCA
+CCCCCCTTTAAGAATTCAATAGAGaagccagacgcaaaactacagatatcgtatgagtcc
+agttttgtgaagtgcctagaatagtcaaaattcacagagacagaagcagtggtcgccagg
+aatggggaagcaaggcggagttgggcagctcgtgttcaatgggtagagtttcaggctggg
+gtgatggaagggtgctggaaatgagtggtagtgatggcggcacaacagtgtgaatctact
+taatcccactgaactgtatgctgaaaaatggtttagacggtgaattttaggttatgtatg
+ttttaccacaatttttaaaaaGCTAGTGAAAAGCTGGTAAAAAGAAAGAAAAGAGGCTTT
+TTTAAAAAGTTAAATATATAAAAAGAGCATCATCAGTCCAAAGTCCAGCAGTTGTCCCTC
+CTGGAATCCGTTGGCTTGCCTCCGGCATTTTTGGCCCTTGCCTTTtagggttgccagatt
+aaaagacaggatgcccagctagtttgaattttagataaacaacgaataatttcgtagcat
+aaatatgtcccaagcttagtttgggacatacttatgctaaaaaacattattggttgttta
+tctgagattcagaattaagcattttatattttatttgctgcctctggccaccctaCTCTC
+TTCCTAACACTCTCTCCCTCTCCCAGTTTTGTCCGCCTTCCCTGCCTCCTCTTCTGGGGG
+AGTTAGATCGAGTTGTAACAAGAACATGCCACTGTCTCGCTGGCTGCAGCGTGTGGTCCC
+CTTACCAGAGGTAAAGAAGAGATGGATCTCCACTCAtgttgtagacagaatgtttatgtc
+ctctccaaatgcttatgttgaaaccctaacccctaatgtgatggtatgtggagatgggcc
+tttggtaggtaattacggttagatgaggtcatggggtggggccctcattatagatctggt
+aagaaaagagaGCATTGtctctgtgtctccctctctctctctctctctctctctcatttc
+tctctatctcatttctctctctctcgctatctcatttttctctctctctctttctctcct
+ctgtcttttcccaccaagtgaggatgcgaagagaaggtggctgtctgcaaaccaggaaga
+gagccctcaccgggaacccgtccagctgccaccttgaacttggacttccaagcctccaga
+actgtgagggataaatgtatgattttaaagtcgcccagtgtgtggtattttgttttgact
+aatacaaCCTGAAAACATTTTCCCCTCACTCCACCTGAGCAATATCTGAGTGGCTTAAGG
+TACTCAGGACACAACAAAGGAGAAATGTCCCATGCACAAGGTGCACCCATGCCTGGGTAA
+AGCAGCCTGGCACAGAGGGAAGCACACAGGCTCAGggatctgctattcattctttgtgtg
+accctgggcaagccatgaatggagcttcagtcaccccatttgtaatgggatttaattgtg
+cttgccctgcctccttttgagggctgtagagaaaagatgtcaaagtattttgtaATCTgg
+ctgggcgtggtggctcatgcctgtaatcctagcactttggtaggctgacgcgagaggact
+gcttgagcccaagagtttgagatcagcctgggcaatattgtgagattccatctctacaaa
+aataaaataaaatagccagtcatggtgtcacacacctgtagtcccagctacatgggaggc
+tgaggcgggaggatcacttgagcttgggagatcgaggctgcagtgagctatgattgtacc
+actgcactccaggctgggcgacagagagagaccctgtctcagaaaaaaaaaaaaaaGTAC
+TTTGTAATCTGTAAGGTTTATTTCAACACACACAAAAAAAGTGTATATGCTCCACGATGC
+CTGTGAATATACACACACACCACATCATATACCAAGCCTGGCTGTGTCTTCTCACAAATG
+CACTGCTAGGCACCACCCCCAGTTCTAGAATCACACCAGCCAGTTCACCCTCCAGATGGT
+TCACCCTCAACTTCATAAAAGTTCCCTACCTAATCTACTGACAGGCTCATCCCCGACCTA
+ATTTTAAAGATTTCCTAGGAGCTGCAGTGGGAATCCTGGACCTCAGCCTGGACAAAGAAC
+AGCTGCAGGTCATTCTCATGTGTGGACACAGAAGCTCTGCCTGCCTTTGCTGGCCAGCTG
+GGCTGAGCGGGCCTGGGAATTAAGGCTGCAGGGTTGGTCCCAGGCAGTCTTGCTGAAGCT
+TGCCACATCCCCCAGCCTCCTGGATTTGCCAGGATCCAAGAGCATGGACTTTAGGAATTC
+CTGGTGGAGGAGTGAAGAAAATGTGACAGGGTGTCCTAAGCCCCGATCTACAGGAAGAAA
+ACTGGAAATAAGACTGAGGACTTAGTTTAAGATGTTCCTACTCAGCCTCTAGCTTTTGTG
+CTACAGTTCTGGGAACAGACTCCTCTCTCCTGAAAACCACTTCCCTCCGCAGCATTAGAT
+TTCACCAAGATGTCTTGCTTGTGGGAAAGACTTCCAAGGATGCCTGGAGAGAGGAGGATG
+GAAATGTCCTGCTCTCTAAACAGATAGACAGATGCAGCCAGACAGAAAATAGTTTATCTT
+GCTGAGGTTTCTAATGTATTTGAAAGAGGCCTGGGTCTAGAAGTCTACCCAGAGGGCTCT
+GTGTTGTGCACGCAAAGATAAGAACCTTCCCTGTGGGAGTTCCAGAGCCAGTTTTCATAA
+ACACCCATCGGTGACTGTGTTCAGAGTGAGTTCACACCATCCTGACCTGCCCTGAGTTAG
+ACCTTACATGGTCTTCCTCCTCTAGGAAGCCTCTGCAGCCCAGGAACCTCCCCTTATCGG
+AAATGAACAGCATTTGAAGCTTCACCAGACAGACCAGACAGCTTAGCCCTCGTGTTGTGC
+CATGTGGGTTGTTCTCTGAGAGGcaggagagcatagtggttactaggaagggaaggactt
+tgggactagactgcctcggctggagtcctctttctgcttcatagccacgtgatcctaggc
+atgttacctgtgcctcagttttcactctgtcaatatgtaataactgaatctgtctttgtg
+gtgaggattcagtgagttaacatatttgaagtgcttaaaaATGAGGCTTGtgtccataga
+ttaatgagtgaatacacaaatggtgatatggacatacagtggagtattagtcataaaaag
+gaaggcagagctgatccatggcaccatgtgacagaacctcaaaagcattaggttaagtgg
+aagaagccagacacaggtcacctattgtgtaattccatttataggaaatatacagaatat
+gtaaatccgtggagaaagaaagccgatttccaggggctaaggggaggggagaatgggaag
+tggctgcttcatgggtacaaggtttcattttgagctgatgaaaatgttttggaactacat
+agagatagtgttggcacaacatggtgaatgtactgaatgccactgattgttcaatttaaa
+atggtcaaacttatatgaatttcacctccattaaaaaaaAAAAAAAAGgaccagatgtgg
+ttgctcacacccataatcccaacactttggaaAAAGGTGAAAGTTTTTTTTtcttttttt
+ttttatatacttaagttctagggtacatgtgcataatgtgcaggttggatacatagatat
+gcgtgtgccatgttggtttgctgcacccatcaacttgtcatttacattaggtatttcttc
+taatgctatccctcccccagccccccacccactgacaggccccagtgtatgatgttctct
+gccccatgtccaagcgttctcattgttcaattcccacctgtgagtgagaacatgcagtgt
+ttggttttctgtctttgtgatagtttgctcagaatgatggtttccagcttcatccatgtc
+cctgcaaaggacatgaactcatcctttttaatggctgcatagtatcccatggtatatatg
+tgccacattctcttaatccagtctgtcattgatggacatttgggttggttcaaagtcttt
+gctattgtgaatactgccacaataaacatacatgtgcatgtgtctttatagtagcacgat
+ttataatcctttgggtatatacccTAAGACctgggacgcatttaaagcagtgtgtaaaga
+gacatttatagcactaaatgcccacaagagaCCTCTGCCTGAGAACGTGGGTTTCAGCCT
+AAGAGTTGTAATATGTGTGCCCATTCACAGGTGCTGCATCAGAGTCCCAGGTGGGAAGAA
+GGCAAGCATACACAAAAATGGTAAaaggcagaaaggagcccagtctcgttctttttaaga
+agttttcctaagaatctccacccagcgacttgctctcacatcttcttggccagcactgga
+ccacacaactccttctagatacagaggagTCCTAGGATTCTATGAGAAAGAAGGGGAGGG
+TGGGCAAAGGGCAGCCAGCTGTGCAGCATCTGCTGGAGACACCTAACCCTTGGTGGAGGG
+GTTGTGGTGCTGGgagaaggctttctggacggtgtgacagcagagataaacttaaaggcc
+aagtaggagttaccctggtgaagcagggcagggttacaagcattccagcaacatgaagca
+gcaGGAGtgttttaattaaaagaaggcagttgctgtaaccaactataaacaaataaaggc
+ttaaacacaatggaagtttatttctcactaagggaacatccaaatccatgatactttaag
+tcagggacccaggttcctcccatctatggttctgccatcactaatctgggtcttccacaa
+ttgccgtgctccttggaggtgggaagagcaggcggaggacacgtgggaggttttagggac
+aagcctggaggcagcatgcgtcactcccatgcagagtccattggccaatgctggctccga
+tggccacatctcactgcaggggcagctgggaaatacagtctggctgtctacccaggagga
+agagcagccagtttctgctgCTGATGATCAGGAGGTGGAGAAAATGTTCAGTCAGGCAGG
+GAGTGGGAATAGACAAGACCACAAGCAGCTTGGTGCCTCTGAAAGGGAGAGGGGTGGAGG
+GGAGACTAGAGAGGTGGGTAGGAATACTGGATTCCACTGACCACGTGCTGGATGTCACGC
+TTAGCCCTCCTGCTCTGTGCCGGGTTAGGCACCTGGTGTTTTACGTACATAATCTCAATT
+CTGTGAGGGCATCCGACCTGTGGGAAAAGAGCTGTTTGTTTCAAATGCCAGTCCTGCTTC
+CTAACAAGTGTTTAGAGCTTAATCGTGTTCAAAAtacatatacaatgtttaatacttaca
+agaatttggtggggaaaatattaccatctttcccttttgtgattggagaaaaatgaggct
+ttgaagggtttaagaacttgcccaaggtcggccaggtgcagtggctcatgtctataatcc
+caacactttgggaggctgaggtgggaggatcgcttgaggccaggagttcaagaccagcct
+gagcaacatagtgagactttgtctctataaaaaataaataaataaataaaaaCAACTTGT
+CCAAGGTCAGACAGGCAGCCTCTTAGTAAGCACACATATCCTCTATATTATACTACCTCT
+CATGGAGGATCTCCTGTGTTCTACAAATAGTCTGGACTTGAGCCAGAATGTGTTATAATC
+CTGGGATCACGGCCAGTGGGCTTAGAAGAAGCCATCTCTTTCTCATGCCAAGATGAGGCT
+CCCCCAGATTTGCTCAGACTTACCTATAGTCAGCAGCATCGGGGGTCAGGAAAGACTTCA
+CGAAGCCATAAATGCATCCTTCTCGGGGCAGCACCTGGCTCTCCCAGGTGAGAGAGGACT
+CCATTTTCACAGGCAGGCGTGGGAGCTTCAGCACCCATCTCTGGGCCCAGAATGACCCAC
+TGGAGACCTTACAGCTCTCCTGTCACCCCCAATTCCTGCCCCCTCTGCAGCCTTGGAGGA
+GAATGGAGCTGAAGGGCCTGCCCTCTGTAGGGTGAGAAAGGGAGGCTAAAGCCTGGTGCC
+CACTGCCCTGGCTGCTCCGCATTGCAGGAGCTGCGCCCTTCCTTTCCTGGCACAGGGTCC
+ACAGCCCCGAAACCCCGTTGTGTGGGAGCTGGGCACAGGGCAGCAGGACTAATCCTTGGA
+ACAGCTCAGGGAGGATTATCCCAGCCACTGTCAGCAGCGGTGCAGCTGGCTCATTCCCAT
+ATAGGGGGAGGCCAGAGCCAGGGGCCTGCCACAAGTTGGAAGGCTGGGGAAGGGGAGGCC
+AGCAGAGGTGTCCTGGCTGTGGGTGGCTCTGAGGGGGCTCTCAGGGGTGGGGCTAAATCT
+CAGGGGCAGGATTATGTAAATCAAACCAATTCTAGCCACAGATTTAAAGTTTGGAAAAAA
+AAAAAAACCCAGCCTGGCGGAAAGAATTTAAATTATAAAAACTTAGAAGTATGGAATGTG
+AAATCATCCTGTAGGTGCTTATTTAACAACGAAATCATCCCGACACAATGAGCCATATGT
+GAAAAGTCATCCTTCCCCAACACATCCCCCAACAGGCACTCCTCAAGCCTCTCCCACCCA
+AGTGCTGGCATCCTCCCTGTCCTGCTTCACCTGAGACACCCCTTGTCTCATTAGACATGC
+AACTACGGGAGGGGTGACAGGAAGACAAGACACTATTTCCTCAGGCCCAGTTTGGTGTGG
+GGAGAAAGCCTCCTGATCCTGAAAGCAAGAATTTGACCAGAGCAGAAGTAATCAGTATGC
+AGATTGATTCTGTGGTATGTTAATGTTTATGCATAGATTATGAGGACCAGGTGAAAAGTG
+GGCCAGGGGAGCCAGATGTGTGTGTGAGTCATGGGTGGCTGAGATGAGGACAGGAGGGAA
+ACTGGTTTGGAGGGTGCTGGCGATGGGGTGGGGGTGCCAGGAGGAAGGGAGGCTAGTTGT
+TTGAATGTCTGCATGAAAAAGCGGACGACAGCGGGGTCTGGGTGAATTCGGGCAACCATT
+TGGACCGTGGAGAAAACTGCCTGCGTGCGGCTGAGGACCTGCACTATTAATTTGTTTTTT
+AGCTAAGGCAAAGATAAATATAAAAACtgatactccacccagttaccagaaaacatttag
+gtatgtgtgagacaacttgggtatgtgaacctaccttttcaatgtaaattcagtgaaatc
+taagtgcagatcccatatttccaataaaaaggtaacatccaaactcagatgtcctatgag
+tataaaatacacaaagatcttctggacttagtatgaaaagggattttttttttgtcaggt
+acctcactagttatttttaaaataggattgcatgttgaaatgataatcttttggatatat
+tgggttaaataaatttattattaaagttaatttcacttaaaaatgtttaatgtagctact
+agaaattttaaaattaagcatgttgctcaccttatgtttctattggacggctctCTCTAG
+ATACAAAGGCTGCCAAGAGGGACCTCACTCTAGCTTCAGGGAGAAGAGAGGAATTAGCAA
+GGCCAAGCAGAGGCTCCTGAGGGCAGGGCCAAGGGCGGCTTGGTGGGGTGGGGATGGGAT
+GCACAGAGATAACTCCAACCCTTAAGAAGGTGTTTCCTAGAGCAGGCTGTGACCTGTCAG
+TTTATATACTGAGGCTTAGGAGCCTCTTGGATGCCCCCAGATCTGCACCCCTGAATTGCC
+CTGTGCCCCTGCCGTCTTTGTTCCTGTGCTGGCATAGTGGTCTCACCTCCGGCAGtatca
+ccaccactgggcacaagcttctccagcacagcaactgtgtcttatttctccttgtactcc
+cagtgttcacaccatgctgcactcacagaagactcttcgttgatattttgtggacagaga
+gaatGCCTGTGAGAGTGGGCTGAAGTGTGCGTTGGGCTCCAGAGACCTTAAGGAGGGGAG
+ACCAGGTCCTGAGTAAAGTTGAAGGGGAGGGGCTGAGTCCTGCTAGCCAGGAGTCTCATC
+CCCTGGGGAAGTTCCAGGGACCCCTCAGAAGTGCAAGGGGACGGTGTTAGTGTTAGTCCA
+GTAACACAGCCCAGAGCCTGCcttccacgtgggtttgacaggagcctcctaactgctctt
+ctgcttccatttttgccccttcagtctattctcaacagggaagccagaggcatccttaac
+catgtcagatcatgtggctcctcagctcaaagccTCATCTCAGAGGAAAGCTCTGGTCCC
+TTAGAAATGGCCCAAGTGGTGACAGACAGACTCTAAGGtgagcagactgttgctagatat
+ctgggctcggaggactcgccactgctcaaaggcagtgaggattttcgcactagaagctgg
+aggacagggatccttgttaggtaggagcagaaagcttagaaaagtggtctcctgcagtta
+cgtggcaaacacatcatgtaagtgataaattgggtatgcagttgaggagatttccaagta
+aaatgttgaggatgctgcctggtttcttcttactgcttataatatagtgtgagagaagag
+agataaattgagaaagagactggtttttaaactgttaaaattgaatcaggacttgatgat
+tttgaaaattgtcagtctccccacatggaaaaagatgctgaaattaacaaatggcttctg
+agcatgtggcatagggtgtaactgtacagtcttttgtgattatgcataaagatcaaagga
+tgggagtagcaatgagtcacacagaggtctgttgcaagagattacaagggtgtaccatgc
+agaacctctccaccaaaccttagggcccttgggaagcttcagtgagttaccctgggggcc
+atcttggcaggagctgaaggtagaaaggtagagtttatctctaaaagattcatgggtatg
+gctcttgacaaatcgactatgagccccaccgaaacccacagaggacaggcaaagggtttg
+ggaaagctgtttcacccacagtgctggcagattggtctgtaggggacagagtgcaaaatg
+aaagaagactgtcagagaccccaaactctgctgtcaagaagaaggctgataaaactactt
+ggctgcaaacacgtggatctttcgtgagaaaagaaggatgacccagaggcagaagcccag
+aaggcagagccaagagacatggaatcttcccacatcttaaaacctgtttagggaacacca
+gcatctgtccagctggatttcagaaccaccattccttcatccttcccctgctgcctcttt
+ctgaacagcaatgtctcaagctttacccaccattgtgtgttgcatatgtagggggcagat
+agcttgtatctttagttttccagatcagaggaacatccaaagaaatctgttctacaccta
+aacccgatttagatgagattcgggactgtgagcatgaagggatctcaagaggggtgaatg
+tgttttgcatgcacaagggacaggagtcttggggacagaggacaggctgtggtggcagat
+actaaggtgacccccacaacccccacctctgccattcacacccttgaataatccccttct
+ctggttgtaagcagaacctgtggcttgcttatgaaggaggcggtatatatgtgattcatg
+tactgatcatattgtataagatcactggctggatgcagtggctcgtgcctgtaatcccaa
+cactttgggaggctgaggcgggtggatcacctgaggtcaggagttcgagaccaggctggc
+caacatggcaaaaccccgcctctactaaaaatacaaaaattagccaggcatagtggtgca
+cgcctgtaatcacagctactcaagaggctgaagcaggagaattgcttgaactcaggaggt
+ggaggtggcagtgagccaagatcgtgccactgcactccagcctcagtgacagagcgagac
+tctgtctcaaaaaataaataaataaaatgttaagatcataacctgtctttctggggactc
+tctcttgacgcctttgaagaagcaggctgccatgttgcaagctgcctcatggaggggatc
+agctgcgaggagctaagagccccctccagtcgatgctcaccaggaagctgaggtcttgtg
+tccagcaccctgcatagaactgaatgctgccatgtgagcttggaagcagagccatccaca
+cagctgagccctagatgagaacccagtgctggctgacaccctgatggcaccttacagagg
+accagttaggctgtgccaactcctgacctgcagaagctggggaacactgggtcgtatttg
+cagctgctggatttgtgggaatttgtcacacagcaatTGGGAGTCACACAGCCTGTGACG
+CCCCAACAATCCACAcctcctgcatctccctgccttcacttcctagcacactgccctgac
+tccctctgccgcagccacgctggccctctgctgttcttcgaagccaccagggctgcattg
+gctcccagcctttgctctcactgctttctcctcctagagagcccttcctgcatgtatatg
+tttgactcactcccttgcctccttcagacttgtacttaaaaatctcagtaagcatttccc
+tggctacccttttaaaaattgcaacccacttccatccccatccccaacatgccatatttc
+ctttcttcttcttccttcttcctttttttttttttttttttgacacaggttctctgtcac
+ccagcctggagtgcagtgacatgatctcggctcactgcaacctctgcctcccCAGGCAag
+aaaaggggaggatgccaataaaggatgcattgatttgtatttactacagtggacatcaag
+ggcacattcttgctgtggccatcaagagactgtataaattctatgacttgtagttgtccc
+acttaagaaacaaagaagctgtgcatttctttactggtctagagctgctctagggcattt
+tctctacagcaattctaggtttccccaccttgtgagtttagctttttctatattcaaaga
+aaagtcctcagccagagattctcaggagcttatagaacaatccaaactcttgggaatatt
+aagtggagaggggtacgtgcaagacaccaacagcACTAGAAACAGTCCACATCTTTCCAT
+GCGTGGAGGAGTTTATGCTCTATGTGAGTTCACTCCATCATTAATTCTTCAAACACAAGA
+GTGTTAAAGGAACAAGAGTTAATGGGTCCTGTCATTACACTTGTTCCCAGGATGACATTC
+TTCATCTTCCTCTTCTACAACCTGTTCTATATTCCCCTCATGTTTATCCAGTGCTTCTGC
+TAGTCTAGTTCACTTCCAAAGACCCATGATTACCATGGCCCTGTCAGGCTGTAATTGCTG
+CAATTTCCAATTTACAATTGTCATCATCTATGGTTGATAAAGgtatagcaatatttctat
+ttcctcatgataatgaaggtcaattacaactgccagtataataacttatttctttgtctg
+ccaacctacatacacaaggaagccaaaatgacagggagctactaaaactttattcttatt
+ggaatgcttactatgtacccagaagaagcattctccctactccagcagagcttaatgctg
+taggtccaggaagctcaaattctccaagggagttttagtgagaggagccactctcaccct
+ctgcccttggtttacaaacctgtatattctaggacccaatatcttacaatgtccattggt
+tcaaagtataacatgttaaagcacagagccccaactctgaaaagtaccatccctaaattg
+gcatttagttgcacctttatatccacctttaaaagaaatatcttttaatgttctatcaga
+ctgatagattctgtttaatatagtatattatagcaccagtggatcatttggttgtatgca
+tattattgtaccttctctgctacaaaatatattcctttgtcctaaggtgtgttacaaaga
+acattaggcattctatgcatctttggatagtttaatggccaagacattgatggcaggaga
+gtcaaagccacaggtggaaaacacatttatcccagtaagaacaaattgctattcttccac
+tgtagagagggtaaacaatgtgccattacgttgccaattgaatgcctcaatcatgtcaag
+ggctgaacatctatgactgtttctgaaaggtcaaacattcaacagaggctgtagctagaa
+ctgccttaatgataagagatcatgctgaattacccatgcaaaaccttaatacttgacact
+tatcactactttattcaagagcctattgtgcaagcataagtggctgagTCAGGTTCTCAA
+CTCTGCTCATTAATACTATGCTTGGAGTATACAGTAAGATAAGAAACATAAATAAGAAGT
+GTACATTTGTTTCTTCCTGTTTTCTTCTGGCTATTGGATCAATTACATCCCATCTTAAGC
+TGACCCCTGTGTAATTAATCAATATCCGTTTTAAGCAGCAATCCATAGTTGTGCAGAAAT
+TAGAAAACTGACCCACACAGAAAAACTAATTGTGAGAACCAATATTATACTAAATTCATT
+TGACAATTCTCAGCAAAGTGCTGGGTTGATCTCTATTTACGCTTTTCTTAAACACACAAA
+ATACAAAAGTTAACCCATATGGAATGCAATGGAGGAAATCAATGACATATCAGATCTAGA
+AACTAATCAATTAGCAATCAGGAAGGAGTTGTGGTAGGAAGTCTGTGCTGTTGAATGTAC
+ACTAATCAATGATTCCTTAAATTATTCACAATAAAAAAAAAGATTAGAATAGTTTTTTTA
+AAAAAAAAGCCCAGAAACTAATCTAAGTTTTGTCTGGTAATAAAGGTATATTTTCAAAAG
+AGAGGTAAATAGATCCACATACTGTGGAGGGAATAAAATACTTTTTGAAAAACAAACAAC
+AAGTTGGATTTTTAGACACATAGAAATTGAATATGTACATTTATAAATATTTTTGGATTG
+AACTATTTCAAAATTATACCATAAAATAACTTGTAAAAATGTAGGCAAAATGTATATAAT
+TATGGCATGAGGTATGCAACTTTAGGCAAGGAAGCAAAAGCAGAAACCATGAAAAAAGTC
+TAAATTTTACCATATTGAATTTAAATTTTCAAAAACAAAAATAAAGACAAAGTGGGAAAA
+ATATGTATGCTTCATGTGTGACAAGCCACTGATACCTATTAAATATGAAGAATATTATAA
+ATCATATCAATAACCACAACATTCAAGCTGTCAGTTTGAATAGACaatgtaaatgacaaa
+actacatactcaacaagataacagcaaaccagcttcgacagcacgttaaaggggtcatac
+aacataatcgagtagaatttatctctgagatgcaagaatggttcaaaatatggaaaccaa
+taaatgtgatatgccacactaacagaataaaaaataaaaatcatattatcatctcaatag
+atgcagaaaaagcattaacaaaagtaaacattctttcataataagacatcagataaaaca
+aattaggaatagaaggaatgtaccgcaacacaataaaggccatatataacaagcccacag
+ctaacatcataatagtaaaatcatcacactggtaaaaaaaatgaaagcttttcctctaag
+gtcagaaataatataaaggttcccactcttgctatttctattccatatcgtactaaaagt
+cctagccaggacaattagacaaaataaaaataaaaacacccaaattggaaagatagaagc
+aaacttttctgtttacagataacataatcttatatgtagaaaccccttaaaacttcagca
+aaaaaaaaaaaaaaactacagagctagtaaattcagtgaagttgcagaatacaaaatcaa
+catacaaaaatcagtagtgtctctatacactaataaggacttaacagagaaagaagttaa
+gaaaacaataccactaacaatagaatccaaaaaataaaatacttaggaataaattttacc
+aaacatctgtacactaaaaactataaaacattgaaaaaagaagttgaataagacacatat
+aaatagaaagctatctcatgttaatagattagaaaaagtaatattgttaagatgtcctca
+ctacttaaagcaatttatagatctaatgcatttattgcaatctcttcaaaatcccaaagg
+tatttttgacagaaataaaaaaaaaattctaaaatatgcatgaaaccacaaaagactgtg
+aatagctaaagcaatcttgagcaagatgaacaacactggaagcatcacactaccttattt
+caaaatctactacaaagctatagtgatcaaagcaacatgatactgtcataaaaacacaca
+gataaacctatggaatggaataaagagcacagaaataagtccacacatttacattcaatt
+gattttcaacaacaatgtcaagaagacaatggggaaaagacaatctcttcaataaatgat
+gctggaaaaactatatatccacatgcagaagaatgcagttgaatcctgatttcataccat
+atgcaaaattcaactggaaatggattaaatacaaatttaaaacatgaaatggtataacta
+ttagaacaaaacatagaaaatattcttcctgacattggtttgggccatcatttttctgat
+atgactctaaaagcacaggcaaaaaaagaaaaaatagacaaatgagactatgccaaatta
+aaaaatttctaacaacaaaagaaacgatcaatagagtgaaaaagataacctcttgaatgg
+gagaaatatttgcaaactactcatccaaccggggattgatatccagaatatacaagtaac
+acaaatatgtcaaaagtaaaataaataaataaataaataaataaataaattaaataaatt
+atttaaaaatcggcagaggacaggaatagacatttctcaggagacaacatacaaagggcc
+acagatacatcaaaaaatgctcaacatcactatttgtcagggaagtactaattaaaacca
+aaatgagatgtcccctcaaacctgttagaatggctattatcaaaaagatgaaagatagca
+actatcagagaggatgatagaaaagggaacccttgcatcatgtacaaattaaaaatagaa
+ctatcacatgatccaagaatcctacttctgggtatatagccaaaggaattgaaatcaata
+tgtcaaagggatatctgcactcctatgttattgcagcatgttcacaatggccaagatata
+gaatcaacctaactgttcatagacagatgaatggataaatgaaatgtgatatggaaaatt
+attcagccttaaaaacagtaggaaattctgtcatttgagacaacgtggatgaacctagag
+gacattaagctaagtgaaataagctagacacagaaagacaaatattgcatgatctcactt
+agaatctaaaaaatctgaactcatagaagcagagaatagtatgatggttactagggttat
+ctggcagggagaggatgaggaaatgggacattgttaataaaaggaaaaaaattcaattag
+taggattacattcaggggacccaatatacgacatgttgactgtaattaataatgtattgt
+atgcttgaaaattgctaatacagtatattgtaaatgttaatatgaggtaatatatgtgtt
+aattaacttgatttattcattcaacaacatacacatatattaaaacatcacactgtattc
+cacaaatatatataatttttgtcaattaaaaaaTAATTTTTAAAAATGAGAAACAAAAAA
+GCTGACATTTTCAGATTAAAAAAATTATACAGAAGAATTAATTCATTAAAGTAAAAACAA
+ATGTGGGAAAATGGTTTTTAAATATAATTTAAACCAAATTTAAAATAAGCATATaaagac
+tatggacaaaacaagaaatccaaataaaaaataaacatatgaagaatattcaaactcact
+ttttatcaaagaaatgtaaattTTAAAATATAGCATTGCTATTGTGTTTTCATAAATAAT
+AATATATCATGGATGAGCCTGTGAGGAAACAGACACTCATACTCTGCAAAGCAATGACTA
+Agataattatgtcagatcatgaattacgttaattagcttgatggtggtcactgtttcacg
+ataaatatacatatgtatcaaaacatcacattacacaccataaagatatataacttgtta
+tCAAAAAGAAATATAGCAGttaaaatttaaaatttttaaaaaaCGTCTTTTTGAGGTTCG
+TACCTCACTTAAGTCACACTGTTCAAAATATTCATGCACTCATTTCTCTCATTCATGTGT
+TAATGTACAGGGTACGGGCCACTATAAATTCCTTCAGCAACTGGAAAGGAAACTTTATGT
+ACTGAGTGCTCAGAGTTGTATTAACTTTTTTTTTTTTTtgagcagcagcaagatttattg
+tgaagagtgaaagaacaaagcttccacagtgtggaaggggacccgagcggtttgccCAGT
+TGTATTAACTTCTAATTCAACACTTTAAGATTCTTAGCATTATTGCAGACAACATcagct
+tcacaagtgtgtgtcctgtgcagttgaacaagatcccacacttaaaaggatcctacactt
+tttttaatgctctgctgtttctgccttgaaattcttaacaatttttttaaccaaagtcct
+cacaaattcagtttacattagccctgcaatcatgtagacatcctgATTCCAGACAATGTG
+TCTGGAGGCAGGGTTTACAGGACTTCAAGAACCTTACCTTCTCAACTTTCATCTGCATCT
+TTACTCCCAACTATATATGAAGATGATGAAGATAGATATGGATGGTGCTTCTACCATACC
+CTCTTCCTCTGCCAAACTTCCTTGATCTAGGATAAggtcagtaaacttcttccgtaaaag
+gccaaaagtaaatattataggctctacaggccctagagtgtctgtcataactactcaact
+cttattgtagcataaaaactgtcaacagacaatacagaaacaaatgagtgtgactgggtt
+ccagtgaaactttatttacaaaagatttgtcccatgagtcaaatttaccacctccAGATC
+TAGAGAAACAGTTTTGAGCCCTTTTATTTTGCTCAACAGTTAAGCATGGCTCCATGTCCC
+TTATATTTAGTCAGAACTCGGTATGTTTTAAGGAAAGAATGGTTACACGAAGACATACAT
+TCATTCATTTATACAACACATTTTCAGTGTTGAATGATAAATTTTGGAATAGTTAACAGA
+TGATAAAAGTGTTGTTTTCAGTCATCCCTATCCAATGAAGTAAAAAAAAAAGTGTTGAAT
+GGGAAGAAATCAAGAATAGTTATACGAATATCACCATTGCATTAAAGCTCTCTTCCTTGT
+TTCTAAAAGAATATCTTGACACACATTAAGCTCACTGACCCCCACACCATGAATGAGGGC
+ATCTTCAACAATGGTGGATGACGTCTTAGTTTCCCTCAACTCAGTTAATCTAAGTAAGCT
+CATGGTATCACTTTCCTGTCCTAGAGGGAACATATTTCCTGCATTTTTCTTTTTTTCCTT
+ACTTTCCATCACCAAGTAACTCTTCTGATATTTTTTCTCTTGAGAAAATTAATATGACTC
+ATAGATCTGGTTCCCAAGAGAAATCAATGGAGGCCTGGTTACAAGGATCTAAGAAGCATC
+AATGGGTCACTAACATCTAGTGGTACTAATTAACTCTGTTAATCATTGGGAAGAAAATGT
+ATATATACTTTTGTCTTGGAGCTGATTCTACTAGAAAGCAGAAATCAAAATGATCAGTTT
+CCCAGTGTCACTACTGCACACCCTGGAACAGAACAGGTAGGTCAGAAAAACGCTCCCAAA
+GTTTAGCAATGTCAAGGCAATCTCTCTCTTCTTACATTTCCCTTCAACCTTCTATCTCCT
+CCACTTTTCTGTTTTCCTCCTATCTCCAATTATTTCAATCCTCAGAGCATTATTCTTACA
+ATCTTAATCACTAAATTATATTACACCCGTTAAAGGAGAGATTTCTAAATGCATTGACAT
+TTGTACTGTCTCTCTTTGGAGAATTAGTATTATAAGGATCTGTTATCTCTTGTCACCTTC
+CTTATGTCATATGATATGTCACATTTCCCACTGCGGAGACCAAACATGTTCACATCGTGT
+GCGTTCCATTTTCCTAATGGAAAGTGGGGGGAAGTGATTTTCTGTCCTCATATAGAGAAT
+GCTGGGGCCATTCCCTCTGTATGCCATATTTGATAAAGCATTTGATAATCTTAGTCAATG
+CCTGGGCCAAGAATTAAAGGGGTAATTATCAGAATGAAAATGGTTTAATGAAACTGTGTC
+TATCAGTTCTGAAAAGGGCCTCTATCACAATGAACTAAGGTAGTTATGAATAGAGCTAAa
+acttaggcaacaccatcctggacataggaacgggcaaagatttcatgacaaagacacgga
+aaccaatcacaacaaaagcaaaaattgagaagtggaatctaataaaacaatagcttctgc
+acagcaaaagaagctaccaacaaagtaaacagacaacctacagaatgggagaaaatattt
+gccaactgtaagtctgacaaaaatctaatatctggcagctataaggaacttaaatttaca
+agacaaaaacaaccccattaaaaagtgggcaaagaacatgaatagacactctcaaaagaa
+gatatacatatggttaacaagcatatgaaaaaaaagctcaatatactgagcattagagaa
+atgcaaatcaaaaccatattgagatatcatctcataccaggcagaatggctattattaaa
+aagtcaaaaataacagatatcggtgaggttacagagaaaagggaacacttatacactgtt
+ggtgggactgtaaattatttcaaccattgtggaaagcagtatgggatggcgattcctcaa
+aaagccaaaaacagaactatcattcaacccagcaattccattactgggtatatacccaga
+agaatataaatcgttctaccataaagacgcatgcatgagaatgttcattgcagcactact
+cacaatagcagagacatggaatcaacttaaatgcccatcagtaacagactggataaagaa
+agtgtggtacagatacaccgtggattactatgcagccataaaaaagaacaagatcatgtc
+tttgacaggaacatggatggagctggaggctactatccttagcaagctaaggcaggaaca
+gaaatccaaataccgcatgttctcacttatgagcgtgagataaatgatgagaacttgtaa
+acacaaagaaggaaacaacaggcagtggggtctacttgaggacgacgggaagagggagag
+gagcagaaaagataactactgactaccgggcgctacctgggggatgaaacaatctgtaca
+acgaacccccaggacatgagtttacctatgtaacaaaccttcacgtgtacccccgaacct
+aaaataaaagtcaaaaagaaaAAGAAAAAAAGAAAAATCCATGCATATGATACATCAGTT
+AACAAGGCACTGGTGAAATTAATTTTAAGTATTATTGTCTCTTTGTGTTTTTGGTCTCAG
+AAAAGTTACGATTTCCCTTAGTTCCTTAGGGCAGAGAGAATCTTCAATCACTGAAGTCAG
+GAGACACACATTCTATCTGATTTTCTACATTATCTGTTTGAAAAGGTTACCCACTTATTA
+GTGTTAAAGCCAAGATATCCAGCAAGGATAGCAACCAACTCTTAAGGTACTCTCCCTTAG
+GAGGATTCCTGATTCTTTAATGTTTTCTAAAAAAGCAAAACAAACAAACAAACAAAACAA
+AACACTAAATGTTTTCTCTTTCAACTTATTTGAATACACTCTTTTCTCACTGCTCTGAGC
+ATGAATTCAATATTTCAGGGCAAACTAACTGAATGTTAGAACCAACTCCTGATAAGTCTT
+GAACAAAAGATAGGATCCTCTATAAACAGGTTAATCGCCACGACATAGTAGTATTTAGAG
+TTACTAGTAAGCCTGATGCCACTACACAATTCTAGCTTTTCTCTTTAGGATGATTGTTTC
+ATTCAGTCTTATCTCTTTTAGAAAACATAGGaaaaaattatttaataataaaatttaatt
+GGCAAAATGAAGGTATGGCTTATAAGAGTGTTTTCCTATTGTTTTCAGTGTAGGACTCAC
+TGTTCTAAATAACTGGGACACCCAAGGATTCTGTAAAATGCCATCCAGTTATCATTTATA
+TTCCCTAACTCAAAATTCATTCACATGTATTCATTTTTTTCTAAACAAATTAGCATGTAG
+AATTCTGGTTAAAATTTGGCATAGAACACCCGGGTATTTTTTCATAATGCACCCAATAAC
+TGTCATTCACTAATTGAGAATGGTGATTTAACAAAGGATAATAAAGTTATGAAACCAATG
+CCACAAAACATCTGTCTCTAACTGgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtAAGA
+GGGAGAGAGAGAAAATTTCACTCCCTCCATAAATCTCACAGTATTCTTTTCTTtttcctt
+tcctttccttgctcttctttctctcctattgctttcctttcatttccttCTCATAAAAGA
+AAAATAACAATATAGAAAATAACAAAATATAGATGGTCAACCTTTTTAATATTAAGGTTA
+CCTAAAATGCCATTATCCAAAGTGGTTCTCTAGAGATGCTGATGTATATACTTACATATT
+TTACAGTGTATTCAAATAAAGAGTATATTACATAAGACATATCCTTTTGTAACCAACTTT
+TGTCATTAACAATTTACTGGACTTGTCAACAAACCTAAATCTGTATCGTCTATAATGGCT
+ACGTTCATTTTGGTATGAATCTTAATTACCCCTTTCTGCATTATTTAATGATTTTCTCAT
+ATGTCACTCTTAAATGTACTTCTAATTTTTCACTTTACATCACATAATGAATGGATCCAA
+ATATGTTATGGATAGATATCTTCAAACTTTCTACTTACAAGTAGTGATAATAACAGATGT
+TCTCTCTAAAGTGTAGTTGGTATCAATTTTACTGACCTTTAAAAATATCTTAATGGGACA
+AAGTTCAAATATTTGATGACCAGCTATCGTGACCTTTATCTCTGTGGCTCTGTGGGCCTG
+TAGTTTTTACGTGCTTTTAGTGTATCATGATTAAATATTTTGTTTTAGTAAAGACACCAT
+TATTTCCCAACTTCATATTCAAATTGTCAAAGGTATTAATCCTAGAGCAGAACTCTCAAA
+AGCACCAACTCTGATTCCTAACAAAGCATGGAAAAGCCCTCTCTCTGAGTTTCAGATACT
+CTTTTTTGTGGGGGTTGAGTTTCACTTTATTTAAAGTGAGTCTTAATCCTCCAACAAGTC
+AACAAGTGATTGGCTGGAATCACACGTATTGGAAAACCAGCGGAAGAGTAAGTCTTTGTA
+TTTTATGCTACTGTACCTCTGGGATTAATTGCTCTTTCCCTCATTGGCCAGTCACTCTTA
+GTGTGTGATTAATGCCTGAGACTGTGTGAAGTAAGAGATGGATCAGAggccgggcgcggg
+ggctcgcgcctgtcatcccagcactttgggaggccgaggcgggcggatcacgaggtcagg
+agatcgagaccatcctggctaacacggggaaaccccgtctccactaaaaatacaaaaagt
+tagccgggcgcggtggcgggcgcctgcggtcccagctgctggggaggccgaggcgggagc
+atggcgggaaccgggaggcggagcctgcagtgagccgagatggcgccaccgcactccagc
+ctgggcgacccagcgagactccgcctcaaaaaaaaaaaaagaaGATTGATCAGAGAGTAC
+CTCCCCTAAGGGTACATGCAGATAAATACAGTTAAGGCGATTAACATTTCAAATACGGTG
+ACTGTTTCTTACGTGGACGACGTTGTGTTGAACATGGGTGAGTAAGACTGAAGCAGCCGT
+AATTACTGCACGATGCGCATGGTAAAGAAGCACTCCGTTAGGGAAATTATATTCTTTGCC
+CCTCTAATCCTTCACTCCACCTGCCATATTCCCACATGATTTTTTTCTTTGCTGTTCTTG
+TCTAATTGttattaataattaataaataaCTTATGATCTAATTGTTATTAATAATAACTT
+ATCATCACATGatttattaataaattaataaataacttattatCACCGCATTTCCCCAAT
+TCATTTATCTTTCTTTCATTTTCTCTCTTTGTGTGTTTTCTGTCTTCATATTTCAGCACT
+TGCCACATATTTCCCACAAAATCATTTATGGTCAAACAACACTTCAACGTGTAGCATTTG
+TATTTCTCAATTCTTCCTCACTTTCTTCCTTCAGAATACTAAAGCTTCTTCTCTACTGAC
+TGAGTCAATGGCCAATGGATAGAGTAAATAATTCTGCGGTATCTAAATTTGTATTGATTG
+GACTTTCAAGCTCTTGGGAGATGCATCTTTTTCTTTTTTGGTTCTTCTCTGTGTTCTACA
+TGGGAATTATCCTGGAAAATCTCTTCATTGTGTTCACAGTAATTATTGACTCTCATTTAA
+ATTCCCCAGGTACTGCCTACTGGCCAACATTTATCTTCTTGATCTGGGTCTTCTCCTACA
+GTTCTGACTTTTTCACTAACTGCAGCATCATTTCTTTTCCAAGATGCATCATACAGATAT
+TTTTCATTTGTGTCATGCGTAAAAATTGAGATGGTGCTGCTCATAACCATGGCATAGAGC
+AGGTACACTGCCAATCTGTAAGCCTCCCCATTACCTGACCACAATGAACCCCAAAATGTG
+TGTTTCCTTTGTTGGAGGCATCCTGGATAGTCAGGATAATCCATGCTGTATCTCAGTTTG
+TTTTTGCCATAAACTTGCCTTTTTGTGGCCCTAATAGAGTAGGTAGTTTTCACTGTGATT
+TTCCTTATGTCATGAAACTTGCTTGTGTAGACACTTACAAACTAGAGGTTGTAGTCACTG
+CTAACAGTGGGCTTATATCCATAGCTACCTGTTTCTTATTAATAATATCCTATATTTTCA
+TTTCGGTAACCGTCTAGAATCCTTCTTCAGGAGACTTATCTAAAGCATTTGTGTCATGTT
+AGATCACATCACAGTAGGGATTTTGTTTTTTATGCCATGTATATTTCTGTATGTGTAGCC
+TTTGCCTAAAACAACACATGATTAATATTTGTTCATTGTTCCTTTTGCTATCACCCCTGT
+CTAGGATCTACACATTAAGAAACAAAGACATGAACGTCTCCATGGAAAGACTGGGAAAAT
+GGATTGCAGGTTCTAGCAGGATGTCATAATAAATGGTGCATATCCAGAGTGCAAGATGAT
+TCAGTCTCACCAAGAACACTGAAAGTCACATGGCTACCAGCATTATTGTGATAAGAACTA
+CTATTTTGGGAGATAGTTTAGCAAAGGTGCCATGTAGAAATTGATTAAGTCAGAGGTATC
+TTTAACTTGCCACCACAGAGAAGAGATTAATTTCATATACTTCCATTGAGAAGAGAGATA
+AGAATACAAAACCAAGCTGATTTGCAGGAGTAAACTTGATATTCAAATACTATTTCCTGA
+ATGACATTTTCTGAGACATGCTAATTGTAATTACTTTCAGCTTCAAAACATAATAAATTT
+ATCTCATAGTAAGCATATAGATGGAATAAATAAAATGTGAACTTAGGtaaattataaatt
+aataaagtatatttttaaaatttCCATTTTAATTTCTGTTTAAATTAGAATAAGAAACAA
+AAACAACTATGTAATACGTGTGCAAAGCCCTGAACTGAGATTTGACTTTACCTTGAGCTT
+TGTCAGTTTACGATGCTATTTCAGTTTTGTGCTCAGATTTGAGTGATTGCAGGAAGAGAA
+TAAATTTCTTTAATGCTGTCAAGACTTTAAATAGATACAGACAGAGCATTTTCACTTTTT
+CCTACATCTCTATTATTCTAAAAATGAGAACATTCCAAAAGTCAACCATCCAAGTTTATT
+CTAAATAGATGTGTAGAAATAACAGTTGTTTCACAGGAGACTAATCGCCCAAGGATATGT
+GTTTAGAGGTACTGGTTTCTTAAATAAGGTTTTCTAGTCAGGCAAAAGATTCCCTGGAGC
+TTATGCATCTGTGGTTGATATTTTGGGATAAGAATAAAGCTAGAAATGGTGAGGCATATT
+CAATTTCATTGAAGATTTCTGCATTCAAAATAAAAACTCTATTGAAGTTACACATACTTT
+TTTCATGTATTTGTTTCTACTGCTTTGTAAATTATAACAGCTCAATTAAGAGAAACCGTA
+CCTATGCTATTTTGTCCTGTGATTCTCCAAGAACCTTCCTAAGTTATTCTACTTAATTGC
+TTTATCACTCATATGAATGGGAATTTCTTCTCTTAATTGCTGCTAATctcccccatcttc
+aaatactctaccgggcttctggaacaccacagcttcctggctttttctcctacctcctgg
+gcaagtccttccctgtgtcttttgttgagtgttcctcatctgcttaactaccaatcaacc
+tattgcccctaatttgatctttggcctgttttcacttagattctatccctacgtatcacc
+cattcccacagctttaatcaccatctaaacactaggggctctcaaaccttgtatttttct
+ttctttctttctttctttctttctttctttctttctttctttctttctttctttcttcct
+ccttttctttccttttctttctttcattctttctttcttttttaaggggcagggtctcac
+tatgttgctgaggctggtctcaaactcctgacctcaagcaatctgtctgcttcagcctcc
+caagtagctgagaatacagggacaagccattgcacctgaccctggtactatttcttgagt
+tcctgatccacagatctaacctcctactttcctggatgccacacaagatcttccactcaa
+caagtctgcaactaaactagccttcctcttttcaaacctactcttctttcagtgttctca
+gtcacaataatttgtaccaactagttacctagttgcacaacccaaaatctgggaaaaata
+atagatttctttctccatagtacccccaaatcaataaatcatcaagtcttattctacctt
+ccaaagagccttacatatgttcctttattttcatctgtaacaccactattcctgtctaag
+cctacctatgtcatttttggaagagaatatagtcacctatgcgaccttcccacttaaaat
+cctactatttacgcttcagtaaaagaaaaaaaatttttaatctaagtatgtaattctttt
+gctgaagacacttcacttgcttctgtgcccttaaactggtatgttatcatggtatagtag
+gccatccaagacctggcttccttcctttttttcagtctcagagaataacatactctttcc
+ctgcaactccagatccaatttggttttcttttacttgcctggaaactccaaaatctatca
+actctggggctttccactagctaatcattttgtatacaatatttgtccttcATGTTTTGC
+CTCTTAACATCTCAGCTTTCAGTTTCATCATTTTACCAGGGAGGCCTCCCAGAACCTGAG
+TCCAGAAGAGTTCCTTCCATTGTATATTCCTCTAGCACTACCTATTACCTCTTTTGTAAG
+ACTAACAGCCCTCAAAATTTTTCATTCAGTGATGTCTTCCTCATTGCATTTTAAGTTCAA
+CATGAGCAGGACTTTGTCGTGTTCACCTCTATCACATCATAAATATAGCAAACAGTAAAA
+CTATTGCAACATGACTAATGTATTGAACGATGCTTCAGCTTTCTTCTTACGTTCAATCAC
+AGGTCATATGACTAAAGAACTTCCTTTTTAATCTCCTTTTCTATTCTCAATTAATTTCTT
+CTGCCTGCATCACCTCAAGTCTCTGGGGTGAAATCCACTAATGAATTCCTTTTGCAGCTT
+AAGCCAATTCCAATCTTGAGCCAATCTCAGGTGAAGAAGCCTGTAAATTATCACTCTCAG
+TCCTCTCTTGTACTACTAGGTCTCATGAACTCTTCATTAACAACTCCAGCTTCTCTGTTA
+GCCCAAAAGCCTTTTGCTGCCTAGAAAACCCATGATTCATGCCTCAGGAAACAGCCTTCA
+AATCACAACATGTTCTGTATCTGGCTGGCCAACTCCCTGCAACTTATTTCTGCCTAGATT
+CTCCCTCATTCATTTCAATACGCTGTTCGGCCTGCTACCCCAGTTTCCCACTTAGAACAA
+TGGCACACAGGACAGGAGCACATTGGCACATCAGAATGACTTATGTACTGCTCATTGTGT
+TGCAGAAGAGACCTCTGTGGGGGCAATAGAACAGATTTTCCTCTCACGTCACTGTAGTTG
+TGGTTTCCCTAAGCACCTACACTGTTTCACCTCATCTTAGGTAGACAATAATCCATGTAA
+CTGACTGTGTATCCTAATTTTAAAAAATATTTCTGCCCACATTATTCTGCAGTTTTTATC
+TTGCTTACGTATTTTTGGAATGTTACTATTTTTCAAAAATTAATTTGGGATCAACCAACA
+CTTCTTATTCTGCTGCTGTTCTAGAGAAAATCATTTTCCTCATTTCTGAACAAGAGAAAA
+TGAAATACAGCTCTAAACAAATGCCACTGTAAACCAAGGTGGAGCCTTTGCACTTTCAGG
+CCACCATGATAACCTGGAGATTAGATTTTTCTGTGTCTTTATATCAATAATAAAGCCAAG
+CTTCTCCAGGGGTATCCACTAGGCTTGTCTCAATGGCTCAATACAGGTCCTTTTGTGAAT
+GATTACCTCACCCTCATGGAAACACACTCTTGTTACAGAAACTCAGAATGATTCTATTTT
+TTCTTTTATATTTGTATATGTTTTTCCAATACCTCTGAAAAAACTGATCCAAAAAAAATA
+CAAATTTTAATTGTAGCCAGTCAATTCAGGAAGGATAAAGGTCAAAAACTTTCAAAGAAA
+CCTTCAGCCCCAACACACTAAACTTTGGGAGCACAGGTTGGCATCCAGAGGTAAACATTT
+GCTATAACTGATAACAGGAGAAGGATCCATTTATTCACCTGTTATCAATTACAGGCATTG
+TATTTAAAGATCAGATGTTTTATATTTATTTCTTCAAATTTCATTCATGGTGCCATAAGT
+GAAGGTATCTCTGTCCACCCTGAATATATTTTCACTCCCTCATCTCAGTCATTCCGAACA
+ATTCACACACTAAGATTACCCATGCTAAATGGGGATTCTTTTTTACTAGCCAATGTAGTA
+CCTCAAATCCTTCCTTCCCTCCCCCTATTTCATCAGCAGGCAATTCTTTTGATACTTTTG
+TCAAGGGGAAATTGTGTGACTCAGAGATCTAGTCCCCAAGAGAAACTAATAATGGGCTGG
+GTATTGTCTGTCTCAGCAGCATCAGTGGGTCCCTCTCCTGTGCAGCTAATTAGCTTCCTT
+TCCAATATGAAGAATCTTATATATAGCTTTGTCTTTGGGGTATTACATAAATGAAGATTA
+AGCTATCTGAATTTCTCCTTCTCCTAAAAATGCACATCCTATGACTGAAAAGACAGGTAA
+AAGAGATGCTTTTAATTACAAAACTTTCCCTGTCGTGGTTGCTTCTCTCTATCCTTCTAA
+ACTCCCTTTCAATTTCTTCTCTTCTGTAACATATTTGTGCCCAAAATCTTCTGCTTTCTG
+AAATATTTTATCTTTTTCTTCCACACTATCTCTTATTTTCCAATTTTAATCATTAAATTA
+TATTATGTCTTATAAAACTAATCCCACATATAAACCCCTATGATAATTTCAGTTTGTCCC
+TAGTATGAAGTTCTTTAAAGATGTGTAGTTTTCTAACTTTCATGCTCTCCAATTAATTAT
+AAACTTCATTTTCCACTCTGAAAAGGAGATGTCTGATCTCAGCTATTTCCATCCTATTTG
+AAAACCAGATTTAGTTTTAAACCAGAGGAAGGGAATCTCAAGTCTTTACCTCCCACAGTC
+TGGTGTGATTCTCTCTCTTTTGGTATTACCTTCCTCCACATTGGAACACTCCAGCCAATG
+CATAGGCTGAGAGGCTATCTCAGATTCAGAAAGATTTGGCCTCATCCCAGGGGAGGGTAC
+AGAGGAGCTGATGACTATGAATTCTGAAATGGAACTGTTCCAGGTTGAAGAAATAAGAAA
+GGGAATTGGGAAGAGCAATGCCCAGTGAAAAAGAAGAAATAATATTTTAGGAAGTGAATG
+CTAATTTTATTTTAAACAAAATAAGAACTCAAGGAATAAGAGGGTTCTTCCAATAGGTTA
+GAGTGATCCTGTCAAACATATATGCTTCTAGATTTTTTTAAAGACTGTTTCTACTAAGAA
+AGCATAGACCGCTATTGAGAAAGATCATTAAACTGGAATTTAGGAGGTCTGCCTTCTGAT
+TCTGACTTCTTGAATGTATTGTTAGCCATTTAACCACACTGTGTTGTTTCTCATTCTACC
+TGTAGAATCTCAAAGTTCTTTCCCACTTCTATACAAAACTATAATTCTGAACATCCTTTT
+TGTTTAATATAAGTCTGCATTTCCTGTTTGAAGATATGTGTCCCAGACCCTAAATGACTG
+ACAAATTTTAAATCTCCAATAGGAAAGATGACAAACTCTATGGAAACTTGGCTTCTGAAG
+AACTCCTAGAAGCTTTCCAAAGTCATCAGTGTTTCCTAAGAAGGCAGAGAAATCAAACAC
+ATGGTCTTTTCCTCCAGACAAGCTCCTTTGGGTCATCAGGATTTCTTCAACAATAAAATG
+TAATAATTCCAAATGTTTGTAACAGAATGGGTAGGACTTTCTTCACTTATTTAAATACTC
+CCTTTTTTATGCAACTGAGTTTTCATCAACAAGTACAAGCTTGTGAAGGAGTACTTTAAA
+ATGCAATTTCTCTCTATTTTTGTGGGGGCTAATATTTTATTTCTCATATTGACAATTTAT
+TATGCTGTTTTTAAAAAGttcattcatcaagtatttcttgagctttttctatgagacagg
+cactgttttaggcaagtaattatgcactgaacaatgcaaaaagtttccctgcactcatgg
+actttaattttaCATTTATGAAAAGCTACAAATATTAGAATAAGTAAAATACTGCCTGGA
+GGCTAAAGCATATTTTGATCACTTATTCCCTAATTCTTTTAGAAGAGAACTCACCTGTCG
+GTTAGCTGAACCACTGCCAGTGATATCCAACTATACATTCAATCCCACCATACCTCATTA
+TCACACCTATTCACTCACAAGCTTAAACTCTTAACTTTTCTCCACATATCAGTGACTATT
+TCCTACAGCTTTTCTTTTACTTTCCATGTTTGCAGTGACAATATACATAAACAGTGTATG
+AAAACTCAAGTAAAATCTACTCTCTCAGGTGTTCATAATGTATCAATGTATATTGCTTTA
+AGCCTGAAGGTAACCTAAGTAAAGATGTACCATGTTCCACCAATGCTTCTTTTGATCATC
+ATTTTATCCTGTTTTTTCTTTAGGATTCTTTCTTATTCCTTCCCCTGACCCTTCTTTTAT
+TCTCCAAATTTCTTTCCAATTCATCTTTGTTCTTCCCTTTCCTTTTTACTCTCTTTAAAC
+ATTCTATGGACTCTGCCTCCTTCACACTGATATTGAACGCCCATAGTTTCATATTTTGGA
+TTGCGATTGTTTTATTTTAAAATGGCAAATGTTCATGTTATAAAGAGAATTTTTCAGTCT
+TTAGACTAATAGGTTCATGTAGTTTGGGATTTTCCTCTTTAAGAAAATTAATTATCACTC
+ACACTCCAAGACAAACACCATTTCAGTAGCAATATGAATTTCAGTAGTAATAGGAATCTC
+CAAATATGACAAAGTAATTCAGACATTAATTGCTTTTGTTTTGGAATTGCTCTTATAAGA
+TGAAATATCACTTTCATGATGAGAGTCCTAGAGTGCTTGGTTTATATATTGTATCTTAGT
+TTTAACAGGATAAAACACTTGATCCTAAGCAGTAAACATGATTCTTCAGCTTCAACTTCA
+TTTCTTTATAAATAACTATTTATGAATTGGTGTTGAGCTTAGTAAGTCACCAAACACCTT
+CTGCTCAGCAGCATAAAGGACATTTCCATGAAACCTCCCAGGGATAATCTTATTTACTCT
+ATAATGTTTCCCGGGTTCAATTCCTCTCCCAAAATTCTTTGTTCTTAAGCCCCTATGATC
+TGGGTGATCTAAATATGGGTAAGAAGTCCAGGGATAGCACTATGAATGAAGTGAAAATAG
+TAAAACATAGTTAAAAATGTAcagatgctctctgacttataatagggttacgtcctgata
+aatccatcataagtcaaaaatgcatttaatattcctaatgtacctcacatcatagtttgg
+cctagcctaccttaaatgtgctcagaacactttcattagcttatataagatcacctaata
+caaagcctattttataataaaatattgaatagctcacgtaatatactgactactatactc
+aagtacagtttcttctgaatgcatgtcactttctcaccattgtaaagtcaaacaattata
+agtcaaactatcacaagccagggaccatcCATATGTATTTCATTCAGAAAATGCTGGAAA
+GAGCATTTCGGAGAATATCTAGATGAGAGAAGGTAGAAAGCCATGCACAAATTCACTGAG
+AGTTTAAAAAAATACATGCATATTGTGGAGATAGAAATCAAATCTATTTGTCTCCATCTG
+CTGTATTCTTCCCAAAATATTATCTCTTCTTATCCCATTGTACTATATTGCATTTCTTTG
+ACCATTTATTGTGTATCTCTTAATATTTCCCACTTCATCATTACTAACCTCACTCACTCT
+GAACTTGATGAGAGCACCTGAGCATTAATTTTTCTTATAATTATTTAATGATTACCAGAA
+TTCGTTCAGTATGGCCAGCTCTGGTCAAAGTGAGGCAGGCAAGATGCTTTGTCAACTGCC
+TGGATGGAATGTCTCAAAAGGTTTCCATTTCATGGTAGCATTATGCAAAGTTCAAGACGT
+TTAATCAAGACCCTTCACTTACTTAACTATACCTCCTTGAGAATCCCATCTATGAAAAAA
+TTCTAGTCATTATAAAAATGATTGATTAAATGAGGGAAGTAGTAGAGTTCTTCATTTCTT
+TAGTTGGTTTAGTCTCCTATGAGTCAATCCTATTTTCAAAATTCTTAATAAACCATTTAT
+TCCTTCAACTTTCTATGCCATTTGATGTTTTGTAAAAAAAAAAATATAATATGTATACAA
+AAAGATATTTCAAAATCTAGAAAGAGAGCTTTAGAGCTTTGTAAAGCTCTTTTAAAAATC
+AAAAACAACTACTGTTAATTAACATGTTGTACTATGCAATTTGTTTACCATTATTACTCT
+TGGTATTTTTAAGAAAAGTCTTTCCATTGTTATTATAAATGCTTCTATTGATATTTATTT
+TAATAACTGTTATTACAGTCCGTCATGTACATACACTATACTTAAACCTAATGTTTGGTA
+TTTAAATCGTTTCAAGATTTTATCACTGTCAACAAAGTATGATGAATATTTTTATGCTGA
+AAACTTCTGTAAAAatagaattccaagagtattattgcaccaaaaggcatggacttaaaa
+ttcttgatacatgatttcaaaatattttctttaaggtttgaatcagtctatattccctcc
+agcagcgtataaaagtgccaatttctctgatccttaGCCAGTTTGGGTAATAATAATTGT
+AAAACttttttttctttttttttgagacagagtctccctctgtcgccaggctgaagtgca
+gtggcgcaatctcggctcactgcaacctccgcctcccggggtcaagctattctcctgcct
+cagcctcccaagtagctgggactacaggcatgcaccaccatgcccagctaatttttgtta
+tttttagtagagatggagtttccccatgttggacaggatggtctcgatctcttgacctcg
+tgatccaccctcctcggcctcccaaagtgctgggataacaggcgtgaacaaccatgcccg
+gccTGTAAAACTTTTTCCTAATTTAACAGAAAAATAATAGTATTATATTTTATCATATTT
+CTTTGATTTCTAAGacacacatacacacacacacacacaTATCTGTATATACAAATACAC
+GTATAGCTTACATTTTAATTCTTCATTTCATTTGTTCATTTATTAGGTCTTGGAGATTTT
+GTGAAACTGTTTAAATTCTTTTTTATACTATGAAGATATCAACCTTTTGTCTCTACAGCA
+TTTCAAATTCAAGTATGATTCACGTGTTGGTTTGGGGTAGATCATTATAGGCACATGTAG
+GAAACAGCTTTCAGAGATGCCTTAACCGTAATTATGCATTTGTATTCTAATTTTTATTTA
+ATGTTATTATTGATTGCATTTTTAAAGATTCTGTATTTTTTAAACCATTTATTTGTATAT
+GTTGGTATACAATCTTGCCATTTTCTGGGATTTCATATTTCCTTATTTTTGTTTTTTACC
+TTTTTTGGCTTGAATTTTTTGAGTTTTTATGCATTCTTTTCCAGTTTCTTAAGATGCTAA
+TAAGTTCATGTATTTGAGCAATTGAGAACATTTAAAGCAATAGACTGCCTCTGAGCACAG
+CTTTGTCCATATTACATTAACCTTTTATACCCTGGGTTCCCACTAGTTTTTAAATAATCT
+ACTATCAAATAAAAGATTTGTTAATAATAAATTTTAAATCATTAACACTTAACGCATTAT
+TTTCAGTCACACTAAGTTGATTCCTTCGTTTCTTTCAGGTTGCTTCAGAGTCTTCCCTTC
+TATCTGATTCAGTGGACCAAGTAAATGACTCTCTGGTAACAGAATTTGTATTACTTGGAC
+TTGCACAATCCTTGGAAATGCAGTTTTTCCTTTTTCTCTTCTTCTCTTTATTCTATGTGG
+GAATTATCCTGGGAAAACTCTTCATTGTGTTCACAGTGATCTTTGATCCTCACTTACACT
+CCCCCATGTATATTCTGCTGGCCAACCTATCGCTCATTGACTTGAGCCTTTCATCTACCA
+CAGTTCCTAGGTTGATCTACGATCTTTTTACTGATTGTAAAGTTATTTCCTTCCATAATT
+GCATGATACAAAAGTTCTTTATCCATGTTATGGGAGGAGTTGAAATGGTGCTGCTGATAG
+TCATGGCATATGATAGGTACACTGCGATCTGCAAGCCTCTCCACTATCCAACTATTATGA
+ATCCCAAAATGTGCATGTTTTTGGTAGCAGCAGCTTGGGTCATTGGGGTGATTCATGCTA
+TGTCTCAGTTTGTTTTTGTCATAAATTTACCCTTCTGTGGCCCTAATAATGTGGGGAGCT
+TTTATTGTGATTTTCCTCGGGTTATTAAACTTGCATGCATGGACACTTATGGGCTAGAAT
+TTGTGGTCACTGCCAACAGTGGATTCATATCGATGGGCACCTTCTTTTTCTTAATTGTAT
+CATACATTTTTATTCTGGTCACTGTCCAACGACATTCCTCAAATGATTTATCCAAAGCAT
+TCTTCACTTCGTCGGCTCACATCACCGTAGTGGTTTTGTTTTTTGCTCCATGCATGTTTC
+TCTACGTGTGGCCTTTCCCTACTAAGTCATTGGATAAATTTTTTGCCATCATGAACTTTG
+TTGTCACCCCTGTCGTAAATCCTGCCATCTATACTTTAAGGAACAAAGATATGAAGTTTG
+CAATGAGAAGGCTGAATCAACATATTTTAAATTCTATGGAGACGACATAACACATTTGGT
+TGATGAGAGCACAGGATAAATGCCATGGACCATCAAGACTCCTGTGATCACCATGATCAC
+TATGGAACGCGCACATTTTTAGTATTGCCTGAAAAAACTGAAAAATCTGCAAAAAGGATG
+CATTAAATCTAAGAATTGTATTTCAGATAAAGTTGCAACATTTTTTGTTAATCATAAAAA
+GTATATATTTCTATCTAATGTGTGTATCTAATTAACAGCAATGACTACCTTTAATTTTGA
+TGTAGTTATTTTATATCTGTATATAAGCACATACACATATATATGACCTAGGTTTATTTA
+TCAGTATTTTTATGCTGATAATAAGCATCACTGGAAATTAATTTTCTTATGGAAATTATG
+TGGATCCAATGGATAAAATATGAGTTTATATAAATTAGTAAATGCCAAAATCAAGGAAGA
+AACAATTTTTATTTTAATTGTACTTTAAGTTAGATAAATGGTAAGGTCAACAGCTTGTTA
+CAACCCTTAAGTATTATTTTCAGGCTGATTGTCAATATGTTTTGTACAatgttctcactt
+ataggtgggaattgaacaatgagaacacatggacacaggaaggggaacatcacacaccgg
+ggcctgttgtggggtggggggaagggggagggatagcattaggagatataactagtgtta
+aatgacgagttaatgggtgcagcacacccacatggcacatgtatacatatgtaactaacc
+tgcacattgtgcacatgtaccctagaacttaaagtataataaaaaaaaaTAGACTCTAGT
+ACTCTGTATTATGCAAAATTTGTCTATGTTACACTTTTTTAACAACACAATCCTATTGCC
+CTTGAAATCTTCTTCAAAGCATTTCTCGAGTCACTCTTAAAAAGCATCTACAACCTAAAA
+GTATAGGAAGAGATTTATTTCCTGGAGAAGAGACCCCATTGAGATCTTAAAAGCACATTT
+AATGTGCCTGTGCTTAACTTAAGGTGCTTAGGACAAAGAAGGCGATTGACATCTTTCAGG
+TAAAACCTGGTAAGTTTGGTGGTCAAGGAACACAACTGAGACATCACTTGGATGTATTCC
+TATGACTATTTTAAGAAACATAAATTGTGGTGACTCACTCAGCTCACTTTTAACTACTGC
+ATGGTAATTAAAGATGCAAAATAAAATAAGTTACAAGAAGTGAGGTTTTTTATTGGTTAA
+AGCAATTTTTCTATATTTTCTCCGCAAGTTGGTCATAAAAGTTCTAAGCATTCCTCTTTT
+TATAAAATCGAAGCATTATTACTTACTCTCTTGTTAACCTATCTGGATTTTAATTTTGTA
+ACTTTATTATATTTGTTTTGCTGTGATTCTTTAAAAAGCACCTTTAGACTCAGTGAGATA
+GCAAAAATATCCAAATAGGCCAAAAAATTGTGGCAATGTCCTCTCACTCAGGAAAATTCT
+GTGTGTTTTCTCTAATGGCCAAGGGAAAACTTGTGAGACTATAAAAGTTAGTCTCAGTAC
+ACAAAGCTCAGACTGGCTATTCCCAGATCTCTTCAGGTACATCTAGTCCATTCATAAAGG
+GCTTTTAATTAACCAAGTGGTTTACTAAAAAGGACAATTCACTACATATTATTCTCTTAC
+AGTTTTTATGCCTCATTCTGTGAAAATTGCTGTAGTCTCTTCCAGTTATGAAGAAGGTAG
+GTGGAAACAAAGACAAAACACATATATTAGAAGAATGAATGAAATTGTAGCATTTTATTG
+ACAATGAGATGGTTCTATTAGTAGGAATCTATTCTGCATAATTCCATTTTGTGTTTACCT
+TCTGGAAAAATGAAAGGATTCTGTATGGTTAACTTAAATACTTAGAGAAATTAATATGAA
+TAATGTTAGCAAGAATAACCCTTGTTATAAGTATTATGCTGGCAACAATTGTCGAGTCCT
+CCTCCTCACTCTTCTGGGCTAATTTGTTCTTTTCTCCCCATTTAATAGTCCTTTTCCCCA
+TCTTTCCCCAGGTCCGGTGTTTTCTTACCCACCTCCTTCCCTCCTTTTTATAATACCAGT
+GAAACTTGGTTTGGAGCATTTCTTTCACATAAAGGTACAaatcatactgctagagttgtg
+aggatttttacagcttttgaaagaataaactcattttaaaaacaggaaagctaaggccca
+gagatttttaaatgatattcccatgatcacactgtgaatttgtgccagaacccaaatgcc
+tactcccatctcactgaGACTTACTATAAGGACATAAGGCatttatatatatatatatta
+tatatactatatatttatatatattacatattatatatataatatatattatataatata
+tattatattatataatatataatataaatataatataaattatattatataatatataat
+ataaatataatataaattatataaatataatatatattttattatataatataatatata
+ttatataaatataatatataaattatataatataatatatattatataatataatatatt
+ttattatataaatatatattatattatataatatatattttattatataatatatattat
+atatttatagaatataatatatattttattatataatatatattatataatatatattat
+atttatatataacatatattattatataaaatatgtataatatatattatataaatatat
+ttatatattatataaatatatatattatatataatTCTAATGGTTGAATTCCAAGAATAA
+TCTATGGCATGAAAGATTTTACCTGTCAACAGTGGCTGGCTCTTCATGGTTGCTACAATG
+AGTGTGTAAGATTCTGAAGGACTCCTTTAATAAGCCTAAACTTAATGTTCAACTTAGAAT
+AAATACAATTCTTCTAATTTTTTTTGAATAATTTTTAAAAAGTCAGAAATGAGCTTTGAA
+AGAATTATGGTGGTGAAGGATCCCCTCAGCAGCACAAATTCAGGAGAGAGATGTCTTAAC
+TACGTTAGCAAGAAATTCCTTTTGCTAAAGAATAGCATTCCTGAATTCTTACTAACAGCC
+ATGATAGAAAGTCTTTTGCTACAGATGAGAACCCTCGGGTCAACCTCATCCTTGGCATAT
+TTCATGTGAAGATATAACTTCAAGATTGTCCTTGCCTATCAATGAAATGAATTAATTTTA
+TGTCAATGCATATTTAAGGTCTATTCTAAATTGCACACTTTGATTCAAAAGAAACAGTCC
+AACCAACCAGTCAGGACAGAAATTATCTCACAATAAAAATCCTATCGTTTGTACTGTCAA
+TGATTAGTATGATTATATTTATTACCGTGCTAAGCAGAAGAGAAATGAAGTGAATGTTCA
+TGATTTATTCCACTATTAGACTTCTCTTTATTCTTAAAAATATTTAAGATCACTAAATTT
+TTATAGGACTTTAAAAACAGTAATGTGCTGCTTTGAGTGTGTAGGACTAAGAAATGGGAT
+TCAGAGTAGTAAAGAGAAAAGTGGAATTTCCAAGCACTATGAATTACTGTTCTTTAAAAA
+ACAGCAAAAATCAAATAACAGTATTCCTCCAAAAAAGATGGCAAGTGTAAACTCTATACC
+TTCATGTCTCCCGTGGAATGTTAGTGATCAATTTCCACTTCTCTCTTTTACATCTTACTT
+GCCCATTAACTCTTATACCTAATCCAAAGATTGTTAATATGGCTATGTCTCACTTTCAGG
+ACACCTTTTATTTGTTACTTCTCTTCACTGCAAAACTTCTTGAAACAGTACTTATTTTCT
+CTCCTCCATACACAATTGAAATGGCTCTCAACTCATGCCCAGAAGTCAGTGTTCAGTCTC
+TCACCTGGCAGATAGCAACTTACAAAGATGCCCCAACAATACCTCCTTGTGTCTAGACAG
+TCATCATTATCCTTTACCTTTTTCTGTATTTATTTCTGCTCCTAAAAGGGATCTCTATGT
+AAAGTATTGTTATACTAGTGCTTGTTATAATTATTATCAGAGTTAAAGCCATCACAATGT
+TCCCAATTACTTAAAGACATTGGAATAACATTTTTTTTATTTTCCACATCTTGCCAAAAA
+ATATTTTGTTATCAGTACCTTaataatggctattatatattgaccattactatttgctag
+aaaatttatatacctggtcgtatccaatcctcacagaacttctataaagttgtgctatta
+tcacctatattttccagatgtggccgtaagactgaaatcacttaggtgacttgtctaagg
+tcattcagatacatagtagataacccaggatttgaacacaggcctcctagcacacaagct
+catatcttaactactttaatacgttgctcGATGGGATCTTACAGGTCTTCATTCACCCCT
+TTCCTGCTCACACAACCACAACCTGCAGCTATTACCTATTGTTAGGCTTAAAATAATTAC
+TTGGCTTCATTTCCAAGCTCCCTCCCTTCCAATTCACATTGAGTCCAGAGCTAAATTAAA
+CAATCATTCAAAATTTTTCAGTAGTTCTTGTCTCTATAATAAAACAGAAATGCTTTAGAA
+AGCATTCCAAAATCTCTTACCAGTTTTATCTCCTATGAAAGTCCTTCACactttctctca
+tttaaactttattgcattttcctcactttttctcacttcacttttgaattccctattctt
+ttatcctctgttaatttttaagtattatatttgtgatattattttttctttttttctatt
+ttttatctttcatttcattttggcctatttttttctcttAAGAACTTTAATATCACCAAA
+TAACATGTGTGCTACAAACTGTTTTGTAGTTCAAAGAAAAAGGAGATAAACATAGAGTTA
+TGGCATAGACTTAATCTGGCAGAGAGACAAGCATAAATAATGGTATTTTATATTAGGAAT
+AAACCTAACATTAATGGAGACACTGAGAAGCCGAGATAACTGAATTATAAGGCATAGCCA
+GGGAAGTAGTGCGAGATAGAATTATGATCTTGTTGAATTCTGAATGTCTTTAAGTAATAG
+ATTATAGAAAGTCACTGTAAGAGTGAGCAGAATGATATAAAATGAGGCTTTGAATTTGAA
+TATAATAATTCTGACTTCCTTCTCCTTCTCTTCTTCAAGGTAACTGCAGAGGCTATTTCC
+TGGAATGAATCAACGAGTGAAACGAATAACTCTATGGTGACTGAATTCATTTTTCTGGGT
+CTCTCTGATTCTCAGGAACTCCAGACCTTCCTATTTATGTTGTTTTTTGTATTCTATGGA
+GGAATCGTGTTTGGAAACCTTCTTATTGTCATAACAGTGGTATCTGACTCCCACCTTCAC
+TCTCCCATGTACTTCCTGCTAGCCAACCTCTCACTCATTGATCTGTCTCTGTCTTCAGTC
+ACAGCCCCCAAGATGATTACTGACTTTTTCAGCCAGCGCAAAGTCATCTCTTTCAAGGGC
+TGCCTTGTTCAGATATTTCTCCTTCACTTCTTTGGTGGGAGTGAGATGGTGATCCTCATA
+GCCATGGGCTTTGACAGATATATAGCAATATGCAAGCCCCTACACTACACTACAATTATG
+TGTGGCAACGCATGTGTCGGCATTATGGCTGTCACATGGGGAATTGGCTTTCTCCATTCG
+GTGAGCCAGTTGGCGTTTGCCGTGCACTTACTCTTCTGTGGTCCCAATGAGGTCGATAGT
+TTTTATTGTGACCTTCCTAGGGTAATCAAACTTGCCTGTACAGATACCTACAGGCTAGAT
+ATTATGGTCATTGCTAACAGTGGTGTGCTCACTGTGTGTTCTTTTGTTCTTCTAATCATC
+TCATACACTATCATCCTAATGACCATCCAGCATCGCCCTTTAGATAAGTCGTCCAAAGCT
+CTGTCCACTTTGACTGCTCACATTACAGTAGTTCTTTTGTTCTTTGGACCATGTGTCTTT
+ATTTATGCCTGGCCATTCCCCATCAAGTCATTAGATAAATTCCTTGCTGTATTTTATTCT
+GTGATCACCCCTCTCTTGAACCCAATTATATACACACTGAGGAACAAAGACATGAAGACG
+GCAATAAGACAGCTGAGAAAATGGGATGCACATTCTAGTGTAAAGTTTTAGATCTTATAT
+AACTGTGAGATTAATCTCAGATAATGACACAAAATATAGTGAAGTTGGTAAGTTATTTAG
+TAAAGCTCATGAAAATTGTGCCCTCCATTCCCATATAATTTAGTAATTGTCTAGGAACTT
+CCACATACATTGCCTCAATTTATCTTTCAACAACTTGTGTGTTATATTTTGGAATACAGA
+TACAAAGTTATTATGCTTTCAAAATATTCTTTTGCTAATTCTTAGAACAAAGAAAGGCAT
+AAATATATTAGTATTTGTGTACACCTGTTCCTTCCTGTGTGACCCTAAGTTTAGTAGAAG
+AAAGGAGAGAAAATATAGCCTAGCttataaatttaaaaaaaaatttatttGGTCCATTTT
+GTGAAAAACATAAAAAAAGAACTGTCACATCTTAATTTAAAAAATATATGCTTAGTGGTA
+AGGAGATATATGTCAACTTTTAAGAGGTTGAAAAACAAACGCCTCCCATTATAAGTTTAT
+ACTTCACCTCCCACCACTATAACAACCCAGAATCCATGAGGGCATTATCAGGAGTGAGTG
+GAAGAGTAAGTTTGCCAATGTGAAATGTGCCTTCTAGGTCCTAGACGTCTGTGGTATAAC
+TGCTCATAAGCAGTAGAAAGAATTTAGAGGGATCCAGGCTCTCATCACGTTGGCACAAAG
+TATATTACTTGGATCCATCTATGTCATTTTCCATGGTTAATGTTTaaaagcacaggcttt
+aaagtaaaaaacaaagagctggattcaactctactgactcttattaatcatgattttggg
+cacattacgtagctttcatgagctttagtttctacatttataaacaggagattataccta
+ttatgcatggttattatgaaggaaaatgacaaaatagatataaatcaaatagcccacttc
+gagacatattaagcatgaataaacattagatactattaAAATCCTATATATTAACAAAGC
+CAAAAGTTTCAAACTTTACTTTTTCCCAACATTCTTGTGAAATATGACACATCCCAATCT
+TAACAGATGCTCATTTGGGATACTGTACTTGTGAGTGGAAGTGTGTATATTTGTGTGCAA
+GTGTGTACTCATATACTTCCACCTTACCACCCTAGAAAGGCATGATGAAAATTTAAGATA
+GAAGGAAAATATAAATTGAAAAAAAAAAACCTTAACAAATGATTCTGACAAATATCTTCT
+CTTTCCAGGGAGAATCACTGAGCCAGAATAAAATTGAACACTAAATATTCTAAGAAAAAA
+GGAATCTAGTTTGTCAAAATGTGACTTGAATTAATAGATAAGGAGAGTCAGATGATAAGA
+GGGTCAAAATTATGTTTATCTTAGGAAAAGTAGAATAGAAAATTTATAAGCAGATTAAAA
+ACACATAATAAAAGTAGTAAATAATAATGACAGTATCTCAAATcagtgcaggggggaaag
+gcctactaatgtgatggtgggataattggatagcaatatgggaaaagatatatttaattt
+atttgctacaccaaatgccaggacaatctctaagtgaattcaagacataactcttttttc
+aaaaaaactatgcaaatattaaaagaaaacaagttaatgtttttataatctatgaatatg
+gtaaagatGGATAACATTGACTATCAAATTAATTTTTAATGCGTAATAAAACTATGAGAA
+AATTTAAAAGTGAGAAGAAACTACTTGTAACTCACATAATAGActagtacttctaacaca
+tagggaacttctaaaacaaaacccaaaatattaataggaaaatgggcaaaacagttaaac
+ttacagttcataCATAAGGAGAATCAGTCTTTTTTTTTTTTTTTACAGTTGTAGGCAGAA
+AACTTTTATTTTTCATTTATTTGTAAAATTTACCCCTAATTTATTCATAATTCATTTAAC
+TGCTAAGGGCATTAATGTGTACAACGCCATGGGAGAAACCAGTATATTCAGAATTTCTCC
+TGAAATTTGACCAGAAGTTATGGGCATCCCTCCCCTGGGAAGGAGGCAGGCAGAAAAGTT
+TGGAATCTATGTAGTAAAATATGTTACTCTTTtatatatatacatatatgtgtgtatatg
+tgtatatatatatacacacatatatacatacatacatacatacatatTATCTGAATTAGG
+CCTGGTCttttttaatactttaagttctgggatacatgtgcagaatgtacaggtttgtta
+cacaggtatacacctgccatggttgtttgctgcacccatcaactcaccatctacattagg
+tatttctcctaacgttatccctctccttgcctcccacctcccgacaggccctggtgtgtg
+atattcccttccctgtgcccatatgttctcattggtcaactcccatttatgagtgagaac
+atgcggtgtttggttttctgttcttgtgttagtttgcggagaatgatggtttccagcttc
+atccatgtccctgcaaaggacatgaactcattcttttttatggctgcaagaaatgcaaat
+caaaaccacaatgagatgccatctcacaccagttagaatggcaatcattaaaaagtcagg
+aaacaatagatgctggagaggatgtggagaaataggaatgcttttacactgttggtggga
+gcgtacattagttcaaccattgtggaagacagtgtggtgtttcctcaaggatctaaaact
+agaaataccatttgacccagcaatcccattactgggtatatacccaaacgattgtaagtc
+attctactacaaagacacatgcacaggtatgtttattgcagcactattcacaatagggaa
+gacttggaaccaacccaaatgcccgtcaatgttagactagataaaatgtggcacatagac
+CTGGTCTTAAAATCAAGAACAGAGATTGTTACTTTTACATCCATTCCTAATTGATAAACC
+ATTCAGTTATACCACATCTTAGCTTCTGGACTACAATGACCATATTTGGGGttttctttc
+taatttcattataggttcagagggtacatgtgcaggtttgagacaaaggtatattgcatg
+atactaaggtttggagtacaaatgattccacctcccaggtagcaagaataatacccaata
+tgtagtttttcaactctttcccctcttcctccatcctccctctgctactctgtggtgtct
+gtttttctcatctttatgtccatgtgtactcgatgtttagctcccccttgttaggtgaga
+acatgtggtatttggttttctgtttcagtgttaattcacttaggataatggcctccaact
+gcattcatgctgctgcaaaggatgtgactttcttcttattagctgcatatattttgtggt
+ggatttgtaccacatttactttatctagtccaaagttgttgggcacccaggtggattcca
+tgtctttgctattgtgaatagcactgggacaacccatacaagttcatgtgtctttttggt
+aaaacaatgtattttcctttgggcatatatgcggtgatggaattgctggatcgagtggta
+gtttaactcttagttctttgagaaatccccagactgttctccacagtggctggactaagt
+tgcattcccaccagcagtgtagaagtgttccccattctctgtagcctcaccagcacatgt
+tAAACTATCTttaaatatatgaaaaaaatgttcaagtctctcagattaagatgcatgcaa
+agtaaaatgatacttaaatatcagttctaacctataaaatatcaaatatctgacctcaat
+atttgataatccaacctgttgatgaagctgtagagagaggcaccctTtttttttttttta
+attatactttaagttttagggtacatgtgcaccttgtgcaggttagttacatatgtatac
+atgtgccatgctggtgcgctgaacccactaactcgtcatctagcattaggtatatctccc
+aatgctatccctcccccctccccccaccccacaacagtccccagagtgtgatattcccct
+tcctgtgtccatgtgatctcattgttcacttcccacctatgagtgagaatatgcggtgtt
+tggttttttgttcttgcgatagtttactgagaatgatgatttccagtttcatccatgtcc
+ctacaaaggacatgaactcatcattttttatggctgcatagtattccatggtgtatatgt
+gccacattttcttaatccagtctatcattgttggacatttgggttggttccaagtctttg
+ctattgtgaataatgccgcaataaacatacgtgtgcatgtgtctttatagcagcatgatt
+tatagtcctttgggtatatacccagtaatgggatggctgggtcaaatggtatttccagtt
+cgagatccctgaggaatcgccacactgacttccacaatggttgaactagtttacagtccc
+accaacagtgtaaaagtgttcctatttctccacatcctctccagcacctgttgtttcctg
+actttttaatgattgccattctaactggtgtgagatgatatctcattgtggttttgattt
+gcatttctctgatggccagtgatgatgagcattttttcatgtgttttttggctgcataga
+tgtcttcttttgagaagtgtctgttcatgtccttcgcccacttgttgatggggttgtttg
+tttttttcttgtaaatttgtttgagttcattgtagattctggatattagccctttgtcag
+atgagtaggttgcaaaaattttctcccattttctgggttgcctgttcactctgatggtag
+tttcttttgctgtgcagaagctctttagtttaattagatcccatttgtcaattttgtctt
+ttgttgccattgcttttgTCccaccgatcccacagaaatacaaactaccatcagagaata
+ctacaaacacctctacgcaaataaactagaaaatctagaagaaatggataaattcctgga
+cacatacactctcccaagcctaaaccaggaagaagttgaatctctgaatagaccaataac
+agaagctgaaattgtggcaataatcaatagcttaccaaccaaaaagagtccaggaccaga
+tggattcacagccgaattctaccagaggtacaaggaggaactggtaccattccttctgaa
+actattccaatcaatagaaaaagagggagtcctccctaactcattttatgaggccagcat
+cattctgataccaaagccaggcagagacacaacaaaaaaagagaattttagaccaatatc
+cttgatgaacattgatgcaaaaatcctcaataaaatactggcaaaacgaatccagcagca
+catcaaaaagcttatccaccaagatcaagtgggcttcatccctgggatgcaaggctggtt
+caatatacgcaaatcaataaatgtaatccagcatataaacagagccaaagacaaaaacca
+catgattatctcaatagatgcagaaaaggcctttgacaaaattcaacaacccttcatgct
+aaaaactctcaataaattaggtattgatgggacgtatttcaaaataataagagctatcta
+tgacaaacccacagccaatatcatactgaatgggcaaaaactggaagcattccctttgaa
+aactggcacaagacagggatgccctctctcaccactcctattcaacatagtgttggaagt
+tctggccagggcaattaggcaggagaaggaaataaagggtattcagttaggaaaagagga
+agtcaaattgtccctgtttgcagacgacatgattgtatatctagaaaaccccattgtctc
+agcccaaaatcttcctaagctgataagcaacttcagcaaagtctcaggatacaaaatcaa
+tgtacaaaaatcacaagcattcttatacaccaacaacagacaaacagagagccaaaccat
+gagtgaactcccattcacaattgtttcaaagagaataaaatacctaggaatccaacttac
+aagggacgtgaaggacctcttcaaggagaactacaaatcactgctcaaggaaataaaaga
+ggatacaaagaaatggaagaacattccatgctcatgggtaggaagaatcaatatcgtgaa
+aatggccatactgcccaaggtaatttacagattcaatgccatccccatcaagctaccaat
+gactttcttcacagaattggaaaaaactactttaaagttcatatggaaccaaaaaagagc
+ctgcattgccaagtcaatcctaagccaaaagaacaaagctggaggcatcacgctacctga
+cttcaaactatacgacaaggctacagtaaccaaaacagcatggtactggtaccaaaacag
+agatatagatcaatggaacagaacagagccctcagaaataatgccgcatatctacaacta
+tctgatctttgacaaacctgagaaaaacaagcaatggggaaaggattccctatttaataa
+atggtgctgggaaaactggctagccatatgtagaaagctgaaactggatcccttccttac
+accttatacaaaaatcaattcaagatggattaaagacttaaacgttagacctcaaaccat
+aaaaaccctagaagaaaacctaggctttaccattcaggacataggcatgggcaaggactt
+catgtctaaaacaccgagagaggcactcttatgcattgttggtgagaatacaaaatggta
+caactcttggcaatatcttaaaaaatttacatggtactgacttttggtctagcaatccta
+cttctatcctaaagatatattggcaaaaatacaaaataattgatgcactcaagtctattc
+attgaagcattgtttttcatagtaaacggaaagtaggccgggcgtggtggctcatgcctg
+tgatcccagcattttgggaggctgaggcgggcagatcacttgaggccaggaattcaagac
+cagcgtggctaacatggcgaaaccccatctctaccaaaaatacaaaaattagctgggcgt
+ggtggtgcacacttgtaattccagctacttgagaggctgaggtgggaggatcgcttgaac
+ctgggaggcagaagtttcagtgagcccagaacgtgcctctgcactccagccaggatgaca
+gagcaagactccatctcaaaaaaaaaaaaaaaaaaaaaggaaaataaccaaatgacaatt
+agtgagtactacttgcaaaacttgtacgcaatagagtatgaagcaactataaaatgagag
+agaaatatctccaaatactactctaaagtaatctacaaggtataccttaactgaaaagaa
+acaaaaaagtgacaccagaatgctatttttatgttaaaacagggataaataCATTGGATT
+TACATGCatatataagtatatattttataaatgtttaaataaGCATACTTAAAATGGCAA
+AAACGTAATACATATATAATTTTCTTATGGCAGGAGGAGGAAACAGGGCAAGGCACAGGG
+ATAAAAGTTATTCTGAATACATCTTATTTTATATTTTTGACTTTGAAATCCTGTAGCTGT
+TTTATGTAATATAAAAATGTAATTAAATTAACAGAAAAAAATTACAACTGCTAAAAATCA
+AGATCTGGCATTTTAATTAAGTTATAAAACATCGGAGAAAAGAATTGTTTCATGGGACAC
+TAACATACAGACAAATTCATTTGGAACCCAATGAATTAATGGGCCTAAGATAACAACCAA
+TAGAAGCTAAAATGACGAATAACTGTTTCAGAAGAAAACATATATGGAATGAATCAGCTG
+AAAATACCTGAACCTACTGATCAATTTTTATATCACATGAAGTGAATACACATAAAGTAT
+AATATGGAGCACATAGAACCAACTAGAAATGAGCCTAATTGTTAAATATTCTCTATTTTA
+TGAcaatatacaggaaatatgtcgaagagagaaacatgcaagaacaccgtagggtttaat
+aagataatcacaaggtatggaatattcaacaggatgagtatcctggattattcagcaaat
+acacagagctaaaaagcaggagaaaggaattcatatatatttttaaaaactaaaaagata
+tattagctgatgcaactttgaaacttctttagatcctgattcaaatagagcaaatttaac
+aaatatatttgaaactattaaaataatttaaaaatgaccaagtatttgattatatcaaat
+atagacaataataaccttgaatgtacatggattaaatgtccacttaGGggctgggtgtgg
+tggctcatgactataattccagcactttgggaggccaaggcagaaggattgcttgaggtc
+agaggttcaagtgcagcctggtcaacacagtgaaaccctatctctacaaaaaacaaacaa
+aaataaaaaaTTAACtaattttaaaaaatatatatttCTTCtaaattctccacctgaaag
+atatagactgactgaatgaattttaactatgatctgactatgtgcttccctgaacaaatg
+cactttacctgtaaaacacatattaactaaaagaaaagagatggaaaaaggtattccatg
+aacagaaaccaaaatgagtaggagtagctatacttctgtcagacaaaacagactttaagt
+caaaactagctttagaaaaaagacaaaaatgcttattatacaacgataaaggaatcaatc
+cagaaagaggatataacaattttaaatatatatgcagccaacactggagcagccagattc
+ataaagcaaatactactagatcaaaacagagaggtagactcaaatataataatagtgaag
+gacttcaacaccccactttcagcattaaacagatcatctaataagaaaaccaatctcgca
+gccctcaccctggagagtccacaggtaccaggggttggtctgaacccccagcacagagca
+cctgcctcacagaagagtggctgcatttttcttcctgcagttttcagtcctcacttctcc
+ttaccaagcagggccacctggcctgggactccggtacaactaccctgccccccacctgac
+gacttcaataagaagtagcccagcatttctccaaggaggaaataccagagtcaattcaca
+accactgcaattgcagtggtaccaccataacagcccttgggctgcagaaggaactaagag
+tctagtcactacagtggcaccttcagcacaccacagccaccatacagagaggaatccagc
+cccctcccctgggaacccccaccacccactccaccaggcacagcacccagctcataactg
+cagatcagttgccccacccacagctgagcttacctactggcagtggcccagactttccct
+agggagaggctcccagaggcaaacggcagcctctctgcccgtgtcacagcagcagttcta
+tccatgctgtcctcaggcttggaaagaaacaaagcgcctgaaggctgcacctgaacttac
+agcatgccacagttcccatatggagaggagaccagtctctcctcccagtgagccctaaac
+cccctgatccccaacaagcagagccctaacctcacaccagcagtacagctgccccatccc
+ccaggctgaacattcccagtaatagcagctccacctggagatggaacccccagggtcaac
+taaaagcccctctgccactgcctctacagtggtactacccctgctacccttgaactaaca
+aaggagcaaagaccccagtgctttatccacacctccaacaagctgcagtcgaccacaaag
+aagaaacacgtctgtctcccatgggtcctacccacaccccctgctgttcaccatggatga
+tagagtcaacagtgtgaaaacgaccatactgccaaaagcaacctacaaattcaatgcaat
+tcccatcaaaataccaccatcattcttcacagaactagaaaaaacaaggctaaaattcac
+atggaaccaaaaaagagcccacatagccaaagcaagactaagcaaaaagaataaatctag
+aggcatcacattactcgacttcaaactatactataaggccatagtcaccaaaacagcatg
+gtactggtataaaaataggcatatagaccaatggaatagaataaagaacccagaaataaa
+gccaaatactttcagccaactgatctttgacaaagcaagcaaaaacataaagtggggaaa
+ggacaccctattcaacaaatggtgctggtataattggcaagccacatgtagaagaatgca
+actggatcctcatctctcaccttataaacaaatcaactcaagatggttcacagacttaaa
+tctaagacctgaaaccataaaaattctagaagataagattggaaaaacccttctagacat
+tggcttaggcaaagacttcacaatcaagaacccaaaagcaaacacaacaaaacaaagata
+aatagatgggacttaattaaactgaaagccttctgcacatcaaaataaataatcagcaga
+gtaaacagacaacccacagagtgggagaaaatcttcacaaactatgcatccaacagagga
+ctaatatccagaatctacaaagaattggaacaaatcagcaagaaaaaaaaccaaacaCAA
+GGATGACAGTGGAAATACAAAAACAAGACATAAATATTCTGAATAGTGATAATAAAACAG
+TGCATACCAGAATAcaaactgtttccaagttacaatggttcaaccatttttcagctttat
+ggtggtgtgaaagtgatatccattcattagaaaccatgctccaggatgggcgcagtgggt
+cacgcctgtaatcctagcactttgggaggccgaggagggcggatcacaaggtcaagagat
+caagaccatcctggccaacatggtgaaaccccgtctctcctaaaaatacaaaaattagct
+gggcattgtggtgcgtgcctgtaatcccagctattcgggaggctgaggcaggagaatcac
+ttgaaccagggagtcggaggtgttgcagtgagccgagatcgtgccactgcctccagcctg
+gcaacagagtgagactccatctcaaaaaaaagaaagaaaccctactccgaattttgaatt
+ttgatattttcctggactaccaatatgtggcacaatgctctctcacaatgttgtgcaaca
+gcggtgagctgcagcttccagtcagctaaatgataataaaggtagataatccatcttgat
+atcttcctgaagaacataatgcctgcctaccatcaacaggcatcaatactttctaccagc
+tattctcaaccctcatgatcggaagagacagagactgactgtgtcaaagtattagtccca
+tcattcagcaattaactttagctcaatgcttcaaaaattcttcaggccctgtgtaatttc
+agctacgtacattaatgatgagtacccatacaaccattctgtttcttattttcagtacca
+tatttaataaatatcagttattcaatactttatttagacattttgttagattattttgac
+caactgaagtctaatctaaatgttctgagcatgttcaaagtaagctaggccaacctataa
+ttttcggtgtgctaaatgcatttttaacttatgatattttcagtttacgggggtttgttg
+agacataacttcatcatacatcaaggagcatctgTAtatgggatatagttaaagcagtga
+tcagaggaaaatctatagccttaacacatttattaataaaagtgtaggaattaaattatc
+agctgaaaaatgtaaaaagtatctaaaagagtaagcagaaagtacaagaaagaacccaaa
+gtagaaaaaagtgaaaattaataaaataagaagccaaaaaacagatcaaatcagtaaacc
+aaaaatcttgttctttaaacaaatcaacaaagttgacaaaaaaattagatcttttaatca
+tgaataaaaaaaagagaaagcacaaaaatgaataaggaatggtgagagaaataactattg
+ataatcagcaaataaaaaatcattaaaaacaatgttgttcacatctatgaaaaacattga
+aagctagagggaatgggtaattttctagaaaaatacaattcaccacaactgacttcaaaa
+aaaaaaaaaaaaAAAAAGAAGTACCGCACTTATGTGAGCAATTTCCATAGAGAAATACAG
+TTGTCATGGAATTATAACACACACACAAACACTAGGTTTAGATGTTTTCACAGAGAATTC
+CACCAAACCTTTAGAAATCAGATCGTCCAaaggcaaattaacaactctcagccatttgag
+gcaaaatattacaattgaggcaagatatactgtactgaaaacttgaggaaaaagcaggag
+agaaagttcctttgggaaattcgaatactcaaaagtgcttacatacaatgaaaaatttgg
+aaatccataagcatggccaaggtgggacacatgctcagaaaaggcctgagaagacactaa
+taactcacctttagtaattcctaggctcacagcaagaaaaaatgaaggctaaggcagaat
+tatatatggctccgctaagtgttgagggagccccaatacagagtcagtaagcaaagtctg
+ggagaagtttttcatatttttttctttcttggctccttgcagtcaaggaaatcattttta
+aatcactaaatgctaaatgaacacaagctaaaggaaccgagccttcaaacatcaaatata
+aaaaagaatgcagatattacaaaaccagtttacaaaagttactaaacaaataaaaactac
+atcccacagtgggtaacaaaaataaccttgaagaagggaaaaatttggtttccagaataa
+acacattataatatccaaaatgtccagttttcaacaaaaattaagaagcatgcaaataaa
+cacaaaactatggcccatttacagaagaaataaatgagactctccctgagtaagcagata
+ttgaaaatattagacaaaaactttatataactgtcttaaataaacttaaagagctaaaga
+aacccaagagaatgacatataaataaataagaaatatgaatttttttaaaggtacaaaaa
+aattctgaggctgaaaagtacaataagtaaaaagttactttttacttagggttccaatag
+aagatttgagcagctggaaaaaagaatcagtgaacttgatagatcaaatgaaatgattca
+gtctgaagagcaggaaaatgaaagaatgacaacaaaaaagaatagagcctaaagacctgt
+gtaacaacatcaagaatgcctacatacagaatcctggtggggagtgaggggcaggaagac
+tatttgaagaaatgtgtttgaaagcttcccaaatttcactaaaaacaaatatatacattc
+aaaaagctcagtgaacttcatcaaggaaatatacaaagatattcacaccaagacacacta
+tgtttcaaattgtcaaaaggcaaagcgaatgtttgaaagcagcaagagaaaggcaacgcg
+tcatttacaaaggatcctcaataagtttgacagcagatagtgcattataagccatggatg
+ccagaagagcttaggaaaaaggcaacgcgtcatttacaaaggatcctcagtaagtttgac
+agcagagagctcattataaaccatgggtgccagaagagcttaggatgacattttaaagtt
+ctgaaagaaaaaaacactgtcaaccaaaaattctataacttggaagatgccccttcaagt
+attaaggataaattacacattcccagattaaaaaaaagaaagagagagagagagaaagag
+aaagaaagaaagagaaagaaagaaagaaagaaagaaagaaagaaagaaagaaagaagaga
+aagaaagaaagaagaaagagaaagaaagaaagaaagagagagagaaagagagagaaagaa
+aaagaaggaaagaaagaaagaaagaaaaaagaaagaaaaagaaagaaagaaagaaagaaa
+gaaagaaagaaagaaagaaagaaagaaagaaagaaagaaagaaaagcaagcaagctttaa
+aagttcatgtttggtaggctgtacttcaagatacacttttaaaaaaaagactccttcaga
+tacaaactaaaaaacactagaaagtaactcaaaaccacataaagaaataactccagtaaa
+gataactacataggtaaatataaaagcaattatcacattttttgtaagtcttttttaata
+ttctatatgttttaaaacaaatgtgtaaaataatgactataaatctatgttaatgaagca
+tgatgtatacagatgtggtttgtgaaattaccaacataaagaaattcataggaaactaaa
+taataatagagattttgtatactattgaagttgtttcaatttactctaaattgttccaaa
+ttaagaatgttaattgtaaatccccatggtaaccactaagttaatatcttttgaaaatac
+agaaaaggaaagcacagggtaaacacagtgatatgctacaaaatagcaactaaacacaaa
+agaaggcgataattgaggaaattaggaacaaaggaggtataagacatacagaaaacaaaa
+gcaaaatggtaggagtaagcccctctttatcagtaattacattaaatacaaatgaattaa
+actctccaatccaaagaaagagattaacagaatggattttttaaaaatgatccaactata
+ttgtccacaagatactcactttagatcaaaatacacaatgagttgaaatgaaaggatggg
+agaaaatattccatgtaagtaataaccaaaggagatctgaggcaaatatacttatatcag
+acaaaatagactttaagtcaaaaactgttacaaaatacaaagaacagtatatattgattt
+caaaattaattaagaagatataacaattataaatatatgtacaccaactaacagggctcc
+aaaatatataatgtaaccattgagagaattaaagggagagacagacaattccacgaaaat
+tgttgggcatttgaaaacccaactttaaataaaagataaaacatctagagcaaatatcaa
+gggaggaattagaggatttgaataaaactataagcaataactatagataacacttctctc
+aaaaactgcagagtacacattcttctcaagtgaacatggaacattctccagcacagatga
+tatgttaggccataagataagctcaataaacttaaaaagattgaaatcatgcaaagtatc
+ttcactggccacaatggaatgaaataagatatcaataacaaaagaaaaactagaaaattt
+acaaatatttggaaattaaacaacacagtatttaccaaccaatgaatcaaagaacaaatc
+atgagggaaattagaaaatgtttagagacgattgaaaacaaatatataacaagatgggtg
+tgatatatcaaaagcagtgctcagagttgtaacacctacattttaaaaaagaaacatgtc
+aaatcaataaccaaactttactcaataaaccgtaaaaggaagagcaaacaaaatccagag
+ctagcagaaggaaggaaatgaagattagagcagagataaatgaaattgagaattaaaaaa
+ttatacagagatcaacaaaattaaaagttggttcttttaaaatatcaataaaattaatat
+acttttacatagactaagcaaaacatctctattcagctgactttttttacaagggagcca
+acattattcagtggggaataatagctttttcaacaaaaagtgctgggaatactgaatatt
+catatgcaaaaaaaatgaagctggacccctacctcacattatatacaaaatctagattgg
+atcaataatgtaaatataagagtgaaaaccatacatgcttagaagaaaacatggaaataa
+aacattgctgtggattggcaatgcgttcttagataatacaccaaaaatacaagcatgaaa
+caaacaaatGCAGCCAAAATGTACCAGAATCTGAAAACATCTATTATCTATGAAGAATTA
+GAGGGGAATTTGGTGAAAGAAATatgggagaatgggacattgctctgtgaatgcttttgt
+gcataattgtacatttttaattaagttaatcttttacactctcaaagtgtgatattaagc
+aagcaaagataagttattacaagactctaaaaccgaatgcaatgagaaacaagtgaatcc
+aaatatatttcaaatgaatgaatgacataatcaaacttaaggggaaaataataattaatc
+tgattaatttttgactgttcttttagttcaaattgacttttgaacatacttggactacat
+accattgcttgaaaaaataaaatatctgcaaaaaattattaaatcttcatgataggcttt
+tttctttttatattagtataaatataacaattctgaaacaaatgtatgtgcattgtaaga
+ttaagccaatgagtaaatattaatatatttgtattgctagaaccccagattctcactgtg
+aaaggacagagatacagatatggaataagacaaggaaagaagcagcccactgagttacat
+tagaatcagtattatcaacataaaTATGCAATGTGCTCTCTCACATGCTCTTTCCTTCTC
+TTAAAAAAATATAATATGGACATATTATATATTATATGCATAGACACACGTGTGTCTATA
+CATATCCTATCTATACATATTGAGGATTAACAGGTGCTAGTAGAAAATATTAACTTTCTT
+TGTATTAACAGGTGTTAGTAGAAAGTAGTAGTAGGTGCTAAGATAAAAGCCATAATTAAA
+cctcctggtgaatgaacacaccatcacctacaatcttaccaaaaatagaatcaagcacgt
+gtcctagtcaaacctctggattcaactgtcatttggataaaacgcaaaggatagtgaaaa
+tgtcgatcttcactgagagtctaaccagcaaatttcacagtgtggacatcaagtgacaaa
+aatcccaaatttttcaacaaatatattgtatgggaaagaaaactttgaaaagaaacctgt
+atgttagaagagattttaaaaacatgacaaATGAAAAAAAATGGGCAAGACTAAAACTTT
+TAAAAAAGtttgagacagggtctcactctgtcacccaggctggagtgcagtggtgtgacc
+atggctcactgtggcctcaacctcctggctcaagtgatcctaccacctcagtcttccatg
+tagctgggactacagctgcgtgccaccacatctggctcatttttttttcttttttaagta
+gagacggggacttgctatgttgcccaggctagtctcaaactcctaagcacaagcgatcct
+cccgcctcggcccctgaaagtgctgggattgcaggcatgagccaccacacccggccAAAA
+GTTGCTTTTGAGGAGTTATTGCTGTGTGGATGTGATATAACCCTTTCTGTCATCTCTTCA
+CAAAACTTTCTGTAAAACATAAAAATCACCTGGACCTTCAGAGATGAGTTTGtttatttt
+tttattttttaaaaaattGCTAATTTACAGAACATGGAGATGAGTATGTTTTGAAGGCTT
+GGAAGCATGCAAGTGGGAGAAGAAAGGAGTCAGCTACATTCTGGCTGTGTGCAGAGGCAG
+GTCACTGTGGTGGGAGTGTTCCTGTTTCATGGACTCTGCAAATCGCAATGCTTGGCATGG
+CCTCCCGACCCTGATGGCAGAGAAGCAAACACCAGTCGGAGAGCTGGGGTCCTCCCAGCC
+CTCTTGGCCCTGTGGCCAATTTTTTCTTCAATAGCCTCATAAAATCACATTATTTGAGTG
+CCCATGGCTCCAAAACAAGCAGGGATGCCCATGGACCCTGATTATCCATTGTCACCCTTC
+CCTCCAAACAGCCACCTCTCCCCTGGAGACAGCCCCATACTCCACTCAGACCTGTGCACT
+TTCTGGTATCCTTGTCACCTGCTTTTTATGTCTCATTTTACAAACACCAAATTGGAAGAC
+AGCAGGAGCTGCCCCATAATACCAGTAAAGTGAGAAGCAGAGATAAACTAGTCCTAGACA
+GCCGACTCATGTTGGGGGCAGCCCACTCACAGTGGCCCTGACCCAACTCTGACTAGAGGC
+CACTTGctctcaacaccagggtgctcaatggcccgtcctggtactctgctcttctctctc
+caccttcgctttcctgcaatctatgcagcctgtgactccatccatgggctagtgaccccc
+agaccttctcctgggaccacaggcctgtgtctctatctgctgctcaatacctcccctcga
+acatccatggctaaaactgagctcctgatactctctccctacccgcttctctgtggattc
+cccacctccgcgaaggacagcttcatcctttcagctactcaggccagaagattgaagtca
+tctccttctccaggaaatcgtattgagggagctacaaatatccaaaatccgatcgcttct
+cctccactacacccgaggcccgccacccatttttgcctgaattgctgcagcagcctccta
+accgatctctgctttcacgtgggcacctcagttttttccagaacaacaaccagagagatc
+tgctcacacccaagtcagaccaggttactcctctgctctcatagcatttggaggaaaacc
+cagagtgctcgtgttggccggcagagccggcccccatctcctctgacctcctccccacct
+cttgccctcagcacccagagtgctcgtgacggccagcagagccagcctccatctcctctg
+acctcccacctctcgccctcagcaccCAGAGTGCTCGTGTTGGCCAGCAAAGCCGGCCCC
+CATCTCCTCTGACCTCCCACCTCTCGCCCTCTGCACCCAGAGTGCTCGTGACGGCCAGCA
+GAGCCGGcccccatctcctctgacctcccacctctctccctcagctagtcctcgaacatg
+tctgatgtggtcccaccttgggacccacattgctactcctctgcctgtaggggtacccac
+agttatccacacagttcactcctgtctttcaggtctttgtgcaaatatcaccttctcagt
+ggagacTACaccttcaggacttaggctgtgcctggcacatagtaggtgctcagtagacac
+tggttgtaggaaggaatCTACAGGTTGAAATAAGGAGATCATTTCCCTGAGGTTCCGAAG
+CTCATATTTACTCACCATTTGTTGTTTACTGCTAATATTGAGCACTATCAGTAAAATACA
+TAAAACCCtttgccaatccaggaagtgaaaatgacactttactgttttagtttgcatttc
+tctgcttacaaatggattacacgcattttcatgtgctgttggctacttATTCATTCAGAA
+AACATACTAAGTGCTGGCTCTTTTTCATGTCCTTTATCAAGTTTGGATCATGTCATTTGC
+TGTTTTCTTTCTGATGTAAACTCTCAAAGTTTGAAGGGTATTGTCTTTTCCTGACACATA
+CGTTGTAAATAATTTTCTGGCTTACATTTTGACTTTTAATTTCATTCACGATGTTTTTAA
+TGAATAATTTTAATTTTTATGAATGCAAGTTAAAATAATTCTTTCATTGTGGTTTCTGAC
+ATGTCATGCCAATAAGGGTCTTCTCCTCCAAGAGCACAGAAATATTTGCCAATACTGTCC
+TTAAAATCGGTCACAGTTTCATTTTTTATATATGCATTTTACTTCAATTGGGGCTTCATT
+TTACTGGCCCTATTTGAAGCAAGTTTCTCAGTTAATTCTTTTCTCAAAGTGCTAAGTATG
+GTAGATTGCAAACATAAGTGGCCACATAATACTCCCACCTCctttgcctcctctcccagg
+aggagatagcctccatctttccactccttaatctgggcttggccaagtgacttacactgg
+ccaatgggatattaacaagtctgatgtgcacagaggctgtagaatgtgcactggggcttg
+gtctctcttgctgccctggagaccagctgccCCACGAAGGAAACAGAGCCAACCTGCTGC
+TTCCTGGGGGGAGACAGTCCCTCAGTCCCTCTGTCTCTGCCAATCAGTTAACCTGCTGCT
+TCCTGGAGGAAGACAGTCCCTCAGTCCCTCTGTCTCTGCCAACCAGTTAACCTGCTGCTT
+CCTGGAGGAAGACAGTCCCTCAGTCCCTCTGTCTCTGCCAACCAGTTAACCTGCTGCTTC
+ATGGAGGAAGACAGTCCCTCAGTCCCTCTGTCTCTGCCAACCAGTTAACCTGCTGCTTCC
+TGGAGGAAGACAGTCCCTCTGTCCCTCTGTCTCTGCCAACCAGTTAACCTGCTGCTTCCT
+GGAGGAAGACAGTCCCTCTGTCCCTCTGTCTCTGCCAACCAGTTAACCTGCTGCTTCCTG
+GAGGAAGACAGTCACTCTGTCTCTGCcaacccagttgaccgcagacatgcaggtctgctc
+aggtaagaccagcacagtccctgccctgtgagccaaaccaaatggtccagccacagaatc
+gtgagcaaataagtgatgcttaagtcactaagatttgggCAAAAGCTGAGCATTTATCCC
+AATCCCAATACTGTTTGTCCTTCTGTTTATCTGTCTGTCCTTCTCTGCTCATTTAAAATG
+CCCCCACTGCATCTAGTACATTTTTATAGGATCAGGGATCTGCTCTTGGATTTATGTCAT
+GTTCCCACCTCGAGGCAGCTTTGTAAGCTTCTGAGCACTTCCCAATTCCGGGTGACTTCA
+GGCGCTGGGAGGCCTGTGCATCAGCTGCTGCTGTCTGTAGCTGAGTTCCTTCACCCCTCT
+GCTGTCCTCAGCTCCTTCGCCCCTGGGCCTCAGGAAATCAATGTCATGCTGACATCACTC
+TAGATCTAAAACTTGGGTTCTTGgaccaggtgcggtggctcacatctgtaatcccagcaa
+tttgggaggccgaggcgggtggatcacaaggtcaggagatcaagacgatcctggctaaca
+cggtgaaaccccgtctctactaaaaatacaaaaaaattagccgggtttggtggcaggtgc
+ctgtagccccagctacttgggaggctgaagcaggagaatggcgtgaacctgggaggtgga
+gctggcagtgagccaagatcacgccactgcactccagactgggagagagagcgagacttt
+ctcaaaaaaaaaaaaaTCTTAGGTTCTTGGATGTTCGGGAAAGGGGGTTATTATCTAGAA
+TCCTTGAAGCGCCCCCAAGGGCATCTTCTCAAAGTTGGATGTGTGCATTTTCCTGAGAGG
+AAAGCTTTCCCACATTATACAGCTTCTGAAAGGGTTGCTTGACCCACAGATGTGAAGCTG
+AGGCTGAAGGAGACTGATGTGGTTTCTCCTCAGTTTCTCTGTGTGGCACCAGGTGGCAGC
+AGAGGTCAGCAAGGCAAACCCGAGCCCAGGGATGCGGGGTGGGGGCAGGTACATCCTCTC
+TTGAGCTACAGCAGATTAACTCTGTTCTGTTTCATTGTGGTTGTTTAGTTTGCGTTTTTT
+TTTCTCCAACTTTGTGCTTCATCGGGAAAAGCTTTGGATCACAATTCCCAGtgctgaaga
+aaaggccaaactctggaaaaaatttgaatattttgagccaaatgtgaggaccacaacctg
+tgagaacggaaaataaatcctgggaccccagactcactaagccaaagggaaaagccaagc
+tgggaactggcttatgcaaacctgcttcccatctggttcctaaataagatagctattaca
+caaagacaaaaaagctacatccctgcctctacctccatcgcatgcaaaatgtgtattcag
+tgaacgctgaccaaagacagaagaatgcaaccatttgcctctgatttacccacacccatt
+ttttccacttcttcccctttccccaatacccgcacttttcccctttacttactgaggtcc
+ccagacaacctttgggaaaagcacggaccacagtttttcctgtggttctctgttcttttc
+tcaggtgtgtccttaaccttgcaaatagatttcttgaaatgattgagactcaccttggtt
+gtgttctttgattAGTgcctgtgacgcagcttcaggaggtcctgagaacgtgtgcacagt
+ttagtcggcagaaacttagggaaatgtaagaccaccatcagcacataggagttctgcatt
+ggtttggtctgcattggtttggtctggaaggaggaaaattcaaagtaatggggcttacag
+gtcatagatagattcaaagattttctgattgtcaattggttgaaagaattattatctaca
+gacctgctatcaatagaaaggagagtctgggttaagataagagactgtggagaccGTGCA
+TAGTTGCTTCCTGATCAGCTCTTTATTTGATTGAGAGTGAGGCAGGGAAGATTAGAGGGA
+AGCTTACAGTGGAATTCAGGGCTGAGGCTGCTATTCTTTTGCTCCTTGTAACTTCCTACA
+GTGTTGTCAGCATCCACATACTTCTCTGTGGGGTTggtctcagagccaggttaccttgtc
+ttaggtccagtggcaccctgactggcttggtgtccttgaacaagttacctaacctctcca
+aacctcagtccctcagttgtaaaattaaaaaaaaaaaaaagaagaagaagagtacctact
+gtatagcattgatttgaagattgaatgagctggtattatacaacgtttagaagcagtgcc
+tgacacgcaaaaggctctcaacaaatACTATCCTTTACTAATATCCTGTGTGTCTGTATC
+AGAGCTGGTGGGGTGGAGGGACAGAAACAAGTGGGAGAAGGTaaagagatggacaaatga
+tctctaaagtctctctggcactaacaCAATTCTTTATTATGTGTTTTGTCTGGCTCTTTA
+TATTGATAGCTGTTCCAGAGGCAATCAATAGCTATTAGTCGGTTTTATTCTTATTTTTCT
+GTCTGATCTTACAGGGGAGCAAACTGTGGCAAAGTATGAACTTACTTCTCAGGAAATTAA
+CCATTATATTGGCAATCACTGTGATTATTTGAACTTCAGCGTCTGGACAAATTTAGTCAC
+ATGAAATACAGAAGAGAGATTTCTCATGGTTAAAACGAAGCTCTCTTTATTTGCTTCTGC
+TAATTAAAAAATCAGAGCTAAAGATACTTAAACACTACAGTTAAAATGCCATGGTTGTCT
+ATTGGCTTAACGAATTCTCTTATGAAATCAACTCTAAAATGCTATCCATCATAAATCATG
+AAACGCAATTTTTCTTATTCTCTTTAGAGCTTTACAATTCATCTTAAAGACCAGTGTTTA
+CACTCTCTTCTGTAGGTTGTACAATAACTTTTGGCGAGAAAAAATAAAAGTCTGGCTTTC
+TGACTCATAGGTGTGTTCCCTTTAACAGAAAAAGAAAATATGTCCTCTTTAAAACTGATG
+ATCATTGGTCACCTCAATTTTATTGAAGTTCACTTCTGACCTCTTTAGATGTAGTTCTCT
+ACATAAAACTGCCCAACAGAATTCTCTGTCTGAATGTCTCCTCCACAAACAAAATTTTAA
+GAACTAAAATTATCATCTTTCCTTCCAAATATGCTCTCCCTATGTCCCCAGGGCTCTCCA
+TGTGTAGAGCTGAGACCATTTGCCACTCAGTTTCCTCACCCAATTAATTACAAGTCCCAA
+CAATTTTCCGGtttttttgtttttgtttttgtttttagacggagtcttgctctgtcacca
+ggctggtgtgcggtggtgcaatctcagctcactgcaacctccgctgcctgtgttcaagcg
+attctcctgcctcagcttcccaagtagctgggattataggtgtgtgccactacatccaga
+taatttttgtatttttagtagagaggggatttcaccatattggcccagatgatctcaatc
+tcttgacctcatgatctgcccaccttggcctcccaaagtgctgggattacaggtgtgagc
+cgccatccctggccCAGTTTTGCCTTTTTAACATCCCTCAGCTCTTCAAATCCATTTTCT
+cttctctaacacctccccattccccagctcgtaatgaactcgtaagtagattactacaat
+cacctcccaaatggtcttcctggctccatcagccttgtgaccttcaagttcattttccac
+atggatgtcagagtaactttctaaaatgaaaatctgaccacgttactctcttgcctaaat
+ccgcctatggccgctgttaggatcaagtctaaactcccgaccctggaacatcaggtcttc
+gtgctctgttcactgcttctctacctcacctgcaaccaACACCACTCCCACATCCATATG
+CTGCTCACCGTGTATCAACATGAACAGGAGGTGGGTGTTTCAGTCCCCAGGAAGACACTG
+GGCCTTTTCAATCATCTACTGCTGTGTAATAACCACCCCGCAAACTGACCACATGATTTC
+ATTTTGCAAGGGTTCCTTCCTTgggctgtgttcagcaaaagggtttactgagctggcagg
+tccaagatggcctcactcacaggactggctgttgatgggagccttgatgctcttgggctc
+accccttatcctccagtaggttagagcttcttacagtggtttcaggcagcatctgaagac
+agtaaaagcagaagctccaaggcttcttacattctagcctggaaaatcacatcacattgc
+ttccttcatatttttttggcaaatcaggttgcaaggcttgcccagattagggtaaagagg
+caaagaggctccttttcttTTCttttctttttttttttttttttttttttgagtcagaat
+ctcgctctgttgcccaggctggagtgcagtggtgcaatctaggctcactgcaagctctgc
+ctcctgggttcacgtcattctcctgcctcaggctcccaagtagctgagactacaggcacc
+taccaccacgcctggctaatttttttttattttttattttttagtagagactgtgtttca
+ctgtgttagccaggatggtctccatctcctgacctcgtgatccTTGCAAAGGGACATGCA
+GACCACATTAGTGAGAATATGTGCCTGTATTTTGCAATCTGTAACATGGGCATAAACTAA
+ATGTTTTCCAAAGGGAATAGGGCAAAACAAAAAGGACCTTGACCACTCCTTGGCCCTGAA
+TAAATCCAGGAAGCCTAAGAGTATGACTATCCTGAGGTAGAAAGAGGGTCACATGCTGGA
+TAAGAGGTACCTGGGCTCTCCACTTACAAGAAGAGAGCATGGTTACATTTATAATCACCA
+TTCCCAACATGCTGTGAGTGCAGGCAGCTACCAGGAGGAGAACAAAGGAAATAACCAGGA
+CACTCATCTCTAAACCTGTTAATTTAATCACACGGAACACTTCTATTTAAAATTCCCGAG
+AGTTAAGATGTAAGAATGCTTATCAAGGTAAATGCTGTTCACACTGCTTGGAGTGTCAGG
+CCTAGATCTCTATCCATCAGAaacaacaatatcaataacaacaacagcaacaTGATGATG
+GGGCAATTTCTTAAAAGCACCATGTATTTTATCGATACATGTCCGTTGCAGAAAATCCAG
+GTGAATCCAAAGAAGAAATAAATGTCTTCCACAATCCCATAGCCCAGAGCTAACTAACCA
+CTATAAAGAACCCAGCGTGGTTTTAACTAATGGATCAAAAGATGCTCATCAAAGGCTCTG
+AGCTTTCCTGAGTGCTAACAGGAAACATCCAGCATCACTGGTCTCTCCAAGGCTGCAGGT
+GTCTTTGCCCATAGTGCCTGTTTTGTGTCAGGGAAAGAATCAACCTGGGAGCCAAGCCCA
+GGAATCAGGATGACCAAGACATACTGCACAAGGAGGGAACAAACCCATCCAAGGACACTC
+AAGGACAAATCAAGCAAATGAATTTAAGGGAGACGTGCTCATGGTCTGCTTTGCTGCTCA
+GCATGGCTGGGAGGCACAGTGGAAGATCATGCATCCTGCCCCTGGGACTCCTCTGCCAGA
+GCCTGAGAGCTTTCTCCTGCCCACAGGCTAGGGGTAGGGCAGTTGGAATTGATCCATGCC
+TTCTAGCTAGACTGTGGGTCCCCTCAGTCTTGGGCATGGTGACAGCCCAGCATCAGACAG
+AGGTCAGTATCAAACTAGAAAATTTAATAAATACTGTCAGATTTGTAGACCCAAGAAAAT
+ATAAACTGCCAATCACGGAGGAAAAAAATCTCTCAATGATCTTATCTTTATATGATTCCC
+TTGCTGCCTGGAGATTGACATTTCCTTGGGGATAATCTGGTCATAGGATTGGTGAAGGTG
+GAAGGGAGGCAACCTCCAAAGGTGGGGCCCTCTGCTCACCTGGGACAGGGAGGGCCTGAG
+GTAGGTGTCTGTGTGGGCTGGGGAGGAGGATGGGAGCAGTGCTTCTAGATGTTTCCACTT
+TCTCCTCATTAGATAATAACGAATGGGTGATTTCCCTAGTCACTGCAGTGTGAGGAAATC
+TACAAAATTAATTTCACAATACGCTTTACAGGATAGGTGGAGAAACACATGAAGTACAAC
+TGCAGTGGGTTATAAAAAACGGCCTTTCGAGTTGAGCAATAAATTCGTTCAAGCAGCCAT
+TCTGAAGGACAAACTGGCTCTGTATTTAAGAGGGGCATTCCAGCACTTCTCTAGCCACTG
+GGTTGACAATGACTCACCAAAGCCTCTGGTAGCCACCACAGGACACCCAGAGCATATGTT
+TTAAAGCTGAACACCAAACTGCGGACTTCGGGAGTAAGTGAACTGACTGGTTTTTATTTT
+GTTTTACTGCTTTTAACATTACAGTAACTGTTACAGGTTCCAGCAGGCTAACTGGGTGGA
+AATGAGTTTGGTTTCACTTAGTCTCTCTAAAGAGAAAGCAAGTCGGTAGACTAATACCTA
+ATAAAAGCAAAGCTGCCAACAATTGAAATTGCCTAGGCTGCTCTGTGTGTCCCACAtgca
+tgggtgtgggtgccagtgtgtgtgcgtgtgtgcatgcatgtgcatgtgtgtTGGGATAGA
+GTGGTAAGAAAATGGGAAATAATAAGAATGTTCAGTCCATAGCCCTTCATTATAAAAAGG
+TGAGCTGTAATAAATACTAGTGCCACATTTAGCCAAAACTTTACTCCAGCCAAAGGTGAT
+ATTTTCATGATAACATCCTGTGATTGCTTTGTTCTTCGTCTTTTATGTTCTTCCTAGATG
+GGCTCAGAACATACAAGAATTAAGTACACATCTTATTTTCCAGTGATAATGCTACCGGCA
+AATTCTGTTGTTTGTATAAACATCAGCCATGTTTATATAACTAAACTAGTGTTTTGTTTT
+GTCAATTCAGCAAGAAATTAGACCAAATGGTGGCTTAATGCTGCATTGATTTGGCTATCA
+ATTTGTTTTCACTTTTCTGCAAAATAATTAATACATTATTAAATTGAATTGTGCTGATGC
+CACAGTTGTTCTTATCTCAAGTGTCTTAAAATTCATTTAATTTGTTTTTCCTTTGGTTTC
+ATTATTCAAATTTTAACTTCAGTTCTCAAGATTTTATCTGATGGAAGAGATGGAGTCCAT
+TACTAAGGACTCCATTGTGCTCCATCATGCCAGAGTTGTAAAATAGATCTTTTAAAGGAA
+ATTTACTGTGATTTTTTTTCTATTTAAGAGCTTCCTCTCCAGTTGAGCATGTAAGAAAAT
+TATACCAGGAGAATACAGTAAACTCTATGAGGCAAGCTATAAACATGTAGCATTGTGATT
+AGGGctggttctccttctagagacatggtaggattgcaatttcataccatccttgaagtt
+agagagagccacgtgactcatttagccaatgaactgtgagcagaatgacatgtcacttcc
+agctgaagctttaaCAATCTGAGAGACATTCATACATTTTCCATGTGCTGTAGCCTTATA
+CCCAAAGCCTGGGTCCCAAGTGACCATGACAGGCAGAGCTCCCTGttgagccacagagat
+ttagagaatggctgttaacacagcataatccagcccatcctgactaatCTGATATTAACA
+TGTATAATAAAGAATTCTATCAATGCTGAGGGAAGATGACTAGTTAAGGTCCTAGGTTGC
+AAGTCTCAAAACCTCTTCTAAGGATTGTAGACAGGAAATTAAATGACTTCTAGTCCCTAG
+AGTTCCCAATCTCCTACCATCCCATCCTAATATGACAGAAGTAATTCCTGAGTTGCTTCT
+GAAACCAGAGCTTCCCTCAGAACCCTTAGCCTGCCAGATGGCTTCTTGGAGAGCCCTCAC
+TCACTTTTCTCCTTCTGCTATTGCTGCTCATTCATTCCAGTTTTTAAAAATTCATCTTTA
+TCCAGGAACCTCGCTTCTAGAAAAGTCATACAGGTGCTTCCAGGAGGCTACATGGGCACC
+CATATTTTTCTAGCCACTTTCATTAGACCAATGCAGCAGAGAAGAAAAGCCTCAATAATT
+ATTATGACATGGCATGTTAGGATACCAAGTAAATTGCATTTGTAAAATGTGATTTTCTGT
+TGGTGTTCACTTCAGCTCTACTGACATTTGGTAAGTATTATTGACTGACTGACTAACTAA
+TGTGGTCATTAGTCTTCATAAAGAAAGGCTCTCTACAAAAACGGAGGGATGCCCTTTTTC
+TGGCATTTAATACGTAAGAAATTGCCTCCAATAGAAACCAGAGTTGCCTGATTACTATCA
+GCACAGGAGAAATGTATTAATGTGCCTTTCTAGTAACAGGTTTTTAGAAAGTCAAATATA
+AACAAATCTGTCTATTTGTGTGTGTGCATGTGGTAGTGGGGAGGGAAGAAAAAAGGAGGG
+GGAGAGAAAGAGAAATAAGAACCAAGTTTATTATACTGTATTCAGGGGGAAAAAATTTTC
+CCAAGGTCCTAACAGAAGAGCAAAGTGCCACTGTCAATAGCCTCAGTAGTGTTAGGGTTG
+CTtttatttatttatttatttatttatttatttatttatttatttttccttttttttctt
+tctctttttttcttcttttttttttcttttctttcttttttttttttttttttttttttg
+gacagagtctcacactgtcacctgggctggagtgcattggtgcaatctcgactcactgca
+acttctgcctcccaggttcaagtgattctcctgcctcagccgcccaagtagctgggatta
+caggtgtctgccaccgtgcctagctaatttttttgtatttttagtagagatgaggtttca
+ctatgttggccaggctggtctcaaactcctgacctcatgatccacccacgttggcctccc
+aaagtgctgggattacaggcgtgagccaccgcccctggccAGGATTGCTTTTACAGCCAG
+TCTTCAGGTGCCCACTGTAGGAACAATGTCATTTAACCCTCGGGATTATTCTGTGCCAAA
+TATGGATAATGACTAATATCCAACACAGATATTCTCAGCTCAGAAGAGCAATTAGCAAAT
+TCATAAATTAAGTGCTTGCTTCCTCTTTAGTCAAATACAAACGTTTGTTAAAAGATATTA
+TTTTGCTTTACACTTTTTCTCTCAGAAATAAGCAGATGCTTGAATTCCCACAGTGCTGCT
+TGAGCCTCACACCATGTCATCCTGCCAGGCACCCAGATCCAGTTCTAGAGTTTCACATGA
+TCGTGAgtgttggttaataagtcaatgtgaactgggaggggagatttttcaggagtgcca
+cagggctctccctttaatcACATACACTCCCTGCTTTCATTGGAAAGTGTATAATGATGT
+CAGAGTGCCCCAGAATGGAGCTAGTTGGAAGACTGCCGTCATAGGGATGCCTTAGTGAAT
+TAATAAGGTTTTAATTTCTGGCTCTCAACTTTGTAGATGTAAAAGTTGATTTATCAATAT
+GTGAGAAAGGATGAATCTTTCTGAAGGTTATGTCATCACACTCACTAAGCACACAGAGAA
+TAATGTCTAGAATCTGAGTGCCATGTTATCAAATTGTACTGAGACTCTTGCAGTCACACA
+GGCTGACATGTAAGCATCGCCATGCCTAGTACAGACTCTCCCTGCAGATGAAATTATATG
+GGATGCTAAATTATAATGAGAACAATGTTTGGTGAGCCAAAACTACAACAAGGGAAGCTA
+ATTGGATGAATTTATAAAAATATGCCTCAGCCAAAATAGCTTAATTCACTCTCCCTTATC
+ATAAGGATAATCTTGCCTAAAGGGACAGTAATATTAAAGACACTAGGAATAACCTCTGTA
+CTTTGGACAGTAGACCTGCATAGCCCATTAGGCCTCAATGAAGTCTTATGCAAGACCAGA
+AGCCAATTTGCCATTTAAGGTGATTCTCCATGTTTCTGCTCTAACTGTGCTTCACAATAC
+TCAAAACACTAAATCAGGATGTTTCCTGGAGTTCAGGGAGCTGTCCGTGTTACTGAGCAG
+TTCTCAGCAACACAAAGATCCTACTGACTCCTCATCAGACTTCTTTCTCACTGGAATTTT
+ACACCTGGGCTGTTAACACCAGGCCAGGTCAAATTCAAAGGAGAGAAAAAAGCTCATTAT
+GAAGGGTAAAATCCAAAACACTGTGCATAAAGATATGGCACAATTTTTATACATAAAGAT
+TTCATAAAACCAAAGCATCAGGAAATGAAAAGAGATACAGAAAGAAAAATGATGGTAAAT
+GAGACATTAATTTACCCTTCTAATCTCTATCACAGCAAAAAGATAATTAAAAAATCTATA
+TGAGGACCACAAAATACACAAAAATTATGTAGCAAAGCCTATAGCCTGAAAAAGTAAACA
+TTGAAATTTGTATGTCCATAAAATGTTTACAAAATTCAGTACATATTACACACCCCACCC
+TAAAAACATCTAAGCAAAGTAGAGAATGTAGAAATGCTACAGATTATATTCTCTGATTAT
+GACACAACAAAACTAGAAATTACAGCATGGAAATTTAAAAGCTTTCTCTTAAATAATTCT
+ATGTCAAAAAGAAATCCAggccgggtacagtggctcatgcctgtaattccagtactttgg
+gaggccaaggtgggcaggtcacttgaggtcagcagttcaagaccagcctcgtcaacatgg
+taacaccctgtctctactaaaaatacaaaaattagctgggcctggtggctcatgcctgta
+atcccagctacttaggaggctgaggcaggagaattccttgaacccagaaggtggaggttg
+cagtgagctgagattgcaccactgcactccagcctaggtgacacagcaagactctgtcaa
+aaaaaaaaaaagaaaTCCAAATAAAATTTCCAGAATATGTGGAAAATAGTGACAATAAAA
+ATATTAcacatgtgtaatcccagcattttgagatgccaaggtggcaggatcacttgagac
+caggagttcgcaaccagcctggacaacatagggagactccatctccacacacgccaaaaa
+aaattttaaatagccaggtatagtggtacttcctgtaatcccatctacttgggaggctaa
+ggtgggagaatcacccaacctcaggagttcagggcttcagcaagccatgatcatatcact
+gcactccagcctcagcaacagagcaagatcctatctcaaaaaaaaaaaaaaaaTCACATG
+TGGGAAATAGCTATAGCACAAtaaaaataaatgtattaagtatgaacaacaaaaaagcta
+gtaaaggttgaacaacaactatccttaggaaagtggaaataatgtattaataaatatgaa
+agcaggctagccacggtgactcacatctgtaatcccagcactttgggaggctgaggcagg
+cagatcacctgaggtcaggagttccagaccagcctggccaacatggtgaaatcttgtctc
+tcctacaaatacaaaaactagccaggcttggttgtgcactcctgtaattcgagctacttg
+ggaggctgaggcaggagaatctcttgaacctgagaggcagaggttgcagtgagccaagat
+catgccactgcactccagctggggcaacagagtgacactccatctcaaaataaataaata
+agaaagcagaaactaataaactagaaaacagaaacatagaactaatttataaatcaaagc
+actatgccttgaaaagaGGGAGAAAAATTGTGAATTAAGGAAGGGAAGAGATGGTTGGAG
+AGGAGGTGGGAGAAGGCAGAGATAATTGAAGGAGCAAAAGCATCTGGAGAAGCAAAGCCA
+CTGAAAGATGAACAGGGCTCTGAAAGAGATGCTTGACTGCTATCTTTTCAAATGACTGCA
+GTTCCCAGTGACATCATTTTTCTCCTCCCTGGAAGTCTGAGGGGCAGTTCACTTATCTCC
+TCCCCTCCCCTACTCCTCACCCCACACTCAAAACCTGTCTATGCTCCTTTCATTCTCATA
+TGACAGATTTCAGATGGCATTCTTATTTCCCTGATTTCTTTTTGAGATAGCTTGCATTTC
+CCTCCTCTATataaagccaccgtttatcaaatgcctacatggaccaagcagtccacaagg
+gcttcacagacagttttactaaactcatgccaaaactttcaggttttatacctaccttat
+agataaagaaattgaagcttatagagtttaagtaatgttcccaaagcctcgtggctagta
+attcaaacctaatttctgcctactccaaagtctatttttccttatgatactctactgcct
+ctcCAtggataaagacagagatcacatattaataaaatttgcacaaagtcggcaaattgt
+tgaaagggaaggctaagatgattaataaaatcaagagccagatgatctcaacaacctgaa
+ataactggctgacaaccaatttgaataactccctgcgggtgaagttcaaagtactatttg
+ggtttttttttaaagtttggctgggtgcagcggctcacgcctgtaatccaagcacttagg
+gaagccaaggtgggcagatcatgaagtcaggagttgaagaccagcccggtcaacatggtg
+aaaccccatctctactaaaaataaaaaattagccgggcctgctggtggatgcctgtagtc
+ccagctactcgggaggctaaggcaggagaatcgcttgaacccaggaggtggaggttgcag
+ggagccgagatcgcaccactgcactccagcctgggcgacagagcgagattccgtctcaaa
+aagtaaaataaaataaaataaaaAATAAAAgtttgatatattcagaatcagggaggtctg
+ttgggtgcagttcatttgaaaaattcctcagcattttagtGATCTGTATGGTCCCTCtat
+ctgtcagggtcctagcaggaaattgttgcactctcaaaggattaagcagaaagagtttaa
+tgaagggtctctttccagggttaagggaactgctagggtttggatatttgaccactccaa
+actcatgttgaaatgtgatccccattgttggaggtggggcctaatgggaggtgttttggt
+cctgagtgtggacctctcacgaatgtcttggtgccatccaagtgagttcttgctcgctct
+tttttttctttttgagatgtagtttcactcttgctgcccaggttggaatgtagtggtgcg
+atcttggctcactgcaacatccacctcacgggttcaacccattctcctgtgtcagcctcc
+agagtagctaggattacaggtgcccaccactatgcccagctaatttttggtatttttagt
+agagacggggtttcaccatgttggccaggctggtctcaaactcctgacctcaggtgatac
+acctgcctcggcctcccaaagtgctgggattacaggtgtgagccaccatgcctacctagt
+tctagctctcttaattcccacaagagctggttgttaacaagagcctggcacaaacccctc
+tctctcgccacgtgatctctgcacatgccagcttcccttccccttctgccatgagtggaa
+acagcctaacgccctcaccagaagcaaatggtggcaccatgcttcttgcacaccttcaga
+actgtgagccaaataaacctctcttctttaaaattattcagcctctggtattcctttata
+acaacacacacacacacacacacacacatacacacacacgcaaaagcagactaaaacagg
+aactaattagaaatggtgatgcaccgagggattggcaCCGAGGCTCCCCAACAGGAACTG
+AGGTCATGGATAGAAGGACACATTCATGTTATTTTTTTCTAATGGTTAAGTAATTATTTG
+ctcttactctcaaaatttctgccaaggcctcccatggaccaaactcaactagaatctagg
+aagcagagaacctgagtgttgcattcagcagaagtcagcttcctagggaatcttgcagga
+agggtgaaggtagagaatctggtggggaagcaagcaaatgcccatcacaTGCACTTTCCT
+ccaacagagcgactcagatgctataaaacttgctaacacagtctcagggtctgatcacag
+taacatacaatccaggttttaatcatcagaaatcacagtcctattgtcttctgcacagac
+ccaaacacacttggaggtcatgttcaatatgaatacctcacagagaaggaaatttacacg
+cgagaagtacatctgcagaaagccagctggcatgtcaaccattcaaaaactcagggtgtt
+ctggataaagaagactcaggaagacaagtatgaagcataatctgtgacattccatgcggc
+agacattagacacatacaagagagttgttggaaagcggaatttatcttcatataaacaac
+actgagctaaatctcaatatttcagatctctagaactatccatcagtgaaatggattgca
+aatacaaagagtaataccatgtcacttaagaatagaatcatggacgaggctgccacctgc
+tgttgggggccactgcagaagaaattccagaacactggactggagagcacctcactttcc
+ttacagctctaagtttctgACTCAGTGACCTGATTCACTACCATATACACAAAGACCCAC
+TTACACAAATGACTGTTCTTCACACTAGGCCCATGGAGACAGGGATAAAATTCTGAATTT
+GCTCAGATACCTTCTCCGCTACTGACATCTAGGCATTACACAATTCATCTCTTCATATTT
+AACCTTTGAAGTTTGCTACTTCTCAGAGAGACTAATGAGTAGTGAGCAAATATCCTGAAG
+CTGAGAATGCTTCTACCTCCTCTCAAAACAACGGAATATTCATCAAAACACAGCAGTTCT
+GCACTTAACTTTAGGCCTTTTCTAACACCTTGTTTCTTGGCAGTAACTGTGGCCAGAATA
+GCTCTTTCCACAGATAAAGGACCTTTTGAAAGGATAGGGTCTCTAGATAGAAAAGCAAAT
+GCCTCATTCCAGAAGGTCTTCAAGAAGAAAATGTTGTGGTGATAACAAACATAACTGATT
+ATAATCTATTCTGTGAAAAAAGCTTATGAAACAGTAGATGTGTGTATCTAGTACATAAGA
+GCTGAATGTCAATATATATATAGATATATACacacactcaaataaataatagttatctct
+aactagagaaattctagttgccttatattttcttctttttccttactatattttctacaa
+taaacatgtgtttttaacaagaaaaGTCTTTTCTGGTGTGCTTTTTAATTTTCTTTGTTT
+AAGTGAGAGTGAGGCTACATAACTACATGGCTAGGTAGACTTTTAGAAAACTTGGCTGCT
+CTAGAAAATTGACATATCCTGATTTCTTCCATAGCTTGGATCTTGACCTAGAGGGAAATA
+TAAAAGTGTTGACTTGAACCTGAGGGGTGCCATTTTCACTGCTGAAGTAGTTTCATGGAT
+CATGAATTGGAGAAATGACTTCAGCAACATGGGTGTTAAAATCAGAAAGCACAAGTGACC
+CACAACAGATGATGGAGAACAAAGAGCAAGCTGGGAAAGCAGTGGCCTTTAATACAGAAA
+AGAAGAAGTATAGCCACAATAAATATTAGGCAGACAGCAGTTCAGCAGTTTATACTATTA
+AGCTGTTGTTTAGGGGAATAGTAAACTGACATGACCCTTGAGGTAGGTATATATAGGTAA
+ATTCTATGTGTCCCTTGAAATAGGTGTATGACACAACTTCTGGCATCTACATGGATTTGG
+TCACTCTAAAGTAGCCATGAGGCTTAAGATAGTTCAGCTGTTTGGGGATAAGTTAAATCA
+TTTGCCATTGTCTTTCTGCAATTTGCATATCCTACAGTTATCATTGCCATTACTGAATGG
+CACAGAGAAAAATTCTGGTCTAAAGTGGTTCTCAAACCTGGTtgctggagggccaccctc
+agtgatgatgatttaatctgtagaagaatagaacattgatagtttttatatatctccagg
+taattttaatatataactggggtgagaatcattgACATAATTGTAACAGGATAATATTCA
+GGAAATATGGAGATAAATAATTTTCTTCTCGACATTAAAAAAATCTAATAAAAAGTTTTA
+TGTTTTCCCCTAACTCAGGGTCATCAGCCTTCAAGCTTCAGTCTCTGTGTGTTCACAGGT
+GCTGTAAACACACGCATCACTACTAATATCCCACTTCAGTGCTATTGCTGCTCCCAAAAC
+TCCAGGTATTTTTAACCTTATAAACCTCCAGAATAATGAGACCACTGGGTTCAGTAAATT
+GCTTTGTTTTGAAGCACTATTAGACAAAGTGGGAGACTAGAAGATAAATCTGTCAATGAC
+ATGTCCTTTAAGACTACTTAGATTTTGTTGAATTTGTGGATCATTCCTTACTTGAGCAAA
+TGGTAAATTAACTCTCTCTTTTCTCTCTCTCTCTAGCTGGCACACTTTTTCCAGTAGCCA
+TTCTACTTGGTATGCTTACTTATCAGCTGTCCTCCAGGGGCCTCACATTAGATGTTTCTC
+TGACTAACCAAACATGACACACAGCTGAAGTCAGAAAAACCAGATTGATAATTTCACTCA
+AACTATTTTCCTTCATTCTAACAATTTACTGGAGTACACAATTGTGACTATTTTTAGCCA
+TAGGAACTCATAGAAAGACCAACTTCATTAGACCTACAAAATCGAATTGTGTAACAGTAT
+ATGCAGTATGTGTAGGAATAAAAAGCATTTCTCAAATATGCAGTACTGGATTTTGCAAAA
+GCACCTTACACTTAGCTATAAAGGAGTGGAAAACACAAAGATGAGTAACTGCACTTTTCA
+AAAGACTAGAGCTATACCAATAATACAAAGGTGTAAACAAATAATGATGAGATGACAAAG
+GCTGAGTGTTTTCTATTTGGAAGCTATGTTGTTGAGTTATTTATGTATATAATTTCATGC
+AATCTTCATGTTATGGGGATGTTctaatccactgtgactctgtccttaaataaaagggag
+atttggacatagagagaggcacacggggaggatgccatatgagaattgacactgtgctgt
+cacaagccaaggaactactggaaggagagaaagaggactggaacagttccttccttagca
+ccttttcaggcagcctagccctgccagcttcttgatctggacttctcacctctagaattg
+tgaggcaataaatctctgttgcttaagttacccagtttgtggtaccttattacaggagcc
+ctaggaaaataattcaTTATataatctgctaaggtagatatgatcattgtctccaatttc
+catatgaagaaactatgcctcaggcattgtgtcagttgtccaaaatcatacattcctgac
+tcacttcaatgaattcttcattcagcaaaatttttaaggtaccttaaaaaaattatgtta
+actcttagggccttgctttaaagcttcaatgggcttttcctttgcaaagaataaaatcct
+aatacttaagcatagctctctttcctggctatgtttctgacatcctcttgtaccatgctc
+ctccttaatcattctgaggttacatcttaagtcctttccccttgccattcccacttcttg
+gaatactttcccatcaactcttcaaagaactgccttctttaagtatttggtctcagttcc
+aatgtcacttccctgtaaaagcttcctggccatcaagccttctttacacactctatttta
+ttttttcatggttcctataacaacctaatatattctcaattgattaactgttttgctgaa
+tactgccttccataagaatggaaagaaaacatggccaggtgcagtggctcacacctgtaa
+tcccaccacttcaggaggctgaggcaacatggcaaaaccttctcttcaaaaaatttttta
+aaagttagctggatgttgtggaggcaagaggatcacttgaggatcacttgagtccatgag
+gtcaaggctgcagtgagtcatgtttgcaccactgcactctagcctaggtgacagagctag
+tcactatcaaaaaaaaaaaaaaaagaatggagagaatgctacatgagagaaaggatctta
+tctatcatgttcacctcccaagaggtgaacatatcccccaaagcctgatagagagaagat
+gctcattaatatttaatgcatgaCCATGTGCAGACTTGGGAGGAAAAATATGCCTCAGCC
+TATCAATATTGGATCCTTAATAAACAAGGATGTTTCTGCATCATTTCCCCACAACACCGA
+ACAAGTGTGGCTCACTGTGGATGTTTAAGCAAATGCATTGTTTTTCCAGTTATATATCTG
+GTAGAGATGAGGCCATTGATAGGAATGGGAAGACGATCTCCTTTTATTTTGATGACCCAG
+CATGGCTGAACACTCAGTGACTACCACTGCACTTTGTTGTACTTTCAGCATTAGAGATGC
+CAGCCCTGTAGGATATAAAACAGGAACATCTAGTCCTCAATTATATTCAGAATTACTCAA
+GTCTTAGAAGCACCACTTGTCTTTTTTCAAGGGAGAGAAATGCTCAAGTGATGGGCTGAA
+GTGAAGGGAGGGAGTCACTCACTTGAACGGTTCCCTTAGGCTGTGTGGATGCAAACAGCA
+TTAGACAATGACACTGACAGTGGGAAATGCACTGGAGACGATGACTGGCAAAGCCCTCCT
+TTTCTCCCCATCCACTATAGATACTGACAGCAAAGGGTTTGTCACAATGACAACTATACA
+CTCCCAATATCACAGAAGAAGGAGGAATAAAAGGGTATATTATGAGTGACTGAAGTTTAG
+AATAAATTAATAAATATTATGTCCCTCATCCATAGAAACCACAAAGGTCTAGTAAGGCTA
+AGGATATAACAAGAAAATAATATGAATATTTGCTTCCCCTTCCTAGTGTAATAGAGTAAG
+TTACAAATGGCTTCAGGAAGGGGAGAGAGGAAGAAGAGTGGATGAGATACGTAAGAGTGC
+TTGAGGGCTAATTTTATGAAAGCTTTGGGAAGTTTTAAGAAAAAGAAAAGCTATTTTTCA
+AGGTACAtgtgtgtatgcgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgtgAAA
+GACAGAAGAAAGAGGGAGACCTTAGAAGACTATGAGACACTAAGAGAAAAATTAAGGTAA
+AAAAGACACACACTTAGAAAAACACACATAGGGAGGAGGGAGGAGGTTAAGACATTTTAC
+TATGTGCTGTGAATGGAAACTACAAACCATTTTTGATatatgcaatatatatacatatat
+acacacatatacatatGTATTTAAATATTTAAATTACAttttctctttttttagagatat
+ggtttcactatgtcactctgcccaggctgcagtacagtggttgttcacagtcatgatcat
+agcacattatagccttgaactcctgggctcaagcaaccctcctgtattagtctccccagt
+agttgggattactagcatatgccaccatgtccACCTTTATGCTTTTTAAAGTGAAAAACC
+ATACTAAGAATGAGGCAGCTCAACTTAATAATAAAAACATTTCAAATGtaaagaaattta
+caaaagaaaaacaatcaaccccattaaaattgggcaaagg
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA.fasta.amb b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.amb
new file mode 100644
index 0000000..986e6d6
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.amb
@@ -0,0 +1 @@
+100000 1 0
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA.fasta.ann b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.ann
new file mode 100644
index 0000000..642ddb6
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.ann
@@ -0,0 +1,3 @@
+100000 1 11
+0 chr1 (null)
+0 100000 0
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA.fasta.bwt b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.bwt
new file mode 100644
index 0000000..fe74222
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.bwt differ
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA.fasta.fai b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.fai
new file mode 100644
index 0000000..1cc63a5
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.fai
@@ -0,0 +1 @@
+chr1 100000 6 60 61
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA.fasta.pac b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.pac
new file mode 100644
index 0000000..b0f55c0
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.pac differ
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA.fasta.rbwt b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.rbwt
new file mode 100644
index 0000000..f623b8c
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.rbwt differ
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA.fasta.rpac b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.rpac
new file mode 100644
index 0000000..b88ff49
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.rpac differ
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA.fasta.rsa b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.rsa
new file mode 100644
index 0000000..6e7e213
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.rsa differ
diff --git a/public/gatk-engine/src/test/resources/exampleFASTA.fasta.sa b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.sa
new file mode 100644
index 0000000..d6db971
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleFASTA.fasta.sa differ
diff --git a/public/gatk-engine/src/test/resources/exampleGATKReport.eval b/public/gatk-engine/src/test/resources/exampleGATKReport.eval
new file mode 100644
index 0000000..3d43c81
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleGATKReport.eval
@@ -0,0 +1,36 @@
+##:GATKReport.v0.1 CompOverlap : The overlap between eval and comp sites
+CompOverlap CompRod EvalRod JexlExpression Novelty nEvalVariants nCompVariants novelSites nVariantsAtComp compRate nConcordant concordantRate
+CompOverlap none eval none all 0 0 0 0 0.00000000 0 0.00000000
+CompOverlap none eval none known 0 0 0 0 0.00000000 0 0.00000000
+CompOverlap none eval none novel 0 0 0 0 0.00000000 0 0.00000000
+
+##:GATKReport.v0.1 CountVariants : Counts different classes of variants in the sample
+CountVariants CompRod EvalRod JexlExpression Novelty nProcessedLoci nCalledLoci nRefLoci nVariantLoci variantRate variantRatePerBp nSNPs nMNPs nInsertions nDeletions nComplex nNoCalls nHets nHomRef nHomVar nSingletons heterozygosity heterozygosityPerBp hetHomRatio indelRate indelRatePerBp deletionInsertionRatio
+CountVariants none eval none all 100000 100000 100000 0 0.00000000 0.00000000 0 0 0 0 0 99872 0 128 0 0 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+CountVariants none eval none known 100000 0 0 0 0.00000000 0.00000000 0 0 0 0 0 0 0 0 0 0 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+CountVariants none eval none novel 100000 100000 100000 0 0.00000000 0.00000000 0 0 0 0 0 99872 0 128 0 0 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000
+
+##:GATKReport.v0.1 SimpleMetricsByAC.metrics : TiTv by allele count
+SimpleMetricsByAC.metrics CompRod EvalRod JexlExpression Novelty row AC nTi nTv n TiTv
+SimpleMetricsByAC.metrics none eval none all ac0 0 0 0 0 0.0
+SimpleMetricsByAC.metrics none eval none all ac1 1 0 0 0 0.0
+SimpleMetricsByAC.metrics none eval none all ac2 2 0 0 0 0.0
+SimpleMetricsByAC.metrics none eval none known ac0 0 0 0 0 0.0
+SimpleMetricsByAC.metrics none eval none known ac1 1 0 0 0 0.0
+SimpleMetricsByAC.metrics none eval none known ac2 2 0 0 0 0.0
+SimpleMetricsByAC.metrics none eval none novel ac0 0 0 0 0 0.0
+SimpleMetricsByAC.metrics none eval none novel ac1 1 0 0 0 0.0
+SimpleMetricsByAC.metrics none eval none novel ac2 2 0 0 0 0.0
+
+##:GATKReport.v0.1 TiTvVariantEvaluator : Ti/Tv Variant Evaluator
+TiTvVariantEvaluator CompRod EvalRod JexlExpression Novelty nTi nTv tiTvRatio nTiInComp nTvInComp TiTvRatioStandard
+TiTvVariantEvaluator none eval none all 0 0 0.00000000 0 0 0.00000000
+TiTvVariantEvaluator none eval none known 0 0 0.00000000 0 0 0.00000000
+TiTvVariantEvaluator none eval none novel 0 0 0.00000000 0 0 0.00000000
+
+##:GATKReport.v0.1 ValidationReport : Assess site accuracy and sensitivity of callset against follow-up validation assay
+ValidationReport CompRod EvalRod JexlExpression Novelty nComp TP FP FN TN sensitivity PPV FDR CompMonoEvalNoCall CompMonoEvalFiltered CompMonoEvalMono CompMonoEvalPoly CompPolyEvalNoCall CompPolyEvalFiltered CompPolyEvalMono CompPolyEvalPoly CompFiltered nDifferentAlleleSites
+ValidationReport none eval none all 0 0 0 0 0 NaN NaN NaN 0 0 0 0 0 0 0 0 0 0
+ValidationReport none eval none known 0 0 0 0 0 NaN NaN NaN 0 0 0 0 0 0 0 0 0 0
+ValidationReport none eval none novel 0 0 0 0 0 NaN NaN NaN 0 0 0 0 0 0 0 0 0 0
+
diff --git a/public/gatk-engine/src/test/resources/exampleGATKReportv1.tbl b/public/gatk-engine/src/test/resources/exampleGATKReportv1.tbl
new file mode 100644
index 0000000..1002274
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleGATKReportv1.tbl
@@ -0,0 +1,36 @@
+#:GATKReport.v1.0:5
+#:GATKTable:false:11:3:%s:%s:%s:%s:%s:%s:%s:%s:%.2f:%s:%.2f
+#:GATKTable:CompOverlap:The overlap between eval and comp sites
+CompOverlap CompRod EvalRod JexlExpression Novelty nEvalVariants novelSites nVariantsAtComp compRate nConcordant concordantRate
+CompOverlap dbsnp eval none all 481 12 469 97.51 468 99.79
+CompOverlap dbsnp eval none known 469 0 469 100.00 468 99.79
+CompOverlap dbsnp eval none novel 12 12 0 0.00 0 0.00
+
+#:GATKTable:false:30:3:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%.2e:%.2f:%.2f:%.2e:%.2f:%.2f
+#:GATKTable:CountVariants:Counts different classes of variants in the sample
+CountVariants CompRod EvalRod JexlExpression Novelty nProcessedLoci nCalledLoci nRefLoci nVariantLoci variantRate variantRatePerBp nSNPs nMNPs nInsertions nDeletions nComplex nSymbolic nMixed nNoCalls nHets nHomRef nHomVar nSingletons nHomDerived heterozygosity heterozygosityPerBp hetHomRatio indelRate indelRatePerBp deletionInsertionRatio
+CountVariants dbsnp eval none all 63025520 481 0 481 7.63182913841885E-6 131030.0 481 0 0 0 0 0 0 0 298 0 183 298 0 4.73e-06 211495.00 1.63 0.00e+00 0.00 0.00
+CountVariants dbsnp eval none known 63025520 469 0 469 7.441430074674513E-6 134382.0 469 0 0 0 0 0 0 0 288 0 181 288 0 4.57e-06 218838.00 1.59 0.00e+00 0.00 0.00
+CountVariants dbsnp eval none novel 63025520 12 0 12 1.9039906374433722E-7 5252126.0 12 0 0 0 0 0 0 0 10 0 2 10 0 1.59e-07 6302552.00 5.00 0.00e+00 0.00 0.00
+
+#:GATKTable:false:14:3:%s:%s:%s:%s:%s:%s:%s:%.2f:%s:%s:%.2f:%s:%s:%.2f
+#:GATKTable:TiTvVariantEvaluator:Ti/Tv Variant Evaluator
+TiTvVariantEvaluator CompRod EvalRod JexlExpression Novelty nTi nTv tiTvRatio nTiInComp nTvInComp TiTvRatioStandard nTiDerived nTvDerived tiTvDerivedRatio
+TiTvVariantEvaluator dbsnp eval none all 382 99 3.86 203506 85497 2.38 0 0 0.00
+TiTvVariantEvaluator dbsnp eval none known 374 95 3.94 360 91 3.96 0 0 0.00
+TiTvVariantEvaluator dbsnp eval none novel 8 4 2.00 203146 85406 2.38 0 0 0.00
+
+#:GATKTable:false:24:3:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%.2f:%.2f:%.2f:%.2f:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s
+#:GATKTable:ValidationReport:Assess site accuracy and sensitivity of callset against follow-up validation assay
+ValidationReport CompRod EvalRod JexlExpression Novelty nComp TP FP FN TN sensitivity specificity PPV FDR CompMonoEvalNoCall CompMonoEvalFiltered CompMonoEvalMono CompMonoEvalPoly CompPolyEvalNoCall CompPolyEvalFiltered CompPolyEvalMono CompPolyEvalPoly CompFiltered nDifferentAlleleSites
+ValidationReport dbsnp eval none all 369102 469 0 368633 0 0.13 100.00 100.00 0.00 0 0 0 0 368633 0 0 469 0 0
+ValidationReport dbsnp eval none known 469 469 0 0 0 100.00 100.00 100.00 0.00 0 0 0 0 0 0 0 469 0 0
+ValidationReport dbsnp eval none novel 368633 0 0 368633 0 0.00 100.00 NaN NaN 0 0 0 0 368633 0 0 0 0 0
+
+#:GATKTable:false:20:3:%s:%s:%s:%s:%s:%s:%s:%s:%.2f:%s:%s:%.2f:%.1f:%s:%s:%s:%.1f:%s:%s:%s
+#:GATKTable:VariantSummary:1000 Genomes Phase I summary of variants table
+VariantSummary CompRod EvalRod JexlExpression Novelty nSamples nProcessedLoci nSNPs TiTvRatio SNPNoveltyRate nSNPsPerSample TiTvRatioPerSample SNPDPPerSample nIndels IndelNoveltyRate nIndelsPerSample IndelDPPerSample nSVs SVNoveltyRate nSVsPerSample
+VariantSummary dbsnp eval none all 1 63025520 481 3.86 0.02 481 3.86 481.0 0 NA 0 0.0 0 NA 0
+VariantSummary dbsnp eval none known 1 63025520 469 3.94 0.00 469 3.94 469.0 0 NA 0 0.0 0 NA 0
+VariantSummary dbsnp eval none novel 1 63025520 12 2.00 1.00 12 2.00 12.0 0 NA 0 0.0 0 NA 0
+
diff --git a/public/gatk-engine/src/test/resources/exampleGATKReportv2.tbl b/public/gatk-engine/src/test/resources/exampleGATKReportv2.tbl
new file mode 100644
index 0000000..8b300a1
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleGATKReportv2.tbl
@@ -0,0 +1,36 @@
+#:GATKReport.v1.1:5
+#:GATKTable:11:3:%s:%s:%s:%s:%s:%s:%s:%s:%.2f:%s:%.2f
+#:GATKTable:CompOverlap:The overlap between eval and comp sites
+CompOverlap CompRod EvalRod JexlExpression Novelty nEvalVariants novelSites nVariantsAtComp compRate nConcordant concordantRate
+CompOverlap dbsnp eval none all 481 12 469 97.51 468 99.79
+CompOverlap dbsnp eval none known 469 0 469 100.00 468 99.79
+CompOverlap dbsnp eval none novel 12 12 0 0.00 0 0.00
+
+#:GATKTable:30:3:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%.2e:%.2f:%.2f:%.2e:%.2f:%.2f
+#:GATKTable:CountVariants:Counts different classes of variants in the sample
+CountVariants CompRod EvalRod JexlExpression Novelty nProcessedLoci nCalledLoci nRefLoci nVariantLoci variantRate variantRatePerBp nSNPs nMNPs nInsertions nDeletions nComplex nSymbolic nMixed nNoCalls nHets nHomRef nHomVar nSingletons nHomDerived heterozygosity heterozygosityPerBp hetHomRatio indelRate indelRatePerBp deletionInsertionRatio
+CountVariants dbsnp eval none all 63025520 481 0 481 7.63182913841885E-6 131030.0 481 0 0 0 0 0 0 0 298 0 183 298 0 4.73e-06 211495.00 1.63 0.00e+00 0.00 0.00
+CountVariants dbsnp eval none known 63025520 469 0 469 7.441430074674513E-6 134382.0 469 0 0 0 0 0 0 0 288 0 181 288 0 4.57e-06 218838.00 1.59 0.00e+00 0.00 0.00
+CountVariants dbsnp eval none novel 63025520 12 0 12 1.9039906374433722E-7 5252126.0 12 0 0 0 0 0 0 0 10 0 2 10 0 1.59e-07 6302552.00 5.00 0.00e+00 0.00 0.00
+
+#:GATKTable:14:3:%s:%s:%s:%s:%s:%s:%s:%.2f:%s:%s:%.2f:%s:%s:%.2f
+#:GATKTable:TiTvVariantEvaluator:Ti/Tv Variant Evaluator
+TiTvVariantEvaluator CompRod EvalRod JexlExpression Novelty nTi nTv tiTvRatio nTiInComp nTvInComp TiTvRatioStandard nTiDerived nTvDerived tiTvDerivedRatio
+TiTvVariantEvaluator dbsnp eval none all 382 99 3.86 203506 85497 2.38 0 0 0.00
+TiTvVariantEvaluator dbsnp eval none known 374 95 3.94 360 91 3.96 0 0 0.00
+TiTvVariantEvaluator dbsnp eval none novel 8 4 2.00 203146 85406 2.38 0 0 0.00
+
+#:GATKTable:24:3:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%.2f:%.2f:%.2f:%.2f:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s
+#:GATKTable:ValidationReport:Assess site accuracy and sensitivity of callset against follow-up validation assay
+ValidationReport CompRod EvalRod JexlExpression Novelty nComp TP FP FN TN sensitivity specificity PPV FDR CompMonoEvalNoCall CompMonoEvalFiltered CompMonoEvalMono CompMonoEvalPoly CompPolyEvalNoCall CompPolyEvalFiltered CompPolyEvalMono CompPolyEvalPoly CompFiltered nDifferentAlleleSites
+ValidationReport dbsnp eval none all 369102 469 0 368633 0 0.13 100.00 100.00 0.00 0 0 0 0 368633 0 0 469 0 0
+ValidationReport dbsnp eval none known 469 469 0 0 0 100.00 100.00 100.00 0.00 0 0 0 0 0 0 0 469 0 0
+ValidationReport dbsnp eval none novel 368633 0 0 368633 0 0.00 100.00 NaN NaN 0 0 0 0 368633 0 0 0 0 0
+
+#:GATKTable:20:3:%s:%s:%s:%s:%s:%s:%s:%s:%.2f:%s:%s:%.2f:%.1f:%s:%s:%s:%.1f:%s:%s:%s
+#:GATKTable:VariantSummary:1000 Genomes Phase I summary of variants table
+VariantSummary CompRod EvalRod JexlExpression Novelty nSamples nProcessedLoci nSNPs TiTvRatio SNPNoveltyRate nSNPsPerSample TiTvRatioPerSample SNPDPPerSample nIndels IndelNoveltyRate nIndelsPerSample IndelDPPerSample nSVs SVNoveltyRate nSVsPerSample
+VariantSummary dbsnp eval none all 1 63025520 481 3.86 0.02 481 3.86 481.0 0 NA 0 0.0 0 NA 0
+VariantSummary dbsnp eval none known 1 63025520 469 3.94 0.00 469 3.94 469.0 0 NA 0 0.0 0 NA 0
+VariantSummary dbsnp eval none novel 1 63025520 12 2.00 1.00 12 2.00 12.0 0 NA 0 0.0 0 NA 0
+
diff --git a/public/gatk-engine/src/test/resources/exampleGRP.grp b/public/gatk-engine/src/test/resources/exampleGRP.grp
new file mode 100644
index 0000000..61a10ac
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleGRP.grp
@@ -0,0 +1,1118 @@
+#:GATKReport.v1.1:5
+#:GATKTable:2:18:%s:%s:;
+#:GATKTable:Arguments:Recalibration argument collection values used in this run
+Argument Value
+binary_tag_name null
+covariate ReadGroupCovariate,QualityScoreCovariate,ContextCovariate,CycleCovariate
+default_platform null
+deletions_default_quality 45
+force_platform null
+indels_context_size 3
+insertions_default_quality 45
+low_quality_tail 2
+maximum_cycle_value 500
+mismatches_context_size 2
+mismatches_default_quality -1
+no_standard_covs false
+plot_pdf_file null
+quantizing_levels 16
+recalibration_report null
+run_without_dbsnp false
+solid_nocall_strategy THROW_EXCEPTION
+solid_recal_mode SET_Q_ZERO
+
+#:GATKTable:3:94:%s:%s:%s:;
+#:GATKTable:Quantized:Quality quantization map
+QualityScore Count QuantizedScore
+ 0 0 8
+ 1 0 8
+ 2 0 8
+ 3 0 8
+ 4 0 8
+ 5 0 8
+ 6 11 8
+ 7 0 8
+ 8 7 8
+ 9 4 8
+ 10 1 8
+ 11 2 8
+ 12 4 19
+ 13 3 19
+ 14 1 19
+ 15 5 19
+ 16 10 19
+ 17 6 19
+ 18 7 19
+ 19 15 19
+ 20 5 19
+ 21 17 19
+ 22 9 19
+ 23 15 23
+ 24 20 24
+ 25 15 13
+ 26 6 13
+ 27 22 27
+ 28 15 28
+ 29 20 29
+ 30 20 30
+ 31 25 31
+ 32 32 32
+ 33 35 33
+ 34 36 34
+ 35 0 93
+ 36 0 93
+ 37 0 93
+ 38 0 93
+ 39 0 93
+ 40 0 93
+ 41 0 93
+ 42 0 93
+ 43 0 93
+ 44 0 93
+ 45 736 45
+ 46 0 93
+ 47 0 93
+ 48 0 93
+ 49 0 93
+ 50 0 93
+ 51 0 93
+ 52 0 93
+ 53 0 93
+ 54 0 93
+ 55 0 93
+ 56 0 93
+ 57 0 93
+ 58 0 93
+ 59 0 93
+ 60 0 93
+ 61 0 93
+ 62 0 93
+ 63 0 93
+ 64 0 93
+ 65 0 93
+ 66 0 93
+ 67 0 93
+ 68 0 93
+ 69 0 93
+ 70 0 93
+ 71 0 93
+ 72 0 93
+ 73 0 93
+ 74 0 93
+ 75 0 93
+ 76 0 93
+ 77 0 93
+ 78 0 93
+ 79 0 93
+ 80 0 93
+ 81 0 93
+ 82 0 93
+ 83 0 93
+ 84 0 93
+ 85 0 93
+ 86 0 93
+ 87 0 93
+ 88 0 93
+ 89 0 93
+ 90 0 93
+ 91 0 93
+ 92 0 93
+ 93 0 93
+
+#:GATKTable:6:3:%s:%s:%.4f:%.4f:%d:%.2f:;
+#:GATKTable:RecalTable0:
+ReadGroup EventType EmpiricalQuality EstimatedQReported Observations Errors
+exampleBAM.bam M 17.0000 17.4959 368 11.00
+exampleBAM.bam I 45.0000 45.0000 368 0.00
+exampleBAM.bam D 45.0000 45.0000 368 0.00
+
+#:GATKTable:6:30:%s:%s:%s:%.4f:%d:%.2f:;
+#:GATKTable:RecalTable1:
+ReadGroup QualityScore EventType EmpiricalQuality Observations Errors
+exampleBAM.bam 6 M 6.0000 11 3.00
+exampleBAM.bam 8 M 8.0000 7 1.00
+exampleBAM.bam 9 M 9.0000 4 0.00
+exampleBAM.bam 10 M 10.0000 1 0.00
+exampleBAM.bam 11 M 11.0000 2 1.00
+exampleBAM.bam 12 M 12.0000 4 0.00
+exampleBAM.bam 13 M 13.0000 3 0.00
+exampleBAM.bam 14 M 14.0000 1 0.00
+exampleBAM.bam 15 M 15.0000 5 0.00
+exampleBAM.bam 16 M 16.0000 10 1.00
+exampleBAM.bam 17 M 17.0000 6 1.00
+exampleBAM.bam 18 M 18.0000 7 1.00
+exampleBAM.bam 19 M 19.0000 15 1.00
+exampleBAM.bam 20 M 20.0000 5 1.00
+exampleBAM.bam 21 M 21.0000 17 0.00
+exampleBAM.bam 22 M 22.0000 9 0.00
+exampleBAM.bam 23 M 23.0000 15 0.00
+exampleBAM.bam 24 M 24.0000 20 1.00
+exampleBAM.bam 25 M 25.0000 15 0.00
+exampleBAM.bam 26 M 26.0000 6 0.00
+exampleBAM.bam 27 M 27.0000 22 0.00
+exampleBAM.bam 28 M 28.0000 15 0.00
+exampleBAM.bam 29 M 29.0000 20 0.00
+exampleBAM.bam 30 M 30.0000 20 0.00
+exampleBAM.bam 31 M 31.0000 25 0.00
+exampleBAM.bam 32 M 32.0000 32 0.00
+exampleBAM.bam 33 M 33.0000 35 0.00
+exampleBAM.bam 34 M 34.0000 36 0.00
+exampleBAM.bam 45 I 45.0000 368 0.00
+exampleBAM.bam 45 D 45.0000 368 0.00
+
+#:GATKTable:8:952:%s:%s:%s:%s:%s:%.4f:%d:%.2f:;
+#:GATKTable:RecalTable2:
+ReadGroup QualityScore CovariateValue CovariateName EventType EmpiricalQuality Observations Errors
+exampleBAM.bam 6 AA Context M 6.0000 1 0.00
+exampleBAM.bam 6 GA Context M 6.0000 1 0.00
+exampleBAM.bam 6 GC Context M 6.0000 2 2.00
+exampleBAM.bam 6 TG Context M 6.0000 1 0.00
+exampleBAM.bam 6 AT Context M 6.0000 1 0.00
+exampleBAM.bam 6 CT Context M 6.0000 1 0.00
+exampleBAM.bam 6 GT Context M 6.0000 2 0.00
+exampleBAM.bam 6 TT Context M 6.0000 2 1.00
+exampleBAM.bam 8 AA Context M 8.0000 1 0.00
+exampleBAM.bam 8 GA Context M 8.0000 2 0.00
+exampleBAM.bam 8 GC Context M 8.0000 1 0.00
+exampleBAM.bam 8 TG Context M 8.0000 1 1.00
+exampleBAM.bam 8 GT Context M 8.0000 2 0.00
+exampleBAM.bam 9 TG Context M 9.0000 1 0.00
+exampleBAM.bam 9 AT Context M 9.0000 1 0.00
+exampleBAM.bam 9 CT Context M 9.0000 1 0.00
+exampleBAM.bam 9 GT Context M 9.0000 1 0.00
+exampleBAM.bam 10 TT Context M 10.0000 1 0.00
+exampleBAM.bam 11 TC Context M 11.0000 1 1.00
+exampleBAM.bam 11 GT Context M 11.0000 1 0.00
+exampleBAM.bam 12 GA Context M 12.0000 1 0.00
+exampleBAM.bam 12 CC Context M 12.0000 1 0.00
+exampleBAM.bam 12 TC Context M 12.0000 1 0.00
+exampleBAM.bam 12 AG Context M 12.0000 1 0.00
+exampleBAM.bam 13 AA Context M 13.0000 1 0.00
+exampleBAM.bam 13 AG Context M 13.0000 1 0.00
+exampleBAM.bam 13 AT Context M 13.0000 1 0.00
+exampleBAM.bam 14 GA Context M 14.0000 1 0.00
+exampleBAM.bam 15 AA Context M 15.0000 2 0.00
+exampleBAM.bam 15 GA Context M 15.0000 1 0.00
+exampleBAM.bam 15 GT Context M 15.0000 2 0.00
+exampleBAM.bam 16 AA Context M 16.0000 1 0.00
+exampleBAM.bam 16 TA Context M 16.0000 4 1.00
+exampleBAM.bam 16 TC Context M 16.0000 1 0.00
+exampleBAM.bam 16 GG Context M 16.0000 1 0.00
+exampleBAM.bam 16 TG Context M 16.0000 1 0.00
+exampleBAM.bam 16 CT Context M 16.0000 1 0.00
+exampleBAM.bam 16 GT Context M 16.0000 1 0.00
+exampleBAM.bam 17 CA Context M 17.0000 1 0.00
+exampleBAM.bam 17 TA Context M 17.0000 1 0.00
+exampleBAM.bam 17 TG Context M 17.0000 1 1.00
+exampleBAM.bam 17 GT Context M 17.0000 1 0.00
+exampleBAM.bam 17 TT Context M 17.0000 2 0.00
+exampleBAM.bam 18 AC Context M 18.0000 1 0.00
+exampleBAM.bam 18 TC Context M 18.0000 1 1.00
+exampleBAM.bam 18 AT Context M 18.0000 1 0.00
+exampleBAM.bam 18 GT Context M 18.0000 1 0.00
+exampleBAM.bam 18 TT Context M 18.0000 2 0.00
+exampleBAM.bam 19 AA Context M 19.0000 2 0.00
+exampleBAM.bam 19 CA Context M 19.0000 2 0.00
+exampleBAM.bam 19 GA Context M 19.0000 2 0.00
+exampleBAM.bam 19 TA Context M 19.0000 3 0.00
+exampleBAM.bam 19 GC Context M 19.0000 1 0.00
+exampleBAM.bam 19 GG Context M 19.0000 1 0.00
+exampleBAM.bam 19 TG Context M 19.0000 2 1.00
+exampleBAM.bam 19 GT Context M 19.0000 1 0.00
+exampleBAM.bam 19 TT Context M 19.0000 1 0.00
+exampleBAM.bam 20 AA Context M 20.0000 1 0.00
+exampleBAM.bam 20 CA Context M 20.0000 1 0.00
+exampleBAM.bam 20 CC Context M 20.0000 1 0.00
+exampleBAM.bam 20 TG Context M 20.0000 1 0.00
+exampleBAM.bam 20 TT Context M 20.0000 1 1.00
+exampleBAM.bam 21 CA Context M 21.0000 1 0.00
+exampleBAM.bam 21 GA Context M 21.0000 1 0.00
+exampleBAM.bam 21 TA Context M 21.0000 1 0.00
+exampleBAM.bam 21 CC Context M 21.0000 1 0.00
+exampleBAM.bam 21 TC Context M 21.0000 2 0.00
+exampleBAM.bam 21 AG Context M 21.0000 1 0.00
+exampleBAM.bam 21 GG Context M 21.0000 4 0.00
+exampleBAM.bam 21 TG Context M 21.0000 1 0.00
+exampleBAM.bam 21 AT Context M 21.0000 2 0.00
+exampleBAM.bam 21 CT Context M 21.0000 1 0.00
+exampleBAM.bam 21 GT Context M 21.0000 2 0.00
+exampleBAM.bam 22 CA Context M 22.0000 1 0.00
+exampleBAM.bam 22 GA Context M 22.0000 3 0.00
+exampleBAM.bam 22 TA Context M 22.0000 1 0.00
+exampleBAM.bam 22 GC Context M 22.0000 1 0.00
+exampleBAM.bam 22 GG Context M 22.0000 1 0.00
+exampleBAM.bam 22 TG Context M 22.0000 1 0.00
+exampleBAM.bam 22 TT Context M 22.0000 1 0.00
+exampleBAM.bam 23 AA Context M 23.0000 1 0.00
+exampleBAM.bam 23 CA Context M 23.0000 1 0.00
+exampleBAM.bam 23 TA Context M 23.0000 1 0.00
+exampleBAM.bam 23 CC Context M 23.0000 2 0.00
+exampleBAM.bam 23 GC Context M 23.0000 1 0.00
+exampleBAM.bam 23 TC Context M 23.0000 2 0.00
+exampleBAM.bam 23 GG Context M 23.0000 1 0.00
+exampleBAM.bam 23 TG Context M 23.0000 3 0.00
+exampleBAM.bam 23 AT Context M 23.0000 1 0.00
+exampleBAM.bam 23 TT Context M 23.0000 2 0.00
+exampleBAM.bam 24 CA Context M 24.0000 3 0.00
+exampleBAM.bam 24 GA Context M 24.0000 2 0.00
+exampleBAM.bam 24 TA Context M 24.0000 2 1.00
+exampleBAM.bam 24 GC Context M 24.0000 1 0.00
+exampleBAM.bam 24 AG Context M 24.0000 2 0.00
+exampleBAM.bam 24 CG Context M 24.0000 1 0.00
+exampleBAM.bam 24 GG Context M 24.0000 3 0.00
+exampleBAM.bam 24 AT Context M 24.0000 1 0.00
+exampleBAM.bam 24 CT Context M 24.0000 1 0.00
+exampleBAM.bam 24 GT Context M 24.0000 1 0.00
+exampleBAM.bam 24 TT Context M 24.0000 3 0.00
+exampleBAM.bam 25 AA Context M 25.0000 2 0.00
+exampleBAM.bam 25 CA Context M 25.0000 1 0.00
+exampleBAM.bam 25 GG Context M 25.0000 2 0.00
+exampleBAM.bam 25 TG Context M 25.0000 2 0.00
+exampleBAM.bam 25 AT Context M 25.0000 2 0.00
+exampleBAM.bam 25 GT Context M 25.0000 1 0.00
+exampleBAM.bam 25 TT Context M 25.0000 5 0.00
+exampleBAM.bam 26 TA Context M 26.0000 1 0.00
+exampleBAM.bam 26 GG Context M 26.0000 1 0.00
+exampleBAM.bam 26 TG Context M 26.0000 1 0.00
+exampleBAM.bam 26 AT Context M 26.0000 1 0.00
+exampleBAM.bam 26 GT Context M 26.0000 1 0.00
+exampleBAM.bam 26 TT Context M 26.0000 1 0.00
+exampleBAM.bam 27 AA Context M 27.0000 2 0.00
+exampleBAM.bam 27 CA Context M 27.0000 1 0.00
+exampleBAM.bam 27 TA Context M 27.0000 1 0.00
+exampleBAM.bam 27 TC Context M 27.0000 2 0.00
+exampleBAM.bam 27 AG Context M 27.0000 3 0.00
+exampleBAM.bam 27 GG Context M 27.0000 3 0.00
+exampleBAM.bam 27 TG Context M 27.0000 2 0.00
+exampleBAM.bam 27 AT Context M 27.0000 4 0.00
+exampleBAM.bam 27 CT Context M 27.0000 2 0.00
+exampleBAM.bam 27 TT Context M 27.0000 2 0.00
+exampleBAM.bam 28 AA Context M 28.0000 1 0.00
+exampleBAM.bam 28 CA Context M 28.0000 1 0.00
+exampleBAM.bam 28 TA Context M 28.0000 2 0.00
+exampleBAM.bam 28 AG Context M 28.0000 3 0.00
+exampleBAM.bam 28 GG Context M 28.0000 3 0.00
+exampleBAM.bam 28 TG Context M 28.0000 1 0.00
+exampleBAM.bam 28 GT Context M 28.0000 4 0.00
+exampleBAM.bam 29 CA Context M 29.0000 1 0.00
+exampleBAM.bam 29 TA Context M 29.0000 1 0.00
+exampleBAM.bam 29 AC Context M 29.0000 1 0.00
+exampleBAM.bam 29 CC Context M 29.0000 1 0.00
+exampleBAM.bam 29 GC Context M 29.0000 1 0.00
+exampleBAM.bam 29 AG Context M 29.0000 3 0.00
+exampleBAM.bam 29 CG Context M 29.0000 1 0.00
+exampleBAM.bam 29 GG Context M 29.0000 4 0.00
+exampleBAM.bam 29 TG Context M 29.0000 1 0.00
+exampleBAM.bam 29 AT Context M 29.0000 1 0.00
+exampleBAM.bam 29 GT Context M 29.0000 1 0.00
+exampleBAM.bam 29 TT Context M 29.0000 4 0.00
+exampleBAM.bam 30 AA Context M 30.0000 2 0.00
+exampleBAM.bam 30 CA Context M 30.0000 1 0.00
+exampleBAM.bam 30 AC Context M 30.0000 4 0.00
+exampleBAM.bam 30 CC Context M 30.0000 1 0.00
+exampleBAM.bam 30 TC Context M 30.0000 2 0.00
+exampleBAM.bam 30 AG Context M 30.0000 3 0.00
+exampleBAM.bam 30 GG Context M 30.0000 1 0.00
+exampleBAM.bam 30 TG Context M 30.0000 1 0.00
+exampleBAM.bam 30 AT Context M 30.0000 2 0.00
+exampleBAM.bam 30 CT Context M 30.0000 2 0.00
+exampleBAM.bam 30 GT Context M 30.0000 1 0.00
+exampleBAM.bam 31 CA Context M 31.0000 1 0.00
+exampleBAM.bam 31 GA Context M 31.0000 1 0.00
+exampleBAM.bam 31 CC Context M 31.0000 2 0.00
+exampleBAM.bam 31 GC Context M 31.0000 2 0.00
+exampleBAM.bam 31 AG Context M 31.0000 2 0.00
+exampleBAM.bam 31 GG Context M 31.0000 6 0.00
+exampleBAM.bam 31 TG Context M 31.0000 2 0.00
+exampleBAM.bam 31 AT Context M 31.0000 2 0.00
+exampleBAM.bam 31 CT Context M 31.0000 2 0.00
+exampleBAM.bam 31 GT Context M 31.0000 1 0.00
+exampleBAM.bam 31 TT Context M 31.0000 3 0.00
+exampleBAM.bam 32 CA Context M 32.0000 2 0.00
+exampleBAM.bam 32 TA Context M 32.0000 1 0.00
+exampleBAM.bam 32 AC Context M 32.0000 1 0.00
+exampleBAM.bam 32 CC Context M 32.0000 1 0.00
+exampleBAM.bam 32 TC Context M 32.0000 1 0.00
+exampleBAM.bam 32 AG Context M 32.0000 1 0.00
+exampleBAM.bam 32 CG Context M 32.0000 1 0.00
+exampleBAM.bam 32 GG Context M 32.0000 8 0.00
+exampleBAM.bam 32 TG Context M 32.0000 3 0.00
+exampleBAM.bam 32 AT Context M 32.0000 4 0.00
+exampleBAM.bam 32 CT Context M 32.0000 2 0.00
+exampleBAM.bam 32 TT Context M 32.0000 6 0.00
+exampleBAM.bam 33 CA Context M 33.0000 2 0.00
+exampleBAM.bam 33 GA Context M 33.0000 2 0.00
+exampleBAM.bam 33 TA Context M 33.0000 1 0.00
+exampleBAM.bam 33 AC Context M 33.0000 1 0.00
+exampleBAM.bam 33 CC Context M 33.0000 2 0.00
+exampleBAM.bam 33 GC Context M 33.0000 1 0.00
+exampleBAM.bam 33 TC Context M 33.0000 3 0.00
+exampleBAM.bam 33 AG Context M 33.0000 2 0.00
+exampleBAM.bam 33 CG Context M 33.0000 1 0.00
+exampleBAM.bam 33 GG Context M 33.0000 2 0.00
+exampleBAM.bam 33 TG Context M 33.0000 5 0.00
+exampleBAM.bam 33 AT Context M 33.0000 2 0.00
+exampleBAM.bam 33 CT Context M 33.0000 4 0.00
+exampleBAM.bam 33 GT Context M 33.0000 1 0.00
+exampleBAM.bam 33 TT Context M 33.0000 4 0.00
+exampleBAM.bam 34 AA Context M 34.0000 1 0.00
+exampleBAM.bam 34 CA Context M 34.0000 3 0.00
+exampleBAM.bam 34 GA Context M 34.0000 1 0.00
+exampleBAM.bam 34 TA Context M 34.0000 2 0.00
+exampleBAM.bam 34 AC Context M 34.0000 1 0.00
+exampleBAM.bam 34 CC Context M 34.0000 1 0.00
+exampleBAM.bam 34 GC Context M 34.0000 2 0.00
+exampleBAM.bam 34 TC Context M 34.0000 6 0.00
+exampleBAM.bam 34 AG Context M 34.0000 1 0.00
+exampleBAM.bam 34 CG Context M 34.0000 1 0.00
+exampleBAM.bam 34 GG Context M 34.0000 1 0.00
+exampleBAM.bam 34 TG Context M 34.0000 4 0.00
+exampleBAM.bam 34 AT Context M 34.0000 4 0.00
+exampleBAM.bam 34 CT Context M 34.0000 2 0.00
+exampleBAM.bam 34 GT Context M 34.0000 1 0.00
+exampleBAM.bam 34 TT Context M 34.0000 5 0.00
+exampleBAM.bam 45 AAA Context I 45.0000 5 0.00
+exampleBAM.bam 45 AAA Context D 45.0000 5 0.00
+exampleBAM.bam 45 CAA Context I 45.0000 5 0.00
+exampleBAM.bam 45 CAA Context D 45.0000 5 0.00
+exampleBAM.bam 45 GAA Context I 45.0000 2 0.00
+exampleBAM.bam 45 GAA Context D 45.0000 2 0.00
+exampleBAM.bam 45 TAA Context I 45.0000 6 0.00
+exampleBAM.bam 45 TAA Context D 45.0000 6 0.00
+exampleBAM.bam 45 ACA Context I 45.0000 4 0.00
+exampleBAM.bam 45 ACA Context D 45.0000 4 0.00
+exampleBAM.bam 45 CCA Context I 45.0000 8 0.00
+exampleBAM.bam 45 CCA Context D 45.0000 8 0.00
+exampleBAM.bam 45 GCA Context I 45.0000 5 0.00
+exampleBAM.bam 45 GCA Context D 45.0000 5 0.00
+exampleBAM.bam 45 TCA Context I 45.0000 6 0.00
+exampleBAM.bam 45 TCA Context D 45.0000 6 0.00
+exampleBAM.bam 45 AGA Context I 45.0000 5 0.00
+exampleBAM.bam 45 AGA Context D 45.0000 5 0.00
+exampleBAM.bam 45 GGA Context I 45.0000 3 0.00
+exampleBAM.bam 45 GGA Context D 45.0000 3 0.00
+exampleBAM.bam 45 TGA Context I 45.0000 10 0.00
+exampleBAM.bam 45 TGA Context D 45.0000 10 0.00
+exampleBAM.bam 45 ATA Context I 45.0000 6 0.00
+exampleBAM.bam 45 ATA Context D 45.0000 6 0.00
+exampleBAM.bam 45 CTA Context I 45.0000 3 0.00
+exampleBAM.bam 45 CTA Context D 45.0000 3 0.00
+exampleBAM.bam 45 GTA Context I 45.0000 2 0.00
+exampleBAM.bam 45 GTA Context D 45.0000 2 0.00
+exampleBAM.bam 45 TTA Context I 45.0000 11 0.00
+exampleBAM.bam 45 TTA Context D 45.0000 11 0.00
+exampleBAM.bam 45 CAC Context I 45.0000 6 0.00
+exampleBAM.bam 45 CAC Context D 45.0000 6 0.00
+exampleBAM.bam 45 GAC Context I 45.0000 2 0.00
+exampleBAM.bam 45 GAC Context D 45.0000 2 0.00
+exampleBAM.bam 45 TAC Context I 45.0000 1 0.00
+exampleBAM.bam 45 TAC Context D 45.0000 1 0.00
+exampleBAM.bam 45 ACC Context I 45.0000 3 0.00
+exampleBAM.bam 45 ACC Context D 45.0000 3 0.00
+exampleBAM.bam 45 CCC Context I 45.0000 1 0.00
+exampleBAM.bam 45 CCC Context D 45.0000 1 0.00
+exampleBAM.bam 45 GCC Context I 45.0000 5 0.00
+exampleBAM.bam 45 GCC Context D 45.0000 5 0.00
+exampleBAM.bam 45 TCC Context I 45.0000 4 0.00
+exampleBAM.bam 45 TCC Context D 45.0000 4 0.00
+exampleBAM.bam 45 AGC Context I 45.0000 3 0.00
+exampleBAM.bam 45 AGC Context D 45.0000 3 0.00
+exampleBAM.bam 45 GGC Context I 45.0000 6 0.00
+exampleBAM.bam 45 GGC Context D 45.0000 6 0.00
+exampleBAM.bam 45 TGC Context I 45.0000 4 0.00
+exampleBAM.bam 45 TGC Context D 45.0000 4 0.00
+exampleBAM.bam 45 ATC Context I 45.0000 7 0.00
+exampleBAM.bam 45 ATC Context D 45.0000 7 0.00
+exampleBAM.bam 45 CTC Context I 45.0000 3 0.00
+exampleBAM.bam 45 CTC Context D 45.0000 3 0.00
+exampleBAM.bam 45 GTC Context I 45.0000 3 0.00
+exampleBAM.bam 45 GTC Context D 45.0000 3 0.00
+exampleBAM.bam 45 TTC Context I 45.0000 9 0.00
+exampleBAM.bam 45 TTC Context D 45.0000 9 0.00
+exampleBAM.bam 45 AAG Context I 45.0000 4 0.00
+exampleBAM.bam 45 AAG Context D 45.0000 4 0.00
+exampleBAM.bam 45 CAG Context I 45.0000 7 0.00
+exampleBAM.bam 45 CAG Context D 45.0000 7 0.00
+exampleBAM.bam 45 GAG Context I 45.0000 6 0.00
+exampleBAM.bam 45 GAG Context D 45.0000 6 0.00
+exampleBAM.bam 45 TAG Context I 45.0000 5 0.00
+exampleBAM.bam 45 TAG Context D 45.0000 5 0.00
+exampleBAM.bam 45 TCG Context I 45.0000 5 0.00
+exampleBAM.bam 45 TCG Context D 45.0000 5 0.00
+exampleBAM.bam 45 AGG Context I 45.0000 7 0.00
+exampleBAM.bam 45 AGG Context D 45.0000 7 0.00
+exampleBAM.bam 45 CGG Context I 45.0000 3 0.00
+exampleBAM.bam 45 CGG Context D 45.0000 3 0.00
+exampleBAM.bam 45 GGG Context I 45.0000 16 0.00
+exampleBAM.bam 45 GGG Context D 45.0000 16 0.00
+exampleBAM.bam 45 TGG Context I 45.0000 16 0.00
+exampleBAM.bam 45 TGG Context D 45.0000 16 0.00
+exampleBAM.bam 45 ATG Context I 45.0000 8 0.00
+exampleBAM.bam 45 ATG Context D 45.0000 8 0.00
+exampleBAM.bam 45 CTG Context I 45.0000 6 0.00
+exampleBAM.bam 45 CTG Context D 45.0000 6 0.00
+exampleBAM.bam 45 GTG Context I 45.0000 8 0.00
+exampleBAM.bam 45 GTG Context D 45.0000 8 0.00
+exampleBAM.bam 45 TTG Context I 45.0000 11 0.00
+exampleBAM.bam 45 TTG Context D 45.0000 11 0.00
+exampleBAM.bam 45 AAT Context I 45.0000 7 0.00
+exampleBAM.bam 45 AAT Context D 45.0000 7 0.00
+exampleBAM.bam 45 CAT Context I 45.0000 6 0.00
+exampleBAM.bam 45 CAT Context D 45.0000 6 0.00
+exampleBAM.bam 45 GAT Context I 45.0000 8 0.00
+exampleBAM.bam 45 GAT Context D 45.0000 8 0.00
+exampleBAM.bam 45 TAT Context I 45.0000 9 0.00
+exampleBAM.bam 45 TAT Context D 45.0000 9 0.00
+exampleBAM.bam 45 ACT Context I 45.0000 4 0.00
+exampleBAM.bam 45 ACT Context D 45.0000 4 0.00
+exampleBAM.bam 45 CCT Context I 45.0000 4 0.00
+exampleBAM.bam 45 CCT Context D 45.0000 4 0.00
+exampleBAM.bam 45 GCT Context I 45.0000 2 0.00
+exampleBAM.bam 45 GCT Context D 45.0000 2 0.00
+exampleBAM.bam 45 TCT Context I 45.0000 8 0.00
+exampleBAM.bam 45 TCT Context D 45.0000 8 0.00
+exampleBAM.bam 45 AGT Context I 45.0000 5 0.00
+exampleBAM.bam 45 AGT Context D 45.0000 5 0.00
+exampleBAM.bam 45 CGT Context I 45.0000 2 0.00
+exampleBAM.bam 45 CGT Context D 45.0000 2 0.00
+exampleBAM.bam 45 GGT Context I 45.0000 13 0.00
+exampleBAM.bam 45 GGT Context D 45.0000 13 0.00
+exampleBAM.bam 45 TGT Context I 45.0000 5 0.00
+exampleBAM.bam 45 TGT Context D 45.0000 5 0.00
+exampleBAM.bam 45 ATT Context I 45.0000 9 0.00
+exampleBAM.bam 45 ATT Context D 45.0000 9 0.00
+exampleBAM.bam 45 CTT Context I 45.0000 7 0.00
+exampleBAM.bam 45 CTT Context D 45.0000 7 0.00
+exampleBAM.bam 45 GTT Context I 45.0000 17 0.00
+exampleBAM.bam 45 GTT Context D 45.0000 17 0.00
+exampleBAM.bam 45 TTT Context I 45.0000 12 0.00
+exampleBAM.bam 45 TTT Context D 45.0000 12 0.00
+exampleBAM.bam 6 -4 Cycle M 6.0000 1 0.00
+exampleBAM.bam 6 31 Cycle M 6.0000 1 1.00
+exampleBAM.bam 6 36 Cycle M 6.0000 1 0.00
+exampleBAM.bam 6 -52 Cycle M 6.0000 1 1.00
+exampleBAM.bam 6 -62 Cycle M 6.0000 1 0.00
+exampleBAM.bam 6 63 Cycle M 6.0000 1 0.00
+exampleBAM.bam 6 -63 Cycle M 6.0000 1 0.00
+exampleBAM.bam 6 -65 Cycle M 6.0000 1 0.00
+exampleBAM.bam 6 67 Cycle M 6.0000 1 0.00
+exampleBAM.bam 6 -68 Cycle M 6.0000 1 1.00
+exampleBAM.bam 6 75 Cycle M 6.0000 1 0.00
+exampleBAM.bam 8 17 Cycle M 8.0000 1 0.00
+exampleBAM.bam 8 46 Cycle M 8.0000 1 0.00
+exampleBAM.bam 8 57 Cycle M 8.0000 1 1.00
+exampleBAM.bam 8 58 Cycle M 8.0000 1 0.00
+exampleBAM.bam 8 60 Cycle M 8.0000 1 0.00
+exampleBAM.bam 8 63 Cycle M 8.0000 1 0.00
+exampleBAM.bam 8 71 Cycle M 8.0000 1 0.00
+exampleBAM.bam 9 -16 Cycle M 9.0000 1 0.00
+exampleBAM.bam 9 38 Cycle M 9.0000 1 0.00
+exampleBAM.bam 9 52 Cycle M 9.0000 1 0.00
+exampleBAM.bam 9 69 Cycle M 9.0000 1 0.00
+exampleBAM.bam 10 -75 Cycle M 10.0000 1 0.00
+exampleBAM.bam 11 -20 Cycle M 11.0000 1 0.00
+exampleBAM.bam 11 -40 Cycle M 11.0000 1 1.00
+exampleBAM.bam 12 25 Cycle M 12.0000 1 0.00
+exampleBAM.bam 12 40 Cycle M 12.0000 1 0.00
+exampleBAM.bam 12 62 Cycle M 12.0000 1 0.00
+exampleBAM.bam 12 68 Cycle M 12.0000 1 0.00
+exampleBAM.bam 13 39 Cycle M 13.0000 1 0.00
+exampleBAM.bam 13 55 Cycle M 13.0000 1 0.00
+exampleBAM.bam 13 75 Cycle M 13.0000 1 0.00
+exampleBAM.bam 14 -33 Cycle M 14.0000 1 0.00
+exampleBAM.bam 15 -8 Cycle M 15.0000 1 0.00
+exampleBAM.bam 15 -14 Cycle M 15.0000 1 0.00
+exampleBAM.bam 15 35 Cycle M 15.0000 1 0.00
+exampleBAM.bam 15 68 Cycle M 15.0000 1 0.00
+exampleBAM.bam 15 74 Cycle M 15.0000 1 0.00
+exampleBAM.bam 16 7 Cycle M 16.0000 1 0.00
+exampleBAM.bam 16 19 Cycle M 16.0000 1 0.00
+exampleBAM.bam 16 -34 Cycle M 16.0000 1 1.00
+exampleBAM.bam 16 -47 Cycle M 16.0000 1 0.00
+exampleBAM.bam 16 51 Cycle M 16.0000 1 0.00
+exampleBAM.bam 16 -55 Cycle M 16.0000 1 0.00
+exampleBAM.bam 16 -58 Cycle M 16.0000 1 0.00
+exampleBAM.bam 16 -65 Cycle M 16.0000 1 0.00
+exampleBAM.bam 16 70 Cycle M 16.0000 1 0.00
+exampleBAM.bam 16 73 Cycle M 16.0000 1 0.00
+exampleBAM.bam 17 -4 Cycle M 17.0000 1 0.00
+exampleBAM.bam 17 -20 Cycle M 17.0000 1 0.00
+exampleBAM.bam 17 58 Cycle M 17.0000 1 0.00
+exampleBAM.bam 17 62 Cycle M 17.0000 1 0.00
+exampleBAM.bam 17 -63 Cycle M 17.0000 1 0.00
+exampleBAM.bam 17 -76 Cycle M 17.0000 1 1.00
+exampleBAM.bam 18 -1 Cycle M 18.0000 1 0.00
+exampleBAM.bam 18 10 Cycle M 18.0000 1 0.00
+exampleBAM.bam 18 -19 Cycle M 18.0000 1 0.00
+exampleBAM.bam 18 22 Cycle M 18.0000 1 0.00
+exampleBAM.bam 18 36 Cycle M 18.0000 1 0.00
+exampleBAM.bam 18 -56 Cycle M 18.0000 1 0.00
+exampleBAM.bam 18 -58 Cycle M 18.0000 1 1.00
+exampleBAM.bam 19 5 Cycle M 19.0000 1 0.00
+exampleBAM.bam 19 -7 Cycle M 19.0000 1 0.00
+exampleBAM.bam 19 10 Cycle M 19.0000 1 0.00
+exampleBAM.bam 19 21 Cycle M 19.0000 2 0.00
+exampleBAM.bam 19 -30 Cycle M 19.0000 1 0.00
+exampleBAM.bam 19 32 Cycle M 19.0000 1 0.00
+exampleBAM.bam 19 33 Cycle M 19.0000 1 0.00
+exampleBAM.bam 19 49 Cycle M 19.0000 1 0.00
+exampleBAM.bam 19 54 Cycle M 19.0000 1 0.00
+exampleBAM.bam 19 61 Cycle M 19.0000 1 0.00
+exampleBAM.bam 19 65 Cycle M 19.0000 1 0.00
+exampleBAM.bam 19 -70 Cycle M 19.0000 1 1.00
+exampleBAM.bam 19 -71 Cycle M 19.0000 1 0.00
+exampleBAM.bam 19 72 Cycle M 19.0000 1 0.00
+exampleBAM.bam 20 9 Cycle M 20.0000 1 0.00
+exampleBAM.bam 20 -28 Cycle M 20.0000 1 1.00
+exampleBAM.bam 20 -29 Cycle M 20.0000 1 0.00
+exampleBAM.bam 20 -57 Cycle M 20.0000 1 0.00
+exampleBAM.bam 20 69 Cycle M 20.0000 1 0.00
+exampleBAM.bam 21 -3 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 11 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 17 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 29 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 -42 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 -44 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 48 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 -50 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 59 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 -60 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 -61 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 64 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 66 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 67 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 71 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 73 Cycle M 21.0000 1 0.00
+exampleBAM.bam 21 74 Cycle M 21.0000 1 0.00
+exampleBAM.bam 22 -9 Cycle M 22.0000 1 0.00
+exampleBAM.bam 22 -15 Cycle M 22.0000 1 0.00
+exampleBAM.bam 22 -23 Cycle M 22.0000 1 0.00
+exampleBAM.bam 22 38 Cycle M 22.0000 1 0.00
+exampleBAM.bam 22 44 Cycle M 22.0000 1 0.00
+exampleBAM.bam 22 -44 Cycle M 22.0000 1 0.00
+exampleBAM.bam 22 51 Cycle M 22.0000 1 0.00
+exampleBAM.bam 22 -59 Cycle M 22.0000 1 0.00
+exampleBAM.bam 22 -70 Cycle M 22.0000 1 0.00
+exampleBAM.bam 23 -12 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 -15 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 18 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 19 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 -35 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 37 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 -38 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 56 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 59 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 61 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 64 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 -64 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 66 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 -67 Cycle M 23.0000 1 0.00
+exampleBAM.bam 23 -75 Cycle M 23.0000 1 0.00
+exampleBAM.bam 24 3 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 5 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 6 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 -6 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 -10 Cycle M 24.0000 1 1.00
+exampleBAM.bam 24 13 Cycle M 24.0000 2 0.00
+exampleBAM.bam 24 -13 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 -25 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 27 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 33 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 41 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 45 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 -48 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 -49 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 50 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 52 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 53 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 56 Cycle M 24.0000 1 0.00
+exampleBAM.bam 24 -62 Cycle M 24.0000 1 0.00
+exampleBAM.bam 25 -9 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 14 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 -21 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 -24 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 31 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 -32 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 -36 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 37 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 46 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 47 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 -51 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 -52 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 55 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 -73 Cycle M 25.0000 1 0.00
+exampleBAM.bam 25 -74 Cycle M 25.0000 1 0.00
+exampleBAM.bam 26 -3 Cycle M 26.0000 1 0.00
+exampleBAM.bam 26 7 Cycle M 26.0000 1 0.00
+exampleBAM.bam 26 20 Cycle M 26.0000 1 0.00
+exampleBAM.bam 26 -44 Cycle M 26.0000 1 0.00
+exampleBAM.bam 26 50 Cycle M 26.0000 1 0.00
+exampleBAM.bam 26 -67 Cycle M 26.0000 1 0.00
+exampleBAM.bam 27 11 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 14 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 16 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 -17 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 -18 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 22 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 -27 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 28 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 30 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 -31 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 40 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 53 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 -53 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 -55 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 -56 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 57 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 65 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 -66 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 -69 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 -72 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 -73 Cycle M 27.0000 1 0.00
+exampleBAM.bam 27 76 Cycle M 27.0000 1 0.00
+exampleBAM.bam 28 -2 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 -11 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 25 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 -27 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 30 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 34 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 39 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 -41 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 47 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 48 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 -50 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 -53 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 54 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 -61 Cycle M 28.0000 1 0.00
+exampleBAM.bam 28 -71 Cycle M 28.0000 1 0.00
+exampleBAM.bam 29 4 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -5 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 6 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -7 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -8 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 9 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 12 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -24 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 27 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -28 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -37 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 42 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -43 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -45 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -47 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -48 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -54 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -60 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -68 Cycle M 29.0000 1 0.00
+exampleBAM.bam 29 -76 Cycle M 29.0000 1 0.00
+exampleBAM.bam 30 -9 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 12 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 -17 Cycle M 30.0000 2 0.00
+exampleBAM.bam 30 18 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 20 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 -21 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 23 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 24 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 26 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 -30 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 32 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 34 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 35 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 -35 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 -42 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 -45 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 -52 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 -54 Cycle M 30.0000 1 0.00
+exampleBAM.bam 30 -69 Cycle M 30.0000 1 0.00
+exampleBAM.bam 31 -1 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 4 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -5 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -6 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 8 Cycle M 31.0000 2 0.00
+exampleBAM.bam 31 -10 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -11 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -12 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -13 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 15 Cycle M 31.0000 2 0.00
+exampleBAM.bam 31 -16 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -19 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -25 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 26 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -26 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -32 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -34 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -39 Cycle M 31.0000 2 0.00
+exampleBAM.bam 31 43 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -45 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 60 Cycle M 31.0000 1 0.00
+exampleBAM.bam 31 -66 Cycle M 31.0000 1 0.00
+exampleBAM.bam 32 1 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 2 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -2 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -14 Cycle M 32.0000 2 0.00
+exampleBAM.bam 32 -15 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 16 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -16 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -18 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -19 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 23 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 24 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 28 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -28 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -30 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -31 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -33 Cycle M 32.0000 2 0.00
+exampleBAM.bam 32 -36 Cycle M 32.0000 2 0.00
+exampleBAM.bam 32 41 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -41 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 43 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -43 Cycle M 32.0000 2 0.00
+exampleBAM.bam 32 -46 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -49 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -51 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -53 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -54 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -57 Cycle M 32.0000 1 0.00
+exampleBAM.bam 32 -72 Cycle M 32.0000 1 0.00
+exampleBAM.bam 33 1 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -1 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 2 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 3 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -7 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -8 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -10 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -12 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -18 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -22 Cycle M 33.0000 2 0.00
+exampleBAM.bam 33 -23 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -24 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -29 Cycle M 33.0000 2 0.00
+exampleBAM.bam 33 -31 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -32 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -35 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -37 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -39 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -40 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 42 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 44 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 45 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -46 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -48 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -49 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -57 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -59 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -66 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -67 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -69 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -72 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -73 Cycle M 33.0000 1 0.00
+exampleBAM.bam 33 -76 Cycle M 33.0000 1 0.00
+exampleBAM.bam 34 -2 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -3 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -4 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -5 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -6 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -11 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -13 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -20 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -21 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -23 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -25 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -26 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -27 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -34 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -38 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -40 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -41 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -42 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -47 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -50 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -51 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -55 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -56 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -58 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -59 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -60 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -61 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -62 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -63 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -64 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -65 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -68 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -70 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -71 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -74 Cycle M 34.0000 1 0.00
+exampleBAM.bam 34 -75 Cycle M 34.0000 1 0.00
+exampleBAM.bam 45 5 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 5 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -5 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -5 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 6 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 6 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -6 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -6 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 7 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 7 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -7 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -7 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 8 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 8 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -8 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -8 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 9 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 9 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -9 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -9 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 10 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 10 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -10 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -10 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 11 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 11 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -11 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -11 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 12 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 12 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -12 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -12 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 13 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 13 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -13 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -13 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 14 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 14 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -14 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -14 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 15 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 15 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -15 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -15 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 16 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 16 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -16 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -16 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 17 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 17 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -17 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -17 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 18 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 18 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -18 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -18 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 19 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 19 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -19 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -19 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 20 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 20 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -20 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -20 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 21 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 21 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -21 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -21 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 22 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 22 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -22 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 -22 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 23 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 23 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -23 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -23 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 24 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 24 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -24 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -24 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 25 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 25 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -25 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -25 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 26 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 26 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -26 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 -26 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 27 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 27 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -27 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -27 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 28 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 28 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -28 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -28 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 29 Cycle I 45.0000 1 0.00
+exampleBAM.bam 45 29 Cycle D 45.0000 1 0.00
+exampleBAM.bam 45 -29 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -29 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 30 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 30 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -30 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -30 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 31 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 31 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -31 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -31 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 32 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 32 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -32 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -32 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 33 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 33 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -33 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -33 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 34 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 34 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -34 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -34 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 35 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 35 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -35 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -35 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 36 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 36 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -36 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -36 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 37 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 37 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -37 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 -37 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 38 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 38 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -38 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 -38 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 39 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 39 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -39 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -39 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 40 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 40 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -40 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -40 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 41 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 41 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -41 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -41 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 42 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 42 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -42 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -42 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 43 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 43 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -43 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -43 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 44 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 44 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -44 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -44 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 45 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 45 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -45 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -45 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 46 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 46 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -46 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 -46 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 47 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 47 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -47 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -47 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 48 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 48 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -48 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -48 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 49 Cycle I 45.0000 1 0.00
+exampleBAM.bam 45 49 Cycle D 45.0000 1 0.00
+exampleBAM.bam 45 -49 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -49 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 50 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 50 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -50 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -50 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 51 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 51 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -51 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -51 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 52 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 52 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -52 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -52 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 53 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 53 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -53 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -53 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 54 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 54 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -54 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -54 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 55 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 55 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -55 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -55 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 56 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 56 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -56 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -56 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 57 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 57 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -57 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -57 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 58 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 58 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -58 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -58 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 59 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 59 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -59 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -59 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 60 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 60 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -60 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -60 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 61 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 61 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -61 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -61 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 62 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 62 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -62 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -62 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 63 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 63 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -63 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -63 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 64 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 64 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -64 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 -64 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 65 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 65 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -65 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -65 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 66 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 66 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -66 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -66 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 67 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 67 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -67 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -67 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 68 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 68 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -68 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -68 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 69 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 69 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -69 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -69 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 70 Cycle I 45.0000 1 0.00
+exampleBAM.bam 45 70 Cycle D 45.0000 1 0.00
+exampleBAM.bam 45 -70 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -70 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 71 Cycle I 45.0000 2 0.00
+exampleBAM.bam 45 71 Cycle D 45.0000 2 0.00
+exampleBAM.bam 45 -71 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -71 Cycle D 45.0000 3 0.00
+exampleBAM.bam 45 72 Cycle I 45.0000 1 0.00
+exampleBAM.bam 45 72 Cycle D 45.0000 1 0.00
+exampleBAM.bam 45 -72 Cycle I 45.0000 3 0.00
+exampleBAM.bam 45 -72 Cycle D 45.0000 3 0.00
+
diff --git a/public/gatk-engine/src/test/resources/exampleINTERVAL.intervals b/public/gatk-engine/src/test/resources/exampleINTERVAL.intervals
new file mode 100644
index 0000000..f224381
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/exampleINTERVAL.intervals
@@ -0,0 +1,3 @@
+chr1:1-100
+chr1:200-400
+chr1:450-459
diff --git a/public/gatk-engine/src/test/resources/exampleNORG.bam b/public/gatk-engine/src/test/resources/exampleNORG.bam
new file mode 100644
index 0000000..f59219f
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleNORG.bam differ
diff --git a/public/gatk-engine/src/test/resources/exampleNORG.bam.bai b/public/gatk-engine/src/test/resources/exampleNORG.bam.bai
new file mode 100644
index 0000000..26cfe74
Binary files /dev/null and b/public/gatk-engine/src/test/resources/exampleNORG.bam.bai differ
diff --git a/public/gatk-engine/src/test/resources/forAlleleFractionSimulation.vcf b/public/gatk-engine/src/test/resources/forAlleleFractionSimulation.vcf
new file mode 100644
index 0000000..e29e49d
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/forAlleleFractionSimulation.vcf
@@ -0,0 +1,29 @@
+##fileformat=VCFv4.1
+##phasing=none
+##INDIVIDUAL=TRUTH
+##SAMPLE=<ID=TRUTH,Individual="TRUTH",Description="bamsurgeon spike-in">
+##INFO=<ID=SOMATIC,Number=0,Type=Flag,Description="Somatic mutation in primary">
+##INFO=<ID=AF,Number=1,Type=Float,Description="Variant Allele Frequency">
+##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
+#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT TUMOR
+20 100000 . A T 100 PASS SOMATIC;AF=0.500 GT 0/1
+20 101000 . T C 100 PASS SOMATIC;AF=0.400 GT 0/1
+20 102000 . A C 100 PASS SOMATIC;AF=0.300 GT 0/1
+20 103000 . C T 100 PASS SOMATIC;AF=0.200 GT 0/1
+20 104000 . A C 100 PASS SOMATIC;AF=0.100 GT 0/1
+20 105000 . A C 100 PASS SOMATIC;AF=0.050 GT 0/1
+20 105500 . A G 100 PASS SOMATIC;AF=0.020 GT 0/1
+20 106000 . CAT C 100 PASS SOMATIC;AF=0.500 GT 0/1
+20 107000 . ACT A 100 PASS SOMATIC;AF=0.400 GT 0/1
+20 107994 . AAG A 100 PASS SOMATIC;AF=0.300 GT 0/1
+20 108999 . GCA G 100 PASS SOMATIC;AF=0.200 GT 0/1
+20 110009 . CAT C 100 PASS SOMATIC;AF=0.100 GT 0/1
+20 112000 . ACC A 100 PASS SOMATIC;AF=0.050 GT 0/1
+20 112500 . AGC A 100 PASS SOMATIC;AF=0.020 GT 0/1
+20 113000 . G GAAT 100 PASS SOMATIC;AF=0.500 GT 0/1
+20 113999 . G GTGA 100 PASS SOMATIC;AF=0.400 GT 0/1
+20 115000 . T TCCA 100 PASS SOMATIC;AF=0.300 GT 0/1
+20 116000 . G GTTT 100 PASS SOMATIC;AF=0.200 GT 0/1
+20 117000 . T TCCA 100 PASS SOMATIC;AF=0.100 GT 0/1
+20 118000 . C CTGT 100 PASS SOMATIC;AF=0.050 GT 0/1
+20 119000 . C CTGT 100 PASS SOMATIC;AF=0.020 GT 0/1
\ No newline at end of file
diff --git a/public/gatk-engine/src/test/resources/forAlleleFractionSimulation.vcf.idx b/public/gatk-engine/src/test/resources/forAlleleFractionSimulation.vcf.idx
new file mode 100644
index 0000000..8b82f26
Binary files /dev/null and b/public/gatk-engine/src/test/resources/forAlleleFractionSimulation.vcf.idx differ
diff --git a/public/gatk-engine/src/test/resources/forLongInsert.vcf b/public/gatk-engine/src/test/resources/forLongInsert.vcf
new file mode 100644
index 0000000..3566b88
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/forLongInsert.vcf
@@ -0,0 +1,16 @@
+##fileformat=VCFv4.1
+##fileDate=20140820
+##source=mutatrix population genome simulator
+##seed=100
+##reference=ref.fasta
+##phasing=true
+##commandline=mutatrix ref.fasta --file-prefix mutations/ --sample-prefix 0 -n 1 --ploidy 2 --random-seed 100 --snp-rate 0.001
+##INFO=<ID=AC,Number=A,Type=Integer,Description="Alternate allele count">
+##INFO=<ID=TYPE,Number=A,Type=String,Description="Type of each allele (snp, ins, del, mnp, complex)">
+##INFO=<ID=NS,Number=1,Type=Integer,Description="Number of samples at the site">
+##INFO=<ID=NA,Number=1,Type=Integer,Description="Number of alternate alleles">
+##INFO=<ID=LEN,Number=A,Type=Integer,Description="Length of each alternate allele">
+##INFO=<ID=MICROSAT,Number=0,Type=Flag,Description="Generated at a sequence repeat loci">
+##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
+#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT 01
+20 10000000 . T TGTCTTAGTGTCGTATGGGCTTCCATATTCAACTTTCTTCTATAAGTAGAATATCTACACGTGATGCTCTGGTCTTTCTACTACACGTCTATTGTAGCTTAATCTTTTCCTCGGGGGGGAAGAGGCTGTTTAGAATCATACCTCCAACCGACATTAACCCTGTTGGATTATAACTAGGGGCAAATCCGGATATTGGTATACGGCCCTATTATTCTATGGGTCTACGCACCTAGTAGGCACCCACGCAGTCTCTGGCCCGACCCCA 99 . AC=2;LEN=264;NA=1;NS=1;TYPE=ins GT 1|1
diff --git a/public/gatk-engine/src/test/resources/forLongInsert.vcf.idx b/public/gatk-engine/src/test/resources/forLongInsert.vcf.idx
new file mode 100644
index 0000000..a22e932
Binary files /dev/null and b/public/gatk-engine/src/test/resources/forLongInsert.vcf.idx differ
diff --git a/public/gatk-engine/src/test/resources/forSimulation.vcf b/public/gatk-engine/src/test/resources/forSimulation.vcf
new file mode 100644
index 0000000..a0c57c2
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/forSimulation.vcf
@@ -0,0 +1,8 @@
+##fileformat=VCFv4.1
+##FORMAT=<ID=GT,Number=1,Type=String,Description="Genotype">
+#CHROM POS ID REF ALT QUAL FILTER INFO FORMAT NA12878 NA12891 NA12892
+20 10000000 . T C . . . GT 0/1 0/0 1/1
+20 10001000 . GG AA . . . GT 0/1 0/0 1/1
+20 10002000 . TAGTA T . . . GT 0/1 0/0 1/1
+20 10003000 . A AGCT . . . GT 0/1 0/0 1/1
+20 10004000 . GAT G,GATAT . . . GT 0/1 0/0 1/1
diff --git a/public/gatk-engine/src/test/resources/forSimulation.vcf.idx b/public/gatk-engine/src/test/resources/forSimulation.vcf.idx
new file mode 100644
index 0000000..4f734b7
Binary files /dev/null and b/public/gatk-engine/src/test/resources/forSimulation.vcf.idx differ
diff --git a/public/gatk-engine/src/test/resources/testfile.sam b/public/gatk-engine/src/test/resources/testfile.sam
new file mode 100644
index 0000000..7345c03
--- /dev/null
+++ b/public/gatk-engine/src/test/resources/testfile.sam
@@ -0,0 +1,450 @@
+ at HD VN:1.0 GO:none SO:coordinate
+ at SQ SN:chrM LN:16571 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:d2ed829b8a1628d16cbeee88e88e39eb SP:Homo sapiens
+ at SQ SN:chr1 LN:247249719 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:9ebc6df9496613f373e73396d5b3b6b6 SP:Homo sapiens
+ at SQ SN:chr2 LN:242951149 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:b12c7373e3882120332983be99aeb18d SP:Homo sapiens
+ at SQ SN:chr3 LN:199501827 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:0e48ed7f305877f66e6fd4addbae2b9a SP:Homo sapiens
+ at SQ SN:chr4 LN:191273063 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:cf37020337904229dca8401907b626c2 SP:Homo sapiens
+ at SQ SN:chr5 LN:180857866 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:031c851664e31b2c17337fd6f9004858 SP:Homo sapiens
+ at SQ SN:chr6 LN:170899992 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:bfe8005c536131276d448ead33f1b583 SP:Homo sapiens
+ at SQ SN:chr7 LN:158821424 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:74239c5ceee3b28f0038123d958114cb SP:Homo sapiens
+ at SQ SN:chr8 LN:146274826 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:1eb00fe1ce26ce6701d2cd75c35b5ccb SP:Homo sapiens
+ at SQ SN:chr9 LN:140273252 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:ea244473e525dde0393d353ef94f974b SP:Homo sapiens
+ at SQ SN:chr10 LN:135374737 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:4ca41bf2d7d33578d2cd7ee9411e1533 SP:Homo sapiens
+ at SQ SN:chr11 LN:134452384 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:425ba5eb6c95b60bafbf2874493a56c3 SP:Homo sapiens
+ at SQ SN:chr12 LN:132349534 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:d17d70060c56b4578fa570117bf19716 SP:Homo sapiens
+ at SQ SN:chr13 LN:114142980 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:c4f3084a20380a373bbbdb9ae30da587 SP:Homo sapiens
+ at SQ SN:chr14 LN:106368585 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:c1ff5d44683831e9c7c1db23f93fbb45 SP:Homo sapiens
+ at SQ SN:chr15 LN:100338915 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:5cd9622c459fe0a276b27f6ac06116d8 SP:Homo sapiens
+ at SQ SN:chr16 LN:88827254 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:3e81884229e8dc6b7f258169ec8da246 SP:Homo sapiens
+ at SQ SN:chr17 LN:78774742 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:2a5c95ed99c5298bb107f313c7044588 SP:Homo sapiens
+ at SQ SN:chr18 LN:76117153 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:3d11df432bcdc1407835d5ef2ce62634 SP:Homo sapiens
+ at SQ SN:chr19 LN:63811651 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:2f1a59077cfad51df907ac25723bff28 SP:Homo sapiens
+ at SQ SN:chr20 LN:62435964 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:f126cdf8a6e0c7f379d618ff66beb2da SP:Homo sapiens
+ at SQ SN:chr21 LN:46944323 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:f1b74b7f9f4cdbaeb6832ee86cb426c6 SP:Homo sapiens
+ at SQ SN:chr22 LN:49691432 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:2041e6a0c914b48dd537922cca63acb8 SP:Homo sapiens
+ at SQ SN:chrX LN:154913754 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:d7e626c80ad172a4d7c95aadb94d9040 SP:Homo sapiens
+ at SQ SN:chrY LN:57772954 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:62f69d0e82a12af74bad85e2e4a8bd91 SP:Homo sapiens
+ at SQ SN:chr1_random LN:1663265 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:cc05cb1554258add2eb62e88c0746394 SP:Homo sapiens
+ at SQ SN:chr2_random LN:185571 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:18ceab9e4667a25c8a1f67869a4356ea SP:Homo sapiens
+ at SQ SN:chr3_random LN:749256 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:9cc571e918ac18afa0b2053262cadab6 SP:Homo sapiens
+ at SQ SN:chr4_random LN:842648 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:9cab2949ccf26ee0f69a875412c93740 SP:Homo sapiens
+ at SQ SN:chr5_random LN:143687 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:05926bdbff978d4a0906862eb3f773d0 SP:Homo sapiens
+ at SQ SN:chr6_random LN:1875562 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:d62eb2919ba7b9c1d382c011c5218094 SP:Homo sapiens
+ at SQ SN:chr7_random LN:549659 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:28ebfb89c858edbc4d71ff3f83d52231 SP:Homo sapiens
+ at SQ SN:chr8_random LN:943810 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:0ed5b088d843d6f6e6b181465b9e82ed SP:Homo sapiens
+ at SQ SN:chr9_random LN:1146434 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:1e3d2d2f141f0550fa28a8d0ed3fd1cf SP:Homo sapiens
+ at SQ SN:chr10_random LN:113275 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:50be2d2c6720dabeff497ffb53189daa SP:Homo sapiens
+ at SQ SN:chr11_random LN:215294 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:bfc93adc30c621d5c83eee3f0d841624 SP:Homo sapiens
+ at SQ SN:chr13_random LN:186858 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:563531689f3dbd691331fd6c5730a88b SP:Homo sapiens
+ at SQ SN:chr15_random LN:784346 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:bf885e99940d2d439d83eba791804a48 SP:Homo sapiens
+ at SQ SN:chr16_random LN:105485 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:dd06ea813a80b59d9c626b31faf6ae7f SP:Homo sapiens
+ at SQ SN:chr17_random LN:2617613 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:34d5e2005dffdfaaced1d34f60ed8fc2 SP:Homo sapiens
+ at SQ SN:chr18_random LN:4262 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:f3814841f1939d3ca19072d9e89f3fd7 SP:Homo sapiens
+ at SQ SN:chr19_random LN:301858 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:420ce95da035386cc8c63094288c49e2 SP:Homo sapiens
+ at SQ SN:chr21_random LN:1679693 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:a7252115bfe5bb5525f34d039eecd096 SP:Homo sapiens
+ at SQ SN:chr22_random LN:257318 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:4f2d259b82f7647d3b668063cf18378b SP:Homo sapiens
+ at SQ SN:chrX_random LN:1719168 AS:HG18 UR:/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta M5:f4d71e0758986c15e5455bf3e14e5d6f SP:Homo sapiens
+ at RG ID:20FUK.1 PL:illumina PU:20FUKAAXX100202.1 LB:Solexa-18483 DT:2010-02-02T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20FUK.2 PL:illumina PU:20FUKAAXX100202.2 LB:Solexa-18484 DT:2010-02-02T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20FUK.3 PL:illumina PU:20FUKAAXX100202.3 LB:Solexa-18483 DT:2010-02-02T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20FUK.4 PL:illumina PU:20FUKAAXX100202.4 LB:Solexa-18484 DT:2010-02-02T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20FUK.5 PL:illumina PU:20FUKAAXX100202.5 LB:Solexa-18483 DT:2010-02-02T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20FUK.6 PL:illumina PU:20FUKAAXX100202.6 LB:Solexa-18484 DT:2010-02-02T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20FUK.7 PL:illumina PU:20FUKAAXX100202.7 LB:Solexa-18483 DT:2010-02-02T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20FUK.8 PL:illumina PU:20FUKAAXX100202.8 LB:Solexa-18484 DT:2010-02-02T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20GAV.1 PL:illumina PU:20GAVAAXX100126.1 LB:Solexa-18483 DT:2010-01-26T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20GAV.2 PL:illumina PU:20GAVAAXX100126.2 LB:Solexa-18484 DT:2010-01-26T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20GAV.3 PL:illumina PU:20GAVAAXX100126.3 LB:Solexa-18483 DT:2010-01-26T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20GAV.4 PL:illumina PU:20GAVAAXX100126.4 LB:Solexa-18484 DT:2010-01-26T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20GAV.5 PL:illumina PU:20GAVAAXX100126.5 LB:Solexa-18483 DT:2010-01-26T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20GAV.6 PL:illumina PU:20GAVAAXX100126.6 LB:Solexa-18484 DT:2010-01-26T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20GAV.7 PL:illumina PU:20GAVAAXX100126.7 LB:Solexa-18483 DT:2010-01-26T00:00:00-0500 SM:NA12878 CN:BI
+ at RG ID:20GAV.8 PL:illumina PU:20GAVAAXX100126.8 LB:Solexa-18484 DT:2010-01-26T00:00:00-0500 SM:NA12878 CN:BI
+ at PG ID:BWA VN:0.5.7 CL:tk
+20GAVAAXX100126:8:21:18798:198557 83 chr1 9999918 60 101M = 9999594 -424 CAAGCTCCGCCTCCCAGGTTCACGCCATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGACTACAGGCACCCACCACCACGCCTGGCCAATTTTTTTGTATT 7<CAB>A9AAA79;;.@=BAA;60@<CDACBCC at A@CDBDBCCBCC;BDACCBCCBBBBCCBBCBBBACCBBCBBCBB;BCCCBBCBDBAAADDDCAABDC MD:Z:15G85 PG:Z:BWA RG:Z:20GAV.8 AM:i:23 NM:i:1 SM:i:23 MQ:i:60 OQ:Z:5BFFF?GGFFG:=@@/FDFDF=D7FBHHDHFHHDGFHHHHHHHFHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHGGGGHHHHHHHHH UQ:i:13
+20GAVAAXX100126:8:22:9500:19764 147 chr1 9999949 60 6S95M = 9999628 -415 CATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGACTACAGGCACCCACCACCACGCCTGGCCAATTTTTTTGTATTTTTAGTAGAGATAGGGTTTCACCAT #######A:A@?3=<AA:.,A:B:??:?BB at BA79BBAAA>C=BCBBAC<ACA;CBACAACABBBCCDDDCBCCDDDDCEACDCDCCADCCACC at AAABC@ MD:Z:95 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:#######@4?@:1;4=?7+0 at AA8A?6?@>@@@5;A>A??@B6?BA;BB9BB at BBABBAABBBBBBBBBBBCBBBBBBBCBBBCBCBBBCCBBCCB@CCBB UQ:i:0
+20GAVAAXX100126:8:26:17788:24663 99 chr1 9999965 60 101M = 10000321 441 GAGTAGCTGGGACTACAGGCACCCACCACCACGCCTGGCCAATTTTTTTGTATTTTTAGTAGAGATAGGGTTTCACCATATTAGCCAGGATGGTCTTGATC CDBACCCDBCCDADCACCCACABBBABC;BCA;BBCBCBBCDCDDDDDA at BBCDDDABCACCDCDCCCCCAD@BCABCCCCDCCBCCCCDCCCCCDDCDDD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHGHHHHIHHHDHHHHHHHHHHHHHHHHHHHGGGGHHHHGGHGHHHHHHHHHHFHGHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:47:10796:84088 99 chr1 9999998 60 101M = 10000328 430 CCTGGCCAATTTTTTTGTATTTTTAGTAGAGATAGGGTTTCACCATATTAGCCAGGATGGTCTTGATCTGCTGACCTCATGACCCACCCGCCTCGGCCTTC CBC at CCCCDCDDDDDAA@BCDDDAACBCCDCDCC at CCBBDBBABCCCCDCCBBCCCCC>C;BDDBDCBDBBDBDABDBCCBDACCC at AA9CCDC;DCCDED MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHGGEGHHHHGGHHHHHHHHHGHHHIHHIHHHHHHHHHHHHHHGHDHCHHHHHHHHHHHHHHHHHHHHHHHHHIGGGHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:62:7317:185100 675 chr1 10000001 60 78M23S = 10000382 415 GGCCAATTTTTTTGTATTTTTAGTAGAGATAGAGTTTCACCATATTAGCCAGGATGGCCTTAATCTGCTGACCTCATAATCACACAGCCTCGTCCTTCAAA >?78+*?88CBC24B.BBCA>6=846;8C-2@(?@10AB++7C>A/C9<>A,@?.B,()C6*B3:D8 at C*+92A:BA######################## MD:Z:32G24T3G15G0 PG:Z:BWA RG:Z:20GAV.8 AM:i:25 NM:i:4 SM:i:25 MQ:i:60 OQ:Z:==76**=76BCA44A.ACC?;4:43273B,1=*=A34BB--8B<B/B4=9B+=@+@/))@7+ at 26ACC@)+5/@9AA######################## UQ:i:25
+20GAVAAXX100126:8:5:4250:100581 99 chr1 10000006 60 101M = 10000330 415 ATTTTTTTGTATTTTTAGTAGAGATAGGGTTTCACCATATTAGCCAGGATGGTCTTGATCTGCTGACCTCATGACCCACCCGCCTCGGCCTTCCAAAGTGC CCCBDDDA at BBCDDDABCBCCDCDBCCCCBDDBCABCCCCDCCBBCCCCCBCBBDDBDCBDBBDBDABDBCCADABBCAC>7BCDB;CCCDDCCBE>D at DD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHGGGGHHHHGGHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHFHHHHHHHEEHHHHHHHHHHHHGHBHGHH UQ:i:0
+20GAVAAXX100126:8:64:9003:28381 83 chr1 10000026 60 101M = 9999704 -422 GAGATAGGGTTTCACCATATTAGCCAGGATGGTCTTGATCTGCTGACCTCATGACCCACCCGCCTCGGCCTTCCAAAGTGCTGGGATTACAGGTGTGAGCC DCCBDD?A2ABB at BCBCCCDC@BC at CA@AB at ABCDCBCCCCBACAACCDBCCB@BCB at CC;BCCD;BBCCDDCBDDDACBCCBBBCDCCBDBACACBBBCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HFHFHHDG9GGGGGHHHHHHHDHHGIGGFFFHGHHHHHGHHHGHGFHHHHHHHEGHHFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:66:8049:3241 83 chr1 10000031 60 101M = 9999623 -508 AGGGTTTCACCATATTAGCCAGGATGGTCTTGATCTGCTGACCTCATGACCCACCCGCCTCGGCCTTCCAAAGTGCTGGGATTACAGGTGTGAGCCACCGC ?DCBEEDCCCCCCCD=DBCBDCBCCBADCDCBCCCCBCCBBCCDB at CB9BCBBCC;BCCD;BBCCDDCBDDDACBCCBBBCDCBBDBACACBDCCCCA:BC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BHHHHHHHIHHHHHHBHHHHHHHHHHHHHHHHHGHHHHHHGHHHHFHHBGHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:65:18189:17218 163 chr1 10000038 60 101M = 10000302 364 CACCATATTAGCCAGGATGGTCTTGATCTGCTGACCTCATGACCCACCCGCCTCGGCCTTCCAAAGTGCTGGGATTACAGGTGTGAGCCACCGCGACCGGC @CABAAABCCBBCBCCCCCCBBDCBCCBDCBDBA at BB?B at B@AC?CACC;@CD@:BBCBB>CB>=A;ACC@:CA@@@>A<@<B7ABBA7C>B9@;B?C4BB MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCCBCCCBCCCCBCCBBCB at BBBBBBBBBBBB>BBBABAB at BBABBBBABBAB@?AB@@@B@>9?=@BAA8A@?>@@=;?6?4?=?@6@??<@?@==8=A UQ:i:0
+20GAVAAXX100126:8:27:11272:197846 611 chr1 10000110 60 79M22S = 10000329 297 GATTACAGGTGTGAGCCACCGCGACCGGCCTGCTCAAGATAATTTTTAGGGCTAACTATGACATGAACCCCAAAATTCCTGTCCTCTAGATGGCAGAAACC 1;>5;;5?9>>;:;02<=<<5>5@;<4 at 9<<=:><<>=A6;*<;<???:=(:?=;/=5::?3>:=B8?)78:9::;9;####################### MD:Z:79 PG:Z:BWA RG:Z:20GAV.8 AM:i:25 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:5555551455<==@014544EEEEA>>F@>>E>AE>AAF:4+454AAF=A/=AA50=9==A7A=AF;F-;44544=5?####################### UQ:i:0
+20GAVAAXX100126:8:7:13574:93999 163 chr1 10000133 60 101M = 10000392 359 ACCGGCCTGCTCAAGATAATTTTTAGGGCTAACTATGACATGAACCCCAAAATTCCTGTCCTCTAGATGGCAGAAACCAAGATAAAGTATCCCCACATGGC @AB:AABCBBDBCBCCCCDCCCCCCCCCCDCDADB=>A at BAACD=BCCCDBBC at CCCCABBCB@CC@@AA at CBBAB?BC=ABC at CDB??A?B>AC?CC<CC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBBBABBBBBBBBBBBCBBABBBBBBBBBBB at AABBAABBAABBBBBAAABAAA>ABAB?BAA?@?AA at A?@AA@<@@@@A@?;@=?A9AA@??:>B UQ:i:0
+20GAVAAXX100126:8:65:18208:188053 163 chr1 10000137 60 101M = 10000358 321 GCCTGCTCAAGATAATTTTTAGGGCTAACTATGACATGAACCCCAAAATTCCTGTCCTCTAGATGGCAGAAACCAAGATAAAGTATCCCCACATGGCCACA @CCC?@BBBDBBCAEDBBCCCCDDCDDEBECCBC?@AAB@?CCDADDDCC at AD@BCADADBCCBCC8CCCBDBABCABABBBDABDCB at C@?C at CACD?BC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCCCCCCCCCCCCCCCCCCBCCCCBCCCCCBBCCCBBBCCBBCBBBBBBBCBBBCCBCBBBBBBACBBBABBBBBBB?BB at B>BBBBABBBBBA at ABBBB UQ:i:0
+20GAVAAXX100126:8:65:17424:133143 163 chr1 10000184 60 101M = 10000444 360 ATTCCTGTCCTCTAGATGGCAGAAACCAAGATAAAGTATCCCCACATGGCCACAAGGTTAAGCTCTTATGGACACAAAACAAGGCAGAGAAATGTCATTTG @CBA at BAABCDBDACCBBCBC=CDDACCDCCCCDCB;BBABCCC?CCBCC at BAADCBBCBBBBBBD@CBB at DBA?BBBB?@BBABCCC=BAAA at A@CBAAB MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBCBBABBBBBBBB at BBBB9BBBBBBBBBBBBBB?BBBBBBBBBAABBAABBAAA:AAAABABAAB at A@ABA at A@A>@?A?@A@@@>>A>>@9@@=?;A UQ:i:0
+20GAVAAXX100126:8:24:16681:115751 83 chr1 10000185 60 101M = 9999853 -432 TTCCTGTCCTCTAGATGGCAGAAACCAAGATAAAGTATCCCCACATGGCCACAAGGTTAAGCTCTTATGGACACAAAACAAGGCAGAGAAATGTCATTTGG 6EA6DADD?DCCD at CCCB?DBDDCCBDDBCCDDDACCDCCCBBBCCBB at BBBDDBADCDCBCDCDCCCBBBBC=>DDBBDDBBBDBDBDD at CADCCDBCBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:23 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:5HG;HHHHEHHHHGHHHHDHHHHHHHHHHHHHHHHHHHHHHHGHHHHHFHHHHHHHHHHHHHHHHHHHHHHHHEEHHHHHHHHHHHHHHHFHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:65:2449:158320 147 chr1 10000187 60 24S77M = 9999832 -431 AACTATGACATGACCCCCAAAATTCCTGTCCTCTAGATGGCAGAAACCAAGATAAAGTATCCCCACATGGCCACAAGGTTAAGCTCTTATGGACACAAAAC #########################@<=?>?A at 67C@?A@>?4BACB=D?<B:CCB:A>>A==@;?BBCBACBCCDCADCCDBCACDACCCBBBBAA at BA@ MD:Z:77 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:#########################?:?::?><68B>?@??;1??@@@A>@@;@@@@@?>A@@A?AB at AA@BABBBBBBBBBBB?BBBBBBBABABBCBBB UQ:i:0
+20GAVAAXX100126:8:66:6889:6402 163 chr1 10000196 60 74M27S = 10000514 418 TAGATGGCAGAAACCAAGATAAAGTATCCCCACATGGCCACAAGGTTAAGCTCTTATGGACACAAAACAAGGCAGAGAAATGTCATTTGGCATTGGTTTCA @C<<B9?=>B>?A at BDD?<=?DD>-A=<C>C?=?;97A7B<=7>532;C><9B7D=8<<C<277?=@4D>2:B############################ MD:Z:74 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BC;9B:=>:B><ACACB;7;?BB:*@::B<B<>=>;=B;B@>7;;-08B9 at 7A6B:56<B?/85<9B5B:08?############################ UQ:i:0
+20GAVAAXX100126:8:68:13621:42696 675 chr1 10000250 37 35M66S = 10000556 340 TATGGACACAAAAAAAGGCAGAGAAATGTCATTTGGCATTGGTTTCAGGGACCCATAGCAACATTTGTAAATGACCAGCCTGTTGGGCTGGCTTTTTACAT =C7A at B=8-B5>2)8B##################################################################################### MD:Z:13C21 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:1 SM:i:37 MQ:i:29 OQ:Z::B5BCB=6,A4:1)4@##################################################################################### UQ:i:8
+20GAVAAXX100126:8:65:18189:17218 83 chr1 10000302 60 101M = 10000038 -364 CCATAGCAACATTTGTAAATGACCAGCCTGATGGGCTGGCTTGAAAACTTGGCTTATAGGCATCCTAAACCCACGTTCTATCCCCTGATACTCCCCTCTTC DDCDDCCDCCCDDCACDDCBBCCBDBCCCBCCBBBCCCBBDCBDDDBCDCBBCDCCCCBBBCDCCCDD at CCBA;ADDCCCDCCCCCBCCBCDCCCCDADDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHIHHHHHHHFHHHHHHHHHHHHHHHHHHHIHHHHHHGHHHHHHHHHHHHHHHHHHHHHFHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:4:6560:50417 163 chr1 10000312 60 76M25S = 10000637 425 ATTTGTAAATGACCAGCCTGATGGGCTGGCTTGAAAACTTGGCTTATAGGCATCCTAAACCCACCTTCTATCCCCTGATACTCCGCTTTTCATTACAGCAC ?>9?=7;BA;:B;<C<B?907>/5BCD?CCC>)A8=:$;30B474@>8<8?*B)BE7?@+?<.-/+39978BCAA########################## MD:Z:64G11 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:?;9=:18A?7:???B:B<4-4;,6ACB<BBA;)>8?>'=60A627@:6<8A*@*>B58>+?;+-,)69259 at CB@########################## UQ:i:14
+20GAVAAXX100126:8:26:17788:24663 147 chr1 10000321 60 15S86M = 9999965 -441 AGCAACATTTGTAAATGACCAGCCTGATGGGCTGGCTTGAAAACTTGGCTTATAGGCATCCTAATCCCACGTTCTATCCCCTGATACTCCCCTCTTCATTA ################B=?@@@B@>>4:CB5;C??BDB@@<BBCCCC<CB9@=DCB9>3>BBB8&4BCB;?DCCCB at CCDCBACA<ABCCCBCBCBABCC@ MD:Z:49A36 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:################B7<@>@?@=>2:?>77@>B at BB??=@?BA at B?AA>>>AAB=;2?BBB<(9BBAB at BBBBA=BBCCAABA7 at BBBBBBBBBBCBCB UQ:i:5
+20GAVAAXX100126:8:3:21049:178760 163 chr1 10000325 60 95M6S = 10000650 425 CAGCCTGATGGGCTGGCTTGAAAACTTGGCTTATAGGCATCCTAAACCCACGTTCTATCCCCTGATACTCCCCTCTTCATTACAGAACAACAAAGAAAGAC @CBAABACCBCCBCBCBDC?CDDEADCCCBDCAAB=?==@@CBCBD8CCC?;CAAD=C at BBC?>BA=?C>?=CA at CB?B<B<?<?AC?<D<8BA####### MD:Z:95 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBBBBBBBBBBBBBB=BBBCBBBBCABB@@B at A@@AABABBB5ABABB?B at A<A??BA<???@@?<?8A@@AB??<B=<:=;??<A>4>?####### UQ:i:0
+20GAVAAXX100126:8:47:10796:84088 147 chr1 10000328 60 101M = 9999998 -430 CCTGATGGGCTGGCTTGAAAACTTGGCTTATAGGCATCCTAAACCCACGTTCTATCCCCTGATACTCCCCTCTTCATTACAGAACAACAAAGAAAGACAAA ;?@B::A5;?8B:9@?=@DB at B@97@>4':8>B>?>?@>:BC>CCAC6AC>C at CCCABBCBB?>A3>CCCBCBCBD at B?BEBCACCAACCDBCBCA at ABC@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z::7>@55<37=6=;6:9<?A@>A;78?>3'4::>>A;;@<;AA8AB>>?AB at A@AABB at BBBBA@B3 at BBB@B?ABC=A:ACBCBCBBBBBBBBBBBBBBBB UQ:i:0
+20GAVAAXX100126:8:27:11272:197846 659 chr1 10000329 60 22S79M = 10000110 -297 GCAACCTTTGTAACAGACCTGTCTGATGGGCTGGCTTGAAAACTTGGCTTATAGGAATCCGAAACCTACGTACTATCCCCTGATACTCCCCTCTTCATTAC #######################@1>:@C3<B;377:2BB(@BC4)A2+>ACBB1*?CA7(-)87)'>%.(-65;B&@<765@=B3 at 2C5;C7,*?76 at A; MD:Z:33C4T5C4T29 PG:Z:BWA RG:Z:20GAV.8 AM:i:25 NM:i:4 SM:i:25 MQ:i:60 OQ:Z:#######################?0=8??0>?839350@@);A?0)@1*?BBC at -,ACA@)/,6=)):*-)(128@)>;333?;@1=7B6;B3+*@33AB7 UQ:i:34
+20GAVAAXX100126:8:5:4250:100581 147 chr1 10000330 60 9S92M = 10000006 -415 TGACCAGCCTGATGGGCTGGCTTGAAAACTTGGCTTATAGGCATCCTAAACCCACGTTCTATCCCCTGATACTCCCCTCTTCATTACAGAACAACAAAGAA ##########?A>@==??B79=@819@;>8 at BBA=@;5?A>@=::BA;B?<C@>:>>B?A;5@>?@=BBBBCCCCCCBCDCBCDCBBCBCABCAAAACBC@ MD:Z:92 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:##########?>>>7:>==77<<817?9:1@?A@??86<@@><4:??=?>?A at 7@@@?@A>6A at AA?AAA at B@BBBB at BBABBBB@BBBBBBBBBBBBBBB UQ:i:0
+20GAVAAXX100126:8:65:18208:188053 83 chr1 10000358 60 101M = 10000137 -321 TAGGCATCCTAAACCCACGTTCTATCCCCTGATACTCCCCTCTTCATTACAGAACAACAAAGAAAGACAAATTCTTAGCATAAAGTACACCAGATTTGCTA DECCCCDDCCA@>BBAC9ADDCCCDCCCCCBCCCCDCCCCDCDDBCDCBBCBDBBDB@@DDBDDCBBBDDCDDCDCDBBCCDDDACBBCCBDBCDDC at BCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHGGAGGFHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:62:7317:185100 595 chr1 10000382 60 66S35M = 10000001 -415 TTAAATGTCCAGCATGATGGGCTGGCTTGAAAACTTGGCTTATAGGCATCCTAAACCCACGTTCTATCCCCTGATACTCCCCTCTTCATTCCAGAACAACA ##################################################################################################### MD:Z:24A10 PG:Z:BWA RG:Z:20GAV.8 AM:i:25 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:##################################################################################################### UQ:i:2
+20GAVAAXX100126:8:7:13574:93999 83 chr1 10000392 60 101M = 10000133 -359 CTCCCCTCTTCATTACAGAACAACAAAGAAAGACAAATTCTTAGCATAAAGTACACCAGATTTGCTACAGCCTAAGACTGGTCTGACAAATCCTTTTTTTC DEDDDCDCDDCCDCCBDBDCBDC at ADDBDDDBCBDDCDCCDCDBBCCDDDACBBBCBCBCDDCBCCBBCBCCCDDBBCCBADCCBBBDDCDCAADDDBDDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHGHHHHHHHHHHHHHIHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHH UQ:i:0
+20GAVAAXX100126:8:25:6601:158705 99 chr1 10000400 37 101M = 10000802 436 TTCATTACAGAACAACAAAGAAAGACAAATTCTTAGCATAAAGTACACCAGATTTGCTACAGCCTAAGACTGGTCTGACAAATCCTTTTTTTCTACTAATC 8;>7=;A?@5>>=>>;3>6=5=4328<::9;;=;:<6198=*7;9>A>??;<:>>?<A><A?@@@81;:9;,:89;:97,99999@>>B6==:41>A:4;, MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:37 MQ:i:29 OQ:Z:@CCEE at CCC;44444A7A;<7<863@<===55444=:1===,:@@FFFFD@==CAE<EEEFEFFD515444.@:=4455.44455ACCF;=@>88CE>9 at 0 UQ:i:0
+20GAVAAXX100126:8:4:15177:54134 99 chr1 10000435 60 101M = 10000750 415 GCATAAAGTACACCAGATTTGCTACAGCCTAAGACTGGTCTGACAAATCCTTTTTTTCTACTAATCAGACCCTCGCAGAGAAGACAAATAGTGGCATTTAC CBCACDDC at CACAB-CDCDDBBCCACCBBDCDCDACBCABDBDACDDCBBCDDDDDA>CAADBDCBBCDABBDB;BCCDCDDCDACDDCCCBCDCDCDBDB MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHIHHHHH-HHHHHHHHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHGEGGHHIHHHFHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHIFHH UQ:i:0
+20GAVAAXX100126:8:65:17424:133143 83 chr1 10000444 60 101M = 10000184 -360 ACACCAGATTTGCTACAGCCTAAGACTGGTCTGACAAATCCTTTTTTTCTACTAATCAGACCCTCGCAGAGAAGACAAATAGTGGCATTTACCGTTTACAC DDCDCDCCDDCBCCCBDBCCCDDBBCCBADCCBCBDDCDCBAAADDDDCCBCCDCDBCBBCCCD;BBCBCBDDBBBDDCCDACBBBCDDCCC;ADDCABCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:61:14621:35929 163 chr1 10000470 60 101M = 10000818 448 TGGTCTGACAAATCCTTTTTTTCTACTAATCAGACCCTCGCAGAGAAGACAAATAGTGGCATTTACCGTTTACACAACATATACAGAGAGAGAGAGACCAG =BC at ABAAAC=DCADDBBCCCCBDCBDCEDCC at C?B>C<:@CAC?BDB@@@BDACCACCCAC6?AA>8BCACA?>AB?CBA9C?BDDB>C@>C at DACB>@7 MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:<BB?BACCCB=BCCCBCCCCCABBBCBCCCCB?CCBCB at BCBAAACB@?@ACBBBB?BBBAB4?CC at CBBBCA???BBCBBCBBABBBBBB;?B at A?A<82 UQ:i:0
+20GAVAAXX100126:8:66:6889:6402 83 chr1 10000514 60 101M = 10000196 -418 GAAGACAAATAGTGGCATTTACCGTTTACACAACATATACAGAGAGAGAGAGACCAGAAACTTGGCTGGTAAGAATTTCTTCCTCTGGCCAGGAGCGGTGG ;ED>CCBBB=A?ACCB?DDBC>5<?@CBBBB@@>@@?>:?BBC at DBC@C@?;;7=>9>=>;@?AACCBACDDBDCDAD@?D:=?=><===?<?<=9?09:; MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:<HHEHHFFFBDGEHHHDHHGHEEEEEHHHHHDDEEFDECDFHGGHHGGGGD55544 at A??@GEGGHHHHHHHHHHHFHFDH at ADAADDDDDDCBDC?@@>? UQ:i:0
+20GAVAAXX100126:8:21:13663:85034 163 chr1 10000518 60 86M15S = 10000794 376 ACAAATAGTGGCATTTACCGTTTACACAACATATACAGAGAGAGAGAGACCAGAAACTTGGCTGGTAAGAATTTCTTCCTCTGGCCAGGAGCGGTGGCTCA @ABCBABBBBCBCABCCAC;ACCCACBCDACCCCB>ABBBAABC at CCCBA@CC at DDADCA?BB?CB=CABACCA at CB<?B@@B at A################ MD:Z:86 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBCBBABCBBCCBCBBBBBBBBBCBBBBBBBBABBBBAAABABABAAABBAABBAA@@A@@A>@A=@@A@@@A@=;@@>???################ UQ:i:0
+20GAVAAXX100126:8:68:13621:42696 595 chr1 10000556 29 66S35M = 10000250 -340 TTCTACAAATCAGACCCTCGCAGAGAAGACAAATAGTGGCATTTACCGTTTACCCAACATATACAGAGAGAGAGAGACCAGAAACTTGGCTGGTAAGCATT ##################################################################################################### MD:Z:31A3 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:1 SM:i:0 MQ:i:37 OQ:Z:##################################################################################################### UQ:i:2
+20GAVAAXX100126:8:4:6560:50417 83 chr1 10000637 60 101M = 10000312 -425 TTGGGGAGGTTGAGGCGTGTGGATCAGAAGGTCAAGAGATCCAGACCATCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCTG A37:<;++7+::2%848-8:909::>9;;;:9<:<;6,:A>;<<==;6>=<@BB:B@@=>;=AC=D;;7778A@=D>CBA@>DD>C39@>=@>;;=:8:6: MD:Z:2T6C7G83 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:3 SM:i:37 MQ:i:60 OQ:Z:E84<@<-05-443(444/4553<<=<@@=@>544446-=DA?@?A?=:A?=EHH=HFFDDBEHHEH55445FHDDHCHHGCCHHEH11444FDBBDBFEBE UQ:i:44
+20GAVAAXX100126:8:3:21049:178760 83 chr1 10000650 60 101M = 10000325 -425 GGCGGGTGGATCAGAAGGTCAAGAGATCCAGACCATCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCTGGACATGGTGGTGG DD;CCADCCCDCDBDDCADBDDBDBCDCBDBBCBCDCCCBBCBDCBCCBACBDDBCCC;ADCDCCBCA at DDDCAABDDDDCDCDBCCBBBBCCCACC?CBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHGGHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:4:15177:54134 147 chr1 10000750 60 101M = 10000435 -415 GGCGCCTGTAGTCCCAGCTACTCAGGAGGCTGAGGCAGGAGAATTGCTTGAACCCAGGAGGTGGAGGTTGCAGTGAGCCTAGATCACGCCACTGCACTCCA CA8 at 1@B?BC>D?BCDBBCAB>CBBACABDABEC?CDBBDACCCCCCAC@@ACDCDACDC at BAABB@DCBCDACBDBCCCDBCCBA;ACA,ACBA at ABCB@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:A<>;2>=?A@?@@AAAAAA?B=BABBABABABBBBBBBBBBBB at BBBBBCA;BBBBBBBBBBBBBBBBBBBBBBBBBABBBBBBBBBBB@)@BBB at BBBBB UQ:i:0
+20GAVAAXX100126:8:21:13663:85034 83 chr1 10000794 60 101M = 10000518 -376 TGCTTGAACCCAGGAGGTGGAGGTTGCAGTGAGCCTAGATCACGCCACTGCACTCCAGCCTGGCGACACAGCGAGACTCCGTCTCAAAAAAAAAAATAATA =0;BC at D<A?CDCBDCACCBCCADCBBDAABDBBCC at BCCB@;BCBBCB;B at CACBCB?CCBB8BBBBBCB;B?BBC at C;@DCD>>>>>>>>=DDCCBBCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:@8 at FFFH@FDHHHHHHHHHHIHHHHHHHHDHHHIHHEHHGHEHHHHGHGBHFHFHHHHFHHHHFHHHHHHHHHEHHHEHHGHHHEEEEEEEEEHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:25:6601:158705 147 chr1 10000802 29 66S35M = 10000400 -436 TGTACATGGTGGTGGGAGCATGGAGTCCCACCTACTCAGGAGGCTGAGGCAGGAGAATTGCTTTAACCCAGGAGGTGGAGCTTGCAGTGAGCCTAGATCAC ##########################################################################??=9;5*BBA6:?9'@5;096;>8?B? MD:Z:14G20 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:1 SM:i:0 MQ:i:37 OQ:Z:##########################################################################@;9654)@@@35@<'<5;-:/<<5@?? UQ:i:9
+20GAVAAXX100126:8:61:14621:35929 83 chr1 10000818 60 101M = 10000470 -448 TGCAGTGAGCCTAGATCACGCCACTGCACTCCAGCCTGGCGACACAGCGAGACTCCGTCTCAAAAAAAAAAATAATAAATAAGAAAAGGAAAAAAAAGAAT 7D2DAD at AAA?@DBC??@9;=>AAC?BBCDCADABCCCB;BCB at BDB;BDB?CDC;ADADA@@@@A@@>@DCCDCCDDCBADBDDDDB at AAAAADDD@CCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:5H8HHHGDFFEFHHHCDDFBBDFFHEHHHHHFHFGHHHHHHHIDHHHHHHHDHHHHHHGHGGGGGGGGEGHHHHHHHHHGGHHHHHHHGGGGGGHHHHHHH UQ:i:0
+20GAVAAXX100126:8:22:20335:91038 163 chr1 10000847 29 68M33S = 10001097 350 TCCAGCCTGGCGACACAGCGAGACTCCGTCTCAAAAAAAAAAAAAATAAAAAAAAAAAGAAAAAAAAAAAAAAAAATAAAGGAAAAGCCAAATGCAGAGAA @BBBAABCBCA;A at B@CBA:CBB?CBC;BBDB9ACC?<@A??2)<4';C72<8)AC;%7(=CCBCD=################################## MD:Z:43T6T2G5G8 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:4 SM:i:0 MQ:i:37 OQ:Z:BBBBBBBBABABABAABAAAAA??ABBB?ABA7?BBA>AA@?2(?4'8A22;3'<A7%3'>AAAAA?################################## UQ:i:40
+20GAVAAXX100126:8:65:4263:123939 99 chr1 10000877 60 101M = 10001182 403 CAAAAAAAAAAAATAATAAATAAGAAAAGGAAAAAAAAGAATACAACTCAGGAACAGCCAAATGGAGGAGATGCATGGGACAAGGTTTAGTGGGGGGCTGC CCDBDDD>>>??>A>?A?DDCCDCDDD?=CDDDDDD??>@A at C>CDADBCCCBDACCBACDDCBCDCCDCA:;9:B@@ABACBACAB@>;::555@?>DD5 MD:Z:0T0C99 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:2 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHEEEEEECEECFHHHHHHHHHEEHHHHHHHEECECCHFHHHHHHHHFHHHHHGHHHHHHHHHHHE at B@=GGFFGHHFGHDFDD?54444CCCHH5 UQ:i:68
+20GAVAAXX100126:8:48:15961:32254 675 chr1 10000919 29 27M74S = 10001301 416 ACAACTCAGGAACAGCCAAATGGAGGATTTGCGCGGGCCTTGGTTTAGTGGGCGGCGGCGGAGCTTTCTCGCCCTCCGCAAGTGAATCACCCTTCCAGTGC 8=1==>?4A############################################################################################ MD:Z:27 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:0 SM:i:29 MQ:i:29 OQ:Z:3</<===0@############################################################################################ UQ:i:0
+20GAVAAXX100126:8:25:1952:6902 99 chr1 10000924 60 101M = 10001276 438 TCAGGAACAGCCAAATGGAGGAGATGCATGGGACAAGGTTTAGTGGGGGGCTGCGGAGCTTCCTTGCCCTCTGCAGGTGCACCACCCTTGCAGTGCGTGGA CBCACDDACCBBCDDCBCDCCDCDCBBCCBCCDACDCCADDCCABCCCBBBDBB;CCCBDDBBDDBBBBDBDBBCCC:BBCACC?CCDDCCCCC at C;CCE= MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHIHHHHGGGHHHHHGHHHHHHHHHIHHHHHHHHHHCHHHHHHGHHHHHHHHHGHHHHH? UQ:i:0
+20GAVAAXX100126:8:22:20896:187194 163 chr1 10000959 60 55M46S = 10001303 444 AGGTTTAGTGGGGGGCTGCGGAGCTTCCTTGCCCTCTGCAGGTGCACCACCCTTGCAGTGCGTGGATATGTTTGAGGCAGGGGGGCAGGGTGTGGGGGTTG @C<9BAA@@>=BCBBAC;@::3<AA99B at 5@;(;?63=947;94%>;>78;5A@############################################### MD:Z:55 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BB=5 at BA@<;>ABBAA at 7@A:/9@=55@<4 at 9)9 at 84@>69=70(=9:56>5;A############################################### UQ:i:0
+20GAVAAXX100126:8:22:20335:91038 83 chr1 10001097 37 101M = 10000847 -350 AAATTGAAAAGAAAATCCTAACTTTCCAAGCCTAAGTAACAAAAGGACCAGAGGCTACCCCTTTGCAAACCCCTACCTTTTCTGTGGCAGATGGGAAATTG EECED?@?ADCDDB at CCCCD;CDDDCBDDBCCCDDABAABDDDDBBBCBDBCBBCC at CCCCDDCBBDD:CCCCCACCDDDDCCACBBBDBCCBCBDDADCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:37 MQ:i:29 OQ:Z:HHHHHEGEGHHHHFEFHHHHBHHHHHHHHHHHHHHHGGFHHHHHHHGHHHHHHHHHFHHHHHHHHHHHCHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:48:6949:111164 99 chr1 10001106 60 101M = 10001431 425 AGAAAATCCTAACTTTCCAAGCCTAAGTAACAAAAGGACCAGAGGCTACCCCTTTGCAAACCCCTACCTTTTCTGTGGCAGATGGGAAATTGTAAGTACCT CCCBDDCBBDCDADDDBBCDCBBDCDCBCDACDD at ACDABCCDCCBCCABBBDDDBBCDDABBCDCABDDDDBDBCBCBBC<CCCC=AA at BABABA>A?A@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGH at HHHHBGGEFFFFFGAFFFA UQ:i:0
+20GAVAAXX100126:8:21:7038:31450 99 chr1 10001134 60 101M = 10001404 359 AACAAAAGGACCAGAGGCTACCCCTTTGCAAACCCCTACCTTTTCTGTGGCAGATGGGAAATTGTAAGTACCTCTAATTAATTAATTAATTGCCTTTTTTT CD at ADDAACDABCCDCCBDCABBBDDDBBCDDABBBCCABDDDDBCBBBCBCCDCBCC;DDCDBBCDC=CABDBDCDCDCDCDCDCDCDCDCCADDDDDE@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHBHHHHHGHHHAHHHHHHHHHHHHHHHHHHHIHHHHGHHHHHHE UQ:i:0
+20GAVAAXX100126:8:65:4263:123939 147 chr1 10001182 60 2S99M = 10000877 -403 GTTGCAGATGGGAAATTGTAAGTACCTCTAATTAATTAATTAATTGCCTTTTTTTTTTTTTGAGACAGAGTCTCTCTCTGTTGCCCAGGCTGGAGTGCAGT ###B;?C2%<?@>CCD@=1?C<B=2<??<?<C;-?BC7<B/?;??@?@DBBECDCB:?BBA>C??ACCDACCCCABCB?ACBBCCBCA?CABBC at AAAB@? MD:Z:0G98 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:###@5;B/%9><BAAA=>.>A>@:6:>?99>A8-A?B7;@0<98=><ABCBCBBA@=;AACCBCBBBCBBBBAB?AAA<BAABBBBABABAABBBAABAA? UQ:i:2
+20GAVAAXX100126:8:4:13777:19279 633 chr1 10001217 0 66S35M = 10001217 0 AAGAGAAAATCTTGCATTTTTAAAACTCAAATGTGGATTTCACGGAAACATCAAGGTGATTTGTGTAATTAACTCCCTTTTTTTTTTTTTGAGACAGAGTC ##################################################################################################### MD:Z:6T1G26 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:2 SM:i:0 OQ:Z:##################################################################################################### UQ:i:4
+20GAVAAXX100126:8:4:13777:19279 693 chr1 10001217 0 * = 10001217 0 AAGAAAACCCACTCAAGACTGACTTCCCAGAGAGGTGATGGATGAAGCATTTCCCTTTTACTATTATCTTTCCATATTGTTTAATAGCCTTCAATAAGAAG ########################################>;@=B4B at D=<>9>,1)@7A;:*3;3;,A2=-:+:A4A=AD=-=AB8:2C?<ABB=9-AC2 PG:Z:BWA RG:Z:20GAV.8 OQ:Z:########################################@9>8 at .ABC=>8;<*/)=:A=>+5 at 4=+>.:14*9 at 1>>>B=,:A at 6>1A?8?CB=3+@@-
+20GAVAAXX100126:8:25:1952:6902 147 chr1 10001276 60 14S87M = 10000924 -438 GCCCAGGCTGGAGTGCAGTGGCACCATCTCAGCTTGCTGCAACCTCCACCTCCTGCGTTCAGGTGATTCCCCCACACTTACTGGGCTGCATTCCCAGAAGG ###############BB:;?9ABA?>A=C=<BC@@CBBAB3>4?CBC4DC at DCC@;=DCACB at B@BCC=CBCCBBBCDCACDDCBCCABCCBBBAA?@CD@ MD:Z:16G70 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:###############??:4>:B=@?=?>?6;BA>ABABAB4859A at B4BBABBA>BABBABBBBBBBA=BABCBB at CBBBBCCBBCBCBCBCCCCCCCCCB UQ:i:27
+20GAVAAXX100126:8:48:15961:32254 595 chr1 10001301 29 66S35M = 10000919 -416 TTTTATGAGACAGAGTCTCTCTCTGTTTCCCAGGCTGTAGTGCAGCGCCACCATCTAAGCTTGCTGCAACCTACACCTCCTGCGTTCAGGTGATTCCCCCA ##################################################################################################### MD:Z:6C28 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:1 SM:i:29 MQ:i:29 OQ:Z:##################################################################################################### UQ:i:2
+20GAVAAXX100126:8:22:20896:187194 83 chr1 10001303 60 101M = 10000959 -444 ACCTCCACCTCCTGCGTTCAGGTGATTCCCCCACACTTACTGGGCTGCATTCCCAGAAGGTTAAGGCATTCTTAGTCACAGGATGAGATAGGAGGACAGCA 7ADDAC8A;.?C>B;ADDCDBABB at D=:BB at AAAAAABBCCB=ACAABCAA:CBCBDCB<DCDCB?@CDCCDCDADBBBDBBC?BD?CCDBBDCBCCBBBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:6FHHFH;F?0DHAHHHHHHHHHFHEH>@GGFFFFFFGGGHGHEGHEGHHGF at HHHHHHHAHHHHHEFHHGHHHHHHHHHHHHHDHHFHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:63:14360:55959 163 chr1 10001309 60 101M = 10001646 437 ACCTCCTGCGTTCAGGTGATTCCCCCACACTTACTGGGCTGCATTCCCAGAAGGTTAAGGCATTCTTAGTCACAGGATGAGATAGGAGGACAGCACAAGAC @ABCAACBB;ACBBCC at BCDCBCCCCCACADCCBCAA@ACBBCCABCCCCABCACDCDBCACCBBD at CCB@DBAAB?ACBBBCABDBB at C>BBAC?C=@EA MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBBBBBBBBBBB=BBCBBBBBBBBBBBBBCBBBABBBBBBBBBBBBBABB?BBBABBBBBBBBBBABBBB at B>AB at B@AABA>BA?@ABAAAA5>@B UQ:i:0
+20GAVAAXX100126:8:23:14390:98082 99 chr1 10001338 60 101M = 10001748 510 CTTACTGGGCTGCATTCCCAGAAGGTTAAGGCATTCTTAGTCACAGGATGAGATAGGAGGACAGCACAAGACACAGGTCACAAAGACCTTGCTAATAAAAC CDCAADCCCBDBBCCDBBBCCDDCCBDCDCCBCCDBCDCCBBCACCCDCBDCDCCCCDCCDACCBCACDCDACACCCCBCACADCDAADDCCDCACDE@@> MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHGHHHHGHHHHHHGHHHGGE UQ:i:0
+20GAVAAXX100126:8:42:20734:56938 633 chr1 10001343 23 66S35M = 10001343 0 ACAGACATCTGAACCAGAGAAACCAAAGGTTGTATAGAATCTGTGTAAAATGAAGTTGATGCCGAATGGGGTGCATTCCCAGAAGGTTAAGGCATTCTTAG ################################################################################################948>8 MD:Z:4C30 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:1 SM:i:23 OQ:Z:################################################################################################@@@G@ UQ:i:2
+20GAVAAXX100126:8:42:20734:56938 693 chr1 10001343 0 * = 10001343 0 CGTTTCATGGAGCTGGAAAGCTAGAGCTTTCCTCTAAAAGGCAGGAAGATGGGTGCTAGTCACAGCTCTAATCCTAAATTGTGAAACCTTAAGCAATTCAT ##########################################################################################AB%6/>:)*?> PG:Z:BWA RG:Z:20GAV.8 OQ:Z:##########################################################################################@?'3-?6))>=
+20GAVAAXX100126:8:63:8225:63647 163 chr1 10001369 60 69M32S = 10001736 467 CATTCTTAGTCACAGGATGAGATAGGAGGACAGCACAAGACACAGGTCACAAAGACCTTGCTAATAAAACAGGTTGCGGTAAAGAAGCCAGGAAAAACCAC @AAA>?>BB=<B9BA at CA?>@ACCC@@52B,B47>48A?>?B:A76:<<>5@>.C/?B8C;1?<)?0B################################# MD:Z:69 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:@=A@>?;BC6=A>B??B@=:>>BBB?=13@, at 27@8=AA at AA>>9959;=6?8- at -==6B>.?;)>0@################################# UQ:i:0
+20GAVAAXX100126:8:21:7038:31450 147 chr1 10001404 60 11S90M = 10001134 -359 GGAGGACAGCACAAGACACAGGTCACAAAGACCTTGCTAATAAAACAGGTTGTGGTAAAGAAGCCAGGAAAACCCACCAAAACCAAGATGGTGATGAGAGT ############ACACB>ABA?@@;=BBDB>CB?7>C?CA=CCDBCCAAA at ABC@BACBABCABACBBCCCBCCCADBCCCBDCCDCBCCACBCA at BACA@ MD:Z:90 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:############A@>>A:>A?@;@9<@AA?>B@=9<B at B@?BBA at B@BA at AAAA@ABBAABBBBBBBBBBB at BBC?CBCCCACCBBCBBCCBBBCCBCCBB UQ:i:0
+20GAVAAXX100126:8:48:6949:111164 147 chr1 10001431 60 101M = 10001106 -425 AATAAAACAGGTTGTGGTAAAGAAGCCAGGAAAACCCACCAAAACCAAGATGGTGATGAGAGTGGCCTCTGGTCTTCCTCACTGCTCATCATACACTAATT C@/CD=9=:B4A7?>B78D?*7DB?B at ABBBCC;@CB>CBBCCCCBDACC at CACBCACDBC@BB>B at CCCCACCECCCCBBCCBCCBBCBCCBAB@A at BD@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:A:->@:/;3?5;6?8=77B>)7A@?A@@@@AA at 6BAA>BABBA?BABABBAABBABBBBBBBBBABABBBBBBBCBBBBB at CBBBBBBBCBCACACBCCBB UQ:i:0
+20GAVAAXX100126:8:41:12744:193967 163 chr1 10001443 60 101M = 10001607 264 TGTGGTAAAGAAGCCAGGAAAACCCACCAAAACCAAGATGGTGATGAGAGTGGCCTCTGGTCTTCCTCACTGCTCATCATACACTAATTATAATGCATTAG @CAA?<ABC at CD;>B=ABCDDDADCCACCDDD at CBAAA8?>9<7:>BB)@8=A9CBBC@>6:@=<B?9>?<BAA=;?@CB?<@<?5B@<8@;=;A8?C9=7 MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCBB>9AAB=BB>AA;@AABBBBCBBBBBBBBABBABA<A at 6>3>>>?*<6>>=?=A??=2:>=:@@99@;@@@=9?@@A?=:=<1=?<4@:7:<6:?672 UQ:i:0
+20GAVAAXX100126:8:67:20277:111625 163 chr1 10001509 37 90M11S = 10001528 88 TCACTGCTCATCATACACTAATTATAATGCATTAGCATTAGCACCCACCACACCCAGCTAATTTTTGTATTTTTAGTAGAGACGGGGGTAGATCGGAAGAG @CB>B>AB>B;A<BCAD@@;?>:C at ADDC@DBC<=A7=<=@>@AA at B@>D60 at ACD?AC?>CCBCA7>B?=7CA<B>:A>BAB::@D,;C4 at 6;;@9C;C= MD:Z:51G35T1T0 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:3 SM:i:37 MQ:i:37 OQ:Z:BCC at B?BA<A<?>BBBCA<:<<7B?ABCC?CAA<@B<@?@C?@BB??@>C;- at BBB>>A>?BBBBC::A=>1@@=A=C==BBBA:=B06B1=1:BB4>7<: UQ:i:60 XT:i:90
+20GAVAAXX100126:8:2:15613:129653 99 chr1 10001516 29 101M = 10001879 396 TCATCATACACTAATTATAATGCATTAGCATTAGCACCCACCACGCCCAGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTTACCATGTTGGCCAGGAT CBCABCCCACADBDCDCCCDCBBCCDCCBCCDCCBCABBCABCA;BBBCCBDCDCDDDDBBBCDDDAACCCCBCDA;CCC;DDDCACCCCCDCC>CDDDE= MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:0 SM:i:29 MQ:i:29 OQ:Z:HHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHGGHHHHGHHHHHHHCHHHHHHHHHIHHICHHHHH@ UQ:i:0
+20GAVAAXX100126:8:6:3004:12551 675 chr1 10001521 29 74M27S = 10001879 391 ATACACTAATTATAATGCATTAGCATTAGCACCCACCACGCCCAGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTTACCATGTTGTCCAGGATGGTCT @B6<A?BBCCA?::C:=A>ACD@@CC?;A:9><AB at 6=:.72?::@@'5B1=C;@B6B>C9=/;>9=@.7?9C############################ MD:Z:74 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:0 SM:i:29 MQ:i:29 OQ:Z:B at 7=ABCBBB@>=?@8:@:@AC>?BB=:@:6=:@BB;??8;3 at 5=@;(3 at 3=B=;;4@<B:<.;67@>+4B;A############################ UQ:i:0
+20GAVAAXX100126:8:67:20277:111625 83 chr1 10001528 37 31S70M = 10001509 -88 CTCTTCCGATCTTCACTGCTCATCATCCACTAATTATAATGCATTAGCATTAGCACCCACCACACCCAGCTAATTTTTGTATTTTTAGTAGAGACGGGGTT ################################=?:69;;3:-;;9>-2;<:=/=.78=48>195?@9?==B<-48>==02=?>?AB?:>A>?<<8=?7<=< MD:Z:32G37 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:37 OQ:Z:################################AA>655515/555502555514'4442440 at 3CC@DADG?08:A44114DADGG55444DD:FDFFGGG UQ:i:20 XT:i:90
+20GAVAAXX100126:8:21:3663:199637 99 chr1 10001543 60 101M = 10001860 376 GCATTAGCACCCACCACGCCCAGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTTACCATGTTGGCCAGGATGGTCTCCATCTCTTGACCTCATCATCC CBCADCCCCABBCABCA;BBBCCBDCDCDDDDB at ACDDD@BCBCCDCDA;CCCBDDDCABCCBCDBCBBCCCDCBCBBDBBCCBDBDDCDACDCDCCDCDD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHEGHHHHGGHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:63:4634:186518 99 chr1 10001553 23 71M30S = 10001924 425 CCACCACGCCCAGCTAATTTTTGTATTTTTAGTAGAGACGGGGTTTTACCATGTTGGCCAGGATGGTCTCCATCTCTTGACCTCATCATCCGCCCACCTCA :<>6=@>8@??;=:<?;=>?>>5;;@AA@;3::83;=;:4B>=@@<<;9;9:;;;=7:;;=7;;<@;>?=############################### MD:Z:71 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:23 MQ:i:29 OQ:Z:EFCFDFFFFFFBABBF at AAAEC;@>FFFF at 6=@=844445GEEEF44455:>=@=4555555555CCCCA############################### UQ:i:0
+20GAVAAXX100126:8:26:17894:31587 163 chr1 10001582 60 97M4S = 10001891 407 TAGTAGAGACGGGGTTTTACCATGTTGGCCAGGATGGTCTCCATCTCTTGACCTCATCATCCGCCCACCTCTGCTTTCCGCAACCAATCGGACTGATTACA @CBAAABBCA:CCBBCCCCACCCBACBCCCC@@BBA?>?C8C at C@BCDCA@>CACCAB at A@C9>CA9 at BC@B?@=<@<C7=A?>BCC>;48?@BBB##### MD:Z:97 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBAABABBBABBBABBBBBBBBBBBBABBB>?@BBA at AB;B at BB@BAA at A@AABA@?>?AA@?B><A?AA<;B:;?=A>=?9????<=5:;??=?##### UQ:i:0
+20GAVAAXX100126:8:41:12744:193967 83 chr1 10001607 60 101M = 10001443 -264 TGGCCAGGATGGTCTCCATCTCTTGACCTCATCATCCGCCCACCTCTGCTTTCCGCAACCAATCGGACTGATTACAGGCCACTACTTCACCTCATTTACAT A>CACBC>CC at AC?CCBCAAD at ABBCA>B at CDB@D>;?CCBACCCCCBC?D:C;BB at BCBDCD;BBBCCBCDCBBDBBCBCCCBCDDB at CC<BCDDCABCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GAHFHDHEHGFHGEFGHHEGHGGFHHGDGGHHHEHDHDHHHGHHGHHHHDHBHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHEHHBHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:63:14360:55959 83 chr1 10001646 60 101M = 10001309 -437 CCACCTCTGCTTTCCGCAACCAATCGGACTGATTACAGGCCACTACTTCACCTCATTTACATGGGTGAACACCCAGTGGCCAATGGGAAACCTCTAGTGGG BDCDCDCDCCDDDC;BBDCCBDCD;B at BBCBCDCBBDCBCBACCBCDDB@CCDBCDDCBBCCBBACBDBB at CCBDACBBCBDCCBBBDDBCCDCCDAABBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:FHHHHHHHHHHHHHHHHHHHHHHHHHGHIHHHHHHHHHHHHGHHGHHHHEHHHHHHHHHHHHHHHHHHHHEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:65:13649:138985 99 chr1 10001701 60 93M8S = 10002037 410 TTTACATGGGTGAACACCCAGTGGCCAATGGGAAACCTCTAGTGGGTATTTGGACTGGAGAAAATTCTGTATCCAGGGCCCTTGAGTGGCTGGCGGGGGCC CDCAACCCCCBBDDACABBCCBBCBBCDCBCCDDDABCBCCCBBCC at CCDDBCDADBCDCDDDDCD@DBCCCBBCCC at BCBDDCDCCCCBBA######### MD:Z:92C0 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHEHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHFHHHHHHHHHHHHFF######### UQ:i:2
+20GAVAAXX100126:8:63:8225:63647 83 chr1 10001736 60 101M = 10001369 -467 CCTCTAGTGGGTATTTGGACTGGAGAAAATTCTGTATCCAGGGCCCTTGAGTGGCTGCTGGGGCCCGCTCCCACCTGGTGAAATGTACTTTCATTTTCAAT &<C=?A?A<=>CCBBC;=:?<:;===DAADD?B9:?8C>AB::+09 at A=A>=:9:<B:C=BB=CC;BCDCC=====BACBDDCCACB at DDDBCDDDD@CCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:2BFBDCFEBBEHHFFH at DCD@@>>A>HFFHHDFB at D:HEEH==26:CFDFFA@@@=H at HEHHAHHHHHHHHA4DDAHHHHHHHHHHGCHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:23:14390:98082 147 chr1 10001748 60 101M = 10001338 -510 ATTTGGACTGGAGAAAATTCTGTATCCAGGGCCCTTGAGTGGCTGCTGGGGCCCGCTCCCACCTGGTGAAATGTACTTTCATTTTCAATAACTCTCTGCTT BE at DC@CAC?@D??DA>BCAB at CABB@ACB@;BA at CBAACBBCDBCDACC?DB9CB at CAB>=AB7 at BBCCDCACBCDECBCDEECCBABBABCBB@AABD@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:@@BBA???@=A@@=@<<A?ABBBA at A@@B>A:?@B at A@BBBABBBBBBBBABA at BAABAB?@BB<BBBABCBBB at BBCBBBBCCBCCCBCACACBCBCCBB UQ:i:0
+20GAVAAXX100126:8:66:19565:6891 99 chr1 10001761 60 35M66S = 10002052 375 AAAATTCTGTATCCAGGGCCCTTGAGTGGCTGGCGGGGGCCGCCCCCACCCTGTGAAATTTACTTTTACTTTCTATAACTCTCTGCTTTTTTTGTTTCATT >>=7>@?A?@<B<B?<@=9><?<<;A@@B@####################################################################### MD:Z:32C0T1 PG:Z:BWA RG:Z:20GAV.8 AM:i:25 NM:i:2 SM:i:25 MQ:i:60 OQ:Z:DFADAFFFFFDGDGD>C?@A44555GEFGF####################################################################### UQ:i:4
+20GAVAAXX100126:8:28:18116:51320 99 chr1 10001794 60 101M = 10002126 432 TGGGGCCCGCTCCCACCTGGTGAAATGTACTTTCATTTTCAATAACTCTCTGCTTTTGTTGTTTCATTTTTTTCTTGGTTGTGTGTTTTCTTAAACTCTTT CBCACCCC;BDBBBBABDBCCBDDDCBBCADDDBCCDDDBCDCCDACBCBCBBDDDDBC at ACADBCCDDDDD@@BA>CBDBCCCBCDDDBDA<<AAD at BEE MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHGHHHHHHHHHGGGGEHIHHHHHHHHHHHHGB at GHHGGHH UQ:i:0
+20GAVAAXX100126:8:25:15872:153534 163 chr1 10001807 60 101M = 10002149 442 CACCTGGTGAAATGTACTTTCATTTTCAATAACTCTCTGCTTTTGTTGTTTCATTTTTTTCTTGGTTGTGTGTTTTCTTAAACTCTTTTTTTTTTTTTTTT @CABAABABCCDCABCADCCBCDCCCBCDCCDADAC at AAACCCC@ACCACAACADDCDCC at DCACC@BCB at CCACC@BD???@BADDC at BBCBBBBDCBEC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBCCCBB at BBBBBB@BBBCBBBCBBBBBBBBBBBBBBABBBBBBB at BB@BBAABBBABBBABBBA at AB>A?B@@AA at BA?>>@@?@@A@?AA?@?@@?AAB UQ:i:0
+20GAVAAXX100126:8:25:15890:153544 1187 chr1 10001807 60 101M = 10002149 442 CACCTGGTGAAATGTACTTTCATTTTCAATAACTCTCTGCTTTTGTTGTTTCATTTTTTTCTTGGTTGTGTGTTTTCTGATACTCTTTTTTTTTTTTTTTT @@ABB at A6BCBC;>@?ADCCABCCCC=CDCACAD at C@C<?>5CC at BCCACABCACDCDCCADCACC@BC>7AAAB(A?(5(5ABB at DC>B>5A at CACAACA MD:Z:78T1A20 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:2 SM:i:37 MQ:i:60 OQ:Z:B>CABA?4BAAA>A8?BBBAAABBCC;ABBAABBCBBB at A?5BBBABCBBBBBBCBBBBABBABBABB?;3><BB(A>'5)5ABB:@AB>=3=>>??;?<> UQ:i:14
+20GAVAAXX100126:8:24:3855:143240 163 chr1 10001827 60 85M16S = 10002054 327 CATTTTCAATAACTCTCTGCTTTTGTTGTTTCATTTTTTTCTTGGTTGTGTGTTTTCTTAAACTCTTTTTTTTTTTTTTTTTTTTTTCTTTGATTTTTCCT @CB at A<ABC>AD>BBE at CCBECCCCACCBCBBBA@><BBBBBBCA>BC at C=BBADDABCCBDACB/5;D>:BD3=BBA??@AD@################# MD:Z:85 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCCB<AAA<ABACBC?ACBCCBCCBCB?BCA@@CC at BBBBAABB=>B?B?BABABC=BBBBBBB+7:B;;?A3<@BB;>?BB?################# UQ:i:0
+20GAVAAXX100126:8:21:3663:199637 147 chr1 10001860 60 41S60M = 10001543 -376 TGTGCTTTCATTTTTAATAACTCTCTGCTTTTGTTGTTTTTTTTTTTTCTTGGTTTTGTGTTTTTTTAAACTCTTTTTTTTTTTTTTTTTTTTTGATGGAG ##########################################BCDCD8(;8/;>>)0.2-9A>?(>:3=89+)CDDDDDDDDDDDDDBCDCCCBABABBD@ MD:Z:14G8C36 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:2 SM:i:37 MQ:i:60 OQ:Z:##########################################@@B at B8'::->:9(/-1/;A@@*@>3<16+(ABBBBBBBBBBBBBBBBBBBBCBBBBBB UQ:i:15
+20GAVAAXX100126:8:2:15613:129653 147 chr1 10001879 29 64S34M3S = 10001516 -396 GGAATGTCGTTTCATTTTCAATAACTCTCTTCTTTTTTTTTTTCATTTTTTTCTTGGTTTTGTTTTTTCTTAAACTCTTTTTTTTTTTTTTTTTTTTTTGA #################################################################>C;'79AA94)*ADEEEEEEDEBCDDCCCBABCBC@ MD:Z:34 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:0 SM:i:29 MQ:i:29 OQ:Z:#################################################################@B8&39>>40*)?BCCCCCCBCCBCCBBBCCBBCCB UQ:i:0
+20GAVAAXX100126:8:6:3004:12551 595 chr1 10001879 29 68S10M1D23M = 10001521 -391 TATGAGATTGTTTCTTTTTTTTTTCATTCCGCGAGTTTTTTTTTTTTTCTTTTTTTTCTTTGTTGGTTTTTTTTTATATATTTTTTTTTTTTTTTTTTTTT ##################################################################################;;;<;;;;=;;;;=?428? MD:Z:4C3A1^C1C21 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:4 SM:i:29 MQ:i:29 OQ:Z:##################################################################################@@@@@@@@>@@@@EA at 2@A UQ:i:6
+20GAVAAXX100126:8:26:17894:31587 83 chr1 10001891 60 2S99M = 10001582 -407 CTCTTTTTTTTTTTTTTTTTTTTTGATGGAGTCTTGCTCTGTCACCCAGGCTGGAGTACAGTGGCGTGATCTCGGCTCACTGCAACCTCTGCCTCCCAGGT ###@>BA;A at AAA@AB=ADDDDDCBCCBBDADCDCBCDCCADBBCCBDBBCCBBCACBBCACBB;ACBCCCD;BBCDBBCCBBDBCCDCCBCCDCCCBBAC MD:Z:99 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:###GBGG?GEEGGEGG>GHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:63:4634:186518 147 chr1 10001924 29 46S55M = 10001553 -425 TGTTTTTTACATTTTTTTTTTTTTTTTTTTTTTTTGATGGAGTCTTGCTCTGTCACCCAGGCTGGAGTACAGTGGCGTGATCTCGGCTCACTGCAACCTCT ###############################################@C:5==8->548?7027 at 84B,-B2**(%6A;>))B4B:A4-B9<==A at 7>A@? MD:Z:55 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:0 MQ:i:23 OQ:Z:###############################################A?95;<3'>:08?;029B88A)+ at 2(**)6?8<))@7 at 9@5- at 88;=?A7>@<> UQ:i:0
+20GAVAAXX100126:8:65:13649:138985 147 chr1 10002037 60 26S75M = 10001701 -410 GCCCGCCGAAGAGCTGGGACCACAGGCACCCGCCACCACGCCCGGCTAATTTTTTGTATTTTTAGTAGAGACAGTGTTTCACTATGTTAGCCAGGATGGTC ###########################ADB3?8>9DC@;=BC;B>CC9DBBDCDBAACCB879C4BCBDAACC?B>DCCB?AADDBEADBCBCBAA at BAC@ MD:Z:75 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:###########################@B>;>8>9BBBB=BAB>>CBCCABBBB?BBBCA:9>B<BBBC@?CA@@?BAAA8?ACCCCCCCCCCCCCCBCBB UQ:i:0
+20GAVAAXX100126:8:66:19565:6891 147 chr1 10002052 60 16S85M = 10001761 -375 GCTCCCGCCGCCACGCCCGGCTAATTTTTTGTATTTTTAGTAGAGACAGTGTTTCCCTATGTTAGCCAGGATGGTCTCACTCTCCTGACCTCGTGATCTGC #################95>>784B6A14:35D4:*C4A:6:B@<;79AC667=<$87B:3>3C896+8A9<@9)6)A7*,+).>B*/5>9:A>777:??> MD:Z:39A23A21 PG:Z:BWA RG:Z:20GAV.8 AM:i:25 NM:i:2 SM:i:37 MQ:i:60 OQ:Z:#################@1>>942A4?//353B2=*@5?;95B9;519BB;168:(;5C;7 at 8B>=5*8 at 79=7)2*@0)+*)0;A*+9;7AC=2527?== UQ:i:12
+20GAVAAXX100126:8:24:3855:143240 83 chr1 10002054 60 101M = 10001827 -327 GGCTAATTTTTTGTATTTTTAGTAGAGACAGTGTTTCACTATGTTAGCCAGGATGGTCTCAATCTCCTGACCTCGTGATCTGCCCGCCTCGGCCTCCCAAA AD<DDA?@@DDC=?@DDDDCDAAD at DBABDACAADB:9>@=CA@;DBCBDBBCC=A>9:??>6=;==?B at CCD;?CBC=CCABB5>=CD;BBC=D=<4:<< MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:FHBHHEEEEHHHEEDHHHHHHHGHGHHGHHHHHGHF at BCCBHHCBHHHHHHHHHEHCBBCDD;A at DEEHFHHHHGHHH>HHGGGEEEHHHHHHEHDEEEGG UQ:i:0
+20GAVAAXX100126:8:48:18256:122283 163 chr1 10002059 60 101M = 10002396 437 ATTTTTTGTATTTTTAGTAGAGACAGTGTTTCACTATGTTAGCCAGGATGGTCTCAATCTCCTGACCTCGTGATCTGCCCGCCTCGGCCTCCCAAAGTGCT @CA@??@ABBCBB at BCCBCCCCCACCBCBCCBCACBAA?BBCBCACDCCCA at CBCDDDBDACC?CA at DC;@CA<@BAAB?8ACBB:DA at D>ABAC@@<<DA MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCCCCCCABCCCCCBBABCBBBBBCACBBBBBBBBBBABBBBBBBBABBB?BBBBBBABBBA@@BABBB?B=>@@AA@>@A@@B at A?A@>BB??=;1:B> UQ:i:0
+20GAVAAXX100126:8:61:16672:156327 163 chr1 10002072 60 101M = 10002410 438 TTAGTAGAGACAGTGTTTCACTATGTTAGCCAGGATGGTCTCAATCTCCTGACCTCGTGATCTGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCG @CBBA at BCBCACB>BACCBCBDCCBACCCCCBCCABAB>ACBCCABDBCD?BA at DC;CCB?BC?AB49ACAB:AAAB?CB>9BA=CC>?C1BBA@<=C>C: MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBB at CBBBBBBBABABBBBCBBBBBBBBBBABBABBB@BBBBABBBABBAABAABB at B@@AA@@@8@@B at A@AA at A?AB=7=@6AA;@A4@@?<;7@=?@ UQ:i:0
+20GAVAAXX100126:8:28:18116:51320 147 chr1 10002126 60 101M = 10001794 -432 TCGTGATCTGCCCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCACCTGGCCCTTGTTAAATTCTTTGTTCAAAATGCCAAAAACCT 85=C@;CA75=9/=A<?9C==9@;<>BADA at ABB@B?@CA>A at C@:A at BC@CABC;;C at CABAA?=BCCADCCCCDCCEECADCCCB at CCBCBBBAAACC@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:45==<8??14=84<>6<??==8;<==@@@A@@?AA@>@B@>@=B@@AAAABAA>ABCB at BABBBA@BABBBBBBBBBBCCBBBBCBCCCBBBBBBBBABCB UQ:i:0
+20GAVAAXX100126:8:65:9835:166164 163 chr1 10002137 60 101M = 10002441 404 CCGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCACCTGGCCCTTGTTAAATTCTTTGTTCAAAATGCCAAAAACCTGGACACCCTCC @C:AABA:CBCDBACCDDB?BBDBCCCBCCABBC?8>A=B;CAA=7 at C=C;?A?CCBB@@BBAABA?BDA>CB at B?=?CAAACACDB@@C at 4(9C?7D>@B MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBBBBBBBBBBBBBA<BBBBBBAABBBAABAAAB?B>BAA?>>A?B=?>AAB???;AA?@A?A at A????A@=<>AAB?@?@@=B@?A5'9?A3?::? UQ:i:0
+20GAVAAXX100126:8:26:12389:180500 99 chr1 10002138 60 101M = 10002456 418 CGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCACCTGGCCCTTGTTAAATTCTTTGTTCAAAATGCCAAAAACCTGGACACCCTCCA C;B at DB;CBBDBBBCDDCB at BDBCCDCDCACCCA;B at DCBBCAB;BCABCBCBBBDDBC at CDDCDBDD@BCDBCDDDCBBBBDDDBA+ACCDADABABCDE MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHIHHGHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHGHHHHHHHHHHHHGHHHFH0DHHHHHHGGDHHH UQ:i:0
+20GAVAAXX100126:8:23:10396:142336 163 chr1 10002141 60 101M = 10002456 415 CTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCACCTGGCCCTTGTTAAATTCTTTGTTCAAAATGCCAAACACCTGGACGCCATCCACTG @DB:BA at CBCCCCBA<AACBCBCCCCACCCB;BA?;@7<;-7 at B=CD at 898BD;CBAADC<<;<CC??DA=CB3>;'7<49/A;.A5;<)#8?):>=C?E9 MD:Z:81A8A2C7 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:3 SM:i:37 MQ:i:60 OQ:Z:BBBAAB=BABBBBB at 7@AAABABBBBBBBABBA@@>B9?@. at A@ABA=:6;AA=BA??BA>;:;ABB=B@=??1>:*6737/<;-;0;<*&6;'4=8??@4 UQ:i:24
+20GAVAAXX100126:8:25:15872:153534 83 chr1 10002149 60 101M = 10001807 -442 CCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCACCTGGCCCTTGTTAAATTCTTTGTTCAAAATGCCAAAAACCTGGACACCCTCCACTGGTACTGAA DE?DDDADCCCCCBCDCACDB>;ACBBBCBBC;BBBCCCBBCCCDCADCDDCDDCDDCADDBDDDCCBCBDDDDBCCCBBCBBCCCDCBBCCBACCCABDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHGHHHHHHHHHHHHHHEHHHCHHHHGHHHIHHHHIHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:25:15890:153544 1107 chr1 10002149 60 101M = 10001807 -442 CCCAAAGTGCTGGGATTACAGGCGTGAGCCACCGCCCCTGGCCCTTGTTAAATTCTTTGTTCAAAATGCCAAAAACCTGGACACCCTCCACTGGTACTGAA ?<ABAB-?A=B8(99:4AAB at A97B;;85;2)526%==<>7=BADCADCAD at AA@ADCADD=DDD?CBC=D at DDACAAA@A=7CCCBCBBCCBACCCABDC MD:Z:35A65 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:BBFFDF2CFBF4,555;FFFFFF5F at 5444/0464'AA at A9DGGHHHHHGHFFFFFHHHHHEHHHEHHHEHGHHGHGFGGFD8HHHFHHHHHHHHHHHHHH UQ:i:4
+20GAVAAXX100126:8:47:1669:10922 99 chr1 10002166 60 101M = 10002512 444 ACAGGCGTGAGCCACCGCACCTGGCCCTTGTTAAATTCTTTGTTCAAAATGCCAAAAACCTGGACACCCTCCACTGGTACTGAAGCTCACTGAACCTCCTT CACACC;C:DCBBCAB5BCABDBCBBBD at BBD=DD;@=??DB:D?CD?D?@BBCDDDD9BA?CA<B<>@@B at C<BBC at CABABBA@B>B=>7=<9CDCCAE MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHBHHHHHHHEHHHHHHHHHHHGHGHEHHBFEDDHHCHFHHEHEFHHHHHHHBHEEHEEFAAFDHFHDFHHEHHFFFFFCFCFD?;@@@HHHHDH UQ:i:0
+20GAVAAXX100126:8:21:8551:122892 163 chr1 10002192 60 101M = 10002500 408 CTTGTTAAATTCTTTGTTCAAAATGCCAAAAACCTGGCCACCCTCCACTGGTACTGAAGCTCACTGAACCTCCTTGTTCAGGAGTTTTCATAGAGCTCCAT @DAA;?ABCC=AD at BB?BCDEEEDBCDCDDCC>CCA4)7B at CCD@DCBDCAAC?B<BDCBCBC at D@?9?=>CCB?ABACBA8D=8)@@=B=?<7>?DC at DC MD:Z:37A63 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:BCCCCCAAAC=ACCCBCCCCCCCCBCCBBBAA?BBB;,;BBBBBBCBCBCB at BB<7 at BBCBBBBB>@7>:>BAA>A at BBA@9@;2);>B>=>748B?A>BA UQ:i:8
+20GAVAAXX100126:8:25:5802:132383 99 chr1 10002223 60 101M = 10002536 413 ACCTGGACACCCTCCACTGGTACTGAAGCTCACTGAACCTCCTTGTTCAGGAGTTTTCATAGAGCTCCATCTCCAGCCCCCTTCCCTCCCAGGAGGTTGGG CABBCCDACABBDBBCADBCCCADBDDABDBCACBDDABCBBCDBBDBCCCDABDDDBCCCCDCBDBBCCBDBBCCBCBCBDDB=CDBCABCCBC=6??>A MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHEHHHHGEHHEH?7ADEG UQ:i:0
+20GAVAAXX100126:8:21:10727:109276 99 chr1 10002227 60 101M = 10002534 407 GGACACCCTCCACTGGTACTGAAGCTCACTGAACCTCCTTGTTCAGGAGTTTTCATAGAGCTCCATCTCCAGCCCCCTTCCCTCCCAGGAGGTTGGGGTGG CCC?CACCDBBCADBCBCADBDDCBDBCADBDDABCBBDDBBDBCACDCADDDBCCCCCCBDBCCCBDBBCCBBBBBDDBBCDBCBBACDCCCDCDDD at DA MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHGHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHGGGHHHHHHHHHHGHG UQ:i:0
+20GAVAAXX100126:8:28:14388:67948 163 chr1 10002344 60 101M = 10002661 417 TAATCAAAGTCCTCTAATTTGGTCTTTCTGGTGAGCAGCCCCAACCCTGAGTCACATCATTAGCATAGACTCTGGTGTGTTCTAAAGGGGCTCCTTATGAA @CCBABCCBBBCDADCDCCCBCBADCCBDCCBAC=AAB<BBCCD?CCCBCAAB at BDCBCCBCCACC@CC at BBEAA@=8=B;@B?CC?23B?CAAD?BC at C@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCBBBBBBBABBBBBBBBBBBBA at BBBBBBB@@B at BBB@BBBBBBBB at B@B at AABBBAABABBABABBAAAABA@>>39@:B<?@>:46?@@@@A<@@A;< UQ:i:0
+20GAVAAXX100126:8:48:18256:122283 83 chr1 10002396 60 101M = 10002059 -437 CACATCATTAGCATAGACTCTGGTGTGTTCTAAAGGGGCTCCTTATGAATAGCAAAAGACAATCCTATCACTCAGGAAATTCCAAGGAATTTAGGAGCCCT DDCCDCCDCDCCCCDBCCDCCCACACADDCCDDDBBCBCDCCDCCCBDCCCBBDDDCBBBDCDCCCCDBBCDBDBBDDCDDCBDDBBDCDDCDCBDCACCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:61:16672:156327 83 chr1 10002410 60 101M = 10002072 -438 AGACTCTGGTGTGTTCTAAAGGGGCTCCTTATGAATAGCAAAAGACAATCCTATCACTCAGGAAATTCCAAGGAATTTAGGAGCCCTGTGCCAGAACCAGG EDCDDCDCACACADDCCDDDBCABCDCCDCCCBDCCDBBDDDDBCBDCDCBCCDBACDBCBBDDCDDCBDDBBDCDDCCBBDBCCCCACBCBDBDCC at CBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHIHHHHHHHIHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:65:9835:166164 83 chr1 10002441 60 101M = 10002137 -404 TGAATAGCAAAAGACAATCCTATCACTCAGGAAATTCCAAGGAATTTAGGAGCCCTGTGCCAGAACCAGGGAAAAAGACCAAATATATATTTCATTAAACT EDDCBDCCDDDDBCCD?DCCCCDBBCDBDBBDDCDDCBDDBBDCDDCDBBCBCCCCACBCBCBDBCBCBB@@DDDDBBCBDDCCCCCCCDDDBCDCDBBCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHGHHHHHHHHHHHEHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:23:10396:142336 83 chr1 10002456 60 101M = 10002141 -415 AATCCTATCACTCAGGAAATTCCAAGGAATTTAGGAGCCCTGTGCCAGAACCAGGGAAAAAGACCAAATATATATTTCATTAAACTTTACTACATGATACA EDDA?DC>CCCBCDCADDCBAABDDBBDBADCDB>D?>CC at ACBCBDB>BCBCBBA at DDDD?BC at DDCACCCCCDDDBADCDDBCDDCCCCCBCCBC:<BC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHFEHHAHHHFHHHGHHHFDGHHHHHHGGHHHHEHEEHHDHHHHHHHEHGHHHHGGHHHHGHHGHHHGHHHHHHHHHIHHHHHHHHHHHHHHHHHHGEHH UQ:i:0
+20GAVAAXX100126:8:26:12389:180500 147 chr1 10002456 60 101M = 10002138 -418 AATCCTATCACTCAGGAAATTCCAAGGAATTTAGGAGCCCTGTGCCAGAACCAGGGAAAAAGACCAAATATATATTTCATTAAACTTTACTACATGATACA CC=@C at C@BB at A5ADBB>@BB6C@<<>?A?BCC49C?BC?B?CCC6D at D>7BC>C<AC at 6;(8@;A?DCDCDBBEECCBEDACACED>@BBABBBAAA<B@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:A?9<@B at BB@@;3>B at B=<@A9B?:C>??8BB at 4=@>BB>B at BBB1ABA=<AA:A=BB at 8<)9A at A@CCCBCAACCCCACC?ABBCBAAAB=BCABAA9A@ UQ:i:0
+20GAVAAXX100126:8:21:8551:122892 83 chr1 10002500 60 101M = 10002192 -408 CCAGAACCAGGGAAAAAGACCAAATATATATTTCATTAAACTTTACTACATGATACAAACTACAGTTTGGAAAGACATTTAGGAATGGTAGAACAAAACAA &?DCDBDCDCC1:?@A at BBCBDDCCCCCACDDDBCDCDDCCDDCCCCBBCCBCCBBDDBBCBBCADDCBBDDDBBBCDDCDBBDCCBACD@AC at ADD9BDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:2GHHHFHHHHH7<ADDDHIHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHGGHHFHHH UQ:i:0
+20GAVAAXX100126:8:47:1669:10922 147 chr1 10002512 60 2S99M = 10002166 -444 GCAAAAAGAACAAATATATATTTCATTAAACTTTACTACATGATACAAACTACAGTTTGGAAAGACATTTAGGAATGGTAGAACAAAACAAGTGAGAAAAT ###DD?C8;->D>>@?;=773/65608?DC?9:78CBAB>6=C=ACDAB at 3BBC@B7)/3B>CA?AAA)?DA at CA<A?=DAC?CBBB<BBDABAB@?@AC@ MD:Z:7C91 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:###@@=>56'>A>=>;;<251-236.9?B@@5576BA at B>6;B:>BBBA at 5?B@?@9'/4BCBBBBC>(>B?>B at 9>?<BACCCCCCCCCCBAACCCCCC@ UQ:i:12
+20GAVAAXX100126:8:21:10727:109276 147 chr1 10002534 60 101M = 10002227 -407 ATTAAACTTTACTACATGATACAAACTACAGTTTGGAAAGACATTTAGGAATGGTAGAACAAAACAAGTGAGAAAATATAATATGTAAAAGGTCTTTTTGT CD7DCBCBCA@@>5BCB9DAAACBB<B at CE?CD at 9<CBDA at CBC@CE;DC;DCBDD?B=A?B>@=BBBCCECBCCDCDDCDCDDBCBBBDCACBBABCBB@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:C>CBB at BABBACB-CC@CBBABBA at CBBBBBAACC9BBBCBBC@>BCCCBCCBCCBA at CCCBCBCBCCCCCCCBCCBCCCCBCCCCCBCCCCBBCCBBBCB UQ:i:0
+20GAVAAXX100126:8:25:5802:132383 147 chr1 10002536 60 101M = 10002223 -413 TAAACTTTACTACATGATACAAACTACAGTTTGGAAAGACATTTAGGAATGGTAGAACAAAACAAGTGAGAAAATATAATATGTAAAAGGTCTTTTTGTCA BDBD@@D at AA<B>>DB>AB8BBB:ABB;ADBCCB at CC<AA=DDDBDC9DA;BADCB?C at CB@?B?>ACDCBBBDDDDCDDDDBDBBBBCAABDCBA@@AC@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:CB@@CBBBBB=BBCBCCBBCBBBCBABCCBBBBBBBACBCCBBCCCBCCCCCCBCCBCCBBBABCCCCCCCCCCCCCCCCCCCCCCCCCB at BCCCCCCCCB UQ:i:0
+20GAVAAXX100126:8:46:6526:26315 99 chr1 10002542 60 101M = 10002857 415 TTACTACATGATACAAACTACAGTTTGGAAAGACATTTAGGAATGGTAGAACAAAACAAGTGAGAAAATATAATATGTAAAAGGTCTTTTTGTCATTTCAA CDC?DCACCBDCCACDDADCACCBDDBCDDDCDACCDDCCCDDCBCBCCDDACDDB at CAABBDCDDDDCCCCDCCCBCCDDDCCABDDDDAAA@DCDDCEE MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHHHHHGGHGGIHHHHHHHHHHHHHHHHHHHHHHHGHHHHHGGEGHHHHHHH UQ:i:0
+20GAVAAXX100126:8:61:8680:44720 163 chr1 10002550 60 101M = 10002899 449 TGATACAAACTACAGTTTGGAAAGACATTTAGGAATGGTAGAACAAAACAAGTGAGAAAATATAATATGTAAAAGGTCTTTTTGTCATTTCAAAATACAAG @AA at 7;B?D@=@;9A at BAACCEECB:CCBCCCC9=B7/8?A09?ADDAAA=B:<BB=AB?ACBB at B@ABB?DDAB<45B?6?3=BCCB;D@<?<?ABB>C= MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:@?@@4=A?CA<?@;@>@?@BBCCB at 9BBCBBBA7?B=59CA/:@BBB=B=?A4?>?9;@<ABAB=@B at A@@AA at A<03>>5>/;?B at B;AA9:98@@A<<: UQ:i:0
+20GAVAAXX100126:8:28:14388:67948 83 chr1 10002661 60 101M = 10002344 -417 GCATGGTGGCTCACACCTGTAATCCTAGCATTTTGGGAGGCTGAGGCAGGAGGATCCCTTGAGCCCAGGAGTTGGAGACCAGCCTGAACAACATACTGAGA DDCDCADCCCDCCCBCCCACDCDCCCDABCDDDCBBBDBBCCBCBBBDBBCBBCDCCCDCBCBCCBCBBCADCBBDBACBDBCCCBDBBDCBCCCCC at CBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHFHHHHHHHHHHHHGHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHFHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:5:7404:40226 163 chr1 10002668 37 91M10S = 52476437 42473869 GGCTCACACCTGTAATCCTAGCATTTTGGGAGGCTGAGGCAGGAGGATCCCTTGAGCCCAGGAGTTGGAGACCAGCCTGAACAACATACTGAGACCCCGTC @CBB?A?BACAA@<>ACDED@>@CCCCCBAC@?BB;6<8?AC=B76A38AAD=6A8/A:@7CC=:D7 at BA7'B38ABBCB>7B@:BC72D########### MD:Z:91 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:37 OQ:Z:BCBACA at ACC@@A@:@CCCC?=>BBCCB@@B>>BC>:?=ACB>?99=08=BB97;2.=7=8AA=2A9?=?6(>16BBAAA=8=>:>@73@########### UQ:i:0
+20GAVAAXX100126:8:43:16629:51559 163 chr1 10002681 60 100M1S = 10002869 288 AATCCTAGCATTTTGGGAGGCTGAGGCAGGAGGATCCCTTGAGCCCAGGAGTTGGAGACCAGCCTGAACAACATACTGAGACCCCGTCTCTACAAAAAATA @DCA at BBBBCCBBBCCCCCCBDBCCCBCCCBBA=:7;B at B;?;>=C;ACB::@8B?==?C>==@AA8A<=?>@;<?831:>>BA?;@9:B<8>5:9AAA## MD:Z:100 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBCBBBBBCCCBCBBBBBBBBABBBBBB at A@:=:@BAB>?<<?B6>B?>6<:?::6 at B?<<?>?:?:9?:;<<@61-9=?=?=?669?:7=145;8?## UQ:i:0
+20GAVAAXX100126:8:45:10866:114173 99 chr1 10002696 60 101M = 10003041 434 GGAGGCTGAGGCAGGAGGATCCCTTGAGCCCAGGAGTTGGAGACCAGCCTGAACAACATACTGAGACCCCGTCTCTACAAAAAATAGAAAATTAGTTGGGG CCCACCDCDCCBCCCDCCDCBBBDDBDCBBBCCCDCADBCDCDABCCBBCBDDACDACCCADBDCDABBB;BBDBDCACDDDAABBADDDDCDCCBDC>E# MD:Z:100T0 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGHHHHHHHHGHHCH# UQ:i:2
+20GAVAAXX100126:8:65:6494:152486 99 chr1 10002718 60 101M = 10003049 431 CTTGAGCCCAGGAGTTGGAGACCAGCCTGAACAACATACTGAGACCCCGTCTCTACAAAAAATAGAAAATTAGTTGGGTGTGGTGGTCCATGCCTGTAGTC CDC at DCCCBCCCDCBDBCDCDABCCBBDBDDACDACCCACBDCDABBB;BBDBDCACDDD@@BBADDD at CDCCBDBCCABCBCCBCCBCCCCCCDCCADDD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHEEGGGHHHDHHHHHHHHHFHHHHHHHHHHHHHHHHHHGHHH UQ:i:0
+20GAVAAXX100126:8:65:4031:65332 163 chr1 10002722 60 101M = 10003065 443 AGCCCAGGAGTTGGAGACCAGCCTGAACAACATACTGAGACCCCGTCTCTACAAAAAATAGAAAATTAGTTGGGTGTGGTGGTCCATGCCTGTAGTCCCAG @C at BABBCCB@CBBCC<AB?CBCDACDACD at CDC9;;BAB?CCC3ACDADA?C:BDDDCC<CC>D at 8CC>BCBA5A?@D>AACABC at B=BAAB at CBCC=?B MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBAABBABAB?BBBAB8BA<BBBB at BBBBBACCB>=@BBBABBBCBCBCBBCB<?BBBBBCBB>B>;BB7AB at B0B>@B;B@@ABA<BB=?A;B@@B=:7@ UQ:i:0
+20GAVAAXX100126:8:63:2945:69121 163 chr1 10002736 60 95M6S = 10003053 412 AGACCAGCCTGAACAACATACTGAGACCCCGTCTCTACAAAAAATAGAAAATTAGTTGGGTGTGGTGGTCCATGCCTGTAGTCCCAGCTACTCCAGAGGCT @CC at ABBBBDBCC@CDACCCACBCCCACCC;BBDACA>BBCCBDACCCCC at CC@CCCCAC>AAAA??A?8AC@?@?98C;@<A:BA?A<A><AA####### MD:Z:95 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBBBBBBBBBBBBBBBBABBBBBBBBBABBBBBCBBBBABBBB at BAAB@BB at AB@B>@?A?8B at 64AA=@@>76><?6>7?<:@;?@8?@####### UQ:i:0
+20GAVAAXX100126:8:27:6582:134282 163 chr1 10002742 60 94M7S = 10003068 426 GCCTGAACAACATACTGAGACCCCGTCTCTACAAAAAATAGAAAATTAGTTGGGTGTGGTGGTCCATGCCTGTAGTCCCAGCTACTCCAGAGGCTGAGGGG @BCCABB at CCACCAADBCCCBCCC;ABDCECACDCCBBBB@@CCB?CCCCABD at CCBCCBA;8>B=<B at C@BB?A>AAC@=A???>=B?A64B######## MD:Z:94 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBCCBBCBBBBBCBBBBBBACBBBCBBBCCBBBBBBBBBBC at BAB?BBB>BBBA?B at AA?B</?@9?A>A??=@@8A at A?<A8??67B?<41@######## UQ:i:0
+20GAVAAXX100126:8:25:10200:154913 99 chr1 10002841 60 101M = 10003177 436 TGAGGGGATAGCTTAAGCCAGGAAGTTGAGGCTGCAGTGAGCCAAGATTGTGCCAGTGCACTCCAGACTGGACAACAGAGCAAGACCCTGTCTCAGGGGGC CBCACCCDCCCBDDCDCBBCCCDDCBD at DCCBCB@CCBBDCBBCDADCDBBBBBCCCBBCADBCCCDADB at CACDA@CDCBCDBDACCBCCCDCDCCACE@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHFHHHHHHGHHHHHHHHHHGHHHHGHHHHHHHHHHHHHHHHHHHFGHHHHDHHHHHHIHHHHFHIHHHHHIGIHD UQ:i:0
+20GAVAAXX100126:8:46:6526:26315 147 chr1 10002857 60 101M = 10002542 -415 GCCAGGAAGTTGAGGCTGCAGTGAGCCAAGATTGTGCCAGTGCACTCCAGACTGGACAACAGAGCAAGACCCTGTCTCAAGGGGCTGGCCACGCATGGTGA ?D<:B>B;>6>A=@AB=@B>>>AA<==:<A>BB@=BC>@>>BB:<B??CA;C at C@>@C at BBA@AAAC??CBCC at CBCBC@CCCACCCA at BA;BBBBA at BB@ MD:Z:79G21 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:>?:1=<=7<3=><>==:?@<?=??==<:6=??=A?AA?=??AA49=<A?A=B?B==BA at BABABBAB>;BABBABAABA=BBBABBBBABABBBABBBBBB UQ:i:31
+20GAVAAXX100126:8:43:16629:51559 83 chr1 10002869 60 101M = 10002681 -288 AGGCTGCAGTGAGCCAAGATTGTGCCAGTGCACTCCAGACTGGACAACAGAGCAAGACCCTGTCTCAGGGGGCTGGCCACGCATGGTGACACATCCCTGTA :DCDDCCDACCDCCCDDBCDCACBCBDACBB at CDCBDBCCCBBCBDBBDBCBBDCBBCCCCADCDBCBBBBBCCBBCBB;BBCCBACBCBCBCDCCCA at CC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:;HHHHHHHHHHHHHHHHHHHGHHHHHHHHHHEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:63:6936:45669 611 chr1 10002875 29 35M66S = 10003208 424 CAGTGAGCCAAGATTGTGCCAGTGCACTCCAGACTGGACAACAGAGCAAGACCCTGTCTCAGGGGGCTGGCCAAGCATGGTCACACATCCCTGTAGTCTGT ##################################################################################################### MD:Z:35 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:0 MQ:i:37 OQ:Z:##################################################################################################### UQ:i:0
+20GAVAAXX100126:8:61:8680:44720 83 chr1 10002899 60 101M = 10002550 -449 CACTCCAGACTGGACAACAGAGCAAGACCCTGTCTCAGGGGGCTGGCCACGCATGGTGACACATGCCTGTAGTCTGAGGAGCTCAAGGTTGCAACAGTGAG 646:<?<:<?=>>:CD9A=>@B=DDBA=CCC<ACDB<@;8>A?C>B<:98;B:CBABBBBBB?CBCCC?ACADACBDBBDBACBADBADCBBDCCDAABDC MD:Z:64C36 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:47;<@A?@@A>EECHHCF?DDHAHHHGEHHHEEHHHBFB9DGCGEG?BBFBHBHHHGHHHHHCHHHHHGGGHHGHHHHHHHGGHGHHHHHHHHHHHHHHHH UQ:i:33
+20GAVAAXX100126:8:28:18332:173597 163 chr1 10002902 60 97M4S = 10003158 356 TCCAGACTGGACAACAGAGCAAGACCCTGTCTCAGGGGGCTGGCCACGCATGGTGACACATGCCTGTAGTCTGAGGAGCTCAAGGTTGCAACAGTGAGCCA @BCBAB at CBCCACBACCCCBCDBBACDDCBBDBC@B?@BABA?B=C>:AC:?B6BC=B:A?@=@BA;=?><D@:8=29<797B>A at BA875:BACA##### MD:Z:61C35 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:BBCBBBBBBBBBBBBBBBBBBBA at BBCBBBBBBAABAABBAA@A?B=?AA>??3??=>:?@?=@??;=:7>?=:5=17:494>=?6>?:13:?@=?##### UQ:i:31
+20GAVAAXX100126:8:62:6496:91010 99 chr1 10002902 60 101M = 10003193 391 TCCAGACTGGACAACAGAGCAAGACCCTGTCTCAGGGGGCTGGCCACGCATGGTGACACATCCCTGTAGTCTGAGGAGCTCAAGGTTGCAACAGTGAGCCA CBBACDADBCDACDACCDCBCDCDABBDBBBCBCCCCCC at DBCBBCA;BCCBCBBDACACCBBCDBBCCCBCBDCCDCBDBCDCC>DCCCB at BABCDD@D> MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHFHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHAHHHHFGGFFHHHDHB UQ:i:0
+20GAVAAXX100126:8:45:20504:142467 163 chr1 10003007 60 90M11S = 10003337 430 CGCACCATTCCACTTCATCCTGGGCAACAGAGCAAAACCCTATCTCTATGAAAAAAAAAAAAAAGCAAGAGGCTATCTTCTCTGAGGTTTACTATAGTTAA @;BB>AACABCCACCBDCCDDBDCCCDBCCCCBCCCB at A?C?CCBCDCACACD at DDDDDDBDCB=A at B;/<6688.5B?4:<?60B?=@############ MD:Z:90 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCCCCCBCCCCCBBBCBCCBBCBCBBCBBBBBBBBBBBCB at BBBCBBCCBBBAABBBBBBBAB:@B at 5,=4459,4@;37<82.=<9@############ UQ:i:0
+20GAVAAXX100126:8:48:5253:110179 675 chr1 10003025 60 38M63S = 10003197 242 CCTGGGCAACAGAGCAAAACCCTATCTCTATGAAAAAAAAAAAAAAGAAATTGGCTATCTTCTCTAAGGTTTACTTTGGTTAACTTTTACAAGAATTTAAT ><AABBAA??<A36CC??:@>>8:?@B>C5BA1>A<;################################################################ MD:Z:38 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:=7 at BABA@;@;@28CB;:6A;:39>@@<@5A@/;A>?################################################################ UQ:i:0
+20GAVAAXX100126:8:45:10866:114173 147 chr1 10003041 60 11S90M = 10002696 -434 GCAACAGAGCAAAACCCTATCTCTATGAAAAAAAAAAAAAAGCAAGAGGCTATCTTCTCTGAGGTTTACTATAGTTAACTTTTACAAGTATTTAATCATAA ############?8.D=4.,9388?<3<CBBBDB>CCACCB at BCCBC@BB=B at BCBACBBBAA@BCB<BCBADADACBCDDEA?ACD at BCCCBBBAABBC@ MD:Z:90 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:############?1/A;2++7139?:1<@?A at A@@@A at AAA@A at AA@A?A@@?@@@BABABABBBBB6ABA at BBBABABBBCA9ABBBBBBBBBBABBBBB UQ:i:0
+20GAVAAXX100126:8:65:6494:152486 147 chr1 10003049 60 101M = 10002718 -431 TCTCTATGAAAAAAAAAAAAAAGCAAGAGGCTATCTTCTCTGAGGTTTACTATAGTTAACTTTTACAAGTATTTAATCATAATTGCTTAGATTGAATTCGG 6B=74698BC?DACDDCBDBBCC at BCABCBABBC@ACBCCABDCADB at CCADCDACAC@CCBBB>ABDACCDDCCCCCDCCDDCBCDADCCCCBBBBB:C@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:2;901225?A>@AAAAA at A@@AB at AABBBABA@BB>ABABABBABB?B at BBBBBAABB@BBBBBABBBBBBBBBBBBCCBCCBBBBBBBCBBBBBBBBBBB UQ:i:0
+20GAVAAXX100126:8:45:5977:75469 163 chr1 10003052 60 71M30S = 10003336 384 CTATGAAAAAAAAAAAAAAGCAAGAGGCTATCTTCTCTGAGGTTTACTATAGTTAACTTTTACAAGTATTTAATCATAATTGCTTAGATTGAATTCGGTTC @DBBABCCCCCDCBDDDA=.7@@4)@@397:6?:241'-%366C6/0?-:37A6>=3 at BC303<=45';B############################### MD:Z:71 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBBBBBBBBBBBB?9,6==1*?>13683=9224'-%4:5A90.:-55688;729 at A402;902'7@############################### UQ:i:0
+20GAVAAXX100126:8:63:2945:69121 83 chr1 10003053 60 5S96M = 10002736 -412 TTCTCTATGAAAAAAAAAAAAAAGCAAGAGGCTATCTTCTCTGAGGTTTACTATAGTTAACTTTTACAAGTATTTAATCATAATTGCTTAGATTGAATTCG ######@A;AA at A?AA at DDDDDDBBDDBDBBCCCDCDDCDCCBDBADDCBCCCCCADCDBCDDDCBBDCACCDDCDCDBCCDCDCBCDCDBCDCBDCBC;C MD:Z:96 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:######DD at GGGGEGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:65:4031:65332 83 chr1 10003065 60 101M = 10002722 -443 AAAAAAGCAAGAGGCTATCTTCTCTGAGGTTTACTATAGTTAACTTTTACAAGTATTTAATCATAATTGCTTAGATTGAATTCGGTTCAGTATATATTCCT EEDDAD=?=A>DCBCCCDCDDCDCCAD at A?DCCCCCC6ADCACADDDCBB?CACCDDCDCDBCCDCDCBCDADBCDCBDCDD;BADDBBACCCCCCDBCCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHGHAD at DAHHHHHHHHHHHHHHGHFHEHHHHHHH7HHHFHGHHHHHHEHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHIHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:27:6582:134282 83 chr1 10003068 60 101M = 10002742 -426 AAAGCAAGAGGCTATCTTCTCTGAGGTTTACTATAGTTAACTTTTACAAGTATTTAATCATAATTGCTTAGATTGAATTCGGTTCAGTATATATTCCTGGA EDDCCDDCACCCCCDCDCCDCCBDBAD at CBCCCCDADCDCCDDDCBBDDACCDDCDCDBCCDCDCBCDCCBCDCBDCDD;BADDBDACCCCCCDDCCABBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HIHHHHHHEHHHHHHHHIHHHHHHHHHDHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:26:6455:142223 163 chr1 10003070 60 101M = 10003403 433 AGCAAGAGGCTATCTTCTCTGAGGTTTACTATAGTTAACTTTTACAAGTATTTAATCATAATTGCTTAGATTGAATTCGGTTCAGTATATATTCCTGGAAG @CBBBABBCBDCCADCCDCDBBCCBCCCADCCBC>BAB;CBBBC?CDC at B?CC at DCBDBABCCABD@CCB at CCABBB@;B at BCBBAB>>C;BC?CBBCBDB MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCBBBBBBBBBBBBBBCBCBA at BB@BCBBBBBAC at BBB@BBAABBBBB?AABBBAABBA at ABBAABABB@@@A@@B@@BA>@BAA9@<?@<A@>A?@@@>@ UQ:i:0
+20GAVAAXX100126:8:68:8704:167789 99 chr1 10003123 60 101M = 10003414 361 AATCATAATTGCTTAGATTGAATTCGGTTCAGTATATATTCCTGGAAGTTCACTATTATTATTATTACTAGGTCCTGAGAATATGAAACAACCATAAAAAT CDB at CCCDCABBDDCCDCDBDDCDB;CBDBCCAC>CC>CDBBC9CDDC at DBCADCCDCCDCCDCCDCADCACCBBDBBCDDCCCBDADACDACDCDE=E@; MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHGHEHHEHHHHH at HHHHEHHHHHHHHHHHHHHHHHHHHHGHHHHHHGHHHHHHHHGHHHHHHHHHHBHG> UQ:i:0
+20GAVAAXX100126:8:28:18332:173597 83 chr1 10003158 60 101M = 10002902 -356 ATATTCCTGGAAGTTCACTATTATTATTATTACTAGGTCCTGAGAATATGAAACAACCATAAAAATGAGTGATGAATTCAATATATATTATTCTGACACTG BDCEBDCBCCDD?DDBCACCDCCDCCDCCDCCCCDBADCCCBDBDCCCCBDDBBDBC at BCDDDDCCBCACBCCBDCDDBDCCCCCCCDCCDDCCBCC:BCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:FHHHEHHGHHHHGHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHH UQ:i:0
+20GAVAAXX100126:8:25:10200:154913 147 chr1 10003177 60 101M = 10002841 -436 ATTATTATTATTACTAGGTCCTGAGAATATGAAACAACCATAAAAATGAGTGATGAATTCAATATATATTATTCTGACACTGAGAAGTATTGTAACAAAAA <C<=C at BAAB?B<>=>455>8=@B at B@5>=8AD>?DBABB at CCDCCC?D@>BBCBCAC>AABAB>BBCDCCCCCCBBBBCCBDBCDAACDCABBBAABAC@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:9<<6>????A>@:<97340>6<=@@@?6:69?A<BA at AAAABBBBAAABA@AAAABBA>AABBBABBBBBBABBBB at B@CBBBBBBBBBBBBBBABBBCBB UQ:i:0
+20GAVAAXX100126:8:62:6496:91010 147 chr1 10003193 60 101M = 10002902 -391 GGTCCTGAGAATATGAAACAACCATAAAAATGAGTGATGAATTCAATATATATTATTCTGACACTGAGAAGTATTGTAACAAAAAACAAGTTTCTAGGTCA CA=2CAAB at B>>;;>AA5BB>BBAACBACDABEA at BCBBCBCCCCDCACCADCCDDACCB@A?BAACBCDACCDBBCCABCCCBBACBDACCCBBB@@CB@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:B=81??>?>@>;<9:<?,?@<A at ABA@B at BABBBBABBBBBABBBBBBBBBBBBBBBBBBABABBBBBBBBBBBACBBBBBBCCCACBCCBBBBBBCCBBB UQ:i:0
+20GAVAAXX100126:8:48:5253:110179 595 chr1 10003197 60 30S71M = 10003025 -242 GAAGTTCACTATTATTATTATTACTAGGTCCTGAGAATATGAAACAACCATAAAAATGAGTGAGGAATTCAATATATATTATTCTGACCCTGAGAAGTATT ###############################B at B=?<2,-+2;=;@<72+1+<.2;0589557&99;;;=<-(=;<-<2)=>884:>9'>>351>;77?9< MD:Z:33T24A12 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:2 SM:i:37 MQ:i:60 OQ:Z:###############################FFFAA43.-,64<>D551-1.421=09:>7::)@:55444/+444/43+4>::3B>=+<?8804@:FC?F UQ:i:11
+20GAVAAXX100126:8:26:15631:70339 163 chr1 10003203 60 101M = 10003538 435 ATATGAAACAACCATAAAAATGAGTGATGAATTCAATATATATTATTCTGACACTGAGAAGTATTGTAACAAAAAACAAGTTTCTAGGTCATACCAAAAGC @CBBA?CC@?CABBCCDDDDCBBABBCACCBCCBBCABBBCACCAACCACAAC?EBCCCCB>@ACA>=A=ACB?AC at BBB>BB at CCCA<CAAB?CAA>=CB MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBCBBA;BBBBBBBBBBBB@@ABA?BB at BBBBBBBBBBABBB@BB at BBBABBABAAAB<@AA@@><>A????ABA?B;@?@@A@?<BA at A?>?;6:=A UQ:i:0
+20GAVAAXX100126:8:63:6936:45669 659 chr1 10003208 37 9S92M = 10002875 -424 GAGAATATGAAACAACCATAAAAATGAGTGATGAATTCAATATATCTTATTCTGACACTGAGAAGTATTGTAACAAAAAACAAGTTTCTAGGTCATACCAA ##########B at 19<?:=>:97;=>;C?@43?;B at 9(0<>5>BD8(28C=3B97C>?C,5B?>?08;3@*>A@;?CBCA@?-C'9<CA5;,'AA?5A49<@ MD:Z:36A55 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:1 SM:i:37 MQ:i:29 OQ:Z:##########A9073<8<:9977=>:BA;.3<7 at B5'.:>7<AB5'-<A=2 at 83@>AA+6AA@@6<>1>+>?85=C at B>:=-@)6:AC86-)=A>5 at 589@ UQ:i:7
+20GAVAAXX100126:8:68:17460:23672 99 chr1 10003272 60 101M = 10003550 378 CAAAAAACAAGTTTCTAGGTCATACCAAAAGCCGGGCAAAGTGGCAGATTCCTGTAATCCCAGCTACTCAGGAGGCTGAGGGGGGAGGATTGCTTGAACCC CCD:@DDA at A@BD>BDCCCCBCCC?BCDDDAB=;C@?B@@=;===?A;BABB at ABC?:=BBCCADCAD@>C>DCC=@?@ACCC>>???>?DACAD<=:>?= MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHGGHHHCCCGHDHHHHHHHHHHGHHHHHGHDHHCCGCGD at DDDDG=GGHHEGHHE=EHHHHGHHHHGCHDHHH?DDDFHHHCCCCCCCHGHDH<?<DD= UQ:i:0
+20GAVAAXX100126:8:68:4068:49998 585 chr1 10003316 0 35M66S = 10003316 0 CAGATTCCTGTAATCCCAGCTACTCAGGAGGCTGAGGCAGGAGAATCGCTTGAACCCAGGAGGCAGAGGGTGCAGTGAGCCTAGATTGCGCCATTGCACTC ##################################################################################################### MD:Z:35 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:0 OQ:Z:##################################################################################################### UQ:i:0
+20GAVAAXX100126:8:68:4068:49998 645 chr1 10003316 0 * = 10003316 0 TGCAAAAGCGCAAACTCGGCTCTTTGCAACCTACGCTTGCTGGGTTCAGGGAATTATTCGGCTTAAGCCCTCTGAGTAGTTGAGGCTACAGGCACCTTACA ;7(A################################################################################################# PG:Z:BWA RG:Z:20GAV.8 OQ:Z:70*@#################################################################################################
+20GAVAAXX100126:8:45:5977:75469 83 chr1 10003336 60 101M = 10003052 -384 TACTCAGGAGGCTGAGGGGGGAGGATTGCTTGAACCCGGGAGGCAGAGGTTGCAGTGAGCAGAGATAGCGCCATGCCATTGCACTCCAGCCTGGGCAACAA >ADDCDCCDCCCB at CBAACCBD@BCDCBCDCBDACC;CBBDBBBDBDBADCBBDACBCBBDBDBCCCB;>CBCCBCBCDCBBBCDCBDBCCCBCCCDABDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BGHHHHHHHHHHGGGGGGHHHHFHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:45:20504:142467 83 chr1 10003337 60 101M = 10003007 -430 ACTCAGGAGGCTGAGGGGGGAGGATTGCTTGAACCCGGGAGGCAGAGGTTGCAGTGAGCAGAGATAGCGCCATGCCATTGCACTCCAGCCTGGGCAACAAG DDD at DCCDCCCB@CABACC at DCBCDCBCDCBD@CC;CCBDBBBDBDBADCBBCACBCBBCBCBCCCB;BCBCCBCBCDCBB at CDCBDBCCCBBCCDC@CDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHDHHHHHHHGGGGGGHHGHHHHHHHHHHHHEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHFHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:26:6455:142223 83 chr1 10003403 60 101M = 10003070 -433 GCGCCATGCCATTGCACTCCAGCCTGGGCAACAAGAGTGAAACTCCATCTCAAAAAAAAAAAAATCCTTTCATGAAATTACTACCAGATGTTGGCCCTTCA >6=@>=<??<@9:8::?<A;BBCCCB@>;A@>AB at BACBDDC>BCBCDC@?AAAAA at ADDDDDCDCCDDDACCBDDCDCBCCBCBDBCCADCBCCCCBCBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BAADA?BDDBD55444DBFBFHHIHHFDBFDEFFFFHHHHHHEFHHHHHDCGGGGGGGHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:68:8704:167789 147 chr1 10003414 60 30S71M = 10003123 -361 GTTGCAGTGAGCAGAGATAGCGCCATGCCATTGCACTCCAGCCTGGGCAACAAGAGTGAAACTCCATCTCAAAAAAAAAAAAATCCTTTCATGAAATTACT ###############################B@<347:@::>>A at CC=B>7A@@C>9A;<:;7>;28>>>CCCCCCCCCCCCBCCCDBCBCCBBBBBBAC@ MD:Z:71 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:###############################?=;002<?7<=<;>AB@?=:=?>?@<@<=<>:@@39<<<ABBBCBBBBBBBABBBBBBCCBCBBBABACB UQ:i:0
+20GAVAAXX100126:8:2:19645:190338 163 chr1 10003434 60 82M19S = 10003700 366 CAAGAGTGAAACTCCATCTCAAAAAAAAAAAAATCCTTTCATGAAATTACTACCAGATGTTGGCCCTTCAGCACAACCAGCTTGGGAGCTTCATCCTTAGC ?A?A??@BADDADADDBCCCCAEEEED at CEEDB59=0145<6:DBCCA1:>5?;:B71?A8>:07B49;9-6.5?A9B@;A#################### MD:Z:82 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:???AC@:BCCCBCCCC at CACB?CCCCB=ACCC at 4<?0478>8<BBAA>08 at 7>=4 at 4-==9=;14 at 3875,2+7>?;A<:A#################### UQ:i:0
+20GAVAAXX100126:8:45:3960:5771 163 chr1 10003525 60 101M = 10003872 447 CATCCTTAGCAAAGAAAGATCTTCAAAGCAGGCACTTCCATGATCCACATACTTTGGATGCCCTTAAAGGGGGGGAAAAAGGGAGAGGAAGGGAGGAGAGG @CBA at BBBBBCDCABEECCCBECBDEECBACCCD@CAAA?CBCC?CCACDAADADCCDCBACCCCB?DCCADDAB>@BB=BBCBB0CB at DABC@AACC?DB MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCBCBBBBCBCBBCCCBBBBCCBCCCBA?BBCCBBBBBCBBBBABBBBBBBBBBBBABCBBBBBA at BBBABBBB;?A?<BA@@A,A@?@AAA><@?@;@@ UQ:i:0
+20GAVAAXX100126:8:26:5030:62604 99 chr1 10003529 60 101M = 10003851 422 CTTAGCAAAGAAAGATCTTCAAAGCAGGCACTTCCATGATCCACATACTTTGGATGCCCTTAAAGGGGGGGAAAAAGGGAGAGGAAGGGAGGAGAGGAAGA CDCACCCDDCDDAADCBDDBCDDCBCCCBCACDBBCCBDCBBCACCCACDDBCDCBBBBDDBDDCCCCC>B>DDDDCCCDCBCCDDCCCDCCCCCCDDED5 MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHEGCHHHHHHHHHEHHHHHHHIHHGHFHHIHH4 UQ:i:0
+20GAVAAXX100126:8:26:15631:70339 83 chr1 10003538 60 101M = 10003203 -435 GAAAGATCTTCAAAGCAGGCACTTCCATGATCCACATACTTTGGATGCCCTTAAAGGGGGGAAAAAAGGGAGAGGAAGGGAGGAGAGGAAGAGGAGGAGAA DEDDCCDCD?CDDDABDCBBCCDDCBCCBCDCACBCCBCADCBBCCBCC at DCDDCBBBBBBDDDDDCBBBDBDBBDDBBBDBBDBDBBDDBDBBDCBBBDC MD:Z:61G39 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHCHHIHGHHHHHHHHHHHHHHHHHIHHHHGHFHHHHHHHHHFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:35
+20GAVAAXX100126:8:68:17460:23672 147 chr1 10003550 60 101M = 10003272 -378 AAGCAGGCACTTCCATGATCCACATACTTTGGATGCCCTTAAAGGGGGGGAAAAAGGGAGAGGAAGGGAGGAGAGGAAGAGGAGGAGAAATAGCATTTCAA CE at CBA?1B>)8.>1%94=096A;>->88CAA=:4=.?7A0CAC<>B78=A=CCDC8C7?==?:?@9<DC@;BDC at BB?AABDBB>@BCC<ABAB:BB?@@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:@@@B<>;.=<'23<-%616384?;?'=74?B?997<0?3 at 2A>B99>94>B9BBBB;B6@>@A=AA;;BB at 8ABB?@?>>?BB at B;?BBB>>ACB:BA?<B UQ:i:0
+20GAVAAXX100126:8:47:13004:90024 99 chr1 10003567 60 101M = 10003910 383 ATCCACATACTTTGGATGCCCTTAAAGGGGGGGAAAAAGGGAGAGGAAGGGAGGAGAGGAAGAGGAGGAGAAATAGCATTTCAATTCTGCTTTAATATATA >982;8A>=?DDD==?CBBBADDCDA>=>A@=;;@?A@=;8<13=,<;<78)=7<=2=72A>B@>B;>*</:9:8:(:9:7@<@???,;=699&:7B?@?4 MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:><@==@CDACHHHDDDHHHHGHHHHCADAGCD>4CEFCE?44234245554+44441443FAFFCF=C,?254444-5559F?DDCC.?A654'5:GCGE4 UQ:i:0
+20GAVAAXX100126:8:25:18450:91287 163 chr1 10003652 60 101M = 10003979 427 TCTGCTTTAATATATATATATTTTTTGAGACAGAGTCTCACTCTGTCATCCAGGCTGGAGTGCAGTGGTGCAATCTCCGCTCACTGCAACCTCCACCTCCC @CCA?A at ABCCCCACCCCCCDCCCCCBCCC@CACB>@C?B at DBD@BCCCAACB=BDBCBA<B@<AB=A at B?CB@>@=A9AA<=>ABBB>=@BAAB>BA?AB MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCBBCCCCBBBBBBBBBBBBCCCBBBAABBAB at BB?BBABBBBBBABBB at BB??AAAA?@;A?<@>@@9A@?>@>>>@>B?<6?>@@@>:???@>>>9>:@ UQ:i:0
+20GAVAAXX100126:8:44:17629:79062 1187 chr1 10003678 60 99M2S = 10004001 423 GAGACAGAGTCTCACTCTGTCATCCAGGCTGGAGTGCAGTGGTGCAATCTCCGCTCACTGCAACCTCCACCTCCCGGGTTTAAGCGATTCTCCTGCCTCAG =B:6:=::9ABD61?D<D??@BA>DDCCCD97@@>374=48?AA@<;@BD8B46CB5>C<<C<8BD98;1::A7(#2&9?8'@8%2B@:=@ABB59CD### MD:Z:84T14 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:<?949=474BCB80 at B:B=C@@@=CCBBBB68>?@2=6 at 5;@B at B;6=BA;A4:@A1;A:CA9;@B>85/:2?7*'5)4>8':4&3=?:8BABA07B@### UQ:i:4
+20GAVAAXX100126:8:2:19645:190338 83 chr1 10003700 60 101M = 10003434 -366 TCCAGGCTGGAGTGCAGTGGTGCAATCTCCGCTCACTGCAACCTCCACCTCCCGGGTTTAAGTGATTCTCCTGCCTCAGCCTCCCTAGTAGCTGGGATTAC 5ECACCC?;CD?BBCD=A><A495:=;9547;:<;;3:<;+7=<83=CCACC;BBADDCD@;@<=?<<>=:?9==<BDACCD at CCCDACDBCCCCBCBC;C MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:5HHEHHHC=HHGGHHHDDDAD;<;<=44444444551555)44442<HHEHHHHHHHHHHEDDDAA>?AA at D=DDBHHGHHHFHHHHHHHHHHHHHHHHEH UQ:i:0
+20GAVAAXX100126:8:25:1734:195910 99 chr1 10003819 60 101M = 10004149 430 TGGCCAGCTAATTTTTGTATTTTTAGTATTTTTGTATTTTTGTTTCGCCATGTTGGTTGGGCTGGTCTCCAACTCCTGGCCTCAAGTGATCCACCCACCTC CBC at CCCCDCDCDDDDBBBCDDDAACBCCDDD@@ABCDDDA at AA@=;BBCCBBDBCCDBCCBDBCCBDBBCDADBBDBCBBDBCDCCCDC at CC:CCDBAED MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHGGHHHHGGHHHHHHHGGGGHHHHGGGGGEHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHIHHHFHHBHHHHFHH UQ:i:0
+20GAVAAXX100126:8:26:5030:62604 147 chr1 10003851 60 101M = 10003529 -422 TGTATTTTTGTTTCGCCATGTTGGTTGGGCTGGTCTCCAACTCCTGGCCTCAAGTGATCCACCCACCTCAGCCTACCAAAATGCTCGGATTACAAGTGTGG C@<CDBC6B?AD at 9CD<8:>B;)?9)8=@BAC at C?CB?=7ABCCBCC at C@@CDA>?=DCB3BBA6BBCBDBCCCBDBCCCCCBCC;DACDCABAB?@@BD@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:@<<?@@?3?B@@@@AA:53@@:)A8'8=>=AA?AA@@@;2A?ABAABAB?BBBB9?@BBB4BBB6BBABBBBCB at CBBCCBBBCBCCCBCCBCCCCCCCCB UQ:i:0
+20GAVAAXX100126:8:45:3960:5771 83 chr1 10003872 60 101M = 10003525 -447 TGGTTGGGCTGGTCTCCAACTCCTGGCCTCAAGTGATCCACCCACCTCAGCCTACCAAAATGCTCGGATTACAAGTGTGGCCCCTTGTAATAAAAATTTAA EA?A, at CCCCCADCDCBDCCDCCCBBCADBDDACBCDCBACCBBCCDBDBCCCBCBDDDCCBCD;BBCDCBBDDACACBBCCCCDCABABCDDDDCDBCDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HFFD.CHHHHHHHHHHHHHHHHHHHHHFHHHHHHHHHHHFHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:4:16802:116090 611 chr1 10003895 60 101M = 10004234 439 TGGCCTCAAGTGATCCACCCACCTCAGCCTACCAAAATGCTCGGATTACAAGTGTGGCCCCTTGTAATAAAAATTTAATTTTTTGGAATATGACTCTTGGA 1.)4=???3/>@,=<<30+->;>6<<<:;>:+:6;;;<<:9*31=;;99=97=:<@>:==AA7=<9::9:>765198:9+=;:5:A/<>:::86<9@=:.B MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:5..54544/.44+55473+0<AA9E45554=/=:=444549+=8<55554:8A==FA at EECC:A at 45544?:::744550===:<F2 at A@445555AB=8E UQ:i:0
+20GAVAAXX100126:8:63:8454:180865 1187 chr1 10003896 60 101M = 10004216 420 GGCCTCAAGTGATCCACCCACCTCAGCCTACCAAAATGCTCGGATTACAAGTGTGGCCCCTTGTAATAAAAATTTAATTTTTTGGAATATGACTCTTGGAG @CBBB at ACBBBCCADDACBBACDBCCBBDCACCAAAAAACB;CDACC at CCAAC;ADBCBCCBB=CC at AC?ACDABA@=CCBADA8=AB9C>B at BBBCB;8@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBCBCCBB at BBBBCCBBAABBBBBBB@BBBBB>AABBBBBBBBBBB at BAB@B=@BAAABB at A<B at B@@<@@B@@A?=BA at B@B96;A;@>@@@@??<;1= UQ:i:0
+20GAVAAXX100126:8:47:13004:90024 147 chr1 10003910 60 60S41M = 10003567 -383 TTGTATTTTTGTTTCGCCATGTTGGTTGGGCTGGCATCCAACTCCTGGCCTCAAGTAATCCACCCACCTCAGCCTACCAAAATGCTCGGATTACAAGTGTG #############################################################>:;6=5 at 6BB7;;A8(@CCC>;AAC;>?A<B>=AB>A at B@ MD:Z:41 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:#############################################################@>><>9>5A at 6:6A1,>BBB=7A?BBAA?;B7=?B@@BAB UQ:i:0
+20GAVAAXX100126:8:2:13260:81311 163 chr1 10003923 60 90M11S = 10004222 399 CTACCAAAATGCTCGGATTACAAGTGTGGCCCCTTGTAATAAAAATTTAATTTTTTGGAATATGACTCTTGGAGTTTTTCTTTTTCTTTTTTTACTTTTGG @C4:97@:CB>??>9=;<@:??2?-4?BACACC:<=6:<:16>@9BAD9 at 889:?BBB3?96>;?=;BDB:?4877?(?;C?D>78D6@############ MD:Z:90 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:B at 4;66=7 at A?=@A@=79=9@<.;'1:A?B at BA7>@6>?>47><<A=A:<;84<;>B?0<;7><<<=BA@;<0755>);;B>B<53 at 4@############ UQ:i:0
+20GAVAAXX100126:8:1:17413:63912 1187 chr1 10003958 60 101M = 10004229 371 GTAATAAAAATTTAATTTTTTGGAATATGACTCTTGGAGATTTTCTTTTTATTCTTTTACTTTTGGACTCTGTTGGACTTCAGTTGTTTTTCTTTAATGGC @BBCBACCCCCCCADCCCCCCBCCDCCCCCADBDB?*34->CCC6DDCCB&:C/CDCD4;8C6BB at 0@EB*CC2>$8<D;(3D9=CC9,=7;C8B@>?5>4 MD:Z:39T10C2T26G20 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:4 SM:i:37 MQ:i:60 OQ:Z:BABBBBBBBABBBBBBBBBBBBBBBBBBBABBBBBA355- at BBA:BABB?';@.>BBB3;7A4BA>/ABA)BA1=(6>B:(0B1;B?7-869?6??991:2 UQ:i:38
+20GAVAAXX100126:8:7:11540:56171 163 chr1 10003958 60 101M = 10004229 371 GTAATAAAAATTTAATTTTTTGGAATATGACTCTTGGAGTTTTTCTTTTTCTTTTTTTACTTTTGGACTCTGTTGGACTTGAGTTGTTTTTCTTTAATGGC @ABCBACCCCCCCAACCCCCCBCBCCACCBADBDBAA<A=BCCC?CDDCC<DDADDCCB at BCB?BC=@EB at CC?@@=?CB at AB?@CB@>D=ABBA?CA at C? MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:ABBBBBBBBBBBBB?BBBBBCBB?ABABB at BBBBBBB>B?BBBBAAAAAA at BABBAA@AAAA@?AA?ABA?A>?@?<A?@??@=>B8>>@<?>@<>><?>< UQ:i:0
+20GAVAAXX100126:8:7:11542:56193 1187 chr1 10003958 60 101M = 10004229 371 GTAATAAAAATTTAATTTTTTGGAATATGACTCTTGGAGTTTTTCTTTTTCTTTTTTTACTTTTGGACTCTGTTGGACTTGAGTTGTTTTTCTTTAATGGC @ABBBACCCCCCCACCCCCCCBCBBCACCBADBDBAA7A<BBCC?DCDCC<CCADDCDB?CB at AAB;>EABCCAAA=9DBA>C?ACB@>B@=ABB?CA?D# MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBABBBBAABBBBABBBBBCBB?@BABB at BBABBBB9B>BABBABBAA@?A at BBAAAA?B@?@@@>?B?AA>@A@<;A at A<A<?B<>>=?<<@?>><>?# UQ:i:0
+20GAVAAXX100126:8:25:18450:91287 83 chr1 10003979 60 101M = 10003652 -427 GGAATATGACTCTTGGAGTTTTTCTTTTTCTTTTTTTACTTTTGGACTCTGTTGGACTTGAGTTGTTTTTCTTTAATGGCTTTATTGAGGTATATTTTATG >D<CBCDCCCDCDCCBD?AABABAAA at ABAADDDDDCBCDDDCBBBC@CCADCBBBCDCBD?@B?A@@DDCDDCDCCBBCDDCCDCBDBACCCCDDDABCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BHBHGHHHHHHHHHHHHGGGGGGGGGGGGGGHHHHHHGHHHHHHHGHDHHHHHHHHHHHHHGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:25:13133:61877 99 chr1 10003984 60 101M = 10004291 407 ATGACTCTTGGAGTTTTTCTTTTTCTTTTTTTACTTTTGGACTCTGTTGGACTTGAGTTGTTTTTCTTTAATGGCTTTATTGAGGTATATTTTATGTACCA CCBBADBDDBCDCBDDDDBCAAAA at CAA@@A at AACDDDBCDACBCBBDBCDADDBDCCDBCDDAAAC@@ADCACBDDDCCDBDCCBCCCADDBCCCCDBDE MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGHHFHHHHHHHHHHHHIHHHGHHFHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:8:8310:17522 99 chr1 10003989 60 101M = 10004327 421 TCTTGGAGTTTTTCTTTTTCTTTTTTTACTTTTGGACTCTGTTGGACTTGAGTTGTTTTTCTTTAATGGCTTTATTGAGGTATATTTTATGTACCATAAAA CBCBCCDCCDDDDBCAAAA at CAAA@AAAADDDDBCDACBCBBDBCDADDBDCBDBBDDA at ACAABDCBCBDDDCCDBDCCCCCCCDDDCCCBCACDBDEE@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHGGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHFHHHHGHHIG UQ:i:0
+20GAVAAXX100126:8:45:4754:168834 1187 chr1 10003992 60 86M15S = 10004321 413 TGGAGTTTTTCTTTTTCTTTTTTTACTTTTGGACTCTGTTGGACTTGAGTTGTTTTTCTTTAATGGCTTTATTGAGGTATATTTTATGTACCATAAAATGC @A2?A@=AAC;C?=8B=CCCBCCCC:DC4C at 7A@>ABA><0*(?BC:BCA;B9(BDCBCCBC at 6;96ADC?DD7+>65=8'=D at C################ MD:Z:86 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:B at 6=AA:@CB<A@@4@;@CB at BCAB9BB2A@7?A?BBB@>00)?BA6>B<>B/)=BBAABBB>679:?BB at BB6+=9-;8(=B?A################ UQ:i:0
+20GAVAAXX100126:8:44:17629:79062 1107 chr1 10004001 60 101M = 10003678 -423 TCTTTTTCTTTTTTTACTTTTGGACTCTGTTGGACTTGAGTTGTTTTTCTTTAATGGCTTTATTGAGGTATATTTTATGTACCATAAAATGCACCTAAGTG =::6<=<<=BBB@<=>A@@<C==;>B;@?ABA@:ABA at B:=:9<<=AC>ABAABABAAAABAA@@C@??@B>???=<??B99?>====<><=;?AA@<<>< MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:?><:><BBBFGFD at AAGDD@GDD at DF?EGGFGGCGGFGFBBBBBBBGGEGGGGGFGGGGGGGFDGGGGFFGDDDDD>DGGB5444445554DCFGGGGFGF UQ:i:0
+20GAVAAXX100126:8:25:9891:26690 99 chr1 10004020 60 101M = 10004321 387 TTGGACTCTGTTGGACTTGAGTTGTTTTTCTTTAATGGCTTTATTGAGGTATATTTTATGTACCATAAAATGCACCTAAGTGTACAATTTGATAATTTCTA CDBADADBDBCDBCDADDBDCBDBBDDA@@C@@ADCBCBCDDCCDBCCCBCCCCDDDCCBCCACCCCDDDCBBCABDCDCABCCACDCDDCDCCDCDDCED MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHFHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:21:17746:177127 163 chr1 10004141 60 101M = 10004479 438 AACCATTCCTACAATCCAGTTTCAGAACAAGTCAATCACTCCAAAAAGTTCCCTAGAGACCATGTGCTGACAACTATTATTTTATAGGCTTTTCTTTTTCT @DAB at A@BCDCACBDCDDCACCCDCCEACCCBBDC@=B@@@CBDBD?CAC?CDBD:CCCABCBABC8DCC?BB>CBBBB>BAD at BBDB=CAAC>D at CCBCD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCCCCCCCCCCCCCCCCBBCCCCCCCBBACBBCBCCBBCCBCBBC:BABABCBC4BCBBBBABBBCBBBB>>@BBBA@>BB@@A at BBB=@BB=ABB?A at A UQ:i:0
+20GAVAAXX100126:8:21:17763:177132 1187 chr1 10004141 60 101M = 10004479 438 AACCATTCCTACAATCCAGTTTCAGAACAAGTCAATCACTCCAAAAAGTTCCCTAGAGACCATGTGCTGACAACTATTATTTTATAGGATTTTTTTTTTCT >C>A at AB?@D9:@<DB>BA?CC?*;CBBCAC8 at B)=6B4 at BC;=:<@=7C<AD>C at CCC?BB@<B at 8CB??D?>AB=>;71<B??BB<'C8CD)DBDD>BD MD:Z:88C4C7 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:2 SM:i:37 MQ:i:60 OQ:Z:=A@@?CB?=C;9A?CB<A?:CA>)7A at CB?B4@@)@<B:CBB;9=;<91@?CC?B;ACA at BC?>@>CAACBB:@?BC=872;=?>C?<(A7AA)BA at B<<C UQ:i:14
+20GAVAAXX100126:8:25:1734:195910 147 chr1 10004149 60 101M = 10003819 -430 CTACAATCCAGTTTCAGAACAAGTCAATCACTCCAAAAAGTTCCCTAGAGACCATGTGCTGACAACTATTATTTTATAGGCTTTTCTTTTTCTTTTTCTTT CCBCBACAAA6A:>CEABCABCAA at BAACCACCA@CCBDABBCDCBE at D@?DBDCAACBCB at A>??ADDCDDDDDDDEDBCDEECCDBDDCBCCBABACD@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:B??A>A?@>>6<:;AB@@AA at BA?@@@@B?BBA at BBABBBB@BBBABBBCABBCBBBBBBBBBCBCCCBCCBBBCCCCCBCBCCCCBCCCBCBCCCBCBBB UQ:i:0
+20GAVAAXX100126:8:42:7969:44162 1187 chr1 10004170 60 101M = 10004491 421 AGTCAATCACTCCAAAAAGTTCCCTAGAGACCATGTGCTGACAACTATTATTTTATAGGCTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGA @CAA at ABBCADCCAEEEECBBCDDDCDCCCBBC?@>AACAA at CD:DCDCC;CCACDCCCCCC?BBD at CCC@DDABCABCBBBBABCDB>CAADABBDCBB> MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:@CBCCCCBBCCCCCCCCCC@@CCCBBCBCBCAA>A at BBBBACBBCBBBBBCBBBBBBBBBBB=BBAAB at BA?BBBABB at BAA=BBB at ABB@BBA:@@A@<: UQ:i:0
+20GAVAAXX100126:8:42:7986:44148 163 chr1 10004170 60 101M = 10004491 421 AGTCAATCACTCCAAAAAGTTCCCTAGAGACCATGTGCTGACAACTATTATTTTATAGGCTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGA @CAA at ABBCADCCBEEEDCBCCDDECCCCCBCCCB>=AC>AACD?DCDCBACCACDBCCCCCCBBD at CDC@EDABB?BCBBADABCE=>CBAD at CBCC5B; MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCBCCCCCBCCCCBCCCBCACCCCCBBBBBCBBBB at CBBCABBBBBBCBABBBBBBABBBBBBBABBBBBBBBBBB?BB at BBBBBBB=BBA at A??AB?1<6 UQ:i:0
+20GAVAAXX100126:8:28:13507:25203 99 chr1 10004176 60 101M = 10004453 376 TCACTCCAAAAAGTTCCCTAGAGACCATGTGCTGACAACTATTATTTTATAGGCTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGACAGAGT CBC?DBCCDDDDCBDBBBDCCDCDABCCBBBBCBDACDACCCDCCDDABCCCCBDDDDBDAAAA at CA@@@@C@@@AA@@@C<CDDBDCCDDCDCDADDDDD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGBHHHHHHHHHHHHHHHHHHI UQ:i:0
+20GAVAAXX100126:8:63:8454:180865 1107 chr1 10004216 60 101M = 10003896 -420 ATTATTTTATAGGCTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGACAGAGTCTCTTTCTGTCACCCAGGGTGGAGTGGAGTGGCATAATCT A at DCEEDCCCDCCAABABAABAABAA@AACAA?A at DDDDCCCDDDCCADDCBCBBBCBCADCDCDDDCCADBACCBDBBACBBDACBBDACBBCCCDACCC MD:Z:95C5 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:GGHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGEGEHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:34
+20GAVAAXX100126:8:2:15114:83430 99 chr1 10004220 60 101M = 10004542 422 TTTTATAGGCTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGACAGAGTCTCTTTCTGTCACCCAGGGTGGAGTGGAGTGGCACAATCTCAGC CDCBCCCCCBDDDDBDAAAA at CAA@A at C@@A@@@@@CACDDBCBBDDBDCDACCDCCBDBDDDBDBBBCABBBCCCBBCDCCCCDCCCCBCACDCCDCDD> MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHGHHHHHHHHHHHHHHHHHHHHHHHA UQ:i:0
+20GAVAAXX100126:8:2:13260:81311 83 chr1 10004222 60 101M = 10003923 -399 TTATAGGCTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGACAGAGTCTCTTTCTGTCACCCAGGGTGGAGTGGAGTGGCACAATCTCAGCTC ?<@AC>C>@AA>>@@A;<;?=?@>>A??9DDADCBC?AAACADDCB=;>==B?A-CD=DADC??DBB=C>DBBAC=BDA at BBDACBBBCB@CDCD at D@>DC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBEGFBHCCCCCCCCC@@@A at CCCCCCC5HHGHHGHEGEGHHHHHH????@HDH.HHEHGHHEGHHHEHCHHHHHDHHHEHHHHHHHHHHFHHHHGHHFHH UQ:i:0
+20GAVAAXX100126:8:45:4354:79437 99 chr1 10004223 60 101M = 10004540 414 TATAGGCTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGACAGAGTCTCTTTCTGTCACCCAGGGTGGAGTGGAGTGGCACAATCTCAGCTCA CCBACCCDDDDBDAAAAACAAAA<BAAA@@A@@BACDDBCBBDDBDCDACCDCBBDBDDDBDBCBCABBCCCCABCDCCBCDC at BCCBACDCCDCDC@DDA MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHGGGGGGGGGGEGGGGGGGGGGGHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHGHHHHHHHHHDHHHGHHHHHHHHHDHHG UQ:i:0
+20GAVAAXX100126:8:4:5529:91628 163 chr1 10004227 60 101M = 10004550 423 GGCTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGACAGAGTCTCTTTCTGTCACCCAGGGTGGAGTGGAGTGGCACAATCTCAGCTCACTGC @B?C?ABBCBCBBADBBBCADCCCCCCCBDCCCCAC6 at BA@;AC?CCC at C@DBBDDBDCB>B=ACC?9C??C?=>@ABC6>>BB at C?:<C06>@C6A@?C? MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:B@@BCBBCCCBCCBCCCCCABCCCCCCBBBBBBBBB<ABAA<AABBB@@@BBABBABAB@@@>AA at A:A:@@:>;@@@A5>>@@A?89>=-29?>2<=;>< UQ:i:0
+20GAVAAXX100126:8:44:5789:104432 163 chr1 10004228 60 101M = 10004558 430 GCTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGACAGAGTCTCTTTCTGTCACCCAGGGTGGAGTGGAGTGGCACAATCTCAGCTCACTGCA @BCB??ACCBBBBBBBBBBECCCCCCCCECDBBCBA?B>ACCCA<BBCAC<BDADCDCBBBACBC>@CCB at DC@@B?ABAA at D@CDCAACA>=BB at AD@?C MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBCBCCBCBCCCCCCCCCBCCCCCCCCCCCCCCCCBBBCBBBBBCA>AABCBBBBBBBBBBBBBA:BA>B at AB?@B>A=A at BBAB@@AABA<:@@BA@?:A UQ:i:0
+20GAVAAXX100126:8:1:17413:63912 1107 chr1 10004229 60 101M = 10003958 -371 CTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGACAGAGTCTCTTTCTGTCACCCAGGGTGGAGTGGAGTGGCACAATCTCAGCTCACTGCAA @@@@CAAAAACAAAABBAAABADDDDCCCDDDCCADDCBDBCBDBDADCDCDDDCCADBBCCBCBBACBBDACBBDACBBBCBDCDCDBDBCDCCCC at BDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GGGGGGGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:7:11540:56171 83 chr1 10004229 60 101M = 10003958 -371 CTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGACAGAGTCTCTTTCTGTCACCCAGGGTGGAGTGGAGTGGCACAATCTCAGCTCACTGCAA @@@@CAAAAACAAAABBAAABADDDDCCCDDDCCADDCBDBCBDBDADCDCDDDCCADBBCCBCBBACBBDACBBDACBBBCBDCDCDBDBCDCCCC at BDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GGGGGGGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:7:11542:56193 1107 chr1 10004229 60 101M = 10003958 -371 CTTTTCTTTTTCTTTTTCTTTTTTTTCTATTTCTGTTTGAGACAGAGTCTCTTTCTGTCACCCAGGGTGGAGTGGAGTGGCACAATCTCAGCTCACTGCAA @@@@CAAAAACAAAABBAAABADDADCCCDDDCCADDCBDBCBDBDADCDCDDDCCADBBCCBCBBACBBDACBBDACBBBCBDCDCDBDBCDCCCC at BDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GGGGGGGGGGGGGGGGGGGGGGHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:4:16802:116090 659 chr1 10004234 60 101M = 10003895 -439 CTTTTTCTTTATCTTTTTTTTCTATTACTGTTTGAGACAGAGTCTCTTTCTGTCACCCAGGGTGGAGTGGAGTGGCTCAATCTCAGCTCACTGCAACCTCT CEAB?%B*A<&A>)D?;@9<9<@;43, at B(=9C>8AA<D,B87C at CD;/B922<BC at CDB>3<85?;*A47?CC>3)@*6,44BA:@?71B@@;>4B=A9; MD:Z:10T15T49A24 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:3 SM:i:37 MQ:i:60 OQ:Z:BB>;8%=)<;'<B*B98>3:7C>;42)@?)=5A>9?==B+A84ACCA=,A<008ABABBC?8?;;@@*?13 at AB</)>*3+01A>9=A8+C>?9;-A;@37 UQ:i:24
+20GAVAAXX100126:8:25:13133:61877 147 chr1 10004291 60 101M = 10003984 -407 CAGGGTGGAGTGGAGTGGCACAATCTCAGCTCACTGCACCCTCTGTCTCCTGGGTTCAAGGGATTCTCCTGCCTCAGCTTCCCAAGTAGCTGGGATTACAG BBA>AAC9A:2>?@@=>=A7<><9>9@;?B7=@>=?B>,=ABAC=4@>B?;CB at C=8A?AB<;?0:ACBCBCCCBDBCDCCCCCEACCBCCCBBBBA at BD@ MD:Z:38A62 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:A:?8A??6<:/9@=?7<<<5<=96>6?:<>6:8=?>A>/=A?@@=/<?@?=BA@@<<??AB??@3=ABABBABBBBBBBBBBCBCBBBBBBBBBBBBBCBB UQ:i:11
+20GAVAAXX100126:8:66:6823:31942 163 chr1 10004294 29 35M66S = 10004641 427 GGTGGAGTGGAGTGGCACAATCCCAGCTCACTGAAACCTCTGTCTCCGGGGTTCAAGGGATTCTCCTGCCTCAGCTCCCCAAGAAGCTGGGATTCCAGGCC @B0 at A:A6AC5C<<####################################################################################### MD:Z:22T10C1 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:2 SM:i:0 MQ:i:37 OQ:Z:@@+ at B9@4 at B3B=@####################################################################################### UQ:i:4
+20GAVAAXX100126:8:25:9891:26690 147 chr1 10004321 60 14S87M = 10004020 -387 GGCACAATCTCAGCTCACTGCAACCTCTGTCTCCTGGGTTCAAGGGATTCTCCTGCCTCAGCTTCCCAAGTAGCTGGGATTACAGGCACTTGCCACCACGC ###############B=:A7<9>>:<@?@B?BBB=BB?B@>CCC>BC=A@@DCCBC?CBD at BBB5BBCDACDCCCCCBCEDABCCAB;BDCACBBBA@:B@ MD:Z:87 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:###############?67<7<97>::???<??@A???A@>?AAB<AA?<@ABBAABAABBABBB<BBBBBBBBBBBBBBCCBAABAA=BBBABBABABBBB UQ:i:0
+20GAVAAXX100126:8:45:4754:168834 1107 chr1 10004321 60 16S85M = 10003992 -413 GTGGCACAATCTCAGCTCACTGCAACCTCTGTCTCCTGGGTTCAAGGGATTCTCCTGCCTCAGCTTCCCAAGTAGCTGGGATTACAGGCACTTGCCACCAC #################=<<<8:,:55<56<3<:6;<:;0<<6<==;;<<1=:7<<;8=;==9<;;:995=;:@>@35??@==>>>>B=B@>A==9?5<=> MD:Z:85 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:#################A??>552449>;9A3455544515<8<><55440455554445555554<=@9=A>CCC89CCC54455AGDGFAFAD at DDDDD UQ:i:0
+20GAVAAXX100126:8:8:8310:17522 147 chr1 10004327 60 17S84M = 10003989 -421 ACAATCTCAGCTCACTGCAACCTCTGTCTCCTGGGTTCAAGGGATTCTCCTGCCTCAGCTTCCCAAGTAGCTGGGATTACAGGCACTTGCCACCACGCGCA ##################B<@AA@>147?874 at C8BB>CAAB?@CCA9ABACBCCB=CB?C@@A?C at CDBBCCCB?DBBBCCBBBCDBBCBBCB at 9A:BB@ MD:Z:84 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:##################?6?@<?=115:670<B=???A?A?>=A@>:>ABBABAB?BB?BAABABBBBAABBBB>BAAAABBBABBBBBBABBBBBBBBB UQ:i:0
+20GAVAAXX100126:8:21:4413:182078 99 chr1 10004409 60 101M = 10004700 382 CAGCTAATTTTTGCATTTTGAGTAGACAGGGGGTTTCACCATGTTGGCAAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCTGCCCACCTTGGCCTGCTG CCB at DCDCDDDDBBCCDDDBDCBCCDACCCCCCADDBCABCCBBDBCBCDCCBDBCBBDB;DD at DBBDBCABDBCCCA@DCBDCBCCCACDDCD?CDCCED MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:23 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHIHHHHHHIHHHHHIHHHHHHHGGHHHHHHHHHHHHHHHEHHHHHH UQ:i:0
+20GAVAAXX100126:8:1:11745:83846 163 chr1 10004442 37 101M = 10004719 377 TTTCACCATGTTGGCAAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCTGCCCACCTTGGCCTGCTGGAGGTATGTGACAAACTGATGGCAAATGGATTA @BAA@?BBCBACBBCCDCCCDBC at BBB;CDADBCC;7 at ACBCBC;BD?BD=BC@?BBCCAABBCAC at B8A?C?;:>A;C>BAC?@BA;?C=;C>=A;?AA; MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:37 MQ:i:29 OQ:Z:BCCCCCCCBCBBBBCBBCBCBBB:B at BBABBBABB><BBBBBBB=AB<BA at BBA9BA@A?ABAB?BAB7>@A6=9=?:??B??B=?;:?@=CB;7?97@:8 UQ:i:0
+20GAVAAXX100126:8:45:9158:12274 633 chr1 10004442 0 62S39M = 10004442 0 CTGGGATTACAGGTGCCCACCACCACACTTGGCTAAGTTTTGTATTTTTAGTAGAGTCGGGGTTTCACCATGTTGGCAAGGCTGGTCTCGAACTCCTGACC ###############################################################>>=;+<<=9;<:9=;?;;?=<<=?<6==?@>9@>5>*1 MD:Z:39 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:0 OQ:Z:###############################################################AA?51544555455545545544455544445455515 UQ:i:0
+20GAVAAXX100126:8:45:9158:12274 693 chr1 10004442 0 * = 10004442 0 CAAGAATTTCAGTTGCAGTCAGTACTCGGTTCAGGAACACTCCACCCAGGTTTGTAGCTTAGGAGCAATAGACTTTTTCCTATGCAATGTAGGTGTGTGGT ##################################################################?1AC5516*B*C'BA*A&@-<-0;4;6B.@)41@< PG:Z:BWA RG:Z:20GAV.8 OQ:Z:##################################################################@/@A30-2)@*A*A@*?'?-8,29074A,@*02A8
+20GAVAAXX100126:8:28:13507:25203 147 chr1 10004453 60 1S100M = 10004176 -376 TTGGCAAGGCTGGTCTCGAACTCCTGACCTCAGGTGATCTGCCCACCTTGGCCTGCTGGAGGTATGTGACAAACTGATGGCAAATGGATTATGCCCCCAAT ##A:AAC?:?@C:CBB1 at B>A>@A at A=ABC at CC@@BBBBB at AAC>BC at CC?CBCCC=CBA5>ABA at BBBCCCBCCBCBCBBCCCCCCBCCCCBCBBAABC@ MD:Z:100 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:##@4=?<=6=?A=@==4B=;@==A?B8A@?AABAAA at AA@A@@A8 at AA@BAAAABB at AB@7ABBBBBBABBBABBBB at BBBBCBBBCBBBBBBBBBBBBCB UQ:i:0
+20GAVAAXX100126:8:21:17746:177127 83 chr1 10004479 60 101M = 10004141 -438 CCTCAGGTGATCTGCCCACCTTGGCCTGCTGGAGGTATGTGACAAACTGATGGCAAATGGATTATGCCCCCAATGGACAGTGTTCTCAAACCGTGATCTGA DDDCAC?DCCDCCBCCBCCAD;BBCCCBCCABDBACCCACBCBDDBCCBCCBBBDDCCBBCDCCCBCCCABDCCBBBBCACADDCDBDDBC;ACBCDACBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHDHGHHHHIHHHHHHHGHBHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:21:17763:177132 1107 chr1 10004479 60 101M = 10004141 -438 CCTCAGGTGATCTGCCCACCTTGGCCTGCTGGAGGTATGTGACAAACTGATGGCAAATGGATTATGCCCCCAATGGACAGTGTTCTCAAACCGTGATCTGA BACCDC=D at CD??>?@;45::@A>B?B>><A at BB??@<9<<C>DDA=A:@@B at BADCCBBCDCCC@CCCCBDCCBB at BC<C<ADCD=;;A;;ACB=B:?8< MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:FFFHHHEHGHHDCCCC43555EGEGCGDCBGGFHGEF@@@BHEHHEEFBEDHFHGHHHHHHHHHHFHHHHHHHHHHFHHEHEGHHHDB at FBHHHHEGGGEG UQ:i:0
+20GAVAAXX100126:8:45:18787:46333 163 chr1 10004482 60 100M1S = 10004790 408 CAGGTGATCTGCCCACCTTGGCCTGCTGGAGGTATGTGACAAACTGATGGCAAATGGATTATGCCCCCAATGGACAGTGTTCTCAAACCGTGATCTGAGGA @CBB?ABABDBBBACACDCBBACCBBBBCCCC?BBA:AB at ACBABBCABC@CD?DCBCBB at ABA?C>CCB>BB=?AA<BA@@C@@4@<7;;AA;BBACA## MD:Z:100 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBB<BBABBBBBBBBBBBAAABABB at AAABB=ABB>BBBABABBA@?BABBB at BBA@A at A@AA<A at BA??@@=@?A9@????@=/:<6?7?=:??==?## UQ:i:0
+20GAVAAXX100126:8:42:7969:44162 1107 chr1 10004491 60 101M = 10004170 -421 TGCCCACCTTGGCCTGCTGGAGGTATGTGACAAACTGATGGCAAATGGATTATGCCCCCAATGGACAGTGTTCTCAAACCGTGATCTGAGGACCCGGGGAT 7 at A@@<A>@CBA>ABBABA at CA?ABC<>>8@@@AAC at BBBB@AABCA@@?BB@>BBBB=AB>A@:AB?B?AB at C@A at AB9@BABCAC at CA@?BB:@@:==< MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:5GGDG;GCEGGGEGGGGGGGGGGGGGCAC9CGGEGGGGGGGGGGGGGGCDGGECGGGGEGGAGGCGGGGGGGGGGGGGGGGGGGGGGGGGGEGGGGGGGGG UQ:i:0
+20GAVAAXX100126:8:42:7986:44148 83 chr1 10004491 60 101M = 10004170 -421 TGCCCACCTTGGCCTGCTGGAGGTATGTGACAAACTGATGGCAAATGGATTATGCCCCCAATGGACAGTGTTCTCAAACCGTGATCTGAGGACCCGGGGAT <DDACBDCDCCBCCCBCCC at D=ACCCABBBBDDCCCBCBBBBDDCCBBCDCCCBCCCCBDCCBBBBCACADDCDBDDAC;ACBCDCCBCBB at CC;CC at BCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:<HHFHGHHHHHHHHHHHHHGHEHHHHHGHHHHHHHHHHFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHGHHFHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:45:4354:79437 147 chr1 10004540 60 3S98M = 10004223 -414 GGATTATGCCCCCAATGGACAGTGTTCTCAAACCGTGATCTGAGGACCCGGGGATCCCGAGACCTTTTAAGGGTATCTGTGAGATCAAAGCTATTTTCATA ####A?>89A4 at 9@BCB at C@@>B>BBAABB=?B7>CBABB at BCBBCD>:C=CBDCB@;BDB>=BBCCCCDCCACCCCCACBDBCCBCBDBCBCCCBBABC@ MD:Z:98 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:####?>778?6=9>??A???>??@@@@@@=>:@>BAAA at A@BA at B?B@@B at ABBAAAABBB@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCBB UQ:i:0
+20GAVAAXX100126:8:2:15114:83430 147 chr1 10004542 60 101M = 10004220 -422 ATGCCCCCAATGGACAGTGTTCTCAAACCGTGATCTGAGGACCCGGGGATCCCGAGACCTTTTAAGGGTATCTGTGAGATCAAAGCTATTTTCATAATAAT >D=@B<=ACAAC?BCD at BABBBDAB@=A;BABDC?CBCC>;CC;CCC?DC at C;CDB>BBCCBABBBBACCCCCACBDCCCCCCDBCCBCDDCBBB?@ABC@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:;?;<?;:A@@@A@@B at A@ABAAAB@>8AABABBBABBBB>:BABBBAABBAABBBB@@BBBBBBBBBBBBBBBBBBBCBBCBBBBBBBBBCBBCBCCCBCB UQ:i:0
+20GAVAAXX100126:8:4:5529:91628 83 chr1 10004550 60 101M = 10004227 -423 AATGGACAGTGTTCTCAAACCGTGATCTGAGGACCCGGGGATCCCGAGACCTTTTAAGGGTATCTGTGAGATCAAAGCTATTTTCATAATAATCCTGAGAT EDDCCCCDAC at DDCDBDDBC;ACBCDCCBDBBBCC;CCBBCDC>;BDBBCCDDDCDCBBACCDCCACBCBCDBDDDBACCDDDDBCCDCCDCDCCCBBBCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHIHHHHHHHGHHHHHHHHHHHHHIHHHHHHHHHHEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:44:5789:104432 83 chr1 10004558 60 101M = 10004228 -430 GTGTTCTCAAACCGTGATCTGAGGACCCGGGGATCCCGAGACCTTTTAAGGGTATCTGTGAGATCAAAGCTATTTTCATAATAATCCTGAGATGATATTTG ?EBEDCCCDDCC;ACBCDCCBBBB at CC;BBBBCDCC8BDBBCCDDDCDDBBACCDCCACBDB at DBDDCBCCCDDDDBCCDCCDCDCCCBDBCCBCCCBDCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GHHHHHFHHHHHHHHHHHHHHGHHEHHHHHHHHHHHFHHHIHHHHHHHHHHHHHHHHHHHHHFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:25:3804:30880 163 chr1 10004579 60 101M = 10004891 412 AGGACCCGGGGATCCCGAGACCTTTTAAGGGTATCTGTGAGATCAAAGCTATTTTCATAATAATCCTGAGATGATATTTGCTCTTCATTCTCTCTCTCTCA @CCB?AB:CCCCCACC;CCCACDCCCCDCCCACCACA>AB at CCCADDCBDACCADCCDBDBCCBACABDCADBABAB@?AABCCCCDB>:AAD?D?DBBD@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBB;BBBBB at BBCBBBBBBBBBBBBBBCBBCBBBABCABBBB@BCBBAB?;AB at BA@BBB>4??BB?B@@@A< UQ:i:0
+20GAVAAXX100126:8:42:4321:53069 99 chr1 10004580 60 101M = 10004795 315 GGACCCGGGGATCCCGAGACCTTTTAAGGGTATCTGTGAGATCAAAGCTATTTTCATAATAATCCTGAGATGATATTTGCTCTTCATTCTCTCTCTCTCAT CCC?CC;ACCDCBBB;DCDABDDDDCDCCCBCCBCBB at DCDCBCDDCBCCCDDDBCCCDCCDCBCDBACDCBDC=CDDBBDBDDBCCD at DADCDCDCDCED MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHDHHHHHHDHHHHHHHHHHHHHGHGHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:41:10214:75276 163 chr1 10004590 60 101M = 10004899 409 ATCCCGAGACCTTTTAAGGGTATCTGTGAGATCAAAGCTATTTTCATAATAATCCTGAGATGATATTTGCTCTTCATTCTCTCTCTCTCATGAGCATATGG @CBBA8BBCACDB at CCDCDCBCCCDBBCCCCCBCCCAACBCCCC@CDCCDABD at CEBDCCBBCBCD@CCBBCEAABAAAC at BBBADCC?C at AC@BAC at ACD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBCCBCBBBBBCCCBBBCCB at BBCBBABABBBBBBBBBBBBBBBBBBBBBBABBBBBABBBBBBBBAABAABBBBBAB@B at B@B at ABB@@BA at B@?@<@@B UQ:i:0
+20GAVAAXX100126:8:5:7628:108971 99 chr1 10004623 60 101M = 10004891 362 AAAGCTATTTTCATAATAATCCTGAGATGATATTTGCTCTTCATTCTCTCTCTCTCATGAGCATATGGGAGTTTTCCAGAGACTTCCTGCCAGGCCACATC CDDACDCCDDDBCCCDCCDCBBCBDCDCBDCCCDDBBCBCDBCCDBCBCBCBDBDBCCBDCBCCCCBCCACBDDDBBCCDCDADDBCDCACCCDCCDBDDD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHEHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:5:7649:108990 1123 chr1 10004623 60 101M = 10004910 362 GAAGCTATTTTCATAATAATCCTGAGATGATATTTGCTCTTCATTCTCTCTCTCTCATGAGCATATGGGAGTTTTCCAGAGACTTCCTGCCAGGCCACATC *DDACBCADBD?ACBCC?ACBABBDCDCBDCCADBBBCBCDBCCDBCBC?CBDBDBCCBDCBCC>CBCBACBDDDABC at DCDADDBCDCA@CADCCD?DDD MD:Z:0A100 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:8HHHHGHIHIHIIHGIHFGHHGIHHHHHHHHHIHIHHHHHHHHHHHHHHFHHHHHHHHHHHHHHCHHHGDHHHHHGHHGHHHHHHHHHHGFHFHHHHGHHH UQ:i:9
+20GAVAAXX100126:8:42:11066:118124 163 chr1 10004633 60 101M = 10004938 405 TCATAATAATCCTGAGATGATATTTGCTCTTCATTCTCTCTCTCTCATGAGCATATGGGAGTTTTCCAGAGACTTCCTGCCAGGCCACATCACAACTGACC @CBB at ABBDCBCDACCCCCCCCDCCBBDBDCBCCBABACACBDCBBCDBDABCABDBDCCBACACB@CCCACABC at BBB@ABBB?CC@@C?B?>D?DCBBA MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCCCCCCCBCCCCBCBBCBBBCCCBBBBBBBBBBBBBBBBBBBBBBBBBBBBBABBBAAB?A at BAABBAB@AAA at BA@?@A?A>A at A@@@@><@??@@@> UQ:i:0
+20GAVAAXX100126:8:66:6823:31942 83 chr1 10004641 37 20S81M = 10004294 -427 TCAAAGCTATTTTTATAATAATCCTGAGATGATATTTGCTCTTCATTCTCTCTCTCTCATGAGCATATGGGAGTTTTCCAGAGACTTCCTGCCAGGCCACA #####################<>6=><99:26:>@=<:=<=;,<<<+5<;9=<=<===BB?B<BCBC?BBBBAADD at CB?=CBBCDDCCCBC=DCC=4:<< MD:Z:81 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:37 MQ:i:29 OQ:Z:#####################?A;?A45553:?AD?544455-544-8<@;44444<EGGCG?HHGHDHHHGHGHHEHHDEGHHHHHHHHHHDHHHDECGG UQ:i:0
+20GAVAAXX100126:8:25:19700:154119 99 chr1 10004642 60 101M = 10004969 427 TCCTGAGATGATATTTGCTCTTCATTCTCTCTCTCTCATGAGCATATGGGAGTTTTCCAGAGACTTCCTGCCAGGCCACATCACAACTGACCTGACCCAGA CBBBCDCDCBDCCCDDBBDBDDBCCDBDBDBCBCBCBCCBDCBCCCCBCCDCBDDDBBCBDCDADDBBDBBBCCCBBCACCBCACDADCDACDCDACCDDE MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:21:4413:182078 147 chr1 10004700 60 9S92M = 10004409 -382 GAGTTTTCCAGAGACTTCCTGCCAGGCCACATCACAACTGACCTGACCCAGAAGTACATCTGAGAATTCAGCTGTCTTCTATTAAGCCAGACATTAAAGAG ##########?:77BC<A?1<>??AAB8AA>@A@=CBAAB9CACBAB at AC@CDABA?C at CB?@AA at CCBCBBCACADC=CADDCDBCADBABCCBA?CBD@ MD:Z:92 PG:Z:BWA RG:Z:20GAV.8 AM:i:23 NM:i:0 SM:i:23 MQ:i:60 OQ:Z:##########?364??8 at 9-<>;>@AA8;;?=@>@B>A?A6A@?A:@A at ABBBAABAA@BBAABBABBB at BABBB@BB:B at BCBBBBCBBBCCBBBCCBBB UQ:i:0
+20GAVAAXX100126:8:1:11745:83846 83 chr1 10004719 29 101M = 10004442 -377 ACATCACAACTGACCTGACCCAGAAGTACATCTGAGAATTCAGCTGTCTTCTATTAAGCCAGACATTAAAGAGATTTGCAAAAATGTCAAACAAGGCCACT DDCBCCCDCCCBCCCCBCCCBDBDDACBBCDCCBDBDCDDBDBCCADCDDCCCDCDCBCBDBBBCDCDDCBDBCDDCBBDDDDCCADBDDCBDDCCC at BCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:0 MQ:i:37 OQ:Z:HHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:26:5797:83894 99 chr1 10004750 60 101M = 10005102 425 CTGAGAATTCAGCTGTCTTCTATTAAGCCAGACATTAAAGAGATTTGCAAAAATGTCAAACAAGGCCACTCTGCATGTAATAGGCTTATCTTAAAAATGAA CDBBCDDCDBCCBDBBBDDBDCCDCDCBBCCCABCDCDDCDCDCDDBBCADDDCBBBCDDACDCCBBCADBDBBCCBCCBCC>CBADC at BDDCDB?>BAC6 MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHIHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHFHHEHHEHHEHHHHHFBBFFF5 UQ:i:0
+20GAVAAXX100126:8:43:4132:159191 675 chr1 10004784 29 95M6S = 10005128 377 TTAAATAGATTTGCAAAAATGTCAAACAAGGCCACTCTGCATGTAATAGGCTTATCTTAAAAATGAATTAATATGTCTCTTGGTTGCCGTTTCTAATCAAA <*89B,A<C<BC6;<@C at D@6==BDC8C?,B?@<@A=?44;;8=A9>A=@4@)(@@CCB=6/C>CB5>B6)7C<>7A;@?.7DA>CCB8BBABA####### MD:Z:5G89 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:1 SM:i:29 MQ:i:29 OQ:Z:8):5@,@;B:AA7 at 7>A=B?27;ABA7A<+A=>:BAC at 78==:7B9:@==8?))<>ACC:6-A?B?6=>4(1B==/A9==.4B?<AABABABAB####### UQ:i:11
+20GAVAAXX100126:8:45:18787:46333 83 chr1 10004790 60 101M = 10004482 -408 AGATTTGCAAAAATGTCAAACAAGGCCACTCTGCATGTAATAGGCTTATCTTAAAAATGAATTAATATGTCTCTTGGTTGCCGTTTCTAATACAATCCATC EDCEECCCDDDDCCADBDDCBDDCBCBBCDCCBBCCACDCCDBBCDCCDCDCDDDDCCBDCDCDCCCCABCDCDCBADCBC;ADDDCCDCCCBDCDC at BDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:68:18251:192056 99 chr1 10004792 60 101M = 10005081 362 ATTTGCAAAAATGTCAAACAAGGCCACTCTGCATGTAATAGGCTTATCTTAAAAATGAATTAATATGTCTCTTGGTTGCCGTTTCTAATACAATCCATCTG CCCBCCCDDDDCBBBCDDACDCCBBCADBDBBCCBBCDCCCCBCDCCBCDCDDDDCBDDCDBDCCCBCBDBDDBCCD at BC;CDDBDCDCCACDCCCDCCED MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:42:4321:53069 147 chr1 10004795 60 101M = 10004580 -315 TGCAAAAATGTCAAACAAGGCCACTCTGCATGTAATAGGCTTATCTTAAAAATGAATTAATATGTCTCTTGGTTGCCGTTTCTAATACAATCCATCTGCCT @C at EDBDAC?AC<BDBBBD at 7ACA=BB at CDAAAC@CDBBCBCCDCDCAC?:DCBCD at C@A@?@><?BCDCC at DC?D;ADECCDBDCAABCCCBBB at AABC@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:<@AAA at B@@@@B<@@@BBBB9B at A<B at BABAB@BBBBBBBBBBBBBBBCCCCBACCABCCACAC at CBBBBBABB>CCBBCCBCCCCBCCCBCCCBCBCCCB UQ:i:0
+20GAVAAXX100126:8:27:3628:73265 611 chr1 10004826 60 35M66S = 10005114 346 GTAATAGGCTTATCTTAAAAATGAATTAATATGTCTCTTGGTTGCCGTTTCTAATACAATCCATCTGCCTCAGACTCCCAAAGTCCTAAGATTATAGGTAT 1405==>9;?<+?>@==<<>>=<=############################################################################# MD:Z:35 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:51155455555,44444554??>?############################################################################# UQ:i:0
+20GAVAAXX100126:8:21:16295:166486 163 chr1 10004833 60 101M = 10005120 387 GCTTATCTTAAAAATGAATTAATATGTCTCTTGGTTGCCGTTTCTAATACAATCCATCTGCCTCGGCCTCCCAAAGTCCTGAGATTATAGGTATGAGCCGC @BCBAAACACDDDBCCCDDCCDDCCBBBDBDCBC at BA?A:@BCCBCDDCAACD at CDBBCB@AC@:C=ACA at DCABA?@BA@;B at ACAB<B@@AAABBCA;A MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBCBCCCCCCCBCBBCBBBCBBBABBBBBBBABBABBAABBBBBBBABBBBBBAAAAA?AA?A@?@@@B@@@@>@@?@8@>?@?@>@?;?@>?>??>? UQ:i:0
+20GAVAAXX100126:8:63:6148:94882 675 chr1 10004865 37 73M28S = 10005252 421 GGTTGCCGTTTCTAATACAATCCATCTGCCTCGGCCTCCCAAAGTCCTGAGATTATAGGTATGAGCCGCTGCACCCGACCTAGCCTTTTCATATGGAGTCT @?5??AB6>A;A71DC;@CABB9?C;CA60790,%=7/=?>BC=?8;;=665D=77:;483A:24A.0;73B############################# MD:Z:73 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:37 MQ:i:29 OQ:Z:B=4=?BB>7?;@62BB:AB?AB5;B9A at 3.2650(?;0 at C?AB9A975>175B?32945/5 at 80/?/5811@############################# UQ:i:0
+20GAVAAXX100126:8:42:16609:191180 163 chr1 10004875 60 101M = 10005207 432 TCTAATACAATCCATCTGCCTCGGCCTCCCAAAGTCCTGAGATTATAGGTATGAGCCGCTGCACCCGGCCTAGCCTTTTCATATGGAGTCTCAGACAGTGA @CCAAAA at BDCCCACCDCCDDC;CCDEBCDDDDC at A>CABBBCCACCCCBACCACBC;BCABB?CB5CBCBBC at ACBBCAAABBACAB:BBA:AD?BD at DD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCBCCCCCCCCCCCBCBCCCBCBBCCCBBCCBBBABCBBBBABBBBBBB?BBBBBABBBABAAAB@@BABAAAB at AAA@B at B@A@@<A7@@A4?@A=A=BB UQ:i:0
+20GAVAAXX100126:8:8:2524:114198 675 chr1 10004891 29 35M66S = 10005259 428 TGCCTCGGCCTCCCCACGTCCTGCGATTATAGGTATGAGCCGCTGCACCCGGCCAAACCATTTCGTATGGAGTCAAAATCCATGAAGTTCATGCAATCTAT @:0?B::=4(6AB:)A##################################################################################### MD:Z:14A1A6A11 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:3 SM:i:29 MQ:i:29 OQ:Z:A60=B;B=2)2 at B=*@##################################################################################### UQ:i:12
+20GAVAAXX100126:8:25:3804:30880 83 chr1 10004891 60 101M = 10004579 -412 TGCCTCGGCCTCCCAAAGTCCTGAGATTATAGGTATGAGCCGCTGCACCCGGCCTAGCCTTTTCATATGGAGTCTCAGACAGTGAAATTCAGTCAATATAT #DDDD;CCCC at BCCDDDABCCCBDBBDCCCDBA>CCBDBC;BCCBB at CC;BBCCCCBCCDDDDBCCCCBBDADCDBDBBBDACBDDCDDBDADCDCCACCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:#HHHHHHHHHAGHHHHHHFHHHHHHIHHHHHHHDHHHHHHHHHHHHEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:5:7628:108971 147 chr1 10004891 60 6S95M = 10004623 -362 TCCATCTGCCTCGGCCTCCCAAAGTCCTGAGATTATAGGTATGAGCCGCTGCACCCGGCCTAGCCTTTTCATATGGAGTCTCAGACAGTGAAATTCAGTCA #######@B>25;8 at 8/:A;>B<><B887B;;B=9=@@>9;;>C at B;<B?<A=DD:ABC?BAABACCDCCCCCCCCDACCCBDCACD at CBCBCCB@A at CC@ MD:Z:95 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:#######??;/6;7=2-:=:=@6?;A673:=9?==<<@?:=7=>?@?????@;BBABAB at BABBBBBBBBBBBBBCBBBBBBBCBCBBBBBCBBBCCCBCB UQ:i:0
+20GAVAAXX100126:8:41:10214:75276 83 chr1 10004899 60 101M = 10004590 -409 CCTCCCAAAGTCCTGAGATTATAGGTATGAGCCGCTGCACCCGGCCTAGCCTTTTCATATGGAGTCTCAGACAGTGAAATTCAGTCAATATATTTATAATG DDCDDCDDDADCCCBDBADCCCDCACCCBDBC;BCCBBBCC;BBCCCDBCCDDDDBCCCCBBDADCDBCBBBDACBDDCDDBDADBDCCCCCDDCCCBBCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHFHHHHHHHHHHHHHHFHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:5:7649:108990 1171 chr1 10004910 60 25S76M = 10004623 -362 TCCATCTGCCTCGGCCTCCCAAAGTCCTGAGATTATAGGTATGAGCCGCTGCACCCGGCCTAGCCTTTTCATATGGAGTCTCAGACAGTGAAATTCAGTCA ##########################B7:B8;C<88 at A740B@C=D:?C?<C;DD8<A??BCA;>ACDCCCCDCDCDACCCBDCBBD at CCCBCCBAB@CB@ MD:Z:76 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:##########################A56<99@<<6<A740@@@<B at AA??B7BB at C@@@BBB>ACBBBBBBCBCCBBBCBBBCABBBBCBCBCBBBCBBB UQ:i:0
+20GAVAAXX100126:8:42:11066:118124 83 chr1 10004938 60 101M = 10004633 -405 CCCGGCCTAGCCTTTTCATATGGAGTCTCAGACAGTGAAATTCAGTCAATATATTTATAATGAATACTTTTTTTTTTGAGATGGAGTCTTGCTCTTGTCAC DE;AADCCDCCCDDDCBCCCCCBDADCDADBCBDAC>ADBBCBCACADCBCACCC?CADBC?D at C;=>AAADDDDDCBCBCCBBDADCDCBCDCDCABBCC MD:Z:70A30 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:IHHGGHHHHHHHHHHGHHHHHHHHHHHHIHHHHHHHCGHIGGHGHGGHHIGIHIIFHGHGHGHFHCEEGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:32
+20GAVAAXX100126:8:25:19700:154119 147 chr1 10004969 60 101M = 10004642 -427 ACAGTGAAATTCAGTCAATATATTTATAATGAATACTTTTTTTTTTGAGATGGAGTCTTGCTCTTGTCACCCAGGCTGGAGTGCAATGGCGTGATCTTGGC BD?@C at D@CCAC??DCCAC@<@DBABAADD at CDC<CD=CDBDCDDDCBDCACBEAC;ECA@>>AA>BCACCCEDBCCDCDBDCCBDCBB;ACBC@@ABCC@ MD:Z:39A61 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:?B;<B@@BBAABB at AB@BB?=?ABBAABBBBBBB>BBCBBBBCBBCCBCBBBBCBBCCBCCCCABCBC>BBBCCBCBCCBCCCCCCCCCCCCCBCCCCCCB UQ:i:35
+20GAVAAXX100126:8:48:10519:110723 99 chr1 10004994 60 101M = 10005311 417 ATAATGAATACTTTTTTTTTTGAGATGGAGTCTTGCTCTTGTCACCCAGGCTGGAGTGCAATGGCGTGATCTTGGCTCACTGCAACCTCCGCCTCCCAGGC CCCBCCCDCCADDDDDD;>:?>:C@<<7:==;=;=???A@>BBBABBCCCB at BC8CCB?@BC>B:5<:7;9<9;5B<BCAA?B at DACDBC;CCD>CCDDE@ MD:Z:14A86 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:HHHHHHGHHHHHHHHHHBCBCC=HD4555445444EDFFFEHHGHGHHHHHEHH:HHHCDGHCGB=<@;>54445H=HHHEEHEHHHHHHHHHHDHHHHHE UQ:i:35
+20GAVAAXX100126:8:68:18251:192056 147 chr1 10005081 60 27S74M = 10004792 -362 ATGTCGTGATCTTGGCTCACTGCAACCTCCGCCTCCCAGGCTCAAGCGATTCTCCTGTCTCAGCCTCCTGAGTAGCTGGAATTACAGGCATGGGCCACCAC ############################B99A at 9<AA;A@>?9BBA;<?B=C at AC@?C?@@9<@>=@@<BB?>BB@@CACBDCBACC>@AABBABA at BBC@ MD:Z:74 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:############################?;;?<6???:@??<6?????;A?A?>A?B@@@A;@AA?A?:A@@=?B>>BABABB@@ABAA?AABABB>AB at B UQ:i:0
+20GAVAAXX100126:8:1:6636:49601 99 chr1 10005102 29 101M = 10005477 440 ATTCTCCTGTCTCAGCCTCCTGAGTAGCTGGAATTACAGGCATGGGCCACCACGCCCGGCTAATTTTTGTGTATTTAGTAGAGATGGGGGTTTCACTATGT CCC at DBCDBCBDBCCBBDBBDBDCBCCBDBCDDCDCACCCBCCBCCBBCABCA;BBB;CBDCDCDDDDB at ABCCDDCCCCCDCDCBCCCC?DDCDADD at DD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:0 SM:i:29 MQ:i:29 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHEGHHHHHHHHHHHHHHHHHHHAHHHHHHHDHH UQ:i:0
+20GAVAAXX100126:8:26:5797:83894 147 chr1 10005102 60 27S74M = 10004750 -425 GCAACATCCGCCTCCCAGGCTCAAGCCATTCTCCTGTCTCAGCCTCCTGAGTAGCTGGAATTACAGGCATGGGCCACCACGCCCGGCTAATTTTTGTGTAT ############################B865235A?;>>C;9A:>@)?C7<=@>C899CC28)5B??:CB at CA<8/B>8B;@8@>B:CC?CCCB?@@BC@ MD:Z:74 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:############################?161316B;;<=B99=6<;*;A<9<>:B;6:BB58)8BA>9BA>B at 942B9>B;><>>A?BB?BBCBB?BBBB UQ:i:0
+20GAVAAXX100126:8:27:3628:73265 659 chr1 10005114 60 42S59M = 10004826 -346 CATCCAAGCACCCACTCCAAGGCTCAAGCAATTCTCCTGTCTCAGGCTCCTGAGTAGCTGCAATTACAGGCATGGGCCACCACGCCCGGCTAATTTTTGTG ###########################################C at 3=3<=>C<&><@C@*'8B9;:'>@8?:BCBBC<,0CA;C9&0/1>9C.CB?@?9A? MD:Z:3C14G40 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:2 SM:i:37 MQ:i:60 OQ:Z:###########################################?>172:>@B:(;;BA@,';B;@9';>6>9?BABB9)3CBCC9)204;;B,BC??><=> UQ:i:24
+20GAVAAXX100126:8:21:16295:166486 83 chr1 10005120 60 101M = 10004833 -387 CCTGAGTAGCTGGAATTACAGGCATGGGCCACCACGCCCGGCTAATTTTTGTGTATTTAGTAGAGATGGGGGTTTCACTATGTTGGCCAGGCTGGTCTCGA DDDCDACDCCCCBDCDCCCDBBBCCBBBCBCCBC;BCC;BBCCDBBDDDCACACCDDCCACCBCBCCBBBBADDDBBCCCCADCBBCBDBBCCCADCB:BC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:43:4132:159191 595 chr1 10005128 29 66S34M1S = 10004784 -377 GTCTGGGCTCACTGCAACCTCCGCCTCCCAGGATCAAGCGATTCTCCTGTCTCAGCCTCCTGAGTAGCGGGAATTAAAGGCATGGGCCCCCACGCCCGGCG ###################################################################################################4. MD:Z:2T7C11A11 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:3 SM:i:29 MQ:i:29 OQ:Z:###################################################################################################A7 UQ:i:6
+20GAVAAXX100126:8:48:2299:12648 99 chr1 10005135 60 101M = 10005519 438 TTACAGGCATGGGCCACCACGCCCGGCTAATTTTTGTGTATTTAGTAGAGATGGGGGTTTCACTATGTTGGCCAGGCTGGTCTCGAACTCCTGACCTCATG 9DC?CCCCCCBCABBCABCA;BBB;CBDCDCDDDDBA@?CCD at CCBCC@:DC at CCCC9@DBCADCCBC@:==;;=BABA;:>?:69A9A=?=AC:A=?BAD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:IHHHHHHHHHHHIHHGHHHHHHHHHHHHHHHHHHHHGGEHHHFHHHHHDBHHFHHHHBFHHHHHHHHHD at BABBAGGFFB;DA at D:D at DAA?GGBF>DDGH UQ:i:0
+20GAVAAXX100126:8:42:16609:191180 83 chr1 10005207 60 101M = 10004875 -432 CAGGCTGGTCTCGAACTCCTGACCTCATGATCCACCTGCCTCAGCCTCCCAAAGTGCTGGAATTACAGGCGTGAGCCACTGTGCCTGGCCTATAATGAATA DBC?CDCADCD;BDBCACCB at 9CCDB?B=<ACB3CCCB at CDBDBCCCCCBDDCABBCCB@DCDCABCBB;ACBDBCBACCACBCCCBBCCCCCDCCBBBCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HGHEHHHHHHHHHHGHDHHFFBHHHHDFDBDHH/HHGHFHHHHHHHIHHHHHHHGHHHHIHHHHGHHHHHHHHHHHHFHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:63:6148:94882 595 chr1 10005252 29 66S35M = 10004865 -421 TGGCAGTTTCATTATGTTGGCCAGCCTGGTCTCAAACTCCTGACCTCATGATCCACCTCCCTCAGCCTCCCAAAGTGCTGGATTTCCAGGCGTGAGCCACT ##################################################################################################### MD:Z:16A2A15 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:2 SM:i:0 MQ:i:37 OQ:Z:##################################################################################################### UQ:i:4
+20GAVAAXX100126:8:8:2524:114198 595 chr1 10005259 29 40S61M = 10004891 -428 GAACTCTTGCCCTCATGATCCACCTGCCTCAGCCTCCCAAAGTGCTGGAATTACAGGCGTGAGCCACTGTGCCTGGCCTATAATGAATACTTTTTAATATT #########################################;<=7>7=>-A9;:<<;7:===:7=<<<:<:7<<,99=</:=978<@@=>>>?>=>?5>;1 MD:Z:61 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:0 SM:i:29 MQ:i:29 OQ:Z:#########################################A=A9A:AA/F=@===444444444544454555/5444/55=9:=CF5AA4454444555 UQ:i:0
+20GAVAAXX100126:8:48:10519:110723 147 chr1 10005311 60 101M = 10004994 -417 TTTAATATTCTCTTTGTTTCTGTCCACAGCAAGAATCTTTATTTCCTGAGACCTTTTGTAGCAGATTATTTTCCCTCAGTTTCTTGCCCTTAAGAGTCTTC DE?BC at ABCA?A=CDAC?A at B@CB:9BACC at CCB>BABCCBDDDCBD:CB:DBDBDABBABACA>A?CDDDCCCDCBDAAECCCDCC8BDCBCBC??BCB@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BAB<@B=AA@>==@BA@=;?BA at A:3B at BA@AB@@?@BBBBBBBB at CC@B<BAB?CBCB at BBBBCCABBBBBABCBBBB?CBBACCB=BCCCCCBBCBCCB UQ:i:0
+20GAVAAXX100126:8:22:15343:70426 675 chr1 10005335 37 77M24S = 10005751 450 CACAGCAAGAATCTTTTTTTCCTGAGACCTTTTGTAGCAGATGATTTTCCCTCAGTTTCTTGCCCGTAAGAGTCTTCGATTCTCCTCTGAGCAGAGGTTTG -,&@>-A2A(;A3;9B*ACB8A8;B+A&;>B>81:=/852?97481CB=2=4+*)A)CBC/++@)%>.?''8C3C@######################### MD:Z:16A25T22T11 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:3 SM:i:37 MQ:i:29 OQ:Z:*((?<-?/?(:@4=6@*>C at 4@37@*>(8;@;7/9 at 1<72@;81<1@?>/?1*)(<)@B@/*+@))@.:'(1 at 2A?######################### UQ:i:35
+20GAVAAXX100126:8:43:10736:78356 611 chr1 10005394 60 35M66S = 10005705 411 TTGCCCTTAAGAGTCTTCGGTTCTCCACAGATAAGAGATTTGCTTTTGATATTTCCTCGACCTGCTCATAAGGATTTCATTATAACTTCTGGGTGCAATCT ?</3>################################################################################################ MD:Z:35 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:AA7>A################################################################################################ UQ:i:0
+20GAVAAXX100126:8:61:2951:38254 163 chr1 10005434 60 96M5S = 10005758 424 TGCTTTTGATATTTCCTCGACCTGCTCATAAGGATTTCATTATAACTTCTGGGTGCAATCTTTAGGAGAGTTTGCAAAACAGTCTTTTTTTTTTTTGTAAT @BBC??@ACCBCB at CDEC;CBDDCCDCCDCDCCCBBAABBBACCBBDCBD at CD>CCCDCB=CC;CD at ACC@DD?ABBBC@@ACACCDCADBCD at D###### MD:Z:96 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBCCCCCCBBBCCCCCCCCBCCBCCBCBCBBCBBBBBBBBBCBBBCBBBBBBB?BBBBBBCBB=BBB at AB@BB at BBA@@B?B?AB at AAAAAAABA###### UQ:i:0
+20GAVAAXX100126:8:21:9990:22806 163 chr1 10005457 60 72M29S = 10005782 425 GCTCATAAGGATTTCATTATAACTTCTGGGTGCAATCTTTAGGAGAGTTTGCAAAACAGTCTTTTTTTTTTTGTAATGGAGTTTCGCTCCGTCACCCAGGC @CCAABBCBCCCB at CCDBCCCDADCBECCCBCBCAB@C>BBCCDACCBCC at BC@CC?DCBADCBCC at CDCA############################## MD:Z:72 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCBCBBBBBCBBCCCBCCBBBBBBCBCBBBABBBABBBCBBBBBBBB?BABBBA at ACBBBBBBBBBBBBBB############################## UQ:i:0
+20GAVAAXX100126:8:6:21370:119926 99 chr1 10005465 60 97M4S = 10005757 389 GGATTTCATTATAACTTCTGGGTGCAATCTTTAGGAGAGTTTGCAAAACAGTCTTTTTTTTTTTTGTAATGGAGTTTCGCTCAGTCACCCAGGCTGAAGTT >743?<?A>@CCBDADD?DBC=?BBCDC?DDDCCCCA>=?DDB<?DDDACC=BDDDD>>>????>;;2>:=4A>@?D56>B2:>98</58A;?;A=##### MD:Z:82C14 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:>@/<CEFFEFHHGHHHHFHHHEEHHHHHFHHHHHHGGAEDHHH?EHHHHHHAHHHHHCCCEEEEE448A@?:DCECH;CCF64CC;@6;4D>DBD?##### UQ:i:25
+20GAVAAXX100126:8:1:6636:49601 147 chr1 10005477 29 35S66M = 10005102 -440 ATGATTCCTCGGGCTGCGCATAAGGATCTCCTTTGAACTTCTGGGTGGAATCTTTAAGAGAGTCCTCAAAACAGTCTTTTTTTTTTTTGTAATGGAGTTTC ###############################BC*89BA>=(29CACC?:+8'%BC54 at 21,-6%5'85=CB?<7%0>EEEEEEEEEEAACBCCBAA?CCB@ MD:Z:12C8G6T0T0G35 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:5 SM:i:29 MQ:i:29 OQ:Z:###############################?@);6 at A<;(.8BB at AA5+:'%?B54>/1+08,:(:4<BA=55%-:CCCCCCCCCCCCCCCBCCCBBBCB UQ:i:79
+20GAVAAXX100126:8:67:2948:89942 99 chr1 10005484 60 101M = 10005805 401 GGGTGCAATCTTTAGGAGAGTTTGCAAAACAGTCTTTTTTTTTTTTGTAATGGAGTTTCGCTCCGTCACCCAGGCTGAAGTGCAGTGGTGCAATCTTGGCT CCC:CCCDCBDDDCCCDCDC at DDBBCDDDACCBBCDDD@@AA at A@A>=BDCBCCCBDDA;BABC6BBCABBCACB=@BBA;A?;?CCCCBCCDCCDD at D@. MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHGHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHGGGGGGGGEAGHGHHGHGHHIHHEHHEGHHHHHHGHH=GFFFCFDBDHHHHIHHHHHHHGHG2 UQ:i:0
+20GAVAAXX100126:8:48:2299:12648 147 chr1 10005519 60 46S55M = 10005135 -438 TTTAAACTTTGGGGTTAAACTTTTAGGAGAGTTTGCAAAAAATTCTTTTTTTTTTTTGTAATGGAGTTTCGCTCCGTCACCCAGGCTGAAGTGCAGTGGTG ###############################################ACCBDCDDDA=3>C9A?<@CDC;ABCC;=BBBBC?EDAABABD=CB?B?A@=C? MD:Z:55 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:###############################################B at BBBBBBBB<5?B;BA at BBBBBAAABB=@A at AB=CCA at ACCC?CC at CAB??B? UQ:i:0
+20GAVAAXX100126:8:48:13575:23805 163 chr1 10005529 60 83M18S = 10005856 427 TGTAATGGAGTTTCGCTCCGTCACCCAGGCTGAAGTGCAGTGGTGCAATCTTGGCTCACTGCAACCTCCGCCTCCAGGGTTCAAGGGATTCTTGTGCCCCA @BABBBACCBACC>;BDBC;BABACABACBDCCDB;A<<B>ACA at BCBBA>?B at BC@C?BA at A=?B>@B9>CC?>A@<B46A################### MD:Z:83 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBBBAAABBABBBBBC at AABB@A?AABBABB=B??B?AB=BB@?A@@??AA?????B@?=@??@?@???@=??=?.5A################### UQ:i:0
+20GAVAAXX100126:8:3:12608:19745 585 chr1 10005617 23 35M66S = 10005617 0 TTCTTGTGCCCCAGCCTCCCAAGTAGTTGGGATTACAGGCGCGTGCCACCATGCCCGGCTAATTGTTGTATTTTTAGTAGAGGTGGGGTTTCACCATGTTG ##################################################################################################### MD:Z:35 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:23 OQ:Z:##################################################################################################### UQ:i:0
+20GAVAAXX100126:8:3:12608:19745 645 chr1 10005617 0 * = 10005617 0 AAAAAAAAGAGTCAAGGTAATTCTGAGGACTTAGCCTGCATAAATGACGTACGGATTTGCCTTCAAATTACAAGAAAAAGACTCTAAGATATTACATTGAA -C,BBACBB at 6>9<####################################################################################### PG:Z:BWA RG:Z:20GAV.8 OQ:Z:*@+ABCBAA=47;?#######################################################################################
+20GAVAAXX100126:8:46:11003:55063 99 chr1 10005652 60 101M = 10005971 396 CAGGCGCCCGCCACCACACCTGGCTAATTGTTGTATTTTTAGTAGAGATGGGGTTTTACCATGTTGCCCAGGCTGATCTCAACTCCTTTTTTTTTGAGACA CCBAC;CCB;BBCABCACABDBCBDCDCDBB@@@ACDDD at BCBCADCCCBCBC@ADDCABCCBCDBBBBCCBADBBCBCBCDAD at CDDDDDD?@@?D at DBE MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGFGHHHHGGHHHGHHGHHHGHFGHHHHHHHHHHHHHHHHGGHHFHHIHHHHHFHHHHHHHEGGCHDHHH UQ:i:0
+20GAVAAXX100126:8:43:10736:78356 659 chr1 10005705 60 101M = 10005394 -411 GTTTACCATGTTGCCCAGGGTGATCTCAACTCCTGTTTTTTTGAGACAGAGTCTCGCTCTGTTGCCCAGGCTGGAGTATAGTGGCATGATCTCGGCTCACT =@BA::A=C648=BD96>C'@4:(1?5:CD at CCA'3;*@?=C@=>C2<=>8BCD5>?B8@/9@/2@<+@?>CBAB=ACA79B@?@B=69A899BA?@4,?< MD:Z:0T18C14T66 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:3 SM:i:37 MQ:i:60 OQ:Z:=9@>2:>;B512BAB32<A)?36(0=2:?B?BB?*07)>=>C at 5=?-=9=>>BB8>A>9 at 2<A39A?*>=<A?@?=@B at 28@==?A8:;>75 at BA@>1';9 UQ:i:40
+20GAVAAXX100126:8:43:10431:27195 99 chr1 10005733 60 101M = 10006098 428 ACTCCTTTTTTTTTGAGACAGAGTCTCGCTCTGTTGCCCAGGCTGGAGTATAGTGGCATGATCTCGGCTCACTGCAACCTCTGCCTCCCGGGTTCAAGCGA CAC at CDDDDDDAAAADCCACCDCBBDB;AABCB at DBBBBACCBCBCAC@CCCCBBCBCCBC@@DB9CBBBB:@@@ADA at DBCCBCDBCC9??;?=>?<;6B MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHGGGGHHGHHHHHHHHHHGFHHHFHHHHHFHHHHHHFHFHHHHGHHHHHHGEFHHIHHGHFBDGFFHHFHHIHHHHHHHGDD<AA at A@@AD UQ:i:0
+20GAVAAXX100126:8:22:15343:70426 595 chr1 10005751 29 66S35M = 10005335 -450 GATTTTTAGAAACAATGGGGTTATAACCTGTTTCCCATGATAAACTAAACTCCTTTTTTTTTGAGACAGAGTCTCGCTCTGTTGCCCAGGCTGGAGTATAG ##################################################################################################### MD:Z:35 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:0 MQ:i:37 OQ:Z:##################################################################################################### UQ:i:0
+20GAVAAXX100126:8:6:21370:119926 147 chr1 10005757 60 3S98M = 10005465 -389 AGTCTCGCTCTGTTGCCCAGGCTGGAGTATAGTGGCATGATCTCGGCTCACTACAACCTCTGCCTCCCGGGTTCAAGCGATTCTCTTGCCTTGGCCTCCTG ####D:C>A;6A8BAACAEA7BBA9<>9>8:@@A6@@=8;1BB;CCA at CA:;->C4 at A7<BA at B3BB;A=<EACCD at 9@CEBCCCECA@@3BB1??*AAB= MD:Z:49G48 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:####AAB<<83B7B>>ABBB7A?@:9?;:39A<?:>>>6:0A??BB>ACA>8(:@0A at 7=BBAB6BBC@:=C>BCB?@@BC at CACCBCA>1@@1>@*@AA< UQ:i:12
+20GAVAAXX100126:8:61:2951:38254 83 chr1 10005758 60 101M = 10005434 -424 TCGCTCTGTTGCCCAGGCTGGAGTATAGTGGCATGATCTCGGCTCACTGCAACCTCTGCCTCCCGGGTTCAAGCGATTCTCTTGCCTTGGCCTCCTGAGTA B<CDDCDADCCCBCDCBCCCBDACCCDACBBBCCBCBCD;BBCDBBCCBBDBCCDCCBCCDCC;BBADDBDDB;BCDDCDCDCBCCDCBBCCDCCCBB at CC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHFHHHGHHHHGHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:21:9990:22806 83 chr1 10005782 60 101M = 10005457 -425 ATAGTGGCATGATCTCGGCTCACTGCAACCTCTGCCTCCCGGGTTCAAGCGATTCTCTTGCCTTGGCCTCCTGAGTAGCTGGGACTACGGGCACATGCCAT ADBBDCCCCCA9DCD;CBCDBCCCBBDBCCDCCB>C>CC;BBA at DBDDB;>CDDCDCDCBBCDCBBCCDCCCBDACDBCCBBBBCCB;BBBBCCCCCABCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GHGHHHHHHHG=HHHHHHHHHHHHHHIHHHHHHHDHCHHHHHHEHHHHHHEHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:67:2948:89942 147 chr1 10005805 60 20S81M = 10005484 -401 GTGGCATGATCTCGGCTCCCTGCAACCTCTGCCTCCCGGGTTCAAGCGATTCTCTTGCCTTGGCCTCCTGAGTAGCTGGGACTACGGGCACATGCCATCAT #####################@A=;@>=BB at AA5<@:@CA>=@ABC:<BC>CBCBC<CABBB<@>@@B?BDACBBB at CCB@>CB;CCABBBCCBBABBBC@ MD:Z:81 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:#####################?=<6?==@>A?=4?>?@BB?:?=?B=??B at BAB?B?AAABB?AAAAA=BBBB?BA=BBB<<BABBBBBABBBBBBBBBBB UQ:i:0
+20GAVAAXX100126:8:45:17313:6715 163 chr1 10005854 60 92M9S = 10006154 400 GAGTAGCTGGGACTACGGGCACATGCCATCATGCCCGGCTAATTTTTGCATTTTTAGTAGGGACGGGGTTTCACCATGTCGGCCAGGATGGTCTTGATCTC @BB@@AACBCCCACCA;CBBCACCBACCCBCCBBBB9BAABCCCACCCAC?CCADBBCBBACB at 9C>C at CBCD?BBAACA8=BBA<B:6<@########## MD:Z:92 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCBCBCCCCCBCBBBBBABBBBBAABBBBBBBBBBBBBABBBBBBBBAAABBBAAA?AAAB at B@A at B8AABBABB@A?A@=@A?6?766?########## UQ:i:0
+20GAVAAXX100126:8:48:13575:23805 83 chr1 10005856 60 101M = 10005529 -427 GTAGCTGGGACTACGGGCACATGCCATCATGCCCGGCTAATTTTTGCATTTTTAGTAGGGACGGGGTTTCACCATGTCGGCCAGGATGGTCTTGATCTCCT BDDCCDCCCBCCC;CCBCCBCCBCBCDBCCBCC;BBCCDCDDDDCBBCDDDDCDACCBBBB;BBBADDDBBCBCCAD;BBCBDBBCCBADCDCBCDCBCCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:43:16553:40365 99 chr1 10005967 37 101M = 10006358 425 TCTGTCTGCCTCAGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCTCACCCAGCCAAGTTAGTATGTGTTTAAAGATCACACTTGTAATCCTAGCA CBC at CBDCBBDBCCBBDBBBCDDC@BBDBCCDCDCACCCB;BBDCBBCABCBCABBCCBBCDCBDCCBCCBBBADDCADCDCBCACADDCCCDCCCDD>DE MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:37 MQ:i:29 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHIHHHHHFHHHGHHHHHHHHHHHHHHHHHHHHEHH UQ:i:0
+20GAVAAXX100126:8:46:11003:55063 147 chr1 10005971 60 23S78M = 10005652 -396 TGATCTCCTGACCTCGTGATCTGTCTGCCTCAGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCTCACCCAGCCAAGTTAGTATGTGTTTAAAGAT ########################@=@=8><>?C96A88@=?<*;;BAB67C;>;4?:2;B<7=A95C;B@,BCBCCCACDBDCEBCBCACADCA??CBC@ MD:Z:78 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:########################?;@>36>9<A;2?:4>>;<(:6>B at 6:A=672A89>B at 9@B<1B9?@)@BBACB at BBCBBCCBBBCCCCCCCCCBCB UQ:i:0
+20GAVAAXX100126:8:26:2983:65747 99 chr1 10005981 29 79M22S = 10006359 410 CCTCCCAAAGGGCTGGGATTACAGGCGTGAGCCACCTCACCCAGCCAAGTTAGTATGTGTTAAAAGATCACACTTGTAATCCTAGAACTTTGGGAGGCTGA 64911=?>?@*:=?>?@A@@:9==8'6==<=::<:@9>>=>>63;;<;<;<:<29@?6?:A;<A>;:;:;??=3>>=;####################### MD:Z:10T50T17 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:2 SM:i:29 MQ:i:29 OQ:Z:=9==84454404455FFFFF55445+444444554C:CAC??;7?55555555.5CC3CCG4 at GA44455CCC8AA??####################### UQ:i:35
+20GAVAAXX100126:8:61:18274:143796 163 chr1 10006062 60 92M9S = 10006396 429 CTAGCACTTTGGGAGGCTGATGTAGGAGGATCACTTGAAGCCAGGGGTTTGAGCCCAGCCTGGGCAACATAAAGATTACAGGCGTTAGCCACTAAGCCTGG >A:@?@?A?C?/>9A:AB;??:-7@@A<;B9<C69>1'<B8>8C.>>B;C7=A%?>@@B9(8C<;:?@@A/A8::57::=0,C1%%?>:C@########## MD:Z:53A31G6 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:2 SM:i:37 MQ:i:60 OQ:Z:;>;@CC@@<A at 1@;@;A>7;>7'5>??8:@79B79 at 2)?B<>8A4><>;@9==(99>;A8'5B=96 at A;@0:4:737;9<.0A5%%<<<AB########## UQ:i:8
+20GAVAAXX100126:8:62:16536:90438 99 chr1 10006082 60 101M = 10006385 337 TGTAGGAGGATCACTTGAAGCCAGGGGTTTGAGACCAGCCTGGGCAACATAAAGATTACAGGCGTGAGCCACTGAGCCTGGACCCTTCCCTCTCTTAATCT <<>5 at A>@>=<==<@<>7?=>=>=977=;<=:<;:;<<9:=;:::@A=??;<<=<<;99<=7:6<?74;?=8>5>A5:@:617/8>?;><=3?9<>?5>8B MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:23 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:FFDDFCACA>55544=<9<<DDAD=444544544455555>><<=CCCCC444444555445544C98>C><A9AG;=D<53534 at A?A>>7A<4 at C9A<D UQ:i:0
+20GAVAAXX100126:8:43:10431:27195 147 chr1 10006098 60 37S64M = 10005733 -428 CCTAGCACTTTGGGAGGCTGATGTAGGAGGATCACTTGAAGCCAGGGGTTTGAGACCAGCCTGGGCAACATAAAGATTACAGGCGTGAGCCACTGAGCCTG ######################################B:2A5>ACC;CA8>>@9A8C<B8>@@34BBBB at CCC?CD?7A:CA:@;B?BCBBBBABABBB@ MD:Z:64 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:######################################@74 at 16@AA at A@:;=>4@<@>A:@AA94B at AA@BBA>BB>0 at 6BA?A9BABBB?BBBBBBBAB UQ:i:0
+20GAVAAXX100126:8:3:10732:109401 163 chr1 10006103 60 101M = 10006447 444 CAGGGGTTTGAGACCAGCCTGGGCAACATAAAGATTACAGGCGTGAGCCACTGAGCCTGGACCCTTCCCTCTCTTAATCTGTTCAGGCTGCTATAACATAA @BBBABBAABCBA at CCCBCABBCACDADCCDDCCBAA;;BCB9 at 7>CCCC?AC at CCADCAB>BBB@?CBD:E@@@BBAAC<AB at BCCA?A=;A9==>D;D= MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BABBBBACCBBAABBBBBB>BAB at BBBCBBBBBBBAB@>BBBA;9=ABBBB at BAABCBB@A?AB?=BB?BCB>??BB@@A<??B at A@BB==6?68:<@9A9 UQ:i:0
+20GAVAAXX100126:8:48:11905:175240 163 chr1 10006103 60 81M20S = 10006478 475 CAGGGGTTTGAGACCAGCCTGGGCAACATAAAGATTACAGGCGTGAGCCACTGAGCCTGGACCCTTCCCTCTCTTAATCTGTTCAGGCTGCTATAACATAA =7 at AA>BBC<B>58CAABAD at C51BCACBBEDA906>;8=AB9@<CCCCA8>B:CCB@<C61 at 88<98CA at EC><;@9BC##################### MD:Z:81 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:<0@@@??AA9A;5>B@?B?B?B60 at ABBAACB@608C@;@ABA;?BABB>>=A<ABA99B62>729=8A>ABB>;;?9AA##################### UQ:i:0
+20GAVAAXX100126:8:46:19844:141004 99 chr1 10006137 60 95M6S = 10006468 401 TTACAGGCGTGAGCCACTGAGCCTGGACCCTTCCCTCTCTTAATCTGTTCAGGCTGCTATAACATAATACTGTAGGCTGGCTACAGAGGTTTTAAAATTTG CDC?CCCA;CBDCBBCADBDCBBD@=><=<@;<A@@=@BCDC;CBA:9 at 9<=79=BBDBC?AA@::<:99<;:8:)8<:6-+77:??;$A@@?:####### MD:Z:88T6 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHGHHHHHHHHHHHHHHHHGAAADDEBEGGEEEHHHHBHHFBBFB55555HHHGHEFHE==<=<<55445255552-554DA at .DAAA?####### UQ:i:3
+20GAVAAXX100126:8:67:19765:57485 163 chr1 10006149 11 101M = 10006437 382 GCCACTGAGCCTGGACCCTTCCCTCTCTTAATCTGTTCAGGCTGCTATAACATAATACTGTAGGCTGGCTACAGAGTTTTTAAAATTAGTATTTTTTTTTT @BBB?BACBBCD at BCACCDCBCCCBDBDCCDCBDB@A?BBCBDC?DCDCD?CD at DCBACB?BAACC=CA;:=93.:,3 at BB2B@A>B34;82ABB>DCBEC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:11 NM:i:0 SM:i:11 MQ:i:11 OQ:Z:BBBBBBBBBBBBABABBBBBBBBABBBBBBBBBBBABCBBBBBBABBBBBBBBBBAABAA?A at AB?@A?5<941,8'3<@@1=>>:>32280=@?;@>A at B UQ:i:0
+20GAVAAXX100126:8:45:17313:6715 83 chr1 10006154 60 101M = 10005854 -400 TGAGCCTGGACCCTTCCCTCTCTTAATCTGTTCAGGCTGCTATAACATAATACTGTAGGCTGGCTACAGAGTTTTTAAAATTAGTATTTTTTTTTTTTTTG <>A@??BA at B?CCD>CCCACDCDCDCDCCADA at DBB;CBAB at CDCAC?DCC at CCAC?B at C@@A@?=@;??>DDDDCDDDCDBA<:;?>>??>>>DDDBDCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:<DDDDAFFGFEHHHCHHHEHHHHHHHHHHHHEFHHHBHIGIFHHHGHFHHHEHHHHEHFHEGGFFAG=FDFHHHHHHHHHHGFA@=EEEEEEEEHHHHHHH UQ:i:0
+20GAVAAXX100126:8:22:5067:77679 1187 chr1 10006173 60 82M19S = 10006497 424 CTCTTAATCTGTTCAGGCTGCTATAACATAATACTGTAGGCTGGCTACAGAGTTTTTAAAATTAGTATTTTTTTTTTTTTTGAGACTGAGTCTTTCTCTGT @DBCAACCBDBACABCCBCB>BACBDACCABAB><;;7?@@A?C<=;;8>+665DC:0<?==B8@:2<CBA?CAC@=BD;@#################### MD:Z:82 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBBBBBBBBBABBBAB<?ABABBAB@@@A?=>?<AAA@@A?<8:7:+4,5A at 8-9<><@:>35;@@B9@@A?=@A;?#################### UQ:i:0
+20GAVAAXX100126:8:22:5084:77687 163 chr1 10006173 60 81M20S = 10006497 424 CTCTTAATCTGTTCAGGCTGCTATAACATAATACTGTAGGCTGGCTACAGAGTTTTTAAAATTAGTATTTTTTTTTTTTTTGAGACGGAGGCTTGCTCTGT @DBC?ACCBDBBCACCCBDB?BCAACACCCDBCA??>=?<@=;C5;@@983<::DDC;AA>A>3813ADBACC<@BBABC##################### MD:Z:81 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBCCCBBBBBBABBBBBBBB>?B@@ABBBBBABB at AA@A?A==B::>@832<4<BBB7???@<33+7 at A@B@@<?@@B?A##################### UQ:i:0
+20GAVAAXX100126:8:21:11247:101401 99 chr1 10006257 60 101M = 10006514 345 ACGGAGTCTTGCTCTGTTGCCCAGGCTGGAGTGCAGTGGTGTGATCTCGGCTCACTGCAAGCTCCACCTCCCAGGTTCACACCATTCTCCTGCCTCAGCCT CA:ADCCBDDBBDBDBBDBBBBCCCBDBCDCABBCCBBCBBBBDCBCB;CBDBCADBBC??BDBCCABDBBBCCCCDBCACACCCDBDBCDCCCDCDDCB8 MD:Z:39C61 PG:Z:BWA RG:Z:20GAV.8 AM:i:23 NM:i:1 SM:i:23 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHEEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHI5 UQ:i:33
+20GAVAAXX100126:8:46:8850:165700 163 chr1 10006281 29 101M = 10006624 443 GCTGGAGTGCAGTGGTGTGATCTCGGCTCACTGCAAGCTCCACCTCCCAGGTTCACACCATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGACTACAGGCG @BBAABB at BBCC?ACACACCDBDB;CADBCADBB at AAA@ABB?BBBCCBCA?D?CAC?BC<CABBC?B>CBCD?AB?;BB6?C:9ACB?@7@=AA?B<>73 MD:Z:15C85 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:1 SM:i:0 MQ:i:37 OQ:Z:BBABBBB>BBBB at CC?C=CBCBBBBBABBABBABAABBABBAA?BBBBAAB>AAAAB>AA>BAAAB at A;BBBB?AB=;@B==A39>A??=9=;>>@>4=26 UQ:i:32
+20GAVAAXX100126:8:43:16553:40365 147 chr1 10006358 29 66S35M = 10005967 -425 GTGGTGTGAGCGCGGTTCACTGCAAGCCCCACCCCCCAGGTTCCCACCATCCCCCTGCCTCAGCCTCCCGAGTAGCTGGGACTACAGGCGCCTGCCACCAC #############################################################################BA:8:8::2B420 at B@ABA at BBC@ MD:Z:35 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:0 MQ:i:37 OQ:Z:#############################################################################@@727537. at 8<. at A>ABB>BB at B UQ:i:0
+20GAVAAXX100126:8:26:2983:65747 147 chr1 10006359 29 68S33M = 10005981 -410 AGGTGCTTGAGCCCGCCCACATGCACGCTCCACATCCCGGTTGCACACCGTACCCCTCCCTCAGCATTCCGAGTAGCTGGGACTACAGGCGCCTGCCACCA ############################################################################################BB@?;7=@? MD:Z:33 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:0 SM:i:29 MQ:i:29 OQ:Z:############################################################################################BB@@70>=> UQ:i:0
+20GAVAAXX100126:8:62:16536:90438 147 chr1 10006385 60 66S35M = 10006082 -337 CCCTCCTCCCAGCTTCACTCCTTTCTCCTCCCTCAGCCTCCCGAGTAGATGGGACTACAGGCGCCTGCCACCACGCCGGGCTAATTTTTTTATTTTAGTAG #####################################################################B4,B3?$6;63ACC at 9@DBDA;9?8C5?1:D@ MD:Z:35 PG:Z:BWA RG:Z:20GAV.8 AM:i:23 NM:i:0 SM:i:23 MQ:i:60 OQ:Z:#####################################################################?5+ at 5>(:742 at BB>6>BBC?=6<5B6;1;CB UQ:i:0
+20GAVAAXX100126:8:61:18274:143796 83 chr1 10006396 60 5S96M = 10006062 -429 ACGCCGGGCTAATTTTTTTATTTTAGTAGAGACGGGGTTTCACCATGTTAGCCAGGATGGTCTCGATCTCCTGACCTCGTGATCTGCCGGCCTCGGCCTCC ######?9AB><<<=@<<A at B;>>@==B at B4;59*:@AB?A8;;;=>?@A>7.=,;2;=88<:4;<6<<=:;95:=:8>A?>>==;/7=/:@<7</:7=71 MD:Z:96 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:######D=FGBB>>BAB>GDG<ADDDDFGF7544,5GGFAG:>@=@FDFFD5/5.57 at A@845554;?<?@@@3<<BFFFF445558<>2=4555044555 UQ:i:0
+20GAVAAXX100126:8:23:12774:197414 99 chr1 10006420 60 101M = 10006790 437 AGACGGGGTTTCACCATGTTAGCCAGGATGGTCTCGATCTCCTGACCTCGTGATCTGCCGGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCA CCC?;CCCCDDBCABCCBBDCCBBCCCDCBCBBCB;CCBCBBCBDABDB;BBDCBDBBB;CBBDB;CBBDBBBCDDCABBDB>CDCDCACCCC;CCDDCDA MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:23 NM:i:0 SM:i:23 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHEHHHHHHHHHHHHHHHHHG UQ:i:0
+20GAVAAXX100126:8:67:19765:57485 83 chr1 10006437 11 1S18M3I77M2S = 10006149 -382 CGTTGGCCAGGATGCTCTCGTGGATCTCTTGACCTCGTAATCCGCCCACCTCCGCCTCCCAAAATGCTGGGGTTACAGGCATGAGCCACTGTGCCCGGCTT <BEDCCD at DCC@CBCD;B9 at BCBCDCDCDCB=CCB6ACDCCC;BCCBBCCDC;BCCDCCBDDDCCBCCBBBADCBBDBBBCCBDBCBBCCACBCC;C at BDC MD:Z:3A9G10C9G3T3G0G4G10G7A8G8C0A0C7 PG:Z:BWA RG:Z:20GAV.8 AM:i:11 NM:i:17 SM:i:11 MQ:i:11 OQ:Z:HHHHHHHGHHHDHHHHBFGGFHHHHHHHHHH>HHFEHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:456
+20GAVAAXX100126:8:3:10732:109401 83 chr1 10006447 60 101M = 10006103 -444 ATGGTCTCGATCTCCTGACCTCGTGATCTGCCGGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCACGCCCGGCCTAAAATTAGTATGTT =ECBDC=4@=B;5>>=B at CCB9AC@BDCCBC;BBCCD;BBCCACBBDDDACBCBBBBCACBBDBB;?CBCBCBBCBB;BCC;BBCCCDDDCDCDACCA at DC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:@HHHHHCBFBD?9AA?HDHHEGHHGGHHHHHHHHHHHHHHHHEHGHHHHHHHHGHHHHGHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:46:19844:141004 147 chr1 10006468 60 30S71M = 10006137 -401 TGAGCCAGGTTGGTCTCGATCTCATGACTGCGTGATCTGCCGGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCACGCCCGGCCTAAAAT ###############################?9<'@A<:=9>8@:>;7C632<83.1;A=;000-8*?<B at 4@<-8B>;&9A>>BA9>>86>?CA;B at A>@ MD:Z:71 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:###############################@4<&<?<9=A<7=78A9B92.=7.036B>>0032;+==?@0=907A;6(9 at 6=BB at A@8=;=B@=@?@;@ UQ:i:0
+20GAVAAXX100126:8:48:11905:175240 83 chr1 10006478 60 101M = 10006103 -475 CGGCCTCGGCCTCCCAAAGTGCTGGGATTACAGGCGTGAGCCACCACGCCCGGCCTAAAATTAGTATGTTTTTTGTTGTACTTGTTTTTGTTTTTGTTTTT /8,)09:AABA<>B>ADDACBACCB>AD>BBBBB9ACBDB>B at CBA;B at C;BB at BCD@DCDCDAC??<>??DDBADCACB>?@<???>?<?AAAAADBDDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:551215FGGGGBEGAGHHHHHFHHHDGHEHHGHHGHHHHHDHDHHEHHFHHHHFIHHFHHHHHHHEEEEEEHHGHHHHHGEEEEEEEEEEECCCCHHHHHH UQ:i:0
+20GAVAAXX100126:8:22:5067:77679 1107 chr1 10006497 60 101M = 10006173 -424 TGCTGGGATTACAGGCGTGAGCCACCACGCCCGGCCTAAAATTAGTATGTTTTTTGTTGTACTTGTTTTTGTTTTTGTTTTTTTTTTGAGGCGGAGTTTCA 7D>DCCCBDCC at D>C;ABBCBCBCCBB9BCC;BBCCCDDDCDCDACBB?ABADDCADCAC9@@B?A@@AB at AAAAB?AAAADDDDDCBDBB;BBDADBCBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:5HEHHHHGHHHGHEHHHGHGHHHHHHHGHHHHHHHHHHHHHHHHHHGGGGGGHHHHHHHHBGGGGGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:22:5084:77687 83 chr1 10006497 60 101M = 10006173 -424 GGCTGGGATTACAGGCGTGAGCCACCACGCCCGGCCTAAAATTAGTATGTTTTTTGTTGTACTTGTTTTTGTTTTTGTTTTTTTTTTGAGGCGGAGTTTCA *@DBCCCCDCCCDCC;ACBDBCBC at BB;A@@:BACCC?DDCDCDACBB?ABADDCADCACB@@B?A@@AB at AAAAB?AAAADDDDDCBDBB;BBDADBCBC MD:Z:0T100 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:2GHGHHHHHHHHHHHHHHHHHHHHFHHHFFFIHGHHHEHHHHHHHHGGGGGGHHHHHHHHHGGGGGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHH UQ:i:9
+20GAVAAXX100126:8:21:11247:101401 147 chr1 10006514 60 12S89M = 10006257 -345 GGATTACAGGCGTGAGCCACCACGCCCGGCCTAAAATTAGTATGTTTTTTGTTGTACTTGTTTTTGTTTTTGTTTTTTTTTTGAGGCGGAGTTTCACTCTT #############@@A6 at A@>@;@@A:A at C<BBC at CDBC??BC at CDD;CC?CCAB6?CCAC=BBA;CDDDCADDEDDEEEEDCDDC;ABDACDAA@?BBD@ MD:Z:89 PG:Z:BWA RG:Z:20GAV.8 AM:i:23 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:#############?:=7 at 9?>>B@?@AB=@>A>BAABBA@@AB at ABA=ABBABBA1AABBB?BBB at BBBCBBBBCBBCCCCCCBCCBBCBCBCCB@CBBCB UQ:i:0
+20GAVAAXX100126:8:46:8850:165700 83 chr1 10006624 37 101M = 10006281 -443 TGGCGTGATCTTGGTTCACCACGACCTCTGCCTCCCGGGTTCAAGCGATTCTCCTGCCTCAGCCTCCTGAGTAGCTGGGACTACAAGCATGCACCACCATG EDC;ADCCDADBA at ACB@CBC;BACCDCCBCCDCC;CCADDBDDB;?CDDCDCCCBCCDBDBCCDCCCBCACDBCCBBBBCCBBDDBBCCBBCCCCC at BCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:37 MQ:i:29 OQ:Z:HHHHHHHHHGHGGGGFHDHHHHHFHHHHHHHHHHHHHHHHHHHHHHFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:22:6227:26566 163 chr1 10006730 60 83M18S = 10006988 358 CTAATTTTGTATTTTTAGTAGAGACAGAGTTTCTCCATATTGGTCAGGCTGGTCTCGAACTCCCGACATCACGTGATCCACCTGCCTCAACGTCCATAAGG @DBC@?BBBBCCBBCCCCADCCCCBCBCCBCCBDABAB9BBA?@?@@?A??=;7=?39@?81AA886:?>:>3687':A@?A################### MD:Z:83 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCBCCBBCACBCBBBBB;CBBBACBABB?BBBBBBBB>BBA@;A?<=A:A>2:6;83>?7/?A=5<9<<:;5/55(:=?@?################### UQ:i:0
+20GAVAAXX100126:8:2:2951:16973 99 chr1 10006763 60 101M = 10007005 342 TCCATATTGGTCAGGCTGGTCTCGAACTCCCGACATCACGTGATCCACCTGCCTCAACCTCCAAAAGGGCTGGGATTACAGGTGCGAGCCACCTCGCCTGA <<>7A<BA at BB@B;=;?=8==?<5 at A?C at AA9B?:=9@<49;6:<<786;??=@=CA at ACABBAA:;'69<;55:BAA?B@?<;95<:91178;::?A@:B MD:Z:67T33 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:GGGCGEGGGGGGGBE55555EDEEEGGGGGGGGGB?@DD?;=;@<=;=;@CEEEEGGGGGGGGGG44/4455544GGGGGCC??@<===824444GCGE=G UQ:i:6
+20GAVAAXX100126:8:1:16535:116063 99 chr1 10006767 60 101M = 10007127 436 TATTGGTCAGGCTGGTCTCGAACTCCCGACATCACGTGATCCACCTGCCTCAACCTCCAAAAGTGCTGGGATTACAGGTGCGAGCCACCTCGCCTGACCAA CCBBCCCBCCCBAB@@BDB;DDA?BBB;DACCBCA5 at BACBBCABC>BBCBCDABDBBADDD>:BBDB at CCCD@AACCC=B4BCBCCACDC;CCDCDBC<6 MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHCHFEHHHHHHHEHHHHHHHHHHHDFHFHHHHHHHEHHHHHHHHHHHFHHHECHHHHFHGHHFHEHHHEHBFHHHHHHHHHHHHHHHH at 5 UQ:i:0
+20GAVAAXX100126:8:23:12774:197414 147 chr1 10006790 60 33S68M = 10006420 -437 AGTTTCTCCATATGGGTCAGGCTGGTCTCGAACTCCCGACATCACGTGATCCACCTGCCTCAACCTCCAAAAGTGCTGGGATTACAGGTGCGAGCCACCTC ##################################<?7:=@1/:;59/1>'@@3DB:?CA@@A9BA=BBCCCDACABACCABDABACC<<A:BDABA at BBC@ MD:Z:68 PG:Z:BWA RG:Z:20GAV.8 AM:i:23 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:##################################?=<;6?1,7596+1:(A=,B?:AAA at AA:BB?BABBBBBAAA?BBAABAAAABA=AABBABB>BBAB UQ:i:0
+20GAVAAXX100126:8:21:7822:20748 163 chr1 10006812 60 83M18S = 10007120 408 TGCCTCAACCTCCAAAAGTGCTGGGATTACAGGTGCGAGCCACCTCGCCTGACCAAGTTAGTATGTGTTTAAAGATCACACTTGTAATCCCAGCACTTTGG @=5AA>>A:AA>=7:C?4 at A@A>CC?;A:;A@;=7<+77:>C?C at 5.A:B(4 at .+**@@><;BA<61ADC8:@;A7;AA<@A################### MD:Z:83 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:@86@??:@9?@<?:5A;08@@>;BB;8?7;?><88 at 59;>?BAAA50 at 9>(3@/)()6>=>7AA9-0BBA:3<;?5<BB;B?################### UQ:i:0
+20GAVAAXX100126:8:68:20656:34221 163 chr1 10006818 60 101M = 10007102 384 AACCTCCAAAAGTGCTGGGATTACAGGTGCGAGCCACCTCGCCTGACCAAGTTAGTATGTGTTTAAAGATCACACTTGTAATCCCAGCACTTTGGGAGGCT @D at BBAB>CCCC?ABDBCCCCCCACCB at BC;CCB at B=BCA9ACD at CACACA@C at CCCDBAAACBBD@ACA4CA?@@B at BA@AB@@CCA?@AAA at C*ACA:A MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBB>ABBB at BBBBBBABBBBBBA<ABBABAABABBBAABABABB at AB?BBB at BBA=B?AAAAA at A@3?A?B>B@=A?A@>>@@@?@??=?@-<=A4< UQ:i:0
+20GAVAAXX100126:8:1:4286:192808 99 chr1 10006849 60 101M = 10007174 425 AGCCACCTCGCCTGACCAAGTTAGTATGTGTTTAAAGATCACACTTGTAATCCCAGCACTTTGGGAGGCTGATGTAGGAGGATCGCTTGAGGCCAGGTGTT <<;:A:<DB5BBDBD<B at A=BA?A?CCBCBBDDAD<@5@?=>??BDBBCDC=BAC?BCA?DDB>>?ABABBACBB>><:=CDCB;@ADCDC?@CDA=;?A5 MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GGEGGEDHHEHHHHHEGCGDGGCGEHHHHHHHHGHBF9FF=CDGGHHGHHHEHGHEHHHDHHHEECGGGGHEHHHAA?=AHHHHHEEHHHHDEHHGBBGG4 UQ:i:0
+20GAVAAXX100126:8:63:5666:148033 163 chr1 10006932 60 101M = 10007256 424 CGCTTGAGGCCAGGTGTTTGAGACCAGCCTGGGCAACATAGGGAGACCCTGTCTCTACAAAAAATACAAAAATTAGTTGGGTGTGATGGTTCATGCCTGTA @;BCAABBCBCCBBABABCBCCABCCBCCCBCCBBC?BBBBBCCA?ACCC@>BACD>ACBBBCBBA>BDCACBB at B:BBB;9A>ADCA at C?AC?B?CD at B@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBBBBBBBBB;BBCBABB>CBBABBAAAABBBBBBBBABAB>AAB?B=?ABA>BA at A@AAA at B@A@@@@A at A7A@A<3>9 at AA@A>>?A>@B@>@9? UQ:i:0
+20GAVAAXX100126:8:62:2555:107007 99 chr1 10006969 60 101M = 10007301 421 ATAGGGAGACCCTGTCTCTACAAAAAATACAAAAATTAGTTGGGTGTGATGGTTCATGCCTGTAGTCTCAGCTACTCAGGAAGCTGAGGTGGGAGGATTAC CCCACCDCDABBDBBBDBDCACDDDAABA?CDDD at BDCCBDBCC@B at BDCBCBDBC@BBBDBCCCCBDBCCBDCADBCCCCDCBDBDAC=CC?DCD?B<DB MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHGGGGGHHHHGGHHHHHHHHFHEHHHHHGHHHFHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHGHAHHEHHHAFBHH UQ:i:0
+20GAVAAXX100126:8:22:6227:26566 83 chr1 10006988 60 101M = 10006730 -358 ACAAAAAATACAAAAATTAGTTGGGTGTGATGGTTCATGCCTGTAGTCTCAGCTACTCAGGAAGCTGAGGTGGGAGGATTACTTGGGCCCAGGAGGTCGGG =?@?DDDCBBCDDDDCDCBADCBCACACBCCBADDBCCBCCCACDADCDBCBCCBCDBCBBDDBCCBCBACBBBDBBCDCCCDCBBBCCBDBBDCAD9BBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BGGEHHHHGEHHHHHHHHFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:2:2951:16973 147 chr1 10007005 60 101M = 10006763 -342 GAGTTGGGTGTGATGGTTCATGCATGTAGTCTCAGCTACTCAGGAAGCTGAGGTGGGAGGATTCCTTGGGCCCAGGAGGTCGGGGCTGCAGTGAGCCAGTG #E38>AC1 at 9?A8 at C1CB@4?<@%1:<9@@7?>C<CB@>CACCC*BB9C?;;0BC@@A?799>#7)6ACBBA66CBDC<(-A?B=AB96<;BBAAAA@@C@ MD:Z:0T22C39A37 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:3 SM:i:37 MQ:i:60 OQ:Z:#?219@>1;9>>8>A. at A;2><<%/;=7 at 97;9A?BAB=BAABB*=?<B?=70 at A?B<?9<;@(<'5 at ABA@10BBBB;'1><?;@A=75>AB at CAA=BBA UQ:i:8
+20GAVAAXX100126:8:46:18774:97831 163 chr1 10007015 60 79M22S = 10007344 429 TGATGGTTCATGCCTGTAGTCTCAGCTACTCAGGAAGCTGAGGTGGGAGGATTACTTGGGCCCAGGAGGTCGGGGCTGCAGTGAGCCAGTGACCATGCCAG @CCB?B at BBCCBBBDBBCCBBDBCCBCCADBBBC?AAA at A?AC=?CCACC=?C==CB@;A>AB=AA6 at B8>;?<>@??####################### MD:Z:79 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCBBCBBBBBBBBCBBABBABBBBBBABBBBAAB at ABBAB@AB6ABA=BA??@@;?@<;@?@A=@?7?@4??==>?=?####################### UQ:i:0
+20GAVAAXX100126:8:24:7834:75053 163 chr1 10007028 60 64M37S = 10007352 424 CTGTAGTCTCAGCTACTCAGGAAGCTGAGGTGGGAGGATTACTTGGGCCCAGGAGGTCGGGGCTGCCGTGAGCCAGTGACCATGCCAGTATACTCCAGCCC @DB at AA@ADACCBCC>CAABCBCBADBBCC<ACC?BA9?>@?BB7<DA at C>BB:CB9<80:C@###################################### MD:Z:64 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBBABABBBBB at AA?AB at AAABB@BB6 at BB@BB;A at AAA@:=B??A at A?<A at 57>3=B?###################################### UQ:i:0
+20GAVAAXX100126:8:68:8790:55871 163 chr1 10007049 60 96M5S = 10007343 394 AAGCTGAGGCGGGAGGATTACTTGGGCCCAGGAGGTCGGGGCTGCAGTGAGCCAGTGACCATGCCAGTATACTCCAGTCCTGATTACAGAACAAACCCCTA >=<1?;B>:&0B1'253=B8>=3:5A<3=*?.>=15255%><;=78;CB<6&?@@B<59B<855(C<?<A9:<2'*44A==6B(-D?>;D?@<AD###### MD:Z:9T67C18 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:2 SM:i:37 MQ:i:60 OQ:Z:;9;1;;@=9(5 at 5(.80:@7?8255@:09*>1;;5/5@;+@>;9;77 at B75(;A<B909?=716(@?=9@;651()2,@<;3>(-B>C;A>A6BA###### UQ:i:24
+20GAVAAXX100126:8:68:20656:34221 83 chr1 10007102 60 101M = 10006818 -384 AGTGACCATGCCAGTATACTCCAGCCCTGATTACAGAACAAACCCCTATCTCAAACAAACAAACAAGTACATAAATGAAAGAAAGTTTGTGTTCCTACCAC =BDCCDCCCCCAB?@>@ACDCBDBCCCCBCDCC at D@DCBDDACCCCCCDCD at ADBA@DBBDDBBDCACBBCCDDCC at ADD@DDDADDCACAADCCCCABCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:>HHHHHHHHHHFFFFBFFHHHHHHHHHHHHHHHGHFHHHHHFHHHHHHHHHGGHHGGHHHHHHHHHHHHHHHHHHHGGHHGHHHHHHHHHHGHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:21:7822:20748 83 chr1 10007120 60 101M = 10006812 -408 CTCCAGCCCTGATTACAGAACAAACCCCTATCTCAAACAAACAAACAAGTACATAAATGAAAGAAAGTTTGTGTTCCTACCACAGGTGTGTCCAGTGAGAA >)49;7%9;<;0:?9 at B9>A?990555;8:945;8?@:;AA><<:=;7;?9=<;<;;49;>;1@>A><AA>?:<>;=>:??5<<=<A<@>A?=A>9;7==< MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:C+5554.=>=>3<C;CF=CFC4504454444885:CEBBFFC<<;A=:?C744445>6@@EB6FDFF?FFFC?<C at ACCCC7?=A?F?FFFFEFFBEEFFF UQ:i:0
+20GAVAAXX100126:8:3:4038:181802 1187 chr1 10007126 60 99M2S = 10007427 401 CCCTGATTACAGAACAAACCCCTATCTCAAACAAACAAACAAGTACATAAATGAAAGAAAGTTTGTGTTCCTACCACAGGTGTGTCCAGTGAGAAGAGTGT @DCC??BABACCCBBDEEBDDDDDDCECDDEBCAB@>B@=ACAB;ADDADBACADDADDB<AC;CB?BDAADC;AB at BB=@8C8ACCB5C?@BB?@8C### MD:Z:99 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCCCCCCBCBBBCCCCCCCCCBCCCCCCBCCC?CBCBCCCBCACBCBABBCCBBBCAB at CBBCBBB@B?A?B>@BBACCBC at CBACBC@B=?@9>3?### UQ:i:0
+20GAVAAXX100126:8:3:4050:181815 163 chr1 10007126 60 101M = 10007427 401 CCCTGATTACAGAACAAACCCCTATCTCAAACAAACAAACAAGTACATAAATGAAAGAAAGTTTGTGTTCCTACCACAGGTGTGTCCAGTGAGAAGAGTGT @CCCABBABACCCBADDDBDCCDCDCDCDDEACDC at ABB@BCBBAACDCD>CCADDCCDBBBCBCC?BDBAEC?BB@@BBB at CABCDB>C77B at A>1C?D? MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBCCBBBCBBBBBCBCBBCCBBBBCCBCCBCBBBBBBBBBBBB at BBBBBB@BBBBBB at B@B at BBBAB@BBBBBBBAB?CB@@AB at BBAB@C4@>;;-?<B9 UQ:i:0
+20GAVAAXX100126:8:1:16535:116063 147 chr1 10007127 60 24S77M = 10006767 -436 GTGACCATGCCAGTATACTCCAGCCCTGATTACAGAACAAACCCCTATCTCAAACAAACAAACAAGTACATAAATGAAAGAAAGTTTGTGTTCCTACCACA #########################@=<6?;A?A8A9':>9>5BA<@:@;=CC at 61<B?@;57A<79<?B?BC>>>CC=9BCCADC?<:4<?BBA<@A<B@ MD:Z:77 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:#########################?;>28>=;?;?4'8=7=6?@9<<<:@BB<11?>@@=3;A@<=6>A?@B<:<AB95 at BABBA;A<2;;@BA:?A9BB UQ:i:0
+20GAVAAXX100126:8:48:10097:181097 1699 chr1 10007155 29 92M9S = 10007512 383 AACAAACAAACAAGTACATATATGAAAGAAAGTTTGTGTTCCTACCACAGGTGTGTCCAGTGAGAAGAGTGTGATGTTGCAGTTGAGAGGGGGTAAATGCT 18246))A339B36AC?C>3*?>;=?3BAEEAA=<<26:35//C029A0A&4::A9</+*@@<:(*<5BA:CB(:@7AB'*@-CA at BB;3@########## MD:Z:20A61A9 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:2 SM:i:29 MQ:i:29 OQ:Z:,3202(*@//;A47;B?B<2*?;89<0A>CC at B;>?59=672-B444A-=+-49=/:,))@?9:'(?3?BC@?)9?CBC**?)A@:CB<3@########## UQ:i:21
+20GAVAAXX100126:8:48:10108:181079 163 chr1 10007155 60 101M = 10007444 389 AACAAACAAACAAGTACATAAATGAAAGAAAGTTTGTGTTCCTACCACAGGTGTGTCCAGTGAGAAGAGTGTGATGTTGCAGATGAGAGGGGATAAATGCT @D at BBA@BCDACCAACACDCDDCCCDDCCDDCBC at A>A at BBCDC?CCACC at AB>CBBCCC at BBBCD?AC?@CC at BA?BBA at ABABCBB?C at AB?BBCB at DA MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCBBBCBCBCBCBCBBBBCBBBBCBBBBABBB at BCBABBBBBBBBBBBBBA@A?BABBBB at B@B at AA?B8B>A?AA>@@B?B>@A???@@?@>>@@?>@A> UQ:i:0
+20GAVAAXX100126:8:48:10118:181094 1187 chr1 10007155 60 101M = 10007444 389 AACAAACAAACAAGTACATAAATGAAAGAAAGTTTGTGTTCCTACCACAGGTGTGTCCAGTGAGAAGAGTGTGATGTTGCAGATGAGAGGGGATAAATGCT @D at BBB@BCCACCABCACCCDDCBCDDCCCDCACBA>A at BBCDC=BCABC@<C>CBBCCC?BABB?@@C@@CCABABBCA at ABABBA<@B at A>A@<=C at CB MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCBBBBBBBBBBBB?BBBBBBBBBBBBBAABBBBBBABBBBBBBAABBABA8B at BABBAB?B?B?;B>A;B>B at BB@@BA?A>@A>>8A?@?9@=87??@? UQ:i:0
+20GAVAAXX100126:8:1:4286:192808 147 chr1 10007174 60 101M = 10006849 -425 AAATGAAAGAAAGTTTGTGTTCCTACAACAGGTGTGTCCAGTGAGAAGAGTGTGATGTTGCAGATGAGAGGGGATAAATGCTGGACCAAAGTCCTTGAGAA =DADBADAB+ at D8CDC:.;>6A?3:>'?@DA@;;@ACBBD9BBE at DE?A at AAACDC:DCBB at A@>?BCDB5=ADCBCBB@@CCC?CC?BDACA?CBACB<@ MD:Z:26C74 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z::?AAA?BBB+?@;BB?:+8=5@;37>(><@AA6<BBBBBB=@AC at ACA<ABBCBCBCBBBBCBCCCCCCA4;?CB at AA@??BBCCCCACCCB??BBABB5A UQ:i:6
+20GAVAAXX100126:8:3:11681:100672 163 chr1 10007181 60 101M = 10007491 410 AGAAAGTTTGTGTTCCTACCACAGGTGTGTCCAGTGAGAAGAGTGTGATGTTGCAGATGAGAGGGGATAAATGCTGGACCAAAGTCCTTGAGAAGGTGAGA @CCCBABBCBABABCDDDBDCACCCBBBCBBCCC>A?B>ABBBB at ACDCC?CC at CCADCBB@CBBC=ABCBCC?@ABBA;ABCB?8CCACAAA>BB at CAD@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBABBBBBBBCCBCCCBBBCB at B?BABBBB at BAB@ABAB>B at BBBBBBBB@B?BB at B>BB at A?@A at AAB@>BABA;@B?A;3?BAA?@;<>A6@>@= UQ:i:0
+20GAVAAXX100126:8:7:7502:151389 1187 chr1 10007181 60 101M = 10007491 410 AGAAAGTTTGTGTTCCTACCACAGGTGTGTCCAGTGAGAAGAGTGTGATGTTGCAGATGAGAGGGGATAAATGCTGGACCAAAGTCCTTGAGAAGGTGAGA @CACB?8AABABA at CDECBDCACCC@B?CBCCCC;A7=:+;;9??;C at CC?CB=DCCDCC?5ABCA6>BC?@B;8=<9 at BBBDB?C@;@B9B>1ABCC?>@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCCB at .@CCAABCCCCBCCBBBCB<B9CACBBB<B;@=+=<:8A9B<BBAA?@BBABBB at 4@BB?7>A@?:@<4<=C at BAB@A:A;6@?7A9.<A>@;6< UQ:i:0
+20GAVAAXX100126:8:24:17458:9144 163 chr1 10007190 60 101M = 10007539 449 GTGTTCCTACCACAGGTGTGTCCAGTGAGAAGAGTGTGATGTTGCAGATGAGAGGGGATAAATGCTGGACCAAAGTCCTTGAGAAGGTGAGAGAGAAAGGA @AB at A@BCBACCABCCBBBBBCDBCABCCCDCB?9A;@@@B@@A at ACC@A>BCACBBCACBBA?AC=@DA;CCBB>A at D92=BA at BA8?C>@A?CBCD at CA MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBCBBBBBCBBBB at B@BACCAB?BABBBB@=7B?AAAB@@@B at BA@@@A at BA@A@@BB@@@?@@?BB<@@AA:A?@9/;@?=@>5@?====@?>@>>> UQ:i:0
+20GAVAAXX100126:8:45:16821:90529 1187 chr1 10007194 60 101M = 10007535 436 TCCTACCACAGGTGTGTCCAGTGAGAAGAGTGTGATGTTGCAGATGAGAGGGGATAAATGCTGGACCAAAGTCCTTGAGAAGGTGAGAGAGAAAGGAGAGA @BCCA?BBACCC?ABC?BDCCBBCCCDC>C9CBC?B>=7ABBB=ABACBC9=A@@CD??>AC at 8CA;CBD?C@&=B at BA<BAA89?9@?@@?*>BBA>;:D MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBCBBCBCCBBC at C?CCBCBBABBBBBC9C5B at B@BA>;BBAB9BB=BAB=>>A<BB9><BA@:BB>B>B?>=':B at A=:@@=/683=?:@<(<=A<663B UQ:i:0
+20GAVAAXX100126:8:45:16833:90513 163 chr1 10007194 60 101M = 10007530 436 TCCTACCACAGGTGTGTCCAGTGAGAAGAGTGTGATGTTGCAGATGAGAGGGGATAAATGCTGGACCAAAGTCCTTGAGAAGGTGAGAGAGAAAGGAGAGA @CCC@?BBACCC=AABABDCC at BCCCDCCCBCACBBA@@?BBB@?BCC at BABB@?<BB?>@=B?AA>CDDAC at +>BABC?>AC8=>@2<C?BABAACC;DD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCBCCCCCBBB>BBBBBCBB<BABBBB at B@B?BBBBAAABAB<AB at B??BA at A:9@=><A;B?CB at BABB@>+;BAAB>=A at 5;7;/=?B@<A;@?@7 at B UQ:i:0
+20GAVAAXX100126:8:43:20013:129172 163 chr1 10007196 60 97M4S = 10007463 367 CTACCACAGGTGTGTCCAGTGAGAAGAGTGTGATGTTGCAGATGAGAGGGGATAAATGCTGGACCAAAGTCCTTGAGAAGGTGAGAGAGAAAGGAGAGAAA @DB at AB@BBC at BAABBB?BBBCCCDCCC at CACCCB@?AA at B@AC=BCCCC@@B?DCAC at B?AC=BC=?B?@BD<<>AAC>A=C>ABC<?B>=CABA##### MD:Z:97 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBCBBBCBBB at BBB>BA;AABBBBBBAB8B?BABBAABBAB at AB?A?BBAA?@AA@@A@?@@B?@B?=?9B=A<;<A?@>@9A<?>@8@>=:A?=@##### UQ:i:0
+20GAVAAXX100126:8:27:21458:11536 629 chr1 10007225 0 * = 10007225 0 NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNTNAAANTGTTAANNNNNNNNNNNNNNNNNNNNNAGTN ##################################################################################################### PG:Z:BWA RG:Z:20GAV.8 OQ:Z:#####################################################################################################
+20GAVAAXX100126:8:27:21458:11536 697 chr1 10007225 37 16S85M = 10007225 0 GTCCAGTGAGAAGAGTGTGATGTTGCAGATGAGAGGGGATAAATGCTGGACCAAAGTCCTTGAGAAGGTGAGAGAGAAAGGAGAGAAAGGAATCCAGAGTC #################BAA=@D at 2@;974/A at B:3'2>7 at CBC=>D>::73?BB87=28?A=AAC>7:8 at BC@D=CCCCCD?BACBBB>CCCBAAACAC@ MD:Z:85 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:37 OQ:Z:#################A=@<AA?3?8:3-->>@=1'0=8 at AA@<9B at 56<.??=;8<19 at B?BBB at 884>BA>B;BCABCB>?AACCB<BBBCCCBCCBB UQ:i:0
+20GAVAAXX100126:8:27:21479:11534 629 chr1 10007241 0 * = 10007241 0 NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN ##################################################################################################### PG:Z:BWA RG:Z:20GAV.8 XN:i:1 OQ:Z:#####################################################################################################
+20GAVAAXX100126:8:27:21479:11534 1721 chr1 10007241 37 32S69M = 10007241 0 GTCCAGTGAGAAGAGTGTGATGTTGCAGATGAGAGGGGATAAATGCTGGACCAAAGTCCTTGAGAAGGTGAGAGAGAAAGGAGAGAAAGGAATCCAGAGTC #################################B5224>?;=@C>;B4=>2 at A?C=9C>:>?>=?A8-8ACBDAD at CCCA?D at E=BBCBBCCBCABAC at C@ MD:Z:69 PG:Z:BWA RG:Z:20GAV.8 AM:i:0 NM:i:0 SM:i:37 OQ:Z:#################################@7/03=?<;?@=6>59=7=@;??;B?;?A@@AA:-6?AAB at B@BB@?=B at C<CCBBBBB at BBBABBAB UQ:i:0
+20GAVAAXX100126:8:63:5666:148033 83 chr1 10007256 60 101M = 10006932 -424 GGACCAAAGTCCTTGAGAAGGTGAGAGAGAAAGGAGAGAAAGGAATCCAGAGTCCAGATGAAGGAGTTGATCTCTGATGGCAGCCGAGATAACAGCACATC DDCD=DDDADCCDCBDBDDCACBDBDBDBDDDBBDBDBDDDBBDCBCBDBCADCBCBCCBDCBBCADCBCDCDCCBCCBBBDBC;BDBCCDCBDCCC at BDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHBHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:67:10895:75253 99 chr1 10007283 60 101M = 10007475 292 AGAAAGGAGAGAAAGGAATCCAGAGTCCAGATGAAGGAGTTGATCTCTGATGGCAGCCGAGATAACAGCACATCCTTACGGTTGTAGGTGGCTTTGTAGAT CCCBDCCDCDCDDDCCDDCBBCCDCBBBCCDCBDDCCDCBDBDCBCBDBDCBCBCCBB;DCDCCDACCBCACCBBDDCA;CCDCCCCCBCCCCDDCCDDBB MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHFHHHHHHGF UQ:i:0
+20GAVAAXX100126:8:62:2555:107007 147 chr1 10007301 60 11S90M = 10006969 -421 AGAGAAATGAATCCAGAGTCCAGATGAAGGATTTGATCTCTGATGGCAGCCGAGATAACAGCACATCCTTACGGTTGTAGGTGGCTTTGTAGATCTAAGAA ############?AC;;8=>@CA?==?@C?83A<5@?7669-<B>@BBCC5AABDBABBBBA?AABBCCCB;CADCABDD at C?ACEEAACDBCCA@?CBB@ MD:Z:20G69 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:############??=5686>@A@?<<>??:9/=:8>;524:+:=<=ABBB@@@ABAB at BABBABBBBBABABBBBBBABCAB<ABCCCBCCBBBCCCCBCB UQ:i:18
+20GAVAAXX100126:8:68:8790:55871 83 chr1 10007343 60 101M = 10007049 -394 GATAACAGCACATCCTTACGGTTGTAGGTGGCTTTGTAGATCTAAGAAGATCAGGAAGATTGCTGGCTCTAGTTTTGTAGATTATCAGGAAGATTATCAGA >9789;<8::;985;:8:298648:==<@>;:;;;:6C@@C<:;>=<=:6=?A??@?>5<<9<;;:>?=???>AAB<=?<@<<==<>:@?=<@?=>B5?:< MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:A44445544455555555554:9<>=DDDD>@==@<;GFFG54444?<>8<FFFFFCC8>>55554ADDFAGAGFGDDADF??A>>>@C?>DFAADGAGDG UQ:i:0
+20GAVAAXX100126:8:46:18774:97831 83 chr1 10007344 60 101M = 10007015 -429 ATAACAGCACATCCTTACGGTTGTAGGTGGCTTTGTAGATCTAAGAAGATCAGGAAGATTGCTGGCTCTAGTTTTGTAGATTATCAGGAAGATTATCAGAA ?DDCCBCCCCCDCCDCC;CADCACDBACBBCDDCACDBCDCCDDBDDBCDBCBBDCBCDCBCCBBCDCCCADDDCACDBCDCCDBDBBDDBCDCCDCBBDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BHHHHEHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:24:7834:75053 83 chr1 10007352 60 101M = 10007028 -424 ACATCCTTACGGTTGTAGGTGGCTTTGTAGATCTAAGAAGATCAGGAAGATTGCTGGCTCTAGTTTTGTAGATTATCAGGAAGATTATCAGAAAAACATAT C?CDDCDCC;CADCACDCACBBCDDCACDBCDCCDDBDDBCDBDBBDDBCDCBCCBBCDCCCADDDCACCBCDCCDBDBBDDBCDCCDAC at ADDDCCACCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:FGHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:3:4038:181802 1107 chr1 10007427 60 101M = 10007126 -401 TCAGGAAGATTATCAGAAAAACATATCTTAACCTGGTGAGCTCTCTATGCTCTGGCACTTGAATAAAAGCTATCCTAAAATATTACAAATTCTAGAATTTA EDDCCDDCCDC at DACA@DDDCBCCCDCDCDCCCCBACBDBBDCDCCCCBCDCCBBBBCDC@@CCDDDCBCCCDCCCDDDCCCDCBBDDCDDCCDBDCBDCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHEHGGGGHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:3:4050:181815 83 chr1 10007427 60 101M = 10007126 -401 TCAGGAAGATTATCAGAAAAACATATCTTAACCTGGTGAGCTCTCTATGCTCTGGCACTTGAATAAAAGCTATCCTAAAATATTACAAATTCTAGAATTTA BDDCCDDCCDBCDACA at DDDCBCCCDCDCDCCCCBACBDBCDCDCCCCBCDCCBBBBCDC@@CCDDDCBCCCDCCCDDDCCCDCBBDDCDDCCDBDCBDCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GHHHHHHHIHIHHGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:48:10108:181079 83 chr1 10007444 60 101M = 10007155 -389 AAAACATATCTTAACCTGGTGAGCTCTCTATGCTCTGGCACTTGAATAAAAGCTATCCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTT EEDCCCCCDCDCDCCCCCACBDBCDCBCCCCBCDCCCBBCCDC at ACCDDDCBCCCDCCCDDDCCCDCBBDDCDDCCDBDCDDCBCCDDABBDDDDCCBDDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHIHHHHHIHHHHHHHHHGHHHIHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:48:10118:181094 1107 chr1 10007444 60 101M = 10007155 -389 AAAACATATCTTAACCTGGTGAGCTCTCTATGCTCTGGCACTTGAATAAAAGCTATCCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTT EEDC at CCCDCBCABCCBCABBDBCDCDCCCCBC<CCCBBBCAC>?CCDDDC at CCCDCCCDDDCACDABBDDCDDCCDBDCDDCBCCDD@;BAAAA@@7>=< MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHGHHHHHFHGGHHGHHGHHHHHHHHHHHHHBHHHHHGHGHEEHHHHHHFHHHHHHHHHHHGHHGHHHHHHHHHHHHHHHHHHHHHCCHGGGGFGDGGG UQ:i:0
+20GAVAAXX100126:8:43:20013:129172 83 chr1 10007463 60 101M = 10007196 -367 TGAGCTCTCTATGCTCTGGCACTTGAATAAAAGCTATCCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTTTCATTAACTAGGAGGCTTT DDDCCCCDCCCCCCDCCCBBCBDC at ACCDDDDA>CCDCCCDDDBCCD>BBDDCDDCCCBDCDDCBCCDD@@BDDDDACDDDDDBCDCDCCCDBBDC at A>DC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:IHHHHGIHHHHHHHHHHHHHHIHHGGHHHHHHFEHHHHHHHHHGHHHEHHHHHHHHHHHHHHHHHHHHHGEHHHHHIHHHHHHHHHHHHHHHHHHHGHGHH UQ:i:0
+20GAVAAXX100126:8:42:6558:108923 163 chr1 10007468 60 101M = 10007800 432 TCTCTATGCTCTGGCACTTGAATAAAAGCTATCCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTTTCATTAACTAGGAGGCTTTTTTTT @BCABABBBDBDBBBCBDCBCDDCEDDCCDCCBCCBBBBBBCCC:CDCCC at DDADCCDCC@CDBBC>BDCBD at BBCBBCBBBCB@ECB=D at ABBDBCDAAC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBCCBBBBBBBBBBBBCBCBCBCBCBBBBBCBBBBBBBBBBBBB at BBABBBBCBBABBBBBBBBABBAAABA@B at A@ABABAB at BBAB>A@@A?@@?@?;B UQ:i:0
+20GAVAAXX100126:8:45:3840:54807 163 chr1 10007468 60 101M = 10007795 427 TCTCTATGCTCTGGCACTTGAATAAAAGCTATCCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTTTCATTAACTAGGAGGCTTTTTTTT @CCAA at BABDBBB<?BADCCCDDCDEECA?CCBCC:?B at B6C@C:CE@<C;AD;CECD at C@CD;BC>?DABDBB7B?9A=BAC:@D??@??AB=;ADCBDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCBCCBCBBC?B@>ABBBCCBCBBCCB?<BBBBB>ABCB:B at BCBC<=BCCC>@CBB>BBBBCBBB=BCBBBA6B>C at CBBBCBA<>ACBBA95>A?@BB UQ:i:0
+20GAVAAXX100126:8:61:17876:93642 99 chr1 10007468 29 101M = 10007872 438 TCTCTATGCTCTGGCACTTGAATAAAAGCTATCCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTTTCATTAACTAGGAGGCTTTTTTTT CBC at DCCCBDBDBCBCADDBDDCCDDAABDCCBBCCDDDCCCDCACDDCDBDCCDDCDDCABDDBCACDDDA?DDDDDBCCDCDADCCCDCCCDDADDD@@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:0 SM:i:29 MQ:i:29 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHGHHHGG UQ:i:0
+20GAVAAXX100126:8:67:10895:75253 147 chr1 10007475 60 101M = 10007283 -292 GCTCTGGCACTTGAATAAAAGCTATCCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTTTCATTAACTAGGAGGCTTTTTTTTTTGGATA ;DBCCAB at CAAC?BCBCCDB=ABA>BB?DDACAC at BBACCBCCCCECADBBCADCC@C at BBBBB:BACDCCCCDCCACCDDBDCBBDBCDCDDCB@@ACC@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:9@?@@>@@?@@@A at A@@A@@>@A@=AB at BBBB@BAA?ABBBAABBBBBBABB at BBAAB@BBBBB>BAABAABBBBBBBBBCBBBBABBBBBCCBCCCBBCB UQ:i:0
+20GAVAAXX100126:8:68:20495:7123 99 chr1 10007491 60 101M = 10007858 412 AAAAGCTATCCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTTTCATTAACTAGGAGGCTTTTTTTTTTGGATACGGAGTCTTGCTCTGT CDDBCCDCCBBDCDDDCCCDCACDDCDBDACDDCDDCABCDBCACDDDA?CDDDDBCCDCDADCCCDCCBDDDDDDA@@@ACDCCA;CDCCCDDCCDCDDD MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:25 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGHHHHHHHHHIHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:3:11681:100672 83 chr1 10007491 60 101M = 10007181 -410 AAAAGCTATCCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTTTCATTAACTAGGAGGCTTTTTTTTTTGGATACGGAGTCTTGCTCTGT <E at DCCCACCCCDDDCCCDCBBDDCDDCCCB@ADDCACCAB:9>DDDDBADDDDDB>DCD@==6@<=BB6AAAADDDDDCBBCCB;BBDADCDCCCDACAC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:<HGHHHHFFHHHHHHHHHHHGHHHHHHHHGHGFHHHFHHFFB9EHHHHGGHHHHHHEHHHFAA9CD?HH9GGGGHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:7:7502:151389 1107 chr1 10007491 60 101M = 10007181 -410 AAAAGCTATCCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTTTCATTAACTAGGAGGCTTTTTTTTTTGGATACGGAGTCTTGCTCTGT @EDDCCC at BCCCDDDC;?=>@@DDCDDC>@BDCDDC=BAAB@:BDDDDBC?DDDDBC>ADBCCCBBBBBAAAAADDDDDCBBC at B;BBDADCDCCCDACAC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:AHHHHHHEEHHHHHHHBCBDDGHHHHHHEEHHHHHH?GGFFGBHHHHHHHDHHHHHHEGHHHHHHHIHHGGGGGHHHHHHHHHIHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:3:9830:12196 163 chr1 10007492 60 83M18S = 10007808 416 AAAGCTATCCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTTTCATTAACTAGGAGGCTTTTTTTTTTGGATACGGAGTCTTGCTCTGTC @DCBAAABBCDCCBDDCDCCACDDCCBDCCCDDCBB?BCB at CACBBDDADACCACDCDBD;D at BCC=CCCBDCABC at 8.67A################### MD:Z:83 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBCCCBCCBBBBCBCCBBBBBBCBBCBBBCBBBBBBBABBBB at BBBBBBBBBBBBABCB@BA@@AB at AB@@@A?8-49?################### UQ:i:0
+20GAVAAXX100126:8:4:4481:73051 163 chr1 10007500 60 101M = 10007790 390 CCTAAAATATTACAAATTCTAGAATTTACCTTCACAAAAACTTTTTCATTAACTAGGAGGCTTTTTTTTTTGGATACGGAGTCTTGCTCTGTCCTCCAGGC @DCAAABBBCBCA>DDCBCEDCCEDCCCBDEBBD?@?B at B@B at CACCCAC;BB;DC at DCCADCB@C>?DCABDAB>;6>98-CC@>@C=D at BB@D@?D=B< MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCCCCCCBCCCCABBBCCCCCCCCCCCCCCCBCCCCBCBBCCCBBCBCCCCCCCC?BBABBBBCB at CBBB=B at B>=><76(AA>9<AB@@@ABA@:@:=: UQ:i:0
+20GAVAAXX100126:8:48:10097:181097 1619 chr1 10007512 29 68S27M6S = 10007155 -383 AGAACGTATCTTCACCTGGTGAGCTCTCTATGCTCTGGCACTTGAATAAAAGCTACCCTAAAATATAGCAAATTCAAGGACTTACCTTCACAAAAGCGCTG ##################################################################################################### MD:Z:7T2A1T14 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:3 SM:i:29 MQ:i:29 OQ:Z:##################################################################################################### UQ:i:6
+20GAVAAXX100126:8:3:12227:40820 611 chr1 10007513 60 35M66S = 10007841 377 AAATTCTAGAATTTACCTTCACAAAAACTTTTTCAATAACTAGGAGGCTTTATTATTTCGAAAAGGATTACAACTCTGACCTCAAGGCTCGAGTCCAGAGG 1;?6=2;89############################################################################################ MD:Z:35 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:554452@=@############################################################################################ UQ:i:0
+20GAVAAXX100126:8:63:18841:113901 675 chr1 10007517 60 54M47S = 10007842 359 TCTAGAATTTACCTTCACAAAAACTTTTTCATCAACTAGGAGGCTTTTTTTTTTTGACACGGTATCTTGCTCCGTCCTACCGGAGAGATGGCGGTGGCCCG @<75;)A(((?(*9C?4'A1 at B2?311(A6BA(AA'.+:5CA3A>0))?(*CD################################################ MD:Z:32T21 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:A7445*?)))@*+<B?1)?.=@.?.0/(>4@?)?A*.->:BA8?@2))?(+BA################################################ UQ:i:7
+20GAVAAXX100126:8:45:16833:90513 83 chr1 10007530 60 101M = 10007194 -436 TTCACAAAAACTTTTTCATTAACTAGGAGGCTTTTTTTTTTGGATACGGAGTCTTGCTCTGTCCTCCAGGCTGGAGTGCAGTGGCACCATCTAGGCTAACT AE>;CDDDDBC?DADB at CDCDCC>DB@@=B><??@DDDDDCBBCCB;BBDADCDCBCDCCA at CCDCBCBBCCBBDABBBDABBB>?CBCDCCDCCCCBBCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:EHCBHHHHHGHEHGHEGHHHHHHDHHGEEHEBEEEHHHHHHHHHHHHHHHHHHHHHHHHHHEHHHHHHHHHHHHHHGHHHHGGGEDHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:45:16821:90529 1107 chr1 10007535 60 5S96M = 10007194 -436 TTCACAAAAACTTTTTCATTAACTAGGAGGCTTTTTTTTTTGGATACGGAGTCTTGCTCTGTCCTCCAGGCTGGAGTGCAGTGGCACCATCTAGGCTAACT ######<<=965DDDDBADCDC>=?BBB=B4=A?ADAADDCBBCCB;BBDADCDCBCDCCADCCDCBCBBCCBBDACBBDACBBB at CBCDCCDCCCCBBCC MD:Z:96 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:######@@@:89HHHHHFHHHHDAAHHFEH6>GEGHGFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHEHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:24:17458:9144 83 chr1 10007539 60 101M = 10007190 -449 ACTTTTTCATTAACTAGGAGGCTTTTTTTTTTGGATACGGAGTCTTGCTCTGTCCTCCAGGCTGGAGTGCAGTGGCACCATCTAGGCTAACTGCAACCTCT D at E@EEDCCDCDBCCDCBDCB=A?AADDAADCBBCCC;ABDADADCBCDBCADCCDCBCBBCABBCACBBDACBBB at CBCDCCDBBCCDBCCBCDCCACCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HGHEHHHHHHHHGHHHHHHHHEGEGGHHGGHHHHHHHHIHHHHGHHHHHIHHHHHHHHHHHHFHHHHHHHHHHHHHFHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:63:6242:80411 163 chr1 10007707 60 101M = 10007988 381 CCACACCCAGCTAATTTTTGTATTTTTAGTGGAGACGGGGTTTCACCATACTGGCCAGGCTGGTCTGGAACTCCTGACCTCAGGTGATCTGCCCGGTGAGG @CB at A?BBCBBDBBCCCBCCBCDCCCCCCBCCCCA at 9@<B>BCB at ACCBC>CC at BCBBC<4<B7??<A=?9>A at 9;-2B<@7@<-<::7-88AA7<9=75A MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBCBBBBBBBBBBCBC at BCCCCBBB@BBBBABBA?B?ABAABBAABAABA?AA at A;1;A1=;?@7;<6?@59,3@:?4;<(5586*67=@8;/44/? UQ:i:0
+20GAVAAXX100126:8:7:17495:193398 99 chr1 10007724 60 101M = 10007961 337 TTGTATTTTTAGTGGAGACGGGGTTTCACCATACTGGCCAGGCTGGTCTGGAACTCCTGACCTCAGGTGATCTGCCCGGTGAGGCATAACTTTTATTTCAG <<=:AAAAA;;A=AB?@C@:=?=9 at A@B?AB?A?A at BAABA?A@;73;718;;9=8><<>?@@>?AB:@AA>=5A<=7;:<A;>?CB at A?@A?@A>==:>@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GGGGGGGGGBBGAGGDFGGGDCDCGGGGGGGCGGFFGGGGGCGC=5/582555559D=?CCCCCCGGCGEFC?;G@?D?4BD at DDGGFGGAGEGGBBB>CG UQ:i:0
+20GAVAAXX100126:8:68:12222:58992 99 chr1 10007740 60 101M = 10008056 416 GACGGGGTTTCACCATACTGGCCAGGCTGGTCTGGAACTCCTGACCTCAGGTGATCTGCCCGGTGAGGCATAACTTTTATTTCAGTCTCACATTTCAGTTT CD at 9CCCCDDBCABCCCADBCBBCCCADBC;BCBCDD?DBBCBAABCBCC?BBACBDBBBB;BCBDCCBCCCDADDDD>C?A at CCCBDBCACCDDCADBEE MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHIHHHCHHHHHHGHHHHHFHHHHHHFGHFHHHHHHHHGHHHHHHHHHHHHHHHDHEGGHHHHHHHHIHHHHEHFHH UQ:i:0
+20GAVAAXX100126:8:44:5440:118213 163 chr1 10007743 60 101M = 10008043 400 GGGGTTTCACCATACTGGCCAGGCTGGTCTGGAACTCCTGACCTCAGGTGATCTGCCCGGTGAGGCATAACTTTTATTTCAGTCTCACATTTCAGTTTGTT @CCBA?BBCACCCABDCCCDCBCCA at A9B;?C;C7;>@3:;8CA@=@B5A:9@;A at CC:@6=:<C=783?:BCAB9:BC1-3 at 6@@C?8>?A=:@:AD at AA MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBACBBBCCBBBCBCBCCBABC>?@4B8>B8A<<AA3>=<B=B<<@0><:=<>=BB?>3<7<A;970<=:@B at 9:@@/+063=<?@7:>?96:3<@@7> UQ:i:0
+20GAVAAXX100126:8:4:4481:73051 83 chr1 10007790 60 101M = 10007500 -390 GTGATCTGCCCGGTGAGGCATAACTTTTATTTCAGTCTCACATTTCAGTTTGTTCTGTGGTCTCCTCCTTTATTTGTTGCTAGGTAAAAAACATTTTTTTT BECCDCDCCC;CACBDCBCCCDCAAADACDDDBDADCDBCBCDDDBDADACADDCCACBADCDCCDC at ADCCDDCADCBCCDBABAADDDCBBAADDBDDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHGGGHGHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHGGHHHHHHHHHHHHHHHGGGHHHHHGGGHHHHHH UQ:i:0
+20GAVAAXX100126:8:45:3840:54807 83 chr1 10007795 60 101M = 10007468 -427 CTGCCCGGTGAGGCATAACTTTTATTTCAGTCTCACATTTCAGTTTGTTCTGTGGTCTCCTCCTTTATTTGTTGCTAGGTAAAAAACATTTTTTTTTTTTT @A@??:A?BACAA>BB at A<=>AABAAB at B?CAB>A?BAACAC at AAC?@C>C<@A<A46&<;::;AB=?AA<A?A?===;<;:AAABA><<<<;<;@@:>=< MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GGGECGGGGGGGGCGGGGBBBGGGGGGGGGGFFEFEGGGGGGGGGGGCGEGEEGEE69*<5<@@GGADGFEGEGCD?EE4 at BGGGGG?BBBBBBBGGGGGG UQ:i:0
+20GAVAAXX100126:8:42:6558:108923 83 chr1 10007800 60 101M = 10007468 -432 CGGTGAGGCATAACTTTTATTTCAGTCTCACATTTCAGTTTGTTCTGTGGTCTCCTCCTTTATTTGTTGCTAGGTAAAAAACATTTTTTTTTTTTTTTTTT 8D>DCD?A?=?;C>@=D>9DD9:<896::67?DADB=28<>/>@7<37@;701+.4=3<@=+;;<1>=;7:@?>1<;AAAA=:????>>??>>>>DDBDDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:GHGHHHDFDBDBHCC at HE=HH55544;=<6;EHGHH?6;@A3AD9>8:C?6022/3A7<CD.4443AA<:@CFF6@@GGGFDBEEEEEEEEEEEEHHHHHH UQ:i:0
+20GAVAAXX100126:8:3:9830:12196 83 chr1 10007808 60 101M = 10007492 -416 GATAACTTTTATTTCAGTCTCACATTTCAGTTTGTTCTGTGGTCTCCTCCTTTATTTGTTGCTAGGTAAAAAACATTTTTTTTTTTTTTTTTTTGCTGGTT #><BB>;:??=BBBAB89:1:::,9:D>D=DBB?@B==:8=:<=88CAC>>AB3AAC8?CB:C?BA:=@DD>@=1>AAAAAAAAAAAADDDDDCCCC@@DC MD:Z:0C100 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:#CBFFB<<AD at FFFFF4443445/45HCHCHFGFDF4<<:=?=?94HFHD?GG6GGH at DHHBHDHH<CGHHDF?7<GGGGGGGGGGGGHHHHHHHHHHHHH UQ:i:2
+20GAVAAXX100126:8:3:8864:24332 1187 chr1 10007819 60 83M18S = 10008145 426 TTTCAGTCTCACATTTCAGTTTGTTCTGTGGTCTCCTCCTTTATTTGTTGCTAGGTAAAAAACATTTTTTTTTTTTTTTTTTTTGTTGGTTTCAGGGGAAT @BAAAA at BDBCACABCBCCACCBACBDCBCCBBDABBAACBBBCACCBCC@DBADC at CBCBB>@CD at BDCBDCABCBACBBA################### MD:Z:83 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCBBBBCBBBBBCCBBBCBCBBBBBBBABB at BBBBBBBBBABBBBBAABBBABB@@@@AA@?@BAB at AAAB@B at A@B at BAB################### UQ:i:0
+20GAVAAXX100126:8:3:8873:24347 163 chr1 10007819 60 83M18S = 10008145 426 TTTCAGTCTCACATTTCAGTTTGTTCTGTGGTCTCCTCCTTTATTTGTTGCTAGGTAAAAAACATTTTTTTTTTTTTTTTTTTTTTGGTTTCCAGGGAATT @BAAAA at BDBCACABBBCCACCBACBDCBCCBBDABBAACBCBCACCBCC@DAADC at DBCBB??BD at CDCACDBBBBBC?BA################### MD:Z:83 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BCCBBBBCBBBBBCCCBBCBCCBBBBBBABBABBBBBBBBBBBBBABABBBB at BB?@A at AA@@?AAAABAB at AA@BAAB>AB################### UQ:i:0
+20GAVAAXX100126:8:3:12227:40820 659 chr1 10007841 60 51S50M = 10007513 -377 GTGAGCTGCGACGTGAGGCATAACTTTTATTTCAGTCTCTCATTTCAGTTTGTTCTGTGGTCTCCTCATTTATTTGTTGCTAGGTAAAAAACCTTTTTTTT ####################################################@9B at -3A='&77,''&9=@6%343A>4A.43<2B456B;A'4C76:>D@ MD:Z:16C24A8 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:2 SM:i:37 MQ:i:60 OQ:Z:####################################################?5@?//A@''9<-'''78 at 4%.12?:3 at -02;1 at 277@7@'1B627=BB UQ:i:11
+20GAVAAXX100126:8:63:18841:113901 595 chr1 10007842 60 66S35M = 10007517 -359 ACTCCTGACCTCAGGTGATCTGCCCGCTGAGGCATAACTTTTATTTCAGTATCACATTTCAGTTTGTTCTGTGGTCTGCTCCTTTATTTGTTGCTAGGTAA ##################################################################################################### MD:Z:11C23 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:1 SM:i:37 MQ:i:60 OQ:Z:##################################################################################################### UQ:i:2
+20GAVAAXX100126:8:68:20495:7123 147 chr1 10007858 60 55S46M = 10007491 -412 TGAGGCATAACTTTTATTTCAGTCTCACATTTCAGTTTGTTCTGTGGTCTCCTCCTTTTTTTGTTGCTAGGTAAAAAACATTTTTTTTTTTTTTTTTTTTG ########################################################@B);C9,?33277?85ACCCC92(ADDDDDDBCDCCCCCBBCCC@ MD:Z:3A40G0C0 PG:Z:BWA RG:Z:20GAV.8 AM:i:25 NM:i:3 SM:i:25 MQ:i:60 OQ:Z:########################################################A?)<B</@65074<85>BCCB5.(>BBBBBBBBBBBBBBBBBBBB UQ:i:73
+20GAVAAXX100126:8:64:7784:120262 163 chr1 10007860 60 42M59S = 10008147 387 TATTTGTTGCTAGGTAAAAAACATTTTTTTTTTTTTTTTTTTTCTGGTTTCCGGGAATTTTAAAAAATAACTAAAGGCCCGTTTCTTTGGAGTTTCTCAGG @CBB?A at BBBDCBABCDDDDD@BCCCCCCCCCCCBBABBB?############################################################ MD:Z:42 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBCBCBBBBCBBCC at BBBBBBAABCCBBBBBBBBBBBBBB@############################################################ UQ:i:0
+20GAVAAXX100126:8:61:17876:93642 147 chr1 10007872 29 66S35M = 10007468 -438 GGATTAACTTTTTTTTCATCTTCACTTTCAGGTTTGTCTTGTGGTCCCCCCTTTTTTTTTTTCCAGGGAAAAAAAATTTTTTTTTTTTTTTTTTTTGCTGG #####################################################################ACCCA-')CEEEEEDEDDBCDCCCCCBABBC@ MD:Z:2T6C0A24 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:3 SM:i:29 MQ:i:29 OQ:Z:#####################################################################?BBB?-''ACCCCCBCBBBBCBBBBBBBBBBB UQ:i:16
+20GAVAAXX100126:8:62:20479:199378 99 chr1 10007875 60 8M1D78M15S = 10008195 420 AAAAAACATTTTTTTTTTTTTTTTTTGCTGGTTTCCAGGTAATTCTAAGAACTAACTAAGGTCCTGTTGCTTGGTGGTTACTAAGGGGGGCAGACAGAGTA CDDBDDABBDDDDDAAAAAAAAAA at 3+36;;@@@?A?@@;:=:<.6;;0<A<?BA3>9;<C:B?A;;:<9<::541$:,8?=><A################ MD:Z:8^T67A10 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:2 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHGGHHHHHGGGGGGGGGGG6-;;>BFFFFGCGF=><=?/34504FDDGF34555HBHCF54445555531-425FBDBF################ UQ:i:16
+20GAVAAXX100126:8:7:17495:193398 147 chr1 10007961 60 101M = 10007724 -337 GGAGGCAGACAGAGTATTTTGCACCATCCAAAGGAGGTAATGTAATGCTTAAATGGAAGAAACTGAACCAAACAACGAAAATATGGGCTATGTATTACAAA CD<4A<8)A9:C9%5?-ADA6 at AA=@48<?@AC at 9CA>=<B?BB?C?9CBACCCC>4A<>A<:;4<AC:@@BACA:BCCCDD at DBDCACCCABCBA@ABC@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BA70=91)<66B8%1;,?B?6@;@>?1;89@>AC:AA?;;B?C>>@<;@BBBBBB>5<>>A>>=:>BB8=>A?A?ABBCCCC?CACCCCBCCBB at B;ABBB UQ:i:0
+20GAVAAXX100126:8:63:6242:80411 83 chr1 10007988 60 101M = 10007707 -381 CCAAAGGAGGTAATGTAATGCTTAAATGGAAGAAACTGAACCAAACAACGAAAATATGGGCTATGTATTACAAACAACTCTGACACACTGTTATTTATGAT DDDDDCCDCACDCCACDCCBCDCDDCCBBDDBDDBCCBDCCBDDCBDB;BDDDCCCCBBBCCCCACCDCBBDDBBDBCDCCBBBBBBCCADCCDDCCABCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:44:5440:118213 83 chr1 10008043 60 101M = 10007743 -400 ATGGGCTATGTATTACAAACAACTCTGACACACTGTTATTTATGATATTATAGGAAAGCTTCTCCCAAGGAAAGTGGTGGAAACTCCATCACTTAGACAAG DECCCCCCCACCDCCBDDCBDCCDCCBBBBBCCCADCCDDCCCBCCCDCCCCBBDDCBCDDCDCCBDCBBDDDACBACBBDDBCDCBCDBCCDCDBC at CDC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:4:14239:56438 611 chr1 10008048 60 35M66S = 10008306 358 CTATGTATTACAAACAACTCTGACACACTGTTATTTATGATATTATAGGAAAGCTTCTCCCAAGGAAAGTGGTGGAAGATCCATCACTTAGACAAGTTAGA ##################################################################################################### MD:Z:35 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:##################################################################################################### UQ:i:0
+20GAVAAXX100126:8:68:12222:58992 147 chr1 10008056 60 101M = 10007740 -416 TACAAACAACTCTGACACACTGTTATTTATGATATTATAGGAAAGCTTCTCCCAAGGAAAGTGGTGGAAACTCCATCACTTAGACAAGTTAGAACACAACT BA:CD at CBCAAC@ACCBACAB at DAACCADD:CCC?CCBDC at CAD@CD at CCADBCDD@CCD at BA>>@@CCBCCCCCCCACEDECACBD at DCDBCAA@?@AC@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:A77=A<A@?B?A at BABAAABBBBBABABBBCBBB@BBBBBAB?BCBBABBBCBBBCBCBBBBBCCCCBBBCBBCBBCBCCCCCBCCCCCCCCBBCBCCBCB UQ:i:0
+20GAVAAXX100126:8:63:20674:138624 163 chr1 10008082 60 101M = 10008392 410 TTATGATATTATAGGAAAGCTTCTCCCAAGGAAAGTGGTGGAAACTCCATCACTTAGACAAGTTAGAACACAACTGTAAAGGTACTAAAAAGTGTATTAGA @CBB?BBBCCBCBACCDDCBDCBDBDCCDCCCDDB>AB>AABCC?DCCCD at CABDCCDACBCBBCC?D at B?CD?CAA?BBBA@@@ECC?D at BAACACC@DC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBCBBBCBBBBBBBBBBBBBBBBCBBBBBBBBB at BB@BAABABBBBBBBBABBBBBBAAB at ABB@B@@AAABAB???@A at 7@ABAA?A?A<A>@A?@@@ UQ:i:0
+20GAVAAXX100126:8:45:11956:153764 1699 chr1 10008108 29 56M1D3M1I41M = 10008497 423 CAAGGAAAGTGGTGGACACTCCATCACTTAGACAAGTTAGCACACCCGTGTAAAGGACTCATTTAGTGTCTCAGTGACATTTCTACTGTAATAGCCACTGG >:5=A7=C?A?8+5<:-+76;A86)B12C9>C45);641+&B2/?+4%,<?/*?7C6;();&''3@?B-)B9+8,AB,DBB8)2(B9+-B=(15(6CBBBB MD:Z:16A23A4A0A0C8^T4A0A0A5A1T2A2G3C0A1C6A2A1C4 PG:Z:BWA RG:Z:20GAV.8 AM:i:29 NM:i:20 SM:i:29 MQ:i:29 OQ:Z:;64<B68B;B at 7)7;7-*528 at 43)@0-A9<B52)>775+)A4,B+1))8A/)@1A28')<''(0>AA))A2)7*BB,BBB7(-)B2*(@<(.1)4@ [...]
+20GAVAAXX100126:8:45:11971:153753 163 chr1 10008108 60 101M = 10008431 423 CAAGGAAAGTGGTGGAAACTCCATCACTTAGACAAGTTAGAACACAACTGTAAAGGTACTAAAAAGTGTATTAGAGAGATTCATCCTGTAAAAGACCCTGG @CCBAACCBBBC>ACCDD at DBCCCACACCBCCAC?B;AA@?BAC=BCACB=BC at CB?AACB at C?CC:AABACBABAB at DA@@DAACDA<BA>BAC>4CBCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBABBB at BB?BBBBBABBBBBABBABABABA at B?ABA at ABBAAABAA?BAAA@;@BAB>A?@A<@:AA@@A@@@?A@?@A@@@??<@@;>??>2@@>A UQ:i:0
+20GAVAAXX100126:8:3:8864:24332 1107 chr1 10008145 60 101M = 10007819 -426 TAGAACACAACTGTAAAGGTACTAAAAAGTGTATTAGAGAGATTCATCCTGTAAAAGACCCTGGGGGCTGAGTGTGGTGGCTCATGCCTGTAACCCTAACA DECDBCCCDCCCACDDDCACCCCDDDDDACACCDCDBDBDBCDDBCDCCCACDDDCBBCCCCBBBBBCCBDACACBACBBCDBCCBCCCACDCCCCCBBBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHFHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:3:8873:24347 83 chr1 10008145 60 101M = 10007819 -426 TAGAACACAACTGTAAAGGTACTAAAAAGTGTATTAGAGAGATTCATCCTGTAAAAGACCCTGGGGGCTGAGTGTGGTGGCTCATGCCTGTAACCCTAACA DECDCCCCDCCCACDDDCACCCCDDDDDACACCDCDBDBDBCDDBCDCCCACDDDCBACCCCBBBBBCCBDACACBACBBCDBCCBCCCACDCCCCCBBBC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:64:7784:120262 83 chr1 10008147 60 101M = 10007860 -387 GAACACAACTGTAAAGGTACTAAAAAGTGTATTAGAGAGATTCATCCTGTAAAAGACCCTGGGGGCTGAGTGTGGTGGCTCATGCCTGTAACCCTAACACT DECCCCDCCCACDDDCACCCCDDDDDACACCDCDBDBDBCDDBCDCCCACDDDDBACCCCBBBBBCCBCACACBACBBCDBCCBCCCACDCCCCCDC at BCC MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH UQ:i:0
+20GAVAAXX100126:8:4:10255:86573 99 chr1 10008172 60 101M = 10008499 427 AGTGTATTAGAGAGATTCATCCTGTAAAAGACCCTGGGGGCTGAGTGTGGTGGCTCATGCCTGTAACCCTAACACTTTGGGAGGGTGAAGCAGAAGGATCA CCB at CCCDCCDCDCDCDBCCBBCBBCDDDCDABBCBCCCCBCBDCBBBBCBBCBDBCCBBBDBCCD=BBDCDACADDDBCCDCCB<CDDCCCCDDCDDCD= MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHEHHHHHHHHHHHHHHHHHGCHHHHHHHHHHHHHH? UQ:i:0
+20GAVAAXX100126:8:1:9991:44859 163 chr1 10008183 60 101M = 10008551 429 GAGATTCATCCTGTAAAAGACCCTGGGGGCTGAGTGTGGTGGCTCATGCCTGTAACCCTAACACTTTGGGAGGGTGAAGCAGAAGGATCACTTGAGTCCAG @CB at B?ABCBADB<CEEECCBDDECDDCCCECCC;A??@;BCAD at CC@ABBBB at DBCCDCBAC@DC7B<BABD.6A80<-5;@%?9::=B4>7)(=DB@@B MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:@AB?BCCBCBABCCCCCCCCCCCCCCCBBCCCBC<BBCA=BBCBBBA>A?BBABBCBBBBBBBBBBCA:@B>B34B7.8.3::%=859B=5:3(':@>>8C UQ:i:0
+20GAVAAXX100126:8:5:20728:120252 163 chr1 10008188 60 93M8S = 10008458 370 TCATCCTGTAAAAGACCCTGGGGGCTGAGTGTGGTGGCTCATGCCTGTAACCCTAACACTTTGGGAGGGTGAAGCAGAAGGATCACTTGAGTCCAGGAGTT @BBBAABBABCDCABACCDBCCCCABBBC at CBBC::7<=<>>;?==B?>?7 at C9AC???CBC@?A5?@B=<>B<:A==27=6;=@@>B77:B######### MD:Z:93 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BBBBBBCBBBBBBB?BBBBBBBBBA at B?B=B?BA9==?????==@<A9?:<@?:?A?9?AAA???1A??6>6?<:?=<.6=45==@6 at 519?######### UQ:i:0
+20GAVAAXX100126:8:62:20479:199378 147 chr1 10008195 60 101M = 10007875 -420 GTAAAAGACCCTGGGGGCTGAGTGTGGTGGCTCATGCCTGTAACCCTAACACTTTGGGAGGGTGAAGCAGAAGGATCACTTGAGTCCAGGAGTTTGAGACC ADB;@BB?C:AC at BDC7AD@C at D?BA at ABBACBB@?CBC at BC@D9CCAB?>CCDCCACCBB@?AAC at CDCBECBCCCBCEDCEBCCCBCCDADCA@AAAC@ MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:BA at 4;??<A:A at AAB?6BA at BBBAA?BB at ABAAAA=BBBCBB=B9ABB=@@BBBBBBCCCBBCBBBCBCCCCBBBCCACCCCCCBCCCCCCCCCCCCCBBB UQ:i:0
+20GAVAAXX100126:8:43:9142:90413 99 chr1 10008198 60 101M = 10008465 366 AAAGACCCTGGGGGCTGAGTGTGGTGGCTCATGCCTGTAACCCTAACACTTTGGGAGGGTGAAGCAGAAGGATCACTTGAGTCCAGGAGTTTGAGACCAGC CDDADACCDBCCCCBDBDCCBBBCABCBDBCCBBBCBBCDABBCCDACACDDBCCDCCB:BDDCBCCDDCCDC at CAD@ADCCBABCBBACDACDCDACADB MD:Z:101 PG:Z:BWA RG:Z:20GAV.8 AM:i:37 NM:i:0 SM:i:37 MQ:i:60 OQ:Z:HHHHHHHHHHHHHHHHHHHHHHHHGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGCHHHHHHHHHHHHHGIHHGIHHHHIGHGFGHHGHIHHHHGHF UQ:i:0
diff --git a/public/gatk-queue-extensions-generator/pom.xml b/public/gatk-queue-extensions-generator/pom.xml
new file mode 100644
index 0000000..296ca52
--- /dev/null
+++ b/public/gatk-queue-extensions-generator/pom.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-aggregator</artifactId>
+ <version>3.3</version>
+ <relativePath>../..</relativePath>
+ </parent>
+
+ <artifactId>gatk-queue-extensions-generator</artifactId>
+ <packaging>jar</packaging>
+ <name>GATK Queue Extensions Generator</name>
+ <description>GATK Queue Extensions Generator</description>
+
+ <properties>
+ <gatk.basedir>${project.basedir}/../..</gatk.basedir>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-tools-public</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/ArgumentDefinitionField.java b/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/ArgumentDefinitionField.java
new file mode 100644
index 0000000..1e9e5cc
--- /dev/null
+++ b/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/ArgumentDefinitionField.java
@@ -0,0 +1,558 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk;
+import htsjdk.samtools.BAMIndex;
+import htsjdk.samtools.SAMFileWriter;
+import htsjdk.tribble.Tribble;
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.utils.commandline.*;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+
+import java.io.File;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public abstract class ArgumentDefinitionField extends ArgumentField {
+
+ protected final ArgumentDefinition argumentDefinition;
+ protected ArgumentDefinitionField(ArgumentDefinition argumentDefinition) {
+ this.argumentDefinition = argumentDefinition;
+ }
+
+ @Override protected String getRawFieldName() { return argumentDefinition.fullName; }
+ @Override protected Class<? extends Annotation> getAnnotationIOClass() { return argumentDefinition.ioType.annotationClass; }
+ @Override protected String getDoc() { return escape(argumentDefinition.doc); }
+ @Override protected String getFullName() { return escape(argumentDefinition.fullName); }
+ @Override protected String getShortName() { return escape(argumentDefinition.shortName); }
+ @Override protected boolean isRequired() { return argumentDefinition.required; }
+ @Override protected String getExclusiveOf() { return escape(argumentDefinition.exclusiveOf); }
+ @Override protected String getValidation() { return escape(argumentDefinition.validation); }
+ protected boolean isFlag() { return argumentDefinition.isFlag; }
+ protected boolean isMultiValued() { return argumentDefinition.isMultiValued; }
+
+ protected final String getShortFieldGetter() { return getFieldName(getRawShortFieldName()); }
+ protected final String getShortFieldSetter() { return getFieldName(getRawShortFieldName() + "_="); }
+ protected String getRawShortFieldName() { return argumentDefinition.shortName; }
+ @Override protected String getDefineAddition() {
+ if (argumentDefinition.shortName == null)
+ return "";
+ else if(getShortFieldGetter().equals(getFieldName()))
+ return "";
+ else
+ return String.format("%n" +
+ "/**%n" +
+ " * Short name of %1$s%n" +
+ " * @return Short name of %1$s%n" +
+ " */%n" +
+ "%5$sdef %3$s = this.%1$s%n" +
+ "%n" +
+ "/**%n" +
+ " * Short name of %1$s%n" +
+ " * @param value Short name of %1$s%n" +
+ " */%n" +
+ "%5$sdef %4$s(value: %2$s) { this.%1$s = value }%n",
+ getFieldName(),
+ getFieldType(),
+ getShortFieldGetter(),
+ getShortFieldSetter(),
+ getPrivacy());
+ }
+
+ protected static final String REQUIRED_TEMPLATE = " + required(\"%1$s\", %3$s, spaceSeparated=true, escape=true, format=%2$s)";
+ protected static final String REPEAT_TEMPLATE = " + repeat(\"%1$s\", %3$s, spaceSeparated=true, escape=true, format=%2$s)";
+ protected static final String OPTIONAL_TEMPLATE = " + optional(\"%1$s\", %3$s, spaceSeparated=true, escape=true, format=%2$s)";
+ protected static final String FLAG_TEMPLATE = " + conditional(%3$s, \"%1$s\", escape=true, format=%2$s)";
+
+ public final String getCommandLineAddition() {
+ return String.format(getCommandLineTemplate(), getCommandLineParam(), getCommandLineFormat(), getFieldName());
+ }
+
+ protected String getCommandLineParam() {
+ return (argumentDefinition.shortName != null)
+ ? "-" + argumentDefinition.shortName
+ : "--" + argumentDefinition.fullName;
+ }
+
+ protected String getCommandLineFormat() {
+ return "\"%s\"";
+ }
+
+ @Override
+ protected String getGatherAnnotation() {
+ return "";
+ }
+
+ protected String getCommandLineTemplate() {
+ if (isFlag()) return FLAG_TEMPLATE;
+ if (isMultiValued()) return REPEAT_TEMPLATE;
+ if (isRequired()) return REQUIRED_TEMPLATE;
+ return OPTIONAL_TEMPLATE;
+ }
+
+ public static List<? extends ArgumentField> getArgumentFields(ParsingEngine parsingEngine,Class<?> classType) {
+ List<ArgumentField> argumentFields = new ArrayList<>();
+ for (ArgumentSource argumentSource: parsingEngine.extractArgumentSources(classType))
+ if (!argumentSource.isDeprecated()) {
+ String gatherer = null;
+ if (argumentSource.field.isAnnotationPresent(Gather.class)) {
+ Gather gather = argumentSource.field.getAnnotation(Gather.class);
+ if(! "".equals(gather.className()))
+ gatherer = gather.className();
+ else
+ gatherer = gather.value().getName();
+ }
+ for (ArgumentDefinition argumentDefinition: argumentSource.createArgumentDefinitions())
+ argumentFields.addAll(getArgumentFields(argumentDefinition, gatherer));
+ }
+ return argumentFields;
+ }
+
+ public static String getArgumentFullName(final Class<?> collection, final String fieldName) {
+ try {
+ final Field field = collection.getField(fieldName);
+ final Argument arg = field.getAnnotation(Argument.class);
+ if (arg != null)
+ return arg.fullName();
+ final Input inputAnnotation = field.getAnnotation(Input.class);
+ if (inputAnnotation != null)
+ return inputAnnotation.fullName();
+ final Output outputAnnotation = field.getAnnotation(Output.class);
+ if (outputAnnotation != null)
+ return outputAnnotation.fullName();
+ } catch (NoSuchFieldException e) {
+ throw new IllegalStateException(String.format("Can't find field %s in ArgumentCollection %s", fieldName, collection.getSimpleName()), e);
+ }
+ throw new IllegalStateException(String.format("Field %s in class %s is not annotated as an argument", fieldName, collection.getName()));
+ }
+
+ private static final List<String> intervalFields = new ArrayList<>();
+ private static final String inputFileArgument = getArgumentFullName(GATKArgumentCollection.class, "samFiles");
+
+ static {
+ intervalFields.add(getArgumentFullName(IntervalArgumentCollection.class, "intervals"));
+ intervalFields.add(getArgumentFullName(IntervalArgumentCollection.class, "excludeIntervals"));
+ }
+
+ private static List<? extends ArgumentField> getArgumentFields(ArgumentDefinition argumentDefinition, String gatherer) {
+ if (intervalFields.contains(argumentDefinition.fullName) && argumentDefinition.ioType == ArgumentIOType.INPUT) {
+ return Arrays.asList(
+ new IntervalFileArgumentField(argumentDefinition),
+ new IntervalStringArgumentField(argumentDefinition));
+
+ } else if (NumThreadsArgumentField.NUM_THREADS_FIELD.equals(argumentDefinition.fullName)) {
+ return Arrays.asList(new NumThreadsArgumentField(argumentDefinition));
+
+ } else if (inputFileArgument.equals(argumentDefinition.fullName) && argumentDefinition.ioType == ArgumentIOType.INPUT) {
+ return Arrays.asList(new InputTaggedFileDefinitionField(argumentDefinition), new InputIndexesArgumentField(argumentDefinition, BAMIndex.BAMIndexSuffix, ".bam"));
+
+ } else if ((RodBinding.class.equals(argumentDefinition.argumentType) || RodBinding.class.equals(argumentDefinition.componentType) || RodBindingCollection.class.equals(argumentDefinition.componentType)) && argumentDefinition.ioType == ArgumentIOType.INPUT) {
+ return Arrays.asList(new InputTaggedFileDefinitionField(argumentDefinition), new InputIndexesArgumentField(argumentDefinition, Tribble.STANDARD_INDEX_EXTENSION));
+
+ } else if (argumentDefinition.ioType == ArgumentIOType.INPUT) {
+ return Collections.singletonList(new InputArgumentField(argumentDefinition));
+
+ } else if (argumentDefinition.ioType == ArgumentIOType.OUTPUT) {
+
+ List<ArgumentField> fields = new ArrayList<>();
+
+ String gatherClass;
+
+ // one can set the specific gatherer to use by adding @Gather before any output argument.
+ // For example (used to be part of UG):
+ // @Gather(className = "org.broadinstitute.gatk.queue.extensions.gatk.CatVariantsGatherer")
+ // @Output(doc="File to which variants should be written",required=true)
+ // protected VariantContextWriter writer = null;
+ if (gatherer != null)
+ gatherClass = gatherer;
+ else if (SAMFileWriter.class.isAssignableFrom(argumentDefinition.argumentType))
+ gatherClass = "BamGatherFunction";
+ else if (VariantContextWriter.class.isAssignableFrom(argumentDefinition.argumentType))
+ gatherClass = "CatVariantsGatherer"; // used to be "VcfGatherFunction";
+ else
+ gatherClass = "org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction";
+
+ fields.add(new OutputArgumentField(argumentDefinition, gatherClass));
+
+ if (SAMFileWriter.class.isAssignableFrom(argumentDefinition.argumentType)) {
+ fields.add(new SAMFileWriterIndexArgumentField(argumentDefinition));
+ fields.add(new SAMFileWriterMD5ArgumentField(argumentDefinition));
+ }
+ else if (VariantContextWriter.class.isAssignableFrom(argumentDefinition.argumentType)) {
+ fields.add(new VCFWriterIndexArgumentField(argumentDefinition));
+ }
+
+ return fields;
+
+ } else if (argumentDefinition.isFlag) {
+ return Collections.singletonList(new FlagArgumentField(argumentDefinition));
+
+ } else if (argumentDefinition.isMultiValued) {
+ return Collections.singletonList(new MultiValuedArgumentField(argumentDefinition));
+
+ } else if (!argumentDefinition.required && useOption(argumentDefinition.argumentType)) {
+ boolean useFormat = useFormatter(argumentDefinition.argumentType);
+ List<ArgumentField> fields = new ArrayList<>();
+ ArgumentField field = new OptionedArgumentField(argumentDefinition, useFormat);
+ fields.add(field);
+ if (useFormat) fields.add(new FormatterArgumentField(field));
+ return fields;
+
+ } else {
+ boolean useFormat = useFormatter(argumentDefinition.argumentType);
+ List<ArgumentField> fields = new ArrayList<>();
+ ArgumentField field = new DefaultArgumentField(argumentDefinition, useFormat);
+ fields.add(field);
+ if (useFormat) fields.add(new FormatterArgumentField(field));
+ return fields;
+
+ }
+ }
+
+ // if (intervalFields.contains(argumentDefinition.fullName) && argumentDefinition.ioType == ArgumentIOType.INPUT)
+ // Change intervals exclusive of intervalsString.
+ private static class IntervalFileArgumentField extends InputArgumentField {
+ public IntervalFileArgumentField(ArgumentDefinition argumentDefinition) {
+ super(argumentDefinition);
+ }
+
+ @Override
+ protected String getExclusiveOf() {
+ StringBuilder exclusiveOf = new StringBuilder(super.getExclusiveOf());
+ if (exclusiveOf.length() > 0)
+ exclusiveOf.append(",");
+ exclusiveOf.append(escape(argumentDefinition.fullName)).append("String");
+ return exclusiveOf.toString();
+ }
+ }
+
+ // if (intervalFields.contains(argumentDefinition.fullName) && argumentDefinition.ioType == ArgumentIOType.INPUT)
+ // Change intervals to a string but as an argument.
+ private static class IntervalStringArgumentField extends ArgumentDefinitionField {
+ public IntervalStringArgumentField(ArgumentDefinition argumentDefinition) {
+ super(argumentDefinition);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override protected Class<? extends Annotation> getAnnotationIOClass() { return Argument.class; }
+ @Override protected Class<?> getInnerType() { return String.class; }
+ @Override protected String getRawFieldName() { return super.getRawFieldName() + "String"; }
+ @Override protected String getFullName() { return super.getFullName() + "String"; }
+ @Override protected String getRawShortFieldName() { return super.getRawShortFieldName() + "String"; }
+ @Override protected String getFieldType() { return "Seq[String]"; }
+ @Override protected String getDefaultValue() { return "Nil"; }
+ @Override public String getCommandLineTemplate() { return REPEAT_TEMPLATE; }
+
+ @Override
+ protected String getExclusiveOf() {
+ StringBuilder exclusiveOf = new StringBuilder(super.getExclusiveOf());
+ if (exclusiveOf.length() > 0)
+ exclusiveOf.append(",");
+ exclusiveOf.append(escape(argumentDefinition.fullName));
+ return exclusiveOf.toString();
+ }
+ }
+
+ // if (argumentDefinition.ioType == ArgumentIOType.INPUT)
+ // Map all inputs to files. Handles multi valued files.
+ private static class InputArgumentField extends ArgumentDefinitionField {
+ public InputArgumentField(ArgumentDefinition argumentDefinition) {
+ super(argumentDefinition);
+ }
+
+ @Override protected Class<?> getInnerType() { return File.class; }
+ @Override protected String getFieldType() { return isMultiValued() ? "Seq[File]" : "File"; }
+ @Override protected String getDefaultValue() { return isMultiValued() ? "Nil" : "_"; }
+ }
+
+ // if (argumentDefinition.ioType == ArgumentIOType.OUTPUT)
+ // Map all outputs to files.
+ private static class OutputArgumentField extends ArgumentDefinitionField {
+ private final String gatherClass;
+ public OutputArgumentField(ArgumentDefinition argumentDefinition, String gatherClass) {
+ super(argumentDefinition);
+ this.gatherClass = gatherClass;
+ }
+
+ @Override protected Class<?> getInnerType() { return File.class; }
+ @Override protected String getFieldType() { return "File"; }
+ @Override protected String getDefaultValue() { return "_"; }
+
+ @Override public boolean isGather() { return true; }
+ @Override protected String getGatherAnnotation() {
+ return String.format("@Gather(classOf[%s])%n", gatherClass);
+ }
+ }
+
+ // if (argumentDefinition.isFlag)
+ // Booleans should be set on the commandline only if they are true.
+ private static class FlagArgumentField extends ArgumentDefinitionField {
+ public FlagArgumentField(ArgumentDefinition argumentDefinition) {
+ super(argumentDefinition);
+ }
+
+ @Override protected Class<?> getInnerType() { return boolean.class; }
+ @Override protected String getFieldType() { return "Boolean"; }
+ @Override protected String getDefaultValue() { return "_"; }
+ @Override protected String getCommandLineTemplate() { return FLAG_TEMPLATE; }
+ }
+
+ // if (argumentDefinition.isMultiValued)
+ // Multi value arguments are mapped to List[] and use repeat.
+ private static class MultiValuedArgumentField extends ArgumentDefinitionField {
+ public MultiValuedArgumentField(ArgumentDefinition argumentDefinition) {
+ super(argumentDefinition);
+ }
+
+ @Override protected Class<?> getInnerType() { return mapType(argumentDefinition.componentType); }
+ @Override protected String getFieldType() { return String.format("Seq[%s]", getType(getInnerType())); }
+ @Override protected String getDefaultValue() { return "Nil"; }
+ @Override protected String getCommandLineTemplate() { return REPEAT_TEMPLATE; }
+ }
+
+ // if (!argumentDefinition.required && useOption(argumentDefinition.argumentType))
+ // Any optional arguments that are primitives are wrapped in options.
+ private static class OptionedArgumentField extends ArgumentDefinitionField {
+ private final boolean useFormatter;
+
+ public OptionedArgumentField(ArgumentDefinition argumentDefinition, boolean useFormatter) {
+ super(argumentDefinition);
+ this.useFormatter = useFormatter;
+ }
+
+ @Override protected Class<?> getInnerType() { return mapType(argumentDefinition.argumentType); }
+ @Override protected String getFieldType() { return String.format("Option[%s]", getType(getInnerType())); }
+ @Override protected String getDefaultValue() { return "None"; }
+ @Override protected String getCommandLineTemplate() { return OPTIONAL_TEMPLATE; }
+ @Override protected String getCommandLineFormat() {
+ return this.useFormatter ? getFieldName(this.getRawFieldName() + "Format") : super.getCommandLineFormat();
+ }
+ }
+
+ // Any other @Arguments
+ private static class DefaultArgumentField extends ArgumentDefinitionField {
+ private final boolean useFormatter;
+
+ public DefaultArgumentField(ArgumentDefinition argumentDefinition, boolean useFormatter) {
+ super(argumentDefinition);
+ this.useFormatter = useFormatter;
+ }
+
+ @Override protected Class<?> getInnerType() { return mapType(argumentDefinition.argumentType); }
+ @Override protected String getFieldType() { return getType(getInnerType()); }
+ @Override protected String getDefaultValue() { return "_"; }
+ @Override protected String getCommandLineFormat() {
+ return this.useFormatter ? getFieldName(this.getRawFieldName() + "Format") : super.getCommandLineFormat();
+ }
+ }
+
+ // Allows the user to specify the track name, track type, and the file.
+ public static class NumThreadsArgumentField extends OptionedArgumentField {
+ public static final String NUM_THREADS_FIELD = getArgumentFullName(GATKArgumentCollection.class, "numberOfDataThreads");
+ public static final String NCT_FIELD = getArgumentFullName(GATKArgumentCollection.class, "numberOfCPUThreadsPerDataThread");
+
+ public NumThreadsArgumentField(ArgumentDefinition argumentDefinition) {
+ super(argumentDefinition, false);
+ }
+
+ @Override
+ protected String getFreezeFields() {
+ return String.format("if (%1$s.isDefined) nCoresRequest = %1$s%nif (%2$s.isDefined) nCoresRequest = Some(nCoresRequest.getOrElse(1) * %2$s.getOrElse(1))%n",
+ NUM_THREADS_FIELD, NCT_FIELD);
+ }
+ }
+
+ // Tagged input_files or other rods.
+ public static class InputTaggedFileDefinitionField extends ArgumentDefinitionField {
+ public InputTaggedFileDefinitionField(ArgumentDefinition argumentDefinition) {
+ super(argumentDefinition);
+ }
+ @Override protected Class<?> getInnerType() { return null; } // TaggedFile does not need to be imported.
+ @Override protected String getFieldType() { return argumentDefinition.isMultiValued ? "Seq[File]" : "File"; }
+ @Override protected String getDefaultValue() { return argumentDefinition.isMultiValued ? "Nil" : "_"; }
+ @Override protected String getCommandLineTemplate() {
+ if (argumentDefinition.isMultiValued) {
+ return " + repeat(\"%1$s\", %3$s, formatPrefix=TaggedFile.formatCommandLineParameter, spaceSeparated=true, escape=true, format=%2$s)";
+ } else if (!argumentDefinition.required) {
+ return " + optional(TaggedFile.formatCommandLineParameter(\"%1$s\", %3$s), %3$s, spaceSeparated=true, escape=true, format=%2$s)";
+ } else {
+ return " + required(TaggedFile.formatCommandLineParameter(\"%1$s\", %3$s), %3$s, spaceSeparated=true, escape=true, format=%2$s)";
+ }
+ }
+ }
+
+ // Adds optional inputs for the indexes of any rods added to this function.
+ private static class InputIndexesArgumentField extends ArgumentField {
+ private final boolean originalIsMultiValued;
+ private final String indexFieldName;
+ private final String originalFieldName;
+ private final String indexSuffix;
+ private final String originalSuffix;
+ public InputIndexesArgumentField(ArgumentDefinition originalArgumentDefinition, String indexSuffix) {
+ this(originalArgumentDefinition, indexSuffix, null);
+ }
+ public InputIndexesArgumentField(ArgumentDefinition originalArgumentDefinition, String indexSuffix, String originalSuffix) {
+ this.originalIsMultiValued = originalArgumentDefinition.isMultiValued;
+ this.indexFieldName = originalArgumentDefinition.fullName + "Index" + (originalIsMultiValued ? "es" : "");
+ this.originalFieldName = originalArgumentDefinition.fullName;
+ this.indexSuffix = indexSuffix;
+ this.originalSuffix = originalSuffix;
+ }
+ @Override protected Class<? extends Annotation> getAnnotationIOClass() { return Input.class; }
+ @Override public String getCommandLineAddition() { return ""; }
+ @Override protected String getDoc() {
+ return originalIsMultiValued
+ ? "Dependencies on any indexes of " + this.originalFieldName
+ : "Dependencies on the index of " + this.originalFieldName;
+ }
+ @Override protected String getFullName() { return this.indexFieldName; }
+ @Override protected boolean isRequired() { return false; }
+ @Override protected String getFieldType() { return "Seq[File]"; }
+ @Override protected String getDefaultValue() { return "Nil"; }
+ @Override protected Class<?> getInnerType() { return File.class; }
+ @Override protected String getRawFieldName() { return this.indexFieldName; }
+ @Override protected String getPrivacy() { return "private "; }
+ @Override protected String getFreezeFields() {
+ if (originalIsMultiValued) {
+ if (originalSuffix == null) {
+ return String.format(
+ ("%1$s ++= %2$s" +
+ ".filter(orig => orig != null && (!orig.getName.endsWith(\".list\")))" +
+ ".map(orig => new File(orig.getPath + \"%3$s\"))%n"),
+ indexFieldName, originalFieldName, indexSuffix);
+ } else {
+ return String.format(
+ ("%1$s ++= %2$s" +
+ ".filter(orig => orig != null && orig.getName.endsWith(\"%4$s\"))" +
+ ".flatMap(orig => Array(" +
+ " new File(orig.getPath + \"%3$s\")," +
+ " new File(orig.getPath.stripSuffix(\"%4$s\") + \"%3$s\") ))%n"),
+ indexFieldName, originalFieldName, indexSuffix, originalSuffix);
+ }
+ } else {
+ if (originalSuffix == null) {
+ return String.format(
+ ("if (%2$s != null)%n " +
+ "%1$s :+= new File(%2$s.getPath + \"%3$s\")%n"),
+ indexFieldName, originalFieldName, indexSuffix);
+ } else {
+ return String.format(
+ ("if (%2$s != null && %2$s.getName.endsWith(\"%4$s\"))%n " +
+ "%1$s ++= Array(" +
+ " new File(%2$s.getPath + \"%3$s\")," +
+ " new File(%2$s.getPath.stripSuffix(\"%4$s\") + \"%3$s\") )%n"),
+ indexFieldName, originalFieldName, indexSuffix, originalSuffix);
+ }
+ }
+ }
+ }
+
+ // Tracks an automatically generated index, md5, etc.
+ private static abstract class AuxilliaryOutputArgumentField extends ArgumentField {
+ protected final String originalFieldName;
+ protected final String auxFieldName;
+ protected final String auxFieldLabel;
+ public AuxilliaryOutputArgumentField(ArgumentDefinition originalArgumentDefinition, String auxFieldLabel) {
+ this.originalFieldName = originalArgumentDefinition.fullName;
+ this.auxFieldName = originalArgumentDefinition.fullName + auxFieldLabel;
+ this.auxFieldLabel = auxFieldLabel;
+ }
+ @Override protected Class<? extends Annotation> getAnnotationIOClass() { return Output.class; }
+ @Override public String getCommandLineAddition() { return ""; }
+ @Override protected String getDoc() { return String.format("Automatically generated %s for %s", auxFieldLabel.toLowerCase(), this.originalFieldName); }
+ @Override protected String getFullName() { return this.auxFieldName; }
+ @Override protected boolean isRequired() { return false; }
+ @Override protected String getFieldType() { return "File"; }
+ @Override protected String getDefaultValue() { return "_"; }
+ @Override protected Class<?> getInnerType() { return File.class; }
+ @Override protected String getRawFieldName() { return this.auxFieldName; }
+ @Override protected String getPrivacy() { return "private "; }
+
+ @Override public boolean isGather() { return true; }
+ @Override protected String getGatherAnnotation() {
+ return String.format("@Gather(enabled=false)%n");
+ }
+ }
+
+ private static class VCFWriterIndexArgumentField extends AuxilliaryOutputArgumentField {
+ public VCFWriterIndexArgumentField(ArgumentDefinition originalArgumentDefinition) {
+ super(originalArgumentDefinition, "Index");
+ }
+ @Override protected String getFreezeFields() {
+ return String.format(
+ ("if (%2$s != null && !org.broadinstitute.gatk.utils.io.IOUtils.isSpecialFile(%2$s))%n" +
+ " if (!org.broadinstitute.gatk.engine.io.stubs.VCFWriterArgumentTypeDescriptor.isCompressed(%2$s.getPath))%n" +
+ " %1$s = new File(%2$s.getPath + \"%3$s\")%n"),
+ auxFieldName, originalFieldName, Tribble.STANDARD_INDEX_EXTENSION);
+ }
+ }
+
+ private static class SAMFileWriterIndexArgumentField extends AuxilliaryOutputArgumentField {
+ public SAMFileWriterIndexArgumentField(ArgumentDefinition originalArgumentDefinition) {
+ super(originalArgumentDefinition, "Index");
+ }
+ @Override protected String getFreezeFields() {
+ return String.format(
+ ("if (%2$s != null && !org.broadinstitute.gatk.utils.io.IOUtils.isSpecialFile(%2$s))%n" +
+ " if (!%3$s)%n" +
+ " %1$s = new File(%2$s.getPath.stripSuffix(\".bam\") + \"%4$s\")%n"),
+ auxFieldName, originalFieldName, getArgumentFullName(GATKArgumentCollection.class, "disableBAMIndexing"), BAMIndex.BAMIndexSuffix);
+ }
+ }
+
+ private static class SAMFileWriterMD5ArgumentField extends AuxilliaryOutputArgumentField {
+ public SAMFileWriterMD5ArgumentField(ArgumentDefinition originalArgumentDefinition) {
+ super(originalArgumentDefinition, "MD5");
+ }
+ @Override protected String getFreezeFields() {
+ return String.format(
+ ("if (%2$s != null && !org.broadinstitute.gatk.utils.io.IOUtils.isSpecialFile(%2$s))%n" +
+ " if (%3$s)%n" +
+ " %1$s = new File(%2$s.getPath + \"%4$s\")%n"),
+ auxFieldName, originalFieldName, getArgumentFullName(GATKArgumentCollection.class, "enableBAMmd5"), ".md5");
+ }
+ }
+
+ // Allows setting the format for floats and doubles
+ private static class FormatterArgumentField extends ArgumentField {
+ private final ArgumentField argumentField;
+ public FormatterArgumentField(ArgumentField argumentField) {
+ this.argumentField = argumentField;
+ }
+ @Override protected Class<? extends Annotation> getAnnotationIOClass() { return Argument.class; }
+ @Override public String getCommandLineAddition() { return ""; }
+ @Override protected String getDoc() { return "Format string for " + this.argumentField.getFullName(); }
+ @Override protected String getFullName() { return this.argumentField.getFullName() + "Format"; }
+ @Override protected boolean isRequired() { return false; }
+ @Override protected String getFieldType() { return "String"; }
+ @Override protected String getDefaultValue() { return "\"%s\""; }
+ @Override protected Class<?> getInnerType() { return String.class; }
+ @Override protected String getRawFieldName() { return this.argumentField.getRawFieldName() + "Format"; }
+ }
+}
diff --git a/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/ArgumentField.java b/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/ArgumentField.java
new file mode 100644
index 0000000..9c93efd
--- /dev/null
+++ b/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/ArgumentField.java
@@ -0,0 +1,250 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk;
+
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMFileWriter;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang.StringUtils;
+import org.broadinstitute.gatk.engine.filters.PlatformUnitFilterHelper;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+public abstract class ArgumentField {
+
+ public Collection<String> getImportStatements() {
+ List<String> imports = new ArrayList<String>();
+ for (Class<?> importClass: getImportClasses()) {
+ if (!isBuiltIn(importClass))
+ imports.add("import " + importClass.getName().replace("$", "."));
+ }
+ return imports;
+ }
+
+ /** @return Scala code defining the argument and it's annotation. */
+ public final String getArgumentAddition() {
+ return String.format("%n" +
+ "/** %s */%n" +
+ "@%s(fullName=\"%s\", shortName=\"%s\", doc=\"%s\", required=%s, exclusiveOf=\"%s\", validation=\"%s\")%n" +
+ "%s%svar %s: %s = %s%n" +
+ "%s",
+ getDoc(),
+ getAnnotationIOClass().getSimpleName(),
+ getFullName(),
+ getShortName(),
+ getDoc(),
+ isRequired(),
+ getExclusiveOf(),
+ getValidation(),
+ getGatherAnnotation(), getPrivacy(), getFieldName(), getFieldType(), getDefaultValue(),
+ getDefineAddition());
+ }
+
+ /** @return Scala code with defines to append to the argument definition. */
+ protected String getDefineAddition() { return ""; }
+
+ /** @return Scala code to append to the command line. */
+ public abstract String getCommandLineAddition();
+
+ // Argument Annotation
+
+ /** @return Documentation for the annotation. */
+ protected abstract String getDoc();
+
+ /** @return Annotation class of the annotation. */
+ protected abstract Class<? extends Annotation> getAnnotationIOClass();
+
+ /** @return Full name for the annotation. */
+ protected abstract String getFullName();
+
+ /** @return Short name for the annotation or "". */
+ protected String getShortName() { return ""; }
+
+ /** @return true if the argument is required. */
+ protected abstract boolean isRequired();
+
+ /** @return A comma separated list of arguments that may be substituted for this field. */
+ protected String getExclusiveOf() { return ""; }
+
+ /** @return A validation string for the argument. */
+ protected String getValidation() { return ""; }
+
+ /** @return A gather annotation with a line feed, or "". */
+ protected String getGatherAnnotation() { return ""; }
+
+ // Scala
+
+ /** @return The scala field type. */
+ protected abstract String getFieldType();
+
+ /** @return The scala default value. */
+ protected abstract String getDefaultValue();
+
+ /** @return The class of the field, or the component type if the scala
+ * field is a collection, or null if no type needs to be imported.
+ * NOTE: Used in some cases by getFieldType so the two function should be overriden together.
+ */
+ protected abstract Class<?> getInnerType();
+
+ /** @return A custom command for overriding freeze. */
+ protected String getFreezeFields() { return ""; }
+
+ /** @return Classes that should be imported. */
+ protected Collection<Class<?>> getImportClasses() {
+ ArrayList<Class<?>> importClasses = new ArrayList<Class<?>>();
+ importClasses.add(this.getAnnotationIOClass());
+ Class<?> innerType = this.getInnerType();
+ if (innerType != null)
+ if (!innerType.isEnum()) // see getType()
+ importClasses.add(innerType);
+ return importClasses;
+ }
+
+ /** @return Classes that should be imported by BCEL during packaging. */
+ protected Collection<Class<?>> getDependentClasses() {
+ ArrayList<Class<?>> dependentClasses = new ArrayList<Class<?>>();
+ Class<?> innerType = this.getInnerType();
+ if (innerType != null)
+ if (innerType.isEnum()) // Enums are not being implicitly picked up...
+ dependentClasses.add(innerType);
+ return dependentClasses;
+ }
+
+ /** @return True if this field uses @Gather. */
+ public boolean isGather() { return false; }
+
+ /** @return Privacy for the field. */
+ protected String getPrivacy() { return ""; }
+
+ /** @return The raw field name, which will be checked against scala build in types. */
+ protected abstract String getRawFieldName();
+ /** @return The field name checked against reserved words. */
+ protected final String getFieldName() {
+ return getFieldName(this.getRawFieldName());
+ }
+
+ /**
+ * Returns true if a class is built in and doesn't need to be imported.
+ * @param argType The class to check.
+ * @return true if the class is built in and doesn't need to be imported
+ */
+ public static boolean isBuiltIn(Class<?> argType) {
+ return argType.isPrimitive() || argType == String.class || Number.class.isAssignableFrom(argType);
+ }
+
+ /**
+ * @param rawFieldName The raw field name
+ * @return The field name checked against reserved words.
+ */
+ protected static String getFieldName(String rawFieldName) {
+ String fieldName = rawFieldName;
+ if (StringUtils.isNumeric(fieldName.substring(0,1)))
+ fieldName = "_" + fieldName;
+ if (isReserved(fieldName) || fieldName.contains("-"))
+ fieldName = "`" + fieldName + "`";
+ return fieldName;
+ }
+
+ /** via http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaReference.pdf */
+ private static final List<String> reservedWords = Arrays.asList(
+ "abstract", "case", "catch", "class", "def",
+ "do", "else", "extends", "false", "final",
+ "finally", "for", "forSome", "if", "implicit",
+ "import", "lazy", "match", "new", "null",
+ "object", "override", "package", "private", "protected",
+ "return", "sealed", "super", "this", "throw",
+ "trait", "try", "true", "type", "val",
+ "var", "while", "with", "yield");
+
+ protected static boolean isReserved(String word) {
+ return reservedWords.contains(word);
+ }
+
+ /**
+ * On primitive types returns the capitalized scala type.
+ * @param argType The class to check for options.
+ * @return the simple name of the class.
+ */
+ protected static String getType(Class<?> argType) {
+ // Special case for enums.
+ // Return the full path as sometimes two enums
+ // used in the same class have the same name
+ // ex: Model and Model
+ if (argType.isEnum())
+ return argType.getName().replace("$", ".");
+
+ String type = argType.getSimpleName();
+
+ if (argType.isPrimitive())
+ type = StringUtils.capitalize(type);
+
+ if ("Integer".equals(type))
+ type = "Int";
+
+ return type;
+ }
+
+ protected static String escape(String string) {
+ return (string == null) ? "" : StringEscapeUtils.escapeJava(string);
+ }
+
+ /**
+ * @param argType The class to check for options.
+ * @return true if option should be used.
+ */
+ protected static boolean useOption(Class<?> argType) {
+ return (argType.isPrimitive()) || (Number.class.isAssignableFrom(argType));
+ }
+
+ /**
+ * @param argType The class to check for options.
+ * @return true if option should be used.
+ */
+ protected static boolean useFormatter(Class<?> argType) {
+ return (argType.equals(Double.class) || argType.equals(Double.TYPE) ||
+ argType.equals(Float.class) || argType.equals(Float.TYPE));
+ }
+
+ // TODO: Use an annotation, type descriptor, anything but hardcoding these lists!
+
+ protected static Class<?> mapType(Class<?> clazz) {
+ if (InputStream.class.isAssignableFrom(clazz)) return File.class;
+ if (SAMFileReader.class.isAssignableFrom(clazz)) return File.class;
+ if (OutputStream.class.isAssignableFrom(clazz)) return File.class;
+ if (VariantContextWriter.class.isAssignableFrom(clazz)) return File.class;
+ if (SAMFileWriter.class.isAssignableFrom(clazz)) return File.class;
+ if (PlatformUnitFilterHelper.class.isAssignableFrom(clazz)) return String.class;
+ return clazz;
+ }
+}
diff --git a/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/GATKExtensionsGenerator.java b/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/GATKExtensionsGenerator.java
new file mode 100644
index 0000000..d125e3d
--- /dev/null
+++ b/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/GATKExtensionsGenerator.java
@@ -0,0 +1,399 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.commandline.ArgumentTypeDescriptor;
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.utils.commandline.ParsingEngine;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.WalkerManager;
+import org.broadinstitute.gatk.engine.filters.FilterManager;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.io.stubs.OutputStreamArgumentTypeDescriptor;
+import org.broadinstitute.gatk.engine.io.stubs.SAMFileWriterArgumentTypeDescriptor;
+import org.broadinstitute.gatk.engine.io.stubs.VCFWriterArgumentTypeDescriptor;
+import org.broadinstitute.gatk.engine.walkers.PartitionBy;
+import org.broadinstitute.gatk.engine.walkers.PartitionType;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.classloader.JVMUtils;
+import org.broadinstitute.gatk.utils.classloader.PluginManager;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * Generates Queue modules that can be used to run GATK walkers.
+ *
+ * ArgumentCollections are flattened into a single module.
+ */
+public class GATKExtensionsGenerator extends CommandLineProgram {
+ private static final Logger logger = Logger.getLogger(GATKExtensionsGenerator.class);
+ public static final String GATK_EXTENSIONS_PACKAGE_NAME = GATKExtensionsGenerator.class.getPackage().getName();
+ private static final String NEWLINE = String.format("%n");
+
+ private static final String CLASS_TEMPLATE = "package %s%n"+
+ "%s%n" +
+ "class %s extends %s {%n" +
+ "%s%s%n" +
+ "%soverride def commandLine = super.commandLine%s%n" +
+ "}%n";
+
+ private static final String TRAIT_TEMPLATE = "package %s%n"+
+ "%s%n" +
+ "trait %s extends %s {%n" +
+ "%s%s%n" +
+ "%sabstract override def commandLine = super.commandLine%s%n" +
+ "}%n";
+
+ private static final String GATK_DEPENDENCIES_TEMPLATE = "package %s%n" +
+ "%n" +
+ "/** A dynamicly generated list of classes that the GATK Extensions depend on, but are not be detected by default by BCEL. */%n" +
+ "class %s {%n" +
+ "val types = Seq(%n%s)%n" +
+ "}%n";
+
+ @Output(fullName="output_directory", shortName="outDir", doc="Directory to output the generated scala", required=true)
+ public File outputDirectory;
+
+ PluginManager<CommandLineProgram> clpManager = new PluginManager<CommandLineProgram>(CommandLineProgram.class, "CommandLineProgram", "CLP");
+ GenomeAnalysisEngine GATKEngine = new GenomeAnalysisEngine();
+ WalkerManager walkerManager = new WalkerManager();
+ FilterManager filterManager = new FilterManager();
+
+ /**
+ * Required main method implementation.
+ * @param argv Command-line arguments.
+ */
+ public static void main(String[] argv) {
+ try {
+ start(new GATKExtensionsGenerator(), argv);
+ System.exit(CommandLineProgram.result);
+ } catch (Exception e) {
+ exitSystemWithError(e);
+ }
+ }
+
+ @Override
+ protected Collection<ArgumentTypeDescriptor> getArgumentTypeDescriptors() {
+ List<ArgumentTypeDescriptor> typeDescriptors = new ArrayList<ArgumentTypeDescriptor>();
+ typeDescriptors.add(new VCFWriterArgumentTypeDescriptor(GATKEngine,System.out,Collections.<Object>emptyList()));
+ typeDescriptors.add(new SAMFileWriterArgumentTypeDescriptor(GATKEngine,System.out));
+ typeDescriptors.add(new OutputStreamArgumentTypeDescriptor(GATKEngine,System.out));
+ return typeDescriptors;
+ }
+
+ /**
+ * Loops over all the walkers and filters and generates a scala class for each.
+ * @return zero if the run was successful, non-zero if there was an error.
+ */
+ @Override
+ protected int execute() {
+ try {
+ if (!outputDirectory.isDirectory() && !outputDirectory.mkdirs())
+ throw new ReviewedGATKException("Unable to create output directory: " + outputDirectory);
+
+ SortedSet<Class<?>> dependents = new TreeSet<Class<?>>(classComparator);
+
+ for (Class<? extends CommandLineProgram> clp: clpManager.getPlugins()) {
+
+ try {
+ if (!isGatkProgram(clp)) {
+ logger.debug("Skipping: " + clp);
+ continue;
+ }
+
+ logger.debug("Generating: " + clp);
+ String clpClassName = clpManager.getName(clp);
+ String clpConstructor = String.format("analysisName = \"%s\"%njavaMainClass = \"%s\"%n", clpClassName, clp.getName());
+
+ writeClass("org.broadinstitute.gatk.queue.function.JavaCommandLineFunction", clpClassName,
+ false, clpConstructor, ArgumentDefinitionField.getArgumentFields(parser,clp), dependents);
+
+ if (clp == CommandLineGATK.class) {
+ for (Entry<String, Collection<Class<? extends Walker>>> walkersByPackage: walkerManager.getWalkerNamesByPackage(false).entrySet()) {
+ for(Class<? extends Walker> walkerType: walkersByPackage.getValue()) {
+ try {
+ String walkerName = walkerManager.getName(walkerType);
+ List<ArgumentField> argumentFields = new ArrayList<ArgumentField>();
+
+ argumentFields.addAll(ArgumentDefinitionField.getArgumentFields(parser,walkerType));
+ //argumentFields.addAll(RodBindField.getRodArguments(walkerType, trackBuilder));
+ argumentFields.addAll(ReadFilterField.getFilterArguments(parser,walkerType));
+
+ String constructor = String.format("analysisName = \"%1$s\"%nanalysis_type = \"%1$s\"%n", walkerName);
+ String scatterClass = getScatterClass(walkerType);
+ boolean isScatter = false;
+ if (scatterClass != null) {
+ isScatter = true;
+ constructor += String.format("scatterClass = classOf[%s]%n", scatterClass);
+ }
+
+ writeClass(GATK_EXTENSIONS_PACKAGE_NAME + "." + clpClassName, walkerName,
+ isScatter, constructor, argumentFields, dependents);
+ } catch (Exception e) {
+ throw new ReviewedGATKException("Error generating wrappers for walker " + walkerType, e);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new ReviewedGATKException("Error generating wrappers for " + clp, e);
+ }
+ }
+
+ for (Class<? extends ReadFilter> filter: filterManager.getValues()) {
+ String filterName = filterManager.getName(filter);
+ writeFilter(filterName, ArgumentDefinitionField.getArgumentFields(new ParsingEngine(null),filter), dependents);
+ }
+
+ writeDependencies(dependents);
+
+ return 0;
+ } catch (IOException exception) {
+ logger.error("Error generating queue output.", exception);
+ return 1;
+ }
+ }
+
+ /**
+ * The list of packages to search through.
+ */
+ private static final List<String> gatkPackages = Arrays.asList(
+ "org.broadinstitute.gatk.engine",
+ "org.broadinstitute.gatk.utils.pipeline",
+ "org.broadinstitute.gatk.tools",
+ "org.broadinstitute.gatk.engine.datasources.reads.utilities");
+
+ /**
+ * Returns true if the class is part of the GATK.
+ * @param clazz Class to check.
+ * @return True if the class is part of the GATK.
+ */
+ private boolean isGatkProgram(Class<?> clazz) {
+ if (clazz.getPackage() == null)
+ return false;
+ String classPackage = clazz.getPackage().getName();
+ for (String gatkPackage : gatkPackages)
+ if (classPackage.startsWith(gatkPackage))
+ return true;
+ return false;
+ }
+
+ /**
+ * Returns the scatter type for a walker.
+ * @param walkerType The walker to check.
+ * @return The scatter type for the walker.
+ */
+ private String getScatterClass(Class<? extends Walker> walkerType) {
+ PartitionType partitionType = walkerType.getAnnotation(PartitionBy.class).value();
+ if (partitionType == PartitionType.NONE)
+ return null;
+ return StringUtils.capitalize(partitionType.name().toLowerCase()) + "ScatterFunction";
+ }
+
+ /**
+ * Writes a dynamically generated scala wrapper for a class.
+ * @param baseClass The class to extend from.
+ * @param className The class name to generate.
+ * @param isScatter True if the class is scatter/gatherable.
+ * @param constructor Additional logic for the constructor, or an empty string.
+ * @param argumentFields The list of argument fields for the generated class.
+ * @param dependents A set that should be updated with explicit dependencies that need to be packaged.
+ * @throws IOException If the file cannot be written.
+ */
+ private void writeClass(String baseClass, String className, boolean isScatter,
+ String constructor, List<? extends ArgumentField> argumentFields,
+ Set<Class<?>> dependents) throws IOException {
+ String content = getContent(CLASS_TEMPLATE, baseClass, className, constructor, isScatter, "", argumentFields, dependents);
+ writeFile(GATK_EXTENSIONS_PACKAGE_NAME + "." + className, content);
+ }
+
+ /**
+ * Writes a dynamically generated scala wrapper for a GATK filter.
+ * The filter is defined as a trait in scala, and can be mixed into a GATK command via "val myMixin = new PrintReads with FilterName"
+ * @param className The class name to generate.
+ * @param argumentFields The list of argument fields for the generated class.
+ * @param dependents A set that should be updated with explicit dependencies that need to be packaged.
+ * @throws IOException If the file cannot be written.
+ */
+ private void writeFilter(String className, List<? extends ArgumentField> argumentFields, Set<Class<?>> dependents) throws IOException {
+ String content = getContent(TRAIT_TEMPLATE, "org.broadinstitute.gatk.queue.function.CommandLineFunction",
+ className, "", false, String.format(" + required(\"--read_filter\", \"%s\")", className), argumentFields, dependents);
+ writeFile(GATK_EXTENSIONS_PACKAGE_NAME + "." + className, content);
+ }
+
+ /**
+ * Writes the dependents to a scala wrapper that will compile and get picked up by BCEL.
+ * BCEL was missing some classes, such as Enums, when they were defined in the other generated classes.
+ * This generated wrapper makes sure they are explicitly seen by BCEL.
+ * @param dependents Explicit dependencies that need to be packaged.
+ * @throws IOException If the file cannot be written.
+ */
+ private void writeDependencies(SortedSet<Class<?>> dependents) throws IOException {
+ // Include the enclosing classes too. Scala will be looking for them.
+ SortedSet<Class<?>> enclosings = new TreeSet<Class<?>>(classComparator);
+ for (Class<?> dependent: dependents)
+ for (Class<?> enclosing = dependent; enclosing != null; enclosing = enclosing.getEnclosingClass())
+ enclosings.add(enclosing);
+ dependents = enclosings;
+
+ // Oh, and include the classes defined on methods too!
+ enclosings = new TreeSet<Class<?>>(classComparator);
+ for (Class<?> dependent: dependents) {
+ for (Method method: dependent.getDeclaredMethods()) {
+ JVMUtils.addGenericTypes(enclosings, method.getGenericReturnType());
+ for (Type parameterType: method.getGenericParameterTypes())
+ JVMUtils.addGenericTypes(enclosings, parameterType);
+ for (Type exceptionType: method.getGenericExceptionTypes())
+ JVMUtils.addGenericTypes(enclosings, exceptionType);
+ }
+ }
+ dependents = enclosings;
+
+ // Generate the dependents.
+ String className = "GATKClassDependencies";
+ StringBuilder classes = new StringBuilder();
+
+ for (Class<?> dependent: dependents) {
+ if (dependent.isArray())
+ continue;
+ if (ArgumentField.isBuiltIn(dependent))
+ continue;
+ if (!Modifier.isPublic(dependent.getModifiers()))
+ continue;
+ if (classes.length() > 0)
+ classes.append(",").append(NEWLINE);
+ String typeParams = getScalaTypeParams(dependent);
+ classes.append("classOf[").append(dependent.getName().replace("$", ".")).append(typeParams).append("]");
+ }
+ String content = String.format(GATK_DEPENDENCIES_TEMPLATE, GATK_EXTENSIONS_PACKAGE_NAME, className, classes);
+ writeFile(GATK_EXTENSIONS_PACKAGE_NAME + "." + className, content);
+ }
+
+ /**
+ * Returns a string representing the type parameters for a class, or an empty string if there are no type parameters.
+ * @param clazz The class to look for type parameters.
+ * @return The type parameters or an empty string.
+ */
+ private String getScalaTypeParams(Class<?> clazz) {
+ TypeVariable[] typeParams = clazz.getTypeParameters();
+ if (typeParams.length == 0)
+ return "";
+ return "[" + StringUtils.repeat("_", ",", typeParams.length) + "]";
+ }
+
+ /**
+ * Writes the generated scala file with this content.
+ * @param fullClassName Generated class name.
+ * @param content scala content.
+ * @throws IOException If the file cannot be written.
+ */
+ private void writeFile(String fullClassName, String content) throws IOException {
+ File outputFile = new File(outputDirectory, fullClassName.replace(".", "/") + ".scala");
+ if (outputFile.exists()) {
+ String existingContent = FileUtils.readFileToString(outputFile);
+ if (StringUtils.equals(content, existingContent))
+ return;
+ }
+ FileUtils.writeStringToFile(outputFile, content);
+ }
+
+ /**
+ * Generates scala content using CLASS_TEMPLATE or TRAIT_TEMPLATE.
+ * @param scalaTemplate CLASS_TEMPLATE or TRAIT_TEMPLATE
+ * @param baseClass The class to extend from.
+ * @param className The class name to generate.
+ * @param constructor Additional logic for the constructor, or an empty string.
+ * @param isScatter True if the class is scatter/gatherable.
+ * @param commandLinePrefix Additional logic to prefix to the QCommandLine.commandLine, or an empty string.
+ * @param argumentFields The list of argument fields for the generated class.
+ * @param dependents A set that should be updated with explicit dependencies that need to be packaged.
+ * @return The populated template.
+ */
+ private static String getContent(String scalaTemplate, String baseClass, String className,
+ String constructor, boolean isScatter, String commandLinePrefix,
+ List<? extends ArgumentField> argumentFields, Set<Class<?>> dependents) {
+ StringBuilder arguments = new StringBuilder();
+ StringBuilder commandLine = new StringBuilder(commandLinePrefix);
+
+ Set<String> importSet = new HashSet<String>();
+ boolean isGather = false;
+ List<String> freezeFields = new ArrayList<String>();
+ for(ArgumentField argumentField: argumentFields) {
+ arguments.append(argumentField.getArgumentAddition());
+ commandLine.append(argumentField.getCommandLineAddition());
+ importSet.addAll(argumentField.getImportStatements());
+ freezeFields.add(argumentField.getFreezeFields());
+ dependents.addAll(argumentField.getDependentClasses());
+
+ isGather |= argumentField.isGather();
+ }
+
+ if (isScatter) {
+ importSet.add("import org.broadinstitute.gatk.queue.function.scattergather.ScatterGatherableFunction");
+ baseClass += " with ScatterGatherableFunction";
+ }
+ if (isGather)
+ importSet.add("import org.broadinstitute.gatk.utils.commandline.Gather");
+
+ // Sort the imports so that the are always in the same order.
+ List<String> sortedImports = new ArrayList<String>(importSet);
+ Collections.sort(sortedImports);
+
+ StringBuffer freezeFieldOverride = new StringBuffer();
+ for (String freezeField: freezeFields)
+ freezeFieldOverride.append(freezeField);
+ if (freezeFieldOverride.length() > 0) {
+ freezeFieldOverride.insert(0, String.format("override def freezeFieldValues() {%nsuper.freezeFieldValues()%n"));
+ freezeFieldOverride.append(String.format("}%n%n"));
+ }
+
+ String importText = sortedImports.size() == 0 ? "" : NEWLINE + StringUtils.join(sortedImports, NEWLINE) + NEWLINE;
+
+ // see CLASS_TEMPLATE and TRAIT_TEMPLATE below
+ return String.format(scalaTemplate, GATK_EXTENSIONS_PACKAGE_NAME, importText,
+ className, baseClass, constructor, arguments, freezeFieldOverride, commandLine);
+ }
+
+ private static final Comparator<Class<?>> classComparator = new Comparator<Class<?>>() {
+ @Override
+ public int compare(Class<?> a, Class<?> b) {
+ return (a == null ? "" : a.getName()).compareTo(b == null ? "" : b.getName());
+ }
+ };
+}
diff --git a/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/ReadFilterField.java b/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/ReadFilterField.java
new file mode 100644
index 0000000..b23f1aa
--- /dev/null
+++ b/public/gatk-queue-extensions-generator/src/main/java/org/broadinstitute/gatk/queue/extensions/gatk/ReadFilterField.java
@@ -0,0 +1,48 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk;
+
+import htsjdk.samtools.filter.SamRecordFilter;
+import org.broadinstitute.gatk.utils.commandline.ParsingEngine;
+import org.broadinstitute.gatk.engine.WalkerManager;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ReadFilterField {
+ /**
+ * Adds an argument for each read filters listed on the walker.
+ * @param walkerClass the class of the walker
+ * @return the list of argument fields
+ */
+ public static List<ArgumentField> getFilterArguments(ParsingEngine parser, Class<? extends Walker> walkerClass) {
+ List<ArgumentField> argumentFields = new ArrayList<ArgumentField>();
+ for(Class<? extends SamRecordFilter> filter: WalkerManager.getReadFilterTypes(walkerClass))
+ argumentFields.addAll(ArgumentDefinitionField.getArgumentFields(parser,filter));
+ return argumentFields;
+ }
+}
diff --git a/public/gatk-queue-extensions-public/pom.xml b/public/gatk-queue-extensions-public/pom.xml
new file mode 100644
index 0000000..4d46ce1
--- /dev/null
+++ b/public/gatk-queue-extensions-public/pom.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-aggregator</artifactId>
+ <version>3.3</version>
+ <relativePath>../..</relativePath>
+ </parent>
+
+ <artifactId>gatk-queue-extensions-public</artifactId>
+ <packaging>jar</packaging>
+ <name>GATK Queue Extensions Public</name>
+
+ <properties>
+ <gatk.basedir>${project.basedir}/../..</gatk.basedir>
+ <gatk.extensions.sources>${project.build.directory}/generated-sources/gatk-extensions</gatk.extensions.sources>
+ <gatk.generate-gatk-extensions.skipped>false</gatk.generate-gatk-extensions.skipped>
+ <gatk.packagetests.artifactId>gatk-queue-package-distribution</gatk.packagetests.artifactId>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-tools-public</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-queue</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-compiler</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <!--
+ Extensions generator dependency only applies to the exec:exec,
+ not the artifact, but don't know another way to include
+ the artifact *only* in the <classpath/> of exec.
+ See https://jira.codehaus.org/browse/MEXEC-111
+
+ Perhaps extensions-generator should be wrapped in a maven plugin?
+ -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-queue-extensions-generator</artifactId>
+ <version>${project.version}</version>
+ <scope>runtime</scope>
+ </dependency>
+
+ <!--
+ NOTE: Because exec-maven-plugin is used, this aggregator dependency
+ will cause mvn compile to not work. Use mvn test-compile for now.
+
+ See:
+ http://stackoverflow.com/questions/4786881/why-is-test-jar-dependency-required-for-mvn-compile
+ http://jira.codehaus.org/browse/MEXEC-91
+ -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-tools-public</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-queue</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!--
+ See note above about exec plugin breaking mvn compile
+ -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-gatk-extensions</id>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <phase>generate-sources</phase>
+ <configuration>
+ <skip>${gatk.generate-gatk-extensions.skipped}</skip>
+ <executable>java</executable>
+ <arguments>
+ <argument>-classpath</argument>
+ <classpath />
+ <argument>org.broadinstitute.gatk.queue.extensions.gatk.GATKExtensionsGenerator</argument>
+ <argument>-l</argument>
+ <argument>WARN</argument>
+ <argument>-outDir</argument>
+ <argument>${gatk.extensions.sources}</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>add-gatk-extensions</id>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <phase>generate-sources</phase>
+ <configuration>
+ <sources>
+ <source>${gatk.extensions.sources}</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>example-resources</id>
+ <phase>${gatk.generate-resources.phase}</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.scala-tools</groupId>
+ <artifactId>maven-scala-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>package-unittests</id>
+ </execution>
+ <execution>
+ <id>package-integrationtests</id>
+ </execution>
+ <execution>
+ <id>package-largescaletests</id>
+ </execution>
+ <execution>
+ <id>package-knowledgebasetests</id>
+ </execution>
+ <execution>
+ <id>package-queuetests</id>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/public/gatk-queue-extensions-public/src/main/assembly/example-resources.xml b/public/gatk-queue-extensions-public/src/main/assembly/example-resources.xml
new file mode 100644
index 0000000..f3cd6f9
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/assembly/example-resources.xml
@@ -0,0 +1,20 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>example-resources</id>
+ <formats>
+ <format>tar.bz2</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <directory>src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples</directory>
+ <outputDirectory>.</outputDirectory>
+ <includes>
+ <include>ExampleCountReads.scala</include>
+ <include>ExampleCountLoci.scala</include>
+ <include>ExampleUnifiedGenotyper.scala</include>
+ <include>ExampleReadFilter.scala</include>
+ <include>ExampleCustomWalker.scala</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/CNV/xhmmCNVpipeline.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/CNV/xhmmCNVpipeline.scala
new file mode 100644
index 0000000..7d25668
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/CNV/xhmmCNVpipeline.scala
@@ -0,0 +1,615 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts.CNV
+
+import org.broadinstitute.gatk.queue.extensions.gatk._
+import org.broadinstitute.gatk.queue.QScript
+import org.broadinstitute.gatk.queue.util.VCF_BAM_utilities
+import org.broadinstitute.gatk.queue.extensions.gatk.DoC._
+import org.broadinstitute.gatk.utils.commandline._
+import java.io.{File, PrintStream, PrintWriter}
+import org.broadinstitute.gatk.utils.text.XReadLines
+import collection.JavaConversions._
+import org.broadinstitute.gatk.tools.walkers.coverage.CoverageUtils
+import org.broadinstitute.gatk.queue.function.scattergather.{CloneFunction, ScatterFunction, GatherFunction, ScatterGatherableFunction}
+import org.broadinstitute.gatk.queue.function.{CommandLineFunction, InProcessFunction}
+import org.broadinstitute.gatk.utils.io.IOUtils
+
+class xhmmCNVpipeline extends QScript {
+ qscript =>
+
+ @Input(doc = "bam input, as as a list of .bam files, or a list of bam files with sample IDs to be used ( as specified at https://www.broadinstitute.org/gatk/gatkdocs/org_broadinstitute_sting_gatk_CommandLineGATK.html#--sample_rename_mapping_file )", shortName = "I", required = true)
+ var bams: File = _
+
+ @Input(doc = "gatk jar file", shortName = "J", required = true)
+ var gatkJarFile: File = _
+
+ @Input(doc = "xhmm executable file", shortName = "xhmmExec", required = true)
+ var xhmmExec: File = _
+
+ @Input(doc = "Plink/Seq executable file", shortName = "pseqExec", required = true)
+ var pseqExec: File = _
+
+ @Argument(doc = "Plink/Seq SEQDB file (Reference genome sequence)", shortName = "SEQDB", required = true)
+ var pseqSeqDB: String = _
+
+ @Input(shortName = "R", doc = "ref", required = true)
+ var referenceFile: File = _
+
+ @Input(shortName = "L", doc = "Intervals", required = false)
+ var intervals: File = _
+
+ @Argument(doc = "level of parallelism for BAM DoC. By default is set to 0 [no scattering].", shortName = "scatter", required = false)
+ var scatterCountInput = 0
+
+ @Argument(doc = "Samples to run together for DoC, CNV discovery, and CNV genotyping. By default is set to 1 [one job per sample].", shortName = "samplesPerJob", required = false)
+ var samplesPerJob = 1
+
+ @Output(doc = "Base name for files to output", shortName = "o", required = true)
+ var outputBase: File = _
+
+ @Hidden
+ @Argument(doc = "How should overlapping reads from the same fragment be handled?", shortName = "countType", required = false)
+ var countType = CoverageUtils.CountPileupType.COUNT_FRAGMENTS
+
+ @Argument(doc = "Maximum depth (before GATK down-sampling kicks in...)", shortName = "MAX_DEPTH", required = false)
+ var MAX_DEPTH = 20000
+
+ @Hidden
+ @Argument(doc = "Number of read-depth bins", shortName = "NUM_BINS", required = false)
+ var NUM_BINS = 200
+
+ @Hidden
+ @Argument(doc = "Starting value of read-depth bins", shortName = "START_BIN", required = false)
+ var START_BIN = 1
+
+ @Argument(doc = "Minimum read mapping quality", shortName = "MMQ", required = false)
+ var minMappingQuality = 0
+
+ @Argument(doc = "Minimum base quality to be counted in depth", shortName = "MBQ", required = false)
+ var minBaseQuality = 0
+
+ @Argument(doc = "Memory (in GB) required for storing the whole matrix in memory", shortName = "wholeMatrixMemory", required = false)
+ var wholeMatrixMemory = -1
+
+ @Argument(shortName = "minTargGC", doc = "Exclude all targets with GC content less than this value", required = false)
+ var minTargGC : Double = 0.1
+
+ @Argument(shortName = "maxTargGC", doc = "Exclude all targets with GC content greater than this value", required = false)
+ var maxTargGC : Double = 0.9
+
+ @Argument(shortName = "minTargRepeats", doc = "Exclude all targets with % of repeat-masked bases less than this value", required = false)
+ var minTargRepeats : Double = 0.0
+
+ @Argument(shortName = "maxTargRepeats", doc = "Exclude all targets with % of repeat-masked bases greater than this value", required = false)
+ var maxTargRepeats : Double = 0.1
+
+ @Argument(shortName = "rawFilters", doc = "xhmm command-line parameters to filter targets and samples from raw data", required = false)
+ var targetSampleFiltersString: String = ""
+
+ @Argument(shortName = "PCAnormalize", doc = "xhmm command-line parameters to Normalize data using PCA information", required = false)
+ var PCAnormalizeMethodString: String = ""
+
+ @Argument(shortName = "normalizedFilters", doc = "xhmm command-line parameters to filter targets and samples from PCA-normalized data", required = false)
+ var targetSampleNormalizedFiltersString: String = ""
+
+ @Argument(shortName = "xhmmParams", doc = "xhmm model parameters file", required = true)
+ var xhmmParamsArg: File = _
+
+ @Argument(shortName = "discoverParams", doc = "xhmm command-line parameters for discovery step", required = false)
+ var discoverCommandLineParams: String = ""
+
+ @Argument(shortName = "genotypeParams", doc = "xhmm command-line parameters for genotyping step", required = false)
+ var genotypeCommandLineParams: String = ""
+
+ @Argument(shortName = "genotypeSubsegments", doc = "Should we also genotype all subsegments of the discovered CNV?", required = false)
+ var genotypeSubsegments: Boolean = false
+
+ @Argument(shortName = "maxTargetsInSubsegment", doc = "If genotypeSubsegments, then only consider sub-segments consisting of this number of targets or fewer", required = false)
+ var maxTargetsInSubsegment = 30
+
+ @Argument(shortName = "subsegmentGenotypeThreshold", doc = "If genotypeSubsegments, this is the default genotype quality threshold for the sub-segments", required = false)
+ var subsegmentGenotypeThreshold = 20.0
+
+ @Argument(shortName = "longJobQueue", doc = "Job queue to run the 'long-running' commands", required = false)
+ var longJobQueue: String = ""
+
+
+ val PREPARED_TARGS_SUFFIX: String = ".merged.interval_list"
+
+ val RD_OUTPUT_SUFFIX: String = ".RD.txt"
+
+ val TARGS_GC_SUFFIX = ".locus_GC.txt"
+ val EXTREME_GC_TARGS_SUFFIX = ".extreme_gc_targets.txt"
+
+ val TARGS_REPEAT_COMPLEXITY_SUFFIX = ".locus_complexity.txt"
+ val EXTREME_REPEAT_COMPLEXITY_SUFFIX = ".extreme_complexity_targets.txt"
+
+ val FILTERED_TARGS_SUFFIX: String = ".filtered_targets.txt"
+ val FILTERED_SAMPS_SUFFIX: String = ".filtered_samples.txt"
+
+
+ trait WholeMatrixMemoryLimit extends CommandLineFunction {
+ // Since loading ALL of the data can take significant memory:
+ if (wholeMatrixMemory < 0) {
+ this.memoryLimit = 24
+ }
+ else {
+ this.memoryLimit = wholeMatrixMemory
+ }
+ }
+
+ trait LongRunTime extends CommandLineFunction {
+ if (longJobQueue != "")
+ this.jobQueue = longJobQueue
+ }
+
+ def script = {
+ val prepTargets = new PrepareTargets(List(qscript.intervals), outputBase.getPath + PREPARED_TARGS_SUFFIX, xhmmExec, referenceFile)
+ add(prepTargets)
+
+ trait CommandLineGATKArgs extends CommandLineGATK {
+ this.intervals :+= prepTargets.out
+ this.jarFile = qscript.gatkJarFile
+ this.reference_sequence = qscript.referenceFile
+ this.logging_level = "INFO"
+ }
+
+ val parseMixedInputBamList = parseBamListWithOptionalSampleMappings(bams)
+
+ val processMixedInputBamList = new ProcessBamListWithOptionalSampleMappings(parseMixedInputBamList, outputBase.getPath)
+ add(processMixedInputBamList)
+
+ val samples: List[String] = parseMixedInputBamList.sampleToBams.keys.toList
+ Console.out.printf("Samples are %s%n", samples)
+
+ val groups: List[Group] = buildDoCgroups(samples, parseMixedInputBamList.sampleToBams, samplesPerJob, outputBase)
+ var docs: List[DoC] = List[DoC]()
+ for (group <- groups) {
+ Console.out.printf("Group is %s%n", group)
+ docs ::= new DoC(group.bams, group.DoC_output, countType, MAX_DEPTH, minMappingQuality, minBaseQuality, scatterCountInput, START_BIN, NUM_BINS, Nil, Some(processMixedInputBamList.bamSampleMap)) with CommandLineGATKArgs
+ }
+ addAll(docs)
+
+ val mergeDepths = new MergeGATKdepths(docs.map(u => u.intervalSampleOut), outputBase.getPath + RD_OUTPUT_SUFFIX, "_mean_cvg", xhmmExec, None, false) with WholeMatrixMemoryLimit with LongRunTime
+ add(mergeDepths)
+
+ var excludeTargets : List[File] = List[File]()
+ if (minTargGC > 0 || maxTargGC < 1) {
+ val calcGCcontents = new GCContentByInterval with CommandLineGATKArgs
+ calcGCcontents.out = outputBase.getPath + TARGS_GC_SUFFIX
+ add(calcGCcontents)
+
+ val excludeTargetsBasedOnGC = new ExcludeTargetsBasedOnValue(calcGCcontents.out, EXTREME_GC_TARGS_SUFFIX, minTargGC, maxTargGC)
+ add(excludeTargetsBasedOnGC)
+ excludeTargets ::= excludeTargetsBasedOnGC.out
+ }
+
+
+ class CalculateRepeatComplexity(outFile : String) extends CommandLineFunction {
+ @Input(doc="")
+ var intervals: File = prepTargets.out
+
+ @Output(doc="")
+ var out : File = new File(outFile)
+
+ val regFile : String = outputBase.getPath + ".targets.reg"
+ val locDB : String = outputBase.getPath + ".targets.LOCDB"
+
+ val removeFiles = "rm -f " + regFile + " " + locDB
+ val createRegFile = "cat " + intervals + " | awk 'BEGIN{OFS=\"\\t\"; print \"#CHR\\tBP1\\tBP2\\tID\"} {split($1,a,\":\"); chr=a[1]; if (match(chr,\"chr\")==0) {chr=\"chr\"chr} split(a[2],b,\"-\"); bp1=b[1]; bp2=bp1; if (length(b) > 1) {bp2=b[2]} print chr,bp1,bp2,NR}' > " + regFile
+ val createLOCDB = pseqExec + " . loc-load --locdb " + locDB + " --file " + regFile + " --group targets --out " + locDB + ".loc-load"
+ val calcRepeatMaskedPercent = pseqExec + " . loc-stats --locdb " + locDB + " --group targets --seqdb " + pseqSeqDB + " --out " + locDB + ".loc-stats"
+ val extractRepeatMaskedPercent = "cat " + locDB + ".loc-stats.locstats | awk '{if (NR > 1) print $_}' | sort -k1 -g | awk '{print $10}' | paste " + intervals + " - | awk '{print $1\"\\t\"$2}' > " + out
+
+ var command: String =
+ removeFiles +
+ " && " + createRegFile +
+ " && " + createLOCDB +
+ " && " + calcRepeatMaskedPercent +
+ " && " + extractRepeatMaskedPercent
+
+ override def commandLine = command
+
+ override def description = "Calculate the percentage of each target that is repeat-masked in the reference sequence: " + command
+ }
+
+ if (minTargRepeats > 0 || maxTargRepeats < 1) {
+ val calcRepeatComplexity = new CalculateRepeatComplexity(outputBase.getPath + TARGS_REPEAT_COMPLEXITY_SUFFIX)
+ add(calcRepeatComplexity)
+
+ val excludeTargetsBasedOnRepeats = new ExcludeTargetsBasedOnValue(calcRepeatComplexity.out, EXTREME_REPEAT_COMPLEXITY_SUFFIX, minTargRepeats, maxTargRepeats)
+ add(excludeTargetsBasedOnRepeats)
+ excludeTargets ::= excludeTargetsBasedOnRepeats.out
+ }
+
+ val filterCenterDepths = new FilterCenterRawMatrix(mergeDepths.mergedDoC, excludeTargets)
+ add(filterCenterDepths)
+
+ val pca = new PCA(filterCenterDepths.filteredCentered)
+ add(pca)
+
+ val normalize = new Normalize(pca)
+ add(normalize)
+
+ val filterZscore = new FilterAndZscoreNormalized(normalize.normalized)
+ add(filterZscore)
+
+ val filterOriginal = new FilterOriginalData(mergeDepths.mergedDoC, filterCenterDepths, filterZscore)
+ add(filterOriginal)
+
+
+ class DiscoverCNVs(inputParam: File, origRDParam: File) extends SamplesScatterable(xhmmExec, groups) with LongRunTime {
+ @Input(doc = "")
+ val input = inputParam
+
+ @Input(doc = "")
+ val xhmmParams = xhmmParamsArg
+
+ @Input(doc = "")
+ val origRD = origRDParam
+
+ @Output
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ val xcnv: File = new File(outputBase.getPath + ".xcnv")
+
+ @Output
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ val aux_xcnv: File = new File(outputBase.getPath + ".aux_xcnv")
+
+ // Set as an @Output, so that its value is updated in the cloned jobs being scattered:
+ @Output
+ @Gather(classOf[DummyGatherFunction])
+ val posteriorsBase = outputBase
+
+ @Output
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ val dipPosteriors: File = new File(posteriorsBase.getPath + ".posteriors.DIP.txt")
+
+ @Output
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ val delPosteriors: File = new File(posteriorsBase.getPath + ".posteriors.DEL.txt")
+
+ @Output
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ val dupPosteriors: File = new File(posteriorsBase.getPath + ".posteriors.DUP.txt")
+
+ override def commandLine =
+ xhmmExec + " --discover" +
+ " -p " + xhmmParams +
+ " -r " + input +
+ " -R " + origRD +
+ " -c " + xcnv +
+ " -a " + aux_xcnv +
+ " -s " + posteriorsBase +
+ " " + discoverCommandLineParams +
+ " " + addCommand
+
+ override def description = "Discovers CNVs in normalized data: " + commandLine
+ }
+
+ val discover = new DiscoverCNVs(filterZscore.filteredZscored, filterOriginal.sameFiltered)
+ add(discover)
+
+
+ abstract class BaseGenotypeCNVs(inputParam: File, xcnv: File, origRDParam: File, outName: String) extends SamplesScatterable(xhmmExec, groups) with LongRunTime {
+ @Input(doc = "")
+ val input = inputParam
+
+ @Input(doc = "")
+ val xhmmParams = xhmmParamsArg
+
+ @Input(doc = "")
+ val origRD = origRDParam
+
+ @Input(doc = "")
+ val inXcnv = xcnv
+
+ @Output
+ @Gather(classOf[MergeVCFsGatherFunction])
+ val vcf: File = new File(outName)
+
+ override def commandLine =
+ xhmmExec + " --genotype" +
+ " -p " + xhmmParams +
+ " -r " + input +
+ " -g " + inXcnv +
+ " -F " + referenceFile +
+ " -R " + origRD +
+ " -v " + vcf +
+ " " + genotypeCommandLineParams +
+ " " + addCommand
+ }
+
+ class GenotypeCNVs(inputParam: File, xcnv: File, origRDParam: File) extends BaseGenotypeCNVs(inputParam, xcnv, origRDParam, outputBase.getPath + ".vcf") {
+ override def description = "Genotypes discovered CNVs in all samples: " + commandLine
+ }
+
+ class GenotypeCNVandSubsegments(inputParam: File, xcnv: File, origRDParam: File) extends BaseGenotypeCNVs(inputParam, xcnv, origRDParam, outputBase.getPath + ".subsegments.vcf") {
+ override def commandLine =
+ super.commandLine +
+ " --subsegments" +
+ " --maxTargetsInSubsegment " + maxTargetsInSubsegment +
+ " --genotypeQualThresholdWhenNoExact " + subsegmentGenotypeThreshold
+
+ override def description = "Genotypes discovered CNVs (and their sub-segments, of up to " + maxTargetsInSubsegment + " targets) in all samples: " + commandLine
+ }
+
+ val genotype = new GenotypeCNVs(filterZscore.filteredZscored, discover.xcnv, filterOriginal.sameFiltered)
+ add(genotype)
+
+ if (genotypeSubsegments) {
+ val genotypeSegs = new GenotypeCNVandSubsegments(filterZscore.filteredZscored, discover.xcnv, filterOriginal.sameFiltered)
+ add(genotypeSegs)
+ }
+ }
+
+ class ExcludeTargetsBasedOnValue(locus_valueIn : File, outSuffix : String, minVal : Double, maxVal : Double) extends InProcessFunction {
+ @Input(doc="")
+ var locus_value : File = locus_valueIn
+
+ @Output(doc="")
+ var out : File = new File(outputBase.getPath + outSuffix)
+
+ def run = {
+ var outWriter = new PrintWriter(new PrintStream(out))
+ var elems = asScalaIterator(new XReadLines(locus_value))
+
+ while (elems.hasNext) {
+ val line = elems.next
+ val splitLine = line.split("\\s+")
+ val locus = splitLine(0)
+ val locValStr = splitLine(1)
+ try {
+ val locVal = locValStr.toDouble
+ if (locVal < minVal || locVal > maxVal)
+ outWriter.printf("%s%n", locus)
+ }
+ catch {
+ case nfe: NumberFormatException => println("Ignoring non-numeric value " + locValStr + " for locus " + locus)
+ case e: Exception => throw e
+ }
+ }
+
+ outWriter.close
+ }
+ }
+
+ class FilterCenterRawMatrix(inputParam: File, excludeTargetsIn : List[File]) extends CommandLineFunction with WholeMatrixMemoryLimit with LongRunTime {
+ @Input(doc = "")
+ val input = inputParam
+
+ @Input(doc = "")
+ val excludeTargets = excludeTargetsIn
+
+ @Output
+ val filteredCentered: File = new File(outputBase.getPath + ".filtered_centered" + RD_OUTPUT_SUFFIX)
+ @Output
+ val filteredTargets: File = new File(filteredCentered.getPath + FILTERED_TARGS_SUFFIX)
+ @Output
+ val filteredSamples: File = new File(filteredCentered.getPath + FILTERED_SAMPS_SUFFIX)
+
+ var command: String =
+ xhmmExec + " --matrix" +
+ " -r " + input +
+ " --centerData --centerType target" +
+ " -o " + filteredCentered +
+ " --outputExcludedTargets " + filteredTargets +
+ " --outputExcludedSamples " + filteredSamples
+ command += excludeTargets.map(u => " --excludeTargets " + u).reduceLeft(_ + "" + _)
+ if (targetSampleFiltersString != "")
+ command += " " + targetSampleFiltersString
+
+ override def commandLine = command
+
+ override def description = "Filters samples and targets and then mean-centers the targets: " + command
+ }
+
+ class PCA(inputParam: File) extends CommandLineFunction with WholeMatrixMemoryLimit with LongRunTime {
+ @Input(doc = "")
+ val input = inputParam
+
+ val PCAbase: String = outputBase.getPath + ".RD_PCA"
+
+ @Output
+ val outPC: File = new File(PCAbase + ".PC.txt")
+ @Output
+ val outPC_SD: File = new File(PCAbase + ".PC_SD.txt")
+ @Output
+ val outPC_LOADINGS: File = new File(PCAbase + ".PC_LOADINGS.txt")
+
+ var command: String =
+ xhmmExec + " --PCA" +
+ " -r " + input +
+ " --PCAfiles " + PCAbase
+
+ override def commandLine = command
+
+ override def description = "Runs PCA on mean-centered data: " + command
+ }
+
+ class Normalize(pca: PCA) extends CommandLineFunction with LongRunTime {
+ @Input(doc = "")
+ val input = pca.input
+
+ @Input(doc = "")
+ val inPC = pca.outPC
+
+ @Input(doc = "")
+ val inPC_SD = pca.outPC_SD
+
+ @Input(doc = "")
+ val inPC_LOADINGS = pca.outPC_LOADINGS
+
+ @Output
+ val normalized: File = new File(outputBase.getPath + ".PCA_normalized.txt")
+
+ var command: String =
+ xhmmExec + " --normalize" +
+ " -r " + input +
+ " --PCAfiles " + pca.PCAbase +
+ " --normalizeOutput " + normalized
+ if (PCAnormalizeMethodString != "")
+ command += " " + PCAnormalizeMethodString
+
+ override def commandLine = command
+
+ override def description = "Normalizes mean-centered data using PCA information: " + command
+ }
+
+ class FilterAndZscoreNormalized(inputParam: File) extends CommandLineFunction with WholeMatrixMemoryLimit with LongRunTime {
+ @Input(doc = "")
+ val input = inputParam
+
+ @Output
+ val filteredZscored: File = new File(outputBase.getPath + ".PCA_normalized.filtered.sample_zscores" + RD_OUTPUT_SUFFIX)
+ @Output
+ val filteredTargets: File = new File(filteredZscored.getPath + FILTERED_TARGS_SUFFIX)
+ @Output
+ val filteredSamples: File = new File(filteredZscored.getPath + FILTERED_SAMPS_SUFFIX)
+
+ var command: String =
+ xhmmExec + " --matrix" +
+ " -r " + input +
+ " --centerData --centerType sample --zScoreData" +
+ " -o " + filteredZscored +
+ " --outputExcludedTargets " + filteredTargets +
+ " --outputExcludedSamples " + filteredSamples
+ if (targetSampleNormalizedFiltersString != "")
+ command += " " + targetSampleNormalizedFiltersString
+
+ override def commandLine = command
+
+ override def description = "Filters and z-score centers (by sample) the PCA-normalized data: " + command
+ }
+
+ class FilterOriginalData(inputParam: File, filt1: FilterCenterRawMatrix, filt2: FilterAndZscoreNormalized) extends CommandLineFunction with WholeMatrixMemoryLimit with LongRunTime {
+ @Input(doc = "")
+ val input = inputParam
+
+ @Input(doc = "")
+ val targFilters: List[File] = List(filt1.filteredTargets, filt2.filteredTargets).map(u => new File(u))
+
+ @Input(doc = "")
+ val sampFilters: List[File] = List(filt1.filteredSamples, filt2.filteredSamples).map(u => new File(u))
+
+ @Output
+ val sameFiltered: File = new File(outputBase.getPath + ".same_filtered" + RD_OUTPUT_SUFFIX)
+
+ var command: String =
+ xhmmExec + " --matrix" +
+ " -r " + input +
+ targFilters.map(u => " --excludeTargets " + u).reduceLeft(_ + "" + _) +
+ sampFilters.map(u => " --excludeSamples " + u).reduceLeft(_ + "" + _) +
+ " -o " + sameFiltered
+
+ override def commandLine = command
+
+ override def description = "Filters original read-depth data to be the same as filtered, normalized data: " + command
+ }
+}
+
+
+abstract class SamplesScatterable(val xhmmExec: File, val groups: List[Group]) extends ScatterGatherableFunction with CommandLineFunction {
+ this.scatterCount = groups.size
+ this.scatterClass = classOf[SamplesScatterFunction]
+
+ @Input(doc = "", required=false)
+ var keepSampleIDs: Option[String] = None
+
+ def addCommand = if (keepSampleIDs.isDefined) ("--keepSampleIDs " + keepSampleIDs.get) else ""
+}
+
+class SamplesScatterFunction extends ScatterFunction with InProcessFunction {
+ protected var groups: List[Group] = _
+ override def scatterCount = groups.size
+
+ @Output(doc="Scatter function outputs")
+ var scatterSamples: Seq[File] = Nil
+
+ override def init() {
+ this.groups = this.originalFunction.asInstanceOf[SamplesScatterable].groups
+ }
+
+ override def bindCloneInputs(cloneFunction: CloneFunction, index: Int) {
+ val scatterPart = IOUtils.absolute(cloneFunction.commandDirectory, "keepSampleIDs.txt")
+ cloneFunction.setFieldValue("keepSampleIDs", Some(scatterPart))
+ this.scatterSamples :+= scatterPart
+ }
+
+ override def run() {
+ if (groups.size != this.scatterSamples.size)
+ throw new Exception("Internal inconsistency error in scattering jobs")
+
+ (groups, this.scatterSamples).zipped foreach {
+ (group, sampsFile) => {
+ val sampsWriter = new PrintWriter(new PrintStream(sampsFile))
+
+ for (samp <- group.samples) {
+ try {
+ sampsWriter.printf("%s%n", samp)
+ }
+ catch {
+ case e: Exception => throw e
+ }
+ }
+ sampsWriter.close
+ }
+ }
+ }
+}
+
+trait MergeVCFs extends CommandLineFunction {
+ var xhmmExec: File = _
+
+ @Input(doc = "")
+ var inputVCFs: List[File] = Nil
+
+ @Output
+ var mergedVCF: File = null
+
+ override def commandLine =
+ xhmmExec + " --mergeVCFs" +
+ inputVCFs.map(input => " --mergeVCF " + input).reduceLeft(_ + "" + _) +
+ " -v " + mergedVCF
+
+ override def description = "Combines VCF outputs for multiple samples (at same loci): " + commandLine
+}
+
+class MergeVCFsGatherFunction extends MergeVCFs with GatherFunction {
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+
+ this.xhmmExec = originalFunction.asInstanceOf[SamplesScatterable].xhmmExec
+
+ this.inputVCFs = this.gatherParts.toList
+ this.mergedVCF = this.originalOutput
+ }
+}
+
+class DummyGatherFunction extends InProcessFunction with GatherFunction {
+ override def run() {}
+}
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/GATKResourcesBundle.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/GATKResourcesBundle.scala
new file mode 100644
index 0000000..d89e605
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/GATKResourcesBundle.scala
@@ -0,0 +1,426 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts
+
+import org.broadinstitute.gatk.queue.QScript
+import org.broadinstitute.gatk.queue.extensions.gatk._
+import org.broadinstitute.gatk.queue.extensions.samtools.SamtoolsIndexFunction
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException
+import org.broadinstitute.gatk.queue.extensions.picard.PicardBamFunction
+import org.broadinstitute.gatk.queue.function.JavaCommandLineFunction
+
+class GATKResourcesBundle extends QScript {
+ // todo -- update to released version when things stabilize
+ @Argument(doc="gatkJarFile", required=false)
+ var gatkJarFile: File = new File("dist/GenomeAnalysisTK.jar")
+
+ @Argument(doc="liftOverPerl", required=false)
+ var liftOverPerl: File = new File("./public/perl/liftOverVCF.pl")
+
+ @Argument(shortName = "ver", doc="The GIT version of this release", required=true)
+ var BUNDLE_VERSION: String = _
+
+ @Argument(shortName = "bundleDir", doc="Path to root where resource files will be placed", required=false)
+ val BUNDLE_ROOT = new File("/humgen/gsa-hpprojects/GATK/bundle")
+
+ @Argument(shortName = "downloadDir", doc="Path to root where resource files will be placed for users to download", required=false)
+ val DOWNLOAD_ROOT = new File("/humgen/gsa-scr1/pub/bundle")
+
+ @Argument(shortName = "test", doc="", required=false)
+ val TEST = false
+
+ @Argument(shortName = "phase2", doc="", required=false)
+ val DO_DOWNLOAD = false
+
+ val SITES_EXT: String = "sites"
+
+ def BUNDLE_DIR: File = BUNDLE_ROOT + "/" + BUNDLE_VERSION
+ def DOWNLOAD_DIR: File = DOWNLOAD_ROOT + "/" + BUNDLE_VERSION
+
+ // REFERENCES
+ class Reference( val name: String, val file: File ) { }
+ var hg19: Reference = _
+ var b37: Reference = _
+ var hg18: Reference = _
+ var b36: Reference = _
+ var exampleFASTA: Reference = _
+ var refs: List[Reference] = _
+
+ class Resource(val file: File, val name: String, val ref: Reference, val useName: Boolean = true, val makeSites: Boolean = true, val makeCallsIfBam: Boolean = true ) {
+ def destname(target: Reference): String = {
+ if ( useName )
+ return name + "." + target.name + "." + getExtension(file)
+ else
+ return file.getName
+ }
+ }
+
+ def liftover(in: File, inRef: Reference, out: File, outRef: Reference): CommandLineFunction = {
+ //Console.printf("liftover(%s => %s)%n", inRef.name, outRef.name)
+ (inRef.name, outRef.name) match {
+ case ("b37", "hg19") =>
+ return new LiftOverPerl(in, out, new File("public/chainFiles/b37tohg19.chain"), inRef, outRef)
+ case ("b37", "hg18") =>
+ return new LiftOverPerl(in, out, new File("public/chainFiles/b37tohg18.chain"), inRef, outRef)
+ case ("b37", "b36") =>
+ return new LiftOverPerl(in, out, new File("public/chainFiles/b37tob36.chain"), inRef, outRef)
+ case _ => return null
+ }
+ }
+
+ def isVCF(file: File) = file.getName.endsWith(".vcf")
+ def isBAM(file: File) = file.getName.endsWith(".bam")
+ def isOUT(file: File) = file.getName.endsWith(".out")
+ def isFASTA(file: File) = file.getName.endsWith(".fasta")
+ def isIntervalList(file: File) = file.getName.endsWith(".interval_list")
+
+ var RESOURCES: List[Resource] = Nil
+ def addResource(comp: Resource) { RESOURCES = comp :: RESOURCES }
+
+ trait UNIVERSAL_GATK_ARGS extends CommandLineGATK {
+ this.logging_level = "INFO";
+ this.jarFile = gatkJarFile;
+ this.memoryLimit = 2
+ }
+
+ def initializeTestDataFiles() = {
+ //
+ // Standard evaluation files for indel
+ //
+ b37 = new Reference("b37", new File("/Users/depristo/Desktop/broadLocal/localData/human_g1k_v37.fasta"))
+ hg18 = new Reference("hg18", new File("/Users/depristo/Desktop/broadLocal/localData/Homo_sapiens_assembly18.fasta"))
+ exampleFASTA = new Reference("exampleFASTA", new File("public/testdata/exampleFASTA.fasta"))
+ refs = List(b37, hg18, exampleFASTA)
+
+ val DATAROOT = "/Users/depristo/Desktop/broadLocal/localData/"
+ //addResource(new Resource(DATAROOT + "human_g1k_v37.fasta", "human_g1k_v37.fasta", b37, false))
+ addResource(new Resource(DATAROOT + "1000G.snp.validation.b37.vcf", "1000G.snp.validation", b37))
+ addResource(new Resource(DATAROOT + "dbsnp_132_b37.vcf", "dbsnp_132", b37, true, false))
+
+ addResource(new Resource(exampleFASTA.file, "exampleFASTA", exampleFASTA, false))
+ addResource(new Resource("public/testdata/exampleBAM.bam", "exampleBAM", exampleFASTA, false, false, false))
+ }
+
+ def initializeStandardDataFiles() = {
+ //
+ // references
+ //
+ hg19 = new Reference("hg19", new File("/humgen/gsa-hpprojects/GATK/data/ucsc.hg19/ucsc.hg19.fasta"))
+ b37 = new Reference("b37", new File("/humgen/1kg/reference/human_g1k_v37.fasta"))
+ hg18 = new Reference("hg18", new File("/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta"))
+ b36 = new Reference("b36", new File("/humgen/1kg/reference/human_b36_both.fasta"))
+ exampleFASTA = new Reference("exampleFASTA", new File("public/testdata/exampleFASTA.fasta"))
+ refs = List(hg19, b37, hg18, b36, exampleFASTA)
+
+ addResource(new Resource(b37.file, "", b37, false))
+ addResource(new Resource(b36.file, "", b36, false))
+ addResource(new Resource(hg19.file, "", hg19, false))
+ addResource(new Resource(hg18.file, "", hg18, false))
+
+ //
+ // The b37_decoy reference
+ //
+ addResource(new Resource("/humgen/1kg/reference/human_g1k_v37_decoy.fasta",
+ "IGNORE", b37, false, false))
+
+ //
+ // standard VCF files. Will be lifted to each reference
+ //
+ addResource(new Resource("/humgen/gsa-hpprojects/GATK/data/Comparisons/Validated/dbSNP/dbsnp_138_b37.leftAligned.vcf",
+ "dbsnp_138", b37, true, false))
+
+ addResource(new Resource("/humgen/gsa-hpprojects/GATK/data/Comparisons/Validated/Omni2.5_chip/Omni25_sites_2141_samples.b37.vcf",
+ "1000G_omni2.5", b37, true, false))
+
+ addResource(new Resource("/humgen/gsa-hpprojects/GATK/data/Comparisons/Validated/HapMap/3.3/sites_r27_nr.b37_fwd.vcf",
+ "hapmap_3.3", b37, true, false))
+
+ addResource(new Resource("/humgen/1kg/DCC/ftp/technical/working/20120312_phase1_v2_indel_cleaned_sites_list/ALL.wgs.phase1_release_v2.20101123.official_indel_calls.20120312.sites.vcf",
+ "1000G_phase1.indels", b37, true, false))
+
+ addResource(new Resource("/humgen/1kg/processing/official_release/phase1/projectConsensus/phase1.wgs.projectConsensus.v2b.recal.highQuality.vcf",
+ "1000G_phase1.snps.high_confidence", b37, true, false))
+
+ addResource(new Resource("/humgen/gsa-hpprojects/GATK/data/Comparisons/Unvalidated/GoldStandardIndel/gold.standard.indel.MillsAnd1000G.b37.vcf",
+ "Mills_and_1000G_gold_standard.indels", b37, true, false))
+
+ //
+ // CEU trio (NA12878,NA12891,NA12892) best practices results
+ //
+
+ addResource(new Resource("/humgen/1kg/processing/production_wgs_final/trio/CEU/CEU.wgs.HaplotypeCaller.20131118.snps_indels.high_coverage_pcr_free.genotypes.vcf",
+ "CEUTrio.HiSeq.WGS.b37.bestPractices",b37,true,false))
+
+ //
+ // NA12878 knowledgebase snapshot
+ //
+
+ addResource(new Resource("/humgen/gsa-hpprojects/NA12878Collection/knowledgeBase/snapshots/NA12878.wgs.broad_truth_set.20131119.snps_and_indels.genotypes.vcf",
+ "NA12878.knowledgebase.snapshot.20131119",b37,true,false))
+
+ //
+ // example call set for documentation guide tutorial
+ //
+ addResource(new Resource("/humgen/gsa-hpprojects/NA12878Collection/exampleCalls/NA12878.HiSeq.WGS.bwa.cleaned.raw.b37.subset.vcf",
+ "NA12878.HiSeq.WGS.bwa.cleaned.raw.subset", b37, true, true))
+
+ //
+ // Test BAM file, only for the b37 reference
+ //
+ addResource(new Resource("/humgen/gsa-hpprojects/NA12878Collection/bams/CEUTrio.HiSeq.WGS.b37.NA12878.bam",
+ "IGNORE", b37, false, false))
+
+ //
+ // Exome targets file, only for the b37 reference
+ //
+ addResource(new Resource("/seq/references/HybSelOligos/HybSelOligos/whole_exome_agilent_1.1_refseq_plus_3_boosters/whole_exome_agilent_1.1_refseq_plus_3_boosters.Homo_sapiens_assembly19.targets.interval_list",
+ "Broad.human.exome", b37, true, false, false))
+
+ //
+ // refGene files specific to each reference
+ //
+ addResource(new Resource("/humgen/gsa-hpprojects/GATK/data/refGene_b37.sorted.txt",
+ "refGene", b37, true, false))
+
+ addResource(new Resource("public/chainFiles/hg18tob37.chain", "", hg18, false, false))
+ addResource(new Resource("public/chainFiles/b36tob37.chain", "", b36, false, false))
+
+ // todo -- chain files?
+ // todo 1000G SNP and indel call sets?
+
+ //
+ // exampleFASTA file
+ //
+ addResource(new Resource(exampleFASTA.file, "exampleFASTA", exampleFASTA, false))
+ addResource(new Resource("public/testdata/exampleBAM.bam", "exampleBAM", exampleFASTA, false, false, false))
+ }
+
+ def createBundleDirectories(dir: File) = {
+ if ( ! dir.exists ) dir.mkdirs()
+
+ for ( ref <- refs ) {
+ val refDir = new File(dir + "/" + ref.name)
+ if ( ! refDir.exists ) refDir.mkdirs()
+ }
+ }
+
+ def createCurrentLink(bundleDir: File) = {
+
+ val currentLink = new File(BUNDLE_ROOT + "/current")
+
+ if ( currentLink.exists ) add(new deleteLink(currentLink))
+
+ add(new linkFile(bundleDir, currentLink))
+ }
+
+ def script = {
+ if ( TEST )
+ initializeTestDataFiles();
+ else
+ initializeStandardDataFiles();
+
+ if ( ! DO_DOWNLOAD ) {
+ // create destination directory structure
+ createBundleDirectories(BUNDLE_DIR)
+
+ for ( resource: Resource <- RESOURCES ) {
+ if ( isFASTA(resource.file) ) {
+ copyBundleFasta(resource, resource.ref)
+ } else if ( isBAM(resource.file) ) {
+ val f = copyBundleFile(resource, resource.ref)
+ add(new IndexBAM(f))
+ if ( resource.makeCallsIfBam ) {
+ @Output val outvcf: File = swapExt(f.getParent, f, ".bam", ".vcf")
+ add(new UG(resource.file, resource.ref.file, outvcf))
+ }
+ } else if ( isVCF(resource.file) ) {
+ for ( destRef <- refs ) {
+ val out = destFile(BUNDLE_DIR, destRef, resource.destname(destRef))
+ var continue = true
+
+ // copy or lift over the original vcf
+ if ( resource.ref == destRef ) {
+ add(new cpFile(resource.file, out))
+ } else {
+ val clf = liftover(resource.file, resource.ref, out, destRef)
+ if ( clf != null ) {
+ add(clf)
+ } else {
+ continue = false
+ }
+ }
+
+ if ( continue ) {
+ add(new IndexVCF(out, destRef.file))
+
+ if ( resource.makeSites ) {
+ val sites: Resource = new Resource(swapExt(out.getParent, out, ".vcf", "." + SITES_EXT + ".vcf"), "", destRef, false)
+ add(new JustSites(out, sites.file))
+ add(new IndexVCF(sites.file, destRef.file))
+ }
+
+ if ( resource.name.contains("dbsnp") ) {
+ val dbsnp129: Resource = new Resource(swapExt(out.getParent, out, ".vcf", ".excluding_sites_after_129.vcf"), "", destRef, false)
+ add(new MakeDBSNP129(out, destRef.file, dbsnp129.file))
+ add(new IndexVCF(dbsnp129.file, destRef.file))
+ }
+ }
+ }
+ } else if ( isIntervalList(resource.file) ) {
+ val out = destFile(BUNDLE_DIR, resource.ref, resource.destname(resource.ref))
+ add(new cpFile(resource.file, out))
+ } else {
+ //throw new ReviewedStingException("Unknown file type: " + resource)
+ }
+ }
+
+ } else {
+ createCurrentLink(BUNDLE_DIR)
+ createBundleDirectories(DOWNLOAD_DIR)
+ createDownloadsFromBundle(BUNDLE_DIR, DOWNLOAD_DIR)
+ }
+ }
+
+
+ def createDownloadsFromBundle(in: File, out: File) {
+ Console.printf("Visiting %s%n", in)
+ if (! in.getName.startsWith(".")) {
+ if ( in.isDirectory ) {
+ out.mkdirs
+
+ for ( child: File <- in.listFiles ) {
+ createDownloadsFromBundle(child, out + "/" + child.getName)
+ }
+ } else {
+ if ( isBAM(in) ) {
+ add(new cpFile(in, out))
+ add(new md5sum(out))
+ } else if ( !isOUT(in) ) {
+ add(new GzipFile(in, out + ".gz"))
+ add(new md5sum(out + ".gz"))
+ }
+
+ }
+ }
+ }
+
+ def copyBundleFasta(res: Resource, ref: Reference) {
+ val out = destFile(BUNDLE_DIR, ref, res.destname(ref))
+ add(new cpFile(res.file, out))
+
+ val oldRefDict = swapExt(res.file.getParent, res.file, ".fasta", ".dict")
+ val newRefDict = swapExt(out.getParent, out, ".fasta", ".dict")
+
+ val oldRefFai = swapExt(res.file.getParent, res.file, ".fasta", ".fasta.fai")
+ val newRefFai = swapExt(out.getParent, out, ".fasta", ".fasta.fai")
+
+ add(new cpFile(oldRefDict, newRefDict))
+ add(new cpFile(oldRefFai, newRefFai))
+ }
+
+ def copyBundleFile(res: Resource, ref: Reference): File = {
+ val out = destFile(BUNDLE_DIR, ref, res.destname(ref))
+ add(new cpFile(res.file, out))
+ return out
+ }
+
+ def destFile(dir: File, ref: Reference, f: File): File = {
+ return destFile(dir, ref, f.getName)
+ }
+
+ def destFile(dir: File, ref: Reference, name: String): File = {
+ return new File(dir + "/" + ref.name + "/" + name)
+ }
+
+ /**
+ * A command line (cut) that removes all genotyping information from a file
+ */
+ class JustSites(@Input(doc="foo") in: File, @Output(doc="foo") out: File) extends CommandLineFunction {
+ def commandLine = "cut -f 1-8 %s > %s".format(in, out)
+ }
+
+ class GzipFile(@Input val in: File, @Output val out: File) extends CommandLineFunction {
+ def commandLine = "gzip -c %s > %s".format(in.getAbsolutePath, out.getAbsolutePath)
+ }
+
+ class cpFile(@Input val in: File, @Output val out: File) extends CommandLineFunction {
+ def commandLine = "cp %s %s".format(in.getAbsolutePath, out.getAbsolutePath)
+ }
+
+ class deleteLink(@Input val in: File) extends CommandLineFunction {
+ def commandLine = "rm %s".format(in.getAbsolutePath)
+ }
+
+ class linkFile(@Input val in: File, @Output val out: File) extends CommandLineFunction {
+ def commandLine = "ln -s %s %s".format(in.getAbsolutePath, out.getAbsolutePath)
+ }
+
+ class md5sum(@Input val in: File) extends CommandLineFunction {
+ @Output val o: File = new File(in.getAbsolutePath + ".md5")
+ def commandLine = "md5sum %s > %s".format(in.getAbsolutePath, o)
+ }
+
+ class IndexBAM(bamIn: File) extends SamtoolsIndexFunction {
+ bamFile = bamIn
+ }
+
+ class IndexVCF(@Input vcf: File, @Input ref: File) extends CountRODs with UNIVERSAL_GATK_ARGS {
+ //@Output val vcfIndex: File = swapExt(vcf.getParent, vcf, ".vcf", ".vcf.idx")
+ this.rod :+= vcf
+ this.reference_sequence = ref
+ }
+
+ class UG(@Input bam: File, @Input ref: File, @Input outVCF: File) extends UnifiedGenotyper with UNIVERSAL_GATK_ARGS {
+ this.input_file = List(bam)
+ this.reference_sequence = ref
+ this.intervalsString ++= List("20");
+ this.out = outVCF
+ }
+
+ class MakeDBSNP129(@Input dbsnp: File, @Input ref: File, @Output dbsnp129: File) extends SelectVariants with UNIVERSAL_GATK_ARGS {
+ this.variant = dbsnp
+ this.select ++= List("dbSNPBuildID <= 129")
+ this.reference_sequence = ref
+ this.out = dbsnp129
+ }
+
+ class LiftOverPerl(@Input val in: File, @Output val out: File, @Input val chain: File, oldRef: Reference, newRef: Reference) extends CommandLineFunction {
+ this.memoryLimit = 12
+ def commandLine = ("%s -vcf %s -chain %s -out %s " +
+ "-gatk ./ -newRef %s -oldRef %s -tmp %s").format(liftOverPerl, in.getAbsolutePath, chain,
+ out.getAbsolutePath, newRef.file.replace(".fasta", ""),
+ oldRef.file.replace(".fasta", ""), jobTempDir)
+ }
+
+ def getExtension(f: File): String = {
+ val i = f.getName.lastIndexOf('.');
+ if (i > 0 && i < f.getName.length() - 1)
+ return f.getName.substring(i+1).toLowerCase();
+ else
+ return "";
+ }
+}
+
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleCountLoci.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleCountLoci.scala
new file mode 100644
index 0000000..e988a42
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleCountLoci.scala
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts.examples
+
+import org.broadinstitute.gatk.queue.QScript
+import org.broadinstitute.gatk.queue.extensions.gatk._
+
+/**
+ * An introductory pipeline with integration tests testing the MD5 of the @Output.
+ */
+class ExampleCountLoci extends QScript {
+ @Input(doc="The reference file for the bam files.", shortName="R")
+ var referenceFile: File = null
+
+ @Input(doc="One or more bam files.", shortName="I")
+ var bamFiles: List[File] = Nil
+
+ @Input(doc="Intervals to traverse.", shortName="L", required=false)
+ var intervals: List[String] = Nil
+
+ @Output
+ var out: File = _
+
+ def script() {
+ val countLoci = new CountLoci
+ countLoci.reference_sequence = referenceFile
+ countLoci.input_file = bamFiles
+ countLoci.intervalsString = intervals
+ countLoci.out = out
+ countLoci.memoryLimit = 1
+ add(countLoci)
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleCountReads.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleCountReads.scala
new file mode 100644
index 0000000..55711c0
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleCountReads.scala
@@ -0,0 +1,87 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts.examples
+
+import org.broadinstitute.gatk.queue.QScript
+import org.broadinstitute.gatk.queue.extensions.gatk._
+
+/**
+ * An introductory pipeline for Queue.
+ * Runs the GATK CountReads individually and across a set of bams.
+ * All bams must have the same reference.
+ */
+class ExampleCountReads extends QScript {
+ @Input(doc="The reference file for the bam files.", shortName="R")
+ var referenceFile: File = null
+
+ // NOTE: Do not initialize List, Set, or Option to null
+ // as you won't be able to update the collection.
+ // By default set:
+ // List[T] = Nil
+ // Set[T] = Set.empty[T]
+ // Option[T] = None
+ @Input(doc="One or more bam files.", shortName="I")
+ var bamFiles: List[File] = Nil
+
+ /**
+ * In script, you create and then add() functions to the pipeline.
+ */
+ def script() {
+
+ // Run CountReads for all bams jointly.
+
+ // Create a new CountReads from the Queue GATK Extensions.
+ // The names of walkers are the same as you would use for '-T <WalkerName>'
+ val jointCountReads = new CountReads
+
+ // Each field in the extensions is based off of the full form of the arguments.
+ // To get the list of arguments and their descriptions run
+ // java -jar <path to GenomeAnalysisTK.jar> -T <WalkerName> -help
+ jointCountReads.reference_sequence = referenceFile
+
+ // GATK inputs that take more than one file will have a singular name which
+ // matches the full form of the argument, but will actually be a scala List[]
+ jointCountReads.input_file = bamFiles
+
+ // Set the memory limit. Also acts as a memory request on LSF and GridEngine.
+ jointCountReads.memoryLimit = 1
+
+ // Add the newly created function to the pipeline.
+ add(jointCountReads)
+
+ // If there is more than one BAM, also run CountReads once for each bam.
+ if (bamFiles.size > 1) {
+ for (bamFile <- bamFiles) {
+ val singleCountReads = new CountReads
+ singleCountReads.reference_sequence = referenceFile
+ // ':+' is the scala List append operator
+ singleCountReads.input_file :+= bamFile
+ singleCountReads.memoryLimit = 1
+ add(singleCountReads)
+ }
+ }
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleCustomWalker.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleCustomWalker.scala
new file mode 100644
index 0000000..e38ba3e
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleCustomWalker.scala
@@ -0,0 +1,73 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts.examples
+
+import org.broadinstitute.gatk.queue.QScript
+import org.broadinstitute.gatk.queue.extensions.gatk._
+
+/**
+ * A pipeline for Queue that runs a custom walker on the classpath.
+ * NOTE: This code is an unsupported example for soliciting feedback on how to improve Queue.
+ * Future syntax will simplify running the GATK so please expect the syntax below to change significantly.
+ */
+class ExampleCustomWalker extends QScript {
+ @Input(doc="The reference file for the bam files.", shortName="R")
+ var referenceFile: File = null
+
+ // NOTE: Do not initialize List, Set, or Option to null
+ // as you won't be able to update the collection.
+ // By default set:
+ // List[T] = Nil
+ // Set[T] = Set.empty[T]
+ // Option[T] = None
+ @Input(doc="One or more bam files.", shortName="I")
+ var bamFiles: List[File] = Nil
+
+ /**
+ * In script, you create and then add() functions to the pipeline.
+ */
+ def script() {
+ val customWalker = new CommandLineGATK {
+ // Set the name of your walker, for example this will be passed as -T MyCustomWalker
+ this.analysis_type = "MyCustomWalker"
+
+ // If your walker is already on the classpath you shouldn't need to do anything else
+
+ // If your walker is in a GATK jar that is for some reason NOT on the classpath
+ // nor referenced in the Queue.jar's, specify the jar file here
+ //this.jarFile = "myGATK.jar"
+
+ // If your walker needs a custom classpath, specify it here
+ //this.javaClasspath = List("myClasses")
+ }
+
+ customWalker.reference_sequence = referenceFile
+ customWalker.input_file = bamFiles
+
+ // Add the newly created function to the pipeline.
+ add(customWalker)
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExamplePrintReads.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExamplePrintReads.scala
new file mode 100644
index 0000000..440b6f2
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExamplePrintReads.scala
@@ -0,0 +1,53 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts.examples
+
+import org.broadinstitute.gatk.queue.QScript
+import org.broadinstitute.gatk.queue.extensions.gatk._
+
+/**
+ * Script used for testing output to /dev/null, deleting .bai files, etc.
+ */
+class ExamplePrintReads extends QScript {
+ @Input(doc="The reference file for the bam files.", shortName="R")
+ var referenceFile: File = _
+
+ @Input(doc="Bam file to genotype.", shortName="I")
+ var bamFile: File = _
+
+ @Output(doc="Bam output", shortName="out")
+ var outFile: File = _
+
+ def script() {
+ val printReads = new PrintReads
+ printReads.reference_sequence = referenceFile
+ printReads.memoryLimit = 2
+ printReads.scatterCount = 3
+ printReads.input_file :+= bamFile
+ printReads.out = outFile
+ add(printReads)
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleReadFilter.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleReadFilter.scala
new file mode 100644
index 0000000..f736406
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleReadFilter.scala
@@ -0,0 +1,48 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts.examples
+
+import org.broadinstitute.gatk.queue.QScript
+import org.broadinstitute.gatk.queue.extensions.gatk._
+
+/**
+ * Script used for testing inclusion of a read filter
+ */
+class ExampleReadFilter extends QScript {
+ @Input(doc="The reference file for the bam files.", shortName="R")
+ var referenceFile: File = _
+
+ @Input(doc="Bam file to genotype.", shortName="I")
+ var bamFile: File = _
+
+ def script() {
+ val printReads = new PrintReads with BadMate
+ printReads.reference_sequence = referenceFile
+ printReads.memoryLimit = 2
+ printReads.input_file :+= bamFile
+ add(printReads)
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleRetryMemoryLimit.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleRetryMemoryLimit.scala
new file mode 100644
index 0000000..71e0094
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/ExampleRetryMemoryLimit.scala
@@ -0,0 +1,53 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts.examples
+
+import org.broadinstitute.gatk.queue.function.RetryMemoryLimit
+import org.broadinstitute.gatk.queue.QScript
+import org.broadinstitute.gatk.queue.extensions.gatk._
+
+class ExampleRetryMemoryLimit extends QScript {
+ @Input(doc="The reference file for the bam files.", shortName="R")
+ var referenceFile: File = _
+
+ @Input(doc="Bam file to print.", shortName="I")
+ var bamFile: File = _
+
+ def script() {
+ for (scatterCount <- 1 to 2) {
+ val printReads = new PrintReads with RetryMemoryLimit
+ // First run with 1m
+ printReads.memoryLimit = .001
+ // On retry run with 1g
+ printReads.retryMemoryFunction = (d => d * 1000)
+ printReads.reference_sequence = referenceFile
+ printReads.input_file = Seq(bamFile)
+ printReads.out = swapExt(bamFile, ".bam", ".out.scattered_%d.bam".format(scatterCount))
+ printReads.scatterCount = scatterCount
+ add(printReads)
+ }
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/HelloWorld.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/HelloWorld.scala
new file mode 100644
index 0000000..c095169
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/examples/HelloWorld.scala
@@ -0,0 +1,36 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts.examples
+
+import org.broadinstitute.gatk.queue.QScript
+
+class HelloWorld extends QScript {
+ def script() {
+ add(new CommandLineFunction {
+ def commandLine = "echo hello world"
+ })
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/lib/ChunkVCF.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/lib/ChunkVCF.scala
new file mode 100644
index 0000000..ab687c0
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/lib/ChunkVCF.scala
@@ -0,0 +1,115 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts.lib
+
+import org.broadinstitute.gatk.queue.QScript
+import org.broadinstitute.gatk.queue.library.ipf.vcf.VCFExtractIntervals
+import scala.collection.JavaConversions._
+import org.broadinstitute.gatk.utils.text.XReadLines
+import java.io.PrintStream
+import org.broadinstitute.gatk.queue.extensions.gatk.SelectVariants
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: chartl
+ * Date: 2/2/12
+ * Time: 12:13 PM
+ * To change this template use File | Settings | File Templates.
+ */
+
+class ChunkVCF extends QScript {
+
+ @Input(shortName="V",fullName="VCF",doc="The VCF you want to chunk",required=true)
+ var inVCF : File = _
+
+ @Input(shortName="N",fullName="numEntriesInChunk",doc="The number of variants per chunk",required=true)
+ var numEntries : Int = _
+
+ @Input(shortName="I",fullName="Intervals",doc="The SNP interval list to chunk. If not provided, one will be created for you to provide in a second run.",required=false)
+ var intervals : File = _
+
+ @Input(fullName="preserveChromosomes",doc="Restrict chunks to one chromosome (smaller chunk at end of chromosome)",required=false)
+ var preserve : Boolean = false
+
+ @Input(fullName="reference",doc="The reference file",required=false)
+ var ref : File = new File("/humgen/1kg/reference/human_g1k_v37.fasta")
+
+ @Input(fullName="samples",doc="A file of sample IDs to condense VCF file to",required=false)
+ var extractSamples : File = _
+
+ val tmpdir : File = System.getProperty("java.io.tmpdir")
+
+ def script = {
+ if ( intervals == null ) {
+ // create an interval list from the VCF
+ val ivals : File = swapExt(inVCF,".vcf",".intervals.list")
+ val extract : VCFExtractIntervals = new VCFExtractIntervals(inVCF,ivals,false)
+ add(extract)
+ } else {
+ var chunkNum = 1
+ var numLinesInChunk = 0
+ var chromosome : String = asScalaIterator(new XReadLines(intervals)).next().split(":")(0)
+ var chunkFile : File = new File(tmpdir,"ChunkVCF.chunk%d.intervals.list".format(chunkNum))
+ var chunkWriter = new PrintStream(chunkFile)
+ asScalaIterator(new XReadLines(intervals)).foreach( int => {
+ // check new chromosome or full chunk
+ if ( ( preserve && ! int.split(":")(0).equals(chromosome) ) || numLinesInChunk > numEntries ) {
+ chunkWriter.close()
+ val chunkSelect : SelectVariants = new SelectVariants
+ chunkSelect.variant = inVCF
+ chunkSelect.reference_sequence = ref
+ chunkSelect.memoryLimit = 2
+ chunkSelect.intervals :+= chunkFile
+ if ( extractSamples != null )
+ chunkSelect.sample_file :+= extractSamples
+ chunkSelect.out = swapExt(inVCF,".vcf",".chunk%d.vcf".format(chunkNum))
+ add(chunkSelect)
+ chunkNum += 1
+ numLinesInChunk = 0
+ chromosome = int.split(":")(0)
+ chunkFile = new File(tmpdir,"ChunkVCF.chunk%d.intervals.list".format(chunkNum))
+ chunkWriter = new PrintStream(chunkFile)
+ }
+ chunkWriter.printf("%s%n",int)
+ numLinesInChunk += 1
+ })
+ // last chunk
+ if ( numLinesInChunk > 0 ) {
+ // some work to do
+ val chunkSelect : SelectVariants = new SelectVariants
+ chunkSelect.variant = inVCF
+ chunkSelect.reference_sequence = ref
+ chunkSelect.memoryLimit = 2
+ chunkSelect.intervals :+= chunkFile
+ chunkWriter.close()
+ if ( extractSamples != null )
+ chunkSelect.sample_file :+= extractSamples
+ chunkSelect.out = swapExt(inVCF,".vcf",".chunk%d.vcf".format(chunkNum))
+ add(chunkSelect)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/lib/Vcf2Table.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/lib/Vcf2Table.scala
new file mode 100755
index 0000000..eb57d2e
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/lib/Vcf2Table.scala
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts.lib
+
+import org.broadinstitute.sting.commandline.Hidden
+import org.broadinstitute.sting.queue.extensions.gatk.{RodBind, VariantsToTable}
+import org.broadinstitute.sting.queue.QScript
+import collection.JavaConversions._
+
+class Vcf2Table extends QScript {
+ @Argument(shortName="vcf",doc="VCF file",required=true) var vcf : File = _
+ @Argument(shortName="f",doc="Info fields to extract",required=false) var fields : java.util.List[String] = new java.util.ArrayList[String]
+ @Argument(shortName="o",doc="Output file",required=true) var output : File = _
+ @Argument(shortName="useFilters",doc="Use filtered sites?",required=false) var useFilters : Boolean = false
+ @Argument(shortName="r",doc="Reference file") var ref : File = _
+ @Argument(shortName="i",doc="Intervals",required=false) var ints : java.util.List[File] = new java.util.ArrayList[File]
+ @Argument(shortName="g",doc="gatk jar",required=true) var gatk: File = _
+
+
+ def script = {
+ var vcf2table : VariantsToTable = new VariantsToTable
+ vcf2table.rodBind :+= new RodBind("variant","vcf",vcf)
+ vcf2table.reference_sequence = ref
+ vcf2table.intervals = ints.toList
+ vcf2table.raw = useFilters
+ vcf2table.out = output
+ vcf2table.F = fields.toList
+ vcf2table.jarFile = gatk
+ add(vcf2table)
+
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/lib/VcfToPed.scala b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/lib/VcfToPed.scala
new file mode 100644
index 0000000..962d495
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/qscripts/org/broadinstitute/gatk/queue/qscripts/lib/VcfToPed.scala
@@ -0,0 +1,225 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.qscripts.lib
+
+import org.broadinstitute.gatk.queue.QScript
+import org.broadinstitute.gatk.utils.commandline.Input
+import org.broadinstitute.gatk.queue.library.ipf.vcf.VCFExtractIntervals
+import org.broadinstitute.gatk.utils.text.XReadLines
+import collection.JavaConversions._
+import java.io._
+import org.broadinstitute.gatk.queue.extensions.gatk.{SelectVariants, VariantsToPed}
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: chartl
+ * Date: 1/31/12
+ * Time: 10:46 PM
+ * To change this template use File | Settings | File Templates.
+ */
+
+class VcfToPed extends QScript {
+
+ @Input(shortName = "V", fullName="Variants", required=true,doc="VCF to convert to ped")
+ var variants : File = _
+
+ @Output(shortName = "B", fullName="Bed",required=true,doc="Name of the ped output file (fam and bim will use the root of this file)")
+ var bed : File = _
+
+ @Input(shortName = "M", fullName="Meta",required=true,doc="The sample metadata file, can be a .fam or [NAME]\\tkey1=val1;key2=val2")
+ var meta : File = _
+
+ @Input(shortName = "Int", fullName="Intervals",required=false,doc="Intervals. If not specified script will produce them and exit.")
+ var intervals : File = _
+
+ @Argument(shortName="R",fullName="Ref",required=false,doc="Reference file")
+ var ref : File = new File("/humgen/1kg/reference/human_g1k_v37.fasta")
+
+ @Argument(shortName="D",fullName="dbsnp",required=false,doc="dbsnp file")
+ var dbsnp : File = new File("/humgen/gsa-hpprojects/GATK/data/dbsnp_129_b37.vcf")
+
+ @Argument(shortName="sf",fullName="sampleFile",required=false,doc="sample file")
+ var samFile : File = _
+
+ val tmpdir : File = System.getProperty("java.io.tmpdir")
+
+ def script = {
+ if ( intervals == null ) {
+ val ivals : File = swapExt(variants,".vcf",".intervals.list")
+ val extract : VCFExtractIntervals = new VCFExtractIntervals(variants,ivals,false)
+ add(extract)
+ } else {
+ val IS_GZ : Boolean = variants.getName.endsWith(".vcf.gz")
+ var iXRL = new XReadLines(intervals)
+ var chunk = 1;
+ var subListFile : File = null
+ if ( IS_GZ )
+ subListFile = swapExt(tmpdir,variants,".vcf.gz",".chunk%d.list".format(chunk))
+ else
+ subListFile = swapExt(tmpdir,variants,".vcf",".chunk%d.list".format(chunk))
+ var subList = new PrintStream(subListFile)
+ var nL = 0;
+ var bedOuts : List[File] = Nil;
+ var bimOuts : List[File] = Nil
+ var lastFam : File = null;
+ while ( iXRL.hasNext ) {
+ subList.printf("%s%n",iXRL.next())
+ nL = nL + 1
+ if ( nL > 10000 ) {
+ val toPed : VariantsToPed = new VariantsToPed
+ toPed.memoryLimit = 2
+ toPed.reference_sequence = ref
+ toPed.intervals :+= subListFile
+ toPed.dbsnp = dbsnp
+ if ( samFile != null ) {
+ val base : String = bed.getName.stripSuffix(".bed")+"_%d".format(chunk)
+ val extract : SelectVariants = new SelectVariants
+ extract.reference_sequence = ref
+ extract.memoryLimit = 2
+ extract.intervals :+= subListFile
+ extract.variant = variants
+ extract.out = new File(tmpdir,base+"_extract%d.vcf".format(chunk))
+ extract.sample_file :+= samFile
+ add(extract)
+ toPed.variant = extract.out
+ } else {
+ toPed.variant = variants
+ }
+ toPed.metaData = meta
+ val base : String = bed.getName.stripSuffix(".bed")+"_%d".format(chunk)
+ val tBed = new File(tmpdir,base+".bed")
+ val bim = new File(tmpdir,base+".bim")
+ val fam = new File(tmpdir,base+".fam")
+ toPed.bed = tBed
+ toPed.bim = bim
+ toPed.fam = fam
+ add(toPed)
+ subList.close()
+ chunk = chunk + 1
+ if ( IS_GZ )
+ subListFile = swapExt(tmpdir,variants,".vcf.gz",".chunk%d.list".format(chunk))
+ else
+ subListFile = swapExt(tmpdir,variants,".vcf",".chunk%d.list".format(chunk))
+ subList = new PrintStream(subListFile)
+ bedOuts :+= tBed
+ bimOuts :+= bim
+ lastFam = fam
+ nL = 0;
+ }
+ }
+
+ if ( nL > 0 ) {
+ val toPed : VariantsToPed = new VariantsToPed
+ toPed.reference_sequence = ref
+ toPed.intervals :+= new File(subListFile)
+ toPed.dbsnp = dbsnp
+ if ( samFile != null ) {
+ val base : String = bed.getName.stripSuffix(".bed")+"_%d".format(chunk)
+ val extract : SelectVariants = new SelectVariants
+ extract.reference_sequence = ref
+ extract.memoryLimit = 2
+ extract.intervals :+= subListFile
+ extract.variant = variants
+ extract.out = new File(tmpdir,base+"_extract%d.vcf".format(chunk))
+ extract.sample_file :+= samFile
+ add(extract)
+ toPed.variant = extract.out
+ } else {
+ toPed.variant = variants
+ }
+ toPed.metaData = meta
+ toPed.memoryLimit = 2
+ val base : String = bed.getName.stripSuffix(".bed")+"_%d".format(chunk)
+ val tBed = new File(tmpdir,base+".bed")
+ val bim = new File(tmpdir,base+".bim")
+ val fam = new File(tmpdir,base+".fam")
+ toPed.bed = tBed
+ toPed.bim = bim
+ toPed.fam = fam
+ lastFam = fam
+ add(toPed)
+ subList.close()
+ bedOuts :+= tBed
+ bimOuts :+= bim
+ }
+
+ var gatherUP = new MyPedGather
+ gatherUP.binPed = bedOuts
+ gatherUP.bim = bimOuts
+ gatherUP.outPed = bed
+ gatherUP.outBim = swapExt(bed,".bed",".bim")
+
+ add(gatherUP)
+
+ class copyFam extends InProcessFunction {
+ @Input(doc="fam") var inFam = lastFam
+ @Output(doc="fam") var outFam = swapExt(bed,".bed",".fam")
+
+ def run = {
+ var stream = new PrintStream(outFam)
+ asScalaIterator(new XReadLines(inFam)).foreach( u => {
+ stream.printf("%s%n",u)
+ })
+ stream.close()
+ }
+ }
+
+ add(new copyFam)
+ }
+
+ }
+
+ class MyPedGather extends InProcessFunction {
+ @Input(doc="Peds to be merged") var binPed: List[File] = Nil
+ @Input(doc="Bims to be merged") var bim : List[File] = Nil
+ @Output(doc="The final Ped to write to") var outPed : File = _
+ @Output(doc="The final bim to write to") var outBim : File = _
+
+ def run : Unit = {
+ var stream : PrintStream = new PrintStream(outPed)
+ stream.write((List[Byte](0x6c.toByte,0x1b.toByte,0x1.toByte)).toArray)
+ binPed.map(u => new FileInputStream(u) ).foreach( u => {
+ u.skip(3)
+ var b = -1
+ do {
+ b = u.read()
+ stream.write(b.toByte)
+ } while ( b != -1 )
+ })
+ stream.close()
+
+ stream = new PrintStream(outBim)
+ bim.map(u => new XReadLines(u)).foreach( u => {
+ asScalaIterator(u).foreach( x => {
+ stream.printf("%s%n",x)
+ })
+ })
+
+ stream.close()
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/cancer/MuTect.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/cancer/MuTect.scala
new file mode 100644
index 0000000..36031d9
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/cancer/MuTect.scala
@@ -0,0 +1,420 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.cancer
+
+import java.io.File
+import org.broadinstitute.gatk.utils.commandline.Argument
+import org.broadinstitute.gatk.utils.commandline.Gather
+import org.broadinstitute.gatk.utils.commandline.Input
+import org.broadinstitute.gatk.utils.commandline.Output
+import org.broadinstitute.gatk.queue.function.scattergather.ScatterGatherableFunction
+import org.broadinstitute.gatk.queue.extensions.gatk.{TaggedFile, VcfGatherFunction, LocusScatterFunction}
+
+class MuTect extends org.broadinstitute.gatk.queue.extensions.gatk.CommandLineGATK with ScatterGatherableFunction {
+ analysisName = "MuTect"
+ analysis_type = "MuTect"
+ scatterClass = classOf[LocusScatterFunction]
+
+ /** used for debugging, basically exit as soon as we get the reads */
+ @Argument(fullName="noop", shortName="", doc="used for debugging, basically exit as soon as we get the reads", required=false, exclusiveOf="", validation="")
+ var noop: Boolean = _
+
+ /** add many additional columns of statistics to the output file */
+ @Argument(fullName="enable_extended_output", shortName="", doc="add many additional columns of statistics to the output file", required=false, exclusiveOf="", validation="")
+ var enable_extended_output: Boolean = _
+
+ /** used when running the caller on a normal (as if it were a tumor) to detect artifacts */
+ @Argument(fullName="artifact_detection_mode", shortName="", doc="used when running the caller on a normal (as if it were a tumor) to detect artifacts", required=false, exclusiveOf="", validation="")
+ var artifact_detection_mode: Boolean = _
+
+ /** name to use for tumor in output files */
+ @Argument(fullName="tumor_sample_name", shortName="", doc="name to use for tumor in output files", required=false, exclusiveOf="", validation="")
+ var tumor_sample_name: String = _
+
+ /** if the tumor bam contains multiple samples, only use read groups with SM equal to this value */
+ @Argument(fullName="bam_tumor_sample_name", shortName="", doc="if the tumor bam contains multiple samples, only use read groups with SM equal to this value", required=false, exclusiveOf="", validation="")
+ var bam_tumor_sample_name: String = _
+
+ /** name to use for normal in output files */
+ @Argument(fullName="normal_sample_name", shortName="", doc="name to use for normal in output files", required=false, exclusiveOf="", validation="")
+ var normal_sample_name: String = _
+
+ /** force output for each site */
+ @Argument(fullName="force_output", shortName="", doc="force output for each site", required=false, exclusiveOf="", validation="")
+ var force_output: Boolean = _
+
+ /** force output for all alleles at each site */
+ @Argument(fullName="force_alleles", shortName="", doc="force output for all alleles at each site", required=false, exclusiveOf="", validation="")
+ var force_alleles: Boolean = _
+
+ /** only emit passing calls */
+ @Argument(fullName="only_passing_calls", shortName="", doc="only emit passing calls", required=false, exclusiveOf="", validation="")
+ var only_passing_calls: Boolean = _
+
+ /** Initial LOD threshold for calling tumor variant */
+ @Argument(fullName="initial_tumor_lod", shortName="", doc="Initial LOD threshold for calling tumor variant", required=false, exclusiveOf="", validation="")
+ var initial_tumor_lod: Option[Float] = None
+
+ /** Format string for initial_tumor_lod */
+ @Argument(fullName="initial_tumor_lodFormat", shortName="", doc="Format string for initial_tumor_lod", required=false, exclusiveOf="", validation="")
+ var initial_tumor_lodFormat: String = "%s"
+
+ /** LOD threshold for calling tumor variant */
+ @Argument(fullName="tumor_lod", shortName="", doc="LOD threshold for calling tumor variant", required=false, exclusiveOf="", validation="")
+ var tumor_lod: Option[Float] = None
+
+ /** Format string for tumor_lod */
+ @Argument(fullName="tumor_lodFormat", shortName="", doc="Format string for tumor_lod", required=false, exclusiveOf="", validation="")
+ var tumor_lodFormat: String = "%s"
+
+ /** estimate of fraction (0-1) of physical contamination with other unrelated samples */
+ @Argument(fullName="fraction_contamination", shortName="", doc="estimate of fraction (0-1) of physical contamination with other unrelated samples", required=false, exclusiveOf="", validation="")
+ var fraction_contamination: Option[Float] = None
+
+ /** Format string for fraction_contamination */
+ @Argument(fullName="fraction_contaminationFormat", shortName="", doc="Format string for fraction_contamination", required=false, exclusiveOf="", validation="")
+ var fraction_contaminationFormat: String = "%s"
+
+ /** minimum fraction of cells which are presumed to have a mutation, used to handle non-clonality and contamination */
+ @Argument(fullName="minimum_mutation_cell_fraction", shortName="", doc="minimum fraction of cells which are presumed to have a mutation, used to handle non-clonality and contamination", required=false, exclusiveOf="", validation="")
+ var minimum_mutation_cell_fraction: Option[Float] = None
+
+ /** Format string for minimum_mutation_cell_fraction */
+ @Argument(fullName="minimum_mutation_cell_fractionFormat", shortName="", doc="Format string for minimum_mutation_cell_fraction", required=false, exclusiveOf="", validation="")
+ var minimum_mutation_cell_fractionFormat: String = "%s"
+
+ /** LOD threshold for calling normal non-germline */
+ @Argument(fullName="normal_lod", shortName="", doc="LOD threshold for calling normal non-germline", required=false, exclusiveOf="", validation="")
+ var normal_lod: Option[Float] = None
+
+ /** Format string for normal_lod */
+ @Argument(fullName="normal_lodFormat", shortName="", doc="Format string for normal_lod", required=false, exclusiveOf="", validation="")
+ var normal_lodFormat: String = "%s"
+
+ /** LOD threshold for calling normal non-variant */
+ @Argument(fullName="normal_artifact_lod", shortName="", doc="LOD threshold for calling normal non-variant", required=false, exclusiveOf="", validation="")
+ var normal_artifact_lod: Option[Float] = None
+
+ /** Format string for normal_artifact_lod */
+ @Argument(fullName="normal_artifact_lodFormat", shortName="", doc="Format string for normal_artifact_lod", required=false, exclusiveOf="", validation="")
+ var normal_artifact_lodFormat: String = "%s"
+
+ /** LOD threshold for calling strand bias */
+ @Argument(fullName="strand_artifact_lod", shortName="", doc="LOD threshold for calling strand bias", required=false, exclusiveOf="", validation="")
+ var strand_artifact_lod: Option[Float] = None
+
+ /** Format string for strand_artifact_lod */
+ @Argument(fullName="strand_artifact_lodFormat", shortName="", doc="Format string for strand_artifact_lod", required=false, exclusiveOf="", validation="")
+ var strand_artifact_lodFormat: String = "%s"
+
+ /** power threshold for calling strand bias */
+ @Argument(fullName="strand_artifact_power_threshold", shortName="", doc="power threshold for calling strand bias", required=false, exclusiveOf="", validation="")
+ var strand_artifact_power_threshold: Option[Float] = None
+
+ /** Format string for strand_artifact_power_threshold */
+ @Argument(fullName="strand_artifact_power_thresholdFormat", shortName="", doc="Format string for strand_artifact_power_threshold", required=false, exclusiveOf="", validation="")
+ var strand_artifact_power_thresholdFormat: String = "%s"
+
+ /** LOD threshold for calling normal non-variant at dbsnp sites */
+ @Argument(fullName="dbsnp_normal_lod", shortName="", doc="LOD threshold for calling normal non-variant at dbsnp sites", required=false, exclusiveOf="", validation="")
+ var dbsnp_normal_lod: Option[Float] = None
+
+ /** Format string for dbsnp_normal_lod */
+ @Argument(fullName="dbsnp_normal_lodFormat", shortName="", doc="Format string for dbsnp_normal_lod", required=false, exclusiveOf="", validation="")
+ var dbsnp_normal_lodFormat: String = "%s"
+
+ /** Power threshold for normal to determine germline vs variant */
+ @Argument(fullName="somatic_classification_normal_power_threshold", shortName="", doc="Power threshold for normal to determine germline vs variant", required=false, exclusiveOf="", validation="")
+ var somatic_classification_normal_power_threshold: Option[Float] = None
+
+ /** Format string for somatic_classification_normal_power_threshold */
+ @Argument(fullName="somatic_classification_normal_power_thresholdFormat", shortName="", doc="Format string for somatic_classification_normal_power_threshold", required=false, exclusiveOf="", validation="")
+ var somatic_classification_normal_power_thresholdFormat: String = "%s"
+
+ /** minimum allele fraction to be considered in normal, useful for normal sample contaminated with tumor */
+ @Argument(fullName="minimum_normal_allele_fraction", shortName="", doc="minimum allele fraction to be considered in normal, useful for normal sample contaminated with tumor", required=false, exclusiveOf="", validation="")
+ var minimum_normal_allele_fraction: Option[Float] = None
+
+ /** Format string for minimum_normal_allele_fraction */
+ @Argument(fullName="minimum_normal_allele_fractionFormat", shortName="", doc="Format string for minimum_normal_allele_fraction", required=false, exclusiveOf="", validation="")
+ var minimum_normal_allele_fractionFormat: String = "%s"
+
+ /** for computational efficiency, reject sites with allelic fraction below this threshold */
+ @Argument(fullName="tumor_f_pretest", shortName="", doc="for computational efficiency, reject sites with allelic fraction below this threshold", required=false, exclusiveOf="", validation="")
+ var tumor_f_pretest: Option[Float] = None
+
+ /** Format string for tumor_f_pretest */
+ @Argument(fullName="tumor_f_pretestFormat", shortName="", doc="Format string for tumor_f_pretest", required=false, exclusiveOf="", validation="")
+ var tumor_f_pretestFormat: String = "%s"
+
+ /** threshold for minimum base quality score */
+ @Argument(fullName="min_qscore", shortName="", doc="threshold for minimum base quality score", required=false, exclusiveOf="", validation="")
+ var min_qscore: Option[Int] = None
+
+ /** how many gapped events (ins/del) are allowed in proximity to this candidate */
+ @Argument(fullName="gap_events_threshold", shortName="", doc="how many gapped events (ins/del) are allowed in proximity to this candidate", required=false, exclusiveOf="", validation="")
+ var gap_events_threshold: Option[Int] = None
+
+ /** if this fraction or more of the bases in a read are soft/hard clipped, do not use this read for mutation calling */
+ @Argument(fullName="heavily_clipped_read_fraction", shortName="", doc="if this fraction or more of the bases in a read are soft/hard clipped, do not use this read for mutation calling", required=false, exclusiveOf="", validation="")
+ var heavily_clipped_read_fraction: Option[Float] = None
+
+ /** Format string for heavily_clipped_read_fraction */
+ @Argument(fullName="heavily_clipped_read_fractionFormat", shortName="", doc="Format string for heavily_clipped_read_fraction", required=false, exclusiveOf="", validation="")
+ var heavily_clipped_read_fractionFormat: String = "%s"
+
+ /** pvalue threshold for fishers exact test of clipping bias in mutant reads vs ref reads */
+ @Argument(fullName="clipping_bias_pvalue_threshold", shortName="", doc="pvalue threshold for fishers exact test of clipping bias in mutant reads vs ref reads", required=false, exclusiveOf="", validation="")
+ var clipping_bias_pvalue_threshold: Option[Float] = None
+
+ /** Format string for clipping_bias_pvalue_threshold */
+ @Argument(fullName="clipping_bias_pvalue_thresholdFormat", shortName="", doc="Format string for clipping_bias_pvalue_threshold", required=false, exclusiveOf="", validation="")
+ var clipping_bias_pvalue_thresholdFormat: String = "%s"
+
+ /** threshold for determining if there is relatedness between the alt and ref allele read piles */
+ @Argument(fullName="fraction_mapq0_threshold", shortName="", doc="threshold for determining if there is relatedness between the alt and ref allele read piles", required=false, exclusiveOf="", validation="")
+ var fraction_mapq0_threshold: Option[Float] = None
+
+ /** Format string for fraction_mapq0_threshold */
+ @Argument(fullName="fraction_mapq0_thresholdFormat", shortName="", doc="Format string for fraction_mapq0_threshold", required=false, exclusiveOf="", validation="")
+ var fraction_mapq0_thresholdFormat: String = "%s"
+
+ /** threshold for clustered read position artifact median */
+ @Argument(fullName="pir_median_threshold", shortName="", doc="threshold for clustered read position artifact median", required=false, exclusiveOf="", validation="")
+ var pir_median_threshold: Option[Double] = None
+
+ /** Format string for pir_median_threshold */
+ @Argument(fullName="pir_median_thresholdFormat", shortName="", doc="Format string for pir_median_threshold", required=false, exclusiveOf="", validation="")
+ var pir_median_thresholdFormat: String = "%s"
+
+ /** threshold for clustered read position artifact MAD */
+ @Argument(fullName="pir_mad_threshold", shortName="", doc="threshold for clustered read position artifact MAD", required=false, exclusiveOf="", validation="")
+ var pir_mad_threshold: Option[Double] = None
+
+ /** Format string for pir_mad_threshold */
+ @Argument(fullName="pir_mad_thresholdFormat", shortName="", doc="Format string for pir_mad_threshold", required=false, exclusiveOf="", validation="")
+ var pir_mad_thresholdFormat: String = "%s"
+
+ /** required minimum value for tumor alt allele maximum mapping quality score */
+ @Argument(fullName="required_maximum_alt_allele_mapping_quality_score", shortName="", doc="required minimum value for tumor alt allele maximum mapping quality score", required=false, exclusiveOf="", validation="")
+ var required_maximum_alt_allele_mapping_quality_score: Option[Int] = None
+
+ /** threshold for maximum alternate allele counts in normal */
+ @Argument(fullName="max_alt_alleles_in_normal_count", shortName="", doc="threshold for maximum alternate allele counts in normal", required=false, exclusiveOf="", validation="")
+ var max_alt_alleles_in_normal_count: Option[Int] = None
+
+ /** threshold for maximum alternate allele quality score sum in normal */
+ @Argument(fullName="max_alt_alleles_in_normal_qscore_sum", shortName="", doc="threshold for maximum alternate allele quality score sum in normal", required=false, exclusiveOf="", validation="")
+ var max_alt_alleles_in_normal_qscore_sum: Option[Int] = None
+
+ /** threshold for maximum alternate allele fraction in normal */
+ @Argument(fullName="max_alt_allele_in_normal_fraction", shortName="", doc="threshold for maximum alternate allele fraction in normal", required=false, exclusiveOf="", validation="")
+ var max_alt_allele_in_normal_fraction: Option[Double] = None
+
+ /** Format string for max_alt_allele_in_normal_fraction */
+ @Argument(fullName="max_alt_allele_in_normal_fractionFormat", shortName="", doc="Format string for max_alt_allele_in_normal_fraction", required=false, exclusiveOf="", validation="")
+ var max_alt_allele_in_normal_fractionFormat: String = "%s"
+
+ /** Phred scale quality score constant to use in power calculations */
+ @Argument(fullName="power_constant_qscore", shortName="", doc="Phred scale quality score constant to use in power calculations", required=false, exclusiveOf="", validation="")
+ var power_constant_qscore: Option[Int] = None
+
+ /** Absolute Copy Number Data, as defined by Absolute, to use in power calculations */
+ @Argument(fullName="absolute_copy_number_data", shortName="", doc="Absolute Copy Number Data, as defined by Absolute, to use in power calculations", required=false, exclusiveOf="", validation="")
+ var absolute_copy_number_data: File = _
+
+ /** Allelic fraction constant to use in power calculations */
+ @Argument(fullName="power_constant_af", shortName="", doc="Allelic fraction constant to use in power calculations", required=false, exclusiveOf="", validation="")
+ var power_constant_af: Option[Double] = None
+
+ /** Format string for power_constant_af */
+ @Argument(fullName="power_constant_afFormat", shortName="", doc="Format string for power_constant_af", required=false, exclusiveOf="", validation="")
+ var power_constant_afFormat: String = "%s"
+
+ /** Call-stats output */
+ @Output(fullName="out", shortName="o", doc="Call-stats output", required=false, exclusiveOf="", validation="")
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ var out: File = _
+
+ /**
+ * Short name of out
+ * @return Short name of out
+ */
+ def o = this.out
+
+ /**
+ * Short name of out
+ * @param value Short name of out
+ */
+ def o_=(value: File) { this.out = value }
+
+ /** VCF output of mutation candidates */
+ @Output(fullName="vcf", shortName="vcf", doc="VCF output of mutation candidates", required=false, exclusiveOf="", validation="")
+ @Gather(classOf[VcfGatherFunction])
+ var vcf: File = _
+
+ /** Automatically generated index for vcf */
+ @Output(fullName="vcfIndex", shortName="", doc="Automatically generated index for vcf", required=false, exclusiveOf="", validation="")
+ @Gather(enabled=false)
+ private var vcfIndex: File = _
+
+ /** VCF file of DBSNP information */
+ @Input(fullName="dbsnp", shortName="dbsnp", doc="VCF file of DBSNP information", required=false, exclusiveOf="", validation="")
+ var dbsnp: Seq[File] = Nil
+
+ /** Dependencies on any indexes of dbsnp */
+ @Input(fullName="dbsnpIndexes", shortName="", doc="Dependencies on any indexes of dbsnp", required=false, exclusiveOf="", validation="")
+ private var dbsnpIndexes: Seq[File] = Nil
+
+ /** VCF file of COSMIC sites */
+ @Input(fullName="cosmic", shortName="cosmic", doc="VCF file of COSMIC sites", required=false, exclusiveOf="", validation="")
+ var cosmic: Seq[File] = Nil
+
+ /** Dependencies on any indexes of cosmic */
+ @Input(fullName="cosmicIndexes", shortName="", doc="Dependencies on any indexes of cosmic", required=false, exclusiveOf="", validation="")
+ private var cosmicIndexes: Seq[File] = Nil
+
+ /** VCF file of sites observed in normal */
+ @Input(fullName="normal_panel", shortName="normal_panel", doc="VCF file of sites observed in normal", required=false, exclusiveOf="", validation="")
+ var normal_panel: Seq[File] = Nil
+
+ /** Dependencies on any indexes of normal_panel */
+ @Input(fullName="normal_panelIndexes", shortName="", doc="Dependencies on any indexes of normal_panel", required=false, exclusiveOf="", validation="")
+ private var normal_panelIndexes: Seq[File] = Nil
+
+ /** write out coverage in WIGGLE format to this file */
+ @Output(fullName="coverage_file", shortName="cov", doc="write out coverage in WIGGLE format to this file", required=false, exclusiveOf="", validation="")
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ var coverage_file: File = _
+
+ /**
+ * Short name of coverage_file
+ * @return Short name of coverage_file
+ */
+ def cov = this.coverage_file
+
+ /**
+ * Short name of coverage_file
+ * @param value Short name of coverage_file
+ */
+ def cov_=(value: File) { this.coverage_file = value }
+
+ /** write out 20x of Q20 coverage in WIGGLE format to this file */
+ @Output(fullName="coverage_20_q20_file", shortName="cov_q20", doc="write out 20x of Q20 coverage in WIGGLE format to this file", required=false, exclusiveOf="", validation="")
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ var coverage_20_q20_file: File = _
+
+ /**
+ * Short name of coverage_20_q20_file
+ * @return Short name of coverage_20_q20_file
+ */
+ def cov_q20 = this.coverage_20_q20_file
+
+ /**
+ * Short name of coverage_20_q20_file
+ * @param value Short name of coverage_20_q20_file
+ */
+ def cov_q20_=(value: File) { this.coverage_20_q20_file = value }
+
+ /** write out power in WIGGLE format to this file */
+ @Output(fullName="power_file", shortName="pow", doc="write out power in WIGGLE format to this file", required=false, exclusiveOf="", validation="")
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ var power_file: File = _
+
+ /**
+ * Short name of power_file
+ * @return Short name of power_file
+ */
+ def pow = this.power_file
+
+ /**
+ * Short name of power_file
+ * @param value Short name of power_file
+ */
+ def pow_=(value: File) { this.power_file = value }
+
+ /** write out tumor read depth in WIGGLE format to this file */
+ @Output(fullName="tumor_depth_file", shortName="tdf", doc="write out tumor read depth in WIGGLE format to this file", required=false, exclusiveOf="", validation="")
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ var tumor_depth_file: File = _
+
+ /**
+ * Short name of tumor_depth_file
+ * @return Short name of tumor_depth_file
+ */
+ def tdf = this.tumor_depth_file
+
+ /**
+ * Short name of tumor_depth_file
+ * @param value Short name of tumor_depth_file
+ */
+ def tdf_=(value: File) { this.tumor_depth_file = value }
+
+ /** write out normal read depth in WIGGLE format to this file */
+ @Output(fullName="normal_depth_file", shortName="ndf", doc="write out normal read depth in WIGGLE format to this file", required=false, exclusiveOf="", validation="")
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ var normal_depth_file: File = _
+
+ /**
+ * Short name of normal_depth_file
+ * @return Short name of normal_depth_file
+ */
+ def ndf = this.normal_depth_file
+
+ /**
+ * Short name of normal_depth_file
+ * @param value Short name of normal_depth_file
+ */
+ def ndf_=(value: File) { this.normal_depth_file = value }
+
+ /** if a read has mismatching number of bases and base qualities, filter out the read instead of blowing up. */
+ @Argument(fullName="filter_mismatching_base_and_quals", shortName="filterMBQ", doc="if a read has mismatching number of bases and base qualities, filter out the read instead of blowing up.", required=false, exclusiveOf="", validation="")
+ var filter_mismatching_base_and_quals: Boolean = _
+
+ /**
+ * Short name of filter_mismatching_base_and_quals
+ * @return Short name of filter_mismatching_base_and_quals
+ */
+ def filterMBQ = this.filter_mismatching_base_and_quals
+
+ /**
+ * Short name of filter_mismatching_base_and_quals
+ * @param value Short name of filter_mismatching_base_and_quals
+ */
+ def filterMBQ_=(value: Boolean) { this.filter_mismatching_base_and_quals = value }
+
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+ if (vcf != null && !org.broadinstitute.gatk.utils.io.IOUtils.isSpecialFile(vcf))
+ if (!org.broadinstitute.gatk.engine.io.stubs.VCFWriterArgumentTypeDescriptor.isCompressed(vcf.getPath))
+ vcfIndex = new File(vcf.getPath + ".idx")
+ dbsnpIndexes ++= dbsnp.filter(orig => orig != null).map(orig => new File(orig.getPath + ".idx"))
+ cosmicIndexes ++= cosmic.filter(orig => orig != null).map(orig => new File(orig.getPath + ".idx"))
+ normal_panelIndexes ++= normal_panel.filter(orig => orig != null).map(orig => new File(orig.getPath + ".idx"))
+ }
+
+ override def commandLine = super.commandLine + conditional(noop, "--noop", escape=true, format="%s") + conditional(enable_extended_output, "--enable_extended_output", escape=true, format="%s") + conditional(artifact_detection_mode, "--artifact_detection_mode", escape=true, format="%s") + optional("--tumor_sample_name", tumor_sample_name, spaceSeparated=true, escape=true, format="%s") + optional("--bam_tumor_sample_name", bam_tumor_sample_name, spaceSeparated=true, escape=true, format=" [...]
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/BamGatherFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/BamGatherFunction.scala
new file mode 100644
index 0000000..5388510
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/BamGatherFunction.scala
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import org.broadinstitute.gatk.queue.function.scattergather.GatherFunction
+import org.broadinstitute.gatk.queue.extensions.picard.MergeSamFiles
+import org.broadinstitute.gatk.queue.function.RetryMemoryLimit
+import java.io.File
+
+/**
+ * Merges BAM files using htsjdk.samtools.MergeSamFiles.
+ */
+class BamGatherFunction extends MergeSamFiles with GatherFunction with RetryMemoryLimit {
+ this.assumeSorted = Some(true)
+
+ override def freezeFieldValues() {
+ this.input = this.gatherParts
+ this.output = this.originalOutput
+ //Left to its own devices (ie, MergeSamFiles.freezeFieldValues), outputIndex
+ //will be in the gather directory. Ensure that it actually matches this.output
+ if (output != null)
+ outputIndex = new File(output.getParentFile, output.getName.stripSuffix(".bam") + ".bai")
+
+ val originalGATK = originalFunction.asInstanceOf[CommandLineGATK]
+
+ // Whatever the original function can handle, merging *should* do less.
+ this.memoryLimit = originalFunction.memoryLimit
+ this.compressionLevel = originalGATK.bam_compression
+ this.createIndex = Some(!originalGATK.disable_bam_indexing)
+ this.createMD5 = Some(originalGATK.generate_md5)
+
+ super.freezeFieldValues()
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/CatVariantsGatherer.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/CatVariantsGatherer.scala
new file mode 100644
index 0000000..fd91e53
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/CatVariantsGatherer.scala
@@ -0,0 +1,59 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import org.broadinstitute.gatk.queue.function.RetryMemoryLimit
+import org.broadinstitute.gatk.queue.function.scattergather.GatherFunction
+
+
+/**
+ *
+ * Currently this is the default gather for VCFs.
+ * One can set a specific gatherer to use by adding @Gather before any output argument.
+ * For example (used to be part of UG):
+ * @Gather(className = "org.broadinstitute.gatk.queue.extensions.gatk.CatVariantsGatherer")
+ * @Output(doc="File to which variants should be written",required=true)
+ * protected VariantContextWriter writer = null;
+ */
+class CatVariantsGatherer extends CatVariants with GatherFunction with RetryMemoryLimit{
+ this.assumeSorted = true
+
+ private lazy val originalGATK = this.originalFunction.asInstanceOf[CommandLineGATK]
+
+ override def freezeFieldValues() {
+ this.reference = originalGATK.reference_sequence
+ this.variant = this.gatherParts.zipWithIndex map { case (input, index) => new TaggedFile(input, "input"+index) }
+ this.outputFile = this.originalOutput
+ this.assumeSorted = true
+ this.variant_index_type = originalGATK.variant_index_type
+ this.variant_index_parameter = originalGATK.variant_index_parameter
+
+ super.freezeFieldValues()
+ }
+
+
+
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/ContigScatterFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/ContigScatterFunction.scala
new file mode 100644
index 0000000..7eff645
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/ContigScatterFunction.scala
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import collection.JavaConversions._
+import org.broadinstitute.gatk.utils.interval.IntervalUtils
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+
+/**
+ * Splits intervals by contig instead of evenly.
+ */
+class ContigScatterFunction extends GATKScatterFunction with InProcessFunction {
+ // Include unmapped reads by default.
+ this.includeUnmapped = true
+
+ override def scatterCount = if (intervalFilesExist) super.scatterCount min this.maxIntervals else super.scatterCount
+
+ protected override def maxIntervals = {
+ GATKScatterFunction.getGATKIntervals(this.originalGATK).contigs.size
+ }
+
+ def run() {
+ val gi = GATKScatterFunction.getGATKIntervals(this.originalGATK)
+ IntervalUtils.scatterContigIntervals(gi.samFileHeader, gi.locs, this.scatterOutputFiles)
+ }
+}
+
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/DistributedScatterFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/DistributedScatterFunction.scala
new file mode 100644
index 0000000..f4ad993
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/DistributedScatterFunction.scala
@@ -0,0 +1,52 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import java.io.File
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+import org.broadinstitute.gatk.queue.function.scattergather.{ScatterFunction, CloneFunction}
+import org.broadinstitute.gatk.utils.commandline.Output
+import util.Random
+
+/**
+ * An scatter function that uses the Distributed GATK.
+ */
+class DistributedScatterFunction extends ScatterFunction with InProcessFunction {
+ @Output(doc="processingTracker")
+ var processingTracker: File = _
+
+ override def init() {
+ this.processingTracker = new File(this.commandDirectory, "processingTracker.%8d".format(Random.nextInt(100000000)))
+ }
+
+ override def initCloneInputs(cloneFunction: CloneFunction, index: Int) {
+ cloneFunction.setFieldValue("processingTracker", this.processingTracker)
+ }
+
+ def run() {
+ /* doesn't actually need to run. */
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/DoC/package.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/DoC/package.scala
new file mode 100644
index 0000000..fd54be6
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/DoC/package.scala
@@ -0,0 +1,242 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import java.io.{PrintStream, PrintWriter, File}
+import org.broadinstitute.gatk.queue.function.scattergather.ScatterGatherableFunction
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType
+import org.broadinstitute.gatk.utils.commandline.{Input, Gather, Output}
+import org.broadinstitute.gatk.queue.function.{InProcessFunction, CommandLineFunction}
+import org.broadinstitute.gatk.tools.walkers.coverage.CoverageUtils
+import scala.collection.JavaConversions._
+import scala.Some
+import org.broadinstitute.gatk.utils.text.XReadLines
+import org.broadinstitute.gatk.queue.util.VCF_BAM_utilities
+
+// Minimal refactor from a package object to a file full of classes/objects
+// due to ongoing bugs with inner classes/objects in package objects:
+// https://issues.scala-lang.org/browse/SI-4344
+// https://issues.scala-lang.org/browse/SI-5954
+ class DoC(val bams: List[File], val DoC_output: File, val countType: CoverageUtils.CountPileupType, val MAX_DEPTH: Int, val minMappingQuality: Int, val minBaseQuality: Int, val scatterCountInput: Int, val START_BIN: Int, val NUM_BINS: Int, val minCoverageCalcs: Seq[Int], val sampleRenameMappingFile: Option[File] = None) extends CommandLineGATK with ScatterGatherableFunction {
+ val DOC_OUTPUT_SUFFIX: String = ".sample_interval_summary"
+
+ // So that the output files of this DoC run get deleted once they're used further downstream:
+ this.isIntermediate = true
+
+ this.analysis_type = "DepthOfCoverage"
+
+ this.input_file = bams
+ if (sampleRenameMappingFile.isDefined)
+ this.sample_rename_mapping_file = sampleRenameMappingFile.get
+
+ this.downsample_to_coverage = Some(MAX_DEPTH)
+ this.downsampling_type = DownsampleType.BY_SAMPLE
+
+ this.scatterCount = scatterCountInput
+ this.scatterClass = classOf[IntervalScatterFunction]
+
+ // HACK for DoC to work properly within Queue:
+ @Output
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ var intervalSampleOut: File = new File(DoC_output.getPath + DOC_OUTPUT_SUFFIX)
+
+ override def commandLine = super.commandLine +
+ " --omitDepthOutputAtEachBase" +
+ " --omitLocusTable" +
+ " --minMappingQuality " + minMappingQuality +
+ " --minBaseQuality " + minBaseQuality +
+ optional("--countType", countType, spaceSeparated=true, escape=true, format="%s") +
+ " --start " + START_BIN + " --stop " + MAX_DEPTH + " --nBins " + NUM_BINS +
+ (if (!minCoverageCalcs.isEmpty) minCoverageCalcs.map(cov => " --summaryCoverageThreshold " + cov).reduceLeft(_ + "" + _) else "") +
+ " --includeRefNSites" +
+ " -o " + DoC_output
+
+ override def shortDescription = "DoC: " + DoC_output
+ }
+
+ class DoCwithDepthOutputAtEachBase(bams: List[File], DoC_output: File, countType: CoverageUtils.CountPileupType, MAX_DEPTH: Int, minMappingQuality: Int, minBaseQuality: Int, scatterCountInput: Int, START_BIN: Int, NUM_BINS: Int, minCoverageCalcs: Seq[Int], sampleRenameMappingFile: Option[File] = None) extends DoC(bams, DoC_output, countType: CoverageUtils.CountPileupType, MAX_DEPTH: Int, minMappingQuality, minBaseQuality, scatterCountInput, START_BIN, NUM_BINS, minCoverageCalcs, sample [...]
+ // HACK for DoC to work properly within Queue:
+ @Output
+ @Gather(classOf[org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction])
+ var outPrefix = DoC_output
+
+ override def commandLine = super.commandLine.replaceAll(" --omitDepthOutputAtEachBase", "")
+ }
+
+ // A group has a list of samples and bam files to use for DoC
+ class Group(val name: String, val outputBase: File, val samples: List[String], val bams: List[File]) {
+ // getName() just includes the file name WITHOUT the path:
+ val groupOutputName = name + "." + outputBase.getName
+
+ // Comment this out, so that when jobs are scattered in DoC class below, they do not scatter into outputs at directories that don't exist!!! :
+ //def DoC_output = new File(outputBase.getParentFile(), groupOutputName)
+
+ def DoC_output = new File(groupOutputName)
+
+ override def toString(): String = String.format("[Group %s [%s] with samples %s against bams %s]", name, DoC_output, samples, bams)
+ }
+
+ class MergeGATKdepths(DoCsToCombine: List[File], outFile: String, columnSuffix: String, xhmmExec: File, rdPrecisionArg: Option[Int], outputTargetsBySamples: Boolean, sampleIDsMap: String = "", sampleIDsMapFromColumn: Int = 1, sampleIDsMapToColumn: Int = 2) extends CommandLineFunction {
+ @Input(doc = "")
+ var inputDoCfiles: List[File] = DoCsToCombine
+
+ @Output
+ val mergedDoC: File = new File(outFile)
+ var command: String =
+ xhmmExec + " --mergeGATKdepths" +
+ inputDoCfiles.map(input => " --GATKdepths " + input).reduceLeft(_ + "" + _) +
+ " --columnSuffix " + columnSuffix +
+ " -o " + mergedDoC
+ if (sampleIDsMap != "")
+ command += " --sampleIDmap " + sampleIDsMap + " --fromID " + sampleIDsMapFromColumn + " --toID " + sampleIDsMapToColumn
+ rdPrecisionArg match {
+ case Some(rdPrecision) => {
+ command += " --rdPrecision " + rdPrecision
+ }
+ case None => {}
+ }
+ if (outputTargetsBySamples)
+ command += " --outputTargetsBySamples"
+
+ def commandLine = command
+
+ override def description = "Combines DoC outputs for multiple samples (at same loci): " + command
+ }
+
+ class PrepareTargets(intervalsIn: List[File], outIntervals: String, val xhmmExec: File, val referenceFile: File) extends CommandLineFunction {
+ @Input(doc = "List of files containing targeted intervals to be prepared and merged")
+ var inIntervals: List[File] = intervalsIn
+
+ @Output(doc = "The merged intervals file to write to")
+ var out: File = new File(outIntervals)
+
+ var command: String =
+ xhmmExec + " --prepareTargets" +
+ " -F " + referenceFile +
+ inIntervals.map(intervFile => " --targets " + intervFile).reduceLeft(_ + "" + _) +
+ " --mergedTargets " + out
+
+ def commandLine = command
+
+ override def description = "Sort all target intervals, merge overlapping ones, and print the resulting interval list: " + command
+ }
+
+ class ParsedBamListWithOptionalSampleMappings(bamsFile: File) {
+ var bams = bamsFile
+
+ var allBams = List[File]()
+ var bamsWithoutSampleMapping = List[File]()
+ var userMappedSampleToBams = scala.collection.mutable.Map.empty[String, scala.collection.mutable.Set[File]]
+
+ var sampleToBams = scala.collection.mutable.Map.empty[String, scala.collection.mutable.Set[File]]
+ }
+
+object DoC {
+ def buildDoCgroups(samples: List[String], sampleToBams: scala.collection.mutable.Map[String, scala.collection.mutable.Set[File]], samplesPerJob: Int, outputBase: File): List[Group] = {
+ var l: List[Group] = Nil
+
+ var remaining = samples
+ var subsamples: List[String] = Nil
+ var count = 1
+
+ while (!remaining.isEmpty) {
+ val splitRes = (remaining splitAt samplesPerJob)
+ subsamples = splitRes._1
+ remaining = splitRes._2
+ l ::= new Group("group" + count, outputBase, subsamples, VCF_BAM_utilities.findBAMsForSamples(subsamples, sampleToBams))
+ count = count + 1
+ }
+
+ return l
+ }
+
+ def parseBamListWithOptionalSampleMappings(bamsFile: File): ParsedBamListWithOptionalSampleMappings = {
+ val r = new ParsedBamListWithOptionalSampleMappings(bamsFile)
+
+ val rows = asScalaIterator(new XReadLines(r.bams))
+
+ while (rows.hasNext) {
+ val line = rows.next
+ val splitLine = line.split("\\t")
+
+ if (splitLine.length < 1 || splitLine.length > 2)
+ throw new Exception("Invalid row in " + bamsFile.getPath + " : " + line)
+
+ val bam = splitLine(0)
+ val bamFile = new File(bam)
+ r.allBams ::= bamFile
+
+ if (splitLine.length == 2) {
+ val sampleName = splitLine(1)
+
+ if (r.userMappedSampleToBams.contains(sampleName))
+ throw new Exception("Cannot map multiple BAM files to the same sample name: " + sampleName)
+
+ r.userMappedSampleToBams += sampleName -> (scala.collection.mutable.Set.empty[File] + bamFile)
+ }
+ else {
+ r.bamsWithoutSampleMapping ::= bamFile
+ }
+ }
+
+ val autoMappedSampleToBams = VCF_BAM_utilities.getMapOfBAMsForSample(r.bamsWithoutSampleMapping)
+
+ val overlappingSamples = autoMappedSampleToBams.keys.toList.intersect(r.userMappedSampleToBams.keys.toList)
+ if (overlappingSamples.nonEmpty)
+ throw new Exception("Cannot have the same sample mapped to different BAMs: " + overlappingSamples.toString)
+
+ r.sampleToBams = autoMappedSampleToBams
+ r.userMappedSampleToBams.foreach{ keyVal => {r.sampleToBams += keyVal._1 -> keyVal._2} }
+
+
+ return r
+ }
+}
+
+ class ProcessBamListWithOptionalSampleMappings(parsedBamList: ParsedBamListWithOptionalSampleMappings, outputBase: String) extends InProcessFunction {
+ @Input(doc="")
+ var bams: File = parsedBamList.bams
+
+ @Output(doc="")
+ var bamsList: File = new File(outputBase + ".bam.list")
+
+ @Output(doc="")
+ var bamSampleMap: File = new File(outputBase + ".bam_sample.txt")
+
+ def run = {
+ val bamsListWriter = new PrintWriter(new PrintStream(bamsList))
+ for (bam <- parsedBamList.allBams) {
+ bamsListWriter.printf("%s%n", bam)
+ }
+ bamsListWriter.close
+
+ val bamSampleMapWriter = new PrintWriter(new PrintStream(bamSampleMap))
+ for ((sampleName, sampleNameBams) <- parsedBamList.userMappedSampleToBams) {
+ sampleNameBams.foreach { bam => bamSampleMapWriter.printf("%s\t%s%n", bam, sampleName) }
+ }
+ bamSampleMapWriter.close
+ }
+ }
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/GATKIntervals.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/GATKIntervals.scala
new file mode 100644
index 0000000..0e568b6
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/GATKIntervals.scala
@@ -0,0 +1,98 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import java.io.File
+import collection.JavaConversions._
+import org.broadinstitute.gatk.utils.interval.{IntervalSetRule, IntervalMergingRule, IntervalUtils}
+import org.broadinstitute.gatk.engine.datasources.reference.ReferenceDataSource
+import htsjdk.samtools.SAMFileHeader
+import org.broadinstitute.gatk.utils.GenomeLoc
+import org.broadinstitute.gatk.utils.commandline._
+import htsjdk.tribble.Feature
+
+case class GATKIntervals(reference: File, intervals: Seq[File], intervalsString: Seq[String],
+ intervalSetRule: IntervalSetRule, intervalMergingRule: IntervalMergingRule, intervalPadding: Option[Int],
+ excludeIntervals: Seq[File], excludeIntervalsString: Seq[String]) {
+
+ def this(gatk: CommandLineGATK) = this(
+ gatk.reference_sequence,
+ gatk.intervals, gatk.intervalsString,
+ gatk.interval_set_rule, gatk.interval_merging, gatk.interval_padding,
+ gatk.excludeIntervals, gatk.excludeIntervalsString)
+
+ private lazy val referenceDataSource = new ReferenceDataSource(reference)
+
+ lazy val samFileHeader = {
+ val header = new SAMFileHeader
+ header.setSequenceDictionary(referenceDataSource.getReference.getSequenceDictionary)
+ header
+ }
+
+ lazy val locs: java.util.List[GenomeLoc] = {
+ val includeIntervalBindings = this.intervals.map(GATKIntervals.createBinding(_, "intervals")) ++
+ this.intervalsString.map(GATKIntervals.createBinding(_, "intervalsString"))
+ val excludeIntervalBindings = this.excludeIntervals.map(GATKIntervals.createBinding(_, "excludeIntervals")) ++
+ this.excludeIntervalsString.map(GATKIntervals.createBinding(_, "excludeIntervalsString"))
+
+ IntervalUtils.parseIntervalBindings(
+ referenceDataSource,
+ includeIntervalBindings,
+ intervalSetRule, intervalMergingRule, intervalPadding.getOrElse(0),
+ excludeIntervalBindings).toList
+ }
+
+ lazy val contigs = locs.map(_.getContig).distinct.toSeq
+}
+
+object GATKIntervals {
+ def copyIntervalArguments(src: CommandLineGATK, dst: CommandLineGATK) {
+ dst.reference_sequence = src.reference_sequence
+ dst.intervals = src.intervals
+ dst.intervalsString = src.intervalsString
+ dst.interval_set_rule = src.interval_set_rule
+ dst.interval_merging = src.interval_merging
+ dst.interval_padding = src.interval_padding
+ dst.excludeIntervals = src.excludeIntervals
+ dst.excludeIntervalsString = src.excludeIntervalsString
+ }
+
+ private def createBinding(interval: File, argumentName: String): IntervalBinding[Feature] = {
+ val tags = interval match {
+ case taggedFile: TaggedFile => ParsingMethod.parseTags(argumentName, taggedFile.tag)
+ case file: File => new Tags
+ }
+ createBinding(interval.getAbsolutePath, argumentName, tags)
+ }
+
+ private def createBinding(interval: String, argumentName: String): IntervalBinding[Feature] = {
+ createBinding(interval, argumentName, new Tags)
+ }
+
+ private def createBinding(interval: String, argumentName: String, tags: Tags): IntervalBinding[Feature] = {
+ ArgumentTypeDescriptor.parseBinding(new ArgumentMatchStringValue(interval), classOf[Feature], classOf[IntervalBinding[Feature]], argumentName, tags, argumentName).asInstanceOf[IntervalBinding[Feature]]
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/GATKScatterFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/GATKScatterFunction.scala
new file mode 100644
index 0000000..01075c3
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/GATKScatterFunction.scala
@@ -0,0 +1,111 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import org.broadinstitute.gatk.utils.interval.IntervalUtils
+import java.io.File
+import org.broadinstitute.gatk.utils.io.IOUtils
+import org.broadinstitute.gatk.queue.function.scattergather.{CloneFunction, ScatterFunction}
+import org.broadinstitute.gatk.utils.commandline._
+
+trait GATKScatterFunction extends ScatterFunction {
+ /* The runtime field to set for specifying intervals. */
+ private final val intervalsField = "intervals"
+ private final val intervalsStringField = "intervalsString"
+ private final val excludeIntervalsField = "excludeIntervals"
+ private final val excludeIntervalsStringField = "excludeIntervalsString"
+ private final val intervalsSetRuleField = "interval_set_rule"
+ private final val intervalMergingField = "interval_merging"
+ private final val intervalPaddingField = "interval_padding"
+
+ @Output(doc="Scatter function outputs")
+ var scatterOutputFiles: Seq[File] = Nil
+
+ /** The original GATK function. */
+ protected var originalGATK: CommandLineGATK = _
+
+ /** Whether the last scatter job should also include any unmapped reads. */
+ protected var includeUnmapped: Boolean = _
+
+ override def init() {
+ this.originalGATK = this.originalFunction.asInstanceOf[CommandLineGATK]
+ // If intervals have been specified check if unmapped is included
+ if (this.originalGATK.intervals.size + this.originalGATK.intervalsString.size > 0)
+ this.includeUnmapped = this.originalGATK.intervalsString.exists(interval => IntervalUtils.isUnmapped(interval))
+ }
+
+ override def isScatterGatherable = {
+ this.originalGATK.reference_sequence != null
+ }
+
+ override def initCloneInputs(cloneFunction: CloneFunction, index: Int) {
+ cloneFunction.setFieldValue(this.intervalsField, Seq(new File("scatter.intervals")))
+ if (index == this.scatterCount && this.includeUnmapped)
+ cloneFunction.setFieldValue(this.intervalsStringField, Seq("unmapped"))
+ else
+ cloneFunction.setFieldValue(this.intervalsStringField, Seq.empty[String])
+
+ cloneFunction.setFieldValue(this.intervalsSetRuleField, null)
+ cloneFunction.setFieldValue(this.intervalMergingField, null)
+ cloneFunction.setFieldValue(this.intervalPaddingField, None)
+ cloneFunction.setFieldValue(this.excludeIntervalsField, Seq.empty[File])
+ cloneFunction.setFieldValue(this.excludeIntervalsStringField, Seq.empty[String])
+ }
+
+ override def bindCloneInputs(cloneFunction: CloneFunction, index: Int) {
+ val scatterPart = cloneFunction.getFieldValue(this.intervalsField)
+ .asInstanceOf[Seq[File]]
+ .map(file => IOUtils.absolute(cloneFunction.commandDirectory, file))
+ cloneFunction.setFieldValue(this.intervalsField, scatterPart)
+ this.scatterOutputFiles ++= scatterPart
+ }
+
+ /**
+ * @return true if all interval files exist.
+ */
+ protected def intervalFilesExist = {
+ !(this.originalGATK.intervals ++ this.originalGATK.excludeIntervals).exists(interval => !interval.exists())
+ }
+
+ /**
+ * @return the maximum number of intervals or this.scatterCount if the maximum can't be determined ahead of time.
+ */
+ protected def maxIntervals: Int
+}
+
+object GATKScatterFunction {
+ var gatkIntervalsCache = Seq.empty[GATKIntervals]
+
+ def getGATKIntervals(originalFunction: CommandLineGATK) = {
+ val gatkIntervals = new GATKIntervals(originalFunction)
+ gatkIntervalsCache.find(_ == gatkIntervals) match {
+ case Some(existingGatkIntervals) => existingGatkIntervals
+ case None =>
+ gatkIntervalsCache :+= gatkIntervals
+ gatkIntervals
+ }
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/IntervalScatterFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/IntervalScatterFunction.scala
new file mode 100644
index 0000000..99454d4
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/IntervalScatterFunction.scala
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import collection.JavaConversions._
+import org.broadinstitute.gatk.utils.interval.IntervalUtils
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+
+/**
+ * An interval scatter function.
+ */
+class IntervalScatterFunction extends GATKScatterFunction with InProcessFunction {
+ protected override def maxIntervals =
+ GATKScatterFunction.getGATKIntervals(this.originalGATK).locs.size
+
+ override def scatterCount = if (intervalFilesExist) super.scatterCount min this.maxIntervals else super.scatterCount
+
+ def run() {
+ val gi = GATKScatterFunction.getGATKIntervals(this.originalGATK)
+ val splits = IntervalUtils.splitFixedIntervals(gi.locs, this.scatterOutputFiles.size)
+ IntervalUtils.scatterFixedIntervals(gi.samFileHeader, splits, this.scatterOutputFiles)
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/LocusScatterFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/LocusScatterFunction.scala
new file mode 100644
index 0000000..5d71d35
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/LocusScatterFunction.scala
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import collection.JavaConversions._
+import org.broadinstitute.gatk.utils.interval.IntervalUtils
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+
+/**
+ * A scatter function that divides down to the locus level.
+ */
+class LocusScatterFunction extends GATKScatterFunction with InProcessFunction {
+ protected override def maxIntervals = scatterCount
+
+ def run() {
+ val gi = GATKScatterFunction.getGATKIntervals(this.originalGATK)
+ val splits = IntervalUtils.splitLocusIntervals(gi.locs, this.scatterOutputFiles.size)
+ IntervalUtils.scatterFixedIntervals(gi.samFileHeader, splits, this.scatterOutputFiles)
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/ReadScatterFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/ReadScatterFunction.scala
new file mode 100644
index 0000000..01e9eed
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/ReadScatterFunction.scala
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+/*
+ * Copyright (c) 2011, The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Currently ReadScatterFunction only does ContigScattering, but it
+ * could in principle do something more aggressive.
+ */
+class ReadScatterFunction extends ContigScatterFunction { }
+
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/TaggedFile.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/TaggedFile.scala
new file mode 100644
index 0000000..e161209
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/TaggedFile.scala
@@ -0,0 +1,58 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import java.io.File
+import org.broadinstitute.gatk.utils.io.FileExtension
+import org.broadinstitute.gatk.queue.util.ShellUtils
+
+/**
+ * Used to provide tagged -I input_file arguments to the GATK.
+ */
+class TaggedFile(path: String, val tag: String) extends File(path) with FileExtension {
+ def this(file: File, tag: String) =
+ this(file.getPath, tag)
+ def withPath(path: String) = new TaggedFile(path, tag)
+}
+
+/**
+ * Used to provide -I input_file arguments to the GATK.
+ */
+object TaggedFile {
+ def apply(path: String, tag: String) = new TaggedFile(path, tag)
+ def apply(file: File, tag: String) = new TaggedFile(file, tag)
+
+ def formatCommandLineParameter(cmdLineParam: String, value: Any) = {
+ value match {
+ case taggedFile: TaggedFile if (taggedFile.tag != null) =>
+ "%s:%s".format(cmdLineParam, taggedFile.tag)
+ case file: File =>
+ cmdLineParam
+ case x =>
+ ""
+ }
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/VcfGatherFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/VcfGatherFunction.scala
new file mode 100644
index 0000000..68664c3
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/VcfGatherFunction.scala
@@ -0,0 +1,53 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import org.broadinstitute.gatk.queue.function.scattergather.GatherFunction
+import org.broadinstitute.gatk.queue.function.RetryMemoryLimit
+
+/**
+ * Merges a vcf text file.
+ */
+class VcfGatherFunction extends CombineVariants with GatherFunction with RetryMemoryLimit {
+ this.assumeIdenticalSamples = true
+ this.suppressCommandLineHeader = true
+
+ private lazy val originalGATK = this.originalFunction.asInstanceOf[CommandLineGATK]
+
+ override def freezeFieldValues() {
+ this.variant = this.gatherParts.zipWithIndex map { case (input, index) => new TaggedFile(input, "input"+index) }
+ this.out = this.originalOutput
+ GATKIntervals.copyIntervalArguments(this.originalGATK, this)
+
+ this.no_cmdline_in_header = originalGATK.no_cmdline_in_header
+ this.sites_only = originalGATK.sites_only
+
+ // ensure that the gather function receives the same unsafe parameter as the scattered function
+ this.unsafe = this.originalGATK.unsafe
+
+ super.freezeFieldValues()
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/WriteFlankingIntervalsFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/WriteFlankingIntervalsFunction.scala
new file mode 100644
index 0000000..290eff9
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/gatk/WriteFlankingIntervalsFunction.scala
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+import org.broadinstitute.gatk.utils.commandline.{Output, Argument, Input}
+import java.io.File
+import org.broadinstitute.gatk.utils.interval.IntervalUtils
+
+class WriteFlankingIntervalsFunction extends InProcessFunction {
+ @Input(doc="The reference sequence")
+ var reference : File = _
+
+ @Input(doc="The interval list to flank")
+ var inputIntervals : File = _
+
+ @Output(doc="The output intervals file to write to")
+ var outputIntervals: File = _
+
+ @Argument(doc="Number of base pair to flank the input intervals")
+ var flankSize : Int = _
+
+ def run() {
+ IntervalUtils.writeFlankingIntervals(reference, inputIntervals, outputIntervals, flankSize)
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/AddOrReplaceReadGroups.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/AddOrReplaceReadGroups.scala
new file mode 100644
index 0000000..6b70d2f
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/AddOrReplaceReadGroups.scala
@@ -0,0 +1,90 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import org.broadinstitute.gatk.utils.commandline._
+
+import java.io.File
+
+/*
+ * Created by IntelliJ IDEA.
+ * User: carneiro
+ * Date: 6/22/11
+ * Time: 10:35 AM
+ */
+class AddOrReplaceReadGroups extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction with PicardBamFunction {
+ analysisName = "AddOrReplaceReadGroups"
+ javaMainClass = "picard.sam.AddOrReplaceReadGroups"
+
+ @Input(doc="The input SAM or BAM files to analyze. Must be coordinate sorted.", shortName = "input", fullName = "input_bam_files", required = true)
+ var input: Seq[File] = Nil
+
+ @Output(doc="The output BAM file with the modified/added read groups", shortName = "output", fullName = "output_bam_file", required = true)
+ var output: File = _
+
+ @Output(doc="The output bam index", shortName = "out_index", fullName = "output_bam_index_file", required = false)
+ var outputIndex: File = _
+
+ @Argument(doc="Read group ID", shortName = "id", fullName = "read_group_id", required = true)
+ var RGID: String = _
+
+ @Argument(doc = "Read group library", shortName = "lb", fullName = "read_group_library", required = true)
+ var RGLB: String = _
+
+ @Argument(doc = "Read group platform (e.g. illumina, solid)", shortName = "pl", fullName ="read_group_platform", required=true)
+ var RGPL: String = _
+
+ @Argument(doc = "Read group platform unit (e.g. run barcode)", shortName = "pu", fullName = "read_group_platform_unit", required = true)
+ var RGPU: String = _
+
+ @Argument(doc = "Read group sample name", shortName = "sm", fullName = "read_group_sample_name", required = true)
+ var RGSM: String = _
+
+ @Argument(doc = "Read group center name", shortName = "cn", fullName = "read_group_center_name", required = false)
+ var RGCN: String = ""
+
+ @Argument(doc = "Read group description", shortName = "ds", fullName = "read_group_description", required = false)
+ var RGDS: String = ""
+
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+ if (outputIndex == null && output != null)
+ outputIndex = new File(output.getName.stripSuffix(".bam") + ".bai")
+ }
+
+
+ override def inputBams = input
+ override def outputBam = output
+ this.createIndex = Some(true)
+ override def commandLine = super.commandLine +
+ required("RGID=" + RGID) +
+ required("RGLB=" + RGLB) +
+ required("RGPL=" + RGPL) +
+ required("RGPU=" + RGPU) +
+ required("RGSM=" + RGSM) +
+ conditional(RGCN != null && !RGCN.isEmpty, "RGCN=" + RGCN) +
+ conditional(RGDS != null && !RGDS.isEmpty, "RGDS=" + RGDS)
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/CalculateHsMetrics.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/CalculateHsMetrics.scala
new file mode 100644
index 0000000..68c4ca7
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/CalculateHsMetrics.scala
@@ -0,0 +1,68 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import org.broadinstitute.gatk.utils.commandline.{Argument, Output, Input}
+import java.io.File
+import picard.analysis.MetricAccumulationLevel
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: delangel
+ * Date: 10/9/12
+ * Time: 5:59 PM
+ * To change this template use File | Settings | File Templates.
+ */
+class CalculateHsMetrics extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction with PicardMetricsFunction {
+ analysisName = "CalculateHsMetrics"
+ javaMainClass = "picard.analysis.directed.CalculateHsMetrics"
+
+ @Input(doc="The input SAM or BAM files to analyze. Must be coordinate sorted.", shortName = "input", fullName = "input_bam_files", required = true)
+ var input: Seq[File] = Nil
+
+ @Output(doc="The output file to write statistics to", shortName = "output", fullName = "output_file", required = true)
+ var output: File = _
+
+ @Argument(doc="Interval list with targets", shortName = "targets", fullName = "target_list", required = true)
+ var targets: File = _
+
+ @Argument(doc="Interval list with baits", shortName = "baits", fullName = "bait_list", required = true)
+ var baits: File = _
+
+ @Argument(doc="Reference file", shortName = "reference", fullName = "reference", required = true)
+ var reference: File = _
+
+ @Argument(doc="The level(s) at which to accumulate metrics. Possible values: {ALL_READS, SAMPLE, LIBRARY, READ_GROUP} This option may be specified 0 or more times.", shortName = "level", fullName = "metric_accumulation_level", required = false)
+ var level: Seq[picard.analysis.MetricAccumulationLevel] = Seq(MetricAccumulationLevel.SAMPLE)
+
+ override def inputBams = input
+ override def outputFile = output
+ override def commandLine = super.commandLine +
+ required("BAIT_INTERVALS=" + baits) +
+ required("TARGET_INTERVALS=" + targets) +
+ required("REFERENCE_SEQUENCE=" + reference) +
+ repeat("METRIC_ACCUMULATION_LEVEL=", level, spaceSeparated=false, escape=true, format="%s")
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/CollectGcBiasMetrics.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/CollectGcBiasMetrics.scala
new file mode 100644
index 0000000..f0d2300
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/CollectGcBiasMetrics.scala
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import org.broadinstitute.gatk.utils.commandline.{Argument, Output, Input}
+import java.io.File
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: delangel
+ * Date: 10/10/12
+ * Time: 10:37 AM
+ * To change this template use File | Settings | File Templates.
+ */
+class CollectGcBiasMetrics extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction with PicardMetricsFunction {
+ analysisName = "CollectGcBiasMetrics"
+ javaMainClass = "picard.analysis.CollectGcBiasMetrics"
+
+ @Input(doc="The input SAM or BAM files to analyze. Must be coordinate sorted.", shortName = "input", fullName = "input_bam_files", required = true)
+ var input: Seq[File] = Nil
+
+ @Output(doc="The output file to write statistics to", shortName = "output", fullName = "output_file", required = true)
+ var output: File = _
+
+ @Argument(doc="Reference file", shortName = "reference", fullName = "reference", required = true)
+ var reference: File = _
+
+ override def inputBams = input
+ override def outputFile = output
+ override def commandLine = super.commandLine +
+ required("SUMMARY_OUTPUT=" + output) +
+ required("CHART_OUTPUT=" + output+".pdf") +
+ required("REFERENCE_SEQUENCE=" + reference)
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/CollectMultipleMetrics.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/CollectMultipleMetrics.scala
new file mode 100644
index 0000000..1507366
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/CollectMultipleMetrics.scala
@@ -0,0 +1,61 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import org.broadinstitute.gatk.utils.commandline.{Argument, Output, Input}
+import java.io.File
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: delangel
+ * Date: 10/10/12
+ * Time: 10:37 AM
+ * To change this template use File | Settings | File Templates.
+ */
+class CollectMultipleMetrics extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction with PicardMetricsFunction{
+ analysisName = "CollectMultipleMetrics"
+ javaMainClass = "picard.analysis.CollectMultipleMetrics"
+
+ @Input(doc="The input SAM or BAM files to analyze. Must be coordinate sorted.", shortName = "input", fullName = "input_bam_files", required = true)
+ var input: Seq[File] = Nil
+
+ @Output(doc="The output file to write statistics to", shortName = "output", fullName = "output_file", required = true)
+ var output: File = _
+
+ @Argument(doc="Reference file", shortName = "reference", fullName = "reference", required = true)
+ var reference: File = _
+
+ override def inputBams = input
+ override def outputFile = output
+ override def commandLine = super.commandLine +
+ required("REFERENCE_SEQUENCE=" + reference) +
+ required("ASSUME_SORTED=true") +
+ required("PROGRAM=QualityScoreDistribution") +
+ required("PROGRAM=MeanQualityByCycle") +
+ required("PROGRAM=CollectAlignmentSummaryMetrics" )
+
+
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/FastqToSam.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/FastqToSam.scala
new file mode 100644
index 0000000..44e10af
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/FastqToSam.scala
@@ -0,0 +1,104 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+import org.broadinstitute.gatk.utils.commandline._
+
+import java.io.File
+
+class FastqToSam extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction /*with PicardBamFunction*/ {
+ analysisName = "FastqToSam"
+ javaMainClass = "picard.sam.FastqToSam"
+
+ @Input(shortName = "fq1", fullName = "input_fq_file1", required = true, doc = "Input Fastq file to extract reads from (single-end fastq or, if paired, first end of the pair fastq)")
+ var fastq: File = _
+
+ @Input(shortName = "fq2", fullName = "input_fq_file2", required = false, doc = "Input Fastq file to extract reads from (if paired, second end of the pair fastq).")
+ var secondEndFastQ: File = _
+
+ @Output(shortName = "bam", fullName = "output_bam_file", required = true, doc = "Output bam file .")
+ var bam: File = _
+
+ @Argument(shortName = "SM", fullName = "SM", required = false, doc = "SM")
+ var SM: String = "SM"
+
+ @Argument(shortName = "LIB", fullName = "LIB", required = false, doc = "LIB")
+ var LIB: String = "LIB"
+
+ @Argument(shortName = "PU", fullName = "PU", required = false, doc = "PU")
+ var PU: String = "PU"
+
+ @Argument(shortName = "RG", fullName = "RG", required = false, doc = "RG")
+ var RG: String = "RG"
+
+ @Argument(shortName = "PL", fullName = "PL", required = false, doc = "PL")
+ var PL: String = "illumina"
+
+ @Argument(shortName = "CN", fullName = "CN", required = false, doc = "CN")
+ var CN: String = "CN"
+
+
+// override def inputBams = Seq(fastq)
+// override def outputBam = bam
+// this.sortOrder = null
+ val createIndex:Boolean = true
+ override def commandLine = super.commandLine +
+ required("FASTQ=" + fastq) +
+ optional("FASTQ2=", secondEndFastQ, spaceSeparated=false) +
+ required("OUTPUT=" + bam) +
+ optional("READ_GROUP_NAME=", RG, spaceSeparated=false) +
+ required("SAMPLE_NAME=" + SM) +
+ optional("LIBRARY_NAME=", LIB, spaceSeparated=false) +
+ optional("PLATFORM_UNIT=", PU, spaceSeparated=false) +
+ optional("PLATFORM=", PL, spaceSeparated=false) +
+ optional("CREATE_INDEX=", createIndex, spaceSeparated=false) +
+ optional("SEQUENCING_CENTER=", CN, spaceSeparated=false)
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/MarkDuplicates.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/MarkDuplicates.scala
new file mode 100644
index 0000000..66460b6
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/MarkDuplicates.scala
@@ -0,0 +1,79 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import org.broadinstitute.gatk.utils.commandline._
+
+import java.io.File
+
+/*
+ * Created by IntelliJ IDEA.
+ * User: carneiro
+ * Date: 6/22/11
+ * Time: 10:35 AM
+ */
+class MarkDuplicates extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction with PicardBamFunction {
+ analysisName = "MarkDuplicates"
+ javaMainClass = "picard.sam.MarkDuplicates"
+
+ @Input(doc="The input SAM or BAM files to analyze. Must be coordinate sorted.", shortName = "input", fullName = "input_bam_files", required = true)
+ var input: Seq[File] = Nil
+
+ @Output(doc="The output file to write marked records to", shortName = "output", fullName = "output_bam_file", required = true)
+ var output: File = _
+
+ @Output(doc="The output bam index", shortName = "out_index", fullName = "output_bam_index_file", required = false)
+ var outputIndex: File = _
+
+ @Output(doc="File to write duplication metrics to", shortName = "out_metrics", fullName = "output_metrics_file", required = true)
+ var metrics: File = new File(output + ".metrics")
+
+ @Argument(doc="If true do not write duplicates to the output file instead of writing them with appropriate flags set.", shortName = "remdup", fullName = "remove_duplicates", required = false)
+ var REMOVE_DUPLICATES: Boolean = false
+
+ @Argument(doc = "Maximum number of file handles to keep open when spilling read ends to disk. Set this number a little lower than the per-process maximum number of file that may be open. This number can be found by executing the 'ulimit -n' command on a Unix system.", shortName = "max_file_handles", fullName ="max_file_handles_for_read_ends_maps", required=false)
+ var MAX_FILE_HANDLES_FOR_READ_ENDS_MAP: Int = -1;
+
+ @Argument(doc = "This number, plus the maximum RAM available to the JVM, determine the memory footprint used by some of the sorting collections. If you are running out of memory, try reducing this number.", shortName = "sorting_ratio", fullName = "sorting_collection_size_ratio", required = false)
+ var SORTING_COLLECTION_SIZE_RATIO: Double = -1
+
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+ if (outputIndex == null && output != null)
+ outputIndex = new File(output.getName.stripSuffix(".bam") + ".bai")
+ }
+
+
+ override def inputBams = input
+ override def outputBam = output
+ this.sortOrder = null
+ this.createIndex = Some(true)
+ override def commandLine = super.commandLine +
+ required("M=" + metrics) +
+ conditional(REMOVE_DUPLICATES, "REMOVE_DUPLICATES=true") +
+ conditional(MAX_FILE_HANDLES_FOR_READ_ENDS_MAP > 0, "MAX_FILE_HANDLES_FOR_READ_ENDS_MAP=" + MAX_FILE_HANDLES_FOR_READ_ENDS_MAP.toString) +
+ conditional(SORTING_COLLECTION_SIZE_RATIO > 0, "SORTING_COLLECTION_SIZE_RATIO=" + SORTING_COLLECTION_SIZE_RATIO.toString)
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/MergeSamFiles.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/MergeSamFiles.scala
new file mode 100644
index 0000000..1b25a8e
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/MergeSamFiles.scala
@@ -0,0 +1,74 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import org.broadinstitute.gatk.utils.commandline._
+
+import java.io.File
+
+/*
+ * Created by IntelliJ IDEA.
+ * User: carneiro
+ * Date: 6/22/11
+ * Time: 10:35 AM
+ */
+class MergeSamFiles extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction with PicardBamFunction {
+ analysisName = "MergeSamFiles"
+ javaMainClass = "picard.sam.MergeSamFiles"
+
+ @Input(doc="The input SAM or BAM files to analyze. Must be coordinate sorted.", shortName = "input", fullName = "input_bam_files", required = true)
+ var input: Seq[File] = Nil
+
+ @Output(doc="The output merged BAM file", shortName = "output", fullName = "output_bam_file", required = true)
+ var output: File = _
+
+ @Output(doc="The output bam index", shortName = "out_index", fullName = "output_bam_index_file", required = false)
+ var outputIndex: File = _
+
+ @Argument(doc="Merge the seqeunce dictionaries Default value: false. This option can be set to 'null' to clear the default value.", shortName = "merge_dict", fullName = "merge_sequence_dictionaries", required = false)
+ var MERGE_SEQUENCE_DICTIONARIES: Boolean = false
+
+ @Argument(doc = "Option to enable a simple two-thread producer consumer version of the merge algorithm that uses one thread to read and merge the records from the input files and another thread to encode, compress and write to disk the output file. The threaded version uses about 20% more CPU and decreases runtime by ~20% when writing out a compressed BAM file. ", shortName = "thread", fullName ="use_threading", required=false)
+ var USE_THREADING: Boolean = false;
+
+ @Argument(doc = "Comments to include in the merged output file's header.", shortName = "com", fullName = "comments", required = false)
+ var COMMENT: String = ""
+
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+ if (outputIndex == null && output != null)
+ outputIndex = new File(output.getName.stripSuffix(".bam") + ".bai")
+ }
+
+
+ override def inputBams = input
+ override def outputBam = output
+ this.createIndex = Some(true)
+ override def commandLine = super.commandLine +
+ conditional(MERGE_SEQUENCE_DICTIONARIES, "MERGE_SEQUENCE_DICTIONARIES=true") +
+ conditional(USE_THREADING, "USE_THREADING=true") +
+ conditional(COMMENT != null && !COMMENT.isEmpty, "COMMENT=" + COMMENT)
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/PicardBamFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/PicardBamFunction.scala
new file mode 100644
index 0000000..80a60c5
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/PicardBamFunction.scala
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import java.io.File
+import org.broadinstitute.gatk.queue.function.JavaCommandLineFunction
+import htsjdk.samtools.ValidationStringency
+import htsjdk.samtools.SAMFileHeader.SortOrder
+
+/**
+ * Wraps a Picard function that operates on BAM files.
+ * See http://picard.sourceforge.net/ for more info.
+ *
+ * Since the various BAM utilities take slightly different arguments
+ * some values are optional.
+ */
+trait PicardBamFunction extends JavaCommandLineFunction {
+ var validationStringency = ValidationStringency.SILENT
+ var sortOrder = SortOrder.coordinate
+ var compressionLevel: Option[Int] = None
+ var createIndex: Option[Boolean] = None
+ var createMD5: Option[Boolean] = None
+ var maxRecordsInRam: Option[Int] = None
+ var assumeSorted: Option[Boolean] = None
+
+ protected def inputBams: Seq[File]
+ protected def outputBam: File
+
+ abstract override def commandLine = super.commandLine +
+ repeat("INPUT=", inputBams, spaceSeparated=false) +
+ required("TMP_DIR=" + jobTempDir) +
+ optional("OUTPUT=", outputBam, spaceSeparated=false) +
+ optional("COMPRESSION_LEVEL=", compressionLevel, spaceSeparated=false) +
+ optional("VALIDATION_STRINGENCY=", validationStringency, spaceSeparated=false) +
+ optional("SO=", sortOrder, spaceSeparated=false) +
+ optional("MAX_RECORDS_IN_RAM=", maxRecordsInRam, spaceSeparated=false) +
+ optional("ASSUME_SORTED=", assumeSorted, spaceSeparated=false) +
+ optional("CREATE_INDEX=", createIndex, spaceSeparated=false) +
+ optional("CREATE_MD5_FILE=", createMD5, spaceSeparated=false)
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/PicardMetricsFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/PicardMetricsFunction.scala
new file mode 100644
index 0000000..b9885a9
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/PicardMetricsFunction.scala
@@ -0,0 +1,54 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import java.io.File
+import org.broadinstitute.gatk.queue.function.JavaCommandLineFunction
+import htsjdk.samtools.ValidationStringency
+import htsjdk.samtools.SAMFileHeader.SortOrder
+
+/**
+ * Wraps a Picard function that operates on BAM files but doesn't output a new BAM file (i.e. QC metric files).
+ * See http://picard.sourceforge.net/ for more info.
+ *
+ * Since the various BAM utilities take slightly different arguments
+ * some values are optional.
+ */
+trait PicardMetricsFunction extends JavaCommandLineFunction {
+ var validationStringency = ValidationStringency.SILENT
+ var maxRecordsInRam: Option[Int] = None
+ var assumeSorted: Option[Boolean] = None
+ protected def inputBams: Seq[File]
+ protected def outputFile: File
+
+ abstract override def commandLine = super.commandLine +
+ repeat("INPUT=", inputBams, spaceSeparated=false) +
+ required("TMP_DIR=" + jobTempDir) +
+ optional("VALIDATION_STRINGENCY=", validationStringency, spaceSeparated=false) +
+ optional("OUTPUT=", outputFile, spaceSeparated=false) +
+ optional("MAX_RECORDS_IN_RAM=", maxRecordsInRam, spaceSeparated=false) +
+ optional("ASSUME_SORTED=", assumeSorted, spaceSeparated=false)
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/ReorderSam.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/ReorderSam.scala
new file mode 100644
index 0000000..1813694
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/ReorderSam.scala
@@ -0,0 +1,73 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import org.broadinstitute.gatk.utils.commandline._
+
+import java.io.File
+/*
+ * Created by IntelliJ IDEA.
+ * User: carneiro
+ * Date: 6/22/11
+ * Time: 10:35 AM
+ */
+class ReorderSam extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction with PicardBamFunction {
+ analysisName = "ReorderSam"
+ javaMainClass = "picard.sam.ReorderSam"
+
+ @Input(doc="Input file (bam or sam) to extract reads from.", shortName = "input", fullName = "input_bam_files", required = true)
+ var input: Seq[File] = Nil
+
+ @Output(doc="Output file (bam or sam) to write extracted reads to.", shortName = "output", fullName = "output_bam_file", required = true)
+ var output: File = _
+
+ @Output(doc="The output bam index", shortName = "out_index", fullName = "output_bam_index_file", required = false)
+ var outputIndex: File = _
+
+ @Argument(doc="Reference sequence to reorder reads to match.", shortName = "ref", fullName = "sort_reference", required = true)
+ var sortReference: File = _
+
+ @Argument(doc="If true, then allows only a partial overlap of the BAM contigs with the new reference sequence contigs. By default, this tool requires a corresponding contig in the new reference for each read contig.", shortName = "aic", fullName = "allow_incomplete_concordance", required = false)
+ var ALLOW_INCOMPLETE_DICT_CONCORDANCE: Boolean = _
+
+ @Argument(doc="If true, then permits mapping from a read contig to a new reference contig with the same name but a different length. Highly dangerous, only use if you know what you are doing.", shortName = "acld", fullName = "allow_contig_length_discordance", required = false)
+ var ALLOW_CONTIG_LENGTH_DISCORDANCE: Boolean = _
+
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+ if (outputIndex == null && output != null)
+ outputIndex = new File(output.getName.stripSuffix(".bam") + ".bai")
+ }
+
+ override def inputBams = input
+ override def outputBam = output
+ this.createIndex = Some(true)
+ this.sortOrder = null
+ override def commandLine = super.commandLine +
+ required("REFERENCE=" + sortReference) +
+ optional("ALLOW_INCOMPLETE_DICT_CONCORDANCE=", ALLOW_INCOMPLETE_DICT_CONCORDANCE, spaceSeparated=false)
+ optional("ALLOW_CONTIG_LENGTH_DISCORDANCE=", ALLOW_CONTIG_LENGTH_DISCORDANCE, spaceSeparated=false)
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/RevertSam.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/RevertSam.scala
new file mode 100644
index 0000000..2012b54
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/RevertSam.scala
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import org.broadinstitute.gatk.utils.commandline._
+
+import java.io.File
+
+/*
+ * Created by IntelliJ IDEA.
+ * User: carneiro
+ * Date: 6/22/11
+ * Time: 10:35 AM
+ */
+class RevertSam extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction with PicardBamFunction {
+ analysisName = "RevertSam"
+ javaMainClass = "picard.sam.RevertSam"
+
+ @Input(shortName = "input", fullName = "input_bam_files", required = true, doc = "The input SAM or BAM files to revert.")
+ var input: Seq[File] = Nil
+
+ @Output(shortName = "output", fullName = "output_bam_file", required = true, doc = "The reverted BAM or SAM output file.")
+ var output: File = _
+
+ @Output(shortName = "out_index", fullName = "output_bam_index_file", required = false, doc = "The output bam index")
+ var outputIndex: File = _
+
+ @Argument(shortName = "roq", fullName = "restore_original_qualities", required = false, doc = "True to restore original qualities from the OQ field to the QUAL field if available.")
+ var restoreOriginalQualities: Boolean = true
+
+ @Argument(shortName = "rdi", fullName = "remove_duplicate_information", required = false, doc = "Remove duplicate read flags from all reads. Note that if this is true and REMOVE_ALIGNMENT_INFORMATION==false, the output may have the unusual but sometimes desirable trait of having unmapped reads that are marked as duplicates.")
+ var removeDuplicateInformation: Boolean = true
+
+ @Argument(shortName = "rai", fullName = "remove_alignment_information", required = false, doc = "Remove all alignment information from the file.")
+ var removeAlignmentInformation: Boolean = true
+
+ @Argument(shortName = "atc", fullName = "attributes_to_clear", required = false, doc = "When removing alignment information, the set of optional tags to remove.")
+ var attributesToClear: Seq[String] = Nil
+
+ @Argument(shortName = "sa", fullName = "sample_alias", required = false, doc = "The sample alias to use in the reverted output file. This will override the existing sample alias in the file and is used only if all the read groups in the input file have the same sample alias.")
+ var sampleAlias: String = null
+
+ @Argument(shortName = "ln", fullName = "library_name", required = false, doc = "The library name to use in the reverted output file. This will override the existing sample alias in the file and is used only if all the read groups in the input file have the same sample alias.")
+ var libraryName: String = null
+
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+ if (outputIndex == null && output != null)
+ outputIndex = new File(output.getName.stripSuffix(".bam") + ".bai")
+ }
+
+
+ override def inputBams = input
+ override def outputBam = output
+ this.createIndex = Some(true)
+ override def commandLine = super.commandLine +
+ conditional(!restoreOriginalQualities, "RESTORE_ORIGINAL_QUALITIES=false") +
+ conditional(!removeDuplicateInformation, "REMOVE_DUPLICATE_INFORMATION=false") +
+ conditional(!removeAlignmentInformation, "REMOVE_ALIGNMENT_INFORMATION=false") +
+ repeat("ATTRIBUTE_TO_CLEAR=", attributesToClear, spaceSeparated=false) + // repeat() returns "" for null/empty list
+ conditional(sampleAlias != null, "SAMPLE_ALIAS=" + sampleAlias) +
+ conditional(libraryName != null, "LIBRARY_NAME=" + libraryName)
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/SamToFastq.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/SamToFastq.scala
new file mode 100644
index 0000000..e5624fc
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/SamToFastq.scala
@@ -0,0 +1,107 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import org.broadinstitute.gatk.utils.commandline._
+
+import java.io.File
+
+/*
+ * Created by IntelliJ IDEA.
+ * User: carneiro
+ * Date: 6/22/11
+ * Time: 10:35 AM
+ */
+class SamToFastq extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction with PicardBamFunction {
+ analysisName = "SamToFastq"
+ javaMainClass = "picard.sam.SamToFastq"
+
+ @Input(shortName = "input", fullName = "input_bam_files", required = true, doc = "Input SAM/BAM file to extract reads from.")
+ var input: Seq[File] = Nil
+
+ @Output(shortName = "fastq", fullName = "output_fastq_file", required = true, doc = "Output fastq file (single-end fastq or, if paired, first end of the pair fastq).")
+ var fastq: File = _
+
+ @Output(shortName = "se", fullName = "second_end_fastq", required = false, doc = "Output fastq file (if paired, second end of the pair fastq).")
+ var secondEndFastQ: File = _
+
+ @Argument(shortName = "opg", fullName = "output_per_readgroup", required = false, doc = "Output a fastq file per read group (two fastq files per read group if the group is paired).")
+ var outputPerReadGroup: Boolean = false
+
+ @Argument(shortName = "od", fullName = "output_dir", required = false, doc = "Directory in which to output the fastq file(s). Used only when OUTPUT_PER_RG is true.")
+ var outputDir: File = _
+
+ @Argument(shortName = "rr", fullName = "re_reverse", required = false, doc = "Re-reverse bases and qualities of reads with negative strand flag set before writing them to fastq.")
+ var reReverse: Boolean = true
+
+ @Argument(shortName = "nonpf", fullName = "include_non_pf_reads", required = false, doc = "Include non-PF reads from the SAM file into the output FASTQ files.")
+ var includeNonPFReads: Boolean = false
+
+ @Argument(shortName = "cat", fullName = "clipping_attribute", required = false, doc = "The attribute that stores the position at which the SAM record should be clipped.")
+ var clippingAttribute: String = null
+
+ @Argument(shortName = "cac", fullName = "clipping_action", required = false, doc = "The action that should be taken with clipped reads: 'X' means the reads and qualities should be trimmed at the clipped position; 'N' means the bases should be changed to Ns in the clipped region; and any integer means that the base qualities should be set to that value in the clipped region.")
+ var clippingAction: String = null
+
+ @Argument(shortName = "r1t", fullName = "read_one_trim", required = false, doc = "The number of bases to trim from the beginning of read 1.")
+ var readOneTrim: Int = -1
+
+ @Argument(shortName = "r1mbtw", fullName = "read_one_max_bases_to_write", required = false, doc = "The maximum number of bases to write from read 1 after trimming. If there are fewer than this many bases left after trimming, all will be written. If this value is null then all bases left after trimming will be written.")
+ var readOneMaxBasesToWrite: Int = -1
+
+ @Argument(shortName = "r2t", fullName = "read_two_trim", required = false, doc = "The number of bases to trim from the beginning of read 2.")
+ var readTwoTrim: Int = -1
+
+ @Argument(shortName = "r2mbtw", fullName = "read_two_max_bases_to_write", required = false, doc = "The maximum number of bases to write from read 2 after trimming. If there are fewer than this many bases left after trimming, all will be written. If this value is null then all bases left after trimming will be written.")
+ var readTwoMaxBasesToWrite: Int = -1
+
+ @Argument(shortName = "inpa", fullName = "include_non_primary_alignments", required = false, doc = "If true, include non-primary alignments in the output. Support of non-primary alignments in SamToFastq is not comprehensive, so there may be exceptions if this is set to true and there are paired reads with non-primary alignments.")
+ var includeNonPrimaryAlignments: Boolean = false
+
+ @Argument(shortName = "il", fullName = "interleave", required = false, doc = "Will generate an interleaved fastq if paired, each line will have /1 or /2 to describe which end it came from")
+ var interleave: Boolean = false
+
+ override def inputBams = input
+ override def outputBam = null
+ this.sortOrder = null
+
+ override def commandLine = super.commandLine +
+ required("FASTQ=" + fastq) +
+ optional("SECOND_END_FASTQ=", secondEndFastQ, spaceSeparated=false) +
+ conditional(outputPerReadGroup, "OUTPUT_PER_RG=" + outputPerReadGroup) +
+ optional("OUTPUT_DIR=", outputDir, spaceSeparated=false) +
+ conditional(!reReverse, "RE_REVERSE=" + reReverse) +
+ conditional(includeNonPFReads, "INCLUDE_NON_PF_READS=" + includeNonPFReads) +
+ optional("CLIPPING_ATTRIBUTE=", clippingAttribute, spaceSeparated=false) +
+ optional("CLIPPING_ACTION=", clippingAction, spaceSeparated=false) +
+ conditional(readOneTrim >= 0, "READ1_TRIM=" + readOneTrim) +
+ conditional(readOneMaxBasesToWrite >= 0, "READ1_MAX_BASES_TO_WRITE=" + readOneMaxBasesToWrite) +
+ conditional(readTwoTrim >= 0, "READ2_TRIM=" + readTwoTrim) +
+ conditional(readTwoMaxBasesToWrite >= 0, "READ2_MAX_BASES_TO_WRITE=" + readTwoMaxBasesToWrite) +
+ conditional(includeNonPrimaryAlignments, "INCLUDE_NON_PRIMARY_ALIGNMENTS=" + includeNonPrimaryAlignments) +
+ conditional(interleave, "INTERLEAVE=" + interleave)
+
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/SortSam.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/SortSam.scala
new file mode 100644
index 0000000..847ed92
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/SortSam.scala
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import org.broadinstitute.gatk.utils.commandline._
+
+import java.io.File
+
+/*
+ * Created by IntelliJ IDEA.
+ * User: carneiro
+ * Date: 6/22/11
+ * Time: 10:35 AM
+ */
+class SortSam extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction with PicardBamFunction {
+ analysisName = "SortSam"
+ javaMainClass = "picard.sam.SortSam"
+
+ @Input(doc="The input SAM or BAM files to sort.", shortName = "input", fullName = "input_bam_files", required = true)
+ var input: Seq[File] = Nil
+
+ @Output(doc="The sorted BAM or SAM output file.", shortName = "output", fullName = "output_bam_file", required = true)
+ var output: File = _
+
+ @Output(doc="The output bam index", shortName = "out_index", fullName = "output_bam_index_file", required = false)
+ var outputIndex: File = _
+
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+ if (outputIndex == null && output != null)
+ outputIndex = new File(output.getAbsolutePath.stripSuffix(".bam") + ".bai")
+ }
+
+
+
+ override def inputBams = input
+ override def outputBam = output
+ this.createIndex = Some(true)
+ override def commandLine = super.commandLine
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/ValidateSamFile.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/ValidateSamFile.scala
new file mode 100644
index 0000000..e9ad097
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/picard/ValidateSamFile.scala
@@ -0,0 +1,85 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.picard
+
+import org.broadinstitute.gatk.utils.commandline._
+
+import picard.sam.ValidateSamFile.Mode
+
+import java.io.File
+
+/*
+ * Created by IntelliJ IDEA.
+ * User: carneiro
+ * Date: 6/22/11
+ * Time: 10:35 AM
+ */
+class ValidateSamFile extends org.broadinstitute.gatk.queue.function.JavaCommandLineFunction with PicardBamFunction {
+ analysisName = "ValidateSamFile"
+ javaMainClass = "picard.sam.ValidateSamFile"
+
+ @Input(doc="The input SAM or BAM files to analyze. Must be coordinate sorted.", shortName = "input", fullName = "input_bam_files", required = true)
+ var input: Seq[File] = Nil
+
+ @Output(doc="Send output to a file instead of stdout", shortName = "output", fullName = "output_file", required = false)
+ var output: File = _
+
+ @Argument(doc="Mode of output", shortName = "mode", fullName = "mode_of_output", required = false)
+ var MODE: Mode = Mode.VERBOSE
+
+ @Argument(doc="List of validation error types to ignore.", shortName = "ignore", fullName = "ignore_error_types", required = false)
+ var IGNORE: Seq[String] = Nil
+
+ @Argument(doc = "The maximum number of lines output in verbose mode.", shortName = "max", fullName = "max_output", required = false)
+ var MAX_OUTPUT: Int = 100
+
+ @Argument(doc = "Reference sequence file, the NM tag check will be skipped if this is missing.", shortName = "ref", fullName ="reference_sequence", required=false)
+ var REFERENCE_SEQUENCE: File = _
+
+ @Argument(doc = "If true, only report errors, and ignore warnings.", shortName = "iw", fullName = "ignore_warnings", required = false)
+ var IGNORE_WARNINGS: Boolean = false
+
+ @Argument(doc = "If true and input is a BAM file with an index file, also validates the index.", shortName = "vi", fullName = "validate_index", required = false)
+ var VALIDATE_INDEX: Boolean = true
+
+ @Argument(doc = "Whether the SAM or BAM file consists of bisulfite sequenced reads. If so, C->T is not counted as an error in computing the value of the NM tag.", shortName = "bs", fullName = "is_bisulfite_sequenced", required = false)
+ var IS_BISULFITE_SEQUENCED: Boolean = false
+
+ @Argument(doc = "Relevant for a coordinate-sorted file containing read pairs only. Maximum number of file handles to keep open when spilling mate info to disk. Set this number a little lower than the per-process maximum number of file that may be open. This number can be found by executing the 'ulimit -n' command on a Unix system.", shortName = "max_files", fullName = "max_open_temp_files", required = false)
+ var MAX_OPEN_TEMP_FILES: Int = 8000
+
+ this.sortOrder = null
+ override def inputBams = input
+ override def outputBam = output
+ override def commandLine = super.commandLine +
+ required("MODE=" + MODE) +
+ required("MAX_OUTPUT=" + MAX_OUTPUT) +
+ required("MAX_OPEN_TEMP_FILES=" + MAX_OPEN_TEMP_FILES) +
+ conditional(!VALIDATE_INDEX, "VALIDATE_INDEX=false") +
+ conditional(IGNORE_WARNINGS, "IGNORE_WARNINGS=true") +
+ conditional(IS_BISULFITE_SEQUENCED, "IS_BISULFITE_SEQUENCED=true") +
+ repeat("IGNORE=", IGNORE, spaceSeparated=false) // repeat() returns "" for null/empty list
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/samtools/SamtoolsCommandLineFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/samtools/SamtoolsCommandLineFunction.scala
new file mode 100644
index 0000000..a7e6030
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/samtools/SamtoolsCommandLineFunction.scala
@@ -0,0 +1,37 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.samtools
+
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.utils.commandline.Argument
+
+/**
+ * samtools command line function
+ */
+abstract class SamtoolsCommandLineFunction extends CommandLineFunction {
+ @Argument(doc="samtools path")
+ var samtools: String = "samtools"
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/samtools/SamtoolsIndexFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/samtools/SamtoolsIndexFunction.scala
new file mode 100644
index 0000000..cb55c06
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/samtools/SamtoolsIndexFunction.scala
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.samtools
+
+import java.io.File
+import org.broadinstitute.gatk.utils.commandline.{Output, Input}
+
+/**
+ * Indexes a BAM file using samtools.
+ */
+class SamtoolsIndexFunction extends SamtoolsCommandLineFunction {
+ analysisName = "samtools index"
+
+ @Input(doc="BAM file to index")
+ var bamFile: File = _
+
+ @Output(doc="BAM file index to output", required=false)
+ var bamFileIndex: File = _
+
+ /**
+ * Sets the bam file index to the bam file name + ".bai".
+ */
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+ if (bamFileIndex == null && bamFile != null)
+ bamFileIndex = new File(bamFile.getPath + ".bai")
+ }
+
+ def commandLine = required(samtools) +
+ required("index") +
+ required(bamFile) +
+ required(bamFileIndex)
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/samtools/SamtoolsMergeFunction.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/samtools/SamtoolsMergeFunction.scala
new file mode 100644
index 0000000..4d7c0c6
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/samtools/SamtoolsMergeFunction.scala
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.samtools
+
+import java.io.File
+import org.broadinstitute.gatk.utils.commandline.{Argument, Output, Input}
+
+/**
+ * Merges BAM files using samtools.
+ */
+class SamtoolsMergeFunction extends SamtoolsCommandLineFunction {
+ analysisName = "samtools merge"
+
+ @Input(doc="BAM file input")
+ var inputBams: Seq[File] = Nil
+
+ @Output(doc="BAM file output")
+ var outputBam: File = _
+
+ @Argument(doc="region", required=false)
+ var region: String = _
+
+ @Input(doc="BAM file input indexes")
+ var inputBamIndexes: Seq[File] = Nil
+
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+ inputBamIndexes ++= inputBams
+ .filter(orig => orig != null && orig.getName.endsWith(".bam"))
+ .flatMap(orig => Array(
+ new File(orig.getPath + ".bai"),
+ new File(orig.getPath.stripSuffix(".bam") + ".bai")
+ ))
+ }
+
+ def commandLine = required(samtools) +
+ required("merge") +
+ optional("-R", region) +
+ required(outputBam) +
+ repeat(inputBams)
+}
diff --git a/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/snpeff/SnpEff.scala b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/snpeff/SnpEff.scala
new file mode 100644
index 0000000..ae316bc
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/main/scala/org/broadinstitute/gatk/queue/extensions/snpeff/SnpEff.scala
@@ -0,0 +1,68 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.snpeff
+
+import org.broadinstitute.gatk.queue.function.JavaCommandLineFunction
+import java.io.File
+import org.broadinstitute.gatk.utils.commandline.{Argument, Output, Input}
+
+/**
+ * Basic snpEff support.
+ * See: http://www.broadinstitute.org/gatk/guide/article?id=50
+ */
+class SnpEff extends JavaCommandLineFunction {
+ javaMainClass = "ca.mcgill.mcb.pcingola.snpEffect.commandLine.SnpEff"
+
+ @Input(doc="snp vcf4 file")
+ var inVcf: File = _
+
+ @Input(doc="config file with path to data dir", required=false)
+ var config: File = _
+
+ @Argument(doc="genome version")
+ var genomeVersion: String = _
+
+ @Argument(doc="verbose", required=false)
+ var verbose = true
+
+ @Argument(doc="onlyCoding", required=false)
+ var onlyCoding = true
+
+ @Output(doc="snp eff output")
+ var outVcf: File = _
+
+ override def commandLine = super.commandLine +
+ required("eff") +
+ conditional(verbose, "-v") +
+ required("-onlyCoding", onlyCoding.toString) +
+ optional("-c", config) +
+ required("-i", "vcf") +
+ required("-o", "vcf") +
+ required(genomeVersion) +
+ required(inVcf) +
+ required(">", escape=false) +
+ required(outVcf)
+}
diff --git a/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/extensions/gatk/GATKIntervalsUnitTest.scala b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/extensions/gatk/GATKIntervalsUnitTest.scala
new file mode 100644
index 0000000..f2ec8a9
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/extensions/gatk/GATKIntervalsUnitTest.scala
@@ -0,0 +1,154 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.extensions.gatk
+
+import java.io.File
+import org.testng.Assert
+import org.testng.annotations.{DataProvider, Test}
+import org.broadinstitute.gatk.utils.BaseTest
+import org.broadinstitute.gatk.engine.datasources.reference.ReferenceDataSource
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile
+import org.broadinstitute.gatk.utils.{GenomeLocSortedSet, GenomeLocParser}
+import collection.JavaConversions._
+import org.broadinstitute.gatk.utils.interval.IntervalUtils
+import org.broadinstitute.gatk.utils.exceptions.UserException
+
+class GATKIntervalsUnitTest {
+ private final lazy val hg18Reference = new File(BaseTest.hg18Reference)
+ private final lazy val hg18GenomeLocParser = new GenomeLocParser(new CachingIndexedFastaSequenceFile(hg18Reference))
+ private final lazy val hg18ReferenceLocs = GenomeLocSortedSet.
+ createSetFromSequenceDictionary(new ReferenceDataSource(hg18Reference).getReference.getSequenceDictionary).toList
+ private final lazy val hg19GenomeLocParser = new GenomeLocParser(new CachingIndexedFastaSequenceFile(hg19Reference))
+
+ private final lazy val hg19Reference = new File(BaseTest.hg19Reference)
+
+ @Test
+ def testWithIntervals() {
+ val chr1 = hg18GenomeLocParser.parseGenomeLoc("chr1:1-1")
+ val chr2 = hg18GenomeLocParser.parseGenomeLoc("chr2:2-3")
+ val chr3 = hg18GenomeLocParser.parseGenomeLoc("chr3:3-5")
+
+ val gi = createGATKIntervals(hg18Reference, Seq("chr1:1-1", "chr2:2-3", "chr3:3-5"))
+ Assert.assertEquals(gi.locs.toSeq, Seq(chr1, chr2, chr3))
+ Assert.assertEquals(gi.contigs, Seq("chr1", "chr2", "chr3"))
+ }
+
+ @Test(timeOut = 30000L)
+ def testIntervalFile() {
+ val gi = createGATKIntervals(hg19Reference, Seq(BaseTest.hg19Intervals))
+ Assert.assertEquals(gi.locs.size, 189894)
+ // Timeout check is because of bad:
+ // for(Item item: javaConvertedScalaList)
+ // This for loop is actually an O(N^2) operation as the iterator calls the
+ // O(N) javaConvertedScalaList.size() for each iteration of the loop.
+ Assert.assertEquals(IntervalUtils.splitFixedIntervals(gi.locs, 189894).size(), 189894)
+ Assert.assertEquals(gi.contigs.size, 24)
+ }
+
+ @Test
+ def testEmptyIntervals() {
+ val gi = createGATKIntervals(hg18Reference, Nil)
+ Assert.assertEquals(gi.locs, hg18ReferenceLocs)
+ Assert.assertEquals(gi.contigs.size, hg18ReferenceLocs.size)
+ }
+
+ @Test
+ def testContigCounts() {
+ Assert.assertEquals(createGATKIntervals(hg18Reference, Nil).contigs, hg18ReferenceLocs.map(_.getContig))
+ Assert.assertEquals(createGATKIntervals(hg18Reference, Seq("chr1", "chr2", "chr3")).contigs, Seq("chr1", "chr2", "chr3"))
+ Assert.assertEquals(createGATKIntervals(hg18Reference, Seq("chr1:1-2", "chr1:4-5", "chr2:1-1", "chr3:2-2")).contigs, Seq("chr1", "chr2", "chr3"))
+ }
+
+ @DataProvider(name="sortAndMergeIntervals")
+ def getSortAndMergeIntervals: Array[Array[AnyRef]] = {
+ Array(
+ Array(Seq("chr1:1-10", "chr1:1-10", "chr1:1-10"), Seq("chr1:1-10")),
+ Array(Seq("chr1:1-10", "chr1:1-11", "chr1:1-12"), Seq("chr1:1-12")),
+ Array(Seq("chr1:1-10", "chr1:11-20", "chr1:21-30"), Seq("chr1:1-30")),
+ Array(Seq("chr1:1-10", "chr1:10-20", "chr1:21-30"), Seq("chr1:1-30")),
+ Array(Seq("chr1:1-9", "chr1:21-30", "chr1:11-20"), Seq("chr1:1-9", "chr1:11-30"))
+ ).asInstanceOf[Array[Array[AnyRef]]]
+ }
+
+ @Test(dataProvider="sortAndMergeIntervals")
+ def testSortAndMergeIntervals(unmerged: Seq[String], expected: Seq[String]) {
+ Assert.assertEquals(createGATKIntervals(hg18Reference, unmerged).locs.toSeq, expected.map(hg18GenomeLocParser.parseGenomeLoc(_)))
+ }
+
+ @DataProvider(name="taggedFiles")
+ def getTaggedFiles: Array[Array[AnyRef]] = {
+ Array(
+ Array(hg18Reference, BaseTest.privateTestDir + "small_unmerged_gatk_intervals.list", null, Seq("chr1:1-10")),
+ Array(hg18Reference, BaseTest.privateTestDir + "small_unmerged_gatk_intervals.list", "", Seq("chr1:1-10")),
+ Array(hg18Reference, BaseTest.privateTestDir + "small_unmerged_gatk_intervals.list", "myList", Seq("chr1:1-10")),
+ Array(hg19Reference, BaseTest.privateTestDir + "small.indel.test.vcf", null, Seq("1:897475-897481", "1:10001292")),
+ Array(hg19Reference, BaseTest.privateTestDir + "small.indel.test.vcf", "", Seq("1:897475-897481", "1:10001292")),
+ Array(hg19Reference, BaseTest.privateTestDir + "small.indel.test.vcf", "myVcf", Seq("1:897475-897481", "1:10001292")),
+ Array(hg19Reference, BaseTest.privateTestDir + "small.indel.test.vcf", "VCF", Seq("1:897475-897481", "1:10001292")),
+ Array(hg19Reference, BaseTest.privateTestDir + "small.indel.test.vcf", "myVcf,VCF", Seq("1:897475-897481", "1:10001292")),
+ Array(hg19Reference, BaseTest.privateTestDir + "sampleBedFile.bed", null, Seq("20:1-999", "20:1002-2000", "22:1001-6000")),
+ Array(hg19Reference, BaseTest.privateTestDir + "sampleBedFile.bed", "", Seq("20:1-999", "20:1002-2000", "22:1001-6000")),
+ Array(hg19Reference, BaseTest.privateTestDir + "sampleBedFile.bed", "myBed", Seq("20:1-999", "20:1002-2000", "22:1001-6000")),
+ Array(hg19Reference, BaseTest.privateTestDir + "sampleBedFile.bed", "BED", Seq("20:1-999", "20:1002-2000", "22:1001-6000")),
+ Array(hg19Reference, BaseTest.privateTestDir + "sampleBedFile.bed", "myBed,BED", Seq("20:1-999", "20:1002-2000", "22:1001-6000"))
+ )
+ }
+
+ @Test(dataProvider="taggedFiles")
+ def testTaggedFiles(reference: File, file: String, tags: String, expected: Seq[String]) {
+ val gatk = new CommandLineGATK
+ gatk.reference_sequence = reference
+ gatk.intervals = Seq(new TaggedFile(file, tags))
+ val parser = if (reference == hg18Reference) hg18GenomeLocParser else hg19GenomeLocParser
+ Assert.assertEquals(new GATKIntervals(gatk).locs.toSeq, expected.map(parser.parseGenomeLoc(_)))
+ }
+
+ @DataProvider(name="badTaggedFiles")
+ def getBadTaggedFiles: Array[Array[AnyRef]] = {
+ Array(
+ Array(hg18Reference, BaseTest.privateTestDir + "small_unmerged_gatk_intervals.list", "VCF"),
+ Array(hg18Reference, BaseTest.privateTestDir + "small_unmerged_gatk_intervals.list", "too,many,tags"),
+ Array(hg19Reference, BaseTest.privateTestDir + "small.indel.test.vcf", "BED"),
+ Array(hg19Reference, BaseTest.privateTestDir + "small.indel.test.vcf", "VCF,myVCF"),
+ Array(hg19Reference, BaseTest.privateTestDir + "small.indel.test.vcf", "myVCF,VCF,extra"),
+ Array(hg19Reference, BaseTest.privateTestDir + "sampleBedFile.bed", "VCF"),
+ Array(hg19Reference, BaseTest.privateTestDir + "sampleBedFile.bed", "BED,myBed"),
+ Array(hg19Reference, BaseTest.privateTestDir + "sampleBedFile.bed", "myBed,BED,extra")
+ ).asInstanceOf[Array[Array[AnyRef]]]
+ }
+
+ @Test(dataProvider = "badTaggedFiles", expectedExceptions = Array(classOf[UserException]))
+ def testBadTaggedFiles(reference: File, file: String, tags: String) {
+ testTaggedFiles(reference, file, tags, Nil)
+ }
+
+ private def createGATKIntervals(reference: File, intervals: Seq[String]) = {
+ val gatk = new CommandLineGATK
+ gatk.reference_sequence = reference
+ gatk.intervalsString = intervals
+ new GATKIntervals(gatk)
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleCountLociQueueTest.scala b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleCountLociQueueTest.scala
new file mode 100644
index 0000000..f6cc746
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleCountLociQueueTest.scala
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.pipeline.examples
+
+import org.testng.annotations.Test
+import org.broadinstitute.gatk.queue.pipeline.{QueueTest, QueueTestSpec}
+import org.broadinstitute.gatk.utils.BaseTest
+
+class ExampleCountLociQueueTest {
+ @Test(timeOut=36000000)
+ def testCountLoci() {
+ val testOut = "count.out"
+ val spec = new QueueTestSpec
+ spec.name = "countloci"
+ spec.args = Array(
+ " -S " + QueueTest.publicQScriptsPackageDir + "examples/ExampleCountLoci.scala",
+ " -R " + BaseTest.publicTestDir + "exampleFASTA.fasta",
+ " -I " + BaseTest.publicTestDir + "exampleBAM.bam",
+ " -o " + testOut).mkString
+ spec.fileMD5s += testOut -> "ade93df31a6150321c1067e749cae9be"
+ QueueTest.executeTest(spec)
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleCountReadsQueueTest.scala b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleCountReadsQueueTest.scala
new file mode 100644
index 0000000..e79ea8a
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleCountReadsQueueTest.scala
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.pipeline.examples
+
+import org.testng.annotations.Test
+import org.broadinstitute.gatk.queue.pipeline.{QueueTest, QueueTestSpec}
+import org.broadinstitute.gatk.utils.BaseTest
+
+class ExampleCountReadsQueueTest {
+ @Test(timeOut=36000000)
+ def testCountReads() {
+ val spec = new QueueTestSpec
+ spec.name = "countreads"
+ spec.args = Array(
+ " -S " + QueueTest.publicQScriptsPackageDir + "examples/ExampleCountReads.scala",
+ " -R " + BaseTest.publicTestDir + "exampleFASTA.fasta",
+ " -I " + BaseTest.publicTestDir + "exampleBAM.bam").mkString
+ QueueTest.executeTest(spec)
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExamplePrintReadsQueueTest.scala b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExamplePrintReadsQueueTest.scala
new file mode 100644
index 0000000..fcaf0d7
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExamplePrintReadsQueueTest.scala
@@ -0,0 +1,83 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.pipeline.examples
+
+/*
+ * Copyright (c) 2011, The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+import org.testng.annotations.Test
+import org.broadinstitute.gatk.queue.pipeline.{QueueTest, QueueTestSpec}
+import org.broadinstitute.gatk.utils.BaseTest
+
+class ExamplePrintReadsQueueTest {
+ @Test(timeOut=36000000)
+ def testDevNullOutput() {
+ val spec = new QueueTestSpec
+ spec.name = "devnulloutput"
+ spec.args = Array(
+ " -S " + QueueTest.publicQScriptsPackageDir + "examples/ExamplePrintReads.scala",
+ " -R " + BaseTest.publicTestDir + "exampleFASTA.fasta",
+ " -I " + BaseTest.publicTestDir + "exampleBAM.bam",
+ " -out /dev/null").mkString
+ spec.jobRunners = QueueTest.allJobRunners
+ QueueTest.executeTest(spec)
+ }
+
+ @Test(timeOut=36000000)
+ def testCleanupBai() {
+ val spec = new QueueTestSpec
+ spec.name = "cleanupbai"
+ spec.args = Array(
+ " -S " + QueueTest.publicQScriptsPackageDir + "examples/ExamplePrintReads.scala",
+ " -R " + BaseTest.publicTestDir + "exampleFASTA.fasta",
+ " -I " + BaseTest.publicTestDir + "exampleBAM.bam",
+ " -out exampleOut.bam").mkString
+ spec.jobRunners = QueueTest.allJobRunners
+ spec.unexpectedFilePaths :+= ".queue/scatterGather/ExamplePrintReads-1-sg/temp_1_of_1/exampleOut.bai"
+ QueueTest.executeTest(spec)
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleReadFilterQueueTest.scala b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleReadFilterQueueTest.scala
new file mode 100644
index 0000000..af70174
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleReadFilterQueueTest.scala
@@ -0,0 +1,91 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.pipeline.examples
+
+/*
+ * Copyright (c) 2012, The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Copyright (c) 2011, The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+import org.testng.annotations.Test
+import org.broadinstitute.gatk.queue.pipeline.{QueueTest, QueueTestSpec}
+import org.broadinstitute.gatk.utils.BaseTest
+
+class ExampleReadFilterQueueTest {
+ @Test(timeOut=36000000)
+ def testExampleReadFilter() {
+ val spec = new QueueTestSpec
+ spec.name = "examplereadfilter"
+ spec.args = Array(
+ " -S " + QueueTest.publicQScriptsPackageDir + "examples/ExampleReadFilter.scala",
+ " -R " + BaseTest.publicTestDir + "exampleFASTA.fasta",
+ " -I " + BaseTest.publicTestDir + "exampleBAM.bam").mkString
+ QueueTest.executeTest(spec)
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleRetryMemoryLimitQueueTest.scala b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleRetryMemoryLimitQueueTest.scala
new file mode 100644
index 0000000..dddccaa
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/ExampleRetryMemoryLimitQueueTest.scala
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.pipeline.examples
+
+import org.testng.annotations.Test
+import org.broadinstitute.gatk.queue.pipeline.{QueueTest, QueueTestSpec}
+import org.broadinstitute.gatk.utils.BaseTest
+
+class ExampleRetryMemoryLimitQueueTest {
+
+ // This test is currently disabled due to unexplained intermittent failures (see GSA-943)
+ @Test(timeOut=36000000,enabled = false)
+ def testRetryMemoryLimit() {
+ val spec = new QueueTestSpec
+ spec.name = "RetryMemoryLimit"
+ spec.args = Array(
+ " -S " + QueueTest.publicQScriptsPackageDir + "examples/ExampleRetryMemoryLimit.scala",
+ " -R " + BaseTest.publicTestDir + "exampleFASTA.fasta",
+ " -I " + BaseTest.publicTestDir + "exampleBAM.bam",
+ " -retry 1").mkString
+ spec.jobRunners = QueueTest.allJobRunners
+ QueueTest.executeTest(spec)
+ }
+}
diff --git a/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/HelloWorldQueueTest.scala b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/HelloWorldQueueTest.scala
new file mode 100644
index 0000000..093050a
--- /dev/null
+++ b/public/gatk-queue-extensions-public/src/test/scala/org/broadinstitute/gatk/queue/pipeline/examples/HelloWorldQueueTest.scala
@@ -0,0 +1,152 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.pipeline.examples
+
+import org.testng.annotations.Test
+import org.broadinstitute.gatk.queue.pipeline.{QueueTest, QueueTestSpec}
+
+class HelloWorldQueueTest {
+ @Test(timeOut=36000000)
+ def testHelloWorld() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorld"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala"
+ spec.jobRunners = QueueTest.allJobRunners
+ QueueTest.executeTest(spec)
+ }
+
+ @Test(timeOut=36000000)
+ def testHelloWorldWithRunName() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorldWithRunName"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala" +
+ " -runName HelloWorld"
+ spec.jobRunners = QueueTest.allJobRunners
+ QueueTest.executeTest(spec)
+ }
+
+ @Test(timeOut=36000000)
+ def testHelloWorldWithMemoryLimit() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorldMemoryLimit"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala" +
+ " -memLimit 1.25"
+ spec.jobRunners = QueueTest.allJobRunners
+ QueueTest.executeTest(spec)
+ }
+
+ @Test(timeOut=36000000)
+ def testHelloWorldWithPriority() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorldWithPriority"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala" +
+ " -jobPriority 100"
+ spec.jobRunners = QueueTest.allJobRunners
+ QueueTest.executeTest(spec)
+ }
+
+ @Test(timeOut=36000000)
+ def testHelloWorldWithLsfResource() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorldWithLsfResource"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala" +
+ " -jobResReq rusage[iodine_io=1] -jobResReq select[swp>0] -jobResReq order[swp]"
+ spec.jobRunners = Seq("Lsf706")
+ QueueTest.executeTest(spec)
+ }
+
+ @Test(timeOut=36000000)
+ def testHelloWorldWithLsfResourceAndMemoryLimit() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorldWithLsfResourceAndMemoryLimit"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala" +
+ " -memLimit 1.25 -jobResReq rusage[iodine_io=1] -jobResReq select[swp>0] -jobResReq order[swp]"
+ spec.jobRunners = Seq("Lsf706")
+ QueueTest.executeTest(spec)
+ }
+
+ @Test(timeOut=36000000)
+ def testHelloWorldWithLsfEnvironment() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorldWithLsfEnvironment"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala" +
+ " -jobEnv tv"
+ spec.jobRunners = Seq("Lsf706")
+ QueueTest.executeTest(spec)
+ }
+
+ @Test(timeOut=36000000)
+ def testHelloWorldWithGridEngineResource() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorldWithGridEngineResource"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala" +
+ " -jobResReq s_core=1000M"
+ spec.jobRunners = Seq("GridEngine")
+ QueueTest.executeTest(spec)
+ }
+
+ @Test(timeOut=36000000)
+ def testHelloWorldWithGridEngineResourceAndMemoryLimit() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorldWithGridEngineResourceAndMemoryLimit"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala" +
+ " -memLimit 1.25 -jobResReq s_core=1000M"
+ spec.jobRunners = Seq("GridEngine")
+ QueueTest.executeTest(spec)
+ }
+
+ @Test(timeOut=36000000)
+ def testHelloWorldWithGridEngineEnvironment() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorldWithGridEngineEnvironment"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala" +
+ " -jobEnv \"make 1\""
+ spec.jobRunners = Seq("GridEngine")
+ QueueTest.executeTest(spec)
+ }
+
+ // disabled because our DRMAA implementation doesn't support wallTime
+ @Test(enabled=false, timeOut=36000000)
+ def testHelloWorldWithWalltime() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorldWithWalltime"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala" +
+ " -wallTime 100"
+ spec.jobRunners = QueueTest.allJobRunners
+ QueueTest.executeTest(spec)
+ }
+
+ @Test(timeOut=36000000)
+ def testHelloWorldWithLogDirectory() {
+ val spec = new QueueTestSpec
+ spec.name = "HelloWorldWithLogDirectory"
+ spec.args = "-S " + QueueTest.publicQScriptsPackageDir + "examples/HelloWorld.scala" +
+ " -logDir pipelineLogDir"
+ spec.jobRunners = QueueTest.allJobRunners
+ spec.expectedFilePaths = Seq("pipelineLogDir/HelloWorld-1.out")
+ QueueTest.executeTest(spec)
+ }
+}
diff --git a/public/gatk-queue/pom.xml b/public/gatk-queue/pom.xml
new file mode 100644
index 0000000..05ce207
--- /dev/null
+++ b/public/gatk-queue/pom.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-aggregator</artifactId>
+ <version>3.3</version>
+ <relativePath>../..</relativePath>
+ </parent>
+
+ <artifactId>gatk-queue</artifactId>
+ <packaging>jar</packaging>
+ <name>GATK Queue</name>
+
+ <properties>
+ <gatk.basedir>${project.basedir}/../..</gatk.basedir>
+ <gatk.packagetests.artifactId>gatk-queue-package-distribution</gatk.packagetests.artifactId>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-tools-public</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-compiler</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>net.sf.jgrapht</groupId>
+ <artifactId>jgrapht</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-email</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-tools-public</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.scala-tools</groupId>
+ <artifactId>maven-scala-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-resource-bundle-log4j</id>
+ <phase>prepare-package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>extract-resource-bundle</id>
+ <phase>prepare-package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>package-unittests</id>
+ </execution>
+ <execution>
+ <id>package-integrationtests</id>
+ </execution>
+ <execution>
+ <id>package-largescaletests</id>
+ </execution>
+ <execution>
+ <id>package-knowledgebasetests</id>
+ </execution>
+ <execution>
+ <id>package-queuetests</id>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/public/gatk-queue/src/main/java/org/broadinstitute/gatk/queue/QueueVersion.java b/public/gatk-queue/src/main/java/org/broadinstitute/gatk/queue/QueueVersion.java
new file mode 100644
index 0000000..e5e9dcb
--- /dev/null
+++ b/public/gatk-queue/src/main/java/org/broadinstitute/gatk/queue/QueueVersion.java
@@ -0,0 +1,32 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue;
+
+/**
+ * Generates the Queue version in the GATKText.properties by working around http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4492654
+ */
+public class QueueVersion {
+}
diff --git a/public/gatk-queue/src/main/java/org/broadinstitute/gatk/queue/package-info.java b/public/gatk-queue/src/main/java/org/broadinstitute/gatk/queue/package-info.java
new file mode 100644
index 0000000..755b696
--- /dev/null
+++ b/public/gatk-queue/src/main/java/org/broadinstitute/gatk/queue/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue;
diff --git a/public/gatk-queue/src/main/resources/org/broadinstitute/gatk/queue/util/queueJobReport.R b/public/gatk-queue/src/main/resources/org/broadinstitute/gatk/queue/util/queueJobReport.R
new file mode 100644
index 0000000..70d3c78
--- /dev/null
+++ b/public/gatk-queue/src/main/resources/org/broadinstitute/gatk/queue/util/queueJobReport.R
@@ -0,0 +1,240 @@
+library(gsalib)
+library(ggplot2)
+library(gplots)
+library(tools)
+library(reshape)
+library(plyr)
+
+#
+# Standard command line switch. Can we loaded interactively for development
+# or executed with RScript
+#
+args = commandArgs(TRUE)
+onCMDLine = ! is.na(args[1])
+if ( onCMDLine ) {
+ inputFileName = args[1]
+ outputPDF = args[2]
+} else {
+ inputFileName = "~/workspaces/scratch/SingleSample_VQSRwNewSOR.jobreport.txt"
+ #inputFileName = "/humgen/gsa-hpprojects/dev/depristo/oneOffProjects/Q-25718 at node1149.jobreport.txt"
+ #inputFileName = "/humgen/gsa-hpprojects/dev/depristo/oneOffProjects/rodPerformanceGoals/history/report.082711.txt"
+ outputPDF = NA
+}
+
+RUNTIME_UNITS = "(hours)"
+ORIGINAL_UNITS_TO_RUNTIME_UNITS = 1/1000/60/60
+
+#
+# Helper function to aggregate all of the jobs in the report across all tables
+#
+allJobsFromReport <- function(report) {
+ names <- c("jobName", "startTime", "analysisName", "doneTime", "exechosts", "runtime")
+ sub <- lapply(report, function(table) table[,names])
+ do.call("rbind", sub)
+}
+
+#
+# Creates segmentation plots of time (x) vs. job (y) with segments for the duration of the job
+#
+plotJobsGantt <- function(gatkReport, sortOverall, title, includeText) {
+ allJobs = allJobsFromReport(gatkReport)
+ if ( sortOverall ) {
+ allJobs = allJobs[order(allJobs$analysisName, allJobs$startTime, decreasing=T), ]
+ } else {
+ allJobs = allJobs[order(allJobs$startTime, decreasing=T), ]
+ }
+ allJobs$index = 1:nrow(allJobs)
+ minTime = min(allJobs$startTime)
+ allJobs$relStartTime = allJobs$startTime - minTime
+ allJobs$relDoneTime = allJobs$doneTime - minTime
+ allJobs$ganttName = paste(allJobs$jobName, "@", allJobs$exechosts)
+ maxRelTime = max(allJobs$relDoneTime)
+ p <- ggplot(data=allJobs, aes(x=relStartTime, y=index, color=analysisName))
+ p <- p + theme_bw()
+ p <- p + geom_segment(aes(xend=relDoneTime, yend=index), size=1, arrow=arrow(length = unit(0.1, "cm")))
+ if ( includeText )
+ p <- p + geom_text(aes(x=relStartTime, label=ganttName, hjust=0, vjust=-1), size=2)
+ p <- p + xlim(0, maxRelTime * 1.3)
+ p <- p + xlab(paste("Start time, relative to first job", RUNTIME_UNITS))
+ p <- p + ylab("Job number")
+ p <- p + ggtitle(title)
+ print(p)
+}
+
+#
+# Plots scheduling efficiency at job events
+#
+plotProgressByTime <- function(gatkReport) {
+ allJobs = allJobsFromReport(gatkReport)
+ nJobs = dim(allJobs)[1]
+ allJobs = allJobs[order(allJobs$startTime, decreasing=F),]
+ allJobs$index = 1:nrow(allJobs)
+
+ minTime = min(allJobs$startTime)
+ allJobs$relStartTime = allJobs$startTime - minTime
+ allJobs$relDoneTime = allJobs$doneTime - minTime
+
+ times = sort(c(allJobs$relStartTime, allJobs$relDoneTime))
+
+ countJobs <- function(p) {
+ s = allJobs$relStartTime
+ e = allJobs$relDoneTime
+ x = c() # I wish I knew how to make this work with apply
+ for ( time in times )
+ x = c(x, sum(p(s, e, time)))
+ x
+ }
+
+ pending = countJobs(function(s, e, t) s > t)
+ done = countJobs(function(s, e, t) e < t)
+ running = nJobs - pending - done
+
+ d = data.frame(times=times, pending=pending, running=running, done=done)
+
+ p <- ggplot(data=melt(d, id.vars=c("times")), aes(x=times, y=value, color=variable))
+ p <- p + facet_grid(variable ~ ., scales="free")
+ p <- p + geom_line(size=2)
+ p <- p + xlab(paste("Time since start of first job", RUNTIME_UNITS))
+ p <- p + ggtitle("Job scheduling")
+ print(p)
+}
+
+#
+# Creates tables for each job in this group
+#
+standardColumns = c("jobName", "startTime", "formattedStartTime", "analysisName", "intermediate", "exechosts", "formattedDoneTime", "doneTime", "runtime")
+plotGroup <- function(groupTable) {
+ name = unique(groupTable$analysisName)[1]
+ groupAnnotations = setdiff(names(groupTable), standardColumns)
+ sub = groupTable[,c("jobName", groupAnnotations, "runtime")]
+ sub = sub[order(sub$iteration, sub$jobName, decreasing=F), ]
+
+ # create a table showing each job and all annotations
+ textplot(sub, show.rownames=F)
+ title(paste("Job summary for", name, "full itemization"), cex=3)
+
+ # create the table for each combination of values in the group, listing iterations in the columns
+ sum = cast(melt(sub, id.vars=groupAnnotations, measure.vars=c("runtime")), ... ~ iteration, fun.aggregate=mean)
+ textplot(as.data.frame(sum), show.rownames=F)
+ title(paste("Job summary for", name, "itemizing each iteration"), cex=3)
+
+ # histogram of job times by groupAnnotations
+ if ( length(groupAnnotations) == 1 && dim(sub)[1] > 1 ) {
+ # todo -- how do we group by annotations?
+ p <- ggplot(data=sub, aes(x=runtime)) + geom_histogram()
+ p <- p + xlab(paste("runtime", RUNTIME_UNITS)) + ylab("No. of jobs")
+ p <- p + ggtitle(paste("Job runtime histogram for", name))
+ print(p)
+ }
+
+ # as above, but averaging over all iterations
+ groupAnnotationsNoIteration = setdiff(groupAnnotations, "iteration")
+ if ( dim(sub)[1] > 1 ) {
+ try({ # need a try here because we will fail to reduce when there's just a single iteration
+ sum = cast(melt(sub, id.vars=groupAnnotationsNoIteration, measure.vars=c("runtime")), ... ~ ., fun.aggregate=c(mean, sd))
+ textplot(as.data.frame(sum), show.rownames=F)
+ title(paste("Job summary for", name, "averaging over all iterations"), cex=3)
+ }, silent=T)
+ }
+}
+
+# print out some useful basic information
+print("Report")
+print(paste("Project :", inputFileName))
+
+convertUnits <- function(gatkReportData) {
+ convertGroup <- function(g) {
+ g$runtime = g$runtime * ORIGINAL_UNITS_TO_RUNTIME_UNITS
+ g$startTime = g$startTime * ORIGINAL_UNITS_TO_RUNTIME_UNITS
+ g$doneTime = g$doneTime * ORIGINAL_UNITS_TO_RUNTIME_UNITS
+ g
+ }
+ lapply(gatkReportData, convertGroup)
+}
+
+#
+# Plots runtimes by analysis name and exechosts
+#
+# Useful to understand the performance of analysis jobs by hosts,
+# and to debug problematic nodes
+#
+plotTimeByHost <- function(gatkReportData) {
+ fields = c("analysisName", "exechosts", "runtime")
+
+ runtimes = data.frame()
+ for ( report in gatkReportData ) {
+ runtimes = rbind(runtimes, report[,fields])
+ }
+
+ plotMe <- function(name, vis) {
+ p = ggplot(data=runtimes, aes(x=exechosts, y=runtime, group=exechosts, color=exechosts))
+ p = p + facet_grid(analysisName ~ ., scale="free")
+ p = p + vis()
+ p = p + xlab("Job execution host")
+ p = p + ggtitle(paste(name, "of job runtimes by analysis name and execution host"))
+ p = p + ylab(paste("Distribution of runtimes", RUNTIME_UNITS))
+ p = p + theme(axis.text.x=element_text(angle=45, hjust=1, vjust=1))
+ print(p)
+ }
+
+ plotMe("Boxplot", geom_boxplot)
+ plotMe("Jittered points", geom_jitter)
+}
+
+mergeScattersForAnalysis <- function(table) {
+ #allJobs$ganttName = paste(allJobs$jobName, "@", allJobs$exechosts)
+
+ ddply(table, .(analysisName, iteration), summarize,
+ jobName = analysisName[1],
+ exechosts = paste(length(exechosts), "hosts"),
+ formattedStartTime = "NA",
+ formattedDoneTime = "NA",
+ intermediate = intermediate[1],
+ startTime = min(startTime),
+ doneTime = min(startTime) + sum(runtime),
+ runtime = sum(runtime))
+}
+
+mergeScatters <- function(report) {
+ newReport = list()
+ for ( name in names(gatkReportData) ) {
+ newReport[[name]] = mergeScattersForAnalysis(gatkReportData[[name]])
+ }
+ newReport
+}
+
+# read the table
+gatkReportData <- gsa.read.gatkreport(inputFileName)
+gatkReportData <- convertUnits(gatkReportData)
+#print(summary(gatkReportData))
+
+if ( ! is.na(outputPDF) ) {
+ pdf(outputPDF, height=8.5, width=11)
+}
+
+plotJobsGantt(gatkReportData, T, "All jobs, by analysis, by start time", F)
+plotJobsGantt(gatkReportData, F, "All jobs, sorted by start time", F)
+plotProgressByTime(gatkReportData)
+
+# plots summarizing overall costs, merging scattered counts
+merged.by.scatter = mergeScatters(gatkReportData)
+plotJobsGantt(merged.by.scatter, F, "Jobs merged by scatter by start time", T)
+
+merged.as.df = do.call(rbind.data.frame, merged.by.scatter)[,c("analysisName", "runtime")]
+merged.as.df$percent = merged.as.df$runtime / sum(merged.as.df$runtime) * 100
+merged.as.df.formatted = data.frame(analysisName=merged.as.df$analysisName,runtime=prettyNum(merged.as.df$runtime), percent=prettyNum(merged.as.df$percent,digits=2))
+textplot(merged.as.df.formatted[order(merged.as.df$runtime),], show.rownames=F)
+title("Total runtime for each analysis")
+
+plotTimeByHost(gatkReportData)
+for ( group in gatkReportData ) {
+ #print(group)
+ plotGroup(group)
+}
+
+if ( ! is.na(outputPDF) ) {
+ dev.off()
+ if (exists("compactPDF")) {
+ compactPDF(outputPDF)
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QCommandLine.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QCommandLine.scala
new file mode 100644
index 0000000..297e10b
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QCommandLine.scala
@@ -0,0 +1,295 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue
+
+import java.io.File
+import org.broadinstitute.gatk.utils.commandline._
+import org.broadinstitute.gatk.queue.util._
+import org.broadinstitute.gatk.queue.engine.{QStatusMessenger, QGraphSettings, QGraph}
+import collection.JavaConversions._
+import org.broadinstitute.gatk.utils.classloader.PluginManager
+import org.broadinstitute.gatk.utils.exceptions.UserException
+import org.broadinstitute.gatk.utils.io.IOUtils
+import org.broadinstitute.gatk.utils.help.ApplicationDetails
+import java.util.{ResourceBundle, Arrays}
+import org.broadinstitute.gatk.utils.text.TextFormattingUtils
+import org.apache.commons.io.FilenameUtils
+
+/**
+ * Entry point of Queue. Compiles and runs QScripts passed in to the command line.
+ */
+object QCommandLine extends Logging {
+ /**
+ * Main.
+ * @param argv Arguments.
+ */
+ def main(argv: Array[String]) {
+ val qCommandLine = new QCommandLine
+
+ val shutdownHook = new Thread {
+ override def run() {
+ logger.info("Shutting down jobs. Please wait...")
+ qCommandLine.shutdown()
+ }
+ }
+
+ Runtime.getRuntime.addShutdownHook(shutdownHook)
+
+ try {
+ CommandLineProgram.start(qCommandLine, argv)
+ try {
+ Runtime.getRuntime.removeShutdownHook(shutdownHook)
+ qCommandLine.shutdown()
+ } catch {
+ case e: Exception => /* ignore, example 'java.lang.IllegalStateException: Shutdown in progress' */
+ }
+ if (CommandLineProgram.result != 0)
+ System.exit(CommandLineProgram.result)
+ } catch {
+ case e: Exception => CommandLineProgram.exitSystemWithError(e)
+ }
+ }
+}
+
+/**
+ * Entry point of Queue. Compiles and runs QScripts passed in to the command line.
+ */
+class QCommandLine extends CommandLineProgram with Logging {
+ @Input(fullName="script", shortName="S", doc="QScript scala file", required=true)
+ @ClassType(classOf[File])
+ var scripts = Seq.empty[File]
+
+ @ArgumentCollection
+ val settings = new QGraphSettings
+
+ private val qScriptManager = new QScriptManager
+ private val qGraph = new QGraph
+ private var qScriptClasses: File = _
+ private var shuttingDown = false
+
+ private lazy val qScriptPluginManager = {
+ qScriptClasses = IOUtils.tempDir("Q-Classes-", "", settings.qSettings.tempDirectory)
+ qScriptManager.loadScripts(scripts, qScriptClasses)
+ new PluginManager[QScript](qPluginType, Seq(qScriptClasses.toURI.toURL))
+ }
+
+ private lazy val qCommandPlugin = {
+ new PluginManager[QCommandPlugin](classOf[QCommandPlugin])
+ }
+
+ private lazy val allCommandPlugins = qCommandPlugin.createAllTypes()
+
+ private lazy val qPluginType: Class[_ <: QScript] = {
+ allCommandPlugins.map(_.qScriptClass).headOption.getOrElse(classOf[QScript])
+ }
+
+ /**
+ * Takes the QScripts passed in, runs their script() methods, retrieves their generated
+ * functions, and then builds and runs a QGraph based on the dependencies.
+ */
+ def execute = {
+ var success = false
+ var result = 1
+ var functionsAndStatusSize = 0
+ try {
+ ClassFieldCache.parsingEngine = this.parser
+
+ if (settings.qSettings.runName == null)
+ settings.qSettings.runName = FilenameUtils.removeExtension(scripts.head.getName)
+ if (IOUtils.isDefaultTempDir(settings.qSettings.tempDirectory))
+ settings.qSettings.tempDirectory = IOUtils.absolute(settings.qSettings.runDirectory, ".queue/tmp")
+ qGraph.initializeWithSettings(settings)
+
+ for (commandPlugin <- allCommandPlugins) {
+ loadArgumentsIntoObject(commandPlugin)
+ }
+
+ for (commandPlugin <- allCommandPlugins) {
+ if (commandPlugin.statusMessenger != null)
+ commandPlugin.statusMessenger.started()
+ }
+
+ qGraph.messengers = allCommandPlugins.filter(_.statusMessenger != null).map(_.statusMessenger).toSeq
+
+ // TODO: Default command plugin argument?
+ val remoteFileConverter = (
+ for (commandPlugin <- allCommandPlugins if (commandPlugin.remoteFileConverter != null))
+ yield commandPlugin.remoteFileConverter
+ ).headOption.getOrElse(null)
+
+ if (remoteFileConverter != null)
+ loadArgumentsIntoObject(remoteFileConverter)
+
+ val allQScripts = qScriptPluginManager.createAllTypes()
+ for (script <- allQScripts) {
+ logger.info("Scripting " + qScriptPluginManager.getName(script.getClass.asSubclass(classOf[QScript])))
+ loadArgumentsIntoObject(script)
+ allCommandPlugins.foreach(_.initScript(script))
+ // TODO: Pulling inputs can be time/io expensive! Some scripts are using the files to generate functions-- even for dry runs-- so pull it all down for now.
+ //if (settings.run)
+ script.pullInputs()
+ script.qSettings = settings.qSettings
+ try {
+ script.script()
+ } catch {
+ case e: Exception =>
+ throw new UserException.CannotExecuteQScript(script.getClass.getSimpleName + ".script() threw the following exception: " + e, e)
+ }
+
+ if (remoteFileConverter != null) {
+ if (remoteFileConverter.convertToRemoteEnabled)
+ script.mkRemoteOutputs(remoteFileConverter)
+ }
+
+ script.functions.foreach(qGraph.add(_))
+ logger.info("Added " + script.functions.size + " functions")
+ }
+ // Execute the job graph
+ qGraph.run()
+
+ val functionsAndStatus = qGraph.getFunctionsAndStatus
+
+ // walk over each script, calling onExecutionDone
+ for (script <- allQScripts) {
+ val scriptFunctions = functionsAndStatus.filterKeys(f => script.functions.contains(f))
+ script.onExecutionDone(scriptFunctions, success)
+ }
+ functionsAndStatusSize = functionsAndStatus.size
+
+ // write the final complete job report
+ logger.info("Writing final jobs report...")
+ qGraph.writeJobsReport()
+
+ if (qGraph.success) {
+ if (settings.run) {
+ allQScripts.foreach(_.pushOutputs())
+ for (commandPlugin <- allCommandPlugins)
+ if (commandPlugin.statusMessenger != null) {
+ val allInputs = allQScripts.map(_.remoteInputs)
+ val allOutputs = allQScripts.map(_.remoteOutputs)
+ commandPlugin.statusMessenger.done(allInputs, allOutputs)
+ }
+ }
+ success = true
+ result = 0
+ }
+ } finally {
+ if (!success) {
+ logger.info("Done with errors")
+ qGraph.logFailed()
+ if (settings.run) {
+ for (commandPlugin <- allCommandPlugins)
+ if (commandPlugin.statusMessenger != null)
+ commandPlugin.statusMessenger.exit("Done with errors: %s".format(qGraph.formattedStatusCounts))
+ }
+ }
+ }
+ if (success)
+ logger.info("Script completed successfully with %d total jobs".format(functionsAndStatusSize))
+ else
+ logger.info("Script failed: %s".format(qGraph.formattedStatusCounts))
+ result
+ }
+
+ /**
+ * Returns true as QScripts are located and compiled.
+ * @return true
+ */
+ override def canAddArgumentsDynamically = true
+
+ /**
+ * Returns the list of QScripts passed in via -S and other plugins
+ * so that their arguments can be inspected before QScript.script is called.
+ * @return Array of dynamic sources
+ */
+ override def getArgumentSources = {
+ var plugins = Seq.empty[Class[_]]
+ plugins ++= qScriptPluginManager.getPlugins
+ plugins ++= qCommandPlugin.getPlugins
+ plugins.toArray
+ }
+
+ /**
+ * Returns the name of a script/plugin
+ * @return The name of a script/plugin
+ */
+ override def getArgumentSourceName(source: Class[_]) = {
+ if (classOf[QScript].isAssignableFrom(source))
+ qScriptPluginManager.getName(source.asSubclass(classOf[QScript]))
+ else if (classOf[QCommandPlugin].isAssignableFrom(source))
+ qCommandPlugin.getName(source.asSubclass(classOf[QCommandPlugin]))
+ else
+ null
+ }
+
+ /**
+ * Returns a ScalaCompoundArgumentTypeDescriptor that can parse argument sources into scala collections.
+ * @return a ScalaCompoundArgumentTypeDescriptor
+ */
+ override def getArgumentTypeDescriptors =
+ Arrays.asList(new ScalaCompoundArgumentTypeDescriptor)
+
+ override def getApplicationDetails : ApplicationDetails = {
+ new ApplicationDetails(createQueueHeader(),
+ Seq.empty[String],
+ ApplicationDetails.createDefaultRunningInstructions(getClass.asInstanceOf[Class[CommandLineProgram]]),
+ "")
+ }
+
+ private def createQueueHeader() : Seq[String] = {
+ Seq(String.format("Queue v%s, Compiled %s", getQueueVersion, getBuildTimestamp),
+ "Copyright (c) 2012 The Broad Institute",
+ "For support and documentation go to http://www.broadinstitute.org/gatk")
+ }
+
+ private def getQueueVersion : String = {
+ val stingResources : ResourceBundle = TextFormattingUtils.loadResourceBundle("GATKText")
+
+ if ( stingResources.containsKey("org.broadinstitute.gatk.queue.QueueVersion.version") ) {
+ stingResources.getString("org.broadinstitute.gatk.queue.QueueVersion.version")
+ }
+ else {
+ "<unknown>"
+ }
+ }
+
+ private def getBuildTimestamp : String = {
+ val stingResources : ResourceBundle = TextFormattingUtils.loadResourceBundle("GATKText")
+
+ if ( stingResources.containsKey("build.timestamp") ) {
+ stingResources.getString("build.timestamp")
+ }
+ else {
+ "<unknown>"
+ }
+ }
+
+ def shutdown() = {
+ shuttingDown = true
+ qGraph.shutdown()
+ if (qScriptClasses != null) IOUtils.tryDelete(qScriptClasses)
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QCommandPlugin.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QCommandPlugin.scala
new file mode 100644
index 0000000..6df8b3c
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QCommandPlugin.scala
@@ -0,0 +1,36 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue
+
+import engine.QStatusMessenger
+import util.RemoteFileConverter
+
+trait QCommandPlugin {
+ def statusMessenger: QStatusMessenger = null
+ def remoteFileConverter: RemoteFileConverter = null
+ def qScriptClass: Class[_ <: QScript] = classOf[QScript]
+ def initScript(script: QScript) {}
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QException.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QException.scala
new file mode 100644
index 0000000..1ae41e9
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QException.scala
@@ -0,0 +1,31 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue
+
+import org.broadinstitute.gatk.utils.exceptions.GATKException
+
+class QException(private val message: String, private val throwable: Throwable = null)
+ extends GATKException(message, throwable)
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QScript.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QScript.scala
new file mode 100644
index 0000000..f010445
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QScript.scala
@@ -0,0 +1,184 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue
+
+import engine.JobRunInfo
+import org.broadinstitute.gatk.queue.function.QFunction
+import annotation.target.field
+import util._
+import org.broadinstitute.gatk.utils.commandline.ArgumentSource
+
+/**
+ * Defines a Queue pipeline as a collection of CommandLineFunctions.
+ */
+trait QScript extends Logging with PrimitiveOptionConversions with StringFileConversions {
+
+ // Type aliases so users don't have to import
+ type File = java.io.File
+ type CommandLineFunction = org.broadinstitute.gatk.queue.function.CommandLineFunction
+ type InProcessFunction = org.broadinstitute.gatk.queue.function.InProcessFunction
+ type ScatterGatherableFunction = org.broadinstitute.gatk.queue.function.scattergather.ScatterGatherableFunction
+ type SimpleTextGatherFunction = org.broadinstitute.gatk.queue.function.scattergather.SimpleTextGatherFunction
+
+ // Make sure annotations can be used in class constructors but target the fields
+ // ex: class MyClass(@Input var myVar: File) {}
+ // This was implicitly enabled in 2.8.0-RC2 and then updated to this new syntax:
+ // http://lampsvn.epfl.ch/trac/scala/ticket/3596
+ // http://lampsvn.epfl.ch/trac/scala/ticket/3421
+ type Input = org.broadinstitute.gatk.utils.commandline.Input @field
+ type Output = org.broadinstitute.gatk.utils.commandline.Output @field
+ type Argument = org.broadinstitute.gatk.utils.commandline.Argument @field
+ type ArgumentCollection = org.broadinstitute.gatk.utils.commandline.ArgumentCollection @field
+ type Gather = org.broadinstitute.gatk.utils.commandline.Gather @field
+
+ /**
+ * Default settings for QFunctions
+ */
+ var qSettings: QSettings = _
+
+ /**
+ * Builds the CommandLineFunctions that will be used to run this script and adds them to this.functions directly or using the add() utility method.
+ */
+ def script()
+
+ /**
+ * A default handler for the onExecutionDone() function. By default this doesn't do anything
+ */
+ def onExecutionDone(jobs: Map[QFunction, JobRunInfo], success: Boolean) {
+ }
+
+ /**
+ * The command line functions that will be executed for this QScript.
+ */
+ var functions = Seq.empty[QFunction]
+
+ /**
+ * Exchanges the extension on a file.
+ * @param file File to look for the extension.
+ * @param oldExtension Old extension to strip off, if present.
+ * @param newExtension New extension to append.
+ * @return new File with the new extension in the current directory.
+ */
+ protected def swapExt(file: File, oldExtension: String, newExtension: String) =
+ new File(file.getName.stripSuffix(oldExtension) + newExtension)
+
+ /**
+ * Exchanges the extension on a file.
+ * @param dir New directory for the file.
+ * @param file File to look for the extension.
+ * @param oldExtension Old extension to strip off, if present.
+ * @param newExtension New extension to append.
+ * @return new File with the new extension in dir.
+ */
+ protected def swapExt(dir: File, file: File, oldExtension: String, newExtension: String) =
+ new File(dir, file.getName.stripSuffix(oldExtension) + newExtension)
+
+ /**
+ * Adds one or more command line functions to be run.
+ * @param functions Functions to add.
+ */
+ def add(functions: QFunction*) {
+ functions.foreach(function => function.addOrder = QScript.nextAddOrder)
+ this.functions ++= functions
+ }
+
+ def addAll(functions: Traversable[QFunction]) {
+ functions.foreach( f => add(f) )
+ }
+
+ /**
+ * Convert all @Output files to remote output files.
+ * @param remoteFileConverter Converter for files to remote files.
+ */
+ def mkRemoteOutputs(remoteFileConverter: RemoteFileConverter) {
+ for (field <- outputFields) {
+ val fieldFile = ClassFieldCache.getFieldFile(this, field)
+ if (fieldFile != null && !fieldFile.isInstanceOf[RemoteFile]) {
+ val fieldName = ClassFieldCache.fullName(field)
+ val remoteFile = remoteFileConverter.convertToRemote(fieldFile, fieldName)
+ ClassFieldCache.setFieldValue(this, field, remoteFile)
+ }
+ }
+ }
+
+ /**
+ * Pull all remote files to the local disk
+ */
+ def pullInputs() {
+ val inputs = ClassFieldCache.getFieldFiles(this, inputFields)
+ for (remoteFile <- filterRemoteFiles(inputs)) {
+ logger.info("Pulling %s from %s".format(remoteFile.getAbsolutePath, remoteFile.remoteDescription))
+ remoteFile.pullToLocal()
+ }
+ }
+
+ /**
+ * Push all remote files from the local disk
+ */
+ def pushOutputs() {
+ val outputs = ClassFieldCache.getFieldFiles(this, outputFields)
+ for (remoteFile <- filterRemoteFiles(outputs)) {
+ logger.info("Pushing %s to %s".format(remoteFile.getAbsolutePath, remoteFile.remoteDescription))
+ remoteFile.pushToRemote()
+ }
+ }
+
+ private def filterRemoteFiles(fields: Seq[File]): Seq[RemoteFile] =
+ fields.filter(field => field != null && field.isInstanceOf[RemoteFile]).map(_.asInstanceOf[RemoteFile])
+ /**
+ * @return the inputs or null if there are no inputs
+ */
+ def remoteInputs: AnyRef = null
+
+ /**
+ * @return the outputs or null if there are no outputs
+ */
+ def remoteOutputs: AnyRef = null
+
+ /** The complete list of fields. */
+ def functionFields: Seq[ArgumentSource] = ClassFieldCache.classFunctionFields(this.getClass)
+ /** The @Input fields. */
+ def inputFields: Seq[ArgumentSource] = ClassFieldCache.classInputFields(this.getClass)
+ /** The @Output fields. */
+ def outputFields: Seq[ArgumentSource] = ClassFieldCache.classOutputFields(this.getClass)
+ /** The @Argument fields. */
+ def argumentFields: Seq[ArgumentSource] = ClassFieldCache.classArgumentFields(this.getClass)
+}
+
+object QScript {
+ private var addOrder = 0
+ private def nextAddOrder = {
+ addOrder += 1
+ Seq(addOrder)
+ }
+
+ /**
+ * Resets the add order back to zero. Useful for testing purposes.
+ */
+ def resetAddOrder() {
+ addOrder = 0
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QScriptManager.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QScriptManager.scala
new file mode 100644
index 0000000..8df12c2
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QScriptManager.scala
@@ -0,0 +1,168 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue
+
+import scala.tools.nsc.{Global, Settings}
+import scala.tools.nsc.io.PlainFile
+import org.broadinstitute.gatk.queue.util.Logging
+import collection.JavaConversions._
+import java.io.File
+import scala.tools.nsc.reporters.AbstractReporter
+import java.lang.String
+import org.apache.log4j.Level
+import org.broadinstitute.gatk.queue.util.TextFormatUtils._
+import org.broadinstitute.gatk.utils.classloader.JVMUtils
+import scala.reflect.internal.util.{FakePos, NoPosition, Position, StringOps}
+import org.broadinstitute.gatk.utils.exceptions.UserException
+
+/**
+ * Plugin manager for QScripts which loads QScripts into the current class loader.
+ */
+class QScriptManager() extends Logging {
+ /**
+ * Compiles and loads the scripts in the files into the current classloader.
+ * Heavily based on scala/src/compiler/scala/tools/ant/Scalac.scala
+ */
+ def loadScripts(scripts: Seq[File], tempDir: File) {
+ // Make sure the scripts actually exist.
+ scripts.foreach{
+ file => if( !file.exists()) throw new UserException.CouldNotReadInputFile(file, "it does not exist.")
+ }
+
+ if (scripts.size > 0) {
+ val settings = new Settings((error: String) => logger.error(error))
+ settings.deprecation.value = true
+ settings.outdir.value = tempDir.getPath
+
+ // Set the classpath to the current class path.
+ JVMUtils.getClasspathURLs.foreach(url => {
+ settings.bootclasspath.append(url.getPath)
+ settings.classpath.append(url.getPath)
+ })
+
+ val reporter = new QScriptManager.Log4JReporter(settings)
+
+ val compiler = new Global(settings, reporter)
+ val run = new compiler.Run
+
+ logger.info("Compiling %s QScript%s".format(scripts.size, plural(scripts.size)))
+ logger.debug("Compilation directory: " + settings.outdir.value)
+ run.compileFiles(scripts.toList.map(new PlainFile(_)))
+
+ reporter.printSummary()
+ if (reporter.hasErrors) {
+ val msg = "Compile of %s failed with %d error%s".format(
+ scripts.mkString(", "), reporter.ERROR.count, plural(reporter.ERROR.count))
+ throw new QException(msg)
+ }
+ else if (reporter.WARNING.count > 0)
+ logger.warn("Compile succeeded with %d warning%s".format(
+ reporter.WARNING.count, plural(reporter.WARNING.count)))
+ else
+ logger.info("Compilation complete")
+ }
+ }
+}
+
+/**
+ * Plugin manager for QScripts which loads QScripts into the current classloader.
+ */
+object QScriptManager extends Logging {
+
+ /**
+ * NSC (New Scala Compiler) reporter which logs to Log4J.
+ * Heavily based on scala/src/compiler/scala/tools/nsc/reporters/ConsoleReporter.scala
+ */
+ private class Log4JReporter(val settings: Settings) extends AbstractReporter {
+ def displayPrompt() { throw new UnsupportedOperationException("Unable to prompt the user. Prompting should be off.") }
+
+ /**
+ * Displays the message at position with severity.
+ * @param posIn Position of the event in the file that generated the message.
+ * @param msg Message to display.
+ * @param severity Severity of the event.
+ */
+ def display(posIn: Position, msg: String, severity: Severity) {
+ severity.count += 1
+ val level = severity match {
+ case INFO => Level.INFO
+ case WARNING => Level.WARN
+ case ERROR => Level.ERROR
+ }
+ val pos = if (posIn eq null) NoPosition
+ else if (posIn.isDefined) posIn.inUltimateSource(posIn.source)
+ else posIn
+ pos match {
+ case FakePos(fmsg) =>
+ printMessage(level, fmsg+" "+msg)
+ case NoPosition =>
+ printMessage(level, msg)
+ case _ =>
+ val file = pos.source.file
+ printMessage(level, file.name+":"+pos.line+": "+msg)
+ printSourceLine(level, pos)
+ }
+ }
+
+ /**
+ * Prints a summary count of warnings and errors.
+ */
+ def printSummary() {
+ if (WARNING.count > 0)
+ printMessage(Level.WARN, StringOps.countElementsAsString(WARNING.count, "warning") + " found")
+ if (ERROR.count > 0)
+ printMessage(Level.ERROR, StringOps.countElementsAsString(ERROR.count, "error") + " found")
+ }
+
+ /**
+ * Prints the source code line of an event followed by a pointer within the line to the error.
+ * @param level Severity level.
+ * @param pos Position in the file of the event.
+ */
+ private def printSourceLine(level: Level, pos: Position) {
+ printMessage(level, pos.lineContent.stripLineEnd)
+ printColumnMarker(level, pos)
+ }
+
+ /**
+ * Prints the column marker of the given position.
+ * @param level Severity level.
+ * @param pos Position in the file of the event.
+ */
+ private def printColumnMarker(level: Level, pos: Position) {
+ if (pos.isDefined) { printMessage(level, " " * (pos.column - 1) + "^") }
+ }
+
+ /**
+ * Prints the message at the severity level.
+ * @param level Severity level.
+ * @param message Message content.
+ */
+ private def printMessage(level: Level, message: String) {
+ logger.log(level, message)
+ }
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QSettings.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QSettings.scala
new file mode 100644
index 0000000..86457fb
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/QSettings.scala
@@ -0,0 +1,101 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue
+
+import java.io.File
+import org.broadinstitute.gatk.utils.commandline.{ClassType, Argument}
+
+/**
+ * Default settings settable on the command line and passed to CommandLineFunctions.
+ */
+class QSettings {
+ @Argument(fullName="run_name", shortName="runName", doc="A name for this run used for various status messages.", required=false)
+ var runName: String = _
+
+ @Argument(fullName="job_project", shortName="jobProject", doc="Default project for compute farm jobs.", required=false)
+ var jobProject: String = _
+
+ @Argument(fullName="job_queue", shortName="jobQueue", doc="Default queue for compute farm jobs.", required=false)
+ var jobQueue: String = _
+
+ @Argument(fullName="job_priority", shortName="jobPriority", doc="Default priority for jobs. Min = 0, Max = 100", required=false)
+ @ClassType(classOf[Int])
+ var jobPriority: Option[Int] = None
+
+ @Argument(fullName="job_native_arg", shortName="jobNative", doc="Native arguments to pass to the job runner.", required=false)
+ var jobNativeArgs: Seq[String] = Nil
+
+ @Argument(fullName="job_resource_request", shortName="jobResReq", doc="Resource requests to pass to the job runner.", required=false)
+ var jobResourceRequests: Seq[String] = Nil
+
+ @Argument(fullName="job_environment_name", shortName="jobEnv", doc="Environment names for the job runner.", required=false)
+ var jobEnvironmentNames: Seq[String] = Nil
+
+ @Argument(fullName="memory_limit", shortName="memLimit", doc="Default memory limit for jobs, in gigabytes. If not set defaults to 2GB.", required=false)
+ @ClassType(classOf[Double])
+ var memoryLimit: Option[Double] = Some(2)
+
+ @Argument(fullName="memory_limit_threshold", shortName="memLimitThresh", doc="After passing this threshold stop increasing memory limit for jobs, in gigabytes.", required=false)
+ @ClassType(classOf[Double])
+ var memoryLimitThreshold: Option[Double] = None
+
+ @Argument(fullName="resident_memory_limit", shortName="resMemLimit", doc="Default resident memory limit for jobs, in gigabytes.", required=false)
+ @ClassType(classOf[Double])
+ var residentLimit: Option[Double] = None
+
+ @Argument(fullName="resident_memory_request", shortName="resMemReq", doc="Default resident memory request for jobs, in gigabytes.", required=false)
+ @ClassType(classOf[Double])
+ var residentRequest: Option[Double] = None
+
+ @Argument(fullName="resident_memory_request_parameter", shortName="resMemReqParam", doc="Parameter for resident memory requests. By default not requested.", required=false)
+ var residentRequestParameter: String = _
+
+ @Argument(fullName="job_walltime", shortName="wallTime", doc="Setting the required DRMAA walltime or LSF run limit.", required=false)
+ @ClassType(classOf[Long])
+ var jobWalltime: Option[Long] = None
+
+ /** The name of the parallel environment (required for SGE, for example) */
+ @Argument(fullName="job_parallel_env", shortName="jobParaEnv", doc="An SGE style parallel environment to use for jobs requesting more than 1 core. Equivalent to submitting jobs with -pe ARG nt for jobs with nt > 1", required=false)
+ var parallelEnvironmentName: String = "smp_pe" // Broad default
+
+ @Argument(fullName="dontRequestMultipleCores", shortName="multiCoreJerk", doc="If provided, Queue will not request multiple processors for jobs using multiple processors. Sometimes you eat the bear, sometimes the bear eats you.", required=false)
+ var dontRequestMultipleCores: Boolean = false
+
+ @Argument(fullName="disableDefaultJavaGCOptimizations", shortName="noGCOpt", doc="If provided, Queue will not ensure that java GC threads are limited and that the a minimum amount of time is spent in GC.")
+ var disableDefaultJavaGCOptimizations = false
+
+ @Argument(fullName="run_directory", shortName="runDir", doc="Root directory to run functions from.", required=false)
+ var runDirectory = new File(".")
+
+ @Argument(fullName="temp_directory", shortName="tempDir", doc="Temp directory to pass to functions.", required=false)
+ var tempDirectory = new File(System.getProperty("java.io.tmpdir"))
+
+ @Argument(fullName="job_scatter_gather_directory", shortName="jobSGDir", doc="Default directory to place scatter gather output for compute farm jobs.", required=false)
+ var jobScatterGatherDirectory: File = _
+
+ @Argument(fullName="log_directory", shortName="logDir", doc="Directory to write log files into.", required=false)
+ var logDirectory: File = _
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/CommandLineJobManager.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/CommandLineJobManager.scala
new file mode 100644
index 0000000..a3b004c
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/CommandLineJobManager.scala
@@ -0,0 +1,35 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+
+/**
+ * Creates and stops CommandLineJobRunners
+ */
+trait CommandLineJobManager[TRunner <: CommandLineJobRunner] extends JobManager[CommandLineFunction, TRunner] {
+ def functionType = classOf[CommandLineFunction]
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/CommandLineJobRunner.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/CommandLineJobRunner.scala
new file mode 100644
index 0000000..e5c2594
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/CommandLineJobRunner.scala
@@ -0,0 +1,107 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import java.io.File
+import org.broadinstitute.gatk.queue.util.Logging
+import org.broadinstitute.gatk.utils.io.IOUtils
+
+/**
+ * Runs a command line function.
+ */
+trait CommandLineJobRunner extends JobRunner[CommandLineFunction] with Logging {
+
+ /** The string representation of the identifier of the running job. */
+ def jobIdString: String = null
+
+ /** A generated exec shell script. */
+ protected var jobScript: File = _
+
+ /** Which directory to use for the job status files. */
+ protected def jobStatusDir = function.jobTempDir
+
+ /** Amount of time a job can go without status before giving up. */
+ private val unknownStatusMaxSeconds = 5 * 60
+
+ /** Last known status */
+ protected var lastStatus: RunnerStatus.Value = _
+
+ /** The last time the status was updated */
+ protected var lastStatusUpdate: Long = _
+
+ /** The runner specific priority for a minimum priority job */
+ protected val minRunnerPriority = 0
+
+ /** The runner specific priority for a maximum priority job */
+ protected val maxRunnerPriority = 0
+
+ /** The priority of the function in the range defined by the runner */
+ protected def functionPriority = {
+ function.jobPriority.map { priority =>
+ (((priority / 100D) * (maxRunnerPriority - minRunnerPriority)) + minRunnerPriority).
+ round.intValue() min maxRunnerPriority max minRunnerPriority
+ }
+ }
+
+ final override def status = this.lastStatus
+
+ override def init() {
+ super.init()
+ val exec = new StringBuilder
+
+ var dirs = Set.empty[File]
+ for (dir <- function.jobDirectories)
+ dirs += IOUtils.dirLevel(dir, 2)
+ if (dirs.size > 0) {
+ // prepend "cd '<dir_1>' [&& cd '<dir_n>']" to automount the directories.
+ exec.append(dirs.mkString("cd '", "' && cd '", "'"))
+ exec.append(" && cd '%s' && \\%n".format(function.commandDirectory))
+ }
+ exec.append(function.commandLine)
+
+ this.jobScript = IOUtils.writeTempFile(exec.toString(), ".exec", "", jobStatusDir)
+ }
+
+ protected def updateStatus(updatedStatus: RunnerStatus.Value) {
+ this.lastStatus = updatedStatus
+ this.lastStatusUpdate = System.currentTimeMillis
+ }
+
+ override def checkUnknownStatus() {
+ val unknownStatusMillis = (System.currentTimeMillis - lastStatusUpdate)
+ if (unknownStatusMillis > (unknownStatusMaxSeconds * 1000L)) {
+ // Unknown status has been returned for a while now.
+ updateStatus(RunnerStatus.FAILED)
+ logger.error("Unable to read status for %0.2f minutes: job id %d: %s".format(unknownStatusMillis/(60 * 1000D), jobIdString, function.description))
+ }
+ }
+
+ override def cleanup() {
+ super.cleanup()
+ IOUtils.tryDelete(jobScript)
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/CommandLinePluginManager.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/CommandLinePluginManager.scala
new file mode 100644
index 0000000..3931c5f
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/CommandLinePluginManager.scala
@@ -0,0 +1,33 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import org.broadinstitute.gatk.utils.classloader.PluginManager
+
+class CommandLinePluginManager extends
+ PluginManager[CommandLineJobManager[CommandLineJobRunner]](
+ classOf[CommandLineJobManager[CommandLineJobRunner]], "JobManager", "JobManager") {
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/FunctionEdge.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/FunctionEdge.scala
new file mode 100644
index 0000000..1b02f5d
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/FunctionEdge.scala
@@ -0,0 +1,211 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import org.broadinstitute.gatk.queue.function.QFunction
+import java.io.{StringWriter, PrintWriter}
+import org.broadinstitute.gatk.queue.util.Logging
+import org.broadinstitute.gatk.utils.io.IOUtils
+import org.apache.commons.io.FileUtils
+import org.apache.commons.lang.StringUtils
+
+/**
+ * An edge in the QGraph that runs a QFunction.
+ * The edge is created first to determine inter-node dependencies,
+ * and then the runner is specified later when the time comes to
+ * execute the function in the edge.
+ */
+class FunctionEdge(val function: QFunction, val inputs: QNode, val outputs: QNode) extends QEdge with Logging {
+ var runner: JobRunner[_] =_
+
+ /**
+ * The depth of this edge in the graph.
+ */
+ var depth = -1
+
+ val myRunInfo: JobRunInfo = JobRunInfo.default // purely for dryRun testing
+
+ /**
+ * When using reset status this variable tracks the old status
+ */
+ var resetFromStatus: RunnerStatus.Value = null
+
+ /**
+ * Initializes with the current status of the function.
+ */
+ private var currentStatus = {
+ if (function.isFail)
+ RunnerStatus.FAILED
+ else if (function.isDone)
+ RunnerStatus.DONE
+ else
+ RunnerStatus.PENDING
+ }
+
+ def start() {
+ try {
+ if (logger.isDebugEnabled) {
+ logger.debug("Starting: " + function.commandDirectory + " > " + function.description)
+ } else {
+ logger.info("Starting: " + function.description)
+ }
+ logger.info("Output written to " + function.jobOutputFile)
+ if (function.jobErrorFile != null)
+ logger.info("Errors written to " + function.jobErrorFile)
+
+ function.deleteLogs()
+ function.deleteOutputs()
+ function.mkOutputDirectories()
+
+ runner.init()
+ runner.start()
+ } catch {
+ case e: Throwable =>
+ currentStatus = RunnerStatus.FAILED
+ try {
+ runner.cleanup()
+ function.failOutputs.foreach(_.createNewFile())
+ writeStackTrace(e)
+ } catch {
+ case _: Throwable => /* ignore errors in the exception handler */
+ }
+ logger.error("Error: " + function.description, e)
+ }
+ }
+
+ /**
+ * Returns the current status of the edge.
+ */
+ def status = {
+ if (currentStatus == RunnerStatus.PENDING || currentStatus == RunnerStatus.RUNNING) {
+ if (runner != null) {
+ try {
+ currentStatus = runner.status
+
+ if (currentStatus == RunnerStatus.FAILED) {
+ try {
+ runner.cleanup()
+ function.failOutputs.foreach(_.createNewFile())
+ } catch {
+ case _: Throwable => /* ignore errors in the error handler */
+ }
+ logger.error("Error: " + function.description)
+ tailError()
+ } else if (currentStatus == RunnerStatus.DONE) {
+ try {
+ runner.cleanup()
+ function.doneOutputs.foreach(_.createNewFile())
+ } catch {
+ case _: Throwable => /* ignore errors in the done handler */
+ }
+ logger.info("Done: " + function.description)
+ }
+ } catch {
+ case e: Throwable =>
+ currentStatus = RunnerStatus.FAILED
+ try {
+ runner.cleanup()
+ function.failOutputs.foreach(_.createNewFile())
+ writeStackTrace(e)
+ } catch {
+ case _: Throwable => /* ignore errors in the exception handler */
+ }
+ logger.error("Error retrieving status: " + function.description, e)
+ }
+ }
+ }
+
+ currentStatus
+ }
+
+ /**
+ * Explicitly sets the status of the runner to done..
+ */
+ def markAsDone() {
+ currentStatus = RunnerStatus.DONE
+ }
+
+ /**
+ * Marks this edge as skipped as it is not needed for the current run.
+ */
+ def markAsSkipped() {
+ currentStatus = RunnerStatus.SKIPPED
+ }
+
+ /**
+ * Resets the edge to pending status.
+ */
+ def resetToPending(cleanOutputs: Boolean) {
+ if (resetFromStatus == null)
+ resetFromStatus = currentStatus
+ currentStatus = RunnerStatus.PENDING
+ if (cleanOutputs)
+ function.deleteOutputs()
+ function.jobErrorLines = Nil
+ runner = null
+ }
+
+ override def shortDescription = function.shortDescription
+
+ /**
+ * Returns the path to the file to use for logging errors.
+ * @return the path to the file to use for logging errors.
+ */
+ private def functionErrorFile = if (function.jobErrorFile != null) function.jobErrorFile else function.jobOutputFile
+
+ /**
+ * Outputs the last lines of the error logs.
+ */
+ private def tailError() {
+ val errorFile = functionErrorFile
+ if (IOUtils.waitFor(errorFile, 120)) {
+ val maxLines = 100
+ val tailLines = IOUtils.tail(errorFile, maxLines)
+ val nl = "%n".format()
+ val summary = if (tailLines.size > maxLines) "Last %d lines".format(maxLines) else "Contents"
+ this.function.jobErrorLines = collection.JavaConversions.collectionAsScalaIterable(tailLines).toSeq
+ logger.error("%s of %s:%n%s".format(summary, errorFile, StringUtils.join(tailLines, nl)))
+ } else {
+ logger.error("Unable to access log file: %s".format(errorFile))
+ }
+ }
+
+ /**
+ * Writes the stack trace to the error file.
+ */
+ private def writeStackTrace(e: Throwable) {
+ val stackTrace = new StringWriter
+ val printWriter = new PrintWriter(stackTrace)
+ printWriter.println(function.description)
+ e.printStackTrace(printWriter)
+ printWriter.close()
+ FileUtils.writeStringToFile(functionErrorFile, stackTrace.toString)
+ }
+
+ def getRunInfo = {
+ if ( runner == null ) myRunInfo else runner.getRunInfo
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/InProcessJobManager.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/InProcessJobManager.scala
new file mode 100644
index 0000000..aa7d069
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/InProcessJobManager.scala
@@ -0,0 +1,34 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+
+class InProcessJobManager extends JobManager[InProcessFunction, InProcessRunner] {
+ def runnerType = classOf[InProcessRunner]
+ def functionType = classOf[InProcessFunction]
+ def create(function: InProcessFunction) = new InProcessRunner(function)
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/InProcessRunner.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/InProcessRunner.scala
new file mode 100644
index 0000000..bb8896d
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/InProcessRunner.scala
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+import java.util.Date
+import org.broadinstitute.gatk.utils.Utils
+import org.apache.commons.io.{IOUtils, FileUtils}
+import java.io.PrintStream
+
+/**
+ * Runs a function that executes in process and does not fork out an external process.
+ */
+class InProcessRunner(val function: InProcessFunction) extends JobRunner[InProcessFunction] {
+ private var runStatus: RunnerStatus.Value = _
+
+ def start() {
+ getRunInfo.startTime = new Date()
+ getRunInfo.exechosts = Utils.resolveHostname()
+ runStatus = RunnerStatus.RUNNING
+
+ function.jobOutputStream = new PrintStream(FileUtils.openOutputStream(function.jobOutputFile))
+ function.jobErrorStream = {
+ if (function.jobErrorFile != null)
+ new PrintStream(FileUtils.openOutputStream(function.jobErrorFile))
+ else
+ function.jobOutputStream
+ }
+ try {
+ function.run()
+ function.jobOutputStream.println("%s%nDone.".format(function.description))
+ } finally {
+ IOUtils.closeQuietly(function.jobOutputStream)
+ if (function.jobErrorFile != null)
+ IOUtils.closeQuietly(function.jobErrorStream)
+ }
+
+ runStatus = RunnerStatus.DONE
+ getRunInfo.doneTime = new Date()
+ }
+
+ def status = runStatus
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/JobManager.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/JobManager.scala
new file mode 100644
index 0000000..e8fb1f0
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/JobManager.scala
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import org.broadinstitute.gatk.queue.function.QFunction
+
+/**
+ * Creates and stops JobRunners
+ */
+trait JobManager[TFunction <: QFunction, TRunner <: JobRunner[TFunction]] {
+ def init() {}
+ def exit() {}
+
+ /** The class type of the runner. Available at runtime even after erasure. */
+ def functionType: Class[TFunction]
+
+ /** The class type of the functions processed by the runner. Available at runtime even after erasure. */
+ def runnerType: Class[TRunner]
+
+ /** Creates a new runner.
+ * @param function Function for the runner.
+ */
+ def create(function: TFunction): TRunner
+
+ /**
+ * Updates the status on a list of functions.
+ * @param runners Runners to update.
+ * @return runners which were updated.
+ */
+ def updateStatus(runners: Set[TRunner]): Set[TRunner] = Set.empty
+
+ /**
+ * Stops a list of functions.
+ * @param runners Runners to stop.
+ */
+ def tryStop(runners: Set[TRunner]) {}
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/JobRunInfo.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/JobRunInfo.scala
new file mode 100644
index 0000000..20a536e
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/JobRunInfo.scala
@@ -0,0 +1,79 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import java.text.SimpleDateFormat
+
+/**
+ * Class containing tracked information about a job run.
+ */
+ // todo -- it might be nice to have the hostname
+class JobRunInfo {
+ /** constant date format */
+ val formatter = new SimpleDateFormat("yy-MM-dd H:mm:ss:SSS");
+
+ /** The start time with millisecond resolution of this job */
+ var startTime: java.util.Date = _
+ /** The done time with millisecond resolution of this job */
+ var doneTime: java.util.Date = _
+ var exechosts: String = "localhost"
+
+ def getStartTime: String = getTime(startTime)
+ def getDoneTime: String = getTime(doneTime)
+ def getFormattedStartTime = formatTime(startTime)
+ def getFormattedDoneTime = formatTime(doneTime)
+
+ /** Helper function that returns the time of the date */
+ private def getTime(d: java.util.Date): String = if ( d != null ) d.getTime.toString else "null"
+
+ /** Helper function that pretty prints the date */
+ private def formatTime(d: java.util.Date): String = if ( d != null ) formatter.format(d) else "null"
+
+ def getExecHosts = exechosts
+
+ /**
+ * Was any information set for this jobInfo? JobInfo can be unset because
+ * the job never ran or because it already completed.
+ */
+ def isFilledIn = startTime != null && doneTime != null
+
+ /**
+ * How long did the job run (in wall time)? Returns -1 if this jobInfo isn't filled in
+ */
+ def getRuntimeInMs: Long = {
+ if ( isFilledIn )
+ doneTime.getTime - startTime.getTime
+ else
+ -1
+ }
+
+ override def toString: String =
+ "started %s ended %s runtime %s".format(getFormattedStartTime, getFormattedDoneTime, getRuntimeInMs)
+}
+
+object JobRunInfo {
+ def default: JobRunInfo = new JobRunInfo()
+}
\ No newline at end of file
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/JobRunner.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/JobRunner.scala
new file mode 100644
index 0000000..d7e4868
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/JobRunner.scala
@@ -0,0 +1,89 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import org.broadinstitute.gatk.queue.function.QFunction
+
+/**
+ * Base interface for job runners.
+ */
+trait JobRunner[TFunction <: QFunction] {
+
+ /**
+ * Initializes this job.
+ */
+ def init() {
+ }
+
+ /**
+ * Runs the function.
+ * After the function returns the status of the function should
+ * be RUNNING, FAILED, or DONE.
+ * @param function Command to run.
+ */
+ def start()
+
+ /**
+ * Returns the current run status.
+ * Must only be called AFTER start().
+ * @return RUNNING, DONE, or FAILED.
+ */
+ def status: RunnerStatus.Value
+
+ /**
+ * Checks if the status has been unknown for an extended period of time.
+ */
+ def checkUnknownStatus() {}
+
+ /**
+ * Returns the function to be run.
+ */
+ def function: TFunction
+
+ /**
+ * Cleans up after the function is run.
+ * For example removing all temporary files.
+ */
+ def cleanup() {
+ }
+
+ /**
+ * Must be overloaded
+ */
+ val runInfo = JobRunInfo.default
+ def getRunInfo = runInfo
+
+ /**
+ * Calls back to a hook that an expert user can setup to modify a job.
+ * @param value Value to modify.
+ */
+ protected def updateJobRun(value: Any) {
+ val updater = function.updateJobRun
+ if (updater != null)
+ if (updater.isDefinedAt(value))
+ updater(value)
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/MappingEdge.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/MappingEdge.scala
new file mode 100644
index 0000000..af51602
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/MappingEdge.scala
@@ -0,0 +1,39 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+/**
+ * Utility class to map a set of inputs to set of outputs.
+ * The QGraph uses this function internally to map between user defined functions.
+ */
+class MappingEdge(val inputs: QNode, val outputs: QNode) extends QEdge {
+ /**
+ * For debugging purposes returns <map>.
+ * @return <map>
+ */
+ override def toString = "<map>"
+ override def shortDescription = ""
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QEdge.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QEdge.scala
new file mode 100644
index 0000000..d3f2f4b
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QEdge.scala
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+/**
+ * An edge in the QGraph
+ */
+trait QEdge {
+ /**
+ * List of inputs for this function sorted by path.
+ */
+ def inputs: QNode
+
+ /**
+ * List of outputs for this function sorted by path.
+ */
+ def outputs: QNode
+
+ /**
+ * The short description
+ */
+ def shortDescription = ""
+
+ override def hashCode = inputs.hashCode + outputs.hashCode
+
+ override def equals(obj: Any) = {
+ obj match {
+ case other: QEdge =>
+ this.inputs == other.inputs &&
+ this.outputs == other.outputs
+ case _ => false
+ }
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QGraph.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QGraph.scala
new file mode 100644
index 0000000..7d09bf5
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QGraph.scala
@@ -0,0 +1,1228 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import org.jgrapht.traverse.TopologicalOrderIterator
+import org.jgrapht.graph.SimpleDirectedGraph
+import scala.collection.JavaConversions._
+import org.jgrapht.alg.CycleDetector
+import org.jgrapht.EdgeFactory
+import org.jgrapht.ext.DOTExporter
+import org.jgrapht.event.{TraversalListenerAdapter, EdgeTraversalEvent}
+import org.broadinstitute.gatk.queue.QException
+import org.broadinstitute.gatk.queue.function.{InProcessFunction, CommandLineFunction, QFunction}
+import org.apache.commons.lang.StringUtils
+import org.broadinstitute.gatk.queue.util._
+import collection.immutable.{TreeSet, TreeMap}
+import org.broadinstitute.gatk.queue.function.scattergather.{ScatterFunction, CloneFunction, GatherFunction, ScatterGatherableFunction}
+import java.util.Date
+import org.broadinstitute.gatk.utils.Utils
+import org.apache.commons.io.{FilenameUtils, FileUtils, IOUtils}
+import java.io.{OutputStreamWriter, File}
+
+/**
+ * The internal dependency tracker between sets of function input and output files.
+ */
+class QGraph extends Logging {
+ var settings: QGraphSettings = _
+ var messengers: Seq[QStatusMessenger] = Nil
+
+ private def dryRun = !settings.run
+ private var numMissingValues = 0
+
+ private val jobGraph = newGraph
+ private val functionOrdering = Ordering.by[FunctionEdge, Iterable[Int]](edge => -graphDepth(edge) +: edge.function.addOrder)
+ private val fileOrdering = Ordering.by[File,String](_.getAbsolutePath)
+ // A map of nodes by list of files.
+ private var nodeMap = TreeMap.empty[Iterable[File], QNode](Ordering.Iterable(fileOrdering))
+ // The next unique id for a node if not found in the nodeMap.
+ private var nextNodeId = 0
+
+ private var running = true
+ private val runningLock = new Object
+ private var runningJobs = Set.empty[FunctionEdge]
+ private var cleanupJobs = Set.empty[FunctionEdge]
+
+ private val nl = "%n".format()
+
+ private val commandLinePluginManager = new CommandLinePluginManager
+ private var commandLineManager: CommandLineJobManager[CommandLineJobRunner] = _
+ private val inProcessManager = new InProcessJobManager
+ private def managers = Seq[Any](inProcessManager, commandLineManager)
+
+ /**
+ * If true, we will write out incremental job reports
+ */
+ private val INCREMENTAL_JOBS_REPORT = true
+
+ /**
+ * Holds the optional jobInfoReporter structure
+ */
+ private var jobInfoReporter: QJobsReporter = null
+
+ private class StatusCounts {
+ var pending = 0
+ var running = 0
+ var failed = 0
+ var done = 0
+ }
+ private val statusCounts = new StatusCounts
+
+ /**
+ * Final initialization step of this QGraph -- tell it runtime setting information
+ *
+ * The settings aren't necessarily available until after this QGraph object has been constructed, so
+ * this function must be called once the QGraphSettings have been filled in.
+ *
+ * @param settings QGraphSettings
+ */
+ def initializeWithSettings(settings: QGraphSettings) {
+ this.settings = settings
+ this.jobInfoReporter = createJobsReporter()
+ }
+
+ /**
+ * Adds a QScript created CommandLineFunction to the graph.
+ * @param command Function to add to the graph.
+ */
+ def add(command: QFunction) {
+ try {
+ runningLock.synchronized {
+ if (running) {
+ command.qSettings = settings.qSettings
+ command.freeze()
+ val inputFiles = command.inputs
+ var outputFiles = command.outputs
+ outputFiles :+= command.jobOutputFile
+ if (command.jobErrorFile != null)
+ outputFiles :+= command.jobErrorFile
+ val inputs = getQNode(inputFiles.sorted(fileOrdering))
+ val outputs = getQNode(outputFiles.sorted(fileOrdering))
+ addEdge(new FunctionEdge(command, inputs, outputs))
+ }
+ }
+ } catch {
+ case e: Exception =>
+ throw new QException("Error adding function: " + command, e)
+ }
+ }
+
+ /**
+ * Checks the functions for missing values and the graph for cyclic dependencies and then runs the functions in the graph.
+ */
+ def run() {
+ runningLock.synchronized {
+ if (running) {
+ org.broadinstitute.gatk.utils.io.IOUtils.checkTempDir(settings.qSettings.tempDirectory)
+ fillGraph()
+ val isReady = numMissingValues == 0
+
+ if (this.jobGraph.edgeSet.isEmpty) {
+ logger.warn("Nothing to run! Were any Functions added?")
+ } else if (settings.getStatus) {
+ logger.info("Checking pipeline status.")
+ logStatus()
+ } else if (this.dryRun) {
+ dryRunJobs()
+ if (running && isReady) {
+ logger.info("Dry run completed successfully!")
+ logger.info("Re-run with \"-run\" to execute the functions.")
+ }
+ } else if (isReady) {
+ logger.info("Running jobs.")
+ runJobs()
+ }
+
+ if (numMissingValues > 0) {
+ logger.error("Total missing values: " + numMissingValues)
+ }
+ }
+ }
+ }
+
+ private def fillGraph() {
+ logger.info("Generating graph.")
+ fill()
+ if (settings.graphvizFile != null)
+ renderGraph(settings.graphvizFile)
+ validate()
+
+ if (running && numMissingValues == 0) {
+ val scatterGathers = jobGraph.edgeSet.filter(edge => scatterGatherable(edge))
+ if (!scatterGathers.isEmpty) {
+ logger.info("Generating scatter gather jobs.")
+
+ var addedFunctions = Seq.empty[QFunction]
+ for (scatterGather <- scatterGathers) {
+ val functions = scatterGather.asInstanceOf[FunctionEdge]
+ .function.asInstanceOf[ScatterGatherableFunction]
+ .generateFunctions()
+ addedFunctions ++= functions
+ }
+
+ logger.info("Removing original jobs.")
+ this.jobGraph.removeAllEdges(scatterGathers)
+ prune()
+
+ logger.info("Adding scatter gather jobs.")
+ addedFunctions.foreach(function => if (running) this.add(function))
+
+ logger.info("Regenerating graph.")
+ fill()
+ val scatterGatherDotFile = if (settings.graphvizScatterGatherFile != null) settings.graphvizScatterGatherFile else settings.graphvizFile
+ if (scatterGatherDotFile != null)
+ renderGraph(scatterGatherDotFile)
+ validate()
+ }
+ }
+ }
+
+ private def scatterGatherable(edge: QEdge) = {
+ edge match {
+ case functionEdge: FunctionEdge => {
+ functionEdge.function match {
+ case scatterGather: ScatterGatherableFunction if (scatterGather.scatterGatherable) => true
+ case _ => false
+ }
+ }
+ case _ => false
+ }
+ }
+
+ /**
+ * Walks up the graph looking for the previous function edges.
+ * @param edge Graph edge to examine for the previous functions.
+ * @return A list of prior function edges.
+ */
+ private def previousFunctions(edge: QEdge): Seq[FunctionEdge] = {
+ var previous = Seq.empty[FunctionEdge]
+ val source = this.jobGraph.getEdgeSource(edge)
+ for (incomingEdge <- this.jobGraph.incomingEdgesOf(source)) {
+ incomingEdge match {
+
+ // Stop recursing when we find a function edge and return it
+ case functionEdge: FunctionEdge => previous :+= functionEdge
+
+ // For any other type of edge find the jobs preceding the edge
+ case edge: QEdge => previous ++= previousFunctions(edge)
+ }
+ }
+ previous
+ }
+
+ /**
+ * Walks up the graph looking for the next function edges.
+ * @param edge Graph edge to examine for the next functions.
+ * @return A list of prior function edges.
+ */
+ private def nextFunctions(edge: QEdge): Seq[FunctionEdge] = {
+ var next = Seq.empty[FunctionEdge]
+ val target = this.jobGraph.getEdgeTarget(edge)
+ for (outgoingEdge <- this.jobGraph.outgoingEdgesOf(target)) {
+ outgoingEdge match {
+
+ // Stop recursing when we find a function edge and return it
+ case functionEdge: FunctionEdge => next :+= functionEdge
+
+ // For any other type of edge find the jobs following the edge
+ case edge: QEdge => next ++= nextFunctions(edge)
+ }
+ }
+ next
+ }
+
+ /**
+ * Fills in the graph using mapping functions, then removes out of date
+ * jobs, then cleans up mapping functions and nodes that aren't need.
+ */
+ private def fill() {
+ fillIn()
+ prune()
+ }
+
+ /**
+ * Looks through functions with multiple inputs and outputs and adds mapping functions for single inputs and outputs.
+ */
+ private def fillIn() {
+ // clone since edgeSet is backed by the graph
+ asScalaSet(jobGraph.edgeSet).clone().foreach(edge => {
+ if (running) edge match {
+ case cmd: FunctionEdge => {
+ addCollectionOutputs(cmd.outputs)
+ addCollectionInputs(cmd.inputs)
+ }
+ case map: MappingEdge => /* do nothing for mapping edges */
+ }
+ })
+ }
+
+ private def getReadyJobs: Set[FunctionEdge] = {
+ jobGraph.edgeSet.filter{
+ case f: FunctionEdge =>
+ this.previousFunctions(f).forall(_.status == RunnerStatus.DONE) && f.status == RunnerStatus.PENDING
+ case _ => false
+ }.toSet.asInstanceOf[Set[FunctionEdge]]
+ }
+
+ /**
+ * Removes mapping edges that aren't being used, and nodes that don't belong to anything.
+ */
+ private def prune() {
+ var pruning = true
+ while (pruning) {
+ pruning = false
+ val filler = jobGraph.edgeSet.filter(isFiller(_))
+ if (filler.size > 0) {
+ jobGraph.removeAllEdges(filler)
+ pruning = running
+ }
+ }
+
+ if (running) {
+ for (orphan <- jobGraph.vertexSet.filter(isOrphan(_))) {
+ jobGraph.removeVertex(orphan)
+ nodeMap -= orphan.files
+ }
+ }
+ }
+
+ /**
+ * Validates that the functions in the graph have no missing values and that there are no cycles.
+ */
+ private def validate() {
+ asScalaSet(jobGraph.edgeSet).foreach(
+ edge =>
+ if (running) edge match
+ {
+ case cmd: FunctionEdge =>
+ val missingFieldValues = cmd.function.missingFields
+ if (missingFieldValues.size > 0) {
+ numMissingValues += missingFieldValues.size
+ logger.error("Missing %s values for function: %s".format(missingFieldValues.size, cmd.function.description))
+ for (missing <- missingFieldValues)
+ logger.error(" " + missing)
+ }
+ case map: MappingEdge => /* do nothing for mapping edges */
+ }
+ )
+
+ val detector = new CycleDetector(jobGraph)
+ if (detector.detectCycles) {
+ logger.error("Cycles were detected in the graph:")
+ for (cycle <- detector.findCycles)
+ logger.error(" " + cycle)
+ throw new QException("Cycles were detected in the graph.")
+ }
+ }
+
+ /**
+ * Dry-runs the jobs by traversing the graph.
+ */
+ private def dryRunJobs() {
+ if (settings.startFromScratch)
+ logger.info("Will remove outputs from previous runs.")
+
+ updateGraphStatus(cleanOutputs = false)
+
+ var readyJobs = getReadyJobs
+ while (running && readyJobs.size > 0) {
+ logger.debug("+++++++")
+ foreachFunction(readyJobs.toSeq, edge => {
+ if (running) {
+ edge.myRunInfo.startTime = new Date()
+ edge.getRunInfo.exechosts = Utils.resolveHostname()
+ logEdge(edge)
+ edge.myRunInfo.doneTime = new Date()
+ edge.markAsDone()
+ }
+ })
+ readyJobs = getReadyJobs
+ }
+ }
+
+ private def logEdge(edge: FunctionEdge) {
+ logger.info("-------")
+ logger.info("%-8s %s".format(StringUtils.capitalize(edge.status.toString) + ":", edge.function.description))
+ if (logger.isDebugEnabled) {
+ logger.debug("Inputs: " + edge.inputs)
+ logger.debug("Outputs: " + edge.outputs)
+ logger.debug("Done+: " + edge.function.doneOutputs.filter(_.exists()))
+ logger.debug("Done-: " + edge.function.doneOutputs.filterNot(_.exists()))
+ logger.debug("CmdDir: " + edge.function.commandDirectory)
+ logger.debug("Temp?: " + edge.function.isIntermediate)
+ logger.debug("Prev: " +
+ (if (edge.resetFromStatus == null) "none" else StringUtils.capitalize(edge.resetFromStatus.toString)) +
+ " (reset = " + (edge.resetFromStatus != null && edge.resetFromStatus != edge.status) + ")" )
+ }
+ logger.info("Log: " + edge.function.jobOutputFile.getAbsolutePath)
+ if (edge.function.jobErrorFile != null)
+ logger.info("Error: " + edge.function.jobErrorFile.getAbsolutePath)
+ }
+
+ /**
+ * Logs job statuses by traversing the graph and looking for status-related files
+ */
+ private def logStatus() {
+ updateGraphStatus(cleanOutputs = false)
+ doStatus(status => logger.info(status))
+ }
+
+ /**
+ * Runs the jobs by traversing the graph.
+ */
+ private def runJobs() {
+ try {
+ if (settings.bsub)
+ settings.jobRunner = "Lsf706"
+ else if (settings.qsub)
+ settings.jobRunner = "GridEngine"
+ else if (settings.jobRunner == null)
+ settings.jobRunner = "Shell"
+ commandLineManager = commandLinePluginManager.createByName(settings.jobRunner)
+
+ for (mgr <- managers) {
+ if (mgr != null) {
+ val manager = mgr.asInstanceOf[JobManager[QFunction,JobRunner[QFunction]]]
+ manager.init()
+ }
+ }
+
+ if (settings.startFromScratch)
+ logger.info("Removing outputs from previous runs.")
+
+ updateGraphStatus(cleanOutputs = true)
+
+ var readyJobs = TreeSet.empty[FunctionEdge](functionOrdering)
+ readyJobs ++= getReadyJobs
+ runningJobs = Set.empty[FunctionEdge]
+ var lastRunningCheck = System.currentTimeMillis
+ var logNextStatusCounts = true
+ var startedJobsToEmail = Set.empty[FunctionEdge]
+
+ while (running && readyJobs.size + runningJobs.size > 0) {
+
+ var startedJobs = Set.empty[FunctionEdge]
+ var doneJobs = Set.empty[FunctionEdge]
+ var failedJobs = Set.empty[FunctionEdge]
+
+ while (running && readyJobs.size > 0 && !readyRunningCheck(lastRunningCheck)) {
+ val edge = readyJobs.head
+ edge.runner = newRunner(edge.function)
+ edge.start()
+ messengers.foreach(_.started(jobShortName(edge.function)))
+ startedJobs += edge
+ readyJobs -= edge
+ logNextStatusCounts = true
+ }
+
+ runningJobs ++= startedJobs
+ startedJobsToEmail ++= startedJobs
+ statusCounts.pending -= startedJobs.size
+ statusCounts.running += startedJobs.size
+
+ if (logNextStatusCounts)
+ logStatusCounts()
+ logNextStatusCounts = false
+
+ deleteCleanup(lastRunningCheck)
+
+ if (running && startedJobs.size > 0 && !readyRunningCheck(lastRunningCheck)) {
+ emailStartedJobs(startedJobsToEmail)
+ startedJobsToEmail = Set.empty[FunctionEdge]
+ }
+
+ if (readyJobs.size == 0 && runningJobs.size > 0) {
+ runningLock.synchronized {
+ if (running) {
+ val timeout = nextRunningCheck(lastRunningCheck)
+ if (timeout > 0)
+ runningLock.wait(timeout)
+ }
+ }
+ }
+
+ lastRunningCheck = System.currentTimeMillis
+ updateStatus()
+
+ runningJobs.foreach(edge => edge.status match {
+ case RunnerStatus.DONE => {
+ doneJobs += edge
+ messengers.foreach(_.done(jobShortName(edge.function)))
+ }
+ case RunnerStatus.FAILED => {
+ failedJobs += edge
+ messengers.foreach(_.exit(jobShortName(edge.function), edge.function.jobErrorLines.mkString("%n".format())))
+ }
+ case RunnerStatus.RUNNING => /* do nothing while still running */
+ })
+
+ runningJobs --= doneJobs
+ runningJobs --= failedJobs
+
+ startedJobsToEmail &~= failedJobs
+
+ addCleanup(doneJobs)
+
+ statusCounts.running -= doneJobs.size
+ statusCounts.running -= failedJobs.size
+ statusCounts.done += doneJobs.size
+ statusCounts.failed += failedJobs.size
+
+ if (doneJobs.size > 0 || failedJobs.size > 0)
+ logNextStatusCounts = true
+
+ if (running && failedJobs.size > 0) {
+ emailFailedJobs(failedJobs)
+ checkRetryJobs(failedJobs)
+ }
+
+ // incremental
+ if ( logNextStatusCounts && INCREMENTAL_JOBS_REPORT ) {
+ logger.info("Writing incremental jobs reports...")
+ writeJobsReport(plot = false)
+ }
+
+ readyJobs ++= getReadyJobs
+ }
+
+ logStatusCounts()
+ deleteCleanup(-1)
+ } catch {
+ case e: Throwable =>
+ logger.error("Uncaught error running jobs.", e)
+ throw e
+ } finally {
+ emailStatus()
+ }
+ }
+
+ private def readyRunningCheck(lastRunningCheck: Long) =
+ lastRunningCheck > 0 && nextRunningCheck(lastRunningCheck) <= 0
+
+ private def nextRunningCheck(lastRunningCheck: Long) =
+ ((30 * 1000L) - (System.currentTimeMillis - lastRunningCheck))
+
+ def formattedStatusCounts: String = {
+ "%d Pend, %d Run, %d Fail, %d Done".format(
+ statusCounts.pending, statusCounts.running, statusCounts.failed, statusCounts.done)
+ }
+
+ private def logStatusCounts() {
+ logger.info(formattedStatusCounts)
+ }
+
+ /**
+ * Updates the status of edges in the graph.
+ * @param cleanOutputs If true will delete outputs when setting edges to pending.
+ */
+ private def updateGraphStatus(cleanOutputs: Boolean) {
+ if (settings.startFromScratch)
+ foreachFunction(edge => edge.resetToPending(cleanOutputs))
+ else
+ traverseFunctions(edge => checkDone(edge, cleanOutputs))
+ traverseFunctions(edge => recheckDone(edge))
+ }
+
+ // TODO: Yet another field to add (with overloads) to QFunction?
+ private def jobShortName(function: QFunction): String = {
+ var name = function.analysisName
+ if (function.isInstanceOf[CloneFunction]) {
+ val cloneFunction = function.asInstanceOf[CloneFunction]
+ name += " %d of %d".format(cloneFunction.cloneIndex, cloneFunction.cloneCount)
+ }
+ name
+ }
+
+ /**
+ * First pass that checks if an edge is done or if it's an intermediate edge if it can be skipped.
+ * This function may modify the status of previous edges if it discovers that the edge passed in
+ * is dependent jobs that were previously marked as skipped.
+ * @param edge Edge to check to see if it's done or can be skipped.
+ * @param cleanOutputs If true will delete outputs when setting edges to pending.
+ */
+ private def checkDone(edge: FunctionEdge, cleanOutputs: Boolean) {
+ if (edge.function.isIntermediate) {
+ // By default we do not need to run intermediate edges.
+ // Mark any intermediate edges as skipped, if they're not already done.
+ if (edge.status != RunnerStatus.DONE)
+ edge.markAsSkipped()
+ } else {
+ val previous = this.previousFunctions(edge)
+ val isDone = edge.status == RunnerStatus.DONE &&
+ previous.forall(edge => edge.status == RunnerStatus.DONE || edge.status == RunnerStatus.SKIPPED)
+ if (!isDone) {
+ edge.resetToPending(cleanOutputs)
+ resetPreviousSkipped(edge, previous, cleanOutputs)
+ }
+ }
+ }
+
+ /**
+ * Second pass which
+ * a) Updates the status counts based on the function statuses
+ * b) Checks if the edge is a completed intermediate edge then adds it to the set of candidates for cleanup
+ * @param edge Edge to check to see if it's done or skipped.
+ */
+ private def recheckDone(edge: FunctionEdge) {
+ edge.status match {
+ case RunnerStatus.PENDING => statusCounts.pending += 1
+ case RunnerStatus.FAILED => statusCounts.failed += 1
+ case RunnerStatus.DONE => statusCounts.done += 1
+ case RunnerStatus.SKIPPED => statusCounts.done += 1
+ }
+
+ if (edge.status == RunnerStatus.DONE || edge.status == RunnerStatus.SKIPPED) {
+ if (logger.isDebugEnabled)
+ logEdge(edge)
+ addCleanup(edge)
+ }
+ }
+
+ /**
+ * Checks if the functions should have their outptus removed after they finish running
+ * @param edges Functions to check
+ */
+ private def addCleanup(edges: Traversable[FunctionEdge]) {
+ edges.foreach(addCleanup(_))
+ }
+
+ /**
+ * Checks if the function should have their outputs removed after they finish running
+ * @param edge Function to check
+ */
+ private def addCleanup(edge: FunctionEdge) {
+ if (!settings.keepIntermediates)
+ if (edge.function.isIntermediate)
+ cleanupJobs += edge
+ }
+
+ /**
+ * Continues deleting the outputs of intermediate jobs that are no longer needed until it's time to recheck running status.
+ * @param lastRunningCheck The last time the status was checked.
+ */
+ private def deleteCleanup(lastRunningCheck: Long) {
+ var doneJobs = Set.empty[FunctionEdge]
+
+ for (edge <- cleanupJobs) {
+ val nextDone = nextFunctions(edge).forall(next => {
+ val status = next.status
+ (status == RunnerStatus.DONE || status == RunnerStatus.SKIPPED)
+ })
+
+ if (nextDone)
+ doneJobs += edge
+ }
+
+ for (edge <- doneJobs) {
+ if (running && !readyRunningCheck(lastRunningCheck)) {
+ logger.debug("Deleting intermediates:" + edge.function.description)
+ edge.function.deleteOutputs()
+ cleanupJobs -= edge
+ }
+ }
+ }
+
+ /**
+ * Returns the graph depth for the function.
+ * @param edge Function edge to get the edge for.
+ * @return the graph depth for the function.
+ */
+ private def graphDepth(edge: FunctionEdge): Int = {
+ if (edge.depth < 0) {
+ val previous = previousFunctions(edge)
+ if (previous.size == 0)
+ edge.depth = 0
+ else
+ edge.depth = previous.map(f => graphDepth(f)).max + 1
+ }
+ edge.depth
+ }
+
+ /**
+ * From the previous edges, resets any that are marked as skipped to pending.
+ * If those that are reset have skipped edges, those skipped edges are recursively also set
+ * to pending.
+ * Any edges after this edge are also reset to pending.
+ * @param edge Dependent edge.
+ * @param previous Previous edges that provide inputs to edge.
+ * @param cleanOutputs If true will clean up the output files when resetting jobs to pending.
+ */
+ private def resetPreviousSkipped(edge: FunctionEdge, previous: Seq[FunctionEdge], cleanOutputs: Boolean) {
+ val edges = previous.filter(_.status == RunnerStatus.SKIPPED) ++ this.nextFunctions(edge).filter(_.status != RunnerStatus.PENDING)
+ for (resetEdge <- edges) {
+ resetEdge.resetToPending(cleanOutputs)
+ resetPreviousSkipped(resetEdge, this.previousFunctions(resetEdge), cleanOutputs)
+ }
+ }
+
+ private def newRunner(f: QFunction) = {
+ f match {
+ case cmd: CommandLineFunction =>
+ commandLineManager.create(cmd)
+ case inProc: InProcessFunction =>
+ inProcessManager.create(inProc)
+ case _ =>
+ throw new QException("Unexpected function: " + f)
+ }
+ }
+
+ private def emailStartedJobs(started: Set[FunctionEdge]) {
+ if (settings.statusEmailTo.size > 0) {
+ val emailMessage = new EmailMessage
+ emailMessage.from = settings.statusEmailFrom
+ emailMessage.to = settings.statusEmailTo
+ emailMessage.subject = "Queue function: Started: " + settings.qSettings.runName
+ addStartedFunctions(emailMessage, started.toSeq)
+ emailMessage.trySend(settings.emailSettings)
+ }
+ }
+
+ private def emailFailedJobs(failed: Set[FunctionEdge]) {
+ if (settings.statusEmailTo.size > 0) {
+ val emailMessage = new EmailMessage
+ emailMessage.from = settings.statusEmailFrom
+ emailMessage.to = settings.statusEmailTo
+ emailMessage.subject = "Queue function: Failure: " + settings.qSettings.runName
+ addFailedFunctions(emailMessage, failed.toSeq)
+ emailMessage.trySend(settings.emailSettings)
+ }
+ }
+
+ private def checkRetryJobs(failed: Set[FunctionEdge]) {
+ if (settings.retries > 0) {
+ for (failedJob <- failed) {
+ if (failedJob.function.jobRestartable && failedJob.function.retries < settings.retries) {
+ failedJob.function.retries += 1
+ failedJob.function.setupRetry()
+ failedJob.resetToPending(cleanOutputs = true)
+ logger.info("Reset for retry attempt %d of %d: %s".format(
+ failedJob.function.retries, settings.retries, failedJob.function.description))
+ statusCounts.failed -= 1
+ statusCounts.pending += 1
+ } else {
+ logger.info("Giving up after retrying %d times: %s".format(
+ settings.retries, failedJob.function.description))
+ }
+ }
+ }
+ }
+
+ private def emailStatus() {
+ if (running && settings.statusEmailTo.size > 0) {
+ var failed = Seq.empty[FunctionEdge]
+ foreachFunction(edge => {
+ if (edge.status == RunnerStatus.FAILED) {
+ failed :+= edge
+ }
+ })
+
+ val emailMessage = new EmailMessage
+ emailMessage.from = settings.statusEmailFrom
+ emailMessage.to = settings.statusEmailTo
+ emailMessage.body = getStatus + nl
+ if (failed.size == 0) {
+ emailMessage.subject = "Queue run: Success: " + settings.qSettings.runName
+ } else {
+ emailMessage.subject = "Queue run: Failure: " + settings.qSettings.runName
+ addFailedFunctions(emailMessage, failed)
+ }
+ emailMessage.trySend(settings.emailSettings)
+ }
+ }
+
+ private def addStartedFunctions(emailMessage: EmailMessage, started: Seq[FunctionEdge]) {
+ if (emailMessage.body == null)
+ emailMessage.body = ""
+ emailMessage.body += """
+ |Started functions:
+ |
+ |%s
+ |""".stripMargin.trim.format(
+ started.map(edge => emailDescription(edge)).mkString(nl+nl))
+ }
+
+ private def addFailedFunctions(emailMessage: EmailMessage, failed: Seq[FunctionEdge]) {
+ val logs = failed.flatMap(edge => logFiles(edge))
+
+ if (emailMessage.body == null)
+ emailMessage.body = ""
+ emailMessage.body += """
+ |Failed functions:
+ |
+ |%s
+ |
+ |Logs:
+ |%s%n
+ |""".stripMargin.trim.format(
+ failed.map(edge => emailDescription(edge)).mkString(nl+nl),
+ logs.map(_.getAbsolutePath).mkString(nl))
+
+ emailMessage.attachments = logs
+ }
+
+ private def emailDescription(edge: FunctionEdge) = {
+ val description = new StringBuilder
+ if (settings.retries > 0)
+ description.append("Attempt %d of %d.%n".format(edge.function.retries + 1, settings.retries + 1))
+ description.append(edge.function.description)
+ description.toString()
+ }
+
+ private def logFiles(edge: FunctionEdge) = {
+ var failedOutputs = Seq.empty[File]
+ failedOutputs :+= edge.function.jobOutputFile
+ if (edge.function.jobErrorFile != null)
+ failedOutputs :+= edge.function.jobErrorFile
+ failedOutputs.filter(file => file != null && file.exists)
+ }
+
+ /**
+ * Tracks analysis status.
+ */
+ private class AnalysisStatus(val analysisName: String) {
+ val jobs = new GroupStatus
+ val scatter = new GroupStatus
+ val gather = new GroupStatus
+
+ def total = jobs.total + scatter.total + gather.total
+ def done = jobs.done + scatter.done + gather.done
+ def failed = jobs.failed + scatter.failed + gather.failed
+ def skipped = jobs.skipped + scatter.skipped + gather.skipped
+ }
+
+ /**
+ * Tracks status of a group of jobs.
+ */
+ private class GroupStatus {
+ var total = 0
+ var done = 0
+ var failed = 0
+ var skipped = 0
+ }
+
+ /**
+ * Gets job statuses by traversing the graph and looking for status-related files
+ */
+ private def getStatus = {
+ val buffer = new StringBuilder
+ doStatus(status => buffer.append(status).append(nl))
+ buffer.toString()
+ }
+
+ /**
+ * Gets job statuses by traversing the graph and looking for status-related files
+ */
+ private def doStatus(statusFunc: String => Unit) {
+ var statuses = Seq.empty[AnalysisStatus]
+ var maxWidth = 0
+ foreachFunction(edge => {
+ val name = edge.function.analysisName
+ if (name != null) {
+ updateAnalysisStatus(statuses.find(_.analysisName == name) match {
+ case Some(status) => status
+ case None =>
+ val status = new AnalysisStatus(name)
+ maxWidth = maxWidth max name.length
+ statuses :+= status
+ status
+ }, edge)
+ }
+ })
+
+ statuses.foreach(status => {
+ val total = status.total
+ val done = status.done
+ val failed = status.failed
+ val skipped = status.skipped
+ val jobsTotal = status.jobs.total
+ val jobsDone = status.jobs.done
+ val gatherTotal = status.gather.total
+ val gatherDone = status.gather.done
+
+ var summaryStatus = RunnerStatus.PENDING
+ if (failed > 0)
+ summaryStatus = RunnerStatus.FAILED
+ else if (gatherDone == gatherTotal && jobsDone == jobsTotal)
+ summaryStatus = RunnerStatus.DONE
+ else if (done + skipped == total)
+ summaryStatus = RunnerStatus.SKIPPED
+ else if (done > 0)
+ summaryStatus = RunnerStatus.RUNNING
+
+ var info = ("%-" + maxWidth + "s %7s")
+ .format(status.analysisName, "[" + summaryStatus.toString + "]")
+ if (status.jobs.total > 1) {
+ info += formatGroupStatus(status.jobs)
+ }
+ if (status.scatter.total + status.gather.total > 1) {
+ info += formatGroupStatus(status.scatter, "s:")
+ info += formatGroupStatus(status.gather, "g:")
+ }
+ statusFunc(info)
+ })
+ }
+
+ /**
+ * Updates a status map with scatter/gather status information (e.g. counts)
+ */
+ private def updateAnalysisStatus(stats: AnalysisStatus, edge: FunctionEdge) {
+ if (edge.function.isInstanceOf[ScatterFunction]) {
+ updateGroupStatus(stats.scatter, edge)
+ } else if (edge.function.isInstanceOf[CloneFunction]) {
+ updateGroupStatus(stats.scatter, edge)
+ } else if (edge.function.isInstanceOf[GatherFunction]) {
+ updateGroupStatus(stats.gather, edge)
+ } else {
+ updateGroupStatus(stats.jobs, edge)
+ }
+ }
+
+ private def updateGroupStatus(groupStatus: GroupStatus, edge: FunctionEdge) {
+ groupStatus.total += 1
+ edge.status match {
+ case RunnerStatus.DONE => groupStatus.done += 1
+ case RunnerStatus.FAILED => groupStatus.failed += 1
+ case RunnerStatus.SKIPPED => groupStatus.skipped += 1
+ /* can't tell the difference between pending and running right now! */
+ case RunnerStatus.PENDING =>
+ case RunnerStatus.RUNNING =>
+ }
+ }
+
+ /**
+ * Formats a status into nice strings
+ */
+ private def formatGroupStatus(stats: GroupStatus, prefix: String = "") = {
+ " %s%dt/%dd/%df".format(
+ prefix, stats.total, stats.done, stats.failed)
+ }
+
+ /**
+ * Creates a new graph where if new edges are needed (for cyclic dependency checking) they can be automatically created using a generic MappingFunction.
+ * @return A new graph
+ */
+ private def newGraph = new SimpleDirectedGraph[QNode, QEdge](new EdgeFactory[QNode, QEdge] {
+ def createEdge(input: QNode, output: QNode) = new MappingEdge(input, output)})
+
+ private def getQNode(files: Seq[File]) = {
+ nodeMap.get(files) match {
+ case Some(node) =>
+ node
+ case None =>
+ if (nextNodeId % 100 == 0)
+ logger.debug("adding QNode: " + nextNodeId)
+ val node = new QNode(nextNodeId, files)
+ nextNodeId += 1
+ jobGraph.addVertex(node)
+ nodeMap += files -> node
+ node
+ }
+ }
+
+ private def addEdge(edge: QEdge) {
+ jobGraph.removeAllEdges(edge.inputs, edge.outputs)
+ jobGraph.addEdge(edge.inputs, edge.outputs, edge)
+ }
+
+ /**
+ * Adds input mappings between the node's files and the individual files.
+ * @param inputs Input node.
+ */
+ private def addCollectionInputs(inputs: QNode) {
+ if (inputs.files.size > 1)
+ for (file <- inputs.files) {
+ if (running) {
+ val input = getQNode(Seq(file))
+ if (!jobGraph.containsEdge(input, inputs))
+ addEdge(new MappingEdge(input, inputs))
+ }
+ }
+ }
+
+ /**
+ * Adds output mappings between the node's files and the individual files.
+ * @param outputs Output node.
+ */
+ private def addCollectionOutputs(outputs: QNode) {
+ if (outputs.files.size > 1)
+ for (file <- outputs.files) {
+ if (running) {
+ val output = getQNode(Seq(file))
+ if (!jobGraph.containsEdge(outputs, output))
+ addEdge(new MappingEdge(outputs, output))
+ }
+ }
+ }
+
+ /**
+ * Returns true if the edge is mapping edge that is not needed because it does
+ * not direct input or output from a user generated CommandLineFunction.
+ * @param edge Edge to check.
+ * @return true if the edge is not needed in the graph.
+ */
+ private def isFiller(edge: QEdge) = {
+ edge match {
+ case mapping: MappingEdge =>
+ jobGraph.outgoingEdgesOf(jobGraph.getEdgeTarget(edge)).size == 0 &&
+ jobGraph.incomingEdgesOf(jobGraph.getEdgeSource(edge)).size == 0
+ case _ => false
+ }
+ }
+
+ /**
+ * Returns true if the node is not connected to any edges.
+ * @param node Node (set of files) to check.
+ * @return true if this set of files is not needed in the graph.
+ */
+ private def isOrphan(node: QNode) = {
+ jobGraph.incomingEdgesOf(node).size == 0 &&
+ jobGraph.outgoingEdgesOf(node).size == 0
+ }
+
+ /**
+ * Utility function for running a method over all function edges.
+ * @param f Function to run for each FunctionEdge.
+ */
+ private def foreachFunction(f: (FunctionEdge) => Unit) {
+ foreachFunction(jobGraph.edgeSet.toSeq.filter(_.isInstanceOf[FunctionEdge]).asInstanceOf[Seq[FunctionEdge]], f)
+ }
+
+ /**
+ * Utility function for running a method over a list of function edges.
+ * @param edges Edges to traverse.
+ * @param f Function to run for each FunctionEdge.
+ */
+ private def foreachFunction(edges: Seq[FunctionEdge], f: (FunctionEdge) => Unit) {
+ edges.sorted(functionOrdering).foreach(edge => if (running) f(edge))
+ }
+
+ /**
+ * Utility function returning all function edges.
+ */
+ private def getFunctionEdges: Seq[FunctionEdge] = {
+ jobGraph.edgeSet.toSeq.filter(_.isInstanceOf[FunctionEdge]).asInstanceOf[Seq[FunctionEdge]]
+ }
+
+ /**
+ * Utility function for running a method over all functions, but traversing the nodes in order of dependency.
+ * @param f Function to run for each FunctionEdge.
+ */
+ private def traverseFunctions(f: (FunctionEdge) => Unit) {
+ val iterator = new TopologicalOrderIterator(this.jobGraph)
+ iterator.addTraversalListener(new TraversalListenerAdapter[QNode, QEdge] {
+ override def edgeTraversed(event: EdgeTraversalEvent[QNode, QEdge]) {
+ if (running) {
+ event.getEdge match {
+ case functionEdge: FunctionEdge => f(functionEdge)
+ case map: MappingEdge => /* do nothing for mapping functions */
+ }
+ }
+ }
+ })
+ iterator.foreach(_ => {})
+ }
+
+ /**
+ * Outputs the graph to a .gv DOT file.
+ * http://www.graphviz.org/Documentation.php
+ * http://en.wikipedia.org/wiki/DOT_language
+ * @param file Path to output the .gv file.
+ */
+ private def renderGraph(file: java.io.File) {
+ val vertexIDProvider = new org.jgrapht.ext.VertexNameProvider[QNode] {
+ def getVertexName(node: QNode) = node.id.toString
+ }
+
+ val vertexLabelProvider = new org.jgrapht.ext.VertexNameProvider[QNode] {
+ // The QGraph fills in with single file nodes between nodes that contain more than one file.
+ // We only need to display the single element nodes.
+ def getVertexName(node: QNode) = {
+ if (!node.files.isEmpty && node.files.tail.isEmpty)
+ node.files.head.getName
+ else
+ ""
+ }
+ }
+
+ val edgeNameProvider = new org.jgrapht.ext.EdgeNameProvider[QEdge] {
+ def getEdgeName(edge: QEdge) = {
+ if (edge.shortDescription != null)
+ edge.shortDescription.replace("\"", "\\\"")
+ else
+ ""
+ }
+ }
+
+ val exporter = new DOTExporter(vertexIDProvider, vertexLabelProvider, edgeNameProvider)
+
+ val out = new OutputStreamWriter(FileUtils.openOutputStream(file))
+ try {
+ exporter.export(out, jobGraph)
+ } finally {
+ IOUtils.closeQuietly(out)
+ }
+ }
+
+ /**
+ * Returns true if no functions have missing values nor a status of failed.
+ * @return true if no functions have missing values nor a status of failed.
+ */
+ def success = {
+ if (numMissingValues > 0) {
+ false
+ } else if (this.dryRun) {
+ true
+ } else {
+ !this.jobGraph.edgeSet.exists(edge => {
+ if (edge.isInstanceOf[FunctionEdge]) {
+ val status = edge.asInstanceOf[FunctionEdge].status
+ (status == RunnerStatus.PENDING || status == RunnerStatus.RUNNING || status == RunnerStatus.FAILED)
+ } else {
+ false
+ }
+ })
+ }
+ }
+
+ def logFailed() {
+ foreachFunction(edge => {
+ if (edge.status == RunnerStatus.FAILED)
+ logEdge(edge)
+ })
+ }
+
+
+ private def updateStatus() {
+ val runners = runningJobs.map(_.runner)
+ for (mgr <- managers) {
+ if (mgr != null) {
+ val manager = mgr.asInstanceOf[JobManager[QFunction,JobRunner[QFunction]]]
+ val managerRunners = runners
+ .filter(runner => manager.runnerType.isAssignableFrom(runner.getClass))
+ .asInstanceOf[Set[JobRunner[QFunction]]]
+ if (managerRunners.size > 0)
+ try {
+ val updatedRunners = manager.updateStatus(managerRunners)
+ for (runner <- managerRunners.diff(updatedRunners)) {
+ runner.checkUnknownStatus()
+ }
+ } catch {
+ case e: Throwable => /* ignore */
+ }
+ }
+ }
+ }
+
+ /**
+ * Create the jobsReporter for this QGraph, based on the settings data.
+ *
+ * Must be called after settings has been initialized properly
+ *
+ * @return
+ */
+ private def createJobsReporter(): QJobsReporter = {
+ val jobStringName = if (settings.jobReportFile != null)
+ settings.jobReportFile
+ else
+ settings.qSettings.runName + ".jobreport.txt"
+
+ val reportFile = org.broadinstitute.gatk.utils.io.IOUtils.absolute(settings.qSettings.runDirectory, jobStringName)
+
+ val pdfFile = if ( settings.run )
+ Some(org.broadinstitute.gatk.utils.io.IOUtils.absolute(settings.qSettings.runDirectory, FilenameUtils.removeExtension(jobStringName) + ".pdf"))
+ else
+ None
+
+ new QJobsReporter(settings.disableJobReport, reportFile, pdfFile)
+ }
+
+ /**
+ * Write, if possible, the jobs report
+ */
+ def writeJobsReport(plot: Boolean = true) {
+ // note: the previous logic didn't write the job report if the system was shutting down, but I don't
+ // see any reason not to write the job report
+ if ( jobInfoReporter != null )
+ jobInfoReporter.write(this, plot)
+ }
+
+ /**
+ * Returns true if the graph was shutdown instead of exiting on its own.
+ */
+ def isShutdown = !running
+
+ def getFunctionsAndStatus: Map[QFunction, JobRunInfo] = {
+ getFunctionEdges.map(edge => (edge.function, edge.getRunInfo)).toMap
+ }
+
+ /**
+ * Kills any forked jobs still running.
+ */
+ def shutdown() {
+ // Signal the main thread to shutdown.
+ running = false
+
+ // Try and wait for the thread to finish and exit normally.
+ runningLock.synchronized {
+ runningLock.notify()
+ }
+
+ // Start killing jobs.
+ runningLock.synchronized {
+ val runners = runningJobs.map(_.runner)
+ runningJobs = Set.empty[FunctionEdge]
+ for (mgr <- managers) {
+ if (mgr != null) {
+ val manager = mgr.asInstanceOf[JobManager[QFunction,JobRunner[QFunction]]]
+ try {
+ val managerRunners = runners
+ .filter(runner => manager.runnerType.isAssignableFrom(runner.getClass))
+ .asInstanceOf[Set[JobRunner[QFunction]]]
+ if (managerRunners.size > 0)
+ try {
+ manager.tryStop(managerRunners)
+ } catch {
+ case e: Throwable => /* ignore */
+ }
+ for (runner <- managerRunners) {
+ try {
+ runner.cleanup()
+ } catch {
+ case e: Throwable => /* ignore */
+ }
+ }
+ } finally {
+ try {
+ manager.exit()
+ } catch {
+ case e: Throwable => /* ignore */
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QGraphSettings.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QGraphSettings.scala
new file mode 100644
index 0000000..49dace9
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QGraphSettings.scala
@@ -0,0 +1,85 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import java.io.File
+import org.broadinstitute.gatk.queue.QSettings
+import org.broadinstitute.gatk.queue.util.{EmailSettings, SystemUtils}
+import org.broadinstitute.gatk.utils.commandline.{Advanced, ArgumentCollection, Argument}
+
+/**
+ * Command line options for a QGraph.
+ */
+class QGraphSettings {
+ @Argument(fullName="run_scripts", shortName="run", doc="Run QScripts. Without this flag set only performs a dry run.", required=false)
+ var run = false
+
+ @Argument(fullName="job_runner", shortName="jobRunner", doc="Use the specified job runner to dispatch command line jobs", required=false)
+ var jobRunner: String = _
+
+ @Argument(fullName="bsub", shortName="bsub", doc="Equivalent to -jobRunner Lsf706", required=false)
+ var bsub = false
+
+ @Argument(fullName="qsub", shortName="qsub", doc="Equivalent to -jobRunner GridEngine", required=false)
+ var qsub = false
+
+ @Argument(fullName="status",shortName="status",doc="Get status of jobs for the qscript",required=false)
+ var getStatus = false
+
+ @Argument(fullName="retry_failed", shortName="retry", doc="Retry the specified number of times after a command fails. Defaults to no retries.", required=false)
+ var retries = 0
+
+ @Argument(fullName="start_from_scratch", shortName="startFromScratch", doc="Runs all command line functions even if the outputs were previously output successfully.", required=false)
+ var startFromScratch = false
+
+ @Argument(fullName="keep_intermediate_outputs", shortName="keepIntermediates", doc="After a successful run keep the outputs of any Function marked as intermediate.", required=false)
+ var keepIntermediates = false
+
+ @Argument(fullName="status_email_to", shortName="statusTo", doc="Email address to send emails to upon completion or on error.", required=false)
+ var statusEmailTo: Seq[String] = Nil
+
+ @Argument(fullName="status_email_from", shortName="statusFrom", doc="Email address to send emails from upon completion or on error.", required=false)
+ var statusEmailFrom: String = System.getProperty("user.name") + "@" + SystemUtils.mailName
+
+ @Argument(fullName="graphviz", shortName="gv", doc="Outputs the queue graph to a Graphviz .gv file. See: http://www.graphviz.org/Documentation.php", required=false)
+ var graphvizFile: File = _
+
+ @Argument(fullName="graphviz_scatter_gather", shortName="gvsg", doc="Outputs the scatter/gather queue graph to a Graphviz .gv file. Otherwise overwrites the --graphviz file.", required=false)
+ var graphvizScatterGatherFile: File = _
+
+ @Argument(fullName="jobReport", shortName="jobReport", doc="File where we will write the Queue job report", required=false)
+ var jobReportFile: String = _
+
+ @Advanced
+ @Argument(fullName="disableJobReport", shortName="disabpleJobReport", doc="If provided, we will not create a job report", required=false)
+ var disableJobReport: Boolean = false
+
+ @ArgumentCollection
+ val emailSettings = new EmailSettings
+
+ @ArgumentCollection
+ val qSettings = new QSettings
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QNode.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QNode.scala
new file mode 100644
index 0000000..5751a72
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QNode.scala
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import java.io.File
+
+/**
+ * Represents a state between QFunctions the directed acyclic QGraph
+ * @param files The list of files that represent this node state ordered by file name.
+ */
+class QNode (val id: Int, val files: Seq[File]) {
+ override def equals(obj: Any) = {
+ obj match {
+ case other: QNode => this.id == other.id
+ case _ => false
+ }
+ }
+
+ override def hashCode = id
+
+ override def toString = files.toString()
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QStatusMessenger.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QStatusMessenger.scala
new file mode 100644
index 0000000..14e4082
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/QStatusMessenger.scala
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+import org.broadinstitute.gatk.queue.util.RemoteFile
+
+/**
+ * Plugin to sends QStatus messages
+ */
+trait QStatusMessenger {
+ def started()
+ def done(inputs: Seq[_], outputs: Seq[_])
+ def exit(message: String)
+
+ def started(job: String)
+ def done(job: String)
+ def exit(job: String, message: String)
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/RunnerStatus.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/RunnerStatus.scala
new file mode 100644
index 0000000..93c9fde
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/RunnerStatus.scala
@@ -0,0 +1,34 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine
+
+object RunnerStatus extends Enumeration {
+ val PENDING = Value("pending")
+ val RUNNING = Value("running")
+ val FAILED = Value("failed")
+ val DONE = Value("done")
+ val SKIPPED = Value("skipped")
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/drmaa/DrmaaJobManager.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/drmaa/DrmaaJobManager.scala
new file mode 100644
index 0000000..02cf34e
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/drmaa/DrmaaJobManager.scala
@@ -0,0 +1,62 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine.drmaa
+
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.queue.engine.CommandLineJobManager
+import org.broadinstitute.gatk.utils.jna.drmaa.v1_0.JnaSessionFactory
+import org.ggf.drmaa.Session
+
+/**
+ * Runs jobs using DRMAA
+ */
+class DrmaaJobManager extends CommandLineJobManager[DrmaaJobRunner] {
+ protected var session: Session = _
+
+ protected def newSession() = new JnaSessionFactory().getSession
+ protected def contact = null
+
+ override def init() {
+ session = newSession()
+ session.init(contact)
+ }
+
+ override def exit() {
+ session.exit()
+ }
+
+ def runnerType = classOf[DrmaaJobRunner]
+ def create(function: CommandLineFunction) = new DrmaaJobRunner(session, function)
+
+ override def updateStatus(runners: Set[DrmaaJobRunner]) = {
+ var updatedRunners = Set.empty[DrmaaJobRunner]
+ runners.foreach(runner => if (runner.updateJobStatus()) {updatedRunners += runner})
+ updatedRunners
+ }
+ override def tryStop(runners: Set[DrmaaJobRunner]) {
+ runners.foreach(_.tryStop())
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/drmaa/DrmaaJobRunner.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/drmaa/DrmaaJobRunner.scala
new file mode 100644
index 0000000..aa19bfa
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/drmaa/DrmaaJobRunner.scala
@@ -0,0 +1,169 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine.drmaa
+
+import org.broadinstitute.gatk.queue.QException
+import org.broadinstitute.gatk.queue.util.{Logging,Retry}
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.queue.engine.{RunnerStatus, CommandLineJobRunner}
+import org.ggf.drmaa._
+import java.util.{Date, Collections}
+
+/**
+ * Runs jobs using DRMAA.
+ */
+class DrmaaJobRunner(val session: Session, val function: CommandLineFunction) extends CommandLineJobRunner with Logging {
+ /** Job Id of the currently executing job. */
+ var jobId: String = _
+ override def jobIdString = jobId
+
+ // Set the display name to < 512 characters of the description
+ // NOTE: Not sure if this is configuration specific?
+ protected val jobNameLength = 500
+ protected val jobNameFilter = """[^A-Za-z0-9_]"""
+ protected def functionNativeSpec = function.jobNativeArgs.mkString(" ")
+
+ def start() {
+ session.synchronized {
+ val drmaaJob: JobTemplate = session.createJobTemplate
+
+ drmaaJob.setJobName(function.jobRunnerJobName.take(jobNameLength).replaceAll(jobNameFilter, "_"))
+
+ // Set the current working directory
+ drmaaJob.setWorkingDirectory(function.commandDirectory.getPath)
+
+ // Set the output file for stdout
+ drmaaJob.setOutputPath(":" + function.jobOutputFile.getPath)
+
+ // If the error file is set specify the separate output for stderr
+ // Otherwise join with stdout
+ if (function.jobErrorFile != null) {
+ drmaaJob.setErrorPath(":" + function.jobErrorFile.getPath)
+ } else {
+ drmaaJob.setJoinFiles(true)
+ }
+
+ if(!function.wallTime.isEmpty)
+ drmaaJob.setHardWallclockTimeLimit(function.wallTime.get)
+
+ drmaaJob.setNativeSpecification(functionNativeSpec)
+
+ // Instead of running the function.commandLine, run "sh <jobScript>"
+ drmaaJob.setRemoteCommand("sh")
+ drmaaJob.setArgs(Collections.singletonList(jobScript.toString))
+
+ // Allow advanced users to update the request via QFunction.updateJobRun()
+ updateJobRun(drmaaJob)
+
+ updateStatus(RunnerStatus.RUNNING)
+
+ // Start the job and store the id so it can be killed in tryStop
+ try {
+ Retry.attempt(() => {
+ try {
+ jobId = session.runJob(drmaaJob)
+ } catch {
+ case de: DrmaaException => throw new QException("Unable to submit job: " + de.getLocalizedMessage)
+ }
+ }, 1, 5, 10)
+ } finally {
+ // Prevent memory leaks
+ session.deleteJobTemplate(drmaaJob)
+ }
+ logger.info("Submitted job id: " + jobId)
+ }
+ }
+
+ def updateJobStatus() = {
+ session.synchronized {
+ var returnStatus: RunnerStatus.Value = null
+
+ try {
+ val jobStatus = session.getJobProgramStatus(jobId);
+ jobStatus match {
+ case Session.QUEUED_ACTIVE => returnStatus = RunnerStatus.RUNNING
+ case Session.DONE =>
+ val jobInfo: JobInfo = session.wait(jobId, Session.TIMEOUT_NO_WAIT)
+
+ // Update jobInfo
+ def convertDRMAATime(key: String): Date = {
+ val v = jobInfo.getResourceUsage.get(key)
+ if ( v != null ) new Date(v.toString.toDouble.toLong * 1000) else null;
+ }
+ if ( jobInfo.getResourceUsage != null ) {
+ getRunInfo.startTime = convertDRMAATime("start_time")
+ getRunInfo.doneTime = convertDRMAATime("end_time")
+ getRunInfo.exechosts = "unknown"
+ }
+
+ if ((jobInfo.hasExited && jobInfo.getExitStatus != 0)
+ || jobInfo.hasSignaled
+ || jobInfo.wasAborted)
+ returnStatus = RunnerStatus.FAILED
+ else
+ returnStatus = RunnerStatus.DONE
+ case Session.FAILED => returnStatus = RunnerStatus.FAILED
+ case Session.UNDETERMINED => logger.warn("Unable to determine status of job id " + jobId)
+ case _ => returnStatus = RunnerStatus.RUNNING
+ }
+ } catch {
+ // getJobProgramStatus will throw an exception once wait has run, as the
+ // job will be reaped. If the status is currently DONE or FAILED, return
+ // the status.
+ case de: DrmaaException =>
+ if (lastStatus == RunnerStatus.DONE || lastStatus == RunnerStatus.FAILED)
+ returnStatus = lastStatus
+ else
+ logger.warn("Unable to determine status of job id " + jobId, de)
+ }
+
+ if (returnStatus != null) {
+ updateStatus(returnStatus)
+ true
+ } else {
+ false
+ }
+ }
+ }
+
+ def tryStop() {
+ session.synchronized {
+ // Assumes that after being set the job may be
+ // reassigned but will not be reset back to null
+ if (jobId != null) {
+ try {
+ // Stop runners. SIGTERM(15) is preferred to SIGKILL(9).
+ // Only way to send SIGTERM is for the Sys Admin set the terminate_method
+ // resource of the designated queue to SIGTERM
+ session.control(jobId, Session.TERMINATE)
+ } catch {
+ case e: Exception =>
+ logger.error("Unable to kill job " + jobId, e)
+ }
+ }
+ }
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/gridengine/GridEngineJobManager.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/gridengine/GridEngineJobManager.scala
new file mode 100644
index 0000000..eb60cb3
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/gridengine/GridEngineJobManager.scala
@@ -0,0 +1,33 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine.gridengine
+
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.queue.engine.drmaa.DrmaaJobManager
+
+class GridEngineJobManager extends DrmaaJobManager {
+ override def create(function: CommandLineFunction) = new GridEngineJobRunner(session, function)
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/gridengine/GridEngineJobRunner.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/gridengine/GridEngineJobRunner.scala
new file mode 100644
index 0000000..b21f43b
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/gridengine/GridEngineJobRunner.scala
@@ -0,0 +1,88 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine.gridengine
+
+import org.broadinstitute.gatk.queue.util.Logging
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.queue.engine.drmaa.DrmaaJobRunner
+import org.ggf.drmaa.Session
+
+/**
+ * Runs jobs on a Grid Engine compute cluster.
+ */
+class GridEngineJobRunner(session: Session, function: CommandLineFunction) extends DrmaaJobRunner(session, function) with Logging {
+ // Grid Engine disallows certain characters from being in job names.
+ // This replaces all illegal characters with underscores
+ protected override val jobNameFilter = """[\s/:,@\\*?]"""
+ protected override val minRunnerPriority = -1023
+ protected override val maxRunnerPriority = 0
+
+ override protected def functionNativeSpec = {
+ // Force the remote environment to inherit local environment settings
+ var nativeSpec: String = "-V"
+
+ // If a project name is set specify the project name
+ if (function.jobProject != null)
+ nativeSpec += " -P " + function.jobProject
+
+ // If the job queue is set specify the job queue
+ if (function.jobQueue != null)
+ nativeSpec += " -q " + function.jobQueue
+
+ // If the resident set size is requested pass on the memory request
+ // mem_free is the standard, but may also be virtual_free or even not available
+ if (function.qSettings.residentRequestParameter != null && function.residentRequest.isDefined)
+ nativeSpec += " -l %s=%dM".format(function.qSettings.residentRequestParameter, function.residentRequest.map(_ * 1024).get.ceil.toInt)
+
+ // If the resident set size limit is defined specify the memory limit
+ if (function.residentLimit.isDefined)
+ nativeSpec += " -l h_rss=%dM".format(function.residentLimit.map(_ * 1024).get.ceil.toInt)
+
+ // If more than 1 core is requested, set the proper request
+ // if we aren't being jerks and just stealing cores (previous behavior)
+ if ( function.nCoresRequest.getOrElse(1) > 1 ) {
+ if ( function.qSettings.dontRequestMultipleCores )
+ logger.warn("Sending multicore job %s to farm without requesting appropriate number of cores (%d)".format(
+ function.shortDescription, function.nCoresRequest.get))
+ else
+ nativeSpec += " -pe %s %d".format(function.qSettings.parallelEnvironmentName, function.nCoresRequest.get)
+ }
+
+ // Pass on any job resource requests
+ nativeSpec += function.jobResourceRequests.map(" -l " + _).mkString
+
+ // Pass on any job environment names
+ nativeSpec += function.jobEnvironmentNames.map(" -pe " + _).mkString
+
+ // If the priority is set specify the priority
+ val priority = functionPriority
+ if (priority.isDefined)
+ nativeSpec += " -p " + priority.get
+
+ logger.debug("Native spec is: %s".format(nativeSpec))
+ (nativeSpec + " " + super.functionNativeSpec).trim()
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/lsf/Lsf706JobManager.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/lsf/Lsf706JobManager.scala
new file mode 100644
index 0000000..dbe2536
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/lsf/Lsf706JobManager.scala
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine.lsf
+
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.queue.engine.CommandLineJobManager
+
+/**
+ * Creates and stops Lsf706JobRunners
+ */
+class Lsf706JobManager extends CommandLineJobManager[Lsf706JobRunner] {
+ def runnerType = classOf[Lsf706JobRunner]
+ def create(function: CommandLineFunction) = new Lsf706JobRunner(function)
+
+ override def updateStatus(runners: Set[Lsf706JobRunner]) = { Lsf706JobRunner.updateStatus(runners) }
+ override def tryStop(runners: Set[Lsf706JobRunner]) { Lsf706JobRunner.tryStop(runners) }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/lsf/Lsf706JobRunner.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/lsf/Lsf706JobRunner.scala
new file mode 100644
index 0000000..eeb82a3
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/lsf/Lsf706JobRunner.scala
@@ -0,0 +1,421 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine.lsf
+
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.queue.util._
+import org.broadinstitute.gatk.queue.QException
+import org.broadinstitute.gatk.utils.jna.lsf.v7_0_6.{LibLsf, LibBat}
+import org.broadinstitute.gatk.utils.Utils
+import org.broadinstitute.gatk.utils.jna.clibrary.LibC
+import org.broadinstitute.gatk.utils.jna.lsf.v7_0_6.LibBat.{submitReply, submit}
+import org.broadinstitute.gatk.queue.engine.{RunnerStatus, CommandLineJobRunner}
+import java.util.regex.Pattern
+import java.lang.StringBuffer
+import java.util.Date
+import com.sun.jna.{Pointer, Structure, StringArray, NativeLong}
+import com.sun.jna.ptr.IntByReference
+
+/**
+ * Runs jobs on an LSF compute cluster.
+ */
+class Lsf706JobRunner(val function: CommandLineFunction) extends CommandLineJobRunner with Logging {
+
+ // Run the static initializer for Lsf706JobRunner
+ Lsf706JobRunner
+
+ /** Job Id of the currently executing job. */
+ private var jobId = -1L
+ override def jobIdString = jobId.toString
+
+ protected override val minRunnerPriority = 1
+ protected override val maxRunnerPriority = Lsf706JobRunner.maxUserPriority
+
+ private val selectString = new StringBuffer()
+ private val usageString = new StringBuffer()
+ private val requestString = new StringBuffer()
+ private val spanString = new StringBuffer()
+
+ /**
+ * Dispatches the function on the LSF cluster.
+ */
+ def start() {
+ Lsf706JobRunner.lsfLibLock.synchronized {
+
+ parseResourceRequest()
+
+ val request = new submit
+ for (i <- 0 until LibLsf.LSF_RLIM_NLIMITS)
+ request.rLimits(i) = LibLsf.DEFAULT_RLIMIT;
+
+ request.jobName = function.jobRunnerJobName.take(LibBat.MAX_JOB_NAME_LEN)
+ request.options |= LibBat.SUB_JOB_NAME
+
+ // Set the output file for stdout
+ request.outFile = function.jobOutputFile.getPath
+ request.options |= LibBat.SUB_OUT_FILE
+
+ // Set the current working directory
+ request.cwd = function.commandDirectory.getPath
+ request.options3 |= LibBat.SUB3_CWD
+
+ // If the error file is set specify the separate output for stderr
+ if (function.jobErrorFile != null) {
+ request.errFile = function.jobErrorFile.getPath
+ request.options |= LibBat.SUB_ERR_FILE
+ }
+
+ // If the job queue is set specify the job queue
+ if (function.jobQueue != null) {
+ request.queue = function.jobQueue
+ request.options |= LibBat.SUB_QUEUE
+ }
+
+ // If the resident set size is requested pass on the memory request
+ if (function.residentRequest.isDefined) {
+ val memInUnits = Lsf706JobRunner.convertUnits(function.residentRequest.get)
+ appendRequest("select", selectString, "&&", "mem>%d".format(memInUnits))
+ appendRequest("rusage", usageString, ",", "mem=%d".format(memInUnits))
+ }
+
+ //
+ // Request multiple cores on the same host. If nCoresRequest > 1, and we
+ // aren't being jerks and stealing cores, set numProcessors and maxNumProcessors
+ // and the span[host=1] parameters to get us exactly the right number of
+ // cores on a single host
+ //
+ if ( function.nCoresRequest.getOrElse(1) > 1 ) {
+ if ( function.qSettings.dontRequestMultipleCores )
+ logger.warn("Sending multicore job %s to farm without requesting appropriate number of cores (%d)".format(
+ function.shortDescription, function.nCoresRequest.get))
+ else {
+ request.numProcessors = function.nCoresRequest.get
+ request.maxNumProcessors = request.numProcessors
+ appendRequest("span", spanString, ",", "hosts=1")
+ }
+ }
+
+ val resReq = getResourceRequest
+ if (resReq.length > 0) {
+ request.resReq = resReq
+ request.options |= LibBat.SUB_RES_REQ
+ }
+
+ // If the resident set size limit is defined specify the memory limit
+ if (function.residentLimit.isDefined) {
+ val memInUnits = Lsf706JobRunner.convertUnits(function.residentLimit.get)
+ request.rLimits(LibLsf.LSF_RLIMIT_RSS) = memInUnits
+ }
+
+ // If the priority is set (user specified Int) specify the priority
+ val priority = functionPriority
+ if (priority.isDefined) {
+ request.userPriority = priority.get
+ request.options2 |= LibBat.SUB2_JOB_PRIORITY
+ }
+
+ // Set the project to either the function or LSF default
+ val project = if (function.jobProject != null) function.jobProject else Lsf706JobRunner.defaultProject
+ if (project != null) {
+ request.projectName = project
+ request.options |= LibBat.SUB_PROJECT_NAME
+ }
+
+ // Set the esub names based on the job envorinment names
+ if (!function.jobEnvironmentNames.isEmpty) {
+ val argv = Array("", "-a", function.jobEnvironmentNames.mkString(" "))
+ val setOptionResult = LibBat.setOption_(argv.length, new StringArray(argv), "a:", request, ~0, ~0, ~0, null);
+ if (setOptionResult == -1)
+ throw new QException("setOption_() returned -1 while setting esub");
+ }
+
+ if(!function.wallTime.isEmpty)
+ request.rLimits(LibLsf.LSF_RLIMIT_RUN) = function.wallTime.get.toInt
+ else
+ // LSF specific: get the max runtime for the jobQueue and pass it for this job
+ request.rLimits(LibLsf.LSF_RLIMIT_RUN) = Lsf706JobRunner.getRlimitRun(function.jobQueue)
+
+ // Run the command as sh <jobScript>
+ request.command = "sh " + jobScript
+
+ // Allow advanced users to update the request via QFunction.updateJobRun()
+ updateJobRun(request)
+
+ updateStatus(RunnerStatus.RUNNING)
+ Retry.attempt(() => {
+ val reply = new submitReply
+ jobId = LibBat.lsb_submit(request, reply)
+ if (jobId < 0)
+ throw new QException(LibBat.lsb_sperror("Unable to submit job"))
+ }, 1, 5, 10)
+ logger.info("Submitted LSF job id: " + jobId)
+ }
+ }
+
+ override def checkUnknownStatus() {
+ // TODO: Need a second pass through either of the two archive logs using lsb_geteventrecbyline() for disappeared jobs.
+ // Can also tell if we wake up and the last time we saw status was greater than lsb_parameterinfo().cleanPeriod
+ // LSB_SHAREDIR/cluster_name/logdir/lsb.acct (man bacct)
+ // LSB_SHAREDIR/cluster_name/logdir/lsb.events (man bhist)
+ logger.debug("Job Id %s status / exitStatus / exitInfo: ??? / ??? / ???".format(jobId))
+ super.checkUnknownStatus()
+ }
+
+ private def parseResourceRequest() {
+ requestString.setLength(0)
+ selectString.setLength(0)
+ usageString.setLength(0)
+ spanString.setLength(0)
+
+ requestString.append(function.jobResourceRequests.mkString(" "))
+ extractSection(requestString, "select", selectString)
+ extractSection(requestString, "rusage", usageString)
+ extractSection(requestString, "span", spanString)
+ }
+
+ private def extractSection(requestString: StringBuffer, section: String, sectionString: StringBuffer) {
+ val pattern = Pattern.compile(section + "\\s*\\[[^\\]]+\\]\\s*");
+ val matcher = pattern.matcher(requestString.toString)
+ if (matcher.find()) {
+ sectionString.setLength(0)
+ sectionString.append(matcher.group().trim())
+
+ val sb = new StringBuffer
+ matcher.appendReplacement(sb, "")
+ matcher.appendTail(sb)
+
+ requestString.setLength(0)
+ requestString.append(sb)
+ }
+ }
+
+ private def appendRequest(section: String, sectionString: StringBuffer, separator: String, request: String) {
+ if (sectionString.length() == 0)
+ sectionString.append(section).append("[").append(request).append("]")
+ else
+ sectionString.insert(sectionString.length() - 1, separator + request)
+ }
+
+ private def getResourceRequest = "%s %s %s %s".format(selectString, usageString, spanString, requestString).trim()
+}
+
+object Lsf706JobRunner extends Logging {
+ private val lsfLibLock = new Object
+ private val SIGTERM = 15
+
+ /** Number of seconds for a non-normal exit status before we give up on expecting LSF to retry the function. */
+ private val retryExpiredSeconds = 5 * 60
+
+ /**
+ * Initialize the Lsf library.
+ */
+ private val (defaultQueue, defaultProject, maxUserPriority) = {
+ lsfLibLock.synchronized {
+ if (LibBat.lsb_init("Queue") < 0)
+ throw new QException(LibBat.lsb_sperror("lsb_init() failed"))
+
+ val parameterInfo = LibBat.lsb_parameterinfo(null, null, 0);
+ var defaultQueue: String = parameterInfo.defaultQueues
+ val defaultProject = parameterInfo.defaultProject
+ val maxUserPriority = parameterInfo.maxUserPriority
+
+ if (defaultQueue != null && defaultQueue.indexOf(' ') > 0)
+ defaultQueue = defaultQueue.split(" ")(0)
+
+ (defaultQueue, defaultProject, maxUserPriority)
+ }
+ }
+
+ /**
+ * Bulk updates job statuses.
+ * @param runners Runners to update.
+ * @return runners which were updated.
+ */
+ def updateStatus(runners: Set[Lsf706JobRunner]) = {
+ var updatedRunners = Set.empty[Lsf706JobRunner]
+
+ Lsf706JobRunner.lsfLibLock.synchronized {
+ val result = LibBat.lsb_openjobinfo(0L, null, null, null, null, LibBat.ALL_JOB)
+ if (result < 0) {
+ logger.error(LibBat.lsb_sperror("Unable to check LSF job info"))
+ } else {
+ try {
+ val more = new IntByReference(result)
+ while (more.getValue > 0) {
+ val jobInfo = LibBat.lsb_readjobinfo(more)
+ if (jobInfo == null) {
+ logger.error(LibBat.lsb_sperror("Unable to read LSF job info"))
+ more.setValue(0)
+ } else {
+ runners.find(runner => runner.jobId == jobInfo.jobId) match {
+ case Some(runner) =>
+ updateRunnerStatus(runner, jobInfo)
+ updatedRunners += runner
+ case None => /* not our job */
+ }
+ }
+ }
+ } finally {
+ LibBat.lsb_closejobinfo()
+ }
+ }
+ }
+
+ updatedRunners
+ }
+
+ private def updateRunnerStatus(runner: Lsf706JobRunner, jobInfo: LibBat.jobInfoEnt) {
+ val jobStatus = jobInfo.status
+ val exitStatus = jobInfo.exitStatus
+ val exitInfo = jobInfo.exitInfo
+ val endTime = jobInfo.endTime
+
+ logger.debug("Job Id %s status / exitStatus / exitInfo: 0x%02x / 0x%02x / 0x%02x".format(runner.jobId, jobStatus, exitStatus, exitInfo))
+
+ def updateRunInfo() {
+ // the platform LSF startTimes are in seconds, not milliseconds, so convert to the java convention
+ runner.getRunInfo.startTime = new Date(jobInfo.startTime.longValue * 1000)
+ runner.getRunInfo.doneTime = new Date(jobInfo.endTime.longValue * 1000)
+
+ val exHostsList =
+ if (jobInfo.numExHosts != 1) {
+ // this is necessary because
+ val exHostsString = "multipleHosts_" + jobInfo.numExHosts
+ logger.debug("numExHosts = " + jobInfo.numExHosts + " != 1 for job " + runner.jobId + ", cannot safely get exhosts, setting to " + exHostsString)
+ List(exHostsString)
+ } else {
+ jobInfo.exHosts.getStringArray(0).toSeq
+ }
+
+ //logger.warn("exHostsList = " + exHostsList)
+ val exHosts = exHostsList.reduceLeft(_ + "," + _)
+ //logger.warn("exHosts = " + exHosts)
+ runner.getRunInfo.exechosts = exHosts
+ }
+
+ runner.updateStatus(
+ if (Utils.isFlagSet(jobStatus, LibBat.JOB_STAT_DONE)) {
+ // Done successfully.
+ updateRunInfo()
+ RunnerStatus.DONE
+ } else if (Utils.isFlagSet(jobStatus, LibBat.JOB_STAT_EXIT) && !willRetry(exitInfo, endTime)) {
+ // Exited function that (probably) won't be retried.
+ updateRunInfo()
+ RunnerStatus.FAILED
+ } else {
+ // Note that we still saw the job in the system.
+ RunnerStatus.RUNNING
+ }
+ )
+ }
+
+ /**
+ * Returns true if LSF is expected to retry running the function.
+ * @param exitInfo The reason the job exited.
+ * @param endTime THe time the job exited.
+ * @return true if LSF is expected to retry running the function.
+ */
+ private def willRetry(exitInfo: Int, endTime: NativeLong) = {
+ exitInfo match {
+ case LibBat.EXIT_NORMAL => false
+ case _ => {
+ val seconds = LibC.difftime(LibC.time(null), endTime)
+ (seconds <= retryExpiredSeconds)
+ }
+ }
+ }
+
+ /**
+ * Tries to stop any running jobs.
+ * @param runners Runners to stop.
+ */
+ def tryStop(runners: Set[Lsf706JobRunner]) {
+ lsfLibLock.synchronized {
+ // lsb_killbulkjobs does not seem to forward SIGTERM,
+ // only SIGKILL, so send the Ctrl-C (SIGTERM) one by one.
+ for (runner <- runners.filterNot(_.jobId < 0)) {
+ try {
+ if (LibBat.lsb_signaljob(runner.jobId, SIGTERM) < 0)
+ logger.error(LibBat.lsb_sperror("Unable to kill job " + runner.jobId))
+ } catch {
+ case e: Exception=>
+ logger.error("Unable to kill job " + runner.jobId, e)
+ }
+ }
+ }
+ }
+
+ /** The run limits for each queue. */
+ private var queueRlimitRun = Map.empty[String,Int]
+
+ /**
+ * Returns the run limit in seconds for the queue.
+ * If the queue name is null returns the length of the default queue.
+ * @param queueName Name of the queue or null for the default queue.
+ * @return the run limit in seconds for the queue.
+ */
+ private def getRlimitRun(queueName: String) = {
+ lsfLibLock.synchronized {
+ val queue = if (queueName == null) defaultQueue else queueName
+ queueRlimitRun.get(queue) match {
+ case Some(limit) => limit
+ case None =>
+ // Cache miss. Go get the run limits from LSF.
+ val queues = new StringArray(Array(queue))
+ val numQueues = new IntByReference(1)
+ val queueInfo = LibBat.lsb_queueinfo(queues, numQueues, null, null, 0)
+ if (queueInfo == null)
+ throw new QException(LibBat.lsb_sperror("Unable to get LSF queue info for queue: " + queue))
+ val limit = queueInfo.rLimits(LibLsf.LSF_RLIMIT_RUN)
+ queueRlimitRun += queue -> limit
+ limit
+ }
+ }
+ }
+
+ private lazy val unitDivisor: Double = {
+ lsfLibLock.synchronized {
+ val unitsParam: Array[LibLsf.config_param] = new LibLsf.config_param().toArray(2).asInstanceOf[Array[LibLsf.config_param]]
+ unitsParam(0).paramName = "LSF_UNIT_FOR_LIMITS"
+
+ Structure.autoWrite(unitsParam.asInstanceOf[Array[Structure]])
+ if (LibLsf.ls_readconfenv(unitsParam(0), null) != 0)
+ throw new QException(LibBat.lsb_sperror("ls_readconfenv() failed"))
+ Structure.autoRead(unitsParam.asInstanceOf[Array[Structure]])
+
+ unitsParam(0).paramValue match {
+ case "MB" => 1 / 1024D
+ case "GB" => 1D
+ case "TB" => 1024D
+ case "PB" => 1024D * 1024
+ case "EB" => 1024D * 1024 * 1024
+ case null => 1 / 1024D
+ }
+ }
+ }
+
+ private def convertUnits(gb: Double) = (gb / unitDivisor).ceil.toInt
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/pbsengine/PbsEngineJobManager.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/pbsengine/PbsEngineJobManager.scala
new file mode 100644
index 0000000..fb68231
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/pbsengine/PbsEngineJobManager.scala
@@ -0,0 +1,33 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine.pbsengine
+
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.queue.engine.drmaa.DrmaaJobManager
+
+class PbsEngineJobManager extends DrmaaJobManager {
+ override def create(function: CommandLineFunction) = new PbsEngineJobRunner(session, function)
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/pbsengine/PbsEngineJobRunner.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/pbsengine/PbsEngineJobRunner.scala
new file mode 100644
index 0000000..092152f
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/pbsengine/PbsEngineJobRunner.scala
@@ -0,0 +1,98 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine.pbsengine
+
+import org.broadinstitute.gatk.queue.util.Logging
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.queue.engine.drmaa.DrmaaJobRunner
+import org.ggf.drmaa.Session
+
+/**
+ * Runs jobs on a PBS/Torque Engine compute cluster.
+ * NB - THIS FILE HAS BEEN MODIFIED from the original code
+ * of the GridEngine package
+ */
+class PbsEngineJobRunner(session: Session, function: CommandLineFunction) extends DrmaaJobRunner(session, function) with Logging {
+ // Pbs Engine disallows certain characters from being in job names.
+ // This replaces all illegal characters with underscores
+ protected override val jobNameFilter = """[\n\t\r/:,@\\*?]"""
+ protected override val minRunnerPriority = -1023
+ protected override val maxRunnerPriority = 0
+
+ override protected def functionNativeSpec = {
+
+ // create nativeSpec variable
+ var nativeSpec: String = ""
+
+ // If a project name is set specify the project name
+ if (function.jobProject != null)
+ nativeSpec += " -P " + function.jobProject
+
+ // If the job queue is set specify the job queue
+ if (function.jobQueue != null)
+ nativeSpec += " -q " + function.jobQueue
+
+ // If the resident set size is requested pass on the memory request
+ // mem_free is the standard, but may also be virtual_free or even not available
+
+ if (function.qSettings.residentRequestParameter != null && function.residentRequest.isDefined)
+ nativeSpec += " -l %s=%dM".format(function.qSettings.residentRequestParameter, function.residentRequest.map(_ * 1024).get.ceil.toInt)
+
+ // If the resident set size limit is defined specify the memory limit
+ if (function.residentLimit.isDefined)
+ nativeSpec += " -l mem=%dM".format(function.residentLimit.map(_ * 1024).get.ceil.toInt)
+
+ // If more than 1 core is requested, set the proper request
+ // the cores will be requested as part of a single node
+
+ if ( function.nCoresRequest.getOrElse(1) > 1 ) {
+ if ( function.qSettings.dontRequestMultipleCores )
+ logger.warn("Sending multicore job %s to farm without requesting appropriate number of cores (%d)".format(
+ function.shortDescription, function.nCoresRequest.get))
+ else
+ nativeSpec += " -l nodes=1:ppn=%d".format(function.nCoresRequest.get)
+ }
+
+ // Pass on any job resource requests
+ // NB: blank because resource requests in PBS can be preceded by different
+ // arguments, i.e. -l but also -o or -j if they are not exactly "resources" strictly speaking
+ // therefore the user will add them in the request, i.e. -jobResReq "-j oe"
+ // but this will allow more flexibility in setting the options for PBS jobs on different Clusters
+
+ nativeSpec += function.jobResourceRequests.map(" " + _).mkString
+
+ // Pass on any job environment names
+ nativeSpec += function.jobEnvironmentNames.map(" " + _).mkString
+
+ // If the priority is set specify the priority
+ val priority = functionPriority
+ if (priority.isDefined)
+ nativeSpec += " -p " + priority.get
+
+ logger.debug("Native spec is: %s".format(nativeSpec))
+ (nativeSpec + " " + super.functionNativeSpec).trim()
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/shell/ShellJobManager.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/shell/ShellJobManager.scala
new file mode 100644
index 0000000..5645590
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/shell/ShellJobManager.scala
@@ -0,0 +1,35 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine.shell
+
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.queue.engine.CommandLineJobManager
+
+class ShellJobManager extends CommandLineJobManager[ShellJobRunner] {
+ def runnerType = classOf[ShellJobRunner]
+ def create(function: CommandLineFunction) = new ShellJobRunner(function)
+ override def tryStop(runners: Set[ShellJobRunner]) { runners.foreach(_.tryStop()) }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/shell/ShellJobRunner.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/shell/ShellJobRunner.scala
new file mode 100644
index 0000000..327be22
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/engine/shell/ShellJobRunner.scala
@@ -0,0 +1,91 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.engine.shell
+
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.queue.engine.{RunnerStatus, CommandLineJobRunner}
+import java.util.Date
+import org.broadinstitute.gatk.utils.Utils
+import org.broadinstitute.gatk.utils.runtime.{ProcessSettings, OutputStreamSettings, ProcessController}
+
+/**
+ * Runs jobs one at a time locally
+ * @param function Command to run.
+ */
+class ShellJobRunner(val function: CommandLineFunction) extends CommandLineJobRunner {
+ // Controller on the thread that started the job
+ private var controller: ProcessController = null
+
+ /**
+ * Runs the function on the local shell.
+ */
+ def start() {
+ val commandLine = Array("sh", jobScript.getAbsolutePath)
+ val stdoutSettings = new OutputStreamSettings
+ val stderrSettings = new OutputStreamSettings
+ val mergeError = (function.jobErrorFile == null)
+
+ stdoutSettings.setOutputFile(function.jobOutputFile, true)
+ if (function.jobErrorFile != null)
+ stderrSettings.setOutputFile(function.jobErrorFile, true)
+
+ if (logger.isDebugEnabled) {
+ stdoutSettings.printStandard(true)
+ stderrSettings.printStandard(true)
+ }
+
+ val processSettings = new ProcessSettings(
+ commandLine, mergeError, function.commandDirectory, null,
+ null, stdoutSettings, stderrSettings)
+
+ updateJobRun(processSettings)
+
+ getRunInfo.startTime = new Date()
+ getRunInfo.exechosts = Utils.resolveHostname()
+ updateStatus(RunnerStatus.RUNNING)
+ controller = ProcessController.getThreadLocal
+ val exitStatus = controller.exec(processSettings).getExitValue
+ getRunInfo.doneTime = new Date()
+ updateStatus(if (exitStatus == 0) RunnerStatus.DONE else RunnerStatus.FAILED)
+ }
+
+ /**
+ * Possibly invoked from a shutdown thread, find and
+ * stop the controller from the originating thread
+ */
+ def tryStop() {
+ // Assumes that after being set the job may be
+ // reassigned but will not be reset back to null
+ if (controller != null) {
+ try {
+ controller.tryDestroy()
+ } catch {
+ case e: Exception =>
+ logger.error("Unable to kill shell job: " + function.description, e)
+ }
+ }
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/CommandLineFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/CommandLineFunction.scala
new file mode 100644
index 0000000..e1cb7d0
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/CommandLineFunction.scala
@@ -0,0 +1,341 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function
+
+import org.broadinstitute.gatk.queue.util._
+import org.broadinstitute.gatk.utils.commandline.Argument
+
+/**
+ * A command line that will be run in a pipeline.
+ */
+trait CommandLineFunction extends QFunction with Logging {
+ def commandLine: String
+
+ /** Setting the wall time request for DRMAA / run limit for LSF */
+ var wallTime: Option[Long] = None
+
+ /** Upper memory limit */
+ @Argument(doc="Memory limit", required=false)
+ var memoryLimit: Option[Double] = None
+
+ /** Resident memory limit */
+ @Argument(doc="Resident memory limit", required=false)
+ var residentLimit: Option[Double] = None
+
+ /** Resident memory request */
+ @Argument(doc="Resident memory request", required=false)
+ var residentRequest: Option[Double] = None
+
+ /** the number of SMP cores this job wants */
+ var nCoresRequest: Option[Int] = None
+
+ /** Job project to run the command */
+ var jobProject: String = _
+
+ /** Job queue to run the command */
+ var jobQueue: String = _
+
+ /** Native arguments to pass to the job runner */
+ var jobNativeArgs: Seq[String] = Nil
+
+ /** Native arguments to pass to the job runner */
+ var jobResourceRequests: Seq[String] = Nil
+
+ /** Environment names to pass to the job runner */
+ var jobEnvironmentNames: Seq[String] = Nil
+
+ override def copySettingsTo(function: QFunction) {
+ super.copySettingsTo(function)
+ function match {
+ case commandLineFunction: CommandLineFunction =>
+ if(commandLineFunction.wallTime.isEmpty)
+ commandLineFunction.wallTime = this.wallTime
+
+ if (commandLineFunction.memoryLimit.isEmpty)
+ commandLineFunction.memoryLimit = this.memoryLimit
+
+ if (commandLineFunction.residentLimit.isEmpty)
+ commandLineFunction.residentLimit = this.residentLimit
+
+ if (commandLineFunction.residentRequest.isEmpty)
+ commandLineFunction.residentRequest = this.residentRequest
+
+ if (commandLineFunction.nCoresRequest.isEmpty)
+ commandLineFunction.nCoresRequest = this.nCoresRequest
+
+ if (commandLineFunction.jobProject == null)
+ commandLineFunction.jobProject = this.jobProject
+
+ if (commandLineFunction.jobQueue == null)
+ commandLineFunction.jobQueue = this.jobQueue
+
+ if (commandLineFunction.jobNativeArgs.isEmpty)
+ commandLineFunction.jobNativeArgs = this.jobNativeArgs
+
+ if (commandLineFunction.jobResourceRequests.isEmpty)
+ commandLineFunction.jobResourceRequests = this.jobResourceRequests
+
+ if (commandLineFunction.jobEnvironmentNames.isEmpty)
+ commandLineFunction.jobEnvironmentNames = this.jobEnvironmentNames
+
+ case _ => /* ignore */
+ }
+ }
+
+ /**
+ * Returns set of directories required to run the command.
+ * @return Set of directories required to run the command.
+ */
+ def jobDirectories = outputDirectories ++ inputs.map(_.getParentFile)
+
+ override def description = commandLine
+
+ /**
+ * Sets all field values.
+ */
+ override def freezeFieldValues() {
+
+ if(wallTime.isEmpty)
+ wallTime = qSettings.jobWalltime
+
+ if (jobQueue == null)
+ jobQueue = qSettings.jobQueue
+
+ if (jobProject == null)
+ jobProject = qSettings.jobProject
+
+ if (jobNativeArgs.isEmpty)
+ jobNativeArgs = qSettings.jobNativeArgs
+
+ if (jobResourceRequests.isEmpty)
+ jobResourceRequests = qSettings.jobResourceRequests
+
+ if (jobEnvironmentNames.isEmpty)
+ jobEnvironmentNames = qSettings.jobEnvironmentNames
+
+ if (memoryLimit.isEmpty)
+ memoryLimit = qSettings.memoryLimit
+
+ if (residentLimit.isEmpty)
+ residentLimit = qSettings.residentLimit
+
+ if (residentRequest.isEmpty)
+ residentRequest = qSettings.residentRequest
+
+ // the default value is 1 core
+ if (nCoresRequest.isEmpty)
+ nCoresRequest = Some(1)
+
+ if (residentRequest.isEmpty)
+ residentRequest = memoryLimit
+
+ if (residentLimit.isEmpty || residentLimit == residentRequest)
+ residentLimit = residentRequest.map(residentLimitBuffer)
+
+ super.freezeFieldValues()
+ }
+
+ /**
+ * @return A function that decides how much memory cushion to add to the residentRequest to create the residentLimit
+ */
+ def residentLimitBuffer: (Double => Double) = (1.2 * _)
+
+ /**
+ * Safely construct a full required command-line argument with consistent quoting, whitespace separation, etc.
+ *
+ * @param prefix Prefix to insert before the argument value (eg., "-f")
+ * @param param The argument value itself
+ * @param suffix Suffix to append after the argument value
+ * @param spaceSeparated If true, insert a space between the prefix, param, and suffix
+ * @param escape If true, quote the generated argument to avoid interpretation by the shell
+ * @param format Format String used to convert param to a String
+ * @return The combined and formatted argument, surrounded by whitespace
+ */
+ protected def required( prefix: String, param: Any, suffix: String = "", spaceSeparated: Boolean = true,
+ escape: Boolean = true, format: String = "%s" ): String = {
+ " %s ".format(formatArgument(prefix, param, suffix, spaceSeparated, escape, format))
+ }
+
+ /**
+ * Safely construct a one-token required command-line argument with quoting
+ *
+ * @param param The command-line argument value
+ * @return The argument value quoted and surrounded by whitespace
+ */
+ protected def required( param: Any ): String = {
+ required("", param)
+ }
+
+ /**
+ * Safely construct a one-token required command-line argument, and specify whether you want quoting
+ *
+ * @param param The command-line argument value
+ * @param escape If true, quote the generated argument to avoid interpretation by the shell
+ * @return The argument value, quoted if quoting was requested, and surrounded by whitespace
+ */
+ protected def required( param: Any, escape: Boolean ): String = {
+ required("", param, escape=escape)
+ }
+
+ /**
+ * Safely construct a full optional command-line argument with consistent quoting, whitespace separation, etc.
+ * If the argument has no value, returns an empty String.
+ *
+ * @param prefix Prefix to insert before the argument value (eg., "-f")
+ * @param param The argument value itself (if null/empty, the method returns empty String)
+ * @param suffix Suffix to append after the argument value
+ * @param spaceSeparated If true, insert a space between the prefix, param, and suffix
+ * @param escape If true, quote the generated argument to avoid interpretation by the shell
+ * @param format Format String used to convert param to a String
+ * @return The combined and formatted argument, surrounded by whitespace, or an empty String
+ * if the argument has no value
+ */
+ protected def optional( prefix: String, param: Any, suffix: String = "", spaceSeparated: Boolean = true,
+ escape: Boolean = true, format: String = "%s" ): String = {
+ if ( hasValue(param) ) " %s ".format(formatArgument(prefix, param, suffix, spaceSeparated, escape, format)) else ""
+ }
+
+ /**
+ * Safely construct a one-token optional command-line argument with quoting.
+ * If the argument has no value, returns an empty String.
+ *
+ * @param param The command-line argument value
+ * @return The argument value quoted and surrounded by whitespace, or an empty String
+ * if the argument has no value
+ */
+ protected def optional( param: Any ): String = {
+ optional("", param)
+ }
+
+ /**
+ * Safely construct a one-token conditional command-line argument. If the provided condition
+ * is false, an empty String is returned.
+ *
+ * @param condition The condition to check
+ * @param param The command-line argument value
+ * @param escape If true, quote the generated argument to avoid interpretation by the shell
+ * @param format Format String used to convert param to a String
+ * @return The command-line argument value, quoted if quoting was requested and surrounded
+ * by whitespace, or an empty String if the argument has no value.
+ */
+ protected def conditional( condition: Boolean, param: Any, escape: Boolean = true, format: String = "%s" ): String = {
+ if ( condition ) {
+ " %s ".format(formatArgument("", param, "", spaceSeparated = false, escape = escape, paramFormat = format))
+ }
+ else {
+ ""
+ }
+ }
+
+ /**
+ * Safely construct a series of full command-line arguments with consistent quoting, whitespace separation, etc.
+ *
+ * Each argument value is preceded by a prefix/suffix if they are set. A function can be provided to vary
+ * each prefix for each argument value (eg., -f:tag1 file1 -f:tag2 file2) -- the default is to use
+ * the same prefix for all arguments.
+ *
+ * @param prefix Prefix to insert before each argument value (eg., "-f")
+ * @param params The collection of argument values
+ * @param suffix Suffix to append after each argument value
+ * @param separator Specifies how to separate the various arguments from each other
+ * (eg., what should go between '-f' 'file1' and '-f' 'file2'?)
+ * Default is one space character.
+ * @param spaceSeparated If true, insert a space between each individual prefix, param, and suffix
+ * @param escape If true, quote the generated argument to avoid interpretation by the shell
+ * @param format Format String used to convert each individual param within params to a String
+ * @param formatPrefix Function mapping (prefix, argumentValue) pairs to prefixes. Can be used to
+ * vary each prefix depending on the argument value (useful for tags, etc.).
+ * Default is to use the same prefix for all argument values.
+ * @return The series of command-line arguments, quoted and whitespace-delimited as requested,
+ * or an empty String if params was null/Nil/None.
+ */
+ protected def repeat(prefix: String, params: Traversable[_], suffix: String = "", separator: String = " ",
+ spaceSeparated: Boolean = true, escape: Boolean = true, format: String = "%s",
+ formatPrefix: (String, Any) => String = (prefix, value) => prefix): String = {
+ if (CollectionUtils.isNullOrEmpty(params))
+ ""
+ else
+ " %s ".format(params.filter(param => hasValue(param)).map(param => formatArgument(formatPrefix(prefix, param), param, suffix, spaceSeparated, escape, format)).mkString(separator))
+ }
+
+ /**
+ * Safely construct a series of one-token command-line arguments with quoting and space separation.
+ *
+ * @param params The collection of argument values
+ * @return The argument values quoted and space-delimited, or an empty String if params was null/Nil/None
+ */
+ protected def repeat( params: Traversable[_] ): String = {
+ repeat("", params)
+ }
+
+ /**
+ * Given an (optional) prefix, an argument value, and an (optional) suffix, formats a command-line
+ * argument with the specified level of quoting and space-separation.
+ *
+ * Helper method for required(), optional(), conditional(), and repeat() -- do not use this
+ * method directly!
+ *
+ * @param prefix Prefix to insert before the argument value (eg., "-f"). Ignored if empty/null.
+ * @param param The argument value itself. If this is Some(x), it is unwrapped to x before processing.
+ * @param suffix Suffix to append after the argument value. Ignored if empty/null.
+ * @param spaceSeparated If true, insert a space between the prefix, param, and suffix
+ * @param escape If true, quote the generated argument to avoid interpretation by the shell
+ * @param paramFormat Format string used to convert param to a String
+ * @return The combined and formatted argument, NOT surrounded by any whitespace.
+ * Returns an empty String if param was null/empty.
+ */
+ protected def formatArgument( prefix: String, param: Any, suffix: String, spaceSeparated: Boolean, escape: Boolean,
+ paramFormat: String ): String = {
+ if (CollectionUtils.isNullOrEmpty(param)) {
+ return ""
+ }
+
+ // Trim leading and trailing whitespace off our three tokens, and unwrap Some(x) to x for the param
+ val trimmedValues : Seq[String] = Seq((if ( prefix != null ) prefix.trim else ""),
+ (param match {
+ case Some(x) => paramFormat.format(x).trim
+ case x => paramFormat.format(x).trim
+ }),
+ (if ( suffix != null ) suffix.trim else ""))
+ var joinedArgument : String = null
+
+ // If the user requested space-separation, join the tokens with a space, and escape individual
+ // NON-EMPTY tokens if escaping was requested (eg., ("-f", "foo", "") -> "'-f' 'foo'")
+ if ( spaceSeparated ) {
+ joinedArgument = trimmedValues.map(x => if ( x.length > 0 && escape ) ShellUtils.escapeShellArgument(x) else x).mkString(" ").trim()
+ }
+
+ // Otherwise join the tokens without any intervening whitespace, and if quoting was requested
+ // quote the entire concatenated value (eg., ("-Xmx", "4", "G") -> "'-Xmx4G'")
+ else {
+ joinedArgument = if ( escape ) ShellUtils.escapeShellArgument(trimmedValues.mkString("")) else trimmedValues.mkString("")
+ }
+
+ // If the user requested escaping and we ended up with an empty String after joining, quote the empty
+ // String to preserve the command line token. Otherwise just return the joined argument
+ if ( joinedArgument.length == 0 && escape ) ShellUtils.escapeShellArgument(joinedArgument) else joinedArgument
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/InProcessFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/InProcessFunction.scala
new file mode 100644
index 0000000..5525eeb
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/InProcessFunction.scala
@@ -0,0 +1,48 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function
+
+import java.io.PrintStream
+
+
+/**
+ * Runs a function in process.
+ */
+trait InProcessFunction extends QFunction {
+ analysisName = this.getClass.getSimpleName
+
+ def run()
+
+ /**
+ * During run() this stream will write to the stdout.
+ */
+ var jobOutputStream: PrintStream = null
+
+ /**
+ * Write errors to this stream run().
+ */
+ var jobErrorStream: PrintStream = null
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/JavaCommandLineFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/JavaCommandLineFunction.scala
new file mode 100644
index 0000000..80027a0
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/JavaCommandLineFunction.scala
@@ -0,0 +1,139 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function
+
+import org.broadinstitute.gatk.utils.commandline.Argument
+import org.broadinstitute.gatk.utils.io.IOUtils
+import java.io.File
+
+/**
+ * Defines a command line function that runs java code.
+ */
+trait JavaCommandLineFunction extends CommandLineFunction {
+ @Argument(doc="jar", exclusiveOf="javaMainClass")
+ var jarFile: File = _
+
+ @Argument(doc="Main class to run from javaClasspath", exclusiveOf="jarFile")
+ var javaMainClass: String = _
+
+ /**
+ * Class path for the main class.
+ * Defaults to the current classpath.
+ */
+ var javaClasspath: Seq[String] = Nil
+
+ /**
+ * Memory limit for the java executable, or if None will use the default memoryLimit.
+ */
+ @Argument(doc="Java memory limit", required=false)
+ var javaMemoryLimit: Option[Double] = None
+
+ /**
+ * Max number of GC threads
+ */
+ var javaGCThreads: Option[Int] = None
+
+ /**
+ * Max percent of time spent in garbage collection
+ */
+ var javaGCTimeLimit: Option[Int] = None
+
+ /**
+ * Min percent of max heap freed during a garbage collection
+ */
+ var javaGCHeapFreeLimit: Option[Int] = None
+
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+
+ if (javaMemoryLimit.isEmpty && memoryLimit.isDefined)
+ javaMemoryLimit = memoryLimit
+
+ if (javaMainClass != null && javaClasspath.isEmpty)
+ javaClasspath = JavaCommandLineFunction.currentClasspath
+
+ if (!this.qSettings.disableDefaultJavaGCOptimizations) {
+ // By default set the GC threads to 4
+ if (javaGCThreads.isEmpty)
+ javaGCThreads = Some(4)
+
+ // By default exit if more than 50% of time in GC
+ if (javaGCTimeLimit.isEmpty)
+ javaGCTimeLimit = Some(50)
+
+ // By default exit if GC does not free up 10% of the heap
+ if (javaGCHeapFreeLimit.isEmpty)
+ javaGCHeapFreeLimit = Some(10)
+ }
+ }
+
+
+ override def copySettingsTo(function: QFunction) {
+ super.copySettingsTo(function)
+ function match {
+ case java: JavaCommandLineFunction =>
+ if (java.javaMemoryLimit.isEmpty)
+ java.javaMemoryLimit = this.javaMemoryLimit
+ if (java.javaGCThreads.isEmpty)
+ java.javaGCThreads = this.javaGCThreads
+ if (java.javaGCTimeLimit.isEmpty)
+ java.javaGCTimeLimit = this.javaGCTimeLimit
+ if (java.javaGCHeapFreeLimit.isEmpty)
+ java.javaGCHeapFreeLimit = this.javaGCHeapFreeLimit
+ case _ => /* ignore */
+ }
+ }
+
+ /**
+ * Returns the java executable to run.
+ */
+ def javaExecutable: String = {
+ if (jarFile != null)
+ required("-jar", jarFile)
+ else if (javaMainClass != null)
+ required("-cp", javaClasspath.mkString(File.pathSeparator)) +
+ required(javaMainClass)
+ else
+ null
+ }
+
+ def javaOpts = Array(
+ optional("-Xmx", javaMemoryLimit.map(gb => (gb * 1024).ceil.toInt), "m", spaceSeparated=false),
+ conditional(javaGCThreads.isDefined || javaGCTimeLimit.isDefined || javaGCHeapFreeLimit.isDefined, "-XX:+UseParallelOldGC"),
+ optional("-XX:ParallelGCThreads=", javaGCThreads, spaceSeparated=false),
+ optional("-XX:GCTimeLimit=", javaGCTimeLimit, spaceSeparated=false),
+ optional("-XX:GCHeapFreeLimit=", javaGCHeapFreeLimit, spaceSeparated=false),
+ required("-Djava.io.tmpdir=", jobTempDir, spaceSeparated=false)).mkString("")
+
+ def commandLine = required("java") +
+ javaOpts +
+ javaExecutable
+}
+
+object JavaCommandLineFunction {
+ val currentClasspath = System.getProperty("java.class.path")
+ .split(File.pathSeparatorChar).map(path => IOUtils.absolute(new File(path)).getPath).toSeq
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/ListWriterFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/ListWriterFunction.scala
new file mode 100644
index 0000000..c7450b1
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/ListWriterFunction.scala
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function
+
+import org.broadinstitute.gatk.utils.commandline.{Input, Output}
+import java.io.{PrintWriter, File}
+import org.apache.commons.io.IOUtils
+
+/**
+ * Writes a list of inputs to an output file.
+ * Custom formats can override addFile.
+ */
+class ListWriterFunction extends InProcessFunction {
+ analysisName = "WriteList"
+
+ @Input(doc="input files") var inputFiles: Seq[File] = Nil
+ @Output(doc="output file") var listFile: File = _
+
+ def run() {
+ val writer = new PrintWriter(listFile)
+ try {
+ for (inputFile <- inputFiles)
+ addFile(writer, inputFile)
+ } finally {
+ IOUtils.closeQuietly(writer)
+ }
+ }
+
+ /**
+ * Adds the inputFile to the output list.
+ * @param writer Output file.
+ * @param inputFile File to add to the output file.
+ */
+ def addFile(writer: PrintWriter, inputFile: File) {
+ writer.println(inputFile.toString)
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/QFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/QFunction.scala
new file mode 100644
index 0000000..f7e2671
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/QFunction.scala
@@ -0,0 +1,517 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function
+
+import java.io.File
+import java.lang.annotation.Annotation
+import org.broadinstitute.gatk.utils.commandline._
+import org.broadinstitute.gatk.queue.{QException, QSettings}
+import java.lang.IllegalStateException
+import org.broadinstitute.gatk.queue.util._
+import org.broadinstitute.gatk.utils.io.IOUtils
+import scala.language.reflectiveCalls
+
+/**
+ * The base interface for all functions in Queue.
+ * Inputs and outputs are specified as Sets of values.
+ * Inputs are matched to other outputs by using .equals()
+ */
+trait QFunction extends Logging with QJobReport {
+ /**
+ * A short description of what this class of function does.
+ * By default does not include the output specific to this function.
+ * See shortDescription for a description of what this instance of the function outputs.
+ */
+ var analysisName: String = "<function>"
+
+ /**
+ * The name name of the job, must be file system safe and unique to the graph.
+ * Defaults to "runName-<order_function_added>".
+ * Use shortDescription for an alternative that is display friendly.
+ */
+ var jobName: String = _
+
+ /** Default settings */
+ var qSettings: QSettings = _
+
+ /** Directory to run the command in. */
+ var commandDirectory: File = new File(".")
+
+ /** Temporary directory to write any files. Must be network accessible. */
+ var jobTempDir: File = null
+
+ /**
+ * Local path available on all machines to store LOCAL temporary files. Not an @Input,
+ * nor an @Output. Currently only used for local intermediate files for composite jobs.
+ * Needs to be an annotated field so that it's mutated during cloning.
+ */
+ @Argument(doc="Local path available on all machines to store LOCAL temporary files.")
+ var jobLocalDir: File = _
+
+ /** Order the function was added to the graph. */
+ var addOrder: Seq[Int] = Nil
+
+ /** Job priority */
+ var jobPriority: Option[Int] = None
+
+ /** Whether a job is restartable */
+ var jobRestartable = true
+
+ /**
+ * A callback for modifying the run.
+ * NOTE: This function is for ADVANCED use only and is unsupported.
+ */
+ var updateJobRun: PartialFunction[Any,Unit] = null
+
+ /**
+ * If true, unless another unfinished function is dependent on this function,
+ * this function will NOT be run even if the outputs have not been created.
+ */
+ var isIntermediate = false
+
+ // -------------------------------------------------------
+ //
+ // job run information
+ //
+ // -------------------------------------------------------
+
+ /**
+ * Copies settings from this function to another function.
+ * @param function QFunction to copy values to.
+ */
+ override def copySettingsTo(function: QFunction) {
+ function.qSettings = this.qSettings
+ function.commandDirectory = this.commandDirectory
+ function.jobTempDir = this.jobTempDir
+ function.jobLocalDir = this.jobLocalDir
+ function.addOrder = this.addOrder
+ function.jobPriority = this.jobPriority
+ function.jobRestartable = this.jobRestartable
+ function.updateJobRun = this.updateJobRun
+ function.isIntermediate = this.isIntermediate
+ function.reportGroup = this.reportGroup
+ function.reportFeatures = this.reportFeatures
+ }
+
+ /** File to redirect any output. Defaults to <jobName>.out */
+ var jobOutputFile: File = _
+
+ /** File to redirect any errors. Defaults to <jobName>.out */
+ var jobErrorFile: File = _
+
+ /** Errors (if any) from the last failed run of jobErrorFiles. */
+ @Argument(doc="Job error lines", required=false)
+ var jobErrorLines: Seq[String] = Nil
+
+ /**
+ * The number of times this function has previously been run.
+ */
+ @Argument(doc="Job retries", required=false)
+ var retries = 0
+
+ /** Change settings for the next run. Retries will be set to the number of times the function was run and jobErrorLines may contain the error text. */
+ def setupRetry() {
+ }
+
+ /**
+ * Description of this command line function.
+ */
+ def description: String = "%s: %s > %s".format(analysisName, inputs, outputs)
+
+ /**
+ * A short description of the function.
+ */
+ def shortDescription = {
+ firstOutput match {
+ case file: File => analysisName + ": " + file.getName
+ case _ => analysisName
+ }
+ }
+
+ /**
+ * The name of the job as submitted to the job runner
+ */
+ def jobRunnerJobName = shortDescription
+
+ /**
+ * Returns true if the function is done.
+ */
+ def isDone: Boolean = {
+ val files = doneOutputs
+ if (files.size == 0)
+ throw new IllegalStateException("Function should have at least one output: " + analysisName)
+ files.forall(_.exists)
+ }
+
+ /**
+ * Returns true if the function has failed.
+ */
+ def isFail: Boolean = {
+ val files = failOutputs
+ if (files.size == 0)
+ throw new IllegalStateException("Function should have at least one output: " + analysisName)
+ files.exists(_.exists)
+ }
+
+ /**
+ * Returns files to track for hidden done/fail files.
+ * @return Seq[String] files.
+ */
+ protected def statusPaths = {
+ var paths = outputs
+ paths :+= jobOutputFile
+ if (jobErrorFile != null)
+ paths :+= jobErrorFile
+ paths
+ }
+
+ /**
+ * Returns prefixes for hidden done/fail files.
+ * @return prefixes.
+ */
+ private def statusPrefixes = statusPaths.
+ filter(file => !IOUtils.isSpecialFile(file)).
+ map(file => file.getParentFile + "/." + file.getName)
+
+ /**
+ * Returns the output files for this function.
+ * @return outputs for this function.
+ */
+ def doneOutputs: Seq[File] = statusPrefixes.map(path => new File(path + ".done"))
+
+ /**
+ * Returns the output files for this function.
+ * @return outputs for this function.
+ */
+ def failOutputs: Seq[File] = statusPrefixes.map(path => new File(path + ".fail"))
+
+ /** The complete list of fields on this CommandLineFunction. */
+ def functionFields: Seq[ArgumentSource] = ClassFieldCache.classFunctionFields(this.functionFieldClass)
+ /** The @Input fields on this CommandLineFunction. */
+ def inputFields: Seq[ArgumentSource] = ClassFieldCache.classInputFields(this.functionFieldClass)
+ /** The @Output fields on this CommandLineFunction. */
+ def outputFields: Seq[ArgumentSource] = ClassFieldCache.classOutputFields(this.functionFieldClass)
+ /** The @Argument fields on this CommandLineFunction. */
+ def argumentFields: Seq[ArgumentSource] = ClassFieldCache.classArgumentFields(this.functionFieldClass)
+
+ /**
+ * Returns the class that should be used for looking up fields.
+ */
+ protected def functionFieldClass = this.getClass
+
+ /**
+ * Returns the input files for this function.
+ * @return inputs for this function.
+ */
+ def inputs: Seq[File] = getFieldFiles(inputFields)
+
+ /**
+ * Returns the output files for this function.
+ * @return outputs for this function.
+ */
+ def outputs: Seq[File] = getFieldFiles(outputFields)
+
+ /**
+ * Returns the first output file.
+ * @return first output for this function.
+ */
+ def firstOutput: File = outputs.headOption.getOrElse(null)
+
+ /**
+ * Returns the set of directories where files may be written.
+ */
+ def outputDirectories = {
+ var dirs = Set.empty[File]
+ dirs += commandDirectory
+ dirs += jobTempDir
+ dirs += jobLocalDir
+ dirs += jobOutputFile.getParentFile
+ if (jobErrorFile != null)
+ dirs += jobErrorFile.getParentFile
+ dirs ++= outputs.map(_.getParentFile)
+ dirs
+ }
+
+ /**
+ * Deletes the log files for this function.
+ */
+ def deleteLogs() = {
+ IOUtils.tryDelete(jobOutputFile)
+ if (jobErrorFile != null)
+ IOUtils.tryDelete(jobErrorFile)
+ }
+
+ /**
+ * Deletes the output files and all the status files for this function.
+ */
+ def deleteOutputs() {
+ outputs.filter(file => !IOUtils.isSpecialFile(file)).foreach(file => IOUtils.tryDelete(file))
+ doneOutputs.foreach(file => IOUtils.tryDelete(file))
+ failOutputs.foreach(file => IOUtils.tryDelete(file))
+ }
+
+ /**
+ * Creates the output directories for this function if it doesn't exist.
+ */
+ def mkOutputDirectories() {
+ outputDirectories.foreach(dir => {
+ if (!dir.exists && !dir.mkdirs)
+ throw new QException("Unable to create directory: " + dir)
+ })
+ }
+
+ /**
+ * Returns fields that do not have values which are required.
+ * @return Seq[String] names of fields missing values.
+ */
+ def missingFields: Seq[String] = {
+ val missingInputs = missingFields(inputFields, classOf[Input])
+ val missingOutputs = missingFields(outputFields, classOf[Output])
+ val missingArguments = missingFields(argumentFields, classOf[Argument])
+ (missingInputs ++ missingOutputs ++ missingArguments).distinct.sorted
+ }
+
+ /**
+ * Returns fields that do not have values which are required.
+ * @param sources Fields to check.
+ * @param annotation Annotation.
+ * @return names of fields missing values.
+ */
+ private def missingFields(sources: Seq[ArgumentSource], annotation: Class[_ <: Annotation]): Seq[String] = {
+ var missing: Seq[String] = Nil
+ for (source <- sources) {
+ if (isRequired(source, annotation))
+ if (!hasFieldValue(source))
+ if (!exclusiveOf(source, annotation).exists(otherSource => hasFieldValue(otherSource)))
+ missing :+= "@%s: %s - %s".format(annotation.getSimpleName, source.field.getName, doc(source, annotation))
+ }
+ missing
+ }
+
+ /**
+ * Gets the files from the fields. The fields must be a File, a FileExtension, or a Seq or Set of either.
+ * @param fields Fields to get files.
+ * @return for the fields.
+ */
+ private def getFieldFiles(fields: Seq[ArgumentSource]): Seq[File] = {
+ var files: Seq[File] = Nil
+ for (field <- fields)
+ files ++= getFieldFiles(field)
+ files.distinct
+ }
+
+ /**
+ * Gets the files from the field. The field must be a File, a FileExtension, or a Seq or Set of either.
+ * @param field Field to get files.
+ * @return for the field.
+ */
+ def getFieldFiles(field: ArgumentSource): Seq[File] = {
+ var files: Seq[File] = Nil
+ CollectionUtils.foreach(getFieldValue(field), (fieldValue) => {
+ val file = fieldValueToFile(field, fieldValue)
+ if (file != null)
+ files :+= file
+ })
+ files.distinct
+ }
+
+ /**
+ * Gets the file from the field. The field must be a File or a FileExtension and not a Seq or Set.
+ * @param field Field to get the file.
+ * @return for the field.
+ */
+ def getFieldFile(field: ArgumentSource): File =
+ fieldValueToFile(field, getFieldValue(field))
+
+ /**
+ * Converts the field value to a file. The field must be a File or a FileExtension.
+ * @param field Field to get the file.
+ * @param value Value of the File or FileExtension or null.
+ * @return Null if value is null, otherwise the File.
+ * @throws QException if the value is not a File or FileExtension.
+ */
+ private def fieldValueToFile(field: ArgumentSource, value: Any): File = value match {
+ case file: File => file
+ case null => null
+ case unknown => throw new QException("Non-file found. Try removing the annotation, change the annotation to @Argument, or extend File with FileExtension: %s: %s".format(field.field, unknown))
+ }
+
+ /**
+ * After a function is frozen no more updates are allowed by the user.
+ * The function is allow to make necessary updates internally to make sure
+ * the inputs and outputs will be equal to other inputs and outputs.
+ */
+ final def freeze() {
+ freezeFieldValues()
+ canonFieldValues()
+ }
+
+ /**
+ * Sets all field values.
+ */
+ def freezeFieldValues() {
+ if (jobName == null)
+ jobName = qSettings.runName + "-" + this.addOrder.mkString("-")
+
+ if (jobOutputFile == null) {
+ /*If the outputFile has been set to an absolute path, respect that.
+ Otherwise, place it in (possibly a subdirectory of) the log directory
+ The relative case is first as it's arguably the most common condition
+ */
+ jobOutputFile = firstOutput match {
+ case file: File if !IOUtils.isSpecialFile(file) && !file.isAbsolute =>
+ val logDir : File = if (file.getParentFile == null) qSettings.logDirectory else new File(qSettings.logDirectory, file.getParent)
+ new File(logDir, file.getName + ".out")
+
+ case file: File if !IOUtils.isSpecialFile(file) && file.isAbsolute =>
+ new File(file.getParentFile, file.getName + ".out")
+
+ case _ =>
+ new File(qSettings.logDirectory, jobName + ".out")
+ }
+ }
+
+ if (jobTempDir == null)
+ jobTempDir = qSettings.tempDirectory
+
+ if (jobLocalDir == null)
+ jobLocalDir = jobTempDir
+
+ if (jobPriority.isEmpty)
+ jobPriority = qSettings.jobPriority
+
+ // Do not set the temp and local dir relative to the command directory
+ jobTempDir = IOUtils.absolute(jobTempDir)
+ jobLocalDir = IOUtils.absolute(jobLocalDir)
+
+ absoluteCommandDirectory()
+ }
+
+ /**
+ * If the command directory is relative, insert the run directory ahead of it.
+ */
+ def absoluteCommandDirectory() {
+ commandDirectory = IOUtils.absolute(qSettings.runDirectory, commandDirectory)
+ }
+
+ /**
+ * Makes all field values canonical so that the graph can match the
+ * inputs of one function to the output of another using equals().
+ */
+ def canonFieldValues() {
+ for (field <- this.functionFields) {
+ var fieldValue = this.getFieldValue(field)
+ fieldValue = CollectionUtils.updated(fieldValue, canon).asInstanceOf[AnyRef]
+ this.setFieldValue(field, fieldValue)
+ }
+
+ this.jobOutputFile = canon(this.jobOutputFile).asInstanceOf[File]
+ if (this.jobErrorFile != null)
+ this.jobErrorFile = canon(this.jobErrorFile).asInstanceOf[File]
+ }
+
+ /**
+ * Set value to a uniform value across functions.
+ * Base implementation changes any relative path to an absolute path.
+ * @param value to be updated
+ * @return the modified value, or a copy if the value is immutable
+ */
+ protected def canon(value: Any) = {
+ value match {
+ case file: File => IOUtils.absolute(commandDirectory, file)
+ case x => x
+ }
+ }
+
+ /**
+ * Scala sugar type for checking annotation required and exclusiveOf.
+ */
+ private type ArgumentAnnotation = {
+ def required(): Boolean
+ def exclusiveOf(): String
+ def doc(): String
+ }
+
+ /**
+ * Returns the isRequired value from the field.
+ * @param field Field to check.
+ * @param annotation Annotation.
+ * @return the isRequired value from the field annotation.
+ */
+ private def isRequired(field: ArgumentSource, annotation: Class[_ <: Annotation]) =
+ ReflectionUtils.getAnnotation(field.field, annotation).asInstanceOf[ArgumentAnnotation].required()
+
+ /**
+ * Returns an array of ArgumentSources from functionFields listed in the exclusiveOf of the original field
+ * @param field Field to check.
+ * @param annotation Annotation.
+ * @return the Array[ArgumentSource] that may be set instead of the field.
+ */
+ private def exclusiveOf(field: ArgumentSource, annotation: Class[_ <: Annotation]) =
+ ReflectionUtils.getAnnotation(field.field, annotation).asInstanceOf[ArgumentAnnotation].exclusiveOf()
+ .split(",").map(_.trim).filter(_.length > 0)
+ .map(fieldName => functionFields.find(fieldName == _.field.getName) match {
+ case Some(x) => x
+ case None => throw new QException("Unable to find exclusion field %s on %s".format(fieldName, this.getClass.getSimpleName))
+ })
+
+ /**
+ * Returns the doc value from the field.
+ * @param field Field to check.
+ * @param annotation Annotation.
+ * @return the doc value from the field annotation.
+ */
+ private def doc(field: ArgumentSource, annotation: Class[_ <: Annotation]) =
+ ReflectionUtils.getAnnotation(field.field, annotation).asInstanceOf[ArgumentAnnotation].doc()
+
+ /**
+ * Returns true if the field has a value.
+ * @param source Field to check for a value.
+ * @return true if the field has a value.
+ */
+ protected def hasFieldValue(source: ArgumentSource) = this.hasValue(this.getFieldValue(source))
+
+ /**
+ * Returns false if the value is null or an empty collection.
+ * @param param Value to test for null, or a collection to test if it is empty.
+ * @return false if the value is null, or false if the collection is empty, otherwise true.
+ */
+ protected def hasValue(param: Any) = CollectionUtils.isNotNullOrNotEmpty(param)
+
+ /**
+ * Gets the value of a field.
+ * @param source Field to get the value for.
+ * @return value of the field.
+ */
+ def getFieldValue(source: ArgumentSource) = ClassFieldCache.getFieldValue(this, source)
+
+ /**
+ * Gets the value of a field.
+ * @param source Field to set the value for.
+ * @return value of the field.
+ */
+ def setFieldValue(source: ArgumentSource, value: Any) = ClassFieldCache.setFieldValue(this, source, value)
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/RetryMemoryLimit.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/RetryMemoryLimit.scala
new file mode 100644
index 0000000..9202c2a
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/RetryMemoryLimit.scala
@@ -0,0 +1,103 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function
+
+import org.broadinstitute.gatk.utils.commandline.Argument
+
+object RetryMemoryLimit {
+ private val defaultRetryMemoryFunction: (Double => Double) = ( 2 * _ )
+ private val defaultMemoryLimitErrorText = Seq("OutOfMemory", "you did not provide enough memory", "TERM_MEMLIMIT")
+}
+
+/** A mixin that on retry increases the memory limit when certain text is found. */
+trait RetryMemoryLimit extends CommandLineFunction {
+
+ /** How to increase the memory. By default doubles the memory. */
+ var retryMemoryFunction: (Double => Double) = RetryMemoryLimit.defaultRetryMemoryFunction
+
+ /** Once the threshold is passed, no more memory will be added to memory limit. */
+ @Argument(doc="threshold to stop doubling the memory", required=false)
+ var memoryLimitThreshold: Option[Double] = None
+
+ /** Various strings to look for to determine we ran out of memory. */
+ @Argument(doc="text to look for in the errors", required = false)
+ var memoryLimitErrorText = RetryMemoryLimit.defaultMemoryLimitErrorText
+
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+ if (this.memoryLimitThreshold.isEmpty)
+ this.memoryLimitThreshold = this.qSettings.memoryLimitThreshold
+ }
+
+
+ override def copySettingsTo(function: QFunction) {
+ super.copySettingsTo(function)
+ function match {
+ case retryMemoryLimit: RetryMemoryLimit =>
+ if (retryMemoryLimit.memoryLimitThreshold.isEmpty)
+ retryMemoryLimit.memoryLimitThreshold = this.memoryLimitThreshold
+ if (retryMemoryLimit.retryMemoryFunction == RetryMemoryLimit.defaultRetryMemoryFunction)
+ retryMemoryLimit.retryMemoryFunction = this.retryMemoryFunction
+ if (retryMemoryLimit.memoryLimitErrorText == RetryMemoryLimit.defaultMemoryLimitErrorText)
+ retryMemoryLimit.memoryLimitErrorText = this.memoryLimitErrorText
+ case _ => /* ignore */
+ }
+ }
+
+ override def setupRetry() {
+ super.setupRetry()
+ if (this.memoryLimitThreshold.isDefined && this.memoryLimit.isDefined) {
+
+ // NOTE: If we're already at or above the memoryLimit, don't do anything.
+ if (this.memoryLimit.get < this.memoryLimitThreshold.get) {
+ updateMemoryLimits()
+ }
+
+ } else {
+ updateMemoryLimits()
+ }
+ }
+
+ def updateMemoryLimits() {
+ if (isMemoryError) {
+ this.memoryLimit = this.memoryLimit.map(this.retryMemoryFunction)
+ this.residentRequest = this.residentRequest.map(this.retryMemoryFunction)
+ this.residentLimit = this.residentLimit.map(this.retryMemoryFunction)
+
+ // Rebuffer the memory limit if the limit was set exactly to the request
+ if (this.residentLimit == this.residentRequest)
+ this.residentLimit = this.residentRequest.map(this.residentLimitBuffer)
+
+ this match {
+ case java: JavaCommandLineFunction =>
+ java.javaMemoryLimit = java.javaMemoryLimit.map(this.retryMemoryFunction)
+ case _ => /* ignore */
+ }
+ }
+ }
+
+ def isMemoryError = this.jobErrorLines.exists(line => this.memoryLimitErrorText.exists(error => line.contains(error)))
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/CloneFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/CloneFunction.scala
new file mode 100644
index 0000000..ccc9dcf
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/CloneFunction.scala
@@ -0,0 +1,111 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function.scattergather
+
+import org.broadinstitute.gatk.utils.commandline.ArgumentSource
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.queue.util.ClassFieldCache
+
+/**
+ * Shadow clones another command line function.
+ */
+object CloneFunction {
+ private lazy val cloneFunctionFields = ClassFieldCache.classFunctionFields(classOf[CloneFunction])
+}
+
+class CloneFunction extends CommandLineFunction {
+ var originalFunction: ScatterGatherableFunction = _
+ var cloneIndex: Int = _
+ var cloneCount: Int = _
+
+ private var overriddenFields = Map.empty[ArgumentSource, Any]
+ private var withScatterPartCount = 0
+
+ private def withScatterPart[A](f: () => A): A = {
+ var originalValues = Map.empty[ArgumentSource, Any]
+ withScatterPartCount += 1
+ if (withScatterPartCount == 1) {
+ originalFunction.functionFields.foreach {
+ case (field) => {
+ originalValues += field -> originalFunction.getFieldValue(field)
+ originalFunction.setFieldValue(field, getFieldValue(field))
+ }
+ }
+ }
+ try {
+ f()
+ } finally {
+ if (withScatterPartCount == 1) {
+ originalFunction.functionFields.foreach {
+ case (field) => {
+ setFieldValue(field, originalFunction.getFieldValue(field))
+ originalFunction.setFieldValue(field, originalValues(field))
+ }
+ }
+ }
+ withScatterPartCount -= 1
+ }
+ }
+
+ override def description = withScatterPart(() => originalFunction.description)
+ override def shortDescription = withScatterPart(() => originalFunction.shortDescription)
+ override def setupRetry() { withScatterPart(() => originalFunction.setupRetry()) }
+
+ override protected def functionFieldClass = originalFunction.getClass
+
+ def commandLine = withScatterPart(() => originalFunction.commandLine)
+
+ def getFieldValue(field: String): AnyRef = {
+ val source = ClassFieldCache.findField(originalFunction.getClass, field)
+ getFieldValue(source)
+ }
+
+ override def getFieldValue(source: ArgumentSource): AnyRef = {
+ CloneFunction.cloneFunctionFields.find(_.field.getName == source.field.getName) match {
+ case Some(cloneSource) =>
+ super.getFieldValue(cloneSource)
+ case None =>
+ overriddenFields.get(source) match {
+ case Some(value) =>
+ value.asInstanceOf[AnyRef]
+ case None => {
+ val value = originalFunction.getFieldValue(source)
+ overriddenFields += source -> value
+ value
+ }
+ }
+ }
+ }
+
+ def setFieldValue(field: String, value: Any) {
+ val source = ClassFieldCache.findField(originalFunction.getClass, field)
+ setFieldValue(source, value)
+ }
+
+ override def setFieldValue(source: ArgumentSource, value: Any) {
+ overriddenFields += source -> value
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/ConcatenateLogsFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/ConcatenateLogsFunction.scala
new file mode 100644
index 0000000..b97cee1
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/ConcatenateLogsFunction.scala
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function.scattergather
+
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+import org.broadinstitute.gatk.queue.QException
+import org.broadinstitute.gatk.utils.commandline.Input
+import org.apache.commons.io.FileUtils
+import java.io.File
+import collection.JavaConversions._
+
+/**
+ * Concatenate log files to the jobOutputFile.
+ */
+class ConcatenateLogsFunction extends InProcessFunction {
+ analysisName = "Concat"
+
+ @Input(doc="Parts to gather back into the original output")
+ var logs: Seq[File] = Nil
+
+ override def description = "%s: %s > %s".format(analysisName, logs, jobOutputFile)
+ override def shortDescription = analysisName + ": " + jobOutputFile.getName
+
+ def run() {
+ val missing = org.broadinstitute.gatk.utils.io.IOUtils.waitFor(logs, 120)
+ if (!missing.isEmpty)
+ throw new QException("Unable to find log: " + missing.mkString(", "))
+ logs.foreach(log => {
+ FileUtils.copyFile(log, this.jobOutputStream)
+ this.jobOutputStream.println()
+ })
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/GatherFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/GatherFunction.scala
new file mode 100644
index 0000000..7044265
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/GatherFunction.scala
@@ -0,0 +1,72 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function.scattergather
+
+import java.io.File
+import org.broadinstitute.gatk.utils.commandline.{Input, Output}
+import org.broadinstitute.gatk.queue.function.QFunction
+import org.broadinstitute.gatk.queue.QException
+import org.broadinstitute.gatk.utils.io.IOUtils
+import collection.JavaConversions._
+
+/**
+ * Base class for Gather command line functions.
+ */
+trait GatherFunction extends QFunction {
+ analysisName = "Gather"
+
+ var originalFunction: ScatterGatherableFunction = _
+
+ @Output(doc="The original output of the scattered function")
+ var originalOutput: File = _
+
+ @Input(doc="Parts to gather back into the original output")
+ var gatherParts: Seq[File] = Nil
+
+ /**
+ * Called to initialize the gather function values after all other values have been setup for this function.
+ */
+ def init() {}
+
+ /**
+ * Don't include this @Gather's log file when tracking .done.
+ * The done files for original log file being produced will do.
+ *
+ * The logs from the scatter/gather jobs are concatenated together into the original log.
+ * Without removing the logs a .done file would be created for the logs. If a SGF is switched
+ * from scatterCount=1 to >1 then this Gather would be "missing" its logs and re-run.
+ */
+ override protected def statusPaths = outputs
+
+ /**
+ * Waits for gather parts to propagate over NFS or throws an exception.
+ */
+ protected def waitForGatherParts() {
+ val missing = IOUtils.waitFor(gatherParts, 120)
+ if (!missing.isEmpty)
+ throw new QException("Unable to find gather inputs: " + missing.mkString(", "))
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/GathererFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/GathererFunction.scala
new file mode 100644
index 0000000..4fcc19f
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/GathererFunction.scala
@@ -0,0 +1,44 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function.scattergather
+
+import org.broadinstitute.gatk.utils.commandline.Gatherer
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+import collection.JavaConversions._
+
+/**
+ * Runs a Gatherer in process.
+ */
+class GathererFunction(gathererClass: Class[_ <: Gatherer]) extends InProcessFunction with GatherFunction {
+ analysisName = this.gathererClass.getSimpleName
+
+ def run() {
+ val gatherer = gathererClass.newInstance
+ if (gatherer.waitForInputs)
+ waitForGatherParts()
+ gatherer.gather(this.gatherParts, this.originalOutput)
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/ScatterFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/ScatterFunction.scala
new file mode 100644
index 0000000..29f8c41
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/ScatterFunction.scala
@@ -0,0 +1,78 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function.scattergather
+
+import java.io.File
+import org.broadinstitute.gatk.utils.commandline.Input
+import org.broadinstitute.gatk.queue.function.QFunction
+
+/**
+ * Base class for Scatter functions.
+ */
+trait ScatterFunction extends QFunction {
+ analysisName = "Scatter"
+
+ var originalFunction: ScatterGatherableFunction = _
+
+ @Input(doc="Original inputs to scatter")
+ var originalInputs: Set[File] = _
+
+ override def shortDescription = analysisName + ": %s ...".format(firstOutput.getName)
+
+ /**
+ * Called to initialize scatter function values after all other values have been setup for this function.
+ */
+ def init() {}
+
+ /**
+ * Returns true if the scatter function can scatter this original function.
+ * @return true if the scatter function can scatter this original function.
+ */
+ def isScatterGatherable = true
+
+ /**
+ * Returns the number of clones that should be created.
+ */
+ def scatterCount: Int = originalFunction.scatterCount
+
+ /**
+ * Initializes the input fields for the clone function.
+ * The input values should be set to their defaults
+ * and may be changed by the user.
+ * @param cloneFunction CloneFunction to initialize.
+ * @param index The one based scatter index.
+ */
+ def initCloneInputs(cloneFunction: CloneFunction, index: Int) {}
+
+ /**
+ * Binds the input fields for the clone function to this scatter function.
+ * The input values should be set to their absolute values and added
+ * to scatter parts.
+ * @param cloneFunction CloneFunction to bind.
+ * @param index The one based scatter index.
+ */
+ def bindCloneInputs(cloneFunction: CloneFunction, index: Int) {}
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/ScatterGatherableFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/ScatterGatherableFunction.scala
new file mode 100644
index 0000000..50ad3cf
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/ScatterGatherableFunction.scala
@@ -0,0 +1,376 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function.scattergather
+
+import java.io.File
+import org.broadinstitute.gatk.queue.util._
+import org.broadinstitute.gatk.utils.commandline.{Gatherer, Gather, ArgumentSource}
+import org.broadinstitute.gatk.queue.function.{QFunction, CommandLineFunction}
+import org.broadinstitute.gatk.queue.QException
+import org.broadinstitute.gatk.utils.io.IOUtils
+import collection.immutable.ListMap
+
+/**
+ * A function that can be run faster by splitting it up into pieces and then joining together the results.
+ */
+trait ScatterGatherableFunction extends CommandLineFunction {
+
+ /** Maximum number of parts to scatter the function into. */
+ var scatterCount: Int = 1
+
+ /** scatter gather directory */
+ var scatterGatherDirectory: File = _
+
+ /** Class to use for scattering. Defaults to the annotation used in the @Scatter tag. */
+ var scatterClass: Class[_ <: ScatterFunction] = _
+
+ /**
+ * Function that returns the class to use for gathering a directory. If it returns null then @Gather annotation will be used.
+ * PartialFunction param gatherField Field that is to be gathered.
+ * @return The class of the GatherFunction to be used or null.
+ */
+ var gatherClass: PartialFunction[ArgumentSource, Class[_ <: GatherFunction]] = _
+
+ /**
+ * Allows external modification of the ScatterFunction that will create the scatter pieces in the temporary directories.
+ * PartialFunction param scatterFunction The function that will create the scatter pieces in the temporary directories.
+ */
+ var setupScatterFunction: PartialFunction[ScatterFunction, Unit] = _
+
+ /**
+ * Allows external modification of the GatherFunction that will collect the gather pieces in the temporary directories.
+ * PartialFunction param gatherFunction The function that will merge the gather pieces from the temporary directories.
+ * PartialFunction param gatherField The output field being gathered.
+ */
+ var setupGatherFunction: PartialFunction[(GatherFunction, ArgumentSource), Unit] = _
+
+ /**
+ * Allows external modification of the cloned function.
+ * PartialFunction param cloneFunction A clone wrapper of this ScatterGatherableFunction
+ * PartialFunction param index The one based index (from 1..scatterCount inclusive) of the scatter piece.
+ */
+ var setupCloneFunction: PartialFunction[(CloneFunction, Int), Unit] = _
+
+ /**
+ * Returns true if the function is ready to be scatter / gathered.
+ * The base implementation checks if the scatter count is greater than one,
+ * and that the scatter function can scatter this instance.
+ * @return true if the function is ready to be scatter / gathered.
+ */
+ def scatterGatherable = this.scatterCount > 1 && scatterFunction.isScatterGatherable
+
+ /**
+ * Sets the scatter gather directory to the command directory if it is not already set.
+ */
+ override def freezeFieldValues() {
+ super.freezeFieldValues()
+
+ if (this.scatterGatherDirectory == null) {
+ if (qSettings.jobScatterGatherDirectory != null) {
+ this.scatterGatherDirectory = IOUtils.absolute(qSettings.jobScatterGatherDirectory)
+ } else {
+ this.scatterGatherDirectory = IOUtils.absolute(this.commandDirectory, ".queue/scatterGather")
+ }
+ }
+ }
+
+ /**
+ * The scatter function.
+ */
+ private lazy val scatterFunction = {
+ // Only depend on input fields that have a value
+ val inputFieldsWithValues = this.inputFields.filter(hasFieldValue(_))
+ val inputFiles = inputFieldsWithValues.flatMap(getFieldFiles(_)).toSet
+
+ val scatterFunction = newScatterFunction()
+ this.copySettingsTo(scatterFunction)
+ scatterFunction.originalFunction = this
+ scatterFunction.originalInputs = inputFiles
+ scatterFunction.commandDirectory = this.scatterGatherCommandDir("scatter")
+ scatterFunction.jobOutputFile = new File("scatter.out")
+ scatterFunction.addOrder = this.addOrder :+ 1
+ scatterFunction.isIntermediate = true
+
+ initScatterFunction(scatterFunction)
+ scatterFunction.absoluteCommandDirectory()
+ scatterFunction.init()
+ scatterFunction
+ }
+
+ /**
+ * Returns a list of scatter / gather and clones of this function
+ * that can be run in parallel to produce the same output as this
+ * command line function.
+ * @return Seq[QFunction] to run instead of this function.
+ */
+ def generateFunctions() = {
+ // Ask the scatter function how many clones to create.
+ val numClones = scatterFunction.scatterCount
+
+ // Create the gather functions for each output field
+ var gatherFunctions = ListMap.empty[ArgumentSource, GatherFunction]
+ var gatherOutputs = ListMap.empty[ArgumentSource, File]
+ var gatherAddOrder = numClones + 2
+
+ // Only track fields that will have an output file
+ val outputFieldsWithValues = this.outputFields.
+ filter(hasFieldValue(_)).
+ filter(gatherField => !IOUtils.isSpecialFile(getFieldFile(gatherField)))
+
+ for (gatherField <- outputFieldsWithValues) {
+ gatherOutputs += gatherField -> getFieldFile(gatherField)
+ }
+
+ // Only gather fields that are @Gather(enabled=true)
+ val outputFieldsWithGathers = outputFieldsWithValues.filter(hasGatherFunction(_))
+
+ for (gatherField <- outputFieldsWithGathers) {
+ val gatherOutput = gatherOutputs(gatherField)
+
+ val gatherFunction = this.newGatherFunction(gatherField)
+ this.copySettingsTo(gatherFunction)
+ gatherFunction.originalFunction = this
+ gatherFunction.originalOutput = gatherOutput
+ gatherFunction.commandDirectory = this.scatterGatherCommandDir("gather-" + gatherField.field.getName)
+ gatherFunction.jobOutputFile = new File("gather-" + gatherOutput.getName + ".out")
+ gatherFunction.addOrder = this.addOrder :+ gatherAddOrder
+
+ initGatherFunction(gatherFunction, gatherField)
+ gatherFunction.absoluteCommandDirectory()
+ gatherFunction.init()
+
+ gatherFunctions += gatherField -> gatherFunction
+
+ gatherAddOrder += 1
+ }
+
+ // Create the clone functions for running the parallel jobs
+ var cloneFunctions = Seq.empty[CloneFunction]
+ val dirFormat = "temp_%%0%dd_of_%d".format(numClones.toString.length(), numClones)
+ for (i <- 1 to numClones) {
+ val cloneFunction = this.newCloneFunction()
+
+ this.copySettingsTo(cloneFunction)
+ cloneFunction.originalFunction = this
+ cloneFunction.analysisName = this.analysisName
+ cloneFunction.cloneIndex = i
+ cloneFunction.cloneCount = numClones
+ cloneFunction.commandDirectory = this.scatterGatherCommandDir(dirFormat.format(i))
+ cloneFunction.jobOutputFile = if (IOUtils.isSpecialFile(this.jobOutputFile)) this.jobOutputFile else new File(this.jobOutputFile.getName)
+ if (this.jobErrorFile != null)
+ cloneFunction.jobErrorFile = if (IOUtils.isSpecialFile(this.jobErrorFile)) this.jobErrorFile else new File(this.jobErrorFile.getName)
+ // jic the "local" dir is actually on the network, create different sub local directories for each clone.
+ // This might be better handled with a hook that allows clones to create unique file names. Right now no hook
+ // like freezeFieldValues exists for specifying per cloneFunction fields.
+ cloneFunction.jobLocalDir = this.scatterGatherLocalDir(dirFormat.format(i))
+ cloneFunction.addOrder = this.addOrder :+ (i+1)
+ cloneFunction.isIntermediate = true
+
+ // Setup the fields on the clone function, outputting each as a relative file in the sg directory.
+ scatterFunction.initCloneInputs(cloneFunction, i)
+ for (gatherField <- outputFieldsWithValues) {
+ val gatherPart = new File(gatherOutputs(gatherField).getName)
+ cloneFunction.setFieldValue(gatherField, gatherPart)
+ }
+
+ // Allow the script writer to change the paths to the files.
+ initCloneFunction(cloneFunction, i)
+
+ // If the command directory is relative, insert the run directory ahead of it.
+ cloneFunction.absoluteCommandDirectory()
+
+ // Allow the scatter function to set the specific input for this clone
+ scatterFunction.bindCloneInputs(cloneFunction, i)
+
+ // Set each of the clone outputs to be absolute paths.
+ for (gatherField <- outputFieldsWithValues) {
+ val gatherPart = IOUtils.absolute(cloneFunction.commandDirectory, cloneFunction.getFieldFile(gatherField))
+ cloneFunction.setFieldValue(gatherField, gatherPart)
+ }
+
+ // For the outputs that are being gathered add this clone's output to be gathered.
+ for (gatherField <- outputFieldsWithGathers) {
+ gatherFunctions(gatherField).gatherParts :+= cloneFunction.getFieldFile(gatherField)
+ }
+
+ cloneFunctions :+= cloneFunction
+ }
+
+ // Track the functions starting with the scatter function.
+ var functions: Seq[QFunction] = Seq(scatterFunction) ++ cloneFunctions ++ gatherFunctions.values
+
+ // Make all log file paths absolute.
+ for (function <- functions) {
+ function.jobOutputFile = IOUtils.absolute(function.commandDirectory, function.jobOutputFile)
+ if (function.jobErrorFile != null)
+ function.jobErrorFile = IOUtils.absolute(function.commandDirectory, function.jobErrorFile)
+ }
+
+ val jobOutputGather = gatherLogFile(_.jobOutputFile, functions, gatherAddOrder)
+ if (this.jobErrorFile != null) {
+ val jobErrorGather = gatherLogFile(_.jobErrorFile, functions, gatherAddOrder + 1)
+ functions :+= jobErrorGather
+ }
+ functions :+= jobOutputGather
+
+ // Return all the various created functions.
+ functions
+ }
+
+ /**
+ * Creates a new ScatterFunction.
+ * @return A ScatterFunction instantiated scatterClass
+ */
+ protected def newScatterFunction(): ScatterFunction = {
+ if (this.scatterClass == null)
+ throw new QException("scatterClass is null.")
+ this.scatterClass.newInstance.asInstanceOf[ScatterFunction]
+ }
+
+ /**
+ * Initializes the ScatterFunction created by newScatterFunction() that will create the scatter pieces in the temporary directories.
+ * Calls setupScatterFunction with scatterFunction.
+ * @param scatterFunction The function that will create the scatter pieces in the temporary directories.
+ */
+ protected def initScatterFunction(scatterFunction: ScatterFunction) {
+ if (this.setupScatterFunction != null)
+ if (this.setupScatterFunction.isDefinedAt(scatterFunction))
+ this.setupScatterFunction(scatterFunction)
+ }
+
+ /**
+ * Returns true if the field should be gathered.
+ * @param gatherField Field that defined @Gather.
+ * @return true if the field should be gathered.
+ */
+ protected def hasGatherFunction(gatherField: ArgumentSource) : Boolean = {
+ // Check if there is a function that will return the gather class for this field.
+ if (this.gatherClass != null && this.gatherClass.isDefinedAt(gatherField))
+ true
+
+ // Check for an annotation defining the gather class.
+ else if (ReflectionUtils.hasAnnotation(gatherField.field, classOf[Gather]))
+ ReflectionUtils.getAnnotation(gatherField.field, classOf[Gather]).enabled
+
+ // Nothing else to disable this field.
+ else
+ true
+ }
+
+ /**
+ * Creates a new GatherFunction for the gatherField.
+ * @param gatherField Field that defined @Gather.
+ * @return A GatherFunction instantiated from @Gather.
+ */
+ protected def newGatherFunction(gatherField: ArgumentSource) : GatherFunction = {
+ var gatherClass: Class[_] = null
+
+ // Check if there is a function that will return the gather class for this field.
+ if (this.gatherClass != null)
+ if (this.gatherClass.isDefinedAt(gatherField))
+ gatherClass = this.gatherClass(gatherField)
+
+ // Check for an annotation defining the gather class.
+ if (gatherClass == null) {
+ if (ReflectionUtils.hasAnnotation(gatherField.field, classOf[Gather])) {
+ gatherClass = ReflectionUtils.getAnnotation(gatherField.field, classOf[Gather]).value
+ } else {
+ throw new QException("Missing @Gather annotation on %s".format(gatherField.field))
+ }
+ }
+
+ if (gatherClass == classOf[GatherFunction]) {
+ throw new QException("@Gather did not specify class type on %s".format(gatherField.field))
+ } else if (classOf[GatherFunction].isAssignableFrom(gatherClass)) {
+ gatherClass.newInstance.asInstanceOf[GatherFunction]
+ } else if (classOf[Gatherer].isAssignableFrom(gatherClass)) {
+ new GathererFunction(gatherClass.asSubclass(classOf[Gatherer]))
+ } else {
+ throw new QException("Unsupported @Gather class type on %s: %s".format(gatherField.field, gatherClass))
+ }
+ }
+
+ /**
+ * Initializes the GatherFunction created by newGatherFunction() that will collect the gather pieces in the temporary directories.
+ * Calls the gatherFunction.setOriginalFunction with this ScatterGatherableFunction.
+ * Calls setupGatherFunction with gatherFunction.
+ * @param gatherFunction The function that will merge the gather pieces from the temporary directories.
+ * @param gatherField The output field being gathered.
+ */
+ protected def initGatherFunction(gatherFunction: GatherFunction, gatherField: ArgumentSource) {
+ if (this.setupGatherFunction != null)
+ if (this.setupGatherFunction.isDefinedAt(gatherFunction, gatherField))
+ this.setupGatherFunction(gatherFunction, gatherField)
+ }
+
+ /**
+ * Creates a new clone of this ScatterGatherableFunction, setting the scatterCount to 1 so it doesn't infinitely scatter.
+ * @return An uninitialized clone wrapper for ScatterGatherableFunction
+ */
+ protected def newCloneFunction() = new CloneFunction
+
+ /**
+ * Calls setupCloneFunction with cloneFunction.
+ * @param cloneFunction The clone of this ScatterGatherableFunction
+ * @param index The one based index (from 1..scatterCount inclusive) of the scatter piece.
+ */
+ protected def initCloneFunction(cloneFunction: CloneFunction, index: Int) {
+ if (this.setupCloneFunction != null)
+ if (this.setupCloneFunction.isDefinedAt(cloneFunction, index))
+ this.setupCloneFunction(cloneFunction, index)
+ }
+
+ /**
+ * Gathers up the logs files from other functions.
+ * @param logFile Takes the QFunction and return the log file.
+ * @param functions The functions for which the logs will be concatenated.
+ * @param addOrder The order this function should be added in the graph.
+ */
+ private def gatherLogFile(logFile: (QFunction) => File, functions: Seq[QFunction], addOrder: Int) = {
+ val gatherLogFunction = new ConcatenateLogsFunction
+ this.copySettingsTo(gatherLogFunction)
+ gatherLogFunction.logs = functions.map(logFile).filter(_ != null)
+ gatherLogFunction.jobOutputFile = logFile(this)
+ gatherLogFunction.commandDirectory = this.scatterGatherCommandDir()
+ gatherLogFunction.addOrder = this.addOrder :+ addOrder
+ gatherLogFunction.isIntermediate = false
+ gatherLogFunction
+ }
+
+ /**
+ * Returns a temporary directory under this scatter gather directory.
+ * @param subDir directory under the scatter gather directory.
+ * @return temporary directory under this scatter gather directory.
+ */
+ private def scatterGatherCommandDir(subDir: String = "") = IOUtils.absolute(this.scatterGatherDirectory, this.jobName + "-sg/" + subDir)
+
+ /**
+ * Returns a sub directory under this job local directory.
+ * @param subDir directory under the job local directory.
+ * @return absolute path to a directory under the original job local directory.
+ */
+ private def scatterGatherLocalDir(subDir: String = "") = IOUtils.absolute(this.jobLocalDir, this.jobName + "-sg/" + subDir)
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/SimpleTextGatherFunction.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/SimpleTextGatherFunction.scala
new file mode 100644
index 0000000..2c6aa58
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/function/scattergather/SimpleTextGatherFunction.scala
@@ -0,0 +1,89 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function.scattergather
+
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+import org.broadinstitute.gatk.queue.QException
+import java.io.PrintWriter
+import org.apache.commons.io.{LineIterator, IOUtils, FileUtils}
+
+/**
+ * Merges a text file.
+ */
+class SimpleTextGatherFunction extends GatherFunction with InProcessFunction {
+ def run() = {
+ waitForGatherParts
+ if (gatherParts.size < 1) {
+ throw new QException("No files to gather to output: " + originalOutput)
+ } else if (gatherParts.size == 1) {
+ FileUtils.copyFile(gatherParts(0), originalOutput)
+ } else {
+ val writer = new PrintWriter(originalOutput)
+ try {
+ var startLine = 0
+
+ val readerA = FileUtils.lineIterator(gatherParts(0))
+ val readerB = FileUtils.lineIterator(gatherParts(1))
+ try {
+ var headersMatch = true
+ while (headersMatch) {
+ if (readerA.hasNext && readerB.hasNext) {
+ val headerA = readerA.nextLine
+ val headerB = readerB.nextLine
+ headersMatch = headerA == headerB
+ if (headersMatch) {
+ startLine += 1
+ writer.println(headerA)
+ }
+ } else {
+ headersMatch = false
+ }
+ }
+ } finally {
+ LineIterator.closeQuietly(readerA)
+ LineIterator.closeQuietly(readerB)
+ }
+
+ for (file <- gatherParts) {
+ val reader = FileUtils.lineIterator(file)
+ try {
+ var lineNum = 0
+ while (reader.hasNext && lineNum < startLine) {
+ reader.nextLine
+ lineNum += 1
+ }
+ while (reader.hasNext)
+ writer.println(reader.nextLine)
+ } finally {
+ LineIterator.closeQuietly(reader)
+ }
+ }
+ } finally {
+ IOUtils.closeQuietly(writer)
+ }
+ }
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/clf/vcf/VCFExtractIntervals.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/clf/vcf/VCFExtractIntervals.scala
new file mode 100644
index 0000000..e3b936f
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/clf/vcf/VCFExtractIntervals.scala
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.library.clf.vcf
+
+import java.io.File
+import org.broadinstitute.gatk.utils.commandline.{Argument, Output, Input}
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+
+class VCFExtractIntervals(inVCF: File, outList: File, passOnly: Boolean ) extends CommandLineFunction {
+ def this(vcf: File, list: File ) = this(vcf,list,false)
+ def this(vcf: File) = this(vcf, new File(vcf.getAbsolutePath.replace("vcf","intervals.list")),false)
+ def this(vcf: File, removeFilters: Boolean) = this(vcf, new File(vcf.getAbsolutePath.replace("vcf","intervals.list")), removeFilters)
+
+ @Input(doc="The VCF from which to extract an interval list") var inputVCF : File = inVCF
+ @Output(doc="The file to write the interval list to") var outputList : File = outList
+ @Argument(doc="Whether to use all sites, or only the unfiltered sites") var usePFOnly: Boolean = passOnly
+
+ def commandLine = {
+ if ( usePFOnly ) "grep PASS %s | awk '{print $1\":\"$2}' | uniq > %s".format(inputVCF.getAbsolutePath,outputList.getAbsolutePath)
+ else "grep -v \\\\# %s | awk '{print $1\":\"$2}' | uniq > %s".format(inputVCF.getAbsolutePath,outputList.getAbsolutePath)
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/clf/vcf/VCFExtractSamples.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/clf/vcf/VCFExtractSamples.scala
new file mode 100644
index 0000000..799061a
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/clf/vcf/VCFExtractSamples.scala
@@ -0,0 +1,58 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.library.clf.vcf
+
+import java.io.File
+import collection.JavaConversions._
+import org.broadinstitute.gatk.utils.commandline._
+import org.broadinstitute.gatk.queue.function.CommandLineFunction
+import org.broadinstitute.gatk.utils.text.XReadLines
+
+class VCFExtractSamples(inVCF: File, outVCF: File, samples: List[String]) extends CommandLineFunction {
+ @Input(doc="input VCF from which to extract samples") var inputVCF : File = inVCF
+ @Output(doc="output VCF to write extracted samples to") var outputVCF : File = outVCF
+ @Argument(doc="List of samples to extract from the VCF") var sampleList : List[String] = samples
+
+ var sampleGrep : String = _
+
+ def this(in: File, out: File, samples: File) = this(in,out, (new XReadLines(samples)).readLines.toList)
+
+ override def freezeFieldValues = {
+ this.logger.warn("Note: Using VCFExtractSamples invalidates AC/AF/AN annotations. This is an explicit warning.")
+ sampleGrep = "'" + sampleList.reduceLeft(_ + "|" + _) + "'"
+ super.freezeFieldValues
+ }
+
+ def commandLine = {
+
+ var first : String = "head -n 500 %s | grep \\\\#\\\\# > %s".format(inputVCF.getAbsolutePath,outputVCF.getAbsolutePath)
+ var second : String = "head -n 500 %s | grep \\\\#CHR | tr '\\t' '\\n' | awk '{print ++count\"\\t\"$1}' ".format(inputVCF.getAbsolutePath)
+ second += "| egrep %s | awk '{print $1}' | tr '\\n' ',' | xargs -i cut -f1-9,\\{\\} %s | grep -v \\\\#\\\\# >> %s".format(sampleGrep,inputVCF.getAbsolutePath,outputVCF.getAbsolutePath)
+
+ first+" ; "+second
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/SortByRef.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/SortByRef.scala
new file mode 100644
index 0000000..0ee38e9
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/SortByRef.scala
@@ -0,0 +1,82 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.library.ipf
+
+import collection.JavaConversions._
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+import org.broadinstitute.gatk.utils.commandline._
+import org.broadinstitute.gatk.utils.text.XReadLines
+import java.io.{PrintStream, PrintWriter, File}
+import collection.immutable.HashMap
+
+
+class SortByRef( input: File, reference: File, output: File ) extends InProcessFunction {
+ @Input(doc="The file to be sorted") var inFile: File = input
+ @Input(doc="The reference fasta index") var fai: File = reference
+ @Output(doc="The file to write the sorted file to") var outFile : File = output
+ @Argument(doc="The character or expression that separates entries") var separator : String = "\t"
+ @Argument(doc="The position of the contig in the file (1-based)") var pos: Int = 1
+ @Argument(doc="Comment characters (lines will be brought to file head)") var comment: List[String] = List("#")
+
+ val COMMENT_STRING = "@#!"
+
+ var contigMap: List[(String,PrintWriter,File)] = Nil;
+
+ def entryToTriplet( line : String ) : (String,PrintWriter,File) = {
+ val ctig : String = line.split("\t",2)(0)
+ val tmpf : File = File.createTempFile("sbr",".tmp")
+ val pw : PrintWriter = new PrintWriter(new PrintStream(tmpf))
+ return (ctig,pw,tmpf)
+ }
+
+ def contigVal( line : String ) : PrintWriter = {
+
+ if ( contigMap.size < 1 ) { // no contigs
+ contigMap :+= entryToTriplet(COMMENT_STRING+"\t.")
+ contigMap ++= ( new XReadLines(fai)).readLines.map( entryToTriplet(_)).toList
+ }
+
+ if ( comment.contains(line.charAt(0).toString) ) {
+ return contigMap.find( u => u._1.equals(COMMENT_STRING)).head._2;
+ }
+
+ val matches = contigMap.find( u => u._1.equals(line.split(separator)(pos-1)))
+ if ( matches.isEmpty ) {
+ System.out.println("Empty match for "+line)
+ return contigMap(0)._2
+ } else { return matches.head._2 }
+ }
+
+ def run = {
+ var w : PrintWriter = new PrintWriter(new PrintStream(outFile))
+ System.out.println("Writing to temp files...")
+ ( new XReadLines(inFile) ).readLines.foreach( u => contigVal(u).println(u) )
+ contigMap.foreach( u => u._2.close )
+ System.out.println("Concatenating...")
+ contigMap.map( u => new XReadLines(u._3) ).foreach( u => asScalaIterator(u).foreach(u => w.println(u)))
+ w.close()
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFExtractIntervals.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFExtractIntervals.scala
new file mode 100644
index 0000000..8abcf5b
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFExtractIntervals.scala
@@ -0,0 +1,85 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.library.ipf.vcf
+
+import collection.JavaConversions._
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+import org.broadinstitute.gatk.utils.commandline._
+import org.broadinstitute.gatk.utils.text.XReadLines
+import java.io.{PrintStream, PrintWriter, File}
+
+class VCFExtractIntervals(inVCF: File, outList: File, useFilterSites: Boolean) extends InProcessFunction {
+ def this(in : File, out: File) = this(in,out,true)
+ def this(in : File) = this(in,new File(in.getAbsolutePath.replace(".vcf",".intervals.list")),true)
+
+ @Input(doc="The VCF to convert to an interval list") var vcfIn : File = inVCF
+ @Output(doc="The intervals file to write to") var listOut : File = outList
+ @Argument(doc="Keep filtered sites?") var keepFilters : Boolean = useFilterSites
+
+ var out : PrintWriter = _
+
+ def run = {
+ out = new PrintWriter(new PrintStream(listOut))
+ var elems = asScalaIterator(new XReadLines(vcfIn)).map(vcf2int).filter(p => !p.equals(""))
+ var prev : String = null
+ if ( elems.hasNext ) {
+ prev = elems.next
+ }
+ var cur : String = null
+ if ( elems.hasNext ) {
+ cur = elems.next
+ while ( elems.hasNext ) {
+ out.printf("%s%n",prev)
+ while ( cur.equals(prev) && elems.hasNext && !cur.equals("") ) {
+ cur = elems.next
+ }
+
+ if ( ! cur.equals(prev) ) {
+ if ( elems.hasNext ) {
+ prev = cur
+ cur = elems.next
+ }
+ }
+ }
+ out.printf("%s%n",prev)
+ out.printf("%s%n",cur)
+ } else {
+ out.printf("%s%n",prev)
+ }
+
+ out.close
+ }
+
+ def vcf2int( vcfLine: String ) : String = {
+ var spline = vcfLine.split("\t")
+ if ( ! vcfLine.startsWith("#") && (spline(6).equals("PASS") || spline(6).equals(".") || keepFilters) ) {
+ return("%s:%s".format(spline(0),spline(1)))
+ } else {
+ return ""
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFExtractSamples.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFExtractSamples.scala
new file mode 100644
index 0000000..99571e9
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFExtractSamples.scala
@@ -0,0 +1,62 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.library.ipf.vcf
+
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+import org.broadinstitute.gatk.utils.text.XReadLines
+import collection.JavaConversions._
+import org.broadinstitute.gatk.utils.commandline._
+import java.io.{PrintWriter, PrintStream, File}
+
+class VCFExtractSamples(inVCF: File, outVCF: File, samples: List[String]) extends InProcessFunction {
+ def this(in: File, out: File, samples: File) = this(in,out, (new XReadLines(samples)).readLines.toList)
+
+ @Input(doc="VCF from which to extract samples") var inputVCF : File = inVCF
+ @Output(doc="VCF to which to write the sample-subset vcf") var outputVCF : File = outVCF
+ @Argument(doc="The samples to extract from the VCF") var extractSamples : List[String] = samples
+
+ var out : PrintWriter = _
+ var columns : List[Int] = (0 to 8).toList
+
+ def run = {
+ out = new PrintWriter(new PrintStream(outputVCF))
+ asScalaIterator(new XReadLines(inputVCF)).foreach(subset)
+ out.close
+ }
+
+ def subset( line : String ) {
+ if ( line.startsWith("##") ) {
+ out.print("%s%n".format(line))
+ } else {
+ val spline = line.split("\t")
+ if ( spline(0).equals("#CHROM") ) {
+ columns ++= spline.zipWithIndex.filter( p => samples.contains(p._1) ).map( p => p._2 )
+ }
+
+ out.print("%s%n".format(columns.map(p => spline(p)).reduceLeft(_ + "\t" + _)))
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFExtractSites.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFExtractSites.scala
new file mode 100644
index 0000000..5bd25bf
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFExtractSites.scala
@@ -0,0 +1,99 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.library.ipf.vcf
+
+import collection.JavaConversions._
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+import org.broadinstitute.gatk.utils.commandline._
+import org.broadinstitute.gatk.utils.text.XReadLines
+import java.io.{PrintStream, PrintWriter, File}
+
+
+class VCFExtractSites( vcf: File, output: File) extends InProcessFunction {
+ @Input(doc="VCF file from which to extract sites") var inVCF: File = vcf
+ @Output(doc="Sites VCF file to write to") var outVCF: File = output
+ @Argument(doc="Keep non-PASS sites") var keepFilters: Boolean = false
+ @Argument(doc="Keep info field") var keepInfo : Boolean = true
+ @Argument(doc="Keep qual field") var keepQual : Boolean = true
+
+ def lineMap( line: String ) : String = {
+ if ( line.startsWith("##") ) { return line }
+ var spline = line.split("\t",9)
+ if ( spline(0).startsWith("#")) { return spline.slice(0,8).reduceLeft( _+"\t"+_) }
+
+ if ( spline(6) == "PASS" || keepFilters ) {
+ var buf = new StringBuffer(spline.slice(0,5).reduceLeft(_ + "\t" + _ ))
+ if ( keepQual ) {
+ buf.append("\t%s".format(spline(5)))
+ } else {
+ buf.append("\t.")
+ }
+
+ buf.append("\tPASS")
+
+ if ( keepInfo ) {
+ buf.append("\t%s".format(spline(7)))
+ } else {
+ buf.append("\t.")
+ }
+
+ return buf.toString
+ }
+
+ return ""
+ }
+
+ def lineMapDebug( line: String ) : String = {
+ System.out.printf("Input: %s%n ",line)
+ val o = lineMap(line)
+ System.out.printf("Output: %s%n",o)
+
+ return o
+ }
+
+ def debugFilter ( line : String ) : Boolean = {
+ System.out.printf("Filter In: %s%n",line)
+ if ( line != "" ) {
+ System.out.printf("Not filtered %n")
+ return true
+ } else {
+ System.out.printf("Filtered%n")
+ return false
+ }
+ }
+
+ def debugPrint(line: String, k : PrintWriter) : Unit = {
+ System.out.printf("Into print: %s%n",line)
+ k.println(line)
+ }
+
+ def run {
+ var w: PrintWriter = new PrintWriter( new PrintStream(outVCF) )
+ asScalaIterator[String](new XReadLines(inVCF)).map(lineMap).filter( u => u != "" ).foreach( u => w.println(u) )
+ w.close
+ }
+
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFSimpleMerge.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFSimpleMerge.scala
new file mode 100644
index 0000000..b3093c8
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/library/ipf/vcf/VCFSimpleMerge.scala
@@ -0,0 +1,107 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.library.ipf.vcf
+
+import collection.JavaConversions._
+import org.broadinstitute.gatk.queue.function.InProcessFunction
+import org.broadinstitute.gatk.utils.commandline._
+import org.broadinstitute.gatk.utils.text.XReadLines
+import java.io.{PrintStream, PrintWriter, File}
+import htsjdk.samtools.{SAMSequenceRecord, SAMSequenceDictionary}
+import org.broadinstitute.gatk.utils.{GenomeLocParser, GenomeLoc}
+
+class VCFSimpleMerge extends InProcessFunction {
+ @Input(doc="VCFs to be merged") var vcfs: List[File] = Nil
+ @Input(doc="The reference fasta index") var fai: File = _
+ @Output(doc="The final VCF to write to") var outVCF : File = _
+
+ class PeekableXRL(f : File ) {
+ var xrl : XReadLines = new XReadLines(f)
+ var cur : String = if ( xrl.hasNext ) xrl.next else null
+
+ def hasNext : Boolean = xrl.hasNext || cur != null
+ def next : String = {
+ var toRet : String = cur
+ if ( xrl.hasNext ) {
+ cur = xrl.next
+ } else {
+ cur = null
+ }
+
+ return toRet
+ }
+
+ def peek : String = cur
+
+ }
+
+ def readHeader( xrl : PeekableXRL ) : List[String] = {
+ var toRet : List[String] = Nil
+ while ( xrl.hasNext && xrl.peek.startsWith("#") ) {
+ toRet :+= xrl.next
+ }
+
+ return toRet
+ }
+
+ def genomeLoc(xrl : PeekableXRL, p : GenomeLocParser ) : GenomeLoc = {
+ var slp = xrl.peek.split("\t",3)
+ return p.createGenomeLoc(slp(0),Integer.parseInt(slp(1)),Integer.parseInt(slp(1)))
+ }
+
+ def run = {
+ var ssd : SAMSequenceDictionary = new SAMSequenceDictionary
+ for ( line <- (new XReadLines(fai)).readLines ) {
+ val spl = line.split("\\s+")
+ val ctig = spl(0)
+ val pos = Integer.parseInt(spl(1))
+ ssd.addSequence(new SAMSequenceRecord(ctig,pos))
+ }
+
+ var xrls : List[PeekableXRL] = vcfs.map( new PeekableXRL(_) )
+
+ var w : PrintWriter = new PrintWriter(new PrintStream(outVCF))
+
+ readHeader(xrls(0)).foreach(u => w.println(u) )
+
+ xrls.foreach(readHeader(_))
+
+ val glp : GenomeLocParser = new GenomeLocParser(ssd)
+
+ var last = ""
+ while ( ! xrls.forall( u => ! u.hasNext ) ) {
+ val first = xrls.filter( u => u.hasNext).reduceLeft( (a,b) => if ( genomeLoc(a,glp).isBefore(genomeLoc(b,glp))) a else b )
+ if ( ! first.peek.equals(last) ) {
+ w.println(first.peek)
+ }
+ last = first.next
+ }
+
+ w.close
+
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ClassFieldCache.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ClassFieldCache.scala
new file mode 100644
index 0000000..82b8ca5
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ClassFieldCache.scala
@@ -0,0 +1,219 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import org.broadinstitute.gatk.utils.commandline._
+import scala.Some
+import org.broadinstitute.gatk.queue.QException
+import collection.JavaConversions._
+import java.io.File
+
+/**
+ * Utilities and a static cache of argument fields for various classes populated by the parsingEngine.
+ * Because this class works with the ParsingEngine it can walk @ArgumentCollection hierarchies.
+ */
+object ClassFieldCache {
+ var parsingEngine: ParsingEngine = _
+
+
+ //
+ // Field caching
+ //
+
+ /**
+ * The list of fields defined on a class
+ * @param clazz The class to lookup fields.
+ */
+ private class ClassFields(clazz: Class[_]) {
+ /** The complete list of fields on this CommandLineFunction. */
+ val functionFields: Seq[ArgumentSource] = parsingEngine.extractArgumentSources(clazz).toSeq
+ /** The @Input fields on this CommandLineFunction. */
+ val inputFields: Seq[ArgumentSource] = functionFields.filter(source => ReflectionUtils.hasAnnotation(source.field, classOf[Input]))
+ /** The @Output fields on this CommandLineFunction. */
+ val outputFields: Seq[ArgumentSource] = functionFields.filter(source => ReflectionUtils.hasAnnotation(source.field, classOf[Output]))
+ /** The @Argument fields on this CommandLineFunction. */
+ val argumentFields: Seq[ArgumentSource] = functionFields.filter(source => ReflectionUtils.hasAnnotation(source.field, classOf[Argument]))
+ }
+
+ /**
+ * The mapping from class to fields.
+ */
+ private var classFieldsMap = Map.empty[Class[_], ClassFields]
+
+ /**
+ * Returns the fields for a class.
+ * @param clazz Class to retrieve fields for.
+ * @return the fields for the class.
+ */
+ private def classFields(clazz: Class[_]): ClassFields = {
+ classFieldsMap.get(clazz) match {
+ case Some(classFields) => classFields
+ case None =>
+ val classFields = new ClassFields(clazz)
+ classFieldsMap += clazz -> classFields
+ classFields
+ }
+ }
+
+ /**
+ * Returns the field on clazz.
+ * @param clazz Class to search.
+ * @param name Name of the field to return.
+ * @return Argument source for the field.
+ */
+ def findField(clazz: Class[_], name: String): ArgumentSource = {
+ classFields(clazz).functionFields.find(_.field.getName == name) match {
+ case Some(source) => source
+ case None => throw new QException("Could not find a field on class %s with name %s".format(clazz, name))
+ }
+ }
+
+ /**
+ * Returns the Seq of fields for a QFunction class.
+ * @param clazz Class to retrieve fields for.
+ * @return the fields of the class.
+ */
+ def classFunctionFields(clazz: Class[_]): Seq[ArgumentSource] = classFields(clazz).functionFields
+
+ /**
+ * Returns the Seq of inputs for a QFunction class.
+ * @param clazz Class to retrieve inputs for.
+ * @return the inputs of the class.
+ */
+ def classInputFields(clazz: Class[_]): Seq[ArgumentSource] = classFields(clazz).inputFields
+
+ /**
+ * Returns the Seq of outputs for a QFunction class.
+ * @param clazz Class to retrieve outputs for.
+ * @return the outputs of the class.
+ */
+ def classOutputFields(clazz: Class[_]): Seq[ArgumentSource] = classFields(clazz).outputFields
+
+ /**
+ * Returns the Seq of arguments for a QFunction class.
+ * @param clazz Class to retrieve arguments for.
+ * @return the arguments of the class.
+ */
+ def classArgumentFields(clazz: Class[_]): Seq[ArgumentSource] = classFields(clazz).argumentFields
+
+
+ //
+ // get/set fields as AnyRef
+ //
+
+ /**
+ * Gets the value of a field.
+ * @param obj Top level object storing the source info.
+ * @param source Field to get the value for.
+ * @return value of the field.
+ */
+ def getFieldValue(obj: AnyRef, source: ArgumentSource) = ReflectionUtils.getValue(invokeObj(obj, source), source.field)
+
+ /**
+ * Gets the value of a field.
+ * @param obj Top level object storing the source info.
+ * @param source Field to set the value for.
+ * @return value of the field.
+ */
+ def setFieldValue(obj: AnyRef, source: ArgumentSource, value: Any) = ReflectionUtils.setValue(invokeObj(obj, source), source.field, value)
+
+ /**
+ * Walks gets the fields in this object or any collections in that object
+ * recursively to find the object holding the field to be retrieved or set.
+ * @param obj Top level object storing the source info.
+ * @param source Field find the invoke object for.
+ * @return Object to invoke the field on.
+ */
+ private def invokeObj(obj: AnyRef, source: ArgumentSource) = source.parentFields.foldLeft[AnyRef](obj)(ReflectionUtils.getValue(_, _))
+
+
+ //
+ // get/set fields as java.io.File
+ //
+
+ /**
+ * Gets the files from the fields. The fields must be a File, a FileExtension, or a Seq or Set of either.
+ * @param obj Top level object storing the source info.
+ * @param fields Fields to get files.
+ * @return for the fields.
+ */
+ def getFieldFiles(obj: AnyRef, fields: Seq[ArgumentSource]): Seq[File] = {
+ var files: Seq[File] = Nil
+ for (field <- fields)
+ files ++= getFieldFiles(obj, field)
+ files.distinct
+ }
+
+ /**
+ * Gets the files from the field. The field must be a File, a FileExtension, or a Seq or Set of either.
+ * @param obj Top level object storing the source info.
+ * @param field Field to get files.
+ * @return for the field.
+ */
+ def getFieldFiles(obj: AnyRef, field: ArgumentSource): Seq[File] = {
+ var files: Seq[File] = Nil
+ CollectionUtils.foreach(getFieldValue(obj, field), (fieldValue) => {
+ val file = fieldValueToFile(field, fieldValue)
+ if (file != null)
+ files :+= file
+ })
+ files.distinct
+ }
+
+ /**
+ * Gets the file from the field. The field must be a File or a FileExtension and not a Seq or Set.
+ * @param obj Top level object storing the source info.
+ * @param field Field to get the file.
+ * @return for the field.
+ */
+ def getFieldFile(obj: AnyRef, field: ArgumentSource): File =
+ fieldValueToFile(field, getFieldValue(obj, field))
+
+ /**
+ * Converts the field value to a file. The field must be a File or a FileExtension.
+ * @param field Field to get the file.
+ * @param value Value of the File or FileExtension or null.
+ * @return Null if value is null, otherwise the File.
+ * @throws QException if the value is not a File or FileExtension.
+ */
+ private def fieldValueToFile(field: ArgumentSource, value: Any): File = value match {
+ case file: File => file
+ case null => null
+ case unknown => throw new QException("Non-file found. Try removing the annotation, change the annotation to @Argument, or extend File with FileExtension: %s: %s".format(field.field, unknown))
+ }
+
+
+ //
+ // other utilities
+ //
+
+ /**
+ * Retrieves the fullName of the argument
+ * @param field ArgumentSource to check
+ * @return Full name of the argument source
+ */
+ def fullName(field: ArgumentSource) = field.createArgumentDefinitions().get(0).fullName
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/CollectionUtils.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/CollectionUtils.scala
new file mode 100644
index 0000000..5c0be04
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/CollectionUtils.scala
@@ -0,0 +1,116 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+/**
+ * Utilities that try to deeply apply operations to collections, specifically Traversable and Option.
+ */
+object CollectionUtils {
+
+ /**
+ * Loops though a collection running the function f on each value.
+ * @param value The value to run f on, or a collection of values for which f should be run on.
+ * @param f The function to run on value, or to run on the values within the collection.
+ * @return The updated value.
+ */
+ def updated(value: Any, f: Any => Any): Any = {
+ value match {
+ case traversable: Traversable[_] => traversable.map(updated(_, f))
+ case option: Option[_] => option.map(updated(_, f))
+ case x => f(x)
+ }
+ }
+
+ /**
+ * Utility for recursively processing collections.
+ * @param value Initial the collection to be processed
+ * @param f a function that will be called for each (item, collection) in the initial collection
+ */
+ def foreach(value: Any, f: (Any, Any) => Unit): Unit = {
+ value match {
+ case traversable: Traversable[_] =>
+ for (item <- traversable) {
+ f(item, traversable)
+ foreach(item, f)
+ }
+ case option: Option[_] =>
+ for (item <- option) {
+ f(item, option)
+ foreach(item, f)
+ }
+ case _ =>
+ }
+ }
+
+ /**
+ * Utility for recursively processing collections.
+ * @param value Initial the collection to be processed
+ * @param f a function that will be called for each (item, collection) in the initial collection
+ */
+ def foreach(value: Any, f: (Any) => Unit): Unit = {
+ value match {
+ case traversable: Traversable[_] => traversable.foreach(f(_))
+ case option: Option[_] => option.foreach(f(_))
+ case item => f(item)
+ }
+ }
+
+ /**
+ * Removes empty values from collections.
+ * @param value The collection to test.
+ * @return The value if it is not a collection, otherwise the collection with nulls and empties removed.
+ */
+ private def filterNotNullOrNotEmpty[T](value: T): T = {
+ val newValue = value match {
+ case traversable: Traversable[_] => traversable.map(filterNotNullOrNotEmpty(_)).filter(isNotNullOrNotEmpty(_)).asInstanceOf[T]
+ case option: Option[_] => option.map(filterNotNullOrNotEmpty(_)).filter(isNotNullOrNotEmpty(_)).asInstanceOf[T]
+ case x => x
+ }
+ newValue
+ }
+
+
+ /**
+ * Returns true if the value is null or an empty collection.
+ * @param value Value to test for null, or a collection to test if it is empty.
+ * @return true if the value is null, or false if the collection is empty, otherwise true.
+ */
+ def isNullOrEmpty(value: Any): Boolean = !isNotNullOrNotEmpty(value)
+
+ /**
+ * Returns false if the value is null or an empty collection.
+ * @param value Value to test for null, or a collection to test if it is empty.
+ * @return false if the value is null, or false if the collection is empty, otherwise true.
+ */
+ def isNotNullOrNotEmpty(value: Any): Boolean = {
+ val result = value match {
+ case traversable: Traversable[_] => !filterNotNullOrNotEmpty(traversable).isEmpty
+ case option: Option[_] => !filterNotNullOrNotEmpty(option).isEmpty
+ case x => x != null
+ }
+ result
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/EmailMessage.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/EmailMessage.scala
new file mode 100644
index 0000000..e38183a
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/EmailMessage.scala
@@ -0,0 +1,140 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import org.apache.commons.mail.{MultiPartEmail, EmailAttachment}
+import java.io.{IOException, FileReader, File}
+import javax.mail.internet.InternetAddress
+import scala.collection.JavaConversions._
+
+/**
+ * Encapsulates a message to be sent over email.
+ */
+class EmailMessage extends Logging {
+ var from: String = _
+ var to: Seq[String] = Nil
+ var cc: Seq[String] = Nil
+ var bcc: Seq[String] = Nil
+ var subject: String = _
+ var body: String = _
+ var attachments: Seq[File] = Nil
+
+ /**
+ * Sends the email and throws an exception if the email can't be sent.
+ * @param settings The server settings for the email.
+ */
+ def send(settings: EmailSettings) = {
+ val email = new MultiPartEmail
+
+ email.setHostName(settings.host)
+ email.setSmtpPort(settings.port)
+ email.setTLS(settings.tls)
+ if (settings.ssl) {
+ email.setSSL(true)
+ email.setSslSmtpPort(settings.port.toString)
+ }
+
+ if (settings.username != null && (settings.password != null || settings.passwordFile != null)) {
+ val password = {
+ if (settings.passwordFile != null) {
+ val reader = new FileReader(settings.passwordFile)
+ try {
+ org.apache.commons.io.IOUtils.toString(reader).replaceAll("\\r|\\n", "")
+ } finally {
+ org.apache.commons.io.IOUtils.closeQuietly(reader)
+ }
+ } else {
+ settings.password
+ }
+ }
+ email.setAuthentication(settings.username, password)
+ }
+
+ email.setFrom(this.from)
+ if (this.subject != null)
+ email.setSubject(this.subject)
+ if (this.body != null)
+ email.setMsg(this.body)
+ if (this.to.size > 0)
+ email.setTo(convert(this.to))
+ if (this.cc.size > 0)
+ email.setCc(convert(this.cc))
+ if (this.bcc.size > 0)
+ email.setBcc(convert(this.bcc))
+
+ for (file <- this.attachments) {
+ val attachment = new EmailAttachment
+ attachment.setDisposition(EmailAttachment.ATTACHMENT)
+ attachment.setPath(file.getAbsolutePath)
+ attachment.setDescription(file.getAbsolutePath)
+ attachment.setName(file.getName)
+ email.attach(attachment)
+ }
+
+ email.send
+ }
+
+ /**
+ * Tries twice 30 seconds apart to send the email. Then logs the message if it can't be sent.
+ * @param settings The server settings for the email.
+ */
+ def trySend(settings: EmailSettings) = {
+ try {
+ Retry.attempt(() => send(settings), .5)
+ } catch {
+ case e: RetryException=> logger.error("Error sending message: %n%s".format(this.toString), e)
+ }
+ }
+
+ /**
+ * Converts the email addresses to a collection of InternetAddress which can bypass client side validation,
+ * specifically that the domain is specified.
+ * @param addresses Seq of email addresses.
+ * @return java.util.List of InternetAddress'es
+ */
+ private def convert(addresses: Seq[String]): java.util.List[InternetAddress] = {
+ addresses.map(address => new InternetAddress(address, false))
+ }
+
+ override def toString = {
+ """
+ |From: %s
+ |To: %s
+ |Cc: %s
+ |Bcc: %s
+ |Subject: %s
+ |
+ |%s
+ |
+ |Attachments:
+ |%s
+ |""".stripMargin.format(
+ this.from, this.to.mkString(", "),
+ this.cc.mkString(", "), this.bcc.mkString(", "),
+ this.subject, this.body,
+ this.attachments.map(_.getAbsolutePath).mkString("%n".format()))
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/EmailSettings.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/EmailSettings.scala
new file mode 100644
index 0000000..d315410
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/EmailSettings.scala
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import java.io.File
+import org.broadinstitute.gatk.utils.commandline.Argument
+
+/**
+ * Email server settings.
+ */
+class EmailSettings {
+ @Argument(doc="Email SMTP host. Defaults to localhost.", shortName="emailHost", fullName="emailSmtpHost", required=false)
+ var host = "localhost"
+
+ @Argument(doc="Email SMTP port. Defaults to 465 for ssl, otherwise 25.", shortName="emailPort", fullName="emailSmtpPort", required=false)
+ var port = 25
+
+ @Argument(doc="Email should use TLS. Defaults to false.", shortName="emailTLS", fullName="emailUseTLS", required=false)
+ var tls = false
+
+ @Argument(doc="Email should use SSL. Defaults to false.", shortName="emailSSL", fullName="emailUseSSL", required=false)
+ var ssl = false
+
+ @Argument(doc="Email SMTP username. Defaults to none.", shortName="emailUser", fullName="emailUsername", required=false)
+ var username: String = _
+
+ @Argument(doc="Email SMTP password file. Defaults to none.", shortName="emailPassFile", fullName="emailPasswordFile", required=false)
+ var passwordFile: File = _
+
+ @Argument(doc="Email SMTP password. Defaults to none. Not secure! See emailPassFile.", shortName="emailPass", fullName="emailPassword", required=false)
+ var password: String = _
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/Logging.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/Logging.scala
new file mode 100644
index 0000000..3a83a2f
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/Logging.scala
@@ -0,0 +1,62 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import org.apache.log4j._
+import java.lang.{Throwable, String}
+import org.apache.log4j.spi.{ThrowableInformation, LocationInfo, LoggingEvent, LoggerFactory}
+import java.util.Hashtable
+
+/**
+ * A mixin to add logging to a class
+ */
+trait Logging {
+ private val className = this.getClass.getName
+ protected lazy val logger = Logger.getLogger(className, Logging.factory)
+}
+
+object Logging {
+ private object factory extends LoggerFactory {
+ /**
+ * Do not log the scala generated class name after "$".
+ * All these shenanigans can be avoided if we use the format
+ * string c{1} (the name passed to Logger.getLogger)
+ * versus C{1} (the class name of the calling method)
+ */
+ def makeNewLoggerInstance(name: String) = new Logger(name) {
+ override def forcedLog(fqcn: String, level: Priority, message: AnyRef, t: Throwable) = {
+ // Strip off the "$" from the class name.
+ val info = new LocationInfo(new Throwable, fqcn) { override def getClassName = super.getClassName.takeWhile(_ != '$') }
+ // If the following aren't retrieved here, LoggingEvent will NOT lazy load them.
+ val throwable = if (t == null) null else new ThrowableInformation(t)
+ val ndc = NDC.get
+ val mdc = MDC.getContext().asInstanceOf[Hashtable[_,_]];
+ callAppenders(new LoggingEvent(fqcn, this, System.currentTimeMillis,
+ level.asInstanceOf[Level], message, null, throwable, ndc, info, mdc))
+ }
+ }
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/PrimitiveOptionConversions.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/PrimitiveOptionConversions.scala
new file mode 100644
index 0000000..edaf802
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/PrimitiveOptionConversions.scala
@@ -0,0 +1,142 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import scala.language.implicitConversions
+
+/**
+ * An importable object that provides automatic primitive to option conversion.
+ */
+object PrimitiveOptionConversions {
+
+ // Conversion from Option
+ implicit def byteOption2byte(x: Option[Byte]): Byte = x.get
+ implicit def shortOption2short(x: Option[Short]): Short = x.get
+ implicit def charOption2char(x: Option[Char]): Char = x.get
+ implicit def intOption2int(x: Option[Int]): Int = x.get
+ implicit def longOption2long(x: Option[Long]): Long = x.get
+ implicit def floatOption2float(x: Option[Float]): Float = x.get
+ implicit def doubleOption2double(x: Option[Double]): Double = x.get
+ implicit def booleanOption2boolean(x: Option[Boolean]): Boolean = x.get
+
+ // Conversion to Option
+ implicit def byte2byteOption(x: Byte): Option[Byte] = Some(x)
+ implicit def short2shortOption(x: Short): Option[Short] = Some(x)
+ implicit def char2charOption(x: Char): Option[Char] = Some(x)
+ implicit def int2intOption(x: Int): Option[Int] = Some(x)
+ implicit def long2longOption(x: Long): Option[Long] = Some(x)
+ implicit def float2floatOption(x: Float): Option[Float] = Some(x)
+ implicit def double2doubleOption(x: Double): Option[Double] = Some(x)
+ implicit def boolean2booleanOption(x: Boolean): Option[Boolean] = Some(x)
+
+ // Narrowing for constants to byte, short, and float
+ implicit def int2byteOption(x: Int): Option[Byte] = Some(x.toByte)
+ implicit def int2shortOption(x: Int): Option[Short] = Some(x.toShort)
+ implicit def double2floatOption(x: Float): Option[Float] = Some(x.toFloat)
+
+ // Widening
+ implicit def byte2shortOption(x: Byte): Option[Short] = Some(x.toShort)
+ implicit def byte2intOption(x: Byte): Option[Int] = Some(x.toInt)
+ implicit def byte2longOption(x: Byte): Option[Long] = Some(x.toLong)
+ implicit def byte2floatOption(x: Byte): Option[Float] = Some(x.toFloat)
+ implicit def byte2doubleOption(x: Byte): Option[Double] = Some(x.toDouble)
+
+ implicit def short2intOption(x: Short): Option[Int] = Some(x.toInt)
+ implicit def short2longOption(x: Short): Option[Long] = Some(x.toLong)
+ implicit def short2floatOption(x: Short): Option[Float] = Some(x.toFloat)
+ implicit def short2doubleOption(x: Short): Option[Double] = Some(x.toDouble)
+
+ implicit def char2intOption(x: Char): Option[Int] = Some(x.toInt)
+ implicit def char2longOption(x: Char): Option[Long] = Some(x.toLong)
+ implicit def char2floatOption(x: Char): Option[Float] = Some(x.toFloat)
+ implicit def char2doubleOption(x: Char): Option[Double] = Some(x.toDouble)
+
+ implicit def int2longOption(x: Int): Option[Long] = Some(x.toLong)
+ implicit def int2floatOption(x: Int): Option[Float] = Some(x.toFloat)
+ implicit def int2doubleOption(x: Int): Option[Double] = Some(x.toDouble)
+
+ implicit def long2floatOption(x: Long): Option[Float] = Some(x.toFloat)
+ implicit def long2doubleOption(x: Long): Option[Double] = Some(x.toDouble)
+
+ implicit def float2doubleOption(x: Float): Option[Double] = Some(x.toDouble)
+
+}
+
+/**
+ * A trait that exposes the above functions to all sub classes as well.
+ */
+trait PrimitiveOptionConversions {
+ // How to we import these implicit definitions into the trait so that they are seen by objects extending a trait?
+ // import PrimitiveOptionConversion._ inside of a trait does not seem to work?
+ // Declaring them in a trait like this does work but does not seem scala-ish.
+
+ implicit def byteOption2byte(x: Option[Byte]): Byte = PrimitiveOptionConversions.byteOption2byte(x)
+ implicit def shortOption2short(x: Option[Short]): Short = PrimitiveOptionConversions.shortOption2short(x)
+ implicit def charOption2char(x: Option[Char]): Char = PrimitiveOptionConversions.charOption2char(x)
+ implicit def intOption2int(x: Option[Int]): Int = PrimitiveOptionConversions.intOption2int(x)
+ implicit def longOption2long(x: Option[Long]): Long = PrimitiveOptionConversions.longOption2long(x)
+ implicit def floatOption2float(x: Option[Float]): Float = PrimitiveOptionConversions.floatOption2float(x)
+ implicit def doubleOption2double(x: Option[Double]): Double = PrimitiveOptionConversions.doubleOption2double(x)
+ implicit def booleanOption2boolean(x: Option[Boolean]): Boolean = PrimitiveOptionConversions.booleanOption2boolean(x)
+
+ implicit def byte2byteOption(x: Byte): Option[Byte] = PrimitiveOptionConversions.byte2byteOption(x)
+ implicit def short2shortOption(x: Short): Option[Short] = PrimitiveOptionConversions.short2shortOption(x)
+ implicit def char2charOption(x: Char): Option[Char] = PrimitiveOptionConversions.char2charOption(x)
+ implicit def int2intOption(x: Int): Option[Int] = PrimitiveOptionConversions.int2intOption(x)
+ implicit def long2longOption(x: Long): Option[Long] = PrimitiveOptionConversions.long2longOption(x)
+ implicit def float2floatOption(x: Float): Option[Float] = PrimitiveOptionConversions.float2floatOption(x)
+ implicit def double2doubleOption(x: Double): Option[Double] = PrimitiveOptionConversions.double2doubleOption(x)
+ implicit def boolean2booleanOption(x: Boolean): Option[Boolean] = PrimitiveOptionConversions.boolean2booleanOption(x)
+
+ implicit def int2byteOption(x: Int): Option[Byte] = PrimitiveOptionConversions.int2byteOption(x)
+ implicit def int2shortOption(x: Int): Option[Short] = PrimitiveOptionConversions.int2shortOption(x)
+ implicit def double2floatOption(x: Float): Option[Float] = PrimitiveOptionConversions.double2floatOption(x)
+
+ implicit def byte2shortOption(x: Byte): Option[Short] = PrimitiveOptionConversions.byte2shortOption(x)
+ implicit def byte2intOption(x: Byte): Option[Int] = PrimitiveOptionConversions.byte2intOption(x)
+ implicit def byte2longOption(x: Byte): Option[Long] = PrimitiveOptionConversions.byte2longOption(x)
+ implicit def byte2floatOption(x: Byte): Option[Float] = PrimitiveOptionConversions.byte2floatOption(x)
+ implicit def byte2doubleOption(x: Byte): Option[Double] = PrimitiveOptionConversions.byte2doubleOption(x)
+
+ implicit def short2intOption(x: Short): Option[Int] = PrimitiveOptionConversions.short2intOption(x)
+ implicit def short2longOption(x: Short): Option[Long] = PrimitiveOptionConversions.short2longOption(x)
+ implicit def short2floatOption(x: Short): Option[Float] = PrimitiveOptionConversions.short2floatOption(x)
+ implicit def short2doubleOption(x: Short): Option[Double] = PrimitiveOptionConversions.short2doubleOption(x)
+
+ implicit def char2intOption(x: Char): Option[Int] = PrimitiveOptionConversions.char2intOption(x)
+ implicit def char2longOption(x: Char): Option[Long] = PrimitiveOptionConversions.char2longOption(x)
+ implicit def char2floatOption(x: Char): Option[Float] = PrimitiveOptionConversions.char2floatOption(x)
+ implicit def char2doubleOption(x: Char): Option[Double] = PrimitiveOptionConversions.char2doubleOption(x)
+
+ implicit def int2longOption(x: Int): Option[Long] = PrimitiveOptionConversions.int2longOption(x)
+ implicit def int2floatOption(x: Int): Option[Float] = PrimitiveOptionConversions.int2floatOption(x)
+ implicit def int2doubleOption(x: Int): Option[Double] = PrimitiveOptionConversions.int2doubleOption(x)
+
+ implicit def long2floatOption(x: Long): Option[Float] = PrimitiveOptionConversions.long2floatOption(x)
+ implicit def long2doubleOption(x: Long): Option[Double] = PrimitiveOptionConversions.long2doubleOption(x)
+
+ implicit def float2doubleOption(x: Float): Option[Double] = PrimitiveOptionConversions.float2doubleOption(x)
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/QJobReport.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/QJobReport.scala
new file mode 100644
index 0000000..be5a17f
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/QJobReport.scala
@@ -0,0 +1,110 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import org.broadinstitute.gatk.queue.function.QFunction
+import org.broadinstitute.gatk.engine.report.GATKReportTable
+import org.broadinstitute.gatk.queue.engine.JobRunInfo
+
+/**
+ * A mixin to add Job info to the class
+ */
+trait QJobReport extends Logging {
+ self: QFunction =>
+
+ protected var reportGroup: String = null
+ protected var userReportFeatures: Map[String, String] = Map()
+ protected var reportFeatures: Map[String, String] = Map()
+ protected var reportEnabled: Boolean = true
+
+ def includeInReport = reportEnabled
+ def enableReport() { reportEnabled = true }
+ def disableReport() { reportEnabled = false }
+
+ def setRunInfo(info: JobRunInfo) {
+ //logger.info("info " + info)
+ val runtimeFeatures = Map(
+ "iteration" -> 1,
+ "analysisName" -> getReportGroup,
+ "jobName" -> QJobReport.workAroundSameJobNames(this),
+ "intermediate" -> self.isIntermediate,
+ "exechosts" -> info.getExecHosts,
+ "startTime" -> info.getStartTime,
+ "doneTime" -> info.getDoneTime,
+ "formattedStartTime" -> info.getFormattedStartTime,
+ "formattedDoneTime" -> info.getFormattedDoneTime,
+ "runtime" -> info.getRuntimeInMs).mapValues((x:Any) => if (x != null) x.toString else "null")
+ reportFeatures = runtimeFeatures ++ userReportFeatures
+ // note -- by adding reportFeatures second we override iteration
+ // (or any other binding) with the user provided value
+ }
+
+ /** The report Group is the analysis name transform to only contain valid GATKReportTable characters */
+ def getReportGroup = self.analysisName.replaceAll(GATKReportTable.INVALID_TABLE_NAME_REGEX, "_")
+
+ def getReportFeatureNames: Seq[String] = reportFeatures.keys.toSeq
+ def getReportFeature(key: String): String = {
+ reportFeatures.get(key) match {
+ case Some(x) => x
+ case None =>
+ logger.warn("getReportFeature called with key %s but no value was found for group %s. This can be caused by adding user-defined job features to a job with a generic name used elsewhere in the Queue script. To fix the problem make sure that each group of commands with user-specific features has a unique analysisName".format(key, reportGroup))
+ "NA"
+ }
+ }
+
+ def getReportName: String = getReportFeature("jobName")
+
+ def configureJobReport(features: Map[String, Any]) {
+ this.userReportFeatures = features.mapValues(_.toString)
+ }
+
+ def addJobReportBinding(key: String, value: Any) {
+ this.userReportFeatures += (key -> value.toString)
+ }
+
+ // copy the QJobReport information -- todo : what's the best way to do this?
+ override def copySettingsTo(function: QFunction) {
+ self.copySettingsTo(function)
+ function.userReportFeatures = this.userReportFeatures
+ function.reportFeatures = this.reportFeatures
+ }
+}
+
+object QJobReport {
+ // todo -- fixme to have a unique name for Scatter/gather jobs as well
+ var seenCounter = 1
+ var seenNames = Set[String]()
+
+ def workAroundSameJobNames(func: QFunction):String = {
+ if ( seenNames.apply(func.jobName) ) {
+ seenCounter += 1
+ "%s_%d".format(func.jobName, seenCounter)
+ } else {
+ seenNames += func.jobName
+ func.jobName
+ }
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/QJobsReporter.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/QJobsReporter.scala
new file mode 100644
index 0000000..b3b0b33
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/QJobsReporter.scala
@@ -0,0 +1,122 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import java.io.{PrintStream, File}
+import org.broadinstitute.gatk.utils.io.{Resource}
+import org.broadinstitute.gatk.queue.engine.{JobRunInfo, QGraph}
+import org.broadinstitute.gatk.queue.function.QFunction
+import org.broadinstitute.gatk.utils.R.{RScriptLibrary, RScriptExecutor}
+import org.broadinstitute.gatk.engine.report.{GATKReportTable, GATKReport}
+import org.broadinstitute.gatk.utils.exceptions.UserException
+import org.apache.commons.io.{FileUtils, IOUtils}
+
+/**
+ * Writes out RunInfo to a GATKReport
+ */
+class QJobsReporter(val disabled: Boolean, val reportFile: File, val pdfFile: Option[File]) extends Logging {
+ private val JOB_REPORT_QUEUE_SCRIPT = "queueJobReport.R"
+
+ /**
+ * Write out a job report based on the finished jobs graph
+ * @param jobGraph
+ * @param enabledPlotting if true, we will plot the report as well with the JOB_REPORT_QUEUE_SCRIPT
+ */
+ def write(jobGraph: QGraph, enabledPlotting: Boolean) {
+ if ( ! disabled ) {
+ logger.info("Writing JobLogging GATKReport to file " + reportFile)
+ printReport(jobGraph.getFunctionsAndStatus, reportFile)
+
+ if ( enabledPlotting )
+ pdfFile match {
+ case Some(file) =>
+ logger.info("Plotting JobLogging GATKReport to file " + file)
+ plotReport(reportFile, file)
+ case None =>
+ }
+ }
+ }
+
+ private def printReport(jobsRaw: Map[QFunction, JobRunInfo], dest: File) {
+ val jobs = jobsRaw.filter(_._2.isFilledIn).filter(_._1.includeInReport)
+ jobs foreach {case (qf, info) => qf.setRunInfo(info)}
+ val stream = new PrintStream(FileUtils.openOutputStream(dest))
+ try {
+ printJobLogging(jobs.keys.toSeq, stream)
+ } finally {
+ IOUtils.closeQuietly(stream)
+ }
+ }
+
+ private def plotReport(reportFile: File, pdfFile: File) {
+ val executor = new RScriptExecutor
+ executor.addLibrary(RScriptLibrary.GSALIB)
+ executor.addScript(new Resource(JOB_REPORT_QUEUE_SCRIPT, classOf[QJobReport]))
+ executor.addArgs(reportFile.getAbsolutePath, pdfFile.getAbsolutePath)
+ executor.exec()
+ }
+
+ /**
+ * Prints the JobLogging logs to a GATKReport. First splits up the
+ * logs by group, and for each group generates a GATKReportTable
+ */
+ private def printJobLogging(logs: Seq[QFunction], stream: PrintStream) {
+ // create the report
+ val report: GATKReport = new GATKReport
+
+ // create a table for each group of logs
+ for ( (group, groupLogs) <- groupLogs(logs) ) {
+ val keys = logKeys(groupLogs)
+ report.addTable(group, "Job logs for " + group, keys.size)
+ val table: GATKReportTable = report.getTable(group)
+
+ // add the columns
+ keys.foreach(table.addColumn(_))
+ for (log <- groupLogs) {
+ for ( key <- keys )
+ table.set(log.getReportName, key, log.getReportFeature(key))
+ }
+ }
+
+ report.print(stream)
+ }
+
+ private def groupLogs(logs: Seq[QFunction]): Map[String, Seq[QFunction]] = {
+ logs.groupBy(_.getReportGroup)
+ }
+
+ private def logKeys(logs: Seq[QFunction]): Set[String] = {
+ // the keys should be the same for each log, but we will check that
+ val keys = Set[String](logs(0).getReportFeatureNames : _*)
+
+ for ( log <- logs )
+ if ( keys.sameElements(Set(log.getReportFeatureNames)) )
+ throw new UserException(("All JobLogging jobs in the same group must have the same set of features. " +
+ "We found one with %s and another with %s").format(keys, log.getReportFeatureNames))
+
+ keys
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/QScriptUtils.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/QScriptUtils.scala
new file mode 100644
index 0000000..3fbce22
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/QScriptUtils.scala
@@ -0,0 +1,101 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import java.io.File
+import io.Source._
+import htsjdk.samtools.{SAMReadGroupRecord, SAMFileReader}
+
+import collection.JavaConversions._
+
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: carneiro
+ * Date: 7/14/11
+ * Time: 4:57 PM
+ */
+
+object QScriptUtils {
+
+ /**
+ * Takes a bam list file and produces a scala sequence with each file allowing the bam list
+ * to have empty lines and comment lines (lines starting with #).
+ */
+ def createSeqFromFile(in: File):Seq[File] = {
+ // If the file provided ends with .bam, .fasta, fastq or .fq, it is not a bam list, we treat it as a single file.
+ // and return a list with only this file.
+ if (in.toString.toUpperCase.endsWith(".BAM") ||
+ in.toString.toUpperCase.endsWith(".FASTA") ||
+ in.toString.toUpperCase.endsWith(".FQ") ||
+ in.toString.toUpperCase.endsWith("FASTQ") )
+ return Seq(in)
+
+ var list: Seq[File] = Seq()
+ for (file <- fromFile(in).getLines())
+ if (!file.startsWith("#") && !file.isEmpty )
+ list :+= new File(file.trim())
+// list.sortWith(_.compareTo(_) < 0)
+ list
+ }
+
+ /**
+ * Returns the number of contigs in the BAM file header.
+ */
+ def getNumberOfContigs(bamFile: File): Int = {
+ val samReader = new SAMFileReader(bamFile)
+ samReader.getFileHeader.getSequenceDictionary.getSequences.size()
+ }
+
+ /**
+ * Check if there are multiple samples in a BAM file
+ */
+ def hasMultipleSamples(readGroups: Seq[SAMReadGroupRecord]): Boolean = {
+ var sample: String = ""
+ for (r <- readGroups) {
+ if (sample.isEmpty)
+ sample = r.getSample
+ else if (sample != r.getSample)
+ return true
+ }
+ false
+ }
+
+ /**
+ * Returns all distinct samples in the BAM file
+ *
+ * @param bam the bam file
+ * @return a set with all distinct samples (in no particular order)
+ */
+ def getSamplesFromBAM(bam: File) : Set[String] = {
+ val reader = new SAMFileReader(bam)
+ var samples: Set[String] = Set()
+ for (rg <- reader.getFileHeader.getReadGroups) {
+ samples += rg.getSample
+ }
+ samples
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ReflectionUtils.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ReflectionUtils.scala
new file mode 100644
index 0000000..d172e97
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ReflectionUtils.scala
@@ -0,0 +1,170 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import org.broadinstitute.gatk.queue.QException
+import java.lang.annotation.Annotation
+import java.lang.reflect.{ParameterizedType, Field}
+import org.broadinstitute.gatk.utils.commandline.ClassType
+import org.broadinstitute.gatk.utils.classloader.JVMUtils
+
+/**
+ * A collection of scala extensions to the GATK JVMUtils.
+ */
+object ReflectionUtils {
+
+ /**
+ * Returns true if field has the annotation.
+ * @param field Field to check.
+ * @param annotation Class of the annotation to look for.
+ * @return true if field has the annotation.
+ */
+ def hasAnnotation(field: Field, annotation: Class[_ <: Annotation]) = field.getAnnotation(annotation) != null
+
+ /**
+ * Returns true if clazz or one of its superclasses has the annotation.
+ * @param clazz Class to check.
+ * @param annotation Class of the annotation to look for.
+ * @return true if field has the annotation.
+ */
+ def hasAnnotation(clazz: Class[_], annotation: Class[_ <: Annotation]) = {
+ var foundAnnotation = false
+ while (!foundAnnotation && clazz != null)
+ foundAnnotation = (clazz.getAnnotation(annotation) != null)
+ foundAnnotation
+ }
+
+ /**
+ * Gets the annotation or throws an exception if the annotation is not found.
+ * @param field Field to check.
+ * @param annotation Class of the annotation to look for.
+ * @return The annotation.
+ */
+ def getAnnotation[T <: Annotation](field: Field, annotation: Class[T]): T = {
+ field.getAnnotation(annotation) match {
+ case null =>
+ throw new QException("Field %s is missing annotation %s".format(field, annotation))
+ case fieldAnnotation => fieldAnnotation.asInstanceOf[T]
+ }
+ }
+
+ /**
+ * Gets the annotation or throws an exception if the annotation is not found.
+ * @param clazz Class to check.
+ * @param annotation Class of the annotation to look for.
+ * @return The annotation.
+ */
+ def getAnnotation[T <: Annotation](clazz: Class[_], annotation: Class[T]): T = {
+ var result: T = null.asInstanceOf[T]
+ while (result == null && clazz != null)
+ result = clazz.getAnnotation(annotation)
+ if (result == null)
+ throw new QException("Class %s is missing annotation %s".format(clazz, annotation))
+ result
+ }
+
+ /**
+ * Returns all the declared fields on a class in order of sub type to super type.
+ * @param clazz Base class to start looking for fields.
+ * @return Seq[Field] found on the class and all super classes.
+ */
+ def getAllFields(clazz: Class[_]) = getAllTypes(clazz).map(_.getDeclaredFields).flatMap(_.toSeq)
+
+ /**
+ * Gets all the types on a class in order of sub type to super type.
+ * @param clazz Base class.
+ * @return Seq[Class] including the class and all super classes.
+ */
+ def getAllTypes(clazz: Class[_]) = {
+ var types = Seq.empty[Class[_]]
+ var c = clazz
+ while (c != null) {
+ types :+= c
+ c = c.getSuperclass
+ }
+ types
+ }
+
+ /**
+ * Gets a field value using reflection.
+ * Attempts to use the scala getter then falls back to directly accessing the field.
+ * @param obj Object to inspect.
+ * @param field Field to retrieve.
+ * @return The field value.
+ */
+ def getValue(obj: AnyRef, field: Field): AnyRef =
+ try {
+ field.getDeclaringClass.getMethod(field.getName).invoke(obj)
+ } catch {
+ case e: NoSuchMethodException => JVMUtils.getFieldValue(field, obj)
+ }
+
+ /**
+ * Sets a field value using reflection.
+ * Attempts to use the scala setter then falls back to directly accessing the field.
+ * @param obj Object to inspect.
+ * @param field Field to set.
+ * @param value The new field value.
+ */
+ def setValue(obj: AnyRef, field: Field, value: Any) =
+ try {
+ field.getDeclaringClass.getMethod(field.getName+"_$eq", field.getType).invoke(obj, value.asInstanceOf[AnyRef])
+ } catch {
+ case e: NoSuchMethodException => JVMUtils.setFieldValue(field, obj, value)
+ }
+
+ /**
+ * Returns the collection type of a field or throws an exception if the field contains more than one parameterized type, or the collection type cannot be found.
+ * @param field Field to retrieve the collection type.
+ * @return The collection type for the field.
+ */
+ def getCollectionType(field: Field) = {
+ getGenericTypes(field) match {
+ case Some(classes) =>
+ if (classes.length > 1)
+ throw new IllegalArgumentException("Field contains more than one generic type: " + field)
+ classes(0)
+ case None =>
+ throw new QException("Generic type not set for collection. Did it declare an @ClassType?: " + field)
+ }
+ }
+
+ /**
+ * Returns the generic types for a field or None.
+ * @param field Field to retrieve the collection type.
+ * @return The array of classes that are in the collection type, or None if the type cannot be found.
+ */
+ private def getGenericTypes(field: Field): Option[Array[Class[_]]] = {
+ // TODO: Refactor: based on java code in org.broadinstitute.gatk.utils.commandline.ArgumentTypeDescriptor
+ // If this is a parameterized collection, find the contained type. If blow up if only one type exists.
+ if (hasAnnotation(field, classOf[ClassType])) {
+ Some(Array(getAnnotation(field, classOf[ClassType]).value))
+ } else if (field.getGenericType.isInstanceOf[ParameterizedType]) {
+ val parameterizedType = field.getGenericType.asInstanceOf[ParameterizedType]
+ Some(parameterizedType.getActualTypeArguments.map(_.asInstanceOf[Class[_]]))
+ } else None
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/RemoteFile.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/RemoteFile.scala
new file mode 100644
index 0000000..1410813
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/RemoteFile.scala
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import java.io.File
+import org.broadinstitute.gatk.utils.io.FileExtension
+import java.util.Date
+import java.net.URL
+
+/**
+ * An extension of java.io.File that can be pulled from or pushed to a remote location.
+ */
+trait RemoteFile extends File with FileExtension {
+ def pullToLocal()
+ def pushToRemote()
+ def deleteRemote()
+ def createUrl(expiration: Date): URL
+ def remoteDescription: String
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/RemoteFileConverter.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/RemoteFileConverter.scala
new file mode 100644
index 0000000..b38b27a
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/RemoteFileConverter.scala
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import java.io.File
+
+trait RemoteFileConverter {
+ type RemoteFileType <: RemoteFile
+
+ /**
+ * If this remote file creator is capable of converting to a remote file.
+ * @return true if ready to convert
+ */
+ def convertToRemoteEnabled: Boolean
+
+ /**
+ * Converts to a remote file
+ * @param file The original file
+ * @param name A "name" to use for the remote file
+ * @return The new version of this remote file.
+ */
+ def convertToRemote(file: File, name: String): RemoteFileType
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/Retry.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/Retry.scala
new file mode 100644
index 0000000..8d1c1cf
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/Retry.scala
@@ -0,0 +1,70 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import org.broadinstitute.gatk.queue.util.TextFormatUtils._
+
+/**
+ * Utilities for retrying a function and waiting a number of minutes.
+ */
+object Retry extends Logging {
+ /**
+ * Attempt the function and return the value on success.
+ * Each time the function fails the stack trace is logged.
+ * @param f Function to run and return its value.
+ * @param wait The length in minutes to wait before each attempt.
+ * @throws RetryException when all retries are exhausted.
+ * @return The successful result of f.
+ */
+ def attempt[A](f: () => A, wait: Double*): A = {
+ var count = 0
+ var success = false
+ val tries = wait.size + 1
+ var result = null.asInstanceOf[A]
+ while (!success && count < tries) {
+ try {
+ result = f()
+ success = true
+ } catch {
+ case e: Exception=> {
+ count += 1
+ if (count < tries) {
+ val minutes = wait(count-1)
+ logger.error("Caught error during attempt %s of %s."
+ .format(count, tries), e)
+ logger.error("Retrying in %.1f minute%s.".format(minutes, plural(minutes)))
+ Thread.sleep((minutes * 1000 * 60).toLong)
+ } else {
+ logger.error("Caught error during attempt %s of %s. Giving up."
+ .format(count, tries), e)
+ throw new RetryException("Gave up after %s attempts.".format(tries), e)
+ }
+ }
+ }
+ }
+ result
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/RetryException.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/RetryException.scala
new file mode 100644
index 0000000..ffd69cc
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/RetryException.scala
@@ -0,0 +1,34 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import org.broadinstitute.gatk.queue.QException
+
+/**
+ * Thrown after giving up on retrying.
+ */
+class RetryException(private val message: String, private val throwable: Throwable)
+ extends QException(message, throwable) {}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ScalaCompoundArgumentTypeDescriptor.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ScalaCompoundArgumentTypeDescriptor.scala
new file mode 100644
index 0000000..80ab068
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ScalaCompoundArgumentTypeDescriptor.scala
@@ -0,0 +1,114 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import collection.JavaConversions._
+import org.broadinstitute.gatk.queue.QException
+import java.lang.Class
+import org.broadinstitute.gatk.utils.commandline.{ArgumentMatches, ArgumentSource, ArgumentTypeDescriptor, ParsingEngine}
+import org.broadinstitute.gatk.utils.exceptions.UserException
+import java.lang.reflect.Type
+
+/**
+ * An ArgumentTypeDescriptor that can parse the scala collections.
+ */
+class ScalaCompoundArgumentTypeDescriptor extends ArgumentTypeDescriptor {
+
+ /**
+ * Checks if the class type is a scala collection.
+ * @param classType Class type to check.
+ * @return true if the class is a Seq, Set, or an Option.
+ */
+ def supports(classType: Class[_]) = isCompound(classType)
+
+ /**
+ * Checks if the class type is a scala collection.
+ * @param source Argument source to check.
+ * @return true if the source is a Seq, Set, or an Option.
+ */
+ override def isMultiValued(source: ArgumentSource) = isCompound(source.field.getType)
+
+ /**
+ * Checks if the class type is a scala collection.
+ * @param classType Class type to check.
+ * @return true if the class is a Seq, Set, or an Option.
+ */
+ private def isCompound(classType: Class[_]) = {
+ classOf[Seq[_]].isAssignableFrom(classType) ||
+ classOf[List[_]].isAssignableFrom(classType) || // see comment below re: List vs. Seq
+ classOf[Set[_]].isAssignableFrom(classType) ||
+ classOf[Option[_]].isAssignableFrom(classType)
+ }
+
+ /**
+ * Parses the argument matches based on the class type of the argument source's field.
+ * @param parsingEngine Parsing engine.
+ * @param source Argument source that contains the field being populated.
+ * @param typeType Type of the argument source's field.
+ * @param argumentMatches The argument match strings that were found for this argument source.
+ * @return The parsed object.
+ */
+ def parse(parsingEngine: ParsingEngine, source: ArgumentSource, typeType: Type, argumentMatches: ArgumentMatches) = {
+ parse(parsingEngine,source, ArgumentTypeDescriptor.makeRawTypeIfNecessary(typeType), argumentMatches)
+ }
+
+ def parse(parsingEngine: ParsingEngine, source: ArgumentSource, classType: Class[_], argumentMatches: ArgumentMatches) = {
+ val componentType = ReflectionUtils.getCollectionType(source.field)
+ if (componentType == classOf[java.lang.Object])
+ throw new UserException.CannotExecuteQScript("Please also include a @ClassType(classOf[<primitive type>]) annotation on field: " + source.field + ". Example: @ClassType(classOf[Double]). The scala generic type for the field was subjected to java/scala type erasure and is not available via reflection.")
+ val componentArgumentParser = parsingEngine.selectBestTypeDescriptor(componentType)
+
+ if (classOf[Seq[_]].isAssignableFrom(classType)) {
+ var seq = Seq.empty[Any]
+ for (argumentMatch <- argumentMatches)
+ for (value <- argumentMatch)
+ seq :+= componentArgumentParser.parse(parsingEngine, source, componentType, new ArgumentMatches(value))
+ seq
+ } else if (classOf[List[_]].isAssignableFrom(classType)) {
+ // QScripts should be using the interface Seq instead of the class List.
+ // Leaving this here for now for legacy support until the effects of switching have been tested for a while. -ks
+ var list = List.empty[Any]
+ for (argumentMatch <- argumentMatches)
+ for (value <- argumentMatch)
+ list :+= componentArgumentParser.parse(parsingEngine, source, componentType, new ArgumentMatches(value))
+ list
+ } else if (classOf[Set[_]].isAssignableFrom(classType)) {
+ var set = Set.empty[Any]
+ for (argumentMatch <- argumentMatches)
+ for (value <- argumentMatch)
+ set += componentArgumentParser.parse(parsingEngine, source, componentType, new ArgumentMatches(value))
+ set
+ } else if (classOf[Option[_]].isAssignableFrom(classType)) {
+ if (argumentMatches.size > 1)
+ throw new QException("Unable to set Option to multiple values: " + argumentMatches.mkString(" "))
+ else if (argumentMatches.size == 1)
+ Some(componentArgumentParser.parse(parsingEngine, source, componentType, argumentMatches))
+ else
+ None
+ } else
+ throw new QException("Unsupported compound argument type: " + classType)
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ShellUtils.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ShellUtils.scala
new file mode 100644
index 0000000..02d767a
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/ShellUtils.scala
@@ -0,0 +1,61 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import java.lang.IllegalArgumentException
+
+object ShellUtils {
+
+ /**
+ * Escapes the String it's passed so that it will be interpreted literally when
+ * parsed by sh/bash. Can correctly escape all characters except \0, \r, and \n
+ *
+ * Replaces all instances of ' with '\'', and then surrounds the resulting String
+ * with single quotes.
+ *
+ * Examples:
+ * ab -> 'ab'
+ * a'b -> 'a'\''b'
+ * '' -> ''\'''\'''
+ *
+ * Since \' is not supported inside single quotes in the shell (ie., '\'' does not work),
+ * whenever we encounter a single quote we need to terminate the existing single-quoted
+ * string, place the \' outside of single quotes, and then start a new single-quoted
+ * string. As long as we don't insert spaces between the separate strings, the shell will
+ * concatenate them together into a single argument value for us.
+ *
+ * @param str the String to escape
+ * @return the same String quoted so that it will be interpreted literally when
+ * parsed by sh/bash
+ */
+ def escapeShellArgument ( str : String ) : String = {
+ if ( str == null ) {
+ throw new IllegalArgumentException("escapeShellArgument() was passed a null String")
+ }
+
+ "'" + str.replaceAll("'", "'\\\\''") + "'"
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/StringFileConversions.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/StringFileConversions.scala
new file mode 100644
index 0000000..ee21380
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/StringFileConversions.scala
@@ -0,0 +1,113 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import java.io.{Serializable, File}
+import scala.language.implicitConversions
+
+/**
+ * Converts String to/from File
+ * The method signatures are based on the compiler errors reported by StringFileConversionsUnitTest.
+ * The implementations are based on the runtime errors reported by StringFileConversionsUnitTest.
+ */
+object StringFileConversions {
+ implicit def stringAsFile(x: String): File = {
+ if (x == null) null else new File(x)
+ }
+
+ implicit def fileAsString(x: File): String = {
+ if (x == null) null else x.getPath
+ }
+
+ // Possible to get the invariants, covariants, contravariants, upper type bounds, lower type bounds
+ // and mixins all correct so this doesn't have to be duplicated with concrete implementations?
+ // http://programming-scala.labs.oreilly.com/ch12.html is your friend.
+
+ implicit def stringsAsFiles(x: Seq[Comparable[_ >: String with File <: Comparable[_ >: String with File <: Serializable] with Serializable] with Serializable]): Seq[File] = {
+ x.map(_ match {
+ case string: String => stringAsFile(string)
+ case file: File => file
+ case null => null
+ })
+ }
+
+ implicit def filesAsStrings(x: Seq[Comparable[_ >: File with String <: Comparable[_ >: File with String <: Serializable] with Serializable] with Serializable]): Seq[String] = {
+ x.map(_ match {
+ case file: File => fileAsString(file)
+ case string: String => string
+ case null => null
+ })
+ }
+
+ implicit def stringsAsFilesList(x: List[Comparable[_ >: String with File <: Comparable[_ >: String with File <: Serializable] with Serializable] with Serializable]): List[File] = {
+ x.map(_ match {
+ case string: String => stringAsFile(string)
+ case file: File => file
+ case null => null
+ })
+ }
+
+ implicit def filesAsStringsList(x: List[Comparable[_ >: File with String <: Comparable[_ >: File with String <: Serializable] with Serializable] with Serializable]): List[String] = {
+ x.map(_ match {
+ case file: File => fileAsString(file)
+ case string: String => string
+ case null => null
+ })
+ }
+
+}
+
+/**
+ * Converts String to/from File
+ * The method signatures are based on the compiler errors reported by StringFileConversionsUnitTest.
+ * The implementations are based on the runtime errors reported by StringFileConversionsUnitTest.
+ */
+trait StringFileConversions {
+ implicit def stringAsFile(x: String): File = {
+ StringFileConversions.stringAsFile(x)
+ }
+
+ implicit def fileAsString(x: File): String = {
+ StringFileConversions.fileAsString(x)
+ }
+
+ implicit def stringsAsFiles(x: Seq[Comparable[_ >: String with File <: Comparable[_ >: String with File <: Serializable] with Serializable] with Serializable]): Seq[File] = {
+ StringFileConversions.stringsAsFiles(x)
+ }
+
+ implicit def filesAsStrings(x: Seq[Comparable[_ >: File with String <: Comparable[_ >: File with String <: Serializable] with Serializable] with Serializable]): Seq[String] = {
+ StringFileConversions.filesAsStrings(x)
+ }
+
+ implicit def stringsAsFilesList(x: List[Comparable[_ >: String with File <: Comparable[_ >: String with File <: Serializable] with Serializable] with Serializable]): List[File] = {
+ StringFileConversions.stringsAsFilesList(x)
+ }
+
+ implicit def filesAsStringsList(x: List[Comparable[_ >: File with String <: Comparable[_ >: File with String <: Serializable] with Serializable] with Serializable]): List[String] = {
+ StringFileConversions.filesAsStringsList(x)
+ }
+
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/SystemUtils.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/SystemUtils.scala
new file mode 100644
index 0000000..cf85372
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/SystemUtils.scala
@@ -0,0 +1,67 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import java.net.InetAddress
+import java.io.File
+import io.Source
+
+/**
+ * A collection of various system utilities.
+ */
+object SystemUtils extends Logging {
+ private val localAddress = {
+ try {
+ InetAddress.getLocalHost
+ } catch {
+ case e: Exception =>
+ InetAddress.getLoopbackAddress
+ }
+ }
+ val inetAddress = localAddress.getHostAddress
+ val canonicalHostName = localAddress.getCanonicalHostName
+
+ val hostName = {
+ if (canonicalHostName != inetAddress)
+ canonicalHostName
+ else
+ localAddress.getHostName
+ }
+
+ val mailName = {
+ val mailnameFile = new File("/etc/mailname")
+ if (mailnameFile.exists)
+ try {
+ Source.fromFile(mailnameFile).mkString.trim
+ } catch {
+ case e: Exception =>
+ logger.error("Unabled to read mail domain. Using hostname.", e)
+ hostName.split('.').takeRight(2).mkString(".")
+ }
+ else
+ hostName.split('.').takeRight(2).mkString(".")
+ }
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/TextFormatUtils.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/TextFormatUtils.scala
new file mode 100644
index 0000000..c776dd5
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/TextFormatUtils.scala
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+object TextFormatUtils {
+ /**
+ * Returns the string "s" if x is greater than 1.
+ * @param x Value to test.
+ * @return "s" if x is greater than one else "".
+ */
+ def plural(x: Int) = if (x > 1) "s" else ""
+
+ /**
+ * Returns the string "s" if x is greater than 1.
+ * @param x Value to test.
+ * @return "s" if x is greater than one else "".
+ */
+ def plural(x: Long) = if (x > 1) "s" else ""
+
+ /**
+ * Returns the string "s" if x is not equal to 1.
+ * @param x Value to test.
+ * @return "s" if x is greater than one else "".
+ */
+ def plural(x: Float) = if (x != 1) "s" else ""
+
+ /**
+ * Returns the string "s" if x is not equal to 1.
+ * @param x Value to test.
+ * @return "s" if x is greater than one else "".
+ */
+ def plural(x: Double) = if (x != 1) "s" else ""
+}
diff --git a/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/VCF_BAM_utilities.scala b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/VCF_BAM_utilities.scala
new file mode 100644
index 0000000..9de4b28
--- /dev/null
+++ b/public/gatk-queue/src/main/scala/org/broadinstitute/gatk/queue/util/VCF_BAM_utilities.scala
@@ -0,0 +1,79 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import java.io.File
+import org.apache.commons.io.FilenameUtils
+import scala.io.Source._
+import htsjdk.samtools.SAMFileReader
+import htsjdk.variant.vcf.{VCFHeader, VCFCodec}
+import scala.collection.JavaConversions._
+import htsjdk.tribble.AbstractFeatureReader
+
+object VCF_BAM_utilities {
+
+ def getSamplesFromVCF(vcfFile: File): List[String] = {
+ AbstractFeatureReader.getFeatureReader(vcfFile.getPath, new VCFCodec()).getHeader.asInstanceOf[VCFHeader].getGenotypeSamples.toList
+ }
+
+ def getSamplesInBAM(bam: File): List[String] = {
+ return new SAMFileReader(bam).getFileHeader().getReadGroups().toList.map(srgr => srgr.getSample()).toSet.toList
+ }
+
+ def parseBAMsInput(bamsIn: File): List[File] = FilenameUtils.getExtension(bamsIn.getPath) match {
+ case "bam" => return List(bamsIn)
+ case "list" => return (for (line <- fromFile(bamsIn).getLines) yield new File(line)).toList
+ case _ => throw new RuntimeException("Unexpected BAM input type: " + bamsIn + "; only permitted extensions are .bam and .list")
+ }
+
+ def getMapOfBAMsForSample(bams: List[File]): scala.collection.mutable.Map[String, scala.collection.mutable.Set[File]] = {
+ var m = scala.collection.mutable.Map.empty[String, scala.collection.mutable.Set[File]]
+
+ for (bam <- bams) {
+ val bamSamples: List[String] = getSamplesInBAM(bam)
+ for (s <- bamSamples) {
+ if (!m.contains(s))
+ m += s -> scala.collection.mutable.Set.empty[File]
+
+ m(s) += bam
+ }
+ }
+
+ return m
+ }
+
+ def findBAMsForSamples(samples: List[String], sampleToBams: scala.collection.mutable.Map[String, scala.collection.mutable.Set[File]]): List[File] = {
+ var s = scala.collection.mutable.Set.empty[File]
+
+ for (sample <- samples) {
+ if (sampleToBams.contains(sample))
+ s ++= sampleToBams(sample)
+ }
+
+ val l: List[File] = Nil
+ return l ++ s
+ }
+}
diff --git a/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/function/CommandLineFunctionUnitTest.scala b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/function/CommandLineFunctionUnitTest.scala
new file mode 100644
index 0000000..351fb71
--- /dev/null
+++ b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/function/CommandLineFunctionUnitTest.scala
@@ -0,0 +1,196 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.function
+
+import org.testng.Assert
+import org.testng.annotations.{DataProvider, Test}
+
+// Since "protected" in Scala is subclass-only and doesn't allow package-level access, we need to
+// extend a class if we want to test it
+class CommandLineFunctionUnitTest extends CommandLineFunction {
+ def commandLine = ""
+
+ @DataProvider( name="formatArgumentTestData" )
+ def formatArgumentDataProvider = {
+ Array(Array("", "argvalue", "", true, true, "'argvalue'"),
+ Array("", "argvalue", "", true, false, "argvalue"),
+ Array("", "argvalue", "", false, true, "'argvalue'"),
+ Array("", "argvalue", "", false, false, "argvalue"),
+ Array("-arg", "argvalue", "", true, true, "'-arg' 'argvalue'"),
+ Array("-arg", "argvalue", "", true, false, "-arg argvalue"),
+ Array("ARGNAME=", "ARGVALUE", "", false, true, "'ARGNAME=ARGVALUE'"),
+ Array("ARGNAME=", "ARGVALUE", "", false, false, "ARGNAME=ARGVALUE"),
+ Array("-Xmx", "4", "G", true, true, "'-Xmx' '4' 'G'"),
+ Array("-Xmx", "4", "G", true, false, "-Xmx 4 G"),
+ Array("-Xmx", "4", "G", false, true, "'-Xmx4G'"),
+ Array("-Xmx", "4", "G", false, false, "-Xmx4G"),
+ Array("", "", "", true, true, "''"),
+ Array("", "", "", true, false, ""),
+ Array("", "", "", false, true, "''"),
+ Array("", "", "", false, false, ""),
+ Array("", null, "", true, true, ""),
+ Array("", Nil, "", true, true, ""),
+ Array("", None, "", true, true, ""),
+ Array(null, null, null, true, true, ""),
+ Array("", Some("argvalue"), "", true, true, "'argvalue'")
+ )
+ }
+
+ @Test( dataProvider="formatArgumentTestData" )
+ def testFormatArgument( prefix: String, param: Any, suffix: String, spaceSeparated: Boolean, escape: Boolean, expectedReturnValue: String ) {
+ Assert.assertEquals(formatArgument(prefix, param, suffix, spaceSeparated, escape, "%s"),
+ expectedReturnValue)
+ }
+
+ @Test
+ def testFormatArgumentCustomFormatString() {
+ Assert.assertEquals(formatArgument("", "argvalue", "", true, true, "%.3s"), "'arg'")
+ }
+
+ @DataProvider( name = "requiredTestData" )
+ def requiredDataProvider = {
+ Array(Array("", "argvalue", "", true, true, " 'argvalue' "),
+ Array("", "argvalue", "", true, false, " argvalue "),
+ Array("", "argvalue", "", false, true, " 'argvalue' "),
+ Array("", "argvalue", "", false, false, " argvalue "),
+ Array("-arg", "argvalue", "", true, true, " '-arg' 'argvalue' "),
+ Array("-arg", "argvalue", "", true, false, " -arg argvalue "),
+ Array("ARGNAME=", "ARGVALUE", "", false, true, " 'ARGNAME=ARGVALUE' "),
+ Array("ARGNAME=", "ARGVALUE", "", false, false, " ARGNAME=ARGVALUE "),
+ Array("-Xmx", "4", "G", true, true, " '-Xmx' '4' 'G' "),
+ Array("-Xmx", "4", "G", true, false, " -Xmx 4 G "),
+ Array("-Xmx", "4", "G", false, true, " '-Xmx4G' "),
+ Array("-Xmx", "4", "G", false, false, " -Xmx4G "),
+ Array("", "", "", true, true, " '' "),
+ Array("", "", "", true, false, " "),
+ Array("", "", "", false, true, " '' "),
+ Array("", "", "", false, false, " "),
+ Array("", null, "", true, true, " "),
+ Array("", Nil, "", true, true, " "),
+ Array("", None, "", true, true, " ")
+ )
+ }
+
+ @Test( dataProvider="requiredTestData" )
+ def testRequired( prefix: String, param: Any, suffix: String, spaceSeparated: Boolean, escape: Boolean, expectedReturnValue: String ) {
+ Assert.assertEquals(required(prefix, param, suffix, spaceSeparated, escape),
+ expectedReturnValue)
+ }
+
+ @DataProvider( name = "optionalTestData" )
+ def optionalDataProvider = {
+ Array(Array("-arg", "argvalue", "", true, true, " '-arg' 'argvalue' "),
+ Array("-arg", null, "", true, true, ""),
+ Array("-arg", Nil, "", true, true, ""),
+ Array("-arg", None, "", true, true, ""),
+ Array("-arg", "", "", true, true, " '-arg' ")
+ )
+ }
+
+ @Test( dataProvider="optionalTestData" )
+ def testOptional( prefix: String, param: Any, suffix: String, spaceSeparated: Boolean, escape: Boolean, expectedReturnValue: String ) {
+ Assert.assertEquals(optional(prefix, param, suffix, spaceSeparated, escape),
+ expectedReturnValue)
+ }
+
+ @DataProvider( name = "conditionalTestData" )
+ def conditionalDataProvider = {
+ Array(Array(true, "-FLAG", true, " '-FLAG' "),
+ Array(true, "-FLAG", false, " -FLAG "),
+ Array(false, "-FLAG", true, ""),
+ Array(false, "-FLAG", false, ""),
+ Array(true, null, true, " "),
+ Array(true, Nil, true, " "),
+ Array(true, None, true, " "),
+ Array(false, null, true, ""),
+ Array(false, Nil, true, ""),
+ Array(false, None, true, "")
+ )
+ }
+
+ @Test( dataProvider="conditionalTestData" )
+ def testConditional( condition: Boolean, param: Any, escape: Boolean, expectedReturnValue: String ) {
+ Assert.assertEquals(conditional(condition, param, escape),
+ expectedReturnValue)
+ }
+
+ @DataProvider( name = "repeatTestData" )
+ def repeatDataProvider = {
+ Array(Array("", Seq("a", "bc", "d"), "", " ", true, true, " 'a' 'bc' 'd' "),
+ Array("", Seq("a", "bc", "d"), "", " ", true, false, " a bc d "),
+ Array("", Seq("a", "bc", "d"), "", "", true, true, " 'a''bc''d' "),
+ Array("", Seq("a", "bc", "d"), "", "", true, false, " abcd "),
+ Array("-f", Seq("file1", "file2", "file3"), "", " ", true, true, " '-f' 'file1' '-f' 'file2' '-f' 'file3' "),
+ Array("-f", Seq("file1", "file2", "file3"), "", " ", true, false, " -f file1 -f file2 -f file3 "),
+ Array("-f", Seq("file1", "file2", "file3"), "", " ", false, true, " '-ffile1' '-ffile2' '-ffile3' "),
+ Array("-f", Seq("file1", "file2", "file3"), "", " ", false, false, " -ffile1 -ffile2 -ffile3 "),
+ Array("-f", Seq("file1", "file2", "file3"), "", "", false, true, " '-ffile1''-ffile2''-ffile3' "),
+ Array("-f", Seq("file1", "file2", "file3"), "", "", false, false, " -ffile1-ffile2-ffile3 "),
+ Array("-f", Seq("file1", "file2", "file3"), "suffix", " ", true, true, " '-f' 'file1' 'suffix' '-f' 'file2' 'suffix' '-f' 'file3' 'suffix' "),
+ Array("-f", Seq("file1", "file2", "file3"), "suffix", " ", true, false, " -f file1 suffix -f file2 suffix -f file3 suffix "),
+ Array("-f", Seq("file1", "file2", "file3"), "suffix", " ", false, true, " '-ffile1suffix' '-ffile2suffix' '-ffile3suffix' "),
+ Array("-f", Seq("file1", "file2", "file3"), "suffix", " ", false, false, " -ffile1suffix -ffile2suffix -ffile3suffix "),
+ Array("-f", null, "", " ", true, true, ""),
+ Array("-f", Nil, "", " ", true, true, "")
+ )
+ }
+
+ @Test( dataProvider="repeatTestData" )
+ def testRepeat( prefix: String, params: Traversable[_], suffix: String, separator: String,
+ spaceSeparated: Boolean, escape: Boolean, expectedReturnValue: String ) {
+ Assert.assertEquals(repeat(prefix, params, suffix, separator, spaceSeparated, escape),
+ expectedReturnValue)
+ }
+
+ // Need to test None separately due to implicit conversion issues when using None in a TestNG data provider
+ @Test
+ def testRepeatNone() {
+ testRepeat("", None, "", " ", true, true, "")
+ }
+
+ @DataProvider( name = "repeatWithPrefixFormattingTestData" )
+ def repeatWithPrefixFormattingDataProvider = {
+ Array(Array("-f", Seq("file1", "file2", "file3"), "", " ", true, true, (prefix: String, value: Any) => "%s:tag%s".format(prefix, value),
+ " '-f:tagfile1' 'file1' '-f:tagfile2' 'file2' '-f:tagfile3' 'file3' "),
+ Array("-f", Seq("file1", "file2", "file3"), "", " ", true, false, (prefix: String, value: Any) => "%s:tag%s".format(prefix, value),
+ " -f:tagfile1 file1 -f:tagfile2 file2 -f:tagfile3 file3 "),
+ Array("", Seq("file1", "file2", "file3"), "", " ", true, true, (prefix: String, value: Any) => "-%s".format(value),
+ " '-file1' 'file1' '-file2' 'file2' '-file3' 'file3' "),
+ Array("-f", null, "", " ", true, true, (prefix: String, value: Any) => "%s:tag%s".format(prefix, value),
+ ""),
+ Array("-f", Nil, "", " ", true, true, (prefix: String, value: Any) => "%s:tag%s".format(prefix, value),
+ "")
+ )
+ }
+
+ @Test( dataProvider = "repeatWithPrefixFormattingTestData" )
+ def testRepeatWithPrefixFormatting( prefix: String, params: Traversable[_], suffix: String, separator: String,
+ spaceSeparated: Boolean, escape: Boolean, formatPrefix: (String, Any) => String,
+ expectedReturnValue: String ) {
+ Assert.assertEquals(repeat(prefix, params, suffix, separator, spaceSeparated, escape, "%s", formatPrefix),
+ expectedReturnValue)
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/pipeline/QueueTest.scala b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/pipeline/QueueTest.scala
new file mode 100644
index 0000000..62ac8e1
--- /dev/null
+++ b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/pipeline/QueueTest.scala
@@ -0,0 +1,265 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.pipeline
+
+import org.broadinstitute.gatk.utils.Utils
+import org.testng.Assert
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram
+import java.util.Date
+import java.text.SimpleDateFormat
+import org.broadinstitute.gatk.utils.BaseTest
+import org.broadinstitute.gatk.utils.MD5DB
+import org.broadinstitute.gatk.queue.{QScript, QCommandLine}
+import org.broadinstitute.gatk.queue.util.Logging
+import java.io.{FilenameFilter, File}
+import org.broadinstitute.gatk.engine.report.GATKReport
+import org.apache.commons.io.FileUtils
+import org.apache.commons.io.filefilter.WildcardFileFilter
+
+object QueueTest extends BaseTest with Logging {
+
+ private final val qscriptsSrcDir = "src/main/qscripts/"
+ private final val qscriptsPackageDir = qscriptsSrcDir + "org/broadinstitute/gatk/queue/qscripts/"
+ final val publicQScriptsPackageDir = BaseTest.gatkDirectory + "public/gatk-queue-extensions-public/" + qscriptsPackageDir
+ final val protectedQScriptsPackageDir = BaseTest.gatkDirectory + "protected/gatk-queue-extensions-distribution/" + qscriptsPackageDir
+ final val privateQScriptsPackageDir = BaseTest.gatkDirectory + "private/gatk-queue-extensions-internal/" + qscriptsPackageDir
+
+ private val validationReportsDataLocation = "/humgen/gsa-hpprojects/GATK/validationreports/submitted/"
+ private val md5DB = new MD5DB()
+
+ /**
+ * All the job runners configured to run QueueTests at The Broad.
+ */
+ final val allJobRunners = Seq("Lsf706", "GridEngine", "Shell")
+
+ /**
+ * The default job runners to run.
+ */
+ final val defaultJobRunners = Seq("Lsf706", "GridEngine")
+
+ /**
+ * Returns the top level output path to this test.
+ * @param testName The name of the test passed to QueueTest.executeTest()
+ * @param jobRunner The name of the job manager to run the jobs.
+ * @return the top level output path to this test.
+ */
+ def testDir(testName: String, jobRunner: String) = "queuetests/%s/%s/".format(testName, jobRunner)
+
+ /**
+ * Returns the directory where relative output files will be written for this test.
+ * @param testName The name of the test passed to QueueTest.executeTest()
+ * @param jobRunner The name of the job manager to run the jobs.
+ * @return the directory where relative output files will be written for this test.
+ */
+ private def runDir(testName: String, jobRunner: String) = testDir(testName, jobRunner) + "run/"
+
+ /**
+ * Returns the directory where temp files will be written for this test.
+ * @param testName The name of the test passed to QueueTest.executeTest()
+ * @param jobRunner The name of the job manager to run the jobs.
+ * @return the directory where temp files will be written for this test.
+ */
+ private def tempDir(testName: String, jobRunner: String) = testDir(testName, jobRunner) + "temp/"
+
+ /**
+ * Runs the queueTest.
+ * @param queueTest test to run.
+ */
+ def executeTest(queueTest: QueueTestSpec) {
+ var jobRunners = queueTest.jobRunners
+ if (jobRunners == null)
+ jobRunners = defaultJobRunners
+ jobRunners.foreach(executeTest(queueTest, _))
+ }
+
+ /**
+ * Runs the queueTest.
+ * @param queueTest test to run.
+ * @param jobRunner The name of the job manager to run the jobs.
+ */
+ def executeTest(queueTest: QueueTestSpec, jobRunner: String) {
+ // Reset the order of functions added to the graph.
+ QScript.resetAddOrder()
+
+ val name = queueTest.name
+ if (name == null)
+ Assert.fail("QueueTestSpec.name is null")
+ println(Utils.dupString('-', 80))
+ executeTest(name, queueTest.args, queueTest.jobQueue, queueTest.expectedException, jobRunner)
+ if (BaseTest.queueTestRunModeIsSet) {
+ assertMatchingMD5s(name, queueTest.fileMD5s.map{case (file, md5) => new File(runDir(name, jobRunner), file) -> md5}, queueTest.parameterize)
+ if (queueTest.evalSpec != null)
+ validateEval(name, queueTest.evalSpec, jobRunner)
+ for (path <- queueTest.expectedFilePaths)
+ assertPathExists(runDir(name, jobRunner), path)
+ for (path <- queueTest.unexpectedFilePaths)
+ assertPathDoesNotExist(runDir(name, jobRunner), path)
+ println(" => %s PASSED (%s)".format(name, jobRunner))
+ }
+ else
+ println(" => %s PASSED DRY RUN (%s)".format(name, jobRunner))
+ }
+
+ private def assertMatchingMD5s(name: String, fileMD5s: Traversable[(File, String)], parameterize: Boolean) {
+ var failed = 0
+ for ((file, expectedMD5) <- fileMD5s) {
+ val calculatedMD5 = md5DB.testFileMD5(name, "", file, expectedMD5, parameterize).actualMD5
+ if (!parameterize && expectedMD5 != "" && expectedMD5 != calculatedMD5)
+ failed += 1
+ }
+ if (failed > 0)
+ Assert.fail("%d of %d MD5s did not match".format(failed, fileMD5s.size))
+ }
+
+ private def validateEval(name: String, evalSpec: QueueTestEvalSpec, jobRunner: String) {
+ // write the report to the shared validation data location
+ val formatter = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss")
+ val reportLocation = "%s%s/%s/validation.%s.eval".format(validationReportsDataLocation, jobRunner, name, formatter.format(new Date))
+ val reportFile = new File(reportLocation)
+
+ FileUtils.copyFile(new File(runDir(name, jobRunner) + evalSpec.evalReport), reportFile)
+
+ val report = new GATKReport(reportFile)
+
+ var allInRange = true
+
+ println()
+ println(name + " validation values:")
+ println(" value (min,target,max) table key metric")
+ for (validation <- evalSpec.validations) {
+ val table = report.getTable(validation.table)
+ val key = table.findRowByData(validation.table +: validation.key.split('.') : _*)
+ val value = String.valueOf(table.get(key, validation.metric))
+ val inRange = if (value == null) false else validation.inRange(value)
+ val flag = if (!inRange) "*" else " "
+ println(" %s %s (%s,%s,%s) %s %s %s".format(flag, value, validation.min, validation.target, validation.max, validation.table, validation.key, validation.metric))
+ allInRange &= inRange
+ }
+
+ if (!allInRange)
+ Assert.fail("Eval outside of expected range")
+ }
+
+ /**
+ * execute the test
+ * @param name the name of the test
+ * @param args the argument list
+ * @param jobQueue the queue to run the job on. Defaults to hour if jobQueue is null.
+ * @param expectedException the expected exception or null if no exception is expected.
+ * @param jobRunner The name of the job manager to run the jobs.
+ */
+ private def executeTest(name: String, args: String, jobQueue: String, expectedException: Class[_], jobRunner: String) {
+ var command = Utils.escapeExpressions(args)
+
+ // add the logging level to each of the integration test commands
+
+ command = Utils.appendArray(command, "-jobRunner", jobRunner,
+ "-tempDir", tempDir(name, jobRunner), "-runDir", runDir(name, jobRunner))
+
+ if (jobQueue != null)
+ command = Utils.appendArray(command, "-jobQueue", jobQueue)
+
+ if (BaseTest.queueTestRunModeIsSet)
+ command = Utils.appendArray(command, "-run")
+
+ // run the executable
+ var gotAnException = false
+
+ val instance = new QCommandLine
+ runningCommandLines += instance
+ try {
+ println("Executing test %s with Queue arguments: %s".format(name, Utils.join(" ",command)))
+ CommandLineProgram.start(instance, command)
+ } catch {
+ case e: Exception =>
+ gotAnException = true
+ if (expectedException != null) {
+ // we expect an exception
+ println("Wanted exception %s, saw %s".format(expectedException, e.getClass))
+ if (expectedException.isInstance(e)) {
+ // it's the type we expected
+ println(String.format(" => %s PASSED (%s)", name, jobRunner))
+ } else {
+ e.printStackTrace()
+ Assert.fail("Test %s expected exception %s but got %s instead (%s)".format(
+ name, expectedException, e.getClass, jobRunner))
+ }
+ } else {
+ // we didn't expect an exception but we got one :-(
+ throw new RuntimeException(e)
+ }
+ } finally {
+ instance.shutdown()
+ runningCommandLines -= instance
+ }
+
+ // catch failures from the integration test
+ if (expectedException != null) {
+ if (!gotAnException)
+ // we expected an exception but didn't see it
+ Assert.fail("Test %s expected exception %s but none was thrown (%s)".format(name, expectedException.toString, jobRunner))
+ } else {
+ if (CommandLineProgram.result != 0)
+ throw new RuntimeException("Error running Queue with arguments: " + args)
+ }
+ }
+
+ private def assertPathExists(runDir: String, path: String) {
+ val orig = new File(runDir, path)
+ var dir = orig.getParentFile
+ if (dir == null)
+ dir = new File(".")
+ Assert.assertTrue(dir.exists, "Missing directory: " + dir.getAbsolutePath)
+ val filter: FilenameFilter = new WildcardFileFilter(orig.getName)
+ Assert.assertNotEquals(dir.listFiles(filter).length, 0, "Missing file: " + orig.getAbsolutePath)
+ }
+
+ private def assertPathDoesNotExist(runDir: String, path: String) {
+ val orig = new File(runDir, path)
+ var dir = orig.getParentFile
+ if (dir == null)
+ dir = new File(".")
+ if (dir.exists) {
+ val filter: FilenameFilter = new WildcardFileFilter(orig.getName)
+ Assert.assertEquals(dir.listFiles(filter).length, 0,
+ "Found unexpected file(s): " + dir.listFiles().map(_.getAbsolutePath).mkString(", "))
+ }
+ }
+
+ private var runningCommandLines = Set.empty[QCommandLine]
+
+ Runtime.getRuntime.addShutdownHook(new Thread {
+ /** Cleanup as the JVM shuts down. */
+ override def run() {
+ runningCommandLines.foreach(commandLine =>
+ try {
+ commandLine.shutdown()
+ } catch {
+ case _: Throwable => /* ignore */
+ })
+ }
+ })
+}
diff --git a/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/pipeline/QueueTestEvalSpec.scala b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/pipeline/QueueTestEvalSpec.scala
new file mode 100644
index 0000000..764449c
--- /dev/null
+++ b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/pipeline/QueueTestEvalSpec.scala
@@ -0,0 +1,59 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.pipeline
+
+/**
+ * Data validations to evaluate on a GATKReport.
+ */
+class QueueTestEvalSpec {
+ /** Eval modules to output. */
+ var evalReport: String = _
+
+ /** Validations to assert. */
+ var validations: Seq[PipelineValidation[_]] = Nil
+}
+
+/** A VariantEval JEXL and range of values to validate. */
+abstract class PipelineValidation[T <: AnyVal](val table: String, val key: String, val metric: String, val target: T, val min: T, val max: T) {
+ def parse(x: String): T
+ def inRange(x: String): Boolean
+}
+
+/** A VariantEval JEXL and target to validate within a 1% tolerance. */
+class IntegerValidation(table: String, key: String, metric: String, target: Int)
+ extends PipelineValidation[Int](table, key, metric, target,
+ (target * .99).floor.toInt, (target * 1.01).ceil.toInt) {
+ def parse(x: String) = x.toInt
+ def inRange(x: String) = parse(x) >= min && parse(x) <= max
+}
+
+/** A VariantEval JEXL and target to validate within a 1% tolerance. */
+class DoubleValidation(table: String, key: String, metric: String, target: Double)
+ extends PipelineValidation(table, key, metric, target,
+ (target * 99).floor / 100, (target * 101).ceil / 100) {
+ def parse(x: String) = x.toDouble
+ def inRange(x: String) = parse(x) >= min && parse(x) <= max
+}
diff --git a/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/pipeline/QueueTestSpec.scala b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/pipeline/QueueTestSpec.scala
new file mode 100644
index 0000000..4fdcb08
--- /dev/null
+++ b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/pipeline/QueueTestSpec.scala
@@ -0,0 +1,68 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.pipeline
+
+class QueueTestSpec(var name: String = null) {
+
+ /** The arguments to pass to the Queue test, ex: "-S scala/qscript/examples/HelloWorld.scala" */
+ var args: String = _
+
+ /** Job Queue to run the test. Default is null which means use hour. */
+ var jobQueue: String = _
+
+ /** Job runners to run the test. Default is null which means use the default. */
+ var jobRunners: Seq[String] = _
+
+ /** Expected MD5 results for each file path. */
+ var fileMD5s = Map.empty[String, String]
+
+ /** VariantEval validations to run on a VCF after the pipeline has completed. */
+ var evalSpec: QueueTestEvalSpec = _
+
+ /** Expected exception from the test. */
+ var expectedException: Class[_ <: Exception] = null
+
+ /** Expected files. The file name may contain wildcards acceptable by the WildcardFileFilter. */
+ var expectedFilePaths: Seq[String] = Seq.empty
+
+ /** Unexpected files. The file name may contain wildcards acceptable by the WildcardFileFilter. */
+ var unexpectedFilePaths: Seq[String] = Seq.empty
+
+ /** If true will check the MD5s without failing. */
+ var parameterize = false
+
+ def this(args: String, fileMD5s: Traversable[(String, String)]) = {
+ this()
+ this.args = args
+ this.fileMD5s = fileMD5s.toMap
+ }
+
+ def this(args: String, expectedException: Class[_ <: Exception]) = {
+ this()
+ this.args = args
+ this.expectedException = expectedException
+ }
+}
diff --git a/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/util/ShellUtilsUnitTest.scala b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/util/ShellUtilsUnitTest.scala
new file mode 100644
index 0000000..944cc85
--- /dev/null
+++ b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/util/ShellUtilsUnitTest.scala
@@ -0,0 +1,82 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import org.testng.annotations.Test
+import org.testng.Assert
+import java.io.{InputStreamReader, BufferedReader}
+
+class ShellUtilsUnitTest {
+
+ @Test
+ def testEscapeShellArgumentOneCharSequences() {
+ // Test all ASCII characters except \0, \n, and \r, which we do not support escaping
+ for ( asciiCode <- 1 to 127 if asciiCode != 10 && asciiCode != 13 ) {
+ val originalString: String = "%c".format(asciiCode.toChar)
+ val quotedString: String = ShellUtils.escapeShellArgument(originalString)
+
+ val child : Process = new ProcessBuilder("/bin/sh", "-c", "printf \"%s\" " + quotedString).start()
+ val childReader : BufferedReader = new BufferedReader(new InputStreamReader(child.getInputStream))
+ val childOutputBuffer : StringBuilder = new StringBuilder
+
+ val childReaderThread : Thread = new Thread(new Runnable() {
+ def run() {
+ var line : String = childReader.readLine()
+
+ while ( line != null ) {
+ childOutputBuffer.append(line)
+ line = childReader.readLine()
+ }
+ }
+ })
+ childReaderThread.start()
+
+ val childReturnValue = child.waitFor()
+ childReaderThread.join()
+
+ childReader.close()
+ val childOutput = childOutputBuffer.toString()
+
+ if ( childReturnValue != 0 ) {
+ Assert.fail("With character ASCII %d, sh child process returned: %d".format(asciiCode, childReturnValue))
+ }
+ else if ( ! originalString.equals(childOutput) ) {
+ Assert.fail("With character ASCII %d, sh child process output \"%s\" instead of the expected \"%s\"".format(
+ asciiCode, childOutput, originalString))
+ }
+ }
+ }
+
+ @Test(expectedExceptions = Array(classOf[IllegalArgumentException]))
+ def testEscapeShellArgumentNullString() {
+ ShellUtils.escapeShellArgument(null)
+ }
+
+ @Test
+ def testEscapeShellArgumentEmptyString() {
+ Assert.assertEquals(ShellUtils.escapeShellArgument(""), "''")
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/util/StringFileConversionsUnitTest.scala b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/util/StringFileConversionsUnitTest.scala
new file mode 100644
index 0000000..160e040
--- /dev/null
+++ b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/util/StringFileConversionsUnitTest.scala
@@ -0,0 +1,128 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import org.testng.annotations.Test
+import java.io.File
+import org.testng.Assert
+import StringFileConversions._
+
+class StringFileConversionsUnitTest {
+ @Test
+ def testStringToFile() {
+ var string: String = new File("foo")
+ Assert.assertEquals(string, "foo")
+
+ string = null.asInstanceOf[File]
+ Assert.assertNull(string)
+ }
+
+ @Test
+ def testFileToString() {
+ var file: File = "foo"
+ Assert.assertEquals(file, new File("foo"))
+
+ file = null.asInstanceOf[String]
+ Assert.assertNull(file)
+ }
+
+ @Test
+ def testStringToFileList() {
+ var files = Seq(new File("foo"))
+ files :+= "bar"
+ Assert.assertEquals(files, Seq(new File("foo"), new File("bar")))
+
+ files = Seq(new File("foo"))
+ files :+= null.asInstanceOf[String]
+ Assert.assertEquals(files, Seq(new File("foo"), null))
+
+ files = Seq[File](null)
+ files :+= "foo"
+ Assert.assertEquals(files, Seq(null, new File("foo")))
+
+ files = Seq[File](null)
+ files :+= null.asInstanceOf[String]
+ Assert.assertEquals(files, Seq(null, null))
+ }
+
+ @Test
+ def testFileToStringList() {
+ var strings = Seq("foo")
+ strings :+= new File("bar")
+ Assert.assertEquals(strings, Seq("foo", "bar"))
+
+ strings = Seq("foo")
+ strings :+= null.asInstanceOf[File]
+ Assert.assertEquals(strings, Seq("foo", null))
+
+ strings = Seq[String](null)
+ strings :+= new File("foo")
+ Assert.assertEquals(strings, Seq(null, "foo"))
+
+ strings = Seq[String](null)
+ strings :+= null.asInstanceOf[File]
+ Assert.assertEquals(strings, Seq(null, null))
+ }
+
+ @Test
+ def testStringListToFileList() {
+ var files = Seq(new File("foo"))
+ files ++= Seq("bar")
+ Assert.assertEquals(files, Seq(new File("foo"), new File("bar")))
+
+ files = Seq(new File("foo"))
+ files ++= Seq[String](null)
+ Assert.assertEquals(files, Seq(new File("foo"), null))
+
+ files = Seq[File](null)
+ files ++= Seq("foo")
+ Assert.assertEquals(files, Seq(null, new File("foo")))
+
+ files = Seq[File](null)
+ files ++= Seq[String](null)
+ Assert.assertEquals(files, Seq(null, null))
+ }
+
+ @Test
+ def testFileListToStringList() {
+ var strings = Seq("foo")
+ strings ++= Seq(new File("bar"))
+ Assert.assertEquals(strings, Seq("foo", "bar"))
+
+ strings = Seq("foo")
+ strings ++= Seq[File](null)
+ Assert.assertEquals(strings, Seq("foo", null))
+
+ strings = Seq[String](null)
+ strings ++= Seq(new File("foo"))
+ Assert.assertEquals(strings, Seq(null, "foo"))
+
+ strings = Seq[String](null)
+ strings ++= Seq[File](null)
+ Assert.assertEquals(strings, Seq(null, null))
+ }
+
+}
diff --git a/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/util/SystemUtilsUnitTest.scala b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/util/SystemUtilsUnitTest.scala
new file mode 100644
index 0000000..2fd78e3
--- /dev/null
+++ b/public/gatk-queue/src/test/scala/org/broadinstitute/gatk/queue/util/SystemUtilsUnitTest.scala
@@ -0,0 +1,44 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.queue.util
+
+import org.testng.annotations.Test
+import org.testng.Assert
+
+class SystemUtilsUnitTest {
+ @Test
+ def testHostInfo {
+ val inetAddress = SystemUtils.inetAddress
+ val hostName = SystemUtils.hostName
+ val mailName = SystemUtils.mailName
+
+ if (inetAddress.split('.').takeRight(2).mkString(".") == mailName)
+ Assert.fail("""Invalid domain name generated:
+ |inetAddress: %s
+ |hostName: %s
+ |mailName: %s""".stripMargin.format(inetAddress, hostName, mailName))
+ }
+}
diff --git a/public/gatk-root/pom.xml b/public/gatk-root/pom.xml
new file mode 100644
index 0000000..c9f2517
--- /dev/null
+++ b/public/gatk-root/pom.xml
@@ -0,0 +1,717 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!--
+ This pom is parent for all gatk poms
+ See also:
+ http://maven.apache.org/pom.html#Inheritance_v
+ http://maven.apache.org/guides/introduction/introduction-to-the-pom.html#Project_Inheritance_vs_Project_Aggregation
+ http://stackoverflow.com/questions/1992213/maven-parent-pom-vs-modules-pom
+ -->
+
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-root</artifactId>
+ <version>3.3</version>
+ <packaging>pom</packaging>
+ <name>GATK Root</name>
+
+ <prerequisites>
+ <maven>3.0.4</maven>
+ </prerequisites>
+
+ <properties>
+ <sourceEncoding>UTF-8</sourceEncoding>
+ <project.build.sourceEncoding>${sourceEncoding}</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>${sourceEncoding}</project.reporting.outputEncoding>
+ <maven.compiler.source>1.7</maven.compiler.source>
+ <maven.compiler.target>1.7</maven.compiler.target>
+ <maven.build.timestamp.format>yyyy/MM/dd HH:mm:ss</maven.build.timestamp.format>
+ <gatk.basedir>${project.basedir}/../..</gatk.basedir>
+ <gatk.committests.skipped>true</gatk.committests.skipped>
+ <gatk.unittests.skipped>${gatk.committests.skipped}</gatk.unittests.skipped>
+ <gatk.integrationtests.skipped>${gatk.committests.skipped}</gatk.integrationtests.skipped>
+ <gatk.queuetests.skipped>${gatk.committests.skipped}</gatk.queuetests.skipped>
+ <gatk.largescaletests.skipped>true</gatk.largescaletests.skipped>
+ <gatk.knowledgebasetests.skipped>true</gatk.knowledgebasetests.skipped>
+ <gatk.queuetests.run>false</gatk.queuetests.run>
+ <scala.maxmemory>1g</scala.maxmemory>
+ <test.maxmemory>4g</test.maxmemory>
+ <java.gc.threads>4</java.gc.threads>
+ <java.gc.timeLimit>50</java.gc.timeLimit>
+ <java.gc.heapFreeLimit>10</java.gc.heapFreeLimit>
+ <test.args>-Xmx${test.maxmemory} -XX:+UseParallelOldGC -XX:ParallelGCThreads=${java.gc.threads} -XX:GCTimeLimit=${java.gc.timeLimit} -XX:GCHeapFreeLimit=${java.gc.heapFreeLimit}</test.args>
+ <test.listeners>org.testng.reporters.FailedReporter,org.testng.reporters.JUnitXMLReporter,org.broadinstitute.gatk.utils.TestNGTestTransformer,org.broadinstitute.gatk.utils.GATKTextReporter,org.uncommons.reportng.HTMLReporter</test.listeners>
+
+ <!-- Version numbers for picard and htsjdk -->
+ <htsjdk.version>1.120.1620</htsjdk.version>
+ <picard.version>1.120.1579</picard.version>
+ </properties>
+
+ <!-- Dependency configuration (versions, etc.) -->
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-compiler</artifactId>
+ <version>2.10.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-library</artifactId>
+ <version>2.10.2</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.cofoja</groupId>
+ <artifactId>cofoja</artifactId>
+ <version>1.0-r139</version>
+ </dependency>
+ <dependency>
+ <groupId>samtools</groupId>
+ <artifactId>htsjdk</artifactId>
+ <version>${htsjdk.version}</version>
+ <exclusions>
+ <!-- The jdk15 classfier seems to throw off the normal dependency resolution,
+ leading to both 6.8 and 5.0-jdk15 on the classpath, then leading to an old
+ version testng loading, as seen by the super old TestNG4751Configurator.
+ -->
+ <exclusion>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>picard</groupId>
+ <artifactId>picard</artifactId>
+ <version>${picard.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.15</version>
+ <exclusions>
+ <exclusion>
+ <groupId>com.sun.jdmk</groupId>
+ <artifactId>jmxtools</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.jms</groupId>
+ <artifactId>jms</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jmx</groupId>
+ <artifactId>jmxri</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ <version>1.4.4</version>
+ </dependency>
+ <dependency>
+ <groupId>colt</groupId>
+ <artifactId>colt</artifactId>
+ <version>1.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>it.unimi.dsi</groupId>
+ <artifactId>fastutil</artifactId>
+ <version>6.5.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.simpleframework</groupId>
+ <artifactId>simple-xml</artifactId>
+ <version>2.0.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.reflections</groupId>
+ <artifactId>reflections</artifactId>
+ <version>0.9.9-RC1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.6.1</version>
+ </dependency>
+ <dependency>
+ <groupId>gov.nist.math</groupId>
+ <artifactId>jama</artifactId>
+ <version>1.0.2</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sf.jgrapht</groupId>
+ <artifactId>jgrapht</artifactId>
+ <version>0.8.3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ <version>2.3.18</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-email</artifactId>
+ <version>1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-jexl</artifactId>
+ <version>2.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.5</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>3.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-httpclient</groupId>
+ <artifactId>commons-httpclient</artifactId>
+ <version>3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-math</artifactId>
+ <version>2.2</version>
+ </dependency>
+ <dependency>
+ <groupId>net.java.dev.jna</groupId>
+ <artifactId>jna</artifactId>
+ <version>3.2.7</version>
+ </dependency>
+ <dependency>
+ <groupId>net.java.dev.jets3t</groupId>
+ <artifactId>jets3t</artifactId>
+ <version>0.8.1</version>
+ </dependency>
+ <dependency>
+ <groupId>us.levk</groupId>
+ <artifactId>drmaa-gridengine</artifactId>
+ <version>6.2u5</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sf.snpeff</groupId>
+ <artifactId>snpeff</artifactId>
+ <version>2.0.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mongodb</groupId>
+ <artifactId>mongo-java-driver</artifactId>
+ <version>2.7.3</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.2.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.1.1</version>
+ </dependency>
+
+ <!--
+ For com.sun.javadoc
+ See also: http://sunnytalkstech.blogspot.in/2011/08/maven-dependency-for-toolsjar-in-jdk7.html
+ -->
+ <dependency>
+ <groupId>com.sun</groupId>
+ <artifactId>tools</artifactId>
+ <version>1.4.2</version>
+ <scope>system</scope>
+ <systemPath>${java.home}/../lib/tools.jar</systemPath>
+ </dependency>
+
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>6.8</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.uncommons</groupId>
+ <artifactId>reportng</artifactId>
+ <version>1.1.2</version>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ <version>3.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.caliper</groupId>
+ <artifactId>caliper</artifactId>
+ <version>0.5-rc1</version>
+ <scope>test</scope>
+ <exclusions>
+ <!--
+ TODO: After upgrade to caliper 1.0-beta-1 or later, this may need a revisit.
+ Possibly other modules may need to exclude *their* old guava versions.
+ -->
+ <exclusion>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <!-- Dependencies for custom testng reports -->
+ <dependency>
+ <groupId>org.uncommons</groupId>
+ <artifactId>reportng</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <!-- Plugin configuration -->
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.2.1</version>
+ </plugin>
+ <plugin>
+ <groupId>com.lukegb.mojo</groupId>
+ <artifactId>gitdescribe-maven-plugin</artifactId>
+ <version>2.0</version>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.8</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-clean-plugin</artifactId>
+ <version>2.5</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>2.8</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.6</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.9.1</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.1</version>
+ </plugin>
+ <plugin>
+ <groupId>org.scala-tools</groupId>
+ <artifactId>maven-scala-plugin</artifactId>
+ <version>2.15.2</version>
+ <configuration>
+ <jvmArgs>
+ <jvmArg>-Xmx${scala.maxmemory}</jvmArg>
+ </jvmArgs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.4</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.1</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>1.3.1</version>
+ </plugin>
+ <!--
+ surefire/failsafe configurations are global, even across poms
+ not directly aggregated, for example package-tests/pom.xml
+ -->
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.16</version>
+ <configuration>
+ <!-- See explicit executions below -->
+ <skip>true</skip>
+ <failIfNoTests>false</failIfNoTests>
+ <useFile>false</useFile>
+ <reportFormat>plain</reportFormat>
+ <argLine>${test.args}</argLine>
+ <properties>
+ <property>
+ <name>usedefaultlisteners</name>
+ <value>false</value>
+ </property>
+ <property>
+ <name>listener</name>
+ <value>${test.listeners}</value>
+ </property>
+ </properties>
+ <systemPropertyVariables>
+ <gatkdir>${gatk.basedir}</gatkdir>
+ <clover.pertest.coverage>diff</clover.pertest.coverage>
+ <java.awt.headless>true</java.awt.headless>
+ <java.io.tmpdir>${java.io.tmpdir}</java.io.tmpdir>
+ </systemPropertyVariables>
+ </configuration>
+ <executions>
+ <execution>
+ <id>default-test</id>
+ <phase>none</phase>
+ </execution>
+ <execution>
+ <!-- run all non integration tests -->
+ <id>unit-tests</id>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <!-- TODO: Re-enable unit tests by default? -->
+ <skip>${gatk.unittests.skipped}</skip>
+ <reportsDirectory>${project.build.directory}/surefire-reports/unit/${test}</reportsDirectory>
+ <includes>
+ <include>**/*UnitTest.class</include>
+ </includes>
+ <systemPropertyVariables>
+ <testType>unit</testType>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.16</version>
+ <configuration>
+ <!-- See explicit executions below -->
+ <skip>true</skip>
+ <failIfNoTests>false</failIfNoTests>
+ <useFile>false</useFile>
+ <reportFormat>plain</reportFormat>
+ <argLine>${test.args}</argLine>
+ <properties>
+ <property>
+ <name>usedefaultlisteners</name>
+ <value>false</value>
+ </property>
+ <property>
+ <name>listener</name>
+ <value>${test.listeners}</value>
+ </property>
+ </properties>
+ <systemPropertyVariables>
+ <gatkdir>${gatk.basedir}</gatkdir>
+ <clover.pertest.coverage>diff</clover.pertest.coverage>
+ <java.awt.headless>true</java.awt.headless>
+ <!-- TODO: Fix BaseTest to not error out if this property is missing. -->
+ <pipeline.run>${gatk.queuetests.run}</pipeline.run>
+ <java.io.tmpdir>${java.io.tmpdir}</java.io.tmpdir>
+ </systemPropertyVariables>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-tests</id>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <!-- run integration tests -->
+ <configuration>
+ <!-- TODO: Re-enable integration tests by default? -->
+ <skip>${gatk.integrationtests.skipped}</skip>
+ <reportsDirectory>${project.build.directory}/failsafe-reports/integration/${it.test}</reportsDirectory>
+ <summaryFile>${project.build.directory}/failsafe-reports/integration/failsafe-summary-${it.test}.xml</summaryFile>
+ <includes>
+ <include>**/*IntegrationTest.class</include>
+ </includes>
+ <systemPropertyVariables>
+ <testType>integration</testType>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ <execution>
+ <id>queue-tests</id>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <!-- run queue dry run tests -->
+ <configuration>
+ <!-- TODO: Re-enable queue tests by default? -->
+ <skip>${gatk.queuetests.skipped}</skip>
+ <reportsDirectory>${project.build.directory}/failsafe-reports/queue/${it.test}</reportsDirectory>
+ <summaryFile>${project.build.directory}/failsafe-reports/queue/failsafe-summary-${it.test}.xml</summaryFile>
+ <includes>
+ <include>**/*QueueTest.class</include>
+ </includes>
+ <systemPropertyVariables>
+ <testType>queue</testType>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ <execution>
+ <id>large-scale-tests</id>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <!-- run large scale tests -->
+ <configuration>
+ <skip>${gatk.largescaletests.skipped}</skip>
+ <reportsDirectory>${project.build.directory}/failsafe-reports/largescale/${it.test}</reportsDirectory>
+ <summaryFile>${project.build.directory}/failsafe-reports/largescale/failsafe-summary-${it.test}.xml</summaryFile>
+ <includes>
+ <include>**/*LargeScaleTest.class</include>
+ </includes>
+ <systemPropertyVariables>
+ <testType>largescale</testType>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ <execution>
+ <id>knowledge-base-tests</id>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <!-- run knowledge base tests -->
+ <configuration>
+ <skip>${gatk.knowledgebasetests.skipped}</skip>
+ <reportsDirectory>${project.build.directory}/failsafe-reports/knowledgebasetests/${it.test}</reportsDirectory>
+ <summaryFile>${project.build.directory}/failsafe-reports/knowledgebasetests/failsafe-summary-${it.test}.xml</summaryFile>
+ <includes>
+ <include>**/*KnowledgeBaseTest.class</include>
+ </includes>
+ <systemPropertyVariables>
+ <testType>knowledgebasetests</testType>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>com.google.code.sortpom</groupId>
+ <artifactId>maven-sortpom-plugin</artifactId>
+ <version>2.2</version>
+ <configuration>
+ <createBackupFile>false</createBackupFile>
+ <predefinedSortOrder>custom_1</predefinedSortOrder>
+ <lineSeparator>\n</lineSeparator>
+ <encoding>${sourceEncoding}</encoding>
+ <keepBlankLines>true</keepBlankLines>
+ <sortDependencies>scope</sortDependencies>
+ <nrOfIndentSpace>4</nrOfIndentSpace>
+ <expandEmptyElements>false</expandEmptyElements>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>sort</goal>
+ </goals>
+ <phase>verify</phase>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- TODO: Remove temporary symbolic link creation, after fixing test paths to use local resources. -->
+ <plugin>
+ <groupId>com.pyx4j</groupId>
+ <artifactId>maven-junction-plugin</artifactId>
+ <version>1.0.3</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <version>1.8</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <version>2.5</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>3.3</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+
+ <!-- Invoke plugins that always run -->
+ <plugins>
+ <plugin>
+ <groupId>com.lukegb.mojo</groupId>
+ <artifactId>gitdescribe-maven-plugin</artifactId>
+ <configuration>
+ <extraArguments>
+ <param>--long</param>
+ </extraArguments>
+ <setReactorProjectsProperties>true</setReactorProjectsProperties>
+ <descriptionProperty>git.version</descriptionProperty>
+ <failOutput>exported</failOutput>
+ </configuration>
+ <executions>
+ <execution>
+ <id>gitdescribe-initialize</id>
+ <goals>
+ <goal>gitdescribe</goal>
+ </goals>
+ <phase>initialize</phase>
+ </execution>
+ <execution>
+ <id>gitdescribe-presite</id>
+ <goals>
+ <goal>gitdescribe</goal>
+ </goals>
+ <phase>pre-site</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <!-- TODO: gitdescribe plugin doesn't allow null prefixes -->
+ <executions>
+ <execution>
+ <id>fix-version-initialize</id>
+ <goals>
+ <goal>regex-property</goal>
+ </goals>
+ <phase>initialize</phase>
+ <configuration>
+ <name>build.version</name>
+ <value>${git.version}</value>
+ <regex>git-</regex>
+ </configuration>
+ </execution>
+ <execution>
+ <id>fix-version-pre-site</id>
+ <goals>
+ <goal>regex-property</goal>
+ </goals>
+ <phase>pre-site</phase>
+ <configuration>
+ <name>build.version</name>
+ <value>${git.version}</value>
+ <regex>git-</regex>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>com.google.code.sortpom</groupId>
+ <artifactId>maven-sortpom-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>default</id>
+ <goals>
+ <goal>sort</goal>
+ </goals>
+ <phase>verify</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-install-plugin</artifactId>
+ <executions>
+ <!--
+ The pom for com.pyx4j:maven-junction-plugin:1.0.3 points to
+ sysinternals:junction:1.04:exe. This file is only hosted in the repo
+ http://www.pyx4me.com/maven2, and the website keeps going down.
+
+ This file is only used on windows, but the maven-plugin devs never finished
+ implementing *plugin* dependency exclusions: http://jira.codehaus.org/browse/MNG-2163
+
+ Until someone updates or replaces this 2007 plugin with a new plugin using Java 7's Files class,
+ for now we copy over the artifact just in case the website is unavailable.
+
+ See also: http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#createSymbolicLink(java.nio.file.Path,%20java.nio.file.Path,%20java.nio.file.attribute.FileAttribute...)
+ -->
+ <execution>
+ <id>install-sysinternals-junction</id>
+ <goals>
+ <goal>install-file</goal>
+ </goals>
+ <phase>initialize</phase>
+ <inherited>false</inherited>
+ <configuration>
+ <file>${gatk.basedir}/public/repo/sysinternals/junction/1.04/junction-1.04.exe</file>
+ <pomFile>${gatk.basedir}/public/repo/sysinternals/junction/1.04/junction-1.04.pom</pomFile>
+ <packaging>exe</packaging>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <reporting>
+ <excludeDefaults>true</excludeDefaults>
+ </reporting>
+
+ <repositories>
+ <repository>
+ <id>gatk.public.repo.local</id>
+ <name>GATK Public Local Repository</name>
+ <url>file:${gatk.basedir}/public/repo</url>
+ </repository>
+ </repositories>
+
+</project>
diff --git a/public/gatk-tools-public/pom.xml b/public/gatk-tools-public/pom.xml
new file mode 100644
index 0000000..5386b32
--- /dev/null
+++ b/public/gatk-tools-public/pom.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-aggregator</artifactId>
+ <version>3.3</version>
+ <relativePath>../..</relativePath>
+ </parent>
+
+ <artifactId>gatk-tools-public</artifactId>
+ <packaging>jar</packaging>
+ <name>GATK Tools Public</name>
+
+ <properties>
+ <gatk.basedir>${project.basedir}/../..</gatk.basedir>
+ <gatk.packagetests.artifactId>gatk-package-distribution</gatk.packagetests.artifactId>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-engine</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.caliper</groupId>
+ <artifactId>caliper</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-resource-bundle-log4j</id>
+ <phase>prepare-package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>extract-resource-bundle</id>
+ <phase>prepare-package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>package-unittests</id>
+ </execution>
+ <execution>
+ <id>package-integrationtests</id>
+ </execution>
+ <execution>
+ <id>package-largescaletests</id>
+ </execution>
+ <execution>
+ <id>package-knowledgebasetests</id>
+ </execution>
+ <execution>
+ <id>package-queuetests</id>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/public/gatk-tools-public/src/main/java/htsjdk/samtools/GATKBAMFileSpan.java b/public/gatk-tools-public/src/main/java/htsjdk/samtools/GATKBAMFileSpan.java
new file mode 100644
index 0000000..c2a5e80
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/htsjdk/samtools/GATKBAMFileSpan.java
@@ -0,0 +1,308 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package htsjdk.samtools;
+
+import htsjdk.samtools.util.PeekableIterator;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+/**
+ * A temporary solution to work around Java access rights issues:
+ * override BAMFileSpan and make it public.
+ * TODO: Eliminate once we determine the final fate of the BAM index reading code.
+ */
+public class GATKBAMFileSpan extends BAMFileSpan {
+ /**
+ * Create a new empty list of chunks.
+ */
+ public GATKBAMFileSpan() {
+ super();
+ }
+
+ /**
+ * Create a new GATKBAMFileSpan from an existing BAMFileSpan.
+ * @param sourceFileSpan
+ */
+ public GATKBAMFileSpan(SAMFileSpan sourceFileSpan) {
+ if(!(sourceFileSpan instanceof BAMFileSpan))
+ throw new SAMException("Unable to create GATKBAMFileSpan from a SAMFileSpan. Please submit a BAMFileSpan instead");
+ BAMFileSpan sourceBAMFileSpan = (BAMFileSpan)sourceFileSpan;
+ for(Chunk chunk: sourceBAMFileSpan.getChunks())
+ add(chunk instanceof GATKChunk ? chunk : new GATKChunk(chunk));
+ }
+
+ /**
+ * Convenience constructor to construct a BAM file span from
+ * a single chunk.
+ * @param chunk Chunk to use as the sole region in this span.
+ */
+ public GATKBAMFileSpan(final Chunk chunk) {
+ super(chunk);
+ }
+
+ /**
+ * Create a new chunk list from the given list of chunks.
+ * @param chunks Constituent chunks.
+ */
+ public GATKBAMFileSpan(final GATKChunk[] chunks) {
+ super(Arrays.<Chunk>asList(chunks));
+ }
+
+ @Override
+ public boolean equals(final Object other) {
+ if(!(other instanceof BAMFileSpan))
+ return false;
+
+ List<Chunk> theseChunks = getChunks();
+ List<Chunk> otherChunks = ((BAMFileSpan)other).getChunks();
+
+ if(theseChunks.size() != otherChunks.size())
+ return false;
+ for(int i = 0; i < theseChunks.size(); i++) {
+ if(!theseChunks.get(i).equals(otherChunks.get(i)))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets the constituent chunks stored in this span.
+ * @return An unmodifiable list of chunks.
+ */
+ public List<GATKChunk> getGATKChunks() {
+ List<GATKChunk> gatkChunks = new ArrayList<GATKChunk>();
+ for(Chunk chunk: getChunks())
+ gatkChunks.add(new GATKChunk(chunk));
+ return gatkChunks;
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ for(GATKChunk chunk: getGATKChunks())
+ builder.append(String.format("%s;",chunk));
+ return builder.toString();
+ }
+
+ /**
+ * Returns an approximation of the number of uncompressed bytes in this
+ * file span.
+ * @return Approximation of uncompressed bytes in filespan.
+ */
+ public long size() {
+ long size = 0L;
+ for(GATKChunk chunk: getGATKChunks())
+ size += chunk.size();
+ return size;
+ }
+
+ /**
+ * Get a GATKChunk representing the "extent" of this file span, from the start of the first
+ * chunk to the end of the last chunk.The chunks list must be sorted in order to use this method.
+ *
+ * @return a GATKChunk representing the extent of this file span, or a GATKChunk representing
+ * a span of size 0 if there are no chunks
+ */
+ public GATKChunk getExtent() {
+ validateSorted(); // TODO: defensive measure: may be unnecessary
+
+ List<Chunk> chunks = getChunks();
+ if ( chunks.isEmpty() ) {
+ return new GATKChunk(0L, 0L);
+ }
+
+ return new GATKChunk(chunks.get(0).getChunkStart(), chunks.get(chunks.size() - 1).getChunkEnd());
+ }
+
+ /**
+ * Validates the list of chunks to ensure that they appear in sorted order.
+ */
+ private void validateSorted() {
+ List<Chunk> chunks = getChunks();
+ for ( int i = 1; i < chunks.size(); i++ ) {
+ if ( chunks.get(i).getChunkStart() < chunks.get(i-1).getChunkEnd() ) {
+ throw new ReviewedGATKException(String.format("Chunk list is unsorted; chunk %s is before chunk %s", chunks.get(i-1), chunks.get(i)));
+
+ }
+ }
+ }
+
+ /**
+ * Computes the union of two FileSpans.
+ * @param other FileSpan to union with this one.
+ * @return A file span that's been unioned.
+ */
+ public GATKBAMFileSpan union(final GATKBAMFileSpan other) {
+ // No data? Return an empty file span.
+ if(getGATKChunks().size() == 0 && other.getGATKChunks().size() == 0)
+ return new GATKBAMFileSpan();
+
+ LinkedList<GATKChunk> unmergedUnion = new LinkedList<GATKChunk>();
+ unmergedUnion.addAll(getGATKChunks());
+ unmergedUnion.addAll(other.getGATKChunks());
+ Collections.sort(unmergedUnion);
+
+ List<GATKChunk> mergedUnion = new ArrayList<GATKChunk>();
+ GATKChunk currentChunk = unmergedUnion.remove();
+ while(!unmergedUnion.isEmpty()) {
+
+ // While the current chunk can be merged with the next chunk:
+ while( ! unmergedUnion.isEmpty() &&
+ (currentChunk.overlaps(unmergedUnion.peek()) || currentChunk.isAdjacentTo(unmergedUnion.peek())) ) {
+
+ // Merge the current chunk with the next chunk:
+ GATKChunk nextChunk = unmergedUnion.remove();
+ currentChunk = currentChunk.merge(nextChunk);
+ }
+ // Add the accumulated range.
+ mergedUnion.add(currentChunk);
+ currentChunk = !unmergedUnion.isEmpty() ? unmergedUnion.remove() : null;
+ }
+
+ // At end of the loop above, the last chunk will be contained in currentChunk and will not yet have been added. Add it.
+ if(currentChunk !=null)
+ mergedUnion.add(currentChunk);
+
+ return new GATKBAMFileSpan(mergedUnion.toArray(new GATKChunk[mergedUnion.size()]));
+ }
+
+ /**
+ * Intersects two BAM file spans.
+ * @param other File span to intersect with this one.
+ * @return The intersected BAM file span.
+ */
+ public GATKBAMFileSpan intersection(final GATKBAMFileSpan other) {
+ Iterator<GATKChunk> thisIterator = getGATKChunks().iterator();
+ Iterator<GATKChunk> otherIterator = other.getGATKChunks().iterator();
+
+ if(!thisIterator.hasNext() || !otherIterator.hasNext())
+ return new GATKBAMFileSpan();
+
+ GATKChunk thisChunk = thisIterator.next();
+ GATKChunk otherChunk = otherIterator.next();
+
+ List<GATKChunk> intersected = new ArrayList<GATKChunk>();
+
+ while(thisChunk != null && otherChunk != null) {
+ // If this iterator is before other, skip this ahead.
+ if(thisChunk.getChunkEnd() <= otherChunk.getChunkStart()) {
+ thisChunk = thisIterator.hasNext() ? thisIterator.next() : null;
+ continue;
+ }
+
+ // If other iterator is before this, skip other ahead.
+ if(thisChunk.getChunkStart() >= otherChunk.getChunkEnd()) {
+ otherChunk = otherIterator.hasNext() ? otherIterator.next() : null;
+ continue;
+ }
+
+ // If these two chunks overlap, pull out intersection of data and truncated current chunks to point after
+ // the intersection (or next chunk if no such overlap exists).
+ if(thisChunk.overlaps(otherChunk)) {
+ // Determine the chunk constraints
+ GATKChunk firstChunk = thisChunk.getChunkStart() < otherChunk.getChunkStart() ? thisChunk : otherChunk;
+ GATKChunk secondChunk = thisChunk==firstChunk ? otherChunk : thisChunk;
+ GATKChunk intersectedChunk = new GATKChunk(secondChunk.getChunkStart(),Math.min(firstChunk.getChunkEnd(),secondChunk.getChunkEnd()));
+ intersected.add(intersectedChunk);
+
+ if(thisChunk.getChunkEnd() > intersectedChunk.getChunkEnd())
+ thisChunk = new GATKChunk(intersectedChunk.getChunkEnd(),thisChunk.getChunkEnd());
+ else
+ thisChunk = thisIterator.hasNext() ? thisIterator.next() : null;
+
+ if(otherChunk.getChunkEnd() > intersectedChunk.getChunkEnd())
+ otherChunk = new GATKChunk(intersectedChunk.getChunkEnd(),otherChunk.getChunkEnd());
+ else
+ otherChunk = otherIterator.hasNext() ? otherIterator.next() : null;
+ }
+
+ }
+
+ return new GATKBAMFileSpan(intersected.toArray(new GATKChunk[intersected.size()]));
+ }
+
+ /**
+ * Substracts other file span from this file span.
+ * @param other File span to strike out.
+ * @return This file span minuse the other file span.
+ */
+
+ public GATKBAMFileSpan minus(final GATKBAMFileSpan other) {
+ Iterator<GATKChunk> thisIterator = getGATKChunks().iterator();
+ Iterator<GATKChunk> otherIterator = other.getGATKChunks().iterator();
+
+ if(!thisIterator.hasNext() || !otherIterator.hasNext())
+ return this;
+
+ GATKChunk thisChunk = thisIterator.next();
+ GATKChunk otherChunk = otherIterator.next();
+
+ List<GATKChunk> subtracted = new ArrayList<GATKChunk>();
+
+ while(thisChunk != null && otherChunk != null) {
+ // If this iterator is before the other, add this to the subtracted list and forge ahead.
+ if(thisChunk.getChunkEnd() <= otherChunk.getChunkStart()) {
+ subtracted.add(thisChunk);
+ thisChunk = thisIterator.hasNext() ? thisIterator.next() : null;
+ continue;
+ }
+
+ // If other iterator is before this, skip other ahead.
+ if(thisChunk.getChunkStart() >= otherChunk.getChunkEnd()) {
+ otherChunk = otherIterator.hasNext() ? otherIterator.next() : null;
+ continue;
+ }
+
+ // If these two chunks overlap, pull out intersection of data and truncated current chunks to point after
+ // the intersection (or next chunk if no such overlap exists).
+ if(thisChunk.overlaps(otherChunk)) {
+ // Add in any sort of prefix that this chunk might have over the other.
+ if(thisChunk.getChunkStart() < otherChunk.getChunkStart())
+ subtracted.add(new GATKChunk(thisChunk.getChunkStart(),otherChunk.getChunkStart()));
+
+ if(thisChunk.getChunkEnd() > otherChunk.getChunkEnd())
+ thisChunk = new GATKChunk(otherChunk.getChunkEnd(),thisChunk.getChunkEnd());
+ else
+ thisChunk = thisIterator.hasNext() ? thisIterator.next() : null;
+ }
+ }
+
+ // Finish up any remaining contents of this that didn't make it into the subtracted array.
+ if(thisChunk != null)
+ subtracted.add(thisChunk);
+ while(thisIterator.hasNext())
+ subtracted.add(thisIterator.next());
+
+ return new GATKBAMFileSpan(subtracted.toArray(new GATKChunk[subtracted.size()]));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/htsjdk/samtools/GATKBin.java b/public/gatk-tools-public/src/main/java/htsjdk/samtools/GATKBin.java
new file mode 100644
index 0000000..d1e689d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/htsjdk/samtools/GATKBin.java
@@ -0,0 +1,135 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package htsjdk.samtools;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A temporary solution to work around Java access rights issues:
+ * override GATKBin and make it public.
+ * TODO: Eliminate once we determine the final fate of the BAM index reading code.
+ */
+public class GATKBin implements Comparable<GATKBin> {
+ /**
+ * The reference sequence associated with this bin.
+ */
+ private final int referenceSequence;
+
+ /**
+ * The number of this bin within the BAM file.
+ */
+ private final int binNumber;
+
+ /**
+ * The chunks associated with this bin.
+ */
+ private GATKChunk[] chunkList;
+
+ public GATKBin(Bin bin) {
+ this(bin.getReferenceSequence(),bin.getBinNumber());
+ }
+
+ public GATKBin(final int referenceSequence, final int binNumber) {
+ this.referenceSequence = referenceSequence;
+ this.binNumber = binNumber;
+ }
+
+ public int getReferenceSequence() {
+ return referenceSequence;
+ }
+
+ public int getBinNumber() {
+ return binNumber;
+ }
+
+ /**
+ * Convert this GATKBin to a normal bin, for processing with the standard BAM query interface.
+ * @return
+ */
+ public Bin toBin() {
+ return new Bin(referenceSequence,binNumber);
+ }
+
+ /**
+ * See whether two bins are equal. If the ref seq and the bin number
+ * are equal, assume equality of the chunk list.
+ * @param other The other Bin to which to compare this.
+ * @return True if the two bins are equal. False otherwise.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if(other == null) return false;
+ if(!(other instanceof GATKBin)) return false;
+
+ GATKBin otherBin = (GATKBin)other;
+ return this.referenceSequence == otherBin.referenceSequence && this.binNumber == otherBin.binNumber;
+ }
+
+ /**
+ * Compute a unique hash code for the given reference sequence and bin number.
+ * @return A unique hash code.
+ */
+ @Override
+ public int hashCode() {
+ return ((Integer)referenceSequence).hashCode() ^ ((Integer)binNumber).hashCode();
+ }
+
+ /**
+ * Compare two bins to see what ordering they should appear in.
+ * @param other Other bin to which this bin should be compared.
+ * @return -1 if this < other, 0 if this == other, 1 if this > other.
+ */
+ public int compareTo(GATKBin other) {
+ if(other == null)
+ throw new ClassCastException("Cannot compare to a null object");
+
+ // Check the reference sequences first.
+ if(this.referenceSequence != other.referenceSequence)
+ return referenceSequence - other.referenceSequence;
+
+ // Then check the bin ordering.
+ return binNumber - other.binNumber;
+ }
+
+ /**
+ * Sets the chunks associated with this bin
+ */
+ public void setChunkList(GATKChunk[] list){
+ chunkList = list;
+ }
+
+ /**
+ * Gets the list of chunks associated with this bin.
+ * @return the chunks in this bin. If no chunks are associated, an empty list will be returned.
+ */
+ public GATKChunk[] getChunkList(){
+ if(chunkList == null)
+ return new GATKChunk[0];
+ return chunkList;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/htsjdk/samtools/GATKChunk.java b/public/gatk-tools-public/src/main/java/htsjdk/samtools/GATKChunk.java
new file mode 100644
index 0000000..aed7aec
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/htsjdk/samtools/GATKChunk.java
@@ -0,0 +1,116 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package htsjdk.samtools;
+
+/**
+ * A temporary solution to work around Java access rights issues:
+ * override chunk and make it public.
+ * TODO: Eliminate once we determine the final fate of the BAM index reading code.
+ */
+public class GATKChunk extends Chunk {
+ /**
+ * The average ratio of compressed block size / uncompressed block size, computed empirically
+ * using the output of org.broadinstitute.gatk.engine.datasources.reads.utilities.PrintBGZFBounds.
+ */
+ private static final double AVERAGE_BAM_COMPRESSION_RATIO = 0.39;
+
+ public GATKChunk(final long start, final long stop) {
+ super(start,stop);
+ }
+
+ public GATKChunk(final long blockStart, final int blockOffsetStart, final long blockEnd, final int blockOffsetEnd) {
+ super(blockStart << 16 | blockOffsetStart,blockEnd << 16 | blockOffsetEnd);
+ }
+
+ public GATKChunk(final Chunk chunk) {
+ super(chunk.getChunkStart(),chunk.getChunkEnd());
+ }
+
+ @Override
+ public GATKChunk clone() {
+ return new GATKChunk(getChunkStart(),getChunkEnd());
+ }
+
+ @Override
+ public long getChunkStart() {
+ return super.getChunkStart();
+ }
+
+ @Override
+ public void setChunkStart(final long value) {
+ super.setChunkStart(value);
+ }
+
+ @Override
+ public long getChunkEnd() {
+ return super.getChunkEnd();
+ }
+
+ @Override
+ public void setChunkEnd(final long value) {
+ super.setChunkEnd(value);
+ }
+
+ public long getBlockStart() {
+ return getChunkStart() >>> 16;
+ }
+
+ public int getBlockOffsetStart() {
+ return (int)(getChunkStart() & 0xFFFF);
+ }
+
+ public long getBlockEnd() {
+ return getChunkEnd() >>> 16;
+ }
+
+ public int getBlockOffsetEnd() {
+ return ((int)getChunkEnd() & 0xFFFF);
+ }
+
+ /**
+ * Computes an approximation of the uncompressed size of the
+ * chunk, in bytes. Can be used to determine relative weights
+ * of chunk size.
+ * @return An approximation of the chunk size in bytes.
+ */
+ public long size() {
+ final long chunkSpan = Math.round(((getChunkEnd()>>16)-(getChunkStart()>>16))/AVERAGE_BAM_COMPRESSION_RATIO);
+ final int offsetSpan = (int)((getChunkEnd()&0xFFFF)-(getChunkStart()&0xFFFF));
+ return chunkSpan + offsetSpan;
+ }
+
+ /**
+ * Merges two chunks together. The caller is responsible for testing whether the
+ * chunks overlap/are adjacent before calling this method!
+ *
+ * @param other the chunk to merge with this chunk
+ * @return a new chunk representing the union of the two chunks (provided the chunks were
+ * overlapping/adjacent)
+ */
+ public GATKChunk merge ( GATKChunk other ) {
+ return new GATKChunk(Math.min(getChunkStart(), other.getChunkStart()), Math.max(getChunkEnd(), other.getChunkEnd()));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/htsjdk/samtools/PicardNamespaceUtils.java b/public/gatk-tools-public/src/main/java/htsjdk/samtools/PicardNamespaceUtils.java
new file mode 100644
index 0000000..00f65e5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/htsjdk/samtools/PicardNamespaceUtils.java
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package htsjdk.samtools;
+
+/**
+ * Utils that insist on being in the same package as Picard.
+ */
+public class PicardNamespaceUtils {
+ /**
+ * Private constructor only. Do not instantiate.
+ */
+ private PicardNamespaceUtils() {}
+
+ public static void setFileSource(final SAMRecord read, final SAMFileSource fileSource) {
+ read.setFileSource(fileSource);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/CommandLineExecutable.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/CommandLineExecutable.java
new file mode 100644
index 0000000..b8221bb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/CommandLineExecutable.java
@@ -0,0 +1,229 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.commandline.ArgumentTypeDescriptor;
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.io.stubs.OutputStreamArgumentTypeDescriptor;
+import org.broadinstitute.gatk.engine.io.stubs.SAMFileWriterArgumentTypeDescriptor;
+import org.broadinstitute.gatk.engine.io.stubs.VCFWriterArgumentTypeDescriptor;
+import org.broadinstitute.gatk.engine.phonehome.GATKRunReport;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.crypt.CryptUtils;
+import org.broadinstitute.gatk.utils.crypt.GATKKey;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.text.ListFileUtils;
+
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * @author aaron
+ */
+public abstract class CommandLineExecutable extends CommandLineProgram {
+ /**
+ * The actual engine which performs the analysis.
+ */
+ protected GenomeAnalysisEngine engine = new GenomeAnalysisEngine();
+
+ // get the analysis name
+ public abstract String getAnalysisName();
+
+ /**
+ * Gets the GATK argument bundle.
+ * @return A structure consisting of whatever arguments should be used to initialize the GATK engine.
+ */
+ protected abstract GATKArgumentCollection getArgumentCollection();
+
+ /**
+ * A list of all the arguments initially used as sources.
+ */
+ private final Collection<Object> argumentSources = new ArrayList<Object>();
+
+ protected static Logger logger = Logger.getLogger(CommandLineExecutable.class);
+
+ /**
+ * this is the function that the inheriting class can expect to have called
+ * when the command line system has initialized.
+ *
+ * @return the return code to exit the program with
+ */
+ protected int execute() throws Exception {
+ engine.setParser(parser);
+ argumentSources.add(this);
+
+ Walker<?,?> walker = engine.getWalkerByName(getAnalysisName());
+
+ try {
+ // Make sure a valid GATK user key is present, if required.
+ authorizeGATKRun();
+
+ engine.setArguments(getArgumentCollection());
+
+ // File lists can require a bit of additional expansion. Set these explicitly by the engine.
+ final Collection<SAMReaderID> bamFileList=ListFileUtils.unpackBAMFileList(getArgumentCollection().samFiles,parser);
+ engine.setSAMFileIDs(bamFileList);
+ if(getArgumentCollection().showFullBamList){
+ logger.info(String.format("Adding the following input SAM Files: %s",bamFileList.toString()));
+ }
+
+ engine.setWalker(walker);
+ walker.setToolkit(engine);
+
+ Collection<ReadFilter> filters = engine.createFilters();
+ engine.setFilters(filters);
+
+ // load the arguments into the walker / filters.
+ // TODO: The fact that this extra load call exists here when all the parsing happens at the engine
+ // TODO: level indicates that we're doing something wrong. Turn this around so that the GATK can drive
+ // TODO: argument processing.
+ loadArgumentsIntoObject(walker);
+ argumentSources.add(walker);
+
+ Collection<RMDTriplet> rodBindings = ListFileUtils.unpackRODBindings(parser.getRodBindings(), parser);
+ engine.setReferenceMetaDataFiles(rodBindings);
+
+ for (ReadFilter filter: filters) {
+ loadArgumentsIntoObject(filter);
+ argumentSources.add(filter);
+ }
+
+ engine.execute();
+ generateGATKRunReport(walker);
+ } catch ( Exception e ) {
+ generateGATKRunReport(walker, e);
+ throw e;
+ }
+
+ // always return 0
+ return 0;
+ }
+
+ /**
+ * Authorizes this run of the GATK by checking for a valid GATK user key, if required.
+ * Currently, a key is required only if running with the -et NO_ET or -et STDOUT options.
+ */
+ private void authorizeGATKRun() {
+ if ( getArgumentCollection().phoneHomeType == GATKRunReport.PhoneHomeOption.NO_ET ||
+ getArgumentCollection().phoneHomeType == GATKRunReport.PhoneHomeOption.STDOUT ) {
+ if ( getArgumentCollection().gatkKeyFile == null ) {
+ throw new UserException("Running with the -et NO_ET or -et STDOUT option requires a GATK Key file. " +
+ "Please see " + UserException.PHONE_HOME_DOCS_URL +
+ " for more information and instructions on how to obtain a key.");
+ }
+ else {
+ PublicKey gatkPublicKey = CryptUtils.loadGATKDistributedPublicKey();
+ GATKKey gatkUserKey = new GATKKey(gatkPublicKey, getArgumentCollection().gatkKeyFile);
+
+ if ( ! gatkUserKey.isValid() ) {
+ throw new UserException.KeySignatureVerificationException(getArgumentCollection().gatkKeyFile);
+ }
+ }
+ }
+ }
+
+ /**
+ * Generate the GATK run report for this walker using the current GATKEngine, if -et is enabled.
+ * This report will be written to either STDOUT or to the run repository, depending on the options
+ * for -et.
+ *
+ * @param e the exception, can be null if no exception occurred
+ */
+ private void generateGATKRunReport(Walker<?,?> walker, Exception e) {
+ if ( getArgumentCollection().phoneHomeType != GATKRunReport.PhoneHomeOption.NO_ET ) {
+ GATKRunReport report = new GATKRunReport(walker, e, engine, getArgumentCollection().phoneHomeType );
+ report.postReport(getArgumentCollection().phoneHomeType);
+ }
+ }
+
+ /**
+ * Convenience method for fully parameterized generateGATKRunReport when an exception has
+ * not occurred
+ *
+ * @param walker
+ */
+ private void generateGATKRunReport(Walker<?,?> walker) {
+ generateGATKRunReport(walker, null);
+ }
+
+ /**
+ * Subclasses of CommandLinePrograms can provide their own types of command-line arguments.
+ * @return A collection of type descriptors generating implementation-dependent placeholders.
+ */
+ protected Collection<ArgumentTypeDescriptor> getArgumentTypeDescriptors() {
+ return Arrays.asList( new VCFWriterArgumentTypeDescriptor(engine,System.out,argumentSources),
+ new SAMFileWriterArgumentTypeDescriptor(engine,System.out),
+ new OutputStreamArgumentTypeDescriptor(engine,System.out) );
+ }
+
+ /**
+ * GATK can add arguments dynamically based on analysis type.
+ *
+ * @return true
+ */
+ @Override
+ protected boolean canAddArgumentsDynamically() {
+ return true;
+ }
+
+ /**
+ * GATK provides the walker as an argument source.
+ * @return List of walkers to load dynamically.
+ */
+ @Override
+ protected Class[] getArgumentSources() {
+ // No walker info? No plugins.
+ if (getAnalysisName() == null) return new Class[] {};
+
+ Collection<Class> argumentSources = new ArrayList<Class>();
+
+ Walker walker = engine.getWalkerByName(getAnalysisName());
+ engine.setArguments(getArgumentCollection());
+ engine.setWalker(walker);
+ walker.setToolkit(engine);
+ argumentSources.add(walker.getClass());
+
+ Collection<ReadFilter> filters = engine.createFilters();
+ for(ReadFilter filter: filters)
+ argumentSources.add(filter.getClass());
+
+ Class[] argumentSourcesAsArray = new Class[argumentSources.size()];
+ return argumentSources.toArray(argumentSourcesAsArray);
+ }
+
+ @Override
+ protected String getArgumentSourceName( Class argumentSource ) {
+ return engine.getWalkerName((Class<Walker>)argumentSource);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/CommandLineGATK.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/CommandLineGATK.java
new file mode 100644
index 0000000..f88c413
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/CommandLineGATK.java
@@ -0,0 +1,385 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import picard.PicardException;
+import htsjdk.samtools.SAMException;
+import htsjdk.tribble.TribbleException;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.ArgumentCollection;
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.engine.refdata.tracks.FeatureManager;
+import org.broadinstitute.gatk.engine.walkers.Attribution;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.*;
+import org.broadinstitute.gatk.utils.text.TextFormattingUtils;
+
+import java.util.*;
+
+/**
+ * All command line parameters accepted by all tools in the GATK.
+ *
+ * <h3>Info for general users</h3>
+ *
+ * <p>This is a list of options and parameters that are generally available to all tools in the GATK.</p>
+ *
+ * <p>There may be a few restrictions, which are indicated in individual argument descriptions. For example the -BQSR
+ * argument is only meant to be used with a subset of tools, and the -pedigree argument will only be effectively used
+ * by a subset of tools as well. Some arguments conflict with others, and some conversely are dependent on others. This
+ * is all indicated in the detailed argument descriptions, so be sure to read those in their entirety rather than just
+ * skimming the one-line summaey in the table.</p>
+ *
+ * <h3>Info for developers</h3>
+ *
+ * <p>This class is the GATK engine itself, which manages map/reduce data access and runs walkers.</p>
+ *
+ * <p>We run command line GATK programs using this class. It gets the command line args, parses them, and hands the
+ * gatk all the parsed out information. Pretty much anything dealing with the underlying system should go here;
+ * the GATK engine should deal with any data related information.</p>
+ */
+ at DocumentedGATKFeature(groupName = HelpConstants.DOCS_CAT_ENGINE)
+public class CommandLineGATK extends CommandLineExecutable {
+ /**
+ * A complete list of tools (sometimes also called walkers because they "walk" through the data to perform analyses)
+ * is available in the online documentation.
+ */
+ @Argument(fullName = "analysis_type", shortName = "T", doc = "Name of the tool to run")
+ private String analysisName = null;
+
+ // our argument collection, the collection of command line args we accept
+ @ArgumentCollection
+ private GATKArgumentCollection argCollection = new GATKArgumentCollection();
+
+ /**
+ * Get pleasing info about the GATK.
+ *
+ * @return A list of Strings that contain pleasant info about the GATK.
+ */
+ @Override
+ protected ApplicationDetails getApplicationDetails() {
+ return new ApplicationDetails(createApplicationHeader(),
+ getAttribution(),
+ ApplicationDetails.createDefaultRunningInstructions(getClass()),
+ getAdditionalHelp());
+ }
+
+ @Override
+ public String getAnalysisName() {
+ return analysisName;
+ }
+
+ @Override
+ protected GATKArgumentCollection getArgumentCollection() {
+ return argCollection;
+ }
+
+ /**
+ * Required main method implementation.
+ */
+ public static void main(String[] argv) {
+ try {
+ CommandLineGATK instance = new CommandLineGATK();
+ start(instance, argv);
+ System.exit(CommandLineProgram.result); // todo -- this is a painful hack
+ } catch (UserException e) {
+ exitSystemWithUserError(e);
+ } catch (TribbleException e) {
+ // We can generate Tribble Exceptions in weird places when e.g. VCF genotype fields are
+ // lazy loaded, so they aren't caught elsewhere and made into User Exceptions
+ exitSystemWithUserError(e);
+ } catch(PicardException e) {
+ // TODO: Should Picard exceptions be, in general, UserExceptions or ReviewedGATKExceptions?
+ exitSystemWithError(e);
+ } catch (SAMException e) {
+ checkForMaskedUserErrors(e);
+ exitSystemWithSamError(e);
+ } catch (OutOfMemoryError e) {
+ exitSystemWithUserError(new UserException.NotEnoughMemory());
+ } catch (Throwable t) {
+ checkForMaskedUserErrors(t);
+ exitSystemWithError(t);
+ }
+ }
+
+ public static final String PICARD_TEXT_SAM_FILE_ERROR_1 = "Cannot use index file with textual SAM file";
+ public static final String PICARD_TEXT_SAM_FILE_ERROR_2 = "Cannot retrieve file pointers within SAM text files";
+ public static final String NO_SPACE_LEFT_ON_DEVICE_ERROR = "No space left on device";
+ public static final String DISK_QUOTA_EXCEEDED_ERROR = "Disk quota exceeded";
+
+ private static void checkForMaskedUserErrors(final Throwable t) {
+ // masked out of memory error
+ if ( t instanceof OutOfMemoryError )
+ exitSystemWithUserError(new UserException.NotEnoughMemory());
+ // masked user error
+ if ( t instanceof UserException || t instanceof TribbleException )
+ exitSystemWithUserError(new UserException(t.getMessage()));
+
+ // no message means no masked error
+ final String message = t.getMessage();
+ if ( message == null )
+ return;
+
+ // too many open files error
+ if ( message.contains("Too many open files") )
+ exitSystemWithUserError(new UserException.TooManyOpenFiles());
+
+ // malformed BAM looks like a SAM file
+ if ( message.contains(PICARD_TEXT_SAM_FILE_ERROR_1) || message.contains(PICARD_TEXT_SAM_FILE_ERROR_2) )
+ exitSystemWithSamError(t);
+
+ // can't close tribble index when writing
+ if ( message.contains("Unable to close index for") )
+ exitSystemWithUserError(new UserException(t.getCause() == null ? message : t.getCause().getMessage()));
+
+ // disk is full
+ if ( message.contains(NO_SPACE_LEFT_ON_DEVICE_ERROR) || message.contains(DISK_QUOTA_EXCEEDED_ERROR) )
+ exitSystemWithUserError(new UserException.NoSpaceOnDevice());
+
+ // masked error wrapped in another one
+ if ( t.getCause() != null )
+ checkForMaskedUserErrors(t.getCause());
+ }
+
+ /**
+ * Creates the a short blurb about the GATK, copyright info, and where to get documentation.
+ *
+ * @return The application header.
+ */
+ public static List<String> createApplicationHeader() {
+ List<String> header = new ArrayList<String>();
+ header.add(String.format("The Genome Analysis Toolkit (GATK) v%s, Compiled %s",getVersionNumber(), getBuildTime()));
+ header.add("Copyright (c) 2010 The Broad Institute");
+ header.add("For support and documentation go to " + HelpConstants.BASE_GATK_URL);
+ return header;
+ }
+
+ public static String getVersionNumber() {
+ ResourceBundle headerInfo = TextFormattingUtils.loadResourceBundle("GATKText");
+ return headerInfo.containsKey("org.broadinstitute.gatk.tools.version") ? headerInfo.getString("org.broadinstitute.gatk.tools.version") : "<unknown>";
+ }
+
+ public static String getBuildTime() {
+ ResourceBundle headerInfo = TextFormattingUtils.loadResourceBundle("GATKText");
+ return headerInfo.containsKey("build.timestamp") ? headerInfo.getString("build.timestamp") : "<unknown>";
+ }
+
+ /**
+ * If the user supplied any additional attribution, return it here.
+ * @return Additional attribution if supplied by the user. Empty (non-null) list otherwise.
+ */
+ private List<String> getAttribution() {
+ List<String> attributionLines = new ArrayList<String>();
+
+ // If no analysis name is present, fill in extra help on the walkers.
+ WalkerManager walkerManager = engine.getWalkerManager();
+ String analysisName = getAnalysisName();
+ if(analysisName != null && walkerManager.exists(analysisName)) {
+ Class<? extends Walker> walkerType = walkerManager.getWalkerClassByName(analysisName);
+ if(walkerType.isAnnotationPresent(Attribution.class))
+ attributionLines.addAll(Arrays.asList(walkerType.getAnnotation(Attribution.class).value()));
+ }
+ return attributionLines;
+ }
+
+ /**
+ * Retrieves additional information about GATK walkers.
+ * the code in HelpFormatter and supply it as a helper to this method.
+ *
+ * @return A string summarizing the walkers available in this distribution.
+ */
+ private String getAdditionalHelp() {
+ String additionalHelp;
+
+ // If no analysis name is present, fill in extra help on the walkers.
+ WalkerManager walkerManager = engine.getWalkerManager();
+ String analysisName = getAnalysisName();
+ if(analysisName != null && walkerManager.exists(getAnalysisName()))
+ additionalHelp = getWalkerHelp(walkerManager.getWalkerClassByName(getAnalysisName()));
+ else
+ additionalHelp = getAllWalkerHelp();
+
+ return additionalHelp;
+ }
+
+ private static final int PACKAGE_INDENT = 1;
+ private static final int WALKER_INDENT = 3;
+ private static final String FIELD_SEPARATOR = " ";
+
+ private String getWalkerHelp(Class<? extends Walker> walkerType) {
+ // Construct a help string to output details on this walker.
+ StringBuilder additionalHelp = new StringBuilder();
+ Formatter formatter = new Formatter(additionalHelp);
+
+ formatter.format("Available Reference Ordered Data types:%n");
+ formatter.format(new FeatureManager().userFriendlyListOfAvailableFeatures());
+ formatter.format("%n");
+
+ formatter.format("For a full description of this walker, see its GATKdocs at:%n");
+ formatter.format("%s%n", GATKDocUtils.helpLinksToGATKDocs(walkerType));
+
+ return additionalHelp.toString();
+ }
+
+ /**
+ * Load in additional help information about all available walkers.
+ * @return A string representation of the additional help.
+ */
+ private String getAllWalkerHelp() {
+ // Construct a help string to output available walkers.
+ StringBuilder additionalHelp = new StringBuilder();
+ Formatter formatter = new Formatter(additionalHelp);
+
+ // Get the list of walker names from the walker manager.
+ WalkerManager walkerManager = engine.getWalkerManager();
+
+ // Build a list sorted by walker display name. As this information is collected, keep track of the longest
+ // package / walker name for later formatting.
+ SortedSet<HelpEntry> helpText = new TreeSet<HelpEntry>(new HelpEntryComparator());
+
+ int longestPackageName = 0;
+ int longestWalkerName = 0;
+ for(Map.Entry<String,Collection<Class<? extends Walker>>> walkersByPackage: walkerManager.getWalkerNamesByPackage(true).entrySet()) {
+ // Get the display name.
+ String packageName = walkersByPackage.getKey();
+ String packageDisplayName = walkerManager.getPackageDisplayName(walkersByPackage.getKey());
+ String packageHelpText = walkerManager.getPackageSummaryText(packageName);
+
+ // Compute statistics about which names is longest.
+ longestPackageName = Math.max(longestPackageName,packageDisplayName.length());
+
+ SortedSet<HelpEntry> walkersInPackage = new TreeSet<HelpEntry>(new HelpEntryComparator());
+ for(Class<? extends Walker> walkerType: walkersByPackage.getValue()) {
+ String walkerName = walkerType.getName();
+ String walkerDisplayName = walkerManager.getName(walkerType);
+ String walkerHelpText = walkerManager.getWalkerSummaryText(walkerType);
+
+ longestWalkerName = Math.max(longestWalkerName,walkerManager.getName(walkerType).length());
+
+ walkersInPackage.add(new HelpEntry(walkerName,walkerDisplayName,walkerHelpText));
+ }
+
+ // Dump the walkers into the sorted set.
+ helpText.add(new HelpEntry(packageName,packageDisplayName,packageHelpText,Collections.unmodifiableSortedSet(walkersInPackage)));
+ }
+
+ final int headerWidth = Math.max(longestPackageName+PACKAGE_INDENT,longestWalkerName+WALKER_INDENT);
+
+
+ for(HelpEntry packageHelp: helpText) {
+ printDescriptorLine(formatter,PACKAGE_INDENT,packageHelp.displayName,headerWidth,FIELD_SEPARATOR,packageHelp.summary,TextFormattingUtils.DEFAULT_LINE_WIDTH);
+
+ for(HelpEntry walkerHelp: packageHelp.children)
+ printDescriptorLine(formatter,WALKER_INDENT,walkerHelp.displayName,headerWidth,FIELD_SEPARATOR,walkerHelp.summary,TextFormattingUtils.DEFAULT_LINE_WIDTH);
+
+ // Print a blank line between sets of walkers.
+ printDescriptorLine(formatter,0,"",headerWidth,FIELD_SEPARATOR,"", TextFormattingUtils.DEFAULT_LINE_WIDTH);
+ }
+
+ return additionalHelp.toString();
+ }
+
+ private void printDescriptorLine(Formatter formatter,
+ int headerIndentWidth,
+ String header,
+ int headerWidth,
+ String fieldSeparator,
+ String description,
+ int lineWidth) {
+ final int headerPaddingWidth = headerWidth - header.length() - headerIndentWidth;
+ final int descriptionWidth = lineWidth - fieldSeparator.length() - headerWidth;
+ List<String> wordWrappedText = TextFormattingUtils.wordWrap(description,descriptionWidth);
+
+ String headerIndentFormatString = headerIndentWidth > 0 ? "%" + headerIndentWidth + "s" : "%s";
+ String headerPaddingFormatString = headerPaddingWidth > 0 ? "%" + headerPaddingWidth + "s" : "%s";
+ String headerWidthFormatString = headerWidth > 0 ? "%" + headerWidth + "s" : "%s";
+
+ // Output description line.
+ formatter.format(headerIndentFormatString + "%s" + headerPaddingFormatString + "%s%s%n",
+ "", header, "", fieldSeparator, wordWrappedText.size()>0?wordWrappedText.get(0):"");
+ for(int i = 1; i < wordWrappedText.size(); i++)
+ formatter.format(headerWidthFormatString + "%s%s%n", "", fieldSeparator, wordWrappedText.get(i));
+ }
+
+}
+
+/**
+ * Represents a given help entry; contains a display name, a summary and optionally some children.
+ */
+class HelpEntry {
+ public final String uid;
+ public final String displayName;
+ public final String summary;
+ public final SortedSet<HelpEntry> children;
+
+ /**
+ * Create a new help entry with the given display name, summary and children.
+ * @param uid a unique identifier. Usually, the java package.
+ * @param displayName display name for this help entry.
+ * @param summary summary for this help entry.
+ * @param children children for this help entry.
+ */
+ public HelpEntry(String uid, String displayName, String summary, SortedSet<HelpEntry> children) {
+ this.uid = uid;
+ this.displayName = displayName;
+ this.summary = summary;
+ this.children = children;
+ }
+
+ /**
+ * Create a new help entry with the given display name, summary and children.
+ * @param uid a unique identifier. Usually, the java package.
+ * @param displayName display name for this help entry.
+ * @param summary summary for this help entry.
+ */
+ public HelpEntry(String uid, String displayName, String summary) {
+ this(uid,displayName,summary,null);
+ }
+
+}
+
+/**
+ * Compare two help entries by display name.
+ */
+class HelpEntryComparator implements Comparator<HelpEntry> {
+ private static TextFormattingUtils.CaseInsensitiveComparator textComparator = new TextFormattingUtils.CaseInsensitiveComparator();
+
+ /**
+ * Compares the order of lhs to rhs, not taking case into account.
+ * @param lhs First object to compare.
+ * @param rhs Second object to compare.
+ * @return 0 if objects are identical; -1 if lhs is before rhs, 1 if rhs is before lhs. Nulls are treated as after everything else.
+ */
+ public int compare(HelpEntry lhs, HelpEntry rhs) {
+ if(lhs == null && rhs == null) return 0;
+ if(lhs == null || lhs.displayName.equals("")) return 1;
+ if(rhs == null || rhs.displayName.equals("")) return -1;
+ return lhs.displayName.equals(rhs.displayName) ? textComparator.compare(lhs.uid,rhs.uid) : textComparator.compare(lhs.displayName,rhs.displayName);
+ }
+
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/GenomeAnalysisEngine.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/GenomeAnalysisEngine.java
new file mode 100644
index 0000000..abb6993
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/GenomeAnalysisEngine.java
@@ -0,0 +1,1280 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import com.google.java.contract.Ensures;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.variant.vcf.VCFConstants;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.datasources.reads.*;
+import org.broadinstitute.gatk.engine.datasources.reference.ReferenceDataSource;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.downsampling.DownsamplingMethod;
+import org.broadinstitute.gatk.engine.executive.MicroScheduler;
+import org.broadinstitute.gatk.engine.filters.FilterManager;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.filters.ReadGroupBlackListFilter;
+import org.broadinstitute.gatk.engine.io.OutputTracker;
+import org.broadinstitute.gatk.engine.io.stubs.SAMFileWriterStub;
+import org.broadinstitute.gatk.engine.io.stubs.Stub;
+import org.broadinstitute.gatk.engine.io.stubs.VariantContextWriterStub;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformersMode;
+import org.broadinstitute.gatk.engine.phonehome.GATKRunReport;
+import org.broadinstitute.gatk.engine.refdata.tracks.IndexDictionaryUtils;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrackBuilder;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.engine.samples.SampleDB;
+import org.broadinstitute.gatk.engine.samples.SampleDBBuilder;
+import org.broadinstitute.gatk.engine.walkers.*;
+import org.broadinstitute.gatk.tools.walkers.genotyper.IndexedSampleList;
+import org.broadinstitute.gatk.tools.walkers.genotyper.SampleList;
+import org.broadinstitute.gatk.utils.*;
+import org.broadinstitute.gatk.utils.classloader.PluginManager;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.interval.IntervalUtils;
+import org.broadinstitute.gatk.utils.progressmeter.ProgressMeter;
+import org.broadinstitute.gatk.utils.recalibration.BQSRArgumentSet;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+import org.broadinstitute.gatk.utils.threading.ThreadEfficiencyMonitor;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+import static org.broadinstitute.gatk.utils.DeprecatedToolChecks.getWalkerDeprecationInfo;
+import static org.broadinstitute.gatk.utils.DeprecatedToolChecks.isDeprecatedWalker;
+
+/**
+ * A GenomeAnalysisEngine that runs a specified walker.
+ */
+public class GenomeAnalysisEngine {
+ /**
+ * our log, which we want to capture anything from this class
+ */
+ private static Logger logger = Logger.getLogger(GenomeAnalysisEngine.class);
+ public static final long NO_RUNTIME_LIMIT = -1;
+
+ /**
+ * The GATK command-line argument parsing code.
+ */
+ private ParsingEngine parsingEngine;
+
+ /**
+ * The genomeLocParser can create and parse GenomeLocs.
+ */
+ private GenomeLocParser genomeLocParser;
+
+ /**
+ * Accessor for sharded read data.
+ */
+ private SAMDataSource readsDataSource = null;
+
+ /**
+ * Accessor for sharded reference data.
+ */
+ private ReferenceDataSource referenceDataSource = null;
+
+ /**
+ * Accessor for sample metadata
+ */
+ private SampleDB sampleDB = new SampleDB();
+
+ /**
+ * Accessor for sharded reference-ordered data.
+ */
+ private List<ReferenceOrderedDataSource> rodDataSources;
+
+ // our argument collection
+ private GATKArgumentCollection argCollection;
+
+ /**
+ * Collection of intervals used by the engine.
+ */
+ private GenomeLocSortedSet intervals = null;
+
+ /**
+ * Explicitly assign the interval set to use for this traversal (for unit testing purposes)
+ * @param intervals set of intervals to use for this traversal
+ */
+ public void setIntervals( GenomeLocSortedSet intervals ) {
+ this.intervals = intervals;
+ }
+
+ /**
+ * Collection of inputs used by the engine.
+ */
+ private Map<ArgumentSource, Object> inputs = new HashMap<ArgumentSource, Object>();
+
+ /**
+ * Collection of outputs used by the engine.
+ */
+ private Collection<Stub<?>> outputs = new ArrayList<Stub<?>>();
+
+ /**
+ * Collection of the filters applied to the input data.
+ */
+ private Collection<ReadFilter> filters;
+
+ /**
+ * Collection of the read transformers applied to the reads
+ */
+ private List<ReadTransformer> readTransformers;
+
+ /**
+ * Controls the allocation of threads between CPU vs IO.
+ */
+ private ThreadAllocation threadAllocation;
+
+ private ReadMetrics cumulativeMetrics = null;
+
+ /**
+ * A currently hacky unique name for this GATK instance
+ */
+ private String myName = "GATK_" + Math.abs(getRandomGenerator().nextInt());
+
+ /**
+ * our walker manager
+ */
+ private final WalkerManager walkerManager = new WalkerManager();
+
+ private Walker<?, ?> walker;
+
+ public void setWalker(Walker<?, ?> walker) {
+ this.walker = walker;
+ }
+
+ /**
+ * The short name of the current GATK walker as a string
+ * @return a non-null String
+ */
+ public String getWalkerName() {
+ return getWalkerName(walker.getClass());
+ }
+
+ /**
+ * A processed collection of SAM reader identifiers.
+ */
+ private Collection<SAMReaderID> samReaderIDs = Collections.emptyList();
+
+ /**
+ * Set the SAM/BAM files over which to traverse.
+ * @param samReaderIDs Collection of ids to use during this traversal.
+ */
+ public void setSAMFileIDs(Collection<SAMReaderID> samReaderIDs) {
+ this.samReaderIDs = samReaderIDs;
+ }
+
+ /**
+ * Collection of reference metadata files over which to traverse.
+ */
+ private Collection<RMDTriplet> referenceMetaDataFiles;
+
+ /**
+ * The threading efficiency monitor we use in the GATK to monitor our efficiency.
+ *
+ * May be null if one isn't active, or hasn't be initialized yet
+ */
+ private ThreadEfficiencyMonitor threadEfficiencyMonitor = null;
+
+ /**
+ * The global progress meter we are using to track our progress through the genome
+ */
+ private ProgressMeter progressMeter = null;
+
+ /**
+ * Set the reference metadata files to use for this traversal.
+ * @param referenceMetaDataFiles Collection of files and descriptors over which to traverse.
+ */
+ public void setReferenceMetaDataFiles(Collection<RMDTriplet> referenceMetaDataFiles) {
+ this.referenceMetaDataFiles = referenceMetaDataFiles;
+ }
+
+ /**
+ * The maximum runtime of this engine, in nanoseconds, set during engine initialization
+ * from the GATKArgumentCollection command line value
+ */
+ private long runtimeLimitInNanoseconds = -1;
+
+ /**
+ * Static random number generator and seed.
+ */
+ private static final long GATK_RANDOM_SEED = 47382911L;
+ private static Random randomGenerator = new Random(GATK_RANDOM_SEED);
+ public static Random getRandomGenerator() { return randomGenerator; }
+ public static void resetRandomGenerator() { randomGenerator.setSeed(GATK_RANDOM_SEED); }
+ public static void resetRandomGenerator(long seed) { randomGenerator.setSeed(seed); }
+
+ /**
+ * Base Quality Score Recalibration helper object
+ */
+ private BQSRArgumentSet bqsrArgumentSet = null;
+ public BQSRArgumentSet getBQSRArgumentSet() { return bqsrArgumentSet; }
+ public boolean hasBQSRArgumentSet() { return bqsrArgumentSet != null; }
+ public void setBaseRecalibration(final GATKArgumentCollection args) {
+ bqsrArgumentSet = new BQSRArgumentSet(args);
+ }
+
+ /**
+ * Actually run the GATK with the specified walker.
+ *
+ * @return the value of this traversal.
+ */
+ public Object execute() {
+ // first thing is to make sure the AWS keys can be decrypted
+ GATKRunReport.checkAWSAreValid();
+
+ //HeapSizeMonitor monitor = new HeapSizeMonitor();
+ //monitor.start();
+ setStartTime(new java.util.Date());
+
+ final GATKArgumentCollection args = this.getArguments();
+
+ // validate our parameters
+ if (args == null) {
+ throw new ReviewedGATKException("The GATKArgumentCollection passed to GenomeAnalysisEngine can not be null.");
+ }
+
+ // validate our parameters
+ if (this.walker == null)
+ throw new ReviewedGATKException("The walker passed to GenomeAnalysisEngine can not be null.");
+
+ if (args.nonDeterministicRandomSeed)
+ resetRandomGenerator(System.currentTimeMillis());
+
+ // if the use specified an input BQSR recalibration table then enable on the fly recalibration
+ if (args.BQSR_RECAL_FILE != null)
+ setBaseRecalibration(args);
+
+ // setup the runtime limits
+ setupRuntimeLimits(args);
+
+ // Determine how the threads should be divided between CPU vs. IO.
+ determineThreadAllocation();
+
+ // Prepare the data for traversal.
+ initializeDataSources();
+
+ // initialize and validate the interval list
+ initializeIntervals();
+ validateSuppliedIntervals();
+
+ // check to make sure that all sequence dictionaries are compatible with the reference's sequence dictionary
+ validateDataSourcesAgainstReference(readsDataSource, referenceDataSource.getReference(), rodDataSources);
+
+ // initialize sampleDB
+ initializeSampleDB();
+
+ // our microscheduler, which is in charge of running everything
+ MicroScheduler microScheduler = createMicroscheduler();
+ threadEfficiencyMonitor = microScheduler.getThreadEfficiencyMonitor();
+
+ // create temp directories as necessary
+ initializeTempDirectory();
+
+ // create the output streams
+ initializeOutputStreams(microScheduler.getOutputTracker());
+
+ // Initializing the shard iterator / BAM schedule might take some time, so let the user know vaguely what's going on
+ logger.info("Preparing for traversal" +
+ (readsDataSource.getReaderIDs().size() > 0 ? String.format(" over %d BAM files", readsDataSource.getReaderIDs().size()) : ""));
+ Iterable<Shard> shardStrategy = getShardStrategy(readsDataSource,microScheduler.getReference(),intervals);
+ logger.info("Done preparing for traversal");
+
+ // execute the microscheduler, storing the results
+ return microScheduler.execute(this.walker, shardStrategy);
+
+ //monitor.stop();
+ //logger.info(String.format("Maximum heap size consumed: %d",monitor.getMaxMemoryUsed()));
+
+ //return result;
+ }
+
+ /**
+ * Retrieves an instance of the walker based on the walker name.
+ *
+ * @param walkerName Name of the walker. Must not be null. If the walker cannot be instantiated, an exception will be thrown.
+ * @return An instance of the walker.
+ */
+ public Walker<?, ?> getWalkerByName(String walkerName) {
+ try {
+ return walkerManager.createByName(walkerName);
+ } catch ( UserException e ) {
+ if ( isDeprecatedWalker(walkerName) ) {
+ e = new UserException.DeprecatedWalker(walkerName, getWalkerDeprecationInfo(walkerName));
+ }
+ throw e;
+ }
+ }
+
+ /**
+ * Gets the name of a given walker type.
+ * @param walkerType Type of walker.
+ * @return Name of the walker.
+ */
+ public String getWalkerName(Class<? extends Walker> walkerType) {
+ return walkerManager.getName(walkerType);
+ }
+
+ public String getName() {
+ return myName;
+ }
+
+ /**
+ * Gets a list of the filters to associate with the given walker. Will NOT initialize the engine with this filters;
+ * the caller must handle that directly.
+ * @return A collection of available filters.
+ */
+ public Collection<ReadFilter> createFilters() {
+ final List<ReadFilter> filters = new LinkedList<>();
+
+ // First add the user requested filters
+ if (this.getArguments().readGroupBlackList != null && this.getArguments().readGroupBlackList.size() > 0)
+ filters.add(new ReadGroupBlackListFilter(this.getArguments().readGroupBlackList));
+ for(final String filterName: this.getArguments().readFilters)
+ filters.add(this.getFilterManager().createByName(filterName));
+
+ // now add the walker default filters. This ordering is critical important if
+ // users need to apply filters that fix up reads that would be removed by default walker filters
+ filters.addAll(WalkerManager.getReadFilters(walker,this.getFilterManager()));
+
+ return Collections.unmodifiableList(filters);
+ }
+
+ /**
+ * Returns a list of active, initialized read transformers
+ *
+ * @param walker the walker we need to apply read transformers too
+ */
+ public void initializeReadTransformers(final Walker walker) {
+ // keep a list of the active read transformers sorted based on priority ordering
+ List<ReadTransformer> activeTransformers = new ArrayList<ReadTransformer>();
+
+ final ReadTransformersMode overrideMode = WalkerManager.getWalkerAnnotation(walker, ReadTransformersMode.class);
+ final ReadTransformer.ApplicationTime overrideTime = overrideMode != null ? overrideMode.ApplicationTime() : null;
+
+ final PluginManager<ReadTransformer> pluginManager = new PluginManager<ReadTransformer>(ReadTransformer.class);
+
+ for ( final ReadTransformer transformer : pluginManager.createAllTypes() ) {
+ transformer.initialize(overrideTime, this, walker);
+ if ( transformer.enabled() )
+ activeTransformers.add(transformer);
+ }
+
+ setReadTransformers(activeTransformers);
+ }
+
+ public List<ReadTransformer> getReadTransformers() {
+ return readTransformers;
+ }
+
+ /*
+ * Sanity checks that incompatible read transformers are not active together (and throws an exception if they are).
+ *
+ * @param readTransformers the active read transformers
+ */
+ protected void checkActiveReadTransformers(final List<ReadTransformer> readTransformers) {
+ if ( readTransformers == null )
+ throw new IllegalArgumentException("read transformers cannot be null");
+
+ ReadTransformer sawMustBeFirst = null;
+ ReadTransformer sawMustBeLast = null;
+
+ for ( final ReadTransformer r : readTransformers ) {
+ if ( r.getOrderingConstraint() == ReadTransformer.OrderingConstraint.MUST_BE_FIRST ) {
+ if ( sawMustBeFirst != null )
+ throw new UserException.IncompatibleReadFiltersException(sawMustBeFirst.toString(), r.toString());
+ sawMustBeFirst = r;
+ } else if ( r.getOrderingConstraint() == ReadTransformer.OrderingConstraint.MUST_BE_LAST ) {
+ if ( sawMustBeLast != null )
+ throw new UserException.IncompatibleReadFiltersException(sawMustBeLast.toString(), r.toString());
+ sawMustBeLast = r;
+ }
+ }
+ }
+
+ protected void setReadTransformers(final List<ReadTransformer> readTransformers) {
+ if ( readTransformers == null )
+ throw new ReviewedGATKException("read transformers cannot be null");
+
+ // sort them in priority order
+ Collections.sort(readTransformers, new ReadTransformer.ReadTransformerComparator());
+
+ // make sure we don't have an invalid set of active read transformers
+ checkActiveReadTransformers(readTransformers);
+
+ this.readTransformers = readTransformers;
+ }
+
+ /**
+ * Parse out the thread allocation from the given command-line argument.
+ */
+ private void determineThreadAllocation() {
+ if ( argCollection.numberOfDataThreads < 1 ) throw new UserException.BadArgumentValue("num_threads", "cannot be less than 1, but saw " + argCollection.numberOfDataThreads);
+ if ( argCollection.numberOfCPUThreadsPerDataThread < 1 ) throw new UserException.BadArgumentValue("num_cpu_threads", "cannot be less than 1, but saw " + argCollection.numberOfCPUThreadsPerDataThread);
+ if ( argCollection.numberOfIOThreads < 0 ) throw new UserException.BadArgumentValue("num_io_threads", "cannot be less than 0, but saw " + argCollection.numberOfIOThreads);
+
+ this.threadAllocation = new ThreadAllocation(argCollection.numberOfDataThreads,
+ argCollection.numberOfCPUThreadsPerDataThread,
+ argCollection.numberOfIOThreads,
+ argCollection.monitorThreadEfficiency);
+ }
+
+ public int getTotalNumberOfThreads() {
+ return this.threadAllocation == null ? 1 : threadAllocation.getTotalNumThreads();
+ }
+
+
+
+ /**
+ * Allow subclasses and others within this package direct access to the walker manager.
+ * @return The walker manager used by this package.
+ */
+ protected WalkerManager getWalkerManager() {
+ return walkerManager;
+ }
+
+ /**
+ * setup a microscheduler
+ *
+ * @return a new microscheduler
+ */
+ private MicroScheduler createMicroscheduler() {
+ // Temporarily require all walkers to have a reference, even if that reference is not conceptually necessary.
+ if ((walker instanceof ReadWalker || walker instanceof DuplicateWalker || walker instanceof ReadPairWalker) &&
+ this.getArguments().referenceFile == null) {
+ throw new UserException.CommandLineException("Read-based traversals require a reference file but none was given");
+ }
+
+ return MicroScheduler.create(this,walker,this.getReadsDataSource(),this.getReferenceDataSource().getReference(),this.getRodDataSources(),threadAllocation);
+ }
+
+ protected DownsamplingMethod getDownsamplingMethod() {
+ GATKArgumentCollection argCollection = this.getArguments();
+
+ DownsamplingMethod commandLineMethod = argCollection.getDownsamplingMethod();
+ DownsamplingMethod walkerMethod = WalkerManager.getDownsamplingMethod(walker);
+
+ DownsamplingMethod method = commandLineMethod != null ? commandLineMethod : walkerMethod;
+ method.checkCompatibilityWithWalker(walker);
+ return method;
+ }
+
+ protected void setDownsamplingMethod(DownsamplingMethod method) {
+ argCollection.setDownsamplingMethod(method);
+ }
+
+ protected boolean includeReadsWithDeletionAtLoci() {
+ return walker.includeReadsWithDeletionAtLoci();
+ }
+
+ /**
+ * Verifies that the supplied set of reads files mesh with what the walker says it requires;
+ * also makes sure that list of SAM files specified on the command line is not empty and contains
+ * no duplicates.
+ */
+ protected void validateSuppliedReads() {
+ GATKArgumentCollection arguments = this.getArguments();
+ final Boolean samFilesArePresent = (arguments.samFiles != null && !arguments.samFiles.isEmpty());
+
+ // Check what the walker says is required against what was provided on the command line.
+ if (WalkerManager.isRequired(walker, DataSource.READS) && !samFilesArePresent)
+ throw new ArgumentException("Walker requires reads but none were provided.");
+
+ // Check what the walker says is allowed against what was provided on the command line.
+ if (samFilesArePresent && !WalkerManager.isAllowed(walker, DataSource.READS))
+ throw new ArgumentException("Walker does not allow reads but reads were provided.");
+
+ //Make sure SAM list specified by the user (if necessary) is not empty
+ if(WalkerManager.isRequired(walker, DataSource.READS) && samFilesArePresent && samReaderIDs.isEmpty() ) {
+ throw new UserException("The list of input files does not contain any BAM files.");
+ }
+
+ // Make sure no SAM files were specified multiple times by the user.
+ checkForDuplicateSamFiles();
+ }
+
+ /**
+ * Checks whether there are SAM files that appear multiple times in the fully unpacked list of
+ * SAM files (samReaderIDs). If there are, throws an ArgumentException listing the files in question.
+ */
+ protected void checkForDuplicateSamFiles() {
+ Set<SAMReaderID> encounteredSamFiles = new HashSet<SAMReaderID>();
+ Set<String> duplicateSamFiles = new LinkedHashSet<String>();
+
+ for ( SAMReaderID samFile : samReaderIDs ) {
+ if ( encounteredSamFiles.contains(samFile) ) {
+ duplicateSamFiles.add(samFile.getSamFilePath());
+ }
+ else {
+ encounteredSamFiles.add(samFile);
+ }
+ }
+
+ if ( duplicateSamFiles.size() > 0 ) {
+ throw new UserException("The following BAM files appear multiple times in the list of input files: " +
+ duplicateSamFiles + " BAM files may be specified at most once.");
+ }
+
+ }
+
+ /**
+ * Verifies that the supplied reference file mesh with what the walker says it requires.
+ */
+ protected void validateSuppliedReference() {
+ GATKArgumentCollection arguments = this.getArguments();
+ // Check what the walker says is required against what was provided on the command line.
+ // TODO: Temporarily disabling WalkerManager.isRequired check on the reference because the reference is always required.
+ if (/*WalkerManager.isRequired(walker, DataSource.REFERENCE) &&*/ arguments.referenceFile == null)
+ throw new ArgumentException("Walker requires a reference but none was provided.");
+
+ // Check what the walker says is allowed against what was provided on the command line.
+ if (arguments.referenceFile != null && !WalkerManager.isAllowed(walker, DataSource.REFERENCE))
+ throw new ArgumentException("Walker does not allow a reference but one was provided.");
+ }
+
+ protected void validateSuppliedIntervals() {
+ // Only read walkers support '-L unmapped' intervals. Trap and validate any other instances of -L unmapped.
+ if(!(walker instanceof ReadWalker)) {
+ GenomeLocSortedSet intervals = getIntervals();
+ if(intervals != null && getIntervals().contains(GenomeLoc.UNMAPPED))
+ throw new ArgumentException("Interval list specifies unmapped region. Only read walkers may include the unmapped region.");
+ }
+
+ // If intervals is non-null and empty at this point, it means that the list of intervals to process
+ // was filtered down to an empty set (eg., the user specified something like -L chr1 -XL chr1). Since
+ // this was very likely unintentional, the user should be informed of this. Note that this is different
+ // from the case where intervals == null, which indicates that there were no interval arguments.
+ if ( intervals != null && intervals.isEmpty() ) {
+ logger.warn("The given combination of -L and -XL options results in an empty set. No intervals to process.");
+ }
+
+ // TODO: add a check for ActiveRegion walkers to prevent users from passing an entire contig/chromosome
+ }
+
+ /**
+ * Get the sharding strategy given a driving data source.
+ *
+ * @param readsDataSource readsDataSource
+ * @param drivingDataSource Data on which to shard.
+ * @param intervals intervals
+ * @return the sharding strategy
+ */
+ protected Iterable<Shard> getShardStrategy(SAMDataSource readsDataSource, ReferenceSequenceFile drivingDataSource, GenomeLocSortedSet intervals) {
+ ValidationExclusion exclusions = (readsDataSource != null ? readsDataSource.getReadsInfo().getValidationExclusionList() : null);
+ DownsamplingMethod downsamplingMethod = readsDataSource != null ? readsDataSource.getReadsInfo().getDownsamplingMethod() : null;
+ ReferenceDataSource referenceDataSource = this.getReferenceDataSource();
+
+ // If reads are present, assume that accessing the reads is always the dominant factor and shard based on that supposition.
+ if(!readsDataSource.isEmpty()) {
+ if(!readsDataSource.hasIndex() && !exclusions.contains(ValidationExclusion.TYPE.ALLOW_UNINDEXED_BAM))
+ throw new UserException.CommandLineException("Cannot process the provided BAM file(s) because they were not indexed. The GATK does offer limited processing of unindexed BAMs in --unsafe mode, but this GATK feature is currently unsupported.");
+ if(!readsDataSource.hasIndex() && intervals != null && !argCollection.allowIntervalsWithUnindexedBAM)
+ throw new UserException.CommandLineException("Cannot perform interval processing when reads are present but no index is available.");
+
+ if(walker instanceof LocusWalker) {
+ if (readsDataSource.getSortOrder() != SAMFileHeader.SortOrder.coordinate)
+ throw new UserException.MissortedBAM(SAMFileHeader.SortOrder.coordinate, "Locus walkers can only traverse coordinate-sorted data. Please resort your input BAM file(s) or set the Sort Order tag in the header appropriately.");
+ if(intervals == null)
+ return readsDataSource.createShardIteratorOverMappedReads(new LocusShardBalancer());
+ else
+ return readsDataSource.createShardIteratorOverIntervals(intervals,new LocusShardBalancer());
+ }
+ else if(walker instanceof ActiveRegionWalker) {
+ if (readsDataSource.getSortOrder() != SAMFileHeader.SortOrder.coordinate)
+ throw new UserException.MissortedBAM(SAMFileHeader.SortOrder.coordinate, "Active region walkers can only traverse coordinate-sorted data. Please resort your input BAM file(s) or set the Sort Order tag in the header appropriately.");
+ if(intervals == null)
+ return readsDataSource.createShardIteratorOverMappedReads(new ActiveRegionShardBalancer());
+ else
+ return readsDataSource.createShardIteratorOverIntervals(((ActiveRegionWalker)walker).extendIntervals(intervals, this.genomeLocParser, this.getReferenceDataSource().getReference()), new ActiveRegionShardBalancer());
+ }
+ else if(walker instanceof ReadWalker || walker instanceof ReadPairWalker || walker instanceof DuplicateWalker) {
+ // Apply special validation to read pair walkers.
+ if(walker instanceof ReadPairWalker) {
+ if(readsDataSource.getSortOrder() != SAMFileHeader.SortOrder.queryname)
+ throw new UserException.MissortedBAM(SAMFileHeader.SortOrder.queryname, "Read pair walkers are exceptions in that they cannot be run on coordinate-sorted BAMs but instead require query name-sorted files. You will need to resort your input BAM file in query name order to use this walker.");
+ if(intervals != null && !intervals.isEmpty())
+ throw new UserException.CommandLineException("Pairs traversal cannot be used in conjunction with intervals.");
+ }
+
+ if(intervals == null)
+ return readsDataSource.createShardIteratorOverAllReads(new ReadShardBalancer());
+ else
+ return readsDataSource.createShardIteratorOverIntervals(intervals, new ReadShardBalancer());
+ }
+ else
+ throw new ReviewedGATKException("Unable to determine walker type for walker " + walker.getClass().getName());
+ }
+ else {
+ // TODO -- Determine what the ideal shard size should be here. Matt suggested that a multiple of 16K might work well
+ // TODO -- (because of how VCF indexes work), but my empirical experience has been simply that the larger the shard
+ // TODO -- size the more efficient the traversal (at least for RODWalkers). Keeping the previous values for now. [EB]
+ final int SHARD_SIZE = walker instanceof RodWalker ? 1000000 : 100000;
+ if(intervals == null)
+ return referenceDataSource.createShardsOverEntireReference(readsDataSource,genomeLocParser,SHARD_SIZE);
+ else
+ return referenceDataSource.createShardsOverIntervals(readsDataSource,intervals,SHARD_SIZE);
+ }
+ }
+
+ protected boolean flashbackData() {
+ return walker instanceof ReadWalker;
+ }
+
+ /**
+ * Create the temp directory if it doesn't exist.
+ */
+ private void initializeTempDirectory() {
+ File tempDir = new File(System.getProperty("java.io.tmpdir"));
+ if (!tempDir.exists() && !tempDir.mkdirs())
+ throw new UserException.BadTmpDir("Unable to create directory");
+ }
+
+ /**
+ * Initialize the output streams as specified by the user.
+ *
+ * @param outputTracker the tracker supplying the initialization data.
+ */
+ private void initializeOutputStreams(final OutputTracker outputTracker) {
+ for (final Map.Entry<ArgumentSource, Object> input : getInputs().entrySet())
+ outputTracker.addInput(input.getKey(), input.getValue());
+ for (final Stub<?> stub : getOutputs()) {
+ stub.processArguments(argCollection);
+ outputTracker.addOutput(stub);
+ }
+
+ outputTracker.prepareWalker(walker, getArguments().strictnessLevel);
+ }
+
+ public ReferenceDataSource getReferenceDataSource() {
+ return referenceDataSource;
+ }
+
+ public GenomeLocParser getGenomeLocParser() {
+ return genomeLocParser;
+ }
+
+ /**
+ * Manage lists of filters.
+ */
+ private final FilterManager filterManager = new FilterManager();
+
+ private Date startTime = null; // the start time for execution
+
+ public void setParser(ParsingEngine parsingEngine) {
+ this.parsingEngine = parsingEngine;
+ }
+
+ /**
+ * Explicitly set the GenomeLocParser, for unit testing.
+ * @param genomeLocParser GenomeLocParser to use.
+ */
+ public void setGenomeLocParser(GenomeLocParser genomeLocParser) {
+ this.genomeLocParser = genomeLocParser;
+ }
+
+ /**
+ * Sets the start time when the execute() function was last called
+ * @param startTime the start time when the execute() function was last called
+ */
+ protected void setStartTime(Date startTime) {
+ this.startTime = startTime;
+ }
+
+ /**
+ * @return the start time when the execute() function was last called
+ */
+ public Date getStartTime() {
+ return startTime;
+ }
+
+ /**
+ * Setup the intervals to be processed
+ */
+ protected void initializeIntervals() {
+ intervals = IntervalUtils.parseIntervalArguments(this.referenceDataSource, argCollection.intervalArguments);
+ }
+
+ /**
+ * Add additional, externally managed IO streams for inputs.
+ *
+ * @param argumentSource Field into which to inject the value.
+ * @param value Instance to inject.
+ */
+ public void addInput(ArgumentSource argumentSource, Object value) {
+ inputs.put(argumentSource, value);
+ }
+
+ /**
+ * Add additional, externally managed IO streams for output.
+ *
+ * @param stub Instance to inject.
+ */
+ public void addOutput(Stub<?> stub) {
+ outputs.add(stub);
+ }
+
+ /**
+ * Returns the tag associated with a given command-line argument.
+ * @param key Object for which to inspect the tag.
+ * @return Tags object associated with the given key, or an empty Tag structure if none are present.
+ */
+ public Tags getTags(Object key) {
+ return parsingEngine.getTags(key);
+ }
+
+ protected void initializeDataSources() {
+ logger.info("Strictness is " + argCollection.strictnessLevel);
+
+ validateSuppliedReference();
+ setReferenceDataSource(argCollection.referenceFile);
+
+ validateSuppliedReads();
+ initializeReadTransformers(walker);
+
+ final Map<String, String> sampleRenameMap = argCollection.sampleRenameMappingFile != null ?
+ loadSampleRenameMap(argCollection.sampleRenameMappingFile) :
+ null;
+
+ readsDataSource = createReadsDataSource(argCollection,genomeLocParser,referenceDataSource.getReference(), sampleRenameMap);
+
+ for (ReadFilter filter : filters)
+ filter.initialize(this);
+
+ // set the sequence dictionary of all of Tribble tracks to the sequence dictionary of our reference
+ rodDataSources = getReferenceOrderedDataSources(referenceMetaDataFiles,referenceDataSource.getReference().getSequenceDictionary(),
+ genomeLocParser,argCollection.unsafe,sampleRenameMap);
+ }
+
+ /**
+ * Purely for testing purposes. Do not use unless you absolutely positively know what you are doing (or
+ * need to absolutely positively kill everyone in the room)
+ * @param dataSource
+ */
+ public void setReadsDataSource(final SAMDataSource dataSource) {
+ this.readsDataSource = dataSource;
+ }
+
+ /**
+ * Entry-point function to initialize the samples database from input data and pedigree arguments
+ */
+ private void initializeSampleDB() {
+ SampleDBBuilder sampleDBBuilder = new SampleDBBuilder(this, argCollection.pedigreeValidationType);
+ sampleDBBuilder.addSamplesFromSAMHeader(getSAMFileHeader());
+ sampleDBBuilder.addSamplesFromSampleNames(SampleUtils.getUniqueSamplesFromRods(this));
+ sampleDBBuilder.addSamplesFromPedigreeFiles(argCollection.pedigreeFiles);
+ sampleDBBuilder.addSamplesFromPedigreeStrings(argCollection.pedigreeStrings);
+ sampleDB = sampleDBBuilder.getFinalSampleDB();
+ }
+
+ /**
+ * Gets a unique identifier for the reader sourcing this read.
+ * @param read Read to examine.
+ * @return A unique identifier for the source file of this read. Exception if not found.
+ */
+ public SAMReaderID getReaderIDForRead(final SAMRecord read) {
+ return getReadsDataSource().getReaderID(read);
+ }
+
+ /**
+ * Gets the source file for this read.
+ * @param id Unique identifier determining which input file to use.
+ * @return The source filename for this read.
+ */
+ public File getSourceFileForReaderID(final SAMReaderID id) {
+ return getReadsDataSource().getSAMFile(id);
+ }
+
+ /**
+ * Now that all files are open, validate the sequence dictionaries of the reads vs. the reference vrs the reference ordered data (if available).
+ *
+ * @param reads Reads data source.
+ * @param reference Reference data source.
+ * @param rods a collection of the reference ordered data tracks
+ */
+ private void validateDataSourcesAgainstReference(SAMDataSource reads, ReferenceSequenceFile reference, Collection<ReferenceOrderedDataSource> rods) {
+ if ((reads.isEmpty() && (rods == null || rods.isEmpty())) || reference == null )
+ return;
+
+ // Compile a set of sequence names that exist in the reference file.
+ SAMSequenceDictionary referenceDictionary = reference.getSequenceDictionary();
+
+ if (!reads.isEmpty()) {
+ // Compile a set of sequence names that exist in the BAM files.
+ SAMSequenceDictionary readsDictionary = reads.getHeader().getSequenceDictionary();
+
+ if (readsDictionary.size() == 0) {
+ logger.info("Reads file is unmapped. Skipping validation against reference.");
+ return;
+ }
+
+ // compare the reads to the reference
+ SequenceDictionaryUtils.validateDictionaries(logger, getArguments().unsafe, "reads", readsDictionary,
+ "reference", referenceDictionary, true, intervals);
+ }
+
+ for (ReferenceOrderedDataSource rod : rods)
+ IndexDictionaryUtils.validateTrackSequenceDictionary(rod.getName(), rod.getSequenceDictionary(), referenceDictionary, getArguments().unsafe);
+ }
+
+ /**
+ * Gets a data source for the given set of reads.
+ *
+ * @param argCollection arguments
+ * @param genomeLocParser parser
+ * @param refReader reader
+ * @return A data source for the given set of reads.
+ */
+ private SAMDataSource createReadsDataSource(final GATKArgumentCollection argCollection, final GenomeLocParser genomeLocParser,
+ final IndexedFastaSequenceFile refReader, final Map<String, String> sampleRenameMap) {
+ DownsamplingMethod downsamplingMethod = getDownsamplingMethod();
+
+ // Synchronize the method back into the collection so that it shows up when
+ // interrogating for the downsampling method during command line recreation.
+ setDownsamplingMethod(downsamplingMethod);
+
+ logger.info(downsamplingMethod);
+
+ if (argCollection.removeProgramRecords && argCollection.keepProgramRecords)
+ throw new UserException.BadArgumentValue("rpr / kpr", "Cannot enable both options");
+
+ boolean removeProgramRecords = argCollection.removeProgramRecords || walker.getClass().isAnnotationPresent(RemoveProgramRecords.class);
+
+ if (argCollection.keepProgramRecords)
+ removeProgramRecords = false;
+
+ final boolean keepReadsInLIBS = walker instanceof ActiveRegionWalker;
+
+ return new SAMDataSource(
+ samReaderIDs,
+ threadAllocation,
+ argCollection.numberOfBAMFileHandles,
+ genomeLocParser,
+ argCollection.useOriginalBaseQualities,
+ argCollection.strictnessLevel,
+ argCollection.readBufferSize,
+ downsamplingMethod,
+ new ValidationExclusion(Arrays.asList(argCollection.unsafe)),
+ filters,
+ readTransformers,
+ includeReadsWithDeletionAtLoci(),
+ argCollection.defaultBaseQualities,
+ removeProgramRecords,
+ keepReadsInLIBS,
+ sampleRenameMap,
+ argCollection.intervalArguments.intervalMerging);
+ }
+
+ /**
+ * Loads a user-provided sample rename map file for use in on-the-fly sample renaming into an in-memory
+ * HashMap. This file must consist of lines with two whitespace-separated fields, the second of which
+ * may contain whitespace:
+ *
+ * absolute_path_to_file new_sample_name
+ *
+ * The engine will verify that each file contains data from only one sample when the on-the-fly sample
+ * renaming feature is being used. Note that this feature works only with bam and vcf files.
+ *
+ * @param sampleRenameMapFile sample rename map file from which to load data
+ * @return a HashMap containing the contents of the map file, with the keys being the input file paths and
+ * the values being the new sample names.
+ */
+ protected Map<String, String> loadSampleRenameMap( final File sampleRenameMapFile ) {
+ logger.info("Renaming samples from input files on-the-fly using mapping file " + sampleRenameMapFile.getAbsolutePath());
+
+ final Map<String, String> sampleRenameMap = new HashMap<>((int)sampleRenameMapFile.length() / 50);
+
+ try {
+ for ( final String line : new XReadLines(sampleRenameMapFile) ) {
+ final String[] tokens = line.split("\\s+", 2);
+
+ if ( tokens.length != 2 ) {
+ throw new UserException.MalformedFile(sampleRenameMapFile,
+ String.format("Encountered a line with %s fields instead of the required 2 fields. Line was: %s",
+ tokens.length, line));
+ }
+
+ final File inputFile = new File(tokens[0]);
+ final String newSampleName = tokens[1].trim();
+
+ if (newSampleName.contains(VCFConstants.FIELD_SEPARATOR)) {
+ throw new UserException.MalformedFile(sampleRenameMapFile, String.format(
+ "Encountered illegal sample name; sample names may not include the VCF field delimiter (%s). Sample name: %s; line: %s",
+ VCFConstants.FIELD_SEPARATOR,
+ newSampleName,
+ line
+ ));
+ }
+
+ if ( ! inputFile.isAbsolute() ) {
+ throw new UserException.MalformedFile(sampleRenameMapFile, "Input file path not absolute at line: " + line);
+ }
+
+ final String inputFilePath = inputFile.getAbsolutePath();
+
+ if ( sampleRenameMap.containsKey(inputFilePath) ) {
+ throw new UserException.MalformedFile(sampleRenameMapFile,
+ String.format("Input file %s appears more than once", inputFilePath));
+ }
+
+ sampleRenameMap.put(inputFilePath, newSampleName);
+ }
+ }
+ catch ( FileNotFoundException e ) {
+ throw new UserException.CouldNotReadInputFile(sampleRenameMapFile, e);
+ }
+
+ return sampleRenameMap;
+ }
+
+
+ /**
+ * Opens a reference sequence file paired with an index. Only public for testing purposes
+ *
+ * @param refFile Handle to a reference sequence file. Non-null.
+ */
+ public void setReferenceDataSource(File refFile) {
+ this.referenceDataSource = new ReferenceDataSource(refFile);
+ genomeLocParser = new GenomeLocParser(referenceDataSource.getReference());
+ }
+
+ /**
+ * Open the reference-ordered data sources.
+ *
+ * @param referenceMetaDataFiles collection of RMD descriptors to load and validate.
+ * @param sequenceDictionary GATK-wide sequnce dictionary to use for validation.
+ * @param genomeLocParser to use when creating and validating GenomeLocs.
+ * @param validationExclusionType potentially indicate which validations to include / exclude.
+ * @param sampleRenameMap map of file -> new sample name used when doing on-the-fly sample renaming
+ *
+ * @return A list of reference-ordered data sources.
+ */
+ private List<ReferenceOrderedDataSource> getReferenceOrderedDataSources(final Collection<RMDTriplet> referenceMetaDataFiles,
+ final SAMSequenceDictionary sequenceDictionary,
+ final GenomeLocParser genomeLocParser,
+ final ValidationExclusion.TYPE validationExclusionType,
+ final Map<String, String> sampleRenameMap) {
+ final RMDTrackBuilder builder = new RMDTrackBuilder(sequenceDictionary,genomeLocParser, validationExclusionType,
+ getArguments().disableAutoIndexCreationAndLockingWhenReadingRods,
+ sampleRenameMap);
+
+ final List<ReferenceOrderedDataSource> dataSources = new ArrayList<ReferenceOrderedDataSource>();
+ for (RMDTriplet fileDescriptor : referenceMetaDataFiles)
+ dataSources.add(new ReferenceOrderedDataSource(fileDescriptor,
+ builder,
+ sequenceDictionary,
+ genomeLocParser,
+ flashbackData()));
+
+ return dataSources;
+ }
+
+ /**
+ * Returns the SAM File Header from the input reads' data source file
+ * @return the SAM File Header from the input reads' data source file
+ */
+ public SAMFileHeader getSAMFileHeader() {
+ return readsDataSource.getHeader();
+ }
+
+ public boolean lenientVCFProcessing() {
+ return lenientVCFProcessing(argCollection.unsafe);
+ }
+
+ public static boolean lenientVCFProcessing(final ValidationExclusion.TYPE val) {
+ return val == ValidationExclusion.TYPE.ALL
+ || val == ValidationExclusion.TYPE.LENIENT_VCF_PROCESSING;
+ }
+
+ /**
+ * Returns the unmerged SAM file header for an individual reader.
+ * @param reader The reader.
+ * @return Header for that reader or null if not available.
+ */
+ public SAMFileHeader getSAMFileHeader(SAMReaderID reader) {
+ return readsDataSource == null ? null : readsDataSource.getHeader(reader);
+ }
+
+ /**
+ * Returns an ordered list of the unmerged SAM file headers known to this engine.
+ * @return list of header for each input SAM file, in command line order
+ */
+ public List<SAMFileHeader> getSAMFileHeaders() {
+ final List<SAMFileHeader> headers = new ArrayList<SAMFileHeader>();
+ for ( final SAMReaderID id : getReadsDataSource().getReaderIDs() ) {
+ headers.add(getReadsDataSource().getHeader(id));
+ }
+ return headers;
+ }
+
+ /**
+ * Gets the master sequence dictionary for this GATK engine instance
+ * @return a never-null dictionary listing all of the contigs known to this engine instance
+ */
+ public SAMSequenceDictionary getMasterSequenceDictionary() {
+ return getReferenceDataSource().getReference().getSequenceDictionary();
+ }
+
+ /**
+ * Returns data source object encapsulating all essential info and handlers used to traverse
+ * reads; header merger, individual file readers etc can be accessed through the returned data source object.
+ *
+ * @return the reads data source
+ */
+ public SAMDataSource getReadsDataSource() {
+ return this.readsDataSource;
+ }
+
+ /**
+ * Sets the collection of GATK main application arguments.
+ *
+ * @param argCollection the GATK argument collection
+ */
+ public void setArguments(GATKArgumentCollection argCollection) {
+ this.argCollection = argCollection;
+ }
+
+ /**
+ * Gets the collection of GATK main application arguments.
+ *
+ * @return the GATK argument collection
+ */
+ public GATKArgumentCollection getArguments() {
+ return this.argCollection;
+ }
+
+ /**
+ * Get the list of intervals passed to the engine.
+ * @return List of intervals, or null if no intervals are in use
+ */
+ public GenomeLocSortedSet getIntervals() {
+ return this.intervals;
+ }
+
+ /**
+ * Get the list of regions of the genome being processed. If the user
+ * requested specific intervals, return those, otherwise return regions
+ * corresponding to the entire genome. Never returns null.
+ *
+ * @return a non-null set of intervals being processed
+ */
+ @Ensures("result != null")
+ public GenomeLocSortedSet getRegionsOfGenomeBeingProcessed() {
+ if ( getIntervals() == null )
+ // if we don't have any intervals defined, create intervals from the reference itself
+ return GenomeLocSortedSet.createSetFromSequenceDictionary(getReferenceDataSource().getReference().getSequenceDictionary());
+ else
+ return getIntervals();
+ }
+
+ /**
+ * Gets the list of filters employed by this engine.
+ * @return Collection of filters (actual instances) used by this engine.
+ */
+ public Collection<ReadFilter> getFilters() {
+ return this.filters;
+ }
+
+ /**
+ * Sets the list of filters employed by this engine.
+ * @param filters Collection of filters (actual instances) used by this engine.
+ */
+ public void setFilters(Collection<ReadFilter> filters) {
+ this.filters = filters;
+ }
+
+ /**
+ * Gets the filter manager for this engine.
+ * @return filter manager for this engine.
+ */
+ protected FilterManager getFilterManager() {
+ return filterManager;
+ }
+
+ /**
+ * Gets the input sources for this engine.
+ * @return input sources for this engine.
+ */
+ protected Map<ArgumentSource, Object> getInputs() {
+ return inputs;
+ }
+
+ /**
+ * Gets the output stubs for this engine.
+ * @return output stubs for this engine.
+ */
+ protected Collection<Stub<?>> getOutputs() {
+ return outputs;
+ }
+
+ /**
+ * Returns data source objects encapsulating all rod data;
+ * individual rods can be accessed through the returned data source objects.
+ *
+ * @return the rods data sources, never {@code null}.
+ */
+ public List<ReferenceOrderedDataSource> getRodDataSources() {
+ return this.rodDataSources;
+ }
+
+ /**
+ * Gets cumulative metrics about the entire run to this point.
+ * Returns a clone of this snapshot in time.
+ * @return cumulative metrics about the entire run at this point. ReadMetrics object is a unique instance and is
+ * owned by the caller; the caller can do with the object what they wish.
+ */
+ public ReadMetrics getCumulativeMetrics() {
+ // todo -- probably shouldn't be lazy
+ if ( cumulativeMetrics == null )
+ cumulativeMetrics = readsDataSource == null ? new ReadMetrics() : readsDataSource.getCumulativeReadMetrics();
+ return cumulativeMetrics;
+ }
+
+ /**
+ * Return the global ThreadEfficiencyMonitor, if there is one
+ *
+ * @return the monitor, or null if none is active
+ */
+ public ThreadEfficiencyMonitor getThreadEfficiencyMonitor() {
+ return threadEfficiencyMonitor;
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // code for working with Samples database
+ //
+ // -------------------------------------------------------------------------------------
+
+ public SampleDB getSampleDB() {
+ return this.sampleDB;
+ }
+
+ public Map<String,String> getApproximateCommandLineArguments(Object... argumentProviders) {
+ return CommandLineUtils.getApproximateCommandLineArguments(parsingEngine,argumentProviders);
+ }
+
+ public String createApproximateCommandLineArgumentString(Object... argumentProviders) {
+ return CommandLineUtils.createApproximateCommandLineArgumentString(parsingEngine,argumentProviders);
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // code for working with progress meter
+ //
+ // -------------------------------------------------------------------------------------
+
+ /**
+ * Register the global progress meter with this engine
+ *
+ * Calling this function more than once will result in an IllegalStateException
+ *
+ * @param meter a non-null progress meter
+ */
+ public void registerProgressMeter(final ProgressMeter meter) {
+ if ( meter == null ) throw new IllegalArgumentException("Meter cannot be null");
+ if ( progressMeter != null ) throw new IllegalStateException("Progress meter already set");
+
+ progressMeter = meter;
+ }
+
+ /**
+ * Get the progress meter being used by this engine. May be null if no meter has been registered yet
+ * @return a potentially null pointer to the progress meter
+ */
+ public ProgressMeter getProgressMeter() {
+ return progressMeter;
+ }
+
+ /**
+ * Does the current runtime in unit exceed the runtime limit, if one has been provided?
+ *
+ * @return false if not limit was requested or if runtime <= the limit, true otherwise
+ */
+ public boolean exceedsRuntimeLimit() {
+ if ( progressMeter == null )
+ // not yet initialized or not set because of testing
+ return false;
+
+ if ( getArguments().maxRuntime == NO_RUNTIME_LIMIT )
+ return false;
+ else {
+ final long runtime = progressMeter.getRuntimeInNanosecondsUpdatedPeriodically();
+ if ( runtime < 0 ) throw new IllegalArgumentException("runtime must be >= 0 but got " + runtime);
+ final long maxRuntimeNano = getRuntimeLimitInNanoseconds();
+ return runtime > maxRuntimeNano;
+ }
+ }
+
+ /**
+ * @return the runtime limit in nanoseconds, or -1 if no limit was specified
+ */
+ public long getRuntimeLimitInNanoseconds() {
+ return runtimeLimitInNanoseconds;
+ }
+
+ /**
+ * Setup the runtime limits for this engine, updating the runtimeLimitInNanoseconds
+ * as appropriate
+ *
+ * @param args the GATKArgumentCollection to retrieve our runtime limits from
+ */
+ private void setupRuntimeLimits(final GATKArgumentCollection args) {
+ if ( args.maxRuntime == NO_RUNTIME_LIMIT )
+ runtimeLimitInNanoseconds = -1;
+ else if (args.maxRuntime < 0 )
+ throw new UserException.BadArgumentValue("maxRuntime", "must be >= 0 or == -1 (meaning no limit) but received negative value " + args.maxRuntime);
+ else {
+ runtimeLimitInNanoseconds = TimeUnit.NANOSECONDS.convert(args.maxRuntime, args.maxRuntimeUnits);
+ }
+ }
+
+ /**
+ * Returns the sample list including all samples.
+ * @return never {@code null}.
+ */
+ public SampleList getSampleList() {
+ return new IndexedSampleList(getSampleDB().getSampleNames());
+ }
+
+ /**
+ * Returns the sample list including samples in read inputs.
+ * @return never {@code null}.
+ */
+ public SampleList getReadSampleList() {
+ return new IndexedSampleList(SampleUtils.getSAMFileSamples(getSAMFileHeader()));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/ReadProperties.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/ReadProperties.java
new file mode 100644
index 0000000..6ee9ad3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/ReadProperties.java
@@ -0,0 +1,198 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.ValidationStringency;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.broadinstitute.gatk.engine.downsampling.DownsamplingMethod;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+
+import java.util.Collection;
+import java.util.List;
+/**
+ * User: hanna
+ * Date: May 14, 2009
+ * Time: 4:06:26 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * A data structure containing information about the reads data sources as well as
+ * information about how they should be downsampled, sorted, and filtered.
+ */
+public class ReadProperties {
+ private final Collection<SAMReaderID> readers;
+ private final SAMFileHeader header;
+ private final SAMFileHeader.SortOrder sortOrder;
+ private final ValidationStringency validationStringency;
+ private final DownsamplingMethod downsamplingMethod;
+ private final ValidationExclusion exclusionList;
+ private final Collection<ReadFilter> supplementalFilters;
+ private final List<ReadTransformer> readTransformers;
+ private final boolean keepUniqueReadListInLIBS;
+ private final boolean includeReadsWithDeletionAtLoci;
+ private final boolean useOriginalBaseQualities;
+ private final byte defaultBaseQualities;
+
+ /**
+ * Return true if the walker wants to see reads that contain deletions when looking at locus pileups
+ *
+ * @return
+ */
+ public boolean includeReadsWithDeletionAtLoci() {
+ return includeReadsWithDeletionAtLoci;
+ }
+
+ public boolean keepUniqueReadListInLIBS() {
+ return keepUniqueReadListInLIBS;
+ }
+
+ /**
+ * Gets a list of the files acting as sources of reads.
+ * @return A list of files storing reads data.
+ */
+ public Collection<SAMReaderID> getSAMReaderIDs() {
+ return readers;
+ }
+
+ /**
+ * Gets the sam file header
+ * @return the sam file header
+ */
+ public SAMFileHeader getHeader() {
+ return header;
+ }
+
+ /**
+ * Gets the sort order of the reads
+ * @return the sort order of the reads
+ */
+ public SAMFileHeader.SortOrder getSortOrder() {
+ return sortOrder;
+ }
+
+ /**
+ * How strict should validation be?
+ * @return Stringency of validation.
+ */
+ public ValidationStringency getValidationStringency() {
+ return validationStringency;
+ }
+
+ /**
+ * Gets the method and parameters used when downsampling reads.
+ * @return Downsample fraction.
+ */
+ public DownsamplingMethod getDownsamplingMethod() {
+ return downsamplingMethod;
+ }
+
+ /**
+ * Return whether to 'verify' the reads as we pass through them.
+ * @return Whether to verify the reads.
+ */
+ public ValidationExclusion getValidationExclusionList() {
+ return exclusionList;
+ }
+
+ public Collection<ReadFilter> getSupplementalFilters() {
+ return supplementalFilters;
+ }
+
+
+ public List<ReadTransformer> getReadTransformers() {
+ return readTransformers;
+ }
+
+ /**
+ * Return whether to use original base qualities.
+ * @return Whether to use original base qualities.
+ */
+ public boolean useOriginalBaseQualities() {
+ return useOriginalBaseQualities;
+ }
+
+ /**
+ * @return Default base quality value to fill reads missing base quality information.
+ */
+ public byte defaultBaseQualities() {
+ return defaultBaseQualities;
+ }
+
+ /**
+ * Extract the command-line arguments having to do with reads input
+ * files and store them in an easy-to-work-with package. Constructor
+ * is package protected.
+ * @param samFiles list of reads files.
+ * @param header sam file header.
+ * @param useOriginalBaseQualities True if original base qualities should be used.
+ * @param strictness Stringency of reads file parsing.
+ * @param downsamplingMethod Method for downsampling reads at a given locus.
+ * @param exclusionList what safety checks we're willing to let slide
+ * @param supplementalFilters additional filters to dynamically apply.
+ * @param includeReadsWithDeletionAtLoci if 'true', the base pileups sent to the walker's map() method
+ * will explicitly list reads with deletion over the current reference base; otherwise, only observed
+ * bases will be seen in the pileups, and the deletions will be skipped silently.
+ * @param defaultBaseQualities if the reads have incomplete quality scores, set them all to defaultBaseQuality.
+ * @param keepUniqueReadListInLIBS If true, we will tell LocusIteratorByState to track the unique reads it sees
+ * This is really useful for ActiveRegionTraversals
+ */
+ public ReadProperties( Collection<SAMReaderID> samFiles,
+ SAMFileHeader header,
+ SAMFileHeader.SortOrder sortOrder,
+ boolean useOriginalBaseQualities,
+ ValidationStringency strictness,
+ DownsamplingMethod downsamplingMethod,
+ ValidationExclusion exclusionList,
+ Collection<ReadFilter> supplementalFilters,
+ List<ReadTransformer> readTransformers,
+ boolean includeReadsWithDeletionAtLoci,
+ byte defaultBaseQualities,
+ final boolean keepUniqueReadListInLIBS) {
+ this.readers = samFiles;
+ this.header = header;
+ this.sortOrder = sortOrder;
+ this.validationStringency = strictness;
+ this.downsamplingMethod = downsamplingMethod == null ? DownsamplingMethod.NONE : downsamplingMethod;
+ this.exclusionList = exclusionList == null ? new ValidationExclusion() : exclusionList;
+ this.supplementalFilters = supplementalFilters;
+ this.readTransformers = readTransformers;
+ this.includeReadsWithDeletionAtLoci = includeReadsWithDeletionAtLoci;
+ this.useOriginalBaseQualities = useOriginalBaseQualities;
+ this.defaultBaseQualities = defaultBaseQualities;
+ this.keepUniqueReadListInLIBS = keepUniqueReadListInLIBS;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/WalkerManager.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/WalkerManager.java
new file mode 100644
index 0000000..fb9d489
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/WalkerManager.java
@@ -0,0 +1,431 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import org.broadinstitute.gatk.engine.walkers.*;
+import org.broadinstitute.gatk.utils.commandline.Hidden;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+import org.broadinstitute.gatk.engine.downsampling.DownsamplingMethod;
+import org.broadinstitute.gatk.engine.filters.FilterManager;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.utils.classloader.PluginManager;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.help.ResourceBundleExtractorDoclet;
+import org.broadinstitute.gatk.utils.text.TextFormattingUtils;
+
+import java.lang.annotation.Annotation;
+import java.util.*;
+
+/**
+ * Plugin manager that also provides various utilities for inspecting Walkers.
+ */
+public class WalkerManager extends PluginManager<Walker> {
+
+ /**
+ * A collection of help text for walkers and their enclosing packages.
+ */
+ private ResourceBundle helpText;
+
+ public WalkerManager() {
+ super(Walker.class,"walker","");
+ helpText = TextFormattingUtils.loadResourceBundle("GATKText");
+ }
+
+ /**
+ * Get the list of walkers currently available to the GATK, organized
+ * by package.
+ * @param visibleWalkersOnly If true, return only the walker names that aren't hidden.
+ * @return Names of currently available walkers.
+ */
+ public Map<String,Collection<Class<? extends Walker>>> getWalkerNamesByPackage(boolean visibleWalkersOnly) {
+ Map<String,Collection<Class<? extends Walker>>> walkersByPackage = new HashMap<String,Collection<Class<? extends Walker>>>();
+ for(Class<? extends Walker> walker: getPlugins()) {
+ if(visibleWalkersOnly && isHidden(walker))
+ continue;
+
+ // Extract the name for the package; if the walker is in the unnamed package, use the empty string
+ String walkerPackage = walker.getPackage() != null ? walker.getPackage().getName() : "";
+ if(!walkersByPackage.containsKey(walkerPackage))
+ walkersByPackage.put(walkerPackage,new ArrayList<Class<? extends Walker>>());
+ walkersByPackage.get(walkerPackage).add(walker);
+ }
+ return Collections.unmodifiableMap(walkersByPackage);
+ }
+
+ /**
+ * Gets the display name for a given package.
+ * @param packageName Fully qualified package name.
+ * @return A suitable display name for the package.
+ */
+ public String getPackageDisplayName(String packageName) {
+ // ...try to compute the override from the text of the package name, while accounting for
+ // unpackaged walkers.
+ String displayName = packageName.substring(packageName.lastIndexOf('.')+1);
+ if (displayName.trim().equals("")) displayName = "<unpackaged>";
+ return displayName;
+ }
+
+ /**
+ * Gets the help text associated with a given package name.
+ * @param packageName Package for which to search for help text.
+ * @return Package help text, or "" if none exists.
+ */
+ public String getPackageSummaryText(String packageName) {
+ String key = String.format("%s.%s",packageName, ResourceBundleExtractorDoclet.SUMMARY_TAGLET_NAME);
+ if(!helpText.containsKey(key))
+ return "";
+ return helpText.getString(key);
+ }
+
+ /**
+ * Gets the summary help text associated with a given walker type.
+ * @param walkerType Type of walker for which to search for help text.
+ * @return Walker summary description, or "" if none exists.
+ */
+ public String getWalkerSummaryText(Class<? extends Walker> walkerType) {
+ String walkerSummary = String.format("%s.%s",walkerType.getName(), ResourceBundleExtractorDoclet.SUMMARY_TAGLET_NAME);
+ if(!helpText.containsKey(walkerSummary))
+ return "";
+ return helpText.getString(walkerSummary);
+ }
+
+ /**
+ * Gets the summary help text associated with a given walker type.
+ * @param walker Walker for which to search for help text.
+ * @return Walker summary description, or "" if none exists.
+ */
+ public String getWalkerSummaryText(Walker walker) {
+ return getWalkerSummaryText(walker.getClass());
+ }
+
+ /**
+ * Gets the descriptive help text associated with a given walker type.
+ * @param walkerType Type of walker for which to search for help text.
+ * @return Walker full description, or "" if none exists.
+ */
+ public String getWalkerDescriptionText(Class<? extends Walker> walkerType) {
+ String walkerDescription = String.format("%s.%s",walkerType.getName(), ResourceBundleExtractorDoclet.DESCRIPTION_TAGLET_NAME);
+ if(!helpText.containsKey(walkerDescription))
+ return "";
+ return helpText.getString(walkerDescription);
+ }
+
+ /**
+ * Gets the descriptive help text associated with a given walker type.
+ * @param walker Walker for which to search for help text.
+ * @return Walker full description, or "" if none exists.
+ */
+ public String getWalkerDescriptionText(Walker walker) {
+ return getWalkerDescriptionText(walker.getClass());
+ }
+
+ /**
+ * Retrieves the walker class given a walker name.
+ * @param walkerName Name of the walker.
+ * @return Class representing the walker.
+ */
+ public Class<? extends Walker> getWalkerClassByName(String walkerName) {
+ return getPluginsByName().get(walkerName);
+ }
+
+ /**
+ * Gets the data source for the provided walker.
+ * @param walkerClass The class of the walker.
+ * @return Which type of data source to traverse over...reads or reference?
+ */
+ public static DataSource getWalkerDataSource(Class<? extends Walker> walkerClass) {
+ By byDataSource = walkerClass.getAnnotation(By.class);
+ if( byDataSource == null )
+ throw new ReviewedGATKException("Unable to find By annotation for walker class " + walkerClass.getName());
+ return byDataSource.value();
+ }
+
+ /**
+ * Gets the data source for the provided walker.
+ * @param walker The walker.
+ * @return Which type of data source to traverse over...reads or reference?
+ */
+ public static DataSource getWalkerDataSource(Walker walker) {
+ return getWalkerDataSource(walker.getClass());
+ }
+
+ /**
+ * Get a list of RODs allowed by the walker.
+ * @param walkerClass Class of the walker to query.
+ * @return The list of allowed reference meta data.
+ */
+ public static List<RMD> getAllowsMetaData(Class<? extends Walker> walkerClass) {
+ return Collections.<RMD>emptyList();
+ }
+
+ /**
+ * Determine whether the given walker supports the given data source.
+ * @param walkerClass Class of the walker to query.
+ * @param dataSource Source to check for .
+ * @return True if the walker forbids this data type. False otherwise.
+ */
+ public static boolean isAllowed(Class<? extends Walker> walkerClass, DataSource dataSource) {
+ Allows allowsDataSource = getWalkerAllowed(walkerClass);
+
+ // Allows is less restrictive than requires. If an allows
+ // clause is not specified, any kind of data is allowed.
+ if( allowsDataSource == null )
+ return true;
+
+ return Arrays.asList(allowsDataSource.value()).contains(dataSource);
+ }
+
+ /**
+ * Determine whether the given walker supports the given data source.
+ * @param walker Walker to query.
+ * @param dataSource Source to check for .
+ * @return True if the walker forbids this data type. False otherwise.
+ */
+ public static boolean isAllowed(Walker walker, DataSource dataSource) {
+ return isAllowed(walker.getClass(), dataSource);
+ }
+
+ /**
+ * Determine whether the given walker supports the given reference ordered data.
+ * @param walkerClass Class of the walker to query.
+ * @param rod Source to check.
+ * @return True if the walker forbids this data type. False otherwise.
+ */
+ public static boolean isAllowed(Class<? extends Walker> walkerClass, ReferenceOrderedDataSource rod) {
+ return true;
+ }
+
+ /**
+ * Determine whether the given walker supports the given reference ordered data.
+ * @param walker Walker to query.
+ * @param rod Source to check.
+ * @return True if the walker forbids this data type. False otherwise.
+ */
+ public static boolean isAllowed(Walker walker, ReferenceOrderedDataSource rod) {
+ return isAllowed(walker.getClass(), rod);
+ }
+
+ /**
+ * Determine whether the given walker requires the given data source.
+ * @param walkerClass Class of the walker to query.
+ * @param dataSource Source to check for.
+ * @return True if the walker allows this data type. False otherwise.
+ */
+ public static boolean isRequired(Class<? extends Walker> walkerClass, DataSource dataSource) {
+ Requires requiresDataSource = getWalkerRequirements(walkerClass);
+ return Arrays.asList(requiresDataSource.value()).contains(dataSource);
+ }
+
+ /**
+ * Determine whether the given walker requires the given data source.
+ * @param walker Walker to query.
+ * @param dataSource Source to check for.
+ * @return True if the walker allows this data type. False otherwise.
+ */
+ public static boolean isRequired(Walker walker, DataSource dataSource) {
+ return isRequired(walker.getClass(), dataSource);
+ }
+
+ /**
+ * Get a list of RODs required by the walker.
+ * @param walkerClass Class of the walker to query.
+ * @return The list of required reference meta data.
+ */
+ public static List<RMD> getRequiredMetaData(Class<? extends Walker> walkerClass) {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Get a list of RODs required by the walker.
+ * @param walker Walker to query.
+ * @return The list of required reference meta data.
+ */
+ public static List<RMD> getRequiredMetaData(Walker walker) {
+ return getRequiredMetaData(walker.getClass());
+ }
+
+ /**
+ * Reports whether this walker type is hidden -- in other words, whether it'll appear in the help output.
+ * @param walkerType Class to test for visibility.
+ * @return True if the walker should be hidden. False otherwise.
+ */
+ public static boolean isHidden(Class<? extends Walker> walkerType) {
+ return walkerType.isAnnotationPresent(Hidden.class);
+ }
+
+ /**
+ * Extracts filters that the walker has requested be run on the dataset.
+ * @param walkerClass Class of the walker to inspect for filtering requests.
+ * @param filterManager Manages the creation of filters.
+ * @return A non-empty list of filters to apply to the reads.
+ */
+ public static List<ReadFilter> getReadFilters(Class<? extends Walker> walkerClass, FilterManager filterManager) {
+ List<ReadFilter> filters = new ArrayList<ReadFilter>();
+ for(Class<? extends ReadFilter> filterType: getReadFilterTypes(walkerClass))
+ filters.add(filterManager.createFilterByType(filterType));
+ return filters;
+ }
+
+ /**
+ * Extracts filters that the walker has requested be run on the dataset.
+ * @param walker Walker to inspect for filtering requests.
+ * @param filterManager Manages the creation of filters.
+ * @return A non-empty list of filters to apply to the reads.
+ */
+ public static List<ReadFilter> getReadFilters(Walker walker, FilterManager filterManager) {
+ return getReadFilters(walker.getClass(), filterManager);
+ }
+
+ /**
+ * Gets the type of downsampling method requested by the walker. If an alternative
+ * downsampling method is specified on the command-line, the command-line version will
+ * be used instead.
+ * @param walker The walker to interrogate.
+ * @return The downsampling method, as specified by the walker. Null if none exists.
+ */
+ public static DownsamplingMethod getDownsamplingMethod( Walker walker ) {
+ return getDownsamplingMethod(walker.getClass());
+ }
+
+ /**
+ * Gets the type of downsampling method requested by the walker. If an alternative
+ * downsampling method is specified on the command-line, the command-line version will
+ * be used instead.
+ * @param walkerClass The class of the walker to interrogate.
+ * @return The downsampling method, as specified by the walker. Null if none exists.
+ */
+ public static DownsamplingMethod getDownsamplingMethod( Class<? extends Walker> walkerClass ) {
+ DownsamplingMethod downsamplingMethod = null;
+
+ if( walkerClass.isAnnotationPresent(Downsample.class) ) {
+ Downsample downsampleParameters = walkerClass.getAnnotation(Downsample.class);
+ DownsampleType type = downsampleParameters.by();
+ Integer toCoverage = downsampleParameters.toCoverage() >= 0 ? downsampleParameters.toCoverage() : null;
+ Double toFraction = downsampleParameters.toFraction() >= 0.0d ? downsampleParameters.toFraction() : null;
+ downsamplingMethod = new DownsamplingMethod(type, toCoverage, toFraction);
+ }
+
+ return downsamplingMethod;
+ }
+
+ public static <T extends Annotation> T getWalkerAnnotation(final Walker walker, final Class<T> clazz) {
+ return walker.getClass().getAnnotation(clazz);
+ }
+
+ public static ReadTransformer.ApplicationTime getBAQApplicationTime(Walker walker) {
+ return walker.getClass().getAnnotation(BAQMode.class).ApplicationTime();
+ }
+
+ /**
+ * Create a name for this type of walker.
+ *
+ * @param walkerType The type of walker.
+ * @return A name for this type of walker.
+ */
+ @Override
+ public String getName(Class walkerType) {
+ String walkerName = "";
+
+ if (walkerType.getAnnotation(WalkerName.class) != null)
+ walkerName = ((WalkerName)walkerType.getAnnotation(WalkerName.class)).value().trim();
+ else
+ walkerName = super.getName(walkerType);
+
+ return walkerName;
+ }
+
+ /**
+ * Utility to get the requires attribute from the walker.
+ * Throws an exception if requirements are missing.
+ * @param walkerClass Class of the walker to query for required data.
+ * @return Required data attribute.
+ */
+ private static Requires getWalkerRequirements(Class<? extends Walker> walkerClass) {
+ Requires requiresDataSource = walkerClass.getAnnotation(Requires.class);
+ if( requiresDataSource == null )
+ throw new ReviewedGATKException( "Unable to find data types required by walker class " + walkerClass.getName());
+ return requiresDataSource;
+ }
+
+ /**
+ * Utility to get the requires attribute from the walker.
+ * Throws an exception if requirements are missing.
+ * @param walker Walker to query for required data.
+ * @return Required data attribute.
+ */
+ private static Requires getWalkerRequirements(Walker walker) {
+ return getWalkerRequirements(walker.getClass());
+ }
+
+ /**
+ * Utility to get the forbidden attribute from the walker.
+ * @param walkerClass Class of the walker to query for required data.
+ * @return Required data attribute. Null if forbidden info isn't present.
+ */
+ private static Allows getWalkerAllowed(Class<? extends Walker> walkerClass) {
+ Allows allowsDataSource = walkerClass.getAnnotation(Allows.class);
+ return allowsDataSource;
+ }
+
+ /**
+ * Utility to get the forbidden attribute from the walker.
+ * @param walker Walker to query for required data.
+ * @return Required data attribute. Null if forbidden info isn't present.
+ */
+ private static Allows getWalkerAllowed(Walker walker) {
+ return getWalkerAllowed(walker.getClass());
+ }
+
+ /**
+ * Gets the list of filtering classes specified as walker annotations.
+ * @param walkerClass Class of the walker to inspect.
+ * @return An array of types extending from SamRecordFilter. Will never be null.
+ */
+ public static Collection<Class<? extends ReadFilter>> getReadFilterTypes(Class<?> walkerClass) {
+ List<Class<? extends ReadFilter>> filterTypes = new ArrayList<Class<? extends ReadFilter>>();
+ while(walkerClass != null) {
+ if(walkerClass.isAnnotationPresent(ReadFilters.class)) {
+ for ( Class c : walkerClass.getAnnotation(ReadFilters.class).value() ) {
+ if( !filterTypes.contains(c) )
+ filterTypes.add(c);
+ }
+ }
+ walkerClass = walkerClass.getSuperclass();
+ }
+ return filterTypes;
+ }
+
+ /**
+ * Gets the list of filtering classes specified as walker annotations.
+ * @param walker The walker to inspect.
+ * @return An array of types extending from SamRecordFilter. Will never be null.
+ */
+ public static Collection<Class<? extends ReadFilter>> getReadFilterTypes(Walker walker) {
+ return getReadFilterTypes(walker.getClass());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/Aligner.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/Aligner.java
new file mode 100644
index 0000000..e9622c9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/Aligner.java
@@ -0,0 +1,74 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Create perfect alignments from the read to the genome represented by the given BWT / suffix array.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public interface Aligner {
+ /**
+ * Close this instance of the BWA pointer and delete its resources.
+ */
+ public void close();
+
+ /**
+ * Allow the aligner to choose one alignment randomly from the pile of best alignments.
+ * @param bases Bases to align.
+ * @return An align
+ */
+ public Alignment getBestAlignment(final byte[] bases);
+
+ /**
+ * Align the read to the reference.
+ * @param read Read to align.
+ * @param header Optional header to drop in place.
+ * @return A list of the alignments.
+ */
+ public SAMRecord align(final SAMRecord read, final SAMFileHeader header);
+
+ /**
+ * Get a iterator of alignments, batched by mapping quality.
+ * @param bases List of bases.
+ * @return Iterator to alignments.
+ */
+ public Iterable<Alignment[]> getAllAlignments(final byte[] bases);
+
+ /**
+ * Get a iterator of aligned reads, batched by mapping quality.
+ * @param read Read to align.
+ * @param newHeader Optional new header to use when aligning the read. If present, it must be null.
+ * @return Iterator to alignments.
+ */
+ public Iterable<SAMRecord[]> alignAll(final SAMRecord read, final SAMFileHeader newHeader);
+}
+
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/Alignment.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/Alignment.java
new file mode 100644
index 0000000..02bc06f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/Alignment.java
@@ -0,0 +1,246 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment;
+
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+/**
+ * Represents an alignment of a read to a site in the reference genome.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class Alignment {
+ protected int contigIndex;
+ protected long alignmentStart;
+ protected boolean negativeStrand;
+ protected int mappingQuality;
+
+ protected char[] cigarOperators;
+ protected int[] cigarLengths;
+
+ protected int editDistance;
+ protected String mismatchingPositions;
+
+ protected int numMismatches;
+ protected int numGapOpens;
+ protected int numGapExtensions;
+ protected int bestCount;
+ protected int secondBestCount;
+
+ /**
+ * Gets the index of the given contig.
+ * @return the inde
+ */
+ public int getContigIndex() { return contigIndex; }
+
+ /**
+ * Gets the starting position for the given alignment.
+ * @return Starting position.
+ */
+ public long getAlignmentStart() { return alignmentStart; }
+
+ /**
+ * Is the given alignment on the reverse strand?
+ * @return True if the alignment is on the reverse strand.
+ */
+ public boolean isNegativeStrand() { return negativeStrand; }
+
+ /**
+ * Gets the score of this alignment.
+ * @return The score.
+ */
+ public int getMappingQuality() { return mappingQuality; }
+
+ /**
+ * Gets the edit distance; will eventually end up in the NM SAM tag
+ * if this alignment makes it that far.
+ * @return The edit distance.
+ */
+ public int getEditDistance() { return editDistance; }
+
+ /**
+ * A string representation of which positions mismatch; contents of MD tag.
+ * @return String representation of mismatching positions.
+ */
+ public String getMismatchingPositions() { return mismatchingPositions; }
+
+ /**
+ * Gets the number of mismatches in the read.
+ * @return Number of mismatches.
+ */
+ public int getNumMismatches() { return numMismatches; }
+
+ /**
+ * Get the number of gap opens.
+ * @return Number of gap opens.
+ */
+ public int getNumGapOpens() { return numGapOpens; }
+
+ /**
+ * Get the number of gap extensions.
+ * @return Number of gap extensions.
+ */
+ public int getNumGapExtensions() { return numGapExtensions; }
+
+ /**
+ * Get the number of best alignments.
+ * @return Number of top scoring alignments.
+ */
+ public int getBestCount() { return bestCount; }
+
+ /**
+ * Get the number of second best alignments.
+ * @return Number of second best scoring alignments.
+ */
+ public int getSecondBestCount() { return secondBestCount; }
+
+ /**
+ * Gets the cigar for this alignment.
+ * @return sam-jdk formatted alignment.
+ */
+ public Cigar getCigar() {
+ Cigar cigar = new Cigar();
+ for(int i = 0; i < cigarOperators.length; i++) {
+ CigarOperator operator = CigarOperator.characterToEnum(cigarOperators[i]);
+ cigar.add(new CigarElement(cigarLengths[i],operator));
+ }
+ return cigar;
+ }
+
+ /**
+ * Temporarily implement getCigarString() for debugging; the TextCigarCodec is unfortunately
+ * package-protected.
+ * @return
+ */
+ public String getCigarString() {
+ Cigar cigar = getCigar();
+ if(cigar.isEmpty()) return "*";
+
+ StringBuilder cigarString = new StringBuilder();
+ for(CigarElement element: cigar.getCigarElements()) {
+ cigarString.append(element.getLength());
+ cigarString.append(element.getOperator());
+ }
+ return cigarString.toString();
+ }
+
+ /**
+ * Stub for inheritance.
+ */
+ public Alignment() {}
+
+ /**
+ * Create a new alignment object.
+ * @param contigIndex The contig to which this read aligned.
+ * @param alignmentStart The point within the contig to which this read aligned.
+ * @param negativeStrand Forward or reverse alignment of the given read.
+ * @param mappingQuality How good does BWA think this mapping is?
+ * @param cigarOperators The ordered operators in the cigar string.
+ * @param cigarLengths The lengths to which each operator applies.
+ * @param editDistance The edit distance (cumulative) of the read.
+ * @param mismatchingPositions String representation of which bases in the read mismatch.
+ * @param numMismatches Number of total mismatches in the read.
+ * @param numGapOpens Number of gap opens in the read.
+ * @param numGapExtensions Number of gap extensions in the read.
+ * @param bestCount Number of best alignments in the read.
+ * @param secondBestCount Number of second best alignments in the read.
+ */
+ public Alignment(int contigIndex,
+ int alignmentStart,
+ boolean negativeStrand,
+ int mappingQuality,
+ char[] cigarOperators,
+ int[] cigarLengths,
+ int editDistance,
+ String mismatchingPositions,
+ int numMismatches,
+ int numGapOpens,
+ int numGapExtensions,
+ int bestCount,
+ int secondBestCount) {
+ this.contigIndex = contigIndex;
+ this.alignmentStart = alignmentStart;
+ this.negativeStrand = negativeStrand;
+ this.mappingQuality = mappingQuality;
+ this.cigarOperators = cigarOperators;
+ this.cigarLengths = cigarLengths;
+ this.editDistance = editDistance;
+ this.mismatchingPositions = mismatchingPositions;
+ this.numMismatches = numMismatches;
+ this.numGapOpens = numGapOpens;
+ this.numGapExtensions = numGapExtensions;
+ this.bestCount = bestCount;
+ this.secondBestCount = secondBestCount;
+ }
+
+ /**
+ * Creates a read directly from an alignment.
+ * @param alignment The alignment to convert to a read.
+ * @param unmappedRead Source of the unmapped read. Should have bases, quality scores, and flags.
+ * @param newSAMHeader The new SAM header to use in creating this read. Can be null, but if so, the sequence
+ * dictionary in the
+ * @return A mapped alignment.
+ */
+ public static SAMRecord convertToRead(Alignment alignment, SAMRecord unmappedRead, SAMFileHeader newSAMHeader) {
+ SAMRecord read;
+ try {
+ read = (SAMRecord)unmappedRead.clone();
+ }
+ catch(CloneNotSupportedException ex) {
+ throw new ReviewedGATKException("Unable to create aligned read from template.");
+ }
+
+ if(newSAMHeader != null)
+ read.setHeader(newSAMHeader);
+
+ // If we're realigning a previously aligned record, strip out the placement of the alignment.
+ read.setReferenceName(SAMRecord.NO_ALIGNMENT_REFERENCE_NAME);
+ read.setAlignmentStart(SAMRecord.NO_ALIGNMENT_START);
+ read.setMateReferenceName(SAMRecord.NO_ALIGNMENT_REFERENCE_NAME);
+ read.setMateAlignmentStart(SAMRecord.NO_ALIGNMENT_START);
+
+ if(alignment != null) {
+ read.setReadUnmappedFlag(false);
+ read.setReferenceIndex(alignment.getContigIndex());
+ read.setAlignmentStart((int)alignment.getAlignmentStart());
+ read.setReadNegativeStrandFlag(alignment.isNegativeStrand());
+ read.setMappingQuality(alignment.getMappingQuality());
+ read.setCigar(alignment.getCigar());
+ if(alignment.isNegativeStrand()) {
+ read.setReadBases(BaseUtils.simpleReverseComplement(read.getReadBases()));
+ read.setBaseQualities(Utils.reverse(read.getBaseQualities()));
+ }
+ read.setAttribute("NM",alignment.getEditDistance());
+ read.setAttribute("MD",alignment.getMismatchingPositions());
+ }
+
+ return read;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/BWAAligner.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/BWAAligner.java
new file mode 100644
index 0000000..2668b8c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/BWAAligner.java
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.bwa;
+
+import org.broadinstitute.gatk.engine.alignment.Aligner;
+
+/**
+ * Align reads using BWA.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public abstract class BWAAligner implements Aligner {
+ /**
+ * The supporting files used by BWA.
+ */
+ protected BWTFiles bwtFiles;
+
+ /**
+ * The current configuration for the BWA aligner.
+ */
+ protected BWAConfiguration configuration;
+
+ /**
+ * Create a new BWAAligner. Purpose of this call is to ensure that all BWA constructors accept the correct
+ * parameters.
+ * @param bwtFiles The many files representing BWTs persisted to disk.
+ * @param configuration Configuration parameters for the alignment.
+ */
+ public BWAAligner(BWTFiles bwtFiles, BWAConfiguration configuration) {
+ this.bwtFiles = bwtFiles;
+ this.configuration = configuration;
+ }
+
+ /**
+ * Update the configuration passed to the BWA aligner.
+ * @param configuration New configuration to set.
+ */
+ public abstract void updateConfiguration(BWAConfiguration configuration);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/BWAConfiguration.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/BWAConfiguration.java
new file mode 100644
index 0000000..b533a0d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/BWAConfiguration.java
@@ -0,0 +1,79 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.bwa;
+
+/**
+ * Configuration for the BWA/C aligner.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class BWAConfiguration {
+ /**
+ * The maximum edit distance used by BWA.
+ */
+ public Float maximumEditDistance = null;
+
+ /**
+ * How many gap opens are acceptable within this alignment?
+ */
+ public Integer maximumGapOpens = null;
+
+ /**
+ * How many gap extensions are acceptable within this alignment?
+ */
+ public Integer maximumGapExtensions = null;
+
+ /**
+ * Do we disallow indels within a certain range from the start / end?
+ */
+ public Integer disallowIndelWithinRange = null;
+
+ /**
+ * What is the scoring penalty for a mismatch?
+ */
+ public Integer mismatchPenalty = null;
+
+ /**
+ * What is the scoring penalty for a gap open?
+ */
+ public Integer gapOpenPenalty = null;
+
+ /**
+ * What is the scoring penalty for a gap extension?
+ */
+ public Integer gapExtensionPenalty = null;
+
+ /**
+ * Enter bwa's 'non-stop' mode (equivalent to bwa aln -N parameter).
+ */
+ public Boolean nonStopMode = false;
+
+ /**
+ * Set the max queue size that bwa will use when searching for matches (equivalent to bwa aln -m parameter).
+ */
+ public Integer maxEntriesInQueue = null;
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/BWTFiles.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/BWTFiles.java
new file mode 100644
index 0000000..16cc4ad
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/BWTFiles.java
@@ -0,0 +1,259 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.bwa;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import htsjdk.samtools.util.StringUtil;
+import org.broadinstitute.gatk.engine.alignment.reference.bwt.*;
+import org.broadinstitute.gatk.engine.alignment.reference.packing.PackUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Support files for BWT.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class BWTFiles {
+ /**
+ * ANN (?) file name.
+ */
+ public final File annFile;
+
+ /**
+ * AMB (?) file name.
+ */
+ public final File ambFile;
+
+ /**
+ * Packed reference sequence file.
+ */
+ public final File pacFile;
+
+ /**
+ * Reverse of packed reference sequence file.
+ */
+ public final File rpacFile;
+
+ /**
+ * Forward BWT file.
+ */
+ public final File forwardBWTFile;
+
+ /**
+ * Forward suffix array file.
+ */
+ public final File forwardSAFile;
+
+ /**
+ * Reverse BWT file.
+ */
+ public final File reverseBWTFile;
+
+ /**
+ * Reverse suffix array file.
+ */
+ public final File reverseSAFile;
+
+ /**
+ * Where these files autogenerated on the fly?
+ */
+ public final boolean autogenerated;
+
+ /**
+ * Create a new BWA configuration file using the given prefix.
+ * @param prefix Prefix to use when creating the configuration. Must not be null.
+ */
+ public BWTFiles(String prefix) {
+ if(prefix == null)
+ throw new ReviewedGATKException("Prefix must not be null.");
+ annFile = new File(prefix + ".ann");
+ ambFile = new File(prefix + ".amb");
+ pacFile = new File(prefix + ".pac");
+ rpacFile = new File(prefix + ".rpac");
+ forwardBWTFile = new File(prefix + ".bwt");
+ forwardSAFile = new File(prefix + ".sa");
+ reverseBWTFile = new File(prefix + ".rbwt");
+ reverseSAFile = new File(prefix + ".rsa");
+ autogenerated = false;
+ }
+
+ /**
+ * Hand-create a new BWTFiles object, specifying a unique file object for each type.
+ * @param annFile ANN (alternate dictionary) file.
+ * @param ambFile AMB (holes) files.
+ * @param pacFile Packed representation of the forward reference sequence.
+ * @param forwardBWTFile BWT representation of the forward reference sequence.
+ * @param forwardSAFile SA representation of the forward reference sequence.
+ * @param rpacFile Packed representation of the reversed reference sequence.
+ * @param reverseBWTFile BWT representation of the reversed reference sequence.
+ * @param reverseSAFile SA representation of the reversed reference sequence.
+ */
+ private BWTFiles(File annFile,
+ File ambFile,
+ File pacFile,
+ File forwardBWTFile,
+ File forwardSAFile,
+ File rpacFile,
+ File reverseBWTFile,
+ File reverseSAFile) {
+ this.annFile = annFile;
+ this.ambFile = ambFile;
+ this.pacFile = pacFile;
+ this.forwardBWTFile = forwardBWTFile;
+ this.forwardSAFile = forwardSAFile;
+ this.rpacFile = rpacFile;
+ this.reverseBWTFile = reverseBWTFile;
+ this.reverseSAFile = reverseSAFile;
+ autogenerated = true;
+ }
+
+ /**
+ * Close out this files object, in the process deleting any temporary filse
+ * that were created.
+ */
+ public void close() {
+ if(autogenerated) {
+ boolean success = true;
+ success = annFile.delete();
+ success &= ambFile.delete();
+ success &= pacFile.delete();
+ success &= forwardBWTFile.delete();
+ success &= forwardSAFile.delete();
+ success &= rpacFile.delete();
+ success &= reverseBWTFile.delete();
+ success &= reverseSAFile.delete();
+
+ if(!success)
+ throw new ReviewedGATKException("Unable to clean up autogenerated representation");
+ }
+ }
+
+ /**
+ * Create a new set of BWT files from the given reference sequence.
+ * @param referenceSequence Sequence from which to build metadata.
+ * @return A new object representing encoded representations of each sequence.
+ */
+ public static BWTFiles createFromReferenceSequence(byte[] referenceSequence) {
+ byte[] normalizedReferenceSequence = new byte[referenceSequence.length];
+ System.arraycopy(referenceSequence,0,normalizedReferenceSequence,0,referenceSequence.length);
+ normalizeReferenceSequence(normalizedReferenceSequence);
+
+ File annFile,ambFile,pacFile,bwtFile,saFile,rpacFile,rbwtFile,rsaFile;
+ try {
+ // Write the ann and amb for this reference sequence.
+ annFile = File.createTempFile("bwt",".ann");
+ ambFile = File.createTempFile("bwt",".amb");
+
+ SAMSequenceDictionary dictionary = new SAMSequenceDictionary();
+ dictionary.addSequence(new SAMSequenceRecord("autogenerated",normalizedReferenceSequence.length));
+
+ ANNWriter annWriter = new ANNWriter(annFile);
+ annWriter.write(dictionary);
+ annWriter.close();
+
+ AMBWriter ambWriter = new AMBWriter(ambFile);
+ ambWriter.writeEmpty(dictionary);
+ ambWriter.close();
+
+ // Write the encoded files for the forward version of this reference sequence.
+ pacFile = File.createTempFile("bwt",".pac");
+ bwtFile = File.createTempFile("bwt",".bwt");
+ saFile = File.createTempFile("bwt",".sa");
+
+ writeEncodedReferenceSequence(normalizedReferenceSequence,pacFile,bwtFile,saFile);
+
+ // Write the encoded files for the reverse version of this reference sequence.
+ byte[] reverseReferenceSequence = Utils.reverse(normalizedReferenceSequence);
+
+ rpacFile = File.createTempFile("bwt",".rpac");
+ rbwtFile = File.createTempFile("bwt",".rbwt");
+ rsaFile = File.createTempFile("bwt",".rsa");
+
+ writeEncodedReferenceSequence(reverseReferenceSequence,rpacFile,rbwtFile,rsaFile);
+ }
+ catch(IOException ex) {
+ throw new ReviewedGATKException("Unable to write autogenerated reference sequence to temporary files");
+ }
+
+ // Make sure that, at the very least, all temporary files are deleted on exit.
+ annFile.deleteOnExit();
+ ambFile.deleteOnExit();
+ pacFile.deleteOnExit();
+ bwtFile.deleteOnExit();
+ saFile.deleteOnExit();
+ rpacFile.deleteOnExit();
+ rbwtFile.deleteOnExit();
+ rsaFile.deleteOnExit();
+
+ return new BWTFiles(annFile,ambFile,pacFile,bwtFile,saFile,rpacFile,rbwtFile,rsaFile);
+ }
+
+ /**
+ * Write the encoded form of the reference sequence. In the case of BWA, the encoded reference
+ * sequence is the reference itself in PAC format, the BWT, and the suffix array.
+ * @param referenceSequence The reference sequence to encode.
+ * @param pacFile Target for the PAC-encoded reference.
+ * @param bwtFile Target for the BWT representation of the reference.
+ * @param suffixArrayFile Target for the suffix array encoding of the reference.
+ * @throws java.io.IOException In case of issues writing to the file.
+ */
+ private static void writeEncodedReferenceSequence(byte[] referenceSequence,
+ File pacFile,
+ File bwtFile,
+ File suffixArrayFile) throws IOException {
+ PackUtils.writeReferenceSequence(pacFile,referenceSequence);
+
+ BWT bwt = BWT.createFromReferenceSequence(referenceSequence);
+ BWTWriter bwtWriter = new BWTWriter(bwtFile);
+ bwtWriter.write(bwt);
+ bwtWriter.close();
+
+ SuffixArray suffixArray = SuffixArray.createFromReferenceSequence(referenceSequence);
+ SuffixArrayWriter suffixArrayWriter = new SuffixArrayWriter(suffixArrayFile);
+ suffixArrayWriter.write(suffixArray);
+ suffixArrayWriter.close();
+ }
+
+ /**
+ * Convert the given reference sequence into a form suitable for building into
+ * on-the-fly sequences.
+ * @param referenceSequence The reference sequence to normalize.
+ * @throws org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException if normalized sequence cannot be generated.
+ */
+ private static void normalizeReferenceSequence(byte[] referenceSequence) {
+ StringUtil.toUpperCase(referenceSequence);
+ for(byte base: referenceSequence) {
+ if(base != 'A' && base != 'C' && base != 'G' && base != 'T')
+ throw new ReviewedGATKException(String.format("Base type %c is not supported when building references on-the-fly",(char)base));
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/AlignerTestHarness.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/AlignerTestHarness.java
new file mode 100644
index 0000000..91e41e5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/AlignerTestHarness.java
@@ -0,0 +1,189 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.bwa.java;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.engine.alignment.Aligner;
+import org.broadinstitute.gatk.engine.alignment.Alignment;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * A test harness to ensure that the perfect aligner works.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class AlignerTestHarness {
+ public static void main( String argv[] ) throws FileNotFoundException {
+ if( argv.length != 6 ) {
+ System.out.println("PerfectAlignerTestHarness <fasta> <bwt> <rbwt> <sa> <rsa> <bam>");
+ System.exit(1);
+ }
+
+ File referenceFile = new File(argv[0]);
+ File bwtFile = new File(argv[1]);
+ File rbwtFile = new File(argv[2]);
+ File suffixArrayFile = new File(argv[3]);
+ File reverseSuffixArrayFile = new File(argv[4]);
+ File bamFile = new File(argv[5]);
+
+ align(referenceFile,bwtFile,rbwtFile,suffixArrayFile,reverseSuffixArrayFile,bamFile);
+ }
+
+ private static void align(File referenceFile, File bwtFile, File rbwtFile, File suffixArrayFile, File reverseSuffixArrayFile, File bamFile) throws FileNotFoundException {
+ Aligner aligner = new BWAJavaAligner(bwtFile,rbwtFile,suffixArrayFile,reverseSuffixArrayFile);
+ int count = 0;
+
+ SAMFileReader reader = new SAMFileReader(bamFile);
+ reader.setValidationStringency(ValidationStringency.SILENT);
+
+ int mismatches = 0;
+ int failures = 0;
+
+ for(SAMRecord read: reader) {
+ count++;
+ if( count > 200000 ) break;
+ //if( count < 366000 ) continue;
+ //if( count > 2 ) break;
+ //if( !read.getReadName().endsWith("SL-XBC:1:82:506:404#0") )
+ // continue;
+ //if( !read.getReadName().endsWith("SL-XBC:1:36:30:1926#0") )
+ // continue;
+ //if( !read.getReadName().endsWith("SL-XBC:1:60:1342:1340#0") )
+ // continue;
+
+ SAMRecord alignmentCleaned = null;
+ try {
+ alignmentCleaned = (SAMRecord)read.clone();
+ }
+ catch( CloneNotSupportedException ex ) {
+ throw new ReviewedGATKException("SAMRecord clone not supported", ex);
+ }
+
+ if( alignmentCleaned.getReadNegativeStrandFlag() )
+ alignmentCleaned.setReadBases(BaseUtils.simpleReverseComplement(alignmentCleaned.getReadBases()));
+
+ alignmentCleaned.setReferenceIndex(SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX);
+ alignmentCleaned.setAlignmentStart(SAMRecord.NO_ALIGNMENT_START);
+ alignmentCleaned.setMappingQuality(SAMRecord.NO_MAPPING_QUALITY);
+ alignmentCleaned.setCigarString(SAMRecord.NO_ALIGNMENT_CIGAR);
+
+ // Clear everything except flags pertaining to pairing and set 'unmapped' status to true.
+ alignmentCleaned.setFlags(alignmentCleaned.getFlags() & 0x00A1 | 0x000C);
+
+ Iterable<Alignment[]> alignments = aligner.getAllAlignments(alignmentCleaned.getReadBases());
+ if(!alignments.iterator().hasNext() ) {
+ //throw new GATKException(String.format("Unable to align read %s to reference; count = %d",read.getReadName(),count));
+ System.out.printf("Unable to align read %s to reference; count = %d%n",read.getReadName(),count);
+ failures++;
+ }
+
+ Alignment foundAlignment = null;
+ for(Alignment[] alignmentsOfQuality: alignments) {
+ for(Alignment alignment: alignmentsOfQuality) {
+ if( read.getReadNegativeStrandFlag() != alignment.isNegativeStrand() )
+ continue;
+ if( read.getAlignmentStart() != alignment.getAlignmentStart() )
+ continue;
+
+ foundAlignment = alignment;
+ }
+ }
+
+ if( foundAlignment != null ) {
+ //System.out.printf("%s: Aligned read to reference at position %d with %d mismatches, %d gap opens, and %d gap extensions.%n", read.getReadName(), foundAlignment.getAlignmentStart(), foundAlignment.getMismatches(), foundAlignment.getGapOpens(), foundAlignment.getGapExtensions());
+ }
+ else {
+ System.out.printf("Error aligning read %s%n", read.getReadName());
+
+ mismatches++;
+
+ IndexedFastaSequenceFile reference = new IndexedFastaSequenceFile(referenceFile);
+
+ System.out.printf("read = %s, position = %d, negative strand = %b%n", formatBasesBasedOnCigar(read.getReadString(),read.getCigar(),CigarOperator.DELETION),
+ read.getAlignmentStart(),
+ read.getReadNegativeStrandFlag());
+ int numDeletions = numDeletionsInCigar(read.getCigar());
+ String expectedRef = new String(reference.getSubsequenceAt(reference.getSequenceDictionary().getSequences().get(0).getSequenceName(),read.getAlignmentStart(),read.getAlignmentStart()+read.getReadLength()+numDeletions-1).getBases());
+ System.out.printf("expected ref = %s%n", formatBasesBasedOnCigar(expectedRef,read.getCigar(),CigarOperator.INSERTION));
+
+ for(Alignment[] alignmentsOfQuality: alignments) {
+ for(Alignment alignment: alignmentsOfQuality) {
+ System.out.println();
+
+ Cigar cigar = ((BWAAlignment)alignment).getCigar();
+
+ System.out.printf("read = %s%n", formatBasesBasedOnCigar(read.getReadString(),cigar,CigarOperator.DELETION));
+
+ int deletionCount = ((BWAAlignment)alignment).getNumberOfBasesMatchingState(AlignmentState.DELETION);
+ String alignedRef = new String(reference.getSubsequenceAt(reference.getSequenceDictionary().getSequences().get(0).getSequenceName(),alignment.getAlignmentStart(),alignment.getAlignmentStart()+read.getReadLength()+deletionCount-1).getBases());
+ System.out.printf("actual ref = %s, position = %d, negative strand = %b%n", formatBasesBasedOnCigar(alignedRef,cigar,CigarOperator.INSERTION),
+ alignment.getAlignmentStart(),
+ alignment.isNegativeStrand());
+ }
+ }
+
+ //throw new GATKException(String.format("Read %s was placed at incorrect location; count = %d%n",read.getReadName(),count));
+ }
+
+
+ if( count % 1000 == 0 )
+ System.out.printf("%d reads examined.%n",count);
+ }
+
+ System.out.printf("%d reads examined; %d mismatches; %d failures.%n",count,mismatches,failures);
+ }
+
+ private static String formatBasesBasedOnCigar( String bases, Cigar cigar, CigarOperator toBlank ) {
+ StringBuilder formatted = new StringBuilder();
+ int readIndex = 0;
+ for(CigarElement cigarElement: cigar.getCigarElements()) {
+ if(cigarElement.getOperator() == toBlank) {
+ int number = cigarElement.getLength();
+ while( number-- > 0 ) formatted.append(' ');
+ }
+ else {
+ int number = cigarElement.getLength();
+ while( number-- > 0 ) formatted.append(bases.charAt(readIndex++));
+ }
+ }
+ return formatted.toString();
+ }
+
+ private static int numDeletionsInCigar( Cigar cigar ) {
+ int numDeletions = 0;
+ for(CigarElement cigarElement: cigar.getCigarElements()) {
+ if(cigarElement.getOperator() == CigarOperator.DELETION)
+ numDeletions += cigarElement.getLength();
+ }
+ return numDeletions;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/AlignmentMatchSequence.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/AlignmentMatchSequence.java
new file mode 100644
index 0000000..f1148c6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/AlignmentMatchSequence.java
@@ -0,0 +1,175 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.bwa.java;
+
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+
+/**
+ * Represents a sequence of matches.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class AlignmentMatchSequence implements Cloneable {
+ /**
+ * Stores the particular match entries in the order they occur.
+ */
+ private Deque<AlignmentMatchSequenceEntry> entries = new ArrayDeque<AlignmentMatchSequenceEntry>();
+
+ /**
+ * Clone the given match sequence.
+ * @return A deep copy of the current match sequence.
+ */
+ public AlignmentMatchSequence clone() {
+ AlignmentMatchSequence copy = null;
+ try {
+ copy = (AlignmentMatchSequence)super.clone();
+ }
+ catch( CloneNotSupportedException ex ) {
+ throw new ReviewedGATKException("Unable to clone AlignmentMatchSequence.");
+ }
+
+ copy.entries = new ArrayDeque<AlignmentMatchSequenceEntry>();
+ for( AlignmentMatchSequenceEntry entry: entries )
+ copy.entries.add(entry.clone());
+
+ return copy;
+ }
+
+ public Cigar convertToCigar(boolean negativeStrand) {
+ Cigar cigar = new Cigar();
+ Iterator<AlignmentMatchSequenceEntry> iterator = negativeStrand ? entries.descendingIterator() : entries.iterator();
+ while( iterator.hasNext() ) {
+ AlignmentMatchSequenceEntry entry = iterator.next();
+ CigarOperator operator;
+ switch( entry.getAlignmentState() ) {
+ case MATCH_MISMATCH: operator = CigarOperator.MATCH_OR_MISMATCH; break;
+ case INSERTION: operator = CigarOperator.INSERTION; break;
+ case DELETION: operator = CigarOperator.DELETION; break;
+ default: throw new ReviewedGATKException("convertToCigar: cannot process state: " + entry.getAlignmentState());
+ }
+ cigar.add( new CigarElement(entry.count,operator) );
+ }
+ return cigar;
+ }
+
+ /**
+ * All a new alignment of the given state.
+ * @param state State to add to the sequence.
+ */
+ public void addNext( AlignmentState state ) {
+ AlignmentMatchSequenceEntry last = entries.peekLast();
+ // If the last entry is the same as this one, increment it. Otherwise, add a new entry.
+ if( last != null && last.alignmentState == state )
+ last.increment();
+ else
+ entries.add(new AlignmentMatchSequenceEntry(state));
+ }
+
+ /**
+ * Gets the current state of this alignment (what's the state of the last base?)
+ * @return State of the most recently aligned base.
+ */
+ public AlignmentState getCurrentState() {
+ if( entries.size() == 0 )
+ return AlignmentState.MATCH_MISMATCH;
+ return entries.peekLast().getAlignmentState();
+ }
+
+ /**
+ * How many bases in the read match the given state.
+ * @param state State to test.
+ * @return number of bases which match that state.
+ */
+ public int getNumberOfBasesMatchingState(AlignmentState state) {
+ int matches = 0;
+ for( AlignmentMatchSequenceEntry entry: entries ) {
+ if( entry.getAlignmentState() == state )
+ matches += entry.count;
+ }
+ return matches;
+ }
+
+ /**
+ * Stores an individual match sequence entry.
+ */
+ private class AlignmentMatchSequenceEntry implements Cloneable {
+ /**
+ * The state of the alignment throughout a given point in the sequence.
+ */
+ private final AlignmentState alignmentState;
+
+ /**
+ * The number of bases having this particular state.
+ */
+ private int count;
+
+ /**
+ * Create a new sequence entry with the given state.
+ * @param alignmentState The state that this sequence should contain.
+ */
+ AlignmentMatchSequenceEntry( AlignmentState alignmentState ) {
+ this.alignmentState = alignmentState;
+ this.count = 1;
+ }
+
+ /**
+ * Clone the given match sequence entry.
+ * @return A deep copy of the current match sequence entry.
+ */
+ public AlignmentMatchSequenceEntry clone() {
+ try {
+ return (AlignmentMatchSequenceEntry)super.clone();
+ }
+ catch( CloneNotSupportedException ex ) {
+ throw new ReviewedGATKException("Unable to clone AlignmentMatchSequenceEntry.");
+ }
+ }
+
+ /**
+ * Retrieves the current state of the alignment.
+ * @return The state of the current sequence.
+ */
+ AlignmentState getAlignmentState() {
+ return alignmentState;
+ }
+
+ /**
+ * Increment the count of alignments having this particular state.
+ */
+ void increment() {
+ count++;
+ }
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/AlignmentState.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/AlignmentState.java
new file mode 100644
index 0000000..f4ba1bb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/AlignmentState.java
@@ -0,0 +1,38 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.bwa.java;
+
+/**
+ * The state of a given base in the alignment.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public enum AlignmentState {
+ MATCH_MISMATCH,
+ INSERTION,
+ DELETION
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/BWAAlignment.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/BWAAlignment.java
new file mode 100644
index 0000000..88ef4a5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/BWAAlignment.java
@@ -0,0 +1,215 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.bwa.java;
+
+import htsjdk.samtools.Cigar;
+import org.broadinstitute.gatk.engine.alignment.Alignment;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+/**
+ * An alignment object to be used incrementally as the BWA aligner
+ * inspects the read.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class BWAAlignment extends Alignment implements Cloneable {
+ /**
+ * Track the number of alignments that have been created.
+ */
+ private static long numCreated;
+
+ /**
+ * Which number alignment is this?
+ */
+ private long creationNumber;
+
+ /**
+ * The aligner performing the alignments.
+ */
+ protected BWAJavaAligner aligner;
+
+ /**
+ * The sequence of matches/mismatches/insertions/deletions.
+ */
+ private AlignmentMatchSequence alignmentMatchSequence = new AlignmentMatchSequence();
+
+ /**
+ * Working variable. How many bases have been matched at this point.
+ */
+ protected int position;
+
+ /**
+ * Working variable. How many mismatches have been encountered at this point.
+ */
+ private int mismatches;
+
+ /**
+ * Number of gap opens in alignment.
+ */
+ private int gapOpens;
+
+ /**
+ * Number of gap extensions in alignment.
+ */
+ private int gapExtensions;
+
+ /**
+ * Working variable. The lower bound of the alignment within the BWT.
+ */
+ protected long loBound;
+
+ /**
+ * Working variable. The upper bound of the alignment within the BWT.
+ */
+ protected long hiBound;
+
+ protected void setAlignmentStart(long position) {
+ this.alignmentStart = position;
+ }
+
+ protected void setNegativeStrand(boolean negativeStrand) {
+ this.negativeStrand = negativeStrand;
+ }
+
+ /**
+ * Cache the score.
+ */
+ private int score;
+
+ public Cigar getCigar() {
+ return alignmentMatchSequence.convertToCigar(isNegativeStrand());
+ }
+
+ /**
+ * Gets the current state of this alignment (state of the last base viewed)..
+ * @return Current state of the alignment.
+ */
+ public AlignmentState getCurrentState() {
+ return alignmentMatchSequence.getCurrentState();
+ }
+
+ /**
+ * Adds the given state to the current alignment.
+ * @param state State to add to the given alignment.
+ */
+ public void addState( AlignmentState state ) {
+ alignmentMatchSequence.addNext(state);
+ }
+
+ /**
+ * Gets the BWA score of this alignment.
+ * @return BWA-style scores. 0 is best.
+ */
+ public int getScore() {
+ return score;
+ }
+
+ public int getMismatches() { return mismatches; }
+ public int getGapOpens() { return gapOpens; }
+ public int getGapExtensions() { return gapExtensions; }
+
+ public void incrementMismatches() {
+ this.mismatches++;
+ updateScore();
+ }
+
+ public void incrementGapOpens() {
+ this.gapOpens++;
+ updateScore();
+ }
+
+ public void incrementGapExtensions() {
+ this.gapExtensions++;
+ updateScore();
+ }
+
+ /**
+ * Updates the score based on new information about matches / mismatches.
+ */
+ private void updateScore() {
+ score = mismatches*aligner.MISMATCH_PENALTY + gapOpens*aligner.GAP_OPEN_PENALTY + gapExtensions*aligner.GAP_EXTENSION_PENALTY;
+ }
+
+ /**
+ * Create a new alignment with the given parent aligner.
+ * @param aligner Aligner being used.
+ */
+ public BWAAlignment( BWAJavaAligner aligner ) {
+ this.aligner = aligner;
+ this.creationNumber = numCreated++;
+ }
+
+ /**
+ * Clone the alignment.
+ * @return New instance of the alignment.
+ */
+ public BWAAlignment clone() {
+ BWAAlignment newAlignment = null;
+ try {
+ newAlignment = (BWAAlignment)super.clone();
+ }
+ catch( CloneNotSupportedException ex ) {
+ throw new ReviewedGATKException("Unable to clone BWAAlignment.");
+ }
+ newAlignment.creationNumber = numCreated++;
+ newAlignment.alignmentMatchSequence = alignmentMatchSequence.clone();
+
+ return newAlignment;
+ }
+
+ /**
+ * How many bases in the read match the given state.
+ * @param state State to test.
+ * @return number of bases which match that state.
+ */
+ public int getNumberOfBasesMatchingState(AlignmentState state) {
+ return alignmentMatchSequence.getNumberOfBasesMatchingState(state);
+ }
+
+ /**
+ * Compare this alignment to another alignment.
+ * @param rhs Other alignment to which to compare.
+ * @return < 0 if this < other, == 0 if this == other, > 0 if this > other
+ */
+ public int compareTo(Alignment rhs) {
+ BWAAlignment other = (BWAAlignment)rhs;
+
+ // If the scores are different, disambiguate using the score.
+ if(score != other.score)
+ return score > other.score ? 1 : -1;
+
+ // Otherwise, use the order in which the elements were created.
+ if(creationNumber != other.creationNumber)
+ return creationNumber > other.creationNumber ? -1 : 1;
+
+ return 0;
+ }
+
+ public String toString() {
+ return String.format("position: %d, strand: %b, state: %s, mismatches: %d, gap opens: %d, gap extensions: %d, loBound: %d, hiBound: %d, score: %d, creationNumber: %d", position, negativeStrand, alignmentMatchSequence.getCurrentState(), mismatches, gapOpens, gapExtensions, loBound, hiBound, getScore(), creationNumber);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/BWAJavaAligner.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/BWAJavaAligner.java
new file mode 100644
index 0000000..09a5b45
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/BWAJavaAligner.java
@@ -0,0 +1,418 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.bwa.java;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.alignment.Alignment;
+import org.broadinstitute.gatk.engine.alignment.bwa.BWAAligner;
+import org.broadinstitute.gatk.engine.alignment.bwa.BWAConfiguration;
+import org.broadinstitute.gatk.engine.alignment.reference.bwt.*;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.Utils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.PriorityQueue;
+
+/**
+ * Create imperfect alignments from the read to the genome represented by the given BWT / suffix array.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class BWAJavaAligner extends BWAAligner {
+ /**
+ * BWT in the forward direction.
+ */
+ private BWT forwardBWT;
+
+ /**
+ * BWT in the reverse direction.
+ */
+ private BWT reverseBWT;
+
+ /**
+ * Suffix array in the forward direction.
+ */
+ private SuffixArray forwardSuffixArray;
+
+ /**
+ * Suffix array in the reverse direction.
+ */
+ private SuffixArray reverseSuffixArray;
+
+ /**
+ * Maximum edit distance (-n option from original BWA).
+ */
+ private final int MAXIMUM_EDIT_DISTANCE = 4;
+
+ /**
+ * Maximum number of gap opens (-o option from original BWA).
+ */
+ private final int MAXIMUM_GAP_OPENS = 1;
+
+ /**
+ * Maximum number of gap extensions (-e option from original BWA).
+ */
+ private final int MAXIMUM_GAP_EXTENSIONS = 6;
+
+ /**
+ * Penalty for straight mismatches (-M option from original BWA).
+ */
+ public final int MISMATCH_PENALTY = 3;
+
+ /**
+ * Penalty for gap opens (-O option from original BWA).
+ */
+ public final int GAP_OPEN_PENALTY = 11;
+
+ /**
+ * Penalty for gap extensions (-E option from original BWA).
+ */
+ public final int GAP_EXTENSION_PENALTY = 4;
+
+ /**
+ * Skip the ends of indels.
+ */
+ public final int INDEL_END_SKIP = 5;
+
+ public BWAJavaAligner( File forwardBWTFile, File reverseBWTFile, File forwardSuffixArrayFile, File reverseSuffixArrayFile ) {
+ super(null,null);
+ forwardBWT = new BWTReader(forwardBWTFile).read();
+ reverseBWT = new BWTReader(reverseBWTFile).read();
+ forwardSuffixArray = new SuffixArrayReader(forwardSuffixArrayFile,forwardBWT).read();
+ reverseSuffixArray = new SuffixArrayReader(reverseSuffixArrayFile,reverseBWT).read();
+ }
+
+ /**
+ * Close this instance of the BWA pointer and delete its resources.
+ */
+ @Override
+ public void close() {
+ throw new UnsupportedOperationException("BWA aligner can't currently be closed.");
+ }
+
+ /**
+ * Update the current parameters of this aligner.
+ * @param configuration New configuration to set.
+ */
+ public void updateConfiguration(BWAConfiguration configuration) {
+ throw new UnsupportedOperationException("Configuration of the BWA aligner can't currently be changed.");
+ }
+
+ /**
+ * Allow the aligner to choose one alignment randomly from the pile of best alignments.
+ * @param bases Bases to align.
+ * @return An align
+ */
+ public Alignment getBestAlignment(final byte[] bases) { throw new UnsupportedOperationException("BWAJavaAligner does not yet support the standard Aligner interface."); }
+
+ /**
+ * Align the read to the reference.
+ * @param read Read to align.
+ * @param header Optional header to drop in place.
+ * @return A list of the alignments.
+ */
+ public SAMRecord align(final SAMRecord read, final SAMFileHeader header) { throw new UnsupportedOperationException("BWAJavaAligner does not yet support the standard Aligner interface."); }
+
+ /**
+ * Get a iterator of alignments, batched by mapping quality.
+ * @param bases List of bases.
+ * @return Iterator to alignments.
+ */
+ public Iterable<Alignment[]> getAllAlignments(final byte[] bases) { throw new UnsupportedOperationException("BWAJavaAligner does not yet support the standard Aligner interface."); }
+
+ /**
+ * Get a iterator of aligned reads, batched by mapping quality.
+ * @param read Read to align.
+ * @param newHeader Optional new header to use when aligning the read. If present, it must be null.
+ * @return Iterator to alignments.
+ */
+ public Iterable<SAMRecord[]> alignAll(final SAMRecord read, final SAMFileHeader newHeader) { throw new UnsupportedOperationException("BWAJavaAligner does not yet support the standard Aligner interface."); }
+
+
+ public List<Alignment> align( SAMRecord read ) {
+ List<Alignment> successfulMatches = new ArrayList<Alignment>();
+
+ Byte[] uncomplementedBases = normalizeBases(read.getReadBases());
+ Byte[] complementedBases = normalizeBases(Utils.reverse(BaseUtils.simpleReverseComplement(read.getReadBases())));
+
+ List<LowerBound> forwardLowerBounds = LowerBound.create(uncomplementedBases,forwardBWT);
+ List<LowerBound> reverseLowerBounds = LowerBound.create(complementedBases,reverseBWT);
+
+ // Seed the best score with any score that won't overflow on comparison.
+ int bestScore = Integer.MAX_VALUE - MISMATCH_PENALTY;
+ int bestDiff = MAXIMUM_EDIT_DISTANCE+1;
+ int maxDiff = MAXIMUM_EDIT_DISTANCE;
+
+ PriorityQueue<BWAAlignment> alignments = new PriorityQueue<BWAAlignment>();
+
+ // Create a fictional initial alignment, with the position just off the end of the read, and the limits
+ // set as the entire BWT.
+ alignments.add(createSeedAlignment(reverseBWT));
+ alignments.add(createSeedAlignment(forwardBWT));
+
+ while(!alignments.isEmpty()) {
+ BWAAlignment alignment = alignments.remove();
+
+ // From bwtgap.c in the original BWT; if the rank is worse than the best score + the mismatch PENALTY, move on.
+ if( alignment.getScore() > bestScore + MISMATCH_PENALTY )
+ break;
+
+ Byte[] bases = alignment.isNegativeStrand() ? complementedBases : uncomplementedBases;
+ BWT bwt = alignment.isNegativeStrand() ? forwardBWT : reverseBWT;
+ List<LowerBound> lowerBounds = alignment.isNegativeStrand() ? reverseLowerBounds : forwardLowerBounds;
+
+ // if z < D(i) then return {}
+ int mismatches = maxDiff - alignment.getMismatches() - alignment.getGapOpens() - alignment.getGapExtensions();
+ if( alignment.position < lowerBounds.size()-1 && mismatches < lowerBounds.get(alignment.position+1).value )
+ continue;
+
+ if(mismatches == 0) {
+ exactMatch(alignment,bases,bwt);
+ if(alignment.loBound > alignment.hiBound)
+ continue;
+ }
+
+ // Found a valid alignment; store it and move on.
+ if(alignment.position >= read.getReadLength()-1) {
+ for(long bwtIndex = alignment.loBound; bwtIndex <= alignment.hiBound; bwtIndex++) {
+ BWAAlignment finalAlignment = alignment.clone();
+
+ if( finalAlignment.isNegativeStrand() )
+ finalAlignment.setAlignmentStart(forwardSuffixArray.get(bwtIndex) + 1);
+ else {
+ int sizeAlongReference = read.getReadLength() -
+ finalAlignment.getNumberOfBasesMatchingState(AlignmentState.INSERTION) +
+ finalAlignment.getNumberOfBasesMatchingState(AlignmentState.DELETION);
+ finalAlignment.setAlignmentStart(reverseBWT.length() - reverseSuffixArray.get(bwtIndex) - sizeAlongReference + 1);
+ }
+
+ successfulMatches.add(finalAlignment);
+
+ bestScore = Math.min(finalAlignment.getScore(),bestScore);
+ bestDiff = Math.min(finalAlignment.getMismatches()+finalAlignment.getGapOpens()+finalAlignment.getGapExtensions(),bestDiff);
+ maxDiff = bestDiff + 1;
+ }
+
+ continue;
+ }
+
+ //System.out.printf("Processing alignments; queue size = %d, alignment = %s, bound = %d, base = %s%n", alignments.size(), alignment, lowerBounds.get(alignment.position+1).value, alignment.position >= 0 ? (char)bases[alignment.position].byteValue() : "");
+ /*
+ System.out.printf("#1\t[%d,%d,%d,%c]\t[%d,%d,%d]\t[%d,%d]\t[%d,%d]%n",alignments.size(),
+ alignment.negativeStrand?1:0,
+ bases.length-alignment.position-1,
+ alignment.getCurrentState().toString().charAt(0),
+ alignment.getMismatches(),
+ alignment.getGapOpens(),
+ alignment.getGapExtensions(),
+ lowerBounds.get(alignment.position+1).value,
+ lowerBounds.get(alignment.position+1).width,
+ alignment.loBound,
+ alignment.hiBound);
+ */
+
+ // Temporary -- look ahead to see if the next alignment is bounded.
+ boolean allowDifferences = mismatches > 0;
+ boolean allowMismatches = mismatches > 0;
+
+ if( allowDifferences &&
+ alignment.position+1 >= INDEL_END_SKIP-1+alignment.getGapOpens()+alignment.getGapExtensions() &&
+ read.getReadLength()-1-(alignment.position+1) >= INDEL_END_SKIP+alignment.getGapOpens()+alignment.getGapExtensions() ) {
+ if( alignment.getCurrentState() == AlignmentState.MATCH_MISMATCH ) {
+ if( alignment.getGapOpens() < MAXIMUM_GAP_OPENS ) {
+ // Add a potential insertion extension.
+ BWAAlignment insertionAlignment = createInsertionAlignment(alignment);
+ insertionAlignment.incrementGapOpens();
+ alignments.add(insertionAlignment);
+
+ // Add a potential deletion by marking a deletion and augmenting the position.
+ List<BWAAlignment> deletionAlignments = createDeletionAlignments(bwt,alignment);
+ for( BWAAlignment deletionAlignment: deletionAlignments )
+ deletionAlignment.incrementGapOpens();
+ alignments.addAll(deletionAlignments);
+ }
+ }
+ else if( alignment.getCurrentState() == AlignmentState.INSERTION ) {
+ if( alignment.getGapExtensions() < MAXIMUM_GAP_EXTENSIONS && mismatches > 0 ) {
+ // Add a potential insertion extension.
+ BWAAlignment insertionAlignment = createInsertionAlignment(alignment);
+ insertionAlignment.incrementGapExtensions();
+ alignments.add(insertionAlignment);
+ }
+ }
+ else if( alignment.getCurrentState() == AlignmentState.DELETION ) {
+ if( alignment.getGapExtensions() < MAXIMUM_GAP_EXTENSIONS && mismatches > 0 ) {
+ // Add a potential deletion by marking a deletion and augmenting the position.
+ List<BWAAlignment> deletionAlignments = createDeletionAlignments(bwt,alignment);
+ for( BWAAlignment deletionAlignment: deletionAlignments )
+ deletionAlignment.incrementGapExtensions();
+ alignments.addAll(deletionAlignments);
+ }
+ }
+ }
+
+ // Mismatches
+ alignments.addAll(createMatchedAlignments(bwt,alignment,bases,allowDifferences&&allowMismatches));
+ }
+
+ return successfulMatches;
+ }
+
+ /**
+ * Create an seeding alignment to use as a starting point when traversing.
+ * @param bwt source BWT.
+ * @return Seed alignment.
+ */
+ private BWAAlignment createSeedAlignment(BWT bwt) {
+ BWAAlignment seed = new BWAAlignment(this);
+ seed.setNegativeStrand(bwt == forwardBWT);
+ seed.position = -1;
+ seed.loBound = 0;
+ seed.hiBound = bwt.length();
+ return seed;
+ }
+
+ /**
+ * Creates a new alignments representing direct matches / mismatches.
+ * @param bwt Source BWT with which to work.
+ * @param alignment Alignment for the previous position.
+ * @param bases The bases in the read.
+ * @param allowMismatch Should mismatching bases be allowed?
+ * @return New alignment representing this position if valid; null otherwise.
+ */
+ private List<BWAAlignment> createMatchedAlignments( BWT bwt, BWAAlignment alignment, Byte[] bases, boolean allowMismatch ) {
+ List<BWAAlignment> newAlignments = new ArrayList<BWAAlignment>();
+
+ List<Byte> baseChoices = new ArrayList<Byte>();
+ Byte thisBase = bases[alignment.position+1];
+
+ if( allowMismatch )
+ baseChoices.addAll(Bases.allOf());
+ else
+ baseChoices.add(thisBase);
+
+ if( thisBase != null ) {
+ // Keep rotating the current base to the last position until we've hit the current base.
+ for( ;; ) {
+ baseChoices.add(baseChoices.remove(0));
+ if( thisBase.equals(baseChoices.get(baseChoices.size()-1)) )
+ break;
+
+ }
+ }
+
+ for(byte base: baseChoices) {
+ BWAAlignment newAlignment = alignment.clone();
+
+ newAlignment.loBound = bwt.counts(base) + bwt.occurrences(base,alignment.loBound-1) + 1;
+ newAlignment.hiBound = bwt.counts(base) + bwt.occurrences(base,alignment.hiBound);
+
+ // If this alignment is valid, skip it.
+ if( newAlignment.loBound > newAlignment.hiBound )
+ continue;
+
+ newAlignment.position++;
+ newAlignment.addState(AlignmentState.MATCH_MISMATCH);
+ if( bases[newAlignment.position] == null || base != bases[newAlignment.position] )
+ newAlignment.incrementMismatches();
+
+ newAlignments.add(newAlignment);
+ }
+
+ return newAlignments;
+ }
+
+ /**
+ * Create a new alignment representing an insertion at this point in the read.
+ * @param alignment Alignment from which to derive the insertion.
+ * @return New alignment reflecting the insertion.
+ */
+ private BWAAlignment createInsertionAlignment( BWAAlignment alignment ) {
+ // Add a potential insertion extension.
+ BWAAlignment newAlignment = alignment.clone();
+ newAlignment.position++;
+ newAlignment.addState(AlignmentState.INSERTION);
+ return newAlignment;
+ }
+
+ /**
+ * Create new alignments representing a deletion at this point in the read.
+ * @param bwt source BWT for inferring deletion info.
+ * @param alignment Alignment from which to derive the deletion.
+ * @return New alignments reflecting all possible deletions.
+ */
+ private List<BWAAlignment> createDeletionAlignments( BWT bwt, BWAAlignment alignment) {
+ List<BWAAlignment> newAlignments = new ArrayList<BWAAlignment>();
+ for(byte base: Bases.instance) {
+ BWAAlignment newAlignment = alignment.clone();
+
+ newAlignment.loBound = bwt.counts(base) + bwt.occurrences(base,alignment.loBound-1) + 1;
+ newAlignment.hiBound = bwt.counts(base) + bwt.occurrences(base,alignment.hiBound);
+
+ // If this alignment is valid, skip it.
+ if( newAlignment.loBound > newAlignment.hiBound )
+ continue;
+
+ newAlignment.addState(AlignmentState.DELETION);
+
+ newAlignments.add(newAlignment);
+ }
+
+ return newAlignments;
+ }
+
+ /**
+ * Exactly match the given alignment against the given BWT.
+ * @param alignment Alignment to match.
+ * @param bases Bases to use.
+ * @param bwt BWT to use.
+ */
+ private void exactMatch( BWAAlignment alignment, Byte[] bases, BWT bwt ) {
+ while( ++alignment.position < bases.length ) {
+ byte base = bases[alignment.position];
+ alignment.loBound = bwt.counts(base) + bwt.occurrences(base,alignment.loBound-1) + 1;
+ alignment.hiBound = bwt.counts(base) + bwt.occurrences(base,alignment.hiBound);
+ if( alignment.loBound > alignment.hiBound )
+ return;
+ }
+ }
+
+ /**
+ * Make each base into A/C/G/T or null if unknown.
+ * @param bases Base string to normalize.
+ * @return Array of normalized bases.
+ */
+ private Byte[] normalizeBases( byte[] bases ) {
+ Byte[] normalBases = new Byte[bases.length];
+ for(int i = 0; i < bases.length; i++)
+ normalBases[i] = Bases.fromASCII(bases[i]);
+ return normalBases;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/LowerBound.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/LowerBound.java
new file mode 100644
index 0000000..e5e292b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/bwa/java/LowerBound.java
@@ -0,0 +1,113 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.bwa.java;
+
+import org.broadinstitute.gatk.engine.alignment.reference.bwt.BWT;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * At any point along the given read, what is a good lower bound for the
+ * total number of differences?
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class LowerBound {
+ /**
+ * Lower bound of the suffix array.
+ */
+ public final long loIndex;
+
+ /**
+ * Upper bound of the suffix array.
+ */
+ public final long hiIndex;
+
+ /**
+ * Width of the bwt from loIndex -> hiIndex, inclusive.
+ */
+ public final long width;
+
+ /**
+ * The lower bound at the given point.
+ */
+ public final int value;
+
+ /**
+ * Create a new lower bound with the given value.
+ * @param loIndex The lower bound of the BWT.
+ * @param hiIndex The upper bound of the BWT.
+ * @param value Value for the lower bound at this site.
+ */
+ private LowerBound(long loIndex, long hiIndex, int value) {
+ this.loIndex = loIndex;
+ this.hiIndex = hiIndex;
+ this.width = hiIndex - loIndex + 1;
+ this.value = value;
+ }
+
+ /**
+ * Create a non-optimal bound according to the algorithm specified in Figure 3 of the BWA paper.
+ * @param bases Bases of the read to use when creating a new BWT.
+ * @param bwt BWT to check against.
+ * @return A list of lower bounds at every point in the reference.
+ *
+ */
+ public static List<LowerBound> create(Byte[] bases, BWT bwt) {
+ List<LowerBound> bounds = new ArrayList<LowerBound>();
+
+ long loIndex = 0, hiIndex = bwt.length();
+ int mismatches = 0;
+ for( int i = bases.length-1; i >= 0; i-- ) {
+ Byte base = bases[i];
+
+ // Ignore non-ACGT bases.
+ if( base != null ) {
+ loIndex = bwt.counts(base) + bwt.occurrences(base,loIndex-1) + 1;
+ hiIndex = bwt.counts(base) + bwt.occurrences(base,hiIndex);
+ }
+
+ if( base == null || loIndex > hiIndex ) {
+ loIndex = 0;
+ hiIndex = bwt.length();
+ mismatches++;
+ }
+ bounds.add(0,new LowerBound(loIndex,hiIndex,mismatches));
+ }
+
+ return bounds;
+ }
+
+ /**
+ * Create a string representation of this bound.
+ * @return String version of this bound.
+ */
+ public String toString() {
+ return String.format("LowerBound: w = %d, value = %d",width,value);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/package-info.java
new file mode 100644
index 0000000..5a6d70d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/AMBWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/AMBWriter.java
new file mode 100644
index 0000000..b090bab
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/AMBWriter.java
@@ -0,0 +1,93 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * Writes .amb files - a file indicating where 'holes' (indeterminant bases)
+ * exist in the contig. Currently, only empty, placeholder AMBs are supported.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class AMBWriter {
+ /**
+ * Number of holes is fixed at zero.
+ */
+ private static final int NUM_HOLES = 0;
+
+ /**
+ * Input stream from which to read BWT data.
+ */
+ private final PrintStream out;
+
+ /**
+ * Create a new ANNWriter targeting the given file.
+ * @param file file into which ANN data should be written.
+ * @throws java.io.IOException if there is a problem opening the output file.
+ */
+ public AMBWriter(File file) throws IOException {
+ out = new PrintStream(file);
+ }
+
+ /**
+ * Create a new ANNWriter targeting the given OutputStream.
+ * @param stream Stream into which ANN data should be written.
+ */
+ public AMBWriter(OutputStream stream) {
+ out = new PrintStream(stream);
+ }
+
+ /**
+ * Write the contents of the given dictionary into the AMB file.
+ * Assumes that there are no holes in the dictionary.
+ * @param dictionary Dictionary to write.
+ */
+ public void writeEmpty(SAMSequenceDictionary dictionary) {
+ long genomeLength = 0L;
+ for(SAMSequenceRecord sequence: dictionary.getSequences())
+ genomeLength += sequence.getSequenceLength();
+
+ int sequences = dictionary.getSequences().size();
+
+ // Write the header
+ out.printf("%d %d %d%n",genomeLength,sequences,NUM_HOLES);
+ }
+
+ /**
+ * Close the given output stream.
+ */
+ public void close() {
+ out.close();
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/ANNWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/ANNWriter.java
new file mode 100644
index 0000000..123b3ca
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/ANNWriter.java
@@ -0,0 +1,120 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * Writes .ann files - an alternate sequence dictionary format
+ * used by BWA/C. For best results, the input sequence dictionary
+ * should be created with Picard's CreateSequenceDictionary.jar,
+ * TRUNCATE_NAMES_AT_WHITESPACE=false.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class ANNWriter {
+ /**
+ * BWA uses a fixed seed of 11, written into every file.
+ */
+ private static final int BNS_SEED = 11;
+
+ /**
+ * A seemingly unused value that appears in every contig in the ANN.
+ */
+ private static final int GI = 0;
+
+ /**
+ * Input stream from which to read BWT data.
+ */
+ private final PrintStream out;
+
+ /**
+ * Create a new ANNWriter targeting the given file.
+ * @param file file into which ANN data should be written.
+ * @throws IOException if there is a problem opening the output file.
+ */
+ public ANNWriter(File file) throws IOException {
+ out = new PrintStream(file);
+ }
+
+ /**
+ * Create a new ANNWriter targeting the given OutputStream.
+ * @param stream Stream into which ANN data should be written.
+ */
+ public ANNWriter(OutputStream stream) {
+ out = new PrintStream(stream);
+ }
+
+ /**
+ * Write the contents of the given dictionary into the ANN file.
+ * Assumes that no ambs (blocks of indeterminate base) are present in the dictionary.
+ * @param dictionary Dictionary to write.
+ */
+ public void write(SAMSequenceDictionary dictionary) {
+ long genomeLength = 0L;
+ for(SAMSequenceRecord sequence: dictionary.getSequences())
+ genomeLength += sequence.getSequenceLength();
+
+ int sequences = dictionary.getSequences().size();
+
+ // Write the header
+ out.printf("%d %d %d%n",genomeLength,sequences,BNS_SEED);
+
+ for(SAMSequenceRecord sequence: dictionary.getSequences()) {
+ String fullSequenceName = sequence.getSequenceName();
+ String trimmedSequenceName = fullSequenceName;
+ String sequenceComment = "(null)";
+
+ long offset = 0;
+
+ // Separate the sequence name from the sequence comment, based on BWA's definition.
+ // BWA's definition appears to accept a zero-length contig name, so mimic that behavior.
+ if(fullSequenceName.indexOf(' ') >= 0) {
+ trimmedSequenceName = fullSequenceName.substring(0,fullSequenceName.indexOf(' '));
+ sequenceComment = fullSequenceName.substring(fullSequenceName.indexOf(' ')+1);
+ }
+
+ // Write the sequence GI (?), name, and comment.
+ out.printf("%d %s %s%n",GI,trimmedSequenceName,sequenceComment);
+ // Write the sequence offset, length, and ambs (currently fixed at 0).
+ out.printf("%d %d %d%n",offset,sequence.getSequenceLength(),0);
+ }
+ }
+
+ /**
+ * Close the given output stream.
+ */
+ public void close() {
+ out.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWT.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWT.java
new file mode 100644
index 0000000..7d0c43b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWT.java
@@ -0,0 +1,197 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import org.broadinstitute.gatk.engine.alignment.reference.packing.PackUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+/**
+ * Represents the Burrows-Wheeler Transform of a reference sequence.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class BWT {
+ /**
+ * Write an occurrence table after every SEQUENCE_BLOCK_SIZE bases.
+ * For this implementation to behave correctly, SEQUENCE_BLOCK_SIZE % 8 == 0
+ */
+ public static final int SEQUENCE_BLOCK_SIZE = 128;
+
+ /**
+ * The inverse SA, used as a placeholder for determining where the special EOL character sits.
+ */
+ protected final long inverseSA0;
+
+ /**
+ * Cumulative counts for the entire BWT.
+ */
+ protected final Counts counts;
+
+ /**
+ * The individual sequence blocks, modelling how they appear on disk.
+ */
+ protected final SequenceBlock[] sequenceBlocks;
+
+ /**
+ * Creates a new BWT with the given inverse SA, counts, and sequence (in ASCII).
+ * @param inverseSA0 Inverse SA entry for the first element. Will be missing from the BWT sequence.
+ * @param counts Cumulative count of bases, in A,C,G,T order.
+ * @param sequenceBlocks The full BWT sequence, sans the '$'.
+ */
+ public BWT( long inverseSA0, Counts counts, SequenceBlock[] sequenceBlocks ) {
+ this.inverseSA0 = inverseSA0;
+ this.counts = counts;
+ this.sequenceBlocks = sequenceBlocks;
+ }
+
+ /**
+ * Creates a new BWT with the given inverse SA, occurrences, and sequence (in ASCII).
+ * @param inverseSA0 Inverse SA entry for the first element. Will be missing from the BWT sequence.
+ * @param counts Count of bases, in A,C,G,T order.
+ * @param sequence The full BWT sequence, sans the '$'.
+ */
+ public BWT( long inverseSA0, Counts counts, byte[] sequence ) {
+ this(inverseSA0,counts,generateSequenceBlocks(sequence));
+ }
+
+ /**
+ * Extract the full sequence from the list of block.
+ * @return The full BWT string as a byte array.
+ */
+ public byte[] getSequence() {
+ byte[] sequence = new byte[(int)counts.getTotal()];
+ for( SequenceBlock block: sequenceBlocks )
+ System.arraycopy(block.sequence,0,sequence,block.sequenceStart,block.sequenceLength);
+ return sequence;
+ }
+
+ /**
+ * Get the total counts of bases lexicographically smaller than the given base, for Ferragina and Manzini's search.
+ * @param base The base.
+ * @return Total counts for all bases lexicographically smaller than this base.
+ */
+ public long counts(byte base) {
+ return counts.getCumulative(base);
+ }
+
+ /**
+ * Get the total counts of bases lexicographically smaller than the given base, for Ferragina and Manzini's search.
+ * @param base The base.
+ * @param index The position to search within the BWT.
+ * @return Total counts for all bases lexicographically smaller than this base.
+ */
+ public long occurrences(byte base,long index) {
+ SequenceBlock block = getSequenceBlock(index);
+ int position = getSequencePosition(index);
+ long accumulator = block.occurrences.get(base);
+ for(int i = 0; i <= position; i++) {
+ if(base == block.sequence[i])
+ accumulator++;
+ }
+ return accumulator;
+ }
+
+ /**
+ * The number of bases in the BWT as a whole.
+ * @return Number of bases.
+ */
+ public long length() {
+ return counts.getTotal();
+ }
+
+ /**
+ * Create a new BWT from the given reference sequence.
+ * @param referenceSequence Sequence from which to derive the BWT.
+ * @return reference sequence-derived BWT.
+ */
+ public static BWT createFromReferenceSequence(byte[] referenceSequence) {
+ SuffixArray suffixArray = SuffixArray.createFromReferenceSequence(referenceSequence);
+
+ byte[] bwt = new byte[(int)suffixArray.length()-1];
+ int bwtIndex = 0;
+ for(long suffixArrayIndex = 0; suffixArrayIndex < suffixArray.length(); suffixArrayIndex++) {
+ if(suffixArray.get(suffixArrayIndex) == 0)
+ continue;
+ bwt[bwtIndex++] = referenceSequence[(int)suffixArray.get(suffixArrayIndex)-1];
+ }
+
+ return new BWT(suffixArray.inverseSA0,suffixArray.occurrences,bwt);
+ }
+
+ /**
+ * Gets the base at a given position in the BWT.
+ * @param index The index to use.
+ * @return The base at that location.
+ */
+ protected byte getBase(long index) {
+ if(index == inverseSA0)
+ throw new ReviewedGATKException(String.format("Base at index %d does not have a text representation",index));
+
+ SequenceBlock block = getSequenceBlock(index);
+ int position = getSequencePosition(index);
+ return block.sequence[position];
+ }
+
+ private SequenceBlock getSequenceBlock(long index) {
+ // If the index is above the SA-1[0], remap it to the appropriate coordinate space.
+ if(index > inverseSA0) index--;
+ return sequenceBlocks[(int)(index/SEQUENCE_BLOCK_SIZE)];
+ }
+
+ private int getSequencePosition(long index) {
+ // If the index is above the SA-1[0], remap it to the appropriate coordinate space.
+ if(index > inverseSA0) index--;
+ return (int)(index%SEQUENCE_BLOCK_SIZE);
+ }
+
+ /**
+ * Create a set of sequence blocks from one long sequence.
+ * @param sequence Sequence from which to derive blocks.
+ * @return Array of sequence blocks containing data from the sequence.
+ */
+ private static SequenceBlock[] generateSequenceBlocks( byte[] sequence ) {
+ Counts occurrences = new Counts();
+
+ int numSequenceBlocks = PackUtils.numberOfPartitions(sequence.length,SEQUENCE_BLOCK_SIZE);
+ SequenceBlock[] sequenceBlocks = new SequenceBlock[numSequenceBlocks];
+
+ for( int block = 0; block < numSequenceBlocks; block++ ) {
+ int blockStart = block*SEQUENCE_BLOCK_SIZE;
+ int blockLength = Math.min(SEQUENCE_BLOCK_SIZE, sequence.length-blockStart);
+ byte[] subsequence = new byte[blockLength];
+
+ System.arraycopy(sequence,blockStart,subsequence,0,blockLength);
+
+ sequenceBlocks[block] = new SequenceBlock(blockStart,blockLength,occurrences.clone(),subsequence);
+
+ for( byte base: subsequence )
+ occurrences.increment(base);
+ }
+
+ return sequenceBlocks;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWTReader.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWTReader.java
new file mode 100644
index 0000000..9b28e2a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWTReader.java
@@ -0,0 +1,114 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import org.broadinstitute.gatk.engine.alignment.reference.packing.BasePackedInputStream;
+import org.broadinstitute.gatk.engine.alignment.reference.packing.PackUtils;
+import org.broadinstitute.gatk.engine.alignment.reference.packing.UnsignedIntPackedInputStream;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.ByteOrder;
+/**
+ * Reads a BWT from a given file.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class BWTReader {
+ /**
+ * Input stream from which to read BWT data.
+ */
+ private FileInputStream inputStream;
+
+ /**
+ * Create a new BWT reader.
+ * @param inputFile File in which the BWT is stored.
+ */
+ public BWTReader( File inputFile ) {
+ try {
+ this.inputStream = new FileInputStream(inputFile);
+ }
+ catch( FileNotFoundException ex ) {
+ throw new ReviewedGATKException("Unable to open input file", ex);
+ }
+ }
+
+ /**
+ * Read a BWT from the input stream.
+ * @return The BWT stored in the input stream.
+ */
+ public BWT read() {
+ UnsignedIntPackedInputStream uintPackedInputStream = new UnsignedIntPackedInputStream(inputStream, ByteOrder.LITTLE_ENDIAN);
+ BasePackedInputStream basePackedInputStream = new BasePackedInputStream<Integer>(Integer.class, inputStream, ByteOrder.LITTLE_ENDIAN);
+
+ long inverseSA0;
+ long[] count;
+ SequenceBlock[] sequenceBlocks;
+
+ try {
+ inverseSA0 = uintPackedInputStream.read();
+ count = new long[PackUtils.ALPHABET_SIZE];
+ uintPackedInputStream.read(count);
+
+ long bwtSize = count[PackUtils.ALPHABET_SIZE-1];
+ sequenceBlocks = new SequenceBlock[PackUtils.numberOfPartitions(bwtSize,BWT.SEQUENCE_BLOCK_SIZE)];
+
+ for( int block = 0; block < sequenceBlocks.length; block++ ) {
+ int sequenceStart = block* BWT.SEQUENCE_BLOCK_SIZE;
+ int sequenceLength = (int)Math.min(BWT.SEQUENCE_BLOCK_SIZE,bwtSize-sequenceStart);
+
+ long[] occurrences = new long[PackUtils.ALPHABET_SIZE];
+ byte[] bwt = new byte[sequenceLength];
+
+ uintPackedInputStream.read(occurrences);
+ basePackedInputStream.read(bwt);
+
+ sequenceBlocks[block] = new SequenceBlock(sequenceStart,sequenceLength,new Counts(occurrences,false),bwt);
+ }
+ }
+ catch( IOException ex ) {
+ throw new ReviewedGATKException("Unable to read BWT from input stream.", ex);
+ }
+
+ return new BWT(inverseSA0, new Counts(count,true), sequenceBlocks);
+ }
+
+ /**
+ * Close the input stream.
+ */
+ public void close() {
+ try {
+ inputStream.close();
+ }
+ catch( IOException ex ) {
+ throw new ReviewedGATKException("Unable to close input file", ex);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWTSupplementaryFileGenerator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWTSupplementaryFileGenerator.java
new file mode 100644
index 0000000..e60a78b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWTSupplementaryFileGenerator.java
@@ -0,0 +1,85 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequenceFileFactory;
+import htsjdk.samtools.SAMSequenceDictionary;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Generate BWA supplementary files (.ann, .amb) from the command line.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class BWTSupplementaryFileGenerator {
+ enum SupplementaryFileType { ANN, AMB }
+
+ public static void main(String[] args) throws IOException {
+ if(args.length < 3)
+ usage("Incorrect number of arguments supplied");
+
+ File fastaFile = new File(args[0]);
+ File outputFile = new File(args[1]);
+ SupplementaryFileType outputType = null;
+ try {
+ outputType = Enum.valueOf(SupplementaryFileType.class,args[2]);
+ }
+ catch(IllegalArgumentException ex) {
+ usage("Invalid output type: " + args[2]);
+ }
+
+ ReferenceSequenceFile sequenceFile = ReferenceSequenceFileFactory.getReferenceSequenceFile(fastaFile);
+ SAMSequenceDictionary dictionary = sequenceFile.getSequenceDictionary();
+
+ switch(outputType) {
+ case ANN:
+ ANNWriter annWriter = new ANNWriter(outputFile);
+ annWriter.write(dictionary);
+ annWriter.close();
+ break;
+ case AMB:
+ AMBWriter ambWriter = new AMBWriter(outputFile);
+ ambWriter.writeEmpty(dictionary);
+ ambWriter.close();
+ break;
+ default:
+ usage("Unsupported output type: " + outputType);
+ }
+ }
+
+ /**
+ * Print usage information and exit.
+ */
+ private static void usage(String message) {
+ System.err.println(message);
+ System.err.println("Usage: BWTSupplementaryFileGenerator <fasta> <output file> <output type>");
+ System.exit(1);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWTWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWTWriter.java
new file mode 100644
index 0000000..4f2a159
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/BWTWriter.java
@@ -0,0 +1,96 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import org.broadinstitute.gatk.engine.alignment.reference.packing.BasePackedOutputStream;
+import org.broadinstitute.gatk.engine.alignment.reference.packing.UnsignedIntPackedOutputStream;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.*;
+import java.nio.ByteOrder;
+
+/**
+ * Writes an in-memory BWT to an outputstream.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class BWTWriter {
+ /**
+ * Input stream from which to read BWT data.
+ */
+ private final OutputStream outputStream;
+
+ /**
+ * Create a new BWT writer.
+ * @param outputFile File in which the BWT is stored.
+ */
+ public BWTWriter( File outputFile ) {
+ try {
+ this.outputStream = new BufferedOutputStream(new FileOutputStream(outputFile));
+ }
+ catch( FileNotFoundException ex ) {
+ throw new ReviewedGATKException("Unable to open output file", ex);
+ }
+ }
+
+ /**
+ * Write a BWT to the output stream.
+ * @param bwt Transform to be written to the output stream.
+ */
+ public void write( BWT bwt ) {
+ UnsignedIntPackedOutputStream intPackedOutputStream = new UnsignedIntPackedOutputStream(outputStream, ByteOrder.LITTLE_ENDIAN);
+ BasePackedOutputStream basePackedOutputStream = new BasePackedOutputStream<Integer>(Integer.class, outputStream, ByteOrder.LITTLE_ENDIAN);
+
+ try {
+ intPackedOutputStream.write(bwt.inverseSA0);
+ intPackedOutputStream.write(bwt.counts.toArray(true));
+
+ for( SequenceBlock block: bwt.sequenceBlocks ) {
+ intPackedOutputStream.write(block.occurrences.toArray(false));
+ basePackedOutputStream.write(block.sequence);
+ }
+
+ // The last block is the last set of counts in the structure.
+ intPackedOutputStream.write(bwt.counts.toArray(false));
+ }
+ catch( IOException ex ) {
+ throw new ReviewedGATKException("Unable to read BWT from input stream.", ex);
+ }
+ }
+
+ /**
+ * Close the input stream.
+ */
+ public void close() {
+ try {
+ outputStream.close();
+ }
+ catch( IOException ex ) {
+ throw new ReviewedGATKException("Unable to close input file", ex);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/Bases.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/Bases.java
new file mode 100644
index 0000000..d0cd849
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/Bases.java
@@ -0,0 +1,133 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ * Enhanced enum representation of a base.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class Bases implements Iterable<Byte>
+{
+ public static final byte A = 'A';
+ public static final byte C = 'C';
+ public static final byte G = 'G';
+ public static final byte T = 'T';
+
+ public static final Bases instance = new Bases();
+
+ private static final List<Byte> allBases;
+
+ /**
+ * Representation of the base broken down by packed value.
+ */
+ private static final Map<Integer,Byte> basesByPack = new HashMap<Integer,Byte>();
+
+ static {
+ List<Byte> bases = new ArrayList<Byte>();
+ bases.add(A);
+ bases.add(C);
+ bases.add(G);
+ bases.add(T);
+ allBases = Collections.unmodifiableList(bases);
+
+ for(int i = 0; i < allBases.size(); i++)
+ basesByPack.put(i,allBases.get(i));
+ }
+
+ /**
+ * Create a new base with the given ascii representation and
+ * pack value.
+ */
+ private Bases() {
+ }
+
+ /**
+ * Return all possible bases.
+ * @return Byte representation of all bases.
+ */
+ public static Collection<Byte> allOf() {
+ return allBases;
+ }
+
+ /**
+ * Gets the number of known bases.
+ * @return The number of known bases.
+ */
+ public static int size() {
+ return allBases.size();
+ }
+
+ /**
+ * Gets an iterator over the total number of known base types.
+ * @return Iterator over all known bases.
+ */
+ public Iterator<Byte> iterator() {
+ return basesByPack.values().iterator();
+ }
+
+ /**
+ * Get the given base from the packed representation.
+ * @param pack Packed representation.
+ * @return base.
+ */
+ public static byte fromPack( int pack ) { return basesByPack.get(pack); }
+
+ /**
+ * Convert the given base to its packed value.
+ * @param ascii ASCII representation of the base.
+ * @return Packed value.
+ */
+ public static int toPack( byte ascii )
+ {
+ for( Map.Entry<Integer,Byte> entry: basesByPack.entrySet() ) {
+ if( entry.getValue().equals(ascii) )
+ return entry.getKey();
+ }
+ throw new ReviewedGATKException(String.format("Base %c is an invalid base to pack", (char)ascii));
+ }
+
+ /**
+ * Convert the ASCII representation of a base to its 'normalized' representation.
+ * @param base The base itself.
+ * @return The byte, if present. Null if unknown.
+ */
+ public static Byte fromASCII( byte base ) {
+ Byte found = null;
+ for( Byte normalized: allBases ) {
+ if( normalized.equals(base) ) {
+ found = normalized;
+ break;
+ }
+ }
+ return found;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/Counts.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/Counts.java
new file mode 100644
index 0000000..c6684b5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/Counts.java
@@ -0,0 +1,176 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Counts of how many bases of each type have been seen.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class Counts implements Cloneable {
+ /**
+ * Internal representation of counts, broken down by ASCII value.
+ */
+ private Map<Byte,Long> counts = new HashMap<Byte,Long>();
+
+ /**
+ * Internal representation of cumulative counts, broken down by ASCII value.
+ */
+ private Map<Byte,Long> cumulativeCounts = new HashMap<Byte,Long>();
+
+ /**
+ * Create an empty Counts object with values A=0,C=0,G=0,T=0.
+ */
+ public Counts()
+ {
+ for(byte base: Bases.instance) {
+ counts.put(base,0L);
+ cumulativeCounts.put(base,0L);
+ }
+ }
+
+ /**
+ * Create a counts data structure with the given initial values.
+ * @param data Count data, broken down by base.
+ * @param cumulative Whether the counts are cumulative, (count_G=numA+numC+numG,for example).
+ */
+ public Counts( long[] data, boolean cumulative ) {
+ if(cumulative) {
+ long priorCount = 0;
+ for(byte base: Bases.instance) {
+ long count = data[Bases.toPack(base)];
+ counts.put(base,count-priorCount);
+ cumulativeCounts.put(base,priorCount);
+ priorCount = count;
+ }
+ }
+ else {
+ long priorCount = 0;
+ for(byte base: Bases.instance) {
+ long count = data[Bases.toPack(base)];
+ counts.put(base,count);
+ cumulativeCounts.put(base,priorCount);
+ priorCount += count;
+ }
+ }
+ }
+
+ /**
+ * Convert to an array for persistence.
+ * @param cumulative Use a cumulative representation.
+ * @return Array of count values.
+ */
+ public long[] toArray(boolean cumulative) {
+ long[] countArray = new long[counts.size()];
+ if(cumulative) {
+ int index = 0;
+ boolean first = true;
+ for(byte base: Bases.instance) {
+ if(first) {
+ first = false;
+ continue;
+ }
+ countArray[index++] = getCumulative(base);
+ }
+ countArray[countArray.length-1] = getTotal();
+ }
+ else {
+ int index = 0;
+ for(byte base: Bases.instance)
+ countArray[index++] = counts.get(base);
+ }
+ return countArray;
+ }
+
+ /**
+ * Create a unique copy of the current object.
+ * @return A duplicate of this object.
+ */
+ public Counts clone() {
+ Counts other;
+ try {
+ other = (Counts)super.clone();
+ }
+ catch(CloneNotSupportedException ex) {
+ throw new ReviewedGATKException("Unable to clone counts object", ex);
+ }
+ other.counts = new HashMap<Byte,Long>(counts);
+ other.cumulativeCounts = new HashMap<Byte,Long>(cumulativeCounts);
+ return other;
+ }
+
+ /**
+ * Increment the number of bases seen at the given location.
+ * @param base Base to increment.
+ */
+ public void increment(byte base) {
+ counts.put(base,counts.get(base)+1);
+ boolean increment = false;
+ for(byte cumulative: Bases.instance) {
+ if(increment) cumulativeCounts.put(cumulative,cumulativeCounts.get(cumulative)+1);
+ increment |= (cumulative == base);
+ }
+ }
+
+ /**
+ * Gets a count of the number of bases seen at a given location.
+ * Note that counts in this case are not cumulative (counts for A,C,G,T
+ * are independent).
+ * @param base Base for which to query counts.
+ * @return Number of bases of this type seen.
+ */
+ public long get(byte base) {
+ return counts.get(base);
+ }
+
+ /**
+ * Gets a count of the number of bases seen before this base.
+ * Note that counts in this case are cumulative.
+ * @param base Base for which to query counts.
+ * @return Number of bases of this type seen.
+ */
+ public long getCumulative(byte base) {
+ return cumulativeCounts.get(base);
+ }
+
+ /**
+ * How many total bases are represented by this count structure?
+ * @return Total bases represented.
+ */
+ public long getTotal() {
+ int accumulator = 0;
+ for(byte base: Bases.instance) {
+ accumulator += get(base);
+ }
+ return accumulator;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/CreateBWTFromReference.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/CreateBWTFromReference.java
new file mode 100644
index 0000000..baa5ebe
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/CreateBWTFromReference.java
@@ -0,0 +1,200 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import htsjdk.samtools.reference.ReferenceSequence;
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequenceFileFactory;
+import org.broadinstitute.gatk.engine.alignment.reference.packing.PackUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Create a suffix array data structure.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class CreateBWTFromReference {
+ private byte[] loadReference( File inputFile ) {
+ // Read in the first sequence in the input file
+ ReferenceSequenceFile reference = ReferenceSequenceFileFactory.getReferenceSequenceFile(inputFile);
+ ReferenceSequence sequence = reference.nextSequence();
+ return sequence.getBases();
+ }
+
+ private byte[] loadReverseReference( File inputFile ) {
+ ReferenceSequenceFile reference = ReferenceSequenceFileFactory.getReferenceSequenceFile(inputFile);
+ ReferenceSequence sequence = reference.nextSequence();
+ PackUtils.reverse(sequence.getBases());
+ return sequence.getBases();
+ }
+
+ private Counts countOccurrences( byte[] sequence ) {
+ Counts occurrences = new Counts();
+ for( byte base: sequence )
+ occurrences.increment(base);
+ return occurrences;
+ }
+
+ private long[] createSuffixArray( byte[] sequence ) {
+ return SuffixArray.createFromReferenceSequence(sequence).sequence;
+ }
+
+ private long[] invertSuffixArray( long[] suffixArray ) {
+ long[] inverseSuffixArray = new long[suffixArray.length];
+ for( int i = 0; i < suffixArray.length; i++ )
+ inverseSuffixArray[(int)suffixArray[i]] = i;
+ return inverseSuffixArray;
+ }
+
+ private long[] createCompressedSuffixArray( int[] suffixArray, int[] inverseSuffixArray ) {
+ long[] compressedSuffixArray = new long[suffixArray.length];
+ compressedSuffixArray[0] = inverseSuffixArray[0];
+ for( int i = 1; i < suffixArray.length; i++ )
+ compressedSuffixArray[i] = inverseSuffixArray[suffixArray[i]+1];
+ return compressedSuffixArray;
+ }
+
+ private long[] createInversedCompressedSuffixArray( int[] compressedSuffixArray ) {
+ long[] inverseCompressedSuffixArray = new long[compressedSuffixArray.length];
+ for( int i = 0; i < compressedSuffixArray.length; i++ )
+ inverseCompressedSuffixArray[compressedSuffixArray[i]] = i;
+ return inverseCompressedSuffixArray;
+ }
+
+ public static void main( String argv[] ) throws IOException {
+ if( argv.length != 5 ) {
+ System.out.println("USAGE: CreateBWTFromReference <input>.fasta <output bwt> <output rbwt> <output sa> <output rsa>");
+ return;
+ }
+
+ String inputFileName = argv[0];
+ File inputFile = new File(inputFileName);
+
+ String bwtFileName = argv[1];
+ File bwtFile = new File(bwtFileName);
+
+ String rbwtFileName = argv[2];
+ File rbwtFile = new File(rbwtFileName);
+
+ String saFileName = argv[3];
+ File saFile = new File(saFileName);
+
+ String rsaFileName = argv[4];
+ File rsaFile = new File(rsaFileName);
+
+ CreateBWTFromReference creator = new CreateBWTFromReference();
+
+ byte[] sequence = creator.loadReference(inputFile);
+ byte[] reverseSequence = creator.loadReverseReference(inputFile);
+
+ // Count the occurences of each given base.
+ Counts occurrences = creator.countOccurrences(sequence);
+ System.out.printf("Occurrences: a=%d, c=%d, g=%d, t=%d%n",occurrences.getCumulative(Bases.A),
+ occurrences.getCumulative(Bases.C),
+ occurrences.getCumulative(Bases.G),
+ occurrences.getCumulative(Bases.T));
+
+ // Generate the suffix array and print diagnostics.
+ long[] suffixArrayData = creator.createSuffixArray(sequence);
+ long[] reverseSuffixArrayData = creator.createSuffixArray(reverseSequence);
+
+ // Invert the suffix array and print diagnostics.
+ long[] inverseSuffixArray = creator.invertSuffixArray(suffixArrayData);
+ long[] reverseInverseSuffixArray = creator.invertSuffixArray(reverseSuffixArrayData);
+
+ SuffixArray suffixArray = new SuffixArray( inverseSuffixArray[0], occurrences, suffixArrayData );
+ SuffixArray reverseSuffixArray = new SuffixArray( reverseInverseSuffixArray[0], occurrences, reverseSuffixArrayData );
+
+ /*
+ // Create the data structure for the compressed suffix array and print diagnostics.
+ int[] compressedSuffixArray = creator.createCompressedSuffixArray(suffixArray.sequence,inverseSuffixArray);
+ int reconstructedInverseSA = compressedSuffixArray[0];
+ for( int i = 0; i < 8; i++ ) {
+ System.out.printf("compressedSuffixArray[%d] = %d (SA-1[%d] = %d)%n", i, compressedSuffixArray[i], i, reconstructedInverseSA);
+ reconstructedInverseSA = compressedSuffixArray[reconstructedInverseSA];
+ }
+
+ // Create the data structure for the inverse compressed suffix array and print diagnostics.
+ int[] inverseCompressedSuffixArray = creator.createInversedCompressedSuffixArray(compressedSuffixArray);
+ for( int i = 0; i < 8; i++ ) {
+ System.out.printf("inverseCompressedSuffixArray[%d] = %d%n", i, inverseCompressedSuffixArray[i]);
+ }
+ */
+
+ // Create the BWT.
+ BWT bwt = BWT.createFromReferenceSequence(sequence);
+ BWT reverseBWT = BWT.createFromReferenceSequence(reverseSequence);
+
+ byte[] bwtSequence = bwt.getSequence();
+ System.out.printf("BWT: %s... (length = %d)%n", new String(bwtSequence,0,80),bwt.length());
+
+ BWTWriter bwtWriter = new BWTWriter(bwtFile);
+ bwtWriter.write(bwt);
+ bwtWriter.close();
+
+ BWTWriter reverseBWTWriter = new BWTWriter(rbwtFile);
+ reverseBWTWriter.write(reverseBWT);
+ reverseBWTWriter.close();
+
+ /*
+ SuffixArrayWriter saWriter = new SuffixArrayWriter(saFile);
+ saWriter.write(suffixArray);
+ saWriter.close();
+
+ SuffixArrayWriter reverseSAWriter = new SuffixArrayWriter(rsaFile);
+ reverseSAWriter.write(reverseSuffixArray);
+ reverseSAWriter.close();
+ */
+
+ File existingBWTFile = new File(inputFileName+".bwt");
+ BWTReader existingBWTReader = new BWTReader(existingBWTFile);
+ BWT existingBWT = existingBWTReader.read();
+
+ byte[] existingBWTSequence = existingBWT.getSequence();
+ System.out.printf("Existing BWT: %s... (length = %d)%n",new String(existingBWTSequence,0,80),existingBWT.length());
+
+ for( int i = 0; i < bwt.length(); i++ ) {
+ if( bwtSequence[i] != existingBWTSequence[i] )
+ throw new ReviewedGATKException("BWT mismatch at " + i);
+ }
+
+ File existingSAFile = new File(inputFileName+".sa");
+ SuffixArrayReader existingSuffixArrayReader = new SuffixArrayReader(existingSAFile,existingBWT);
+ SuffixArray existingSuffixArray = existingSuffixArrayReader.read();
+
+ for(int i = 0; i < suffixArray.length(); i++) {
+ if( i % 10000 == 0 )
+ System.out.printf("Validating suffix array entry %d%n", i);
+ if( suffixArray.get(i) != existingSuffixArray.get(i) )
+ throw new ReviewedGATKException(String.format("Suffix array mismatch at %d; SA is %d; should be %d",i,existingSuffixArray.get(i),suffixArray.get(i)));
+ }
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SequenceBlock.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SequenceBlock.java
new file mode 100644
index 0000000..555e7cc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SequenceBlock.java
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+/**
+ * Models a block of bases within the BWT.
+ */
+public class SequenceBlock {
+ /**
+ * Start position of this sequence within the BWT.
+ */
+ public final int sequenceStart;
+
+ /**
+ * Length of this sequence within the BWT.
+ */
+ public final int sequenceLength;
+
+
+ /**
+ * Occurrences of each letter up to this sequence block.
+ */
+ public final Counts occurrences;
+
+ /**
+ * Sequence for this segment.
+ */
+ public final byte[] sequence;
+
+ /**
+ * Create a new block within this BWT.
+ * @param sequenceStart Starting position of this sequence within the BWT.
+ * @param sequenceLength Length of this sequence.
+ * @param occurrences How many of each base has been seen before this sequence began.
+ * @param sequence The actual sequence from the BWT.
+ */
+ public SequenceBlock( int sequenceStart, int sequenceLength, Counts occurrences, byte[] sequence ) {
+ this.sequenceStart = sequenceStart;
+ this.sequenceLength = sequenceLength;
+ this.occurrences = occurrences;
+ this.sequence = sequence;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SuffixArray.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SuffixArray.java
new file mode 100644
index 0000000..d1edfe5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SuffixArray.java
@@ -0,0 +1,183 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import htsjdk.samtools.util.StringUtil;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.Comparator;
+import java.util.TreeSet;
+
+/**
+ * An in-memory representation of a suffix array.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class SuffixArray {
+ public final long inverseSA0;
+ public final Counts occurrences;
+
+ /**
+ * The elements of the sequence actually stored in memory.
+ */
+ protected final long[] sequence;
+
+ /**
+ * How often are individual elements in the sequence actually stored
+ * in memory, as opposed to being calculated on the fly?
+ */
+ protected final int sequenceInterval;
+
+ /**
+ * The BWT used to calculate missing portions of the sequence.
+ */
+ protected final BWT bwt;
+
+ public SuffixArray(long inverseSA0, Counts occurrences, long[] sequence) {
+ this(inverseSA0,occurrences,sequence,1,null);
+ }
+
+ /**
+ * Creates a new sequence array with the given inverse SA, occurrences, and values.
+ * @param inverseSA0 Inverse SA entry for the first element.
+ * @param occurrences Cumulative number of occurrences of A,C,G,T, in order.
+ * @param sequence The full suffix array.
+ * @param sequenceInterval How frequently is the sequence interval stored.
+ * @param bwt bwt used to infer the remaining entries in the BWT.
+ */
+ public SuffixArray(long inverseSA0, Counts occurrences, long[] sequence, int sequenceInterval, BWT bwt) {
+ this.inverseSA0 = inverseSA0;
+ this.occurrences = occurrences;
+ this.sequence = sequence;
+ this.sequenceInterval = sequenceInterval;
+ this.bwt = bwt;
+
+ if(sequenceInterval != 1 && bwt == null)
+ throw new ReviewedGATKException("A BWT must be provided if the sequence interval is not 1");
+ }
+
+ /**
+ * Retrieves the length of the sequence array.
+ * @return Length of the suffix array.
+ */
+ public long length() {
+ if( bwt != null )
+ return bwt.length()+1;
+ else
+ return sequence.length;
+ }
+
+ /**
+ * Get the suffix array value at a given sequence.
+ * @param index Index at which to retrieve the suffix array vaule.
+ * @return The suffix array value at that entry.
+ */
+ public long get(long index) {
+ int iterations = 0;
+ while(index%sequenceInterval != 0) {
+ // The inverseSA0 ('$') doesn't have a usable ASCII representation; it must be treated as a special case.
+ if(index == inverseSA0)
+ index = 0;
+ else {
+ byte base = bwt.getBase(index);
+ index = bwt.counts(base) + bwt.occurrences(base,index);
+ }
+ iterations++;
+ }
+ return (sequence[(int)(index/sequenceInterval)]+iterations) % length();
+ }
+
+ /**
+ * Create a suffix array from a given reference sequence.
+ * @param sequence The reference sequence to use when building the suffix array.
+ * @return a constructed suffix array.
+ */
+ public static SuffixArray createFromReferenceSequence(byte[] sequence) {
+ // The builder for the suffix array. Use an integer in this case because
+ // Java arrays can only hold an integer.
+ TreeSet<Integer> suffixArrayBuilder = new TreeSet<Integer>(new SuffixArrayComparator(sequence));
+
+ Counts occurrences = new Counts();
+ for( byte base: sequence )
+ occurrences.increment(base);
+
+ // Build out the suffix array using a custom comparator.
+ for( int i = 0; i <= sequence.length; i++ )
+ suffixArrayBuilder.add(i);
+
+ // Copy the suffix array into an array.
+ long[] suffixArray = new long[suffixArrayBuilder.size()];
+ int i = 0;
+ for( Integer element: suffixArrayBuilder )
+ suffixArray[i++] = element;
+
+ // Find the first element in the inverse suffix array.
+ long inverseSA0 = -1;
+ for(i = 0; i < suffixArray.length; i++) {
+ if(suffixArray[i] == 0)
+ inverseSA0 = i;
+ }
+ if(inverseSA0 < 0)
+ throw new ReviewedGATKException("Unable to find first inverse SA entry in generated suffix array.");
+
+ return new SuffixArray(inverseSA0,occurrences,suffixArray);
+ }
+
+ /**
+ * Compares two suffix arrays of the given sequence. Will return whichever string appears
+ * first in lexicographic order.
+ */
+ private static class SuffixArrayComparator implements Comparator<Integer> {
+ /**
+ * The data source for all suffix arrays.
+ */
+ private final String sequence;
+
+ /**
+ * Create a new comparator.
+ * @param sequence Reference sequence to use as basis for comparison.
+ */
+ public SuffixArrayComparator( byte[] sequence ) {
+ // Processing the suffix array tends to be easier as a string.
+ this.sequence = StringUtil.bytesToString(sequence);
+ }
+
+ /**
+ * Compare the two given suffix arrays. Criteria for comparison is the lexicographic order of
+ * the two substrings sequence[lhs:], sequence[rhs:].
+ * @param lhs Left-hand side of comparison.
+ * @param rhs Right-hand side of comparison.
+ * @return How the suffix arrays represented by lhs, rhs compare.
+ */
+ public int compare( Integer lhs, Integer rhs ) {
+ String lhsSuffixArray = sequence.substring(lhs);
+ String rhsSuffixArray = sequence.substring(rhs);
+ return lhsSuffixArray.compareTo(rhsSuffixArray);
+ }
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SuffixArrayReader.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SuffixArrayReader.java
new file mode 100644
index 0000000..dc8cdc0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SuffixArrayReader.java
@@ -0,0 +1,110 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import org.broadinstitute.gatk.engine.alignment.reference.packing.PackUtils;
+import org.broadinstitute.gatk.engine.alignment.reference.packing.UnsignedIntPackedInputStream;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.ByteOrder;
+
+/**
+ * A reader for suffix arrays in permanent storage.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class SuffixArrayReader {
+ /**
+ * Input stream from which to read suffix array data.
+ */
+ private FileInputStream inputStream;
+
+ /**
+ * BWT to use to fill in missing data.
+ */
+ private BWT bwt;
+
+ /**
+ * Create a new suffix array reader.
+ * @param inputFile File in which the suffix array is stored.
+ * @param bwt BWT to use when filling in missing data.
+ */
+ public SuffixArrayReader(File inputFile, BWT bwt) {
+ try {
+ this.inputStream = new FileInputStream(inputFile);
+ this.bwt = bwt;
+ }
+ catch( FileNotFoundException ex ) {
+ throw new ReviewedGATKException("Unable to open input file", ex);
+ }
+ }
+
+ /**
+ * Read a suffix array from the input stream.
+ * @return The suffix array stored in the input stream.
+ */
+ public SuffixArray read() {
+ UnsignedIntPackedInputStream uintPackedInputStream = new UnsignedIntPackedInputStream(inputStream, ByteOrder.LITTLE_ENDIAN);
+
+ long inverseSA0;
+ long[] occurrences;
+ long[] suffixArray;
+ int suffixArrayInterval;
+
+ try {
+ inverseSA0 = uintPackedInputStream.read();
+ occurrences = new long[PackUtils.ALPHABET_SIZE];
+ uintPackedInputStream.read(occurrences);
+ // Throw away the suffix array size in bytes and use the occurrences table directly.
+ suffixArrayInterval = (int)uintPackedInputStream.read();
+ suffixArray = new long[(int)((occurrences[occurrences.length-1]+suffixArrayInterval-1)/suffixArrayInterval)];
+ uintPackedInputStream.read(suffixArray);
+ }
+ catch( IOException ex ) {
+ throw new ReviewedGATKException("Unable to read BWT from input stream.", ex);
+ }
+
+ return new SuffixArray(inverseSA0, new Counts(occurrences,true), suffixArray, suffixArrayInterval, bwt);
+ }
+
+
+ /**
+ * Close the input stream.
+ */
+ public void close() {
+ try {
+ inputStream.close();
+ }
+ catch( IOException ex ) {
+ throw new ReviewedGATKException("Unable to close input file", ex);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SuffixArrayWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SuffixArrayWriter.java
new file mode 100644
index 0000000..df152b9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/bwt/SuffixArrayWriter.java
@@ -0,0 +1,92 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.bwt;
+
+import org.broadinstitute.gatk.engine.alignment.reference.packing.UnsignedIntPackedOutputStream;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.*;
+import java.nio.ByteOrder;
+
+/**
+ * Javadoc goes here.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class SuffixArrayWriter {
+ /**
+ * Input stream from which to read suffix array data.
+ */
+ private OutputStream outputStream;
+
+ /**
+ * Create a new suffix array reader.
+ * @param outputFile File in which the suffix array is stored.
+ */
+ public SuffixArrayWriter( File outputFile ) {
+ try {
+ this.outputStream = new BufferedOutputStream(new FileOutputStream(outputFile));
+ }
+ catch( FileNotFoundException ex ) {
+ throw new ReviewedGATKException("Unable to open input file", ex);
+ }
+ }
+
+ /**
+ * Write a suffix array to the output stream.
+ * @param suffixArray suffix array to write.
+ */
+ public void write(SuffixArray suffixArray) {
+ UnsignedIntPackedOutputStream uintPackedOutputStream = new UnsignedIntPackedOutputStream(outputStream, ByteOrder.LITTLE_ENDIAN);
+
+ try {
+ uintPackedOutputStream.write(suffixArray.inverseSA0);
+ uintPackedOutputStream.write(suffixArray.occurrences.toArray(true));
+ // How frequently the suffix array entry is placed.
+ uintPackedOutputStream.write(1);
+ // Length of the suffix array.
+ uintPackedOutputStream.write(suffixArray.length()-1);
+ uintPackedOutputStream.write(suffixArray.sequence,1,suffixArray.sequence.length-1);
+ }
+ catch( IOException ex ) {
+ throw new ReviewedGATKException("Unable to read BWT from input stream.", ex);
+ }
+ }
+
+
+ /**
+ * Close the input stream.
+ */
+ public void close() {
+ try {
+ outputStream.close();
+ }
+ catch( IOException ex ) {
+ throw new ReviewedGATKException("Unable to close input file", ex);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/BasePackedInputStream.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/BasePackedInputStream.java
new file mode 100644
index 0000000..727a378
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/BasePackedInputStream.java
@@ -0,0 +1,120 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.packing;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+
+/**
+ * Reads a packed version of the input stream.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class BasePackedInputStream<T> {
+ /**
+ * Type of object to unpack.
+ */
+ private final Class<T> type;
+
+ /**
+ * Ultimate source for packed bases.
+ */
+ private final FileInputStream targetInputStream;
+
+ /**
+ * Channel source for packed bases.
+ */
+ private final FileChannel targetInputChannel;
+
+ /**
+ * A fixed-size buffer for word-packed data.
+ */
+ private final ByteOrder byteOrder;
+
+ /**
+ * How many bases are in a given packed word.
+ */
+ private final int basesPerPackedWord = PackUtils.bitsInType(Integer.class)/PackUtils.BITS_PER_BASE;
+
+ /**
+ * How many bytes in an integer?
+ */
+ private final int bytesPerInteger = PackUtils.bitsInType(Integer.class)/PackUtils.BITS_PER_BYTE;
+
+
+ public BasePackedInputStream( Class<T> type, File inputFile, ByteOrder byteOrder ) throws FileNotFoundException {
+ this(type,new FileInputStream(inputFile),byteOrder);
+ }
+
+ public BasePackedInputStream( Class<T> type, FileInputStream inputStream, ByteOrder byteOrder ) {
+ if( type != Integer.class )
+ throw new ReviewedGATKException("Only bases packed into 32-bit words are currently supported by this input stream. Type specified: " + type.getName());
+ this.type = type;
+ this.targetInputStream = inputStream;
+ this.targetInputChannel = inputStream.getChannel();
+ this.byteOrder = byteOrder;
+ }
+
+ /**
+ * Read the entire contents of the input stream.
+ * @param bwt array into which bases should be read.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void read(byte[] bwt) throws IOException {
+ read(bwt,0,bwt.length);
+ }
+
+ /**
+ * Read the next <code>length</code> bases into the bwt array, starting at the given offset.
+ * @param bwt array holding the given data.
+ * @param offset target position in the bases array into which bytes should be written.
+ * @param length number of bases to read from the stream.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void read(byte[] bwt, int offset, int length) throws IOException {
+ int bufferWidth = ((bwt.length+basesPerPackedWord-1)/basesPerPackedWord)*bytesPerInteger;
+ ByteBuffer buffer = ByteBuffer.allocate(bufferWidth).order(byteOrder);
+ targetInputChannel.read(buffer);
+ targetInputChannel.position(targetInputChannel.position()+buffer.remaining());
+ buffer.flip();
+
+ int packedWord = 0;
+ int i = 0;
+ while(i < length) {
+ if(i % basesPerPackedWord == 0) packedWord = buffer.getInt();
+ int position = basesPerPackedWord - i%basesPerPackedWord - 1;
+ bwt[offset+i++] = PackUtils.unpackBase((byte)((packedWord >> position*PackUtils.BITS_PER_BASE) & 0x3));
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/BasePackedOutputStream.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/BasePackedOutputStream.java
new file mode 100644
index 0000000..b3dbba8
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/BasePackedOutputStream.java
@@ -0,0 +1,165 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.packing;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A general-purpose stream for writing packed bases.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class BasePackedOutputStream<T> {
+ /**
+ * Type of object to pack.
+ */
+ private final Class<T> type;
+
+ /**
+ * How many bases can be stored in the given data structure?
+ */
+ private final int basesPerType;
+
+ /**
+ * Ultimate target for the packed bases.
+ */
+ private final OutputStream targetOutputStream;
+
+ /**
+ * A fixed-size buffer for word-packed data.
+ */
+ private final ByteBuffer buffer;
+
+ public BasePackedOutputStream( Class<T> type, File outputFile, ByteOrder byteOrder ) throws FileNotFoundException {
+ this(type,new BufferedOutputStream(new FileOutputStream(outputFile)),byteOrder);
+ }
+
+ /**
+ * Write packed bases to the given output stream.
+ * @param type Type of data to pack bases into.
+ * @param outputStream Output stream to which to write packed bases.
+ * @param byteOrder Switch between big endian / little endian when reading / writing files.
+ */
+ public BasePackedOutputStream( Class<T> type, OutputStream outputStream, ByteOrder byteOrder) {
+ this.targetOutputStream = outputStream;
+ this.type = type;
+ basesPerType = PackUtils.bitsInType(type)/PackUtils.BITS_PER_BASE;
+ this.buffer = ByteBuffer.allocate(basesPerType/PackUtils.ALPHABET_SIZE).order(byteOrder);
+ }
+
+ /**
+ * Writes the given base to the output stream. Will write only this base; no packing will be performed.
+ * @param base List of bases to write.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void write( int base ) throws IOException {
+ write( new byte[] { (byte)base } );
+ }
+
+ /**
+ * Writes an array of bases to the target output stream.
+ * @param bases List of bases to write.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void write( byte[] bases ) throws IOException {
+ write(bases,0,bases.length);
+ }
+
+ /**
+ * Writes a subset of the array of bases to the output stream.
+ * @param bases List of bases to write.
+ * @param offset site at which to start writing.
+ * @param length number of bases to write.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void write( byte[] bases, int offset, int length ) throws IOException {
+ int packedBases = 0;
+ int positionInPack = 0;
+
+ for( int base = offset; base < offset+length; base++ ) {
+ packedBases = packBase(bases[base], packedBases, positionInPack);
+
+ // Increment the packed counter. If all possible bases have been squeezed into this byte, write it out.
+ positionInPack = ++positionInPack % basesPerType;
+ if( positionInPack == 0 ) {
+ writePackedBases(packedBases);
+ packedBases = 0;
+ }
+ }
+
+ if( positionInPack > 0 )
+ writePackedBases(packedBases);
+ }
+
+ /**
+ * Flush the contents of the OutputStream to disk.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void flush() throws IOException {
+ targetOutputStream.flush();
+ }
+
+ /**
+ * Closes the given output stream.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void close() throws IOException {
+ targetOutputStream.close();
+ }
+
+ /**
+ * Pack the given base into the basepack.
+ * @param base The base to pack.
+ * @param basePack Target for the pack operation.
+ * @param position Position within the pack to which to add the base.
+ * @return The packed integer.
+ */
+ private int packBase( byte base, int basePack, int position ) {
+ basePack |= (PackUtils.packBase(base) << 2*(basesPerType-position-1));
+ return basePack;
+ }
+
+ /**
+ * Write the given packed base structure to the output file.
+ * @param packedBases Packed bases to write.
+ * @throws IOException on error writing to the file.
+ */
+ private void writePackedBases(int packedBases) throws IOException {
+ buffer.rewind();
+ if( type == Integer.class )
+ buffer.putInt(packedBases);
+ else if( type == Byte.class )
+ buffer.put((byte)packedBases);
+ else
+ throw new ReviewedGATKException("Cannot pack bases into type " + type.getName());
+ targetOutputStream.write(buffer.array());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/CreatePACFromReference.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/CreatePACFromReference.java
new file mode 100644
index 0000000..fac3d92
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/CreatePACFromReference.java
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.packing;
+
+import htsjdk.samtools.reference.ReferenceSequence;
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequenceFileFactory;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Generate a .PAC file from a given reference.
+ *
+ * @author hanna
+ * @version 0.1
+ */
+
+public class CreatePACFromReference {
+ public static void main( String argv[] ) throws IOException {
+ if( argv.length != 3 ) {
+ System.out.println("USAGE: CreatePACFromReference <input>.fasta <output pac> <output rpac>");
+ return;
+ }
+
+ // Read in the first sequence in the input file
+ String inputFileName = argv[0];
+ File inputFile = new File(inputFileName);
+ ReferenceSequenceFile reference = ReferenceSequenceFileFactory.getReferenceSequenceFile(inputFile);
+ ReferenceSequence sequence = reference.nextSequence();
+
+ // Target file for output
+ PackUtils.writeReferenceSequence( new File(argv[1]), sequence.getBases() );
+
+ // Reverse the bases in the reference
+ PackUtils.reverse(sequence.getBases());
+
+ // Target file for output
+ PackUtils.writeReferenceSequence( new File(argv[2]), sequence.getBases() );
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/PackUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/PackUtils.java
new file mode 100644
index 0000000..e60780a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/PackUtils.java
@@ -0,0 +1,160 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.packing;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteOrder;
+
+/**
+ * Utilities designed for packing / unpacking bases.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class PackUtils {
+ /**
+ * How many possible bases can be encoded?
+ */
+ public static final int ALPHABET_SIZE = 4;
+
+ /**
+ * How many bits does it take to store a single base?
+ */
+ public static final int BITS_PER_BASE = (int)(Math.log(ALPHABET_SIZE)/Math.log(2));
+
+ /**
+ * How many bits fit into a single byte?
+ */
+ public static final int BITS_PER_BYTE = 8;
+
+ /**
+ * Writes a reference sequence to a PAC file.
+ * @param outputFile Filename for the PAC file.
+ * @param referenceSequence Reference sequence to write.
+ * @throws IOException If there's a problem writing to the output file.
+ */
+ public static void writeReferenceSequence( File outputFile, byte[] referenceSequence ) throws IOException {
+ OutputStream outputStream = new FileOutputStream(outputFile);
+
+ BasePackedOutputStream<Byte> basePackedOutputStream = new BasePackedOutputStream<Byte>(Byte.class, outputStream, ByteOrder.BIG_ENDIAN);
+ basePackedOutputStream.write(referenceSequence);
+
+ outputStream.write(referenceSequence.length%PackUtils.ALPHABET_SIZE);
+
+ outputStream.close();
+ }
+
+
+ /**
+ * How many bits can a given type hold?
+ * @param type Type to test.
+ * @return Number of bits that the given type can hold.
+ */
+ public static int bitsInType( Class<?> type ) {
+ try {
+ long typeSize = type.getField("MAX_VALUE").getLong(null) - type.getField("MIN_VALUE").getLong(null)+1;
+ long intTypeSize = (long)Integer.MAX_VALUE - (long)Integer.MIN_VALUE + 1;
+ if( typeSize > intTypeSize )
+ throw new ReviewedGATKException("Cannot determine number of bits available in type: " + type.getName());
+ return (int)(Math.log(typeSize)/Math.log(2));
+ }
+ catch( NoSuchFieldException ex ) {
+ throw new ReviewedGATKException("Cannot determine number of bits available in type: " + type.getName(),ex);
+ }
+ catch( IllegalAccessException ex ) {
+ throw new ReviewedGATKException("Cannot determine number of bits available in type: " + type.getName(),ex);
+ }
+ }
+
+ /**
+ * Gets the two-bit representation of a base. A=00b, C=01b, G=10b, T=11b.
+ * @param base ASCII value for the base to pack.
+ * @return A byte from 0-3 indicating the base's packed value.
+ */
+ public static byte packBase(byte base) {
+ switch( base ) {
+ case 'A':
+ return 0;
+ case 'C':
+ return 1;
+ case 'G':
+ return 2;
+ case 'T':
+ return 3;
+ default:
+ throw new ReviewedGATKException("Unknown base type: " + base);
+ }
+ }
+
+ /**
+ * Converts a two-bit representation of a base into an ASCII representation of a base.
+ * @param pack Byte from 0-3 indicating which base is represented.
+ * @return An ASCII value representing the packed base.
+ */
+ public static byte unpackBase(byte pack) {
+ switch( pack ) {
+ case 0:
+ return 'A';
+ case 1:
+ return 'C';
+ case 2:
+ return 'G';
+ case 3:
+ return 'T';
+ default:
+ throw new ReviewedGATKException("Unknown pack type: " + pack);
+ }
+ }
+
+ /**
+ * Reverses an unpacked sequence of bases.
+ * @param bases bases to reverse.
+ */
+ public static void reverse( byte[] bases ) {
+ for( int i = 0, j = bases.length-1; i < j; i++, j-- ) {
+ byte temp = bases[j];
+ bases[j] = bases[i];
+ bases[i] = temp;
+ }
+ }
+
+ /**
+ * Given a structure of size <code>size</code> that should be split
+ * into <code>partitionSize</code> partitions, how many partitions should
+ * be created? Size of last partition will be <= partitionSize.
+ * @param size Total size of the data structure.
+ * @param partitionSize Size of an individual partition.
+ * @return Number of partitions that would be created.
+ */
+ public static int numberOfPartitions( long size, long partitionSize ) {
+ return (int)((size+partitionSize-1) / partitionSize);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/UnsignedIntPackedInputStream.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/UnsignedIntPackedInputStream.java
new file mode 100644
index 0000000..0600500
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/UnsignedIntPackedInputStream.java
@@ -0,0 +1,129 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.packing;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+
+/**
+ * Read a set of integers packed into
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class UnsignedIntPackedInputStream {
+ /**
+ * Ultimate target for the occurrence array.
+ */
+ private final FileInputStream targetInputStream;
+
+ /**
+ * Target channel from which to pull file data.
+ */
+ private final FileChannel targetInputChannel;
+
+ /**
+ * The byte order in which integer input data appears.
+ */
+ private final ByteOrder byteOrder;
+
+ /**
+ * How many bytes are required to store an integer?
+ */
+ private final int bytesPerInteger = PackUtils.bitsInType(Integer.class)/PackUtils.BITS_PER_BYTE;
+
+ /**
+ * Create a new PackedIntInputStream, writing to the given target file.
+ * @param inputFile target input file.
+ * @param byteOrder Endianness to use when writing a list of integers.
+ * @throws java.io.IOException if an I/O error occurs.
+ */
+ public UnsignedIntPackedInputStream(File inputFile, ByteOrder byteOrder) throws IOException {
+ this(new FileInputStream(inputFile),byteOrder);
+ }
+
+ /**
+ * Read ints from the given InputStream.
+ * @param inputStream Input stream from which to read ints.
+ * @param byteOrder Endianness to use when writing a list of integers.
+ */
+ public UnsignedIntPackedInputStream(FileInputStream inputStream, ByteOrder byteOrder) {
+ this.targetInputStream = inputStream;
+ this.targetInputChannel = inputStream.getChannel();
+ this.byteOrder = byteOrder;
+ }
+
+ /**
+ * Read a datum from the input stream.
+ * @return The next input datum in the stream.
+ * @throws IOException if an I/O error occurs.
+ */
+ public long read() throws IOException {
+ long[] data = new long[1];
+ read(data);
+ return data[0];
+ }
+
+ /**
+ * Read the data from the input stream.
+ * @param data placeholder for input data.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void read( long[] data ) throws IOException {
+ read( data, 0, data.length );
+ }
+
+ /**
+ * Read the data from the input stream, starting at the given offset.
+ * @param data placeholder for input data.
+ * @param offset place in the array to start reading in data.
+ * @param length number of ints to read in.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void read( long[] data, int offset, int length ) throws IOException {
+ ByteBuffer readBuffer = ByteBuffer.allocate(bytesPerInteger*length).order(byteOrder);
+
+ targetInputChannel.read(readBuffer,targetInputChannel.position());
+ readBuffer.flip();
+ targetInputChannel.position(targetInputChannel.position()+readBuffer.remaining());
+
+ int i = 0;
+ while(i < length)
+ data[offset+i++] = readBuffer.getInt() & 0xFFFFFFFFL;
+ }
+
+ /**
+ * Closes the given output stream.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void close() throws IOException {
+ targetInputStream.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/UnsignedIntPackedOutputStream.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/UnsignedIntPackedOutputStream.java
new file mode 100644
index 0000000..44c462b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/alignment/reference/packing/UnsignedIntPackedOutputStream.java
@@ -0,0 +1,121 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.alignment.reference.packing;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Writes an list of integers to the output file.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class UnsignedIntPackedOutputStream {
+ /**
+ * Ultimate target for the occurrence array.
+ */
+ private final OutputStream targetOutputStream;
+
+ /**
+ * A fixed-size buffer for int-packed data.
+ */
+ private final ByteBuffer buffer;
+
+ /**
+ * Create a new PackedIntOutputStream, writing to the given target file.
+ * @param outputFile target output file.
+ * @param byteOrder Endianness to use when writing a list of integers.
+ * @throws IOException if an I/O error occurs.
+ */
+ public UnsignedIntPackedOutputStream(File outputFile, ByteOrder byteOrder) throws IOException {
+ this(new FileOutputStream(outputFile),byteOrder);
+ }
+
+ /**
+ * Write packed ints to the given OutputStream.
+ * @param outputStream Output stream to which to write packed ints.
+ * @param byteOrder Endianness to use when writing a list of integers.
+ */
+ public UnsignedIntPackedOutputStream(OutputStream outputStream, ByteOrder byteOrder) {
+ this.targetOutputStream = outputStream;
+ buffer = ByteBuffer.allocate(PackUtils.bitsInType(Integer.class)/PackUtils.BITS_PER_BYTE).order(byteOrder);
+ }
+
+ /**
+ * Write the data to the output stream.
+ * @param datum datum to write.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void write( long datum ) throws IOException {
+ buffer.rewind();
+ buffer.putInt((int)datum);
+ targetOutputStream.write(buffer.array());
+ }
+
+ /**
+ * Write the data to the output stream.
+ * @param data data to write. occurrences.length must match alphabet size.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void write( long[] data ) throws IOException {
+ for(long datum: data)
+ write(datum);
+ }
+
+ /**
+ * Write the given chunk of data to the input stream.
+ * @param data data to write.
+ * @param offset position at which to start.
+ * @param length number of ints to write.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void write( long[] data, int offset, int length ) throws IOException {
+ for( int i = offset; i < offset+length; i++ )
+ write(data[i]);
+ }
+
+ /**
+ * Flush the contents of the OutputStream to disk.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void flush() throws IOException {
+ targetOutputStream.flush();
+ }
+
+ /**
+ * Closes the given output stream.
+ * @throws IOException if an I/O error occurs.
+ */
+ public void close() throws IOException {
+ targetOutputStream.close();
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/DbsnpArgumentCollection.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/DbsnpArgumentCollection.java
new file mode 100644
index 0000000..05ebffa
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/DbsnpArgumentCollection.java
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.arguments;
+
+
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import htsjdk.variant.variantcontext.VariantContext;
+
+/**
+ * @author ebanks
+ * @version 1.0
+ */
+public class DbsnpArgumentCollection {
+
+ /**
+ * A dbSNP VCF file.
+ */
+ @Input(fullName="dbsnp", shortName = "D", doc="dbSNP file", required=false)
+ public RodBinding<VariantContext> dbsnp;
+
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/GATKArgumentCollection.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/GATKArgumentCollection.java
new file mode 100644
index 0000000..05834f7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/GATKArgumentCollection.java
@@ -0,0 +1,628 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.arguments;
+
+import htsjdk.samtools.ValidationStringency;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+import org.broadinstitute.gatk.engine.downsampling.DownsamplingMethod;
+import org.broadinstitute.gatk.engine.phonehome.GATKRunReport;
+import org.broadinstitute.gatk.engine.samples.PedigreeValidationType;
+import org.broadinstitute.gatk.utils.QualityUtils;
+import org.broadinstitute.gatk.utils.baq.BAQ;
+import org.broadinstitute.gatk.utils.variant.GATKVCFIndexType;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author aaron
+ * @version 1.0
+ */
+public class GATKArgumentCollection {
+
+ /** the constructor */
+ public GATKArgumentCollection() {
+ }
+
+ // parameters and their defaults
+ /**
+ * An input file containing sequence data mapped to a reference, in SAM or BAM format, or a text file containing a
+ * list of input files (with extension .list). Note that the GATK requires an accompanying index for each SAM or
+ * BAM file. Please see our online documentation for more details on input formatting requirements.
+ */
+ @Input(fullName = "input_file", shortName = "I", doc = "Input file containing sequence data (SAM or BAM)", required = false)
+ public List<String> samFiles = new ArrayList<>();
+
+ @Hidden
+ @Argument(fullName = "showFullBamList",doc="Emit a log entry (level INFO) containing the full list of sequence data files to be included in the analysis (including files inside .bam.list files).")
+ public Boolean showFullBamList = false;
+
+ @Argument(fullName = "read_buffer_size", shortName = "rbs", doc="Number of reads per SAM file to buffer in memory", required = false, minValue = 0)
+ public Integer readBufferSize = null;
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // GATKRunReport options
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * By default, GATK generates a run report that is uploaded to a cloud-based service. This report contains basic
+ * statistics about the run (which tool was used, whether the run was successful etc.) that help us for debugging
+ * and development. Up to version 3.2-2 the run report contains a record of the username and hostname associated
+ * with the run, but it does **NOT** contain any information that could be used to identify patient data.
+ * Nevertheless, if your data is subject to stringent confidentiality clauses (no outside communication) or if your
+ * run environment is not connected to the internet, you can disable the reporting system by seeting this option to
+ * "NO_ET". You will also need to request a key using the online request form on our website (se FAQs).
+ */
+ @Argument(fullName = "phone_home", shortName = "et", doc="Run reporting mode", required = false)
+ public GATKRunReport.PhoneHomeOption phoneHomeType = GATKRunReport.PhoneHomeOption.AWS;
+ /**
+ * Please see the "phone_home" argument below and the online documentation FAQs for more details on the key system
+ * and how to request a key.
+ */
+ @Argument(fullName = "gatk_key", shortName = "K", doc="GATK key file required to run with -et NO_ET", required = false)
+ public File gatkKeyFile = null;
+
+ /**
+ * The GATKRunReport supports (as of GATK 2.2) tagging GATK runs with an arbitrary tag that can be
+ * used to group together runs during later analysis. One use of this capability is to tag runs as GATK
+ * performance tests, so that the performance of the GATK over time can be assessed from the logs directly.
+ *
+ * Note that the tags do not conform to any ontology, so you are free to use any tags that you might find
+ * meaningful.
+ */
+ @Argument(fullName = "tag", shortName = "tag", doc="Tag to identify this GATK run as part of a group of runs", required = false)
+ public String tag = "NA";
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // General features
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Reads that fail the specified filters will not be used in the analysis. Multiple filters can be specified separately,
+ * e.g. you can do -rf MalformedRead -rf BadCigar and so on. Available read filters are listed in the online tool
+ * documentation. Note that the read name format is e.g. MalformedReadFilter, but at the command line the filter
+ * name should be given without the Filter suffix; e.g. -rf MalformedRead (NOT -rf MalformedReadFilter, which is not
+ * recognized by the program). Note also that some read filters are applied by default for some analysis tools; this
+ * is specified in each tool's documentation. The default filters cannot be disabled.
+ */
+ @Argument(fullName = "read_filter", shortName = "rf", doc = "Filters to apply to reads before analysis", required = false)
+ public final List<String> readFilters = new ArrayList<>();
+
+ @ArgumentCollection
+ public IntervalArgumentCollection intervalArguments = new IntervalArgumentCollection();
+ /**
+ * The reference genome against which the sequence data was mapped. The GATK requires an index file and a dictionary
+ * file accompanying the reference (please see the online documentation FAQs for more details on these files). Although
+ * this argument is indicated as being optional, almost all GATK tools require a reference in order to run.
+ * Note also that while GATK can in theory process genomes from any organism with any number of chromosomes or contigs,
+ * it is not designed to process draft genome assemblies and performance will decrease as the number of contigs in
+ * the reference increases. We strongly discourage the use of unfinished genome assemblies containing more than a few
+ * hundred contigs. Contig numbers in the thousands will most probably cause memory-related crashes.
+ */
+ @Input(fullName = "reference_sequence", shortName = "R", doc = "Reference sequence file", required = false)
+ public File referenceFile = null;
+ /**
+ * If this flag is enabled, the random numbers generated will be different in every run, causing GATK to behave non-deterministically.
+ */
+ @Argument(fullName = "nonDeterministicRandomSeed", shortName = "ndrs", doc = "Use a non-deterministic random seed", required = false)
+ public boolean nonDeterministicRandomSeed = false;
+ /**
+ * To be used in the testing framework where dynamic parallelism can result in differing numbers of calls to the random generator.
+ */
+ @Hidden
+ @Argument(fullName = "disableDithering",doc="Completely eliminates randomized dithering from rank sum tests.")
+ public boolean disableDithering = false;
+ /**
+ * This will truncate the run but without exiting with a failure. By default the value is interpreted in minutes, but this can be changed with the maxRuntimeUnits argument.
+ */
+ @Argument(fullName = "maxRuntime", shortName = "maxRuntime", doc="Stop execution cleanly as soon as maxRuntime has been reached", required = false)
+ public long maxRuntime = GenomeAnalysisEngine.NO_RUNTIME_LIMIT;
+
+ @Argument(fullName = "maxRuntimeUnits", shortName = "maxRuntimeUnits", doc="Unit of time used by maxRuntime", required = false)
+ public TimeUnit maxRuntimeUnits = TimeUnit.MINUTES;
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // Downsampling Arguments
+ //
+ // --------------------------------------------------------------------------------------------------------------
+ /**
+ * There are several ways to downsample reads, i.e. to removed reads from the pile of reads that will be used for analysis.
+ * See the documentation of the individual downsampling options for details on how they work. Note that Many GATK tools
+ * specify a default downsampling type and target, but this behavior can be overridden from command line using the
+ * downsampling arguments.
+ */
+ @Argument(fullName = "downsampling_type", shortName="dt", doc="Type of read downsampling to employ at a given locus", required = false)
+ public DownsampleType downsamplingType = null;
+ /**
+ * Reads will be downsampled so the specified fraction remains; e.g. if you specify -dfrac 0.25, three-quarters of
+ * the reads will be removed, and the remaining one quarter will be used in the analysis. This method of downsampling
+ * is truly unbiased and random. It is typically used to simulate the effect of generating different amounts of
+ * sequence data for a given sample. For example, you can use this in a pilot experiment to evaluate how much target
+ * coverage you need to aim for in order to obtain enough coverage in all loci of interest.
+ */
+ @Argument(fullName = "downsample_to_fraction", shortName = "dfrac", doc = "Fraction of reads to downsample to", required = false, minValue = 0.0, maxValue = 1.0)
+ public Double downsampleFraction = null;
+
+ /**
+ * The principle of this downsampling type is to downsample reads to a given capping threshold coverage. Its purpose is to
+ * get rid of excessive coverage, because above a certain depth, having additional data is not informative and imposes
+ * unreasonable computational costs. The downsampling process takes two different forms depending on the type of
+ * analysis it is used with.
+ *
+ * For locus-based traversals (LocusWalkers like UnifiedGenotyper and ActiveRegionWalkers like HaplotypeCaller),
+ * downsample_to_coverage controls the maximum depth of coverage at each locus. For read-based traversals
+ * (ReadWalkers like BaseRecalibrator), it controls the maximum number of reads sharing the same alignment start
+ * position. For ReadWalkers you will typically need to use much lower dcov values than you would with LocusWalkers
+ * to see an effect. Note that this downsampling option does not produce an unbiased random sampling from all available
+ * reads at each locus: instead, the primary goal of the to-coverage downsampler is to maintain an even representation
+ * of reads from all alignment start positions when removing excess coverage. For a truly unbiased random sampling of
+ * reads, use -dfrac instead. Also note that the coverage target is an approximate goal that is not guaranteed to be
+ * met exactly: the downsampling algorithm will under some circumstances retain slightly more or less coverage than
+ * requested.
+ */
+ @Argument(fullName = "downsample_to_coverage", shortName = "dcov",
+ doc = "Target coverage threshold for downsampling to coverage",
+ required = false, minValue = 0)
+ public Integer downsampleCoverage = null;
+
+ /**
+ * Gets the downsampling method explicitly specified by the user. If the user didn't specify
+ * a default downsampling mechanism, return the default.
+ * @return The explicitly specified downsampling mechanism, or the default if none exists.
+ */
+ public DownsamplingMethod getDownsamplingMethod() {
+ if ( downsamplingType == null && downsampleFraction == null && downsampleCoverage == null )
+ return null;
+
+ return new DownsamplingMethod(downsamplingType, downsampleCoverage, downsampleFraction);
+ }
+
+ /**
+ * Set the downsampling method stored in the argument collection so that it is read back out when interrogating the command line arguments.
+ * @param method The downsampling mechanism.
+ */
+ public void setDownsamplingMethod(DownsamplingMethod method) {
+ if (method == null)
+ throw new IllegalArgumentException("method is null");
+
+ downsamplingType = method.type;
+ downsampleCoverage = method.toCoverage;
+ downsampleFraction = method.toFraction;
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // BAQ arguments
+ //
+ // --------------------------------------------------------------------------------------------------------------
+ @Argument(fullName = "baq", shortName="baq", doc="Type of BAQ calculation to apply in the engine", required = false)
+ public BAQ.CalculationMode BAQMode = BAQ.CalculationMode.OFF;
+ /**
+ * Phred-scaled gap open penalty for BAQ calculation. Although the default value is 40, a value of 30 may be better for whole genome call sets.
+ */
+ @Argument(fullName = "baqGapOpenPenalty", shortName="baqGOP", doc="BAQ gap open penalty", required = false, minValue = 0)
+ public double BAQGOP = BAQ.DEFAULT_GOP;
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // refactor NDN cigar string arguments
+ //
+ // --------------------------------------------------------------------------------------------------------------
+ /**
+ * This flag tells GATK to refactor cigar string with NDN elements to one element. It intended primarily for use in
+ * a RNAseq pipeline since the problem might come up when using RNAseq aligner such as Tophat2 with provided transcriptoms.
+ * You should only use this if you know that your reads have that problem.
+ */
+ @Argument(fullName = "refactor_NDN_cigar_string", shortName = "fixNDN", doc = "refactor cigar string with NDN elements to one element", required = false)
+ public boolean REFACTOR_NDN_CIGAR_READS = false;
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // quality encoding checking arguments
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * By default the GATK assumes that base quality scores start at Q0 == ASCII 33 according to the SAM specification.
+ * However, encoding in some datasets (especially older Illumina ones) starts at Q64. This argument will fix the
+ * encodings on the fly (as the data is read in) by subtracting 31 from every quality score. Note that this argument should
+ * NEVER be used by default; you should only use it when you have confirmed that the quality scores in your data are
+ * not in the correct encoding.
+ */
+ @Argument(fullName = "fix_misencoded_quality_scores", shortName="fixMisencodedQuals", doc="Fix mis-encoded base quality scores", required = false)
+ public boolean FIX_MISENCODED_QUALS = false;
+ /**
+ * This flag tells GATK to ignore warnings when encountering base qualities that are too high and that seemingly
+ * indicate a problem with the base quality encoding of the BAM file. You should only use this if you really know
+ * what you are doing; otherwise you could seriously mess up your data and ruin your analysis.
+ */
+ @Argument(fullName = "allow_potentially_misencoded_quality_scores", shortName="allowPotentiallyMisencodedQuals", doc="Ignore warnings about base quality score encoding", required = false)
+ public boolean ALLOW_POTENTIALLY_MISENCODED_QUALS = false;
+ /**
+ * This flag tells GATK to use the original base qualities (that were in the data before BQSR/recalibration) which
+ * are stored in the OQ tag, if they are present, rather than use the post-recalibration quality scores. If no OQ
+ * tag is present for a read, the standard qual score will be used.
+ */
+ @Argument(fullName="useOriginalQualities", shortName = "OQ", doc = "Use the base quality scores from the OQ tag", required=false)
+ public Boolean useOriginalBaseQualities = false;
+ /**
+ * If reads are missing some or all base quality scores, this value will be used for all base quality scores.
+ * By default this is set to -1 to disable default base quality assignment.
+ */
+ @Argument(fullName="defaultBaseQualities", shortName = "DBQ", doc = "Assign a default base quality", required=false, minValue = 0, maxValue = Byte.MAX_VALUE)
+ public byte defaultBaseQualities = -1;
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // performance log arguments
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * The file name for the GATK performance log output, or null if you don't want to generate the
+ * detailed performance logging table. This table is suitable for importing into R or any
+ * other analysis software that can read tsv files.
+ */
+ @Argument(fullName = "performanceLog", shortName="PF", doc="Write GATK runtime performance log to this file", required = false)
+ public File performanceLog = null;
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // BQSR arguments
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Enables on-the-fly recalibrate of base qualities, intended primarily for use with BaseRecalibrator and PrintReads
+ * (see Best Practices workflow documentation). The covariates tables are produced by the BaseRecalibrator tool.
+ * Please be aware that you should only run recalibration with the covariates file created on the same input bam(s).
+ */
+ @Input(fullName="BQSR", shortName="BQSR", required=false, doc="Input covariates table file for on-the-fly base quality score recalibration")
+ public File BQSR_RECAL_FILE = null;
+
+ /**
+ * Turns on the base quantization module. It requires a recalibration report (-BQSR).
+ *
+ * A value of 0 here means "do not quantize".
+ * Any value greater than zero will be used to recalculate the quantization using that many levels.
+ * Negative values mean that we should quantize using the recalibration report's quantization level.
+ */
+ @Hidden
+ @Argument(fullName="quantize_quals", shortName = "qq", doc = "Quantize quality scores to a given number of levels (with -BQSR)", required=false)
+ public int quantizationLevels = 0;
+
+ /**
+ * Turns off printing of the base insertion and base deletion tags when using the -BQSR argument. Only the base substitution qualities will be produced.
+ */
+ @Argument(fullName="disable_indel_quals", shortName = "DIQ", doc = "Disable printing of base insertion and deletion tags (with -BQSR)", required=false)
+ public boolean disableIndelQuals = false;
+
+ /**
+ * By default, the OQ tag in not emitted when using the -BQSR argument. Use this flag to include OQ tags in the output BAM file.
+ * Note that this may results in significant file size increase.
+ */
+ @Argument(fullName="emit_original_quals", shortName = "EOQ", doc = "Emit the OQ tag with the original base qualities (with -BQSR)", required=false)
+ public boolean emitOriginalQuals = false;
+
+ /**
+ * This flag tells GATK not to modify quality scores less than this value. Instead they will be written out unmodified in the recalibrated BAM file.
+ * In general it's unsafe to change qualities scores below < 6, since base callers use these values to indicate random or bad bases.
+ * For example, Illumina writes Q2 bases when the machine has really gone wrong. This would be fine in and of itself,
+ * but when you select a subset of these reads based on their ability to align to the reference and their dinucleotide effect,
+ * your Q2 bin can be elevated to Q8 or Q10, leading to issues downstream.
+ */
+ @Argument(fullName = "preserve_qscores_less_than", shortName = "preserveQ", doc = "Don't recalibrate bases with quality scores less than this threshold (with -BQSR)", required = false, minValue = 0, minRecommendedValue = QualityUtils.MIN_USABLE_Q_SCORE)
+ public int PRESERVE_QSCORES_LESS_THAN = QualityUtils.MIN_USABLE_Q_SCORE;
+ /**
+ * If specified, this value will be used as the prior for all mismatch quality scores instead of the actual reported quality score.
+ */
+ @Argument(fullName = "globalQScorePrior", shortName = "globalQScorePrior", doc = "Global Qscore Bayesian prior to use for BQSR", required = false)
+ public double globalQScorePrior = -1.0;
+
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // Other utility arguments
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Keep in mind that if you set this to LENIENT, we may refuse to provide you with support if anything goes wrong.
+ */
+ @Argument(fullName = "validation_strictness", shortName = "S", doc = "How strict should we be with validation", required = false)
+ public ValidationStringency strictnessLevel = ValidationStringency.SILENT;
+ /**
+ * Some tools keep program records in the SAM header by default. Use this argument to override that behavior and discard program records for the SAM header.
+ */
+ @Argument(fullName = "remove_program_records", shortName = "rpr", doc = "Remove program records from the SAM header", required = false)
+ public boolean removeProgramRecords = false;
+ /**
+ * Some tools discard program records from the SAM header by default. Use this argument to override that behavior and keep program records in the SAM header.
+ */
+ @Argument(fullName = "keep_program_records", shortName = "kpr", doc = "Keep program records in the SAM header", required = false)
+ public boolean keepProgramRecords = false;
+
+ /**
+ * On-the-fly sample renaming works only with single-sample BAM and VCF files. Each line of the mapping file must
+ * contain the absolute path to a BAM or VCF file, followed by whitespace, followed by the new sample name for that
+ * BAM or VCF file. The sample name may contain non-tab whitespace, but leading or trailing whitespace will be
+ * ignored. The engine will verify at runtime that each BAM/VCF targeted for sample renaming has only a single
+ * sample specified in its header (though, in the case of BAM files, there may be multiple read groups for that
+ * sample).
+ */
+ @Advanced
+ @Argument(fullName = "sample_rename_mapping_file", shortName = "sample_rename_mapping_file", doc = "Rename sample IDs on-the-fly at runtime using the provided mapping file", required = false)
+ public File sampleRenameMappingFile = null;
+
+ /**
+ * For expert users only who know what they are doing. We do not support usage of this argument, so we may refuse to help you if you use it and something goes wrong. The one exception to this rule is ALLOW_N_CIGAR_READS, which is necessary for RNAseq analysis.
+ */
+ @Argument(fullName = "unsafe", shortName = "U", doc = "Enable unsafe operations: nothing will be checked at runtime", required = false)
+ public ValidationExclusion.TYPE unsafe;
+ /**
+ * UNSAFE FOR GENERAL USE (FOR TEST SUITE USE ONLY). Disable both auto-generation of index files and index file locking
+ * when reading VCFs and other rods and an index isn't present or is out-of-date. The file locking necessary for auto index
+ * generation to work safely is prone to random failures/hangs on certain platforms, which makes it desirable to disable it
+ * for situations like test suite runs where the indices are already known to exist, however this option is unsafe in general
+ * because it allows reading from index files without first acquiring a lock.
+ */
+ @Hidden
+ @Advanced
+ @Argument(fullName = "disable_auto_index_creation_and_locking_when_reading_rods", shortName = "disable_auto_index_creation_and_locking_when_reading_rods",
+ doc = "Disable both auto-generation of index files and index file locking",
+ required = false)
+ public boolean disableAutoIndexCreationAndLockingWhenReadingRods = false;
+
+ @Hidden
+ @Argument(fullName = "no_cmdline_in_header", shortName = "no_cmdline_in_header", doc = "Don't output the usual VCF header tag with the command line. FOR DEBUGGING PURPOSES ONLY. This option is required in order to pass integration tests.",
+ required = false)
+ public boolean disableCommandLineInVCF = false;
+
+ @Argument(fullName = "sites_only", shortName = "sites_only", doc = "Just output sites without genotypes (i.e. only the first 8 columns of the VCF)",
+ required = false)
+ public boolean sitesOnlyVCF = false;
+
+ /**
+ * <p>The VCF specification permits missing records to be dropped from the end of FORMAT fields, so long as GT is always output.
+ * This option prevents GATK from performing that trimming.</p>
+ *
+ * <p>For example, given a FORMAT of <pre>GT:AD:DP:PL</pre>, GATK will by default emit <pre>./.</pre> for a variant with
+ * no reads present (ie, the AD, DP, and PL fields are trimmed). If you specify -writeFullFormat, this record
+ * would be emitted as <pre>./.:.:.:.</pre></p>
+ */
+ @Argument(fullName = "never_trim_vcf_format_field", shortName = "writeFullFormat", doc = "Always output all the records in VCF FORMAT fields, even if some are missing",
+ required = false)
+ public boolean neverTrimVCFFormatField = false;
+
+ @Hidden
+ @Argument(fullName = "bcf", shortName = "bcf", doc = "Force BCF output, regardless of the file's extension",
+ required = false)
+ public boolean forceBCFOutput = false;
+
+ @Advanced
+ @Argument(fullName = "bam_compression", shortName = "compress", doc = "Compression level to use for writing BAM files (0 - 9, higher is more compressed)",
+ minValue = 0, maxValue = 9, required = false)
+ public Integer bamCompression = null;
+
+ @Advanced
+ @Argument(fullName = "simplifyBAM", shortName = "simplifyBAM",
+ doc = "If provided, output BAM files will be simplified to include just key reads for downstream variation discovery analyses (removing duplicates, PF-, non-primary reads), as well stripping all extended tags from the kept reads except the read group identifier",
+ required = false)
+ public boolean simplifyBAM = false;
+
+ @Argument(fullName = "disable_bam_indexing", doc = "Turn off on-the-fly creation of indices for output BAM files.",
+ required = false)
+ public boolean disableBAMIndexing = false;
+
+ @Argument(fullName = "generate_md5", doc = "Enable on-the-fly creation of md5s for output BAM files.",
+ required = false)
+ public boolean enableBAMmd5 = false;
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // Multi-threading arguments
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Data threads contains N cpu threads per data thread, and act as completely data parallel processing, increasing
+ * the memory usage of GATK by M data threads. Data threads generally scale extremely effectively, up to 24 cores.
+ * See online documentation FAQs for more information.
+ */
+ @Argument(fullName = "num_threads", shortName = "nt", doc = "Number of data threads to allocate to this analysis", required = false, minValue = 1)
+ public Integer numberOfDataThreads = 1;
+
+ /**
+ * Each CPU thread operates the map cycle independently, but may run into earlier scaling problems with IO than
+ * data threads. Has the benefit of not requiring X times as much memory per thread as data threads do, but rather
+ * only a constant overhead. See online documentation FAQs for more information.
+ */
+ @Argument(fullName="num_cpu_threads_per_data_thread", shortName = "nct", doc="Number of CPU threads to allocate per data thread", required = false, minValue = 1)
+ public int numberOfCPUThreadsPerDataThread = 1;
+
+ @Argument(fullName="num_io_threads", shortName = "nit", doc="Number of given threads to allocate to IO", required = false, minValue = 0)
+ @Hidden
+ public int numberOfIOThreads = 0;
+
+ /**
+ * Enable GATK to monitor its own threading efficiency, at an itsy-bitsy tiny
+ * cost (< 0.1%) in runtime because of turning on the JavaBean. This is largely for
+ * debugging purposes. Note that this argument is not compatible with -nt, it only works with -nct.
+ */
+ @Argument(fullName = "monitorThreadEfficiency", shortName = "mte", doc = "Enable threading efficiency monitoring", required = false)
+ public Boolean monitorThreadEfficiency = false;
+
+ @Argument(fullName = "num_bam_file_handles", shortName = "bfh", doc="Total number of BAM file handles to keep open simultaneously", required=false, minValue = 1)
+ public Integer numberOfBAMFileHandles = null;
+ /**
+ * This will filter out read groups matching <TAG>:<STRING> (e.g. SM:sample1) or a .txt file containing the filter strings one per line.
+ */
+ @Input(fullName = "read_group_black_list", shortName="rgbl", doc="Exclude read groups based on tags", required = false)
+ public List<String> readGroupBlackList = null;
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // PED (pedigree) support
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * <p>Reads PED file-formatted tabular text files describing meta-data about the samples being
+ * processed in the GATK.</p>
+ *
+ * <ul>
+ * <li>see <a href="http://www.broadinstitute.org/mpg/tagger/faq.html">http://www.broadinstitute.org/mpg/tagger/faq.html</a></li>
+ * <li>see <a href="http://pngu.mgh.harvard.edu/~purcell/plink/data.shtml#ped">http://pngu.mgh.harvard.edu/~purcell/plink/data.shtml#ped</a></li>
+ * </ul>
+ *
+ * <p>The PED file is a white-space (space or tab) delimited file: the first six columns are mandatory:</p>
+ *
+ * <ul>
+ * <li>Family ID</li>
+ * <li>Individual ID</li>
+ * <li>Paternal ID</li>
+ * <li>Maternal ID</li>
+ * <li>Sex (1=male; 2=female; other=unknown)</li>
+ * <li>Phenotype</li>
+ * </ul>
+ *
+ * <p>The IDs are alphanumeric: the combination of family and individual ID should uniquely identify a person.
+ * A PED file must have 1 and only 1 phenotype in the sixth column. The phenotype can be either a
+ * quantitative trait or an affection status column: GATK will automatically detect which type
+ * (i.e. based on whether a value other than 0, 1, 2 or the missing genotype code is observed).</p>
+ *
+ * <p>If an individual's sex is unknown, then any character other than 1 or 2 can be used.</p>
+ *
+ * <p>You can add a comment to a PED or MAP file by starting the line with a # character. The rest of that
+ * line will be ignored. Do not start any family IDs with this character therefore.</p>
+ *
+ * <p>Affection status should be coded:</p>
+ *
+ * <ul>
+ * <li>-9 missing</li>
+ * <li>0 missing</li>
+ * <li>1 unaffected</li>
+ * <li>2 affected</li>
+ * </ul>
+ *
+ * <p>If any value outside of -9,0,1,2 is detected than the samples are assumed
+ * to phenotype values are interpreted as string phenotype values. In this case -9 uniquely
+ * represents the missing value.</p>
+ *
+ * <p>Genotypes (column 7 onwards) cannot be specified to the GATK.</p>
+ *
+ * <p>For example, here are two individuals (one row = one person):</p>
+ *
+ * <pre>
+ * FAM001 1 0 0 1 2
+ * FAM001 2 0 0 1 2
+ * </pre>
+ *
+ * <p>Each -ped argument can be tagged with NO_FAMILY_ID, NO_PARENTS, NO_SEX, NO_PHENOTYPE to
+ * tell the GATK PED parser that the corresponding fields are missing from the ped file.</p>
+ *
+ * <p>Note that most GATK walkers do not use pedigree information. Walkers that require pedigree
+ * data should clearly indicate so in their arguments and will throw errors if required pedigree
+ * information is missing.</p>
+ */
+ @Argument(fullName="pedigree", shortName = "ped", doc="Pedigree files for samples",required=false)
+ public List<File> pedigreeFiles = Collections.emptyList();
+
+ /**
+ * Inline PED records (see -ped argument). Each -pedString STRING can contain one or more
+ * valid PED records (see -ped) separated by semi-colons. Supports all tags for each pedString
+ * as -ped supports
+ */
+ @Argument(fullName="pedigreeString", shortName = "pedString", doc="Pedigree string for samples",required=false)
+ public List<String> pedigreeStrings = Collections.emptyList();
+
+ /**
+ * How strict should we be in parsing the PED files?
+ */
+ @Argument(fullName="pedigreeValidationType", shortName = "pedValidationType", doc="Validation strictness for pedigree information",required=false)
+ public PedigreeValidationType pedigreeValidationType = PedigreeValidationType.STRICT;
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // BAM indexing and sharding arguments
+ //
+ // --------------------------------------------------------------------------------------------------------------
+ /**
+ * NO INTEGRATION TESTS are available. Use at your own risk.
+ */
+ @Argument(fullName="allow_intervals_with_unindexed_bam",doc="Allow interval processing with an unsupported BAM",required=false)
+ @Hidden
+ public boolean allowIntervalsWithUnindexedBAM = false;
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // testing BCF2
+ //
+ // --------------------------------------------------------------------------------------------------------------
+ /**
+ * If provided, whenever we create a VCFWriter we will also write out a BCF file alongside it, for testing purposes.
+ */
+ @Argument(fullName="generateShadowBCF",shortName = "generateShadowBCF",doc="Write a BCF copy of the output VCF",required=false)
+ @Hidden
+ public boolean generateShadowBCF = false;
+ // TODO -- remove all code tagged with TODO -- remove me when argument generateShadowBCF is removed
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // VCF/BCF index parameters
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Specify the Tribble indexing strategy to use for VCFs.
+ *
+ * LINEAR creates a LinearIndex with bins of equal width, specified by the Bin Width parameter
+ * INTERVAL creates an IntervalTreeIndex with bins with an equal amount of features, specified by the Features Per Bin parameter
+ * DYNAMIC_SEEK attempts to optimize for minimal seek time by choosing an appropriate strategy and parameter (user-supplied parameter is ignored)
+ * DYNAMIC_SIZE attempts to optimize for minimal index size by choosing an appropriate strategy and parameter (user-supplied parameter is ignored)
+ */
+ @Argument(fullName="variant_index_type",shortName = "variant_index_type",doc="Type of IndexCreator to use for VCF/BCF indices",required=false)
+ @Advanced
+ public GATKVCFIndexType variant_index_type = GATKVCFUtils.DEFAULT_INDEX_TYPE;
+ /**
+ * This is either the bin width or the number of features per bin, depending on the indexing strategy
+ */
+ @Argument(fullName="variant_index_parameter",shortName = "variant_index_parameter",doc="Parameter to pass to the VCF/BCF IndexCreator",required=false)
+ @Advanced
+ public int variant_index_parameter = GATKVCFUtils.DEFAULT_INDEX_PARAMETER;
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/StandardVariantContextInputArgumentCollection.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/StandardVariantContextInputArgumentCollection.java
new file mode 100644
index 0000000..331029f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/StandardVariantContextInputArgumentCollection.java
@@ -0,0 +1,48 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.arguments;
+
+
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import htsjdk.variant.variantcontext.VariantContext;
+
+/**
+ * @author ebanks
+ * @version 1.0
+ */
+public class StandardVariantContextInputArgumentCollection {
+
+ /**
+ * Variants from this VCF file are used by this tool as input.
+ * The file must at least contain the standard VCF header lines, but
+ * can be empty (i.e., no variants are contained in the file).
+ */
+ @Input(fullName="variant", shortName = "V", doc="Input VCF file", required=true)
+ public RodBinding<VariantContext> variants;
+
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/ValidationExclusion.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/ValidationExclusion.java
new file mode 100644
index 0000000..ccd4fdc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/arguments/ValidationExclusion.java
@@ -0,0 +1,67 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.arguments;
+
+import org.broadinstitute.gatk.utils.commandline.EnumerationArgumentDefault;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ValidationExclusion {
+
+ // our validation options
+
+ public enum TYPE {
+ ALLOW_N_CIGAR_READS, // ignore the presence of N operators in CIGARs: do not blow up and process reads that contain one or more N operators.
+ // This exclusion does not have effect on reads that get filtered {@see MalformedReadFilter}.
+ ALLOW_UNINDEXED_BAM, // allow bam files that do not have an index; we'll traverse them using monolithic shard
+ ALLOW_UNSET_BAM_SORT_ORDER, // assume that the bam is sorted, even if the SO (sort-order) flag is not set
+ NO_READ_ORDER_VERIFICATION, // do not validate that the reads are in order as we take them from the bam file
+ ALLOW_SEQ_DICT_INCOMPATIBILITY, // allow dangerous, but not fatal, sequence dictionary incompabilities
+ LENIENT_VCF_PROCESSING, // allow non-standard values for standard VCF header lines. Don't worry about size differences between header and values, etc.
+ @EnumerationArgumentDefault // set the ALL value to the default value, so if they specify just -U, we get the ALL
+ ALL // do not check for all of the above conditions, DEFAULT
+ }
+
+ // a storage for the passed in exclusions
+ List<TYPE> exclusions = new ArrayList<TYPE>();
+
+ public ValidationExclusion(List<TYPE> exclusionsList) {
+ exclusions.addAll(exclusionsList);
+ }
+
+ public ValidationExclusion() {}
+
+ /**
+ * do we contain the exclusion specified, or were we set to ALL
+ * @param t the exclusion case to test for
+ * @return true if we contain the exclusion or if we're set to ALL, false otherwise
+ */
+ public boolean contains(TYPE t) {
+ return (exclusions.contains(TYPE.ALL) || exclusions.contains(t));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/contexts/AlignmentContext.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/contexts/AlignmentContext.java
new file mode 100644
index 0000000..6ac2048
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/contexts/AlignmentContext.java
@@ -0,0 +1,154 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.contexts;
+
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.HasGenomeLocation;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.List;
+
+/**
+ * Useful class for forwarding on locusContext data from this iterator
+ *
+ * Created by IntelliJ IDEA.
+ * User: mdepristo
+ * Date: Feb 22, 2009
+ * Time: 3:01:34 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class AlignmentContext implements HasGenomeLocation {
+ protected GenomeLoc loc = null;
+ protected ReadBackedPileup basePileup = null;
+ protected boolean hasPileupBeenDownsampled;
+
+ /**
+ * The number of bases we've skipped over in the reference since the last map invocation.
+ * Only filled in by RodTraversals right now. By default, nothing is being skipped, so skippedBases == 0.
+ */
+ private long skippedBases = 0;
+
+ public AlignmentContext(GenomeLoc loc, ReadBackedPileup basePileup) {
+ this(loc, basePileup, 0, false);
+ }
+
+ public AlignmentContext(GenomeLoc loc, ReadBackedPileup basePileup, boolean hasPileupBeenDownsampled) {
+ this(loc, basePileup, 0, hasPileupBeenDownsampled);
+ }
+
+ public AlignmentContext(GenomeLoc loc, ReadBackedPileup basePileup, long skippedBases) {
+ this(loc, basePileup, skippedBases, false);
+ }
+
+ public AlignmentContext(GenomeLoc loc, ReadBackedPileup basePileup, long skippedBases,boolean hasPileupBeenDownsampled ) {
+ if ( loc == null ) throw new ReviewedGATKException("BUG: GenomeLoc in Alignment context is null");
+ if ( basePileup == null ) throw new ReviewedGATKException("BUG: ReadBackedPileup in Alignment context is null");
+ if ( skippedBases < 0 ) throw new ReviewedGATKException("BUG: skippedBases is -1 in Alignment context");
+
+ this.loc = loc;
+ this.basePileup = basePileup;
+ this.skippedBases = skippedBases;
+ this.hasPileupBeenDownsampled = hasPileupBeenDownsampled;
+ }
+
+ /** Returns base pileup over the current genomic location. Deprectated. Use getBasePileup() to make your intentions
+ * clear.
+ * @return
+ */
+ @Deprecated
+ public ReadBackedPileup getPileup() { return basePileup; }
+
+ /** Returns base pileup over the current genomic location. May return null if this context keeps only
+ * extended event (indel) pileup.
+ * @return
+ */
+ public ReadBackedPileup getBasePileup() {
+ return basePileup;
+ }
+
+ /**
+ * Returns true if any reads have been filtered out of the pileup due to excess DoC.
+ * @return True if reads have been filtered out. False otherwise.
+ */
+ public boolean hasPileupBeenDownsampled() { return hasPileupBeenDownsampled; }
+
+ /**
+ * get all of the reads within this context
+ *
+ * @return
+ */
+ @Deprecated
+ //todo: unsafe and tailored for current usage only; both pileups can be null or worse, bot can be not null in theory
+ public List<GATKSAMRecord> getReads() { return ( basePileup.getReads() ); }
+
+ /**
+ * Are there any reads associated with this locus?
+ *
+ * @return
+ */
+ public boolean hasReads() {
+ return basePileup != null && basePileup.getNumberOfElements() > 0 ;
+ }
+
+ /**
+ * How many reads cover this locus?
+ * @return
+ */
+ public int size() {
+ return basePileup.getNumberOfElements();
+ }
+
+ /**
+ * get a list of the equivalent positions within in the reads at Pos
+ *
+ * @return
+ */
+ @Deprecated
+ public List<Integer> getOffsets() {
+ return basePileup.getOffsets();
+ }
+
+ public String getContig() { return getLocation().getContig(); }
+ public long getPosition() { return getLocation().getStart(); }
+ public GenomeLoc getLocation() { return loc; }
+
+ public void downsampleToCoverage(int coverage) {
+ basePileup = basePileup.getDownsampledPileup(coverage);
+ hasPileupBeenDownsampled = true;
+ }
+
+ /**
+ * Returns the number of bases we've skipped over in the reference since the last map invocation.
+ * Only filled in by RodTraversals right now. A value of 0 indicates that no bases were skipped.
+ *
+ * @return the number of skipped bases
+ */
+ public long getSkippedBases() {
+ return skippedBases;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/contexts/AlignmentContextUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/contexts/AlignmentContextUtils.java
new file mode 100644
index 0000000..afeb1e7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/contexts/AlignmentContextUtils.java
@@ -0,0 +1,150 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.contexts;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.pileup.*;
+
+import java.util.*;
+
+/**
+ * Useful utilities for storing different AlignmentContexts
+ * User: ebanks
+ */
+public class AlignmentContextUtils {
+
+ // Definitions:
+ // COMPLETE = full alignment context
+ // FORWARD = reads on forward strand
+ // REVERSE = reads on forward strand
+ //
+ public enum ReadOrientation { COMPLETE, FORWARD, REVERSE }
+
+ private AlignmentContextUtils() {
+ // cannot be instantiated
+ }
+
+ /**
+ * Returns a potentially derived subcontext containing only forward, reverse, or in fact all reads
+ * in alignment context context.
+ *
+ * @param context
+ * @param type
+ * @return
+ */
+ public static AlignmentContext stratify(AlignmentContext context, ReadOrientation type) {
+ switch(type) {
+ case COMPLETE:
+ return context;
+ case FORWARD:
+ return new AlignmentContext(context.getLocation(),context.getPileup().getPositiveStrandPileup());
+ case REVERSE:
+ return new AlignmentContext(context.getLocation(),context.getPileup().getNegativeStrandPileup());
+ default:
+ throw new ReviewedGATKException("Unable to get alignment context for type = " + type);
+ }
+ }
+
+ public static Map<String, AlignmentContext> splitContextBySampleName(AlignmentContext context) {
+ return splitContextBySampleName(context, null);
+ }
+
+ /**
+ * Splits the given AlignmentContext into a StratifiedAlignmentContext per sample, but referencd by sample name instead
+ * of sample object.
+ *
+ * @param context the original pileup
+ *
+ * @return a Map of sample name to StratifiedAlignmentContext
+ *
+ **/
+ public static Map<String, AlignmentContext> splitContextBySampleName(AlignmentContext context, String assumedSingleSample) {
+ GenomeLoc loc = context.getLocation();
+ HashMap<String, AlignmentContext> contexts = new HashMap<String, AlignmentContext>();
+
+ for(String sample: context.getPileup().getSamples()) {
+ ReadBackedPileup pileupBySample = context.getPileup().getPileupForSample(sample);
+
+ // Don't add empty pileups to the split context.
+ if(pileupBySample.getNumberOfElements() == 0)
+ continue;
+
+ if(sample != null)
+ contexts.put(sample, new AlignmentContext(loc, pileupBySample));
+ else {
+ if(assumedSingleSample == null) {
+ throw new UserException.ReadMissingReadGroup(pileupBySample.iterator().next().getRead());
+ }
+ contexts.put(assumedSingleSample,new AlignmentContext(loc, pileupBySample));
+ }
+ }
+
+ return contexts;
+ }
+
+ /**
+ * Splits the AlignmentContext into one context per read group
+ *
+ * @param context the original pileup
+ * @return a Map of ReadGroup to AlignmentContext, or an empty map if context has no base pileup
+ *
+ **/
+ public static Map<SAMReadGroupRecord, AlignmentContext> splitContextByReadGroup(AlignmentContext context, Collection<SAMReadGroupRecord> readGroups) {
+ HashMap<SAMReadGroupRecord, AlignmentContext> contexts = new HashMap<SAMReadGroupRecord, AlignmentContext>();
+
+ for (SAMReadGroupRecord rg : readGroups) {
+ ReadBackedPileup rgPileup = context.getBasePileup().getPileupForReadGroup(rg.getReadGroupId());
+ if ( rgPileup != null ) // there we some reads for RG
+ contexts.put(rg, new AlignmentContext(context.getLocation(), rgPileup));
+ }
+
+ return contexts;
+ }
+
+ public static Map<String, AlignmentContext> splitContextBySampleName(ReadBackedPileup pileup) {
+ return splitContextBySampleName(new AlignmentContext(pileup.getLocation(), pileup));
+ }
+
+
+ public static AlignmentContext joinContexts(Collection<AlignmentContext> contexts) {
+ // validation
+ GenomeLoc loc = contexts.iterator().next().getLocation();
+ for(AlignmentContext context: contexts) {
+ if(!loc.equals(context.getLocation()))
+ throw new ReviewedGATKException("Illegal attempt to join contexts from different genomic locations");
+ }
+
+ List<PileupElement> pe = new ArrayList<PileupElement>();
+ for(AlignmentContext context: contexts) {
+ for(PileupElement pileupElement: context.basePileup)
+ pe.add(pileupElement);
+ }
+ return new AlignmentContext(loc, new ReadBackedPileupImpl(loc,pe));
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/contexts/ReferenceContext.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/contexts/ReferenceContext.java
new file mode 100644
index 0000000..201ea49
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/contexts/ReferenceContext.java
@@ -0,0 +1,217 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.contexts;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+/**
+ * The section of the reference that overlaps with the given
+ * read / locus.
+ *
+ * @author hanna
+ * @version 0.1
+ */
+public class ReferenceContext {
+ /**
+ * Facilitates creation of new GenomeLocs.
+ */
+ final private GenomeLocParser genomeLocParser;
+
+ /**
+ * The locus.
+ */
+ final private GenomeLoc locus;
+
+ /**
+ * The window of reference information around the current locus.
+ */
+ final private GenomeLoc window;
+
+ /**
+ * The bases in the window around the current locus. If null, then bases haven't been fetched yet.
+ * Bases are always upper cased
+ */
+ private byte[] basesCache = null;
+
+ /**
+ * Lazy loader to fetch reference bases
+ */
+ final private ReferenceContextRefProvider basesProvider;
+
+ /**
+ * Interface to create byte[] contexts for lazy loading of the reference
+ */
+ public static interface ReferenceContextRefProvider {
+ /**
+ * You must provide a routine that gets the byte[] bases that would have been passed into the
+ * ReferenceContext. The RC will handling caching. The value of this interface and routine is
+ * that it is only called when the bytes are actually requested by the walker, not up front. So
+ * if the walker doesn't need the refBases for whatever reason, there's no overhead to
+ * provide them.
+ *
+ * @return
+ */
+ @Ensures({"result != null"})
+ public byte[] getBases();
+ }
+
+ private static class ForwardingProvider implements ReferenceContextRefProvider {
+ byte[] bases;
+
+ public ForwardingProvider( byte base ) {
+ this(new byte[] { base });
+ }
+
+ public ForwardingProvider( byte[] bases ) {
+ this.bases = bases;
+ }
+
+ public byte[] getBases() { return bases; }
+ }
+
+ /**
+ * Contructor for a simple, windowless reference context.
+ * @param locus locus of interest.
+ * @param base reference base at that locus.
+ */
+ @Requires({
+ "genomeLocParser != null",
+ "locus != null",
+ "locus.size() > 0"})
+ public ReferenceContext( GenomeLocParser genomeLocParser, GenomeLoc locus, byte base ) {
+ this( genomeLocParser, locus, locus, new ForwardingProvider(base) );
+ }
+
+ @Requires({
+ "genomeLocParser != null",
+ "locus != null",
+ "locus.size() > 0",
+ "window != null",
+ "window.size() > 0",
+ "bases != null && bases.length > 0"})
+ public ReferenceContext( GenomeLocParser genomeLocParser, GenomeLoc locus, GenomeLoc window, byte[] bases ) {
+ this( genomeLocParser, locus, window, new ForwardingProvider(bases) );
+ }
+
+ @Requires({
+ "genomeLocParser != null",
+ "locus != null",
+ "locus.size() > 0",
+ "window != null",
+ "window.size() > 0",
+ "basesProvider != null"})
+ public ReferenceContext( GenomeLocParser genomeLocParser, GenomeLoc locus, GenomeLoc window, ReferenceContextRefProvider basesProvider ) {
+ this.genomeLocParser = genomeLocParser;
+ this.locus = locus;
+ this.window = window;
+ this.basesProvider = basesProvider;
+ }
+
+ /**
+ * Utility function to load bases from the provider to the cache, if necessary
+ */
+ @Ensures({
+ "basesCache != null",
+ "old(basesCache) == null || old(basesCache) == basesCache"})
+ private void fetchBasesFromProvider() {
+ if ( basesCache == null ) {
+ basesCache = basesProvider.getBases();
+
+ // must be an assertion that only runs when the bases are fetch to run in a reasonable amount of time
+ assert BaseUtils.isUpperCase(basesCache);
+ }
+ }
+
+ /**
+ * @return The genome loc parser associated with this reference context
+ */
+ @Ensures("result != null")
+ public GenomeLocParser getGenomeLocParser() {
+ return genomeLocParser;
+ }
+
+ /**
+ * The locus currently being examined.
+ * @return The current locus.
+ */
+ @Ensures("result != null")
+ public GenomeLoc getLocus() {
+ return locus;
+ }
+
+ @Ensures("result != null")
+ public GenomeLoc getWindow() {
+ return window;
+ }
+
+ /**
+ * Get the base at the given locus.
+ * @return The base at the given locus from the reference.
+ */
+ public byte getBase() {
+ return getBases()[(locus.getStart() - window.getStart())];
+ }
+
+ /**
+ * All the bases in the window currently being examined.
+ * @return All bases available. If the window is of size [0,0], the array will
+ * contain only the base at the given locus.
+ */
+ @Ensures({"result != null", "result.length > 0"})
+ public byte[] getBases() {
+ fetchBasesFromProvider();
+ return basesCache;
+ }
+
+ /**
+ * All the bases in the window from the current base forward to the end of the window.
+ */
+ @Ensures({"result != null", "result.length > 0"})
+ public byte[] getForwardBases() {
+ final byte[] bases = getBases();
+ final int mid = locus.getStart() - window.getStart();
+ // todo -- warning of performance problem, especially if this is called over and over
+ return new String(bases).substring(mid).getBytes();
+ }
+
+ @Deprecated
+ public char getBaseAsChar() {
+ return (char)getBase();
+ }
+
+ /**
+ * Get the base at the given locus.
+ * @return The base at the given locus from the reference.
+ */
+ @Deprecated()
+ public int getBaseIndex() {
+ return BaseUtils.simpleBaseToBaseIndex(getBase());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/package-info.java
new file mode 100644
index 0000000..680da25
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/AllLocusView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/AllLocusView.java
new file mode 100644
index 0000000..56ecce2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/AllLocusView.java
@@ -0,0 +1,169 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.iterators.GenomeLocusIterator;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileupImpl;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
+/**
+ * User: hanna
+ * Date: May 13, 2009
+ * Time: 3:32:30 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * A LocusView over which the user can iterate.
+ */
+
+public class AllLocusView extends LocusView {
+ private GenomeLocusIterator locusIterator;
+
+ /**
+ * Gets the next position in the view: next call to next() will jump there.
+ * Note that both nextPosition and nextLocus are PRE-read and cached.
+ */
+ private GenomeLoc nextPosition = null;
+
+ /**
+ * What's the next available context?
+ */
+ private AlignmentContext nextLocus = null;
+
+ /**
+ * Signal not to advance the iterator because we're currently sitting at the next element.
+ */
+ private boolean atNextElement = false;
+
+ /**
+ * Create a new queue of locus contexts.
+ *
+ * @param provider
+ */
+ public AllLocusView(LocusShardDataProvider provider) {
+ super(provider);
+ // Seed the state tracking members with the first possible seek position and the first possible locus context.
+ locusIterator = new GenomeLocusIterator(genomeLocParser, provider.getLocus());
+ }
+
+ public boolean hasNext() {
+ advance();
+ return nextPosition != null;
+ }
+
+ public AlignmentContext next() {
+ advance();
+
+ if (nextPosition == null)
+ throw new NoSuchElementException("No next is available in the all locus view");
+
+ // Flag to the iterator that no data is waiting in the queue to be processed.
+ atNextElement = false;
+
+ AlignmentContext currentLocus;
+
+ // If actual data is present, return it. Otherwise, return empty data.
+ if (nextLocus != null && nextLocus.getLocation().equals(nextPosition))
+ currentLocus = nextLocus;
+ else
+ currentLocus = createEmptyLocus(nextPosition);
+
+ return currentLocus;
+ }
+
+ private void advance() {
+ // Already at the next element? Don't move forward.
+ if (atNextElement)
+ return;
+
+ // Out of elements?
+ if (nextPosition == null && !locusIterator.hasNext())
+ return;
+
+ // If nextLocus has been consumed, clear it out to make room for the next incoming locus.
+ if (nextPosition != null && nextLocus != null && !nextLocus.getLocation().isPast(nextPosition)) {
+ nextLocus = null;
+
+ // Determine the next locus. The trick is that we may have more than one alignment context at the same
+ // reference position (regular base pileup, then extended pileup). If next alignment context (that we just pre-read)
+ // is still at the current position, we do not increment current position and wait for next call to next() to return
+ // that context. If we know that next context is past the current position, we are done with current
+ // position
+ if (hasNextLocus()) {
+ nextLocus = nextLocus();
+ if (nextPosition.equals(nextLocus.getLocation())) {
+ atNextElement = true;
+ return;
+ }
+ }
+ }
+
+ // No elements left in queue? Clear out the position state tracker and return.
+ if (!locusIterator.hasNext()) {
+ nextPosition = null;
+ return;
+ }
+
+ // Actually fill the next position.
+ nextPosition = locusIterator.next();
+ atNextElement = true;
+
+ // Crank the iterator to (if possible) or past the next context. Be careful not to hold a reference to nextLocus
+ // while using the hasNextLocus() / nextLocus() machinery; this will cause us to use more memory than is optimal.
+ while (nextLocus == null || nextLocus.getLocation().isBefore(nextPosition)) {
+ nextLocus = null;
+ if (!hasNextLocus())
+ break;
+ nextLocus = nextLocus();
+ }
+ }
+
+ /**
+ * Creates a blank locus context at the specified location.
+ *
+ * @param site Site at which to create the blank locus context.
+ * @return empty context.
+ */
+ private final static List<GATKSAMRecord> EMPTY_PILEUP_READS = Collections.emptyList();
+ private final static List<Integer> EMPTY_PILEUP_OFFSETS = Collections.emptyList();
+ private final static List<Boolean> EMPTY_DELETION_STATUS = Collections.emptyList();
+
+ private AlignmentContext createEmptyLocus(GenomeLoc site) {
+ return new AlignmentContext(site, new ReadBackedPileupImpl(site, EMPTY_PILEUP_READS, EMPTY_PILEUP_OFFSETS));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/CoveredLocusView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/CoveredLocusView.java
new file mode 100644
index 0000000..900612a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/CoveredLocusView.java
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+/**
+ * User: hanna
+ * Date: May 12, 2009
+ * Time: 11:24:42 AM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * A queue of locus contexts. Provides unidirectional seek. Stripped down
+ * implementation of java.util.Queue interface.
+ */
+
+public class CoveredLocusView extends LocusView {
+ /**
+ * Create a new queue of locus contexts.
+ * @param provider
+ */
+ public CoveredLocusView(LocusShardDataProvider provider) {
+ super(provider);
+ }
+
+ public boolean hasNext() {
+ return hasNextLocus();
+ }
+
+ public AlignmentContext next() {
+ return nextLocus();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/IntervalOverlappingRODsFromStream.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/IntervalOverlappingRODsFromStream.java
new file mode 100644
index 0000000..9100905
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/IntervalOverlappingRODsFromStream.java
@@ -0,0 +1,168 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.util.PeekableIterator;
+import org.broadinstitute.gatk.engine.refdata.RODRecordListImpl;
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+/**
+ * Key algorithmic helper for ReadBasedReferenceOrderedData
+ *
+ * Takes a single iterator of features, and provides a single capability that returns
+ * the list of RODs that overlap an interval. Allows sequential getOverlapping calls
+ * from intervals provided that these intervals always have increasing getStart() values.
+ *
+ */
+class IntervalOverlappingRODsFromStream {
+ /**
+ * Only held for QC purposes
+ */
+ GenomeLoc lastQuery = null;
+
+ private final String name;
+ private final LinkedList<GATKFeature> currentFeatures = new LinkedList<GATKFeature>();
+ private final PeekableIterator<RODRecordList> futureFeatures;
+
+ /**
+ * Create a new IntervalOverlappingRODsFromStream that reads elements from futureFeatures and
+ * returns RODRecordLists having name
+ *
+ * @param name
+ * @param futureFeatures
+ */
+ IntervalOverlappingRODsFromStream(final String name, final PeekableIterator<RODRecordList> futureFeatures) {
+ if ( futureFeatures == null ) throw new IllegalArgumentException("futureFeatures cannot be null");
+
+ this.name = name;
+ this.futureFeatures = futureFeatures;
+ }
+
+ /**
+ * Get the list of RODs overlapping loc from this stream of RODs.
+ *
+ * @param loc the interval to query
+ * @return a non-null RODRecordList containing the overlapping RODs, which may be empty
+ */
+ @Ensures({"overlaps(loc, result)",
+ "! futureFeatures.hasNext() || futureFeatures.peek().getLocation().isPast(loc)",
+ "result != null"})
+ public RODRecordList getOverlapping(final GenomeLoc loc) {
+ if ( lastQuery != null && loc.getStart() < lastQuery.getStart() )
+ throw new IllegalArgumentException(String.format("BUG: query interval (%s) starts before the previous interval %s", loc, lastQuery));
+
+ readOverlappingFutureFeatures(loc);
+ return new RODRecordListImpl(name, subsetToOverlapping(loc, currentFeatures), loc);
+ }
+
+
+ /**
+ * For contract assurance. Checks that all bindings in loc overlap
+ *
+ * @param loc
+ * @param bindings
+ * @return
+ */
+ @Requires({"loc != null", "bindings != null"})
+ private boolean overlaps(final GenomeLoc loc, final RODRecordList bindings) {
+ for ( final GATKFeature feature : bindings )
+ if ( ! feature.getLocation().overlapsP(loc) )
+ return false;
+ return true;
+ }
+
+ /**
+ * Subset the features in all to those that overlap with loc
+ *
+ * The current features list contains everything read that cannot be thrown away yet, but not
+ * everything in there necessarily overlaps with loc. Subset to just those that do overlap
+ *
+ * @param loc the location that features must overlap
+ * @param all the list of all features
+ * @return a subset of all that overlaps with loc
+ */
+ @Requires({"loc != null", "all != null"})
+ @Ensures("result.size() <= all.size()")
+ private Collection<GATKFeature> subsetToOverlapping(final GenomeLoc loc, final Collection<GATKFeature> all) {
+ final LinkedList<GATKFeature> overlapping = new LinkedList<GATKFeature>();
+ for ( final GATKFeature feature : all )
+ if ( feature.getLocation().overlapsP(loc) )
+ overlapping.add(feature);
+ return overlapping;
+ }
+
+ /**
+ * Update function. Remove all elements of currentFeatures that end before loc
+ *
+ * Must be called by clients periodically when they know they they will never ask for data before
+ * loc, so that the running cache of RODs doesn't grow out of control.
+ *
+ * @param loc the location to use
+ */
+ @Requires("loc != null")
+ @Ensures("currentFeatures.size() <= old(currentFeatures.size())")
+ public void trimCurrentFeaturesToLoc(final GenomeLoc loc) {
+ final ListIterator<GATKFeature> it = currentFeatures.listIterator();
+ while ( it.hasNext() ) {
+ final GATKFeature feature = it.next();
+ if ( feature.getLocation().isBefore(loc) )
+ it.remove();
+ }
+ }
+
+ /**
+ * Update function: Read all elements from futureFeatures that overlap with loc
+ *
+ * Stops at the first element that starts before the end of loc, or the stream empties
+ *
+ * @param loc
+ */
+ @Requires("loc != null")
+ @Ensures("currentFeatures.size() >= old(currentFeatures.size())")
+ private void readOverlappingFutureFeatures(final GenomeLoc loc) {
+ while ( futureFeatures.hasNext() ) {
+ final GenomeLoc nextLoc = futureFeatures.peek().getLocation();
+ if ( nextLoc.isBefore(loc) ) {
+ futureFeatures.next(); // next rod element is before loc, throw it away and keep looking
+ } else if ( nextLoc.isPast(loc) ) {
+ break; // next element is past loc, stop looking but don't pop it
+ } else if ( nextLoc.overlapsP(loc) ) {
+ // add overlapping elements to our current features, removing from stream
+ for ( final GATKFeature feature : futureFeatures.next() ) {
+ currentFeatures.add(feature);
+ }
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/IntervalReferenceOrderedView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/IntervalReferenceOrderedView.java
new file mode 100644
index 0000000..23f4f73
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/IntervalReferenceOrderedView.java
@@ -0,0 +1,184 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.samtools.util.PeekableIterator;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.datasources.reads.ReadShard;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.refdata.utils.LocationAwareSeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * a ROD view that allows for requests for RODs that overlap intervals on the genome to produce a RefMetaDataTracker
+ */
+public class IntervalReferenceOrderedView implements ReferenceOrderedView {
+ /** a list of the RMDDataState (location->iterators) */
+ private final List<RMDDataState> states = new ArrayList<>(1);
+
+ /**
+ * Used to get genome locs for reads
+ */
+ protected final GenomeLocParser genomeLocParser;
+
+ /**
+ * The total extent of all reads in this span. We create iterators from our RODs
+ * from the start of this span, to the end.
+ */
+ private final GenomeLoc shardSpan;
+
+ /**
+ * Create a new IntervalReferenceOrderedView taking data from provider and capable of
+ * servicing ROD overlap requests within the genomic interval span
+ *
+ * @param provider a ShardDataProvider to give us data
+ * @param span a GenomeLoc span, or null indicating take the entire genome
+ */
+ public IntervalReferenceOrderedView(final ShardDataProvider provider, final GenomeLoc span) {
+ if ( provider == null ) throw new IllegalArgumentException("provider cannot be null");
+ if ( provider.hasReferenceOrderedData() && span == null ) throw new IllegalArgumentException("span cannot be null when provider has reference ordered data");
+
+ this.genomeLocParser = provider.getGenomeLocParser();
+ this.shardSpan = span;
+ provider.register(this);
+
+ // conditional to optimize the case where we don't have any ROD data
+ if ( provider.hasReferenceOrderedData() && ! shardSpan.isUnmapped() ) {
+ for (final ReferenceOrderedDataSource dataSource : provider.getReferenceOrderedData())
+ states.add(new RMDDataState(dataSource, dataSource.seek(shardSpan)));
+ }
+ }
+
+ /**
+ * Testing constructor
+ */
+ protected IntervalReferenceOrderedView(final GenomeLocParser genomeLocParser,
+ final GenomeLoc shardSpan,
+ final List<String> names,
+ final List<PeekableIterator<RODRecordList>> featureSources) {
+ this.genomeLocParser = genomeLocParser;
+ this.shardSpan = shardSpan;
+ for ( int i = 0; i < names.size(); i++ )
+ states.add(new RMDDataState(names.get(i), featureSources.get(i)));
+ }
+
+ public Collection<Class<? extends View>> getConflictingViews() {
+ List<Class<? extends View>> classes = new ArrayList<>();
+ classes.add(ManagingReferenceOrderedView.class);
+ return classes;
+ }
+
+ /**
+ * Get a RefMetaDataTracker containing bindings for all RODs overlapping the start position of loc
+ * @param loc a GenomeLoc of size == 1
+ * @return a non-null RefMetaDataTracker
+ */
+ @Override
+ public RefMetaDataTracker getReferenceOrderedDataAtLocus(GenomeLoc loc) {
+ if ( loc == null ) throw new IllegalArgumentException("loc cannot be null");
+ if ( loc.size() != 1 ) throw new IllegalArgumentException("GenomeLoc must have size == 1 but got " + loc);
+ return getReferenceOrderedDataForInterval(loc);
+ }
+
+ /**
+ * Get a RefMetaDataTracker containing bindings for all RODs overlapping interval
+ *
+ * @param interval a non=null interval
+ * @return a non-null RefMetaDataTracker
+ */
+ public RefMetaDataTracker getReferenceOrderedDataForInterval(final GenomeLoc interval) {
+ if ( interval == null ) throw new IllegalArgumentException("Interval cannot be null");
+
+ if ( states.isEmpty() || shardSpan.isUnmapped() ) // optimization for no bindings (common for read walkers)
+ return RefMetaDataTracker.EMPTY_TRACKER;
+ else {
+ final List<RODRecordList> bindings = new ArrayList<>(states.size());
+ for ( final RMDDataState state : states )
+ bindings.add(state.stream.getOverlapping(interval));
+ return new RefMetaDataTracker(bindings);
+ }
+ }
+
+ /**
+ * Trim down all of the ROD managers so that they only hold ROD bindings wit start >= startOfDataToKeep.getStart()
+ *
+ * @param startOfDataToKeep a non-null genome loc
+ */
+ public void trimCurrentFeaturesToLoc(final GenomeLoc startOfDataToKeep) {
+ if ( startOfDataToKeep == null ) throw new IllegalArgumentException("startOfDataToKeep cannot be null");
+
+ for ( final RMDDataState state : states )
+ state.stream.trimCurrentFeaturesToLoc(startOfDataToKeep);
+ }
+
+ /**
+ * Closes the current view.
+ */
+ public void close() {
+ for (final RMDDataState state : states)
+ state.close();
+
+ // Clear out the existing data so that post-close() accesses to this data will fail-fast.
+ states.clear();
+ }
+
+ /**
+ * Models the traversal state of a given ROD lane.
+ */
+ private static class RMDDataState {
+ public final ReferenceOrderedDataSource dataSource;
+ public final IntervalOverlappingRODsFromStream stream;
+ private final LocationAwareSeekableRODIterator iterator;
+
+ public RMDDataState(ReferenceOrderedDataSource dataSource, LocationAwareSeekableRODIterator iterator) {
+ this.dataSource = dataSource;
+ this.iterator = iterator;
+ this.stream = new IntervalOverlappingRODsFromStream(dataSource.getName(), new PeekableIterator<>(iterator));
+ }
+
+ /**
+ * For testing
+ */
+ public RMDDataState(final String name, final PeekableIterator<RODRecordList> iterator) {
+ this.dataSource = null;
+ this.iterator = null;
+ this.stream = new IntervalOverlappingRODsFromStream(name, new PeekableIterator<>(iterator));
+ }
+
+ public void close() {
+ if ( dataSource != null )
+ dataSource.close( iterator );
+ }
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/InvalidPositionException.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/InvalidPositionException.java
new file mode 100644
index 0000000..997435d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/InvalidPositionException.java
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: hanna
+ * Date: Apr 16, 2009
+ * Time: 4:11:40 PM
+ *
+ * Thrown to indicate invalid positions passed to the providers.
+ * Extend from RuntimeException to make it easier on our walker writers; don't make
+ * them catch every exception that comes their way.
+ */
+public class InvalidPositionException extends RuntimeException {
+ public InvalidPositionException(String message) {
+ super(message);
+ }
+
+ public InvalidPositionException(String message, Throwable throwable) {
+ super(message,throwable);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/LocusReferenceView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/LocusReferenceView.java
new file mode 100644
index 0000000..b535050
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/LocusReferenceView.java
@@ -0,0 +1,236 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.samtools.reference.ReferenceSequence;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.walkers.Reference;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.engine.walkers.Window;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Provides access to the portion of the reference covering a single locus.
+ */
+public class LocusReferenceView extends ReferenceView {
+ /**
+ * Bound the reference view to make sure all accesses are within the shard.
+ */
+ private GenomeLoc bounds;
+
+ /**
+ * Start of the expanded window for which the reference context should be provided,
+ * relative to the locus in question.
+ */
+ private final int windowStart;
+
+
+ /**
+ * Start of the expanded window for which the reference context should be provided,
+ * relative to the locus in question.
+ */
+ private final int windowStop;
+
+ /**
+ * Track the reference sequence and the last point accessed. Used to
+ * track state when traversing over the reference.
+ */
+ private ReferenceSequence referenceSequence;
+
+ /**
+ * Create a LocusReferenceView given no other contextual information about
+ * the walkers, etc.
+ * @param provider source for locus data.
+ */
+ public LocusReferenceView( LocusShardDataProvider provider ) {
+ super(provider);
+ initializeBounds(provider);
+ windowStart = windowStop = 0;
+ initializeReferenceSequence(bounds);
+ }
+
+ /**
+ * Create a new locus reference view.
+ * @param provider source for locus data.
+ */
+ public LocusReferenceView( Walker walker, LocusShardDataProvider provider ) {
+ super( provider );
+ initializeBounds(provider);
+
+ // Retrieve information about the window being accessed.
+ if( walker.getClass().isAnnotationPresent(Reference.class) ) {
+ Window window = walker.getClass().getAnnotation(Reference.class).window();
+
+ if( window.start() > 0 ) throw new ReviewedGATKException( "Reference window starts after current locus" );
+ if( window.stop() < 0 ) throw new ReviewedGATKException( "Reference window ends before current locus" );
+
+ windowStart = window.start();
+ windowStop = window.stop();
+ }
+ else {
+ windowStart = 0;
+ windowStop = 0;
+ }
+
+ if(bounds != null) {
+ int expandedStart = getWindowStart( bounds );
+ int expandedStop = getWindowStop( bounds );
+ initializeReferenceSequence(genomeLocParser.createGenomeLoc(bounds.getContig(), bounds.getContigIndex(), expandedStart, expandedStop));
+ }
+ }
+
+ /**
+ * Initialize the bounds of this shard, trimming the bounds so that they match the reference.
+ * @param provider Provider covering the appropriate locus.
+ */
+ private void initializeBounds(LocusShardDataProvider provider) {
+ if(provider.getLocus() != null) {
+ int sequenceLength = reference.getSequenceDictionary().getSequence(provider.getLocus().getContig()).getSequenceLength();
+ bounds = genomeLocParser.createGenomeLoc(provider.getLocus().getContig(),
+ Math.max(provider.getLocus().getStart(),1),
+ Math.min(provider.getLocus().getStop(),sequenceLength));
+ }
+ else
+ bounds = null;
+ }
+
+ /**
+ * Initialize reference sequence data using the given locus.
+ * @param locus
+ */
+ private void initializeReferenceSequence( GenomeLoc locus ) {
+ this.referenceSequence = reference.getSubsequenceAt( locus.getContig(), locus.getStart(), locus.getStop() );
+ }
+
+ protected GenomeLoc trimToBounds(GenomeLoc l) {
+ int expandedStart = getWindowStart( bounds );
+ int expandedStop = getWindowStop( bounds );
+ if ( l.getStart() < expandedStart ) l = genomeLocParser.setStart(l, expandedStart);
+ if ( l.getStop() > expandedStop ) l = genomeLocParser.setStop(l, expandedStop);
+ return l;
+ }
+
+ public class Provider implements ReferenceContext.ReferenceContextRefProvider {
+ int refStart, len;
+
+ public Provider( int refStart, int len ) {
+ this.refStart = refStart;
+ this.len = len;
+ }
+
+ public byte[] getBases() {
+ //System.out.printf("Getting bases for location%n");
+ byte[] bases = new byte[len];
+ System.arraycopy(referenceSequence.getBases(), refStart, bases, 0, len);
+ return bases;
+ }
+ }
+
+ /**
+ * Gets the reference context associated with this particular point or extended interval on the genome.
+ * @param genomeLoc Region for which to retrieve the base(s). If region spans beyond contig end or beyond current bounds, it will be trimmed down.
+ * @return The base at the position represented by this genomeLoc.
+ */
+ public ReferenceContext getReferenceContext( GenomeLoc genomeLoc ) {
+ //validateLocation( genomeLoc );
+
+ GenomeLoc window = genomeLocParser.createGenomeLoc( genomeLoc.getContig(), genomeLoc.getContigIndex(),
+ getWindowStart(genomeLoc), getWindowStop(genomeLoc) );
+
+ int refStart = -1;
+ if (bounds != null) {
+ window = trimToBounds(window);
+ refStart = (int)(window.getStart() - getWindowStart(bounds));
+ }
+ else {
+ if(referenceSequence == null || referenceSequence.getContigIndex() != genomeLoc.getContigIndex())
+ referenceSequence = reference.getSequence(genomeLoc.getContig());
+ refStart = (int)window.getStart()-1;
+ }
+
+ int len = (int)window.size();
+ return new ReferenceContext( genomeLocParser, genomeLoc, window, new Provider(refStart, len));
+ }
+
+ /**
+ * Allow the user to pull reference info from any arbitrary region of the reference.
+ * @param genomeLoc The locus.
+ * @return A list of the bases starting at the start of the locus (inclusive) and ending
+ * at the end of the locus (inclusive).
+ */
+ public byte[] getReferenceBases( GenomeLoc genomeLoc ) {
+ return super.getReferenceBases(genomeLoc);
+ }
+
+ /**
+ * Gets the start of the expanded window, bounded if necessary by the contig.
+ * @param locus The locus to expand.
+ * @return The expanded window.
+ */
+ private int getWindowStart( GenomeLoc locus ) {
+ // If the locus is not within the bounds of the contig it allegedly maps to, expand only as much as we can.
+ if(locus.getStart() < 1) return 1;
+// if(locus.getStart() < 1) return locus.getStart();
+ return Math.max( locus.getStart() + windowStart, 1 );
+ }
+
+ /**
+ * Gets the stop of the expanded window, bounded if necessary by the contig.
+ * @param locus The locus to expand.
+ * @return The expanded window.
+ */
+ private int getWindowStop( GenomeLoc locus ) {
+ // If the locus is not within the bounds of the contig it allegedly maps to, expand only as much as we can.
+ int sequenceLength = reference.getSequenceDictionary().getSequence(locus.getContig()).getSequenceLength();
+ if(locus.getStop() > sequenceLength) return sequenceLength;
+ return Math.min( locus.getStop() + windowStop, sequenceLength );
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/LocusShardDataProvider.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/LocusShardDataProvider.java
new file mode 100644
index 0000000..7dc589d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/LocusShardDataProvider.java
@@ -0,0 +1,100 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.broadinstitute.gatk.engine.ReadProperties;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.utils.locusiterator.LocusIterator;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+import java.util.Collection;
+
+/**
+ * Presents data sharded by locus to the traversal engine.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class LocusShardDataProvider extends ShardDataProvider {
+ /**
+ * Information about the source of the read data.
+ */
+ private final ReadProperties sourceInfo;
+
+ /**
+ * The particular locus for which data is provided. Should be contained within shard.getGenomeLocs().
+ */
+ private final GenomeLoc locus;
+
+ /**
+ * The raw collection of reads.
+ */
+ private final LocusIterator locusIterator;
+
+ /**
+ * Create a data provider for the shard given the reads and reference.
+ * @param shard The chunk of data over which traversals happen.
+ * @param reference A getter for a section of the reference.
+ */
+ public LocusShardDataProvider(Shard shard, ReadProperties sourceInfo, GenomeLocParser genomeLocParser, GenomeLoc locus, LocusIterator locusIterator, IndexedFastaSequenceFile reference, Collection<ReferenceOrderedDataSource> rods) {
+ super(shard,genomeLocParser,reference,rods);
+ this.sourceInfo = sourceInfo;
+ this.locus = locus;
+ this.locusIterator = locusIterator;
+ }
+
+ /**
+ * Returns information about the source of the reads.
+ * @return Info about the source of the reads.
+ */
+ public ReadProperties getSourceInfo() {
+ return sourceInfo;
+ }
+
+ /**
+ * Gets the locus associated with this shard data provider.
+ * @return The locus.
+ */
+ public GenomeLoc getLocus() {
+ return locus;
+ }
+
+ /**
+ * Gets an iterator over all the reads bound by this shard.
+ * @return An iterator over all reads in this shard.
+ */
+ public LocusIterator getLocusIterator() {
+ return locusIterator;
+ }
+
+ @Override
+ public void close() {
+ super.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/LocusView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/LocusView.java
new file mode 100644
index 0000000..9bc37e5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/LocusView.java
@@ -0,0 +1,220 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+import org.broadinstitute.gatk.engine.ReadProperties;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.utils.locusiterator.LocusIterator;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.locusiterator.LocusIteratorByState;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+/**
+ * User: hanna
+ * Date: May 13, 2009
+ * Time: 3:30:16 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * The two goals of the LocusView are as follows:
+ * 1) To provide a 'trigger track' iteration interface so that TraverseLoci can easily switch
+ * between iterating over all bases in a region, only covered bases in a region covered by
+ * reads, only bases in a region covered by RODs, or any other sort of trigger track
+ * implementation one can think of.
+ * 2) To manage the copious number of iterators that have to be jointly pulled through the
+ * genome to make a locus traversal function.
+ */
+public abstract class LocusView extends LocusIterator implements View {
+ /**
+ * The locus bounding this view.
+ */
+ protected GenomeLoc locus;
+
+ /**
+ * The GenomeLocParser, used to create new genome locs.
+ */
+ protected GenomeLocParser genomeLocParser;
+
+ /**
+ * Source info for this view. Informs the class about downsampling requirements.
+ */
+ private ReadProperties sourceInfo;
+
+ /**
+ * The actual locus context iterator.
+ */
+ private LocusIterator loci;
+
+ /**
+ * The next locus context from the iterator. Lazy loaded: if nextLocus is null and advance() doesn't
+ * populate it, the iterator is exhausted. If populated, this is the value that should be returned by
+ * next().
+ */
+ private AlignmentContext nextLocus = null;
+
+ public LocusView(LocusShardDataProvider provider) {
+ this.locus = provider.getLocus();
+
+ this.sourceInfo = provider.getSourceInfo();
+ this.genomeLocParser = provider.getGenomeLocParser();
+ this.loci = provider.getLocusIterator();
+
+ advance();
+
+ provider.register(this);
+ }
+
+ /**
+ * Only one view of the locus is supported at any given time.
+ * @return A list consisting of all other locus views.
+ */
+ public Collection<Class<? extends View>> getConflictingViews() {
+ return Arrays.<Class<? extends View>>asList(LocusView.class,ReadView.class);
+ }
+
+ /**
+ * Close this view.
+ */
+ public void close() {
+ // Set everything to null with the hope of failing fast.
+ locus = null;
+ sourceInfo = null;
+ loci = null;
+
+ super.close();
+ }
+
+ /**
+ * Is there another covered locus context bounded by this view.
+ * @return True if another covered locus context exists. False otherwise.
+ */
+ public abstract boolean hasNext();
+
+ /**
+ * Returns the next covered locus context in the shard.
+ * @return Next covered locus context in the shard.
+ * @throw NoSuchElementException if no such element exists.
+ */
+ public abstract AlignmentContext next();
+
+ /**
+ * Unsupported.
+ * @throw UnsupportedOperationException always.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("Unable to remove elements from this queue.");
+ }
+
+ /**
+ * Is there another locus context bounded by this shard.
+ * @return True if another locus context is bounded by this shard.
+ */
+ protected boolean hasNextLocus() {
+ advance();
+ return nextLocus != null;
+ }
+
+ /**
+ * Get the next locus context bounded by this shard.
+ * @return Next locus context bounded by this shard.
+ * @throw NoSuchElementException if the next element is missing.
+ */
+ protected AlignmentContext nextLocus() {
+ advance();
+ if(nextLocus == null)
+ throw new NoSuchElementException("No more elements remain in locus context queue.");
+
+ // Cache the current and apply filtering.
+ AlignmentContext current = nextLocus;
+
+ // Indicate that the next operation will need to advance.
+ nextLocus = null;
+
+ return current;
+ }
+
+ /**
+ * Seed the nextLocus variable with the contents of the next locus (if one exists).
+ */
+ private void advance() {
+ // Already an unclaimed locus present
+ if(nextLocus != null)
+ return;
+
+ //System.out.printf("loci is %s%n", loci);
+ if( !loci.hasNext() ) {
+ nextLocus = null;
+ return;
+ }
+
+ nextLocus = loci.next();
+
+ // If the location of this shard is available, trim the data stream to match the shard.
+ // TODO: Much of this functionality is being replaced by the WindowMaker.
+ if(locus != null) {
+ // Iterate through any elements not contained within this shard.
+ while( nextLocus != null && !isContainedInShard(nextLocus.getLocation()) && loci.hasNext() )
+ nextLocus = loci.next();
+
+ // If nothing in the shard was found, indicate that by setting nextLocus to null.
+ if( nextLocus != null && !isContainedInShard(nextLocus.getLocation()) )
+ nextLocus = null;
+ }
+ }
+
+ /**
+ * Is this location contained in the given shard.
+ * @param location Location to check.
+ * @return True if the given location is contained within the shard. False otherwise.
+ */
+ private boolean isContainedInShard(GenomeLoc location) {
+ return locus.containsP(location);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Since this class has an actual LIBS, so this function will never throw an exception
+ *
+ * @return the LocusIteratorByState used by this view to get pileups
+ */
+ @Override
+ public LocusIteratorByState getLIBS() {
+ return loci.getLIBS();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ManagingReferenceOrderedView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ManagingReferenceOrderedView.java
new file mode 100644
index 0000000..2dd42c1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ManagingReferenceOrderedView.java
@@ -0,0 +1,117 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.refdata.utils.LocationAwareSeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+/**
+ * User: hanna
+ * Date: May 21, 2009
+ * Time: 2:49:17 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * A view into the reference-ordered data in the provider.
+ */
+public class ManagingReferenceOrderedView implements ReferenceOrderedView {
+ /**
+ * The data sources along with their current states.
+ */
+ private List<ReferenceOrderedDataState> states = new ArrayList<ReferenceOrderedDataState>();
+
+ /**
+ * Create a new view of reference-ordered data.
+ * @param provider
+ */
+ public ManagingReferenceOrderedView( LocusShardDataProvider provider ) {
+ for( ReferenceOrderedDataSource dataSource: provider.getReferenceOrderedData() )
+ states.add(new ReferenceOrderedDataState(dataSource, dataSource.seek(provider.getLocus())));
+
+ provider.register(this);
+ }
+
+ public Collection<Class<? extends View>> getConflictingViews() { return Collections.emptyList(); }
+
+ /**
+ * Gets an object which can track the reference-ordered data at every locus.
+ * @param loc Locus at which to track.
+ * @return A tracker containing information about this locus.
+ */
+ @Override
+ public RefMetaDataTracker getReferenceOrderedDataAtLocus( GenomeLoc loc ) {
+ if ( states.isEmpty() )
+ return RefMetaDataTracker.EMPTY_TRACKER;
+ else {
+ List<RODRecordList> bindings = new ArrayList<RODRecordList>(states.size());
+
+ for ( ReferenceOrderedDataState state: states )
+ // todo -- warning, I removed the reference to the name from states
+ bindings.add( state.iterator.seekForward(loc) );
+
+ return new RefMetaDataTracker(bindings);
+ }
+ }
+
+ /**
+ * Closes the current view.
+ */
+ public void close() {
+ for( ReferenceOrderedDataState state: states )
+ state.dataSource.close( state.iterator );
+
+ // Clear out the existing data so that post-close() accesses to this data will fail-fast.
+ states = null;
+ }
+}
+
+/**
+ * Models the traversal state of a given ROD lane.
+ */
+class ReferenceOrderedDataState {
+ public final ReferenceOrderedDataSource dataSource;
+ public final LocationAwareSeekableRODIterator iterator;
+
+ public ReferenceOrderedDataState( ReferenceOrderedDataSource dataSource, LocationAwareSeekableRODIterator iterator ) {
+ this.dataSource = dataSource;
+ this.iterator = iterator;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/RODMetaDataContainer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/RODMetaDataContainer.java
new file mode 100644
index 0000000..f244e50
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/RODMetaDataContainer.java
@@ -0,0 +1,83 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.utils.collections.Pair;
+
+import java.util.*;
+
+
+/**
+ *
+ * @author aaron
+ *
+ * Class RODMetaDataContainer
+ *
+ * stores both the name and the class for each ROD. This class assumes that:
+ *
+ * -Names must be unique
+ * -Classes are allowed to have duplicates
+ *
+ * This class encapsulates the ref data associations, and provides lookup by name and by
+ * class type.
+ *
+ */
+public class RODMetaDataContainer {
+ // we only allow non-duplicate ROD names, a HashMap is fine
+ private final HashMap<String, GATKFeature> nameMap = new HashMap<String, GATKFeature>();
+
+ // we do allow duplicate class entries, so we need to store pairs of data
+ private final List<Pair<Class, GATKFeature>> classMap = new ArrayList<Pair<Class, GATKFeature>>();
+
+ public void addEntry(GATKFeature data) {
+ nameMap.put(data.getName(),data);
+ classMap.add(new Pair<Class, GATKFeature>(data.getClass(),data));
+ }
+
+ public Collection<GATKFeature> getSet(String name) {
+ if (name == null) return getSet();
+ Set<GATKFeature> set = new HashSet<GATKFeature>();
+ if (nameMap.containsKey(name)) set.add(nameMap.get(name));
+ return set;
+ }
+
+ /**
+ * get the feature contents of this container; the unfiltered set without their name association
+ * @return
+ */
+ public Collection<GATKFeature> getSet() {
+ return new ArrayList<GATKFeature>(nameMap.values());
+ }
+
+ // the brute force (n) search ended up being faster than sorting and binary search in all but the most extreme cases (thousands of RODs at a location).
+ public Collection<GATKFeature> getSet(Class cls) {
+ Collection<GATKFeature> ret = new ArrayList<GATKFeature>();
+ for (Pair<Class, GATKFeature> pair: classMap)
+ if (pair.first.equals(cls)) ret.add(pair.second);
+ return ret;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadBasedReferenceOrderedView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadBasedReferenceOrderedView.java
new file mode 100644
index 0000000..1d73501
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadBasedReferenceOrderedView.java
@@ -0,0 +1,69 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.util.PeekableIterator;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.datasources.reads.ReadShard;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.refdata.utils.LocationAwareSeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/** a ROD view for reads. This provides the Read traversals a way of getting a RefMetaDataTracker */
+public class ReadBasedReferenceOrderedView extends IntervalReferenceOrderedView {
+ public ReadBasedReferenceOrderedView(final ShardDataProvider provider) {
+ super(provider, provider.hasReferenceOrderedData() ? ((ReadShard)provider.getShard()).getReadsSpan() : null);
+ }
+
+ /**
+ * create a RefMetaDataTracker given the current read
+ *
+ * @param rec the read
+ *
+ * @return a RefMetaDataTracker for the read, from which you can get ROD -> read alignments
+ */
+ @Requires("rec != null")
+ @Ensures("result != null")
+ public RefMetaDataTracker getReferenceOrderedDataForRead(final SAMRecord rec) {
+ if ( rec.getReadUnmappedFlag() )
+ return RefMetaDataTracker.EMPTY_TRACKER;
+ else {
+ final GenomeLoc readSpan = genomeLocParser.createGenomeLoc(rec);
+ trimCurrentFeaturesToLoc(readSpan);
+ return getReferenceOrderedDataForInterval(readSpan);
+ }
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadReferenceView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadReferenceView.java
new file mode 100644
index 0000000..14d5827
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadReferenceView.java
@@ -0,0 +1,102 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * User: hanna
+ * Date: May 22, 2009
+ * Time: 12:36:14 PM
+ *
+ */
+
+/** Provides access to the reference over a single read. */
+
+public class ReadReferenceView extends ReferenceView {
+ /**
+ * Create a view of the reference with respect to a single read.
+ *
+ * @param provider
+ */
+ public ReadReferenceView( ShardDataProvider provider ) {
+ super(provider);
+ }
+
+ protected ReferenceContext.ReferenceContextRefProvider getReferenceBasesProvider( GenomeLoc genomeLoc ) {
+ return new Provider(genomeLoc);
+ }
+
+ public class Provider implements ReferenceContext.ReferenceContextRefProvider {
+ GenomeLoc loc;
+
+ public Provider( GenomeLoc loc ) {
+ this.loc = loc;
+ }
+
+ public byte[] getBases() {
+ return getReferenceBases(loc);
+ }
+ }
+
+ /**
+ * Return a reference context appropriate for the span of read
+ *
+ * @param read the mapped read to test
+ * @return
+ */
+ public ReferenceContext getReferenceContext( final SAMRecord read ) {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc(read);
+ return new ReferenceContext( genomeLocParser, loc, loc, getReferenceBasesProvider(loc) );
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadShardDataProvider.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadShardDataProvider.java
new file mode 100644
index 0000000..8acfad0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadShardDataProvider.java
@@ -0,0 +1,82 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+import java.util.Collection;
+
+/**
+ * Present data sharded by read to a traversal engine.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class ReadShardDataProvider extends ShardDataProvider {
+ /**
+ * The raw collection of reads.
+ */
+ private final GATKSAMIterator reads;
+
+ /**
+ * Create a data provider for the shard given the reads and reference.
+ * @param shard The chunk of data over which traversals happen.
+ * @param reference A getter for a section of the reference.
+ */
+ public ReadShardDataProvider(Shard shard, GenomeLocParser genomeLocParser, GATKSAMIterator reads, IndexedFastaSequenceFile reference, Collection<ReferenceOrderedDataSource> rods) {
+ super(shard,genomeLocParser,reference,rods);
+ this.reads = reads;
+ }
+
+ /**
+ * Can this data source provide reads?
+ * @return True if reads are available, false otherwise.
+ */
+ public boolean hasReads() {
+ return reads != null;
+ }
+
+ /**
+ * Gets an iterator over all the reads bound by this shard.
+ * @return An iterator over all reads in this shard.
+ */
+ public GATKSAMIterator getReadIterator() {
+ return reads;
+ }
+
+ @Override
+ public void close() {
+ super.close();
+
+ if(reads != null)
+ reads.close();
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadView.java
new file mode 100644
index 0000000..160dbd5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReadView.java
@@ -0,0 +1,88 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+
+import java.util.Arrays;
+import java.util.Collection;
+/**
+ * User: hanna
+ * Date: May 22, 2009
+ * Time: 12:06:54 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * A view into the reads that a provider can provide.
+ */
+public class ReadView implements View, Iterable<SAMRecord> {
+ /**
+ * The iterator into the reads supplied by this provider.
+ */
+ private GATKSAMIterator reads;
+
+ /**
+ * Create a new view of the reads given the current data set.
+ * @param provider Source for the data.
+ */
+ public ReadView( ReadShardDataProvider provider ) {
+ reads = provider.getReadIterator();
+ }
+
+ /**
+ * Other reads and loci conflict with this view.
+ * @return Array of reads and loci.
+ */
+ public Collection<Class<? extends View>> getConflictingViews() {
+ return Arrays.<Class<? extends View>>asList(ReadView.class, LocusView.class);
+ }
+
+ /**
+ * Close the view over these reads. Note that this method closes just
+ * the view into the reads, not the reads themselves.
+ */
+ public void close() {
+ // Don't close the reads. The provider is responsible for this.
+ // Just dispose of the pointer.
+ reads = null;
+ }
+
+ /**
+ * Gets an iterator into the reads supplied by this provider.
+ * @return Iterator into the reads that this provider covers.
+ */
+ public GATKSAMIterator iterator() {
+ return reads;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceOrderedView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceOrderedView.java
new file mode 100644
index 0000000..9f3db51
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceOrderedView.java
@@ -0,0 +1,33 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+
+public interface ReferenceOrderedView extends View {
+ RefMetaDataTracker getReferenceOrderedDataAtLocus( GenomeLoc loc );
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceView.java
new file mode 100644
index 0000000..2eade15
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceView.java
@@ -0,0 +1,131 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequence;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+/**
+ * User: hanna
+ * Date: May 22, 2009
+ * Time: 12:19:17 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * A view into the reference backing this shard.
+ */
+public class ReferenceView implements View {
+ /**
+ * The parser, used to create and parse GenomeLocs.
+ */
+ protected final GenomeLocParser genomeLocParser;
+
+ /**
+ * The source of reference data.
+ */
+ protected IndexedFastaSequenceFile reference = null;
+
+ /**
+ * Create a new ReferenceView.
+ * @param provider
+ */
+ public ReferenceView( ShardDataProvider provider ) {
+ this.genomeLocParser = provider.getGenomeLocParser();
+ this.reference = provider.getReference();
+ }
+
+ /**
+ * Reference views don't conflict with anything else.
+ * @return Empty list.
+ */
+ public Collection<Class<? extends View>> getConflictingViews() { return Collections.emptyList(); }
+
+ /**
+ * Deinitialize pointers for fast fail. Someone else will handle file management.
+ */
+ public void close() {
+ reference = null;
+ }
+
+ /**
+ * Allow the user to pull reference info from any arbitrary region of the reference.
+ * If parts of the reference don't exist, mark them in the char array with 'X'es.
+ * @param genomeLoc The locus.
+ * @return A list of the bases starting at the start of the locus (inclusive) and ending
+ * at the end of the locus (inclusive).
+ */
+ final static int BUFFER = 10000;
+ final static byte[] Xs = new byte[BUFFER];
+ static {
+ Arrays.fill(Xs, (byte)'X');
+ }
+
+ protected byte[] getReferenceBases( SAMRecord read ) {
+ return getReferenceBases(genomeLocParser.createGenomeLoc(read));
+
+ }
+
+ protected byte[] getReferenceBases( GenomeLoc genomeLoc ) {
+ SAMSequenceRecord sequenceInfo = reference.getSequenceDictionary().getSequence(genomeLoc.getContig());
+
+ long start = genomeLoc.getStart();
+ long stop = Math.min( genomeLoc.getStop(), sequenceInfo.getSequenceLength() );
+
+ // Read with no aligned bases? Return an empty array.
+ if(stop - start + 1 == 0)
+ return new byte[0];
+
+ ReferenceSequence subsequence = reference.getSubsequenceAt(genomeLoc.getContig(), start, stop);
+
+ int overhang = (int)(genomeLoc.getStop() - stop);
+ if ( overhang > 0 ) {
+ if ( overhang > BUFFER ) // todo -- this is a bit dangerous
+ throw new ReviewedGATKException("Insufficient buffer size for Xs overhanging genome -- expand BUFFER");
+ byte[] all = new byte[subsequence.getBases().length + overhang];
+ System.arraycopy(subsequence.getBases(), 0, all, 0, subsequence.getBases().length);
+ System.arraycopy(Xs, 0, all, subsequence.getBases().length, overhang);
+ return all;
+ } else {
+ // fast path
+ return subsequence.getBases();
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/RodLocusView.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/RodLocusView.java
new file mode 100644
index 0000000..21cb3ef
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/RodLocusView.java
@@ -0,0 +1,197 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.refdata.utils.LocationAwareSeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.collections.RODMergingIterator;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileupImpl;
+
+import java.util.*;
+
+/**
+ * A view into the reference-ordered data in the provider.
+ */
+public class RodLocusView extends LocusView implements ReferenceOrderedView {
+ /**
+ * The data sources along with their current states.
+ */
+ private RODMergingIterator rodQueue = null;
+
+ Collection<RODRecordList> allTracksHere;
+
+ GenomeLoc lastLoc = null;
+ RODRecordList interval = null;
+
+ /**
+ * The data sources along with their current states.
+ */
+ private List<ReferenceOrderedDataState> states = new ArrayList<ReferenceOrderedDataState>();
+
+ /**
+ * Enable debugging output -- todo remove me
+ */
+ final static boolean DEBUG = false;
+
+ final static String INTERVAL_ROD_NAME = "interval";
+
+ /**
+ * Create a new view of reference-ordered data.
+ *
+ * @param provider
+ */
+ public RodLocusView( LocusShardDataProvider provider ) {
+ super(provider);
+
+ GenomeLoc loc = provider.getLocus();
+
+ List< Iterator<RODRecordList> > iterators = new LinkedList< Iterator<RODRecordList> >();
+ for( ReferenceOrderedDataSource dataSource: provider.getReferenceOrderedData() ) {
+ if ( DEBUG ) System.out.printf("Shard is %s%n", provider.getLocus());
+
+ // grab the ROD iterator from the data source, and compute the first location in this shard, forwarding
+ // the iterator to immediately before it, so that it can be added to the merging iterator primed for
+ // next() to return the first real ROD in this shard
+ LocationAwareSeekableRODIterator it = dataSource.seek(provider.getLocus());
+ it.seekForward(genomeLocParser.createGenomeLoc(loc.getContig(), loc.getStart()-1));
+
+ states.add(new ReferenceOrderedDataState(dataSource,it));
+
+ // we need to special case the interval so we don't always think there's a rod at the first location
+ if ( dataSource.getName().equals(INTERVAL_ROD_NAME) ) {
+ if ( interval != null )
+ throw new RuntimeException("BUG: interval local variable already assigned " + interval);
+ interval = it.next();
+ } else {
+ iterators.add( it );
+ }
+ }
+
+ rodQueue = new RODMergingIterator(iterators);
+ }
+
+ @Override
+ public RefMetaDataTracker getReferenceOrderedDataAtLocus( GenomeLoc loc ) {
+ // special case the interval again -- add it into the ROD
+ if ( interval != null ) { allTracksHere.add(interval); }
+ return new RefMetaDataTracker(allTracksHere);
+ }
+
+ public boolean hasNext() {
+ if ( ! rodQueue.hasNext() )
+ return false;
+ else {
+ return ! rodQueue.peekLocation().isPast(locus);
+ }
+ }
+
+ /**
+ * Returns the next covered locus context in the shard.
+ * @return Next covered locus context in the shard.
+ * @throw NoSuchElementException if no such element exists.
+ */
+ public AlignmentContext next() {
+ if ( DEBUG ) System.out.printf("In RodLocusView.next()...%n");
+ RODRecordList datum = rodQueue.next();
+ if ( DEBUG ) System.out.printf("In RodLocusView.next(); datum = %s...%n", datum.getLocation());
+
+ if ( DEBUG ) System.out.printf("In RodLocusView.next(): creating tracker...%n");
+
+ allTracksHere = getSpanningTracks(datum);
+ GenomeLoc rodSite = datum.getLocation();
+ GenomeLoc site = genomeLocParser.createGenomeLoc( rodSite.getContig(), rodSite.getStart(), rodSite.getStart());
+
+ if ( DEBUG ) System.out.printf("rodLocusView.next() is at %s%n", site);
+
+ // calculate the number of skipped bases, and update lastLoc so we can do that again in the next()
+ long skippedBases = getSkippedBases( rodSite );
+ lastLoc = site;
+ return new AlignmentContext(site, new ReadBackedPileupImpl(site), skippedBases);
+ }
+
+ private Collection<RODRecordList> getSpanningTracks(RODRecordList marker) {
+ return rodQueue.allElementsLTE(marker);
+ }
+
+ /**
+ * Returns the number of reference bases that have been skipped:
+ *
+ * 1 -- since the last processed location if we have one
+ * 2 -- from the beginning of the shard if this is the first loc
+ * 3 -- from the last location to the current position
+ *
+ * @param currentPos
+ * @return
+ */
+ private long getSkippedBases( GenomeLoc currentPos ) {
+ // the minus - is because if lastLoc == null, you haven't yet seen anything in this interval, so it should also be counted as skipped
+ Integer compStop = lastLoc == null ? locus.getStart() - 1 : lastLoc.getStop();
+ long skippedBases = currentPos.getStart() - compStop - 1;
+
+ if ( skippedBases < -1 ) { // minus 1 value is ok
+ throw new RuntimeException(String.format("BUG: skipped bases=%d is < 0: cur=%s vs. last=%s, shard=%s",
+ skippedBases, currentPos, lastLoc, locus));
+ }
+ return Math.max(skippedBases, 0);
+ }
+
+ /**
+ * Get the location one after the last position we will traverse through
+ * @return
+ */
+ public GenomeLoc getLocOneBeyondShard() {
+ return genomeLocParser.createGenomeLoc(locus.getContig(),locus.getStop()+1);
+ }
+
+ /**
+ * How many bases are we skipping from the current location to the end of the interval / shard
+ * if we have no more elements
+ *
+ * @return
+ */
+ public long getLastSkippedBases() {
+ if ( hasNext() )
+ throw new RuntimeException("BUG: getLastSkippedBases called when there are elements remaining.");
+
+ return getSkippedBases(getLocOneBeyondShard());
+ }
+
+ /**
+ * Closes the current view.
+ */
+ public void close() {
+ for( ReferenceOrderedDataState state: states )
+ state.dataSource.close( state.iterator );
+
+ rodQueue = null;
+ allTracksHere = null;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ShardDataProvider.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ShardDataProvider.java
new file mode 100644
index 0000000..a36bee5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/ShardDataProvider.java
@@ -0,0 +1,197 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+/**
+ * User: hanna
+ * Date: May 8, 2009
+ * Time: 3:09:57 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * An umbrella class that examines the data passed to the microscheduler and
+ * tries to assemble as much as possible with it.
+ */
+public abstract class ShardDataProvider {
+ /**
+ * An ArrayList of all the views that are examining this data.
+ */
+ private List<View> registeredViews = new ArrayList<View>();
+
+ /**
+ * The shard over which we're providing data.
+ */
+ private final Shard shard;
+
+ /**
+ * The parser, used to create and build new GenomeLocs.
+ */
+ private final GenomeLocParser genomeLocParser;
+
+ /**
+ * Provider of reference data for this particular shard.
+ */
+ private final IndexedFastaSequenceFile reference;
+
+ /**
+ * Sources of reference-ordered data.
+ */
+ private final Collection<ReferenceOrderedDataSource> referenceOrderedData;
+
+ /**
+ * Returns the GenomeLocParser associated with this traversal.
+ * @return The associated parser.
+ */
+ public GenomeLocParser getGenomeLocParser() {
+ return genomeLocParser;
+ }
+
+ /**
+ * Retrieves the shard associated with this data provider.
+ * @return The shard associated with this data provider.
+ */
+ public Shard getShard() {
+ return shard;
+ }
+
+ /**
+ * Can this data source provide reference information?
+ * @return True if possible, false otherwise.
+ */
+ public boolean hasReference() {
+ return reference != null;
+ }
+
+
+ /**
+ * Gets a pointer into the given indexed fasta sequence file.
+ * @return The indexed fasta sequence file.
+ */
+ IndexedFastaSequenceFile getReference() {
+ return reference;
+ }
+
+ /**
+ * Gets a window into the reference-ordered data. Package protected so that only
+ * views can access it.
+ * @return List of reference-ordered data sources.
+ */
+ Collection<ReferenceOrderedDataSource> getReferenceOrderedData() {
+ return referenceOrderedData;
+ }
+
+ /**
+ * @return true if reference ordered data will be provided by this shard
+ */
+ public boolean hasReferenceOrderedData() {
+ return ! getReferenceOrderedData().isEmpty();
+ }
+
+ /**
+ * Create a data provider for the shard given the reads and reference.
+ * @param shard The chunk of data over which traversals happen.
+ * @param reference A getter for a section of the reference.
+ */
+ public ShardDataProvider(Shard shard,GenomeLocParser genomeLocParser,IndexedFastaSequenceFile reference,Collection<ReferenceOrderedDataSource> rods) {
+ this.shard = shard;
+ this.genomeLocParser = genomeLocParser;
+ this.reference = reference;
+ this.referenceOrderedData = rods;
+ }
+
+ /**
+ * Skeletal, package protected constructor for unit tests which require a ShardDataProvider.
+ * @param shard the shard
+ */
+ ShardDataProvider(Shard shard,GenomeLocParser genomeLocParser) {
+ this(shard,genomeLocParser,null,null);
+ }
+
+ /**
+ * Register this view with the shard provider, and make sure it has no conflicts with any other views.
+ * @param view The new view.
+ */
+ void register( View view ) {
+ // Check all registered classes to see whether a conflict exists.
+ for( View registeredView: registeredViews ) {
+ Collection<Class<? extends View>> conflicts = registeredView.getConflictingViews();
+ for( Class<? extends View> conflict: conflicts ) {
+ if( conflict.isInstance(view) )
+ throw new ReviewedGATKException(String.format("Tried to register two conflicting views: %s and %s",
+ registeredView.getClass().getSimpleName(),
+ view.getClass().getSimpleName()));
+ }
+ }
+
+ // Check whether this class has any objection to any other classes.
+ for( Class<? extends View> conflict: view.getConflictingViews() ) {
+ for( View registeredView: registeredViews ) {
+ if( conflict.isInstance(registeredView) )
+ throw new ReviewedGATKException(String.format("Tried to register two conflicting views: %s and %s",
+ registeredView.getClass().getSimpleName(),
+ view.getClass().getSimpleName()));
+ }
+ }
+
+ this.registeredViews.add(view);
+ }
+
+ /**
+ * Retire this shard.
+ */
+ public void close() {
+ for( View view: registeredViews )
+ view.close();
+
+ // Explicitly purge registered views to ensure that we don't end up with circular references
+ // to views, which can in turn hold state.
+ registeredViews.clear();
+
+ if(shard != null)
+ shard.close();
+ }
+
+ @Override
+ public String toString() {
+ return shard.toString();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/View.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/View.java
new file mode 100644
index 0000000..f628bb4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/View.java
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import java.util.Collection;
+/**
+ * User: hanna
+ * Date: May 21, 2009
+ * Time: 3:14:56 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Represents a view into given data.
+ */
+public interface View {
+ /**
+ * Gets a list of all types of views which can conflict with this view.
+ */
+ public Collection<Class<? extends View>> getConflictingViews();
+
+ /**
+ * Inform this view that the data provided to it no longer exists.
+ */
+ public void close();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/package-info.java
new file mode 100644
index 0000000..bc8a602
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/providers/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ActiveRegionShardBalancer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ActiveRegionShardBalancer.java
new file mode 100644
index 0000000..efe6336
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ActiveRegionShardBalancer.java
@@ -0,0 +1,85 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * ActiveRegionShardBalancer
+ *
+ * Merges all of the file pointer information for a single contig index into a single
+ * combined shard. The purpose of doing this is to ensure that the HaplotypeCaller, which
+ * doesn't support TreeReduction by construction, gets all of the data on a single
+ * contig together so the the NanoSchedule runs efficiently
+ */
+public class ActiveRegionShardBalancer extends ShardBalancer {
+ /**
+ * Convert iterators of file pointers into balanced iterators of shards.
+ * @return An iterator over balanced shards.
+ */
+ public Iterator<Shard> iterator() {
+ return new Iterator<Shard>() {
+ public boolean hasNext() {
+ return filePointers.hasNext();
+ }
+
+ public Shard next() {
+ FilePointer current = getCombinedFilePointersOnSingleContig();
+
+ // FilePointers have already been combined as necessary at the IntervalSharder level. No
+ // need to do so again here.
+
+ return new LocusShard(parser,readsDataSource,current.getLocations(),current.fileSpans);
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Unable to remove from shard balancing iterator");
+ }
+ };
+ }
+
+ /**
+ * Combine all of the file pointers in the filePointers iterator into a single combined
+ * FilePointer that spans all of the file pointers on a single contig
+ * @return a non-null FilePointer
+ */
+ private FilePointer getCombinedFilePointersOnSingleContig() {
+ FilePointer current = filePointers.next();
+
+ final List<FilePointer> toCombine = new LinkedList<>();
+ toCombine.add(current);
+
+ while ( filePointers.hasNext() &&
+ current.isRegionUnmapped == filePointers.peek().isRegionUnmapped &&
+ (current.getContigIndex() == filePointers.peek().getContigIndex() || current.isRegionUnmapped) ) {
+ toCombine.add(filePointers.next());
+ }
+
+ return FilePointer.union(toCombine, parser);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BAMAccessPlan.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BAMAccessPlan.java
new file mode 100644
index 0000000..1e30d6c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BAMAccessPlan.java
@@ -0,0 +1,170 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.util.PeekableIterator;
+import htsjdk.samtools.GATKBAMFileSpan;
+import htsjdk.samtools.GATKChunk;
+import htsjdk.samtools.util.BlockCompressedFilePointerUtil;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+* Created by IntelliJ IDEA.
+* User: mhanna
+* Date: 10/14/11
+* Time: 10:47 PM
+* To change this template use File | Settings | File Templates.
+*/
+class BAMAccessPlan {
+ private final SAMReaderID reader;
+ private final BlockInputStream inputStream;
+
+ private final List<GATKChunk> positions;
+ private PeekableIterator<GATKChunk> positionIterator;
+
+ /**
+ * Stores the next block address to read, or -1 if no such block is available.
+ */
+ private long nextBlockAddress;
+
+
+ BAMAccessPlan(final SAMReaderID reader, final BlockInputStream inputStream, GATKBAMFileSpan fileSpan) {
+ this.reader = reader;
+ this.inputStream = inputStream;
+
+ this.positions = fileSpan.getGATKChunks();
+ initialize();
+ }
+
+ public SAMReaderID getReader() {
+ return reader;
+ }
+
+ public BlockInputStream getInputStream() {
+ return inputStream;
+ }
+
+ /**
+ * Retrieves the next block address to be read.
+ * @return Next block address to be read.
+ */
+ public long getBlockAddress() {
+ return nextBlockAddress;
+ }
+
+ /**
+ * Retrieves the first offset of interest in the block returned by getBlockAddress().
+ * @return First block of interest in this segment.
+ */
+ public int getFirstOffsetInBlock() {
+ return (nextBlockAddress == positionIterator.peek().getBlockStart()) ? positionIterator.peek().getBlockOffsetStart() : 0;
+ }
+
+ /**
+ * Gets the spans overlapping the given block; used to copy the contents of the block into the circular buffer.
+ * @param blockAddress Block address for which to search.
+ * @param filePosition Block address at which to terminate the last chunk if the last chunk goes beyond this span.
+ * @return list of chunks containing that block.
+ */
+ public List<GATKChunk> getSpansOverlappingBlock(long blockAddress, long filePosition) {
+ List<GATKChunk> spansOverlapping = new LinkedList<GATKChunk>();
+ // While the position iterator overlaps the given block, pull out spans to report.
+ while(positionIterator.hasNext() && positionIterator.peek().getBlockStart() <= blockAddress) {
+ // Create a span over as much of the block as is covered by this chunk.
+ int blockOffsetStart = (blockAddress == positionIterator.peek().getBlockStart()) ? positionIterator.peek().getBlockOffsetStart() : 0;
+
+ // Calculate the end of this span. If the span extends past this block, cap it using the current file position.
+ long blockEnd;
+ int blockOffsetEnd;
+ if(blockAddress < positionIterator.peek().getBlockEnd()) {
+ blockEnd = filePosition;
+ blockOffsetEnd = 0;
+ }
+ else {
+ blockEnd = positionIterator.peek().getBlockEnd();
+ blockOffsetEnd = positionIterator.peek().getBlockOffsetEnd();
+ }
+
+ GATKChunk newChunk = new GATKChunk(blockAddress,blockOffsetStart,blockEnd,blockOffsetEnd);
+
+ if(newChunk.getChunkStart() <= newChunk.getChunkEnd())
+ spansOverlapping.add(new GATKChunk(blockAddress,blockOffsetStart,blockEnd,blockOffsetEnd));
+
+ // If the value currently stored in the position iterator ends past the current block, we must be done. Abort.
+ if(!positionIterator.hasNext() || positionIterator.peek().getBlockEnd() > blockAddress)
+ break;
+
+ // If the position iterator ends before the block ends, pull the position iterator forward.
+ if(positionIterator.peek().getBlockEnd() <= blockAddress)
+ positionIterator.next();
+ }
+
+ return spansOverlapping;
+ }
+
+ public void reset() {
+ initialize();
+ }
+
+ /**
+ * Resets the SAM reader position to its original state.
+ */
+ private void initialize() {
+ this.positionIterator = new PeekableIterator<GATKChunk>(positions.iterator());
+ if(positionIterator.hasNext())
+ nextBlockAddress = positionIterator.peek().getBlockStart();
+ else
+ nextBlockAddress = -1;
+ }
+
+ /**
+ * Advances the current position to the next block to read, given the current position in the file.
+ * @param filePosition The current position within the file.
+ */
+ void advancePosition(final long filePosition) {
+ nextBlockAddress = BlockCompressedFilePointerUtil.getBlockAddress(filePosition);
+
+ // Check the current file position against the iterator; if the iterator is before the current file position,
+ // draw the iterator forward. Remember when performing the check that coordinates are half-open!
+ while(positionIterator.hasNext() && isFilePositionPastEndOfChunk(filePosition,positionIterator.peek()))
+ positionIterator.next();
+
+ // If the block iterator has shot past the file pointer, bring the file pointer flush with the start of the current block.
+ if(positionIterator.hasNext() && filePosition < positionIterator.peek().getChunkStart())
+ nextBlockAddress = positionIterator.peek().getBlockStart();
+
+ // If we've shot off the end of the block pointer, notify consumers that iteration is complete.
+ if(!positionIterator.hasNext())
+ nextBlockAddress = -1;
+ }
+
+ private boolean isFilePositionPastEndOfChunk(final long filePosition, final GATKChunk chunk) {
+ return filePosition >= chunk.getChunkEnd();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BAMSchedule.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BAMSchedule.java
new file mode 100644
index 0000000..a80b0a4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BAMSchedule.java
@@ -0,0 +1,530 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.util.PeekableIterator;
+import htsjdk.samtools.Bin;
+import htsjdk.samtools.GATKBAMFileSpan;
+import htsjdk.samtools.GATKChunk;
+import htsjdk.samtools.util.CloseableIterator;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import java.util.*;
+
+/**
+ * Writes schedules for a single BAM file to a target output file.
+ */
+public class BAMSchedule implements CloseableIterator<BAMScheduleEntry> {
+ /**
+ * File in which to store schedule data.
+ */
+ private File scheduleFile;
+
+ /**
+ * File channel for the schedule file.
+ */
+ private FileChannel scheduleFileChannel;
+
+ /**
+ * The definitive, sorted list of reader IDs. Order is important here: the order
+ * in which the reader IDs are presented here maps to the order in which they appear in the file.
+ */
+ private final List<SAMReaderID> readerIDs = new ArrayList<SAMReaderID>();
+
+ /**
+ * Iterators over the schedule. Stored in the same order as readerIDs, above.
+ */
+ private final List<PeekableIterator<BAMScheduleEntry>> scheduleIterators = new ArrayList<PeekableIterator<BAMScheduleEntry>>();
+
+ /**
+ * Next schedule entry to be returned. Null if no additional entries are present.
+ */
+ private BAMScheduleEntry nextScheduleEntry;
+
+ /**
+ * Reference sequence for which to write the schedule.
+ */
+ private final int referenceSequence;
+
+ /**
+ * Sizes of ints and longs in bytes.
+ */
+ private static final int INT_SIZE_IN_BYTES = Integer.SIZE / 8;
+ private static final int LONG_SIZE_IN_BYTES = Long.SIZE / 8;
+
+ /**
+ * Create a new BAM schedule based on the given index.
+ * @param dataSource The SAM data source to use.
+ * @param intervals List of
+ */
+ public BAMSchedule(final SAMDataSource dataSource, final List<GenomeLoc> intervals) {
+ if(intervals.isEmpty())
+ throw new ReviewedGATKException("Tried to write schedule for empty interval list.");
+
+ referenceSequence = dataSource.getHeader().getSequence(intervals.get(0).getContig()).getSequenceIndex();
+
+ createScheduleFile();
+
+ readerIDs.addAll(dataSource.getReaderIDs());
+
+ for(final SAMReaderID reader: readerIDs) {
+ final GATKBAMIndex index = dataSource.getIndex(reader);
+ final GATKBAMIndexData indexData = index.readReferenceSequence(referenceSequence);
+
+ int currentBinInLowestLevel = GATKBAMIndex.getFirstBinInLevel(GATKBAMIndex.getNumIndexLevels()-1);
+ Iterator<GenomeLoc> locusIterator = intervals.iterator();
+ GenomeLoc currentLocus = locusIterator.next();
+
+ final long readerStartOffset = position();
+
+ int maxChunkCount = 0;
+
+ while(currentBinInLowestLevel < GATKBAMIndex.MAX_BINS && currentLocus != null) {
+ final Bin bin = new Bin(referenceSequence,currentBinInLowestLevel);
+ final int binStart = index.getFirstLocusInBin(bin);
+ final int binStop = index.getLastLocusInBin(bin);
+
+ // In required, pull bin iterator ahead to the point of the next GenomeLoc.
+ if(binStop < currentLocus.getStart()) {
+ currentBinInLowestLevel++;
+ continue;
+ }
+
+ // At this point, the bin stop is guaranteed to be >= the start of the locus.
+ // If the bins have gone past the current locus, update the current locus if at all possible.
+ if(binStart > currentLocus.getStop()) {
+ currentLocus = locusIterator.hasNext() ? locusIterator.next() : null;
+ continue;
+ }
+
+ // Code at this point knows that the current bin is neither before nor after the current locus,
+ // so it must overlap. Add this region to the filesystem.
+ final GATKBAMFileSpan fileSpan = indexData.getSpanOverlapping(bin);
+
+ if(!fileSpan.isEmpty()) {
+ // File format is binary in little endian; start of region, end of region, num chunks, then the chunks themselves.
+ ByteBuffer buffer = allocateByteBuffer(2*INT_SIZE_IN_BYTES + INT_SIZE_IN_BYTES + fileSpan.getGATKChunks().size()*LONG_SIZE_IN_BYTES*2);
+ buffer.putInt(binStart);
+ buffer.putInt(binStop);
+ buffer.putInt(fileSpan.getGATKChunks().size());
+ for(GATKChunk chunk: fileSpan.getGATKChunks()) {
+ buffer.putLong(chunk.getChunkStart());
+ buffer.putLong(chunk.getChunkEnd());
+ }
+ maxChunkCount = Math.max(maxChunkCount,fileSpan.getGATKChunks().size());
+
+ // Prepare buffer for writing
+ buffer.flip();
+
+ // And write.
+ write(buffer);
+ }
+
+ currentBinInLowestLevel++;
+ }
+
+ final long readerStopOffset = position();
+
+ scheduleIterators.add(new PeekableIterator<BAMScheduleEntry>(new BAMScheduleIterator(reader,readerStartOffset,readerStopOffset,maxChunkCount)));
+
+ // Iterator initialization might move the file pointer. Make sure it gets reset back to where it was before iterator initialization.
+ position(readerStopOffset);
+ }
+
+ advance();
+ }
+
+ /**
+ * Determine whether more ScheduleEntries are present in the iterator.
+ * @return Next schedule entry to parse.
+ */
+ @Override
+ public boolean hasNext() {
+ return nextScheduleEntry != null;
+ }
+
+ /**
+ * Retrieve the next schedule entry in the list.
+ * @return next schedule entry in the queue.
+ */
+ @Override
+ public BAMScheduleEntry next() {
+ BAMScheduleEntry currentScheduleEntry = nextScheduleEntry;
+ advance();
+ return currentScheduleEntry;
+ }
+
+ /**
+ * Close down and delete the file.
+ */
+ @Override
+ public void close() {
+ try {
+ scheduleFileChannel.close();
+ }
+ catch(IOException ex) {
+ throw makeIOFailureException(true, "Unable to close schedule file.", ex);
+ }
+ }
+
+ /**
+ * Convenience routine for creating UserExceptions
+ * @param wasWriting
+ * @param message
+ * @param e
+ * @return
+ */
+ private final GATKException makeIOFailureException(final boolean wasWriting, final String message, final Exception e) {
+ if ( wasWriting ) {
+ if ( e == null )
+ return new UserException.CouldNotCreateOutputFile(scheduleFile, message);
+ else
+ return new UserException.CouldNotCreateOutputFile(scheduleFile, message, e);
+ } else {
+ if ( e == null )
+ return new UserException.CouldNotReadInputFile(scheduleFile, message);
+ else
+ return new UserException.CouldNotReadInputFile(scheduleFile, message, e);
+ }
+ }
+
+ /**
+ * Advance to the next schedule entry.
+ */
+ private void advance() {
+ nextScheduleEntry = null;
+
+ BitSet selectedIterators = new BitSet(readerIDs.size());
+ int currentStart = Integer.MAX_VALUE;
+ int currentStop = Integer.MAX_VALUE;
+
+ // Select every iterator whose next element is the lowest element in the list.
+ for(int reader = 0; reader < scheduleIterators.size(); reader++) {
+ PeekableIterator<BAMScheduleEntry> scheduleIterator = scheduleIterators.get(reader);
+ if(!scheduleIterator.hasNext())
+ continue;
+
+ // If the iterator starts after this one, skip over it.
+ if(scheduleIterator.peek().start > currentStart)
+ continue;
+
+ // If the iterator starts at the same point as this one, add it to the list.
+ if(scheduleIterator.peek().start == currentStart) {
+ selectedIterators.set(reader);
+ currentStop = Math.min(scheduleIterator.peek().stop,currentStop);
+ continue;
+ }
+
+ // If the iterator is less than anything seen before it, purge the selections and make this one current.
+ if(scheduleIterator.peek().start < currentStart) {
+ selectedIterators.clear();
+ selectedIterators.set(reader);
+ currentStart = scheduleIterator.peek().start;
+ currentStop = scheduleIterator.peek().stop;
+ }
+ }
+
+ // Out of iterators? Abort early.
+ if(selectedIterators.isEmpty())
+ return;
+
+ // Create the target schedule entry
+ BAMScheduleEntry mergedScheduleEntry = new BAMScheduleEntry(currentStart,currentStop);
+
+ // For each schedule entry with data, load the data into the merged schedule.
+ for (int reader = selectedIterators.nextSetBit(0); reader >= 0; reader = selectedIterators.nextSetBit(reader+1)) {
+ PeekableIterator<BAMScheduleEntry> scheduleIterator = scheduleIterators.get(reader);
+ BAMScheduleEntry individualScheduleEntry = scheduleIterator.peek();
+ mergedScheduleEntry.mergeInto(individualScheduleEntry);
+
+ // If the schedule iterator ends after this entry, consume it.
+ if(individualScheduleEntry.stop <= currentStop)
+ scheduleIterator.next();
+ }
+
+ // For each schedule entry without data, add a blank entry.
+ for (int reader = selectedIterators.nextClearBit(0); reader < readerIDs.size(); reader = selectedIterators.nextClearBit(reader+1)) {
+ mergedScheduleEntry.addFileSpan(readerIDs.get(reader),new GATKBAMFileSpan());
+ }
+
+ nextScheduleEntry = mergedScheduleEntry;
+ }
+
+ @Override
+ public void remove() { throw new UnsupportedOperationException("Unable to remove from a schedule iterator."); }
+
+ /**
+ * Create a new schedule file, containing schedule information for all BAM files being dynamically merged.
+ */
+ private void createScheduleFile() {
+ try {
+ scheduleFile = File.createTempFile("bamschedule."+referenceSequence,null);
+ scheduleFileChannel = new RandomAccessFile(scheduleFile,"rw").getChannel();
+ }
+ catch(IOException ex) {
+ throw new UserException("Unable to create a temporary BAM schedule file. Please make sure Java can write to the default temp directory or use -Djava.io.tmpdir= to instruct it to use a different temp directory instead.",ex);
+ }
+ scheduleFile.deleteOnExit();
+
+ }
+
+ /**
+ * Creates a new byte buffer of the given size.
+ * @param size the size of buffer to allocate.
+ * @return Newly allocated byte buffer.
+ */
+ private ByteBuffer allocateByteBuffer(final int size) {
+ ByteBuffer buffer = ByteBuffer.allocate(size);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+ return buffer;
+ }
+
+ /**
+ * Reads the contents at the current position on disk into the given buffer.
+ * @param buffer buffer to fill.
+ */
+ private int read(final ByteBuffer buffer) {
+ try {
+ return scheduleFileChannel.read(buffer);
+ }
+ catch(IOException ex) {
+ throw makeIOFailureException(false, "Unable to read data from BAM schedule file.", ex);
+ }
+ }
+
+ private void write(final ByteBuffer buffer) {
+ try {
+ scheduleFileChannel.write(buffer);
+ if(buffer.remaining() > 0)
+ throw makeIOFailureException(true, "Unable to write entire buffer to file.", null);
+ }
+ catch(IOException ex) {
+ throw makeIOFailureException(true, "Unable to write data to BAM schedule file.", ex);
+ }
+ }
+
+ /**
+ * Reads the current position from the file channel.
+ * @return Current position within file channel.
+ */
+ private long position() {
+ try {
+ return scheduleFileChannel.position();
+ }
+ catch(IOException ex) {
+ throw makeIOFailureException(false, "Unable to retrieve position of BAM schedule file.", ex);
+ }
+ }
+
+ /**
+ * Reposition the file channel to the specified offset wrt the start of the file.
+ * @param position The position.
+ */
+ private void position(final long position) {
+ try {
+ scheduleFileChannel.position(position);
+ }
+ catch(IOException ex) {
+ throw makeIOFailureException(false, "Unable to position BAM schedule file.",ex);
+ }
+ }
+
+ /**
+ * An iterator over the schedule for a single BAM file.
+ */
+ private class BAMScheduleIterator implements Iterator<BAMScheduleEntry> {
+ /**
+ * ID of the reader associated with the given schedule.
+ */
+ private final SAMReaderID reader;
+
+ /**
+ * Current position in the file.
+ */
+ private long currentPosition;
+
+ /**
+ * Stopping file position of last bin in file for this reader, exclusive.
+ */
+ private final long stopPosition;
+
+ /**
+ * Byte buffer used to store BAM header info.
+ */
+ private final ByteBuffer binHeader;
+
+ /**
+ * Byte buffer used to store chunk data.
+ */
+ private final ByteBuffer chunkData;
+
+ public BAMScheduleIterator(final SAMReaderID reader, final long startPosition, final long stopPosition, final int maxChunkCount) {
+ this.reader = reader;
+ this.currentPosition = startPosition;
+ this.stopPosition = stopPosition;
+ binHeader = allocateByteBuffer(INT_SIZE_IN_BYTES*3);
+ chunkData = allocateByteBuffer(maxChunkCount*LONG_SIZE_IN_BYTES*2);
+ }
+
+ @Override
+ public boolean hasNext() {
+ return currentPosition < stopPosition;
+ }
+
+ @Override
+ public BAMScheduleEntry next() {
+ position(currentPosition);
+
+ // Read data.
+ int binHeaderBytesRead = read(binHeader);
+
+ // Make sure we read in a complete bin header:
+ if ( binHeaderBytesRead < INT_SIZE_IN_BYTES * 3 ) {
+ throw new ReviewedGATKException(String.format("Unable to read a complete bin header from BAM schedule file %s for BAM file %s. " +
+ "The BAM schedule file is likely incomplete/corrupt.",
+ scheduleFile.getAbsolutePath(), reader.getSamFilePath()));
+ }
+
+ // Decode contents.
+ binHeader.flip();
+ final int start = binHeader.getInt();
+ final int stop = binHeader.getInt();
+ final int numChunks = binHeader.getInt();
+
+ // Prepare bin buffer for next read.
+ binHeader.flip();
+
+ // Prepare a target buffer for chunks.
+ GATKChunk[] chunks = new GATKChunk[numChunks];
+
+ // Read all chunk data.
+ chunkData.limit(numChunks*LONG_SIZE_IN_BYTES*2);
+ long bytesRead = read(chunkData);
+ if(bytesRead != numChunks*LONG_SIZE_IN_BYTES*2)
+ throw new ReviewedGATKException("Unable to read all chunks from file");
+
+ // Prepare for reading.
+ chunkData.flip();
+
+ for(int i = 0; i < numChunks; i++)
+ chunks[i] = new GATKChunk(chunkData.getLong(),chunkData.getLong());
+
+ // Prepare chunk buffer for next read.
+ chunkData.flip();
+
+ BAMScheduleEntry nextScheduleEntry = new BAMScheduleEntry(start,stop);
+ nextScheduleEntry.addFileSpan(reader,new GATKBAMFileSpan(chunks));
+
+ // Reset the position of the iterator at the next contig.
+ currentPosition = position();
+
+ return nextScheduleEntry;
+ }
+
+ /**
+ * Not supported.
+ */
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Unable to remove from a BAMScheduleIterator");
+ }
+
+ }
+}
+
+/**
+ * A single proto-shard to be processed.
+ */
+class BAMScheduleEntry {
+ /**
+ * Starting position for the genomic entry.
+ */
+ public final int start;
+
+ /**
+ * Ending position for the genomic entry.
+ */
+ public final int stop;
+
+ /**
+ * The spans representing the given region.
+ */
+ public final Map<SAMReaderID,GATKBAMFileSpan> fileSpans = new HashMap<SAMReaderID,GATKBAMFileSpan>();
+
+ BAMScheduleEntry(final int start, final int stop) {
+ this.start = start;
+ this.stop = stop;
+ }
+
+ /**
+ * Add a new file span to this schedule.
+ * @param reader Reader associated with the span.
+ * @param fileSpan Blocks to read in the given reader.
+ */
+ public void addFileSpan(final SAMReaderID reader, final GATKBAMFileSpan fileSpan) {
+ fileSpans.put(reader,fileSpan);
+ }
+
+ /**
+ * A naive merge operation. Merge the fileSpans in other into this, blowing up if conflicts are
+ * detected. Completely ignores merging start and stop.
+ * @param other Other schedule entry to merging into this one.
+ */
+ public void mergeInto(final BAMScheduleEntry other) {
+ final int thisSize = fileSpans.size();
+ final int otherSize = other.fileSpans.size();
+ fileSpans.putAll(other.fileSpans);
+ if(fileSpans.size() != thisSize+otherSize)
+ throw new ReviewedGATKException("Unable to handle overlaps when merging BAM schedule entries.");
+ }
+
+ /**
+ * Returns true if the location of this bin tree is before the given position.
+ * @param locus Locus to test.
+ * @return True if this bin sits completely before the given locus; false otherwise.
+ */
+ public boolean isBefore(final GenomeLoc locus) {
+ return stop < locus.getStart();
+ }
+
+ /**
+ * Checks overlap between this bin tree and other bin trees.
+ * @param position the position over which to detect overlap.
+ * @return True if the segment overlaps. False otherwise.
+ */
+ public boolean overlaps(final GenomeLoc position) {
+ return !(position.getStop() < start || position.getStart() > stop);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BAMScheduler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BAMScheduler.java
new file mode 100644
index 0000000..1ea8d39
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BAMScheduler.java
@@ -0,0 +1,320 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.util.PeekableIterator;
+import htsjdk.samtools.GATKBAMFileSpan;
+import htsjdk.samtools.GATKChunk;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+import java.util.*;
+
+/**
+ * Assign intervals to the most appropriate blocks, keeping as little as possible in memory at once.
+ */
+public class BAMScheduler implements Iterator<FilePointer> {
+ private final SAMDataSource dataSource;
+
+ private final Map<SAMReaderID,GATKBAMIndex> indexFiles = new HashMap<SAMReaderID,GATKBAMIndex>();
+
+ private FilePointer nextFilePointer = null;
+
+ private GenomeLocSortedSet loci;
+ private PeekableIterator<GenomeLoc> locusIterator;
+ private GenomeLoc currentLocus;
+ private IntervalMergingRule intervalMergingRule;
+
+ /*
+ * Creates BAMScheduler using contigs from the given BAM data source.
+ *
+ * @param dataSource BAM source
+ * @return non-null BAM scheduler
+ */
+ public static BAMScheduler createOverMappedReads(final SAMDataSource dataSource) {
+ final BAMScheduler scheduler = new BAMScheduler(dataSource, IntervalMergingRule.ALL);
+ final GenomeLocSortedSet intervals = GenomeLocSortedSet.createSetFromSequenceDictionary(dataSource.getHeader().getSequenceDictionary());
+ scheduler.populateFilteredIntervalList(intervals);
+ return scheduler;
+ }
+
+ public static BAMScheduler createOverAllReads(final SAMDataSource dataSource, final GenomeLocParser parser) {
+ BAMScheduler scheduler = new BAMScheduler(dataSource, IntervalMergingRule.ALL);
+ scheduler.populateUnfilteredIntervalList(parser);
+ return scheduler;
+ }
+
+ public static BAMScheduler createOverIntervals(final SAMDataSource dataSource, final IntervalMergingRule mergeRule, final GenomeLocSortedSet loci) {
+ BAMScheduler scheduler = new BAMScheduler(dataSource, mergeRule);
+ scheduler.populateFilteredIntervalList(loci);
+ return scheduler;
+ }
+
+
+ private BAMScheduler(final SAMDataSource dataSource, final IntervalMergingRule mergeRule) {
+ this.dataSource = dataSource;
+ this.intervalMergingRule = mergeRule;
+ for(SAMReaderID reader: dataSource.getReaderIDs()) {
+ GATKBAMIndex index = dataSource.getIndex(reader);
+ if(index != null)
+ indexFiles.put(reader,dataSource.getIndex(reader));
+ }
+ }
+
+ /**
+ * The consumer has asked for a bounded set of locations. Prepare an iterator over those locations.
+ * @param loci The list of locations to search and iterate over.
+ */
+ private void populateFilteredIntervalList(final GenomeLocSortedSet loci) {
+ this.loci = loci;
+ if(!indexFiles.isEmpty()) {
+ // If index data is available, start up the iterator.
+ locusIterator = new PeekableIterator<GenomeLoc>(loci.iterator());
+ if(locusIterator.hasNext())
+ currentLocus = locusIterator.next();
+ advance();
+ }
+ else {
+ // Otherwise, seed the iterator with a single file pointer over the entire region.
+ nextFilePointer = generatePointerOverEntireFileset();
+ for(GenomeLoc locus: loci)
+ nextFilePointer.addLocation(locus);
+ locusIterator = new PeekableIterator<GenomeLoc>(Collections.<GenomeLoc>emptyList().iterator());
+ }
+ }
+
+ /**
+ * The consumer has provided null, meaning to iterate over all available data. Create a file pointer stretching
+ * from just before the start of the region to the end of the region.
+ */
+ private void populateUnfilteredIntervalList(final GenomeLocParser parser) {
+ this.loci = new GenomeLocSortedSet(parser);
+ locusIterator = new PeekableIterator<GenomeLoc>(Collections.<GenomeLoc>emptyList().iterator());
+ nextFilePointer = generatePointerOverEntireFileset();
+ }
+
+ /**
+ * Generate a span that runs from the end of the BAM header to the end of the fle.
+ * @return A file pointer over the specified region.
+ */
+ private FilePointer generatePointerOverEntireFileset() {
+ FilePointer filePointer = new FilePointer(intervalMergingRule);
+
+ // This is a "monolithic" FilePointer representing all regions in all files we will ever visit, and is
+ // the only FilePointer we will create. This allows us to have this FilePointer represent regions from
+ // multiple contigs
+ filePointer.setIsMonolithic(true);
+
+ Map<SAMReaderID,GATKBAMFileSpan> currentPosition;
+
+ currentPosition = dataSource.getInitialReaderPositions();
+
+ for(SAMReaderID reader: dataSource.getReaderIDs())
+ filePointer.addFileSpans(reader,createSpanToEndOfFile(currentPosition.get(reader).getGATKChunks().get(0).getChunkStart()));
+ return filePointer;
+ }
+
+ public boolean hasNext() {
+ return nextFilePointer != null;
+ }
+
+ public FilePointer next() {
+ if(!hasNext())
+ throw new NoSuchElementException("No next element available in interval sharder");
+ FilePointer currentFilePointer = nextFilePointer;
+ nextFilePointer = null;
+ advance();
+
+ return currentFilePointer;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Unable to remove FilePointers from an IntervalSharder");
+ }
+
+ private void advance() {
+ if(loci.isEmpty())
+ return;
+
+ while(nextFilePointer == null && currentLocus != null) {
+ // special case handling of the unmapped shard.
+ if(currentLocus == GenomeLoc.UNMAPPED) {
+ nextFilePointer = new FilePointer(intervalMergingRule, GenomeLoc.UNMAPPED);
+ for(SAMReaderID id: dataSource.getReaderIDs())
+ nextFilePointer.addFileSpans(id,createSpanToEndOfFile(indexFiles.get(id).getStartOfLastLinearBin()));
+ currentLocus = null;
+ continue;
+ }
+
+ nextFilePointer = new FilePointer(intervalMergingRule);
+
+ int coveredRegionStart = 1;
+ int coveredRegionStop = Integer.MAX_VALUE;
+ GenomeLoc coveredRegion = null;
+
+ BAMScheduleEntry scheduleEntry = getNextOverlappingBAMScheduleEntry(currentLocus);
+
+ // No overlapping data at all.
+ if(scheduleEntry != null) {
+ coveredRegionStart = Math.max(coveredRegionStart,scheduleEntry.start);
+ coveredRegionStop = Math.min(coveredRegionStop,scheduleEntry.stop);
+ coveredRegion = loci.getGenomeLocParser().createGenomeLoc(currentLocus.getContig(),coveredRegionStart,coveredRegionStop);
+
+ nextFilePointer.addFileSpans(scheduleEntry.fileSpans);
+ }
+ else {
+ // Always create a file span, whether there was covered data or not. If there was no covered data, then the binTree is empty.
+ for(SAMReaderID reader: indexFiles.keySet())
+ nextFilePointer.addFileSpans(reader,new GATKBAMFileSpan());
+ }
+
+ // Early exit if no bins were found.
+ if(coveredRegion == null) {
+ // for debugging only: maximum split is 16384.
+ nextFilePointer.addLocation(currentLocus);
+ currentLocus = locusIterator.hasNext() ? locusIterator.next() : null;
+ continue;
+ }
+
+ // Early exit if only part of the first interval was found.
+ if(currentLocus.startsBefore(coveredRegion)) {
+ int splitPoint = Math.min(coveredRegion.getStart()-currentLocus.getStart(),16384)+currentLocus.getStart();
+ GenomeLoc[] splitContigs = currentLocus.split(splitPoint);
+ nextFilePointer.addLocation(splitContigs[0]);
+ currentLocus = splitContigs[1];
+ continue;
+ }
+
+ // Define the initial range of the file pointer, aka the region where the locus currently being processed intersects the BAM list.
+ GenomeLoc initialLocation = currentLocus.intersect(coveredRegion);
+ nextFilePointer.addLocation(initialLocation);
+
+ // See whether the BAM regions discovered overlap the next set of intervals in the interval list. If so, include every overlapping interval.
+ if(!nextFilePointer.locations.isEmpty()) {
+ while(locusIterator.hasNext() && locusIterator.peek().overlapsP(coveredRegion)) {
+ currentLocus = locusIterator.next();
+ nextFilePointer.addLocation(currentLocus.intersect(coveredRegion));
+ }
+
+ // Chop off the uncovered portion of the locus. Since we know that the covered region overlaps the current locus,
+ // we can simplify the interval creation process to the end of the covered region to the stop of the given interval.
+ if(coveredRegionStop < currentLocus.getStop())
+ currentLocus = loci.getGenomeLocParser().createGenomeLoc(currentLocus.getContig(),coveredRegionStop+1,currentLocus.getStop());
+ else if(locusIterator.hasNext())
+ currentLocus = locusIterator.next();
+ else
+ currentLocus = null;
+ }
+
+ }
+ }
+
+
+ /**
+ * The last reference sequence processed by this iterator.
+ */
+ private Integer lastReferenceSequenceLoaded = null;
+
+ /**
+ * The stateful iterator used to progress through the genoem.
+ */
+ private PeekableIterator<BAMScheduleEntry> bamScheduleIterator = null;
+
+ /**
+ * Clean up underlying BAMSchedule file handles.
+ */
+ public void close() {
+ if(bamScheduleIterator != null)
+ bamScheduleIterator.close();
+ }
+
+ /**
+ * Get the next overlapping tree of bins associated with the given BAM file.
+ * @param currentLocus The actual locus for which to check overlap.
+ * @return The next schedule entry overlapping with the given list of loci.
+ */
+ private BAMScheduleEntry getNextOverlappingBAMScheduleEntry(final GenomeLoc currentLocus) {
+ // Make sure that we consult the BAM header to ensure that we're using the correct contig index for this contig name.
+ // This will ensure that if the two sets of contigs don't quite match (b36 male vs female ref, hg19 Epstein-Barr), then
+ // we'll be using the correct contig index for the BAMs.
+ // TODO: Warning: assumes all BAMs use the same sequence dictionary! Get around this with contig aliasing.
+ SAMSequenceRecord currentContigSequenceRecord = dataSource.getHeader().getSequence(currentLocus.getContig());
+ if ( currentContigSequenceRecord == null ) {
+ throw new UserException(String.format("Contig %s not present in sequence dictionary for merged BAM header: %s",
+ currentLocus.getContig(),
+ ReadUtils.prettyPrintSequenceRecords(dataSource.getHeader().getSequenceDictionary())));
+ }
+
+ final int currentContigIndex = currentContigSequenceRecord.getSequenceIndex();
+
+ // Stale reference sequence or first invocation. (Re)create the binTreeIterator.
+ if(lastReferenceSequenceLoaded == null || lastReferenceSequenceLoaded != currentContigIndex) {
+ if(bamScheduleIterator != null)
+ bamScheduleIterator.close();
+ lastReferenceSequenceLoaded = currentContigIndex;
+
+ // Naive algorithm: find all elements in current contig for proper schedule creation.
+ List<GenomeLoc> lociInContig = new LinkedList<GenomeLoc>();
+ for(GenomeLoc locus: loci) {
+ if (!GenomeLoc.isUnmapped(locus) && dataSource.getHeader().getSequence(locus.getContig()) == null)
+ throw new ReviewedGATKException("BAM file(s) do not have the contig: " + locus.getContig() + ". You are probably using a different reference than the one this file was aligned with");
+
+ if (!GenomeLoc.isUnmapped(locus) && dataSource.getHeader().getSequence(locus.getContig()).getSequenceIndex() == lastReferenceSequenceLoaded)
+ lociInContig.add(locus);
+ }
+
+ bamScheduleIterator = new PeekableIterator<BAMScheduleEntry>(new BAMSchedule(dataSource,lociInContig));
+ }
+
+ if(!bamScheduleIterator.hasNext())
+ return null;
+
+ // Peek the iterator along until finding the first binTree at or following the current locus.
+ BAMScheduleEntry bamScheduleEntry = bamScheduleIterator.peek();
+ while(bamScheduleEntry != null && bamScheduleEntry.isBefore(currentLocus)) {
+ bamScheduleIterator.next();
+ bamScheduleEntry = bamScheduleIterator.hasNext() ? bamScheduleIterator.peek() : null;
+ }
+
+ return (bamScheduleEntry != null && bamScheduleEntry.overlaps(currentLocus)) ? bamScheduleEntry : null;
+ }
+
+ /**
+ * Create a span from the given start point to the end of the file.
+ * @param startOfRegion Start of the region, in encoded coordinates (block start << 16 & block offset).
+ * @return A file span from the given point to the end of the file.
+ */
+ private GATKBAMFileSpan createSpanToEndOfFile(final long startOfRegion) {
+ return new GATKBAMFileSpan(new GATKChunk(startOfRegion,Long.MAX_VALUE));
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BGZFBlockLoadingDispatcher.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BGZFBlockLoadingDispatcher.java
new file mode 100644
index 0000000..cc1d9e9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BGZFBlockLoadingDispatcher.java
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Preloads BGZF blocks in preparation for unzipping and data processing.
+ * TODO: Right now, the block loader has all threads blocked waiting for a work request. Ultimately this should
+ * TODO: be replaced with a central thread management strategy.
+ */
+public class BGZFBlockLoadingDispatcher {
+ /**
+ * The file handle cache, used when allocating blocks from the dispatcher.
+ */
+ private final FileHandleCache fileHandleCache;
+
+ private final ExecutorService threadPool;
+
+ private final Queue<BAMAccessPlan> inputQueue;
+
+ public BGZFBlockLoadingDispatcher(final int numThreads, final int numFileHandles) {
+ threadPool = Executors.newFixedThreadPool(numThreads);
+ fileHandleCache = new FileHandleCache(numFileHandles);
+ inputQueue = new LinkedList<BAMAccessPlan>();
+
+ threadPool.execute(new BlockLoader(this,fileHandleCache,true));
+ }
+
+ /**
+ * Initiates a request for a new block load.
+ * @param readerPosition Position at which to load.
+ */
+ void queueBlockLoad(final BAMAccessPlan readerPosition) {
+ synchronized(inputQueue) {
+ inputQueue.add(readerPosition);
+ inputQueue.notify();
+ }
+ }
+
+ /**
+ * Claims the next work request from the queue.
+ * @return The next work request, or null if none is available.
+ */
+ BAMAccessPlan claimNextWorkRequest() {
+ synchronized(inputQueue) {
+ while(inputQueue.isEmpty()) {
+ try {
+ inputQueue.wait();
+ }
+ catch(InterruptedException ex) {
+ throw new ReviewedGATKException("Interrupt occurred waiting for next block reader work item");
+ }
+ }
+ return inputQueue.poll();
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BlockInputStream.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BlockInputStream.java
new file mode 100644
index 0000000..11fecb6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BlockInputStream.java
@@ -0,0 +1,450 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.GATKBAMFileSpan;
+import htsjdk.samtools.GATKChunk;
+import htsjdk.samtools.util.BlockCompressedInputStream;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Presents decompressed blocks to the SAMFileReader.
+ */
+public class BlockInputStream extends InputStream {
+ /**
+ * Mechanism for triggering block loads.
+ */
+ private final BGZFBlockLoadingDispatcher dispatcher;
+
+ /**
+ * The reader whose data is supplied by this input stream.
+ */
+ private final SAMReaderID reader;
+
+ /**
+ * Length of the input stream.
+ */
+ private final long length;
+
+ /**
+ * The latest error reported by an asynchronous block load.
+ */
+ private Throwable error;
+
+ /**
+ * Current accessPlan.
+ */
+ private BAMAccessPlan accessPlan;
+
+ /**
+ * A stream of compressed data blocks.
+ */
+ private final ByteBuffer buffer;
+
+ /**
+ * Offsets of the given blocks in the buffer.
+ */
+ private LinkedList<Integer> blockOffsets = new LinkedList<Integer>();
+
+ /**
+ * Source positions of the given blocks in the buffer.
+ */
+ private LinkedList<Long> blockPositions = new LinkedList<Long>();
+
+ /**
+ * Provides a lock to wait for more data to arrive.
+ */
+ private final Object lock = new Object();
+
+ /**
+ * An input stream to use when comparing data back to what it should look like.
+ */
+ private final BlockCompressedInputStream validatingInputStream;
+
+ /**
+ * Create a new block presenting input stream with a dedicated buffer.
+ * @param dispatcher the block loading messenger.
+ * @param reader the reader for which to load data.
+ * @param validate validates the contents read into the buffer against the contents of a Picard BlockCompressedInputStream.
+ */
+ BlockInputStream(final BGZFBlockLoadingDispatcher dispatcher, final SAMReaderID reader, final boolean validate) {
+ this.reader = reader;
+ this.length = reader.samFile.length();
+
+ buffer = ByteBuffer.wrap(new byte[64*1024]);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+
+ // The state of the buffer assumes that the range of data written into the buffer appears in the range
+ // [position,limit), while extra capacity exists in the range [limit,capacity)
+ buffer.limit(0);
+
+ this.dispatcher = dispatcher;
+ // TODO: Kill the region when all we want to do is start at the beginning of the stream and run to the end of the stream.
+ this.accessPlan = new BAMAccessPlan(reader,this,new GATKBAMFileSpan(new GATKChunk(0,Long.MAX_VALUE)));
+
+ // The block offsets / block positions guarantee that the ending offset/position in the data structure maps to
+ // the point in the file just following the last read. These two arrays should never be empty; initializing
+ // to 0 to match the position above.
+ this.blockOffsets.add(0);
+ this.blockPositions.add(0L);
+
+ try {
+ if(validate) {
+ System.out.printf("BlockInputStream %s: BGZF block validation mode activated%n",this);
+ validatingInputStream = new BlockCompressedInputStream(reader.samFile);
+ // A bug in ValidatingInputStream means that calling getFilePointer() immediately after initialization will result in an NPE.
+ // Poke the stream to start reading data.
+ validatingInputStream.available();
+ }
+ else
+ validatingInputStream = null;
+ }
+ catch(IOException ex) {
+ throw new ReviewedGATKException("Unable to validate against Picard input stream",ex);
+ }
+ }
+
+ public long length() {
+ return length;
+ }
+
+ public long getFilePointer() {
+ long filePointer;
+ synchronized(lock) {
+ // Find the current block within the input stream.
+ int blockIndex;
+ for(blockIndex = 0; blockIndex+1 < blockOffsets.size() && buffer.position() > blockOffsets.get(blockIndex+1); blockIndex++)
+ ;
+ filePointer = blockPositions.get(blockIndex) + (buffer.position()-blockOffsets.get(blockIndex));
+ }
+
+// if(validatingInputStream != null && filePointer != validatingInputStream.getFilePointer())
+// throw new ReviewedGATKException(String.format("Position of input stream is invalid; expected (block address, block offset) = (%d,%d), got (%d,%d)",
+// BlockCompressedFilePointerUtil.getBlockAddress(validatingInputStream.getFilePointer()),BlockCompressedFilePointerUtil.getBlockOffset(validatingInputStream.getFilePointer()),
+// BlockCompressedFilePointerUtil.getBlockAddress(filePointer),BlockCompressedFilePointerUtil.getBlockOffset(filePointer)));
+
+ return filePointer;
+ }
+
+ private void clearBuffers() {
+ this.accessPlan.reset();
+
+ // Buffer semantics say that outside of a lock, buffer should always be prepared for reading.
+ // Indicate no data to be read.
+ buffer.clear();
+ buffer.limit(0);
+
+ // Clear everything except the last block offset / position
+ blockOffsets.clear();
+ blockOffsets.add(0);
+ while(blockPositions.size() > 1)
+ blockPositions.removeFirst();
+ }
+
+ public boolean eof() {
+ synchronized(lock) {
+ // TODO: Handle multiple empty BGZF blocks at end of the file.
+ return accessPlan != null && (accessPlan.getBlockAddress() < 0 || accessPlan.getBlockAddress() >= length);
+ }
+ }
+
+ /**
+ * Submits a new access plan for the given dataset and seeks to the given point.
+ * @param accessPlan The next seek point for BAM data in this reader.
+ */
+ public void submitAccessPlan(final BAMAccessPlan accessPlan) {
+ //System.out.printf("Thread %s: submitting access plan for block at position: %d%n",Thread.currentThread().getId(),position.getBlockAddress());
+ this.accessPlan = accessPlan;
+ accessPlan.reset();
+
+ clearBuffers();
+
+ // Pull the iterator past any oddball chunks at the beginning of the shard (chunkEnd < chunkStart, empty chunks, etc).
+ // TODO: Don't pass these empty chunks in.
+ accessPlan.advancePosition(makeFilePointer(accessPlan.getBlockAddress(),0));
+
+ if(accessPlan.getBlockAddress() >= 0) {
+ waitForBufferFill();
+ }
+
+ if(validatingInputStream != null) {
+ try {
+ validatingInputStream.seek(makeFilePointer(accessPlan.getBlockAddress(),0));
+ }
+ catch(IOException ex) {
+ throw new ReviewedGATKException("Unable to validate against Picard input stream",ex);
+ }
+ }
+
+ }
+
+
+ private void compactBuffer() {
+ // Compact buffer to maximize storage space.
+ int bytesToRemove = 0;
+
+ // Look ahead to see if we can compact away the first blocks in the series.
+ while(blockOffsets.size() > 1 && buffer.position() >= blockOffsets.get(1)) {
+ blockOffsets.remove();
+ blockPositions.remove();
+ bytesToRemove = blockOffsets.peek();
+ }
+
+ // If we end up with an empty block at the end of the series, compact this as well.
+ if(buffer.remaining() == 0 && blockOffsets.size() > 1 && buffer.position() >= blockOffsets.peek()) {
+ bytesToRemove += buffer.position();
+ blockOffsets.remove();
+ blockPositions.remove();
+ }
+
+ int finalBufferStart = buffer.position() - bytesToRemove;
+ int finalBufferSize = buffer.remaining();
+
+ // Position the buffer to remove the unneeded data, and compact it away.
+ buffer.position(bytesToRemove);
+ buffer.compact();
+
+ // Reset the limits for reading.
+ buffer.position(finalBufferStart);
+ buffer.limit(finalBufferStart+finalBufferSize);
+
+ // Shift everything in the offset buffer down to accommodate the bytes removed from the buffer.
+ for(int i = 0; i < blockOffsets.size(); i++)
+ blockOffsets.set(i,blockOffsets.get(i)-bytesToRemove);
+ }
+
+ /**
+ * Push contents of incomingBuffer into the end of this buffer.
+ * MUST be called from a thread that is NOT the reader thread.
+ * @param incomingBuffer The data being pushed into this input stream.
+ * @param accessPlan target access plan for the data.
+ * @param filePosition the current position of the file pointer
+ */
+ public void copyIntoBuffer(final ByteBuffer incomingBuffer, final BAMAccessPlan accessPlan, final long filePosition) {
+ synchronized(lock) {
+ try {
+ if(validatingInputStream != null) {
+ byte[] validBytes = new byte[incomingBuffer.remaining()];
+
+ byte[] currentBytes = new byte[incomingBuffer.remaining()];
+ int pos = incomingBuffer.position();
+ int lim = incomingBuffer.limit();
+ incomingBuffer.get(currentBytes);
+
+ incomingBuffer.limit(lim);
+ incomingBuffer.position(pos);
+
+ long currentFilePointer = validatingInputStream.getFilePointer();
+ validatingInputStream.seek(makeFilePointer(accessPlan.getBlockAddress(), 0));
+ validatingInputStream.read(validBytes);
+ validatingInputStream.seek(currentFilePointer);
+
+ if(!Arrays.equals(validBytes,currentBytes))
+ throw new ReviewedGATKException(String.format("Bytes being inserted into BlockInputStream %s are incorrect",this));
+ }
+
+ compactBuffer();
+ // Open up the buffer for more reading.
+ buffer.limit(buffer.capacity());
+
+ // Get the spans overlapping this particular block...
+ List<GATKChunk> spansOverlapping = accessPlan.getSpansOverlappingBlock(accessPlan.getBlockAddress(),filePosition);
+
+ // ...and advance the block
+ this.accessPlan = accessPlan;
+ accessPlan.advancePosition(makeFilePointer(filePosition, 0));
+
+ if(buffer.remaining() < incomingBuffer.remaining())
+ lock.wait();
+
+ final int bytesInIncomingBuffer = incomingBuffer.limit();
+
+ for(GATKChunk spanOverlapping: spansOverlapping) {
+ // Clear out the endcap tracking state and add in the starting position for this transfer.
+ blockOffsets.removeLast();
+ blockOffsets.add(buffer.position());
+ blockPositions.removeLast();
+ blockPositions.add(spanOverlapping.getChunkStart());
+
+ // Stream the buffer into the data stream.
+ incomingBuffer.limit((spanOverlapping.getBlockEnd() > spanOverlapping.getBlockStart()) ? bytesInIncomingBuffer : spanOverlapping.getBlockOffsetEnd());
+ incomingBuffer.position(spanOverlapping.getBlockOffsetStart());
+ buffer.put(incomingBuffer);
+
+ // Add the endcap for this transfer.
+ blockOffsets.add(buffer.position());
+ blockPositions.add(spanOverlapping.getChunkEnd());
+ }
+
+ // Set up the buffer for reading.
+ buffer.flip();
+
+ lock.notify();
+ }
+ catch(Exception ex) {
+ reportException(ex);
+ lock.notify();
+ }
+ }
+ }
+
+ void reportException(Throwable t) {
+ synchronized(lock) {
+ this.error = t;
+ lock.notify();
+ }
+ }
+
+ private void checkForErrors() {
+ synchronized(lock) {
+ if(error != null) {
+ ReviewedGATKException toThrow = new ReviewedGATKException(String.format("Thread %s, BlockInputStream %s: Unable to retrieve BAM data from disk",Thread.currentThread().getId(),this),error);
+ toThrow.setStackTrace(error.getStackTrace());
+ throw toThrow;
+ }
+ }
+ }
+
+ /**
+ * Reads the next byte of data from the input stream.
+ * @return Next byte of data, from 0->255, as an int.
+ */
+ @Override
+ public int read() {
+ byte[] singleByte = new byte[1];
+ read(singleByte);
+ return singleByte[0];
+ }
+
+ /**
+ * Fills the given byte array to the extent possible.
+ * @param bytes byte array to be filled.
+ * @return The number of bytes actually read.
+ */
+ @Override
+ public int read(byte[] bytes) {
+ return read(bytes,0,bytes.length);
+ }
+
+ @Override
+ public int read(byte[] bytes, final int offset, final int length) {
+ int remaining = length;
+ synchronized(lock) {
+ while(remaining > 0) {
+ // Check for error conditions during last read.
+ checkForErrors();
+
+ // If completely out of space, queue up another buffer fill.
+ waitForBufferFill();
+
+ // Couldn't manage to load any data at all; abort and return what's available.
+ if(buffer.remaining() == 0)
+ break;
+
+ int numBytesToCopy = Math.min(buffer.remaining(),remaining);
+ buffer.get(bytes,length-remaining+offset,numBytesToCopy);
+ remaining -= numBytesToCopy;
+
+ //if(remaining > 0)
+ // System.out.printf("Thread %s: read the first %d bytes of a %d byte request%n",Thread.currentThread().getId(),length-remaining,length);
+ // TODO: Assert that we don't copy across a block boundary
+ }
+
+ // Notify any waiting threads that some of the contents of the buffer were removed.
+ if(length-remaining > 0)
+ lock.notify();
+ }
+
+// if(validatingInputStream != null) {
+// byte[] validBytes = new byte[length];
+// try {
+// validatingInputStream.read(validBytes,offset,length);
+// for(int i = offset; i < offset+length; i++) {
+// if(bytes[i] != validBytes[i])
+// throw new ReviewedGATKException(String.format("Thread %s: blockInputStream %s attempting to return wrong set of bytes; mismatch at offset %d",Thread.currentThread().getId(),this,i));
+// }
+// }
+// catch(IOException ex) {
+// throw new ReviewedGATKException("Unable to validate against Picard input stream",ex);
+// }
+// }
+
+ // If any data was copied into the buffer, return the amount of data copied.
+ if(remaining < length)
+ return length - remaining;
+
+ // Otherwise, return -1.
+ return -1;
+ }
+
+ public void close() {
+ if(validatingInputStream != null) {
+ try {
+ validatingInputStream.close();
+ }
+ catch(IOException ex) {
+ throw new ReviewedGATKException("Unable to validate against Picard input stream",ex);
+ }
+ }
+ }
+
+ public String getSource() {
+ return reader.getSamFilePath();
+ }
+
+ private void waitForBufferFill() {
+ synchronized(lock) {
+ if(buffer.remaining() == 0 && !eof()) {
+ //System.out.printf("Thread %s is waiting for a buffer fill from position %d to buffer %s%n",Thread.currentThread().getId(),position.getBlockAddress(),this);
+ dispatcher.queueBlockLoad(accessPlan);
+ try {
+ lock.wait();
+ }
+ catch(InterruptedException ex) {
+ throw new ReviewedGATKException("Interrupt occurred waiting for buffer to fill",ex);
+ }
+ }
+ }
+ }
+
+ /**
+ * Create an encoded BAM file pointer given the address of a BGZF block and an offset.
+ * @param blockAddress Physical address on disk of a BGZF block.
+ * @param blockOffset Offset into the uncompressed data stored in the BGZF block.
+ * @return 64-bit pointer encoded according to the BAM spec.
+ */
+ public static long makeFilePointer(final long blockAddress, final int blockOffset) {
+ return blockAddress << 16 | blockOffset;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BlockLoader.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BlockLoader.java
new file mode 100644
index 0000000..09a0cab
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/BlockLoader.java
@@ -0,0 +1,189 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.util.BlockCompressedStreamConstants;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+/**
+ * An engine for loading blocks.
+ */
+class BlockLoader implements Runnable {
+ /**
+ * Coordinates the input queue.
+ */
+ private BGZFBlockLoadingDispatcher dispatcher;
+
+ /**
+ * A cache from which to retrieve open file handles.
+ */
+ private final FileHandleCache fileHandleCache;
+
+ /**
+ * Whether asynchronous decompression should happen.
+ */
+ private final boolean decompress;
+
+ /**
+ * An direct input buffer for incoming data from disk.
+ */
+ private final ByteBuffer inputBuffer;
+
+ public BlockLoader(final BGZFBlockLoadingDispatcher dispatcher, final FileHandleCache fileHandleCache, final boolean decompress) {
+ this.dispatcher = dispatcher;
+ this.fileHandleCache = fileHandleCache;
+ this.decompress = decompress;
+
+ this.inputBuffer = ByteBuffer.allocateDirect(64*1024 + BlockCompressedStreamConstants.EMPTY_GZIP_BLOCK.length);
+ inputBuffer.order(ByteOrder.LITTLE_ENDIAN);
+ }
+
+ public void run() {
+ for(;;) {
+ BAMAccessPlan accessPlan = null;
+ try {
+ accessPlan = dispatcher.claimNextWorkRequest();
+ FileInputStream inputStream = fileHandleCache.claimFileInputStream(accessPlan.getReader());
+
+ //long blockAddress = readerPosition.getBlockAddress();
+ //System.out.printf("Thread %s: BlockLoader: copying bytes from %s at position %d into %s%n",Thread.currentThread().getId(),inputStream,blockAddress,readerPosition.getInputStream());
+
+ ByteBuffer compressedBlock = readBGZFBlock(inputStream,accessPlan.getBlockAddress());
+ long nextBlockAddress = position(inputStream);
+ fileHandleCache.releaseFileInputStream(accessPlan.getReader(),inputStream);
+
+ ByteBuffer block = decompress ? decompressBGZFBlock(compressedBlock) : compressedBlock;
+ int bytesCopied = block.remaining();
+
+ BlockInputStream bamInputStream = accessPlan.getInputStream();
+ bamInputStream.copyIntoBuffer(block,accessPlan,nextBlockAddress);
+
+ //System.out.printf("Thread %s: BlockLoader: copied %d bytes from %s at position %d into %s%n",Thread.currentThread().getId(),bytesCopied,inputStream,blockAddress,readerPosition.getInputStream());
+ }
+ catch(Throwable error) {
+ if(accessPlan != null && accessPlan.getInputStream() != null)
+ accessPlan.getInputStream().reportException(error);
+ }
+ }
+
+ }
+
+ private ByteBuffer readBGZFBlock(final FileInputStream inputStream, final long blockAddress) throws IOException {
+ FileChannel channel = inputStream.getChannel();
+
+ // Read the block header
+ channel.position(blockAddress);
+
+ int uncompressedDataSize = 0;
+ int bufferSize = 0;
+
+ do {
+ inputBuffer.clear();
+ inputBuffer.limit(BlockCompressedStreamConstants.BLOCK_HEADER_LENGTH);
+ channel.read(inputBuffer);
+
+ // Read out the size of the full BGZF block into a two bit short container, then 'or' that
+ // value into an int buffer to transfer the bitwise contents into an int.
+ inputBuffer.flip();
+ if(inputBuffer.remaining() != BlockCompressedStreamConstants.BLOCK_HEADER_LENGTH)
+ throw new ReviewedGATKException("BUG: unable to read a the complete block header in one pass.");
+
+ // Verify that the file was read at a valid point.
+ if(unpackUByte8(inputBuffer,0) != BlockCompressedStreamConstants.GZIP_ID1 ||
+ unpackUByte8(inputBuffer,1) != BlockCompressedStreamConstants.GZIP_ID2 ||
+ unpackUByte8(inputBuffer,3) != BlockCompressedStreamConstants.GZIP_FLG ||
+ unpackUInt16(inputBuffer,10) != BlockCompressedStreamConstants.GZIP_XLEN ||
+ unpackUByte8(inputBuffer,12) != BlockCompressedStreamConstants.BGZF_ID1 ||
+ unpackUByte8(inputBuffer,13) != BlockCompressedStreamConstants.BGZF_ID2) {
+ throw new ReviewedGATKException("BUG: Started reading compressed block at incorrect position");
+ }
+
+ inputBuffer.position(BlockCompressedStreamConstants.BLOCK_LENGTH_OFFSET);
+ bufferSize = unpackUInt16(inputBuffer,BlockCompressedStreamConstants.BLOCK_LENGTH_OFFSET)+1;
+
+ // Adjust buffer limits and finish reading the block. Also read the next header, just in case there's a 0-byte block.
+ inputBuffer.limit(bufferSize);
+ inputBuffer.position(BlockCompressedStreamConstants.BLOCK_HEADER_LENGTH);
+ channel.read(inputBuffer);
+
+ // Check the uncompressed length. If 0 and not at EOF, we'll want to check the next block.
+ uncompressedDataSize = inputBuffer.getInt(inputBuffer.limit()-4);
+ //System.out.printf("Uncompressed block size of the current block (at position %d) is %d%n",channel.position()-inputBuffer.limit(),uncompressedDataSize);
+ }
+ while(uncompressedDataSize == 0 && channel.position() < channel.size());
+
+ // Prepare the buffer for reading.
+ inputBuffer.flip();
+
+ return inputBuffer;
+ }
+
+ private ByteBuffer decompressBGZFBlock(final ByteBuffer bgzfBlock) throws DataFormatException {
+ final int compressedBufferSize = bgzfBlock.remaining();
+
+ // Determine the uncompressed buffer size (
+ bgzfBlock.position(bgzfBlock.limit()-4);
+ int uncompressedBufferSize = bgzfBlock.getInt();
+ byte[] uncompressedContent = new byte[uncompressedBufferSize];
+
+ // Bound the CDATA section of the buffer.
+ bgzfBlock.limit(compressedBufferSize-BlockCompressedStreamConstants.BLOCK_FOOTER_LENGTH);
+ bgzfBlock.position(BlockCompressedStreamConstants.BLOCK_HEADER_LENGTH);
+ byte[] compressedContent = new byte[bgzfBlock.remaining()];
+ ByteBuffer.wrap(compressedContent).put(bgzfBlock);
+
+ // Decompress the buffer.
+ final Inflater inflater = new Inflater(true);
+ inflater.setInput(compressedContent);
+ int bytesUncompressed = inflater.inflate(uncompressedContent);
+ if(bytesUncompressed != uncompressedBufferSize)
+ throw new ReviewedGATKException("Error decompressing block");
+
+ return ByteBuffer.wrap(uncompressedContent);
+ }
+
+ private long position(final FileInputStream inputStream) throws IOException {
+ return inputStream.getChannel().position();
+ }
+
+ private int unpackUByte8(final ByteBuffer buffer,final int position) {
+ return buffer.get(position) & 0xFF;
+ }
+
+ private int unpackUInt16(final ByteBuffer buffer,final int position) {
+ // Read out the size of the full BGZF block into a two bit short container, then 'or' that
+ // value into an int buffer to transfer the bitwise contents into an int.
+ return buffer.getShort(position) & 0xFFFF;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/FileHandleCache.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/FileHandleCache.java
new file mode 100644
index 0000000..8d5ab3b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/FileHandleCache.java
@@ -0,0 +1,232 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+
+/**
+ * Caches frequently used file handles. Right now, caches only a single file handle.
+ * TODO: Generalize to support arbitrary file handle caches.
+ */
+public class FileHandleCache {
+ /**
+ * The underlying data structure storing file handles.
+ */
+ private final FileHandleStorage fileHandleStorage;
+
+ /**
+ * How many file handles should be kept open at once.
+ */
+ private final int cacheSize;
+
+ /**
+ * A uniquifier: assign a unique ID to every instance of a file handle.
+ */
+ private final Map<SAMReaderID,Integer> keyCounter = new HashMap<SAMReaderID,Integer>();
+
+ /**
+ * A shared lock, private so that outside users cannot notify it.
+ */
+ private final Object lock = new Object();
+
+ /**
+ * Indicates how many file handles are outstanding at this point.
+ */
+ private int numOutstandingFileHandles = 0;
+
+ /**
+ * Create a new file handle cache of the given cache size.
+ * @param cacheSize how many readers to hold open at once.
+ */
+ public FileHandleCache(final int cacheSize) {
+ this.cacheSize = cacheSize;
+ fileHandleStorage = new FileHandleStorage();
+ }
+
+ /**
+ * Retrieves or opens a file handle for the given reader ID.
+ * @param key The ke
+ * @return A file input stream from the cache, if available, or otherwise newly opened.
+ */
+ public FileInputStream claimFileInputStream(final SAMReaderID key) {
+ synchronized(lock) {
+ FileInputStream inputStream = findExistingEntry(key);
+ if(inputStream == null) {
+ try {
+ // If the cache is maxed out, wait for another file handle to emerge.
+ if(numOutstandingFileHandles >= cacheSize)
+ lock.wait();
+ }
+ catch(InterruptedException ex) {
+ throw new ReviewedGATKException("Interrupted while waiting for a file handle");
+ }
+ inputStream = openInputStream(key);
+ }
+ numOutstandingFileHandles++;
+
+ //System.out.printf("Handing input stream %s to thread %s%n",inputStream,Thread.currentThread().getId());
+ return inputStream;
+ }
+ }
+
+ /**
+ * Releases the current reader and returns it to the cache.
+ * @param key The reader.
+ * @param inputStream The stream being used.
+ */
+ public void releaseFileInputStream(final SAMReaderID key, final FileInputStream inputStream) {
+ synchronized(lock) {
+ numOutstandingFileHandles--;
+ UniqueKey newID = allocateKey(key);
+ fileHandleStorage.put(newID,inputStream);
+ // Let any listeners know that another file handle has become available.
+ lock.notify();
+ }
+ }
+
+ /**
+ * Finds an existing entry in the storage mechanism.
+ * @param key Reader.
+ * @return a cached stream, if available. Otherwise,
+ */
+ private FileInputStream findExistingEntry(final SAMReaderID key) {
+ int existingHandles = getMostRecentUniquifier(key);
+
+ // See if any of the keys currently exist in the repository.
+ for(int i = 0; i <= existingHandles; i++) {
+ UniqueKey uniqueKey = new UniqueKey(key,i);
+ if(fileHandleStorage.containsKey(uniqueKey))
+ return fileHandleStorage.remove(uniqueKey);
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets the most recent uniquifier used for the given reader.
+ * @param reader Reader for which to determine uniqueness.
+ * @return
+ */
+ private int getMostRecentUniquifier(final SAMReaderID reader) {
+ if(keyCounter.containsKey(reader))
+ return keyCounter.get(reader);
+ else return -1;
+ }
+
+ private UniqueKey allocateKey(final SAMReaderID reader) {
+ int uniquifier = getMostRecentUniquifier(reader)+1;
+ keyCounter.put(reader,uniquifier);
+ return new UniqueKey(reader,uniquifier);
+ }
+
+ private FileInputStream openInputStream(final SAMReaderID reader) {
+ try {
+ return new FileInputStream(reader.getSamFilePath());
+ }
+ catch(IOException ex) {
+ throw new GATKException("Unable to open input file");
+ }
+ }
+
+ private void closeInputStream(final FileInputStream inputStream) {
+ try {
+ inputStream.close();
+ }
+ catch(IOException ex) {
+ throw new GATKException("Unable to open input file");
+ }
+ }
+
+ /**
+ * Actually contains the file handles, purging them as they get too old.
+ */
+ private class FileHandleStorage extends LinkedHashMap<UniqueKey,FileInputStream> {
+ /**
+ * Remove the oldest entry
+ * @param entry Entry to consider removing.
+ * @return True if the cache size has been exceeded. False otherwise.
+ */
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<UniqueKey,FileInputStream> entry) {
+ synchronized (lock) {
+ if(size() > cacheSize) {
+ keyCounter.put(entry.getKey().key,keyCounter.get(entry.getKey().key)-1);
+ closeInputStream(entry.getValue());
+
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Uniquifies a key by adding a numerical uniquifier.
+ */
+ private class UniqueKey {
+ /**
+ * The file handle's key.
+ */
+ private final SAMReaderID key;
+
+ /**
+ * A uniquifier, so that multiple of the same reader can exist in the cache.
+ */
+ private final int uniqueID;
+
+ public UniqueKey(final SAMReaderID reader, final int uniqueID) {
+ this.key = reader;
+ this.uniqueID = uniqueID;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if(!(other instanceof UniqueKey))
+ return false;
+ UniqueKey otherUniqueKey = (UniqueKey)other;
+ return key.equals(otherUniqueKey.key) && this.uniqueID == otherUniqueKey.uniqueID;
+ }
+
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+ }
+
+
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/FilePointer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/FilePointer.java
new file mode 100644
index 0000000..99d9def
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/FilePointer.java
@@ -0,0 +1,436 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.util.PeekableIterator;
+import htsjdk.samtools.GATKBAMFileSpan;
+import htsjdk.samtools.GATKChunk;
+import htsjdk.samtools.SAMFileSpan;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.interval.IntervalUtils;
+
+import java.util.*;
+
+/**
+ * Represents a small section of a BAM file, and every associated interval.
+ */
+public class FilePointer {
+ protected final SortedMap<SAMReaderID,SAMFileSpan> fileSpans = new TreeMap<SAMReaderID,SAMFileSpan>();
+ protected final List<GenomeLoc> locations = new ArrayList<GenomeLoc>();
+ protected final IntervalMergingRule intervalMergingRule;
+
+ /**
+ * Does this file pointer point into an unmapped region?
+ */
+ protected final boolean isRegionUnmapped;
+
+ /**
+ * Is this FilePointer "monolithic"? That is, does it represent all regions in all files that we will
+ * ever visit during this GATK run? If this is set to true, the engine will expect to see only this
+ * one FilePointer during the entire run, and this FilePointer will be allowed to contain intervals
+ * from more than one contig.
+ */
+ private boolean isMonolithic = false;
+
+ /**
+ * Index of the contig covered by this FilePointer. Only meaningful for non-monolithic, mapped FilePointers
+ */
+ private Integer contigIndex = null;
+
+
+ public FilePointer( final IntervalMergingRule mergeRule, final List<GenomeLoc> locations ) {
+ this.intervalMergingRule = mergeRule;
+ this.locations.addAll(locations);
+ this.isRegionUnmapped = checkUnmappedStatus();
+
+ validateAllLocations();
+ if ( locations.size() > 0 ) {
+ contigIndex = locations.get(0).getContigIndex();
+ }
+ }
+
+ public FilePointer( final IntervalMergingRule mergeRule, final GenomeLoc... locations ) {
+ this(mergeRule, Arrays.asList(locations));
+ }
+
+ public FilePointer( final Map<SAMReaderID,SAMFileSpan> fileSpans, final IntervalMergingRule mergeRule, final List<GenomeLoc> locations ) {
+ this(mergeRule, locations);
+ this.fileSpans.putAll(fileSpans);
+ }
+
+ private boolean checkUnmappedStatus() {
+ boolean foundMapped = false, foundUnmapped = false;
+
+ for( GenomeLoc location: locations ) {
+ if ( GenomeLoc.isUnmapped(location) )
+ foundUnmapped = true;
+ else
+ foundMapped = true;
+ }
+ if ( foundMapped && foundUnmapped )
+ throw new ReviewedGATKException("BUG: File pointers cannot be mixed mapped/unmapped.");
+
+ return foundUnmapped;
+ }
+
+ private void validateAllLocations() {
+ // Unmapped and monolithic FilePointers are exempted from the one-contig-only restriction
+ if ( isRegionUnmapped || isMonolithic ) {
+ return;
+ }
+
+ Integer previousContigIndex = null;
+
+ for ( GenomeLoc location : locations ) {
+ if ( previousContigIndex != null && previousContigIndex != location.getContigIndex() ) {
+ throw new ReviewedGATKException("Non-monolithic file pointers must contain intervals from at most one contig");
+ }
+
+ previousContigIndex = location.getContigIndex();
+ }
+ }
+
+ private void validateLocation( GenomeLoc location ) {
+ if ( isRegionUnmapped != GenomeLoc.isUnmapped(location) ) {
+ throw new ReviewedGATKException("BUG: File pointers cannot be mixed mapped/unmapped.");
+ }
+ if ( ! isRegionUnmapped && ! isMonolithic && contigIndex != null && contigIndex != location.getContigIndex() ) {
+ throw new ReviewedGATKException("Non-monolithic file pointers must contain intervals from at most one contig");
+ }
+ }
+
+ /**
+ * Returns an immutable view of this FilePointer's file spans
+ *
+ * @return an immutable view of this FilePointer's file spans
+ */
+ public Map<SAMReaderID, SAMFileSpan> getFileSpans() {
+ return Collections.unmodifiableMap(fileSpans);
+ }
+
+ /**
+ * Returns an immutable variant of the list of locations.
+ * @return
+ */
+ public List<GenomeLoc> getLocations() {
+ return Collections.unmodifiableList(locations);
+ }
+
+ /**
+ * Returns the index of the contig into which this FilePointer points (a FilePointer can represent
+ * regions in at most one contig).
+ *
+ * @return the index of the contig into which this FilePointer points
+ */
+ public int getContigIndex() {
+ return locations.size() > 0 ? locations.get(0).getContigIndex() : SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX;
+ }
+
+ /**
+ * Returns the IntervalMergingRule used by this FilePointer to merge adjacent locations
+ *
+ * @return the IntervalMergingRule used by this FilePointer (never null)
+ */
+ public IntervalMergingRule getIntervalMergingRule() {
+ return intervalMergingRule;
+ }
+
+ /**
+ * Is this FilePointer "monolithic"? That is, does it represent all regions in all files that we will
+ * ever visit during this GATK run? If this is set to true, the engine will expect to see only this
+ * one FilePointer during the entire run, and this FilePointer will be allowed to contain intervals
+ * from more than one contig.
+ *
+ * @return true if this FP is a monolithic FP representing all regions in all files, otherwise false
+ */
+ public boolean isMonolithic() {
+ return isMonolithic;
+ }
+
+ /**
+ * Set this FP's "monolithic" status to true or false. An FP is monolithic if it represents all
+ * regions in all files that we will ever visit, and is the only FP we will ever create. A monolithic
+ * FP may contain intervals from more than one contig.
+ *
+ * @param isMonolithic set this FP's monolithic status to this value
+ */
+ public void setIsMonolithic( boolean isMonolithic ) {
+ this.isMonolithic = isMonolithic;
+ }
+
+ @Override
+ public boolean equals(final Object other) {
+ if(!(other instanceof FilePointer))
+ return false;
+ FilePointer otherFilePointer = (FilePointer)other;
+
+ // intervals
+ if(this.locations.size() != otherFilePointer.locations.size())
+ return false;
+ for(int i = 0; i < locations.size(); i++) {
+ if(!this.locations.get(i).equals(otherFilePointer.locations.get(i)))
+ return false;
+ }
+
+ // fileSpans
+ if(this.fileSpans.size() != otherFilePointer.fileSpans.size())
+ return false;
+ Iterator<Map.Entry<SAMReaderID,SAMFileSpan>> thisEntries = this.fileSpans.entrySet().iterator();
+ Iterator<Map.Entry<SAMReaderID,SAMFileSpan>> otherEntries = otherFilePointer.fileSpans.entrySet().iterator();
+ while(thisEntries.hasNext() || otherEntries.hasNext()) {
+ if(!thisEntries.next().equals(otherEntries.next()))
+ return false;
+ }
+
+ return true;
+ }
+
+ public void addLocation(final GenomeLoc location) {
+ validateLocation(location);
+
+ this.locations.add(location);
+ if ( contigIndex == null ) {
+ contigIndex = location.getContigIndex();
+ }
+ }
+
+ public void addFileSpans(final SAMReaderID id, final SAMFileSpan fileSpan) {
+ this.fileSpans.put(id,fileSpan);
+ }
+
+ public void addFileSpans(final Map<SAMReaderID, GATKBAMFileSpan> fileSpans) {
+ this.fileSpans.putAll(fileSpans);
+ }
+
+
+ /**
+ * Computes the size of this file span, in uncompressed bytes.
+ * @return Size of the file span.
+ */
+ public long size() {
+ long size = 0L;
+ for(SAMFileSpan fileSpan: fileSpans.values())
+ size += ((GATKBAMFileSpan)fileSpan).size();
+ return size;
+ }
+
+ /**
+ * Returns the difference in size between two filespans.
+ * @param other Other filespan against which to measure.
+ * @return The difference in size between the two file pointers.
+ */
+ public long minus(final FilePointer other) {
+ long difference = 0;
+ PeekableIterator<Map.Entry<SAMReaderID,SAMFileSpan>> thisIterator = new PeekableIterator<Map.Entry<SAMReaderID,SAMFileSpan>>(this.fileSpans.entrySet().iterator());
+ PeekableIterator<Map.Entry<SAMReaderID,SAMFileSpan>> otherIterator = new PeekableIterator<Map.Entry<SAMReaderID,SAMFileSpan>>(other.fileSpans.entrySet().iterator());
+
+ while(thisIterator.hasNext()) {
+ // If there are no elements left in the 'other' iterator, spin out this iterator.
+ if(!otherIterator.hasNext()) {
+ GATKBAMFileSpan nextSpan = (GATKBAMFileSpan)thisIterator.next().getValue();
+ difference += nextSpan.size();
+ continue;
+ }
+
+ // Otherwise, compare the latest value.
+ int compareValue = thisIterator.peek().getKey().compareTo(otherIterator.peek().getKey());
+
+ if(compareValue < 0) {
+ // This before other.
+ difference += ((GATKBAMFileSpan)thisIterator.next().getValue()).size();
+ }
+ else if(compareValue > 0) {
+ // Other before this.
+ difference += ((GATKBAMFileSpan)otherIterator.next().getValue()).size();
+ }
+ else {
+ // equality; difference the values.
+ GATKBAMFileSpan thisRegion = (GATKBAMFileSpan)thisIterator.next().getValue();
+ GATKBAMFileSpan otherRegion = (GATKBAMFileSpan)otherIterator.next().getValue();
+ difference += Math.abs(thisRegion.minus(otherRegion).size());
+ }
+ }
+ return difference;
+ }
+
+ /**
+ * Combines two file pointers into one.
+ * @param parser The genomelocparser to use when manipulating intervals.
+ * @param other File pointer to combine into this one.
+ * @return A completely new file pointer that is the combination of the two.
+ */
+ public FilePointer combine(final GenomeLocParser parser, final FilePointer other) {
+ FilePointer combined = new FilePointer(intervalMergingRule);
+
+ List<GenomeLoc> intervals = new ArrayList<GenomeLoc>();
+ intervals.addAll(locations);
+ intervals.addAll(other.locations);
+ for(GenomeLoc interval: IntervalUtils.sortAndMergeIntervals(parser,intervals,intervalMergingRule))
+ combined.addLocation(interval);
+
+ PeekableIterator<Map.Entry<SAMReaderID,SAMFileSpan>> thisIterator = new PeekableIterator<Map.Entry<SAMReaderID,SAMFileSpan>>(this.fileSpans.entrySet().iterator());
+ PeekableIterator<Map.Entry<SAMReaderID,SAMFileSpan>> otherIterator = new PeekableIterator<Map.Entry<SAMReaderID,SAMFileSpan>>(other.fileSpans.entrySet().iterator());
+
+ while(thisIterator.hasNext() || otherIterator.hasNext()) {
+ int compareValue;
+ if(!otherIterator.hasNext()) {
+ compareValue = -1;
+ }
+ else if(!thisIterator.hasNext())
+ compareValue = 1;
+ else
+ compareValue = thisIterator.peek().getKey().compareTo(otherIterator.peek().getKey());
+
+ // This before other.
+ if(compareValue < 0)
+ mergeElementsInto(combined,thisIterator);
+ // Other before this.
+ else if(compareValue > 0)
+ mergeElementsInto(combined,otherIterator);
+ // equality; union the values.
+ else
+ mergeElementsInto(combined,thisIterator,otherIterator);
+ }
+ return combined;
+ }
+
+ /**
+ * Roll the next element in the iterator into the combined entry.
+ * @param combined Entry into which to roll the next element.
+ * @param iterators Sources of next elements.
+ */
+ private void mergeElementsInto(final FilePointer combined, Iterator<Map.Entry<SAMReaderID,SAMFileSpan>>... iterators) {
+ if(iterators.length == 0)
+ throw new ReviewedGATKException("Tried to add zero elements to an existing file pointer.");
+ Map.Entry<SAMReaderID,SAMFileSpan> initialElement = iterators[0].next();
+ GATKBAMFileSpan fileSpan = (GATKBAMFileSpan)initialElement.getValue();
+ for(int i = 1; i < iterators.length; i++)
+ fileSpan = fileSpan.union((GATKBAMFileSpan)iterators[i].next().getValue());
+ combined.addFileSpans(initialElement.getKey(),fileSpan);
+ }
+
+ /**
+ * Efficiently generate the union of the n FilePointers passed in. Much more efficient than
+ * combining two FilePointers at a time using the combine() method above.
+ *
+ * IMPORTANT: the FilePointers to be unioned must either all represent regions on the
+ * same contig, or all be unmapped, since we cannot create FilePointers with a mix of
+ * contigs or with mixed mapped/unmapped regions.
+ *
+ * @param filePointers the FilePointers to union
+ * @param parser our GenomeLocParser
+ * @return the union of the FilePointers passed in
+ */
+ public static FilePointer union( List<FilePointer> filePointers, GenomeLocParser parser ) {
+ if ( filePointers == null || filePointers.isEmpty() ) {
+ return new FilePointer(IntervalMergingRule.ALL);
+ }
+
+ Map<SAMReaderID, List<GATKChunk>> fileChunks = new HashMap<SAMReaderID, List<GATKChunk>>();
+ List<GenomeLoc> locations = new ArrayList<GenomeLoc>();
+ IntervalMergingRule mergeRule = filePointers.get(0).getIntervalMergingRule();
+
+ // First extract all intervals and file chunks from the FilePointers into unsorted, unmerged collections
+ for ( FilePointer filePointer : filePointers ) {
+ locations.addAll(filePointer.getLocations());
+ if (mergeRule != filePointer.getIntervalMergingRule())
+ throw new ReviewedGATKException("All FilePointers in FilePointer.union() must have use the same IntervalMergeRule");
+
+ for ( Map.Entry<SAMReaderID, SAMFileSpan> fileSpanEntry : filePointer.getFileSpans().entrySet() ) {
+ GATKBAMFileSpan fileSpan = (GATKBAMFileSpan)fileSpanEntry.getValue();
+
+ if ( fileChunks.containsKey(fileSpanEntry.getKey()) ) {
+ fileChunks.get(fileSpanEntry.getKey()).addAll(fileSpan.getGATKChunks());
+ }
+ else {
+ fileChunks.put(fileSpanEntry.getKey(), fileSpan.getGATKChunks());
+ }
+ }
+ }
+
+ // Now sort and merge the intervals
+ List<GenomeLoc> sortedMergedLocations = new ArrayList<GenomeLoc>();
+ sortedMergedLocations.addAll(IntervalUtils.sortAndMergeIntervals(parser, locations, mergeRule));
+
+ // For each BAM file, convert from an unsorted, unmerged list of chunks to a GATKBAMFileSpan containing
+ // the sorted, merged union of the chunks for that file
+ Map<SAMReaderID, SAMFileSpan> mergedFileSpans = new HashMap<SAMReaderID, SAMFileSpan>(fileChunks.size());
+ for ( Map.Entry<SAMReaderID, List<GATKChunk>> fileChunksEntry : fileChunks.entrySet() ) {
+ List<GATKChunk> unmergedChunks = fileChunksEntry.getValue();
+ mergedFileSpans.put(fileChunksEntry.getKey(),
+ (new GATKBAMFileSpan(unmergedChunks.toArray(new GATKChunk[unmergedChunks.size()]))).union(new GATKBAMFileSpan()));
+ }
+
+ return new FilePointer(mergedFileSpans, mergeRule, sortedMergedLocations);
+ }
+
+ /**
+ * Returns true if any of the file spans in this FilePointer overlap their counterparts in
+ * the other FilePointer. "Overlap" is defined as having an overlapping extent (the region
+ * from the start of the first chunk to the end of the last chunk).
+ *
+ * @param other the FilePointer against which to check overlap with this FilePointer
+ * @return true if any file spans overlap their counterparts in other, otherwise false
+ */
+ public boolean hasFileSpansOverlappingWith( FilePointer other ) {
+ for ( Map.Entry<SAMReaderID, SAMFileSpan> thisFilePointerEntry : fileSpans.entrySet() ) {
+ GATKBAMFileSpan thisFileSpan = new GATKBAMFileSpan(thisFilePointerEntry.getValue());
+
+ SAMFileSpan otherEntry = other.fileSpans.get(thisFilePointerEntry.getKey());
+ if ( otherEntry == null ) {
+ continue; // no counterpart for this file span in other
+ }
+ GATKBAMFileSpan otherFileSpan = new GATKBAMFileSpan(otherEntry);
+
+ if ( thisFileSpan.getExtent().overlaps(otherFileSpan.getExtent()) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("FilePointer:\n");
+ builder.append("\tlocations = {");
+ builder.append(Utils.join(";",locations));
+ builder.append("}\n\tregions = \n");
+ for(Map.Entry<SAMReaderID,SAMFileSpan> entry: fileSpans.entrySet()) {
+ builder.append(entry.getKey());
+ builder.append("= {");
+ builder.append(entry.getValue());
+ builder.append("}");
+ }
+ return builder.toString();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/GATKBAMIndex.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/GATKBAMIndex.java
new file mode 100644
index 0000000..17afd58
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/GATKBAMIndex.java
@@ -0,0 +1,468 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.Bin;
+import htsjdk.samtools.GATKBin;
+import htsjdk.samtools.GATKChunk;
+import htsjdk.samtools.LinearIndex;
+import htsjdk.samtools.seekablestream.SeekableBufferedStream;
+import htsjdk.samtools.seekablestream.SeekableFileStream;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A basic interface for querying BAM indices.
+ * Very much not thread-safe.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class GATKBAMIndex {
+ /**
+ * BAM index file magic number.
+ */
+ private static final byte[] BAM_INDEX_MAGIC = "BAI\1".getBytes();
+
+ /**
+ * Reports the total amount of genomic data that any bin can index.
+ */
+ protected static final int BIN_GENOMIC_SPAN = 512*1024*1024;
+
+ /**
+ * What is the starting bin for each level?
+ */
+ private static final int[] LEVEL_STARTS = {0,1,9,73,585,4681};
+
+ /**
+ * Reports the maximum number of bins that can appear in a BAM file.
+ */
+ public static final int MAX_BINS = 37450; // =(8^6-1)/7+1
+
+ private final File mFile;
+
+ //TODO: figure out a good value for this buffer size
+ private final int BUFFERED_STREAM_BUFFER_SIZE = 8192;
+
+ /**
+ * Number of sequences stored in this index.
+ */
+ private final int sequenceCount;
+
+ /**
+ * A cache of the starting positions of the sequences.
+ */
+ private final long[] sequenceStartCache;
+
+ private SeekableFileStream fileStream;
+ private SeekableBufferedStream bufferedStream;
+ private long fileLength;
+
+ public GATKBAMIndex(final File file) {
+ mFile = file;
+ // Open the file stream.
+ openIndexFile();
+
+ // Verify the magic number.
+ seek(0);
+ final byte[] buffer = readBytes(4);
+ if (!Arrays.equals(buffer, BAM_INDEX_MAGIC)) {
+ throw new ReviewedGATKException("Invalid file header in BAM index " + mFile +
+ ": " + new String(buffer));
+ }
+
+ seek(4);
+
+ sequenceCount = readInteger();
+
+ // Create a cache of the starting position of each sequence. Initialize it to -1.
+ sequenceStartCache = new long[sequenceCount];
+ for(int i = 1; i < sequenceCount; i++)
+ sequenceStartCache[i] = -1;
+
+ // Seed the first element in the array with the current position.
+ if(sequenceCount > 0)
+ sequenceStartCache[0] = position();
+
+ closeIndexFile();
+ }
+
+ public GATKBAMIndexData readReferenceSequence(final int referenceSequence) {
+ openIndexFile();
+
+ if (referenceSequence >= sequenceCount)
+ throw new ReviewedGATKException("Invalid sequence number " + referenceSequence + " in index file " + mFile);
+
+ skipToSequence(referenceSequence);
+
+ int binCount = readInteger();
+ List<GATKBin> bins = new ArrayList<GATKBin>();
+ for (int binNumber = 0; binNumber < binCount; binNumber++) {
+ final int indexBin = readInteger();
+ final int nChunks = readInteger();
+
+ List<GATKChunk> chunks = new ArrayList<GATKChunk>(nChunks);
+ long[] rawChunkData = readLongs(nChunks*2);
+ for (int ci = 0; ci < nChunks; ci++) {
+ final long chunkBegin = rawChunkData[ci*2];
+ final long chunkEnd = rawChunkData[ci*2+1];
+ chunks.add(new GATKChunk(chunkBegin, chunkEnd));
+ }
+ GATKBin bin = new GATKBin(referenceSequence, indexBin);
+ bin.setChunkList(chunks.toArray(new GATKChunk[chunks.size()]));
+ while(indexBin >= bins.size())
+ bins.add(null);
+ bins.set(indexBin,bin);
+ }
+
+ final int nLinearBins = readInteger();
+ long[] linearIndexEntries = readLongs(nLinearBins);
+
+ LinearIndex linearIndex = new LinearIndex(referenceSequence,0,linearIndexEntries);
+
+ closeIndexFile();
+
+ return new GATKBAMIndexData(this,referenceSequence,bins,linearIndex);
+ }
+
+ /**
+ * Get the number of levels employed by this index.
+ * @return Number of levels in this index.
+ */
+ public static int getNumIndexLevels() {
+ return LEVEL_STARTS.length;
+ }
+
+ /**
+ * Gets the first bin in the given level.
+ * @param levelNumber Level number. 0-based.
+ * @return The first bin in this level.
+ */
+ public static int getFirstBinInLevel(final int levelNumber) {
+ return LEVEL_STARTS[levelNumber];
+ }
+
+ /**
+ * Gets the number of bins in the given level.
+ * @param levelNumber Level number. 0-based.
+ * @return The size (number of possible bins) of the given level.
+ */
+ public int getLevelSize(final int levelNumber) {
+ if(levelNumber == getNumIndexLevels()-1)
+ return MAX_BINS-LEVEL_STARTS[levelNumber]-1;
+ else
+ return LEVEL_STARTS[levelNumber+1]-LEVEL_STARTS[levelNumber];
+ }
+
+ /**
+ * Gets the level associated with the given bin number.
+ * @param bin The bin for which to determine the level.
+ * @return the level associated with the given bin number.
+ */
+ public int getLevelForBin(final Bin bin) {
+ GATKBin gatkBin = new GATKBin(bin);
+ if(gatkBin.getBinNumber() >= MAX_BINS)
+ throw new ReviewedGATKException("Tried to get level for invalid bin in index file " + mFile);
+ for(int i = getNumIndexLevels()-1; i >= 0; i--) {
+ if(gatkBin.getBinNumber() >= LEVEL_STARTS[i])
+ return i;
+ }
+ throw new ReviewedGATKException("Unable to find correct bin for bin " + bin + " in index file " + mFile);
+ }
+
+ /**
+ * Gets the first locus that this bin can index into.
+ * @param bin The bin to test.
+ * @return The last position that the given bin can represent.
+ */
+ public int getFirstLocusInBin(final Bin bin) {
+ final int level = getLevelForBin(bin);
+ final int levelStart = LEVEL_STARTS[level];
+ final int levelSize = ((level==getNumIndexLevels()-1) ? MAX_BINS-1 : LEVEL_STARTS[level+1]) - levelStart;
+ return (new GATKBin(bin).getBinNumber() - levelStart)*(BIN_GENOMIC_SPAN /levelSize)+1;
+ }
+
+ /**
+ * Gets the last locus that this bin can index into.
+ * @param bin The bin to test.
+ * @return The last position that the given bin can represent.
+ */
+ public int getLastLocusInBin(final Bin bin) {
+ final int level = getLevelForBin(bin);
+ final int levelStart = LEVEL_STARTS[level];
+ final int levelSize = ((level==getNumIndexLevels()-1) ? MAX_BINS-1 : LEVEL_STARTS[level+1]) - levelStart;
+ return (new GATKBin(bin).getBinNumber()-levelStart+1)*(BIN_GENOMIC_SPAN /levelSize);
+ }
+
+ /**
+ * Use to get close to the unmapped reads at the end of a BAM file.
+ * @return The file offset of the first record in the last linear bin, or -1
+ * if there are no elements in linear bins (i.e. no mapped reads).
+ */
+ public long getStartOfLastLinearBin() {
+ openIndexFile();
+
+ seek(4);
+
+ final int sequenceCount = readInteger();
+ // Because no reads may align to the last sequence in the sequence dictionary,
+ // grab the last element of the linear index for each sequence, and return
+ // the last one from the last sequence that has one.
+ long lastLinearIndexPointer = -1;
+ for (int i = 0; i < sequenceCount; i++) {
+ // System.out.println("# Sequence TID: " + i);
+ final int nBins = readInteger();
+ // System.out.println("# nBins: " + nBins);
+ for (int j1 = 0; j1 < nBins; j1++) {
+ // Skip bin #
+ skipBytes(4);
+ final int nChunks = readInteger();
+ // Skip chunks
+ skipBytes(16 * nChunks);
+ }
+ final int nLinearBins = readInteger();
+ if (nLinearBins > 0) {
+ // Skip to last element of list of linear bins
+ skipBytes(8 * (nLinearBins - 1));
+ lastLinearIndexPointer = readLongs(1)[0];
+ }
+ }
+
+ closeIndexFile();
+
+ return lastLinearIndexPointer;
+ }
+
+ /**
+ * Gets the possible number of bins for a given reference sequence.
+ * @return How many bins could possibly be used according to this indexing scheme to index a single contig.
+ */
+ protected int getMaxAddressibleGenomicLocation() {
+ return BIN_GENOMIC_SPAN;
+ }
+
+ protected void skipToSequence(final int referenceSequence) {
+ // Find the offset in the file of the last sequence whose position has been determined. Start here
+ // when searching the sequence for the next value to read. (Note that sequenceStartCache[0] will always
+ // be present, so no extra stopping condition is necessary.
+ int sequenceIndex = referenceSequence;
+ while(sequenceStartCache[sequenceIndex] == -1)
+ sequenceIndex--;
+
+ // Advance to the most recently found position.
+ seek(sequenceStartCache[sequenceIndex]);
+
+ for (int i = sequenceIndex; i < referenceSequence; i++) {
+ sequenceStartCache[i] = position();
+ // System.out.println("# Sequence TID: " + i);
+ final int nBins = readInteger();
+ // System.out.println("# nBins: " + nBins);
+ for (int j = 0; j < nBins; j++) {
+ final int bin = readInteger();
+ final int nChunks = readInteger();
+ // System.out.println("# bin[" + j + "] = " + bin + ", nChunks = " + nChunks);
+ skipBytes(16 * nChunks);
+ }
+ final int nLinearBins = readInteger();
+ // System.out.println("# nLinearBins: " + nLinearBins);
+ skipBytes(8 * nLinearBins);
+
+ }
+
+ sequenceStartCache[referenceSequence] = position();
+ }
+
+
+
+ private void openIndexFile() {
+ try {
+ fileStream = new SeekableFileStream(mFile);
+ bufferedStream = new SeekableBufferedStream(fileStream,BUFFERED_STREAM_BUFFER_SIZE);
+ fileLength=bufferedStream.length();
+ }
+ catch (IOException exc) {
+ throw new ReviewedGATKException("Unable to open index file (" + exc.getMessage() +")" + mFile, exc);
+ }
+ }
+
+ private void closeIndexFile() {
+ try {
+ bufferedStream.close();
+ fileStream.close();
+ fileLength = -1;
+ }
+ catch (IOException exc) {
+ throw new ReviewedGATKException("Unable to close index file " + mFile, exc);
+ }
+ }
+
+ private static final int INT_SIZE_IN_BYTES = Integer.SIZE / 8;
+ private static final int LONG_SIZE_IN_BYTES = Long.SIZE / 8;
+
+ private byte[] readBytes(int count) {
+ ByteBuffer buffer = getBuffer(count);
+ read(buffer);
+ buffer.flip();
+ byte[] contents = new byte[count];
+ buffer.get(contents);
+ return contents;
+ }
+
+ private int readInteger() {
+ ByteBuffer buffer = getBuffer(INT_SIZE_IN_BYTES);
+ read(buffer);
+ buffer.flip();
+ return buffer.getInt();
+ }
+
+ /**
+ * Reads an array of <count> longs from the file channel, returning the results as an array.
+ * @param count Number of longs to read.
+ * @return An array of longs. Size of array should match count.
+ */
+ private long[] readLongs(final int count) {
+ ByteBuffer buffer = getBuffer(count*LONG_SIZE_IN_BYTES);
+ read(buffer);
+ buffer.flip();
+ long[] result = new long[count];
+ for(int i = 0; i < count; i++)
+ result[i] = buffer.getLong();
+ return result;
+ }
+
+ private void read(final ByteBuffer buffer) {
+ final int bytesRequested = buffer.limit();
+
+ try {
+
+ //BufferedInputStream cannot read directly into a byte buffer, so we read into an array
+ //and put the result into the bytebuffer after the if statement.
+
+ // We have a rigid expectation here to read in exactly the number of bytes we've limited
+ // our buffer to -- if there isn't enough data in the file, the index
+ // must be truncated or otherwise corrupt:
+ if(bytesRequested > fileLength - bufferedStream.position()){
+ throw new UserException.MalformedFile(mFile, String.format("Premature end-of-file while reading BAM index file %s. " +
+ "It's likely that this file is truncated or corrupt -- " +
+ "Please try re-indexing the corresponding BAM file.",
+ mFile));
+ }
+
+ int totalBytesRead = 0;
+ // This while loop must terminate since we demand that we read at least one byte from the file at each iteration
+ while (totalBytesRead < bytesRequested) {
+ // bufferedStream.read may return less than the requested amount of byte despite
+ // not reaching the end of the file, hence the loop.
+ int bytesRead = bufferedStream.read(byteArray, totalBytesRead, bytesRequested-totalBytesRead);
+
+ // We have a rigid expectation here to read in exactly the number of bytes we've limited
+ // our buffer to -- if we encounter EOF (-1), the index
+ // must be truncated or otherwise corrupt:
+ if (bytesRead <= 0) {
+ throw new UserException.MalformedFile(mFile, String.format("Premature end-of-file while reading BAM index file %s. " +
+ "It's likely that this file is truncated or corrupt -- " +
+ "Please try re-indexing the corresponding BAM file.",
+ mFile));
+ }
+ totalBytesRead += bytesRead;
+ }
+ if(totalBytesRead != bytesRequested)
+ throw new RuntimeException("Read amount different from requested amount. This should not happen.");
+
+ buffer.put(byteArray, 0, bytesRequested);
+ }
+ catch(IOException ex) {
+ throw new ReviewedGATKException("Index: unable to read bytes from index file " + mFile);
+ }
+ }
+
+
+ /**
+ * A reusable buffer for use by this index generator.
+ * TODO: Should this be a SoftReference?
+ */
+ private ByteBuffer buffer = null;
+
+ //BufferedStream don't read into ByteBuffers, so we need this temporary array
+ private byte[] byteArray=null;
+ private ByteBuffer getBuffer(final int size) {
+ if(buffer == null || buffer.capacity() < size) {
+ // Allocate a new byte buffer. For now, make it indirect to make sure it winds up on the heap for easier debugging.
+ buffer = ByteBuffer.allocate(size);
+ byteArray = new byte[size];
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+ }
+ buffer.clear();
+ buffer.limit(size);
+ return buffer;
+ }
+
+ private void skipBytes(final int count) {
+ try {
+
+ //try to skip forward the requested amount.
+ long skipped = bufferedStream.skip(count);
+
+ if( skipped != count ) { //if not managed to skip the requested amount
+ throw new ReviewedGATKException("Index: unable to reposition file channel of index file " + mFile);
+ }
+ }
+ catch(IOException ex) {
+ throw new ReviewedGATKException("Index: unable to reposition file channel of index file " + mFile);
+ }
+ }
+
+ private void seek(final long position) {
+ try {
+ //to seek a new position, move the fileChannel, and reposition the bufferedStream
+ bufferedStream.seek(position);
+ }
+ catch(IOException ex) {
+ throw new ReviewedGATKException("Index: unable to reposition of file channel of index file " + mFile);
+ }
+ }
+
+ /**
+ * Retrieve the position from the current file channel.
+ * @return position of the current file channel.
+ */
+ private long position() {
+ try {
+ return bufferedStream.position();
+ }
+ catch (IOException exc) {
+ throw new ReviewedGATKException("Unable to read position from index file " + mFile, exc);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/GATKBAMIndexData.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/GATKBAMIndexData.java
new file mode 100644
index 0000000..f1d6203
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/GATKBAMIndexData.java
@@ -0,0 +1,121 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Stores and processes a single reference worth of GATK data.
+ */
+public class GATKBAMIndexData {
+ private final GATKBAMIndex index;
+ private final int referenceSequence;
+ private final List<GATKBin> bins;
+ private final LinearIndex linearIndex;
+
+ public GATKBAMIndexData(final GATKBAMIndex index, final int referenceSequence, final List<GATKBin> bins, final LinearIndex linearIndex) {
+ this.index = index;
+ this.referenceSequence = referenceSequence;
+ this.bins = bins;
+ this.linearIndex = linearIndex;
+ }
+
+ public int getReferenceSequence() {
+ return referenceSequence;
+ }
+
+ /**
+ * Perform an overlapping query of all bins bounding the given location.
+ * @param bin The bin over which to perform an overlapping query.
+ * @return The file pointers
+ */
+ public GATKBAMFileSpan getSpanOverlapping(final Bin bin) {
+ if(bin == null)
+ return null;
+
+ GATKBin gatkBin = new GATKBin(bin);
+
+ final int binLevel = index.getLevelForBin(bin);
+ final int firstLocusInBin = index.getFirstLocusInBin(bin);
+
+ // Add the specified bin to the tree if it exists.
+ List<GATKBin> binTree = new ArrayList<GATKBin>();
+ if(gatkBin.getBinNumber() < bins.size() && bins.get(gatkBin.getBinNumber()) != null)
+ binTree.add(bins.get(gatkBin.getBinNumber()));
+
+ int currentBinLevel = binLevel;
+ while(--currentBinLevel >= 0) {
+ final int binStart = index.getFirstBinInLevel(currentBinLevel);
+ final int binWidth = index.getMaxAddressibleGenomicLocation()/index.getLevelSize(currentBinLevel);
+ final int binNumber = firstLocusInBin/binWidth + binStart;
+ if(binNumber < bins.size() && bins.get(binNumber) != null)
+ binTree.add(bins.get(binNumber));
+ }
+
+ List<GATKChunk> chunkList = new ArrayList<GATKChunk>();
+ for(GATKBin coveringBin: binTree) {
+ for(GATKChunk chunk: coveringBin.getChunkList())
+ chunkList.add(chunk.clone());
+ }
+
+ final int start = index.getFirstLocusInBin(bin);
+ chunkList = optimizeChunkList(chunkList,linearIndex.getMinimumOffset(start));
+ return new GATKBAMFileSpan(chunkList.toArray(new GATKChunk[chunkList.size()]));
+ }
+
+ private List<GATKChunk> optimizeChunkList(final List<GATKChunk> chunks, final long minimumOffset) {
+ GATKChunk lastChunk = null;
+ Collections.sort(chunks);
+ final List<GATKChunk> result = new ArrayList<GATKChunk>();
+ for (final GATKChunk chunk : chunks) {
+ if (chunk.getChunkEnd() <= minimumOffset) {
+ continue; // linear index optimization
+ }
+ if (result.isEmpty()) {
+ result.add(chunk);
+ lastChunk = chunk;
+ continue;
+ }
+ // Coalesce chunks that are in adjacent file blocks.
+ // This is a performance optimization.
+ if (!lastChunk.overlaps(chunk) && !lastChunk.isAdjacentTo(chunk)) {
+ result.add(chunk);
+ lastChunk = chunk;
+ } else {
+ if (chunk.getChunkEnd() > lastChunk.getChunkEnd()) {
+ lastChunk.setChunkEnd(chunk.getChunkEnd());
+ }
+ }
+ }
+ return result;
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/IntervalOverlapFilteringIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/IntervalOverlapFilteringIterator.java
new file mode 100644
index 0000000..c272e0a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/IntervalOverlapFilteringIterator.java
@@ -0,0 +1,205 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.CloseableIterator;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.sam.AlignmentUtils;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * High efficiency filtering iterator designed to filter out reads only included
+ * in the query results due to the granularity of the BAM index.
+ *
+ * Built into the BAM index is a notion of 16kbase granularity -- an index query for
+ * two regions contained within a 16kbase chunk (say, chr1:5-10 and chr1:11-20) will
+ * return exactly the same regions within the BAM file. This iterator is optimized
+ * to subtract out reads which do not at all overlap the interval list passed to the
+ * constructor.
+ *
+ * Example:
+ * interval list: chr20:6-10
+ * Reads that would pass through the filter: chr20:6-10, chr20:1-15, chr20:1-7, chr20:8-15.
+ * Reads that would be discarded by the filter: chr20:1-5, chr20:11-15.
+ */
+class IntervalOverlapFilteringIterator implements CloseableIterator<SAMRecord> {
+ /**
+ * The wrapped iterator.
+ */
+ private CloseableIterator<SAMRecord> iterator;
+
+ /**
+ * The next read, queued up and ready to go.
+ */
+ private SAMRecord nextRead;
+
+ /**
+ * Rather than using the straight genomic bounds, use filter out only mapped reads.
+ */
+ private boolean keepOnlyUnmappedReads;
+
+ /**
+ * Custom representation of interval bounds.
+ * Makes it simpler to track current position.
+ */
+ private int[] intervalContigIndices;
+ private int[] intervalStarts;
+ private int[] intervalEnds;
+
+ /**
+ * Position within the interval list.
+ */
+ private int currentBound = 0;
+
+ public IntervalOverlapFilteringIterator(CloseableIterator<SAMRecord> iterator, List<GenomeLoc> intervals) {
+ this.iterator = iterator;
+
+ // Look at the interval list to detect whether we should worry about unmapped reads.
+ // If we find a mix of mapped/unmapped intervals, throw an exception.
+ boolean foundMappedIntervals = false;
+ for(GenomeLoc location: intervals) {
+ if(! GenomeLoc.isUnmapped(location))
+ foundMappedIntervals = true;
+ keepOnlyUnmappedReads |= GenomeLoc.isUnmapped(location);
+ }
+
+
+ if(foundMappedIntervals) {
+ if(keepOnlyUnmappedReads)
+ throw new ReviewedGATKException("Tried to apply IntervalOverlapFilteringIterator to a mixed of mapped and unmapped intervals. Please apply this filter to only mapped or only unmapped reads");
+ this.intervalContigIndices = new int[intervals.size()];
+ this.intervalStarts = new int[intervals.size()];
+ this.intervalEnds = new int[intervals.size()];
+ int i = 0;
+ for(GenomeLoc interval: intervals) {
+ intervalContigIndices[i] = interval.getContigIndex();
+ intervalStarts[i] = interval.getStart();
+ intervalEnds[i] = interval.getStop();
+ i++;
+ }
+ }
+
+ advance();
+ }
+
+ public boolean hasNext() {
+ return nextRead != null;
+ }
+
+ public SAMRecord next() {
+ if(nextRead == null)
+ throw new NoSuchElementException("No more reads left in this iterator.");
+ SAMRecord currentRead = nextRead;
+ advance();
+ return currentRead;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Cannot remove from an IntervalOverlapFilteringIterator");
+ }
+
+
+ public void close() {
+ iterator.close();
+ }
+
+ private void advance() {
+ nextRead = null;
+
+ if(!iterator.hasNext())
+ return;
+
+ SAMRecord candidateRead = iterator.next();
+ while(nextRead == null && (keepOnlyUnmappedReads || currentBound < intervalStarts.length)) {
+ if(!keepOnlyUnmappedReads) {
+ // Mapped read filter; check against GenomeLoc-derived bounds.
+ if(readEndsOnOrAfterStartingBound(candidateRead)) {
+ // This read ends after the current interval begins.
+ // Promising, but this read must be checked against the ending bound.
+ if(readStartsOnOrBeforeEndingBound(candidateRead)) {
+ // Yes, this read is within both bounds. This must be our next read.
+ nextRead = candidateRead;
+ break;
+ }
+ else {
+ // Oops, we're past the end bound. Increment the current bound and try again.
+ currentBound++;
+ continue;
+ }
+ }
+ }
+ else {
+ // Found a -L UNMAPPED read. NOTE: this is different than just being flagged as unmapped! We're done.
+ if(AlignmentUtils.isReadGenomeLocUnmapped(candidateRead)) {
+ nextRead = candidateRead;
+ break;
+ }
+ }
+
+ // No more reads available. Stop the search.
+ if(!iterator.hasNext())
+ break;
+
+ // No reasonable read found; advance the iterator.
+ candidateRead = iterator.next();
+ }
+ }
+
+ /**
+ * Check whether the read lies after the start of the current bound. If the read is unmapped but placed, its
+ * end will be distorted, so rely only on the alignment start.
+ * @param read The read to position-check.
+ * @return True if the read starts after the current bounds. False otherwise.
+ */
+ private boolean readEndsOnOrAfterStartingBound(final SAMRecord read) {
+ return
+ // Read ends on a later contig, or...
+ read.getReferenceIndex() > intervalContigIndices[currentBound] ||
+ // Read ends of this contig...
+ (read.getReferenceIndex() == intervalContigIndices[currentBound] &&
+ // either after this location, or...
+ (read.getAlignmentEnd() >= intervalStarts[currentBound] ||
+ // read is unmapped but positioned and alignment start is on or after this start point.
+ (read.getReadUnmappedFlag() && read.getAlignmentStart() >= intervalStarts[currentBound])));
+ }
+
+ /**
+ * Check whether the read lies before the end of the current bound.
+ * @param read The read to position-check.
+ * @return True if the read starts after the current bounds. False otherwise.
+ */
+ private boolean readStartsOnOrBeforeEndingBound(final SAMRecord read) {
+ return
+ // Read starts on a prior contig, or...
+ read.getReferenceIndex() < intervalContigIndices[currentBound] ||
+ // Read starts on this contig and the alignment start is registered before this end point.
+ (read.getReferenceIndex() == intervalContigIndices[currentBound] && read.getAlignmentStart() <= intervalEnds[currentBound]);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/IntervalSharder.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/IntervalSharder.java
new file mode 100644
index 0000000..e355c7e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/IntervalSharder.java
@@ -0,0 +1,93 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.util.PeekableIterator;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+
+import java.util.Iterator;
+
+/**
+ * Handles the process of aggregating BAM intervals into individual shards.
+ * TODO: The task performed by IntervalSharder is now better performed by LocusShardBalancer. Merge BAMScheduler and IntervalSharder.
+ */
+public class IntervalSharder implements Iterator<FilePointer> {
+ /**
+ * The iterator actually laying out the data for BAM scheduling.
+ */
+ private final PeekableIterator<FilePointer> wrappedIterator;
+
+ /**
+ * The parser, for interval manipulation.
+ */
+ private final GenomeLocParser parser;
+
+ public static IntervalSharder shardOverAllReads(final SAMDataSource dataSource, final GenomeLocParser parser) {
+ return new IntervalSharder(BAMScheduler.createOverAllReads(dataSource,parser),parser);
+ }
+
+ public static IntervalSharder shardOverMappedReads(final SAMDataSource dataSource, final GenomeLocParser parser) {
+ return new IntervalSharder(BAMScheduler.createOverMappedReads(dataSource),parser);
+ }
+
+ public static IntervalSharder shardOverIntervals(final SAMDataSource dataSource, final GenomeLocSortedSet loci, final IntervalMergingRule intervalMergeRule) {
+ return new IntervalSharder(BAMScheduler.createOverIntervals(dataSource,intervalMergeRule,loci),loci.getGenomeLocParser());
+ }
+
+ private IntervalSharder(final BAMScheduler scheduler, final GenomeLocParser parser) {
+ wrappedIterator = new PeekableIterator<FilePointer>(scheduler);
+ this.parser = parser;
+ }
+ public void close() {
+ wrappedIterator.close();
+ }
+
+ public boolean hasNext() {
+ return wrappedIterator.hasNext();
+ }
+
+ /**
+ * Accumulate shards where there's no additional cost to processing the next shard in the sequence.
+ * @return The next file pointer to process.
+ */
+ public FilePointer next() {
+ FilePointer current = wrappedIterator.next();
+
+ while ( wrappedIterator.hasNext() &&
+ current.isRegionUnmapped == wrappedIterator.peek().isRegionUnmapped &&
+ (current.getContigIndex() == wrappedIterator.peek().getContigIndex() || current.isRegionUnmapped) &&
+ current.minus(wrappedIterator.peek()) == 0 ) {
+
+ current = current.combine(parser,wrappedIterator.next());
+ }
+
+ return current;
+ }
+
+ public void remove() { throw new UnsupportedOperationException("Unable to remove from an interval sharder."); }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/LocusShard.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/LocusShard.java
new file mode 100644
index 0000000..28d4faf
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/LocusShard.java
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.SAMFileSpan;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.Utils;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Handles locus shards of BAM information.
+ * @author aaron
+ * @version 1.0
+ * @date Apr 7, 2009
+ */
+public class LocusShard extends Shard {
+ /**
+ * Create a new locus shard, divided by index.
+ * @param intervals List of intervals to process.
+ * @param fileSpans File spans associated with that interval.
+ */
+ public LocusShard(GenomeLocParser parser, SAMDataSource dataSource, List<GenomeLoc> intervals, Map<SAMReaderID,SAMFileSpan> fileSpans) {
+ super(parser, ShardType.LOCUS, intervals, dataSource, fileSpans, false);
+ }
+
+ /**
+ * String representation of this shard.
+ * @return A string representation of the boundaries of this shard.
+ */
+ @Override
+ public String toString() {
+ return Utils.join(";",getGenomeLocs());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/LocusShardBalancer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/LocusShardBalancer.java
new file mode 100644
index 0000000..6fb4d48
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/LocusShardBalancer.java
@@ -0,0 +1,58 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import java.util.Iterator;
+
+/**
+ * Batch granular file pointers into potentially larger shards.
+ */
+public class LocusShardBalancer extends ShardBalancer {
+ /**
+ * Convert iterators of file pointers into balanced iterators of shards.
+ * @return An iterator over balanced shards.
+ */
+ public Iterator<Shard> iterator() {
+ return new Iterator<Shard>() {
+ public boolean hasNext() {
+ return filePointers.hasNext();
+ }
+
+ public Shard next() {
+ FilePointer current = filePointers.next();
+
+ // FilePointers have already been combined as necessary at the IntervalSharder level. No
+ // need to do so again here.
+
+ return new LocusShard(parser,readsDataSource,current.getLocations(),current.fileSpans);
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Unable to remove from shard balancing iterator");
+ }
+ };
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ReadShard.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ReadShard.java
new file mode 100644
index 0000000..d4321da
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ReadShard.java
@@ -0,0 +1,271 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.util.PeekableIterator;
+import htsjdk.samtools.*;
+import htsjdk.samtools.util.CloseableIterator;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIteratorAdapter;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ *
+ * User: aaron
+ * Date: Apr 10, 2009
+ * Time: 5:03:13 PM
+ *
+ * The Broad Institute
+ * SOFTWARE COPYRIGHT NOTICE AGREEMENT
+ * This software and its documentation are copyright 2009 by the
+ * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
+ *
+ * This software is supplied without any warranty or guaranteed support whatsoever. Neither
+ * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
+ *
+ */
+
+/**
+ * Expresses a shard of read data in block format.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class ReadShard extends Shard {
+
+ /**
+ * Default read shard buffer size
+ */
+ public static final int DEFAULT_MAX_READS = 10000;
+
+ /**
+ * What is the maximum number of reads per BAM file which should go into a read shard.
+ *
+ * TODO: this non-final static variable should either be made final or turned into an
+ * TODO: instance variable somewhere -- as both static and mutable it wreaks havoc
+ * TODO: with tests that use multiple instances of SAMDataSource (since SAMDataSource
+ * TODO: changes this value)
+ */
+ public static int MAX_READS = DEFAULT_MAX_READS;
+
+ /**
+ * The reads making up this shard.
+ */
+ private final Collection<SAMRecord> reads = new ArrayList<SAMRecord>(MAX_READS);
+
+ public ReadShard(GenomeLocParser parser, SAMDataSource readsDataSource, Map<SAMReaderID,SAMFileSpan> fileSpans, List<GenomeLoc> loci, boolean isUnmapped) {
+ super(parser, ShardType.READ, loci, readsDataSource, fileSpans, isUnmapped);
+ }
+
+ /**
+ * Sets the maximum number of reads buffered in a read shard. Implemented as a weirdly static interface
+ * until we know what effect tuning this parameter has.
+ *
+ * TODO: this mutable static interface is awful and breaks tests -- need to refactor
+ *
+ * @param bufferSize New maximum number
+ */
+ static void setReadBufferSize(final int bufferSize) {
+ MAX_READS = bufferSize;
+ }
+
+ /**
+ * What read buffer size are we using?
+ *
+ * @return
+ */
+ public static int getReadBufferSize() {
+ return MAX_READS;
+ }
+
+ /**
+ * Returns true if this shard is meant to buffer reads, rather
+ * than just holding pointers to their locations.
+ * @return True if this shard can buffer reads. False otherwise.
+ */
+ public boolean buffersReads() {
+ return true;
+ }
+
+ /**
+ * Returns true if the read buffer is currently full.
+ * @return True if this shard's buffer is full (and the shard can buffer reads).
+ */
+ public boolean isBufferEmpty() {
+ return reads.size() == 0;
+ }
+
+ /**
+ * Returns true if the read buffer is currently full.
+ * @return True if this shard's buffer is full (and the shard can buffer reads).
+ */
+ public boolean isBufferFull() {
+ return reads.size() > ReadShard.MAX_READS;
+ }
+
+ /**
+ * Adds a read to the read buffer.
+ * @param read Add a read to the internal shard buffer.
+ */
+ public void addRead(SAMRecord read) {
+ // DO NOT validate that the buffer is full. Paired read sharding will occasionally have to stuff another
+ // read or two into the buffer.
+ reads.add(read);
+ }
+
+ /**
+ * Fills this shard's buffer with reads from the iterator passed in
+ *
+ * @param readIter Iterator from which to draw the reads to fill the shard
+ */
+ @Override
+ public void fill( PeekableIterator<SAMRecord> readIter ) {
+ if( ! buffersReads() )
+ throw new ReviewedGATKException("Attempting to fill a non-buffering shard.");
+
+ SAMFileHeader.SortOrder sortOrder = getReadProperties().getSortOrder();
+ SAMRecord read = null;
+
+ while( ! isBufferFull() && readIter.hasNext() ) {
+ final SAMRecord nextRead = readIter.peek();
+ if ( read == null || (nextRead.getReferenceIndex().equals(read.getReferenceIndex())) ) {
+ // only add reads to the shard if they are on the same contig
+ read = readIter.next();
+ addRead(read);
+ } else {
+ break;
+ }
+ }
+
+ // If the reads are sorted in coordinate order, ensure that all reads
+ // having the same alignment start become part of the same shard, to allow
+ // downsampling to work better across shard boundaries. Note that because our
+ // read stream has already been fed through the positional downsampler, which
+ // ensures that at each alignment start position there are no more than dcov
+ // reads, we're in no danger of accidentally creating a disproportionately huge
+ // shard
+ if ( sortOrder == SAMFileHeader.SortOrder.coordinate ) {
+ while ( readIter.hasNext() ) {
+ SAMRecord additionalRead = readIter.peek();
+
+ // Stop filling the shard as soon as we encounter a read having a different
+ // alignment start or contig from the last read added in the earlier loop
+ // above, or an unmapped read
+ if ( read == null ||
+ additionalRead.getReadUnmappedFlag() ||
+ ! additionalRead.getReferenceIndex().equals(read.getReferenceIndex()) ||
+ additionalRead.getAlignmentStart() != read.getAlignmentStart() ) {
+ break;
+ }
+
+ addRead(readIter.next());
+ }
+ }
+
+ // If the reads are sorted in queryname order, ensure that all reads
+ // having the same queryname become part of the same shard.
+ if( sortOrder == SAMFileHeader.SortOrder.queryname ) {
+ while( readIter.hasNext() ) {
+ SAMRecord nextRead = readIter.peek();
+ if( read == null || ! read.getReadName().equals(nextRead.getReadName()) )
+ break;
+ addRead(readIter.next());
+ }
+ }
+ }
+
+ /**
+ * Creates an iterator over reads stored in this shard's read cache.
+ * @return
+ */
+ public GATKSAMIterator iterator() {
+ return GATKSAMIteratorAdapter.adapt(reads.iterator());
+ }
+
+ /**
+ * String representation of this shard.
+ * @return A string representation of the boundaries of this shard.
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for(Map.Entry<SAMReaderID,SAMFileSpan> entry: getFileSpans().entrySet()) {
+ sb.append(entry.getKey());
+ sb.append(": ");
+ sb.append(entry.getValue());
+ sb.append(' ');
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get the full span from the start of the left most read to the end of the right most one
+ *
+ * Note this may be different than the getLocation() of the shard, as this reflects the
+ * targeted span, not the actual span of reads
+ *
+ * @return the genome loc representing the span of these reads on the genome
+ */
+ public GenomeLoc getReadsSpan() {
+ if ( isUnmapped() || super.getGenomeLocs() == null || reads.isEmpty() )
+ return super.getLocation();
+ else {
+ int start = Integer.MAX_VALUE;
+ int stop = Integer.MIN_VALUE;
+ String contig = null;
+ boolean foundMapped = false;
+
+ for ( final SAMRecord read : reads ) {
+ if ( contig != null && ! read.getReferenceName().equals(contig) )
+ throw new ReviewedGATKException("ReadShard contains reads spanning contig boundaries, which is no longer allowed. "
+ + "First contig is " + contig + " next read was " + read.getReferenceName() );
+ contig = read.getReferenceName();
+
+ // Even if this shard as a *whole* is not "unmapped", we can still encounter *individual* unmapped mates
+ // of mapped reads within this shard's buffer. In fact, if we're very unlucky with shard boundaries,
+ // this shard might consist *only* of unmapped mates! We need to refrain from using the alignment
+ // starts/stops of these unmapped mates, and detect the case where the shard has been filled *only*
+ // with unmapped mates.
+ if ( ! read.getReadUnmappedFlag() ) {
+ foundMapped = true;
+ if ( read.getAlignmentStart() < start ) start = read.getAlignmentStart();
+ if ( read.getAlignmentEnd() > stop ) stop = read.getAlignmentEnd();
+ }
+ }
+
+ assert contig != null;
+
+ if ( ! foundMapped || contig.equals("*") ) // all reads are unmapped
+ return GenomeLoc.UNMAPPED;
+ else
+ return parser.createGenomeLoc(contig, start, stop);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ReadShardBalancer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ReadShardBalancer.java
new file mode 100644
index 0000000..4a27219
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ReadShardBalancer.java
@@ -0,0 +1,231 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.util.PeekableIterator;
+import htsjdk.samtools.SAMRecord;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ * Convert from an unbalanced iterator over FilePointers to a balanced iterator over Shards.
+ *
+ * When processing FilePointers, our strategy is to aggregate all FilePointers for each contig
+ * together into one monolithic FilePointer, create one persistent set of read iterators over
+ * that monolithic FilePointer, and repeatedly use that persistent set of read iterators to
+ * fill read shards with reads.
+ *
+ * This strategy has several important advantages:
+ *
+ * 1. We avoid issues with file span overlap. FilePointers that are more granular than a whole
+ * contig will have regions that overlap with other FilePointers on the same contig, due
+ * to the limited granularity of BAM index data. By creating only one FilePointer per contig,
+ * we avoid having to track how much of each file region we've visited (as we did in the
+ * former implementation), we avoid expensive non-sequential access patterns in the files,
+ * and we avoid having to repeatedly re-create our iterator chain for every small region
+ * of interest.
+ *
+ * 2. We avoid boundary issues with the engine-level downsampling. Since we create a single
+ * persistent set of read iterators (which include the downsampling iterator(s)) per contig,
+ * the downsampling process is never interrupted by FilePointer or Shard boundaries, and never
+ * loses crucial state information while downsampling within a contig.
+ *
+ * TODO: There is also at least one important disadvantage:
+ *
+ * 1. We load more BAM index data into memory at once, and this work is done upfront before processing
+ * the next contig, creating a delay before traversal of each contig. This delay may be
+ * compensated for by the gains listed in #1 above, and we may be no worse off overall in
+ * terms of total runtime, but we need to verify this empirically.
+ *
+ * @author David Roazen
+ */
+public class ReadShardBalancer extends ShardBalancer {
+
+ private static Logger logger = Logger.getLogger(ReadShardBalancer.class);
+
+ /**
+ * Convert iterators of file pointers into balanced iterators of shards.
+ * @return An iterator over balanced shards.
+ */
+ public Iterator<Shard> iterator() {
+ return new Iterator<Shard>() {
+ /**
+ * The cached shard to be returned next. Prefetched in the peekable iterator style.
+ */
+ private Shard nextShard = null;
+
+ /**
+ * The file pointer currently being processed.
+ */
+ private FilePointer currentContigFilePointer = null;
+
+ /**
+ * Iterator over the reads from the current contig's file pointer. The same iterator will be
+ * used to fill all shards associated with a given file pointer
+ */
+ private PeekableIterator<SAMRecord> currentContigReadsIterator = null;
+
+ /**
+ * How many FilePointers have we pulled from the filePointers iterator?
+ */
+ private int totalFilePointersConsumed = 0;
+
+ /**
+ * Have we encountered a monolithic FilePointer?
+ */
+ private boolean encounteredMonolithicFilePointer = false;
+
+
+ {
+ createNextContigFilePointer();
+ advance();
+ }
+
+ public boolean hasNext() {
+ return nextShard != null;
+ }
+
+ public Shard next() {
+ if ( ! hasNext() )
+ throw new NoSuchElementException("No next read shard available");
+ Shard currentShard = nextShard;
+ advance();
+ return currentShard;
+ }
+
+ private void advance() {
+ nextShard = null;
+
+ // May need multiple iterations to fill the next shard if all reads in current file spans get filtered/downsampled away
+ while ( nextShard == null && currentContigFilePointer != null ) {
+
+ // If we've exhausted the current file pointer of reads, move to the next file pointer (if there is one):
+ if ( currentContigReadsIterator != null && ! currentContigReadsIterator.hasNext() ) {
+
+ // Close the old, exhausted chain of iterators to release resources
+ currentContigReadsIterator.close();
+
+ // Advance to the FilePointer for the next contig
+ createNextContigFilePointer();
+
+ // We'll need to create a fresh iterator for this file pointer when we create the first
+ // shard for it below.
+ currentContigReadsIterator = null;
+ }
+
+ // At this point our currentContigReadsIterator may be null or non-null depending on whether or not
+ // this is our first shard for this file pointer.
+ if ( currentContigFilePointer != null ) {
+ Shard shard = new ReadShard(parser,readsDataSource, currentContigFilePointer.fileSpans, currentContigFilePointer.locations, currentContigFilePointer.isRegionUnmapped);
+
+ // Create a new reads iterator only when we've just advanced to the file pointer for the next
+ // contig. It's essential that the iterators persist across all shards that share the same contig
+ // to allow the downsampling to work properly.
+ if ( currentContigReadsIterator == null ) {
+ currentContigReadsIterator = new PeekableIterator<SAMRecord>(readsDataSource.getIterator(shard));
+ }
+
+ if ( currentContigReadsIterator.hasNext() ) {
+ shard.fill(currentContigReadsIterator);
+ nextShard = shard;
+ }
+ }
+ }
+ }
+
+ /**
+ * Aggregate all FilePointers for the next contig together into one monolithic FilePointer
+ * to avoid boundary issues with visiting the same file regions more than once (since more
+ * granular FilePointers will have regions that overlap with other nearby FilePointers due
+ * to the nature of BAM indices).
+ *
+ * By creating one persistent set of iterators per contig we also avoid boundary artifacts
+ * in the engine-level downsampling.
+ *
+ * TODO: This FilePointer aggregation should ideally be done at the BAMSchedule level for
+ * TODO: read traversals, as there's little point in the BAMSchedule emitting extremely
+ * TODO: granular FilePointers if we're just going to union them. The BAMSchedule should
+ * TODO: emit one FilePointer per contig for read traversals (but, crucially, NOT for
+ * TODO: locus traversals).
+ */
+ private void createNextContigFilePointer() {
+ currentContigFilePointer = null;
+ List<FilePointer> nextContigFilePointers = new ArrayList<FilePointer>();
+
+ if ( filePointers.hasNext() ) {
+ logger.info("Loading BAM index data");
+ }
+
+ while ( filePointers.hasNext() ) {
+
+ // Make sure that if we see a monolithic FilePointer (representing all regions in all files) that
+ // it is the ONLY FilePointer we ever encounter
+ if ( encounteredMonolithicFilePointer ) {
+ throw new ReviewedGATKException("Bug: encountered additional FilePointers after encountering a monolithic FilePointer");
+ }
+ if ( filePointers.peek().isMonolithic() ) {
+ if ( totalFilePointersConsumed > 0 ) {
+ throw new ReviewedGATKException("Bug: encountered additional FilePointers before encountering a monolithic FilePointer");
+ }
+ encounteredMonolithicFilePointer = true;
+ logger.debug(String.format("Encountered monolithic FilePointer: %s", filePointers.peek()));
+ }
+
+ // If this is the first FP we've seen, or we're dealing with mapped regions and the next FP is on the
+ // same contig as previous FPs, or all our FPs are unmapped, add the next FP to the list of FPs to merge
+ if ( nextContigFilePointers.isEmpty() ||
+ (! nextContigFilePointers.get(0).isRegionUnmapped && ! filePointers.peek().isRegionUnmapped &&
+ nextContigFilePointers.get(0).getContigIndex() == filePointers.peek().getContigIndex()) ||
+ (nextContigFilePointers.get(0).isRegionUnmapped && filePointers.peek().isRegionUnmapped) ) {
+
+ nextContigFilePointers.add(filePointers.next());
+ totalFilePointersConsumed++;
+ }
+ else {
+ break; // next FilePointer is on a different contig or has different mapped/unmapped status,
+ // save it for next time
+ }
+ }
+
+ if ( ! nextContigFilePointers.isEmpty() ) {
+ currentContigFilePointer = FilePointer.union(nextContigFilePointers, parser);
+ }
+
+ if ( currentContigFilePointer != null ) {
+ logger.info("Done loading BAM index data");
+ logger.debug(String.format("Next FilePointer: %s", currentContigFilePointer));
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Unable to remove from shard balancing iterator");
+ }
+ };
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/SAMDataSource.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/SAMDataSource.java
new file mode 100644
index 0000000..0fc06fc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/SAMDataSource.java
@@ -0,0 +1,1179 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.MergingSamRecordIterator;
+import htsjdk.samtools.SamFileHeaderMerger;
+import htsjdk.samtools.*;
+import htsjdk.samtools.util.CloseableIterator;
+import htsjdk.samtools.util.RuntimeIOException;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.ReadMetrics;
+import org.broadinstitute.gatk.engine.ReadProperties;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.downsampling.*;
+import org.broadinstitute.gatk.engine.filters.CountingFilteringIterator;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.iterators.*;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.SimpleTimer;
+import org.broadinstitute.gatk.utils.baq.ReadTransformingIterator;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.sam.GATKSAMReadGroupRecord;
+import org.broadinstitute.gatk.utils.sam.GATKSamRecordFactory;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.concurrent.Callable;
+
+/**
+ * User: aaron
+ * Date: Mar 26, 2009
+ * Time: 2:36:16 PM
+ * <p/>
+ * Converts shards to SAM iterators over the specified region
+ */
+public class SAMDataSource {
+ final private static GATKSamRecordFactory factory = new GATKSamRecordFactory();
+
+ /** Backing support for reads. */
+ protected final ReadProperties readProperties;
+
+ /**
+ * Runtime metrics of reads filtered, etc.
+ */
+ private final ReadMetrics readMetrics;
+
+ /**
+ * Tools for parsing GenomeLocs, for verifying BAM ordering against general ordering.
+ */
+ protected final GenomeLocParser genomeLocParser;
+
+ /**
+ * Identifiers for the readers driving this data source.
+ */
+ private final Collection<SAMReaderID> readerIDs;
+
+ /**
+ * How strict are the readers driving this data source.
+ */
+ private final ValidationStringency validationStringency;
+
+ /**
+ * Do we want to remove the program records from this data source?
+ */
+ private final boolean removeProgramRecords;
+
+ /**
+ * Store BAM indices for each reader present.
+ */
+ private final Map<SAMReaderID,GATKBAMIndex> bamIndices = new HashMap<SAMReaderID,GATKBAMIndex>();
+
+ /**
+ * The merged header.
+ */
+ private final SAMFileHeader mergedHeader;
+
+ /**
+ * The constituent headers of the unmerged files.
+ */
+ private final Map<SAMReaderID,SAMFileHeader> headers = new HashMap<SAMReaderID,SAMFileHeader>();
+
+ /**
+ * The sort order of the BAM files. Files without a sort order tag are assumed to be
+ * in coordinate order.
+ */
+ private SAMFileHeader.SortOrder sortOrder = null;
+
+ /**
+ * Whether the read groups in overlapping files collide.
+ */
+ private final boolean hasReadGroupCollisions;
+
+ /**
+ * Maps the SAM readers' merged read group ids to their original ids. Since merged read group ids
+ * are always unique, we can simply use a map here, no need to stratify by reader.
+ */
+ private final ReadGroupMapping mergedToOriginalReadGroupMappings = new ReadGroupMapping();
+
+ /**
+ * Maps the SAM readers' original read group ids to their revised ids. This mapping must be stratified
+ * by readers, since there can be readgroup id collision: different bam files (readers) can list the
+ * same read group id, which will be disambiguated when these input streams are merged.
+ */
+ private final Map<SAMReaderID,ReadGroupMapping> originalToMergedReadGroupMappings = new HashMap<SAMReaderID,ReadGroupMapping>();
+
+ /**
+ * Mapping from input file path to new sample name. Used only when doing on-the-fly sample renaming.
+ */
+ private Map<String, String> sampleRenameMap = null;
+
+ /** our log, which we want to capture anything from this class */
+ private static Logger logger = Logger.getLogger(SAMDataSource.class);
+
+ /**
+ * A collection of readers driving the merging process.
+ */
+ private final SAMResourcePool resourcePool;
+
+ /**
+ * Asynchronously loads BGZF blocks.
+ */
+ private final BGZFBlockLoadingDispatcher dispatcher;
+
+ /**
+ * How are threads allocated.
+ */
+ private final ThreadAllocation threadAllocation;
+
+ /**
+ * How are adjacent intervals merged by the sharder?
+ */
+ private final IntervalMergingRule intervalMergingRule;
+
+ /**
+ * Static set of unsupported programs that create bam files.
+ * The key is the PG record ID and the value is the name of the tool that created it
+ */
+ private static Map<String, String> unsupportedPGs = new HashMap<>();
+ static {
+ unsupportedPGs.put("GATK ReduceReads", "ReduceReads");
+ }
+
+ /**
+ * Create a new SAM data source given the supplied read metadata.
+ *
+ * For testing purposes
+ *
+ * @param samFiles list of reads files.
+ */
+ public SAMDataSource(Collection<SAMReaderID> samFiles, ThreadAllocation threadAllocation, Integer numFileHandles, GenomeLocParser genomeLocParser) {
+ this(
+ samFiles,
+ threadAllocation,
+ numFileHandles,
+ genomeLocParser,
+ false,
+ ValidationStringency.STRICT,
+ null,
+ null,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ false);
+ }
+
+ /**
+ * See complete constructor. Does not enable BAQ by default.
+ *
+ * For testing purposes
+ */
+ public SAMDataSource(
+ Collection<SAMReaderID> samFiles,
+ ThreadAllocation threadAllocation,
+ Integer numFileHandles,
+ GenomeLocParser genomeLocParser,
+ boolean useOriginalBaseQualities,
+ ValidationStringency strictness,
+ Integer readBufferSize,
+ DownsamplingMethod downsamplingMethod,
+ ValidationExclusion exclusionList,
+ Collection<ReadFilter> supplementalFilters,
+ boolean includeReadsWithDeletionAtLoci) {
+ this( samFiles,
+ threadAllocation,
+ numFileHandles,
+ genomeLocParser,
+ useOriginalBaseQualities,
+ strictness,
+ readBufferSize,
+ downsamplingMethod,
+ exclusionList,
+ supplementalFilters,
+ Collections.<ReadTransformer>emptyList(),
+ includeReadsWithDeletionAtLoci,
+ (byte) -1,
+ false,
+ false,
+ null,
+ IntervalMergingRule.ALL);
+ }
+
+ /**
+ * Create a new SAM data source given the supplied read metadata.
+ * @param samFiles list of reads files.
+ * @param useOriginalBaseQualities True if original base qualities should be used.
+ * @param strictness Stringency of reads file parsing.
+ * @param readBufferSize Number of reads to hold in memory per BAM.
+ * @param downsamplingMethod Method for downsampling reads at a given locus.
+ * @param exclusionList what safety checks we're willing to let slide
+ * @param supplementalFilters additional filters to dynamically apply.
+ * @param includeReadsWithDeletionAtLoci if 'true', the base pileups sent to the walker's map() method
+ * will explicitly list reads with deletion over the current reference base; otherwise, only observed
+ * bases will be seen in the pileups, and the deletions will be skipped silently.
+ * @param defaultBaseQualities if the reads have incomplete quality scores, set them all to defaultBaseQuality.
+ * @param keepReadsInLIBS should we keep a unique list of reads in LIBS?
+ * @param sampleRenameMap Map of BAM file to new sample ID used during on-the-fly runtime sample renaming.
+ * Will be null if we're not doing sample renaming.
+ * @param intervalMergingRule how are adjacent intervals merged by the sharder
+ */
+ public SAMDataSource(
+ Collection<SAMReaderID> samFiles,
+ ThreadAllocation threadAllocation,
+ Integer numFileHandles,
+ GenomeLocParser genomeLocParser,
+ boolean useOriginalBaseQualities,
+ ValidationStringency strictness,
+ Integer readBufferSize,
+ DownsamplingMethod downsamplingMethod,
+ ValidationExclusion exclusionList,
+ Collection<ReadFilter> supplementalFilters,
+ List<ReadTransformer> readTransformers,
+ boolean includeReadsWithDeletionAtLoci,
+ byte defaultBaseQualities,
+ boolean removeProgramRecords,
+ final boolean keepReadsInLIBS,
+ final Map<String, String> sampleRenameMap,
+ final IntervalMergingRule intervalMergingRule) {
+
+ this.readMetrics = new ReadMetrics();
+ this.genomeLocParser = genomeLocParser;
+ this.intervalMergingRule = intervalMergingRule;
+
+ readerIDs = samFiles;
+
+ this.threadAllocation = threadAllocation;
+ // TODO: Consider a borrowed-thread dispatcher implementation.
+ if(this.threadAllocation.getNumIOThreads() > 0) {
+ logger.info("Running in asynchronous I/O mode; number of threads = " + this.threadAllocation.getNumIOThreads());
+ dispatcher = new BGZFBlockLoadingDispatcher(this.threadAllocation.getNumIOThreads(), numFileHandles != null ? numFileHandles : 1);
+ }
+ else
+ dispatcher = null;
+
+ validationStringency = strictness;
+ this.removeProgramRecords = removeProgramRecords;
+ if(readBufferSize != null)
+ ReadShard.setReadBufferSize(readBufferSize); // TODO: use of non-final static variable here is just awful, especially for parallel tests
+ else {
+ // Choose a sensible default for the read buffer size.
+ // Previously we we're picked 100000 reads per BAM per shard with a max cap of 250K reads in memory at once.
+ // Now we are simply setting it to 100K reads
+ ReadShard.setReadBufferSize(100000);
+ }
+
+ this.sampleRenameMap = sampleRenameMap;
+
+ resourcePool = new SAMResourcePool(Integer.MAX_VALUE);
+ SAMReaders readers = resourcePool.getAvailableReaders();
+
+ // Determine the sort order.
+ for(SAMReaderID readerID: readerIDs) {
+ if (! readerID.samFile.canRead() )
+ throw new UserException.CouldNotReadInputFile(readerID.samFile,"file is not present or user does not have appropriate permissions. " +
+ "Please check that the file is present and readable and try again.");
+
+ // Get the sort order, forcing it to coordinate if unsorted.
+ SAMFileReader reader = readers.getReader(readerID);
+ SAMFileHeader header = reader.getFileHeader();
+
+ headers.put(readerID,header);
+
+ if ( header.getReadGroups().isEmpty() ) {
+ throw new UserException.MalformedBAM(readers.getReaderID(reader).samFile,
+ "SAM file doesn't have any read groups defined in the header. The GATK no longer supports SAM files without read groups");
+ }
+
+ SAMFileHeader.SortOrder sortOrder = header.getSortOrder() != SAMFileHeader.SortOrder.unsorted ? header.getSortOrder() : SAMFileHeader.SortOrder.coordinate;
+
+ // Validate that all input files are sorted in the same order.
+ if(this.sortOrder != null && this.sortOrder != sortOrder)
+ throw new UserException.MissortedBAM(String.format("Attempted to process mixed of files sorted as %s and %s.",this.sortOrder,sortOrder));
+
+ // Update the sort order.
+ this.sortOrder = sortOrder;
+ }
+
+ mergedHeader = readers.getMergedHeader();
+ hasReadGroupCollisions = readers.hasReadGroupCollisions();
+
+ readProperties = new ReadProperties(
+ samFiles,
+ mergedHeader,
+ sortOrder,
+ useOriginalBaseQualities,
+ strictness,
+ downsamplingMethod,
+ exclusionList,
+ supplementalFilters,
+ readTransformers,
+ includeReadsWithDeletionAtLoci,
+ defaultBaseQualities,
+ keepReadsInLIBS);
+
+ // cache the read group id (original) -> read group id (merged)
+ // and read group id (merged) -> read group id (original) mappings.
+ for(SAMReaderID id: readerIDs) {
+ SAMFileReader reader = readers.getReader(id);
+
+ ReadGroupMapping mappingToMerged = new ReadGroupMapping();
+
+ List<SAMReadGroupRecord> readGroups = reader.getFileHeader().getReadGroups();
+ for(SAMReadGroupRecord readGroup: readGroups) {
+ if(hasReadGroupCollisions) {
+ mappingToMerged.put(readGroup.getReadGroupId(),readers.getReadGroupId(id,readGroup.getReadGroupId()));
+ mergedToOriginalReadGroupMappings.put(readers.getReadGroupId(id,readGroup.getReadGroupId()),readGroup.getReadGroupId());
+ } else {
+ mappingToMerged.put(readGroup.getReadGroupId(),readGroup.getReadGroupId());
+ mergedToOriginalReadGroupMappings.put(readGroup.getReadGroupId(),readGroup.getReadGroupId());
+ }
+ }
+
+ originalToMergedReadGroupMappings.put(id,mappingToMerged);
+ }
+
+ for(SAMReaderID id: readerIDs) {
+ File indexFile = findIndexFile(id.samFile);
+ if(indexFile != null)
+ bamIndices.put(id,new GATKBAMIndex(indexFile));
+ }
+
+ resourcePool.releaseReaders(readers);
+ }
+
+ /**
+ * Checks whether the provided SAM header if from a reduced bam file.
+ * @param header the SAM header for a given file
+ * @throws UserException if the header is from a reduced bam
+ */
+ private void checkForUnsupportedBamFile(final SAMFileHeader header) {
+ for ( final SAMProgramRecord PGrecord : header.getProgramRecords() ) {
+ if ( unsupportedPGs.containsKey(PGrecord.getId()) )
+ throw new UserException("The GATK no longer supports running off of BAMs produced by " + unsupportedPGs.get(PGrecord.getId()));
+ }
+ }
+
+ public void close() {
+ SAMReaders readers = resourcePool.getAvailableReaders();
+ for(SAMReaderID readerID: readerIDs) {
+ SAMFileReader reader = readers.getReader(readerID);
+ reader.close();
+ }
+ }
+
+ /**
+ * Returns Reads data structure containing information about the reads data sources placed in this pool as well as
+ * information about how they are downsampled, sorted, and filtered
+ * @return
+ */
+ public ReadProperties getReadsInfo() { return readProperties; }
+
+ /**
+ * Checks to see whether any reads files are supplying data.
+ * @return True if no reads files are supplying data to the traversal; false otherwise.
+ */
+ public boolean isEmpty() {
+ return readProperties.getSAMReaderIDs().size() == 0;
+ }
+
+ /**
+ * Gets the SAM file associated with a given reader ID.
+ * @param id The reader for which to retrieve the source file.
+ * @return the file actually associated with the id.
+ */
+ public File getSAMFile(SAMReaderID id) {
+ return id.samFile;
+ }
+
+ /**
+ * Returns readers used by this data source.
+ * @return A list of SAM reader IDs.
+ */
+ public Collection<SAMReaderID> getReaderIDs() {
+ return readerIDs;
+ }
+
+ /**
+ * Retrieves the id of the reader which built the given read.
+ * @param read The read to test.
+ * @return ID of the reader.
+ */
+ public SAMReaderID getReaderID(SAMRecord read) {
+ return resourcePool.getReaderID(read.getFileSource().getReader());
+ }
+
+ /**
+ * Gets the merged header from the SAM file.
+ * @return The merged header.
+ */
+ public SAMFileHeader getHeader() {
+ return mergedHeader;
+ }
+
+ public SAMFileHeader getHeader(SAMReaderID id) {
+ return headers.get(id);
+ }
+
+ /**
+ * Gets the revised read group id mapped to this 'original' read group id.
+ * @param reader for which to grab a read group.
+ * @param originalReadGroupId ID of the original read group.
+ * @return Merged read group ID.
+ */
+ public String getReadGroupId(final SAMReaderID reader, final String originalReadGroupId) {
+ return originalToMergedReadGroupMappings.get(reader).get(originalReadGroupId);
+ }
+
+ /**
+ * Gets the original read group id (as it was specified in the original input bam file) that maps onto
+ * this 'merged' read group id.
+ * @param mergedReadGroupId 'merged' ID of the read group (as it is presented by the read received from merged input stream).
+ * @return Merged read group ID.
+ */
+ public String getOriginalReadGroupId(final String mergedReadGroupId) {
+ return mergedToOriginalReadGroupMappings.get(mergedReadGroupId);
+ }
+
+ /**
+ * True if all readers have an index.
+ * @return True if all readers have an index.
+ */
+ public boolean hasIndex() {
+ return readerIDs.size() == bamIndices.size();
+ }
+
+ /**
+ * Gets the index for a particular reader. Always preloaded.
+ * @param id Id of the reader.
+ * @return The index. Will preload the index if necessary.
+ */
+ public GATKBAMIndex getIndex(final SAMReaderID id) {
+ return bamIndices.get(id);
+ }
+
+ /**
+ * Retrieves the sort order of the readers.
+ * @return Sort order. Can be unsorted, coordinate order, or query name order.
+ */
+ public SAMFileHeader.SortOrder getSortOrder() {
+ return sortOrder;
+ }
+
+ /**
+ * Gets the cumulative read metrics for shards already processed.
+ * @return Cumulative read metrics.
+ */
+ public ReadMetrics getCumulativeReadMetrics() {
+ // don't return a clone here because the engine uses a pointer to this object
+ return readMetrics;
+ }
+
+ /**
+ * Incorporate the given read metrics into the cumulative read metrics.
+ * @param readMetrics The 'incremental' read metrics, to be incorporated into the cumulative metrics.
+ */
+ public void incorporateReadMetrics(final ReadMetrics readMetrics) {
+ this.readMetrics.incrementMetrics(readMetrics);
+ }
+
+ public GATKSAMIterator seek(Shard shard) {
+ if(shard.buffersReads()) {
+ return shard.iterator();
+ }
+ else {
+ return getIterator(shard);
+ }
+ }
+
+ /**
+ * Gets the reader associated with the given read.
+ * @param readers Available readers.
+ * @param read
+ * @return
+ */
+ private SAMReaderID getReaderID(SAMReaders readers, SAMRecord read) {
+ for(SAMReaderID id: getReaderIDs()) {
+ if(readers.getReader(id) == read.getFileSource().getReader())
+ return id;
+ }
+ throw new ReviewedGATKException("Unable to find id for reader associated with read " + read.getReadName());
+ }
+
+ /**
+ * Get the initial reader positions across all BAM files
+ *
+ * @return the start positions of the first chunk of reads for all BAM files
+ */
+ protected Map<SAMReaderID, GATKBAMFileSpan> getInitialReaderPositions() {
+ Map<SAMReaderID, GATKBAMFileSpan> initialPositions = new HashMap<SAMReaderID, GATKBAMFileSpan>();
+ SAMReaders readers = resourcePool.getAvailableReaders();
+
+ for ( SAMReaderID id: getReaderIDs() ) {
+ initialPositions.put(id, new GATKBAMFileSpan(readers.getReader(id).getFilePointerSpanningReads()));
+ }
+
+ resourcePool.releaseReaders(readers);
+ return initialPositions;
+ }
+
+ /**
+ * Get an iterator over the data types specified in the shard.
+ *
+ * @param shard The shard specifying the data limits.
+ * @return An iterator over the selected data.
+ */
+ protected GATKSAMIterator getIterator( Shard shard ) {
+ return getIterator(resourcePool.getAvailableReaders(), shard, shard instanceof ReadShard);
+ }
+
+ /**
+ * Get an iterator over the data types specified in the shard.
+ * @param readers Readers from which to load data.
+ * @param shard The shard specifying the data limits.
+ * @param enableVerification True to verify. For compatibility with old sharding strategy.
+ * @return An iterator over the selected data.
+ */
+ private GATKSAMIterator getIterator(SAMReaders readers, Shard shard, boolean enableVerification) {
+ // Set up merging to dynamically merge together multiple BAMs.
+ Map<SAMFileReader,CloseableIterator<SAMRecord>> iteratorMap = new HashMap<SAMFileReader,CloseableIterator<SAMRecord>>();
+
+ for(SAMReaderID id: getReaderIDs()) {
+ CloseableIterator<SAMRecord> iterator = null;
+
+ // TODO: null used to be the signal for unmapped, but we've replaced that with a simple index query for the last bin.
+ // TODO: Kill this check once we've proven that the design elements are gone.
+ if(shard.getFileSpans().get(id) == null)
+ throw new ReviewedGATKException("SAMDataSource: received null location for reader " + id + ", but null locations are no longer supported.");
+
+ try {
+ if(threadAllocation.getNumIOThreads() > 0) {
+ BlockInputStream inputStream = readers.getInputStream(id);
+ inputStream.submitAccessPlan(new BAMAccessPlan(id, inputStream, (GATKBAMFileSpan) shard.getFileSpans().get(id)));
+ BAMRecordCodec codec = new BAMRecordCodec(getHeader(id),factory);
+ codec.setInputStream(inputStream);
+ iterator = new BAMCodecIterator(inputStream,readers.getReader(id),codec);
+ }
+ else {
+ iterator = readers.getReader(id).iterator(shard.getFileSpans().get(id));
+ }
+ } catch ( RuntimeException e ) { // we need to catch RuntimeExceptions here because the Picard code is throwing them (among SAMFormatExceptions) sometimes
+ throw new UserException.MalformedBAM(id.samFile, e.getMessage());
+ }
+
+ iterator = new MalformedBAMErrorReformatingIterator(id.samFile, iterator);
+ if(shard.getGenomeLocs().size() > 0)
+ iterator = new IntervalOverlapFilteringIterator(iterator,shard.getGenomeLocs());
+
+ iteratorMap.put(readers.getReader(id), iterator);
+ }
+
+ MergingSamRecordIterator mergingIterator = readers.createMergingIterator(iteratorMap);
+
+ // The readMetrics object being passed in should be that of this dataSource and NOT the shard: the dataSource's
+ // metrics is intended to keep track of the reads seen (and hence passed to the CountingFilteringIterator when
+ // we apply the decorators), whereas the shard's metrics is used to keep track the "records" seen.
+ return applyDecoratingIterators(readMetrics,
+ enableVerification,
+ readProperties.useOriginalBaseQualities(),
+ new ReleasingIterator(readers,GATKSAMIteratorAdapter.adapt(mergingIterator)),
+ readProperties.getValidationExclusionList().contains(ValidationExclusion.TYPE.NO_READ_ORDER_VERIFICATION),
+ readProperties.getSupplementalFilters(),
+ readProperties.getReadTransformers(),
+ readProperties.defaultBaseQualities(),
+ shard instanceof LocusShard);
+ }
+
+ private class BAMCodecIterator implements CloseableIterator<SAMRecord> {
+ private final BlockInputStream inputStream;
+ private final SAMFileReader reader;
+ private final BAMRecordCodec codec;
+ private SAMRecord nextRead;
+
+ private BAMCodecIterator(final BlockInputStream inputStream, final SAMFileReader reader, final BAMRecordCodec codec) {
+ this.inputStream = inputStream;
+ this.reader = reader;
+ this.codec = codec;
+ advance();
+ }
+
+ public boolean hasNext() {
+ return nextRead != null;
+ }
+
+ public SAMRecord next() {
+ if(!hasNext())
+ throw new NoSuchElementException("Unable to retrieve next record from BAMCodecIterator; input stream is empty");
+ SAMRecord currentRead = nextRead;
+ advance();
+ return currentRead;
+ }
+
+ public void close() {
+ // NO-OP.
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Unable to remove from BAMCodecIterator");
+ }
+
+ private void advance() {
+ final long startCoordinate = inputStream.getFilePointer();
+ nextRead = codec.decode();
+ final long stopCoordinate = inputStream.getFilePointer();
+
+ if(reader != null && nextRead != null)
+ PicardNamespaceUtils.setFileSource(nextRead, new SAMFileSource(reader, new GATKBAMFileSpan(new GATKChunk(startCoordinate, stopCoordinate))));
+ }
+ }
+
+ /**
+ * Filter reads based on user-specified criteria.
+ *
+ * @param readMetrics metrics to track when using this iterator.
+ * @param enableVerification Verify the order of reads.
+ * @param useOriginalBaseQualities True if original base qualities should be used.
+ * @param wrappedIterator the raw data source.
+ * @param noValidationOfReadOrder Another trigger for the verifying iterator? TODO: look into this.
+ * @param supplementalFilters additional filters to apply to the reads.
+ * @param defaultBaseQualities if the reads have incomplete quality scores, set them all to defaultBaseQuality.
+ * @param isLocusBasedTraversal true if we're dealing with a read stream from a LocusShard
+ * @return An iterator wrapped with filters reflecting the passed-in parameters. Will not be null.
+ */
+ protected GATKSAMIterator applyDecoratingIterators(ReadMetrics readMetrics,
+ boolean enableVerification,
+ boolean useOriginalBaseQualities,
+ GATKSAMIterator wrappedIterator,
+ Boolean noValidationOfReadOrder,
+ Collection<ReadFilter> supplementalFilters,
+ List<ReadTransformer> readTransformers,
+ byte defaultBaseQualities,
+ boolean isLocusBasedTraversal ) {
+
+ // Always apply the ReadFormattingIterator before both ReadFilters and ReadTransformers. At a minimum,
+ // this will consolidate the cigar strings into canonical form. This has to be done before the read
+ // filtering, because not all read filters will behave correctly with things like zero-length cigar
+ // elements. If useOriginalBaseQualities is true or defaultBaseQualities >= 0, this iterator will also
+ // modify the base qualities.
+ wrappedIterator = new ReadFormattingIterator(wrappedIterator, useOriginalBaseQualities, defaultBaseQualities);
+
+ // Read Filters: these are applied BEFORE downsampling, so that we downsample within the set of reads
+ // that actually survive filtering. Otherwise we could get much less coverage than requested.
+ wrappedIterator = GATKSAMIteratorAdapter.adapt(new CountingFilteringIterator(readMetrics,wrappedIterator,supplementalFilters));
+
+ // Downsampling:
+
+ // For locus traversals where we're downsampling to coverage by sample, assume that the downsamplers
+ // will be invoked downstream from us in LocusIteratorByState. This improves performance by avoiding
+ // splitting/re-assembly of the read stream at this stage, and also allows for partial downsampling
+ // of individual reads.
+ boolean assumeDownstreamLIBSDownsampling = isLocusBasedTraversal &&
+ readProperties.getDownsamplingMethod().type == DownsampleType.BY_SAMPLE &&
+ readProperties.getDownsamplingMethod().toCoverage != null;
+
+ // Apply downsampling iterators here only in cases where we know that LocusIteratorByState won't be
+ // doing any downsampling downstream of us
+ if ( ! assumeDownstreamLIBSDownsampling ) {
+ wrappedIterator = applyDownsamplingIterator(wrappedIterator);
+ }
+
+ // unless they've said not to validate read ordering (!noValidationOfReadOrder) and we've enabled verification,
+ // verify the read ordering by applying a sort order iterator
+ if (!noValidationOfReadOrder && enableVerification)
+ wrappedIterator = new VerifyingSamIterator(wrappedIterator);
+
+ // Read transformers: these are applied last, so that we don't bother transforming reads that get discarded
+ // by the read filters or downsampler.
+ for ( final ReadTransformer readTransformer : readTransformers ) {
+ if ( readTransformer.enabled() && readTransformer.getApplicationTime() == ReadTransformer.ApplicationTime.ON_INPUT )
+ wrappedIterator = new ReadTransformingIterator(wrappedIterator, readTransformer);
+ }
+
+ return wrappedIterator;
+ }
+
+ protected GATKSAMIterator applyDownsamplingIterator( GATKSAMIterator wrappedIterator ) {
+ if ( readProperties.getDownsamplingMethod() == null ||
+ readProperties.getDownsamplingMethod().type == DownsampleType.NONE ) {
+ return wrappedIterator;
+ }
+
+ if ( readProperties.getDownsamplingMethod().toFraction != null ) {
+
+ // If we're downsampling to a fraction of reads, there's no point in paying the cost of
+ // splitting/re-assembling the read stream by sample to run the FractionalDownsampler on
+ // reads from each sample separately, since the result would be the same as running the
+ // FractionalDownsampler on the entire stream. So, ALWAYS use the DownsamplingReadsIterator
+ // rather than the PerSampleDownsamplingReadsIterator, even if BY_SAMPLE downsampling
+ // was requested.
+
+ return new DownsamplingReadsIterator(wrappedIterator,
+ new FractionalDownsampler<SAMRecord>(readProperties.getDownsamplingMethod().toFraction));
+ }
+ else if ( readProperties.getDownsamplingMethod().toCoverage != null ) {
+
+ // If we're downsampling to coverage, we DO need to pay the cost of splitting/re-assembling
+ // the read stream to run the downsampler on the reads for each individual sample separately if
+ // BY_SAMPLE downsampling was requested.
+
+ if ( readProperties.getDownsamplingMethod().type == DownsampleType.BY_SAMPLE ) {
+ return new PerSampleDownsamplingReadsIterator(wrappedIterator,
+ new SimplePositionalDownsamplerFactory<SAMRecord>(readProperties.getDownsamplingMethod().toCoverage));
+ }
+ else if ( readProperties.getDownsamplingMethod().type == DownsampleType.ALL_READS ) {
+ return new DownsamplingReadsIterator(wrappedIterator,
+ new SimplePositionalDownsampler<SAMRecord>(readProperties.getDownsamplingMethod().toCoverage));
+ }
+ }
+
+ return wrappedIterator;
+ }
+
+
+ private class SAMResourcePool {
+ /**
+ * How many entries can be cached in this resource pool?
+ */
+ private final int maxEntries;
+
+ /**
+ * All iterators of this reference-ordered data.
+ */
+ private List<SAMReaders> allResources = new ArrayList<SAMReaders>();
+
+ /**
+ * All iterators that are not currently in service.
+ */
+ private List<SAMReaders> availableResources = new ArrayList<SAMReaders>();
+
+ public SAMResourcePool(final int maxEntries) {
+ this.maxEntries = maxEntries;
+ }
+
+ /**
+ * Choose a set of readers from the pool to use for this query. When complete,
+ * @return
+ */
+ public synchronized SAMReaders getAvailableReaders() {
+ if(availableResources.size() == 0)
+ createNewResource();
+ SAMReaders readers = availableResources.get(0);
+ availableResources.remove(readers);
+ return readers;
+ }
+
+ public synchronized void releaseReaders(SAMReaders readers) {
+ if(!allResources.contains(readers))
+ throw new ReviewedGATKException("Tried to return readers from the pool that didn't originate in the pool.");
+ availableResources.add(readers);
+ }
+
+ /**
+ * Gets the reader id for the given reader.
+ * @param reader Reader for which to determine the id.
+ * @return id of the given reader.
+ */
+ protected synchronized SAMReaderID getReaderID(SamReader reader) {
+ for(SAMReaders readers: allResources) {
+ SAMReaderID id = readers.getReaderID(reader);
+ if(id != null)
+ return id;
+ }
+ throw new ReviewedGATKException("No such reader id is available");
+ }
+
+ private synchronized void createNewResource() {
+ if(allResources.size() > maxEntries)
+ throw new ReviewedGATKException("Cannot create a new resource pool. All resources are in use.");
+ SAMReaders readers = new SAMReaders(readerIDs, validationStringency, removeProgramRecords);
+ allResources.add(readers);
+ availableResources.add(readers);
+ }
+
+ }
+
+ /**
+ * A collection of readers derived from a reads metadata structure.
+ */
+ private class SAMReaders implements Iterable<SAMFileReader> {
+ /**
+ * Cached representation of the merged header used to generate a merging iterator.
+ */
+ private final SamFileHeaderMerger headerMerger;
+
+ /**
+ * Internal storage for a map of id -> reader.
+ */
+ private final Map<SAMReaderID,SAMFileReader> readers = new LinkedHashMap<SAMReaderID,SAMFileReader>();
+
+ /**
+ * The inptu streams backing
+ */
+ private final Map<SAMReaderID,BlockInputStream> inputStreams = new LinkedHashMap<SAMReaderID,BlockInputStream>();
+
+ /**
+ * Derive a new set of readers from the Reads metadata.
+ * @param readerIDs reads to load.
+ * TODO: validationStringency is not used here
+ * @param validationStringency validation stringency.
+ * @param removeProgramRecords indicate whether to clear program records from the readers
+ */
+ public SAMReaders(Collection<SAMReaderID> readerIDs, ValidationStringency validationStringency, boolean removeProgramRecords) {
+ final int totalNumberOfFiles = readerIDs.size();
+ int readerNumber = 1;
+ final SimpleTimer timer = new SimpleTimer().start();
+
+ if ( totalNumberOfFiles > 0 ) logger.info("Initializing SAMRecords in serial");
+ final int tickSize = 50;
+ int nExecutedTotal = 0;
+ long lastTick = timer.currentTime();
+ for(final SAMReaderID readerID: readerIDs) {
+ final ReaderInitializer init = new ReaderInitializer(readerID).call();
+
+ checkForUnsupportedBamFile(init.reader.getFileHeader());
+
+ if (removeProgramRecords) {
+ init.reader.getFileHeader().setProgramRecords(new ArrayList<SAMProgramRecord>());
+ }
+
+ if (threadAllocation.getNumIOThreads() > 0) {
+ inputStreams.put(init.readerID, init.blockInputStream); // get from initializer
+ }
+
+ logger.debug(String.format("Processing file (%d of %d) %s...", readerNumber++, totalNumberOfFiles, readerID.samFile));
+ readers.put(init.readerID,init.reader);
+ if ( ++nExecutedTotal % tickSize == 0) {
+ double tickInSec = (timer.currentTime() - lastTick) / 1000.0;
+ printReaderPerformance(nExecutedTotal, tickSize, totalNumberOfFiles, timer, tickInSec);
+ lastTick = timer.currentTime();
+ }
+ }
+
+ if ( totalNumberOfFiles > 0 ) logger.info(String.format("Done initializing BAM readers: total time %.2f", timer.getElapsedTime()));
+
+ Collection<SAMFileHeader> headers = new LinkedList<SAMFileHeader>();
+
+ // Examine the bam headers, perform any requested sample renaming on them, and add
+ // them to the list of headers to pass to the Picard SamFileHeaderMerger:
+ for ( final Map.Entry<SAMReaderID, SAMFileReader> readerEntry : readers.entrySet() ) {
+ final SAMReaderID readerID = readerEntry.getKey();
+ final SAMFileReader reader = readerEntry.getValue();
+ final SAMFileHeader header = reader.getFileHeader();
+
+ // The remappedSampleName will be null if either no on-the-fly sample renaming was requested,
+ // or the user's sample rename map file didn't contain an entry for this bam file:
+ final String remappedSampleName = sampleRenameMap != null ? sampleRenameMap.get(readerID.getSamFilePath()) : null;
+
+ // If we've been asked to rename the sample for this bam file, do so now. We'll check to
+ // make sure this bam only contains reads from one sample before proceeding.
+ //
+ // IMPORTANT: relies on the fact that the Picard SamFileHeaderMerger makes a copy of
+ // the existing read group attributes (including sample name) when merging
+ // headers, regardless of whether there are read group collisions or not.
+ if ( remappedSampleName != null ) {
+ remapSampleName(readerID, header, remappedSampleName);
+ }
+
+ headers.add(header);
+ }
+
+ headerMerger = new SamFileHeaderMerger(SAMFileHeader.SortOrder.coordinate,headers,true);
+
+ // update all read groups to GATKSAMRecordReadGroups
+ final List<SAMReadGroupRecord> gatkReadGroups = new LinkedList<SAMReadGroupRecord>();
+ for ( final SAMReadGroupRecord rg : headerMerger.getMergedHeader().getReadGroups() ) {
+ gatkReadGroups.add(new GATKSAMReadGroupRecord(rg));
+ }
+ headerMerger.getMergedHeader().setReadGroups(gatkReadGroups);
+ }
+
+ /**
+ * Changes the sample name in the read groups for the provided bam file header to match the
+ * remappedSampleName. Blows up with a UserException if the header contains more than one
+ * sample name.
+ *
+ * @param readerID ID for the bam file from which the provided header came from
+ * @param header The bam file header. Will be modified by this call.
+ * @param remappedSampleName New sample name to replace the existing sample attribute in the
+ * read groups for the header.
+ */
+ private void remapSampleName( final SAMReaderID readerID, final SAMFileHeader header, final String remappedSampleName ) {
+ String firstEncounteredSample = null;
+
+ for ( final SAMReadGroupRecord readGroup : header.getReadGroups() ) {
+ final String thisReadGroupSample = readGroup.getSample();
+
+ if ( thisReadGroupSample == null ) {
+ throw new UserException(String.format("On-the fly sample renaming was requested for bam file %s, however this " +
+ "bam file contains a read group (id: %s) with a null sample attribute",
+ readerID.getSamFilePath(), readGroup.getId()));
+ }
+ else if ( firstEncounteredSample == null ) {
+ firstEncounteredSample = thisReadGroupSample;
+ }
+ else if ( ! firstEncounteredSample.equals(thisReadGroupSample) ) {
+ throw new UserException(String.format("On-the-fly sample renaming was requested for bam file %s, " +
+ "however this bam file contains reads from more than one sample " +
+ "(encountered samples %s and %s in the bam header). The GATK requires that " +
+ "all bams for which on-the-fly sample renaming is requested " +
+ "contain reads from only a single sample per bam.",
+ readerID.getSamFilePath(), firstEncounteredSample, thisReadGroupSample));
+ }
+
+ readGroup.setSample(remappedSampleName);
+ }
+ }
+
+ final private void printReaderPerformance(final int nExecutedTotal,
+ final int nExecutedInTick,
+ final int totalNumberOfFiles,
+ final SimpleTimer timer,
+ final double tickDurationInSec) {
+ final int pendingSize = totalNumberOfFiles - nExecutedTotal;
+ final double totalTimeInSeconds = timer.getElapsedTime();
+ final double nTasksPerSecond = nExecutedTotal / (1.0*totalTimeInSeconds);
+ final int nRemaining = pendingSize;
+ final double estTimeToComplete = pendingSize / nTasksPerSecond;
+ logger.info(String.format("Init %d BAMs in last %.2f s, %d of %d in %.2f s / %.2f m (%.2f tasks/s). %d remaining with est. completion in %.2f s / %.2f m",
+ nExecutedInTick, tickDurationInSec,
+ nExecutedTotal, totalNumberOfFiles, totalTimeInSeconds, totalTimeInSeconds / 60, nTasksPerSecond,
+ nRemaining, estTimeToComplete, estTimeToComplete / 60));
+ }
+
+ /**
+ * Return the header derived from the merging of these BAM files.
+ * @return the merged header.
+ */
+ public SAMFileHeader getMergedHeader() {
+ return headerMerger.getMergedHeader();
+ }
+
+ /**
+ * Do multiple read groups collide in this dataset?
+ * @return True if multiple read groups collide; false otherwis.
+ */
+ public boolean hasReadGroupCollisions() {
+ return headerMerger.hasReadGroupCollisions();
+ }
+
+ /**
+ * Get the newly mapped read group ID for the given read group.
+ * @param readerID Reader for which to discern the transformed ID.
+ * @param originalReadGroupID Original read group.
+ * @return Remapped read group.
+ */
+ public String getReadGroupId(final SAMReaderID readerID, final String originalReadGroupID) {
+ SAMFileHeader header = readers.get(readerID).getFileHeader();
+ return headerMerger.getReadGroupId(header,originalReadGroupID);
+ }
+
+ /**
+ * Creates a new merging iterator from the given map, with the given header.
+ * @param iteratorMap A map of readers to iterators.
+ * @return An iterator which will merge those individual iterators.
+ */
+ public MergingSamRecordIterator createMergingIterator(final Map<SAMFileReader,CloseableIterator<SAMRecord>> iteratorMap) {
+ return new MergingSamRecordIterator(headerMerger,iteratorMap,true);
+ }
+
+ /**
+ * Retrieve the reader from the data structure.
+ * @param id The ID of the reader to retrieve.
+ * @return the reader associated with the given id.
+ */
+ public SAMFileReader getReader(SAMReaderID id) {
+ if(!readers.containsKey(id))
+ throw new NoSuchElementException("No reader is associated with id " + id);
+ return readers.get(id);
+ }
+
+ /**
+ * Retrieve the input stream backing a reader.
+ * @param id The ID of the reader to retrieve.
+ * @return the reader associated with the given id.
+ */
+ public BlockInputStream getInputStream(final SAMReaderID id) {
+ return inputStreams.get(id);
+ }
+
+ /**
+ * Searches for the reader id of this reader.
+ * @param reader Reader for which to search.
+ * @return The id associated the given reader, or null if the reader is not present in this collection.
+ */
+ protected SAMReaderID getReaderID(SamReader reader) {
+ for(Map.Entry<SAMReaderID,SAMFileReader> entry: readers.entrySet()) {
+ if(reader == entry.getValue())
+ return entry.getKey();
+ }
+ // Not found? return null.
+ return null;
+ }
+
+ /**
+ * Returns an iterator over all readers in this structure.
+ * @return An iterator over readers.
+ */
+ public Iterator<SAMFileReader> iterator() {
+ return readers.values().iterator();
+ }
+
+ /**
+ * Returns whether any readers are present in this structure.
+ * @return
+ */
+ public boolean isEmpty() {
+ return readers.isEmpty();
+ }
+ }
+
+ class ReaderInitializer implements Callable<ReaderInitializer> {
+ final SAMReaderID readerID;
+ BlockInputStream blockInputStream = null;
+ SAMFileReader reader;
+
+ public ReaderInitializer(final SAMReaderID readerID) {
+ this.readerID = readerID;
+ }
+
+ public ReaderInitializer call() {
+ final File indexFile = findIndexFile(readerID.samFile);
+ try {
+ if (threadAllocation.getNumIOThreads() > 0)
+ blockInputStream = new BlockInputStream(dispatcher,readerID,false);
+ reader = new SAMFileReader(readerID.samFile,indexFile,false);
+ } catch ( RuntimeIOException e ) {
+ throw new UserException.CouldNotReadInputFile(readerID.samFile, e);
+ } catch ( SAMFormatException e ) {
+ throw new UserException.MalformedBAM(readerID.samFile, e.getMessage());
+ }
+ // Picard is throwing a RuntimeException here when BAMs are malformed with bad headers (and so look like SAM files).
+ // Let's keep this separate from the SAMFormatException (which ultimately derives from RuntimeException) case,
+ // just in case we want to change this behavior later.
+ catch ( RuntimeException e ) {
+ throw new UserException.MalformedBAM(readerID.samFile, e.getMessage());
+ }
+ reader.setSAMRecordFactory(factory);
+ reader.enableFileSource(true);
+ reader.setValidationStringency(validationStringency);
+ return this;
+ }
+ }
+
+ private class ReleasingIterator implements GATKSAMIterator {
+ /**
+ * The resource acting as the source of the data.
+ */
+ private final SAMReaders resource;
+
+ /**
+ * The iterator to wrap.
+ */
+ private final GATKSAMIterator wrappedIterator;
+
+ public ReleasingIterator(SAMReaders resource, GATKSAMIterator wrapped) {
+ this.resource = resource;
+ this.wrappedIterator = wrapped;
+ }
+
+ public ReleasingIterator iterator() {
+ return this;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Can't remove from a GATKSAMIterator");
+ }
+
+ public void close() {
+ wrappedIterator.close();
+ resourcePool.releaseReaders(resource);
+ }
+
+ public boolean hasNext() {
+ return wrappedIterator.hasNext();
+ }
+
+ public SAMRecord next() {
+ return wrappedIterator.next();
+ }
+ }
+
+ /**
+ * Maps read groups in the original SAMFileReaders to read groups in
+ */
+ private class ReadGroupMapping extends HashMap<String,String> {}
+
+ /**
+ * Locates the index file alongside the given BAM, if present.
+ * @param bamFile The data file to use.
+ * @return A File object if the index file is present; null otherwise.
+ */
+ private File findIndexFile(File bamFile) {
+ return SamFiles.findIndex(bamFile);
+ }
+
+ /**
+ * Creates a BAM schedule over all reads in the BAM file, both mapped and unmapped. The outgoing stream
+ * will be as granular as possible given our current knowledge of the best ways to split up BAM files.
+ * @return An iterator that spans all reads in all BAM files.
+ */
+ public Iterable<Shard> createShardIteratorOverAllReads(final ShardBalancer shardBalancer) {
+ shardBalancer.initialize(this,IntervalSharder.shardOverAllReads(this,genomeLocParser),genomeLocParser);
+ return shardBalancer;
+ }
+
+ /**
+ * Creates a BAM schedule over all mapped reads in the BAM file, when a 'mapped' read is defined as any
+ * read that has been assigned
+ *
+ * @param shardBalancer shard balancer object
+ * @return non-null initialized version of the shard balancer
+ */
+ public Iterable<Shard> createShardIteratorOverMappedReads(final ShardBalancer shardBalancer) {
+ shardBalancer.initialize(this,IntervalSharder.shardOverMappedReads(this,genomeLocParser),genomeLocParser);
+ return shardBalancer;
+ }
+
+ /**
+ * Create a schedule for processing the initialized BAM file using the given interval list.
+ * The returned schedule should be as granular as possible.
+ * @param intervals The list of intervals for which to create the schedule.
+ * @return A granular iterator over file pointers.
+ */
+ public Iterable<Shard> createShardIteratorOverIntervals(final GenomeLocSortedSet intervals,final ShardBalancer shardBalancer) {
+ if(intervals == null)
+ throw new ReviewedGATKException("Unable to create schedule from intervals; no intervals were provided.");
+ shardBalancer.initialize(this,IntervalSharder.shardOverIntervals(SAMDataSource.this,intervals,intervalMergingRule),genomeLocParser);
+ return shardBalancer;
+ }
+}
+
+
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/SAMReaderID.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/SAMReaderID.java
new file mode 100644
index 0000000..ef5aaa0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/SAMReaderID.java
@@ -0,0 +1,125 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import org.broadinstitute.gatk.utils.commandline.Tags;
+
+import java.io.File;
+
+/**
+ * Uniquely identifies a SAM file reader.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class SAMReaderID implements Comparable {
+ /**
+ * The SAM file at the heart of this reader. SAMReaderID
+ * currently supports only file-based readers.
+ */
+ protected final File samFile;
+
+ /**
+ * A list of tags associated with this BAM file.
+ */
+ protected final Tags tags;
+
+ /**
+ * Creates an identifier for a SAM file based on read.
+ * @param samFile The source file for SAM data.
+ * @param tags tags to use when creating a reader ID.
+ */
+ public SAMReaderID(File samFile, Tags tags) {
+ this.samFile = samFile;
+ this.tags = tags;
+ }
+
+ /**
+ * Creates an identifier for a SAM file based on read.
+ * @param samFileName The source filename for SAM data.
+ * @param tags tags to use when creating a reader ID.
+ */
+ public SAMReaderID(String samFileName, Tags tags) {
+ this(new File(samFileName),tags);
+ }
+
+ /**
+ * Gets the absolute pathname of this SAM file
+ * @return The absolute pathname of this reader's SAM file,
+ * or null if this reader has no associated SAM file
+ */
+ public String getSamFilePath() {
+ if ( samFile == null ) {
+ return null;
+ }
+
+ return samFile.getAbsolutePath();
+ }
+
+ /**
+ * Gets the tags associated with the given BAM file.
+ * @return A collection of the tags associated with this file.
+ */
+ public Tags getTags() {
+ return tags;
+ }
+
+ /**
+ * Compare two IDs to see whether they're equal.
+ * @param other The other identifier.
+ * @return True iff the two readers point to the same file.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if(other == null) return false;
+ if(!(other instanceof SAMReaderID)) return false;
+
+ SAMReaderID otherID = (SAMReaderID)other;
+ return this.getSamFilePath().equals(otherID.getSamFilePath());
+ }
+
+ /**
+ * Generate a hash code for this object.
+ * @return A hash code, based solely on the file name at this point.
+ */
+ @Override
+ public int hashCode() {
+ return samFile.getAbsolutePath().hashCode();
+ }
+
+ /**
+ * Best string representation for a SAM file reader is the path of the source file.
+ */
+ @Override
+ public String toString() {
+ return getSamFilePath();
+ }
+
+ @Override
+ public int compareTo(Object other) {
+ return this.samFile.getAbsolutePath().compareTo(((SAMReaderID)other).samFile.getAbsolutePath());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/Shard.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/Shard.java
new file mode 100644
index 0000000..cc8944c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/Shard.java
@@ -0,0 +1,253 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.util.PeekableIterator;
+import htsjdk.samtools.SAMFileSpan;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.ReadMetrics;
+import org.broadinstitute.gatk.engine.ReadProperties;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.HasGenomeLocation;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+/**
+ *
+ * User: aaron
+ * Date: Apr 10, 2009
+ * Time: 5:00:27 PM
+ *
+ * The Broad Institute
+ * SOFTWARE COPYRIGHT NOTICE AGREEMENT
+ * This software and its documentation are copyright 2009 by the
+ * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
+ *
+ * This software is supplied without any warranty or guaranteed support whatsoever. Neither
+ * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
+ *
+ */
+
+/**
+ * @author aaron
+ * @version 1.0
+ * @date Apr 10, 2009
+ * <p/>
+ * Interface Shard
+ * <p/>
+ * The base abstract class for shards.
+ */
+public abstract class Shard implements HasGenomeLocation {
+ public enum ShardType {
+ READ, LOCUS
+ }
+
+ protected final GenomeLocParser parser; // incredibly annoying!
+
+ /**
+ * What type of shard is this? Read or locus?
+ */
+ protected final ShardType shardType;
+
+ /**
+ * Locations.
+ */
+ protected final List<GenomeLoc> locs;
+
+ /**
+ * Whether the current location is unmapped.
+ */
+ private final boolean isUnmapped;
+
+ /**
+ * Reads data, if applicable.
+ */
+ private final SAMDataSource readsDataSource;
+
+ /**
+ * The data backing the next chunks to deliver to the traversal engine.
+ */
+ private final Map<SAMReaderID,SAMFileSpan> fileSpans;
+
+ /**
+ * Lazy-calculated span of all of the genome locs in this shard
+ */
+ private GenomeLoc spanningLocation = null;
+
+ /**
+ * Statistics about which reads in this shards were used and which were filtered away.
+ */
+ protected final ReadMetrics readMetrics = new ReadMetrics();
+
+ /**
+ * Whether this shard points to an unmapped region.
+ * Some shard types conceptually be unmapped (e.g. LocusShards). In
+ * this case, isUnmapped should always return false.
+ * @return True if this shard is unmapped. False otherwise.
+ */
+ public boolean isUnmapped() {
+ return isUnmapped;
+ }
+
+ public Shard(GenomeLocParser parser,
+ ShardType shardType,
+ List<GenomeLoc> locs,
+ SAMDataSource readsDataSource,
+ Map<SAMReaderID,SAMFileSpan> fileSpans,
+ boolean isUnmapped) {
+ this.locs = locs;
+ this.parser = parser;
+ this.shardType = shardType;
+ this.readsDataSource = readsDataSource;
+ this.fileSpans = fileSpans;
+ this.isUnmapped = isUnmapped;
+ }
+
+ /**
+ * If isUnmapped is true, than getGenomeLocs by
+ * definition will return a singleton list with a GenomeLoc.UNMAPPED
+ *
+ * Can return null, indicating that the entire genome is covered.
+ *
+ * @return the genome location represented by this shard
+ */
+ public List<GenomeLoc> getGenomeLocs() {
+ return locs;
+ }
+
+ /**
+ * Get the list of chunks delimiting this shard.
+ * @return a list of chunks that contain data for this shard.
+ */
+ public Map<SAMReaderID,SAMFileSpan> getFileSpans() {
+ return Collections.unmodifiableMap(fileSpans);
+ }
+
+ /**
+ * Returns the span of the genomeLocs comprising this shard
+ * @return a GenomeLoc that starts as the first position in getGenomeLocs() and stops at the stop of the last
+ * position in getGenomeLocs()
+ */
+ public GenomeLoc getLocation() {
+ if ( spanningLocation == null ) {
+ if ( getGenomeLocs() == null )
+ spanningLocation = GenomeLoc.WHOLE_GENOME;
+ else if ( getGenomeLocs().size() == 0 ) {
+ spanningLocation = getGenomeLocs().get(0);
+ } else {
+ int start = Integer.MAX_VALUE;
+ int stop = Integer.MIN_VALUE;
+ String contig = null;
+
+ for ( GenomeLoc loc : getGenomeLocs() ) {
+ if ( GenomeLoc.isUnmapped(loc) )
+ // special case the unmapped region marker, just abort out
+ return loc;
+ contig = loc.getContig();
+ if ( loc.getStart() < start ) start = loc.getStart();
+ if ( loc.getStop() > stop ) stop = loc.getStop();
+ }
+
+ spanningLocation = parser.createGenomeLoc(contig, start, stop);
+ }
+ }
+
+ return spanningLocation;
+ }
+
+
+ /**
+ * what kind of shard do we return
+ * @return ShardType, indicating the type
+ */
+ public ShardType getShardType() {
+ return shardType;
+ }
+
+ /**
+ * Does any releasing / aggregation required when the shard is through being processed.
+ */
+ public void close() {
+ readsDataSource.incorporateReadMetrics(readMetrics);
+ }
+
+ /**
+ * Gets key read validation and filtering properties.
+ * @return set of read properties associated with this shard.
+ */
+ public ReadProperties getReadProperties() {
+ return readsDataSource.getReadsInfo();
+ }
+
+ /**
+ * Gets the runtime metrics associated with this shard.
+ * Retrieves a storage space of metrics about number of reads included, filtered, etc.
+ * @return Storage space for metrics.
+ */
+ public ReadMetrics getReadMetrics() {
+ return readMetrics;
+ }
+
+ /**
+ * Returns true if this shard is meant to buffer reads, rather
+ * than just holding pointers to their locations.
+ * @return True if this shard can buffer reads. False otherwise.
+ */
+ public boolean buffersReads() { return false; }
+
+ /**
+ * Returns true if the read buffer is currently full.
+ * @return True if this shard's buffer is full (and the shard can buffer reads).
+ */
+ public boolean isBufferEmpty() { throw new UnsupportedOperationException("This shard does not buffer reads."); }
+
+ /**
+ * Returns true if the read buffer is currently full.
+ * @return True if this shard's buffer is full (and the shard can buffer reads).
+ */
+ public boolean isBufferFull() { throw new UnsupportedOperationException("This shard does not buffer reads."); }
+
+ /**
+ * Adds a read to the read buffer.
+ * @param read Add a read to the internal shard buffer.
+ */
+ public void addRead(SAMRecord read) { throw new UnsupportedOperationException("This shard does not buffer reads."); }
+
+ /**
+ * Fills the shard with reads. Can only do this with shards that buffer reads
+ * @param readIter Iterator from which to draw the reads to fill the shard
+ */
+ public void fill( PeekableIterator<SAMRecord> readIter ) { throw new UnsupportedOperationException("This shard does not buffer reads."); }
+
+ /**
+ * Gets the iterator over the elements cached in the shard.
+ * @return
+ */
+ public GATKSAMIterator iterator() { throw new UnsupportedOperationException("This shard does not buffer reads."); }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ShardBalancer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ShardBalancer.java
new file mode 100644
index 0000000..237a380
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/ShardBalancer.java
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.util.PeekableIterator;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+import java.util.Iterator;
+
+/**
+ * Balances maximally granular file pointers into shards of reasonable size.
+ */
+public abstract class ShardBalancer implements Iterable<Shard> {
+ protected SAMDataSource readsDataSource;
+ protected PeekableIterator<FilePointer> filePointers;
+ protected GenomeLocParser parser;
+
+ public void initialize(final SAMDataSource readsDataSource, final Iterator<FilePointer> filePointers, final GenomeLocParser parser) {
+ this.readsDataSource = readsDataSource;
+ this.filePointers = new PeekableIterator<FilePointer>(filePointers);
+ this.parser = parser;
+ }
+ public void close() {
+ this.filePointers.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/package-info.java
new file mode 100644
index 0000000..f3506f2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/BAMFileStat.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/BAMFileStat.java
new file mode 100644
index 0000000..95e0341
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/BAMFileStat.java
@@ -0,0 +1,185 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads.utilities;
+
+import htsjdk.samtools.BAMIndex;
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.ValidationStringency;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.instrumentation.Sizeof;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class BAMFileStat extends CommandLineProgram {
+ public enum CommandType { ShowBlocks, ShowIndex }
+
+ @Argument(doc="Which operation to run.",required=true)
+ private CommandType command;
+
+ @Argument(doc="The BAM file to inspect.",required=true)
+ private String bamFileName;
+
+ @Argument(doc="The range to inspect.",required=false)
+ private String range;
+
+ public int execute() {
+ switch(command) {
+ case ShowBlocks:
+ throw new ReviewedGATKException("The BAM block inspector has been disabled.");
+ case ShowIndex:
+ showIndexBins(new File(bamFileName),range);
+ break;
+ }
+ return 0;
+ }
+
+ /**
+ * Required main method implementation.
+ * @param argv Command-line arguments.
+ */
+ public static void main(String[] argv) {
+ try {
+ BAMFileStat instance = new BAMFileStat();
+ start(instance, argv);
+ System.exit(CommandLineProgram.result);
+ } catch (Exception e) {
+ exitSystemWithError(e);
+ }
+ }
+
+ private void showIndexBins(File bamFile,String contigName) {
+ SAMFileReader reader;
+ BAMIndex index;
+
+ reader = new SAMFileReader(bamFile);
+ reader.setValidationStringency(ValidationStringency.SILENT);
+ reader.enableIndexCaching(true);
+ index = reader.getIndex();
+
+ reader.queryOverlapping(contigName,1,reader.getFileHeader().getSequence(contigName).getSequenceLength()).close();
+
+ int numBins = 0;
+ int numChunks = 0;
+ int numLinearIndexEntries = 0;
+
+ try {
+ Field[] fields = index.getClass().getDeclaredFields();
+ for(Field field: fields) {
+ if(field.getName().equals("mLastReferenceRetrieved")) {
+ field.setAccessible(true);
+ Integer lastReferenceRetrieved = (Integer)field.get(index);
+ System.out.printf("Last reference retrieved: %d%n", lastReferenceRetrieved);
+ }
+
+ if(field.getName().equals("mQueriesByReference")) {
+ field.setAccessible(true);
+ Map<Integer,Object> cachedQueries = (Map<Integer,Object>)field.get(index);
+
+ for(Object bamIndexContent: cachedQueries.values()) {
+ List<Object> bins = null;
+ Map<Object,Object> binToChunkMap = null;
+ Object linearIndex = null;
+
+ Field[] indexContentFields = bamIndexContent.getClass().getDeclaredFields();
+ for(Field indexContentField: indexContentFields) {
+ if(indexContentField.getName().equals("mReferenceSequence")) {
+ indexContentField.setAccessible(true);
+ System.out.printf("Reference sequence: %d%n", indexContentField.getInt(bamIndexContent));
+ }
+
+ if(indexContentField.getName().equals("mBins")) {
+ indexContentField.setAccessible(true);
+ bins = (List<Object>)indexContentField.get(bamIndexContent);
+ }
+
+ if(indexContentField.getName().equals("mBinToChunks")) {
+ indexContentField.setAccessible(true);
+ binToChunkMap = (Map<Object,Object>)indexContentField.get(bamIndexContent);
+ }
+
+ if(indexContentField.getName().equals("mLinearIndex")) {
+ indexContentField.setAccessible(true);
+ linearIndex = indexContentField.get(bamIndexContent);
+ }
+ }
+
+ numBins = bins.size();
+ for(Object bin: bins) {
+ int binNumber;
+
+ Field[] binFields = bin.getClass().getDeclaredFields();
+ for(Field binField: binFields) {
+ if(binField.getName().equals("binNumber")) {
+ binField.setAccessible(true);
+ binNumber = binField.getInt(bin);
+ List<Object> chunks = (List<Object>)binToChunkMap.get(bin);
+ System.out.printf("\tBin: %d, number of chunks: %d%n",binNumber,chunks.size());
+ for(Object chunk: chunks)
+ System.out.printf("\t\tChunk: %s%n",chunk);
+ numChunks += chunks.size();
+ }
+ }
+ }
+
+ Field[] linearIndexFields = linearIndex.getClass().getDeclaredFields();
+ for(Field linearIndexField: linearIndexFields) {
+ if(linearIndexField.getName().equals("mIndexEntries")) {
+ linearIndexField.setAccessible(true);
+ long[] linearIndexEntries = (long[])linearIndexField.get(linearIndex);
+ System.out.printf("\t\tIndex entries: %d", linearIndexEntries.length);
+ for(long indexEntry: linearIndexEntries)
+ System.out.printf("%d,",indexEntry);
+ System.out.printf("%n");
+ numLinearIndexEntries = linearIndexEntries.length;
+ }
+ }
+ }
+ }
+ }
+ }
+ catch(IllegalAccessException ex) {
+ throw new ReviewedGATKException("Unable to examine cached index",ex);
+ }
+
+ System.out.printf("%nOverall: %d bins, %d chunks, %d linear index entries",numBins,numChunks,numLinearIndexEntries);
+ if(Sizeof.isEnabled())
+ System.out.printf(", total index size in bytes: %d",Sizeof.getObjectGraphSize(index));
+ System.out.println();
+
+ reader.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/BAMTagRenamer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/BAMTagRenamer.java
new file mode 100644
index 0000000..bde44a0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/BAMTagRenamer.java
@@ -0,0 +1,100 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads.utilities;
+
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMFileWriter;
+import htsjdk.samtools.SAMFileWriterFactory;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+
+import java.io.File;
+
+/**
+ * A simple utility written directly in Picard that will rename tags
+ * from one name to another.
+ *
+ * @author hanna
+ * @version 0.1
+ */
+
+public class BAMTagRenamer extends CommandLineProgram {
+ @Argument(fullName="input",shortName="I",doc="Input file to process",required=true)
+ private File input = null;
+
+ @Argument(fullName="output",shortName="O",doc="Output file to create",required=true)
+ private File output = null;
+
+ @Argument(fullName="bam_compression",shortName="compress",doc="Compression level to use when writing the BAM file.",required=false)
+ private int compressionLevel = 5;
+
+ @Argument(fullName="original_tag_name",shortName="otn",doc="Tag name to be replaced.",required=true)
+ private String sourceTagName = null;
+
+ @Argument(fullName="replacement_tag_name",shortName="rtn",doc="Tag name to be used as a replacement.",required=true)
+ private String targetTagName = null;
+
+ public int execute() {
+ long readsWritten = 0;
+ long readsAltered = 0;
+
+ SAMFileReader reader = new SAMFileReader(input);
+ SAMFileWriter writer = new SAMFileWriterFactory().makeBAMWriter(reader.getFileHeader(),true,output,compressionLevel);
+
+ for(SAMRecord read: reader) {
+ Object value = read.getAttribute(sourceTagName);
+ if(value != null) {
+ read.setAttribute(sourceTagName,null);
+ read.setAttribute(targetTagName,value);
+ readsAltered++;
+ }
+ writer.addAlignment(read);
+ readsWritten++;
+ if(readsWritten % 1000000 == 0)
+ System.out.printf("%d reads written. %d tag names updated from %s to %s.%n",readsWritten,readsAltered,sourceTagName,targetTagName);
+ }
+
+ writer.close();
+ System.out.printf("%d reads written. %d tag names updated from %s to %s.%n",readsWritten,readsAltered,sourceTagName,targetTagName);
+
+ return 0;
+ }
+
+ /**
+ * Required main method implementation.
+ */
+ public static void main(String[] argv) {
+ BAMTagRenamer instance = new BAMTagRenamer();
+ try {
+ start(instance, argv);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ System.exit(CommandLineProgram.result);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/FindLargeShards.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/FindLargeShards.java
new file mode 100644
index 0000000..9105b4c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/FindLargeShards.java
@@ -0,0 +1,192 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads.utilities;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.datasources.reads.FilePointer;
+import org.broadinstitute.gatk.engine.datasources.reads.IntervalSharder;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMDataSource;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.interval.IntervalUtils;
+import org.broadinstitute.gatk.utils.text.ListFileUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Traverses a region in a dataset looking for outliers.
+ */
+public class FindLargeShards extends CommandLineProgram {
+ private static Logger logger = Logger.getLogger(FindLargeShards.class);
+
+ @Input(fullName = "input_file", shortName = "I", doc = "SAM or BAM file(s)", required = false)
+ public List<String> samFiles = new ArrayList<String>();
+
+ @Input(fullName = "reference_sequence", shortName = "R", doc = "Reference sequence file", required = false)
+ public File referenceFile = null;
+
+ @Input(fullName = "intervals", shortName = "L", doc = "A list of genomic intervals over which to operate. Can be explicitly specified on the command line or in a file.",required=false)
+ public List<String> intervals = null;
+
+ @Output(required=false)
+ public PrintStream out = System.out;
+
+ /**
+ * The square of the sum of all uncompressed data. Based on the BAM spec, the size of this could be
+ * up to (2^64)^2.
+ */
+ private BigInteger sumOfSquares = BigInteger.valueOf(0);
+
+ /**
+ * The running sum of all uncompressed data. Based on the BAM spec, the BAM must be less than Long.MAX_LONG
+ * when compressed -- in other words, the sum of the sizes of all BGZF blocks must be < 2^64.
+ */
+ private BigInteger sum = BigInteger.valueOf(0);
+
+ /**
+ * The number of shards viewed.
+ */
+ private long numberOfShards;
+
+
+ @Override
+ public int execute() throws IOException {
+ // initialize reference
+ IndexedFastaSequenceFile refReader = new IndexedFastaSequenceFile(referenceFile);
+ GenomeLocParser genomeLocParser = new GenomeLocParser(refReader);
+
+ // initialize reads
+ List<SAMReaderID> bamReaders = ListFileUtils.unpackBAMFileList(samFiles,parser);
+ SAMDataSource dataSource = new SAMDataSource(bamReaders,new ThreadAllocation(),null,genomeLocParser);
+
+ // intervals
+ final GenomeLocSortedSet intervalSortedSet;
+ if ( intervals != null )
+ intervalSortedSet = IntervalUtils.sortAndMergeIntervals(genomeLocParser, IntervalUtils.parseIntervalArguments(genomeLocParser, intervals), IntervalMergingRule.ALL);
+ else
+ intervalSortedSet = GenomeLocSortedSet.createSetFromSequenceDictionary(refReader.getSequenceDictionary());
+
+ logger.info(String.format("PROGRESS: Calculating mean and variance: Contig\tRegion.Start\tRegion.Stop\tSize"));
+
+ IntervalSharder sharder = IntervalSharder.shardOverIntervals(dataSource,intervalSortedSet,IntervalMergingRule.ALL);
+ while(sharder.hasNext()) {
+ FilePointer filePointer = sharder.next();
+
+ // Size of the file pointer.
+ final long size = filePointer.size();
+
+ BigInteger bigSize = BigInteger.valueOf(size);
+ sumOfSquares = sumOfSquares.add(bigSize.pow(2));
+ sum = sum.add(bigSize);
+ numberOfShards++;
+
+ if(numberOfShards % 1000 == 0) {
+ GenomeLoc boundingRegion = getBoundingRegion(filePointer,genomeLocParser);
+ logger.info(String.format("PROGRESS: Calculating mean and variance: %s\t%d\t%d\t%d",boundingRegion.getContig(),boundingRegion.getStart(),boundingRegion.getStop(),size));
+ }
+
+ }
+
+ // Print out the stddev: (sum(x^2) - (1/N)*sum(x)^2)/N
+ long mean = sum.divide(BigInteger.valueOf(numberOfShards)).longValue();
+ long stddev = (long)(Math.sqrt(sumOfSquares.subtract(sum.pow(2).divide(BigInteger.valueOf(numberOfShards))).divide(BigInteger.valueOf(numberOfShards)).doubleValue()));
+ logger.info(String.format("Number of shards: %d; mean uncompressed size = %d; stddev uncompressed size = %d%n",numberOfShards,mean,stddev));
+
+ // Crank through the shards again, this time reporting on the shards significantly larger than the mean.
+ long threshold = mean + stddev*5;
+ logger.warn(String.format("PROGRESS: Searching for large shards: Contig\tRegion.Start\tRegion.Stop\tSize"));
+ out.printf("Contig\tRegion.Start\tRegion.Stop\tSize%n");
+
+ sharder = IntervalSharder.shardOverIntervals(dataSource,intervalSortedSet,IntervalMergingRule.ALL);
+ while(sharder.hasNext()) {
+ FilePointer filePointer = sharder.next();
+
+ // Bounding region.
+ GenomeLoc boundingRegion = getBoundingRegion(filePointer,genomeLocParser);
+
+ // Size of the file pointer.
+ final long size = filePointer.size();
+
+ numberOfShards++;
+
+ if(filePointer.size() <= threshold) {
+ if(numberOfShards % 1000 == 0)
+ logger.info(String.format("PROGRESS: Searching for large shards: %s\t%d\t%d\t%d",boundingRegion.getContig(),boundingRegion.getStart(),boundingRegion.getStop(),size));
+ continue;
+ }
+
+ out.printf("%s\t%d\t%d\t%d%n",boundingRegion.getContig(),boundingRegion.getStart(),boundingRegion.getStop(),size);
+ }
+
+ return 0;
+ }
+
+ private GenomeLoc getBoundingRegion(final FilePointer filePointer, final GenomeLocParser genomeLocParser) {
+ List<GenomeLoc> regions = filePointer.getLocations();
+
+ // The region contained by this FilePointer.
+ final String contig = regions.get(0).getContig();
+ final int start = regions.get(0).getStart();
+ final int stop = regions.get(regions.size()-1).getStop();
+
+ return genomeLocParser.createGenomeLoc(contig,start,stop);
+ }
+
+ /**
+ * Required main method implementation.
+ * @param argv Command-line argument text.
+ * @throws Exception on error.
+ */
+ public static void main(String[] argv) throws Exception {
+ int returnCode = 0;
+ try {
+ FindLargeShards instance = new FindLargeShards();
+ start(instance, argv);
+ returnCode = 0;
+ }
+ catch(Exception ex) {
+ returnCode = 1;
+ ex.printStackTrace();
+ throw ex;
+ }
+ finally {
+ System.exit(returnCode);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/PrintBAMRegion.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/PrintBAMRegion.java
new file mode 100644
index 0000000..b0842e1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/PrintBAMRegion.java
@@ -0,0 +1,113 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads.utilities;
+
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mhanna
+ * Date: Feb 25, 2011
+ * Time: 3:25:13 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class PrintBAMRegion extends CommandLineProgram {
+ @Argument(fullName="input",shortName="I",doc="Input file to process",required=true)
+ private File input = null;
+
+ @Argument(fullName="region",shortName="R",doc="BAM region to process, in chunk format (mmmm:nn-xxxx:yy)",required=true)
+ private String region;
+
+ private static final long MIN_BLOCK_SIZE = 0;
+ private static final long MAX_BLOCK_SIZE = (long)Math.pow(2,48)-1;
+ private static final int MIN_OFFSET_SIZE = 0;
+ private static final int MAX_OFFSET_SIZE = (int)Math.pow(2,16)-1;
+
+ public int execute() {
+ SAMFileReader reader = new SAMFileReader(input);
+ reader.setValidationStringency(ValidationStringency.SILENT);
+
+ Pattern regionPattern = Pattern.compile("(\\d+):(\\d+)-(\\d+):(\\d+)");
+ Matcher matcher = regionPattern.matcher(region);
+ if(!matcher.matches())
+ throw new UserException("BAM region to process must be in chunk format (mmmm:nn-xxxx:yy)");
+
+ long firstBlock = Long.parseLong(matcher.group(1));
+ int firstOffset = Integer.parseInt(matcher.group(2));
+ long lastBlock = Long.parseLong(matcher.group(3));
+ int lastOffset = Integer.parseInt(matcher.group(4));
+
+ if(firstBlock < MIN_BLOCK_SIZE || firstBlock > MAX_BLOCK_SIZE)
+ throw new UserException(String.format("First block is invalid; must be between %d and %d; actually is %d",MIN_BLOCK_SIZE,MAX_BLOCK_SIZE,firstBlock));
+ if(lastBlock < MIN_BLOCK_SIZE || lastBlock > MAX_BLOCK_SIZE)
+ throw new UserException(String.format("Last block is invalid; must be between %d and %d; actually is %d",MIN_BLOCK_SIZE,MAX_BLOCK_SIZE,lastBlock));
+ if(firstOffset < MIN_OFFSET_SIZE || firstOffset > MAX_OFFSET_SIZE)
+ throw new UserException(String.format("First offset is invalid; must be between %d and %d; actually is %d",MIN_OFFSET_SIZE,MAX_OFFSET_SIZE,firstOffset));
+ if(lastOffset < MIN_OFFSET_SIZE || lastOffset > MAX_OFFSET_SIZE)
+ throw new UserException(String.format("Last offset is invalid; must be between %d and %d; actually is %d",MIN_OFFSET_SIZE,MAX_OFFSET_SIZE,lastOffset));
+
+ GATKChunk chunk = new GATKChunk(firstBlock<<16 | firstOffset,lastBlock<<16 | lastOffset);
+ GATKBAMFileSpan fileSpan = new GATKBAMFileSpan(chunk);
+
+ SAMRecordIterator iterator = reader.iterator(fileSpan);
+ long readCount = 0;
+ while(iterator.hasNext()) {
+ System.out.printf("%s%n",iterator.next().format());
+ readCount++;
+ }
+ System.out.printf("%d reads shown.",readCount);
+
+ iterator.close();
+ reader.close();
+
+ return 0;
+ }
+
+
+ /**
+ * Required main method implementation.
+ * @param argv Command-line argument text.
+ * @throws Exception on error.
+ */
+ public static void main(String[] argv) throws Exception {
+ try {
+ PrintBAMRegion instance = new PrintBAMRegion();
+ start(instance, argv);
+ System.exit(0);
+ }
+ catch(Exception ex) {
+ ex.printStackTrace();
+ System.exit(1);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/PrintBGZFBounds.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/PrintBGZFBounds.java
new file mode 100644
index 0000000..807e038
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/PrintBGZFBounds.java
@@ -0,0 +1,137 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads.utilities;
+
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Calculates the bounds of each BGZF block in a BAM index file, along with
+ */
+public class PrintBGZFBounds extends CommandLineProgram {
+ @Argument(fullName="input",shortName="I",doc="Input bai file to process",required=true)
+ private File input = null;
+
+ private final int BYTE_SIZE_IN_BYTES = Byte.SIZE / 8;
+ private final int INT_SIZE_IN_BYTES = Integer.SIZE / 8;
+ private final int SHORT_SIZE_IN_BYTES = INT_SIZE_IN_BYTES / 2;
+
+ /**
+ * ID1 + ID2 + CM + FLG + MTIME + XFL + OS + XLEN.
+ */
+ private final int HEADER_SIZE = BYTE_SIZE_IN_BYTES*4+INT_SIZE_IN_BYTES+BYTE_SIZE_IN_BYTES*2+SHORT_SIZE_IN_BYTES + BYTE_SIZE_IN_BYTES*2 + SHORT_SIZE_IN_BYTES*2;;
+
+ /**
+ * CRC32 + ISIZE
+ */
+ private final int FOOTER_SIZE = INT_SIZE_IN_BYTES*2;
+
+ @Override
+ public int execute() throws IOException {
+ FileInputStream fis = new FileInputStream(input);
+ ByteBuffer headerBuffer = allocateBuffer(HEADER_SIZE);
+ ByteBuffer footerBuffer = allocateBuffer(FOOTER_SIZE);
+
+ float compressedSize = 0;
+ float uncompressedSize = 0;
+ long totalBlocks = 0;
+
+ //SAMFileReader reader = new SAMFileReader(input);
+
+ while(true) {
+ final long blockStart = fis.getChannel().position();
+
+ int totalRead = fis.getChannel().read(headerBuffer);
+ if(totalRead <= 0)
+ break;
+ headerBuffer.flip();
+
+ // Read out header information, including subfield IDs.
+ headerBuffer.position(headerBuffer.capacity()-BYTE_SIZE_IN_BYTES*2);
+ final int cDataSize = headerBuffer.getShort()-HEADER_SIZE-FOOTER_SIZE+1;
+ compressedSize += cDataSize;
+
+ // Skip past body.
+ fis.getChannel().position(fis.getChannel().position()+cDataSize);
+
+ // Read the footer
+ fis.getChannel().read(footerBuffer);
+ footerBuffer.flip();
+
+ // Retrieve the uncompressed size from the footer.
+ footerBuffer.position(footerBuffer.capacity()-INT_SIZE_IN_BYTES);
+ uncompressedSize += footerBuffer.getInt();
+
+ // Reset buffers for subsequent reads.
+ headerBuffer.flip();
+ footerBuffer.flip();
+
+ totalBlocks++;
+
+ final long blockStop = fis.getChannel().position() - 1;
+
+ System.out.printf("BGZF block %d: [%d-%d]%n",totalBlocks,blockStart,blockStop);
+ }
+
+ System.out.printf("SUCCESS! Average compressed block size = %f, average uncompressed size = %f, compressed/uncompressed ratio: %f%n",compressedSize/totalBlocks,uncompressedSize/totalBlocks,compressedSize/uncompressedSize);
+
+ return 0;
+ }
+
+ private ByteBuffer allocateBuffer(final int size) {
+ ByteBuffer buffer = ByteBuffer.allocate(size);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+ return buffer;
+ }
+
+ /**
+ * Required main method implementation.
+ * @param argv Command-line argument text.
+ * @throws Exception on error.
+ */
+ public static void main(String[] argv) throws Exception {
+ int returnCode = 0;
+ try {
+ PrintBGZFBounds instance = new PrintBGZFBounds();
+ start(instance, argv);
+ returnCode = 0;
+ }
+ catch(Exception ex) {
+ returnCode = 1;
+ ex.printStackTrace();
+ throw ex;
+ }
+ finally {
+ System.exit(returnCode);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/UnzipSingleBlock.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/UnzipSingleBlock.java
new file mode 100644
index 0000000..d65b779
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/UnzipSingleBlock.java
@@ -0,0 +1,89 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads.utilities;
+
+import htsjdk.samtools.util.BlockGunzipper;
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+import org.broadinstitute.gatk.utils.commandline.Input;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Test decompression of a single BGZF block.
+ */
+public class UnzipSingleBlock extends CommandLineProgram {
+ @Input(fullName = "block_file", shortName = "b", doc = "block file over which to test unzipping", required = true)
+ private File blockFile;
+
+ @Input(fullName = "compressed_block_size", shortName = "cbs", doc = "size of compressed block", required = true)
+ private int compressedBufferSize;
+
+ public int execute() throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ byte[] compressedBuffer = new byte[(int)blockFile.length()];
+ byte[] uncompressedBuffer = new byte[65536];
+
+ FileInputStream fis = new FileInputStream(blockFile);
+ fis.read(compressedBuffer);
+ fis.close();
+
+ BlockGunzipper gunzipper = new BlockGunzipper();
+ gunzipper.setCheckCrcs(true);
+ Method unzipBlock = BlockGunzipper.class.getDeclaredMethod("unzipBlock",byte[].class,byte[].class,Integer.TYPE);
+ unzipBlock.setAccessible(true);
+
+ unzipBlock.invoke(gunzipper,uncompressedBuffer,compressedBuffer,compressedBufferSize);
+
+ System.out.printf("SUCCESS!%n");
+
+ return 0;
+ }
+
+ /**
+ * Required main method implementation.
+ * @param argv Command-line argument text.
+ * @throws Exception on error.
+ */
+ public static void main(String[] argv) throws Exception {
+ int returnCode = 0;
+ try {
+ UnzipSingleBlock instance = new UnzipSingleBlock();
+ start(instance, argv);
+ returnCode = 0;
+ }
+ catch(Exception ex) {
+ returnCode = 1;
+ ex.printStackTrace();
+ throw ex;
+ }
+ finally {
+ System.exit(returnCode);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/package-info.java
new file mode 100644
index 0000000..65a909a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reads/utilities/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads.utilities;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reference/ReferenceDataSource.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reference/ReferenceDataSource.java
new file mode 100644
index 0000000..6fdbea3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reference/ReferenceDataSource.java
@@ -0,0 +1,199 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reference;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.broadinstitute.gatk.engine.datasources.reads.LocusShard;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMDataSource;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Loads reference data from fasta file
+ * Looks for fai and dict files, and tries to create them if they don't exist
+ */
+public class ReferenceDataSource {
+ private IndexedFastaSequenceFile reference;
+
+ /** our log, which we want to capture anything from this class */
+ protected static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(ReferenceDataSource.class);
+
+ /**
+ * Create reference data source from fasta file
+ * @param fastaFile Fasta file to be used as reference
+ */
+ public ReferenceDataSource(File fastaFile) {
+ // does the fasta file exist? check that first...
+ if (!fastaFile.exists())
+ throw new UserException("The fasta file you specified (" + fastaFile.getAbsolutePath() + ") does not exist.");
+
+ final boolean isGzipped = fastaFile.getAbsolutePath().endsWith(".gz");
+ if ( isGzipped ) {
+ throw new UserException.CannotHandleGzippedRef();
+ }
+
+ final File indexFile = new File(fastaFile.getAbsolutePath() + ".fai");
+
+ // determine the name for the dict file
+ final String fastaExt = fastaFile.getAbsolutePath().endsWith("fa") ? "\\.fa$" : "\\.fasta$";
+ final File dictFile = new File(fastaFile.getAbsolutePath().replaceAll(fastaExt, ".dict"));
+
+ // It's an error if either the fai or dict file does not exist. The user is now responsible
+ // for creating these files.
+ if (!indexFile.exists()) {
+ throw new UserException.MissingReferenceFaiFile(indexFile, fastaFile);
+ }
+ if (!dictFile.exists()) {
+ throw new UserException.MissingReferenceDictFile(dictFile, fastaFile);
+ }
+
+ // Read reference data by creating an IndexedFastaSequenceFile.
+ try {
+ reference = new CachingIndexedFastaSequenceFile(fastaFile);
+ }
+ catch (IllegalArgumentException e) {
+ throw new UserException.CouldNotReadInputFile(fastaFile, "Could not read reference sequence. The FASTA must have either a .fasta or .fa extension", e);
+ }
+ catch (Exception e) {
+ throw new UserException.CouldNotReadInputFile(fastaFile, e);
+ }
+ }
+
+ /**
+ * Get indexed fasta file
+ * @return IndexedFastaSequenceFile that was created from file
+ */
+ public IndexedFastaSequenceFile getReference() {
+ return this.reference;
+ }
+
+ /**
+ * Creates an iterator for processing the entire reference.
+ * @param readsDataSource the reads datasource to embed in the locus shard.
+ * @param parser used to generate/regenerate intervals. TODO: decouple the creation of the shards themselves from the creation of the driving iterator so that datasources need not be passed to datasources.
+ * @param maxShardSize The maximum shard size which can be used to create this list.
+ * @return Creates a schedule for performing a traversal over the entire reference.
+ */
+ public Iterable<Shard> createShardsOverEntireReference(final SAMDataSource readsDataSource, final GenomeLocParser parser, final int maxShardSize) {
+ List<Shard> shards = new ArrayList<Shard>();
+ for(SAMSequenceRecord refSequenceRecord: reference.getSequenceDictionary().getSequences()) {
+ for(int shardStart = 1; shardStart <= refSequenceRecord.getSequenceLength(); shardStart += maxShardSize) {
+ final int shardStop = Math.min(shardStart+maxShardSize-1, refSequenceRecord.getSequenceLength());
+ shards.add(new LocusShard(parser,
+ readsDataSource,
+ Collections.singletonList(parser.createGenomeLoc(refSequenceRecord.getSequenceName(),shardStart,shardStop)),
+ null));
+ }
+ }
+ return shards;
+ }
+
+
+ public Iterable<Shard> createShardsOverIntervals(final SAMDataSource readsDataSource, final GenomeLocSortedSet intervals, final int maxShardSize) {
+ List<Shard> shards = new ArrayList<Shard>();
+
+ for(GenomeLoc interval: intervals) {
+ while(interval.size() > maxShardSize) {
+ shards.add(new LocusShard(intervals.getGenomeLocParser(),
+ readsDataSource,
+ Collections.singletonList(intervals.getGenomeLocParser().createGenomeLoc(interval.getContig(),interval.getStart(),interval.getStart()+maxShardSize-1)),
+ null));
+ interval = intervals.getGenomeLocParser().createGenomeLoc(interval.getContig(),interval.getStart()+maxShardSize,interval.getStop());
+ }
+ shards.add(new LocusShard(intervals.getGenomeLocParser(),
+ readsDataSource,
+ Collections.singletonList(interval),
+ null));
+ }
+
+ return shards;
+ }
+
+
+ /**
+ * Creates an iterator for processing the entire reference.
+ * @param readsDataSource the reads datasource to embed in the locus shard. TODO: decouple the creation of the shards themselves from the creation of the driving iterator so that datasources need not be passed to datasources.
+ * @param intervals the list of intervals to use when processing the reference.
+ * @param targetShardSize the suggested - and maximum - shard size which can be used to create this list; we will merge intervals greedily so that we generate shards up to but not greater than the target size.
+ * @return Creates a schedule for performing a traversal over the entire reference.
+ */
+/*
+ public Iterable<Shard> createShardsOverIntervals(final SAMDataSource readsDataSource, final GenomeLocSortedSet intervals, final int targetShardSize) {
+ final List<Shard> shards = new ArrayList<Shard>();
+ final GenomeLocParser parser = intervals.getGenomeLocParser();
+ LinkedList<GenomeLoc> currentIntervals = new LinkedList<GenomeLoc>();
+
+ for(GenomeLoc interval: intervals) {
+ // if the next interval is too big, we can safely shard currentInterval and then break down this one
+ if (interval.size() > targetShardSize) {
+ if (!currentIntervals.isEmpty())
+ shards.add(createShardFromInterval(currentIntervals, readsDataSource, parser));
+ while(interval.size() > targetShardSize) {
+ final GenomeLoc partialInterval = parser.createGenomeLoc(interval.getContig(), interval.getStart(), interval.getStart()+targetShardSize-1);
+ shards.add(createShardFromInterval(Collections.singletonList(partialInterval), readsDataSource, parser));
+ interval = parser.createGenomeLoc(interval.getContig(), interval.getStart() + targetShardSize, interval.getStop());
+ }
+ currentIntervals = new LinkedList<GenomeLoc>();
+ currentIntervals.add(interval);
+ }
+ // otherwise, we need to check whether we can merge this interval with currentInterval (and either shard currentInterval or merge accordingly)
+ else {
+ if (currentIntervals.isEmpty()) {
+ currentIntervals.add(interval);
+ }
+ else {
+ if (currentIntervals.getLast().compareContigs(interval) != 0 || interval.getStop() - currentIntervals.getLast().getStart() + 1 > targetShardSize) {
+ shards.add(createShardFromInterval(currentIntervals, readsDataSource, parser));
+ currentIntervals = new LinkedList<GenomeLoc>();
+ }
+ currentIntervals.add(interval);
+ }
+ }
+ }
+ if (!currentIntervals.isEmpty())
+ shards.add(createShardFromInterval(currentIntervals, readsDataSource, parser));
+ return shards;
+ }
+
+ private static Shard createShardFromInterval(final List<GenomeLoc> intervals, final SAMDataSource readsDataSource, final GenomeLocParser parser) {
+ //logger.debug("Adding shard " + interval);
+ return new LocusShard(parser,
+ readsDataSource,
+ intervals,
+ null);
+ }
+*/
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reference/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reference/package-info.java
new file mode 100644
index 0000000..581d213
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/reference/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reference;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/DataStreamSegment.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/DataStreamSegment.java
new file mode 100644
index 0000000..2543c42
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/DataStreamSegment.java
@@ -0,0 +1,32 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.rmd;
+
+/**
+ * Marker interface that represents an arbitrary consecutive segment within a data stream.
+ */
+interface DataStreamSegment {
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/EntireStream.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/EntireStream.java
new file mode 100644
index 0000000..eba5b53
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/EntireStream.java
@@ -0,0 +1,32 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.rmd;
+
+/**
+ * Models the entire stream of data.
+ */
+class EntireStream implements DataStreamSegment {
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/MappedStreamSegment.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/MappedStreamSegment.java
new file mode 100644
index 0000000..0344ff0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/MappedStreamSegment.java
@@ -0,0 +1,48 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.rmd;
+
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.HasGenomeLocation;
+
+/**
+ * Models a mapped position within a stream of GATK input data.
+ */
+class MappedStreamSegment implements DataStreamSegment, HasGenomeLocation {
+ public final GenomeLoc locus;
+
+ /**
+ * Retrieves the first location covered by a mapped stream segment.
+ * @return Location of the first base in this segment.
+ */
+ public GenomeLoc getLocation() {
+ return locus;
+ }
+
+ public MappedStreamSegment(GenomeLoc locus) {
+ this.locus = locus;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedDataPool.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedDataPool.java
new file mode 100644
index 0000000..762eb0b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedDataPool.java
@@ -0,0 +1,153 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.rmd;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import org.broadinstitute.gatk.engine.refdata.SeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrack;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrackBuilder;
+import org.broadinstitute.gatk.engine.refdata.utils.FlashBackIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.LocationAwareSeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.List;
+
+/**
+ * A pool of reference-ordered data iterators.
+ */
+class ReferenceOrderedDataPool extends ResourcePool<LocationAwareSeekableRODIterator, LocationAwareSeekableRODIterator> {
+ // the reference-ordered data itself.
+ private final RMDTriplet fileDescriptor;
+
+ // our tribble track builder
+ private final RMDTrackBuilder builder;
+
+ /**
+ * The header from this RMD, if present.
+ */
+ private final Object header;
+
+ /**
+ * The sequence dictionary from this ROD. If no sequence dictionary is present, this dictionary will be the same as the reference's.
+ */
+ private final SAMSequenceDictionary sequenceDictionary;
+
+ boolean flashbackData = false;
+ public ReferenceOrderedDataPool(RMDTriplet fileDescriptor,RMDTrackBuilder builder,SAMSequenceDictionary sequenceDictionary, GenomeLocParser genomeLocParser,boolean flashbackData) {
+ super(sequenceDictionary,genomeLocParser);
+ this.fileDescriptor = fileDescriptor;
+ this.builder = builder;
+ this.flashbackData = flashbackData;
+
+ // prepopulate one RMDTrack
+ LocationAwareSeekableRODIterator iterator = createNewResource();
+ this.addNewResource(iterator);
+
+ // Pull the proper header and sequence dictionary from the prepopulated track.
+ this.header = iterator.getHeader();
+ this.sequenceDictionary = iterator.getSequenceDictionary();
+ }
+
+ /**
+ * Gets the header used by this resource pool.
+ * @return Header used by this resource pool.
+ */
+ public Object getHeader() {
+ return header;
+ }
+
+ /**
+ * Gets the sequence dictionary built into the ROD index file.
+ * @return Sequence dictionary from the index file.
+ */
+ public SAMSequenceDictionary getSequenceDictionary() {
+ return sequenceDictionary;
+ }
+
+ /**
+ * Create a new iterator from the existing reference-ordered data. This new iterator is expected
+ * to be completely independent of any other iterator.
+ * @return The newly created resource.
+ */
+ public LocationAwareSeekableRODIterator createNewResource() {
+ if(numIterators() > 0)
+ throw new ReviewedGATKException("BUG: Tried to create multiple iterators over streaming ROD interface");
+ RMDTrack track = builder.createInstanceOfTrack(fileDescriptor);
+ LocationAwareSeekableRODIterator iter = new SeekableRODIterator(track.getHeader(),track.getSequenceDictionary(),referenceSequenceDictionary,genomeLocParser,track.getIterator());
+ return (flashbackData) ? new FlashBackIterator(iter) : iter;
+ }
+
+ /**
+ * Finds the best existing ROD iterator from the pool. In this case, the best existing ROD is defined as
+ * the first one encountered that is at or before the given position.
+ * @param segment @{inheritedDoc}
+ * @param resources @{inheritedDoc}
+ * @return @{inheritedDoc}
+ */
+ public LocationAwareSeekableRODIterator selectBestExistingResource( DataStreamSegment segment, List<LocationAwareSeekableRODIterator> resources ) {
+ if(segment instanceof MappedStreamSegment) {
+ GenomeLoc position = ((MappedStreamSegment)segment).getLocation();
+
+ for( LocationAwareSeekableRODIterator RODIterator : resources ) {
+
+ if( (RODIterator.position() == null && RODIterator.hasNext()) ||
+ (RODIterator.position() != null && RODIterator.position().isBefore(position)) )
+ return RODIterator;
+ if (RODIterator.position() != null && RODIterator instanceof FlashBackIterator && ((FlashBackIterator)RODIterator).canFlashBackTo(position)) {
+ ((FlashBackIterator)RODIterator).flashBackTo(position);
+ return RODIterator;
+ }
+
+ }
+ return null;
+ }
+ else if(segment instanceof EntireStream) {
+ // Asking for a segment over the entire stream, so by definition, there is no best existing resource.
+ // Force the system to create a new one.
+ return null;
+ }
+ else {
+ throw new ReviewedGATKException("Unable to find a ROD iterator for segments of type " + segment.getClass());
+ }
+ }
+
+ /**
+ * In this case, the iterator is the resource. Pass it through.
+ */
+ public LocationAwareSeekableRODIterator createIteratorFromResource( DataStreamSegment segment, LocationAwareSeekableRODIterator resource ) {
+ return resource;
+ }
+
+ /**
+ * kill the buffers in the iterator
+ */
+ public void closeResource( LocationAwareSeekableRODIterator resource ) {
+ if (resource instanceof FlashBackIterator) ((FlashBackIterator)resource).close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedDataSource.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedDataSource.java
new file mode 100644
index 0000000..9d9e7c8
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedDataSource.java
@@ -0,0 +1,256 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.rmd;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.refdata.SeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrack;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrackBuilder;
+import org.broadinstitute.gatk.engine.refdata.utils.LocationAwareSeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.List;
+
+/**
+ * A data source which provides a single type of reference-ordered data.
+ */
+public class ReferenceOrderedDataSource {
+ /**
+ * The reference-ordered data itself.
+ */
+ private final RMDTriplet fileDescriptor;
+
+ /**
+ * The header associated with this VCF, if any.
+ */
+ private final Object header;
+
+ /**
+ * The private sequence dictionary associated with this RMD.
+ */
+ private final SAMSequenceDictionary sequenceDictionary;
+
+ /**
+ * The builder to use when constructing new reference-ordered data readers.
+ */
+ private final RMDTrackBuilder builder;
+
+ /**
+ * A pool of iterators for navigating through the genome.
+ */
+ private final ResourcePool<?,LocationAwareSeekableRODIterator> iteratorPool;
+
+ /**
+ * Create a new reference-ordered data source.
+ */
+ public ReferenceOrderedDataSource(RMDTriplet fileDescriptor,
+ RMDTrackBuilder builder,
+ SAMSequenceDictionary referenceSequenceDictionary,
+ GenomeLocParser genomeLocParser,
+ boolean flashbackData ) {
+ this.fileDescriptor = fileDescriptor;
+ this.builder = builder;
+
+ // TODO: Unify the two blocks of code below by creating a ReferenceOrderedDataPool base class of a coherent type (not RMDTrack for one and SeekableIterator for the other).
+ if (fileDescriptor.getStorageType() != RMDTriplet.RMDStorageType.STREAM) {
+ iteratorPool = new ReferenceOrderedQueryDataPool(fileDescriptor,
+ builder,
+ referenceSequenceDictionary,
+ genomeLocParser);
+ this.header = ((ReferenceOrderedQueryDataPool)iteratorPool).getHeader();
+ this.sequenceDictionary = ((ReferenceOrderedQueryDataPool)iteratorPool).getSequenceDictionary();
+ }
+ else {
+ iteratorPool = new ReferenceOrderedDataPool(fileDescriptor,
+ builder,
+ referenceSequenceDictionary,
+ genomeLocParser,
+ flashbackData);
+ this.header = ((ReferenceOrderedDataPool)iteratorPool).getHeader();
+ this.sequenceDictionary = ((ReferenceOrderedDataPool)iteratorPool).getSequenceDictionary();
+ }
+ }
+
+ /**
+ * Return the name of the underlying reference-ordered data.
+ * @return Name of the underlying rod.
+ */
+ public String getName() {
+ return fileDescriptor.getName();
+ }
+
+ public Class getType() {
+ return builder.getFeatureManager().getByTriplet(fileDescriptor).getCodecClass();
+ }
+
+ public Class getRecordType() {
+ return builder.getFeatureManager().getByTriplet(fileDescriptor).getFeatureClass();
+ }
+
+ public File getFile() {
+ return new File(fileDescriptor.getFile());
+ }
+
+ public Object getHeader() {
+ return header;
+ }
+
+ public Tags getTags() {
+ return fileDescriptor.getTags();
+ }
+
+ public String getTagValue( final String key ) {
+ return fileDescriptor.getTags().getValue( key );
+ }
+
+
+ /**
+ * Retrieves the sequence dictionary created by this ROD.
+ * @return
+ */
+ public SAMSequenceDictionary getSequenceDictionary() {
+ return sequenceDictionary;
+ }
+
+ /**
+ * helper function for determining if we are the same track based on name and record type
+ *
+ * @param name the name to match
+ * @param type the type to match
+ *
+ * @return true on a match, false if the name or type is different
+ */
+ public boolean matchesNameAndRecordType(String name, Type type) {
+ return (name.equals(fileDescriptor.getName()) && (type.getClass().isAssignableFrom(getType().getClass())));
+ }
+
+ /**
+ * Seek to the specified position and return an iterator through the data.
+ *
+ * @param loc GenomeLoc that points to the selected position.
+ *
+ * @return Iterator through the data.
+ */
+ public LocationAwareSeekableRODIterator seek(GenomeLoc loc) {
+ DataStreamSegment dataStreamSegment = loc != null ? new MappedStreamSegment(loc) : new EntireStream();
+ return iteratorPool.iterator(dataStreamSegment);
+ }
+
+
+ /**
+ * Close the specified iterator, returning it to the pool.
+ * @param iterator Iterator to close.
+ */
+ public void close( LocationAwareSeekableRODIterator iterator ) {
+ iteratorPool.release(iterator);
+ }
+
+}
+
+/**
+ * a data pool for the new query based RODs
+ */
+class ReferenceOrderedQueryDataPool extends ResourcePool<RMDTrack,LocationAwareSeekableRODIterator> {
+ // the reference-ordered data itself.
+ private final RMDTriplet fileDescriptor;
+
+ // our tribble track builder
+ private final RMDTrackBuilder builder;
+
+ /**
+ * The header from this RMD, if present.
+ */
+ private final Object header;
+
+ /**
+ * The sequence dictionary from this ROD. If no sequence dictionary is present, this dictionary will be the same as the reference's.
+ */
+ private final SAMSequenceDictionary sequenceDictionary;
+
+ public ReferenceOrderedQueryDataPool(RMDTriplet fileDescriptor, RMDTrackBuilder builder, SAMSequenceDictionary referenceSequenceDictionary, GenomeLocParser genomeLocParser) {
+ super(referenceSequenceDictionary,genomeLocParser);
+ this.fileDescriptor = fileDescriptor;
+ this.builder = builder;
+
+ // prepopulate one RMDTrack
+ RMDTrack track = builder.createInstanceOfTrack(fileDescriptor);
+ this.addNewResource(track);
+
+ // Pull the proper header and sequence dictionary from the prepopulated track.
+ this.header = track.getHeader();
+ this.sequenceDictionary = track.getSequenceDictionary();
+ }
+
+ public Object getHeader() {
+ return header;
+ }
+
+ public SAMSequenceDictionary getSequenceDictionary() {
+ return sequenceDictionary;
+ }
+
+ @Override
+ protected RMDTrack createNewResource() {
+ return builder.createInstanceOfTrack(fileDescriptor);
+ }
+
+ @Override
+ protected RMDTrack selectBestExistingResource(DataStreamSegment segment, List<RMDTrack> availableResources) {
+ for (RMDTrack reader : availableResources)
+ if (reader != null) return reader;
+ return null;
+ }
+
+ @Override
+ protected LocationAwareSeekableRODIterator createIteratorFromResource(DataStreamSegment position, RMDTrack track) {
+ try {
+ if (position instanceof MappedStreamSegment) {
+ GenomeLoc pos = ((MappedStreamSegment) position).locus;
+ return new SeekableRODIterator(header,sequenceDictionary,referenceSequenceDictionary,genomeLocParser,track.query(pos));
+ } else {
+ return new SeekableRODIterator(header,sequenceDictionary,referenceSequenceDictionary,genomeLocParser,track.getIterator());
+ }
+ } catch (FileNotFoundException e) {
+ throw new UserException.CouldNotReadInputFile(fileDescriptor.getName(), "it could not be found");
+ } catch (IOException e) {
+ throw new ReviewedGATKException("Unable to create iterator for rod named " + fileDescriptor.getName(),e);
+ }
+ }
+
+ @Override
+ protected void closeResource(RMDTrack track) {
+ track.close();
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/ResourcePool.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/ResourcePool.java
new file mode 100644
index 0000000..7d6e9c0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/ResourcePool.java
@@ -0,0 +1,188 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.rmd;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.util.CloseableIterator;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ * A pool of open resources, all of which can create a closeable iterator.
+ */
+abstract class ResourcePool <T,I extends CloseableIterator> {
+ /**
+ * Sequence dictionary.
+ */
+ protected final SAMSequenceDictionary referenceSequenceDictionary;
+
+ /**
+ * Builder/parser for GenomeLocs.
+ */
+ protected final GenomeLocParser genomeLocParser;
+
+ /**
+ * All iterators of this reference-ordered data.
+ */
+ private List<T> allResources = new ArrayList<T>();
+
+ /**
+ * All iterators that are not currently in service.
+ */
+ private List<T> availableResources = new ArrayList<T>();
+
+ /**
+ * Which iterators are assigned to which pools.
+ */
+ private Map<I,T> resourceAssignments = new HashMap<I,T>();
+
+ protected ResourcePool(SAMSequenceDictionary referenceSequenceDictionary,GenomeLocParser genomeLocParser) {
+ this.referenceSequenceDictionary = referenceSequenceDictionary;
+ this.genomeLocParser = genomeLocParser;
+ }
+
+ /**
+ * Get an iterator whose position is before the specified location. Create a new one if none exists.
+ * @param segment Target position for the iterator.
+ * @return An iterator that can traverse the selected region. Should be able to iterate concurrently with other
+ * iterators from tihs pool.
+ */
+ public I iterator( DataStreamSegment segment ) {
+ // Grab the first iterator in the list whose position is before the requested position.
+ T selectedResource = null;
+ synchronized (this) {
+ selectedResource = selectBestExistingResource(segment, availableResources);
+
+ // No iterator found? Create another. It is expected that
+ // each iterator created will have its own file handle.
+ if (selectedResource == null) {
+ selectedResource = createNewResource();
+ addNewResource(selectedResource);
+ }
+
+ // Remove the iterator from the list of available iterators.
+ availableResources.remove(selectedResource);
+ }
+
+
+ I iterator = createIteratorFromResource(segment, selectedResource);
+
+ // also protect the resource assignment
+ synchronized (this) {
+ // Make a note of this assignment for proper releasing later.
+ resourceAssignments.put(iterator, selectedResource);
+ }
+
+ return iterator;
+ }
+
+ /**
+ * Release the lock on the given iterator, returning it to the pool.
+ * @param iterator Iterator to return to the pool.
+ */
+ public void release( I iterator ) {
+ synchronized(this) {
+ // Find and remove the resource from the list of allocated resources.
+ T resource = resourceAssignments.get( iterator );
+ Object obj = resourceAssignments.remove(iterator);
+
+ // Close the iterator.
+ iterator.close();
+
+ // make sure we actually removed the assignment
+ if (obj == null)
+ throw new ReviewedGATKException("Failed to remove resource assignment; target key had no associated value in the resource assignment map");
+ // Return the resource to the pool.
+ if( !allResources.contains(resource) )
+ throw new ReviewedGATKException("Iterator does not belong to the given pool.");
+ availableResources.add(resource);
+ }
+ }
+
+ /**
+ * Add a resource to the list of available resources. Useful if derived classes
+ * want to seed the pool with a set of at a given time (like at initialization).
+ * @param resource The new resource to add.
+ */
+ protected void addNewResource( T resource ) {
+ synchronized(this) {
+ allResources.add(resource);
+ availableResources.add(resource);
+ }
+ }
+
+ /**
+ * If no appropriate resources are found in the pool, the system can create a new resource.
+ * Delegate the creation of the resource to the subclass.
+ * @return The new resource created.
+ */
+ protected abstract T createNewResource();
+
+ /**
+ * Find the most appropriate resource to acquire the specified data.
+ * @param segment The data over which the resource is required.
+ * @param availableResources A list of candidate resources to evaluate.
+ * @return The best choice of the availableResources, or null if no resource meets the criteria.
+ */
+ protected abstract T selectBestExistingResource( DataStreamSegment segment, List<T> availableResources );
+
+ /**
+ * Create an iterator over the specified resource.
+ * @param position The bounds of iteration. The first element of the iterator through the last element should all
+ * be in the range described by position.
+ * @param resource The resource from which to derive the iterator.
+ * @return A new iterator over the given data.
+ */
+ protected abstract I createIteratorFromResource( DataStreamSegment position, T resource );
+
+ /**
+ * Retire this resource from service.
+ * @param resource The resource to retire.
+ */
+ protected abstract void closeResource(T resource);
+
+ /**
+ * Operating stats...get the number of total iterators. Package-protected
+ * for unit testing.
+ * @return An integer number of total iterators.
+ */
+ int numIterators() {
+ return allResources.size();
+ }
+
+ /**
+ * Operating stats...get the number of available iterators. Package-protected
+ * for unit testing.
+ * @return An integer number of available iterators.
+ */
+ int numAvailableIterators() {
+ return availableResources.size();
+ }
+
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/package-info.java
new file mode 100644
index 0000000..41b7e53
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/datasources/rmd/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.rmd;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/AlleleBiasedDownsamplingUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/AlleleBiasedDownsamplingUtils.java
new file mode 100644
index 0000000..0bcf4ee
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/AlleleBiasedDownsamplingUtils.java
@@ -0,0 +1,369 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.collections.DefaultHashMap;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileupImpl;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+import htsjdk.variant.variantcontext.Allele;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+public class AlleleBiasedDownsamplingUtils {
+
+ // define this class so that we can use Java generics below
+ private final static class PileupElementList extends ArrayList<PileupElement> {}
+
+ /**
+ * Computes an allele biased version of the given pileup
+ *
+ * @param pileup the original pileup
+ * @param downsamplingFraction the fraction of total reads to remove per allele
+ * @return allele biased pileup
+ */
+ public static ReadBackedPileup createAlleleBiasedBasePileup(final ReadBackedPileup pileup, final double downsamplingFraction) {
+ // special case removal of all or no reads
+ if ( downsamplingFraction <= 0.0 )
+ return pileup;
+ if ( downsamplingFraction >= 1.0 )
+ return new ReadBackedPileupImpl(pileup.getLocation(), new ArrayList<PileupElement>());
+
+ final PileupElementList[] alleleStratifiedElements = new PileupElementList[4];
+ for ( int i = 0; i < 4; i++ )
+ alleleStratifiedElements[i] = new PileupElementList();
+
+ // start by stratifying the reads by the alleles they represent at this position
+ for ( final PileupElement pe : pileup ) {
+ final int baseIndex = BaseUtils.simpleBaseToBaseIndex(pe.getBase());
+ if ( baseIndex != -1 )
+ alleleStratifiedElements[baseIndex].add(pe);
+ }
+
+ // make a listing of allele counts and calculate the total count
+ final int[] alleleCounts = calculateAlleleCounts(alleleStratifiedElements);
+ final int totalAlleleCount = (int)MathUtils.sum(alleleCounts);
+
+ // do smart down-sampling
+ final int numReadsToRemove = (int)(totalAlleleCount * downsamplingFraction); // floor
+ final int[] targetAlleleCounts = runSmartDownsampling(alleleCounts, numReadsToRemove);
+
+ final HashSet<PileupElement> readsToRemove = new HashSet<PileupElement>(numReadsToRemove);
+ for ( int i = 0; i < 4; i++ ) {
+ final PileupElementList alleleList = alleleStratifiedElements[i];
+ // if we don't need to remove any reads, then don't
+ if ( alleleCounts[i] > targetAlleleCounts[i] )
+ readsToRemove.addAll(downsampleElements(alleleList, alleleCounts[i], alleleCounts[i] - targetAlleleCounts[i]));
+ }
+
+ // we need to keep the reads sorted because the FragmentUtils code will expect them in coordinate order and will fail otherwise
+ final List<PileupElement> readsToKeep = new ArrayList<PileupElement>(totalAlleleCount - numReadsToRemove);
+ for ( final PileupElement pe : pileup ) {
+ if ( !readsToRemove.contains(pe) ) {
+ readsToKeep.add(pe);
+ }
+ }
+
+ return new ReadBackedPileupImpl(pileup.getLocation(), new ArrayList<PileupElement>(readsToKeep));
+ }
+
+ /**
+ * Calculates actual allele counts for each allele (which can be different than the list size when reduced reads are present)
+ *
+ * @param alleleStratifiedElements pileup elements stratified by allele
+ * @return non-null int array representing allele counts
+ */
+ private static int[] calculateAlleleCounts(final PileupElementList[] alleleStratifiedElements) {
+ final int[] alleleCounts = new int[alleleStratifiedElements.length];
+ for ( int i = 0; i < alleleStratifiedElements.length; i++ ) {
+ alleleCounts[i] = alleleStratifiedElements[i].size();
+ }
+ return alleleCounts;
+ }
+
+ private static int scoreAlleleCounts(final int[] alleleCounts) {
+ if ( alleleCounts.length < 2 )
+ return 0;
+
+ // sort the counts (in ascending order)
+ final int[] alleleCountsCopy = alleleCounts.clone();
+ Arrays.sort(alleleCountsCopy);
+
+ final int maxCount = alleleCountsCopy[alleleCounts.length - 1];
+ final int nextBestCount = alleleCountsCopy[alleleCounts.length - 2];
+
+ int remainderCount = 0;
+ for ( int i = 0; i < alleleCounts.length - 2; i++ )
+ remainderCount += alleleCountsCopy[i];
+
+ // try to get the best score:
+ // - in the het case the counts should be equal with nothing else
+ // - in the hom case the non-max should be zero
+ return Math.min(maxCount - nextBestCount + remainderCount, Math.abs(nextBestCount + remainderCount));
+ }
+
+ /**
+ * Computes an allele biased version of the allele counts for a given pileup
+ *
+ * @param alleleCounts the allele counts for the original pileup
+ * @param numReadsToRemove number of total reads to remove per allele
+ * @return non-null array of new counts needed per allele
+ */
+ protected static int[] runSmartDownsampling(final int[] alleleCounts, final int numReadsToRemove) {
+ final int numAlleles = alleleCounts.length;
+
+ int maxScore = scoreAlleleCounts(alleleCounts);
+ int[] alleleCountsOfMax = alleleCounts;
+
+ final int numReadsToRemovePerAllele = numReadsToRemove / 2;
+
+ for ( int i = 0; i < numAlleles; i++ ) {
+ for ( int j = i; j < numAlleles; j++ ) {
+ final int[] newCounts = alleleCounts.clone();
+
+ // split these cases so we don't lose on the floor (since we divided by 2)
+ if ( i == j ) {
+ newCounts[i] = Math.max(0, newCounts[i] - numReadsToRemove);
+ } else {
+ newCounts[i] = Math.max(0, newCounts[i] - numReadsToRemovePerAllele);
+ newCounts[j] = Math.max(0, newCounts[j] - numReadsToRemovePerAllele);
+ }
+
+ final int score = scoreAlleleCounts(newCounts);
+
+ if ( score < maxScore ) {
+ maxScore = score;
+ alleleCountsOfMax = newCounts;
+ }
+ }
+ }
+
+ return alleleCountsOfMax;
+ }
+
+ /**
+ * Performs allele biased down-sampling on a pileup and computes the list of elements to remove
+ *
+ * @param elements original list of pileup elements
+ * @param originalElementCount original count of elements (taking reduced reads into account)
+ * @param numElementsToRemove the number of records to remove
+ * @return the list of pileup elements TO REMOVE
+ */
+ protected static List<PileupElement> downsampleElements(final List<PileupElement> elements, final int originalElementCount, final int numElementsToRemove) {
+ // are there no elements to remove?
+ if ( numElementsToRemove == 0 )
+ return Collections.<PileupElement>emptyList();
+
+ final ArrayList<PileupElement> elementsToRemove = new ArrayList<PileupElement>(numElementsToRemove);
+
+ // should we remove all of the elements?
+ if ( numElementsToRemove >= originalElementCount ) {
+ elementsToRemove.addAll(elements);
+ return elementsToRemove;
+ }
+
+ // create a bitset describing which elements to remove
+ final BitSet itemsToRemove = new BitSet(originalElementCount);
+ for ( final Integer selectedIndex : MathUtils.sampleIndicesWithoutReplacement(originalElementCount, numElementsToRemove) ) {
+ itemsToRemove.set(selectedIndex);
+ }
+
+ int currentBitSetIndex = 0;
+ for ( final PileupElement element : elements ) {
+ if ( itemsToRemove.get(currentBitSetIndex++) ) {
+ elementsToRemove.add(element);
+ }
+ }
+
+ return elementsToRemove;
+ }
+
+ /**
+ * Computes reads to remove based on an allele biased down-sampling
+ *
+ * @param alleleReadMap original list of records per allele
+ * @param downsamplingFraction the fraction of total reads to remove per allele
+ * @return list of reads TO REMOVE from allele biased down-sampling
+ */
+ public static <A extends Allele> List<GATKSAMRecord> selectAlleleBiasedReads(final Map<A, List<GATKSAMRecord>> alleleReadMap, final double downsamplingFraction) {
+ int totalReads = 0;
+ for ( final List<GATKSAMRecord> reads : alleleReadMap.values() )
+ totalReads += reads.size();
+
+ int numReadsToRemove = (int)(totalReads * downsamplingFraction);
+
+ // make a listing of allele counts
+ final List<Allele> alleles = new ArrayList<Allele>(alleleReadMap.keySet());
+ alleles.remove(Allele.NO_CALL); // ignore the no-call bin
+ final int numAlleles = alleles.size();
+
+ final int[] alleleCounts = new int[numAlleles];
+ for ( int i = 0; i < numAlleles; i++ )
+ alleleCounts[i] = alleleReadMap.get(alleles.get(i)).size();
+
+ // do smart down-sampling
+ final int[] targetAlleleCounts = runSmartDownsampling(alleleCounts, numReadsToRemove);
+
+ final List<GATKSAMRecord> readsToRemove = new ArrayList<GATKSAMRecord>(numReadsToRemove);
+ for ( int i = 0; i < numAlleles; i++ ) {
+ if ( alleleCounts[i] > targetAlleleCounts[i] ) {
+ readsToRemove.addAll(downsampleElements(alleleReadMap.get(alleles.get(i)), alleleCounts[i] - targetAlleleCounts[i]));
+ }
+ }
+
+ return readsToRemove;
+ }
+
+ /**
+ * Performs allele biased down-sampling on a pileup and computes the list of elements to remove
+ *
+ * @param reads original list of records
+ * @param numElementsToRemove the number of records to remove
+ * @return the list of pileup elements TO REMOVE
+ */
+ protected static List<GATKSAMRecord> downsampleElements(final List<GATKSAMRecord> reads, final int numElementsToRemove) {
+ // are there no elements to remove?
+ if ( numElementsToRemove == 0 )
+ return Collections.<GATKSAMRecord>emptyList();
+
+ final ArrayList<GATKSAMRecord> elementsToRemove = new ArrayList<GATKSAMRecord>(numElementsToRemove);
+ final int originalElementCount = reads.size();
+
+ // should we remove all of the elements?
+ if ( numElementsToRemove >= originalElementCount ) {
+ elementsToRemove.addAll(reads);
+ return elementsToRemove;
+ }
+
+ // create a bitset describing which elements to remove
+ final BitSet itemsToRemove = new BitSet(originalElementCount);
+ for ( final Integer selectedIndex : MathUtils.sampleIndicesWithoutReplacement(originalElementCount, numElementsToRemove) ) {
+ itemsToRemove.set(selectedIndex);
+ }
+
+ int currentBitSetIndex = 0;
+ for ( final GATKSAMRecord read : reads ) {
+ if ( itemsToRemove.get(currentBitSetIndex++) )
+ elementsToRemove.add(read);
+ }
+
+ return elementsToRemove;
+ }
+
+ /**
+ * Create sample-contamination maps from file
+ *
+ * @param ContaminationFractionFile Filename containing two columns: SampleID and Contamination
+ * @param AvailableSampleIDs Set of Samples of interest (no reason to include every sample in file) or null to turn off checking
+ * @param logger for logging output
+ * @return sample-contamination Map
+ */
+
+ public static DefaultHashMap<String, Double> loadContaminationFile(File ContaminationFractionFile, final Double defaultContaminationFraction, final Set<String> AvailableSampleIDs, Logger logger) throws GATKException {
+ DefaultHashMap<String, Double> sampleContamination = new DefaultHashMap<String, Double>(defaultContaminationFraction);
+ Set<String> nonSamplesInContaminationFile = new HashSet<String>(sampleContamination.keySet());
+ try {
+
+ XReadLines reader = new XReadLines(ContaminationFractionFile, true);
+ for (String line : reader) {
+
+ if (line.length() == 0) {
+ continue;
+ }
+
+ StringTokenizer st = new StringTokenizer(line,"\t");
+
+ String fields[] = new String[2];
+ try {
+ fields[0] = st.nextToken();
+ fields[1] = st.nextToken();
+ } catch(NoSuchElementException e){
+ throw new UserException.MalformedFile("Contamination file must have exactly two, tab-delimited columns. Offending line:\n" + line);
+ }
+ if(st.hasMoreTokens()) {
+ throw new UserException.MalformedFile("Contamination file must have exactly two, tab-delimited columns. Offending line:\n" + line);
+ }
+
+ if (fields[0].length() == 0 || fields[1].length() == 0) {
+ throw new UserException.MalformedFile("Contamination file can not have empty strings in either column. Offending line:\n" + line);
+ }
+
+ if (sampleContamination.containsKey(fields[0])) {
+ throw new UserException.MalformedFile("Contamination file contains duplicate entries for input name " + fields[0]);
+ }
+
+ try {
+ final Double contamination = Double.valueOf(fields[1]);
+ if (contamination < 0 || contamination > 1){
+ throw new UserException.MalformedFile("Contamination file contains unacceptable contamination value (must be 0<=x<=1): " + line);
+ }
+ if (AvailableSampleIDs==null || AvailableSampleIDs.contains(fields[0])) {// only add samples if they are in the sampleSet (or if it is null)
+ sampleContamination.put(fields[0], contamination);
+ }
+ else {
+ nonSamplesInContaminationFile.add(fields[0]);
+ }
+ } catch (NumberFormatException e) {
+ throw new UserException.MalformedFile("Contamination file contains unparsable double in the second field. Offending line: " + line);
+ }
+ }
+
+
+ //output to the user info lines telling which samples are in the Contamination File
+ if (sampleContamination.size() > 0) {
+ logger.info(String.format("The following samples were found in the Contamination file and will be processed at the contamination level therein: %s", sampleContamination.keySet().toString()));
+
+ //output to the user info lines telling which samples are NOT in the Contamination File
+ if(AvailableSampleIDs!=null){
+ Set<String> samplesNotInContaminationFile = new HashSet<String>(AvailableSampleIDs);
+ samplesNotInContaminationFile.removeAll(sampleContamination.keySet());
+ if (samplesNotInContaminationFile.size() > 0)
+ logger.info(String.format("The following samples were NOT found in the Contamination file and will be processed at the default contamination level: %s", samplesNotInContaminationFile.toString()));
+ }
+ }
+
+ //output to the user Samples that do not have lines in the Contamination File
+ if (nonSamplesInContaminationFile.size() > 0) {
+ logger.info(String.format("The following entries were found in the Contamination file but were not SAMPLEIDs. They will be ignored: %s", nonSamplesInContaminationFile.toString()));
+ }
+
+ return sampleContamination;
+
+ } catch (IOException e) {
+ throw new GATKException("I/O Error while reading sample-contamination file " + ContaminationFractionFile.getName() + ": " + e.getMessage());
+ }
+
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsampleType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsampleType.java
new file mode 100644
index 0000000..715ef6e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsampleType.java
@@ -0,0 +1,39 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+/**
+ * Type of downsampling method to invoke.
+ *
+ * @author hanna
+ * @version 0.1
+ */
+
+public enum DownsampleType {
+ NONE,
+ ALL_READS,
+ BY_SAMPLE
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/Downsampler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/Downsampler.java
new file mode 100644
index 0000000..8ab0198
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/Downsampler.java
@@ -0,0 +1,161 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * The basic downsampler API, with no reads-specific operations.
+ *
+ * Downsamplers that extend this class rather than the ReadsDownsampler class can handle
+ * any kind of item, however they cannot be wrapped within a DownsamplingReadsIterator or a
+ * PerSampleDownsamplingReadsIterator.
+ *
+ * @author David Roazen
+ */
+public abstract class Downsampler<T> {
+
+ /**
+ * Number of items discarded by this downsampler since the last call to resetStats()
+ */
+ protected int numDiscardedItems = 0;
+
+ /**
+ * Submit one item to the downsampler for consideration. Some downsamplers will be able to determine
+ * immediately whether the item survives the downsampling process, while others will need to see
+ * more items before making that determination.
+ *
+ * @param item the individual item to submit to the downsampler for consideration
+ */
+ public abstract void submit( final T item );
+
+ /**
+ * Submit a collection of items to the downsampler for consideration. Should be equivalent to calling
+ * submit() on each individual item in the collection.
+ *
+ * @param items the collection of items to submit to the downsampler for consideration
+ */
+ public void submit( final Collection<T> items ) {
+ if ( items == null ) {
+ throw new IllegalArgumentException("submitted items must not be null");
+ }
+
+ for ( final T item : items ) {
+ submit(item);
+ }
+ }
+
+ /**
+ * Are there items that have survived the downsampling process waiting to be retrieved?
+ *
+ * @return true if this downsampler has > 0 finalized items, otherwise false
+ */
+ public abstract boolean hasFinalizedItems();
+
+ /**
+ * Return (and *remove*) all items that have survived downsampling and are waiting to be retrieved.
+ *
+ * @return a list of all finalized items this downsampler contains, or an empty list if there are none
+ */
+ public abstract List<T> consumeFinalizedItems();
+
+ /**
+ * Are there items stored in this downsampler that it doesn't yet know whether they will
+ * ultimately survive the downsampling process?
+ *
+ * @return true if this downsampler has > 0 pending items, otherwise false
+ */
+ public abstract boolean hasPendingItems();
+
+ /**
+ * Peek at the first finalized item stored in this downsampler (or null if there are no finalized items)
+ *
+ * @return the first finalized item in this downsampler (the item is not removed from the downsampler by this call),
+ * or null if there are none
+ */
+ public abstract T peekFinalized();
+
+ /**
+ * Peek at the first pending item stored in this downsampler (or null if there are no pending items)
+ *
+ * @return the first pending item stored in this downsampler (the item is not removed from the downsampler by this call),
+ * or null if there are none
+ */
+ public abstract T peekPending();
+
+ /**
+ * Get the current number of items in this downsampler
+ *
+ * This should be the best estimate of the total number of elements that will come out of the downsampler
+ * were consumeFinalizedItems() to be called immediately after this call. In other words it should
+ * be number of finalized items + estimate of number of pending items that will ultimately be included as well.
+ *
+ * @return a positive integer
+ */
+ public abstract int size();
+
+ /**
+ * Returns the number of items discarded (so far) during the downsampling process
+ *
+ * @return the number of items that have been submitted to this downsampler and discarded in the process of
+ * downsampling
+ */
+ public int getNumberOfDiscardedItems() {
+ return numDiscardedItems;
+ }
+
+ /**
+ * Used to tell the downsampler that no more items will be submitted to it, and that it should
+ * finalize any pending items.
+ */
+ public abstract void signalEndOfInput();
+
+ /**
+ * Empty the downsampler of all finalized/pending items
+ */
+ public abstract void clearItems();
+
+ /**
+ * Reset stats in the downsampler such as the number of discarded items *without* clearing the downsampler of items
+ */
+ public void resetStats() {
+ numDiscardedItems = 0;
+ }
+
+ /**
+ * Indicates whether an item should be excluded from elimination during downsampling. By default,
+ * all items representing reduced reads are excluded from downsampling, but individual downsamplers
+ * may override if they are able to handle reduced reads correctly. Downsamplers should check
+ * the return value of this method before discarding an item.
+ *
+ * @param item The item to test
+ * @return true if the item should not be subject to elimination during downsampling, otherwise false
+ */
+ protected boolean doNotDiscardItem( final Object item ) {
+ return false;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingMethod.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingMethod.java
new file mode 100644
index 0000000..94a3cc7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingMethod.java
@@ -0,0 +1,142 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import org.broadinstitute.gatk.engine.walkers.ActiveRegionWalker;
+import org.broadinstitute.gatk.engine.walkers.LocusWalker;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+/**
+ * Describes the method for downsampling reads at a given locus.
+ */
+
+public class DownsamplingMethod {
+ /**
+ * Type of downsampling to perform.
+ */
+ public final DownsampleType type;
+
+ /**
+ * Actual downsampling target is specified as an integer number of reads.
+ */
+ public final Integer toCoverage;
+
+ /**
+ * Actual downsampling target is specified as a fraction of total available reads.
+ */
+ public final Double toFraction;
+
+ /**
+ * Expresses no downsampling applied at all.
+ */
+ public static final DownsamplingMethod NONE = new DownsamplingMethod(DownsampleType.NONE, null, null);
+
+ /**
+ * Default type to use if no type is specified
+ */
+ public static final DownsampleType DEFAULT_DOWNSAMPLING_TYPE = DownsampleType.BY_SAMPLE;
+
+ /**
+ * Don't allow dcov values below this threshold for locus-based traversals (ie., Locus
+ * and ActiveRegion walkers), as they can result in problematic downsampling artifacts
+ */
+ public static final int MINIMUM_SAFE_COVERAGE_TARGET_FOR_LOCUS_BASED_TRAVERSALS = 200;
+
+
+ public DownsamplingMethod( DownsampleType type, Integer toCoverage, Double toFraction ) {
+ this.type = type != null ? type : DEFAULT_DOWNSAMPLING_TYPE;
+
+ if ( type == DownsampleType.NONE ) {
+ this.toCoverage = null;
+ this.toFraction = null;
+ }
+ else {
+ this.toCoverage = toCoverage;
+ this.toFraction = toFraction;
+ }
+
+ validate();
+ }
+
+ private void validate() {
+ // Can't leave toFraction and toCoverage null unless type is NONE
+ if ( type != DownsampleType.NONE && toFraction == null && toCoverage == null )
+ throw new UserException("Must specify either toFraction or toCoverage when downsampling.");
+
+ // Fraction and coverage cannot both be specified.
+ if ( toFraction != null && toCoverage != null )
+ throw new UserException("Downsampling coverage and fraction are both specified. Please choose only one.");
+
+ // toCoverage must be > 0 when specified
+ if ( toCoverage != null && toCoverage <= 0 ) {
+ throw new UserException("toCoverage must be > 0 when downsampling to coverage");
+ }
+
+ // toFraction must be >= 0.0 and <= 1.0 when specified
+ if ( toFraction != null && (toFraction < 0.0 || toFraction > 1.0) ) {
+ throw new UserException("toFraction must be >= 0.0 and <= 1.0 when downsampling to a fraction of reads");
+ }
+ }
+
+ public void checkCompatibilityWithWalker( Walker walker ) {
+ boolean isLocusTraversal = walker instanceof LocusWalker || walker instanceof ActiveRegionWalker;
+
+ if ( isLocusTraversal && type == DownsampleType.ALL_READS && toCoverage != null ) {
+ throw new UserException("Downsampling to coverage with the ALL_READS method for locus-based traversals (eg., LocusWalkers) is not currently supported (though it is supported for ReadWalkers).");
+ }
+
+ // For locus traversals, ensure that the dcov value (if present) is not problematically low
+ if ( isLocusTraversal && type != DownsampleType.NONE && toCoverage != null &&
+ toCoverage < MINIMUM_SAFE_COVERAGE_TARGET_FOR_LOCUS_BASED_TRAVERSALS ) {
+ throw new UserException(String.format("Locus-based traversals (ie., Locus and ActiveRegion walkers) require " +
+ "a minimum -dcov value of %d when downsampling to coverage. Values less " +
+ "than this can produce problematic downsampling artifacts while providing " +
+ "only insignificant improvements in memory usage in most cases.",
+ MINIMUM_SAFE_COVERAGE_TARGET_FOR_LOCUS_BASED_TRAVERSALS));
+ }
+ }
+
+ public String toString() {
+ StringBuilder builder = new StringBuilder("Downsampling Settings: ");
+
+ if ( type == DownsampleType.NONE ) {
+ builder.append("No downsampling");
+ }
+ else {
+ builder.append(String.format("Method: %s, ", type));
+
+ if ( toCoverage != null ) {
+ builder.append(String.format("Target Coverage: %d", toCoverage));
+ }
+ else {
+ builder.append(String.format("Target Fraction: %.2f", toFraction));
+ }
+ }
+
+ return builder.toString();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingReadsIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingReadsIterator.java
new file mode 100644
index 0000000..6b398ab
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingReadsIterator.java
@@ -0,0 +1,116 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+
+/**
+ * GATKSAMIterator wrapper around our generic reads downsampler interface. Converts the push-style
+ * downsampler interface to a pull model.
+ *
+ * @author David Roazen
+ */
+public class DownsamplingReadsIterator implements GATKSAMIterator {
+
+ private GATKSAMIterator nestedSAMIterator;
+ private ReadsDownsampler<SAMRecord> downsampler;
+ private Collection<SAMRecord> downsampledReadsCache;
+ private SAMRecord nextRead = null;
+ private Iterator<SAMRecord> downsampledReadsCacheIterator = null;
+
+ /**
+ * @param iter wrapped iterator from which this iterator will pull reads
+ * @param downsampler downsampler through which the reads will be fed
+ */
+ public DownsamplingReadsIterator( GATKSAMIterator iter, ReadsDownsampler<SAMRecord> downsampler ) {
+ nestedSAMIterator = iter;
+ this.downsampler = downsampler;
+
+ advanceToNextRead();
+ }
+
+ public boolean hasNext() {
+ return nextRead != null;
+ }
+
+ public SAMRecord next() {
+ if ( nextRead == null ) {
+ throw new NoSuchElementException("next() called when there are no more items");
+ }
+
+ SAMRecord toReturn = nextRead;
+ advanceToNextRead();
+
+ return toReturn;
+ }
+
+ private void advanceToNextRead() {
+ if ( ! readyToReleaseReads() && ! fillDownsampledReadsCache() ) {
+ nextRead = null;
+ }
+ else {
+ nextRead = downsampledReadsCacheIterator.next();
+ }
+ }
+
+ private boolean readyToReleaseReads() {
+ return downsampledReadsCacheIterator != null && downsampledReadsCacheIterator.hasNext();
+ }
+
+ private boolean fillDownsampledReadsCache() {
+ while ( nestedSAMIterator.hasNext() && ! downsampler.hasFinalizedItems() ) {
+ downsampler.submit(nestedSAMIterator.next());
+ }
+
+ if ( ! nestedSAMIterator.hasNext() ) {
+ downsampler.signalEndOfInput();
+ }
+
+ // use returned collection directly rather than make a copy, for speed
+ downsampledReadsCache = downsampler.consumeFinalizedItems();
+ downsampledReadsCacheIterator = downsampledReadsCache.iterator();
+
+ return downsampledReadsCacheIterator.hasNext();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Can not remove records from a SAM file via an iterator!");
+ }
+
+ public void close() {
+ nestedSAMIterator.close();
+ }
+
+ public Iterator<SAMRecord> iterator() {
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingUtils.java
new file mode 100644
index 0000000..bd236c0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingUtils.java
@@ -0,0 +1,107 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+import java.util.*;
+
+/**
+ * Utilities for using the downsamplers for common tasks
+ *
+ * User: depristo
+ * Date: 3/6/13
+ * Time: 4:26 PM
+ */
+public class DownsamplingUtils {
+ private DownsamplingUtils() { }
+
+ /**
+ * Level the coverage of the reads in each sample to no more than downsampleTo reads, no reducing
+ * coverage at any read start to less than minReadsPerAlignmentStart
+ *
+ * This algorithm can be used to handle the situation where you have lots of coverage in some interval, and
+ * want to reduce the coverage of the big peak down without removing the many reads at the edge of this
+ * interval that are in fact good
+ *
+ * This algorithm separately operates on the reads for each sample independently.
+ *
+ * @param reads a sorted list of reads
+ * @param downsampleTo the targeted number of reads we want from reads per sample
+ * @param minReadsPerAlignmentStart don't reduce the number of reads starting at a specific alignment start
+ * to below this. That is, if this value is 2, we'll never reduce the number
+ * of reads starting at a specific start site to less than 2
+ * @return a sorted list of reads
+ */
+ public static List<GATKSAMRecord> levelCoverageByPosition(final List<GATKSAMRecord> reads, final int downsampleTo, final int minReadsPerAlignmentStart) {
+ if ( reads == null ) throw new IllegalArgumentException("reads must not be null");
+
+ final List<GATKSAMRecord> downsampled = new ArrayList<GATKSAMRecord>(reads.size());
+
+ final Map<String, Map<Integer, List<GATKSAMRecord>>> readsBySampleByStart = partitionReadsBySampleAndStart(reads);
+ for ( final Map<Integer, List<GATKSAMRecord>> readsByPosMap : readsBySampleByStart.values() ) {
+ final LevelingDownsampler<List<GATKSAMRecord>, GATKSAMRecord> downsampler = new LevelingDownsampler<List<GATKSAMRecord>, GATKSAMRecord>(downsampleTo, minReadsPerAlignmentStart);
+ downsampler.submit(readsByPosMap.values());
+ downsampler.signalEndOfInput();
+ for ( final List<GATKSAMRecord> downsampledReads : downsampler.consumeFinalizedItems())
+ downsampled.addAll(downsampledReads);
+ }
+
+ return ReadUtils.sortReadsByCoordinate(downsampled);
+ }
+
+ /**
+ * Build the data structure mapping for each sample -> (position -> reads at position)
+ *
+ * Note that the map position -> reads isn't ordered in any meaningful way
+ *
+ * @param reads a list of sorted reads
+ * @return a map containing the list of reads at each start location, for each sample independently
+ */
+ private static Map<String, Map<Integer, List<GATKSAMRecord>>> partitionReadsBySampleAndStart(final List<GATKSAMRecord> reads) {
+ final Map<String, Map<Integer, List<GATKSAMRecord>>> readsBySampleByStart = new LinkedHashMap<String, Map<Integer, List<GATKSAMRecord>>>();
+
+ for ( final GATKSAMRecord read : reads ) {
+ Map<Integer, List<GATKSAMRecord>> readsByStart = readsBySampleByStart.get(read.getReadGroup().getSample());
+
+ if ( readsByStart == null ) {
+ readsByStart = new LinkedHashMap<Integer, List<GATKSAMRecord>>();
+ readsBySampleByStart.put(read.getReadGroup().getSample(), readsByStart);
+ }
+
+ List<GATKSAMRecord> readsAtStart = readsByStart.get(read.getAlignmentStart());
+ if ( readsAtStart == null ) {
+ readsAtStart = new LinkedList<GATKSAMRecord>();
+ readsByStart.put(read.getAlignmentStart(), readsAtStart);
+ }
+
+ readsAtStart.add(read);
+ }
+
+ return readsBySampleByStart;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/FractionalDownsampler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/FractionalDownsampler.java
new file mode 100644
index 0000000..a2d613c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/FractionalDownsampler.java
@@ -0,0 +1,129 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Fractional Downsampler: selects a specified fraction of the reads for inclusion.
+ *
+ * Since the selection is done randomly, the actual fraction of reads retained may be slightly
+ * more or less than the requested fraction, depending on the total number of reads submitted.
+ *
+ * @author David Roazen
+ */
+public class FractionalDownsampler<T extends SAMRecord> extends ReadsDownsampler<T> {
+
+ private ArrayList<T> selectedReads;
+
+ private final int cutoffForInclusion;
+
+ private static final int RANDOM_POOL_SIZE = 10000;
+
+ /**
+ * Construct a FractionalDownsampler
+ *
+ * @param fraction Fraction of reads to preserve, between 0.0 (inclusive) and 1.0 (inclusive).
+ * Actual number of reads preserved may differ randomly.
+ */
+ public FractionalDownsampler( final double fraction ) {
+ if ( fraction < 0.0 || fraction > 1.0 ) {
+ throw new ReviewedGATKException("Fraction of reads to include must be between 0.0 and 1.0, inclusive");
+ }
+
+ cutoffForInclusion = (int)(fraction * RANDOM_POOL_SIZE);
+ clearItems();
+ resetStats();
+ }
+
+ @Override
+ public void submit( final T newRead ) {
+ if ( GenomeAnalysisEngine.getRandomGenerator().nextInt(10000) < cutoffForInclusion || doNotDiscardItem(newRead) ) {
+ selectedReads.add(newRead);
+ }
+ else {
+ numDiscardedItems++;
+ }
+ }
+
+ @Override
+ public boolean hasFinalizedItems() {
+ return selectedReads.size() > 0;
+ }
+
+ @Override
+ public List<T> consumeFinalizedItems() {
+ // pass by reference rather than make a copy, for speed
+ List<T> downsampledItems = selectedReads;
+ clearItems();
+ return downsampledItems;
+ }
+
+ @Override
+ public boolean hasPendingItems() {
+ return false;
+ }
+
+ @Override
+ public T peekFinalized() {
+ return selectedReads.isEmpty() ? null : selectedReads.get(0);
+ }
+
+ @Override
+ public T peekPending() {
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return selectedReads.size();
+ }
+
+ @Override
+ public void signalEndOfInput() {
+ // NO-OP
+ }
+
+ @Override
+ public void clearItems() {
+ selectedReads = new ArrayList<T>();
+ }
+
+ @Override
+ public boolean requiresCoordinateSortOrder() {
+ return false;
+ }
+
+ @Override
+ public void signalNoMoreReadsBefore( final T read ) {
+ // NO-OP
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/FractionalDownsamplerFactory.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/FractionalDownsamplerFactory.java
new file mode 100644
index 0000000..4ddf8dd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/FractionalDownsamplerFactory.java
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Factory for creating FractionalDownsamplers on demand
+ *
+ * @author David Roazen
+ */
+public class FractionalDownsamplerFactory<T extends SAMRecord> implements ReadsDownsamplerFactory<T> {
+
+ private double fraction;
+
+ public FractionalDownsamplerFactory( double fraction ) {
+ this.fraction = fraction;
+ }
+
+ public ReadsDownsampler<T> newInstance() {
+ return new FractionalDownsampler<T>(fraction);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/LevelingDownsampler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/LevelingDownsampler.java
new file mode 100644
index 0000000..4ae7bc5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/LevelingDownsampler.java
@@ -0,0 +1,242 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import org.broadinstitute.gatk.utils.MathUtils;
+
+import java.util.*;
+
+/**
+ * Leveling Downsampler: Given a set of Lists of arbitrary items and a target size, removes items from
+ * the Lists in an even fashion until the total size of all Lists is <= the target size. Leveling
+ * does not occur until all Lists have been submitted and signalEndOfInput() is called.
+ *
+ * The Lists should be LinkedLists for maximum efficiency during item removal, however other
+ * kinds of Lists are also accepted (albeit at a slight performance penalty).
+ *
+ * Since this downsampler extends the Downsampler interface rather than the ReadsDownsampler interface,
+ * the Lists need not contain reads. However this downsampler may not be wrapped within one of the
+ * DownsamplingReadsIterators
+ *
+ * @param <T> the List type representing the stacks to be leveled
+ * @param <E> the type of the elements of each List
+ *
+ * @author David Roazen
+ */
+public class LevelingDownsampler<T extends List<E>, E> extends Downsampler<T> {
+ private final int minElementsPerStack;
+
+ private final int targetSize;
+
+ private List<T> groups;
+
+ private boolean groupsAreFinalized;
+
+ /**
+ * Construct a LevelingDownsampler
+ *
+ * Uses the default minElementsPerStack of 1
+ *
+ * @param targetSize the sum of the sizes of all individual Lists this downsampler is fed may not exceed
+ * this value -- if it does, items are removed from Lists evenly until the total size
+ * is <= this value
+ */
+ public LevelingDownsampler( final int targetSize ) {
+ this(targetSize, 1);
+ }
+
+ /**
+ * Construct a LevelingDownsampler
+ *
+ * @param targetSize the sum of the sizes of all individual Lists this downsampler is fed may not exceed
+ * this value -- if it does, items are removed from Lists evenly until the total size
+ * is <= this value
+ * @param minElementsPerStack no stack will be reduced below this size during downsampling. That is,
+ * if a stack has only 3 elements and minElementsPerStack is 3, no matter what
+ * we'll not reduce this stack below 3.
+ */
+ public LevelingDownsampler( final int targetSize, final int minElementsPerStack ) {
+ if ( targetSize < 0 ) throw new IllegalArgumentException("targetSize must be >= 0 but got " + targetSize);
+ if ( minElementsPerStack < 0 ) throw new IllegalArgumentException("minElementsPerStack must be >= 0 but got " + minElementsPerStack);
+
+ this.targetSize = targetSize;
+ this.minElementsPerStack = minElementsPerStack;
+ clearItems();
+ resetStats();
+ }
+
+ @Override
+ public void submit( final T item ) {
+ groups.add(item);
+ }
+
+ @Override
+ public void submit( final Collection<T> items ){
+ groups.addAll(items);
+ }
+
+ @Override
+ public boolean hasFinalizedItems() {
+ return groupsAreFinalized && groups.size() > 0;
+ }
+
+ @Override
+ public List<T> consumeFinalizedItems() {
+ if ( ! hasFinalizedItems() ) {
+ return new ArrayList<T>();
+ }
+
+ // pass by reference rather than make a copy, for speed
+ final List<T> toReturn = groups;
+ clearItems();
+ return toReturn;
+ }
+
+ @Override
+ public boolean hasPendingItems() {
+ return ! groupsAreFinalized && groups.size() > 0;
+ }
+
+ @Override
+ public T peekFinalized() {
+ return hasFinalizedItems() ? groups.get(0) : null;
+ }
+
+ @Override
+ public T peekPending() {
+ return hasPendingItems() ? groups.get(0) : null;
+ }
+
+ @Override
+ public int size() {
+ int s = 0;
+ for ( final List<E> l : groups ) {
+ s += l.size();
+ }
+ return s;
+ }
+
+ @Override
+ public void signalEndOfInput() {
+ levelGroups();
+ groupsAreFinalized = true;
+ }
+
+ @Override
+ public void clearItems() {
+ groups = new ArrayList<T>();
+ groupsAreFinalized = false;
+ }
+
+ private void levelGroups() {
+ final int[] groupSizes = new int[groups.size()];
+ int totalSize = 0;
+ int currentGroupIndex = 0;
+
+ for ( final T group : groups ) {
+ groupSizes[currentGroupIndex] = group.size();
+ totalSize += groupSizes[currentGroupIndex];
+ currentGroupIndex++;
+ }
+
+ if ( totalSize <= targetSize ) {
+ return; // no need to eliminate any items
+ }
+
+ // We will try to remove exactly this many items, however we will refuse to allow any
+ // one group to fall below size 1, and so might end up removing fewer items than this
+ int numItemsToRemove = totalSize - targetSize;
+
+ currentGroupIndex = 0;
+ int numConsecutiveUmodifiableGroups = 0;
+
+ // Continue until we've either removed all the items we wanted to, or we can't
+ // remove any more items without violating the constraint that all groups must
+ // be left with at least one item
+ while ( numItemsToRemove > 0 && numConsecutiveUmodifiableGroups < groupSizes.length ) {
+ if ( groupSizes[currentGroupIndex] > minElementsPerStack ) {
+ groupSizes[currentGroupIndex]--;
+ numItemsToRemove--;
+ numConsecutiveUmodifiableGroups = 0;
+ }
+ else {
+ numConsecutiveUmodifiableGroups++;
+ }
+
+ currentGroupIndex = (currentGroupIndex + 1) % groupSizes.length;
+ }
+
+ // Now we actually go through and reduce each group to its new count as specified in groupSizes
+ currentGroupIndex = 0;
+ for ( final T group : groups ) {
+ downsampleOneGroup(group, groupSizes[currentGroupIndex]);
+ currentGroupIndex++;
+ }
+ }
+
+ private void downsampleOneGroup( final T group, final int numItemsToKeep ) {
+ if ( numItemsToKeep >= group.size() ) {
+ return;
+ }
+
+ final BitSet itemsToKeep = new BitSet(group.size());
+ for ( Integer selectedIndex : MathUtils.sampleIndicesWithoutReplacement(group.size(), numItemsToKeep) ) {
+ itemsToKeep.set(selectedIndex);
+ }
+
+ int currentIndex = 0;
+
+ // If our group is a linked list, we can remove the desired items in a single O(n) pass with an iterator
+ if ( group instanceof LinkedList ) {
+ final Iterator<E> iter = group.iterator();
+ while ( iter.hasNext() ) {
+ final E item = iter.next();
+
+ if ( ! itemsToKeep.get(currentIndex) && ! doNotDiscardItem(item) ) {
+ iter.remove();
+ numDiscardedItems++;
+ }
+
+ currentIndex++;
+ }
+ }
+ // If it's not a linked list, it's more efficient to copy the desired items into a new list and back rather
+ // than suffer O(n^2) of item shifting
+ else {
+ final List<E> keptItems = new ArrayList<E>(group.size());
+
+ for ( final E item : group ) {
+ if ( itemsToKeep.get(currentIndex) || doNotDiscardItem(item) ) {
+ keptItems.add(item);
+ }
+ currentIndex++;
+ }
+ numDiscardedItems += group.size() - keptItems.size();
+ group.clear();
+ group.addAll(keptItems);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/PassThroughDownsampler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/PassThroughDownsampler.java
new file mode 100644
index 0000000..a5fdf24
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/PassThroughDownsampler.java
@@ -0,0 +1,111 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMRecord;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Pass-Through Downsampler: Implementation of the ReadsDownsampler interface that does no
+ * downsampling whatsoever, and instead simply "passes-through" all the reads it's given.
+ * Useful for situations where you want to disable downsampling, but still need to use
+ * the downsampler interface.
+ *
+ * @author David Roazen
+ */
+public class PassThroughDownsampler<T extends SAMRecord> extends ReadsDownsampler<T> {
+
+ private LinkedList<T> selectedReads;
+
+ public PassThroughDownsampler() {
+ clearItems();
+ }
+
+ @Override
+ public void submit( T newRead ) {
+ // All reads pass-through, no reads get downsampled
+ selectedReads.add(newRead);
+ }
+
+ @Override
+ public boolean hasFinalizedItems() {
+ return ! selectedReads.isEmpty();
+ }
+
+ /**
+ * Note that this list is a linked list and so doesn't support fast random access
+ * @return
+ */
+ @Override
+ public List<T> consumeFinalizedItems() {
+ // pass by reference rather than make a copy, for speed
+ final List<T> downsampledItems = selectedReads;
+ clearItems();
+ return downsampledItems;
+ }
+
+ @Override
+ public boolean hasPendingItems() {
+ return false;
+ }
+
+ @Override
+ public T peekFinalized() {
+ return selectedReads.isEmpty() ? null : selectedReads.getFirst();
+ }
+
+ @Override
+ public T peekPending() {
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return selectedReads.size();
+ }
+
+ @Override
+ public void signalEndOfInput() {
+ // NO-OP
+ }
+
+ @Override
+ public void clearItems() {
+ selectedReads = new LinkedList<T>();
+ }
+
+ @Override
+ public boolean requiresCoordinateSortOrder() {
+ return false;
+ }
+
+ @Override
+ public void signalNoMoreReadsBefore( T read ) {
+ // NO-OP
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/PerSampleDownsamplingReadsIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/PerSampleDownsamplingReadsIterator.java
new file mode 100644
index 0000000..118bbbb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/PerSampleDownsamplingReadsIterator.java
@@ -0,0 +1,207 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMRecordComparator;
+import htsjdk.samtools.SAMRecordCoordinateComparator;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+
+import java.util.*;
+
+
+/**
+ * GATKSAMIterator wrapper around our generic reads downsampler interface
+ * that downsamples reads for each sample independently, and then re-assembles
+ * the reads back into a single merged stream.
+ *
+ * @author David Roazen
+ */
+public class PerSampleDownsamplingReadsIterator implements GATKSAMIterator {
+
+ private GATKSAMIterator nestedSAMIterator;
+ private ReadsDownsamplerFactory<SAMRecord> downsamplerFactory;
+ private Map<String, ReadsDownsampler<SAMRecord>> perSampleDownsamplers;
+ private PriorityQueue<SAMRecord> orderedDownsampledReadsCache;
+ private SAMRecord nextRead = null;
+ private SAMRecordComparator readComparator = new SAMRecordCoordinateComparator();
+ private SAMRecord earliestPendingRead = null;
+ private ReadsDownsampler<SAMRecord> earliestPendingDownsampler = null;
+
+ // Initial size of our cache of finalized reads
+ private static final int DOWNSAMPLED_READS_INITIAL_CACHE_SIZE = 4096;
+
+ // The number of positional changes that can occur in the read stream before all downsamplers
+ // should be informed of the current position (guards against samples with relatively sparse reads
+ // getting stuck in a pending state):
+ private static final int DOWNSAMPLER_POSITIONAL_UPDATE_INTERVAL = 3; // TODO: experiment with this value
+
+ /**
+ * @param iter wrapped iterator from which this iterator will pull reads
+ * @param downsamplerFactory factory used to create new downsamplers as needed
+ */
+ public PerSampleDownsamplingReadsIterator( GATKSAMIterator iter, ReadsDownsamplerFactory<SAMRecord> downsamplerFactory ) {
+ nestedSAMIterator = iter;
+ this.downsamplerFactory = downsamplerFactory;
+ perSampleDownsamplers = new HashMap<String, ReadsDownsampler<SAMRecord>>();
+ orderedDownsampledReadsCache = new PriorityQueue<SAMRecord>(DOWNSAMPLED_READS_INITIAL_CACHE_SIZE, readComparator);
+
+ advanceToNextRead();
+ }
+
+ public boolean hasNext() {
+ return nextRead != null;
+ }
+
+ public SAMRecord next() {
+ if ( nextRead == null ) {
+ throw new NoSuchElementException("next() called when there are no more items");
+ }
+
+ SAMRecord toReturn = nextRead;
+ advanceToNextRead();
+
+ return toReturn;
+ }
+
+ private void advanceToNextRead() {
+ if ( ! readyToReleaseReads() && ! fillDownsampledReadsCache() ) {
+ nextRead = null;
+ }
+ else {
+ nextRead = orderedDownsampledReadsCache.poll();
+ }
+ }
+
+ private boolean readyToReleaseReads() {
+ if ( orderedDownsampledReadsCache.isEmpty() ) {
+ return false;
+ }
+
+ return earliestPendingRead == null ||
+ readComparator.compare(orderedDownsampledReadsCache.peek(), earliestPendingRead) <= 0;
+ }
+
+ private boolean fillDownsampledReadsCache() {
+ SAMRecord prevRead = null;
+ int numPositionalChanges = 0;
+
+ // Continue submitting reads to the per-sample downsamplers until the read at the top of the priority queue
+ // can be released without violating global sort order
+ while ( nestedSAMIterator.hasNext() && ! readyToReleaseReads() ) {
+ SAMRecord read = nestedSAMIterator.next();
+ String sampleName = read.getReadGroup() != null ? read.getReadGroup().getSample() : null;
+
+ ReadsDownsampler<SAMRecord> thisSampleDownsampler = perSampleDownsamplers.get(sampleName);
+ if ( thisSampleDownsampler == null ) {
+ thisSampleDownsampler = downsamplerFactory.newInstance();
+ perSampleDownsamplers.put(sampleName, thisSampleDownsampler);
+ }
+
+ thisSampleDownsampler.submit(read);
+ processFinalizedAndPendingItems(thisSampleDownsampler);
+
+ if ( prevRead != null && prevRead.getAlignmentStart() != read.getAlignmentStart() ) {
+ numPositionalChanges++;
+ }
+
+ // Periodically inform all downsamplers of the current position in the read stream. This is
+ // to prevent downsamplers for samples with sparser reads than others from getting stuck too
+ // long in a pending state.
+ if ( numPositionalChanges > 0 && numPositionalChanges % DOWNSAMPLER_POSITIONAL_UPDATE_INTERVAL == 0 ) {
+ for ( ReadsDownsampler<SAMRecord> perSampleDownsampler : perSampleDownsamplers.values() ) {
+ perSampleDownsampler.signalNoMoreReadsBefore(read);
+ processFinalizedAndPendingItems(perSampleDownsampler);
+ }
+ }
+
+ prevRead = read;
+ }
+
+ if ( ! nestedSAMIterator.hasNext() ) {
+ for ( ReadsDownsampler<SAMRecord> perSampleDownsampler : perSampleDownsamplers.values() ) {
+ perSampleDownsampler.signalEndOfInput();
+ if ( perSampleDownsampler.hasFinalizedItems() ) {
+ orderedDownsampledReadsCache.addAll(perSampleDownsampler.consumeFinalizedItems());
+ }
+ }
+ earliestPendingRead = null;
+ earliestPendingDownsampler = null;
+ }
+
+ return readyToReleaseReads();
+ }
+
+ private void updateEarliestPendingRead( ReadsDownsampler<SAMRecord> currentDownsampler ) {
+ // If there is no recorded earliest pending read and this downsampler has pending items,
+ // then this downsampler's first pending item becomes the new earliest pending read:
+ if ( earliestPendingRead == null && currentDownsampler.hasPendingItems() ) {
+ earliestPendingRead = currentDownsampler.peekPending();
+ earliestPendingDownsampler = currentDownsampler;
+ }
+ // In all other cases, we only need to update the earliest pending read when the downsampler
+ // associated with it experiences a change in its pending reads, since by assuming a sorted
+ // read stream we're assured that each downsampler's earliest pending read will only increase
+ // in genomic position over time.
+ //
+ // TODO: An occasional O(samples) linear search seems like a better option than keeping the downsamplers
+ // TODO: sorted by earliest pending read, which would cost at least O(total_reads * (samples + log(samples))),
+ // TODO: but need to verify this empirically.
+ else if ( currentDownsampler == earliestPendingDownsampler &&
+ (! currentDownsampler.hasPendingItems() || readComparator.compare(currentDownsampler.peekPending(), earliestPendingRead) != 0) ) {
+
+ earliestPendingRead = null;
+ earliestPendingDownsampler = null;
+ for ( ReadsDownsampler<SAMRecord> perSampleDownsampler : perSampleDownsamplers.values() ) {
+ if ( perSampleDownsampler.hasPendingItems() &&
+ (earliestPendingRead == null || readComparator.compare(perSampleDownsampler.peekPending(), earliestPendingRead) < 0) ) {
+
+ earliestPendingRead = perSampleDownsampler.peekPending();
+ earliestPendingDownsampler = perSampleDownsampler;
+ }
+ }
+ }
+ }
+
+ private void processFinalizedAndPendingItems( ReadsDownsampler<SAMRecord> currentDownsampler ) {
+ if ( currentDownsampler.hasFinalizedItems() ) {
+ orderedDownsampledReadsCache.addAll(currentDownsampler.consumeFinalizedItems());
+ }
+ updateEarliestPendingRead(currentDownsampler);
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Can not remove records from a SAM file via an iterator!");
+ }
+
+ public void close() {
+ nestedSAMIterator.close();
+ }
+
+ public Iterator<SAMRecord> iterator() {
+ return this;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReadsDownsampler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReadsDownsampler.java
new file mode 100644
index 0000000..9263920
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReadsDownsampler.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * An extension of the basic downsampler API with reads-specific operations
+ *
+ * @author David Roazen
+ */
+public abstract class ReadsDownsampler<T extends SAMRecord> extends Downsampler<T> {
+
+ /**
+ * Does this downsampler require that reads be fed to it in coordinate order?
+ *
+ * @return true if reads must be submitted to this downsampler in coordinate order, otherwise false
+ */
+ public abstract boolean requiresCoordinateSortOrder();
+
+ /**
+ * Tell this downsampler that no more reads located before the provided read (according to
+ * the sort order of the read stream) will be fed to it.
+ *
+ * Allows position-aware downsamplers to finalize pending reads earlier than they would
+ * otherwise be able to, particularly when doing per-sample downsampling and reads for
+ * certain samples are sparser than average.
+ *
+ * @param read the downsampler will assume that no reads located before this read will ever
+ * be submitted to it in the future
+ */
+ public abstract void signalNoMoreReadsBefore( final T read );
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReadsDownsamplerFactory.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReadsDownsamplerFactory.java
new file mode 100644
index 0000000..9ef847e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReadsDownsamplerFactory.java
@@ -0,0 +1,38 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * A ReadsDownsamplerFactory can be used to create an arbitrary number of instances of a particular
+ * downsampler, all sharing the same construction parameters.
+ *
+ * @author David Roazen
+ */
+public interface ReadsDownsamplerFactory<T extends SAMRecord> {
+ public ReadsDownsampler<T> newInstance();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReservoirDownsampler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReservoirDownsampler.java
new file mode 100644
index 0000000..99a0bbd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReservoirDownsampler.java
@@ -0,0 +1,219 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ * Reservoir Downsampler: Selects n reads out of a stream whose size is not known in advance, with
+ * every read in the stream having an equal chance of being selected for inclusion.
+ *
+ * An implementation of "Algorithm R" from the paper "Random Sampling with a Reservoir" (Jeffrey Scott Vitter, 1985)
+ *
+ * @author David Roazen
+ */
+public class ReservoirDownsampler<T extends SAMRecord> extends ReadsDownsampler<T> {
+
+ /**
+ * size of our reservoir -- ie., the maximum number of reads from the stream that will be retained
+ * (not including any undiscardable items)
+ */
+ private final int targetSampleSize;
+
+ /**
+ * if true, this downsampler will be optimized for the case
+ * where most of the time we won't fill up anything like the
+ * targetSampleSize elements. If this is false, we will allocate
+ * internal buffers to targetSampleSize initially, which minimizes
+ * the cost of allocation if we often use targetSampleSize or more
+ * elements.
+ */
+ private final boolean expectFewOverflows;
+
+ /**
+ * At times this can be a linked list or an array list, depending on how we're accessing the
+ * data and whether or not we're expecting few overflows
+ */
+ private List<T> reservoir;
+
+ /**
+ * Certain items (eg., reduced reads) cannot be discarded at all during downsampling. We store
+ * these items separately so as not to impact the fair selection of items for inclusion in the
+ * reservoir. These items are returned (and cleared) along with any items in the reservoir in
+ * calls to consumeFinalizedItems().
+ */
+ private List<T> undiscardableItems;
+
+ /**
+ * Are we currently using a linked list for the reservoir?
+ */
+ private boolean isLinkedList;
+
+ /**
+ * Count of the number of reads seen that were actually eligible for discarding. Used by the reservoir downsampling
+ * algorithm to ensure that all discardable reads have an equal chance of making it into the reservoir.
+ */
+ private int totalDiscardableReadsSeen;
+
+
+ /**
+ * Construct a ReservoirDownsampler
+ *
+ * @param targetSampleSize Size of the reservoir used by this downsampler. Number of items retained
+ * after downsampling will be min(totalDiscardableReads, targetSampleSize) + any
+ * undiscardable reads (eg., reduced reads).
+ *
+ * @param expectFewOverflows if true, this downsampler will be optimized for the case
+ * where most of the time we won't fill up anything like the
+ * targetSampleSize elements. If this is false, we will allocate
+ * internal buffers to targetSampleSize initially, which minimizes
+ * the cost of allocation if we often use targetSampleSize or more
+ * elements.
+ */
+ public ReservoirDownsampler ( final int targetSampleSize, final boolean expectFewOverflows ) {
+ if ( targetSampleSize <= 0 ) {
+ throw new ReviewedGATKException("Cannot do reservoir downsampling with a sample size <= 0");
+ }
+
+ this.targetSampleSize = targetSampleSize;
+ this.expectFewOverflows = expectFewOverflows;
+ clearItems();
+ resetStats();
+ }
+
+ /**
+ * Construct a ReservoirDownsampler
+ *
+ * @param targetSampleSize Size of the reservoir used by this downsampler. Number of items retained
+ * after downsampling will be min(totalReads, targetSampleSize)
+ */
+ public ReservoirDownsampler ( final int targetSampleSize ) {
+ this(targetSampleSize, false);
+ }
+
+ @Override
+ public void submit ( final T newRead ) {
+ if ( doNotDiscardItem(newRead) ) {
+ undiscardableItems.add(newRead);
+ return;
+ }
+
+ // Only count reads that are actually eligible for discarding for the purposes of the reservoir downsampling algorithm
+ totalDiscardableReadsSeen++;
+
+ if ( totalDiscardableReadsSeen <= targetSampleSize ) {
+ reservoir.add(newRead);
+ }
+ else {
+ if ( isLinkedList ) {
+ reservoir = new ArrayList<T>(reservoir);
+ isLinkedList = false;
+ }
+
+ final int randomSlot = GenomeAnalysisEngine.getRandomGenerator().nextInt(totalDiscardableReadsSeen);
+ if ( randomSlot < targetSampleSize ) {
+ reservoir.set(randomSlot, newRead);
+ }
+ numDiscardedItems++;
+ }
+ }
+
+ @Override
+ public boolean hasFinalizedItems() {
+ return ! reservoir.isEmpty() || ! undiscardableItems.isEmpty();
+ }
+
+ @Override
+ public List<T> consumeFinalizedItems() {
+ if ( ! hasFinalizedItems() ) {
+ // if there's nothing here, don't bother allocating a new list
+ return Collections.emptyList();
+ } else {
+ // pass reservoir by reference rather than make a copy, for speed
+ final List<T> downsampledItems = reservoir;
+ downsampledItems.addAll(undiscardableItems);
+ clearItems();
+ return downsampledItems;
+ }
+ }
+
+ @Override
+ public boolean hasPendingItems() {
+ return false;
+ }
+
+ @Override
+ public T peekFinalized() {
+ return ! reservoir.isEmpty() ? reservoir.get(0) : (! undiscardableItems.isEmpty() ? undiscardableItems.get(0) : null);
+ }
+
+ @Override
+ public T peekPending() {
+ return null;
+ }
+
+ @Override
+ public int size() {
+ return reservoir.size() + undiscardableItems.size();
+ }
+
+ @Override
+ public void signalEndOfInput() {
+ // NO-OP
+ }
+
+ /**
+ * Clear the data structures used to hold information
+ */
+ @Override
+ public void clearItems() {
+ // if we aren't expecting many overflows, allocate a linked list not an arraylist
+ reservoir = expectFewOverflows ? new LinkedList<T>() : new ArrayList<T>(targetSampleSize);
+
+ // there's no possibility of overflow with the undiscardable items, so we always use a linked list for them
+ undiscardableItems = new LinkedList<>();
+
+ // it's a linked list if we allocate one
+ isLinkedList = expectFewOverflows;
+
+ // an internal stat used by the downsampling process, so not cleared by resetStats() below
+ totalDiscardableReadsSeen = 0;
+ }
+
+ @Override
+ public boolean requiresCoordinateSortOrder() {
+ return false;
+ }
+
+ @Override
+ public void signalNoMoreReadsBefore( T read ) {
+ // NO-OP
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReservoirDownsamplerFactory.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReservoirDownsamplerFactory.java
new file mode 100644
index 0000000..c825bae
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/ReservoirDownsamplerFactory.java
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Factory for creating ReservoirDownsamplers on demand
+ *
+ * @author David Roazen
+ */
+public class ReservoirDownsamplerFactory<T extends SAMRecord> implements ReadsDownsamplerFactory<T> {
+
+ private int targetSampleSize;
+
+ public ReservoirDownsamplerFactory( int targetSampleSize ) {
+ this.targetSampleSize = targetSampleSize;
+ }
+
+ public ReadsDownsampler<T> newInstance() {
+ return new ReservoirDownsampler<T>(targetSampleSize);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/SimplePositionalDownsampler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/SimplePositionalDownsampler.java
new file mode 100644
index 0000000..af0aa54
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/SimplePositionalDownsampler.java
@@ -0,0 +1,171 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMRecord;
+
+import java.util.*;
+
+/**
+ * Simple Positional Downsampler: Downsample each stack of reads at each alignment start to a size <= a target coverage
+ * using a Reservoir downsampler. Stores only O(target coverage) reads in memory at any given time.
+ *
+ * @author David Roazen
+ */
+public class SimplePositionalDownsampler<T extends SAMRecord> extends ReadsDownsampler<T> {
+
+ private final int targetCoverage;
+
+ private final ReservoirDownsampler<T> reservoir;
+
+ private int currentContigIndex;
+
+ private int currentAlignmentStart;
+
+ private boolean positionEstablished;
+
+ private boolean unmappedReadsReached;
+
+ private ArrayList<T> finalizedReads;
+
+
+ /**
+ * Construct a SimplePositionalDownsampler
+ *
+ * @param targetCoverage Maximum number of reads that may share any given alignment start position
+ */
+ public SimplePositionalDownsampler( final int targetCoverage ) {
+ this.targetCoverage = targetCoverage;
+ reservoir = new ReservoirDownsampler<T>(targetCoverage);
+ finalizedReads = new ArrayList<T>();
+ clearItems();
+ resetStats();
+ }
+
+ @Override
+ public void submit( final T newRead ) {
+ updatePositionalState(newRead);
+
+ if ( unmappedReadsReached ) { // don't downsample the unmapped reads at the end of the stream
+ finalizedReads.add(newRead);
+ }
+ else {
+ final int reservoirPreviouslyDiscardedItems = reservoir.getNumberOfDiscardedItems();
+ // our reservoir downsampler will call doNotDiscardItem() for us to exclude items from elimination as appropriate
+ reservoir.submit(newRead);
+ numDiscardedItems += reservoir.getNumberOfDiscardedItems() - reservoirPreviouslyDiscardedItems;
+ }
+ }
+
+ @Override
+ public boolean hasFinalizedItems() {
+ return finalizedReads.size() > 0;
+ }
+
+ @Override
+ public List<T> consumeFinalizedItems() {
+ // pass by reference rather than make a copy, for speed
+ final List<T> toReturn = finalizedReads;
+ finalizedReads = new ArrayList<T>();
+ return toReturn;
+ }
+
+ @Override
+ public boolean hasPendingItems() {
+ return reservoir.hasFinalizedItems();
+ }
+
+ @Override
+ public T peekFinalized() {
+ return finalizedReads.isEmpty() ? null : finalizedReads.get(0);
+ }
+
+ @Override
+ public T peekPending() {
+ return reservoir.peekFinalized();
+ }
+
+ @Override
+ public int size() {
+ return finalizedReads.size() + reservoir.size();
+ }
+
+ @Override
+ public void signalEndOfInput() {
+ finalizeReservoir();
+ }
+
+ @Override
+ public void clearItems() {
+ reservoir.clearItems();
+ reservoir.resetStats();
+ finalizedReads.clear();
+ positionEstablished = false;
+ unmappedReadsReached = false;
+ }
+
+ @Override
+ public boolean requiresCoordinateSortOrder() {
+ return true;
+ }
+
+ @Override
+ public void signalNoMoreReadsBefore( final T read ) {
+ updatePositionalState(read);
+ }
+
+ private void updatePositionalState( final T newRead ) {
+ if ( readIsPastCurrentPosition(newRead) ) {
+ if ( reservoir.hasFinalizedItems() ) {
+ finalizeReservoir();
+ }
+
+ setCurrentPosition(newRead);
+
+ if ( newRead.getReadUnmappedFlag() ) {
+ unmappedReadsReached = true;
+ }
+ }
+ }
+
+ private void setCurrentPosition( final T read ) {
+ currentContigIndex = read.getReferenceIndex();
+ currentAlignmentStart = read.getAlignmentStart();
+ positionEstablished = true;
+ }
+
+ private boolean readIsPastCurrentPosition( final T read ) {
+ return ! positionEstablished ||
+ read.getReferenceIndex() > currentContigIndex ||
+ read.getAlignmentStart() > currentAlignmentStart ||
+ (read.getReadUnmappedFlag() && ! unmappedReadsReached);
+ }
+
+ private void finalizeReservoir() {
+ finalizedReads.addAll(reservoir.consumeFinalizedItems());
+ reservoir.resetStats();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/SimplePositionalDownsamplerFactory.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/SimplePositionalDownsamplerFactory.java
new file mode 100644
index 0000000..3fc66ca
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/downsampling/SimplePositionalDownsamplerFactory.java
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Factory for creating SimplePositionalDownsamplers on demand
+ *
+ * @author David Roazen
+ */
+public class SimplePositionalDownsamplerFactory<T extends SAMRecord> implements ReadsDownsamplerFactory<T> {
+
+ private int targetCoverage;
+
+ public SimplePositionalDownsamplerFactory( int targetCoverage ) {
+ this.targetCoverage = targetCoverage;
+ }
+
+ public ReadsDownsampler<T> newInstance() {
+ return new SimplePositionalDownsampler<T>(targetCoverage);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/Accumulator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/Accumulator.java
new file mode 100644
index 0000000..9276331
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/Accumulator.java
@@ -0,0 +1,211 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.datasources.providers.LocusShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.providers.ShardDataProvider;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+/**
+ * Manages the
+ */
+
+public abstract class Accumulator {
+ /**
+ * The walker for which to accumulate.
+ */
+ protected final Walker walker;
+
+ /**
+ * Create a new Accumulator. Forbid outside classes from performing this operation.
+ * @param walker
+ */
+ protected Accumulator( Walker walker ) {
+ this.walker = walker;
+ }
+
+ /**
+ * Creates an accumulator suitable for accumulating results of the given walker.
+ * @param walker Walker for which to build an accumulator.
+ * @return Accumulator suitable for this walker.s
+ */
+ public static Accumulator create( GenomeAnalysisEngine engine, Walker walker ) {
+ if( walker.isReduceByInterval() && engine.getIntervals() != null)
+ return new IntervalAccumulator( walker, engine.getIntervals() );
+ else
+ return new StandardAccumulator( walker );
+ }
+
+ /**
+ * Gets the appropriate reduce initializer for this accumulator.
+ * @return Traversal reduce init to feed into traversal engine.
+ */
+ public abstract Object getReduceInit();
+
+ /**
+ * Roll this traversal result into the given accumulator.
+ * @param result Result of the most recent accumulation.
+ * @return the newest accumulation of the given data.
+ */
+ public abstract void accumulate( ShardDataProvider provider, Object result );
+
+ /**
+ * Finishes off the traversal. Submits accumulated results to
+ * the walker and returns them.
+ * TODO: Its a bit funky to delegate the finishing of the traversal
+ * to an accumulator, but we're doing it for type safety so the
+ * right Walker override gets called. Clean this up.
+ * @return Final result of accumulation.
+ */
+ public abstract Object finishTraversal();
+
+ /**
+ * Accumulates in the 'standard' fashion; basically funnels
+ * the reduce result back into the reduce init and relies on
+ * the user-supplied reduce to handle the accumulation.
+ */
+ private static class StandardAccumulator extends Accumulator {
+ private Object accumulator = null;
+ private boolean initialized = false;
+
+ protected StandardAccumulator( Walker walker ) {
+ super(walker);
+ }
+
+ /**
+ * Standard accumulator returns reduceInit first, then the
+ * results of the previous accumulation.
+ */
+ public Object getReduceInit() {
+ if( !initialized ) {
+ initialized = true;
+ return walker.reduceInit();
+ }
+ else
+ return accumulator;
+ }
+
+ /**
+ * The result of the accumulator in a non-intervals walker
+ * already takes the accumulation into account. return the result.
+ */
+ public void accumulate( ShardDataProvider provider, Object result ) { this.accumulator = result; }
+
+ /**
+ * The result of the traversal is the list of accumulated intervals.
+ */
+ public Object finishTraversal() {
+ walker.onTraversalDone(getReduceInit()); // must call getReduceInit to ensure that we get the accumulator value or the reduceInit value
+ return this.accumulator;
+ }
+ }
+
+ /**
+ * An interval-based accumulator. Treats each reduce result independently,
+ * and aggregates those results into a single list.
+ */
+ private static class IntervalAccumulator extends Accumulator {
+ /**
+ * True if a new interval is being started. This flag is used to
+ * ensure that reduceInit() is not called unnecessarily.
+ */
+ private boolean startingNewInterval = true;
+
+ /**
+ * An iterator through all intervals in the series.
+ */
+ private final Iterator<GenomeLoc> intervalIterator;
+
+ /**
+ * For which interval is the accumulator currently accumulating?
+ */
+ private GenomeLoc currentInterval = null;
+
+ /**
+ * The actual mapping of interval to accumulator.
+ */
+ private final List<Pair<GenomeLoc,Object>> intervalAccumulator = new ArrayList<Pair<GenomeLoc,Object>>();
+
+ /**
+ * Holds the next value to be passed in as the reduce result.
+ */
+ private Object nextReduceInit = null;
+
+ protected IntervalAccumulator(Walker walker, GenomeLocSortedSet intervals) {
+ super(walker);
+ this.intervalIterator = intervals.iterator();
+ if(intervalIterator.hasNext()) currentInterval = intervalIterator.next();
+ }
+
+ /**
+ * Interval accumulator always feeds reduceInit into every new traversal.
+ */
+ public Object getReduceInit() {
+ if(startingNewInterval) {
+ startingNewInterval = false;
+ nextReduceInit = walker.reduceInit();
+ }
+ return nextReduceInit;
+ }
+
+ /**
+ * Create a holder for interval results if none exists. Add the result to the holder.
+ */
+ public void accumulate( ShardDataProvider provider, Object result ) {
+ if(!(provider instanceof LocusShardDataProvider))
+ throw new ReviewedGATKException("Unable to reduce by interval on reads traversals at this time.");
+
+ GenomeLoc location = ((LocusShardDataProvider)provider).getLocus();
+
+ // Pull the interval iterator ahead to the interval overlapping this shard fragment.
+ while((currentInterval == null || currentInterval.isBefore(location)) && intervalIterator.hasNext())
+ currentInterval = intervalIterator.next();
+
+ if(currentInterval != null && currentInterval.getContig().equals(location.getContig()) && currentInterval.getStop() == location.getStop()) {
+ intervalAccumulator.add(new Pair<GenomeLoc,Object>(currentInterval,result));
+ startingNewInterval = true;
+ }
+ else
+ nextReduceInit = result;
+ }
+
+ /**
+ * The result of the traversal is the list of accumulated intervals.
+ */
+ public Object finishTraversal() {
+ walker.onTraversalDone(intervalAccumulator);
+ return intervalAccumulator;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/HierarchicalMicroScheduler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/HierarchicalMicroScheduler.java
new file mode 100644
index 0000000..f7e3dbc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/HierarchicalMicroScheduler.java
@@ -0,0 +1,495 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.tribble.TribbleException;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMDataSource;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.io.OutputTracker;
+import org.broadinstitute.gatk.engine.io.ThreadGroupOutputTracker;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.MultiThreadedErrorTracker;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.threading.ThreadPoolMonitor;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.concurrent.*;
+
+/**
+ * A microscheduler that schedules shards according to a tree-like structure.
+ * Requires a special walker tagged with a 'TreeReducible' interface.
+ */
+public class HierarchicalMicroScheduler extends MicroScheduler implements HierarchicalMicroSchedulerMBean, ReduceTree.TreeReduceNotifier {
+ /**
+ * How many outstanding output merges are allowed before the scheduler stops
+ * allowing new processes and starts merging flat-out.
+ */
+ private static final int MAX_OUTSTANDING_OUTPUT_MERGES = 50;
+
+ /** Manage currently running threads. */
+ private ExecutorService threadPool;
+
+ /**
+ * A thread local output tracker for managing output per-thread.
+ */
+ private ThreadGroupOutputTracker outputTracker = new ThreadGroupOutputTracker();
+
+ private final Queue<TreeReduceTask> reduceTasks = new LinkedList<TreeReduceTask>();
+
+ /**
+ * An exception that's occurred in this traversal. If null, no exception has occurred.
+ */
+ final MultiThreadedErrorTracker errorTracker = new MultiThreadedErrorTracker();
+
+ /**
+ * Queue of incoming shards.
+ */
+ private Iterator<Shard> traversalTasks;
+
+ /**
+ * Keep a queue of shard traversals, and constantly monitor it to see what output
+ * merge tasks remain.
+ * TODO: Integrate this into the reduce tree.
+ */
+ private final Queue<ShardTraverser> outputMergeTasks = new LinkedList<ShardTraverser>();
+
+ /** How many shard traversals have run to date? */
+ private int totalCompletedTraversals = 0;
+
+ /** What is the total time spent traversing shards? */
+ private long totalShardTraverseTime = 0;
+
+ /** What is the total time spent tree reducing shard output? */
+ private long totalTreeReduceTime = 0;
+
+ /** How many tree reduces have been completed? */
+ private long totalCompletedTreeReduces = 0;
+
+ /** What is the total time spent merging output? */
+ private long totalOutputMergeTime = 0;
+
+ /**
+ * Create a new hierarchical microscheduler to process the given reads and reference.
+ *
+ * @param walker the walker used to process the dataset.
+ * @param reads Reads file(s) to process.
+ * @param reference Reference for driving the traversal.
+ * @param threadAllocation How should we apply multi-threaded execution?
+ */
+ protected HierarchicalMicroScheduler(final GenomeAnalysisEngine engine,
+ final Walker walker,
+ final SAMDataSource reads,
+ final IndexedFastaSequenceFile reference,
+ final Collection<ReferenceOrderedDataSource> rods,
+ final ThreadAllocation threadAllocation) {
+ super(engine, walker, reads, reference, rods, threadAllocation);
+
+ final int nThreadsToUse = threadAllocation.getNumDataThreads();
+ if ( threadAllocation.monitorThreadEfficiency() ) {
+ throw new UserException.BadArgumentValue("nt", "Cannot monitor thread efficiency with -nt, sorry");
+ }
+
+ this.threadPool = Executors.newFixedThreadPool(nThreadsToUse, new UniqueThreadGroupThreadFactory());
+ }
+
+ /**
+ * Creates threads for HMS each with a unique thread group. Critical to
+ * track outputs via the ThreadGroupOutputTracker.
+ */
+ private static class UniqueThreadGroupThreadFactory implements ThreadFactory {
+ int counter = 0;
+
+ @Override
+ public Thread newThread(Runnable r) {
+ final ThreadGroup group = new ThreadGroup("HMS-group-" + counter++);
+ return new Thread(group, r);
+ }
+ }
+
+ public Object execute( Walker walker, Iterable<Shard> shardStrategy ) {
+ super.startingExecution();
+
+ // Fast fail for walkers not supporting TreeReducible interface.
+ if (!( walker instanceof TreeReducible ))
+ throw new IllegalArgumentException("The GATK can currently run in parallel only with TreeReducible walkers");
+
+ this.traversalTasks = shardStrategy.iterator();
+
+ final ReduceTree reduceTree = new ReduceTree(this);
+ initializeWalker(walker);
+
+ while (! abortExecution() && (isShardTraversePending() || isTreeReducePending())) {
+ // Check for errors during execution.
+ errorTracker.throwErrorIfPending();
+
+ // Too many files sitting around taking up space? Merge them.
+ if (isMergeLimitExceeded())
+ mergeExistingOutput(false);
+
+ // Wait for the next slot in the queue to become free.
+ waitForFreeQueueSlot();
+
+ // Pick the next most appropriate task and run it. In the interest of
+ // memory conservation, hierarchical reduces always run before traversals.
+ if (isTreeReduceReady())
+ queueNextTreeReduce(walker);
+ else if (isShardTraversePending())
+ queueNextShardTraverse(walker, reduceTree);
+ }
+
+ errorTracker.throwErrorIfPending();
+
+ threadPool.shutdown();
+
+ // Merge any lingering output files. If these files aren't ready,
+ // sit around and wait for them, then merge them.
+ mergeExistingOutput(true);
+
+ Object result = null;
+ try {
+ result = reduceTree.getResult().get();
+ notifyTraversalDone(walker,result);
+ } catch (ReviewedGATKException ex) {
+ throw ex;
+ } catch ( ExecutionException ex ) {
+ // the thread died and we are failing to get the result, rethrow it as a runtime exception
+ throw notifyOfTraversalError(ex.getCause());
+ } catch (Exception ex) {
+ throw new ReviewedGATKException("Unable to retrieve result", ex);
+ }
+
+ // do final cleanup operations
+ outputTracker.close();
+ cleanup();
+ executionIsDone();
+
+ return result;
+ }
+
+ /**
+ * Run the initialize method of the walker. Ensure that any calls
+ * to the output stream will bypass thread local storage and write
+ * directly to the output file.
+ * @param walker Walker to initialize.
+ */
+ protected void initializeWalker(Walker walker) {
+ outputTracker.bypassThreadLocalStorage(true);
+ try {
+ walker.initialize();
+ }
+ finally {
+ outputTracker.bypassThreadLocalStorage(false);
+ }
+ }
+
+ /**
+ * Run the initialize method of the walker. Ensure that any calls
+ * to the output stream will bypass thread local storage and write
+ * directly to the output file.
+ * @param walker Walker to initialize.
+ */
+ protected void notifyTraversalDone(Walker walker, Object result) {
+ outputTracker.bypassThreadLocalStorage(true);
+ try {
+ walker.onTraversalDone(result);
+ }
+ finally {
+ outputTracker.bypassThreadLocalStorage(false);
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public OutputTracker getOutputTracker() {
+ return outputTracker;
+ }
+
+ /**
+ * Returns true if there are unscheduled shard traversal waiting to run.
+ *
+ * @return true if a shard traversal is waiting; false otherwise.
+ */
+ protected boolean isShardTraversePending() {
+ return traversalTasks.hasNext();
+ }
+
+ /**
+ * Returns true if there are tree reduces that can be run without
+ * blocking.
+ *
+ * @return true if a tree reduce is ready; false otherwise.
+ */
+ protected boolean isTreeReduceReady() {
+ if (reduceTasks.size() == 0)
+ return false;
+ return reduceTasks.peek().isReadyForReduce();
+ }
+
+ /**
+ * Returns true if there are tree reduces that need to be run before
+ * the computation is complete. Returns true if any entries are in the queue,
+ * blocked or otherwise.
+ *
+ * @return true if a tree reduce is pending; false otherwise.
+ */
+ protected boolean isTreeReducePending() {
+ return reduceTasks.size() > 0;
+ }
+
+ /**
+ * Returns whether the maximum number of files is sitting in the temp directory
+ * waiting to be merged back in.
+ *
+ * @return True if the merging needs to take priority. False otherwise.
+ */
+ protected boolean isMergeLimitExceeded() {
+ int pendingTasks = 0;
+ for( ShardTraverser shardTraverse: outputMergeTasks ) {
+ if( !shardTraverse.isComplete() )
+ break;
+ pendingTasks++;
+ }
+ return (outputMergeTasks.size() >= MAX_OUTSTANDING_OUTPUT_MERGES);
+ }
+
+ /**
+ * Merging all output that's sitting ready in the OutputMerger queue into
+ * the final data streams.
+ */
+ protected void mergeExistingOutput( boolean wait ) {
+ long startTime = System.currentTimeMillis();
+
+// logger.warn("MergingExistingOutput");
+// printOutputMergeTasks();
+
+ // Create a list of the merge tasks that will be performed in this run of the mergeExistingOutput().
+ Queue<ShardTraverser> mergeTasksInSession = new LinkedList<ShardTraverser>();
+ while( !outputMergeTasks.isEmpty() ) {
+ ShardTraverser traverser = outputMergeTasks.peek();
+
+ // If the next traversal isn't done and we're not supposed to wait, we've found our working set. Continue.
+ if( !traverser.isComplete() && !wait )
+ break;
+
+ outputMergeTasks.remove();
+ mergeTasksInSession.add(traverser);
+ }
+
+// logger.warn("Selected things to merge:");
+// printOutputMergeTasks(mergeTasksInSession);
+
+ // Actually run through, merging the tasks in the working queue.
+ for( ShardTraverser traverser: mergeTasksInSession ) {
+ //logger.warn("*** Merging " + traverser.getIntervalsString());
+ if( !traverser.isComplete() )
+ traverser.waitForComplete();
+
+ OutputMergeTask mergeTask = traverser.getOutputMergeTask();
+ if( mergeTask != null ) {
+ try {
+ mergeTask.merge();
+ }
+ catch(TribbleException ex) {
+ // Specifically catch Tribble I/O exceptions and rethrow them as Reviewed. We don't expect
+ // any issues here because we created the Tribble output file mere moments ago and expect it to
+ // be completely valid.
+ throw new ReviewedGATKException("Unable to merge temporary Tribble output file.",ex);
+ }
+ }
+ }
+
+ long endTime = System.currentTimeMillis();
+
+ totalOutputMergeTime += ( endTime - startTime );
+ }
+
+ /**
+ * Queues the next traversal of a walker from the traversal tasks queue.
+ *
+ * @param walker Walker to apply to the dataset.
+ * @param reduceTree Tree of reduces to which to add this shard traverse.
+ */
+ protected void queueNextShardTraverse( Walker walker, ReduceTree reduceTree ) {
+ if (!traversalTasks.hasNext())
+ throw new IllegalStateException("Cannot traverse; no pending traversals exist.");
+
+ final Shard shard = traversalTasks.next();
+
+ // todo -- add ownership claim here
+
+ final ShardTraverser traverser = new ShardTraverser(this, walker, shard, outputTracker);
+
+ final Future traverseResult = threadPool.submit(traverser);
+
+ // Add this traverse result to the reduce tree. The reduce tree will call a callback to throw its entries on the queue.
+ reduceTree.addEntry(traverseResult);
+ outputMergeTasks.add(traverser);
+
+// logger.warn("adding merge task");
+// printOutputMergeTasks();
+
+ // No more data? Let the reduce tree know so it can finish processing what it's got.
+ if (!isShardTraversePending())
+ reduceTree.complete();
+ }
+
+ private synchronized void printOutputMergeTasks() {
+ printOutputMergeTasks(outputMergeTasks);
+ }
+
+ private synchronized void printOutputMergeTasks(final Queue<ShardTraverser> tasks) {
+ logger.info("Output merge tasks " + tasks.size());
+ for ( final ShardTraverser traverser : tasks )
+ logger.info(String.format("\t%s: complete? %b", traverser.getIntervalsString(), traverser.isComplete()));
+ }
+
+ /** Pulls the next reduce from the queue and runs it. */
+ protected void queueNextTreeReduce( Walker walker ) {
+ if (reduceTasks.size() == 0)
+ throw new IllegalStateException("Cannot reduce; no pending reduces exist.");
+ final TreeReduceTask reducer = reduceTasks.remove();
+ reducer.setWalker((TreeReducible) walker);
+
+ threadPool.submit(reducer);
+ }
+
+ /** Blocks until a free slot appears in the thread queue. */
+ protected void waitForFreeQueueSlot() {
+ final ThreadPoolMonitor monitor = new ThreadPoolMonitor();
+ synchronized (monitor) {
+ threadPool.submit(monitor);
+ monitor.watch();
+ }
+ }
+
+ /**
+ * Callback for adding reduce tasks to the run queue.
+ *
+ * @return A new, composite future of the result of this reduce.
+ */
+ public Future notifyReduce( final Future lhs, final Future rhs ) {
+ final TreeReduceTask reducer = new TreeReduceTask(new TreeReducer(this, lhs, rhs));
+ reduceTasks.add(reducer);
+ return reducer;
+ }
+
+ /**
+ * Allows other threads to notify of an error during traversal.
+ */
+ protected synchronized RuntimeException notifyOfTraversalError(Throwable error) {
+ return errorTracker.notifyOfError(error);
+ }
+
+ /** A small wrapper class that provides the TreeReducer interface along with the FutureTask semantics. */
+ private class TreeReduceTask extends FutureTask {
+ final private TreeReducer treeReducer;
+
+ public TreeReduceTask( TreeReducer treeReducer ) {
+ super(treeReducer);
+ this.treeReducer = treeReducer;
+ }
+
+ public void setWalker( TreeReducible walker ) {
+ treeReducer.setWalker(walker);
+ }
+
+ public boolean isReadyForReduce() {
+ return treeReducer.isReadyForReduce();
+ }
+ }
+
+ /**
+ * Used by the ShardTraverser to report time consumed traversing a given shard.
+ *
+ * @param shardTraversalTime Elapsed time traversing a given shard.
+ */
+ synchronized void reportShardTraverseTime( long shardTraversalTime ) {
+ totalShardTraverseTime += shardTraversalTime;
+ totalCompletedTraversals++;
+ }
+
+ /**
+ * Used by the TreeReducer to report time consumed reducing two shards.
+ *
+ * @param treeReduceTime Elapsed time reducing two shards.
+ */
+ synchronized void reportTreeReduceTime( long treeReduceTime ) {
+ totalTreeReduceTime += treeReduceTime;
+ totalCompletedTreeReduces++;
+
+ }
+
+ /** {@inheritDoc} */
+ public int getNumberOfTasksInReduceQueue() {
+ return reduceTasks.size();
+ }
+
+ /** {@inheritDoc} */
+ public int getNumberOfTasksInIOQueue() {
+ synchronized( outputMergeTasks ) {
+ return outputMergeTasks.size();
+ }
+ }
+
+ /** {@inheritDoc} */
+ public long getTotalShardTraverseTimeMillis() {
+ return totalShardTraverseTime;
+ }
+
+ /** {@inheritDoc} */
+ public long getAvgShardTraverseTimeMillis() {
+ if (totalCompletedTraversals == 0)
+ return 0;
+ return totalShardTraverseTime / totalCompletedTraversals;
+ }
+
+ /** {@inheritDoc} */
+ public long getTotalTreeReduceTimeMillis() {
+ return totalTreeReduceTime;
+ }
+
+ /** {@inheritDoc} */
+ public long getAvgTreeReduceTimeMillis() {
+ if (totalCompletedTreeReduces == 0)
+ return 0;
+ return totalTreeReduceTime / totalCompletedTreeReduces;
+ }
+
+ /** {@inheritDoc} */
+ public long getTotalOutputMergeTimeMillis() {
+ return totalOutputMergeTime;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/HierarchicalMicroSchedulerMBean.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/HierarchicalMicroSchedulerMBean.java
new file mode 100644
index 0000000..30e03c6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/HierarchicalMicroSchedulerMBean.java
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+/**
+ * User: hanna
+ * Date: May 29, 2009
+ * Time: 4:05:27 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * An interface for retrieving runtime statistics about how the hierarchical
+ * microscheduler is behaving.
+ */
+public interface HierarchicalMicroSchedulerMBean {
+ /**
+ * How many tree reduces are waiting in the tree reduce queue?
+ * @return Total number of reduces waiting in the tree reduce queue?
+ */
+ public int getNumberOfTasksInReduceQueue();
+
+ /**
+ * How many pending I/O combining tasks are waiting in the queue?
+ * @return Total number of I/O tasks waiting in the I/O queue.
+ */
+ public int getNumberOfTasksInIOQueue();
+
+ /**
+ * What is the total time spent running traversals?
+ * @return Total time spent traversing shards; 0 if none have been traversed.
+ */
+ public long getTotalShardTraverseTimeMillis();
+
+ /**
+ * What is the average time spent running traversals?
+ * @return Average time spent traversing shards; 0 if none have been traversed.
+ */
+ public long getAvgShardTraverseTimeMillis();
+
+ /**
+ * What is the total time spent merging output?
+ */
+ public long getTotalOutputMergeTimeMillis();
+
+ /**
+ * What is the total time spent running tree reduces?
+ * @return Total time spent running tree reduces; 0 if none have been run.
+ */
+ public long getTotalTreeReduceTimeMillis();
+
+ /**
+ * What is the average time spent running tree reduces?
+ * @return Average time spent running tree reduces; 0 if none have been run.
+ */
+ public long getAvgTreeReduceTimeMillis();
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/LinearMicroScheduler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/LinearMicroScheduler.java
new file mode 100644
index 0000000..293bb1c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/LinearMicroScheduler.java
@@ -0,0 +1,130 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.datasources.providers.LocusShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.providers.ReadShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.providers.ShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMDataSource;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.io.DirectOutputTracker;
+import org.broadinstitute.gatk.engine.io.OutputTracker;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.engine.traversals.TraversalEngine;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.threading.ThreadEfficiencyMonitor;
+
+import java.util.Collection;
+
+
+/** A micro-scheduling manager for single-threaded execution of a traversal. */
+public class LinearMicroScheduler extends MicroScheduler {
+
+ /**
+ * A direct output tracker for directly managing output.
+ */
+ private DirectOutputTracker outputTracker = new DirectOutputTracker();
+
+ /**
+ * Create a new linear microscheduler to process the given reads and reference.
+ *
+ * @param walker Walker for the traversal.
+ * @param reads Reads file(s) to process.
+ * @param reference Reference for driving the traversal.
+ * @param rods Reference-ordered data.
+ */
+ protected LinearMicroScheduler(final GenomeAnalysisEngine engine,
+ final Walker walker,
+ final SAMDataSource reads,
+ final IndexedFastaSequenceFile reference,
+ final Collection<ReferenceOrderedDataSource> rods,
+ final ThreadAllocation threadAllocation) {
+ super(engine, walker, reads, reference, rods, threadAllocation);
+
+ if ( threadAllocation.monitorThreadEfficiency() )
+ setThreadEfficiencyMonitor(new ThreadEfficiencyMonitor());
+ }
+
+ /**
+ * Run this traversal over the specified subsection of the dataset.
+ *
+ * @param walker Computation to perform over dataset.
+ * @param shardStrategy A strategy for sharding the data.
+ */
+ public Object execute(Walker walker, Iterable<Shard> shardStrategy) {
+ super.startingExecution();
+ walker.initialize();
+ Accumulator accumulator = Accumulator.create(engine,walker);
+
+ boolean done = walker.isDone();
+ int counter = 0;
+
+ final TraversalEngine traversalEngine = borrowTraversalEngine(this);
+ for (Shard shard : shardStrategy ) {
+ if ( abortExecution() || done || shard == null ) // we ran out of shards that aren't owned
+ break;
+
+ if(shard.getShardType() == Shard.ShardType.LOCUS) {
+ WindowMaker windowMaker = new WindowMaker(shard, engine.getGenomeLocParser(),
+ getReadIterator(shard), shard.getGenomeLocs(), SampleUtils.getSAMFileSamples(engine));
+ for(WindowMaker.WindowMakerIterator iterator: windowMaker) {
+ ShardDataProvider dataProvider = new LocusShardDataProvider(shard,iterator.getSourceInfo(),engine.getGenomeLocParser(),iterator.getLocus(),iterator,reference,rods);
+ Object result = traversalEngine.traverse(walker, dataProvider, accumulator.getReduceInit());
+ accumulator.accumulate(dataProvider,result);
+ dataProvider.close();
+ if ( walker.isDone() ) break;
+ }
+ windowMaker.close();
+ }
+ else {
+ ShardDataProvider dataProvider = new ReadShardDataProvider(shard,engine.getGenomeLocParser(),getReadIterator(shard),reference,rods);
+ Object result = traversalEngine.traverse(walker, dataProvider, accumulator.getReduceInit());
+ accumulator.accumulate(dataProvider,result);
+ dataProvider.close();
+ }
+
+ done = walker.isDone();
+ }
+
+ Object result = accumulator.finishTraversal();
+
+ outputTracker.close();
+ returnTraversalEngine(this, traversalEngine);
+ cleanup();
+ executionIsDone();
+
+ return accumulator;
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public OutputTracker getOutputTracker() { return outputTracker; }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/MicroScheduler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/MicroScheduler.java
new file mode 100644
index 0000000..e192b9a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/MicroScheduler.java
@@ -0,0 +1,463 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+
+import com.google.java.contract.Ensures;
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.ReadMetrics;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMDataSource;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.io.OutputTracker;
+import org.broadinstitute.gatk.engine.iterators.NullSAMIterator;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.engine.traversals.*;
+import org.broadinstitute.gatk.engine.walkers.*;
+import org.broadinstitute.gatk.utils.AutoFormattingTime;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.progressmeter.ProgressMeter;
+import org.broadinstitute.gatk.utils.threading.ThreadEfficiencyMonitor;
+
+import javax.management.JMException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import java.io.File;
+import java.lang.management.ManagementFactory;
+import java.util.*;
+
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mhanna
+ * Date: Apr 26, 2009
+ * Time: 12:37:23 PM
+ *
+ * General base class for all scheduling algorithms
+ * Shards and schedules data in manageable chunks.
+ *
+ * Creates N TraversalEngines for each data thread for the MicroScheduler. This is necessary
+ * because in the HMS case you have multiple threads executing a traversal engine independently, and
+ * these engines may need to create separate resources for efficiency or implementation reasons. For example,
+ * the nanoScheduler creates threads to implement the traversal, and this creation is instance specific.
+ * So each HMS thread needs to have it's own distinct copy of the traversal engine if it wants to have
+ * N data threads x M nano threads => N * M threads total. These are borrowed from this microscheduler
+ * and returned when done. Also allows us to tracks all created traversal engines so this microscheduler
+ * can properly shut them all down when the scheduling is done.
+ *
+ */
+public abstract class MicroScheduler implements MicroSchedulerMBean {
+ protected static final Logger logger = Logger.getLogger(MicroScheduler.class);
+
+ /**
+ * The list of all Traversal engines we've created in this micro scheduler
+ */
+ final List<TraversalEngine> allCreatedTraversalEngines = new LinkedList<TraversalEngine>();
+
+ /**
+ * All available engines. Engines are borrowed and returned when a subclass is actually
+ * going to execute the engine on some data. This allows us to have N copies for
+ * N data parallel executions, but without the dangerous code of having local
+ * ThreadLocal variables.
+ */
+ final LinkedList<TraversalEngine> availableTraversalEngines = new LinkedList<TraversalEngine>();
+
+ /**
+ * Engines that have been allocated to a key already.
+ */
+ final HashMap<Object, TraversalEngine> allocatedTraversalEngines = new HashMap<Object, TraversalEngine>();
+
+ /**
+ * Counts the number of instances of the class that are currently alive.
+ */
+ private static int instanceNumber = 0;
+
+ /**
+ * The engine invoking this scheduler.
+ */
+ protected final GenomeAnalysisEngine engine;
+
+ protected final IndexedFastaSequenceFile reference;
+
+ private final SAMDataSource reads;
+ protected final Collection<ReferenceOrderedDataSource> rods;
+
+ private final MBeanServer mBeanServer;
+ private final ObjectName mBeanName;
+
+ /**
+ * Threading efficiency monitor for tracking the resource utilization of the GATK
+ *
+ * may be null
+ */
+ ThreadEfficiencyMonitor threadEfficiencyMonitor = null;
+
+ /**
+ * MicroScheduler factory function. Create a microscheduler appropriate for reducing the
+ * selected walker.
+ *
+ * @param walker Which walker to use.
+ * @param reads the informations associated with the reads
+ * @param reference the reference file
+ * @param rods the rods to include in the traversal
+ * @param threadAllocation Number of threads to utilize.
+ *
+ * @return The best-fit microscheduler.
+ */
+ public static MicroScheduler create(GenomeAnalysisEngine engine, Walker walker, SAMDataSource reads, IndexedFastaSequenceFile reference, Collection<ReferenceOrderedDataSource> rods, ThreadAllocation threadAllocation) {
+ if ( threadAllocation.isRunningInParallelMode() ) {
+ logger.info(String.format("Running the GATK in parallel mode with %d total threads, " +
+ "%d CPU thread(s) for each of %d data thread(s), of %d processors available on this machine",
+ threadAllocation.getTotalNumThreads(),
+ threadAllocation.getNumCPUThreadsPerDataThread(),
+ threadAllocation.getNumDataThreads(),
+ Runtime.getRuntime().availableProcessors()));
+ if ( threadAllocation.getTotalNumThreads() > Runtime.getRuntime().availableProcessors() )
+ logger.warn(String.format("Number of requested GATK threads %d is more than the number of " +
+ "available processors on this machine %d", threadAllocation.getTotalNumThreads(),
+ Runtime.getRuntime().availableProcessors()));
+ }
+
+ if ( threadAllocation.getNumDataThreads() > 1 ) {
+ if (walker.isReduceByInterval())
+ throw new UserException.BadArgumentValue("nt", String.format("This run of %s is set up to aggregate results by interval. Due to a current limitation of the GATK, analyses of this type do not currently support parallel execution. Please run your analysis without the -nt option or check if this tool has an option to disable per-interval calculations.", engine.getWalkerName(walker.getClass())));
+
+ if ( ! (walker instanceof TreeReducible) ) {
+ throw badNT("nt", engine, walker);
+ }
+ }
+
+ if ( threadAllocation.getNumCPUThreadsPerDataThread() > 1 && ! (walker instanceof NanoSchedulable) ) {
+ throw badNT("nct", engine, walker);
+ }
+
+ if ( threadAllocation.getNumDataThreads() > 1 ) {
+ return new HierarchicalMicroScheduler(engine, walker, reads, reference, rods, threadAllocation);
+ } else {
+ return new LinearMicroScheduler(engine, walker, reads, reference, rods, threadAllocation);
+ }
+ }
+
+ private static UserException badNT(final String parallelArg, final GenomeAnalysisEngine engine, final Walker walker) {
+ throw new UserException.BadArgumentValue(parallelArg,
+ String.format("The analysis %s currently does not support parallel execution with %s. " +
+ "Please run your analysis without the %s option.", engine.getWalkerName(walker.getClass()), parallelArg, parallelArg));
+ }
+
+ /**
+ * Create a microscheduler given the reads and reference.
+ *
+ * @param walker the walker to execute with
+ * @param reads The reads.
+ * @param reference The reference.
+ * @param rods the rods to include in the traversal
+ * @param threadAllocation the allocation of threads to use in the underlying traversal
+ */
+ protected MicroScheduler(final GenomeAnalysisEngine engine,
+ final Walker walker,
+ final SAMDataSource reads,
+ final IndexedFastaSequenceFile reference,
+ final Collection<ReferenceOrderedDataSource> rods,
+ final ThreadAllocation threadAllocation) {
+ this.engine = engine;
+ this.reads = reads;
+ this.reference = reference;
+ this.rods = rods;
+
+ final File progressLogFile = engine.getArguments() == null ? null : engine.getArguments().performanceLog;
+
+ // Creates uninitialized TraversalEngines appropriate for walker and threadAllocation,
+ // and adds it to the list of created engines for later shutdown.
+ for ( int i = 0; i < threadAllocation.getNumDataThreads(); i++ ) {
+ final TraversalEngine traversalEngine = createTraversalEngine(walker, threadAllocation);
+ allCreatedTraversalEngines.add(traversalEngine);
+ availableTraversalEngines.add(traversalEngine);
+ }
+
+ // Create the progress meter, and register it with the analysis engine
+ engine.registerProgressMeter(new ProgressMeter(progressLogFile,
+ availableTraversalEngines.peek().getTraversalUnits(),
+ engine.getRegionsOfGenomeBeingProcessed()));
+
+ // Now that we have a progress meter, go through and initialize the traversal engines
+ for ( final TraversalEngine traversalEngine : allCreatedTraversalEngines )
+ traversalEngine.initialize(engine, walker, engine.getProgressMeter());
+
+ // JMX does not allow multiple instances with the same ObjectName to be registered with the same platform MXBean.
+ // To get around this limitation and since we have no job identifier at this point, register a simple counter that
+ // will count the number of instances of this object that have been created in this JVM.
+ int thisInstance = instanceNumber++;
+ mBeanServer = ManagementFactory.getPlatformMBeanServer();
+ try {
+ mBeanName = new ObjectName("org.broadinstitute.gatk.engine.executive:type=MicroScheduler,instanceNumber="+thisInstance);
+ mBeanServer.registerMBean(this, mBeanName);
+ }
+ catch (JMException ex) {
+ throw new ReviewedGATKException("Unable to register microscheduler with JMX", ex);
+ }
+ }
+
+ /**
+ * Really make us a traversal engine of the appropriate type for walker and thread allocation
+ *
+ * @return a non-null uninitialized traversal engine
+ */
+ @Ensures("result != null")
+ private TraversalEngine createTraversalEngine(final Walker walker, final ThreadAllocation threadAllocation) {
+ if (walker instanceof ReadWalker) {
+ return new TraverseReadsNano(threadAllocation.getNumCPUThreadsPerDataThread());
+ } else if (walker instanceof LocusWalker) {
+ return new TraverseLociNano(threadAllocation.getNumCPUThreadsPerDataThread());
+ } else if (walker instanceof DuplicateWalker) {
+ return new TraverseDuplicates();
+ } else if (walker instanceof ReadPairWalker) {
+ return new TraverseReadPairs();
+ } else if (walker instanceof ActiveRegionWalker) {
+ return new TraverseActiveRegions(threadAllocation.getNumCPUThreadsPerDataThread());
+ } else {
+ throw new UnsupportedOperationException("Unable to determine traversal type, the walker is an unknown type.");
+ }
+ }
+
+
+ /**
+ * Return the ThreadEfficiencyMonitor we are using to track our resource utilization, if there is one
+ *
+ * @return the monitor, or null if none is active
+ */
+ public ThreadEfficiencyMonitor getThreadEfficiencyMonitor() {
+ return threadEfficiencyMonitor;
+ }
+
+ /**
+ * Inform this Microscheduler to use the efficiency monitor used to create threads in subclasses
+ *
+ * @param threadEfficiencyMonitor
+ */
+ public void setThreadEfficiencyMonitor(final ThreadEfficiencyMonitor threadEfficiencyMonitor) {
+ this.threadEfficiencyMonitor = threadEfficiencyMonitor;
+ }
+
+ /**
+ * Should we stop all execution work and exit gracefully?
+ *
+ * Returns true in the case where some external signal or time limit has been received, indicating
+ * that this GATK shouldn't continue executing. This isn't a kill signal, it is really a "shutdown
+ * gracefully at the next opportunity" signal. Concrete implementations of the MicroScheduler
+ * examine this value as often as reasonable and, if it returns true, stop what they are doing
+ * at the next available opportunity, shutdown their resources, call notify done, and return.
+ *
+ * @return true if we should abort execution, or false otherwise
+ */
+ protected boolean abortExecution() {
+ final boolean abort = engine.exceedsRuntimeLimit();
+ if ( abort ) {
+ final AutoFormattingTime aft = new AutoFormattingTime(engine.getRuntimeLimitInNanoseconds(), -1, 4);
+ logger.info("Aborting execution (cleanly) because the runtime has exceeded the requested maximum " + aft);
+ }
+ return abort;
+ }
+
+ /**
+ * Walks a walker over the given list of intervals.
+ *
+ * @param walker Computation to perform over dataset.
+ * @param shardStrategy A strategy for sharding the data.
+ *
+ * @return the return type of the walker
+ */
+ public abstract Object execute(Walker walker, Iterable<Shard> shardStrategy);
+
+ /**
+ * Tells this MicroScheduler that the execution of one of the subclass of this object as started
+ *
+ * Must be called when the implementation of execute actually starts up
+ *
+ * Currently only starts the progress meter timer running, but other start up activities could be incorporated
+ */
+ protected void startingExecution() {
+ engine.getProgressMeter().start();
+ }
+
+ /**
+ * Retrieves the object responsible for tracking and managing output.
+ * @return An output tracker, for loading data in and extracting results. Will not be null.
+ */
+ public abstract OutputTracker getOutputTracker();
+
+ /**
+ * Gets the an iterator over the given reads, which will iterate over the reads in the given shard.
+ * @param shard the shard to use when querying reads.
+ * @return an iterator over the reads specified in the shard.
+ */
+ protected GATKSAMIterator getReadIterator(Shard shard) {
+ return (!reads.isEmpty()) ? reads.seek(shard) : new NullSAMIterator();
+ }
+
+ /**
+ * Must be called by subclasses when execute is done
+ */
+ protected void executionIsDone() {
+ engine.getProgressMeter().notifyDone(engine.getCumulativeMetrics().getNumIterations());
+ printReadFilteringStats();
+ shutdownTraversalEngines();
+
+ // Print out the threading efficiency of this HMS, if state monitoring is enabled
+ if ( threadEfficiencyMonitor != null ) {
+ // include the master thread information
+ threadEfficiencyMonitor.threadIsDone(Thread.currentThread());
+ threadEfficiencyMonitor.printUsageInformation(logger);
+ }
+ }
+
+ /**
+ * Shutdown all of the created engines, and clear the list of created engines, dropping
+ * pointers to the traversal engines
+ */
+ public synchronized void shutdownTraversalEngines() {
+ for ( final TraversalEngine te : allCreatedTraversalEngines)
+ te.shutdown();
+
+ allCreatedTraversalEngines.clear();
+ availableTraversalEngines.clear();
+ }
+
+ /**
+ * Prints out information about number of reads observed and filtering, if any reads were used in the traversal
+ *
+ * Looks like:
+ *
+ * INFO 10:40:47,370 MicroScheduler - 22 reads were filtered out during traversal out of 101 total (21.78%)
+ * INFO 10:40:47,370 MicroScheduler - -> 1 reads (0.99% of total) failing BadMateFilter
+ * INFO 10:40:47,370 MicroScheduler - -> 20 reads (19.80% of total) failing DuplicateReadFilter
+ * INFO 10:40:47,370 MicroScheduler - -> 1 reads (0.99% of total) failing FailsVendorQualityCheckFilter
+ */
+ private void printReadFilteringStats() {
+ final ReadMetrics cumulativeMetrics = engine.getCumulativeMetrics();
+ if ( cumulativeMetrics.getNumReadsSeen() > 0 ) {
+ // count up the number of skipped reads by summing over all filters
+ long nSkippedReads = 0L;
+ for ( final long countsByFilter : cumulativeMetrics.getCountsByFilter().values())
+ nSkippedReads += countsByFilter;
+
+ logger.info(String.format("%d reads were filtered out during the traversal out of approximately %d total reads (%.2f%%)",
+ nSkippedReads,
+ cumulativeMetrics.getNumReadsSeen(),
+ 100.0 * MathUtils.ratio(nSkippedReads, cumulativeMetrics.getNumReadsSeen())));
+
+ for ( final Map.Entry<String, Long> filterCounts : cumulativeMetrics.getCountsByFilter().entrySet() ) {
+ long count = filterCounts.getValue();
+ logger.info(String.format(" -> %d reads (%.2f%% of total) failing %s",
+ count, 100.0 * MathUtils.ratio(count,cumulativeMetrics.getNumReadsSeen()), filterCounts.getKey()));
+ }
+ }
+ }
+
+ /**
+ * Gets the engine that created this microscheduler.
+ * @return The engine owning this microscheduler.
+ */
+ public GenomeAnalysisEngine getEngine() { return engine; }
+
+ /**
+ * Returns data source maintained by this scheduler
+ * @return
+ */
+ public SAMDataSource getSAMDataSource() { return reads; }
+
+ /**
+ * Returns the reference maintained by this scheduler.
+ * @return The reference maintained by this scheduler.
+ */
+ public IndexedFastaSequenceFile getReference() { return reference; }
+
+ protected void cleanup() {
+ try {
+ mBeanServer.unregisterMBean(mBeanName);
+ }
+ catch (JMException ex) {
+ throw new ReviewedGATKException("Unable to unregister microscheduler with JMX", ex);
+ }
+ }
+
+ /**
+ * Returns a traversal engine suitable for use, associated with key
+ *
+ * Key is an arbitrary object that is used to retrieve the same traversal
+ * engine over and over. This can be important in the case where the
+ * traversal engine has data associated with it in some other context,
+ * and we need to ensure that the context always sees the same traversal
+ * engine. This happens in the HierarchicalMicroScheduler, where you want
+ * the a thread executing traversals to retrieve the same engine each time,
+ * as outputs are tracked w.r.t. that engine.
+ *
+ * If no engine is associated with key yet, pops the next available engine
+ * from the available ones maintained by this
+ * microscheduler. Note that it's a runtime error to pop a traversal engine
+ * from this scheduler if there are none available. Callers that
+ * once pop'd an engine for use must return it with returnTraversalEngine
+ *
+ * @param key the key to associate with this engine
+ * @return a non-null TraversalEngine suitable for execution in this scheduler
+ */
+ @Ensures("result != null")
+ protected synchronized TraversalEngine borrowTraversalEngine(final Object key) {
+ if ( key == null ) throw new IllegalArgumentException("key cannot be null");
+
+ final TraversalEngine engine = allocatedTraversalEngines.get(key);
+ if ( engine == null ) {
+ if ( availableTraversalEngines.isEmpty() )
+ throw new IllegalStateException("no traversal engines were available");
+ allocatedTraversalEngines.put(key, availableTraversalEngines.pop());
+ return allocatedTraversalEngines.get(key);
+ } else {
+ return engine;
+ }
+ }
+
+ /**
+ * Return a borrowed traversal engine to this MicroScheduler, for later use
+ * in another traversal execution
+ *
+ * @param key the key used to id the engine, provided to the borrowTraversalEngine function
+ * @param traversalEngine the borrowed traversal engine. Must have been previously borrowed.
+ */
+ protected synchronized void returnTraversalEngine(final Object key, final TraversalEngine traversalEngine) {
+ if ( traversalEngine == null )
+ throw new IllegalArgumentException("Attempting to push a null traversal engine");
+ if ( ! allCreatedTraversalEngines.contains(traversalEngine) )
+ throw new IllegalArgumentException("Attempting to push a traversal engine not created by this MicroScheduler" + engine);
+ if ( ! allocatedTraversalEngines.containsKey(key) )
+ throw new IllegalArgumentException("No traversal engine was never checked out with key " + key);
+
+ // note there's nothing to actually do here, but a function implementation
+ // might want to do something
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/MicroSchedulerMBean.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/MicroSchedulerMBean.java
new file mode 100644
index 0000000..772fe01
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/MicroSchedulerMBean.java
@@ -0,0 +1,37 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mhanna
+ * Date: Jan 12, 2011
+ * Time: 9:19:27 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface MicroSchedulerMBean {
+ // has nothing because we don't have anything we currently track
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/OutputMergeTask.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/OutputMergeTask.java
new file mode 100644
index 0000000..4e5ef9f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/OutputMergeTask.java
@@ -0,0 +1,102 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+
+import org.broadinstitute.gatk.engine.io.storage.Storage;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * User: hanna
+ * Date: Apr 30, 2009
+ * Time: 4:04:38 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Hold pointers to the output and error streams, and state to indicate whether
+ * a write is complete. Not generally thread-safe. Calls to isComplete()/complete()
+ * can be made at any time from any thread, but complete() should be called on the
+ * thread which is doing the writing.
+ */
+public class OutputMergeTask {
+ /**
+ * The output streams which should be written to.
+ */
+ private final Collection<MergeOperation<?>> mergeOperations = new ArrayList<MergeOperation<?>>();
+
+ /**
+ * Add a new merge operation to this merge task.
+ * @param targetStream Target for stream output.
+ * @param temporaryStorage Temporary storage.
+ * @param <StreamType> Type of the output stream.
+ */
+ public <StreamType> void addMergeOperation( StreamType targetStream, Storage<StreamType> temporaryStorage ) {
+ mergeOperations.add( new MergeOperation<StreamType>(targetStream,temporaryStorage) );
+ }
+
+ /**
+ * Merge data from output streams into target storage.
+ */
+ public synchronized void merge() {
+ for( MergeOperation mergeOperation: mergeOperations )
+ mergeOperation.temporaryStorage.mergeInto(mergeOperation.targetStream);
+ }
+
+ /**
+ * Represents a single file needed to be merged.
+ * @param <StreamType> Type of the file to be merged.
+ */
+ private class MergeOperation<StreamType> {
+ /**
+ * Destination for the temporary file's output.
+ */
+ public final StreamType targetStream;
+
+ /**
+ * Temporary storage location for the file.
+ */
+ public final Storage<StreamType> temporaryStorage;
+
+ /**
+ * Create a new merge file object with the given output stream and storage placeholder.
+ * @param targetStream Target for temporary data.
+ * @param temporaryStorage The temporary data itself.
+ */
+ public MergeOperation( StreamType targetStream, Storage<StreamType> temporaryStorage ) {
+ this.targetStream = targetStream;
+ this.temporaryStorage = temporaryStorage;
+ }
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/ReduceTree.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/ReduceTree.java
new file mode 100644
index 0000000..e02b846
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/ReduceTree.java
@@ -0,0 +1,187 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.Future;
+/**
+ * User: hanna
+ * Date: Apr 28, 2009
+ * Time: 11:09:29 AM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * A tree for organizing reduce results and detecting when enough dependencies
+ * are resolved for a reduce to be scheduled. The tree can trigger a callback
+ * whenever it believes a reduce operation is pending.
+ *
+ * Not thread-safe. All calls should be made sequentially from the same thread.
+ */
+public class ReduceTree {
+ /**
+ * Data structure for the tree. Each entry in the outer list represents a level
+ * of the tree, and each entry in the inner queues represent nodes in that level.
+ *
+ * Whenever a reduce can happen, the entries to be reduced are pulled out of
+ * their slots in level n of the tree and the composite entry is added to level n+1.
+ */
+ private List<Queue<Future>> treeNodes = new ArrayList<Queue<Future>>();
+
+ /**
+ * The entire contents have been added to the tree. Completely schedule the reductions.
+ */
+ private boolean treeComplete = false;
+
+ /**
+ * Called to indicate that all data required to perform a given reduce has been scheduled.
+ */
+ private TreeReduceNotifier treeReduceNotifier = null;
+
+ /**
+ * Creates a ReduceTree.
+ * @param notifier A callback indicating that all data required to perform a given reduce has been scheduled.
+ */
+ public ReduceTree( TreeReduceNotifier notifier ) {
+ this.treeReduceNotifier = notifier;
+ }
+
+ /**
+ * A callback indicating that all computations have been scheduled to complete the given reduce.
+ */
+ public interface TreeReduceNotifier {
+ /**
+ * Indicates that a reduce is ready to happen.
+ * @param lhs Left-hand side of the tree reduce.
+ * @param rhs Right-hand side of the tree reduce.
+ * @return The future result of the computation reduce(lhs,rhs)
+ */
+ Future notifyReduce( Future lhs, Future rhs );
+ }
+
+ /**
+ * Add an entry to the list of data to be reduced. The results of entry.get() will
+ * be scheduled for reduction with neighboring elements.
+ * @param entry Entry to be paired with other elements.
+ */
+ public void addEntry( Future entry ) {
+ addNodeAtLevel( entry, 0 );
+ }
+
+ /**
+ * Signal to the ReduceTree that all possible data has been added and it should reduce
+ * as much as is possible.
+ */
+ public void complete() {
+ treeComplete = true;
+ reduce();
+ }
+
+ /**
+ * Gets the placeholder for the final result of the tree reduce.
+ * @return Future whose get() method will return the final result. Null if nothing has been added.
+ */
+ public Future getResult() {
+ if( !treeComplete )
+ throw new IllegalStateException( "Cannot get the final result for an incomplete tree.");
+
+ // If nothing has been added to the tree, return null.
+ if( treeNodes.size() == 0 )
+ return null;
+
+ // Assert that there aren't any pending computations that were forgotten along the way.
+ for( int i = 0; i < treeNodes.size() - 2; i++ ) {
+ if( treeNodes.get(i).size() > 0 )
+ throw new IllegalStateException( "Some inner reduces were missed along the way.");
+ }
+
+ Queue<Future> lastLevel = treeNodes.get(treeNodes.size() - 1);
+
+ // Assert that there's only one reduce left at the last level.
+ if( lastLevel.size() != 1 )
+ throw new IllegalStateException( "Invalid number of entries at the tip of the tree: " + lastLevel.size() );
+
+ // Get the placeholder for the last result.
+ return lastLevel.element();
+ }
+
+ /**
+ * Recursively collapse the tree whereever possible.
+ */
+ protected void reduce() {
+ reduce( 0 );
+ }
+
+ /**
+ * Recursively collapse the tree, starting at the specified level.
+ * @param level Level at which to start reducing.
+ */
+ private void reduce( int level ) {
+ // base case for recursion.
+ if( treeNodes.size() <= level )
+ return;
+
+ Queue<Future> treeLevel = treeNodes.get(level);
+
+ while( treeLevel.size() >= 2 ) {
+ addNodeAtLevel( treeReduceNotifier.notifyReduce( treeLevel.remove(), treeLevel.remove() ), level + 1 );
+ }
+
+ if( treeLevel.size() == 1 && treeComplete && !isDeepestLevel(level) ) {
+ Future element = treeLevel.remove();
+ addNodeAtLevel( element, level + 1 );
+ }
+
+ reduce( level + 1 );
+ }
+
+ private boolean isDeepestLevel( int level ) {
+ return level == (treeNodes.size() - 1);
+ }
+
+ /**
+ * Add the given node to the tree at the corresponding level. Create the level
+ * if it doesn't exist.
+ * @param node Node to add. Must not be null.
+ * @param level Level number at which to add. 0-based index into treeNodes list.
+ */
+ protected void addNodeAtLevel( Future node, int level ) {
+ while( treeNodes.size() <= level )
+ treeNodes.add( new LinkedList<Future>() );
+ treeNodes.get(level).add(node);
+ reduce(level);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/ShardTraverser.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/ShardTraverser.java
new file mode 100644
index 0000000..443fdf7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/ShardTraverser.java
@@ -0,0 +1,163 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.datasources.providers.LocusShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.providers.ShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.engine.io.ThreadGroupOutputTracker;
+import org.broadinstitute.gatk.engine.traversals.TraversalEngine;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.concurrent.Callable;
+/**
+ * User: hanna
+ * Date: Apr 29, 2009
+ * Time: 4:40:38 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+/**
+ * Carries the walker over a given shard, in a callable interface.
+ */
+public class ShardTraverser implements Callable {
+ final private HierarchicalMicroScheduler microScheduler;
+ final private Walker walker;
+ final private Shard shard;
+ final private ThreadGroupOutputTracker outputTracker;
+ private OutputMergeTask outputMergeTask;
+
+ /** our log, which we want to capture anything from this class */
+ final protected static Logger logger = Logger.getLogger(ShardTraverser.class);
+
+ /**
+ * Is this traversal complete?
+ */
+ private boolean complete = false;
+
+ public ShardTraverser( HierarchicalMicroScheduler microScheduler,
+ Walker walker,
+ Shard shard,
+ ThreadGroupOutputTracker outputTracker) {
+ this.microScheduler = microScheduler;
+ this.walker = walker;
+ this.shard = shard;
+ this.outputTracker = outputTracker;
+ }
+
+ public Object call() {
+ final Object traversalEngineKey = Thread.currentThread();
+ final TraversalEngine traversalEngine = microScheduler.borrowTraversalEngine(traversalEngineKey);
+
+ try {
+ final long startTime = System.currentTimeMillis();
+
+ // this is CRITICAL -- initializes output maps in this master thread,
+ // so that any subthreads created by the traversal itself can access this map
+ outputTracker.initializeStorage();
+
+ Object accumulator = walker.reduceInit();
+ final WindowMaker windowMaker = new WindowMaker(shard,microScheduler.getEngine().getGenomeLocParser(),
+ microScheduler.getReadIterator(shard),
+ shard.getGenomeLocs(),
+ microScheduler.engine.getSampleDB().getSampleNames()); // todo: microScheduler.engine is protected - is it okay to user it here?
+
+ for(WindowMaker.WindowMakerIterator iterator: windowMaker) {
+ final ShardDataProvider dataProvider = new LocusShardDataProvider(shard,iterator.getSourceInfo(),microScheduler.getEngine().getGenomeLocParser(),iterator.getLocus(),iterator,microScheduler.reference,microScheduler.rods);
+ accumulator = traversalEngine.traverse(walker, dataProvider, accumulator);
+ dataProvider.close();
+ }
+
+ windowMaker.close();
+ outputMergeTask = outputTracker.closeStorage();
+
+ final long endTime = System.currentTimeMillis();
+
+ microScheduler.reportShardTraverseTime(endTime-startTime);
+
+ return accumulator;
+ } catch(Throwable t) {
+ // Notify that an exception has occurred and rethrow it.
+ throw microScheduler.notifyOfTraversalError(t);
+ } finally {
+ synchronized(this) {
+ complete = true;
+ microScheduler.returnTraversalEngine(traversalEngineKey, traversalEngine);
+ notifyAll();
+ }
+ }
+ }
+
+ /**
+ * Return a human readable string describing the intervals this traverser is operating on
+ * @return
+ */
+ public String getIntervalsString() {
+ return Utils.join(",", shard.getGenomeLocs());
+ }
+
+ /**
+ * Has this traversal completed?
+ * @return True if completed, false otherwise.
+ */
+ public boolean isComplete() {
+ synchronized(this) {
+ return complete;
+ }
+ }
+
+ /**
+ * Waits for any the given OutputMerger to be ready for merging.
+ */
+ public void waitForComplete() {
+ try {
+ synchronized(this) {
+ if( isComplete() )
+ return;
+ wait();
+ }
+ }
+ catch( InterruptedException ex ) {
+ throw new ReviewedGATKException("Interrupted while waiting for more output to be finalized.",ex);
+ }
+ }
+
+ /**
+ * Gets the output merge task associated with the given shard.
+ * @return OutputMergeTask if one exists; null if nothing needs to be merged.
+ */
+ public OutputMergeTask getOutputMergeTask() {
+ return outputMergeTask;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/TreeReducer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/TreeReducer.java
new file mode 100644
index 0000000..270b06f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/TreeReducer.java
@@ -0,0 +1,127 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+/**
+ * User: hanna
+ * Date: Apr 29, 2009
+ * Time: 4:47:35 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Represents a future reduce...a reduce that will be ready at some point in the future.
+ * Provides services for indicating when all data is prepared for the reduce a callable
+ * interface to force the reduce.
+ */
+public class TreeReducer implements Callable {
+ final private HierarchicalMicroScheduler microScheduler;
+ private TreeReducible walker;
+ private Future lhs;
+ private Future rhs;
+
+ /**
+ * Create a full tree reduce. Combine this two results using an unspecified walker at some point in the future.
+ * @param microScheduler The parent hierarchical microscheduler for this reducer.
+ * @param lhs Left-hand side of the reduce.
+ * @param rhs Right-hand side of the reduce.
+ */
+ public TreeReducer( HierarchicalMicroScheduler microScheduler, Future lhs, Future rhs ) {
+ this.microScheduler = microScheduler;
+ this.lhs = lhs;
+ this.rhs = rhs;
+ }
+
+ /**
+ * Provide a walker for the future reduce.
+ * @param walker walker to use when performing the reduce.
+ */
+ public void setWalker( TreeReducible walker ) {
+ this.walker = walker;
+ }
+
+ /**
+ * Is the data ready for reduce? True if lhs and rhs have already been resolved.
+ * @return True if data is ready and waiting, false otherwise.
+ */
+ public boolean isReadyForReduce() {
+ if( lhs == null )
+ throw new IllegalStateException(String.format("Insufficient data on which to reduce; lhs = %s, rhs = %s", lhs, rhs) );
+
+ return lhs.isDone() && (rhs == null || rhs.isDone());
+ }
+
+ /**
+ * Returns the value of the reduce. If not isReadyForReduce(), this call will until all entries become ready.
+ * @return Result of the reduce.
+ */
+ public Object call() {
+ Object result;
+
+ final long startTime = System.currentTimeMillis();
+
+ try {
+ if( lhs == null )
+ result = null;
+ // todo -- what the hell is this above line? Shouldn't it be the two below?
+// if( lhs == null )
+// throw new IllegalStateException(String.format("Insufficient data on which to reduce; lhs = %s, rhs = %s", lhs, rhs) );
+ else
+ result = walker.treeReduce( lhs.get(), rhs.get() );
+ }
+ catch( InterruptedException ex ) {
+ microScheduler.notifyOfTraversalError(ex);
+ throw new ReviewedGATKException("Hierarchical reduce interrupted", ex);
+ }
+ catch( ExecutionException ex ) {
+ microScheduler.notifyOfTraversalError(ex);
+ throw new ReviewedGATKException("Hierarchical reduce failed", ex);
+ }
+
+ final long endTime = System.currentTimeMillis();
+
+ // Constituent bits of this tree reduces are no longer required. Throw them away.
+ this.lhs = null;
+ this.rhs = null;
+
+ microScheduler.reportTreeReduceTime( endTime - startTime );
+
+ return result;
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/WindowMaker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/WindowMaker.java
new file mode 100644
index 0000000..c848329
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/WindowMaker.java
@@ -0,0 +1,217 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+
+import htsjdk.samtools.util.PeekableIterator;
+import org.broadinstitute.gatk.engine.ReadProperties;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMRecordIterator;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.locusiterator.LocusIterator;
+import org.broadinstitute.gatk.utils.locusiterator.LocusIteratorByState;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Transforms an iterator of reads which overlap the given interval list into an iterator of covered single-base loci
+ * completely contained within the interval list. To do this, it creates a LocusIteratorByState which will emit a single-bp
+ * locus for every base covered by the read iterator, then uses the WindowMakerIterator.advance() to filter down that stream of
+ * loci to only those covered by the given interval list.
+ *
+ * Example:
+ * Incoming stream of reads: A:chr20:1-5, B:chr20:2-6, C:chr20:2-7, D:chr20:3-8, E:chr20:5-10
+ * Incoming intervals: chr20:3-7
+ *
+ * Locus iterator by state will produce the following stream of data:
+ * chr1:1 {A}, chr1:2 {A,B,C}, chr1:3 {A,B,C,D}, chr1:4 {A,B,C,D}, chr1:5 {A,B,C,D,E},
+ * chr1:6 {B,C,D,E}, chr1:7 {C,D,E}, chr1:8 {D,E}, chr1:9 {E}, chr1:10 {E}
+ *
+ * WindowMakerIterator will then filter the incoming stream, emitting the following stream:
+ * chr1:3 {A,B,C,D}, chr1:4 {A,B,C,D}, chr1:5 {A,B,C,D,E}, chr1:6 {B,C,D,E}, chr1:7 {C,D,E}
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class WindowMaker implements Iterable<WindowMaker.WindowMakerIterator>, Iterator<WindowMaker.WindowMakerIterator> {
+ /**
+ * Source information for iteration.
+ */
+ private final ReadProperties sourceInfo;
+
+ /**
+ * Hold the read iterator so that it can be closed later.
+ */
+ private final GATKSAMRecordIterator readIterator;
+
+ /**
+ * The data source for reads. Will probably come directly from the BAM file.
+ */
+ private final PeekableIterator<AlignmentContext> sourceIterator;
+
+ /**
+ * Stores the sequence of intervals that the windowmaker should be tracking.
+ */
+ private final PeekableIterator<GenomeLoc> intervalIterator;
+
+ /**
+ * In the case of monolithic sharding, this case returns whether the only shard has been generated.
+ */
+ private boolean shardGenerated = false;
+
+ /**
+ * The alignment context to return from this shard's iterator. Lazy implementation: the iterator will not find the
+ * currentAlignmentContext until absolutely required to do so. If currentAlignmentContext is null and advance()
+ * doesn't populate it, no more elements are available. If currentAlignmentContext is non-null, currentAlignmentContext
+ * should be returned by next().
+ */
+ private AlignmentContext currentAlignmentContext;
+
+ /**
+ * Create a new window maker with the given iterator as a data source, covering
+ * the given intervals.
+ * @param iterator The data source for this window.
+ * @param intervals The set of intervals over which to traverse.
+ * @param sampleNames The complete set of sample names in the reads in shard
+ */
+
+ private final LocusIteratorByState libs;
+
+ public WindowMaker(Shard shard, GenomeLocParser genomeLocParser, GATKSAMIterator iterator, List<GenomeLoc> intervals, Collection<String> sampleNames) {
+ this.sourceInfo = shard.getReadProperties();
+ this.readIterator = new GATKSAMRecordIterator(iterator);
+
+ this.libs = new LocusIteratorByState(readIterator,sourceInfo,genomeLocParser,sampleNames);
+ this.sourceIterator = new PeekableIterator<AlignmentContext>(libs);
+
+ this.intervalIterator = intervals.size()>0 ? new PeekableIterator<GenomeLoc>(intervals.iterator()) : null;
+ }
+
+ public WindowMaker(Shard shard, GenomeLocParser genomeLocParser, GATKSAMIterator iterator, List<GenomeLoc> intervals ) {
+ this(shard, genomeLocParser, iterator, intervals, LocusIteratorByState.sampleListForSAMWithoutReadGroups());
+ }
+
+ public Iterator<WindowMakerIterator> iterator() {
+ return this;
+ }
+
+ public boolean hasNext() {
+ return (intervalIterator != null && intervalIterator.hasNext()) || !shardGenerated;
+ }
+
+ public WindowMakerIterator next() {
+ shardGenerated = true;
+ return new WindowMakerIterator(intervalIterator != null ? intervalIterator.next() : null);
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Cannot remove from a window maker.");
+ }
+
+ public void close() {
+ this.readIterator.close();
+ }
+
+ public class WindowMakerIterator extends LocusIterator {
+ /**
+ * The locus for which this iterator is currently returning reads.
+ */
+ private final GenomeLoc locus;
+
+ public WindowMakerIterator(GenomeLoc locus) {
+ this.locus = locus;
+ advance();
+ }
+
+ public ReadProperties getSourceInfo() {
+ return sourceInfo;
+ }
+
+ public GenomeLoc getLocus() {
+ return locus;
+ }
+
+ public WindowMakerIterator iterator() {
+ return this;
+ }
+
+ public boolean hasNext() {
+ advance();
+ return currentAlignmentContext != null;
+ }
+
+ public AlignmentContext next() {
+ if(!hasNext()) throw new NoSuchElementException("WindowMakerIterator is out of elements for this interval.");
+
+ // Consume this alignment context.
+ AlignmentContext toReturn = currentAlignmentContext;
+ currentAlignmentContext = null;
+
+ // Return the current element.
+ return toReturn;
+ }
+
+ private void advance() {
+ // Need to find the next element that is not past shard boundaries. If we travel past the edge of
+ // shard boundaries, stop and let the next interval pick it up.
+ while(currentAlignmentContext == null && sourceIterator.hasNext()) {
+ // Advance the iterator and try again.
+ AlignmentContext candidateAlignmentContext = sourceIterator.peek();
+
+ if(locus == null) {
+ // No filter present. Return everything that LocusIteratorByState provides us.
+ currentAlignmentContext = sourceIterator.next();
+ }
+ else if(locus.isPast(candidateAlignmentContext.getLocation()))
+ // Found a locus before the current window; claim this alignment context and throw it away.
+ sourceIterator.next();
+ else if(locus.containsP(candidateAlignmentContext.getLocation())) {
+ // Found a locus within the current window; claim this alignment context and call it the next entry.
+ currentAlignmentContext = sourceIterator.next();
+ }
+ else if(locus.isBefore(candidateAlignmentContext.getLocation())) {
+ // Whoops. Skipped passed the end of the region. Iteration for this window is complete. Do
+ // not claim this alignment context in case it is part of the next shard.
+ break;
+ }
+ else
+ throw new ReviewedGATKException("BUG: filtering locus does not contain, is not before, and is not past the given alignment context");
+ }
+ }
+
+ @Override
+ public LocusIteratorByState getLIBS() {
+ return libs;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/package-info.java
new file mode 100644
index 0000000..c0d6e9d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/executive/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/BadCigarFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/BadCigarFilter.java
new file mode 100644
index 0000000..fce3a71
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/BadCigarFilter.java
@@ -0,0 +1,122 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.SAMRecord;
+
+import java.util.Iterator;
+
+/**
+ * Filter out reads with wonky cigar strings.
+ *
+ * - No reads with Hard/Soft clips in the middle of the cigar
+ * - No reads starting with deletions (with or without preceding clips)
+ * - No reads ending in deletions (with or without follow-up clips)
+ * - No reads that are fully hard or soft clipped
+ * - No reads that have consecutive indels in the cigar (II, DD, ID or DI)
+ *
+ * ps: apparently an empty cigar is okay...
+ *
+ * @author ebanks
+ * @version 0.1
+ */
+
+public class BadCigarFilter extends ReadFilter {
+
+ public boolean filterOut(final SAMRecord rec) {
+ final Cigar c = rec.getCigar();
+
+ // if there is no Cigar then it can't be bad
+ if( c.isEmpty() ) {
+ return false;
+ }
+
+ Iterator<CigarElement> elementIterator = c.getCigarElements().iterator();
+
+ CigarOperator firstOp = CigarOperator.H;
+ while (elementIterator.hasNext() && (firstOp == CigarOperator.H || firstOp == CigarOperator.S)) {
+ CigarOperator op = elementIterator.next().getOperator();
+
+ // No reads with Hard/Soft clips in the middle of the cigar
+ if (firstOp != CigarOperator.H && op == CigarOperator.H) {
+ return true;
+ }
+ firstOp = op;
+ }
+
+ // No reads starting with deletions (with or without preceding clips)
+ if (firstOp == CigarOperator.D) {
+ return true;
+ }
+
+ boolean hasMeaningfulElements = (firstOp != CigarOperator.H && firstOp != CigarOperator.S);
+ boolean previousElementWasIndel = firstOp == CigarOperator.I;
+ CigarOperator lastOp = firstOp;
+ CigarOperator previousOp = firstOp;
+
+ while (elementIterator.hasNext()) {
+ CigarOperator op = elementIterator.next().getOperator();
+
+ if (op != CigarOperator.S && op != CigarOperator.H) {
+
+ // No reads with Hard/Soft clips in the middle of the cigar
+ if (previousOp == CigarOperator.S || previousOp == CigarOperator.H)
+ return true;
+
+ lastOp = op;
+
+ if (!hasMeaningfulElements && op.consumesReadBases()) {
+ hasMeaningfulElements = true;
+ }
+
+ if (op == CigarOperator.I || op == CigarOperator.D) {
+
+ // No reads that have consecutive indels in the cigar (II, DD, ID or DI)
+ if (previousElementWasIndel) {
+ return true;
+ }
+ previousElementWasIndel = true;
+ }
+ else {
+ previousElementWasIndel = false;
+ }
+ }
+ // No reads with Hard/Soft clips in the middle of the cigar
+ else if (op == CigarOperator.S && previousOp == CigarOperator.H) {
+ return true;
+ }
+
+ previousOp = op;
+ }
+
+ // No reads ending in deletions (with or without follow-up clips)
+ // No reads that are fully hard or soft clipped
+ return lastOp == CigarOperator.D || !hasMeaningfulElements;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/BadMateFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/BadMateFilter.java
new file mode 100644
index 0000000..c25d8d9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/BadMateFilter.java
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Filter out reads whose mate maps to a different contig.
+ *
+ * @author ebanks
+ * @version 0.1
+ */
+
+public class BadMateFilter extends ReadFilter {
+
+ public boolean filterOut(final SAMRecord rec) {
+ return hasBadMate(rec);
+ }
+
+ public static boolean hasBadMate(final SAMRecord rec) {
+ return (rec.getReadPairedFlag() && !rec.getMateUnmappedFlag() && !rec.getReferenceIndex().equals(rec.getMateReferenceIndex()));
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/CountingFilteringIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/CountingFilteringIterator.java
new file mode 100644
index 0000000..8717f1f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/CountingFilteringIterator.java
@@ -0,0 +1,150 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.filter.SamRecordFilter;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.CloseableIterator;
+import htsjdk.samtools.util.CloserUtil;
+import org.broadinstitute.gatk.engine.ReadMetrics;
+
+import java.util.*;
+
+/**
+ * Filtering Iterator which takes a filter and an iterator and iterates
+ * through only those records which are not rejected by the filter.
+ * @author Mark DePristo
+ */
+public class CountingFilteringIterator implements CloseableIterator<SAMRecord> {
+ private final ReadMetrics globalRuntimeMetrics;
+ private final ReadMetrics privateRuntimeMetrics;
+ private final Iterator<SAMRecord> iterator;
+ private final List<CountingReadFilter> filters = new ArrayList<>();
+ private SAMRecord next = null;
+
+ // wrapper around ReadFilters to count the number of filtered reads
+ private final class CountingReadFilter extends ReadFilter {
+ protected final ReadFilter readFilter;
+ protected long counter = 0L;
+
+ public CountingReadFilter(final ReadFilter readFilter) {
+ this.readFilter = readFilter;
+ }
+
+ @Override
+ public boolean filterOut(final SAMRecord record) {
+ final boolean result = readFilter.filterOut(record);
+ if ( result )
+ counter++;
+ return result;
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param metrics metrics to accumulate on the nature of filtered reads.
+ * @param iterator the backing iterator
+ * @param filters the filter (which may be a FilterAggregator)
+ */
+ public CountingFilteringIterator(ReadMetrics metrics, Iterator<SAMRecord> iterator, Collection<ReadFilter> filters) {
+ this.globalRuntimeMetrics = metrics;
+ privateRuntimeMetrics = new ReadMetrics();
+ this.iterator = iterator;
+ for ( final ReadFilter filter : filters )
+ this.filters.add(new CountingReadFilter(filter));
+ next = getNextRecord();
+ }
+
+ /**
+ * Returns true if the iteration has more elements.
+ *
+ * @return true if the iteration has more elements. Otherwise returns false.
+ */
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ /**
+ * Returns the next element in the iteration.
+ *
+ * @return the next element in the iteration
+ * @throws java.util.NoSuchElementException
+ */
+ public SAMRecord next() {
+ if (next == null) {
+ throw new NoSuchElementException("Iterator has no more elements.");
+ }
+ final SAMRecord result = next;
+ next = getNextRecord();
+ return result;
+ }
+
+ /**
+ * Required method for Iterator API.
+ *
+ * @throws UnsupportedOperationException
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("Remove() not supported by CountingFilteringIterator");
+ }
+
+ public void close() {
+ CloserUtil.close(iterator);
+
+ for ( final CountingReadFilter filter : filters )
+ privateRuntimeMetrics.setFilterCount(filter.readFilter.getClass().getSimpleName(), filter.counter);
+ // update the global metrics with all the data we collected here
+ globalRuntimeMetrics.incrementMetrics(privateRuntimeMetrics);
+ }
+
+ /**
+ * Gets the next record from the underlying iterator that passes the filter
+ *
+ * @return SAMRecord the next filter-passing record
+ */
+ private SAMRecord getNextRecord() {
+ while (iterator.hasNext()) {
+ SAMRecord record = iterator.next();
+
+ // update only the private copy of the metrics so that we don't need to worry about race conditions
+ // that can arise when trying to update the global copy; it was agreed that this is the cleanest solution.
+ privateRuntimeMetrics.incrementNumReadsSeen();
+
+ boolean filtered = false;
+ for(SamRecordFilter filter: filters) {
+ if(filter.filterOut(record)) {
+ filtered = true;
+ break;
+ }
+ }
+
+ if(!filtered) return record;
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/DuplicateReadFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/DuplicateReadFilter.java
new file mode 100644
index 0000000..52861e2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/DuplicateReadFilter.java
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Filter out duplicate reads.
+ *
+ * @author rpoplin
+ * @since Dec 9, 2009
+ */
+
+public class DuplicateReadFilter extends ReadFilter {
+ public boolean filterOut( final SAMRecord read ) {
+ return read.getDuplicateReadFlag();
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/FailsVendorQualityCheckFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/FailsVendorQualityCheckFilter.java
new file mode 100644
index 0000000..2cc5e2a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/FailsVendorQualityCheckFilter.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Filter out reads that fail the vendor quality check.
+ *
+ * @author rpoplin
+ * @since Jul 19, 2010
+ */
+
+public class FailsVendorQualityCheckFilter extends ReadFilter {
+ public boolean filterOut( final SAMRecord read ) {
+ return read.getReadFailsVendorQualityCheckFlag();
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/FilterManager.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/FilterManager.java
new file mode 100644
index 0000000..59c3f15
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/FilterManager.java
@@ -0,0 +1,95 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import org.broadinstitute.gatk.utils.classloader.PluginManager;
+import org.broadinstitute.gatk.utils.help.GATKDocUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Manage filters and filter options. Any requests for basic filtering classes
+ * should ultimately be made through this class.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class FilterManager extends PluginManager<ReadFilter> {
+ public FilterManager() {
+ super(ReadFilter.class,"filter","Filter");
+ }
+
+ /**
+ * Instantiate a filter of the given type. Along the way, scream bloody murder if
+ * the filter is not available.
+ * @param filterType The type of the filter
+ * @return The filter
+ */
+ public ReadFilter createFilterByType(Class<? extends ReadFilter> filterType) {
+ return this.createByName(getName(filterType));
+ }
+
+ public Collection<Class<? extends ReadFilter>> getValues() {
+ return this.getPlugins();
+ }
+
+ /**
+ * Rather than use the default error message, print out a list of read filters as well.
+ * @param pluginCategory - string, the category of the plugin (e.g. read filter)
+ * @param pluginName - string, what we were trying to match (but failed to)
+ * @return - A wall of text with the default message, followed by a listing of available read filters
+ */
+ @Override
+ protected String formatErrorMessage(String pluginCategory, String pluginName) {
+ List<Class<? extends ReadFilter>> availableFilters = this.getPluginsImplementing(ReadFilter.class);
+
+
+ return String.format("Read filter %s not found. Available read filters:%n%n%s%n%n%s",pluginName,
+ userFriendlyListofReadFilters(availableFilters),
+ "Please consult the GATK Documentation (" + HelpConstants.GATK_DOCS_URL + ") for more information.");
+ }
+
+ private String userFriendlyListofReadFilters(List<Class<? extends ReadFilter>> filters) {
+ final String headName = "FilterName", headDoc = "Documentation";
+ int longestNameLength = -1;
+ for ( Class < ? extends ReadFilter> filter : filters ) {
+ longestNameLength = Math.max(longestNameLength,this.getName(filter).length());
+ }
+ String format = " %"+longestNameLength+"s %s%n";
+
+ StringBuilder listBuilder = new StringBuilder();
+ listBuilder.append(String.format(format,headName,headDoc));
+ for ( Class<? extends ReadFilter> filter : filters ) {
+ String helpLink = GATKDocUtils.helpLinksToGATKDocs(filter);
+ String filterName = this.getName(filter);
+ listBuilder.append(String.format(format,filterName,helpLink));
+ }
+
+ return listBuilder.toString();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/LibraryReadFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/LibraryReadFilter.java
new file mode 100644
index 0000000..8b0f076
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/LibraryReadFilter.java
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+
+/**
+ * Only use reads from the specified library
+ *
+ * @author kcibul
+ * @since Aug 15, 2012
+ *
+ */
+
+public class LibraryReadFilter extends ReadFilter {
+ @Argument(fullName = "library", shortName = "library", doc="The name of the library to keep, filtering out all others", required=true)
+ private String LIBRARY_TO_KEEP = null;
+
+ public boolean filterOut( final SAMRecord read ) {
+ final SAMReadGroupRecord readGroup = read.getReadGroup();
+ return ( readGroup == null || readGroup.getLibrary() == null || !readGroup.getLibrary().equals( LIBRARY_TO_KEEP ) );
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MalformedReadFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MalformedReadFilter.java
new file mode 100644
index 0000000..1b59a06
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MalformedReadFilter.java
@@ -0,0 +1,260 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.ReadProperties;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMDataSource;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.Collections;
+
+/**
+ * Filter out malformed reads.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class MalformedReadFilter extends ReadFilter {
+
+
+ private static final String FILTER_READS_WITH_N_CIGAR_ARGUMENT_FULL_NAME = "filter_reads_with_N_cigar" ;
+
+ private SAMFileHeader header;
+
+ @Argument(fullName = FILTER_READS_WITH_N_CIGAR_ARGUMENT_FULL_NAME, shortName = "filterRNC", doc = "filter out reads with CIGAR containing the N operator, instead of stop processing and report an error.", required = false)
+ boolean filterReadsWithNCigar = false;
+
+
+ @Argument(fullName = "filter_mismatching_base_and_quals", shortName = "filterMBQ", doc = "if a read has mismatching number of bases and base qualities, filter out the read instead of blowing up.", required = false)
+ boolean filterMismatchingBaseAndQuals = false;
+
+ @Argument(fullName = "filter_bases_not_stored", shortName = "filterNoBases", doc = "if a read has no stored bases (i.e. a '*'), filter out the read instead of blowing up.", required = false)
+ boolean filterBasesNotStored = false;
+
+ /**
+ * Indicates the applicable validation exclusions
+ */
+ private boolean allowNCigars;
+
+ @Override
+ public void initialize(final GenomeAnalysisEngine engine) {
+ header = engine.getSAMFileHeader();
+ ValidationExclusion validationExclusions = null;
+ final SAMDataSource rds = engine.getReadsDataSource();
+ if (rds != null) {
+ final ReadProperties rps = rds.getReadsInfo();
+ if (rps != null) {
+ validationExclusions = rps.getValidationExclusionList();
+ }
+ }
+ if (validationExclusions == null) {
+ allowNCigars = false;
+ } else {
+ allowNCigars = validationExclusions.contains(ValidationExclusion.TYPE.ALLOW_N_CIGAR_READS);
+ }
+ }
+
+ public boolean filterOut(final SAMRecord read) {
+ // slowly changing the behavior to blow up first and filtering out if a parameter is explicitly provided
+ return !checkInvalidAlignmentStart(read) ||
+ !checkInvalidAlignmentEnd(read) ||
+ !checkAlignmentDisagreesWithHeader(this.header,read) ||
+ !checkHasReadGroup(read) ||
+ !checkMismatchingBasesAndQuals(read, filterMismatchingBaseAndQuals) ||
+ !checkCigarDisagreesWithAlignment(read) ||
+ !checkSeqStored(read, filterBasesNotStored) ||
+ !checkCigarIsSupported(read,filterReadsWithNCigar,allowNCigars);
+ }
+
+ private static boolean checkHasReadGroup(final SAMRecord read) {
+ if ( read.getReadGroup() == null ) {
+ // there are 2 possibilities: either the RG tag is missing or it is not defined in the header
+ final String rgID = (String)read.getAttribute(SAMTagUtil.getSingleton().RG);
+ if ( rgID == null )
+ throw new UserException.ReadMissingReadGroup(read);
+ throw new UserException.ReadHasUndefinedReadGroup(read, rgID);
+ }
+ return true;
+ }
+
+ /**
+ * Check for the case in which the alignment start is inconsistent with the read unmapped flag.
+ * @param read The read to validate.
+ * @return true if read start is valid, false otherwise.
+ */
+ private static boolean checkInvalidAlignmentStart(final SAMRecord read ) {
+ // read is not flagged as 'unmapped', but alignment start is NO_ALIGNMENT_START
+ if( !read.getReadUnmappedFlag() && read.getAlignmentStart() == SAMRecord.NO_ALIGNMENT_START )
+ return false;
+ // Read is not flagged as 'unmapped', but alignment start is -1
+ if( !read.getReadUnmappedFlag() && read.getAlignmentStart() == -1 )
+ return false;
+ return true;
+ }
+
+ /**
+ * Check for invalid end of alignments.
+ * @param read The read to validate.
+ * @return true if read end is valid, false otherwise.
+ */
+ private static boolean checkInvalidAlignmentEnd(final SAMRecord read ) {
+ // Alignment aligns to negative number of bases in the reference.
+ if( !read.getReadUnmappedFlag() && read.getAlignmentEnd() != -1 && (read.getAlignmentEnd()-read.getAlignmentStart()+1)<0 )
+ return false;
+ return true;
+ }
+
+ /**
+ * Check to ensure that the alignment makes sense based on the contents of the header.
+ * @param header The SAM file header.
+ * @param read The read to verify.
+ * @return true if alignment agrees with header, false othrewise.
+ */
+ private static boolean checkAlignmentDisagreesWithHeader(final SAMFileHeader header, final SAMRecord read ) {
+ // Read is aligned to nonexistent contig
+ if( read.getReferenceIndex() == SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX && read.getAlignmentStart() != SAMRecord.NO_ALIGNMENT_START )
+ return false;
+ final SAMSequenceRecord contigHeader = header.getSequence( read.getReferenceIndex() );
+ // Read is aligned to a point after the end of the contig
+ if( !read.getReadUnmappedFlag() && read.getAlignmentStart() > contigHeader.getSequenceLength() )
+ return false;
+ return true;
+ }
+
+ /**
+ * Check for inconsistencies between the cigar string and the
+ * @param read The read to validate.
+ * @return true if cigar agrees with alignment, false otherwise.
+ */
+ private static boolean checkCigarDisagreesWithAlignment(final SAMRecord read) {
+ // Read has a valid alignment start, but the CIGAR string is empty
+ if( !read.getReadUnmappedFlag() &&
+ read.getAlignmentStart() != -1 &&
+ read.getAlignmentStart() != SAMRecord.NO_ALIGNMENT_START &&
+ read.getAlignmentBlocks().size() < 0 )
+ return false;
+ return true;
+ }
+
+ /**
+ * Check for unsupported CIGAR operators.
+ * Currently the N operator is not supported.
+ * @param read The read to validate.
+ * @param filterReadsWithNCigar whether the offending read should just
+ * be silently filtered or not.
+ * @param allowNCigars whether reads that contain N operators in their CIGARs
+ * can be processed or an exception should be thrown instead.
+ * @throws UserException.UnsupportedCigarOperatorException
+ * if {@link #filterReadsWithNCigar} is <code>false</code> and
+ * the input read has some unsupported operation.
+ * @return <code>true</code> if the read CIGAR operations are
+ * fully supported, otherwise <code>false</code>, as long as
+ * no exception has been thrown.
+ */
+ private static boolean checkCigarIsSupported(final SAMRecord read, final boolean filterReadsWithNCigar, final boolean allowNCigars) {
+ if( containsNOperator(read)) {
+ if (! filterReadsWithNCigar && !allowNCigars) {
+ throw new UserException.UnsupportedCigarOperatorException(
+ CigarOperator.N,read,
+ "Perhaps you are"
+ + " trying to use RNA-Seq data?"
+ + " While we are currently actively working to"
+ + " support this data type unfortunately the"
+ + " GATK cannot be used with this data in its"
+ + " current form. You have the option of either"
+ + " filtering out all reads with operator "
+ + CigarOperator.N + " in their CIGAR string"
+ + " (please add --"
+ + FILTER_READS_WITH_N_CIGAR_ARGUMENT_FULL_NAME
+ + " to your command line) or"
+ + " assume the risk of processing those reads as they"
+ + " are including the pertinent unsafe flag (please add -U"
+ + ' ' + ValidationExclusion.TYPE.ALLOW_N_CIGAR_READS
+ + " to your command line). Notice however that if you were"
+ + " to choose the latter, an unspecified subset of the"
+ + " analytical outputs of an unspecified subset of the tools"
+ + " will become unpredictable. Consequently the GATK team"
+ + " might well not be able to provide you with the usual support"
+ + " with any issue regarding any output");
+ }
+ return ! filterReadsWithNCigar;
+ }
+ return true;
+ }
+
+ private static boolean containsNOperator(final SAMRecord read) {
+ final Cigar cigar = read.getCigar();
+ if (cigar == null) {
+ return false;
+ }
+ for (final CigarElement ce : cigar.getCigarElements()) {
+ if (ce.getOperator() == CigarOperator.N) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Check if the read has the same number of bases and base qualities
+ * @param read the read to validate
+ * @return true if they have the same number. False otherwise.
+ */
+ private static boolean checkMismatchingBasesAndQuals(final SAMRecord read, final boolean filterMismatchingBaseAndQuals) {
+ final boolean result;
+ if (read.getReadLength() == read.getBaseQualities().length)
+ result = true;
+ else if (filterMismatchingBaseAndQuals)
+ result = false;
+ else
+ throw new UserException.MalformedBAM(read,
+ String.format("BAM file has a read with mismatching number of bases and base qualities. Offender: %s [%d bases] [%d quals].%s",
+ read.getReadName(), read.getReadLength(), read.getBaseQualities().length,
+ read.getBaseQualities().length == 0 ? " You can use --defaultBaseQualities to assign a default base quality for all reads, but this can be dangerous in you don't know what you are doing." : ""));
+
+ return result;
+ }
+
+ /**
+ * Check if the read has its base sequence stored
+ * @param read the read to validate
+ * @return true if the sequence is stored and false otherwise ("*" in the SEQ field).
+ */
+ protected static boolean checkSeqStored(final SAMRecord read, final boolean filterBasesNotStored) {
+
+ if ( read.getReadBases() != SAMRecord.NULL_SEQUENCE )
+ return true;
+
+ if ( filterBasesNotStored )
+ return false;
+
+ throw new UserException.MalformedBAM(read, String.format("the BAM file has a read with no stored bases (i.e. it uses '*') which is not supported in the GATK; see the --filter_bases_not_stored argument. Offender: %s", read.getReadName()));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MappingQualityFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MappingQualityFilter.java
new file mode 100644
index 0000000..67c62b9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MappingQualityFilter.java
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+
+/**
+ * Filter out reads with low mapping qualities.
+ *
+ * @author ebanks
+ * @version 0.1
+ */
+
+public class MappingQualityFilter extends ReadFilter {
+
+ @Argument(fullName = "min_mapping_quality_score", shortName = "mmq", doc = "Minimum read mapping quality required to consider a read for calling", required = false)
+ public int MIN_MAPPING_QUALTY_SCORE = 10;
+
+ public boolean filterOut(SAMRecord rec) {
+ return (rec.getMappingQuality() < MIN_MAPPING_QUALTY_SCORE);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MappingQualityUnavailableFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MappingQualityUnavailableFilter.java
new file mode 100644
index 0000000..05df7fb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MappingQualityUnavailableFilter.java
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.QualityUtils;
+
+/**
+ * Filter out mapping quality zero reads.
+ *
+ * @author ebanks
+ * @version 0.1
+ */
+
+public class MappingQualityUnavailableFilter extends ReadFilter {
+ public boolean filterOut(SAMRecord rec) {
+ return (rec.getMappingQuality() == QualityUtils.MAPPING_QUALITY_UNAVAILABLE);
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MappingQualityZeroFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MappingQualityZeroFilter.java
new file mode 100644
index 0000000..f3f7032
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MappingQualityZeroFilter.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Filter out mapping quality zero reads.
+ *
+ * @author hanna
+ * @version 0.1
+ */
+
+public class MappingQualityZeroFilter extends ReadFilter {
+ public boolean filterOut(SAMRecord rec) {
+ return (rec.getMappingQuality() == 0);
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MateSameStrandFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MateSameStrandFilter.java
new file mode 100644
index 0000000..0818f8f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MateSameStrandFilter.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Filter out reads that are not paired, have their mate unmapped, are duplicates, fail vendor quality check or both mate and read are in the same strand.
+ *
+ * @author chartl
+ * @since 5/18/11
+ */
+public class MateSameStrandFilter extends ReadFilter {
+
+ public boolean filterOut(SAMRecord read) {
+ return (! read.getReadPairedFlag() ) || read.getMateUnmappedFlag() || read.getDuplicateReadFlag() ||
+ read.getReadFailsVendorQualityCheckFlag() || read.getMateNegativeStrandFlag() != read.getReadNegativeStrandFlag();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MaxInsertSizeFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MaxInsertSizeFilter.java
new file mode 100644
index 0000000..cca05eb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MaxInsertSizeFilter.java
@@ -0,0 +1,44 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+
+/**
+ * Filter out reads that exceed a given max insert size
+ *
+ * @author chartl
+ * @since 5/2/11
+ */
+public class MaxInsertSizeFilter extends ReadFilter {
+ @Argument(fullName = "maxInsertSize", shortName = "maxInsert", doc="Discard reads with insert size greater than the specified value, defaults to 1000000", required=false)
+ private int maxInsertSize = 1000000;
+
+ public boolean filterOut(SAMRecord record) {
+ return (record.getReadPairedFlag() && (record.getInferredInsertSize() > maxInsertSize || record.getInferredInsertSize() < -1*maxInsertSize));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MissingReadGroupFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MissingReadGroupFilter.java
new file mode 100644
index 0000000..21b291b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/MissingReadGroupFilter.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Filter out reads without read groups.
+ *
+ * @author ebanks
+ * @version 0.1
+ */
+
+public class MissingReadGroupFilter extends ReadFilter {
+ public boolean filterOut(SAMRecord rec) {
+ return rec.getReadGroup() == null;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/NDNCigarReadTransformer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/NDNCigarReadTransformer.java
new file mode 100644
index 0000000..65bf1eb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/NDNCigarReadTransformer.java
@@ -0,0 +1,118 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.iterators.RNAReadTransformer;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+/**
+ * A read transformer that refactor NDN cigar elements to one N element.
+ *
+ * <p>
+ * This read transformer will refactor cigar strings that contain N-D-N elements to one N element (with total length of the three refactored elements).
+ * This is intended primarily for users of RNA-Seq data handling programs such as TopHat2.
+ * Currently we consider that the internal N-D-N motif is illegal and we error out when we encounter it. By refactoring the cigar string of
+ * those specific reads, users of TopHat and other tools can circumvent this problem without affecting the rest of their dataset.
+ *
+ * NOTE: any walker that need that functionality should apply that read transformer in its map function, since it won't be activated by the GATK engine.
+ *
+ * The engine parameter that activate this read transformer is --refactor_NDN_cigar_string or -fixNDN
+ * </p>
+ *
+ *
+ *
+ * @author ami
+ * @since 04/22/14
+ */
+
+public class NDNCigarReadTransformer extends RNAReadTransformer {
+
+ private boolean refactorReads;
+
+ @Override
+ public ApplicationTime initializeSub(final GenomeAnalysisEngine engine, final Walker walker) {
+ refactorReads = engine.getArguments().REFACTOR_NDN_CIGAR_READS;
+
+ return ApplicationTime.HANDLED_IN_WALKER; // NOTE: any walker that need that functionality should apply that read transformer in its map function, since it won't be activated by the GATK engine.
+ }
+
+ @Override
+ public GATKSAMRecord apply(final GATKSAMRecord read) {
+ if(read == null)
+ throw new UserException.BadInput("try to transform a null GATKSAMRecord");
+ final Cigar originalCigar = read.getCigar();
+ if (originalCigar.isValid(read.getReadName(),-1) != null)
+ throw new UserException.BadInput("try to transform a read with non-valid cigar string: readName: "+read.getReadName()+" Cigar String: "+originalCigar);
+ read.setCigar(refactorNDNtoN(originalCigar));
+ return read;
+ }
+
+ @Override
+ public boolean enabled() {
+ return refactorReads;
+ }
+
+
+
+ protected Cigar refactorNDNtoN(final Cigar originalCigar) {
+ final Cigar refactoredCigar = new Cigar();
+ final int cigarLength = originalCigar.numCigarElements();
+ for(int i = 0; i < cigarLength; i++){
+ final CigarElement element = originalCigar.getCigarElement(i);
+ if(element.getOperator() == CigarOperator.N && thereAreAtLeast2MoreElements(i,cigarLength)){
+ final CigarElement nextElement = originalCigar.getCigarElement(i+1);
+ final CigarElement nextNextElement = originalCigar.getCigarElement(i+2);
+
+ // if it is N-D-N replace with N (with the total length) otherwise just add the first N.
+ if(nextElement.getOperator() == CigarOperator.D && nextNextElement.getOperator() == CigarOperator.N){
+ final int threeElementsLength = element.getLength() + nextElement.getLength() + nextNextElement.getLength();
+ final CigarElement refactoredElement = new CigarElement(threeElementsLength,CigarOperator.N);
+ refactoredCigar.add(refactoredElement);
+ i += 2; //skip the elements that were refactored
+ }
+ else
+ refactoredCigar.add(element); // add only the first N
+ }
+ else
+ refactoredCigar.add(element); // add any non-N element
+ }
+ return refactoredCigar;
+ }
+
+ private boolean thereAreAtLeast2MoreElements(final int index, final int cigarLength){
+ return index < cigarLength - 2;
+ }
+
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/NoOriginalQualityScoresFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/NoOriginalQualityScoresFilter.java
new file mode 100644
index 0000000..8297903
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/NoOriginalQualityScoresFilter.java
@@ -0,0 +1,65 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * Filter out reads that don't have base an original quality quality score tag (usually added by BQSR)
+ *
+ * @author rpoplin
+ * @since Nov 19, 2009
+ */
+public class NoOriginalQualityScoresFilter extends ReadFilter {
+ public boolean filterOut( final SAMRecord read ) {
+ return (read.getAttribute("OQ") == null);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/NotPrimaryAlignmentFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/NotPrimaryAlignmentFilter.java
new file mode 100644
index 0000000..b09e1f6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/NotPrimaryAlignmentFilter.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Filter out duplicate reads.
+ *
+ * @author rpoplin
+ * @since Dec 9, 2009
+ */
+
+public class NotPrimaryAlignmentFilter extends ReadFilter {
+ public boolean filterOut( final SAMRecord read ) {
+ return read.getNotPrimaryAlignmentFlag();
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/Platform454Filter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/Platform454Filter.java
new file mode 100644
index 0000000..79f16a5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/Platform454Filter.java
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+/**
+ * Filter out 454 reads.
+ *
+ * @author ebanks
+ * @version 0.1
+ */
+
+public class Platform454Filter extends ReadFilter {
+ public boolean filterOut(SAMRecord rec) {
+ return (ReadUtils.is454Read((GATKSAMRecord)rec));
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/PlatformFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/PlatformFilter.java
new file mode 100644
index 0000000..8236cc2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/PlatformFilter.java
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+/**
+ * Filter out PL matching reads.
+ *
+ * @author ebanks
+ * @version 0.1
+ */
+public class PlatformFilter extends ReadFilter {
+ @Argument(fullName = "PLFilterName", shortName = "PLFilterName", doc="Discard reads with RG:PL attribute containing this string", required=false)
+ protected String[] PLFilterNames;
+
+ public boolean filterOut(SAMRecord rec) {
+ for ( String name : PLFilterNames )
+ if ( ReadUtils.isPlatformRead((GATKSAMRecord)rec, name.toUpperCase() ))
+ return true;
+ return false;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/PlatformUnitFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/PlatformUnitFilter.java
new file mode 100644
index 0000000..4a6781f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/PlatformUnitFilter.java
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Filter out reads that have blacklisted platform unit tags. (See code documentation for how to create the blacklist).
+ *
+ * @author asivache
+ * @since Sep 21, 2009
+ */
+public class PlatformUnitFilter extends ReadFilter {
+ // a hack: use static in order to be able to fill it with the data from command line at runtime
+ static private Set<String> blackListedLanes = new HashSet<String>();
+
+ public boolean filterOut(SAMRecord samRecord) {
+
+ if ( blackListedLanes.size() == 0 ) return false; // no filters set, nothing to do
+
+ Object pu_attr = samRecord.getAttribute("PU");
+
+ if ( pu_attr == null ) {
+ // no platform unit in the record, go get from read group
+ SAMReadGroupRecord rgr = samRecord.getReadGroup();
+ if ( rgr == null ) throw new UserException.MalformedBAM(samRecord, "Read " + samRecord.getReadName() +" has NO associated read group record");
+ pu_attr = rgr.getAttribute("PU") ;
+ }
+ if ( pu_attr == null ) return false; // could not get PU, forget about the filtering...
+ return blackListedLanes.contains((String)pu_attr);
+ }
+
+ /**
+ * The argument is interpreted as a comma-separated list of lanes (platform units) to be filtered
+ * out. All the specified names will be registered with the filter and filterOut(r) for any SAMRecord r
+ * belonging to one of the specified lanes will thereafter return true.
+ * The names can be surrounded by additional spaces, the latters will be trimmed by this method.
+ * This method can be called multiple times to add more lanes. Re-registering the same lane again is safe.
+ * @param arg
+ */
+ public static void setBlackListedLanes(String arg) {
+ String[] lanes = arg.split(",");
+ for ( int i = 0; i < lanes.length ; i++ ) {
+ blackListedLanes.add(lanes[i].trim());
+ }
+ }
+
+ /**
+ * Adds a single name of a lane (platform unit) to be filtered out by this filter. The name can be surrounded
+ * by spaces, the latters will be trimmed out. This method can be called multiple times to add more lanes.
+ * Re-registering the same lane again is safe.
+ * @param arg
+ */
+ public static void addBlackListedLane(String arg) {
+ blackListedLanes.add(arg.trim());
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/PlatformUnitFilterHelper.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/PlatformUnitFilterHelper.java
new file mode 100644
index 0000000..428806d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/PlatformUnitFilterHelper.java
@@ -0,0 +1,87 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.regex.Pattern;
+
+/**
+ * This is a utility class, its sole purpose is to populate PlatformUnitFilter with data. When a command line argument
+ * (@Argument) of the type PlatformUnitFilterHelper is declared in an application (walker), its constuctor
+ * PlatformUnitFilterHelper(String) automatically called by the argument system will parse its String argument
+ * and set up static fields of PlatformUnitFilter object.
+ *
+ * The String argument can be either a name of existing file, or a list of comma-separated lane (Platform Unit) names.
+ * First, the constructor will check if a file with specified name exists. If it does, then it is assumed that each line
+ * in the file contains one name of a lane (Platfor Unit) to filter out. If such file does not exist, then the argument is
+ * interpreted as a comma-separated list. Blank spaces around lane names are allowed in both cases and will be trimmed out.
+ *
+ * In other words, all it takes to request filtering out reads from specific lane(s) is
+ *
+ * 1) declare filter usage in the walker
+ *
+ * @ReadFilters({PlatformUnitFilter.class,...})
+ *
+ * 2) specify the argument that will take the list of lanes to filter:
+ *
+ * @Argument(fullName="filterLanes", shortName="FL", doc="all specified lanes will be ignored", required=false)
+ * PlatformUnitFilterHelper dummy;
+ *
+ * After that, the walker can be invoked with "--filterLanes 302UBAAXX090508.8,302YAAAXX090427.8" argument.
+ *
+ * Created by IntelliJ IDEA.
+ * User: asivache
+ * Date: Sep 22, 2009
+ * Time: 11:11:48 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class PlatformUnitFilterHelper {
+ final public static Pattern EMPTYLINE_PATTERN = Pattern.compile("^\\s*$");
+
+ public PlatformUnitFilterHelper(String arg) {
+ File f = new File(arg);
+
+ if ( f.exists() ) {
+ try {
+ XReadLines reader = new XReadLines(f);
+ for ( String line : reader ) {
+ if ( EMPTYLINE_PATTERN.matcher(line).matches() ) continue; // skip empty lines
+ PlatformUnitFilter.addBlackListedLane(line); // PlatformUnitFilter will trim the line as needed
+ }
+ } catch ( FileNotFoundException e) { throw new UserException.CouldNotReadInputFile(f, e); } // this should NEVER happen
+ return;
+ }
+
+ // no such file, must be a comma-separated list:
+
+ PlatformUnitFilter.setBlackListedLanes(arg); // PlatformUnitFilter will split on commas and trim as needed
+
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadFilter.java
new file mode 100644
index 0000000..a2102a8
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadFilter.java
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.filter.SamRecordFilter;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+/**
+ * A SamRecordFilter that also depends on the header.
+ */
+ at DocumentedGATKFeature(
+ groupName = HelpConstants.DOCS_CAT_RF,
+ summary = "GATK Engine arguments that filter or transfer incoming SAM/BAM data files" )
+public abstract class ReadFilter implements SamRecordFilter {
+ /**
+ * Sets the header for use by this filter.
+ * @param engine the engine.
+ */
+ public void initialize(GenomeAnalysisEngine engine) {}
+
+
+ /**
+ * Determines whether a pair of SAMRecord matches this filter
+ *
+ * @param first the first SAMRecord to evaluate
+ * @param second the second SAMRecord to evaluate
+ *
+ * @return true if the SAMRecords matches the filter, otherwise false
+ * @throws UnsupportedOperationException when paired filter not implemented
+ */
+ public boolean filterOut(final SAMRecord first, final SAMRecord second) {
+ throw new UnsupportedOperationException("Paired filter not implemented: " + this.getClass());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadGroupBlackListFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadGroupBlackListFilter.java
new file mode 100644
index 0000000..7c6bfb0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadGroupBlackListFilter.java
@@ -0,0 +1,120 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * Removes records matching the read group tag and exact match string.
+ * For example, this filter value:
+ * PU:1000G-mpimg-080821-1_1
+ * would filter out a read with the read group PU:1000G-mpimg-080821-1_1
+ */
+public class ReadGroupBlackListFilter extends ReadFilter {
+ private Set<Entry<String, Collection<String>>> filterEntries;
+
+ public ReadGroupBlackListFilter(List<String> blackLists) {
+ Map<String, Collection<String>> filters = new TreeMap<String, Collection<String>>();
+ for (String blackList : blackLists)
+ addFilter(filters, blackList, null, 0);
+ this.filterEntries = filters.entrySet();
+ }
+
+ public boolean filterOut(SAMRecord samRecord) {
+ for (Entry<String, Collection<String>> filterEntry : filterEntries) {
+ String attributeType = filterEntry.getKey();
+
+ SAMReadGroupRecord samReadGroupRecord = samRecord.getReadGroup();
+ if (samReadGroupRecord != null) {
+ Object attribute;
+ if ("ID".equals(attributeType) || "RG".equals(attributeType))
+ attribute = samReadGroupRecord.getId();
+ else
+ attribute = samReadGroupRecord.getAttribute(attributeType);
+ if (attribute != null && filterEntry.getValue().contains(attribute))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void addFilter(Map<String, Collection<String>> filters, String filter, File parentFile, int parentLineNum) {
+ if (filter.toLowerCase().endsWith(".list") || filter.toLowerCase().endsWith(".txt")) {
+ File file = new File(filter);
+ try {
+ int lineNum = 0;
+ XReadLines lines = new XReadLines(file);
+ for (String line : lines) {
+ lineNum++;
+
+ if (line.trim().length() == 0)
+ continue;
+
+ if (line.startsWith("#"))
+ continue;
+
+ addFilter(filters, line, file, lineNum);
+ }
+ } catch (FileNotFoundException e) {
+ String message = "Error loading black list: " + file.getAbsolutePath();
+ if (parentFile != null) {
+ message += ", " + parentFile.getAbsolutePath() + ":" + parentLineNum;
+ }
+ throw new UserException(message);
+ }
+ } else {
+ String[] filterEntry = filter.split(":", 2);
+
+ String message = null;
+ if (filterEntry.length != 2) {
+ message = "Invalid read group filter: " + filter;
+ } else if (filterEntry[0].length() != 2) {
+ message = "Tag is not two characters: " + filter;
+ }
+
+ if (message != null) {
+ if (parentFile != null) {
+ message += ", " + parentFile.getAbsolutePath() + ":" + parentLineNum;
+ }
+ message += ", format is <TAG>:<SUBSTRING>";
+ throw new UserException(message);
+ }
+
+ if (!filters.containsKey(filterEntry[0]))
+ filters.put(filterEntry[0], new TreeSet<String>());
+ filters.get(filterEntry[0]).add(filterEntry[1]);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadLengthFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadLengthFilter.java
new file mode 100644
index 0000000..1e44df8
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadLengthFilter.java
@@ -0,0 +1,48 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+
+/**
+ * Filters out reads whose length is >= some value or < some value.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class ReadLengthFilter extends ReadFilter {
+ @Argument(fullName = "maxReadLength", shortName = "maxRead", doc="Discard reads with length greater than the specified value", required=true)
+ private int maxReadLength;
+
+ @Argument(fullName = "minReadLength", shortName = "minRead", doc="Discard reads with length shorter than the specified value", required=true)
+ private int minReadLength = 1;
+ public boolean filterOut(SAMRecord read) {
+ // check the length
+ return read.getReadLength() > maxReadLength || read.getReadLength() < minReadLength;
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadNameFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadNameFilter.java
new file mode 100644
index 0000000..23a5151
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadNameFilter.java
@@ -0,0 +1,44 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+
+/**
+ * Filter out all reads except those with this read name
+ *
+ * @author chartl
+ * @since 9/19/11
+ */
+public class ReadNameFilter extends ReadFilter {
+ @Argument(fullName = "readName", shortName = "rn", doc="Filter out all reads except those with this read name", required=true)
+ private String readName;
+
+ public boolean filterOut(final SAMRecord rec) {
+ return ! rec.getReadName().equals(readName);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadStrandFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadStrandFilter.java
new file mode 100644
index 0000000..fd28766
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReadStrandFilter.java
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+
+/**
+ * Filters out reads whose strand is negative or positive
+ *
+ * @author chartl
+ * @version 0.1
+ */
+public class ReadStrandFilter extends ReadFilter {
+ @Argument(fullName = "filterPositive", shortName = "fp", doc="Discard reads on the forward strand",required=false)
+ boolean filterForward = false;
+
+ public boolean filterOut(SAMRecord read) {
+ // check the length
+ return read.getReadNegativeStrandFlag() != filterForward;
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReassignMappingQualityFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReassignMappingQualityFilter.java
new file mode 100644
index 0000000..0c8a93a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReassignMappingQualityFilter.java
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+
+/**
+ * A read filter (transformer) that sets all reads mapping quality to a given value.
+ *
+ * <p>
+ * If a BAM file contains erroneous or missing mapping qualities (MAPQ), this read transformer will set all your
+ * mapping qualities to a given value (see arguments list for default value).
+ * </p>
+ *
+ * <h3>See also</h3>
+ *
+ * <p>ReassignOneMappingQualityFilter: reassigns a single MAPQ value, as opposed to all those found in the BAM file.</p>
+ *
+ * <h3>Caveats</h3>
+ *
+ * <p>Note that due to the order of operations involved in applying filters, it is possible that other read filters
+ * (determined either at command-line or internally by the tool you are using) will be applied to your data before
+ * this read transformation can be applied. If one of those other filters acts on the read mapping quality (MAPQ),
+ * then you may not obtain the expected results. Unfortunately it is currently not possible to change the order of
+ * operations from command line. To avoid the problem, we recommend applying this filter separately from any other
+ * analysis, using PrintReads.</p>
+ *
+ *
+ * <h3>Input</h3>
+ * <p>
+ * BAM file(s)
+ * </p>
+ *
+ *
+ * <h3>Output</h3>
+ * <p>
+ * BAM file(s) with all reads mapping qualities reassigned
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -jar GenomeAnalysisTK.jar \
+ * -T PrintReads \
+ * -rf ReassignMappingQuality \
+ * -DMQ 35
+ * </pre>
+ *
+ * @author carneiro
+ * @since 8/8/11
+ */
+
+public class ReassignMappingQualityFilter extends ReadFilter {
+
+ @Argument(fullName = "default_mapping_quality", shortName = "DMQ", doc = "Default read mapping quality to assign to all reads", required = false)
+ public int defaultMappingQuality = 60;
+
+ public boolean filterOut(SAMRecord rec) {
+ rec.setMappingQuality(defaultMappingQuality);
+ return false;
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReassignOneMappingQualityFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReassignOneMappingQualityFilter.java
new file mode 100644
index 0000000..f07f197
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/ReassignOneMappingQualityFilter.java
@@ -0,0 +1,87 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+
+/**
+ * A read filter (transformer) that changes a given read mapping quality to a different value.
+ *
+ * <p>
+ * This read transformer will change a certain read mapping quality to a different value without affecting reads that
+ * have other mapping qualities. This is intended primarily for users of RNA-Seq data handling programs such
+ * as TopHat, which use MAPQ = 255 to designate uniquely aligned reads. According to convention, 255 normally
+ * designates "unknown" quality, and most GATK tools automatically ignore such reads. By reassigning a different
+ * mapping quality to those specific reads, users of TopHat and other tools can circumvent this problem without
+ * affecting the rest of their dataset.
+ * </p>
+ *
+ * <p>
+ * This differs from the ReassignMappingQuality filter by its selectivity -- only one mapping quality is targeted.
+ * ReassignMappingQuality will change ALL mapping qualities to a single one, and is typically used for datasets
+ * that have no assigned mapping qualities.
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * BAM file(s)
+ * </p>
+ *
+ *
+ * <h3>Output</h3>
+ * <p>
+ * BAM file(s) with one read mapping quality selectively reassigned as desired
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -jar GenomeAnalysisTK.jar
+ * -T PrintReads
+ * -rf ReassignOneMappingQuality
+ * -RMQF 255
+ * -RMQT 60
+ * </pre>
+ *
+ * @author vdauwera
+ * @since 2/19/13
+ */
+
+public class ReassignOneMappingQualityFilter extends ReadFilter {
+
+ @Argument(fullName = "reassign_mapping_quality_from", shortName = "RMQF", doc = "Original mapping quality", required = false)
+ public int reassignMappingQualityFrom = 255;
+
+ @Argument(fullName = "reassign_mapping_quality_to", shortName = "RMQT", doc = "Desired mapping quality", required = false)
+ public int reassignMappingQualityTo = 60;
+
+ public boolean filterOut(SAMRecord rec) {
+ if (rec.getMappingQuality() == reassignMappingQualityFrom)
+ rec.setMappingQuality(reassignMappingQualityTo);
+ return false;
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/SampleFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/SampleFilter.java
new file mode 100644
index 0000000..2ec0112
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/SampleFilter.java
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+
+import java.util.Set;
+
+/**
+ * Filter out all reads except those with this sample
+ */
+public class SampleFilter extends ReadFilter {
+ @Argument(fullName = "sample_to_keep", shortName = "goodSM", doc="The name of the sample(s) to keep, filtering out all others", required=true)
+ private Set SAMPLES_TO_KEEP = null;
+
+ public boolean filterOut( final SAMRecord read ) {
+ final SAMReadGroupRecord readGroup = read.getReadGroup();
+ return !( readGroup != null && SAMPLES_TO_KEEP.contains(readGroup.getSample()) );
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/SingleReadGroupFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/SingleReadGroupFilter.java
new file mode 100644
index 0000000..5a9d214
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/SingleReadGroupFilter.java
@@ -0,0 +1,48 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+
+/**
+ * Only use reads from the specified read group.
+ *
+ * @author rpoplin
+ * @since Nov 27, 2009
+ *
+ */
+
+public class SingleReadGroupFilter extends ReadFilter {
+ @Argument(fullName = "read_group_to_keep", shortName = "goodRG", doc="The name of the read group to keep, filtering out all others", required=true)
+ private String READ_GROUP_TO_KEEP = null;
+
+ public boolean filterOut( final SAMRecord read ) {
+ final SAMReadGroupRecord readGroup = read.getReadGroup();
+ return !( readGroup != null && readGroup.getReadGroupId().equals( READ_GROUP_TO_KEEP ) );
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/UnmappedReadFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/UnmappedReadFilter.java
new file mode 100644
index 0000000..e9cc302
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/UnmappedReadFilter.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Filter out unmapped reads.
+ *
+ * @author rpoplin
+ * @since Dec 9, 2009
+ */
+
+public class UnmappedReadFilter extends ReadFilter {
+ public boolean filterOut( final SAMRecord read ) {
+ return read.getReadUnmappedFlag() || read.getAlignmentStart() == SAMRecord.NO_ALIGNMENT_START;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/package-info.java
new file mode 100644
index 0000000..7e36ffb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/filters/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/DirectOutputTracker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/DirectOutputTracker.java
new file mode 100644
index 0000000..96c9cb2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/DirectOutputTracker.java
@@ -0,0 +1,48 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io;
+
+import org.broadinstitute.gatk.engine.io.storage.Storage;
+import org.broadinstitute.gatk.engine.io.storage.StorageFactory;
+import org.broadinstitute.gatk.engine.io.stubs.Stub;
+
+/**
+ * Maps creation of storage directly to output streams in parent.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class DirectOutputTracker extends OutputTracker {
+ public <T> T getStorage( Stub<T> stub ) {
+ Storage target = outputs.get(stub);
+ if( target == null ) {
+ target = StorageFactory.createStorage(stub);
+ outputs.put(stub, target);
+ }
+ return (T)target;
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/FastqFileWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/FastqFileWriter.java
new file mode 100644
index 0000000..772c327
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/FastqFileWriter.java
@@ -0,0 +1,77 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+
+/**
+ * User: carneiro
+ * Date: 1/27/13
+ * Time: 12:54 AM
+ */
+public class FastqFileWriter {
+ private PrintStream output;
+
+ public FastqFileWriter(String filename) {
+ try {
+ this.output = new PrintStream(filename);
+ } catch (FileNotFoundException e) {
+ throw new ReviewedGATKException("Can't open file " + filename);
+ }
+ }
+
+ public void addAlignment(GATKSAMRecord read) {
+ output.println("@" + read.getReadName());
+
+ if (read.getReadNegativeStrandFlag()) {
+ output.println(ReadUtils.getBasesReverseComplement(read));
+ output.println("+");
+ output.println(ReadUtils.convertReadQualToString(invertQuals(read.getBaseQualities())));
+ } else {
+ output.println(ReadUtils.convertReadBasesToString(read));
+ output.println("+");
+ output.println(ReadUtils.convertReadQualToString(read));
+ }
+ }
+
+ public void close() {
+ this.output.close();
+ }
+
+ private byte[] invertQuals (byte[] quals) {
+ final int l = quals.length;
+ byte[] invertedQuals = new byte[l];
+ for (int i=0; i<l; i++) {
+ invertedQuals[l-1-i] = quals[i];
+ }
+ return invertedQuals;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/GATKSAMFileWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/GATKSAMFileWriter.java
new file mode 100644
index 0000000..c60aae8
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/GATKSAMFileWriter.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMFileWriter;
+
+/**
+ * A writer that will allow unsorted BAM files to be written
+ * and sorted on-the-fly.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public interface GATKSAMFileWriter extends SAMFileWriter {
+ /**
+ * Writes the given custom header to SAM file output.
+ * @param header The header to write.
+ */
+ public void writeHeader(SAMFileHeader header);
+
+ /**
+ * Set Whether the BAM file to create is actually presorted.
+ * @param presorted True if the BAM file is presorted. False otherwise.
+ */
+ public void setPresorted(boolean presorted);
+
+ /**
+ * Set how many records in RAM the BAM file stores when sorting on-the-fly.
+ * @param maxRecordsInRam Max number of records in RAM.
+ */
+ public void setMaxRecordsInRam(int maxRecordsInRam);
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/OutputTracker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/OutputTracker.java
new file mode 100644
index 0000000..8f2fbe3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/OutputTracker.java
@@ -0,0 +1,178 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io;
+
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.ValidationStringency;
+import org.broadinstitute.gatk.utils.commandline.ArgumentSource;
+import org.broadinstitute.gatk.engine.io.storage.Storage;
+import org.broadinstitute.gatk.engine.io.storage.StorageFactory;
+import org.broadinstitute.gatk.engine.io.stubs.OutputStreamStub;
+import org.broadinstitute.gatk.engine.io.stubs.Stub;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.classloader.JVMUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.io.IOUtils;
+import org.broadinstitute.gatk.utils.sam.SAMFileReaderBuilder;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Manages the output and err streams that are created specifically for walker
+ * output.
+ */
+public abstract class OutputTracker {
+ /**
+ * The streams to which walker users should be reading directly.
+ */
+ protected Map<ArgumentSource, Object> inputs = new HashMap<ArgumentSource,Object>();
+
+ /**
+ * The streams to which walker users should be writing directly.
+ */
+ protected Map<Stub,Storage> outputs = new HashMap<Stub,Storage>();
+
+ /**
+ * Special-purpose stub. Provides a connection to output streams.
+ */
+ protected OutputStreamStub outStub = null;
+
+ /**
+ * Special-purpose stream. Provides a connection to error streams.
+ */
+ protected OutputStreamStub errStub = null;
+
+ /**
+ * Gets the output storage associated with a given stub.
+ * @param stub The stub for which to find / create the right output stream.
+ * @param <T> Type of the stream to create.
+ * @return Storage object with a facade of type T.
+ */
+ public abstract <T> T getStorage( Stub<T> stub );
+
+ public void prepareWalker( Walker walker, ValidationStringency strictnessLevel ) {
+ for( Map.Entry<ArgumentSource,Object> io: inputs.entrySet() ) {
+ ArgumentSource targetField = io.getKey();
+ Object targetValue = io.getValue();
+
+ // Ghastly hack: reaches in and finishes building out the SAMFileReader.
+ // TODO: Generalize this, and move it to its own initialization step.
+ if( targetValue instanceof SAMFileReaderBuilder) {
+ SAMFileReaderBuilder builder = (SAMFileReaderBuilder)targetValue;
+ builder.setValidationStringency(strictnessLevel);
+ targetValue = builder.build();
+ }
+
+ JVMUtils.setFieldValue( targetField.field, walker, targetValue );
+ }
+ }
+
+ /**
+ * Provide a mechanism for injecting supplemental streams for external management.
+ * @param argumentSource source Class / field into which to inject this stream.
+ * @param stub Stream to manage.
+ */
+ public void addInput( ArgumentSource argumentSource, Object stub ) {
+ inputs.put(argumentSource,stub);
+ }
+
+ /**
+ * Provide a mechanism for injecting supplemental streams for external management.
+ * @param stub Stream to manage.
+ */
+ public <T> void addOutput(Stub<T> stub) {
+ addOutput(stub,null);
+ }
+
+ /**
+ * Provide a mechanism for injecting supplemental streams for external management.
+ * @param stub Stream to manage.
+ */
+ public <T> void addOutput(Stub<T> stub, Storage<T> storage) {
+ stub.register(this);
+ outputs.put(stub,storage);
+ validateOutputPath(stub);
+ }
+
+ /**
+ * Close down all existing output streams.
+ */
+ public void close() {
+ for( Stub stub: outputs.keySet() ) {
+ // If the stream hasn't yet been created, create it so that there's at least an empty file present.
+ if( outputs.get(stub) == null )
+ getTargetStream(stub);
+
+ // Close down the storage.
+ outputs.get(stub).close();
+ }
+ }
+
+ /**
+ * Collects the target stream for this data.
+ * @param stub The stub for this stream.
+ * @param <T> type of stub.
+ * @return An instantiated file into which data can be written.
+ */
+ protected <T> T getTargetStream( Stub<T> stub ) {
+ if( !outputs.containsKey(stub) )
+ throw new ReviewedGATKException("OutputTracker was not notified that this stub exists: " + stub);
+ Storage<T> storage = outputs.get(stub);
+ if( storage == null ) {
+ storage = StorageFactory.createStorage(stub);
+ outputs.put(stub,storage);
+ }
+ return (T)storage;
+ }
+
+ /**
+ * Ensures that the File associated with this stub (if any) is in a writable location
+ * @param stub
+ */
+ protected <T> void validateOutputPath(final Stub<T> stub) {
+ if (stub.getOutputFile() != null && !(IOUtils.isSpecialFile(stub.getOutputFile()))) {
+ final File parentDir = stub.getOutputFile().getAbsoluteFile().getParentFile();
+ if (! (parentDir.canWrite() && parentDir.canExecute()))
+ throw new UserException.CouldNotCreateOutputFile(stub.getOutputFile(),
+ "either the containing directory doesn't exist or it isn't writable");
+ }
+ }
+
+ /**
+ * Install an OutputStreamStub into the given fieldName of the given walker.
+ * @param walker Walker into which to inject the field name.
+ * @param fieldName Name of the field into which to inject the stub.
+ */
+ private void installStub( Walker walker, String fieldName, OutputStream outputStream ) {
+ Field field = JVMUtils.findField( walker.getClass(), fieldName );
+ JVMUtils.setFieldValue( field, walker, outputStream );
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/ThreadGroupOutputTracker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/ThreadGroupOutputTracker.java
new file mode 100644
index 0000000..fdb5fd2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/ThreadGroupOutputTracker.java
@@ -0,0 +1,170 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io;
+
+import org.broadinstitute.gatk.engine.executive.OutputMergeTask;
+import org.broadinstitute.gatk.engine.io.storage.Storage;
+import org.broadinstitute.gatk.engine.io.storage.StorageFactory;
+import org.broadinstitute.gatk.engine.io.stubs.Stub;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An output tracker that can either track its output per-thread or directly.
+ *
+ * This output tracker doesn't use thread local values, but rather looks up the
+ * storage map via the thread's group. This is necessary in the case where
+ * there's a master thread that creates the output map, and spawns subthreads
+ * that actually do work. As long as those subthreads are spawned in the
+ * thread group of the master thread, this tracker will properly find the
+ * storage map associated with the master thread in the group, and return
+ * the map to all subthreads.
+ *
+ * @author mhanna, depristo
+ * @version 0.2
+ */
+public class ThreadGroupOutputTracker extends OutputTracker {
+ /**
+ * A map from thread ID of the master thread to the storage map from
+ * Stub to Storage objects
+ */
+ private Map<ThreadGroup, Map<Stub, Storage>> threadsToStorage = new HashMap<ThreadGroup, Map<Stub, Storage>>();
+
+ /**
+ * A total hack. If bypass = true, bypass thread local storage and write directly
+ * to the target file. Used to handle output during initialize() and onTraversalDone().
+ */
+ private boolean bypass = false;
+ public void bypassThreadLocalStorage(boolean bypass) {
+ this.bypass = bypass;
+ }
+
+ /**
+ * Initialize the storage map for this thread.
+ *
+ * Checks if there's a thread local binding for this thread, and if
+ * not initializes the map for it. This map is then
+ * populated with stub -> storage bindings according to the
+ * superclasses' outputs map.
+ *
+ * Must be called within the master thread to create a map associated with
+ * the master thread ID.
+ */
+ public synchronized void initializeStorage() {
+ final ThreadGroup group = Thread.currentThread().getThreadGroup();
+ Map<Stub,Storage> threadLocalOutputStreams = threadsToStorage.get(group);
+
+ if( threadLocalOutputStreams == null ) {
+ threadLocalOutputStreams = new HashMap<Stub,Storage>();
+ threadsToStorage.put( group, threadLocalOutputStreams );
+ }
+
+ for ( final Stub stub : outputs.keySet() ) {
+ final Storage target = StorageFactory.createStorage(stub, createTempFile(stub));
+ threadLocalOutputStreams.put(stub, target);
+ }
+ }
+
+ @Override
+ public <T> T getStorage( final Stub<T> stub ) {
+ Storage target;
+
+ if (bypass) {
+ target = outputs.get(stub);
+ if( target == null ) {
+ target = StorageFactory.createStorage(stub);
+ outputs.put(stub, target);
+ }
+ }
+ else {
+ final Map<Stub,Storage> threadLocalOutputStreams = findStorage(Thread.currentThread());
+ target = threadLocalOutputStreams.get(stub);
+
+ // make sure something hasn't gone wrong, and we somehow find a map that doesn't include our stub
+ if ( target == null )
+ throw new ReviewedGATKException("target isn't supposed to be null for " + Thread.currentThread()
+ + " id " + Thread.currentThread().getId() + " map is " + threadLocalOutputStreams);
+ }
+
+ return (T)target;
+ }
+
+
+ private synchronized Map<Stub,Storage> findStorage(final Thread thread) {
+ final Map<Stub, Storage> map = threadsToStorage.get(thread.getThreadGroup());
+
+ if ( map != null ) {
+ return map;
+ } else {
+ // something is terribly wrong, we have a storage lookup for a thread that doesn't have
+ // any map data associated with it!
+ throw new ReviewedGATKException("Couldn't find storage map associated with thread " + thread + " in group " + thread.getThreadGroup());
+ }
+ }
+
+ /**
+ * Close down any existing temporary files which have been opened.
+ */
+ public synchronized OutputMergeTask closeStorage() {
+ final Map<Stub,Storage> threadLocalOutputStreams = findStorage(Thread.currentThread());
+
+ if( threadLocalOutputStreams == null || threadLocalOutputStreams.isEmpty() )
+ return null;
+
+ final OutputMergeTask outputMergeTask = new OutputMergeTask();
+ for( Map.Entry<Stub,Storage> entry: threadLocalOutputStreams.entrySet() ) {
+ final Stub stub = entry.getKey();
+ final Storage storageEntry = entry.getValue();
+
+ storageEntry.close();
+ outputMergeTask.addMergeOperation(getTargetStream(stub), storageEntry);
+ }
+
+// logger.info("Closing " + Thread.currentThread().getId() + " => " + threadLocalOutputStreams);
+ threadLocalOutputStreams.clear();
+
+ return outputMergeTask;
+ }
+
+ /**
+ * Creates a temporary file for a stub of the given type.
+ * @param stub Stub for which to create a temporary file.
+ * @param <T> Type of the stub to accept.
+ * @return A temp file, or throw an exception if the temp file cannot be created.
+ */
+ private <T> File createTempFile( Stub<T> stub ) {
+ try {
+ return File.createTempFile( stub.getClass().getName(), null );
+ } catch( IOException ex ) {
+ throw new UserException.BadTmpDir("Unable to create temporary file for stub: " + stub.getClass().getName() );
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/OutputStreamStorage.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/OutputStreamStorage.java
new file mode 100644
index 0000000..ac348a2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/OutputStreamStorage.java
@@ -0,0 +1,144 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.storage;
+
+import org.broadinstitute.gatk.engine.io.stubs.OutputStreamStub;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.*;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.WritableByteChannel;
+
+public class OutputStreamStorage extends OutputStream implements Storage<OutputStream> {
+ /**
+ * File to which data will temporarily be written.
+ */
+ private final File file;
+
+ /**
+ * Stream to which data in this shard will be written.
+ */
+ private final OutputStream outputStream;
+
+ /**
+ * Create a new storage area with the given stub.
+ * @param stub
+ */
+ public OutputStreamStorage( OutputStreamStub stub ) {
+ if( stub.getOutputFile() != null ) {
+ this.file = stub.getOutputFile();
+ this.outputStream = initializeOutputStream(stub.getOutputFile());
+ }
+ else if( stub.getOutputStream() != null ) {
+ this.file = null;
+ this.outputStream = stub.getOutputStream();
+ }
+ else
+ throw new ReviewedGATKException("Not enough information to create storage for an OutputStream; need either a file or an existing output stream");
+ }
+
+ public OutputStreamStorage( OutputStreamStub stub, File file ) {
+ this.file = file;
+ this.outputStream = initializeOutputStream(file);
+ }
+
+ private OutputStream initializeOutputStream( File file ) {
+ try {
+ return new FileOutputStream( file );
+ }
+ catch(FileNotFoundException ex) {
+ throw new UserException.CouldNotCreateOutputFile(file, "Unable to open output stream for file", ex);
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void flush() throws IOException {
+ outputStream.flush();
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void close() {
+ // Don't close System.out or System.err; this'll cause trouble
+ // with subsequent code running in this VM.
+ if( outputStream == System.out || outputStream == System.err )
+ return;
+
+ try {
+ outputStream.close();
+ }
+ catch( IOException ex ) {
+ throw new UserException.CouldNotCreateOutputFile(file, "Unable to close output stream", ex );
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void write( byte[] b ) throws IOException {
+ outputStream.write(b);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void write( byte[] b, int off, int len ) throws IOException {
+ outputStream.write(b, off, len);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void write( int b ) throws IOException {
+ outputStream.write(b);
+ }
+
+
+ public void mergeInto( OutputStream targetStream ) {
+ FileInputStream sourceStream = null;
+ try {
+ sourceStream = new FileInputStream( file );
+ FileChannel sourceChannel = sourceStream.getChannel();
+
+ WritableByteChannel targetChannel = Channels.newChannel( targetStream );
+ sourceChannel.transferTo( 0, sourceChannel.size(), targetChannel );
+
+ sourceStream.close();
+ file.delete();
+ }
+ catch( FileNotFoundException ex ) {
+ throw new UserException.CouldNotReadInputFile(file, "Unable to open input stream for file", ex);
+ }
+ catch( IOException ex ) {
+ throw new UserException.CouldNotReadInputFile(file, "Unable to transfer contents of file", ex);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/SAMFileWriterStorage.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/SAMFileWriterStorage.java
new file mode 100644
index 0000000..3956e6e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/SAMFileWriterStorage.java
@@ -0,0 +1,157 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.storage;
+
+import htsjdk.samtools.*;
+import htsjdk.samtools.util.CloseableIterator;
+import htsjdk.samtools.util.ProgressLoggerInterface;
+import htsjdk.samtools.util.RuntimeIOException;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.io.stubs.SAMFileWriterStub;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.sam.SimplifyingSAMFileWriter;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Provides temporary storage for SAMFileWriters.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class SAMFileWriterStorage implements SAMFileWriter, Storage<SAMFileWriter> {
+ private final File file;
+ private SAMFileWriter writer;
+
+ private static Logger logger = Logger.getLogger(SAMFileWriterStorage.class);
+
+ public SAMFileWriterStorage( SAMFileWriterStub stub ) {
+ this(stub,stub.getOutputFile());
+ }
+
+ public SAMFileWriterStorage( SAMFileWriterStub stub, File file ) {
+ this.file = file;
+ SAMFileWriterFactory factory = new SAMFileWriterFactory();
+ // Enable automatic index creation for pre-sorted BAMs.
+ if (stub.getFileHeader().getSortOrder().equals(SAMFileHeader.SortOrder.coordinate) && stub.getIndexOnTheFly())
+ factory.setCreateIndex(true);
+ if (stub.getGenerateMD5())
+ factory.setCreateMd5File(true);
+ // Adjust max records in RAM.
+ // TODO -- this doesn't actually work because of a bug in Picard; do not use until fixed
+ if(stub.getMaxRecordsInRam() != null)
+ factory.setMaxRecordsInRam(stub.getMaxRecordsInRam());
+
+ if(stub.getOutputFile() != null) {
+ try {
+ this.writer = createBAMWriter(factory,stub.getFileHeader(),stub.isPresorted(),file,stub.getCompressionLevel());
+ }
+ catch(RuntimeIOException ex) {
+ throw new UserException.CouldNotCreateOutputFile(file,"file could not be created",ex);
+ }
+ }
+ else if(stub.getOutputStream() != null){
+ this.writer = factory.makeSAMWriter( stub.getFileHeader(), stub.isPresorted(), stub.getOutputStream());
+ }
+ else
+ throw new UserException("Unable to write to SAM file; neither a target file nor a stream has been specified");
+
+ // if we want to send the BAM file through the simplifying writer, wrap it here
+ if ( stub.simplifyBAM() ) {
+ this.writer = new SimplifyingSAMFileWriter(this.writer);
+ }
+ }
+
+ public SAMFileHeader getFileHeader() {
+ return writer.getFileHeader();
+ }
+
+ public void addAlignment( SAMRecord read ) {
+ writer.addAlignment(read);
+ }
+
+ public void close() {
+ try {
+ writer.close();
+ } catch (RuntimeIOException e) {
+ throw new UserException.ErrorWritingBamFile(e.getMessage());
+ }
+ }
+
+ public void mergeInto( SAMFileWriter targetStream ) {
+ SAMFileReader reader = new SAMFileReader( file );
+ try {
+ CloseableIterator<SAMRecord> iterator = reader.iterator();
+ while( iterator.hasNext() )
+ targetStream.addAlignment( iterator.next() );
+ iterator.close();
+ }
+ finally {
+ reader.close();
+ file.delete();
+ }
+ }
+
+ private SAMFileWriter createBAMWriter(final SAMFileWriterFactory factory,
+ final SAMFileHeader header,
+ final boolean presorted,
+ final File outputFile,
+ final Integer compressionLevel) {
+ SAMFileWriter writer;
+ if(compressionLevel != null)
+ writer = factory.makeBAMWriter(header, presorted, outputFile, compressionLevel);
+ else
+ writer = factory.makeBAMWriter(header, presorted, outputFile);
+
+ // mhanna - 1 Mar 2011 - temporary hack until Picard generates an index file for empty BAMs --
+ // - do a pre-initialization of the BAM file.
+ try {
+ Method prepareToWriteAlignmentsMethod = writer.getClass().getDeclaredMethod("prepareToWriteAlignments");
+ if(prepareToWriteAlignmentsMethod != null) {
+ prepareToWriteAlignmentsMethod.setAccessible(true);
+ prepareToWriteAlignmentsMethod.invoke(writer);
+ }
+ }
+ catch(NoSuchMethodException ex) {
+ logger.info("Unable to call prepareToWriteAlignments method; this should be reviewed when Picard is updated.");
+ }
+ catch(IllegalAccessException ex) {
+ logger.info("Unable to access prepareToWriteAlignments method; this should be reviewed when Picard is updated.");
+ }
+ catch(InvocationTargetException ex) {
+ logger.info("Unable to invoke prepareToWriteAlignments method; this should be reviewed when Picard is updated.");
+ }
+
+ return writer;
+ }
+
+ @Override
+ public void setProgressLogger(final ProgressLoggerInterface logger) {
+ writer.setProgressLogger(logger);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/Storage.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/Storage.java
new file mode 100644
index 0000000..363b70f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/Storage.java
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.storage;
+
+/**
+ * An interface representing the temporary storage of data.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public interface Storage<StreamType> {
+ /**
+ * Writing to the temporary storage is done. Close down the file.
+ */
+ public void close();
+
+ /**
+ * Merges the stream backing up this temporary storage into the target.
+ * @param target Target stream for the temporary storage. May not be null.
+ */
+ public void mergeInto( StreamType target );
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/StorageFactory.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/StorageFactory.java
new file mode 100644
index 0000000..3396006
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/StorageFactory.java
@@ -0,0 +1,92 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.storage;
+
+import org.broadinstitute.gatk.engine.io.stubs.OutputStreamStub;
+import org.broadinstitute.gatk.engine.io.stubs.SAMFileWriterStub;
+import org.broadinstitute.gatk.engine.io.stubs.Stub;
+import org.broadinstitute.gatk.engine.io.stubs.VariantContextWriterStub;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+
+/**
+ * Construct storage of the required type.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class StorageFactory {
+ /**
+ * Disable storage factory construction.
+ */
+ private StorageFactory() {}
+
+ /**
+ * Gets the output storage associated with a given stub.
+ * @param stub The stub for which to find / create the right output stream.
+ * @param <T> Type of the stream to create.
+ * @return Storage object with a facade of type T.
+ */
+ public static <T> Storage<T> createStorage( Stub<T> stub ) {
+ return createStorage( stub, null );
+ }
+
+ /**
+ * Gets the output storage associated with a given stub.
+ * @param stub The stub for which to find / create the right output stream.
+ * @param file The filename to which to write the file.
+ * @param <T> Type of the stream to create.
+ * @return Storage object with a facade of type T.
+ */
+ public static <T> Storage<T> createStorage( Stub<T> stub, File file ) {
+ Storage storage;
+
+ if(stub instanceof OutputStreamStub) {
+ if( file != null )
+ storage = new OutputStreamStorage((OutputStreamStub)stub,file);
+ else
+ storage = new OutputStreamStorage((OutputStreamStub)stub);
+ }
+ else if(stub instanceof SAMFileWriterStub) {
+ if( file != null )
+ storage = new SAMFileWriterStorage((SAMFileWriterStub)stub,file);
+ else
+ storage = new SAMFileWriterStorage((SAMFileWriterStub)stub);
+ }
+ else if(stub instanceof VariantContextWriterStub) {
+ VariantContextWriterStub vcfWriterStub = (VariantContextWriterStub)stub;
+ if( file != null )
+ storage = new VariantContextWriterStorage(vcfWriterStub,file);
+ else
+ storage = new VariantContextWriterStorage(vcfWriterStub);
+ }
+ else
+ throw new ReviewedGATKException("Unsupported stub type: " + stub.getClass().getName());
+
+ return storage;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/VariantContextWriterStorage.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/VariantContextWriterStorage.java
new file mode 100644
index 0000000..c4f7769
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/storage/VariantContextWriterStorage.java
@@ -0,0 +1,228 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.storage;
+
+import htsjdk.samtools.util.BlockCompressedOutputStream;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.AbstractFeatureReader;
+import htsjdk.tribble.Feature;
+import htsjdk.tribble.FeatureCodec;
+import org.broadinstitute.gatk.engine.io.stubs.VariantContextWriterStub;
+import org.broadinstitute.gatk.engine.refdata.tracks.FeatureManager;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import htsjdk.variant.bcf2.BCF2Utils;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.writer.Options;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.variantcontext.writer.VariantContextWriterFactory;
+import htsjdk.variant.vcf.VCFHeader;
+
+import java.io.*;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+
+/**
+ * Provides temporary and permanent storage for genotypes in VCF format.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class VariantContextWriterStorage implements Storage<VariantContextWriterStorage>, VariantContextWriter {
+ /**
+ * our log, which we want to capture anything from this class
+ */
+ private static Logger logger = Logger.getLogger(VariantContextWriterStorage.class);
+
+ private final static int BUFFER_SIZE = 1048576;
+
+ protected final File file;
+ protected OutputStream stream;
+ protected final VariantContextWriter writer;
+ boolean closed = false;
+
+ /**
+ * Constructs an object which will write directly into the output file provided by the stub.
+ * Intentionally delaying the writing of the header -- this should be filled in by the walker.
+ *
+ * Respecs the isCompressed() request in stub, so if isCompressed() is true then this
+ * will create a storage output that dumps output to a BlockCompressedOutputStream.
+ *
+ * @param stub Stub to use when constructing the output file.
+ */
+ public VariantContextWriterStorage(VariantContextWriterStub stub) {
+ if ( stub.getOutputFile() != null ) {
+ this.file = stub.getOutputFile();
+ writer = vcfWriterToFile(stub,stub.getOutputFile(),true,true);
+ }
+ else if ( stub.getOutputStream() != null ) {
+ this.file = null;
+ this.stream = stub.getOutputStream();
+ writer = VariantContextWriterFactory.create(stream,
+ stub.getMasterSequenceDictionary(), stub.getWriterOptions(false));
+ }
+ else
+ throw new ReviewedGATKException("Unable to create target to which to write; storage was provided with neither a file nor a stream.");
+ }
+
+ /**
+ * Constructs an object which will redirect into a different file.
+ *
+ * Note that this function does not respect the isCompressed() request from the stub, in order
+ * to ensure that tmp. files can be read back in by the Tribble system, and merged with the mergeInto function.
+ *
+ * @param stub Stub to use when synthesizing file / header info.
+ * @param tempFile File into which to direct the output data.
+ */
+ public VariantContextWriterStorage(VariantContextWriterStub stub, File tempFile) {
+ //logger.debug("Creating temporary output file " + tempFile.getAbsolutePath() + " for VariantContext output.");
+ this.file = tempFile;
+ this.writer = vcfWriterToFile(stub, file, false, false);
+ writer.writeHeader(stub.getVCFHeader());
+ }
+
+ /**
+ * common initialization routine for multiple constructors
+ * @param stub Stub to use when constructing the output file.
+ * @param file Target file into which to write VCF records.
+ * @param indexOnTheFly true to index the file on the fly. NOTE: will be forced to false for compressed files.
+ * @param allowCompressed if false, we won't compress the output, even if the stub requests it. Critical
+ * for creating temp. output files that will be subsequently merged, as these do not
+ * support compressed output
+ * @return A VCF writer for use with this class
+ */
+ private VariantContextWriter vcfWriterToFile(final VariantContextWriterStub stub,
+ final File file,
+ final boolean indexOnTheFly,
+ final boolean allowCompressed) {
+ try {
+ // we cannot merge compressed outputs, so don't compress if allowCompressed is false,
+ // which is the case when we have a temporary output file for later merging
+ if ( allowCompressed && stub.isCompressed() )
+ stream = new BlockCompressedOutputStream(file);
+ else
+ stream = new PrintStream(new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE));
+ }
+ catch(IOException ex) {
+ throw new UserException.CouldNotCreateOutputFile(file, "Unable to open target output stream", ex);
+ }
+
+ EnumSet<Options> options = stub.getWriterOptions(indexOnTheFly);
+ VariantContextWriter writer = VariantContextWriterFactory.create(file, this.stream, stub.getMasterSequenceDictionary(), stub.getIndexCreator(), options);
+
+ // if the stub says to test BCF, create a secondary writer to BCF and an 2 way out writer to send to both
+ // TODO -- remove me when argument generateShadowBCF is removed
+ if ( stub.alsoWriteBCFForTest() && ! VariantContextWriterFactory.isBCFOutput(file, options)) {
+ final File bcfFile = BCF2Utils.shadowBCF(file);
+ if ( bcfFile != null ) {
+ FileOutputStream bcfStream;
+ try {
+ bcfStream = new FileOutputStream(bcfFile);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(bcfFile + ": Unable to create BCF writer", e);
+ }
+
+ VariantContextWriter bcfWriter = VariantContextWriterFactory.create(bcfFile, bcfStream, stub.getMasterSequenceDictionary(), stub.getIndexCreator(), options);
+ writer = new TestWriter(writer, bcfWriter);
+ }
+ }
+
+ return writer;
+ }
+
+ private final static class TestWriter implements VariantContextWriter {
+ final List<VariantContextWriter> writers;
+
+ private TestWriter(final VariantContextWriter ... writers) {
+ this.writers = Arrays.asList(writers);
+ }
+
+ @Override
+ public void writeHeader(final VCFHeader header) {
+ for ( final VariantContextWriter writer : writers ) writer.writeHeader(header);
+ }
+
+ @Override
+ public void close() {
+ for ( final VariantContextWriter writer : writers ) writer.close();
+ }
+
+ @Override
+ public void add(final VariantContext vc) {
+ for ( final VariantContextWriter writer : writers ) writer.add(vc);
+ }
+ }
+
+ public void add(VariantContext vc) {
+ if ( closed ) throw new ReviewedGATKException("Attempting to write to a closed VariantContextWriterStorage " + vc.getStart() + " storage=" + this);
+ writer.add(vc);
+ }
+
+ /**
+ * initialize this VCF header
+ *
+ * @param header the header
+ */
+ public void writeHeader(VCFHeader header) {
+ writer.writeHeader(header);
+ }
+
+ /**
+ * Close the VCF storage object.
+ */
+ public void close() {
+ writer.close();
+ closed = true;
+ }
+
+ public void mergeInto(VariantContextWriterStorage target) {
+ try {
+ if ( ! closed )
+ throw new ReviewedGATKException("Writer not closed, but we are merging into the file!");
+ final String targetFilePath = target.file != null ? target.file.getAbsolutePath() : "/dev/stdin";
+ logger.debug(String.format("Merging VariantContextWriterStorage from %s into %s", file.getAbsolutePath(), targetFilePath));
+
+ // use the feature manager to determine the right codec for the tmp file
+ // that way we don't assume it's a specific type
+ final FeatureManager.FeatureDescriptor fd = new FeatureManager().getByFiletype(file);
+ if ( fd == null )
+ throw new UserException.LocalParallelizationProblem(file);
+
+ final FeatureCodec codec = fd.getCodec();
+ final AbstractFeatureReader<Feature, ?> source = AbstractFeatureReader.getFeatureReader(file.getAbsolutePath(), codec, false);
+
+ for ( final Feature vc : source.iterator() ) {
+ target.writer.add((VariantContext) vc);
+ }
+
+ source.close();
+ file.delete(); // this should be last to aid in debugging when the process fails
+ } catch (IOException e) {
+ throw new UserException.CouldNotReadInputFile(file, "Error reading file in VCFWriterStorage: ", e);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/OutputStreamArgumentTypeDescriptor.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/OutputStreamArgumentTypeDescriptor.java
new file mode 100644
index 0000000..89b8b59
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/OutputStreamArgumentTypeDescriptor.java
@@ -0,0 +1,134 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.stubs;
+
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.exceptions.DynamicClassResolutionException;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Type;
+
+/**
+ * Insert an OutputStreamStub instead of a full-fledged concrete OutputStream implementations.
+ */
+public class OutputStreamArgumentTypeDescriptor extends ArgumentTypeDescriptor {
+ /**
+ * The engine into which output stubs should be fed.
+ */
+ private final GenomeAnalysisEngine engine;
+
+ /**
+ * The default output stream to write to write this info if
+ */
+ private final OutputStream defaultOutputStream;
+
+ /**
+ * Create a new OutputStream argument, notifying the given engine when that argument has been created.
+ * @param engine Engine to add SAMFileWriter output to.
+ * @param defaultOutputStream Default target for output file.
+ */
+ public OutputStreamArgumentTypeDescriptor(GenomeAnalysisEngine engine,OutputStream defaultOutputStream) {
+ this.engine = engine;
+ this.defaultOutputStream = defaultOutputStream;
+ }
+
+ @Override
+ public boolean supports( Class type ) {
+ return getConstructorForClass(type) != null;
+ }
+
+ @Override
+ public boolean createsTypeDefault(ArgumentSource source) {
+ return !source.isRequired() && source.defaultsToStdout();
+ }
+
+ @Override
+ public String typeDefaultDocString(ArgumentSource source) {
+ return "stdout";
+ }
+
+ @Override
+ public Object createTypeDefault(ParsingEngine parsingEngine,ArgumentSource source, Type type) {
+ if(source.isRequired() || !source.defaultsToStdout())
+ throw new ReviewedGATKException("BUG: tried to create type default for argument type descriptor that can't support a type default.");
+ OutputStreamStub stub = new OutputStreamStub(defaultOutputStream);
+ engine.addOutput(stub);
+ return createInstanceOfClass((Class)type,stub);
+ }
+
+ @Override
+ public Object parse( ParsingEngine parsingEngine, ArgumentSource source, Type type, ArgumentMatches matches ) {
+ ArgumentDefinition definition = createDefaultArgumentDefinition(source);
+ String fileName = getArgumentValue( definition, matches ).asString();
+
+ // This parser has been passed a null filename and the GATK is not responsible for creating a type default for the object;
+ // therefore, the user must have failed to specify a type default
+ if(fileName == null && source.isRequired())
+ throw new MissingArgumentValueException(definition);
+
+ OutputStreamStub stub = new OutputStreamStub(new File(fileName));
+
+ engine.addOutput(stub);
+
+ Object result = createInstanceOfClass(makeRawTypeIfNecessary(type),stub);
+ // WARNING: Side effects required by engine!
+ parsingEngine.addTags(result,getArgumentTags(matches));
+
+ return result;
+ }
+
+ /**
+ * Retrieves the constructor for an object that takes exactly one argument: an output stream.
+ * @param type Type for which to go constructor spelunking.
+ * @return Constructor, if available. Null, if not.
+ */
+ private Constructor<OutputStream> getConstructorForClass( Class type ) {
+ try {
+ return type.getConstructor( OutputStream.class );
+ }
+ catch( NoSuchMethodException ex ) {
+ return null;
+ }
+ }
+
+ /**
+ * Creat a new instance of the class accepting a single outputstream constructor.
+ * @param type Type of object to create.
+ * @param outputStream resulting output stream.
+ * @return A new instance of the outputstream-derived class.
+ */
+ private Object createInstanceOfClass(Class type,OutputStream outputStream) {
+ try {
+ return getConstructorForClass(type).newInstance(outputStream);
+ } catch (Exception e) {
+ throw new DynamicClassResolutionException(type, e);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/OutputStreamStub.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/OutputStreamStub.java
new file mode 100644
index 0000000..2f64dc2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/OutputStreamStub.java
@@ -0,0 +1,142 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.stubs;
+
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.engine.io.OutputTracker;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A stub for routing and management of anything backed by an OutputStream.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class OutputStreamStub extends OutputStream implements Stub<OutputStream> {
+ /**
+ * The file that this stub should write to. Should be passed along to
+ * whatever happens to create storage for this stub. Might be null, if
+ * this stub connects directly to an existing stream.
+ */
+ private final File targetFile;
+
+ /**
+ * The stream that this stub should write to. Should be passed along to
+ * whatever happens to create storage for this stub. Might be null, if
+ * this stub connects directly to an existing stream.
+ */
+ private final OutputStream targetStream;
+
+ /**
+ * Connects this stub with an external stream capable of serving the
+ * requests of the consumer of this stub.
+ */
+ private OutputTracker outputTracker = null;
+
+ /**
+ * Specify that this target output stream should write to the given file.
+ * @param targetFile Target file to which to write. Should not be null.
+ */
+ public OutputStreamStub( File targetFile ) {
+ this.targetFile = targetFile;
+ this.targetStream = null;
+ }
+
+ /**
+ * Specify that this target output stream should write to the given stream.
+ * @param targetStream Target stream to which to write. Should not be null.
+ */
+ public OutputStreamStub( OutputStream targetStream ) {
+ this.targetFile = null;
+ this.targetStream = targetStream;
+ }
+
+
+ /**
+ * Return the target file to which this data should be written.
+ * @return Target file. No sanity checking will have been performed by the file object.
+ */
+ public File getOutputFile() {
+ return targetFile;
+ }
+
+ /**
+ * Return the target stream to which this data should be written.
+ * @return Target stream. No sanity checking will have been performed by the file object.
+ */
+ public OutputStream getOutputStream() {
+ return targetStream;
+ }
+
+ /**
+ * Registers the given streamConnector with this stub.
+ * @param outputTracker The connector used to provide an appropriate stream.
+ */
+ public void register( OutputTracker outputTracker ) {
+ this.outputTracker = outputTracker;
+ }
+
+ @Override
+ public void processArguments( final GATKArgumentCollection argumentCollection ) {}
+
+ /**
+ * @{inheritDoc}
+ */
+ public void flush() throws IOException {
+ outputTracker.getStorage(this).flush();
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void close() throws IOException {
+ outputTracker.getStorage(this).close();
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void write( byte[] b ) throws IOException {
+ outputTracker.getStorage(this).write(b);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void write( byte[] b, int off, int len ) throws IOException {
+ outputTracker.getStorage(this).write(b, off, len);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void write( int b ) throws IOException {
+ outputTracker.getStorage(this).write(b);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/SAMFileReaderArgumentTypeDescriptor.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/SAMFileReaderArgumentTypeDescriptor.java
new file mode 100644
index 0000000..42397cb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/SAMFileReaderArgumentTypeDescriptor.java
@@ -0,0 +1,77 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.stubs;
+
+import htsjdk.samtools.SAMFileReader;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.sam.SAMFileReaderBuilder;
+
+import java.lang.reflect.Type;
+
+/**
+ * Describe how to parse SAMFileReaders.
+ */
+public class SAMFileReaderArgumentTypeDescriptor extends ArgumentTypeDescriptor {
+ /**
+ * The engine into which output stubs should be fed.
+ */
+ private GenomeAnalysisEngine engine;
+
+ /**
+ * Create a new SAMFileReader argument, notifying the given engine when that argument has been created.
+ * @param engine engine
+ */
+ public SAMFileReaderArgumentTypeDescriptor( GenomeAnalysisEngine engine ) {
+ this.engine = engine;
+ }
+
+ @Override
+ public boolean supports( Class type ) {
+ return SAMFileReader.class.isAssignableFrom(type);
+ }
+
+ @Override
+ public Object parse( ParsingEngine parsingEngine, ArgumentSource source, Type type, ArgumentMatches matches ) {
+ SAMFileReaderBuilder builder = new SAMFileReaderBuilder();
+
+ ArgumentMatchValue readerFileName = getArgumentValue( createDefaultArgumentDefinition(source), matches );
+
+ if( readerFileName == null )
+ throw new UserException.CommandLineException("SAM file compression was supplied, but no associated writer was supplied with it.");
+
+ builder.setSAMFile(readerFileName.asFile());
+
+ // WARNING: Skipping required side-effect because stub is impossible to generate.
+ engine.addInput(source, builder);
+
+ // MASSIVE KLUDGE! SAMFileReader is tricky to implement and we don't yet have a stub. Return null, then
+ // let the output tracker load it in.
+ // TODO: Add a stub for SAMFileReader.
+ return null;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/SAMFileWriterArgumentTypeDescriptor.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/SAMFileWriterArgumentTypeDescriptor.java
new file mode 100644
index 0000000..c454324
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/SAMFileWriterArgumentTypeDescriptor.java
@@ -0,0 +1,106 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.stubs;
+
+import htsjdk.samtools.SAMFileWriter;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.io.GATKSAMFileWriter;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.OutputStream;
+import java.lang.reflect.Type;
+
+/**
+ * Insert a SAMFileWriterStub instead of a full-fledged concrete OutputStream implementations.
+ */
+public class SAMFileWriterArgumentTypeDescriptor extends ArgumentTypeDescriptor {
+
+ /**
+ * The engine into which output stubs should be fed.
+ */
+ private final GenomeAnalysisEngine engine;
+
+ /**
+ * The default location to which data should be written if the user specifies no such location.
+ */
+ private final OutputStream defaultOutputStream;
+
+ /**
+ * Create a new SAMFileWriter argument, notifying the given engine when that argument has been created.
+ * @param engine Engine to add SAMFileWriter output to.
+ * @param defaultOutputStream the target for the data
+ */
+ public SAMFileWriterArgumentTypeDescriptor( GenomeAnalysisEngine engine, OutputStream defaultOutputStream ) {
+ this.engine = engine;
+ this.defaultOutputStream = defaultOutputStream;
+ }
+
+ @Override
+ public boolean supports( Class type ) {
+ return SAMFileWriter.class.equals(type) || GATKSAMFileWriter.class.equals(type);
+ }
+
+ @Override
+ public boolean createsTypeDefault(ArgumentSource source) {
+ return !source.isRequired() && source.defaultsToStdout();
+ }
+
+ @Override
+ public String typeDefaultDocString(ArgumentSource source) {
+ return "stdout";
+ }
+
+ @Override
+ public Object createTypeDefault(ParsingEngine parsingEngine,ArgumentSource source, Type type) {
+ if(source.isRequired() || !source.defaultsToStdout())
+ throw new ReviewedGATKException("BUG: tried to create type default for argument type descriptor that can't support a type default.");
+ SAMFileWriterStub stub = new SAMFileWriterStub(engine,defaultOutputStream);
+ engine.addOutput(stub);
+ return stub;
+ }
+
+ @Override
+ public Object parse( ParsingEngine parsingEngine, ArgumentSource source, Type type, ArgumentMatches matches ) {
+ // Extract all possible parameters that could be passed to a BAM file writer?
+ ArgumentDefinition bamArgumentDefinition = createDefaultArgumentDefinition(source);
+ ArgumentMatchValue writerFileName = getArgumentValue( bamArgumentDefinition, matches );
+
+ // Create the stub
+ SAMFileWriterStub stub = null; // stub = new SAMFileWriterStub(engine, defaultOutputStream);
+
+ if (writerFileName != null && writerFileName.asFile() != null ) {
+ stub = new SAMFileWriterStub(engine, writerFileName.asFile());
+
+ // WARNING: Side effects required by engine!
+ parsingEngine.addTags(stub,getArgumentTags(matches));
+ engine.addOutput(stub);
+ }
+
+ return stub;
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/SAMFileWriterStub.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/SAMFileWriterStub.java
new file mode 100644
index 0000000..cc814e9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/SAMFileWriterStub.java
@@ -0,0 +1,336 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.stubs;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMFileWriter;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.ProgressLoggerInterface;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.engine.io.OutputTracker;
+import org.broadinstitute.gatk.engine.io.GATKSAMFileWriter;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.utils.baq.BAQ;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A stub for routing and management of SAM file reading and writing.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class SAMFileWriterStub implements Stub<SAMFileWriter>, GATKSAMFileWriter {
+ /**
+ * Engine to use for collecting attributes for the output SAM file.
+ */
+ private final GenomeAnalysisEngine engine;
+
+ /**
+ * A header supplied by the user that overrides the merged header from the input BAM.
+ */
+ private SAMFileHeader headerOverride = null;
+
+ /**
+ * The sam file that this stub should write to. Should be passed along to
+ * whatever happens to create the StreamConnector.
+ */
+ private final File samFile;
+
+ /**
+ * The target output stream, to be used in place of the SAM file.
+ */
+ private final OutputStream samOutputStream;
+
+ /**
+ * The validation stringency to apply when reading this file.
+ */
+ private Integer compressionLevel = null;
+
+ /**
+ * Should the GATK index the output BAM on-the-fly?
+ */
+ private boolean indexOnTheFly = false;
+
+ /**
+ * Should the GATK generate an md5 for the output BAM?
+ */
+ private boolean generateMD5 = false;
+
+ /**
+ * Should this BAM be presorted?
+ */
+ private boolean presorted = true;
+
+ /**
+ * How many records should the BAM writer store in RAM while
+ * sorting the BAM on-the-fly?
+ */
+ private Integer maxRecordsInRam = null;
+
+ /**
+ * Connects this stub with an external stream capable of serving the
+ * requests of the consumer of this stub.
+ */
+ private OutputTracker outputTracker = null;
+
+ /**
+ * Has the write started? If so, throw an exception if someone tries to
+ * change write parameters to the file (compression level, presorted flag,
+ * header, etc).
+ */
+ private boolean writeStarted = false;
+
+
+ /**
+ * HMM for BAQ, if needed
+ */
+ BAQ baqHMM = new BAQ();
+
+ /**
+ * Should we simplify the BAM file while writing it out?
+ */
+ private boolean simplifyBAM = false;
+
+ private List<ReadTransformer> onOutputReadTransformers = null;
+
+ /**
+ * Create a new stub given the requested SAM file and compression level.
+ * @param engine source of header data, maybe other data about input files.
+ * @param samFile SAM file to (ultimately) create.
+ */
+ public SAMFileWriterStub( GenomeAnalysisEngine engine, File samFile ) {
+ this(engine, samFile, null);
+ }
+
+ /**
+ * Create a new stub given the requested SAM file and compression level.
+ * @param engine source of header data, maybe other data about input files.
+ * @param stream Output stream to which data should be written.
+ */
+ public SAMFileWriterStub( GenomeAnalysisEngine engine, OutputStream stream ) {
+ this(engine, null, stream);
+ }
+
+ private SAMFileWriterStub(final GenomeAnalysisEngine engine, final File samFile, final OutputStream stream) {
+ this.engine = engine;
+ this.samFile = samFile;
+ this.samOutputStream = stream;
+ }
+
+ /**
+ * Retrieves the SAM file to (ultimately) be created.
+ * @return The SAM file. Must not be null.
+ */
+ public File getOutputFile() {
+ return samFile;
+ }
+
+ public boolean simplifyBAM() {
+ return simplifyBAM;
+ }
+
+ public void setSimplifyBAM(boolean v) {
+ simplifyBAM = v;
+ }
+
+ public OutputStream getOutputStream() {
+ return samOutputStream;
+ }
+
+ /**
+ * Retrieves the header to use when creating the new SAM file.
+ * @return header to use when creating the new SAM file.
+ */
+ public SAMFileHeader getFileHeader() {
+ return headerOverride != null ? headerOverride : engine.getSAMFileHeader();
+ }
+
+ /**
+ * Retrieves the desired compression level for
+ * @return The current compression level. Could be null if the user doesn't care.
+ */
+ public Integer getCompressionLevel() {
+ return compressionLevel;
+ }
+
+ /**
+ * Sets the desired compression level.
+ * @param compressionLevel The suggested compression level.
+ */
+ public void setCompressionLevel( Integer compressionLevel ) {
+ if(writeStarted)
+ throw new ReviewedGATKException("Attempted to change the compression level of a file with alignments already in it.");
+ this.compressionLevel = compressionLevel;
+ }
+
+ /**
+ * Gets whether to index this output stream on-the-fly.
+ * @return True means create an index. False means skip index creation.
+ */
+ public Boolean getIndexOnTheFly() {
+ return indexOnTheFly;
+ }
+
+ /**
+ * Controls whether to index this output stream on-the-fly.
+ * @param indexOnTheFly True means create an index. False means skip index creation.
+ */
+ public void setIndexOnTheFly( boolean indexOnTheFly ) {
+ if(writeStarted)
+ throw new UserException("Attempted to index a BAM on the fly of a file with alignments already in it.");
+ this.indexOnTheFly = indexOnTheFly;
+ }
+
+ /**
+ * Gets whether to generate an md5 on-the-fly for this BAM.
+ * @return True generates the md5. False means skip writing the file.
+ */
+ public Boolean getGenerateMD5() {
+ return generateMD5;
+ }
+
+ /**
+ * Gets whether to generate an md5 on-the-fly for this BAM.
+ * @param generateMD5 True generates the md5. False means skip writing the file.
+ */
+ public void setGenerateMD5(boolean generateMD5) {
+ if(writeStarted)
+ throw new UserException("Attempted to turn on md5 generation for BAM file with alignments already in it.");
+ this.generateMD5 = generateMD5;
+ }
+
+ /**
+ * Whether the BAM file to create is actually presorted.
+ * @return True if the BAM file is presorted. False otherwise.
+ */
+ public boolean isPresorted() {
+ return this.presorted;
+ }
+
+ /**
+ * Set Whether the BAM file to create is actually presorted.
+ * @param presorted True if the BAM file is presorted. False otherwise.
+ */
+ public void setPresorted(boolean presorted) {
+ if(writeStarted)
+ throw new ReviewedGATKException("Attempted to change the presorted state of a file with alignments already in it.");
+ this.presorted = presorted;
+ }
+
+ /**
+ * Get the maximum number of reads to hold in RAM when sorting a BAM on-the-fly.
+ * @return Max records in RAM, or null if unset.
+ */
+ public Integer getMaxRecordsInRam() {
+ return this.maxRecordsInRam;
+ }
+
+ /**
+ * Sets the maximum number of reads to hold in RAM when sorting a BAM on-the-fly.
+ * @param maxRecordsInRam Max number of records in RAM.
+ */
+ public void setMaxRecordsInRam(int maxRecordsInRam) {
+ if(writeStarted)
+ throw new ReviewedGATKException("Attempted to change the max records in RAM of a file with alignments already in it.");
+ this.maxRecordsInRam = maxRecordsInRam;
+ }
+
+ /**
+ * Registers the given streamConnector with this stub.
+ * @param outputTracker The connector used to provide an appropriate stream.
+ */
+ public void register( OutputTracker outputTracker ) {
+ this.outputTracker = outputTracker;
+ }
+
+ @Override
+ public void processArguments( final GATKArgumentCollection argumentCollection ) {
+ if (argumentCollection.bamCompression != null)
+ setCompressionLevel(argumentCollection.bamCompression);
+ setGenerateMD5(argumentCollection.enableBAMmd5);
+ setIndexOnTheFly(!argumentCollection.disableBAMIndexing);
+ setSimplifyBAM(argumentCollection.simplifyBAM);
+
+ }
+
+ /**
+ * Use the given header as the target for this writer.
+ * @param header The header to write.
+ */
+ public void writeHeader(SAMFileHeader header) {
+ if(writeStarted)
+ throw new ReviewedGATKException("Attempted to change the header of a file with alignments already in it.");
+ this.headerOverride = header;
+ }
+
+ private void initializeReadTransformers() {
+ this.onOutputReadTransformers = new ArrayList<>(engine.getReadTransformers().size());
+ for ( final ReadTransformer transformer : engine.getReadTransformers() ) {
+ if ( transformer.getApplicationTime() == ReadTransformer.ApplicationTime.ON_OUTPUT )
+ onOutputReadTransformers.add(transformer);
+ }
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void addAlignment( final SAMRecord readIn ) {
+ if ( onOutputReadTransformers == null )
+ initializeReadTransformers();
+
+ GATKSAMRecord workingRead = (GATKSAMRecord)readIn;
+
+ // run on output read transformers
+ for ( final ReadTransformer transform : onOutputReadTransformers )
+ workingRead = transform.apply(workingRead);
+
+ writeStarted = true;
+ outputTracker.getStorage(this).addAlignment(workingRead);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void close() {
+ outputTracker.getStorage(this).close();
+ }
+
+ /**
+ * @throws java.lang.UnsupportedOperationException No progress logging in this implementation.
+ */
+ @Override
+ public void setProgressLogger(final ProgressLoggerInterface logger) {
+ throw new UnsupportedOperationException("Progress logging not supported");
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/Stub.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/Stub.java
new file mode 100644
index 0000000..8a00007
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/Stub.java
@@ -0,0 +1,69 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.stubs;
+
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.engine.io.OutputTracker;
+
+import java.io.File;
+import java.io.OutputStream;
+
+/**
+ * A stub used for managing IO. Acts as a proxy for IO streams
+ * not yet created or streams that need significant external
+ * management.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public interface Stub<StreamType> {
+ /**
+ * Provides a facility to register this stream with the given
+ * StreamConnector. The stub should route each output method
+ * to the specified connector.
+ * @param outputTracker The connector used to provide an appropriate stream.
+ */
+ public void register( OutputTracker outputTracker );
+
+ /**
+ * Provides a mechanism for uniformly processing command-line arguments
+ * that are important for file processing. For example, this method
+ * might pass on the compression value specified by the user to
+ * a SAMFileWriter
+ * @param argumentCollection The arguments to be processed
+ */
+ public void processArguments( final GATKArgumentCollection argumentCollection );
+
+ /**
+ * Returns the OutputStream represented by this stub or null if not available.
+ */
+ public OutputStream getOutputStream();
+
+ /**
+ * Returns the File represented by this stub or null if not available.
+ */
+ public File getOutputFile();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/VCFWriterArgumentTypeDescriptor.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/VCFWriterArgumentTypeDescriptor.java
new file mode 100644
index 0000000..6861339
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/VCFWriterArgumentTypeDescriptor.java
@@ -0,0 +1,148 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.stubs;
+
+import htsjdk.tribble.AbstractFeatureReader;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.lang.reflect.Type;
+import java.util.Collection;
+
+/**
+ * Injects new command-line arguments into the system providing support for the genotype writer.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class VCFWriterArgumentTypeDescriptor extends ArgumentTypeDescriptor {
+
+ /**
+ * The engine into which output stubs should be fed.
+ */
+ private final GenomeAnalysisEngine engine;
+
+ /**
+ * The default location to which data should be written if the user specifies no such location.
+ */
+ private final OutputStream defaultOutputStream;
+
+ /**
+ * The sources into which arguments were injected.
+ */
+ private final Collection<Object> argumentSources;
+
+ /**
+ * Create a new GenotypeWriter argument, notifying the given engine when that argument has been created.
+ * @param engine the engine to be notified.
+ * @param defaultOutputStream the default output stream to be written to if nothing else is specified.
+ * @param argumentSources sources from which command-line arguments should be derived.
+ */
+ public VCFWriterArgumentTypeDescriptor(GenomeAnalysisEngine engine, OutputStream defaultOutputStream, Collection<Object> argumentSources) {
+ this.engine = engine;
+ this.defaultOutputStream = defaultOutputStream;
+ this.argumentSources = argumentSources;
+ }
+
+ /**
+ * Reports whether this ArgumentTypeDescriptor supports the given type.
+ * @param type The type to check.
+ * @return True if the argument is a GenotypeWriter.
+ */
+ @Override
+ public boolean supports( Class type ) {
+ return VariantContextWriter.class.equals(type);
+ }
+
+ /**
+ * This command-line argument descriptor does want to override the provided default value.
+ * @return true always.
+ */
+ @Override
+ public boolean createsTypeDefault(ArgumentSource source) {
+ return !source.isRequired() && source.defaultsToStdout();
+ }
+
+ @Override
+ public String typeDefaultDocString(ArgumentSource source) {
+ return "stdout";
+ }
+
+ @Override
+ public Object createTypeDefault(ParsingEngine parsingEngine, ArgumentSource source, Type type) {
+ if(source.isRequired() || !source.defaultsToStdout())
+ throw new ReviewedGATKException("BUG: tried to create type default for argument type descriptor that can't support a type default.");
+ VariantContextWriterStub stub = new VariantContextWriterStub(engine, defaultOutputStream, argumentSources);
+ engine.addOutput(stub);
+ return stub;
+ }
+
+ /**
+ * Convert the given argument matches into a single object suitable for feeding into the ArgumentSource.
+ * @param source Source for this argument.
+ * @param type not used
+ * @param matches Matches that match with this argument.
+ * @return Transform from the matches into the associated argument.
+ */
+ @Override
+ public Object parse( ParsingEngine parsingEngine, ArgumentSource source, Type type, ArgumentMatches matches ) {
+ ArgumentDefinition defaultArgumentDefinition = createDefaultArgumentDefinition(source);
+ // Get the filename for the genotype file, if it exists. If not, we'll need to send output to out.
+ ArgumentMatchValue writerFileName = getArgumentValue(defaultArgumentDefinition,matches);
+ File writerFile = writerFileName != null ? writerFileName.asFile() : null;
+
+ // This parser has been passed a null filename and the GATK is not responsible for creating a type default for the object;
+ // therefore, the user must have failed to specify a type default
+ if(writerFile == null && source.isRequired())
+ throw new MissingArgumentValueException(defaultArgumentDefinition);
+
+ // Create a stub for the given object.
+ final VariantContextWriterStub stub = (writerFile != null)
+ ? new VariantContextWriterStub(engine, writerFile, argumentSources)
+ : new VariantContextWriterStub(engine, defaultOutputStream, argumentSources);
+
+ stub.setCompressed(isCompressed(writerFileName == null ? null: writerFileName.asString()));
+
+ // WARNING: Side effects required by engine!
+ parsingEngine.addTags(stub,getArgumentTags(matches));
+ engine.addOutput(stub);
+
+ return stub;
+ }
+
+ /**
+ * Returns true if the file will be compressed.
+ * @param writerFileName Name of the file
+ * @return true if the file will be compressed.
+ */
+ public static boolean isCompressed(String writerFileName) {
+ return writerFileName != null && AbstractFeatureReader.hasBlockCompressedExtension(writerFileName);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/VariantContextWriterStub.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/VariantContextWriterStub.java
new file mode 100644
index 0000000..f40ede5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/io/stubs/VariantContextWriterStub.java
@@ -0,0 +1,301 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io.stubs;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.tribble.index.IndexCreator;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.engine.io.OutputTracker;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.writer.Options;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.variantcontext.writer.VariantContextWriterFactory;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+
+/**
+ * A stub for routing and management of genotype reading and writing.
+ *
+ * @author ebanks
+ * @version 0.1
+ */
+public class VariantContextWriterStub implements Stub<VariantContextWriter>, VariantContextWriter {
+ public final static boolean UPDATE_CONTIG_HEADERS = true;
+
+ /**
+ * The engine, central to the GATK's processing.
+ */
+ private final GenomeAnalysisEngine engine;
+
+ /**
+ * The file that this stub should write to. Should be mutually
+ * exclusive with genotypeStream.
+ */
+ private final File genotypeFile;
+
+ /**
+ * The output stream to which stub data should be written. Will be
+ * mutually exclusive with genotypeFile.
+ */
+ private final PrintStream genotypeStream;
+
+ /**
+ * A hack: push the argument sources into the VCF header so that the VCF header
+ * can rebuild the command-line arguments.
+ */
+ private final Collection<Object> argumentSources;
+
+ /**
+ * Which IndexCreator to use
+ */
+ private final IndexCreator indexCreator;
+
+ /**
+ * The cached VCF header (initialized to null)
+ */
+ private VCFHeader vcfHeader = null;
+
+ /**
+ * Should we emit a compressed output stream?
+ */
+ private boolean isCompressed = false;
+
+ /**
+ * Should the header be written out? A hidden argument.
+ */
+ private boolean skipWritingCommandLineHeader = false;
+
+ /**
+ * Should we not write genotypes even when provided?
+ */
+ private boolean doNotWriteGenotypes = false;
+
+ /**
+ * Should we force BCF writing regardless of the file extension?
+ */
+ private boolean forceBCF = false;
+
+ /**
+ * Should we write all of the fields in the FORMAT field, even if missing fields could be trimmed?
+ */
+ private boolean writeFullFormatField = false;
+
+ /**
+ * Connects this stub with an external stream capable of serving the
+ * requests of the consumer of this stub.
+ */
+ protected OutputTracker outputTracker = null;
+
+ /**
+ * Create a new stub given the requested file.
+ *
+ * @param engine engine.
+ * @param genotypeFile file to (ultimately) create.
+ * @param argumentSources sources.
+ */
+ public VariantContextWriterStub(GenomeAnalysisEngine engine, File genotypeFile, Collection<Object> argumentSources) {
+ this.engine = engine;
+ this.genotypeFile = genotypeFile;
+ this.genotypeStream = null;
+ this.indexCreator = GATKVCFUtils.getIndexCreator(engine.getArguments().variant_index_type, engine.getArguments().variant_index_parameter, genotypeFile);
+ this.argumentSources = argumentSources;
+ }
+
+ /**
+ * Create a new stub given the requested file.
+ *
+ * @param engine engine.
+ * @param genotypeStream stream to (ultimately) write.
+ * @param argumentSources sources.
+ */
+ public VariantContextWriterStub(GenomeAnalysisEngine engine, OutputStream genotypeStream, Collection<Object> argumentSources) {
+ this.engine = engine;
+ this.genotypeFile = null;
+ this.genotypeStream = new PrintStream(genotypeStream);
+ this.indexCreator = null;
+ this.argumentSources = argumentSources;
+ }
+
+ /**
+ * Retrieves the file to (ultimately) be created.
+ * @return The file. Can be null if genotypeStream is not.
+ */
+ public File getOutputFile() {
+ return genotypeFile;
+ }
+
+ /**
+ * Retrieves the output stream to which to (ultimately) write.
+ * @return The file. Can be null if genotypeFile is not.
+ */
+ public OutputStream getOutputStream() {
+ return genotypeStream;
+ }
+
+ public boolean isCompressed() {
+ return isCompressed;
+ }
+
+ public void setCompressed(final boolean compressed) {
+ isCompressed = compressed;
+ }
+
+ public void setSkipWritingCommandLineHeader(final boolean skipWritingCommandLineHeader) {
+ this.skipWritingCommandLineHeader = skipWritingCommandLineHeader;
+ }
+
+ public void setDoNotWriteGenotypes(final boolean doNotWriteGenotypes) {
+ this.doNotWriteGenotypes = doNotWriteGenotypes;
+ }
+
+ public void setForceBCF(final boolean forceBCF) {
+ this.forceBCF = forceBCF;
+ }
+
+ public void setWriteFullFormatField(final boolean writeFullFormatField) {
+ this.writeFullFormatField = writeFullFormatField;
+ }
+
+ public IndexCreator getIndexCreator() {
+ return indexCreator;
+ }
+
+ /**
+ * Gets the master sequence dictionary from the engine associated with this stub
+ * @link GenomeAnalysisEngine.getMasterSequenceDictionary
+ * @return the master sequence dictionary from the engine associated with this stub
+ */
+ public SAMSequenceDictionary getMasterSequenceDictionary() {
+ return engine.getMasterSequenceDictionary();
+ }
+
+ public EnumSet<Options> getWriterOptions() {
+ return getWriterOptions(false);
+ }
+
+ public EnumSet<Options> getWriterOptions(boolean indexOnTheFly) {
+ final List<Options> options = new ArrayList<>();
+
+ if ( doNotWriteGenotypes ) options.add(Options.DO_NOT_WRITE_GENOTYPES);
+ if ( engine.lenientVCFProcessing() ) options.add(Options.ALLOW_MISSING_FIELDS_IN_HEADER);
+ if ( indexOnTheFly) options.add(Options.INDEX_ON_THE_FLY);
+ if ( writeFullFormatField ) options.add(Options.WRITE_FULL_FORMAT_FIELD);
+
+ if ( forceBCF || (getOutputFile() != null && VariantContextWriterFactory.isBCFOutput(getOutputFile())) )
+ options.add(Options.FORCE_BCF);
+
+ return options.isEmpty() ? EnumSet.noneOf(Options.class) : EnumSet.copyOf(options);
+ }
+
+ /**
+ * Retrieves the header to use when creating the new file.
+ * @return header to use when creating the new file.
+ */
+ public VCFHeader getVCFHeader() {
+ return vcfHeader;
+ }
+
+ /**
+ * Registers the given streamConnector with this stub.
+ * @param outputTracker The connector used to provide an appropriate stream.
+ */
+ public void register( OutputTracker outputTracker ) {
+ this.outputTracker = outputTracker;
+ }
+
+ @Override
+ public void processArguments( final GATKArgumentCollection argumentCollection ) {
+ setDoNotWriteGenotypes(argumentCollection.sitesOnlyVCF);
+ setSkipWritingCommandLineHeader(argumentCollection.disableCommandLineInVCF);
+ setForceBCF(argumentCollection.forceBCFOutput);
+ setWriteFullFormatField(argumentCollection.neverTrimVCFFormatField);
+ }
+
+ public void writeHeader(VCFHeader header) {
+ vcfHeader = header;
+
+ if ( header.isWriteEngineHeaders() ) {
+ // skip writing the command line header if requested
+ if ( ! skipWritingCommandLineHeader && header.isWriteCommandLine() ) {
+ // Always add the header line, as the current format allows multiple entries
+ final VCFHeaderLine commandLineArgHeaderLine = GATKVCFUtils.getCommandLineArgumentHeaderLine(engine, argumentSources);
+ vcfHeader.addMetaDataLine(commandLineArgHeaderLine);
+ }
+
+ if ( UPDATE_CONTIG_HEADERS )
+ vcfHeader = GATKVCFUtils.withUpdatedContigs(vcfHeader, engine);
+ }
+
+ outputTracker.getStorage(this).writeHeader(vcfHeader);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void add(VariantContext vc) {
+ outputTracker.getStorage(this).add(vc);
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void close() {
+ outputTracker.getStorage(this).close();
+ }
+
+ /**
+ * Gets a string representation of this object.
+ * @return a string representation of this object.
+ */
+ @Override
+ public String toString() {
+ return getClass().getName();
+ }
+
+ /**
+ * Should we also write a BCF file alongside our VCF file for testing
+ *
+ * TODO -- remove me when argument generateShadowBCF is removed
+ *
+ * @return
+ */
+ public boolean alsoWriteBCFForTest() {
+ return engine.getArguments().numberOfDataThreads == 1 && // only works single threaded
+ ! isCompressed() && // for non-compressed outputs
+ getOutputFile() != null && // that are going to disk
+ engine.getArguments().generateShadowBCF; // and we actually want to do it
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/BoundedReadIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/BoundedReadIterator.java
new file mode 100644
index 0000000..cb696e5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/BoundedReadIterator.java
@@ -0,0 +1,159 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.MergingSamRecordIterator;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+
+import java.util.Iterator;
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/**
+ * @author aaron
+ * @version 1.0
+ * @date Apr 14, 2009
+ * <p/>
+ * Class BoundedReadIterator
+ * <p/>
+ * This class implements a read iterator that is bounded by the number of reads
+ * it will produce over the iteration.
+ */
+public class BoundedReadIterator implements GATKSAMIterator {
+
+ // the genome loc we're bounding
+ final private long readCount;
+ private long currentCount = 0;
+
+ // the iterator we want to decorate
+ private final GATKSAMIterator iterator;
+
+ // our unmapped read flag
+ private boolean doNotUseThatUnmappedReadPile = false;
+
+ /**
+ * The next read that we've buffered. Null indicates that there's
+ * nothing in the buffer (not that there isn't a next read).
+ */
+ private SAMRecord record = null;
+
+ /**
+ * constructor
+ * @param iter
+ * @param readCount
+ */
+ public BoundedReadIterator(GATKSAMIterator iter, long readCount) {
+ this.iterator = iter;
+ this.readCount = readCount;
+ }
+
+ public void useUnmappedReads(boolean useThem) {
+ this.doNotUseThatUnmappedReadPile = useThem;
+ }
+
+ public SAMFileHeader getHeader() {
+ // todo: this is bad, we need an iterface out there for samrecords that supports getting the header,
+ // regardless of the merging
+ if (iterator instanceof MergingSamRecordIterator)
+ return ((MergingSamRecordIterator)iterator).getMergedHeader();
+ else
+ return null;
+ }
+
+ /**
+ * Do we have a next? If the iterator has a read and we're not over the read
+ * count, then yes
+ * @return
+ */
+ public boolean hasNext() {
+ if( record != null )
+ return true;
+
+ if (iterator.hasNext() && currentCount < readCount) {
+ record = iterator.next();
+ ++currentCount;
+ if (record.getAlignmentStart() == 0 && doNotUseThatUnmappedReadPile) {
+ return false;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * get the next SAMRecord
+ * @return SAMRecord representing the next read
+ */
+ public SAMRecord next() {
+ SAMRecord cached = record;
+ record = null;
+ return cached;
+ }
+
+ /**
+ * this is unsupported on SAMRecord iterators
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("You cannot use an iterator to remove a SAMRecord");
+ }
+
+ /**
+ * close the iterator
+ */
+ public void close() {
+ iterator.close();
+ }
+
+ public Iterator<SAMRecord> iterator() {
+ return this;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GATKSAMIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GATKSAMIterator.java
new file mode 100644
index 0000000..8ca5cfd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GATKSAMIterator.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.CloseableIterator;
+/**
+ *
+ * User: aaron
+ * Date: May 6, 2009
+ * Time: 5:30:41 PM
+ *
+ * The Broad Institute
+ * SOFTWARE COPYRIGHT NOTICE AGREEMENT
+ * This software and its documentation are copyright 2009 by the
+ * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
+ *
+ * This software is supplied without any warranty or guaranteed support whatsoever. Neither
+ * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
+ *
+ */
+
+/**
+ * @author aaron
+ * @version 1.0
+ * @date May 6, 2009
+ * <p/>
+ * Interface GATKSAMIterator
+ * <p/>
+ * This is the standard interface for all iterators in the GATK package that iterate over SAMRecords
+ */
+public interface GATKSAMIterator extends CloseableIterator<SAMRecord>, Iterable<SAMRecord> {
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GATKSAMIteratorAdapter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GATKSAMIteratorAdapter.java
new file mode 100644
index 0000000..0dc3e62
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GATKSAMIteratorAdapter.java
@@ -0,0 +1,136 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.CloseableIterator;
+
+import java.util.Iterator;
+
+/**
+ *
+ * User: aaron
+ * Date: May 13, 2009
+ * Time: 6:33:15 PM
+ *
+ * The Broad Institute
+ * SOFTWARE COPYRIGHT NOTICE AGREEMENT
+ * This software and its documentation are copyright 2009 by the
+ * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
+ *
+ * This software is supplied without any warranty or guaranteed support whatsoever. Neither
+ * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
+ *
+ */
+
+
+/**
+ * @author aaron
+ * @version 1.0
+ * @date May 13, 2009
+ * <p/>
+ * Class GATKSAMIteratorAdapter
+ * <p/>
+ * This class adapts other SAMRecord iterators to the GATKSAMIterator
+ */
+public class GATKSAMIteratorAdapter {
+
+ public static GATKSAMIterator adapt(Iterator<SAMRecord> iter) {
+ return new PrivateStringSAMIterator(iter);
+ }
+
+ public static GATKSAMIterator adapt(CloseableIterator<SAMRecord> iter) {
+ return new PrivateStringSAMCloseableIterator(iter);
+ }
+
+}
+
+
+/**
+ * this class wraps iterators<SAMRecord> in a GATKSAMIterator, which means just adding the
+ * methods that implement the iterable<> interface and the close() method from CloseableIterator
+ */
+class PrivateStringSAMIterator implements GATKSAMIterator {
+ private Iterator<SAMRecord> iter = null;
+
+ PrivateStringSAMIterator(Iterator<SAMRecord> iter) {
+ this.iter = iter;
+ }
+
+ public void close() {
+ // do nothing, we can't close the iterator anyway.
+ }
+
+ public boolean hasNext() {
+ return iter.hasNext();
+ }
+
+ public SAMRecord next() {
+ return iter.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("GATKSAMIterator's don't allow remove()ing");
+ }
+
+ public Iterator<SAMRecord> iterator() {
+ return iter;
+ }
+}
+
+
+/**
+ * this class wraps closeable iterators<SAMRecord> in a GATKSAMIterator, which means adding the
+ * methods that implement the iterable<> interface.
+ */
+class PrivateStringSAMCloseableIterator implements GATKSAMIterator {
+ private CloseableIterator<SAMRecord> iter = null;
+
+ PrivateStringSAMCloseableIterator(CloseableIterator<SAMRecord> iter) {
+ this.iter = iter;
+ }
+
+ public void close() {
+ iter.close();
+ }
+
+ public boolean hasNext() {
+ return iter.hasNext();
+ }
+
+ public SAMRecord next() {
+ return iter.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("GATKSAMIterator's don't allow remove()ing");
+ }
+
+ public Iterator<SAMRecord> iterator() {
+ return iter;
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GATKSAMRecordIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GATKSAMRecordIterator.java
new file mode 100644
index 0000000..6d02acd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GATKSAMRecordIterator.java
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.CloseableIterator;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Iterator;
+
+/**
+ * Temporarily hack to convert SAMRecords to GATKSAMRecords
+ *
+ * User: depristo
+ * Date: 1/11/13
+ * Time: 1:19 PM
+ */
+public class GATKSAMRecordIterator implements CloseableIterator<GATKSAMRecord>, Iterable<GATKSAMRecord> {
+ final CloseableIterator<SAMRecord> it;
+
+ public GATKSAMRecordIterator(final CloseableIterator<SAMRecord> it) {
+ this.it = it;
+ }
+
+ public GATKSAMRecordIterator(final GATKSAMIterator it) {
+ this.it = it;
+ }
+
+ @Override public boolean hasNext() { return it.hasNext(); }
+ @Override public GATKSAMRecord next() { return (GATKSAMRecord)it.next(); }
+ @Override public void remove() { it.remove(); }
+ @Override public void close() { it.close(); }
+ @Override public Iterator<GATKSAMRecord> iterator() { return this; }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GenomeLocusIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GenomeLocusIterator.java
new file mode 100644
index 0000000..c76a07e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/GenomeLocusIterator.java
@@ -0,0 +1,100 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+/**
+ * User: hanna
+ * Date: May 12, 2009
+ * Time: 10:52:47 AM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Iterates through all of the loci provided in the reference.
+ */
+public class GenomeLocusIterator implements Iterator<GenomeLoc> {
+ /**
+ * Builds individual loci.
+ */
+ private GenomeLocParser parser;
+
+ /**
+ * The entire region over which we're iterating.
+ */
+ private GenomeLoc completeLocus;
+
+ /**
+ * The current position in the traversal.
+ */
+ private GenomeLoc currentLocus;
+
+ /**
+ * Creates an iterator that can traverse over the entire
+ * reference specified in the given ShardDataProvider.
+ * @param completeLocus Data provider to use as a backing source.
+ * Provider must have a reference (hasReference() == true).
+ */
+ public GenomeLocusIterator( GenomeLocParser parser, GenomeLoc completeLocus ) {
+ this.parser = parser;
+ this.completeLocus = completeLocus;
+ this.currentLocus = parser.createGenomeLoc(completeLocus.getContig(),completeLocus.getStart());
+ }
+
+ /**
+ * Is the iterator still within the locus?
+ * @return True if the iterator has more elements. False otherwise.
+ */
+ public boolean hasNext() {
+ return !currentLocus.isPast(completeLocus);
+ }
+
+ /**
+ * Get the next single-base locus context bounded by the iterator.
+ * @return GenomeLoc representing the next single-base locus context.
+ */
+ public GenomeLoc next() {
+ if( !hasNext() )
+ throw new NoSuchElementException("No elements remaining in bounded reference region.");
+ GenomeLoc toReturn = currentLocus;
+ currentLocus = parser.incPos(currentLocus);
+ return toReturn;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException( "ReferenceLocusIterator is read-only" );
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/IterableIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/IterableIterator.java
new file mode 100644
index 0000000..bf8b697
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/IterableIterator.java
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import java.util.Iterator;
+
+public class IterableIterator<T> implements Iterable<T> {
+ private Iterator<T> iter;
+
+ public IterableIterator(Iterator<T> iter) {
+ this.iter = iter;
+ }
+
+ public Iterator<T> iterator() {
+ return iter;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/MalformedBAMErrorReformatingIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/MalformedBAMErrorReformatingIterator.java
new file mode 100644
index 0000000..d3a6bdc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/MalformedBAMErrorReformatingIterator.java
@@ -0,0 +1,69 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.CloseableIterator;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.util.Iterator;
+
+/**
+ * Traps BAM formatting errors in underlying iterator and rethrows meaningful GATK UserExceptions
+ */
+public class MalformedBAMErrorReformatingIterator implements CloseableIterator<SAMRecord> {
+ File source;
+ CloseableIterator<SAMRecord> it;
+
+ public MalformedBAMErrorReformatingIterator(final File source, final CloseableIterator<SAMRecord> it) {
+ this.it = it;
+ this.source = source;
+ }
+
+ public boolean hasNext() {
+ try {
+ return this.it.hasNext();
+ } catch ( RuntimeException e ) { // we need to catch RuntimeExceptions here because the Picard code is throwing them (among SAMFormatExceptions) sometimes
+ throw new UserException.MalformedBAM(source, e.getMessage());
+ }
+ }
+
+ public SAMRecord next() {
+ try {
+ return it.next();
+ } catch ( RuntimeException e ) { // we need to catch RuntimeExceptions here because the Picard code is throwing them (among SAMFormatExceptions) sometimes
+ throw new UserException.MalformedBAM(source, e.getMessage());
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Can not remove records from a SAM file via an iterator!");
+ }
+
+ public void close() { it.close(); }
+ public Iterator<SAMRecord> iterator() { return this; }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/NullSAMIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/NullSAMIterator.java
new file mode 100644
index 0000000..fa130f9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/NullSAMIterator.java
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.SAMRecord;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+/**
+ * User: hanna
+ * Date: May 19, 2009
+ * Time: 6:47:16 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * A placeholder for an iterator with no data.
+ */
+public class NullSAMIterator implements GATKSAMIterator {
+ public NullSAMIterator() {}
+
+ public Iterator<SAMRecord> iterator() { return this; }
+ public void close() { /* NO-OP */ }
+
+ public boolean hasNext() { return false; }
+ public SAMRecord next() { throw new NoSuchElementException("No next element is available."); }
+ public void remove() { throw new UnsupportedOperationException("Cannot remove from a GATKSAMIterator"); }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/PeekingIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/PeekingIterator.java
new file mode 100644
index 0000000..f46fb0c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/PeekingIterator.java
@@ -0,0 +1,65 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author aaron
+ * <p/>
+ * Class PeekingIterator
+ * <p/>
+ * a peekable interface, that requires a peek() method
+ */
+public interface PeekingIterator<T> {
+
+ /** @return returns a peeked value */
+ public T peek();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/PositionTrackingIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/PositionTrackingIterator.java
new file mode 100644
index 0000000..2eba344
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/PositionTrackingIterator.java
@@ -0,0 +1,105 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.CloseableIterator;
+
+/**
+ * Iterates through a list of elements, tracking the number of elements it has seen.
+ * @author hanna
+ * @version 0.1
+ */
+public class PositionTrackingIterator implements GATKSAMIterator {
+ /**
+ * The iterator being tracked.
+ */
+ private CloseableIterator<SAMRecord> iterator;
+
+ /**
+ * Current position within the tracked iterator.
+ */
+ private long position;
+
+ /**
+ * Retrieves the current position of the iterator. The 'current position' of the iterator is defined as
+ * the coordinate of the read that will be returned if next() is called.
+ * @return The current position of the iterator.
+ */
+ public long getPosition() {
+ return position;
+ }
+
+ /**
+ * Create a new iterator wrapping the given position, assuming that the reader is <code>position</code> reads
+ * into the sequence.
+ * @param iterator Iterator to wraps.
+ * @param position Non-negative position where the iterator currently sits.
+ */
+ public PositionTrackingIterator(CloseableIterator<SAMRecord> iterator, long position ) {
+ this.iterator = iterator;
+ this.position = position;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ /**
+ * Try to get the next read in the list. If a next read is available, increment the position.
+ * @return next read in the list, if available.
+ */
+ public SAMRecord next() {
+ try {
+ return iterator.next();
+ }
+ finally {
+ position++;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public GATKSAMIterator iterator() {
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close() {
+ iterator.close();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void remove() { throw new UnsupportedOperationException("Cannot remove from a GATKSAMIterator"); }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/PushbackIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/PushbackIterator.java
new file mode 100644
index 0000000..0bb545b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/PushbackIterator.java
@@ -0,0 +1,82 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import java.util.Iterator;
+
+public class PushbackIterator<T> implements Iterator<T>, Iterable<T> {
+ Iterator<T> underlyingIterator;
+ T pushedElement = null;
+
+ public PushbackIterator(final Iterator<T> underlyingIterator) {
+ this.underlyingIterator = underlyingIterator;
+ }
+
+ public boolean hasNext() {
+ return pushedElement != null || underlyingIterator.hasNext();
+ }
+
+ public Iterator<T> iterator() {
+ return this;
+ }
+
+ /**
+ * Retrieves, but does not remove, the head of this iterator.
+ * @return T the next element in the iterator
+ */
+ public T element() {
+ T x = next();
+ pushback(x);
+ return x;
+ }
+
+ /**
+ * @return the next element in the iteration.
+ */
+ public T next() {
+ if (pushedElement != null) {
+ final T ret = pushedElement;
+ pushedElement = null;
+ return ret;
+ } else {
+ return underlyingIterator.next();
+ }
+ }
+
+ public void pushback(T elt) {
+ assert(pushedElement == null);
+
+ pushedElement = elt;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Iterator<T> getUnderlyingIterator() {
+ return underlyingIterator;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/RNAReadTransformer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/RNAReadTransformer.java
new file mode 100644
index 0000000..4cc2a82
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/RNAReadTransformer.java
@@ -0,0 +1,37 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+/**
+ *
+ * A baseclass for RNAseq read transformer
+ *
+ * @author ami
+ * @since 4/28/14.
+ */
+public abstract class RNAReadTransformer extends ReadTransformer{
+ public boolean isRNAReadTransformer(){return true;}
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/ReadFormattingIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/ReadFormattingIterator.java
new file mode 100644
index 0000000..4922279
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/ReadFormattingIterator.java
@@ -0,0 +1,140 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.SAMRecord;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.sam.AlignmentUtils;
+
+/**
+ * An iterator which does post-processing of a read, including potentially wrapping
+ * the read in something with a compatible interface or replacing the read entirely.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class ReadFormattingIterator implements GATKSAMIterator {
+ /**
+ * Logger.
+ */
+ final protected static Logger logger = Logger.getLogger(ReadFormattingIterator.class);
+
+ /**
+ * Iterator to which to pass
+ */
+ private GATKSAMIterator wrappedIterator;
+
+ /**
+ * True if original base qualities should be used.
+ */
+ private final boolean useOriginalBaseQualities;
+
+ /**
+ * Positive if there is a default Base Quality value to fill in the reads with.
+ */
+ private final byte defaultBaseQualities;
+
+
+ /**
+ * Decorate the given iterator inside a ReadWrappingIterator.
+ * @param wrappedIterator iterator
+ * @param useOriginalBaseQualities true if original base qualities should be used
+ * @param defaultBaseQualities if the reads have incomplete quality scores, set them all to defaultBaseQuality.
+ */
+ public ReadFormattingIterator(GATKSAMIterator wrappedIterator, boolean useOriginalBaseQualities, byte defaultBaseQualities) {
+ this.wrappedIterator = wrappedIterator;
+ this.useOriginalBaseQualities = useOriginalBaseQualities;
+ this.defaultBaseQualities = defaultBaseQualities;
+
+ }
+
+ /**
+ * Convenience function for use in foreach loops. Dangerous because it does not actually
+ * reset the iterator.
+ * @return An iterator through the current data stream.
+ */
+ public GATKSAMIterator iterator() {
+ // NOTE: this iterator doesn't perform any kind of reset operation; it just returns itself.
+ // can we do something better? Do we really have to provide support for the Iterable interface?
+ return this;
+ }
+
+ /**
+ * Close this iterator.
+ */
+ public void close() {
+ wrappedIterator.close();
+ }
+
+ /**
+ * Does the iterator contain more values?
+ * @return True if there are more left to return, false otherwise.
+ */
+ public boolean hasNext() {
+ return wrappedIterator.hasNext();
+ }
+
+ /**
+ * Get the next value in the sequence.
+ * @return Next value in the sequence. By convention, a NoSuchElementException should be thrown if
+ * no next exists.
+ */
+ public SAMRecord next() {
+ SAMRecord rec = wrappedIterator.next();
+
+ // Always consolidate the cigar string into canonical form, collapsing zero-length / repeated cigar elements.
+ // Downstream code (like LocusIteratorByState) cannot necessarily handle non-consolidated cigar strings.
+ rec.setCigar(AlignmentUtils.consolidateCigar(rec.getCigar()));
+
+ // if we are using default quals, check if we need them, and add if necessary.
+ // 1. we need if reads are lacking or have incomplete quality scores
+ // 2. we add if defaultBaseQualities has a positive value
+ if (defaultBaseQualities >= 0) {
+ byte reads [] = rec.getReadBases();
+ byte quals [] = rec.getBaseQualities();
+ if (quals == null || quals.length < reads.length) {
+ byte new_quals [] = new byte [reads.length];
+ for (int i=0; i<reads.length; i++)
+ new_quals[i] = defaultBaseQualities;
+ rec.setBaseQualities(new_quals);
+ }
+ }
+
+ // if we are using original quals, set them now if they are present in the record
+ if ( useOriginalBaseQualities ) {
+ byte[] originalQuals = rec.getOriginalBaseQualities();
+ if ( originalQuals != null )
+ rec.setBaseQualities(originalQuals);
+ }
+
+ return rec;
+ }
+
+ /**
+ * Remove the current element from the list. Unsupported in this wrapper.
+ */
+ public void remove() { throw new UnsupportedOperationException("Cannot remove from a ReadWrappingIterator"); }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/ReadTransformer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/ReadTransformer.java
new file mode 100644
index 0000000..b7db505
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/ReadTransformer.java
@@ -0,0 +1,205 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Comparator;
+
+/**
+ * Baseclass used to describe a read transformer like BAQ and BQSR
+ *
+ * Read transformers are plugable infrastructure that modify read state
+ * either on input, on output, or within walkers themselves.
+ *
+ * The function apply() is called on each read seen by the GATK (after passing
+ * all ReadFilters) and it can do as it sees fit (without modifying the alignment)
+ * to the read to change qualities, add tags, etc.
+ *
+ * Initialize is called once right before the GATK traversal begins providing
+ * the ReadTransformer with the ability to collect and initialize data from the
+ * engine.
+ *
+ * Note that all ReadTransformers within the classpath are created and initialized. If one
+ * shouldn't be run it should look at the command line options of the engine and override
+ * the enabled.
+ *
+ * @since 8/31/12
+ * @author depristo
+ */
+abstract public class ReadTransformer {
+ /**
+ * When should this read transform be applied?
+ */
+ private ApplicationTime applicationTime;
+
+ /**
+ * Keep track of whether we've been initialized already, and ensure it's not called more than once.
+ */
+ private boolean initialized = false;
+
+ protected ReadTransformer() {}
+
+ /*
+ * @return the ordering constraint for the given read transformer
+ */
+ public OrderingConstraint getOrderingConstraint() { return OrderingConstraint.DO_NOT_CARE; }
+
+ /**
+ * Master initialization routine. Called to setup a ReadTransform, using it's overloaded initializeSub routine.
+ *
+ * @param overrideTime if not null, we will run this ReadTransform at the time provided, regardless of the timing of this read transformer itself
+ * @param engine the engine, for initializing values
+ * @param walker the walker we intend to run
+ */
+ @Requires({"initialized == false", "engine != null", "walker != null"})
+ @Ensures("initialized == true")
+ public final void initialize(final ApplicationTime overrideTime, final GenomeAnalysisEngine engine, final Walker walker) {
+ if ( engine == null ) throw new IllegalArgumentException("engine cannot be null");
+ if ( walker == null ) throw new IllegalArgumentException("walker cannot be null");
+
+ this.applicationTime = initializeSub(engine, walker);
+ if ( overrideTime != null ) this.applicationTime = overrideTime;
+ initialized = true;
+ }
+
+ /**
+ * Subclasses must override this to initialize themselves
+ *
+ * @param engine the engine, for initializing values
+ * @param walker the walker we intend to run
+ * @return the point of time we'd like this read transform to be run
+ */
+ @Requires({"engine != null", "walker != null"})
+ @Ensures("result != null")
+ protected abstract ApplicationTime initializeSub(final GenomeAnalysisEngine engine, final Walker walker);
+
+ /**
+ * Should this ReadTransformer be activated? Called after initialize, which allows this
+ * read transformer to look at its arguments and decide if it should be active. All
+ * ReadTransformers must override this, as by default they are not enabled.
+ *
+ * @return true if this ReadTransformer should be used on the read stream
+ */
+ public boolean enabled() {
+ return false;
+ }
+
+ /**
+ * Has this transformer been initialized?
+ *
+ * @return true if it has
+ */
+ public final boolean isInitialized() {
+ return initialized;
+ }
+
+ /**
+ * When should we apply this read transformer?
+ *
+ * @return true if yes
+ */
+ public final ApplicationTime getApplicationTime() {
+ return applicationTime;
+ }
+
+ /**
+ * Primary interface function for a read transform to actually do some work
+ *
+ * The function apply() is called on each read seen by the GATK (after passing
+ * all ReadFilters) and it can do as it sees fit (without modifying the alignment)
+ * to the read to change qualities, add tags, etc.
+ *
+ * @param read the read to transform
+ * @return the transformed read
+ */
+ @Requires("read != null")
+ @Ensures("result != null")
+ abstract public GATKSAMRecord apply(final GATKSAMRecord read);
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
+
+ /**
+ * When should a read transformer be applied?
+ */
+ public static enum ApplicationTime {
+ /**
+ * Walker does not tolerate this read transformer
+ */
+ FORBIDDEN,
+
+ /**
+ * apply the transformation to the incoming reads, the default
+ */
+ ON_INPUT,
+
+ /**
+ * apply the transformation to the outgoing read stream
+ */
+ ON_OUTPUT,
+
+ /**
+ * the walker will deal with the calculation itself
+ */
+ HANDLED_IN_WALKER
+ }
+
+ /*
+ * This enum specifies the constraints that the given read transformer has relative to any other read transformers being used
+ */
+ public enum OrderingConstraint {
+ /*
+ * If 2 read transformers are both active and MUST_BE_FIRST, then an error will be generated
+ */
+ MUST_BE_FIRST,
+
+ /*
+ * No constraints on the ordering for this read transformer
+ */
+ DO_NOT_CARE,
+
+ /*
+ * If 2 read transformers are both active and MUST_BE_LAST, then an error will be generated
+ */
+ MUST_BE_LAST
+ }
+
+ public static class ReadTransformerComparator implements Comparator<ReadTransformer> {
+
+ public int compare(final ReadTransformer r1, final ReadTransformer r2) {
+ if ( r1.getOrderingConstraint() == r2.getOrderingConstraint() )
+ return 0;
+ return ( r1.getOrderingConstraint() == OrderingConstraint.MUST_BE_FIRST || r2.getOrderingConstraint() == OrderingConstraint.MUST_BE_LAST ) ? -1 : 1;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/ReadTransformersMode.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/ReadTransformersMode.java
new file mode 100644
index 0000000..3fa18c4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/ReadTransformersMode.java
@@ -0,0 +1,53 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import java.lang.annotation.*;
+
+/**
+ * User: hanna
+ * Date: May 14, 2009
+ * Time: 1:51:22 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Allows the walker to indicate what type of data it wants to consume.
+ */
+
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface ReadTransformersMode {
+ public abstract ReadTransformer.ApplicationTime ApplicationTime() default ReadTransformer.ApplicationTime.ON_INPUT;
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/VerifyingSamIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/VerifyingSamIterator.java
new file mode 100644
index 0000000..a34d4de
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/VerifyingSamIterator.java
@@ -0,0 +1,90 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.Iterator;
+
+/**
+ * Verifies that the incoming stream of reads is correctly sorted
+ */
+public class VerifyingSamIterator implements GATKSAMIterator {
+ GATKSAMIterator it;
+ SAMRecord last = null;
+ boolean checkOrderP = true;
+
+ public VerifyingSamIterator(GATKSAMIterator it) {
+ this.it = it;
+ }
+
+ public boolean hasNext() { return this.it.hasNext(); }
+ public SAMRecord next() {
+
+ SAMRecord cur = it.next();
+ if ( last != null )
+ verifyRecord(last, cur);
+ if ( ! cur.getReadUnmappedFlag() )
+ last = cur;
+ return cur;
+ }
+
+ private void verifyRecord( final SAMRecord last, final SAMRecord cur ) {
+ if ( checkOrderP && isOutOfOrder(last, cur) ) {
+ this.last = null;
+ throw new UserException.MissortedBAM(String.format("reads are out of order:%nlast:%n%s%ncurrent:%n%s%n", last.format(), cur.format()) );
+ }
+ }
+
+ private boolean isOutOfOrder( final SAMRecord last, final SAMRecord cur ) {
+ if ( last == null || cur.getReadUnmappedFlag() )
+ return false;
+ else {
+ if(last.getReferenceIndex() == SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX || last.getAlignmentStart() == SAMRecord.NO_ALIGNMENT_START)
+ throw new UserException.MalformedBAM(last,String.format("read %s has inconsistent mapping information.",last.format()));
+ if(cur.getReferenceIndex() == SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX || cur.getAlignmentStart() == SAMRecord.NO_ALIGNMENT_START)
+ throw new UserException.MalformedBAM(last,String.format("read %s has inconsistent mapping information.",cur.format()));
+
+ return (last.getReferenceIndex() > cur.getReferenceIndex()) ||
+ (last.getReferenceIndex().equals(cur.getReferenceIndex()) &&
+ last.getAlignmentStart() > cur.getAlignmentStart());
+ }
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Can not remove records from a SAM file via an iterator!");
+ }
+
+ public void close() {
+ it.close();
+ }
+
+ public Iterator<SAMRecord> iterator() {
+ return this;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/package-info.java
new file mode 100644
index 0000000..3387890
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/iterators/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/phonehome/GATKRunReport.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/phonehome/GATKRunReport.java
new file mode 100644
index 0000000..f8126b9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/phonehome/GATKRunReport.java
@@ -0,0 +1,786 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.phonehome;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.crypt.CryptUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.io.IOUtils;
+import org.broadinstitute.gatk.utils.io.Resource;
+import org.broadinstitute.gatk.utils.threading.ThreadEfficiencyMonitor;
+import org.jets3t.service.S3Service;
+import org.jets3t.service.S3ServiceException;
+import org.jets3t.service.impl.rest.httpclient.RestS3Service;
+import org.jets3t.service.model.S3Object;
+import org.jets3t.service.security.AWSCredentials;
+import org.simpleframework.xml.Element;
+import org.simpleframework.xml.Serializer;
+import org.simpleframework.xml.core.Persister;
+
+import java.io.*;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+
+/**
+ * A detailed description of a GATK run, and error if applicable. Simply create a GATKRunReport
+ * with the constructor, providing the walker that was run and the fully instantiated GenomeAnalysisEngine
+ * <b>after the run finishes</b> and the GATKRunReport will collect all of the report information
+ * into this object. Call postReport to write out the report, as an XML document, to either STDOUT,
+ * a file (in which case the output is gzipped), or with no arguments the report will be posted to the
+ * GATK run report database.
+ *
+ * @author depristo
+ * @since 2010
+ */
+public class GATKRunReport {
+ protected static final String REPORT_BUCKET_NAME = "broad.gsa.gatk.run.reports";
+ protected static final String TEST_REPORT_BUCKET_NAME = "broad.gsa.gatk.run.reports.test";
+ protected final static String AWS_ACCESS_KEY_MD5 = "34d4a26eb2062b3f06e833b28f9a38c6";
+ protected final static String AWS_SECRET_KEY_MD5 = "83f2332eec99ef1d7425d5dc5d4b514a";
+
+ private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH.mm.ss");
+
+ /**
+ * our log
+ */
+ protected static final Logger logger = Logger.getLogger(GATKRunReport.class);
+
+ /**
+ * Default value for the number of milliseconds before an S3 put operation is timed-out.
+ * Can be overridden via a constructor argument.
+ */
+ private static final long S3_DEFAULT_PUT_TIME_OUT_IN_MILLISECONDS = 30 * 1000;
+
+ /**
+ * Number of milliseconds before an S3 put operation is timed-out.
+ */
+ private long s3PutTimeOutInMilliseconds = S3_DEFAULT_PUT_TIME_OUT_IN_MILLISECONDS;
+
+ // -----------------------------------------------------------------
+ // elements captured for the report
+ // -----------------------------------------------------------------
+
+ @Element(required = false, name = "id")
+ private String id;
+
+ @Element(required = false, name = "exception")
+ private GATKRunReportException mException;
+
+ @Element(required = true, name = "start-time")
+ private String startTime = "ND";
+
+ @Element(required = true, name = "end-time")
+ private String endTime;
+
+ @Element(required = true, name = "run-time")
+ private long runTime = 0;
+
+ @Element(required = true, name = "walker-name")
+ private String walkerName;
+
+ @Element(required = true, name = "svn-version")
+ private String svnVersion;
+
+ @Element(required = true, name = "total-memory")
+ private long totalMemory;
+
+ @Element(required = true, name = "max-memory")
+ private long maxMemory;
+
+ @Element(required = true, name = "user-name")
+ private String userName;
+
+ @Element(required = true, name = "host-name")
+ private String hostName;
+
+ @Element(required = true, name = "java")
+ private String javaVersion;
+
+ @Element(required = true, name = "machine")
+ private String machine;
+
+ @Element(required = true, name = "iterations")
+ private long nIterations;
+
+ @Element(required = true, name = "tag")
+ private String tag;
+
+ @Element(required = true, name = "num-threads")
+ private int numThreads;
+ @Element(required = true, name = "percent-time-running")
+ private String percentTimeRunning;
+ @Element(required = true, name = "percent-time-waiting")
+ private String percentTimeWaiting;
+ @Element(required = true, name = "percent-time-blocking")
+ private String percentTimeBlocking;
+ @Element(required = true, name = "percent-time-waiting-for-io")
+ private String percentTimeWaitingForIO;
+
+ /** The error message, if one occurred, or null if none did */
+ public String errorMessage = null;
+ /** The error that occurred, if one did, or null if none did */
+ public Throwable errorThrown = null;
+
+ /**
+ * How should the GATK report its usage?
+ */
+ public enum PhoneHomeOption {
+ /** Disable phone home */
+ NO_ET,
+ /** Forces the report to go to S3 */
+ AWS,
+ /** Force output to STDOUT. For debugging only */
+ STDOUT
+ }
+
+ /**
+ * To allow us to deserial reports from XML
+ */
+ private GATKRunReport() { }
+
+ /**
+ * Read a GATKRunReport from the serialized XML representation in String reportAsXML
+ * @param stream an input stream containing a serialized XML report
+ * @return a reconstituted GATKRunReport from reportAsXML
+ * @throws Exception if parsing fails for any reason
+ */
+ @Ensures("result != null")
+ protected static GATKRunReport deserializeReport(final InputStream stream) throws Exception {
+ final Serializer serializer = new Persister();
+ return serializer.read(GATKRunReport.class, stream);
+ }
+
+ /**
+ * Create a new GATKRunReport from a report on S3
+ *
+ * Assumes that s3Object has already been written to S3, and this function merely
+ * fetches it from S3 and deserializes it. The access keys must have permission to
+ * GetObject from S3.
+ *
+ * @param downloaderAccessKey AWS access key with permission to GetObject from bucketName
+ * @param downloaderSecretKey AWS secret key with permission to GetObject from bucketName
+ * @param bucketName the name of the bucket holding the report
+ * @param s3Object the s3Object we wrote to S3 in bucketName that we want to get back and decode
+ * @return a deserialized report derived from s3://bucketName/s3Object.getName()
+ * @throws Exception
+ */
+ @Ensures("result != null")
+ protected static GATKRunReport deserializeReport(final String downloaderAccessKey,
+ final String downloaderSecretKey,
+ final String bucketName,
+ final S3Object s3Object) throws Exception {
+ final S3Service s3Service = initializeAWSService(downloaderAccessKey, downloaderSecretKey);
+
+ // Retrieve the whole data object we created previously
+ final S3Object objectComplete = s3Service.getObject(bucketName, s3Object.getName());
+
+ // Read the data from the object's DataInputStream using a loop, and print it out.
+ return deserializeReport(new GZIPInputStream(objectComplete.getDataInputStream()));
+ }
+
+ /**
+ * Create a new RunReport and population all of the fields with values from the walker and engine.
+ * Allows the S3 put timeout to be explicitly set.
+ *
+ * @param walker the GATK walker that we ran
+ * @param e the exception caused by running this walker, or null if we completed successfully
+ * @param engine the GAE we used to run the walker, so we can fetch runtime, args, etc
+ * @param type the GATK phone home setting
+ * @param s3PutTimeOutInMilliseconds number of milliseconds to wait before timing out an S3 put operation
+ */
+ public GATKRunReport(final Walker<?,?> walker, final Exception e, final GenomeAnalysisEngine engine, final PhoneHomeOption type,
+ final long s3PutTimeOutInMilliseconds) {
+ this(walker, e, engine, type);
+ this.s3PutTimeOutInMilliseconds = s3PutTimeOutInMilliseconds;
+ }
+
+ /**
+ * Create a new RunReport and population all of the fields with values from the walker and engine.
+ * Leaves the S3 put timeout set to the default value of S3_DEFAULT_PUT_TIME_OUT_IN_MILLISECONDS.
+ *
+ * @param walker the GATK walker that we ran
+ * @param e the exception caused by running this walker, or null if we completed successfully
+ * @param engine the GAE we used to run the walker, so we can fetch runtime, args, etc
+ * @param type the GATK phone home setting
+ */
+ public GATKRunReport(final Walker<?,?> walker, final Exception e, final GenomeAnalysisEngine engine, final PhoneHomeOption type) {
+ if ( type == PhoneHomeOption.NO_ET )
+ throw new ReviewedGATKException("Trying to create a run report when type is NO_ET!");
+
+ logger.debug("Aggregating data for run report");
+
+ // what did we run?
+ id = org.apache.commons.lang.RandomStringUtils.randomAlphanumeric(32);
+ walkerName = engine.getWalkerName(walker.getClass());
+ svnVersion = CommandLineGATK.getVersionNumber();
+
+ // runtime performance metrics
+ Date end = new java.util.Date();
+ endTime = DATE_FORMAT.format(end);
+ if ( engine.getStartTime() != null ) { // made it this far during initialization
+ startTime = DATE_FORMAT.format(engine.getStartTime());
+ runTime = (end.getTime() - engine.getStartTime().getTime()) / 1000L; // difference in seconds
+ }
+
+ // deal with memory usage
+ Runtime.getRuntime().gc(); // call GC so totalMemory is ~ used memory
+ maxMemory = Runtime.getRuntime().maxMemory();
+ totalMemory = Runtime.getRuntime().totalMemory();
+
+ // we can only do some operations if an error hasn't occurred
+ if ( engine.getCumulativeMetrics() != null ) {
+ // it's possible we aborted so early that these data structures arent initialized
+ nIterations = engine.getCumulativeMetrics().getNumIterations();
+ }
+
+ tag = engine.getArguments().tag;
+
+ // user and hostname -- information about the runner of the GATK
+ userName = System.getProperty("user.name");
+ hostName = Utils.resolveHostname();
+
+ // basic java information
+ javaVersion = Utils.join("-", Arrays.asList(System.getProperty("java.vendor"), System.getProperty("java.version")));
+ machine = Utils.join("-", Arrays.asList(System.getProperty("os.name"), System.getProperty("os.arch")));
+
+ // if there was an exception, capture it
+ this.mException = e == null ? null : new GATKRunReportException(e);
+
+ numThreads = engine.getTotalNumberOfThreads();
+ percentTimeRunning = getThreadEfficiencyPercent(engine, ThreadEfficiencyMonitor.State.USER_CPU);
+ percentTimeBlocking = getThreadEfficiencyPercent(engine, ThreadEfficiencyMonitor.State.BLOCKING);
+ percentTimeWaiting = getThreadEfficiencyPercent(engine, ThreadEfficiencyMonitor.State.WAITING);
+ percentTimeWaitingForIO = getThreadEfficiencyPercent(engine, ThreadEfficiencyMonitor.State.WAITING_FOR_IO);
+ }
+
+ /**
+ * Get the random alpha-numeric ID of this GATKRunReport
+ * @return a non-null string ID
+ */
+ @Ensures("result != null")
+ public String getID() {
+ return id;
+ }
+
+ /**
+ * Return a string representing the percent of time the GATK spent in state, if possible. Otherwise return NA
+ *
+ * @param engine the GATK engine whose threading efficiency info we will use
+ * @param state the state whose occupancy we wish to know
+ * @return a string representation of the percent occupancy of state, or NA is not possible
+ */
+ @Requires({"engine != null", "state != null"})
+ @Ensures("result != null")
+ private String getThreadEfficiencyPercent(final GenomeAnalysisEngine engine, final ThreadEfficiencyMonitor.State state) {
+ final ThreadEfficiencyMonitor tem = engine.getThreadEfficiencyMonitor();
+ return tem == null ? "NA" : String.format("%.2f", tem.getStatePercent(state));
+ }
+
+ /**
+ * Get a filename (no path) appropriate for this report
+ *
+ * @return a non-null string filename
+ */
+ @Ensures("result != null")
+ protected String getReportFileName() {
+ return getID() + ".report.xml.gz";
+ }
+
+ // ---------------------------------------------------------------------------
+ //
+ // Main public interface method for posting reports
+ //
+ // ---------------------------------------------------------------------------
+
+ /**
+ * Post this GATK report to the destination implied by the PhoneHomeOption type
+ *
+ * Guaranteed to never throw an exception (exception noted below) and to return
+ * with a reasonable (~10 seconds) time regardless of successful writing of the report.
+ *
+ * @throws IllegalArgumentException if type == null
+ * @param type the type of phoning home we want to do
+ * @return true if a report was successfully written, false otherwise
+ */
+ public boolean postReport(final PhoneHomeOption type) {
+ if ( type == null ) throw new IllegalArgumentException("type cannot be null");
+
+ logger.debug("Posting report of type " + type);
+ switch (type) {
+ case NO_ET: // don't do anything
+ return false;
+ case AWS:
+ wentToAWS = true;
+ return postReportToAWSS3() != null;
+ case STDOUT:
+ return postReportToStream(System.out);
+ default:
+ exceptDuringRunReport("BUG: unexpected PhoneHomeOption ");
+ return false;
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ //
+ // Code for sending reports to local files
+ //
+ // ---------------------------------------------------------------------------
+
+ /**
+ * Write an XML representation of this report to the stream, throwing a GATKException if the marshalling
+ * fails for any reason.
+ *
+ * @param stream an output stream to write the report to
+ */
+ @Requires("stream != null")
+ protected boolean postReportToStream(final OutputStream stream) {
+ final Serializer serializer = new Persister();
+ try {
+ serializer.write(this, stream);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ //
+ // Code for sending reports to s3
+ //
+ // ---------------------------------------------------------------------------
+
+ /**
+ * Get the name of the S3 bucket where we should upload this report
+ *
+ * @return the string name of the s3 bucket
+ */
+ @Ensures("result != null")
+ protected String getS3ReportBucket() {
+ return s3ReportBucket;
+ }
+
+ /**
+ * Decrypts encrypted AWS key from encryptedKeySource
+ * @param encryptedKeySource a file containing an encrypted AWS key
+ * @return a decrypted AWS key as a String
+ */
+ @Ensures("result != null")
+ public static String decryptAWSKey(final File encryptedKeySource) throws FileNotFoundException {
+ if ( encryptedKeySource == null ) throw new IllegalArgumentException("encryptedKeySource cannot be null");
+ return decryptAWSKey(new FileInputStream(encryptedKeySource));
+ }
+
+ /**
+ * @see #decryptAWSKey(java.io.File) but with input from an inputstream
+ */
+ @Requires("encryptedKeySource != null")
+ @Ensures("result != null")
+ private static String decryptAWSKey(final InputStream encryptedKeySource) {
+ final PublicKey key = CryptUtils.loadGATKDistributedPublicKey();
+ final byte[] fromDisk = IOUtils.readStreamIntoByteArray(encryptedKeySource);
+ final byte[] decrypted = CryptUtils.decryptData(fromDisk, key);
+ return new String(decrypted);
+ }
+
+ /**
+ * Get the decrypted AWS key sorted in the resource directories of name
+ * @param name the name of the file containing the needed AWS key
+ * @return a non-null GATK
+ */
+ @Requires("name != null")
+ @Ensures("result != null")
+ private static String getAWSKey(final String name) {
+ final Resource resource = new Resource(name, GATKRunReport.class);
+ return decryptAWSKey(resource.getResourceContentsAsStream());
+ }
+
+ /**
+ * Get the AWS access key for the GATK user
+ * @return a non-null AWS access key for the GATK user
+ */
+ @Ensures("result != null")
+ protected static String getAWSUploadAccessKey() {
+ return getAWSKey("resources/GATK_AWS_access.key");
+ }
+
+ /**
+ * Get the AWS secret key for the GATK user
+ * @return a non-null AWS secret key for the GATK user
+ */
+ @Ensures("result != null")
+ protected static String getAWSUploadSecretKey() {
+ return getAWSKey("resources/GATK_AWS_secret.key");
+ }
+
+ /**
+ * Check that the AWS keys can be decrypted and are what we expect them to be
+ *
+ * @throws ReviewedGATKException if anything goes wrong
+ */
+ public static void checkAWSAreValid() {
+ try {
+ final String accessKeyMD5 = Utils.calcMD5(getAWSUploadAccessKey());
+ final String secretKeyMD5 = Utils.calcMD5(getAWSUploadSecretKey());
+
+ if ( ! AWS_ACCESS_KEY_MD5.equals(accessKeyMD5) ) {
+ throw new ReviewedGATKException("Invalid AWS access key found, expected MD5 " + AWS_ACCESS_KEY_MD5 + " but got " + accessKeyMD5);
+ }
+ if ( ! AWS_SECRET_KEY_MD5.equals(secretKeyMD5) ) {
+ throw new ReviewedGATKException("Invalid AWS secret key found, expected MD5 " + AWS_SECRET_KEY_MD5 + " but got " + secretKeyMD5);
+ }
+
+ } catch ( Exception e ) {
+ throw new ReviewedGATKException("Couldn't decrypt AWS keys, something is wrong with the GATK distribution");
+ }
+ }
+
+ /**
+ * Get an initialized S3Service for use in communicating with AWS/s3
+ *
+ * @param awsAccessKey our AWS access key to use
+ * @param awsSecretKey our AWS secret key to use
+ * @return an initialized S3Service object that can be immediately used to interact with S3
+ * @throws S3ServiceException
+ */
+ @Requires({"awsAccessKey != null", "awsSecretKey != null"})
+ @Ensures("result != null")
+ protected static S3Service initializeAWSService(final String awsAccessKey, final String awsSecretKey) throws S3ServiceException {
+ // To communicate with S3, create a class that implements an S3Service. We will use the REST/HTTP
+ // implementation based on HttpClient, as this is the most robust implementation provided with JetS3t.
+ final AWSCredentials awsCredentials = new AWSCredentials(awsAccessKey, awsSecretKey);
+ return new RestS3Service(awsCredentials);
+ }
+
+ /**
+ * A runnable that pushes this GATKReport up to s3.
+ *
+ * Should be run in a separate thread so we can time it out if something is taking too long
+ */
+ private class S3PutRunnable implements Runnable {
+ /** Was the upload operation successful? */
+ public final AtomicBoolean isSuccess;
+ /** The name of this report */
+ private final String filename;
+ /** The contents of this report */
+ private final byte[] contents;
+
+ /** The s3Object that we created to upload, or null if it failed */
+ public S3Object s3Object = null;
+
+ @Requires({"filename != null", "contents != null"})
+ public S3PutRunnable(final String filename, final byte[] contents){
+ this.isSuccess = new AtomicBoolean();
+ this.filename = filename;
+ this.contents = contents;
+ }
+
+ public void run() {
+ try {
+ switch ( awsMode ) {
+ case FAIL_WITH_EXCEPTION:
+ throw new IllegalStateException("We are throwing an exception for testing purposes");
+ case TIMEOUT:
+ try {
+ Thread.sleep(s3PutTimeOutInMilliseconds * 100);
+ } catch ( InterruptedException e ) {
+ // supposed to be empty
+ }
+ break;
+ case NORMAL:
+ // IAM GATK user credentials -- only right is to PutObject into broad.gsa.gatk.run.reports bucket
+ final S3Service s3Service = initializeAWSService(getAWSUploadAccessKey(), getAWSUploadSecretKey());
+
+ // Create an S3Object based on a file, with Content-Length set automatically and
+ // Content-Type set based on the file's extension (using the Mimetypes utility class)
+ final S3Object fileObject = new S3Object(filename, contents);
+ //logger.info("Created S3Object" + fileObject);
+ //logger.info("Uploading " + localFile + " to AWS bucket");
+ s3Object = s3Service.putObject(getS3ReportBucket(), fileObject);
+ isSuccess.set(true);
+ break;
+ default:
+ throw new IllegalStateException("Unexpected AWS exception");
+ }
+ } catch ( S3ServiceException e ) {
+ exceptDuringRunReport("S3 exception occurred", e);
+ } catch ( NoSuchAlgorithmException e ) {
+ exceptDuringRunReport("Couldn't calculate MD5", e);
+ } catch ( IOException e ) {
+ exceptDuringRunReport("Couldn't read report file", e);
+ } catch ( Exception e ) {
+ exceptDuringRunReport("An unexpected exception occurred during posting", e);
+ }
+ }
+ }
+
+ /**
+ * Post this GATK report to the AWS s3 GATK_Run_Report log
+ *
+ * @return the s3Object pointing to our pushed report, or null if we failed to push
+ */
+ protected S3Object postReportToAWSS3() {
+ // modifying example code from http://jets3t.s3.amazonaws.com/toolkit/code-samples.html
+ this.hostName = Utils.resolveHostname(); // we want to fill in the host name
+ final String key = getReportFileName();
+ logger.debug("Generating GATK report to AWS S3 with key " + key);
+
+ try {
+ // create an byte output stream so we can capture the output as a byte[]
+ final ByteArrayOutputStream byteStream = new ByteArrayOutputStream(8096);
+ final OutputStream outputStream = new GZIPOutputStream(byteStream);
+ postReportToStream(outputStream);
+ outputStream.close();
+ final byte[] report = byteStream.toByteArray();
+
+ // stop us from printing the annoying, and meaningless, mime types warning
+ final Logger mimeTypeLogger = Logger.getLogger(org.jets3t.service.utils.Mimetypes.class);
+ mimeTypeLogger.setLevel(Level.FATAL);
+
+ // Set the S3 upload on its own thread with timeout:
+ final S3PutRunnable s3run = new S3PutRunnable(key,report);
+ final Thread s3thread = new Thread(s3run);
+ s3thread.setDaemon(true);
+ s3thread.setName("S3Put-Thread");
+ s3thread.start();
+
+ s3thread.join(s3PutTimeOutInMilliseconds);
+
+ if(s3thread.isAlive()){
+ s3thread.interrupt();
+ exceptDuringRunReport("Run statistics report upload to AWS S3 timed-out");
+ } else if(s3run.isSuccess.get()) {
+ logger.info("Uploaded run statistics report to AWS S3");
+ logger.debug("Uploaded to AWS: " + s3run.s3Object);
+ return s3run.s3Object;
+ } else {
+ // an exception occurred, the thread should have already invoked the exceptDuringRunReport function
+ }
+ } catch ( IOException e ) {
+ exceptDuringRunReport("Couldn't read report file", e);
+ } catch ( InterruptedException e) {
+ exceptDuringRunReport("Run statistics report upload interrupted", e);
+ }
+
+ return null;
+ }
+
+ // ---------------------------------------------------------------------------
+ //
+ // Error handling code
+ //
+ // ---------------------------------------------------------------------------
+
+ /**
+ * Note that an exception occurred during creating or writing this report
+ * @param msg the message to print
+ * @param e the exception that occurred
+ */
+ @Ensures("exceptionOccurredDuringPost()")
+ private void exceptDuringRunReport(final String msg, final Throwable e) {
+ this.errorMessage = msg;
+ this.errorThrown = e;
+ logger.debug("A problem occurred during GATK run reporting [*** everything is fine, but no report could be generated; please do not post this to the support forum ***]. Message is: " + msg + ". Error message is: " + e.getMessage());
+ }
+
+ /**
+ * Note that an exception occurred during creating or writing this report
+ * @param msg the message to print
+ */
+ @Ensures("exceptionOccurredDuringPost()")
+ private void exceptDuringRunReport(final String msg) {
+ this.errorMessage = msg;
+ logger.debug("A problem occurred during GATK run reporting [*** everything is fine, but no report could be generated; please do not post this to the support forum ***]. Message is " + msg);
+ }
+
+ /**
+ * Did an error occur during the posting of this run report?
+ * @return true if so, false if not
+ */
+ public boolean exceptionOccurredDuringPost() {
+ return getErrorMessage() != null;
+ }
+
+ /**
+ * If an error occurred during posting of this report, retrieve the message of the error that occurred, or null if
+ * no error occurred
+ * @return a string describing the error that occurred, or null if none did
+ */
+ public String getErrorMessage() {
+ return errorMessage;
+ }
+
+ /**
+ * Get the throwable that caused the exception during posting of this message, or null if none was available
+ *
+ * Note that getting a null valuable from this function doesn't not imply that no error occurred. Some
+ * errors that occurred many not have generated a throwable.
+ *
+ * @return the Throwable that caused the error, or null if no error occurred or was not caused by a throwable
+ */
+ public Throwable getErrorThrown() {
+ return errorThrown;
+ }
+
+ /**
+ * Helper method to format the exception that occurred during posting, or a string saying none occurred
+ * @return a non-null string
+ */
+ @Ensures("result != null")
+ protected String formatError() {
+ return exceptionOccurredDuringPost()
+ ? String.format("Exception message=%s with cause=%s", getErrorMessage(), getErrorThrown())
+ : "No exception occurred";
+ }
+
+ // ---------------------------------------------------------------------------
+ //
+ // Equals and hashcode -- purely for comparing reports for testing
+ //
+ // ---------------------------------------------------------------------------
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ GATKRunReport that = (GATKRunReport) o;
+
+ if (maxMemory != that.maxMemory) return false;
+ if (nIterations != that.nIterations) return false;
+ if (numThreads != that.numThreads) return false;
+ if (runTime != that.runTime) return false;
+ if (totalMemory != that.totalMemory) return false;
+ if (endTime != null ? !endTime.equals(that.endTime) : that.endTime != null) return false;
+ if (hostName != null ? !hostName.equals(that.hostName) : that.hostName != null) return false;
+ if (id != null ? !id.equals(that.id) : that.id != null) return false;
+ if (javaVersion != null ? !javaVersion.equals(that.javaVersion) : that.javaVersion != null) return false;
+ if (mException != null ? !mException.equals(that.mException) : that.mException != null) return false;
+ if (machine != null ? !machine.equals(that.machine) : that.machine != null) return false;
+ if (percentTimeBlocking != null ? !percentTimeBlocking.equals(that.percentTimeBlocking) : that.percentTimeBlocking != null)
+ return false;
+ if (percentTimeRunning != null ? !percentTimeRunning.equals(that.percentTimeRunning) : that.percentTimeRunning != null)
+ return false;
+ if (percentTimeWaiting != null ? !percentTimeWaiting.equals(that.percentTimeWaiting) : that.percentTimeWaiting != null)
+ return false;
+ if (percentTimeWaitingForIO != null ? !percentTimeWaitingForIO.equals(that.percentTimeWaitingForIO) : that.percentTimeWaitingForIO != null)
+ return false;
+ if (startTime != null ? !startTime.equals(that.startTime) : that.startTime != null) return false;
+ if (svnVersion != null ? !svnVersion.equals(that.svnVersion) : that.svnVersion != null) return false;
+ if (tag != null ? !tag.equals(that.tag) : that.tag != null) return false;
+ if (userName != null ? !userName.equals(that.userName) : that.userName != null) return false;
+ if (walkerName != null ? !walkerName.equals(that.walkerName) : that.walkerName != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = id != null ? id.hashCode() : 0;
+ result = 31 * result + (mException != null ? mException.hashCode() : 0);
+ result = 31 * result + (startTime != null ? startTime.hashCode() : 0);
+ result = 31 * result + (endTime != null ? endTime.hashCode() : 0);
+ result = 31 * result + (int) (runTime ^ (runTime >>> 32));
+ result = 31 * result + (walkerName != null ? walkerName.hashCode() : 0);
+ result = 31 * result + (svnVersion != null ? svnVersion.hashCode() : 0);
+ result = 31 * result + (int) (totalMemory ^ (totalMemory >>> 32));
+ result = 31 * result + (int) (maxMemory ^ (maxMemory >>> 32));
+ result = 31 * result + (userName != null ? userName.hashCode() : 0);
+ result = 31 * result + (hostName != null ? hostName.hashCode() : 0);
+ result = 31 * result + (javaVersion != null ? javaVersion.hashCode() : 0);
+ result = 31 * result + (machine != null ? machine.hashCode() : 0);
+ result = 31 * result + (int) (nIterations ^ (nIterations >>> 32));
+ result = 31 * result + (tag != null ? tag.hashCode() : 0);
+ result = 31 * result + numThreads;
+ result = 31 * result + (percentTimeRunning != null ? percentTimeRunning.hashCode() : 0);
+ result = 31 * result + (percentTimeWaiting != null ? percentTimeWaiting.hashCode() : 0);
+ result = 31 * result + (percentTimeBlocking != null ? percentTimeBlocking.hashCode() : 0);
+ result = 31 * result + (percentTimeWaitingForIO != null ? percentTimeWaitingForIO.hashCode() : 0);
+ return result;
+ }
+
+ // ---------------------------------------------------------------------------
+ //
+ // Code specifically for testing the GATKRunReport
+ //
+ // ---------------------------------------------------------------------------
+
+ /**
+ * Enum specifying how the S3 uploader should behave. Must be normal by default. Purely for testing purposes
+ */
+ protected enum AWSMode {
+ NORMAL, // write normally to AWS
+ FAIL_WITH_EXCEPTION, // artificially fail during writing
+ TIMEOUT // sleep, so we time out
+ }
+ /** Our AWS mode */
+ private AWSMode awsMode = AWSMode.NORMAL;
+ /** The bucket were we send the GATK report on AWS/s3 */
+ private String s3ReportBucket = REPORT_BUCKET_NAME;
+ /** Did we send the report to AWS? */
+ private boolean wentToAWS = false;
+
+ /**
+ * Send the report to the AWS test bucket -- for testing only
+ */
+ protected void sendAWSToTestBucket() {
+ s3ReportBucket = TEST_REPORT_BUCKET_NAME;
+ }
+
+ /**
+ * Has the report been written to AWS?
+ *
+ * Does not imply anything about the success of the send, just that it was attempted
+ *
+ * @return true if the report has been sent to AWS, false otherwise
+ */
+ protected boolean wentToAWS() {
+ return wentToAWS;
+ }
+
+ /**
+ * Purely for testing purposes. Tells the AWS uploader whether to actually upload or simulate errors
+ * @param mode what we want to do
+ */
+ @Requires("mode != null")
+ protected void setAwsMode(final AWSMode mode) {
+ this.awsMode = mode;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/phonehome/GATKRunReportException.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/phonehome/GATKRunReportException.java
new file mode 100644
index 0000000..4de344e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/phonehome/GATKRunReportException.java
@@ -0,0 +1,99 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.phonehome;
+
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.simpleframework.xml.Element;
+import org.simpleframework.xml.ElementList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class for formatting in XML the throwable chain starting at e.
+ */
+class GATKRunReportException {
+ @Element(required = false, name = "message")
+ String message = null;
+
+ @ElementList(required = false, name = "stacktrace")
+ final List<String> stackTrace = new ArrayList<String>();
+
+ @Element(required = false, name = "cause")
+ GATKRunReportException cause = null;
+
+ @Element(required = false, name = "is-user-exception")
+ Boolean isUserException;
+
+ @Element(required = false, name = "exception-class")
+ Class exceptionClass;
+
+ /**
+ * Allow us to deserialize from XML
+ */
+ public GATKRunReportException() { }
+
+ public GATKRunReportException(Throwable e) {
+ message = e.getMessage();
+ exceptionClass = e.getClass();
+ isUserException = e instanceof UserException;
+ for (StackTraceElement element : e.getStackTrace()) {
+ stackTrace.add(element.toString());
+ }
+
+ if ( e.getCause() != null ) {
+ cause = new GATKRunReportException(e.getCause());
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ GATKRunReportException that = (GATKRunReportException) o;
+
+ if (cause != null ? !cause.equals(that.cause) : that.cause != null) return false;
+ if (exceptionClass != null ? !exceptionClass.equals(that.exceptionClass) : that.exceptionClass != null)
+ return false;
+ if (isUserException != null ? !isUserException.equals(that.isUserException) : that.isUserException != null)
+ return false;
+ if (message != null ? !message.equals(that.message) : that.message != null) return false;
+ if (stackTrace != null ? !stackTrace.equals(that.stackTrace) : that.stackTrace != null) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = message != null ? message.hashCode() : 0;
+ result = 31 * result + (stackTrace != null ? stackTrace.hashCode() : 0);
+ result = 31 * result + (cause != null ? cause.hashCode() : 0);
+ result = 31 * result + (isUserException != null ? isUserException.hashCode() : 0);
+ result = 31 * result + (exceptionClass != null ? exceptionClass.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/RODRecordListImpl.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/RODRecordListImpl.java
new file mode 100644
index 0000000..7296c39
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/RODRecordListImpl.java
@@ -0,0 +1,129 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata;
+
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.HasGenomeLocation;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: asivache
+ * Date: Sep 10, 2009
+ * Time: 6:10:48 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class RODRecordListImpl extends AbstractList<GATKFeature> implements Comparable<RODRecordList>, Cloneable, RODRecordList, HasGenomeLocation {
+ private List<GATKFeature> records;
+ private GenomeLoc location = null;
+ private String name = null;
+
+ public RODRecordListImpl(String name) {
+ records = new ArrayList<GATKFeature>();
+ this.name = name;
+ }
+
+ /**
+ * Fully qualified constructor: instantiates a new GATKFeatureRecordList object with specified GATKFeature track name, location on the
+ * reference, and list of associated GATKFeatures. This is a knee-deep COPY constructor: passed name, loc, and data element
+ * objects will be referenced from the created GATKFeatureRecordList (so that changing them from outside will affect data
+ * in this object), however, the data elements will be copied into a newly
+ * allocated list, so that the 'data' collection argument can be modified afterwards without affecting the state
+ * of this record list. WARNING: this constructor is (semi-)validating: passed name and location
+ * are allowed to be nulls (although it maybe unsafe, use caution), but if they are not nulls, then passed non-null GATKFeature data
+ * elements must have same track name, and their locations must overlap with the passed 'location' argument. Null
+ * data elements or null 'data' collection argument are allowed as well.
+ * @param name the name of the track
+ * @param data the collection of features at this location
+ * @param loc the location
+ */
+ public RODRecordListImpl(String name, Collection<GATKFeature> data, GenomeLoc loc) {
+ this.records = new ArrayList<GATKFeature>(data==null?0:data.size());
+ this.name = name;
+ this.location = loc;
+ if ( data == null || data.size() == 0 ) return; // empty dataset, nothing to do
+ for ( GATKFeature r : data ) {
+ records.add(r);
+ if ( r == null ) continue;
+ if ( ! this.name.equals(r.getName() ) ) {
+ throw new ReviewedGATKException("Attempt to add GATKFeature with non-matching name "+r.getName()+" to the track "+name);
+ }
+ if ( location != null && ! location.overlapsP(r.getLocation()) ) {
+ throw new ReviewedGATKException("Attempt to add GATKFeature that lies outside of specified interval "+location+"; offending GATKFeature:\n"+r.toString());
+ }
+ }
+ }
+
+
+ public GenomeLoc getLocation() { return location; }
+ public String getName() { return name; }
+ public Iterator<GATKFeature> iterator() { return records.iterator() ; }
+ public void clear() { records.clear(); }
+ public boolean isEmpty() { return records.isEmpty(); }
+
+ public boolean add(GATKFeature record) { add(record, false); return true;}
+
+ @Override
+ public GATKFeature get(int i) {
+ return records.get(i);
+ }
+
+ public void add(GATKFeature record, boolean allowNameMismatch) {
+ if ( record != null ) {
+ if ( ! allowNameMismatch && ! name.equals(record.getName() ) )
+ throw new ReviewedGATKException("Attempt to add GATKFeature with non-matching name "+record.getName()+" to the track "+name);
+ }
+ records.add(record);
+ }
+
+ public void add(RODRecordList records ) { add( records, false ); }
+
+ public void add(RODRecordList records, boolean allowNameMismatch) {
+ for ( GATKFeature record : records )
+ add(record, allowNameMismatch);
+ }
+
+ public int size() { return records.size() ; }
+
+ /**
+ * Compares this object with the specified object for order. Returns a
+ * negative integer, zero, or a positive integer as this object is less
+ * than, equal to, or greater than the specified object.
+ *
+ * @param that the object to be compared.
+ * @return a negative integer, zero, or a positive integer as this object
+ * is less than, equal to, or greater than the specified object.
+ * @throws ClassCastException if the specified object's type prevents it
+ * from being compared to this object.
+ */
+ public int compareTo(RODRecordList that) {
+ return getLocation().compareTo(that.getLocation()); //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/RefMetaDataTracker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/RefMetaDataTracker.java
new file mode 100644
index 0000000..7ccf6e5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/RefMetaDataTracker.java
@@ -0,0 +1,497 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.*;
+
+/**
+ * This class represents the Reference Metadata available at a particular site in the genome. It can be
+ * used to conveniently lookup the RMDs at this site, as well just getting a list of all of the RMDs
+ *
+ * The standard interaction model is:
+ *
+ * Traversal system arrives at a site, which has a bunch of RMDs covering it
+ * Traversal passes creates a tracker and passes it to the walker
+ * walker calls get(rodBinding) to obtain the RMDs values at this site for the track
+ * associated with rodBinding.
+ *
+ * Note that this is an immutable class. Once created the underlying data structures
+ * cannot be modified
+ *
+ * User: mdepristo
+ * Date: Apr 3, 2009
+ * Time: 3:05:23 PM
+ */
+public class RefMetaDataTracker {
+ // TODO: this should be a list, not a bindings, actually
+ private final static RODRecordList EMPTY_ROD_RECORD_LIST = new RODRecordListImpl("EMPTY");
+
+ final Map<String, RODRecordList> bindings;
+ final protected static Logger logger = Logger.getLogger(RefMetaDataTracker.class);
+ public final static RefMetaDataTracker EMPTY_TRACKER = new RefMetaDataTracker();
+
+ // ------------------------------------------------------------------------------------------
+ //
+ //
+ // Special ENGINE interaction functions
+ //
+ //
+ // ------------------------------------------------------------------------------------------
+
+ /**
+ * Create an tracker with no bindings
+ */
+ public RefMetaDataTracker() {
+ bindings = Collections.emptyMap();
+ }
+
+ public RefMetaDataTracker(final Collection<RODRecordList> allBindings) {
+ // set up the bindings
+ if ( allBindings.isEmpty() )
+ bindings = Collections.emptyMap();
+ else {
+ final Map<String, RODRecordList> tmap = new HashMap<String, RODRecordList>(allBindings.size());
+ for ( RODRecordList rod : allBindings ) {
+ if ( rod != null && ! rod.isEmpty() )
+ tmap.put(canonicalName(rod.getName()), rod);
+ }
+
+ // ensure that no one modifies the bindings itself
+ bindings = Collections.unmodifiableMap(tmap);
+ }
+ }
+
+ // ------------------------------------------------------------------------------------------
+ //
+ //
+ // Generic accessors
+ //
+ //
+ // ------------------------------------------------------------------------------------------
+
+ /**
+ * Gets all of the Tribble features spanning this locus, returning them as a list of specific
+ * type T extending Feature. This function looks across all tracks to find the Features, so
+ * if you have two tracks A and B each containing 1 Feature, then getValues will return
+ * a list containing both features.
+ *
+ * Note that this function assumes that all of the bound features are instances of or
+ * subclasses of T. A ClassCastException will occur if this isn't the case. If you want
+ * to get all Features without any danger of such an exception use the root Tribble
+ * interface Feature.
+ *
+ * @param type The type of the underlying objects bound here
+ * @param <T> as above
+ * @return A freshly allocated list of all of the bindings, or an empty list if none are bound.
+ */
+ @Requires({"type != null"})
+ @Ensures("result != null")
+ public <T extends Feature> List<T> getValues(final Class<T> type) {
+ return addValues(bindings.keySet(), type, new ArrayList<T>(), null, false, false);
+ }
+
+ /**
+ * Provides the same functionality as @link #getValues(Class<T>) but will only include
+ * Features that start as the GenomeLoc provide onlyAtThisLoc.
+ *
+ * @param type The type of the underlying objects bound here
+ * @param onlyAtThisLoc
+ * @param <T> as above
+ * @return A freshly allocated list of all of the bindings, or an empty list if none are bound.
+ */
+ @Requires({"type != null", "onlyAtThisLoc != null"})
+ @Ensures("result != null")
+ public <T extends Feature> List<T> getValues(final Class<T> type, final GenomeLoc onlyAtThisLoc) {
+ return addValues(bindings.keySet(), type, new ArrayList<T>(), onlyAtThisLoc, true, false);
+ }
+
+ /**
+ * Uses the same logic as @link #getValues(Class) but arbitrary select one of the resulting
+ * elements of the list to return. That is, if there would be two elements in the result of
+ * @link #getValues(Class), one of these two is selected, and which one it will be isn't
+ * specified. Consequently, this method is only really safe if (1) you absolutely know
+ * that only one binding will meet the constraints of @link #getValues(Class) or (2)
+ * you truly don't care which of the multiple bindings available you are going to examine.
+ *
+ * If there are no bindings here, getFirstValue() return null
+ *
+ * @param type The type of the underlying objects bound here
+ * @param <T> as above
+ * @return A random single element the RODs bound here, or null if none are bound.
+ */
+ @Requires({"type != null"})
+ public <T extends Feature> T getFirstValue(final Class<T> type) {
+ return safeGetFirst(getValues(type));
+ }
+
+ /**
+ * Uses the same logic as @link #getValue(Class,GenomeLoc) to determine the list
+ * of eligible Features and @link #getFirstValue(Class) to select a single
+ * element from the interval list.
+ *
+ * @param type The type of the underlying objects bound here
+ * @param <T> as above
+ * @param onlyAtThisLoc only Features starting at this site are considered
+ * @return A random single element the RODs bound here starting at onlyAtThisLoc, or null if none are bound.
+ */
+ @Requires({"type != null", "onlyAtThisLoc != null"})
+ public <T extends Feature> T getFirstValue(final Class<T> type, final GenomeLoc onlyAtThisLoc) {
+ return safeGetFirst(getValues(type, onlyAtThisLoc));
+ }
+
+ /**
+ * Same logic as @link #getFirstValue(RodBinding, boolean) but prioritizes records from prioritizeThisLoc if available
+ *
+ * @param rodBindings Only Features coming from the tracks associated with one of rodBindings are fetched
+ * @param <T> The Tribble Feature type of the rodBinding, and consequently the type of the resulting list of Features
+ * @param prioritizeThisLoc only Features starting at this site are considered
+ * @return A freshly allocated list of all of the bindings, or an empty list if none are bound.
+ */
+ @Requires({"rodBindings != null", "prioritizeThisLoc != null"})
+ @Ensures("result != null")
+ public <T extends Feature> List<T> getPrioritizedValue(final Collection<RodBinding<T>> rodBindings, final GenomeLoc prioritizeThisLoc) {
+ final List<T> results = new ArrayList<>();
+
+ for ( final RodBinding<T> rodBinding : rodBindings ) {
+
+ // if there's a value at the prioritized location, take it
+ T value = getFirstValue(rodBinding, prioritizeThisLoc);
+
+ // otherwise, grab any one
+ if ( value == null )
+ value = getFirstValue(rodBinding);
+
+ // add if not null
+ if ( value != null )
+ results.add(value);
+ }
+
+ return results;
+ }
+
+ /**
+ * Gets all of the Tribble features bound to RodBinding spanning this locus, returning them as
+ * a list of specific type T extending Feature.
+ *
+ * Note that this function assumes that all of the bound features are instances of or
+ * subclasses of T. A ClassCastException will occur if this isn't the case.
+ *
+ * @param rodBinding Only Features coming from the track associated with this rodBinding are fetched
+ * @param <T> The Tribble Feature type of the rodBinding, and consequently the type of the resulting list of Features
+ * @return A freshly allocated list of all of the bindings, or an empty list if none are bound.
+ */
+ @Requires({"rodBinding != null"})
+ @Ensures("result != null")
+ public <T extends Feature> List<T> getValues(final RodBinding<T> rodBinding) {
+ return addValues(rodBinding.getName(), rodBinding.getType(), new ArrayList<T>(1), getTrackDataByName(rodBinding), null, false, false);
+ }
+
+ /**
+ * Gets all of the Tribble features bound to any RodBinding in rodBindings,
+ * spanning this locus, returning them as a list of specific type T extending Feature.
+ *
+ * Note that this function assumes that all of the bound features are instances of or
+ * subclasses of T. A ClassCastException will occur if this isn't the case.
+ *
+ * @param rodBindings Only Features coming from the tracks associated with one of rodBindings are fetched
+ * @param <T> The Tribble Feature type of the rodBinding, and consequently the type of the resulting list of Features
+ * @return A freshly allocated list of all of the bindings, or an empty list if none are bound.
+ */
+ @Requires({"rodBindings != null"})
+ @Ensures("result != null")
+ public <T extends Feature> List<T> getValues(final Collection<RodBinding<T>> rodBindings) {
+ List<T> results = new ArrayList<T>(1);
+ for ( RodBinding<T> rodBinding : rodBindings )
+ results.addAll(getValues(rodBinding));
+ return results;
+ }
+
+ /**
+ * The same logic as @link #getValues(RodBinding) but enforces that each Feature start at onlyAtThisLoc
+ *
+ * @param rodBinding Only Features coming from the track associated with this rodBinding are fetched
+ * @param <T> The Tribble Feature type of the rodBinding, and consequently the type of the resulting list of Features
+ * @param onlyAtThisLoc only Features starting at this site are considered
+ * @return A freshly allocated list of all of the bindings, or an empty list if none are bound.
+ */
+ @Requires({"rodBinding != null", "onlyAtThisLoc != null"})
+ @Ensures("result != null")
+ public <T extends Feature> List<T> getValues(final RodBinding<T> rodBinding, final GenomeLoc onlyAtThisLoc) {
+ return addValues(rodBinding.getName(), rodBinding.getType(), new ArrayList<T>(1), getTrackDataByName(rodBinding), onlyAtThisLoc, true, false);
+ }
+
+ /**
+ * The same logic as @link #getValues(List) but enforces that each Feature start at onlyAtThisLoc
+ *
+ * @param rodBindings Only Features coming from the tracks associated with one of rodBindings are fetched
+ * @param <T> The Tribble Feature type of the rodBinding, and consequently the type of the resulting list of Features
+ * @param onlyAtThisLoc only Features starting at this site are considered
+ * @return A freshly allocated list of all of the bindings, or an empty list if none are bound.
+ */
+ @Requires({"rodBindings != null", "onlyAtThisLoc != null"})
+ @Ensures("result != null")
+ public <T extends Feature> List<T> getValues(final Collection<RodBinding<T>> rodBindings, final GenomeLoc onlyAtThisLoc) {
+ List<T> results = new ArrayList<T>(1);
+ for ( RodBinding<T> rodBinding : rodBindings )
+ results.addAll(getValues(rodBinding, onlyAtThisLoc));
+ return results;
+ }
+
+ /**
+ * Uses the same logic as @getValues(RodBinding) to determine the list
+ * of eligible Features and select a single element from the resulting set
+ * of eligible features.
+ *
+ * @param rodBinding Only Features coming from the track associated with this rodBinding are fetched
+ * @param <T> as above
+ * @return A random single element the eligible Features found, or null if none are bound.
+ */
+ @Requires({"rodBinding != null"})
+ public <T extends Feature> T getFirstValue(final RodBinding<T> rodBinding) {
+ return safeGetFirst(addValues(rodBinding.getName(), rodBinding.getType(), null, getTrackDataByName(rodBinding), null, false, true));
+ }
+
+ /**
+ * Uses the same logic as @getValues(RodBinding, GenomeLoc) to determine the list
+ * of eligible Features and select a single element from the resulting set
+ * of eligible features.
+ *
+ * @param rodBinding Only Features coming from the track associated with this rodBinding are fetched
+ * @param <T> as above
+ * @param onlyAtThisLoc only Features starting at this site are considered
+ * @return A random single element the eligible Features found, or null if none are bound.
+ */
+ @Requires({"rodBinding != null", "onlyAtThisLoc != null"})
+ public <T extends Feature> T getFirstValue(final RodBinding<T> rodBinding, final GenomeLoc onlyAtThisLoc) {
+ return safeGetFirst(addValues(rodBinding.getName(), rodBinding.getType(), null, getTrackDataByName(rodBinding), onlyAtThisLoc, true, true));
+ }
+
+ /**
+ * Uses the same logic as @getValues(List) to determine the list
+ * of eligible Features and select a single element from the resulting set
+ * of eligible features.
+ *
+ * @param rodBindings Only Features coming from the tracks associated with these rodBindings are fetched
+ * @param <T> as above
+ * @return A random single element the eligible Features found, or null if none are bound.
+ */
+ @Requires({"rodBindings != null"})
+ public <T extends Feature> T getFirstValue(final Collection<RodBinding<T>> rodBindings) {
+ for ( RodBinding<T> rodBinding : rodBindings ) {
+ T val = getFirstValue(rodBinding);
+ if ( val != null )
+ return val;
+ }
+ return null;
+ }
+
+ /**
+ * Uses the same logic as @getValues(RodBinding,GenomeLoc) to determine the list
+ * of eligible Features and select a single element from the resulting set
+ * of eligible features.
+ *
+ * @param rodBindings Only Features coming from the tracks associated with these rodBindings are fetched
+ * @param <T> as above
+ * @param onlyAtThisLoc only Features starting at this site are considered
+ * @return A random single element the eligible Features found, or null if none are bound.
+ */
+ @Requires({"rodBindings != null", "onlyAtThisLoc != null"})
+ public <T extends Feature> T getFirstValue(final Collection<RodBinding<T>> rodBindings, final GenomeLoc onlyAtThisLoc) {
+ for ( RodBinding<T> rodBinding : rodBindings ) {
+ T val = getFirstValue(rodBinding, onlyAtThisLoc);
+ if ( val != null )
+ return val;
+ }
+ return null;
+ }
+
+ /**
+ * Is there a binding at this site to a ROD/track with the specified name?
+ *
+ * @param rodBinding the rod binding we want to know about
+ * @return true if any Features are bound in this tracker to rodBinding
+ */
+ @Requires({"rodBinding != null"})
+ public boolean hasValues(final RodBinding rodBinding) {
+ return bindings.containsKey(canonicalName(rodBinding.getName()));
+ }
+
+ /**
+ * Get all of the RMD tracks at the current site. Each track is returned as a single compound
+ * object (RODRecordList) that may contain multiple RMD records associated with the current site.
+ *
+ * @return List of all tracks
+ */
+ public List<RODRecordList> getBoundRodTracks() {
+ return new ArrayList<RODRecordList>(bindings.values());
+ }
+
+ /**
+ * The number of tracks with at least one value bound here
+ * @return the number of tracks with at least one bound Feature
+ */
+ public int getNTracksWithBoundFeatures() {
+ return bindings.size();
+ }
+
+ // ------------------------------------------------------------------------------------------
+ // Protected accessors using strings for unit testing
+ // ------------------------------------------------------------------------------------------
+
+ protected boolean hasValues(final String name) {
+ return bindings.containsKey(canonicalName(name));
+ }
+
+ protected <T extends Feature> List<T> getValues(final Class<T> type, final String name) {
+ return addValues(name, type, new ArrayList<T>(), getTrackDataByName(name), null, false, false);
+ }
+
+ protected <T extends Feature> List<T> getValues(final Class<T> type, final String name, final GenomeLoc onlyAtThisLoc) {
+ return addValues(name, type, new ArrayList<T>(), getTrackDataByName(name), onlyAtThisLoc, true, false);
+ }
+
+ protected <T extends Feature> T getFirstValue(final Class<T> type, final String name) {
+ return safeGetFirst(getValues(type, name));
+ }
+
+ protected <T extends Feature> T getFirstValue(final Class<T> type, final String name, final GenomeLoc onlyAtThisLoc) {
+ return safeGetFirst(getValues(type, name, onlyAtThisLoc));
+ }
+
+ // ------------------------------------------------------------------------------------------
+ //
+ //
+ // Private utility functions
+ //
+ //
+ // ------------------------------------------------------------------------------------------
+
+ /**
+ * Helper function for getFirst() operations that takes a list of <T> and
+ * returns the first element, or null if no such element exists.
+ *
+ * @param l
+ * @param <T>
+ * @return
+ */
+ @Requires({"l != null"})
+ private <T extends Feature> T safeGetFirst(final List<T> l) {
+ return l.isEmpty() ? null : l.get(0);
+ }
+
+ private <T extends Feature> List<T> addValues(final Collection<String> names,
+ final Class<T> type,
+ List<T> values,
+ final GenomeLoc curLocation,
+ final boolean requireStartHere,
+ final boolean takeFirstOnly ) {
+ for ( String name : names ) {
+ RODRecordList rodList = getTrackDataByName(name); // require that the name is an exact match
+ values = addValues(name, type, values, rodList, curLocation, requireStartHere, takeFirstOnly );
+ if ( takeFirstOnly && ! values.isEmpty() )
+ break;
+ }
+
+ return values;
+ }
+
+
+
+ private <T extends Feature> List<T> addValues(final String name,
+ final Class<T> type,
+ List<T> values,
+ final RODRecordList rodList,
+ final GenomeLoc curLocation,
+ final boolean requireStartHere,
+ final boolean takeFirstOnly ) {
+ for ( GATKFeature rec : rodList ) {
+ if ( ! requireStartHere || rec.getLocation().getStart() == curLocation.getStart() ) { // ok, we are going to keep this thing
+ Object obj = rec.getUnderlyingObject();
+ if (!(type.isAssignableFrom(obj.getClass())))
+ throw new UserException.CommandLineException("Unable to cast track named " + name + " to type of " + type.toString()
+ + " it's of type " + obj.getClass());
+
+ T objT = (T)obj;
+ if ( takeFirstOnly ) {
+ if ( values == null )
+ values = Arrays.asList(objT);
+ else
+ values.add(objT);
+
+ break;
+ } else {
+ if ( values == null )
+ values = new ArrayList<T>();
+ values.add(objT);
+ }
+ }
+ }
+
+ return values == null ? Collections.<T>emptyList() : values;
+ }
+
+ /**
+ * Finds the reference metadata track named 'name' and returns all ROD records from that track associated
+ * with the current site as a RODRecordList List object. If no data track with specified name is available,
+ * returns defaultValue wrapped as RODRecordList object. NOTE: if defaultValue is null, it will be wrapped up
+ * with track name set to 'name' and location set to null; otherwise the wrapper object will have name and
+ * location set to defaultValue.getID() and defaultValue.getLocation(), respectively (use caution,
+ * defaultValue.getLocation() may be not equal to what RODRecordList's location would be expected to be otherwise:
+ * for instance, on locus traversal, location is usually expected to be a single base we are currently looking at,
+ * regardless of the presence of "extended" RODs overlapping with that location).
+ * @param name track name
+ * @return track data for the given rod
+ */
+ private RODRecordList getTrackDataByName(final String name) {
+ final String luName = canonicalName(name);
+ RODRecordList l = bindings.get(luName);
+ return l == null ? EMPTY_ROD_RECORD_LIST : l;
+ }
+
+ private RODRecordList getTrackDataByName(final RodBinding binding) {
+ return getTrackDataByName(binding.getName());
+ }
+
+ /**
+ * Returns the canonical name of the rod name (lowercases it)
+ * @param name the name of the rod
+ * @return canonical name of the rod
+ */
+ private String canonicalName(final String name) {
+ // todo -- remove me after switch to RodBinding syntax
+ return name.toLowerCase();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/ReferenceDependentFeatureCodec.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/ReferenceDependentFeatureCodec.java
new file mode 100644
index 0000000..9bff00d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/ReferenceDependentFeatureCodec.java
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata;
+
+import htsjdk.tribble.FeatureCodec;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+/**
+ * An interface marking that a given Tribble feature/codec is actually dependent on context within the
+ * reference, rather than having a dependency only on the contig, start, and stop of the given feature.
+ * A HACK. Tribble should contain all the information in needs to decode the unqualified position of
+ * a feature.
+ */
+public interface ReferenceDependentFeatureCodec {
+ /**
+ * Sets the appropriate GenomeLocParser, providing additional context when decoding larger and more variable features.
+ * @param genomeLocParser The parser to supply.
+ */
+ public void setGenomeLocParser(GenomeLocParser genomeLocParser);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/ReferenceOrderedDatum.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/ReferenceOrderedDatum.java
new file mode 100644
index 0000000..95de832
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/ReferenceOrderedDatum.java
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata;
+
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.HasGenomeLocation;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mdepristo
+ * Date: Feb 27, 2009
+ * Time: 10:49:47 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface ReferenceOrderedDatum extends Comparable<ReferenceOrderedDatum>, HasGenomeLocation {
+ public String getName();
+ public boolean parseLine(final Object header, final String[] parts) throws IOException;
+ public String toString();
+ public String toSimpleString();
+ public String repl();
+
+ /**
+ * Used by the ROD system to determine how to split input lines
+ * @return Regex string delimiter separating fields
+ */
+ public String delimiterRegex();
+
+ public GenomeLoc getLocation();
+ public int compareTo( ReferenceOrderedDatum that );
+
+ /**
+ * Backdoor hook to read header, meta-data, etc. associated with the file. Will be
+ * called by the ROD system before streaming starts
+ *
+ * @param source source data file on disk from which this rod stream will be pulled
+ * @return a header object that will be passed to parseLine command
+ */
+ public Object initialize(final File source) throws FileNotFoundException;
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/SeekableRODIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/SeekableRODIterator.java
new file mode 100644
index 0000000..4126214
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/SeekableRODIterator.java
@@ -0,0 +1,412 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.util.CloseableIterator;
+import org.broadinstitute.gatk.engine.iterators.PushbackIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.engine.refdata.utils.LocationAwareSeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Wrapper class for iterators over ROD objects. It is assumed that the underlying iterator can only
+ * perform standard next() operation, which advances it to the next ROD in the stream (i.e. reads the data file
+ * line by line). This iterator 1) shifts the focus from record-based traversal to position-based traversal,
+ * and 2) adds querying seekForward() method.
+ *
+ * Namely, this iterator's next() method advances not to the next ROD in the underlying stream, but to the next
+ * genomic position covered by (at least one) ROD, and returns all RODs overlapping with that position as a RODRecordList
+ * collection-like object. Similarly, when seekForward(interval) is called, this iterator skips all the RODs from the
+ * underlying stream, until it reaches specified genomic interval, and returns the list of all RODs overlapping with that interval.
+ *
+ * NOTE: this iterator has a STATE: next() operation is not allowed after a seekForward() to a non-point (extended) interval
+ * of length > 1. Such a call would leave the iterator in an inconsistent state. seekForward() can always be called after
+ * either seekForward() or next() (as long as usual ordering criteria are satisfied: the query interval location can neither
+ * start before the current position, nor end before the previous query end). seekForward to an interval of length 1
+ * reenables next() operation.
+ *
+ * Created by IntelliJ IDEA.
+ * User: asivache
+ * Date: Sep 10, 2009
+ * Time: 6:20:46 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class SeekableRODIterator implements LocationAwareSeekableRODIterator {
+ /**
+ * Header for the datasource backing this iterator.
+ */
+ private final Object header;
+
+ /**
+ * The parser, used to construct new genome locs.
+ */
+ private final GenomeLocParser parser;
+
+ private final SAMSequenceDictionary sequenceDictionary;
+
+ private PushbackIterator<GATKFeature> it;
+ List<GATKFeature> records = null; // here we will keep a pile of records overlaping with current position; when we iterate
+ // and step out of record's scope, we purge it from the list
+ String name = null; // name of the ROD track wrapped by this iterator. Will be pulled from underlying iterator.
+
+ int curr_position = 0; // where the iterator is currently positioned on the genome
+ int max_position = 0; // the rightmost stop position of currently loaded records
+ String curr_contig = null; // what contig the iterator is currently on
+ boolean next_is_allowed = true; // see discussion below. next() is illegal after seek-forward queries of length > 1
+
+ // the stop position of the last query. We can query only in forward direction ("seek forward");
+ // it is not only the start position of every successive query that can not be before the start
+ // of the previous one (curr_start), but it is also illegal for a query interval to *end* before
+ // the end of previous query, otherwise we can end up in an inconsistent state
+ int curr_query_end = -1;
+
+ // EXAMPLE of inconsistency curr_query_end guards against:
+ // record 1 record 2
+ // ---------- -----------
+ // -------------------------------------------------- REF
+ // ------------------------- query 1 (interval 1)
+ // ---------- query 2 (interval 2)
+ // --------------- query 3
+ //
+ // If we query first for interval 1, both record 1 and record 2 will be loaded.
+ // Query for interval 2, on the other hand, should return only record 1, but after
+ // query 1 was performed, record 2 is already loaded from the file. If, on the other hand,
+ // we try to un-load it from memory, we won't be able to read it again. Hence query 2 is not
+ // allowed after query 1. Note also, that curr_query_end is not equivalent to max_position:
+ // the latter only tracks where currently loaded records end (and hence helps to re-load records);
+ // after query 1 is performed, max_position will be the end of record 2, but query 3 is still
+ // perfectly legal after query 1.
+ //
+ // IMPORTANT NOTE: it follows from the above discussion and example that next() is illegal after ANY
+ // seek-forward query EXCEPT those that are performed with length-1 intervals (queryInterval.start=queryinteval.stop).
+ // Indeed, in the example above, after, e.g., query 1 is performed, the iterator is "located" at the start
+ // of interval 1, but record1 and record 2 are already loaded. On the other hand, a subsequent call to next() would
+ // need to shift iterator's position by 1 base and return only record 1.
+ //
+ // This implementation tracks the query history and makes next() illegal after a seekforward query of length > 1,
+ // but re-enables next() again after a length-1 query.
+
+ public SeekableRODIterator(Object header,SAMSequenceDictionary rodDictionary,SAMSequenceDictionary referenceDictionary,GenomeLocParser parser,CloseableIterator<GATKFeature> it) {
+ this.header = header;
+ this.parser = parser;
+ this.sequenceDictionary = rodDictionary;
+ this.it = new PushbackIterator<GATKFeature>(it);
+ records = new LinkedList<GATKFeature>();
+ // the following is a trick: we would like the iterator to know the actual name assigned to
+ // the ROD implementing object we are working with. But the only way to do that is to
+ // get an instance of that ROD and query it for its name. Now, the only generic way we have at this point to instantiate
+ // the ROD is to make the underlying stream iterator to do it for us. So we are reading (or rather peeking into)
+ // the first line of the track data file just to get the ROD object created.
+ GATKFeature r = null;
+ if (this.it.hasNext()) r = this.it.element();
+ name = (r==null?null:r.getName());
+
+ curr_contig = referenceDictionary.getSequence(0).getSequenceName();
+ }
+
+ /**
+ * Gets the header associated with the backing input stream.
+ * @return the ROD header.
+ */
+ @Override
+ public Object getHeader() {
+ return header;
+ }
+
+ /**
+ * Gets the sequence dictionary associated with the backing input stream.
+ * @return sequence dictionary from the ROD header.
+ */
+ @Override
+ public SAMSequenceDictionary getSequenceDictionary() {
+ return sequenceDictionary;
+ }
+
+
+ /**
+ * Returns true if the data we iterate over has records associated with (any, not necessarily adjacent)
+ * genomic position farther along the reference.
+ * @return
+ */
+ public boolean hasNext() {
+
+ // if we did not walk to the very end of the interval(s) covered by currently loaded
+ // annotations (records), then we definitely have data for next genomic location
+ if ( curr_position < max_position ) return true;
+
+ // we are past currently loaded stuff; we have next if there are more lines to load:
+ return it.hasNext();
+ }
+
+ // Returns point location (i.e. genome loc of length 1) on the reference, to which this iterator will advance
+ // upon next call to next().
+ public GenomeLoc peekNextLocation() {
+ if ( curr_position + 1 <= max_position ) return parser.createGenomeLoc(curr_contig,curr_position+1);
+
+ // sorry, next reference position is not covered by the RODs we are currently holding. In this case,
+ // the location we will jump to upon next call to next() is the start of the next ROD record that we did
+ // not read yet:
+ if ( it.hasNext() ) {
+ GATKFeature r = it.element(); // peek, do not load!
+ return parser.createGenomeLoc(r.getLocation().getContig(),r.getLocation().getStart());
+ }
+ return null; // underlying iterator has no more records, there is no next location!
+ }
+
+ /** Advances iterator to the next genomic position that has ROD record(s) associated with it,
+ * and returns all the records overlapping with that position as a RODList. The location of the whole
+ * RODList object will be set to the smallest interval subsuming genomic intervals of all returned records.
+ * Note that next() is disabled (will throw an exception) after seekForward() operation with query length > 1.
+ * @return list of all RODs overlapping with the next "covered" genomic position
+ */
+ public RODRecordList next() {
+ if ( ! next_is_allowed )
+ throw new ReviewedGATKException("Illegal use of iterator: Can not advance iterator with next() after seek-forward query of length > 1");
+
+ curr_position++;
+ // curr_query_end = -1;
+
+ if ( curr_position <= max_position ) {
+
+ // we still have bases covered by at least one currently loaded record;
+ // we have to purge only subset of records, on which we moved past the end
+ purgeOutOfScopeRecords();
+ } else {
+ // ooops, we are past the end of all loaded records - kill them all at once,
+ // load next record and reinitialize by fastforwarding current position to the start of next record
+ records.clear();
+ GATKFeature r = it.next(); // if hasNext() previously returned true, we are guaranteed that this call to reader.next() is safe
+ records.add( r );
+ curr_contig = r.getLocation().getContig();
+ curr_position = r.getLocation().getStart();
+ max_position = r.getLocation().getStop();
+ }
+
+ // current position is ste and at this point 'records' only keeps those annotations, on which we did not reach the end yet
+ // (we might have reloaded records completely if it was necessary); but we are not guaranteed yet that we
+ // hold ALL the records overlapping with the current position. Time to check if we just walked into the interval(s)
+ // covered by new records, so we need to load them too:
+
+ while ( it.hasNext() ) {
+ GATKFeature r = it.element();
+ if ( r == null ) {
+ it.next();
+ continue;
+ }
+
+ GenomeLoc currentContig = parser.createOverEntireContig(curr_contig);
+ GenomeLoc thatContig = r.getLocation();
+
+ if ( currentContig.isPast(thatContig) )
+ throw new UserException("LocationAwareSeekableRODIterator: contig " +r.getLocation().getContig() +
+ " occurs out of order in track " + r.getName() );
+ if ( currentContig.isBefore(thatContig) ) break; // next record is on a higher contig, we do not need it yet...
+
+ if ( r.getLocation().getStart() < curr_position )
+ throw new UserException("LocationAwareSeekableRODIterator: track "+r.getName() +
+ " is out of coordinate order on contig "+r.getLocation() + " compared to " + curr_contig + ":" + curr_position);
+
+ if ( r.getLocation().getStart() > curr_position ) break; // next record starts after the current position; we do not need it yet
+
+ r = it.next(); // we got here only if we do need next record, time to load it for real
+
+ int stop = r.getLocation().getStop();
+ if ( stop < curr_position ) throw new ReviewedGATKException("DEBUG: encountered contig that should have been loaded earlier"); // this should never happen
+ if ( stop > max_position ) max_position = stop; // max_position keeps the rightmost stop position across all loaded records
+ records.add(r);
+ }
+
+ // 'records' and current position are fully updated. Last, we need to set the location of the whole track
+ // (collection of ROD records) to the genomic site we are currently looking at, and return the list
+
+ return new RODRecordListImpl(name,records, parser.createGenomeLoc(curr_contig,curr_position));
+ }
+
+ /**
+ * Removes from the underlying collection the last element returned by the
+ * iterator (optional operation). This method can be called only once per
+ * call to <tt>next</tt>. The behavior of an iterator is unspecified if
+ * the underlying collection is modified while the iteration is in
+ * progress in any way other than by calling this method.
+ *
+ * @throws UnsupportedOperationException if the <tt>remove</tt>
+ * operation is not supported by this Iterator.
+ * @throws IllegalStateException if the <tt>next</tt> method has not
+ * yet been called, or the <tt>remove</tt> method has already
+ * been called after the last call to the <tt>next</tt>
+ * method.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("LocationAwareSeekableRODIterator does not implement remove() operation");
+ }
+
+
+ /**
+ * Returns the current "position" (not location!! ;) ) of this iterator. This method is used by the sharding
+ * system when it searches for available iterators in the pool that can be reused to resume traversal.
+ * When iterator is advanced using next(), current position
+ * is the same as 'location'. However, after a seekForward() query with extended interval, returned position
+ * will be set to the last position of the query interval, to disable (illegal) attempts to roll the iterator
+ * back and re-start traversal from current location.
+ * @return Current ending position of the iterator, or null if no position exists.
+ */
+ public GenomeLoc position() {
+ if ( curr_contig == null ) return null;
+ if ( curr_query_end > curr_position ) {
+ // do not attempt to reuse this iterator if the position we need it for lies before the end of last query performed
+ return parser.createGenomeLoc(curr_contig,curr_query_end,curr_query_end);
+ }
+ else {
+ return parser.createGenomeLoc(curr_contig,curr_position);
+ }
+ }
+
+ /**
+ * Seeks forward through the file until the specified interval is reached.
+ * The location object <code>interval</code> can be either a single point or an extended interval. All
+ * ROD records overlapping with the whole interval will be returned, or null if no such records exist.
+ *
+ * Query interval must start at or after the iterator's current location, or exception will be thrown.
+ *
+ * Query interval must end at or after the stop position of the previous query, if any, or an exception will
+ * be thrown: subsequent queries that end before the stop of previous ones are illegal.
+ *
+ * If seekForward() is performed to an extended (length > 1 i.e. start != stop) interval, next() operation becomes
+ * illegal (the iterator changes state). Only seekForward() calls are allowed thereafter, until a seekForward() call
+ * to a length-1 interval is performed, which re-enables next(). seekForward() queries with length-1 intervals can
+ * always be safely intermixed with next() (as long as ordering is respected and query intervals are at or after the
+ * current position).
+ *
+ * Note that in contrast to
+ * next() (which always advances current position of the iterator on the reference), this method scrolls
+ * forward ONLY if the specified interval is ahead of the current location of
+ * the iterator. However, if called again with the same 'interval' argument as before, seekForward will NOT
+ * advance, but will simply return the same ROD list as before.
+ *
+ *
+ * @param interval point-like genomic location to fastforward to.
+ * @return ROD object at (or overlapping with) the specified position, or null if no such ROD exists.
+ */
+ public RODRecordList seekForward(GenomeLoc interval) {
+
+ if ( interval.isBefore(parser.createOverEntireContig(curr_contig)) &&
+ !(interval.getStart() == 0 && interval.getStop() == 0 && interval.getContig().equals(curr_contig)) ) // This criteria is syntactic sugar for 'seek to right before curr_contig'
+ throw new ReviewedGATKException("Out of order query: query contig "+interval.getContig()+" is located before "+
+ "the iterator's current contig");
+ if ( interval.getContig().equals(curr_contig) ) {
+ if ( interval.getStart() < curr_position )
+ throw new ReviewedGATKException("Out of order query: query position "+interval +" is located before "+
+ "the iterator's current position "+curr_contig + ":" + curr_position);
+ if ( interval.getStop() < curr_query_end )
+ throw new ReviewedGATKException("Unsupported querying sequence: current query interval " +
+ interval+" ends before the end of previous query interval ("+curr_query_end+")");
+ }
+
+ curr_position = interval.getStart();
+ curr_query_end = interval.getStop();
+
+ next_is_allowed = ( curr_position == curr_query_end ); // we can call next() later only if interval length is 1
+
+ if ( interval.getContig().equals(curr_contig) && curr_position <= max_position ) {
+ // some of the intervals we are currently keeping do overlap with the query interval
+
+ purgeOutOfScopeRecords();
+ } else {
+ // clean up and get ready for fast-forwarding towards the requested position
+ records.clear();
+ max_position = -1;
+ curr_contig = interval.getContig();
+ }
+
+ // curr_contig and curr_position are set to where we asked to scroll to
+
+ while ( it.hasNext() ) {
+ GATKFeature r = it.next();
+ if ( r == null ) continue;
+
+ GenomeLoc currentContig = parser.createOverEntireContig(curr_contig);
+ GenomeLoc thatContig = r.getLocation();
+
+ if ( currentContig.isPast(thatContig) ) continue; // did not reach requested contig yet
+ if ( currentContig.isBefore(thatContig) ) {
+ it.pushback(r); // next record is on the higher contig, we do not need it yet...
+ break;
+ }
+
+ // we get here if we are on the requested contig:
+
+ if ( r.getLocation().getStop() < curr_position ) continue; // did not reach the requested interval yet
+
+ if ( r.getLocation().getStart() > curr_query_end ) {
+ // past the query interval
+ it.pushback(r);
+ break;
+ }
+
+ // we get here only if interval of the record r overlaps with query interval, so the record should be loaded
+ if ( r.getLocation().getStop() > max_position ) max_position = r.getLocation().getStop();
+ records.add(r);
+ }
+
+ if ( records.size() > 0 ) {
+ return new RODRecordListImpl(name,records,interval);
+ } else {
+ return null;
+ }
+
+ }
+
+ /**
+ * Removes records that end before the curr_position from the list of currently kept records. This is a
+ * convenience (private) shortcut that does not perform extensive checking. In particular, it assumes that
+ * curr_position <= max_position, as well as that we are still on the same contig.
+ */
+ private void purgeOutOfScopeRecords() {
+ Iterator<GATKFeature> i = records.iterator();
+ while ( i.hasNext() ) {
+ GATKFeature r = i.next();
+ if ( r.getLocation().getStop() < curr_position ) {
+ i.remove(); // we moved past the end of interval the record r is associated with, purge the record forever
+ }
+ }
+
+ }
+
+ @Override
+ public void close() {
+ if (this.it != null) ((CloseableIterator)this.it.getUnderlyingIterator()).close();
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/VariantContextAdaptors.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/VariantContextAdaptors.java
new file mode 100644
index 0000000..82a826c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/VariantContextAdaptors.java
@@ -0,0 +1,399 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata;
+
+import htsjdk.samtools.util.SequenceUtil;
+import htsjdk.tribble.Feature;
+import htsjdk.tribble.annotation.Strand;
+import htsjdk.tribble.dbsnp.OldDbSNPFeature;
+import htsjdk.tribble.gelitext.GeliTextFeature;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.classloader.PluginManager;
+import org.broadinstitute.gatk.utils.codecs.hapmap.RawHapMapFeature;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.variantcontext.*;
+
+import java.util.*;
+
+/**
+ * A terrible but temporary approach to converting objects to VariantContexts. If you want to add a converter,
+ * you need to create a adaptor object here and register a converter from your class to this object. When tribble arrives,
+ * we'll use a better approach.
+ *
+ * To add a new converter:
+ *
+ * create a subclass of VCAdaptor, overloading the convert operator
+ * add it to the static map from input type -> converter where the input type is the object.class you want to convert
+ *
+ * That's it
+ *
+ * @author depristo at broadinstitute.org
+ */
+public class VariantContextAdaptors {
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // Generic support routines. Do not modify
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ private static Map<Class<? extends Feature>,VCAdaptor> adaptors = new HashMap<Class<? extends Feature>,VCAdaptor>();
+
+ static {
+ PluginManager<VCAdaptor> vcAdaptorManager = new PluginManager<VCAdaptor>(VCAdaptor.class);
+ List<VCAdaptor> adaptorInstances = vcAdaptorManager.createAllTypes();
+ for(VCAdaptor adaptor: adaptorInstances)
+ adaptors.put(adaptor.getAdaptableFeatureType(),adaptor);
+ }
+
+ public static boolean canBeConvertedToVariantContext(Object variantContainingObject) {
+ return adaptors.containsKey(variantContainingObject.getClass());
+ }
+
+ /** generic superclass */
+ public interface VCAdaptor {
+ /**
+ * Gets the type of feature that this adaptor can 'adapt' into a VariantContext.
+ * @return Type of adaptable feature. Must be a Tribble feature class.
+ */
+ Class<? extends Feature> getAdaptableFeatureType();
+ VariantContext convert(String name, Object input, ReferenceContext ref);
+ }
+
+ public static VariantContext toVariantContext(String name, Object variantContainingObject, ReferenceContext ref) {
+ if ( ! adaptors.containsKey(variantContainingObject.getClass()) )
+ return null;
+ else {
+ return adaptors.get(variantContainingObject.getClass()).convert(name, variantContainingObject, ref);
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // From here below you can add adaptor classes for new rods (or other types) to convert to VC
+ //
+ // --------------------------------------------------------------------------------------------------------------
+ private static class VariantContextAdaptor implements VCAdaptor {
+ /**
+ * 'Null' adaptor; adapts variant contexts to variant contexts.
+ * @return VariantContext.
+ */
+ @Override
+ public Class<? extends Feature> getAdaptableFeatureType() { return VariantContext.class; }
+
+ // already a VC, just cast and return it
+ @Override
+ public VariantContext convert(String name, Object input, ReferenceContext ref) {
+ return (VariantContext)input;
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // dbSNP to VariantContext
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ private static class DBSnpAdaptor implements VCAdaptor {
+ private static boolean isSNP(OldDbSNPFeature feature) {
+ return feature.getVariantType().contains("single") && feature.getLocationType().contains("exact");
+ }
+
+ private static boolean isMNP(OldDbSNPFeature feature) {
+ return feature.getVariantType().contains("mnp") && feature.getLocationType().contains("range");
+ }
+
+ private static boolean isInsertion(OldDbSNPFeature feature) {
+ return feature.getVariantType().contains("insertion");
+ }
+
+ private static boolean isDeletion(OldDbSNPFeature feature) {
+ return feature.getVariantType().contains("deletion");
+ }
+
+ private static boolean isIndel(OldDbSNPFeature feature) {
+ return isInsertion(feature) || isDeletion(feature) || isComplexIndel(feature);
+ }
+
+ public static boolean isComplexIndel(OldDbSNPFeature feature) {
+ return feature.getVariantType().contains("in-del");
+ }
+
+ /**
+ * gets the alternate alleles. This method should return all the alleles present at the location,
+ * NOT including the reference base. This is returned as a string list with no guarantee ordering
+ * of alleles (i.e. the first alternate allele is not always going to be the allele with the greatest
+ * frequency).
+ *
+ * @return an alternate allele list
+ */
+ public static List<String> getAlternateAlleleList(OldDbSNPFeature feature) {
+ List<String> ret = new ArrayList<String>();
+ for (String allele : getAlleleList(feature))
+ if (!allele.equals(String.valueOf(feature.getNCBIRefBase()))) ret.add(allele);
+ return ret;
+ }
+
+ /**
+ * gets the alleles. This method should return all the alleles present at the location,
+ * including the reference base. The first allele should always be the reference allele, followed
+ * by an unordered list of alternate alleles.
+ *
+ * @return an alternate allele list
+ */
+ public static List<String> getAlleleList(OldDbSNPFeature feature) {
+ List<String> alleleList = new ArrayList<String>();
+ // add ref first
+ if ( feature.getStrand() == Strand.POSITIVE )
+ alleleList = Arrays.asList(feature.getObserved());
+ else
+ for (String str : feature.getObserved())
+ alleleList.add(SequenceUtil.reverseComplement(str));
+ if ( alleleList.size() > 0 && alleleList.contains(feature.getNCBIRefBase())
+ && !alleleList.get(0).equals(feature.getNCBIRefBase()) )
+ Collections.swap(alleleList, alleleList.indexOf(feature.getNCBIRefBase()), 0);
+
+ return alleleList;
+ }
+
+ /**
+ * Converts non-VCF formatted dbSNP records to VariantContext.
+ * @return OldDbSNPFeature.
+ */
+ @Override
+ public Class<? extends Feature> getAdaptableFeatureType() { return OldDbSNPFeature.class; }
+
+ @Override
+ public VariantContext convert(String name, Object input, ReferenceContext ref) {
+ OldDbSNPFeature dbsnp = (OldDbSNPFeature)input;
+
+ int index = dbsnp.getStart() - ref.getWindow().getStart() - 1;
+ if ( index < 0 )
+ return null; // we weren't given enough reference context to create the VariantContext
+
+ final byte refBaseForIndel = ref.getBases()[index];
+ final boolean refBaseIsDash = dbsnp.getNCBIRefBase().equals("-");
+
+ boolean addPaddingBase;
+ if ( isSNP(dbsnp) || isMNP(dbsnp) )
+ addPaddingBase = false;
+ else if ( isIndel(dbsnp) || dbsnp.getVariantType().contains("mixed") )
+ addPaddingBase = refBaseIsDash || GATKVariantContextUtils.requiresPaddingBase(stripNullDashes(getAlleleList(dbsnp)));
+ else
+ return null; // can't handle anything else
+
+ Allele refAllele;
+ if ( refBaseIsDash )
+ refAllele = Allele.create(refBaseForIndel, true);
+ else if ( ! Allele.acceptableAlleleBases(dbsnp.getNCBIRefBase()) )
+ return null;
+ else
+ refAllele = Allele.create((addPaddingBase ? (char)refBaseForIndel : "") + dbsnp.getNCBIRefBase(), true);
+
+ final List<Allele> alleles = new ArrayList<Allele>();
+ alleles.add(refAllele);
+
+ // add all of the alt alleles
+ for ( String alt : getAlternateAlleleList(dbsnp) ) {
+ if ( Allele.wouldBeNullAllele(alt.getBytes()))
+ alt = "";
+ else if ( ! Allele.acceptableAlleleBases(alt) )
+ return null;
+
+ alleles.add(Allele.create((addPaddingBase ? (char)refBaseForIndel : "") + alt, false));
+ }
+
+ final VariantContextBuilder builder = new VariantContextBuilder();
+ builder.source(name).id(dbsnp.getRsID());
+ builder.loc(dbsnp.getChr(), dbsnp.getStart() - (addPaddingBase ? 1 : 0), dbsnp.getEnd() - (addPaddingBase && refAllele.length() == 1 ? 1 : 0));
+ builder.alleles(alleles);
+ return builder.make();
+ }
+
+ private static List<String> stripNullDashes(final List<String> alleles) {
+ final List<String> newAlleles = new ArrayList<String>(alleles.size());
+ for ( final String allele : alleles ) {
+ if ( allele.equals("-") )
+ newAlleles.add("");
+ else
+ newAlleles.add(allele);
+ }
+ return newAlleles;
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // GELI to VariantContext
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ private static class GeliTextAdaptor implements VCAdaptor {
+ /**
+ * Converts Geli text records to VariantContext.
+ * @return GeliTextFeature.
+ */
+ @Override
+ public Class<? extends Feature> getAdaptableFeatureType() { return GeliTextFeature.class; }
+
+ /**
+ * convert to a Variant Context, given:
+ * @param name the name of the ROD
+ * @param input the Rod object, in this case a RodGeliText
+ * @param ref the reference context
+ * @return a VariantContext object
+ */
+ @Override
+ public VariantContext convert(String name, Object input, ReferenceContext ref) {
+ GeliTextFeature geli = (GeliTextFeature)input;
+ if ( ! Allele.acceptableAlleleBases(String.valueOf(geli.getRefBase())) )
+ return null;
+ Allele refAllele = Allele.create(String.valueOf(geli.getRefBase()), true);
+
+ // make sure we can convert it
+ if ( geli.getGenotype().isHet() || !geli.getGenotype().containsBase(geli.getRefBase())) {
+ // add the reference allele
+ List<Allele> alleles = new ArrayList<Allele>();
+ List<Allele> genotypeAlleles = new ArrayList<Allele>();
+ // add all of the alt alleles
+ for ( char alt : geli.getGenotype().toString().toCharArray() ) {
+ if ( ! Allele.acceptableAlleleBases(String.valueOf(alt)) ) {
+ return null;
+ }
+ Allele allele = Allele.create(String.valueOf(alt), false);
+ if (!alleles.contains(allele) && !refAllele.basesMatch(allele.getBases())) alleles.add(allele);
+
+ // add the allele, first checking if it's reference or not
+ if (!refAllele.basesMatch(allele.getBases())) genotypeAlleles.add(allele);
+ else genotypeAlleles.add(refAllele);
+ }
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ Collection<Genotype> genotypes = new ArrayList<Genotype>();
+ Genotype call = GenotypeBuilder.create(name, genotypeAlleles);
+
+ // add the call to the genotype list, and then use this list to create a VariantContext
+ genotypes.add(call);
+ alleles.add(refAllele);
+ GenomeLoc loc = ref.getGenomeLocParser().createGenomeLoc(geli.getChr(),geli.getStart());
+ return new VariantContextBuilder(name, loc.getContig(), loc.getStart(), loc.getStop(), alleles).genotypes(genotypes).log10PError(-1 * geli.getLODBestToReference()).attributes(attributes).make();
+ } else
+ return null; // can't handle anything else
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // HapMap to VariantContext
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ private static class HapMapAdaptor implements VCAdaptor {
+ /**
+ * Converts HapMap records to VariantContext.
+ * @return HapMapFeature.
+ */
+ @Override
+ public Class<? extends Feature> getAdaptableFeatureType() { return RawHapMapFeature.class; }
+
+ /**
+ * convert to a Variant Context, given:
+ * @param name the name of the ROD
+ * @param input the Rod object, in this case a RodGeliText
+ * @param ref the reference context
+ * @return a VariantContext object
+ */
+ @Override
+ public VariantContext convert(String name, Object input, ReferenceContext ref) {
+ if ( ref == null )
+ throw new UnsupportedOperationException("Conversion from HapMap to VariantContext requires a reference context");
+
+ RawHapMapFeature hapmap = (RawHapMapFeature)input;
+
+ int index = hapmap.getStart() - ref.getWindow().getStart();
+ if ( index < 0 )
+ return null; // we weren't given enough reference context to create the VariantContext
+
+ HashSet<Allele> alleles = new HashSet<Allele>();
+ Allele refSNPAllele = Allele.create(ref.getBase(), true);
+ int deletionLength = -1;
+
+ Map<String, Allele> alleleMap = hapmap.getActualAlleles();
+ // use the actual alleles, if available
+ if ( alleleMap != null ) {
+ alleles.addAll(alleleMap.values());
+ Allele deletionAllele = alleleMap.get(RawHapMapFeature.INSERTION); // yes, use insertion here (since we want the reference bases)
+ if ( deletionAllele != null && deletionAllele.isReference() )
+ deletionLength = deletionAllele.length();
+ } else {
+ // add the reference allele for SNPs
+ alleles.add(refSNPAllele);
+ }
+
+ // make a mapping from sample to genotype
+ String[] samples = hapmap.getSampleIDs();
+ String[] genotypeStrings = hapmap.getGenotypes();
+
+ GenotypesContext genotypes = GenotypesContext.create(samples.length);
+ for ( int i = 0; i < samples.length; i++ ) {
+ // ignore bad genotypes
+ if ( genotypeStrings[i].contains("N") )
+ continue;
+
+ String a1 = genotypeStrings[i].substring(0,1);
+ String a2 = genotypeStrings[i].substring(1);
+ ArrayList<Allele> myAlleles = new ArrayList<Allele>(2);
+
+ // use the mapping to actual alleles, if available
+ if ( alleleMap != null ) {
+ myAlleles.add(alleleMap.get(a1));
+ myAlleles.add(alleleMap.get(a2));
+ } else {
+ // ignore indels (which we can't handle without knowing the alleles)
+ if ( genotypeStrings[i].contains("I") || genotypeStrings[i].contains("D") )
+ continue;
+
+ Allele allele1 = Allele.create(a1, refSNPAllele.basesMatch(a1));
+ Allele allele2 = Allele.create(a2, refSNPAllele.basesMatch(a2));
+
+ myAlleles.add(allele1);
+ myAlleles.add(allele2);
+ alleles.add(allele1);
+ alleles.add(allele2);
+ }
+
+ Genotype g = GenotypeBuilder.create(samples[i], myAlleles);
+ genotypes.add(g);
+ }
+
+ long end = hapmap.getEnd();
+ if ( deletionLength > 0 )
+ end += (deletionLength - 1);
+ VariantContext vc = new VariantContextBuilder(name, hapmap.getChr(), hapmap.getStart(), end, alleles).id(hapmap.getName()).genotypes(genotypes).make();
+ return vc;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/package-info.java
new file mode 100644
index 0000000..e9e9714
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/FeatureManager.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/FeatureManager.java
new file mode 100644
index 0000000..d466f3f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/FeatureManager.java
@@ -0,0 +1,280 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.tracks;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.tribble.Feature;
+import htsjdk.tribble.FeatureCodec;
+import htsjdk.tribble.NameAwareCodec;
+import org.broadinstitute.gatk.engine.refdata.ReferenceDependentFeatureCodec;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.classloader.PluginManager;
+import htsjdk.variant.vcf.AbstractVCFCodec;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.help.GATKDocUtils;
+
+import java.io.File;
+import java.util.*;
+
+
+/**
+ * Class for managing Tribble Feature readers available to the GATK. The features
+ * are dynamically determined via a PluginManager. This class provides convenient
+ * getter methods for obtaining FeatureDescriptor objects that collect all of the
+ * useful information about the Tribble Codec, Feature, and name in one place.
+ *
+ * @author depristo
+ */
+public class FeatureManager {
+ public static class FeatureDescriptor implements Comparable<FeatureDescriptor> {
+ final String name;
+ final FeatureCodec codec;
+
+ public FeatureDescriptor(final String name, final FeatureCodec codec) {
+ this.name = name;
+ this.codec = codec;
+ }
+
+ public String getName() {
+ return name;
+ }
+ public String getSimpleFeatureName() { return getFeatureClass().getSimpleName(); }
+ public FeatureCodec getCodec() {
+ return codec;
+ }
+ public Class getCodecClass() { return codec.getClass(); }
+ public Class getFeatureClass() { return codec.getFeatureType(); }
+
+ @Override
+ public String toString() {
+ return String.format("FeatureDescriptor name=%s codec=%s feature=%s",
+ getName(), getCodecClass().getName(), getFeatureClass().getName());
+ }
+
+ @Override
+ public int compareTo(FeatureDescriptor o) {
+ return getName().compareTo(o.getName());
+ }
+ }
+
+ private final PluginManager<FeatureCodec> pluginManager;
+ private final Collection<FeatureDescriptor> featureDescriptors = new TreeSet<FeatureDescriptor>();
+ private final boolean lenientVCFProcessing;
+
+ /**
+ * Construct a FeatureManager without a master VCF header
+ */
+ public FeatureManager() {
+ this(false);
+ }
+
+ public FeatureManager(final boolean lenientVCFProcessing) {
+ this.lenientVCFProcessing = lenientVCFProcessing;
+ pluginManager = new PluginManager<FeatureCodec>(FeatureCodec.class, "Codecs", "Codec");
+
+ for (final String rawName: pluginManager.getPluginsByName().keySet()) {
+ FeatureCodec codec = pluginManager.createByName(rawName);
+ String name = rawName.toUpperCase();
+ FeatureDescriptor featureDescriptor = new FeatureDescriptor(name, codec);
+ featureDescriptors.add(featureDescriptor);
+ }
+ }
+
+ /**
+ * Return the FeatureDescriptor whose getCodecClass().equals(codecClass).
+ *
+ * @param codecClass
+ * @return A FeatureDescriptor or null if none is found
+ */
+ @Requires("codecClass != null")
+ public FeatureDescriptor getByCodec(Class codecClass) {
+ for ( FeatureDescriptor descriptor : featureDescriptors )
+ if ( descriptor.getCodecClass().equals(codecClass) )
+ return descriptor;
+ return null;
+ }
+
+ /**
+ * Returns a collection of FeatureDescriptors that emit records of type featureClass
+ *
+ * @param featureClass
+ * @return A FeatureDescriptor or null if none is found
+ */
+ @Requires("featureClass != null")
+ public <T extends Feature> Collection<FeatureDescriptor> getByFeature(Class<T> featureClass) {
+ Set<FeatureDescriptor> consistentDescriptors = new TreeSet<FeatureDescriptor>();
+
+ if (featureClass == null)
+ throw new IllegalArgumentException("trackRecordType value is null, please pass in an actual class object");
+
+ for ( FeatureDescriptor descriptor : featureDescriptors ) {
+ if ( featureClass.isAssignableFrom(descriptor.getFeatureClass()))
+ consistentDescriptors.add(descriptor);
+ }
+ return consistentDescriptors;
+ }
+
+ /**
+ * Return the FeatureDescriptor with getID().equals(name)
+ *
+ * @param name
+ * @return A FeatureDescriptor or null if none is found
+ */
+ @Requires("name != null")
+ public FeatureDescriptor getByName(String name) {
+ for ( FeatureDescriptor descriptor : featureDescriptors )
+ if ( descriptor.getName().equalsIgnoreCase(name) )
+ return descriptor;
+ return null;
+ }
+
+ /**
+ * Returns the FeatureDescriptor that can read the contexts of File file, is one can be determined
+ *
+ * @param file
+ * @return A FeatureDescriptor or null if none is found
+ */
+ @Requires({"file != null", "file.isFile()", "file.canRead()"})
+ public FeatureDescriptor getByFiletype(File file) {
+ List<FeatureDescriptor> canParse = new ArrayList<FeatureDescriptor>();
+ for ( FeatureDescriptor descriptor : featureDescriptors )
+ if ( descriptor.getCodec().canDecode(file.getPath()) ) {
+ canParse.add(descriptor);
+ }
+
+ if ( canParse.size() == 0 )
+ return null;
+ else if ( canParse.size() > 1 )
+ throw new ReviewedGATKException("BUG: multiple feature descriptors can read file " + file + ": " + canParse);
+ else
+ return canParse.get(0);
+ }
+
+ /**
+ * Returns the FeatureDescriptor associated with the type described by triplet, or null if none is found
+ * @param triplet
+ * @return
+ */
+ @Requires("triplet != null")
+ public FeatureDescriptor getByTriplet(RMDTriplet triplet) {
+ return getByName(triplet.getType());
+ }
+
+ /**
+ * @return all of the FeatureDescriptors available to the GATK. Never null
+ */
+ @Ensures("result != null")
+ public Collection<FeatureDescriptor> getFeatureDescriptors() {
+ return Collections.unmodifiableCollection(featureDescriptors);
+ }
+
+
+ /**
+ * Returns a list of the available tribble track names (vcf,dbsnp,etc) that we can load
+ * @return
+ */
+ @Ensures("result != null")
+ public String userFriendlyListOfAvailableFeatures() {
+ return userFriendlyListOfAvailableFeatures(Feature.class);
+ }
+
+ /**
+ * Returns a list of the available tribble track names (vcf,dbsnp,etc) that we can load
+ * restricted to only Codecs producting Features consistent with the requiredFeatureType
+ * @return
+ */
+ @Ensures("result != null")
+ public String userFriendlyListOfAvailableFeatures(Class<? extends Feature> requiredFeatureType) {
+ final String nameHeader="Name", featureHeader = "FeatureType", docHeader="Documentation";
+
+ int maxNameLen = nameHeader.length(), maxFeatureNameLen = featureHeader.length();
+ for ( final FeatureDescriptor descriptor : featureDescriptors ) {
+ if ( requiredFeatureType.isAssignableFrom(descriptor.getFeatureClass()) ) {
+ maxNameLen = Math.max(maxNameLen, descriptor.getName().length());
+ maxFeatureNameLen = Math.max(maxFeatureNameLen, descriptor.getSimpleFeatureName().length());
+ }
+ }
+
+ StringBuilder docs = new StringBuilder();
+ String format = "%" + maxNameLen + "s %" + maxFeatureNameLen + "s %s%n";
+ docs.append(String.format(format, nameHeader, featureHeader, docHeader));
+ for ( final FeatureDescriptor descriptor : featureDescriptors ) {
+ if ( requiredFeatureType.isAssignableFrom(descriptor.getFeatureClass()) ) {
+ final String DocURL = GATKDocUtils.helpLinksToGATKDocs(descriptor.getCodecClass());
+ final String oneDoc;
+ if ( DocURL.contains("_sting_") ) {
+ oneDoc = String.format(format,
+ descriptor.getName(),
+ descriptor.getSimpleFeatureName(),
+ DocURL);
+ } else {
+ oneDoc = String.format(format,
+ descriptor.getName(),
+ descriptor.getSimpleFeatureName(),
+ "(this is an external codec and is not documented within GATK)");
+ }
+
+ docs.append(oneDoc);
+ }
+ }
+
+ return docs.toString();
+ }
+
+ /**
+ * Create a new FeatureCodec of the type described in descriptor, assigning it the
+ * name (if possible) and providing it the genomeLocParser (where necessary)
+ *
+ * @param descriptor FeatureDescriptor of the Tribble FeatureCodec we want to create
+ * @param name the name to assign this codec
+ * @param genomeLocParser GenomeLocParser for ReferenceDependentFeatureCodecs
+ * @param remappedSampleName replacement sample name for single-sample vcfs, or null if we're not performing
+ * sample name remapping
+ * @return the feature codec itself
+ */
+ @Requires({"descriptor != null", "name != null", "genomeLocParser != null"})
+ @Ensures("result != null")
+ public FeatureCodec createCodec(final FeatureDescriptor descriptor, final String name, final GenomeLocParser genomeLocParser,
+ final String remappedSampleName) {
+ FeatureCodec codex = pluginManager.createByType(descriptor.getCodecClass());
+ if ( codex instanceof NameAwareCodec )
+ ((NameAwareCodec)codex).setName(name);
+ if ( codex instanceof ReferenceDependentFeatureCodec )
+ ((ReferenceDependentFeatureCodec)codex).setGenomeLocParser(genomeLocParser);
+ if ( codex instanceof AbstractVCFCodec ) {
+ if ( lenientVCFProcessing ) {
+ ((AbstractVCFCodec)codex).disableOnTheFlyModifications();
+ }
+ if ( remappedSampleName != null ) {
+ ((AbstractVCFCodec)codex).setRemappedSampleName(remappedSampleName);
+ }
+ }
+
+ return codex;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/IndexDictionaryUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/IndexDictionaryUtils.java
new file mode 100644
index 0000000..5c18d3a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/IndexDictionaryUtils.java
@@ -0,0 +1,114 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.tracks;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.index.Index;
+import htsjdk.tribble.index.MutableIndex;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.utils.SequenceDictionaryUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Utilities for working with Sequence Dictionaries embedded in tribble indices
+ *
+ * @author Your Name
+ * @since Date created
+ */
+public class IndexDictionaryUtils {
+ private final static Logger logger = Logger.getLogger(IndexDictionaryUtils.class);
+
+ // a constant we use for marking sequence dictionary entries in the Tribble index property list
+ public static final String SequenceDictionaryPropertyPredicate = "DICT:";
+
+ /**
+ * get the sequence dictionary from the track, if available. If not, make it from the contig list that is always in the index
+ * @param index the index file to use
+ * @return a SAMSequenceDictionary if available, null if unavailable
+ */
+ public static SAMSequenceDictionary getSequenceDictionaryFromProperties(Index index) {
+ SAMSequenceDictionary dict = new SAMSequenceDictionary();
+ for (Map.Entry<String,String> entry : index.getProperties().entrySet()) {
+ if (entry.getKey().startsWith(SequenceDictionaryPropertyPredicate))
+ dict.addSequence(new SAMSequenceRecord(entry.getKey().substring(SequenceDictionaryPropertyPredicate.length() , entry.getKey().length()),
+ Integer.valueOf(entry.getValue())));
+ }
+ return dict;
+ }
+
+ /**
+ * create the sequence dictionary with the contig list; a backup approach
+ * @param index the index file to use
+ * @param dict the sequence dictionary to add contigs to
+ * @return the filled-in sequence dictionary
+ */
+ static SAMSequenceDictionary createSequenceDictionaryFromContigList(final Index index, final SAMSequenceDictionary dict) {
+ final List<String> seqNames = index.getSequenceNames();
+ if (seqNames == null) {
+ return dict;
+ }
+ for (final String name : seqNames) {
+ SAMSequenceRecord seq = new SAMSequenceRecord(name, 0);
+ dict.addSequence(seq);
+ }
+ return dict;
+ }
+
+ /**
+ * Sets the sequence dictionary of the given index. THE INDEX MUST BE MUTABLE (i.e. not Tabix).
+ *
+ * @param index the (mutable) index file to use
+ * @param dict the dictionary to use
+ */
+ public static void setIndexSequenceDictionary(Index index, SAMSequenceDictionary dict) {
+ for ( SAMSequenceRecord seq : dict.getSequences() ) {
+ final String contig = IndexDictionaryUtils.SequenceDictionaryPropertyPredicate + seq.getSequenceName();
+ final String length = String.valueOf(seq.getSequenceLength());
+ ((MutableIndex)index).addProperty(contig, length);
+ }
+ }
+
+ public static void validateTrackSequenceDictionary(final String trackName,
+ final SAMSequenceDictionary trackDict,
+ final SAMSequenceDictionary referenceDict,
+ final ValidationExclusion.TYPE validationExclusionType ) {
+ // if the sequence dictionary is empty (as well as null which means it doesn't have a dictionary), skip validation
+ if (trackDict == null || trackDict.size() == 0)
+ logger.warn("Track " + trackName + " doesn't have a sequence dictionary built in, skipping dictionary validation");
+ else {
+ Set<String> trackSequences = new TreeSet<String>();
+ for (SAMSequenceRecord dictionaryEntry : trackDict.getSequences())
+ trackSequences.add(dictionaryEntry.getSequenceName());
+ SequenceDictionaryUtils.validateDictionaries(logger, validationExclusionType, trackName, trackDict, "reference", referenceDict, false, null);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/RMDTrack.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/RMDTrack.java
new file mode 100644
index 0000000..51cb8f4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/RMDTrack.java
@@ -0,0 +1,147 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.tracks;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.util.CloseableIterator;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.AbstractFeatureReader;
+import htsjdk.tribble.CloseableTribbleIterator;
+import htsjdk.tribble.Feature;
+import htsjdk.tribble.FeatureCodec;
+import org.broadinstitute.gatk.engine.refdata.utils.FeatureToGATKFeatureIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.io.IOException;
+
+
+/**
+ * @author aaron
+ * <p/>
+ * Class RMDTrack
+ * <p/>
+ * the basics of what a reference metadata track must contain.
+ */
+public class RMDTrack {
+ private final static Logger logger = Logger.getLogger(RMDTrackBuilder.class);
+
+ // the basics of a track:
+ private final Class type; // our type
+ private final String name; // the name
+ private final File file; // the associated file we create the reader from
+
+ // our feature reader - allows queries
+ private AbstractFeatureReader reader;
+
+ // our sequence dictionary, which can be null
+ private final SAMSequenceDictionary dictionary;
+
+ /**
+ * Parser to use when creating/parsing GenomeLocs.
+ */
+ private final GenomeLocParser genomeLocParser;
+
+ // our codec type
+ private final FeatureCodec codec;
+
+ public Class getType() {
+ return type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * Create a track
+ *
+ * @param type the type of track, used for track lookup
+ * @param name the name of this specific track
+ * @param file the associated file, for reference or recreating the reader
+ * @param reader the feature reader to use as the underlying data source
+ * @param dict the sam sequence dictionary
+ * @param codec the feature codec we use to decode this type
+ */
+ public RMDTrack(Class type, String name, File file, AbstractFeatureReader reader, SAMSequenceDictionary dict, GenomeLocParser genomeLocParser, FeatureCodec codec) {
+ this.type = type;
+ this.name = name;
+ this.file = file;
+ this.reader = reader;
+ this.dictionary = dict;
+ this.genomeLocParser = genomeLocParser;
+ this.codec = codec;
+ }
+
+ /**
+ * @return how to get an iterator of the underlying data. This is all a track has to support,
+ * but other more advanced tracks support the query interface
+ */
+ public CloseableIterator<GATKFeature> getIterator() {
+ try {
+ return new FeatureToGATKFeatureIterator(genomeLocParser,reader.iterator(),this.getName());
+ } catch (IOException e) {
+ throw new UserException.CouldNotReadInputFile(getFile(), "Unable to read from file", e);
+ }
+ }
+
+ public CloseableIterator<GATKFeature> query(GenomeLoc interval) throws IOException {
+ CloseableTribbleIterator<Feature> iter = reader.query(interval.getContig(),interval.getStart(),interval.getStop());
+ return new FeatureToGATKFeatureIterator(genomeLocParser, iter, this.getName());
+ }
+
+ public void close() {
+ try {
+ reader.close();
+ } catch (IOException e) {
+ throw new UserException.MalformedFile("Unable to close reader " + reader.toString(),e);
+ }
+ reader = null;
+ }
+
+ /**
+ * get the sequence dictionary from the track, if available
+ * @return a SAMSequenceDictionary if available, null if unavailable
+ */
+ public SAMSequenceDictionary getSequenceDictionary() {
+ return dictionary;
+ }
+
+ public Object getHeader() {
+ return reader.getHeader();
+ }
+
+ public FeatureCodec getCodec() {
+ return codec;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/RMDTrackBuilder.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/RMDTrackBuilder.java
new file mode 100644
index 0000000..dc9e967
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/tracks/RMDTrackBuilder.java
@@ -0,0 +1,430 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.tracks;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.AbstractFeatureReader;
+import htsjdk.tribble.FeatureCodec;
+import htsjdk.tribble.Tribble;
+import htsjdk.tribble.TribbleException;
+import htsjdk.tribble.index.Index;
+import htsjdk.tribble.index.IndexFactory;
+import htsjdk.tribble.util.LittleEndianOutputStream;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.io.stubs.VCFWriterArgumentTypeDescriptor;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet.RMDStorageType;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.file.FSLockWithShared;
+import org.broadinstitute.gatk.utils.instrumentation.Sizeof;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Map;
+
+
+/**
+ *
+ * @author aaron
+ * `
+ * Class RMDTrackBuilder
+ *
+ * This class keeps track of the available codecs, and knows how to put together a track of
+ * that gets iterators from the FeatureReader using Tribble.
+ *
+ */
+public class RMDTrackBuilder { // extends PluginManager<FeatureCodec> {
+ /**
+ * our log, which we use to capture anything from this class
+ */
+ private final static Logger logger = Logger.getLogger(RMDTrackBuilder.class);
+
+ // private sequence dictionary we use to set our tracks with
+ private final SAMSequenceDictionary dict;
+
+ /**
+ * Private genome loc parser to use when building out new locs.
+ */
+ private final GenomeLocParser genomeLocParser;
+
+ /**
+ * Validation exclusions, for validating the sequence dictionary.
+ */
+ private ValidationExclusion.TYPE validationExclusionType;
+
+ private final FeatureManager featureManager;
+
+ // If true, do not attempt to create index files if they don't exist or are outdated, and don't
+ // make any file lock acquisition calls on the index files.
+ private final boolean disableAutoIndexCreation;
+
+ // Map of file name -> new sample name used when performing on-the-fly sample renaming
+ private final Map<String, String> sampleRenameMap;
+
+ /**
+ * Construct an RMDTrackerBuilder, allowing the user to define tracks to build after-the-fact. This is generally
+ * used when walkers want to directly manage the ROD system for whatever reason. Before using this constructor,
+ * please talk through your approach with the SE team.
+ * @param dict Sequence dictionary to use.
+ * @param genomeLocParser Location parser to use.
+ * @param validationExclusionType Types of validations to exclude, for sequence dictionary verification.
+ * @param disableAutoIndexCreation Do not auto-create index files, and do not use file locking when accessing index files.
+ * UNSAFE in general (because it causes us not to lock index files before reading them) --
+ * suitable only for test suite use.
+ * @param sampleRenameMap Map of file name -> new sample name used when performing on-the-fly sample renaming
+ */
+ public RMDTrackBuilder(final SAMSequenceDictionary dict,
+ final GenomeLocParser genomeLocParser,
+ final ValidationExclusion.TYPE validationExclusionType,
+ final boolean disableAutoIndexCreation,
+ final Map<String, String> sampleRenameMap) {
+ this.dict = dict;
+ this.validationExclusionType = validationExclusionType;
+ this.genomeLocParser = genomeLocParser;
+ this.featureManager = new FeatureManager(GenomeAnalysisEngine.lenientVCFProcessing(validationExclusionType));
+ this.disableAutoIndexCreation = disableAutoIndexCreation;
+ this.sampleRenameMap = sampleRenameMap;
+ }
+
+ /**
+ * Return the feature manager this RMDTrackBuilder is using the create tribble tracks
+ *
+ * @return
+ */
+ public FeatureManager getFeatureManager() {
+ return featureManager;
+ }
+
+ /**
+ * create a RMDTrack of the specified type
+ *
+ * @param fileDescriptor a description of the type of track to build.
+ *
+ * @return an instance of the track
+ */
+ public RMDTrack createInstanceOfTrack(RMDTriplet fileDescriptor) {
+ String name = fileDescriptor.getName();
+ File inputFile = new File(fileDescriptor.getFile());
+
+ FeatureManager.FeatureDescriptor descriptor = getFeatureManager().getByTriplet(fileDescriptor);
+ if (descriptor == null)
+ throw new UserException.BadArgumentValue("-B",fileDescriptor.getType());
+
+ // return a feature reader track
+ Pair<AbstractFeatureReader, SAMSequenceDictionary> pair;
+ if (VCFWriterArgumentTypeDescriptor.isCompressed(inputFile.toString()))
+ pair = createTabixIndexedFeatureSource(descriptor, name, inputFile);
+ else
+ pair = getFeatureSource(descriptor, name, inputFile, fileDescriptor.getStorageType());
+ if (pair == null) throw new UserException.CouldNotReadInputFile(inputFile, "Unable to make the feature reader for input file");
+ return new RMDTrack(descriptor.getCodecClass(), name, inputFile, pair.first, pair.second, genomeLocParser, createCodec(descriptor, name, inputFile));
+ }
+
+ /**
+ * Convenience method simplifying track creation. Assume unnamed track based on a file rather than a stream.
+ * @param codecClass Type of Tribble codec class to build.
+ * @param inputFile Input file type to use.
+ * @return An RMDTrack, suitable for accessing reference metadata.
+ */
+ public RMDTrack createInstanceOfTrack(Class codecClass, File inputFile) {
+ final FeatureManager.FeatureDescriptor descriptor = getFeatureManager().getByCodec(codecClass);
+
+ if (descriptor == null)
+ throw new ReviewedGATKException("Unable to find type name for codec class " + codecClass.getName());
+
+ return createInstanceOfTrack(new RMDTriplet("anonymous",descriptor.getName(),inputFile.getAbsolutePath(),RMDStorageType.FILE,new Tags()));
+ }
+
+ /**
+ * create a feature reader, without assuming there exists an index. This code assumes the feature
+ * reader of the appropriate type will figure out what the right index type is, and determine if it
+ * exists.
+ *
+ * @param descriptor the FeatureDescriptor describing the FeatureCodec we want to create
+ * @param name the name of the track
+ * @param inputFile the file to load
+ * @return a feature reader implementation
+ */
+ private Pair<AbstractFeatureReader, SAMSequenceDictionary> createTabixIndexedFeatureSource(FeatureManager.FeatureDescriptor descriptor, String name, File inputFile) {
+ // we might not know the index type, try loading with the default reader constructor
+ logger.debug("Attempting to load " + inputFile + " as a tabix indexed file without validating it");
+ try {
+ // getFeatureReader will detect that it's Tabix
+ return new Pair<>(AbstractFeatureReader.getFeatureReader(inputFile.getAbsolutePath(), createCodec(descriptor, name, inputFile)), null);
+ } catch (TribbleException e) {
+ throw new UserException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * add a name to the codec, if it takes one
+ * @param descriptor the class to create a codec for
+ * @param name the name to assign this codec
+ * @param inputFile input file that we will be decoding
+ * @return the feature codec itself
+ */
+ private FeatureCodec createCodec(final FeatureManager.FeatureDescriptor descriptor, final String name, final File inputFile) {
+ // The remappedSampleName will be null if either no on-the-fly sample renaming was requested,
+ // or the user's sample rename map file didn't contain an entry for this file:
+ final String remappedSampleName = sampleRenameMap != null ? sampleRenameMap.get(inputFile.getAbsolutePath()) : null;
+
+ return featureManager.createCodec(descriptor, name, genomeLocParser, remappedSampleName);
+ }
+
+ /**
+ * create a feature source object given:
+ * @param descriptor the FeatureDescriptor describing the FeatureCodec we want to create
+ * @param name the name of the codec
+ * @param inputFile the tribble file to parse
+ * @param storageType How the RMD is streamed into the input file.
+ * @return the input file as a FeatureReader
+ */
+ private Pair<AbstractFeatureReader, SAMSequenceDictionary> getFeatureSource(FeatureManager.FeatureDescriptor descriptor,
+ String name,
+ File inputFile,
+ RMDStorageType storageType) {
+ // Feature source and sequence dictionary to use as the ultimate reference
+ AbstractFeatureReader featureSource = null;
+ SAMSequenceDictionary sequenceDictionary = null;
+
+ // Detect whether or not this source should be indexed.
+ boolean canBeIndexed = (storageType == RMDStorageType.FILE);
+
+ if(canBeIndexed) {
+ try {
+ Index index = loadIndex(inputFile, createCodec(descriptor, name, inputFile));
+ try { logger.info(String.format(" Index for %s has size in bytes %d", inputFile, Sizeof.getObjectGraphSize(index))); }
+ catch (ReviewedGATKException e) { }
+
+ sequenceDictionary = IndexDictionaryUtils.getSequenceDictionaryFromProperties(index);
+
+ // if we don't have a dictionary in the Tribble file, and we've set a dictionary for this builder, set it in the file if they match
+ if (sequenceDictionary.size() == 0 && dict != null) {
+ validateAndUpdateIndexSequenceDictionary(inputFile, index, dict);
+
+ if ( ! disableAutoIndexCreation ) {
+ File indexFile = Tribble.indexFile(inputFile);
+ try { // re-write the index
+ writeIndexToDisk(index,indexFile,new FSLockWithShared(indexFile));
+ } catch (IOException e) {
+ logger.warn("Unable to update index with the sequence dictionary for file " + indexFile + "; this will not affect your run of the GATK");
+ }
+ }
+
+ sequenceDictionary = IndexDictionaryUtils.getSequenceDictionaryFromProperties(index);
+ }
+
+ featureSource = AbstractFeatureReader.getFeatureReader(inputFile.getAbsolutePath(), createCodec(descriptor, name, inputFile), index);
+ }
+ catch (TribbleException e) {
+ throw new UserException(e.getMessage());
+ }
+ catch (IOException e) {
+ throw new UserException("I/O error loading or writing tribble index file for " + inputFile.getAbsolutePath(), e);
+ }
+ }
+ else {
+ featureSource = AbstractFeatureReader.getFeatureReader(inputFile.getAbsolutePath(), createCodec(descriptor, name, inputFile), false);
+ }
+
+ return new Pair<AbstractFeatureReader,SAMSequenceDictionary>(featureSource,sequenceDictionary);
+ }
+
+ /**
+ * create an index for the input file
+ * @param inputFile the input file
+ * @param codec the codec to use
+ * @return a linear index for the specified type
+ * @throws IOException if we cannot write the index file
+ */
+ public synchronized Index loadIndex( final File inputFile, final FeatureCodec codec) throws IOException {
+ final File indexFile = Tribble.indexFile(inputFile);
+ final FSLockWithShared lock = new FSLockWithShared(indexFile);
+ Index idx = null;
+
+ // If the index file exists and is readable, attempt to load it from disk. We'll get null back
+ // if a problem was discovered with the index file when it was inspected, and we'll get an
+ // in-memory index back in the case where the index file could not be locked.
+ if (indexFile.canRead()) {
+ idx = disableAutoIndexCreation ? loadFromDisk(inputFile, indexFile) // load without locking if we're in disableAutoIndexCreation mode
+ : attemptToLockAndLoadIndexFromDisk(inputFile, codec, indexFile, lock);
+ }
+
+ // If we have an index, it means we either loaded it from disk without issue or we created an in-memory
+ // index due to not being able to acquire a lock.
+ if (idx != null) return idx;
+
+ // We couldn't read the file, or we discovered a problem with the index file, so continue on to making a new index
+ idx = createIndexInMemory(inputFile, codec);
+ if ( ! disableAutoIndexCreation ) {
+ writeIndexToDisk(idx, indexFile, lock);
+ }
+ return idx;
+ }
+
+ /**
+ * Attempt to acquire a shared lock and then load the index from disk. Returns an in-memory index if
+ * a lock could not be obtained. Returns null if a problem was discovered with the index file when it
+ * was examined (eg., it was out-of-date).
+ *
+ * @param inputFile the input file
+ * @param codec the codec to read from
+ * @param indexFile the index file itself
+ * @param lock the lock file
+ * @return an index, or null if we couldn't load one
+ * @throws IOException if we fail for FS issues
+ */
+ protected Index attemptToLockAndLoadIndexFromDisk( final File inputFile, final FeatureCodec codec, final File indexFile, final FSLockWithShared lock ) throws IOException {
+ boolean locked = false;
+ Index idx = null;
+
+ try {
+ locked = lock.sharedLock();
+
+ if ( ! locked ) { // can't lock file
+ logger.info(String.format("Could not acquire a shared lock on index file %s, falling back to using an in-memory index for this GATK run.",
+ indexFile.getAbsolutePath()));
+ idx = createIndexInMemory(inputFile, codec);
+ }
+ else {
+ idx = loadFromDisk(inputFile, indexFile);
+ }
+ } finally {
+ if (locked) lock.unlock();
+ }
+ return idx;
+ }
+
+ /**
+ * load the index from disk, checking for out of date indexes and old versions (both of which are deleted)
+ * @param inputFile the input file
+ * @param indexFile the input file, plus the index extension
+ * @return an Index, or null if we're unable to load
+ */
+ protected Index loadFromDisk( final File inputFile, final File indexFile ) {
+ logger.debug("Loading Tribble index from disk for file " + inputFile);
+ Index index = IndexFactory.loadIndex(indexFile.getAbsolutePath());
+
+ // check if the file is up-to date (filestamp and version check)
+ if (index.isCurrentVersion() && indexFile.lastModified() >= inputFile.lastModified())
+ return index;
+ else if (indexFile.lastModified() < inputFile.lastModified())
+ logger.warn("Index file " + indexFile + " is out of date (index older than input file), " +
+ (disableAutoIndexCreation ? "falling back to an in-memory index" : "deleting and updating the index file"));
+ else // we've loaded an old version of the index, we want to remove it <-- currently not used, but may re-enable
+ logger.warn("Index file " + indexFile + " is out of date (old version), " +
+ (disableAutoIndexCreation ? "falling back to an in-memory index" : "deleting and updating the index file"));
+
+ if ( ! disableAutoIndexCreation ) {
+ boolean deleted = indexFile.delete();
+ if (!deleted) logger.warn("Index file " + indexFile + " is out of date, but could not be removed; it will not be trusted (we'll try to rebuild an in-memory copy)");
+ }
+
+ return null;
+ }
+
+
+ /**
+ * attempt to write the index to disk
+ * @param index the index to write to disk
+ * @param indexFile the index file location
+ * @param lock the locking object
+ * @throws IOException when unable to create the new index
+ */
+ private void writeIndexToDisk( final Index index, final File indexFile, final FSLockWithShared lock ) throws IOException {
+ if ( disableAutoIndexCreation ) {
+ return;
+ }
+
+ boolean locked = false;
+
+ try {
+ locked = lock.exclusiveLock();
+
+ if (locked) {
+ logger.info("Writing Tribble index to disk for file " + indexFile);
+ LittleEndianOutputStream stream = new LittleEndianOutputStream(new FileOutputStream(indexFile));
+ index.write(stream);
+ stream.close();
+ }
+ else // we can't write it to disk, just store it in memory, tell them this
+ logger.warn("Unable to write to " + indexFile + " for the index file, creating index in memory only");
+
+ try { logger.info(String.format(" Index for %s has size in bytes %d", indexFile, Sizeof.getObjectGraphSize(index))); }
+ catch ( ReviewedGATKException e) { }
+ }
+ finally {
+ if (locked) lock.unlock();
+ }
+
+ }
+
+ /**
+ * create the index in memory, given the input file and feature codec
+ * @param inputFile the input file
+ * @param codec the codec
+ * @return a LinearIndex, given the file location
+ * @throws IOException when unable to create the index in memory
+ */
+ protected Index createIndexInMemory(File inputFile, FeatureCodec codec) {
+ // this can take a while, let them know what we're doing
+ logger.debug("Creating Tribble index in memory for file " + inputFile);
+ Index idx = IndexFactory.createDynamicIndex(inputFile, codec, IndexFactory.IndexBalanceApproach.FOR_SEEK_TIME);
+ validateAndUpdateIndexSequenceDictionary(inputFile, idx, dict);
+ return idx;
+ }
+
+ /**
+ * set the sequence dictionary of the track. This function checks that the contig listing of the underlying file is compatible.
+ * (that each contig in the index is in the sequence dictionary).
+ * @param inputFile for proper error message formatting.
+ * @param dict the sequence dictionary
+ * @param index the index file
+ */
+ public void validateAndUpdateIndexSequenceDictionary(final File inputFile, final Index index, final SAMSequenceDictionary dict) {
+ if (dict == null) throw new ReviewedGATKException("BUG: dict cannot be null");
+
+ // check that every contig in the RMD contig list is at least in the sequence dictionary we're being asked to set
+ final SAMSequenceDictionary currentDict = IndexDictionaryUtils.createSequenceDictionaryFromContigList(index, new SAMSequenceDictionary());
+ validateTrackSequenceDictionary(inputFile.getAbsolutePath(), currentDict, dict);
+
+ // actually update the dictionary in the index
+ IndexDictionaryUtils.setIndexSequenceDictionary(index, dict);
+ }
+
+ public void validateTrackSequenceDictionary(final String trackName,
+ final SAMSequenceDictionary trackDict,
+ final SAMSequenceDictionary referenceDict ) {
+ IndexDictionaryUtils.validateTrackSequenceDictionary(trackName, trackDict, referenceDict, validationExclusionType);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/FeatureToGATKFeatureIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/FeatureToGATKFeatureIterator.java
new file mode 100644
index 0000000..6fb073e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/FeatureToGATKFeatureIterator.java
@@ -0,0 +1,74 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.utils;
+
+import htsjdk.samtools.util.CloseableIterator;
+import htsjdk.tribble.CloseableTribbleIterator;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+
+/**
+ *
+ * @author aaron
+ *
+ * Class FeatureToGATKFeatureIterator
+ *
+ * a wrapper on Tribble feature iterators so that they produce GATKFeatures (which produce GenomeLocs)
+ */
+public class FeatureToGATKFeatureIterator implements CloseableIterator<GATKFeature> {
+ private final GenomeLocParser genomeLocParser;
+ private final CloseableTribbleIterator<Feature> iterator;
+ private final String name;
+
+ public FeatureToGATKFeatureIterator(GenomeLocParser genomeLocParser,CloseableTribbleIterator<Feature> iter, String name) {
+ this.genomeLocParser = genomeLocParser;
+ this.name = name;
+ this.iterator = iter;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public GATKFeature next() {
+ return new GATKFeature.TribbleGATKFeature(genomeLocParser,iterator.next(),name);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Why does Iterator have this method? We always throw an exception here");
+ }
+
+ @Override
+ public void close() {
+ // The private adapted iterator may not be passed on by the method constructing this object,
+ // leaving only this adapter to close the wrapped iterator.
+ iterator.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/FlashBackIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/FlashBackIterator.java
new file mode 100644
index 0000000..8fc549c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/FlashBackIterator.java
@@ -0,0 +1,221 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.utils;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.HasGenomeLocation;
+
+import java.util.Comparator;
+import java.util.LinkedList;
+
+
+/**
+ *
+ * @author aaron
+ *
+ * Class FlashBackIterator
+ *
+ * better than acid washed jeans...more like a Delorean that flies through time
+ *
+ * This iterator buffers a certain amount of ROD data to 'flash back' to. This
+ * is needed for using ROD's in read traversals, because between shards we sometimes
+ * (actually often) need to go back to before the current iterators location and
+ * get RODs that overlap the current read.
+ */
+public class FlashBackIterator implements LocationAwareSeekableRODIterator {
+ private LocationAwareSeekableRODIterator iterator;
+ private LinkedList<ComparableList> pastQueue = new LinkedList<ComparableList>();
+ private LinkedList<ComparableList> aheadQueue = new LinkedList<ComparableList>();
+ private int MAX_QUEUE = 200;
+
+ /**
+ * create a flashback iterator
+ * @param iterator given a LocationAwareSeekableRODIterator
+ */
+ public FlashBackIterator(LocationAwareSeekableRODIterator iterator) {
+ this.iterator = iterator;
+ }
+
+ /**
+ * Gets the header associated with the backing input stream.
+ * @return the ROD header.
+ */
+ @Override
+ public Object getHeader() {
+ return iterator.getHeader();
+ }
+
+ /**
+ * Gets the sequence dictionary associated with the backing input stream.
+ * @return sequence dictionary from the ROD header.
+ */
+ @Override
+ public SAMSequenceDictionary getSequenceDictionary() {
+ return iterator.getSequenceDictionary();
+ }
+
+
+ /**
+ * peek at the next location
+ * @return
+ */
+ @Override
+ public GenomeLoc peekNextLocation() {
+ return (aheadQueue.size() > 0) ? aheadQueue.getFirst().getLocation() : iterator.peekNextLocation();
+ }
+
+ /**
+ * get the position of this iterator
+ * @return
+ */
+ @Override
+ public GenomeLoc position() {
+ return (aheadQueue.size() > 0) ? aheadQueue.getFirst().getLocation() : iterator.position();
+ }
+
+ /**
+ * seek forward on the iterator
+ * @param interval the interval to seek to
+ * @return a RODRecordList at that location, null otherwise
+ */
+ @Override
+ public RODRecordList seekForward(GenomeLoc interval) {
+
+ RODRecordList lt = iterator.seekForward(interval);
+ createPastRecord(lt);
+ return lt;
+ }
+
+ /**
+ * do we have a next record
+ * @return true if we have another record
+ */
+ @Override
+ public boolean hasNext() {
+ return (aheadQueue.size() > 0 || iterator.hasNext());
+ }
+
+ /**
+ * get the next record
+ * @return a RODRecordList
+ */
+ @Override
+ public RODRecordList next() {
+ return getNext();
+ }
+
+ /**
+ * we don't support remove
+ */
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("We don't support remove");
+ }
+
+ /**
+ * get the next record, either from the queue or from the iterator
+ * @return a RODRecordList
+ */
+ private RODRecordList getNext() {
+ if (aheadQueue.size() > 0) {
+ RODRecordList ret = aheadQueue.getFirst().getList();
+ aheadQueue.removeFirst();
+ return ret;
+ } else {
+ RODRecordList ret = iterator.next();
+ createPastRecord(ret);
+ return ret;
+ }
+ }
+
+ private void createPastRecord(RODRecordList ret) {
+ ComparableList rec = new ComparableList(ret);
+ if (rec.getLocation() != null) pastQueue.addLast(new ComparableList(ret));
+ if (pastQueue.size() > this.MAX_QUEUE) pastQueue.removeFirst();
+ }
+
+ /**
+ * can we flash back to the specified location?
+ *
+ * @param location the location to try and flash back to
+ *
+ * @return true if we can, false otherwise
+ */
+ public boolean canFlashBackTo(GenomeLoc location) {
+ GenomeLoc farthestBack = (pastQueue.size() > 0) ? pastQueue.getFirst().getLocation() : iterator.peekNextLocation();
+ return (!farthestBack.isPast(location));
+ }
+
+ /**
+ * flashback! Throws an unsupported operation exception
+ *
+ * @param location where to flash back to
+ */
+ public void flashBackTo(GenomeLoc location) {
+ if (!canFlashBackTo(location)) throw new UnsupportedOperationException("we can't flash back to " + location);
+ if (pastQueue.size()==0) return; // the iterator can do it alone
+ while (pastQueue.size() > 0 && !pastQueue.getLast().getLocation().isBefore(location)) {
+ aheadQueue.addFirst(pastQueue.getLast());
+ pastQueue.removeLast();
+ }
+ }
+
+ public void close() {
+ this.aheadQueue.clear();
+ this.pastQueue.clear();
+ }
+}
+
+/**
+ * a list that buffers the location for this rod
+ */
+class ComparableList implements Comparator<ComparableList>, HasGenomeLocation {
+ private RODRecordList list;
+ private GenomeLoc location = null;
+ public ComparableList(RODRecordList list) {
+ this.list = list;
+ if (list != null && list.size() != 0)
+ location = list.getLocation();
+ }
+
+ @Override
+ public int compare(ComparableList list1, ComparableList list2) {
+ if (list1.location == null && list2.location == null)
+ return 0;
+ if (list1.location == null) return 1;
+ if (list2.location == null) return -1;
+ return (list1.location.compareTo(list2.location));
+ }
+
+ public GenomeLoc getLocation() {
+ return location;
+ }
+
+ public RODRecordList getList() {
+ return list;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/GATKFeature.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/GATKFeature.java
new file mode 100644
index 0000000..4d08f1b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/GATKFeature.java
@@ -0,0 +1,109 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.utils;
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.engine.refdata.ReferenceOrderedDatum;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.HasGenomeLocation;
+
+
+/**
+ *
+ * @author aaron
+ *
+ * Class GATKFeature
+ *
+ * This wraps a Tribble feature or a RODatum so that both present the same interface: a genome loc for position and a
+ * way of retrieving the track name.
+ */
+public abstract class GATKFeature implements Feature, HasGenomeLocation {
+
+ public GATKFeature(String name) {
+ this.name = name;
+ }
+
+ String name;
+
+ protected void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public abstract GenomeLoc getLocation();
+
+ // TODO: this should be a Feature
+ public abstract Object getUnderlyingObject();
+
+ /**
+ * wrapping a Tribble feature in a GATK friendly interface
+ */
+ public static class TribbleGATKFeature extends GATKFeature {
+ private final GenomeLocParser genomeLocParser;
+ private final Feature feature;
+ private GenomeLoc position = null;
+
+ public TribbleGATKFeature(GenomeLocParser genomeLocParser,Feature f, String name) {
+ super(name);
+ this.genomeLocParser = genomeLocParser;
+ feature = f;
+ }
+ public GenomeLoc getLocation() {
+ if (position == null) position = genomeLocParser.createGenomeLoc(feature.getChr(), feature.getStart(), feature.getEnd());
+ return position;
+ }
+
+ /** Return the features reference sequence name, e.g chromosome or contig */
+ @Override
+ public String getChr() {
+ return feature.getChr();
+ }
+
+ /** Return the start position in 1-based coordinates (first base is 1) */
+ @Override
+ public int getStart() {
+ return feature.getStart();
+ }
+
+ /**
+ * Return the end position following 1-based fully closed conventions. The length of a feature is
+ * end - start + 1;
+ */
+ @Override
+ public int getEnd() {
+ return feature.getEnd();
+ }
+
+ // TODO: this should be a Feature, actually
+ public Object getUnderlyingObject() {
+ return feature;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/LocationAwareSeekableRODIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/LocationAwareSeekableRODIterator.java
new file mode 100644
index 0000000..96c60b9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/LocationAwareSeekableRODIterator.java
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.utils;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.util.CloseableIterator;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+
+/**
+ * @author aaron
+ * <p/>
+ * Interface LocationAwareSeekableRODIterator
+ * <p/>
+ * combine iteration with a position aware interface
+ */
+public interface LocationAwareSeekableRODIterator extends CloseableIterator<RODRecordList> {
+ public Object getHeader();
+
+ public SAMSequenceDictionary getSequenceDictionary();
+
+ public GenomeLoc peekNextLocation();
+
+ public GenomeLoc position();
+
+ public RODRecordList seekForward(GenomeLoc interval);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/RMDTriplet.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/RMDTriplet.java
new file mode 100644
index 0000000..9fa3d1e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/RMDTriplet.java
@@ -0,0 +1,92 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.utils;
+
+
+import org.broadinstitute.gatk.utils.commandline.Tags;
+
+/**
+ * a helper class to manage our triplets of data for the -B command line option (name, type, file)
+ * TODO: The presence of four datapoints here suggests that this class' name isn't sufficient to describe its function. Rename.
+ */
+public class RMDTriplet {
+ public enum RMDStorageType { FILE, STREAM };
+
+ private final String name;
+ private final String type;
+ private final String file;
+ private final RMDStorageType storageType;
+ private final Tags tags;
+
+ public RMDTriplet(final String name, final String type, final String file, final RMDStorageType storageType, final Tags tags) {
+ this.name = name;
+ this.type = type;
+ this.file = file;
+ this.storageType = storageType;
+ this.tags = tags;
+ }
+
+ /**
+ * Gets the name of this track. RefMetaDataTrackers can use this identifier to retrieve data of a certain type.
+ * @return Name associated with this track.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the type of this track. Informs the GATK how to parse this file type.
+ * @return Type associated with this track.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Gets the filename representing this track. Data is loaded from this file.
+ * @return Filename of the RMD.
+ */
+ public String getFile() {
+ return file;
+ }
+
+ /**
+ * The type of storage being used for this metadata track. Right now, can be either a
+ * file type (can be indexed) or a stream type (can't be indexed).
+ * @return Storage type for this RMD 'triplet'.
+ */
+ public RMDStorageType getStorageType() {
+ return storageType;
+ }
+
+ /**
+ * Gets the key=value tags associated with this track
+ * @return Tags associated with this track.
+ */
+ public Tags getTags() {
+ return tags;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/RODRecordList.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/RODRecordList.java
new file mode 100644
index 0000000..b859edc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/refdata/utils/RODRecordList.java
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.utils;
+
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.HasGenomeLocation;
+
+import java.util.List;
+
+
+/**
+ * @author aaron
+ * <p/>
+ * Class RODRecordList
+ * <p/>
+ * make the RODRecord list an interface, so we can stub in other implementations
+ * during testing.
+ */
+public interface RODRecordList extends List<GATKFeature>, Comparable<RODRecordList>, HasGenomeLocation {
+ public GenomeLoc getLocation();
+ public String getName();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReport.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReport.java
new file mode 100644
index 0000000..660ea95
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReport.java
@@ -0,0 +1,376 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.report;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.*;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Container class for GATK report tables
+ */
+public class GATKReport {
+ public static final String GATKREPORT_HEADER_PREFIX = "#:GATKReport.";
+ public static final GATKReportVersion LATEST_REPORT_VERSION = GATKReportVersion.V1_1;
+ private static final String SEPARATOR = ":";
+ private GATKReportVersion version = LATEST_REPORT_VERSION;
+
+ private final TreeMap<String, GATKReportTable> tables = new TreeMap<String, GATKReportTable>();
+
+ /**
+ * Create a new, empty GATKReport.
+ */
+ public GATKReport() {
+ }
+
+ /**
+ * Create a new GATKReport with the contents of a GATKReport on disk.
+ *
+ * @param filename the path to the file to load
+ */
+ public GATKReport(String filename) {
+ this(new File(filename));
+ }
+
+ /**
+ * Create a new GATKReport with the contents of a GATKReport on disk.
+ *
+ * @param file the file to load
+ */
+ public GATKReport(File file) {
+ loadReport(file);
+ }
+
+ /**
+ * Create a new GATK report from GATK report tables
+ * @param tables Any number of tables that you want to add to the report
+ */
+ public GATKReport(GATKReportTable... tables) {
+ for( GATKReportTable table: tables)
+ addTable(table);
+ }
+
+ /**
+ * Load a GATKReport file from disk
+ *
+ * @param file the file to load
+ */
+ private void loadReport(File file) {
+ BufferedReader reader;
+ String reportHeader;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ reportHeader = reader.readLine();
+ } catch (FileNotFoundException e) {
+ throw new UserException.CouldNotReadInputFile(file, "it does not exist");
+ } catch (IOException e) {
+ throw new UserException.CouldNotReadInputFile(file, e);
+ }
+
+
+ // Read the first line for the version and number of tables.
+ version = GATKReportVersion.fromHeader(reportHeader);
+ if (version.equals(GATKReportVersion.V0_1) ||
+ version.equals(GATKReportVersion.V0_2))
+ throw new UserException("The GATK no longer supports reading legacy GATK Reports. Please use v1.0 or newer.");
+
+ int nTables = Integer.parseInt(reportHeader.split(":")[2]);
+
+ // Read each table according ot the number of tables
+ for (int i = 0; i < nTables; i++) {
+ addTable(new GATKReportTable(reader, version));
+ }
+ }
+
+ /**
+ * Add a new, empty table to the report
+ *
+ * @param tableName the name of the table
+ * @param tableDescription the description of the table
+ * @param numColumns the number of columns in this table
+ */
+ public void addTable(final String tableName, final String tableDescription, final int numColumns) {
+ addTable(tableName, tableDescription, numColumns, GATKReportTable.TableSortingWay.DO_NOT_SORT);
+ }
+
+ /**
+ * Add a new, empty table to the report
+ *
+ * @param tableName the name of the table
+ * @param tableDescription the description of the table
+ * @param numColumns the number of columns in this table
+ * @param sortingWay way to sort table
+ */
+ public void addTable(final String tableName, final String tableDescription, final int numColumns, final GATKReportTable.TableSortingWay sortingWay) {
+ GATKReportTable table = new GATKReportTable(tableName, tableDescription, numColumns, sortingWay);
+ tables.put(tableName, table);
+ }
+
+ /**
+ * Adds a table, empty or populated, to the report
+ *
+ * @param table the table to add
+ */
+ public void addTable(GATKReportTable table) {
+ tables.put(table.getTableName(), table);
+ }
+
+ public void addTables(List<GATKReportTable> gatkReportTableV2s) {
+ for ( GATKReportTable table : gatkReportTableV2s )
+ addTable(table);
+ }
+
+ /**
+ * Return true if table with a given name exists
+ *
+ * @param tableName the name of the table
+ * @return true if the table exists, false otherwise
+ */
+ public boolean hasTable(String tableName) {
+ return tables.containsKey(tableName);
+ }
+
+ /**
+ * Return a table with a given name
+ *
+ * @param tableName the name of the table
+ * @return the table object
+ */
+ public GATKReportTable getTable(String tableName) {
+ GATKReportTable table = tables.get(tableName);
+ if (table == null)
+ throw new ReviewedGATKException("Table is not in GATKReport: " + tableName);
+ return table;
+ }
+
+ /**
+ * Print all tables contained within this container to a PrintStream
+ *
+ * @param out the PrintStream to which the tables should be written
+ */
+ public void print(PrintStream out) {
+ out.println(GATKREPORT_HEADER_PREFIX + getVersion().toString() + SEPARATOR + getTables().size());
+ for (GATKReportTable table : tables.values())
+ table.write(out);
+ }
+
+ public Collection<GATKReportTable> getTables() {
+ return tables.values();
+ }
+
+ /**
+ * This is the main function is charge of gathering the reports. It checks that the reports are compatible and then
+ * calls the table gathering functions.
+ *
+ * @param input another GATKReport of the same format
+ */
+ public void concat(GATKReport input) {
+
+ if ( !isSameFormat(input) ) {
+ throw new ReviewedGATKException("Failed to combine GATKReport, format doesn't match!");
+ }
+
+ for ( Map.Entry<String, GATKReportTable> table : tables.entrySet() ) {
+ table.getValue().concat(input.getTable(table.getKey()));
+ }
+ }
+
+ public GATKReportVersion getVersion() {
+ return version;
+ }
+
+ /**
+ * Returns whether or not the two reports have the same format, from columns, to tables, to reports, and everything
+ * in between. This does not check if the data inside is the same. This is the check to see if the two reports are
+ * gatherable or reduceable.
+ *
+ * @param report another GATK report
+ * @return true if the the reports are gatherable
+ */
+ public boolean isSameFormat(GATKReport report) {
+ if (!version.equals(report.version)) {
+ return false;
+ }
+ if (!tables.keySet().equals(report.tables.keySet())) {
+ return false;
+ }
+ for (String tableName : tables.keySet()) {
+ if (!getTable(tableName).isSameFormat(report.getTable(tableName)))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks that the reports are exactly the same.
+ *
+ * @param report another GATK report
+ * @return true if all field in the reports, tables, and columns are equal.
+ */
+ public boolean equals(GATKReport report) {
+ if (!version.equals(report.version)) {
+ return false;
+ }
+ if (!tables.keySet().equals(report.tables.keySet())) {
+ return false;
+ }
+ for (String tableName : tables.keySet()) {
+ if (!getTable(tableName).equals(report.getTable(tableName)))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * The constructor for a simplified GATK Report. Simplified GATK report are designed for reports that do not need
+ * the advanced functionality of a full GATK Report.
+ * <p/>
+ * A simple GATK Report consists of:
+ * <p/>
+ * - A single table
+ * - No primary key ( it is hidden )
+ * <p/>
+ * Optional:
+ * - Only untyped columns. As long as the data is an Object, it will be accepted.
+ * - Default column values being empty strings.
+ * <p/>
+ * Limitations:
+ * <p/>
+ * - A simple GATK report cannot contain multiple tables.
+ * - It cannot contain typed columns, which prevents arithmetic gathering.
+ *
+ * @param tableName The name of your simple GATK report table
+ * @param columns The names of the columns in your table
+ * @return a simplified GATK report
+ */
+ public static GATKReport newSimpleReport(final String tableName, final String... columns) {
+ return newSimpleReportWithDescription(tableName, "A simplified GATK table report", columns);
+ }
+
+ /**
+ * @see #newSimpleReport(String, String...) but with a customized description
+ * @param tableName
+ * @param desc
+ * @param columns
+ * @return
+ */
+ public static GATKReport newSimpleReportWithDescription(final String tableName, final String desc, final String... columns) {
+ GATKReportTable table = new GATKReportTable(tableName, desc, columns.length);
+
+ for (String column : columns) {
+ table.addColumn(column, "");
+ }
+
+ GATKReport output = new GATKReport();
+ output.addTable(table);
+
+ return output;
+ }
+
+ /**
+ * The constructor for a simplified GATK Report. Simplified GATK report are designed for reports that do not need
+ * the advanced functionality of a full GATK Report.
+ * <p/>
+ * A simple GATK Report consists of:
+ * <p/>
+ * - A single table
+ * - No primary key ( it is hidden )
+ * <p/>
+ * Optional:
+ * - Only untyped columns. As long as the data is an Object, it will be accepted.
+ * - Default column values being empty strings.
+ * <p/>
+ * Limitations:
+ * <p/>
+ * - A simple GATK report cannot contain multiple tables.
+ * - It cannot contain typed columns, which prevents arithmetic gathering.
+ *
+ * @param tableName The name of your simple GATK report table
+ * @param columns The names of the columns in your table
+ * @return a simplified GATK report
+ */
+ public static GATKReport newSimpleReport(final String tableName, final List<String> columns) {
+ GATKReportTable table = new GATKReportTable(tableName, "A simplified GATK table report", columns.size());
+
+ for (String column : columns) {
+ table.addColumn(column, "");
+ }
+
+ GATKReport output = new GATKReport();
+ output.addTable(table);
+
+ return output;
+ }
+
+ /**
+ * This method provides an efficient way to populate a simplified GATK report. This method will only work on reports
+ * that qualify as simplified GATK reports. See the newSimpleReport() constructor for more information.
+ *
+ * @param values the row of data to be added to the table.
+ * Note: the number of arguments must match the columns in the table.
+ */
+ public void addRow(final Object... values) {
+ // Must be a simple report
+ if ( tables.size() != 1 )
+ throw new ReviewedGATKException("Cannot write a row to a complex GATK Report");
+
+ GATKReportTable table = tables.firstEntry().getValue();
+ if ( table.getNumColumns() != values.length )
+ throw new ReviewedGATKException("The number of arguments in writeRow (" + values.length + ") must match the number of columns in the table (" + table.getNumColumns() + ")" );
+
+ final int rowIndex = table.getNumRows();
+ for ( int i = 0; i < values.length; i++ )
+ table.set(rowIndex, i, values[i]);
+ }
+
+ /**
+ * This method provides an efficient way to populate a simplified GATK report. This method will only work on reports
+ * that qualify as simplified GATK reports. See the newSimpleReport() constructor for more information.
+ *
+ * @param values the row of data to be added to the table.
+ * Note: the number of arguments must match the columns in the table.
+ */
+ public void addRowList(final List<Object> values) {
+ if ( tables.size() != 1 )
+ throw new ReviewedGATKException("Cannot write a row to a complex GATK Report");
+
+ GATKReportTable table = tables.firstEntry().getValue();
+ if ( table.getNumColumns() != values.size() )
+ throw new ReviewedGATKException("The number of arguments in writeRow() must match the number of columns in the table");
+
+ final int rowIndex = table.getNumRows();
+ int idx = 0;
+ for ( Object value : values ) {
+ table.set(rowIndex,idx,value);
+ idx++;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportColumn.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportColumn.java
new file mode 100644
index 0000000..ffdefff
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportColumn.java
@@ -0,0 +1,147 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.report;
+
+import org.apache.commons.lang.math.NumberUtils;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * column information within a GATK report table
+ */
+public class GATKReportColumn {
+ final private String columnName;
+ final private String format;
+ final private GATKReportDataType dataType;
+
+ private GATKReportColumnFormat columnFormat;
+ private GATKReportColumnFormat.Alignment alignment = GATKReportColumnFormat.Alignment.RIGHT; // default alignment is to the right unless values added ask for a left alignment
+ private int maxWidth = 0;
+
+ /**
+ * Construct the column object, specifying the column name, default value, whether or not the column should be
+ * displayed, and the format string. This cannot be null.
+ *
+ * @param columnName the name of the column
+ * @param format format string
+ */
+ public GATKReportColumn(final String columnName, final String format) {
+ this.columnName = columnName;
+ this.maxWidth = columnName.length();
+ if ( format.equals("") ) {
+ this.format = "%s";
+ this.dataType = GATKReportDataType.Unknown;
+ }
+ else {
+ this.format = format;
+ this.dataType = GATKReportDataType.fromFormatString(format);
+ }
+ }
+
+ /**
+ * Get the display width for this column. This allows the entire column to be displayed with the appropriate, fixed
+ * width.
+ *
+ * @return the format string for this column
+ */
+ public GATKReportColumnFormat getColumnFormat() {
+ if (columnFormat != null)
+ return columnFormat;
+
+ columnFormat = new GATKReportColumnFormat(maxWidth, alignment);
+ return columnFormat;
+ }
+
+ private static final Collection<String> RIGHT_ALIGN_STRINGS = Arrays.asList(
+ "null",
+ "NA",
+ String.valueOf(Double.POSITIVE_INFINITY),
+ String.valueOf(Double.NEGATIVE_INFINITY),
+ String.valueOf(Double.NaN));
+
+ /**
+ * Check if the value can be right aligned. Does not trim the values before checking if numeric since it assumes
+ * the spaces mean that the value is already padded.
+ *
+ * @param value to check
+ * @return true if the value is a right alignable
+ */
+ protected static boolean isRightAlign(final String value) {
+ return value == null || RIGHT_ALIGN_STRINGS.contains(value) || NumberUtils.isNumber(value.trim());
+ }
+
+ /**
+ * Returns a string version of the values.
+ *
+ * @param obj The object to convert to a string
+ * @return The string representation of the column
+ */
+ private String formatValue(final Object obj) {
+ String value;
+ if (obj == null) {
+ value = "null";
+ }
+ else if ( dataType.equals(GATKReportDataType.Unknown) && (obj instanceof Double || obj instanceof Float) ) {
+ value = String.format("%.8f", obj);
+ }
+ else
+ value = String.format(format, obj);
+
+ return value;
+ }
+
+ public GATKReportDataType getDataType() {
+ return dataType;
+ }
+
+ public String getColumnName() {
+ return columnName;
+ }
+
+ public String getFormat() {
+ return dataType.equals(GATKReportDataType.Unknown) ? "%s" : format;
+ }
+
+ public void updateFormatting(final Object value) {
+ if (value != null) {
+ final String formatted = formatValue(value);
+ if ( formatted.length() > 0 ) {
+ updateMaxWidth(formatted);
+ updateFormat(formatted);
+ }
+ }
+ }
+
+ private void updateMaxWidth(final String formatted) {
+ maxWidth = Math.max(formatted.length(), maxWidth);
+ }
+
+ private void updateFormat(final String formatted) {
+ if (alignment == GATKReportColumnFormat.Alignment.RIGHT)
+ alignment = isRightAlign(formatted) ? GATKReportColumnFormat.Alignment.RIGHT : GATKReportColumnFormat.Alignment.LEFT;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportColumnFormat.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportColumnFormat.java
new file mode 100644
index 0000000..664b503
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportColumnFormat.java
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.report;
+
+/**
+ * Column width and left/right alignment.
+ */
+public class GATKReportColumnFormat {
+ public static enum Alignment { LEFT, RIGHT }
+ private final int width;
+ private final Alignment alignment;
+
+ public GATKReportColumnFormat(int width, Alignment alignment) {
+ this.width = width;
+ this.alignment = alignment;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public Alignment getAlignment() {
+ return alignment;
+ }
+
+ public String getNameFormat() {
+ return "%-" + width + "s";
+ }
+
+ public String getValueFormat() {
+ switch (alignment) {
+ case LEFT:
+ return "%-" + width + "s";
+ case RIGHT:
+ return "%" + width + "s";
+ default:
+ throw new UnsupportedOperationException("Unknown alignment: " + alignment);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportDataType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportDataType.java
new file mode 100644
index 0000000..acfa74f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportDataType.java
@@ -0,0 +1,236 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.report;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The gatherable data types acceptable in a GATK report column.
+ */
+public enum GATKReportDataType {
+ /**
+ * The null type should not be used.
+ */
+ Null("Null"),
+
+ /**
+ * The default value when a format string is not present
+ */
+ Unknown("Unknown"),
+
+ /**
+ * Used for boolean values. Will display as true or false in the table.
+ */
+ Boolean("%[Bb]"),
+
+ /**
+ * Used for char values. Will display as a char so use printable values!
+ */
+ Character("%[Cc]"),
+
+ /**
+ * Used for float and double values. Will output a decimal with format %.8f unless otherwise specified.
+ */
+ Decimal("%.*[EeFf]"),
+
+ /**
+ * Used for int, byte, short, and long values. Will display the full number by default.
+ */
+ Integer("%[Dd]"),
+
+ /**
+ * Used for string values. Displays the string itself.
+ */
+ String("%[Ss]");
+
+ private final String dataTypeString;
+
+ private GATKReportDataType(String dataTypeString) {
+ this.dataTypeString = dataTypeString;
+ }
+
+ private static final Map<String, GATKReportDataType> lookup = new HashMap<String, GATKReportDataType>();
+
+ static {
+ for (GATKReportDataType s : EnumSet.allOf(GATKReportDataType.class))
+ lookup.put(s.dataTypeString, s);
+ }
+
+
+ @Override
+ public String toString() {
+ return this.dataTypeString;
+ }
+
+ /**
+ * Returns a GATK report data type from the Object specified. It looks through the list of acceptable classes and
+ * returns the appropriate data type.
+ *
+ * @param object the object ot derive the data type from
+ * @return the appropriate data type
+ */
+ public static GATKReportDataType fromObject(Object object) {
+ GATKReportDataType value;
+ if (object instanceof Boolean) {
+ value = GATKReportDataType.Boolean;
+
+ } else if (object instanceof Character) {
+ value = GATKReportDataType.Character;
+
+ } else if (object instanceof Float ||
+ object instanceof Double) {
+ value = GATKReportDataType.Decimal;
+
+ } else if (object instanceof Integer ||
+ object instanceof Long ||
+ object instanceof Short ||
+ object instanceof Byte ) {
+ value = GATKReportDataType.Integer;
+
+ } else if (object instanceof String) {
+ value = GATKReportDataType.String;
+
+ } else {
+ value = GATKReportDataType.Unknown;
+ //throw new UserException("GATKReport could not convert the data object into a GATKReportDataType. Acceptable data objects are found in the documentation.");
+ }
+ return value;
+ }
+
+ /**
+ * Returns a GATK report data type from the format string specified. It uses regex matching from the enumerated
+ * Strings.
+ *
+ * @param format the format string to derive the data type from
+ * @return the appropriate data type
+ */
+ public static GATKReportDataType fromFormatString(String format) {
+ if (format.equals(""))
+ return Unknown;
+ for (GATKReportDataType type : lookup.values()) {
+ if (format.matches(type.toString()) )
+ return type;
+ }
+ return Unknown;
+ }
+
+ /**
+ * Returns the default value of the data type. It returns an object that matches the class of the data type.
+ *
+ * @return an object that matches the data type
+ */
+ public Object getDefaultValue() {
+ switch (this) {
+ case Decimal:
+ return 0.0D;
+ case Boolean:
+ return false;
+ case Character:
+ return '0';
+ case Integer:
+ return 0L;
+ case String:
+ return "";
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Checks if the two objects are equal using the appropriate test form the data types.
+ *
+ * @param a an object
+ * @param b another object to check if equal
+ * @return true - the objects are equal, false - the objects are nto equal
+ */
+ public boolean isEqual(Object a, Object b) {
+ switch (this) {
+ case Null:
+ return true;
+ case Decimal:
+ case Boolean:
+ case Integer:
+ return a.toString().equals(b.toString());
+ case Character:
+ case String:
+ default:
+ return a.equals(b);
+ }
+ }
+
+ /**
+ * Converts an input String to the appropriate type using the data type. Used for parsing loading a GATK report from
+ * file.
+ *
+ * @param obj The input string
+ * @return an object that matches the data type.
+ */
+ Object Parse(Object obj) {
+ if (obj instanceof String) {
+ String str = obj.toString();
+ switch (this) {
+ case Decimal:
+ return Double.parseDouble(str);
+ case Boolean:
+ return java.lang.Boolean.parseBoolean(str);
+ case Integer:
+ return Long.parseLong(str);
+ case String:
+ return str;
+ case Character:
+ return str.toCharArray()[0];
+ default:
+ return str;
+ }
+ } else
+ return null;
+ }
+
+ /**
+ * Returns a format string version of the value according to the data type.
+ *
+ * @return The printf string representation of the object according to data type.
+ */
+ public String getDefaultFormatString() {
+ switch (this) {
+ case Decimal:
+ return "%.8f";
+ case Boolean:
+ return "%b";
+ case Integer:
+ return "%d";
+ case String:
+ return "%s";
+ case Character:
+ return "%c";
+ case Null:
+ default:
+ return "%s";
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportGatherer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportGatherer.java
new file mode 100644
index 0000000..5f7f767
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportGatherer.java
@@ -0,0 +1,62 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.report;
+
+import org.broadinstitute.gatk.utils.commandline.Gatherer;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.util.List;
+
+public class GATKReportGatherer extends Gatherer {
+ @Override
+ public void gather(List<File> inputs, File output) {
+ //Combines inputs GATKReport to one output
+
+ PrintStream o;
+ try {
+ o = new PrintStream(output);
+ } catch (FileNotFoundException e) {
+ throw new UserException(String.format("File %s to be output by GATKReportGatherer function was not found", output));
+ }
+
+ GATKReport current = new GATKReport();
+ boolean isFirst = true;
+ for (File input : inputs) {
+ if (isFirst) {
+ current = new GATKReport(input);
+ isFirst = false;
+ } else {
+ current.concat(new GATKReport(input));
+ }
+ }
+
+ current.print(o);
+ o.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportTable.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportTable.java
new file mode 100644
index 0000000..6a1e456
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportTable.java
@@ -0,0 +1,779 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.report;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.text.TextFormattingUtils;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class GATKReportTable {
+ /**
+ * REGEX that matches any table with an invalid name
+ */
+ public static final String INVALID_TABLE_NAME_REGEX = "[^a-zA-Z0-9_\\-\\.]";
+ private static final String GATKTABLE_HEADER_PREFIX = "#:GATKTable";
+ private static final String SEPARATOR = ":";
+ private static final String ENDLINE = ":;";
+
+ private final String tableName;
+ private final String tableDescription;
+
+ private final TableSortingWay sortingWay;
+
+ private List<Object[]> underlyingData;
+ private final List<GATKReportColumn> columnInfo;
+ private final Map<Object, Integer> columnNameToIndex;
+ private final HashMap<Object, Integer> rowIdToIndex;
+
+ private static final String COULD_NOT_READ_HEADER = "Could not read the header of this file -- ";
+ private static final String COULD_NOT_READ_COLUMN_NAMES = "Could not read the column names of this file -- ";
+ private static final String COULD_NOT_READ_DATA_LINE = "Could not read a data line of this table -- ";
+ private static final String COULD_NOT_READ_EMPTY_LINE = "Could not read the last empty line of this table -- ";
+ private static final String OLD_GATK_TABLE_VERSION = "We no longer support older versions of the GATK Tables";
+
+ private static final int INITITAL_ARRAY_SIZE = 10000;
+ private static final String NUMBER_CONVERSION_EXCEPTION = "String is a number but is not a long or a double: ";
+
+ protected enum TableDataHeaderFields {
+ COLS(2),
+ ROWS(3),
+ FORMAT_START(4);
+
+ private final int index;
+ TableDataHeaderFields(int index) { this.index = index; }
+ public int index() { return index; }
+ }
+
+ public enum TableSortingWay {
+ SORT_BY_ROW,
+ SORT_BY_COLUMN,
+ DO_NOT_SORT
+ }
+
+ protected enum TableNameHeaderFields {
+ NAME(2),
+ DESCRIPTION(3);
+
+ private final int index;
+ TableNameHeaderFields(int index) { this.index = index; }
+ public int index() { return index; }
+ }
+
+ /**
+ * Construct a new GATK report table from the reader
+ * Note that the row ID mappings are just the index -> index
+ *
+ * @param reader the reader
+ * @param version the GATK report version
+ */
+ public GATKReportTable(BufferedReader reader, GATKReportVersion version) {
+
+ switch ( version ) {
+ case V1_1:
+ // read in the header lines
+ final String[] tableData, tableNameData;
+ try {
+ tableData = reader.readLine().split(SEPARATOR);
+ tableNameData = reader.readLine().split(SEPARATOR);
+ } catch (IOException e) {
+ throw new ReviewedGATKException(COULD_NOT_READ_HEADER + e.getMessage());
+ }
+
+ // parse the header fields
+ tableName = tableNameData[TableNameHeaderFields.NAME.index()];
+ tableDescription = (tableNameData.length <= TableNameHeaderFields.DESCRIPTION.index()) ? "" : tableNameData[TableNameHeaderFields.DESCRIPTION.index()]; // table may have no description! (and that's okay)
+
+ // when reading from a file, we do not re-sort the rows
+ sortingWay = TableSortingWay.DO_NOT_SORT;
+
+ // initialize the data
+ final int nColumns = Integer.parseInt(tableData[TableDataHeaderFields.COLS.index()]);
+ final int nRows = Integer.parseInt(tableData[TableDataHeaderFields.ROWS.index()]);
+ underlyingData = new ArrayList<Object[]>(nRows);
+ columnInfo = new ArrayList<GATKReportColumn>(nColumns);
+ columnNameToIndex = new HashMap<Object, Integer>(nColumns);
+
+ // when reading from a file, the row ID mapping is just the index
+ rowIdToIndex = new HashMap<Object, Integer>();
+ for ( int i = 0; i < nRows; i++ )
+ rowIdToIndex.put(i, i);
+
+ // read the column names
+ final String columnLine;
+ try {
+ columnLine = reader.readLine();
+ } catch (IOException e) {
+ throw new ReviewedGATKException(COULD_NOT_READ_COLUMN_NAMES);
+ }
+
+ final List<Integer> columnStarts = TextFormattingUtils.getWordStarts(columnLine);
+ final String[] columnNames = TextFormattingUtils.splitFixedWidth(columnLine, columnStarts);
+
+ // Put in columns using the format string from the header
+ for ( int i = 0; i < nColumns; i++ ) {
+ final String format = tableData[TableDataHeaderFields.FORMAT_START.index() + i];
+ addColumn(columnNames[i], format);
+ }
+
+ // fill in the table
+ try {
+ for ( int i = 0; i < nRows; i++ ) {
+ // read a data line
+ final String dataLine = reader.readLine();
+ final List<String> lineSplits = Arrays.asList(TextFormattingUtils.splitFixedWidth(dataLine, columnStarts));
+
+ underlyingData.add(new Object[nColumns]);
+ for ( int columnIndex = 0; columnIndex < nColumns; columnIndex++ ) {
+
+ final GATKReportDataType type = columnInfo.get(columnIndex).getDataType();
+ final String columnName = columnNames[columnIndex];
+ set(i, columnName, type.Parse(lineSplits.get(columnIndex)));
+
+ }
+ }
+ } catch (IOException e) {
+ throw new ReviewedGATKException(COULD_NOT_READ_DATA_LINE + e.getMessage());
+ }
+
+ try {
+ reader.readLine();
+ } catch (IOException e) {
+ throw new ReviewedGATKException(COULD_NOT_READ_EMPTY_LINE + e.getMessage());
+ }
+ break;
+
+ default:
+ throw new ReviewedGATKException(OLD_GATK_TABLE_VERSION);
+ }
+ }
+
+ /**
+ * Construct a new GATK report table with the specified name and description
+ *
+ * @param tableName the name of the table
+ * @param tableDescription the description of the table
+ * @param numColumns the number of columns in this table
+ */
+ public GATKReportTable(final String tableName, final String tableDescription, final int numColumns) {
+ this(tableName, tableDescription, numColumns, TableSortingWay.SORT_BY_ROW);
+ }
+
+ /**
+ * Construct a new GATK report table with the specified name and description and whether to sort rows by the row ID.
+ *
+ * @param tableName the name of the table
+ * @param tableDescription the description of the table
+ * @param numColumns the number of columns in this table
+ * @param sortingWay in what way to sort rows (instead of the order in which they were added)
+ */
+ public GATKReportTable(final String tableName, final String tableDescription, final int numColumns, final TableSortingWay sortingWay) {
+ if ( !isValidName(tableName) ) {
+ throw new ReviewedGATKException("Attempted to set a GATKReportTable name of '" + tableName + "'. GATKReportTable names must be purely alphanumeric - no spaces or special characters are allowed.");
+ }
+
+ if ( !isValidDescription(tableDescription) ) {
+ throw new ReviewedGATKException("Attempted to set a GATKReportTable description of '" + tableDescription + "'. GATKReportTable descriptions must not contain newlines.");
+ }
+
+ this.tableName = tableName;
+ this.tableDescription = tableDescription;
+ this.sortingWay = sortingWay;
+
+ underlyingData = new ArrayList<Object[]>(INITITAL_ARRAY_SIZE);
+ columnInfo = new ArrayList<GATKReportColumn>(numColumns);
+ columnNameToIndex = new HashMap<Object, Integer>(numColumns);
+ rowIdToIndex = new HashMap<Object, Integer>();
+ }
+
+ /**
+ * Create a new GATKReportTable with the same structure
+ * @param tableToCopy
+ */
+ public GATKReportTable(final GATKReportTable tableToCopy, final boolean copyData) {
+ this(tableToCopy.getTableName(), tableToCopy.getTableDescription(), tableToCopy.getNumColumns(), tableToCopy.sortingWay);
+ for ( final GATKReportColumn column : tableToCopy.getColumnInfo() )
+ addColumn(column.getColumnName(), column.getFormat());
+ if ( copyData )
+ throw new IllegalArgumentException("sorry, copying data in GATKReportTable isn't supported");
+ }
+
+ /**
+ * Verifies that a table or column name has only alphanumeric characters - no spaces or special characters allowed
+ *
+ * @param name the name of the table or column
+ * @return true if the name is valid, false if otherwise
+ */
+ private boolean isValidName(String name) {
+ Pattern p = Pattern.compile(INVALID_TABLE_NAME_REGEX);
+ Matcher m = p.matcher(name);
+
+ return !m.find();
+ }
+
+ /**
+ * Verifies that a table or column name has only alphanumeric characters - no spaces or special characters allowed
+ *
+ * @param description the name of the table or column
+ * @return true if the name is valid, false if otherwise
+ */
+ private boolean isValidDescription(String description) {
+ Pattern p = Pattern.compile("\\r|\\n");
+ Matcher m = p.matcher(description);
+
+ return !m.find();
+ }
+
+ /**
+ * Add a mapping from ID to the index of a new row added to the table.
+ *
+ * @param ID the unique ID
+ */
+ public void addRowID(final String ID) {
+ addRowID(ID, false);
+ }
+
+ /**
+ * Add a mapping from ID to the index of a new row added to the table.
+ *
+ * @param ID the unique ID
+ * @param populateFirstColumn should we automatically populate the first column with the row's ID?
+ */
+ public void addRowID(final String ID, final boolean populateFirstColumn) {
+ addRowIDMapping(ID, underlyingData.size(), populateFirstColumn);
+ }
+
+ /**
+ * Add a mapping from ID to row index.
+ *
+ * @param ID the unique ID
+ * @param index the index associated with the ID
+ */
+ public void addRowIDMapping(final String ID, final int index) {
+ addRowIDMapping(ID, index, false);
+ }
+
+ /**
+ * Add a mapping from ID to row index.
+ *
+ * @param ID the unique ID
+ * @param index the index associated with the ID
+ * @param populateFirstColumn should we automatically populate the first column with the row's ID?
+ */
+ public void addRowIDMapping(final Object ID, final int index, final boolean populateFirstColumn) {
+ expandTo(index, false);
+ rowIdToIndex.put(ID, index);
+
+ if ( populateFirstColumn )
+ set(index, 0, ID);
+ }
+
+ /**
+ * Remove a mapping from ID to row index.
+ *
+ * @param ID the row ID
+ */
+ public void removeRowIDMapping(final Object ID) {
+ rowIdToIndex.remove(ID);
+ }
+
+ /**
+ * Add a column to the report
+ *
+ * @param columnName the name of the column
+ */
+ public void addColumn(String columnName) {
+ addColumn(columnName, "");
+ }
+
+ /**
+ * Add a column to the report and the format string used to display the data.
+ *
+ * @param columnName the name of the column
+ * @param format the format string used to display data
+ */
+ public void addColumn(String columnName, String format) {
+ columnNameToIndex.put(columnName, columnInfo.size());
+ columnInfo.add(new GATKReportColumn(columnName, format));
+ }
+
+ /**
+ * Check if the requested cell is valid and expand the table if necessary
+ *
+ * @param rowIndex the row index
+ * @param colIndex the column index
+ */
+ private void verifyEntry(final int rowIndex, final int colIndex) {
+ if ( rowIndex < 0 || colIndex < 0 || colIndex >= getNumColumns() )
+ throw new ReviewedGATKException("attempted to access a cell that does not exist in table '" + tableName + "'");
+ }
+
+ /**
+ * expand the underlying table if needed to include the given row index
+ *
+ * @param rowIndex the row index
+ * @param updateRowIdMap should we update the row ID map?
+ */
+ private void expandTo(final int rowIndex, final boolean updateRowIdMap) {
+ int currentSize = underlyingData.size();
+ if ( rowIndex >= currentSize ) {
+ final int numNewRows = rowIndex - currentSize + 1;
+ for ( int i = 0; i < numNewRows; i++ ) {
+ if ( updateRowIdMap )
+ rowIdToIndex.put(currentSize, currentSize);
+ underlyingData.add(new Object[getNumColumns()]);
+ currentSize++;
+ }
+ }
+ }
+
+ /**
+ * Set the value for a given position in the table.
+ * If the row ID doesn't exist, it will create a new row in the table with the given ID.
+ *
+ * @param rowID the row ID
+ * @param columnName the name of the column
+ * @param value the value to set
+ */
+ public void set(final Object rowID, final String columnName, final Object value) {
+ if ( !rowIdToIndex.containsKey(rowID) ) {
+ rowIdToIndex.put(rowID, underlyingData.size());
+ expandTo(underlyingData.size(), false);
+ }
+ set(rowIdToIndex.get(rowID), columnNameToIndex.get(columnName), value);
+ }
+
+ /**
+ * Set the value for a given position in the table.
+ * If the row index doesn't exist, it will create new rows in the table accordingly.
+ *
+ * @param rowIndex the row index
+ * @param colIndex the column index
+ * @param value the value to set
+ */
+ public void set(final int rowIndex, final int colIndex, Object value) {
+ expandTo(rowIndex, true);
+ verifyEntry(rowIndex, colIndex);
+ GATKReportColumn column = columnInfo.get(colIndex);
+
+ // We do not accept internal null values
+ if (value == null)
+ value = "null";
+ else
+ value = fixType(value, column);
+
+ if ( column.getDataType().equals(GATKReportDataType.fromObject(value)) || column.getDataType().equals(GATKReportDataType.Unknown) ) {
+ underlyingData.get(rowIndex)[colIndex] = value;
+ column.updateFormatting(value);
+ } else {
+ throw new ReviewedGATKException(String.format("Tried to add an object of type: %s to a column of type: %s", GATKReportDataType.fromObject(value).name(), column.getDataType().name()));
+ }
+ }
+
+ /**
+ * Returns true if the table contains a row mapping with the given ID
+ *
+ * @param rowID the row ID
+ */
+ public boolean containsRowID(final Object rowID) {
+ return rowIdToIndex.containsKey(rowID);
+ }
+
+ /**
+ * Returns the row mapping IDs
+ *
+ */
+ public Collection<Object> getRowIDs() {
+ return rowIdToIndex.keySet();
+ }
+
+ /**
+ * Increment the value for a given position in the table.
+ * Throws an exception if the value in the cell is not an integer.
+ *
+ * @param rowID the row ID
+ * @param columnName the name of the column
+ */
+ public void increment(final Object rowID, final String columnName) {
+ int prevValue;
+ if ( !rowIdToIndex.containsKey(rowID) ) {
+ rowIdToIndex.put(rowID, underlyingData.size());
+ underlyingData.add(new Object[getNumColumns()]);
+ prevValue = 0;
+ } else {
+ Object obj = get(rowID, columnName);
+ if ( !(obj instanceof Integer) )
+ throw new ReviewedGATKException("Attempting to increment a value in a cell that is not an integer");
+ prevValue = (Integer)obj;
+ }
+
+ set(rowIdToIndex.get(rowID), columnNameToIndex.get(columnName), prevValue + 1);
+ }
+
+ /**
+ * Returns the index of the first row matching the column values.
+ * Ex: "CountVariants", "dbsnp", "eval", "called", "all", "novel", "all"
+ *
+ * @param columnValues column values.
+ * @return The index of the first row matching the column values or -1 if no such row exists.
+ */
+ public int findRowByData(final Object... columnValues) {
+ if ( columnValues == null || columnValues.length == 0 || columnValues.length > getNumColumns() )
+ return -1;
+
+ for ( int rowIndex = 0; rowIndex < underlyingData.size(); rowIndex++ ) {
+
+ final Object[] row = underlyingData.get(rowIndex);
+
+ boolean matches = true;
+ for ( int colIndex = 0; colIndex < columnValues.length; colIndex++ ) {
+ if ( !columnValues[colIndex].equals(row[colIndex]) ) {
+ matches = false;
+ break;
+ }
+ }
+
+ if ( matches )
+ return rowIndex;
+ }
+
+ return -1;
+ }
+
+ private Object fixType(final Object value, final GATKReportColumn column) {
+ // Below is some code to convert a string into its appropriate type.
+
+ // todo -- Types have to be more flexible. For example, %d should accept Integers, Shorts and Bytes.
+
+ Object newValue = null;
+ if ( value instanceof String && !column.getDataType().equals(GATKReportDataType.String) ) {
+ // Integer case
+ if ( column.getDataType().equals(GATKReportDataType.Integer) ) {
+ try {
+ newValue = Long.parseLong((String) value);
+ } catch (Exception e) {
+ /** do nothing */
+ }
+ }
+ if ( column.getDataType().equals(GATKReportDataType.Decimal) ) {
+ try {
+ newValue = Double.parseDouble((String) value);
+ } catch (Exception e) {
+ /** do nothing */
+ }
+ }
+ if ( column.getDataType().equals(GATKReportDataType.Character) && ((String) value).length() == 1 ) {
+ newValue = ((String) value).charAt(0);
+ }
+ }
+
+ return (newValue != null) ? newValue : value;
+ }
+
+ /**
+ * Get a value from the given position in the table
+ *
+ * @param rowID the row ID
+ * @param columnName the name of the column
+ * @return the value stored at the specified position in the table
+ */
+ public Object get(final Object rowID, final String columnName) {
+ return get(rowIdToIndex.get(rowID), columnNameToIndex.get(columnName));
+ }
+
+ /**
+ * Get a value from the given position in the table
+ *
+ * @param rowIndex the row ID
+ * @param columnName the name of the column
+ * @return the value stored at the specified position in the table
+ */
+ public Object get(final int rowIndex, final String columnName) {
+ return get(rowIndex, columnNameToIndex.get(columnName));
+ }
+
+ /**
+ * Get a value from the given position in the table
+ *
+ * @param rowIndex the index of the row
+ * @param columnIndex the index of the column
+ * @return the value stored at the specified position in the table
+ */
+ public Object get(int rowIndex, int columnIndex) {
+ verifyEntry(rowIndex, columnIndex);
+ return underlyingData.get(rowIndex)[columnIndex];
+ }
+
+ /**
+ * Write the table to the PrintStream, formatted nicely to be human-readable, AWK-able, and R-friendly.
+ *
+ * @param out the PrintStream to which the table should be written
+ */
+ void write(final PrintStream out) {
+
+ /*
+ * Table header:
+ * #:GATKTable:nColumns:nRows:(DataType for each column):;
+ * #:GATKTable:TableName:Description :;
+ * key colA colB
+ * row1 xxxx xxxxx
+ */
+
+ // write the table definition
+ out.printf(GATKTABLE_HEADER_PREFIX + ":%d:%d", getNumColumns(), getNumRows());
+
+ // write the formats for all the columns
+ for ( final GATKReportColumn column : columnInfo )
+ out.print(SEPARATOR + column.getFormat());
+ out.println(ENDLINE);
+
+ // write the table name & description
+ out.printf(GATKTABLE_HEADER_PREFIX + ":%s:%s\n", tableName, tableDescription);
+
+ // write the column names
+ boolean needsPadding = false;
+ for ( final GATKReportColumn column : columnInfo ) {
+ if ( needsPadding )
+ out.printf(" ");
+ needsPadding = true;
+
+ out.printf(column.getColumnFormat().getNameFormat(), column.getColumnName());
+ }
+ out.println();
+
+ // write the table body
+ switch (sortingWay) {
+ case SORT_BY_COLUMN:
+ Collections.sort(underlyingData, new Comparator<Object[]>() {
+ //INVARIANT the two arrays are of the same length and corresponding elements are of the same type
+ @Override
+ public int compare(Object[] objectArr1, Object[] objectArr2) {
+ final int EQUAL = 0;
+
+ int result = EQUAL;
+
+ int l = objectArr1.length;
+ for (int x = 0; x < l; x++) {
+ if (objectArr1[x] instanceof Integer) {
+ result = ((Integer)objectArr1[x]).compareTo((Integer)objectArr2[x]);
+ } else if (objectArr1[x] instanceof Double) {
+ result = ((Double)objectArr1[x]).compareTo((Double)objectArr2[x]);
+ } else { // default uses String comparison
+ result = objectArr1[x].toString().compareTo(objectArr2[x].toString());
+ }
+ if( result != EQUAL) {
+ return result;
+ }
+ }
+ return result;
+ }
+ });
+ for ( final Object[] row : underlyingData )
+ writeRow(out, row);
+ break;
+ case SORT_BY_ROW:
+ // make sure that there are exactly the correct number of ID mappings
+ if ( rowIdToIndex.size() != underlyingData.size() )
+ throw new ReviewedGATKException("There isn't a 1-to-1 mapping from row ID to index; this can happen when rows are not created consistently");
+
+ final TreeMap<Object, Integer> sortedMap;
+ try {
+ sortedMap = new TreeMap<Object, Integer>(rowIdToIndex);
+ } catch (ClassCastException e) {
+ throw new ReviewedGATKException("Unable to sort the rows based on the row IDs because the ID Objects are of different types");
+ }
+ for ( final Map.Entry<Object, Integer> rowKey : sortedMap.entrySet() )
+ writeRow(out, underlyingData.get(rowKey.getValue()));
+ break;
+ case DO_NOT_SORT:
+ for ( final Object[] row : underlyingData )
+ writeRow(out, row);
+ }
+ out.println();
+ }
+
+ private void writeRow(final PrintStream out, final Object[] row) {
+ boolean needsPadding = false;
+ for ( int i = 0; i < row.length; i++ ) {
+ if ( needsPadding )
+ out.printf(" ");
+ needsPadding = true;
+
+ final Object obj = row[i];
+ final String value;
+
+ final GATKReportColumn info = columnInfo.get(i);
+
+ if ( obj == null )
+ value = "null";
+ else if ( info.getDataType().equals(GATKReportDataType.Unknown) && (obj instanceof Double || obj instanceof Float) )
+ value = String.format("%.8f", obj);
+ else
+ value = String.format(info.getFormat(), obj);
+
+ out.printf(info.getColumnFormat().getValueFormat(), value);
+ }
+
+ out.println();
+ }
+
+ public int getNumRows() {
+ return underlyingData.size();
+ }
+
+ public int getNumColumns() {
+ return columnInfo.size();
+ }
+
+ public List<GATKReportColumn> getColumnInfo() {
+ return columnInfo;
+ }
+
+ public String getTableName() {
+ return tableName;
+ }
+
+ public String getTableDescription() {
+ return tableDescription;
+ }
+
+ /**
+ * Concatenates the rows from the table to this one
+ *
+ * @param table another GATK table
+ */
+ public void concat(final GATKReportTable table) {
+ if ( !isSameFormat(table) )
+ throw new ReviewedGATKException("Error trying to concatenate tables with different formats");
+
+ // add the data
+ underlyingData.addAll(table.underlyingData);
+
+ // update the row index map
+ final int currentNumRows = getNumRows();
+ for ( Map.Entry<Object, Integer> entry : table.rowIdToIndex.entrySet() )
+ rowIdToIndex.put(entry.getKey(), entry.getValue() + currentNumRows);
+ }
+
+ /**
+ * Returns whether or not the two tables have the same format including columns and everything in between. This does
+ * not check if the data inside is the same. This is the check to see if the two tables are gatherable or
+ * reduceable
+ *
+ * @param table another GATK table
+ * @return true if the the tables are gatherable
+ */
+ public boolean isSameFormat(final GATKReportTable table) {
+ if ( !tableName.equals(table.tableName) ||
+ !tableDescription.equals(table.tableDescription) ||
+ columnInfo.size() != table.columnInfo.size() )
+ return false;
+
+ for ( int i = 0; i < columnInfo.size(); i++ ) {
+ if ( !columnInfo.get(i).getFormat().equals(table.columnInfo.get(i).getFormat()) ||
+ !columnInfo.get(i).getColumnName().equals(table.columnInfo.get(i).getColumnName()) )
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks that the tables are exactly the same.
+ *
+ * @param table another GATK report
+ * @return true if all field in the reports, tables, and columns are equal.
+ */
+ public boolean equals(final GATKReportTable table) {
+ if ( !isSameFormat(table) ||
+ underlyingData.size() != table.underlyingData.size() )
+ return false;
+
+ final List<Object[]> myOrderedRows = getOrderedRows();
+ final List<Object[]> otherOrderedRows = table.getOrderedRows();
+
+ for ( int i = 0; i < underlyingData.size(); i++ ) {
+ final Object[] myData = myOrderedRows.get(i);
+ final Object[] otherData = otherOrderedRows.get(i);
+ for ( int j = 0; j < myData.length; j++ ) {
+ if ( !myData[j].toString().equals(otherData[j].toString()) ) // need to deal with different typing (e.g. Long vs. Integer)
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private List<Object[]> getOrderedRows() {
+
+ switch (sortingWay) {
+ case SORT_BY_COLUMN:
+ Collections.sort(underlyingData, new Comparator<Object[]>() {
+ //INVARIANT the two arrays are of the same length and corresponding elements are of the same type
+ @Override
+ public int compare(Object[] objectArr1, Object[] objectArr2) {
+ final int EQUAL = 0;
+ int result = EQUAL;
+ int l = objectArr1.length;
+ for (int x = 0; x < l; x++) {
+ if (objectArr1[x] instanceof Integer) {
+ result = ((Integer)objectArr1[x]).compareTo((Integer)objectArr2[x]);
+ } else if (objectArr1[x] instanceof Double) {
+ result = ((Double)objectArr1[x]).compareTo((Double)objectArr2[x]);
+ } else { // default uses String comparison
+ result = objectArr1[x].toString().compareTo(objectArr2[x].toString());
+ }
+ if( result != EQUAL) {
+ return result;
+ }
+ }
+ return result;
+ }
+ });
+ return underlyingData;
+ case SORT_BY_ROW:
+ final TreeMap<Object, Integer> sortedMap;
+ try {
+ sortedMap = new TreeMap<Object, Integer>(rowIdToIndex);
+ } catch (ClassCastException e) {
+ return underlyingData;
+ }
+
+ final List<Object[]> orderedData = new ArrayList<Object[]>(underlyingData.size());
+ for ( final int rowKey : sortedMap.values() )
+ orderedData.add(underlyingData.get(rowKey));
+
+ return orderedData;
+ default:
+ return underlyingData;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportVersion.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportVersion.java
new file mode 100644
index 0000000..226365b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/report/GATKReportVersion.java
@@ -0,0 +1,101 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.report;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+public enum GATKReportVersion {
+ /**
+ * Differences between other versions:
+ * - Does not allow spaces in cells.
+ * - Mostly fixed width but has a bug where the string width of floating point
+ * values was not measured correctly leading to columns that aren't aligned
+ */
+ V0_1("v0.1"),
+
+ /**
+ * Differences between other versions:
+ * - Spaces allowed in cells, for example in sample names with spaces in them ex: "C507/FG-CR 6".
+ * - Fixed width fixed for floating point values
+ */
+ V0_2("v0.2"),
+
+ /*
+ * Differences between v0.x
+ * - Added table and report headers
+ * - Headers changed format, include the number of tables, rows, and metadata for gathering
+ * - IS GATHERABLE
+ */
+ V1_0("v1.0"),
+
+ /*
+ * Differences between v1.0
+ * - column numbers in header reflect the actual count of columns
+ * - primary keys are never displayed
+ */
+ V1_1("v1.1");
+
+ private final String versionString;
+
+ private GATKReportVersion(String versionString) {
+ this.versionString = versionString;
+ }
+
+ @Override
+ public String toString() {
+ return versionString;
+ }
+
+ public boolean equals(GATKReportVersion that) {
+ return (versionString.equals(that.versionString));
+ }
+
+ /**
+ * Returns the GATK Report Version from the file header.
+ *
+ * @param header Header from the file starting with ##:GATKReport.v[version]
+ * @return The version as an enum.
+ */
+ public static GATKReportVersion fromHeader(String header) {
+ if ( header == null )
+ throw new UserException.BadInput("The GATK report has no version specified in the header");
+
+ if (header.startsWith("##:GATKReport.v0.1 "))
+ return GATKReportVersion.V0_1;
+
+ if (header.startsWith("##:GATKReport.v0.2 "))
+ return GATKReportVersion.V0_2;
+
+ if (header.startsWith("#:GATKReport.v1.0"))
+ return GATKReportVersion.V1_0;
+
+ if (header.startsWith("#:GATKReport.v1.1"))
+ return GATKReportVersion.V1_1;
+
+ throw new UserException.BadInput("The GATK report has an unknown/unsupported version in the header: " + header);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/resourcemanagement/ThreadAllocation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/resourcemanagement/ThreadAllocation.java
new file mode 100644
index 0000000..0344135
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/resourcemanagement/ThreadAllocation.java
@@ -0,0 +1,116 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.resourcemanagement;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+/**
+ * Models how threads are distributed between various components of the GATK.
+ */
+public class ThreadAllocation {
+ /**
+ * The number of CPU threads to be used by the GATK.
+ */
+ private final int numDataThreads;
+
+ /**
+ * The number of CPU threads per data thread for GATK processing
+ */
+ private final int numCPUThreadsPerDataThread;
+
+ /**
+ * Number of threads to devote exclusively to IO. Default is 0.
+ */
+ private final int numIOThreads;
+
+ /**
+ * Should we monitor thread efficiency?
+ */
+ private final boolean monitorEfficiency;
+
+ public int getNumDataThreads() {
+ return numDataThreads;
+ }
+
+ public int getNumCPUThreadsPerDataThread() {
+ return numCPUThreadsPerDataThread;
+ }
+
+ public int getNumIOThreads() {
+ return numIOThreads;
+ }
+
+ public boolean monitorThreadEfficiency() {
+ return monitorEfficiency;
+ }
+
+ /**
+ * Are we running in parallel mode?
+ *
+ * @return true if any parallel processing is enabled
+ */
+ public boolean isRunningInParallelMode() {
+ return getTotalNumThreads() > 1;
+ }
+
+ /**
+ * What is the total number of threads in use by the GATK?
+ *
+ * @return the sum of all thread allocations in this object
+ */
+ public int getTotalNumThreads() {
+ return getNumDataThreads() * getNumCPUThreadsPerDataThread() + getNumIOThreads();
+ }
+
+ /**
+ * Construct the default thread allocation.
+ */
+ public ThreadAllocation() {
+ this(1, 1, 0, false);
+ }
+
+ /**
+ * Set up the thread allocation. Default allocation is 1 CPU thread, 0 IO threads.
+ * (0 IO threads means that no threads are devoted exclusively to IO; they're inline on the CPU thread).
+ * @param numDataThreads Total number of threads allocated to the traversal.
+ * @param numCPUThreadsPerDataThread The number of CPU threads per data thread to allocate
+ * @param numIOThreads Total number of threads allocated exclusively to IO.
+ * @param monitorEfficiency should we monitor threading efficiency in the GATK?
+ */
+ public ThreadAllocation(final int numDataThreads,
+ final int numCPUThreadsPerDataThread,
+ final int numIOThreads,
+ final boolean monitorEfficiency) {
+ if ( numDataThreads < 1 ) throw new ReviewedGATKException("numDataThreads cannot be less than 1, but saw " + numDataThreads);
+ if ( numCPUThreadsPerDataThread < 1 ) throw new ReviewedGATKException("numCPUThreadsPerDataThread cannot be less than 1, but saw " + numCPUThreadsPerDataThread);
+ if ( numIOThreads < 0 ) throw new ReviewedGATKException("numIOThreads cannot be less than 0, but saw " + numIOThreads);
+
+ this.numDataThreads = numDataThreads;
+ this.numCPUThreadsPerDataThread = numCPUThreadsPerDataThread;
+ this.numIOThreads = numIOThreads;
+ this.monitorEfficiency = monitorEfficiency;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Affection.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Affection.java
new file mode 100644
index 0000000..0e5833b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Affection.java
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.samples;
+
+/**
+ * Categorical sample trait for association and analysis
+ *
+ * Samples can have unknown status, be affected or unaffected by the
+ * categorical trait, or they can be marked as actually having an
+ * other trait value (stored in an associated value in the Sample class)
+ *
+ * @author Mark DePristo
+ * @since Sept. 2011
+ */
+public enum Affection {
+ /** Status is unknown */
+ UNKNOWN,
+ /** Suffers from the disease */
+ AFFECTED,
+ /** Unaffected by the disease */
+ UNAFFECTED,
+ /** An "other" trait: value of the trait is stored elsewhere and is an arbitrary string */
+ OTHER
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Gender.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Gender.java
new file mode 100644
index 0000000..0f26bc6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Gender.java
@@ -0,0 +1,35 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.samples;
+
+/**
+* ENUM of possible human genders: male, female, or unknown
+*/
+public enum Gender {
+ MALE,
+ FEMALE,
+ UNKNOWN
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/PedReader.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/PedReader.java
new file mode 100644
index 0000000..8946d28
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/PedReader.java
@@ -0,0 +1,311 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.samples;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Reads PED file-formatted tabular text files
+ *
+ * See http://www.broadinstitute.org/mpg/tagger/faq.html
+ * See http://pngu.mgh.harvard.edu/~purcell/plink/data.shtml#ped
+ *
+ * The "ped" file format refers to the widely-used format for linkage pedigree data.
+ * Each line describes a single (diploid) individual in the following format:
+ *
+ * family_ID individual_ID father_ID mother_ID gender phenotype genotype_1 genotype_2 ...
+ *
+ * If your data lacks pedigree information (for example, unrelated case/control individuals),
+ * set the father_ID and mother_ID to 0. sex denotes the individual's gender with 1=male and 2=female.
+ * phenotype refers to the affected status (for association studies) where 0=unknown, 1=unaffected, 2=affected.
+ * Finally, each genotype is written as two (=diploid) integer numbers (separated by whitespace),
+ * where 1=A, 2=C, 3=G, 4=T. No header lines are allowed and all columns must be separated by whitespace.
+ * Check out the information at the PLINK website on the "ped" file format.
+ *
+ * The PED file is a white-space (space or tab) delimited file: the first six columns are mandatory:
+ * Family ID
+ * Individual ID
+ * Paternal ID
+ * Maternal ID
+ * Sex (1=male; 2=female; other=unknown)
+ * Phenotype
+ *
+ * The IDs are alphanumeric: the combination of family and individual ID should uniquely identify a person.
+ * A PED file must have 1 and only 1 phenotype in the sixth column. The phenotype can be either a
+ * quantitative trait or an affection status column: PLINK will automatically detect which type
+ * (i.e. based on whether a value other than 0, 1, 2 or the missing genotype code is observed).
+ * Note that the GATK actually supports arbitrary values for quantitative trait -- not just doubles --
+ * and are actually representing these values as strings instead of doubles
+ *
+ * NOTE Quantitative traits with decimal points must be coded with a period/full-stop character and
+ * not a comma, i.e. 2.394 not 2,394
+ *
+ * If an individual's sex is unknown, then any character other than 1 or 2 can be used.
+ * When new files are created (PED, FAM, or other which contain sex) then the original coding will be
+ * preserved. However, these individuals will be dropped from any analyses (i.e. phenotype set to missing also)
+ * and an error message will arise if an analysis that uses family information is requested and an
+ * individual of 'unknown' sex is specified as a father or mother.
+ *
+ *
+ * HINT You can add a comment to a PED or MAP file by starting the line with a # character. The rest of that
+ * line will be ignored. Do not start any family IDs with this character therefore.
+ *
+ * Affection status, by default, should be coded:
+ * -9 missing
+ * 0 missing
+ * 1 unaffected
+ * 2 affected
+ *
+ * If your file is coded 0/1 to represent unaffected/affected, then use the --1 flag:
+ * plink --file mydata --1 which will specify a disease phenotype coded:
+ *
+ * -9 missing
+ * 0 unaffected
+ * 1 affected
+ *
+ * The missing phenotype value for quantitative traits is, by default, -9 (this can also be used for
+ * disease traits as well as 0). It can be reset by including the --missing-phenotype option:
+ *
+ * Genotypes (column 7 onwards) should also be white-space delimited; they can be any character
+ * (e.g. 1,2,3,4 or A,C,G,T or anything else) except 0 which is, by default, the missing genotype
+ * character. All markers should be biallelic. All SNPs (whether haploid or not) must have two
+ * alleles specified. Either Both alleles should be missing (i.e. 0) or neither.
+ *
+ * No header row should be given. For example, here are two individuals typed for 3 SNPs (one row = one person):
+ *
+ * FAM001 1 0 0 1 2 A A G G A C
+ * FAM001 2 0 0 1 2 A A A G 0 0
+ * ...
+ *
+ * Note that the GATK does not support genotypes in a PED file.
+ *
+ * @author Mark DePristo
+ * @since 2011
+ */
+public class PedReader {
+ private static Logger logger = Logger.getLogger(PedReader.class);
+ final static private Set<String> CATAGORICAL_TRAIT_VALUES = new HashSet<String>(Arrays.asList("-9", "0", "1", "2"));
+ final static private String commentMarker = "#";
+
+ /**
+ * An enum that specifies which, if any, of the standard PED fields are
+ * missing from the input records. For example, suppose we have the full record:
+ *
+ * "fam1 kid dad mom 1 2"
+ *
+ * indicating a male affected child. This can be parsed with the -ped x.ped argument
+ * to the GATK. Suppose we only have:
+ *
+ * "fam1 kid 1"
+ *
+ * we can parse the reduced version of this record with -ped:NO_PARENTS,NO_PHENOTYPE x.ped
+ */
+ public enum MissingPedField {
+ /**
+ * The PED records do not have the first (FAMILY_ID) argument. The family id
+ * will be set to null / empty.
+ */
+ NO_FAMILY_ID,
+
+ /**
+ * The PED records do not have either the paternal or maternal IDs, so
+ * the corresponding IDs are set to null.
+ */
+ NO_PARENTS,
+
+ /**
+ * The PED records do not have the GENDER field, so the sex of each
+ * sample will be set to UNKNOWN.
+ */
+ NO_SEX,
+
+ /**
+ * The PED records do not have the PHENOTYPE field, so the phenotype
+ * of each sample will be set to UNKNOWN.
+ */
+ NO_PHENOTYPE
+ }
+
+ protected enum Field {
+ FAMILY_ID, INDIVIDUAL_ID, PATERNAL_ID, MATERNAL_ID, GENDER, PHENOTYPE
+ }
+
+ // phenotype
+ private final static String MISSING_VALUE1 = "-9";
+ private final static String MISSING_VALUE2 = "0";
+ private final static String PHENOTYPE_UNAFFECTED = "1";
+ private final static String PHENOTYPE_AFFECTED = "2";
+
+ // Sex
+ private final static String SEX_MALE = "1";
+ private final static String SEX_FEMALE = "2";
+ // other=unknown
+
+ public PedReader() { }
+
+ public final List<Sample> parse(File source, EnumSet<MissingPedField> missingFields, SampleDB sampleDB) throws FileNotFoundException {
+ logger.info("Reading PED file " + source + " with missing fields: " + missingFields);
+ return parse(new FileReader(source), missingFields, sampleDB);
+ }
+
+ public final List<Sample> parse(final String source, EnumSet<MissingPedField> missingFields, SampleDB sampleDB) {
+ logger.warn("Reading PED string: \"" + source + "\" with missing fields: " + missingFields);
+ return parse(new StringReader(source.replace(";", String.format("%n"))), missingFields, sampleDB);
+ }
+
+ public final List<Sample> parse(Reader reader, EnumSet<MissingPedField> missingFields, SampleDB sampleDB) {
+ final List<String> lines = new XReadLines(reader).readLines();
+
+ // What are the record offsets?
+ final int familyPos = missingFields.contains(MissingPedField.NO_FAMILY_ID) ? -1 : 0;
+ final int samplePos = familyPos + 1;
+ final int paternalPos = missingFields.contains(MissingPedField.NO_PARENTS) ? -1 : samplePos + 1;
+ final int maternalPos = missingFields.contains(MissingPedField.NO_PARENTS) ? -1 : paternalPos + 1;
+ final int sexPos = missingFields.contains(MissingPedField.NO_SEX) ? -1 : Math.max(maternalPos, samplePos) + 1;
+ final int phenotypePos = missingFields.contains(MissingPedField.NO_PHENOTYPE) ? -1 : Math.max(sexPos, Math.max(maternalPos, samplePos)) + 1;
+ final int nExpectedFields = MathUtils.arrayMaxInt(Arrays.asList(samplePos, paternalPos, maternalPos, sexPos, phenotypePos)) + 1;
+
+ // go through once and determine properties
+ int lineNo = 1;
+ boolean isQT = false;
+ final List<String[]> splits = new ArrayList<String[]>(lines.size());
+ for ( final String line : lines ) {
+ if ( line.startsWith(commentMarker)) continue;
+ if ( line.trim().equals("") ) continue;
+
+ final String[] parts = line.split("\\s+");
+
+ if ( parts.length != nExpectedFields )
+ throw new UserException.MalformedFile(reader.toString(), "Bad PED line " + lineNo + ": wrong number of fields");
+
+ if ( phenotypePos != -1 ) {
+ isQT = isQT || ! CATAGORICAL_TRAIT_VALUES.contains(parts[phenotypePos]);
+ }
+
+ splits.add(parts);
+ lineNo++;
+ }
+ logger.info("Phenotype is other? " + isQT);
+
+ // now go through and parse each record
+ lineNo = 1;
+ final List<Sample> samples = new ArrayList<Sample>(splits.size());
+ for ( final String[] parts : splits ) {
+ String familyID = null, individualID, paternalID = null, maternalID = null;
+ Gender sex = Gender.UNKNOWN;
+ String quantitativePhenotype = Sample.UNSET_QT;
+ Affection affection = Affection.UNKNOWN;
+
+ if ( familyPos != -1 ) familyID = maybeMissing(parts[familyPos]);
+ individualID = parts[samplePos];
+ if ( paternalPos != -1 ) paternalID = maybeMissing(parts[paternalPos]);
+ if ( maternalPos != -1 ) maternalID = maybeMissing(parts[maternalPos]);
+
+ if ( sexPos != -1 ) {
+ if ( parts[sexPos].equals(SEX_MALE) ) sex = Gender.MALE;
+ else if ( parts[sexPos].equals(SEX_FEMALE) ) sex = Gender.FEMALE;
+ else sex = Gender.UNKNOWN;
+ }
+
+ if ( phenotypePos != -1 ) {
+ if ( isQT ) {
+ if ( parts[phenotypePos].equals(MISSING_VALUE1) )
+ affection = Affection.UNKNOWN;
+ else {
+ affection = Affection.OTHER;
+ quantitativePhenotype = parts[phenotypePos];
+ }
+ } else {
+ if ( parts[phenotypePos].equals(MISSING_VALUE1) ) affection = Affection.UNKNOWN;
+ else if ( parts[phenotypePos].equals(MISSING_VALUE2) ) affection = Affection.UNKNOWN;
+ else if ( parts[phenotypePos].equals(PHENOTYPE_UNAFFECTED) ) affection = Affection.UNAFFECTED;
+ else if ( parts[phenotypePos].equals(PHENOTYPE_AFFECTED) ) affection = Affection.AFFECTED;
+ else throw new ReviewedGATKException("Unexpected phenotype type " + parts[phenotypePos] + " at line " + lineNo);
+ }
+ }
+
+ final Sample s = new Sample(individualID, sampleDB, familyID, paternalID, maternalID, sex, affection, quantitativePhenotype);
+ samples.add(s);
+ sampleDB.addSample(s);
+ lineNo++;
+ }
+
+ for ( final Sample sample : new ArrayList<Sample>(samples) ) {
+ Sample dad = maybeAddImplicitSample(sampleDB, sample.getPaternalID(), sample.getFamilyID(), Gender.MALE);
+ if ( dad != null ) samples.add(dad);
+
+ Sample mom = maybeAddImplicitSample(sampleDB, sample.getMaternalID(), sample.getFamilyID(), Gender.FEMALE);
+ if ( mom != null ) samples.add(mom);
+ }
+
+ return samples;
+ }
+
+ private final static String maybeMissing(final String string) {
+ if ( string.equals(MISSING_VALUE1) || string.equals(MISSING_VALUE2) )
+ return null;
+ else
+ return string;
+ }
+
+ private final Sample maybeAddImplicitSample(SampleDB sampleDB, final String id, final String familyID, final Gender gender) {
+ if ( id != null && sampleDB.getSample(id) == null ) {
+ Sample s = new Sample(id, sampleDB, familyID, null, null, gender, Affection.UNKNOWN, Sample.UNSET_QT);
+ sampleDB.addSample(s);
+ return s;
+ } else
+ return null;
+ }
+
+ /**
+ * Parses a list of tags from the command line, assuming it comes from the GATK Engine
+ * tags, and returns the corresponding EnumSet.
+ *
+ * @param arg the actual engine arg, used for the UserException if there's an error
+ * @param tags a list of string tags that should be converted to the MissingPedField value
+ * @return
+ */
+ public static final EnumSet<MissingPedField> parseMissingFieldTags(final Object arg, final List<String> tags) {
+ final EnumSet<MissingPedField> missingFields = EnumSet.noneOf(MissingPedField.class);
+
+ for ( final String tag : tags ) {
+ try {
+ missingFields.add(MissingPedField.valueOf(tag));
+ } catch ( IllegalArgumentException e ) {
+ throw new UserException.BadArgumentValue(arg.toString(), "Unknown tag " + tag + " allowed values are " + MissingPedField.values());
+ }
+ }
+
+ return missingFields;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/PedigreeValidationType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/PedigreeValidationType.java
new file mode 100644
index 0000000..14fefd2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/PedigreeValidationType.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.samples;
+
+/**
+*
+*/
+public enum PedigreeValidationType {
+ /**
+ * Require if a pedigree file is provided at all samples in the VCF or BAM files have a corresponding
+ * entry in the pedigree file(s).
+ */
+ STRICT,
+
+ /**
+ * Do not enforce any overlap between the VCF/BAM samples and the pedigree data
+ * */
+ SILENT
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Sample.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Sample.java
new file mode 100644
index 0000000..0d60c39
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Sample.java
@@ -0,0 +1,259 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.samples;
+
+
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ */
+public class Sample implements Comparable<Sample> { // implements java.io.Serializable {
+ final private String familyID, paternalID, maternalID;
+ final private Gender gender;
+ final private String otherPhenotype;
+ final private Affection affection;
+ final private String ID;
+ final private SampleDB infoDB;
+ final private Map<String, Object> properties = new HashMap<String, Object>();
+
+ public final static String UNSET_QT = null;
+
+ public Sample(final String ID, final SampleDB infoDB,
+ final String familyID, final String paternalID, final String maternalID,
+ final Gender gender, final Affection affection, final String otherPhenotype) {
+ this.familyID = familyID;
+ this.paternalID = paternalID;
+ this.maternalID = maternalID;
+ this.gender = gender;
+ this.otherPhenotype = otherPhenotype;
+ this.affection = affection;
+ this.ID = ID;
+ this.infoDB = infoDB;
+ }
+
+ protected Sample(final String ID,
+ final String familyID, final String paternalID, final String maternalID,
+ final Gender gender, final Affection affection, final String otherPhenotype) {
+ this(ID, null, familyID, paternalID, maternalID, gender, affection, otherPhenotype);
+ }
+
+ protected Sample(final String ID,
+ final String familyID, final String paternalID, final String maternalID,
+ final Gender gender, final Affection affection) {
+ this(ID, null, familyID, paternalID, maternalID, gender, affection, UNSET_QT);
+ }
+
+
+ public Sample(final String ID, final SampleDB infoDB,
+ final String familyID, final String paternalID, final String maternalID, final Gender gender) {
+ this(ID, infoDB, familyID, paternalID, maternalID, gender, Affection.UNKNOWN, UNSET_QT);
+ }
+
+ public Sample(final String ID, final SampleDB infoDB, final Affection affection, final String otherPhenotype) {
+ this(ID, infoDB, null, null, null, Gender.UNKNOWN, affection, otherPhenotype);
+ }
+
+ public Sample(String id, SampleDB infoDB) {
+ this(id, infoDB, null, null, null,
+ Gender.UNKNOWN, Affection.UNKNOWN, UNSET_QT);
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // standard property getters
+ //
+ // -------------------------------------------------------------------------------------
+
+ public String getID() {
+ return ID;
+ }
+
+ public String getFamilyID() {
+ return familyID;
+ }
+
+ public String getPaternalID() {
+ return paternalID;
+ }
+
+ public String getMaternalID() {
+ return maternalID;
+ }
+
+ public Affection getAffection() {
+ return affection;
+ }
+
+ public boolean hasOtherPhenotype() {
+ return affection == Affection.OTHER;
+ }
+
+ public String getOtherPhenotype() {
+ return otherPhenotype;
+ }
+
+ /**
+ * Get the sample's mother
+ * @return sample object with relationship mother, if exists, or null
+ */
+ public Sample getMother() {
+ return infoDB.getSample(maternalID);
+ }
+
+ /**
+ * Get the sample's father
+ * @return sample object with relationship father, if exists, or null
+ */
+ public Sample getFather() {
+ return infoDB.getSample(paternalID);
+ }
+
+ public ArrayList<Sample> getParents(){
+ ArrayList<Sample> parents = new ArrayList<Sample>(2);
+ Sample parent = getMother();
+ if(parent != null)
+ parents.add(parent);
+ parent = getFather();
+ if(parent != null)
+ parents.add(parent);
+ return parents;
+ }
+
+ /**
+ * Get gender of the sample
+ * @return property of key "gender" - must be of type Gender
+ */
+ public Gender getGender() {
+ return gender;
+ }
+
+ @Override
+ public int compareTo(final Sample sample) {
+ return ID.compareTo(sample.getID());
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Sample %s fam=%s dad=%s mom=%s gender=%s affection=%s qt=%s props=%s",
+ getID(), getFamilyID(), getPaternalID(), getMaternalID(), getGender(), getAffection(),
+ getOtherPhenotype(), properties);
+ }
+
+// // -------------------------------------------------------------------------------------
+// //
+// // code for working with additional -- none standard -- properites
+// //
+// // -------------------------------------------------------------------------------------
+//
+// public Map<String, Object> getExtraProperties() {
+// return Collections.unmodifiableMap(properties);
+// }
+//
+// /**
+// * Get one property
+// * @param key key of property
+// * @return value of property as generic object
+// */
+// public Object getExtraPropertyValue(final String key) {
+// return properties.get(key);
+// }
+//
+// /**
+// *
+// * @param key property key
+// * @return true if sample has this property (even if its value is null)
+// */
+// public boolean hasExtraProperty(String key) {
+// return properties.containsKey(key);
+// }
+
+ @Override
+ public int hashCode() {
+ return ID.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if(o == null)
+ return false;
+ if(o instanceof Sample) {
+ Sample otherSample = (Sample)o;
+ return ID.equals(otherSample.ID) &&
+ equalOrNull(familyID, otherSample.familyID) &&
+ equalOrNull(paternalID, otherSample.paternalID) &&
+ equalOrNull(maternalID, otherSample.maternalID) &&
+ equalOrNull(gender, otherSample.gender) &&
+ equalOrNull(otherPhenotype, otherSample.otherPhenotype) &&
+ equalOrNull(affection, otherSample.affection) &&
+ equalOrNull(properties, otherSample.properties);
+ }
+ return false;
+ }
+
+ private final static boolean equalOrNull(final Object o1, final Object o2) {
+ if ( o1 == null )
+ return o2 == null;
+ else
+ return o2 == null ? false : o1.equals(o2);
+ }
+
+ private final static <T> T mergeValues(final String name, final String field, final T o1, final T o2, final T emptyValue) {
+ if ( o1 == null || o1.equals(emptyValue) ) {
+ // take o2 if both are null, otherwise keep o2
+ return o2 == null ? null : o2;
+ } else {
+ if ( o2 == null || o2.equals(emptyValue) )
+ return o1; // keep o1, since it's a real value
+ else {
+ // both o1 and o2 have a value
+ if ( o1 == o2 )
+ return o1;
+ else
+ throw new UserException("Inconsistent values detected for " + name + " for field " + field + " value1 " + o1 + " value2 " + o2);
+ }
+ }
+ }
+
+ public final static Sample mergeSamples(final Sample prev, final Sample next) {
+ if ( prev.equals(next) )
+ return next;
+ else {
+ return new Sample(prev.getID(), prev.infoDB,
+ mergeValues(prev.getID(), "Family_ID", prev.getFamilyID(), next.getFamilyID(), null),
+ mergeValues(prev.getID(), "Paternal_ID", prev.getPaternalID(), next.getPaternalID(), null),
+ mergeValues(prev.getID(), "Material_ID", prev.getMaternalID(), next.getMaternalID(), null),
+ mergeValues(prev.getID(), "Gender", prev.getGender(), next.getGender(), Gender.UNKNOWN),
+ mergeValues(prev.getID(), "Affection", prev.getAffection(), next.getAffection(), Affection.UNKNOWN),
+ mergeValues(prev.getID(), "OtherPhenotype", prev.getOtherPhenotype(), next.getOtherPhenotype(), UNSET_QT));
+ //mergeValues(prev.getID(), "ExtraProperties", prev.getExtraProperties(), next.getExtraProperties(), Collections.emptyMap()));
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/SampleDB.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/SampleDB.java
new file mode 100644
index 0000000..141f01b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/SampleDB.java
@@ -0,0 +1,338 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.samples;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import htsjdk.variant.variantcontext.Genotype;
+
+import java.util.*;
+
+/**
+ *
+ */
+public class SampleDB {
+ /**
+ * This is where Sample objects are stored. Samples are usually accessed by their ID, which is unique, so
+ * this is stored as a HashMap.
+ */
+ private final HashMap<String, Sample> samples = new HashMap<String, Sample>();
+
+ /**
+ * Constructor takes both a SAM header and sample files because the two must be integrated.
+ */
+ public SampleDB() {
+
+ }
+
+ /**
+ * Protected function to add a single sample to the database
+ *
+ * @param sample to be added
+ */
+ protected SampleDB addSample(Sample sample) {
+ Sample prev = samples.get(sample.getID());
+ if ( prev != null )
+ sample = Sample.mergeSamples(prev, sample);
+ samples.put(sample.getID(), sample);
+ return this;
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Functions for getting a sample from the DB
+ //
+ // --------------------------------------------------------------------------------
+
+ /**
+ * Get a sample by its ID
+ * If an alias is passed in, return the main sample object
+ * @param id
+ * @return sample Object with this ID, or null if this does not exist
+ */
+ public Sample getSample(String id) {
+ return samples.get(id);
+ }
+
+ /**
+ *
+ * @param read
+ * @return sample Object with this ID, or null if this does not exist
+ */
+ public Sample getSample(final SAMRecord read) {
+ return getSample(read.getReadGroup());
+ }
+
+ /**
+ *
+ * @param rg
+ * @return sample Object with this ID, or null if this does not exist
+ */
+ public Sample getSample(final SAMReadGroupRecord rg) {
+ return getSample(rg.getSample());
+ }
+
+ /**
+ * @param g Genotype
+ * @return sample Object with this ID, or null if this does not exist
+ */
+ public Sample getSample(final Genotype g) {
+ return getSample(g.getSampleName());
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Functions for accessing samples in the DB
+ //
+ // --------------------------------------------------------------------------------
+
+ /**
+ * Get number of sample objects
+ * @return size of samples map
+ */
+ public int sampleCount() {
+ return samples.size();
+ }
+
+ public Set<Sample> getSamples() {
+ return new LinkedHashSet<>(samples.values());
+ }
+
+ public Collection<String> getSampleNames() {
+ return Collections.unmodifiableCollection(samples.keySet());
+ }
+
+
+ /**
+ * Takes a collection of sample names and returns their corresponding sample objects
+ * Note that, since a set is returned, if you pass in a list with duplicates names there will not be any duplicates in the returned set
+ * @param sampleNameList Set of sample names
+ * @return Corresponding set of samples
+ */
+ public Set<Sample> getSamples(Collection<String> sampleNameList) {
+ HashSet<Sample> samples = new HashSet<Sample>();
+ for (String name : sampleNameList) {
+ try {
+ samples.add(getSample(name));
+ }
+ catch (Exception e) {
+ throw new GATKException("Could not get sample with the following ID: " + name, e);
+ }
+ }
+ return samples;
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Higher level pedigree functions
+ //
+ // --------------------------------------------------------------------------------
+
+ /**
+ * Returns a sorted set of the family IDs in all samples (excluding null ids)
+ * @return
+ */
+ public final Set<String> getFamilyIDs() {
+ return getFamilies().keySet();
+ }
+
+ /**
+ * Returns a map from family ID -> set of family members for all samples with
+ * non-null family ids
+ *
+ * @return
+ */
+ public final Map<String, Set<Sample>> getFamilies() {
+ return getFamilies(null);
+ }
+
+ /**
+ * Returns a map from family ID -> set of family members for all samples in sampleIds with
+ * non-null family ids
+ *
+ * @param sampleIds - all samples to include. If null is passed then all samples are returned.
+ * @return
+ */
+ public final Map<String, Set<Sample>> getFamilies(Collection<String> sampleIds) {
+ final Map<String, Set<Sample>> families = new TreeMap<String, Set<Sample>>();
+
+ for ( final Sample sample : samples.values() ) {
+ if(sampleIds == null || sampleIds.contains(sample.getID())){
+ final String famID = sample.getFamilyID();
+ if ( famID != null ) {
+ if ( ! families.containsKey(famID) )
+ families.put(famID, new TreeSet<Sample>());
+ families.get(famID).add(sample);
+ }
+ }
+ }
+ return families;
+ }
+
+ /**
+ * Returns all the trios present in the sample database. The strictOneChild parameter determines
+ * whether multiple children of the same parents resolve to multiple trios, or are excluded
+ * @param strictOneChild - exclude pedigrees with >1 child for parental pair
+ * @return - all of the mother+father=child triplets, subject to strictOneChild
+ */
+ public final Set<Trio> getTrios(boolean strictOneChild) {
+ Set<Trio> trioSet = new HashSet<Trio>();
+ for ( String familyString : getFamilyIDs() ) {
+ Set<Sample> family = getFamily(familyString);
+ for ( Sample sample : family) {
+ if ( sample.getParents().size() == 2 ) {
+ Trio trio = new Trio(sample.getMother(),sample.getFather(),sample);
+ trioSet.add(trio);
+ }
+ }
+ }
+
+ if ( strictOneChild )
+ trioSet = removeTriosWithSameParents(trioSet);
+
+ return trioSet;
+ }
+
+ /**
+ * Returns all the trios present in the db. See getTrios(boolean strictOneChild)
+ * @return all the trios present in the samples db.
+ */
+ public final Set<Trio> getTrios() {
+ return getTrios(false);
+ }
+
+ /**
+ * Subsets a set of trios to only those with nonmatching founders. If two (or more) trio objects have
+ * the same mother and father, then both (all) are removed from the returned set.
+ * @param trios - a set of Trio objects
+ * @return those subset of Trio objects in the input set with nonmatching founders
+ */
+ private Set<Trio> removeTriosWithSameParents(final Set<Trio> trios) {
+ Set<Trio> filteredTrios = new HashSet<Trio>();
+ filteredTrios.addAll(trios);
+ Set<Trio> triosWithSameParents = new HashSet<Trio>();
+ for ( Trio referenceTrio : filteredTrios ) {
+ for ( Trio compareTrio : filteredTrios ) {
+ if ( referenceTrio != compareTrio &&
+ referenceTrio.getFather().equals(compareTrio.getFather()) &&
+ referenceTrio.getMother().equals(compareTrio.getMother()) ) {
+ triosWithSameParents.add(referenceTrio);
+ triosWithSameParents.add(compareTrio);
+ }
+ }
+ }
+ filteredTrios.removeAll(triosWithSameParents);
+ return filteredTrios;
+ }
+
+ /**
+ * Returns the set of all children that have both of their parents.
+ * Note that if a family is composed of more than 1 child, each child is
+ * returned.
+ * @return - all the children that have both of their parents
+ * @deprecated - getTrios() replaces this function
+ */
+ @Deprecated
+ public final Set<Sample> getChildrenWithParents(){
+ return getChildrenWithParents(false);
+ }
+
+ /**
+ * Returns the set of all children that have both of their parents.
+ * Note that if triosOnly = false, a family is composed of more than 1 child, each child is
+ * returned.
+ *
+ * This method can be used wherever trios are needed
+ *
+ * @param triosOnly - if set to true, only strict trios are returned
+ * @return - all the children that have both of their parents
+ * @deprecated - getTrios(boolean strict) replaces this function
+ * @bug -- does not work for extracting multiple generations of trios, e.g.
+ * ..........Mom1------Dad1
+ * ................|
+ * ..............Child1--------Mom2
+ * .......................|
+ * .....................Child2
+ */
+ @Deprecated
+ public final Set<Sample> getChildrenWithParents(boolean triosOnly) {
+
+ Map<String, Set<Sample>> families = getFamilies();
+ final Set<Sample> childrenWithParents = new HashSet<Sample>();
+ Iterator<Sample> sampleIterator;
+
+ for ( Set<Sample> familyMembers: families.values() ) {
+ if(triosOnly && familyMembers.size() != 3)
+ continue;
+
+ sampleIterator = familyMembers.iterator();
+ Sample sample;
+ while(sampleIterator.hasNext()){
+ sample = sampleIterator.next();
+ if(sample.getParents().size() == 2 && familyMembers.containsAll(sample.getParents()))
+ childrenWithParents.add(sample);
+ }
+
+ }
+ return childrenWithParents;
+ }
+
+ /**
+ * Return all samples with a given family ID
+ * @param familyId
+ * @return
+ */
+ public Set<Sample> getFamily(String familyId) {
+ return getFamilies().get(familyId);
+ }
+
+ /**
+ * Returns all children of a given sample
+ * See note on the efficiency of getFamily() - since this depends on getFamily() it's also not efficient
+ * @param sample
+ * @return
+ */
+ public Set<Sample> getChildren(Sample sample) {
+ final HashSet<Sample> children = new HashSet<Sample>();
+ for ( final Sample familyMember : getFamily(sample.getFamilyID())) {
+ if ( familyMember.getMother() == sample || familyMember.getFather() == sample ) {
+ children.add(familyMember);
+ }
+ }
+ return children;
+ }
+
+ public Set<String> getFounderIds(){
+ Set<String> founders = new HashSet<String>();
+ for(Sample sample : getSamples()){
+ if(sample.getParents().size()<1)
+ founders.add(sample.getID());
+
+ }
+ return founders;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/SampleDBBuilder.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/SampleDBBuilder.java
new file mode 100644
index 0000000..6fdb9fa
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/SampleDBBuilder.java
@@ -0,0 +1,161 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.samples;
+
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.*;
+
+/**
+ *
+ */
+public class SampleDBBuilder {
+ PedigreeValidationType validationStrictness;
+ final SampleDB sampleDB = new SampleDB();
+ final GenomeAnalysisEngine engine;
+
+ Set<Sample> samplesFromDataSources = new HashSet<Sample>();
+ Set<Sample> samplesFromPedigrees = new HashSet<Sample>();
+
+ /** for testing only */
+ protected SampleDBBuilder(PedigreeValidationType validationStrictness) {
+ engine = null;
+ this.validationStrictness = validationStrictness;
+ }
+
+ /**
+ * Constructor takes both a SAM header and sample files because the two must be integrated.
+ */
+ public SampleDBBuilder(GenomeAnalysisEngine engine, PedigreeValidationType validationStrictness) {
+ this.engine = engine;
+ this.validationStrictness = validationStrictness;
+ }
+
+ /**
+ * Hallucinates sample objects for all the samples in the SAM file and stores them
+ */
+ public SampleDBBuilder addSamplesFromSAMHeader(final SAMFileHeader header) {
+ addSamplesFromSampleNames(SampleUtils.getSAMFileSamples(header));
+ return this;
+ }
+
+ public SampleDBBuilder addSamplesFromSampleNames(final Collection<String> sampleNames) {
+ for (final String sampleName : sampleNames) {
+ if (sampleDB.getSample(sampleName) == null) {
+ final Sample newSample = new Sample(sampleName, sampleDB);
+ sampleDB.addSample(newSample);
+ samplesFromDataSources.add(newSample); // keep track of data source samples
+ }
+ }
+ return this;
+ }
+
+ public SampleDBBuilder addSamplesFromPedigreeFiles(final List<File> pedigreeFiles) {
+ for (final File pedFile : pedigreeFiles) {
+ Collection<Sample> samples = addSamplesFromPedigreeArgument(pedFile);
+ samplesFromPedigrees.addAll(samples);
+ }
+
+ return this;
+ }
+
+ public SampleDBBuilder addSamplesFromPedigreeStrings(final List<String> pedigreeStrings) {
+ for (final String pedString : pedigreeStrings) {
+ Collection<Sample> samples = addSamplesFromPedigreeArgument(pedString);
+ samplesFromPedigrees.addAll(samples);
+ }
+
+ return this;
+ }
+
+ /**
+ * Parse one sample file and integrate it with samples that are already there
+ * Fail quickly if we find any errors in the file
+ */
+ private Collection<Sample> addSamplesFromPedigreeArgument(File sampleFile) {
+ final PedReader reader = new PedReader();
+
+ try {
+ return reader.parse(sampleFile, getMissingFields(sampleFile), sampleDB);
+ } catch ( FileNotFoundException e ) {
+ throw new UserException.CouldNotReadInputFile(sampleFile, e);
+ }
+ }
+
+ private Collection<Sample> addSamplesFromPedigreeArgument(final String string) {
+ final PedReader reader = new PedReader();
+ return reader.parse(string, getMissingFields(string), sampleDB);
+ }
+
+ public SampleDB getFinalSampleDB() {
+ validate();
+ return sampleDB;
+ }
+
+ public EnumSet<PedReader.MissingPedField> getMissingFields(final Object engineArg) {
+ if ( engine == null )
+ return EnumSet.noneOf(PedReader.MissingPedField.class);
+ else {
+ final List<String> posTags = engine.getTags(engineArg).getPositionalTags();
+ return PedReader.parseMissingFieldTags(engineArg, posTags);
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Validation
+ //
+ // --------------------------------------------------------------------------------
+
+ protected final void validate() {
+ validatePedigreeIDUniqueness();
+ if ( validationStrictness != PedigreeValidationType.SILENT ) {
+ // check that samples in data sources are all annotated, if anything is annotated
+ if ( ! samplesFromPedigrees.isEmpty() && ! samplesFromDataSources.isEmpty() ) {
+ final Set<String> sampleNamesFromPedigrees = new HashSet<String>();
+ for ( final Sample pSample : samplesFromPedigrees )
+ sampleNamesFromPedigrees.add(pSample.getID());
+
+ for ( final Sample dsSample : samplesFromDataSources )
+ if ( ! sampleNamesFromPedigrees.contains(dsSample.getID()) )
+ throw new UserException("Sample " + dsSample.getID() + " found in data sources but not in pedigree files with STRICT pedigree validation");
+ }
+ }
+ }
+
+ private void validatePedigreeIDUniqueness() {
+ Set<String> pedigreeIDs = new HashSet<String>();
+ for ( Sample sample : samplesFromPedigrees ) {
+ pedigreeIDs.add(sample.getID());
+ }
+ assert pedigreeIDs.size() == samplesFromPedigrees.size() : "The number of sample IDs extracted from the pedigree does not equal the number of samples in the pedigree. Is a sample associated with multiple families?";
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Trio.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Trio.java
new file mode 100644
index 0000000..b5a698b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/samples/Trio.java
@@ -0,0 +1,70 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.samples;
+
+/**
+ * A class for imposing a trio structure on three samples; a common paradigm
+ *
+ * todo -- there should probably be an interface or abstract class "Pedigree" that generalizes the notion of
+ * -- imposing structure on samples. But given how complex pedigrees can quickly become, it's not
+ * -- clear the best way to do this.
+ */
+public class Trio {
+ private Sample mother;
+ private Sample father;
+ private Sample child;
+
+ public Trio(Sample mom, Sample dad, Sample spawn) {
+ assert mom.getID().equals(spawn.getMaternalID()) && dad.getID().equals(spawn.getPaternalID()) : "Samples passed to trio constructor do not form a trio";
+ mother = mom;
+ father = dad;
+ child = spawn;
+ }
+
+ public Sample getMother() {
+ return mother;
+ }
+
+ public String getMaternalID() {
+ return mother.getID();
+ }
+
+ public Sample getFather() {
+ return father;
+ }
+
+ public String getPaternalID() {
+ return father.getID();
+ }
+
+ public Sample getChild() {
+ return child;
+ }
+
+ public String getChildID() {
+ return child.getID();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TAROrderedReadCache.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TAROrderedReadCache.java
new file mode 100644
index 0000000..d28ea3b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TAROrderedReadCache.java
@@ -0,0 +1,168 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import org.broadinstitute.gatk.engine.downsampling.Downsampler;
+import org.broadinstitute.gatk.engine.downsampling.ReservoirDownsampler;
+import org.broadinstitute.gatk.utils.sam.AlignmentStartComparator;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Subsystem to track a list of all reads currently live in the TraverseActiveRegions system,
+ * while limiting the total number of reads to a maximum capacity.
+ *
+ * User: depristo
+ * Date: 4/7/13
+ * Time: 11:23 AM
+ */
+public class TAROrderedReadCache {
+ private final int maxCapacity;
+ private ArrayList<GATKSAMRecord> undownsampledCache;
+ private Downsampler<GATKSAMRecord> downsampler;
+
+ private static final int UNDOWNSAMPLED_CACHE_MAX_INITIAL_SIZE = 10000;
+
+ /**
+ * Create a new empty ReadCache
+ * @param maxCapacity the max capacity of the read cache.
+ */
+ public TAROrderedReadCache( final int maxCapacity ) {
+ if ( maxCapacity < 0 ) throw new IllegalArgumentException("maxCapacity must be >= 0 but got " + maxCapacity);
+ this.maxCapacity = maxCapacity;
+
+ // The one we're not currently using will always be null:
+ initializeUndownsampledCache();
+ this.downsampler = null;
+ }
+
+ /**
+ * Moves all reads over to the downsampler, causing it to be used from this point on. Should be called
+ * when the undownsampledCache fills up and we need to start discarding reads. Since the
+ * ReservoirDownsampler doesn't preserve relative ordering, pop operations become expensive
+ * after this point, as they require a O(n log n) sort.
+ */
+ private void activateDownsampler() {
+ downsampler = new ReservoirDownsampler<>(maxCapacity, false);
+ downsampler.submit(undownsampledCache);
+ undownsampledCache = null; // preferable to the O(n) clear() method
+ }
+
+ /**
+ * Allocate the undownsampled cache used when we have fewer than maxCapacity items
+ */
+ private void initializeUndownsampledCache() {
+ undownsampledCache = new ArrayList<>(Math.min(maxCapacity + 1, UNDOWNSAMPLED_CACHE_MAX_INITIAL_SIZE));
+ }
+
+ /**
+ * What's the maximum number of reads we'll store in the cache?
+ * @return a positive integer
+ */
+ public int getMaxCapacity() {
+ return maxCapacity;
+ }
+
+ /**
+ * Add a single read to this cache. Assumed to be in sorted order w.r.t. the previously added reads
+ * @param read a read to add
+ */
+ public void add( final GATKSAMRecord read ) {
+ if ( read == null ) throw new IllegalArgumentException("Read cannot be null");
+
+ if ( downsampler != null ) {
+ downsampler.submit(read);
+ }
+ else {
+ undownsampledCache.add(read);
+
+ // No more room in the undownsampledCache? Time to start downsampling
+ if ( undownsampledCache.size() > maxCapacity ) {
+ activateDownsampler();
+ }
+ }
+ }
+
+ /**
+ * Add a collection of reads to this cache. Assumed to be in sorted order w.r.t. the previously added reads and each other
+ * @param reads a collection of reads to add
+ */
+ public void addAll( final List<GATKSAMRecord> reads ) {
+ if ( reads == null ) throw new IllegalArgumentException("Reads cannot be null");
+ for ( final GATKSAMRecord read : reads ) {
+ add(read);
+ }
+ }
+
+ /**
+ * How many reads are currently in the cache?
+ * @return a positive integer
+ */
+ public int size() {
+ return downsampler != null ? downsampler.size() : undownsampledCache.size();
+ }
+
+ /**
+ * How many reads were discarded since the last call to popCurrentReads
+ *
+ * @return number of items discarded during downsampling since last pop operation
+ */
+ public int getNumDiscarded() {
+ return downsampler != null ? downsampler.getNumberOfDiscardedItems() : 0;
+ }
+
+ /**
+ * Removes all reads currently in the cache, and returns them in sorted order (w.r.t. alignmentStart)
+ *
+ * Flushes this cache, so after this call the cache will contain no reads, and we'll be in the same
+ * initial state as the constructor would put us in, with a non-null undownsampledCache and a null
+ * downsampler.
+ *
+ * @return a list of GATKSAMRecords in this cache
+ */
+ public List<GATKSAMRecord> popCurrentReads() {
+ final List<GATKSAMRecord> poppedReads;
+
+ if ( downsampler == null ) {
+ poppedReads = undownsampledCache; // avoid making a copy here, since we're going to allocate a new cache
+ }
+ else {
+ // If we triggered the downsampler, we need to sort the reads before returning them,
+ // since the ReservoirDownsampler is not guaranteed to preserve relative ordering of items.
+ // After consuming the downsampled items in this call to popCurrentReads(), we switch back
+ // to using the undownsampledCache until we fill up again.
+ poppedReads = downsampler.consumeFinalizedItems(); // avoid making a copy here
+ Collections.sort(poppedReads, new AlignmentStartComparator());
+ downsampler = null;
+ }
+
+ initializeUndownsampledCache();
+ return poppedReads;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraversalEngine.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraversalEngine.java
new file mode 100644
index 0000000..25abafd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraversalEngine.java
@@ -0,0 +1,124 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.ReadMetrics;
+import org.broadinstitute.gatk.engine.datasources.providers.ShardDataProvider;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.progressmeter.ProgressMeter;
+
+public abstract class TraversalEngine<M,T,WalkerType extends Walker<M,T>,ProviderType extends ShardDataProvider> {
+ /** our log, which we want to capture anything from this class */
+ protected static final Logger logger = Logger.getLogger(TraversalEngine.class);
+
+ protected GenomeAnalysisEngine engine;
+ private ProgressMeter progressMeter;
+
+ // ----------------------------------------------------------------------------------------------------
+ //
+ // ABSTRACT METHODS
+ //
+ // ----------------------------------------------------------------------------------------------------
+
+ /**
+ * Gets the named traversal type associated with the given traversal, such as loci, reads, etc.
+ *
+ * @return A user-friendly name for the given traversal type.
+ */
+ public abstract String getTraversalUnits();
+
+ /**
+ * this method must be implemented by all traversal engines
+ *
+ * @param walker the walker to run with
+ * @param dataProvider the data provider that generates data given the shard
+ * @param sum the accumulator
+ *
+ * @return an object of the reduce type
+ */
+ public abstract T traverse(WalkerType walker,
+ ProviderType dataProvider,
+ T sum);
+
+ /**
+ * Initialize the traversal engine. After this point traversals can be run over the data
+ *
+ * @param engine GenomeAnalysisEngine for this traversal
+ * @param progressMeter An optional (null == optional) meter to track our progress
+ */
+ public void initialize(final GenomeAnalysisEngine engine, final Walker walker, final ProgressMeter progressMeter) {
+ if ( engine == null )
+ throw new ReviewedGATKException("BUG: GenomeAnalysisEngine cannot be null!");
+
+ this.engine = engine;
+ this.progressMeter = progressMeter;
+ }
+
+ /**
+ * For testing only. Does not initialize the progress meter
+ *
+ * @param engine
+ */
+ protected void initialize(final GenomeAnalysisEngine engine, final Walker walker) {
+ initialize(engine, walker, null);
+ }
+
+ /**
+ * Called by the MicroScheduler when all work is done and the GATK is shutting down.
+ *
+ * To be used by subclasses that need to free up resources (such as threads)
+ */
+ public void shutdown() {
+ // by default there's nothing to do
+ }
+
+ /**
+ * Update the cumulative traversal metrics according to the data in this shard
+ *
+ * @param singleTraverseMetrics read metrics object containing the information about a single shard's worth
+ * of data processing
+ */
+ public void updateCumulativeMetrics(final ReadMetrics singleTraverseMetrics) {
+ engine.getCumulativeMetrics().incrementMetrics(singleTraverseMetrics);
+ }
+
+ /**
+ * Forward request to notifyOfProgress
+ *
+ * Assumes that one cycle has been completed
+ *
+ * @param loc the location
+ */
+ public void printProgress(final GenomeLoc loc) {
+ if ( progressMeter != null )
+ progressMeter.notifyOfProgress(loc, engine.getCumulativeMetrics().getNumIterations());
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseActiveRegions.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseActiveRegions.java
new file mode 100644
index 0000000..7d93311
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseActiveRegions.java
@@ -0,0 +1,719 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.datasources.providers.*;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.ActiveRegionTraversalParameters;
+import org.broadinstitute.gatk.engine.walkers.ActiveRegionWalker;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.activeregion.ActiveRegion;
+import org.broadinstitute.gatk.utils.activeregion.ActivityProfile;
+import org.broadinstitute.gatk.utils.activeregion.ActivityProfileState;
+import org.broadinstitute.gatk.utils.activeregion.BandPassActivityProfile;
+import org.broadinstitute.gatk.utils.nanoScheduler.NSMapFunction;
+import org.broadinstitute.gatk.utils.nanoScheduler.NSProgressFunction;
+import org.broadinstitute.gatk.utils.nanoScheduler.NSReduceFunction;
+import org.broadinstitute.gatk.utils.nanoScheduler.NanoScheduler;
+import org.broadinstitute.gatk.utils.progressmeter.ProgressMeter;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.PrintStream;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Implement active region traversal
+ *
+ * User: depristo
+ * Date: 1/9/13
+ * Time: 4:45 PM
+ *
+ * Live region:
+ *
+ * The ART tracks a thing called the live region. The live region is a position on a specific contig
+ * of the alignment start of the last read we processed during this traversal. Because the
+ * read stream is sorted, future reads must occurs in the the live region. Therefore the the dead region
+ * (everything to the left of the live boundary) cannot have any more read data. The live / dead
+ * regions are used to decide when we can safely call map on active regions, as only active regions
+ * contained completely within the dead region (including extensions) have a complete set of read data
+ * in the collected read list. All of the data related to the live region is captured by the local
+ * variable spanOfLastReadSeen
+ *
+ */
+public final class TraverseActiveRegions<M, T> extends TraversalEngine<M,T,ActiveRegionWalker<M,T>,LocusShardDataProvider> {
+ private final static boolean DEBUG = false;
+ protected final static Logger logger = Logger.getLogger(TraversalEngine.class);
+ protected final static boolean LOG_READ_CARRYING = false;
+
+ // set by the traversal
+ private boolean walkerHasPresetRegions = false;
+ private int activeRegionExtension = -1;
+ private int maxRegionSize = -1;
+ private int minRegionSize = -1;
+
+ private final LinkedList<ActiveRegion> workQueue = new LinkedList<>();
+
+ private TAROrderedReadCache myReads = null;
+
+ private GenomeLoc lastRegionProcessed = null;
+ private GenomeLoc spanOfLastReadSeen = null;
+ private ActivityProfile activityProfile = null;
+ int maxReadsInMemory = 0;
+ ActiveRegionWalker<M, T> walker;
+
+ final NanoScheduler<MapData, M, T> nanoScheduler;
+
+ /**
+ * Data to use in the ActiveRegionWalker.map function produced by the NanoScheduler input iterator
+ */
+ private static class MapData {
+ public ActiveRegion activeRegion;
+ public RefMetaDataTracker tracker;
+
+ private MapData(ActiveRegion activeRegion, RefMetaDataTracker tracker) {
+ this.activeRegion = activeRegion;
+ this.tracker = tracker;
+ }
+ }
+
+ /**
+ * Create a single threaded active region traverser
+ */
+ public TraverseActiveRegions() {
+ this(1);
+ }
+
+ /**
+ * Create an active region traverser that uses nThreads for getting its work done
+ * @param nThreads number of threads
+ */
+ public TraverseActiveRegions(final int nThreads) {
+ nanoScheduler = new NanoScheduler<>(nThreads);
+ nanoScheduler.setProgressFunction(new NSProgressFunction<MapData>() {
+ @Override
+ public void progress(MapData lastActiveRegion) {
+ if ( lastActiveRegion != null )
+ // note, need to use getStopLocation so we don't give an interval to ProgressMeterDaemon
+ printProgress(lastActiveRegion.activeRegion.getLocation().getStopLocation());
+ }
+ });
+ }
+
+ /**
+ * Have the debugging output streams been initialized already?
+ *
+ * We have to do lazy initialization because when the initialize() function is called
+ * the streams aren't yet initialized in the GATK walker.
+ */
+ private boolean streamsInitialized = false;
+
+ @Override
+ public void initialize(GenomeAnalysisEngine engine, Walker walker, ProgressMeter progressMeter) {
+ super.initialize(engine, walker, progressMeter);
+
+ this.walker = (ActiveRegionWalker<M,T>)walker;
+ if ( this.walker.wantsExtendedReads() && ! this.walker.wantsNonPrimaryReads() ) {
+ throw new IllegalArgumentException("Active region walker " + this.walker + " requested extended events but not " +
+ "non-primary reads, an inconsistent state. Please modify the walker");
+ }
+
+ ActiveRegionTraversalParameters annotation = walker.getClass().getAnnotation(ActiveRegionTraversalParameters.class);
+ this.activeRegionExtension = this.walker.activeRegionExtension == null ? annotation.extension() : this.walker.activeRegionExtension;
+ this.maxRegionSize = this.walker.activeRegionMaxSize == null ? annotation.maxRegion() : this.walker.activeRegionMaxSize;
+ this.minRegionSize = annotation.minRegion();
+ final double bandPassSigma = this.walker.bandPassSigma == null ? annotation.bandPassSigma() : this.walker.bandPassSigma;
+ walkerHasPresetRegions = this.walker.hasPresetActiveRegions();
+
+ activityProfile = new BandPassActivityProfile(engine.getGenomeLocParser(), engine.getIntervals(), this.walker.maxProbPropagationDistance, this.walker.activeProbThreshold,
+ BandPassActivityProfile.MAX_FILTER_SIZE, bandPassSigma);
+
+ final int maxReadsAcrossSamples = annotation.maxReadsToHoldInMemoryPerSample() * SampleUtils.getSAMFileSamples(engine).size();
+ final int maxReadsToHoldInMemory = Math.min(maxReadsAcrossSamples, annotation.maxReadsToHoldTotal());
+ myReads = new TAROrderedReadCache(maxReadsToHoldInMemory);
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // Utility functions
+ //
+ // -------------------------------------------------------------------------------------
+
+ /**
+ * Load in the preset regions for contig into workQueue
+ *
+ * Should be called before starting to process work on contig
+ *
+ * Can only be called when walkerHasPresetRegions is true or an IllegalStateException will be thrown
+ *
+ * @param contig the contig we are about to process
+ */
+ protected void loadPresetRegionsForContigToWorkQueue(final String contig) {
+ if ( ! walkerHasPresetRegions ) throw new IllegalStateException("only appropriate to call when walker has preset regions");
+
+ final GenomeLoc contigSpan = engine.getGenomeLocParser().createOverEntireContig(contig);
+ for ( final GenomeLoc loc : this.walker.getPresetActiveRegions().getOverlapping(contigSpan) ) {
+ workQueue.add(new ActiveRegion(loc, null, true, engine.getGenomeLocParser(), getActiveRegionExtension()));
+ }
+ }
+
+ protected int getActiveRegionExtension() {
+ return activeRegionExtension;
+ }
+
+ protected int getMaxRegionSize() {
+ return maxRegionSize;
+ }
+
+ protected int getMinRegionSize() {
+ return minRegionSize;
+ }
+
+ @Override
+ public String getTraversalUnits() {
+ return "active regions";
+ }
+
+ @Override
+ public String toString() {
+ return "TraverseActiveRegions";
+ }
+
+ /**
+ * Is the loc outside of the intervals being requested for processing by the GATK?
+ * @param loc
+ * @return
+ */
+ protected boolean outsideEngineIntervals(final GenomeLoc loc) {
+ return engine.getIntervals() != null && ! engine.getIntervals().overlaps(loc);
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // Actual traverse function
+ //
+ // -------------------------------------------------------------------------------------
+
+ /**
+ * Did read appear in the last shard?
+ *
+ * When we transition across shard boundaries we see duplicate reads because
+ * each shard contains the reads that *overlap* the shard. So if we just finished
+ * shard 1-1000 and are now in 1001-2000 we'll see duplicate reads from 1001
+ * that overlapped 1-1000. This function tests read to determine if we would have
+ * seen it before by asking if read.getAlignmentStart() is less than the
+ * stop position of the last seen read at the start of the traversal. The reason
+ * we need to use the location of the last read at the start of the traversal
+ * is that we update the lastRead during the traversal, and we only want to filter
+ * out reads whose start is before the last read of the previous shard, not the
+ * current shard.
+ *
+ * @param locOfLastReadAtTraversalStart the location of the last read seen at the start of the traversal
+ * @param read the read we want to test if it's already been seen in the last shard
+ * @return true if read would have appeared in the last shard, false otherwise
+ */
+ @Requires({"read != null"})
+ private boolean appearedInLastShard(final GenomeLoc locOfLastReadAtTraversalStart, final GATKSAMRecord read) {
+ if ( locOfLastReadAtTraversalStart == null )
+ // we're in the first shard, so obviously the answer is no
+ return false;
+ else {
+ // otherwise check to see if the alignment occurred in the previous shard
+ return read.getAlignmentStart() <= locOfLastReadAtTraversalStart.getStart()
+ // we're on the same contig
+ && read.getReferenceIndex() == locOfLastReadAtTraversalStart.getContigIndex();
+ }
+
+ }
+
+ @Override
+ public T traverse( final ActiveRegionWalker<M,T> walker,
+ final LocusShardDataProvider dataProvider,
+ T sum) {
+ if ( LOG_READ_CARRYING || logger.isDebugEnabled() )
+ logger.info(String.format("TraverseActiveRegions.traverse: Shard is %s", dataProvider));
+
+ nanoScheduler.setDebug(false);
+ final Iterator<MapData> activeRegionIterator = new ActiveRegionIterator(dataProvider);
+ final TraverseActiveRegionMap myMap = new TraverseActiveRegionMap();
+ final TraverseActiveRegionReduce myReduce = new TraverseActiveRegionReduce();
+ final T result = nanoScheduler.execute(activeRegionIterator, myMap, sum, myReduce);
+
+ return result;
+ }
+
+ private class ActiveRegionIterator implements Iterator<MapData> {
+ private final LocusShardDataProvider dataProvider;
+ private LinkedList<MapData> readyActiveRegions = new LinkedList<>();
+ private boolean done = false;
+ private final LocusView locusView;
+ private final LocusReferenceView referenceView;
+ private final GenomeLoc locOfLastReadAtTraversalStart;
+ private final IntervalReferenceOrderedView referenceOrderedDataView;
+ private final GenomeLoc currentWindow;
+ private final boolean processRemainingActiveRegions;
+
+ public ActiveRegionIterator( final LocusShardDataProvider dataProvider ) {
+ this.dataProvider = dataProvider;
+ locusView = new AllLocusView(dataProvider);
+ referenceView = new LocusReferenceView( walker, dataProvider );
+
+ // The data shard may carry a number of locations to process (due to being indexed together).
+ // This value is just the interval we are processing within the entire provider
+ currentWindow = dataProvider.getLocus();
+ final int currentWindowPos = dataProvider.getShard().getGenomeLocs().indexOf(currentWindow);
+ if ( currentWindowPos == -1 ) throw new IllegalStateException("Data provider " + dataProvider + " didn't have our current window in it " + currentWindow);
+ processRemainingActiveRegions = currentWindowPos == dataProvider.getShard().getGenomeLocs().size() - 1;
+
+ // the rodSpan covers all of the bases in the activity profile, including all of the bases
+ // through the current window interval. This is because we may issue a query to get data for an
+ // active region spanning before the current interval as far back as the start of the current profile,
+ // if we have pending work to do that finalizes in this interval.
+ final GenomeLoc rodSpan = activityProfile.getSpan() == null ? currentWindow : activityProfile.getSpan().endpointSpan(currentWindow);
+ if ( ! dataProvider.getShard().getLocation().containsP(rodSpan) ) throw new IllegalStateException("Rod span " + rodSpan + " isn't contained within the data shard " + dataProvider.getShard().getLocation() + ", meaning we wouldn't get all of the data we need");
+ referenceOrderedDataView = new IntervalReferenceOrderedView( dataProvider, rodSpan );
+
+ // We keep processing while the next reference location is within the interval
+ locOfLastReadAtTraversalStart = spanOfLastSeenRead();
+
+ // load in the workQueue the present regions that span the current contig, if it's different from the last one
+ if ( walkerHasPresetRegions && ( lastRegionProcessed == null || ! currentWindow.onSameContig(lastRegionProcessed)) ) {
+ loadPresetRegionsForContigToWorkQueue(currentWindow.getContig());
+ }
+
+ // remember the last region we processed for sanity checking later
+ lastRegionProcessed = currentWindow;
+ }
+
+ @Override public void remove() { throw new UnsupportedOperationException("Cannot remove from ActiveRegionIterator"); }
+
+ @Override
+ public MapData next() {
+ return readyActiveRegions.pop();
+ }
+ @Override
+ public boolean hasNext() {
+ if ( engine.exceedsRuntimeLimit() ) // too much time has been dedicated to doing work, just stop
+ return false;
+ if ( ! readyActiveRegions.isEmpty() )
+ return true;
+ if ( done )
+ return false;
+ else {
+
+ while( locusView.hasNext() ) {
+ final AlignmentContext locus = locusView.next();
+ final GenomeLoc location = locus.getLocation();
+
+ rememberLastLocusLocation(location);
+
+ // get all of the new reads that appear in the current pileup, and them to our list of reads
+ // provided we haven't seen them before
+ final Collection<GATKSAMRecord> reads = locusView.getLIBS().transferReadsFromAllPreviousPileups();
+ for( final GATKSAMRecord read : reads ) {
+ // note that ActiveRegionShards span entire contigs, so this check is in some
+ // sense no longer necessary, as any read that appeared in the last shard would now
+ // by definition be on a different contig. However, the logic here doesn't hurt anything
+ // and makes us robust should we decided to provide shards that don't fully span
+ // contigs at some point in the future
+ if ( ! appearedInLastShard(locOfLastReadAtTraversalStart, read) ) {
+ rememberLastReadLocation(read);
+ myReads.add(read);
+ }
+ }
+
+ // skip this location -- it's not part of our engine intervals
+ if ( outsideEngineIntervals(location) )
+ continue;
+
+ // we've move across some interval boundary, restart profile
+ final boolean flushProfile = ! activityProfile.isEmpty()
+ && ( activityProfile.getContigIndex() != location.getContigIndex()
+ || location.getStart() != activityProfile.getStop() + 1);
+ final List<MapData> newActiveRegions = prepActiveRegionsForProcessing(walker, flushProfile, false, referenceOrderedDataView);
+
+ dataProvider.getShard().getReadMetrics().incrementNumIterations();
+
+ // create reference context. Note that if we have a pileup of "extended events", the context will
+ // hold the (longest) stretch of deleted reference bases (if deletions are present in the pileup).
+ final ReferenceContext refContext = referenceView.getReferenceContext(location);
+
+ // Iterate forward to get all reference ordered data covering this location
+ final RefMetaDataTracker tracker = referenceOrderedDataView.getReferenceOrderedDataAtLocus(locus.getLocation());
+
+ // Call the walkers isActive function for this locus and add them to the list to be integrated later
+ addIsActiveResult(walker, tracker, refContext, locus);
+
+ maxReadsInMemory = Math.max(myReads.size(), maxReadsInMemory);
+ printProgress(location);
+
+ if ( ! newActiveRegions.isEmpty() ) {
+ readyActiveRegions.addAll(newActiveRegions);
+ if ( DEBUG )
+ for ( final MapData region : newActiveRegions )
+ logger.info("Adding region to queue for processing " + region.activeRegion);
+ return true;
+ }
+ }
+
+ if ( processRemainingActiveRegions ) {
+ // we've run out of stuff to process, and since shards now span entire contig boundaries
+ // we should finalized our regions. This allows us to continue to use our referenceOrderedDataView
+ // which would otherwise be shutdown. Only followed when the microschedule says that we're
+ // inside of the last window in the current shard
+ readyActiveRegions.addAll(prepActiveRegionsForProcessing(walker, true, true, referenceOrderedDataView));
+ }
+
+ return ! readyActiveRegions.isEmpty();
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // Functions to manage and interact with the live / dead zone
+ //
+ // -------------------------------------------------------------------------------------
+
+ /**
+ * Update the live region to reflect that the last read we've seen in the traversal is read
+ *
+ * Requires that sequential calls always be provided reads in coordinate sorted order
+ *
+ * @param read the last read we've seen during the traversal
+ */
+ @Requires({"read != null"})
+ protected void rememberLastReadLocation(final GATKSAMRecord read) {
+ final GenomeLoc currentLocation = engine.getGenomeLocParser().createGenomeLoc(read);
+ if ( spanOfLastReadSeen == null )
+ spanOfLastReadSeen = currentLocation;
+ else {
+ if ( currentLocation.isBefore(spanOfLastReadSeen) )
+ throw new IllegalStateException("Updating last read seen in the traversal with read " + read + " with span " + currentLocation + " but this occurs before the previously seen read " + spanOfLastReadSeen);
+ spanOfLastReadSeen = currentLocation;
+ }
+ }
+
+ /**
+ * Update the live region to reflect that we've reached locus
+ *
+ * This function is complementary to #rememberLastReadLocation, but if we don't have any reads for a long
+ * time (e.g., there's no coverage) we will keep active regions around far longer than necessary.
+ *
+ * Only updates the span if it's beyond the last seen
+ *
+ * @param currentLocation the current location we've processed on the genome
+ */
+ protected void rememberLastLocusLocation(final GenomeLoc currentLocation) {
+ if ( spanOfLastReadSeen == null )
+ spanOfLastReadSeen = currentLocation;
+ else {
+ if ( currentLocation.isPast(spanOfLastReadSeen) )
+ spanOfLastReadSeen = currentLocation;
+ }
+ }
+
+
+ /**
+ * Get a GenomeLoc indicating the start (heading to the right) of the live ART region.
+ * @return the left-most position of the live region on the genome
+ */
+ protected GenomeLoc spanOfLastSeenRead() {
+ return spanOfLastReadSeen;
+ }
+
+ /**
+ * Is the active region completely within the traversal's dead zone?
+ *
+ * @param region the region we want to test
+ * @return true if the extended location of region is completely within the current dead zone, false otherwise
+ */
+ protected boolean regionCompletelyWithinDeadZone(final ActiveRegion region) {
+ if ( spanOfLastSeenRead() == null )
+ return false;
+
+ final int contigCmp = region.getExtendedLoc().compareContigs(spanOfLastSeenRead());
+ if ( contigCmp > 0 )
+ throw new IllegalStateException("Active region " + region + " on a contig after last seen read " + spanOfLastSeenRead());
+ else {
+ return contigCmp < 0 || region.getExtendedLoc().getStop() < spanOfLastSeenRead().getStart();
+ }
+ }
+
+ /**
+ * Is the read dead? That is, can it no longer be in any future active region, and therefore can be discarded?
+ *
+ * read: start |--------> stop ------ stop + extension
+ * region: start |-----------------| end
+ *
+ * Since the regions are coming in order, read could potentially be contained in a future interval if
+ * stop + activeRegionExtension >= end. If, on the other hand, stop + extension is < the end
+ * of this region, then we can discard it, since any future region could only include reads
+ * up to end + 1 - extension.
+ *
+ * Note that this function doesn't care about the dead zone. We're assuming that by
+ * actually calling this function with an active region that region is already in the dead zone,
+ * so checking that the read is in the dead zone doesn't make sense.
+ *
+ * @param read the read we're testing
+ * @param activeRegion the current active region
+ * @return true if the read is dead, false other
+ */
+ @Requires({"read != null", "activeRegion != null"})
+ private boolean readCannotOccurInAnyMoreActiveRegions(final GATKSAMRecord read, final ActiveRegion activeRegion) {
+ return read.getReferenceIndex() < activeRegion.getLocation().getContigIndex() ||
+ ( read.getReferenceIndex() == activeRegion.getLocation().getContigIndex()
+ && read.getAlignmentEnd() + getActiveRegionExtension() < activeRegion.getLocation().getStop() );
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // Functions to write out activity profiles and active regions
+ //
+ // -------------------------------------------------------------------------------------
+
+ /**
+ * Initialize the debugging output streams (activity profile and active regions), if not done so already
+ */
+ @Ensures("streamsInitialized == true")
+ private void initializeOutputStreamsIfNecessary() {
+ if ( ! streamsInitialized ) {
+ streamsInitialized = true;
+ if ( walker.activityProfileOutStream != null ) {
+ printIGVFormatHeader(walker.activityProfileOutStream, "line", "ActivityProfile");
+ }
+
+ if ( walker.activeRegionOutStream != null ) {
+ printIGVFormatHeader(walker.activeRegionOutStream, "line", "ActiveRegions");
+ }
+ }
+ }
+
+ /**
+ * Helper function to write out a IGV formatted line to out, at loc, with values
+ *
+ * http://www.broadinstitute.org/software/igv/IGV
+ *
+ * @param out a non-null PrintStream where we'll write our line
+ * @param graphType the type of graph to show in IGV for this track
+ * @param columns the column names for this IGV track
+ */
+ @Requires({
+ "out != null",
+ "graphType != null",
+ "columns.length > 0"
+ })
+ private void printIGVFormatHeader(final PrintStream out, final String graphType, final String ... columns ) {
+ out.printf("#track graphType=%s%n", graphType);
+ out.printf("Chromosome\tStart\tEnd\tFeature\t%s%n", Utils.join("\t", columns));
+
+ }
+
+ /**
+ * Helper function to write out a IGV formatted line to out, at loc, with values
+ *
+ * http://www.broadinstitute.org/software/igv/IGV
+ *
+ * @param out a non-null PrintStream where we'll write our line
+ * @param loc the location of values
+ * @param featureName string name of this feature (see IGV format)
+ * @param values the floating point values to associate with loc and feature name in out
+ */
+ @Requires({
+ "out != null",
+ "loc != null",
+ "values.length > 0"
+ })
+ private void printIGVFormatRow(final PrintStream out, final GenomeLoc loc, final String featureName, final double ... values) {
+ // note that start and stop are 0 based, but the stop is exclusive so we don't subtract 1
+ out.printf("%s\t%d\t%d\t%s", loc.getContig(), loc.getStart() - 1, loc.getStop(), featureName);
+ for ( final double value : values )
+ out.print(String.format("\t%.5f", value));
+ out.println();
+ }
+
+ /**
+ * Write out activity profile information, if requested by the walker
+ *
+ * @param states the states in the current activity profile
+ */
+ @Requires("states != null")
+ private void writeActivityProfile(final List<ActivityProfileState> states) {
+ if ( walker.activityProfileOutStream != null ) {
+ initializeOutputStreamsIfNecessary();
+ for ( final ActivityProfileState state : states ) {
+ printIGVFormatRow(walker.activityProfileOutStream, state.getLoc(), "state", Math.min(state.isActiveProb, 1.0));
+ }
+ }
+ }
+
+ /**
+ * Write out each active region to the walker activeRegionOutStream
+ *
+ * @param region the region we're currently operating on
+ */
+ @Requires("region != null")
+ private void writeActiveRegion(final ActiveRegion region) {
+ if( walker.activeRegionOutStream != null ) {
+ initializeOutputStreamsIfNecessary();
+ printIGVFormatRow(walker.activeRegionOutStream, region.getLocation().getStartLocation(),
+ "end-marker", 0.0);
+ printIGVFormatRow(walker.activeRegionOutStream, region.getLocation(),
+ "size=" + region.getLocation().size(), region.isActive() ? 1.0 : -1.0);
+ }
+ }
+
+
+ // -------------------------------------------------------------------------------------
+ //
+ // Functions to process active regions that are ready for map / reduce calls
+ //
+ // -------------------------------------------------------------------------------------
+
+ /**
+ * Invoke the walker isActive function, and incorporate its result into the activity profile
+ *
+ * @param walker the walker we're running
+ * @param tracker the ref meta data tracker to pass on to the isActive function of walker
+ * @param refContext the refContext to pass on to the isActive function of walker
+ * @param locus the AlignmentContext to pass on to the isActive function of walker
+ */
+ private void addIsActiveResult(final ActiveRegionWalker<M, T> walker,
+ final RefMetaDataTracker tracker, final ReferenceContext refContext,
+ final AlignmentContext locus) {
+ // must be called, even if we won't use the result, to satisfy walker contract
+ final ActivityProfileState state = walker.isActive( tracker, refContext, locus );
+ if ( walker.forceActive) state.isActiveProb = 1.0;
+ if ( ! walkerHasPresetRegions ) {
+ activityProfile.add(state);
+ }
+ }
+
+ /**
+ * Take the individual isActive calls and integrate them into contiguous active regions and
+ * add these blocks of work to the work queue
+ * band-pass filter the list of isActive probabilities and turn into active regions
+ */
+ private List<MapData> prepActiveRegionsForProcessing(final ActiveRegionWalker<M, T> walker,
+ final boolean flushActivityProfile,
+ final boolean forceAllRegionsToBeActive,
+ final IntervalReferenceOrderedView referenceOrderedDataView) {
+ if ( ! walkerHasPresetRegions ) {
+ // We don't have preset regions, so we get our regions from the activity profile
+ final Collection<ActiveRegion> activeRegions = activityProfile.popReadyActiveRegions(getActiveRegionExtension(), getMinRegionSize(), getMaxRegionSize(), flushActivityProfile);
+ workQueue.addAll(activeRegions);
+ if ( ! activeRegions.isEmpty() && logger.isDebugEnabled() ) logger.debug("Integrated " + activityProfile.size() + " isActive calls into " + activeRegions.size() + " regions." );
+ }
+
+ // Since we've traversed sufficiently past this point (or this contig!) in the workQueue we can unload those regions and process them
+ final LinkedList<MapData> readyRegions = new LinkedList<>();
+ while( workQueue.peek() != null ) {
+ final ActiveRegion activeRegion = workQueue.peek();
+ if ( forceAllRegionsToBeActive || regionCompletelyWithinDeadZone(activeRegion) ) {
+ writeActivityProfile(activeRegion.getSupportingStates());
+ writeActiveRegion(activeRegion);
+ readyRegions.add(prepActiveRegionForProcessing(workQueue.remove(), walker, referenceOrderedDataView));
+ } else {
+ break;
+ }
+ }
+
+ return readyRegions;
+
+ }
+
+ private MapData prepActiveRegionForProcessing(final ActiveRegion activeRegion,
+ final ActiveRegionWalker<M, T> walker,
+ final IntervalReferenceOrderedView referenceOrderedDataView) {
+ final List<GATKSAMRecord> stillLive = new LinkedList<>();
+ for ( final GATKSAMRecord read : myReads.popCurrentReads() ) {
+ boolean killed = false;
+ final GenomeLoc readLoc = this.engine.getGenomeLocParser().createGenomeLoc( read );
+
+ if( activeRegion.getLocation().overlapsP( readLoc ) ) {
+ activeRegion.add(read);
+
+ if ( ! walker.wantsNonPrimaryReads() ) {
+ killed = true;
+ }
+ } else if( walker.wantsExtendedReads() && activeRegion.getExtendedLoc().overlapsP( readLoc )) {
+ activeRegion.add( read );
+ }
+
+ // if the read hasn't already been killed, check if it cannot occur in any more active regions, and maybe kill it
+ if ( ! killed && readCannotOccurInAnyMoreActiveRegions(read, activeRegion) ) {
+ killed = true;
+ }
+
+ // keep track of all of the still live active regions
+ if ( ! killed ) stillLive.add(read);
+ }
+ myReads.addAll(stillLive);
+
+ if ( logger.isDebugEnabled() ) {
+ logger.debug(">> Map call with " + activeRegion.getReads().size() + " " + (activeRegion.isActive() ? "active" : "inactive") + " reads @ " + activeRegion.getLocation() + " with full extent: " + activeRegion.getReadSpanLoc());
+ }
+
+ if ( LOG_READ_CARRYING )
+ logger.info(String.format("Processing region %20s span=%3d active?=%5b with %4d reads. Overall max reads carried is %s",
+ activeRegion.getLocation(), activeRegion.getLocation().size(), activeRegion.isActive(), activeRegion.size(), maxReadsInMemory));
+
+ // prepare the RefMetaDataTracker information
+ final GenomeLoc loc = activeRegion.getLocation();
+ // get all of the RODs that cover the active region (without extension)
+ final RefMetaDataTracker tracker = referenceOrderedDataView.getReferenceOrderedDataForInterval(loc);
+ // trim away all of the features that occurred before this location, as we will not need them in the future
+ referenceOrderedDataView.trimCurrentFeaturesToLoc(loc);
+
+ return new MapData(activeRegion, tracker);
+ }
+
+ private class TraverseActiveRegionMap implements NSMapFunction<MapData, M> {
+ @Override
+ public M apply(final MapData mapData) {
+ if ( DEBUG ) logger.info("Executing walker.map for " + mapData.activeRegion + " in thread " + Thread.currentThread().getName());
+ return walker.map(mapData.activeRegion, mapData.tracker);
+ }
+ }
+
+ private class TraverseActiveRegionReduce implements NSReduceFunction<M, T> {
+ @Override
+ public T apply(M one, T sum) {
+ return walker.reduce(one, sum);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseDuplicates.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseDuplicates.java
new file mode 100644
index 0000000..6cffe94
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseDuplicates.java
@@ -0,0 +1,205 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import htsjdk.samtools.SAMRecord;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.datasources.providers.ReadShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.providers.ReadView;
+import org.broadinstitute.gatk.engine.iterators.PushbackIterator;
+import org.broadinstitute.gatk.engine.walkers.DuplicateWalker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileupImpl;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.*;
+
+/**
+ * @author Mark DePristo
+ * @version 0.1
+ * <p/>
+ * Class TraverseDuplicates
+ * <p/>
+ * This class handles traversing lists of duplicate reads in the new shardable style
+ */
+public class TraverseDuplicates<M,T> extends TraversalEngine<M,T,DuplicateWalker<M,T>,ReadShardDataProvider> {
+ /** our log, which we want to capture anything from this class */
+ protected static Logger logger = Logger.getLogger(TraverseDuplicates.class);
+
+ /** Turn this to true to enable logger.debug output */
+ private final boolean DEBUG = false;
+
+ @Override
+ public String getTraversalUnits() {
+ return "dups";
+ }
+
+ private List<GATKSAMRecord> readsAtLoc(final GATKSAMRecord read, PushbackIterator<SAMRecord> iter) {
+ GenomeLoc site = engine.getGenomeLocParser().createGenomeLoc(read);
+ ArrayList<GATKSAMRecord> l = new ArrayList<GATKSAMRecord>();
+
+ l.add(read);
+ for (SAMRecord read2 : iter) {
+ GenomeLoc site2 = engine.getGenomeLocParser().createGenomeLoc(read2);
+
+ // the next read starts too late
+ if (site2.getStart() != site.getStart()) {
+ iter.pushback(read2);
+ break;
+ } else {
+ l.add((GATKSAMRecord) read2);
+ }
+ }
+
+ return l;
+ }
+
+ /**
+ * Creates a set of lists of reads, where each list contains reads from the same underlying molecule according
+ * to their duplicate flag and their (and mate, if applicable) start/end positions.
+ *
+ * @param reads the list of reads to split into unique molecular samples
+ * @return
+ */
+ protected Set<List<GATKSAMRecord>> uniqueReadSets(List<GATKSAMRecord> reads) {
+ Set<List<GATKSAMRecord>> readSets = new LinkedHashSet<List<GATKSAMRecord>>();
+
+ // for each read, find duplicates, and either add the read to its duplicate list or start a new one
+ for ( GATKSAMRecord read : reads ) {
+ List<GATKSAMRecord> readSet = findDuplicateReads(read, readSets);
+
+ if ( readSet == null ) {
+ readSets.add(new ArrayList<GATKSAMRecord>(Arrays.asList(read))); // copy so I can add to the list
+ } else {
+ readSet.add(read);
+ }
+ }
+
+ return readSets;
+ }
+
+ /**
+ * Find duplicate reads for read in the set of unique reads. This is effective a duplicate marking algorithm,
+ * but it relies for safety's sake on the file itself being marked by a true duplicate marking algorithm. Pair
+ * and single-end read aware.
+ *
+ * @param read
+ * @param readSets
+ * @return The list of duplicate reads that read is a member of, or null if it's the only one of its kind
+ */
+ protected List<GATKSAMRecord> findDuplicateReads(GATKSAMRecord read, Set<List<GATKSAMRecord>> readSets ) {
+ if ( read.getReadPairedFlag() ) {
+ // paired
+ final GenomeLoc readMateLoc = engine.getGenomeLocParser().createGenomeLoc(read.getMateReferenceName(), read.getMateAlignmentStart(), read.getMateAlignmentStart());
+
+ for (List<GATKSAMRecord> reads : readSets) {
+ GATKSAMRecord key = reads.get(0);
+
+ // read and key start at the same place, and either the this read and the key
+ // share a mate location or the read is flagged as a duplicate
+ if ( read.getAlignmentStart() == key.getAlignmentStart() && key.getReadPairedFlag() && ( key.getDuplicateReadFlag() || read.getDuplicateReadFlag() ) ) {
+ // at least one has to be marked as a duplicate
+ final GenomeLoc keyMateLoc = engine.getGenomeLocParser().createGenomeLoc(key.getMateReferenceName(), key.getMateAlignmentStart(), key.getMateAlignmentStart());
+ if ( readMateLoc.compareTo(keyMateLoc) == 0 ) {
+ // we are at the same position as the dup and have the same mat pos, it's a dup
+ if (DEBUG) logger.debug(String.format(" => Adding read to dups list: %s %d %s vs. %s", read, reads.size(), readMateLoc, keyMateLoc));
+ return reads;
+ }
+ }
+ }
+ } else {
+ for (List<GATKSAMRecord> reads : readSets) {
+ GATKSAMRecord key = reads.get(0);
+ boolean v = (! key.getReadPairedFlag()) && read.getAlignmentStart() == key.getAlignmentStart() && ( key.getDuplicateReadFlag() || read.getDuplicateReadFlag() ) && read.getReadLength() == key.getReadLength();
+ //System.out.printf("%s %s %b %b %d %d %d %d => %b%n",
+ // read.getReadPairedFlag(), key.getReadPairedFlag(), read.getDuplicateReadFlag(), key.getDuplicateReadFlag(),
+ // read.getAlignmentStart(), key.getAlignmentStart(), read.getReadLength(), key.getReadLength(), v);
+ if ( v ) {
+ //System.out.printf("Returning reads...%n");
+ return reads;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // new style interface to the system
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Traverse by reads, given the data and the walker
+ *
+ * @param walker the walker to execute over
+ * @param sum of type T, the return from the walker
+ *
+ * @return the result type T, the product of all the reduce calls
+ */
+ public T traverse(DuplicateWalker<M, T> walker,
+ ReadShardDataProvider dataProvider,
+ T sum) {
+ PushbackIterator<SAMRecord> iter = new PushbackIterator<SAMRecord>(new ReadView(dataProvider).iterator());
+
+ /**
+ * while we still have more reads:
+ * ok, here's the idea. We get all the reads that start at the same position in the genome
+ * We then split the list of reads into sublists of reads:
+ * -> those with the same mate pair position, for paired reads
+ * -> those flagged as unpaired and duplicated but having the same start and end
+ */
+ boolean done = walker.isDone();
+ for (SAMRecord read : iter) {
+ if ( done ) break;
+ // get the genome loc from the read
+ GenomeLoc site = engine.getGenomeLocParser().createGenomeLoc(read);
+
+ Set<List<GATKSAMRecord>> readSets = uniqueReadSets(readsAtLoc((GATKSAMRecord) read, iter));
+ if ( DEBUG ) logger.debug(String.format("*** TraverseDuplicates.traverse at %s with %d read sets", site, readSets.size()));
+
+ // Jump forward in the reference to this locus location
+ AlignmentContext locus = new AlignmentContext(site, new ReadBackedPileupImpl(site));
+
+ // update the number of duplicate sets we've seen
+ dataProvider.getShard().getReadMetrics().incrementNumIterations();
+
+ // actually call filter and map, accumulating sum
+ final boolean keepMeP = walker.filter(site, locus, readSets);
+ if (keepMeP) {
+ M x = walker.map(site, locus, readSets);
+ sum = walker.reduce(x, sum);
+ }
+
+ printProgress(site.getStopLocation());
+ done = walker.isDone();
+ }
+
+ return sum;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseLociNano.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseLociNano.java
new file mode 100644
index 0000000..02c1a7e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseLociNano.java
@@ -0,0 +1,304 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import org.broadinstitute.gatk.engine.WalkerManager;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.datasources.providers.*;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.LocusWalker;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.nanoScheduler.NSMapFunction;
+import org.broadinstitute.gatk.utils.nanoScheduler.NSProgressFunction;
+import org.broadinstitute.gatk.utils.nanoScheduler.NSReduceFunction;
+import org.broadinstitute.gatk.utils.nanoScheduler.NanoScheduler;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileupImpl;
+
+import java.util.Iterator;
+
+/**
+ * A simple solution to iterating over all reference positions over a series of genomic locations.
+ */
+public class TraverseLociNano<M,T> extends TraversalEngine<M,T,LocusWalker<M,T>,LocusShardDataProvider> {
+ /** our log, which we want to capture anything from this class */
+ private static final boolean DEBUG = false;
+
+ final NanoScheduler<MapData, MapResult, T> nanoScheduler;
+
+ public TraverseLociNano(int nThreads) {
+ nanoScheduler = new NanoScheduler<MapData, MapResult, T>(nThreads);
+ nanoScheduler.setProgressFunction(new TraverseLociProgress());
+ }
+
+ @Override
+ public final String getTraversalUnits() {
+ return "sites";
+ }
+
+ protected static class TraverseResults<T> {
+ final int numIterations;
+ final T reduceResult;
+
+ public TraverseResults(int numIterations, T reduceResult) {
+ this.numIterations = numIterations;
+ this.reduceResult = reduceResult;
+ }
+ }
+
+ @Override
+ public T traverse( LocusWalker<M,T> walker,
+ LocusShardDataProvider dataProvider,
+ T sum) {
+ logger.debug(String.format("TraverseLoci.traverse: Shard is %s", dataProvider));
+
+ final LocusView locusView = getLocusView( walker, dataProvider );
+
+ if ( locusView.hasNext() ) { // trivial optimization to avoid unnecessary processing when there's nothing here at all
+ //ReferenceOrderedView referenceOrderedDataView = new ReferenceOrderedView( dataProvider );
+ ReferenceOrderedView referenceOrderedDataView = null;
+ if ( WalkerManager.getWalkerDataSource(walker) != DataSource.REFERENCE_ORDERED_DATA )
+ referenceOrderedDataView = new ManagingReferenceOrderedView( dataProvider );
+ else
+ referenceOrderedDataView = (RodLocusView)locusView;
+
+ final LocusReferenceView referenceView = new LocusReferenceView( walker, dataProvider );
+
+ final TraverseResults<T> result = traverse( walker, locusView, referenceView, referenceOrderedDataView, sum );
+ sum = result.reduceResult;
+ dataProvider.getShard().getReadMetrics().incrementNumIterations(result.numIterations);
+ }
+
+ // We have a final map call to execute here to clean up the skipped based from the
+ // last position in the ROD to that in the interval
+ if ( WalkerManager.getWalkerDataSource(walker) == DataSource.REFERENCE_ORDERED_DATA && ! walker.isDone() ) {
+ // only do this if the walker isn't done!
+ final RodLocusView rodLocusView = (RodLocusView)locusView;
+ final long nSkipped = rodLocusView.getLastSkippedBases();
+ if ( nSkipped > 0 ) {
+ final GenomeLoc site = rodLocusView.getLocOneBeyondShard();
+ final AlignmentContext ac = new AlignmentContext(site, new ReadBackedPileupImpl(site), nSkipped);
+ final M x = walker.map(null, null, ac);
+ sum = walker.reduce(x, sum);
+ }
+ }
+
+ return sum;
+ }
+
+ /**
+ * Gets the best view of loci for this walker given the available data. The view will function as a 'trigger track'
+ * of sorts, providing a consistent interface so that TraverseLoci doesn't need to be reimplemented for any new datatype
+ * that comes along.
+ * @param walker walker to interrogate.
+ * @param dataProvider Data which which to drive the locus view.
+ * @return A view of the locus data, where one iteration of the locus view maps to one iteration of the traversal.
+ */
+ private LocusView getLocusView( Walker<M,T> walker, LocusShardDataProvider dataProvider ) {
+ final DataSource dataSource = WalkerManager.getWalkerDataSource(walker);
+ if( dataSource == DataSource.READS )
+ return new CoveredLocusView(dataProvider);
+ else if( dataSource == DataSource.REFERENCE ) //|| ! GenomeAnalysisEngine.instance.getArguments().enableRodWalkers )
+ return new AllLocusView(dataProvider);
+ else if( dataSource == DataSource.REFERENCE_ORDERED_DATA )
+ return new RodLocusView(dataProvider);
+ else
+ throw new UnsupportedOperationException("Unsupported traversal type: " + dataSource);
+ }
+
+ protected TraverseResults<T> traverse(final LocusWalker<M, T> walker,
+ final LocusView locusView,
+ final LocusReferenceView referenceView,
+ final ReferenceOrderedView referenceOrderedDataView,
+ final T sum) {
+ nanoScheduler.setDebug(DEBUG);
+ final TraverseLociMap myMap = new TraverseLociMap(walker);
+ final TraverseLociReduce myReduce = new TraverseLociReduce(walker);
+
+ final MapDataIterator inputIterator = new MapDataIterator(locusView, referenceView, referenceOrderedDataView);
+ final T result = nanoScheduler.execute(inputIterator, myMap, sum, myReduce);
+
+ return new TraverseResults<T>(inputIterator.numIterations, result);
+ }
+
+ /**
+ * Create iterator that provides inputs for all map calls into MapData, to be provided
+ * to NanoScheduler for Map/Reduce
+ */
+ private class MapDataIterator implements Iterator<MapData> {
+ final LocusView locusView;
+ final LocusReferenceView referenceView;
+ final ReferenceOrderedView referenceOrderedDataView;
+ int numIterations = 0;
+
+ private MapDataIterator(LocusView locusView, LocusReferenceView referenceView, ReferenceOrderedView referenceOrderedDataView) {
+ this.locusView = locusView;
+ this.referenceView = referenceView;
+ this.referenceOrderedDataView = referenceOrderedDataView;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return locusView.hasNext() && ! engine.exceedsRuntimeLimit();
+ }
+
+ @Override
+ public MapData next() {
+ final AlignmentContext locus = locusView.next();
+ final GenomeLoc location = locus.getLocation();
+
+ //logger.info("Pulling data from MapDataIterator at " + location);
+
+ // create reference context. Note that if we have a pileup of "extended events", the context will
+ // hold the (longest) stretch of deleted reference bases (if deletions are present in the pileup).
+ final ReferenceContext refContext = referenceView.getReferenceContext(location);
+
+ // Iterate forward to get all reference ordered data covering this location
+ final RefMetaDataTracker tracker = referenceOrderedDataView.getReferenceOrderedDataAtLocus(location);
+
+ numIterations++;
+ return new MapData(locus, refContext, tracker);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Cannot remove elements from MapDataIterator");
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ nanoScheduler.shutdown();
+ }
+
+ /**
+ * The input data needed for each map call. The read, the reference, and the RODs
+ */
+ private class MapData {
+ final AlignmentContext alignmentContext;
+ final ReferenceContext refContext;
+ final RefMetaDataTracker tracker;
+
+ private MapData(final AlignmentContext alignmentContext, ReferenceContext refContext, RefMetaDataTracker tracker) {
+ this.alignmentContext = alignmentContext;
+ this.refContext = refContext;
+ this.tracker = tracker;
+ }
+
+ @Override
+ public String toString() {
+ return "MapData " + alignmentContext.getLocation();
+ }
+ }
+
+ /**
+ * Contains the results of a map call, indicating whether the call was good, filtered, or done
+ */
+ private class MapResult {
+ final M value;
+ final boolean reduceMe;
+
+ /**
+ * Create a MapResult with value that should be reduced
+ *
+ * @param value the value to reduce
+ */
+ private MapResult(final M value) {
+ this.value = value;
+ this.reduceMe = true;
+ }
+
+ /**
+ * Create a MapResult that shouldn't be reduced
+ */
+ private MapResult() {
+ this.value = null;
+ this.reduceMe = false;
+ }
+ }
+
+ /**
+ * A static object that tells reduce that the result of map should be skipped (filtered or done)
+ */
+ private final MapResult SKIP_REDUCE = new MapResult();
+
+ /**
+ * MapFunction for TraverseReads meeting NanoScheduler interface requirements
+ *
+ * Applies walker.map to MapData, returning a MapResult object containing the result
+ */
+ private class TraverseLociMap implements NSMapFunction<MapData, MapResult> {
+ final LocusWalker<M,T> walker;
+
+ private TraverseLociMap(LocusWalker<M, T> walker) {
+ this.walker = walker;
+ }
+
+ @Override
+ public MapResult apply(final MapData data) {
+ if ( ! walker.isDone() ) {
+ final boolean keepMeP = walker.filter(data.tracker, data.refContext, data.alignmentContext);
+ if (keepMeP) {
+ final M x = walker.map(data.tracker, data.refContext, data.alignmentContext);
+ return new MapResult(x);
+ }
+ }
+ return SKIP_REDUCE;
+ }
+ }
+
+ /**
+ * NSReduceFunction for TraverseReads meeting NanoScheduler interface requirements
+ *
+ * Takes a MapResult object and applies the walkers reduce function to each map result, when applicable
+ */
+ private class TraverseLociReduce implements NSReduceFunction<MapResult, T> {
+ final LocusWalker<M,T> walker;
+
+ private TraverseLociReduce(LocusWalker<M, T> walker) {
+ this.walker = walker;
+ }
+
+ @Override
+ public T apply(MapResult one, T sum) {
+ if ( one.reduceMe )
+ // only run reduce on values that aren't DONE or FAILED
+ return walker.reduce(one.value, sum);
+ else
+ return sum;
+ }
+ }
+
+ private class TraverseLociProgress implements NSProgressFunction<MapData> {
+ @Override
+ public void progress(MapData lastProcessedMap) {
+ if (lastProcessedMap.alignmentContext != null)
+ printProgress(lastProcessedMap.alignmentContext.getLocation());
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseReadPairs.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseReadPairs.java
new file mode 100644
index 0000000..c68e109
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseReadPairs.java
@@ -0,0 +1,129 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMRecordCoordinateComparator;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.datasources.providers.ReadShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.providers.ReadView;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.ReadPairWalker;
+import org.broadinstitute.gatk.engine.walkers.Requires;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Traverse over a collection of read pairs, assuming that a given shard will contain all pairs.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+ at Requires({DataSource.REFERENCE})
+public class TraverseReadPairs<M,T> extends TraversalEngine<M,T, ReadPairWalker<M,T>,ReadShardDataProvider> {
+
+ /** our log, which we want to capture anything from this class */
+ protected static final Logger logger = Logger.getLogger(TraverseReadPairs.class);
+
+ @Override
+ public String getTraversalUnits() {
+ return "read pairs";
+ }
+
+ /**
+ * Traverse by reads, given the data and the walker
+ *
+ * @param walker the walker to execute over
+ * @param sum of type T, the return from the walker
+ *
+ * @return the result type T, the product of all the reduce calls
+ */
+ public T traverse(ReadPairWalker<M, T> walker,
+ ReadShardDataProvider dataProvider,
+ T sum) {
+ logger.debug(String.format("TraverseReadsPairs.traverse Covered dataset is %s", dataProvider));
+
+ if( !dataProvider.hasReads() )
+ throw new IllegalArgumentException("Unable to traverse reads; no read data is available.");
+
+ ReadView reads = new ReadView(dataProvider);
+ List<SAMRecord> pairs = new ArrayList<SAMRecord>();
+
+ boolean done = walker.isDone();
+ for(SAMRecord read: reads) {
+ if ( done ) break;
+ dataProvider.getShard().getReadMetrics().incrementNumReadsSeen();
+
+ if(pairs.size() == 0 || pairs.get(0).getReadName().equals(read.getReadName())) {
+ // If this read name is the same as the last, accumulate it.
+ pairs.add(read);
+ }
+ else {
+ // Otherwise, walk over the accumulated list, then start fresh with the new read.
+ sum = walkOverPairs(walker,dataProvider.getShard(),pairs,sum);
+ pairs.clear();
+ pairs.add(read);
+
+ printProgress(null);
+ }
+
+ done = walker.isDone();
+ }
+
+ // If any data was left in the queue, process it.
+ if(pairs.size() > 0)
+ sum = walkOverPairs(walker,dataProvider.getShard(),pairs,sum);
+
+ return sum;
+ }
+
+ /**
+ * Filter / map / reduce over a single pair.
+ * @param walker The walker.
+ * @param shard The shard currently being processed.
+ * @param reads The reads in the pair.
+ * @param sum The accumulator.
+ * @return The accumulator after application of the given read pairing.
+ */
+ private T walkOverPairs(ReadPairWalker<M,T> walker, Shard shard, List<SAMRecord> reads, T sum) {
+ // update the number of reads we've seen
+ shard.getReadMetrics().incrementNumIterations();
+
+ // Sort the reads present in coordinate order.
+ Collections.sort(reads,new SAMRecordCoordinateComparator());
+
+ final boolean keepMeP = walker.filter(reads);
+ if (keepMeP) {
+ M x = walker.map(reads);
+ sum = walker.reduce(x, sum);
+ }
+
+ return sum;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseReadsNano.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseReadsNano.java
new file mode 100644
index 0000000..2ce752b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/TraverseReadsNano.java
@@ -0,0 +1,256 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import htsjdk.samtools.SAMRecord;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.datasources.providers.ReadBasedReferenceOrderedView;
+import org.broadinstitute.gatk.engine.datasources.providers.ReadReferenceView;
+import org.broadinstitute.gatk.engine.datasources.providers.ReadShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.providers.ReadView;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.utils.nanoScheduler.NSMapFunction;
+import org.broadinstitute.gatk.utils.nanoScheduler.NSProgressFunction;
+import org.broadinstitute.gatk.utils.nanoScheduler.NSReduceFunction;
+import org.broadinstitute.gatk.utils.nanoScheduler.NanoScheduler;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * A nano-scheduling version of TraverseReads.
+ *
+ * Implements the traversal of a walker that accepts individual reads, the reference, and
+ * RODs per map call. Directly supports shared memory parallelism via NanoScheduler
+ *
+ * @author depristo
+ * @version 1.0
+ * @date 9/2/2012
+ */
+public class TraverseReadsNano<M,T> extends TraversalEngine<M,T,ReadWalker<M,T>,ReadShardDataProvider> {
+ /** our log, which we want to capture anything from this class */
+ private final static boolean PRE_READ_ALL_MAP_DATA = true;
+ protected static final Logger logger = Logger.getLogger(TraverseReadsNano.class);
+ private static final boolean DEBUG = false;
+ final NanoScheduler<MapData, MapResult, T> nanoScheduler;
+
+ public TraverseReadsNano(int nThreads) {
+ nanoScheduler = new NanoScheduler<MapData, MapResult, T>(nThreads);
+ nanoScheduler.setProgressFunction(new NSProgressFunction<MapData>() {
+ @Override
+ public void progress(MapData lastProcessedMap) {
+ if ( lastProcessedMap.refContext != null )
+ // note, need to use getStopLocation so we don't give an interval to ProgressMeterDaemon
+ printProgress(lastProcessedMap.refContext.getLocus().getStopLocation());
+ }
+ });
+ }
+
+ @Override
+ public String getTraversalUnits() {
+ return "reads";
+ }
+
+ /**
+ * Traverse by reads, given the data and the walker
+ *
+ * @param walker the walker to traverse with
+ * @param dataProvider the provider of the reads data
+ * @param sum the value of type T, specified by the walker, to feed to the walkers reduce function
+ * @return the reduce variable of the read walker
+ */
+ public T traverse(ReadWalker<M,T> walker,
+ ReadShardDataProvider dataProvider,
+ T sum) {
+ if ( logger.isDebugEnabled() )
+ logger.debug(String.format("TraverseReadsNano.traverse Covered dataset is %s", dataProvider));
+
+ if( !dataProvider.hasReads() )
+ throw new IllegalArgumentException("Unable to traverse reads; no read data is available.");
+
+ nanoScheduler.setDebug(DEBUG);
+ final TraverseReadsMap myMap = new TraverseReadsMap(walker);
+ final TraverseReadsReduce myReduce = new TraverseReadsReduce(walker);
+
+ final Iterator<MapData> aggregatedInputs = aggregateMapData(dataProvider);
+ final T result = nanoScheduler.execute(aggregatedInputs, myMap, sum, myReduce);
+
+ return result;
+ }
+
+ /**
+ * Aggregate all of the inputs for all map calls into MapData, to be provided
+ * to NanoScheduler for Map/Reduce
+ *
+ * @param dataProvider the source of our data
+ * @return a linked list of MapData objects holding the read, ref, and ROD info for every map/reduce
+ * should execute
+ */
+ private Iterator<MapData> aggregateMapData(final ReadShardDataProvider dataProvider) {
+ final Iterator<MapData> it = makeDataIterator(dataProvider);
+ if ( PRE_READ_ALL_MAP_DATA ) {
+ final LinkedList<MapData> l = new LinkedList<MapData>();
+ while ( it.hasNext() ) l.add(it.next());
+ return l.iterator();
+ } else {
+ return it;
+ }
+ }
+
+
+ private Iterator<MapData> makeDataIterator(final ReadShardDataProvider dataProvider) {
+ return new Iterator<MapData> () {
+ final ReadView reads = new ReadView(dataProvider);
+ final ReadReferenceView reference = new ReadReferenceView(dataProvider);
+ final ReadBasedReferenceOrderedView rodView = new ReadBasedReferenceOrderedView(dataProvider);
+ final Iterator<SAMRecord> readIterator = reads.iterator();
+
+ @Override public boolean hasNext() { return ! engine.exceedsRuntimeLimit() && readIterator.hasNext(); }
+
+ @Override
+ public MapData next() {
+ final SAMRecord read = readIterator.next();
+ final ReferenceContext refContext = ! read.getReadUnmappedFlag()
+ ? reference.getReferenceContext(read)
+ : null;
+
+ // if the read is mapped, create a metadata tracker
+ final RefMetaDataTracker tracker = read.getReferenceIndex() >= 0
+ ? rodView.getReferenceOrderedDataForRead(read)
+ : null;
+
+ // update the number of reads we've seen
+ dataProvider.getShard().getReadMetrics().incrementNumIterations();
+
+ return new MapData((GATKSAMRecord)read, refContext, tracker);
+ }
+
+ @Override public void remove() {
+ throw new UnsupportedOperationException("Remove not supported");
+ }
+ };
+ }
+
+ @Override
+ public void shutdown() {
+ nanoScheduler.shutdown();
+ }
+
+ /**
+ * The input data needed for each map call. The read, the reference, and the RODs
+ */
+ private class MapData {
+ final GATKSAMRecord read;
+ final ReferenceContext refContext;
+ final RefMetaDataTracker tracker;
+
+ private MapData(GATKSAMRecord read, ReferenceContext refContext, RefMetaDataTracker tracker) {
+ this.read = read;
+ this.refContext = refContext;
+ this.tracker = tracker;
+ }
+ }
+
+ /**
+ * Contains the results of a map call, indicating whether the call was good, filtered, or done
+ */
+ private class MapResult {
+ final M value;
+ final boolean reduceMe;
+
+ /**
+ * Create a MapResult with value that should be reduced
+ *
+ * @param value the value to reduce
+ */
+ private MapResult(final M value) {
+ this.value = value;
+ this.reduceMe = true;
+ }
+
+ /**
+ * Create a MapResult that shouldn't be reduced
+ */
+ private MapResult() {
+ this.value = null;
+ this.reduceMe = false;
+ }
+ }
+
+ /**
+ * A static object that tells reduce that the result of map should be skipped (filtered or done)
+ */
+ private final MapResult SKIP_REDUCE = new MapResult();
+
+ /**
+ * MapFunction for TraverseReads meeting NanoScheduler interface requirements
+ *
+ * Applies walker.map to MapData, returning a MapResult object containing the result
+ */
+ private class TraverseReadsMap implements NSMapFunction<MapData, MapResult> {
+ final ReadWalker<M,T> walker;
+
+ private TraverseReadsMap(ReadWalker<M, T> walker) {
+ this.walker = walker;
+ }
+
+ @Override
+ public MapResult apply(final MapData data) {
+ if ( ! walker.isDone() ) {
+ final boolean keepMeP = walker.filter(data.refContext, data.read);
+ if (keepMeP)
+ return new MapResult(walker.map(data.refContext, data.read, data.tracker));
+ }
+
+ return SKIP_REDUCE;
+ }
+ }
+
+ /**
+ * NSReduceFunction for TraverseReads meeting NanoScheduler interface requirements
+ *
+ * Takes a MapResult object and applies the walkers reduce function to each map result, when applicable
+ */
+ private class TraverseReadsReduce implements NSReduceFunction<MapResult, T> {
+ final ReadWalker<M,T> walker;
+
+ private TraverseReadsReduce(ReadWalker<M, T> walker) {
+ this.walker = walker;
+ }
+
+ @Override
+ public T apply(MapResult one, T sum) {
+ if ( one.reduceMe )
+ // only run reduce on values that aren't DONE or FAILED
+ return walker.reduce(one.value, sum);
+ else
+ return sum;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/package-info.java
new file mode 100644
index 0000000..72d1099
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/traversals/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ActiveRegionTraversalParameters.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ActiveRegionTraversalParameters.java
new file mode 100644
index 0000000..7c428cd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ActiveRegionTraversalParameters.java
@@ -0,0 +1,97 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import org.broadinstitute.gatk.utils.activeregion.BandPassActivityProfile;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Describes the parameters that this walker requires of the active region traversal
+ *
+ * User: rpoplin
+ * Date: 1/18/12
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+
+public @interface ActiveRegionTraversalParameters {
+ /**
+ * How far to either side of the active region itself should we include reads?
+ *
+ * That is, if the active region is 10 bp wide, and extension is 5, ART will provide
+ * the walker with active regions 10 bp, with 5 bp of extension on either side, and
+ * all reads that cover the 20 bp of the region + extension.
+ *
+ * @return the size of the active region extension we'd like
+ */
+ public int extension() default 0;
+
+ /**
+ * The minimum number of bp for an active region, when we need to chop it up into pieces because
+ * it's become too big. This only comes into effect when there's literally no good place to chop
+ * that does make the region smaller than this value.
+ *
+ * @return the min size in bp of regions
+ */
+ public int minRegion() default 50;
+
+ /**
+ * The maximum size in bp of active regions wanted by this walker
+ *
+ * Active regions larger than this value are automatically cut up by ART into smaller
+ * regions of size <= this value.
+ *
+ * @return the max size in bp of regions
+ */
+ public int maxRegion() default 1500;
+
+ /**
+ * The variance value for the Gaussian kernel of the band pass filter employed by ART
+ * @return the breadth of the band pass gaussian kernel we want for our traversal
+ */
+ public double bandPassSigma() default BandPassActivityProfile.DEFAULT_SIGMA;
+
+ /**
+ * What is the maximum number of reads we're willing to hold in memory per sample
+ * during the traversal? This limits our exposure to unusually large amounts
+ * of coverage in the engine.
+ * @return the maximum number of reads we're willing to hold in memory
+ */
+ public int maxReadsToHoldInMemoryPerSample() default 3000;
+
+ /**
+ * No matter what the per sample value says, we will never hold more than this
+ * number of reads in memory at any time. Provides an upper bound on the total number
+ * of reads in the case where we have a lot of samples.
+ * @return the maximum number of reads to hold in memory
+ */
+ public int maxReadsToHoldTotal() default 1000000;
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ActiveRegionWalker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ActiveRegionWalker.java
new file mode 100644
index 0000000..9ff68bc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ActiveRegionWalker.java
@@ -0,0 +1,196 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import com.google.java.contract.Ensures;
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+import org.broadinstitute.gatk.engine.filters.*;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.activeregion.ActiveRegion;
+import org.broadinstitute.gatk.utils.activeregion.ActiveRegionReadState;
+import org.broadinstitute.gatk.utils.activeregion.ActivityProfileState;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.interval.IntervalSetRule;
+import org.broadinstitute.gatk.utils.interval.IntervalUtils;
+
+import java.io.PrintStream;
+import java.util.*;
+
+/**
+ * Base class for all the Active Region Walkers.
+ * User: rpoplin
+ * Date: 12/7/11
+ */
+
+ at By(DataSource.READS)
+ at Requires({DataSource.READS, DataSource.REFERENCE})
+ at PartitionBy(PartitionType.READ)
+ at ActiveRegionTraversalParameters(extension=50,maxRegion=1500)
+ at ReadFilters({UnmappedReadFilter.class, NotPrimaryAlignmentFilter.class, DuplicateReadFilter.class, FailsVendorQualityCheckFilter.class, MappingQualityUnavailableFilter.class})
+ at Downsample(by = DownsampleType.BY_SAMPLE, toCoverage = 1000)
+ at RemoveProgramRecords
+public abstract class ActiveRegionWalker<MapType, ReduceType> extends Walker<MapType, ReduceType> {
+ /**
+ * If provided, this walker will write out its activity profile (per bp probabilities of being active)
+ * to this file in the IGV formatted TAB deliminated output:
+ *
+ * http://www.broadinstitute.org/software/igv/IGV
+ *
+ * Intended to make debugging the activity profile calculations easier
+ */
+ @Output(fullName="activityProfileOut", shortName="APO", doc="Output the raw activity profile results in IGV format", required = false, defaultToStdout = false)
+ public PrintStream activityProfileOutStream = null;
+
+ /**
+ * If provided, this walker will write out its active and inactive regions
+ * to this file in the IGV formatted TAB deliminated output:
+ *
+ * http://www.broadinstitute.org/software/igv/IGV
+ *
+ * Intended to make debugging the active region calculations easier
+ */
+ @Output(fullName="activeRegionOut", shortName="ARO", doc="Output the active region to this IGV formatted file", required = false, defaultToStdout = false)
+ public PrintStream activeRegionOutStream = null;
+
+ @Advanced
+ @Input(fullName="activeRegionIn", shortName="AR", doc="Use this interval list file as the active regions to process", required = false)
+ protected List<IntervalBinding<Feature>> activeRegionBindings = null;
+
+ @Advanced
+ @Argument(fullName="activeRegionExtension", shortName="activeRegionExtension", doc="The active region extension; if not provided defaults to Walker annotated default", required = false)
+ public Integer activeRegionExtension = null;
+
+ /**
+ * For the active region walker to treat all bases as active. Useful for debugging when you want to force something like
+ * the HaplotypeCaller to process a specific interval you provide the GATK
+ */
+ @Advanced
+ @Argument(fullName="forceActive", shortName="forceActive", doc="If provided, all bases will be tagged as active", required = false)
+ public boolean forceActive = false;
+
+ @Advanced
+ @Argument(fullName="activeRegionMaxSize", shortName="activeRegionMaxSize", doc="The active region maximum size; if not provided defaults to Walker annotated default", required = false)
+ public Integer activeRegionMaxSize = null;
+
+ @Advanced
+ @Argument(fullName="bandPassSigma", shortName="bandPassSigma", doc="The sigma of the band pass filter Gaussian kernel; if not provided defaults to Walker annotated default", required = false)
+ public Double bandPassSigma = null;
+
+ /*
+ * For active region limits in ActivityProfile
+* */
+ @Hidden
+ @Argument(fullName = "maxProbPropagationDistance", shortName = "maxProbPropDist", minValue = 0, doc="Region probability propagation distance beyond it's maximum size.", required = false)
+ public Integer maxProbPropagationDistance = 50;
+
+ @Advanced
+ @Argument(fullName = "activeProbabilityThreshold", shortName = "ActProbThresh", minValue = 0.0, maxValue = 1.0, doc="Threshold for the probability of a profile state being active.", required = false)
+ public Double activeProbThreshold = 0.002;
+
+ private GenomeLocSortedSet presetActiveRegions = null;
+
+ @Override
+ public void initialize() {
+ if( activeRegionBindings == null ) { return; }
+ List<GenomeLoc> allIntervals = new ArrayList<GenomeLoc>(0);
+ for ( IntervalBinding intervalBinding : activeRegionBindings ) {
+ List<GenomeLoc> intervals = intervalBinding.getIntervals(this.getToolkit());
+
+ if ( intervals.isEmpty() ) {
+ logger.warn("The interval file " + intervalBinding.getSource() + " contains no intervals that could be parsed.");
+ }
+
+ allIntervals = IntervalUtils.mergeListsBySetOperator(intervals, allIntervals, IntervalSetRule.UNION);
+ }
+
+ presetActiveRegions = IntervalUtils.sortAndMergeIntervals(this.getToolkit().getGenomeLocParser(), allIntervals, IntervalMergingRule.ALL);
+ }
+
+ /**
+ * Does this walker want us to use a set of preset action regions instead of dynamically using the result of isActive?
+ * @return true if yes, false if no
+ */
+ public boolean hasPresetActiveRegions() {
+ return presetActiveRegions != null;
+ }
+
+ /**
+ * Get the set of preset active regions, or null if none were provided
+ * @return a set of genome locs specifying fixed active regions requested by the walker, or null if none exist
+ */
+ public GenomeLocSortedSet getPresetActiveRegions() {
+ return presetActiveRegions;
+ }
+
+ // Do we actually want to operate on the context?
+ public boolean filter(final RefMetaDataTracker tracker, final ReferenceContext ref, final AlignmentContext context) {
+ return true; // We are keeping all the reads
+ }
+
+ public EnumSet<ActiveRegionReadState> desiredReadStates() {
+ return EnumSet.of(ActiveRegionReadState.PRIMARY);
+ }
+
+ public final boolean wantsNonPrimaryReads() {
+ return desiredReadStates().contains(ActiveRegionReadState.NONPRIMARY);
+ }
+
+ public boolean wantsExtendedReads() {
+ return desiredReadStates().contains(ActiveRegionReadState.EXTENDED);
+ }
+
+ public boolean wantsUnmappedReads() {
+ return desiredReadStates().contains(ActiveRegionReadState.UNMAPPED);
+ }
+
+ // Determine probability of active status over the AlignmentContext
+ @Ensures({"result.isActiveProb >= 0.0", "result.isActiveProb <= 1.0"})
+ public abstract ActivityProfileState isActive(final RefMetaDataTracker tracker, final ReferenceContext ref, final AlignmentContext context);
+
+ // Map over the ActiveRegion
+ public abstract MapType map(final ActiveRegion activeRegion, final RefMetaDataTracker metaDataTracker);
+
+ public final GenomeLocSortedSet extendIntervals( final GenomeLocSortedSet intervals, final GenomeLocParser genomeLocParser, IndexedFastaSequenceFile reference ) {
+ final int activeRegionExtension = this.getClass().getAnnotation(ActiveRegionTraversalParameters.class).extension();
+ final List<GenomeLoc> allIntervals = new ArrayList<GenomeLoc>();
+ for( final GenomeLoc interval : intervals.toList() ) {
+ final int start = Math.max( 1, interval.getStart() - activeRegionExtension );
+ final int stop = Math.min( reference.getSequenceDictionary().getSequence(interval.getContig()).getSequenceLength(), interval.getStop() + activeRegionExtension );
+ allIntervals.add( genomeLocParser.createGenomeLoc(interval.getContig(), start, stop) );
+ }
+ return IntervalUtils.sortAndMergeIntervals(genomeLocParser, allIntervals, IntervalMergingRule.ALL);
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Allows.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Allows.java
new file mode 100644
index 0000000..7188fd0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Allows.java
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import java.lang.annotation.*;
+/**
+ * User: hanna
+ * Date: May 19, 2009
+ * Time: 10:05:01 AM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Determines what data sources are allowed by a given walker.
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface Allows {
+ DataSource[] value();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Attribution.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Attribution.java
new file mode 100644
index 0000000..ded2941
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Attribution.java
@@ -0,0 +1,39 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import java.lang.annotation.*;
+
+/**
+ * Allow users to provide attribution text that will appear prominently in the log output.
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface Attribution {
+ public String[] value();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/BAQMode.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/BAQMode.java
new file mode 100644
index 0000000..931381e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/BAQMode.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+
+import java.lang.annotation.*;
+
+/**
+ * User: hanna
+ * Date: May 14, 2009
+ * Time: 1:51:22 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Allows the walker to indicate what type of data it wants to consume.
+ */
+
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface BAQMode {
+ public abstract org.broadinstitute.gatk.utils.baq.BAQ.QualityMode QualityMode() default org.broadinstitute.gatk.utils.baq.BAQ.QualityMode.OVERWRITE_QUALS;
+ public abstract ReadTransformer.ApplicationTime ApplicationTime() default ReadTransformer.ApplicationTime.ON_INPUT;
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/By.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/By.java
new file mode 100644
index 0000000..3962c98
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/By.java
@@ -0,0 +1,53 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import java.lang.annotation.*;
+/**
+ * User: hanna
+ * Date: May 14, 2009
+ * Time: 1:51:22 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Allows the walker to indicate what type of data it wants to consume.
+ */
+
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface By {
+ DataSource value();
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/DataSource.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/DataSource.java
new file mode 100644
index 0000000..fab9840
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/DataSource.java
@@ -0,0 +1,58 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+/**
+ * User: hanna
+ * Date: May 14, 2009
+ * Time: 2:12:33 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Allow user to choose between a number of different data sources.
+ */
+public enum DataSource {
+ /**
+ * Does this walker require read (BAM) data to work?
+ */
+ READS,
+
+ /**
+ * Does this walker require reference data to work?
+ */
+ REFERENCE,
+
+ /**
+ * Does this walker require reference order data (VCF) to work?
+ */
+ REFERENCE_ORDERED_DATA
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Downsample.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Downsample.java
new file mode 100644
index 0000000..c112d7d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Downsample.java
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+
+import java.lang.annotation.*;
+
+/**
+ * Specifies a method for downsampling the reads passed to a given
+ * walker based on the input from that walker.
+ *
+ * @author hanna
+ * @version 0.1
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface Downsample {
+ DownsampleType by();
+ int toCoverage() default -1;
+ double toFraction() default -1.0F;
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/DuplicateWalker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/DuplicateWalker.java
new file mode 100644
index 0000000..96d2d5d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/DuplicateWalker.java
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.filters.NotPrimaryAlignmentFilter;
+import org.broadinstitute.gatk.engine.filters.UnmappedReadFilter;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mdepristo
+ * Date: Feb 22, 2009
+ * Time: 2:52:28 PM
+ * To change this template use File | Settings | File Templates.
+ */
+ at Requires({DataSource.READS,DataSource.REFERENCE})
+ at ReadFilters({UnmappedReadFilter.class,NotPrimaryAlignmentFilter.class})
+public abstract class DuplicateWalker<MapType, ReduceType> extends Walker<MapType, ReduceType> {
+ // Do we actually want to operate on the context?
+ public boolean filter(GenomeLoc loc, AlignmentContext context, Set<List<GATKSAMRecord>> readSets ) {
+ return true; // We are keeping all the reads
+ }
+
+ public abstract MapType map(GenomeLoc loc, AlignmentContext context, Set<List<GATKSAMRecord>> readSets );
+
+ // Given result of map function
+ public abstract ReduceType reduceInit();
+ public abstract ReduceType reduce(MapType value, ReduceType sum);
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/LocusWalker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/LocusWalker.java
new file mode 100644
index 0000000..1e7b0e5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/LocusWalker.java
@@ -0,0 +1,58 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+import org.broadinstitute.gatk.engine.filters.DuplicateReadFilter;
+import org.broadinstitute.gatk.engine.filters.FailsVendorQualityCheckFilter;
+import org.broadinstitute.gatk.engine.filters.NotPrimaryAlignmentFilter;
+import org.broadinstitute.gatk.engine.filters.UnmappedReadFilter;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mdepristo
+ * Date: Feb 22, 2009
+ * Time: 2:52:28 PM
+ * To change this template use File | Settings | File Templates.
+ */
+ at By(DataSource.READS)
+ at Requires({DataSource.READS,DataSource.REFERENCE})
+ at PartitionBy(PartitionType.LOCUS)
+ at ReadFilters({UnmappedReadFilter.class,NotPrimaryAlignmentFilter.class,DuplicateReadFilter.class,FailsVendorQualityCheckFilter.class})
+ at Downsample(by = DownsampleType.BY_SAMPLE, toCoverage = 1000)
+ at RemoveProgramRecords
+public abstract class LocusWalker<MapType, ReduceType> extends Walker<MapType, ReduceType> {
+ // Do we actually want to operate on the context?
+ public boolean filter(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ return true; // We are keeping all the reads
+ }
+
+ // Map over the org.broadinstitute.gatk.engine.contexts.AlignmentContext
+ public abstract MapType map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Multiplex.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Multiplex.java
new file mode 100644
index 0000000..e771d1e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Multiplex.java
@@ -0,0 +1,44 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import java.lang.annotation.*;
+
+/**
+ * Indicates that the class should be multiplexed according to the rules
+ * specified in the multiplexer.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.FIELD})
+public @interface Multiplex {
+ public Class<? extends Multiplexer> value();
+ public String[] arguments() default {};
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Multiplexer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Multiplexer.java
new file mode 100644
index 0000000..969e288
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Multiplexer.java
@@ -0,0 +1,52 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import java.util.Collection;
+
+/**
+ * An interface for multiplexing output streams.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public interface Multiplexer<T> {
+ /**
+ * Generate a list of the potential outputs that can be created as a function of the other
+ * command-line arguments in this class.
+ * @return A collection of unique identifiers for the file multiplex.
+ */
+ public Collection<T> multiplex();
+
+ /**
+ * Transform the given command-line argument into a suitable form specific to this filename.
+ * @param multiplexedEntry Identifies the individual component of the multiplex. Will be a value in the collection
+ * passed back by multiplex().
+ * @param argument The actual command-line argument, supplied for transformation.
+ * @return A transformed representation of the command-line argument.
+ */
+ public String transformArgument(final T multiplexedEntry, final String argument);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/NanoSchedulable.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/NanoSchedulable.java
new file mode 100644
index 0000000..5852b77
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/NanoSchedulable.java
@@ -0,0 +1,34 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+/**
+ * Root parallelism interface. Walkers that implement this
+ * declare that their map function is thread-safe and so multiple
+ * map calls can be run in parallel in the same JVM instance.
+ */
+public interface NanoSchedulable {
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/PartitionBy.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/PartitionBy.java
new file mode 100644
index 0000000..346f7c4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/PartitionBy.java
@@ -0,0 +1,39 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import java.lang.annotation.*;
+
+/**
+ * Allows the walker to indicate how to partition data it wants to consume.
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface PartitionBy {
+ PartitionType value();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/PartitionType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/PartitionType.java
new file mode 100644
index 0000000..2c738e1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/PartitionType.java
@@ -0,0 +1,61 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+/**
+ * Defines the ways walkers inputs can be partitioned before
+ * being passed to multiple instances of the walker.
+ */
+public enum PartitionType {
+ /**
+ * Do not partition the walker inputs.
+ */
+ NONE,
+
+ /**
+ * The walker inputs can be chunked down to individual
+ * reads.
+ */
+ READ,
+
+ /**
+ * The walker inputs can be chunked down to the
+ * per-locus level.
+ */
+ LOCUS,
+
+ /**
+ * The walker inputs should be processed as complete
+ * intervals defined -L or the reference contigs.
+ */
+ INTERVAL,
+
+ /**
+ * The walker inputs should always be processed as complete
+ * contigs, even if there are multiple intervals per contig.
+ */
+ CONTIG
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RMD.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RMD.java
new file mode 100644
index 0000000..a2ee8d0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RMD.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import htsjdk.tribble.Feature;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+/**
+ * User: hanna
+ * Date: May 19, 2009
+ * Time: 1:34:15 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * A data type representing reference-ordered data.
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+public @interface RMD {
+ String name();
+ Class type() default Feature.class;
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ReadFilters.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ReadFilters.java
new file mode 100644
index 0000000..eac5715
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ReadFilters.java
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import htsjdk.samtools.filter.SamRecordFilter;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+
+import java.lang.annotation.*;
+
+/**
+ * An annotation to describe what kind of data will be filtered out.
+ *
+ * @author hanna
+ * @version 0.1
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface ReadFilters {
+ public Class<? extends SamRecordFilter>[] value() default {};
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ReadPairWalker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ReadPairWalker.java
new file mode 100644
index 0000000..67eae69
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ReadPairWalker.java
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import htsjdk.samtools.SAMRecord;
+
+import java.util.Collection;
+
+/**
+ * Walks over all pairs/collections of reads in a BAM file sorted by
+ * read name.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+ at Requires({DataSource.READS})
+public abstract class ReadPairWalker<MapType,ReduceType> extends Walker<MapType,ReduceType> {
+
+ /**
+ * Optionally filters out read pairs.
+ * @param reads collections of all reads with the same read name.
+ * @return True to process the reads with map/reduce; false otherwise.
+ */
+ public boolean filter(Collection<SAMRecord> reads) {
+ // Keep all pairs by default.
+ return true;
+ }
+
+ /**
+ * Maps a read pair to a given reduce of type MapType. Semantics determined by subclasser.
+ * @param reads Collection of reads having the same name.
+ * @return Semantics defined by implementer.
+ */
+ public abstract MapType map(Collection<SAMRecord> reads);
+
+ // Given result of map function
+ public abstract ReduceType reduceInit();
+ public abstract ReduceType reduce(MapType value, ReduceType sum);
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ReadWalker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ReadWalker.java
new file mode 100644
index 0000000..9528cf1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/ReadWalker.java
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mdepristo
+ * Date: Feb 22, 2009
+ * Time: 2:52:28 PM
+ * To change this template use File | Settings | File Templates.
+ */
+ at Requires({DataSource.READS, DataSource.REFERENCE})
+ at PartitionBy(PartitionType.READ)
+public abstract class ReadWalker<MapType, ReduceType> extends Walker<MapType, ReduceType> {
+ public boolean requiresOrderedReads() { return false; }
+
+ // Do we actually want to operate on the context?
+ /** Must return true for reads that need to be processed. Reads, for which this method return false will
+ * be skipped by the engine and never passed to the walker.
+ */
+ public boolean filter(ReferenceContext ref, GATKSAMRecord read) {
+ // We are keeping all the reads
+ return true;
+ }
+
+ // Map over the org.broadinstitute.gatk.engine.contexts.AlignmentContext
+ public abstract MapType map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker metaDataTracker);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RefWalker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RefWalker.java
new file mode 100644
index 0000000..90c10c5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RefWalker.java
@@ -0,0 +1,39 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mdepristo
+ * Date: Feb 22, 2009
+ * Time: 2:52:28 PM
+ * To change this template use File | Settings | File Templates.
+ */
+ at By(DataSource.REFERENCE)
+ at Requires({DataSource.REFERENCE})
+ at Allows(DataSource.REFERENCE)
+public abstract class RefWalker<MapType, ReduceType> extends LocusWalker<MapType, ReduceType> {
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Reference.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Reference.java
new file mode 100644
index 0000000..3598cf5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Reference.java
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import java.lang.annotation.*;
+
+/**
+ * Describes presentation, capabilities, and limitations of the reference
+ * provided to the GATK.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface Reference {
+ /**
+ * Specifies the window expansion for the current walker.
+ * @return The window to which the reference should be expanded. Defaults to [0,0] (no expansion).
+ */
+ public Window window() default @Window;
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RemoveProgramRecords.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RemoveProgramRecords.java
new file mode 100644
index 0000000..ad945f2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RemoveProgramRecords.java
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: thibault
+ * Date: 8/2/12
+ * Time: 1:58 PM
+ * To change this template use File | Settings | File Templates.
+ */
+
+import java.lang.annotation.*;
+
+/**
+ * Indicates that program records should be removed from SAM headers by default for this walker
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface RemoveProgramRecords {
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Requires.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Requires.java
new file mode 100644
index 0000000..5a16a67
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Requires.java
@@ -0,0 +1,52 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import java.lang.annotation.*;
+/**
+ * User: hanna
+ * Date: May 19, 2009
+ * Time: 10:06:47 AM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Determines what data sources are mandated by a given walker.
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface Requires {
+ DataSource[] value();
+ RMD[] referenceMetaData() default {};
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RodWalker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RodWalker.java
new file mode 100644
index 0000000..88a1eaa
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/RodWalker.java
@@ -0,0 +1,39 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mdepristo
+ * Date: Feb 22, 2009
+ * Time: 2:52:28 PM
+ * To change this template use File | Settings | File Templates.
+ */
+ at By(DataSource.REFERENCE_ORDERED_DATA)
+ at Requires({DataSource.REFERENCE, DataSource.REFERENCE_ORDERED_DATA})
+ at Allows({DataSource.REFERENCE, DataSource.REFERENCE_ORDERED_DATA})
+public abstract class RodWalker<MapType, ReduceType> extends LocusWalker<MapType, ReduceType> {
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/TreeReducible.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/TreeReducible.java
new file mode 100644
index 0000000..c170f3d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/TreeReducible.java
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mhanna
+ * Date: Apr 26, 2009
+ * Time: 5:34:11 PM
+ * To change this template use File | Settings | File Templates.
+ */
+
+/**
+ * Indicates that a class is tree reducible, aka that any two adjacent
+ * shards of the data can reduce with each other, and the composite result
+ * can be reduced with other composite results.
+ */
+public interface TreeReducible<ReduceType> {
+ /**
+ * A composite, 'reduce of reduces' function.
+ * @param lhs 'left-most' portion of data in the composite reduce.
+ * @param rhs 'right-most' portion of data in the composite reduce.
+ * @return The composite reduce type.
+ */
+ ReduceType treeReduce(ReduceType lhs, ReduceType rhs);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Walker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Walker.java
new file mode 100644
index 0000000..31472fd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Walker.java
@@ -0,0 +1,177 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+import org.broadinstitute.gatk.engine.filters.MalformedReadFilter;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.engine.samples.Sample;
+import org.broadinstitute.gatk.engine.samples.SampleDB;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.baq.BAQ;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.recalibration.BQSRMode;
+
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: hanna
+ * Date: Mar 17, 2009
+ * Time: 1:53:31 PM
+ * To change this template use File | Settings | File Templates.
+ */
+ at ReadFilters(MalformedReadFilter.class)
+ at PartitionBy(PartitionType.NONE)
+ at Downsample(by = DownsampleType.NONE)
+ at BAQMode(QualityMode = BAQ.QualityMode.OVERWRITE_QUALS, ApplicationTime = ReadTransformer.ApplicationTime.ON_INPUT)
+ at BQSRMode(ApplicationTime = ReadTransformer.ApplicationTime.ON_INPUT)
+ at DocumentedGATKFeature(groupName = "Uncategorized", extraDocs = {CommandLineGATK.class})
+public abstract class Walker<MapType, ReduceType> {
+ final protected static Logger logger = Logger.getLogger(Walker.class);
+ private GenomeAnalysisEngine toolkit;
+
+ protected Walker() {
+ }
+
+ /**
+ * Set the toolkit, for peering into internal structures that can't
+ * otherwise be read.
+ * @param toolkit The genome analysis toolkit.
+ */
+ public void setToolkit(GenomeAnalysisEngine toolkit) {
+ this.toolkit = toolkit;
+ }
+
+ /**
+ * Retrieve the toolkit, for peering into internal structures that can't
+ * otherwise be read. Use sparingly, and discuss uses with software engineering
+ * team.
+ * @return The genome analysis toolkit.
+ */
+ protected GenomeAnalysisEngine getToolkit() {
+ return toolkit;
+ }
+
+ /**
+ * Gets the master sequence dictionary for this walker
+ * @link GenomeAnalysisEngine.getMasterSequenceDictionary
+ * @return
+ */
+ protected SAMSequenceDictionary getMasterSequenceDictionary() {
+ return getToolkit().getMasterSequenceDictionary();
+ }
+
+ public SampleDB getSampleDB() {
+ return getToolkit().getSampleDB();
+ }
+
+ protected Sample getSample(final String id) {
+ return getToolkit().getSampleDB().getSample(id);
+ }
+
+ /**
+ * (conceptual static) method that states whether you want to see reads piling up at a locus
+ * that contain a deletion at the locus.
+ *
+ * ref: ATCTGA
+ * read1: ATCTGA
+ * read2: AT--GA
+ *
+ * Normally, the locus iterator only returns a list of read1 at this locus at position 3, but
+ * if this function returns true, then the system will return (read1, read2) with offsets
+ * of (3, -1). The -1 offset indicates a deletion in the read.
+ *
+ * @return false if you don't want to see deletions, or true if you do
+ */
+ public boolean includeReadsWithDeletionAtLoci() {
+ return false;
+ }
+
+ public void initialize() { }
+
+ /**
+ * A function for overloading in subclasses providing a mechanism to abort early from a walker.
+ *
+ * If this ever returns true, then the Traversal engine will stop executing map calls
+ * and start the process of shutting down the walker in an orderly fashion.
+ * @return
+ */
+ public boolean isDone() {
+ return false;
+ }
+
+ /**
+ * Provide an initial value for reduce computations.
+ * @return Initial value of reduce.
+ */
+ public abstract ReduceType reduceInit();
+
+ /**
+ * Reduces a single map with the accumulator provided as the ReduceType.
+ * @param value result of the map.
+ * @param sum accumulator for the reduce.
+ * @return accumulator with result of the map taken into account.
+ */
+ public abstract ReduceType reduce(MapType value, ReduceType sum);
+
+ public void onTraversalDone(ReduceType result) {
+ logger.info("[REDUCE RESULT] Traversal result is: " + result);
+ }
+
+ /**
+ * General interval reduce routine called after all of the traversals are done
+ * @param results interval reduce results
+ */
+ public void onTraversalDone(List<Pair<GenomeLoc, ReduceType>> results) {
+ for ( Pair<GenomeLoc, ReduceType> result : results ) {
+ logger.info(String.format("[INTERVAL REDUCE RESULT] at %s ", result.getFirst()));
+ this.onTraversalDone(result.getSecond());
+ }
+ }
+
+ /**
+ * Return true if your walker wants to reduce each interval separately. Default is false.
+ *
+ * If you set this flag, several things will happen.
+ *
+ * The system will invoke reduceInit() once for each interval being processed, starting a fresh reduce
+ * Reduce will accumulate normally at each map unit in the interval
+ * However, onTraversalDone(reduce) will be called after each interval is processed.
+ * The system will call onTraversalDone( GenomeLoc -> reduce ), after all reductions are done,
+ * which is overloaded here to call onTraversalDone(reduce) for each location
+ *
+ * @return true if your walker wants to reduce each interval separately.
+ */
+ public boolean isReduceByInterval() {
+ return false;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/WalkerName.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/WalkerName.java
new file mode 100644
index 0000000..9e02bf1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/WalkerName.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import java.lang.annotation.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: hanna
+ * Date: Mar 26, 2009
+ * Time: 3:00:16 PM
+ * To change this template use File | Settings | File Templates.
+ */
+ at Documented
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface WalkerName {
+ public String value() default "";
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Window.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Window.java
new file mode 100644
index 0000000..66205b9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/Window.java
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Describes the size of the window into the genome. Has differing semantics based on
+ * the data this annotation is used to describe.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+public @interface Window {
+ /**
+ * Controls where the window should start and stop relative to
+ * the locus currently being processed.
+ * @return start point; default is 0, indicating 'supply only the reference base at the current locus'.
+ */
+ public int start() default 0;
+
+ /**
+ * Controls where the window should start and stop relative to
+ * the locus currently being processed.
+ * @return stop point; default is 0, indicating 'supply only the reference base at the current locus'.
+ */
+ public int stop() default 0;
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/BAMDiffableReader.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/BAMDiffableReader.java
new file mode 100644
index 0000000..2c8cc7a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/BAMDiffableReader.java
@@ -0,0 +1,119 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers.diffengine;
+
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMRecordIterator;
+import htsjdk.samtools.ValidationStringency;
+import htsjdk.samtools.util.BlockCompressedInputStream;
+
+import java.io.*;
+import java.util.Arrays;
+
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: 7/4/11
+ * Time: 1:09 PM
+ *
+ * Class implementing diffnode reader for VCF
+ */
+public class BAMDiffableReader implements DiffableReader {
+ @Override
+ public String getName() { return "BAM"; }
+
+ @Override
+ public DiffElement readFromFile(File file, int maxElementsToRead) {
+ final SAMFileReader reader = new SAMFileReader(file, null); // null because we don't want it to look for the index
+ reader.setValidationStringency(ValidationStringency.SILENT);
+
+ DiffNode root = DiffNode.rooted(file.getName());
+ SAMRecordIterator iterator = reader.iterator();
+
+ int count = 0;
+ while ( iterator.hasNext() ) {
+ final SAMRecord record = iterator.next();
+
+ // name is the read name + first of pair
+ String name = record.getReadName().replace('.', '_');
+ if ( record.getReadPairedFlag() ) {
+ name += record.getFirstOfPairFlag() ? "_1" : "_2";
+ }
+
+ DiffNode readRoot = DiffNode.empty(name, root);
+
+ // add fields
+ readRoot.add("NAME", record.getReadName());
+ readRoot.add("FLAGS", record.getFlags());
+ readRoot.add("RNAME", record.getReferenceName());
+ readRoot.add("POS", record.getAlignmentStart());
+ readRoot.add("MAPQ", record.getMappingQuality());
+ readRoot.add("CIGAR", record.getCigarString());
+ readRoot.add("RNEXT", record.getMateReferenceName());
+ readRoot.add("PNEXT", record.getMateAlignmentStart());
+ readRoot.add("TLEN", record.getInferredInsertSize());
+ readRoot.add("SEQ", record.getReadString());
+ readRoot.add("QUAL", record.getBaseQualityString());
+
+ for ( SAMRecord.SAMTagAndValue xt : record.getAttributes() ) {
+ readRoot.add(xt.tag, xt.value);
+ }
+
+ // add record to root
+ if ( ! root.hasElement(name) )
+ // protect ourselves from malformed files
+ root.add(readRoot);
+ count += readRoot.size();
+ if ( count > maxElementsToRead && maxElementsToRead != -1)
+ break;
+ }
+
+ reader.close();
+
+ return root.getBinding();
+ }
+
+ @Override
+ public boolean canRead(File file) {
+ final byte[] BAM_MAGIC = "BAM\1".getBytes();
+ final byte[] buffer = new byte[BAM_MAGIC.length];
+ try {
+ InputStream fstream = new BufferedInputStream(new FileInputStream(file));
+ if ( !BlockCompressedInputStream.isValidFile(fstream) )
+ return false;
+ final BlockCompressedInputStream BCIS = new BlockCompressedInputStream(fstream);
+ BCIS.read(buffer, 0, BAM_MAGIC.length);
+ BCIS.close();
+ return Arrays.equals(buffer, BAM_MAGIC);
+ } catch ( IOException e ) {
+ return false;
+ } catch ( htsjdk.samtools.FileTruncatedException e ) {
+ return false;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffElement.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffElement.java
new file mode 100644
index 0000000..ebed914
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffElement.java
@@ -0,0 +1,125 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers.diffengine;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Invariant;
+import com.google.java.contract.Requires;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: 7/4/11
+ * Time: 12:55 PM
+ *
+ * An interface that must be implemented to allow us to calculate differences
+ * between structured objects
+ */
+ at Invariant({
+ "name != null",
+ "value != null",
+ "parent != null || name.equals(\"ROOT\")",
+ "value == null || value.getBinding() == this"})
+public class DiffElement {
+ public final static DiffElement ROOT = new DiffElement();
+
+ final private String name;
+ final private DiffElement parent;
+ final private DiffValue value;
+
+ /**
+ * For ROOT only
+ */
+ private DiffElement() {
+ this.name = "ROOT";
+ this.parent = null;
+ this.value = new DiffValue(this, "ROOT");
+ }
+
+ @Requires({"name != null", "parent != null", "value != null"})
+ public DiffElement(String name, DiffElement parent, DiffValue value) {
+ if ( name.equals("ROOT") ) throw new IllegalArgumentException("Cannot use reserved name ROOT");
+ this.name = name;
+ this.parent = parent;
+ this.value = value;
+ this.value.setBinding(this);
+ }
+
+ @Ensures({"result != null"})
+ public String getName() {
+ return name;
+ }
+
+ public DiffElement getParent() {
+ return parent;
+ }
+
+ @Ensures({"result != null"})
+ public DiffValue getValue() {
+ return value;
+ }
+
+ public boolean isRoot() { return this == ROOT; }
+
+ @Ensures({"result != null"})
+ @Override
+ public String toString() {
+ return getName() + "=" + getValue().toString();
+ }
+
+ public String toString(int offset) {
+ return (offset > 0 ? Utils.dupString(' ', offset) : 0) + getName() + "=" + getValue().toString(offset);
+ }
+
+ @Ensures({"result != null"})
+ public final String fullyQualifiedName() {
+ if ( isRoot() )
+ return "";
+ else if ( parent.isRoot() )
+ return name;
+ else
+ return parent.fullyQualifiedName() + "." + name;
+ }
+
+ @Ensures({"result != null"})
+ public String toOneLineString() {
+ return getName() + "=" + getValue().toOneLineString();
+ }
+
+ @Ensures({"result != null"})
+ public DiffNode getValueAsNode() {
+ if ( getValue().isCompound() )
+ return (DiffNode)getValue();
+ else
+ throw new ReviewedGATKException("Illegal request conversion of a DiffValue into a DiffNode: " + this);
+ }
+
+ public int size() {
+ return 1 + getValue().size();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffEngine.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffEngine.java
new file mode 100644
index 0000000..d10cfea
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffEngine.java
@@ -0,0 +1,437 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers.diffengine;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.report.GATKReport;
+import org.broadinstitute.gatk.engine.report.GATKReportTable;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.classloader.PluginManager;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.util.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: 7/4/11
+ * Time: 12:51 PM
+ * A generic engine for comparing tree-structured objects
+ *
+ */
+public class DiffEngine {
+ final protected static Logger logger = Logger.getLogger(DiffEngine.class);
+
+ private final Map<String, DiffableReader> readers = new HashMap<String, DiffableReader>();
+
+ public DiffEngine() {
+ loadDiffableReaders();
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // difference calculation
+ //
+ // --------------------------------------------------------------------------------
+
+ public List<Difference> diff(DiffElement master, DiffElement test) {
+ DiffValue masterValue = master.getValue();
+ DiffValue testValue = test.getValue();
+
+ if ( masterValue.isCompound() && masterValue.isCompound() ) {
+ return diff(master.getValueAsNode(), test.getValueAsNode());
+ } else if ( masterValue.isAtomic() && testValue.isAtomic() ) {
+ return diff(masterValue, testValue);
+ } else {
+ // structural difference in types. one is node, other is leaf
+ return Arrays.asList(new Difference(master, test));
+ }
+ }
+
+ public List<Difference> diff(DiffNode master, DiffNode test) {
+ Set<String> allNames = new HashSet<String>(master.getElementNames());
+ allNames.addAll(test.getElementNames());
+ List<Difference> diffs = new ArrayList<Difference>();
+
+ for ( String name : allNames ) {
+ DiffElement masterElt = master.getElement(name);
+ DiffElement testElt = test.getElement(name);
+ if ( masterElt == null && testElt == null ) {
+ throw new ReviewedGATKException("BUG: unexpectedly got two null elements for field: " + name);
+ } else if ( masterElt == null || testElt == null ) { // if either is null, we are missing a value
+ // todo -- should one of these be a special MISSING item?
+ diffs.add(new Difference(masterElt, testElt));
+ } else {
+ diffs.addAll(diff(masterElt, testElt));
+ }
+ }
+
+ return diffs;
+ }
+
+ public List<Difference> diff(DiffValue master, DiffValue test) {
+ if ( master.getValue().equals(test.getValue()) ) {
+ return Collections.emptyList();
+ } else {
+ return Arrays.asList(new Difference(master.getBinding(), test.getBinding()));
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Summarizing differences
+ //
+ // --------------------------------------------------------------------------------
+
+ /**
+ * Emits a summary of the diffs to out. Suppose you have the following three differences:
+ *
+ * A.X.Z:1!=2
+ * A.Y.Z:3!=4
+ * B.X.Z:5!=6
+ *
+ * The above is the itemized list of the differences. The summary looks for common differences
+ * in the name hierarchy, counts those shared elements, and emits the differences that occur
+ * in order of decreasing counts.
+ *
+ * So, in the above example, what are the shared elements?
+ *
+ * A.X.Z and B.X.Z share X.Z, so there's a *.X.Z with count 2
+ * A.X.Z, A.Y.Z, and B.X.Z all share *.*.Z, with count 3
+ * Each of A.X.Z, A.Y.Z, and B.X.Z are individually unique, with count 1
+ *
+ * So we would emit the following summary:
+ *
+ * *.*.Z: 3
+ * *.X.Z: 2
+ * A.X.Z: 1 [specific difference: 1!=2]
+ * A.Y.Z: 1 [specific difference: 3!=4]
+ * B.X.Z: 1 [specific difference: 5!=6]
+ *
+ * The algorithm to accomplish this calculation is relatively simple. Start with all of the
+ * concrete differences. For each pair of differences A1.A2....AN and B1.B2....BN:
+ *
+ * find the longest common subsequence Si.Si+1...SN where Ai = Bi = Si
+ * If i == 0, then there's no shared substructure
+ * If i > 0, then generate the summarized value X = *.*...Si.Si+1...SN
+ * if X is a known summary, increment it's count, otherwise set its count to 1
+ *
+ * Not that only pairs of the same length are considered as potentially equivalent
+ *
+ * @param params determines how we display the items
+ * @param diffs the list of differences to summarize
+ */
+ public void reportSummarizedDifferences(List<Difference> diffs, SummaryReportParams params ) {
+ printSummaryReport(summarizedDifferencesOfPaths(diffs, params.doPairwise, params.maxRawDiffsToSummarize), params );
+ }
+
+ final protected static String[] diffNameToPath(String diffName) {
+ return diffName.split("\\.");
+ }
+
+ protected List<Difference> summarizedDifferencesOfPathsFromString(List<String> singletonDiffs) {
+ List<Difference> diffs = new ArrayList<Difference>();
+
+ for ( String diff : singletonDiffs ) {
+ diffs.add(new Difference(diff));
+ }
+
+ return summarizedDifferencesOfPaths(diffs, true, -1);
+ }
+
+ /**
+ * Computes a minimum set of potential differences between all singleton differences
+ * in singletonDiffs. Employs an expensive pairwise O(n^2) algorithm.
+ *
+ * @param singletonDiffs
+ * @param maxRawDiffsToSummarize
+ * @return
+ */
+ private Map<String, Difference> initialPairwiseSummaries(final List<? extends Difference> singletonDiffs,
+ final int maxRawDiffsToSummarize) {
+ Map<String, Difference> summaries = new HashMap<String, Difference>();
+
+ // create the initial set of differences
+ for ( int i = 0; i < singletonDiffs.size(); i++ ) {
+ for ( int j = 0; j <= i; j++ ) {
+ Difference diffPath1 = singletonDiffs.get(i);
+ Difference diffPath2 = singletonDiffs.get(j);
+ if ( diffPath1.length() == diffPath2.length() ) {
+ int lcp = longestCommonPostfix(diffPath1.getParts(), diffPath2.getParts());
+ String path = diffPath2.getPath();
+ if ( lcp != 0 && lcp != diffPath1.length() )
+ path = summarizedPath(diffPath2.getParts(), lcp);
+ Difference sumDiff = new Difference(path, diffPath2.getMaster(), diffPath2.getTest());
+ sumDiff.setCount(0);
+ addSummaryIfMissing(summaries, sumDiff);
+
+ if ( maxRawDiffsToSummarize != -1 && summaries.size() > maxRawDiffsToSummarize)
+ return summaries;
+ }
+ }
+ }
+
+ return summaries;
+ }
+
+ /**
+ * Computes the possible leaf differences among the singleton diffs.
+ *
+ * The leaf differences are all of the form *.*...*.X where all internal
+ * differences are wildcards and the only summarized difference considered
+ * interesting to compute is
+ *
+ * @param singletonDiffs
+ * @param maxRawDiffsToSummarize
+ * @return
+ */
+ private Map<String, Difference> initialLeafSummaries(final List<? extends Difference> singletonDiffs,
+ final int maxRawDiffsToSummarize) {
+ Map<String, Difference> summaries = new HashMap<String, Difference>();
+
+ // create the initial set of differences
+ for ( final Difference d : singletonDiffs ) {
+ final String path = summarizedPath(d.getParts(), 1);
+ Difference sumDiff = new Difference(path, d.getMaster(), d.getTest());
+ sumDiff.setCount(0);
+ addSummaryIfMissing(summaries, sumDiff);
+
+ if ( maxRawDiffsToSummarize != -1 && summaries.size() > maxRawDiffsToSummarize)
+ return summaries;
+ }
+
+ return summaries;
+ }
+
+ protected List<Difference> summarizedDifferencesOfPaths(final List<? extends Difference> singletonDiffs,
+ final boolean doPairwise,
+ final int maxRawDiffsToSummarize) {
+ final Map<String, Difference> summaries = doPairwise
+ ? initialPairwiseSummaries(singletonDiffs, maxRawDiffsToSummarize)
+ : initialLeafSummaries(singletonDiffs, maxRawDiffsToSummarize);
+
+ // count differences
+ for ( Difference diffPath : singletonDiffs ) {
+ for ( Difference sumDiff : summaries.values() ) {
+ if ( sumDiff.matches(diffPath.getParts()) )
+ sumDiff.incCount();
+ }
+ }
+
+ List<Difference> sortedSummaries = new ArrayList<Difference>(summaries.values());
+ Collections.sort(sortedSummaries);
+ return sortedSummaries;
+ }
+
+ protected void addSummaryIfMissing(Map<String, Difference> summaries, Difference diff) {
+ if ( ! summaries.containsKey(diff.getPath()) ) {
+ summaries.put(diff.getPath(), diff);
+ }
+ }
+
+ protected void printSummaryReport(List<Difference> sortedSummaries, SummaryReportParams params ) {
+ List<Difference> toShow = new ArrayList<Difference>();
+ int count = 0, count1 = 0;
+ for ( Difference diff : sortedSummaries ) {
+ if ( diff.getCount() < params.minSumDiffToShow )
+ // in order, so break as soon as the count is too low
+ break;
+
+ if ( params.maxItemsToDisplay != 0 && count++ > params.maxItemsToDisplay )
+ break;
+
+ if ( diff.getCount() == 1 ) {
+ count1++;
+ if ( params.maxCountOneItems != 0 && count1 > params.maxCountOneItems )
+ break;
+ }
+
+ toShow.add(diff);
+ }
+
+ // if we want it in descending order, reverse the list
+ if ( ! params.descending ) {
+ Collections.reverse(toShow);
+ }
+
+ // now that we have a specific list of values we want to show, display them
+ GATKReport report = new GATKReport();
+ final String tableName = "differences";
+ report.addTable(tableName, "Summarized differences between the master and test files. See http://www.broadinstitute.org/gatk/guide/article?id=1299 for more information", 3);
+ final GATKReportTable table = report.getTable(tableName);
+ table.addColumn("Difference");
+ table.addColumn("NumberOfOccurrences");
+ table.addColumn("ExampleDifference");
+ for ( final Difference diff : toShow ) {
+ final String key = diff.getPath();
+ table.addRowID(key, true);
+ table.set(key, "NumberOfOccurrences", diff.getCount());
+ table.set(key, "ExampleDifference", diff.valueDiffString());
+ }
+ GATKReport output = new GATKReport(table);
+ output.print(params.out);
+ }
+
+ protected static int longestCommonPostfix(String[] diffPath1, String[] diffPath2) {
+ int i = 0;
+ for ( ; i < diffPath1.length; i++ ) {
+ int j = diffPath1.length - i - 1;
+ if ( ! diffPath1[j].equals(diffPath2[j]) )
+ break;
+ }
+ return i;
+ }
+
+ /**
+ * parts is [A B C D]
+ * commonPostfixLength: how many parts are shared at the end, suppose its 2
+ * We want to create a string *.*.C.D
+ *
+ * @param parts the separated path values [above without .]
+ * @param commonPostfixLength
+ * @return
+ */
+ protected static String summarizedPath(String[] parts, int commonPostfixLength) {
+ int stop = parts.length - commonPostfixLength;
+ if ( stop > 0 ) parts = parts.clone();
+ for ( int i = 0; i < stop; i++ ) {
+ parts[i] = "*";
+ }
+ return Utils.join(".", parts);
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // plugin manager
+ //
+ // --------------------------------------------------------------------------------
+
+ public void loadDiffableReaders() {
+ List<Class<? extends DiffableReader>> drClasses = new PluginManager<DiffableReader>( DiffableReader.class ).getPlugins();
+
+ logger.info("Loading diffable modules:");
+ for (Class<? extends DiffableReader> drClass : drClasses ) {
+ logger.info("\t" + drClass.getSimpleName());
+
+ try {
+ DiffableReader dr = drClass.newInstance();
+ readers.put(dr.getName(), dr);
+ } catch (InstantiationException e) {
+ throw new ReviewedGATKException("Unable to instantiate module '" + drClass.getSimpleName() + "'");
+ } catch (IllegalAccessException e) {
+ throw new ReviewedGATKException("Illegal access error when trying to instantiate '" + drClass.getSimpleName() + "'");
+ }
+ }
+ }
+
+ protected Map<String, DiffableReader> getReaders() {
+ return readers;
+ }
+
+ protected DiffableReader getReader(String name) {
+ return readers.get(name);
+ }
+
+ /**
+ * Returns a reader appropriate for this file, or null if no such reader exists
+ * @param file
+ * @return
+ */
+ public DiffableReader findReaderForFile(File file) {
+ for ( DiffableReader reader : readers.values() )
+ if (reader.canRead(file) )
+ return reader;
+
+ return null;
+ }
+
+ /**
+ * Returns true if reader appropriate for this file, or false if no such reader exists
+ * @param file
+ * @return
+ */
+ public boolean canRead(File file) {
+ return findReaderForFile(file) != null;
+ }
+
+
+ public DiffElement createDiffableFromFile(File file) {
+ return createDiffableFromFile(file, -1);
+ }
+
+ public DiffElement createDiffableFromFile(File file, int maxElementsToRead) {
+ DiffableReader reader = findReaderForFile(file);
+ if ( reader == null )
+ throw new UserException("Unsupported file type: " + file);
+ else
+ return reader.readFromFile(file, maxElementsToRead);
+ }
+
+ public static boolean simpleDiffFiles(File masterFile, File testFile, int maxElementsToRead, DiffEngine.SummaryReportParams params) {
+ DiffEngine diffEngine = new DiffEngine();
+
+ if ( diffEngine.canRead(masterFile) && diffEngine.canRead(testFile) ) {
+ DiffElement master = diffEngine.createDiffableFromFile(masterFile, maxElementsToRead);
+ DiffElement test = diffEngine.createDiffableFromFile(testFile, maxElementsToRead);
+ List<Difference> diffs = diffEngine.diff(master, test);
+ diffEngine.reportSummarizedDifferences(diffs, params);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public static class SummaryReportParams {
+ final PrintStream out;
+ final int maxItemsToDisplay;
+ final int maxCountOneItems;
+ final int minSumDiffToShow;
+ final int maxRawDiffsToSummarize;
+ final boolean doPairwise;
+ boolean descending = true;
+
+ public SummaryReportParams(PrintStream out,
+ int maxItemsToDisplay,
+ int maxCountOneItems,
+ int minSumDiffToShow,
+ int maxRawDiffsToSummarize,
+ final boolean doPairwise) {
+ this.out = out;
+ this.maxItemsToDisplay = maxItemsToDisplay;
+ this.maxCountOneItems = maxCountOneItems;
+ this.minSumDiffToShow = minSumDiffToShow;
+ this.maxRawDiffsToSummarize = maxRawDiffsToSummarize;
+ this.doPairwise = doPairwise;
+ }
+
+ public void setDescending(boolean descending) {
+ this.descending = descending;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffNode.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffNode.java
new file mode 100644
index 0000000..dde9ca5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffNode.java
@@ -0,0 +1,249 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers.diffengine;
+
+import com.google.java.contract.Requires;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: 7/4/11
+ * Time: 12:55 PM
+ *
+ * An interface that must be implemented to allow us to calculate differences
+ * between structured objects
+ */
+public class DiffNode extends DiffValue {
+ private Map<String, DiffElement> getElementMap() {
+ return (Map<String, DiffElement>)super.getValue();
+ }
+ private static Map<String, DiffElement> emptyElements() { return new HashMap<String, DiffElement>(); }
+
+ private DiffNode(Map<String, DiffElement> elements) {
+ super(elements);
+ }
+
+ private DiffNode(DiffElement binding, Map<String, DiffElement> elements) {
+ super(binding, elements);
+ }
+
+ // ---------------------------------------------------------------------------
+ //
+ // constructors
+ //
+ // ---------------------------------------------------------------------------
+
+ public static DiffNode rooted(String name) {
+ return empty(name, DiffElement.ROOT);
+ }
+
+ public static DiffNode empty(String name, DiffElement parent) {
+ DiffNode df = new DiffNode(emptyElements());
+ DiffElement elt = new DiffElement(name, parent, df);
+ df.setBinding(elt);
+ return df;
+ }
+
+ public static DiffNode empty(String name, DiffValue parent) {
+ return empty(name, parent.getBinding());
+ }
+
+ // ---------------------------------------------------------------------------
+ //
+ // accessors
+ //
+ // ---------------------------------------------------------------------------
+
+ @Override
+ public boolean isAtomic() { return false; }
+
+ public Collection<String> getElementNames() {
+ return getElementMap().keySet();
+ }
+
+ public Collection<DiffElement> getElements() {
+ return getElementMap().values();
+ }
+
+ private Collection<DiffElement> getElements(boolean atomicOnly) {
+ List<DiffElement> elts = new ArrayList<DiffElement>();
+ for ( DiffElement elt : getElements() )
+ if ( (atomicOnly && elt.getValue().isAtomic()) || (! atomicOnly && elt.getValue().isCompound()))
+ elts.add(elt);
+ return elts;
+ }
+
+ public Collection<DiffElement> getAtomicElements() {
+ return getElements(true);
+ }
+
+ public Collection<DiffElement> getCompoundElements() {
+ return getElements(false);
+ }
+
+ /**
+ * Returns the element bound to name, or null if no such binding exists
+ * @param name
+ * @return
+ */
+ public DiffElement getElement(String name) {
+ return getElementMap().get(name);
+ }
+
+ /**
+ * Returns true if name is bound in this node
+ * @param name
+ * @return
+ */
+ public boolean hasElement(String name) {
+ return getElement(name) != null;
+ }
+
+ // ---------------------------------------------------------------------------
+ //
+ // add
+ //
+ // ---------------------------------------------------------------------------
+
+ @Requires("elt != null")
+ public void add(DiffElement elt) {
+ if ( getElementMap().containsKey(elt.getName()) )
+ throw new IllegalArgumentException("Attempting to rebind already existing binding: " + elt + " node=" + this);
+ getElementMap().put(elt.getName(), elt);
+ }
+
+ @Requires("elt != null")
+ public void add(DiffValue elt) {
+ add(elt.getBinding());
+ }
+
+ @Requires("elts != null")
+ public void add(Collection<DiffElement> elts) {
+ for ( DiffElement e : elts )
+ add(e);
+ }
+
+ public void add(String name, Object value) {
+ add(new DiffElement(name, this.getBinding(), new DiffValue(value)));
+ }
+
+ public int size() {
+ int count = 0;
+ for ( DiffElement value : getElements() )
+ count += value.size();
+ return count;
+ }
+
+ // ---------------------------------------------------------------------------
+ //
+ // toString
+ //
+ // ---------------------------------------------------------------------------
+
+ @Override
+ public String toString() {
+ return toString(0);
+ }
+
+ @Override
+ public String toString(int offset) {
+ String off = offset > 0 ? Utils.dupString(' ', offset) : "";
+ StringBuilder b = new StringBuilder();
+
+ b.append("(").append("\n");
+ Collection<DiffElement> atomicElts = getAtomicElements();
+ for ( DiffElement elt : atomicElts ) {
+ b.append(elt.toString(offset + 2)).append('\n');
+ }
+
+ for ( DiffElement elt : getCompoundElements() ) {
+ b.append(elt.toString(offset + 4)).append('\n');
+ }
+ b.append(off).append(")").append("\n");
+
+ return b.toString();
+ }
+
+ @Override
+ public String toOneLineString() {
+ StringBuilder b = new StringBuilder();
+
+ b.append('(');
+ List<String> parts = new ArrayList<String>();
+ for ( DiffElement elt : getElements() )
+ parts.add(elt.toOneLineString());
+ b.append(Utils.join(" ", parts));
+ b.append(')');
+
+ return b.toString();
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // fromString and toOneLineString
+ //
+ // --------------------------------------------------------------------------------
+
+ public static DiffElement fromString(String tree) {
+ return fromString(tree, DiffElement.ROOT);
+ }
+
+ /**
+ * Doesn't support full tree structure parsing
+ * @param tree
+ * @param parent
+ * @return
+ */
+ private static DiffElement fromString(String tree, DiffElement parent) {
+ // X=(A=A B=B C=(D=D))
+ String[] parts = tree.split("=", 2);
+ if ( parts.length != 2 )
+ throw new ReviewedGATKException("Unexpected tree structure: " + tree);
+ String name = parts[0];
+ String value = parts[1];
+
+ if ( value.length() == 0 )
+ throw new ReviewedGATKException("Illegal tree structure: " + value + " at " + tree);
+
+ if ( value.charAt(0) == '(' ) {
+ if ( ! value.endsWith(")") )
+ throw new ReviewedGATKException("Illegal tree structure. Missing ): " + value + " at " + tree);
+ String subtree = value.substring(1, value.length()-1);
+ DiffNode rec = DiffNode.empty(name, parent);
+ String[] subParts = subtree.split(" ");
+ for ( String subPart : subParts ) {
+ rec.add(fromString(subPart, rec.getBinding()));
+ }
+ return rec.getBinding();
+ } else {
+ return new DiffValue(name, parent, value).getBinding();
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffObjects.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffObjects.java
new file mode 100644
index 0000000..c622e24
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffObjects.java
@@ -0,0 +1,276 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers.diffengine;
+
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.util.List;
+
+/**
+ * A generic engine for comparing tree-structured objects
+ *
+ * <p>
+ * Compares two record-oriented files, itemizing specific difference between equivalent
+ * records in the two files. Reports both itemized and summarized differences.
+ * </p>
+ *
+ * <h3>What are the summarized differences and the DiffObjectsWalker?</h3>
+ *
+ * <p>
+ * The GATK contains a summarizing difference engine that compares hierarchical data structures to emit:
+ * <ul>
+ * <li>A list of specific differences between the two data structures. This is similar to saying the value in field A in record 1 in file F differences from the value in field A in record 1 in file G.
+ * <li>A summarized list of differences ordered by frequency of the difference. This output is similar to saying field A in 50 records in files F and G differed.
+ * </ul>
+ * </p>
+ *
+ * <p>
+ * The GATK contains a private walker DiffObjects that allows you access to the DiffEngine capabilities on the command line. Simply provide the walker with the master and test files and it will emit summarized differences for you.
+ * </p>
+ *
+ * <h3>Why?</h3>
+ *
+ * <p>
+ * The reason for this system is that it allows you to compare two structured files -- such as BAMs and VCFs -- for common differences among them. This is primarily useful in regression testing or optimization, where you want to ensure that the differences are those that you expect and not any others.
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * The DiffObjectsWalker works with BAM or VCF files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * The DiffEngine system compares to two hierarchical data structures for specific differences in the values of named
+ * nodes. Suppose I have two trees:
+ * <pre>
+ * Tree1=(A=1 B=(C=2 D=3))
+ * Tree2=(A=1 B=(C=3 D=3 E=4))
+ * Tree3=(A=1 B=(C=4 D=3 E=4))
+ * </pre>
+ * <p>
+ * where every node in the tree is named, or is a raw value (here all leaf values are integers). The DiffEngine
+ * traverses these data structures by name, identifies equivalent nodes by fully qualified names
+ * (Tree1.A is distinct from Tree2.A, and determines where their values are equal (Tree1.A=1, Tree2.A=1, so they are).
+ * These itemized differences are listed as:
+ * <pre>
+ * Tree1.B.C=2 != Tree2.B.C=3
+ * Tree1.B.C=2 != Tree3.B.C=4
+ * Tree2.B.C=3 != Tree3.B.C=4
+ * Tree1.B.E=MISSING != Tree2.B.E=4
+ * </pre>
+ *
+ * <p>
+ * This conceptually very similar to the output of the unix command line tool diff. What's nice about DiffEngine though
+ * is that it computes similarity among the itemized differences and displays the count of differences names
+ * in the system. In the above example, the field C is not equal three times, while the missing E in Tree1 occurs
+ * only once. So the summary is:
+ *
+ * <pre>
+ * *.B.C : 3
+ * *.B.E : 1
+ * </pre>
+ *
+ * <p>
+ * where the * operator indicates that any named field matches. This output is sorted by counts, and provides an
+ * immediate picture of the commonly occurring differences among the files.
+ * <p>
+ * Below is a detailed example of two VCF fields that differ because of a bug in the AC, AF, and AN counting routines,
+ * detected by the integrationtest integration (more below). You can see that in the although there are many specific
+ * instances of these differences between the two files, the summarized differences provide an immediate picture that
+ * the AC, AF, and AN fields are the major causes of the differences.
+ * <p>
+ *
+ * <pre>
+ [testng] path count
+ [testng] *.*.*.AC 6
+ [testng] *.*.*.AF 6
+ [testng] *.*.*.AN 6
+ [testng] 64b991fd3850f83614518f7d71f0532f.integrationtest.20:10000000.AC 1
+ [testng] 64b991fd3850f83614518f7d71f0532f.integrationtest.20:10000000.AF 1
+ [testng] 64b991fd3850f83614518f7d71f0532f.integrationtest.20:10000000.AN 1
+ [testng] 64b991fd3850f83614518f7d71f0532f.integrationtest.20:10000117.AC 1
+ [testng] 64b991fd3850f83614518f7d71f0532f.integrationtest.20:10000117.AF 1
+ [testng] 64b991fd3850f83614518f7d71f0532f.integrationtest.20:10000117.AN 1
+ [testng] 64b991fd3850f83614518f7d71f0532f.integrationtest.20:10000211.AC 1
+ [testng] 64b991fd3850f83614518f7d71f0532f.integrationtest.20:10000211.AF 1
+ [testng] 64b991fd3850f83614518f7d71f0532f.integrationtest.20:10000211.AN 1
+ [testng] 64b991fd3850f83614518f7d71f0532f.integrationtest.20:10000598.AC 1
+ </pre>
+ *
+ * <h3>Caveat</h3>
+ * <p>Because this is a walker, it requires that you pass a reference file. However the reference is not actually used, so it does not matter what you pass as reference.</p>
+ *
+ *
+ * @author Mark DePristo
+ * @since 7/4/11
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class DiffObjects extends RodWalker<Integer, Integer> {
+ /**
+ * Writes out a file of the DiffEngine format:
+ *
+ * See http://www.broadinstitute.org/gatk/guide/article?id=1299 for details.
+ */
+ @Output(doc="File to which results should be written")
+ protected PrintStream out;
+
+ /**
+ * The master file against which we will compare test. This is one of the two required
+ * files to do the comparison. Conceptually master is the original file contained the expected
+ * results, but this doesn't currently have an impact on the calculations, but might in the future.
+ */
+ @Input(fullName="master", shortName="m", doc="Master file: expected results", required=true)
+ File masterFile;
+
+ /**
+ * The test file against which we will compare to the master. This is one of the two required
+ * files to do the comparison. Conceptually test is the derived file from master, but this
+ * doesn't currently have an impact on the calculations, but might in the future.
+ */
+ @Input(fullName="test", shortName="t", doc="Test file: new results to compare to the master file", required=true)
+ File testFile;
+
+ /**
+ * The engine will read at most this number of objects from each of master and test files. This reduces
+ * the memory requirements for DiffObjects but does limit you to comparing at most this number of objects
+ */
+ @Argument(fullName="maxObjectsToRead", shortName="motr", doc="Max. number of objects to read from the files. -1 [default] means unlimited", required=false)
+ int MAX_OBJECTS_TO_READ = -1;
+
+ @Argument(fullName="maxRawDiffsToSummarize", shortName="maxRawDiffsToSummarize", doc="Max. number of differences to include in the summary. -1 [default] means unlimited", required=false)
+ int maxRawDiffsToSummary = -1;
+
+ @Argument(fullName="doPairwise", shortName="doPairwise", doc="If provided, we will compute the minimum pairwise differences to summary, which can be extremely expensive", required=false)
+ boolean doPairwise = false;
+
+ /**
+ * The max number of differences to display when summarizing. For example, if there are 10M differences, but
+ * maxDiffs is 10, then the comparison aborts after first ten summarized differences are shown. Note that
+ * the system shows differences sorted by frequency, so these 10 would be the most common between the two files.
+ * A value of 0 means show all possible differences.
+ */
+ @Argument(fullName="maxDiffs", shortName="M", doc="Max. number of diffs to process", required=false)
+ int MAX_DIFFS = 0;
+
+ /**
+ * The maximum number of singleton (occurs exactly once between the two files) to display when writing out
+ * the summary. Only applies if maxDiffs hasn't been exceeded. For example, if maxDiffs is 10 and maxCount1Diffs
+ * is 2 and there are 20 diffs with count > 1, then only 10 are shown, all of which have count above 1.
+ */
+ @Argument(fullName="maxCount1Diffs", shortName="M1", doc="Max. number of diffs occuring exactly once in the file to process", required=false)
+ int MAX_COUNT1_DIFFS = 0;
+
+ /**
+ * Only differences that occur more than minCountForDiff are displayed. For example, if minCountForDiff is 10, then
+ * a difference must occur at least 10 times between the two files to be shown.
+ */
+ @Argument(fullName="minCountForDiff", shortName="MCFD", doc="Min number of observations for a records to display", required=false)
+ int minCountForDiff = 1;
+
+ /**
+ * If provided, the system will write out the summarized, individual differences. May lead to enormous outputs,
+ * depending on how many differences are found. Note these are not sorted in any way, so if you have 10M
+ * common differences in the files, you will see 10M records, whereas the final summarize will just list the
+ * difference and its count of 10M.
+ */
+ @Argument(fullName="showItemizedDifferences", shortName="SID", doc="Should we enumerate all differences between the files?", required=false)
+ boolean showItemizedDifferences = false;
+
+ @Argument(fullName="iterations", doc="Number of iterations to perform, should be 1 unless you are doing memory testing", required=false)
+ int iterations = 1;
+
+ DiffEngine diffEngine;
+
+ @Override
+ public void initialize() {
+ this.diffEngine = new DiffEngine();
+ }
+
+ @Override
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ return 0;
+ }
+
+ @Override
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ @Override
+ public Integer reduce(Integer counter, Integer sum) {
+ return counter + sum;
+ }
+
+ @Override
+ public void onTraversalDone(Integer sum) {
+ if ( iterations > 1 ) {
+ for ( int i = 0; i < iterations; i++ ) {
+ DiffEngine.SummaryReportParams params = new DiffEngine.SummaryReportParams(out, 20, 10, 0, -1, false);
+ boolean success = DiffEngine.simpleDiffFiles(masterFile, testFile, MAX_OBJECTS_TO_READ, params);
+ logger.info("Iteration " + i + " success " + success);
+ }
+ } else {
+ //out.printf("Reading master file %s%n", masterFile);
+ DiffElement master = diffEngine.createDiffableFromFile(masterFile, MAX_OBJECTS_TO_READ);
+ logger.info(String.format("Read %d objects", master.size()));
+ //out.printf("Reading test file %s%n", testFile);
+ DiffElement test = diffEngine.createDiffableFromFile(testFile, MAX_OBJECTS_TO_READ);
+ logger.info(String.format("Read %d objects", test.size()));
+
+// out.printf("Master diff objects%n");
+// out.println(master.toString());
+// out.printf("Test diff objects%n");
+// out.println(test.toString());
+
+ List<Difference> diffs = diffEngine.diff(master, test);
+ logger.info(String.format("Done computing diff with %d differences found", diffs.size()));
+ if ( showItemizedDifferences ) {
+ out.printf("Itemized results%n");
+ for ( Difference diff : diffs )
+ out.printf("DIFF: %s%n", diff.toString());
+ }
+
+ DiffEngine.SummaryReportParams params = new DiffEngine.SummaryReportParams(out,
+ MAX_DIFFS, MAX_COUNT1_DIFFS, minCountForDiff,
+ maxRawDiffsToSummary, doPairwise);
+ params.setDescending(false);
+ diffEngine.reportSummarizedDifferences(diffs, params);
+ logger.info(String.format("Done summarizing differences"));
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffValue.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffValue.java
new file mode 100644
index 0000000..acec383
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffValue.java
@@ -0,0 +1,90 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers.diffengine;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: 7/4/11
+ * Time: 12:55 PM
+ *
+ * An interface that must be implemented to allow us to calculate differences
+ * between structured objects
+ */
+public class DiffValue {
+ private DiffElement binding = null;
+ final private Object value;
+
+ public DiffValue(Object value) {
+ this.value = value;
+ }
+
+ public DiffValue(DiffElement binding, Object value) {
+ this.binding = binding;
+ this.value = value;
+ }
+
+ public DiffValue(DiffValue parent, Object value) {
+ this(parent.getBinding(), value);
+ }
+
+ public DiffValue(String name, DiffElement parent, Object value) {
+ this.binding = new DiffElement(name, parent, this);
+ this.value = value;
+ }
+
+ public DiffValue(String name, DiffValue parent, Object value) {
+ this(name, parent.getBinding(), value);
+ }
+
+ public DiffElement getBinding() {
+ return binding;
+ }
+
+ protected void setBinding(DiffElement binding) {
+ this.binding = binding;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public String toString() {
+ return getValue().toString();
+ }
+
+ public String toString(int offset) {
+ return toString();
+ }
+
+ public String toOneLineString() {
+ return getValue().toString();
+ }
+
+ public boolean isAtomic() { return true; }
+ public boolean isCompound() { return ! isAtomic(); }
+ public int size() { return 1; }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffableReader.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffableReader.java
new file mode 100644
index 0000000..903a073
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/DiffableReader.java
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers.diffengine;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+
+import java.io.File;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: 7/4/11
+ * Time: 1:09 PM
+ *
+ * Interface for readers creating diffable objects from a file
+ */
+public interface DiffableReader {
+ @Ensures("result != null")
+ /**
+ * Return the name of this DiffableReader type. For example, the VCF reader returns 'VCF' and the
+ * bam reader 'BAM'
+ */
+ public String getName();
+
+ @Ensures("result != null")
+ @Requires("file != null")
+ /**
+ * Read up to maxElementsToRead DiffElements from file, and return them.
+ */
+ public DiffElement readFromFile(File file, int maxElementsToRead);
+
+ /**
+ * Return true if the file can be read into DiffElement objects with this reader. This should
+ * be uniquely true/false for all readers, as the system will use the first reader that can read the
+ * file. This routine should never throw an exception. The VCF reader, for example, looks at the
+ * first line of the file for the ##format=VCF4.1 header, and the BAM reader for the BAM_MAGIC value
+ * @param file
+ * @return
+ */
+ @Requires("file != null")
+ public boolean canRead(File file);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/Difference.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/Difference.java
new file mode 100644
index 0000000..c8794a7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/Difference.java
@@ -0,0 +1,137 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers.diffengine;
+
+public class Difference implements Comparable<Difference> {
+ final String path; // X.Y.Z
+ final String[] parts;
+ int count = 1;
+ DiffElement master = null , test = null;
+
+ public Difference(String path) {
+ this.path = path;
+ this.parts = DiffEngine.diffNameToPath(path);
+ }
+
+ public Difference(DiffElement master, DiffElement test) {
+ this(createPath(master, test), master, test);
+ }
+
+ public Difference(String path, DiffElement master, DiffElement test) {
+ this(path);
+ this.master = master;
+ this.test = test;
+ }
+
+ public String[] getParts() {
+ return parts;
+ }
+
+ public void incCount() { count++; }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ /**
+ * The fully qualified path object A.B.C etc
+ * @return
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * @return the length of the parts of this summary
+ */
+ public int length() {
+ return this.parts.length;
+ }
+
+ /**
+ * Returns true if the string parts matches this summary. Matches are
+ * must be equal() everywhere where this summary isn't *.
+ * @param otherParts
+ * @return
+ */
+ public boolean matches(String[] otherParts) {
+ if ( otherParts.length != length() )
+ return false;
+
+ // TODO optimization: can start at right most non-star element
+ for ( int i = 0; i < length(); i++ ) {
+ String part = parts[i];
+ if ( ! part.equals("*") && ! part.equals(otherParts[i]) )
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s:%d:%s", getPath(), getCount(), valueDiffString());
+ }
+
+ @Override
+ public int compareTo(Difference other) {
+ // sort first highest to lowest count, then by lowest to highest path
+ int countCmp = Integer.valueOf(count).compareTo(other.count);
+ return countCmp != 0 ? -1 * countCmp : path.compareTo(other.path);
+ }
+
+ public String valueDiffString() {
+ if ( hasSpecificDifference() ) {
+ return String.format("%s!=%s", getOneLineString(master), getOneLineString(test));
+ } else {
+ return "N/A";
+ }
+ }
+
+ private static String createPath(DiffElement master, DiffElement test) {
+ return (master == null ? test : master).fullyQualifiedName();
+ }
+
+ private static String getOneLineString(DiffElement elt) {
+ return elt == null ? "MISSING" : elt.getValue().toOneLineString();
+ }
+
+ public boolean hasSpecificDifference() {
+ return master != null || test != null;
+ }
+
+ public DiffElement getMaster() {
+ return master;
+ }
+
+ public DiffElement getTest() {
+ return test;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/GATKReportDiffableReader.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/GATKReportDiffableReader.java
new file mode 100644
index 0000000..4a78448
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/GATKReportDiffableReader.java
@@ -0,0 +1,104 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers.diffengine;
+
+import org.broadinstitute.gatk.engine.report.GATKReport;
+import org.broadinstitute.gatk.engine.report.GATKReportColumn;
+import org.broadinstitute.gatk.engine.report.GATKReportTable;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+
+/**
+ * Class implementing diffnode reader for GATKReports
+ */
+
+// TODO Version check to be added at the report level
+
+public class GATKReportDiffableReader implements DiffableReader {
+ @Override
+ public String getName() {
+ return "GATKReport";
+ }
+
+ @Override
+ public DiffElement readFromFile(File file, int maxElementsToRead) {
+ DiffNode root = DiffNode.rooted(file.getName());
+ try {
+ // one line reads the whole thing into memory
+ GATKReport report = new GATKReport(file);
+
+ for (GATKReportTable table : report.getTables()) {
+ root.add(tableToNode(table, root));
+ }
+
+ return root.getBinding();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ private DiffNode tableToNode(GATKReportTable table, DiffNode root) {
+ DiffNode tableRoot = DiffNode.empty(table.getTableName(), root);
+
+ tableRoot.add("Description", table.getTableDescription());
+ tableRoot.add("NumberOfRows", table.getNumRows());
+
+ for ( GATKReportColumn column : table.getColumnInfo() ) {
+ DiffNode columnRoot = DiffNode.empty(column.getColumnName(), tableRoot);
+
+ columnRoot.add("Width", column.getColumnFormat().getWidth());
+ // NOTE: as the values are trimmed during parsing left/right alignment is not currently preserved
+ columnRoot.add("Displayable", true);
+
+ for ( int i = 0; i < table.getNumRows(); i++ ) {
+ String name = column.getColumnName() + (i+1);
+ columnRoot.add(name, table.get(i, column.getColumnName()).toString());
+ }
+
+ tableRoot.add(columnRoot);
+ }
+
+ return tableRoot;
+ }
+
+ @Override
+ public boolean canRead(File file) {
+ try {
+ final String HEADER = GATKReport.GATKREPORT_HEADER_PREFIX;
+ final char[] buff = new char[HEADER.length()];
+ final FileReader FR = new FileReader(file);
+ FR.read(buff, 0, HEADER.length());
+ FR.close();
+ String firstLine = new String(buff);
+ return firstLine.startsWith(HEADER);
+ } catch (IOException e) {
+ return false;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/VCFDiffableReader.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/VCFDiffableReader.java
new file mode 100644
index 0000000..23b213e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/engine/walkers/diffengine/VCFDiffableReader.java
@@ -0,0 +1,145 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers.diffengine;
+
+import org.apache.log4j.Logger;
+import htsjdk.tribble.AbstractFeatureReader;
+import htsjdk.tribble.FeatureReader;
+import org.broadinstitute.gatk.utils.Utils;
+import htsjdk.variant.vcf.*;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.io.*;
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: 7/4/11
+ * Time: 1:09 PM
+ *
+ * Class implementing diffnode reader for VCF
+ */
+public class VCFDiffableReader implements DiffableReader {
+ private static Logger logger = Logger.getLogger(VCFDiffableReader.class);
+
+ @Override
+ public String getName() { return "VCF"; }
+
+ @Override
+ public DiffElement readFromFile(File file, int maxElementsToRead) {
+ DiffNode root = DiffNode.rooted(file.getName());
+ try {
+ // read the version line from the file
+ BufferedReader br = new BufferedReader(new FileReader(file));
+ final String version = br.readLine();
+ root.add("VERSION", version);
+ br.close();
+
+ final VCFCodec vcfCodec = new VCFCodec();
+ vcfCodec.disableOnTheFlyModifications(); // must be read as state is stored in reader itself
+
+ FeatureReader<VariantContext> reader = AbstractFeatureReader.getFeatureReader(file.getAbsolutePath(), vcfCodec, false);
+ VCFHeader header = (VCFHeader)reader.getHeader();
+ for ( VCFHeaderLine headerLine : header.getMetaDataInInputOrder() ) {
+ String key = headerLine.getKey();
+ if ( headerLine instanceof VCFIDHeaderLine)
+ key += "_" + ((VCFIDHeaderLine) headerLine).getID();
+ if ( root.hasElement(key) )
+ logger.warn("Skipping duplicate header line: file=" + file + " line=" + headerLine.toString());
+ else
+ root.add(key, headerLine.toString());
+ }
+
+ int count = 0, nRecordsAtPos = 1;
+ String prevName = "";
+ Iterator<VariantContext> it = reader.iterator();
+ while ( it.hasNext() ) {
+ VariantContext vc = it.next();
+ String name = vc.getChr() + ":" + vc.getStart();
+ if ( name.equals(prevName) ) {
+ name += "_" + ++nRecordsAtPos;
+ } else {
+ prevName = name;
+ }
+ DiffNode vcRoot = DiffNode.empty(name, root);
+
+ // add fields
+ vcRoot.add("CHROM", vc.getChr());
+ vcRoot.add("POS", vc.getStart());
+ vcRoot.add("ID", vc.getID());
+ vcRoot.add("REF", vc.getReference());
+ vcRoot.add("ALT", vc.getAlternateAlleles());
+ vcRoot.add("QUAL", vc.hasLog10PError() ? vc.getLog10PError() * -10 : VCFConstants.MISSING_VALUE_v4);
+ vcRoot.add("FILTER", ! vc.filtersWereApplied() // needs null to differentiate between PASS and .
+ ? VCFConstants.MISSING_VALUE_v4
+ : ( vc.getFilters().isEmpty() ? VCFConstants.PASSES_FILTERS_v4 : vc.getFilters()) );
+
+ // add info fields
+ for (Map.Entry<String, Object> attribute : vc.getAttributes().entrySet()) {
+ if ( ! attribute.getKey().startsWith("_") )
+ vcRoot.add(attribute.getKey(), attribute.getValue());
+ }
+
+ for (Genotype g : vc.getGenotypes() ) {
+ DiffNode gRoot = DiffNode.empty(g.getSampleName(), vcRoot);
+ gRoot.add("GT", g.getGenotypeString());
+ if ( g.hasGQ() ) gRoot.add("GQ", g.getGQ() );
+ if ( g.hasDP() ) gRoot.add("DP", g.getDP() );
+ if ( g.hasAD() ) gRoot.add("AD", Utils.join(",", g.getAD()));
+ if ( g.hasPL() ) gRoot.add("PL", Utils.join(",", g.getPL()));
+ if ( g.getFilters() != null ) gRoot.add("FT", g.getFilters());
+
+ for (Map.Entry<String, Object> attribute : g.getExtendedAttributes().entrySet()) {
+ if ( ! attribute.getKey().startsWith("_") )
+ gRoot.add(attribute.getKey(), attribute.getValue());
+ }
+
+ vcRoot.add(gRoot);
+ }
+
+ root.add(vcRoot);
+ count += vcRoot.size();
+ if ( count > maxElementsToRead && maxElementsToRead != -1)
+ break;
+ }
+
+ reader.close();
+ } catch ( IOException e ) {
+ return null;
+ }
+
+ return root.getBinding();
+ }
+
+ @Override
+ public boolean canRead(File file) {
+ return AbstractVCFCodec.canDecodeFile(file.getPath(), VCFCodec.VCF4_MAGIC_HEADER);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/CatVariants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/CatVariants.java
new file mode 100644
index 0000000..43403ab
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/CatVariants.java
@@ -0,0 +1,338 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools;
+
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequenceFileFactory;
+import org.apache.log4j.BasicConfigurator;
+import org.apache.log4j.Level;
+import htsjdk.tribble.AbstractFeatureReader;
+import htsjdk.tribble.FeatureReader;
+import htsjdk.tribble.index.IndexCreator;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+import org.broadinstitute.gatk.utils.variant.GATKVCFIndexType;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import htsjdk.variant.bcf2.BCF2Codec;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import htsjdk.variant.vcf.VCFCodec;
+import htsjdk.variant.vcf.VCFHeader;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.writer.Options;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.variantcontext.writer.VariantContextWriterFactory;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ *
+ * Concatenates VCF files of non-overlapped genome intervals, all with the same set of samples
+ *
+ * <p>
+ * The main purpose of this tool is to speed up the gather function when using scatter-gather parallelization.
+ * This tool concatenates the scattered output VCF files. It assumes that:
+ * - All the input VCFs (or BCFs) contain the same samples in the same order.
+ * - The variants in each input file are from non-overlapping (scattered) intervals.
+ *
+ * When the input files are already sorted based on the intervals start positions, use -assumeSorted.
+ *
+ * Note: Currently the tool is more efficient when working with VCFs; we will work to make it as efficient for BCFs.
+ *
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more variant sets to combine. They should be of non-overlapping genome intervals and with the same samples (in the same order).
+ * If the files are ordered according to the appearance of intervals in the ref genome, then one can use the -assumeSorted flag.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A combined VCF or BCF. The output file should have the same extension as the input(s).
+ * <\p>
+ *
+ * <h3>Important note</h3>
+ * <p>This is a command-line utility that bypasses the GATK engine. As a result, the command-line you must use to
+ * invoke it is a little different from other GATK tools (see example below), and it does not accept any of the
+ * classic "CommandLineGATK" arguments.</p>
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java -cp GenomeAnalysisTK.jar org.broadinstitute.gatk.tools.CatVariants \
+ * -R ref.fasta \
+ * -V input1.vcf \
+ * -V input2.vcf \
+ * -out output.vcf \
+ * -assumeSorted
+ * </pre>
+ *
+ * @author Ami Levy Moonshine
+ * @since Jan 2012
+ */
+
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP )
+public class CatVariants extends CommandLineProgram {
+ // setup the logging system, used by some codecs
+ private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getRootLogger();
+
+ @Input(fullName = "reference", shortName = "R", doc = "genome reference file <name>.fasta", required = true)
+ private File refFile = null;
+
+ /**
+ * The VCF or BCF files to merge together
+ *
+ * CatVariants can take any number of -V arguments on the command line. Each -V argument
+ * will be included in the final merged output VCF/BCF. The order of arguments does not matter, but it runs more
+ * efficiently if they are sorted based on the intervals and the assumeSorted argument is used.
+ *
+ */
+ @Input(fullName="variant", shortName="V", doc="Input VCF file/s", required = true)
+ private List<File> variant = null;
+
+ @Output(fullName = "outputFile", shortName = "out", doc = "output file", required = true)
+ private File outputFile = null;
+
+ @Argument(fullName = "assumeSorted", shortName = "assumeSorted", doc = "assumeSorted should be true if the input files are already sorted (based on the position of the variants)", required = false)
+ private Boolean assumeSorted = false;
+
+ @Argument(fullName = "variant_index_type", doc = "which type of IndexCreator to use for VCF/BCF indices", required = false)
+ private GATKVCFIndexType variant_index_type = GATKVCFUtils.DEFAULT_INDEX_TYPE;
+
+ @Argument(fullName = "variant_index_parameter", doc = "the parameter (bin width or features per bin) to pass to the VCF/BCF IndexCreator", required = false)
+ private Integer variant_index_parameter = GATKVCFUtils.DEFAULT_INDEX_PARAMETER;
+
+ /*
+ * print usage information
+ */
+ private static void printUsage() {
+ System.err.println("Usage: java -cp target/GenomeAnalysisTK.jar org.broadinstitute.gatk.tools.CatVariants --reference <reference> --variant <input VCF or BCF file; can specify --variant multiple times> --outputFile <outputFile> [--assumeSorted]");
+ System.err.println(" The output file must be of the same type as all input files.");
+ System.err.println(" If the input files are already sorted, then indicate that with --assumeSorted to improve performance.");
+ }
+
+ private enum FileType {
+ VCF,
+ BCF,
+ BLOCK_COMPRESSED_VCF,
+ INVALID
+ }
+
+ private FileType fileExtensionCheck(File inFile, File outFile) {
+ final String inFileName = inFile.toString().toLowerCase();
+ final String outFileName = outFile.toString().toLowerCase();
+
+ FileType inFileType = FileType.INVALID;
+
+ if (inFileName.endsWith(".vcf")) {
+ inFileType = FileType.VCF;
+ if (outFileName.endsWith(".vcf"))
+ return inFileType;
+ }
+
+ if (inFileName.endsWith(".bcf")) {
+ inFileType = FileType.BCF;
+ if (outFileName.endsWith(".bcf"))
+ return inFileType;
+ }
+
+ for (String extension : AbstractFeatureReader.BLOCK_COMPRESSED_EXTENSIONS) {
+ if (inFileName.endsWith(".vcf" + extension)) {
+ inFileType = FileType.BLOCK_COMPRESSED_VCF;
+ if (outFileName.endsWith(".vcf" + extension))
+ return inFileType;
+ }
+ }
+
+ if (inFileType == FileType.INVALID)
+ System.err.println(String.format("File extension for input file %s is not valid for CatVariants", inFile));
+ else
+ System.err.println(String.format("File extension mismatch between input %s and output %s", inFile, outFile));
+
+ printUsage();
+ return FileType.INVALID;
+ }
+
+ private FeatureReader<VariantContext> getFeatureReader(final FileType fileType, final File file) {
+ FeatureReader<VariantContext> reader = null;
+ switch(fileType) {
+ case VCF:
+ case BLOCK_COMPRESSED_VCF:
+ // getFeatureReader will handle both block-compressed and plain text VCFs
+ reader = AbstractFeatureReader.getFeatureReader(file.getAbsolutePath(), new VCFCodec(), false);
+ break;
+ case BCF:
+ reader = AbstractFeatureReader.getFeatureReader(file.getAbsolutePath(), new BCF2Codec(), false);
+ break;
+ }
+ return reader;
+ }
+
+ /**
+ * Replaces any .list files in rawFileList with the files named in said .list file
+ * @param rawFileList the original file list, possibly including .list files
+ * @return a new List, with .list files replaced
+ */
+ private List<File> parseVariantList(final List<File> rawFileList) {
+ final List<File> result = new ArrayList<>(rawFileList.size());
+ for (final File rawFile : rawFileList) {
+ if (rawFile.getName().endsWith(".list")) {
+ try {
+ for (final String line : new XReadLines(rawFile, true))
+ result.add(new File(line));
+ } catch (IOException e) {
+ throw new UserException.CouldNotReadInputFile(rawFile, e);
+ }
+ } else {
+ result.add(rawFile);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ protected int execute() throws Exception {
+ BasicConfigurator.configure();
+ logger.setLevel(Level.INFO);
+
+ final ReferenceSequenceFile ref;
+ try {
+ ref = ReferenceSequenceFileFactory.getReferenceSequenceFile(refFile);
+ } catch ( Exception e ) {
+ throw new UserException("Couldn't load provided reference sequence file " + refFile, e);
+ }
+
+ variant = parseVariantList(variant);
+
+ Comparator<Pair<Integer,File>> positionComparator = new PositionComparator();
+
+ Queue<Pair<Integer,File>> priorityQueue;
+ if (assumeSorted)
+ priorityQueue = new LinkedList<>();
+ else
+ priorityQueue = new PriorityQueue<>(10000, positionComparator);
+
+ FileType fileType = FileType.INVALID;
+ for (File file : variant) {
+ // if it returns a valid type, it will be the same for all files
+ fileType = fileExtensionCheck(file, outputFile);
+ if (fileType == FileType.INVALID)
+ return 1;
+
+ if (assumeSorted){
+ priorityQueue.add(new Pair<>(0,file));
+ }
+ else{
+ if (!file.exists()) {
+ throw new UserException(String.format("File %s doesn't exist",file.getAbsolutePath()));
+ }
+ FeatureReader<VariantContext> reader = getFeatureReader(fileType, file);
+ Iterator<VariantContext> it = reader.iterator();
+ if(!it.hasNext()){
+ System.err.println(String.format("File %s is empty. This file will be ignored",file.getAbsolutePath()));
+ continue;
+ }
+ VariantContext vc = it.next();
+ int firstPosition = vc.getStart();
+ reader.close();
+ priorityQueue.add(new Pair<>(firstPosition,file));
+ }
+
+ }
+
+ FileOutputStream outputStream = new FileOutputStream(outputFile);
+ EnumSet<Options> options = EnumSet.of(Options.INDEX_ON_THE_FLY);
+ final IndexCreator idxCreator = GATKVCFUtils.getIndexCreator(variant_index_type, variant_index_parameter, outputFile, ref.getSequenceDictionary());
+ final VariantContextWriter outputWriter = VariantContextWriterFactory.create(outputFile, outputStream, ref.getSequenceDictionary(), idxCreator, options);
+
+ boolean firstFile = true;
+ int count = 0;
+ while(!priorityQueue.isEmpty() ){
+ count++;
+ File file = priorityQueue.remove().getSecond();
+ if (!file.exists()) {
+ throw new UserException(String.format("File %s doesn't exist",file.getAbsolutePath()));
+ }
+ FeatureReader<VariantContext> reader = getFeatureReader(fileType, file);
+
+ if(count%10 ==0)
+ System.out.print(count);
+ else
+ System.out.print(".");
+ if (firstFile){
+ VCFHeader header = (VCFHeader)reader.getHeader();
+ outputWriter.writeHeader(header);
+ firstFile = false;
+ }
+
+ Iterator<VariantContext> it = reader.iterator();
+
+ while (it.hasNext()){
+ VariantContext vc = it.next();
+ outputWriter.add(vc);
+ }
+
+ reader.close();
+
+ }
+ System.out.println();
+
+ outputWriter.close();
+
+ return 0;
+ }
+
+ public static void main(String[] args){
+ try {
+ CatVariants instance = new CatVariants();
+ start(instance, args);
+ System.exit(CommandLineProgram.result);
+ } catch ( UserException e ) {
+ printUsage();
+ exitSystemWithUserError(e);
+ } catch ( Exception e ) {
+ exitSystemWithError(e);
+ }
+ }
+
+ private static class PositionComparator implements Comparator<Pair<Integer,File>> {
+
+ @Override
+ public int compare(Pair<Integer,File> p1, Pair<Integer,File> p2) {
+ int startPositionP1 = p1.getFirst();
+ int startPositionP2 = p2.getFirst();
+ if (startPositionP1 == startPositionP2)
+ return 0;
+ return startPositionP1 < startPositionP2 ? -1 : 1 ;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/ListAnnotations.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/ListAnnotations.java
new file mode 100644
index 0000000..72d30de
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/ListAnnotations.java
@@ -0,0 +1,85 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools;
+
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.help.HelpUtils;
+
+/**
+ * Utility program to print a list of available annotations
+ *
+ * <p>This is a very simple utility tool that retrieves available annotations for use with tools such as
+ * UnifiedGenotyper, HaplotypeCaller and VariantAnnotator.</p>
+ *
+ * <h3>Important note</h3>
+ * <p>This is a command-line utility that bypasses the GATK engine. As a result, the command-line you must use to
+ * invoke it is a little different from other GATK tools (see usage below), and it does not accept any of the
+ * classic "CommandLineGATK" arguments.</p>
+ *
+ * <h3>Usage</h3>
+ * <pre>java -cp GenomeAnalysisTK.jar org.broadinstitute.gatk.tools.ListAnnotations</pre>
+ *
+ * @author vdauwera
+ * @since 3/14/13
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_HELPUTILS )
+public class ListAnnotations extends CommandLineProgram {
+
+ /*
+ * Print usage information
+ *
+ * TODO: would be more convenient if we could just call the program by name instead of the full classpath
+ */
+ private static void printUsage() {
+ System.err.println("Usage: java -cp dist/GenomeAnalysisTK.jar org.broadinstitute.gatk.tools.ListAnnotations");
+ System.err.println(" Prints a list of available annotations and exits.");
+ }
+
+ // TODO: override CommandLineProgram bit that offers version, logging etc arguments. We don't need that stuff here and it makes the doc confusing.
+
+ @Override
+ protected int execute() throws Exception {
+
+ HelpUtils.listAnnotations();
+ return 0;
+ }
+
+ public static void main(String[] args){
+ try {
+ ListAnnotations instance = new ListAnnotations();
+ start(instance, args);
+ System.exit(CommandLineProgram.result);
+ } catch ( UserException e ) {
+ printUsage();
+ exitSystemWithUserError(e);
+ } catch ( Exception e ) {
+ exitSystemWithError(e);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/AlleleBalance.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/AlleleBalance.java
new file mode 100644
index 0000000..9127b5e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/AlleleBalance.java
@@ -0,0 +1,218 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.GenotypesContext;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.vcf.VCFHeaderLineType;
+import htsjdk.variant.vcf.VCFInfoHeaderLine;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.AnnotatorCompatible;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.InfoFieldAnnotation;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Allele balance across all samples
+ *
+ * <p> This is an experimental annotation that attempts to estimate whether the data supporting a variant call fits allelic ratio expectations, or whether there might be some bias in the data. Each sample will contribute its allelic read depth (from the AD annotation) to either ABHom or ABHet depending on its genotype call: ABHom if the call is homozygous (REF/REF or ALT/ALT), and ABHet if the call is heterozygous (REF/ALT). Additionally, reads that support something other than the genot [...]
+ * <h3>Calculations</h3>
+ * <p> $$ ABHom = \frac{# ALT alleles}{total # alleles} $$ <br />
+ * $$ ABHet = \frac{# REF alleles}{# total alleles} $$ <br />
+ * $$ OND = \frac{# genotyped alleles}{# alleles + # non-alleles} $$
+ * </p>
+ * <p> For ABHom, the value should be close to 1.00 because ideally, all the reads should support a single allele. For ABHet, the value should be close to 0.5, so half of the alleles support the ref allele and half of the alleles support the alt allele. Divergence from these expected ratios may indicate that there is some bias in favor of one allele. Note the caveats below regarding cancer and RNAseq analysis. </p>
+ * <h3>Caveats</h3>
+ * <ul>
+ * <li>This annotation will only work properly for biallelic variants where all samples are called heterozygous or homozygous.</li>
+ * <li>This annotation cannot currently be calculated for indels.</li>
+ * <li>tThe reasoning underlying this annotation only applies to germline variants in DNA sequencing data. In somatic/cancer analysis, divergent ratios are expected due to tumor heterogeneity. In RNAseq analysis, divergent ratios may indicate differential allele expression.</li>
+ * <li>As stated above, this annotation is experimental and should be interpreted with caution as we cannot guarantee that it is appropriate. Basically, use it at your own risk.</li>
+ * </ul>
+ * <h3>Related annotations</h3>
+ * <ul>
+ * <li><b><a href="https://www.broadinstitute.org/gatk/guide/tooldocs/org_broadinstitute_gatk_tools_walkers_annotator_AlleleBalanceBySample.php">AlleleBallanceBySample</a></b> calculates allele balance for each individual sample.</li>
+ * <li><b><a href="https://www.broadinstitute.org/gatk/guide/tooldocs/org_broadinstitute_gatk_tools_walkers_annotator_DepthPerAlleleBySample.php">DepthPerAlleleBySample</a></b> calculates depth of coverage for each allele per sample.</li>
+ * </ul>
+ */
+
+public class AlleleBalance extends InfoFieldAnnotation {
+
+ public Map<String, Object> annotate(final RefMetaDataTracker tracker,
+ final AnnotatorCompatible walker,
+ final ReferenceContext ref,
+ final Map<String, AlignmentContext> stratifiedContexts,
+ final VariantContext vc,
+ final Map<String, PerReadAlleleLikelihoodMap> stratifiedPerReadAlleleLikelihoodMap) {
+ //if ( stratifiedContexts.size() == 0 )
+ // return null;
+
+ if ( !vc.isBiallelic() )
+ return null;
+ final GenotypesContext genotypes = vc.getGenotypes();
+ if ( !vc.hasGenotypes() )
+ return null;
+
+ double ratioHom = 0.0;
+ double ratioHet = 0.0;
+ double weightHom = 0.0;
+ double weightHet = 0.0;
+ double overallNonDiploid = 0.0;
+ for ( Genotype genotype : genotypes ) {
+
+ if ( vc.isSNP() ) {
+
+ final int[] counts = getCounts(genotype, stratifiedContexts, vc);
+ // If AD was not calculated, we can't continue
+ if(counts == null)
+ continue;
+
+ final int n_allele = counts.length;
+ int count_sum = 0;
+ for(int i=0; i<n_allele; i++){
+ count_sum += counts[i];
+ }
+ double pTrue = 1.0 - Math.pow(10.0,-genotype.getGQ() / (double) 10 );
+ if ( genotype.isHet() ) {
+
+ final int otherCount = count_sum - (counts[0] + counts[1]);
+ // sanity check
+ if ( counts[0] + counts[1] == 0 )
+ continue;
+
+ // weight the allele balance by genotype quality so that e.g. mis-called homs don't affect the ratio too much
+ ratioHet += pTrue * ((double)counts[0] / (double)(counts[0] + counts[1]));
+ weightHet += pTrue;
+ overallNonDiploid += ( (double) otherCount )/((double) count_sum*genotypes.size());
+ } else if ( genotype.isHom() ) {
+ final int alleleIdx = genotype.isHomRef() ? 0 : 1 ;
+ final int alleleCount = counts[alleleIdx];
+ int bestOtherCount = 0;
+ for(int i=0; i<n_allele; i++){
+ if( i == alleleIdx )
+ continue;
+ if( counts[i] > bestOtherCount )
+ bestOtherCount = counts[i];
+ }
+ final int otherCount = count_sum - alleleCount;
+ ratioHom += pTrue*( (double) alleleCount)/((double) (alleleCount+bestOtherCount));
+ weightHom += pTrue;
+ overallNonDiploid += ((double ) otherCount)/((double) count_sum*genotypes.size());
+ }
+ // Allele Balance for indels was not being computed correctly (since there was no allele matching). Instead of
+ // prolonging the life of imperfect code, I've decided to delete it. If someone else wants to try again from
+ // scratch, be my guest - but make sure it's done correctly! [EB]
+ }
+ }
+
+ // make sure we had a het genotype
+
+ Map<String, Object> map = new HashMap<>();
+ if ( weightHet > 0.0 ) {
+ map.put("ABHet",ratioHet/weightHet);
+ }
+
+ if ( weightHom > 0.0 ) {
+ map.put("ABHom",ratioHom/weightHom);
+ }
+
+ if ( overallNonDiploid > 0.0 ) {
+ map.put("OND",overallNonDiploid);
+ }
+ return map;
+ }
+
+ /**
+ * Provide a centralized method of getting the number of reads per allele,
+ * depending on the input given. Will use the following (in order of preference):
+ * - genotype.getAD()
+ * - reads from an AlignmentContext
+ * - reads from a PerReadAlleleLikelihoodMap (Not yet implemented)
+ *
+ *
+ * @param genotype The genotype of interest
+ * @param stratifiedContexts A mapping
+ * @param vc
+ * @return
+ */
+ private int[] getCounts(final Genotype genotype,
+ final Map<String, AlignmentContext> stratifiedContexts,
+ final VariantContext vc){
+
+ // Can't do anything without a genotype here
+ if(genotype == null)
+ return null;
+
+ int[] retVal = genotype.getAD();
+ AlignmentContext context;
+
+ if ( retVal == null && stratifiedContexts != null &&
+ (context = stratifiedContexts.get(genotype.getSampleName())) != null){
+ // If we get to this point, the getAD() function returned no information
+ // about AlleleDepth by Sample - perhaps it wasn't annotated?
+ // In that case, let's try to build it up using the algorithm that
+ // was here in v 3.1-1 and earlier
+ // Also, b/c of the assignment check in the if statement above,
+ // we know we have a valid AlignmentContext for this sample!
+
+ final ReadBackedPileup pileup = context.getBasePileup();
+ final String bases = new String(pileup.getBases());
+ List<Allele> alleles = vc.getAlleles();
+ final int n_allele = alleles.size();
+ retVal = new int[n_allele];
+
+ // Calculate the depth for each allele, under the assumption that
+ // the allele is a single base
+ int i=0;
+ for(Allele a : alleles){
+ retVal[i] = MathUtils.countOccurrences(a.toString().charAt(0), bases);
+ i++;
+ }
+
+ }
+
+ return retVal;
+
+ }
+
+ public List<String> getKeyNames() { return Arrays.asList("ABHet","ABHom","OND"); }
+
+ public List<VCFInfoHeaderLine> getDescriptions() { return Arrays.asList(new VCFInfoHeaderLine("ABHet", 1, VCFHeaderLineType.Float, "Allele Balance for heterozygous calls (ref/(ref+alt))"),
+ new VCFInfoHeaderLine("ABHom", 1, VCFHeaderLineType.Float, "Allele Balance for homozygous calls (A/(A+O)) where A is the allele (ref or alt) and O is anything other"),
+ new VCFInfoHeaderLine("OND", 1, VCFHeaderLineType.Float, "Overall non-diploid ratio (alleles/(alleles+non-alleles))")); }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/AlleleBalanceBySample.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/AlleleBalanceBySample.java
new file mode 100644
index 0000000..9f5ee9c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/AlleleBalanceBySample.java
@@ -0,0 +1,181 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.GenotypeBuilder;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.vcf.VCFFormatHeaderLine;
+import htsjdk.variant.vcf.VCFHeaderLineType;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.AnnotatorCompatible;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.ExperimentalAnnotation;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.GenotypeAnnotation;
+import org.broadinstitute.gatk.utils.genotyper.MostLikelyAllele;
+import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * Allele balance per sample
+ *
+ * <p> This is an experimental annotation that attempts to estimate whether the data supporting a heterozygous genotype call fits allelic ratio expectations, or whether there might be some bias in the data.</p>
+ * <h3>Calculation</h3>
+ * <p> $$ AB = \frac{# ALT alleles}{total # alleles} $$ </p>
+ * <p> Ideally, the value of AB should be close to 0.5, so half of the alleles support the ref allele and half of the alleles support the alt allele. Divergence from the expected ratio may indicate that there is some bias in favor of one allele. Note the caveats below regarding cancer and RNAseq analysis. </p>
+ * <h3>Caveats</h3>
+ * <ul>
+ * <li>This annotation will only work properly for biallelic heterozygous calls.</li>
+ * <li>This annotation cannot currently be calculated for indels.</li>
+ * <li>tThe reasoning underlying this annotation only applies to germline variants in DNA sequencing data. In somatic/cancer analysis, divergent ratios are expected due to tumor heterogeneity. In RNAseq analysis, divergent ratios may indicate differential allele expression.</li>
+ * <li>As stated above, this annotation is experimental and should be interpreted with caution as we cannot guarantee that it is appropriate. Basically, use it at your own risk.</li>
+ * </ul>
+ * <h3>Related annotations</h3>
+ * <ul>
+ * <li><b><a href="https://www.broadinstitute.org/gatk/guide/tooldocs/org_broadinstitute_gatk_tools_walkers_annotator_AlleleBalance.php">AlleleBallance</a></b> is a generalization of this annotation over all samples.</li>
+ * <li><b><a href="https://www.broadinstitute.org/gatk/guide/tooldocs/org_broadinstitute_gatk_tools_walkers_annotator_DepthPerAlleleBySample.php">DepthPerAlleleBySample</a></b> calculates depth of coverage for each allele per sample.</li>
+ * </ul>
+ */
+public class AlleleBalanceBySample extends GenotypeAnnotation implements ExperimentalAnnotation {
+
+ public void annotate(final RefMetaDataTracker tracker,
+ final AnnotatorCompatible walker,
+ final ReferenceContext ref,
+ final AlignmentContext stratifiedContext,
+ final VariantContext vc,
+ final Genotype g,
+ final GenotypeBuilder gb,
+ final PerReadAlleleLikelihoodMap alleleLikelihoodMap){
+
+
+ // We need a heterozygous genotype and either a context or alleleLikelihoodMap
+ if ( g == null || !g.isCalled() || !g.isHet() || ( stratifiedContext == null && alleleLikelihoodMap == null) )
+ return;
+
+ // Test for existence of <NON_REF> allele, and manually check isSNP()
+ // and isBiallelic() while ignoring the <NON_REF> allele
+ boolean biallelicSNP = vc.isSNP() && vc.isBiallelic();
+
+ if(vc.hasAllele(GVCF_NONREF)){
+ // If we have the GVCF <NON_REF> allele, then the SNP is biallelic
+ // iff there are 3 alleles and both the reference and first alt
+ // allele are length 1.
+ biallelicSNP = vc.getAlleles().size() == 3 &&
+ vc.getReference().length() == 1 &&
+ vc.getAlternateAllele(0).length() == 1;
+ }
+
+ if ( !biallelicSNP )
+ return;
+
+ Double ratio;
+ if (alleleLikelihoodMap != null && !alleleLikelihoodMap.isEmpty())
+ ratio = annotateWithLikelihoods(alleleLikelihoodMap, vc);
+ else if ( stratifiedContext != null )
+ ratio = annotateWithPileup(stratifiedContext, vc);
+ else
+ return;
+
+ if (ratio == null)
+ return;
+
+ gb.attribute(getKeyNames().get(0), Double.valueOf(String.format("%.2f", ratio)));
+ }
+
+ private static final Allele GVCF_NONREF = Allele.create("<NON_REF>", false);
+
+ private Double annotateWithPileup(final AlignmentContext stratifiedContext, final VariantContext vc) {
+
+ final HashMap<Byte, Integer> alleleCounts = new HashMap<>();
+ for ( final Allele allele : vc.getAlleles() )
+ alleleCounts.put(allele.getBases()[0], 0);
+
+ final ReadBackedPileup pileup = stratifiedContext.getBasePileup();
+ for ( final PileupElement p : pileup ) {
+ if ( alleleCounts.containsKey(p.getBase()) )
+ alleleCounts.put(p.getBase(), alleleCounts.get(p.getBase())+1);
+ }
+
+ // we need to add counts in the correct order
+ final int[] counts = new int[alleleCounts.size()];
+ counts[0] = alleleCounts.get(vc.getReference().getBases()[0]);
+ for (int i = 0; i < vc.getAlternateAlleles().size(); i++)
+ counts[i+1] = alleleCounts.get(vc.getAlternateAllele(i).getBases()[0]);
+
+ // sanity check
+ if(counts[0] + counts[1] == 0)
+ return null;
+
+ return ((double) counts[0] / (double)(counts[0] + counts[1]));
+ }
+
+ private Double annotateWithLikelihoods(final PerReadAlleleLikelihoodMap perReadAlleleLikelihoodMap, final VariantContext vc) {
+ final Set<Allele> alleles = new HashSet<>(vc.getAlleles());
+
+ // make sure that there's a meaningful relationship between the alleles in the perReadAlleleLikelihoodMap and our VariantContext
+ if ( ! perReadAlleleLikelihoodMap.getAllelesSet().containsAll(alleles) )
+ throw new IllegalStateException("VC alleles " + alleles + " not a strict subset of per read allele map alleles " + perReadAlleleLikelihoodMap.getAllelesSet());
+
+ final HashMap<Allele, Integer> alleleCounts = new HashMap<>();
+ for ( final Allele allele : vc.getAlleles() ) { alleleCounts.put(allele, 0); }
+
+ for ( final Map.Entry<GATKSAMRecord,Map<Allele,Double>> el : perReadAlleleLikelihoodMap.getLikelihoodReadMap().entrySet()) {
+ final MostLikelyAllele a = PerReadAlleleLikelihoodMap.getMostLikelyAllele(el.getValue(), alleles);
+ if (! a.isInformative() ) continue; // read is non-informative
+ final int prevCount = alleleCounts.get(a.getMostLikelyAllele());
+ alleleCounts.put(a.getMostLikelyAllele(), prevCount + 1);
+ }
+
+ final int[] counts = new int[alleleCounts.size()];
+ counts[0] = alleleCounts.get(vc.getReference());
+ for (int i = 0; i < vc.getAlternateAlleles().size(); i++)
+ counts[i+1] = alleleCounts.get( vc.getAlternateAllele(i) );
+
+ // sanity check
+ if(counts[0] + counts[1] == 0)
+ return null;
+
+ return ((double) counts[0] / (double)(counts[0] + counts[1]));
+
+ }
+
+ public List<String> getKeyNames() { return Arrays.asList("AB"); }
+
+ public List<VCFFormatHeaderLine> getDescriptions() { return Arrays.asList(new VCFFormatHeaderLine(getKeyNames().get(0), 1, VCFHeaderLineType.Float, "Allele balance for each het genotype")); }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/BaseCounts.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/BaseCounts.java
new file mode 100644
index 0000000..44579f9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/BaseCounts.java
@@ -0,0 +1,91 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.AnnotatorCompatible;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.InfoFieldAnnotation;
+import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import htsjdk.variant.vcf.VCFHeaderLineType;
+import htsjdk.variant.vcf.VCFInfoHeaderLine;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Count of A, C, G, T bases across all samples
+ *
+ * <p> This annotation returns the counts of A, C, G, and T bases across all samples, in that order.</p>
+ * <h3>Example:</h3>
+ *
+ * <pre>BaseCounts=3,0,3,0</pre>
+ *
+ * <p>
+ * This means the number of A bases seen is 3, the number of T bases seen is 0, the number of G bases seen is 3, and the number of T bases seen is 0.
+ * </p>
+ *
+ * <h3>Related annotations</h3>
+ * <ul>
+ * <li><b><a href="https://www.broadinstitute.org/gatk/guide/tooldocs/org_broadinstitute_gatk_tools_walkers_annotator_NBaseCount.php">NBaseCount</a></b> counts the percentage of N bases.</li>
+ * </ul>
+ */
+
+ public class BaseCounts extends InfoFieldAnnotation {
+
+ public Map<String, Object> annotate(final RefMetaDataTracker tracker,
+ final AnnotatorCompatible walker,
+ final ReferenceContext ref,
+ final Map<String, AlignmentContext> stratifiedContexts,
+ final VariantContext vc,
+ final Map<String, PerReadAlleleLikelihoodMap> stratifiedPerReadAlleleLikelihoodMap) {
+ if ( stratifiedContexts.size() == 0 )
+ return null;
+
+ int[] counts = new int[4];
+
+ for ( Map.Entry<String, AlignmentContext> sample : stratifiedContexts.entrySet() ) {
+ for (byte base : sample.getValue().getBasePileup().getBases() ) {
+ int index = BaseUtils.simpleBaseToBaseIndex(base);
+ if ( index != -1 )
+ counts[index]++;
+ }
+ }
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put(getKeyNames().get(0), counts);
+ return map;
+ }
+
+ public List<String> getKeyNames() { return Arrays.asList("BaseCounts"); }
+
+ public List<VCFInfoHeaderLine> getDescriptions() { return Arrays.asList(new VCFInfoHeaderLine("BaseCounts", 4, VCFHeaderLineType.Integer, "Counts of each base")); }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/ChromosomeCountConstants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/ChromosomeCountConstants.java
new file mode 100644
index 0000000..67fc0a4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/ChromosomeCountConstants.java
@@ -0,0 +1,44 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+import htsjdk.variant.vcf.VCFConstants;
+import htsjdk.variant.vcf.VCFInfoHeaderLine;
+import htsjdk.variant.vcf.VCFStandardHeaderLines;
+
+
+/**
+ * Keys and descriptions for the common chromosome count annotations
+ */
+public class ChromosomeCountConstants {
+
+ public static final String[] keyNames = { VCFConstants.ALLELE_NUMBER_KEY, VCFConstants.ALLELE_COUNT_KEY, VCFConstants.ALLELE_FREQUENCY_KEY };
+
+ public static final VCFInfoHeaderLine[] descriptions = {
+ VCFStandardHeaderLines.getInfoLine(VCFConstants.ALLELE_FREQUENCY_KEY),
+ VCFStandardHeaderLines.getInfoLine(VCFConstants.ALLELE_COUNT_KEY),
+ VCFStandardHeaderLines.getInfoLine(VCFConstants.ALLELE_NUMBER_KEY) };
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/LowMQ.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/LowMQ.java
new file mode 100644
index 0000000..05054a3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/LowMQ.java
@@ -0,0 +1,91 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.AnnotatorCompatible;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.InfoFieldAnnotation;
+import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap;
+import htsjdk.variant.vcf.VCFHeaderLineType;
+import htsjdk.variant.vcf.VCFInfoHeaderLine;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Proportion of low quality reads
+ *
+ * <p>This annotation tells you what fraction of reads have a mapping quality of less than the given threshold of 10 (including 0). Note that certain tools may impose a different minimum mapping quality threshold. For example, HaplotypeCaller excludes reads with MAPQ<20.</p>
+ *
+ * <h3>Calculation</h3>
+ * <p> $$ LowMQ = \frac{# reads with MAPQ=0 + # reads with MAPQ<10}{total # reads} $$
+ * </p>
+ *
+ * <h3>Related annotations</h3>
+ * <ul>
+ * <li><b><a href="https://www.broadinstitute.org/gatk/guide/tooldocs/org_broadinstitute_gatk_tools_walkers_annotator_MappingQualityZero.php">MappingQualityZero</a></b> gives the count of reads with MAPQ=0 across all samples.</li>
+ * <li><b><a href="https://www.broadinstitute.org/gatk/guide/tooldocs/org_broadinstitute_gatk_tools_walkers_annotator_MappingQualityZeroBySample.php">MappingQualityZeroBySample</a></b> gives the count of reads with MAPQ=0 for each individual sample.</li>
+ * </ul>
+ */
+public class LowMQ extends InfoFieldAnnotation {
+
+ public Map<String, Object> annotate(final RefMetaDataTracker tracker,
+ final AnnotatorCompatible walker,
+ final ReferenceContext ref,
+ final Map<String, AlignmentContext> stratifiedContexts,
+ final VariantContext vc,
+ final Map<String, PerReadAlleleLikelihoodMap> stratifiedPerReadAlleleLikelihoodMap) {
+ if ( stratifiedContexts.size() == 0 )
+ return null;
+
+ double mq0 = 0;
+ double mq10 = 0;
+ double total = 0;
+ for ( Map.Entry<String, AlignmentContext> sample : stratifiedContexts.entrySet() )
+ {
+ for ( PileupElement p : sample.getValue().getBasePileup() )
+ {
+ if ( p.getMappingQual() == 0 ) { mq0 += 1; }
+ if ( p.getMappingQual() <= 10 ) { mq10 += 1; }
+ total += 1;
+ }
+ }
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put(getKeyNames().get(0), String.format("%.04f,%.04f,%.00f", mq0/total, mq10/total, total));
+ return map;
+ }
+
+ public List<String> getKeyNames() { return Arrays.asList("LowMQ"); }
+
+ public List<VCFInfoHeaderLine> getDescriptions() { return Arrays.asList(new VCFInfoHeaderLine(getKeyNames().get(0), 3, VCFHeaderLineType.Float, "3-tuple: <fraction of reads with MQ=0>,<fraction of reads with MQ<=10>,<total number of reads>")); }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/MappingQualityZeroBySample.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/MappingQualityZeroBySample.java
new file mode 100644
index 0000000..cf1323f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/MappingQualityZeroBySample.java
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.AnnotatorCompatible;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.GenotypeAnnotation;
+import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap;
+import htsjdk.variant.vcf.VCFConstants;
+import htsjdk.variant.vcf.VCFFormatHeaderLine;
+import htsjdk.variant.vcf.VCFHeaderLineType;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.GenotypeBuilder;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Count of reads with mapping quality zero for each sample
+ *
+ * <p>This annotation gives you the count of all reads that have MAPQ = 0 for each sample. The count of reads with MAPQ0 can be used for quality control; high counts typically indicate regions where it is difficult to make confident calls.</p>
+ *
+ * <h3>Related annotations</h3>
+ * <ul>
+ * <li><b><a href="https://www.broadinstitute.org/gatk/guide/tooldocs/org_broadinstitute_gatk_tools_walkers_annotator_MappingQualityZero.php">MappingQualityZero</a></b> gives the count of reads with MAPQ=0 across all samples.</li>
+ * <li><b><a href="https://www.broadinstitute.org/gatk/guide/tooldocs/org_broadinstitute_gatk_tools_walkers_annotator_LowMQ.php">LowMQ</a></b> gives the proportion of reads with low mapping quality (MAPQ below 10, including 0).</li>
+ * </ul>
+ */
+public class MappingQualityZeroBySample extends GenotypeAnnotation {
+ public void annotate(final RefMetaDataTracker tracker,
+ final AnnotatorCompatible walker,
+ final ReferenceContext ref,
+ final AlignmentContext stratifiedContext,
+ final VariantContext vc,
+ final Genotype g,
+ final GenotypeBuilder gb,
+ final PerReadAlleleLikelihoodMap alleleLikelihoodMap){
+ if ( g == null || !g.isCalled() || stratifiedContext == null )
+ return;
+
+ int mq0 = 0;
+ final ReadBackedPileup pileup = stratifiedContext.getBasePileup();
+ for (PileupElement p : pileup ) {
+ if ( p.getMappingQual() == 0 )
+ mq0++;
+ }
+
+ gb.attribute(getKeyNames().get(0), mq0);
+ }
+
+ public List<String> getKeyNames() { return Arrays.asList(VCFConstants.MAPPING_QUALITY_ZERO_KEY); }
+
+ public List<VCFFormatHeaderLine> getDescriptions() { return Arrays.asList(
+ new VCFFormatHeaderLine(getKeyNames().get(0), 1,
+ VCFHeaderLineType.Integer, "Number of Mapping Quality Zero Reads per sample")); }
+
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/NBaseCount.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/NBaseCount.java
new file mode 100644
index 0000000..544feb7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/NBaseCount.java
@@ -0,0 +1,89 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.AnnotatorCompatible;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.InfoFieldAnnotation;
+import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import htsjdk.variant.vcf.VCFHeaderLineType;
+import htsjdk.variant.vcf.VCFInfoHeaderLine;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Percentage of N bases
+ *
+ * <p>N occurs in a sequence when the sequencer does not have enough information to determine which base it should call. The presence of many Ns at the same site lowers our confidence in any calls made there, because it suggests that there was some kind of technical difficulty that interfered with the sequencing process.</p>
+ *
+ * <p><b>Note that in GATK versions 3.2 and earlier, this annotation only counted N bases from reads generated with SOLiD technology. This functionality was generalized for all sequencing platforms in GATK version 3.3.</b></p>
+ *
+ * <h3>Related annotations</h3>
+ * <ul>
+ * <li><b><a href="https://www.broadinstitute.org/gatk/guide/tooldocs/org_broadinstitute_gatk_tools_walkers_annotator_BaseCounts.php">BaseCounts</a></b> counts the number of A, C, G, T bases across all samples.</li>
+ * </ul>
+ *
+ * */
+public class NBaseCount extends InfoFieldAnnotation {
+ public Map<String, Object> annotate(final RefMetaDataTracker tracker,
+ final AnnotatorCompatible walker,
+ final ReferenceContext ref,
+ final Map<String, AlignmentContext> stratifiedContexts,
+ final VariantContext vc,
+ final Map<String, PerReadAlleleLikelihoodMap> stratifiedPerReadAlleleLikelihoodMap) {
+ if( stratifiedContexts.size() == 0 )
+ return null;
+
+ int countNBase = 0;
+ int countRegularBase = 0;
+
+ for( final AlignmentContext context : stratifiedContexts.values() ) {
+ for( final PileupElement p : context.getBasePileup()) {
+ final String platform = p.getRead().getReadGroup().getPlatform();
+ if( BaseUtils.isNBase( p.getBase() ) ) {
+ countNBase++;
+ } else if( BaseUtils.isRegularBase( p.getBase() ) ) {
+ countRegularBase++;
+ }
+ }
+ }
+ final Map<String, Object> map = new HashMap<String, Object>();
+ map.put(getKeyNames().get(0), String.format("%.4f", (double)countNBase / (double)(countNBase + countRegularBase + 1)));
+ return map;
+ }
+
+ public List<String> getKeyNames() { return Arrays.asList("PercentNBase"); }
+
+ public List<VCFInfoHeaderLine> getDescriptions() { return Arrays.asList(new VCFInfoHeaderLine("PercentNBase", 1, VCFHeaderLineType.Float, "Percentage of N bases in the pileup")); }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/SnpEff.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/SnpEff.java
new file mode 100644
index 0000000..f514f67
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/SnpEff.java
@@ -0,0 +1,586 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.AnnotatorCompatible;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.InfoFieldAnnotation;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.RodRequiringAnnotation;
+import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import htsjdk.variant.vcf.*;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * Top effect from SnpEff functional predictions
+ *
+ * <p>This annotation processes the output of the SnpEff functional prediction tool to select only the predicted effect with the highest biological impact. The SnpEff output must be provided on the command line by specifying "--snpEffFile filename.vcf". See <a href="http://snpeff.sourceforge.net/">http://snpeff.sourceforge.net/</a> for more information about the SnpEff tool</p>.
+ *
+ * <h3>Caveats</h3>
+ *
+ * <ul><li>This annotation currently only supports output from SnpEff version 2.0.5.</li></ul>
+ *
+ */
+public class SnpEff extends InfoFieldAnnotation implements RodRequiringAnnotation {
+
+ private static Logger logger = Logger.getLogger(SnpEff.class);
+
+ // We refuse to parse SnpEff output files generated by unsupported versions, or
+ // lacking a SnpEff version number in the VCF header:
+ public static final String[] SUPPORTED_SNPEFF_VERSIONS = { "2.0.5" };
+ public static final String SNPEFF_VCF_HEADER_VERSION_LINE_KEY = "SnpEffVersion";
+ public static final String SNPEFF_VCF_HEADER_COMMAND_LINE_KEY = "SnpEffCmd";
+ public static final String SNPEFF_GATK_COMPATIBILITY_ARGUMENT = "-o gatk";
+ public static final Pattern SNPEFF_GATK_COMPATIBILITY_ARGUMENT_PATTERN = Pattern.compile("-o\\s+gatk");
+
+ // When we write the SnpEff version number and command line to the output VCF, we change
+ // the key name slightly so that the output VCF won't be confused in the future for an
+ // output file produced by SnpEff directly:
+ public static final String OUTPUT_VCF_HEADER_VERSION_LINE_KEY = "Original" + SNPEFF_VCF_HEADER_VERSION_LINE_KEY;
+ public static final String OUTPUT_VCF_HEADER_COMMAND_LINE_KEY = "Original" + SNPEFF_VCF_HEADER_COMMAND_LINE_KEY;
+
+ // SnpEff aggregates all effects (and effect metadata) together into a single INFO
+ // field annotation with the key EFF:
+ public static final String SNPEFF_INFO_FIELD_KEY = "EFF";
+ public static final String SNPEFF_EFFECT_METADATA_DELIMITER = "[()]";
+ public static final String SNPEFF_EFFECT_METADATA_SUBFIELD_DELIMITER = "\\|";
+
+ // Key names for the INFO field annotations we will add to each record, along
+ // with parsing-related information:
+ public enum InfoFieldKey {
+ EFFECT_KEY ("SNPEFF_EFFECT", -1),
+ IMPACT_KEY ("SNPEFF_IMPACT", 0),
+ FUNCTIONAL_CLASS_KEY ("SNPEFF_FUNCTIONAL_CLASS", 1),
+ CODON_CHANGE_KEY ("SNPEFF_CODON_CHANGE", 2),
+ AMINO_ACID_CHANGE_KEY ("SNPEFF_AMINO_ACID_CHANGE", 3),
+ GENE_NAME_KEY ("SNPEFF_GENE_NAME", 4),
+ GENE_BIOTYPE_KEY ("SNPEFF_GENE_BIOTYPE", 5),
+ TRANSCRIPT_ID_KEY ("SNPEFF_TRANSCRIPT_ID", 7),
+ EXON_ID_KEY ("SNPEFF_EXON_ID", 8);
+
+ // Actual text of the key
+ private final String keyName;
+
+ // Index within the effect metadata subfields from the SnpEff EFF annotation
+ // where each key's associated value can be found during parsing.
+ private final int fieldIndex;
+
+ InfoFieldKey ( String keyName, int fieldIndex ) {
+ this.keyName = keyName;
+ this.fieldIndex = fieldIndex;
+ }
+
+ public String getKeyName() {
+ return keyName;
+ }
+
+ public int getFieldIndex() {
+ return fieldIndex;
+ }
+ }
+
+ // Possible SnpEff biological effects. All effect names found in the SnpEff input file
+ // are validated against this list.
+ public enum EffectType {
+ // High-impact effects:
+ SPLICE_SITE_ACCEPTOR,
+ SPLICE_SITE_DONOR,
+ START_LOST,
+ EXON_DELETED,
+ FRAME_SHIFT,
+ STOP_GAINED,
+ STOP_LOST,
+
+ // Moderate-impact effects:
+ NON_SYNONYMOUS_CODING,
+ CODON_CHANGE,
+ CODON_INSERTION,
+ CODON_CHANGE_PLUS_CODON_INSERTION,
+ CODON_DELETION,
+ CODON_CHANGE_PLUS_CODON_DELETION,
+ UTR_5_DELETED,
+ UTR_3_DELETED,
+
+ // Low-impact effects:
+ SYNONYMOUS_START,
+ NON_SYNONYMOUS_START,
+ START_GAINED,
+ SYNONYMOUS_CODING,
+ SYNONYMOUS_STOP,
+ NON_SYNONYMOUS_STOP,
+
+ // Modifiers:
+ NONE,
+ CHROMOSOME,
+ CUSTOM,
+ CDS,
+ GENE,
+ TRANSCRIPT,
+ EXON,
+ INTRON_CONSERVED,
+ UTR_5_PRIME,
+ UTR_3_PRIME,
+ DOWNSTREAM,
+ INTRAGENIC,
+ INTERGENIC,
+ INTERGENIC_CONSERVED,
+ UPSTREAM,
+ REGULATION,
+ INTRON
+ }
+
+ // SnpEff labels each effect as either LOW, MODERATE, or HIGH impact, or as a MODIFIER.
+ public enum EffectImpact {
+ MODIFIER (0),
+ LOW (1),
+ MODERATE (2),
+ HIGH (3);
+
+ private final int severityRating;
+
+ EffectImpact ( int severityRating ) {
+ this.severityRating = severityRating;
+ }
+
+ public boolean isHigherImpactThan ( EffectImpact other ) {
+ return this.severityRating > other.severityRating;
+ }
+
+ public boolean isSameImpactAs ( EffectImpact other ) {
+ return this.severityRating == other.severityRating;
+ }
+ }
+
+ // SnpEff labels most effects as either CODING or NON_CODING, but sometimes omits this information.
+ public enum EffectCoding {
+ CODING,
+ NON_CODING,
+ UNKNOWN
+ }
+
+ // SnpEff assigns a functional class to each effect.
+ public enum EffectFunctionalClass {
+ NONE (0),
+ SILENT (1),
+ MISSENSE (2),
+ NONSENSE (3);
+
+ private final int priority;
+
+ EffectFunctionalClass ( int priority ) {
+ this.priority = priority;
+ }
+
+ public boolean isHigherPriorityThan ( EffectFunctionalClass other ) {
+ return this.priority > other.priority;
+ }
+ }
+
+ public void initialize ( AnnotatorCompatible walker, GenomeAnalysisEngine toolkit, Set<VCFHeaderLine> headerLines ) {
+ // Make sure that we actually have a valid SnpEff rod binding (just in case the user specified -A SnpEff
+ // without providing a SnpEff rod via --snpEffFile):
+ validateRodBinding(walker.getSnpEffRodBinding());
+ RodBinding<VariantContext> snpEffRodBinding = walker.getSnpEffRodBinding();
+
+ // Make sure that the SnpEff version number and command-line header lines are present in the VCF header of
+ // the SnpEff rod, and that the file was generated by a supported version of SnpEff:
+ VCFHeader snpEffVCFHeader = GATKVCFUtils.getVCFHeadersFromRods(toolkit, Arrays.asList(snpEffRodBinding.getName())).get(snpEffRodBinding.getName());
+ VCFHeaderLine snpEffVersionLine = snpEffVCFHeader.getOtherHeaderLine(SNPEFF_VCF_HEADER_VERSION_LINE_KEY);
+ VCFHeaderLine snpEffCommandLine = snpEffVCFHeader.getOtherHeaderLine(SNPEFF_VCF_HEADER_COMMAND_LINE_KEY);
+
+ checkSnpEffVersionAndCommandLine(snpEffVersionLine, snpEffCommandLine);
+
+ // If everything looks ok, add the SnpEff version number and command-line header lines to the
+ // header of the VCF output file, changing the key names so that our output file won't be
+ // mistaken in the future for a SnpEff output file:
+ headerLines.add(new VCFHeaderLine(OUTPUT_VCF_HEADER_VERSION_LINE_KEY, snpEffVersionLine.getValue()));
+ headerLines.add(new VCFHeaderLine(OUTPUT_VCF_HEADER_COMMAND_LINE_KEY, snpEffCommandLine.getValue()));
+ }
+
+ public Map<String, Object> annotate(final RefMetaDataTracker tracker,
+ final AnnotatorCompatible walker,
+ final ReferenceContext ref,
+ final Map<String, AlignmentContext> stratifiedContexts,
+ final VariantContext vc,
+ final Map<String, PerReadAlleleLikelihoodMap> stratifiedPerReadAlleleLikelihoodMap) {
+ RodBinding<VariantContext> snpEffRodBinding = walker.getSnpEffRodBinding();
+
+ // Get only SnpEff records that start at this locus, not merely span it:
+ List<VariantContext> snpEffRecords = tracker.getValues(snpEffRodBinding, ref.getLocus());
+
+ // Within this set, look for a SnpEff record whose ref/alt alleles match the record to annotate.
+ // If there is more than one such record, we only need to pick the first one, since the biological
+ // effects will be the same across all such records:
+ VariantContext matchingRecord = getMatchingSnpEffRecord(snpEffRecords, vc);
+ if ( matchingRecord == null ) {
+ return null;
+ }
+
+ // Parse the SnpEff INFO field annotation from the matching record into individual effect objects:
+ List<SnpEffEffect> effects = parseSnpEffRecord(matchingRecord);
+ if ( effects.size() == 0 ) {
+ return null;
+ }
+
+ // Add only annotations for one of the most biologically-significant effects from this set:
+ SnpEffEffect mostSignificantEffect = getMostSignificantEffect(effects);
+ return mostSignificantEffect.getAnnotations();
+ }
+
+ private void validateRodBinding ( RodBinding<VariantContext> snpEffRodBinding ) {
+ if ( snpEffRodBinding == null || ! snpEffRodBinding.isBound() ) {
+ throw new UserException("The SnpEff annotator requires that a SnpEff VCF output file be provided " +
+ "as a rodbinding on the command line via the --snpEffFile option, but " +
+ "no SnpEff rodbinding was found.");
+ }
+ }
+
+ private void checkSnpEffVersionAndCommandLine( final VCFHeaderLine snpEffVersionLine, final VCFHeaderLine snpEffCommandLine ) {
+ if ( snpEffVersionLine == null || snpEffVersionLine.getValue() == null || snpEffVersionLine.getValue().trim().length() == 0 ) {
+ throw new UserException(String.format("Could not find a %s entry in the VCF header for the SnpEff input file, " +
+ "and so could not verify that the file was generated by a supported version of SnpEff (%s)",
+ SNPEFF_VCF_HEADER_VERSION_LINE_KEY, supportedSnpEffVersionsString()));
+ }
+
+ if ( snpEffCommandLine == null || snpEffCommandLine.getValue() == null || snpEffCommandLine.getValue().trim().length() == 0 ) {
+ throw new UserException(String.format("Could not find a %s entry in the VCF header for the SnpEff input file, " +
+ "which should be added by all supported versions of SnpEff (%s)",
+ SNPEFF_VCF_HEADER_COMMAND_LINE_KEY, supportedSnpEffVersionsString()));
+ }
+
+ String snpEffVersionString = snpEffVersionLine.getValue().replaceAll("\"", "").split(" ")[0];
+
+ if ( ! isSupportedSnpEffVersion(snpEffVersionString, snpEffCommandLine.getValue()) ) {
+ throw new UserException(String.format("The version of SnpEff used to generate the SnpEff input file (%s) " +
+ "is not currently supported by the GATK, and was not run in GATK " +
+ "compatibility mode. Supported versions are: %s",
+ snpEffVersionString, supportedSnpEffVersionsString()));
+ }
+ }
+
+ private boolean isSupportedSnpEffVersion( final String versionString, final String commandLine ) {
+ // first check to see if it's an officially-supported version
+ for ( String supportedVersion : SUPPORTED_SNPEFF_VERSIONS ) {
+ if ( supportedVersion.equals(versionString) ) {
+ return true;
+ }
+ }
+
+ // if it's not an officially-supported version, check to see whether the
+ // "-o gatk" compatibility option was specified
+ return SNPEFF_GATK_COMPATIBILITY_ARGUMENT_PATTERN.matcher(commandLine).find();
+ }
+
+ private String supportedSnpEffVersionsString() {
+ return String.format("%s, as well as later versions when run with the option %s",
+ Arrays.toString(SUPPORTED_SNPEFF_VERSIONS), SNPEFF_GATK_COMPATIBILITY_ARGUMENT);
+ }
+
+ private VariantContext getMatchingSnpEffRecord ( List<VariantContext> snpEffRecords, VariantContext vc ) {
+ for ( VariantContext snpEffRecord : snpEffRecords ) {
+ if ( snpEffRecord.hasSameAlternateAllelesAs(vc) && snpEffRecord.getReference().equals(vc.getReference()) ) {
+ return snpEffRecord;
+ }
+ }
+
+ return null;
+ }
+
+ private List<SnpEffEffect> parseSnpEffRecord ( VariantContext snpEffRecord ) {
+ List<SnpEffEffect> parsedEffects = new ArrayList<SnpEffEffect>();
+
+ Object effectFieldValue = snpEffRecord.getAttribute(SNPEFF_INFO_FIELD_KEY);
+ if ( effectFieldValue == null ) {
+ return parsedEffects;
+ }
+
+ // The VCF codec stores multi-valued fields as a List<String>, and single-valued fields as a String.
+ // We can have either in the case of SnpEff, since there may be one or more than one effect in this record.
+ List<String> individualEffects;
+ if ( effectFieldValue instanceof List ) {
+ individualEffects = (List<String>)effectFieldValue;
+ }
+ else {
+ individualEffects = Arrays.asList((String)effectFieldValue);
+ }
+
+ for ( String effectString : individualEffects ) {
+ String[] effectNameAndMetadata = effectString.split(SNPEFF_EFFECT_METADATA_DELIMITER);
+
+ if ( effectNameAndMetadata.length != 2 ) {
+ logger.warn(String.format("Malformed SnpEff effect field at %s:%d, skipping: %s",
+ snpEffRecord.getChr(), snpEffRecord.getStart(), effectString));
+ continue;
+ }
+
+ String effectName = effectNameAndMetadata[0];
+ String[] effectMetadata = effectNameAndMetadata[1].split(SNPEFF_EFFECT_METADATA_SUBFIELD_DELIMITER, -1);
+
+ SnpEffEffect parsedEffect = new SnpEffEffect(effectName, effectMetadata);
+
+ if ( parsedEffect.isWellFormed() ) {
+ parsedEffects.add(parsedEffect);
+ }
+ else {
+ logger.warn(String.format("Skipping malformed SnpEff effect field at %s:%d. Error was: \"%s\". Field was: \"%s\"",
+ snpEffRecord.getChr(), snpEffRecord.getStart(), parsedEffect.getParseError(), effectString));
+ }
+ }
+
+ return parsedEffects;
+ }
+
+ private SnpEffEffect getMostSignificantEffect ( List<SnpEffEffect> effects ) {
+ SnpEffEffect mostSignificantEffect = null;
+
+ for ( SnpEffEffect effect : effects ) {
+ if ( mostSignificantEffect == null ||
+ effect.isHigherImpactThan(mostSignificantEffect) ) {
+
+ mostSignificantEffect = effect;
+ }
+ }
+
+ return mostSignificantEffect;
+ }
+
+ public List<String> getKeyNames() {
+ return Arrays.asList( InfoFieldKey.EFFECT_KEY.getKeyName(),
+ InfoFieldKey.IMPACT_KEY.getKeyName(),
+ InfoFieldKey.FUNCTIONAL_CLASS_KEY.getKeyName(),
+ InfoFieldKey.CODON_CHANGE_KEY.getKeyName(),
+ InfoFieldKey.AMINO_ACID_CHANGE_KEY.getKeyName(),
+ InfoFieldKey.GENE_NAME_KEY.getKeyName(),
+ InfoFieldKey.GENE_BIOTYPE_KEY.getKeyName(),
+ InfoFieldKey.TRANSCRIPT_ID_KEY.getKeyName(),
+ InfoFieldKey.EXON_ID_KEY.getKeyName()
+ );
+ }
+
+ public List<VCFInfoHeaderLine> getDescriptions() {
+ return Arrays.asList(
+ new VCFInfoHeaderLine(InfoFieldKey.EFFECT_KEY.getKeyName(), 1, VCFHeaderLineType.String, "The highest-impact effect resulting from the current variant (or one of the highest-impact effects, if there is a tie)"),
+ new VCFInfoHeaderLine(InfoFieldKey.IMPACT_KEY.getKeyName(), 1, VCFHeaderLineType.String, "Impact of the highest-impact effect resulting from the current variant " + Arrays.toString(EffectImpact.values())),
+ new VCFInfoHeaderLine(InfoFieldKey.FUNCTIONAL_CLASS_KEY.getKeyName(), 1, VCFHeaderLineType.String, "Functional class of the highest-impact effect resulting from the current variant: " + Arrays.toString(EffectFunctionalClass.values())),
+ new VCFInfoHeaderLine(InfoFieldKey.CODON_CHANGE_KEY.getKeyName(), 1, VCFHeaderLineType.String, "Old/New codon for the highest-impact effect resulting from the current variant"),
+ new VCFInfoHeaderLine(InfoFieldKey.AMINO_ACID_CHANGE_KEY.getKeyName(), 1, VCFHeaderLineType.String, "Old/New amino acid for the highest-impact effect resulting from the current variant (in HGVS style)"),
+ new VCFInfoHeaderLine(InfoFieldKey.GENE_NAME_KEY.getKeyName(), 1, VCFHeaderLineType.String, "Gene name for the highest-impact effect resulting from the current variant"),
+ new VCFInfoHeaderLine(InfoFieldKey.GENE_BIOTYPE_KEY.getKeyName(), 1, VCFHeaderLineType.String, "Gene biotype for the highest-impact effect resulting from the current variant"),
+ new VCFInfoHeaderLine(InfoFieldKey.TRANSCRIPT_ID_KEY.getKeyName(), 1, VCFHeaderLineType.String, "Transcript ID for the highest-impact effect resulting from the current variant"),
+ new VCFInfoHeaderLine(InfoFieldKey.EXON_ID_KEY.getKeyName(), 1, VCFHeaderLineType.String, "Exon ID for the highest-impact effect resulting from the current variant")
+ );
+ }
+
+ /**
+ * Helper class to parse, validate, and store a single SnpEff effect and its metadata.
+ */
+ protected static class SnpEffEffect {
+ private EffectType effect;
+ private EffectImpact impact;
+ private EffectFunctionalClass functionalClass;
+ private String codonChange;
+ private String aminoAcidChange;
+ private String geneName;
+ private String geneBiotype;
+ private EffectCoding coding;
+ private String transcriptID;
+ private String exonID;
+
+ private String parseError = null;
+ private boolean isWellFormed = true;
+
+ private static final int EXPECTED_NUMBER_OF_METADATA_FIELDS = 9;
+ private static final int NUMBER_OF_METADATA_FIELDS_UPON_EITHER_WARNING_OR_ERROR = 10;
+ private static final int NUMBER_OF_METADATA_FIELDS_UPON_BOTH_WARNING_AND_ERROR = 11;
+
+ // If there is either a warning OR an error, it will be in the last field. If there is both
+ // a warning AND an error, the warning will be in the second-to-last field, and the error will
+ // be in the last field.
+ private static final int SNPEFF_WARNING_OR_ERROR_FIELD_UPON_SINGLE_ERROR = NUMBER_OF_METADATA_FIELDS_UPON_EITHER_WARNING_OR_ERROR - 1;
+ private static final int SNPEFF_WARNING_FIELD_UPON_BOTH_WARNING_AND_ERROR = NUMBER_OF_METADATA_FIELDS_UPON_BOTH_WARNING_AND_ERROR - 2;
+ private static final int SNPEFF_ERROR_FIELD_UPON_BOTH_WARNING_AND_ERROR = NUMBER_OF_METADATA_FIELDS_UPON_BOTH_WARNING_AND_ERROR - 1;
+
+ // Position of the field indicating whether the effect is coding or non-coding. This field is used
+ // in selecting the most significant effect, but is not included in the annotations we return
+ // since it can be deduced from the SNPEFF_GENE_BIOTYPE field.
+ private static final int SNPEFF_CODING_FIELD_INDEX = 6;
+
+ public SnpEffEffect ( String effectName, String[] effectMetadata ) {
+ parseEffectName(effectName);
+ parseEffectMetadata(effectMetadata);
+ }
+
+ private void parseEffectName ( String effectName ) {
+ try {
+ effect = EffectType.valueOf(effectName);
+ }
+ catch ( IllegalArgumentException e ) {
+ parseError(String.format("%s is not a recognized effect type", effectName));
+ }
+ }
+
+ private void parseEffectMetadata ( String[] effectMetadata ) {
+ if ( effectMetadata.length != EXPECTED_NUMBER_OF_METADATA_FIELDS ) {
+ if ( effectMetadata.length == NUMBER_OF_METADATA_FIELDS_UPON_EITHER_WARNING_OR_ERROR ) {
+ parseError(String.format("SnpEff issued the following warning or error: \"%s\"",
+ effectMetadata[SNPEFF_WARNING_OR_ERROR_FIELD_UPON_SINGLE_ERROR]));
+ }
+ else if ( effectMetadata.length == NUMBER_OF_METADATA_FIELDS_UPON_BOTH_WARNING_AND_ERROR ) {
+ parseError(String.format("SnpEff issued the following warning: \"%s\", and the following error: \"%s\"",
+ effectMetadata[SNPEFF_WARNING_FIELD_UPON_BOTH_WARNING_AND_ERROR],
+ effectMetadata[SNPEFF_ERROR_FIELD_UPON_BOTH_WARNING_AND_ERROR]));
+ }
+ else {
+ parseError(String.format("Wrong number of effect metadata fields. Expected %d but found %d",
+ EXPECTED_NUMBER_OF_METADATA_FIELDS, effectMetadata.length));
+ }
+
+ return;
+ }
+
+ // The impact field will never be empty, and should always contain one of the enumerated values:
+ try {
+ impact = EffectImpact.valueOf(effectMetadata[InfoFieldKey.IMPACT_KEY.getFieldIndex()]);
+ }
+ catch ( IllegalArgumentException e ) {
+ parseError(String.format("Unrecognized value for effect impact: %s", effectMetadata[InfoFieldKey.IMPACT_KEY.getFieldIndex()]));
+ }
+
+ // The functional class field will be empty when the effect has no functional class associated with it:
+ if ( effectMetadata[InfoFieldKey.FUNCTIONAL_CLASS_KEY.getFieldIndex()].trim().length() > 0 ) {
+ try {
+ functionalClass = EffectFunctionalClass.valueOf(effectMetadata[InfoFieldKey.FUNCTIONAL_CLASS_KEY.getFieldIndex()]);
+ }
+ catch ( IllegalArgumentException e ) {
+ parseError(String.format("Unrecognized value for effect functional class: %s", effectMetadata[InfoFieldKey.FUNCTIONAL_CLASS_KEY.getFieldIndex()]));
+ }
+ }
+ else {
+ functionalClass = EffectFunctionalClass.NONE;
+ }
+
+ codonChange = effectMetadata[InfoFieldKey.CODON_CHANGE_KEY.getFieldIndex()];
+ aminoAcidChange = effectMetadata[InfoFieldKey.AMINO_ACID_CHANGE_KEY.getFieldIndex()];
+ geneName = effectMetadata[InfoFieldKey.GENE_NAME_KEY.getFieldIndex()];
+ geneBiotype = effectMetadata[InfoFieldKey.GENE_BIOTYPE_KEY.getFieldIndex()];
+
+ // The coding field will be empty when SnpEff has no coding info for the effect:
+ if ( effectMetadata[SNPEFF_CODING_FIELD_INDEX].trim().length() > 0 ) {
+ try {
+ coding = EffectCoding.valueOf(effectMetadata[SNPEFF_CODING_FIELD_INDEX]);
+ }
+ catch ( IllegalArgumentException e ) {
+ parseError(String.format("Unrecognized value for effect coding: %s", effectMetadata[SNPEFF_CODING_FIELD_INDEX]));
+ }
+ }
+ else {
+ coding = EffectCoding.UNKNOWN;
+ }
+
+ transcriptID = effectMetadata[InfoFieldKey.TRANSCRIPT_ID_KEY.getFieldIndex()];
+ exonID = effectMetadata[InfoFieldKey.EXON_ID_KEY.getFieldIndex()];
+ }
+
+ private void parseError ( String message ) {
+ isWellFormed = false;
+
+ // Cache only the first error encountered:
+ if ( parseError == null ) {
+ parseError = message;
+ }
+ }
+
+ public boolean isWellFormed() {
+ return isWellFormed;
+ }
+
+ public String getParseError() {
+ return parseError == null ? "" : parseError;
+ }
+
+ public boolean isCoding() {
+ return coding == EffectCoding.CODING;
+ }
+
+ public boolean isHigherImpactThan ( SnpEffEffect other ) {
+ // If one effect is within a coding gene and the other is not, the effect that is
+ // within the coding gene has higher impact:
+
+ if ( isCoding() && ! other.isCoding() ) {
+ return true;
+ }
+ else if ( ! isCoding() && other.isCoding() ) {
+ return false;
+ }
+
+ // Otherwise, both effects are either in or not in a coding gene, so we compare the impacts
+ // of the effects themselves. Effects with the same impact are tie-broken using the
+ // functional class of the effect:
+
+ if ( impact.isHigherImpactThan(other.impact) ) {
+ return true;
+ }
+ else if ( impact.isSameImpactAs(other.impact) ) {
+ return functionalClass.isHigherPriorityThan(other.functionalClass);
+ }
+
+ return false;
+ }
+
+ public Map<String, Object> getAnnotations() {
+ Map<String, Object> annotations = new LinkedHashMap<String, Object>(Utils.optimumHashSize(InfoFieldKey.values().length));
+
+ addAnnotation(annotations, InfoFieldKey.EFFECT_KEY.getKeyName(), effect.toString());
+ addAnnotation(annotations, InfoFieldKey.IMPACT_KEY.getKeyName(), impact.toString());
+ addAnnotation(annotations, InfoFieldKey.FUNCTIONAL_CLASS_KEY.getKeyName(), functionalClass.toString());
+ addAnnotation(annotations, InfoFieldKey.CODON_CHANGE_KEY.getKeyName(), codonChange);
+ addAnnotation(annotations, InfoFieldKey.AMINO_ACID_CHANGE_KEY.getKeyName(), aminoAcidChange);
+ addAnnotation(annotations, InfoFieldKey.GENE_NAME_KEY.getKeyName(), geneName);
+ addAnnotation(annotations, InfoFieldKey.GENE_BIOTYPE_KEY.getKeyName(), geneBiotype);
+ addAnnotation(annotations, InfoFieldKey.TRANSCRIPT_ID_KEY.getKeyName(), transcriptID);
+ addAnnotation(annotations, InfoFieldKey.EXON_ID_KEY.getKeyName(), exonID);
+
+ return annotations;
+ }
+
+ private void addAnnotation ( Map<String, Object> annotations, String keyName, String keyValue ) {
+ // Only add annotations for keys associated with non-empty values:
+ if ( keyValue != null && keyValue.trim().length() > 0 ) {
+ annotations.put(keyName, keyValue);
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/SnpEffUtil.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/SnpEffUtil.java
new file mode 100644
index 0000000..c82a013
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/SnpEffUtil.java
@@ -0,0 +1,154 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+import org.broadinstitute.gatk.tools.walkers.annotator.SnpEff.EffectType;
+
+import java.util.*;
+/**
+ * Created with IntelliJ IDEA.
+ * User: farjoun
+ * Date: 6/5/13
+ * Time: 12:06 PM
+ * To change this template use File | Settings | File Templates.
+ */
+
+/* This class holds a tree representation of the annotations used in snpEff, and provides a mechanism for telling if a
+given annotation is a descendant of another.
+The idea is to be able to stratify effects by large branches and not only the specific
+snpEff annotation that a variant might have. For example if we want to know whether a variant is in CDS
+but if it's marked SYNONYMOUS_CODING or NON_SYNONYMOUS_CODING (or many other options) still imply that its in the CDS.
+
+The hierarchy was determined by Yossi Farjoun with input from Pablo (SNPEFF) and Tim Fennel.
+*/
+
+
+public class SnpEffUtil {
+
+ // A map holding for every child, it's parent.
+ // A node that isn't a key node is a root node.
+ static private final Map<EffectType,EffectType> snpEffectGraph = new HashMap<>();
+
+ //A map from each value of EffectType to a set of it's ancestors
+ static private final Map<EffectType,Set<EffectType>> snpEffectAncestorSet = new HashMap<>();
+
+ static {
+
+
+ //INTERGENIC
+ snpEffectGraph.put(EffectType.UPSTREAM,EffectType.INTERGENIC);
+ snpEffectGraph.put(EffectType.DOWNSTREAM,EffectType.INTERGENIC);
+ snpEffectGraph.put(EffectType.INTERGENIC_CONSERVED,EffectType.INTERGENIC);
+
+ //INTRON
+ snpEffectGraph.put(EffectType.INTRON_CONSERVED,EffectType.INTRON);
+ snpEffectGraph.put(EffectType.SPLICE_SITE_ACCEPTOR,EffectType.INTRON);
+ snpEffectGraph.put(EffectType.SPLICE_SITE_DONOR,EffectType.INTRON);
+
+ //CDS
+ snpEffectGraph.put(EffectType.EXON_DELETED,EffectType.CDS);
+ snpEffectGraph.put(EffectType.SYNONYMOUS_CODING,EffectType.CDS);
+ snpEffectGraph.put(EffectType.NON_SYNONYMOUS_CODING,EffectType.CDS);
+
+ //SYNONYMOUS_CODING
+ snpEffectGraph.put(EffectType.SYNONYMOUS_STOP,EffectType.SYNONYMOUS_CODING);
+ snpEffectGraph.put(EffectType.SYNONYMOUS_START,EffectType.SYNONYMOUS_CODING);
+
+ //NON_SYNONYMOUS_CODING
+ snpEffectGraph.put(EffectType.START_LOST,EffectType.NON_SYNONYMOUS_CODING);
+ snpEffectGraph.put(EffectType.STOP_GAINED,EffectType.NON_SYNONYMOUS_CODING);
+ snpEffectGraph.put(EffectType.STOP_LOST,EffectType.NON_SYNONYMOUS_CODING);
+ snpEffectGraph.put(EffectType.CODON_CHANGE,EffectType.NON_SYNONYMOUS_CODING);
+ snpEffectGraph.put(EffectType.CODON_INSERTION,EffectType.NON_SYNONYMOUS_CODING);
+ snpEffectGraph.put(EffectType.CODON_DELETION,EffectType.NON_SYNONYMOUS_CODING);
+ snpEffectGraph.put(EffectType.CODON_CHANGE_PLUS_CODON_DELETION,EffectType.NON_SYNONYMOUS_CODING);
+ snpEffectGraph.put(EffectType.CODON_CHANGE_PLUS_CODON_INSERTION,EffectType.NON_SYNONYMOUS_CODING);
+ snpEffectGraph.put(EffectType.FRAME_SHIFT,EffectType.NON_SYNONYMOUS_CODING);
+
+ //UTRs
+ snpEffectGraph.put(EffectType.UTR_5_DELETED,EffectType.UTR_5_PRIME);
+ snpEffectGraph.put(EffectType.UTR_3_DELETED,EffectType.UTR_3_PRIME);
+ snpEffectGraph.put(EffectType.START_GAINED,EffectType.UTR_5_PRIME);
+
+ //EXON
+ snpEffectGraph.put(EffectType.UTR_5_PRIME,EffectType.EXON);
+ snpEffectGraph.put(EffectType.UTR_3_PRIME,EffectType.EXON);
+ snpEffectGraph.put(EffectType.CDS,EffectType.EXON);
+
+
+ //TRANSCRIPT
+ snpEffectGraph.put(EffectType.INTRON,EffectType.TRANSCRIPT);
+ snpEffectGraph.put(EffectType.EXON,EffectType.TRANSCRIPT);
+
+ //GENE
+ snpEffectGraph.put(EffectType.TRANSCRIPT,EffectType.GENE);
+ snpEffectGraph.put(EffectType.REGULATION,EffectType.GENE);
+
+ //CHROMOSOME
+ snpEffectGraph.put(EffectType.GENE,EffectType.CHROMOSOME);
+ snpEffectGraph.put(EffectType.INTERGENIC,EffectType.CHROMOSOME);
+ }
+
+ //A helper function that gets the parent set of the set of children
+ private static Set<EffectType> getParentSet(final Set<EffectType> children){
+ final Set<EffectType> parents=new HashSet<>();
+ for(EffectType child:children){
+ final EffectType parent = snpEffectGraph.get(child);
+ if(parent!=null) parents.add(parent);
+ }
+ return parents;
+ }
+
+ //builds the total set of ancestors of a given node
+ private static Set<EffectType> getAncestorSet(final EffectType child, final boolean isSelfIncluded){
+
+ final Set<EffectType> ancestors=new HashSet<>();
+ if(isSelfIncluded) ancestors.add(child);
+
+ Set<EffectType> untraversedNodes=Collections.singleton(child);
+
+ while(!untraversedNodes.isEmpty()){
+ final Set<EffectType> putativeParents = getParentSet(untraversedNodes); //get immediate parents of unexamined set
+ putativeParents.removeAll(ancestors); //remove all known parents, remaining with previously unknown parents
+ ancestors.addAll(putativeParents); // add these parents to growing list of ancestors
+ untraversedNodes=putativeParents; //still need to traverse parents of these nodes
+ }
+ return ancestors;
+ }
+
+ //returns true if the child effect is a subType of the parentEffect (including itself)
+ public static boolean isSubTypeOf(final SnpEff.EffectType childEffect, final SnpEff.EffectType parentEffect){
+
+ Set<EffectType> ancestorSet=snpEffectAncestorSet.get(childEffect);
+
+ if(ancestorSet==null) { //lazy population of map.
+ ancestorSet = new HashSet<>();
+ ancestorSet.addAll(getAncestorSet(childEffect, true)); //"true" so that a type is considered a subtype of itself
+ snpEffectAncestorSet.put(childEffect, ancestorSet);
+ }
+ return ancestorSet.contains(parentEffect);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/VariantAnnotator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/VariantAnnotator.java
new file mode 100644
index 0000000..042ba48
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/VariantAnnotator.java
@@ -0,0 +1,336 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+import org.broadinstitute.gatk.engine.walkers.*;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.DbsnpArgumentCollection;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContextUtils;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.*;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.help.HelpUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import htsjdk.variant.vcf.*;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
+
+import java.util.*;
+
+/**
+ * Annotates variant calls with context information.
+ *
+ * <p>
+ * VariantAnnotator is a GATK tool for annotating variant calls based on their context.
+ * The tool is modular; new annotations can be written easily without modifying VariantAnnotator itself.
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A variant set to annotate and optionally one or more BAM files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * An annotated VCF.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T VariantAnnotator \
+ * -I input.bam \
+ * -o output.vcf \
+ * -A Coverage \
+ * --variant input.vcf \
+ * -L input.vcf \
+ * --dbsnp dbsnp.vcf
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+ at Requires(value={})
+ at Allows(value={DataSource.READS, DataSource.REFERENCE})
+ at Reference(window=@Window(start=-50,stop=50))
+ at Downsample(by= DownsampleType.BY_SAMPLE, toCoverage=250)
+ at By(DataSource.REFERENCE)
+public class VariantAnnotator extends RodWalker<Integer, Integer> implements AnnotatorCompatible, TreeReducible<Integer> {
+
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ /**
+ * The INFO field will be annotated with information on the most biologically significant effect
+ * listed in the SnpEff output file for each variant.
+ */
+ @Input(fullName="snpEffFile", shortName = "snpEffFile", doc="A SnpEff output file from which to add annotations", required=false)
+ public RodBinding<VariantContext> snpEffFile;
+ public RodBinding<VariantContext> getSnpEffRodBinding() { return snpEffFile; }
+
+ /**
+ * rsIDs from this file are used to populate the ID column of the output. Also, the DB INFO flag will be set when appropriate.
+ */
+ @ArgumentCollection
+ protected DbsnpArgumentCollection dbsnp = new DbsnpArgumentCollection();
+ public RodBinding<VariantContext> getDbsnpRodBinding() { return dbsnp.dbsnp; }
+
+ /**
+ * If a record in the 'variant' track overlaps with a record from the provided comp track, the INFO field will be
+ * annotated as such in the output with the track name (e.g. -comp:FOO will have 'FOO' in the INFO field).
+ * Records that are filtered in the comp track will be ignored. Note that 'dbSNP' has been special-cased
+ * (see the --dbsnp argument).
+ */
+ @Input(fullName="comp", shortName = "comp", doc="comparison VCF file", required=false)
+ public List<RodBinding<VariantContext>> comps = Collections.emptyList();
+ public List<RodBinding<VariantContext>> getCompRodBindings() { return comps; }
+
+ /**
+ * An external resource VCF file or files from which to annotate.
+ *
+ * Use this option to add annotations from a resource file to the output.
+ * For example, if you want to annotate your callset with the AC field value from a VCF file named
+ * 'resource_file.vcf', you tag it with '-resource:my_resource resource_file.vcf' and you additionally specify
+ * '-E my_resource.AC' (-E is short for --expression, also documented on this page). In the resulting output
+ * VCF, any records for which there is a record at the same position in the resource file will be annotated with
+ * 'my_resource.AC=N'. Note that if there are multiple records in the resource file that overlap the given
+ * position, one is chosen randomly.
+ */
+ @Input(fullName="resource", shortName = "resource", doc="External resource VCF file", required=false)
+ public List<RodBinding<VariantContext>> resources = Collections.emptyList();
+ public List<RodBinding<VariantContext>> getResourceRodBindings() { return resources; }
+
+ @Output(doc="File to which variants should be written")
+ protected VariantContextWriter vcfWriter = null;
+
+ /**
+ * See the --list argument to view available annotations.
+ */
+ @Argument(fullName="annotation", shortName="A", doc="One or more specific annotations to apply to variant calls", required=false)
+ protected List<String> annotationsToUse = new ArrayList<>();
+
+ /**
+ * Note that this argument has higher priority than the -A or -G arguments,
+ * so annotations will be excluded even if they are explicitly included with the other options.
+ */
+ @Argument(fullName="excludeAnnotation", shortName="XA", doc="One or more specific annotations to exclude", required=false)
+ protected List<String> annotationsToExclude = new ArrayList<>();
+
+ /**
+ * If specified, all available annotations in the group will be applied. See the VariantAnnotator -list argument
+ * to view available groups. Keep in mind that RODRequiringAnnotations are not intended to be used as a group,
+ * because they require specific ROD inputs.
+ */
+ @Argument(fullName="group", shortName="G", doc="One or more classes/groups of annotations to apply to variant calls", required=false)
+ protected List<String> annotationGroupsToUse = new ArrayList<>();
+
+ /**
+ * This option enables you to add annotations from one VCF to another.
+ *
+ * For example, if you want to annotate your callset with the AC field value from a VCF file named
+ * 'resource_file.vcf', you tag it with '-resource:my_resource resource_file.vcf' (see the -resource argument, also
+ * documented on this page) and you specify '-E my_resource.AC'. In the resulting output VCF, any records for
+ * which there is a record at the same position in the resource file will be annotated with 'my_resource.AC=N'.
+ * Note that if there are multiple records in the resource file that overlap the given position, one is chosen
+ * randomly.
+ */
+ @Argument(fullName="expression", shortName="E", doc="One or more specific expressions to apply to variant calls", required=false)
+ protected Set<String> expressionsToUse = new ObjectOpenHashSet();
+
+ /**
+ * You can use the -XL argument in combination with this one to exclude specific annotations.Note that some
+ * annotations may not be actually applied if they are not applicable to the data provided or if they are
+ * unavailable to the tool (e.g. there are several annotations that are currently not hooked up to
+ * HaplotypeCaller). At present no error or warning message will be provided, the annotation will simply be
+ * skipped silently. You can check the output VCF header to see which annotations were actually applied (although
+ * this does not guarantee that the annotation was applied to all records in the VCF, since some annotations have
+ * additional requirements, e.g. minimum number of samples or heterozygous sites only -- see the documentation
+ * for individual annotations' requirements).
+ */
+ @Argument(fullName="useAllAnnotations", shortName="all", doc="Use all possible annotations (not for the faint of heart)", required=false)
+ protected Boolean USE_ALL_ANNOTATIONS = false;
+
+ /**
+ * Note that the --list argument requires a fully resolved and correct command-line to work. As an alternative, you can use ListAnnotations (see Help Utilities).
+ */
+ @Argument(fullName="list", shortName="ls", doc="List the available annotations and exit", required=false)
+ protected Boolean LIST = false;
+
+ /**
+ * By default, the dbSNP ID is added only when the ID field in the variant VCF is empty (not already annotated).
+ * This argument allows you to override that behavior. This is used in conjuction with the -dbsnp argument.
+ */
+ @Argument(fullName="alwaysAppendDbsnpId", shortName="alwaysAppendDbsnpId", doc="Append the dbSNP ID even when the variant VCF already has the ID field populated", required=false)
+ protected Boolean ALWAYS_APPEND_DBSNP_ID = false;
+ public boolean alwaysAppendDbsnpId() { return ALWAYS_APPEND_DBSNP_ID; }
+
+ @Argument(fullName="MendelViolationGenotypeQualityThreshold",shortName="mvq",required=false,doc="The genotype quality threshold in order to annotate mendelian violation ratio")
+ public double minGenotypeQualityP = 0.0;
+
+ private VariantAnnotatorEngine engine;
+
+ /**
+ * Prepare the output file and the list of available features.
+ */
+ public void initialize() {
+
+ if ( LIST ) {
+ HelpUtils.listAnnotations();
+ System.exit(0);
+ }
+
+ // get the list of all sample names from the variant VCF input rod, if applicable
+ final List<String> rodName = Arrays.asList(variantCollection.variants.getName());
+ final Set<String> samples = SampleUtils.getUniqueSamplesFromRods(getToolkit(), rodName);
+
+ if ( USE_ALL_ANNOTATIONS )
+ engine = new VariantAnnotatorEngine(annotationsToExclude, this, getToolkit());
+ else
+ engine = new VariantAnnotatorEngine(annotationGroupsToUse, annotationsToUse, annotationsToExclude, this, getToolkit());
+ engine.initializeExpressions(expressionsToUse);
+
+ // setup the header fields
+ // note that if any of the definitions conflict with our new ones, then we want to overwrite the old ones
+ final Set<VCFHeaderLine> hInfo = new HashSet<>();
+ hInfo.addAll(engine.getVCFAnnotationDescriptions());
+ for ( final VCFHeaderLine line : GATKVCFUtils.getHeaderFields(getToolkit(), Arrays.asList(variantCollection.variants.getName())) ) {
+ if ( isUniqueHeaderLine(line, hInfo) )
+ hInfo.add(line);
+ }
+ // for the expressions, pull the info header line from the header of the resource rod
+ for ( final VariantAnnotatorEngine.VAExpression expression : engine.getRequestedExpressions() ) {
+ // special case the ID field
+ if ( expression.fieldName.equals("ID") ) {
+ hInfo.add(new VCFInfoHeaderLine(expression.fullName, 1, VCFHeaderLineType.String, "ID field transferred from external VCF resource"));
+ continue;
+ }
+ VCFInfoHeaderLine targetHeaderLine = null;
+ for ( final VCFHeaderLine line : GATKVCFUtils.getHeaderFields(getToolkit(), Arrays.asList(expression.binding.getName())) ) {
+ if ( line instanceof VCFInfoHeaderLine ) {
+ final VCFInfoHeaderLine infoline = (VCFInfoHeaderLine)line;
+ if ( infoline.getID().equals(expression.fieldName) ) {
+ targetHeaderLine = infoline;
+ break;
+ }
+ }
+ }
+
+ if ( targetHeaderLine != null ) {
+ if ( targetHeaderLine.getCountType() == VCFHeaderLineCount.INTEGER )
+ hInfo.add(new VCFInfoHeaderLine(expression.fullName, targetHeaderLine.getCount(), targetHeaderLine.getType(), targetHeaderLine.getDescription()));
+ else
+ hInfo.add(new VCFInfoHeaderLine(expression.fullName, targetHeaderLine.getCountType(), targetHeaderLine.getType(), targetHeaderLine.getDescription()));
+ } else {
+ hInfo.add(new VCFInfoHeaderLine(expression.fullName, VCFHeaderLineCount.UNBOUNDED, VCFHeaderLineType.String, "Value transferred from another external VCF resource"));
+ }
+ }
+
+ engine.invokeAnnotationInitializationMethods(hInfo);
+
+ VCFHeader vcfHeader = new VCFHeader(hInfo, samples);
+ vcfWriter.writeHeader(vcfHeader);
+ }
+
+ public static boolean isUniqueHeaderLine(VCFHeaderLine line, Set<VCFHeaderLine> currentSet) {
+ if ( !(line instanceof VCFCompoundHeaderLine) )
+ return true;
+
+ for ( VCFHeaderLine hLine : currentSet ) {
+ if ( hLine instanceof VCFCompoundHeaderLine && ((VCFCompoundHeaderLine)line).sameLineTypeAndName((VCFCompoundHeaderLine)hLine) )
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * We want reads that span deletions
+ *
+ * @return true
+ */
+ public boolean includeReadsWithDeletionAtLoci() { return true; }
+
+ /**
+ * For each site of interest, annotate based on the requested annotation types
+ *
+ * @param tracker the meta-data tracker
+ * @param ref the reference base
+ * @param context the context for the given locus
+ * @return 1 if the locus was successfully processed, 0 if otherwise
+ */
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null )
+ return 0;
+
+ Collection<VariantContext> VCs = tracker.getValues(variantCollection.variants, context.getLocation());
+ if ( VCs.size() == 0 )
+ return 0;
+
+ Collection<VariantContext> annotatedVCs = VCs;
+
+ // if the reference base is not ambiguous, we can annotate
+ Map<String, AlignmentContext> stratifiedContexts;
+ if ( BaseUtils.simpleBaseToBaseIndex(ref.getBase()) != -1 ) {
+ stratifiedContexts = AlignmentContextUtils.splitContextBySampleName(context.getBasePileup());
+ annotatedVCs = new ArrayList<>(VCs.size());
+ for ( VariantContext vc : VCs )
+ annotatedVCs.add(engine.annotateContext(tracker, ref, stratifiedContexts, vc));
+ }
+
+ for ( VariantContext annotatedVC : annotatedVCs )
+ vcfWriter.add(annotatedVC);
+
+ return 1;
+ }
+
+ @Override
+ public Integer reduceInit() { return 0; }
+
+ @Override
+ public Integer reduce(Integer value, Integer sum) { return value + sum; }
+
+ @Override
+ public Integer treeReduce(Integer lhs, Integer rhs) {
+ return lhs + rhs;
+ }
+
+ /**
+ * Tell the user the number of loci processed and close out the new variants file.
+ *
+ * @param result the number of loci seen.
+ */
+ public void onTraversalDone(Integer result) {
+ logger.info("Processed " + result + " loci.\n");
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/VariantAnnotatorEngine.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/VariantAnnotatorEngine.java
new file mode 100644
index 0000000..60c8824
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/VariantAnnotatorEngine.java
@@ -0,0 +1,304 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.vcf.*;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.*;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap;
+import org.broadinstitute.gatk.utils.genotyper.ReadLikelihoods;
+
+import java.util.*;
+
+
+public class VariantAnnotatorEngine {
+ private List<InfoFieldAnnotation> requestedInfoAnnotations = Collections.emptyList();
+ private List<GenotypeAnnotation> requestedGenotypeAnnotations = Collections.emptyList();
+ private List<VAExpression> requestedExpressions = new ArrayList<>();
+
+ private final AnnotatorCompatible walker;
+ private final GenomeAnalysisEngine toolkit;
+
+ VariantOverlapAnnotator variantOverlapAnnotator = null;
+
+ protected static class VAExpression {
+
+ public String fullName, fieldName;
+ public RodBinding<VariantContext> binding;
+
+ public VAExpression(String fullExpression, List<RodBinding<VariantContext>> bindings) {
+ final int indexOfDot = fullExpression.lastIndexOf(".");
+ if ( indexOfDot == -1 )
+ throw new UserException.BadArgumentValue(fullExpression, "it should be in rodname.value format");
+
+ fullName = fullExpression;
+ fieldName = fullExpression.substring(indexOfDot+1);
+
+ final String bindingName = fullExpression.substring(0, indexOfDot);
+ for ( final RodBinding<VariantContext> rod : bindings ) {
+ if ( rod.getName().equals(bindingName) ) {
+ binding = rod;
+ break;
+ }
+ }
+ }
+ }
+
+ // use this constructor if you want all possible annotations
+ public VariantAnnotatorEngine(List<String> annotationsToExclude, AnnotatorCompatible walker, GenomeAnalysisEngine toolkit) {
+ this.walker = walker;
+ this.toolkit = toolkit;
+ requestedInfoAnnotations = AnnotationInterfaceManager.createAllInfoFieldAnnotations();
+ requestedGenotypeAnnotations = AnnotationInterfaceManager.createAllGenotypeAnnotations();
+ excludeAnnotations(annotationsToExclude);
+ initializeDBs(toolkit);
+ }
+
+ // use this constructor if you want to select specific annotations (and/or interfaces)
+ public VariantAnnotatorEngine(List<String> annotationGroupsToUse, List<String> annotationsToUse, List<String> annotationsToExclude, AnnotatorCompatible walker, GenomeAnalysisEngine toolkit) {
+ this.walker = walker;
+ this.toolkit = toolkit;
+ initializeAnnotations(annotationGroupsToUse, annotationsToUse, annotationsToExclude);
+ initializeDBs(toolkit);
+ }
+
+ // select specific expressions to use
+ public void initializeExpressions(Set<String> expressionsToUse) {
+ // set up the expressions
+ for ( final String expression : expressionsToUse )
+ requestedExpressions.add(new VAExpression(expression, walker.getResourceRodBindings()));
+ }
+
+ protected List<VAExpression> getRequestedExpressions() { return requestedExpressions; }
+
+ private void initializeAnnotations(List<String> annotationGroupsToUse, List<String> annotationsToUse, List<String> annotationsToExclude) {
+ AnnotationInterfaceManager.validateAnnotations(annotationGroupsToUse, annotationsToUse);
+ requestedInfoAnnotations = AnnotationInterfaceManager.createInfoFieldAnnotations(annotationGroupsToUse, annotationsToUse);
+ requestedGenotypeAnnotations = AnnotationInterfaceManager.createGenotypeAnnotations(annotationGroupsToUse, annotationsToUse);
+ excludeAnnotations(annotationsToExclude);
+ }
+
+ private void excludeAnnotations(List<String> annotationsToExclude) {
+ if ( annotationsToExclude.size() == 0 )
+ return;
+
+ final List<InfoFieldAnnotation> tempRequestedInfoAnnotations = new ArrayList<>(requestedInfoAnnotations.size());
+ for ( final InfoFieldAnnotation annotation : requestedInfoAnnotations ) {
+ if ( !annotationsToExclude.contains(annotation.getClass().getSimpleName()) )
+ tempRequestedInfoAnnotations.add(annotation);
+ }
+ requestedInfoAnnotations = tempRequestedInfoAnnotations;
+
+ final List<GenotypeAnnotation> tempRequestedGenotypeAnnotations = new ArrayList<>(requestedGenotypeAnnotations.size());
+ for ( final GenotypeAnnotation annotation : requestedGenotypeAnnotations ) {
+ if ( !annotationsToExclude.contains(annotation.getClass().getSimpleName()) )
+ tempRequestedGenotypeAnnotations.add(annotation);
+ }
+ requestedGenotypeAnnotations = tempRequestedGenotypeAnnotations;
+ }
+
+ private void initializeDBs(final GenomeAnalysisEngine engine) {
+ // check to see whether comp rods were included
+ RodBinding<VariantContext> dbSNPBinding = walker.getDbsnpRodBinding();
+ if ( dbSNPBinding != null && ! dbSNPBinding.isBound() )
+ dbSNPBinding = null;
+
+ final Map<RodBinding<VariantContext>, String> overlapBindings = new LinkedHashMap<>();
+ for ( final RodBinding<VariantContext> b : walker.getCompRodBindings())
+ if ( b.isBound() ) overlapBindings.put(b, b.getName());
+ if ( dbSNPBinding != null && ! overlapBindings.keySet().contains(VCFConstants.DBSNP_KEY) )
+ overlapBindings.put(dbSNPBinding, VCFConstants.DBSNP_KEY); // add overlap detection with DBSNP by default
+
+ variantOverlapAnnotator = new VariantOverlapAnnotator(dbSNPBinding, overlapBindings, engine.getGenomeLocParser());
+ }
+
+ public void invokeAnnotationInitializationMethods( final Set<VCFHeaderLine> headerLines ) {
+ for ( final VariantAnnotatorAnnotation annotation : requestedInfoAnnotations ) {
+ annotation.initialize(walker, toolkit, headerLines);
+ }
+
+ for ( final VariantAnnotatorAnnotation annotation : requestedGenotypeAnnotations ) {
+ annotation.initialize(walker, toolkit, headerLines);
+ }
+ }
+
+ public Set<VCFHeaderLine> getVCFAnnotationDescriptions() {
+ final Set<VCFHeaderLine> descriptions = new HashSet<>();
+
+ for ( final InfoFieldAnnotation annotation : requestedInfoAnnotations )
+ descriptions.addAll(annotation.getDescriptions());
+ for ( final GenotypeAnnotation annotation : requestedGenotypeAnnotations )
+ descriptions.addAll(annotation.getDescriptions());
+ for ( final String db : variantOverlapAnnotator.getOverlapNames() ) {
+ if ( VCFStandardHeaderLines.getInfoLine(db, false) != null )
+ descriptions.add(VCFStandardHeaderLines.getInfoLine(db));
+ else
+ descriptions.add(new VCFInfoHeaderLine(db, 0, VCFHeaderLineType.Flag, db + " Membership"));
+ }
+
+ return descriptions;
+ }
+
+ public VariantContext annotateContext(final RefMetaDataTracker tracker,
+ final ReferenceContext ref,
+ final Map<String, AlignmentContext> stratifiedContexts,
+ final VariantContext vc) {
+ return annotateContext(tracker, ref, stratifiedContexts, vc, null);
+ }
+
+ public VariantContext annotateContext(final RefMetaDataTracker tracker,
+ final ReferenceContext ref,
+ final Map<String, AlignmentContext> stratifiedContexts,
+ final VariantContext vc,
+ final Map<String,PerReadAlleleLikelihoodMap> perReadAlleleLikelihoodMap) {
+ final Map<String, Object> infoAnnotations = new LinkedHashMap<>(vc.getAttributes());
+
+ // annotate expressions where available
+ annotateExpressions(tracker, ref.getLocus(), infoAnnotations);
+
+ // go through all the requested info annotationTypes
+ for ( final InfoFieldAnnotation annotationType : requestedInfoAnnotations ) {
+ final Map<String, Object> annotationsFromCurrentType = annotationType.annotate(tracker, walker, ref, stratifiedContexts, vc, perReadAlleleLikelihoodMap);
+ if ( annotationsFromCurrentType != null )
+ infoAnnotations.putAll(annotationsFromCurrentType);
+ }
+
+ // generate a new annotated VC
+ final VariantContextBuilder builder = new VariantContextBuilder(vc).attributes(infoAnnotations);
+
+ // annotate genotypes, creating another new VC in the process
+ final VariantContext annotated = builder.genotypes(annotateGenotypes(tracker, ref, stratifiedContexts, vc, perReadAlleleLikelihoodMap)).make();
+
+ // annotate db occurrences
+ return annotateDBs(tracker, annotated);
+ }
+
+ public VariantContext annotateContextForActiveRegion(final RefMetaDataTracker tracker,
+ final ReadLikelihoods<Allele> readLikelihoods,
+ final VariantContext vc) {
+ //TODO we transform the read-likelihood into the Map^2 previous version for the sake of not changing of not changing annotation interface.
+ //TODO should we change those interfaces?
+ final Map<String, PerReadAlleleLikelihoodMap> annotationLikelihoods = readLikelihoods.toPerReadAlleleLikelihoodMap();
+ return annotateContextForActiveRegion(tracker, annotationLikelihoods, vc);
+ }
+
+ public VariantContext annotateContextForActiveRegion(final RefMetaDataTracker tracker,
+ final Map<String, PerReadAlleleLikelihoodMap> perReadAlleleLikelihoodMap,
+ final VariantContext vc) {
+ final Map<String, Object> infoAnnotations = new LinkedHashMap<>(vc.getAttributes());
+
+ // go through all the requested info annotationTypes
+ for ( final InfoFieldAnnotation annotationType : requestedInfoAnnotations ) {
+ if ( !(annotationType instanceof ActiveRegionBasedAnnotation) )
+ continue;
+
+ final Map<String, Object> annotationsFromCurrentType = annotationType.annotate(perReadAlleleLikelihoodMap, vc);
+ if ( annotationsFromCurrentType != null ) {
+ infoAnnotations.putAll(annotationsFromCurrentType);
+ }
+ }
+
+ // generate a new annotated VC
+ final VariantContextBuilder builder = new VariantContextBuilder(vc).attributes(infoAnnotations);
+
+ // annotate genotypes, creating another new VC in the process
+ final VariantContext annotated = builder.genotypes(annotateGenotypes(null, null, null, vc, perReadAlleleLikelihoodMap)).make();
+
+ // annotate db occurrences
+ return annotateDBs(tracker, annotated);
+ }
+
+ /**
+ * Annotate the ID field and other DBs for the given Variant Context
+ *
+ * @param tracker ref meta data tracker (cannot be null)
+ * @param vc variant context to annotate
+ * @return non-null annotated version of vc
+ */
+ @Requires({"tracker != null && loc != null && vc != null && infoAnnotations != null"})
+ @Ensures("result != null")
+ private VariantContext annotateDBs(final RefMetaDataTracker tracker, VariantContext vc) {
+ return variantOverlapAnnotator.annotateOverlaps(tracker, variantOverlapAnnotator.annotateRsID(tracker, vc));
+ }
+
+ private void annotateExpressions(final RefMetaDataTracker tracker, final GenomeLoc loc, final Map<String, Object> infoAnnotations) {
+ for ( final VAExpression expression : requestedExpressions ) {
+ final Collection<VariantContext> VCs = tracker.getValues(expression.binding, loc);
+ if ( VCs.size() == 0 )
+ continue;
+
+ final VariantContext vc = VCs.iterator().next();
+ // special-case the ID field
+ if ( expression.fieldName.equals("ID") ) {
+ if ( vc.hasID() )
+ infoAnnotations.put(expression.fullName, vc.getID());
+ } else if (expression.fieldName.equals("ALT")) {
+ infoAnnotations.put(expression.fullName, vc.getAlternateAllele(0).getDisplayString());
+
+ } else if ( vc.hasAttribute(expression.fieldName) ) {
+ infoAnnotations.put(expression.fullName, vc.getAttribute(expression.fieldName));
+
+ }
+ }
+ }
+
+
+ private GenotypesContext annotateGenotypes(final RefMetaDataTracker tracker,
+ final ReferenceContext ref, final Map<String, AlignmentContext> stratifiedContexts,
+ final VariantContext vc,
+ final Map<String,PerReadAlleleLikelihoodMap> stratifiedPerReadAlleleLikelihoodMap) {
+ if ( requestedGenotypeAnnotations.isEmpty() )
+ return vc.getGenotypes();
+
+ final GenotypesContext genotypes = GenotypesContext.create(vc.getNSamples());
+ for ( final Genotype genotype : vc.getGenotypes() ) {
+ AlignmentContext context = null;
+ PerReadAlleleLikelihoodMap perReadAlleleLikelihoodMap = null;
+ if (stratifiedContexts != null)
+ context = stratifiedContexts.get(genotype.getSampleName());
+ if (stratifiedPerReadAlleleLikelihoodMap != null)
+ perReadAlleleLikelihoodMap = stratifiedPerReadAlleleLikelihoodMap.get(genotype.getSampleName());
+
+
+ final GenotypeBuilder gb = new GenotypeBuilder(genotype);
+ for ( final GenotypeAnnotation annotation : requestedGenotypeAnnotations ) {
+ annotation.annotate(tracker, walker, ref, context, vc, genotype, gb, perReadAlleleLikelihoodMap);
+ }
+ genotypes.add(gb.make());
+ }
+
+ return genotypes;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/VariantOverlapAnnotator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/VariantOverlapAnnotator.java
new file mode 100644
index 0000000..03f707f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/VariantOverlapAnnotator.java
@@ -0,0 +1,224 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+import htsjdk.variant.vcf.VCFConstants;
+
+import java.util.*;
+
+/**
+ * Annotate the ID field and attribute overlap FLAGs for a VariantContext against a RefMetaDataTracker or a list
+ * of VariantContexts
+ */
+public final class VariantOverlapAnnotator {
+ final RodBinding<VariantContext> dbSNPBinding;
+ final Map<RodBinding<VariantContext>, String> overlapBindings;
+ final GenomeLocParser genomeLocParser;
+
+ /**
+ * Create a new VariantOverlapAnnotator without overall bindings
+ *
+ * @see #VariantOverlapAnnotator(org.broadinstitute.gatk.utils.commandline.RodBinding, java.util.Map, org.broadinstitute.gatk.utils.GenomeLocParser)
+ */
+ public VariantOverlapAnnotator(RodBinding<VariantContext> dbSNPBinding, GenomeLocParser genomeLocParser) {
+ this(dbSNPBinding, Collections.<RodBinding<VariantContext>, String>emptyMap(), genomeLocParser);
+ }
+
+ /**
+ * Create a new VariantOverlapAnnotator
+ *
+ * @param dbSNPBinding the RodBinding to use for updating ID field values, or null if that behavior isn't desired
+ * @param overlapBindings a map of RodBindings / name to use for overlap annotation. Each binding will be used to
+ * add name => true for variants that overlap with variants found to a
+ * RefMetaDataTracker at each location. Can be empty but not null
+ * @param genomeLocParser the genome loc parser we'll use to create GenomeLocs for VariantContexts
+ */
+ public VariantOverlapAnnotator(RodBinding<VariantContext> dbSNPBinding, Map<RodBinding<VariantContext>, String> overlapBindings, GenomeLocParser genomeLocParser) {
+ if ( overlapBindings == null ) throw new IllegalArgumentException("overlapBindings cannot be null");
+ if ( genomeLocParser == null ) throw new IllegalArgumentException("genomeLocParser cannot be null");
+
+ this.dbSNPBinding = dbSNPBinding;
+ this.overlapBindings = overlapBindings;
+ this.genomeLocParser = genomeLocParser;
+ }
+
+ /**
+ * Update rsID in vcToAnnotate with rsIDs from dbSNPBinding fetched from tracker
+ * @see #annotateOverlap(java.util.List, String, htsjdk.variant.variantcontext.VariantContext)
+ *
+ * @param tracker non-null tracker, which we will use to update the rsID of vcToAnnotate
+ * for VariantContexts bound to dbSNPBinding that start at vcToAnnotate
+ * @param vcToAnnotate a variant context to annotate
+ * @return a VariantContext (may be == to vcToAnnotate) with updated rsID value
+ */
+ public VariantContext annotateRsID(final RefMetaDataTracker tracker, final VariantContext vcToAnnotate) {
+ if ( dbSNPBinding != null ) {
+ final GenomeLoc loc = getLoc(vcToAnnotate);
+ return annotateRsID(tracker.getValues(dbSNPBinding, loc), vcToAnnotate);
+ } else {
+ return vcToAnnotate;
+ }
+ }
+
+ /**
+ * Update rsID of vcToAnnotate with rsID match found in vcsAtLoc, if one exists
+ *
+ * @param vcsAtLoc a list of variant contexts starting at this location to use as sources for rsID values
+ * @param vcToAnnotate a variant context to annotate
+ * @return a VariantContext (may be == to vcToAnnotate) with updated rsID value
+ */
+ public VariantContext annotateRsID(final List<VariantContext> vcsAtLoc, final VariantContext vcToAnnotate ) {
+ final String rsID = getRsID(vcsAtLoc, vcToAnnotate);
+
+ // add the ID if appropriate
+ if ( rsID != null ) {
+ final VariantContextBuilder vcb = new VariantContextBuilder(vcToAnnotate);
+
+ if ( ! vcToAnnotate.hasID() ) {
+ return vcb.id(rsID).make();
+ } else if ( ! vcToAnnotate.getID().contains(rsID) ) {
+ return vcb.id(vcToAnnotate.getID() + VCFConstants.ID_FIELD_SEPARATOR + rsID).make();
+ } // falling through to return VC lower down
+ }
+
+ // nothing to do, just return vc
+ return vcToAnnotate;
+ }
+
+ private GenomeLoc getLoc(final VariantContext vc) {
+ return genomeLocParser.createGenomeLoc(vc);
+ }
+
+ /**
+ * Add overlap attributes to vcToAnnotate against all overlapBindings in tracker
+ *
+ * @see #annotateOverlap(java.util.List, String, htsjdk.variant.variantcontext.VariantContext)
+ * for more information
+ *
+ * @param tracker non-null tracker, which we will use to update the rsID of vcToAnnotate
+ * for VariantContexts bound to dbSNPBinding that start at vcToAnnotate
+ * @param vcToAnnotate a variant context to annotate
+ * @return a VariantContext (may be == to vcToAnnotate) with updated overlaps update fields value
+ */
+ public VariantContext annotateOverlaps(final RefMetaDataTracker tracker, final VariantContext vcToAnnotate) {
+ if ( overlapBindings.isEmpty() ) return vcToAnnotate;
+
+ VariantContext annotated = vcToAnnotate;
+ final GenomeLoc loc = getLoc(vcToAnnotate);
+ for ( final Map.Entry<RodBinding<VariantContext>, String> overlapBinding : overlapBindings.entrySet() ) {
+ annotated = annotateOverlap(tracker.getValues(overlapBinding.getKey(), loc), overlapBinding.getValue(), annotated);
+ }
+
+ return annotated;
+ }
+
+ /**
+ * Add overlaps flag attributes to vcToAnnotate binding overlapTestVCs.getSource() => true if
+ * an overlapping variant context can be found in overlapTestVCs with vcToAnnotate
+ *
+ * Overlaps here means that the reference alleles are the same and at least one alt
+ * allele in vcToAnnotate is equals to one of the alt alleles in overlapTestVCs
+ *
+ * @param overlapTestVCs a non-null list of potential overlaps that start at vcToAnnotate
+ * @param attributeKey the key to set to true in the attribute map for vcToAnnotate if it overlaps
+ * @param vcToAnnotate a non-null VariantContext to annotate
+ * @return
+ */
+ public VariantContext annotateOverlap(final List<VariantContext> overlapTestVCs, final String attributeKey, VariantContext vcToAnnotate) {
+ if ( overlapBindings.isEmpty() ) return vcToAnnotate;
+
+ final boolean overlaps = overlaps(overlapTestVCs, vcToAnnotate);
+ if ( overlaps ) {
+ return new VariantContextBuilder(vcToAnnotate).attribute(attributeKey, true).make();
+ } else {
+ return vcToAnnotate;
+ }
+ }
+
+ /**
+ * Returns the ID field of the first VariantContext in rsIDSourceVCs that has the same reference allele
+ * as vcToAnnotate and all of the alternative alleles in vcToAnnotate.
+ *
+ * Doesn't require vcToAnnotate to be a complete match, so
+ *
+ * A/C/G in VC in rsIDSourceVCs
+ *
+ * would match the a VC with A/C but not A/T. Also we don't require all alleles to match
+ * so we would also match A/C/T to A/C/G.
+ *
+ * Will only match rsIDSourceVCs that aren't failing filters.
+ *
+ * @param rsIDSourceVCs a non-null list of potential overlaps that start at vcToAnnotate
+ * @param vcToAnnotate a non-null VariantContext to annotate
+ * @return a String to use for the rsID from rsIDSourceVCs if one matches, or null if none matches
+ */
+ private String getRsID(final List<VariantContext> rsIDSourceVCs, final VariantContext vcToAnnotate) {
+ if ( rsIDSourceVCs == null ) throw new IllegalArgumentException("rsIDSourceVCs cannot be null");
+ if ( vcToAnnotate == null ) throw new IllegalArgumentException("vcToAnnotate cannot be null");
+
+ for ( final VariantContext vcComp : rsIDSourceVCs ) {
+ if ( vcComp.isFiltered() ) continue; // don't process any failed VCs
+
+ if ( ! vcComp.getChr().equals(vcToAnnotate.getChr()) || vcComp.getStart() != vcToAnnotate.getStart() )
+ throw new IllegalArgumentException("source rsID VariantContext " + vcComp + " doesn't start at the same position as vcToAnnotate " + vcToAnnotate);
+
+ if ( vcToAnnotate.getReference().equals(vcComp.getReference()) ) {
+ for ( final Allele allele : vcToAnnotate.getAlternateAlleles() ) {
+ if ( vcComp.getAlternateAlleles().contains(allele) )
+ return vcComp.getID();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Does vcToAnnotate overlap with any of the records in potentialOverlaps?
+ *
+ * @param potentialOverlaps a non-null list of potential overlaps that start at vcToAnnotate
+ * @param vcToAnnotate a non-null VariantContext to annotate
+ * @return true if vcToAnnotate overlaps (position and all alt alleles) with some variant in potentialOverlaps
+ */
+ private boolean overlaps(final List<VariantContext> potentialOverlaps, final VariantContext vcToAnnotate) {
+ return getRsID(potentialOverlaps, vcToAnnotate) != null;
+ }
+
+ /**
+ * Get the collection of the RodBinding names for those being used for overlap detection
+ * @return a non-null collection of Strings
+ */
+ public Collection<String> getOverlapNames() {
+ return overlapBindings.values();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/ActiveRegionBasedAnnotation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/ActiveRegionBasedAnnotation.java
new file mode 100644
index 0000000..8a32ae1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/ActiveRegionBasedAnnotation.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator.interfaces;
+
+import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap;
+import htsjdk.variant.vcf.VCFInfoHeaderLine;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.List;
+import java.util.Map;
+
+// TODO -- make this an abstract class when we move away from InfoFieldAnnotation
+public interface ActiveRegionBasedAnnotation extends AnnotationType {
+ // return annotations for the given contexts split by sample and then read likelihood
+ public abstract Map<String, Object> annotate(final Map<String,PerReadAlleleLikelihoodMap> stratifiedContexts, final VariantContext vc);
+
+ // return the descriptions used for the VCF INFO meta field
+ public abstract List<VCFInfoHeaderLine> getDescriptions();
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/AnnotationInterfaceManager.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/AnnotationInterfaceManager.java
new file mode 100644
index 0000000..37b570c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/AnnotationInterfaceManager.java
@@ -0,0 +1,140 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator.interfaces;
+
+import org.broadinstitute.gatk.utils.DeprecatedToolChecks;
+import org.broadinstitute.gatk.utils.classloader.PluginManager;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.*;
+
+public class AnnotationInterfaceManager {
+ private static final String NULL_ANNOTATION_NAME = "none";
+ private static final String NULL_ANNOTATION_GROUP_NAME = "none";
+
+ private static PluginManager<InfoFieldAnnotation> infoFieldAnnotationPluginManager = new PluginManager<InfoFieldAnnotation>(InfoFieldAnnotation.class);
+ private static PluginManager<GenotypeAnnotation> genotypeAnnotationPluginManager = new PluginManager<GenotypeAnnotation>(GenotypeAnnotation.class);
+ private static PluginManager<AnnotationType> annotationTypePluginManager = new PluginManager<AnnotationType>(AnnotationType.class);
+
+ public static List<InfoFieldAnnotation> createAllInfoFieldAnnotations() {
+ return infoFieldAnnotationPluginManager.createAllTypes();
+ }
+
+ public static List<GenotypeAnnotation> createAllGenotypeAnnotations() {
+ return genotypeAnnotationPluginManager.createAllTypes();
+ }
+
+ public static void validateAnnotations(List<String> annotationGroupsToUse, List<String> annotationsToUse) {
+ HashMap<String, Class> classMap = new HashMap<String, Class>();
+ for ( Class c : infoFieldAnnotationPluginManager.getPlugins() )
+ classMap.put(c.getSimpleName(), c);
+ for ( Class c : genotypeAnnotationPluginManager.getPlugins() )
+ classMap.put(c.getSimpleName(), c);
+ for ( Class c : annotationTypePluginManager.getInterfaces() )
+ classMap.put(c.getSimpleName(), c);
+
+ if ( annotationGroupsToUse.size() != 1 || !NULL_ANNOTATION_GROUP_NAME.equals(annotationGroupsToUse.get(0)) ) {
+ for ( String group : annotationGroupsToUse ) {
+ Class interfaceClass = classMap.get(group);
+ if ( interfaceClass == null )
+ interfaceClass = classMap.get(group + "Annotation");
+ if ( interfaceClass == null )
+ throw new UserException.BadArgumentValue("group", "Annotation group " + group + " was not found; please check that you have specified the group name correctly");
+ }
+ }
+
+ // validate the specific classes provided
+ if ( annotationsToUse.size() != 1 || !NULL_ANNOTATION_NAME.equals(annotationsToUse.get(0)) ) {
+ for (String annotation : annotationsToUse) {
+ Class annotationClass = classMap.get(annotation);
+ if (annotationClass == null)
+ annotationClass = classMap.get(annotation + "Annotation");
+ if (annotationClass == null) {
+ if (DeprecatedToolChecks.isDeprecatedAnnotation(annotation)) {
+ throw new UserException.DeprecatedAnnotation(annotation, DeprecatedToolChecks.getAnnotationDeprecationInfo(annotation));
+ } else {
+ throw new UserException.BadArgumentValue("annotation", "Annotation " + annotation + " was not found; please check that you have specified the annotation name correctly");
+ }
+ }
+ }
+ }
+ }
+
+ public static List<InfoFieldAnnotation> createInfoFieldAnnotations(List<String> annotationGroupsToUse, List<String> annotationsToUse) {
+ return createAnnotations(infoFieldAnnotationPluginManager, annotationGroupsToUse, annotationsToUse);
+ }
+
+ public static List<GenotypeAnnotation> createGenotypeAnnotations(List<String> annotationGroupsToUse, List<String> annotationsToUse) {
+ return createAnnotations(genotypeAnnotationPluginManager, annotationGroupsToUse, annotationsToUse);
+ }
+
+ private static <T> List<T> createAnnotations(PluginManager<T> pluginManager, List<String> annotationGroupsToUse, List<String> annotationsToUse) {
+ // get the instances
+ List<T> annotations = new ArrayList<T>();
+
+ // get the classes from the provided groups (interfaces)
+ // create a map for all annotation classes which implement our top-level interfaces
+ HashMap<String, Class> classMap = new HashMap<String, Class>();
+ for ( Class c : pluginManager.getPlugins() )
+ classMap.put(c.getSimpleName(), c);
+ for ( Class c : annotationTypePluginManager.getInterfaces() )
+ classMap.put(c.getSimpleName(), c);
+
+ // use a TreeSet so that classes are returned deterministically (the plugin manager apparently isn't deterministic)
+ TreeSet<Class> classes = new TreeSet<Class>(new Comparator<Class>() {
+ public int compare(Class o1, Class o2) {
+ return o1.getSimpleName().compareTo(o2.getSimpleName());
+ }
+ });
+
+ if ( annotationGroupsToUse.size() != 1 || !NULL_ANNOTATION_GROUP_NAME.equals(annotationGroupsToUse.get(0)) ) {
+ for ( String group : annotationGroupsToUse ) {
+ Class interfaceClass = classMap.get(group);
+ if ( interfaceClass == null )
+ interfaceClass = classMap.get(group + "Annotation");
+ if ( interfaceClass != null )
+ classes.addAll(pluginManager.getPluginsImplementing(interfaceClass));
+ }
+ }
+
+ // get the specific classes provided
+ if ( annotationsToUse.size() != 1 || !NULL_ANNOTATION_NAME.equals(annotationsToUse.get(0)) ) {
+ for (String annotation : annotationsToUse) {
+ Class annotationClass = classMap.get(annotation);
+ if (annotationClass == null)
+ annotationClass = classMap.get(annotation + "Annotation");
+ if (annotationClass != null)
+ classes.add(annotationClass);
+ }
+ }
+
+ // note that technically an annotation can work on both the INFO and FORMAT fields
+ for ( Class c : classes )
+ annotations.add(pluginManager.createByType(c));
+
+ return annotations;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/AnnotationType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/AnnotationType.java
new file mode 100644
index 0000000..0051c97
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/AnnotationType.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator.interfaces;
+
+public interface AnnotationType {}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/AnnotatorCompatible.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/AnnotatorCompatible.java
new file mode 100644
index 0000000..f1aeede
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/AnnotatorCompatible.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator.interfaces;
+
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.List;
+
+public interface AnnotatorCompatible {
+
+ // getter methods for various used bindings
+ public abstract RodBinding<VariantContext> getSnpEffRodBinding();
+ public abstract RodBinding<VariantContext> getDbsnpRodBinding();
+ public abstract List<RodBinding<VariantContext>> getCompRodBindings();
+ public abstract List<RodBinding<VariantContext>> getResourceRodBindings();
+ public abstract boolean alwaysAppendDbsnpId();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/ExperimentalAnnotation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/ExperimentalAnnotation.java
new file mode 100644
index 0000000..9ed24db
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/ExperimentalAnnotation.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator.interfaces;
+
+public interface ExperimentalAnnotation extends AnnotationType {}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/GenotypeAnnotation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/GenotypeAnnotation.java
new file mode 100644
index 0000000..a6a81d7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/GenotypeAnnotation.java
@@ -0,0 +1,54 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator.interfaces;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap;
+import htsjdk.variant.vcf.VCFFormatHeaderLine;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.GenotypeBuilder;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.List;
+
+public abstract class GenotypeAnnotation extends VariantAnnotatorAnnotation {
+
+ // return annotations for the given contexts/genotype split by sample
+ public abstract void annotate(final RefMetaDataTracker tracker,
+ final AnnotatorCompatible walker,
+ final ReferenceContext ref,
+ final AlignmentContext stratifiedContext,
+ final VariantContext vc,
+ final Genotype g,
+ final GenotypeBuilder gb,
+ final PerReadAlleleLikelihoodMap alleleLikelihoodMap);
+
+ // return the descriptions used for the VCF FORMAT meta field
+ public abstract List<VCFFormatHeaderLine> getDescriptions();
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/InfoFieldAnnotation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/InfoFieldAnnotation.java
new file mode 100644
index 0000000..55a30d8
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/InfoFieldAnnotation.java
@@ -0,0 +1,62 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator.interfaces;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.genotyper.PerReadAlleleLikelihoodMap;
+import htsjdk.variant.vcf.VCFInfoHeaderLine;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.List;
+import java.util.Map;
+
+public abstract class InfoFieldAnnotation extends VariantAnnotatorAnnotation {
+ // return annotations for the given contexts split by sample
+ public Map<String, Object> annotate(final RefMetaDataTracker tracker,
+ final AnnotatorCompatible walker,
+ final ReferenceContext ref,
+ final Map<String, AlignmentContext> stratifiedContexts,
+ final VariantContext vc) {
+ return annotate(tracker, walker, ref, stratifiedContexts, vc, null);
+ }
+
+ public Map<String, Object> annotate(Map<String, PerReadAlleleLikelihoodMap> perReadAlleleLikelihoodMap, VariantContext vc) {
+ return annotate(null, null, null, null, vc, perReadAlleleLikelihoodMap);
+ }
+
+
+ public abstract Map<String, Object> annotate(final RefMetaDataTracker tracker,
+ final AnnotatorCompatible walker,
+ final ReferenceContext ref,
+ final Map<String, AlignmentContext> stratifiedContexts,
+ final VariantContext vc,
+ final Map<String, PerReadAlleleLikelihoodMap> stratifiedPerReadAlleleLikelihoodMap);
+
+ // return the descriptions used for the VCF INFO meta field
+ public abstract List<VCFInfoHeaderLine> getDescriptions();
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/RodRequiringAnnotation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/RodRequiringAnnotation.java
new file mode 100644
index 0000000..04e545a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/RodRequiringAnnotation.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator.interfaces;
+
+public interface RodRequiringAnnotation extends AnnotationType {}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/StandardAnnotation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/StandardAnnotation.java
new file mode 100644
index 0000000..247af00
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/StandardAnnotation.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator.interfaces;
+
+public interface StandardAnnotation extends AnnotationType {}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/VariantAnnotatorAnnotation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/VariantAnnotatorAnnotation.java
new file mode 100644
index 0000000..0c68955
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/VariantAnnotatorAnnotation.java
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator.interfaces;
+
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import htsjdk.variant.vcf.VCFHeaderLine;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+
+import java.util.List;
+import java.util.Set;
+
+ at DocumentedGATKFeature(enable = true, groupName = HelpConstants.DOCS_CAT_ANNOT, summary = "Annotations available to VariantAnnotator and the variant callers (some restrictions apply)")
+public abstract class VariantAnnotatorAnnotation {
+ // return the INFO keys
+ public abstract List<String> getKeyNames();
+
+ // initialization method (optional for subclasses, and therefore non-abstract)
+ public void initialize ( AnnotatorCompatible walker, GenomeAnalysisEngine toolkit, Set<VCFHeaderLine> headerLines ) { }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/WorkInProgressAnnotation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/WorkInProgressAnnotation.java
new file mode 100644
index 0000000..9daab43
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/annotator/interfaces/WorkInProgressAnnotation.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator.interfaces;
+
+public interface WorkInProgressAnnotation extends AnnotationType {}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/beagle/BeagleOutputToVCF.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/beagle/BeagleOutputToVCF.java
new file mode 100644
index 0000000..726ea9b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/beagle/BeagleOutputToVCF.java
@@ -0,0 +1,392 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.beagle;
+
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.codecs.beagle.BeagleFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import htsjdk.variant.vcf.*;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+
+import java.util.*;
+
+import static java.lang.Math.log10;
+
+
+/**
+ * Takes files produced by Beagle imputation engine and creates a vcf with modified annotations.
+ *
+ * <p>This walker is intended to be run after Beagle has successfully executed. The full calling sequence for using Beagle along with the GATK is: </p>
+ *
+ * <p>1. Run ProduceBeagleInputWalker. </p>
+ * <p>2. Run Beagle</p>
+ * <p>3. Uncompress output files</p>
+ * <p>4. Run BeagleOutputToVCFWalker.</p>
+ *
+ *
+ * Note that this walker requires all input files produced by Beagle.
+ *
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java -Xmx4000m -jar dist/GenomeAnalysisTK.jar \
+ * -R reffile.fasta -T BeagleOutputToVCF \
+ * -V input_vcf.vcf \
+ * -beagleR2:BEAGLE /myrun.beagle_output.r2 \
+ * -beaglePhased:BEAGLE /myrun.beagle_output.phased \
+ * -beagleProbs:BEAGLE /myrun.beagle_output.gprobs \
+ * -o output_vcf.vcf
+ * </pre>
+
+ <p> Note that Beagle produces some of these files compressed as .gz, so gunzip must be run on them before walker is run in order to decompress them </p>
+
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARDISC, extraDocs = {CommandLineGATK.class} )
+public class BeagleOutputToVCF extends RodWalker<Integer, Integer> {
+
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ /**
+ * If this argument is present, the original allele frequencies and counts from this vcf are added as annotations ACH,AFH and ANH. at each record present in this vcf
+ */
+ @Input(fullName="comp", shortName = "comp", doc="Comparison VCF file", required=false)
+ public RodBinding<VariantContext> comp;
+
+
+ /**
+ * This required argument is used to annotate each site in the vcf INFO field with R2 annotation. Will be NaN if Beagle determined there are no variant samples.
+ */
+ @Input(fullName="beagleR2", shortName = "beagleR2", doc="Beagle-produced .r2 file containing R^2 values for all markers", required=true)
+ public RodBinding<BeagleFeature> beagleR2;
+
+ /**
+ * These values will populate the GL field for each sample and contain the posterior probability of each genotype given the data after phasing and imputation.
+ */
+ @Input(fullName="beagleProbs", shortName = "beagleProbs", doc="Beagle-produced .probs file containing posterior genotype probabilities", required=true)
+ public RodBinding<BeagleFeature> beagleProbs;
+
+ /**
+ * By default, all genotypes will be marked in the VCF as "phased", using the "|" separator after Beagle.
+ */
+ @Input(fullName="beaglePhased", shortName = "beaglePhased", doc="Beagle-produced .phased file containing phased genotypes", required=true)
+ public RodBinding<BeagleFeature> beaglePhased;
+
+ @Output(doc="VCF File to which variants should be written")
+ protected VariantContextWriter vcfWriter = null;
+
+ /**
+ * If this argument is absent, and if Beagle determines that there is no sample in a site that has a variant genotype, the site will be marked as filtered (Default behavior).
+ * If the argument is present, the site won't be marked as filtered under this condition even if there are no variant genotypes.
+ */
+ @Argument(fullName="dont_mark_monomorphic_sites_as_filtered", shortName="keep_monomorphic", doc="If provided, we won't filter sites that beagle tags as monomorphic. Useful for imputing a sample's genotypes from a reference panel" ,required=false)
+ public boolean DONT_FILTER_MONOMORPHIC_SITES = false;
+
+ /**
+ * Value between 0 and 1. If the probability of getting a genotype correctly (based on the posterior genotype probabilities and the actual genotype) is below this threshold,
+ * a genotype will be substitute by a no-call.
+ */
+ @Argument(fullName="no" +
+ "call_threshold", shortName="ncthr", doc="Threshold of confidence at which a genotype won't be called", required=false)
+ private double noCallThreshold = 0.0;
+
+ protected static String line = null;
+
+ private final double MIN_PROB_ERROR = 0.000001;
+ private final double MAX_GENOTYPE_QUALITY = -6.0;
+
+ private final static String BEAGLE_MONO_FILTER_STRING = "BGL_SET_TO_MONOMORPHIC";
+ private final static String ORIGINAL_ALT_ALLELE_INFO_KEY = "OriginalAltAllele";
+
+ public void initialize() {
+
+ // setup the header fields
+
+ final Set<VCFHeaderLine> hInfo = new HashSet<VCFHeaderLine>();
+ hInfo.addAll(GATKVCFUtils.getHeaderFields(getToolkit()));
+ hInfo.add(new VCFFormatHeaderLine("OG",1, VCFHeaderLineType.String, "Original Genotype input to Beagle"));
+ hInfo.add(new VCFInfoHeaderLine("R2", 1, VCFHeaderLineType.Float, "r2 Value reported by Beagle on each site"));
+ hInfo.add(new VCFInfoHeaderLine("NumGenotypesChanged", 1, VCFHeaderLineType.Integer, "The number of genotypes changed by Beagle"));
+ hInfo.add(new VCFInfoHeaderLine(ORIGINAL_ALT_ALLELE_INFO_KEY, 1, VCFHeaderLineType.String, "The original alt allele for a site set to monomorphic by Beagle"));
+ hInfo.add(new VCFFilterHeaderLine(BEAGLE_MONO_FILTER_STRING, "This site was set to monomorphic by Beagle"));
+
+ if ( comp.isBound() ) {
+ hInfo.add(new VCFInfoHeaderLine("ACH", 1, VCFHeaderLineType.Integer, "Allele Count from Comparison ROD at this site"));
+ hInfo.add(new VCFInfoHeaderLine("ANH", 1, VCFHeaderLineType.Integer, "Allele Frequency from Comparison ROD at this site"));
+ hInfo.add(new VCFInfoHeaderLine("AFH", 1, VCFHeaderLineType.Float, "Allele Number from Comparison ROD at this site"));
+ }
+
+ Set<String> samples = SampleUtils.getSampleListWithVCFHeader(getToolkit(), Arrays.asList(variantCollection.variants.getName()));
+
+ final VCFHeader vcfHeader = new VCFHeader(hInfo, samples);
+ vcfWriter.writeHeader(vcfHeader);
+ }
+
+ public Integer map( RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context ) {
+
+ if ( tracker == null )
+ return 0;
+
+ GenomeLoc loc = context.getLocation();
+ VariantContext vc_input = tracker.getFirstValue(variantCollection.variants, loc);
+
+ VariantContext vc_comp = tracker.getFirstValue(comp, loc);
+
+ if ( vc_input == null )
+ return 0;
+
+ if (vc_input.isFiltered()) {
+ vcfWriter.add(vc_input);
+ return 1;
+ }
+
+ BeagleFeature beagleR2Feature = tracker.getFirstValue(beagleR2);
+ BeagleFeature beagleProbsFeature = tracker.getFirstValue(beagleProbs);
+ BeagleFeature beaglePhasedFeature = tracker.getFirstValue(beaglePhased);
+
+ // ignore places where we don't have a variant
+ if ( beagleR2Feature == null || beagleProbsFeature == null || beaglePhasedFeature == null)
+ {
+ vcfWriter.add(vc_input);
+ return 1;
+ }
+
+
+ // get reference base for current position
+ byte refByte = ref.getBase();
+
+ // make new Genotypes based on Beagle results
+ GenotypesContext genotypes = GenotypesContext.create(vc_input.getGenotypes().size());
+
+ // for each genotype, create a new object with Beagle information on it
+
+ int numGenotypesChangedByBeagle = 0;
+ Integer alleleCountH = 0, chrCountH = 0;
+ Double alleleFrequencyH = 0.0;
+ int beagleVarCounts = 0;
+
+ GenotypesContext hapmapGenotypes = null;
+
+ if (vc_comp != null) {
+ hapmapGenotypes = vc_comp.getGenotypes();
+ }
+
+ for ( final Genotype g : vc_input.getGenotypes() ) {
+ boolean genotypeIsPhased = true;
+ String sample = g.getSampleName();
+
+ // If we have a Hapmap (comp) ROD, compute Hapmap AC, AN and AF
+ // use sample as key into genotypes structure
+ if (vc_comp != null) {
+
+ if (vc_input.getGenotypes().containsSample(sample) && hapmapGenotypes.containsSample(sample)) {
+
+ Genotype hapmapGenotype = hapmapGenotypes.get(sample);
+ if (hapmapGenotype.isCalled()){
+ chrCountH += 2;
+ if (hapmapGenotype.isHet()) {
+ alleleCountH += 1;
+ } else if (hapmapGenotype.isHomVar()) {
+ alleleCountH += 2;
+ }
+ }
+ }
+ }
+
+ ArrayList<String> beagleProbabilities = beagleProbsFeature.getProbLikelihoods().get(sample);
+ ArrayList<String> beagleGenotypePairs = beaglePhasedFeature.getGenotypes().get(sample);
+
+ // original alleles at this genotype
+ Allele originalAlleleA = g.getAllele(0);
+
+ Allele originalAlleleB = (g.getAlleles().size() == 2) ? g.getAllele(1) : g.getAllele(0); // hack to deal with no-call genotypes
+
+
+ // We have phased genotype in hp. Need to set the isRef field in the allele.
+ List<Allele> alleles = new ArrayList<Allele>();
+
+ String alleleA = beagleGenotypePairs.get(0);
+ String alleleB = beagleGenotypePairs.get(1);
+
+ if ( alleleA.equals("null") || alleleB.equals("null") ) {
+ logger.warn("Beagle produced 'null' alleles at location "+ref.getLocus().toString()+". Ignoring.");
+ return 0;
+ }
+
+ // Beagle always produces genotype strings based on the strings we input in the likelihood file.
+ String refString = vc_input.getReference().getDisplayString();
+
+ Allele bglAlleleA, bglAlleleB;
+
+ if (alleleA.matches(refString))
+ bglAlleleA = Allele.create(alleleA,true);
+ else
+ bglAlleleA = Allele.create(alleleA,false);
+
+ if (alleleB.matches(refString))
+ bglAlleleB = Allele.create(alleleB,true);
+ else
+ bglAlleleB = Allele.create(alleleB,false);
+
+
+ alleles.add(bglAlleleA);
+ alleles.add(bglAlleleB);
+
+ // Compute new GQ field = -10*log10Pr(Genotype call is wrong)
+ // Beagle gives probability that genotype is AA, AB and BB.
+ // Which, by definition, are prob of hom ref, het and hom var.
+ double probWrongGenotype, genotypeQuality;
+ Double homRefProbability = Double.valueOf(beagleProbabilities.get(0));
+ Double hetProbability = Double.valueOf(beagleProbabilities.get(1));
+ Double homVarProbability = Double.valueOf(beagleProbabilities.get(2));
+
+ if (bglAlleleA.isReference() && bglAlleleB.isReference()) // HomRef call
+ probWrongGenotype = hetProbability + homVarProbability;
+ else if ((bglAlleleB.isReference() && bglAlleleA.isNonReference()) || (bglAlleleA.isReference() && bglAlleleB.isNonReference()))
+ probWrongGenotype = homRefProbability + homVarProbability;
+ else // HomVar call
+ probWrongGenotype = hetProbability + homRefProbability;
+
+ // deal with numerical errors coming from limited formatting value on Beagle output files
+ if (probWrongGenotype > 1 - MIN_PROB_ERROR)
+ probWrongGenotype = 1 - MIN_PROB_ERROR;
+
+ if (1-probWrongGenotype < noCallThreshold) {
+ // quality is bad: don't call genotype
+ alleles.clear();
+ alleles.add(originalAlleleA);
+ alleles.add(originalAlleleB);
+ genotypeIsPhased = false;
+ }
+
+ if (probWrongGenotype < MIN_PROB_ERROR)
+ genotypeQuality = MAX_GENOTYPE_QUALITY;
+ else
+ genotypeQuality = log10(probWrongGenotype);
+
+ HashMap<String,Object> originalAttributes = new HashMap<String,Object>(g.getExtendedAttributes());
+
+ // get original encoding and add to keynotype attributes
+ String a1, a2, og;
+ if (originalAlleleA.isNoCall())
+ a1 = ".";
+ else if (originalAlleleA.isReference())
+ a1 = "0";
+ else
+ a1 = "1";
+
+ if (originalAlleleB.isNoCall())
+ a2 = ".";
+ else if (originalAlleleB.isReference())
+ a2 = "0";
+ else
+ a2 = "1";
+
+ og = a1+"/"+a2;
+
+ // See if Beagle switched genotypes
+ if (! originalAlleleA.equals(Allele.NO_CALL) && beagleSwitchedGenotypes(bglAlleleA,originalAlleleA,bglAlleleB,originalAlleleB)){
+ originalAttributes.put("OG",og);
+ numGenotypesChangedByBeagle++;
+ }
+ else {
+ originalAttributes.put("OG",".");
+ }
+ Genotype imputedGenotype = new GenotypeBuilder(g).alleles(alleles).log10PError(genotypeQuality).attributes(originalAttributes).phased(genotypeIsPhased).make();
+ if ( imputedGenotype.isHet() || imputedGenotype.isHomVar() ) {
+ beagleVarCounts++;
+ }
+
+ genotypes.add(imputedGenotype);
+ }
+
+ final VariantContextBuilder builder = new VariantContextBuilder(vc_input).source("outputvcf").genotypes(genotypes);
+ if ( ! ( beagleVarCounts > 0 || DONT_FILTER_MONOMORPHIC_SITES ) ) {
+ builder.attribute(ORIGINAL_ALT_ALLELE_INFO_KEY, vc_input.getAlternateAllele(0));
+ builder.alleles(Collections.singleton(vc_input.getReference())).filter(BEAGLE_MONO_FILTER_STRING);
+ }
+
+ // re-compute chromosome counts
+ VariantContextUtils.calculateChromosomeCounts(builder, false);
+
+ // Get Hapmap AC and AF
+ if (vc_comp != null) {
+ builder.attribute("ACH", alleleCountH.toString() );
+ builder.attribute("ANH", chrCountH.toString() );
+ builder.attribute("AFH", String.format("%4.2f", (double)alleleCountH/chrCountH) );
+
+ }
+
+ builder.attribute("NumGenotypesChanged", numGenotypesChangedByBeagle );
+ if( !beagleR2Feature.getR2value().equals(Double.NaN) ) {
+ builder.attribute("R2", beagleR2Feature.getR2value().toString() );
+ }
+
+ vcfWriter.add(builder.make());
+
+ return 1;
+ }
+
+ private boolean beagleSwitchedGenotypes(Allele bglAlleleA, Allele originalAlleleA, Allele bglAlleleB, Allele originalAlleleB) {
+ return !((bglAlleleA.equals(originalAlleleA) && bglAlleleB.equals(originalAlleleB) ||
+ (bglAlleleA.equals(originalAlleleB) && bglAlleleB.equals(originalAlleleA))));
+ }
+
+ public Integer reduceInit() {
+ return 0; // Nothing to do here
+ }
+
+ /**
+ * Increment the number of loci processed.
+ *
+ * @param value result of the map.
+ * @param sum accumulator for the reduce.
+ * @return the new number of loci processed.
+ */
+ public Integer reduce(Integer value, Integer sum) {
+ return sum + value;
+ }
+
+ /**
+ * Tell the user the number of loci processed and close out the new variants file.
+ *
+ * @param result the number of loci seen.
+ */
+ public void onTraversalDone(Integer result) {
+ System.out.printf("Processed %d loci.\n", result);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/beagle/ProduceBeagleInput.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/beagle/ProduceBeagleInput.java
new file mode 100644
index 0000000..dab5d16
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/beagle/ProduceBeagleInput.java
@@ -0,0 +1,463 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.beagle;
+
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.samples.Gender;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.tools.walkers.variantrecalibration.VQSRCalibrationCurve;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.vcf.VCFFilterHeaderLine;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.util.*;
+
+/**
+ * Converts the input VCF into a format accepted by the Beagle imputation/analysis program.
+ * <p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A VCF with variants to convert to Beagle format
+ * </p>
+ *
+ * <h2>Outputs</h2>
+ * <p>
+ * A single text file which can be fed to Beagle
+ * </p>
+ * <p>
+ * Optional: A file with a list of markers
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar dist/GenomeAnalysisTK.jar -L 20 \
+ * -R reffile.fasta -T ProduceBeagleInput \
+ * -V path_to_input_vcf/inputvcf.vcf -o path_to_beagle_output/beagle_output
+ * </pre>
+ *
+ */
+
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARDISC, extraDocs = {CommandLineGATK.class} )
+public class ProduceBeagleInput extends RodWalker<Integer, Integer> {
+
+ @ArgumentCollection protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ @Hidden
+ @Input(fullName="validation", shortName = "validation", doc="Validation VCF file", required=false)
+ public RodBinding<VariantContext> validation;
+
+
+ @Output(doc="File to which BEAGLE input should be written")
+ protected PrintStream beagleWriter = null;
+
+ @Hidden
+ @Output(doc="File to which BEAGLE markers should be written", shortName="markers", fullName = "markers", required = false, defaultToStdout = false)
+ protected PrintStream markers = null;
+ int markerCounter = 1;
+
+ @Hidden
+ @Input(doc="VQSqual calibration file", shortName = "cc", required=false)
+ protected File VQSRCalibrationFile = null;
+ protected VQSRCalibrationCurve VQSRCalibrator = null;
+
+ @Hidden
+ @Argument(doc="VQSqual key", shortName = "vqskey", required=false)
+ protected String VQSLOD_KEY = "VQSqual";
+
+ @Hidden
+ @Argument(fullName = "inserted_nocall_rate", shortName = "nc_rate", doc = "Rate (0-1) at which genotype no-calls will be randomly inserted, for testing", required = false)
+ public double insertedNoCallRate = 0;
+ @Hidden
+ @Argument(fullName = "validation_genotype_ptrue", shortName = "valp", doc = "Flat probability to assign to validation genotypes. Will override GL field.", required = false)
+ public double validationPrior = -1.0;
+ @Hidden
+ @Argument(fullName = "validation_bootstrap", shortName = "bs", doc = "Proportion of records to be used in bootstrap set", required = false)
+ public double bootstrap = 0.0;
+ @Hidden
+ @Argument(fullName = "bootstrap_vcf",shortName = "bvcf", doc = "Output a VCF with the records used for bootstrapping filtered out", required = false)
+ VariantContextWriter bootstrapVCFOutput = null;
+
+ /**
+ * If sample gender is known, this flag should be set to true to ensure that Beagle treats male Chr X properly.
+ */
+ @Argument(fullName = "checkIsMaleOnChrX", shortName = "checkIsMaleOnChrX", doc = "Set to true when Beagle-ing chrX and want to ensure male samples don't have heterozygous calls.", required = false)
+ public boolean CHECK_IS_MALE_ON_CHR_X = false;
+
+ @Hidden
+ @Argument(fullName = "variant_genotype_ptrue", shortName = "varp", doc = "Flat probability prior to assign to variant (not validation) genotypes. Does not override GL field.", required = false)
+ public double variantPrior = 0.96;
+
+ private Set<String> samples = null;
+ private Set<String> BOOTSTRAP_FILTER = new HashSet<String>( Arrays.asList("bootstrap") );
+ private int bootstrapSetSize = 0;
+ private int testSetSize = 0;
+ private CachingFormatter formatter = new CachingFormatter("%5.4f ", 100000);
+ private int certainFPs = 0;
+
+ public void initialize() {
+
+ samples = SampleUtils.getSampleListWithVCFHeader(getToolkit(), Arrays.asList(variantCollection.variants.getName()));
+
+ beagleWriter.print("marker alleleA alleleB");
+ for ( String sample : samples )
+ beagleWriter.print(String.format(" %s %s %s", sample, sample, sample));
+
+ beagleWriter.println();
+
+ if ( bootstrapVCFOutput != null ) {
+ initializeVcfWriter();
+ }
+
+ if ( VQSRCalibrationFile != null ) {
+ VQSRCalibrator = VQSRCalibrationCurve.readFromFile(VQSRCalibrationFile);
+ logger.info("Read calibration curve");
+ VQSRCalibrator.printInfo(logger);
+ }
+ }
+
+ public Integer map( RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context ) {
+ if( tracker != null ) {
+ GenomeLoc loc = context.getLocation();
+ VariantContext variant_eval = tracker.getFirstValue(variantCollection.variants, loc);
+ VariantContext validation_eval = tracker.getFirstValue(validation, loc);
+
+ if ( goodSite(variant_eval,validation_eval) ) {
+ if ( useValidation(validation_eval, ref) ) {
+ writeBeagleOutput(validation_eval, variant_eval, true, validationPrior);
+ return 1;
+ } else {
+ if ( goodSite(variant_eval) ) {
+ writeBeagleOutput(variant_eval,validation_eval,false,variantPrior);
+ return 1;
+ } else { // todo -- if the variant site is bad, validation is good, but not in bootstrap set -- what do?
+ return 0;
+ }
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ public boolean goodSite(VariantContext a, VariantContext b) {
+ return goodSite(a) || goodSite(b);
+ }
+
+ public boolean goodSite(VariantContext v) {
+ if ( canBeOutputToBeagle(v) ) {
+ if ( VQSRCalibrator != null && VQSRCalibrator.certainFalsePositive(VQSLOD_KEY, v) ) {
+ certainFPs++;
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ public static boolean canBeOutputToBeagle(VariantContext v) {
+ return v != null && ! v.isFiltered() && v.isBiallelic() && v.hasGenotypes();
+ }
+
+ public boolean useValidation(VariantContext validation, ReferenceContext ref) {
+ if( goodSite(validation) ) {
+ // if using record keeps us below expected proportion, use it
+ logger.debug(String.format("boot: %d, test: %d, total: %d", bootstrapSetSize, testSetSize, bootstrapSetSize+testSetSize+1));
+ if ( (bootstrapSetSize+1.0)/(1.0+bootstrapSetSize+testSetSize) <= bootstrap ) {
+ if ( bootstrapVCFOutput != null ) {
+ bootstrapVCFOutput.add(new VariantContextBuilder(validation).filters(BOOTSTRAP_FILTER).make());
+ }
+ bootstrapSetSize++;
+ return true;
+ } else {
+ if ( bootstrapVCFOutput != null ) {
+ bootstrapVCFOutput.add(validation);
+ }
+ testSetSize++;
+ return false;
+ }
+ } else {
+ if ( validation != null && bootstrapVCFOutput != null ) {
+ bootstrapVCFOutput.add(validation);
+ }
+ return false;
+ }
+ }
+
+ private final static double[] HAPLOID_FLAT_LOG10_LIKELIHOODS = MathUtils.toLog10(new double[]{ 0.5, 0.0, 0.5 });
+ private final static double[] DIPLOID_FLAT_LOG10_LIKELIHOODS = MathUtils.toLog10(new double[]{ 0.33, 0.33, 0.33 });
+
+ public void writeBeagleOutput(VariantContext preferredVC, VariantContext otherVC, boolean isValidationSite, double prior) {
+ GenomeLoc currentLoc = GATKVariantContextUtils.getLocation(getToolkit().getGenomeLocParser(), preferredVC);
+ StringBuffer beagleOut = new StringBuffer();
+
+ String marker = String.format("%s:%d ",currentLoc.getContig(),currentLoc.getStart());
+ beagleOut.append(marker);
+ if ( markers != null ) markers.append(marker).append("\t").append(Integer.toString(markerCounter++)).append("\t");
+ for ( Allele allele : preferredVC.getAlleles() ) {
+ String bglPrintString;
+ if (allele.isNoCall())
+ bglPrintString = "-";
+ else
+ bglPrintString = allele.getBaseString(); // get rid of * in case of reference allele
+
+ beagleOut.append(String.format("%s ", bglPrintString));
+ if ( markers != null ) markers.append(bglPrintString).append("\t");
+ }
+ if ( markers != null ) markers.append("\n");
+
+ GenotypesContext preferredGenotypes = preferredVC.getGenotypes();
+ GenotypesContext otherGenotypes = goodSite(otherVC) ? otherVC.getGenotypes() : null;
+ for ( String sample : samples ) {
+ boolean isMaleOnChrX = CHECK_IS_MALE_ON_CHR_X && getSample(sample).getGender() == Gender.MALE;
+
+ Genotype genotype;
+ boolean isValidation;
+ // use sample as key into genotypes structure
+ if ( preferredGenotypes.containsSample(sample) ) {
+ genotype = preferredGenotypes.get(sample);
+ isValidation = isValidationSite;
+ } else if ( otherGenotypes != null && otherGenotypes.containsSample(sample) ) {
+ genotype = otherGenotypes.get(sample);
+ isValidation = ! isValidationSite;
+ } else {
+ // there is magically no genotype for this sample.
+ throw new GATKException("Sample "+sample+" arose with no genotype in variant or validation VCF. This should never happen.");
+ }
+
+ /*
+ * Use likelihoods if: is validation, prior is negative; or: is not validation, has genotype key
+ */
+ double [] log10Likelihoods = null;
+ if ( (isValidation && prior < 0.0) || genotype.hasLikelihoods() ) {
+ log10Likelihoods = genotype.getLikelihoods().getAsVector();
+
+ // see if we need to randomly mask out genotype in this position.
+ if ( GenomeAnalysisEngine.getRandomGenerator().nextDouble() <= insertedNoCallRate ) {
+ // we are masking out this genotype
+ log10Likelihoods = isMaleOnChrX ? HAPLOID_FLAT_LOG10_LIKELIHOODS : DIPLOID_FLAT_LOG10_LIKELIHOODS;
+ }
+
+ if( isMaleOnChrX ) {
+ log10Likelihoods[1] = -255; // todo -- warning this is dangerous for multi-allele case
+ }
+ }
+ /**
+ * otherwise, use the prior uniformly
+ */
+ else if (! isValidation && genotype.isCalled() && ! genotype.hasLikelihoods() ) {
+ // hack to deal with input VCFs with no genotype likelihoods. Just assume the called genotype
+ // is confident. This is useful for Hapmap and 1KG release VCFs.
+ double AA = (1.0-prior)/2.0;
+ double AB = (1.0-prior)/2.0;
+ double BB = (1.0-prior)/2.0;
+
+ if (genotype.isHomRef()) { AA = prior; }
+ else if (genotype.isHet()) { AB = prior; }
+ else if (genotype.isHomVar()) { BB = prior; }
+
+ log10Likelihoods = MathUtils.toLog10(new double[]{ AA, isMaleOnChrX ? 0.0 : AB, BB });
+ }
+ else {
+ log10Likelihoods = isMaleOnChrX ? HAPLOID_FLAT_LOG10_LIKELIHOODS : DIPLOID_FLAT_LOG10_LIKELIHOODS;
+ }
+
+ writeSampleLikelihoods(beagleOut, preferredVC, log10Likelihoods);
+ }
+
+ beagleWriter.println(beagleOut.toString());
+ }
+
+ private void writeSampleLikelihoods( StringBuffer out, VariantContext vc, double[] log10Likelihoods ) {
+ if ( VQSRCalibrator != null ) {
+ log10Likelihoods = VQSRCalibrator.includeErrorRateInLikelihoods(VQSLOD_KEY, vc, log10Likelihoods);
+ }
+
+ double[] normalizedLikelihoods = MathUtils.normalizeFromLog10(log10Likelihoods);
+ // see if we need to randomly mask out genotype in this position.
+ for (double likeVal: normalizedLikelihoods) {
+ out.append(formatter.format(likeVal));
+// out.append(String.format("%5.4f ",likeVal));
+ }
+ }
+
+
+ public Integer reduceInit() {
+ return 0; // Nothing to do here
+ }
+
+ public Integer reduce( Integer value, Integer sum ) {
+ return value + sum; // count up the sites
+ }
+
+ public void onTraversalDone( Integer includedSites ) {
+ logger.info("Sites included in beagle likelihoods file : " + includedSites);
+ logger.info(String.format("Certain false positive found from recalibration curve : %d (%.2f%%)",
+ certainFPs, (100.0 * certainFPs) / (Math.max(certainFPs + includedSites, 1))));
+ }
+
+ private void initializeVcfWriter() {
+ final List<String> inputNames = Arrays.asList(validation.getName());
+
+ // setup the header fields
+ Set<VCFHeaderLine> hInfo = new HashSet<VCFHeaderLine>();
+ hInfo.addAll(GATKVCFUtils.getHeaderFields(getToolkit(), inputNames));
+ hInfo.add(new VCFFilterHeaderLine("bootstrap","This site used for genotype bootstrapping with ProduceBeagleInputWalker"));
+
+ bootstrapVCFOutput.writeHeader(new VCFHeader(hInfo, SampleUtils.getUniqueSamplesFromRods(getToolkit(), inputNames)));
+ }
+
+ public static class CachingFormatter {
+ private String format;
+ private LRUCache<Double, String> cache;
+
+ public String getFormat() {
+ return format;
+ }
+
+ public String format(double value) {
+ String f = cache.get(value);
+ if ( f == null ) {
+ f = String.format(format, value);
+ cache.put(value, f);
+// if ( cache.usedEntries() < maxCacheSize ) {
+// System.out.printf("CACHE size %d%n", cache.usedEntries());
+// } else {
+// System.out.printf("CACHE is full %f%n", value);
+// }
+// }
+// } else {
+// System.out.printf("CACHE hit %f%n", value);
+// }
+ }
+
+ return f;
+ }
+
+ public CachingFormatter(String format, int maxCacheSize) {
+ this.format = format;
+ this.cache = new LRUCache<Double, String>(maxCacheSize);
+ }
+ }
+
+ /**
+ * An LRU cache, based on <code>LinkedHashMap</code>.
+ *
+ * <p>
+ * This cache has a fixed maximum number of elements (<code>cacheSize</code>).
+ * If the cache is full and another entry is added, the LRU (least recently used) entry is dropped.
+ *
+ * <p>
+ * This class is thread-safe. All methods of this class are synchronized.
+ *
+ * <p>
+ * Author: Christian d'Heureuse, Inventec Informatik AG, Zurich, Switzerland<br>
+ * Multi-licensed: EPL / LGPL / GPL / AL / BSD.
+ */
+ public static class LRUCache<K,V> {
+
+ private static final float hashTableLoadFactor = 0.75f;
+
+ private LinkedHashMap<K,V> map;
+ private int cacheSize;
+
+ /**
+ * Creates a new LRU cache.
+ * @param cacheSize the maximum number of entries that will be kept in this cache.
+ */
+ public LRUCache (int cacheSize) {
+ this.cacheSize = cacheSize;
+ int hashTableCapacity = (int)Math.ceil(cacheSize / hashTableLoadFactor) + 1;
+ map = new LinkedHashMap<K,V>(hashTableCapacity, hashTableLoadFactor, true) {
+ // (an anonymous inner class)
+ private static final long serialVersionUID = 1;
+ @Override protected boolean removeEldestEntry (Map.Entry<K,V> eldest) {
+ return size() > LRUCache.this.cacheSize; }}; }
+
+ /**
+ * Retrieves an entry from the cache.<br>
+ * The retrieved entry becomes the MRU (most recently used) entry.
+ * @param key the key whose associated value is to be returned.
+ * @return the value associated to this key, or null if no value with this key exists in the cache.
+ */
+ public synchronized V get (K key) {
+ return map.get(key); }
+
+ /**
+ * Adds an entry to this cache.
+ * The new entry becomes the MRU (most recently used) entry.
+ * If an entry with the specified key already exists in the cache, it is replaced by the new entry.
+ * If the cache is full, the LRU (least recently used) entry is removed from the cache.
+ * @param key the key with which the specified value is to be associated.
+ * @param value a value to be associated with the specified key.
+ */
+ public synchronized void put (K key, V value) {
+ map.put (key, value); }
+
+ /**
+ * Clears the cache.
+ */
+ public synchronized void clear() {
+ map.clear(); }
+
+ /**
+ * Returns the number of used entries in the cache.
+ * @return the number of entries currently in the cache.
+ */
+ public synchronized int usedEntries() {
+ return map.size(); }
+
+ /**
+ * Returns a <code>Collection</code> that contains a copy of all cache entries.
+ * @return a <code>Collection</code> with a copy of the cache content.
+ */
+ public synchronized Collection<Map.Entry<K,V>> getAll() {
+ return new ArrayList<Map.Entry<K,V>>(map.entrySet()); }
+
+ } // end class LRUCache
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/beagle/VariantsToBeagleUnphased.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/beagle/VariantsToBeagleUnphased.java
new file mode 100644
index 0000000..c45ceb2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/beagle/VariantsToBeagleUnphased.java
@@ -0,0 +1,184 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.beagle;
+
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Set;
+
+/**
+ * Produces an input file to Beagle imputation engine, listing unphased, hard-called genotypes for a single sample
+ * in input variant file. Will additionally hold back a fraction of the sites for evaluation, marking the
+ * genotypes at that sites as missing, and writing the truth of these sites to a second VCF file
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARDISC, extraDocs = {CommandLineGATK.class} )
+public class VariantsToBeagleUnphased extends RodWalker<Integer, Integer> {
+ @Input(fullName="variants", shortName = "V", doc="Input VCF file", required=true)
+ public RodBinding<VariantContext> variants;
+
+ @Output(doc="File to which BEAGLE unphased genotypes should be written")
+ protected PrintStream beagleWriter = null;
+
+ @Argument(fullName = "bootstrap_fraction", shortName = "bs", doc = "Proportion of records to be used in bootstrap set", required = false)
+ public double bootstrap = 0.0;
+
+ @Argument(fullName = "bootstrap_vcf",shortName = "bsvcf", doc = "Output a VCF with the records used for bootstrapping filtered out", required = false)
+ VariantContextWriter bootstrapVCFOutput = null;
+
+ @Argument(fullName = "missing", shortName = "missing", doc = "String to identify missing data in beagle output", required = false)
+ public String MISSING = "?";
+
+ private Set<String> samples = null;
+ private int bootstrapSetSize = 0;
+ private int testSetSize = 0;
+
+ public void initialize() {
+ samples = SampleUtils.getSampleListWithVCFHeader(getToolkit(), Arrays.asList(variants.getName()));
+
+ beagleWriter.print("I marker alleleA alleleB");
+ for ( String sample : samples )
+ beagleWriter.print(String.format(" %s %s", sample, sample));
+
+ beagleWriter.println();
+
+ if ( bootstrap < 0.0 | bootstrap > 1.0 )
+ throw new UserException.BadArgumentValue("bootstrap", "Bootstrap value must be fraction between 0 and 1");
+
+ if ( bootstrapVCFOutput != null ) {
+ Set<VCFHeaderLine> hInfo = GATKVCFUtils.getHeaderFields(getToolkit());
+ bootstrapVCFOutput.writeHeader(new VCFHeader(hInfo, SampleUtils.getUniqueSamplesFromRods(getToolkit())));
+ }
+ }
+
+ /**
+ * Iterate over each site, emitting the BEAGLE unphased genotypes file format
+ * @param tracker
+ * @param ref
+ * @param context
+ * @return
+ */
+ public Integer map( RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context ) {
+ if( tracker != null ) {
+ GenomeLoc loc = context.getLocation();
+ VariantContext vc = tracker.getFirstValue(variants, loc);
+
+ if ( ProduceBeagleInput.canBeOutputToBeagle(vc) ) {
+ // do we want to hold back this site?
+ boolean makeMissing = dropSite(vc);
+
+ // if we are holding it back and we are writing a bootstrap VCF, write it out
+ if ( makeMissing && bootstrapVCFOutput != null ) {
+ bootstrapVCFOutput.add(vc);
+ }
+
+ // regardless, all sites are written to the unphased genotypes file, marked as missing if appropriate
+ writeUnphasedBeagleOutput(vc, makeMissing);
+ }
+ }
+
+ return 0;
+ }
+
+ /**
+ * Do we want to hold back this site for bootstrap? Considers the bootstrap fraction member variable
+ *
+ * @param vc
+ * @return
+ */
+ public boolean dropSite(VariantContext vc) {
+ if ( (bootstrapSetSize+1.0)/(1.0+bootstrapSetSize+testSetSize) <= bootstrap ) {
+ bootstrapSetSize++;
+ return true;
+ } else {
+ testSetSize++;
+ return false;
+ }
+ }
+
+ public void writeUnphasedBeagleOutput(VariantContext vc, boolean makeMissing) {
+ GenomeLoc currentLoc = GATKVariantContextUtils.getLocation(getToolkit().getGenomeLocParser(), vc);
+ StringBuffer beagleOut = new StringBuffer();
+
+ String marker = String.format("%s:%d ",currentLoc.getContig(), currentLoc.getStart());
+ beagleOut.append("M ").append(marker);
+
+ // write out the alleles at this site
+ for ( Allele allele : vc.getAlleles() ) {
+ beagleOut.append(allele.isNoCall() ? "-" : allele.getBaseString()).append(" ");
+ }
+
+ // write out sample level genotypes
+ for ( String sample : samples ) {
+ Genotype genotype = vc.getGenotype(sample);
+ if ( ! makeMissing && genotype.isCalled() ) {
+ addAlleles(beagleOut, genotype);
+ } else {
+ addAlleles(beagleOut, MISSING, MISSING);
+ }
+ }
+
+ beagleWriter.println(beagleOut.toString());
+ }
+
+ private void addAlleles(StringBuffer buf, Genotype g) {
+ addAlleles(buf, g.getAllele(0).getBaseString(), g.getAllele(1).getBaseString());
+
+ }
+
+ private void addAlleles(StringBuffer buf, String a, String b) {
+ buf.append(a).append(" ").append(b);
+ }
+
+ public Integer reduceInit() { return 0; }
+ public Integer reduce( Integer value, Integer sum ) { return value + sum; }
+
+ public void onTraversalDone( Integer includedSites ) {
+ logger.info("Sites included in beagle genotypes file : " + includedSites);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/CallableLoci.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/CallableLoci.java
new file mode 100644
index 0000000..1757e7b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/CallableLoci.java
@@ -0,0 +1,396 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.coverage;
+
+import org.broadinstitute.gatk.utils.commandline.Advanced;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.By;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.LocusWalker;
+import org.broadinstitute.gatk.utils.*;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+
+
+/**
+ * Emits a data file containing information about callable, uncallable, poorly mapped, and other parts of the genome
+ * <p/>
+ * <p>
+ * A very common question about a NGS set of reads is what areas of the genome are considered callable. The system
+ * considers the coverage at each locus and emits either a per base state or a summary interval BED file that
+ * partitions the genomic intervals into the following callable states:
+ * <dl>
+ * <dt>REF_N</dt>
+ * <dd>the reference base was an N, which is not considered callable the GATK</dd>
+ * <dt>PASS</dt>
+ * <dd>the base satisfied the min. depth for calling but had less than maxDepth to avoid having EXCESSIVE_COVERAGE</dd>
+ * <dt>NO_COVERAGE</dt>
+ * <dd>absolutely no reads were seen at this locus, regardless of the filtering parameters</dd>
+ * <dt>LOW_COVERAGE</dt>
+ * <dd>there were less than min. depth bases at the locus, after applying filters</dd>
+ * <dt>EXCESSIVE_COVERAGE</dt>
+ * <dd>more than -maxDepth read at the locus, indicating some sort of mapping problem</dd>
+ * <dt>POOR_MAPPING_QUALITY</dt>
+ * <dd>more than --maxFractionOfReadsWithLowMAPQ at the locus, indicating a poor mapping quality of the reads</dd>
+ * </dl>
+ * </p>
+ * <p/>
+ * <h3>Input</h3>
+ * <p>
+ * A BAM file containing <b>exactly one sample</b>.
+ * </p>
+ * <p/>
+ * <h3>Output</h3>
+ * <p>
+ * <ul>
+ * <li>-o: a OutputFormatted (recommended BED) file with the callable status covering each base</li>
+ * <li>-summary: a table of callable status x count of all examined bases</li>
+ * </ul>
+ * </p>
+ * <p/>
+ * <h3>Examples</h3>
+ * <pre>
+ * java -jar GenomeAnalysisTK.jar \
+ * -T CallableLoci \
+ * -I my.bam \
+ * -summary my.summary \
+ * -o my.bed
+ * </pre>
+ * <p/>
+ * would produce a BED file (my.bed) that looks like:
+ * <p/>
+ * <pre>
+ * 20 10000000 10000864 PASS
+ * 20 10000865 10000985 POOR_MAPPING_QUALITY
+ * 20 10000986 10001138 PASS
+ * 20 10001139 10001254 POOR_MAPPING_QUALITY
+ * 20 10001255 10012255 PASS
+ * 20 10012256 10012259 POOR_MAPPING_QUALITY
+ * 20 10012260 10012263 PASS
+ * 20 10012264 10012328 POOR_MAPPING_QUALITY
+ * 20 10012329 10012550 PASS
+ * 20 10012551 10012551 LOW_COVERAGE
+ * 20 10012552 10012554 PASS
+ * 20 10012555 10012557 LOW_COVERAGE
+ * 20 10012558 10012558 PASS
+ * et cetera...
+ * </pre>
+ * as well as a summary table that looks like:
+ * <p/>
+ * <pre>
+ * state nBases
+ * REF_N 0
+ * PASS 996046
+ * NO_COVERAGE 121
+ * LOW_COVERAGE 928
+ * EXCESSIVE_COVERAGE 0
+ * POOR_MAPPING_QUALITY 2906
+ * </pre>
+ *
+ * @author Mark DePristo
+ * @since May 7, 2010
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+ at By(DataSource.REFERENCE)
+public class CallableLoci extends LocusWalker<CallableLoci.CallableBaseState, CallableLoci.Integrator> {
+ @Output
+ PrintStream out;
+
+ /**
+ * Callable loci summary counts (see outputs) will be written to this file.
+ */
+ @Output(fullName = "summary", shortName = "summary", doc = "Name of file for output summary", required = true)
+ File summaryFile;
+
+ /**
+ * The gap between this value and mmq are reads that are not sufficiently well mapped for calling but
+ * aren't indicative of mapping problems. For example, if maxLowMAPQ = 1 and mmq = 20, then reads with
+ * MAPQ == 0 are poorly mapped, MAPQ >= 20 are considered as contributing to calling, where
+ * reads with MAPQ >= 1 and < 20 are not bad in and of themselves but aren't sufficiently good to contribute to
+ * calling. In effect this reads are invisible, driving the base to the NO_ or LOW_COVERAGE states
+ */
+ @Argument(fullName = "maxLowMAPQ", shortName = "mlmq", doc = "Maximum value for MAPQ to be considered a problematic mapped read.", required = false)
+ byte maxLowMAPQ = 1;
+
+ /**
+ * Reads with MAPQ > minMappingQuality are treated as usable for variation detection, contributing to the PASS
+ * state.
+ */
+ @Argument(fullName = "minMappingQuality", shortName = "mmq", doc = "Minimum mapping quality of reads to count towards depth.", required = false)
+ byte minMappingQuality = 10;
+
+ /**
+ * Bases with less than minBaseQuality are viewed as not sufficiently high quality to contribute to the PASS state
+ */
+ @Argument(fullName = "minBaseQuality", shortName = "mbq", doc = "Minimum quality of bases to count towards depth.", required = false)
+ byte minBaseQuality = 20;
+
+ /**
+ * If the number of QC+ bases (on reads with MAPQ > minMappingQuality and with base quality > minBaseQuality) exceeds this
+ * value and is less than maxDepth the site is considered PASS.
+ */
+ @Advanced
+ @Argument(fullName = "minDepth", shortName = "minDepth", doc = "Minimum QC+ read depth before a locus is considered callable", required = false)
+ int minDepth = 4;
+
+ /**
+ * If the QC+ depth exceeds this value the site is considered to have EXCESSIVE_DEPTH
+ */
+ @Argument(fullName = "maxDepth", shortName = "maxDepth", doc = "Maximum read depth before a locus is considered poorly mapped", required = false)
+ int maxDepth = -1;
+
+ /**
+ * We don't want to consider a site as POOR_MAPPING_QUALITY just because it has two reads, and one is MAPQ. We
+ * won't assign a site to the POOR_MAPPING_QUALITY state unless there are at least minDepthForLowMAPQ reads
+ * covering the site.
+ */
+ @Advanced
+ @Argument(fullName = "minDepthForLowMAPQ", shortName = "mdflmq", doc = "Minimum read depth before a locus is considered a potential candidate for poorly mapped", required = false)
+ int minDepthLowMAPQ = 10;
+
+ /**
+ * If the number of reads at this site is greater than minDepthForLowMAPQ and the fraction of reads with low mapping quality
+ * exceeds this fraction then the site has POOR_MAPPING_QUALITY.
+ */
+ @Argument(fullName = "maxFractionOfReadsWithLowMAPQ", shortName = "frlmq", doc = "If the fraction of reads at a base with low mapping quality exceeds this value, the site may be poorly mapped", required = false)
+ double maxLowMAPQFraction = 0.1;
+
+ /**
+ * The output of this walker will be written in this format. The recommended option is BED.
+ */
+ @Advanced
+ @Argument(fullName = "format", shortName = "format", doc = "Output format", required = false)
+ OutputFormat outputFormat = OutputFormat.BED;
+
+ public enum OutputFormat {
+ /**
+ * The output will be written as a BED file. There's a BED element for each
+ * continuous run of callable states (i.e., PASS, REF_N, etc). This is the recommended
+ * format
+ */
+ BED,
+
+ /**
+ * Emit chr start stop state quads for each base. Produces a potentially disasterously
+ * large amount of output.
+ */
+ STATE_PER_BASE
+ }
+
+ public enum CalledState {
+ /**
+ * the reference base was an N, which is not considered callable the GATK
+ */
+ REF_N,
+ /**
+ * the base satisfied the min. depth for calling but had less than maxDepth to avoid having EXCESSIVE_COVERAGE
+ */
+ CALLABLE,
+ /**
+ * absolutely no reads were seen at this locus, regardless of the filtering parameters
+ */
+ NO_COVERAGE,
+ /**
+ * there were less than min. depth bases at the locus, after applying filters
+ */
+ LOW_COVERAGE,
+ /**
+ * more than -maxDepth read at the locus, indicating some sort of mapping problem
+ */
+ EXCESSIVE_COVERAGE,
+ /**
+ * more than --maxFractionOfReadsWithLowMAPQ at the locus, indicating a poor mapping quality of the reads
+ */
+ POOR_MAPPING_QUALITY
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // STANDARD WALKER METHODS
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public boolean includeReadsWithDeletionAtLoci() {
+ return true;
+ }
+
+ @Override
+ public void initialize() {
+ if (getSampleDB().getSamples().size() != 1) {
+ throw new UserException.BadArgumentValue("-I", "CallableLoci only works for a single sample, but multiple samples were found in the provided BAM files: " + getSampleDB().getSamples());
+ }
+
+ try {
+ PrintStream summaryOut = new PrintStream(summaryFile);
+ summaryOut.close();
+ } catch (FileNotFoundException e) {
+ throw new UserException.CouldNotCreateOutputFile(summaryFile, e);
+ }
+ }
+
+ protected static class Integrator {
+ final long counts[] = new long[CalledState.values().length];
+ CallableBaseState state = null;
+ }
+
+ protected static class CallableBaseState implements HasGenomeLocation {
+ final public GenomeLocParser genomeLocParser;
+ public GenomeLoc loc;
+ final public CalledState state;
+
+ public CallableBaseState(GenomeLocParser genomeLocParser, GenomeLoc loc, CalledState state) {
+ this.genomeLocParser = genomeLocParser;
+ this.loc = loc;
+ this.state = state;
+ }
+
+ public GenomeLoc getLocation() {
+ return loc;
+ }
+
+ public CalledState getState() {
+ return state;
+ }
+
+ // update routines
+ public boolean changingState(CalledState newState) {
+ return state != newState;
+ }
+
+ /**
+ * Updating the location of this CalledBaseState by the new stop location
+ *
+ * @param newStop
+ */
+ public void update(GenomeLoc newStop) {
+ loc = genomeLocParser.createGenomeLoc(loc.getContig(), loc.getStart(), newStop.getStop());
+ }
+
+ public String toString() {
+ return String.format("%s\t%d\t%d\t%s", loc.getContig(), loc.getStart()-1, loc.getStop(), state);
+ }
+ }
+
+ @Override
+ public CallableBaseState map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ CalledState state;
+
+ if ( BaseUtils.isNBase(ref.getBase())) {
+ state = CalledState.REF_N;
+ } else {
+ // count up the depths of all and QC+ bases
+ int rawDepth = 0, QCDepth = 0, lowMAPQDepth = 0;
+ for (PileupElement e : context.getBasePileup()) {
+ rawDepth++;
+
+ if (e.getMappingQual() <= maxLowMAPQ)
+ lowMAPQDepth++;
+
+ if (e.getMappingQual() >= minMappingQuality && (e.getQual() >= minBaseQuality || e.isDeletion())) {
+ QCDepth++;
+ }
+ }
+
+ //System.out.printf("%s rawdepth = %d QCDepth = %d lowMAPQ = %d%n", context.getLocation(), rawDepth, QCDepth, lowMAPQDepth);
+ if (rawDepth == 0) {
+ state = CalledState.NO_COVERAGE;
+ } else if (rawDepth >= minDepthLowMAPQ && MathUtils.ratio(lowMAPQDepth, rawDepth) >= maxLowMAPQFraction) {
+ state = CalledState.POOR_MAPPING_QUALITY;
+ } else if (QCDepth < minDepth) {
+ state = CalledState.LOW_COVERAGE;
+ } else if (rawDepth >= maxDepth && maxDepth != -1) {
+ state = CalledState.EXCESSIVE_COVERAGE;
+ } else {
+ state = CalledState.CALLABLE;
+ }
+ }
+
+ return new CallableBaseState(getToolkit().getGenomeLocParser(), context.getLocation(), state);
+ }
+
+ @Override
+ public Integrator reduceInit() {
+ return new Integrator();
+ }
+
+ @Override
+ public Integrator reduce(CallableBaseState state, Integrator integrator) {
+ // update counts
+ integrator.counts[state.getState().ordinal()]++;
+
+ if (outputFormat == OutputFormat.STATE_PER_BASE) {
+ out.println(state.toString());
+ }
+
+ // format is integrating
+ if (integrator.state == null)
+ integrator.state = state;
+ else if (state.getLocation().getStart() != integrator.state.getLocation().getStop() + 1 ||
+ integrator.state.changingState(state.getState())) {
+ out.println(integrator.state.toString());
+ integrator.state = state;
+ } else {
+ integrator.state.update(state.getLocation());
+ }
+
+ return integrator;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // INTERVAL ON TRAVERSAL DONE
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public void onTraversalDone(Integrator result) {
+ // print out the last state
+ if (result != null) {
+ if (outputFormat == OutputFormat.BED) // get the last interval
+ out.println(result.state.toString());
+
+ try {
+ PrintStream summaryOut = new PrintStream(summaryFile);
+ summaryOut.printf("%30s %s%n", "state", "nBases");
+ for (CalledState state : CalledState.values()) {
+ summaryOut.printf("%30s %d%n", state, result.counts[state.ordinal()]);
+ }
+ summaryOut.close();
+ } catch (FileNotFoundException e) {
+ throw new UserException.CouldNotCreateOutputFile(summaryFile, e);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/CompareCallableLoci.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/CompareCallableLoci.java
new file mode 100644
index 0000000..9ab8555
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/CompareCallableLoci.java
@@ -0,0 +1,143 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.coverage;
+
+import htsjdk.tribble.bed.BEDFeature;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test routine for new VariantContext object
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class CompareCallableLoci extends RodWalker<List<CallableLoci.CallableBaseState>, long[][]> {
+ @Output
+ protected PrintStream out;
+
+ @Input(fullName="comp1", shortName = "comp1", doc="First comparison track name", required=true)
+ public RodBinding<BEDFeature> compTrack1;
+
+ @Input(fullName="comp2", shortName = "comp2", doc="Second comparison track name", required=true)
+ public RodBinding<BEDFeature> compTrack2;
+
+ @Argument(shortName="printState", doc="If provided, prints sites satisfying this state pair", required=false)
+ protected String printState = null;
+
+ CallableLoci.CalledState printState1 = CallableLoci.CalledState.REF_N;
+ CallableLoci.CalledState printState2 = CallableLoci.CalledState.REF_N;
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // initialize
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ public void initialize() {
+ if ( printState != null ) {
+ String[] states = printState.split(",");
+ printState1 = CallableLoci.CalledState.valueOf(states[0]);
+ printState2 = CallableLoci.CalledState.valueOf(states[1]);
+ }
+ }
+
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // map
+ //
+ // --------------------------------------------------------------------------------------------------------------
+ public List<CallableLoci.CallableBaseState> map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker != null ) {
+ CallableLoci.CallableBaseState comp1 = getCallableBaseState(tracker, compTrack1);
+ CallableLoci.CallableBaseState comp2 = getCallableBaseState(tracker, compTrack2);
+
+ if ( printState != null && comp1.getState() == printState1 && comp2.getState() == printState2 ) {
+ out.printf("%s %s %s %s%n", comp1.getLocation(), comp1.getState(), comp2.getLocation(), comp2.getState());
+ }
+
+ return Arrays.asList(comp1, comp2);
+ } else {
+ return null;
+ }
+ }
+
+ private CallableLoci.CallableBaseState getCallableBaseState(RefMetaDataTracker tracker, RodBinding<BEDFeature> rodBinding) {
+ //System.out.printf("tracker %s%n", tracker);
+ List<BEDFeature> bindings = tracker.getValues(rodBinding);
+ if ( bindings.size() != 1 ) {
+ throw new UserException.MalformedFile(String.format("%s track isn't a properly formated CallableBases object!", rodBinding.getName()));
+ }
+
+ BEDFeature bed = bindings.get(0);
+ GenomeLoc loc = getToolkit().getGenomeLocParser().createGenomeLoc(bed.getChr(), bed.getStart(), bed.getEnd());
+ CallableLoci.CalledState state = CallableLoci.CalledState.valueOf(bed.getName());
+ return new CallableLoci.CallableBaseState(getToolkit().getGenomeLocParser(),loc, state);
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // reduce
+ //
+ // --------------------------------------------------------------------------------------------------------------
+ public long[][] reduceInit() {
+ int n = CallableLoci.CalledState.values().length;
+ return new long[n][n];
+ }
+
+ public long[][] reduce(List<CallableLoci.CallableBaseState> comps, long[][] sum) {
+ if ( comps != null ) {
+ CallableLoci.CallableBaseState comp1 = comps.get(0);
+ CallableLoci.CallableBaseState comp2 = comps.get(1);
+
+ sum[comp1.getState().ordinal()][comp2.getState().ordinal()]++;
+ }
+
+ return sum;
+ }
+
+ public void onTraversalDone(long[][] result) {
+ for ( CallableLoci.CalledState state1 : CallableLoci.CalledState.values() ) {
+ for ( CallableLoci.CalledState state2 : CallableLoci.CalledState.values() ) {
+ out.printf("%s %s %s %s %d%n", compTrack1.getName(), compTrack2.getName(), state1, state2, result[state1.ordinal()][state2.ordinal()]);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/CoverageUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/CoverageUtils.java
new file mode 100644
index 0000000..7514fa5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/CoverageUtils.java
@@ -0,0 +1,241 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.coverage;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.fragments.FragmentCollection;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+
+import java.util.*;
+
+/**
+ * IF THERE IS NO JAVADOC RIGHT HERE, YELL AT chartl
+ *
+ * @Author chartl
+ * @Date Mar 3, 2010
+ */
+public class CoverageUtils {
+
+ public enum CountPileupType {
+ /**
+ * Count all reads independently (even if from the same fragment).
+ */
+ COUNT_READS,
+ /**
+ * Count all fragments (even if the reads that compose the fragment are not consistent at that base).
+ */
+ COUNT_FRAGMENTS,
+ /**
+ * Count all fragments (but only if the reads that compose the fragment are consistent at that base).
+ */
+ COUNT_FRAGMENTS_REQUIRE_SAME_BASE
+ }
+
+ /**
+ * Returns the counts of bases from reads with MAPQ > minMapQ and base quality > minBaseQ in the context
+ * as an array of ints, indexed by the index fields of BaseUtils
+ *
+ * @param context
+ * @param minMapQ
+ * @param minBaseQ
+ * @return
+ */
+ public static int[] getBaseCounts(AlignmentContext context, int minMapQ, int minBaseQ) {
+ int[] counts = new int[6];
+
+ for (PileupElement e : context.getBasePileup()) {
+ if ( e.getMappingQual() >= minMapQ && ( e.getQual() >= minBaseQ || e.isDeletion() ) ) {
+ updateCounts(counts,e);
+ }
+ }
+
+ return counts;
+ }
+
+ public static String getTypeID( SAMReadGroupRecord r, DoCOutputType.Partition type ) {
+ if ( type == DoCOutputType.Partition.sample ) {
+ return r.getSample();
+ } else if ( type == DoCOutputType.Partition.readgroup ) {
+ return String.format("%s_rg_%s",r.getSample(),r.getReadGroupId());
+ } else if ( type == DoCOutputType.Partition.library ) {
+ return r.getLibrary();
+ } else if ( type == DoCOutputType.Partition.center ) {
+ return r.getSequencingCenter();
+ } else if ( type == DoCOutputType.Partition.platform ) {
+ return r.getPlatform();
+ } else if ( type == DoCOutputType.Partition.sample_by_center ) {
+ return String.format("%s_cn_%s",r.getSample(),r.getSequencingCenter());
+ } else if ( type == DoCOutputType.Partition.sample_by_platform) {
+ return String.format("%s_pl_%s",r.getSample(),r.getPlatform());
+ } else if ( type == DoCOutputType.Partition.sample_by_platform_by_center ) {
+ return String.format("%s_pl_%s_cn_%s",r.getSample(),r.getPlatform(),r.getSequencingCenter());
+ } else {
+ throw new ReviewedGATKException("Invalid type ID sent to getTypeID. This is a BUG!");
+ }
+ }
+
+ public static Map<DoCOutputType.Partition,Map<String,int[]>>
+ getBaseCountsByPartition(AlignmentContext context, int minMapQ, int maxMapQ, byte minBaseQ, byte maxBaseQ, CountPileupType countType, Collection<DoCOutputType.Partition> types) {
+
+ Map<DoCOutputType.Partition,Map<String,int[]>> countsByIDByType = new HashMap<DoCOutputType.Partition,Map<String,int[]>>();
+ Map<SAMReadGroupRecord,int[]> countsByRG = getBaseCountsByReadGroup(context,minMapQ,maxMapQ,minBaseQ,maxBaseQ,countType);
+ for (DoCOutputType.Partition t : types ) {
+ // iterate through the read group counts and build the type associations
+ for ( Map.Entry<SAMReadGroupRecord,int[]> readGroupCountEntry : countsByRG.entrySet() ) {
+ String typeID = getTypeID(readGroupCountEntry.getKey(),t);
+
+ if ( ! countsByIDByType.keySet().contains(t) ) {
+ countsByIDByType.put(t,new HashMap<String,int[]>());
+ }
+
+ if ( ! countsByIDByType.get(t).keySet().contains(typeID) ) {
+ countsByIDByType.get(t).put(typeID,readGroupCountEntry.getValue().clone());
+ } else {
+ addCounts(countsByIDByType.get(t).get(typeID),readGroupCountEntry.getValue());
+ }
+ }
+ }
+
+
+ return countsByIDByType;
+ }
+
+ public static void addCounts(int[] updateMe, int[] leaveMeAlone ) {
+ for ( int index = 0; index < leaveMeAlone.length; index++ ) {
+ updateMe[index] += leaveMeAlone[index];
+ }
+ }
+
+ public static Map<SAMReadGroupRecord,int[]> getBaseCountsByReadGroup(AlignmentContext context, int minMapQ, int maxMapQ, byte minBaseQ, byte maxBaseQ, CountPileupType countType) {
+ Map<SAMReadGroupRecord, int[]> countsByRG = new HashMap<SAMReadGroupRecord,int[]>();
+
+ List<PileupElement> countPileup = new LinkedList<PileupElement>();
+ FragmentCollection<PileupElement> fpile;
+
+ switch (countType) {
+
+ case COUNT_READS:
+ for (PileupElement e : context.getBasePileup())
+ if (countElement(e, minMapQ, maxMapQ, minBaseQ, maxBaseQ))
+ countPileup.add(e);
+ break;
+
+ case COUNT_FRAGMENTS: // ignore base identities and put in FIRST base that passes filters:
+ fpile = context.getBasePileup().getStartSortedPileup().toFragments();
+
+ for (PileupElement e : fpile.getSingletonReads())
+ if (countElement(e, minMapQ, maxMapQ, minBaseQ, maxBaseQ))
+ countPileup.add(e);
+
+ for (List<PileupElement> overlappingPair : fpile.getOverlappingPairs()) {
+ // iterate over all elements in fragment:
+ for (PileupElement e : overlappingPair) {
+ if (countElement(e, minMapQ, maxMapQ, minBaseQ, maxBaseQ)) {
+ countPileup.add(e); // add the first passing element per fragment
+ break;
+ }
+ }
+ }
+ break;
+
+ case COUNT_FRAGMENTS_REQUIRE_SAME_BASE:
+ fpile = context.getBasePileup().getStartSortedPileup().toFragments();
+
+ for (PileupElement e : fpile.getSingletonReads())
+ if (countElement(e, minMapQ, maxMapQ, minBaseQ, maxBaseQ))
+ countPileup.add(e);
+
+ for (List<PileupElement> overlappingPair : fpile.getOverlappingPairs()) {
+ PileupElement firstElem = null;
+ PileupElement addElem = null;
+
+ // iterate over all elements in fragment:
+ for (PileupElement e : overlappingPair) {
+ if (firstElem == null)
+ firstElem = e;
+ else if (e.getBase() != firstElem.getBase()) {
+ addElem = null;
+ break;
+ }
+
+ // will add the first passing element per base-consistent fragment:
+ if (addElem == null && countElement(e, minMapQ, maxMapQ, minBaseQ, maxBaseQ))
+ addElem = e;
+ }
+
+ if (addElem != null)
+ countPileup.add(addElem);
+ }
+ break;
+
+ default:
+ throw new UserException("Must use valid CountPileupType");
+ }
+
+ for (PileupElement e : countPileup) {
+ SAMReadGroupRecord readGroup = getReadGroup(e.getRead());
+ if (!countsByRG.keySet().contains(readGroup))
+ countsByRG.put(readGroup, new int[6]);
+
+ updateCounts(countsByRG.get(readGroup), e);
+ }
+
+ return countsByRG;
+ }
+
+ private static boolean countElement(PileupElement e, int minMapQ, int maxMapQ, byte minBaseQ, byte maxBaseQ) {
+ return (e.getMappingQual() >= minMapQ && e.getMappingQual() <= maxMapQ && ( e.getQual() >= minBaseQ && e.getQual() <= maxBaseQ || e.isDeletion() ));
+ }
+
+ private static void updateCounts(int[] counts, PileupElement e) {
+ if ( e.isDeletion() ) {
+ counts[BaseUtils.Base.D.ordinal()]++;
+ } else if ( BaseUtils.basesAreEqual(BaseUtils.Base.N.base, e.getBase()) ) {
+ counts[BaseUtils.Base.N.ordinal()]++;
+ } else {
+ try {
+ counts[BaseUtils.simpleBaseToBaseIndex(e.getBase())]++;
+ } catch (ArrayIndexOutOfBoundsException exc) {
+ throw new ReviewedGATKException("Expected a simple base, but actually received"+(char)e.getBase());
+ }
+ }
+ }
+
+ private static SAMReadGroupRecord getReadGroup(SAMRecord r) {
+ SAMReadGroupRecord rg = r.getReadGroup();
+ if ( rg == null ) {
+ String msg = "Read "+r.getReadName()+" lacks read group information; Please associate all reads with read groups";
+ throw new UserException.MalformedBAM(r, msg);
+ }
+
+ return rg;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverage.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverage.java
new file mode 100644
index 0000000..3fc2e59
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverage.java
@@ -0,0 +1,1110 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.coverage;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.engine.walkers.*;
+import org.broadinstitute.gatk.utils.commandline.Advanced;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.refdata.SeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrack;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrackBuilder;
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.engine.refdata.utils.LocationAwareSeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.codecs.refseq.RefSeqCodec;
+import org.broadinstitute.gatk.utils.codecs.refseq.RefSeqFeature;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.util.*;
+
+/**
+ * Assess sequence coverage by a wide array of metrics, partitioned by sample, read group, or library
+ *
+ * <p>
+ * This tool processes a set of bam files to determine coverage at different levels of partitioning and
+ * aggregation. Coverage can be analyzed per locus, per interval, per gene, or in total; can be partitioned by
+ * sample, by read group, by technology, by center, or by library; and can be summarized by mean, median, quartiles,
+ * and/or percentage of bases covered to or beyond a threshold.
+ * Additionally, reads and bases can be filtered by mapping or base quality score.
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more bam files (with proper headers) to be analyzed for coverage statistics
+ * </p>
+ * <p>
+ *(Optional) A REFSEQ Rod to aggregate coverage to the gene level
+ * <p>
+ * (for information about creating the REFSEQ Rod, please consult the online documentation)
+ *</p></p>
+ * <h3>Output</h3>
+ * <p>
+ * Tables pertaining to different coverage summaries. Suffix on the table files declares the contents:
+ * </p><p>
+ * - no suffix: per locus coverage
+ * </p><p>
+ * - _summary: total, mean, median, quartiles, and threshold proportions, aggregated over all bases
+ * </p><p>
+ * - _statistics: coverage histograms (# locus with X coverage), aggregated over all bases
+ * </p><p>
+ * - _interval_summary: total, mean, median, quartiles, and threshold proportions, aggregated per interval
+ * </p><p>
+ * - _interval_statistics: 2x2 table of # of intervals covered to >= X depth in >=Y samples
+ * </p><p>
+ * - _gene_summary: total, mean, median, quartiles, and threshold proportions, aggregated per gene
+ * </p><p>
+ * - _gene_statistics: 2x2 table of # of genes covered to >= X depth in >= Y samples
+ * </p><p>
+ * - _cumulative_coverage_counts: coverage histograms (# locus with >= X coverage), aggregated over all bases
+ * </p><p>
+ * - _cumulative_coverage_proportions: proprotions of loci with >= X coverage, aggregated over all bases
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T DepthOfCoverage \
+ * -o file_name_base \
+ * -I input_bams.list
+ * [-geneList refSeq.sorted.txt] \
+ * [-pt readgroup] \
+ * [-ct 4 -ct 6 -ct 10] \
+ * [-L my_capture_genes.interval_list]
+ * </pre>
+ *
+ */
+// todo -- cache the map from sample names to means in the print functions, rather than regenerating each time
+// todo -- support for granular histograms for total depth; maybe n*[start,stop], bins*sqrt(n)
+// todo -- alter logarithmic scaling to spread out bins more
+// todo -- allow for user to set linear binning (default is logarithmic)
+// todo -- formatting --> do something special for end bins in getQuantile(int[] foo), this gets mushed into the end+-1 bins for now
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class}, gotoDev = HelpConstants.MC)
+ at By(DataSource.REFERENCE)
+ at PartitionBy(PartitionType.NONE)
+ at Downsample(by= DownsampleType.NONE, toCoverage=Integer.MAX_VALUE)
+public class DepthOfCoverage extends LocusWalker<Map<DoCOutputType.Partition,Map<String,int[]>>, CoveragePartitioner> implements TreeReducible<CoveragePartitioner> {
+ @Output
+ @Multiplex(value=DoCOutputMultiplexer.class,arguments={"partitionTypes","refSeqGeneList","omitDepthOutput","omitIntervals","omitSampleSummary","omitLocusTable"})
+ Map<DoCOutputType,PrintStream> out;
+ /**
+ * Reads with mapping quality values lower than this threshold will be skipped. This is set to -1 by default to disable the evaluation and ignore this threshold.
+ */
+ @Argument(fullName = "minMappingQuality", shortName = "mmq", doc = "Minimum mapping quality of reads to count towards depth", required = false, minValue = 0, maxValue = Integer.MAX_VALUE)
+ int minMappingQuality = -1;
+ /**
+ * Reads with mapping quality values higher than this threshold will be skipped. The default value is the largest number that can be represented as an integer by the program.
+ */
+ @Argument(fullName = "maxMappingQuality", doc = "Maximum mapping quality of reads to count towards depth", required = false, minValue = 0, maxValue = Integer.MAX_VALUE)
+ int maxMappingQuality = Integer.MAX_VALUE;
+ /**
+ * Bases with quality scores lower than this threshold will be skipped. This is set to -1 by default to disable the evaluation and ignore this threshold.
+ */
+ @Argument(fullName = "minBaseQuality", shortName = "mbq", doc = "Minimum quality of bases to count towards depth", required = false, minValue = 0, maxValue = Byte.MAX_VALUE)
+ byte minBaseQuality = -1;
+ /**
+ * Bases with quality scores higher than this threshold will be skipped. The default value is the largest number that can be represented as a byte.
+ */
+ @Argument(fullName = "maxBaseQuality", doc = "Maximum quality of bases to count towards depth", required = false, minValue = 0, maxValue = Byte.MAX_VALUE)
+ byte maxBaseQuality = Byte.MAX_VALUE;
+
+ @Argument(fullName = "countType", doc = "How should overlapping reads from the same fragment be handled?", required = false)
+ CoverageUtils.CountPileupType countType = CoverageUtils.CountPileupType.COUNT_READS;
+
+ /**
+ * Instead of reporting depth, the program will report the base pileup at each locus
+ */
+ @Argument(fullName = "printBaseCounts", shortName = "baseCounts", doc = "Add base counts to per-locus output", required = false)
+ boolean printBaseCounts = false;
+
+ /**
+ * Disabling the tabulation of locus statistics (# loci covered by sample by coverage) should speed up processing.
+ */
+ @Argument(fullName = "omitLocusTable", shortName = "omitLocusTable", doc = "Do not calculate per-sample per-depth counts of loci", required = false)
+ boolean omitLocusTable = false;
+
+ /**
+ * Disabling the tabulation of interval statistics (mean, median, quartiles AND # intervals by sample by coverage) should speed up processing. This option is required in order to use -nt parallelism.
+ */
+ @Argument(fullName = "omitIntervalStatistics", shortName = "omitIntervals", doc = "Do not calculate per-interval statistics", required = false)
+ boolean omitIntervals = false;
+ /**
+ * Disabling the tabulation of total coverage at every base should speed up processing.
+ */
+ @Argument(fullName = "omitDepthOutputAtEachBase", shortName = "omitBaseOutput", doc = "Do not output depth of coverage at each base", required = false)
+ boolean omitDepthOutput = false;
+
+ /**
+ * Specify a RefSeq file for use in aggregating coverage statistics over genes.
+ */
+ @Argument(fullName = "calculateCoverageOverGenes", shortName = "geneList", doc = "Calculate coverage statistics over this list of genes", required = false)
+ File refSeqGeneList = null;
+
+ /**
+ * Output file format (e.g. csv, table, rtable); defaults to r-readable table.
+ */
+ @Argument(fullName = "outputFormat", doc = "The format of the output file", required = false)
+ String outputFormat = "rtable";
+
+
+ // ---------------------------------------------------------------------------
+ //
+ // Advanced arguments
+ //
+ // ---------------------------------------------------------------------------
+
+ /**
+ * Normally, sites where the reference is N (or another non-canonical base) are skipped. If this option is enabled, these sites will be included in DoC calculations if there is coverage from neighboring reads.
+ */
+ @Advanced
+ @Argument(fullName = "includeRefNSites", doc = "Include sites where the reference is N", required = false)
+ boolean includeRefNBases = false;
+ /**
+ * Use this option to calibrate what bins you want before performing full calculations on your data.
+ */
+ @Advanced
+ @Argument(fullName = "printBinEndpointsAndExit", doc = "Print the bin values and exit immediately", required = false)
+ boolean printBinEndpointsAndExit = false;
+ /**
+ * Sets the low-coverage cutoff for granular binning. All loci with depth < START are counted in the first bin.
+ */
+ @Advanced
+ @Argument(fullName = "start", doc = "Starting (left endpoint) for granular binning", required = false, minValue = 0)
+ int start = 1;
+ /**
+ * Sets the high-coverage cutoff for granular binning. All loci with depth > STOP are counted in the last bin.
+ */
+ @Advanced
+ @Argument(fullName = "stop", doc = "Ending (right endpoint) for granular binning", required = false, minValue = 1)
+ int stop = 500;
+ /**
+ * Sets the number of bins for granular binning
+ */
+ @Advanced
+ @Argument(fullName = "nBins", doc = "Number of bins to use for granular binning", required = false, minValue = 0, minRecommendedValue = 1)
+ int nBins = 499;
+
+ /**
+ * This option simply disables writing separate files for per-sample summary statistics (total, mean, median, quartile coverage per sample). These statistics are still calculated internally, so enabling this option will not improve runtime.
+ */
+ @Argument(fullName = "omitPerSampleStats", shortName = "omitSampleSummary", doc = "Do not output the summary files per-sample", required = false)
+ boolean omitSampleSummary = false;
+ /**
+ * By default, coverage is partitioning by sample, but it can be any combination of sample, readgroup and/or library.
+ */
+ @Argument(fullName = "partitionType", shortName = "pt", doc = "Partition type for depth of coverage", required = false)
+ Set<DoCOutputType.Partition> partitionTypes = EnumSet.of(DoCOutputType.Partition.sample);
+
+ /**
+ * Consider a spanning deletion as contributing to coverage. Also enables deletion counts in per-base output.
+ */
+ @Advanced
+ @Argument(fullName = "includeDeletions", shortName = "dels", doc = "Include information on deletions", required = false)
+ boolean includeDeletions = false;
+
+ @Advanced
+ @Argument(fullName = "ignoreDeletionSites", doc = "Ignore sites consisting only of deletions", required = false)
+ boolean ignoreDeletionSites = false;
+
+ /**
+ * For summary file outputs, report the percentage of bases covered to an amount equal to or greater than this number (e.g. % bases >= CT for each sample). Defaults to 15; can take multiple arguments.
+ */
+ @Advanced
+ @Argument(fullName = "summaryCoverageThreshold", shortName = "ct", doc = "Coverage threshold (in percent) for summarizing statistics", required = false)
+ int[] coverageThresholds = {15};
+
+ String[] OUTPUT_FORMATS = {"table","rtable","csv"};
+ String separator = "\t";
+ Map<DoCOutputType.Partition,List<String>> orderCheck = new HashMap<DoCOutputType.Partition,List<String>>();
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // STANDARD WALKER METHODS
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ public boolean includeReadsWithDeletionAtLoci() { return includeDeletions && ! ignoreDeletionSites; }
+
+ public void initialize() {
+
+ if ( printBinEndpointsAndExit ) {
+ int[] endpoints = DepthOfCoverageStats.calculateBinEndpoints(start,stop,nBins);
+ System.out.print("[ ");
+ for ( int e : endpoints ) {
+ System.out.print(e+" ");
+ }
+ System.out.println("]");
+ System.exit(0);
+ }
+
+ // Check the output format
+ boolean goodOutputFormat = false;
+ for ( String f : OUTPUT_FORMATS ) {
+ goodOutputFormat = goodOutputFormat || f.equals(outputFormat);
+ }
+
+ if ( ! goodOutputFormat ) {
+ throw new IllegalArgumentException("Improper output format. Can be one of table,rtable,csv. Was "+outputFormat);
+ }
+
+ if ( outputFormat.equals("csv") ) {
+ separator = ",";
+ }
+
+ if ( ! omitDepthOutput ) { // print header
+ PrintStream out = getCorrectStream(null, DoCOutputType.Aggregation.locus, DoCOutputType.FileType.summary);
+ out.printf("%s\t%s","Locus","Total_Depth");
+ for (DoCOutputType.Partition type : partitionTypes ) {
+ out.printf("\t%s_%s","Average_Depth",type.toString());
+ }
+
+ // get all the samples
+ HashSet<String> allSamples = getSamplesFromToolKit(partitionTypes);
+ ArrayList<String> allSampleList = new ArrayList<String>(allSamples.size());
+ for ( String s : allSamples ) {
+ allSampleList.add(s);
+ }
+ Collections.sort(allSampleList);
+
+ for ( String s : allSampleList) {
+ out.printf("\t%s_%s","Depth_for",s);
+ if ( printBaseCounts ) {
+ out.printf("\t%s_%s",s,"base_counts");
+ }
+ }
+
+ out.printf("%n");
+
+ } else {
+ logger.info("Per-Locus Depth of Coverage output was omitted");
+ }
+
+ for (DoCOutputType.Partition type : partitionTypes ) {
+ orderCheck.put(type,new ArrayList<String>());
+ for ( String id : getSamplesFromToolKit(type) ) {
+ orderCheck.get(type).add(id);
+ }
+ Collections.sort(orderCheck.get(type));
+ }
+ }
+
+ private HashSet<String> getSamplesFromToolKit( Collection<DoCOutputType.Partition> types ) {
+ HashSet<String> partitions = new HashSet<String>(); // since the DOCS object uses a HashMap, this will be in the same order
+ for (DoCOutputType.Partition t : types ) {
+ partitions.addAll(getSamplesFromToolKit(t));
+ }
+
+ return partitions;
+ }
+
+ private HashSet<String> getSamplesFromToolKit(DoCOutputType.Partition type) {
+ HashSet<String> partition = new HashSet<String>();
+ if ( type == DoCOutputType.Partition.sample ) {
+ partition.addAll(SampleUtils.getSAMFileSamples(getToolkit()));
+ } else if ( type == DoCOutputType.Partition.readgroup ) {
+ for ( SAMReadGroupRecord rg : getToolkit().getSAMFileHeader().getReadGroups() ) {
+ partition.add(rg.getSample()+"_rg_"+rg.getReadGroupId());
+ }
+ } else if ( type == DoCOutputType.Partition.library ) {
+ for ( SAMReadGroupRecord rg : getToolkit().getSAMFileHeader().getReadGroups() ) {
+ partition.add(rg.getLibrary());
+ }
+ } else if ( type == DoCOutputType.Partition.center ) {
+ for ( SAMReadGroupRecord rg : getToolkit().getSAMFileHeader().getReadGroups() ) {
+ partition.add(rg.getSequencingCenter());
+ }
+ } else if ( type == DoCOutputType.Partition.platform ) {
+ for ( SAMReadGroupRecord rg : getToolkit().getSAMFileHeader().getReadGroups() ) {
+ partition.add(rg.getPlatform());
+ }
+ } else if ( type == DoCOutputType.Partition.sample_by_center ) {
+ for ( SAMReadGroupRecord rg : getToolkit().getSAMFileHeader().getReadGroups() ) {
+ partition.add(String.format("%s_cn_%s",rg.getSample(),rg.getSequencingCenter()));
+ }
+ } else if ( type == DoCOutputType.Partition.sample_by_platform ) {
+ for ( SAMReadGroupRecord rg : getToolkit().getSAMFileHeader().getReadGroups() ) {
+ partition.add(String.format("%s_pl_%s",rg.getSample(),rg.getPlatform()));
+ }
+ } else if ( type == DoCOutputType.Partition.sample_by_platform_by_center ) {
+ for ( SAMReadGroupRecord rg : getToolkit().getSAMFileHeader().getReadGroups() ) {
+ partition.add(String.format("%s_pl_%s_cn_%s",rg.getSample(),rg.getPlatform(),rg.getSequencingCenter()));
+ }
+ } else {
+ throw new ReviewedGATKException("Invalid aggregation type sent to getSamplesFromToolKit");
+ }
+
+ return partition;
+ }
+
+ public boolean isReduceByInterval() {
+ return ( ! omitIntervals );
+ }
+
+ public CoveragePartitioner reduceInit() {
+ CoveragePartitioner aggro = new CoveragePartitioner(partitionTypes,start,stop,nBins);
+ for (DoCOutputType.Partition t : partitionTypes ) {
+ aggro.addIdentifiers(t,getSamplesFromToolKit(t));
+ }
+ aggro.initialize(includeDeletions,omitLocusTable);
+ checkOrder(aggro);
+ return aggro;
+ }
+
+ public Map<DoCOutputType.Partition,Map<String,int[]>> map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if (includeRefNBases || BaseUtils.isRegularBase(ref.getBase())) {
+ if ( ! omitDepthOutput ) {
+ getCorrectStream(null, DoCOutputType.Aggregation.locus, DoCOutputType.FileType.summary).printf("%s",ref.getLocus()); // yes: print locus in map, and the rest of the info in reduce (for eventual cumulatives)
+ //System.out.printf("\t[log]\t%s",ref.getLocus());
+ }
+
+ return CoverageUtils.getBaseCountsByPartition(context,minMappingQuality,maxMappingQuality,minBaseQuality,maxBaseQuality,countType,partitionTypes);
+ } else {
+ return null;
+ }
+ }
+
+ public CoveragePartitioner reduce(Map<DoCOutputType.Partition,Map<String,int[]>> thisMap, CoveragePartitioner prevReduce) {
+ if ( thisMap != null ) { // skip sites we didn't want to include in the calculation (ref Ns)
+ if ( ! omitDepthOutput ) {
+ //checkOrder(prevReduce); // tests prevReduce.getIdentifiersByType().get(t) against the initialized header order
+ printDepths(getCorrectStream(null, DoCOutputType.Aggregation.locus, DoCOutputType.FileType.summary),thisMap,prevReduce.getIdentifiersByType());
+ // this is an additional iteration through thisMap, plus dealing with IO, so should be much slower without
+ // turning on omit
+ }
+
+ prevReduce.update(thisMap); // note that in "useBoth" cases, this method alters the thisMap object
+ }
+
+ return prevReduce;
+ }
+
+ public CoveragePartitioner treeReduce(CoveragePartitioner left, CoveragePartitioner right) {
+ left.merge(right);
+ return left;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // INTERVAL ON TRAVERSAL DONE
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ public void onTraversalDone( List<Pair<GenomeLoc, CoveragePartitioner>> statsByInterval ) {
+ if ( refSeqGeneList != null && partitionTypes.contains(DoCOutputType.Partition.sample) ) {
+ printGeneStats(statsByInterval);
+ }
+
+ if ( statsByInterval.size() > 0 ) {
+ for(DoCOutputType.Partition partition: partitionTypes) {
+ if ( checkType(statsByInterval.get(0).getSecond().getCoverageByAggregationType(partition) ,partition) ) {
+ printIntervalStats(statsByInterval,
+ getCorrectStream(partition, DoCOutputType.Aggregation.interval, DoCOutputType.FileType.summary),
+ getCorrectStream(partition, DoCOutputType.Aggregation.interval, DoCOutputType.FileType.statistics),
+ partition);
+ } else {
+ throw new ReviewedGATKException("Partition type "+partition.toString()+" had no entries. Please check that your .bam header has all appropriate partition types.");
+ }
+ }
+ } else {
+ throw new UserException.CommandLineException("Cannot reduce by interval without a list of intervals. Please provide an interval list using the -L argument.");
+ }
+
+ onTraversalDone(mergeAll(statsByInterval));
+
+ }
+
+ public CoveragePartitioner mergeAll(List<Pair<GenomeLoc, CoveragePartitioner>> stats) {
+ CoveragePartitioner first = stats.remove(0).second;
+ for ( Pair<GenomeLoc, CoveragePartitioner> iStat : stats ) {
+ treeReduce(first,iStat.second);
+ }
+
+ return first;
+ }
+
+ private DepthOfCoverageStats printIntervalStats(List<Pair<GenomeLoc, CoveragePartitioner>> statsByInterval, PrintStream summaryOut, PrintStream statsOut, DoCOutputType.Partition type) {
+ Pair<GenomeLoc, CoveragePartitioner> firstPair = statsByInterval.get(0);
+ CoveragePartitioner firstAggregator = firstPair.second;
+ DepthOfCoverageStats firstStats = firstAggregator.getCoverageByAggregationType(type);
+
+ StringBuilder summaryHeader = new StringBuilder();
+ summaryHeader.append("Target");
+ summaryHeader.append(separator);
+ summaryHeader.append("total_coverage");
+ summaryHeader.append(separator);
+ summaryHeader.append("average_coverage");
+
+ for ( String s : firstStats.getAllSamples() ) {
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_total_cvg");
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_mean_cvg");
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_granular_Q1");
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_granular_median");
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_granular_Q3");
+ for ( int thresh : coverageThresholds ) {
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_%_above_");
+ summaryHeader.append(thresh);
+ }
+ }
+
+ summaryOut.printf("%s%n",summaryHeader);
+
+ int[][] nTargetsByAvgCvgBySample = new int[firstStats.getHistograms().size()][firstStats.getEndpoints().length+1];
+
+ for ( Pair<GenomeLoc, CoveragePartitioner> targetAggregator : statsByInterval ) {
+
+ Pair<GenomeLoc,DepthOfCoverageStats> targetStats = new Pair<GenomeLoc,DepthOfCoverageStats>(
+ targetAggregator.first, targetAggregator.second.getCoverageByAggregationType(type));
+ printTargetSummary(summaryOut,targetStats);
+ updateTargetTable(nTargetsByAvgCvgBySample,targetStats.second);
+ }
+
+ printIntervalTable(statsOut,nTargetsByAvgCvgBySample,firstStats.getEndpoints());
+
+ return firstStats;
+ }
+
+ private void printGeneStats(List<Pair<GenomeLoc, CoveragePartitioner>> statsByTarget) {
+ logger.debug("statsByTarget size is "+Integer.toString(statsByTarget.size()));
+ logger.debug("Initializing refseq...");
+ LocationAwareSeekableRODIterator refseqIterator = initializeRefSeq();
+ logger.debug("Refseq init done.");
+ List<Pair<String,DepthOfCoverageStats>> statsByGene = new ArrayList<Pair<String,DepthOfCoverageStats>>();// maintains order
+ Map<String,DepthOfCoverageStats> geneNamesToStats = new HashMap<String,DepthOfCoverageStats>(); // allows indirect updating of objects in list
+
+ for ( Pair<GenomeLoc, CoveragePartitioner> targetStats : statsByTarget ) {
+ String gene = getGeneName(targetStats.first,refseqIterator);
+ if ( geneNamesToStats.keySet().contains(gene) ) {
+ logger.debug("Merging "+geneNamesToStats.get(gene).toString()+" and "+targetStats.second.getCoverageByAggregationType(DoCOutputType.Partition.sample).toString());
+ geneNamesToStats.get(gene).merge(targetStats.second.getCoverageByAggregationType(DoCOutputType.Partition.sample));
+ } else {
+ DepthOfCoverageStats merger = new DepthOfCoverageStats(targetStats.second.getCoverageByAggregationType(DoCOutputType.Partition.sample));
+ geneNamesToStats.put(gene,merger);
+ statsByGene.add(new Pair<String,DepthOfCoverageStats>(gene,merger));
+ }
+ }
+
+ PrintStream geneSummaryOut = getCorrectStream(DoCOutputType.Partition.sample, DoCOutputType.Aggregation.gene, DoCOutputType.FileType.summary);
+ StringBuilder summaryHeader = new StringBuilder();
+ summaryHeader.append("Gene");
+ summaryHeader.append(separator);
+ summaryHeader.append("total_coverage");
+ summaryHeader.append(separator);
+ summaryHeader.append("average_coverage");
+
+ for ( String s : statsByTarget.get(0).second.getCoverageByAggregationType(DoCOutputType.Partition.sample).getAllSamples() ) {
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_total_cvg");
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_mean_cvg");
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_granular_Q1");
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_granular_median");
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_granular_Q3");
+ for ( int thresh : coverageThresholds ) {
+ summaryHeader.append(separator);
+ summaryHeader.append(s);
+ summaryHeader.append("_%_above_");
+ summaryHeader.append(thresh);
+ }
+ }
+
+ geneSummaryOut.printf("%s%n",summaryHeader);
+
+ for ( Pair<String,DepthOfCoverageStats> geneStats : statsByGene ) {
+ printTargetSummary(geneSummaryOut,geneStats);
+ }
+ }
+
+ //blatantly stolen from Andrew Kernytsky
+ private String getGeneName(GenomeLoc target, LocationAwareSeekableRODIterator refseqIterator) {
+ logger.debug("Examining "+target.toString());
+ if (refseqIterator == null) { return "UNKNOWN"; }
+
+ RODRecordList annotationList = refseqIterator.seekForward(target);
+ logger.debug("Annotation list is " + (annotationList == null ? "null" : annotationList.getName()));
+ if (annotationList == null) { return "UNKNOWN"; }
+
+ for(GATKFeature rec : annotationList) {
+ if ( ((RefSeqFeature)rec.getUnderlyingObject()).overlapsExonP(target) ) {
+ logger.debug("We do overlap "+ rec.getUnderlyingObject().toString());
+ return ((RefSeqFeature)rec.getUnderlyingObject()).getGeneName();
+ }
+ logger.debug("No overlap");
+ }
+
+ return "UNKNOWN";
+
+ }
+
+ private LocationAwareSeekableRODIterator initializeRefSeq() {
+ RMDTrackBuilder builder = new RMDTrackBuilder(getToolkit().getReferenceDataSource().getReference().getSequenceDictionary(),
+ getToolkit().getGenomeLocParser(),
+ getToolkit().getArguments().unsafe,
+ getToolkit().getArguments().disableAutoIndexCreationAndLockingWhenReadingRods,
+ null);
+ RMDTrack refseq = builder.createInstanceOfTrack(RefSeqCodec.class,refSeqGeneList);
+ return new SeekableRODIterator(refseq.getHeader(),refseq.getSequenceDictionary(),getToolkit().getReferenceDataSource().getReference().getSequenceDictionary(),
+ getToolkit().getGenomeLocParser(),refseq.getIterator());
+ }
+
+ private void printTargetSummary(PrintStream output, Pair<?,DepthOfCoverageStats> intervalStats) {
+ DepthOfCoverageStats stats = intervalStats.second;
+ int[] bins = stats.getEndpoints();
+
+ StringBuilder targetSummary = new StringBuilder();
+ targetSummary.append(intervalStats.first.toString());
+ targetSummary.append(separator);
+ targetSummary.append(stats.getTotalCoverage());
+ targetSummary.append(separator);
+ targetSummary.append(String.format("%.2f",stats.getTotalMeanCoverage()));
+
+ for ( String s : stats.getAllSamples() ) {
+ targetSummary.append(separator);
+ targetSummary.append(stats.getTotals().get(s));
+ targetSummary.append(separator);
+ targetSummary.append(String.format("%.2f", stats.getMeans().get(s)));
+ targetSummary.append(separator);
+ int median = getQuantile(stats.getHistograms().get(s),0.5);
+ int q1 = getQuantile(stats.getHistograms().get(s),0.25);
+ int q3 = getQuantile(stats.getHistograms().get(s),0.75);
+ targetSummary.append(formatBin(bins,q1));
+ targetSummary.append(separator);
+ targetSummary.append(formatBin(bins,median));
+ targetSummary.append(separator);
+ targetSummary.append(formatBin(bins,q3));
+ for ( int thresh : coverageThresholds ) {
+ targetSummary.append(String.format("%s%.1f",separator,getPctBasesAbove(stats.getHistograms().get(s),stats.value2bin(thresh))));
+ }
+
+ }
+
+ output.printf("%s%n", targetSummary);
+ }
+
+ private String formatBin(int[] bins, int quartile) {
+ if ( quartile >= bins.length ) {
+ return String.format(">%d",bins[bins.length-1]);
+ } else if ( quartile < 0 ) {
+ return String.format("<%d",bins[0]);
+ } else {
+ return String.format("%d",bins[quartile]);
+ }
+ }
+
+ private void printIntervalTable(PrintStream output, int[][] intervalTable, int[] cutoffs) {
+ String colHeader = outputFormat.equals("rtable") ? "" : "Number_of_sources";
+ output.printf(colHeader + separator+"depth>=%d",0);
+ for ( int col = 0; col < intervalTable[0].length-1; col ++ ) {
+ output.printf(separator+"depth>=%d",cutoffs[col]);
+ }
+
+ output.printf(String.format("%n"));
+ for ( int row = 0; row < intervalTable.length; row ++ ) {
+ output.printf("At_least_%d_samples",row+1);
+ for ( int col = 0; col < intervalTable[0].length; col++ ) {
+ output.printf(separator+"%d",intervalTable[row][col]);
+ }
+ output.printf(String.format("%n"));
+ }
+ }
+
+ /*
+ * @updateTargetTable
+ * The idea is to have counts for how many *targets* have at least K samples with
+ * median coverage of at least X.
+ * To that end:
+ * Iterate over the samples the DOCS object, determine how many there are with
+ * median coverage > leftEnds[0]; how many with median coverage > leftEnds[1]
+ * and so on. Then this target has at least N, N-1, N-2, ... 1, 0 samples covered
+ * to leftEnds[0] and at least M,M-1,M-2,...1,0 samples covered to leftEnds[1]
+ * and so on.
+ */
+ private void updateTargetTable(int[][] table, DepthOfCoverageStats stats) {
+ int[] cutoffs = stats.getEndpoints();
+ int[] countsOfMediansAboveCutoffs = new int[cutoffs.length+1]; // 0 bin to catch everything
+ for ( int i = 0; i < countsOfMediansAboveCutoffs.length; i ++) {
+ countsOfMediansAboveCutoffs[i]=0;
+ }
+
+ for ( String s : stats.getAllSamples() ) {
+ int medianBin = getQuantile(stats.getHistograms().get(s),0.5);
+ for ( int i = 0; i <= medianBin; i ++) {
+ countsOfMediansAboveCutoffs[i]++;
+ }
+ }
+
+ for ( int medianBin = 0; medianBin < countsOfMediansAboveCutoffs.length; medianBin++) {
+ for ( ; countsOfMediansAboveCutoffs[medianBin] > 0; countsOfMediansAboveCutoffs[medianBin]-- ) {
+ table[countsOfMediansAboveCutoffs[medianBin]-1][medianBin]++;
+ // the -1 is due to counts being 1-based and offsets being 0-based
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // FINAL ON TRAVERSAL DONE
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ public void onTraversalDone(CoveragePartitioner coverageProfiles) {
+ ///////////////////
+ // OPTIONAL OUTPUTS
+ //////////////////
+
+ if ( ! omitSampleSummary ) {
+ logger.info("Printing summary info");
+ for (DoCOutputType.Partition type : partitionTypes ) {
+ outputSummaryFiles(coverageProfiles,type);
+ }
+ }
+
+ if ( ! omitLocusTable ) {
+ logger.info("Printing locus summary");
+ for (DoCOutputType.Partition type : partitionTypes ) {
+ outputLocusFiles(coverageProfiles,type);
+ }
+ }
+ }
+
+ private void outputLocusFiles(CoveragePartitioner coverageProfiles, DoCOutputType.Partition type ) {
+ printPerLocus(getCorrectStream(type, DoCOutputType.Aggregation.cumulative, DoCOutputType.FileType.coverage_counts),
+ getCorrectStream(type, DoCOutputType.Aggregation.cumulative, DoCOutputType.FileType.coverage_proportions),
+ coverageProfiles.getCoverageByAggregationType(type),type);
+ }
+
+ private void outputSummaryFiles(CoveragePartitioner coverageProfiles, DoCOutputType.Partition type ) {
+ printPerSample(getCorrectStream(type, DoCOutputType.Aggregation.cumulative, DoCOutputType.FileType.statistics),coverageProfiles.getCoverageByAggregationType(type));
+ printSummary(getCorrectStream(type, DoCOutputType.Aggregation.cumulative, DoCOutputType.FileType.summary),coverageProfiles.getCoverageByAggregationType(type));
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // HELPER OUTPUT METHODS
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ private void printPerSample(PrintStream output,DepthOfCoverageStats stats) {
+ int[] leftEnds = stats.getEndpoints();
+
+ StringBuilder hBuilder = new StringBuilder();
+ if ( ! outputFormat.equals("rTable")) {
+ hBuilder.append("Source_of_reads");
+ }
+ hBuilder.append(separator);
+ hBuilder.append(String.format("from_0_to_%d)%s",leftEnds[0],separator));
+ for ( int i = 1; i < leftEnds.length; i++ )
+ hBuilder.append(String.format("from_%d_to_%d)%s",leftEnds[i-1],leftEnds[i],separator));
+ hBuilder.append(String.format("from_%d_to_inf%n",leftEnds[leftEnds.length-1]));
+ output.print(hBuilder.toString());
+ Map<String,long[]> histograms = stats.getHistograms();
+
+ for ( Map.Entry<String, long[]> p : histograms.entrySet() ) {
+ StringBuilder sBuilder = new StringBuilder();
+ sBuilder.append(String.format("sample_%s",p.getKey()));
+ for ( long count : p.getValue() ) {
+ sBuilder.append(String.format("%s%d",separator,count));
+ }
+ sBuilder.append(String.format("%n"));
+ output.print(sBuilder.toString());
+ }
+ }
+
+ private void printPerLocus(PrintStream output, PrintStream coverageOut, DepthOfCoverageStats stats, DoCOutputType.Partition partitionType) {
+ int[] endpoints = stats.getEndpoints();
+ int samples = stats.getHistograms().size();
+
+ long[][] baseCoverageCumDist = stats.getLocusCounts();
+
+ // rows - # of samples
+ // columns - depth of coverage
+
+ boolean printSampleColumnHeader = outputFormat.equals("csv") || outputFormat.equals("table");
+
+ StringBuilder header = new StringBuilder();
+ if ( printSampleColumnHeader ) {
+ // mhanna 22 Aug 2010 - Deliberately force this header replacement to make sure integration tests pass.
+ // TODO: Update integration tests and get rid of this.
+ header.append(partitionType == DoCOutputType.Partition.readgroup ? "read_group" : partitionType.toString());
+ }
+ header.append(String.format("%sgte_0",separator));
+ for ( int d : endpoints ) {
+ header.append(String.format("%sgte_%d",separator,d));
+ }
+ header.append(String.format("%n"));
+
+ output.print(header);
+ coverageOut.print(header);
+
+ for ( int row = 0; row < samples; row ++ ) {
+ output.printf("%s_%d","NSamples",row+1);
+ for ( int depthBin = 0; depthBin < baseCoverageCumDist[0].length; depthBin ++ ) {
+ output.printf("%s%d",separator,baseCoverageCumDist[row][depthBin]);
+ }
+ output.printf("%n");
+ }
+
+ for ( String sample : stats.getAllSamples() ) {
+ coverageOut.printf("%s",sample);
+ double[] coverageDistribution = stats.getCoverageProportions(sample);
+ for ( int bin = 0; bin < coverageDistribution.length; bin ++ ) {
+ coverageOut.printf("%s%.2f",separator,coverageDistribution[bin]);
+ }
+ coverageOut.printf("%n");
+ }
+ }
+
+ private PrintStream getCorrectStream(DoCOutputType.Partition partition, DoCOutputType.Aggregation aggregation, DoCOutputType.FileType fileType) {
+ DoCOutputType outputType = new DoCOutputType(partition,aggregation,fileType);
+ if(!out.containsKey(outputType))
+ throw new UserException.CommandLineException(String.format("Unable to find appropriate stream for partition = %s, aggregation = %s, file type = %s",partition,aggregation,fileType));
+ return out.get(outputType);
+ }
+
+ private void printSummary(PrintStream output, DepthOfCoverageStats stats) {
+ if ( ! outputFormat.equals("csv") ) {
+ output.printf("%s\t%s\t%s\t%s\t%s\t%s","sample_id","total","mean","granular_third_quartile","granular_median","granular_first_quartile");
+ } else {
+ output.printf("%s,%s,%s,%s,%s,%s","sample_id","total","mean","granular_third_quartile","granular_median","granular_first_quartile");
+ }
+
+ for ( int thresh : coverageThresholds ) {
+ output.printf("%s%s%d",separator,"%_bases_above_",thresh);
+ }
+
+ output.printf("%n");
+
+ Map<String,long[]> histograms = stats.getHistograms();
+ Map<String,Double> means = stats.getMeans();
+ Map<String,Long> totals = stats.getTotals();
+ int[] leftEnds = stats.getEndpoints();
+
+ for ( Map.Entry<String, long[]> p : histograms.entrySet() ) {
+ String s = p.getKey();
+ long[] histogram = p.getValue();
+ int median = getQuantile(histogram,0.5);
+ int q1 = getQuantile(histogram,0.25);
+ int q3 = getQuantile(histogram,0.75);
+ // if any of these are larger than the higest bin, put the median as in the largest bin
+ median = median == histogram.length-1 ? histogram.length-2 : median;
+ q1 = q1 == histogram.length-1 ? histogram.length-2 : q1;
+ q3 = q3 == histogram.length-1 ? histogram.length-2 : q3;
+ if ( ! outputFormat.equals("csv") ) {
+ output.printf("%s\t%d\t%.2f\t%d\t%d\t%d",s,totals.get(s),means.get(s),leftEnds[q3],leftEnds[median],leftEnds[q1]);
+ } else {
+ output.printf("%s,%d,%.2f,%d,%d,%d",s,totals.get(s),means.get(s),leftEnds[q3],leftEnds[median],leftEnds[q1]);
+ }
+
+ for ( int thresh : coverageThresholds ) {
+ output.printf("%s%.1f",separator,getPctBasesAbove(histogram,stats.value2bin(thresh)));
+ }
+
+ output.printf("%n");
+ }
+
+ if ( ! outputFormat.equals("csv") ) {
+ output.printf("%s\t%d\t%.2f\t%s\t%s\t%s%n","Total",stats.getTotalCoverage(),stats.getTotalMeanCoverage(),"N/A","N/A","N/A");
+ } else {
+ output.printf("%s,%d,%.2f,%s,%s,%s%n","Total",stats.getTotalCoverage(),stats.getTotalMeanCoverage(),"N/A","N/A","N/A");
+ }
+ }
+
+ private int getQuantile(long[] histogram, double prop) {
+ int total = 0;
+
+ for ( int i = 0; i < histogram.length; i ++ ) {
+ total += histogram[i];
+ }
+
+ int counts = 0;
+ int bin = -1;
+ while ( counts < prop*total ) {
+ counts += histogram[bin+1];
+ bin++;
+ }
+
+ return bin == -1 ? 0 : bin;
+ }
+
+ private double getPctBasesAbove(long[] histogram, int bin) {
+ long below = 0l;
+ long above = 0l;
+ for ( int index = 0; index < histogram.length; index++) {
+ if ( index < bin ) {
+ below+=histogram[index];
+ } else {
+ above+=histogram[index];
+ }
+ }
+
+ return 100*( (double) above )/( above + below );
+ }
+
+ private void printDepths(PrintStream stream, Map<DoCOutputType.Partition,Map<String,int[]>> countsBySampleByType, Map<DoCOutputType.Partition,List<String>> identifiersByType) {
+ // get the depths per sample and build up the output string while tabulating total and average coverage
+ StringBuilder perSampleOutput = new StringBuilder();
+ int tDepth = 0;
+ boolean depthCounted = false;
+ for (DoCOutputType.Partition type : partitionTypes ) {
+ Map<String,int[]> countsByID = countsBySampleByType.get(type);
+ for ( String s : identifiersByType.get(type) ) {
+ perSampleOutput.append(separator);
+ long dp = (countsByID != null && countsByID.keySet().contains(s)) ? sumArray(countsByID.get(s)) : 0 ;
+ perSampleOutput.append(dp);
+ if ( printBaseCounts ) {
+ perSampleOutput.append(separator);
+ perSampleOutput.append(baseCounts(countsByID != null ? countsByID.get(s) : null ));
+ }
+ if ( ! depthCounted ) {
+ tDepth += dp;
+ }
+ }
+ depthCounted = true; // only sum the total depth once
+ }
+
+ // remember -- genome locus was printed in map()
+ stream.printf("%s%d",separator,tDepth);
+ for (DoCOutputType.Partition type : partitionTypes ) {
+ stream.printf("%s%.2f",separator, ( (double) tDepth / identifiersByType.get(type).size() ) );
+ }
+ stream.printf("%s%n",perSampleOutput);
+ }
+
+ private long sumArray(int[] array) {
+ long i = 0;
+ for ( int j : array ) {
+ i += j;
+ }
+ return i;
+ }
+
+ private String baseCounts(int[] counts) {
+ if ( counts == null ) {
+ counts = new int[6];
+ }
+ StringBuilder s = new StringBuilder();
+ int nbases = 0;
+ for ( byte b : BaseUtils.EXTENDED_BASES ) {
+ nbases++;
+ if ( includeDeletions || b != BaseUtils.Base.D.base ) {
+ s.append((char)b);
+ s.append(":");
+ s.append(counts[BaseUtils.extendedBaseToBaseIndex(b)]);
+ if ( nbases < 6 ) {
+ s.append(" ");
+ }
+ }
+ }
+
+ return s.toString();
+ }
+
+ private void checkOrder(CoveragePartitioner ag) {
+ // make sure the ordering stored at initialize() is propagated along reduce
+ for (DoCOutputType.Partition t : partitionTypes ) {
+ List<String> order = orderCheck.get(t);
+ List<String> namesInAg = ag.getIdentifiersByType().get(t);
+
+ // todo -- chris check me
+ Set<String> namesInDOCS = ag.getCoverageByAggregationType(t).getAllSamples();
+ int index = 0;
+ for ( String s : namesInAg ) {
+ if ( ! s.equalsIgnoreCase(order.get(index)) ) {
+ throw new ReviewedGATKException("IDs are out of order for type "+t+"! Aggregator has different ordering");
+ }
+ index++;
+ }
+ }
+ }
+
+ public boolean checkType(DepthOfCoverageStats stats, DoCOutputType.Partition type ) {
+ if ( stats.getHistograms().size() < 1 ) {
+ logger.warn("The histogram per partition type "+type.toString()+" was empty\n"+
+ "Do your read groups have this type? (Check your .bam header).");
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+}
+
+class DoCOutputMultiplexer implements Multiplexer<DoCOutputType> {
+ private final Set<DoCOutputType.Partition> partitions;
+ private final File refSeqGeneList;
+ private final boolean omitDepthOutput;
+ private final boolean omitIntervals;
+ private final boolean omitSampleSummary;
+ private final boolean omitLocusTable;
+
+ /**
+ * Create a new multiplexer type using the values of all variable fields.
+ * @param partitions
+ * @param refSeqGeneList
+ * @param omitDepthOutput
+ * @param omitIntervals
+ * @param omitSampleSummary
+ * @param omitLocusTable
+ */
+ public DoCOutputMultiplexer(final Set<DoCOutputType.Partition> partitions,
+ final File refSeqGeneList,
+ final boolean omitDepthOutput,
+ final boolean omitIntervals,
+ final boolean omitSampleSummary,
+ final boolean omitLocusTable) {
+ this.partitions = partitions;
+ this.refSeqGeneList = refSeqGeneList;
+ this.omitDepthOutput = omitDepthOutput;
+ this.omitIntervals = omitIntervals;
+ this.omitSampleSummary = omitSampleSummary;
+ this.omitLocusTable = omitLocusTable;
+ }
+
+ public Collection<DoCOutputType> multiplex() {
+ List<DoCOutputType> outputs = new ArrayList<DoCOutputType>();
+ if(!omitDepthOutput) outputs.add(new DoCOutputType(null, DoCOutputType.Aggregation.locus, DoCOutputType.FileType.summary));
+
+ if(!omitIntervals) {
+ for(DoCOutputType.Partition partition: partitions) {
+ outputs.add(new DoCOutputType(partition, DoCOutputType.Aggregation.interval, DoCOutputType.FileType.summary));
+ outputs.add(new DoCOutputType(partition, DoCOutputType.Aggregation.interval, DoCOutputType.FileType.statistics));
+ }
+ }
+
+ if(refSeqGeneList != null && partitions.contains(DoCOutputType.Partition.sample)) {
+ DoCOutputType geneSummaryOut = new DoCOutputType(DoCOutputType.Partition.sample, DoCOutputType.Aggregation.gene, DoCOutputType.FileType.summary);
+ outputs.add(geneSummaryOut);
+ }
+
+ if(!omitSampleSummary) {
+ for(DoCOutputType.Partition partition: partitions) {
+ outputs.add(new DoCOutputType(partition, DoCOutputType.Aggregation.cumulative, DoCOutputType.FileType.summary));
+ outputs.add(new DoCOutputType(partition, DoCOutputType.Aggregation.cumulative, DoCOutputType.FileType.statistics));
+ }
+ }
+
+ if(!omitLocusTable) {
+ for(DoCOutputType.Partition partition: partitions) {
+ outputs.add(new DoCOutputType(partition, DoCOutputType.Aggregation.cumulative, DoCOutputType.FileType.coverage_counts));
+ outputs.add(new DoCOutputType(partition, DoCOutputType.Aggregation.cumulative, DoCOutputType.FileType.coverage_proportions));
+ }
+ }
+
+ return outputs;
+ }
+
+ public String transformArgument(final DoCOutputType outputType, final String argument) {
+ return outputType.getFileName(argument);
+ }
+
+}
+
+class CoveragePartitioner {
+ private Collection<DoCOutputType.Partition> types;
+ private Map<DoCOutputType.Partition,DepthOfCoverageStats> coverageProfiles;
+ private Map<DoCOutputType.Partition,List<String>> identifiersByType;
+ private Set<String> allIdentifiers;
+ public CoveragePartitioner(Collection<DoCOutputType.Partition> typesToUse, int start, int stop, int nBins) {
+ coverageProfiles = new TreeMap<DoCOutputType.Partition,DepthOfCoverageStats>();
+ identifiersByType = new HashMap<DoCOutputType.Partition,List<String>>();
+ types = typesToUse;
+ for ( DoCOutputType.Partition type : types ) {
+ coverageProfiles.put(type,new DepthOfCoverageStats(DepthOfCoverageStats.calculateBinEndpoints(start,stop,nBins)));
+ identifiersByType.put(type,new ArrayList<String>());
+ }
+ allIdentifiers = new HashSet<String>();
+ }
+
+ public void merge(CoveragePartitioner otherAggregator) {
+ for ( DoCOutputType.Partition type : types ) {
+ this.coverageProfiles.get(type).merge(otherAggregator.coverageProfiles.get(type));
+ }
+ }
+
+ public DepthOfCoverageStats getCoverageByAggregationType(DoCOutputType.Partition t) {
+ return coverageProfiles.get(t);
+ }
+
+ public void addIdentifiers(DoCOutputType.Partition t, Set<String> ids) {
+ for ( String s : ids ) {
+ coverageProfiles.get(t).addSample(s);
+ identifiersByType.get(t).add(s);
+ allIdentifiers.add(s);
+ }
+ Collections.sort(identifiersByType.get(t));
+ }
+
+ public void initialize(boolean useDels, boolean omitLocusTable) {
+ for ( DoCOutputType.Partition t : types ) {
+ if ( useDels ) {
+ coverageProfiles.get(t).initializeDeletions();
+ }
+ if ( ! omitLocusTable ) {
+ coverageProfiles.get(t).initializeLocusCounts();
+ }
+ }
+ }
+
+ public void update(Map<DoCOutputType.Partition,Map<String,int[]>> countsByIdentifierByType) {
+ for ( DoCOutputType.Partition t : types ) {
+ coverageProfiles.get(t).update(countsByIdentifierByType.get(t));
+ }
+ }
+
+ public Set<String> getAllIdentifiers() {
+ return allIdentifiers;
+ }
+
+ public Map<DoCOutputType.Partition,List<String>> getIdentifiersByType() {
+ return identifiersByType;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverageStats.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverageStats.java
new file mode 100644
index 0000000..c8a4356
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverageStats.java
@@ -0,0 +1,352 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.coverage;
+
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * IF THERE IS NO JAVADOC RIGHT HERE, YELL AT chartl
+ *
+ * @Author chartl
+ * @Date Feb 26, 2010
+ */
+public class DepthOfCoverageStats {
+ ////////////////////////////////////////////////////////////////////////////////////
+ // STATIC DATA
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ /* none so far */
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // STANDARD DATA
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ private Map<String,long[]> granularHistogramBySample; // holds the counts per each bin
+ private Map<String,Long> totalCoverages; // holds total coverage per sample
+ private int[] binLeftEndpoints; // describes the left endpoint for each bin
+ private long[][] locusCoverageCounts; // holds counts of number of bases with >=X samples at >=Y coverage
+ private boolean tabulateLocusCounts = false;
+ private long nLoci; // number of loci seen
+ private long totalDepthOfCoverage;
+ private boolean includeDeletions = false;
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // TEMPORARY DATA ( not worth re-instantiating )
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ private int[] locusHistogram; // holds a histogram for each locus; reset after each update() call
+ private int totalLocusDepth; // holds the total depth of coverage for each locus; reset after each update() call
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // STATIC METHODS
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ public static int[] calculateBinEndpoints(int lower, int upper, int bins) {
+ if ( bins > upper - lower || lower < 1 ) {
+ throw new UserException.BadInput("the start must be at least 1 and the number of bins may not exceed stop - start");
+ }
+
+ int[] binLeftEndpoints = new int[bins+1];
+ binLeftEndpoints[0] = lower;
+
+ int length = upper - lower;
+ double scale = Math.log10((double) length)/bins;
+
+ for ( int b = 1; b < bins ; b++ ) {
+ int leftEnd = lower + (int) Math.floor(Math.pow(10.0,(b-1.0)*scale));
+ // todo -- simplify to length^(scale/bins); make non-constant to put bin ends in more "useful"
+ // todo -- positions on the number line
+ while ( leftEnd <= binLeftEndpoints[b-1] ) {
+ leftEnd++;
+ }
+
+ binLeftEndpoints[b] = leftEnd;
+ }
+
+ binLeftEndpoints[binLeftEndpoints.length-1] = upper;
+
+ return binLeftEndpoints;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // INITIALIZATION METHODS
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ public DepthOfCoverageStats(int[] leftEndpoints) {
+ this.binLeftEndpoints = leftEndpoints;
+ granularHistogramBySample = new HashMap<String,long[]>();
+ totalCoverages = new HashMap<String,Long>();
+ nLoci = 0;
+ totalLocusDepth = 0;
+ totalDepthOfCoverage = 0;
+ }
+
+ public DepthOfCoverageStats(DepthOfCoverageStats cloneMe) {
+ this.binLeftEndpoints = cloneMe.binLeftEndpoints;
+ granularHistogramBySample = new TreeMap<String,long[]>();
+ totalCoverages = new TreeMap<String,Long>();
+ for ( String s : cloneMe.getAllSamples() ) {
+ granularHistogramBySample.put(s,new long[cloneMe.getHistograms().get(s).length]);
+ for ( int i = 0; i < granularHistogramBySample.get(s).length; i++ ) {
+ granularHistogramBySample.get(s)[i] = cloneMe.getHistograms().get(s)[i];
+ }
+ totalCoverages.put(s,cloneMe.totalCoverages.get(s));
+ }
+
+ this.includeDeletions = cloneMe.includeDeletions;
+ if ( cloneMe.tabulateLocusCounts ) {
+ this.locusCoverageCounts = new long[cloneMe.locusCoverageCounts.length][cloneMe.locusCoverageCounts[0].length];
+ }
+ //this.granularHistogramBySample = cloneMe.granularHistogramBySample;
+ //this.totalCoverages = cloneMe.totalCoverages;
+ this.nLoci = cloneMe.nLoci;
+ this.totalDepthOfCoverage = cloneMe.totalDepthOfCoverage;
+ this.tabulateLocusCounts = cloneMe.tabulateLocusCounts;
+ }
+
+ public void addSample(String sample) {
+ if ( granularHistogramBySample.containsKey(sample) ) {
+ return;
+ }
+
+ long[] binCounts = new long[this.binLeftEndpoints.length+1];
+ for ( int b = 0; b < binCounts.length; b ++ ) {
+ binCounts[b] = 0;
+ }
+
+ granularHistogramBySample.put(sample,binCounts);
+ totalCoverages.put(sample,0l);
+ }
+
+ public void initializeLocusCounts() {
+ locusCoverageCounts = new long[granularHistogramBySample.size()][binLeftEndpoints.length+1];
+ locusHistogram = new int[binLeftEndpoints.length+1];
+ for ( int b = 0; b < binLeftEndpoints.length+1; b ++ ) {
+ for ( int a = 0; a < granularHistogramBySample.size(); a ++ ) {
+ locusCoverageCounts[a][b] = 0;
+ }
+ locusHistogram[b] = 0;
+ }
+
+ tabulateLocusCounts = true;
+ }
+
+ public void initializeDeletions() {
+ includeDeletions = true;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // UPDATE METHODS
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ public void updateDepths(Map<String,Integer> depthBySample) {
+ int b;
+ for ( String sample : granularHistogramBySample.keySet() ) {
+ if ( depthBySample.containsKey(sample) ) {
+ b = updateSample(sample,depthBySample.get(sample));
+ totalLocusDepth += depthBySample.get(sample);
+ } else {
+ b = updateSample(sample,0);
+ }
+
+ if ( tabulateLocusCounts ) {
+ for ( int i = 0; i <= b; i ++ ) {
+ locusHistogram[i]++;
+ }
+ }
+ }
+ updateLocusCounts(locusHistogram);
+
+ nLoci++;
+ totalDepthOfCoverage += totalLocusDepth;
+ totalLocusDepth = 0;
+ }
+
+ public void update(Map<String,int[]> countsBySample) {
+ if ( countsBySample == null ) {
+ this.updateDepths(new HashMap<String,Integer>(1));
+ return;
+ }
+ // todo -- do we want to do anything special regarding base count or deletion statistics?
+ HashMap<String,Integer> depthBySample = new HashMap<String,Integer>();
+ // todo -- needs fixing with advent of new baseutils functionality using ENUMS and handling N,D
+ for ( String s : countsBySample.keySet() ) {
+ int total = 0;
+ int[] counts = countsBySample.get(s);
+ for ( byte base : BaseUtils.EXTENDED_BASES ) {
+ if ( includeDeletions || ! ( base == BaseUtils.Base.D.base) ) { // note basesAreEqual assigns TRUE to (N,D) as both have simple index -1
+ total += counts[BaseUtils.extendedBaseToBaseIndex(base)];
+ }
+ }
+ depthBySample.put(s,total);
+ }
+
+ this.updateDepths(depthBySample);
+ }
+
+ private int updateSample(String sample, int depth) {
+ totalCoverages.put(sample,totalCoverages.get(sample)+depth);
+
+ long[] granularBins = granularHistogramBySample.get(sample);
+ for ( int b = 0; b < binLeftEndpoints.length; b ++ ) {
+ if ( depth < binLeftEndpoints[b] ) {
+ granularBins[b]++;
+ return b;
+ }
+ }
+
+ granularBins[binLeftEndpoints.length]++; // greater than all left-endpoints
+ return binLeftEndpoints.length;
+ }
+
+ public void merge(DepthOfCoverageStats newStats) {
+ this.mergeSamples(newStats);
+ if ( this.tabulateLocusCounts && newStats.tabulateLocusCounts ) {
+ this.mergeLocusCounts(newStats.getLocusCounts());
+ }
+ nLoci += newStats.getTotalLoci();
+ totalDepthOfCoverage += newStats.getTotalCoverage();
+ }
+
+ private void mergeSamples(DepthOfCoverageStats otherStats) {
+ Map<String,long[]> otherHistogram = otherStats.getHistograms();
+ Map<String,Double> otherMeans = otherStats.getMeans();
+ for ( String s : this.getAllSamples() ) {
+ long[] internalCounts = granularHistogramBySample.get(s);
+ long[] externalCounts = otherHistogram.get(s);
+ for ( int b = 0; b < internalCounts.length; b++ ) {
+ internalCounts[b] += externalCounts[b];
+ }
+
+ this.totalCoverages.put(s, this.totalCoverages.get(s) + otherStats.totalCoverages.get(s));
+ }
+ }
+
+ private void mergeLocusCounts( long[][] otherCounts ) {
+ for ( int a = 0; a < locusCoverageCounts.length; a ++ ) {
+ for ( int b = 0; b < locusCoverageCounts[0].length; b ++ ) {
+ locusCoverageCounts[a][b] += otherCounts[a][b];
+ }
+ }
+ }
+
+ /*
+ * Update locus counts -- takes an array in which the number of samples
+ * with depth ABOVE [i] is held. So if the bin left endpoints were 2, 5, 10
+ * then we'd have an array that represented:
+ * [# samples with depth 0 - inf], [# samples with depth 2 - inf],
+ * [# samples with depth 5 - inf], [# samples with depth 10-inf];
+ *
+ * this is
+ * @argument cumulativeSamplesByDepthBin - see above
+ */
+ private void updateLocusCounts(int[] cumulativeSamplesByDepthBin) {
+ if ( tabulateLocusCounts ) {
+ for ( int bin = 0; bin < cumulativeSamplesByDepthBin.length; bin ++ ) {
+ int numSamples = cumulativeSamplesByDepthBin[bin];
+ for ( int i = 0; i < numSamples; i ++ ) {
+ locusCoverageCounts[i][bin]++;
+ }
+
+ cumulativeSamplesByDepthBin[bin] = 0; // reset counts in advance of next update()
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // ACCESSOR METHODS
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ public Map<String,long[]> getHistograms() {
+ return granularHistogramBySample;
+ }
+
+ public long[][] getLocusCounts() {
+ return locusCoverageCounts;
+ }
+
+ public int[] getEndpoints() {
+ return binLeftEndpoints;
+ }
+
+ public Map<String,Double> getMeans() {
+ HashMap<String,Double> means = new HashMap<String,Double>();
+ for ( String s : getAllSamples() ) {
+ means.put(s,( (double)totalCoverages.get(s))/( (double) nLoci ));
+ }
+
+ return means;
+ }
+
+ public Map<String,Long> getTotals() {
+ return totalCoverages;
+ }
+
+ public long getTotalLoci() {
+ return nLoci;
+ }
+
+ public Set<String> getAllSamples() {
+ return granularHistogramBySample.keySet();
+ }
+
+ public double getTotalMeanCoverage() {
+ return ( (double) totalDepthOfCoverage )/ ( (double) nLoci );
+ }
+
+ public long getTotalCoverage() {
+ return totalDepthOfCoverage;
+ }
+
+ public double[] getCoverageProportions(String sample) {
+ long[] hist = granularHistogramBySample.get(sample);
+ double[] distribution = new double[hist.length];
+ long count = 0;
+ for ( int i = hist.length-1; i >= 0; i -- ) {
+ count += hist[i];
+ distribution[i] = ( (double) count) / nLoci;
+ }
+
+ return distribution;
+ }
+
+ public int value2bin(int value) {
+ for ( int index = 0; index < binLeftEndpoints.length; index++ ) {
+ if ( binLeftEndpoints[index] > value ) {
+ return index;
+ }
+ }
+
+ return binLeftEndpoints.length-1;
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/DoCOutputType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/DoCOutputType.java
new file mode 100644
index 0000000..6e2266d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/DoCOutputType.java
@@ -0,0 +1,89 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.coverage;
+
+/**
+ * Models a single output file in the DoC walker.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class DoCOutputType {
+ public enum Partition { readgroup, sample, library, platform, center, sample_by_platform, sample_by_center, sample_by_platform_by_center }
+ public enum Aggregation { locus, interval, gene, cumulative }
+ public enum FileType { summary, statistics, coverage_counts, coverage_proportions }
+
+ private final Partition partition;
+ private final Aggregation aggregation;
+ private final FileType fileType;
+
+ public DoCOutputType(final Partition partition,
+ final Aggregation aggregation,
+ final FileType fileType) {
+ this.partition = partition;
+ this.aggregation = aggregation;
+ this.fileType = fileType;
+ }
+
+ public String getFileName(final String baseName) {
+ // main output
+ if(partition == null)
+ return baseName;
+
+ if(baseName.trim().equals("/dev/null"))
+ return "/dev/null";
+
+ // mhanna 22 Aug 2010 - Deliberately force this header replacement to make sure integration tests pass.
+ // TODO: Update integration tests and get rid of this.
+ String partitionType = (partition == DoCOutputType.Partition.readgroup ? "read_group" : partition.toString());
+
+ if(fileType == FileType.coverage_counts || fileType == FileType.coverage_proportions) {
+ // coverage counts / proportions files always include aggregation.
+ return baseName + "." +
+ partitionType + "_" +
+ aggregation + "_" +
+ fileType;
+ }
+
+ return baseName + "." +
+ partitionType + "_" +
+ (aggregation == Aggregation.interval || aggregation == Aggregation.gene ? aggregation + "_" : "") +
+ fileType;
+ }
+
+ public int hashCode() {
+ return (partition!=null?partition.ordinal()+1:0) * aggregation.ordinal() * fileType.ordinal();
+ }
+
+ public boolean equals(Object other) {
+ if(!(other instanceof DoCOutputType))
+ return false;
+ DoCOutputType otherOutputType = (DoCOutputType)other;
+ return partition == otherOutputType.partition &&
+ aggregation == otherOutputType.aggregation &&
+ fileType == otherOutputType.fileType;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/GCContentByInterval.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/GCContentByInterval.java
new file mode 100644
index 0000000..a23cfe3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/coverage/GCContentByInterval.java
@@ -0,0 +1,106 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.coverage;
+
+import org.broadinstitute.gatk.engine.walkers.*;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.io.PrintStream;
+import java.util.List;
+
+/**
+ * Walks along reference and calculates the GC content for each interval.
+ *
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A reference file
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * GC content calculations per interval.
+ * </p>
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -T GCContentByInterval \
+ * -R ref.fasta \
+ * -o output.txt \
+ * -L input.intervals
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+ at Allows(value = {DataSource.REFERENCE})
+ at Requires(value = {DataSource.REFERENCE})
+ at By(DataSource.REFERENCE)
+public class GCContentByInterval extends LocusWalker<Long, Long> {
+ @Output
+ protected PrintStream out;
+
+ public boolean isReduceByInterval() {
+ return true;
+ }
+
+ public void initialize() {
+ }
+
+ public Long reduceInit() {
+ return 0L;
+ }
+
+ public Long map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if (tracker == null)
+ return null;
+ int baseIndex = ref.getBaseIndex();
+ return (baseIndex == BaseUtils.Base.G.ordinal() || baseIndex == BaseUtils.Base.C.ordinal()) ? 1L : 0L;
+ }
+
+ public Long reduce(Long toAdd, Long runningCount) {
+ return runningCount + toAdd;
+ }
+
+ public void onTraversalDone(List<Pair<GenomeLoc, Long>> results) {
+ for (Pair<GenomeLoc, Long> result : results ) {
+ GenomeLoc loc = result.getFirst();
+ Long gcCount = result.getSecond();
+
+ double gcContent = (double) gcCount / loc.size();
+ out.println(loc + "\t" + gcContent);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/CoveredByNSamplesSites.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/CoveredByNSamplesSites.java
new file mode 100644
index 0000000..370cea2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/CoveredByNSamplesSites.java
@@ -0,0 +1,154 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.diagnostics;
+
+
+import org.broadinstitute.gatk.engine.walkers.By;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.ArgumentCollection;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.GenotypesContext;
+import htsjdk.variant.variantcontext.VariantContext;
+
+
+import java.io.*;
+import java.util.Collection;
+
+/**
+ * Print intervals file with all the variant sites for which most of the samples have good coverage
+ *
+ * <p>
+ * CoveredByNSamplesSites is a GATK tool for filtering out sites based on their coverage.
+ * The sites that pass the filter are printed out to an intervals file.
+ *
+ * See argument defaults for what constitutes "most" samples and "good" coverage. These parameters can be modified from the command line.
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A variant file and optionally min coverage and sample percentage values.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * An intervals file.
+ * </p>
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T CoveredByNSamplesSites \
+ * -V input.vcf \
+ * -out output.intervals \
+ * -minCov 15
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+ at By(DataSource.REFERENCE_ORDERED_DATA)
+public class CoveredByNSamplesSites extends RodWalker<GenomeLoc, Integer> implements TreeReducible<Integer> {
+
+ @Output(fullName = "OutputIntervals", shortName = "out", doc = "Name of file for output intervals")
+ PrintStream outputStream;
+
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ @Argument(fullName = "minCoverage", shortName = "minCov",doc = "only samples that have coverage bigger than minCoverage will be counted",required = false)
+ int minCoverage = 10;
+
+ @Argument(fullName = "percentageOfSamples", shortName = "percentage", doc = "only sites where at least percentageOfSamples of the samples have good coverage, will be emitted", required = false)
+ double percentageOfSamples = 0.9;
+
+ @Override
+ public GenomeLoc map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null )
+ return null;
+
+ Collection<VariantContext> VCs = tracker.getValues(variantCollection.variants, context.getLocation());
+ if ( VCs.size() == 0 )
+ return null;
+
+ boolean emitSite = false;
+ for(VariantContext vc : VCs){
+ int coveredSamples = 0;
+ final GenotypesContext genotypes = vc.getGenotypes();
+ final int numOfGenotypes = genotypes.size();
+ for(Genotype g : genotypes){
+ if(g.getDP() >= minCoverage)
+ coveredSamples++;
+ }
+ if((double)coveredSamples/numOfGenotypes > percentageOfSamples){
+ emitSite = true;
+ }
+ }
+ if (emitSite)
+ return ref.getLocus();
+ else
+ return null;
+ }
+
+ @Override
+ public Integer reduceInit() { return 0; }
+
+ @Override
+ public Integer reduce(GenomeLoc value, Integer sum) {
+ if ( value != null ) {
+ outputStream.println(value);
+ sum++;
+ }
+ return sum;
+ }
+
+ @Override
+ public Integer treeReduce(Integer lhs, Integer rhs) {
+ return lhs + rhs;
+ }
+
+ /**
+ *
+ * @param result the number of sites that passed the filter.
+ */
+ public void onTraversalDone(Integer result) {
+ logger.info(result+" sites that have "+(percentageOfSamples*100)+"% of the samples with at least "+minCoverage+" coverage.\n");
+ }
+
+
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/ErrorRatePerCycle.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/ErrorRatePerCycle.java
new file mode 100644
index 0000000..910afa4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/ErrorRatePerCycle.java
@@ -0,0 +1,215 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.diagnostics;
+
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.report.GATKReport;
+import org.broadinstitute.gatk.engine.report.GATKReportTable;
+import org.broadinstitute.gatk.engine.walkers.LocusWalker;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.QualityUtils;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.PrintStream;
+
+/**
+ * Compute the read error rate per position
+ *
+ * <p>This tool computes the read error rate per position in sequence reads. It does this in the original 5'->3'
+ * orientation that the read had coming off the machine. It then emits a GATKReport containing readgroup, cycle,
+ * mismatches, counts, qual, and error rate for each read group in the input BAMs.</p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * Any number of BAM files
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A GATKReport containing readgroup, cycle, mismatches, counts, qual, and error rate.
+ *
+ * For example, running this tool on the NA12878 data sets yields the following table:
+ *
+ * <pre>
+ * ##:GATKReport.v0.2 ErrorRatePerCycle : The error rate per sequenced position in the reads
+ * readgroup cycle mismatches counts qual errorrate
+ * 20FUK.1 0 80 23368 25 3.47e-03
+ * 20FUK.1 1 40 23433 28 1.75e-03
+ * 20FUK.1 2 36 23453 28 1.58e-03
+ * 20FUK.1 3 26 23476 29 1.15e-03
+ * 20FUK.1 4 32 23495 29 1.40e-03
+ * up to 101 cycles
+ * 20FUK.2 0 77 20886 24 3.73e-03
+ * 20FUK.2 1 28 20920 29 1.39e-03
+ * 20FUK.2 2 24 20931 29 1.19e-03
+ * 20FUK.2 3 30 20940 28 1.48e-03
+ * 20FUK.2 4 25 20948 29 1.24e-03
+ * up to 101 cycles
+ * 20FUK.3 0 78 22038 24 3.58e-03
+ * 20FUK.3 1 40 22091 27 1.86e-03
+ * 20FUK.3 2 23 22108 30 1.09e-03
+ * 20FUK.3 3 36 22126 28 1.67e-03
+ * </pre>
+ * </p>
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java
+ * -jar GenomeAnalysisTK.jar
+ * -T ErrorRatePerCycle
+ * -R human_g1k_v37.fasta
+ * -I my_sequence_reads.bam
+ * -o error_rates.gatkreport.txt
+ * </pre>
+ *
+ * <h3>Caveat</h3>
+ *
+ * <p>Note that when it is run on paired-end sequence data, this tool only uses the first read in a pair.</p>
+ *
+ * @author Kiran Garimella, Mark DePristo
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class ErrorRatePerCycle extends LocusWalker<Integer, Integer> {
+ @Output PrintStream out;
+ @Argument(fullName="min_base_quality_score", shortName="mbq", doc="Minimum base quality required to consider a base for calling", required=false)
+ public Integer MIN_BASE_QUAL = 0;
+ @Argument(fullName="min_mapping_quality_score", shortName="mmq", doc="Minimum read mapping quality required to consider a read for calling", required=false)
+ public Integer MIN_MAPPING_QUAL = 20;
+
+ private GATKReport report;
+ private GATKReportTable table;
+ private final static String reportName = "ErrorRatePerCycle";
+ private final static String reportDescription = "The error rate per sequenced position in the reads";
+
+ /**
+ * Allows us to use multiple records for the key (read group x cycle)
+ */
+ private static class TableKey implements Comparable<TableKey> {
+ final String readGroup;
+ final int cycle;
+
+ private TableKey(final String readGroup, final int cycle) {
+ this.readGroup = readGroup;
+ this.cycle = cycle;
+ }
+
+ // Must overload hashCode and equals to properly work with GATKReportColumn
+ @Override
+ public int hashCode() {
+ return readGroup.hashCode() + 33 * cycle;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final TableKey oKey = (TableKey) o;
+
+ if ( cycle != oKey.cycle ) return false;
+ if ( !readGroup.equals(oKey.readGroup) ) return false;
+
+ return true;
+ }
+
+ @Override
+ public int compareTo(final TableKey tableKey) {
+ final int scmp = readGroup.compareTo(tableKey.readGroup);
+ if ( scmp == 0 )
+ return Integer.valueOf(cycle).compareTo(tableKey.cycle);
+ else
+ return scmp;
+ }
+ }
+
+ public void initialize() {
+ report = new GATKReport();
+ report.addTable(reportName, reportDescription, 6, GATKReportTable.TableSortingWay.SORT_BY_ROW);
+ table = report.getTable(reportName);
+ table.addColumn("readgroup");
+ table.addColumn("cycle");
+ table.addColumn("mismatches");
+ table.addColumn("counts");
+ table.addColumn("qual");
+ table.addColumn("errorrate", "%.2e");
+ }
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ for ( final PileupElement p : context.getBasePileup() ) {
+ final GATKSAMRecord read = p.getRead();
+ final int offset = p.getOffset();
+ final boolean firstOfPair = ! read.getReadPairedFlag() || read.getFirstOfPairFlag();
+
+ if ( firstOfPair && read.getMappingQuality() >= MIN_MAPPING_QUAL && p.getQual() >= MIN_BASE_QUAL ) {
+ final byte readBase = p.getBase();
+ final byte refBase = ref.getBase();
+ final int cycle = offset;
+
+ if ( BaseUtils.isRegularBase(readBase) && BaseUtils.isRegularBase(refBase) ) {
+ final TableKey key = new TableKey(read.getReadGroup().getReadGroupId(), cycle);
+
+ if ( ! table.containsRowID(key) ) {
+ table.set(key, "cycle", cycle);
+ table.set(key, "readgroup", read.getReadGroup().getReadGroupId());
+ table.set(key, "counts", 0);
+ table.set(key, "mismatches", 0);
+ }
+
+ table.increment(key, "counts");
+ if (readBase != refBase)
+ table.increment(key, "mismatches");
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Integer reduceInit() { return null; }
+
+ public Integer reduce(Integer value, Integer sum) { return null; }
+
+ public void onTraversalDone(Integer sum) {
+ for ( Object key : table.getRowIDs() ) {
+ final int mismatches = (Integer)table.get(key, "mismatches");
+ final int count = (Integer)table.get(key, "counts");
+ final double errorRate = (mismatches + 1) / (1.0*(count + 1));
+ final int qual = QualityUtils.errorProbToQual(errorRate);
+ table.set(key, "qual", qual);
+ table.set(key, "errorrate", errorRate);
+ }
+
+ report.print(out);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/ReadGroupProperties.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/ReadGroupProperties.java
new file mode 100644
index 0000000..e9856de
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/ReadGroupProperties.java
@@ -0,0 +1,229 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.diagnostics;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.report.GATKReport;
+import org.broadinstitute.gatk.engine.report.GATKReportTable;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.utils.Median;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Emits a GATKReport containing read group, sample, library, platform, center, sequencing data,
+ * paired end status, simple read type name (e.g. 2x76) median insert size and median read length
+ * for each read group in every provided BAM file
+ *
+ * Note that this walker stops when all read groups have been observed at least a few thousand times so that
+ * the median statistics are well determined. It is safe to run it WG and it'll finish in an appropriate
+ * timeframe.
+ *
+ * <h3>Input</h3>
+ * <p>
+ * Any number of BAM files
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * GATKReport containing read group, sample, library, platform, center, median insert size and median read length.
+ *
+ * For example, running this tool on the NA12878 data sets:
+ *
+ * <pre>
+ * ##:GATKReport.v0.2 ReadGroupProperties : Table of read group properties
+ * readgroup sample library platform center date has.any.reads is.paired.end n.reads.analyzed simple.read.type median.read.length median.insert.size
+ * 20FUK.1 NA12878 Solexa-18483 illumina BI 2/2/10 true true 498 2x101 101 386
+ * 20FUK.2 NA12878 Solexa-18484 illumina BI 2/2/10 true true 476 2x101 101 417
+ * 20FUK.3 NA12878 Solexa-18483 illumina BI 2/2/10 true true 407 2x101 101 387
+ * 20FUK.4 NA12878 Solexa-18484 illumina BI 2/2/10 true true 389 2x101 101 415
+ * 20FUK.5 NA12878 Solexa-18483 illumina BI 2/2/10 true true 433 2x101 101 386
+ * 20FUK.6 NA12878 Solexa-18484 illumina BI 2/2/10 true true 480 2x101 101 418
+ * 20FUK.7 NA12878 Solexa-18483 illumina BI 2/2/10 true true 450 2x101 101 386
+ * 20FUK.8 NA12878 Solexa-18484 illumina BI 2/2/10 true true 438 2x101 101 418
+ * 20GAV.1 NA12878 Solexa-18483 illumina BI 1/26/10 true true 490 2x101 101 391
+ * 20GAV.2 NA12878 Solexa-18484 illumina BI 1/26/10 true true 485 2x101 101 417
+ * 20GAV.3 NA12878 Solexa-18483 illumina BI 1/26/10 true true 460 2x101 101 392
+ * 20GAV.4 NA12878 Solexa-18484 illumina BI 1/26/10 true true 434 2x101 101 415
+ * 20GAV.5 NA12878 Solexa-18483 illumina BI 1/26/10 true true 479 2x101 101 389
+ * 20GAV.6 NA12878 Solexa-18484 illumina BI 1/26/10 true true 461 2x101 101 416
+ * 20GAV.7 NA12878 Solexa-18483 illumina BI 1/26/10 true true 509 2x101 101 386
+ * 20GAV.8 NA12878 Solexa-18484 illumina BI 1/26/10 true true 476 2x101 101 410 101 414
+ * </pre>
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java
+ * -jar GenomeAnalysisTK.jar
+ * -T ReadGroupProperties
+ * -I example1.bam -I example2.bam etc
+ * -R reference.fasta
+ * -o example.gatkreport.txt
+ * </pre>
+ *
+ * @author Mark DePristo
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class ReadGroupProperties extends ReadWalker<Integer, Integer> {
+ @Output
+ public PrintStream out;
+
+ @Argument(shortName="maxElementsForMedian", doc="Calculate median from the first maxElementsForMedian values observed", required=false)
+ public int MAX_VALUES_FOR_MEDIAN = 10000;
+
+ private final static String TABLE_NAME = "ReadGroupProperties";
+ private final Map<String, PerReadGroupInfo> readGroupInfo = new HashMap<String, PerReadGroupInfo>();
+
+ private class PerReadGroupInfo {
+ public final Median<Integer> readLength = new Median<Integer>(MAX_VALUES_FOR_MEDIAN);
+ public final Median<Integer> insertSize = new Median<Integer>(MAX_VALUES_FOR_MEDIAN);
+ public int nReadsSeen = 0, nReadsPaired = 0;
+
+ public boolean needsMoreData() {
+ return ! readLength.isFull() || ! insertSize.isFull();
+ }
+ }
+
+ @Override
+ public void initialize() {
+ for ( final SAMReadGroupRecord rg : getToolkit().getSAMFileHeader().getReadGroups() ) {
+ readGroupInfo.put(rg.getId(), new PerReadGroupInfo());
+ }
+ }
+
+ @Override
+ public boolean filter(ReferenceContext ref, GATKSAMRecord read) {
+ return ! (read.getReadFailsVendorQualityCheckFlag() || read.getReadUnmappedFlag());
+ }
+
+ @Override
+ public boolean isDone() {
+ for ( PerReadGroupInfo info : readGroupInfo.values() ) {
+ if ( info.needsMoreData() )
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public Integer map(ReferenceContext referenceContext, GATKSAMRecord read, RefMetaDataTracker RefMetaDataTracker) {
+ final String rgID = read.getReadGroup().getId();
+ final PerReadGroupInfo info = readGroupInfo.get(rgID);
+
+ if ( info.needsMoreData() ) {
+ info.readLength.add(read.getReadLength());
+ info.nReadsSeen++;
+ if ( read.getReadPairedFlag() ) {
+ info.nReadsPaired++;
+ if ( read.getInferredInsertSize() != 0) {
+ info.insertSize.add(Math.abs(read.getInferredInsertSize()));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public Integer reduceInit() {
+ return null;
+ }
+
+ @Override
+ public Integer reduce(Integer integer, Integer integer1) {
+ return null;
+ }
+
+ @Override
+ public void onTraversalDone(Integer sum) {
+ final GATKReport report = new GATKReport();
+ report.addTable(TABLE_NAME, "Table of read group properties", 12);
+ GATKReportTable table = report.getTable(TABLE_NAME);
+ DateFormat dateFormatter = DateFormat.getDateInstance(DateFormat.SHORT);
+
+ table.addColumn("readgroup");
+ //* Emits a GATKReport containing read group, sample, library, platform, center, median insert size and
+ //* median read length for each read group in every BAM file.
+ table.addColumn("sample", "%s");
+ table.addColumn("library", "%s");
+ table.addColumn("platform", "%s");
+ table.addColumn("center", "%s");
+ table.addColumn("date", "%s");
+ table.addColumn("has.any.reads");
+ table.addColumn("is.paired.end");
+ table.addColumn("n.reads.analyzed", "%d");
+ table.addColumn("simple.read.type", "%s");
+ table.addColumn("median.read.length");
+ table.addColumn("median.insert.size");
+
+ for ( final SAMReadGroupRecord rg : getToolkit().getSAMFileHeader().getReadGroups() ) {
+ final String rgID = rg.getId();
+ table.addRowID(rgID, true);
+ PerReadGroupInfo info = readGroupInfo.get(rgID);
+
+ // we are paired if > 25% of reads are paired
+ final boolean isPaired = info.nReadsPaired / (1.0 * (info.nReadsSeen+1)) > 0.25;
+ final boolean hasAnyReads = info.nReadsSeen > 0;
+ final int readLength = info.readLength.getMedian(0);
+
+ setTableValue(table, rgID, "sample", rg.getSample());
+ setTableValue(table, rgID, "library", rg.getLibrary());
+ setTableValue(table, rgID, "platform", rg.getPlatform());
+ setTableValue(table, rgID, "center", rg.getSequencingCenter());
+ try {
+ setTableValue(table, rgID, "date", rg.getRunDate() != null ? dateFormatter.format(rg.getRunDate()) : "NA");
+ } catch ( NullPointerException e ) {
+ // TODO: remove me when bug in Picard is fixed that causes NPE when date isn't present
+ setTableValue(table, rgID, "date", "NA");
+ }
+ setTableValue(table, rgID, "has.any.reads", hasAnyReads);
+ setTableValue(table, rgID, "is.paired.end", isPaired);
+ setTableValue(table, rgID, "n.reads.analyzed", info.nReadsSeen);
+ setTableValue(table, rgID, "simple.read.type", hasAnyReads ? String.format("%dx%d", isPaired ? 2 : 1, readLength) : "NA");
+ setTableValue(table, rgID, "median.read.length", hasAnyReads ? readLength : "NA" );
+ setTableValue(table, rgID, "median.insert.size", hasAnyReads && isPaired ? info.insertSize.getMedian(0) : "NA" );
+ }
+
+ report.print(out);
+ }
+
+ private final void setTableValue(GATKReportTable table, final String rgID, final String key, final Object value) {
+ table.set(rgID, key, value == null ? "NA" : value);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/ReadLengthDistribution.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/ReadLengthDistribution.java
new file mode 100644
index 0000000..a632f25
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/diagnostics/ReadLengthDistribution.java
@@ -0,0 +1,180 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.diagnostics;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.report.GATKReport;
+import org.broadinstitute.gatk.engine.report.GATKReportTable;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Outputs the read lengths of all the reads in a file.
+ *
+ * <p>
+ * Generates a table with the read lengths categorized per sample. If the file has no sample information
+ * (no read groups) it considers all reads to come from the same sample.
+ * </p>
+ *
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A BAM file.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A human/R readable table of tab separated values with one column per sample and one row per read.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java
+ * -jar GenomeAnalysisTK.jar
+ * -T ReadLengthDistribution
+ * -I example.bam
+ * -R reference.fasta
+ * -o example.tbl
+ * </pre>
+ *
+ * @author Kiran Garimela
+ */
+
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class ReadLengthDistribution extends ReadWalker<Integer, Integer> {
+ @Output
+ public PrintStream out;
+
+ //A map from RG to its column number (its index in an int[] array)
+ private Map<SAMReadGroupRecord,Integer> readGroupsLocation;
+ //Each line in the table is a read length and each column it the number of reads of a specific RG with that length. Thus a table is a map between read lengths to array of values (one for each RG).
+ private Map<Integer,int[]> table;
+ private List<SAMReadGroupRecord> readGroups;
+
+ public void initialize() {
+ readGroups = getToolkit().getSAMFileHeader().getReadGroups();
+ readGroupsLocation = new HashMap<>();
+ table = new TreeMap<>();
+ int readGroupsNum = 0;
+
+ if (!readGroups.isEmpty()){
+ for (SAMReadGroupRecord rg : readGroups){
+ readGroupsLocation.put(rg,readGroupsNum);
+ readGroupsNum++;
+ }
+ }
+ }
+
+ @Override
+ public Integer map(final ReferenceContext referenceContext,final GATKSAMRecord samRecord,final RefMetaDataTracker RefMetaDataTracker) {
+
+ final int length = Math.abs(samRecord.getReadLength());
+ final SAMReadGroupRecord rg = samRecord.getReadGroup();
+
+ increment(table,length, rg);
+
+ return null;
+ }
+
+ final private void increment(final Map<Integer,int[]> table,final int length,final SAMReadGroupRecord rg){
+ if(readGroupsLocation.isEmpty()){
+ if(table.containsKey(length))
+ table.get(length)[0]++;
+ else{
+ final int[] newLength = {1};
+ table.put(length,newLength);
+ }
+ }
+ else{
+ final int rgLocation = readGroupsLocation.get(rg);
+ if(table.containsKey(length))
+ table.get(length)[rgLocation]++;
+ else{
+ table.put(length,new int[readGroupsLocation.size()]);
+ table.get(length)[rgLocation]++;
+ }
+ }
+ }
+
+ @Override
+ public Integer reduceInit() {
+ return null;
+ }
+
+ @Override
+ public Integer reduce(final Integer integer,final Integer integer1) {
+ return null;
+ }
+
+ public void onTraversalDone(final Integer sum) {
+ final GATKReport report = createGATKReport();
+ report.print(out);
+ }
+
+ final private GATKReport createGATKReport(){
+ final GATKReport report = new GATKReport();
+ report.addTable("ReadLengthDistribution", "Table of read length distributions", 1 + (readGroupsLocation.isEmpty() ? 1 : readGroupsLocation.size()));
+ final GATKReportTable tableReport = report.getTable("ReadLengthDistribution");
+
+ tableReport.addColumn("readLength");
+
+ if (readGroupsLocation.isEmpty()){
+ tableReport.addColumn("SINGLE_SAMPLE");
+ int rowIndex = 0;
+ for (Integer length : table.keySet()){
+ tableReport.set(rowIndex,0,length);
+ tableReport.set(rowIndex,1,table.get(length)[0]);
+ rowIndex++;
+ }
+ }
+ else{
+ for (SAMReadGroupRecord rg : readGroups)
+ tableReport.addColumn(rg.getSample());
+ int rowIndex = 0;
+ for (Integer length : table.keySet()){
+ tableReport.set(rowIndex,0,length);
+ for (int i=0; i < readGroupsLocation.size(); i++)
+ tableReport.set(rowIndex,i+1,table.get(length)[i]);
+ rowIndex++;
+ }
+
+ }
+
+ return report;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/examples/GATKDocsExample.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/examples/GATKDocsExample.java
new file mode 100644
index 0000000..80fca67
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/examples/GATKDocsExample.java
@@ -0,0 +1,83 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.examples;
+
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Hidden;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+
+/**
+ * [Short one sentence description of this walker]
+ *
+ * <p>
+ * [Functionality of this walker]
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * [Input description]
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * [Output description]
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java
+ * -jar GenomeAnalysisTK.jar
+ * -T $WalkerName
+ * </pre>
+ *
+ * @author Your Name
+ * @since Date created
+ */
+ at Hidden
+public class GATKDocsExample extends RodWalker<Integer, Integer> {
+ /**
+ * Put detailed documentation about the argument here. No need to duplicate the summary information
+ * in doc annotation field, as that will be added before this text in the documentation page.
+ *
+ * Notes:
+ * <ul>
+ * <li>This field can contain HTML as a normal javadoc</li>
+ * <li>Don't include information about the default value, as gatkdocs adds this automatically</li>
+ * <li>Try your best to describe in detail the behavior of the argument, as ultimately confusing
+ * docs here will just result in user posts on the forum</li>
+ * </ul>
+ */
+ @Argument(fullName="full", shortName="short", doc="Brief summary of argument [~ 80 characters of text]", required=false)
+ private boolean myWalkerArgument = false;
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) { return 0; }
+ public Integer reduceInit() { return 0; }
+ public Integer reduce(Integer value, Integer sum) { return value + sum; }
+ public void onTraversalDone(Integer result) { }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/examples/GATKPaperGenotyper.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/examples/GATKPaperGenotyper.java
new file mode 100644
index 0000000..8cfc14e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/examples/GATKPaperGenotyper.java
@@ -0,0 +1,273 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.examples;
+
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.LocusWalker;
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.utils.genotyper.DiploidGenotype;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * A simple Bayesian genotyper, that outputs a text based call format. Intended to be used only as an
+ * example in the GATK publication.
+ *
+ * @author aaron
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_TOY, extraDocs = {CommandLineGATK.class} )
+public class GATKPaperGenotyper extends LocusWalker<Integer,Long> implements TreeReducible<Long> {
+
+ public static final double HUMAN_SNP_HETEROZYGOSITY = 1e-3;
+
+ // the possible diploid genotype strings
+ private static enum GENOTYPE { AA, AC, AG, AT, CC, CG, CT, GG, GT, TT }
+
+ @Output
+ private PrintStream out;
+
+ @Argument(fullName = "log_odds_score", shortName = "LOD", doc = "The LOD threshold for us to call confidently a genotype", required = false)
+ private double LODScore = 3.0;
+
+ /**
+ * our map function, which takes the reads spanning this locus, any associated reference ordered data,
+ * and the reference information. We output a simple genotype call as the result of this function
+ *
+ * @param tracker the reference ordered data tracker
+ * @param ref the reference information
+ * @param context the locus context, which contains all of the read information
+ * @return a SimpleCall, which stores the genotype we're calling and the LOD score
+ */
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if (ref.getBase() == 'N' || ref.getBase() == 'n') return null; // we don't deal with the N ref base case
+
+ ReadBackedPileup pileup = context.getBasePileup().getPileupWithoutMappingQualityZeroReads();
+ double likelihoods[] = getReferencePolarizedPriors(ref.getBase(),
+ HUMAN_SNP_HETEROZYGOSITY,
+ 0.01);
+ // get the bases and qualities from the pileup
+ byte bases[] = pileup.getBases();
+ byte quals[] = pileup.getQuals();
+
+ // for each genotype, determine it's likelihood value
+ for (GENOTYPE genotype : GENOTYPE.values())
+ for (int index = 0; index < bases.length; index++) {
+ // our epsilon is the de-Phred scored base quality
+ double epsilon = Math.pow(10, quals[index] / -10.0);
+
+ byte pileupBase = bases[index];
+ double p = 0;
+ for (char r : genotype.toString().toCharArray())
+ p += r == pileupBase ? 1 - epsilon : epsilon / 3;
+ likelihoods[genotype.ordinal()] += Math.log10(p / genotype.toString().length());
+ }
+
+ Integer sortedList[] = sortPermutation(likelihoods);
+
+ // create call using the best genotype (GENOTYPE.values()[sortedList[9]].toString())
+ // and calculate the LOD score from best - next best (9 and 8 in the sorted list, since the best likelihoods are closest to zero)
+ GENOTYPE selectedGenotype = GENOTYPE.values()[sortedList[sortedList.length-1]];
+ double lod = likelihoods[sortedList[sortedList.length-1]] - likelihoods[sortedList[sortedList.length-2]];
+
+ if (lod > LODScore) {
+ out.printf("%s\t%s\t%.4f\t%c%n", context.getLocation(), selectedGenotype, lod, (char)ref.getBase());
+ return 1;
+ }
+
+ return 0;
+ }
+
+ private static Integer[] sortPermutation(final double[] A) {
+ class comparator implements Comparator<Integer> {
+ public int compare(Integer a, Integer b) {
+ if (A[a.intValue()] < A[b.intValue()]) {
+ return -1;
+ }
+ if (A[a.intValue()] == A[b.intValue()]) {
+ return 0;
+ }
+ if (A[a.intValue()] > A[b.intValue()]) {
+ return 1;
+ }
+ return 0;
+ }
+ }
+ Integer[] permutation = new Integer[A.length];
+ for (int i = 0; i < A.length; i++) {
+ permutation[i] = i;
+ }
+ Arrays.sort(permutation, new comparator());
+ return permutation;
+ }
+
+ /**
+ * Takes reference base, and three priors for hom-ref, het, hom-var, and fills in the priors vector
+ * appropriately.
+ *
+ * Suppose A is the reference base, and we are given the probability of being hom-ref, het, and hom-var,
+ * and that pTriSateGenotype is the true probability of observing reference A and a true genotype of B/C
+ * then this sets the priors to:
+ *
+ * AA = hom-ref
+ * AC = AG = AT = (het - pTriStateGenotype) / 3
+ * CC = GG = TT = hom-var / 3
+ * CG = CT = GT = pTriStateGenotype / 3
+ *
+ * So that we get:
+ *
+ * hom-ref + 3 * (het - pTriStateGenotype) / 3 + 3 * hom-var / 3 + 3 * pTriStateGenotype
+ * hom-ref + het - pTriStateGenotype + hom-var + pTriStateGenotype
+ * hom-ref + het + hom-var
+ * = 1
+ *
+ * @param ref
+ * @param heterozyosity
+ * @param pRefError
+ */
+ public static double[] getReferencePolarizedPriors(byte ref, double heterozyosity, double pRefError ) {
+ if ( ! MathUtils.isBounded(pRefError, 0.0, 0.01) ) {
+ throw new RuntimeException(String.format("BUG: p Reference error is out of bounds (0.0 - 0.01) is allow range %f", pRefError));
+ }
+
+ double pTriStateGenotype = heterozyosity * pRefError;
+// if ( pTriStateGenotype >= heterozyosity ) {
+// throw new RuntimeException(String.format("p Tristate genotype %f is greater than the heterozygosity %f", pTriStateGenotype, heterozyosity));
+// }
+
+ double pHomRef = heterozygosity2HomRefProbability(heterozyosity);
+ double pHet = heterozygosity2HetProbability(heterozyosity);
+ double pHomVar = heterozygosity2HomVarProbability(heterozyosity);
+
+ if (MathUtils.compareDoubles(pHomRef + pHet + pHomVar, 1.0) != 0) {
+ throw new RuntimeException(String.format("BUG: Prior probabilities don't sum to one => %f, %f, %f", pHomRef, pHet, pHomVar));
+ }
+
+ double[] priors = new double[DiploidGenotype.values().length];
+
+ for ( DiploidGenotype g : DiploidGenotype.values() ) {
+ double POfG;
+
+ final double nOnRefHets = 3;
+ final double nOffRefHets = 3;
+ final double nHomVars = 3;
+
+ if ( g.isHomRef(ref) ) { POfG = pHomRef; }
+ else if ( g.isHomVar(ref) ) { POfG = pHomVar / nHomVars; }
+ else if ( g.isHetRef(ref) ) { POfG = (pHet - pTriStateGenotype ) / nOnRefHets; }
+ else { POfG = pTriStateGenotype / nOffRefHets; }
+
+ priors[g.ordinal()] = Math.log10(POfG);
+ }
+
+ return priors;
+ }
+
+ /**
+ *
+ * @param h
+ * @return
+ */
+ public static double heterozygosity2HomRefProbability(double h) {
+ if (MathUtils.isNegative(h)) {
+ throw new RuntimeException(String.format("Heterozygous value is bad %f", h));
+ }
+
+ double v = 1.0 - (3.0 * h / 2.0);
+ if (MathUtils.isNegative(v)) {
+ throw new RuntimeException(String.format("Heterozygous value is bad %f", h));
+ }
+
+ return v;
+ }
+
+ public static double heterozygosity2HetProbability(double h) {
+ if (MathUtils.isNegative(h)) {
+ throw new RuntimeException(String.format("Heterozygous value is bad %f", h));
+ }
+
+ return h;
+ }
+
+ public static double heterozygosity2HomVarProbability(double h) {
+ if (MathUtils.isNegative(h)) {
+ throw new RuntimeException(String.format("Heterozygous value is bad %f", h));
+ }
+
+ return h / 2.0;
+ }
+
+ /**
+ * Provide an initial value for reduce computations. In this case we simply return an empty list
+ *
+ * @return Initial value of reduce.
+ */
+ public Long reduceInit() {
+ return 0L;
+ }
+
+ /**
+ * Outputs the number of genotypes called.
+ *
+ * @param value result of the map.
+ * @param sum accumulator for the reduce.
+ * @return accumulator with result of the map taken into account.
+ */
+ public Long reduce(Integer value, Long sum) {
+ return value + sum;
+ }
+
+ /**
+ * A composite, 'reduce of reduces' function.
+ *
+ * @param lhs 'left-most' portion of data in the composite reduce.
+ * @param rhs 'right-most' portion of data in the composite reduce.
+ * @return The composite reduce type.
+ */
+ public Long treeReduce(Long lhs, Long rhs) {
+ return lhs + rhs;
+ }
+
+ /**
+ * when we finish traversing, close the result list
+ * @param result the final reduce result
+ */
+ public void onTraversalDone(Integer result) {
+ out.println("Simple Genotyper genotyped " + result + "Loci.");
+ }
+}
+
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaAlternateReferenceMaker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaAlternateReferenceMaker.java
new file mode 100644
index 0000000..8fd4152
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaAlternateReferenceMaker.java
@@ -0,0 +1,187 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.fasta;
+
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.ArgumentCollection;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.*;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ * Generates an alternative reference sequence over the specified interval.
+ *
+ * <p>
+ * Given variant tracks, it replaces the reference bases at variation sites with the bases supplied by the ROD(s).
+ * Additionally, allows for one or more "snpmask" VCFs to set overlapping bases to 'N'.
+ *
+ * The output format can be partially controlled using the provided command-line arguments.
+ * Specify intervals with the usual -L argument to output only the reference bases within your intervals.
+ * Overlapping intervals are automatically merged; reference bases for each disjoint interval will be output as a
+ * separate fasta sequence (named numerically in order).
+ *
+ * Several important notes:
+ * 1) if there are multiple variants that start at a site, it chooses one of them randomly.
+ * 2) when there are overlapping indels (but with different start positions) only the first will be chosen.
+ * 3) this tool works only for SNPs and for simple indels (but not for things like complex substitutions).
+ * Reference bases for each interval will be output as a separate fasta sequence (named numerically in order).
+ *
+ * <h3>Input</h3>
+ * <p>
+ * The reference, requested intervals, and any number of variant rod files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A fasta file representing the requested intervals.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T FastaAlternateReferenceMaker \
+ * -o output.fasta \
+ * -L input.intervals \
+ * --variant input.vcf \
+ * [--snpmask mask.vcf]
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_REFUTILS, extraDocs = {CommandLineGATK.class} )
+ at Reference(window=@Window(start=-1,stop=50))
+ at Requires(value={DataSource.REFERENCE})
+public class FastaAlternateReferenceMaker extends FastaReferenceMaker {
+
+ /**
+ * Variants from this input file are used by this tool to construct an alternate reference.
+ */
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ /**
+ * Snps from this file are used as a mask (inserting N's in the sequence) when constructing the alternate reference
+ * (regardless of whether they overlap a variant site).
+ */
+ @Input(fullName="snpmask", shortName = "snpmask", doc="SNP mask VCF file", required=false)
+ protected RodBinding<VariantContext> snpmask;
+
+ /**
+ * This option will generate an error if the specified sample does not exist in the VCF.
+ * Non-diploid (or non-called) genotypes are ignored.
+ */
+ @Argument(fullName="use_IUPAC_sample", shortName="IUPAC", doc = "If specified, heterozygous SNP sites will be output using IUPAC ambiguity codes given the genotypes for this sample", required=false)
+ private String iupacSample = null;
+
+ private int deletionBasesRemaining = 0;
+
+ @Override
+ public void initialize() {
+ super.initialize();
+ if ( iupacSample != null ) {
+ final List<String> rodName = Arrays.asList(variantCollection.variants.getName());
+ final Set<String> samples = SampleUtils.getUniqueSamplesFromRods(getToolkit(), rodName);
+ if ( !samples.contains(iupacSample) )
+ throw new UserException.BadInput("the IUPAC sample specified is not present in the provided VCF file");
+ }
+ }
+
+ @Override
+ public Pair<GenomeLoc, String> map(final RefMetaDataTracker tracker, final ReferenceContext ref, final AlignmentContext context) {
+
+ if (deletionBasesRemaining > 0) {
+ deletionBasesRemaining--;
+ return new Pair<>(context.getLocation(), "");
+ }
+
+ final String refBase = String.valueOf((char)ref.getBase());
+
+ // Check to see if we have a called snp
+ for ( final VariantContext vc : tracker.getValues(variantCollection.variants, ref.getLocus()) ) {
+ if ( vc.isFiltered() )
+ continue;
+
+ if ( vc.isSimpleDeletion()) {
+ deletionBasesRemaining = vc.getReference().length() - 1;
+ // delete the next n bases, not this one
+ return new Pair<>(context.getLocation(), refBase);
+ } else if ( vc.isSimpleInsertion()) {
+ return new Pair<>(context.getLocation(), vc.getAlternateAllele(0).toString());
+ } else if (vc.isSNP()) {
+ final String base = (iupacSample != null) ? getIUPACbase(vc.getGenotype(iupacSample), refBase) : vc.getAlternateAllele(0).toString();
+ return new Pair<>(context.getLocation(), base);
+ }
+ }
+
+ // if we don't have a called site, and we have a mask at this site, mask it
+ for ( final VariantContext vc : tracker.getValues(snpmask) ) {
+ if ( vc.isSNP()) {
+ return new Pair<>(context.getLocation(), "N");
+ }
+ }
+
+ // if we got here then we're just ref
+ return new Pair<>(context.getLocation(), refBase);
+ }
+
+ /**
+ * Returns the IUPAC encoding for the given genotype or the reference base if not possible
+ *
+ * @param genotype the genotype to encode
+ * @param ref the reference base
+ * @return non-null, non-empty String
+ */
+ private String getIUPACbase(final Genotype genotype, final String ref) {
+ if ( genotype == null )
+ throw new IllegalStateException("The genotype is null for sample " + iupacSample);
+
+ if ( !genotype.isHet() )
+ return genotype.isHom() ? genotype.getAllele(0).getBaseString() : ref;
+
+ final byte allele1 = genotype.getAllele(0).getBases()[0];
+ final byte allele2 = genotype.getAllele(1).getBases()[0];
+ return new String(new byte[] {BaseUtils.basesToIUPAC(allele1, allele2)});
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaReferenceMaker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaReferenceMaker.java
new file mode 100644
index 0000000..8459506
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaReferenceMaker.java
@@ -0,0 +1,127 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.fasta;
+
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RefWalker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.io.PrintStream;
+
+/**
+ * Renders a new reference in FASTA format consisting of only those loci provided in the input data set.
+ *
+ * <p>
+ * The output format can be partially controlled using the provided command-line arguments.
+ * Specify intervals with the usual -L argument to output only the reference bases within your intervals.
+ * Overlapping intervals are automatically merged; reference bases for each disjoint interval will be output as a
+ * separate fasta sequence (named numerically in order).
+ *
+ * <h3>Input</h3>
+ * <p>
+ * The reference and requested intervals.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A fasta file representing the requested intervals.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T FastaReferenceMaker \
+ * -o output.fasta \
+ * -L input.intervals
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_REFUTILS, extraDocs = {CommandLineGATK.class} )
+public class FastaReferenceMaker extends RefWalker<Pair<GenomeLoc, String>, GenomeLoc> {
+
+ @Output PrintStream out;
+
+ @Argument(fullName="lineWidth", shortName="lw", doc="Maximum length of sequence to write per line", required=false)
+ public int fastaLineWidth=60;
+
+ /**
+ * Please note that when using this argument adjacent intervals will automatically be merged.
+ */
+ @Argument(fullName="rawOnelineSeq", shortName="raw", doc="Print sequences with no FASTA header lines, one line per interval (i.e. lineWidth = infinity)", required=false)
+ public boolean fastaRawSeqs=false;
+
+ protected FastaSequence fasta;
+
+ public void initialize() {
+ if (fastaRawSeqs) fastaLineWidth = Integer.MAX_VALUE;
+ fasta = new FastaSequence(out, fastaLineWidth, fastaRawSeqs);
+ }
+
+ public Pair<GenomeLoc, String> map(RefMetaDataTracker rodData, ReferenceContext ref, AlignmentContext context) {
+ return new Pair<GenomeLoc, String>(context.getLocation(), String.valueOf((char)ref.getBase()));
+ }
+
+ public GenomeLoc reduceInit() {
+ return null;
+ }
+
+ public GenomeLoc reduce(Pair<GenomeLoc, String> value, GenomeLoc sum) {
+ if ( value == null )
+ return sum;
+
+ // if there is no interval to the left, then this is the first one
+ if ( sum == null ) {
+ sum = value.first;
+ fasta.append(value.second);
+ }
+ // if the intervals don't overlap, print out the leftmost one and start a new one
+ // (end of contig or new interval)
+ else if ( value.first.getStart() != sum.getStop() + 1 ) {
+ fasta.flush();
+ sum = value.first;
+ fasta.append(value.second);
+ }
+ // otherwise, merge them
+ else {
+ sum = getToolkit().getGenomeLocParser().setStop(sum, value.first.getStop());
+ fasta.append(value.second);
+ }
+ return sum;
+ }
+
+ public void onTraversalDone(GenomeLoc sum) {
+ fasta.flush();
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaSequence.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaSequence.java
new file mode 100644
index 0000000..013e356
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaSequence.java
@@ -0,0 +1,101 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.fasta;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.PrintStream;
+
+// fasta sequence holder class
+
+public class FastaSequence {
+
+ private PrintStream out;
+ private StringBuffer sb = new StringBuffer();
+ private long sequenceCounter = 1;
+ private boolean printedHeader = false;
+ private String name = null;
+ private int lineWidth = -1;
+ private boolean noHeader = false;
+
+ public FastaSequence(PrintStream out, int lineWidth, boolean noHeader) {
+ this.out = out;
+ this.lineWidth = lineWidth;
+ this.noHeader = noHeader;
+ }
+
+ public void setName(String name) {
+ if ( printedHeader ) throw new ReviewedGATKException("Can not set name for FASTA record: header is already printed.");
+ this.name = name;
+ }
+
+ public String getName() {
+ if ( name != null ) return name;
+ else return getCurrentID();
+ }
+
+ public void append(String s) {
+ sb.append(s);
+ printFasta(false);
+ }
+
+ public void flush() {
+ printFasta(true);
+ printedHeader = false;
+ name = null;
+ sequenceCounter++;
+ }
+
+ public long getCurrentCount() {
+ return sequenceCounter;
+ }
+
+ public String getCurrentID() {
+ return String.valueOf(sequenceCounter);
+ }
+
+ private void printFasta(boolean printAll) {
+ if ( sb.length() == 0 || (!printAll && sb.length() < lineWidth) )
+ return;
+ if ( !printedHeader && !noHeader) {
+ if ( name == null ) out.println(">" + sequenceCounter);
+ else out.println(">" + name);
+ printedHeader = true;
+ }
+ int lines = sb.length() / lineWidth;
+ int currentStart = 0;
+ for (int i=0; i < lines; i++) {
+ out.println(sb.substring(currentStart, currentStart+lineWidth));
+ currentStart += lineWidth;
+ }
+ if ( printAll ) {
+ out.println(sb.substring(currentStart));
+ sb.setLength(0);
+ } else {
+ sb.delete(0, currentStart);
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaStats.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaStats.java
new file mode 100644
index 0000000..22a592b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/fasta/FastaStats.java
@@ -0,0 +1,93 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.fasta;
+
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RefWalker;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.io.PrintStream;
+
+/**
+ * Calculate basic statistics about the reference sequence itself
+ *
+ * <p>These are very basic statistics: total number of bases and number of "regular" bases (i.e. A, C, T or G).</p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A FASTA reference file.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Base counts are written to file if an output file name is given (with -o), otherwise output to stdout.
+ * </p>
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -T FastaStats \
+ * -R ref.fasta \
+ * [-o output.txt]
+ * </pre>
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class FastaStats extends RefWalker<Byte, FastaStats.FastaStatistics> {
+ @Output PrintStream out;
+
+ protected class FastaStatistics {
+ long nBases = 0, nRegBases = 0;
+ }
+
+ @Override
+ public Byte map(RefMetaDataTracker rodData, ReferenceContext ref, AlignmentContext context) {
+ return ref.getBase();
+ }
+
+ @Override
+ public FastaStatistics reduceInit() {
+ return new FastaStatistics();
+ }
+
+ @Override
+ public FastaStatistics reduce(Byte base, FastaStatistics stats) {
+ stats.nBases++;
+ if (BaseUtils.isRegularBase(base)) stats.nRegBases++;
+ return stats;
+ }
+
+ @Override
+ public void onTraversalDone(FastaStatistics sum) {
+ out.printf("Total bases %d%n", sum.nBases);
+ out.printf("Regular bases %d%n", sum.nRegBases);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/ClusteredSnps.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/ClusteredSnps.java
new file mode 100644
index 0000000..97bde83
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/ClusteredSnps.java
@@ -0,0 +1,81 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.filters;
+
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+
+public class ClusteredSnps {
+ private GenomeLocParser genomeLocParser;
+ private int window = 10;
+ private int snpThreshold = 3;
+
+ public ClusteredSnps(GenomeLocParser genomeLocParser,int snpThreshold, int window) {
+ this.genomeLocParser = genomeLocParser;
+ this.window = window;
+ this.snpThreshold = snpThreshold;
+ if ( window < 1 || snpThreshold < 1 )
+ throw new IllegalArgumentException("Window and threshold values need to be positive values");
+ }
+
+ public boolean filter(FiltrationContextWindow contextWindow) {
+
+ FiltrationContext[] variants = contextWindow.getWindow(snpThreshold-1, snpThreshold-1);
+ for (int i = 0; i < snpThreshold; i++) {
+ // ignore positions at the beginning or end of the overall interval (where there aren't enough records)
+ if ( variants[i] == null || variants[i+snpThreshold-1] == null )
+ continue;
+
+ // note: the documentation tells users we'll blow up if ref calls are present.
+ // if we ever get a windowed rod context that isn't a hack, we can actually allow this...
+ if ( !variants[i].getVariantContext().isVariant() )
+ throw new UserException.BadInput("The clustered SNPs filter does not work in the presence of non-variant records; see the documentation for more details");
+
+ // find the nth variant
+ GenomeLoc left = GATKVariantContextUtils.getLocation(genomeLocParser, variants[i].getVariantContext());
+ GenomeLoc right = null;
+ int snpsSeen = 1;
+
+ int currentIndex = i;
+ while ( ++currentIndex < variants.length ) {
+ if ( variants[currentIndex] != null && variants[currentIndex].getVariantContext() != null && variants[currentIndex].getVariantContext().isVariant() ) {
+ if ( ++snpsSeen == snpThreshold ) {
+ right = GATKVariantContextUtils.getLocation(genomeLocParser, variants[currentIndex].getVariantContext());
+ break;
+ }
+ }
+ }
+
+ if ( right != null &&
+ left.getContigIndex() == right.getContigIndex() &&
+ Math.abs(right.getStart() - left.getStart()) <= window )
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/FiltrationContext.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/FiltrationContext.java
new file mode 100644
index 0000000..513763b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/FiltrationContext.java
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.filters;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import htsjdk.variant.variantcontext.VariantContext;
+
+
+public class FiltrationContext {
+
+ private ReferenceContext ref;
+ private VariantContext vc;
+
+ public FiltrationContext(ReferenceContext ref, VariantContext vc) {
+ this.ref = ref;
+ this.vc = vc;
+ }
+
+ public ReferenceContext getReferenceContext() { return ref; }
+
+ public VariantContext getVariantContext() { return vc; }
+
+ public void setVariantContext(VariantContext newVC) { vc = newVC; }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/FiltrationContextWindow.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/FiltrationContextWindow.java
new file mode 100644
index 0000000..731b1a3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/FiltrationContextWindow.java
@@ -0,0 +1,104 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.filters;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+
+/**
+ * A window of variants surrounding the current variant being investigated
+ *
+ * @author ebanks
+ * @version 0.1
+ */
+
+public class FiltrationContextWindow {
+
+ /**
+ * The variants.
+ */
+ private LinkedList<FiltrationContext> window = new LinkedList<FiltrationContext>();
+ private int currentContext;
+
+ /**
+ * Contructor for a variant context.
+ * @param firstVariants the first set of variants, comprising the right half of the window
+ */
+ public FiltrationContextWindow(List<FiltrationContext> firstVariants) {
+ int windowSize = (firstVariants == null ? 1 : 2 * firstVariants.size() + 1);
+ currentContext = (firstVariants == null ? 0 : firstVariants.size());
+ window.addAll(firstVariants);
+ while ( window.size() < windowSize )
+ window.addFirst(null);
+ }
+
+ /**
+ * The context currently being examined.
+ * @return The current context.
+ */
+ public FiltrationContext getContext() {
+ return window.get(currentContext);
+ }
+
+ /**
+ * The maximum number of elements that can be requested on either end of the current context.
+ * @return max.
+ */
+ public int maxWindowElements() {
+ return currentContext;
+ }
+
+ /**
+ * The window around the context currently being examined.
+ * @param elementsToLeft number of earlier contexts to return ()
+ * @param elementsToRight number of later contexts to return ()
+ * @return The current context window.
+ */
+ public FiltrationContext[] getWindow(int elementsToLeft, int elementsToRight) {
+ if ( elementsToLeft > maxWindowElements() || elementsToRight > maxWindowElements() )
+ throw new ReviewedGATKException("Too large a window requested");
+ if ( elementsToLeft < 0 || elementsToRight < 0 )
+ throw new ReviewedGATKException("Window size cannot be negative");
+
+ FiltrationContext[] array = new FiltrationContext[elementsToLeft + elementsToRight + 1];
+ ListIterator<FiltrationContext> iter = window.listIterator(currentContext - elementsToLeft);
+ for (int i = 0; i < elementsToLeft + elementsToRight + 1; i++)
+ array[i] = iter.next();
+ return array;
+ }
+
+ /**
+ * Move the window along to the next context
+ * @param context The new rightmost context
+ */
+ public void moveWindow(FiltrationContext context) {
+ window.removeFirst();
+ window.addLast(context);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/VariantFiltration.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/VariantFiltration.java
new file mode 100644
index 0000000..3988498
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/filters/VariantFiltration.java
@@ -0,0 +1,400 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.filters;
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.Reference;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.Window;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import htsjdk.variant.vcf.*;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+
+import java.util.*;
+
+
+/**
+ * Filters variant calls using a number of user-selectable, parameterizable criteria.
+ *
+ * <p>
+ * VariantFiltration is a GATK tool for hard-filtering variant calls based on certain criteria.
+ * Records are hard-filtered by changing the value in the FILTER field to something other than PASS.
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A variant set to filter.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A filtered VCF.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T VariantFiltration \
+ * -o output.vcf \
+ * --variant input.vcf \
+ * --filterExpression "AB < 0.2 || MQ0 > 50" \
+ * --filterName "Nov09filters" \
+ * --mask mask.vcf \
+ * --maskName InDel
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+ at Reference(window=@Window(start=-50,stop=50))
+public class VariantFiltration extends RodWalker<Integer, Integer> {
+
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ /**
+ * Any variant which overlaps entries from the provided mask rod will be filtered. If the user wants logic to be reversed,
+ * i.e. filter variants that do not overlap with provided mask, then argument -filterNotInMask can be used.
+ * Note that it is up to the user to adapt the name of the mask to make it clear that the reverse logic was used
+ * (e.g. if masking against Hapmap, use -maskName=hapmap for the normal masking and -maskName=not_hapmap for the reverse masking).
+ */
+ @Input(fullName="mask", shortName="mask", doc="Input ROD mask", required=false)
+ public RodBinding<Feature> mask;
+
+ @Output(doc="File to which variants should be written")
+ protected VariantContextWriter writer = null;
+
+ /**
+ * VariantFiltration accepts any number of JEXL expressions (so you can have two named filters by using
+ * --filterName One --filterExpression "X < 1" --filterName Two --filterExpression "X > 2").
+ */
+ @Argument(fullName="filterExpression", shortName="filter", doc="One or more expression used with INFO fields to filter", required=false)
+ protected ArrayList<String> FILTER_EXPS = new ArrayList<String>();
+
+ /**
+ * This name is put in the FILTER field for variants that get filtered. Note that there must be a 1-to-1 mapping between filter expressions and filter names.
+ */
+ @Argument(fullName="filterName", shortName="filterName", doc="Names to use for the list of filters", required=false)
+ protected ArrayList<String> FILTER_NAMES = new ArrayList<String>();
+
+ /**
+ * Similar to the INFO field based expressions, but used on the FORMAT (genotype) fields instead.
+ * VariantFiltration will add the sample-level FT tag to the FORMAT field of filtered samples (this does not affect the record's FILTER tag).
+ * One can filter normally based on most fields (e.g. "GQ < 5.0"), but the GT (genotype) field is an exception. We have put in convenience
+ * methods so that one can now filter out hets ("isHet == 1"), refs ("isHomRef == 1"), or homs ("isHomVar == 1"). Also available are
+ * expressions isCalled, isNoCall, isMixed, and isAvailable, in accordance with the methods of the Genotype object.
+ */
+ @Argument(fullName="genotypeFilterExpression", shortName="G_filter", doc="One or more expression used with FORMAT (sample/genotype-level) fields to filter (see documentation guide for more info)", required=false)
+ protected ArrayList<String> GENOTYPE_FILTER_EXPS = new ArrayList<String>();
+
+ /**
+ * Similar to the INFO field based expressions, but used on the FORMAT (genotype) fields instead.
+ */
+ @Argument(fullName="genotypeFilterName", shortName="G_filterName", doc="Names to use for the list of sample/genotype filters (must be a 1-to-1 mapping); this name is put in the FILTER field for variants that get filtered", required=false)
+ protected ArrayList<String> GENOTYPE_FILTER_NAMES = new ArrayList<String>();
+
+ /**
+ * Works together with the --clusterWindowSize argument.
+ */
+ @Argument(fullName="clusterSize", shortName="cluster", doc="The number of SNPs which make up a cluster", required=false)
+ protected Integer clusterSize = 3;
+
+ /**
+ * Works together with the --clusterSize argument. To disable the clustered SNP filter, set this value to less than 1.
+ */
+ @Argument(fullName="clusterWindowSize", shortName="window", doc="The window size (in bases) in which to evaluate clustered SNPs", required=false)
+ protected Integer clusterWindow = 0;
+
+ @Argument(fullName="maskExtension", shortName="maskExtend", doc="How many bases beyond records from a provided 'mask' rod should variants be filtered", required=false)
+ protected Integer MASK_EXTEND = 0;
+
+ /**
+ * When using the -mask argument, the maskName will be annotated in the variant record.
+ * Note that when using the -filterNotInMask argument to reverse the masking logic,
+ * it is up to the user to adapt the name of the mask to make it clear that the reverse logic was used
+ * (e.g. if masking against Hapmap, use -maskName=hapmap for the normal masking and -maskName=not_hapmap for the reverse masking).
+ */
+ @Argument(fullName="maskName", shortName="maskName", doc="The text to put in the FILTER field if a 'mask' rod is provided and overlaps with a variant call", required=false)
+ protected String MASK_NAME = "Mask";
+
+ /**
+ * By default, if the -mask argument is used, any variant falling in a mask will be filtered.
+ * If this argument is used, logic is reversed, and variants falling outside a given mask will be filtered.
+ * Use case is, for example, if we have an interval list or BED file with "good" sites.
+ * Note that it is up to the user to adapt the name of the mask to make it clear that the reverse logic was used
+ * (e.g. if masking against Hapmap, use -maskName=hapmap for the normal masking and -maskName=not_hapmap for the reverse masking).
+ */
+ @Argument(fullName="filterNotInMask", shortName="filterNotInMask", doc="Filter records NOT in given input mask.", required=false)
+ protected boolean filterRecordsNotInMask = false;
+
+ /**
+ * By default, if JEXL cannot evaluate your expression for a particular record because one of the annotations is not present, the whole expression evaluates as PASSing.
+ * Use this argument to have it evaluate as failing filters instead for these cases.
+ */
+ @Argument(fullName="missingValuesInExpressionsShouldEvaluateAsFailing", doc="When evaluating the JEXL expressions, missing values should be considered failing the expression", required=false)
+ protected Boolean FAIL_MISSING_VALUES = false;
+
+ /**
+ * Invalidate previous filters applied to the VariantContext, applying only the filters here
+ */
+ @Argument(fullName="invalidatePreviousFilters",doc="Remove previous filters applied to the VCF",required=false)
+ boolean invalidatePrevious = false;
+
+ // JEXL expressions for the filters
+ List<VariantContextUtils.JexlVCMatchExp> filterExps;
+ List<VariantContextUtils.JexlVCMatchExp> genotypeFilterExps;
+
+ public static final String CLUSTERED_SNP_FILTER_NAME = "SnpCluster";
+ private ClusteredSnps clusteredSNPs = null;
+ private GenomeLoc previousMaskPosition = null;
+
+ // the structures necessary to initialize and maintain a windowed context
+ private FiltrationContextWindow variantContextWindow;
+ private static final int windowSize = 10; // 10 variants on either end of the current one
+ private ArrayList<FiltrationContext> windowInitializer = new ArrayList<FiltrationContext>();
+
+ private void initializeVcfWriter() {
+
+ final List<String> inputNames = Arrays.asList(variantCollection.variants.getName());
+
+ // setup the header fields
+ Set<VCFHeaderLine> hInfo = new HashSet<VCFHeaderLine>();
+ hInfo.addAll(GATKVCFUtils.getHeaderFields(getToolkit(), inputNames));
+
+ if ( clusterWindow > 0 )
+ hInfo.add(new VCFFilterHeaderLine(CLUSTERED_SNP_FILTER_NAME, "SNPs found in clusters"));
+
+ if ( genotypeFilterExps.size() > 0 )
+ hInfo.add(VCFStandardHeaderLines.getFormatLine(VCFConstants.GENOTYPE_FILTER_KEY));
+
+ try {
+ for ( VariantContextUtils.JexlVCMatchExp exp : filterExps )
+ hInfo.add(new VCFFilterHeaderLine(exp.name, exp.exp.toString()));
+ for ( VariantContextUtils.JexlVCMatchExp exp : genotypeFilterExps )
+ hInfo.add(new VCFFilterHeaderLine(exp.name, exp.exp.toString()));
+
+ if ( mask.isBound() ) {
+ if (filterRecordsNotInMask)
+ hInfo.add(new VCFFilterHeaderLine(MASK_NAME, "Doesn't overlap a user-input mask"));
+ else hInfo.add(new VCFFilterHeaderLine(MASK_NAME, "Overlaps a user-input mask"));
+ }
+ } catch (IllegalArgumentException e) {
+ throw new UserException.BadInput(e.getMessage());
+ }
+
+ writer.writeHeader(new VCFHeader(hInfo, SampleUtils.getUniqueSamplesFromRods(getToolkit(), inputNames)));
+ }
+
+ public void initialize() {
+ if ( clusterWindow > 0 )
+ clusteredSNPs = new ClusteredSnps(getToolkit().getGenomeLocParser(),clusterSize, clusterWindow);
+
+ if ( MASK_EXTEND < 0 )
+ throw new UserException.BadArgumentValue("maskExtension", "negative values are not allowed");
+
+ if (filterRecordsNotInMask && !mask.isBound())
+ throw new UserException.BadArgumentValue("filterNotInMask","argument not allowed if mask argument is not provided");
+ filterExps = VariantContextUtils.initializeMatchExps(FILTER_NAMES, FILTER_EXPS);
+ genotypeFilterExps = VariantContextUtils.initializeMatchExps(GENOTYPE_FILTER_NAMES, GENOTYPE_FILTER_EXPS);
+
+ VariantContextUtils.engine.get().setSilent(true);
+
+ initializeVcfWriter();
+ }
+
+ public Integer reduceInit() { return 0; }
+
+ /**
+ *
+ * @param tracker the meta-data tracker
+ * @param ref the reference base
+ * @param context the context for the given locus
+ * @return 1 if the locus was successfully processed, 0 if otherwise
+ */
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null )
+ return 0;
+
+ Collection<VariantContext> VCs = tracker.getValues(variantCollection.variants, context.getLocation());
+
+ // is there a SNP mask present?
+ boolean hasMask = (tracker.hasValues(mask) && !filterRecordsNotInMask) || (filterRecordsNotInMask && !tracker.hasValues(mask));
+ if ( hasMask )
+ previousMaskPosition = ref.getLocus(); // multi-base masks will get triggered over all bases of the mask
+
+ for ( VariantContext vc : VCs ) {
+
+ if ( invalidatePrevious ) {
+ vc = (new VariantContextBuilder(vc)).filters(new HashSet<String>()).make();
+ }
+ // filter based on previous mask position
+ if ( previousMaskPosition != null && // we saw a previous mask site
+ previousMaskPosition.getContig().equals(vc.getChr()) && // it's on the same contig
+ vc.getStart() - previousMaskPosition.getStop() <= MASK_EXTEND && // it's within the mask area (multi-base masks that overlap this site will always give a negative distance)
+ (vc.getFilters() == null || !vc.getFilters().contains(MASK_NAME)) ) { // the filter hasn't already been applied
+ Set<String> filters = new LinkedHashSet<String>(vc.getFilters());
+ filters.add(MASK_NAME);
+ vc = new VariantContextBuilder(vc).filters(filters).make();
+ }
+
+ FiltrationContext varContext = new FiltrationContext(ref, vc);
+
+ // if we're still initializing the context, do so
+ if ( windowInitializer != null ) {
+
+ // if this is a mask position, filter previous records
+ if ( hasMask ) {
+ for ( FiltrationContext prevVC : windowInitializer )
+ prevVC.setVariantContext(checkMaskForPreviousLocation(prevVC.getVariantContext(), ref.getLocus()));
+ }
+
+ windowInitializer.add(varContext);
+ if ( windowInitializer.size() == windowSize ) {
+ variantContextWindow = new FiltrationContextWindow(windowInitializer);
+ windowInitializer = null;
+ }
+ } else {
+
+ // if this is a mask position, filter previous records
+ if ( hasMask ) {
+ for ( FiltrationContext prevVC : variantContextWindow.getWindow(10, 10) ) {
+ if ( prevVC != null )
+ prevVC.setVariantContext(checkMaskForPreviousLocation(prevVC.getVariantContext(), ref.getLocus()));
+ }
+ }
+
+ variantContextWindow.moveWindow(varContext);
+ filter();
+ }
+ }
+
+ return 1;
+ }
+
+ private VariantContext checkMaskForPreviousLocation(VariantContext vc, GenomeLoc maskLoc) {
+ if ( maskLoc.getContig().equals(vc.getChr()) && // it's on the same contig
+ maskLoc.getStart() - vc.getEnd() <= MASK_EXTEND && // it's within the mask area (multi-base VCs that overlap this site will always give a negative distance)
+ (vc.getFilters() == null || !vc.getFilters().contains(MASK_NAME)) ) { // the filter hasn't already been applied
+ Set<String> filters = new LinkedHashSet<String>(vc.getFilters());
+ filters.add(MASK_NAME);
+ vc = new VariantContextBuilder(vc).filters(filters).make();
+ }
+
+ return vc;
+ }
+
+ private void filter() {
+ // get the current context
+ FiltrationContext context = variantContextWindow.getContext();
+ if ( context == null )
+ return;
+
+ final VariantContext vc = context.getVariantContext();
+ final VariantContextBuilder builder = new VariantContextBuilder(vc);
+
+ // make new Genotypes based on filters
+ if ( genotypeFilterExps.size() > 0 ) {
+ GenotypesContext genotypes = GenotypesContext.create(vc.getGenotypes().size());
+
+ // for each genotype, check filters then create a new object
+ for ( final Genotype g : vc.getGenotypes() ) {
+ if ( g.isCalled() ) {
+ final List<String> filters = new ArrayList<String>();
+ if ( g.isFiltered() ) filters.add(g.getFilters());
+
+ for ( VariantContextUtils.JexlVCMatchExp exp : genotypeFilterExps ) {
+ if ( VariantContextUtils.match(vc, g, exp) )
+ filters.add(exp.name);
+ }
+
+ genotypes.add(new GenotypeBuilder(g).filters(filters).make());
+ } else {
+ genotypes.add(g);
+ }
+ }
+
+ builder.genotypes(genotypes);
+ }
+
+ // make a new variant context based on filters
+ Set<String> filters = new LinkedHashSet<String>(vc.getFilters());
+
+ // test for clustered SNPs if requested
+ if ( clusteredSNPs != null && clusteredSNPs.filter(variantContextWindow) )
+ filters.add(CLUSTERED_SNP_FILTER_NAME);
+
+ for ( VariantContextUtils.JexlVCMatchExp exp : filterExps ) {
+ try {
+ if ( VariantContextUtils.match(vc, exp) )
+ filters.add(exp.name);
+ } catch (Exception e) {
+ // do nothing unless specifically asked to; it just means that the expression isn't defined for this context
+ if ( FAIL_MISSING_VALUES )
+ filters.add(exp.name);
+ }
+ }
+
+ if ( filters.isEmpty() )
+ builder.passFilters();
+ else
+ builder.filters(filters);
+
+ writer.add(builder.make());
+ }
+
+ public Integer reduce(Integer value, Integer sum) {
+ return sum + value;
+ }
+
+ /**
+ * Tell the user the number of loci processed and close out the new variants file.
+ *
+ * @param result the number of loci seen.
+ */
+ public void onTraversalDone(Integer result) {
+ // move the window over so that we can filter the last few variants
+ if ( windowInitializer != null ) {
+ while ( windowInitializer.size() < windowSize )
+ windowInitializer.add(null);
+ variantContextWindow = new FiltrationContextWindow(windowInitializer);
+ }
+ for (int i=0; i < windowSize; i++) {
+ variantContextWindow.moveWindow(null);
+ filter();
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/AlleleList.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/AlleleList.java
new file mode 100644
index 0000000..3b0aded
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/AlleleList.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.genotyper;
+
+import htsjdk.variant.variantcontext.Allele;
+
+/**
+ * Created by valentin on 5/12/14.
+ */
+public interface AlleleList<A extends Allele> {
+
+ public int alleleCount();
+
+ public int alleleIndex(final A allele);
+
+ public A alleleAt(final int index);
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/AlleleListPermutation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/AlleleListPermutation.java
new file mode 100644
index 0000000..8d95fa4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/AlleleListPermutation.java
@@ -0,0 +1,35 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.genotyper;
+
+import htsjdk.variant.variantcontext.Allele;
+import org.broadinstitute.gatk.utils.collections.Permutation;
+
+/**
+ * Marks allele list permutation implementation classes.
+ */
+public interface AlleleListPermutation<A extends Allele> extends Permutation<A>, AlleleList<A> {
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/AlleleListUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/AlleleListUtils.java
new file mode 100644
index 0000000..4f40f51
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/AlleleListUtils.java
@@ -0,0 +1,334 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.genotyper;
+
+import htsjdk.variant.variantcontext.Allele;
+
+import java.util.AbstractList;
+import java.util.List;
+
+/**
+ * Utils operations on {@link AlleleList} instances.
+ *
+ * @author Valentin Ruano-Rubio <valentin at broadinstitute.org>
+ */
+public class AlleleListUtils {
+
+ @SuppressWarnings("unchecked")
+ private static final AlleleList EMPTY_LIST = new AlleleList() {
+ @Override
+ public int alleleCount() {
+ return 0;
+ }
+
+ @Override
+ public int alleleIndex(final Allele allele) {
+ return -1;
+ }
+
+ @Override
+ public Allele alleleAt(final int index) {
+ throw new IllegalArgumentException("allele index is out of range");
+ }
+ };
+
+ /**
+ * Checks whether two allele lists are in fact the same.
+ * @param first one list to compare.
+ * @param second another list to compare.
+ *
+ * @throws IllegalArgumentException if if either list is {@code null}.
+ *
+ * @return {@code true} iff both list are equal.
+ */
+ public static <A extends Allele> boolean equals(final AlleleList<A> first, final AlleleList<A> second) {
+ if (first == null || second == null)
+ throw new IllegalArgumentException("no null list allowed");
+ final int alleleCount = first.alleleCount();
+ if (alleleCount != second.alleleCount())
+ return false;
+
+ for (int i = 0; i < alleleCount; i++) {
+ final A firstSample = first.alleleAt(i);
+ if (firstSample == null)
+ throw new IllegalStateException("no null samples allowed in sample-lists: first list at " + i);
+ final A secondSample = second.alleleAt(i);
+ if (secondSample == null)
+ throw new IllegalArgumentException("no null samples allowed in sample-list: second list at " + i);
+ if (!firstSample.equals(secondSample))
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Resolves the index of the reference allele in an allele-list.
+ *
+ * <p>
+ * If there is no reference allele, it returns -1. If there is more than one reference allele,
+ * it returns the first occurrence (lowest index).
+ * </p>
+ *
+ * @param list the search allele-list.
+ * @param <A> allele component type.
+ *
+ * @throws IllegalArgumentException if {@code list} is {@code null}.
+ *
+ * @return -1 if there is no reference allele, or a values in [0,{@code list.alleleCount()}).
+ */
+ public static <A extends Allele> int indexOfReference(final AlleleList<A> list) {
+ if (list == null)
+ throw new IllegalArgumentException("the input list cannot be null");
+ final int alleleCount = list.alleleCount();
+ for (int i = 0; i < alleleCount; i++)
+ if (list.alleleAt(i).isReference())
+ return i;
+ return -1;
+ }
+
+
+ /**
+ * Returns a {@link java.util.List} unmodifiable view of a allele-list
+ * @param list the sample-list to wrap.
+ *
+ * @throws IllegalArgumentException if {@code list} is {@code null}.
+ *
+ * @return never {@code null}.
+ */
+ public static <A extends Allele> List<A> asList(final AlleleList<A> list) {
+ if (list == null)
+ throw new IllegalArgumentException("the list cannot be null");
+ return new AsList(list);
+ }
+
+ /**
+ * Returns an unmodifiable empty allele-list.
+ * @param <A> the allele class.
+ * @return never {@code null}.
+ */
+ @SuppressWarnings("unchecked")
+ public static final <A extends Allele> AlleleList<A> emptyList() {
+ return EMPTY_LIST;
+ }
+
+ /**
+ * Simple list view of a sample-list.
+ */
+ private static class AsList<A extends Allele> extends AbstractList<A> {
+
+ private final AlleleList<A> list;
+
+ private AsList(final AlleleList<A> list) {
+ this.list = list;
+
+ }
+
+ @Override
+ public A get(int index) {
+ return list.alleleAt(index);
+ }
+
+ @Override
+ public int size() {
+ return list.alleleCount();
+ }
+ }
+
+
+ /**
+ * Returns a permutation between two allele lists.
+ * @param original the original allele list.
+ * @param target the target allele list.
+ * @param <A> the allele type.
+ *
+ * @throws IllegalArgumentException if {@code original} or {@code target} is {@code null}, or
+ * elements in {@code target} is not contained in {@code original}
+ *
+ * @return never {@code null}
+ */
+ public static <A extends Allele> AlleleListPermutation<A> permutation(final AlleleList<A> original, final AlleleList<A> target) {
+ if (equals(original,target))
+ return new NonPermutation<>(original);
+ else
+ return new ActualPermutation<>(original,target);
+ }
+
+ private static class NonPermutation<A extends Allele> implements AlleleListPermutation<A> {
+
+ private final AlleleList<A> list;
+
+ public NonPermutation(final AlleleList<A> original) {
+ list = original;
+ }
+
+ @Override
+ public boolean isPartial() {
+ return false;
+ }
+
+ @Override
+ public boolean isNonPermuted() {
+ return true;
+ }
+
+ @Override
+ public int toIndex(int fromIndex) {
+ return fromIndex;
+ }
+
+ @Override
+ public int fromIndex(int toIndex) {
+ return toIndex;
+ }
+
+ @Override
+ public int fromSize() {
+ return list.alleleCount();
+ }
+
+ @Override
+ public int toSize() {
+ return list.alleleCount();
+ }
+
+ @Override
+ public List<A> fromList() {
+ return asList(list);
+ }
+
+ @Override
+ public java.util.List<A> toList() {
+ return asList(list);
+ }
+
+
+ @Override
+ public int alleleCount() {
+ return list.alleleCount();
+ }
+
+ @Override
+ public int alleleIndex(final A allele) {
+ return list.alleleIndex(allele);
+ }
+
+ @Override
+ public A alleleAt(final int index) {
+ return list.alleleAt(index);
+ }
+ }
+
+ private static class ActualPermutation<A extends Allele> implements AlleleListPermutation<A> {
+
+ private final AlleleList<A> from;
+
+ private final AlleleList<A> to;
+
+ private final int[] fromIndex;
+
+ private final boolean nonPermuted;
+
+ private final boolean isPartial;
+
+ private ActualPermutation(final AlleleList<A> original, final AlleleList<A> target) {
+ this.from = original;
+ this.to = target;
+ final int toSize = target.alleleCount();
+ final int fromSize = original.alleleCount();
+ if (fromSize < toSize)
+ throw new IllegalArgumentException("target allele list is not a permutation of the original allele list");
+
+ fromIndex = new int[toSize];
+ boolean nonPermuted = fromSize == toSize;
+ this.isPartial = !nonPermuted;
+ for (int i = 0; i < toSize; i++) {
+ final int originalIndex = original.alleleIndex(target.alleleAt(i));
+ if (originalIndex < 0)
+ throw new IllegalArgumentException("target allele list is not a permutation of the original allele list");
+ fromIndex[i] = originalIndex;
+ nonPermuted &= originalIndex == i;
+ }
+
+ this.nonPermuted = nonPermuted;
+ }
+
+ @Override
+ public boolean isPartial() {
+ return isPartial;
+ }
+
+ @Override
+ public boolean isNonPermuted() {
+ return nonPermuted;
+ }
+
+ @Override
+ public int toIndex(int fromIndex) {
+ return to.alleleIndex(from.alleleAt(fromIndex));
+ }
+
+ @Override
+ public int fromIndex(int toIndex) {
+ return fromIndex[toIndex];
+ }
+
+ @Override
+ public int fromSize() {
+ return from.alleleCount();
+ }
+
+ @Override
+ public int toSize() {
+ return to.alleleCount();
+ }
+
+ @Override
+ public List<A> fromList() {
+ return asList(from);
+ }
+
+ @Override
+ public List<A> toList() {
+ return asList(to);
+ }
+
+ @Override
+ public int alleleCount() {
+ return to.alleleCount();
+ }
+
+ @Override
+ public int alleleIndex(final A allele) {
+ return to.alleleIndex(allele);
+ }
+
+ @Override
+ public A alleleAt(final int index) {
+ return to.alleleAt(index);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/IndexedAlleleList.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/IndexedAlleleList.java
new file mode 100644
index 0000000..9238af7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/IndexedAlleleList.java
@@ -0,0 +1,95 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.genotyper;
+
+import htsjdk.variant.variantcontext.Allele;
+import org.broadinstitute.gatk.utils.collections.IndexedSet;
+
+import java.util.Collection;
+
+/**
+ * Allele list implementation using and indexed-set.
+ *
+ * @author Valentin Ruano-Rubio <valentin at broadinstitute.org>
+ */
+public class IndexedAlleleList<A extends Allele> implements AlleleList<A> {
+
+ private final IndexedSet<A> alleles;
+
+ /**
+ * Constructs a new empty allele-list
+ */
+ public IndexedAlleleList() {
+ alleles = new IndexedSet<>();
+ }
+
+ /**
+ * Constructs a new allele-list from an array of alleles.
+ *
+ * <p>
+ * Repeats in the input array will be ignored (keeping the first one). The order of alleles in the
+ * resulting list is the same as in the natural traversal of the input collection.
+ *
+ * </p>
+ * @param alleles the original allele array
+ *
+ * @throws java.lang.IllegalArgumentException if {@code alleles} is {@code null} or contains {@code null}s.
+ */
+ public IndexedAlleleList(final A ... alleles) {
+ this.alleles = new IndexedSet<>(alleles);
+ }
+
+ /**
+ * Constructs a new allele-list from a collection of alleles.
+ *
+ * <p>
+ * Repeats in the input collection will be ignored (keeping the first one). The order of alleles in the
+ * resulting list is the same as in the natural traversal of the input collection.
+ *
+ * </p>
+ * @param alleles the original allele collection
+ *
+ * @throws java.lang.IllegalArgumentException if {@code alleles} is {@code null} or contains {@code null}s.
+ */
+ public IndexedAlleleList(final Collection<A> alleles) {
+ this.alleles = new IndexedSet<>(alleles);
+ }
+
+ @Override
+ public int alleleCount() {
+ return alleles.size();
+ }
+
+ @Override
+ public int alleleIndex(final A allele) {
+ return alleles.indexOf(allele);
+ }
+
+ @Override
+ public A alleleAt(final int index) {
+ return alleles.get(index);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/IndexedSampleList.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/IndexedSampleList.java
new file mode 100644
index 0000000..94022c8
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/IndexedSampleList.java
@@ -0,0 +1,96 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.genotyper;
+
+import org.broadinstitute.gatk.utils.collections.IndexedSet;
+
+import java.util.Collection;
+
+/**
+ * Simple implementation of a sample-list using and indexed-set.
+ *
+ * @author Valentin Ruano-Rubio <valentin at broadinstitute.org>
+ */
+public class IndexedSampleList implements SampleList {
+
+ private final IndexedSet<String> samples;
+
+ /**
+ * Constructs an empty sample-list.
+ */
+ public IndexedSampleList() {
+ samples = new IndexedSet<>(0);
+ }
+
+ /**
+ * Constructs a sample-list from a collection of samples.
+ *
+ * <p>
+ * Repeats in the input collection are ignored (just the first occurrence is kept).
+ * Sample names will be sorted based on the traversal order
+ * of the original collection.
+ * </p>
+ *
+ * @param samples input sample collection.
+ *
+ * @throws IllegalArgumentException if {@code samples} is {@code null} or it contains {@code nulls}.
+ */
+ public IndexedSampleList(final Collection<String> samples) {
+ this.samples = new IndexedSet<>(samples);
+ }
+
+ /**
+ * Constructs a sample-list from an array of samples.
+ *
+ * <p>
+ * Repeats in the input array are ignored (just the first occurrence is kept).
+ * Sample names will be sorted based on the traversal order
+ * of the original array.
+ * </p>
+ *
+ * @param samples input sample array.
+ *
+ * @throws IllegalArgumentException if {@code samples} is {@code null} or it contains {@code nulls}.
+ */
+ public IndexedSampleList(final String ... samples) {
+ this.samples = new IndexedSet<>(samples);
+ }
+
+ @Override
+ public int sampleCount() {
+ return samples.size();
+ }
+
+ @Override
+ public int sampleIndex(final String sample) {
+ return samples.indexOf(sample);
+ }
+
+ @Override
+ public String sampleAt(int sampleIndex) {
+ return samples.get(sampleIndex);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/SampleList.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/SampleList.java
new file mode 100644
index 0000000..29cb428
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/SampleList.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.genotyper;
+
+/**
+ * A indexed set of samples.
+ *
+ * <p>
+ * Implementing classes must guarantee that the sample list will remain <b>constant</b> through the life of the object.
+ * </p>
+ */
+public interface SampleList {
+
+ public int sampleCount();
+
+ public int sampleIndex(final String sample);
+
+ public String sampleAt(final int sampleIndex);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/SampleListUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/SampleListUtils.java
new file mode 100644
index 0000000..2071f5d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/genotyper/SampleListUtils.java
@@ -0,0 +1,224 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.genotyper;
+
+import java.util.*;
+
+/**
+ * Some utility operations on sample lists.
+ *
+ * @author Valentin Ruano-Rubio <valentin at broadinstitute.org>
+ */
+public class SampleListUtils {
+
+ private static final SampleList EMPTY_LIST = new SampleList() {
+
+ @Override
+ public int sampleCount() {
+ return 0;
+ }
+
+ @Override
+ public int sampleIndex(String sample) {
+ return -1;
+ }
+
+ @Override
+ public String sampleAt(final int sampleIndex) {
+ throw new IllegalArgumentException("index is out of valid range");
+ }
+ };
+
+ /**
+ * Empty list.
+ *
+ * @return never {@code null}
+ */
+ public static SampleList emptyList() {
+ return EMPTY_LIST;
+ }
+
+ /**
+ * Checks whether two sample lists are in fact the same.
+ * @param first one list to compare.
+ * @param second another list to compare.
+ *
+ * @throws IllegalArgumentException if if either list is {@code null}.
+ *
+ * @return {@code true} iff both list are equal.
+ */
+ public static boolean equals(final SampleList first, final SampleList second) {
+ if (first == null || second == null)
+ throw new IllegalArgumentException("no null list allowed");
+ final int sampleCount = first.sampleCount();
+ if (sampleCount != second.sampleCount())
+ return false;
+
+ for (int i = 0; i < sampleCount; i++) {
+ final String firstSample = first.sampleAt(i);
+ if (firstSample == null)
+ throw new IllegalStateException("no null samples allowed in sample-lists: first list at " + i);
+ final String secondSample = second.sampleAt(i);
+ if (secondSample == null)
+ throw new IllegalArgumentException("no null samples allowed in sample-list: second list at " + i);
+ if (!firstSample.equals(secondSample))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns a {@link List} unmodifiable view of a sample-list
+ * @param list the sample-list to wrap.
+ *
+ * @throws IllegalArgumentException if {@code list} is {@code null}.
+ *
+ * @return never {@code null}.
+ */
+ public static List<String> asList(final SampleList list) {
+ if (list == null)
+ throw new IllegalArgumentException("the list cannot be null");
+ return new AsList(list);
+ }
+
+ /**
+ * Returns a {@link Set} unmodifiable view of the sample-list
+ *
+ * @param list the sample-list to wrap.
+ *
+ * @throws IllegalArgumentException if {@code list} is {@code null}
+ */
+ public static Set<String> asSet(final SampleList list) {
+ if (list == null)
+ throw new IllegalArgumentException("the list cannot be null");
+ return new AsSet(list);
+ }
+
+ /**
+ * Creates a list with a single sample.
+ *
+ * @param sampleName the sample name.
+ * @return never {@code sampleName}
+ */
+ public static SampleList singletonList(final String sampleName) {
+ if (sampleName == null)
+ throw new IllegalArgumentException("the sample name cannot be null");
+ return new SampleList() {
+
+ @Override
+ public int sampleCount() {
+ return 1;
+ }
+
+ @Override
+ public int sampleIndex(final String sample) {
+ return sampleName.equals(sample) ? 0 : -1;
+ }
+
+ @Override
+ public String sampleAt(int sampleIndex) {
+ if (sampleIndex == 0)
+ return sampleName;
+ throw new IllegalArgumentException("index is out of bounds");
+ }
+ };
+ }
+
+ /**
+ * Simple list view of a sample-list.
+ */
+ private static class AsList extends AbstractList<String> {
+
+ private final SampleList list;
+
+ private AsList(final SampleList list) {
+ this.list = list;
+
+ }
+
+ @Override
+ public String get(int index) {
+ return list.sampleAt(index);
+ }
+
+ @Override
+ public int size() {
+ return list.sampleCount();
+ }
+ }
+
+ /**
+ * Simple set view of a sample-list
+ */
+ private static class AsSet extends AbstractSet<String> {
+
+ private final SampleList list;
+
+ private AsSet(final SampleList list) {
+ this.list = list;
+
+ }
+
+ @Override
+ public Iterator<String> iterator() {
+ return new Iterator<String>() {
+ private int index = 0;
+
+ @Override
+ public boolean hasNext() {
+ return index < list.sampleCount();
+ }
+
+ @Override
+ public String next() {
+ if (index >= list.sampleCount())
+ throw new NoSuchElementException("iterating beyond sample list end");
+ return list.sampleAt(index++);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("unsupported operation exception");
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return list.sampleCount();
+ }
+
+ @Override
+ public boolean contains(final Object obj) {
+ if (obj == null)
+ return false;
+ else if (obj instanceof String)
+ return list.sampleIndex(((String)obj)) >= 0;
+ else
+ return false;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HCMappingQualityFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HCMappingQualityFilter.java
new file mode 100644
index 0000000..ce6fe06
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/haplotypecaller/HCMappingQualityFilter.java
@@ -0,0 +1,54 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.haplotypecaller;
+
+import htsjdk.samtools.SAMRecord;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+
+/**
+ * Filter out reads with low mapping qualities.
+ *
+ * @author mdepristo
+ */
+public class HCMappingQualityFilter extends ReadFilter {
+ private final static Logger logger = Logger.getLogger(HCMappingQualityFilter.class);
+
+ @Argument(fullName = "min_mapping_quality_score", shortName = "mmq", doc = "Minimum read mapping quality required to consider a read for analysis with the HaplotypeCaller", required = false)
+ public int MIN_MAPPING_QUALTY_SCORE = 20;
+
+ @Override
+ public void initialize(GenomeAnalysisEngine engine) {
+ if ( MIN_MAPPING_QUALTY_SCORE > 0 )
+ logger.info("Filtering out reads with MAPQ < " + MIN_MAPPING_QUALTY_SCORE);
+ }
+
+ public boolean filterOut(SAMRecord rec) {
+ return (rec.getMappingQuality() < MIN_MAPPING_QUALTY_SCORE);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/package-info.java
new file mode 100644
index 0000000..4201ef0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers;
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CheckPileup.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CheckPileup.java
new file mode 100644
index 0000000..a3848dc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CheckPileup.java
@@ -0,0 +1,258 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.LocusWalker;
+import org.broadinstitute.gatk.engine.walkers.Requires;
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.codecs.sampileup.SAMPileupFeature;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+
+/**
+ * Compare GATK's internal pileup to a reference Samtools pileup
+ *
+ * <p>At every locus in the input set, compares the pileup data (reference base, aligned base from
+ * each overlapping read, and quality score) generated internally by GATK to a reference pileup data generated
+ * by Samtools. Note that the pileup program has been replaced in Samtools by mpileup, which produces a slightly
+ * different output format by default.
+ * </p>
+ *
+ * <h3>Format</h3>
+ * <p>There are two versions of the original pileup format: the current 6-column format produced by Samtools, and the old
+ * 10-column "consensus" format which could be obtained by using the -c argument, now deprecated.</p>
+ * <h4>Simple pileup: 6-column format</h4>
+ * <p>
+ * Each line consists of chromosome, 1-based coordinate, reference base, the
+ * number of reads covering the site, read bases and base qualities. At the
+ * read base column, a dot stands for a match to the reference base on the
+ * forward strand, a comma for a match on the reverse strand, `ACGTN' for a mismatch
+ * on the forward strand and `acgtn' for a mismatch on the reverse strand.
+ * A pattern `\+[0-9]+[ACGTNacgtn]+' indicates there is an insertion between
+ * this reference position and the next reference position. The length of the
+ * insertion is given by the integer in the pattern, followed by the inserted sequence.
+ * </p>
+ * <pre>
+ * seq1 272 T 24 ,.$.....,,.,.,...,,,.,..^+. <<<+;<<<<<<<<<<<=<;<;7<&
+ * seq1 273 T 23 ,.....,,.,.,...,,,.,..A <<<;<<<<<<<<<3<=<<<;<<+
+ * seq1 274 T 23 ,.$....,,.,.,...,,,.,... 7<7;<;<<<<<<<<<=<;<;<<6
+ * seq1 275 A 23 ,$....,,.,.,...,,,.,...^l. <+;9*<<<<<<<<<=<<:;<<<<
+ * seq1 276 G 22 ...T,,.,.,...,,,.,.... 33;+<<7=7<<7<&<<1;<<6<
+ * seq1 277 T 22 ....,,.,.,.C.,,,.,..G. +7<;<<<<<<<&<=<<:;<<&<
+ * seq1 278 G 23 ....,,.,.,...,,,.,....^k. %38*<<;<7<<7<=<<<;<<<<<
+ * seq1 279 C 23 A..T,,.,.,...,,,.,..... ;75&<<<<<<<<<=<<<9<<:<<
+ * </pre>
+ * <p>
+ * See the <a href="http://samtools.sourceforge.net/pileup.shtml">Pileup format documentation</a> for more details.
+ * </p>
+ *
+ * <h4>Consensus pileup: 10/13-column format</h4>
+ * <p>The "consensus" or extended pileup consists of the following:
+ * <ul>
+ * <li>original 6 columns as described above</li>
+ * <li>4 extra columns representing consensus values (consensus base, consensus quality, variant quality and maximum mapping quality of the
+ * reads covering the sites) for all sites, inserted before the bases and quality strings</li>
+ * <li>3 extra columns indicating counts of reads supporting indels (just for indel sites)</li>
+ * </ul>
+ * </p>
+ * <h4>Example of consensus pileup for SNP or non-variant sites</h4>
+ * <pre>
+ * seq1 60 T T 66 0 99 13 ...........^~.^~. 9<<55<;<<<<<<
+ * seq1 61 G G 72 0 99 15 .............^~.^y. (;975&;<<<<<<<<
+ * seq1 62 T T 72 0 99 15 .$.............. <;;,55;<<<<<<<<
+ * seq1 63 G G 72 0 99 15 .$.............^~. 4;2;<7:+<<<<<<<
+ * seq1 64 G G 69 0 99 14 .............. 9+5<;;;<<<<<<<
+ * seq1 65 A A 69 0 99 14 .$............. <5-2<;;<<<<<<;
+ * seq1 66 C C 66 0 99 13 ............. &*<;;<<<<<<8<
+ * seq1 67 C C 69 0 99 14 .............^~. ,75<.4<<<<<-<<
+ * seq1 68 C C 69 0 99 14 .............. 576<;7<<<<<8<< *
+ * </pre>
+ *
+ * <h4>Example of consensus pileup for indels</h4>
+ * <pre>
+ * Escherichia_coli_K12 3995037 * *\/* 430 0 37 144 * +A 143 1 0
+ * Escherichia_coli_K12 3995279 * *\/* 202 0 36 68 * +A 67 1 0
+ * Escherichia_coli_K12 3995281 * *\/* 239 0 36 67 * -CG 66 1 0
+ * </pre>
+ * <p>
+ * See <a href="http://samtools.sourceforge.net/cns0.shtml/">Consensus pileup format (deprecated)</a> for more details.
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>A BAM file conatining your aligned sequence data and a pileup file generated by Samtools covering the region you
+ * want to examine.</p>
+ *
+ * <h3>Output</h3>
+ * <p>A text file listing mismatches between the input pileup and the GATK's internal pileup. If there are no mismatches, the output file is empty.</p>
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java -jar GenomeAnalysisTK.jar \
+ * -T CheckPileup \
+ * -R ref.fasta \
+ * -I your_data.bam \
+ * --pileup:SAMPileup pileup_file.txt \
+ * -L chr1:257-275 \
+ * -o output_file_name
+ * </pre>
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+ at Requires(value={DataSource.READS,DataSource.REFERENCE})
+public class CheckPileup extends LocusWalker<Integer, CheckPileupStats> implements TreeReducible<CheckPileupStats> {
+ /**
+ * This is the existing pileup against which we'll compare GATK's internal pileup at each genome position in the desired interval.
+ */
+ @Input(fullName = "pileup", shortName = "pileup", doc="Pileup generated by Samtools", required = true)
+ RodBinding<SAMPileupFeature> pileup;
+
+ @Output
+ private PrintStream out;
+ /**
+ * By default the program will quit if it encounters an error (such as missing truth data for a given position).
+ * Use this flag to override the default behavior; the program will then simply print an error message and move on
+ * to the next position.
+ */
+ @Argument(fullName="continue_after_error",doc="Continue after encountering an error",required=false)
+ public boolean CONTINUE_AFTER_AN_ERROR = false;
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ ReadBackedPileup pileup = context.getBasePileup();
+ SAMPileupFeature truePileup = getTruePileup( tracker );
+
+ if ( truePileup == null ) {
+ out.printf("No truth pileup data available at %s%n", pileup.getPileupString(ref.getBaseAsChar()));
+ if ( ! CONTINUE_AFTER_AN_ERROR ) {
+ throw new UserException.BadInput(String.format("No pileup data available at %s given GATK's output of %s -- this walker requires samtools pileup data over all bases",
+ context.getLocation(), new String(pileup.getBases())));
+ }
+ } else {
+ String pileupDiff = pileupDiff(pileup, truePileup, true);
+ if ( pileupDiff != null ) {
+ out.printf("%s vs. %s%n", pileup.getPileupString(ref.getBaseAsChar()), truePileup.getPileupString());
+ if ( ! CONTINUE_AFTER_AN_ERROR ) {
+ throw new UserException.BadInput(String.format("The input pileup doesn't match the GATK's internal pileup: %s", pileupDiff));
+ }
+ }
+ }
+
+ return pileup.getNumberOfElements();
+ }
+
+ private static String maybeSorted( final String x, boolean sortMe )
+ {
+ if ( sortMe ) {
+ byte[] bytes = x.getBytes();
+ Arrays.sort(bytes);
+ return new String(bytes);
+ }
+ else
+ return x;
+ }
+
+ public String pileupDiff(final ReadBackedPileup a, final SAMPileupFeature b, boolean orderDependent)
+ {
+ if ( a.getNumberOfElements() != b.size() )
+ return "Sizes not equal";
+ GenomeLoc featureLocation = getToolkit().getGenomeLocParser().createGenomeLoc(b.getChr(),b.getStart(),b.getEnd());
+ if ( a.getLocation().compareTo(featureLocation) != 0 )
+ return "Locations not equal";
+
+ String aBases = maybeSorted(new String(a.getBases()), ! orderDependent );
+ String bBases = maybeSorted(b.getBasesAsString(), ! orderDependent );
+ if ( ! aBases.toUpperCase().equals(bBases.toUpperCase()) )
+ return "Bases not equal";
+
+ String aQuals = maybeSorted(new String(a.getQuals()), ! orderDependent );
+ String bQuals = maybeSorted(new String(b.getQuals()), ! orderDependent );
+ if ( ! aQuals.equals(bQuals) )
+ return "Quals not equal";
+
+ return null;
+ }
+
+ // Given result of map function
+ public CheckPileupStats reduceInit() { return new CheckPileupStats(); }
+ public CheckPileupStats reduce(Integer value, CheckPileupStats sum) {
+ sum.nLoci++;
+ sum.nBases += value;
+ return sum;
+ }
+
+ public CheckPileupStats treeReduce( CheckPileupStats lhs, CheckPileupStats rhs ) {
+ CheckPileupStats combined = new CheckPileupStats();
+ combined.nLoci = lhs.nLoci + rhs.nLoci;
+ combined.nBases = lhs.nBases + rhs.nBases;
+ return combined;
+ }
+
+ /**
+ * Extracts the true pileup data from the given rodSAMPileup. Note that this implementation
+ * assumes that the genotype will only be point or indel.
+ * @param tracker ROD tracker from which to extract pileup data.
+ * @return True pileup data.
+ */
+ private SAMPileupFeature getTruePileup( RefMetaDataTracker tracker ) {
+ SAMPileupFeature pileupArg = tracker.getFirstValue(pileup);
+
+ if( pileupArg == null)
+ return null;
+
+ if( pileupArg.hasPointGenotype() )
+ return pileupArg.getPointGenotype();
+ else if( pileupArg.hasIndelGenotype() )
+ return pileupArg.getIndelGenotype();
+ else
+ throw new ReviewedGATKException("Unsupported pileup type: " + pileupArg);
+ }
+}
+
+class CheckPileupStats {
+ public long nLoci = 0;
+ public long nBases = 0;
+
+ public CheckPileupStats() {
+ }
+
+ public String toString() {
+ return String.format("Validated %d sites covered by %d bases%n", nLoci, nBases);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountBases.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountBases.java
new file mode 100644
index 0000000..1500ce3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountBases.java
@@ -0,0 +1,74 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.Requires;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+/**
+ * Walks over the input data set, calculating the number of bases seen for diagnostic purposes.
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more BAM files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Number of bases seen.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T CountBases \
+ * -I input.bam \
+ * [-L input.intervals]
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+ at Requires({DataSource.READS, DataSource.REFERENCE})
+public class CountBases extends ReadWalker<Integer, Long> {
+ public Integer map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker tracker) {
+
+ return read.getReadLength();
+ }
+
+ public Long reduceInit() { return 0L; }
+
+ public Long reduce(Integer value, Long sum) {
+ return (long) value + sum;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountIntervals.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountIntervals.java
new file mode 100644
index 0000000..221c4a9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountIntervals.java
@@ -0,0 +1,128 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RefWalker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.io.PrintStream;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Count contiguous regions in an interval list.
+ *
+ * <p>When the GATK reads in intervals from an intervals list, any intervals that overlap each other get merged into
+ * a single interval spanning the original ones. For example, if you have the following intervals:
+ * <ul><li>
+ * 20:1-2000
+ * </li><li>
+ * 20:1500-3000
+ * </li></ul>
+ * They will be merged into a single interval:
+ * <ul><li>20:1-3000</li></ul>
+ *
+ * This tool allows you to check, for a given list of intervals, how many separate intervals the GATK will actually
+ * distinguish at runtime.
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more rod files containing intervals to check.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Number of separate intervals identified by GATK after merging overlapping intervals.
+ * </p>
+ *
+ * You can use the -numOverlaps argument to find out how many cases you have of a specific number of overlaps.
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -T CountIntervals \
+ * -R ref.fasta \
+ * -0 output.txt \
+ * -check intervals.list
+ * </pre>
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class CountIntervals extends RefWalker<Long, Long> {
+ @Output
+ PrintStream out;
+
+ @Input(fullName="check", shortName = "check", doc="Any number of RODs", required=false)
+ public List<RodBinding<Feature>> features = Collections.emptyList();
+
+ @Argument(fullName="numOverlaps",shortName="no",doc="Count all occurrences of X or more overlapping intervals; defaults to 2", required=false)
+ int numOverlaps = 2;
+
+ public Long reduceInit() {
+ return 0l;
+ }
+
+ public boolean isReduceByInterval() { return true; }
+
+ public Long map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null ) {
+ return null;
+ }
+
+ List<Feature> checkIntervals = tracker.getValues(features);
+ return (long) checkIntervals.size();
+ }
+
+ public Long reduce(Long loc, Long prev) {
+ if ( loc == null ) {
+ return 0l;
+ } else {
+ return Math.max(prev,loc);
+ }
+ }
+
+ public void onTraversalDone(List<Pair<GenomeLoc,Long>> finalReduce) {
+ long count = 0;
+ for ( Pair<GenomeLoc,Long> g : finalReduce ) {
+ if ( g.second >= numOverlaps) {
+ count ++;
+ }
+ }
+ out.printf("Number of contiguous intervals: %d",count);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountLoci.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountLoci.java
new file mode 100644
index 0000000..51c1617
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountLoci.java
@@ -0,0 +1,96 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.LocusWalker;
+import org.broadinstitute.gatk.engine.walkers.NanoSchedulable;
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.io.PrintStream;
+
+/**
+ * Walks over the input data set, calculating the total number of covered loci for diagnostic purposes.
+ *
+ * <p>
+ * This is the simplest example of a locus walker.
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more BAM files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Number of loci traversed. If an output file name is provided, then the result will be written to that file.
+ * Otherwise it will be sent to standard console output.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -T CountLoci \
+ * -R ref.fasta \
+ * -I input.bam \
+ * -o output.txt \
+ * [-L input.intervals]
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class CountLoci extends LocusWalker<Integer, Long> implements TreeReducible<Long>, NanoSchedulable {
+ @Output
+ PrintStream out;
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ return 1;
+ }
+
+ public Long reduceInit() { return 0l; }
+
+ public Long reduce(Integer value, Long sum) {
+ return value + sum;
+ }
+
+ /**
+ * Reduces two subtrees together. In this case, the implementation of the tree reduce
+ * is exactly the same as the implementation of the single reduce.
+ */
+ public Long treeReduce(Long lhs, Long rhs) {
+ return lhs + rhs;
+ }
+
+ public void onTraversalDone( Long c ) {
+ out.println(c);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountMales.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountMales.java
new file mode 100644
index 0000000..d665e61
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountMales.java
@@ -0,0 +1,85 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.samples.Gender;
+import org.broadinstitute.gatk.engine.samples.Sample;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.Requires;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.PrintStream;
+
+/**
+ * Walks over the input data set, calculating the number of reads seen from male samples for diagnostic purposes.
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more BAM files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Number of reads seen from male samples.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -T CountMales \
+ * -R ref.fasta \
+ * -I samples.bam \
+ * -o output.txt
+ * </pre>
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+ at Requires({DataSource.READS, DataSource.REFERENCE})
+public class CountMales extends ReadWalker<Integer, Integer> {
+ @Output
+ public PrintStream out;
+
+ public Integer map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker tracker) {
+ Sample sample = getSampleDB().getSample(read);
+ return sample.getGender() == Gender.MALE ? 1 : 0;
+ }
+
+ public Integer reduceInit() { return 0; }
+
+ public Integer reduce(Integer value, Integer sum) {
+ return value + sum;
+ }
+
+ public void onTraversalDone( Integer c ) {
+ out.println(c);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountRODs.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountRODs.java
new file mode 100644
index 0000000..e068ff7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountRODs.java
@@ -0,0 +1,214 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.engine.walkers.NanoSchedulable;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.collections.ExpandingArrayList;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.io.PrintStream;
+import java.util.*;
+
+/**
+ * Prints out counts of the number of reference ordered data objects encountered.
+ *
+ * <p>CountRods is a RODWalker, and so traverses the data by ROD. For example if the ROD passed to it is a VCF file,
+ * it will count the variants in the file.</p>
+ *
+ * <p>Note that this tool is different from CountRodsByRef which is a RefWalker, and so traverses the data by
+ * position along the reference. CountRodsByRef can count ROD elements (such as, but not limited to, variants) found
+ * at each position or within specific intervals if you use the -L argument (see CommandLineGATK).</p>
+ *
+ * <p>Both these tools are different from CountVariants in that they are more generic (they can also count RODs that
+ * are not variants) and CountVariants is more detailed, in that it computes additional statistics (type of variants
+ * being indels vs. SNPs etc). </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more rod files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Number of rods seen.
+ * </p>
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -T CountRODs \
+ * -R ref.fasta \
+ * -o output.txt \
+ * --rod input.vcf
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class CountRODs extends RodWalker<CountRODs.Datum, Pair<ExpandingArrayList<Long>, Long>> implements TreeReducible<Pair<ExpandingArrayList<Long>, Long>>, NanoSchedulable {
+ @Output
+ public PrintStream out;
+
+ /**
+ * One or more input rod files
+ */
+ @Input(fullName="rod", shortName = "rod", doc="Input VCF file(s)", required=true)
+ public List<RodBinding<Feature>> rods = Collections.emptyList();
+
+ @Argument(fullName = "verbose", shortName = "v", doc="If true, this tool will print out detailed information about the rods it finds and locations", required = false)
+ public boolean verbose = false;
+
+ @Argument(fullName = "showSkipped", shortName = "s", doc="If true, this tool will print out the skipped locations", required = false)
+ public boolean showSkipped = false;
+
+ @Override
+ public Pair<ExpandingArrayList<Long>, Long> treeReduce(Pair<ExpandingArrayList<Long>, Long> lhs, Pair<ExpandingArrayList<Long>, Long> rhs) {
+ ExpandingArrayList<Long> nt = new ExpandingArrayList<Long>();
+ nt.addAll(lhs.first);
+ int index = 0;
+ for (Long l : rhs.first) {
+ if (nt.get(index) == null)
+ nt.add(l);
+ else
+ nt.set(index,nt.get(index) + l);
+ index++;
+ }
+ return new Pair<ExpandingArrayList<Long>, Long>(nt, lhs.second + rhs.second);
+ }
+
+ public class Datum {
+ public long nRodsAtThisLocation = 0;
+ public long nSkippedBases =0;
+ public long nTotalBases = 0;
+
+ public Datum( long nRodsAtThisLocation, long nSkippedBases, long nTotalBases ) {
+ this.nRodsAtThisLocation = nRodsAtThisLocation;
+ this.nSkippedBases = nSkippedBases;
+ this.nTotalBases = nTotalBases;
+ }
+
+ public String toString() {
+ return String.format("<%d %d %d>", nRodsAtThisLocation, nSkippedBases, nTotalBases);
+ }
+ }
+
+ public Datum map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ GenomeLoc cur = context.getLocation();
+
+ if ( verbose && showSkipped ) {
+ for(long i = context.getSkippedBases(); i >= 0; i--) {
+ SAMSequenceDictionary dictionary = getToolkit().getReferenceDataSource().getReference().getSequenceDictionary();
+ SAMSequenceRecord contig = dictionary.getSequence(cur.getContig());
+ if(cur.getStop() < contig.getSequenceLength())
+ cur = getToolkit().getGenomeLocParser().incPos(cur,1);
+ else
+ cur = getToolkit().getGenomeLocParser().createGenomeLoc(dictionary.getSequence(contig.getSequenceIndex()+1).getSequenceName(),1,1);
+ out.printf("%s: skipped%n", cur);
+
+ }
+ }
+
+ long nRodsHere = 0;
+ long nTotalBases = 0;
+
+ if ( ref == null ) {
+ // we're getting the last skipped update
+ if ( verbose )
+ out.printf("Last position was %s: skipping %d bases%n",
+ context.getLocation(), context.getSkippedBases() );
+ nRodsHere = -1; // don't update this
+ nTotalBases = context.getSkippedBases();
+ } else {
+ Collection<RODRecordList> rods = new LinkedList<RODRecordList>();
+ for ( RODRecordList rod : tracker.getBoundRodTracks() ) {
+ //System.out.printf("Considering rod %s%n", rod);
+ if ( rod.getLocation().getStart() == context.getLocation().getStart() && ! rod.getName().equals("interval") ) {
+ // only consider the first element
+ //System.out.printf("adding it%n");
+ rods.add(rod);
+ }
+ }
+
+ nRodsHere = rods.size();
+
+ if ( nRodsHere > 0 ) {
+ if ( verbose ) {
+ List<String> names = new ArrayList<String>();
+ for ( RODRecordList rod : rods ) {
+ names.add(rod.getName());
+ }
+
+ //System.out.printf("context is %s", context.getSkippedBases());
+ out.printf("At %s: found %d rod(s) [%s] after skipping %d bases%n",
+ context.getLocation(), nRodsHere, Utils.join(",", names), context.getSkippedBases() );
+ }
+ }
+
+ nTotalBases = context.getSkippedBases() + 1;
+ }
+
+ return new Datum(nRodsHere, context.getSkippedBases(), nTotalBases);
+ }
+
+ public Pair<ExpandingArrayList<Long>, Long> reduceInit() {
+ return new Pair<ExpandingArrayList<Long>, Long>(new ExpandingArrayList<Long>(), 0l);
+ }
+
+ private void updateCounts(ExpandingArrayList<Long> counts, long nRods, long nObs) {
+ if ( nRods >= 0 ) {
+ long prev = counts.get((int)nRods) == null ? 0l : counts.get((int)nRods);
+ counts.set((int)nRods, nObs + prev);
+ }
+ }
+
+ public Pair<ExpandingArrayList<Long>, Long> reduce(Datum point, Pair<ExpandingArrayList<Long>, Long> sum) {
+ ExpandingArrayList<Long> counts = sum.getFirst();
+ updateCounts(counts, point.nRodsAtThisLocation, 1);
+ updateCounts(counts, 0, point.nSkippedBases);
+
+ Pair<ExpandingArrayList<Long>, Long> r = new Pair<ExpandingArrayList<Long>, Long>(counts, point.nTotalBases + sum.getSecond());
+
+ //System.out.printf("Reduce: %s %s => %s%n", point, sum, r);
+ return r;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountRODsByRef.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountRODsByRef.java
new file mode 100644
index 0000000..40471b5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountRODsByRef.java
@@ -0,0 +1,112 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RefWalker;
+import org.broadinstitute.gatk.utils.collections.ExpandingArrayList;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Prints out counts of the number of reference ordered data objects encountered along the reference.
+ *
+ * <p>CountRodsByRef is a RefWalker, and so traverses the data by position along the reference. It counts ROD
+ * elements (such as, but not limited to, variants) found at each position or within specific intervals if you use
+ * the -L argument (see CommandLineGATK).</p>
+ *
+ * <p>Note that this tool is different from the basic CountRods, which is a RODWalker, and so traverses the data by
+ * ROD. For example if the ROD passed to it is a VCF file, CountRods will simply count the variants in the file.</p>
+ *
+ * <p>Both these tools are different from CountVariants in that they are more generic (they can also count RODs that
+ * are not variants) and CountVariants is more detailed, in that it computes additional statistics (type of variants
+ * being indels vs. SNPs etc). </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more rod files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Number of rods seen.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -T CountRODsByRef \
+ * -R ref.fasta \
+ * -o output.txt \
+ * --rod input.vcf
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class CountRODsByRef extends RefWalker<CountRODs.Datum, Pair<ExpandingArrayList<Long>, Long>> {
+
+ /**
+ * One or more input rod files
+ */
+ @Input(fullName="rod", shortName = "rod", doc="Input VCF file(s)", required=false)
+ public List<RodBinding<Feature>> rods = Collections.emptyList();
+
+ @Argument(fullName = "verbose", shortName = "v", doc="If true, this tool will print out detailed information about the rods it finds and locations", required = false)
+ public boolean verbose = false;
+
+ @Argument(fullName = "showSkipped", shortName = "s", doc="If true, this tool will print out the skipped locations", required = false)
+ public boolean showSkipped = false;
+
+ CountRODs crw = new CountRODs();
+
+ public void initialize() {
+ crw.verbose = verbose;
+ crw.showSkipped = showSkipped;
+ }
+
+ public CountRODs.Datum map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ return crw.map(tracker, ref, context);
+ }
+
+ public Pair<ExpandingArrayList<Long>, Long> reduceInit() {
+ return crw.reduceInit();
+ }
+
+ public Pair<ExpandingArrayList<Long>, Long> reduce(CountRODs.Datum point, Pair<ExpandingArrayList<Long>, Long> sum) {
+ return crw.reduce(point, sum);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountReadEvents.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountReadEvents.java
new file mode 100644
index 0000000..998448e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountReadEvents.java
@@ -0,0 +1,121 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import htsjdk.samtools.CigarOperator;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.report.GATKReport;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.Requires;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Walks over the input data set, counting the number of read events (from the CIGAR operator)
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more BAM files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Number of read events for each category, formatted as a GATKReport table.
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -T CountReadEvents \
+ * -R ref.fasta \
+ * -I input.bam \
+ * -o output.grp \
+ * [-L input.intervals]
+ * </pre>
+ */
+
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+ at Requires({DataSource.READS, DataSource.REFERENCE})
+public class CountReadEvents extends ReadWalker<Map<CigarOperator, ArrayList<Integer>> , Map<Integer, Map<CigarOperator, Long>>> {
+ @Output
+ PrintStream out;
+
+ public Map<CigarOperator, ArrayList<Integer>> map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker tracker) {
+ return ReadUtils.getCigarOperatorForAllBases(read);
+ }
+
+ public Map<Integer, Map<CigarOperator, Long>> reduceInit() {
+ return new HashMap<Integer, Map<CigarOperator, Long>>();
+ }
+
+ public Map<Integer, Map<CigarOperator, Long>> reduce(Map<CigarOperator, ArrayList<Integer>> value, Map<Integer, Map<CigarOperator, Long>> sum) {
+ for (Map.Entry<CigarOperator, ArrayList<Integer>> entry : value.entrySet()) {
+ CigarOperator op = entry.getKey();
+ ArrayList<Integer> positions = entry.getValue();
+
+ for (int p : positions) {
+ Map<CigarOperator, Long> operatorCount = sum.get(p);
+ if (operatorCount == null) {
+ operatorCount = new HashMap<CigarOperator, Long>();
+ sum.put(p, operatorCount);
+ }
+
+ Long count = operatorCount.get(op);
+ if (count == null)
+ count = 0L;
+ count++;
+ operatorCount.put(op, count);
+ }
+ }
+ return sum;
+ }
+
+ @Override
+ public void onTraversalDone(Map<Integer, Map<CigarOperator, Long>> result) {
+ GATKReport report = GATKReport.newSimpleReport("Events", "Position", "Event", "Observations");
+ for (Map.Entry<Integer, Map<CigarOperator, Long>> entry : result.entrySet()) {
+ int position = entry.getKey();
+ Map<CigarOperator, Long> operatorCount = entry.getValue();
+
+ for (Map.Entry<CigarOperator, Long> subEntry: operatorCount.entrySet()) {
+ String operator = subEntry.getKey().name();
+ Long observations = subEntry.getValue();
+ report.addRow(position, operator, observations);
+ }
+ }
+ report.print(out);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountReads.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountReads.java
new file mode 100644
index 0000000..33d22ca
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountReads.java
@@ -0,0 +1,81 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.NanoSchedulable;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.Requires;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+/**
+ * Walks over the input data set, calculating the number of reads seen for diagnostic purposes.
+ *
+ * <p>
+ * Can also count the number of reads matching a given criterion using read filters (see the
+ * --read-filter command line argument). Simplest example of a read-backed analysis.
+ *
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more BAM files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Number of reads seen.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T CountReads \
+ * -I input.bam \
+ * [-L input.intervals]
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+ at Requires({DataSource.READS, DataSource.REFERENCE})
+public class CountReads extends ReadWalker<Integer, Long> implements NanoSchedulable {
+ public Integer map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker tracker) {
+ return 1;
+ }
+
+ @Override public Long reduceInit() { return 0L; }
+
+ public Long reduce(Integer value, Long sum) { return (long) value + sum; }
+
+ public void onTraversalDone(Long result) {
+ logger.info("CountReads counted " + result + " reads in the traversal");
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountTerminusEvent.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountTerminusEvent.java
new file mode 100644
index 0000000..90a131c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/CountTerminusEvent.java
@@ -0,0 +1,104 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.Requires;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.PrintStream;
+import java.util.List;
+
+/**
+ * Walks over the input data set, counting the number of reads ending in insertions/deletions or soft-clips
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more BAM files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Number of reads ending in each category.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T CountTerminusEvent \
+ * -o output.txt \
+ * -I input.bam \
+ * [-L input.intervals]
+ * </pre>
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+ at Requires({DataSource.READS, DataSource.REFERENCE})
+public class CountTerminusEvent extends ReadWalker<Pair<Long, Long>, Pair<Long, Long>> {
+ @Output
+ public PrintStream out;
+
+ public Pair<Long, Long> map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker tracker) {
+ List<CigarElement> cigarElements = read.getCigar().getCigarElements();
+
+ CigarElement lastElement = null;
+ for (CigarElement element : cigarElements) {
+ if (element.getOperator() != CigarOperator.HARD_CLIP)
+ lastElement = element;
+ }
+
+ if (lastElement == null)
+ throw new UserException.MalformedBAM(read, "read does not have any bases, it's all hard clips");
+
+ long endsInIndel = lastElement.getOperator() == CigarOperator.INSERTION || lastElement.getOperator() == CigarOperator.DELETION? 1 : 0;
+ long endsInSC = lastElement.getOperator() == CigarOperator.SOFT_CLIP ? 1 : 0;
+
+ return new Pair<Long, Long>(endsInIndel, endsInSC);
+ }
+
+ public Pair<Long, Long> reduceInit() { return new Pair<Long, Long>(0L, 0L); }
+
+ public Pair<Long, Long> reduce(Pair<Long, Long> value, Pair<Long, Long> sum) {
+ sum.set(sum.getFirst() + value.getFirst(), sum.getSecond() + value.getSecond());
+ return sum;
+ }
+
+ @Override
+ public void onTraversalDone(Pair<Long, Long> result) {
+ out.println(String.format("\tReads ending in indels : %d\n\tReads ending in soft-clips: %d\n", result.getFirst(), result.getSecond()));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/DocumentationTest.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/DocumentationTest.java
new file mode 100644
index 0000000..b5a1e74
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/DocumentationTest.java
@@ -0,0 +1,117 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.arguments.DbsnpArgumentCollection;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.*;
+
+/**
+ * Summary test
+ *
+ * <p>Body test</p>
+ */
+ at Hidden
+public class DocumentationTest extends RodWalker<Integer, Integer> {
+ // the docs for the arguments are in the collection
+ @ArgumentCollection protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ /**
+ * dbSNP comparison VCF. By default, the dbSNP file is used to specify the set of "known" variants.
+ * Other sets can be specified with the -knownName (--known_names) argument.
+ */
+ @ArgumentCollection
+ protected DbsnpArgumentCollection dbsnp = new DbsnpArgumentCollection();
+
+ /**
+ * detailed documentation about the argument goes here.
+ */
+ @Input(fullName="listofRodBinding", shortName = "disc", doc="Output variants that were not called in this Feature comparison track", required=false)
+ private List<RodBinding<VariantContext>> listOfRodBinding = Collections.emptyList();
+
+ @Input(fullName="optionalRodBinding", shortName = "conc", doc="Output variants that were also called in this Feature comparison track", required=false)
+ private RodBinding<VariantContext> concordanceTrack;
+
+ @Input(fullName="optionalRodBindingWithoutDefault", shortName = "optionalRodBindingWithoutDefault", doc="Output variants that were also called in this Feature comparison track", required=false)
+ private RodBinding<VariantContext> noDefaultOptionalRodBinding;
+
+ @Input(fullName="optionalRodBindingWithoutDefaultNull", shortName = "shortTest", doc="Output variants that were also called in this Feature comparison track", required=false)
+ private RodBinding<VariantContext> noDefaultOptionalRodBindingNull = null;
+
+ @Input(fullName="featureArg", shortName = "featureArg", doc="A RodBinding of feature", required=false)
+ private RodBinding<Feature> featureArg = null;
+
+ @Output(doc="VCFWriter")
+ protected VariantContextWriter vcfWriter = null;
+
+ @Advanced
+ @Argument(fullName="setString", shortName="sn", doc="Sample name to be included in the analysis. Can be specified multiple times.", required=false)
+ public Set<String> sampleNames;
+
+ @Argument(fullName="setStringInitialized", shortName="setStringInitialized", doc="Sample name to be included in the analysis. Can be specified multiple times.", required=false)
+ public Set<String> setStringInitialized = new HashSet<String>();
+
+ @Argument(shortName="optionalArgWithMissinglessDefault", doc="One or more criteria to use when selecting the data. Evaluated *after* the specified samples are extracted and the INFO-field annotations are updated.", required=false)
+ public ArrayList<String> SELECT_EXPRESSIONS = new ArrayList<String>();
+
+ @Argument(shortName="AAAAA", fullName = "AAAAA", doc="Should be the first argument", required=false)
+ public boolean FIRST_ARG = false;
+
+ @Advanced
+ @Argument(fullName="booleanArg", shortName="env", doc="Don't include loci found to be non-variant after the subsetting procedure.", required=false)
+ private boolean EXCLUDE_NON_VARIANTS = false;
+
+ @Advanced
+ @Argument(fullName="booleanArray", shortName="booleanArray", doc="x", required=false)
+ private boolean[] boolArray = null;
+
+ @Argument(fullName="enumTest", shortName="enumTest", doc="Test enum", required=false)
+ private TestEnum TestEnumArg = TestEnum.ENUM2;
+ public enum TestEnum {
+ /** Docs for enum1 */
+ ENUM1,
+ /** Docs for enum2 */
+ ENUM2
+ }
+
+ @Hidden
+ @Argument(fullName="hiddenArg", shortName="keepAF", doc="Don't include loci found to be non-variant after the subsetting procedure.", required=false)
+ private boolean KEEP_AF_SPECTRUM = false;
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) { return 0; }
+ public Integer reduceInit() { return 0; }
+ public Integer reduce(Integer value, Integer sum) { return value + sum; }
+ public void onTraversalDone(Integer result) { }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/ErrorThrowing.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/ErrorThrowing.java
new file mode 100644
index 0000000..6e872e3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/ErrorThrowing.java
@@ -0,0 +1,110 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.NanoSchedulable;
+import org.broadinstitute.gatk.engine.walkers.RefWalker;
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+/**
+ * A walker that simply throws errors. Allows us to test that the engine is behaving as expected with error handling
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_TOY, extraDocs = {CommandLineGATK.class} )
+public class ErrorThrowing extends RefWalker<Integer,Integer> implements TreeReducible<Integer>, NanoSchedulable {
+ @Input(fullName="exception", shortName = "E", doc="Java class of exception to throw", required=true)
+ public String exceptionToThrow;
+
+ @Argument(fullName = "failMethod", shortName = "fail", doc = "Determines which method to fail in", required = false)
+ public FailMethod failMethod = FailMethod.MAP;
+
+ public enum FailMethod {
+ MAP,
+ REDUCE,
+ TREE_REDUCE
+ }
+
+ //
+ // Template code to allow us to build the walker, doesn't actually do anything
+ //
+ @Override
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( ref == null ) // only throw exception when we are in proper map, not special map(null) call
+ return null;
+
+ if ( failMethod == FailMethod.MAP )
+ fail();
+
+ return 0;
+ }
+
+ @Override
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ @Override
+ public Integer reduce(Integer value, Integer sum) {
+ if ( value != null && failMethod == FailMethod.REDUCE )
+ fail();
+ return sum;
+ }
+
+ public Integer treeReduce(final Integer lhs, final Integer rhs) {
+ if ( failMethod == FailMethod.TREE_REDUCE )
+ fail();
+ return rhs;
+ }
+
+ private void fail() {
+ if ( exceptionToThrow.equals("UserException") ) {
+ throw new UserException("UserException");
+ } else if ( exceptionToThrow.equals("NullPointerException") ) {
+ throw new NullPointerException();
+ } else if ( exceptionToThrow.equals("ReviewedGATKException") ) {
+ throw new ReviewedGATKException("ReviewedGATKException");
+ } else if ( exceptionToThrow.equals("SamError1") ) {
+ throw new RuntimeException(CommandLineGATK.PICARD_TEXT_SAM_FILE_ERROR_1);
+ } else if ( exceptionToThrow.equals("SamError2") ) {
+ throw new RuntimeException(CommandLineGATK.PICARD_TEXT_SAM_FILE_ERROR_2);
+ } else if ( exceptionToThrow.equals("NoSpace1") ) {
+ throw new htsjdk.samtools.util.RuntimeIOException(new java.io.IOException("No space left on device java.io.FileOutputStream.writeBytes(Native Method)"));
+ } else if ( exceptionToThrow.equals("NoSpace2") ) {
+ throw new htsjdk.samtools.SAMException("Exception writing BAM index file", new java.io.IOException("No space left on device java.io.FileOutputStream.writeBytes(Native Method)"));
+ } else {
+ throw new UserException.BadArgumentValue("exception", "exception isn't a recognized value " + exceptionToThrow);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/FlagStat.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/FlagStat.java
new file mode 100644
index 0000000..83c2cc4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/FlagStat.java
@@ -0,0 +1,225 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.NanoSchedulable;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.Requires;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.PrintStream;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+
+/**
+ * A reimplementation of the 'samtools flagstat' subcommand in the GATK
+ *
+ * <p>This tool walks over all input data, accumulating statistics such as total number of reads,
+ * reads with QC failure flag set, number of duplicates, percentage mapped, etc.</p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A BAM file containing the sequence data.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Resulting stats are written to file if an output file name is given (with -o), otherwise output to stdout.
+ * </p>
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -T FlagStat \
+ * -R ref.fasta \
+ * -I reads.bam \
+ * [-o output.txt]
+ * </pre>
+ *
+ * @author aaron
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+ at Requires({DataSource.READS})
+public class FlagStat extends ReadWalker<FlagStat.FlagStatus, FlagStat.FlagStatus> implements NanoSchedulable {
+ @Output
+ PrintStream out;
+
+ // what comes out of the flagstat
+ public final static class FlagStatus {
+ long readCount = 0L;
+ long QC_failure = 0L;
+ long duplicates = 0L;
+ long mapped = 0L;
+ long paired_in_sequencing = 0L;
+ long read1 = 0L;
+ long read2 = 0L;
+ long properly_paired = 0L;
+ long with_itself_and_mate_mapped = 0L;
+ long singletons = 0L;
+ long with_mate_mapped_to_a_different_chr = 0L;
+ long with_mate_mapped_to_a_different_chr_maq_greaterequal_than_5 = 0L;
+
+ public String toString() {
+ String ret = "";
+ StringBuilder builder = new StringBuilder(ret);
+ NumberFormat percentFormatter = new DecimalFormat("#0.00");
+ builder.append(readCount);
+ builder.append(" in total\n");
+
+ builder.append(QC_failure);
+ builder.append(" QC failure\n");
+
+
+ builder.append(duplicates);
+ builder.append(" duplicates\n");
+
+ builder.append(mapped);
+ builder.append(" mapped (");
+ builder.append(percentFormatter.format(( (float)mapped / (float)readCount ) * 100.0));
+ builder.append("%)\n");
+
+ builder.append(paired_in_sequencing);
+ builder.append(" paired in sequencing\n");
+
+
+ builder.append(read1);
+ builder.append(" read1\n");
+
+ builder.append(read2);
+ builder.append(" read2\n");
+
+ builder.append(properly_paired);
+ builder.append(" properly paired (");
+ builder.append(percentFormatter.format(( (float)properly_paired / (float)readCount ) * 100.0));
+ builder.append("%)\n");
+
+
+ builder.append(with_itself_and_mate_mapped);
+ builder.append(" with itself and mate mapped\n");
+
+ builder.append(singletons);
+ builder.append(" singletons (");
+ builder.append(percentFormatter.format(( (float)singletons / (float)readCount ) * 100.0));
+ builder.append("%)\n");
+
+
+ builder.append(with_mate_mapped_to_a_different_chr);
+ builder.append(" with mate mapped to a different chr\n");
+
+ builder.append(with_mate_mapped_to_a_different_chr_maq_greaterequal_than_5);
+ builder.append(" with mate mapped to a different chr (mapQ>=5)");
+
+ return builder.toString();
+ }
+
+ public FlagStatus add(final FlagStatus other) {
+ readCount += other.readCount;
+ QC_failure += other.QC_failure;
+ duplicates += other.duplicates;
+ mapped += other.mapped;
+ paired_in_sequencing += other.paired_in_sequencing;
+ read1 += other.read1;
+ read2 += other.read2;
+ properly_paired += other.properly_paired;
+ with_itself_and_mate_mapped += other.with_itself_and_mate_mapped;
+ singletons += other.singletons;
+ with_mate_mapped_to_a_different_chr += other.with_mate_mapped_to_a_different_chr;
+ with_mate_mapped_to_a_different_chr_maq_greaterequal_than_5 += other.with_mate_mapped_to_a_different_chr_maq_greaterequal_than_5;
+
+ return this;
+ }
+
+ public FlagStatus add(final GATKSAMRecord read) {
+ this.readCount++;
+
+ if (read.getReadFailsVendorQualityCheckFlag()) {
+ this.QC_failure++;
+ }
+ if (read.getDuplicateReadFlag()) {
+ this.duplicates++;
+ }
+ if (!read.getReadUnmappedFlag()) {
+ this.mapped++;
+ }
+ if (read.getReadPairedFlag()) {
+ this.paired_in_sequencing++;
+
+ if (read.getSecondOfPairFlag()) {
+ this.read2++;
+ } else if (read.getReadPairedFlag()) {
+ this.read1++;
+ }
+ if (read.getProperPairFlag()) {
+ this.properly_paired++;
+ }
+ if (!read.getReadUnmappedFlag() && !read.getMateUnmappedFlag()) {
+ this.with_itself_and_mate_mapped++;
+
+ if (!read.getReferenceIndex().equals(read.getMateReferenceIndex())) {
+ this.with_mate_mapped_to_a_different_chr++;
+
+ if (read.getMappingQuality() >= 5) {
+ this.with_mate_mapped_to_a_different_chr_maq_greaterequal_than_5++;
+ }
+ }
+ }
+ if (!read.getReadUnmappedFlag() && read.getMateUnmappedFlag()) {
+ this.singletons++;
+ }
+ }
+
+ return this;
+ }
+ }
+
+
+ @Override
+ public FlagStatus map( final ReferenceContext ref, final GATKSAMRecord read, final RefMetaDataTracker metaDataTracker ) {
+ return new FlagStatus().add(read);
+ }
+
+ @Override
+ public FlagStatus reduceInit() {
+ return new FlagStatus();
+ }
+
+ @Override
+ public FlagStatus reduce(final FlagStatus value, final FlagStatus sum) {
+ return sum.add(value);
+ }
+
+ @Override
+ public void onTraversalDone(final FlagStatus result) {
+ out.println(result.toString());
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/Pileup.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/Pileup.java
new file mode 100644
index 0000000..322cea6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/Pileup.java
@@ -0,0 +1,217 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.LocusWalker;
+import org.broadinstitute.gatk.engine.walkers.NanoSchedulable;
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Emulates the samtools pileup command to print aligned reads
+ *
+ * <p>Prints the alignment in something similar to the Samtools pileup format (see the
+ * <a href="http://samtools.sourceforge.net/pileup.shtml">Pileup format documentation</a> for more details about
+ * the original format). There is one line per genomic position, listing the chromosome name, coordinate, reference
+ * base, read bases, and read qualities. In addition to these default fields, additional information can be added to
+ * the output as extra columns; see options detailed below.</p>
+ *
+ * <h4>Emulated command:</h4>
+ * <pre>
+ * samtools pileup -f in.ref.fasta -l in.site_list input.bam
+ * </pre>
+
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A BAM file and the interval to print.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Alignment of reads formatted in the Pileup style.
+ * </p>
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -T Pileup \
+ * -R exampleFASTA.fasta \
+ * -I exampleBAM.bam \
+ * -L chr1:257-267
+ * -o output.txt
+ * </pre>
+ * <h4>Expected output</h4>
+ * <pre>
+ * chr1 257 A CAA '&=
+ * chr1 258 C TCC A:=
+ * chr1 259 C CCC )A=
+ * chr1 260 C ACC (=<
+ * chr1 261 T TCT '44
+ * chr1 262 A AAA '?:
+ * chr1 263 A AGA 1'6
+ * chr1 264 C TCC 987
+ * chr1 265 C CCC (@(
+ * chr1 266 C GCC ''=
+ * chr1 267 T AAT 7%>
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class Pileup extends LocusWalker<String, Integer> implements TreeReducible<Integer>, NanoSchedulable {
+
+ private static final String verboseDelimiter = "@"; // it's ugly to use "@" but it's literally the only usable character not allowed in read names
+
+ @Output
+ PrintStream out;
+
+ /**
+ * In addition to the standard pileup output, adds 'verbose' output too. The verbose output contains the number of spanning deletions,
+ * and for each read in the pileup it has the read name, offset in the base string, read length, and read mapping quality. These per
+ * read items are delimited with an '@' character.
+ */
+ @Argument(fullName="showVerbose",shortName="verbose",doc="Add an extra verbose section to the pileup output", required=false)
+ public boolean SHOW_VERBOSE = false;
+ /**
+ * This enables annotating the pileup to show overlaps with metadata from a ROD file.
+ * For example, if you provide a VCF and there is a SNP at a given location covered by the pileup, the pileup
+ * output at that position will be annotated with the corresponding source ROD identifier.
+ */
+ @Input(fullName="metadata",shortName="metadata",doc="ROD file containing metadata", required=false)
+ public List<RodBinding<Feature>> rods = Collections.emptyList();
+ /**
+ * Adds the length of the insert each base comes from to the output pileup. Here, "insert" refers to the DNA insert
+ * produced during library generation before sequencing.
+ */
+ @Hidden
+ @Argument(fullName="outputInsertLength",shortName = "outputInsertLength",doc="Output insert length",required=false)
+ public boolean outputInsertLength=false;
+
+ @Override
+ public String map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ final String rods = getReferenceOrderedData( tracker );
+
+ ReadBackedPileup basePileup = context.getBasePileup();
+
+ final StringBuilder s = new StringBuilder();
+ s.append(String.format("%s %s", basePileup.getPileupString((char)ref.getBase()), rods));
+ if ( outputInsertLength )
+ s.append(" ").append(insertLengthOutput(basePileup));
+ if ( SHOW_VERBOSE )
+ s.append(" ").append(createVerboseOutput(basePileup));
+ s.append("\n");
+
+ return s.toString();
+ }
+
+ // Given result of map function
+ @Override
+ public Integer reduceInit() { return 0; }
+
+ @Override
+ public Integer reduce(String value, Integer sum) {
+ out.print(value);
+ return sum + 1;
+ }
+
+ @Override
+ public Integer treeReduce(Integer lhs, Integer rhs) {
+ return lhs + rhs;
+ }
+
+ /**
+ * Get a string representation the reference-ordered data.
+ * @param tracker Container for the reference-ordered data.
+ * @return String representation of the reference-ordered data.
+ */
+ private String getReferenceOrderedData( RefMetaDataTracker tracker ) {
+ ArrayList<String> rodStrings = new ArrayList<String>();
+ for ( Feature datum : tracker.getValues(rods) ) {
+ rodStrings.add(datum.toString());
+ }
+ String rodString = Utils.join(", ", rodStrings);
+
+ if ( !rodString.equals("") )
+ rodString = "[ROD: " + rodString + "]";
+
+ return rodString;
+ }
+ private static String insertLengthOutput(final ReadBackedPileup pileup) {
+
+ Integer[] insertSizes=new Integer[pileup.depthOfCoverage()];
+
+ int i=0;
+ for ( PileupElement p : pileup ) {
+ insertSizes[i]=p.getRead().getInferredInsertSize();
+ ++i;
+ }
+ return Utils.join(",",insertSizes);
+ }
+
+
+ private static String createVerboseOutput(final ReadBackedPileup pileup) {
+ final StringBuilder sb = new StringBuilder();
+ boolean isFirst = true;
+
+ sb.append(pileup.getNumberOfDeletions());
+ sb.append(" ");
+
+ for ( PileupElement p : pileup ) {
+ if ( isFirst )
+ isFirst = false;
+ else
+ sb.append(",");
+ sb.append(p.getRead().getReadName());
+ sb.append(verboseDelimiter);
+ sb.append(p.getOffset());
+ sb.append(verboseDelimiter);
+ sb.append(p.getRead().getReadLength());
+ sb.append(verboseDelimiter);
+ sb.append(p.getRead().getMappingQuality());
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public void onTraversalDone(Integer result) {
+ out.println("[REDUCE RESULT] Traversal result is: " + result);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/PrintRODs.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/PrintRODs.java
new file mode 100644
index 0000000..22ab7d1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/PrintRODs.java
@@ -0,0 +1,91 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.io.PrintStream;
+
+/**
+ * Prints out all of the RODs in the input data set. Data is rendered using the toString() method
+ * of the given ROD.
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class PrintRODs extends RodWalker<Integer, Integer> {
+ @Input(fullName="input", shortName = "input", doc="The input ROD which should be printed out.", required=true)
+ public RodBinding<Feature> input;
+
+ @Output
+ PrintStream out;
+
+ /**
+ * Initialize the number of loci processed to zero.
+ *
+ * @return 0
+ */
+ public Integer reduceInit() { return 0; }
+
+ /**
+ *
+ * @param tracker the meta-data tracker
+ * @param ref the reference base
+ * @param context the context for the given locus
+ * @return 1 if the locus was successfully processed, 0 if otherwise
+ */
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null )
+ return 0;
+
+ for ( Feature feature : tracker.getValues(Feature.class, context.getLocation()) ) {
+ out.println(feature.toString());
+ }
+
+ return 1;
+ }
+
+ /**
+ * Increment the number of rods processed.
+ *
+ * @param value result of the map.
+ * @param sum accumulator for the reduce.
+ * @return the new number of rods processed.
+ */
+ public Integer reduce(Integer value, Integer sum) {
+ return sum + value;
+ }
+
+ public void onTraversalDone(Integer result) {}
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/QCRef.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/QCRef.java
new file mode 100644
index 0000000..ee8b68f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/QCRef.java
@@ -0,0 +1,142 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequence;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RefWalker;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+
+import java.io.PrintStream;
+
+/**
+ * Quality control for the reference fasta
+ *
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One reference file only. And optionally -L intervals
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * If ok, nothing, else will throw an exception at the site where there's been a problem
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T QCRef
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+public class QCRef extends RefWalker<Integer, Integer> {
+ @Output
+ public PrintStream out;
+
+ String contigName = "";
+ int contigStart, contigEnd;
+ IndexedFastaSequenceFile uncachedRef;
+ byte[] uncachedBases;
+
+ @Override
+ public void initialize() {
+ super.initialize(); //To change body of overridden methods use File | Settings | File Templates.
+ uncachedRef = getToolkit().getReferenceDataSource().getReference();
+ }
+
+ private final void throwError(ReferenceContext ref, String message) {
+ throw new GATKException(String.format("Site %s failed: %s", ref.getLocus(), message));
+ }
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ final String locusContigName = ref.getLocus().getContig();
+ if ( ! locusContigName.equals(contigName) ) {
+ contigName = locusContigName;
+ ReferenceSequence refSeq = uncachedRef.getSequence(contigName);
+ contigStart = 1;
+ contigEnd = contigStart + refSeq.length() - 1;
+ uncachedBases = uncachedRef.getSubsequenceAt(contigName, contigStart, contigEnd).getBases();
+ logger.info(String.format("Loading contig %s (%d-%d)", contigName, contigStart, contigEnd));
+ }
+
+ final byte refBase = ref.getBase();
+ if (! ( BaseUtils.isRegularBase(refBase) || isExtendFastaBase(refBase) ) )
+ throwError(ref, String.format("Refbase isn't a regular base (%d %c)", refBase, (char)refBase));
+
+ // check bases are equal
+ final int pos = (int)context.getPosition() - contigStart;
+ if ( pos > contigEnd )
+ throwError(ref, String.format("off contig (len=%d)", contigEnd));
+ final byte uncachedBase = uncachedBases[pos];
+
+ if ( uncachedBase != refBase )
+ throwError(ref, String.format("Provided refBase (%d %c) not equal to uncached one (%d %c)",
+ refBase, (char)refBase, uncachedBase, (char)uncachedBase));
+
+ return 1;
+ }
+
+ private static final boolean isExtendFastaBase(final byte b) {
+ switch ( b ) {
+ case 'U':
+ case 'R':
+ case 'Y':
+ case 'K':
+ case 'M':
+ case 'S':
+ case 'W':
+ case 'B':
+ case 'D':
+ case 'H':
+ case 'V':
+ case 'N':
+ case 'X':
+ case '-':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ public Integer reduce(Integer one, Integer sum) {
+ return one + sum;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/ReadClippingStats.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/ReadClippingStats.java
new file mode 100644
index 0000000..14a1de5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/ReadClippingStats.java
@@ -0,0 +1,157 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.utils.commandline.Advanced;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.Requires;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.AlignmentUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+
+/**
+ * Read clipping statistics for all reads.
+ *
+ * Walks over the input reads, printing out statistics about the read length, number of clipping events, and length
+ * of the clipping to the output stream.
+ *
+ * Note: Ignores N's in the Cigar string.
+ *
+ * <h3>Input</h3>
+ * One or more BAM files
+ *
+ * <h3>Output</h3>
+ * A simple tabulated text file with read length and clipping statistics for every read (or every N reads if the "skip"
+ * option is used)
+ *
+ * User: depristo
+ * Date: May 5, 2010
+ * Time: 12:16:41 PM
+ */
+
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_QC, extraDocs = {CommandLineGATK.class} )
+ at Requires({DataSource.READS})
+public class ReadClippingStats extends ReadWalker<ReadClippingStats.ReadClippingInfo,Integer> {
+ @Output
+ protected PrintStream out;
+
+ /**
+ * when this flag is set (default), statistics will be collected on unmapped reads as well. The default behavior
+ * is to ignore unmapped reads."
+ */
+ @Argument(fullName="include_unmapped", shortName="u", doc="Include unmapped reads in the analysis", required=false)
+ protected boolean INCLUDE_UNMAPPED = false;
+
+ /**
+ * print every read whose read number is divisible by SKIP. READ_NUMBER % SKIP == 0. First read in the file has read number = 1,
+ * second is 2, third is 3, ... A value of 1 means print every read. A value of 1000 means print every 1000th read.
+ */
+ @Advanced
+ @Argument(fullName="skip", shortName="skip", doc="Do not print all reads, skip some.", required=false)
+ protected int SKIP = 1;
+
+ public class ReadClippingInfo {
+ SAMReadGroupRecord rg;
+ int readLength, nClippingEvents, nClippedBases;
+ }
+
+ public ReadClippingInfo map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker metaDataTracker) {
+ if ( AlignmentUtils.isReadUnmapped(read) && !INCLUDE_UNMAPPED)
+ return null;
+
+ ReadClippingInfo info = new ReadClippingInfo();
+ info.rg = read.getReadGroup();
+
+ if ( info.rg == null ) throw new UserException.ReadMissingReadGroup(read);
+
+ for ( CigarElement elt : read.getCigar().getCigarElements() ) {
+ switch ( elt.getOperator()) {
+ case H : // ignore hard clips
+ case S : // soft clip
+ info.nClippingEvents++;
+ info.nClippedBases += elt.getLength();
+ break;
+ case M :
+ case D : // deletion w.r.t. the reference
+ case P : // ignore pads
+ case I : // insertion w.r.t. the reference
+ case N : // reference skip (looks and gets processed just like a "deletion", just different logical meaning)
+ break;
+ default : throw new IllegalStateException("Case statement didn't deal with cigar op: " + elt.getOperator());
+ }
+ info.readLength = read.getReadLength();
+ }
+
+ return info; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ /**
+ * Provide an initial value for reduce computations.
+ *
+ * @return Initial value of reduce.
+ */
+ public Integer reduceInit() {
+ out.println(Utils.join(" \t", Arrays.asList("ReadGroup", "ReadLength", "NClippingEvents", "NClippedBases", "PercentClipped")));
+ return 0;
+ }
+
+ /**
+ * Reduces a single map with the accumulator provided as the ReduceType.
+ *
+ * @param info result of the map.
+ * @param sum accumulator for the reduce.
+ * @return accumulator with result of the map taken into account.
+ */
+ public Integer reduce(ReadClippingInfo info, Integer sum) {
+ if ( info != null ) {
+ if ( sum % SKIP == 0 ) {
+ String id = info.rg.getReadGroupId();
+ out.printf("%s\t %d\t %d\t %d\t %.2f%n",
+ id, info.readLength, info.nClippingEvents, info.nClippedBases,
+ 100.0 * MathUtils.ratio(info.nClippedBases, info.readLength));
+ }
+ return sum + 1;
+ } else {
+ return sum;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/RodSystemValidation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/RodSystemValidation.java
new file mode 100644
index 0000000..5f1d396
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/qc/RodSystemValidation.java
@@ -0,0 +1,182 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.engine.walkers.Reference;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.Window;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.io.*;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * a walker for validating (in the style of validating pile-up) the ROD system.
+ */
+ at Hidden
+ at Reference(window=@Window(start=-40,stop=40))
+public class RodSystemValidation extends RodWalker<Integer,Integer> {
+
+ // the divider to use in some of the text output
+ private static final String DIVIDER = ",";
+
+ @Input(fullName="eval", shortName = "eval", doc="Input VCF eval file", required=true)
+ public List<RodBinding<VariantContext>> eval;
+
+ @Output
+ public PrintStream out;
+
+ @Argument(fullName="PerLocusEqual",required=false,doc="Should we check that all records at the same site produce equivilent variant contexts")
+ public boolean allRecordsVariantContextEquivalent = false;
+
+ // used to calculate the MD5 of a file
+ MessageDigest digest = null;
+
+ // we sometimes need to know what rods the engine's seen
+ List<ReferenceOrderedDataSource> rodList;
+
+ /**
+ * emit the md5 sums for each of the input ROD files (will save up a lot of time if and when the ROD files change
+ * underneath us).
+ */
+ public void initialize() {
+ // setup the MD5-er
+ try {
+ digest = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new ReviewedGATKException("Unable to find MD5 checksumer");
+ }
+ out.println("Header:");
+ // enumerate the list of ROD's we've loaded
+ rodList = this.getToolkit().getRodDataSources();
+ for (ReferenceOrderedDataSource rod : rodList) {
+ out.println(rod.getName() + DIVIDER + rod.getType());
+ out.println(rod.getName() + DIVIDER + rod.getFile().getName());
+ out.println(rod.getName() + DIVIDER + md5sum(rod.getFile()));
+ }
+ out.println("Data:");
+ }
+
+ /**
+ *
+ * @param tracker the ref meta data tracker to get RODs
+ * @param ref reference context
+ * @param context the reads
+ * @return an 1 for each site with a rod(s), 0 otherwise
+ */
+ @Override
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ int ret = 0;
+ if (tracker != null && tracker.getNTracksWithBoundFeatures() > 0) {
+ out.print(context.getLocation() + DIVIDER);
+ for (RODRecordList rod: tracker.getBoundRodTracks())
+ out.print(rod.getName() + DIVIDER);
+ out.println(";");
+ ret++;
+ }
+
+ // if the argument was set, check for equivalence
+ if (allRecordsVariantContextEquivalent && tracker != null) {
+ Collection<VariantContext> col = tracker.getValues(eval);
+ VariantContext con = null;
+ for (VariantContext contextInList : col)
+ if (con == null) con = contextInList;
+ else if (!con.equals(col)) out.println("FAIL: context " + col + " doesn't match " + con);
+ }
+ return ret;
+ }
+
+ /**
+ * Provide an initial value for reduce computations.
+ *
+ * @return Initial value of reduce.
+ */
+ @Override
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ /**
+ * Reduces a single map with the accumulator provided as the ReduceType.
+ *
+ * @param value result of the map.
+ * @param sum accumulator for the reduce.
+ * @return accumulator with result of the map taken into account.
+ */
+ @Override
+ public Integer reduce(Integer value, Integer sum) {
+ return value + sum;
+ }
+
+ @Override
+ public void onTraversalDone(Integer result) {
+ // Double check traversal result to make count is the same.
+ // TODO: Is this check necessary?
+ out.println("[REDUCE RESULT] Traversal result is: " + result);
+ }
+
+ // shamelessly absconded and adapted from http://www.javalobby.org/java/forums/t84420.html
+ private String md5sum(File f) {
+ InputStream is;
+ try {
+ is = new FileInputStream(f);
+ } catch (FileNotFoundException e) {
+ return "Not a file";
+ }
+ byte[] buffer = new byte[8192];
+ int read = 0;
+ try {
+ while ((read = is.read(buffer)) > 0) {
+ digest.update(buffer, 0, read);
+ }
+ byte[] md5sum = digest.digest();
+ BigInteger bigInt = new BigInteger(1, md5sum);
+ return bigInt.toString(16);
+ }
+ catch (IOException e) {
+ throw new RuntimeException("Unable to process file for MD5", e);
+ }
+ finally {
+ try {
+ is.close();
+ }
+ catch (IOException e) {
+ throw new RuntimeException("Unable to close input stream for MD5 calculation", e);
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/ClipReads.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/ClipReads.java
new file mode 100644
index 0000000..de3c0dc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/ClipReads.java
@@ -0,0 +1,607 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.readutils;
+
+import htsjdk.samtools.reference.ReferenceSequence;
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequenceFileFactory;
+import htsjdk.samtools.util.StringUtil;
+import org.broadinstitute.gatk.utils.commandline.Advanced;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Hidden;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.io.GATKSAMFileWriter;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.Requires;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.clipping.ClippingOp;
+import org.broadinstitute.gatk.utils.clipping.ClippingRepresentation;
+import org.broadinstitute.gatk.utils.clipping.ReadClipper;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Read clipping based on quality, position or sequence matching
+ *
+ * <p>This tool provides simple, powerful read clipping capabilities that allow you to remove low quality strings of bases, sections of reads, and reads containing user-provided sequences.</p>
+ *
+ * <p>There are three options for clipping (quality, position and sequence), which can be used alone or in combination. In addition, you can also specify a clipping representation, which determines exactly how ClipReads applies clips to the reads (soft clips, writing Q0 base quality scores, etc.). Please note that you MUST specify at least one of the three clipping options, and specifying a clipping representation is not sufficient. If you do not specify a clipping option, the program wi [...]
+ *
+ * <dl>
+ * <dt>Quality score based clipping</dt>
+ * <dd>
+ * Clip bases from the read in clipper from
+ * <pre>argmax_x{ \sum{i = x + 1}^l (qTrimmingThreshold - qual)</pre>
+ * to the end of the read. This is copied from BWA.
+ *
+ * Walk through the read from the end (in machine cycle order) to the beginning, calculating the
+ * running sum of qTrimmingThreshold - qual. While we do this, we track the maximum value of this
+ * sum where the delta > 0. After the loop, clipPoint is either -1 (don't do anything) or the
+ * clipping index in the read (from the end).
+ * </dd><br />
+ * <dt>Cycle based clipping</dt>
+ * <dd>Clips machine cycles from the read. Accepts a string of ranges of the form start1-end1,start2-end2, etc.
+ * For each start/end pair, removes bases in machine cycles from start to end, inclusive. These are 1-based values (positions).
+ * For example, 1-5,10-12 clips the first 5 bases, and then three bases at cycles 10, 11, and 12.
+ * </dd><br />
+ * <dt>Sequence matching</dt>
+ * <dd>Clips bases from that exactly match one of a number of base sequences. This employs an exact match algorithm,
+ * filtering only bases whose sequence exactly matches SEQ.</dd>
+ * </dl>
+ *
+ *
+ * <h3>Input</h3>
+ * <p>
+ * Any number of BAM files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A new BAM file containing all of the reads from the input BAMs with the user-specified clipping
+ * operation applied to each read.
+ * </p>
+ * <p>
+ * <h4>Summary output (console)</h4>
+ * <pre>
+ * Number of examined reads 13
+ * Number of clipped reads 13
+ * Percent of clipped reads 100.00
+ * Number of examined bases 988
+ * Number of clipped bases 126
+ * Percent of clipped bases 12.75
+ * Number of quality-score clipped bases 126
+ * Number of range clipped bases 0
+ * Number of sequence clipped bases 0
+ * </pre>
+ * </p>
+ *
+ * <h3>Example</h3>
+ * <pre>
+ * java -jar GenomeAnalysisTK.jar \
+ * -T ClipReads \
+ * -R reference.fasta \
+ * -I original.bam \
+ * -o clipped.bam \
+ * -XF seqsToClip.fasta \
+ * -X CCCCC \
+ * -CT "1-5,11-15" \
+ * -QT 10
+ * </pre>
+ * <p>The command line shown above will apply all three options in combination. See the detailed examples below to see how the choice of clipping representation affects the output.</p>
+ *
+ * <h4>Detailed clipping examples</h4>
+ * <p>Suppose we are given this read:</p>
+ * <pre>
+ * 314KGAAXX090507:1:19:1420:1123#0 16 chrM 3116 29 76M * * *
+ * TAGGACCCGGGCCCCCCTCCCCAATCCTCCAACGCATATAGCGGCCGCGCCTTCCCCCGTAAATGATATCATCTCA
+ * #################4?6/?2135;;;'1/=/<'B9;12;68?A79@,@==@9?=AAA3;A at B;A?B54;?ABA
+ * </pre>
+ *
+ * <p>If we are clipping reads with -QT 10 and -CR WRITE_NS, we get:</p>
+ *
+ * <pre>
+ * 314KGAAXX090507:1:19:1420:1123#0 16 chrM 3116 29 76M * * *
+ * NNNNNNNNNNNNNNNNNTCCCCAATCCTCCAACGCATATAGCGGCCGCGCCTTCCCCCGTAAATGATATCATCTCA
+ * #################4?6/?2135;;;'1/=/<'B9;12;68?A79@,@==@9?=AAA3;A at B;A?B54;?ABA
+ * </pre>
+ *
+ * <p>Whereas with -QT 10 -CR WRITE_Q0S:</p>
+ * <pre>
+ * 314KGAAXX090507:1:19:1420:1123#0 16 chrM 3116 29 76M * * *
+ * TAGGACCCGGGCCCCCCTCCCCAATCCTCCAACGCATATAGCGGCCGCGCCTTCCCCCGTAAATGATATCATCTCA
+ * !!!!!!!!!!!!!!!!!4?6/?2135;;;'1/=/<'B9;12;68?A79@,@==@9?=AAA3;A at B;A?B54;?ABA
+ * </pre>
+ *
+ * <p>Or -QT 10 -CR SOFTCLIP_BASES:</p>
+ * <pre>
+ * 314KGAAXX090507:1:19:1420:1123#0 16 chrM 3133 29 17S59M * * *
+ * TAGGACCCGGGCCCCCCTCCCCAATCCTCCAACGCATATAGCGGCCGCGCCTTCCCCCGTAAATGATATCATCTCA
+ * #################4?6/?2135;;;'1/=/<'B9;12;68?A79@,@==@9?=AAA3;A at B;A?B54;?ABA
+ * </pre>
+ *
+
+ * @author Mark DePristo
+ * @since 2010
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_DATA, extraDocs = {CommandLineGATK.class} )
+ at Requires({DataSource.READS})
+public class ClipReads extends ReadWalker<ClipReads.ReadClipperWithData, ClipReads.ClippingData> {
+ /**
+ * If provided, ClipReads will write summary statistics about the clipping operations applied to the reads in this file.
+ */
+ @Output(fullName = "outputStatistics", shortName = "os", doc = "File to output statistics", required = false, defaultToStdout = false)
+ PrintStream out = null;
+
+ /**
+ * The output SAM/BAM file will be written here
+ */
+ @Output(doc = "Write BAM output here")
+ GATKSAMFileWriter outputBam;
+
+ /**
+ * If a value > 0 is provided, then the quality score based read clipper will be applied to the reads using this
+ * quality score threshold.
+ */
+ @Argument(fullName = "qTrimmingThreshold", shortName = "QT", doc = "If provided, the Q-score clipper will be applied", required = false)
+ int qTrimmingThreshold = -1;
+
+ /**
+ * Clips machine cycles from the read. Accepts a string of ranges of the form start1-end1,start2-end2, etc.
+ * For each start/end pair, removes bases in machine cycles from start to end, inclusive. These are 1-based
+ * values (positions). For example, 1-5,10-12 clips the first 5 bases, and then three bases at cycles 10, 11,
+ * and 12.
+ */
+ @Argument(fullName = "cyclesToTrim", shortName = "CT", doc = "String indicating machine cycles to clip from the reads", required = false)
+ String cyclesToClipArg = null;
+
+ /**
+ * Reads the sequences in the provided FASTA file, and clip any bases that exactly match any of the
+ * sequences in the file.
+ */
+ @Argument(fullName = "clipSequencesFile", shortName = "XF", doc = "Remove sequences within reads matching the sequences in this FASTA file", required = false)
+ String clipSequenceFile = null;
+
+ /**
+ * Clips bases from the reads matching the provided SEQ. Can be provided any number of times on the command line
+ */
+ @Argument(fullName = "clipSequence", shortName = "X", doc = "Remove sequences within reads matching this sequence", required = false)
+ String[] clipSequencesArgs = null;
+
+ /**
+ * The different values for this argument determines how ClipReads applies clips to the reads. This can range
+ * from writing Ns over the clipped bases to hard clipping away the bases from the BAM.
+ */
+ @Argument(fullName = "clipRepresentation", shortName = "CR", doc = "How should we actually clip the bases?", required = false)
+ ClippingRepresentation clippingRepresentation = ClippingRepresentation.WRITE_NS;
+
+ @Hidden
+ @Advanced
+ @Argument(fullName="read", doc="", required=false)
+ String onlyDoRead = null;
+
+ /**
+ * List of sequence that should be clipped from the reads
+ */
+ List<SeqToClip> sequencesToClip = new ArrayList<SeqToClip>();
+
+ /**
+ * List of cycle start / stop pairs (0-based, stop is included in the cycle to remove) to clip from the reads
+ */
+ List<Pair<Integer, Integer>> cyclesToClip = null;
+
+ /**
+ * The initialize function.
+ */
+ public void initialize() {
+ if (qTrimmingThreshold >= 0) {
+ logger.info(String.format("Creating Q-score clipper with threshold %d", qTrimmingThreshold));
+ }
+
+ //
+ // Initialize the sequences to clip
+ //
+ if (clipSequencesArgs != null) {
+ int i = 0;
+ for (String toClip : clipSequencesArgs) {
+ i++;
+ ReferenceSequence rs = new ReferenceSequence("CMDLINE-" + i, -1, StringUtil.stringToBytes(toClip));
+ addSeqToClip(rs.getName(), rs.getBases());
+ }
+ }
+
+ if (clipSequenceFile != null) {
+ ReferenceSequenceFile rsf = ReferenceSequenceFileFactory.getReferenceSequenceFile(new File(clipSequenceFile));
+
+ while (true) {
+ ReferenceSequence rs = rsf.nextSequence();
+ if (rs == null)
+ break;
+ else {
+ addSeqToClip(rs.getName(), rs.getBases());
+ }
+ }
+ }
+
+
+ //
+ // Initialize the cycle ranges to clip
+ //
+ if (cyclesToClipArg != null) {
+ cyclesToClip = new ArrayList<Pair<Integer, Integer>>();
+ for (String range : cyclesToClipArg.split(",")) {
+ try {
+ String[] elts = range.split("-");
+ int start = Integer.parseInt(elts[0]) - 1;
+ int stop = Integer.parseInt(elts[1]) - 1;
+
+ if (start < 0) throw new Exception();
+ if (stop < start) throw new Exception();
+
+ logger.info(String.format("Creating cycle clipper %d-%d", start, stop));
+ cyclesToClip.add(new Pair<Integer, Integer>(start, stop));
+ } catch (Exception e) {
+ throw new RuntimeException("Badly formatted cyclesToClip argument: " + cyclesToClipArg);
+ }
+ }
+ }
+
+ if (outputBam != null) {
+ EnumSet<ClippingRepresentation> presorted = EnumSet.of(ClippingRepresentation.WRITE_NS, ClippingRepresentation.WRITE_NS_Q0S, ClippingRepresentation.WRITE_Q0S);
+ outputBam.setPresorted(presorted.contains(clippingRepresentation));
+ }
+ }
+
+ /**
+ * Helper function that adds a seq with name and bases (as bytes) to the list of sequences to be clipped
+ *
+ * @param name
+ * @param bases
+ */
+ private void addSeqToClip(String name, byte[] bases) {
+ SeqToClip clip = new SeqToClip(name, StringUtil.bytesToString(bases));
+ sequencesToClip.add(clip);
+ logger.info(String.format("Creating sequence clipper %s: %s/%s", clip.name, clip.seq, clip.revSeq));
+ }
+
+ /**
+ * The reads map function.
+ *
+ *
+ * @param ref the reference bases that correspond to our read, if a reference was provided
+ * @param read the read itself, as a GATKSAMRecord
+ * @return the ReadClipper object describing what should be done to clip this read
+ */
+ public ReadClipperWithData map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker metaDataTracker) {
+ if ( onlyDoRead == null || read.getReadName().equals(onlyDoRead) ) {
+ if ( clippingRepresentation == ClippingRepresentation.HARDCLIP_BASES || clippingRepresentation == ClippingRepresentation.REVERT_SOFTCLIPPED_BASES )
+ read = ReadClipper.revertSoftClippedBases(read);
+ ReadClipperWithData clipper = new ReadClipperWithData(read, sequencesToClip);
+
+ //
+ // run all three clipping modules
+ //
+ clipBadQualityScores(clipper);
+ clipCycles(clipper);
+ clipSequences(clipper);
+ return clipper;
+ }
+
+ return null;
+ }
+
+ /**
+ * clip sequences from the reads that match all of the sequences in the global sequencesToClip variable.
+ * Adds ClippingOps for each clip to clipper.
+ *
+ * @param clipper
+ */
+ private void clipSequences(ReadClipperWithData clipper) {
+ if (sequencesToClip != null) { // don't bother if we don't have any sequences to clip
+ GATKSAMRecord read = clipper.getRead();
+ ClippingData data = clipper.getData();
+
+ for (SeqToClip stc : sequencesToClip) {
+ // we have a pattern for both the forward and the reverse strands
+ Pattern pattern = read.getReadNegativeStrandFlag() ? stc.revPat : stc.fwdPat;
+ String bases = read.getReadString();
+ Matcher match = pattern.matcher(bases);
+
+ // keep clipping until match.find() says it can't find anything else
+ boolean found = true; // go through at least once
+ while (found) {
+ found = match.find();
+ //System.out.printf("Matching %s against %s/%s => %b%n", bases, stc.seq, stc.revSeq, found);
+ if (found) {
+ int start = match.start();
+ int stop = match.end() - 1;
+ //ClippingOp op = new ClippingOp(ClippingOp.ClippingType.MATCHES_CLIP_SEQ, start, stop, stc.seq);
+ ClippingOp op = new ClippingOp(start, stop);
+ clipper.addOp(op);
+ data.incSeqClippedBases(stc.seq, op.getLength());
+ }
+ }
+ }
+ clipper.setData(data);
+ }
+ }
+
+ /**
+ * Convenence function that takes a read and the start / stop clipping positions based on the forward
+ * strand, and returns start/stop values appropriate for the strand of the read.
+ *
+ * @param read
+ * @param start
+ * @param stop
+ * @return
+ */
+ private Pair<Integer, Integer> strandAwarePositions(GATKSAMRecord read, int start, int stop) {
+ if (read.getReadNegativeStrandFlag())
+ return new Pair<Integer, Integer>(read.getReadLength() - stop - 1, read.getReadLength() - start - 1);
+ else
+ return new Pair<Integer, Integer>(start, stop);
+ }
+
+ /**
+ * clip bases at cycles between the ranges in cyclesToClip by adding appropriate ClippingOps to clipper.
+ *
+ * @param clipper
+ */
+ private void clipCycles(ReadClipperWithData clipper) {
+ if (cyclesToClip != null) {
+ GATKSAMRecord read = clipper.getRead();
+ ClippingData data = clipper.getData();
+
+ for (Pair<Integer, Integer> p : cyclesToClip) { // iterate over each cycle range
+ int cycleStart = p.first;
+ int cycleStop = p.second;
+
+ if (cycleStart < read.getReadLength()) {
+ // only try to clip if the cycleStart is less than the read's length
+ if (cycleStop >= read.getReadLength())
+ // we do tolerate [for convenience) clipping when the stop is beyond the end of the read
+ cycleStop = read.getReadLength() - 1;
+
+ Pair<Integer, Integer> startStop = strandAwarePositions(read, cycleStart, cycleStop);
+ int start = startStop.first;
+ int stop = startStop.second;
+
+ //ClippingOp op = new ClippingOp(ClippingOp.ClippingType.WITHIN_CLIP_RANGE, start, stop, null);
+ ClippingOp op = new ClippingOp(start, stop);
+ clipper.addOp(op);
+ data.incNRangeClippedBases(op.getLength());
+ }
+ }
+ clipper.setData(data);
+ }
+ }
+
+ /**
+ * Clip bases from the read in clipper from
+ * <p/>
+ * argmax_x{ \sum{i = x + 1}^l (qTrimmingThreshold - qual)
+ * <p/>
+ * to the end of the read. This is blatantly stolen from BWA.
+ * <p/>
+ * Walk through the read from the end (in machine cycle order) to the beginning, calculating the
+ * running sum of qTrimmingThreshold - qual. While we do this, we track the maximum value of this
+ * sum where the delta > 0. After the loop, clipPoint is either -1 (don't do anything) or the
+ * clipping index in the read (from the end).
+ *
+ * @param clipper
+ */
+ private void clipBadQualityScores(ReadClipperWithData clipper) {
+ GATKSAMRecord read = clipper.getRead();
+ ClippingData data = clipper.getData();
+ int readLen = read.getReadBases().length;
+ byte[] quals = read.getBaseQualities();
+
+
+ int clipSum = 0, lastMax = -1, clipPoint = -1; // -1 means no clip
+ for (int i = readLen - 1; i >= 0; i--) {
+ int baseIndex = read.getReadNegativeStrandFlag() ? readLen - i - 1 : i;
+ byte qual = quals[baseIndex];
+ clipSum += (qTrimmingThreshold - qual);
+ if (clipSum >= 0 && (clipSum >= lastMax)) {
+ lastMax = clipSum;
+ clipPoint = baseIndex;
+ }
+ }
+
+ if (clipPoint != -1) {
+ int start = read.getReadNegativeStrandFlag() ? 0 : clipPoint;
+ int stop = read.getReadNegativeStrandFlag() ? clipPoint : readLen - 1;
+ //clipper.addOp(new ClippingOp(ClippingOp.ClippingType.LOW_Q_SCORES, start, stop, null));
+ ClippingOp op = new ClippingOp(start, stop);
+ clipper.addOp(op);
+ data.incNQClippedBases(op.getLength());
+ }
+ clipper.setData(data);
+ }
+
+ /**
+ * reduceInit is called once before any calls to the map function. We use it here to setup the output
+ * bam file, if it was specified on the command line
+ *
+ * @return
+ */
+ public ClippingData reduceInit() {
+ return new ClippingData(sequencesToClip);
+ }
+
+ public ClippingData reduce(ReadClipperWithData clipper, ClippingData data) {
+ if ( clipper == null )
+ return data;
+
+ GATKSAMRecord clippedRead = clipper.clipRead(clippingRepresentation);
+ if (outputBam != null) {
+ outputBam.addAlignment(clippedRead);
+ } else {
+ out.println(clippedRead.format());
+ }
+
+ data.nTotalReads++;
+ data.nTotalBases += clipper.getRead().getReadLength();
+ if (clipper.wasClipped()) {
+ data.nClippedReads++;
+ data.addData(clipper.getData());
+ }
+ return data;
+ }
+
+ public void onTraversalDone(ClippingData data) {
+ if ( out != null )
+ out.printf(data.toString());
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // utility classes
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ private static class SeqToClip {
+ String name;
+ String seq, revSeq;
+ Pattern fwdPat, revPat;
+
+ public SeqToClip(String name, String seq) {
+ this.name = name;
+ this.seq = seq;
+ this.fwdPat = Pattern.compile(seq, Pattern.CASE_INSENSITIVE);
+ this.revSeq = BaseUtils.simpleReverseComplement(seq);
+ this.revPat = Pattern.compile(revSeq, Pattern.CASE_INSENSITIVE);
+ }
+ }
+
+ public static class ClippingData {
+ public long nTotalReads = 0;
+ public long nTotalBases = 0;
+ public long nClippedReads = 0;
+ public long nClippedBases = 0;
+ public long nQClippedBases = 0;
+ public long nRangeClippedBases = 0;
+ public long nSeqClippedBases = 0;
+
+ HashMap<String, Long> seqClipCounts = new HashMap<String, Long>();
+
+ public ClippingData(List<SeqToClip> clipSeqs) {
+ for (SeqToClip clipSeq : clipSeqs) {
+ seqClipCounts.put(clipSeq.seq, 0L);
+ }
+ }
+
+ public void incNQClippedBases(int n) {
+ nQClippedBases += n;
+ nClippedBases += n;
+ }
+
+ public void incNRangeClippedBases(int n) {
+ nRangeClippedBases += n;
+ nClippedBases += n;
+ }
+
+ public void incSeqClippedBases(final String seq, int n) {
+ nSeqClippedBases += n;
+ nClippedBases += n;
+ seqClipCounts.put(seq, seqClipCounts.get(seq) + n);
+ }
+
+ public void addData (ClippingData data) {
+ nTotalReads += data.nTotalReads;
+ nTotalBases += data.nTotalBases;
+ nClippedReads += data.nClippedReads;
+ nClippedBases += data.nClippedBases;
+ nQClippedBases += data.nQClippedBases;
+ nRangeClippedBases += data.nRangeClippedBases;
+ nSeqClippedBases += data.nSeqClippedBases;
+
+ for (String seqClip : data.seqClipCounts.keySet()) {
+ Long count = data.seqClipCounts.get(seqClip);
+ if (seqClipCounts.containsKey(seqClip))
+ count += seqClipCounts.get(seqClip);
+ seqClipCounts.put(seqClip, count);
+ }
+ }
+
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+
+ s.append(Utils.dupString('-', 80) + "\n");
+ s.append(String.format("Number of examined reads %d%n", nTotalReads));
+ s.append(String.format("Number of clipped reads %d%n", nClippedReads));
+ s.append(String.format("Percent of clipped reads %.2f%n", (100.0 * nClippedReads) / nTotalReads));
+ s.append(String.format("Number of examined bases %d%n", nTotalBases));
+ s.append(String.format("Number of clipped bases %d%n", nClippedBases));
+ s.append(String.format("Percent of clipped bases %.2f%n", (100.0 * nClippedBases) / nTotalBases));
+ s.append(String.format("Number of quality-score clipped bases %d%n", nQClippedBases));
+ s.append(String.format("Number of range clipped bases %d%n", nRangeClippedBases));
+ s.append(String.format("Number of sequence clipped bases %d%n", nSeqClippedBases));
+
+ for (Map.Entry<String, Long> elt : seqClipCounts.entrySet()) {
+ s.append(String.format(" %8d clip sites matching %s%n", elt.getValue(), elt.getKey()));
+ }
+
+ s.append(Utils.dupString('-', 80) + "\n");
+ return s.toString();
+ }
+ }
+
+ public static class ReadClipperWithData extends ReadClipper {
+ private ClippingData data;
+
+ public ReadClipperWithData(GATKSAMRecord read, List<SeqToClip> clipSeqs) {
+ super(read);
+ data = new ClippingData(clipSeqs);
+ }
+
+ public ClippingData getData() {
+ return data;
+ }
+
+ public void setData(ClippingData data) {
+ this.data = data;
+ }
+
+ public void addData(ClippingData data) {
+ this.data.addData(data);
+ }
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReads.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReads.java
new file mode 100644
index 0000000..f271fe9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReads.java
@@ -0,0 +1,316 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.readutils;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMFileWriter;
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.engine.walkers.*;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Hidden;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.io.GATKSAMFileWriter;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformersMode;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.baq.BAQ;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * Renders, in SAM/BAM format, all reads from the input data set in the order in which they appear in the input file.
+ *
+ * <p>
+ * PrintReads can dynamically merge the contents of multiple input BAM files, resulting
+ * in merged output sorted in coordinate order. Can also optionally filter reads based on the
+ * --read_filter command line argument.
+ * </p>
+ *
+ * <p>
+ * Note that when PrintReads is used as part of the Base Quality Score Recalibration workflow,
+ * it takes the --BQSR engine argument, which is listed under Inherited Arguments > CommandLineGATK below.
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more bam files.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A single processed bam file.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T PrintReads \
+ * -o output.bam \
+ * -I input1.bam \
+ * -I input2.bam \
+ * --read_filter MappingQualityZero
+ *
+ * // Prints the first 2000 reads in the BAM file
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T PrintReads \
+ * -o output.bam \
+ * -I input.bam \
+ * -n 2000
+ *
+ * // Downsamples BAM file to 25%
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T PrintReads \
+ * -o output.bam \
+ * -I input.bam \
+ * -dfrac 0.25
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_DATA, extraDocs = {CommandLineGATK.class} )
+ at ReadTransformersMode(ApplicationTime = ReadTransformer.ApplicationTime.HANDLED_IN_WALKER)
+ at BAQMode(QualityMode = BAQ.QualityMode.ADD_TAG, ApplicationTime = ReadTransformer.ApplicationTime.HANDLED_IN_WALKER)
+ at Requires({DataSource.READS, DataSource.REFERENCE})
+public class PrintReads extends ReadWalker<GATKSAMRecord, SAMFileWriter> implements NanoSchedulable {
+
+ @Output(doc="Write output to this BAM filename instead of STDOUT")
+ GATKSAMFileWriter out;
+
+ @Argument(fullName = "readGroup", shortName = "readGroup", doc="Exclude all reads with this read group from the output", required = false)
+ String readGroup = null;
+
+ /**
+ * For example, --platform ILLUMINA or --platform 454.
+ */
+ @Argument(fullName = "platform", shortName = "platform", doc="Exclude all reads with this platform from the output", required = false)
+ String platform = null;
+
+ /**
+ * Only prints the first n reads of the file
+ */
+ @Argument(fullName = "number", shortName = "n", doc="Print the first n reads from the file, discarding the rest", required = false)
+ int nReadsToPrint = -1;
+
+ /**
+ * Only reads from samples listed in the provided file(s) will be included in the output.
+ */
+ @Argument(fullName="sample_file", shortName="sf", doc="File containing a list of samples (one per line). Can be specified multiple times", required=false)
+ public Set<File> sampleFile = new TreeSet<>();
+
+ /**
+ * Only reads from the sample(s) will be included in the output.
+ */
+ @Argument(fullName="sample_name", shortName="sn", doc="Sample name to be included in the analysis. Can be specified multiple times.", required=false)
+ public Set<String> sampleNames = new TreeSet<>();
+
+ /**
+ * Erase all extra attributes in the read but keep the read group information
+ */
+ @Argument(fullName="simplify", shortName="s", doc="Simplify all reads.", required=false)
+ public boolean simplifyReads = false;
+
+ @Hidden
+ @Argument(fullName = "no_pg_tag", shortName = "npt", doc ="", required = false)
+ public boolean NO_PG_TAG = false;
+
+ List<ReadTransformer> readTransformers = Collections.emptyList();
+ private Set<String> readGroupsToKeep = Collections.emptySet();
+
+ public static final String PROGRAM_RECORD_NAME = "GATK PrintReads"; // The name that will go in the @PG tag
+
+ Random random;
+
+
+ /**
+ * The initialize function.
+ */
+ public void initialize() {
+ final GenomeAnalysisEngine toolkit = getToolkit();
+
+ if ( toolkit != null )
+ readTransformers = toolkit.getReadTransformers();
+
+ //Sample names are case-insensitive
+ final TreeSet<String> samplesToChoose = new TreeSet<>(new Comparator<String>() {
+ @Override
+ public int compare(String a, String b) {
+ return a.compareToIgnoreCase(b);
+ }
+ });
+ Collection<String> samplesFromFile;
+ if (!sampleFile.isEmpty()) {
+ samplesFromFile = SampleUtils.getSamplesFromFiles(sampleFile);
+ samplesToChoose.addAll(samplesFromFile);
+ }
+
+ if (!sampleNames.isEmpty())
+ samplesToChoose.addAll(sampleNames);
+
+ random = GenomeAnalysisEngine.getRandomGenerator();
+
+ if (toolkit != null) {
+ final SAMFileHeader outputHeader = toolkit.getSAMFileHeader().clone();
+ readGroupsToKeep = determineReadGroupsOfInterest(outputHeader, samplesToChoose);
+
+ //If some read groups are to be excluded, remove them from the output header
+ pruneReadGroups(outputHeader);
+
+ //Add the program record (if appropriate) and set up the writer
+ final boolean preSorted = true;
+ if (toolkit.getArguments().BQSR_RECAL_FILE != null && !NO_PG_TAG ) {
+ Utils.setupWriter(out, toolkit, outputHeader, preSorted, this, PROGRAM_RECORD_NAME);
+ } else {
+ out.writeHeader(outputHeader);
+ out.setPresorted(preSorted);
+ }
+
+ }
+
+ }
+
+ /**
+ * The reads filter function.
+ *
+ * @param ref the reference bases that correspond to our read, if a reference was provided
+ * @param read the read itself, as a GATKSAMRecord
+ * @return true if the read passes the filter, false if it doesn't
+ */
+ public boolean filter(ReferenceContext ref, GATKSAMRecord read) {
+ // check that the read belongs to an RG that we need to keep
+ if (!readGroupsToKeep.isEmpty()) {
+ final SAMReadGroupRecord readGroup = read.getReadGroup();
+ if (!readGroupsToKeep.contains(readGroup.getReadGroupId()))
+ return false;
+ }
+
+ // check if we've reached the output limit
+ if ( nReadsToPrint == 0 ) {
+ return false; // n == 0 means we've printed all we needed.
+ }
+ else if (nReadsToPrint > 0) {
+ nReadsToPrint--; // n > 0 means there are still reads to be printed.
+ }
+
+ return true;
+ }
+
+ /**
+ * The reads map function.
+ *
+ * @param ref the reference bases that correspond to our read, if a reference was provided
+ * @param readIn the read itself, as a GATKSAMRecord
+ * @return the read itself
+ */
+ public GATKSAMRecord map( ReferenceContext ref, GATKSAMRecord readIn, RefMetaDataTracker metaDataTracker ) {
+ GATKSAMRecord workingRead = readIn;
+
+ for ( final ReadTransformer transformer : readTransformers ) {
+ workingRead = transformer.apply(workingRead);
+ }
+
+ if ( simplifyReads ) workingRead = workingRead.simplify();
+
+ return workingRead;
+ }
+
+ /**
+ * reduceInit is called once before any calls to the map function. We use it here to setup the output
+ * bam file, if it was specified on the command line
+ *
+ * @return SAMFileWriter, set to the BAM output file if the command line option was set, null otherwise
+ */
+ public SAMFileWriter reduceInit() {
+ return out;
+ }
+
+ /**
+ * given a read and a output location, reduce by emitting the read
+ *
+ * @param read the read itself
+ * @param output the output source
+ * @return the SAMFileWriter, so that the next reduce can emit to the same source
+ */
+ public SAMFileWriter reduce( GATKSAMRecord read, SAMFileWriter output ) {
+ output.addAlignment(read);
+ return output;
+ }
+
+ /**
+ * Determines the list of read groups that meet the user's criteria for inclusion (based on id, platform, or sample)
+ * @param header the merged header for all input files
+ * @param samplesToKeep the list of specific samples specified by the user
+ * @return a Set of read group IDs that meet the user's criteria, empty if all RGs should be included
+ */
+ private Set<String> determineReadGroupsOfInterest(final SAMFileHeader header, final Set<String> samplesToKeep) {
+ //If no filter options that use read group information have been supplied, exit early
+ if (platform == null && readGroup == null && samplesToKeep.isEmpty())
+ return Collections.emptySet();
+
+ if ( platform != null )
+ platform = platform.toUpperCase();
+
+ final Set<String> result = new HashSet<>();
+ for (final SAMReadGroupRecord rg : header.getReadGroups()) {
+ // To be eligible for output, a read group must:
+ // NOT have an id that is blacklisted on the command line (note that String.equals(null) is false)
+ // AND NOT have a platform that contains the blacklisted platform from the command line
+ // AND have a sample that is whitelisted on the command line
+ if (!rg.getReadGroupId().equals(readGroup) &&
+ (platform == null || !rg.getPlatform().toUpperCase().contains(platform)) &&
+ (samplesToKeep.isEmpty() || samplesToKeep.contains(rg.getSample())))
+ result.add(rg.getReadGroupId());
+ }
+
+ if (result.isEmpty())
+ throw new UserException.BadArgumentValue("-sn/-sf/-platform/-readGroup", "No read groups remain after pruning based on the supplied parameters");
+
+ return result;
+ }
+
+ private void pruneReadGroups(final SAMFileHeader header) {
+ if (readGroupsToKeep.isEmpty())
+ return;
+
+ final List<SAMReadGroupRecord> readGroups = new ArrayList<>();
+ for (final SAMReadGroupRecord rg : header.getReadGroups()) {
+ if (readGroupsToKeep.contains(rg.getReadGroupId()))
+ readGroups.add(rg);
+ }
+ header.setReadGroups(readGroups);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/ReadAdaptorTrimmer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/ReadAdaptorTrimmer.java
new file mode 100644
index 0000000..6f0ee85
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/ReadAdaptorTrimmer.java
@@ -0,0 +1,395 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.readutils;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.SAMFileWriter;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.walkers.NanoSchedulable;
+import org.broadinstitute.gatk.engine.walkers.PartitionBy;
+import org.broadinstitute.gatk.engine.walkers.PartitionType;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.utils.commandline.Advanced;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Hidden;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+/**
+ * Utility tool to blindly strip base adaptors. Main application is for FASTQ/unaligned BAM pre-processing where libraries
+ * have very short inserts, and hence a substantial part of the sequencing data will have adaptor sequence present.
+ * <p>
+ * By design, tool will only work for Illumina-like library constructs, where the typical library architecture is:
+ * [Adaptor 1]-[Genomic Insert]-[Adaptor 2 (index/barcode)]
+ * <p>
+ * It is assumed that when data is paired, one read will span the forward strand and one read will span the reverse strand.
+ * Hence, when specifying adaptors they should be specified as both forward and reverse-complement to make sure they're removed in all cases.
+ * By design, as well, "circular" constructions where a read can have an insert, then adaptor, then more genomic insert, are not supported.
+ * When an adaptor is detected, all bases downstream from it (i.e. in the 3' direction) will be removed.
+ * Adaptor detection is carried out by looking for overlaps between forward and reverse reads in a pair.
+ * If a sufficiently high overlap is found, the insert size is computed and if insert size < read lengths adaptor bases are removed from reads.
+ *
+ * Advantages over ReadClipper:
+ * - No previous knowledge of adaptors or library structure is necessary
+ *
+ * Advantages over 3rd party tools like SeqPrep:
+ * - Can do BAM streaming instead of having to convert to fastq
+ * - No need to merge reads - merging reads can have some advantages, but complicates downstream processing and loses information that can be used,
+ * e.g. in variant calling
+ * <p>
+ *
+ * <h2>Input</h2>
+ * <p>
+ * The input read data in BAM format. Read data MUST be in query name ordering as produced, for example with Picard's FastqToBam
+ *
+ * <h2>Output</h2>
+ * <p>
+ * A merged BAM file with unaligned reads
+ * </p>
+ *
+ * <h2>Examples</h2>
+ * <pre>
+ * java -Xmx4g -jar GenomeAnalysisTK.jar \
+ * -T ReadAdaptorTrimmer \
+ * -I my_reads.bam \
+ * -R resources/Homo_sapiens_assembly18.fasta \
+ * -o trimmed_Reads.bam
+ * </pre>
+ */
+
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_DATA, extraDocs = {CommandLineGATK.class} )
+ at PartitionBy(PartitionType.READ)
+public class ReadAdaptorTrimmer extends ReadWalker<List<GATKSAMRecord>, SAMFileWriter> implements NanoSchedulable {
+ @Output(doc="Write output to this BAM filename instead of STDOUT", required = false)
+ SAMFileWriter out;
+
+ /**
+ * Only prints the first n reads of the file - for short testing
+ */
+ @Hidden
+ @Argument(fullName = "number", shortName = "n", doc="Print the first n reads from the file, discarding the rest", required = false)
+ int nReadsToPrint = -1;
+
+ /**
+ * Argument to control strictness of match between forward and reverse reads - by default, we require 15 matches between them to declare
+ * an overlap.
+ */
+ @Advanced
+ @Argument(fullName = "minMatches", shortName = "minMatches", doc="Minimum number of substring matches to detect pair overlaps", required = false)
+ int minMatchesForOverlap = 15;
+
+
+ /**
+ * If true, this argument will make the walker discard unpaired reads instead of erroring out.
+ */
+ @Advanced
+ @Argument(fullName = "removeUnpairedReads", shortName = "removeUnpairedReads", doc="Remove unpaired reads instead of erroring out", required = false)
+ boolean cleanUnpairedReads = false;
+
+ /**
+ * private class members
+ */
+ private GATKSAMRecord firstReadInPair;
+ private TrimStats trimStats = new TrimStats();
+
+ static class TrimStats {
+ long numReadsProcessed;
+ long numReadsWithAdaptorTrimmed;
+ long numUnpairedReadsFound;
+ }
+
+ /**
+ * The reads filter function.
+ *
+ * @param ref the reference bases that correspond to our read, if a reference was provided
+ * @param read the read itself, as a GATKSAMRecord
+ * @return true if the read passes the filter, false if it doesn't
+ */
+ public boolean filter(ReferenceContext ref, GATKSAMRecord read) {
+ // check if we've reached the output limit
+ if ( nReadsToPrint == 0 ) {
+ return false; // n == 0 means we've printed all we needed.
+ }
+ else if (nReadsToPrint > 0) {
+ nReadsToPrint--; // n > 0 means there are still reads to be printed.
+ }
+ return true;
+ }
+ /**
+ * reduceInit is called once before any calls to the map function. We use it here to setup the output
+ * bam file, if it was specified on the command line
+ *
+ * @return SAMFileWriter, set to the BAM output file if the command line option was set, null otherwise
+ */
+ public SAMFileWriter reduceInit() {
+ return out;
+ }
+
+ public List<GATKSAMRecord> map( final ReferenceContext ref, final GATKSAMRecord readIn, final RefMetaDataTracker metaDataTracker ) {
+
+
+ final List<GATKSAMRecord> readsToEmit = new ArrayList<GATKSAMRecord>();
+
+
+ // cache first read in pair if flag set.
+ if (readIn.getFirstOfPairFlag()) {
+ firstReadInPair = GATKSAMRecord.emptyRead(readIn);
+ firstReadInPair.setReadString(readIn.getReadString());
+ firstReadInPair.setReadName(readIn.getReadName());
+ firstReadInPair.setBaseQualities(readIn.getBaseQualities());
+ }
+ else {
+ if (!readIn.getReadName().equals(firstReadInPair.getReadName())) {
+ if (cleanUnpairedReads) {
+ trimStats.numUnpairedReadsFound++;
+ return readsToEmit;
+ }
+ else // by default require that reads be completely paired
+ throw new IllegalStateException("Second read in pair must follow first read in pair: data not ordered?");
+ }
+
+ final int oldLength1 = firstReadInPair.getReadLength();
+ final int oldLength2 = readIn.getReadLength();
+ // try to strip any adaptor sequence in read pair
+ final Integer result = trimReads(firstReadInPair, readIn, minMatchesForOverlap, logger);
+
+ if (logger.isDebugEnabled()) {
+ if (result == null)
+ logger.debug("No overlap found, insert size cannot be computed");
+ else
+ logger.debug("Insert size estimate = " + result);
+
+ }
+
+
+ readsToEmit.add(firstReadInPair);
+ readsToEmit.add(readIn);
+
+ if (oldLength1 != firstReadInPair.getReadLength())
+ trimStats.numReadsWithAdaptorTrimmed++;
+ if (oldLength2 != readIn.getReadLength())
+ trimStats.numReadsWithAdaptorTrimmed++;
+
+ }
+
+
+ trimStats.numReadsProcessed++;
+ return readsToEmit;
+
+ }
+
+ /**
+ * given a read and a output location, reduce by emitting the read
+ *
+ * @param readsToEmit the read itself
+ * @param output the output source
+ * @return the SAMFileWriter, so that the next reduce can emit to the same source
+ */
+ public SAMFileWriter reduce( final List<GATKSAMRecord> readsToEmit, final SAMFileWriter output ) {
+ for (final GATKSAMRecord read : readsToEmit)
+ output.addAlignment(read);
+
+ return output;
+ }
+
+ @Override
+ public void onTraversalDone(SAMFileWriter output) {
+
+ logger.info("Finished Trimming:");
+ logger.info("Number of processed reads: "+ trimStats.numReadsProcessed);
+ logger.info("Number of reads with adaptor sequence trimmed: "+ trimStats.numReadsWithAdaptorTrimmed);
+ if (cleanUnpairedReads)
+ logger.info("Number of unpaired reads thrown out: "+ trimStats.numUnpairedReadsFound);
+ }
+
+
+ /**
+ *
+ * Workhorse routines...
+ *
+ */
+ /**
+ * Core routine that does most underlying work for walker. Takes two reads and looks for overlaps in them.
+ * An overlap is defined as a contiguous chunk of N bases that matches reverse-complement between reads.
+ * Currently, the only insert structure that it will look for overlaps is as follows:
+ * CASE 1: Insert shorter than read length:
+ * 3' XXXXXXXXXXXXXXXX 5' (second read)
+ * 5' YYYYYYYYYYYYYYYY 3' (first read)
+ * ***********
+ *
+ * In this case, if X and Y are complements at the 11 positions marked by *, routine will do the following
+ * iff minMatchesForOverlap <= 11:
+ * a) Cleave adaptor from end of second read (leftmost dangling part in diagram above)
+ * b) Cleave adaptor from end of first read (rightmost part in diagram).
+ *
+ * CASE 2: Insert size >= read length:
+ * 3' XXXXXXXXXXXXXXXX 5' (second read)
+ * 5' YYYYYYYYYYYYYYYY 3' (first read)
+ * ********* (overlap)
+ *
+ * In this case, no trimming is done and reads are left unchanged
+ * @param first (I/O) First read in pair - read contents (bases/quals) can be modified if adaptor is detected
+ * @param second (I/O) Second read in pair - read contents (bases/quals) can be modified if adaptor is detected
+ * @param minMatchesForOverlap Reads need to match in these # of bases to be joined
+ * @return Offset between second and first read.
+ * If there's no detectable offset, return Null
+ */
+ @Requires({"first != null","second != null","minMatchesForOverlap>0"})
+ protected static Integer trimReads(final GATKSAMRecord first,
+ final GATKSAMRecord second,
+ final int minMatchesForOverlap,
+ final Logger logger) {
+
+ final Integer insertSize = estimateInsertSize(first.getReadBases(), second.getReadBases(),
+ minMatchesForOverlap, logger);
+
+ if (insertSize == null)
+ return insertSize;
+ if (insertSize < first.getReadLength()) {
+ // trim adaptor sequence from read
+ first.setReadBases(Arrays.copyOfRange(first.getReadBases(),0,insertSize));
+ first.setBaseQualities(Arrays.copyOfRange(first.getBaseQualities(),0,insertSize));
+ }
+ if (insertSize < second.getReadLength()) {
+ // trim adaptor sequence from read
+ second.setReadBases(Arrays.copyOfRange(second.getReadBases(),0,insertSize));
+ second.setBaseQualities(Arrays.copyOfRange(second.getBaseQualities(),0,insertSize));
+ }
+ return insertSize;
+ }
+
+ /**
+ * Brain-dead implementation of an aligner of two sequences, where it's assumed that there might be an overlap
+ * from the first into the second. From this, an estimate of insert size is performed and returned
+ * Assumes that reads come in reverse direction, so one of the base sequences needs to be reverse-complemented.]
+ *
+ * @param firstRead Bytes from first read
+ * @param secondRead Bytes from second read (reverse direction)
+ * @return Estimated insert size based on offset between first and second read.
+ * If no overlap can be detected, return null
+ */
+
+ @Requires({"firstRead != null","secondRead != null","minMatches>0","firstRead.length == secondRead.length"})
+ protected static Integer estimateInsertSize(final byte[] firstRead,
+ final byte[] secondRead,
+ final int minMatches,
+ final Logger logger) {
+ final byte[] firstBases = firstRead;
+ final byte[] secondBases = BaseUtils.simpleReverseComplement(secondRead);
+
+ final Pair<Integer,Integer> overlaps = findOverlappingSequence(firstBases, secondBases);
+ final int bestOffset = overlaps.first;
+ final int maxScore = overlaps.second;
+ if ( logger.isDebugEnabled()) {
+ String sb="", s1 = new String(firstBases), s2 = new String(secondBases);
+ for (int k=0; k < Math.abs(bestOffset); k++) sb+=" ";
+ if (maxScore >= minMatches) {
+ logger.debug(String.format("Match, Max Score = %d, best offset = %d\n",maxScore, bestOffset));
+ if (bestOffset>0)
+ s2 = sb+s2;
+ else
+ s1 = sb+s1;
+ }
+ else logger.debug("NoMatch:");
+ logger.debug("R1:"+s1);
+ logger.debug("R2:"+s2);
+
+
+ }
+
+ if (maxScore < minMatches)
+ return null; // no overlap detected
+
+ return bestOffset+secondRead.length;
+
+
+ }
+
+
+ /**
+ * Tries to find overlapping sequence between two reads, and computes offset between them
+ * For each possible offset, computes matching score, which is = MATCH_SCORE*Num_matches + MISMATCH_SCORE*num_mismatches
+ * (like SW with infinite gap penalties).
+ * @param first First read bytes
+ * @param second Second read bytes
+ * @return Pair of integers (x,y). x = best offset between reads, y = corresponding score
+ */
+ @Requires({"first != null","second != null"})
+ @Ensures("result != null")
+ protected static Pair<Integer,Integer> findOverlappingSequence(final byte[] first,
+ final byte[] second) {
+ final int MATCH_SCORE = 1;
+ final int MISMATCH_SCORE = -1;
+ // try every possible offset - O(N^2) algorithm
+
+ // In case of following structure,
+ // 111111111
+ // 222222222
+ // computed offset will be negative (=-5 in this case).
+ // If however,
+ // 111111111
+ // 222222222
+ // then offset will be positive (=3 in this case)
+ int maxScore = 0, bestOffset =0;
+ for (int offset = -second.length; offset < first.length; offset++) {
+ int score = 0;
+ // compute start index for each array
+ int ind1 = (offset<0)?0:offset;
+ int ind2 = (offset<0)?-offset:0;
+ for (int k=0; k < Math.min(first.length, second.length) ; k++) {
+ if (ind1 >= first.length)
+ break;
+ if (ind2 >= second.length )
+ break;
+ if (first[ind1] != 'N' && second[ind2] != 'N') {
+ if (first[ind1] == second[ind2])
+ score += MATCH_SCORE;
+ else
+ score += MISMATCH_SCORE;
+ }
+ ind1++;
+ ind2++;
+ }
+ if (score > maxScore) {
+ maxScore = score;
+ bestOffset = offset;
+ }
+ }
+ return new Pair<Integer, Integer>(bestOffset,maxScore);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/SplitSamFile.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/SplitSamFile.java
new file mode 100644
index 0000000..f4ee4a4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/readutils/SplitSamFile.java
@@ -0,0 +1,151 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.readutils;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMFileWriter;
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecord;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.DataSource;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.Requires;
+import org.broadinstitute.gatk.engine.walkers.WalkerName;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Divides the input data set into separate BAM files, one for each sample in the input data set. The split
+ * files are named concatenating the sample name to the end of the provided outputRoot command-line argument.
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_DATA, extraDocs = {CommandLineGATK.class} )
+ at WalkerName("SplitSamFile")
+ at Requires({DataSource.READS})
+public class SplitSamFile extends ReadWalker<SAMRecord, Map<String, SAMFileWriter>> {
+ @Argument(fullName="outputRoot", doc="output BAM file", required=false)
+ public String outputRoot = "";
+
+ private static final Logger logger = Logger.getLogger(SplitSamFile.class);
+ private static final String VERSION = "0.0.1";
+
+ @Override
+ public void initialize() {
+ logger.info("SplitSamFile version: " + VERSION);
+ }
+
+ @Override
+ public SAMRecord map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker metaDataTracker) {
+ return read;
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // Standard I/O routines
+ //
+ // --------------------------------------------------------------------------------------------------------------
+ @Override
+ public void onTraversalDone(Map<String, SAMFileWriter> outputs) {
+ for ( SAMFileWriter output : outputs.values() ) {
+ output.close();
+ }
+ }
+
+ @Override
+ public Map<String, SAMFileWriter> reduceInit() {
+ HashMap<String, SAMFileHeader> headers = new HashMap<>();
+ for ( SAMReadGroupRecord readGroup : this.getToolkit().getSAMFileHeader().getReadGroups()) {
+ final String sample = readGroup.getSample();
+ if ( ! headers.containsKey(sample) ) {
+ SAMFileHeader header = duplicateSAMFileHeader(this.getToolkit().getSAMFileHeader());
+ logger.debug(String.format("Creating BAM header for sample %s", sample));
+ ArrayList<SAMReadGroupRecord> readGroups = new ArrayList<>();
+ header.setReadGroups(readGroups);
+ headers.put(sample, header);
+ }
+
+ SAMFileHeader header = headers.get(sample);
+ List<SAMReadGroupRecord> newReadGroups = new ArrayList<>(header.getReadGroups());
+ newReadGroups.add(readGroup);
+ header.setReadGroups(newReadGroups);
+ }
+
+ HashMap<String, SAMFileWriter> outputs = new HashMap<>();
+ for ( Map.Entry<String, SAMFileHeader> elt : headers.entrySet() ) {
+ final String sample = elt.getKey();
+ final String filename = outputRoot + sample + ".bam";
+ logger.info(String.format("Creating BAM output file %s for sample %s", filename, sample));
+
+ final SAMFileWriter output = ReadUtils.createSAMFileWriter(filename, getToolkit(), elt.getValue());
+ outputs.put(sample, output);
+ }
+
+ return outputs;
+ }
+
+ /**
+ * Write out the read
+ */
+ @Override
+ public Map<String, SAMFileWriter> reduce(SAMRecord read, Map<String, SAMFileWriter> outputs) {
+ final String sample = read.getReadGroup().getSample();
+ SAMFileWriter output = outputs.get(sample);
+
+ if ( output != null ) {
+ output.addAlignment(read);
+ } else {
+ throw new RuntimeException(String.format("Read group %s not present in header but found in read %s", read.getReadGroup().getReadGroupId(), read.getReadName()));
+ }
+
+ return outputs;
+ }
+
+ public static SAMFileHeader duplicateSAMFileHeader(SAMFileHeader toCopy) {
+ SAMFileHeader copy = new SAMFileHeader();
+
+ copy.setSortOrder(toCopy.getSortOrder());
+ copy.setGroupOrder(toCopy.getGroupOrder());
+ copy.setProgramRecords(toCopy.getProgramRecords());
+ copy.setReadGroups(toCopy.getReadGroups());
+ copy.setSequenceDictionary(toCopy.getSequenceDictionary());
+
+ for (Map.Entry<String, String> e : toCopy.getAttributes())
+ copy.setAttribute(e.getKey(), e.getValue());
+
+ return copy;
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/VariantEval.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/VariantEval.java
new file mode 100644
index 0000000..67c1fcb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/VariantEval.java
@@ -0,0 +1,666 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval;
+
+import com.google.java.contract.Requires;
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.util.IntervalTree;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.engine.walkers.*;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.arguments.DbsnpArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.evaluators.VariantEvaluator;
+import org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.IntervalStratification;
+import org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.VariantStratifier;
+import org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.manager.StratificationManager;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.EvaluationContext;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.SortableJexlVCMatchExp;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.VariantEvalUtils;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.vcf.VCFHeader;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+import htsjdk.variant.variantcontext.VariantContextUtils;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.util.*;
+
+/**
+ * General-purpose tool for variant evaluation (% in dbSNP, genotype concordance, Ti/Tv ratios, and a lot more)
+ *
+ * <p>
+ * Given a variant callset, it is common to calculate various quality control metrics. These metrics include the number of
+ * raw or filtered SNP counts; ratio of transition mutations to transversions; concordance of a particular sample's calls
+ * to a genotyping chip; number of singletons per sample; etc. Furthermore, it is often useful to stratify these metrics
+ * by various criteria like functional class (missense, nonsense, silent), whether the site is CpG site, the amino acid
+ * degeneracy of the site, etc. VariantEval facilitates these calculations in two ways: by providing several built-in
+ * evaluation and stratification modules, and by providing a framework that permits the easy development of new evaluation
+ * and stratification modules.
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more variant sets to evaluate plus any number of comparison sets.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Evaluation tables detailing the results of the eval modules which were applied.
+ * For example:
+ * <pre>
+ * output.eval.gatkreport:
+ * ##:GATKReport.v0.1 CountVariants : Counts different classes of variants in the sample
+ * CountVariants CompRod CpG EvalRod JexlExpression Novelty nProcessedLoci nCalledLoci nRefLoci nVariantLoci variantRate ...
+ * CountVariants dbsnp CpG eval none all 65900028 135770 0 135770 0.00206024 ...
+ * CountVariants dbsnp CpG eval none known 65900028 47068 0 47068 0.00071423 ...
+ * CountVariants dbsnp CpG eval none novel 65900028 88702 0 88702 0.00134601 ...
+ * CountVariants dbsnp all eval none all 65900028 330818 0 330818 0.00502000 ...
+ * CountVariants dbsnp all eval none known 65900028 120685 0 120685 0.00183133 ...
+ * CountVariants dbsnp all eval none novel 65900028 210133 0 210133 0.00318866 ...
+ * CountVariants dbsnp non_CpG eval none all 65900028 195048 0 195048 0.00295976 ...
+ * CountVariants dbsnp non_CpG eval none known 65900028 73617 0 73617 0.00111710 ...
+ * CountVariants dbsnp non_CpG eval none novel 65900028 121431 0 121431 0.00184265 ...
+ * ...
+ * </pre>
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T VariantEval \
+ * -o output.eval.gatkreport \
+ * --eval:set1 set1.vcf \
+ * --eval:set2 set2.vcf \
+ * [--comp comp.vcf]
+ * </pre>
+ *
+ * <h3>Caveat</h3>
+ *
+ * <p>Some stratifications and evaluators are incompatible with each other due to their respective memory requirements, such as AlleleCount and VariantSummary, or Sample and VariantSummary.
+ * If you specify such a combination, the program will output an error message and ask you to disable one of these options.
+ * We do not currently provide an exhaustive list of incompatible combinations, so we recommend trying out combinations that you are interested in on a dummy command line, to rapidly ascertain whether it will work or not.</p>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+ at Reference(window=@Window(start=-50, stop=50))
+ at PartitionBy(PartitionType.NONE)
+public class VariantEval extends RodWalker<Integer, Integer> implements TreeReducible<Integer> {
+ public static final String IS_SINGLETON_KEY = "ISSINGLETON";
+
+ @Output
+ protected PrintStream out;
+
+ /**
+ * The variant file(s) to evaluate.
+ */
+ @Input(fullName="eval", shortName = "eval", doc="Input evaluation file(s)", required=true)
+ public List<RodBinding<VariantContext>> evals;
+
+ /**
+ * The variant file(s) to compare against.
+ */
+ @Input(fullName="comp", shortName = "comp", doc="Input comparison file(s)", required=false)
+ public List<RodBinding<VariantContext>> compsProvided = Collections.emptyList();
+ private List<RodBinding<VariantContext>> comps = new ArrayList<RodBinding<VariantContext>>();
+
+ /**
+ * dbSNP comparison VCF. By default, the dbSNP file is used to specify the set of "known" variants.
+ * Other sets can be specified with the -knownName (--known_names) argument.
+ */
+ @ArgumentCollection
+ protected DbsnpArgumentCollection dbsnp = new DbsnpArgumentCollection();
+
+ /**
+ * Some analyses want to count overlap not with dbSNP (which is in general very open) but
+ * actually want to itemize their overlap specifically with a set of gold standard sites
+ * such as HapMap, OMNI, or the gold standard indels. This argument provides a mechanism
+ * for communicating which file to use
+ */
+ @Input(fullName="goldStandard", shortName = "gold", doc="Evaluations that count calls at sites of true variation (e.g., indel calls) will use this argument as their gold standard for comparison", required=false)
+ public RodBinding<VariantContext> goldStandard = null;
+
+ /**
+ * Note that the --list argument requires a fully resolved and correct command-line to work.
+ */
+ @Argument(fullName="list", shortName="ls", doc="List the available eval modules and exit", required=false)
+ protected Boolean LIST = false;
+
+ // Partitioning the data arguments
+ @Argument(shortName="select", doc="One or more stratifications to use when evaluating the data", required=false)
+ protected ArrayList<String> SELECT_EXPS = new ArrayList<String>();
+
+ @Argument(shortName="selectName", doc="Names to use for the list of stratifications (must be a 1-to-1 mapping)", required=false)
+ protected ArrayList<String> SELECT_NAMES = new ArrayList<String>();
+
+ @Argument(fullName="sample", shortName="sn", doc="Derive eval and comp contexts using only these sample genotypes, when genotypes are available in the original context", required=false)
+ protected Set<String> SAMPLE_EXPRESSIONS;
+
+ /**
+ * List of rod tracks to be used for specifying "known" variants other than dbSNP.
+ */
+ @Argument(shortName="knownName", doc="Name of ROD bindings containing variant sites that should be treated as known when splitting eval rods into known and novel subsets", required=false)
+ protected HashSet<String> KNOWN_NAMES = new HashSet<String>();
+ List<RodBinding<VariantContext>> knowns = new ArrayList<RodBinding<VariantContext>>();
+
+ // Stratification arguments
+ @Argument(fullName="stratificationModule", shortName="ST", doc="One or more specific stratification modules to apply to the eval track(s) (in addition to the standard stratifications, unless -noS is specified)", required=false)
+ protected String[] STRATIFICATIONS_TO_USE = {};
+
+ @Argument(fullName="doNotUseAllStandardStratifications", shortName="noST", doc="Do not use the standard stratification modules by default (instead, only those that are specified with the -S option)", required=false)
+ protected Boolean NO_STANDARD_STRATIFICATIONS = false;
+
+ /**
+ * See the -list argument to view available modules.
+ */
+ @Argument(fullName="evalModule", shortName="EV", doc="One or more specific eval modules to apply to the eval track(s) (in addition to the standard modules, unless -noEV is specified)", required=false)
+ protected String[] MODULES_TO_USE = {};
+
+ @Argument(fullName="doNotUseAllStandardModules", shortName="noEV", doc="Do not use the standard modules by default (instead, only those that are specified with the -EV option)", required=false)
+ protected Boolean NO_STANDARD_MODULES = false;
+
+ @Argument(fullName="minPhaseQuality", shortName="mpq", doc="Minimum phasing quality", required=false)
+ protected double MIN_PHASE_QUALITY = 10.0;
+
+ @Argument(shortName="mvq", fullName="mendelianViolationQualThreshold", doc="Minimum genotype QUAL score for each trio member required to accept a site as a violation. Default is 50.", required=false)
+ protected double MENDELIAN_VIOLATION_QUAL_THRESHOLD = 50;
+
+ @Argument(shortName="ploidy", fullName="samplePloidy", doc="Per-sample ploidy (number of chromosomes per sample)", required=false)
+ protected int ploidy = GATKVariantContextUtils.DEFAULT_PLOIDY;
+
+ @Argument(fullName="ancestralAlignments", shortName="aa", doc="Fasta file with ancestral alleles", required=false)
+ private File ancestralAlignmentsFile = null;
+
+ @Argument(fullName="requireStrictAlleleMatch", shortName="strict", doc="If provided only comp and eval tracks with exactly matching reference and alternate alleles will be counted as overlapping", required=false)
+ private boolean requireStrictAlleleMatch = false;
+
+ @Argument(fullName="keepAC0", shortName="keepAC0", doc="If provided, modules that track polymorphic sites will not require that a site have AC > 0 when the input eval has genotypes", required=false)
+ private boolean keepSitesWithAC0 = false;
+
+ @Hidden
+ @Argument(fullName="numSamples", shortName="numSamples", doc="If provided, modules that track polymorphic sites will not require that a site have AC > 0 when the input eval has genotypes", required=false)
+ private int numSamplesFromArgument = 0;
+
+ /**
+ * If true, VariantEval will treat -eval 1 -eval 2 as separate tracks from the same underlying
+ * variant set, and evaluate the union of the results. Useful when you want to do -eval chr1.vcf -eval chr2.vcf etc.
+ */
+ @Argument(fullName="mergeEvals", shortName="mergeEvals", doc="If provided, all -eval tracks will be merged into a single eval track", required=false)
+ public boolean mergeEvals = false;
+
+ /**
+ * File containing tribble-readable features for the IntervalStratificiation
+ */
+ @Input(fullName="stratIntervals", shortName="stratIntervals", doc="File containing tribble-readable features for the IntervalStratificiation", required=false)
+ public IntervalBinding<Feature> intervalsFile = null;
+
+ /**
+ * File containing tribble-readable features containing known CNVs. For use with VariantSummary table.
+ */
+ @Input(fullName="knownCNVs", shortName="knownCNVs", doc="File containing tribble-readable features describing a known list of copy number variants", required=false)
+ public IntervalBinding<Feature> knownCNVsFile = null;
+ Map<String, IntervalTree<GenomeLoc>> knownCNVsByContig = Collections.emptyMap();
+
+ // Variables
+ private Set<SortableJexlVCMatchExp> jexlExpressions = new TreeSet<SortableJexlVCMatchExp>();
+
+ private boolean isSubsettingSamples;
+ private Set<String> sampleNamesForEvaluation = new LinkedHashSet<String>();
+ private Set<String> sampleNamesForStratification = new LinkedHashSet<String>();
+
+ // important stratifications
+ private boolean byFilterIsEnabled = false;
+ private boolean perSampleIsEnabled = false;
+
+ // Public constants
+ private static String ALL_SAMPLE_NAME = "all";
+
+ // the number of processed bp for this walker
+ long nProcessedLoci = 0;
+
+ // Utility class
+ private final VariantEvalUtils variantEvalUtils = new VariantEvalUtils(this);
+
+ // Ancestral alignments
+ private IndexedFastaSequenceFile ancestralAlignments = null;
+
+ // The set of all possible evaluation contexts
+ StratificationManager<VariantStratifier, EvaluationContext> stratManager;
+ //Set<DynamicStratification> dynamicStratifications = Collections.emptySet();
+
+ /**
+ * Initialize the stratifications, evaluations, evaluation contexts, and reporting object
+ */
+ public void initialize() {
+ // Just list the modules, and exit quickly.
+ if (LIST) { variantEvalUtils.listModulesAndExit(); }
+
+ // maintain the full list of comps
+ comps.addAll(compsProvided);
+ if ( dbsnp.dbsnp.isBound() ) {
+ comps.add(dbsnp.dbsnp);
+ knowns.add(dbsnp.dbsnp);
+ }
+
+ // Add a dummy comp track if none exists
+ if ( comps.size() == 0 )
+ comps.add(new RodBinding<VariantContext>(VariantContext.class, "none", "UNBOUND", "", new Tags()));
+
+ // Set up set of additional knowns
+ for ( RodBinding<VariantContext> compRod : comps ) {
+ if ( KNOWN_NAMES.contains(compRod.getName()) )
+ knowns.add(compRod);
+ }
+
+ // Now that we have all the rods categorized, determine the sample list from the eval rods.
+ Map<String, VCFHeader> vcfRods = GATKVCFUtils.getVCFHeadersFromRods(getToolkit(), evals);
+ Set<String> vcfSamples = SampleUtils.getSampleList(vcfRods, GATKVariantContextUtils.GenotypeMergeType.REQUIRE_UNIQUE);
+
+ // Load the sample list, using an intermediate tree set to sort the samples
+ final Set<String> allSampleNames = SampleUtils.getSamplesFromCommandLineInput(vcfSamples);
+ sampleNamesForEvaluation.addAll(new TreeSet<String>(SampleUtils.getSamplesFromCommandLineInput(vcfSamples, SAMPLE_EXPRESSIONS)));
+ isSubsettingSamples = ! sampleNamesForEvaluation.containsAll(allSampleNames);
+
+ if (Arrays.asList(STRATIFICATIONS_TO_USE).contains("Sample")) {
+ sampleNamesForStratification.addAll(sampleNamesForEvaluation);
+ }
+ sampleNamesForStratification.add(ALL_SAMPLE_NAME);
+
+ // Initialize select expressions
+ for (VariantContextUtils.JexlVCMatchExp jexl : VariantContextUtils.initializeMatchExps(SELECT_NAMES, SELECT_EXPS)) {
+ SortableJexlVCMatchExp sjexl = new SortableJexlVCMatchExp(jexl.name, jexl.exp);
+ jexlExpressions.add(sjexl);
+ }
+
+ // Initialize the set of stratifications and evaluations to use
+ // The list of stratifiers and evaluators to use
+ final List<VariantStratifier> stratificationObjects = variantEvalUtils.initializeStratificationObjects(NO_STANDARD_STRATIFICATIONS, STRATIFICATIONS_TO_USE);
+ final Set<Class<? extends VariantEvaluator>> evaluationClasses = variantEvalUtils.initializeEvaluationObjects(NO_STANDARD_MODULES, MODULES_TO_USE);
+
+ checkForIncompatibleEvaluatorsAndStratifiers(stratificationObjects, evaluationClasses);
+
+ for ( VariantStratifier vs : stratificationObjects ) {
+ if ( vs.getName().equals("Filter") )
+ byFilterIsEnabled = true;
+ else if ( vs.getName().equals("Sample") )
+ perSampleIsEnabled = true;
+ }
+
+ if ( intervalsFile != null ) {
+ boolean fail = true;
+ for ( final VariantStratifier vs : stratificationObjects ) {
+ if ( vs.getClass().equals(IntervalStratification.class) )
+ fail = false;
+ }
+ if ( fail )
+ throw new UserException.BadArgumentValue("ST", "stratIntervals argument provided but -ST IntervalStratification not provided");
+ }
+
+ // Initialize the evaluation contexts
+ createStratificationStates(stratificationObjects, evaluationClasses);
+
+ // Load ancestral alignments
+ if (ancestralAlignmentsFile != null) {
+ try {
+ ancestralAlignments = new IndexedFastaSequenceFile(ancestralAlignmentsFile);
+ } catch (FileNotFoundException e) {
+ throw new ReviewedGATKException(String.format("The ancestral alignments file, '%s', could not be found", ancestralAlignmentsFile.getAbsolutePath()));
+ }
+ }
+
+ // initialize CNVs
+ if ( knownCNVsFile != null ) {
+ knownCNVsByContig = createIntervalTreeByContig(knownCNVsFile);
+ }
+ }
+
+ final void checkForIncompatibleEvaluatorsAndStratifiers( final List<VariantStratifier> stratificationObjects,
+ Set<Class<? extends VariantEvaluator>> evaluationClasses) {
+ for ( final VariantStratifier vs : stratificationObjects ) {
+ for ( Class<? extends VariantEvaluator> ec : evaluationClasses )
+ if ( vs.getIncompatibleEvaluators().contains(ec) )
+ throw new UserException.BadArgumentValue("ST and ET",
+ "The selected stratification " + vs.getName() +
+ " and evaluator " + ec.getSimpleName() +
+ " are incompatible due to combinatorial memory requirements." +
+ " Please disable one");
+ }
+ }
+
+ final void createStratificationStates(final List<VariantStratifier> stratificationObjects, final Set<Class<? extends VariantEvaluator>> evaluationObjects) {
+ final List<VariantStratifier> strats = new ArrayList<VariantStratifier>(stratificationObjects);
+ stratManager = new StratificationManager<VariantStratifier, EvaluationContext>(strats);
+
+ logger.info("Creating " + stratManager.size() + " combinatorial stratification states");
+ for ( int i = 0; i < stratManager.size(); i++ ) {
+ EvaluationContext ec = new EvaluationContext(this, evaluationObjects);
+ stratManager.set(i, ec);
+ }
+ }
+
+ public final Map<String, IntervalTree<GenomeLoc>> createIntervalTreeByContig(final IntervalBinding<Feature> intervals) {
+ final Map<String, IntervalTree<GenomeLoc>> byContig = new HashMap<String, IntervalTree<GenomeLoc>>();
+
+ final List<GenomeLoc> locs = intervals.getIntervals(getToolkit());
+
+ // set up the map from contig -> interval tree
+ for ( final String contig : getContigNames() )
+ byContig.put(contig, new IntervalTree<GenomeLoc>());
+
+ for ( final GenomeLoc loc : locs ) {
+ byContig.get(loc.getContig()).put(loc.getStart(), loc.getStop(), loc);
+ }
+
+ return byContig;
+ }
+
+ /**
+ * Collect relevant information from each variant in the supplied VCFs
+ */
+ @Override
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ // we track the processed bp and expose this for modules instead of wasting CPU power on calculating
+ // the same thing over and over in evals that want the processed bp
+ synchronized (this) {
+ nProcessedLoci += context.getSkippedBases() + (ref == null ? 0 : 1);
+ }
+
+ if (tracker != null) {
+ String aastr = (ancestralAlignments == null) ? null : new String(ancestralAlignments.getSubsequenceAt(ref.getLocus().getContig(), ref.getLocus().getStart(), ref.getLocus().getStop()).getBases());
+
+// // update the dynamic stratifications
+// for (final VariantContext vc : tracker.getValues(evals, ref.getLocus())) {
+// // don't worry -- DynamicStratification only work with one eval object
+// for ( final DynamicStratification ds : dynamicStratifications ) {
+// ds.update(vc);
+// }
+// }
+
+ // --------- track --------- sample - VariantContexts -
+ HashMap<RodBinding<VariantContext>, HashMap<String, Collection<VariantContext>>> evalVCs = variantEvalUtils.bindVariantContexts(tracker, ref, evals, byFilterIsEnabled, true, perSampleIsEnabled, mergeEvals);
+ HashMap<RodBinding<VariantContext>, HashMap<String, Collection<VariantContext>>> compVCs = variantEvalUtils.bindVariantContexts(tracker, ref, comps, byFilterIsEnabled, false, false, false);
+
+ // for each eval track
+ for ( final RodBinding<VariantContext> evalRod : evals ) {
+ final Map<String, Collection<VariantContext>> emptyEvalMap = Collections.emptyMap();
+ final Map<String, Collection<VariantContext>> evalSet = evalVCs.containsKey(evalRod) ? evalVCs.get(evalRod) : emptyEvalMap;
+
+ // for each sample stratifier
+ for ( final String sampleName : sampleNamesForStratification ) {
+ Collection<VariantContext> evalSetBySample = evalSet.get(sampleName);
+ if ( evalSetBySample == null ) {
+ evalSetBySample = new HashSet<VariantContext>(1);
+ evalSetBySample.add(null);
+ }
+
+ // for each eval in the track
+ for ( VariantContext eval : evalSetBySample ) {
+ // deal with ancestral alleles if requested
+ if ( eval != null && aastr != null ) {
+ eval = new VariantContextBuilder(eval).attribute("ANCESTRALALLELE", aastr).make();
+ }
+
+ // for each comp track
+ for ( final RodBinding<VariantContext> compRod : comps ) {
+ // no sample stratification for comps
+ final HashMap<String, Collection<VariantContext>> compSetHash = compVCs.get(compRod);
+ final Collection<VariantContext> compSet = (compSetHash == null || compSetHash.size() == 0) ? Collections.<VariantContext>emptyList() : compVCs.get(compRod).values().iterator().next();
+
+ // find the comp
+ final VariantContext comp = findMatchingComp(eval, compSet);
+
+ for ( EvaluationContext nec : getEvaluationContexts(tracker, ref, eval, evalRod.getName(), comp, compRod.getName(), sampleName) ) {
+
+ // eval against the comp
+ synchronized (nec) {
+ nec.apply(tracker, ref, context, comp, eval);
+ }
+
+ // eval=null against all comps of different type that aren't bound to another eval
+ for ( VariantContext otherComp : compSet ) {
+ if ( otherComp != comp && ! compHasMatchingEval(otherComp, evalSetBySample) ) {
+ synchronized (nec) {
+ nec.apply(tracker, ref, context, otherComp, null);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( mergeEvals ) break; // stop processing the eval tracks
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Given specific eval and comp VCs and the sample name, return an iterable
+ * over all of the applicable state keys.
+ *
+ * this code isn't structured yet for efficiency. Here we currently are
+ * doing the following inefficient algorithm:
+ *
+ * for each strat:
+ * get list of relevant states that eval and comp according to strat
+ * add this list of states to a list of list states
+ *
+ * then
+ *
+ * ask the strat manager to look up all of the keys associated with the combinations
+ * of these states. For example, suppose we have a single variant S. We have active
+ * strats EvalRod, CompRod, and Novelty. We produce a list that looks like:
+ *
+ * L = [[Eval], [Comp], [All, Novel]]
+ *
+ * We then go through the strat manager tree to produce the keys associated with these states:
+ *
+ * K = [0, 1] where EVAL x COMP x ALL = 0 and EVAL x COMP x NOVEL = 1
+ *
+ * It's clear that a better
+ *
+ * TODO -- create an inline version that doesn't create the intermediate list of list
+ *
+ * @param tracker
+ * @param ref
+ * @param eval
+ * @param evalName
+ * @param comp
+ * @param compName
+ * @param sampleName
+ * @return
+ */
+ protected Collection<EvaluationContext> getEvaluationContexts(final RefMetaDataTracker tracker,
+ final ReferenceContext ref,
+ final VariantContext eval,
+ final String evalName,
+ final VariantContext comp,
+ final String compName,
+ final String sampleName ) {
+ final List<List<Object>> states = new LinkedList<List<Object>>();
+ for ( final VariantStratifier vs : stratManager.getStratifiers() ) {
+ states.add(vs.getRelevantStates(ref, tracker, comp, compName, eval, evalName, sampleName));
+ }
+ return stratManager.values(states);
+ }
+
+
+ @Requires({"comp != null", "evals != null"})
+ private boolean compHasMatchingEval(final VariantContext comp, final Collection<VariantContext> evals) {
+ // find all of the matching comps
+ for ( final VariantContext eval : evals ) {
+ if ( eval != null && doEvalAndCompMatch(comp, eval, requireStrictAlleleMatch) != EvalCompMatchType.NO_MATCH )
+ return true;
+ }
+
+ // nothing matched
+ return false;
+ }
+
+ private enum EvalCompMatchType { NO_MATCH, STRICT, LENIENT }
+
+ @Requires({"eval != null", "comp != null"})
+ private EvalCompMatchType doEvalAndCompMatch(final VariantContext eval, final VariantContext comp, boolean requireStrictAlleleMatch) {
+ if ( comp.getType() == VariantContext.Type.NO_VARIATION || eval.getType() == VariantContext.Type.NO_VARIATION )
+ // if either of these are NO_VARIATION they are LENIENT matches
+ return EvalCompMatchType.LENIENT;
+
+ if ( comp.getType() != eval.getType() )
+ return EvalCompMatchType.NO_MATCH;
+
+ // find the comp which matches both the reference allele and alternate allele from eval
+ final Allele altEval = eval.getAlternateAlleles().size() == 0 ? null : eval.getAlternateAllele(0);
+ final Allele altComp = comp.getAlternateAlleles().size() == 0 ? null : comp.getAlternateAllele(0);
+ if ((altEval == null && altComp == null) || (altEval != null && altEval.equals(altComp) && eval.getReference().equals(comp.getReference())))
+ return EvalCompMatchType.STRICT;
+ else
+ return requireStrictAlleleMatch ? EvalCompMatchType.NO_MATCH : EvalCompMatchType.LENIENT;
+ }
+
+ private VariantContext findMatchingComp(final VariantContext eval, final Collection<VariantContext> comps) {
+ // if no comps, return null
+ if ( comps == null || comps.isEmpty() )
+ return null;
+
+ // if no eval, return any comp
+ if ( eval == null )
+ return comps.iterator().next();
+
+ // find all of the matching comps
+ VariantContext lenientMatch = null;
+ for ( final VariantContext comp : comps ) {
+ switch ( doEvalAndCompMatch(comp, eval, requireStrictAlleleMatch) ) {
+ case STRICT:
+ return comp;
+ case LENIENT:
+ if ( lenientMatch == null ) lenientMatch = comp;
+ break;
+ case NO_MATCH:
+ // do nothing
+ }
+ }
+
+ // nothing matched, just return lenientMatch, which might be null
+ return lenientMatch;
+ }
+
+ public Integer treeReduce(Integer lhs, Integer rhs) { return null; }
+
+ @Override
+ public Integer reduceInit() { return null; }
+
+ @Override
+ public Integer reduce(Integer value, Integer sum) { return null; }
+
+ /**
+ * Output the finalized report
+ *
+ * @param result an integer that doesn't get used for anything
+ */
+ public void onTraversalDone(Integer result) {
+ logger.info("Finalizing variant report");
+
+ // go through the evaluations and finalize them
+ for ( final EvaluationContext nec : stratManager.values() )
+ for ( final VariantEvaluator ve : nec.getVariantEvaluators() )
+ ve.finalizeEvaluation();
+
+ VariantEvalReportWriter.writeReport(out, stratManager, stratManager.getStratifiers(), stratManager.get(0).getVariantEvaluators());
+ }
+
+ // Accessors
+ public Logger getLogger() { return logger; }
+
+ public double getMinPhaseQuality() { return MIN_PHASE_QUALITY; }
+
+ public int getSamplePloidy() { return ploidy; }
+ public double getMendelianViolationQualThreshold() { return MENDELIAN_VIOLATION_QUAL_THRESHOLD; }
+
+ public static String getAllSampleName() { return ALL_SAMPLE_NAME; }
+
+ public List<RodBinding<VariantContext>> getKnowns() { return knowns; }
+
+ public List<RodBinding<VariantContext>> getEvals() { return evals; }
+
+ public boolean isSubsettingToSpecificSamples() { return isSubsettingSamples; }
+ public Set<String> getSampleNamesForEvaluation() { return sampleNamesForEvaluation; }
+
+ public int getNumberOfSamplesForEvaluation() {
+ if (sampleNamesForEvaluation!= null && !sampleNamesForEvaluation.isEmpty())
+ return sampleNamesForEvaluation.size();
+ else {
+ return numSamplesFromArgument;
+ }
+
+ }
+ public Set<String> getSampleNamesForStratification() { return sampleNamesForStratification; }
+
+ public List<RodBinding<VariantContext>> getComps() { return comps; }
+
+ public Set<SortableJexlVCMatchExp> getJexlExpressions() { return jexlExpressions; }
+
+ public long getnProcessedLoci() {
+ return nProcessedLoci;
+ }
+
+ public Set<String> getContigNames() {
+ final TreeSet<String> contigs = new TreeSet<String>();
+ for( final SAMSequenceRecord r : getToolkit().getReferenceDataSource().getReference().getSequenceDictionary().getSequences()) {
+ contigs.add(r.getSequenceName());
+ }
+ return contigs;
+ }
+
+ /**
+ * getToolkit is protected, so we have to pseudo-overload it here so eval / strats can get the toolkit
+ * @return
+ */
+ public GenomeAnalysisEngine getToolkit() {
+ return super.getToolkit();
+ }
+
+ public boolean ignoreAC0Sites() {
+ return ! keepSitesWithAC0;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/VariantEvalReportWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/VariantEvalReportWriter.java
new file mode 100644
index 0000000..7244a94
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/VariantEvalReportWriter.java
@@ -0,0 +1,203 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval;
+
+import org.broadinstitute.gatk.engine.report.GATKReport;
+import org.broadinstitute.gatk.engine.report.GATKReportTable;
+import org.broadinstitute.gatk.tools.walkers.varianteval.evaluators.VariantEvaluator;
+import org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.VariantStratifier;
+import org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.manager.StratificationManager;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.AnalysisModuleScanner;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.DataPoint;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.EvaluationContext;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+
+import java.io.PrintStream;
+import java.lang.reflect.Field;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class for writing the GATKReport for VariantEval
+ *
+ * Accepts a fulled evaluated (i.e., there's no more data coming) set of stratifications and evaluators
+ * and supports writing out the data in these evaluators to a GATKReport.
+ */
+public class VariantEvalReportWriter {
+
+ protected VariantEvalReportWriter() {} // no public access
+
+ /**
+ * The business end of the class. Writes out the data in the provided stratManager
+ * to the PrintStream out
+ *
+ * @param out the output stream
+ * @param stratManager the stratification manager
+ * @param stratifiers the stratifiers
+ * @param evaluators the evaluators
+ */
+ public static void writeReport(final PrintStream out,
+ final StratificationManager<VariantStratifier, EvaluationContext> stratManager,
+ final Collection<VariantStratifier> stratifiers,
+ final Collection<VariantEvaluator> evaluators) {
+
+ final GATKReport report = initializeGATKReport(stratifiers, evaluators);
+
+ for ( int key = 0; key < stratManager.size(); key++ ) {
+ final String stratStateString = stratManager.getStratsAndStatesStringForKey(key);
+ final List<Pair<VariantStratifier, Object>> stratsAndStates = stratManager.getStratsAndStatesForKey(key);
+ final EvaluationContext nec = stratManager.get(key);
+
+ for ( final VariantEvaluator ve : nec.getVariantEvaluators() ) {
+ final GATKReportTable table = report.getTable(ve.getSimpleName());
+
+ final AnalysisModuleScanner scanner = new AnalysisModuleScanner(ve);
+ final Map<Field, DataPoint> datamap = scanner.getData();
+ try {
+ if ( scanner.hasMoltenField() ) {
+ final Field field = scanner.getMoltenField();
+ final Object fieldValue = field.get(ve);
+
+ if ( fieldValue == null || ! (fieldValue instanceof Map) )
+ throw new ReviewedGATKException("BUG field " + field.getName() + " must be a non-null instance of Map in " + scanner.getAnalysis().name());
+ final Map<Object, Object> map = (Map<Object, Object>)fieldValue;
+ if ( map.isEmpty() )
+ throw new ReviewedGATKException("BUG: map is null or empty in analysis " + scanner.getAnalysis());
+
+ int counter = 0; // counter is used to ensure printing order is as defined by entrySet
+ for ( Map.Entry<Object, Object> keyValue : map.entrySet() ) {
+ // "%05d" is a terrible hack to ensure sort order
+ final String moltenStratStateString = stratStateString + String.format("%05d", counter++);
+ setStratificationColumns(table, moltenStratStateString, stratsAndStates);
+ table.set(moltenStratStateString, scanner.getMoltenAnnotation().variableName(), keyValue.getKey());
+ table.set(moltenStratStateString, scanner.getMoltenAnnotation().valueName(), keyValue.getValue());
+ }
+ } else {
+ setStratificationColumns(table, stratStateString, stratsAndStates);
+ for ( final Field field : datamap.keySet()) {
+ table.set(stratStateString, field.getName(), field.get(ve));
+ }
+ }
+ } catch (IllegalAccessException e) {
+ throw new ReviewedGATKException("BUG: analysis field not public: " + e);
+ }
+ }
+ }
+
+ report.print(out);
+ }
+
+ /**
+ * Common utility to configure a GATKReportTable columns
+ *
+ * Sets the column names to the strat names in stratsAndStates for the primary key in table
+ *
+ * @param table
+ * @param primaryKey
+ * @param stratsAndStates
+ */
+ private static void setStratificationColumns(final GATKReportTable table,
+ final String primaryKey,
+ final List<Pair<VariantStratifier, Object>> stratsAndStates) {
+ table.set(primaryKey, table.getTableName(), table.getTableName());
+ for ( final Pair<VariantStratifier, Object> stratAndState : stratsAndStates ) {
+ final VariantStratifier vs = stratAndState.getFirst();
+ final String columnName = vs.getName();
+ final Object strat = stratAndState.getSecond();
+ if ( columnName == null || strat == null )
+ throw new ReviewedGATKException("Unexpected null variant stratifier state at " + table + " key = " + primaryKey);
+ table.set(primaryKey, columnName, strat);
+ }
+ }
+
+ /**
+ * Initialize the output report
+ *
+ * We have a set of stratifiers and evaluation objects. We need to create tables that look like:
+ *
+ * strat1 strat2 ... stratN eval1.field1 eval1.field2 ... eval1.fieldM
+ *
+ * for each eval.
+ *
+ * Note that this procedure doesn't support the creation of the old TableType system. As the
+ * VariantEvaluators are effectively tables themselves, we require authors to just create new
+ * evaluation modules externally instead of allow them to embed them in other evaluation modules
+ *
+ * @return an initialized report object
+ */
+ private static GATKReport initializeGATKReport(final Collection<VariantStratifier> stratifiers,
+ final Collection<VariantEvaluator> evaluators) {
+ final GATKReport report = new GATKReport();
+
+ for (final VariantEvaluator ve : evaluators) {
+ final AnalysisModuleScanner scanner = new AnalysisModuleScanner(ve);
+ final Map<Field, DataPoint> datamap = scanner.getData();
+
+ // create the table
+ final String tableName = ve.getSimpleName();
+ final String tableDesc = ve.getClass().getAnnotation(Analysis.class).description();
+ report.addTable(tableName, tableDesc, 1 + stratifiers.size() + (scanner.hasMoltenField() ? 2 : datamap.size()), GATKReportTable.TableSortingWay.SORT_BY_ROW);
+
+ // grab the table, and add the columns we need to it
+ final GATKReportTable table = report.getTable(tableName);
+ table.addColumn(tableName, tableName);
+
+ // first create a column to hold each stratifier state
+ for (final VariantStratifier vs : stratifiers) {
+ final String columnName = vs.getName();
+ table.addColumn(columnName, vs.getFormat());
+ }
+
+ if ( scanner.hasMoltenField() ) {
+ // deal with molten data
+ table.addColumn(scanner.getMoltenAnnotation().variableName(), scanner.getMoltenAnnotation().variableFormat());
+ table.addColumn(scanner.getMoltenAnnotation().valueName(), scanner.getMoltenAnnotation().valueFormat());
+ } else {
+ if ( datamap.isEmpty() )
+ throw new ReviewedGATKException("Datamap is empty for analysis " + scanner.getAnalysis());
+
+ // add DataPoint's for each field marked as such
+ for (final Map.Entry<Field, DataPoint> field : datamap.entrySet()) {
+ try {
+ field.getKey().setAccessible(true);
+
+ // this is an atomic value, add a column for it
+ final String format = field.getValue().format();
+ table.addColumn(field.getKey().getName(), format);
+ } catch (SecurityException e) {
+ throw new GATKException("SecurityException: " + e);
+ }
+ }
+ }
+ }
+
+ return report;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/CompOverlap.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/CompOverlap.java
new file mode 100644
index 0000000..7ebf96e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/CompOverlap.java
@@ -0,0 +1,109 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.DataPoint;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+
+/**
+ * The Broad Institute
+ * SOFTWARE COPYRIGHT NOTICE AGREEMENT
+ * This software and its documentation are copyright 2009 by the
+ * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
+ * <p/>
+ * This software is supplied without any warranty or guaranteed support whatsoever. Neither
+ * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
+ */
+ at Analysis(description = "The overlap between eval and comp sites")
+public class CompOverlap extends VariantEvaluator implements StandardEval {
+ @DataPoint(description = "number of eval variant sites", format = "%d")
+ public long nEvalVariants = 0;
+
+ @DataPoint(description = "number of eval sites outside of comp sites", format = "%d")
+ public long novelSites = 0;
+
+ @DataPoint(description = "number of eval sites at comp sites", format = "%d")
+ public long nVariantsAtComp = 0;
+
+ @DataPoint(description = "percentage of eval sites at comp sites", format = "%.2f" )
+ public double compRate = 0.0;
+
+ @DataPoint(description = "number of concordant sites", format = "%d")
+ public long nConcordant = 0;
+
+ @DataPoint(description = "the concordance rate", format = "%.2f")
+ public double concordantRate = 0.0;
+
+ public int getComparisonOrder() {
+ return 2; // we need to see each eval track and each comp track
+ }
+
+ public long nNovelSites() { return nEvalVariants - nVariantsAtComp; }
+ public double compRate() { return rate(nVariantsAtComp, nEvalVariants); }
+ public double concordanceRate() { return rate(nConcordant, nVariantsAtComp); }
+
+ public void finalizeEvaluation() {
+ compRate = 100 * compRate();
+ concordantRate = 100 * concordanceRate();
+ novelSites = nNovelSites();
+ }
+
+ /**
+ * Returns true if every allele in eval is also in comp
+ *
+ * @param eval eval context
+ * @param comp db context
+ * @return true if eval and db are discordant
+ */
+ public boolean discordantP(VariantContext eval, VariantContext comp) {
+ for (Allele a : eval.getAlleles()) {
+ if (!comp.hasAllele(a, true))
+ return true;
+ }
+
+ return false;
+ }
+
+ public void update2(VariantContext eval, VariantContext comp, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ boolean evalIsGood = eval != null && eval.isPolymorphicInSamples();
+ boolean compIsGood = comp != null && comp.isNotFiltered();
+
+ if (evalIsGood) nEvalVariants++; // count the number of eval events
+
+ if (compIsGood && evalIsGood) {
+ nVariantsAtComp++;
+
+ if (!discordantP(eval, comp)) { // count whether we're concordant or not with the comp value
+ nConcordant++;
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/CountVariants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/CountVariants.java
new file mode 100644
index 0000000..89b37f0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/CountVariants.java
@@ -0,0 +1,219 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.DataPoint;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.VariantContext;
+
+ at Analysis(description = "Counts different classes of variants in the sample")
+public class CountVariants extends VariantEvaluator implements StandardEval {
+ // the following fields are in output order:
+
+ // basic counts on various rates found
+ @DataPoint(description = "Number of processed loci", format = "%d")
+ public long nProcessedLoci = 0;
+ @DataPoint(description = "Number of called loci", format = "%d")
+ public long nCalledLoci = 0;
+ @DataPoint(description = "Number of reference loci", format = "%d")
+ public long nRefLoci = 0;
+ @DataPoint(description = "Number of variant loci", format = "%d")
+ public long nVariantLoci = 0;
+
+ // the following two calculations get set in the finalizeEvaluation
+ @DataPoint(description = "Variants per loci rate", format = "%.8f")
+ public double variantRate = 0;
+ @DataPoint(description = "Number of variants per base", format = "%.8f")
+ public double variantRatePerBp = 0;
+
+ @DataPoint(description = "Number of snp loci", format = "%d")
+ public long nSNPs = 0;
+ @DataPoint(description = "Number of mnp loci", format = "%d")
+ public long nMNPs = 0;
+ @DataPoint(description = "Number of insertions", format = "%d")
+ public long nInsertions = 0;
+ @DataPoint(description = "Number of deletions", format = "%d")
+ public long nDeletions = 0;
+ @DataPoint(description = "Number of complex indels", format = "%d")
+ public long nComplex = 0;
+ @DataPoint(description = "Number of symbolic events", format = "%d")
+ public long nSymbolic = 0;
+
+ @DataPoint(description = "Number of mixed loci (loci that can't be classified as a SNP, Indel or MNP)", format = "%d")
+ public long nMixed = 0;
+
+ @DataPoint(description = "Number of no calls loci", format = "%d")
+ public long nNoCalls = 0;
+ @DataPoint(description = "Number of het loci", format = "%d")
+ public long nHets = 0;
+ @DataPoint(description = "Number of hom ref loci", format = "%d")
+ public long nHomRef = 0;
+ @DataPoint(description = "Number of hom var loci", format = "%d")
+ public long nHomVar = 0;
+ @DataPoint(description = "Number of singletons", format = "%d")
+ public long nSingletons = 0;
+ @DataPoint(description = "Number of derived homozygotes", format = "%d")
+ public long nHomDerived = 0;
+
+ // calculations that get set in the finalizeEvaluation method
+ @DataPoint(description = "heterozygosity per locus rate", format = "%.2e")
+ public double heterozygosity = 0;
+ @DataPoint(description = "heterozygosity per base pair", format = "%.2f")
+ public double heterozygosityPerBp = 0;
+ @DataPoint(description = "heterozygosity to homozygosity ratio", format = "%.2f")
+ public double hetHomRatio = 0;
+ @DataPoint(description = "indel rate (insertion count + deletion count)", format = "%.2e")
+ public double indelRate = 0;
+ @DataPoint(description = "indel rate per base pair", format = "%.2f")
+ public double indelRatePerBp = 0;
+ @DataPoint(description = "insertion to deletion ratio", format = "%.2f")
+ public double insertionDeletionRatio = 0;
+
+ private double perLocusRate(long n) {
+ return rate(n, nProcessedLoci);
+ }
+
+ private long perLocusRInverseRate(long n) {
+ return inverseRate(n, nProcessedLoci);
+ }
+
+
+ public int getComparisonOrder() {
+ return 1; // we only need to see each eval track
+ }
+
+ public void update1(VariantContext vc1, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ nCalledLoci++;
+
+ // Note from Eric:
+ // This is really not correct. What we really want here is a polymorphic vs. monomorphic count (i.e. on the Genotypes).
+ // So in order to maintain consistency with the previous implementation (and the intention of the original author), I've
+ // added in a proxy check for monomorphic status here.
+ // Protect against case when vc only as no-calls too - can happen if we strafity by sample and sample as a single no-call.
+ if ( getWalker().ignoreAC0Sites() && vc1.isMonomorphicInSamples() ) {
+ nRefLoci++;
+ } else {
+ switch (vc1.getType()) {
+ case NO_VARIATION:
+ // shouldn't get here
+ break;
+ case SNP:
+ nVariantLoci++;
+ nSNPs++;
+ if (variantWasSingleton(vc1)) nSingletons++;
+ break;
+ case MNP:
+ nVariantLoci++;
+ nMNPs++;
+ if (variantWasSingleton(vc1)) nSingletons++;
+ break;
+ case INDEL:
+ nVariantLoci++;
+ if (vc1.isSimpleInsertion())
+ nInsertions++;
+ else if (vc1.isSimpleDeletion())
+ nDeletions++;
+ else
+ nComplex++;
+ break;
+ case MIXED:
+ nVariantLoci++;
+ nMixed++;
+ break;
+ case SYMBOLIC:
+ nSymbolic++;
+ break;
+ default:
+ throw new ReviewedGATKException("Unexpected VariantContext type " + vc1.getType());
+ }
+ }
+
+ // these operations are ordered to ensure that we don't get the base string of the ref unless we need it
+ final String aaStr = vc1.hasAttribute("ANCESTRALALLELE") ? vc1.getAttributeAsString("ANCESTRALALLELE", null).toUpperCase() : null;
+ final String refStr = aaStr != null ? vc1.getReference().getBaseString().toUpperCase() : null;
+
+ // ref aa alt class
+ // A C A der homozygote
+ // A C C anc homozygote
+
+ // A A A ref homozygote
+ // A A C
+ // A C A
+ // A C C
+
+ for (final Genotype g : vc1.getGenotypes()) {
+ final String altStr = vc1.getAlternateAlleles().size() > 0 ? vc1.getAlternateAllele(0).getBaseString().toUpperCase() : null;
+
+ switch (g.getType()) {
+ case NO_CALL:
+ nNoCalls++;
+ break;
+ case HOM_REF:
+ nHomRef++;
+
+ if ( aaStr != null && altStr != null && !refStr.equalsIgnoreCase(aaStr) ) {
+ nHomDerived++;
+ }
+
+ break;
+ case HET:
+ nHets++;
+ break;
+ case HOM_VAR:
+ nHomVar++;
+
+ if ( aaStr != null && altStr != null && !altStr.equalsIgnoreCase(aaStr) ) {
+ nHomDerived++;
+ }
+
+ break;
+ case MIXED:
+ break;
+ case UNAVAILABLE:
+ break;
+ default:
+ throw new ReviewedGATKException("BUG: Unexpected genotype type: " + g);
+ }
+ }
+ }
+
+ public void finalizeEvaluation() {
+ nProcessedLoci = getWalker().getnProcessedLoci();
+ variantRate = perLocusRate(nVariantLoci);
+ variantRatePerBp = perLocusRInverseRate(nVariantLoci);
+ heterozygosity = perLocusRate(nHets);
+ heterozygosityPerBp = perLocusRInverseRate(nHets);
+ hetHomRatio = ratio(nHets, nHomVar);
+ indelRate = perLocusRate(nDeletions + nInsertions + nComplex);
+ indelRatePerBp = perLocusRInverseRate(nDeletions + nInsertions + nComplex);
+ insertionDeletionRatio = ratio(nInsertions, nDeletions);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/IndelLengthHistogram.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/IndelLengthHistogram.java
new file mode 100644
index 0000000..8e202a7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/IndelLengthHistogram.java
@@ -0,0 +1,123 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Molten;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.*;
+
+/**
+ * Simple utility for histogramming indel lengths
+ *
+ * Based on code from chartl
+ *
+ * @author Mark DePristo
+ * @since 3/21/12
+ */
+ at Analysis(description = "Indel length histogram", molten = true)
+public class IndelLengthHistogram extends VariantEvaluator implements StandardEval {
+ private final Map<Integer, Integer> counts = new HashMap<Integer, Integer>();
+ private final static boolean asFrequencies = true;
+ int nIndels = 0;
+
+ @Molten(variableName = "Length", valueName = "Freq", variableFormat = "%d", valueFormat = "%.2f")
+ public TreeMap<Object, Object> results;
+
+ public final static int MAX_SIZE_FOR_HISTOGRAM = 10;
+ private final static boolean INCLUDE_LONG_EVENTS_AT_MAX_SIZE = false;
+
+ public IndelLengthHistogram() {
+ initializeCounts(MAX_SIZE_FOR_HISTOGRAM);
+ }
+
+ private void initializeCounts(int size) {
+ for ( int i = -size; i <= size; i++ ) {
+ if ( i != 0 ) counts.put(i, 0);
+ }
+ }
+
+ @Override
+ public void finalizeEvaluation() {
+ if ( asFrequencies ) {
+ results = new TreeMap<Object, Object>();
+ for ( final int len : counts.keySet() ) {
+ final double value = nIndels == 0 ? 0.0 : counts.get(len) / (1.0 * nIndels);
+ results.put(len, value);
+ }
+ } else {
+ results = new TreeMap<Object, Object>(results);
+ }
+ }
+
+ @Override
+ public int getComparisonOrder() {
+ return 1;
+ }
+
+ @Override
+ public void update1(final VariantContext eval, final RefMetaDataTracker tracker, final ReferenceContext ref, final AlignmentContext context) {
+ if ( eval.isIndel() && ! eval.isComplexIndel() ) {
+ if ( ! ( getWalker().ignoreAC0Sites() && eval.isMonomorphicInSamples() )) {
+ // only if we are actually polymorphic in the subsetted samples should we count the allele
+ for ( Allele alt : eval.getAlternateAlleles() ) {
+ final int alleleSize = alt.length() - eval.getReference().length();
+ if ( alleleSize == 0 ) throw new ReviewedGATKException("Allele size not expected to be zero for indel: alt = " + alt + " ref = " + eval.getReference());
+ updateLengthHistogram(eval.getReference(), alt);
+ }
+ }
+ }
+ }
+
+ /**
+ * Update the histogram with the implied length of the indel allele between ref and alt (alt.len - ref.len).
+ *
+ * If this size is outside of MAX_SIZE_FOR_HISTOGRAM, the size is capped to MAX_SIZE_FOR_HISTOGRAM,
+ * if INCLUDE_LONG_EVENTS_AT_MAX_SIZE is set.
+ *
+ * @param ref
+ * @param alt
+ */
+ public void updateLengthHistogram(final Allele ref, final Allele alt) {
+ int len = alt.length() - ref.length();
+ if ( INCLUDE_LONG_EVENTS_AT_MAX_SIZE ) {
+ if ( len > MAX_SIZE_FOR_HISTOGRAM ) len = MAX_SIZE_FOR_HISTOGRAM;
+ if ( len < -MAX_SIZE_FOR_HISTOGRAM ) len = -MAX_SIZE_FOR_HISTOGRAM;
+ }
+
+ if ( Math.abs(len) > MAX_SIZE_FOR_HISTOGRAM )
+ return;
+
+ nIndels++;
+ counts.put(len, counts.get(len) + 1);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/IndelSummary.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/IndelSummary.java
new file mode 100644
index 0000000..484541e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/IndelSummary.java
@@ -0,0 +1,259 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.DataPoint;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.VariantContext;
+
+ at Analysis(description = "Evaluation summary for indels")
+public class IndelSummary extends VariantEvaluator implements StandardEval {
+ final protected static Logger logger = Logger.getLogger(IndelSummary.class);
+
+ //
+ // counts of snps and indels
+ //
+ @DataPoint(description = "Number of SNPs", format = "%d")
+ public int n_SNPs = 0;
+
+ @DataPoint(description = "Number of singleton SNPs", format = "%d")
+ public int n_singleton_SNPs = 0;
+
+ @DataPoint(description = "Number of indels", format = "%d")
+ public int n_indels = 0;
+
+ @DataPoint(description = "Number of singleton indels", format = "%d")
+ public int n_singleton_indels = 0;
+
+ //
+ // gold standard
+ //
+ @DataPoint(description = "Number of Indels overlapping gold standard sites", format = "%d")
+ public int n_indels_matching_gold_standard = 0;
+
+ @DataPoint(description = "Percent of indels overlapping gold standard sites")
+ public String gold_standard_matching_rate;
+
+ //
+ // multi-allelics
+ //
+ // Number of Indels Sites (counts one for any number of alleles at site)
+ public int nIndelSites = 0;
+
+ @DataPoint(description = "Number of sites with where the number of alleles is greater than 2")
+ public int n_multiallelic_indel_sites = 0;
+
+ @DataPoint(description = "Percent of indel sites that are multi-allelic")
+ public String percent_of_sites_with_more_than_2_alleles;
+
+ //
+ // snp : indel ratios
+ //
+ @DataPoint(description = "SNP to indel ratio")
+ public String SNP_to_indel_ratio;
+
+ @DataPoint(description = "Singleton SNP to indel ratio")
+ public String SNP_to_indel_ratio_for_singletons;
+
+ //
+ // novelty
+ //
+ @DataPoint(description = "Number of novel indels", format = "%d")
+ public int n_novel_indels = 0;
+
+ @DataPoint(description = "Indel novelty rate")
+ public String indel_novelty_rate;
+
+ //
+ // insertions to deletions
+ //
+ @DataPoint(description = "Number of insertion indels")
+ public int n_insertions = 0;
+
+ @DataPoint(description = "Number of deletion indels")
+ public int n_deletions = 0;
+
+ @DataPoint(description = "Insertion to deletion ratio")
+ public String insertion_to_deletion_ratio;
+
+ @DataPoint(description = "Number of large (>10 bp) deletions")
+ public int n_large_deletions = 0;
+
+ @DataPoint(description = "Number of large (>10 bp) insertions")
+ public int n_large_insertions = 0;
+
+ @DataPoint(description = "Ratio of large (>10 bp) insertions to deletions")
+ public String insertion_to_deletion_ratio_for_large_indels;
+
+ //
+ // Frameshifts
+ //
+ @DataPoint(description = "Number of indels in protein-coding regions labeled as frameshift")
+ public int n_coding_indels_frameshifting = 0;
+
+ @DataPoint(description = "Number of indels in protein-coding regions not labeled as frameshift")
+ public int n_coding_indels_in_frame = 0;
+
+ @DataPoint(description = "Frameshift percent")
+ public String frameshift_rate_for_coding_indels;
+
+ //
+ // Het : hom ratios
+ //
+ @DataPoint(description = "Het to hom ratio for SNPs")
+ public String SNP_het_to_hom_ratio;
+
+ @DataPoint(description = "Het to hom ratio for indels")
+ public String indel_het_to_hom_ratio;
+
+ int nSNPHets = 0, nSNPHoms = 0, nIndelHets = 0, nIndelHoms = 0;
+
+ int[] insertionCountByLength = new int[]{0, 0, 0, 0}; // note that the first element isn't used
+ int[] deletionCountByLength = new int[]{0, 0, 0, 0}; // note that the first element isn't used
+
+ // - Since 1 & 2 bp insertions and 1 & 2 bp deletions are equally likely to cause a
+ // downstream frameshift, if we make the simplifying assumptions that 3 bp ins
+ // and 3bp del (adding/subtracting 1 AA in general) are roughly comparably
+ // selected against, we should see a consistent 1+2 : 3 bp ratio for insertions
+ // as for deletions, and certainly would expect consistency between in/dels that
+ // multiple methods find and in/dels that are unique to one method (since deletions
+ // are more common and the artifacts differ, it is probably worth looking at the totals,
+ // overlaps and ratios for insertions and deletions separately in the methods
+ // comparison and in this case don't even need to make the simplifying in = del functional assumption
+
+ @DataPoint(description = "ratio of 1 and 2 bp insertions to 3 bp insertions")
+ public String ratio_of_1_and_2_to_3_bp_insertions;
+
+ @DataPoint(description = "ratio of 1 and 2 bp deletions to 3 bp deletions")
+ public String ratio_of_1_and_2_to_3_bp_deletions;
+
+ public final static int LARGE_INDEL_SIZE_THRESHOLD = 10;
+
+ @Override public int getComparisonOrder() { return 2; }
+
+ public void update2(VariantContext eval, VariantContext comp, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( eval == null || (getWalker().ignoreAC0Sites() && eval.isMonomorphicInSamples()) )
+ return;
+
+ // update counts
+ switch ( eval.getType() ) {
+ case SNP:
+ n_SNPs += eval.getNAlleles() - 1; // -1 for ref
+ if ( variantWasSingleton(eval) ) n_singleton_SNPs++;
+
+ // collect information about het / hom ratio
+ for ( final Genotype g : eval.getGenotypes() ) {
+ if ( g.isHet() ) nSNPHets++;
+ if ( g.isHomVar() ) nSNPHoms++;
+ }
+ break;
+ case INDEL:
+ final VariantContext gold = getWalker().goldStandard == null ? null : tracker.getFirstValue(getWalker().goldStandard);
+
+ nIndelSites++;
+ if ( ! eval.isBiallelic() ) n_multiallelic_indel_sites++;
+
+ // collect information about het / hom ratio
+ for ( final Genotype g : eval.getGenotypes() ) {
+ if ( g.isHet() ) nIndelHets++;
+ if ( g.isHomVar() ) nIndelHoms++;
+ }
+
+ for ( Allele alt : eval.getAlternateAlleles() ) {
+ n_indels++; // +1 for each alt allele
+ if ( variantWasSingleton(eval) ) n_singleton_indels++;
+ if ( comp == null ) n_novel_indels++; // TODO -- make this test allele specific?
+ if ( gold != null ) n_indels_matching_gold_standard++;
+
+ // ins : del ratios
+ final int alleleSize = alt.length() - eval.getReference().length();
+ if ( alleleSize == 0 ) throw new ReviewedGATKException("Allele size not expected to be zero for indel: alt = " + alt + " ref = " + eval.getReference());
+ if ( alleleSize > 0 ) n_insertions++;
+ if ( alleleSize < 0 ) n_deletions++;
+
+ // requires snpEFF annotations
+ if ( eval.getAttributeAsString("SNPEFF_GENE_BIOTYPE", "missing").equals("protein_coding") ) {
+ final String effect = eval.getAttributeAsString("SNPEFF_EFFECT", "missing");
+ if ( effect.equals("missing") )
+ throw new ReviewedGATKException("Saw SNPEFF_GENE_BIOTYPE but unexpected no SNPEFF_EFFECT at " + eval);
+ if ( effect.equals("FRAME_SHIFT") )
+ n_coding_indels_frameshifting++;
+ else if ( effect.startsWith("CODON") )
+ n_coding_indels_in_frame++;
+ else
+ ; // lots of protein coding effects that shouldn't be counted, such as INTRON
+ }
+
+ if ( alleleSize > LARGE_INDEL_SIZE_THRESHOLD )
+ n_large_insertions++;
+ else if ( alleleSize < -LARGE_INDEL_SIZE_THRESHOLD )
+ n_large_deletions++;
+
+ // update the baby histogram
+ final int[] countByLength = alleleSize < 0 ? deletionCountByLength : insertionCountByLength;
+ final int absSize = Math.abs(alleleSize);
+ if ( absSize < countByLength.length ) countByLength[absSize]++;
+
+ }
+
+ break;
+ default:
+ // TODO - MIXED, SYMBOLIC, and MNP records are skipped over
+ //throw new UserException.BadInput("Unexpected variant context type: " + eval);
+ break;
+ }
+
+ return;
+ }
+
+ public void finalizeEvaluation() {
+ percent_of_sites_with_more_than_2_alleles = Utils.formattedPercent(n_multiallelic_indel_sites, nIndelSites);
+ SNP_to_indel_ratio = Utils.formattedRatio(n_SNPs, n_indels);
+ SNP_to_indel_ratio_for_singletons = Utils.formattedRatio(n_singleton_SNPs, n_singleton_indels);
+
+ gold_standard_matching_rate = Utils.formattedPercent(n_indels_matching_gold_standard, n_indels);
+ indel_novelty_rate = Utils.formattedNoveltyRate(n_indels - n_novel_indels, n_indels);
+ frameshift_rate_for_coding_indels = Utils.formattedPercent(n_coding_indels_frameshifting, n_coding_indels_in_frame + n_coding_indels_frameshifting);
+
+ ratio_of_1_and_2_to_3_bp_deletions = Utils.formattedRatio(deletionCountByLength[1] + deletionCountByLength[2], deletionCountByLength[3]);
+ ratio_of_1_and_2_to_3_bp_insertions = Utils.formattedRatio(insertionCountByLength[1] + insertionCountByLength[2], insertionCountByLength[3]);
+
+ SNP_het_to_hom_ratio = Utils.formattedRatio(nSNPHets, nSNPHoms);
+ indel_het_to_hom_ratio = Utils.formattedRatio(nIndelHets, nIndelHoms);
+
+ insertion_to_deletion_ratio = Utils.formattedRatio(n_insertions, n_deletions);
+ insertion_to_deletion_ratio_for_large_indels = Utils.formattedRatio(n_large_insertions, n_large_deletions);
+
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/MendelianViolationEvaluator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/MendelianViolationEvaluator.java
new file mode 100644
index 0000000..c01aae1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/MendelianViolationEvaluator.java
@@ -0,0 +1,187 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.samples.Sample;
+import org.broadinstitute.gatk.tools.walkers.varianteval.VariantEval;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.DataPoint;
+import org.broadinstitute.gatk.utils.MendelianViolation;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Mendelian violation detection and counting
+ * <p/>
+ * a violation looks like:
+ * Suppose dad = A/B and mom = C/D
+ * The child can be [A or B] / [C or D].
+ * If the child doesn't match this, the site is a violation
+ * <p/>
+ * Some examples:
+ * <p/>
+ * mom = A/A, dad = C/C
+ * child can be A/C only
+ * <p/>
+ * mom = A/C, dad = C/C
+ * child can be A/C or C/C
+ * <p/>
+ * mom = A/C, dad = A/C
+ * child can be A/A, A/C, C/C
+ * <p/>
+ * The easiest way to do this calculation is to:
+ * <p/>
+ * Get alleles for mom => A/B
+ * Get alleles for dad => C/D
+ * Make allowed genotypes for child: A/C, A/D, B/C, B/D
+ * Check that the child is one of these.
+ */
+ at Analysis(name = "Mendelian Violation Evaluator", description = "Mendelian Violation Evaluator")
+public class MendelianViolationEvaluator extends VariantEvaluator {
+
+ @DataPoint(description = "Number of variants found with at least one family having genotypes", format = "%d")
+ public long nVariants;
+ @DataPoint(description = "Number of variants found with no family having genotypes -- these sites do not count in the nNoCall", format = "%d")
+ public long nSkipped;
+ @DataPoint(description="Number of variants x families called (no missing genotype or lowqual)", format = "%d")
+ public long nFamCalled;
+ @DataPoint(description="Number of variants x families called (no missing genotype or lowqual) that contain at least one var allele.", format = "%d")
+ public long nVarFamCalled;
+ @DataPoint(description="Number of variants x families discarded as low quality", format = "%d")
+ public long nLowQual;
+ @DataPoint(description="Number of variants x families discarded as no call", format = "%d")
+ public long nNoCall;
+ @DataPoint(description="Number of loci with mendelian violations", format = "%d")
+ public long nLociViolations;
+ @DataPoint(description = "Number of mendelian violations found", format = "%d")
+ public long nViolations;
+
+ @DataPoint(description="Number of mendelian violations of the type HOM_REF/HOM_REF -> HOM_VAR", format = "%d")
+ public long mvRefRef_Var;
+ @DataPoint(description="Number of mendelian violations of the type HOM_REF/HOM_REF -> HET", format = "%d")
+ public long mvRefRef_Het;
+ @DataPoint(description="Number of mendelian violations of the type HOM_REF/HET -> HOM_VAR", format = "%d")
+ public long mvRefHet_Var;
+ @DataPoint(description="Number of mendelian violations of the type HOM_REF/HOM_VAR -> HOM_VAR", format = "%d")
+ public long mvRefVar_Var;
+ @DataPoint(description="Number of mendelian violations of the type HOM_REF/HOM_VAR -> HOM_REF", format = "%d")
+ public long mvRefVar_Ref;
+ @DataPoint(description="Number of mendelian violations of the type HOM_VAR/HET -> HOM_REF", format = "%d")
+ public long mvVarHet_Ref;
+ @DataPoint(description="Number of mendelian violations of the type HOM_VAR/HOM_VAR -> HOM_REF", format = "%d")
+ public long mvVarVar_Ref;
+ @DataPoint(description="Number of mendelian violations of the type HOM_VAR/HOM_VAR -> HET", format = "%d")
+ public long mvVarVar_Het;
+
+ @DataPoint(description="Number of HomRef/HomRef/HomRef trios", format = "%d")
+ public long HomRefHomRef_HomRef;
+ @DataPoint(description="Number of Het/Het/Het trios", format = "%d")
+ public long HetHet_Het;
+ @DataPoint(description="Number of Het/Het/HomRef trios", format = "%d")
+ public long HetHet_HomRef;
+ @DataPoint(description="Number of Het/Het/HomVar trios", format = "%d")
+ public long HetHet_HomVar;
+ @DataPoint(description="Number of HomVar/HomVar/HomVar trios", format = "%d")
+ public long HomVarHomVar_HomVar;
+ @DataPoint(description="Number of HomRef/HomVar/Het trios", format = "%d")
+ public long HomRefHomVAR_Het;
+ @DataPoint(description="Number of ref alleles inherited from het/het parents", format = "%d")
+ public long HetHet_inheritedRef;
+ @DataPoint(description="Number of var alleles inherited from het/het parents", format = "%d")
+ public long HetHet_inheritedVar;
+ @DataPoint(description="Number of ref alleles inherited from homRef/het parents", format = "%d")
+ public long HomRefHet_inheritedRef;
+ @DataPoint(description="Number of var alleles inherited from homRef/het parents", format = "%d")
+ public long HomRefHet_inheritedVar;
+ @DataPoint(description="Number of ref alleles inherited from homVar/het parents", format = "%d")
+ public long HomVarHet_inheritedRef;
+ @DataPoint(description="Number of var alleles inherited from homVar/het parents", format = "%d")
+ public long HomVarHet_inheritedVar;
+
+ MendelianViolation mv;
+ Map<String,Set<Sample>> families;
+
+ public void initialize(VariantEval walker) {
+ super.initialize(walker);
+ mv = new MendelianViolation(walker.getMendelianViolationQualThreshold(),false);
+ families = walker.getSampleDB().getFamilies();
+ }
+
+ public String getName() {
+ return "mendelian_violations";
+ }
+
+ public int getComparisonOrder() {
+ return 1; // we only need to see each eval track
+ }
+
+ public void update1(VariantContext vc, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if (vc.isBiallelic() && vc.hasGenotypes()) { // todo -- currently limited to biallelic loci
+
+ if(mv.countViolations(families,vc)>0){
+ nLociViolations++;
+ nViolations += mv.getViolationsCount();
+ mvRefRef_Var += mv.getParentsRefRefChildVar();
+ mvRefRef_Het += mv.getParentsRefRefChildHet();
+ mvRefHet_Var += mv.getParentsRefHetChildVar();
+ mvRefVar_Var += mv.getParentsRefVarChildVar();
+ mvRefVar_Ref += mv.getParentsRefVarChildRef();
+ mvVarHet_Ref += mv.getParentsVarHetChildRef();
+ mvVarVar_Ref += mv.getParentsVarVarChildRef();
+ mvVarVar_Het += mv.getParentsVarVarChildHet();
+
+ }
+ HomRefHomRef_HomRef += mv.getRefRefRef();
+ HetHet_Het += mv.getHetHetHet();
+ HetHet_HomRef += mv.getHetHetHomRef();
+ HetHet_HomVar += mv.getHetHetHomVar();
+ HomVarHomVar_HomVar += mv.getVarVarVar();
+ HomRefHomVAR_Het += mv.getRefVarHet();
+ HetHet_inheritedRef += mv.getParentsHetHetInheritedRef();
+ HetHet_inheritedVar += mv.getParentsHetHetInheritedVar();
+ HomRefHet_inheritedRef += mv.getParentsRefHetInheritedRef();
+ HomRefHet_inheritedVar += mv.getParentsRefHetInheritedVar();
+ HomVarHet_inheritedRef += mv.getParentsVarHetInheritedRef();
+ HomVarHet_inheritedVar += mv.getParentsVarHetInheritedVar();
+
+ if(mv.getFamilyCalledCount()>0){
+ nVariants++;
+ nFamCalled += mv.getFamilyCalledCount();
+ nLowQual += mv.getFamilyLowQualsCount();
+ nNoCall += mv.getFamilyNoCallCount();
+ nVarFamCalled += mv.getVarFamilyCalledCount();
+ }
+ else{
+ nSkipped++;
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/MultiallelicSummary.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/MultiallelicSummary.java
new file mode 100644
index 0000000..88543b5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/MultiallelicSummary.java
@@ -0,0 +1,164 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.DataPoint;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+
+ at Analysis(description = "Evaluation summary for multi-allelic variants")
+public class MultiallelicSummary extends VariantEvaluator implements StandardEval {
+ final protected static Logger logger = Logger.getLogger(MultiallelicSummary.class);
+
+ public enum Type {
+ SNP, INDEL
+ }
+
+ // basic counts on various rates found
+ @DataPoint(description = "Number of processed loci", format = "%d")
+ public long nProcessedLoci = 0;
+
+ @DataPoint(description = "Number of SNPs", format = "%d")
+ public int nSNPs = 0;
+ @DataPoint(description = "Number of multi-allelic SNPs", format = "%d")
+ public int nMultiSNPs = 0;
+ @DataPoint(description = "% processed sites that are multi-allelic SNPs", format = "%.5f")
+ public double processedMultiSnpRatio = 0;
+ @DataPoint(description = "% SNP sites that are multi-allelic", format = "%.3f")
+ public double variantMultiSnpRatio = 0;
+
+ @DataPoint(description = "Number of Indels", format = "%d")
+ public int nIndels = 0;
+ @DataPoint(description = "Number of multi-allelic Indels", format = "%d")
+ public int nMultiIndels = 0;
+ @DataPoint(description = "% processed sites that are multi-allelic Indels", format = "%.5f")
+ public double processedMultiIndelRatio = 0;
+ @DataPoint(description = "% Indel sites that are multi-allelic", format = "%.3f")
+ public double variantMultiIndelRatio = 0;
+
+ @DataPoint(description = "Number of Transitions", format = "%d")
+ public int nTi = 0;
+ @DataPoint(description = "Number of Transversions", format = "%d")
+ public int nTv = 0;
+ @DataPoint(description = "Overall TiTv ratio", format = "%.2f")
+ public double TiTvRatio = 0;
+
+ @DataPoint(description = "Multi-allelic SNPs partially known", format = "%d")
+ public int knownSNPsPartial = 0;
+ @DataPoint(description = "Multi-allelic SNPs completely known", format = "%d")
+ public int knownSNPsComplete = 0;
+ @DataPoint(description = "Multi-allelic SNP Novelty Rate")
+ public String SNPNoveltyRate = "NA";
+
+ //TODO -- implement me
+ //@DataPoint(description = "Multi-allelic Indels partially known", format = "%d")
+ public int knownIndelsPartial = 0;
+ //@DataPoint(description = "Multi-allelic Indels completely known", format = "%d")
+ public int knownIndelsComplete = 0;
+ //@DataPoint(description = "Multi-allelic Indel Novelty Rate")
+ public String indelNoveltyRate = "NA";
+
+
+ @Override public int getComparisonOrder() { return 2; }
+
+ public void update2(VariantContext eval, VariantContext comp, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( eval == null || (getWalker().ignoreAC0Sites() && eval.isMonomorphicInSamples()) )
+ return;
+
+ // update counts
+ switch ( eval.getType() ) {
+ case SNP:
+ nSNPs++;
+ if ( !eval.isBiallelic() ) {
+ nMultiSNPs++;
+ calculatePairwiseTiTv(eval);
+ calculateSNPPairwiseNovelty(eval, comp);
+ }
+ break;
+ case INDEL:
+ nIndels++;
+ if ( !eval.isBiallelic() ) {
+ nMultiIndels++;
+ calculateIndelPairwiseNovelty(eval, comp);
+ }
+ break;
+ default:
+ //throw new UserException.BadInput("Unexpected variant context type: " + eval);
+ break;
+ }
+
+ return;
+ }
+
+ private void calculatePairwiseTiTv(VariantContext vc) {
+ for ( Allele alt : vc.getAlternateAlleles() ) {
+ if ( GATKVariantContextUtils.isTransition(vc.getReference(), alt) )
+ nTi++;
+ else
+ nTv++;
+ }
+ }
+
+ private void calculateSNPPairwiseNovelty(VariantContext eval, VariantContext comp) {
+ if ( comp == null )
+ return;
+
+ int knownAlleles = 0;
+ for ( Allele alt : eval.getAlternateAlleles() ) {
+ if ( comp.getAlternateAlleles().contains(alt) )
+ knownAlleles++;
+ }
+
+ if ( knownAlleles == eval.getAlternateAlleles().size() )
+ knownSNPsComplete++;
+ else if ( knownAlleles > 0 )
+ knownSNPsPartial++;
+ }
+
+ private void calculateIndelPairwiseNovelty(VariantContext eval, VariantContext comp) {
+ // TODO -- implement me
+ }
+
+ public void finalizeEvaluation() {
+ nProcessedLoci = getWalker().getnProcessedLoci();
+ processedMultiSnpRatio = (double)nMultiSNPs / (double)nProcessedLoci;
+ variantMultiSnpRatio = (double)nMultiSNPs / (double)nSNPs;
+ processedMultiIndelRatio = (double)nMultiIndels / (double)nProcessedLoci;
+ variantMultiIndelRatio = (double)nMultiIndels / (double)nIndels;
+
+ TiTvRatio = (double)nTi / (double)nTv;
+
+ SNPNoveltyRate = Utils.formattedNoveltyRate(knownSNPsPartial + knownSNPsComplete, nMultiSNPs);
+ indelNoveltyRate = Utils.formattedNoveltyRate(knownIndelsPartial + knownIndelsComplete, nMultiSNPs);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/PrintMissingComp.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/PrintMissingComp.java
new file mode 100644
index 0000000..0d3d4cf
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/PrintMissingComp.java
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.DataPoint;
+import htsjdk.variant.variantcontext.VariantContext;
+
+ at Analysis(name = "PrintMissingComp", description = "the overlap between eval and comp sites")
+public class PrintMissingComp extends VariantEvaluator {
+ @DataPoint(description = "number of eval sites outside of comp sites", format = "%d")
+ public long nMissing = 0;
+
+ public String getName() {
+ return "PrintMissingComp";
+ }
+
+ public int getComparisonOrder() {
+ return 2; // we need to see each eval track and each comp track
+ }
+
+ public void update2(VariantContext eval, VariantContext comp, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ final boolean compIsGood = comp != null && comp.isNotFiltered() && comp.isSNP();
+ final boolean evalIsGood = eval != null && eval.isSNP();
+
+ if ( compIsGood & ! evalIsGood ) {
+ nMissing++;
+ super.getWalker().getLogger().info("MissingFrom" + eval.toString() + " is missing from " + comp.getSource());
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/StandardEval.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/StandardEval.java
new file mode 100644
index 0000000..c3b75c1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/StandardEval.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+public interface StandardEval {}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/ThetaVariantEvaluator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/ThetaVariantEvaluator.java
new file mode 100644
index 0000000..60a4881
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/ThetaVariantEvaluator.java
@@ -0,0 +1,143 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.DataPoint;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+ at Analysis(description = "Computes different estimates of theta based on variant sites and genotypes")
+public class ThetaVariantEvaluator extends VariantEvaluator {
+ @DataPoint(description = "Average heterozygosity at variant sites; note that missing genotypes are ignored when computing this value", format = "%.8f")
+ public double avgHet = 0.0;
+ @DataPoint(description = "Average pairwise differences at aligned sequences; averaged over both number of sequeneces and number of variant sites; note that missing genotypes are ignored when computing this value", format = "%.8f")
+ public double avgAvgDiffs = 0.0;
+ @DataPoint(description = "Sum of heterozygosity over all variant sites; divide this by total target to get estimate of per base theta", format = "%.8f")
+ public double totalHet = 0.0;
+ @DataPoint(description = "Sum of pairwise diffs over all variant sites; divide this by total target to get estimate of per base theta", format = "%.8f")
+ public double totalAvgDiffs = 0.0;
+ @DataPoint(description = "Theta for entire region estimated based on number of segregating sites; divide ths by total target to get estimate of per base theta", format = "%.8f")
+ public double thetaRegionNumSites = 0.0;
+
+ //helper variables
+ double numSites = 0;
+
+ public int getComparisonOrder() {
+ return 1;
+ }
+
+ public void update1(VariantContext vc, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if (vc == null || !vc.isSNP() || (getWalker().ignoreAC0Sites() && vc.isMonomorphicInSamples())) {
+ return;
+ }
+
+ //this maps allele to a count
+ ConcurrentMap<String, Integer> alleleCounts = new ConcurrentHashMap<String, Integer>();
+
+ int numHetsHere = 0;
+ int numGenosHere = 0;
+ int numIndsHere = 0;
+
+ for (final Genotype genotype : vc.getGenotypes()) {
+ numIndsHere++;
+ if (!genotype.isNoCall()) {
+ //increment stats for heterozygosity
+ if (genotype.isHet()) {
+ numHetsHere++;
+ }
+
+ numGenosHere++;
+ //increment stats for pairwise mismatches
+
+ for (Allele allele : genotype.getAlleles()) {
+ if (allele.isCalled()) {
+ String alleleString = allele.toString();
+ alleleCounts.putIfAbsent(alleleString, 0);
+ alleleCounts.put(alleleString, alleleCounts.get(alleleString) + 1);
+ }
+ }
+ }
+ }
+ if (numGenosHere > 0) {
+ //only if have one called genotype at least
+ this.numSites++;
+
+ this.totalHet += numHetsHere / (double)numGenosHere;
+
+ //compute based on num sites
+ float harmonicFactor = 0;
+ for (int i = 1; i <= numIndsHere; i++) {
+ harmonicFactor += 1.0 / i;
+ }
+ this.thetaRegionNumSites += 1.0 / harmonicFactor;
+
+ //now compute pairwise mismatches
+ float numPairwise = 0;
+ int numDiffs = 0;
+ for (String allele1 : alleleCounts.keySet()) {
+ int allele1Count = alleleCounts.get(allele1);
+
+ for (String allele2 : alleleCounts.keySet()) {
+ if (allele1.compareTo(allele2) < 0) {
+ continue;
+ }
+ if (allele1 .compareTo(allele2) == 0) {
+ numPairwise += allele1Count * (allele1Count - 1) * .5;
+
+ }
+ else {
+ int allele2Count = alleleCounts.get(allele2);
+ numPairwise += allele1Count * allele2Count;
+ numDiffs += allele1Count * allele2Count;
+ }
+ }
+ }
+
+ if (numPairwise > 0) {
+ this.totalAvgDiffs += numDiffs / numPairwise;
+ }
+ }
+ }
+
+ @Override
+ public void finalizeEvaluation() {
+
+ if (this.numSites > 0) {
+
+ this.avgHet = this.totalHet / this.numSites;
+ this.avgAvgDiffs = this.totalAvgDiffs / this.numSites;
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/TiTvVariantEvaluator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/TiTvVariantEvaluator.java
new file mode 100644
index 0000000..1919c5f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/TiTvVariantEvaluator.java
@@ -0,0 +1,100 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.DataPoint;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.variantcontext.VariantContext;
+
+ at Analysis(description = "Ti/Tv Variant Evaluator")
+public class TiTvVariantEvaluator extends VariantEvaluator implements StandardEval {
+ @DataPoint(description = "number of transition loci", format = "%d")
+ public long nTi = 0;
+ @DataPoint(description = "number of transversion loci", format = "%d")
+ public long nTv = 0;
+ @DataPoint(description = "the transition to transversion ratio", format = "%.2f")
+ public double tiTvRatio = 0.0;
+ @DataPoint(description = "number of comp transition sites", format = "%d")
+ public long nTiInComp = 0;
+ @DataPoint(description = "number of comp transversion sites", format = "%d")
+ public long nTvInComp = 0;
+ @DataPoint(description = "the transition to transversion ratio for comp sites", format = "%.2f")
+ public double TiTvRatioStandard = 0.0;
+ @DataPoint(description = "number of derived transition loci", format = "%d")
+ public long nTiDerived = 0;
+ @DataPoint(description = "number of derived transversion loci", format = "%d")
+ public long nTvDerived = 0;
+ @DataPoint(description = "the derived transition to transversion ratio", format = "%.2f")
+ public double tiTvDerivedRatio = 0.0;
+
+ public int getComparisonOrder() {
+ return 2; // we only need to see each eval track
+ }
+
+ public void updateTiTv(VariantContext vc, boolean updateStandard) {
+ if (vc != null && vc.isSNP() && vc.isBiallelic() && vc.isPolymorphicInSamples()) {
+ if ( GATKVariantContextUtils.isTransition(vc)) {
+ if (updateStandard) nTiInComp++;
+ else nTi++;
+ } else {
+ if (updateStandard) nTvInComp++;
+ else nTv++;
+ }
+
+ if (vc.hasAttribute("ANCESTRALALLELE")) {
+ final String aaStr = vc.getAttributeAsString("ANCESTRALALLELE", "null").toUpperCase();
+ if ( ! aaStr.equals(".") ) {
+ switch ( BaseUtils.SNPSubstitutionType(aaStr.getBytes()[0], vc.getAlternateAllele(0).getBases()[0] ) ) {
+ case TRANSITION: nTiDerived++; break;
+ case TRANSVERSION: nTvDerived++; break;
+ default: break;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void update2(VariantContext eval, VariantContext comp, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if (eval != null)
+ updateTiTv(eval, false);
+ if (comp != null)
+ updateTiTv(comp, true);
+ }
+
+ @Override
+ public void finalizeEvaluation() {
+ // the ti/tv ratio needs to be set (it's not calculated per-variant).
+ this.tiTvRatio = rate(nTi,nTv);
+ this.tiTvDerivedRatio = rate(nTiDerived,nTvDerived);
+ this.TiTvRatioStandard = rate(nTiInComp, nTvInComp);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/ValidationReport.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/ValidationReport.java
new file mode 100644
index 0000000..664e5f2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/ValidationReport.java
@@ -0,0 +1,183 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.DataPoint;
+import htsjdk.variant.vcf.VCFConstants;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * The Broad Institute
+ * SOFTWARE COPYRIGHT NOTICE AGREEMENT
+ * This software and its documentation are copyright 2009 by the
+ * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
+ * <p/>
+ * This software is supplied without any warranty or guaranteed support whatsoever. Neither
+ * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
+ */
+ at Analysis(description = "Assess site accuracy and sensitivity of callset against follow-up validation assay")
+public class ValidationReport extends VariantEvaluator implements StandardEval {
+ // todo -- note this isn't strictly allele away. It's really focused on sites. A/T call at a validated A/G site is currently counted as a TP
+ @DataPoint(description = "nComp", format = "%d") public int nComp = 0;
+ @DataPoint(description = "TP", format = "%d") public int TP = 0;
+ @DataPoint(description = "FP", format = "%d") public int FP = 0;
+ @DataPoint(description = "FN", format = "%d") public int FN = 0;
+ @DataPoint(description = "TN", format = "%d") public int TN = 0;
+
+ @DataPoint(description = "Sensitivity", format = "%.2f") public double sensitivity = 0;
+ @DataPoint(description = "Specificity", format = "%.2f") public double specificity = 0;
+ @DataPoint(description = "PPV", format = "%.2f") public double PPV = 0;
+ @DataPoint(description = "FDR", format = "%.2f") public double FDR = 0;
+
+ @DataPoint(description = "CompMonoEvalNoCall", format = "%d") public int CompMonoEvalNoCall = 0;
+ @DataPoint(description = "CompMonoEvalFiltered", format = "%d") public int CompMonoEvalFiltered = 0;
+ @DataPoint(description = "CompMonoEvalMono", format = "%d") public int CompMonoEvalMono = 0;
+ @DataPoint(description = "CompMonoEvalPoly", format = "%d") public int CompMonoEvalPoly = 0;
+
+ @DataPoint(description = "CompPolyEvalNoCall", format = "%d") public int CompPolyEvalNoCall = 0;
+ @DataPoint(description = "CompPolyEvalFiltered", format = "%d") public int CompPolyEvalFiltered = 0;
+ @DataPoint(description = "CompPolyEvalMono", format = "%d") public int CompPolyEvalMono = 0;
+ @DataPoint(description = "CompPolyEvalPoly", format = "%d") public int CompPolyEvalPoly = 0;
+
+ @DataPoint(description = "CompFiltered", format = "%d") public int CompFiltered = 0;
+ @DataPoint(description = "Eval and comp have different alleles", format = "%d") public int nDifferentAlleleSites = 0;
+
+ private static final boolean TREAT_ALL_SITES_IN_EVAL_VCF_AS_CALLED = true;
+ private static final boolean REQUIRE_IDENTICAL_ALLELES = false;
+
+ private enum SiteStatus { NO_CALL, FILTERED, MONO, POLY }
+
+ // Counts of ValidationSiteStatus x CallSiteStatus
+ final int[][] counts = new int[SiteStatus.values().length][SiteStatus.values().length];
+
+ @Override public int getComparisonOrder() { return 2; }
+
+ @Override
+ public void finalizeEvaluation() {
+ for ( SiteStatus x : SiteStatus.values() )
+ CompFiltered += getCounts(SiteStatus.FILTERED, x);
+
+ CompMonoEvalNoCall = getCounts(SiteStatus.MONO, SiteStatus.NO_CALL);
+ CompMonoEvalFiltered = getCounts(SiteStatus.MONO, SiteStatus.FILTERED);
+ CompMonoEvalMono = getCounts(SiteStatus.MONO, SiteStatus.MONO);
+ CompMonoEvalPoly = getCounts(SiteStatus.MONO, SiteStatus.POLY);
+
+ CompPolyEvalNoCall = getCounts(SiteStatus.POLY, SiteStatus.NO_CALL);
+ CompPolyEvalFiltered = getCounts(SiteStatus.POLY, SiteStatus.FILTERED);
+ CompPolyEvalMono = getCounts(SiteStatus.POLY, SiteStatus.MONO);
+ CompPolyEvalPoly = getCounts(SiteStatus.POLY, SiteStatus.POLY);
+
+ TP = CompPolyEvalPoly;
+ FN = CompPolyEvalNoCall + CompPolyEvalFiltered + CompPolyEvalMono;
+ FP = CompMonoEvalPoly;
+ TN = CompMonoEvalNoCall + CompMonoEvalFiltered + CompMonoEvalMono;
+
+ for ( SiteStatus x : SiteStatus.values() )
+ for ( SiteStatus y : SiteStatus.values() )
+ nComp += getCounts(x, y);
+
+ if ( nComp != TP + FN + FP + TN + CompFiltered )
+ throw new ReviewedGATKException("BUG: nComp != TP + FN + FP + TN + CompFiltered!");
+
+ sensitivity = (100.0 * TP) / (TP + FN);
+ specificity = (TN+FP > 0) ? (100.0 * TN) / (TN + FP) : 100.0;
+ PPV = (100.0 * TP) / (TP + FP);
+ FDR = (100.0 * FP) / (FP + TP);
+ }
+
+ private int getCounts(SiteStatus comp, SiteStatus eval) {
+ return counts[comp.ordinal()][eval.ordinal()];
+ }
+
+ @Override
+ public void update2(VariantContext eval, VariantContext comp, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( comp != null ) { // we only need to consider sites in comp
+ if ( REQUIRE_IDENTICAL_ALLELES && (eval != null && haveDifferentAltAlleles(eval, comp)))
+ nDifferentAlleleSites++;
+ else {
+ SiteStatus evalStatus = calcSiteStatus(eval);
+ final Set<String> evalSamples = getWalker().getSampleNamesForEvaluation();
+ if ( comp.hasGenotypes() && ! evalSamples.isEmpty() && comp.hasGenotypes(evalSamples) )
+ // if we have genotypes in both eval and comp, subset comp down just the samples in eval
+ comp = comp.subContextFromSamples(evalSamples, false);
+ SiteStatus compStatus = calcSiteStatus(comp);
+ counts[compStatus.ordinal()][evalStatus.ordinal()]++;
+ }
+ }
+ }
+
+ //
+ // helper routines
+ //
+ private SiteStatus calcSiteStatus(VariantContext vc) {
+ if ( vc == null ) return SiteStatus.NO_CALL;
+ if ( vc.isFiltered() ) return SiteStatus.FILTERED;
+ if ( vc.isMonomorphicInSamples() ) return SiteStatus.MONO;
+ if ( vc.hasGenotypes() ) return SiteStatus.POLY; // must be polymorphic if isMonomorphicInSamples was false and there are genotypes
+
+ if ( vc.hasAttribute(VCFConstants.ALLELE_COUNT_KEY) ) {
+ int ac = 0;
+ if ( vc.getNAlleles() > 2 ) {
+ return SiteStatus.POLY;
+ }
+ else
+ ac = vc.getAttributeAsInt(VCFConstants.ALLELE_COUNT_KEY, 0);
+ return ac > 0 ? SiteStatus.POLY : SiteStatus.MONO;
+ } else {
+ return TREAT_ALL_SITES_IN_EVAL_VCF_AS_CALLED ? SiteStatus.POLY : SiteStatus.NO_CALL; // we can't figure out what to do
+ }
+ }
+
+
+
+ private boolean haveDifferentAltAlleles(VariantContext eval, VariantContext comp) {
+ Collection<Allele> evalAlts = eval.getAlternateAlleles();
+ Collection<Allele> compAlts = comp.getAlternateAlleles();
+ if ( evalAlts.size() != compAlts.size() ) {
+ return true;
+ } else {
+ // same size => every alt from eval must be in comp
+ for ( Allele a : evalAlts ) {
+ if ( ! compAlts.contains(a) ) {
+// System.out.printf("Different alleles: %s:%d eval=%s comp=%s\n\t\teval=%s\n\t\tcomp=%s%n",
+// eval.getChr(), eval.getStart(), eval.getAlleles(), comp.getAlleles(), eval, comp);
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/VariantEvaluator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/VariantEvaluator.java
new file mode 100644
index 0000000..0984a2e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/VariantEvaluator.java
@@ -0,0 +1,133 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.VariantEval;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import htsjdk.variant.variantcontext.VariantContext;
+
+public abstract class VariantEvaluator implements Comparable<VariantEvaluator> {
+ private VariantEval walker;
+ private final String simpleName;
+
+ protected VariantEvaluator() {
+ this.simpleName = getClass().getSimpleName();
+ }
+
+ public void initialize(VariantEval walker) {
+ this.walker = walker;
+ }
+
+ public VariantEval getWalker() {
+ return walker;
+ }
+
+ // Should return the number of VariantContexts expected as inputs to update. Can be 1 or 2
+ public abstract int getComparisonOrder();
+
+ // called at all sites, regardless of eval context itself; useful for counting processed bases
+ // No longer available. The processed bp is kept in VEW itself for performance reasons
+ // public void update0(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+
+ public void update1(VariantContext eval, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ }
+
+ public void update2(VariantContext eval, VariantContext comp, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ }
+
+ public void finalizeEvaluation() {}
+
+ protected double rate(long n, long d) {
+ return n / (1.0 * Math.max(d, 1));
+ }
+
+ protected long inverseRate(long n, long d) {
+ return n == 0 ? 0 : d / Math.max(n, 1);
+ }
+
+ protected double ratio(long num, long denom) {
+ return ((double)num) / (Math.max(denom, 1));
+ }
+
+ /**
+ * Returns true if the variant in vc was a singleton in the original input evaluation
+ * set, regardless of variant context subsetting that has occurred.
+ * @param eval the VariantContext being assessed for this previous status as a singleton
+ * @return true if eval was originally a singleton site
+ */
+ protected static boolean variantWasSingleton(final VariantContext eval) {
+ return eval.getAttributeAsBoolean(VariantEval.IS_SINGLETON_KEY, false);
+ }
+
+ public final String getSimpleName() {
+ return simpleName;
+ }
+
+ @Override
+ public int compareTo(final VariantEvaluator variantEvaluator) {
+ return getSimpleName().compareTo(variantEvaluator.getSimpleName());
+ }
+
+ /**
+ * Evaluation modules that override this function to indicate that they support
+ * combining the results of two independent collections of eval data into
+ * a single meaningful result. The purpose of this interface is to
+ * allow us to cut up the input data into many independent stratifications, and then
+ * at the end of the eval run decide which stratifications to combine. This is
+ * important in the case of AC, where you may have thousands of distinct AC
+ * values that chop up the number of variants to too small a number of variants,
+ * and you'd like to combine the AC values into ranges containing some percent
+ * of the data.
+ *
+ * For example, suppose you have an eval that
+ * counts variants in a variable nVariants. If you want to be able to combine
+ * multiple evaluations of this type, overload the combine function
+ * with a function that sets this.nVariants += other.nVariants.
+ *
+ * Add in the appropriate fields of the VariantEvaluator T
+ * (of the same type as this object) to the values of this object.
+ *
+ * The values in this and other are implicitly independent, so that
+ * the values can be added together.
+ *
+ * @param other a VariantEvaluator of the same type of this object
+ */
+ public void combine(final VariantEvaluator other) {
+ throw new ReviewedGATKException(getSimpleName() + " doesn't support combining results, sorry");
+ }
+
+ /**
+ * Must be overloaded to return true for evaluation modules that support the combine operation
+ *
+ * @return
+ */
+ public boolean supportsCombine() {
+ return false;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/VariantSummary.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/VariantSummary.java
new file mode 100644
index 0000000..9147330
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/evaluators/VariantSummary.java
@@ -0,0 +1,277 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.evaluators;
+
+import htsjdk.samtools.util.IntervalTree;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.VariantEval;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.Analysis;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.DataPoint;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.vcf.VCFConstants;
+import org.broadinstitute.gatk.utils.interval.IntervalUtils;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.*;
+
+ at Analysis(description = "1000 Genomes Phase I summary of variants table")
+public class VariantSummary extends VariantEvaluator implements StandardEval {
+ final protected static Logger logger = Logger.getLogger(VariantSummary.class);
+
+ /** Indels with size greater than this value are tallied in the CNV column */
+ private final static int MAX_INDEL_LENGTH = 50;
+ private final static double MIN_CNV_OVERLAP = 0.5;
+
+ public enum Type {
+ SNP, INDEL, CNV
+ }
+
+ Map<String, IntervalTree<GenomeLoc>> knownCNVs = null;
+
+ // basic counts on various rates found
+ @DataPoint(description = "Number of samples", format = "%d")
+ public long nSamples = 0;
+
+ @DataPoint(description = "Number of processed loci", format = "%d")
+ public long nProcessedLoci = 0;
+
+ @DataPoint(description = "Number of SNPs", format = "%d")
+ public long nSNPs = 0;
+ @DataPoint(description = "Overall TiTv ratio", format = "%.2f")
+ public double TiTvRatio = 0;
+ @DataPoint(description = "SNP Novelty Rate", format = "%s")
+ public String SNPNoveltyRate = "NA";
+ @DataPoint(description = "Mean number of SNPs per individual", format = "%d")
+ public long nSNPsPerSample = 0;
+ @DataPoint(description = "Mean TiTv ratio per individual", format = "%.2f")
+ public double TiTvRatioPerSample = 0;
+ @DataPoint(description = "Mean depth of coverage per sample at SNPs", format = "%.1f")
+ public double SNPDPPerSample = 0;
+
+ @DataPoint(description = "Number of Indels", format = "%d")
+ public long nIndels = 0;
+ @DataPoint(description = "Indel Novelty Rate", format = "%s")
+ public String IndelNoveltyRate = "NA";
+ @DataPoint(description = "Mean number of Indels per individual", format = "%d")
+ public long nIndelsPerSample = 0;
+ @DataPoint(description = "Mean depth of coverage per sample at Indels", format = "%.1f")
+ public double IndelDPPerSample = 0;
+
+ @DataPoint(description = "Number of SVs", format = "%d")
+ public long nSVs = 0;
+ @DataPoint(description = "SV Novelty Rate", format = "%s")
+ public String SVNoveltyRate = "NA";
+ @DataPoint(description = "Mean number of SVs per individual", format = "%d")
+ public long nSVsPerSample = 0;
+
+ TypeSampleMap allVariantCounts, knownVariantCounts;
+ TypeSampleMap countsPerSample;
+ TypeSampleMap transitionsPerSample, transversionsPerSample;
+ TypeSampleMap depthPerSample;
+
+ private final static String ALL = "ALL";
+
+ private class TypeSampleMap extends EnumMap<Type, Map<String, Integer>> {
+ public TypeSampleMap(final Collection<String> samples) {
+ super(Type.class);
+ for ( Type type : Type.values() ) {
+ Map<String, Integer> bySample = new HashMap<String, Integer>(samples.size());
+ for ( final String sample : samples ) {
+ bySample.put(sample, 0);
+ }
+ bySample.put(ALL, 0);
+ this.put(type, bySample);
+ }
+ }
+
+ public final void inc(final Type type, final String sample) {
+ final int count = this.get(type).get(sample);
+ get(type).put(sample, count + 1);
+ }
+
+ public final int all(Type type) {
+ return get(type).get(ALL);
+ }
+
+ public final int meanValue(Type type) {
+ long sum = 0;
+ int n = 0;
+ for ( final Map.Entry<String, Integer> pair : get(type).entrySet() ) {
+ if ( pair.getKey() != ALL) { // truly must be string ==
+ n++;
+ sum += pair.getValue();
+ }
+ }
+ return (int)(Math.round(sum / (1.0 * n)));
+ }
+
+ public final double ratioValue(Type type, TypeSampleMap denoms, boolean allP) {
+ double sum = 0;
+ int n = 0;
+ for ( final String sample : get(type).keySet() ) {
+ if ( (allP && sample == ALL) || (!allP && sample != ALL) ) { // truly must be string ==
+ final long num = get(type).get(sample);
+ final long denom = denoms.get(type).get(sample);
+ sum += ratio(num, denom);
+ n++;
+ }
+ }
+
+ return n > 0 ? sum / (1.0 * n) : 0.0;
+ }
+ }
+
+
+ public void initialize(VariantEval walker) {
+ super.initialize(walker);
+
+ nSamples = walker.getSampleNamesForEvaluation().size();
+ countsPerSample = new TypeSampleMap(walker.getSampleNamesForEvaluation());
+ transitionsPerSample = new TypeSampleMap(walker.getSampleNamesForEvaluation());
+ transversionsPerSample = new TypeSampleMap(walker.getSampleNamesForEvaluation());
+ allVariantCounts = new TypeSampleMap(walker.getSampleNamesForEvaluation());
+ knownVariantCounts = new TypeSampleMap(walker.getSampleNamesForEvaluation());
+ depthPerSample = new TypeSampleMap(walker.getSampleNamesForEvaluation());
+
+ if ( walker.knownCNVsFile != null ) {
+ knownCNVs = walker.createIntervalTreeByContig(walker.knownCNVsFile);
+ final List<GenomeLoc> locs = walker.knownCNVsFile.getIntervals(walker.getToolkit());
+ logger.info(String.format("Creating known CNV list %s containing %d intervals covering %d bp",
+ walker.knownCNVsFile.getSource(), locs.size(), IntervalUtils.intervalSize(locs)));
+ }
+ }
+
+ public int getComparisonOrder() {
+ return 2; // we only need to see each eval track
+ }
+
+ private Type getType(VariantContext vc) {
+ switch (vc.getType()) {
+ case SNP:
+ return Type.SNP;
+ case INDEL:
+ for ( int l : vc.getIndelLengths() )
+ if ( Math.abs(l) > MAX_INDEL_LENGTH )
+ return Type.CNV;
+ return Type.INDEL;
+ case SYMBOLIC:
+ return Type.CNV;
+ default:
+ //throw new UserException.BadInput("Unexpected variant context type: " + vc);
+ return null;
+ }
+ }
+
+ private boolean overlapsKnownCNV(VariantContext cnv) {
+ if ( knownCNVs != null ) {
+ final GenomeLoc loc = getWalker().getToolkit().getGenomeLocParser().createGenomeLoc(cnv);
+ IntervalTree<GenomeLoc> intervalTree = knownCNVs.get(loc.getContig());
+
+ final Iterator<IntervalTree.Node<GenomeLoc>> nodeIt = intervalTree.overlappers(loc.getStart(), loc.getStop());
+ while ( nodeIt.hasNext() ) {
+ final double overlapP = loc.reciprocialOverlapFraction(nodeIt.next().getValue());
+ if ( overlapP > MIN_CNV_OVERLAP )
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public void update2(VariantContext eval, VariantContext comp, RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( eval == null || (getWalker().ignoreAC0Sites() && eval.isMonomorphicInSamples()) )
+ return;
+
+ final Type type = getType(eval);
+ if ( type == null )
+ return;
+
+ TypeSampleMap titvTable = null;
+
+ // update DP, if possible
+ if ( eval.hasAttribute(VCFConstants.DEPTH_KEY) )
+ depthPerSample.inc(type, ALL);
+
+ // update counts
+ allVariantCounts.inc(type, ALL);
+
+ // type specific calculations
+ if ( type == Type.SNP && eval.isBiallelic() ) {
+ titvTable = GATKVariantContextUtils.isTransition(eval) ? transitionsPerSample : transversionsPerSample;
+ titvTable.inc(type, ALL);
+ }
+
+ // novelty calculation
+ if ( comp != null || (type == Type.CNV && overlapsKnownCNV(eval)))
+ knownVariantCounts.inc(type, ALL);
+
+ // per sample metrics
+ for (final Genotype g : eval.getGenotypes()) {
+ if ( ! g.isNoCall() && ! g.isHomRef() ) {
+ countsPerSample.inc(type, g.getSampleName());
+
+ // update transition / transversion ratio
+ if ( titvTable != null ) titvTable.inc(type, g.getSampleName());
+
+ if ( g.hasDP() )
+ depthPerSample.inc(type, g.getSampleName());
+ }
+ }
+ }
+
+ private String noveltyRate(Type type) {
+ final int all = allVariantCounts.all(type);
+ final int known = knownVariantCounts.all(type);
+ return Utils.formattedNoveltyRate(known, all);
+ }
+
+ public void finalizeEvaluation() {
+ nProcessedLoci = getWalker().getnProcessedLoci();
+ nSNPs = allVariantCounts.all(Type.SNP);
+ nIndels = allVariantCounts.all(Type.INDEL);
+ nSVs = allVariantCounts.all(Type.CNV);
+
+ TiTvRatio = transitionsPerSample.ratioValue(Type.SNP, transversionsPerSample, true);
+ TiTvRatioPerSample = transitionsPerSample.ratioValue(Type.SNP, transversionsPerSample, false);
+
+ nSNPsPerSample = countsPerSample.meanValue(Type.SNP);
+ nIndelsPerSample = countsPerSample.meanValue(Type.INDEL);
+ nSVsPerSample = countsPerSample.meanValue(Type.CNV);
+
+ SNPNoveltyRate = noveltyRate(Type.SNP);
+ IndelNoveltyRate = noveltyRate(Type.INDEL);
+ SVNoveltyRate = noveltyRate(Type.CNV);
+
+ SNPDPPerSample = depthPerSample.meanValue(Type.SNP);
+ IndelDPPerSample = depthPerSample.meanValue(Type.INDEL);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/AlleleCount.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/AlleleCount.java
new file mode 100644
index 0000000..1f7ed14
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/AlleleCount.java
@@ -0,0 +1,114 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.evaluators.VariantEvaluator;
+import org.broadinstitute.gatk.tools.walkers.varianteval.evaluators.VariantSummary;
+import htsjdk.variant.vcf.VCFConstants;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.*;
+
+/**
+ * Stratifies the eval RODs by the allele count of the alternate allele
+ *
+ * Looks first at the MLEAC value in the INFO field, and uses that value if present.
+ * If not present, it then looks for the AC value in the INFO field. If both are absent,
+ * it computes the AC from the genotypes themselves. If no AC can be computed, 0 is used.
+ */
+public class AlleleCount extends VariantStratifier {
+ int nchrom;
+
+ @Override
+ public void initialize() {
+ // we can only work with a single eval VCF, and it must have genotypes
+ if ( getVariantEvalWalker().getEvals().size() != 1 && !getVariantEvalWalker().mergeEvals )
+ throw new UserException.BadArgumentValue("AlleleCount", "AlleleCount stratification only works with a single eval vcf");
+
+ // There are ploidy x n sample chromosomes
+ // TODO -- generalize to handle multiple ploidy
+ nchrom = getVariantEvalWalker().getNumberOfSamplesForEvaluation() * getVariantEvalWalker().getSamplePloidy();
+ if ( nchrom < 2 )
+ throw new UserException.BadArgumentValue("AlleleCount", "AlleleCount stratification requires an eval vcf with at least one sample");
+
+ // create an array containing each of the allele counts
+ for( int ac = 0; ac <= nchrom; ac++ ) {
+ states.add(ac);
+ }
+
+ getVariantEvalWalker().getLogger().info("AlleleCount using " + nchrom + " chromosomes");
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ if (eval != null) {
+ int AC = 0; // by default, the site is considered monomorphic
+
+ try {
+ if ( eval.isBiallelic() ) {
+ if ( eval.hasAttribute(VCFConstants.MLE_ALLELE_COUNT_KEY) ) {
+ // the MLEAC is allowed to be larger than the AN (e.g. in the case of all PLs being 0, the GT is ./. but the exact model may arbitrarily choose an AC>1)
+ AC = Math.min(eval.getAttributeAsInt(VCFConstants.MLE_ALLELE_COUNT_KEY, 0), nchrom);
+ } else if ( eval.hasAttribute(VCFConstants.ALLELE_COUNT_KEY) ) {
+ AC = eval.getAttributeAsInt(VCFConstants.ALLELE_COUNT_KEY, 0);
+ }
+ }
+ } catch ( ClassCastException e ) {
+ // protect ourselves from bad inputs
+ // TODO -- fully decode VC
+ }
+
+ if ( AC == 0 && eval.isVariant() ) {
+ // fall back to the direct calculation
+ for (Allele allele : eval.getAlternateAlleles())
+ AC = Math.max(AC, eval.getCalledChrCount(allele));
+ }
+
+ // make sure that the AC isn't invalid
+ if ( AC > nchrom )
+ throw new UserException.MalformedVCF(String.format("The AC value (%d) at position %s:%d " +
+ "is larger than the number of chromosomes over all samples (%d)", AC,
+ eval.getChr(), eval.getStart(), nchrom));
+
+ return Collections.singletonList((Object) AC);
+ } else {
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public Set<Class<? extends VariantEvaluator>> getIncompatibleEvaluators() {
+ return new HashSet<Class<? extends VariantEvaluator>>(Arrays.asList(VariantSummary.class));
+ }
+
+ @Override
+ public String getFormat() {
+ return "%d";
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/AlleleFrequency.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/AlleleFrequency.java
new file mode 100644
index 0000000..349979a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/AlleleFrequency.java
@@ -0,0 +1,61 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.MathUtils;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Stratifies the eval RODs by the allele frequency of the alternate allele
+ *
+ * Uses a constant 0.005 frequency grid, and projects the AF INFO field value. Requires
+ * that AF be present in every ROD, otherwise this stratification throws an exception
+ */
+public class AlleleFrequency extends VariantStratifier {
+ @Override
+ public void initialize() {
+ for( double a = 0.000; a <= 1.005; a += 0.005 ) {
+ states.add(String.format("%.3f", a));
+ }
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ if (eval != null) {
+ try {
+ return Collections.singletonList((Object)String.format("%.3f", (5.0 * MathUtils.round(eval.getAttributeAsDouble("AF", 0.0) / 5.0, 3))));
+ } catch (Exception e) {
+ return Collections.emptyList();
+ }
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/CompRod.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/CompRod.java
new file mode 100644
index 0000000..f131ca7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/CompRod.java
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Collections;
+import java.util.List;
+
+
+/**
+ * Required stratification grouping output by each comp ROD
+ */
+public class CompRod extends VariantStratifier implements RequiredStratification {
+ @Override
+ public void initialize() {
+ for ( RodBinding<VariantContext> rod : getVariantEvalWalker().getComps() ) {
+ states.add(rod.getName());
+ }
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ return Collections.singletonList((Object)compName);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Contig.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Contig.java
new file mode 100644
index 0000000..f90e7c5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Contig.java
@@ -0,0 +1,54 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Stratifies the evaluation by each contig in the reference sequence
+ */
+public class Contig extends VariantStratifier {
+ @Override
+ public void initialize() {
+ states.addAll(getVariantEvalWalker().getContigNames());
+ states.add("all");
+ }
+
+ @Override
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ if (eval != null) {
+ return Arrays.asList((Object)"all", eval.getChr());
+ } else {
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/CpG.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/CpG.java
new file mode 100644
index 0000000..97e5e72
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/CpG.java
@@ -0,0 +1,76 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * CpG is a stratification module for VariantEval that divides the input data by within/not within a CpG site
+ *
+ * <p>
+ * It is a three-state stratification:
+ * <ul>
+ * <li>The locus is a CpG site ("CpG")
+ * <li>The locus is not a CpG site ("non_CpG")
+ * <li>The locus is either a CpG or not a CpG site ("all")
+ * </ul>
+ * A CpG site is defined as a site where the reference base at a locus is a C and the adjacent reference base in the 3' direction is a G.
+ */
+public class CpG extends VariantStratifier {
+ @Override
+ public void initialize() {
+ states.add("all");
+ states.add("CpG");
+ states.add("non_CpG");
+ }
+
+ @Override
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ boolean isCpG = false;
+ if (ref != null && ref.getBases() != null) {
+ String fwRefBases = new String(ref.getBases());
+
+ //String leftFlank = fwRefBases.substring((fwRefBases.length()/2) - 1, (fwRefBases.length()/2) + 1);
+ String rightFlank = fwRefBases.substring((fwRefBases.length()/2), (fwRefBases.length()/2) + 2);
+
+ //if (leftFlank.equalsIgnoreCase("CG") || leftFlank.equalsIgnoreCase("GC") || rightFlank.equalsIgnoreCase("CG") || rightFlank.equalsIgnoreCase("GC")) {
+ if (rightFlank.equalsIgnoreCase("CG")) {
+ isCpG = true;
+ }
+ }
+
+ ArrayList<Object> relevantStates = new ArrayList<Object>(2);
+ relevantStates.add("all");
+ relevantStates.add(isCpG ? "CpG" : "non_CpG");
+
+ return relevantStates;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Degeneracy.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Degeneracy.java
new file mode 100644
index 0000000..03cba8c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Degeneracy.java
@@ -0,0 +1,158 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Experimental stratification by the degeneracy of an amino acid, according to VCF annotation. Not safe
+ */
+public class Degeneracy extends VariantStratifier {
+ private HashMap<String, HashMap<Integer, String>> degeneracies;
+
+ @Override
+ public void initialize() {
+ states.add("1-fold");
+ states.add("2-fold");
+ states.add("3-fold");
+ states.add("4-fold");
+ states.add("6-fold");
+ states.add("all");
+
+ HashMap<String, String[]> aminoAcids = new HashMap<String, String[]>();
+ aminoAcids.put("Ile", new String[]{"ATT", "ATC", "ATA"});
+ aminoAcids.put("Leu", new String[]{"CTT", "CTC", "CTA", "CTG", "TTA", "TTG"});
+ aminoAcids.put("Val", new String[]{"GTT", "GTC", "GTA", "GTG"});
+ aminoAcids.put("Phe", new String[]{"TTT", "TTC"});
+ aminoAcids.put("Met", new String[]{"ATG"});
+ aminoAcids.put("Cys", new String[]{"TGT", "TGC"});
+ aminoAcids.put("Ala", new String[]{"GCT", "GCC", "GCA", "GCG"});
+ aminoAcids.put("Gly", new String[]{"GGT", "GGC", "GGA", "GGG"});
+ aminoAcids.put("Pro", new String[]{"CCT", "CCC", "CCA", "CCG"});
+ aminoAcids.put("Thr", new String[]{"ACT", "ACC", "ACA", "ACG"});
+ aminoAcids.put("Ser", new String[]{"TCT", "TCC", "TCA", "TCG", "AGT", "AGC"});
+ aminoAcids.put("Tyr", new String[]{"TAT", "TAC"});
+ aminoAcids.put("Trp", new String[]{"TGG"});
+ aminoAcids.put("Glu", new String[]{"CAA", "CAG"});
+ aminoAcids.put("Asn", new String[]{"AAT", "AAC"});
+ aminoAcids.put("His", new String[]{"CAT", "CAC"});
+ aminoAcids.put("Gln", new String[]{"GAA", "GAG"});
+ aminoAcids.put("Asp", new String[]{"GAT", "GAC"});
+ aminoAcids.put("Lys", new String[]{"AAA", "AAG"});
+ aminoAcids.put("Arg", new String[]{"CGT", "CGC", "CGA", "CGG", "AGA", "AGG"});
+ aminoAcids.put("Stop", new String[]{"TAA", "TAG", "TGA"});
+
+ degeneracies = new HashMap<String, HashMap<Integer, String>>();
+
+ for (String aminoAcid : aminoAcids.keySet()) {
+ String[] codons = aminoAcids.get(aminoAcid);
+
+ for (int pos = 0; pos < 3; pos++) {
+ HashSet<Character> alleles = new HashSet<Character>();
+
+ for (String codon : codons) {
+ alleles.add(codon.charAt(pos));
+ }
+
+ String degeneracy;
+ switch (alleles.size()) {
+ case 1: degeneracy = "1-fold"; break;
+ case 2: degeneracy = "2-fold"; break;
+ case 3: degeneracy = "3-fold"; break;
+ case 4: degeneracy = "4-fold"; break;
+ case 6: degeneracy = "6-fold"; break;
+ default: degeneracy = "1-fold"; break;
+ }
+
+ if (!degeneracies.containsKey(aminoAcid)) {
+ degeneracies.put(aminoAcid, new HashMap<Integer, String>());
+ }
+
+ degeneracies.get(aminoAcid).put(pos, degeneracy);
+ }
+ }
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ ArrayList<Object> relevantStates = new ArrayList<Object>();
+
+ relevantStates.add("all");
+
+ if (eval != null && eval.isVariant()) {
+ String type = null;
+ String aa = null;
+ Integer frame = null;
+
+ if (eval.hasAttribute("refseq.functionalClass")) {
+ aa = eval.getAttributeAsString("refseq.variantAA", null);
+ frame = eval.getAttributeAsInt("refseq.frame", 0);
+ } else if (eval.hasAttribute("refseq.functionalClass_1")) {
+ int annotationId = 1;
+ String key;
+
+ do {
+ key = String.format("refseq.functionalClass_%d", annotationId);
+
+ String newtype = eval.getAttributeAsString(key, null);
+
+ if ( newtype != null &&
+ ( type == null ||
+ ( type.equals("silent") && !newtype.equals("silent") ) ||
+ ( type.equals("missense") && newtype.equals("nonsense") ) )
+ ) {
+ type = newtype;
+
+ String aakey = String.format("refseq.variantAA_%d", annotationId);
+ aa = eval.getAttributeAsString(aakey, null);
+
+ if (aa != null) {
+ String framekey = String.format("refseq.frame_%d", annotationId);
+
+ if (eval.hasAttribute(framekey)) {
+ frame = eval.getAttributeAsInt(framekey, 0);
+ }
+ }
+ }
+
+ annotationId++;
+ } while (eval.hasAttribute(key));
+ }
+
+ if (aa != null && degeneracies.containsKey(aa) && frame != null) {
+ relevantStates.add(degeneracies.get(aa).get(frame));
+ }
+ }
+
+ return relevantStates;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/DynamicStratification.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/DynamicStratification.java
new file mode 100644
index 0000000..1c42898
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/DynamicStratification.java
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import htsjdk.variant.variantcontext.VariantContext;
+
+/**
+ * Tag this stratification as dynamically determining the final strat based on the input data
+ *
+ * The paradigm here is simple. We upfront create a strat with N states that reflect the finest grained
+ * possible division of the data. The data is processed, and statistics collected for each of the N states.
+ * An update call is made to the stratification for evaluation VariantContext during each map call,
+ * allowing the strat to collect data about the usage of each state. A final call requests that
+ * the stratification map down the N states into M states (typically less than N, not necessarily
+ * a subset of N). This is provided by returning a map from each of M state -> N states and
+ * the VariantEval walker will combine all of the evaluations for N into a single value for
+ * each M.
+ *
+ * For example, suppose I have a dynamic strat called AC, adopting 7 possible values 0,1,2,3,4,5,6. This
+ * strats tracks the number of eval vcs for each state, with final counts 0=1, 1=100, 2=10, 3=5, 4=3, 5=2, 6=1.
+ * The stratification attempts to combine the strats down to so that each state has approximately the same
+ * fraction of the data in each bin. Overall there is 1+100+10+5+3+2+1=124 observations and 7 bins so we really
+ * want ~ 18 observations in each bin. So we merge 3-6 with 5+3+2+1 = 11 and keep 2, 1, and 0 as distinct bins. We
+ * return a map from 0 -> 0, 1 -> 1, 2 -> 2, 3-6 -> {3,4,5,6}.
+ *
+ * TODO - some open implementation questions
+ * -- We should only create one stratifier overall. How do we track this? When we create the stratifiers
+ * perhaps we can look at them and create a tracker?
+ * -- How do we create a new stratifier based on the finalStratifications() given the framework? Conceptually
+ * this new thing is itself a stratifier, just like before, but it's states are determined at the end. We'd
+ * then like to call not getRelevantStates but a different function that accepts an old state and returns
+ * the new state. Perhaps the process should look like:
+ * finalizeStratification -> new Stratifier whose states are the final ones
+ * getNewState(old state) -> new state (one of those in getFinalStratification)
+ *
+ * @author Mark DePristo
+ * @since 4/9/12
+ */
+public interface DynamicStratification {
+ public void update(final VariantContext eval);
+ public VariantStratifier finalizeStratification();
+ public Object getFinalState(final Object oldState);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/EvalRod.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/EvalRod.java
new file mode 100644
index 0000000..8fdd007
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/EvalRod.java
@@ -0,0 +1,52 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Required stratification grouping output by each eval ROD
+ */
+public class EvalRod extends VariantStratifier implements RequiredStratification {
+ @Override
+ public void initialize() {
+ for ( RodBinding<VariantContext> rod : getVariantEvalWalker().getEvals() ) {
+ states.add(rod.getName());
+ if ( getVariantEvalWalker().mergeEvals )
+ break;
+ }
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ return Arrays.asList((Object)evalName);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Filter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Filter.java
new file mode 100644
index 0000000..c37f003
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Filter.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Stratifies by the FILTER status (PASS, FAIL) of the eval records
+ */
+public class Filter extends VariantStratifier {
+ @Override
+ public void initialize() {
+ states.add("called");
+ states.add("filtered");
+ states.add("raw");
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ ArrayList<Object> relevantStates = new ArrayList<Object>();
+
+ relevantStates.add("raw");
+ if (eval != null) {
+ relevantStates.add(eval.isFiltered() ? "filtered" : "called");
+ }
+
+ return relevantStates;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/FunctionalClass.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/FunctionalClass.java
new file mode 100644
index 0000000..08ff9d4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/FunctionalClass.java
@@ -0,0 +1,110 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.annotator.SnpEff;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Stratifies by nonsense, missense, silent, and all annotations in the input ROD, from the INFO field annotation.
+ */
+public class FunctionalClass extends VariantStratifier {
+
+ public enum FunctionalType {
+ silent,
+ missense,
+ nonsense
+ }
+
+
+ @Override
+ public void initialize() {
+ states.add("all");
+ for ( FunctionalType type : FunctionalType.values() )
+ states.add(type.name());
+ }
+
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ ArrayList<Object> relevantStates = new ArrayList<Object>();
+
+ relevantStates.add("all");
+
+ if (eval != null && eval.isVariant()) {
+ FunctionalType type = null;
+
+ if (eval.hasAttribute("refseq.functionalClass")) {
+ try {
+ type = FunctionalType.valueOf(eval.getAttributeAsString("refseq.functionalClass", null));
+ } catch ( Exception e ) {} // don't error out if the type isn't supported
+ } else if (eval.hasAttribute("refseq.functionalClass_1")) {
+ int annotationId = 1;
+ String key;
+
+ do {
+ key = String.format("refseq.functionalClass_%d", annotationId);
+
+ String newtypeStr = eval.getAttributeAsString(key, null);
+ if ( newtypeStr != null && !newtypeStr.equalsIgnoreCase("null") ) {
+ try {
+ FunctionalType newType = FunctionalType.valueOf(newtypeStr);
+ if ( type == null ||
+ ( type == FunctionalType.silent && newType != FunctionalType.silent ) ||
+ ( type == FunctionalType.missense && newType == FunctionalType.nonsense ) ) {
+ type = newType;
+ }
+ } catch ( Exception e ) {} // don't error out if the type isn't supported
+ }
+
+ annotationId++;
+ } while (eval.hasAttribute(key));
+
+ } else if ( eval.hasAttribute(SnpEff.InfoFieldKey.FUNCTIONAL_CLASS_KEY.getKeyName()) ) {
+ try {
+ SnpEff.EffectFunctionalClass snpEffFunctionalClass = SnpEff.EffectFunctionalClass.valueOf(eval.getAttribute(SnpEff.InfoFieldKey.FUNCTIONAL_CLASS_KEY.getKeyName()).toString());
+ if ( snpEffFunctionalClass == SnpEff.EffectFunctionalClass.NONSENSE )
+ type = FunctionalType.nonsense;
+ else if ( snpEffFunctionalClass == SnpEff.EffectFunctionalClass.MISSENSE )
+ type = FunctionalType.missense;
+ else if ( snpEffFunctionalClass == SnpEff.EffectFunctionalClass.SILENT )
+ type = FunctionalType.silent;
+ }
+ catch ( Exception e ) {} // don't error out if the type isn't supported
+ }
+
+ if ( type != null ) {
+ relevantStates.add(type.name());
+ }
+ }
+
+ return relevantStates;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/IndelSize.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/IndelSize.java
new file mode 100644
index 0000000..e5cb240
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/IndelSize.java
@@ -0,0 +1,78 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Stratifies the eval RODs by the indel size
+ *
+ * Indel sizes are stratified from sizes -100 to +100. Sizes greater than this are lumped in the +/- 100 bin
+ * This stratification ignores multi-allelic indels (whose size is not defined uniquely)
+ */
+public class IndelSize extends VariantStratifier {
+ static final int MAX_INDEL_SIZE = 100;
+
+ @Override
+ public void initialize() {
+ for( int a=-MAX_INDEL_SIZE; a <=MAX_INDEL_SIZE; a++ ) {
+ states.add(a);
+ }
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ if (eval != null && eval.isIndel() && eval.isBiallelic()) {
+ try {
+ int eventLength = 0;
+ if ( eval.isSimpleInsertion() ) {
+ eventLength = eval.getAlternateAllele(0).length();
+ } else if ( eval.isSimpleDeletion() ) {
+ eventLength = -eval.getReference().length();
+ }
+
+ if (eventLength > MAX_INDEL_SIZE)
+ eventLength = MAX_INDEL_SIZE;
+ else if (eventLength < -MAX_INDEL_SIZE)
+ eventLength = -MAX_INDEL_SIZE;
+
+ return Collections.singletonList((Object)eventLength);
+ } catch (Exception e) {
+ return Collections.emptyList();
+ }
+ }
+
+ return Collections.emptyList();
+ }
+ @Override
+ public String getFormat() {
+ return "%d";
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/IntervalStratification.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/IntervalStratification.java
new file mode 100644
index 0000000..8ee4e79
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/IntervalStratification.java
@@ -0,0 +1,92 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import htsjdk.samtools.util.IntervalTree;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.interval.IntervalUtils;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.*;
+
+/**
+ * Stratifies the variants by whether they overlap an interval in the set provided on the command line.
+ *
+ * The primary use of this stratification is to provide a mechanism to divide asssessment of a call set up
+ * by whether a variant overlaps an interval or not. I use this to differentiate between variants occurring
+ * in CCDS exons vs. those in non-coding regions, in the 1000G call set, using a command line that looks like:
+ *
+ * -T VariantEval -R human_g1k_v37.fasta -eval 1000G.vcf -stratIntervals:BED ccds.bed -ST IntervalStratification
+ *
+ * Note that the overlap algorithm properly handles symbolic alleles with an INFO field END value. In order to
+ * safely use this module you should provide entire contigs worth of variants, and let the interval strat decide
+ * overlap, as opposed to using -L which will not properly work with symbolic variants.
+ */
+public class IntervalStratification extends VariantStratifier {
+ final protected static Logger logger = Logger.getLogger(IntervalStratification.class);
+ Map<String, IntervalTree<GenomeLoc>> intervalTreeByContig = null;
+
+ final List<Object> OVERLAPPING = Arrays.asList((Object)"all", (Object)"overlaps.intervals");
+ final List<Object> NOT_OVERLAPPING = Arrays.asList((Object)"all", (Object)"outside.intervals");
+
+
+ @Override
+ public void initialize() {
+ if ( getVariantEvalWalker().intervalsFile == null )
+ throw new UserException.MissingArgument("stratIntervals", "Must be provided when IntervalStratification is enabled");
+
+ final List<GenomeLoc> locs = getVariantEvalWalker().intervalsFile.getIntervals(getVariantEvalWalker().getToolkit());
+
+ if ( locs.isEmpty() )
+ throw new UserException.BadArgumentValue("stratIntervals", "Contains no intervals. Perhaps the file is malformed or empty?");
+
+ intervalTreeByContig = getVariantEvalWalker().createIntervalTreeByContig(getVariantEvalWalker().intervalsFile);
+
+ logger.info(String.format("Creating IntervalStratification %s containing %d intervals covering %d bp",
+ getVariantEvalWalker().intervalsFile.getSource(), locs.size(), IntervalUtils.intervalSize(locs)));
+
+ states.addAll(Arrays.asList("all", "overlaps.intervals", "outside.intervals"));
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ if (eval != null) {
+ final GenomeLoc loc = getVariantEvalWalker().getToolkit().getGenomeLocParser().createGenomeLoc(eval);
+ IntervalTree<GenomeLoc> intervalTree = intervalTreeByContig.get(loc.getContig());
+ IntervalTree.Node<GenomeLoc> node = intervalTree.minOverlapper(loc.getStart(), loc.getStop());
+ //logger.info(String.format("Overlap %s found %s", loc, node));
+ if ( node != null )
+ return OVERLAPPING;
+ else
+ return NOT_OVERLAPPING;
+ }
+
+ return Collections.emptyList();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/JexlExpression.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/JexlExpression.java
new file mode 100644
index 0000000..00fec2a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/JexlExpression.java
@@ -0,0 +1,69 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.util.SortableJexlVCMatchExp;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextUtils;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Set;
+
+/**
+ * Stratifies the eval RODs by user-supplied JEXL expressions
+ *
+ * See http://gatkforums.broadinstitute.org/discussion/1255/what-are-jexl-expressions-and-how-can-i-use-them-with-the-gatk for more details
+ */
+public class JexlExpression extends VariantStratifier implements StandardStratification {
+ // needs to know the jexl expressions
+ private Set<SortableJexlVCMatchExp> jexlExpressions;
+
+ @Override
+ public void initialize() {
+ jexlExpressions = getVariantEvalWalker().getJexlExpressions();
+
+ states.add("none");
+ for ( SortableJexlVCMatchExp jexlExpression : jexlExpressions ) {
+ states.add(jexlExpression.name);
+ }
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ ArrayList<Object> relevantStates = new ArrayList<Object>();
+ relevantStates.add("none");
+
+ for ( SortableJexlVCMatchExp jexlExpression : jexlExpressions ) {
+ if (eval != null && VariantContextUtils.match(eval, jexlExpression)) {
+ relevantStates.add(jexlExpression.name);
+ }
+ }
+
+ return relevantStates;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Novelty.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Novelty.java
new file mode 100644
index 0000000..0114bf2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Novelty.java
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.*;
+
+/**
+ * Stratifies by whether a site in in the list of known RODs (e.g., dbsnp by default)
+ */
+public class Novelty extends VariantStratifier implements StandardStratification {
+ // needs the variant contexts and known names
+ private List<RodBinding<VariantContext>> knowns;
+
+ private final static List<Object> KNOWN_STATES = Arrays.asList((Object)"all", (Object)"known");
+ private final static List<Object> NOVEL_STATES = Arrays.asList((Object)"all", (Object)"novel");
+
+ @Override
+ public void initialize() {
+ states.addAll(Arrays.asList("all", "known", "novel"));
+ knowns = getVariantEvalWalker().getKnowns();
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ if (tracker != null && eval != null) {
+ final Collection<VariantContext> knownComps = tracker.getValues(knowns, ref.getLocus());
+ for ( final VariantContext c : knownComps ) {
+ // loop over sites, looking for something that matches the type eval
+ if ( eval.getType() == c.getType() || eval.getType() == VariantContext.Type.NO_VARIATION ) {
+ return KNOWN_STATES;
+ }
+ }
+ }
+
+ return NOVEL_STATES;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/OneBPIndel.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/OneBPIndel.java
new file mode 100644
index 0000000..7ad45e0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/OneBPIndel.java
@@ -0,0 +1,59 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Stratifies the eval RODs into sites where the indel is 1 bp in length and those where the event is 2+.
+ * all non indel events go into all bins, so that SNP counts can be used as contrasts in eval modules.
+ */
+public class OneBPIndel extends VariantStratifier {
+ private final static List<Object> ALL = Arrays.asList((Object)"all", (Object)"one.bp", (Object)"two.plus.bp");
+ private final static List<Object> ONE_BP = Arrays.asList((Object)"all", (Object)"one.bp");
+ private final static List<Object> TWO_PLUS_BP = Arrays.asList((Object)"all", (Object)"two.plus.bp");
+
+ @Override
+ public void initialize() {
+ states.addAll(ALL);
+ }
+
+ @Override
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ if (eval != null && eval.isIndel()) {
+ for ( int l : eval.getIndelLengths() )
+ if ( Math.abs(l) > 1 )
+ return TWO_PLUS_BP; // someone is too long
+ return ONE_BP; // all lengths are one
+ } else
+ return ALL;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/RequiredStratification.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/RequiredStratification.java
new file mode 100644
index 0000000..946c723
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/RequiredStratification.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+public interface RequiredStratification {}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Sample.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Sample.java
new file mode 100644
index 0000000..bd0b6f1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/Sample.java
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.evaluators.VariantEvaluator;
+import org.broadinstitute.gatk.tools.walkers.varianteval.evaluators.VariantSummary;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.*;
+
+/**
+ * Stratifies the eval RODs by each sample in the eval ROD.
+ *
+ * This allows the system to analyze each sample separately. Since many evaluations
+ * only consider non-reference sites, stratifying by sample results in meaningful
+ * calculations for CompOverlap
+ */
+public class Sample extends VariantStratifier {
+ @Override
+ public void initialize() {
+ states.addAll(getVariantEvalWalker().getSampleNamesForStratification());
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ return Collections.singletonList((Object) sampleName);
+ }
+
+ @Override
+ public Set<Class<? extends VariantEvaluator>> getIncompatibleEvaluators() {
+ return new HashSet<Class<? extends VariantEvaluator>>(Arrays.asList(VariantSummary.class));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/SnpEffPositionModifier.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/SnpEffPositionModifier.java
new file mode 100644
index 0000000..c2ddd80
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/SnpEffPositionModifier.java
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.annotator.SnpEff;
+import org.broadinstitute.gatk.tools.walkers.annotator.SnpEff.EffectType;
+import org.broadinstitute.gatk.tools.walkers.annotator.SnpEff.InfoFieldKey;
+import org.broadinstitute.gatk.tools.walkers.annotator.SnpEffUtil;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Stratifies variants as genes or coding regions, according to the effect modifier, as indicated by snpEff.
+ * The 'gene' category includes category 'coding region', and additionally includes introns. 'Coding regions'
+ * includes transcripts and, implicitly, UTRs.
+ */
+public class SnpEffPositionModifier extends VariantStratifier {
+
+ public enum PositionModifier {
+ GENE, // EXON
+ CODING_REGION, // CDS
+ SPLICE_SITE, // not a straight translation -- see getRelevantStates
+ STOP_GAINED, // STOP_GAINED
+ STOP_LOST // STOP_LOST
+ }
+
+ @Override
+ public void initialize() {
+ for (final PositionModifier type : PositionModifier.values()) states.add(type.name());
+ }
+
+ @Override
+ public List<Object> getRelevantStates(
+ final ReferenceContext ref,
+ final RefMetaDataTracker tracker,
+ final VariantContext comp,
+ final String compName,
+ final VariantContext eval,
+ final String evalName,
+ final String sampleName)
+ {
+ final List<Object> relevantStates = new ArrayList<Object>();
+ if (eval != null && eval.isVariant() && eval.hasAttribute(InfoFieldKey.EFFECT_KEY.getKeyName())) {
+ final SnpEff.EffectType effectType = SnpEff.EffectType.valueOf(
+ eval.getAttribute(InfoFieldKey.EFFECT_KEY.getKeyName()).toString());
+
+ if (SnpEffUtil.isSubTypeOf(effectType, EffectType.EXON)) relevantStates.add(PositionModifier.GENE.name());
+ if (SnpEffUtil.isSubTypeOf(effectType, EffectType.CDS)) relevantStates.add(PositionModifier.CODING_REGION.name());
+ if (SnpEffUtil.isSubTypeOf(effectType, EffectType.STOP_GAINED)) relevantStates.add(PositionModifier.STOP_GAINED.name());
+ if (SnpEffUtil.isSubTypeOf(effectType, EffectType.STOP_LOST)) relevantStates.add(PositionModifier.STOP_LOST.name());
+
+ if (SnpEffUtil.isSubTypeOf(effectType, EffectType.SPLICE_SITE_ACCEPTOR) ||
+ SnpEffUtil.isSubTypeOf(effectType, EffectType.SPLICE_SITE_DONOR))
+ relevantStates.add(PositionModifier.SPLICE_SITE.name());
+ }
+
+ return relevantStates;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/StandardStratification.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/StandardStratification.java
new file mode 100644
index 0000000..41c52c2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/StandardStratification.java
@@ -0,0 +1,29 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+public interface StandardStratification {
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/TandemRepeat.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/TandemRepeat.java
new file mode 100644
index 0000000..6eba4b4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/TandemRepeat.java
@@ -0,0 +1,67 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Stratifies the eval RODs into sites that are tandem repeats
+ */
+public class TandemRepeat extends VariantStratifier {
+ private final static List<Object> JUST_ALL = Arrays.asList((Object)"all");
+ private final static List<Object> ALL = Arrays.asList((Object)"all", (Object)"is.repeat", (Object)"not.repeat");
+ private final static List<Object> REPEAT = Arrays.asList((Object)"all", (Object)"is.repeat");
+ private final static List<Object> NOT_REPEAT = Arrays.asList((Object)"all", (Object)"not.repeat");
+
+ @Override
+ public void initialize() {
+ states.addAll(ALL);
+ }
+
+ @Override
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ if ( eval == null || ! eval.isIndel() )
+ return ALL;
+ else if ( GATKVariantContextUtils.isTandemRepeat(eval, ref.getForwardBases()) ) {
+ print("REPEAT", eval, ref);
+ return REPEAT;
+ } else {
+ print("NOT A REPEAT", eval, ref);
+ return NOT_REPEAT;
+ }
+ }
+
+ private final void print(String prefix, VariantContext eval, ReferenceContext ref) {
+// String alleles = ParsingUtils.sortList(eval.getAlleles()).toString();
+// this.getVariantEvalWalker().getLogger().info(prefix + ": " + "pos=" + eval.getStart() + " alleles=" + alleles + " ref=" + new String(ref.getForwardBases()));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/VariantStratifier.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/VariantStratifier.java
new file mode 100644
index 0000000..0832ebd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/VariantStratifier.java
@@ -0,0 +1,110 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.VariantEval;
+import org.broadinstitute.gatk.tools.walkers.varianteval.evaluators.VariantEvaluator;
+import org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.manager.Stratifier;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public abstract class VariantStratifier implements Comparable<VariantStratifier>, Stratifier {
+ private VariantEval variantEvalWalker;
+ final private String name;
+ final protected ArrayList<Object> states = new ArrayList<Object>();
+
+ protected VariantStratifier() {
+ name = this.getClass().getSimpleName();
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // to be overloaded
+ //
+ // -------------------------------------------------------------------------------------
+
+ public abstract void initialize();
+
+ public abstract List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName);
+
+ // -------------------------------------------------------------------------------------
+ //
+ // final capabilities
+ //
+ // -------------------------------------------------------------------------------------
+
+ /**
+ * @return a reference to the parent VariantEvalWalker running this stratification
+ */
+ public final VariantEval getVariantEvalWalker() {
+ return variantEvalWalker;
+ }
+
+ /**
+ * Should only be called by VariantEvalWalker itself
+ * @param variantEvalWalker
+ */
+ public final void setVariantEvalWalker(VariantEval variantEvalWalker) {
+ this.variantEvalWalker = variantEvalWalker;
+ }
+
+ public final int compareTo(VariantStratifier o1) {
+ return this.getName().compareTo(o1.getName());
+ }
+
+ @Override
+ public String toString() {
+ return getName();
+ }
+
+ public final String getName() {
+ return name;
+ }
+
+ public String getFormat() { return "%s"; }
+
+ public final ArrayList<Object> getAllStates() {
+ return states;
+ }
+
+
+ /**
+ * The way for a stratifier to specify that it's incompatible with specific evaluations. For
+ * example, VariantSummary includes a per-sample metric, and so cannot be used safely with Sample
+ * or AlleleCount stratifications as this introduces an O(n^2) memory and cpu cost.
+ *
+ * @return the set of VariantEvaluators that cannot be active with this Stratification
+ */
+ public Set<Class<? extends VariantEvaluator>> getIncompatibleEvaluators() {
+ return Collections.emptySet();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/VariantType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/VariantType.java
new file mode 100644
index 0000000..0ba5b60
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/VariantType.java
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Stratifies the eval variants by their type (SNP, INDEL, ETC)
+ */
+public class VariantType extends VariantStratifier {
+ @Override
+ public void initialize() {
+ for (VariantContext.Type t : VariantContext.Type.values())
+ states.add(t.toString());
+ }
+
+ public List<Object> getRelevantStates(ReferenceContext ref, RefMetaDataTracker tracker, VariantContext comp, String compName, VariantContext eval, String evalName, String sampleName) {
+ return eval == null ? Collections.emptyList() : Collections.singletonList((Object)eval.getType().toString());
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/StratNode.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/StratNode.java
new file mode 100644
index 0000000..0db9370
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/StratNode.java
@@ -0,0 +1,166 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.manager;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Invariant;
+import com.google.java.contract.Requires;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ * Helper class representing a tree of stratification splits, where leaf nodes
+ * are given a unique integer key starting at 0 and incrementing up to the
+ * number of leaves in the tree. This allows you to use this tree to produce
+ * a key to map into an array index mapped data structure.
+ *
+ * Suppose I have to strats, each with two values: A = 1, 2 and B = 3, 4
+ *
+ * This data structure creates a tree such as:
+ *
+ * root -> A -> 1 -> B -> 3 : 0
+ * |- B -> 4 : 1
+ * |- A -> 2 -> B -> 3 : 2
+ * |- B -> 4 : 3
+ *
+ * This code allows us to efficiently look up a state key (A=2, B=3) and map it
+ * to a specific key (an integer) that's unique over the tree
+ *
+ * Note the structure of this tree is that the keys are -1 for all internal nodes, and
+ * leafs are the only nodes with meaningful keys. So for a tree with 2N nodes N of these
+ * will be internal, with no keys, and meaningful maps from states -> subtrees. The
+ * other N nodes are leafs, with meaningful keys, empty maps, and null stratification objects
+ *
+ * @author Mark DePristo
+ * @since 3/27/12
+ */
+ at Invariant({
+ "(isLeaf() && stratifier == null && subnodes.isEmpty()) || (!isLeaf() && stratifier != null && !subnodes.isEmpty())"})
+class StratNode<T extends Stratifier> implements Iterable<StratNode<T>> {
+ int key = -1;
+ final T stratifier;
+ final Map<Object, StratNode<T>> subnodes; // NOTE, because we don't iterate our best option is a HashMap
+
+ protected StratNode() {
+ this.subnodes = Collections.emptyMap();
+ this.stratifier = null;
+ }
+
+ protected StratNode(final T stratifier, final Map<Object, StratNode<T>> subnodes) {
+ this.stratifier = stratifier;
+ // important to reallocate an unmodififable hashmap with this specific size for space and safety
+ this.subnodes = Collections.unmodifiableMap(new HashMap<Object, StratNode<T>>(subnodes));
+ }
+
+ @Requires("key >= 0")
+ public void setKey(final int key) {
+ if ( ! isLeaf() )
+ throw new ReviewedGATKException("Cannot set key of non-leaf node");
+ this.key = key;
+ }
+
+ @Requires({
+ "states != null",
+ "offset >= 0",
+ "offset <= states.size()"
+ })
+ public int find(final List<Object> states, int offset) {
+ if ( isLeaf() ) // we're here!
+ return key;
+ else {
+ final Object state = states.get(offset);
+ StratNode<T> subnode = subnodes.get(state);
+ if ( subnode == null )
+ return -1;
+ else
+ return subnode.find(states, offset+1);
+ }
+ }
+
+ @Requires({
+ "multipleStates != null",
+ "offset >= 0",
+ "offset <= multipleStates.size()",
+ "keys != null",
+ "offset == multipleStates.size() || multipleStates.get(offset) != null"})
+ public void find(final List<List<Object>> multipleStates, final int offset, final HashSet<Integer> keys) {
+ if ( isLeaf() ) // we're here!
+ keys.add(key);
+ else {
+ for ( final Object state : multipleStates.get(offset) ) {
+ // loop over all of the states at this offset
+ final StratNode<T> subnode = subnodes.get(state);
+ if ( subnode == null )
+ throw new ReviewedGATKException("Couldn't find state for " + state + " at node " + this);
+ else
+ subnode.find(multipleStates, offset+1, keys);
+ }
+ }
+ }
+
+ @Ensures("result >= 0")
+ public int getKey() {
+ if ( ! isLeaf() )
+ throw new ReviewedGATKException("Cannot get key of non-leaf node");
+ else
+ return key;
+ }
+
+ protected Map<Object, StratNode<T>> getSubnodes() {
+ return subnodes;
+ }
+
+ @Ensures("result >= 0")
+ public int size() {
+ if ( isLeaf() )
+ return 1;
+ else {
+ return subnodes.values().iterator().next().size() * subnodes.size();
+ }
+ }
+
+ public T getSetOfStates() {
+ return stratifier;
+ }
+
+ /**
+ * @return true if this node is a leaf
+ */
+ public boolean isLeaf() {
+ return stratifier == null;
+ }
+
+ /**
+ * Returns an iterator over this node and all subnodes including internal and leaf nodes
+ * @return
+ */
+ @Override
+ @Ensures("result != null")
+ public Iterator<StratNode<T>> iterator() {
+ return new StratNodeIterator<T>(this);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/StratNodeIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/StratNodeIterator.java
new file mode 100644
index 0000000..a789b70
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/StratNodeIterator.java
@@ -0,0 +1,69 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.manager;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ * Helper class for creating iterators over all nodes in the stratification tree
+ *
+ * @author Mark DePristo
+ * @since 3/27/12
+ */
+class StratNodeIterator<T extends Stratifier> implements Iterator<StratNode<T>> {
+ Queue<Iterator<StratNode<T>>> iterators = new LinkedList<Iterator<StratNode<T>>>();
+ Iterator<StratNode<T>> currentIterator;
+
+ StratNodeIterator(final StratNode<T> root) {
+ currentIterator = Collections.singleton(root).iterator();
+ for ( final StratNode<T> subNode : root.subnodes.values() )
+ iterators.add(new StratNodeIterator<T>(subNode));
+ }
+
+ @Override
+ public boolean hasNext() {
+ return currentIterator.hasNext() || ! iterators.isEmpty();
+ }
+
+ @Override
+ public StratNode<T> next() {
+ if ( currentIterator.hasNext() )
+ return currentIterator.next();
+ else if ( ! iterators.isEmpty() ) {
+ currentIterator = iterators.poll();
+ return next();
+ } else {
+ throw new IllegalStateException("Next called on empty iterator");
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new ReviewedGATKException("Cannot remove from StratNode iterator");
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/StratificationManager.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/StratificationManager.java
new file mode 100644
index 0000000..7290016
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/StratificationManager.java
@@ -0,0 +1,426 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.manager;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ * Represents the full state space of all stratification combinations
+ *
+ * @author Mark DePristo
+ * @since 3/27/12
+ */
+public class StratificationManager<K extends Stratifier, V> implements Map<List<Object>, V> {
+ private final StratNode<K> root;
+ private final int size;
+
+ private final ArrayList<K> stratifiers;
+
+ // values associated with each key
+ private final ArrayList<V> valuesByKey;
+ private final ArrayList<List<Object>> stratifierValuesByKey;
+ private final ArrayList<String> keyStrings;
+
+ // -------------------------------------------------------------------------------------
+ //
+ // creating the manager
+ //
+ // -------------------------------------------------------------------------------------
+
+ /**
+ * Create a new StratificationManager with nodes to store data for all combinations
+ * of the ordered list of strats
+ *
+ * @param strats ordered list of stratifications to representation
+ */
+ @Requires("!strats.isEmpty()")
+ public StratificationManager(final List<K> strats) {
+ this.stratifiers = new ArrayList<K>(strats);
+
+ // construct and store the full tree of strats
+ this.root = buildStratificationTree(new LinkedList<K>(strats));
+ // assign the linear key ordering to the leafs
+ assignKeys(root);
+
+ // cache the size, and check for a bad state
+ this.size = root.size();
+ if ( this.size == 0 )
+ throw new ReviewedGATKException("Size == 0 in StratificationManager");
+
+ // prepare the assocated data vectors mapping from key -> data
+ this.valuesByKey = new ArrayList<V>(size());
+ this.stratifierValuesByKey = new ArrayList<List<Object>>(size());
+ this.keyStrings = new ArrayList<String>(size());
+ for ( int i = 0; i < size(); i++ ) {
+ this.valuesByKey.add(null);
+ this.stratifierValuesByKey.add(null);
+ this.keyStrings.add(null);
+ }
+
+ assignStratifierValuesByKey(root);
+ }
+
+ /**
+ * Recursive construction helper for main constructor that fills into the
+ * complete tree of StratNodes. This function returns the complete tree
+ * suitable for associating data with each combinatino of keys. Note
+ * that the tree is not fully complete as the keys are not yet set for
+ * each note (see assignStratifierValuesByKey)
+ *
+ * @param strats
+ * @return
+ */
+ private StratNode<K> buildStratificationTree(final Queue<K> strats) {
+ final K first = strats.poll();
+ if ( first == null ) {
+ // we are at a leaf
+ return new StratNode<K>();
+ } else {
+ // we are in the middle of the tree
+ final Collection<Object> states = first.getAllStates();
+
+ if ( states.isEmpty() )
+ throw new ReviewedGATKException("State " + first + " is empty!");
+
+ final LinkedHashMap<Object, StratNode<K>> subNodes = new LinkedHashMap<Object, StratNode<K>>(states.size());
+ for ( final Object state : states ) {
+ // have to copy because poll modifies the queue
+ final Queue<K> copy = new LinkedList<K>(strats);
+ subNodes.put(state, buildStratificationTree(copy));
+ }
+ return new StratNode<K>(first, subNodes);
+ }
+ }
+
+ /**
+ * Set the key for each leaf from root, in order from 0 to N - 1 for N leaves in the tree
+ * @param root
+ */
+ @Requires("root == this.root")
+ private void assignKeys(final StratNode<K> root) {
+ int key = 0;
+ for ( final StratNode<K> node : root ) {
+ if ( node.isLeaf() )
+ node.setKey(key++);
+ }
+ }
+
+ /**
+ * Entry point to recursive tool that fills in the list of state values corresponding
+ * to each key. After this function is called you can map from key -> List of StateValues
+ * instead of walking the tree to find the key and reading the list of state values
+ *
+ * @param root
+ */
+ private void assignStratifierValuesByKey(final StratNode<K> root) {
+ assignStratifierValuesByKey(root, new LinkedList<Object>());
+
+ // do a last sanity check that no key has null value after assigning
+ for ( List<Object> stateValues : stratifierValuesByKey )
+ if ( stateValues == null )
+ throw new ReviewedGATKException("Found a null state value set that's null");
+ }
+
+ private void assignStratifierValuesByKey(final StratNode<K> node, final LinkedList<Object> states) {
+ if ( node.isLeaf() ) { // we're here!
+ if ( states.isEmpty() )
+ throw new ReviewedGATKException("Found a leaf node with an empty state values vector");
+ stratifierValuesByKey.set(node.getKey(), Collections.unmodifiableList(new ArrayList<Object>(states)));
+ } else {
+ for ( Map.Entry<Object, StratNode<K>> entry : node.getSubnodes().entrySet() ) {
+ final LinkedList<Object> newStates = new LinkedList<Object>(states);
+ newStates.addLast(entry.getKey());
+ assignStratifierValuesByKey(entry.getValue(), newStates);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // simple accessors
+ //
+ // -------------------------------------------------------------------------------------
+
+ /**
+ * How many states are held in this stratification manager?
+ * @return
+ */
+ @Ensures("result >= 0")
+ public int size() {
+ return size;
+ }
+
+ @Ensures("result != null")
+ protected StratNode<K> getRoot() {
+ return root;
+ }
+
+ @Ensures("result != null")
+ public List<K> getStratifiers() {
+ return stratifiers;
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // mapping from states -> keys
+ //
+ // -------------------------------------------------------------------------------------
+
+ @Requires("states != null")
+ @Ensures("result >= -1")
+ public int getKey(final List<Object> states) {
+ return root.find(states, 0);
+ }
+
+ @Requires("allStates != null")
+ @Ensures("result != null")
+ public Set<Integer> getKeys(final List<List<Object>> allStates) {
+ final HashSet<Integer> keys = new HashSet<Integer>();
+ root.find(allStates, 0, keys);
+ return keys;
+ }
+
+ public List<Object> getStatesForKey(final int key) {
+ final List<Object> states = new ArrayList<Object>(stratifiers.size());
+ for ( int i = 0; i < stratifiers.size(); i++ ) {
+ final Object stratValue = stratifierValuesByKey.get(key).get(i);
+ states.add(stratValue);
+ }
+ return states;
+ }
+
+ public List<Pair<K, Object>> getStratsAndStatesForKey(final int key) {
+ final List<Pair<K, Object>> states = new ArrayList<Pair<K, Object>>(stratifiers.size());
+ for ( int i = 0; i < stratifiers.size(); i++ ) {
+ final K strat = stratifiers.get(i);
+ final Object stratValue = stratifierValuesByKey.get(key).get(i);
+ states.add(new Pair<K, Object>(strat, stratValue));
+ }
+ return states;
+ }
+
+ public String getStratsAndStatesStringForKey(final int key) {
+ if ( keyStrings.get(key) == null ) {
+ StringBuilder b = new StringBuilder();
+ for ( int i = 0; i < stratifiers.size(); i++ ) {
+ final K strat = stratifiers.get(i);
+ final Object stratValue = stratifierValuesByKey.get(key).get(i);
+ b.append(strat.toString()).append(":").append(stratValue.toString());
+ }
+ keyStrings.set(key, b.toString());
+ }
+
+ return keyStrings.get(key);
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // valuesByKey
+ //
+ // -------------------------------------------------------------------------------------
+
+ @Override
+ @Ensures("result != null")
+ public ArrayList<V> values() {
+ return valuesByKey;
+ }
+
+ public Collection<V> values(List<List<Object>> states) {
+ // TODO -- SHOULD BE INLINE TO AVOID CREATING LIST OF KEYS JUST TO ITERATE OVER IT
+ Collection<V> vals = new LinkedList<V>();
+ for ( int key : getKeys(states) )
+ vals.add(get(key));
+ return vals;
+ }
+
+ @Requires("key >= 0 && key <= size()")
+ @Ensures("get(key) == value")
+ public void set(final int key, final V value) {
+ valuesByKey.set(key, value);
+ }
+
+ @Requires("key >= 0 && key <= size()")
+ public V get(final int key) {
+ return valuesByKey.get(key);
+ }
+
+ @Requires("getKey(states) != -1")
+ public V get(final List<Object> states) {
+ return get(getKey(states));
+ }
+
+ @Override
+ public V get(final Object o) {
+ return get((List<Object>)o);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ public boolean containsKey(final List<Object> o) {
+ return getKey(o) != -1;
+ }
+
+ @Override
+ public boolean containsKey(final Object o) {
+ return containsKey((List<Object>)o);
+ }
+
+ @Override
+ public boolean containsValue(final Object o) {
+ throw new ReviewedGATKException("containsValue() not implemented for StratificationManager");
+ }
+
+ @Override
+ public V put(final List<Object> objects, final V v) {
+ throw new ReviewedGATKException("put() not implemented for StratificationManager");
+ }
+
+ @Override
+ public V remove(final Object o) {
+ throw new ReviewedGATKException("remove() not implemented for StratificationManager");
+ }
+
+ @Override
+ public void putAll(final Map<? extends List<Object>, ? extends V> map) {
+ throw new ReviewedGATKException("clear() not implemented for StratificationManager");
+ }
+
+ @Override
+ public void clear() {
+ throw new ReviewedGATKException("clear() not implemented for StratificationManager");
+ }
+
+ @Override
+ public Set<List<Object>> keySet() {
+ throw new ReviewedGATKException("Not yet implemented");
+ }
+
+ @Override
+ public Set<Entry<List<Object>, V>> entrySet() {
+ throw new ReviewedGATKException("Not yet implemented");
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // utilities
+ //
+ // -------------------------------------------------------------------------------------
+
+ public static List<List<Object>> combineStates(final List<Object> first, final List<Object> second) {
+ final List<List<Object>> combined = new ArrayList<List<Object>>(first.size());
+ for ( int i = 0; i < first.size(); i++ ) {
+ final Object firstI = first.get(i);
+ final Object secondI = second.get(i);
+ if ( firstI.equals(secondI) )
+ combined.add(Collections.singletonList(firstI));
+ else
+ combined.add(Arrays.asList(firstI, secondI));
+ }
+ return combined;
+ }
+
+ public interface Combiner<V> {
+ /** take two values of type V and return a combined value of type V */
+ public V combine(final V lhs, final V rhs);
+ }
+
+ /**
+ * Remaps the stratifications from one stratification set to another, combining
+ * the values in V according to the combiner function.
+ *
+ * stratifierToReplace defines a set of states S1, while newStratifier defines
+ * a new set S2. remappedStates is a map from all of S1 into at least some of
+ * S2. This function creates a new, fully initialized manager where all of the
+ * data in this new manager is derived from the original data in this object
+ * combined according to the mapping remappedStates. When multiple
+ * elements of S1 can map to the same value in S2, these are sequentially
+ * combined by the function combiner. Suppose for example at states s1, s2, and
+ * s3 all map to N1. Eventually the value associated with state N1 would be
+ *
+ * value(N1) = combine(value(s1), combine(value(s2), value(s3))
+ *
+ * in some order for s1, s2, and s3, which is not defined. Note that this function
+ * only supports combining one stratification at a time, but in principle a loop over
+ * stratifications and this function could do the multi-dimensional collapse.
+ *
+ * @param stratifierToReplace
+ * @param newStratifier
+ * @param combiner
+ * @param remappedStates
+ * @return
+ */
+ public StratificationManager<K, V> combineStrats(final K stratifierToReplace,
+ final K newStratifier,
+ final Combiner<V> combiner,
+ final Map<Object, Object> remappedStates) {
+ // make sure the mapping is reasonable
+ if ( ! newStratifier.getAllStates().containsAll(remappedStates.values()) )
+ throw new ReviewedGATKException("combineStrats: remapped states contains states not found in newStratifer state set");
+
+ if ( ! remappedStates.keySet().containsAll(stratifierToReplace.getAllStates()) )
+ throw new ReviewedGATKException("combineStrats: remapped states missing mapping for some states");
+
+ // the new strats are the old ones with the single replacement
+ final List<K> newStrats = new ArrayList<K>(getStratifiers());
+ final int stratOffset = newStrats.indexOf(stratifierToReplace);
+ if ( stratOffset == -1 )
+ throw new ReviewedGATKException("Could not find strat to replace " + stratifierToReplace + " in existing strats " + newStrats);
+ newStrats.set(stratOffset, newStratifier);
+
+ // create an empty but fully initialized new manager
+ final StratificationManager<K, V> combined = new StratificationManager<K, V>(newStrats);
+
+ // for each key, get its state, update it according to the map, and update the combined manager
+ for ( int key = 0; key < size(); key++ ) {
+ // the new state is just the old one with the replacement
+ final List<Object> newStates = new ArrayList<Object>(getStatesForKey(key));
+ final Object oldState = newStates.get(stratOffset);
+ final Object newState = remappedStates.get(oldState);
+ newStates.set(stratOffset, newState);
+
+ // look up the new key given the new state
+ final int combinedKey = combined.getKey(newStates);
+ if ( combinedKey == -1 ) throw new ReviewedGATKException("Couldn't find key for states: " + Utils.join(",", newStates));
+
+ // combine the old value with whatever new value is in combined already
+ final V combinedValue = combiner.combine(combined.get(combinedKey), get(key));
+
+ // update the value associated with combined key
+ combined.set(combinedKey, combinedValue);
+ }
+
+ return combined;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/Stratifier.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/Stratifier.java
new file mode 100644
index 0000000..b096db9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/stratifications/manager/Stratifier.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.manager;
+
+import java.util.List;
+
+/**
+ * A basic interface for a class to be used with the StratificationManager system
+ *
+ * @author Mark DePristo
+ * @since 3/28/12
+ */
+public interface Stratifier<Object> {
+ /**
+ * @return a list of all objects states that may be provided by this States provider
+ */
+ public List<Object> getAllStates();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/Analysis.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/Analysis.java
new file mode 100644
index 0000000..67dc187
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/Analysis.java
@@ -0,0 +1,36 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.util;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+ at Retention(RetentionPolicy.RUNTIME)
+public @interface Analysis {
+ String name() default ""; // its description, required
+ String description(); // its description, required
+ boolean molten() default false; // if true we'll look for a @Molten map
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/AnalysisModuleScanner.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/AnalysisModuleScanner.java
new file mode 100644
index 0000000..411394b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/AnalysisModuleScanner.java
@@ -0,0 +1,154 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.util;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+
+/**
+ * @author aaron
+ * <p/>
+ * Class AnalysisModuleScanner
+ * <p/>
+ * Given an analysis, find the annotated fields and methods. Given this module and
+ * the object, a Mashalling object can serialize or deserialize a analysis module.
+ */
+public class AnalysisModuleScanner {
+ final private static Map<String, Annotation[]> annotationCache = new HashMap<String, Annotation[]>();
+
+ // what we extracted from the class
+ private Map<Field, DataPoint> datums = new LinkedHashMap<Field, DataPoint>(); // the data we've discovered
+ private Analysis analysis; // the analysis annotation
+
+ private Field moltenField = null;
+ private Molten moltenAnnotation = null;
+
+ // private storage of the class type
+ private final Class cls;
+
+ /**
+ * create a report scanner from the passed in class
+ * @param cls the target class, annotated with the @Analysis annotation
+ */
+ public AnalysisModuleScanner(Class cls) {
+ this.cls = cls;
+ scan(); // scan the passed in class
+ }
+
+ /**
+ * create a report scanner from the passed in class
+ * @param obj the target object, annotated with the @Analysis annotation
+ */
+ public AnalysisModuleScanner(Object obj) {
+ this.cls = obj.getClass();
+ scan(); // scan the passed in class
+ }
+
+ /** scan the class and find all appropriate fields and tables */
+ public void scan() {
+ if (cls == null || !cls.isAnnotationPresent(Analysis.class))
+ throw new ReviewedGATKException("The class passed in cannot be null, " + "" +
+ "and must contain the @Analysis annotation, class " + cls + " was the input");
+
+ // get the annotation off of the class
+ analysis = (Analysis) cls.getAnnotation(Analysis.class);
+ scanFields();
+ }
+
+ /**
+ * scan the fields of the class, extracting parameters and table annotations and their associated fields
+ */
+ private void scanFields() {
+ // get the fields from the class, and extract
+ for ( Class superCls = cls; superCls != null; superCls=superCls.getSuperclass() ) {
+ for (Field f : superCls.getDeclaredFields()) {
+ for (Annotation annotation : getAnnotations(f)) {
+ if (annotation.annotationType().equals(DataPoint.class))
+ datums.put(f,(DataPoint) annotation);
+ if ( annotation.annotationType().equals(Molten.class)) {
+ if ( hasMoltenField() )
+ throw new ReviewedGATKException("Analysis " + analysis.name() + " has multiple @Molten fields, which is forbidden");
+ moltenField = f;
+ moltenAnnotation = (Molten)annotation;
+ }
+ }
+ }
+ }
+
+ if ( hasMoltenField() ) {
+ if ( datums.size() > 0 )
+ throw new ReviewedGATKException("Analysis " + analysis.name() + " has an @Molten field as well as @DataPoint fields, which is forbidden");
+ }
+ }
+
+ public Field getMoltenField() {
+ return moltenField;
+ }
+
+ public Molten getMoltenAnnotation() {
+ return moltenAnnotation;
+ }
+
+ public boolean hasMoltenField() {
+ return getMoltenField() != null;
+ }
+
+ private Annotation[] getAnnotations(final Field field) {
+ final String fieldName = field.toString();
+ Annotation[] annotations = annotationCache.get(fieldName);
+ if ( annotations == null ) {
+ annotations = field.getAnnotations();
+ annotationCache.put(fieldName, annotations);
+ }
+ return annotations;
+ }
+
+ /**
+ *
+ * @return a map of the datum annotations found
+ */
+ public Map<Field, DataPoint> getData() {
+ return datums;
+ }
+
+ /**
+ *
+ * @return the analysis annotation found
+ */
+ public Analysis getAnalysis() {
+ return analysis;
+ }
+
+ public Class getModuleClass() {
+ return cls;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/DataPoint.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/DataPoint.java
new file mode 100644
index 0000000..0805cb5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/DataPoint.java
@@ -0,0 +1,35 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.util;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+ at Retention(RetentionPolicy.RUNTIME)
+public @interface DataPoint {
+ String description() default ""; // the description, optional
+ String format() default "";
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/EvaluationContext.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/EvaluationContext.java
new file mode 100644
index 0000000..7e9f2da
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/EvaluationContext.java
@@ -0,0 +1,115 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.util;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.VariantEval;
+import org.broadinstitute.gatk.tools.walkers.varianteval.evaluators.VariantEvaluator;
+import org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.manager.StratificationManager;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.TreeSet;
+
+public final class EvaluationContext {
+ // NOTE: must be hashset to avoid O(log n) cost of iteration in the very frequently called apply function
+ final VariantEval walker;
+ private final ArrayList<VariantEvaluator> evaluationInstances;
+ private final Set<Class<? extends VariantEvaluator>> evaluationClasses;
+
+ public EvaluationContext(final VariantEval walker, final Set<Class<? extends VariantEvaluator>> evaluationClasses) {
+ this(walker, evaluationClasses, true);
+ }
+
+ private EvaluationContext(final VariantEval walker, final Set<Class<? extends VariantEvaluator>> evaluationClasses, final boolean doInitialize) {
+ this.walker = walker;
+ this.evaluationClasses = evaluationClasses;
+ this.evaluationInstances = new ArrayList<VariantEvaluator>(evaluationClasses.size());
+
+ for ( final Class<? extends VariantEvaluator> c : evaluationClasses ) {
+ try {
+ final VariantEvaluator eval = c.newInstance();
+ if ( doInitialize ) eval.initialize(walker);
+ evaluationInstances.add(eval);
+ } catch (InstantiationException e) {
+ throw new ReviewedGATKException("Unable to instantiate eval module '" + c.getSimpleName() + "'", e);
+ } catch (IllegalAccessException e) {
+ throw new ReviewedGATKException("Illegal access error when trying to instantiate eval module '" + c.getSimpleName() + "'", e);
+ }
+ }
+ }
+
+ /**
+ * Returns a sorted set of VariantEvaluators
+ *
+ * @return
+ */
+ public final TreeSet<VariantEvaluator> getVariantEvaluators() {
+ return new TreeSet<VariantEvaluator>(evaluationInstances);
+ }
+
+ public final void apply(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context, VariantContext comp, VariantContext eval) {
+ for ( final VariantEvaluator evaluation : evaluationInstances ) {
+ // the other updateN methods don't see a null context
+ if ( tracker == null )
+ continue;
+
+ // now call the single or paired update function
+ switch ( evaluation.getComparisonOrder() ) {
+ case 1:
+ if (eval != null) {
+ evaluation.update1(eval, tracker, ref, context);
+ }
+ break;
+ case 2:
+ evaluation.update2(eval, comp, tracker, ref, context);
+ break;
+ default:
+ throw new ReviewedGATKException("BUG: Unexpected evaluation order " + evaluation);
+ }
+ }
+ }
+
+ public void combine(final EvaluationContext rhs) {
+ for ( int i = 0; i < evaluationInstances.size(); i++ )
+ evaluationInstances.get(i).combine(rhs.evaluationInstances.get(i));
+ }
+
+ public final static EvaluationContextCombiner COMBINER = new EvaluationContext.EvaluationContextCombiner();
+ private static class EvaluationContextCombiner implements StratificationManager.Combiner<EvaluationContext> {
+ @Override
+ public EvaluationContext combine(EvaluationContext lhs, final EvaluationContext rhs) {
+ if ( lhs == null )
+ lhs = new EvaluationContext(rhs.walker, rhs.evaluationClasses, false);
+ lhs.combine(rhs);
+ return lhs;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/Molten.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/Molten.java
new file mode 100644
index 0000000..57c4fbc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/Molten.java
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.util;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Molten for @Analysis modules.
+ *
+ * If you are flagged as a molten analysis, then there must be one and
+ * only one annotation in that evaluation module: @Molten which
+ * must have time Map<Object, Object>. This data set will then
+ * be represented in the VE output as:
+ *
+ * variable value
+ * key1 value1
+ * key2 value1
+ * ...
+ * keyN valueN
+ *
+ * in the output table. The names of these two fields can be override via annotation values.
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+public @interface Molten {
+ String description() default ""; // the description, optional
+
+ /**
+ * The name to use for the molten variable field in the output table.
+ * @return
+ */
+ String variableName() default "variable";
+ String variableFormat() default "";
+
+ /**
+ * The name to use for the molten value field in the output table.
+ * @return
+ */
+ String valueName() default "value";
+ String valueFormat() default "";
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/SortableJexlVCMatchExp.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/SortableJexlVCMatchExp.java
new file mode 100644
index 0000000..a759eb2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/SortableJexlVCMatchExp.java
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.util;
+
+import org.apache.commons.jexl2.Expression;
+import htsjdk.variant.variantcontext.VariantContextUtils;
+
+public class SortableJexlVCMatchExp extends VariantContextUtils.JexlVCMatchExp implements Comparable<SortableJexlVCMatchExp> {
+ /**
+ * Create a new matcher expression with name and JEXL expression exp
+ *
+ * @param name name
+ * @param exp expression
+ */
+ public SortableJexlVCMatchExp(String name, Expression exp) {
+ super(name, exp);
+ }
+
+ public int compareTo(SortableJexlVCMatchExp sortableJexlVCMatchExp) {
+ return this.name.compareTo(sortableJexlVCMatchExp.name);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/VariantEvalUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/VariantEvalUtils.java
new file mode 100644
index 0000000..6f623d4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/varianteval/util/VariantEvalUtils.java
@@ -0,0 +1,311 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.varianteval.util;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.tools.walkers.varianteval.VariantEval;
+import org.broadinstitute.gatk.tools.walkers.varianteval.evaluators.StandardEval;
+import org.broadinstitute.gatk.tools.walkers.varianteval.evaluators.VariantEvaluator;
+import org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.RequiredStratification;
+import org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.StandardStratification;
+import org.broadinstitute.gatk.tools.walkers.varianteval.stratifications.VariantStratifier;
+import org.broadinstitute.gatk.utils.classloader.PluginManager;
+import htsjdk.variant.vcf.VCFConstants;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+import htsjdk.variant.variantcontext.VariantContextUtils;
+
+import java.util.*;
+
+public class VariantEvalUtils {
+ private final VariantEval variantEvalWalker;
+ Logger logger;
+
+ public VariantEvalUtils(VariantEval variantEvalWalker) {
+ this.variantEvalWalker = variantEvalWalker;
+ this.logger = variantEvalWalker.getLogger();
+ }
+
+ /**
+ * List all of the available evaluation modules, then exit successfully
+ */
+ public void listModulesAndExit() {
+ List<Class<? extends VariantStratifier>> vsClasses = new PluginManager<VariantStratifier>(VariantStratifier.class).getPlugins();
+ List<Class<? extends VariantEvaluator>> veClasses = new PluginManager<VariantEvaluator>(VariantEvaluator.class).getPlugins();
+
+ logger.info("Available stratification modules:");
+ logger.info("(Standard modules are starred)");
+ for (Class<? extends VariantStratifier> vsClass : vsClasses) {
+ logger.info("\t" + vsClass.getSimpleName() + (RequiredStratification.class.isAssignableFrom(vsClass) || StandardStratification.class.isAssignableFrom(vsClass) ? "*" : ""));
+ }
+ logger.info("");
+
+ logger.info("Available evaluation modules:");
+ logger.info("(Standard modules are starred)");
+ for (Class<? extends VariantEvaluator> veClass : veClasses) {
+ logger.info("\t" + veClass.getSimpleName() + (StandardEval.class.isAssignableFrom(veClass) ? "*" : ""));
+ }
+ logger.info("");
+
+ System.exit(0);
+ }
+
+ /**
+ * Initialize required, standard and user-specified stratification objects
+ *
+ * @param noStandardStrats don't use the standard stratifications
+ * @param modulesToUse the list of stratification modules to use
+ * @return set of stratifications to use
+ */
+ public List<VariantStratifier> initializeStratificationObjects(boolean noStandardStrats, String[] modulesToUse) {
+ TreeSet<VariantStratifier> strats = new TreeSet<VariantStratifier>();
+ Set<String> stratsToUse = new HashSet<String>();
+
+ // Create a map for all stratification modules for easy lookup.
+ HashMap<String, Class<? extends VariantStratifier>> classMap = new HashMap<String, Class<? extends VariantStratifier>>();
+ for (Class<? extends VariantStratifier> c : new PluginManager<VariantStratifier>(VariantStratifier.class).getPlugins()) {
+ classMap.put(c.getSimpleName(), c);
+ }
+
+ // We must use all required stratification modules.
+ for (Class<? extends RequiredStratification> reqClass : new PluginManager<RequiredStratification>(RequiredStratification.class).getPlugins()) {
+ if (classMap.containsKey(reqClass.getSimpleName())) {
+ stratsToUse.add(reqClass.getSimpleName());
+ }
+ }
+
+ // By default, use standard stratification modules.
+ if (!noStandardStrats) {
+ for (Class<? extends StandardStratification> stdClass : new PluginManager<StandardStratification>(StandardStratification.class).getPlugins()) {
+ if (classMap.containsKey(stdClass.getSimpleName())) {
+ stratsToUse.add(stdClass.getSimpleName());
+ }
+ }
+ }
+
+ // Now add the user-selected modules
+ stratsToUse.addAll(Arrays.asList(modulesToUse));
+
+ // Instantiate the stratifications
+ for (String module : stratsToUse) {
+ if (!classMap.containsKey(module)) {
+ throw new UserException.CommandLineException("Module " + module + " could not be found; please check that you have specified the class name correctly");
+ }
+
+ if (classMap.containsKey(module)) {
+ Class<? extends VariantStratifier> c = classMap.get(module);
+
+ try {
+ VariantStratifier vs = c.newInstance();
+ vs.setVariantEvalWalker(variantEvalWalker);
+ vs.initialize();
+
+ strats.add(vs);
+ } catch (InstantiationException e) {
+ throw new GATKException("Unable to instantiate stratification module '" + c.getSimpleName() + "'");
+ } catch (IllegalAccessException e) {
+ throw new GATKException("Illegal access error when trying to instantiate stratification module '" + c.getSimpleName() + "'");
+ }
+ }
+ }
+
+ return new ArrayList<VariantStratifier>(strats);
+ }
+
+ /**
+ * Initialize required, standard and user-specified evaluation objects
+ *
+ * @param noStandardEvals don't use the standard evaluations
+ * @param modulesToUse the list of evaluation modules to use
+ * @return set of evaluations to use
+ */
+ public Set<Class<? extends VariantEvaluator>> initializeEvaluationObjects(boolean noStandardEvals, String[] modulesToUse) {
+ Set<Class<? extends VariantEvaluator>> evals = new HashSet<Class<? extends VariantEvaluator>>();
+
+ // Create a map for all eval modules for easy lookup.
+ HashMap<String, Class<? extends VariantEvaluator>> classMap = new HashMap<String, Class<? extends VariantEvaluator>>();
+ for (Class<? extends VariantEvaluator> c : new PluginManager<VariantEvaluator>(VariantEvaluator.class).getPlugins()) {
+ classMap.put(c.getSimpleName(), c);
+ }
+
+ // By default, use standard eval modules.
+ if (!noStandardEvals) {
+ for (Class<? extends StandardEval> stdClass : new PluginManager<StandardEval>(StandardEval.class).getPlugins()) {
+ if (classMap.containsKey(stdClass.getSimpleName())) {
+ evals.add(classMap.get(stdClass.getSimpleName()));
+ }
+ }
+ }
+
+ // Get the specific classes provided.
+ for (String module : modulesToUse) {
+ if (!classMap.containsKey(module)) {
+ throw new UserException.CommandLineException("Module " + module + " could not be found; please check that you have specified the class name correctly");
+ }
+
+ if (classMap.containsKey(module)) {
+ evals.add(classMap.get(module));
+ }
+ }
+
+ return evals;
+ }
+
+ /**
+ * Subset a VariantContext to a single sample
+ *
+ * @param vc the VariantContext object containing multiple samples
+ * @param sampleName the sample to pull out of the VariantContext
+ * @return a new VariantContext with just the requested sample
+ */
+ public VariantContext getSubsetOfVariantContext(VariantContext vc, String sampleName) {
+ return getSubsetOfVariantContext(vc, Collections.singleton(sampleName));
+ }
+
+ /**
+ * Subset a VariantContext to a set of samples
+ *
+ * @param vc the VariantContext object containing multiple samples
+ * @param sampleNames the samples to pull out of the VariantContext
+ * @return a new VariantContext with just the requested samples
+ */
+ public VariantContext getSubsetOfVariantContext(VariantContext vc, Set<String> sampleNames) {
+ // if we want to preserve AC0 sites as polymorphic we need to not rederive alleles
+ final boolean deriveAlleles = variantEvalWalker.ignoreAC0Sites();
+ return ensureAnnotations(vc, vc.subContextFromSamples(sampleNames, deriveAlleles));
+ }
+
+ public VariantContext ensureAnnotations(final VariantContext vc, final VariantContext vcsub) {
+ final int originalAlleleCount = vc.getHetCount() + 2 * vc.getHomVarCount();
+ final int newAlleleCount = vcsub.getHetCount() + 2 * vcsub.getHomVarCount();
+ final boolean isSingleton = originalAlleleCount == newAlleleCount && newAlleleCount == 1;
+ final boolean hasChrCountAnnotations = vcsub.hasAttribute(VCFConstants.ALLELE_COUNT_KEY) &&
+ vcsub.hasAttribute(VCFConstants.ALLELE_FREQUENCY_KEY) &&
+ vcsub.hasAttribute(VCFConstants.ALLELE_NUMBER_KEY);
+
+ if ( ! isSingleton && hasChrCountAnnotations ) {
+ // nothing to update
+ return vcsub;
+ } else {
+ // have to do the work
+ VariantContextBuilder builder = new VariantContextBuilder(vcsub);
+
+ if ( isSingleton )
+ builder.attribute(VariantEval.IS_SINGLETON_KEY, true);
+
+ if ( ! hasChrCountAnnotations )
+ VariantContextUtils.calculateChromosomeCounts(builder, true);
+
+ return builder.make();
+ }
+ }
+
+ /**
+ * For a list of track names, bind the variant contexts to a trackName->sampleName->VariantContext mapping.
+ * Additional variant contexts per sample are automatically generated and added to the map unless the sample name
+ * matches the ALL_SAMPLE_NAME constant.
+ *
+ * @param tracker the metadata tracker
+ * @param ref the reference context
+ * @param tracks the list of tracks to process
+ * @param byFilter if false, only accept PASSing VariantContexts. Otherwise, accept both PASSing and filtered
+ * sites
+ * @param subsetBySample if false, do not separate the track into per-sample VCs
+ * @param trackPerSample if false, don't stratify per sample (and don't cut up the VariantContext like we would need
+ * to do this)
+ * @return the mapping of track to VC list that should be populated
+ */
+ public HashMap<RodBinding<VariantContext>, HashMap<String, Collection<VariantContext>>>
+ bindVariantContexts(RefMetaDataTracker tracker,
+ ReferenceContext ref,
+ List<RodBinding<VariantContext>> tracks,
+ boolean byFilter,
+ boolean subsetBySample,
+ boolean trackPerSample,
+ boolean mergeTracks) {
+ if (tracker == null)
+ return null;
+
+ HashMap<RodBinding<VariantContext>, HashMap<String, Collection<VariantContext>>> bindings = new HashMap<RodBinding<VariantContext>, HashMap<String, Collection<VariantContext>>>();
+
+ RodBinding<VariantContext> firstTrack = tracks.isEmpty() ? null : tracks.get(0);
+ for (RodBinding<VariantContext> track : tracks) {
+ HashMap<String, Collection<VariantContext>> mapping = new HashMap<String, Collection<VariantContext>>();
+
+ for (VariantContext vc : tracker.getValues(track, ref.getLocus())) {
+
+ // First, filter the VariantContext to represent only the samples for evaluation
+ VariantContext vcsub = vc;
+
+ if (subsetBySample && vc.hasGenotypes())
+ vcsub = getSubsetOfVariantContext(vc, variantEvalWalker.getSampleNamesForEvaluation());
+
+ if ((byFilter || !vcsub.isFiltered())) {
+ addMapping(mapping, VariantEval.getAllSampleName(), vcsub);
+ }
+
+ // Now, if stratifying, split the subsetted vc per sample and add each as a new context
+ if (vc.hasGenotypes() && trackPerSample) {
+ for (String sampleName : variantEvalWalker.getSampleNamesForEvaluation()) {
+ VariantContext samplevc = getSubsetOfVariantContext(vc, sampleName);
+
+ if (byFilter || !samplevc.isFiltered()) {
+ addMapping(mapping, sampleName, samplevc);
+ }
+ }
+ }
+ }
+
+ if (mergeTracks && bindings.containsKey(firstTrack)) {
+ // go through each binding of sample -> value and add all of the bindings from this entry
+ HashMap<String, Collection<VariantContext>> firstMapping = bindings.get(firstTrack);
+ for (Map.Entry<String, Collection<VariantContext>> elt : mapping.entrySet()) {
+ Collection<VariantContext> firstMappingSet = firstMapping.get(elt.getKey());
+ if (firstMappingSet != null) {
+ firstMappingSet.addAll(elt.getValue());
+ } else {
+ firstMapping.put(elt.getKey(), elt.getValue());
+ }
+ }
+ } else {
+ bindings.put(track, mapping);
+ }
+ }
+
+ return bindings;
+ }
+
+ private void addMapping(HashMap<String, Collection<VariantContext>> mappings, String sample, VariantContext vc) {
+ if (!mappings.containsKey(sample))
+ mappings.put(sample, new ArrayList<VariantContext>(1));
+ mappings.get(sample).add(vc);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantrecalibration/VQSRCalibrationCurve.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantrecalibration/VQSRCalibrationCurve.java
new file mode 100644
index 0000000..355441d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantrecalibration/VQSRCalibrationCurve.java
@@ -0,0 +1,160 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantrecalibration;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: 3/11/11
+ * Time: 10:33 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class VQSRCalibrationCurve {
+ private final static boolean DEBUG = false;
+ List<VQSRRange> points;
+ public static final double CERTAIN_FALSE_POSITIVE = -1;
+
+ private static class VQSRRange {
+ double start, stop, truePositiveRate;
+
+ public double getStart() {
+ return start;
+ }
+
+ public double getStop() {
+ return stop;
+ }
+
+ public double getTruePositiveRate() {
+ return truePositiveRate;
+ }
+
+ private VQSRRange(double start, double stop, double truePositiveRate) {
+ this.start = start;
+ this.stop = stop;
+ this.truePositiveRate = truePositiveRate;
+ }
+ }
+
+ public static VQSRCalibrationCurve readFromFile(File source) {
+ List<VQSRRange> points = new ArrayList<VQSRRange>();
+
+ try {
+ for ( String line : new XReadLines(source).readLines() ) {
+ if ( ! line.trim().isEmpty() ) {
+ String[] parts = line.split("\\s+");
+ double fpRate = Double.parseDouble(parts[2]);
+ double tpRate = fpRate >= 1.0 ? CERTAIN_FALSE_POSITIVE : 1.0 - fpRate;
+ points.add(new VQSRRange(Double.parseDouble(parts[0]), Double.parseDouble(parts[1]), tpRate));
+ }
+ }
+ } catch ( FileNotFoundException e ) {
+ throw new UserException.CouldNotReadInputFile(source, e);
+ }
+
+ // ensure that the entire range gets caught
+ points.get(0).start = Double.POSITIVE_INFINITY;
+ points.get(points.size()-1).stop = Double.NEGATIVE_INFINITY;
+
+ return new VQSRCalibrationCurve(points);
+ }
+
+ protected VQSRCalibrationCurve(List<VQSRRange> points) {
+ this.points = points;
+ }
+
+ public boolean certainFalsePositive(String VQSRQualKey, VariantContext vc) {
+ return probTrueVariant(VQSRQualKey, vc) == CERTAIN_FALSE_POSITIVE;
+ }
+
+
+ public double probTrueVariant(double VQSRqual) {
+ for ( VQSRRange r : points ) {
+ if ( VQSRqual <= r.getStart() && VQSRqual > r.getStop() )
+ return r.getTruePositiveRate();
+ }
+
+ throw new ReviewedGATKException("BUG: should not be able to reach this code");
+ }
+
+ public double probTrueVariant(String VQSRQualKey, VariantContext vc) {
+ if ( vc.isFiltered() )
+ return 0.0;
+ else if ( vc.hasAttribute(VQSRQualKey) ) {
+ double qual = vc.getAttributeAsDouble(VQSRQualKey, 0.0);
+ return probTrueVariant(qual);
+ } else {
+ throw new UserException.VariantContextMissingRequiredField(VQSRQualKey, vc);
+ }
+ }
+
+ /**
+ * Returns a likelihoods vector adjusted by the probability that the site is an error. Returns a
+ * null vector if the probability of the site being real is 0.0
+ * @param VQSRQualKey
+ * @param vc
+ * @param log10Likelihoods
+ * @return
+ */
+ public double[] includeErrorRateInLikelihoods(String VQSRQualKey, VariantContext vc, double[] log10Likelihoods) {
+ double[] updated = new double[log10Likelihoods.length];
+
+ double alpha = probTrueVariant(VQSRQualKey, vc);
+
+ if ( alpha == CERTAIN_FALSE_POSITIVE )
+ return null;
+ else {
+ double noInfoPr = 1.0 / 3;
+ if ( DEBUG ) System.out.printf("------------------------------%n");
+ for ( int i = 0; i < log10Likelihoods.length; i++) {
+ double p = Math.pow(10, log10Likelihoods[i]);
+ double q = alpha * p + (1-alpha) * noInfoPr;
+ if ( DEBUG ) System.out.printf(" vqslod = %.2f, p = %.2e, alpha = %.2e, q = %.2e%n", vc.getAttributeAsDouble(VQSRQualKey, 0.0), p, alpha, q);
+ updated[i] = Math.log10(q);
+ }
+
+ return updated;
+ }
+ }
+
+
+ public void printInfo(Logger logger) {
+ for ( VQSRRange r : points ) {
+ logger.info(String.format(" start=%f stop=%f TPrate=%.6e", r.getStart(), r.getStop(), r.getTruePositiveRate()));
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/CombineVariants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/CombineVariants.java
new file mode 100644
index 0000000..aa69693
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/CombineVariants.java
@@ -0,0 +1,371 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.io.stubs.VariantContextWriterStub;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.Reference;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.engine.walkers.Window;
+import org.broadinstitute.gatk.tools.walkers.annotator.ChromosomeCountConstants;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.vcf.*;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+import htsjdk.variant.variantcontext.VariantContextUtils;
+import htsjdk.variant.variantcontext.writer.Options;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+
+import java.util.*;
+
+/**
+ * Combines VCF records from different sources.
+ *
+ * <p>
+ * CombineVariants combines VCF records from different sources. Any (unique) name can be used to bind your rod data
+ * and any number of sources can be input. This tool currently supports two different combination types for each of
+ * variants (the first 8 fields of the VCF) and genotypes (the rest).
+ * Merge: combines multiple records into a single one; if sample names overlap then they are uniquified.
+ * Union: assumes each rod represents the same set of samples (although this is not enforced); using the
+ * priority list (if provided), it emits a single record instance at every position represented in the rods.
+ *
+ * CombineVariants will include a record at every site in all of your input VCF files, and annotate which input ROD
+ * bindings the record is present, pass, or filtered in in the set attribute in the INFO field. In effect,
+ * CombineVariants always produces a union of the input VCFs. However, any part of the Venn of the N merged VCFs
+ * can be exacted using JEXL expressions on the set attribute using SelectVariants. If you want to extract just
+ * the records in common between two VCFs, you would first run CombineVariants on the two files to generate a single
+ * VCF and then run SelectVariants to extract the common records with -select 'set == "Intersection"', as worked out
+ * in the detailed example in the documentation guide.
+ *
+ * Note that CombineVariants supports multi-threaded parallelism (8/15/12). This is particularly useful
+ * when converting from VCF to BCF2, which can be expensive. In this case each thread spends CPU time
+ * doing the conversion, and the GATK engine is smart enough to merge the partial BCF2 blocks together
+ * efficiency. However, since this merge runs in only one thread, you can quickly reach diminishing
+ * returns with the number of parallel threads. -nt 4 works well but -nt 8 may be too much.
+ *
+ * Some fine details about the merging algorithm:
+ * <ul>
+ * <li> As of GATK 2.1, when merging multiple VCF records at a site, the combined VCF record has the QUAL of
+ * the first VCF record with a non-MISSING QUAL value. The previous behavior was to take the
+ * max QUAL, which resulted in sometime strange downstream confusion</li>
+ * </ul>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * One or more variant sets to combine.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A combined VCF.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T CombineVariants \
+ * --variant input1.vcf \
+ * --variant input2.vcf \
+ * -o output.vcf \
+ * -genotypeMergeOptions UNIQUIFY
+ *
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T CombineVariants \
+ * --variant:foo input1.vcf \
+ * --variant:bar input2.vcf \
+ * -o output.vcf \
+ * -genotypeMergeOptions PRIORITIZE
+ * -priority foo,bar
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+ at Reference(window=@Window(start=-50,stop=50))
+public class CombineVariants extends RodWalker<Integer, Integer> implements TreeReducible<Integer> {
+ /**
+ * The VCF files to merge together
+ *
+ * variants can take any number of arguments on the command line. Each -V argument
+ * will be included in the final merged output VCF. If no explicit name is provided,
+ * the -V arguments will be named using the default algorithm: variants, variants2, variants3, etc.
+ * The user can override this by providing an explicit name -V:name,vcf for each -V argument,
+ * and each named argument will be labeled as such in the output (i.e., set=name rather than
+ * set=variants2). The order of arguments does not matter unless except for the naming, so
+ * if you provide an rod priority list and no explicit names than variants, variants2, etc
+ * are technically order dependent. It is strongly recommended to provide explicit names when
+ * a rod priority list is provided.
+ */
+ @Input(fullName="variant", shortName = "V", doc="Input VCF file", required=true)
+ public List<RodBindingCollection<VariantContext>> variantCollections;
+ final private List<RodBinding<VariantContext>> variants = new ArrayList<>();
+
+ @Output(doc="File to which variants should be written")
+ protected VariantContextWriter vcfWriter = null;
+
+ @Argument(shortName="genotypeMergeOptions", doc="Determines how we should merge genotype records for samples shared across the ROD files", required=false)
+ public GATKVariantContextUtils.GenotypeMergeType genotypeMergeOption = null;
+
+ @Argument(shortName="filteredRecordsMergeType", doc="Determines how we should handle records seen at the same site in the VCF, but with different FILTER fields", required=false)
+ public GATKVariantContextUtils.FilteredRecordMergeType filteredRecordsMergeType = GATKVariantContextUtils.FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED;
+
+ @Hidden
+ @Argument(shortName="multipleAllelesMergeType", doc="Determines how we should handle records seen at the same site in the VCF, but with different allele types (for example, SNP vs. indel)", required=false)
+ public GATKVariantContextUtils.MultipleAllelesMergeType multipleAllelesMergeType = GATKVariantContextUtils.MultipleAllelesMergeType.BY_TYPE;
+
+ /**
+ * Used when taking the union of variants that contain genotypes. A complete priority list MUST be provided.
+ */
+ @Argument(fullName="rod_priority_list", shortName="priority", doc="A comma-separated string describing the priority ordering for the genotypes as far as which record gets emitted", required=false)
+ public String PRIORITY_STRING = null;
+
+ @Argument(fullName="printComplexMerges", shortName="printComplexMerges", doc="Print out interesting sites requiring complex compatibility merging", required=false)
+ public boolean printComplexMerges = false;
+
+ @Argument(fullName="filteredAreUncalled", shortName="filteredAreUncalled", doc="If true, then filtered VCFs are treated as uncalled, so that filtered set annotations don't appear in the combined VCF", required=false)
+ public boolean filteredAreUncalled = false;
+
+ /**
+ * Used to generate a sites-only file.
+ */
+ @Argument(fullName="minimalVCF", shortName="minimalVCF", doc="If true, then the output VCF will contain no INFO or genotype FORMAT fields", required=false)
+ public boolean minimalVCF = false;
+
+ @Argument(fullName="excludeNonVariants", shortName="env", doc="Don't include loci found to be non-variant after the combining procedure", required=false)
+ public boolean EXCLUDE_NON_VARIANTS = false;
+
+ /**
+ * Set to 'null' if you don't want the set field emitted.
+ */
+ @Argument(fullName="setKey", shortName="setKey", doc="Key used in the INFO key=value tag emitted describing which set the combined VCF record came from", required=false)
+ public String SET_KEY = "set";
+
+ /**
+ * This option allows the user to perform a simple merge (concatenation) to combine the VCFs, drastically reducing the runtime.
+ */
+ @Argument(fullName="assumeIdenticalSamples", shortName="assumeIdenticalSamples", doc="If true, assume input VCFs have identical sample sets and disjoint calls", required=false)
+ public boolean ASSUME_IDENTICAL_SAMPLES = false;
+
+ @Argument(fullName="minimumN", shortName="minN", doc="Combine variants and output site only if the variant is present in at least N input files.", required=false)
+ public int minimumN = 1;
+
+ /**
+ * This option allows the suppression of the command line in the VCF header. This is most often usefully when combining variants for dozens or hundreds of smaller VCFs.
+ */
+ @Argument(fullName="suppressCommandLineHeader", shortName="suppressCommandLineHeader", doc="If true, do not output the header containing the command line used", required=false)
+ public boolean SUPPRESS_COMMAND_LINE_HEADER = false;
+
+ @Argument(fullName="mergeInfoWithMaxAC", shortName="mergeInfoWithMaxAC", doc="If true, when VCF records overlap the info field is taken from the one with the max AC instead of only taking the fields which are identical across the overlapping records.", required=false)
+ public boolean MERGE_INFO_WITH_MAX_AC = false;
+
+ private List<String> priority = null;
+
+ /** Optimization to strip out genotypes before merging if we are doing a sites_only output */
+ private boolean sitesOnlyVCF = false;
+ private Set<String> samples;
+
+ public void initialize() {
+ Map<String, VCFHeader> vcfRods = GATKVCFUtils.getVCFHeadersFromRods(getToolkit());
+
+ if ( vcfWriter instanceof VariantContextWriterStub) {
+ sitesOnlyVCF = ((VariantContextWriterStub)vcfWriter).getWriterOptions().contains(Options.DO_NOT_WRITE_GENOTYPES);
+ if ( sitesOnlyVCF ) logger.info("Pre-stripping genotypes for performance");
+ } else
+ logger.warn("VCF output file not an instance of VCFWriterStub; cannot enable sites only output option");
+
+ validateAnnotateUnionArguments();
+
+ final boolean sampleNamesAreUnique = SampleUtils.verifyUniqueSamplesNames(vcfRods);
+
+ if (genotypeMergeOption == null) {
+ if (!sampleNamesAreUnique)
+ throw new UserException("Duplicate sample names were discovered but no genotypemergeoption was supplied. " +
+ "To combine samples without merging specify --genotypemergeoption UNIQUIFY. Merging duplicate samples " +
+ "without specified priority is unsupported, but can be achieved by specifying --genotypemergeoption UNSORTED.");
+ else
+ genotypeMergeOption = GATKVariantContextUtils.GenotypeMergeType.UNSORTED;
+ }
+
+ if ( PRIORITY_STRING == null && genotypeMergeOption == GATKVariantContextUtils.GenotypeMergeType.PRIORITIZE) {
+ //PRIORITY_STRING = Utils.join(",", vcfRods.keySet()); Deleted by Ami (7/10/12)
+ logger.info("Priority string is not provided, using arbitrary genotyping order: "+priority);
+ }
+
+ if (genotypeMergeOption == GATKVariantContextUtils.GenotypeMergeType.REQUIRE_UNIQUE &&
+ !sampleNamesAreUnique)
+ throw new IllegalStateException("REQUIRE_UNIQUE sample names is true but duplicate names were discovered.");
+
+ samples = sitesOnlyVCF ? Collections.<String>emptySet() : SampleUtils.getSampleList(vcfRods, genotypeMergeOption);
+
+ if ( SET_KEY.toLowerCase().equals("null") )
+ SET_KEY = null;
+
+ Set<VCFHeaderLine> headerLines = VCFUtils.smartMergeHeaders(vcfRods.values(), true);
+ if ( SET_KEY != null )
+ headerLines.add(new VCFInfoHeaderLine(SET_KEY, 1, VCFHeaderLineType.String, "Source VCF for the merged record in CombineVariants"));
+ if ( !ASSUME_IDENTICAL_SAMPLES )
+ headerLines.addAll(Arrays.asList(ChromosomeCountConstants.descriptions));
+ VCFHeader vcfHeader = new VCFHeader(headerLines, samples);
+ vcfHeader.setWriteCommandLine(!SUPPRESS_COMMAND_LINE_HEADER);
+ vcfWriter.writeHeader(vcfHeader);
+
+ // collect the actual rod bindings into a list for use later
+ for ( final RodBindingCollection<VariantContext> variantCollection : variantCollections )
+ variants.addAll(variantCollection.getRodBindings());
+ }
+
+ private void validateAnnotateUnionArguments() {
+ Set<String> rodNames = SampleUtils.getRodNamesWithVCFHeader(getToolkit(), null);
+
+ if ( genotypeMergeOption == GATKVariantContextUtils.GenotypeMergeType.PRIORITIZE && PRIORITY_STRING == null )
+ throw new UserException.MissingArgument("rod_priority_list", "Priority string must be provided if you want to prioritize genotypes");
+
+ if ( PRIORITY_STRING != null){
+ priority = new ArrayList<>(Arrays.asList(PRIORITY_STRING.split(",")));
+ if ( rodNames.size() != priority.size() )
+ throw new UserException.BadArgumentValue("rod_priority_list", "The priority list must contain exactly one rod binding per ROD provided to the GATK: rodNames=" + rodNames + " priority=" + priority);
+
+ if ( ! rodNames.containsAll(priority) )
+ throw new UserException.BadArgumentValue("rod_priority_list", "Not all priority elements provided as input RODs: " + PRIORITY_STRING);
+ }
+
+ }
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null ) // RodWalkers can make funky map calls
+ return 0;
+
+ final Set<String> rodNames = SampleUtils.getRodNamesWithVCFHeader(getToolkit(), null);
+ // get all of the vcf rods at this locus
+ // Need to provide reference bases to simpleMerge starting at current locus
+ Collection<VariantContext> vcs = tracker.getValues(variants, context.getLocation());
+
+ if ( sitesOnlyVCF ) {
+ vcs = VariantContextUtils.sitesOnlyVariantContexts(vcs);
+ }
+
+ if ( ASSUME_IDENTICAL_SAMPLES ) {
+ for ( final VariantContext vc : vcs ) {
+ vcfWriter.add(vc);
+ }
+
+ return vcs.isEmpty() ? 0 : 1;
+ }
+
+ int numFilteredRecords = 0;
+ for (final VariantContext vc : vcs) {
+ if (vc.filtersWereApplied() && vc.isFiltered())
+ numFilteredRecords++;
+ }
+
+ if (minimumN > 1 && (vcs.size() - numFilteredRecords < minimumN))
+ return 0;
+
+ final List<VariantContext> mergedVCs = new ArrayList<>();
+
+ if (multipleAllelesMergeType == GATKVariantContextUtils.MultipleAllelesMergeType.BY_TYPE) {
+ final Map<VariantContext.Type, List<VariantContext>> VCsByType = GATKVariantContextUtils.separateVariantContextsByType(vcs);
+
+ // TODO -- clean this up in a refactoring
+ // merge NO_VARIATION into another type of variant (based on the ordering in VariantContext.Type)
+ if ( VCsByType.containsKey(VariantContext.Type.NO_VARIATION) && VCsByType.size() > 1 ) {
+ final List<VariantContext> refs = VCsByType.remove(VariantContext.Type.NO_VARIATION);
+ for ( final VariantContext.Type type : VariantContext.Type.values() ) {
+ if ( VCsByType.containsKey(type) ) {
+ VCsByType.get(type).addAll(refs);
+ break;
+ }
+ }
+ }
+
+ // iterate over the types so that it's deterministic
+ for (final VariantContext.Type type : VariantContext.Type.values()) {
+ // make sure that it is a variant or in case it is not, that we want to include the sites with no variants
+ if (!EXCLUDE_NON_VARIANTS || !type.equals(VariantContext.Type.NO_VARIATION)) {
+ if (VCsByType.containsKey(type)) {
+ mergedVCs.add(GATKVariantContextUtils.simpleMerge(VCsByType.get(type), priority, rodNames.size(),
+ filteredRecordsMergeType, genotypeMergeOption, true, printComplexMerges,
+ SET_KEY, filteredAreUncalled, MERGE_INFO_WITH_MAX_AC));
+ }
+ }
+ }
+ }
+ else if (multipleAllelesMergeType == GATKVariantContextUtils.MultipleAllelesMergeType.MIX_TYPES) {
+ mergedVCs.add(GATKVariantContextUtils.simpleMerge(vcs, priority, rodNames.size(), filteredRecordsMergeType,
+ genotypeMergeOption, true, printComplexMerges, SET_KEY, filteredAreUncalled, MERGE_INFO_WITH_MAX_AC));
+ }
+ else {
+ logger.warn("Ignoring all records at site " + ref.getLocus());
+ }
+
+ for ( final VariantContext mergedVC : mergedVCs ) {
+ // only operate at the start of events
+ if ( mergedVC == null )
+ continue;
+
+ if ( mergedVC.hasAllele(GATKVariantContextUtils.NON_REF_SYMBOLIC_ALLELE) )
+ throw new UserException("CombineVariants should not be used to merge gVCFs produced by the HaplotypeCaller; use CombineGVCFs instead");
+
+ final VariantContextBuilder builder = new VariantContextBuilder(mergedVC);
+ // re-compute chromosome counts
+ VariantContextUtils.calculateChromosomeCounts(builder, false);
+
+ if ( minimalVCF )
+ GATKVariantContextUtils.pruneVariantContext(builder, Arrays.asList(SET_KEY));
+ final VariantContext vc = builder.make();
+ if( !EXCLUDE_NON_VARIANTS || vc.isPolymorphicInSamples() )
+ vcfWriter.add(builder.make());
+ }
+
+ return vcs.isEmpty() ? 0 : 1;
+ }
+
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ public Integer reduce(Integer counter, Integer sum) {
+ return counter + sum;
+ }
+
+ @Override
+ public Integer treeReduce(Integer lhs, Integer rhs) {
+ return reduce(lhs, rhs);
+ }
+
+ public void onTraversalDone(Integer sum) {}
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/ConcordanceMetrics.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/ConcordanceMetrics.java
new file mode 100644
index 0000000..2b1897c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/ConcordanceMetrics.java
@@ -0,0 +1,369 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import com.google.java.contract.Requires;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.vcf.VCFHeader;
+
+import java.io.PrintStream;
+import java.util.*;
+
+/**
+ * A class for tabulating and evaluating a callset-by-callset genotype concordance table
+ * */
+public class ConcordanceMetrics {
+
+ final private Map<String,GenotypeConcordanceTable> perSampleGenotypeConcordance;
+ final private GenotypeConcordanceTable overallGenotypeConcordance;
+ final private SiteConcordanceTable overallSiteConcordance;
+ final PrintStream sitesFile;
+
+ public ConcordanceMetrics(VCFHeader evaluate, VCFHeader truth, PrintStream inputSitesFile) {
+ HashSet<String> overlappingSamples = new HashSet<String>(evaluate.getGenotypeSamples());
+ overlappingSamples.retainAll(truth.getGenotypeSamples());
+ perSampleGenotypeConcordance = new HashMap<String, GenotypeConcordanceTable>(overlappingSamples.size());
+ for ( String sample : overlappingSamples ) {
+ perSampleGenotypeConcordance.put(sample,new GenotypeConcordanceTable());
+ }
+ overallGenotypeConcordance = new GenotypeConcordanceTable();
+ overallSiteConcordance = new SiteConcordanceTable();
+ sitesFile = inputSitesFile;
+ if (sitesFile != null) printSitesFileHeader();
+ }
+
+ private void printSitesFileHeader() {
+ sitesFile.println("Locus\tSample\tTruth Genotype\tEval Genotype");
+ }
+
+ public GenotypeConcordanceTable getOverallGenotypeConcordance() {
+ return overallGenotypeConcordance;
+ }
+
+ public SiteConcordanceTable getOverallSiteConcordance() {
+ return overallSiteConcordance;
+ }
+
+ public GenotypeConcordanceTable getGenotypeConcordance(String sample) {
+ GenotypeConcordanceTable table = perSampleGenotypeConcordance.get(sample);
+ if ( table == null )
+ throw new ReviewedGATKException("Attempted to request the concordance table for sample "+sample+" on which it was not calculated");
+ return table;
+ }
+
+ public Map<String,GenotypeConcordanceTable> getPerSampleGenotypeConcordance() {
+ return Collections.unmodifiableMap(perSampleGenotypeConcordance);
+ }
+
+ public Map<String,Double> getPerSampleNRD() {
+ Map<String,Double> nrd = new HashMap<String,Double>(perSampleGenotypeConcordance.size());
+ for ( Map.Entry<String,GenotypeConcordanceTable> sampleTable : perSampleGenotypeConcordance.entrySet() ) {
+ nrd.put(sampleTable.getKey(),calculateNRD(sampleTable.getValue()));
+ }
+
+ return Collections.unmodifiableMap(nrd);
+ }
+
+ public Map<String,Double> getPerSampleOGC() {
+ Map<String,Double> ogc = new HashMap<String,Double>(perSampleGenotypeConcordance.size());
+ for ( Map.Entry<String,GenotypeConcordanceTable> sampleTable : perSampleGenotypeConcordance.entrySet() ) {
+ ogc.put(sampleTable.getKey(),calculateOGC(sampleTable.getValue()));
+ }
+
+ return Collections.unmodifiableMap(ogc);
+ }
+
+ public Double getOverallNRD() {
+ return calculateNRD(overallGenotypeConcordance);
+ }
+
+ public Double getOverallOGC() {
+ return calculateOGC(overallGenotypeConcordance);
+ }
+
+ public Map<String,Double> getPerSampleNRS() {
+ Map<String,Double> nrs = new HashMap<String,Double>(perSampleGenotypeConcordance.size());
+ for ( Map.Entry<String,GenotypeConcordanceTable> sampleTable : perSampleGenotypeConcordance.entrySet() ) {
+ nrs.put(sampleTable.getKey(),calculateNRS(sampleTable.getValue()));
+ }
+
+ return Collections.unmodifiableMap(nrs);
+ }
+
+ public Double getOverallNRS() {
+ return calculateNRS(overallGenotypeConcordance);
+ }
+
+ @Requires({"eval != null","truth != null"})
+ public void update(VariantContext eval, VariantContext truth) {
+ boolean doPrint = false;
+ overallSiteConcordance.update(eval,truth);
+ Set<String> alleleTruth = new HashSet<String>(8);
+ String truthRef = truth.getReference().getBaseString();
+ alleleTruth.add(truthRef);
+ for ( Allele a : truth.getAlternateAlleles() ) {
+ alleleTruth.add(a.getBaseString());
+ }
+ for ( String sample : perSampleGenotypeConcordance.keySet() ) {
+ Genotype evalGenotype = eval.getGenotype(sample);
+ Genotype truthGenotype = truth.getGenotype(sample);
+ // ensure genotypes are either no-call ("."), missing (empty alleles), or diploid
+ if ( ( ! evalGenotype.isNoCall() && evalGenotype.getPloidy() != 2 && evalGenotype.getPloidy() > 0) ||
+ ( ! truthGenotype.isNoCall() && truthGenotype.getPloidy() != 2 && truthGenotype.getPloidy() > 0) ) {
+ throw new UserException(String.format("Concordance Metrics is currently only implemented for DIPLOID genotypes, found eval ploidy: %d, comp ploidy: %d",evalGenotype.getPloidy(),truthGenotype.getPloidy()));
+ }
+ perSampleGenotypeConcordance.get(sample).update(evalGenotype,truthGenotype,alleleTruth,truthRef);
+ doPrint = overallGenotypeConcordance.update(evalGenotype,truthGenotype,alleleTruth,truthRef);
+ if(sitesFile != null && doPrint)
+ sitesFile.println(eval.getChr() + ":" + eval.getStart() + "\t" + sample + "\t" + truthGenotype.getType() + "\t" + evalGenotype.getType());
+ }
+ }
+
+ private static double calculateNRD(GenotypeConcordanceTable table) {
+ return calculateNRD(table.getTable());
+ }
+
+ private static double calculateNRD(int[][] concordanceCounts) {
+ int correct = 0;
+ int total = 0;
+ correct += concordanceCounts[GenotypeType.HET.ordinal()][GenotypeType.HET.ordinal()];
+ correct += concordanceCounts[GenotypeType.HOM_VAR.ordinal()][GenotypeType.HOM_VAR.ordinal()];
+ total += correct;
+ total += concordanceCounts[GenotypeType.HOM_REF.ordinal()][GenotypeType.HET.ordinal()];
+ total += concordanceCounts[GenotypeType.HOM_REF.ordinal()][GenotypeType.HOM_VAR.ordinal()];
+ total += concordanceCounts[GenotypeType.HET.ordinal()][GenotypeType.HOM_REF.ordinal()];
+ total += concordanceCounts[GenotypeType.HET.ordinal()][GenotypeType.HOM_VAR.ordinal()];
+ total += concordanceCounts[GenotypeType.HOM_VAR.ordinal()][GenotypeType.HOM_REF.ordinal()];
+ total += concordanceCounts[GenotypeType.HOM_VAR.ordinal()][GenotypeType.HET.ordinal()];
+ // NRD is by definition incorrec/total = 1.0-correct/total
+ // note: if there are no observations (so the ratio is NaN), set this to 100%
+ return total == 0 ? 1.0 : 1.0 - ( (double) correct)/( (double) total);
+ }
+
+ private static double calculateOGC(int[][] concordanceCounts) {
+ int correct = 0;
+ int total = 0;
+ correct += concordanceCounts[GenotypeType.HOM_REF.ordinal()][GenotypeType.HOM_REF.ordinal()];
+ correct += concordanceCounts[GenotypeType.HET.ordinal()][GenotypeType.HET.ordinal()];
+ correct += concordanceCounts[GenotypeType.HOM_VAR.ordinal()][GenotypeType.HOM_VAR.ordinal()];
+ total += correct;
+ total += concordanceCounts[GenotypeType.HOM_REF.ordinal()][GenotypeType.HET.ordinal()];
+ total += concordanceCounts[GenotypeType.HOM_REF.ordinal()][GenotypeType.HOM_VAR.ordinal()];
+ total += concordanceCounts[GenotypeType.HET.ordinal()][GenotypeType.HOM_REF.ordinal()];
+ total += concordanceCounts[GenotypeType.HET.ordinal()][GenotypeType.HOM_VAR.ordinal()];
+ total += concordanceCounts[GenotypeType.HOM_VAR.ordinal()][GenotypeType.HOM_REF.ordinal()];
+ total += concordanceCounts[GenotypeType.HOM_VAR.ordinal()][GenotypeType.HET.ordinal()];
+ // OGC is by definition correct/total
+ // note: if there are no observations (so the ratio is NaN), set this to 100%
+ return total == 0 ? 1.0 : ( (double) correct)/( (double) total);
+ }
+
+ private static double calculateNRS(GenotypeConcordanceTable table) {
+ return calculateNRS(table.getTable());
+ }
+
+ private static double calculateOGC(GenotypeConcordanceTable table) {
+ return calculateOGC(table.getTable());
+ }
+
+ private static double calculateNRS(int[][] concordanceCounts) {
+ long confirmedVariant = 0;
+ long unconfirmedVariant = 0;
+ for ( GenotypeType truthState : Arrays.asList(GenotypeType.HET,GenotypeType.HOM_VAR) ) {
+ for ( GenotypeType evalState : GenotypeType.values() ) {
+ if ( evalState == GenotypeType.MIXED )
+ continue;
+ if ( evalState.equals(GenotypeType.HET) || evalState.equals(GenotypeType.HOM_VAR) )
+ confirmedVariant += concordanceCounts[evalState.ordinal()][truthState.ordinal()];
+ else
+ unconfirmedVariant += concordanceCounts[evalState.ordinal()][truthState.ordinal()];
+ }
+ }
+
+ long total = confirmedVariant + unconfirmedVariant;
+ // note: if there are no observations (so the ratio is NaN) set this to 0%
+ return total == 0l ? 0.0 : ( (double) confirmedVariant ) / ( (double) ( total ) );
+ }
+
+
+ class GenotypeConcordanceTable {
+
+ private int[][] genotypeCounts;
+ private int nMismatchingAlt;
+
+ public GenotypeConcordanceTable() {
+ genotypeCounts = new int[GenotypeType.values().length][GenotypeType.values().length];
+ nMismatchingAlt = 0;
+ }
+
+ @Requires({"eval!=null","truth != null","truthAlleles != null"})
+ public Boolean update(Genotype eval, Genotype truth, Set<String> truthAlleles, String truthRef) {
+ // this is slow but correct.
+
+ // NOTE: a reference call in "truth" is a special case, the eval can match *any* of the truth alleles
+ // that is, if the reference base is C, and a sample is C/C in truth, A/C, A/A, T/C, T/T will
+ // all match, so long as A and T are alleles in the truth callset.
+ boolean matchingAlt = true;
+ int evalGT, truthGT;
+ if ( eval.isCalled() && truth.isCalled() && truth.isHomRef() ) {
+ // by default, no-calls "match" between alleles, so if
+ // one or both sites are no-call or unavailable, the alt alleles match
+ // otherwise, check explicitly: if the eval has an allele that's not ref, no-call, or present in truth
+ // the alt allele is mismatching - regardless of whether the genotype is correct.
+ for ( Allele evalAllele : eval.getAlleles() ) {
+ matchingAlt &= truthAlleles.contains(evalAllele.getBaseString());
+ }
+ } else if ( eval.isCalled() && truth.isCalled() ) {
+ // otherwise, the eval genotype has to match either the alleles in the truth genotype, or the truth reference allele
+ // todo -- this can be sped up by caching the truth allele sets
+ Set<String> genoAlleles = new HashSet<String>(3);
+ genoAlleles.add(truthRef);
+ for ( Allele truthGenoAl : truth.getAlleles() ) {
+ genoAlleles.add(truthGenoAl.getBaseString());
+ }
+ for ( Allele evalAllele : eval.getAlleles() ) {
+ matchingAlt &= genoAlleles.contains(evalAllele.getBaseString());
+ }
+ }
+
+ if ( matchingAlt ) {
+ evalGT = eval.getType().ordinal();
+ truthGT = truth.getType().ordinal();
+ genotypeCounts[evalGT][truthGT]++;
+ if(evalGT != truthGT) //report variants where genotypes don't match
+ return true;
+ } else {
+ nMismatchingAlt++;
+ return false;
+ //return true; //alternatively, report variants where alt alleles don't match
+ }
+ return false;
+ }
+
+ public int[][] getTable() {
+ return genotypeCounts;
+ }
+
+ public int getnMismatchingAlt() {
+ return nMismatchingAlt;
+ }
+
+ public int getnEvalGenotypes(GenotypeType type) {
+ int nGeno = 0;
+ for ( GenotypeType comptype : GenotypeType.values() )
+ nGeno += genotypeCounts[type.ordinal()][comptype.ordinal()];
+ return nGeno;
+ }
+
+ public int getnCalledEvalGenotypes() {
+ int nGeno = 0;
+ for ( GenotypeType evalType : Arrays.asList(GenotypeType.HOM_REF,GenotypeType.HOM_VAR,GenotypeType.HET) ) {
+ nGeno += getnEvalGenotypes(evalType);
+ }
+
+ return nGeno + nMismatchingAlt;
+ }
+
+ public int getnCompGenotypes(GenotypeType type) {
+ int nGeno = 0;
+ for ( GenotypeType evaltype : GenotypeType.values() )
+ nGeno += genotypeCounts[evaltype.ordinal()][type.ordinal()];
+ return nGeno;
+ }
+
+ public int getnCalledCompGenotypes() {
+ int nGeno = 0;
+ for ( GenotypeType compType : Arrays.asList(GenotypeType.HOM_REF,GenotypeType.HOM_VAR,GenotypeType.HET) ) {
+ nGeno += getnCompGenotypes(compType);
+ }
+ return nGeno;
+ }
+
+ public int get(GenotypeType evalType, GenotypeType compType) {
+ return genotypeCounts[evalType.ordinal()][compType.ordinal()];
+ }
+ }
+
+ class SiteConcordanceTable {
+
+ private int[] siteConcordance;
+
+ public SiteConcordanceTable() {
+ siteConcordance = new int[SiteConcordanceType.values().length];
+ }
+
+ public void update(VariantContext evalVC, VariantContext truthVC) {
+ SiteConcordanceType matchType = getMatchType(evalVC,truthVC);
+ siteConcordance[matchType.ordinal()]++;
+ }
+
+ @Requires({"evalVC != null","truthVC != null"})
+ private SiteConcordanceType getMatchType(VariantContext evalVC, VariantContext truthVC) {
+ return SiteConcordanceType.getConcordanceType(evalVC,truthVC);
+ }
+
+ public int[] getSiteConcordance() {
+ return siteConcordance;
+ }
+
+ public int get(SiteConcordanceType type) {
+ return getSiteConcordance()[type.ordinal()];
+ }
+ }
+
+ enum SiteConcordanceType {
+ ALLELES_MATCH,
+ EVAL_SUPERSET_TRUTH,
+ EVAL_SUBSET_TRUTH,
+ ALLELES_DO_NOT_MATCH,
+ EVAL_ONLY,
+ TRUTH_ONLY;
+
+ public static SiteConcordanceType getConcordanceType(VariantContext eval, VariantContext truth) {
+ if ( eval.isMonomorphicInSamples() )
+ return TRUTH_ONLY;
+ if ( truth.isMonomorphicInSamples() )
+ return EVAL_ONLY;
+
+ boolean evalSubsetTruth = GATKVariantContextUtils.allelesAreSubset(eval, truth);
+ boolean truthSubsetEval = GATKVariantContextUtils.allelesAreSubset(truth, eval);
+
+ if ( evalSubsetTruth && truthSubsetEval )
+ return ALLELES_MATCH;
+
+ if ( evalSubsetTruth )
+ return EVAL_SUBSET_TRUTH;
+
+ if ( truthSubsetEval )
+ return EVAL_SUPERSET_TRUTH;
+
+ return ALLELES_DO_NOT_MATCH;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/FilterLiftedVariants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/FilterLiftedVariants.java
new file mode 100644
index 0000000..73995bf
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/FilterLiftedVariants.java
@@ -0,0 +1,136 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import org.broadinstitute.gatk.engine.walkers.Reference;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.Window;
+import org.broadinstitute.gatk.utils.commandline.ArgumentCollection;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.*;
+
+/**
+ * Filters a lifted-over VCF file for ref bases that have been changed.
+ *
+ * "Lifting over" variants means adjusting variant calls from one reference to another. Specifically, the process adjusts the position of the call to match the corresponding position on the target reference.
+ * For example, if you have variants called from reads aligned to the hg19 reference, and you want to compare them to calls made based on the b37 reference, you need to liftover one of the callsets to the other reference.
+ *
+ * FilteredLiftedVariants is intended to be the second of two processing steps for the liftover process. The first step is to run LiftoverVariants on your VCF file.
+ * The second step is to run FilterLiftedVariants on the output of LiftoverVariants. This will produce valid well-behaved VCF files, where you'll see that the contig names in the header have all been correctly replaced.
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+ at Reference(window=@Window(start=0,stop=100))
+public class FilterLiftedVariants extends RodWalker<Integer, Integer> {
+
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ private static final int MAX_VARIANT_SIZE = 100;
+
+ @Output(doc="File to which variants should be written")
+ protected VariantContextWriter writer = null;
+
+ private long failedLocs = 0, totalLocs = 0;
+
+ public void initialize() {
+ String trackName = variantCollection.variants.getName();
+ Set<String> samples = SampleUtils.getSampleListWithVCFHeader(getToolkit(), Arrays.asList(trackName));
+ Map<String, VCFHeader> vcfHeaders = GATKVCFUtils.getVCFHeadersFromRods(getToolkit(), Arrays.asList(trackName));
+
+ final VCFHeader vcfHeader = new VCFHeader(vcfHeaders.containsKey(trackName) ? vcfHeaders.get(trackName).getMetaDataInSortedOrder() : Collections.<VCFHeaderLine>emptySet(), samples);
+ writer.writeHeader(vcfHeader);
+ }
+
+ /**
+ * Determines whether records should be filtered; if not, writes them to the output
+ *
+ * @param ref the reference context
+ * @param vc the VariantContext to process
+ * @return true if the record is not filtered, false otherwise
+ */
+ protected boolean filterOrWrite(final byte[] ref, final VariantContext vc) {
+ if ( ref == null ) throw new IllegalArgumentException("Cannot filter based on a null reference array");
+ if ( vc == null ) throw new IllegalArgumentException("Cannot filter a null Variant Context");
+
+ totalLocs++;
+
+ boolean filter = false;
+ final byte[] recordRef = vc.getReference().getBases();
+
+ // this can happen for records that get placed at the ends of chromosomes
+ if ( recordRef.length > ref.length ) {
+ filter = true;
+ } else {
+ for (int i = 0; i < recordRef.length && i < MAX_VARIANT_SIZE; i++) {
+ if ( recordRef[i] != ref[i] ) {
+ filter = true;
+ break;
+ }
+ }
+ }
+
+ if ( filter )
+ failedLocs++;
+ else
+ writer.add(vc);
+
+ return !filter;
+ }
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null )
+ return 0;
+
+ final Collection<VariantContext> VCs = tracker.getValues(variantCollection.variants, context.getLocation());
+ for ( final VariantContext vc : VCs )
+ filterOrWrite(ref.getBases(), vc);
+
+ return 0;
+ }
+
+ public Integer reduceInit() { return 0; }
+
+ public Integer reduce(Integer value, Integer sum) { return 0; }
+
+ public void onTraversalDone(Integer result) {
+ System.out.println("Filtered " + failedLocs + " records out of " + totalLocs + " total records.");
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/GenotypeConcordance.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/GenotypeConcordance.java
new file mode 100644
index 0000000..d2f251a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/GenotypeConcordance.java
@@ -0,0 +1,675 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.report.GATKReport;
+import org.broadinstitute.gatk.engine.report.GATKReportTable;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.vcf.VCFHeader;
+
+import java.io.PrintStream;
+import java.util.*;
+
+/**
+ * Genotype concordance (per-sample and aggregate counts and frequencies, NRD/NRS and site allele overlaps) between two callsets
+ *
+ * <p>
+ * GenotypeConcordance takes in two callsets (vcfs) and tabulates the number of sites which overlap and share alleles,
+ * and for each sample, the genotype-by-genotype counts (e.g. the number of sites at which a sample was
+ * called homozygous-reference in the EVAL callset, but homozygous-variant in the COMP callset). It outputs these
+ * counts as well as convenient proportions (such as the proportion of het calls in the EVAL which were called REF in
+ * the COMP) and metrics (such as NRD and NRS).
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * Genotype concordance requires two callsets (as it does a comparison): an EVAL and a COMP callset, specified via
+ * the -eval and -comp arguments. Typically, the EVAL callset is an experimental set you want to evaluate, while the
+ * COMP callset is a previously existing set used as a standard for comparison (taken to represent "truth").
+ * </p>
+ * <p>
+ * (Optional) Jexl expressions for genotype-level filtering of EVAL or COMP genotypes, specified via the -gfe and
+ * -cfe arguments, respectively.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * Genotype Concordance writes a GATK report to the specified file (via -o), consisting of multiple tables of counts
+ * and proportions. These tables are constructed on a per-sample basis, and include counts of EVAL vs COMP genotype
+ * states.
+ * </p>
+ * <h4>Tables</h4>
+ * <p>
+ * Headers for the (non-moltenized -- see below) GenotypeConcordance counts and proportions tables give the genotype of
+ * the COMP callset followed by the genotype of the EVAL callset. For example the value corresponding to HOM_REF_HET
+ * reflects variants called HOM_REF in the COMP callset and HET in the EVAL callset. Variants for which the alternate
+ * alleles between the EVAL and COMP sample did not match are excluded from genotype comparisons and given in the
+ * "Mismatching_Alleles" field.
+ * </p>
+ * <p>
+ * It may be informative to reshape rows of the GenotypeConcordance counts and proportions tables into separate row-major tables
+ * where the columns indicate the COMP genotype and the rows indicate the EVAL genotype for easy comparison between the
+ * two callsets. This can be done with a command similar to d <- matrix(sampleRow,nrow=6,byrow=T) in R where sampleRow is the 36-value row corresponding to the sample of interest, excluding "Mismatching_Alleles".
+ * In Excel this can be accomplished using the OFFSET function.
+ * </p>
+ * <ul>
+ * <li><i>GenotypeConcordance_CompProportions</i>: Gives the proportion of variants in each category normalized to the total number of called genotypes in the COMP callset</li>
+ * <li><i>GenotypeConcordance_Counts</i>: Gives the counts for number of genotypes in each category</li>
+ * <li><i>GenotypeConcordance_EvalProportions</i>: Gives the proportion of genotypes in each category normalized to the total number of called genotypes in the EVAL callset</li>
+ * <li><i>GenotypeConcordance_Summary</i>: Summary statistics for the sum of all samples and each sample individually. See below for definitions.</li>
+ * <li><i>SiteConcordance_Summary</i>: Gives comparison counts of called genotypes and their alleles between the two callsets. See below for definitions.</li>
+ * </ul>
+ * </p>
+ *
+ * <h4>Term and metrics definitions</h4>
+ * <p>
+ * <ul>
+ * <li><i>GenotypeConcordance_CompProportions</i>, <i>GenotypeConcordance_Counts</i>, and <i>GenotypeConcordance_EvalProportions</i></li>
+ * <ul>
+ * <li>NO_CALL: reported genotype is ./., indicating not enough data to call</li>
+ * <li>HET: heterozygous</li>
+ * <li>HOM_REF: homozygous reference</li>
+ * <li>HOM_VAR: homozygous variant</li>
+ * <li>UNAVAILABLE: variant is not called in this callset</li>
+ * <li>MIXED: something like ./1</li>
+ * </ul>
+ * <li><i>GenotypeConcordance_Summary</i></li>
+ * <ul>
+ * <li>Non-Reference_Sensitivity (NRS): sensitivity of the EVAL calls to polymorphic calls in the COMP set, calculated by (# true positive)/(# true polymorphic)</li>
+ * <li>Non-Reference_Discrepancy (NRD): genotype discordance excluding concordant reference sites, calculated by (# discordant sites)/(total excluding # HOM_REF_HOM_REF) = 1.0-(# HOM_VAR_HOM_VAR + # HET_HET)/(total excluding # HOM_REF_HOM_REF)</li>
+ * <li>Overall_Genotype_Concordance: overall concordance calculated by (# concordant genotypes)/(# genotypes)</li>
+ * </ul>
+ * <li><i>SiteConcordance_Summary</i></li>
+ * <ul>
+ * <li>ALLELES_MATCH: counts of calls at the same site where the alleles match</li>
+ * <li>ALLELES_DO_NOT_MATCH: counts of calls at the same location with different alleles, such as the EVAL set calling a 'G' alternate allele, and the comp set calling a 'T' alternate allele</li>
+ * <li>EVAL_SUBSET_TRUTH: (multi-alleleic sites only) ALT alleles for EVAL are a subset of ALT alleles for COMP. See also below.</li>
+ * <li>EVAL_SUPERSET_TRUTH: (multi-allelic sites only) ALT alleles for COMP are a subset of ALT alleles for EVAL. See also below.</li>
+ * <li>EVAL_ONLY: counts of sites present only in the EVAL set, not in the COMP set</li>
+ * <li>TRUTH_ONLY: counts of sites present only in the COMP set, not in the EVAL set</li>
+ * </ul>
+ * </ul>
+ * </p>
+ *
+ * <h4>Site-level allelic concordance</h4>
+ *
+ * <p>
+ * For strictly bi-allelic VCFs, only the ALLELES_MATCH, EVAL_ONLY, TRUTH_ONLY fields will be populated,
+ * but where multi-allelic sites are involved counts for EVAL_SUBSET_TRUTH and EVAL_SUPERSET_TRUTH will be generated.
+ * </p>
+ * <p>
+ * For example, in the following situation
+ * <pre>
+ * eval: ref - A alt - C
+ * comp: ref - A alt - C,T
+ * </pre>
+ * then the site is tabulated as EVAL_SUBSET_TRUTH. Were the situation reversed, it would be EVAL_SUPERSET_TRUTH.
+ * However, in the case where EVAL has both C and T alternate alleles, both must be observed in the genotypes
+ * (that is, there must be at least one of (0/1,1/1) and at least one of (0/2,1/2,2/2) in the genotype field). If
+ * one of the alleles has no observations in the genotype fields of the EVAL, the site-level concordance is
+ * tabulated as though that allele were not present in the record.
+ * </p>
+ *
+ * <h4>Monomorphic Records</h4>
+ * <p>
+ * A site which has an alternate allele, but which is monomorphic in samples, is treated as not having been
+ * discovered, and will be recorded in the TRUTH_ONLY column (if a record exists in the COMP set), or not at all
+ * (if no record exists in the COMP set).
+ * </p>
+ * <p>
+ * That is, in the situation
+ * <pre>
+ * eval: ref - A alt - C genotypes - 0/0 0/0 0/0 ... 0/0
+ * comp: ref - A alt - C ... 0/0 0/0 ...
+ * </pre>
+ * is equivalent to
+ * <pre>
+ * eval: ref - A alt - . genotypes - 0/0 0/0 0/0 ... 0/0
+ * comp: ref - A alt - C ... 0/0 0/0 ...
+ * </pre>
+ * </p>
+ * <p>
+ * When a record is present in the COMP set the *genotypes* for the monomorphic site will still be used to evaluate
+ * per-sample genotype concordance counts.
+ * </p>
+ *
+ * <h4>Filtered Records</h4>
+ * Filtered records are treated as though they were not present in the VCF, unless -ignoreSiteFilters is provided,
+ * in which case all records are used. There is currently no way to assess concordance metrics on filtered sites
+ * exclusively. SelectVariants can be used to extract filtered sites, and VariantFiltration used to un-filter them.
+ *
+ * <h4>Moltenized tables</h4>
+ *
+ * <p>These tables may be optionally moltenized via the -moltenize argument. That is, the standard table
+ *
+ * <pre>
+ * Sample NO_CALL_HOM_REF NO_CALL_HET NO_CALL_HOM_VAR (...)
+ * NA12878 0.003 0.001 0.000 (...)
+ * NA12891 0.005 0.000 0.000 (...)
+ * </pre>
+ *
+ * would instead be displayed
+ *
+ * <pre>
+ * NA12878 NO_CALL_HOM_REF 0.003
+ * NA12878 NO_CALL_HET 0.001
+ * NA12878 NO_CALL_HOM_VAR 0.000
+ * NA12891 NO_CALL_HOM_REF 0.005
+ * NA12891 NO_CALL_HET 0.000
+ * NA12891 NO_CALL_HOM_VAR 0.000
+ * (...)
+ * </pre>
+
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+public class GenotypeConcordance extends RodWalker<List<Pair<VariantContext,VariantContext>>,ConcordanceMetrics> {
+
+ /**
+ * The callset you want to evaluate, typically this is where you'd put 'unassessed' callsets.
+ */
+ @Input(fullName="eval",shortName="eval",doc="The variants and genotypes to evaluate",required=true)
+ RodBinding<VariantContext> evalBinding;
+
+ /**
+ * The callset you want to treat as 'truth'. Can also be of unknown quality for the sake of callset comparisons.
+ */
+ @Input(fullName="comp",shortName="comp",doc="The variants and genotypes to compare against",required=true)
+ RodBinding<VariantContext> compBinding;
+
+ /**
+ * The FILTER field of the eval and comp VCFs will be ignored. If this flag is not included, all FILTER sites will
+ * be treated as not being present in the VCF. (That is, the genotypes will be assigned UNAVAILABLE, as distinct
+ * from NO_CALL).
+ */
+ @Argument(fullName="ignoreFilters",doc="Filters will be ignored",required=false)
+ boolean ignoreFilters = false;
+
+ /**
+ * A genotype level JEXL expression to apply to eval genotypes. Genotypes filtered in this way will be replaced by NO_CALL.
+ * For instance: -gfe 'GQ<20' will set to no-call any genotype with genotype quality less than 20.
+ */
+ @Argument(shortName="gfe", fullName="genotypeFilterExpressionEval", doc="One or more criteria to use to set EVAL genotypes to no-call. "+
+ "These genotype-level filters are only applied to the EVAL rod.", required=false)
+ public ArrayList<String> genotypeFilterExpressionsEval = new ArrayList<String>();
+
+ /**
+ * Identical to -gfe except the filter is applied to genotypes in the comp rod.
+ */
+ @Argument(shortName="gfc", fullName="genotypeFilterExpressionComp", doc="One or more criteria to use to set COMP genotypes to no-call. "+
+ "These genotype-level filters are only applied to the COMP rod.", required=false)
+ public ArrayList<String> genotypeFilterExpressionsComp = new ArrayList<String>();
+
+ /**
+ * Moltenize the count and proportion tables. Rather than moltenizing per-sample data into a 2x2 table, it is fully
+ * moltenized into elements. That is, WITHOUT this argument, each row of the table begins with the sample name and
+ * proceeds directly with counts/proportions of eval/comp counts (for instance HOM_REF/HOM_REF, HOM_REF/NO_CALL).
+ *
+ * If the Moltenize argument is given, the output will begin with a sample name, followed by the contrastive genotype
+ * type (such as HOM_REF/HOM_REF), followed by the count or proportion. This will significantly increase the number of
+ * rows.
+ */
+ @Argument(shortName="moltenize",fullName="moltenize",doc="Molten rather than tabular output")
+ public boolean moltenize = false;
+
+ /**
+ * Print sites where genotypes are mismatched between callsets along with annotations giving the genotype of each callset
+ * to the given filename
+ *
+ */
+
+ @Argument(shortName = "sites",required = false,fullName = "printInterestingSites", doc="File to output the discordant sites and genotypes.")
+ private PrintStream sitesFile = null;
+
+ @Output
+ PrintStream out;
+
+ private List<String> evalSamples;
+ private List<String> compSamples;
+ private List<VariantContextUtils.JexlVCMatchExp> evalJexls = null;
+ private List<VariantContextUtils.JexlVCMatchExp> compJexls = null;
+
+ // todo -- table with "proportion of overlapping sites" (not just eval/comp margins) [e.g. drop no-calls]
+ // (this will break all the integration tests of course, due to new formatting)
+
+ public void initialize() {
+ evalJexls = initializeJexl(genotypeFilterExpressionsEval);
+ compJexls = initializeJexl(genotypeFilterExpressionsComp);
+ }
+
+ private List<VariantContextUtils.JexlVCMatchExp> initializeJexl(ArrayList<String> genotypeFilterExpressions) {
+ ArrayList<String> dummyNames = new ArrayList<String>(genotypeFilterExpressions.size());
+ int expCount = 1;
+ for ( String exp : genotypeFilterExpressions ) {
+ dummyNames.add(String.format("gfe%d",expCount++));
+ }
+ return VariantContextUtils.initializeMatchExps(dummyNames, genotypeFilterExpressions);
+ }
+
+ public ConcordanceMetrics reduceInit() {
+ Map<String,VCFHeader> headerMap = GATKVCFUtils.getVCFHeadersFromRods(getToolkit(), Arrays.asList(evalBinding,compBinding));
+ VCFHeader evalHeader = headerMap.get(evalBinding.getName());
+ evalSamples = evalHeader.getGenotypeSamples();
+ VCFHeader compHeader = headerMap.get(compBinding.getName());
+ compSamples = compHeader.getGenotypeSamples();
+ return new ConcordanceMetrics(evalHeader,compHeader, sitesFile);
+ }
+
+
+ public List<Pair<VariantContext,VariantContext>> map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ List<Pair<VariantContext,VariantContext>> evalCompPair = new ArrayList<Pair<VariantContext,VariantContext>>(3);
+ if ( tracker != null && (
+ tracker.getValues(evalBinding,ref.getLocus()).size() > 0 ||
+ tracker.getValues(compBinding,ref.getLocus()).size() > 0 ) ) {
+
+ List<VariantContext> eval = tracker.getValues(evalBinding,ref.getLocus());
+ List<VariantContext> comp = tracker.getValues(compBinding,ref.getLocus());
+ if ( eval.size() > 1 || comp.size() > 1 ) {
+ if ( noDuplicateTypes(eval) && noDuplicateTypes(comp) ) {
+ logger.info("Eval or Comp Rod at position " + ref.getLocus().toString() + " has multiple records. Resolving.");
+ evalCompPair = resolveMultipleRecords(eval,comp);
+ } else {
+ logger.warn("Eval or Comp Rod at position "+ref.getLocus().toString()+" has multiple records of the same type. This locus will be skipped.");
+ }
+ } else {
+ // if a rod is missing, explicitly create a variant context with 'missing' genotypes. Slow, but correct.
+ // note that if there is no eval rod there must be a comp rod, and also the reverse
+ VariantContext evalContext = eval.size() == 1 ? eval.get(0) : createEmptyContext(comp.get(0),evalSamples);
+ VariantContext compContext = comp.size() == 1 ? comp.get(0) : createEmptyContext(eval.get(0),compSamples);
+ evalContext = filterGenotypes(evalContext,ignoreFilters,evalJexls);
+ compContext = filterGenotypes(compContext,ignoreFilters,compJexls);
+ evalCompPair.add(new Pair<VariantContext, VariantContext>(evalContext,compContext));
+ }
+ }
+
+ return evalCompPair;
+ }
+
+ private boolean noDuplicateTypes(List<VariantContext> vcList) {
+ HashSet<VariantContext.Type> types = new HashSet<VariantContext.Type>(vcList.size());
+ for ( VariantContext vc : vcList ) {
+ VariantContext.Type type = vc.getType();
+ if ( types.contains(type) )
+ return false;
+ types.add(type);
+ }
+
+ return true;
+ }
+
+ /**
+ * The point of this method is to match up pairs of evals and comps by their type (or alternate alleles for mixed).
+ * Basically multiple records could exist for a site such as:
+ * Eval: 20 4000 A C
+ * Eval: 20 4000 A AC
+ * Comp: 20 4000 A C
+ * So for each eval, loop through the comps. If the types match, or for mixed types if eval alleles (non-emptily)
+ * intersect the comp alleles, pair them up and remove that comp records.
+ * Continue until we're out of evals or comps. This is n^2, but should rarely actually happen.
+ *
+ * The remaining unpaired records get paird with an empty contexts. So in the example above we'd get a list of:
+ * 1 - (20,4000,A/C | 20,4000,A/C)
+ * 2 - (20,4000,A/AC | Empty )
+ * @param evalList - list of eval variant contexts
+ * @param compList - list of comp variant contexts
+ * @return resolved pairs of the input lists
+ */
+ private List<Pair<VariantContext,VariantContext>> resolveMultipleRecords(List<VariantContext> evalList, List<VariantContext> compList) {
+ List<Pair<VariantContext,VariantContext>> resolvedPairs = new ArrayList<Pair<VariantContext,VariantContext>>(evalList.size()+compList.size()); // oversized but w/e
+ List<VariantContext> pairedEval = new ArrayList<VariantContext>(evalList.size());
+ for ( VariantContext eval : evalList ) {
+ VariantContext.Type evalType = eval.getType();
+ Set<Allele> evalAlleles = new HashSet<Allele>(eval.getAlternateAlleles());
+ VariantContext pairedComp = null;
+ for ( VariantContext comp : compList ) {
+ if ( evalType.equals(comp.getType()) ) {
+ pairedComp = comp;
+ break;
+ } else if ( eval.isMixed() || comp.isMixed() ) {
+ for ( Allele compAllele : comp.getAlternateAlleles() ) {
+ if ( evalAlleles.contains(compAllele) ) {
+ pairedComp = comp;
+ break;
+ }
+ }
+ }
+ }
+ if ( pairedComp != null ) {
+ compList.remove(pairedComp);
+ resolvedPairs.add(new Pair<VariantContext, VariantContext>(filterGenotypes(eval,ignoreFilters,evalJexls),filterGenotypes(pairedComp,ignoreFilters,compJexls)));
+ pairedEval.add(eval);
+ if ( compList.size() < 1 )
+ break;
+ }
+ }
+ evalList.removeAll(pairedEval);
+ for ( VariantContext unpairedEval : evalList ) {
+ resolvedPairs.add(new Pair<VariantContext, VariantContext>(filterGenotypes(unpairedEval,ignoreFilters,evalJexls),createEmptyContext(unpairedEval,compSamples)));
+ }
+
+ for ( VariantContext unpairedComp : compList ) {
+ resolvedPairs.add(new Pair<VariantContext, VariantContext>(createEmptyContext(unpairedComp,evalSamples),filterGenotypes(unpairedComp,ignoreFilters,compJexls)));
+ }
+
+ return resolvedPairs;
+ }
+
+ public ConcordanceMetrics reduce(List<Pair<VariantContext,VariantContext>> evalCompList, ConcordanceMetrics metrics) {
+ for ( Pair<VariantContext,VariantContext> evalComp : evalCompList){
+ metrics.update(evalComp.getFirst(),evalComp.getSecond());
+
+ }
+ return metrics;
+ }
+
+ private static double repairNaN(double d) {
+ if ( Double.isNaN(d) ) {
+ return 0.0;
+ }
+ return d;
+ }
+
+ public void onTraversalDone(ConcordanceMetrics metrics) {
+ // todo -- this is over 200 lines of code just to format the output and could use some serious cleanup
+ GATKReport report = new GATKReport();
+ GATKReportTable concordanceCounts = new GATKReportTable("GenotypeConcordance_Counts","Per-sample concordance tables: comparison counts",2+GenotypeType.values().length*GenotypeType.values().length);
+ GATKReportTable concordanceEvalProportions = new GATKReportTable("GenotypeConcordance_EvalProportions", "Per-sample concordance tables: proportions of genotypes called in eval",2+GenotypeType.values().length*GenotypeType.values().length);
+ GATKReportTable concordanceCompProportions = new GATKReportTable("GenotypeConcordance_CompProportions", "Per-sample concordance tables: proportions of genotypes called in comp",2+GenotypeType.values().length*GenotypeType.values().length);
+ GATKReportTable concordanceSummary = new GATKReportTable("GenotypeConcordance_Summary","Per-sample summary statistics: NRS, NRD, and OGC",2);
+ GATKReportTable siteConcordance = new GATKReportTable("SiteConcordance_Summary","Site-level summary statistics",ConcordanceMetrics.SiteConcordanceType.values().length);
+ if ( moltenize ) {
+ concordanceCompProportions.addColumn("Sample","%s");
+ concordanceCounts.addColumn("Sample","%s");
+ concordanceEvalProportions.addColumn("Sample","%s");
+ concordanceSummary.addColumn("Sample","%s");
+
+ concordanceCompProportions.addColumn("Eval_Genotype","%s");
+ concordanceCounts.addColumn("Eval_Genotype","%s");
+ concordanceEvalProportions.addColumn("Eval_Genotype","%s");
+ concordanceSummary.addColumn("Non-Reference_Discrepancy","%.3f");
+
+ concordanceCompProportions.addColumn("Comp_Genotype","%s");
+ concordanceCounts.addColumn("Comp_Genotype","%s");
+ concordanceEvalProportions.addColumn("Comp_Genotype","%s");
+ concordanceSummary.addColumn("Non-Reference_Sensitivity","%.3f");
+
+ concordanceCompProportions.addColumn("Proportion","%.3f");
+ concordanceCounts.addColumn("Count","%d");
+ concordanceEvalProportions.addColumn("Proportion","%.3f");
+ concordanceSummary.addColumn("Overall_Genotype_Concordance","%.3f");
+
+ for ( Map.Entry<String,ConcordanceMetrics.GenotypeConcordanceTable> entry : metrics.getPerSampleGenotypeConcordance().entrySet() ) {
+ ConcordanceMetrics.GenotypeConcordanceTable table = entry.getValue();
+ for ( GenotypeType evalType : GenotypeType.values() ) {
+ for ( GenotypeType compType : GenotypeType.values() ) {
+ String rowKey = String.format("%s_%s_%s",entry.getKey(),evalType.toString(),compType.toString());
+ concordanceCounts.set(rowKey,"Sample",entry.getKey());
+ concordanceCounts.set(rowKey,"Eval_Genotype",evalType.toString());
+ concordanceCounts.set(rowKey,"Comp_Genotype",compType.toString());
+ int count = table.get(evalType, compType);
+ concordanceCounts.set(rowKey,"Count",count);
+ if ( evalType == GenotypeType.HET || evalType == GenotypeType.HOM_REF || evalType == GenotypeType.HOM_VAR) {
+ concordanceEvalProportions.set(rowKey,"Sample",entry.getKey());
+ concordanceEvalProportions.set(rowKey,"Eval_Genotype",evalType.toString());
+ concordanceEvalProportions.set(rowKey,"Comp_Genotype",compType.toString());
+ concordanceEvalProportions.set(rowKey,"Proportion",repairNaN(( (double) count)/table.getnEvalGenotypes(evalType)));
+ }
+ if ( compType == GenotypeType.HET || compType == GenotypeType.HOM_VAR || compType == GenotypeType.HOM_REF ) {
+ concordanceCompProportions.set(rowKey,"Sample",entry.getKey());
+ concordanceCompProportions.set(rowKey,"Eval_Genotype",evalType.toString());
+ concordanceCompProportions.set(rowKey,"Comp_Genotype",compType.toString());
+ concordanceCompProportions.set(rowKey,"Proportion",repairNaN(( (double) count)/table.getnCompGenotypes(compType)));
+ }
+ }
+ }
+ String mismatchKey = String.format("%s_%s",entry.getKey(),"Mismatching");
+ concordanceCounts.set(mismatchKey,"Sample",entry.getKey());
+ concordanceCounts.set(mismatchKey,"Eval_Genotype","Mismatching_Alleles");
+ concordanceCounts.set(mismatchKey,"Comp_Genotype","Mismatching_Alleles");
+ concordanceEvalProportions.set(mismatchKey,"Sample",entry.getKey());
+ concordanceEvalProportions.set(mismatchKey,"Eval_Genotype","Mismatching_Alleles");
+ concordanceEvalProportions.set(mismatchKey,"Comp_Genotype","Mismatching_Alleles");
+ concordanceCompProportions.set(mismatchKey,"Sample",entry.getKey());
+ concordanceCompProportions.set(mismatchKey,"Eval_Genotype","Mismatching_Alleles");
+ concordanceCompProportions.set(mismatchKey,"Comp_Genotype","Mismatching_Alleles");
+ concordanceEvalProportions.set(mismatchKey,"Proportion", repairNaN(( (double) table.getnMismatchingAlt() )/table.getnCalledEvalGenotypes()));
+ concordanceCompProportions.set(mismatchKey,"Proportion", repairNaN(( (double) table.getnMismatchingAlt() )/table.getnCalledCompGenotypes()));
+ concordanceCounts.set(mismatchKey,"Count",table.getnMismatchingAlt());
+ }
+
+ String sampleKey = "ALL";
+ ConcordanceMetrics.GenotypeConcordanceTable table = metrics.getOverallGenotypeConcordance();
+ for ( GenotypeType evalType : GenotypeType.values() ) {
+ for ( GenotypeType compType : GenotypeType.values() ) {
+ String rowKey = String.format("%s_%s_%s",sampleKey,evalType.toString(),compType.toString());
+ concordanceCounts.set(rowKey,"Sample",sampleKey);
+ concordanceCounts.set(rowKey,"Eval_Genotype",evalType.toString());
+ concordanceCounts.set(rowKey,"Comp_Genotype",compType.toString());
+ int count = table.get(evalType, compType);
+ concordanceCounts.set(rowKey,"Count",count);
+ if ( evalType == GenotypeType.HET || evalType == GenotypeType.HOM_REF || evalType == GenotypeType.HOM_VAR) {
+ concordanceEvalProportions.set(rowKey,"Sample",sampleKey);
+ concordanceEvalProportions.set(rowKey,"Eval_Genotype",evalType.toString());
+ concordanceEvalProportions.set(rowKey,"Comp_Genotype",compType.toString());
+ concordanceEvalProportions.set(rowKey,"Proportion",repairNaN(( (double) count)/table.getnEvalGenotypes(evalType)));
+ }
+ if ( compType == GenotypeType.HET || compType == GenotypeType.HOM_VAR || compType == GenotypeType.HOM_REF ) {
+ concordanceCompProportions.set(rowKey,"Sample",sampleKey);
+ concordanceCompProportions.set(rowKey,"Eval_Genotype",evalType.toString());
+ concordanceCompProportions.set(rowKey,"Comp_Genotype",compType.toString());
+ concordanceCompProportions.set(rowKey,"Proportion",repairNaN(( (double) count)/table.getnCompGenotypes(compType)));
+ }
+ }
+ }
+ String rowKey = String.format("%s_%s",sampleKey,"Mismatching");
+ concordanceCounts.set(rowKey,"Sample",sampleKey);
+ concordanceCounts.set(rowKey,"Eval_Genotype","Mismatching_Alleles");
+ concordanceCounts.set(rowKey,"Comp_Genotype","Mismatching_Alleles");
+ concordanceEvalProportions.set(rowKey,"Sample",sampleKey);
+ concordanceEvalProportions.set(rowKey,"Eval_Genotype","Mismatching_Alleles");
+ concordanceEvalProportions.set(rowKey,"Comp_Genotype","Mismatching_Alleles");
+ concordanceCompProportions.set(rowKey,"Sample",sampleKey);
+ concordanceCompProportions.set(rowKey,"Eval_Genotype","Mismatching_Alleles");
+ concordanceCompProportions.set(rowKey,"Comp_Genotype","Mismatching_Alleles");
+ concordanceEvalProportions.set(rowKey,"Proportion", repairNaN(( (double) table.getnMismatchingAlt() )/table.getnCalledEvalGenotypes()));
+ concordanceCompProportions.set(rowKey,"Proportion", repairNaN(( (double) table.getnMismatchingAlt() )/table.getnCalledCompGenotypes()));
+ concordanceCounts.set(rowKey,"Count",table.getnMismatchingAlt());
+
+ for ( Map.Entry<String,Double> nrsEntry : metrics.getPerSampleNRS().entrySet() ) {
+ concordanceSummary.set(nrsEntry.getKey(),"Sample",nrsEntry.getKey());
+ concordanceSummary.set(nrsEntry.getKey(),"Non-Reference_Sensitivity",nrsEntry.getValue());
+ }
+ for ( Map.Entry<String,Double> nrdEntry : metrics.getPerSampleNRD().entrySet() ) {
+ concordanceSummary.set(nrdEntry.getKey(),"Non-Reference_Discrepancy",nrdEntry.getValue());
+ }
+ for ( Map.Entry<String,Double> ogcEntry : metrics.getPerSampleOGC().entrySet() ) {
+ concordanceSummary.set(ogcEntry.getKey(),"Overall_Genotype_Concordance",ogcEntry.getValue());
+ }
+ concordanceSummary.set("ALL_NRS_NRD","Sample","ALL");
+ concordanceSummary.set("ALL_NRS_NRD","Non-Reference_Sensitivity",metrics.getOverallNRS());
+ concordanceSummary.set("ALL_NRS_NRD","Non-Reference_Discrepancy",metrics.getOverallNRD());
+ concordanceSummary.set("ALL_NRS_NRD","Overall_Genotype_Concordance",metrics.getOverallOGC());
+
+
+ for (ConcordanceMetrics.SiteConcordanceType type : ConcordanceMetrics.SiteConcordanceType.values() ) {
+ siteConcordance.addColumn(type.toString(),"%d");
+ }
+
+ for (ConcordanceMetrics.SiteConcordanceType type : ConcordanceMetrics.SiteConcordanceType.values() ) {
+ siteConcordance.set("Comparison",type.toString(),metrics.getOverallSiteConcordance().get(type));
+ }
+
+ } else {
+ concordanceCompProportions.addColumn("Sample","%s");
+ concordanceCounts.addColumn("Sample","%s");
+ concordanceEvalProportions.addColumn("Sample","%s");
+ concordanceSummary.addColumn("Sample","%s");
+ for ( GenotypeType evalType : GenotypeType.values() ) {
+ for ( GenotypeType compType : GenotypeType.values() ) {
+ String colKey = String.format("%s_%s", evalType.toString(), compType.toString());
+ concordanceCounts.addColumn(colKey,"%d");
+ if ( evalType == GenotypeType.HET || evalType == GenotypeType.HOM_REF || evalType == GenotypeType.HOM_VAR)
+ concordanceEvalProportions.addColumn(colKey,"%.3f");
+ if ( compType == GenotypeType.HET || compType == GenotypeType.HOM_VAR || compType == GenotypeType.HOM_REF )
+ concordanceCompProportions.addColumn(colKey,"%.3f");
+ }
+ }
+ concordanceEvalProportions.addColumn("Mismatching_Alleles","%.3f");
+ concordanceCompProportions.addColumn("Mismatching_Alleles","%.3f");
+ concordanceCounts.addColumn("Mismatching_Alleles","%d");
+ concordanceSummary.addColumn("Non-Reference Sensitivity","%.3f");
+ concordanceSummary.addColumn("Non-Reference Discrepancy","%.3f");
+ concordanceSummary.addColumn("Overall_Genotype_Concordance","%.3f");
+ for (ConcordanceMetrics.SiteConcordanceType type : ConcordanceMetrics.SiteConcordanceType.values() ) {
+ siteConcordance.addColumn(type.toString(),"%d");
+ }
+
+ for ( Map.Entry<String,ConcordanceMetrics.GenotypeConcordanceTable> entry : metrics.getPerSampleGenotypeConcordance().entrySet() ) {
+ ConcordanceMetrics.GenotypeConcordanceTable table = entry.getValue();
+ concordanceEvalProportions.set(entry.getKey(),"Sample",entry.getKey());
+ concordanceCompProportions.set(entry.getKey(),"Sample",entry.getKey());
+ concordanceCounts.set(entry.getKey(),"Sample",entry.getKey());
+ for ( GenotypeType evalType : GenotypeType.values() ) {
+ for ( GenotypeType compType : GenotypeType.values() ) {
+ String colKey = String.format("%s_%s",evalType.toString(),compType.toString());
+ int count = table.get(evalType, compType);
+ concordanceCounts.set(entry.getKey(),colKey,count);
+ if ( evalType == GenotypeType.HET || evalType == GenotypeType.HOM_REF || evalType == GenotypeType.HOM_VAR)
+ concordanceEvalProportions.set(entry.getKey(),colKey,repairNaN(( (double) count)/table.getnEvalGenotypes(evalType)));
+ if ( compType == GenotypeType.HET || compType == GenotypeType.HOM_VAR || compType == GenotypeType.HOM_REF )
+ concordanceCompProportions.set(entry.getKey(),colKey,repairNaN(( (double) count)/table.getnCompGenotypes(compType)));
+ }
+ }
+ concordanceEvalProportions.set(entry.getKey(),"Mismatching_Alleles", repairNaN(( (double) table.getnMismatchingAlt() )/table.getnCalledEvalGenotypes()));
+ concordanceCompProportions.set(entry.getKey(),"Mismatching_Alleles", repairNaN(( (double) table.getnMismatchingAlt() )/table.getnCalledCompGenotypes()));
+ concordanceCounts.set(entry.getKey(),"Mismatching_Alleles",table.getnMismatchingAlt());
+ }
+
+ String rowKey = "ALL";
+ concordanceCompProportions.set(rowKey,"Sample",rowKey);
+ concordanceEvalProportions.set(rowKey,"Sample",rowKey);
+ concordanceCounts.set(rowKey,"Sample",rowKey);
+ ConcordanceMetrics.GenotypeConcordanceTable table = metrics.getOverallGenotypeConcordance();
+ for ( GenotypeType evalType : GenotypeType.values() ) {
+ for ( GenotypeType compType : GenotypeType.values() ) {
+ String colKey = String.format("%s_%s",evalType.toString(),compType.toString());
+ int count = table.get(evalType,compType);
+ concordanceCounts.set(rowKey,colKey,count);
+ if ( evalType == GenotypeType.HET || evalType == GenotypeType.HOM_REF || evalType == GenotypeType.HOM_VAR)
+ concordanceEvalProportions.set(rowKey,colKey,repairNaN(( (double) count)/table.getnEvalGenotypes(evalType)));
+ if ( compType == GenotypeType.HET || compType == GenotypeType.HOM_VAR || compType == GenotypeType.HOM_REF )
+ concordanceCompProportions.set(rowKey,colKey,repairNaN(( (double) count)/table.getnCompGenotypes(compType)));
+ }
+ }
+ concordanceEvalProportions.set(rowKey,"Mismatching_Alleles", repairNaN(( (double) table.getnMismatchingAlt() )/table.getnCalledEvalGenotypes()));
+ concordanceCompProportions.set(rowKey,"Mismatching_Alleles", repairNaN(( (double) table.getnMismatchingAlt() )/table.getnCalledCompGenotypes()));
+ concordanceCounts.set(rowKey,"Mismatching_Alleles",table.getnMismatchingAlt());
+
+ for ( Map.Entry<String,Double> nrsEntry : metrics.getPerSampleNRS().entrySet() ) {
+ concordanceSummary.set(nrsEntry.getKey(),"Sample",nrsEntry.getKey());
+ concordanceSummary.set(nrsEntry.getKey(),"Non-Reference Sensitivity",nrsEntry.getValue());
+ }
+ for ( Map.Entry<String,Double> nrdEntry : metrics.getPerSampleNRD().entrySet() ) {
+ concordanceSummary.set(nrdEntry.getKey(),"Non-Reference Discrepancy",nrdEntry.getValue());
+ }
+ for ( Map.Entry<String,Double> ogcEntry : metrics.getPerSampleOGC().entrySet() ) {
+ concordanceSummary.set(ogcEntry.getKey(),"Overall_Genotype_Concordance",ogcEntry.getValue());
+ }
+ concordanceSummary.set("ALL","Sample","ALL");
+ concordanceSummary.set("ALL","Non-Reference Sensitivity",metrics.getOverallNRS());
+ concordanceSummary.set("ALL","Non-Reference Discrepancy",metrics.getOverallNRD());
+ concordanceSummary.set("ALL","Overall_Genotype_Concordance",metrics.getOverallOGC());
+
+ for (ConcordanceMetrics.SiteConcordanceType type : ConcordanceMetrics.SiteConcordanceType.values() ) {
+ siteConcordance.set("Comparison",type.toString(),metrics.getOverallSiteConcordance().get(type));
+ }
+ }
+
+ report.addTable(concordanceCompProportions);
+ report.addTable(concordanceEvalProportions);
+ report.addTable(concordanceCounts);
+ report.addTable(concordanceSummary);
+ report.addTable(siteConcordance);
+
+ report.print(out);
+ }
+
+ public VariantContext createEmptyContext(VariantContext other, List<String> samples) {
+ VariantContextBuilder builder = new VariantContextBuilder();
+ // set the alleles to be the same
+ builder.alleles(other.getAlleles());
+ builder.loc(other.getChr(),other.getStart(),other.getEnd());
+ // set all genotypes to empty
+ List<Genotype> genotypes = new ArrayList<Genotype>(samples.size());
+ for ( String sample : samples )
+ genotypes.add(GenotypeBuilder.create(sample, new ArrayList<Allele>(0)));
+ builder.genotypes(genotypes);
+ return builder.make();
+ }
+
+ public VariantContext filterGenotypes(VariantContext context, boolean ignoreSiteFilter, List<VariantContextUtils.JexlVCMatchExp> exps) {
+ if ( ! context.isFiltered() || ignoreSiteFilter ) {
+ List<Genotype> filteredGenotypes = new ArrayList<Genotype>(context.getNSamples());
+ for ( Genotype g : context.getGenotypes() ) {
+ Map<VariantContextUtils.JexlVCMatchExp, Boolean> matchMap = VariantContextUtils.match(context, g, exps);
+ boolean filtered = false;
+ for ( Boolean b : matchMap.values() ) {
+ if ( b ) {
+ filtered = true;
+ break;
+ }
+ }
+ if ( filtered ) {
+ filteredGenotypes.add(GenotypeBuilder.create(g.getSampleName(),Arrays.asList(Allele.NO_CALL,Allele.NO_CALL),g.getExtendedAttributes()));
+ } else {
+ filteredGenotypes.add(g);
+ }
+ }
+ VariantContextBuilder builder = new VariantContextBuilder(context);
+ builder.genotypes(filteredGenotypes);
+ return builder.make();
+ }
+
+ VariantContextBuilder builder = new VariantContextBuilder();
+ builder.alleles(Arrays.asList(context.getReference()));
+ builder.loc(context.getChr(),context.getStart(),context.getEnd());
+ List<Genotype> newGeno = new ArrayList<Genotype>(context.getNSamples());
+ for ( Genotype g : context.getGenotypes().iterateInSampleNameOrder() ) {
+ newGeno.add(GenotypeBuilder.create(g.getSampleName(),new ArrayList<Allele>()));
+ }
+ builder.genotypes(newGeno);
+ return builder.make();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/LeftAlignAndTrimVariants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/LeftAlignAndTrimVariants.java
new file mode 100644
index 0000000..6410478
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/LeftAlignAndTrimVariants.java
@@ -0,0 +1,303 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.ArgumentCollection;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.Reference;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.Window;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.sam.AlignmentUtils;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.variantcontext.writer.VariantContextWriterFactory;
+
+import java.util.*;
+
+/**
+ * Left-aligns indels from a variants file.
+ *
+ * <p>
+ * LeftAlignAndTrimVariants is a tool that takes a VCF file and left-aligns the indels inside it. The same indel can often be
+ * placed at multiple positions and still represent the same haplotype. While the standard convention with VCF is to
+ * place an indel at the left-most position this doesn't always happen, so this tool can be used to left-align them.
+ * Note that this tool cannot handle anything other than bi-allelic, simple indels. Complex events are written out unchanged.
+ * Optionally, the tool will also trim common bases from indels, leaving them with a minimum representation.
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A variant set to left-align and trim.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A left-aligned VCF.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T LeftAlignAndTrimVariants \
+ * --variant input.vcf \
+ * -o output.vcf
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+ at Reference(window=@Window(start=-200,stop=200)) // WARNING: if this changes,MAX_INDEL_LENGTH needs to change as well!
+public class LeftAlignAndTrimVariants extends RodWalker<Integer, Integer> {
+
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ /**
+ * If this argument is set, bases common to all alleles will be removed, leaving only their minimal representation.
+ */
+ @Argument(fullName="trimAlleles", shortName="trim", doc="Trim alleles to remove bases common to all of them", required=false)
+ protected boolean trimAlleles = false;
+
+ /**
+ * If this argument is set, split multiallelic records and left-align individual alleles.
+ * If this argument is not set, multiallelic records are not attempted to left-align and will be copied as is.
+ */
+ @Argument(fullName="splitMultiallelics", shortName="split", doc="Split multiallelic records and left-align individual alleles", required=false)
+ protected boolean splitMultiallelics = false;
+
+
+ @Output(doc="File to which variants should be written")
+ protected VariantContextWriter baseWriter = null;
+
+ private VariantContextWriter writer;
+
+ private static final int MAX_INDEL_LENGTH = 200; // needs to match reference window size!
+ public void initialize() {
+ String trackName = variantCollection.variants.getName();
+ Set<String> samples = SampleUtils.getSampleListWithVCFHeader(getToolkit(), Arrays.asList(trackName));
+ Map<String, VCFHeader> vcfHeaders = GATKVCFUtils.getVCFHeadersFromRods(getToolkit(), Arrays.asList(trackName));
+
+ Set<VCFHeaderLine> headerLines = vcfHeaders.get(trackName).getMetaDataInSortedOrder();
+ baseWriter.writeHeader(new VCFHeader(headerLines, samples));
+
+ writer = VariantContextWriterFactory.sortOnTheFly(baseWriter, 200);
+ }
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null )
+ return 0;
+
+ Collection<VariantContext> VCs = tracker.getValues(variantCollection.variants, context.getLocation());
+
+ int changedSites = 0;
+ for ( final VariantContext vc : VCs ) {
+ // split first into biallelics, and optionally trim alleles to minimal representation
+ Pair<VariantContext,Integer> result = new Pair<VariantContext, Integer>(vc,0); // default value
+ if (splitMultiallelics) {
+ final List<VariantContext> vcList = GATKVariantContextUtils.splitVariantContextToBiallelics(vc);
+ for (final VariantContext biallelicVC: vcList) {
+ final VariantContext v = (trimAlleles ? GATKVariantContextUtils.trimAlleles(biallelicVC,true,true) : biallelicVC);
+ result = alignAndWrite(v, ref);
+
+ // strip out PLs and AD if we've subsetted the alleles
+ if ( vcList.size() > 1 )
+ result.first = new VariantContextBuilder(result.first).genotypes(GATKVariantContextUtils.stripPLsAndAD(result.first.getGenotypes())).make();
+
+ writer.add(result.first);
+ changedSites += result.second;
+ }
+ }
+ else {
+ if (trimAlleles)
+ result = alignAndWrite(GATKVariantContextUtils.trimAlleles(vc,true,true), ref);
+ else
+ result = alignAndWrite(vc,ref);
+ writer.add(result.first);
+ changedSites += result.second;
+
+ }
+
+ }
+
+ return changedSites;
+ }
+
+ public Integer reduceInit() { return 0; }
+
+ public Integer reduce(Integer value, Integer sum) {
+ return sum + value;
+ }
+
+ public void onTraversalDone(Integer result) {
+ writer.close();
+ System.out.println(result + " variants were aligned");
+ }
+
+ /**
+ * Main routine workhorse. By definitio, it will only take biallelic vc's. Splitting into multiple alleles has to be
+ * handled by calling routine.
+ * @param vc Input VC with variants to left align
+ * @param ref Reference context
+ * @return # of records left-aligned (0 or 1) and new VC.
+ */
+ @Requires({"vc != null","ref != null", "vc.isBiallelic() == true","ref.getBases().length>=2*MAX_INDEL_LENGTH+1"})
+ @Ensures({"result != null","result.first != null", "result.second >=0"})
+ protected static Pair<VariantContext,Integer> alignAndWrite(final VariantContext vc, final ReferenceContext ref) {
+
+ final Pair<VariantContext, Integer> retValue = new Pair<VariantContext, Integer>(vc,0);
+ if (!vc.isIndel() || vc.isComplexIndel() ) {
+ return retValue;
+ }
+
+ // get the indel length
+ final int indelLength;
+ if ( vc.isSimpleDeletion() )
+ indelLength = vc.getReference().length() - 1;
+ else
+ indelLength = vc.getAlternateAllele(0).length() - 1;
+
+ if ( indelLength > MAX_INDEL_LENGTH )
+ return retValue;
+
+ if (vc.getReference().getBases()[0] != vc.getAlternateAllele(0).getBases()[0])
+ return retValue;
+
+ final byte[] refSeq = ref.getBases();
+
+ // create an indel haplotype.
+ //
+ final int originalIndex = vc.getStart() - ref.getWindow().getStart() + 1;
+ if (originalIndex < 0 || originalIndex >= ref.getBases().length)
+ return retValue;
+
+ final byte[] originalIndel = makeHaplotype(vc, refSeq, originalIndex, indelLength);
+
+ // create a CIGAR string to represent the event
+ ArrayList<CigarElement> elements = new ArrayList<CigarElement>();
+ elements.add(new CigarElement(originalIndex, CigarOperator.M));
+ elements.add(new CigarElement(indelLength, vc.isSimpleDeletion() ? CigarOperator.D : CigarOperator.I));
+ elements.add(new CigarElement(refSeq.length - originalIndex, CigarOperator.M));
+ Cigar originalCigar = new Cigar(elements);
+
+ // left align the CIGAR
+ Cigar newCigar = AlignmentUtils.leftAlignIndel(originalCigar, refSeq, originalIndel, 0, 0, true);
+
+ // update if necessary and write
+ if ( !newCigar.equals(originalCigar) && newCigar.numCigarElements() > 1 ) {
+ int difference = originalIndex - newCigar.getCigarElement(0).getLength();
+ VariantContext newVC = new VariantContextBuilder(vc).start(vc.getStart()-difference).stop(vc.getEnd()-difference).make();
+ //System.out.println("Moving record from " + vc.getChr()+":"+vc.getStart() + " to " + vc.getChr()+":"+(vc.getStart()-difference));
+
+ final int indelIndex = originalIndex-difference;
+ final byte[] newBases = new byte[indelLength + 1];
+ newBases[0] = refSeq[indelIndex-1];
+ System.arraycopy((vc.isSimpleDeletion() ? refSeq : originalIndel), indelIndex, newBases, 1, indelLength);
+ final Allele newAllele = Allele.create(newBases, vc.isSimpleDeletion());
+ newVC = updateAllele(newVC, newAllele);
+ // overwrite default return value with new left-aligned VC
+ retValue.first = newVC;
+ retValue.second = 1;
+
+ }
+ return retValue;
+ }
+
+ /**
+ * Make a haplotype from a given alt allele, using bases in input reference, index of an input reference
+ * @param vc Input VC - will use only alt allele from it
+ * @param ref Ref bases
+ * @param indexOfRef Index in ref where to create indel
+ * @param indelLength Indel length
+ * @return
+ */
+ @Requires({"vc != null","ref != null", "indexOfRef +indelLength < ref.length", "vc.getNAlleles() == 2"})
+ @Ensures("result != null")
+ private static byte[] makeHaplotype(VariantContext vc, byte[] ref, int indexOfRef, int indelLength) {
+ byte[] hap = new byte[ref.length + (indelLength * (vc.isSimpleDeletion() ? -1 : 1))];
+
+ // add the bases before the indel
+ System.arraycopy(ref, 0, hap, 0, indexOfRef);
+ int currentPos = indexOfRef;
+
+ // take care of the indel
+ if ( vc.isSimpleDeletion() ) {
+ indexOfRef += indelLength;
+ } else {
+ System.arraycopy(vc.getAlternateAllele(0).getBases(), 1, hap, currentPos, indelLength);
+ currentPos += indelLength;
+ }
+
+ // add the bases after the indel
+ System.arraycopy(ref, indexOfRef, hap, currentPos, ref.length - indexOfRef);
+
+ return hap;
+ }
+
+ public static VariantContext updateAllele(final VariantContext vc, final Allele newAllele) {
+ // create a mapping from original allele to new allele
+ HashMap<Allele, Allele> alleleMap = new HashMap<Allele, Allele>(vc.getAlleles().size());
+ if ( newAllele.isReference() ) {
+ alleleMap.put(vc.getReference(), newAllele);
+ alleleMap.put(vc.getAlternateAllele(0), Allele.create(newAllele.getBases()[0], false));
+ } else {
+ alleleMap.put(vc.getReference(), Allele.create(newAllele.getBases()[0], true));
+ alleleMap.put(vc.getAlternateAllele(0), newAllele);
+ }
+
+ // create new Genotype objects
+ GenotypesContext newGenotypes = GenotypesContext.create(vc.getNSamples());
+ for ( final Genotype genotype : vc.getGenotypes() ) {
+ List<Allele> newAlleles = new ArrayList<Allele>();
+ for ( Allele allele : genotype.getAlleles() ) {
+ Allele newA = alleleMap.get(allele);
+ if ( newA == null )
+ newA = Allele.NO_CALL;
+ newAlleles.add(newA);
+ }
+ newGenotypes.add(new GenotypeBuilder(genotype).alleles(newAlleles).make());
+ }
+
+ return new VariantContextBuilder(vc).alleles(alleleMap.values()).genotypes(newGenotypes).make();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/LiftoverVariants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/LiftoverVariants.java
new file mode 100644
index 0000000..710aad5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/LiftoverVariants.java
@@ -0,0 +1,179 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import htsjdk.samtools.liftover.LiftOver;
+import htsjdk.samtools.util.Interval;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMFileReader;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.ArgumentCollection;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.variantcontext.writer.Options;
+import htsjdk.variant.vcf.*;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.variantcontext.writer.VariantContextWriterFactory;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * Lifts a VCF file over from one build to another.
+ *
+ * "Lifting over" variants means adjusting variant calls from one reference to another. Specifically, the process adjusts the position of the call to match the corresponding position on the target reference.
+ * For example, if you have variants called from reads aligned to the hg19 reference, and you want to compare them to calls made based on the b37 reference, you need to liftover one of the callsets to the other reference.
+ *
+ * LiftoverVariants is intended to be the first of two processing steps for the liftover process.
+ * The second step is to run FilterLiftedVariants on the output of LiftoverVariants. This will produce valid well-behaved VCF files, where you'll see that the contig names in the header have all been correctly replaced.
+ *
+ * To be clear, the VCF resulting from the LiftoverVariants run is not guaranteed to be valid according to the official specification. The file could
+ * possibly be mis-sorted and the header may not be complete. That is why you need to run FilterLiftedVariants on it.
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+public class LiftoverVariants extends RodWalker<Integer, Integer> {
+
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ @Output(doc="File to which variants should be written", required=true, defaultToStdout=false)
+ protected File file = null;
+ protected VariantContextWriter writer = null;
+
+ @Argument(fullName="chain", shortName="chain", doc="Chain file", required=true)
+ protected File CHAIN = null;
+
+ @Argument(fullName="newSequenceDictionary", shortName="dict", doc="Sequence .dict file for the new build", required=true)
+ protected File NEW_SEQ_DICT = null;
+
+ @Argument(fullName="recordOriginalLocation", shortName="recordOriginalLocation", doc="Should we record what the original location was in the INFO field?", required=false)
+ protected Boolean RECORD_ORIGINAL_LOCATION = false;
+
+ private LiftOver liftOver;
+
+ private long successfulIntervals = 0, failedIntervals = 0;
+
+ public void initialize() {
+ try {
+ liftOver = new LiftOver(CHAIN);
+ } catch (RuntimeException e) {
+ throw new UserException.BadInput("there is a problem with the chain file you are using: " + e.getMessage());
+ }
+
+ liftOver.setLiftOverMinMatch(LiftOver.DEFAULT_LIFTOVER_MINMATCH);
+
+ try {
+ final SAMFileHeader toHeader = new SAMFileReader(NEW_SEQ_DICT).getFileHeader();
+ liftOver.validateToSequences(toHeader.getSequenceDictionary());
+ } catch (RuntimeException e) {
+ throw new UserException.BadInput("the chain file you are using is not compatible with the reference you are trying to lift over to; please use the appropriate chain file for the given reference");
+ }
+
+ String trackName = variantCollection.variants.getName();
+ Set<String> samples = SampleUtils.getSampleListWithVCFHeader(getToolkit(), Arrays.asList(trackName));
+ Map<String, VCFHeader> vcfHeaders = GATKVCFUtils.getVCFHeadersFromRods(getToolkit(), Arrays.asList(trackName));
+
+ Set<VCFHeaderLine> metaData = new HashSet<VCFHeaderLine>();
+ if ( vcfHeaders.containsKey(trackName) )
+ metaData.addAll(vcfHeaders.get(trackName).getMetaDataInSortedOrder());
+ if ( RECORD_ORIGINAL_LOCATION ) {
+ metaData.add(new VCFInfoHeaderLine("OriginalChr", 1, VCFHeaderLineType.String, "Original contig name for the record"));
+ metaData.add(new VCFInfoHeaderLine("OriginalStart", 1, VCFHeaderLineType.Integer, "Original start position for the record"));
+ }
+
+
+ final VCFHeader vcfHeader = new VCFHeader(metaData, samples);
+ writer = VariantContextWriterFactory.create(file, getMasterSequenceDictionary(), EnumSet.of(Options.ALLOW_MISSING_FIELDS_IN_HEADER));
+ writer.writeHeader(vcfHeader);
+ }
+
+ private void convertAndWrite(VariantContext vc, ReferenceContext ref) {
+
+ final Interval fromInterval = new Interval(vc.getChr(), vc.getStart(), vc.getStart(), false, String.format("%s:%d", vc.getChr(), vc.getStart()));
+ final int length = vc.getEnd() - vc.getStart();
+ final Interval toInterval = liftOver.liftOver(fromInterval);
+ VariantContext originalVC = vc;
+
+ if ( toInterval != null ) {
+ // check whether the strand flips, and if so reverse complement everything
+ if ( fromInterval.isPositiveStrand() != toInterval.isPositiveStrand() && vc.isPointEvent() ) {
+ vc = GATKVariantContextUtils.reverseComplement(vc);
+ }
+
+ vc = new VariantContextBuilder(vc).loc(toInterval.getSequence(), toInterval.getStart(), toInterval.getStart() + length).make();
+
+ if ( RECORD_ORIGINAL_LOCATION ) {
+ vc = new VariantContextBuilder(vc)
+ .attribute("OriginalChr", fromInterval.getSequence())
+ .attribute("OriginalStart", fromInterval.getStart()).make();
+ }
+
+ if ( originalVC.isSNP() && originalVC.isBiallelic() && GATKVariantContextUtils.getSNPSubstitutionType(originalVC) != GATKVariantContextUtils.getSNPSubstitutionType(vc) ) {
+ logger.warn(String.format("VCF at %s / %d => %s / %d is switching substitution type %s/%s to %s/%s",
+ originalVC.getChr(), originalVC.getStart(), vc.getChr(), vc.getStart(),
+ originalVC.getReference(), originalVC.getAlternateAllele(0), vc.getReference(), vc.getAlternateAllele(0)));
+ }
+
+ writer.add(vc);
+ successfulIntervals++;
+ } else {
+ failedIntervals++;
+ }
+ }
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null )
+ return 0;
+
+ Collection<VariantContext> VCs = tracker.getValues(variantCollection.variants, context.getLocation());
+ for ( VariantContext vc : VCs )
+ convertAndWrite(vc, ref);
+
+ return 0;
+ }
+
+ public Integer reduceInit() { return 0; }
+
+ public Integer reduce(Integer value, Integer sum) { return 0; }
+
+ public void onTraversalDone(Integer result) {
+ System.out.println("Converted " + successfulIntervals + " records; failed to convert " + failedIntervals + " records.");
+ writer.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/RandomlySplitVariants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/RandomlySplitVariants.java
new file mode 100644
index 0000000..d50b4f2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/RandomlySplitVariants.java
@@ -0,0 +1,165 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.ArgumentCollection;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.variantcontext.writer.VariantContextWriterFactory;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * Takes a VCF file, randomly splits variants into two different sets, and outputs 2 new VCFs with the results.
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+public class RandomlySplitVariants extends RodWalker<Integer, Integer> {
+
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ @Output(fullName="out1", shortName="o1", doc="File #1 to which variants should be written", required=false, exclusiveOf = "splitToManyFiles")
+ protected VariantContextWriter vcfWriter1 = null;
+
+ @Output(fullName="out2", shortName="o2", doc="File #2 to which variants should be written", required=false, exclusiveOf = "splitToManyFiles")
+ // there's a reported bug in the GATK where we can't have 2 @Output writers
+ protected File file2 = null;
+ protected VariantContextWriter vcfWriter2 = null;
+
+ @Argument(fullName="fractionToOut1", shortName="fraction", doc="Fraction of records to be placed in out1 (must be 0 >= fraction <= 1); all other records are placed in out2", required=false)
+ protected double fraction = 0.5;
+
+ @Argument(fullName="splitToManyFiles", shortName = "splitToMany", doc="split (with uniform distribution) to more than 2 files. numOfFiles and baseOutputName parameters are required", required = false)
+ protected boolean splitToMany = false;
+
+ @Argument(fullName = "numOfOutputVCFFiles", shortName = "N", doc = "number of output VCF files. Only works with SplitToMany = true", required = false, maxRecommendedValue = 20, minValue = 2)
+ protected int numOfFiles = -1;
+
+ @Argument(fullName = "prefixForAllOutputFileNames", shortName = "baseOutputName", doc = "the name of the output VCF file will be: <baseOutputName>.split.<number>.vcf. Required with SplitToMany option", required = false)
+ protected String baseFileName = null;
+
+ private VariantContextWriter[] writers = null;
+
+ /**
+ * Set up the VCF writer, the sample expressions and regexs, and the JEXL matcher
+ */
+ public void initialize() {
+ if ( fraction < 0.0 || fraction > 1.0 )
+ throw new UserException.BadArgumentValue("fractionToOut1", "this value needs to be a number between 0 and 1");
+
+ if (splitToMany){
+ if (numOfFiles < 2)
+ throw new UserException.BadArgumentValue("numOfFiles", "this value must be greater than 2 when using the splitToMany option");
+ if (baseFileName == null)
+ throw new UserException.BadArgumentValue("baseFileName", "this value cannot be null (unprovided) when using the splitToMany option");
+ }
+ else{
+ if(vcfWriter1 == null || vcfWriter2 == null)
+ throw new UserException.BadArgumentValue("out1 or out2", "this value cannot be null (unprovided) unless you are using the splitToMany option");
+ }
+
+ // setup the header info
+ final List<String> inputNames = Arrays.asList(variantCollection.variants.getName());
+ final Set<String> samples = SampleUtils.getUniqueSamplesFromRods(getToolkit(), inputNames);
+ final Set<VCFHeaderLine> hInfo = new HashSet<>();
+ hInfo.addAll(GATKVCFUtils.getHeaderFields(getToolkit(), inputNames));
+
+
+ if(splitToMany){
+ writers = new VariantContextWriter[numOfFiles];
+ for(int i = 0; i<writers.length; i++){
+ writers[i] = VariantContextWriterFactory.create(new File(baseFileName+".split."+i+".vcf"), getMasterSequenceDictionary());
+ writers[i].writeHeader(new VCFHeader(hInfo,samples));
+ }
+
+ }
+ else {
+ vcfWriter1.writeHeader(new VCFHeader(hInfo, samples));
+ vcfWriter2 = VariantContextWriterFactory.create(file2, getMasterSequenceDictionary());
+ vcfWriter2.writeHeader(new VCFHeader(hInfo, samples));
+ }
+ }
+
+ /**
+ * Subset VC record if necessary and emit the modified record (provided it satisfies criteria for printing)
+ *
+ * @param tracker the ROD tracker
+ * @param ref reference information
+ * @param context alignment info
+ * @return 1 if the record was printed to the output file, 0 if otherwise
+ */
+ public Integer map(final RefMetaDataTracker tracker, final ReferenceContext ref, final AlignmentContext context) {
+ if ( tracker == null )
+ return 0;
+
+ final Collection<VariantContext> vcs = tracker.getValues(variantCollection.variants, context.getLocation());
+ for ( final VariantContext vc : vcs ) {
+ final double random = GenomeAnalysisEngine.getRandomGenerator().nextDouble();
+ if(splitToMany){
+ final int index = (int)(numOfFiles * random);
+ writers[index].add(vc);
+ }
+ else{
+ if ( random < fraction )
+ vcfWriter1.add(vc);
+ else
+ vcfWriter2.add(vc);
+ }
+ }
+
+ return 1;
+ }
+
+ public Integer reduceInit() { return 0; }
+
+ public Integer reduce(final Integer value, final Integer sum) { return value + sum; }
+
+ public void onTraversalDone(final Integer result) {
+ logger.info(result + " records processed.");
+ if(splitToMany)
+ for(final VariantContextWriter writer: writers)
+ writer.close();
+ else
+ vcfWriter2.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/SelectHeaders.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/SelectHeaders.java
new file mode 100644
index 0000000..c9842c8
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/SelectHeaders.java
@@ -0,0 +1,278 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import org.apache.commons.io.FilenameUtils;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.interval.IntervalSetRule;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.vcf.*;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import org.broadinstitute.gatk.utils.text.ListFileUtils;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * Selects headers from a VCF source.
+ * <p/>
+ * <p>
+ * Often, a VCF containing many headers will need to be subset in order to facilitate certain formatting guidelines.
+ * SelectHeaders can be used for this purpose. Given a single VCF file, one or more headers can be extracted from the
+ * file (based on a complete header name or a pattern match).
+ * <p/>
+ * <h3>Input</h3>
+ * <p>
+ * A set of VCFs.
+ * </p>
+ * <p/>
+ * <h3>Output</h3>
+ * <p>
+ * A header selected VCF.
+ * </p>
+ * <p/>
+ * <h3>Examples</h3>
+ * <pre>
+ * Select only the FILTER, FORMAT, and INFO headers:
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectHeaders \
+ * --variant input.vcf \
+ * -o output.vcf \
+ * -hn FILTER \
+ * -hn FORMAT \
+ * -hn INFO
+ *
+ * Select only the FILTER, FORMAT, and INFO headers and add in the reference file names:
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectHeaders \
+ * --variant input.vcf \
+ * -o output.vcf \
+ * -hn FILTER \
+ * -hn FORMAT \
+ * -hn INFO \
+ * -irn \
+ * -iln
+ *
+ * Select only the FILTER, FORMAT, and INFO headers, plus any headers with SnpEff:
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectHeaders \
+ * --variant input.vcf \
+ * -o output.vcf \
+ * -hn FILTER \
+ * -hn FORMAT \
+ * -hn INFO \
+ * -he '.*SnpEff.*'
+ * </pre>
+ */
+ at SuppressWarnings("unused")
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+public class SelectHeaders extends RodWalker<Integer, Integer> implements TreeReducible<Integer> {
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ @Output(doc = "File to which variants should be written")
+ protected VariantContextWriter vcfWriter;
+
+ @Argument(fullName = "header_name", shortName = "hn", doc = "Include header. Can be specified multiple times", required = false)
+ public Set<String> headerNames;
+
+ @Argument(fullName = "header_expression", shortName = "he", doc = "Regular expression to select many headers from the tracks provided. Can be specified multiple times", required = false)
+ public Set<String> headerExpressions;
+
+ /**
+ * Note that header exclusion takes precedence over inclusion, so that if a header is in both lists it will be excluded.
+ */
+ @Argument(fullName = "exclude_header_name", shortName = "xl_hn", doc = "Exclude header. Can be specified multiple times", required = false)
+ public Set<String> XLheaderNames;
+
+ /**
+ * Note that interval name inclusion takes precedence over other header matching. If set other interval lines may be excluded but the intervals will still be added.
+ */
+ @Argument(fullName = "include_interval_names", shortName = "iln", doc = "If set the interval file name minus the file extension, or the command line intervals, will be added to the headers", required = false)
+ public boolean includeIntervals;
+
+ /**
+ * Note that engine header inclusion takes precedence over other header matching. If set other engine lines may be excluded but the intervals will still be added.
+ */
+ @Hidden // TODO: Determine if others find this valuable and either remove @Hidden or remove -ieh.
+ @Argument(fullName = "include_engine_headers", shortName = "ieh", doc = "If set the headers normally output by the engine will be added to the headers", required = false)
+ public boolean includeEngineHeaders;
+
+ private static final ListFileUtils.StringConverter<VCFHeaderLine> headerKey = new ListFileUtils.StringConverter<VCFHeaderLine>() {
+ @Override
+ public String convert(VCFHeaderLine value) {
+ return value.getKey();
+ }
+ };
+
+ /**
+ * Set up the VCF writer, the header expressions and regexps
+ */
+ @Override
+ public void initialize() {
+ // Get list of samples to include in the output
+ List<String> rodNames = Arrays.asList(variantCollection.variants.getName());
+
+ Map<String, VCFHeader> vcfRods = GATKVCFUtils.getVCFHeadersFromRods(getToolkit(), rodNames);
+ Set<VCFHeaderLine> headerLines = VCFUtils.smartMergeHeaders(vcfRods.values(), true);
+
+ headerLines.add(new VCFHeaderLine(VCFHeader.SOURCE_KEY, "SelectHeaders"));
+
+ // Select only the headers requested by name or expression.
+ headerLines = new LinkedHashSet<VCFHeaderLine>(getSelectedHeaders(headerLines));
+
+ // Optionally add in the intervals.
+ if (includeIntervals) {
+ IntervalArgumentCollection intervalArguments = getToolkit().getArguments().intervalArguments;
+ if (intervalArguments.intervals != null) {
+ for (IntervalBinding<Feature> intervalBinding : intervalArguments.intervals) {
+ String source = intervalBinding.getSource();
+ if (source == null)
+ continue;
+ File file = new File(source);
+ if (file.exists()) {
+ headerLines.add(new VCFHeaderLine(VCFHeader.INTERVALS_KEY, FilenameUtils.getBaseName(file.getName())));
+ } else {
+ headerLines.add(new VCFHeaderLine(VCFHeader.INTERVALS_KEY, source));
+ }
+ }
+ }
+
+ if (intervalArguments.excludeIntervals != null) {
+ for (IntervalBinding<Feature> intervalBinding : intervalArguments.excludeIntervals) {
+ String source = intervalBinding.getSource();
+ if (source == null)
+ continue;
+ File file = new File(source);
+ if (file.exists()) {
+ headerLines.add(new VCFHeaderLine(VCFHeader.EXCLUDE_INTERVALS_KEY, FilenameUtils.getBaseName(file.getName())));
+ } else {
+ headerLines.add(new VCFHeaderLine(VCFHeader.EXCLUDE_INTERVALS_KEY, source));
+ }
+ }
+ }
+
+ if (intervalArguments.intervalMerging != IntervalMergingRule.ALL) {
+ headerLines.add(new VCFHeaderLine(VCFHeader.INTERVAL_MERGING_KEY, String.valueOf(intervalArguments.intervalMerging)));
+ }
+
+ if (intervalArguments.intervalSetRule != IntervalSetRule.UNION) {
+ headerLines.add(new VCFHeaderLine(VCFHeader.INTERVAL_SET_RULE_KEY, String.valueOf(intervalArguments.intervalSetRule)));
+ }
+
+ if (intervalArguments.intervalPadding != 0) {
+ headerLines.add(new VCFHeaderLine(VCFHeader.INTERVAL_PADDING_KEY, String.valueOf(intervalArguments.intervalPadding)));
+ }
+ }
+
+ TreeSet<String> vcfSamples = new TreeSet<String>(SampleUtils.getSampleList(vcfRods, GATKVariantContextUtils.GenotypeMergeType.REQUIRE_UNIQUE));
+ VCFHeader vcfHeader = new VCFHeader(headerLines, vcfSamples);
+ vcfHeader.setWriteEngineHeaders(includeEngineHeaders);
+ vcfWriter.writeHeader(vcfHeader);
+ }
+
+ private Set<VCFHeaderLine> getSelectedHeaders(Set<VCFHeaderLine> headerLines) {
+ Set<VCFHeaderLine> selectedHeaders = new TreeSet<VCFHeaderLine>();
+ if (headerNames == null && headerExpressions == null) {
+ // Include everything if nothing was explicitly included.
+ selectedHeaders.addAll(headerLines);
+ } else {
+ // Only include the selected headers.
+ if (headerNames != null)
+ selectedHeaders.addAll(ListFileUtils.includeMatching(headerLines, headerKey, headerNames, true));
+ if (headerExpressions != null)
+ selectedHeaders.addAll(ListFileUtils.includeMatching(headerLines, headerKey, headerExpressions, false));
+ }
+
+ // Remove any excluded headers.
+ if (XLheaderNames != null)
+ selectedHeaders = ListFileUtils.excludeMatching(selectedHeaders, headerKey, XLheaderNames, true);
+
+ // always include the contig lines
+ selectedHeaders = VCFUtils.withUpdatedContigsAsLines(selectedHeaders, getToolkit().getArguments().referenceFile, getToolkit().getMasterSequenceDictionary(), true);
+ return selectedHeaders;
+ }
+
+ /**
+ * Pass through the VC record
+ *
+ * @param tracker the ROD tracker
+ * @param ref reference information
+ * @param context alignment info
+ * @return number of records processed
+ */
+ @Override
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ int count = 0;
+ if (tracker != null) {
+ Collection<VariantContext> vcs = tracker.getValues(variantCollection.variants, context.getLocation());
+ if (vcs != null) {
+ for (VariantContext vc : vcs) {
+ vcfWriter.add(vc);
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+
+ @Override
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ @Override
+ public Integer reduce(Integer value, Integer sum) {
+ return value + sum;
+ }
+
+ @Override
+ public Integer treeReduce(Integer lhs, Integer rhs) {
+ return lhs + rhs;
+ }
+
+ @Override
+ public void onTraversalDone(Integer result) {
+ logger.info(result + " records processed.");
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/SelectVariants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/SelectVariants.java
new file mode 100644
index 0000000..db9d082
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/SelectVariants.java
@@ -0,0 +1,801 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.TreeReducible;
+import org.broadinstitute.gatk.tools.walkers.annotator.ChromosomeCountConstants;
+import org.broadinstitute.gatk.utils.MendelianViolation;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.vcf.*;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.*;
+
+/**
+ * Selects variants from a VCF source.
+ *
+ * <p>
+ * Often, a VCF containing many samples and/or variants will need to be subset in order to facilitate certain analyses
+ * (e.g. comparing and contrasting cases vs. controls; extracting variant or non-variant loci that meet certain
+ * requirements, displaying just a few samples in a browser like IGV, etc.). SelectVariants can be used for this purpose.
+ * Given a single VCF file, one or more samples can be extracted from the file (based on a complete sample name or a
+ * pattern match). Variants can be further selected by specifying criteria for inclusion, i.e. "DP > 1000" (depth of
+ * coverage greater than 1000x), "AF < 0.25" (sites with allele frequency less than 0.25). These JEXL expressions are
+ * documented in the Using JEXL expressions section (http://www.broadinstitute.org/gatk/guide/article?id=1255).
+ * One can optionally include concordance or discordance tracks for use in selecting overlapping variants.
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A variant set to select from.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A selected VCF.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * Select two samples out of a VCF with many samples:
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectVariants \
+ * --variant input.vcf \
+ * -o output.vcf \
+ * -sn SAMPLE_A_PARC \
+ * -sn SAMPLE_B_ACTG
+ *
+ * Select two samples and any sample that matches a regular expression:
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectVariants \
+ * --variant input.vcf \
+ * -o output.vcf \
+ * -sn SAMPLE_1_PARC \
+ * -sn SAMPLE_1_ACTG \
+ * -se 'SAMPLE.+PARC'
+ *
+ * Select any sample that matches a regular expression and sites where the QD annotation is more than 10:
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectVariants \
+ * --variant input.vcf \
+ * -o output.vcf \
+ * -se 'SAMPLE.+PARC'
+ * -select "QD > 10.0"
+ *
+ * Select a sample and exclude non-variant loci and filtered loci:
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectVariants \
+ * --variant input.vcf \
+ * -o output.vcf \
+ * -sn SAMPLE_1_ACTG \
+ * -env \
+ * -ef
+ *
+ * Select a sample and restrict the output vcf to a set of intervals:
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectVariants \
+ * --variant input.vcf \
+ * -o output.vcf \
+ * -L /path/to/my.interval_list \
+ * -sn SAMPLE_1_ACTG
+ *
+ * Select all calls missed in my vcf, but present in HapMap (useful to take a look at why these variants weren't called by this dataset):
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectVariants \
+ * --variant hapmap.vcf \
+ * --discordance myCalls.vcf
+ * -o output.vcf \
+ * -sn mySample
+ *
+ * Select all calls made by both myCalls and hisCalls (useful to take a look at what is consistent between the two callers):
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectVariants \
+ * --variant myCalls.vcf \
+ * --concordance hisCalls.vcf
+ * -o output.vcf \
+ * -sn mySample
+ *
+ * Generating a VCF of all the variants that are mendelian violations:
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectVariants \
+ * --variant input.vcf \
+ * -ped family.ped \
+ * -mvq 50 \
+ * -o violations.vcf
+ *
+ * Creating a set with 50% of the total number of variants in the variant VCF:
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectVariants \
+ * --variant input.vcf \
+ * -o output.vcf \
+ * -fraction 0.5
+ *
+ * Select only indels from a VCF:
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectVariants \
+ * --variant input.vcf \
+ * -o output.vcf \
+ * -selectType INDEL
+ *
+ * Select only multi-allelic SNPs and MNPs from a VCF (i.e. SNPs with more than one allele listed in the ALT column):
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T SelectVariants \
+ * --variant input.vcf \
+ * -o output.vcf \
+ * -selectType SNP -selectType MNP \
+ * -restrictAllelesTo MULTIALLELIC
+ *
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+public class SelectVariants extends RodWalker<Integer, Integer> implements TreeReducible<Integer> {
+ @ArgumentCollection protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ /**
+ * A site is considered discordant if there exists some sample in the variant track that has a non-reference genotype
+ * and either the site isn't present in this track, the sample isn't present in this track,
+ * or the sample is called reference in this track.
+ */
+ @Input(fullName="discordance", shortName = "disc", doc="Output variants that were not called in this comparison track", required=false)
+ protected RodBinding<VariantContext> discordanceTrack;
+
+ /**
+ * A site is considered concordant if (1) we are not looking for specific samples and there is a variant called
+ * in both the variant and concordance tracks or (2) every sample present in the variant track is present in the
+ * concordance track and they have the sample genotype call.
+ */
+ @Input(fullName="concordance", shortName = "conc", doc="Output variants that were also called in this comparison track", required=false)
+ protected RodBinding<VariantContext> concordanceTrack;
+
+ @Output(doc="File to which variants should be written")
+ protected VariantContextWriter vcfWriter = null;
+
+ @Argument(fullName="sample_name", shortName="sn", doc="Include genotypes from this sample. Can be specified multiple times", required=false)
+ public Set<String> sampleNames = new HashSet<String>(0);
+
+ @Argument(fullName="sample_expressions", shortName="se", doc="Regular expression to select many samples from the ROD tracks provided. Can be specified multiple times", required=false)
+ public Set<String> sampleExpressions ;
+
+ @Input(fullName="sample_file", shortName="sf", doc="File containing a list of samples (one per line) to include. Can be specified multiple times", required=false)
+ public Set<File> sampleFiles;
+
+ /**
+ * Note that sample exclusion takes precedence over inclusion, so that if a sample is in both lists it will be excluded.
+ */
+ @Argument(fullName="exclude_sample_name", shortName="xl_sn", doc="Exclude genotypes from this sample. Can be specified multiple times", required=false)
+ public Set<String> XLsampleNames = new HashSet<String>(0);
+
+ /**
+ * Note that sample exclusion takes precedence over inclusion, so that if a sample is in both lists it will be excluded.
+ */
+ @Input(fullName="exclude_sample_file", shortName="xl_sf", doc="File containing a list of samples (one per line) to exclude. Can be specified multiple times", required=false)
+ public Set<File> XLsampleFiles = new HashSet<File>(0);
+
+ /**
+ * Note that these expressions are evaluated *after* the specified samples are extracted and the INFO field annotations are updated.
+ */
+ @Argument(shortName="select", doc="One or more criteria to use when selecting the data", required=false)
+ public ArrayList<String> SELECT_EXPRESSIONS = new ArrayList<String>();
+
+ @Argument(fullName="excludeNonVariants", shortName="env", doc="Don't include loci found to be non-variant after the subsetting procedure", required=false)
+ protected boolean EXCLUDE_NON_VARIANTS = false;
+
+ @Argument(fullName="excludeFiltered", shortName="ef", doc="Don't include filtered loci in the analysis", required=false)
+ protected boolean EXCLUDE_FILTERED = false;
+
+ /**
+ * When this argument is used, we can choose to include only multiallelic or biallelic sites, depending on how many alleles are listed in the ALT column of a vcf.
+ * For example, a multiallelic record such as:
+ * 1 100 . A AAA,AAAAA
+ * will be excluded if "-restrictAllelesTo BIALLELIC" is included, because there are two alternate alleles, whereas a record such as:
+ * 1 100 . A T
+ * will be included in that case, but would be excluded if "-restrictAllelesTo MULTIALLELIC
+ */
+ @Argument(fullName="restrictAllelesTo", shortName="restrictAllelesTo", doc="Select only variants of a particular allelicity. Valid options are ALL (default), MULTIALLELIC or BIALLELIC", required=false)
+ private NumberAlleleRestriction alleleRestriction = NumberAlleleRestriction.ALL;
+
+ @Argument(fullName="keepOriginalAC", shortName="keepOriginalAC", doc="Store the original AC, AF, and AN values in the INFO field after selecting (using keys AC_Orig, AF_Orig, and AN_Orig)", required=false)
+ private boolean KEEP_ORIGINAL_CHR_COUNTS = false;
+
+ /**
+ * This activates the mendelian violation module that will select all variants that correspond to a mendelian violation following the rules given by the family structure.
+ */
+ @Argument(fullName="mendelianViolation", shortName="mv", doc="output mendelian violation sites only", required=false)
+ private Boolean MENDELIAN_VIOLATIONS = false;
+
+ @Argument(fullName="mendelianViolationQualThreshold", shortName="mvq", doc="Minimum genotype QUAL score for each trio member required to accept a site as a violation", required=false)
+ protected double MENDELIAN_VIOLATION_QUAL_THRESHOLD = 0;
+
+ /**
+ * This routine is based on probability, so the final result is not guaranteed to carry the exact fraction. Can be used for large fractions.
+ */
+ @Argument(fullName="select_random_fraction", shortName="fraction", doc="Selects a fraction (a number between 0 and 1) of the total variants at random from the variant track", required=false)
+ protected double fractionRandom = 0;
+
+ @Argument(fullName="remove_fraction_genotypes", shortName="fractionGenotypes", doc="Selects a fraction (a number between 0 and 1) of the total genotypes at random from the variant track and sets them to nocall", required=false)
+ protected double fractionGenotypes = 0;
+
+ /**
+ * This argument select particular kinds of variants out of a list. If left empty, there is no type selection and all variant types are considered for other selection criteria.
+ * When specified one or more times, a particular type of variant is selected.
+ *
+ */
+ @Argument(fullName="selectTypeToInclude", shortName="selectType", doc="Select only a certain type of variants from the input file. Valid types are INDEL, SNP, MIXED, MNP, SYMBOLIC, NO_VARIATION. Can be specified multiple times", required=false)
+ private List<VariantContext.Type> TYPES_TO_INCLUDE = new ArrayList<VariantContext.Type>();
+
+ /**
+ * If provided, we will only include variants whose ID field is present in this list of ids. The matching
+ * is exact string matching. The file format is just one ID per line
+ *
+ */
+ @Argument(fullName="keepIDs", shortName="IDs", doc="Only emit sites whose ID is found in this file (one ID per line)", required=false)
+ private File rsIDFile = null;
+
+
+ @Hidden
+ @Argument(fullName="fullyDecode", doc="If true, the incoming VariantContext will be fully decoded", required=false)
+ private boolean fullyDecode = false;
+
+ @Hidden
+ @Argument(fullName="forceGenotypesDecode", doc="If true, the incoming VariantContext will have its genotypes forcibly decoded by computing AC across all genotypes. For efficiency testing only", required=false)
+ private boolean forceGenotypesDecode = false;
+
+ @Hidden
+ @Argument(fullName="justRead", doc="If true, we won't actually write the output file. For efficiency testing only", required=false)
+ private boolean justRead = false;
+
+ @Argument(doc="indel size select",required=false,fullName="maxIndelSize")
+ private int maxIndelSize = Integer.MAX_VALUE;
+
+ @Argument(doc="Allow samples other than those in the VCF to be specified on the command line. These samples will be ignored.",required=false,fullName="ALLOW_NONOVERLAPPING_COMMAND_LINE_SAMPLES")
+ private boolean ALLOW_NONOVERLAPPING_COMMAND_LINE_SAMPLES = false;
+
+
+ public enum NumberAlleleRestriction {
+ ALL,
+ BIALLELIC,
+ MULTIALLELIC
+ }
+
+ private ArrayList<VariantContext.Type> selectedTypes = new ArrayList<VariantContext.Type>();
+ private ArrayList<String> selectNames = new ArrayList<String>();
+ private List<VariantContextUtils.JexlVCMatchExp> jexls = null;
+
+ private TreeSet<String> samples = new TreeSet<String>();
+ private boolean NO_SAMPLES_SPECIFIED = false;
+
+ private boolean DISCORDANCE_ONLY = false;
+ private boolean CONCORDANCE_ONLY = false;
+
+ private MendelianViolation mv;
+
+
+ /* variables used by the SELECT RANDOM modules */
+ private boolean SELECT_RANDOM_FRACTION = false;
+
+ //Random number generator for the genotypes to remove
+ private Random randomGenotypes = new Random();
+
+ private Set<String> IDsToKeep = null;
+ private Map<String, VCFHeader> vcfRods;
+
+ /**
+ * Set up the VCF writer, the sample expressions and regexs, and the JEXL matcher
+ */
+ public void initialize() {
+ // Get list of samples to include in the output
+ List<String> rodNames = Arrays.asList(variantCollection.variants.getName());
+
+ vcfRods = GATKVCFUtils.getVCFHeadersFromRods(getToolkit(), rodNames);
+ TreeSet<String> vcfSamples = new TreeSet<String>(SampleUtils.getSampleList(vcfRods, GATKVariantContextUtils.GenotypeMergeType.REQUIRE_UNIQUE));
+
+ Collection<String> samplesFromFile = SampleUtils.getSamplesFromFiles(sampleFiles);
+ Collection<String> samplesFromExpressions = SampleUtils.matchSamplesExpressions(vcfSamples, sampleExpressions);
+
+ // first, check overlap between requested and present samples
+ Set<String> commandLineUniqueSamples = new HashSet<String>(samplesFromFile.size()+samplesFromExpressions.size()+sampleNames.size());
+ commandLineUniqueSamples.addAll(samplesFromFile);
+ commandLineUniqueSamples.addAll(samplesFromExpressions);
+ commandLineUniqueSamples.addAll(sampleNames);
+ commandLineUniqueSamples.removeAll(vcfSamples);
+
+ // second, add the requested samples
+ samples.addAll(sampleNames);
+ samples.addAll(samplesFromExpressions);
+ samples.addAll(samplesFromFile);
+
+ logger.debug(Utils.join(",",commandLineUniqueSamples));
+
+ if ( commandLineUniqueSamples.size() > 0 && ALLOW_NONOVERLAPPING_COMMAND_LINE_SAMPLES ) {
+ logger.warn("Samples present on command line input that are not present in the VCF. These samples will be ignored.");
+ samples.removeAll(commandLineUniqueSamples);
+ } else if (commandLineUniqueSamples.size() > 0 ) {
+ throw new UserException.BadInput(String.format("%s%n%n%s%n%n%s%n%n%s",
+ "Samples entered on command line (through -sf or -sn) that are not present in the VCF.",
+ "A list of these samples:",
+ Utils.join(",",commandLineUniqueSamples),
+ "To ignore these samples, run with --ALLOW_NONOVERLAPPING_COMMAND_LINE_SAMPLES"));
+ }
+
+
+ // if none were requested, we want all of them
+ if ( samples.isEmpty() ) {
+ samples.addAll(vcfSamples);
+ NO_SAMPLES_SPECIFIED = true;
+ }
+
+ // now, exclude any requested samples
+ final Collection<String> XLsamplesFromFile = SampleUtils.getSamplesFromFiles(XLsampleFiles);
+ samples.removeAll(XLsamplesFromFile);
+ samples.removeAll(XLsampleNames);
+ NO_SAMPLES_SPECIFIED = NO_SAMPLES_SPECIFIED && XLsampleNames.isEmpty() && XLsamplesFromFile.isEmpty();
+
+ if ( samples.size() == 0 && !NO_SAMPLES_SPECIFIED )
+ throw new UserException("All samples requested to be included were also requested to be excluded.");
+
+ if ( ! NO_SAMPLES_SPECIFIED )
+ for ( String sample : samples )
+ logger.info("Including sample '" + sample + "'");
+
+ // if user specified types to include, add these, otherwise, add all possible variant context types to list of vc types to include
+ if (TYPES_TO_INCLUDE.isEmpty()) {
+
+ for (VariantContext.Type t : VariantContext.Type.values())
+ selectedTypes.add(t);
+
+ }
+ else {
+ for (VariantContext.Type t : TYPES_TO_INCLUDE)
+ selectedTypes.add(t);
+
+ }
+ // Initialize VCF header
+ Set<VCFHeaderLine> headerLines = VCFUtils.smartMergeHeaders(vcfRods.values(), true);
+ headerLines.add(new VCFHeaderLine("source", "SelectVariants"));
+
+ if (KEEP_ORIGINAL_CHR_COUNTS) {
+ headerLines.add(new VCFInfoHeaderLine("AC_Orig", VCFHeaderLineCount.A, VCFHeaderLineType.Integer, "Original AC"));
+ headerLines.add(new VCFInfoHeaderLine("AF_Orig", VCFHeaderLineCount.A, VCFHeaderLineType.Float, "Original AF"));
+ headerLines.add(new VCFInfoHeaderLine("AN_Orig", 1, VCFHeaderLineType.Integer, "Original AN"));
+ }
+ headerLines.addAll(Arrays.asList(ChromosomeCountConstants.descriptions));
+ headerLines.add(VCFStandardHeaderLines.getInfoLine(VCFConstants.DEPTH_KEY));
+
+ for (int i = 0; i < SELECT_EXPRESSIONS.size(); i++) {
+ // It's not necessary that the user supply select names for the JEXL expressions, since those
+ // expressions will only be needed for omitting records. Make up the select names here.
+ selectNames.add(String.format("select-%d", i));
+ }
+
+ jexls = VariantContextUtils.initializeMatchExps(selectNames, SELECT_EXPRESSIONS);
+
+ // Look at the parameters to decide which analysis to perform
+ DISCORDANCE_ONLY = discordanceTrack.isBound();
+ if (DISCORDANCE_ONLY) logger.info("Selecting only variants discordant with the track: " + discordanceTrack.getName());
+
+ CONCORDANCE_ONLY = concordanceTrack.isBound();
+ if (CONCORDANCE_ONLY) logger.info("Selecting only variants concordant with the track: " + concordanceTrack.getName());
+
+ if (MENDELIAN_VIOLATIONS) {
+ mv = new MendelianViolation(MENDELIAN_VIOLATION_QUAL_THRESHOLD,false,true);
+ }
+
+ SELECT_RANDOM_FRACTION = fractionRandom > 0;
+ if (SELECT_RANDOM_FRACTION) logger.info("Selecting approximately " + 100.0*fractionRandom + "% of the variants at random from the variant track");
+
+ /** load in the IDs file to a hashset for matching */
+ if ( rsIDFile != null ) {
+ IDsToKeep = new HashSet<String>();
+ try {
+ for ( final String line : new XReadLines(rsIDFile).readLines() ) {
+ IDsToKeep.add(line.trim());
+ }
+ logger.info("Selecting only variants with one of " + IDsToKeep.size() + " IDs from " + rsIDFile);
+ } catch ( FileNotFoundException e ) {
+ throw new UserException.CouldNotReadInputFile(rsIDFile, e);
+ }
+ }
+
+ vcfWriter.writeHeader(new VCFHeader(headerLines, samples));
+ }
+
+ /**
+ * Subset VC record if necessary and emit the modified record (provided it satisfies criteria for printing)
+ *
+ * @param tracker the ROD tracker
+ * @param ref reference information
+ * @param context alignment info
+ * @return 1 if the record was printed to the output file, 0 if otherwise
+ */
+ @Override
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null )
+ return 0;
+
+ Collection<VariantContext> vcs = tracker.getValues(variantCollection.variants, context.getLocation());
+
+ if ( vcs == null || vcs.size() == 0) {
+ return 0;
+ }
+
+ for (VariantContext vc : vcs) {
+ // an option for performance testing only
+ if ( fullyDecode )
+ vc = vc.fullyDecode(vcfRods.get(vc.getSource()), getToolkit().lenientVCFProcessing() );
+
+ // an option for performance testing only
+ if ( forceGenotypesDecode ) {
+ final int x = vc.getCalledChrCount();
+ //logger.info("forceGenotypesDecode with getCalledChrCount() = " + );
+ }
+
+ if ( IDsToKeep != null && ! IDsToKeep.contains(vc.getID()) )
+ continue;
+
+ if (MENDELIAN_VIOLATIONS && mv.countViolations(this.getSampleDB().getFamilies(samples),vc) < 1)
+ break;
+
+ if (DISCORDANCE_ONLY) {
+ Collection<VariantContext> compVCs = tracker.getValues(discordanceTrack, context.getLocation());
+ if (!isDiscordant(vc, compVCs))
+ continue;
+ }
+ if (CONCORDANCE_ONLY) {
+ Collection<VariantContext> compVCs = tracker.getValues(concordanceTrack, context.getLocation());
+ if (!isConcordant(vc, compVCs))
+ continue;
+ }
+
+ if (alleleRestriction.equals(NumberAlleleRestriction.BIALLELIC) && !vc.isBiallelic())
+ continue;
+
+ if (alleleRestriction.equals(NumberAlleleRestriction.MULTIALLELIC) && vc.isBiallelic())
+ continue;
+
+ if (!selectedTypes.contains(vc.getType()))
+ continue;
+
+ if ( containsIndelLargerThan(vc, maxIndelSize) )
+ continue;
+
+ VariantContext sub = subsetRecord(vc, EXCLUDE_NON_VARIANTS);
+
+ if ( (!EXCLUDE_NON_VARIANTS || sub.isPolymorphicInSamples()) && (!EXCLUDE_FILTERED || !sub.isFiltered()) ) {
+ boolean failedJexlMatch = false;
+ try {
+ for (VariantContextUtils.JexlVCMatchExp jexl : jexls) {
+ if (!VariantContextUtils.match(sub, jexl)) {
+ failedJexlMatch = true;
+ break;
+ }
+ }
+ } catch (IllegalArgumentException e) {
+ /*The IAE thrown by htsjdk already includes an informative error message ("Invalid JEXL
+ expression detected...")*/
+ throw new UserException(e.getMessage());
+ }
+ if ( !failedJexlMatch &&
+ !justRead &&
+ ( !SELECT_RANDOM_FRACTION || GenomeAnalysisEngine.getRandomGenerator().nextDouble() < fractionRandom ) ) {
+ vcfWriter.add(sub);
+ }
+ }
+ }
+
+ return 1;
+ }
+
+ /*
+ * Determines if any of the alternate alleles are greater than the max indel size
+ *
+ * @param vc the variant context to check
+ * @param maxIndelSize the maximum size of allowed indels
+ * @return true if the VC contains an indel larger than maxIndelSize and false otherwise
+ */
+ protected static boolean containsIndelLargerThan(final VariantContext vc, final int maxIndelSize) {
+ final List<Integer> lengths = vc.getIndelLengths();
+ if ( lengths == null )
+ return false;
+
+ for ( Integer indelLength : lengths ) {
+ if ( Math.abs(indelLength) > maxIndelSize )
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if vc has a variant call for (at least one of) the samples.
+ * @param vc the variant rod VariantContext. Here, the variant is the dataset you're looking for discordances to (e.g. HapMap)
+ * @param compVCs the comparison VariantContext (discordance
+ * @return true if is discordant
+ */
+ private boolean isDiscordant (VariantContext vc, Collection<VariantContext> compVCs) {
+ if (vc == null)
+ return false;
+
+ // if we're not looking at specific samples then the absence of a compVC means discordance
+ if (NO_SAMPLES_SPECIFIED)
+ return (compVCs == null || compVCs.isEmpty());
+
+ // check if we find it in the variant rod
+ GenotypesContext genotypes = vc.getGenotypes(samples);
+ for (final Genotype g : genotypes) {
+ if (sampleHasVariant(g)) {
+ // There is a variant called (or filtered with not exclude filtered option set) that is not HomRef for at least one of the samples.
+ if (compVCs == null)
+ return true;
+ // Look for this sample in the all vcs of the comp ROD track.
+ boolean foundVariant = false;
+ for (VariantContext compVC : compVCs) {
+ if (haveSameGenotypes(g, compVC.getGenotype(g.getSampleName()))) {
+ foundVariant = true;
+ break;
+ }
+ }
+ // if (at least one sample) was not found in all VCs of the comp ROD, we have discordance
+ if (!foundVariant)
+ return true;
+ }
+ }
+ return false; // we only get here if all samples have a variant in the comp rod.
+ }
+
+ private boolean isConcordant (VariantContext vc, Collection<VariantContext> compVCs) {
+ if (vc == null || compVCs == null || compVCs.isEmpty())
+ return false;
+
+ // if we're not looking for specific samples then the fact that we have both VCs is enough to call it concordant.
+ if (NO_SAMPLES_SPECIFIED)
+ return true;
+
+ // make a list of all samples contained in this variant VC that are being tracked by the user command line arguments.
+ Set<String> variantSamples = vc.getSampleNames();
+ variantSamples.retainAll(samples);
+
+ // check if we can find all samples from the variant rod in the comp rod.
+ for (String sample : variantSamples) {
+ boolean foundSample = false;
+ for (VariantContext compVC : compVCs) {
+ Genotype varG = vc.getGenotype(sample);
+ Genotype compG = compVC.getGenotype(sample);
+ if (haveSameGenotypes(varG, compG)) {
+ foundSample = true;
+ break;
+ }
+ }
+ // if at least one sample doesn't have the same genotype, we don't have concordance
+ if (!foundSample) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean sampleHasVariant(Genotype g) {
+ return (g !=null && !g.isHomRef() && (g.isCalled() || (g.isFiltered() && !EXCLUDE_FILTERED)));
+ }
+
+ private boolean haveSameGenotypes(final Genotype g1, final Genotype g2) {
+ if ( g1 == null || g2 == null )
+ return false;
+
+ if ((g1.isCalled() && g2.isFiltered()) ||
+ (g2.isCalled() && g1.isFiltered()) ||
+ (g1.isFiltered() && g2.isFiltered() && EXCLUDE_FILTERED))
+ return false;
+
+ List<Allele> a1s = g1.getAlleles();
+ List<Allele> a2s = g2.getAlleles();
+ return (a1s.containsAll(a2s) && a2s.containsAll(a1s));
+ }
+ @Override
+ public Integer reduceInit() { return 0; }
+
+ @Override
+ public Integer reduce(Integer value, Integer sum) { return value + sum; }
+
+ @Override
+ public Integer treeReduce(Integer lhs, Integer rhs) {
+ return lhs + rhs;
+ }
+
+ public void onTraversalDone(Integer result) {
+ logger.info(result + " records processed.");
+ }
+
+
+
+ /**
+ * Helper method to subset a VC record, modifying some metadata stored in the INFO field (i.e. AN, AC, AF).
+ *
+ * @param vc the VariantContext record to subset
+ * @param excludeNonVariants should we exclude sites that have AC=0 for any alternate alleles?
+ * @return the subsetted VariantContext
+ */
+ private VariantContext subsetRecord(final VariantContext vc, final boolean excludeNonVariants) {
+ if ( NO_SAMPLES_SPECIFIED || samples.isEmpty() )
+ return vc;
+
+ final VariantContext sub = vc.subContextFromSamples(samples, excludeNonVariants); // strip out the alternate alleles that aren't being used
+
+ final VariantContextBuilder builder = new VariantContextBuilder(sub);
+
+ // if there are fewer alternate alleles now in the selected VC, we need to fix the PL and AD values
+ GenotypesContext newGC = GATKVariantContextUtils.updatePLsAndAD(sub, vc);
+
+ // if we have fewer samples in the selected VC than in the original VC, we need to strip out the MLE tags
+ if ( vc.getNSamples() != sub.getNSamples() ) {
+ builder.rmAttribute(VCFConstants.MLE_ALLELE_COUNT_KEY);
+ builder.rmAttribute(VCFConstants.MLE_ALLELE_FREQUENCY_KEY);
+ }
+
+ // Remove a fraction of the genotypes if needed
+ if ( fractionGenotypes > 0 ){
+ final ArrayList<Genotype> genotypes = new ArrayList<>();
+ for ( Genotype genotype : newGC ) {
+ //Set genotype to no call if it falls in the fraction.
+ if(fractionGenotypes>0 && randomGenotypes.nextDouble()<fractionGenotypes){
+ final List<Allele> alleles = Arrays.asList(Allele.NO_CALL, Allele.NO_CALL);
+ genotypes.add(new GenotypeBuilder(genotype).alleles(alleles).noGQ().make());
+ }
+ else{
+ genotypes.add(genotype);
+ }
+ }
+ newGC = GenotypesContext.create(genotypes);
+ }
+
+ builder.genotypes(newGC);
+
+ addAnnotations(builder, vc, sub.getSampleNames());
+
+ return builder.make();
+ }
+
+ /*
+ * Add annotations to the new VC
+ *
+ * @param builder the new VC to annotate
+ * @param originalVC the original VC
+ * @param selectedSampleNames the post-selection list of sample names
+ */
+ private void addAnnotations(final VariantContextBuilder builder, final VariantContext originalVC, final Set<String> selectedSampleNames) {
+ if ( fullyDecode ) return; // TODO -- annotations are broken with fully decoded data
+
+ if ( KEEP_ORIGINAL_CHR_COUNTS ) {
+ final int[] indexOfOriginalAlleleForNewAllele;
+ final List<Allele> newAlleles = builder.getAlleles();
+ final int numOriginalAlleles = originalVC.getNAlleles();
+
+ // if the alleles already match up, we can just copy the previous list of counts
+ if ( numOriginalAlleles == newAlleles.size() ) {
+ indexOfOriginalAlleleForNewAllele = null;
+ }
+ // otherwise we need to parse them and select out the correct ones
+ else {
+ indexOfOriginalAlleleForNewAllele = new int[newAlleles.size() - 1];
+ Arrays.fill(indexOfOriginalAlleleForNewAllele, -1);
+
+ // note that we don't care about the reference allele at position 0
+ for ( int newI = 1; newI < newAlleles.size(); newI++ ) {
+ final Allele newAlt = newAlleles.get(newI);
+ for ( int oldI = 0; oldI < numOriginalAlleles - 1; oldI++ ) {
+ if ( newAlt.equals(originalVC.getAlternateAllele(oldI), false) ) {
+ indexOfOriginalAlleleForNewAllele[newI - 1] = oldI;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( originalVC.hasAttribute(VCFConstants.ALLELE_COUNT_KEY) )
+ builder.attribute("AC_Orig", getReorderedAttributes(originalVC.getAttribute(VCFConstants.ALLELE_COUNT_KEY), indexOfOriginalAlleleForNewAllele));
+ if ( originalVC.hasAttribute(VCFConstants.ALLELE_FREQUENCY_KEY) )
+ builder.attribute("AF_Orig", getReorderedAttributes(originalVC.getAttribute(VCFConstants.ALLELE_FREQUENCY_KEY), indexOfOriginalAlleleForNewAllele));
+ if ( originalVC.hasAttribute(VCFConstants.ALLELE_NUMBER_KEY) )
+ builder.attribute("AN_Orig", originalVC.getAttribute(VCFConstants.ALLELE_NUMBER_KEY));
+ }
+
+ VariantContextUtils.calculateChromosomeCounts(builder, false);
+
+ boolean sawDP = false;
+ int depth = 0;
+ for ( final String sample : selectedSampleNames ) {
+ Genotype g = originalVC.getGenotype(sample);
+
+ if ( ! g.isFiltered() ) {
+ if ( g.hasDP() ) {
+ depth += g.getDP();
+ sawDP = true;
+ }
+ }
+ }
+
+ if ( sawDP )
+ builder.attribute("DP", depth);
+ }
+
+ /**
+ * Pulls out the appropriate tokens from the old ordering of an attribute to the new ordering
+ *
+ * @param attribute the non-null attribute (from the INFO field)
+ * @param oldToNewIndexOrdering the mapping from new to old ordering
+ * @return non-null Object attribute
+ */
+ private Object getReorderedAttributes(final Object attribute, final int[] oldToNewIndexOrdering) {
+ // if the ordering is the same, then just use the original attribute
+ if ( oldToNewIndexOrdering == null )
+ return attribute;
+
+ // break the original attributes into separate tokens; unfortunately, this means being smart about class types
+ final Object[] tokens;
+ if ( attribute.getClass().isArray() )
+ tokens = (Object[])attribute;
+ else if ( List.class.isAssignableFrom(attribute.getClass()) )
+ tokens = ((List)attribute).toArray();
+ else
+ tokens = attribute.toString().split(VCFConstants.INFO_FIELD_ARRAY_SEPARATOR);
+
+ final List<Object> result = new ArrayList<>();
+ for ( final int index : oldToNewIndexOrdering ) {
+ if ( index >= tokens.length )
+ throw new IllegalArgumentException("the old attribute has an incorrect number of elements: " + attribute);
+ result.add(tokens[index]);
+ }
+ return result;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/ValidateVariants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/ValidateVariants.java
new file mode 100644
index 0000000..6b6e6ca
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/ValidateVariants.java
@@ -0,0 +1,301 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import htsjdk.tribble.TribbleException;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.ArgumentCollection;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.DbsnpArgumentCollection;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.Reference;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.Window;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.vcf.VCFConstants;
+
+import java.io.File;
+import java.util.*;
+
+
+/**
+ * Validates a VCF file with an extra strict set of criteria.
+ *
+ * <p>
+ * ValidateVariants is a GATK tool that takes a VCF file and validates much of the information inside it.
+ * In addition to standard adherence to the VCF specification, this tool performs extra strict validations to ensure
+ * the information contained within the file is correct. These include:
+ * </p><p>
+ * <dl>
+ * <dt>REF</dt><dd>the correctness of the reference base(s).</dd>
+ * <dt>CHR_COUNTS</dt><dd>accuracy of AC & AN values.</dd>
+ * <dt>IDS</dt><dd>tests against rsIDs when a dbSNP file is provided. Notice that for this one to work, you need
+ * to provide a reference to the dbsnp variant containing file using the <code>--dbsnp</code> as show in examples below.</dd>
+ * <dt>ALLELES</dt><dd>and that all alternate alleles are present in at least one sample.</dd>
+ * </dl>
+ *
+ * </p>
+ *
+ * <p>
+ * By default it will apply all the strict validations unless you indicate which one you want you want to exclude
+ * using <code>-Xtype|--validationTypeToExclude <<i>code</i>></code>, where <i>code</i> is one of the listed above. You
+ * can exclude as many types as you want
+ * <p>
+ * Yo can exclude all strict validations with the special code <code><b>ALL</b></code>. In this case the tool will only
+ * test the adherence to the VCF specification.
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A variant set to validate using <code>-V</code> or <code>--variant</code> as shown below.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ *
+ * <p>To perform VCF format and all strict validations: </p>
+ *
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T ValidateVariants \
+ * --variant input.vcf \
+ * --dbsnp dbsnp.vcf
+ * </pre>
+ *
+ * <p>To perform only VCF format tests:</p>
+ *
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T ValidateVariants \
+ * <b>--validationTypeToExclude ALL</b> \
+ * --variant input.vcf
+ * </pre>
+ *
+ * <p>To perform all validations except the strict <i>ALLELE</i> validation:</p>
+ *
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T ValidateVariants \
+ * <b>--validationTypeToExclude ALLELES</b>
+ * --variant input.vcf \
+ * --dbsnp dbsnp.vcf
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VALIDATION, extraDocs = {CommandLineGATK.class} )
+ at Reference(window=@Window(start=0,stop=100))
+public class ValidateVariants extends RodWalker<Integer, Integer> {
+
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ @ArgumentCollection
+ protected DbsnpArgumentCollection dbsnp = new DbsnpArgumentCollection();
+
+ public enum ValidationType {
+
+ /**
+ * Makes reference to all extra-strict tests listed below.
+ */
+ ALL,
+
+ /**
+ * Check whether the reported reference base in the VCF is the same as the corresponding base in the
+ * actual reference.
+ */
+ REF,
+
+ /**
+ * Checks whether the variant IDs exists, only relevant if the user indicates a DBSNP vcf file (see {@link #dbsnp}).
+ */
+ IDS,
+
+ /**
+ * Check whether all alternative alleles participate in a genotype call of at least on sample.
+ */
+ ALLELES,
+
+ /**
+ * Check that the AN and AC annotations are consistent with the number of calls, alleles and then number these
+ * are called across samples.
+ */
+ CHR_COUNTS;
+
+ /**
+ * Unmodifiable set of concrete validation types.
+ *
+ * <p>These are all types except {@link #ALL}.</p>
+ */
+ public final static Set<ValidationType> CONCRETE_TYPES;
+
+ static {
+ final Set<ValidationType> cts = new LinkedHashSet<>(values().length - 1);
+ for (final ValidationType v : values())
+ if (v != ALL)
+ cts.add(v);
+ CONCRETE_TYPES = Collections.unmodifiableSet(cts);
+ }
+ }
+
+ @Argument(fullName = "validationTypeToExclude", shortName = "Xtype", doc = "which validation type to exclude from a full strict validation", required = false)
+ protected List<ValidationType> excludeTypes = new ArrayList<>();
+
+ /**
+ * By default, even filtered records are validated.
+ */
+ @Argument(fullName = "doNotValidateFilteredRecords", shortName = "doNotValidateFilteredRecords", doc = "skip validation on filtered records", required = false)
+ protected Boolean DO_NOT_VALIDATE_FILTERED = false;
+
+ @Argument(fullName = "warnOnErrors", shortName = "warnOnErrors", doc = "just emit warnings on errors instead of terminating the run at the first instance", required = false)
+ protected Boolean WARN_ON_ERROR = false;
+
+ private long numErrors = 0;
+
+ private File file = null;
+
+ /**
+ * Contains final set of validation to apply.
+ */
+ private Collection<ValidationType> validationTypes;
+
+ public void initialize() {
+ file = new File(variantCollection.variants.getSource());
+ validationTypes = calculateValidationTypesToApply(excludeTypes);
+ }
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null )
+ return 0;
+
+ Collection<VariantContext> VCs = tracker.getValues(variantCollection.variants, context.getLocation());
+ for ( VariantContext vc : VCs )
+ validate(vc, tracker, ref);
+
+ return VCs.size();
+ }
+
+ public Integer reduceInit() { return 0; }
+
+ public Integer reduce(Integer value, Integer sum) { return sum+value; }
+
+ public void onTraversalDone(Integer result) {
+ if ( numErrors == 0 )
+ System.out.println("Successfully validated the input file. Checked " + result + " records with no failures.");
+ else
+ System.out.println("Found " + numErrors + " records with failures.");
+ }
+
+ private void validate(VariantContext vc, RefMetaDataTracker tracker, ReferenceContext ref) {
+ if ( DO_NOT_VALIDATE_FILTERED && vc.isFiltered() )
+ return;
+
+ // get the true reference allele
+ final Allele reportedRefAllele = vc.getReference();
+ final int refLength = reportedRefAllele.length();
+ if ( refLength > 100 ) {
+ logger.info(String.format("Reference allele is too long (%d) at position %s:%d; skipping that record.", refLength, vc.getChr(), vc.getStart()));
+ return;
+ }
+
+ final byte[] observedRefBases = new byte[refLength];
+ System.arraycopy(ref.getBases(), 0, observedRefBases, 0, refLength);
+ final Allele observedRefAllele = Allele.create(observedRefBases);
+
+ // get the RS IDs
+ Set<String> rsIDs = null;
+ if ( tracker.hasValues(dbsnp.dbsnp) ) {
+ rsIDs = new HashSet<String>();
+ for ( VariantContext rsID : tracker.getValues(dbsnp.dbsnp, ref.getLocus()) )
+ rsIDs.addAll(Arrays.asList(rsID.getID().split(VCFConstants.ID_FIELD_SEPARATOR)));
+ }
+
+ try {
+ for (final ValidationType t : validationTypes)
+ applyValidationType(vc, reportedRefAllele, observedRefAllele, rsIDs, t);
+ } catch (TribbleException e) {
+ if ( WARN_ON_ERROR ) {
+ numErrors++;
+ logger.warn("***** " + e.getMessage() + " *****");
+ } else {
+ throw new UserException.FailsStrictValidation(file, e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Given the validation type and exclusion type, calculate the final set of type to validate.
+ * @param excludeTypes types to exclude.
+ *
+ * @throws UserException.BadArgumentValue if the user combines any validation type except 'ALL' and some exclude types.
+ *
+ * @return never {@code null} but perhaps an empty set.
+ */
+ private Collection<ValidationType> calculateValidationTypesToApply(final List<ValidationType> excludeTypes) {
+ if (excludeTypes.size() == 0)
+ return Collections.singleton(ValidationType.ALL);
+ final Set<ValidationType> excludeTypeSet = new LinkedHashSet<>(excludeTypes);
+ if (excludeTypes.size() != excludeTypeSet.size())
+ logger.warn("found repeat redundant validation types listed using the --validationTypeToExclude argument");
+ if (excludeTypeSet.contains(ValidationType.ALL)) {
+ if (excludeTypeSet.size() > 1)
+ logger.warn("found ALL in the --validationTypeToExclude list together with other concrete type exclusions that are redundant");
+ return Collections.emptyList();
+ } else {
+ final Set<ValidationType> result = new LinkedHashSet<>(ValidationType.CONCRETE_TYPES);
+ result.removeAll(excludeTypeSet);
+ return result;
+ }
+ }
+
+ private void applyValidationType(VariantContext vc, Allele reportedRefAllele, Allele observedRefAllele, Set<String> rsIDs, ValidationType t) {
+ switch( t ) {
+ case ALL:
+ vc.extraStrictValidation(reportedRefAllele, observedRefAllele, rsIDs);
+ break;
+ case REF:
+ vc.validateReferenceBases(reportedRefAllele, observedRefAllele);
+ break;
+ case IDS:
+ vc.validateRSIDs(rsIDs);
+ break;
+ case ALLELES:
+ vc.validateAlternateAlleles();
+ break;
+ case CHR_COUNTS:
+ vc.validateChromosomeCounts();
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantValidationAssessor.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantValidationAssessor.java
new file mode 100644
index 0000000..9031bf7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantValidationAssessor.java
@@ -0,0 +1,304 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import org.broadinstitute.gatk.engine.walkers.Reference;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.Window;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.QualityUtils;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.vcf.*;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+
+import java.util.*;
+
+/**
+ * Annotates a validation (from Sequenom for example) VCF with QC metrics (HW-equilibrium, % failed probes)
+ *
+ * <p>
+ * The Variant Validation Assessor is a tool for vetting/assessing validation data (containing genotypes).
+ * The tool produces a VCF that is annotated with information pertaining to plate quality control and by
+ * default is soft-filtered by high no-call rate or low Hardy-Weinberg probability.
+ * If you have .ped files, please first convert them to VCF format.
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A validation VCF to annotate.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * An annotated VCF. Additionally, a table like the following will be output:
+ * <pre>
+ * Total number of samples assayed: 185
+ * Total number of records processed: 152
+ * Number of Hardy-Weinberg violations: 34 (22%)
+ * Number of no-call violations: 12 (7%)
+ * Number of homozygous variant violations: 0 (0%)
+ * Number of records passing all filters: 106 (69%)
+ * Number of passing records that are polymorphic: 98 (92%)
+ * </pre>
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T VariantValidationAssessor \
+ * --variant input.vcf \
+ * -o output.vcf
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VALIDATION, extraDocs = {CommandLineGATK.class} )
+ at Reference(window=@Window(start=0,stop=40))
+public class VariantValidationAssessor extends RodWalker<VariantContext,Integer> {
+
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ @Output(doc="File to which variants should be written")
+ protected VariantContextWriter vcfwriter = null;
+
+ @Argument(fullName="maxHardy", doc="Maximum phred-scaled Hardy-Weinberg violation pvalue to consider an assay valid", required=false)
+ protected double maxHardy = 20.0;
+
+ /**
+ * To disable, set to a value greater than 1.
+ */
+ @Argument(fullName="maxNoCall", doc="Maximum no-call rate (as a fraction) to consider an assay valid", required=false)
+ protected double maxNoCall = 0.05;
+
+ /**
+ * To disable, set to a value greater than 1.
+ */
+ @Argument(fullName="maxHomVar", doc="Maximum homozygous variant rate (as a fraction) to consider an assay valid", required=false)
+ protected double maxHomNonref = 1.1;
+
+ //@Argument(fullName="populationFile", shortName="populations", doc="A tab-delimited file relating individuals to populations,"+
+ // "used for smart Hardy-Weinberg annotation",required = false)
+ //private File popFile = null;
+
+ // sample names
+ private TreeSet<String> sampleNames = null;
+
+ // variant context records
+ private ArrayList<VariantContext> records = new ArrayList<VariantContext>();
+
+ // statistics
+ private int numRecords = 0;
+ private int numHWViolations = 0;
+ private int numNoCallViolations = 0;
+ private int numHomVarViolations = 0;
+ private int numTrueVariants = 0;
+
+ //private HashMap<String,String> samplesToPopulation;
+
+ public void initialize() {
+ //if ( popFile != null ) {
+ // samplesToPopulation = parsePopulationFile(popFile);
+ //}
+ }
+
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ public VariantContext map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null )
+ return null;
+
+ VariantContext vc = tracker.getFirstValue(variantCollection.variants, ref.getLocus());
+ // ignore places where we don't have a variant
+ if ( vc == null )
+ return null;
+
+ if ( sampleNames == null )
+ sampleNames = new TreeSet<String>(vc.getSampleNames());
+
+ return addVariantInformationToCall(vc);
+ }
+
+ public Integer reduce(VariantContext call, Integer numVariants) {
+ if ( call != null ) {
+ numVariants++;
+ records.add(call);
+ }
+ return numVariants;
+ }
+
+ public void onTraversalDone(Integer finalReduce) {
+ final List<String> inputNames = Arrays.asList(variantCollection.variants.getName());
+
+ // setup the header fields
+ Set<VCFHeaderLine> hInfo = new HashSet<VCFHeaderLine>();
+ hInfo.addAll(GATKVCFUtils.getHeaderFields(getToolkit(), inputNames));
+
+ // set up the info and filter headers
+ hInfo.add(new VCFInfoHeaderLine("NoCallPct", 1, VCFHeaderLineType.Float, "Percent of no-calls"));
+ hInfo.add(new VCFInfoHeaderLine("HomRefPct", 1, VCFHeaderLineType.Float, "Percent of homozygous reference genotypes"));
+ hInfo.add(new VCFInfoHeaderLine("HetPct", 1, VCFHeaderLineType.Float, "Percent of heterozygous genotypes"));
+ hInfo.add(new VCFInfoHeaderLine("HomVarPct", 1, VCFHeaderLineType.Float, "Percent homozygous variant genotypes"));
+ hInfo.add(new VCFInfoHeaderLine("HW", 1, VCFHeaderLineType.Float, "Phred-scaled Hardy-Weinberg violation p-value"));
+ hInfo.add(VCFStandardHeaderLines.getInfoLine(VCFConstants.ALLELE_COUNT_KEY));
+ hInfo.add(VCFStandardHeaderLines.getInfoLine(VCFConstants.ALLELE_NUMBER_KEY));
+ hInfo.add(new VCFFilterHeaderLine("HardyWeinbergViolation", "The validation is in Hardy-Weinberg violation"));
+ hInfo.add(new VCFFilterHeaderLine("HighNoCallRate", "The validation no-call rate is too high"));
+ hInfo.add(new VCFFilterHeaderLine("TooManyHomVars", "The validation homozygous variant rate is too high"));
+
+ // print out (and add to headers) the validation metrics
+ System.out.println(String.format("Total number of samples assayed:\t\t\t%d", sampleNames.size()));
+ hInfo.add(new VCFHeaderLine("ValidationMetrics_SamplesAssayed", String.format("%d", sampleNames.size())));
+ System.out.println(String.format("Total number of records processed:\t\t\t%d", numRecords));
+ hInfo.add(new VCFHeaderLine("ValidationMetrics_RecordsProcessed", String.format("%d", numRecords)));
+ if ( numRecords > 0 ) {
+ System.out.println(String.format("Number of Hardy-Weinberg violations:\t\t\t%d (%d%%)", numHWViolations, 100*numHWViolations/numRecords));
+ hInfo.add(new VCFHeaderLine("ValidationMetrics_HardyWeinbergViolations", String.format("\"%d (%d%%)\"", numHWViolations, 100*numHWViolations/numRecords)));
+ System.out.println(String.format("Number of no-call violations:\t\t\t\t%d (%d%%)", numNoCallViolations, 100*numNoCallViolations/numRecords));
+ hInfo.add(new VCFHeaderLine("ValidationMetrics_NoCallViolations", String.format("\"%d (%d%%)\"", numNoCallViolations, 100*numNoCallViolations/numRecords)));
+ System.out.println(String.format("Number of homozygous variant violations:\t\t%d (%d%%)", numHomVarViolations, 100*numHomVarViolations/numRecords));
+ hInfo.add(new VCFHeaderLine("ValidationMetrics_HomVarViolations", String.format("\"%d (%d%%)\"", numHomVarViolations, 100*numHomVarViolations/numRecords)));
+ int goodRecords = numRecords - numHWViolations - numNoCallViolations - numHomVarViolations;
+ System.out.println(String.format("Number of records passing all filters:\t\t\t%d (%d%%)", goodRecords, 100*goodRecords/numRecords));
+ hInfo.add(new VCFHeaderLine("ValidationMetrics_RecordsPassingFilters", String.format("\"%d (%d%%)\"", goodRecords, 100*goodRecords/numRecords)));
+ if ( goodRecords > 0 ) {
+ System.out.println(String.format("Number of passing records that are polymorphic:\t\t%d (%d%%)", numTrueVariants, 100*numTrueVariants/goodRecords));
+ hInfo.add(new VCFHeaderLine("ValidationMetrics_PolymorphicPassingRecords", String.format("\"%d (%d%%)\"", numTrueVariants, 100*numTrueVariants/goodRecords)));
+ }
+ }
+
+ vcfwriter.writeHeader(new VCFHeader(hInfo, SampleUtils.getUniqueSamplesFromRods(getToolkit(), inputNames)));
+
+ for ( VariantContext record : records )
+ vcfwriter.add(record);
+ }
+
+
+ private VariantContext addVariantInformationToCall(VariantContext vContext) {
+
+ // check possible filters
+ double hwPvalue = hardyWeinbergCalculation(vContext);
+ double hwScore = Math.abs(QualityUtils.phredScaleErrorRate(hwPvalue));
+ double noCallProp = (double)vContext.getNoCallCount() / (double)vContext.getNSamples();
+ double homRefProp = (double)vContext.getHomRefCount() / (double)vContext.getNSamples();
+ double hetProp = (double)vContext.getHetCount() / (double)vContext.getNSamples();
+ double homVarProp = (double)vContext.getHomVarCount() / (double)vContext.getNSamples();
+
+ boolean isViolation = false;
+ Set<String> filters = new HashSet<String>();
+ if ( noCallProp > maxNoCall ) {
+ filters.add("HighNoCallRate");
+ numNoCallViolations++;
+ isViolation = true;
+ } else if ( hwScore > maxHardy ) {
+ filters.add("HardyWeinbergViolation");
+ numHWViolations++;
+ isViolation = true;
+ } else if ( homVarProp > maxHomNonref) {
+ filters.add("TooManyHomVars");
+ numHomVarViolations++;
+ isViolation = true;
+ }
+
+ VariantContextBuilder builder = new VariantContextBuilder(vContext).filters(filters);
+ numRecords++;
+
+ // add the info fields
+ builder.attribute("NoCallPct", String.format("%.1f", 100.0 * noCallProp));
+ builder.attribute("HomRefPct", String.format("%.1f", 100.0 * homRefProp));
+ builder.attribute("HomVarPct", String.format("%.1f", 100.0 * homVarProp));
+ builder.attribute("HetPct", String.format("%.1f", 100.0 * hetProp));
+ builder.attribute("HW", String.format("%.2f", hwScore));
+ Collection<Allele> altAlleles = vContext.getAlternateAlleles();
+ int altAlleleCount = altAlleles.size() == 0 ? 0 : vContext.getCalledChrCount(altAlleles.iterator().next());
+ if ( !isViolation && altAlleleCount > 0 )
+ numTrueVariants++;
+ builder.attribute(VCFConstants.ALLELE_COUNT_KEY, String.format("%d", altAlleleCount));
+ builder.attribute(VCFConstants.ALLELE_NUMBER_KEY, String.format("%d", vContext.getCalledChrCount()));
+
+ return builder.make();
+ }
+
+ private double hardyWeinbergCalculation(VariantContext vc) {
+ //if ( popFile != null ) {
+ // throw new GATKException("We still need to implement this!");
+ //} else {
+ return GATKVariantContextUtils.computeHardyWeinbergPvalue(vc);
+ //}
+ }
+
+ // TODO -- REWRITE THIS TO WORK WITH VARIANT CONTEXT
+ /******
+
+ private String smartHardy(ReferenceContext ref, VCFRecord rec) {
+ HashMap<String,ArrayList<Genotype>> genotypesByPopulation = new HashMap<String,ArrayList<Genotype>>(10);
+ HashMap<String,String> hardyWeinbergByPopulation = new HashMap<String,String>(10);
+
+ for ( String population : samplesToPopulation.values() ) {
+ genotypesByPopulation.put(population,new ArrayList<Genotype>());
+ }
+
+ //for ( String name : sampleNames ) {
+ // String pop = samplesToPopulation.get(name);
+ // if ( rec.getGenotype(name) != null ) {
+ // genotypesByPopulation.get(pop).add(rec.getGenotype(name));
+ // }
+ //}
+
+ for ( String population : samplesToPopulation.values() ) {
+ VCFVariationCall v = new VCFVariationCall(ref.getBase(),ref.getLocus(),VCFVariationCall.VARIANT_TYPE.SNP);
+ v.setGenotypeCalls(genotypesByPopulation.get(population));
+ hardyWeinbergByPopulation.put(population,HWCalc.annotate(null,ref,null,v));
+ }
+
+ return smartHardyString(hardyWeinbergByPopulation);
+ }
+
+ private String smartHardyString(HashMap<String,String> hwByPop) {
+ // for now just return the maximum:
+ int maxH = -100;
+ for ( String pop : samplesToPopulation.values() ) {
+ maxH = Integer.parseInt(hwByPop.get(pop)) > maxH ? Integer.parseInt(hwByPop.get(pop)) : maxH;
+ }
+
+ return String.format("%s",maxH);
+ }
+
+ *********/
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToAllelicPrimitives.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToAllelicPrimitives.java
new file mode 100644
index 0000000..1f7b20c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToAllelicPrimitives.java
@@ -0,0 +1,140 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import com.google.java.contract.Requires;
+import org.broadinstitute.gatk.utils.commandline.ArgumentCollection;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.variantcontext.writer.VariantContextWriterFactory;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+
+import java.util.*;
+
+/**
+ * Takes alleles from a variants file and breaks them up (if possible) into more basic/primitive alleles.
+ *
+ * <p>
+ * For now this tool modifies only multi-nucleotide polymorphisms (MNPs) and leaves SNPs, indels, and complex substitutions as is,
+ * although one day it may be extended to handle the complex substitution case.
+ *
+ * This tool will take an MNP (e.g. ACCCA -> TCCCG) and break it up into separate records for each component part (A-T and A->G).
+ *
+ * Note that this tool modifies only bi-allelic variants.
+ *
+ * <h2>Input</h2>
+ * <p>
+ * A variant set with any type of alleles.
+ * </p>
+ *
+ * <h2>Output</h2>
+ * <p>
+ * A VCF with alleles broken into primitive types.
+ * </p>
+ *
+ * <h2>Examples</h2>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T VariantsToAllelicPrimitives \
+ * --variant input.vcf \
+ * -o output.vcf
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+public class VariantsToAllelicPrimitives extends RodWalker<Integer, Integer> {
+
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ @Output(doc="File to which variants should be written")
+ protected VariantContextWriter baseWriter = null;
+
+ private VariantContextWriter vcfWriter;
+
+ public void initialize() {
+ final String trackName = variantCollection.variants.getName();
+ final Set<String> samples = SampleUtils.getSampleListWithVCFHeader(getToolkit(), Arrays.asList(trackName));
+
+ final Map<String, VCFHeader> vcfHeaders = GATKVCFUtils.getVCFHeadersFromRods(getToolkit(), Arrays.asList(trackName));
+ final Set<VCFHeaderLine> headerLines = vcfHeaders.get(trackName).getMetaDataInSortedOrder();
+
+ baseWriter.writeHeader(new VCFHeader(headerLines, samples));
+
+ vcfWriter = VariantContextWriterFactory.sortOnTheFly(baseWriter, 200);
+ }
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null )
+ return 0;
+
+ final Collection<VariantContext> VCs = tracker.getValues(variantCollection.variants, context.getLocation());
+
+ int changedSites = 0;
+ for ( final VariantContext vc : VCs )
+ changedSites += writeVariants(vc);
+
+ return changedSites;
+ }
+
+ public Integer reduceInit() { return 0; }
+
+ public Integer reduce(Integer value, Integer sum) {
+ return sum + value;
+ }
+
+ public void onTraversalDone(Integer result) {
+ System.out.println(result + " MNPs were broken up into primitives");
+ vcfWriter.close();
+ }
+
+ @Requires("vc != null")
+ private int writeVariants(final VariantContext vc) {
+ // for now, we modify only bi-allelic MNPs; update docs above if this changes
+ if ( vc.isBiallelic() && vc.isMNP() ) {
+ for ( final VariantContext splitVC : GATKVariantContextUtils.splitIntoPrimitiveAlleles(vc) )
+ vcfWriter.add(splitVC);
+ return 1;
+ } else {
+ vcfWriter.add(vc);
+ return 0;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToBinaryPed.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToBinaryPed.java
new file mode 100644
index 0000000..b51349a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToBinaryPed.java
@@ -0,0 +1,550 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import htsjdk.tribble.TribbleException;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.DbsnpArgumentCollection;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.Reference;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.Window;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.QualityUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import htsjdk.variant.vcf.VCFHeader;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+import htsjdk.variant.variantcontext.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Converts a VCF file to a binary plink Ped file (.bed/.bim/.fam)
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+ at Reference(window=@Window(start=0,stop=100))
+public class VariantsToBinaryPed extends RodWalker<Integer,Integer> {
+ @ArgumentCollection
+ protected StandardVariantContextInputArgumentCollection variantCollection = new StandardVariantContextInputArgumentCollection();
+
+ @ArgumentCollection
+ protected DbsnpArgumentCollection dbsnp = new DbsnpArgumentCollection();
+
+ /**
+ * The metaData file can take two formats, the first of which is the first 6 lines of the standard ped file. This
+ * is what Plink describes as a fam file. An example fam file is (note that there is no header):
+ * <p><p>
+ * CEUTrio NA12878 NA12891 NA12892 2 -9</p><p>
+ * CEUTrio NA12891 UNKN1 UNKN2 2 -9</p><p>
+ * CEUTrio NA12892 UNKN3 UNKN4 1 -9</p><p>
+ * </p>
+ * where the entries are (FamilyID IndividualID DadID MomID Phenotype Sex)
+ * <p>
+ * An alternate format is a two-column key-value file
+ * </p><p><p>
+ * NA12878 fid=CEUTrio;dad=NA12891;mom=NA12892;sex=2;phenotype=-9</p><p>
+ * NA12891 fid=CEUTrio;sex=2;phenotype=-9</p><p>
+ * NA12892 fid=CEUTrio;sex=1;phenotype=-9</p><p>
+ * </p><p>
+ * wherein unknown parents needn't be specified. The columns are the individual ID, and a list of key-value pairs.
+ * </p><p>
+ * Regardless of which file is specified, the walker will output a .fam file alongside the bed file. If the
+ * command line has "-md [name].fam", the fam file will be subset and reordered to match the sample content and ordering
+ * of the VCF. However, if a metadata file of the alternate format is passed by "-md [name].txt", the walker will
+ * construct a formatted .fam file from the data.
+ * </p>
+ */
+ @Input(shortName="m",fullName = "metaData",required=true,doc="Sample metadata file. You may specify a .fam file " +
+ "(in which case it will be copied to the file you provide as fam output).")
+ File metaDataFile;
+
+ @Input(shortName="mode",fullName="outputMode",required=false,doc="The output file mode (SNP major or individual major)")
+ OutputMode mode = OutputMode.INDIVIDUAL_MAJOR;
+
+ @Output(shortName="bed",fullName = "bed",required=true,doc="output ped file")
+ PrintStream outBed;
+
+ @Output(shortName="bim",fullName="bim",required=true,doc="output map file")
+ PrintStream outBim;
+
+ @Output(shortName="fam",fullName="fam",required=true,doc="output fam file")
+ PrintStream outFam;
+
+ @Argument(shortName="mgq",fullName="minGenotypeQuality",required=true,doc="If genotype quality is lower than this value, output NO_CALL")
+ int minGenotypeQuality = 0;
+
+ @Argument(fullName="majorAlleleFirst",required=false,doc="Sets the major allele to be 'reference' for the bim file, rather than the ref allele")
+ boolean majorAlleleFirst = false;
+
+ @Argument(fullName="checkAlternateAlleles",required=false,doc="Checks that alternate alleles actually appear in samples, erroring out if they do not")
+ boolean checkAlternateAlleles = false;
+
+ enum OutputMode { INDIVIDUAL_MAJOR,SNP_MAJOR }
+
+ private static double APPROX_CM_PER_BP = 1000000.0/750000.0;
+
+ private static final byte HOM_REF = 0x0;
+ private static final byte HOM_VAR = 0x3;
+ private static final byte HET = 0x2;
+ private static final byte NO_CALL = 0x1;
+
+ private static final int BUFFER_SIZE = 1000; //4k genotypes per sample = Nmb for N*1000 samples
+
+ private static final String PLINK_DELETION_MARKER = "-";
+
+ // note that HET and NO_CALL are flipped from the documentation: that's because
+ // plink actually reads these in backwards; and we want to use a shift operator
+ // to put these in the appropriate location
+
+ private Map<String,OutputStream> printMap = new HashMap<String,OutputStream>();
+ private Map<String,File> tempFiles = new HashMap<String,File>();
+ private Map<String,byte[]> genotypeBuffer = new HashMap<String,byte[]>();
+ private int genotypeCount = 0;
+ private int byteCount = 0;
+ private List<String> famOrder = new ArrayList<String>();
+ private long totalByteCount = 0l;
+ private long totalGenotypeCount = 0l;
+
+ public void initialize() {
+ writeBedHeader();
+ Map<String,Map<String,String>> sampleMetaValues = parseMetaData();
+ // create temporary output streams and buffers
+
+ // family ID, individual ID, Paternal ID, Maternal ID, Sex, Phenotype
+ int dummyID = 0; // increments for dummy parental and family IDs used
+ // want to be especially careful to maintain order here
+ Map<String,VCFHeader> headers = GATKVCFUtils.getVCFHeadersFromRods(getToolkit());
+ for ( Map.Entry<String,VCFHeader> header : headers.entrySet() ) {
+ if ( ! header.getKey().equals(variantCollection.variants.getName()) && ! metaDataFile.getAbsolutePath().endsWith(".fam") ) {
+ continue;
+ }
+ for ( String sample : header.getValue().getGenotypeSamples() ) {
+ if ( ! metaDataFile.getAbsolutePath().endsWith(".fam") ) {
+ Map<String,String> mVals = sampleMetaValues.get(sample);
+ if ( mVals == null ) {
+ throw new UserException("No metadata provided for sample "+sample);
+ }
+ if ( ! mVals.containsKey("phenotype") ) {
+ throw new UserException("No phenotype data provided for sample "+sample);
+ }
+ String fid = mVals.containsKey("fid") ? mVals.get("fid") : String.format("dummy_%d",++dummyID);
+ String pid = mVals.containsKey("dad") ? mVals.get("dad") : String.format("dummy_%d",++dummyID);
+ String mid = mVals.containsKey("mom") ? mVals.get("mom") : String.format("dummy_%d",++dummyID);
+ String sex = mVals.containsKey("sex") ? mVals.get("sex") : "3";
+ String pheno = mVals.get("phenotype");
+ outFam.printf("%s\t%s\t%s\t%s\t%s\t%s%n",fid,sample,pid,mid,sex,pheno);
+ } else {
+ // even if a fam file is input, we can't diverge the bed file from the fam file, which
+ // could lead to a malformed plink trio. Fail fast if there's any extra sample in the VCF.
+ if ( ! sampleMetaValues.containsKey(sample) ) {
+ throw new UserException("No metadata provided for sample "+sample);
+ }
+ Map<String,String> mVals = sampleMetaValues.get(sample);
+ String fid = mVals.containsKey("fid") ? mVals.get("fid") : String.format("dummy_%d",++dummyID);
+ String pid = mVals.containsKey("dad") ? mVals.get("dad") : String.format("dummy_%d",++dummyID);
+ String mid = mVals.containsKey("mom") ? mVals.get("mom") : String.format("dummy_%d",++dummyID);
+ String sex = mVals.containsKey("sex") ? mVals.get("sex") : "3";
+ String pheno = mVals.containsKey("phenotype") ? mVals.get("phenotype") : "-1";
+ outFam.printf("%s\t%s\t%s\t%s\t%s\t%s%n",fid,sample,pid,mid,sex,pheno);
+ }
+ if ( mode == OutputMode.INDIVIDUAL_MAJOR ) {
+ // only need to instantiate the files and buffers if in individual major.
+ // Cut down on memory.
+ try {
+ File temp = File.createTempFile("VariantsToBPed_"+sample, ".tmp");
+ temp.deleteOnExit();
+ printMap.put(sample,new PrintStream(temp));
+ tempFiles.put(sample,temp);
+ } catch (IOException e) {
+ throw new ReviewedGATKException("Error creating temporary file",e);
+ }
+ genotypeBuffer.put(sample,new byte[BUFFER_SIZE]);
+ }
+ famOrder.add(sample);
+ }
+ }
+ }
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null ) {
+ return 0;
+ }
+
+ VariantContext vc = tracker.getFirstValue(variantCollection.variants,context.getLocation());
+ if ( vc == null || vc.isFiltered() || ! vc.isBiallelic() ) {
+ return 0;
+ }
+ try {
+ validateVariantSite(vc,ref,context);
+ } catch (TribbleException e) {
+ throw new UserException("Input VCF file is invalid; we cannot guarantee the resulting ped file. "+
+ "Please run ValidateVariants for more detailed information. This error is: "+e.getMessage());
+ }
+
+ String refOut;
+ String altOut;
+ String vcRef = getReferenceAllele(vc);
+ String vcAlt = getAlternateAllele(vc);
+ boolean altMajor;
+ if ( majorAlleleFirst ) {
+ // want to use the major allele as ref
+ HashMap<String,Object> ats = new HashMap<String,Object>(vc.getAttributes());
+ if ( ! vc.hasAttribute("AF") ) {
+ VariantContextUtils.calculateChromosomeCounts(vc,ats,true);
+ }
+ if ( getAF(ats.get("AF")) > 0.5 ) {
+ refOut = vcAlt;
+ altOut = vcRef;
+ altMajor = true;
+ } else {
+ refOut = vcRef;
+ altOut = vcAlt;
+ altMajor = false;
+ }
+ } else {
+ refOut = vcRef;
+ altOut = vcAlt;
+ altMajor = false;
+ }
+ // write an entry into the map file
+ outBim.printf("%s\t%s\t%.2f\t%d\t%s\t%s%n",vc.getChr(),getID(vc),APPROX_CM_PER_BP*vc.getStart(),vc.getStart(),
+ refOut,altOut);
+ if ( mode == OutputMode.INDIVIDUAL_MAJOR ) {
+ writeIndividualMajor(vc,altMajor);
+ } else {
+ writeSNPMajor(vc,altMajor);
+ }
+
+
+ return 1;
+ }
+
+ public void writeIndividualMajor(VariantContext vc, boolean altMajor) {
+ // store genotypes per sample into the buffer
+ for ( Genotype g : vc.getGenotypes() ) {
+ ++totalGenotypeCount;
+ String sample = g.getSampleName();
+ byte[] samBuf = genotypeBuffer.get(sample);
+ byte enc = getEncoding(g,genotypeCount,altMajor);
+ samBuf[byteCount] |= enc;
+ }
+
+ genotypeCount++;
+ if ( genotypeCount % 4 == 0 ) {
+ byteCount++;
+ if ( byteCount >= BUFFER_SIZE ) {
+ // dump the buffer to the print streams
+ for ( String sample : printMap.keySet() ) {
+ OutputStream samOut = printMap.get(sample);
+ // print the buffer for this sample
+ try {
+ samOut.write(genotypeBuffer.get(sample));
+ } catch ( IOException e ) {
+ throw new ReviewedGATKException("Error writing to temporary bed file.",e);
+ }
+ // reset the buffer for this sample
+ genotypeBuffer.put(sample,new byte[BUFFER_SIZE]);
+ }
+ byteCount = 0;
+ }
+ genotypeCount = 0;
+ }
+ }
+
+ public void writeSNPMajor(VariantContext vc, boolean altMajor) {
+ // for each sample, write the genotype into the bed file, in the
+ // order of the fam file
+ genotypeCount = 0;
+ byteCount = 0;
+ byte[] bytes = new byte[(3+famOrder.size())/4]; // this exploits java integer fractions, which round down by default (1-4) -> 1, (5-8) -> 2
+ for ( Genotype g : vc.getGenotypesOrderedBy(famOrder) ) {
+ byte enc = getEncoding(g,genotypeCount,altMajor);
+ bytes[byteCount] |= enc;
+ genotypeCount++;
+ if ( genotypeCount % 4 == 0 ) {
+ byteCount++;
+ genotypeCount = 0;
+ }
+ }
+ totalGenotypeCount += famOrder.size();
+ totalByteCount += bytes.length;
+ try {
+ outBed.write(bytes);
+ } catch (IOException e) {
+ throw new ReviewedGATKException("Error writing to output bed file",e);
+ }
+ }
+
+ public Integer reduce(Integer m, Integer r) {
+ return r + m;
+ }
+
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ public void onTraversalDone(Integer numSites) {
+ logger.info(String.format("%d sites processed for a total of %d genotypes encoded in %d bytes",numSites,totalGenotypeCount,totalByteCount));
+
+ if ( mode == OutputMode.INDIVIDUAL_MAJOR ) {
+ mergeGenotypeTempFiles(numSites);
+ }
+
+ }
+
+ private void mergeGenotypeTempFiles(int numSites) {
+ // push out the remaining genotypes and close stream
+ for ( String sample : printMap.keySet() ) {
+ try {
+ int lim = byteCount + (genotypeCount > 0 ? 1 : 0);
+ printMap.get(sample).write(genotypeBuffer.get(sample),0,lim);
+ } catch (IOException e) {
+ throw new ReviewedGATKException("Error closing temporary file.",e);
+ }
+
+ try {
+ printMap.get(sample).close();
+ } catch (IOException e) {
+ throw new ReviewedGATKException("Error closing temporary file.",e);
+ }
+ }
+ for ( String sample : famOrder ) {
+ logger.info("Merging genotypes for "+sample);
+ FileInputStream inStream;
+ try {
+ inStream = new FileInputStream(tempFiles.get(sample));
+ } catch (IOException e) {
+ throw new ReviewedGATKException("Error opening temp file for input.",e);
+ }
+
+
+ try {
+ int ttr = numSites/4 + (genotypeCount > 0 ? 1 : 0);
+ for ( ; ttr > BUFFER_SIZE ; ttr -= BUFFER_SIZE ) {
+ byte[] readGenotypes = new byte[BUFFER_SIZE];
+ inStream.read(readGenotypes);
+ outBed.write(readGenotypes);
+ totalByteCount += BUFFER_SIZE;
+ }
+ if ( ttr > 0 ) {
+ byte[] readGenotypes = new byte[ttr];
+ inStream.read(readGenotypes);
+ outBed.write(readGenotypes);
+ totalByteCount += ttr;
+ }
+ inStream.close();
+ } catch (IOException e) {
+ throw new ReviewedGATKException("Error reading form temp file for input.",e);
+ }
+ }
+ }
+
+ private byte getEncoding(Genotype g, int offset, boolean altMajor) {
+ if ( ! altMajor ) {
+ return getStandardEncoding(g,offset);
+ }
+
+ return getFlippedEncoding(g,offset);
+ }
+
+ private byte getStandardEncoding(Genotype g, int offset) {
+ byte b;
+ if ( ! checkGQIsGood(g) ) {
+ b = NO_CALL;
+ } else if ( g.isHomRef() ) {
+ b = HOM_REF;
+ } else if ( g.isHomVar() ) {
+ b = HOM_VAR;
+ } else if ( g.isHet() ) {
+ b = HET;
+ } else {
+ b = NO_CALL;
+ }
+
+ return (byte) (b << (2*offset));
+ }
+
+ private byte getFlippedEncoding(Genotype g, int offset) {
+ byte b;
+ if ( ! checkGQIsGood(g) ) {
+ b = NO_CALL;
+ } else if ( g.isHomRef() ) {
+ b = HOM_VAR;
+ } else if ( g.isHomVar() ) {
+ b = HOM_REF;
+ } else if ( g.isHet() ) {
+ b = HET;
+ } else {
+ b = NO_CALL;
+ }
+
+ return (byte) (b << (2*offset));
+ }
+
+ private boolean checkGQIsGood(Genotype genotype) {
+ if ( genotype.hasGQ() ) {
+ return genotype.getGQ() >= minGenotypeQuality;
+ } else if ( genotype.hasLikelihoods() ) {
+ double log10gq = GenotypeLikelihoods.getGQLog10FromLikelihoods(genotype.getType().ordinal()-1,genotype.getLikelihoods().getAsVector());
+ return QualityUtils.phredScaleLog10ErrorRate(log10gq) >= minGenotypeQuality;
+ }
+
+ return minGenotypeQuality <= 0;
+ }
+
+ private static String getID(VariantContext v) {
+ if ( v.hasID() ) {
+ return v.getID();
+ } else {
+ return String.format("Var-%s-%d",v.getChr(),v.getStart());
+ }
+ }
+
+ private double getAF(Object o) {
+ if ( (o instanceof String) ) {
+ return Double.parseDouble((String) o);
+ } else if ( (o instanceof Double) ) {
+ return (Double) o;
+ } else {
+ throw new UserException("Allele frequency appears to be neither String nor Double. Please check the header of your VCF.");
+ }
+ }
+
+ private void writeBedHeader() {
+ // write magic bits into the ped file
+ try {
+ outBed.write(new byte[] { (byte) 0x6c, (byte) 0x1b, (byte) (mode == OutputMode.INDIVIDUAL_MAJOR ? 0x0 : 0x1)});
+ // ultimately, the bed will be in individual-major mode
+ } catch (IOException e) {
+ throw new ReviewedGATKException("error writing to output file.");
+ }
+ }
+
+ private Map<String,Map<String,String>> parseMetaData() {
+ // write to the fam file, the first six columns of the standard ped file
+ // first, load data from the input meta data file
+ Map<String,Map<String,String>> metaValues = new HashMap<String,Map<String,String>>();
+ logger.debug("Reading in metadata...");
+ try {
+ if ( metaDataFile.getAbsolutePath().endsWith(".fam") ) {
+ for ( String line : new XReadLines(metaDataFile) ) {
+ String[] famSplit = line.split("\\s+");
+ if ( famSplit.length != 6 ) {
+ throw new UserException("Line of the fam file is malformatted. Expected 6 entries. Line is "+line);
+ }
+ String sid = famSplit[1];
+ String fid = famSplit[0];
+ String mom = famSplit[2];
+ String dad = famSplit[3];
+ String sex = famSplit[4];
+ String pheno = famSplit[5];
+ HashMap<String,String> values = new HashMap<String, String>();
+ values.put("mom",mom);
+ values.put("dad",dad);
+ values.put("fid",fid);
+ values.put("sex",sex);
+ values.put("phenotype",pheno);
+ metaValues.put(sid,values);
+ }
+ } else {
+ for ( String line : new XReadLines(metaDataFile) ) {
+ logger.debug(line);
+ String[] split = line.split("\\s+");
+ String sampleID = split[0];
+ String keyVals = split[1];
+ HashMap<String,String> values = new HashMap<String, String>();
+ for ( String kvp : keyVals.split(";") ) {
+ String[] kvp_split = kvp.split("=");
+ values.put(kvp_split[0],kvp_split[1]);
+ }
+ metaValues.put(sampleID,values);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ throw new UserException("Meta data file not found: "+metaDataFile.getAbsolutePath(),e);
+ }
+
+ return metaValues;
+ }
+
+ private void validateVariantSite(VariantContext vc, ReferenceContext ref, AlignmentContext context) {
+ final Allele reportedRefAllele = vc.getReference();
+ final int refLength = reportedRefAllele.length();
+ if ( refLength > 100 ) {
+ logger.info(String.format("Reference allele is too long (%d) at position %s:%d; skipping that record.", refLength, vc.getChr(), vc.getStart()));
+ return;
+ }
+
+ final byte[] observedRefBases = new byte[refLength];
+ System.arraycopy(ref.getBases(), 0, observedRefBases, 0, refLength);
+ final Allele observedRefAllele = Allele.create(observedRefBases);
+ vc.validateReferenceBases(reportedRefAllele, observedRefAllele);
+ if ( checkAlternateAlleles )
+ vc.validateAlternateAlleles();
+ }
+
+ private String getReferenceAllele(VariantContext vc) {
+ if ( vc.isSimpleInsertion() ) {
+ // bi-allelic, so we just have "-" for ped output
+ return PLINK_DELETION_MARKER;
+ }
+ if ( vc.isSymbolic() ) {
+ // either symbolic or really long alleles. Plink alleles are allowed to be 1 or 2. Reference will just be 1.
+ return "1";
+ }
+ if ( vc.isSimpleDeletion() ) {
+ // bi-allelic. Want to take the standard representation and strip off the leading base.
+ return vc.getReference().getBaseString().substring(1);
+ }
+ // snp or mnp
+ return vc.getReference().getBaseString();
+ }
+
+ private String getAlternateAllele(VariantContext vc ) {
+ if ( vc.isSimpleInsertion() ) {
+ // bi-allelic. Want to take the standard representation and strip off the leading base.
+ return vc.getAlternateAllele(0).getBaseString().substring(1);
+ }
+ if ( vc.isSymbolic() ) {
+ // either symbolic or really long alleles. Plink alleles are allowed to be 1 or 2. Alt will just be 2.
+ return "2";
+ }
+ if ( vc.isSimpleDeletion() ) {
+ // bi-allelic, so we just have "-" for ped output
+ return PLINK_DELETION_MARKER;
+ }
+ // snp or mnp
+ return vc.getAlternateAllele(0).getBaseString();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToTable.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToTable.java
new file mode 100644
index 0000000..9a65a70
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToTable.java
@@ -0,0 +1,460 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.vcf.VCFConstants;
+import htsjdk.variant.vcf.VCFHeader;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.PrintStream;
+import java.lang.reflect.Array;
+import java.util.*;
+
+/**
+ * Emits specific fields from a VCF file to a tab-deliminated table
+ *
+ * <p>
+ * This walker accepts a single VCF file and writes out user-selected fields from the
+ * VCF as a header-containing, tab-deliminated file. The user specifies one or more
+ * fields to print with the -F NAME, each of which appears as a single column in
+ * the output file, with a header named NAME, and the value of this field in the VCF
+ * one per line. NAME can be any standard VCF column (CHROM, ID, QUAL) or any binding
+ * in the INFO field (AC=10). In addition, there are specially supported values like
+ * EVENTLENGTH (length of the event), TRANSITION (for SNPs), HET (count of het genotypes),
+ * HOM-REF (count of homozygous reference genotypes), HOM-VAR (count of homozygous variant
+ * genotypes), NO-CALL (count of no-call genotypes), TYPE (the type of event), VAR (count of
+ * non-reference genotypes), NSAMPLES (number of samples), NCALLED (number of called samples),
+ * GQ (from the genotype field; works only for a file with a single sample), and MULTI-ALLELIC
+ * (is the record from a multi-allelic site). Note that if a VCF record is missing a value, then the tool by
+ * default throws an error, but the special value NA can be emitted instead with
+ * appropriate tool arguments.
+ *
+ * </p>
+ *
+ * <h3>Input</h3>
+ * <p>
+ * <ul>
+ * <li>A VCF file</li>
+ * <li>A list of -F fields to write</li>
+ * </ul>
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A tab-delimited file containing the values of the requested fields in the VCF file
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -jar GenomeAnalysisTK.jar \
+ * -R reference.fasta
+ * -T VariantsToTable \
+ * -V file.vcf \
+ * -F CHROM -F POS -F ID -F QUAL -F AC \
+ * -o results.table
+ *
+ * would produce a file that looks like:
+ *
+ * CHROM POS ID QUAL AC
+ * 1 10 . 50 1
+ * 1 20 rs10 99 10
+ * et cetera...
+ * </pre>
+ *
+ * @author Mark DePristo
+ * @since 2010
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+public class VariantsToTable extends RodWalker<Integer, Integer> {
+ /**
+ * Variants from this VCF file are used by this tool as input.
+ * The file must at least contain the standard VCF header lines, but
+ * can be empty (i.e., no variants are contained in the file).
+ */
+ @Input(fullName="variant", shortName = "V", doc="Input VCF file", required=true)
+ public List<RodBinding<VariantContext>> variants;
+
+ @Output(doc="File to which results should be written")
+ protected PrintStream out;
+
+ /**
+ * -F NAME can be any standard VCF column (CHROM, ID, QUAL) or any binding in the INFO field (e.g., AC=10).
+ * Note that to capture GENOTYPE (FORMAT) field values, see the GF argument. This argument accepts any number
+ * of inputs. So -F CHROM -F POS is allowed.
+ */
+ @Argument(fullName="fields", shortName="F", doc="The name of each field to capture for output in the table", required=false)
+ public List<String> fieldsToTake = new ArrayList<String>();
+
+ /**
+ * -GF NAME can be any binding in the FORMAT field (e.g., GQ, PL).
+ * Note this argument accepts any number of inputs. So -GF GQ -GF PL is allowed.
+ */
+ @Argument(fullName="genotypeFields", shortName="GF", doc="The name of each genotype field to capture for output in the table", required=false)
+ public List<String> genotypeFieldsToTake = new ArrayList<String>();
+
+ /**
+ * By default this tool only emits values for fields where the FILTER field is either PASS or . (unfiltered).
+ * Throwing this flag will cause VariantsToTable to emit values regardless of the FILTER field value.
+ */
+ @Advanced
+ @Argument(fullName="showFiltered", shortName="raw", doc="If provided, field values from filtered records will be included in the output", required=false)
+ public boolean showFiltered = false;
+
+ /**
+ * If provided, then this tool will exit with success after this number of VCF records have been emitted to the file.
+ */
+ @Argument(fullName="maxRecords", shortName="M", doc="If provided, we will emit at most maxRecord records to the table", required=false)
+ public int MAX_RECORDS = -1;
+ long nRecords = 0L;
+
+ /**
+ * By default, records with multiple ALT alleles will comprise just one line of output; note that in general this can make your resulting file
+ * unreadable/malformed for certain tools like R, as the representation of multi-allelic INFO field values are often comma-separated lists
+ * of values. Using the flag will cause multi-allelic records to be split into multiple lines of output (one for each allele in the ALT field);
+ * INFO field values that are not lists are copied for each of the output records while only the appropriate entry is used for lists.
+ */
+ @Argument(fullName="splitMultiAllelic", shortName="SMA", doc="If provided, we will split multi-allelic records into multiple lines of output", required=false)
+ public boolean splitMultiAllelic = false;
+
+ /**
+ * By default, this tool emits one line per usable VCF record (or per allele if the -SMA flag is provided). Using the -moltenize flag
+ * will cause records to be split into multiple lines of output: one for each field provided with -F or one for each combination of sample
+ * and field provided with -GF. Note that the "Sample" column for -F fields will always be "site".
+ */
+ @Advanced
+ @Argument(fullName="moltenize", shortName="moltenize", doc="If provided, we will produce molten output", required=false)
+ public boolean moltenizeOutput = false;
+
+ /**
+ * By default, this tool throws a UserException when it encounters a field without a value in some record. This
+ * is generally useful when you mistype -F CHROM, so that you get a friendly warning about CHROM not being
+ * found before the tool runs through 40M 1000G records. However, in some cases you genuinely want to allow such
+ * fields (e.g., AC not being calculated for filtered records, if included). When provided, this argument
+ * will cause VariantsToTable to write out NA values for missing fields instead of throwing an error.
+ */
+ @Advanced
+ @Argument(fullName="allowMissingData", shortName="AMD", doc="If provided, we will not require every record to contain every field", required=false)
+ public boolean ALLOW_MISSING_DATA = false;
+ private final static String MISSING_DATA = "NA";
+
+ private final List<String> samples = new ArrayList<String>();
+
+ public void initialize() {
+
+ if ( !genotypeFieldsToTake.isEmpty() ) {
+ Map<String, VCFHeader> vcfRods = GATKVCFUtils.getVCFHeadersFromRods(getToolkit(), variants);
+ TreeSet<String> vcfSamples = new TreeSet<String>(SampleUtils.getSampleList(vcfRods, GATKVariantContextUtils.GenotypeMergeType.REQUIRE_UNIQUE));
+ samples.addAll(vcfSamples);
+
+ // optimization: if there are no samples, we don't have to worry about any genotype fields
+ if ( samples.isEmpty() )
+ genotypeFieldsToTake.clear();
+ }
+
+ // print out the header
+ if ( moltenizeOutput ) {
+ out.println("RecordID\tSample\tVariable\tValue");
+ } else {
+ final String baseHeader = Utils.join("\t", fieldsToTake);
+ final String genotypeHeader = createGenotypeHeader(genotypeFieldsToTake, samples);
+ final String separator = (!baseHeader.isEmpty() && !genotypeHeader.isEmpty()) ? "\t" : "";
+ out.println(baseHeader + separator + genotypeHeader);
+ }
+ }
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null ) // RodWalkers can make funky map calls
+ return 0;
+
+ for ( VariantContext vc : tracker.getValues(variants, context.getLocation())) {
+ if ( showFiltered || vc.isNotFiltered() ) {
+ nRecords++;
+ for ( final List<String> record : extractFields(vc, fieldsToTake, genotypeFieldsToTake, samples, ALLOW_MISSING_DATA, splitMultiAllelic) ) {
+ if ( moltenizeOutput )
+ emitMoltenizedOutput(record);
+ else
+ out.println(Utils.join("\t", record));
+ }
+ }
+ }
+
+ return 1;
+ }
+
+ @Override
+ public boolean isDone() {
+ return (MAX_RECORDS != -1 && nRecords >= MAX_RECORDS);
+ }
+
+ private static final boolean isWildCard(String s) {
+ return s.endsWith("*");
+ }
+
+ private static String createGenotypeHeader(final List<String> genotypeFieldsToTake, final List<String> samples) {
+ boolean firstEntry = true;
+
+ final StringBuilder sb = new StringBuilder();
+ for ( final String sample : samples ) {
+ for ( final String gf : genotypeFieldsToTake ) {
+ if ( firstEntry )
+ firstEntry = false;
+ else
+ sb.append("\t");
+ // spaces in sample names are legal but wreak havoc in R data frames
+ sb.append(sample.replace(" ","_"));
+ sb.append(".");
+ sb.append(gf);
+ }
+ }
+ return sb.toString();
+ }
+
+ private void emitMoltenizedOutput(final List<String> record) {
+ int index = 0;
+ for ( final String field : fieldsToTake ) {
+ out.println(String.format("%d\tsite\t%s\t%s", nRecords, field, record.get(index++)));
+ }
+ for ( final String sample : samples ) {
+ for ( final String gf : genotypeFieldsToTake ) {
+ out.println(String.format("%d\t%s\t%s\t%s", nRecords, sample.replace(" ","_"), gf, record.get(index++)));
+ }
+ }
+ }
+
+ /**
+ * Utility function that returns the list of values for each field in fields from vc.
+ *
+ * @param vc the VariantContext whose field values we can to capture
+ * @param fields a non-null list of fields to capture from VC
+ * @param genotypeFields a (possibly null) list of fields to capture from each genotype
+ * @param samples list of samples in vc
+ * @param allowMissingData if false, then throws a UserException if any field isn't found in vc. Otherwise provides a value of NA
+ * @param splitMultiAllelic if true, multiallelic variants are to be split into multiple records
+ * @return List of lists of field values
+ */
+ private static List<List<String>> extractFields(final VariantContext vc,
+ final List<String> fields,
+ final List<String> genotypeFields,
+ final List<String> samples,
+ final boolean allowMissingData,
+ final boolean splitMultiAllelic) {
+
+ final int numRecordsToProduce = splitMultiAllelic ? vc.getAlternateAlleles().size() : 1;
+ final List<List<String>> records = new ArrayList<List<String>>(numRecordsToProduce);
+
+ int numFields = fields.size();
+ final boolean addGenotypeFields = genotypeFields != null && !genotypeFields.isEmpty();
+ if ( addGenotypeFields )
+ numFields += genotypeFields.size() * samples.size();
+
+ for ( int i = 0; i < numRecordsToProduce; i++ )
+ records.add(new ArrayList<String>(numFields));
+
+ for ( String field : fields ) {
+
+ if ( splitMultiAllelic && field.equals("ALT") ) { // we need to special case the ALT field when splitting out multi-allelic records
+ addFieldValue(splitAltAlleles(vc), records);
+ } else if ( getters.containsKey(field) ) {
+ addFieldValue(getters.get(field).get(vc), records);
+ } else if ( vc.hasAttribute(field) ) {
+ addFieldValue(vc.getAttribute(field, null), records);
+ } else if ( isWildCard(field) ) {
+ Set<String> wildVals = new HashSet<String>();
+ for ( Map.Entry<String,Object> elt : vc.getAttributes().entrySet()) {
+ if ( elt.getKey().startsWith(field.substring(0, field.length() - 1)) ) {
+ wildVals.add(elt.getValue().toString());
+ }
+ }
+
+ String val = MISSING_DATA;
+ if ( wildVals.size() > 0 ) {
+ List<String> toVal = new ArrayList<String>(wildVals);
+ Collections.sort(toVal);
+ val = Utils.join(",", toVal);
+ }
+
+ addFieldValue(val, records);
+ } else if ( ! allowMissingData ) {
+ throw new UserException(String.format("Missing field %s in vc %s at %s", field, vc.getSource(), vc));
+ } else {
+ addFieldValue(MISSING_DATA, records);
+ }
+ }
+
+ if ( addGenotypeFields ) {
+ for ( final String sample : samples ) {
+ for ( final String gf : genotypeFields ) {
+ if ( vc.hasGenotype(sample) && vc.getGenotype(sample).hasAnyAttribute(gf) ) {
+ if ( gf.equals(VCFConstants.GENOTYPE_KEY) )
+ addFieldValue(vc.getGenotype(sample).getGenotypeString(true), records);
+ else
+ addFieldValue(vc.getGenotype(sample).getAnyAttribute(gf), records);
+ }
+ else
+ addFieldValue(MISSING_DATA, records);
+ }
+ }
+ }
+
+ return records;
+ }
+
+ private static void addFieldValue(final Object val, final List<List<String>> result) {
+ final int numResultRecords = result.size();
+
+ // if we're trying to create a single output record, add it
+ if ( numResultRecords == 1 ) {
+ result.get(0).add(prettyPrintObject(val));
+ }
+ // if this field is a list of the proper size, add the appropriate entry to each record
+ else if ( (val instanceof List) && ((List)val).size() == numResultRecords ) {
+ final List list = (List)val;
+ for ( int i = 0; i < numResultRecords; i++ )
+ result.get(i).add(list.get(i).toString());
+ }
+ // otherwise, add the original value to all of the records
+ else {
+ final String valStr = val.toString();
+ for ( List<String> record : result )
+ record.add(valStr);
+ }
+ }
+
+ private static String prettyPrintObject(final Object val) {
+ if ( val instanceof List )
+ return prettyPrintObject(((List)val).toArray());
+
+ if ( !val.getClass().isArray() )
+ return val.toString();
+
+ final int length = Array.getLength(val);
+ if ( length == 0 )
+ return "";
+
+ final StringBuilder sb = new StringBuilder(prettyPrintObject(Array.get(val, 0)));
+ for ( int i = 1; i < length; i++ ) {
+ sb.append(",");
+ sb.append(prettyPrintObject(Array.get(val, i)));
+ }
+ return sb.toString();
+ }
+
+
+ public static List<List<String>> extractFields(VariantContext vc, List<String> fields, boolean allowMissingData) {
+ return extractFields(vc, fields, null, null, allowMissingData, false);
+ }
+ //
+ // default reduce -- doesn't do anything at all
+ //
+ public Integer reduceInit() { return 0; }
+ public Integer reduce(Integer counter, Integer sum) { return counter + sum; }
+ public void onTraversalDone(Integer sum) {}
+
+ // ----------------------------------------------------------------------------------------------------
+ //
+ // static system for getting values from VC by name.
+ //
+ // ----------------------------------------------------------------------------------------------------
+
+ public static abstract class Getter { public abstract String get(VariantContext vc); }
+ public static final Map<String, Getter> getters = new HashMap<String, Getter>();
+
+ static {
+ // #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT
+ getters.put("CHROM", new Getter() { public String get(VariantContext vc) { return vc.getChr(); } });
+ getters.put("POS", new Getter() { public String get(VariantContext vc) { return Integer.toString(vc.getStart()); } });
+ getters.put("REF", new Getter() {
+ public String get(VariantContext vc) {
+ StringBuilder x = new StringBuilder();
+ x.append(vc.getReference().getDisplayString());
+ return x.toString();
+ }
+ });
+ getters.put("ALT", new Getter() {
+ public String get(VariantContext vc) {
+ StringBuilder x = new StringBuilder();
+ int n = vc.getAlternateAlleles().size();
+ if ( n == 0 ) return ".";
+
+ for ( int i = 0; i < n; i++ ) {
+ if ( i != 0 ) x.append(",");
+ x.append(vc.getAlternateAllele(i));
+ }
+ return x.toString();
+ }
+ });
+ getters.put("EVENTLENGTH", new Getter() { public String get(VariantContext vc) {
+ int maxLength = 0;
+ for ( final Allele a : vc.getAlternateAlleles() ) {
+ final int length = a.length() - vc.getReference().length();
+ if( Math.abs(length) > Math.abs(maxLength) ) { maxLength = length; }
+ }
+ return Integer.toString(maxLength);
+ }});
+ getters.put("QUAL", new Getter() { public String get(VariantContext vc) { return Double.toString(vc.getPhredScaledQual()); } });
+ getters.put("TRANSITION", new Getter() { public String get(VariantContext vc) {
+ if ( vc.isSNP() && vc.isBiallelic() )
+ return GATKVariantContextUtils.isTransition(vc) ? "1" : "0";
+ else
+ return "-1";
+ }});
+ getters.put("FILTER", new Getter() { public String get(VariantContext vc) {
+ return vc.isNotFiltered() ? "PASS" : Utils.join(",", vc.getFilters()); }
+ });
+ getters.put("ID", new Getter() { public String get(VariantContext vc) { return vc.getID(); } });
+ getters.put("HET", new Getter() { public String get(VariantContext vc) { return Integer.toString(vc.getHetCount()); } });
+ getters.put("HOM-REF", new Getter() { public String get(VariantContext vc) { return Integer.toString(vc.getHomRefCount()); } });
+ getters.put("HOM-VAR", new Getter() { public String get(VariantContext vc) { return Integer.toString(vc.getHomVarCount()); } });
+ getters.put("NO-CALL", new Getter() { public String get(VariantContext vc) { return Integer.toString(vc.getNoCallCount()); } });
+ getters.put("TYPE", new Getter() { public String get(VariantContext vc) { return vc.getType().toString(); } });
+ getters.put("VAR", new Getter() { public String get(VariantContext vc) { return Integer.toString(vc.getHetCount() + vc.getHomVarCount()); } });
+ getters.put("NSAMPLES", new Getter() { public String get(VariantContext vc) { return Integer.toString(vc.getNSamples()); } });
+ getters.put("NCALLED", new Getter() { public String get(VariantContext vc) { return Integer.toString(vc.getNSamples() - vc.getNoCallCount()); } });
+ getters.put("MULTI-ALLELIC", new Getter() { public String get(VariantContext vc) { return Boolean.toString(vc.getAlternateAlleles().size() > 1); } });
+ }
+
+ private static Object splitAltAlleles(VariantContext vc) {
+ final int numAltAlleles = vc.getAlternateAlleles().size();
+ if ( numAltAlleles == 1 )
+ return vc.getAlternateAllele(0);
+
+ return vc.getAlternateAlleles();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToVCF.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToVCF.java
new file mode 100644
index 0000000..3e0e2ab
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/tools/walkers/variantutils/VariantsToVCF.java
@@ -0,0 +1,271 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import htsjdk.samtools.util.CloseableIterator;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.arguments.DbsnpArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.refdata.VariantContextAdaptors;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrackBuilder;
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.engine.walkers.Reference;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.Window;
+import org.broadinstitute.gatk.tools.walkers.annotator.VariantOverlapAnnotator;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.codecs.hapmap.RawHapMapFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.vcf.*;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.variantcontext.writer.VariantContextWriterFactory;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * Converts variants from other file formats to VCF format.
+ *
+ * <p>
+ * Note that there must be a Tribble feature/codec for the file format as well as an adaptor.
+ *
+ * <h3>Input</h3>
+ * <p>
+ * A variant file to filter.
+ * </p>
+ *
+ * <h3>Output</h3>
+ * <p>
+ * A VCF file.
+ * </p>
+ *
+ * <h3>Examples</h3>
+ * <pre>
+ * java -Xmx2g -jar GenomeAnalysisTK.jar \
+ * -R ref.fasta \
+ * -T VariantsToVCF \
+ * -o output.vcf \
+ * --variant:RawHapMap input.hapmap \
+ * --dbsnp dbsnp.vcf
+ * </pre>
+ *
+ */
+ at DocumentedGATKFeature( groupName = HelpConstants.DOCS_CAT_VARMANIP, extraDocs = {CommandLineGATK.class} )
+ at Reference(window=@Window(start=-40,stop=40))
+public class VariantsToVCF extends RodWalker<Integer, Integer> {
+
+ @Output(doc="File to which variants should be written")
+ protected VariantContextWriter baseWriter = null;
+ private VariantContextWriter vcfwriter; // needed because hapmap/dbsnp indel records move
+
+ /**
+ * Variants from this input file are used by this tool as input.
+ */
+ @Input(fullName="variant", shortName = "V", doc="Input variant file", required=true)
+ public RodBinding<Feature> variants;
+
+ @ArgumentCollection
+ protected DbsnpArgumentCollection dbsnp = new DbsnpArgumentCollection();
+
+ /**
+ * This argument is used for data (like GELI) with genotypes but no sample names encoded within.
+ */
+ @Argument(fullName="sample", shortName="sample", doc="The sample name represented by the variant rod", required=false)
+ protected String sampleName = null;
+
+ private Set<String> allowedGenotypeFormatStrings = new HashSet<String>();
+ private boolean wroteHeader = false;
+ private Set<String> samples;
+
+ // for dealing with indels in hapmap
+ CloseableIterator<GATKFeature> dbsnpIterator = null;
+ VariantOverlapAnnotator variantOverlapAnnotator = null;
+
+ public void initialize() {
+ vcfwriter = VariantContextWriterFactory.sortOnTheFly(baseWriter, 40, false);
+ variantOverlapAnnotator = new VariantOverlapAnnotator(dbsnp.dbsnp, getToolkit().getGenomeLocParser());
+ }
+
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ if ( tracker == null || !BaseUtils.isRegularBase(ref.getBase()) )
+ return 0;
+
+ Collection<VariantContext> contexts = getVariantContexts(tracker, ref);
+
+ for ( VariantContext vc : contexts ) {
+ VariantContextBuilder builder = new VariantContextBuilder(vc);
+
+ // set the appropriate sample name if necessary
+ if ( sampleName != null && vc.hasGenotypes() && vc.hasGenotype(variants.getName()) ) {
+ Genotype g = new GenotypeBuilder(vc.getGenotype(variants.getName())).name(sampleName).make();
+ builder.genotypes(g);
+ }
+
+ final VariantContext withID = variantOverlapAnnotator.annotateRsID(tracker, builder.make());
+ writeRecord(withID, tracker, ref.getLocus());
+ }
+
+ return 1;
+ }
+
+ private Collection<VariantContext> getVariantContexts(RefMetaDataTracker tracker, ReferenceContext ref) {
+
+ List<Feature> features = tracker.getValues(variants, ref.getLocus());
+ List<VariantContext> VCs = new ArrayList<VariantContext>(features.size());
+
+ for ( Feature record : features ) {
+ if ( VariantContextAdaptors.canBeConvertedToVariantContext(record) ) {
+ // we need to special case the HapMap format because indels aren't handled correctly
+ if ( record instanceof RawHapMapFeature) {
+
+ // is it an indel?
+ RawHapMapFeature hapmap = (RawHapMapFeature)record;
+ if ( hapmap.getAlleles()[0].equals(RawHapMapFeature.NULL_ALLELE_STRING) || hapmap.getAlleles()[1].equals(RawHapMapFeature.NULL_ALLELE_STRING) ) {
+ // get the dbsnp object corresponding to this record (needed to help us distinguish between insertions and deletions)
+ VariantContext dbsnpVC = getDbsnp(hapmap.getName());
+ if ( dbsnpVC == null || dbsnpVC.isMixed() )
+ continue;
+
+ Map<String, Allele> alleleMap = new HashMap<String, Allele>(2);
+ alleleMap.put(RawHapMapFeature.DELETION, Allele.create(ref.getBase(), dbsnpVC.isSimpleInsertion()));
+ alleleMap.put(RawHapMapFeature.INSERTION, Allele.create((char)ref.getBase() + ((RawHapMapFeature)record).getAlleles()[1], !dbsnpVC.isSimpleInsertion()));
+ hapmap.setActualAlleles(alleleMap);
+
+ // also, use the correct positioning for insertions
+ hapmap.updatePosition(dbsnpVC.getStart());
+
+ if ( hapmap.getStart() < ref.getWindow().getStart() ) {
+ logger.warn("Hapmap record at " + ref.getLocus() + " represents an indel too large to be converted; skipping...");
+ continue;
+ }
+ }
+ }
+
+ // ok, we might actually be able to turn this record in a variant context
+ VariantContext vc = VariantContextAdaptors.toVariantContext(variants.getName(), record, ref);
+
+ if ( vc != null ) // sometimes the track has odd stuff in it that can't be converted
+ VCs.add(vc);
+ }
+ }
+
+ return VCs;
+ }
+
+ private VariantContext getDbsnp(String rsID) {
+ if ( dbsnpIterator == null ) {
+
+ if ( dbsnp == null )
+ throw new UserException.BadInput("No dbSNP rod was provided, but one is needed to decipher the correct indel alleles from the HapMap records");
+
+ RMDTrackBuilder builder = new RMDTrackBuilder(getToolkit().getReferenceDataSource().getReference().getSequenceDictionary(),
+ getToolkit().getGenomeLocParser(),
+ getToolkit().getArguments().unsafe,
+ getToolkit().getArguments().disableAutoIndexCreationAndLockingWhenReadingRods,
+ null);
+ dbsnpIterator = builder.createInstanceOfTrack(VCFCodec.class, new File(dbsnp.dbsnp.getSource())).getIterator();
+ // Note that we should really use some sort of seekable iterator here so that the search doesn't take forever
+ // (but it's complicated because the hapmap location doesn't match the dbsnp location, so we don't know where to seek to)
+ }
+
+ while ( dbsnpIterator.hasNext() ) {
+ GATKFeature feature = dbsnpIterator.next();
+ VariantContext vc = (VariantContext)feature.getUnderlyingObject();
+ if ( vc.getID().equals(rsID) )
+ return vc;
+ }
+
+ return null;
+ }
+
+ private void writeRecord(VariantContext vc, RefMetaDataTracker tracker, GenomeLoc loc) {
+ if ( !wroteHeader ) {
+ wroteHeader = true;
+
+ // setup the header fields
+ Set<VCFHeaderLine> hInfo = new HashSet<VCFHeaderLine>();
+ hInfo.addAll(GATKVCFUtils.getHeaderFields(getToolkit(), Arrays.asList(variants.getName())));
+ hInfo.add(VCFStandardHeaderLines.getFormatLine(VCFConstants.GENOTYPE_KEY));
+
+ allowedGenotypeFormatStrings.add(VCFConstants.GENOTYPE_KEY);
+ for ( VCFHeaderLine field : hInfo ) {
+ if ( field instanceof VCFFormatHeaderLine) {
+ allowedGenotypeFormatStrings.add(((VCFFormatHeaderLine)field).getID());
+ }
+ }
+
+ samples = new LinkedHashSet<String>();
+ if ( sampleName != null ) {
+ samples.add(sampleName);
+ } else {
+ // try VCF first
+ samples = SampleUtils.getSampleListWithVCFHeader(getToolkit(), Arrays.asList(variants.getName()));
+
+ if ( samples.isEmpty() ) {
+ List<Feature> features = tracker.getValues(variants, loc);
+ if ( features.size() == 0 )
+ throw new IllegalStateException("No rod data is present, but we just created a VariantContext");
+
+ Feature f = features.get(0);
+ if ( f instanceof RawHapMapFeature )
+ samples.addAll(Arrays.asList(((RawHapMapFeature)f).getSampleIDs()));
+ else
+ samples.addAll(vc.getSampleNames());
+ }
+ }
+
+ vcfwriter.writeHeader(new VCFHeader(hInfo, samples));
+ }
+
+ vc = GATKVariantContextUtils.purgeUnallowedGenotypeAttributes(vc, allowedGenotypeFormatStrings);
+ vcfwriter.add(vc);
+ }
+
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ public Integer reduce(Integer value, Integer sum) {
+ return value + sum;
+ }
+
+ public void onTraversalDone(Integer sum) {
+ if ( dbsnpIterator != null )
+ dbsnpIterator.close();
+ vcfwriter.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/AutoFormattingTime.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/AutoFormattingTime.java
new file mode 100644
index 0000000..31032e3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/AutoFormattingTime.java
@@ -0,0 +1,185 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Conveniently print a time with an automatically determined time unit
+ *
+ * For example, if the amount of time is 10^6 seconds, instead of printing
+ * out 10^6 seconds, prints out 11.57 days instead.
+ *
+ * Dynamically uses time units:
+ *
+ * - seconds: s
+ * - minutes: m
+ * - hours : h
+ * - days : d
+ * - weeks : w
+ *
+ * @author depristo
+ * @since 2009
+ */
+public class AutoFormattingTime {
+ private static final double NANOSECONDS_PER_SECOND = 1e9;
+
+ /**
+ * Width a la format's %WIDTH.PERCISIONf
+ */
+ private final int width; // for format
+
+ /**
+ * Precision a la format's %WIDTH.PERCISIONf
+ */
+ private final int precision; // for format
+
+ /**
+ * The elapsed time in nanoseconds
+ */
+ private final long nanoTime;
+
+ /**
+ * Create a new autoformatting time with elapsed time nanoTime in nanoseconds
+ * @param nanoTime the elapsed time in nanoseconds
+ * @param width the width >= 0 (a la format's %WIDTH.PERCISIONf) to use to display the format, or -1 if none is required
+ * @param precision the precision to display the time at. Must be >= 0;
+ */
+ public AutoFormattingTime(final long nanoTime, final int width, int precision) {
+ if ( width < -1 ) throw new IllegalArgumentException("Width " + width + " must be >= -1");
+ if ( precision < 0 ) throw new IllegalArgumentException("Precision " + precision + " must be >= 0");
+
+ this.width = width;
+ this.nanoTime = nanoTime;
+ this.precision = precision;
+ }
+
+ /**
+ * @see #AutoFormattingTime(long, int, int) but with default width and precision
+ * @param nanoTime
+ */
+ public AutoFormattingTime(final long nanoTime) {
+ this(nanoTime, 6, 1);
+ }
+
+ /**
+ * @see #AutoFormattingTime(long, int, int) but with time specificied as a double in seconds
+ */
+ public AutoFormattingTime(final double timeInSeconds, final int width, final int precision) {
+ this(secondsToNano(timeInSeconds), width, precision);
+ }
+
+ /**
+ * @see #AutoFormattingTime(long) but with time specificied as a double in seconds
+ */
+ public AutoFormattingTime(double timeInSeconds) {
+ this(timeInSeconds, 6, 1);
+ }
+
+ /**
+ * Precomputed format string suitable for string.format with the required width and precision
+ */
+ private String getFormatString() {
+ final StringBuilder b = new StringBuilder("%");
+ if ( width != -1 )
+ b.append(width);
+ b.append(".").append(precision).append("f %s");
+ return b.toString();
+ }
+
+ /**
+ * Get the time associated with this object in nanoseconds
+ * @return the time in nanoseconds
+ */
+ public long getTimeInNanoSeconds() {
+ return nanoTime;
+ }
+
+ /**
+ * Get the time associated with this object in seconds, as a double
+ * @return time in seconds as a double
+ */
+ public double getTimeInSeconds() {
+ return TimeUnit.NANOSECONDS.toSeconds(getTimeInNanoSeconds());
+ }
+
+ /**
+ * @return the precision (a la format's %WIDTH.PERCISIONf)
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * @return the precision (a la format's %WIDTH.PERCISIONf)
+ */
+ public int getPrecision() {
+ return precision;
+ }
+
+ /**
+ * Get a string representation of this time, automatically converting the time
+ * to a human readable unit with width and precision provided during construction
+ * @return a non-null string
+ */
+ public String toString() {
+ double unitTime = getTimeInSeconds();
+ String unit = "s";
+
+ if ( unitTime > 120 ) {
+ unitTime /= 60; // minutes
+ unit = "m";
+
+ if ( unitTime > 120 ) {
+ unitTime /= 60; // hours
+ unit = "h";
+
+ if ( unitTime > 100 ) {
+ unitTime /= 24; // days
+ unit = "d";
+
+ if ( unitTime > 20 ) {
+ unitTime /= 7; // weeks
+ unit = "w";
+ }
+ }
+ }
+ }
+
+ return String.format(getFormatString(), unitTime, unit);
+ }
+
+
+ /**
+ * Convert a time in seconds as a double into nanoseconds as a long
+ * @param timeInSeconds an elapsed time in seconds, as a double
+ * @return an equivalent value in nanoseconds as a long
+ */
+ private static long secondsToNano(final double timeInSeconds) {
+ return (long)(NANOSECONDS_PER_SECOND * timeInSeconds);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/BaseUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/BaseUtils.java
new file mode 100644
index 0000000..194db68
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/BaseUtils.java
@@ -0,0 +1,672 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import htsjdk.samtools.util.StringUtil;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Random;
+
+/**
+ * BaseUtils contains some basic utilities for manipulating nucleotides.
+ */
+public class BaseUtils {
+
+ public enum Base {
+ A ('A'),
+ C ('C'),
+ G ('G'),
+ T ('T'),
+ N ('N'),
+ D ('D');
+
+ public byte base;
+
+ private Base(final char base) {
+ this.base = (byte)base;
+ }
+ }
+
+ // todo -- add this to the generalized base abstraction using the Base enum.
+ public final static byte[] BASES = {'A', 'C', 'G', 'T'};
+ public final static byte[] EXTENDED_BASES = {'A', 'C', 'G', 'T', 'N', 'D'};
+
+ static private final int[] baseIndexMap = new int[256];
+ static {
+ Arrays.fill(baseIndexMap, -1);
+ baseIndexMap['A'] = Base.A.ordinal();
+ baseIndexMap['a'] = Base.A.ordinal();
+ baseIndexMap['*'] = Base.A.ordinal(); // the wildcard character counts as an A
+ baseIndexMap['C'] = Base.C.ordinal();
+ baseIndexMap['c'] = Base.C.ordinal();
+ baseIndexMap['G'] = Base.G.ordinal();
+ baseIndexMap['g'] = Base.G.ordinal();
+ baseIndexMap['T'] = Base.T.ordinal();
+ baseIndexMap['t'] = Base.T.ordinal();
+ }
+
+ static private final int[] baseIndexWithIupacMap = baseIndexMap.clone();
+ static {
+ baseIndexWithIupacMap['*'] = -1; // the wildcard character is bad
+ baseIndexWithIupacMap['N'] = Base.N.ordinal();
+ baseIndexWithIupacMap['n'] = Base.N.ordinal();
+ baseIndexWithIupacMap['R'] = Base.N.ordinal();
+ baseIndexWithIupacMap['r'] = Base.N.ordinal();
+ baseIndexWithIupacMap['Y'] = Base.N.ordinal();
+ baseIndexWithIupacMap['y'] = Base.N.ordinal();
+ baseIndexWithIupacMap['M'] = Base.N.ordinal();
+ baseIndexWithIupacMap['m'] = Base.N.ordinal();
+ baseIndexWithIupacMap['K'] = Base.N.ordinal();
+ baseIndexWithIupacMap['k'] = Base.N.ordinal();
+ baseIndexWithIupacMap['W'] = Base.N.ordinal();
+ baseIndexWithIupacMap['w'] = Base.N.ordinal();
+ baseIndexWithIupacMap['S'] = Base.N.ordinal();
+ baseIndexWithIupacMap['s'] = Base.N.ordinal();
+ baseIndexWithIupacMap['B'] = Base.N.ordinal();
+ baseIndexWithIupacMap['b'] = Base.N.ordinal();
+ baseIndexWithIupacMap['D'] = Base.N.ordinal();
+ baseIndexWithIupacMap['d'] = Base.N.ordinal();
+ baseIndexWithIupacMap['H'] = Base.N.ordinal();
+ baseIndexWithIupacMap['h'] = Base.N.ordinal();
+ baseIndexWithIupacMap['V'] = Base.N.ordinal();
+ baseIndexWithIupacMap['v'] = Base.N.ordinal();
+ }
+
+ /// In genetics, a transition is a mutation changing a purine to another purine nucleotide (A <-> G) or
+ // a pyrimidine to another pyrimidine nucleotide (C <-> T).
+ // Approximately two out of every three single nucleotide polymorphisms (SNPs) are transitions.
+ public enum BaseSubstitutionType {
+ TRANSITION, // A <-> G or C <-> T
+ TRANSVERSION
+ }
+
+ /**
+ * Returns the base substitution type of the 2 state SNP
+ *
+ * @param base1
+ * @param base2
+ * @return
+ */
+ public static BaseSubstitutionType SNPSubstitutionType(byte base1, byte base2) {
+ BaseSubstitutionType t = isTransition(base1, base2) ? BaseSubstitutionType.TRANSITION : BaseSubstitutionType.TRANSVERSION;
+ //System.out.printf("SNPSubstitutionType( char %c, char %c ) => %s%n", base1, base2, t);
+ return t;
+ }
+
+ public static boolean isTransition(byte base1, byte base2) {
+ final int b1 = simpleBaseToBaseIndex(base1);
+ final int b2 = simpleBaseToBaseIndex(base2);
+ return b1 == Base.A.ordinal() && b2 == Base.G.ordinal() || b1 == Base.G.ordinal() && b2 == Base.A.ordinal() ||
+ b1 == Base.C.ordinal() && b2 == Base.T.ordinal() || b1 == Base.T.ordinal() && b2 == Base.C.ordinal();
+ }
+
+ public static boolean isTransversion(byte base1, byte base2) {
+ return !isTransition(base1, base2);
+ }
+
+ /**
+ * Private constructor. No instantiating this class!
+ */
+ private BaseUtils() {}
+
+ static public boolean basesAreEqual(byte base1, byte base2) {
+ return simpleBaseToBaseIndex(base1) == simpleBaseToBaseIndex(base2);
+ }
+
+ /**
+ * Checks whether to bases are the same in fact ignore ambiguous 'N' bases.
+ *
+ * @param base1 first base to compare.
+ * @param base2 second base to compare.
+ * @return true if {@code base1 == base2} or either is an 'N', false otherwise.
+ */
+ static public boolean basesAreEqualIgnoreAmbiguous(final byte base1, final byte base2) {
+ if (base1 == base2) return true;
+ else if (base1 == 'n' || base1 == 'N' || base2 == 'N' || base2 == 'n') return true;
+ else return false;
+ }
+
+ /**
+ * Compare to base arrays ranges checking whether they contain the same bases.
+ *
+ * <p>
+ * By default two array have equal bases, i.e. {@code length == 0} results results in {@code true}.
+ * </p>
+ *
+ * @param bases1 first base array to compare.
+ * @param offset1 position of the first base in bases1 to compare.
+ * @param bases2 second base array to compare.
+ * @param offset2 position of the first base in bases2 to compare.
+ * @param length number of bases to compare.
+ *
+ * @throws NullPointerException if {@code bases1} or {@code bases2} is {@code null}.
+ * @throws ArrayIndexOutOfBoundsException if:
+ * <ul>
+ * <li>{@code offset1} is not within the range [0,{@code bases1.length}) or</li>
+ * <li>{@code offset2} is not within the range [0,{@code bases2.length}) or</li>
+ * <li>{@code offset1 + length} is not within the range [0,{@code bases1.length}) or </li>
+ * <li>{@code offset2 + length} is not within the range [0,{@code bases2.length})</li>
+ * </ul>
+ * @return
+ */
+ static public boolean basesAreEqualIgnoreAmbiguous(final byte[] bases1, final int offset1, final byte[] bases2, final int offset2, final int length) {
+ for (int i = 0; i < length; i++)
+ if (!basesAreEqualIgnoreAmbiguous(bases1[offset1 + i],bases2[offset2 + i])) return false;
+ return true;
+ }
+
+ static public boolean extendedBasesAreEqual(byte base1, byte base2) {
+ return extendedBaseToBaseIndex(base1) == extendedBaseToBaseIndex(base2);
+ }
+
+ /**
+ * @return true iff the bases array contains at least one instance of base
+ */
+ static public boolean containsBase(final byte[] bases, final byte base) {
+ for ( final byte b : bases ) {
+ if ( b == base )
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean isUpperCase(final byte[] bases) {
+ for ( byte base : bases )
+ if ( ! isUpperCase(base) )
+ return false;
+ return true;
+ }
+
+ public static boolean isUpperCase(final byte base) {
+ return base >= 'A' && base <= 'Z';
+ }
+
+ public static byte[] convertIUPACtoN(final byte[] bases, final boolean errorOnBadReferenceBase, final boolean ignoreConversionOfFirstByte) {
+ final int length = bases.length;
+ final int start = ignoreConversionOfFirstByte ? 1 : 0;
+
+ for ( int i = start; i < length; i++ ) {
+ final int baseIndex = baseIndexWithIupacMap[bases[i]];
+ if ( baseIndex == Base.N.ordinal() ) {
+ bases[i] = 'N';
+ } else if ( errorOnBadReferenceBase && baseIndex == -1 ) {
+ throw new UserException.BadInput("We encountered a non-standard non-IUPAC base in the provided reference: '" + bases[i] + "'");
+ }
+ }
+ return bases;
+ }
+
+ /**
+ * Converts a IUPAC nucleotide code to a pair of bases
+ *
+ * @param code
+ * @return 0, 1, 2, 3, or -1 if the base can't be understood
+ */
+ @Deprecated
+ static public char[] iupacToBases(char code) {
+ char[] bases = new char[2];
+ switch (code) {
+ case '*': // the wildcard character counts as an A
+ case 'A':
+ case 'a':
+ bases[0] = bases[1] = 'A';
+ break;
+ case 'C':
+ case 'c':
+ bases[0] = bases[1] = 'C';
+ break;
+ case 'G':
+ case 'g':
+ bases[0] = bases[1] = 'G';
+ break;
+ case 'T':
+ case 't':
+ bases[0] = bases[1] = 'T';
+ break;
+ case 'R':
+ case 'r':
+ bases[0] = 'A';
+ bases[1] = 'G';
+ break;
+ case 'Y':
+ case 'y':
+ bases[0] = 'C';
+ bases[1] = 'T';
+ break;
+ case 'S':
+ case 's':
+ bases[0] = 'G';
+ bases[1] = 'C';
+ break;
+ case 'W':
+ case 'w':
+ bases[0] = 'A';
+ bases[1] = 'T';
+ break;
+ case 'K':
+ case 'k':
+ bases[0] = 'G';
+ bases[1] = 'T';
+ break;
+ case 'M':
+ case 'm':
+ bases[0] = 'A';
+ bases[1] = 'C';
+ break;
+ default:
+ bases[0] = bases[1] = 'N';
+ }
+ return bases;
+ }
+
+ /**
+ * Converts a pair of bases to their IUPAC ambiguity code
+ *
+ * @param base1 1st base
+ * @param base2 2nd base
+ * @return byte
+ */
+ static public byte basesToIUPAC(final byte base1, final byte base2) {
+ // ensure that the bases come in order
+ if ( base2 < base1 )
+ return basesToIUPAC(base2, base1);
+
+ // ensure that the bases are regular ones
+ if ( !isRegularBase(base1) || !isRegularBase(base2) )
+ return Base.N.base;
+
+ // IUPAC codes are not needed if the bases are identical
+ if ( basesAreEqual(base1, base2) )
+ return base1;
+
+ if ( base1 == Base.A.base )
+ return (byte)(base2 == Base.C.base ? 'M' : (base2 == Base.G.base ? 'R' : 'W'));
+
+ if ( base1 == Base.C.base )
+ return (byte)(base2 == Base.G.base ? 'S' : 'Y');
+
+ // the only possibility left is G/T
+ return 'K';
+ }
+
+ /**
+ * Converts a simple base to a base index
+ *
+ * @param base [AaCcGgTt]
+ * @return 0, 1, 2, 3, or -1 if the base can't be understood
+ */
+ static public int simpleBaseToBaseIndex(final byte base) {
+ if ( base < 0 || base >= 256 )
+ throw new UserException.BadInput("Non-standard bases were encountered in either the input reference or BAM file(s)");
+ return baseIndexMap[base];
+ }
+
+ /**
+ * Converts a simple base to a base index
+ *
+ * @param base [AaCcGgTt]
+ * @return 0, 1, 2, 3, or -1 if the base can't be understood
+ */
+ @Deprecated
+ static public int simpleBaseToBaseIndex(char base) {
+ return baseIndexMap[base];
+ }
+
+ static public int extendedBaseToBaseIndex(byte base) {
+ switch (base) {
+ case 'd':
+ case 'D':
+ return Base.D.ordinal();
+ case 'n':
+ case 'N':
+ return Base.N.ordinal();
+
+ default:
+ return simpleBaseToBaseIndex(base);
+ }
+ }
+
+ @Deprecated
+ static public boolean isRegularBase( final char base ) {
+ return simpleBaseToBaseIndex(base) != -1;
+ }
+
+ static public boolean isRegularBase( final byte base ) {
+ return simpleBaseToBaseIndex(base) != -1;
+ }
+
+ static public boolean isAllRegularBases( final byte[] bases ) {
+ for( final byte base : bases) {
+ if( !isRegularBase(base) ) { return false; }
+ }
+ return true;
+ }
+
+ static public boolean isNBase(byte base) {
+ return base == 'N' || base == 'n';
+ }
+
+ /**
+ * Converts a base index to a simple base
+ *
+ * @param baseIndex 0, 1, 2, 3
+ * @return A, C, G, T, or '.' if the index can't be understood
+ */
+ static public byte baseIndexToSimpleBase(int baseIndex) {
+ switch (baseIndex) {
+ case 0:
+ return 'A';
+ case 1:
+ return 'C';
+ case 2:
+ return 'G';
+ case 3:
+ return 'T';
+ default:
+ return '.';
+ }
+ }
+
+ /**
+ * Return the complement (A <-> T or C <-> G) of a base, or the specified base if it can't be complemented (i.e. an ambiguous base).
+ *
+ * @param base the base [AaCcGgTt]
+ * @return the complementary base, or the input base if it's not one of the understood ones
+ */
+ static public byte simpleComplement(byte base) {
+ switch (base) {
+ case 'A':
+ case 'a':
+ return 'T';
+ case 'C':
+ case 'c':
+ return 'G';
+ case 'G':
+ case 'g':
+ return 'C';
+ case 'T':
+ case 't':
+ return 'A';
+ default:
+ return base;
+ }
+ }
+
+ @Deprecated
+ static private char simpleComplement(char base) {
+ return (char) simpleComplement((byte) base);
+ }
+
+ /**
+ * Reverse complement a byte array of bases (that is, chars casted to bytes, *not* base indices in byte form)
+ *
+ * @param bases the byte array of bases
+ * @return the reverse complement of the base byte array
+ */
+ static public byte[] simpleReverseComplement(byte[] bases) {
+ byte[] rcbases = new byte[bases.length];
+
+ for (int i = 0; i < bases.length; i++) {
+ rcbases[i] = simpleComplement(bases[bases.length - 1 - i]);
+ }
+
+ return rcbases;
+ }
+
+ /**
+ * Reverse complement a char array of bases
+ *
+ * @param bases the char array of bases
+ * @return the reverse complement of the char byte array
+ */
+ @Deprecated
+ static public char[] simpleReverseComplement(char[] bases) {
+ char[] rcbases = new char[bases.length];
+
+ for (int i = 0; i < bases.length; i++) {
+ rcbases[i] = simpleComplement(bases[bases.length - 1 - i]);
+ }
+
+ return rcbases;
+ }
+
+ /**
+ * Reverse complement a String of bases. Preserves ambiguous bases.
+ *
+ * @param bases the String of bases
+ * @return the reverse complement of the String
+ */
+ @Deprecated
+ static public String simpleReverseComplement(String bases) {
+ return new String(simpleReverseComplement(bases.getBytes()));
+ }
+
+ /**
+ * Returns the uppercased version of the bases
+ *
+ * @param bases the bases
+ * @return the upper cased version
+ */
+ static public void convertToUpperCase(final byte[] bases) {
+ StringUtil.toUpperCase(bases);
+ }
+
+ /**
+ * Returns the index of the most common base in the basecounts array. To be used with
+ * pileup.getBaseCounts.
+ *
+ * @param baseCounts counts of a,c,g,t in order.
+ * @return the index of the most common base
+ */
+ static public int mostFrequentBaseIndex(int[] baseCounts) {
+ int mostFrequentBaseIndex = 0;
+ for (int baseIndex = 1; baseIndex < 4; baseIndex++) {
+ if (baseCounts[baseIndex] > baseCounts[mostFrequentBaseIndex]) {
+ mostFrequentBaseIndex = baseIndex;
+ }
+ }
+ return mostFrequentBaseIndex;
+ }
+
+ static public int mostFrequentBaseIndexNotRef(int[] baseCounts, int refBaseIndex) {
+ int tmp = baseCounts[refBaseIndex];
+ baseCounts[refBaseIndex] = -1;
+ int result = mostFrequentBaseIndex(baseCounts);
+ baseCounts[refBaseIndex] = tmp;
+ return result;
+ }
+
+ static public int mostFrequentBaseIndexNotRef(int[] baseCounts, byte refSimpleBase) {
+ return mostFrequentBaseIndexNotRef(baseCounts, simpleBaseToBaseIndex(refSimpleBase));
+ }
+
+ /**
+ * Returns the most common base in the basecounts array. To be used with pileup.getBaseCounts.
+ *
+ * @param baseCounts counts of a,c,g,t in order.
+ * @return the most common base
+ */
+ static public byte mostFrequentSimpleBase(int[] baseCounts) {
+ return baseIndexToSimpleBase(mostFrequentBaseIndex(baseCounts));
+ }
+
+ /**
+ * For the most frequent base in the sequence, return the percentage of the read it constitutes.
+ *
+ * @param sequence the read sequence
+ * @return the percentage of the read that's made up of the most frequent base
+ */
+ static public double mostFrequentBaseFraction(byte[] sequence) {
+ int[] baseCounts = new int[4];
+
+ for (byte base : sequence) {
+ int baseIndex = simpleBaseToBaseIndex(base);
+
+ if (baseIndex >= 0) {
+ baseCounts[baseIndex]++;
+ }
+ }
+
+ int mostFrequentBaseIndex = mostFrequentBaseIndex(baseCounts);
+
+ return ((double) baseCounts[mostFrequentBaseIndex]) / ((double) sequence.length);
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // random bases
+ //
+ // --------------------------------------------------------------------------------
+
+ /**
+ * Return a random base index (A=0, C=1, G=2, T=3).
+ *
+ * @return a random base index (A=0, C=1, G=2, T=3)
+ */
+ static public int getRandomBaseIndex() {
+ return getRandomBaseIndex(-1);
+ }
+
+ /**
+ * Return random bases.
+ *
+ * @param length base count and length of returned array.
+ *
+ * @throws IllegalArgumentException if {@code length} is less than 0.
+ *
+ * @return never {@code null}
+ */
+ @SuppressWarnings("unused")
+ public static byte[] getRandomBases(final int length) {
+ if (length < 0)
+ throw new IllegalArgumentException("length must zero or greater");
+ final byte[] result = new byte[length];
+ fillWithRandomBases(result);
+ return result;
+ }
+
+ /**
+ * Fills an array with random bases.
+ *
+ * @param dest the array to fill.
+ *
+ * @throws IllegalArgumentException if {@code result} is {@code null}.
+ */
+ public static void fillWithRandomBases(final byte[] dest) {
+ fillWithRandomBases(dest,0,dest.length);
+ }
+
+ /**
+ * Fill an array section with random bases.
+ *
+ * @param dest array to fill.
+ * @param fromIndex first index to be filled (inclusive).
+ * @param toIndex index after last to be filled (exclusive).
+ *
+ * @throws IllegalArgumentException if {@code dest} is {@code null},
+ * {@code fromIndex} or {@code toIndex} is negative,
+ * {@code fromIndex} or {@code toIndex} are greater than {@code dest} length,
+ * or {@code fromIndex} greater than {@code toIndex}.
+ */
+ public static void fillWithRandomBases(final byte[] dest, final int fromIndex, final int toIndex) {
+ final Random rnd = GenomeAnalysisEngine.getRandomGenerator();
+ if (dest == null)
+ throw new IllegalArgumentException("the dest array cannot be null");
+ if (fromIndex > toIndex)
+ throw new IllegalArgumentException("fromIndex cannot be larger than toIndex");
+ if (fromIndex < 0)
+ throw new IllegalArgumentException("both indexes must be positive");
+ if (toIndex > dest.length)
+ throw new IllegalArgumentException("both indexes must be less or equal to the destination array length");
+
+ for (int i = fromIndex; i < toIndex; i++)
+ dest[i] = baseIndexToSimpleBase(rnd.nextInt(4));
+ }
+
+ /**
+ * Return a random base index, excluding some base index.
+ *
+ * @param excludeBaseIndex the base index to exclude
+ * @return a random base index, excluding the one specified (A=0, C=1, G=2, T=3)
+ */
+ static public int getRandomBaseIndex(int excludeBaseIndex) {
+ int randomBaseIndex = excludeBaseIndex;
+
+ while (randomBaseIndex == excludeBaseIndex) {
+ randomBaseIndex = GenomeAnalysisEngine.getRandomGenerator().nextInt(4);
+ }
+
+ return randomBaseIndex;
+ }
+
+ public static byte getComplement(byte base) {
+ switch(base) {
+ case 'a':
+ case 'A':
+ return 'T';
+ case 'c':
+ case 'C':
+ return 'G';
+ case 'g':
+ case 'G':
+ return 'C';
+ case 't':
+ case 'T':
+ return 'A';
+ case 'n':
+ case 'N':
+ return 'N';
+ default:
+ throw new ReviewedGATKException("base must be A, C, G or T. " + (char) base + " is not a valid base.");
+ }
+ }
+
+
+ /**
+ * Lexicographical sorting of base arrays {@link Comparator}.
+ */
+ public static final Comparator<byte[]> BASES_COMPARATOR = new Comparator<byte[]> (){
+
+ @Override
+ public int compare(final byte[] o1,final byte[] o2) {
+ final int minLength = Math.min(o1.length,o2.length);
+ for (int i = 0; i < minLength; i++) {
+ final int cmp = Byte.compare(o1[i],o2[i]);
+ if (cmp != 0) return cmp;
+ }
+ if (o1.length == o2.length)
+ return 0;
+ else if (o1.length == minLength)
+ return -1;
+ else
+ return 1;
+ }
+ };
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/BitSetUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/BitSetUtils.java
new file mode 100644
index 0000000..a9ab00d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/BitSetUtils.java
@@ -0,0 +1,134 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import java.util.BitSet;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utilities for bitset conversion
+ *
+ * @author Mauricio Carneiro
+ * @since 3/5/12
+ */
+public class BitSetUtils {
+
+ static final private byte NBITS_LONG_REPRESENTATION = 64; // the number of bits used in the long version to represent the bit set (necessary for the two's complement representation of negative numbers)
+ static final private byte NBITS_SHORT_REPRESENTATION = 16; // the number of bits used in the short version to represent the bit set (necessary for the two's complement representation of negative numbers)
+
+ /**
+ * Creates an long out of a bitset
+ *
+ * @param bitSet the bitset
+ * @return a long from the bitset representation
+ */
+ public static long longFrom(final BitSet bitSet) {
+ return longFrom(bitSet, NBITS_LONG_REPRESENTATION);
+ }
+
+ /**
+ * Creates a short integer from a bitset
+ *
+ * @param bitSet the bitset
+ * @return a short from the bitset representation
+ */
+ public static short shortFrom(final BitSet bitSet) {
+ return (short) longFrom(bitSet, NBITS_SHORT_REPRESENTATION);
+ }
+
+ /**
+ * Cretes an integer with any number of bits (up to 64 -- long precision) from a bitset
+ *
+ * @param bitSet the bitset
+ * @param nBits the number of bits to be used for this representation
+ * @return an integer with nBits from the bitset representation
+ */
+ public static long longFrom(final BitSet bitSet, final int nBits) {
+ long number = 0;
+ for (int bitIndex = bitSet.nextSetBit(0); bitIndex >= 0 && bitIndex <= nBits; bitIndex = bitSet.nextSetBit(bitIndex + 1))
+ number |= 1L << bitIndex;
+
+ return number;
+ }
+
+ /**
+ * Creates a BitSet representation of a given long
+ *
+ * @param number the number to turn into a bitset
+ * @return a bitset representation of the long
+ */
+ public static BitSet bitSetFrom(long number) {
+ return bitSetFrom(number, NBITS_LONG_REPRESENTATION);
+ }
+
+ /**
+ * Creates a BitSet representation of a given short
+ *
+ * @param number the number to turn into a bitset
+ * @return a bitset representation of the short
+ */
+ public static BitSet bitSetFrom(short number) {
+ BitSet result = shortCache.get(number);
+ if (result == null) {
+ result = bitSetFrom(number, NBITS_SHORT_REPRESENTATION);
+ shortCache.put(number, result);
+ }
+ return result;
+ }
+ // use a static cache for shorts (but not for longs, because there could be a lot of entries)
+ private static final Map<Short, BitSet> shortCache = new HashMap<Short, BitSet>(2 * Short.MAX_VALUE);
+
+ /**
+ * Creates a BitSet representation of an arbitrary integer (number of bits capped at 64 -- long precision)
+ *
+ * @param number the number to turn into a bitset
+ * @param nBits the number of bits to use as precision for this conversion
+ * @return a bitset representation of the integer
+ */
+ public static BitSet bitSetFrom(long number, int nBits) {
+ BitSet bitSet = new BitSet(nBits);
+ boolean isNegative = number < 0;
+ int bitIndex = 0;
+ while (number != 0) {
+ if (number % 2 != 0)
+ bitSet.set(bitIndex);
+ bitIndex++;
+ number /= 2;
+ }
+ if (isNegative) {
+ boolean foundFirstSetBit = false;
+ for (int i = bitSet.nextSetBit(0); i < nBits && i >= 0; i++) {
+ boolean bit = bitSet.get(i);
+ if (!foundFirstSetBit && bit)
+ foundFirstSetBit = true; // maintain all bits until the first 1 is found (inclusive)
+ else if (foundFirstSetBit)
+ bitSet.flip(i); // flip every other bit up to NBITS_REPRESENTATION
+ }
+ }
+ return bitSet;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/ContigComparator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/ContigComparator.java
new file mode 100644
index 0000000..f3f93b4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/ContigComparator.java
@@ -0,0 +1,80 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+
+import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: carneiro
+ * Date: 7/23/11
+ * Time: 6:07 PM
+ *
+ * Contig comparator -- sorting contigs like Picard
+ *
+ * This is very useful if you want to output your text files or manipulate data in the usual chromosome ordering :
+ * 1
+ * 2
+ * 3
+ * ...
+ * 21
+ * 22
+ * X
+ * Y
+ * GL***
+ * ...
+ * Just use this comparator in any SortedSet class constructor and your data will be sorted like in the BAM file.
+ */
+public class ContigComparator implements Comparator<String> {
+ final SAMSequenceDictionary dict;
+
+ public ContigComparator(final SAMSequenceDictionary dict) {
+ if ( dict == null ) throw new IllegalArgumentException("dict cannot be null");
+ this.dict = dict;
+ }
+
+ @Override
+ public int compare(final String chr1, final String chr2) {
+ final int index1 = getIndex(chr1);
+ final int index2 = getIndex(chr2);
+ return Integer.valueOf(index1).compareTo(index2);
+ }
+
+ /**
+ * Convert contig to its index in the dict, or throw an exception if it's not found or is null
+ * @param chr the contig
+ */
+ private int getIndex(final String chr) {
+ if ( chr == null ) throw new IllegalArgumentException("chr is null");
+ final int index = dict.getSequenceIndex(chr);
+ if ( index == -1 ) throw new IllegalArgumentException("Unknown contig " + chr);
+ return index;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/DeprecatedToolChecks.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/DeprecatedToolChecks.java
new file mode 100644
index 0000000..9fcd848
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/DeprecatedToolChecks.java
@@ -0,0 +1,96 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+
+import java.util.*;
+
+/**
+ * Utility class for handling deprecated tools gracefully
+ *
+ * @author vdauwera
+ * @since 3/11/13
+ */
+public class DeprecatedToolChecks {
+
+ // Mapping from walker name to major version number where the walker first disappeared and optional replacement options
+ private static Object2ObjectMap deprecatedGATKWalkers = new Object2ObjectOpenHashMap();
+ static {
+ // Indicate recommended replacement in parentheses if applicable
+ deprecatedGATKWalkers.put("ReduceReads", "3.0 (use recommended best practices pipeline with the HaplotypeCaller)");
+ deprecatedGATKWalkers.put("CountCovariates", "2.0 (use BaseRecalibrator instead; see documentation for usage)");
+ deprecatedGATKWalkers.put("TableRecalibration", "2.0 (use PrintReads with -BQSR instead; see documentation for usage)");
+ deprecatedGATKWalkers.put("AlignmentWalker", "2.2 (no replacement)");
+ deprecatedGATKWalkers.put("CountBestAlignments", "2.2 (no replacement)");
+ deprecatedGATKWalkers.put("SomaticIndelDetector", "2.0 (replaced by the standalone tool Indelocator; see Cancer Tools documentation)");
+ }
+
+ // Mapping from walker name to major version number where the walker first disappeared and optional replacement options
+ private static Object2ObjectMap deprecatedGATKAnnotations = new Object2ObjectOpenHashMap();
+ static {
+ // Same comments as for walkers
+ deprecatedGATKAnnotations.put("DepthOfCoverage", "2.4 (renamed to Coverage)");
+ }
+
+ /**
+ * Utility method to check whether a given walker has been deprecated in a previous GATK release
+ *
+ * @param walkerName the walker class name (not the full package) to check
+ */
+ public static boolean isDeprecatedWalker(final String walkerName) {
+ return deprecatedGATKWalkers.containsKey(walkerName);
+ }
+
+ /**
+ * Utility method to check whether a given annotation has been deprecated in a previous GATK release
+ *
+ * @param annotationName the annotation class name (not the full package) to check
+ */
+ public static boolean isDeprecatedAnnotation(final String annotationName) {
+ return deprecatedGATKAnnotations.containsKey(annotationName);
+ }
+
+ /**
+ * Utility method to pull up the version number at which a walker was deprecated and the suggested replacement, if any
+ *
+ * @param walkerName the walker class name (not the full package) to check
+ */
+ public static String getWalkerDeprecationInfo(final String walkerName) {
+ return deprecatedGATKWalkers.get(walkerName).toString();
+ }
+
+ /**
+ * Utility method to pull up the version number at which an annotation was deprecated and the suggested replacement, if any
+ *
+ * @param annotationName the annotation class name (not the full package) to check
+ */
+ public static String getAnnotationDeprecationInfo(final String annotationName) {
+ return deprecatedGATKAnnotations.get(annotationName).toString();
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/GenomeLocParser.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/GenomeLocParser.java
new file mode 100644
index 0000000..55e6624
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/GenomeLocParser.java
@@ -0,0 +1,622 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import com.google.java.contract.ThrowEnsures;
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+/**
+ * Factory class for creating GenomeLocs
+ */
+public final class GenomeLocParser {
+ private static Logger logger = Logger.getLogger(GenomeLocParser.class);
+
+ /**
+ * How much validation should we do at runtime with this parser?
+ */
+ public enum ValidationLevel {
+ /** Do the standard amount of validation */
+ STANDARD,
+ /** Don't do any real checking at all */
+ NONE
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // Ugly global variable defining the optional ordering of contig elements
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * This single variable holds the underlying SamSequenceDictionary used by the GATK. We assume
+ * it is thread safe.
+ */
+ final private SAMSequenceDictionary SINGLE_MASTER_SEQUENCE_DICTIONARY;
+
+ /**
+ * A thread-local CachingSequenceDictionary
+ */
+ private final ThreadLocal<MRUCachingSAMSequenceDictionary> contigInfoPerThread =
+ new ThreadLocal<MRUCachingSAMSequenceDictionary>() {
+ @Override
+ protected MRUCachingSAMSequenceDictionary initialValue() {
+ return new MRUCachingSAMSequenceDictionary(SINGLE_MASTER_SEQUENCE_DICTIONARY);
+ }
+ };
+
+ /**
+ * How much validation are we doing at runtime with this GenomeLocParser?
+ */
+ private final ValidationLevel validationLevel;
+
+ /**
+ * @return a caching sequence dictionary appropriate for this thread
+ */
+ private MRUCachingSAMSequenceDictionary getContigInfo() {
+ return contigInfoPerThread.get();
+ }
+
+ /**
+ * set our internal reference contig order
+ * @param refFile the reference file
+ */
+ @Requires("refFile != null")
+ public GenomeLocParser(final ReferenceSequenceFile refFile) {
+ this(refFile.getSequenceDictionary());
+ }
+
+ /**
+ * Create a new GenomeLocParser based on seqDictionary with the standard validation level
+ * @param seqDict a non-null sequence dictionary
+ */
+ public GenomeLocParser(SAMSequenceDictionary seqDict) {
+ this(seqDict, ValidationLevel.STANDARD);
+ }
+
+ /**
+ * Create a genome loc parser based on seqDict with the specified level of validation
+ * @param seqDict the sequence dictionary to use when creating genome locs
+ * @param validationLevel how much validation should we do of the genome locs at runtime? Purely for testing purposes
+ */
+ protected GenomeLocParser(SAMSequenceDictionary seqDict, final ValidationLevel validationLevel) {
+ if (validationLevel == null)
+ throw new IllegalArgumentException("validation level cannot be null");
+ if (seqDict == null) { // we couldn't load the reference dictionary
+ //logger.info("Failed to load reference dictionary, falling back to lexicographic order for contigs");
+ throw new UserException.CommandLineException("Failed to load reference dictionary");
+ }
+
+ this.validationLevel = validationLevel;
+ this.SINGLE_MASTER_SEQUENCE_DICTIONARY = seqDict;
+ if ( logger.isDebugEnabled() ) {
+ logger.debug(String.format("Prepared reference sequence contig dictionary"));
+ for (SAMSequenceRecord contig : seqDict.getSequences()) {
+ logger.debug(String.format(" %s (%d bp)", contig.getSequenceName(), contig.getSequenceLength()));
+ }
+ }
+ }
+
+ /**
+ * Determines whether the given contig is valid with respect to the sequence dictionary
+ * already installed in the GenomeLoc.
+ *
+ * @param contig a potentially null string name for the contig
+ * @return True if the contig is valid. False otherwise.
+ */
+ public final boolean contigIsInDictionary(final String contig) {
+ return contig != null && getContigInfo().hasContig(contig);
+ }
+
+ /**
+ * get the contig's SAMSequenceRecord
+ *
+ * @param contig the string name of the contig
+ *
+ * @return the sam sequence record
+ */
+ @Ensures("result != null")
+ @ThrowEnsures({"UserException.MalformedGenomeLoc", "!contigIsInDictionary(contig) || contig == null"})
+ public final SAMSequenceRecord getContigInfo(final String contig) {
+ if ( contig == null || ! contigIsInDictionary(contig) )
+ throw new UserException.MalformedGenomeLoc(String.format("Contig %s given as location, but this contig isn't present in the Fasta sequence dictionary", contig));
+ return getContigInfo().getSequence(contig);
+ }
+
+ /**
+ * Returns the contig index of a specified string version of the contig
+ *
+ * @param contig the contig string
+ *
+ * @return the contig index, -1 if not found
+ */
+ @Ensures("result >= 0")
+ @ThrowEnsures({"UserException.MalformedGenomeLoc", "!contigIsInDictionary(contig) || contig == null"})
+ public final int getContigIndex(final String contig) {
+ return getContigInfo(contig).getSequenceIndex();
+ }
+
+ @Requires("contig != null")
+ protected int getContigIndexWithoutException(final String contig) {
+ if ( contig == null || ! getContigInfo().hasContig(contig) )
+ return -1;
+ return getContigInfo().getSequenceIndex(contig);
+ }
+
+ /**
+ * Return the master sequence dictionary used within this GenomeLocParser
+ * @return
+ */
+ public final SAMSequenceDictionary getContigs() {
+ return getContigInfo().getDictionary();
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // Low-level creation functions
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * @see #createGenomeLoc(String, int, int, int, boolean) for exact details of the creation.
+ *
+ * Note that because this function doesn't take the contig index as an argument for contig, it
+ * has a slight performance penalty over the version that does take the contig index. Does not
+ * require the created genome loc on the reference genome
+ */
+ @Ensures("result != null")
+ @ThrowEnsures({"UserException.MalformedGenomeLoc", "!isValidGenomeLoc(contig, start, stop)"})
+ public GenomeLoc createGenomeLoc(String contig, final int start, final int stop) {
+ return createGenomeLoc(contig, getContigIndex(contig), start, stop);
+ }
+
+ /**
+ * @see #createGenomeLoc(String, int, int, int, boolean) for exact details of the creation.
+ *
+ * Note that because this function doesn't take the contig index as an argument for contig, it
+ * has a slight performance penalty over the version that does take the contig index.
+ */
+ public GenomeLoc createGenomeLoc(final String contig, final int start, final int stop, boolean mustBeOnReference) {
+ return createGenomeLoc(contig, getContigIndex(contig), start, stop, mustBeOnReference);
+ }
+
+ /**
+ * @see #createGenomeLoc(String, int, int, int, boolean) for exact details of the creation.
+ *
+ * Doesn't require the start and stop to be on the genome
+ */
+ @ThrowEnsures({"UserException.MalformedGenomeLoc", "!isValidGenomeLoc(contig, start, stop, false)"})
+ public GenomeLoc createGenomeLoc(String contig, int index, final int start, final int stop) {
+ return createGenomeLoc(contig, index, start, stop, false);
+ }
+
+ /**
+ * Create a GenomeLoc on contig, starting at start and ending (inclusive) at stop.
+ *
+ * @param contig the contig name
+ * @param index the index into the GATK's SAMSequencingDictionary of contig (passed for efficiency to avoid the lookup)
+ * @param start the starting position
+ * @param stop the stop position of this loc, inclusive
+ * @param mustBeOnReference if true, this factory will throw a UserException.MalformedGenomeLoc if start or stop isn't on the contig
+ *
+ * @return a non-null GenomeLoc
+ */
+ @ThrowEnsures({"UserException.MalformedGenomeLoc", "!isValidGenomeLoc(contig, start, stop,mustBeOnReference)"})
+ @Ensures("result != null")
+ public GenomeLoc createGenomeLoc(final String contig, int index, final int start, final int stop, boolean mustBeOnReference) {
+ // optimization: by interning the string we ensure that future comparisons use == not the full string comp
+ final String interned = validateGenomeLoc(contig, index, start, stop, mustBeOnReference);
+ return new GenomeLoc(interned, index, start, stop);
+ }
+
+ /**
+ * Create a new GenomeLoc, on contig, including the single position pos.
+ *
+ * Pos is not required to be on the reference
+ *
+ * @see #createGenomeLoc(String, int, int, int, boolean) for exact details of the creation.
+ *
+ * @param contig the contig name
+ * @param pos the start and stop of the created genome loc
+ *
+ * @return a genome loc representing a single base at the specified postion on the contig
+ */
+ @Ensures("result != null")
+ @ThrowEnsures({"UserException.MalformedGenomeLoc", "!isValidGenomeLoc(contig, pos, pos, true)"})
+ public GenomeLoc createGenomeLoc(final String contig, final int pos) {
+ return createGenomeLoc(contig, getContigIndex(contig), pos, pos);
+ }
+
+ /**
+ * validate a position or interval on the genome as valid
+ *
+ * Requires that contig exist in the master sequence dictionary, and that contig index be valid as well. Requires
+ * that start <= stop.
+ *
+ * if mustBeOnReference is true,
+ * performs boundary validation for genome loc INTERVALS:
+ * start and stop are on contig and start <= stop
+ *
+ * @param contig the contig name
+ * @param start the start position
+ * @param stop the stop position
+ *
+ * @return the interned contig name, an optimization that ensures that contig == the string in the sequence dictionary
+ */
+ protected String validateGenomeLoc(final String contig, final int contigIndex, final int start, final int stop, final boolean mustBeOnReference) {
+ if ( validationLevel == ValidationLevel.NONE )
+ return contig;
+ else {
+ if (stop < start)
+ vglHelper(String.format("The stop position %d is less than start %d in contig %s", stop, start, contig));
+
+ final SAMSequenceRecord contigInfo = getContigInfo().getSequence(contig);
+ if ( contigInfo.getSequenceIndex() != contigIndex )
+ vglHelper(String.format("The contig index %d is bad, doesn't equal the contig index %d of the contig from a string %s",
+ contigIndex, contigInfo.getSequenceIndex(), contig));
+
+ if ( mustBeOnReference ) {
+ if (start < 1)
+ vglHelper(String.format("The start position %d is less than 1", start));
+
+ if (stop < 1)
+ vglHelper(String.format("The stop position %d is less than 1", stop));
+
+ final int contigSize = contigInfo.getSequenceLength();
+ if (start > contigSize || stop > contigSize)
+ vglHelper(String.format("The genome loc coordinates %d-%d exceed the contig size (%d)", start, stop, contigSize));
+ }
+
+ return contigInfo.getSequenceName();
+ }
+ }
+
+ /**
+ * Would a genome loc created with the given parameters be valid w.r.t. the master sequence dictionary?
+ * @param contig the contig we'd use
+ * @param start the start position
+ * @param stop the stop
+ * @param mustBeOnReference should we require the resulting genome loc to be completely on the reference genome?
+ * @return true if this would produce a valid genome loc, false otherwise
+ */
+ public boolean isValidGenomeLoc(String contig, int start, int stop, boolean mustBeOnReference ) {
+ try {
+ validateGenomeLoc(contig, getContigIndexWithoutException(contig), start, stop, mustBeOnReference);
+ return true;
+ } catch ( ReviewedGATKException e) {
+ return false;
+ }
+ }
+
+ /**
+ * @see #isValidGenomeLoc(String, int, int) with mustBeOnReference == true
+ */
+ public boolean isValidGenomeLoc(String contig, int start, int stop ) {
+ return isValidGenomeLoc(contig, start, stop, true);
+ }
+
+ private void vglHelper(final String msg) {
+ throw new UserException.MalformedGenomeLoc("Parameters to GenomeLocParser are incorrect:" + msg);
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // Parsing genome locs
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * parse a genome interval, from a location string
+ *
+ * Performs interval-style validation:
+ *
+ * contig is valid; start and stop less than the end; start <= stop, and start/stop are on the contig
+ * @param str the string to parse
+ *
+ * @return a GenomeLoc representing the String
+ *
+ */
+ @Requires("str != null")
+ @Ensures("result != null")
+ public GenomeLoc parseGenomeLoc(final String str) {
+ // 'chr2', 'chr2:1000000' or 'chr2:1,000,000-2,000,000'
+ //System.out.printf("Parsing location '%s'%n", str);
+
+ String contig = null;
+ int start = 1;
+ int stop = -1;
+
+ final int colonIndex = str.lastIndexOf(":");
+ if(colonIndex == -1) {
+ contig = str.substring(0, str.length()); // chr1
+ stop = Integer.MAX_VALUE;
+ } else {
+ contig = str.substring(0, colonIndex);
+ final int dashIndex = str.indexOf('-', colonIndex);
+ try {
+ if(dashIndex == -1) {
+ if(str.charAt(str.length() - 1) == '+') {
+ start = parsePosition(str.substring(colonIndex + 1, str.length() - 1)); // chr:1+
+ stop = Integer.MAX_VALUE;
+ } else {
+ start = parsePosition(str.substring(colonIndex + 1)); // chr1:1
+ stop = start;
+ }
+ } else {
+ start = parsePosition(str.substring(colonIndex + 1, dashIndex)); // chr1:1-1
+ stop = parsePosition(str.substring(dashIndex + 1));
+ }
+ } catch(Exception e) {
+ throw new UserException("Failed to parse Genome Location string: " + str, e);
+ }
+ }
+
+ // is the contig valid?
+ if (!contigIsInDictionary(contig))
+ throw new UserException.MalformedGenomeLoc("Contig '" + contig + "' does not match any contig in the GATK sequence dictionary derived from the reference; are you sure you are using the correct reference fasta file?");
+
+ if (stop == Integer.MAX_VALUE)
+ // lookup the actually stop position!
+ stop = getContigInfo(contig).getSequenceLength();
+
+ return createGenomeLoc(contig, getContigIndex(contig), start, stop, true);
+ }
+
+ /**
+ * Parses a number like 1,000,000 into a long.
+ * @param pos
+ */
+ @Requires("pos != null")
+ @Ensures("result >= 0")
+ protected int parsePosition(final String pos) {
+ if(pos.indexOf('-') != -1) {
+ throw new NumberFormatException("Position: '" + pos + "' can't contain '-'." );
+ }
+
+ if(pos.indexOf(',') != -1) {
+ final StringBuilder buffer = new StringBuilder();
+ for(int i = 0; i < pos.length(); i++) {
+ final char c = pos.charAt(i);
+
+ if(c == ',') {
+ continue;
+ } else if(c < '0' || c > '9') {
+ throw new NumberFormatException("Position: '" + pos + "' contains invalid chars." );
+ } else {
+ buffer.append(c);
+ }
+ }
+ return Integer.parseInt(buffer.toString());
+ } else {
+ return Integer.parseInt(pos);
+ }
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // Parsing string representations
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Create a genome loc, given a read. If the read is unmapped, *and* yet the read has a contig and start position,
+ * then a GenomeLoc is returned for contig:start-start, otherwise an UNMAPPED GenomeLoc is returned.
+ *
+ * @param read the read from which to create a genome loc
+ *
+ * @return the GenomeLoc that was created
+ */
+ @Requires("read != null")
+ @Ensures("result != null")
+ public GenomeLoc createGenomeLoc(final SAMRecord read) {
+ if ( read.getReadUnmappedFlag() && read.getReferenceIndex() == -1 )
+ // read is unmapped and not placed anywhere on the genome
+ return GenomeLoc.UNMAPPED;
+ else {
+ // Use Math.max to ensure that end >= start (Picard assigns the end to reads that are entirely within an insertion as start-1)
+ final int end = read.getReadUnmappedFlag() ? read.getAlignmentStart() : Math.max(read.getAlignmentEnd(), read.getAlignmentStart());
+ return createGenomeLoc(read.getReferenceName(), read.getReferenceIndex(), read.getAlignmentStart(), end, false);
+ }
+ }
+
+ /**
+ * Create a genome loc, given a read using its unclipped alignment. If the read is unmapped, *and* yet the read has a contig and start position,
+ * then a GenomeLoc is returned for contig:start-start, otherwise an UNMAPPED GenomeLoc is returned.
+ *
+ * @param read the read from which to create a genome loc
+ *
+ * @return the GenomeLoc that was created
+ */
+ @Requires("read != null")
+ @Ensures("result != null")
+ public GenomeLoc createGenomeLocUnclipped(final SAMRecord read) {
+ if ( read.getReadUnmappedFlag() && read.getReferenceIndex() == -1 )
+ // read is unmapped and not placed anywhere on the genome
+ return GenomeLoc.UNMAPPED;
+ else {
+ // Use Math.max to ensure that end >= start (Picard assigns the end to reads that are entirely within an insertion as start-1)
+ final int end = read.getReadUnmappedFlag() ? read.getUnclippedEnd() : Math.max(read.getUnclippedEnd(), read.getUnclippedStart());
+ return createGenomeLoc(read.getReferenceName(), read.getReferenceIndex(), read.getUnclippedStart(), end, false);
+ }
+ }
+
+ /**
+ * Creates a GenomeLoc from a Tribble feature
+ * @param feature
+ * @return
+ */
+ public GenomeLoc createGenomeLoc(final Feature feature) {
+ return createGenomeLoc(feature.getChr(), feature.getStart(), feature.getEnd());
+ }
+
+ /**
+ * @see GenomeLoc.setStart
+ */
+ @Deprecated
+ public GenomeLoc setStart(final GenomeLoc loc, final int start) {
+ return createGenomeLoc(loc.getContig(), loc.getContigIndex(), start, loc.getStop());
+ }
+
+ /**
+ * @see GenomeLoc.setStop
+ */
+ @Deprecated
+ public GenomeLoc setStop(final GenomeLoc loc, final int stop) {
+ return createGenomeLoc(loc.getContig(), loc.getContigIndex(), loc.start, stop);
+ }
+
+ /**
+ * @see GenomeLoc.incPos
+ */
+ @Deprecated
+ public GenomeLoc incPos(final GenomeLoc loc) {
+ return incPos(loc, 1);
+ }
+
+ /**
+ * @see GenomeLoc.incPos
+ */
+ @Deprecated
+ public GenomeLoc incPos(final GenomeLoc loc, final int by) {
+ return createGenomeLoc(loc.getContig(), loc.getContigIndex(), loc.start + by, loc.stop + by);
+ }
+
+ /**
+ * Creates a GenomeLoc than spans the entire contig.
+ * @param contigName Name of the contig.
+ * @return A locus spanning the entire contig.
+ */
+ @Requires("contigName != null")
+ @Ensures("result != null")
+ public GenomeLoc createOverEntireContig(final String contigName) {
+ SAMSequenceRecord contig = getContigInfo().getSequence(contigName);
+ return createGenomeLoc(contigName,contig.getSequenceIndex(),1,contig.getSequenceLength(), true);
+ }
+
+ /**
+ * Creates a loc to the left (starting at the loc start + 1) of maxBasePairs size.
+ * @param loc The original loc
+ * @param maxBasePairs The maximum number of basePairs
+ * @return The contiguous loc of up to maxBasePairs length or null if the loc is already at the start of the contig.
+ */
+ @Requires({"loc != null", "maxBasePairs > 0"})
+ public GenomeLoc createGenomeLocAtStart(final GenomeLoc loc, final int maxBasePairs) {
+ if (GenomeLoc.isUnmapped(loc))
+ return null;
+ final String contigName = loc.getContig();
+ final SAMSequenceRecord contig = getContigInfo().getSequence(contigName);
+ final int contigIndex = contig.getSequenceIndex();
+
+ int start = loc.getStart() - maxBasePairs;
+ int stop = loc.getStart() - 1;
+
+ if (start < 1)
+ start = 1;
+ if (stop < 1)
+ return null;
+
+ return createGenomeLoc(contigName, contigIndex, start, stop, true);
+ }
+
+ /**
+ * Creates a loc padded in both directions by maxBasePairs size (if possible).
+ * @param loc The original loc
+ * @param padding The number of base pairs to pad on either end
+ * @return The contiguous loc of length up to the original length + 2*padding (depending on the start/end of the contig).
+ */
+ @Requires({"loc != null", "padding >= 0"})
+ public GenomeLoc createPaddedGenomeLoc(final GenomeLoc loc, final int padding) {
+ if (GenomeLoc.isUnmapped(loc) || padding == 0)
+ return loc;
+ else
+ return createGenomeLocOnContig(loc.getContig(), loc.getContigIndex(), loc.getStart() - padding, loc.getStop() + padding);
+ }
+
+ /**
+ * Creates a loc to the right (starting at the loc stop + 1) of maxBasePairs size.
+ * @param loc The original loc
+ * @param maxBasePairs The maximum number of basePairs
+ * @return The contiguous loc of up to maxBasePairs length or null if the loc is already at the end of the contig.
+ */
+ @Requires({"loc != null", "maxBasePairs > 0"})
+ public GenomeLoc createGenomeLocAtStop(final GenomeLoc loc, final int maxBasePairs) {
+ if (GenomeLoc.isUnmapped(loc))
+ return null;
+ String contigName = loc.getContig();
+ SAMSequenceRecord contig = getContigInfo().getSequence(contigName);
+ int contigIndex = contig.getSequenceIndex();
+ int contigLength = contig.getSequenceLength();
+
+ int start = loc.getStop() + 1;
+ int stop = loc.getStop() + maxBasePairs;
+
+ if (start > contigLength)
+ return null;
+ if (stop > contigLength)
+ stop = contigLength;
+
+ return createGenomeLoc(contigName, contigIndex, start, stop, true);
+ }
+
+ /**
+ * @see #createGenomeLocOnContig(String, int, int, int) with the contig index looked up from contig
+ */
+ public GenomeLoc createGenomeLocOnContig(final String contig, final int start, final int stop) {
+ return createGenomeLocOnContig(contig, getContigIndex(contig), start, stop);
+ }
+
+ /**
+ * Create a new genome loc, bounding start and stop by the start and end of contig
+ *
+ * This function will return null if start and stop cannot be adjusted in any reasonable way
+ * to be on the contig. For example, if start and stop are both past the end of the contig,
+ * there's no way to fix this, and null will be returned.
+ *
+ * @param contig our contig
+ * @param start our start as an arbitrary integer (may be negative, etc)
+ * @param stop our stop as an arbitrary integer (may be negative, etc)
+ * @return a valid genome loc over contig, or null if a meaningful genome loc cannot be created
+ */
+ public GenomeLoc createGenomeLocOnContig(final String contig, final int contigIndex, final int start, final int stop) {
+ final int contigLength = getContigInfo().getSequence(contigIndex).getSequenceLength();
+ final int boundedStart = Math.max(1, start);
+ final int boundedStop = Math.min(contigLength, stop);
+
+ if ( boundedStart > contigLength || boundedStop < 1 )
+ // there's no meaningful way to create this genome loc, as the start and stop are off the contig
+ return null;
+ else
+ return createGenomeLoc(contig, contigIndex, boundedStart, boundedStop);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/GenomeLocSortedSet.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/GenomeLocSortedSet.java
new file mode 100644
index 0000000..694c271
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/GenomeLocSortedSet.java
@@ -0,0 +1,476 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.interval.IntervalUtils;
+
+import java.util.*;
+
+/**
+ * <p/>
+ * Class GenomeLocCollection
+ * <p/>
+ * a set of genome locations. This collection is self sorting,
+ * and will merge genome locations that are overlapping. The remove function
+ * will also remove a region from the list, if the region to remove is a
+ * partial interval of a region in the collection it will remove the region from
+ * that element.
+ *
+ * @author aaron
+ * Date: May 22, 2009
+ * Time: 10:54:40 AM
+ */
+public class GenomeLocSortedSet extends AbstractSet<GenomeLoc> {
+ private static Logger logger = Logger.getLogger(GenomeLocSortedSet.class);
+
+ private GenomeLocParser genomeLocParser;
+
+ // our private storage for the GenomeLoc's
+ private final List<GenomeLoc> mArray = new ArrayList<GenomeLoc>();
+
+ // cache this to make overlap checking much more efficient
+ private int previousOverlapSearchIndex = -1;
+
+ /**
+ * Create a new, empty GenomeLocSortedSet
+ *
+ * @param parser a non-null the parser we use to create genome locs
+ */
+ public GenomeLocSortedSet(final GenomeLocParser parser) {
+ if ( parser == null ) throw new IllegalArgumentException("parser cannot be null");
+ this.genomeLocParser = parser;
+ }
+
+ /**
+ * Create a new GenomeLocSortedSet containing location e
+ *
+ * @param parser a non-null the parser we use to create genome locs
+ * @param e a single genome locs to add to this set
+ */
+ public GenomeLocSortedSet(final GenomeLocParser parser, final GenomeLoc e) {
+ this(parser);
+ add(e);
+ }
+
+ /**
+ * Create a new GenomeLocSortedSet containing locations l
+ *
+ * The elements in l can be in any order, and can be overlapping. They will be sorted first and
+ * overlapping (but not contiguous) elements will be merged
+ *
+ * @param parser a non-null the parser we use to create genome locs
+ * @param l a collection of genome locs to add to this set
+ */
+ public GenomeLocSortedSet(final GenomeLocParser parser, final Collection<GenomeLoc> l) {
+ this(parser);
+
+ final ArrayList<GenomeLoc> sorted = new ArrayList<GenomeLoc>(l);
+ Collections.sort(sorted);
+ mArray.addAll(IntervalUtils.mergeIntervalLocations(sorted, IntervalMergingRule.OVERLAPPING_ONLY));
+ }
+
+ /**
+ * Gets the GenomeLocParser used to create this sorted set.
+ * @return The parser. Will never be null.
+ */
+ public GenomeLocParser getGenomeLocParser() {
+ return genomeLocParser;
+ }
+
+ /**
+ * get an iterator over this collection
+ *
+ * @return an iterator<GenomeLoc>
+ */
+ public Iterator<GenomeLoc> iterator() {
+ return mArray.iterator();
+ }
+
+ /**
+ * return the size of the collection
+ *
+ * @return the size of the collection
+ */
+ public int size() {
+ return mArray.size();
+ }
+
+ /**
+ * Return the size, in bp, of the genomic regions by all of the regions in this set
+ * @return size in bp of the covered regions
+ */
+ public long coveredSize() {
+ long s = 0;
+ for ( GenomeLoc e : this )
+ s += e.size();
+ return s;
+ }
+
+ /**
+ * Return the number of bps before loc in the sorted set
+ *
+ * @param loc the location before which we are counting bases
+ * @return the number of base pairs over all previous intervals
+ */
+ public long sizeBeforeLoc(GenomeLoc loc) {
+ long s = 0;
+
+ for ( GenomeLoc e : this ) {
+ if ( e.isBefore(loc) )
+ s += e.size();
+ else if ( e.isPast(loc) )
+ break; // we are done
+ else // loc is inside of s
+ s += loc.getStart() - e.getStart();
+ }
+
+ return s;
+ }
+
+ /**
+ * determine if the collection is empty
+ *
+ * @return true if we have no elements
+ */
+ public boolean isEmpty() {
+ return mArray.isEmpty();
+ }
+
+ /**
+ * Determine if the given loc overlaps any loc in the sorted set
+ *
+ * @param loc the location to test
+ * @return trip if the location overlaps any loc
+ */
+ public boolean overlaps(final GenomeLoc loc) {
+ // edge condition
+ if ( mArray.isEmpty() )
+ return false;
+
+ // use the cached version first
+ if ( previousOverlapSearchIndex != -1 && overlapsAtOrImmediatelyAfterCachedIndex(loc, true) )
+ return true;
+
+ // update the cached index
+ previousOverlapSearchIndex = Collections.binarySearch(mArray, loc);
+
+ // if it matches an interval exactly, we are done
+ if ( previousOverlapSearchIndex >= 0 )
+ return true;
+
+ // check whether it overlaps the interval before or after the insertion point
+ previousOverlapSearchIndex = Math.max(0, -1 * previousOverlapSearchIndex - 2);
+ return overlapsAtOrImmediatelyAfterCachedIndex(loc, false);
+ }
+
+ private boolean overlapsAtOrImmediatelyAfterCachedIndex(final GenomeLoc loc, final boolean updateCachedIndex) {
+ // check the cached entry
+ if ( mArray.get(previousOverlapSearchIndex).overlapsP(loc) )
+ return true;
+
+ // check the entry after the cached entry since we may have moved to it
+ boolean returnValue = false;
+ if ( previousOverlapSearchIndex < mArray.size() - 1 ) {
+ returnValue = mArray.get(previousOverlapSearchIndex + 1).overlapsP(loc);
+ if ( updateCachedIndex )
+ previousOverlapSearchIndex++;
+ }
+
+ return returnValue;
+ }
+
+ /**
+ * Return a list of intervals overlapping loc
+ *
+ * @param loc the location we want overlapping intervals
+ * @return a non-null list of locations that overlap loc
+ */
+ public List<GenomeLoc> getOverlapping(final GenomeLoc loc) {
+ // the max ensures that if loc would be the first element, that we start searching at the first element
+ final int index = Collections.binarySearch(mArray, loc);
+ if ( index >= 0 )
+ // we can safely return a singleton because overlapping regions are merged and loc is exactly in
+ // the set already
+ return Collections.singletonList(loc);
+
+ // if loc isn't in the list index is (-(insertion point) - 1). The insertion point is defined as the point at
+ // which the key would be inserted into the list: the index of the first element greater than the key, or list.size()
+ // -ins - 1 = index => -ins = index + 1 => ins = -(index + 1)
+ // Note that we look one before the index in this case, as loc might occur after the previous overlapping interval
+ final int start = Math.max(-(index + 1) - 1, 0);
+ final int size = mArray.size();
+
+ final List<GenomeLoc> overlapping = new LinkedList<GenomeLoc>();
+ for ( int i = start; i < size; i++ ) {
+ final GenomeLoc myLoc = mArray.get(i);
+ if ( loc.overlapsP(myLoc) )
+ overlapping.add(myLoc);
+ else if ( myLoc.isPast(loc) )
+ // since mArray is ordered, if myLoc is past loc that means all future
+ // intervals cannot overlap loc either. So we can safely abort the search
+ // note that we need to be a bit conservative on our tests since index needs to start
+ // at -1 the position of index, so it's possible that myLoc and loc don't overlap but the next
+ // position might
+ break;
+ }
+
+ return overlapping;
+ }
+
+ /**
+ * Return a list of intervals overlapping loc by enumerating all locs and testing for overlap
+ *
+ * Purely for testing purposes -- this is way to slow for any production code
+ *
+ * @param loc the location we want overlapping intervals
+ * @return a non-null list of locations that overlap loc
+ */
+ protected List<GenomeLoc> getOverlappingFullSearch(final GenomeLoc loc) {
+ final List<GenomeLoc> overlapping = new LinkedList<GenomeLoc>();
+
+ // super slow, but definitely works
+ for ( final GenomeLoc myLoc : mArray ) {
+ if ( loc.overlapsP(myLoc) )
+ overlapping.add(myLoc);
+ }
+
+ return overlapping;
+ }
+
+ /**
+ * Adds a GenomeLoc to the collection, inserting at the correct sorted position into the set.
+ * Throws an exception if the loc overlaps another loc already in the set.
+ *
+ * @param loc the GenomeLoc to add
+ *
+ * @return true if the loc was added or false otherwise (if the loc was null)
+ */
+ public boolean add(final GenomeLoc loc) {
+ return add(loc, false);
+ }
+
+ /**
+ * Adds a GenomeLoc to the collection, merging it if it overlaps another region.
+ * If it's not overlapping then we insert it at the correct sorted position into the set.
+ *
+ * @param loc the GenomeLoc to add
+ *
+ * @return true if the loc was added or false otherwise (if the loc was null)
+ */
+ public boolean addRegion(final GenomeLoc loc) {
+ return add(loc, true);
+ }
+
+ /**
+ * Adds a GenomeLoc to the collection, inserting at the correct sorted position into the set.
+ *
+ * @param loc the GenomeLoc to add
+ * @param mergeIfIntervalOverlaps if true we merge the interval if it overlaps another one already in the set, otherwise we throw an exception
+ *
+ * @return true if the loc was added or false otherwise (if the loc was null or an exact duplicate)
+ */
+ public boolean add(final GenomeLoc loc, final boolean mergeIfIntervalOverlaps) {
+ if ( loc == null )
+ return false;
+
+ // if we have no other intervals yet or if the new loc is past the last one in the list (which is usually the
+ // case because locs are generally added in order) then be extra efficient and just add the loc to the end
+ if ( mArray.size() == 0 || loc.isPast(mArray.get(mArray.size() - 1)) ) {
+ return mArray.add(loc);
+ }
+
+ // find where in the list the new loc belongs
+ final int binarySearchIndex = Collections.binarySearch(mArray,loc);
+
+ // if it already exists in the list, return or throw an exception as needed
+ if ( binarySearchIndex >= 0 ) {
+ if ( mergeIfIntervalOverlaps )
+ return false;
+ throw new IllegalArgumentException("GenomeLocSortedSet already contains the GenomeLoc " + loc);
+ }
+
+ // if it overlaps a loc already in the list merge or throw an exception as needed
+ final int insertionIndex = -1 * (binarySearchIndex + 1);
+ if ( ! mergeOverlappingIntervalsFromAdd(loc, insertionIndex, !mergeIfIntervalOverlaps) ) {
+ // it does not overlap any current intervals, so add it to the set
+ mArray.add(insertionIndex, loc);
+ }
+
+ return true;
+ }
+
+ /*
+ * If the provided GenomeLoc overlaps another already in the set, merge them (or throw an exception if requested)
+ *
+ * @param loc the GenomeLoc to add
+ * @param insertionIndex the index in the sorted set to add the new loc
+ * @param throwExceptionIfOverlapping if true we throw an exception if there's overlap, otherwise we merge them
+ *
+ * @return true if the loc was added or false otherwise
+ */
+ private boolean mergeOverlappingIntervalsFromAdd(final GenomeLoc loc, final int insertionIndex, final boolean throwExceptionIfOverlapping) {
+ // try merging with the previous index
+ if ( insertionIndex != 0 && loc.overlapsP(mArray.get(insertionIndex - 1)) ) {
+ if ( throwExceptionIfOverlapping )
+ throw new IllegalArgumentException(String.format("GenomeLocSortedSet contains a GenomeLoc (%s) that overlaps with the provided one (%s)", mArray.get(insertionIndex - 1).toString(), loc.toString()));
+ mArray.set(insertionIndex - 1, mArray.get(insertionIndex - 1).merge(loc));
+ return true;
+ }
+
+ // try merging with the following index
+ if ( insertionIndex < mArray.size() && loc.overlapsP(mArray.get(insertionIndex)) ) {
+ if ( throwExceptionIfOverlapping )
+ throw new IllegalArgumentException(String.format("GenomeLocSortedSet contains a GenomeLoc (%s) that overlaps with the provided one (%s)", mArray.get(insertionIndex).toString(), loc.toString()));
+ mArray.set(insertionIndex, mArray.get(insertionIndex).merge(loc));
+ return true;
+ }
+
+ return false;
+ }
+
+ public GenomeLocSortedSet subtractRegions(GenomeLocSortedSet toRemoveSet) {
+ LinkedList<GenomeLoc> good = new LinkedList<GenomeLoc>();
+ Stack<GenomeLoc> toProcess = new Stack<GenomeLoc>();
+ Stack<GenomeLoc> toExclude = new Stack<GenomeLoc>();
+
+ // initialize the stacks
+ toProcess.addAll(mArray);
+ Collections.reverse(toProcess);
+ toExclude.addAll(toRemoveSet.mArray);
+ Collections.reverse(toExclude);
+
+ int i = 0;
+ while ( ! toProcess.empty() ) { // while there's still stuff to process
+ if ( toExclude.empty() ) {
+ good.addAll(toProcess); // no more excludes, all the processing stuff is good
+ break;
+ }
+
+ GenomeLoc p = toProcess.peek();
+ GenomeLoc e = toExclude.peek();
+
+ if ( p.overlapsP(e) ) {
+ toProcess.pop();
+ for ( GenomeLoc newP : p.subtract(e) )
+ toProcess.push(newP);
+ } else if ( p.compareContigs(e) < 0 ) {
+ good.add(toProcess.pop()); // p is now good
+ } else if ( p.compareContigs(e) > 0 ) {
+ toExclude.pop(); // e can't effect anything
+ } else if ( p.getStop() < e.getStart() ) {
+ good.add(toProcess.pop()); // p stops before e starts, p is good
+ } else if ( e.getStop() < p.getStart() ) {
+ toExclude.pop(); // p starts after e stops, e is done
+ } else {
+ throw new ReviewedGATKException("BUG: unexpected condition: p=" + p + ", e=" + e);
+ }
+
+ if ( i++ % 10000 == 0 )
+ logger.debug("removeRegions operation: i = " + i);
+ }
+
+ return createSetFromList(genomeLocParser,good);
+ }
+
+
+ /**
+ * a simple removal of an interval contained in this list. The interval must be identical to one in the list (no partial locations or overlapping)
+ * @param location the GenomeLoc to remove
+ */
+ public void remove(GenomeLoc location) {
+ if (!mArray.contains(location)) throw new IllegalArgumentException("Unable to remove location: " + location + ", not in the list");
+ mArray.remove(location);
+ }
+
+ /**
+ * create a list of genomic locations, given a reference sequence
+ *
+ * @param dict the sequence dictionary to create a collection from
+ *
+ * @return the GenomeLocSet of all references sequences as GenomeLoc's
+ */
+ public static GenomeLocSortedSet createSetFromSequenceDictionary(final SAMSequenceDictionary dict) {
+ final GenomeLocParser parser = new GenomeLocParser(dict);
+ final GenomeLocSortedSet returnSortedSet = new GenomeLocSortedSet(parser);
+ for ( final SAMSequenceRecord sequence : dict.getSequences() ) {
+ returnSortedSet.add(parser.createOverEntireContig(sequence.getSequenceName()));
+ }
+ return returnSortedSet;
+ }
+
+ /**
+ * Create a sorted genome location set from a list of GenomeLocs.
+ *
+ * @param locs the list<GenomeLoc>
+ *
+ * @return the sorted genome loc list
+ */
+ public static GenomeLocSortedSet createSetFromList(GenomeLocParser parser,List<GenomeLoc> locs) {
+ GenomeLocSortedSet set = new GenomeLocSortedSet(parser);
+ set.addAll(locs);
+ return set;
+ }
+
+
+ /**
+ * return a deep copy of this collection.
+ *
+ * @return a new GenomeLocSortedSet, identical to the current GenomeLocSortedSet.
+ */
+ public GenomeLocSortedSet clone() {
+ GenomeLocSortedSet ret = new GenomeLocSortedSet(genomeLocParser);
+ for (GenomeLoc loc : this.mArray) {
+ // ensure a deep copy
+ ret.mArray.add(genomeLocParser.createGenomeLoc(loc.getContig(), loc.getStart(), loc.getStop()));
+ }
+ return ret;
+ }
+
+ /**
+ * convert this object to a list
+ * @return the lists
+ */
+ public List<GenomeLoc> toList() {
+ return this.mArray;
+ }
+
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ s.append("[");
+ for ( GenomeLoc e : this ) {
+ s.append(" ");
+ s.append(e.toString());
+ }
+ s.append("]");
+
+ return s.toString();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/HeapSizeMonitor.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/HeapSizeMonitor.java
new file mode 100644
index 0000000..041bf76
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/HeapSizeMonitor.java
@@ -0,0 +1,107 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+
+/**
+ * Monitor the current heap size, allowing the application to programmatically
+ * access the data.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class HeapSizeMonitor {
+ private final int monitorFrequencyMillis;
+ private final MonitorRunnable monitorRunnable;
+
+ private Thread monitorThread;
+
+ public HeapSizeMonitor() {
+ this(1000);
+ }
+
+ public HeapSizeMonitor(final int monitorFrequencyMillis) {
+ this.monitorFrequencyMillis = monitorFrequencyMillis;
+ this.monitorRunnable = new MonitorRunnable();
+ }
+
+ public long getMaxMemoryUsed() {
+ return monitorRunnable.getMaxMemoryUsed();
+ }
+
+ public void start() {
+ monitorThread = new Thread(monitorRunnable);
+ monitorThread.start();
+ }
+
+ public void stop() {
+ monitorRunnable.stop = true;
+ try {
+ monitorThread.join();
+ }
+ catch(InterruptedException ex) {
+ throw new ReviewedGATKException("Unable to connect to monitor thread");
+ }
+ monitorThread = null;
+ }
+
+ private class MonitorRunnable implements Runnable {
+ private MemoryMXBean monitor;
+
+ private long maxMemoryUsed;
+ private boolean stop;
+
+ public MonitorRunnable() {
+ monitor = ManagementFactory.getMemoryMXBean();
+ }
+
+ public void reset() {
+ maxMemoryUsed = 0L;
+ stop = false;
+ }
+
+ public long getMaxMemoryUsed() {
+ return maxMemoryUsed;
+ }
+
+ public void run() {
+ while(!stop) {
+ System.gc();
+ maxMemoryUsed = Math.max(monitor.getHeapMemoryUsage().getUsed(),maxMemoryUsed);
+ try {
+ Thread.sleep(monitorFrequencyMillis);
+ }
+ catch(InterruptedException ex) {
+ throw new ReviewedGATKException("Unable to continue monitoring heap consumption",ex);
+ }
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/IndelUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/IndelUtils.java
new file mode 100644
index 0000000..81a2bdc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/IndelUtils.java
@@ -0,0 +1,262 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: delangel
+ * Date: Feb 3, 2011
+ * Time: 2:44:22 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class IndelUtils {
+ protected final static String[] COLUMN_KEYS;
+
+
+
+ static {
+ COLUMN_KEYS= new String[51];
+ COLUMN_KEYS[0] = "Novel_A";
+ COLUMN_KEYS[1] = "Novel_C";
+ COLUMN_KEYS[2] = "Novel_G";
+ COLUMN_KEYS[3] = "Novel_T";
+ COLUMN_KEYS[4] = "NOVEL_1";
+ COLUMN_KEYS[5] = "NOVEL_2";
+ COLUMN_KEYS[6] = "NOVEL_3";
+ COLUMN_KEYS[7] = "NOVEL_4";
+ COLUMN_KEYS[8] = "NOVEL_5";
+ COLUMN_KEYS[9] = "NOVEL_6";
+ COLUMN_KEYS[10] = "NOVEL_7";
+ COLUMN_KEYS[11] = "NOVEL_8";
+ COLUMN_KEYS[12] = "NOVEL_9";
+ COLUMN_KEYS[13] = "NOVEL_10orMore";
+ COLUMN_KEYS[14] = "RepeatExpansion_A";
+ COLUMN_KEYS[15] = "RepeatExpansion_C";
+ COLUMN_KEYS[16] = "RepeatExpansion_G";
+ COLUMN_KEYS[17] = "RepeatExpansion_T";
+ COLUMN_KEYS[18] = "RepeatExpansion_AC";
+ COLUMN_KEYS[19] = "RepeatExpansion_AG";
+ COLUMN_KEYS[20] = "RepeatExpansion_AT";
+ COLUMN_KEYS[21] = "RepeatExpansion_CA";
+ COLUMN_KEYS[22] = "RepeatExpansion_CG";
+ COLUMN_KEYS[23] = "RepeatExpansion_CT";
+ COLUMN_KEYS[24] = "RepeatExpansion_GA";
+ COLUMN_KEYS[25] = "RepeatExpansion_GC";
+ COLUMN_KEYS[26] = "RepeatExpansion_GT";
+ COLUMN_KEYS[27] = "RepeatExpansion_TA";
+ COLUMN_KEYS[28] = "RepeatExpansion_TC";
+ COLUMN_KEYS[29] = "RepeatExpansion_TG";
+ COLUMN_KEYS[30] = "EventLength_1";
+ COLUMN_KEYS[31] = "EventLength_2";
+ COLUMN_KEYS[32] = "EventLength_3";
+ COLUMN_KEYS[33] = "EventLength_4";
+ COLUMN_KEYS[34] = "EventLength_5";
+ COLUMN_KEYS[35] = "EventLength_6";
+ COLUMN_KEYS[36] = "EventLength_7";
+ COLUMN_KEYS[37] = "EventLength_8";
+ COLUMN_KEYS[38] = "EventLength_9";
+ COLUMN_KEYS[39] = "EventLength_10orMore";
+ COLUMN_KEYS[40] = "NumRepetitions_1";
+ COLUMN_KEYS[41] = "NumRepetitions_2";
+ COLUMN_KEYS[42] = "NumRepetitions_3";
+ COLUMN_KEYS[43] = "NumRepetitions_4";
+ COLUMN_KEYS[44] = "NumRepetitions_5";
+ COLUMN_KEYS[45] = "NumRepetitions_6";
+ COLUMN_KEYS[46] = "NumRepetitions_7";
+ COLUMN_KEYS[47] = "NumRepetitions_8";
+ COLUMN_KEYS[48] = "NumRepetitions_9";
+ COLUMN_KEYS[49] = "NumRepetitions_10orMore";
+ COLUMN_KEYS[50] = "Other";
+
+ }
+
+ private static final int START_IND_NOVEL = 4;
+ private static final int STOP_IND_NOVEL = 13;
+ private static final int START_IND_FOR_REPEAT_EXPANSION_1 = 14;
+ private static final int IND_FOR_REPEAT_EXPANSION_A = 14;
+ private static final int IND_FOR_REPEAT_EXPANSION_C = 15;
+ private static final int IND_FOR_REPEAT_EXPANSION_G = 16;
+ private static final int IND_FOR_REPEAT_EXPANSION_T = 17;
+ private static final int STOP_IND_FOR_REPEAT_EXPANSION_2 = 29;
+ private static final int START_IND_FOR_REPEAT_EXPANSION_COUNTS = 30;
+ private static final int STOP_IND_FOR_REPEAT_EXPANSION_COUNTS = 39;
+ private static final int START_IND_FOR_NUM_REPETITION_COUNTS = 40;
+ private static final int STOP_IND_FOR_NUM_REPETITION_COUNTS = 49;
+ private static final int IND_FOR_OTHER_EVENT = 50;
+ private static final int START_IND_NOVEL_PER_BASE = 0;
+ private static final int STOP_IND_NOVEL_PER_BASE = 3;
+
+ private static String findMinimalEvent(String eventString) {
+
+ // for each length up to given string length, see if event string is a repetition of units of size N
+ String minEvent = eventString;
+ for (int k=1; k < eventString.length(); k++) {
+ if (eventString.length() % k > 0)
+ continue;
+ String str = eventString.substring(0,k);
+ // now see if event string is a repetition of str
+ int numReps = eventString.length() / k;
+ String r = "";
+ for (int j=0; j < numReps; j++)
+ r = r.concat(str);
+
+ if (r.matches(eventString)) {
+ minEvent = str;
+ break;
+ }
+
+ }
+ return minEvent;
+ }
+
+ public static ArrayList<Integer> findEventClassificationIndex(VariantContext vc, ReferenceContext ref) {
+ int eventLength;
+
+ String indelAlleleString;
+ boolean done = false;
+
+ ArrayList<Integer> inds = new ArrayList<Integer>();
+ if ( vc.isSimpleInsertion() ) {
+ indelAlleleString = vc.getAlternateAllele(0).getDisplayString().substring(1);
+ } else if ( vc.isSimpleDeletion() ) {
+ indelAlleleString = vc.getReference().getDisplayString().substring(1);
+ }
+ else {
+ inds.add(IND_FOR_OTHER_EVENT);
+ return inds;
+ }
+
+ byte[] refBases = ref.getBases();
+
+ indelAlleleString = findMinimalEvent(indelAlleleString);
+ eventLength = indelAlleleString.length();
+
+ // See first if indel is a repetition of bases before current
+ int indStart = refBases.length/2-eventLength+1;
+
+ int numRepetitions = 0;
+ while (!done) {
+ if (indStart < 0)
+ done = true;
+ else {
+ String refPiece = new String(Arrays.copyOfRange(refBases,indStart,indStart+eventLength));
+ if (refPiece.matches(indelAlleleString))
+ {
+ numRepetitions++;
+ indStart = indStart - eventLength;
+ }
+ else
+ done = true;
+
+ }
+ }
+
+ // now do it forward
+ done = false;
+ indStart = refBases.length/2+1;
+ while (!done) {
+ if (indStart + eventLength >= refBases.length)
+ break;
+ else {
+ String refPiece = new String(Arrays.copyOfRange(refBases,indStart,indStart+eventLength));
+ if (refPiece.matches(indelAlleleString))
+ {
+ numRepetitions++;
+ indStart = indStart + eventLength;
+ }
+ else
+ done = true;
+
+ }
+ }
+
+ if (numRepetitions == 0) {
+ //unrepeated sequence from surroundings
+ int ind = START_IND_NOVEL + (eventLength-1);
+ if (ind > STOP_IND_NOVEL)
+ ind = STOP_IND_NOVEL;
+ inds.add(ind);
+
+ if (eventLength == 1) {
+ // log single base indels additionally by base
+ String keyStr = "Novel_" + indelAlleleString;
+ int k;
+ for (k=START_IND_NOVEL_PER_BASE; k <= STOP_IND_NOVEL_PER_BASE; k++) {
+ if (keyStr.matches(COLUMN_KEYS[k]))
+ break;
+ }
+ inds.add(k);
+ }
+ }
+ else {
+ // log number of repetition counts
+ int ind = START_IND_FOR_NUM_REPETITION_COUNTS + (numRepetitions-1);
+ if (ind > STOP_IND_FOR_NUM_REPETITION_COUNTS)
+ ind = STOP_IND_FOR_NUM_REPETITION_COUNTS;
+ inds.add(ind);
+
+ ind = START_IND_FOR_REPEAT_EXPANSION_COUNTS + (eventLength - 1);
+ if (ind > STOP_IND_FOR_REPEAT_EXPANSION_COUNTS)
+ ind = STOP_IND_FOR_REPEAT_EXPANSION_COUNTS;
+ inds.add(ind);
+
+ // log event length
+ if (eventLength<=2) {
+ // for single or dinucleotide indels, we further log the base in which they occurred
+ String keyStr = "RepeatExpansion_" + indelAlleleString;
+ int k;
+ for (k=START_IND_FOR_REPEAT_EXPANSION_1; k <= STOP_IND_FOR_REPEAT_EXPANSION_2; k++) {
+ if (keyStr.matches(COLUMN_KEYS[k]))
+ break;
+ }
+ // log now event
+ inds.add(k);
+ }
+
+
+ }
+
+ return inds;
+ }
+
+ public static String getIndelClassificationName(int k) {
+ if (k >=0 && k < COLUMN_KEYS.length)
+ return COLUMN_KEYS[k];
+ else
+ throw new ReviewedGATKException("Invalid index when trying to get indel classification name");
+ }
+
+ public static boolean isInsideExtendedIndel(VariantContext vc, ReferenceContext ref) {
+ return (vc.getStart() != ref.getLocus().getStart());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/LRUCache.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/LRUCache.java
new file mode 100644
index 0000000..df2e829
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/LRUCache.java
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * An LRU cache implemented as an extension to LinkedHashMap
+ */
+public class LRUCache<K,V> extends LinkedHashMap<K,V> {
+ private int capacity; // Maximum number of items in the cache.
+
+ public LRUCache(int capacity) {
+ super(capacity+1, 1.0f, true); // Pass 'true' for accessOrder.
+ this.capacity = capacity;
+ }
+
+ protected boolean removeEldestEntry(final Map.Entry entry) {
+ return (size() > this.capacity);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MRUCachingSAMSequenceDictionary.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MRUCachingSAMSequenceDictionary.java
new file mode 100644
index 0000000..2f9a3b0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MRUCachingSAMSequenceDictionary.java
@@ -0,0 +1,186 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+/**
+ * A wrapper class that provides efficient most recently used caching for the global
+ * SAMSequenceDictionary underlying all of the GATK engine capabilities. It is essential
+ * that these class be as efficient as possible. It doesn't need to be thread-safe, as
+ * GenomeLocParser uses a thread-local variable to ensure that each thread gets its own MRU
+ * cache.
+ *
+ * The MRU elements are the SAMSequenceRecord, the lastContig, and the lastIndex. The
+ * cached value is the actual SAMSequenceRecord of the most recently accessed value from
+ * getSequence, along with local variables for the contig index and contig string.
+ */
+final class MRUCachingSAMSequenceDictionary {
+ /**
+ * Our sequence dictionary
+ */
+ private final SAMSequenceDictionary dict;
+
+ SAMSequenceRecord lastSSR = null;
+ String lastContig = "";
+ int lastIndex = -1;
+
+ /**
+ * Create a new MRUCachingSAMSequenceDictionary that provides information about sequences in dict
+ * @param dict a non-null, non-empty sequencing dictionary
+ */
+ @Ensures("lastSSR == null")
+ public MRUCachingSAMSequenceDictionary(final SAMSequenceDictionary dict) {
+ if ( dict == null ) throw new IllegalArgumentException("Dictionary cannot be null");
+ if ( dict.size() == 0 ) throw new IllegalArgumentException("Dictionary cannot have size zero");
+
+ this.dict = dict;
+ }
+
+ /**
+ * Get our sequence dictionary
+ * @return a non-null SAMSequenceDictionary
+ */
+ @Ensures("result != null")
+ public SAMSequenceDictionary getDictionary() {
+ return dict;
+ }
+
+ /**
+ * Is contig present in the dictionary? Efficiently caching.
+ * @param contig a non-null contig we want to test
+ * @return true if contig is in dictionary, false otherwise
+ */
+ @Requires("contig != null")
+ public final boolean hasContig(final String contig) {
+ return contig.equals(lastContig) || dict.getSequence(contig) != null;
+ }
+
+ /**
+ * Is contig index present in the dictionary? Efficiently caching.
+ * @param contigIndex an integer offset that might map to a contig in this dictionary
+ * @return true if contigIndex is in dictionary, false otherwise
+ */
+ @Requires("contigIndex >= 0")
+ public final boolean hasContigIndex(final int contigIndex) {
+ return lastIndex == contigIndex || dict.getSequence(contigIndex) != null;
+ }
+
+ /**
+ * Same as SAMSequenceDictionary.getSequence but uses a MRU cache for efficiency
+ *
+ * @param contig the contig name we want to get the sequence record of
+ * @throws ReviewedGATKException if contig isn't present in the dictionary
+ * @return the sequence record for contig
+ */
+ @Requires("contig != null")
+ @Ensures("result != null")
+ public final SAMSequenceRecord getSequence(final String contig) {
+ if ( isCached(contig) )
+ return lastSSR;
+ else
+ return updateCache(contig, -1);
+ }
+
+ /**
+ * Same as SAMSequenceDictionary.getSequence but uses a MRU cache for efficiency
+ *
+ * @param index the contig index we want to get the sequence record of
+ * @throws ReviewedGATKException if contig isn't present in the dictionary
+ * @return the sequence record for contig
+ */
+ @Requires("index >= 0")
+ @Ensures("result != null")
+ public final SAMSequenceRecord getSequence(final int index) {
+ if ( isCached(index) )
+ return lastSSR;
+ else
+ return updateCache(null, index);
+ }
+
+ /**
+ * Same as SAMSequenceDictionary.getSequenceIndex but uses a MRU cache for efficiency
+ *
+ * @param contig the contig we want to get the sequence record of
+ * @throws ReviewedGATKException if index isn't present in the dictionary
+ * @return the sequence record index for contig
+ */
+ @Requires("contig != null")
+ @Ensures("result >= 0")
+ public final int getSequenceIndex(final String contig) {
+ if ( ! isCached(contig) ) {
+ updateCache(contig, -1);
+ }
+
+ return lastIndex;
+ }
+
+ /**
+ * Is contig the MRU cached contig?
+ * @param contig the contig to test
+ * @return true if contig is the currently cached contig, false otherwise
+ */
+ @Requires({"contig != null"})
+ protected boolean isCached(final String contig) {
+ return contig.equals(lastContig);
+ }
+
+ /**
+ * Is the contig index index the MRU cached index?
+ * @param index the contig index to test
+ * @return true if contig index is the currently cached contig index, false otherwise
+ */
+ protected boolean isCached(final int index) {
+ return lastIndex == index;
+ }
+
+ /**
+ * The key algorithm. Given a new record, update the last used record, contig
+ * name, and index.
+ *
+ * @param contig the contig we want to look up. If null, index is used instead
+ * @param index the contig index we want to look up. Only used if contig is null
+ * @throws ReviewedGATKException if index isn't present in the dictionary
+ * @return the SAMSequenceRecord for contig / index
+ */
+ @Requires("contig != null || index >= 0")
+ @Ensures("result != null")
+ private SAMSequenceRecord updateCache(final String contig, int index ) {
+ SAMSequenceRecord rec = contig == null ? dict.getSequence(index) : dict.getSequence(contig);
+ if ( rec == null ) {
+ throw new ReviewedGATKException("BUG: requested unknown contig=" + contig + " index=" + index);
+ } else {
+ lastSSR = rec;
+ lastContig = rec.getSequenceName();
+ lastIndex = rec.getSequenceIndex();
+ return rec;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MannWhitneyU.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MannWhitneyU.java
new file mode 100644
index 0000000..a918c0a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MannWhitneyU.java
@@ -0,0 +1,508 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import cern.jet.math.Arithmetic;
+import cern.jet.random.Normal;
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.distribution.NormalDistribution;
+import org.apache.commons.math.distribution.NormalDistributionImpl;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.TreeSet;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: chartl
+ */
+public class MannWhitneyU {
+
+ private static Normal STANDARD_NORMAL = new Normal(0.0,1.0,null);
+ private static NormalDistribution APACHE_NORMAL = new NormalDistributionImpl(0.0,1.0,1e-2);
+ private static double LNSQRT2PI = Math.log(Math.sqrt(2.0*Math.PI));
+
+ private TreeSet<Pair<Number,USet>> observations;
+ private int sizeSet1;
+ private int sizeSet2;
+ private ExactMode exactMode;
+
+ public MannWhitneyU(ExactMode mode, boolean dither) {
+ if ( dither )
+ observations = new TreeSet<Pair<Number,USet>>(new DitheringComparator());
+ else
+ observations = new TreeSet<Pair<Number,USet>>(new NumberedPairComparator());
+ sizeSet1 = 0;
+ sizeSet2 = 0;
+ exactMode = mode;
+ }
+
+ public MannWhitneyU() {
+ this(ExactMode.POINT,true);
+ }
+
+ public MannWhitneyU(boolean dither) {
+ this(ExactMode.POINT,dither);
+ }
+
+ public MannWhitneyU(ExactMode mode) {
+ this(mode,true);
+ }
+
+ /**
+ * Add an observation into the observation tree
+ * @param n: the observation (a number)
+ * @param set: whether the observation comes from set 1 or set 2
+ */
+ public void add(Number n, USet set) {
+ observations.add(new Pair<Number,USet>(n,set));
+ if ( set == USet.SET1 ) {
+ ++sizeSet1;
+ } else {
+ ++sizeSet2;
+ }
+ }
+
+ public Pair<Long,Long> getR1R2() {
+ long u1 = calculateOneSidedU(observations,MannWhitneyU.USet.SET1);
+ long n1 = sizeSet1*(sizeSet1+1)/2;
+ long r1 = u1 + n1;
+ long n2 = sizeSet2*(sizeSet2+1)/2;
+ long u2 = n1*n2-u1;
+ long r2 = u2 + n2;
+
+ return new Pair<Long,Long>(r1,r2);
+ }
+
+ /**
+ * Runs the one-sided test under the hypothesis that the data in set "lessThanOther" stochastically
+ * dominates the other set
+ * @param lessThanOther - either Set1 or Set2
+ * @return - u-based z-approximation, and p-value associated with the test (p-value is exact for small n,m)
+ */
+ @Requires({"lessThanOther != null"})
+ @Ensures({"validateObservations(observations) || Double.isNaN(result.getFirst())","result != null", "! Double.isInfinite(result.getFirst())", "! Double.isInfinite(result.getSecond())"})
+ public Pair<Double,Double> runOneSidedTest(USet lessThanOther) {
+ long u = calculateOneSidedU(observations, lessThanOther);
+ int n = lessThanOther == USet.SET1 ? sizeSet1 : sizeSet2;
+ int m = lessThanOther == USet.SET1 ? sizeSet2 : sizeSet1;
+ if ( n == 0 || m == 0 ) {
+ // test is uninformative as one or both sets have no observations
+ return new Pair<Double,Double>(Double.NaN,Double.NaN);
+ }
+
+ // the null hypothesis is that {N} is stochastically less than {M}, so U has counted
+ // occurrences of {M}s before {N}s. We would expect that this should be less than (n*m+1)/2 under
+ // the null hypothesis, so we want to integrate from K=0 to K=U for cumulative cases. Always.
+ return calculateP(n, m, u, false, exactMode);
+ }
+
+ /**
+ * Runs the standard two-sided test,
+ * returns the u-based z-approximate and p values.
+ * @return a pair holding the u and p-value.
+ */
+ @Ensures({"result != null", "! Double.isInfinite(result.getFirst())", "! Double.isInfinite(result.getSecond())"})
+ //@Requires({"validateObservations(observations)"})
+ public Pair<Double,Double> runTwoSidedTest() {
+ Pair<Long,USet> uPair = calculateTwoSidedU(observations);
+ long u = uPair.first;
+ int n = uPair.second == USet.SET1 ? sizeSet1 : sizeSet2;
+ int m = uPair.second == USet.SET1 ? sizeSet2 : sizeSet1;
+ if ( n == 0 || m == 0 ) {
+ // test is uninformative as one or both sets have no observations
+ return new Pair<Double,Double>(Double.NaN,Double.NaN);
+ }
+ return calculateP(n, m, u, true, exactMode);
+ }
+
+ /**
+ * Given a u statistic, calculate the p-value associated with it, dispatching to approximations where appropriate
+ * @param n - The number of entries in the stochastically smaller (dominant) set
+ * @param m - The number of entries in the stochastically larger (dominated) set
+ * @param u - the Mann-Whitney U value
+ * @param twoSided - is the test twosided
+ * @return the (possibly approximate) p-value associated with the MWU test, and the (possibly approximate) z-value associated with it
+ * todo -- there must be an approximation for small m and large n
+ */
+ @Requires({"m > 0","n > 0"})
+ @Ensures({"result != null", "! Double.isInfinite(result.getFirst())", "! Double.isInfinite(result.getSecond())"})
+ protected static Pair<Double,Double> calculateP(int n, int m, long u, boolean twoSided, ExactMode exactMode) {
+ Pair<Double,Double> zandP;
+ if ( n > 8 && m > 8 ) {
+ // large m and n - normal approx
+ zandP = calculatePNormalApproximation(n,m,u, twoSided);
+ } else if ( n > 5 && m > 7 ) {
+ // large m, small n - sum uniform approx
+ // todo -- find the appropriate regimes where this approximation is actually better enough to merit slowness
+ // pval = calculatePUniformApproximation(n,m,u);
+ zandP = calculatePNormalApproximation(n, m, u, twoSided);
+ } else if ( n > 8 || m > 8 ) {
+ zandP = calculatePFromTable(n, m, u, twoSided);
+ } else {
+ // small m and n - full approx
+ zandP = calculatePRecursively(n,m,u,twoSided,exactMode);
+ }
+
+ return zandP;
+ }
+
+ public static Pair<Double,Double> calculatePFromTable(int n, int m, long u, boolean twoSided) {
+ // todo -- actually use a table for:
+ // todo - n large, m small
+ return calculatePNormalApproximation(n,m,u, twoSided);
+ }
+
+ /**
+ * Uses a normal approximation to the U statistic in order to return a cdf p-value. See Mann, Whitney [1947]
+ * @param n - The number of entries in the stochastically smaller (dominant) set
+ * @param m - The number of entries in the stochastically larger (dominated) set
+ * @param u - the Mann-Whitney U value
+ * @param twoSided - whether the test should be two sided
+ * @return p-value associated with the normal approximation
+ */
+ @Requires({"m > 0","n > 0"})
+ @Ensures({"result != null", "! Double.isInfinite(result.getFirst())", "! Double.isInfinite(result.getSecond())"})
+ public static Pair<Double,Double> calculatePNormalApproximation(int n,int m,long u, boolean twoSided) {
+ double z = getZApprox(n,m,u);
+ if ( twoSided ) {
+ return new Pair<Double,Double>(z,2.0*(z < 0 ? STANDARD_NORMAL.cdf(z) : 1.0-STANDARD_NORMAL.cdf(z)));
+ } else {
+ return new Pair<Double,Double>(z,STANDARD_NORMAL.cdf(z));
+ }
+ }
+
+ /**
+ * Calculates the Z-score approximation of the u-statistic
+ * @param n - The number of entries in the stochastically smaller (dominant) set
+ * @param m - The number of entries in the stochastically larger (dominated) set
+ * @param u - the Mann-Whitney U value
+ * @return the asymptotic z-approximation corresponding to the MWU p-value for n < m
+ */
+ @Requires({"m > 0","n > 0"})
+ @Ensures({"! Double.isNaN(result)", "! Double.isInfinite(result)"})
+ private static double getZApprox(int n, int m, long u) {
+ double mean = ( ((long)m)*n+1.0)/2;
+ double var = (((long) n)*m*(n+m+1.0))/12;
+ double z = ( u - mean )/Math.sqrt(var);
+ return z;
+ }
+
+ /**
+ * Uses a sum-of-uniform-0-1 random variable approximation to the U statistic in order to return an approximate
+ * p-value. See Buckle, Kraft, van Eeden [1969] (approx) and Billingsly [1995] or Stephens, MA [1966, biometrika] (sum of uniform CDF)
+ * @param n - The number of entries in the stochastically smaller (dominant) set
+ * @param m - The number of entries in the stochastically larger (dominated) set
+ * @param u - mann-whitney u value
+ * @return p-value according to sum of uniform approx
+ * todo -- this is currently not called due to not having a good characterization of where it is significantly more accurate than the
+ * todo -- normal approxmation (e.g. enough to merit the runtime hit)
+ */
+ public static double calculatePUniformApproximation(int n, int m, long u) {
+ long R = u + (n*(n+1))/2;
+ double a = Math.sqrt(m*(n+m+1));
+ double b = (n/2.0)*(1-Math.sqrt((n+m+1)/m));
+ double z = b + ((double)R)/a;
+ if ( z < 0 ) { return 1.0; }
+ else if ( z > n ) { return 0.0; }
+ else {
+ if ( z > ((double) n) /2 ) {
+ return 1.0-1/(Arithmetic.factorial(n))*uniformSumHelper(z, (int) Math.floor(z), n, 0);
+ } else {
+ return 1/(Arithmetic.factorial(n))*uniformSumHelper(z, (int) Math.floor(z), n, 0);
+ }
+ }
+ }
+
+ /**
+ * Helper function for the sum of n uniform random variables
+ * @param z - value at which to compute the (un-normalized) cdf
+ * @param m - a cutoff integer (defined by m <= z < m + 1)
+ * @param n - the number of uniform random variables
+ * @param k - holder variable for the recursion (alternatively, the index of the term in the sequence)
+ * @return the (un-normalized) cdf for the sum of n random variables
+ */
+ private static double uniformSumHelper(double z, int m, int n, int k) {
+ if ( k > m ) { return 0; }
+ int coef = (k % 2 == 0) ? 1 : -1;
+ return coef*Arithmetic.binomial(n,k)*Math.pow(z-k,n) + uniformSumHelper(z,m,n,k+1);
+ }
+
+ /**
+ * Calculates the U-statistic associated with a two-sided test (e.g. the RV from which one set is drawn
+ * stochastically dominates the RV from which the other set is drawn); two-sidedness is accounted for
+ * later on simply by multiplying the p-value by 2.
+ *
+ * Recall: If X stochastically dominates Y, the test is for occurrences of Y before X, so the lower value of u is chosen
+ * @param observed - the observed data
+ * @return the minimum of the U counts (set1 dominates 2, set 2 dominates 1)
+ */
+ @Requires({"observed != null", "observed.size() > 0"})
+ @Ensures({"result != null","result.first > 0"})
+ public static Pair<Long,USet> calculateTwoSidedU(TreeSet<Pair<Number,USet>> observed) {
+ int set1SeenSoFar = 0;
+ int set2SeenSoFar = 0;
+ long uSet1DomSet2 = 0;
+ long uSet2DomSet1 = 0;
+ USet previous = null;
+ for ( Pair<Number,USet> dataPoint : observed ) {
+
+ if ( dataPoint.second == USet.SET1 ) {
+ ++set1SeenSoFar;
+ } else {
+ ++set2SeenSoFar;
+ }
+
+ if ( previous != null ) {
+ if ( dataPoint.second == USet.SET1 ) {
+ uSet2DomSet1 += set2SeenSoFar;
+ } else {
+ uSet1DomSet2 += set1SeenSoFar;
+ }
+ }
+
+ previous = dataPoint.second;
+ }
+
+ return uSet1DomSet2 < uSet2DomSet1 ? new Pair<Long,USet>(uSet1DomSet2,USet.SET1) : new Pair<Long,USet>(uSet2DomSet1,USet.SET2);
+ }
+
+ /**
+ * Calculates the U-statistic associated with the one-sided hypothesis that "dominator" stochastically dominates
+ * the other U-set. Note that if S1 dominates S2, we want to count the occurrences of points in S2 coming before points in S1.
+ * @param observed - the observed data points, tagged by each set
+ * @param dominator - the set that is hypothesized to be stochastically dominating
+ * @return the u-statistic associated with the hypothesis that dominator stochastically dominates the other set
+ */
+ @Requires({"observed != null","dominator != null","observed.size() > 0"})
+ @Ensures({"result >= 0"})
+ public static long calculateOneSidedU(TreeSet<Pair<Number,USet>> observed,USet dominator) {
+ long otherBeforeDominator = 0l;
+ int otherSeenSoFar = 0;
+ for ( Pair<Number,USet> dataPoint : observed ) {
+ if ( dataPoint.second != dominator ) {
+ ++otherSeenSoFar;
+ } else {
+ otherBeforeDominator += otherSeenSoFar;
+ }
+ }
+
+ return otherBeforeDominator;
+ }
+
+ /**
+ * The Mann-Whitney U statistic follows a recursive equation (that enumerates the proportion of possible
+ * binary strings of "n" zeros, and "m" ones, where a one precedes a zero "u" times). This accessor
+ * calls into that recursive calculation.
+ * @param n: number of set-one entries (hypothesis: set one is stochastically less than set two)
+ * @param m: number of set-two entries
+ * @param u: number of set-two entries that precede set-one entries (e.g. 0,1,0,1,0 -> 3 )
+ * @param twoSided: whether the test is two sided or not. The recursive formula is symmetric, multiply by two for two-sidedness.
+ * @param mode: whether the mode is a point probability, or a cumulative distribution
+ * @return the probability under the hypothesis that all sequences are equally likely of finding a set-two entry preceding a set-one entry "u" times.
+ */
+ @Requires({"m > 0","n > 0","u >= 0"})
+ @Ensures({"result != null","! Double.isInfinite(result.getFirst())", "! Double.isInfinite(result.getSecond())"})
+ public static Pair<Double,Double> calculatePRecursively(int n, int m, long u, boolean twoSided, ExactMode mode) {
+ if ( m > 8 && n > 5 ) { throw new GATKException(String.format("Please use the appropriate (normal or sum of uniform) approximation. Values n: %d, m: %d",n,m)); }
+ double p = mode == ExactMode.POINT ? cpr(n,m,u) : cumulativeCPR(n,m,u);
+ //p *= twoSided ? 2.0 : 1.0;
+ double z;
+ try {
+
+ if ( mode == ExactMode.CUMULATIVE ) {
+ z = APACHE_NORMAL.inverseCumulativeProbability(p);
+ } else {
+ double sd = Math.sqrt((1.0+1.0/(1+n+m))*(n*m)*(1.0+n+m)/12); // biased variance empirically better fit to distribution then asymptotic variance
+ //System.out.printf("SD is %f and Max is %f and prob is %f%n",sd,1.0/Math.sqrt(sd*sd*2.0*Math.PI),p);
+ if ( p > 1.0/Math.sqrt(sd*sd*2.0*Math.PI) ) { // possible for p-value to be outside the range of the normal. Happens at the mean, so z is 0.
+ z = 0.0;
+ } else {
+ if ( u >= n*m/2 ) {
+ z = Math.sqrt(-2.0*(Math.log(sd)+Math.log(p)+LNSQRT2PI));
+ } else {
+ z = -Math.sqrt(-2.0*(Math.log(sd)+Math.log(p)+LNSQRT2PI));
+ }
+ }
+ }
+
+ } catch (MathException me) {
+ throw new GATKException("A math exception occurred in inverting the probability",me);
+ }
+
+ return new Pair<Double,Double>(z,(twoSided ? 2.0*p : p));
+ }
+
+ /**
+ * Hook into CPR with sufficient warning (for testing purposes)
+ * calls into that recursive calculation.
+ * @param n: number of set-one entries (hypothesis: set one is stochastically less than set two)
+ * @param m: number of set-two entries
+ * @param u: number of set-two entries that precede set-one entries (e.g. 0,1,0,1,0 -> 3 )
+ * @return same as cpr
+ */
+ protected static double calculatePRecursivelyDoNotCheckValuesEvenThoughItIsSlow(int n, int m, long u) {
+ return cpr(n,m,u);
+ }
+
+ /**
+ * For testing
+ *
+ * @param n: number of set-one entries (hypothesis: set one is stochastically less than set two)
+ * @param m: number of set-two entries
+ * @param u: number of set-two entries that precede set-one entries (e.g. 0,1,0,1,0 -> 3 )
+ */
+ protected static long countSequences(int n, int m, long u) {
+ if ( u < 0 ) { return 0; }
+ if ( m == 0 || n == 0 ) { return u == 0 ? 1 : 0; }
+
+ return countSequences(n-1,m,u-m) + countSequences(n,m-1,u);
+ }
+
+ /**
+ * : just a shorter name for calculatePRecursively. See Mann, Whitney, [1947]
+ * @param n: number of set-1 entries
+ * @param m: number of set-2 entries
+ * @param u: number of times a set-2 entry as preceded a set-1 entry
+ * @return recursive p-value
+ */
+ private static double cpr(int n, int m, long u) {
+ if ( u < 0 ) {
+ return 0.0;
+ }
+ if ( m == 0 || n == 0 ) {
+ // there are entries in set 1 or set 2, so no set-2 entry can precede a set-1 entry; thus u must be zero.
+ // note that this exists only for edification, as when we reach this point, the coefficient on this term is zero anyway
+ return ( u == 0 ) ? 1.0 : 0.0;
+ }
+
+
+ return (((double)n)/(n+m))*cpr(n-1,m,u-m) + (((double)m)/(n+m))*cpr(n,m-1,u);
+ }
+
+ private static double cumulativeCPR(int n, int m, long u ) {
+ // from above:
+ // the null hypothesis is that {N} is stochastically less than {M}, so U has counted
+ // occurrences of {M}s before {N}s. We would expect that this should be less than (n*m+1)/2 under
+ // the null hypothesis, so we want to integrate from K=0 to K=U for cumulative cases. Always.
+ double p = 0.0;
+ // optimization using symmetry, use the least amount of sums possible
+ long uSym = ( u <= n*m/2 ) ? u : ((long)n)*m-u;
+ for ( long uu = 0; uu < uSym; uu++ ) {
+ p += cpr(n,m,uu);
+ }
+ // correct by 1.0-p if the optimization above was used (e.g. 1-right tail = left tail)
+ return (u <= n*m/2) ? p : 1.0-p;
+ }
+
+ /**
+ * hook into the data tree, for testing purposes only
+ * @return observations
+ */
+ protected TreeSet<Pair<Number,USet>> getObservations() {
+ return observations;
+ }
+
+ /**
+ * hook into the set sizes, for testing purposes only
+ * @return size set 1, size set 2
+ */
+ protected Pair<Integer,Integer> getSetSizes() {
+ return new Pair<Integer,Integer>(sizeSet1,sizeSet2);
+ }
+
+ /**
+ * Validates that observations are in the correct format for a MWU test -- this is only called by the contracts API during testing
+ * @param tree - the collection of labeled observations
+ * @return true iff the tree set is valid (no INFs or NaNs, at least one data point in each set)
+ */
+ protected static boolean validateObservations(TreeSet<Pair<Number,USet>> tree) {
+ boolean seen1 = false;
+ boolean seen2 = false;
+ boolean seenInvalid = false;
+ for ( Pair<Number,USet> p : tree) {
+ if ( ! seen1 && p.getSecond() == USet.SET1 ) {
+ seen1 = true;
+ }
+
+ if ( ! seen2 && p.getSecond() == USet.SET2 ) {
+ seen2 = true;
+ }
+
+ if ( Double.isNaN(p.getFirst().doubleValue()) || Double.isInfinite(p.getFirst().doubleValue())) {
+ seenInvalid = true;
+ }
+
+ }
+
+ return ! seenInvalid && seen1 && seen2;
+ }
+
+ /**
+ * A comparator class which uses dithering on tie-breaking to ensure that the internal treeset drops no values
+ * and to ensure that rank ties are broken at random.
+ */
+ private static class DitheringComparator implements Comparator<Pair<Number,USet>>, Serializable {
+
+ public DitheringComparator() {}
+
+ @Override
+ public boolean equals(Object other) { return false; }
+
+ @Override
+ public int compare(Pair<Number,USet> left, Pair<Number,USet> right) {
+ double comp = Double.compare(left.first.doubleValue(),right.first.doubleValue());
+ if ( comp > 0 ) { return 1; }
+ if ( comp < 0 ) { return -1; }
+ return GenomeAnalysisEngine.getRandomGenerator().nextBoolean() ? -1 : 1;
+ }
+ }
+
+ /**
+ * A comparator that reaches into the pair and compares numbers without tie-braking.
+ */
+ private static class NumberedPairComparator implements Comparator<Pair<Number,USet>>, Serializable {
+
+ public NumberedPairComparator() {}
+
+ @Override
+ public boolean equals(Object other) { return false; }
+
+ @Override
+ public int compare(Pair<Number,USet> left, Pair<Number,USet> right ) {
+ return Double.compare(left.first.doubleValue(),right.first.doubleValue());
+ }
+ }
+
+ public enum USet { SET1, SET2 }
+ public enum ExactMode { POINT, CUMULATIVE }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MathUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MathUtils.java
new file mode 100644
index 0000000..01aa133
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MathUtils.java
@@ -0,0 +1,1690 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.apache.commons.math.distribution.ExponentialDistribution;
+import org.apache.commons.math.distribution.ExponentialDistributionImpl;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.math.BigDecimal;
+import java.util.*;
+
+/**
+ * MathUtils is a static class (no instantiation allowed!) with some useful math methods.
+ *
+ * @author Kiran Garimella
+ */
+public class MathUtils {
+
+ /**
+ * Private constructor. No instantiating this class!
+ */
+ private MathUtils() {
+ }
+
+ /**
+ * The smallest log10 value we'll emit from normalizeFromLog10 and other functions
+ * where the real-space value is 0.0.
+ */
+ public static final double LOG10_P_OF_ZERO = -1000000.0;
+ public static final double FAIR_BINOMIAL_PROB_LOG10_0_5 = Math.log10(0.5);
+ public static final double LOG_ONE_HALF = -Math.log10(2.0);
+ public static final double LOG_ONE_THIRD = -Math.log10(3.0);
+ private static final double NATURAL_LOG_OF_TEN = Math.log(10.0);
+ private static final double SQUARE_ROOT_OF_TWO_TIMES_PI = Math.sqrt(2.0 * Math.PI);
+
+ /**
+ * A helper class to maintain a cache of log10 values
+ */
+ public static class Log10Cache {
+ /**
+ * Get the value of log10(n), expanding the cache as necessary
+ * @param n operand
+ * @return log10(n)
+ */
+ public static double get(final int n) {
+ if (n < 0)
+ throw new ReviewedGATKException(String.format("Can't take the log of a negative number: %d", n));
+ if (n >= cache.length)
+ ensureCacheContains(Math.max(n+10, 2*cache.length));
+ /*
+ Array lookups are not atomic. It's possible that the reference to cache could be
+ changed between the time the reference is loaded and the data is fetched from the correct
+ offset. However, the value retrieved can't change, and it's guaranteed to be present in the
+ old reference by the conditional above.
+ */
+ return cache[n];
+ }
+
+ /**
+ * Ensures that the cache contains a value for n. After completion of ensureCacheContains(n),
+ * #get(n) is guaranteed to return without causing a cache expansion
+ * @param n desired value to be precomputed
+ */
+ public static synchronized void ensureCacheContains(final int n) {
+ if (n < cache.length)
+ return;
+ final double[] newCache = new double[n + 1];
+ System.arraycopy(cache, 0, newCache, 0, cache.length);
+ for (int i=cache.length; i < newCache.length; i++)
+ newCache[i] = Math.log10(i);
+ cache = newCache;
+ }
+
+ //initialize with the special case: log10(0) = NEGATIVE_INFINITY
+ private static double[] cache = new double[] { Double.NEGATIVE_INFINITY };
+ }
+
+ /**
+ * Get a random int between min and max (inclusive) using the global GATK random number generator
+ *
+ * @param min lower bound of the range
+ * @param max upper bound of the range
+ * @return a random int >= min and <= max
+ */
+ public static int randomIntegerInRange( final int min, final int max ) {
+ return GenomeAnalysisEngine.getRandomGenerator().nextInt(max - min + 1) + min;
+ }
+
+ /**
+ * Encapsulates the second term of Jacobian log identity for differences up to MAX_TOLERANCE
+ */
+ private static class JacobianLogTable {
+
+ public static final double MAX_TOLERANCE = 8.0;
+
+ public static double get(final double difference) {
+ if (cache == null)
+ initialize();
+ final int index = fastRound(difference * INV_STEP);
+ return cache[index];
+ }
+
+ private static synchronized void initialize() {
+ if (cache == null) {
+ final int tableSize = (int) (MAX_TOLERANCE / TABLE_STEP) + 1;
+ cache = new double[tableSize];
+ for (int k = 0; k < cache.length; k++)
+ cache[k] = Math.log10(1.0 + Math.pow(10.0, -((double) k) * TABLE_STEP));
+ }
+ }
+
+ private static final double TABLE_STEP = 0.0001;
+ private static final double INV_STEP = 1.0 / TABLE_STEP;
+ private static double[] cache = null;
+ }
+
+ // A fast implementation of the Math.round() method. This method does not perform
+ // under/overflow checking, so this shouldn't be used in the general case (but is fine
+ // if one is already make those checks before calling in to the rounding).
+ public static int fastRound(final double d) {
+ return (d > 0.0) ? (int) (d + 0.5d) : (int) (d - 0.5d);
+ }
+
+ public static double approximateLog10SumLog10(final double[] vals) {
+ return approximateLog10SumLog10(vals, vals.length);
+ }
+
+ /**
+ * Calculate the approximate log10 sum of an array range.
+ * @param vals the input values.
+ * @param fromIndex the first inclusive index in the input array.
+ * @param toIndex index following the last element to sum in the input array (exclusive).
+ * @return the approximate sum.
+ * @throws IllegalArgumentException if {@code vals} is {@code null} or {@code fromIndex} is out of bounds
+ * or if {@code toIndex} is larger than
+ * the length of the input array or {@code fromIndex} is larger than {@code toIndex}.
+ */
+ public static double approximateLog10SumLog10(final double[] vals, final int fromIndex, final int toIndex) {
+ if (fromIndex == toIndex) return Double.NEGATIVE_INFINITY;
+ final int maxElementIndex = MathUtils.maxElementIndex(vals,fromIndex,toIndex);
+ double approxSum = vals[maxElementIndex];
+
+ for (int i = fromIndex; i < toIndex; i++) {
+ final double val;
+ if (i == maxElementIndex || (val = vals[i]) == Double.NEGATIVE_INFINITY)
+ continue;
+ final double diff = approxSum - val;
+ if (diff < JacobianLogTable.MAX_TOLERANCE)
+ approxSum += JacobianLogTable.get(diff);
+ }
+ return approxSum;
+ }
+
+ public static double approximateLog10SumLog10(final double[] vals, final int endIndex) {
+
+ final int maxElementIndex = MathUtils.maxElementIndex(vals, endIndex);
+ double approxSum = vals[maxElementIndex];
+
+ for (int i = 0; i < endIndex; i++) {
+ if (i == maxElementIndex || vals[i] == Double.NEGATIVE_INFINITY)
+ continue;
+
+ final double diff = approxSum - vals[i];
+ if (diff < JacobianLogTable.MAX_TOLERANCE) {
+ // See notes from the 2-inout implementation below
+ approxSum += JacobianLogTable.get(diff);
+ }
+ }
+
+ return approxSum;
+ }
+
+ public static double approximateLog10SumLog10(final double a, final double b, final double c) {
+ return approximateLog10SumLog10(a, approximateLog10SumLog10(b, c));
+ }
+
+ public static double approximateLog10SumLog10(double small, double big) {
+ // make sure small is really the smaller value
+ if (small > big) {
+ final double t = big;
+ big = small;
+ small = t;
+ }
+
+ if (small == Double.NEGATIVE_INFINITY || big == Double.NEGATIVE_INFINITY)
+ return big;
+
+ final double diff = big - small;
+ if (diff >= JacobianLogTable.MAX_TOLERANCE)
+ return big;
+
+ // OK, so |y-x| < tol: we use the following identity then:
+ // we need to compute log10(10^x + 10^y)
+ // By Jacobian logarithm identity, this is equal to
+ // max(x,y) + log10(1+10^-abs(x-y))
+ // we compute the second term as a table lookup with integer quantization
+ // we have pre-stored correction for 0,0.1,0.2,... 10.0
+ return big + JacobianLogTable.get(diff);
+ }
+
+ public static double sum(final double[] values) {
+ double s = 0.0;
+ for (double v : values)
+ s += v;
+ return s;
+ }
+
+ public static long sum(final int[] x) {
+ long total = 0;
+ for (int v : x)
+ total += v;
+ return total;
+ }
+
+ public static int sum(final byte[] x) {
+ int total = 0;
+ for (byte v : x)
+ total += (int)v;
+ return total;
+ }
+
+ public static double percentage(int x, int base) {
+ return (base > 0 ? ((double) x / (double) base) * 100.0 : 0);
+ }
+
+ public static double ratio(final int num, final int denom) {
+ if ( denom > 0 ) {
+ return ((double) num)/denom;
+ } else {
+ if ( num == 0 && denom == 0) {
+ return 0.0;
+ } else {
+ throw new ReviewedGATKException(String.format("The denominator of a ratio cannot be zero or less than zero: %d/%d",num,denom));
+ }
+ }
+ }
+
+ public static double ratio(final long num, final long denom) {
+ if ( denom > 0L ) {
+ return ((double) num)/denom;
+ } else {
+ if ( num == 0L && denom == 0L ) {
+ return 0.0;
+ } else {
+ throw new ReviewedGATKException(String.format("The denominator of a ratio cannot be zero or less than zero: %d/%d",num,denom));
+ }
+ }
+ }
+
+ /**
+ * Converts a real space array of numbers (typically probabilities) into a log10 array
+ *
+ * @param prRealSpace
+ * @return
+ */
+ public static double[] toLog10(final double[] prRealSpace) {
+ double[] log10s = new double[prRealSpace.length];
+ for (int i = 0; i < prRealSpace.length; i++) {
+ log10s[i] = Math.log10(prRealSpace[i]);
+ }
+ return log10s;
+ }
+
+ public static double log10sumLog10(final double[] log10p, final int start) {
+ return log10sumLog10(log10p, start, log10p.length);
+ }
+
+ public static double log10sumLog10(final double[] log10p, final int start, final int finish) {
+
+ if (start >= finish)
+ return Double.NEGATIVE_INFINITY;
+ final int maxElementIndex = MathUtils.maxElementIndex(log10p, start, finish);
+ final double maxValue = log10p[maxElementIndex];
+ if(maxValue == Double.NEGATIVE_INFINITY)
+ return maxValue;
+ double sum = 1.0;
+ for (int i = start; i < finish; i++) {
+ double curVal = log10p[i];
+ double scaled_val = curVal - maxValue;
+ if (i == maxElementIndex || curVal == Double.NEGATIVE_INFINITY) {
+ continue;
+ }
+ else {
+ sum += Math.pow(10.0, scaled_val);
+ }
+ }
+ if ( Double.isNaN(sum) || sum == Double.POSITIVE_INFINITY ) {
+ throw new IllegalArgumentException("log10p: Values must be non-infinite and non-NAN");
+ }
+ return maxValue + (sum != 1.0 ? Math.log10(sum) : 0.0);
+ }
+
+ public static double sumLog10(final double[] log10values) {
+ return Math.pow(10.0, log10sumLog10(log10values));
+ }
+
+ public static double log10sumLog10(final double[] log10values) {
+ return log10sumLog10(log10values, 0);
+ }
+
+ public static boolean wellFormedDouble(final double val) {
+ return !Double.isInfinite(val) && !Double.isNaN(val);
+ }
+
+ public static double bound(final double value, final double minBoundary, final double maxBoundary) {
+ return Math.max(Math.min(value, maxBoundary), minBoundary);
+ }
+
+ public static boolean isBounded(final double val, final double lower, final double upper) {
+ return val >= lower && val <= upper;
+ }
+
+ public static boolean isPositive(final double val) {
+ return !isNegativeOrZero(val);
+ }
+
+ public static boolean isPositiveOrZero(final double val) {
+ return isBounded(val, 0.0, Double.POSITIVE_INFINITY);
+ }
+
+ public static boolean isNegativeOrZero(final double val) {
+ return isBounded(val, Double.NEGATIVE_INFINITY, 0.0);
+ }
+
+ public static boolean isNegative(final double val) {
+ return !isPositiveOrZero(val);
+ }
+
+ /**
+ * Compares double values for equality (within 1e-6), or inequality.
+ *
+ * @param a the first double value
+ * @param b the second double value
+ * @return -1 if a is greater than b, 0 if a is equal to be within 1e-6, 1 if b is greater than a.
+ */
+ public static byte compareDoubles(final double a, final double b) {
+ return compareDoubles(a, b, 1e-6);
+ }
+
+ /**
+ * Compares double values for equality (within epsilon), or inequality.
+ *
+ * @param a the first double value
+ * @param b the second double value
+ * @param epsilon the precision within which two double values will be considered equal
+ * @return -1 if a is greater than b, 0 if a is equal to be within epsilon, 1 if b is greater than a.
+ */
+ public static byte compareDoubles(final double a, final double b, final double epsilon) {
+ if (Math.abs(a - b) < epsilon) {
+ return 0;
+ }
+ if (a > b) {
+ return -1;
+ }
+ return 1;
+ }
+
+ /**
+ * Calculate f(x) = Normal(x | mu = mean, sigma = sd)
+ * @param mean the desired mean of the Normal distribution
+ * @param sd the desired standard deviation of the Normal distribution
+ * @param x the value to evaluate
+ * @return a well-formed double
+ */
+ public static double normalDistribution(final double mean, final double sd, final double x) {
+ if( sd < 0 )
+ throw new IllegalArgumentException("sd: Standard deviation of normal must be >0");
+ if ( ! wellFormedDouble(mean) || ! wellFormedDouble(sd) || ! wellFormedDouble(x) )
+ throw new IllegalArgumentException("mean, sd, or, x : Normal parameters must be well formatted (non-INF, non-NAN)");
+ double a = 1.0 / (sd * Math.sqrt(2.0 * Math.PI));
+ double b = Math.exp(-1.0 * (Math.pow(x - mean, 2.0) / (2.0 * sd * sd)));
+ return a * b;
+ }
+
+ /**
+ * Calculate f(x) = log10 ( Normal(x | mu = mean, sigma = sd) )
+ * @param mean the desired mean of the Normal distribution
+ * @param sd the desired standard deviation of the Normal distribution
+ * @param x the value to evaluate
+ * @return a well-formed double
+ */
+
+ public static double normalDistributionLog10(final double mean, final double sd, final double x) {
+ if( sd < 0 )
+ throw new IllegalArgumentException("sd: Standard deviation of normal must be >0");
+ if ( ! wellFormedDouble(mean) || ! wellFormedDouble(sd) || ! wellFormedDouble(x) )
+ throw new IllegalArgumentException("mean, sd, or, x : Normal parameters must be well formatted (non-INF, non-NAN)");
+ final double a = -1.0 * Math.log10(sd * SQUARE_ROOT_OF_TWO_TIMES_PI);
+ final double b = -1.0 * (square(x - mean) / (2.0 * square(sd))) / NATURAL_LOG_OF_TEN;
+ return a + b;
+ }
+
+ /**
+ * Calculate f(x) = x^2
+ * @param x the value to square
+ * @return x * x
+ */
+ public static double square(final double x) {
+ return x * x;
+ }
+
+ /**
+ * Calculates the log10 of the binomial coefficient. Designed to prevent
+ * overflows even with very large numbers.
+ *
+ * @param n total number of trials
+ * @param k number of successes
+ * @return the log10 of the binomial coefficient
+ */
+ public static double binomialCoefficient(final int n, final int k) {
+ return Math.pow(10, log10BinomialCoefficient(n, k));
+ }
+
+ /**
+ * @see #binomialCoefficient(int, int) with log10 applied to result
+ */
+ public static double log10BinomialCoefficient(final int n, final int k) {
+ if ( n < 0 ) {
+ throw new IllegalArgumentException("n: Must have non-negative number of trials");
+ }
+ if ( k > n || k < 0 ) {
+ throw new IllegalArgumentException("k: Must have non-negative number of successes, and no more successes than number of trials");
+ }
+
+ return log10Factorial(n) - log10Factorial(k) - log10Factorial(n - k);
+ }
+
+ /**
+ * Computes a binomial probability. This is computed using the formula
+ * <p/>
+ * B(k; n; p) = [ n! / ( k! (n - k)! ) ] (p^k)( (1-p)^k )
+ * <p/>
+ * where n is the number of trials, k is the number of successes, and p is the probability of success
+ *
+ * @param n number of Bernoulli trials
+ * @param k number of successes
+ * @param p probability of success
+ * @return the binomial probability of the specified configuration. Computes values down to about 1e-237.
+ */
+ public static double binomialProbability(final int n, final int k, final double p) {
+ return Math.pow(10, log10BinomialProbability(n, k, Math.log10(p)));
+ }
+
+ /**
+ * @see #binomialProbability(int, int, double) with log10 applied to result
+ */
+ public static double log10BinomialProbability(final int n, final int k, final double log10p) {
+ if ( log10p > 1e-18 )
+ throw new IllegalArgumentException("log10p: Log-probability must be 0 or less");
+ double log10OneMinusP = Math.log10(1 - Math.pow(10, log10p));
+ return log10BinomialCoefficient(n, k) + log10p * k + log10OneMinusP * (n - k);
+ }
+
+ /**
+ * @see #binomialProbability(int, int, double) with p=0.5
+ */
+ public static double binomialProbability(final int n, final int k) {
+ return Math.pow(10, log10BinomialProbability(n, k));
+ }
+
+ /**
+ * @see #binomialProbability(int, int, double) with p=0.5 and log10 applied to result
+ */
+ public static double log10BinomialProbability(final int n, final int k) {
+ return log10BinomialCoefficient(n, k) + (n * FAIR_BINOMIAL_PROB_LOG10_0_5);
+ }
+
+ /** A memoization container for {@link #binomialCumulativeProbability(int, int, int)}. Synchronized to accomodate multithreading. */
+ private static final Map<Long, Double> BINOMIAL_CUMULATIVE_PROBABILITY_MEMOIZATION_CACHE =
+ Collections.synchronizedMap(new LRUCache<Long, Double>(10_000));
+
+ /**
+ * Primitive integer-triplet bijection into long. Returns null when the bijection function fails (in lieu of an exception), which will
+ * happen when: any value is negative or larger than a short. This method is optimized for speed; it is not intended to serve as a
+ * utility function.
+ */
+ static Long fastGenerateUniqueHashFromThreeIntegers(final int one, final int two, final int three) {
+ if (one < 0 || two < 0 || three < 0 || Short.MAX_VALUE < one || Short.MAX_VALUE < two || Short.MAX_VALUE < three) {
+ return null;
+ } else {
+ long result = 0;
+ result += (short) one;
+ result <<= 16;
+ result += (short) two;
+ result <<= 16;
+ result += (short) three;
+ return result;
+ }
+ }
+
+ /**
+ * Performs the cumulative sum of binomial probabilities, where the probability calculation is done in log space.
+ * Assumes that the probability of a successful hit is fair (i.e. 0.5).
+ *
+ * This pure function is memoized because of its expensive BigDecimal calculations.
+ *
+ * @param n number of attempts for the number of hits
+ * @param k_start start (inclusive) of the cumulant sum (over hits)
+ * @param k_end end (inclusive) of the cumulant sum (over hits)
+ * @return - returns the cumulative probability
+ */
+ public static double binomialCumulativeProbability(final int n, final int k_start, final int k_end) {
+ if ( k_end > n )
+ throw new IllegalArgumentException(String.format("Value for k_end (%d) is greater than n (%d)", k_end, n));
+
+ // Fetch cached value, if applicable.
+ final Long memoizationKey = fastGenerateUniqueHashFromThreeIntegers(n, k_start, k_end);
+ final Double memoizationCacheResult;
+ if (memoizationKey != null) {
+ memoizationCacheResult = BINOMIAL_CUMULATIVE_PROBABILITY_MEMOIZATION_CACHE.get(memoizationKey);
+ } else {
+ memoizationCacheResult = null;
+ }
+
+ final double result;
+ if (memoizationCacheResult != null) {
+ result = memoizationCacheResult;
+ } else {
+ double cumProb = 0.0;
+ double prevProb;
+ BigDecimal probCache = BigDecimal.ZERO;
+
+ for (int hits = k_start; hits <= k_end; hits++) {
+ prevProb = cumProb;
+ final double probability = binomialProbability(n, hits);
+ cumProb += probability;
+ if (probability > 0 && cumProb - prevProb < probability / 2) { // loss of precision
+ probCache = probCache.add(new BigDecimal(prevProb));
+ cumProb = 0.0;
+ hits--; // repeat loop
+ // prevProb changes at start of loop
+ }
+ }
+
+ result = probCache.add(new BigDecimal(cumProb)).doubleValue();
+ if (memoizationKey != null) {
+ BINOMIAL_CUMULATIVE_PROBABILITY_MEMOIZATION_CACHE.put(memoizationKey, result);
+ }
+ }
+ return result;
+ }
+
+ private static final double LOG1MEXP_THRESHOLD = Math.log(0.5);
+
+ private static final double LN_10 = Math.log(10);
+
+ /**
+ * Calculates {@code log(1-exp(a))} without loosing precision.
+ *
+ * <p>
+ * This is based on the approach described in:
+ *
+ * </p>
+ * <p>
+ * Maechler M, Accurately Computing log(1-exp(-|a|)) Assessed by the Rmpfr package, 2012 <br/>
+ * <a ref="http://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf">Online document</a>.
+ *
+ * </p>
+ *
+ * @param a the input exponent.
+ * @return {@link Double#NaN NaN} if {@code a > 0}, otherwise the corresponding value.
+ */
+ public static double log1mexp(final double a) {
+ if (a > 0) return Double.NaN;
+ if (a == 0) return Double.NEGATIVE_INFINITY;
+
+ return (a < LOG1MEXP_THRESHOLD) ? Math.log1p(-Math.exp(a)) : Math.log(-Math.expm1(a));
+ }
+
+ /**
+ * Calculates {@code log10(1-10^a)} without loosing precision.
+ *
+ * <p>
+ * This is based on the approach described in:
+ *
+ * </p>
+ * <p>
+ * Maechler M, Accurately Computing log(1-exp(-|a|)) Assessed by the Rmpfr package, 2012 <br/>
+ * <a ref="http://cran.r-project.org/web/packages/Rmpfr/vignettes/log1mexp-note.pdf">Online document</a>.
+ * </p>
+ *
+ * @param a the input exponent.
+ * @return {@link Double#NaN NaN} if {@code a > 0}, otherwise the corresponding value.
+ */
+ public static double log10OneMinusPow10(final double a) {
+ if (a > 0) return Double.NaN;
+ if (a == 0) return Double.NEGATIVE_INFINITY;
+ final double b = a * LN_10;
+ return log1mexp(b) / LN_10;
+ }
+
+ /**
+ * Calculates the log10 of the multinomial coefficient. Designed to prevent
+ * overflows even with very large numbers.
+ *
+ * @param n total number of trials
+ * @param k array of any size with the number of successes for each grouping (k1, k2, k3, ..., km)
+ * @return {@link Double#NaN NaN} if {@code a > 0}, otherwise the corresponding value.
+ */
+ public static double log10MultinomialCoefficient(final int n, final int[] k) {
+ if ( n < 0 )
+ throw new IllegalArgumentException("n: Must have non-negative number of trials");
+ double denominator = 0.0;
+ int sum = 0;
+ for (int x : k) {
+ if ( x < 0 )
+ throw new IllegalArgumentException("x element of k: Must have non-negative observations of group");
+ if ( x > n )
+ throw new IllegalArgumentException("x element of k, n: Group observations must be bounded by k");
+ denominator += log10Factorial(x);
+ sum += x;
+ }
+ if ( sum != n )
+ throw new IllegalArgumentException("k and n: Sum of observations in multinomial must sum to total number of trials");
+ return log10Factorial(n) - denominator;
+ }
+
+ /**
+ * Computes the log10 of the multinomial distribution probability given a vector
+ * of log10 probabilities. Designed to prevent overflows even with very large numbers.
+ *
+ * @param n number of trials
+ * @param k array of number of successes for each possibility
+ * @param log10p array of log10 probabilities
+ * @return
+ */
+ public static double log10MultinomialProbability(final int n, final int[] k, final double[] log10p) {
+ if (log10p.length != k.length)
+ throw new IllegalArgumentException("p and k: Array of log10 probabilities must have the same size as the array of number of sucesses: " + log10p.length + ", " + k.length);
+ double log10Prod = 0.0;
+ for (int i = 0; i < log10p.length; i++) {
+ if ( log10p[i] > 1e-18 )
+ throw new IllegalArgumentException("log10p: Log-probability must be <= 0");
+ log10Prod += log10p[i] * k[i];
+ }
+ return log10MultinomialCoefficient(n, k) + log10Prod;
+ }
+
+ /**
+ * Computes a multinomial coefficient efficiently avoiding overflow even for large numbers.
+ * This is computed using the formula:
+ * <p/>
+ * M(x1,x2,...,xk; n) = [ n! / (x1! x2! ... xk!) ]
+ * <p/>
+ * where xi represents the number of times outcome i was observed, n is the number of total observations.
+ * In this implementation, the value of n is inferred as the sum over i of xi.
+ *
+ * @param k an int[] of counts, where each element represents the number of times a certain outcome was observed
+ * @return the multinomial of the specified configuration.
+ */
+ public static double multinomialCoefficient(final int[] k) {
+ int n = 0;
+ for (int xi : k) {
+ n += xi;
+ }
+
+ return Math.pow(10, log10MultinomialCoefficient(n, k));
+ }
+
+ /**
+ * Computes a multinomial probability efficiently avoiding overflow even for large numbers.
+ * This is computed using the formula:
+ * <p/>
+ * M(x1,x2,...,xk; n; p1,p2,...,pk) = [ n! / (x1! x2! ... xk!) ] (p1^x1)(p2^x2)(...)(pk^xk)
+ * <p/>
+ * where xi represents the number of times outcome i was observed, n is the number of total observations, and
+ * pi represents the probability of the i-th outcome to occur. In this implementation, the value of n is
+ * inferred as the sum over i of xi.
+ *
+ * @param k an int[] of counts, where each element represents the number of times a certain outcome was observed
+ * @param p a double[] of probabilities, where each element represents the probability a given outcome can occur
+ * @return the multinomial probability of the specified configuration.
+ */
+ public static double multinomialProbability(final int[] k, final double[] p) {
+ if (p.length != k.length)
+ throw new IllegalArgumentException("p and k: Array of log10 probabilities must have the same size as the array of number of sucesses: " + p.length + ", " + k.length);
+
+ int n = 0;
+ double[] log10P = new double[p.length];
+ for (int i = 0; i < p.length; i++) {
+ log10P[i] = Math.log10(p[i]);
+ n += k[i];
+ }
+ return Math.pow(10, log10MultinomialProbability(n, k, log10P));
+ }
+
+ /**
+ * calculate the Root Mean Square of an array of integers
+ *
+ * @param x an byte[] of numbers
+ * @return the RMS of the specified numbers.
+ */
+ public static double rms(final byte[] x) {
+ if (x.length == 0)
+ return 0.0;
+
+ double rms = 0.0;
+ for (int i : x)
+ rms += i * i;
+ rms /= x.length;
+ return Math.sqrt(rms);
+ }
+
+ /**
+ * calculate the Root Mean Square of an array of integers
+ *
+ * @param x an int[] of numbers
+ * @return the RMS of the specified numbers.
+ */
+ public static double rms(final int[] x) {
+ if (x.length == 0)
+ return 0.0;
+
+ double rms = 0.0;
+ for (int i : x)
+ rms += i * i;
+ rms /= x.length;
+ return Math.sqrt(rms);
+ }
+
+ /**
+ * calculate the Root Mean Square of an array of doubles
+ *
+ * @param x a double[] of numbers
+ * @return the RMS of the specified numbers.
+ */
+ public static double rms(final Double[] x) {
+ if (x.length == 0)
+ return 0.0;
+
+ double rms = 0.0;
+ for (Double i : x)
+ rms += i * i;
+ rms /= x.length;
+ return Math.sqrt(rms);
+ }
+
+ public static double rms(final Collection<Integer> l) {
+ if (l.size() == 0)
+ return 0.0;
+
+ double rms = 0.0;
+ for (int i : l)
+ rms += i * i;
+ rms /= l.size();
+ return Math.sqrt(rms);
+ }
+
+ public static double distanceSquared(final double[] x, final double[] y) {
+ double dist = 0.0;
+ for (int iii = 0; iii < x.length; iii++) {
+ dist += (x[iii] - y[iii]) * (x[iii] - y[iii]);
+ }
+ return dist;
+ }
+
+ public static double round(final double num, final int digits) {
+ double result = num * Math.pow(10.0, (double) digits);
+ result = Math.round(result);
+ result = result / Math.pow(10.0, (double) digits);
+ return result;
+ }
+
+ /**
+ * normalizes the log10-based array. ASSUMES THAT ALL ARRAY ENTRIES ARE <= 0 (<= 1 IN REAL-SPACE).
+ *
+ * @param array the array to be normalized
+ * @param takeLog10OfOutput if true, the output will be transformed back into log10 units
+ * @return a newly allocated array corresponding the normalized values in array, maybe log10 transformed
+ */
+ public static double[] normalizeFromLog10(final double[] array, final boolean takeLog10OfOutput) {
+ return normalizeFromLog10(array, takeLog10OfOutput, false);
+ }
+
+ /**
+ * See #normalizeFromLog10 but with the additional option to use an approximation that keeps the calculation always in log-space
+ *
+ * @param array
+ * @param takeLog10OfOutput
+ * @param keepInLogSpace
+ *
+ * @return
+ */
+ public static double[] normalizeFromLog10(final double[] array, final boolean takeLog10OfOutput, final boolean keepInLogSpace) {
+ // for precision purposes, we need to add (or really subtract, since they're
+ // all negative) the largest value; also, we need to convert to normal-space.
+ double maxValue = arrayMax(array);
+
+ // we may decide to just normalize in log space without converting to linear space
+ if (keepInLogSpace) {
+ for (int i = 0; i < array.length; i++) {
+ array[i] -= maxValue;
+ }
+ return array;
+ }
+
+ // default case: go to linear space
+ double[] normalized = new double[array.length];
+
+ for (int i = 0; i < array.length; i++)
+ normalized[i] = Math.pow(10, array[i] - maxValue);
+
+ // normalize
+ double sum = 0.0;
+ for (int i = 0; i < array.length; i++)
+ sum += normalized[i];
+ for (int i = 0; i < array.length; i++) {
+ double x = normalized[i] / sum;
+ if (takeLog10OfOutput) {
+ x = Math.log10(x);
+ if ( x < LOG10_P_OF_ZERO || Double.isInfinite(x) )
+ x = array[i] - maxValue;
+ }
+
+ normalized[i] = x;
+ }
+
+ return normalized;
+ }
+
+ /**
+ * normalizes the log10-based array. ASSUMES THAT ALL ARRAY ENTRIES ARE <= 0 (<= 1 IN REAL-SPACE).
+ *
+ * @param array the array to be normalized
+ * @return a newly allocated array corresponding the normalized values in array
+ */
+ public static double[] normalizeFromLog10(final double[] array) {
+ return normalizeFromLog10(array, false);
+ }
+
+ /**
+ * normalizes the real-space probability array.
+ *
+ * Does not assume anything about the values in the array, beyond that no elements are below 0. It's ok
+ * to have values in the array of > 1, or have the sum go above 0.
+ *
+ * @param array the array to be normalized
+ * @return a newly allocated array corresponding the normalized values in array
+ */
+ @Requires("array != null")
+ @Ensures({"result != null"})
+ public static double[] normalizeFromRealSpace(final double[] array) {
+ if ( array.length == 0 )
+ return array;
+
+ final double sum = sum(array);
+ final double[] normalized = new double[array.length];
+ if ( sum < 0.0 ) throw new IllegalArgumentException("Values in probability array sum to a negative number " + sum);
+ for ( int i = 0; i < array.length; i++ ) {
+ normalized[i] = array[i] / sum;
+ }
+ return normalized;
+ }
+
+ public static int maxElementIndex(final double[] array) {
+ return maxElementIndex(array, array.length);
+ }
+
+ public static int maxElementIndex(final double[] array, final int start, final int endIndex) {
+ if (array == null || array.length == 0)
+ throw new IllegalArgumentException("Array cannot be null!");
+
+ if (start > endIndex) {
+ throw new IllegalArgumentException("Start cannot be after end.");
+ }
+
+ int maxI = start;
+ for (int i = (start+1); i < endIndex; i++) {
+ if (array[i] > array[maxI])
+ maxI = i;
+ }
+ return maxI;
+ }
+
+ public static int maxElementIndex(final double[] array, final int endIndex) {
+ return maxElementIndex(array, 0, endIndex);
+ }
+
+ public static int maxElementIndex(final int[] array) {
+ return maxElementIndex(array, array.length);
+ }
+
+ public static int maxElementIndex(final byte[] array) {
+ return maxElementIndex(array, array.length);
+ }
+
+ public static int maxElementIndex(final int[] array, final int endIndex) {
+ if (array == null || array.length == 0)
+ throw new IllegalArgumentException("Array cannot be null!");
+
+ int maxI = 0;
+ for (int i = 1; i < endIndex; i++) {
+ if (array[i] > array[maxI])
+ maxI = i;
+ }
+ return maxI;
+ }
+
+ public static int maxElementIndex(final byte[] array, final int endIndex) {
+ if (array == null || array.length == 0)
+ throw new IllegalArgumentException("Array cannot be null!");
+
+ int maxI = 0;
+ for (int i = 1; i < endIndex; i++) {
+ if (array[i] > array[maxI])
+ maxI = i;
+ }
+
+ return maxI;
+ }
+
+ public static int arrayMax(final int[] array) {
+ return array[maxElementIndex(array)];
+ }
+
+
+ public static double arrayMax(final double[] array) {
+ return array[maxElementIndex(array)];
+ }
+
+ public static double arrayMax(final double[] array, final int endIndex) {
+ return array[maxElementIndex(array, endIndex)];
+ }
+
+ public static double arrayMin(final double[] array) {
+ return array[minElementIndex(array)];
+ }
+
+ public static int arrayMin(final int[] array) {
+ return array[minElementIndex(array)];
+ }
+
+ public static byte arrayMin(final byte[] array) {
+ return array[minElementIndex(array)];
+ }
+
+ /**
+ * Compute the min element of a List<Integer>
+ * @param array a non-empty list of integer
+ * @return the min
+ */
+ public static int arrayMin(final List<Integer> array) {
+ if ( array == null || array.isEmpty() ) throw new IllegalArgumentException("Array must be non-null and non-empty");
+ int min = array.get(0);
+ for ( final int i : array )
+ if ( i < min ) min = i;
+ return min;
+ }
+
+ /**
+ * Compute the median element of the list of integers
+ * @param array a list of integers
+ * @return the median element
+ */
+ public static <T extends Comparable<? super T>> T median(final List<T> array) {
+ /* TODO -- from Valentin
+ the current implementation is not the usual median when the input is of even length. More concretely it returns the ith element of the list where i = floor(input.size() / 2).
+
+ But actually that is not the "usual" definition of a median, as it is supposed to return the average of the two middle values when the sample length is an even number (i.e. median(1,2,3,4,5,6) == 3.5). [Sources: R and wikipedia]
+
+ My suggestion for a solution is then:
+
+ unify median and medianDoubles to public static <T extends Number> T median(Collection<T>)
+ check on null elements and throw an exception if there are any or perhaps return a null; documented in the javadoc.
+ relocate, rename and refactor MathUtils.median(X) to Utils.ithElement(X,X.size()/2)
+ In addition, the current median implementation sorts the whole input list witch is O(n log n). However find out the ith element (thus calculate the median) can be done in O(n)
+ */
+ if ( array == null ) throw new IllegalArgumentException("Array must be non-null");
+ final int size = array.size();
+ if ( size == 0 ) throw new IllegalArgumentException("Array cannot have size 0");
+ else if ( size == 1 ) return array.get(0);
+ else {
+ final ArrayList<T> sorted = new ArrayList<>(array);
+ Collections.sort(sorted);
+ return sorted.get(size / 2);
+ }
+ }
+
+ public static int minElementIndex(final double[] array) {
+ if (array == null || array.length == 0)
+ throw new IllegalArgumentException("Array cannot be null!");
+
+ int minI = 0;
+ for (int i = 1; i < array.length; i++) {
+ if (array[i] < array[minI])
+ minI = i;
+ }
+
+ return minI;
+ }
+
+ public static int minElementIndex(final byte[] array) {
+ if (array == null || array.length == 0)
+ throw new IllegalArgumentException("Array cannot be null!");
+
+ int minI = 0;
+ for (int i = 1; i < array.length; i++) {
+ if (array[i] < array[minI])
+ minI = i;
+ }
+
+ return minI;
+ }
+
+ public static int minElementIndex(final int[] array) {
+ if (array == null || array.length == 0)
+ throw new IllegalArgumentException("Array cannot be null!");
+
+ int minI = 0;
+ for (int i = 1; i < array.length; i++) {
+ if (array[i] < array[minI])
+ minI = i;
+ }
+
+ return minI;
+ }
+
+ public static int arrayMaxInt(final List<Integer> array) {
+ if (array == null)
+ throw new IllegalArgumentException("Array cannot be null!");
+ if (array.size() == 0)
+ throw new IllegalArgumentException("Array size cannot be 0!");
+
+ int m = array.get(0);
+ for (int e : array)
+ m = Math.max(m, e);
+ return m;
+ }
+
+ public static int sum(final List<Integer> list ) {
+ int sum = 0;
+ for ( Integer i : list ) {
+ sum += i;
+ }
+ return sum;
+ }
+
+ public static double average(final List<Long> vals, final int maxI) {
+ long sum = 0L;
+
+ int i = 0;
+ for (long x : vals) {
+ if (i > maxI)
+ break;
+ sum += x;
+ i++;
+ }
+
+ return (1.0 * sum) / i;
+ }
+
+ public static double average(final List<Long> vals) {
+ return average(vals, vals.size());
+ }
+
+ public static int countOccurrences(final char c, final String s) {
+ int count = 0;
+ for (int i = 0; i < s.length(); i++) {
+ count += s.charAt(i) == c ? 1 : 0;
+ }
+ return count;
+ }
+
+ public static <T> int countOccurrences(T x, List<T> l) {
+ int count = 0;
+ for (T y : l) {
+ if (x.equals(y))
+ count++;
+ }
+
+ return count;
+ }
+
+ public static int countOccurrences(byte element, byte[] array) {
+ int count = 0;
+ for (byte y : array) {
+ if (element == y)
+ count++;
+ }
+
+ return count;
+ }
+
+ public static int countOccurrences(final boolean element, final boolean[] array) {
+ int count = 0;
+ for (final boolean b : array) {
+ if (element == b)
+ count++;
+ }
+
+ return count;
+ }
+
+
+ /**
+ * Returns n random indices drawn with replacement from the range 0..(k-1)
+ *
+ * @param n the total number of indices sampled from
+ * @param k the number of random indices to draw (with replacement)
+ * @return a list of k random indices ranging from 0 to (n-1) with possible duplicates
+ */
+ static public ArrayList<Integer> sampleIndicesWithReplacement(final int n, final int k) {
+
+ ArrayList<Integer> chosen_balls = new ArrayList<Integer>(k);
+ for (int i = 0; i < k; i++) {
+ //Integer chosen_ball = balls[rand.nextInt(k)];
+ chosen_balls.add(GenomeAnalysisEngine.getRandomGenerator().nextInt(n));
+ //balls.remove(chosen_ball);
+ }
+
+ return chosen_balls;
+ }
+
+ /**
+ * Returns n random indices drawn without replacement from the range 0..(k-1)
+ *
+ * @param n the total number of indices sampled from
+ * @param k the number of random indices to draw (without replacement)
+ * @return a list of k random indices ranging from 0 to (n-1) without duplicates
+ */
+ static public ArrayList<Integer> sampleIndicesWithoutReplacement(final int n, final int k) {
+ ArrayList<Integer> chosen_balls = new ArrayList<Integer>(k);
+
+ for (int i = 0; i < n; i++) {
+ chosen_balls.add(i);
+ }
+
+ Collections.shuffle(chosen_balls, GenomeAnalysisEngine.getRandomGenerator());
+
+ //return (ArrayList<Integer>) chosen_balls.subList(0, k);
+ return new ArrayList<Integer>(chosen_balls.subList(0, k));
+ }
+
+ /**
+ * Given a list of indices into a list, return those elements of the list with the possibility of drawing list elements multiple times
+ *
+ * @param indices the list of indices for elements to extract
+ * @param list the list from which the elements should be extracted
+ * @param <T> the template type of the ArrayList
+ * @return a new ArrayList consisting of the elements at the specified indices
+ */
+ static public <T> ArrayList<T> sliceListByIndices(final List<Integer> indices, final List<T> list) {
+ ArrayList<T> subset = new ArrayList<T>();
+
+ for (int i : indices) {
+ subset.add(list.get(i));
+ }
+
+ return subset;
+ }
+
+ /**
+ * Given two log-probability vectors, compute log of vector product of them:
+ * in Matlab notation, return log10(10.*x'*10.^y)
+ * @param x vector 1
+ * @param y vector 2
+ * @return a double representing log (dotProd(10.^x,10.^y)
+ */
+ public static double logDotProduct(final double [] x, final double[] y) {
+ if (x.length != y.length)
+ throw new ReviewedGATKException("BUG: Vectors of different lengths");
+
+ double tmpVec[] = new double[x.length];
+
+ for (int k=0; k < tmpVec.length; k++ ) {
+ tmpVec[k] = x[k]+y[k];
+ }
+
+ return log10sumLog10(tmpVec);
+
+
+
+ }
+
+ /**
+ * Check that the log10 prob vector vector is well formed
+ *
+ * @param vector
+ * @param expectedSize
+ * @param shouldSumToOne
+ *
+ * @return true if vector is well-formed, false otherwise
+ */
+ public static boolean goodLog10ProbVector(final double[] vector, final int expectedSize, final boolean shouldSumToOne) {
+ if ( vector.length != expectedSize ) return false;
+
+ for ( final double pr : vector ) {
+ if ( ! goodLog10Probability(pr) )
+ return false;
+ }
+
+ if ( shouldSumToOne && compareDoubles(sumLog10(vector), 1.0, 1e-4) != 0 )
+ return false;
+
+ return true; // everything is good
+ }
+
+ /**
+ * Checks that the result is a well-formed log10 probability
+ *
+ * @param result a supposedly well-formed log10 probability value. By default allows
+ * -Infinity values, as log10(0.0) == -Infinity.
+ * @return true if result is really well formed
+ */
+ public static boolean goodLog10Probability(final double result) {
+ return goodLog10Probability(result, true);
+ }
+
+ /**
+ * Checks that the result is a well-formed log10 probability
+ *
+ * @param result a supposedly well-formed log10 probability value
+ * @param allowNegativeInfinity should we consider a -Infinity value ok?
+ * @return true if result is really well formed
+ */
+ public static boolean goodLog10Probability(final double result, final boolean allowNegativeInfinity) {
+ return result <= 0.0 && result != Double.POSITIVE_INFINITY && (allowNegativeInfinity || result != Double.NEGATIVE_INFINITY) && ! Double.isNaN(result);
+ }
+
+ /**
+ * Checks that the result is a well-formed probability
+ *
+ * @param result a supposedly well-formed probability value
+ * @return true if result is really well formed
+ */
+ public static boolean goodProbability(final double result) {
+ return result >= 0.0 && result <= 1.0 && ! Double.isInfinite(result) && ! Double.isNaN(result);
+ }
+
+ /**
+ * A utility class that computes on the fly average and standard deviation for a stream of numbers.
+ * The number of observations does not have to be known in advance, and can be also very big (so that
+ * it could overflow any naive summation-based scheme or cause loss of precision).
+ * Instead, adding a new number <code>observed</code>
+ * to a sample with <code>add(observed)</code> immediately updates the instance of this object so that
+ * it contains correct mean and standard deviation for all the numbers seen so far. Source: Knuth, vol.2
+ * (see also e.g. http://www.johndcook.com/standard_deviation.html for online reference).
+ */
+ public static class RunningAverage {
+ private double mean = 0.0;
+ private double s = 0.0;
+ private long obs_count = 0;
+
+ public void add(double obs) {
+ obs_count++;
+ double oldMean = mean;
+ mean += (obs - mean) / obs_count; // update mean
+ s += (obs - oldMean) * (obs - mean);
+ }
+
+ public void addAll(Collection<Number> col) {
+ for (Number o : col) {
+ add(o.doubleValue());
+ }
+ }
+
+ public double mean() {
+ return mean;
+ }
+
+ public double stddev() {
+ return Math.sqrt(s / (obs_count - 1));
+ }
+
+ public double var() {
+ return s / (obs_count - 1);
+ }
+
+ public long observationCount() {
+ return obs_count;
+ }
+
+ public RunningAverage clone() {
+ RunningAverage ra = new RunningAverage();
+ ra.mean = this.mean;
+ ra.s = this.s;
+ ra.obs_count = this.obs_count;
+ return ra;
+ }
+
+ public void merge(RunningAverage other) {
+ if (this.obs_count > 0 || other.obs_count > 0) { // if we have any observations at all
+ this.mean = (this.mean * this.obs_count + other.mean * other.obs_count) / (this.obs_count + other.obs_count);
+ this.s += other.s;
+ }
+ this.obs_count += other.obs_count;
+ }
+ }
+
+ //
+ // useful common utility routines
+ //
+
+ static public double max(double x0, double x1, double x2) {
+ double a = Math.max(x0, x1);
+ return Math.max(a, x2);
+ }
+
+ /**
+ * Converts LN to LOG10
+ *
+ * @param ln log(x)
+ * @return log10(x)
+ */
+ public static double lnToLog10(final double ln) {
+ return ln * Math.log10(Math.E);
+ }
+
+ /**
+ * Constants to simplify the log gamma function calculation.
+ */
+ private static final double zero = 0.0, one = 1.0, half = .5, a0 = 7.72156649015328655494e-02, a1 = 3.22467033424113591611e-01, a2 = 6.73523010531292681824e-02, a3 = 2.05808084325167332806e-02, a4 = 7.38555086081402883957e-03, a5 = 2.89051383673415629091e-03, a6 = 1.19270763183362067845e-03, a7 = 5.10069792153511336608e-04, a8 = 2.20862790713908385557e-04, a9 = 1.08011567247583939954e-04, a10 = 2.52144565451257326939e-05, a11 = 4.48640949618915160150e-05, tc = 1.46163214496836224576e [...]
+
+ /**
+ * Efficient rounding functions to simplify the log gamma function calculation
+ * double to long with 32 bit shift
+ */
+ private static final int HI(final double x) {
+ return (int) (Double.doubleToLongBits(x) >> 32);
+ }
+
+ /**
+ * Efficient rounding functions to simplify the log gamma function calculation
+ * double to long without shift
+ */
+ private static final int LO(final double x) {
+ return (int) Double.doubleToLongBits(x);
+ }
+
+ /**
+ * Most efficent implementation of the lnGamma (FDLIBM)
+ * Use via the log10Gamma wrapper method.
+ */
+ private static double lnGamma(final double x) {
+ double t, y, z, p, p1, p2, p3, q, r, w;
+ int i;
+
+ int hx = HI(x);
+ int lx = LO(x);
+
+ /* purge off +-inf, NaN, +-0, and negative arguments */
+ int ix = hx & 0x7fffffff;
+ if (ix >= 0x7ff00000)
+ return Double.POSITIVE_INFINITY;
+ if ((ix | lx) == 0 || hx < 0)
+ return Double.NaN;
+ if (ix < 0x3b900000) { /* |x|<2**-70, return -log(|x|) */
+ return -Math.log(x);
+ }
+
+ /* purge off 1 and 2 */
+ if ((((ix - 0x3ff00000) | lx) == 0) || (((ix - 0x40000000) | lx) == 0))
+ r = 0;
+ /* for x < 2.0 */
+ else if (ix < 0x40000000) {
+ if (ix <= 0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */
+ r = -Math.log(x);
+ if (ix >= 0x3FE76944) {
+ y = one - x;
+ i = 0;
+ }
+ else if (ix >= 0x3FCDA661) {
+ y = x - (tc - one);
+ i = 1;
+ }
+ else {
+ y = x;
+ i = 2;
+ }
+ }
+ else {
+ r = zero;
+ if (ix >= 0x3FFBB4C3) {
+ y = 2.0 - x;
+ i = 0;
+ } /* [1.7316,2] */
+ else if (ix >= 0x3FF3B4C4) {
+ y = x - tc;
+ i = 1;
+ } /* [1.23,1.73] */
+ else {
+ y = x - one;
+ i = 2;
+ }
+ }
+
+ switch (i) {
+ case 0:
+ z = y * y;
+ p1 = a0 + z * (a2 + z * (a4 + z * (a6 + z * (a8 + z * a10))));
+ p2 = z * (a1 + z * (a3 + z * (a5 + z * (a7 + z * (a9 + z * a11)))));
+ p = y * p1 + p2;
+ r += (p - 0.5 * y);
+ break;
+ case 1:
+ z = y * y;
+ w = z * y;
+ p1 = t0 + w * (t3 + w * (t6 + w * (t9 + w * t12))); /* parallel comp */
+ p2 = t1 + w * (t4 + w * (t7 + w * (t10 + w * t13)));
+ p3 = t2 + w * (t5 + w * (t8 + w * (t11 + w * t14)));
+ p = z * p1 - (tt - w * (p2 + y * p3));
+ r += (tf + p);
+ break;
+ case 2:
+ p1 = y * (u0 + y * (u1 + y * (u2 + y * (u3 + y * (u4 + y * u5)))));
+ p2 = one + y * (v1 + y * (v2 + y * (v3 + y * (v4 + y * v5))));
+ r += (-0.5 * y + p1 / p2);
+ }
+ }
+ else if (ix < 0x40200000) { /* x < 8.0 */
+ i = (int) x;
+ t = zero;
+ y = x - (double) i;
+ p = y * (s0 + y * (s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6))))));
+ q = one + y * (r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * r6)))));
+ r = half * y + p / q;
+ z = one; /* lgamma(1+s) = log(s) + lgamma(s) */
+ switch (i) {
+ case 7:
+ z *= (y + 6.0); /* FALLTHRU */
+ case 6:
+ z *= (y + 5.0); /* FALLTHRU */
+ case 5:
+ z *= (y + 4.0); /* FALLTHRU */
+ case 4:
+ z *= (y + 3.0); /* FALLTHRU */
+ case 3:
+ z *= (y + 2.0); /* FALLTHRU */
+ r += Math.log(z);
+ break;
+ }
+ /* 8.0 <= x < 2**58 */
+ }
+ else if (ix < 0x43900000) {
+ t = Math.log(x);
+ z = one / x;
+ y = z * z;
+ w = w0 + z * (w1 + y * (w2 + y * (w3 + y * (w4 + y * (w5 + y * w6)))));
+ r = (x - half) * (t - one) + w;
+ }
+ else
+ /* 2**58 <= x <= inf */
+ r = x * (Math.log(x) - one);
+ return r;
+ }
+
+ /**
+ * Calculates the log10 of the gamma function for x using the efficient FDLIBM
+ * implementation to avoid overflows and guarantees high accuracy even for large
+ * numbers.
+ *
+ * @param x the x parameter
+ * @return the log10 of the gamma function at x.
+ */
+ public static double log10Gamma(final double x) {
+ return lnToLog10(lnGamma(x));
+ }
+
+ public static double factorial(final int x) {
+ // avoid rounding errors caused by fact that 10^log(x) might be slightly lower than x and flooring may produce 1 less than real value
+ return (double)Math.round(Math.pow(10, log10Factorial(x)));
+ }
+
+ public static double log10Factorial(final int x) {
+ if (x >= Log10FactorialCache.size() || x < 0)
+ return log10Gamma(x + 1);
+ else
+ return Log10FactorialCache.get(x);
+ }
+
+ /**
+ * Wrapper class so that the log10Factorial array is only calculated if it's used
+ */
+ private static class Log10FactorialCache {
+
+ /**
+ * The size of the precomputed cache. Must be a positive number!
+ */
+ private static final int CACHE_SIZE = 10_000;
+
+ public static int size() { return CACHE_SIZE; }
+
+ public static double get(final int n) {
+ if (cache == null)
+ initialize();
+ return cache[n];
+ }
+
+ private static synchronized void initialize() {
+ if (cache == null) {
+ Log10Cache.ensureCacheContains(CACHE_SIZE);
+ cache = new double[CACHE_SIZE];
+ cache[0] = 0.0;
+ for (int k = 1; k < cache.length; k++)
+ cache[k] = cache[k-1] + Log10Cache.get(k);
+ }
+ }
+
+ private static double[] cache = null;
+ }
+
+ /**
+ * Adds two arrays together and returns a new array with the sum.
+ *
+ * @param a one array
+ * @param b another array
+ * @return a new array with the sum of a and b
+ */
+ @Requires("a.length == b.length")
+ @Ensures("result.length == a.length")
+ public static int[] addArrays(final int[] a, final int[] b) {
+ int[] c = new int[a.length];
+ for (int i = 0; i < a.length; i++)
+ c[i] = a[i] + b[i];
+ return c;
+ }
+
+ /** Same routine, unboxed types for efficiency
+ *
+ * @param x First vector
+ * @param y Second vector
+ * @return Vector of same length as x and y so that z[k] = x[k]+y[k]
+ */
+ public static double[] vectorSum(final double[]x, final double[] y) {
+ if (x.length != y.length)
+ throw new ReviewedGATKException("BUG: Lengths of x and y must be the same");
+
+ double[] result = new double[x.length];
+ for (int k=0; k <x.length; k++)
+ result[k] = x[k]+y[k];
+
+ return result;
+ }
+
+ /** Compute Z=X-Y for two numeric vectors X and Y
+ *
+ * @param x First vector
+ * @param y Second vector
+ * @return Vector of same length as x and y so that z[k] = x[k]-y[k]
+ */
+ public static int[] vectorDiff(final int[]x, final int[] y) {
+ if (x.length != y.length)
+ throw new ReviewedGATKException("BUG: Lengths of x and y must be the same");
+
+ int[] result = new int[x.length];
+ for (int k=0; k <x.length; k++)
+ result[k] = x[k]-y[k];
+
+ return result;
+ }
+
+ /**
+ * Returns a series of integer values between start and stop, inclusive,
+ * expontentially distributed between the two. That is, if there are
+ * ten values between 0-10 there will be 10 between 10-100.
+ *
+ * WARNING -- BADLY TESTED
+ * @param start
+ * @param stop
+ * @param eps
+ * @return
+ */
+ public static List<Integer> log10LinearRange(final int start, final int stop, final double eps) {
+ final LinkedList<Integer> values = new LinkedList<>();
+ final double log10range = Math.log10(stop - start);
+
+ if ( start == 0 )
+ values.add(0);
+
+ double i = 0.0;
+ while ( i <= log10range ) {
+ final int index = (int)Math.round(Math.pow(10, i)) + start;
+ if ( index < stop && (values.peekLast() == null || values.peekLast() != index ) )
+ values.add(index);
+ i += eps;
+ }
+
+ if ( values.peekLast() == null || values.peekLast() != stop )
+ values.add(stop);
+
+ return values;
+ }
+
+ /**
+ * Compute in a numerical correct way the quantity log10(1-x)
+ *
+ * Uses the approximation log10(1-x) = log10(1/x - 1) + log10(x) to avoid very quick underflow
+ * in 1-x when x is very small
+ *
+ * @param x a positive double value between 0.0 and 1.0
+ * @return an estimate of log10(1-x)
+ */
+ @Requires("x >= 0.0 && x <= 1.0")
+ @Ensures("result <= 0.0")
+ public static double log10OneMinusX(final double x) {
+ if ( x == 1.0 )
+ return Double.NEGATIVE_INFINITY;
+ else if ( x == 0.0 )
+ return 0.0;
+ else {
+ final double d = Math.log10(1 / x - 1) + Math.log10(x);
+ return Double.isInfinite(d) || d > 0.0 ? 0.0 : d;
+ }
+ }
+
+ /**
+ * Draw N random elements from list
+ * @param list - the list from which to draw randomly
+ * @param N - the number of elements to draw
+ */
+ public static <T> List<T> randomSubset(final List<T> list, final int N) {
+ if (list.size() <= N) {
+ return list;
+ }
+
+ return sliceListByIndices(sampleIndicesWithoutReplacement(list.size(),N),list);
+ }
+
+ /**
+ * Draw N random elements from list with replacement
+ * @param list - the list from which to draw randomly
+ * @param N - the number of elements to draw
+ */
+ public static <T> List<T> randomSample(final List<T> list, final int N) {
+ if (list.isEmpty() ) {
+ return list;
+ }
+ return sliceListByIndices(sampleIndicesWithReplacement(list.size(),N),list);
+ }
+
+ /**
+ * Return the likelihood of observing the counts of categories having sampled a population
+ * whose categorial frequencies are distributed according to a Dirichlet distribution
+ * @param dirichletParams - params of the prior dirichlet distribution
+ * @param dirichletSum - the sum of those parameters
+ * @param counts - the counts of observation in each category
+ * @param countSum - the sum of counts (number of trials)
+ * @return - associated likelihood
+ */
+ public static double dirichletMultinomial(final double[] dirichletParams, final double dirichletSum,
+ final int[] counts, final int countSum) {
+ if ( dirichletParams.length != counts.length ) {
+ throw new IllegalStateException("The number of dirichlet parameters must match the number of categories");
+ }
+ // todo -- lots of lnGammas here. At some point we can safely switch to x * ( ln(x) - 1)
+ double likelihood = log10MultinomialCoefficient(countSum,counts);
+ likelihood += log10Gamma(dirichletSum);
+ likelihood -= log10Gamma(dirichletSum+countSum);
+ for ( int idx = 0; idx < counts.length; idx++ ) {
+ likelihood += log10Gamma(counts[idx] + dirichletParams[idx]);
+ likelihood -= log10Gamma(dirichletParams[idx]);
+ }
+
+ return likelihood;
+ }
+
+ public static double dirichletMultinomial(double[] params, int[] counts) {
+ return dirichletMultinomial(params,sum(params),counts,(int) sum(counts));
+ }
+
+ public static ExponentialDistribution exponentialDistribution( final double mean ) {
+ return new ExponentialDistributionImpl(mean);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/Median.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/Median.java
new file mode 100644
index 0000000..40e41f2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/Median.java
@@ -0,0 +1,94 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import java.util.*;
+
+/**
+ * Utility class for calculating median from a data set, potentially limiting the size of data to a
+ * fixed amount
+ *
+ * @author Your Name
+ * @since Date created
+ */
+public class Median<T extends Comparable> {
+ final List<T> values;
+ final int maxValuesToKeep;
+ boolean sorted = false;
+
+ public Median() {
+ this(Integer.MAX_VALUE);
+ }
+
+ public Median(final int maxValuesToKeep) {
+ this.maxValuesToKeep = maxValuesToKeep;
+ this.values = new ArrayList<T>();
+ }
+
+ public boolean isFull() {
+ return values.size() >= maxValuesToKeep;
+ }
+
+ public int size() {
+ return values.size();
+ }
+
+ public boolean isEmpty() {
+ return values.isEmpty();
+ }
+
+ public T getMedian() {
+ if ( isEmpty() )
+ throw new IllegalStateException("Cannot get median value from empty array");
+ return getMedian(null); // note that value null will never be used
+ }
+
+ /**
+ * Returns the floor(n + 1 / 2) item from the list of values if the list
+ * has values, or defaultValue is the list is empty.
+ */
+ public T getMedian(final T defaultValue) {
+ if ( isEmpty() )
+ return defaultValue;
+
+ if ( ! sorted ) {
+ sorted = true;
+ Collections.sort(values);
+ }
+
+ final int offset = (int)Math.floor((values.size() + 1) * 0.5) - 1;
+ return values.get(offset);
+ }
+
+ public boolean add(final T value) {
+ if ( ! isFull() ) {
+ sorted = false;
+ return values.add(value);
+ }
+ else
+ return false;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MendelianViolation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MendelianViolation.java
new file mode 100644
index 0000000..75666a7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MendelianViolation.java
@@ -0,0 +1,460 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.broadinstitute.gatk.engine.samples.Sample;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.GenotypeType;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.util.*;
+
+/**
+ * User: carneiro / lfran
+ * Date: 3/9/11
+ * Time: 12:38 PM
+ *
+ * Class for the identification and tracking of mendelian violation. It can be used in 2 distinct ways:
+ * - Either using an instance of the MendelianViolation class to track mendelian violations for each of the families while
+ * walking over the variants
+ * - Or using the static methods to directly get information about mendelian violation in a family at a given locus
+ *
+ */
+public class MendelianViolation {
+ //List of families with violations
+ private List<String> violationFamilies;
+
+ //Call information
+ private int nocall = 0;
+ private int familyCalled = 0;
+ private int varFamilyCalled = 0;
+ private int lowQual = 0;
+
+ private boolean allCalledOnly = true;
+
+ //Stores occurrences of inheritance
+ private EnumMap<GenotypeType, EnumMap<GenotypeType,EnumMap<GenotypeType,Integer>>> inheritance;
+
+ private int violations_total=0;
+
+ private double minGenotypeQuality;
+
+ private boolean abortOnSampleNotFound;
+
+ //Number of families with genotype information for all members
+ public int getFamilyCalledCount(){
+ return familyCalled;
+ }
+
+ //Number of families with genotype information for all members
+ public int getVarFamilyCalledCount(){
+ return varFamilyCalled;
+ }
+
+ //Number of families missing genotypes for one or more of their members
+ public int getFamilyNoCallCount(){
+ return nocall;
+ }
+
+ //Number of families with genotypes below the set quality threshold
+ public int getFamilyLowQualsCount(){
+ return lowQual;
+ }
+
+ public int getViolationsCount(){
+ return violations_total;
+ }
+
+ //Count of alt alleles inherited from het parents (no violation)
+ public int getParentHetInheritedVar(){
+ return getParentsHetHetInheritedVar() + getParentsRefHetInheritedVar() + getParentsVarHetInheritedVar();
+ }
+
+ //Count of ref alleles inherited from het parents (no violation)
+ public int getParentHetInheritedRef(){
+ return getParentsHetHetInheritedRef() + getParentsRefHetInheritedRef() + getParentsVarHetInheritedRef();
+ }
+
+ //Count of HomRef/HomRef/HomRef trios
+ public int getRefRefRef(){
+ return inheritance.get(GenotypeType.HOM_REF).get(GenotypeType.HOM_REF).get(GenotypeType.HOM_REF);
+ }
+
+ //Count of HomVar/HomVar/HomVar trios
+ public int getVarVarVar(){
+ return inheritance.get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_VAR);
+ }
+
+ //Count of HomRef/HomVar/Het trios
+ public int getRefVarHet(){
+ return inheritance.get(GenotypeType.HOM_REF).get(GenotypeType.HOM_VAR).get(GenotypeType.HET) +
+ inheritance.get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_REF).get(GenotypeType.HET);
+ }
+
+ //Count of Het/Het/Het trios
+ public int getHetHetHet(){
+ return inheritance.get(GenotypeType.HET).get(GenotypeType.HET).get(GenotypeType.HET);
+ }
+
+ //Count of Het/Het/HomRef trios
+ public int getHetHetHomRef(){
+ return inheritance.get(GenotypeType.HET).get(GenotypeType.HET).get(GenotypeType.HOM_REF);
+ }
+
+ //Count of Het/Het/HomVar trios
+ public int getHetHetHomVar(){
+ return inheritance.get(GenotypeType.HET).get(GenotypeType.HET).get(GenotypeType.HOM_VAR);
+ }
+
+ //Count of ref alleles inherited from Het/Het parents (no violation)
+ public int getParentsHetHetInheritedRef(){
+ return inheritance.get(GenotypeType.HET).get(GenotypeType.HET).get(GenotypeType.HET)
+ + 2*inheritance.get(GenotypeType.HET).get(GenotypeType.HET).get(GenotypeType.HOM_REF);
+ //return parentsHetHet_childRef;
+ }
+
+ //Count of var alleles inherited from Het/Het parents (no violation)
+ public int getParentsHetHetInheritedVar(){
+ return inheritance.get(GenotypeType.HET).get(GenotypeType.HET).get(GenotypeType.HET)
+ + 2*inheritance.get(GenotypeType.HET).get(GenotypeType.HET).get(GenotypeType.HOM_VAR);
+ //return parentsHetHet_childVar;
+ }
+
+ //Count of ref alleles inherited from HomRef/Het parents (no violation)
+ public int getParentsRefHetInheritedRef(){
+ return inheritance.get(GenotypeType.HOM_REF).get(GenotypeType.HET).get(GenotypeType.HOM_REF)
+ + inheritance.get(GenotypeType.HET).get(GenotypeType.HOM_REF).get(GenotypeType.HOM_REF);
+ //return parentsHomRefHet_childRef;
+ }
+
+ //Count of var alleles inherited from HomRef/Het parents (no violation)
+ public int getParentsRefHetInheritedVar(){
+ return inheritance.get(GenotypeType.HOM_REF).get(GenotypeType.HET).get(GenotypeType.HET)
+ + inheritance.get(GenotypeType.HET).get(GenotypeType.HOM_REF).get(GenotypeType.HET);
+ //return parentsHomRefHet_childVar;
+ }
+
+ //Count of ref alleles inherited from HomVar/Het parents (no violation)
+ public int getParentsVarHetInheritedRef(){
+ return inheritance.get(GenotypeType.HOM_VAR).get(GenotypeType.HET).get(GenotypeType.HET)
+ + inheritance.get(GenotypeType.HET).get(GenotypeType.HOM_VAR).get(GenotypeType.HET);
+ //return parentsHomVarHet_childRef;
+ }
+
+ //Count of var alleles inherited from HomVar/Het parents (no violation)
+ public int getParentsVarHetInheritedVar(){
+ return inheritance.get(GenotypeType.HOM_VAR).get(GenotypeType.HET).get(GenotypeType.HOM_VAR)
+ + inheritance.get(GenotypeType.HET).get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_VAR);
+ //return parentsHomVarHet_childVar;
+ }
+
+ //Count of violations of the type HOM_REF/HOM_REF -> HOM_VAR
+ public int getParentsRefRefChildVar(){
+ return inheritance.get(GenotypeType.HOM_REF).get(GenotypeType.HOM_REF).get(GenotypeType.HOM_VAR);
+ }
+
+ //Count of violations of the type HOM_REF/HOM_REF -> HET
+ public int getParentsRefRefChildHet(){
+ return inheritance.get(GenotypeType.HOM_REF).get(GenotypeType.HOM_REF).get(GenotypeType.HET);
+ }
+
+ //Count of violations of the type HOM_REF/HET -> HOM_VAR
+ public int getParentsRefHetChildVar(){
+ return inheritance.get(GenotypeType.HOM_REF).get(GenotypeType.HET).get(GenotypeType.HOM_VAR)
+ + inheritance.get(GenotypeType.HET).get(GenotypeType.HOM_REF).get(GenotypeType.HOM_VAR);
+ }
+
+ //Count of violations of the type HOM_REF/HOM_VAR -> HOM_VAR
+ public int getParentsRefVarChildVar(){
+ return inheritance.get(GenotypeType.HOM_REF).get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_VAR)
+ + inheritance.get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_REF).get(GenotypeType.HOM_VAR);
+ }
+
+ //Count of violations of the type HOM_REF/HOM_VAR -> HOM_REF
+ public int getParentsRefVarChildRef(){
+ return inheritance.get(GenotypeType.HOM_REF).get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_REF)
+ + inheritance.get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_REF).get(GenotypeType.HOM_REF);
+ }
+
+ //Count of violations of the type HOM_VAR/HET -> HOM_REF
+ public int getParentsVarHetChildRef(){
+ return inheritance.get(GenotypeType.HET).get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_REF)
+ + inheritance.get(GenotypeType.HOM_VAR).get(GenotypeType.HET).get(GenotypeType.HOM_REF);
+ }
+
+ //Count of violations of the type HOM_VAR/HOM_VAR -> HOM_REF
+ public int getParentsVarVarChildRef(){
+ return inheritance.get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_REF);
+ }
+
+ //Count of violations of the type HOM_VAR/HOM_VAR -> HET
+ public int getParentsVarVarChildHet(){
+ return inheritance.get(GenotypeType.HOM_VAR).get(GenotypeType.HOM_VAR).get(GenotypeType.HET);
+ }
+
+
+ //Count of violations of the type HOM_VAR/? -> HOM_REF
+ public int getParentVarChildRef(){
+ return getParentsRefVarChildRef() + getParentsVarHetChildRef() +getParentsVarVarChildRef();
+ }
+
+ //Count of violations of the type HOM_REF/? -> HOM_VAR
+ public int getParentRefChildVar(){
+ return getParentsRefVarChildVar() + getParentsRefHetChildVar() +getParentsRefRefChildVar();
+ }
+
+ //Returns a String containing all trios where a Mendelian violation was observed.
+ //The String is formatted "mom1+dad1=child1,mom2+dad2=child2,..."
+ public String getViolationFamiliesString(){
+ if(violationFamilies.isEmpty())
+ return "";
+
+ Iterator<String> it = violationFamilies.iterator();
+ String violationFams = it.next();
+ while(it.hasNext()){
+ violationFams += ","+it.next();
+ }
+ return violationFams;
+ }
+
+ public List<String> getViolationFamilies(){
+ return violationFamilies;
+ }
+
+ static final int[] mvOffsets = new int[] { 1,2,5,6,8,11,15,18,20,21,24,25 };
+ static final int[] nonMVOffsets = new int[]{ 0,3,4,7,9,10,12,13,14,16,17,19,22,23,26 };
+
+ public double getMinGenotypeQuality() {
+ return minGenotypeQuality;
+ }
+
+ /**
+ * Constructor
+ * @param minGenotypeQualityP - the minimum phred scaled genotype quality score necessary to asses mendelian violation
+ *
+ */
+ public MendelianViolation(double minGenotypeQualityP) {
+ this(minGenotypeQualityP,true);
+ }
+
+ /**
+ * Constructor
+ * @param minGenotypeQualityP - the minimum phred scaled genotype quality score necessary to asses mendelian violation
+ * @param abortOnSampleNotFound - Whether to stop execution if a family is passed but no relevant genotypes are found. If false, then the family is ignored.
+ */
+ public MendelianViolation(double minGenotypeQualityP, boolean abortOnSampleNotFound) {
+ minGenotypeQuality = minGenotypeQualityP;
+ this.abortOnSampleNotFound = abortOnSampleNotFound;
+ violationFamilies = new ArrayList<String>();
+ createInheritanceMap();
+ }
+
+ /**
+ * Constructor
+ * @param minGenotypeQualityP - the minimum phred scaled genotype quality score necessary to asses mendelian violation
+ * @param abortOnSampleNotFound - Whether to stop execution if a family is passed but no relevant genotypes are found. If false, then the family is ignored.
+ * @param completeTriosOnly - whether only complete trios are considered or parent/child pairs are too.
+ */
+ public MendelianViolation(double minGenotypeQualityP, boolean abortOnSampleNotFound, boolean completeTriosOnly) {
+ minGenotypeQuality = minGenotypeQualityP;
+ this.abortOnSampleNotFound = abortOnSampleNotFound;
+ violationFamilies = new ArrayList<String>();
+ createInheritanceMap();
+ allCalledOnly = completeTriosOnly;
+ }
+
+ /**
+ * @param families the families to be checked for Mendelian violations
+ * @param vc the variant context to extract the genotypes and alleles for mom, dad and child.
+ * @return whether or not there is a mendelian violation at the site.
+ */
+ public int countViolations(Map<String, Set<Sample>> families, VariantContext vc){
+
+ //Reset counts
+ nocall = 0;
+ lowQual = 0;
+ familyCalled = 0;
+ varFamilyCalled = 0;
+ violations_total=0;
+ violationFamilies.clear();
+ clearInheritanceMap();
+
+ for(Set<Sample> family : families.values()){
+ Iterator<Sample> sampleIterator = family.iterator();
+ Sample sample;
+ while(sampleIterator.hasNext()){
+ sample = sampleIterator.next();
+ if(sample.getParents().size() > 0)
+ updateViolations(sample.getFamilyID(),sample.getMaternalID(), sample.getPaternalID(), sample.getID() ,vc);
+ }
+ }
+ return violations_total;
+ }
+
+ public boolean isViolation(Sample mother, Sample father, Sample child, VariantContext vc){
+
+ //Reset counts
+ nocall = 0;
+ lowQual = 0;
+ familyCalled = 0;
+ varFamilyCalled = 0;
+ violations_total=0;
+ violationFamilies.clear();
+ clearInheritanceMap();
+ updateViolations(mother.getFamilyID(),mother.getID(),father.getID(),child.getID(),vc);
+ return violations_total>0;
+ }
+
+
+ private void updateViolations(String familyId, String motherId, String fatherId, String childId, VariantContext vc){
+
+ int count;
+ Genotype gMom = vc.getGenotype(motherId);
+ Genotype gDad = vc.getGenotype(fatherId);
+ Genotype gChild = vc.getGenotype(childId);
+
+ if (gMom == null || gDad == null || gChild == null){
+ if(abortOnSampleNotFound)
+ throw new IllegalArgumentException(String.format("Variant %s:%d: Missing genotypes for family %s: mom=%s dad=%s family=%s", vc.getChr(), vc.getStart(), familyId, motherId, fatherId, childId));
+ else
+ return;
+ }
+ //Count No calls
+ if(allCalledOnly && (!gMom.isCalled() || !gDad.isCalled() || !gChild.isCalled())){
+ nocall++;
+ }
+ else if (!gMom.isCalled() && !gDad.isCalled() || !gChild.isCalled()){
+ nocall++;
+ }
+ //Count lowQual. Note that if min quality is set to 0, even values with no quality associated are returned
+ else if (minGenotypeQuality>0 && (gMom.getPhredScaledQual() < minGenotypeQuality ||
+ gDad.getPhredScaledQual() < minGenotypeQuality ||
+ gChild.getPhredScaledQual() < minGenotypeQuality )) {
+ lowQual++;
+ }
+ else{
+ //Count all families per loci called
+ familyCalled++;
+ //If the family is all homref, not too interesting
+ if(!(gMom.isHomRef() && gDad.isHomRef() && gChild.isHomRef()))
+ {
+ varFamilyCalled++;
+ if(isViolation(gMom, gDad, gChild)){
+ violationFamilies.add(familyId);
+ violations_total++;
+ }
+ }
+ count = inheritance.get(gMom.getType()).get(gDad.getType()).get(gChild.getType());
+ inheritance.get(gMom.getType()).get(gDad.getType()).put(gChild.getType(),count+1);
+
+ }
+ }
+
+ /**
+ * Evaluate the genotypes of mom, dad, and child to detect Mendelian violations
+ *
+ * @param gMom
+ * @param gDad
+ * @param gChild
+ * @return true if the three genotypes represent a Mendelian violation; false otherwise
+ */
+ public static boolean isViolation(final Genotype gMom, final Genotype gDad, final Genotype gChild) {
+ //1 parent is no "call
+ if(!gMom.isCalled()){
+ return (gDad.isHomRef() && gChild.isHomVar()) || (gDad.isHomVar() && gChild.isHomRef());
+ }
+ else if(!gDad.isCalled()){
+ return (gMom.isHomRef() && gChild.isHomVar()) || (gMom.isHomVar() && gChild.isHomRef());
+ }
+ //Both parents have genotype information
+ return !(gMom.getAlleles().contains(gChild.getAlleles().get(0)) && gDad.getAlleles().contains(gChild.getAlleles().get(1)) ||
+ gMom.getAlleles().contains(gChild.getAlleles().get(1)) && gDad.getAlleles().contains(gChild.getAlleles().get(0)));
+ }
+
+ private void createInheritanceMap(){
+
+ inheritance = new EnumMap<GenotypeType,EnumMap<GenotypeType,EnumMap<GenotypeType,Integer>>>(GenotypeType.class);
+ for(GenotypeType mType : GenotypeType.values()){
+ inheritance.put(mType, new EnumMap<GenotypeType,EnumMap<GenotypeType,Integer>>(GenotypeType.class));
+ for(GenotypeType dType : GenotypeType.values()){
+ inheritance.get(mType).put(dType, new EnumMap<GenotypeType,Integer>(GenotypeType.class));
+ for(GenotypeType cType : GenotypeType.values()){
+ inheritance.get(mType).get(dType).put(cType, 0);
+ }
+ }
+ }
+
+ }
+
+ private void clearInheritanceMap(){
+ for(GenotypeType mType : GenotypeType.values()){
+ for(GenotypeType dType : GenotypeType.values()){
+ for(GenotypeType cType : GenotypeType.values()){
+ inheritance.get(mType).get(dType).put(cType, 0);
+ }
+ }
+ }
+ }
+
+ /**
+ * @return the likelihood ratio for a mendelian violation
+ */
+ public double violationLikelihoodRatio(VariantContext vc, String motherId, String fatherId, String childId) {
+ double[] logLikAssignments = new double[27];
+ // the matrix to set up is
+ // MOM DAD CHILD
+ // |- AA
+ // AA AA | AB
+ // |- BB
+ // |- AA
+ // AA AB | AB
+ // |- BB
+ // etc. The leaves are counted as 0-11 for MVs and 0-14 for non-MVs
+ double[] momGL = vc.getGenotype(motherId).getLikelihoods().getAsVector();
+ double[] dadGL = vc.getGenotype(fatherId).getLikelihoods().getAsVector();
+ double[] childGL = vc.getGenotype(childId).getLikelihoods().getAsVector();
+ int offset = 0;
+ for ( int oMom = 0; oMom < 3; oMom++ ) {
+ for ( int oDad = 0; oDad < 3; oDad++ ) {
+ for ( int oChild = 0; oChild < 3; oChild ++ ) {
+ logLikAssignments[offset++] = momGL[oMom] + dadGL[oDad] + childGL[oChild];
+ }
+ }
+ }
+ double[] mvLiks = new double[12];
+ double[] nonMVLiks = new double[15];
+ for ( int i = 0; i < 12; i ++ ) {
+ mvLiks[i] = logLikAssignments[mvOffsets[i]];
+ }
+
+ for ( int i = 0; i < 15; i++) {
+ nonMVLiks[i] = logLikAssignments[nonMVOffsets[i]];
+ }
+
+ return MathUtils.log10sumLog10(mvLiks) - MathUtils.log10sumLog10(nonMVLiks);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MultiThreadedErrorTracker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MultiThreadedErrorTracker.java
new file mode 100644
index 0000000..edbf25d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/MultiThreadedErrorTracker.java
@@ -0,0 +1,105 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+/**
+ * A utility to track exceptions that occur across threads.
+ *
+ * Uses a notify mechanism so that multiple threads can tell the tracker that an
+ * error has occurred, and a master thread can monitor this object for an error
+ * occurring and take appropriate action. Only maintains the first
+ * error to reach the tracker.
+ *
+ * Refactored from HierarchicalMicroScheduler
+ *
+ * User: depristo
+ * Date: 9/19/12
+ * Time: 11:20 AM
+ */
+public class MultiThreadedErrorTracker {
+ /**
+ * An exception that's occurred. If null, no exception has occurred.
+ */
+ private RuntimeException error = null;
+
+ /**
+ * Convenience function to check, and throw, an error is one is pending
+ */
+ public synchronized void throwErrorIfPending() {
+ if (hasAnErrorOccurred())
+ throw getError();
+ }
+
+ /**
+ * Detects whether an execution error has occurred.
+ * @return True if an error has occurred. False otherwise.
+ */
+ public synchronized boolean hasAnErrorOccurred() {
+ return error != null;
+ }
+
+ /**
+ * Retrieve the error that has occurred.
+ *
+ * @throws ReviewedGATKException if no error has occurred.
+ * @return
+ */
+ public synchronized RuntimeException getError() {
+ if(!hasAnErrorOccurred())
+ throw new ReviewedGATKException("User has attempted to retrieve a traversal error when none exists");
+ return error;
+ }
+
+ /**
+ * Notify this error tracker that an error has occurs. Only updates the tracked
+ * error if it is currently null (i.e., no error has been already reported). So
+ * calling this successively with multiple errors only keeps the first, which is the
+ * right thing to do as the initial failure is usually the meaningful one, but
+ * generates a cascade of failures as other subsystems fail.
+ */
+ public synchronized RuntimeException notifyOfError(Throwable error) {
+ if ( this.error == null )
+ this.error = toRuntimeException(error);
+
+ return this.error;
+ }
+
+ /**
+ * Convert error to a Runtime exception, or keep as is if it already is one
+ *
+ * @param error the error that has occurred
+ * @return the potentially converted error
+ */
+ private RuntimeException toRuntimeException(final Throwable error) {
+ // If the error is already a Runtime, pass it along as is. Otherwise, wrap it.
+ if (error instanceof RuntimeException)
+ return (RuntimeException)error;
+ else
+ return new ReviewedGATKException("An error occurred during the traversal. Message=" + error.getMessage(), error);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/NGSPlatform.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/NGSPlatform.java
new file mode 100644
index 0000000..f0c40a0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/NGSPlatform.java
@@ -0,0 +1,136 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.broadinstitute.gatk.utils.sam.GATKSAMReadGroupRecord;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A canonical, master list of the standard NGS platforms. These values
+ * can be obtained (efficiently) from a GATKSAMRecord object with the
+ * getNGSPlatform method.
+ *
+ * @author Mark DePristo
+ * @since 2011
+ */
+public enum NGSPlatform {
+ // note the order of elements here determines the order of matching operations, and therefore the
+ // efficiency of getting a NGSPlatform from a string.
+ ILLUMINA("ILLUMINA", "SLX", "SOLEXA"),
+ SOLID("SOLID"),
+ LS454("454"),
+ COMPLETE_GENOMICS("COMPLETE"),
+ PACBIO("PACBIO"),
+ ION_TORRENT("IONTORRENT"),
+ CAPILLARY("CAPILLARY"),
+ HELICOS("HELICOS"),
+ UNKNOWN("UNKNOWN");
+
+ /**
+ * Array of the prefix names in a BAM file for each of the platforms.
+ */
+ protected final String[] BAM_PL_NAMES;
+
+ NGSPlatform(final String... BAM_PL_NAMES) {
+ if ( BAM_PL_NAMES.length == 0 ) throw new IllegalStateException("Platforms must have at least one name");
+
+ for ( int i = 0; i < BAM_PL_NAMES.length; i++ )
+ BAM_PL_NAMES[i] = BAM_PL_NAMES[i].toUpperCase();
+
+ this.BAM_PL_NAMES = BAM_PL_NAMES;
+ }
+
+ /**
+ * Returns a representative PL string for this platform
+ * @return
+ */
+ public final String getDefaultPlatform() {
+ return BAM_PL_NAMES[0];
+ }
+
+ /**
+ * Convenience get -- get the NGSPlatform from a GATKSAMRecord.
+ *
+ * Just gets the platform from the GATKReadGroupRecord associated with this read.
+ *
+ * @param read a non-null GATKSAMRecord
+ * @return an NGSPlatform object matching the PL field of the header, of UNKNOWN if there was no match,
+ * if there is no read group for read, or there's no PL field for the read group
+ */
+ public static NGSPlatform fromRead(final GATKSAMRecord read) {
+ if ( read == null ) throw new IllegalArgumentException("read cannot be null");
+ final GATKSAMReadGroupRecord rg = read.getReadGroup();
+ return rg == null ? UNKNOWN : rg.getNGSPlatform();
+ }
+
+ /**
+ * Returns the NGSPlatform corresponding to the PL tag in the read group
+ * @param plFromRG -- the PL field (or equivalent) in a ReadGroup object. Can be null => UNKNOWN
+ * @return an NGSPlatform object matching the PL field of the header, or UNKNOWN if there was no match or plFromRG is null
+ */
+ public static NGSPlatform fromReadGroupPL(final String plFromRG) {
+ if ( plFromRG == null ) return UNKNOWN;
+
+ // todo -- algorithm could be implemented more efficiently, as the list of all
+ // todo -- names is known upfront, so a decision tree could be used to identify
+ // todo -- a prefix common to PL
+ final String pl = plFromRG.toUpperCase();
+ for ( final NGSPlatform ngsPlatform : NGSPlatform.values() ) {
+ for ( final String bamPLName : ngsPlatform.BAM_PL_NAMES ) {
+ if ( pl.contains(bamPLName) )
+ return ngsPlatform;
+ }
+ }
+
+ return UNKNOWN;
+ }
+
+ /**
+ * checks whether or not the requested platform is listed in the set (and is not unknown)
+ *
+ * @param platform the read group string that describes the platform used. can be null
+ * @return true if the platform is known (i.e. it's in the list and is not UNKNOWN)
+ */
+ public static boolean isKnown(final String platform) {
+ return fromReadGroupPL(platform) != UNKNOWN;
+ }
+
+ /**
+ * Get a human-readable list of platform names
+ * @return the list of platform names
+ */
+ public static String knownPlatformsString() {
+ final List<String> names = new LinkedList<String>();
+ for ( final NGSPlatform pl : values() ) {
+ for ( final String name : pl.BAM_PL_NAMES )
+ names.add(name);
+ }
+ return Utils.join(",", names);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/PathUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/PathUtils.java
new file mode 100644
index 0000000..ef6d5a0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/PathUtils.java
@@ -0,0 +1,195 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.apache.commons.io.comparator.LastModifiedFileComparator;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: hanna
+ * Date: Mar 30, 2009
+ * Time: 5:43:39 PM
+ * To change this template use File | Settings | File Templates.
+ *
+ * A set of static utility methods for common operations on paths.
+ */
+public class PathUtils {
+ private static Logger logger = Logger.getLogger(PathUtils.class);
+
+ /**
+ * Constructor access disallowed...static utility methods only!
+ */
+ private PathUtils() { }
+
+ /**
+ * Find the files in the given directory matching the given extension.
+ *
+ * @param basePath Path to search.
+ * @param relativePrefix What directory should the given files be presented relative to?
+ * @param extension Extension for which to search.
+ * @param recursive Search recursively. Beware of symlinks!
+ * @return A list of files matching the specified criteria.
+ * TODO: Test recursive traversal in the presence of a symlink.
+ */
+ public static List<String> findFilesInPath(final File basePath, final String relativePrefix, final String extension, boolean recursive) {
+ List<String> filesInPath = new ArrayList<String>();
+
+ FilenameFilter filter = new OrFilenameFilter(new DirectoryFilter(),
+ new ExtensionFilter(extension));
+ File[] contents = basePath.listFiles( filter );
+ for (File content : contents) {
+ String relativeFileName = relativePrefix.trim().length() != 0 ?
+ relativePrefix + File.separator + content.getName() :
+ content.getName();
+ if (relativeFileName.endsWith(extension))
+ filesInPath.add(relativeFileName);
+ else if (content.isDirectory() && recursive)
+ filesInPath.addAll(findFilesInPath(content, relativeFileName, extension, recursive));
+ }
+
+ return filesInPath;
+ }
+
+ /**
+ * Filter files by extension.
+ */
+ public static class ExtensionFilter implements FilenameFilter {
+ private String extensionName = null;
+
+ public ExtensionFilter(String extensionName) {
+ this.extensionName = extensionName;
+ }
+
+ public boolean accept(File f, String s) {
+ return s.endsWith("." + extensionName);
+ }
+ }
+
+ /**
+ * Filter directories from list of files.
+ */
+ public static class DirectoryFilter implements FilenameFilter {
+ public boolean accept(File f, String s) {
+ return new File(f, s).isDirectory();
+ }
+ }
+
+ /**
+ * Join two FilenameFilters together in a logical 'or' operation.
+ */
+ public static class OrFilenameFilter implements FilenameFilter {
+ private FilenameFilter lhs = null, rhs = null;
+
+ public OrFilenameFilter(FilenameFilter lhs, FilenameFilter rhs) {
+ this.lhs = lhs;
+ this.rhs = rhs;
+ }
+
+ public boolean accept(File f, String s) {
+ return lhs.accept(f, s) || rhs.accept(f, s);
+ }
+ }
+
+ /**
+ * Refreshes the volume associated with a given file or directory by attempting to access it
+ * a few times before giving up. The file need not exist, though the parent directory must.
+ * This method is particularly useful when your job has been dispatched to LSF and you need to
+ * ensure an NSF-mounted volume is actually accessible (many times it isn't for a few seconds,
+ * just enough to cause your program to come crashing down).
+ *
+ * @param file the file or directory that resides in the volume to be refreshed.
+ */
+ public static void refreshVolume(File file) {
+ File dir = file.isDirectory() ? file : file.getParentFile();
+
+ int sleepCount = 0;
+ while (sleepCount < 3 && dir.listFiles() == null) {
+ try {
+ Thread.sleep((sleepCount + 1)*3000);
+ } catch (InterruptedException e) {
+ }
+
+ sleepCount++;
+ }
+
+ if (dir.listFiles() == null) {
+ throw new ReviewedGATKException("The volume '" + dir.getAbsolutePath() + "' could not be accessed.");
+ }
+ }
+
+
+ /**
+ * Walk over the GATK released directories to find the most recent JAR files corresponding
+ * to the version prefix. For example, providing input "1.2" will
+ * return the full path to the most recent GenomeAnalysisTK.jar in the GATK_RELEASE_DIR
+ * in directories that match gatkReleaseDir/GenomeAnalysisTK-1.2*
+ *
+ * @param gatkReleaseDir Path to directory containing GATK release binaries (e.g., /humgen/gsa-hpprojects/GATK/bin/)
+ * @param releaseVersionNumber Desired GATK version number (e.g., 1.2)
+ * @return A file pointing to the most recent GATK file in the release directory with GATK release number
+ */
+ public static File findMostRecentGATKVersion(final File gatkReleaseDir, final String releaseVersionNumber) {
+ final String versionString = "GenomeAnalysisTK-" + releaseVersionNumber;
+
+ final List<File> gatkJars = new ArrayList<File>();
+ for ( final String path : gatkReleaseDir.list(new isGATKVersion(versionString)) ) {
+ gatkJars.add(new File(gatkReleaseDir.getAbsolutePath() + "/" + path + "/GenomeAnalysisTK.jar"));
+ }
+
+ if ( gatkJars.isEmpty() )
+ return null;
+ else {
+ Collections.sort(gatkJars, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
+ //for ( File jar : gatkJars ) logger.info(String.format("%s => %d", jar, jar.lastModified()));
+ final File last = gatkJars.get(0);
+ logger.debug(String.format("findMostRecentGATKVersion: Found %d jars for %s, keeping last one %s",
+ gatkJars.size(), releaseVersionNumber, last));
+ return last;
+ }
+ }
+
+ private final static class isGATKVersion implements FilenameFilter {
+ private final String versionString;
+
+ private isGATKVersion(final String versionString) {
+ this.versionString = versionString;
+ }
+
+ @Override
+ public boolean accept(final File file, final String s) {
+ return s.contains(versionString);
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/QualityUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/QualityUtils.java
new file mode 100644
index 0000000..cd6cfc6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/QualityUtils.java
@@ -0,0 +1,397 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import com.google.java.contract.Ensures;
+import htsjdk.samtools.SAMUtils;
+
+/**
+ * QualityUtils is a static class (no instantiation allowed!) with some utility methods for manipulating
+ * quality scores.
+ *
+ * @author Kiran Garimella, Mark DePristo
+ * @since Way back
+ */
+public class QualityUtils {
+ /**
+ * Maximum quality score that can be encoded in a SAM/BAM file
+ */
+ public final static byte MAX_SAM_QUAL_SCORE = SAMUtils.MAX_PHRED_SCORE;
+
+
+ private final static double RAW_MIN_PHRED_SCALED_QUAL = Math.log10(Double.MIN_VALUE);
+ protected final static double MIN_PHRED_SCALED_QUAL = -10.0 * RAW_MIN_PHRED_SCALED_QUAL;
+
+ /**
+ * bams containing quals above this value are extremely suspicious and we should warn the user
+ */
+ public final static byte MAX_REASONABLE_Q_SCORE = 60;
+
+ /**
+ * The lowest quality score for a base that is considered reasonable for statistical analysis. This is
+ * because Q 6 => you stand a 25% of being right, which means all bases are equally likely
+ */
+ public final static byte MIN_USABLE_Q_SCORE = 6;
+ public final static int MAPPING_QUALITY_UNAVAILABLE = 255;
+
+ /**
+ * Maximum sense quality value.
+ */
+ public static final int MAX_QUAL = 254;
+
+ /**
+ * Cached values for qual as byte calculations so they are very fast
+ */
+ private static double qualToErrorProbCache[] = new double[MAX_QUAL + 1];
+ private static double qualToProbLog10Cache[] = new double[MAX_QUAL + 1];
+
+
+ static {
+ for (int i = 0; i <= MAX_QUAL; i++) {
+ qualToErrorProbCache[i] = qualToErrorProb((double) i);
+ qualToProbLog10Cache[i] = Math.log10(1.0 - qualToErrorProbCache[i]);
+ }
+ }
+
+ /**
+ * Private constructor. No instantiating this class!
+ */
+ private QualityUtils() {}
+
+ // ----------------------------------------------------------------------
+ //
+ // These are all functions to convert a phred-scaled quality score to a probability
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * Convert a phred-scaled quality score to its probability of being true (Q30 => 0.999)
+ *
+ * This is the Phred-style conversion, *not* the Illumina-style conversion.
+ *
+ * Because the input is a discretized byte value, this function uses a cache so is very efficient
+ *
+ * WARNING -- because this function takes a byte for maxQual, you must be careful in converting
+ * integers to byte. The appropriate way to do this is ((byte)(myInt & 0xFF))
+ *
+ * @param qual a quality score (0-255)
+ * @return a probability (0.0-1.0)
+ */
+ @Ensures("result >= 0.0 && result <= 1.0")
+ public static double qualToProb(final byte qual) {
+ return 1.0 - qualToErrorProb(qual);
+ }
+
+ /**
+ * Convert a phred-scaled quality score to its probability of being true (Q30 => 0.999)
+ *
+ * This is the Phred-style conversion, *not* the Illumina-style conversion.
+ *
+ * Because the input is a double value, this function must call Math.pow so can be quite expensive
+ *
+ * @param qual a phred-scaled quality score encoded as a double. Can be non-integer values (30.5)
+ * @return a probability (0.0-1.0)
+ */
+ @Ensures("result >= 0.0 && result <= 1.0")
+ public static double qualToProb(final double qual) {
+ if ( qual < 0.0 ) throw new IllegalArgumentException("qual must be >= 0.0 but got " + qual);
+ return 1.0 - qualToErrorProb(qual);
+ }
+
+ /**
+ * Convert a phred-scaled quality score to its log10 probability of being true (Q30 => log10(0.999))
+ *
+ * This is the Phred-style conversion, *not* the Illumina-style conversion.
+ *
+ * Because the input is a double value, this function must call Math.pow so can be quite expensive
+ *
+ * WARNING -- because this function takes a byte for maxQual, you must be careful in converting
+ * integers to byte. The appropriate way to do this is ((byte)(myInt & 0xFF))
+ *
+ * @param qual a phred-scaled quality score encoded as a double. Can be non-integer values (30.5)
+ * @return a probability (0.0-1.0)
+ */
+ @Ensures("result <= 0.0")
+ public static double qualToProbLog10(final byte qual) {
+ return qualToProbLog10Cache[(int)qual & 0xff]; // Map: 127 -> 127; -128 -> 128; -1 -> 255; etc.
+ }
+
+ /**
+ * Convert a phred-scaled quality score to its probability of being wrong (Q30 => 0.001)
+ *
+ * This is the Phred-style conversion, *not* the Illumina-style conversion.
+ *
+ * Because the input is a double value, this function must call Math.pow so can be quite expensive
+ *
+ * @param qual a phred-scaled quality score encoded as a double. Can be non-integer values (30.5)
+ * @return a probability (0.0-1.0)
+ */
+ @Ensures("result >= 0.0 && result <= 1.0")
+ public static double qualToErrorProb(final double qual) {
+ if ( qual < 0.0 ) throw new IllegalArgumentException("qual must be >= 0.0 but got " + qual);
+ return Math.pow(10.0, qual / -10.0);
+ }
+
+ /**
+ * Convert a phred-scaled quality score to its probability of being wrong (Q30 => 0.001)
+ *
+ * This is the Phred-style conversion, *not* the Illumina-style conversion.
+ *
+ * Because the input is a byte value, this function uses a cache so is very efficient
+ *
+ * WARNING -- because this function takes a byte for maxQual, you must be careful in converting
+ * integers to byte. The appropriate way to do this is ((byte)(myInt & 0xFF))
+ *
+ * @param qual a phred-scaled quality score encoded as a byte
+ * @return a probability (0.0-1.0)
+ */
+ @Ensures("result >= 0.0 && result <= 1.0")
+ public static double qualToErrorProb(final byte qual) {
+ return qualToErrorProbCache[(int)qual & 0xff]; // Map: 127 -> 127; -128 -> 128; -1 -> 255; etc.
+ }
+
+
+ /**
+ * Convert a phred-scaled quality score to its log10 probability of being wrong (Q30 => log10(0.001))
+ *
+ * This is the Phred-style conversion, *not* the Illumina-style conversion.
+ *
+ * The calculation is extremely efficient
+ *
+ * WARNING -- because this function takes a byte for maxQual, you must be careful in converting
+ * integers to byte. The appropriate way to do this is ((byte)(myInt & 0xFF))
+ *
+ * @param qual a phred-scaled quality score encoded as a byte
+ * @return a probability (0.0-1.0)
+ */
+ @Ensures("result <= 0.0")
+ public static double qualToErrorProbLog10(final byte qual) {
+ return qualToErrorProbLog10((double)(qual & 0xFF));
+ }
+
+ /**
+ * Convert a phred-scaled quality score to its log10 probability of being wrong (Q30 => log10(0.001))
+ *
+ * This is the Phred-style conversion, *not* the Illumina-style conversion.
+ *
+ * The calculation is extremely efficient
+ *
+ * @param qual a phred-scaled quality score encoded as a double
+ * @return a probability (0.0-1.0)
+ */
+ @Ensures("result <= 0.0")
+ public static double qualToErrorProbLog10(final double qual) {
+ if ( qual < 0.0 ) throw new IllegalArgumentException("qual must be >= 0.0 but got " + qual);
+ return qual / -10.0;
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // Functions to convert a probability to a phred-scaled quality score
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * Convert a probability of being wrong to a phred-scaled quality score (0.01 => 20).
+ *
+ * Note, this function caps the resulting quality score by the public static value MAX_SAM_QUAL_SCORE
+ * and by 1 at the low-end.
+ *
+ * @param errorRate a probability (0.0-1.0) of being wrong (i.e., 0.01 is 1% change of being wrong)
+ * @return a quality score (0-MAX_SAM_QUAL_SCORE)
+ */
+ public static byte errorProbToQual(final double errorRate) {
+ return errorProbToQual(errorRate, MAX_SAM_QUAL_SCORE);
+ }
+
+ /**
+ * Convert a probability of being wrong to a phred-scaled quality score (0.01 => 20).
+ *
+ * Note, this function caps the resulting quality score by the public static value MIN_REASONABLE_ERROR
+ * and by 1 at the low-end.
+ *
+ * WARNING -- because this function takes a byte for maxQual, you must be careful in converting
+ * integers to byte. The appropriate way to do this is ((byte)(myInt & 0xFF))
+ *
+ * @param errorRate a probability (0.0-1.0) of being wrong (i.e., 0.01 is 1% change of being wrong)
+ * @return a quality score (0-maxQual)
+ */
+ public static byte errorProbToQual(final double errorRate, final byte maxQual) {
+ if ( ! MathUtils.goodProbability(errorRate) ) throw new IllegalArgumentException("errorRate must be good probability but got " + errorRate);
+ final double d = Math.round(-10.0*Math.log10(errorRate));
+ return boundQual((int)d, maxQual);
+ }
+
+ /**
+ * @see #errorProbToQual(double, byte) with proper conversion of maxQual integer to a byte
+ */
+ public static byte errorProbToQual(final double prob, final int maxQual) {
+ if ( maxQual < 0 || maxQual > 255 ) throw new IllegalArgumentException("maxQual must be between 0-255 but got " + maxQual);
+ return errorProbToQual(prob, (byte)(maxQual & 0xFF));
+ }
+
+ /**
+ * Convert a probability of being right to a phred-scaled quality score (0.99 => 20).
+ *
+ * Note, this function caps the resulting quality score by the public static value MAX_SAM_QUAL_SCORE
+ * and by 1 at the low-end.
+ *
+ * @param prob a probability (0.0-1.0) of being right
+ * @return a quality score (0-MAX_SAM_QUAL_SCORE)
+ */
+ public static byte trueProbToQual(final double prob) {
+ return trueProbToQual(prob, MAX_SAM_QUAL_SCORE);
+ }
+
+ /**
+ * Convert a probability of being right to a phred-scaled quality score (0.99 => 20).
+ *
+ * Note, this function caps the resulting quality score by the min probability allowed (EPS).
+ * So for example, if prob is 1e-6, which would imply a Q-score of 60, and EPS is 1e-4,
+ * the result of this function is actually Q40.
+ *
+ * Note that the resulting quality score, regardless of EPS, is capped by MAX_SAM_QUAL_SCORE and
+ * bounded on the low-side by 1.
+ *
+ * WARNING -- because this function takes a byte for maxQual, you must be careful in converting
+ * integers to byte. The appropriate way to do this is ((byte)(myInt & 0xFF))
+ *
+ * @param trueProb a probability (0.0-1.0) of being right
+ * @param maxQual the maximum quality score we are allowed to emit here, regardless of the error rate
+ * @return a phred-scaled quality score (0-maxQualScore) as a byte
+ */
+ @Ensures("(result & 0xFF) >= 1 && (result & 0xFF) <= (maxQual & 0xFF)")
+ public static byte trueProbToQual(final double trueProb, final byte maxQual) {
+ if ( ! MathUtils.goodProbability(trueProb) ) throw new IllegalArgumentException("trueProb must be good probability but got " + trueProb);
+ final double lp = Math.round(-10.0*MathUtils.log10OneMinusX(trueProb));
+ return boundQual((int)lp, maxQual);
+ }
+
+ /**
+ * @see #trueProbToQual(double, byte) with proper conversion of maxQual to a byte
+ */
+ public static byte trueProbToQual(final double prob, final int maxQual) {
+ if ( maxQual < 0 || maxQual > 255 ) throw new IllegalArgumentException("maxQual must be between 0-255 but got " + maxQual);
+ return trueProbToQual(prob, (byte)(maxQual & 0xFF));
+ }
+
+ /**
+ * Convert a probability of being right to a phred-scaled quality score of being wrong as a double
+ *
+ * This is a very generic method, that simply computes a phred-scaled double quality
+ * score given an error rate. It has the same precision as a normal double operation
+ *
+ * @param trueRate the probability of being right (0.0-1.0)
+ * @return a phred-scaled version of the error rate implied by trueRate
+ */
+ @Ensures("result >= 0.0")
+ public static double phredScaleCorrectRate(final double trueRate) {
+ return phredScaleLog10ErrorRate(MathUtils.log10OneMinusX(trueRate));
+ }
+
+ /**
+ * Convert a log10 probability of being right to a phred-scaled quality score of being wrong as a double
+ *
+ * This is a very generic method, that simply computes a phred-scaled double quality
+ * score given an error rate. It has the same precision as a normal double operation
+ *
+ * @param trueRateLog10 the log10 probability of being right (0.0-1.0). Can be -Infinity to indicate
+ * that the result is impossible in which MIN_PHRED_SCALED_QUAL is returned
+ * @return a phred-scaled version of the error rate implied by trueRate
+ */
+ @Ensures("result >= 0.0")
+ public static double phredScaleLog10CorrectRate(final double trueRateLog10) {
+ return phredScaleCorrectRate(Math.pow(10.0, trueRateLog10));
+ }
+
+ /**
+ * Convert a probability of being wrong to a phred-scaled quality score of being wrong as a double
+ *
+ * This is a very generic method, that simply computes a phred-scaled double quality
+ * score given an error rate. It has the same precision as a normal double operation
+ *
+ * @param errorRate the probability of being wrong (0.0-1.0)
+ * @return a phred-scaled version of the error rate
+ */
+ @Ensures("result >= 0.0")
+ public static double phredScaleErrorRate(final double errorRate) {
+ return phredScaleLog10ErrorRate(Math.log10(errorRate));
+ }
+
+ /**
+ * Convert a log10 probability of being wrong to a phred-scaled quality score of being wrong as a double
+ *
+ * This is a very generic method, that simply computes a phred-scaled double quality
+ * score given an error rate. It has the same precision as a normal double operation
+ *
+ * @param errorRateLog10 the log10 probability of being wrong (0.0-1.0). Can be -Infinity, in which case
+ * the result is MIN_PHRED_SCALED_QUAL
+ * @return a phred-scaled version of the error rate
+ */
+ @Ensures("result >= 0.0")
+ public static double phredScaleLog10ErrorRate(final double errorRateLog10) {
+ if ( ! MathUtils.goodLog10Probability(errorRateLog10) ) throw new IllegalArgumentException("errorRateLog10 must be good probability but got " + errorRateLog10);
+ // abs is necessary for edge base with errorRateLog10 = 0 producing -0.0 doubles
+ return Math.abs(-10.0 * Math.max(errorRateLog10, RAW_MIN_PHRED_SCALED_QUAL));
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // Routines to bound a quality score to a reasonable range
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * Return a quality score that bounds qual by MAX_SAM_QUAL_SCORE and 1
+ *
+ * @param qual the uncapped quality score as an integer
+ * @return the bounded quality score
+ */
+ @Ensures("(result & 0xFF) >= 1 && (result & 0xFF) <= (MAX_SAM_QUAL_SCORE & 0xFF)")
+ public static byte boundQual(int qual) {
+ return boundQual(qual, MAX_SAM_QUAL_SCORE);
+ }
+
+ /**
+ * Return a quality score that bounds qual by maxQual and 1
+ *
+ * WARNING -- because this function takes a byte for maxQual, you must be careful in converting
+ * integers to byte. The appropriate way to do this is ((byte)(myInt & 0xFF))
+ *
+ * @param qual the uncapped quality score as an integer. Can be < 0 (which may indicate an error in the
+ * client code), which will be brought back to 1, but this isn't an error, as some
+ * routines may use this functionality (BaseRecalibrator, for example)
+ * @param maxQual the maximum quality score, must be less < 255
+ * @return the bounded quality score
+ */
+ @Ensures("(result & 0xFF) >= 1 && (result & 0xFF) <= (maxQual & 0xFF)")
+ public static byte boundQual(final int qual, final byte maxQual) {
+ return (byte) (Math.max(Math.min(qual, maxQual & 0xFF), 1) & 0xFF);
+ }
+
+ }
+
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RScriptExecutor.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RScriptExecutor.java
new file mode 100644
index 0000000..c6c4fba
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RScriptExecutor.java
@@ -0,0 +1,191 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.R;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.io.IOUtils;
+import org.broadinstitute.gatk.utils.io.Resource;
+import org.broadinstitute.gatk.utils.runtime.ProcessController;
+import org.broadinstitute.gatk.utils.runtime.ProcessSettings;
+import org.broadinstitute.gatk.utils.runtime.RuntimeUtils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Generic service for executing RScripts
+ */
+public class RScriptExecutor {
+ private static final String RSCRIPT_BINARY = "Rscript";
+ private static final File RSCRIPT_PATH = RuntimeUtils.which(RSCRIPT_BINARY);
+ public static final boolean RSCRIPT_EXISTS = (RSCRIPT_PATH != null);
+ private static final String RSCRIPT_MISSING_MESSAGE = "Please add the Rscript directory to your environment ${PATH}";
+
+ /**
+ * our log
+ */
+ private static Logger logger = Logger.getLogger(RScriptExecutor.class);
+
+ private boolean exceptOnError = false;
+ private final List<RScriptLibrary> libraries = new ArrayList<RScriptLibrary>();
+ private final List<Resource> scriptResources = new ArrayList<Resource>();
+ private final List<File> scriptFiles = new ArrayList<File>();
+ private final List<String> args = new ArrayList<String>();
+
+ public void setExceptOnError(boolean exceptOnError) {
+ this.exceptOnError = exceptOnError;
+ }
+
+ public void addLibrary(RScriptLibrary library) {
+ this.libraries.add(library);
+ }
+
+ public void addScript(Resource script) {
+ this.scriptResources.add(script);
+ }
+
+ public void addScript(File script) {
+ this.scriptFiles.add(script);
+ }
+
+ /**
+ * Adds args to the end of the Rscript command line.
+ * @param args the args.
+ * @throws NullPointerException if any of the args are null.
+ */
+ public void addArgs(Object... args) {
+ for (Object arg: args)
+ this.args.add(arg.toString());
+ }
+
+ public String getApproximateCommandLine() {
+ StringBuilder command = new StringBuilder("Rscript");
+ for (Resource script: this.scriptResources)
+ command.append(" (resource)").append(script.getFullPath());
+ for (File script: this.scriptFiles)
+ command.append(" ").append(script.getAbsolutePath());
+ for (String arg: this.args)
+ command.append(" ").append(arg);
+ return command.toString();
+ }
+
+ public boolean exec() {
+ if (!RSCRIPT_EXISTS) {
+ if (exceptOnError) {
+ throw new UserException.CannotExecuteRScript(RSCRIPT_MISSING_MESSAGE);
+ } else {
+ logger.warn("Skipping: " + getApproximateCommandLine());
+ return false;
+ }
+ }
+
+ List<File> tempFiles = new ArrayList<File>();
+ try {
+ File tempLibSourceDir = IOUtils.tempDir("RlibSources.", "");
+ File tempLibInstallationDir = IOUtils.tempDir("Rlib.", "");
+ tempFiles.add(tempLibSourceDir);
+ tempFiles.add(tempLibInstallationDir);
+
+ StringBuilder expression = new StringBuilder("tempLibDir = '").append(tempLibInstallationDir).append("';");
+
+ if (this.libraries.size() > 0) {
+ List<String> tempLibraryPaths = new ArrayList<String>();
+ for (RScriptLibrary library: this.libraries) {
+ File tempLibrary = library.writeLibrary(tempLibSourceDir);
+ tempFiles.add(tempLibrary);
+ tempLibraryPaths.add(tempLibrary.getAbsolutePath());
+ }
+
+ expression.append("install.packages(");
+ expression.append("pkgs=c('").append(StringUtils.join(tempLibraryPaths, "', '")).append("'), lib=tempLibDir, repos=NULL, type='source', ");
+ // Install faster by eliminating cruft.
+ expression.append("INSTALL_opts=c('--no-libs', '--no-data', '--no-help', '--no-demo', '--no-exec')");
+ expression.append(");");
+
+ for (RScriptLibrary library: this.libraries) {
+ expression.append("library('").append(library.getLibraryName()).append("', lib.loc=tempLibDir);");
+ }
+ }
+
+ for (Resource script: this.scriptResources) {
+ File tempScript = IOUtils.writeTempResource(script);
+ tempFiles.add(tempScript);
+ expression.append("source('").append(tempScript.getAbsolutePath()).append("');");
+ }
+
+ for (File script: this.scriptFiles) {
+ expression.append("source('").append(script.getAbsolutePath()).append("');");
+ }
+
+ String[] cmd = new String[this.args.size() + 3];
+ int i = 0;
+ cmd[i++] = RSCRIPT_BINARY;
+ cmd[i++] = "-e";
+ cmd[i++] = expression.toString();
+ for (String arg: this.args)
+ cmd[i++] = arg;
+
+ ProcessSettings processSettings = new ProcessSettings(cmd);
+ if (logger.isDebugEnabled()) {
+ processSettings.getStdoutSettings().printStandard(true);
+ processSettings.getStderrSettings().printStandard(true);
+ }
+
+ ProcessController controller = ProcessController.getThreadLocal();
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Executing:");
+ for (String arg: cmd)
+ logger.debug(" " + arg);
+ }
+ int exitValue = controller.exec(processSettings).getExitValue();
+ logger.debug("Result: " + exitValue);
+
+ if (exitValue != 0)
+ throw new RScriptExecutorException(
+ "RScript exited with " + exitValue +
+ (logger.isDebugEnabled() ? "" : ". Run with -l DEBUG for more info."));
+
+ return true;
+ } catch (GATKException e) {
+ if (exceptOnError) {
+ throw e;
+ } else {
+ logger.warn(e.getMessage());
+ return false;
+ }
+ } finally {
+ for (File temp: tempFiles)
+ FileUtils.deleteQuietly(temp);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RScriptExecutorException.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RScriptExecutorException.java
new file mode 100644
index 0000000..233ff73
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RScriptExecutorException.java
@@ -0,0 +1,34 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.R;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+public class RScriptExecutorException extends ReviewedGATKException {
+ public RScriptExecutorException(String msg) {
+ super(msg);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RScriptLibrary.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RScriptLibrary.java
new file mode 100644
index 0000000..390edc7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RScriptLibrary.java
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.R;
+
+import org.broadinstitute.gatk.utils.io.IOUtils;
+import org.broadinstitute.gatk.utils.io.Resource;
+
+import java.io.File;
+
+/**
+ * Libraries embedded in the StingUtils package.
+ */
+public enum RScriptLibrary {
+ GSALIB("gsalib");
+
+ private final String name;
+
+ private RScriptLibrary(String name) {
+ this.name = name;
+ }
+
+ public String getLibraryName() {
+ return this.name;
+ }
+
+ public String getResourcePath() {
+ return name + ".tar.gz";
+ }
+
+ /**
+ * Writes the library source code to a temporary tar.gz file and returns the path.
+ * @return The path to the library source code. The caller must delete the code when done.
+ */
+ public File writeTemp() {
+ return IOUtils.writeTempResource(new Resource(getResourcePath(), RScriptLibrary.class));
+ }
+
+ public File writeLibrary(File tempDir) {
+ File libraryFile = new File(tempDir, getLibraryName());
+ IOUtils.writeResource(new Resource(getResourcePath(), RScriptLibrary.class), libraryFile);
+ return libraryFile;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RUtils.java
new file mode 100644
index 0000000..80f7313
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/R/RUtils.java
@@ -0,0 +1,91 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.R;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+
+public class RUtils {
+ /**
+ * Converts a collection of values to an R compatible list. A null list will return NA,
+ * otherwise the values will be escaped with single quotes and combined with c().
+ * @param list Collection of values
+ * @return The R representation of the list
+ */
+ public static String toStringList(Collection<? extends CharSequence> list) {
+ if (list == null)
+ return "NA";
+ if (list.size() == 0)
+ return "c()";
+ return "c('" + StringUtils.join(list, "','") + "')";
+ }
+
+ /**
+ * Converts a collection of values to an R compatible list. A null list will return NA,
+ * otherwise the values will be combined with c().
+ * @param list Collection of values
+ * @return The R representation of the list
+ */
+ public static String toNumberList(Collection<? extends Number> list) {
+ return list == null ? "NA": "c(" + StringUtils.join(list, ",") + ")";
+ }
+
+ /**
+ * Converts a collection of values to an R compatible list. A null list will return NA,
+ * otherwise the date will be escaped with single quotes and combined with c().
+ * @param list Collection of values
+ * @return The R representation of the list
+ */
+ public static String toDateList(Collection<? extends Date> list) {
+ return toDateList(list, "''yyyy-MM-dd''");
+ }
+
+ /**
+ * Converts a collection of values to an R compatible list formatted by pattern.
+ * @param list Collection of values
+ * @param pattern format pattern string for each date
+ * @return The R representation of the list
+ */
+ public static String toDateList(Collection<? extends Date> list, String pattern) {
+
+ if (list == null)
+ return "NA";
+ SimpleDateFormat format = new SimpleDateFormat(pattern);
+ StringBuilder sb = new StringBuilder();
+ sb.append("c(");
+ boolean first = true;
+ for (Date date : list) {
+ if (!first) sb.append(",");
+ sb.append(format.format(date));
+ first = false;
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/SampleUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/SampleUtils.java
new file mode 100644
index 0000000..77fc170
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/SampleUtils.java
@@ -0,0 +1,290 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import htsjdk.variant.vcf.VCFHeader;
+import org.broadinstitute.gatk.utils.text.ListFileUtils;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.*;
+
+
+/**
+ * SampleUtils is a static class (no instantiation allowed!) with some utility methods for getting samples
+ * quality scores.
+ *
+ * @author ebanks
+ */
+public class SampleUtils {
+ /**
+ * Private constructor. No instantiating this class!
+ */
+ private SampleUtils() {}
+
+ /**
+ * Pull out the samples from a SAMFileHeader;
+ * note that we use a TreeSet so that they are sorted
+ *
+ * @param header the sam file header
+ * @return list of strings representing the sample names
+ */
+ public static Set<String> getSAMFileSamples(final SAMFileHeader header) {
+ // get all of the unique sample names
+ final Set<String> samples = new TreeSet<String>();
+ List<SAMReadGroupRecord> readGroups = header.getReadGroups();
+ for ( SAMReadGroupRecord readGroup : readGroups )
+ samples.add(readGroup.getSample());
+ return samples;
+ }
+
+
+ /**
+ * Same as @link getSAMFileSamples but gets all of the samples
+ * in the SAM files loaded by the engine
+ *
+ * @param engine engine
+ * @return samples
+ */
+ public static Set<String> getSAMFileSamples(GenomeAnalysisEngine engine) {
+ return SampleUtils.getSAMFileSamples(engine.getSAMFileHeader());
+ }
+
+ /**
+ * Gets all of the unique sample names from all VCF rods input by the user
+ *
+ * @param toolkit GATK engine
+ *
+ * @return the set of unique samples
+ */
+ public static Set<String> getUniqueSamplesFromRods(GenomeAnalysisEngine toolkit) {
+ return getUniqueSamplesFromRods(toolkit, null);
+ }
+
+ /**
+ * Gets all of the unique sample names from the set of provided VCF rod names input by the user
+ *
+ * @param toolkit GATK engine
+ * @param rodNames list of rods to use; if null, uses all VCF rods
+ *
+ * @return the set of unique samples
+ */
+ public static Set<String> getUniqueSamplesFromRods(GenomeAnalysisEngine toolkit, Collection<String> rodNames) {
+ Set<String> samples = new LinkedHashSet<>();
+
+ for ( VCFHeader header : GATKVCFUtils.getVCFHeadersFromRods(toolkit, rodNames).values() )
+ samples.addAll(header.getGenotypeSamples());
+
+ return samples;
+ }
+
+ public static Set<String> getRodNamesWithVCFHeader(GenomeAnalysisEngine toolkit, Collection<String> rodNames) {
+ return GATKVCFUtils.getVCFHeadersFromRods(toolkit, rodNames).keySet();
+ }
+
+ public static Set<String> getSampleListWithVCFHeader(GenomeAnalysisEngine toolkit, Collection<String> rodNames) {
+ return getSampleList(GATKVCFUtils.getVCFHeadersFromRods(toolkit, rodNames));
+ }
+
+ public static Set<String> getSampleList(Map<String, VCFHeader> headers) {
+ return getSampleList(headers, GATKVariantContextUtils.GenotypeMergeType.PRIORITIZE);
+ }
+
+ public static Set<String> getSampleList(Map<String, VCFHeader> headers, GATKVariantContextUtils.GenotypeMergeType mergeOption) {
+ Set<String> samples = new TreeSet<String>();
+ for ( Map.Entry<String, VCFHeader> val : headers.entrySet() ) {
+ VCFHeader header = val.getValue();
+ for ( String sample : header.getGenotypeSamples() ) {
+ samples.add(GATKVariantContextUtils.mergedSampleName(val.getKey(), sample, mergeOption == GATKVariantContextUtils.GenotypeMergeType.UNIQUIFY));
+ }
+ }
+
+ return samples;
+ }
+
+
+ /**
+ *
+ * @param VCF_Headers
+ * @return false if there are names duplication between the samples names in the VCF headers
+ */
+ public static boolean verifyUniqueSamplesNames(Map<String, VCFHeader> VCF_Headers) {
+ Set<String> samples = new HashSet<String>();
+ for ( Map.Entry<String, VCFHeader> val : VCF_Headers.entrySet() ) {
+ VCFHeader header = val.getValue();
+ for ( String sample : header.getGenotypeSamples() ) {
+ if (samples.contains(sample)){
+
+ return false;
+ }
+ samples.add(sample);
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets the sample names from all VCF rods input by the user and uniquifies them if there is overlap
+ * (e.g. sampleX.1, sampleX.2, ...)
+ * When finished, samples contains the uniquified sample names and rodNamesToSampleNames contains a mapping
+ * from rod/sample pairs to the new uniquified names
+ *
+ * @param toolkit GATK engine
+ * @param samples set to store the sample names
+ * @param rodNamesToSampleNames mapping of rod/sample pairs to new uniquified sample names
+ */
+ public static void getUniquifiedSamplesFromRods(GenomeAnalysisEngine toolkit, Set<String> samples, Map<Pair<String, String>, String> rodNamesToSampleNames) {
+
+ // keep a map of sample name to occurrences encountered
+ HashMap<String, Integer> sampleOverlapMap = new HashMap<String, Integer>();
+
+ // iterate to get all of the sample names
+
+ for ( Map.Entry<String, VCFHeader> pair : GATKVCFUtils.getVCFHeadersFromRods(toolkit).entrySet() ) {
+ for ( String sample : pair.getValue().getGenotypeSamples() )
+ addUniqueSample(samples, sampleOverlapMap, rodNamesToSampleNames, sample, pair.getKey());
+ }
+ }
+
+ private static void addUniqueSample(Set<String> samples, Map<String, Integer> sampleOverlapMap, Map<Pair<String, String>, String> rodNamesToSampleNames, String newSample, String rodName) {
+
+ // how many occurrences have we seen so far?
+ Integer occurrences = sampleOverlapMap.get(newSample);
+
+ // if this is the first one, just add it to the list of samples
+ if ( occurrences == null ) {
+ samples.add(newSample);
+ rodNamesToSampleNames.put(new Pair<String, String>(rodName, newSample), newSample);
+ sampleOverlapMap.put(newSample, 1);
+ }
+
+ // if it's already been seen multiple times, give it a unique suffix and increment the value
+ else if ( occurrences >= 2 ) {
+ String uniqueName = newSample + "." + rodName;
+ samples.add(uniqueName);
+ rodNamesToSampleNames.put(new Pair<String, String>(rodName, newSample), uniqueName);
+ sampleOverlapMap.put(newSample, occurrences + 1);
+ }
+
+ // if this is the second occurrence of the sample name, uniquify both of them
+ else { // occurrences == 2
+
+ // remove the 1st occurrence, uniquify it, and add it back
+ samples.remove(newSample);
+ String uniqueName1 = null;
+ for ( Map.Entry<Pair<String, String>, String> entry : rodNamesToSampleNames.entrySet() ) {
+ if ( entry.getValue().equals(newSample) ) {
+ uniqueName1 = newSample + "." + entry.getKey().first;
+ entry.setValue(uniqueName1);
+ break;
+ }
+ }
+ samples.add(uniqueName1);
+
+ // add the second one
+ String uniqueName2 = newSample + "." + rodName;
+ samples.add(uniqueName2);
+ rodNamesToSampleNames.put(new Pair<String, String>(rodName, newSample), uniqueName2);
+
+ sampleOverlapMap.put(newSample, 2);
+ }
+
+ }
+
+ /**
+ * Returns a new set of samples, containing a final list of samples expanded from sampleArgs
+ *
+ * Each element E of sampleArgs can either be a literal sample name or a file. For each E,
+ * we try to read a file named E from disk, and if possible all lines from that file are expanded
+ * into unique sample names.
+ *
+ * @param sampleArgs args
+ * @return samples
+ */
+ public static Set<String> getSamplesFromCommandLineInput(Collection<String> sampleArgs) {
+ if (sampleArgs != null) {
+ return ListFileUtils.unpackSet(sampleArgs);
+ }
+
+ return new HashSet<String>();
+ }
+
+ public static Set<String> getSamplesFromCommandLineInput(Collection<String> vcfSamples, Collection<String> sampleExpressions) {
+ Set<String> samples = ListFileUtils.unpackSet(vcfSamples);
+ if (sampleExpressions == null) {
+ return samples;
+ } else {
+ return ListFileUtils.includeMatching(samples, sampleExpressions, false);
+ }
+ }
+
+ /**
+ * Given a collection of samples and a collection of regular expressions, generates the set of samples that match each expression
+ * @param originalSamples list of samples to select samples from
+ * @param sampleExpressions list of expressions to use for matching samples
+ * @return the set of samples from originalSamples that satisfy at least one of the expressions in sampleExpressions
+ */
+ public static Collection<String> matchSamplesExpressions (Collection<String> originalSamples, Collection<String> sampleExpressions) {
+ // Now, check the expressions that weren't used in the previous step, and use them as if they're regular expressions
+ Set<String> samples = new HashSet<String>();
+ if (sampleExpressions != null) {
+ samples.addAll(ListFileUtils.includeMatching(originalSamples, sampleExpressions, false));
+ }
+ return samples;
+ }
+
+ /**
+ * Given a list of files with sample names it reads all files and creates a list of unique samples from all these files.
+ * @param files list of files with sample names in
+ * @return a collection of unique samples from all files
+ */
+ public static Collection<String> getSamplesFromFiles (Collection<File> files) {
+ Set<String> samplesFromFiles = new HashSet<String>();
+ if (files != null) {
+ for (File file : files) {
+ try {
+ XReadLines reader = new XReadLines(file);
+ List<String> lines = reader.readLines();
+ for (String line : lines) {
+ samplesFromFiles.add(line);
+ }
+ } catch (FileNotFoundException e) {
+ throw new UserException.CouldNotReadInputFile(file, e);
+ }
+ }
+ }
+ return samplesFromFiles;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/SequenceDictionaryUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/SequenceDictionaryUtils.java
new file mode 100644
index 0000000..d869037
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/SequenceDictionaryUtils.java
@@ -0,0 +1,527 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: Sep 10, 2010
+ * Time: 1:56:24 PM
+ *
+ * A series of utility functions that enable the GATK to compare two sequence dictionaries -- from the reference,
+ * from BAMs, or from RODs -- for consistency. The system supports two basic modes: get an enum state that
+ * describes at a high level the consistency between two dictionaries, or a validateDictionaries that will
+ * blow up with a UserException if the dicts are too incompatible.
+ *
+ * Dictionaries are tested for contig name overlaps, consistency in ordering in these overlap set, and length,
+ * if available. Examines the Engine arguments to decided if the -U option to allow danger seq dict inconsistency
+ * is enabled before it blows up.
+ */
+public class SequenceDictionaryUtils {
+ //
+ // for detecting lexicographically sorted human references
+ //
+ private static final boolean ENABLE_LEXICOGRAPHIC_REQUIREMENT_FOR_HUMAN = true;
+
+ // hg18
+ protected static final SAMSequenceRecord CHR1_HG18 = new SAMSequenceRecord("chr1", 247249719);
+ protected static final SAMSequenceRecord CHR2_HG18 = new SAMSequenceRecord("chr2", 242951149);
+ protected static final SAMSequenceRecord CHR10_HG18 = new SAMSequenceRecord("chr10", 135374737);
+
+ // hg19
+ protected static final SAMSequenceRecord CHR1_HG19 = new SAMSequenceRecord("chr1", 249250621);
+ protected static final SAMSequenceRecord CHR2_HG19 = new SAMSequenceRecord("chr2", 243199373);
+ protected static final SAMSequenceRecord CHR10_HG19 = new SAMSequenceRecord("chr10", 135534747);
+
+ // b36
+ protected static final SAMSequenceRecord CHR1_B36 = new SAMSequenceRecord("1", 247249719);
+ protected static final SAMSequenceRecord CHR2_B36 = new SAMSequenceRecord("2", 242951149);
+ protected static final SAMSequenceRecord CHR10_B36 = new SAMSequenceRecord("10", 135374737);
+
+ // b37
+ protected static final SAMSequenceRecord CHR1_B37 = new SAMSequenceRecord("1", 249250621);
+ protected static final SAMSequenceRecord CHR2_B37 = new SAMSequenceRecord("2", 243199373);
+ protected static final SAMSequenceRecord CHR10_B37 = new SAMSequenceRecord("10", 135534747);
+
+
+ public enum SequenceDictionaryCompatibility {
+ IDENTICAL, // the dictionaries are identical
+ COMMON_SUBSET, // there exists a common subset of equivalent contigs
+ NO_COMMON_CONTIGS, // no overlap between dictionaries
+ UNEQUAL_COMMON_CONTIGS, // common subset has contigs that have the same name but different lengths
+ NON_CANONICAL_HUMAN_ORDER, // human reference detected but the order of the contigs is non-standard (lexicographic, for examine)
+ OUT_OF_ORDER, // the two dictionaries overlap but the overlapping contigs occur in different
+ // orders with respect to each other
+ DIFFERENT_INDICES // the two dictionaries overlap and the overlapping contigs occur in the same
+ // order with respect to each other, but one or more of them have different
+ // indices in the two dictionaries. Eg., { chrM, chr1, chr2 } vs. { chr1, chr2 }
+ }
+
+ /**
+ * @param validationExclusion exclusions to validation
+ * @return Returns true if the engine is in tolerant mode and we'll let through dangerous but not fatal dictionary inconsistency
+ */
+ private static boolean allowNonFatalIncompabilities(ValidationExclusion.TYPE validationExclusion) {
+ return ( validationExclusion == ValidationExclusion.TYPE.ALLOW_SEQ_DICT_INCOMPATIBILITY ||
+ validationExclusion == ValidationExclusion.TYPE.ALL );
+ }
+
+ /**
+ * Tests for compatibility between two sequence dictionaries. If the dictionaries are incompatible, then
+ * UserExceptions are thrown with detailed error messages. If the engine is in permissive mode, then
+ * logger warnings are generated instead.
+ *
+ * @param logger for warnings
+ * @param validationExclusion exclusions to validation
+ * @param name1 name associated with dict1
+ * @param dict1 the sequence dictionary dict1
+ * @param name2 name associated with dict2
+ * @param dict2 the sequence dictionary dict2
+ * @param isReadsToReferenceComparison true if one of the dictionaries comes from a reads data source (eg., a BAM),
+ * and the other from a reference data source
+ * @param intervals the user-specified genomic intervals: only required when isReadsToReferenceComparison is true,
+ * otherwise can be null
+ */
+ public static void validateDictionaries( final Logger logger,
+ final ValidationExclusion.TYPE validationExclusion,
+ final String name1,
+ final SAMSequenceDictionary dict1,
+ final String name2,
+ final SAMSequenceDictionary dict2,
+ final boolean isReadsToReferenceComparison,
+ final GenomeLocSortedSet intervals ) {
+
+ final SequenceDictionaryCompatibility type = compareDictionaries(dict1, dict2);
+
+ switch ( type ) {
+ case IDENTICAL:
+ return;
+ case COMMON_SUBSET:
+ return;
+ case NO_COMMON_CONTIGS:
+ throw new UserException.IncompatibleSequenceDictionaries("No overlapping contigs found", name1, dict1, name2, dict2);
+
+ case UNEQUAL_COMMON_CONTIGS: {
+ List<SAMSequenceRecord> x = findDisequalCommonContigs(getCommonContigsByName(dict1, dict2), dict1, dict2);
+ SAMSequenceRecord elt1 = x.get(0);
+ SAMSequenceRecord elt2 = x.get(1);
+
+ // todo -- replace with toString when SAMSequenceRecord has a nice toString routine
+ UserException ex = new UserException.IncompatibleSequenceDictionaries(String.format("Found contigs with the same name but different lengths:\n contig %s = %s / %d\n contig %s = %s / %d",
+ name1, elt1.getSequenceName(), elt1.getSequenceLength(),
+ name2, elt2.getSequenceName(), elt2.getSequenceLength()),
+ name1, dict1, name2, dict2);
+
+ if ( allowNonFatalIncompabilities(validationExclusion) )
+ logger.warn(ex.getMessage());
+ else
+ throw ex;
+ break;
+ }
+
+ case NON_CANONICAL_HUMAN_ORDER: {
+ UserException ex;
+ if ( nonCanonicalHumanContigOrder(dict1) )
+ ex = new UserException.LexicographicallySortedSequenceDictionary(name1, dict1);
+ else
+ ex = new UserException.LexicographicallySortedSequenceDictionary(name2, dict2);
+
+ if ( allowNonFatalIncompabilities(validationExclusion) )
+ logger.warn(ex.getMessage());
+ else
+ throw ex;
+ break;
+ }
+
+ case OUT_OF_ORDER: {
+ UserException ex = new UserException.IncompatibleSequenceDictionaries("Relative ordering of overlapping contigs differs, which is unsafe", name1, dict1, name2, dict2);
+ if ( allowNonFatalIncompabilities(validationExclusion) )
+ logger.warn(ex.getMessage());
+ else
+ throw ex;
+ break;
+ }
+
+ case DIFFERENT_INDICES: {
+ // This is currently only known to be problematic when the index mismatch is between a bam and the
+ // reference AND when the user's intervals actually include one or more of the contigs that are
+ // indexed differently from the reference. In this case, the engine will fail to correctly serve
+ // up the reads from those contigs, so throw an exception unless unsafe operations are enabled.
+ if ( isReadsToReferenceComparison && intervals != null ) {
+
+ final Set<String> misindexedContigs = findMisindexedContigsInIntervals(intervals, dict1, dict2);
+
+ if ( ! misindexedContigs.isEmpty() ) {
+ final String msg = String.format("The following contigs included in the intervals to process have " +
+ "different indices in the sequence dictionaries for the reads vs. " +
+ "the reference: %s. As a result, the GATK engine will not correctly " +
+ "process reads from these contigs. You should either fix the sequence " +
+ "dictionaries for your reads so that these contigs have the same indices " +
+ "as in the sequence dictionary for your reference, or exclude these contigs " +
+ "from your intervals. This error can be disabled via -U %s, " +
+ "however this is not recommended as the GATK engine will not behave correctly.",
+ misindexedContigs, ValidationExclusion.TYPE.ALLOW_SEQ_DICT_INCOMPATIBILITY);
+ final UserException ex = new UserException.IncompatibleSequenceDictionaries(msg, name1, dict1, name2, dict2);
+
+ if ( allowNonFatalIncompabilities(validationExclusion) )
+ logger.warn(ex.getMessage());
+ else
+ throw ex;
+ }
+ }
+ break;
+ }
+
+ default:
+ throw new ReviewedGATKException("Unexpected SequenceDictionaryComparison type: " + type);
+ }
+ }
+
+ /**
+ * Workhorse routine that takes two dictionaries and returns their compatibility.
+ *
+ * @param dict1 first sequence dictionary
+ * @param dict2 second sequence dictionary
+ * @return A SequenceDictionaryCompatibility enum value describing the compatibility of the two dictionaries
+ */
+ public static SequenceDictionaryCompatibility compareDictionaries( final SAMSequenceDictionary dict1, final SAMSequenceDictionary dict2) {
+ if ( nonCanonicalHumanContigOrder(dict1) || nonCanonicalHumanContigOrder(dict2) )
+ return SequenceDictionaryCompatibility.NON_CANONICAL_HUMAN_ORDER;
+
+ final Set<String> commonContigs = getCommonContigsByName(dict1, dict2);
+
+ if (commonContigs.size() == 0)
+ return SequenceDictionaryCompatibility.NO_COMMON_CONTIGS;
+ else if ( ! commonContigsHaveSameLengths(commonContigs, dict1, dict2) )
+ return SequenceDictionaryCompatibility.UNEQUAL_COMMON_CONTIGS;
+ else if ( ! commonContigsAreInSameRelativeOrder(commonContigs, dict1, dict2) )
+ return SequenceDictionaryCompatibility.OUT_OF_ORDER;
+ else if ( commonContigs.size() == dict1.size() && commonContigs.size() == dict2.size() )
+ return SequenceDictionaryCompatibility.IDENTICAL;
+ else if ( ! commonContigsAreAtSameIndices(commonContigs, dict1, dict2) )
+ return SequenceDictionaryCompatibility.DIFFERENT_INDICES;
+ else {
+ return SequenceDictionaryCompatibility.COMMON_SUBSET;
+ }
+ }
+
+ /**
+ * Utility function that tests whether the commonContigs in both dicts are equivalent. Equivalence means
+ * that the seq records have the same length, if both are non-zero.
+ *
+ * @param commonContigs
+ * @param dict1
+ * @param dict2
+ * @return true if all of the common contigs are equivalent
+ */
+ private static boolean commonContigsHaveSameLengths(Set<String> commonContigs, SAMSequenceDictionary dict1, SAMSequenceDictionary dict2) {
+ return findDisequalCommonContigs(commonContigs, dict1, dict2) == null;
+ }
+
+ /**
+ * Returns a List(x,y) that contains two disequal sequence records among the common contigs in both dicts. Returns
+ * null if all common contigs are equivalent
+ *
+ * @param commonContigs
+ * @param dict1
+ * @param dict2
+ * @return
+ */
+ private static List<SAMSequenceRecord> findDisequalCommonContigs(Set<String> commonContigs, SAMSequenceDictionary dict1, SAMSequenceDictionary dict2) {
+ for ( String name : commonContigs ) {
+ SAMSequenceRecord elt1 = dict1.getSequence(name);
+ SAMSequenceRecord elt2 = dict2.getSequence(name);
+ if ( ! sequenceRecordsAreEquivalent(elt1, elt2) )
+ return Arrays.asList(elt1,elt2);
+ }
+
+ return null;
+ }
+
+ /**
+ * Helper routine that returns two sequence records are equivalent, defined as having the same name and
+ * lengths, if both are non-zero
+ *
+ * @param me
+ * @param that
+ * @return
+ */
+ private static boolean sequenceRecordsAreEquivalent(final SAMSequenceRecord me, final SAMSequenceRecord that) {
+ if (me == that) return true;
+ if (that == null) return false;
+
+ if (me.getSequenceLength() != 0 && that.getSequenceLength() != 0 && me.getSequenceLength() != that.getSequenceLength())
+ return false;
+
+ // todo -- reenable if we want to be really strict here
+// if (me.getExtendedAttribute(SAMSequenceRecord.MD5_TAG) != null && that.getExtendedAttribute(SAMSequenceRecord.MD5_TAG) != null) {
+// final BigInteger thisMd5 = new BigInteger((String)me.getExtendedAttribute(SAMSequenceRecord.MD5_TAG), 16);
+// final BigInteger thatMd5 = new BigInteger((String)that.getExtendedAttribute(SAMSequenceRecord.MD5_TAG), 16);
+// if (!thisMd5.equals(thatMd5)) {
+// return false;
+// }
+// }
+// else {
+ if (me.getSequenceName() != that.getSequenceName())
+ return false; // Compare using == since we intern() the Strings
+// }
+
+ return true;
+ }
+
+ /**
+ * A very simple (and naive) algorithm to determine (1) if the dict is a human reference (hg18/hg19) and if it's
+ * lexicographically sorted. Works by matching lengths of the static chr1, chr10, and chr2, and then if these
+ * are all matched, requiring that the order be chr1, chr2, chr10.
+ *
+ * @param dict
+ * @return
+ */
+ private static boolean nonCanonicalHumanContigOrder(SAMSequenceDictionary dict) {
+ if ( ! ENABLE_LEXICOGRAPHIC_REQUIREMENT_FOR_HUMAN ) // if we don't want to enable this test, just return false
+ return false;
+
+ SAMSequenceRecord chr1 = null, chr2 = null, chr10 = null;
+
+ for ( SAMSequenceRecord elt : dict.getSequences() ) {
+ if ( isHumanSeqRecord(elt, CHR1_HG18, CHR1_HG19 ) ) chr1 = elt;
+ if ( isHumanSeqRecord(elt, CHR2_HG18, CHR2_HG19 ) ) chr2 = elt;
+ if ( isHumanSeqRecord(elt, CHR10_HG18, CHR10_HG19 ) ) chr10 = elt;
+ }
+
+ if ( chr1 != null && chr2 != null && chr10 != null) {
+ // we found them all
+ return ! ( chr1.getSequenceIndex() < chr2.getSequenceIndex() && chr2.getSequenceIndex() < chr10.getSequenceIndex() );
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Trivial helper that returns true if elt has the same length as rec1 or rec2
+ * @param elt record to test
+ * @param rec1 first record to test for length equivalence
+ * @param rec2 first record to test for length equivalence
+ * @return true if elt has the same length as either rec1 or rec2
+ */
+ private static boolean isHumanSeqRecord(SAMSequenceRecord elt, SAMSequenceRecord rec1, SAMSequenceRecord rec2 ) {
+ return elt.getSequenceLength() == rec1.getSequenceLength() || elt.getSequenceLength() == rec2.getSequenceLength();
+ }
+
+ /**
+ * Returns true if the common contigs in dict1 and dict2 are in the same relative order, without regard to
+ * absolute index position. This is accomplished by getting the common contigs in both dictionaries, sorting
+ * these according to their indices, and then walking through the sorted list to ensure that each ordered contig
+ * is equivalent
+ *
+ * @param commonContigs names of the contigs common to both dictionaries
+ * @param dict1 first SAMSequenceDictionary
+ * @param dict2 second SAMSequenceDictionary
+ * @return true if the common contigs occur in the same relative order in both dict1 and dict2, otherwise false
+ */
+ private static boolean commonContigsAreInSameRelativeOrder(Set<String> commonContigs, SAMSequenceDictionary dict1, SAMSequenceDictionary dict2) {
+ List<SAMSequenceRecord> list1 = sortSequenceListByIndex(getSequencesOfName(commonContigs, dict1));
+ List<SAMSequenceRecord> list2 = sortSequenceListByIndex(getSequencesOfName(commonContigs, dict2));
+
+ for ( int i = 0; i < list1.size(); i++ ) {
+ SAMSequenceRecord elt1 = list1.get(i);
+ SAMSequenceRecord elt2 = list2.get(i);
+ if ( ! elt1.getSequenceName().equals(elt2.getSequenceName()) )
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets the subset of SAMSequenceRecords in commonContigs in dict
+ *
+ * @param commonContigs
+ * @param dict
+ * @return
+ */
+ private static List<SAMSequenceRecord> getSequencesOfName(Set<String> commonContigs, SAMSequenceDictionary dict) {
+ List<SAMSequenceRecord> l = new ArrayList<SAMSequenceRecord>(commonContigs.size());
+ for ( String name : commonContigs ) {
+ l.add(dict.getSequence(name) );
+ }
+
+ return l;
+ }
+
+ /**
+ * Compares sequence records by their order
+ */
+ private static class CompareSequenceRecordsByIndex implements Comparator<SAMSequenceRecord> {
+ public int compare(SAMSequenceRecord x, SAMSequenceRecord y) {
+ return Integer.valueOf(x.getSequenceIndex()).compareTo(y.getSequenceIndex());
+ }
+ }
+
+ /**
+ * Returns a sorted list of SAMSequenceRecords sorted by their indices. Note that the
+ * list is modified in place, so the returned list is == to the unsorted list.
+ *
+ * @param unsorted
+ * @return
+ */
+ private static List<SAMSequenceRecord> sortSequenceListByIndex(List<SAMSequenceRecord> unsorted) {
+ Collections.sort(unsorted, new CompareSequenceRecordsByIndex());
+ return unsorted;
+ }
+
+ /**
+ * Checks whether the common contigs in the given sequence dictionaries occur at the same indices
+ * in both dictionaries
+ *
+ * @param commonContigs Set of names of the contigs that occur in both dictionaries
+ * @param dict1 first sequence dictionary
+ * @param dict2 second sequence dictionary
+ * @return true if the contigs common to dict1 and dict2 occur at the same indices in both dictionaries,
+ * otherwise false
+ */
+ private static boolean commonContigsAreAtSameIndices( final Set<String> commonContigs, final SAMSequenceDictionary dict1, final SAMSequenceDictionary dict2 ) {
+ for ( String commonContig : commonContigs ) {
+ SAMSequenceRecord dict1Record = dict1.getSequence(commonContig);
+ SAMSequenceRecord dict2Record = dict2.getSequence(commonContig);
+
+ // Each common contig must have the same index in both dictionaries
+ if ( dict1Record.getSequenceIndex() != dict2Record.getSequenceIndex() ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets the set of names of the contigs found in both sequence dictionaries that have different indices
+ * in the two dictionaries.
+ *
+ * @param commonContigs Set of names of the contigs common to both dictionaries
+ * @param dict1 first sequence dictionary
+ * @param dict2 second sequence dictionary
+ * @return a Set containing the names of the common contigs indexed differently in dict1 vs. dict2,
+ * or an empty Set if there are no such contigs
+ */
+ private static Set<String> getDifferentlyIndexedCommonContigs( final Set<String> commonContigs,
+ final SAMSequenceDictionary dict1,
+ final SAMSequenceDictionary dict2 ) {
+
+ final Set<String> differentlyIndexedCommonContigs = new LinkedHashSet<String>(Utils.optimumHashSize(commonContigs.size()));
+
+ for ( String commonContig : commonContigs ) {
+ if ( dict1.getSequence(commonContig).getSequenceIndex() != dict2.getSequence(commonContig).getSequenceIndex() ) {
+ differentlyIndexedCommonContigs.add(commonContig);
+ }
+ }
+
+ return differentlyIndexedCommonContigs;
+ }
+
+ /**
+ * Finds the names of any contigs indexed differently in the two sequence dictionaries that also
+ * occur in the provided set of intervals.
+ *
+ * @param intervals GenomeLocSortedSet containing the intervals to check
+ * @param dict1 first sequence dictionary
+ * @param dict2 second sequence dictionary
+ * @return a Set of the names of the contigs indexed differently in dict1 vs dict2 that also
+ * occur in the provided intervals, or an empty Set if there are no such contigs
+ */
+ private static Set<String> findMisindexedContigsInIntervals( final GenomeLocSortedSet intervals,
+ final SAMSequenceDictionary dict1,
+ final SAMSequenceDictionary dict2 ) {
+
+ final Set<String> differentlyIndexedCommonContigs = getDifferentlyIndexedCommonContigs(getCommonContigsByName(dict1, dict2), dict1, dict2);
+ final Set<String> misindexedContigsInIntervals = new LinkedHashSet<String>(Utils.optimumHashSize(differentlyIndexedCommonContigs.size()));
+
+ // We know differentlyIndexedCommonContigs is a HashSet, so this loop is O(intervals)
+ for ( GenomeLoc interval : intervals ) {
+ if ( differentlyIndexedCommonContigs.contains(interval.getContig()) ) {
+ misindexedContigsInIntervals.add(interval.getContig());
+ }
+ }
+
+ return misindexedContigsInIntervals;
+ }
+
+ /**
+ * Returns the set of contig names found in both dicts.
+ * @param dict1
+ * @param dict2
+ * @return
+ */
+ public static Set<String> getCommonContigsByName(SAMSequenceDictionary dict1, SAMSequenceDictionary dict2) {
+ Set<String> intersectingSequenceNames = getContigNames(dict1);
+ intersectingSequenceNames.retainAll(getContigNames(dict2));
+ return intersectingSequenceNames;
+ }
+
+ public static Set<String> getContigNames(SAMSequenceDictionary dict) {
+ Set<String> contigNames = new HashSet<String>(Utils.optimumHashSize(dict.size()));
+ for (SAMSequenceRecord dictionaryEntry : dict.getSequences())
+ contigNames.add(dictionaryEntry.getSequenceName());
+ return contigNames;
+ }
+
+ /**
+ * Returns a compact String representation of the sequence dictionary it's passed
+ *
+ * The format of the returned String is:
+ * [ contig1Name(length: contig1Length) contig2Name(length: contig2Length) ... ]
+ *
+ * @param dict a non-null SAMSequenceDictionary
+ * @return A String containing all of the contig names and lengths from the sequence dictionary it's passed
+ */
+ public static String getDictionaryAsString( final SAMSequenceDictionary dict ) {
+ if ( dict == null ) {
+ throw new IllegalArgumentException("Sequence dictionary must be non-null");
+ }
+
+ StringBuilder s = new StringBuilder("[ ");
+
+ for ( SAMSequenceRecord dictionaryEntry : dict.getSequences() ) {
+ s.append(dictionaryEntry.getSequenceName());
+ s.append("(length:");
+ s.append(dictionaryEntry.getSequenceLength());
+ s.append(") ");
+ }
+
+ s.append("]");
+
+ return s.toString();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/UnvalidatingGenomeLoc.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/UnvalidatingGenomeLoc.java
new file mode 100644
index 0000000..2c3d24b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/UnvalidatingGenomeLoc.java
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import com.google.java.contract.Requires;
+
+/**
+ * GenomeLocs are very useful objects to keep track of genomic locations and perform set operations
+ * with them.
+ *
+ * However, GenomeLocs are bound to strict validation through the GenomeLocParser and cannot
+ * be created easily for small tasks that do not require the rigors of the GenomeLocParser validation
+ *
+ * UnvalidatingGenomeLoc is a simple utility to create GenomeLocs without going through the parser.
+ *
+ * WARNING: SHOULD BE USED ONLY BY EXPERT USERS WHO KNOW WHAT THEY ARE DOING!
+ *
+ * User: carneiro
+ * Date: 10/16/12
+ * Time: 2:07 PM
+ */
+public class UnvalidatingGenomeLoc extends GenomeLoc {
+
+ public UnvalidatingGenomeLoc(String contigName, int contigIndex, int start, int stop) {
+ super(contigName, contigIndex, start, stop);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/Utils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/Utils.java
new file mode 100644
index 0000000..d664ef6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/Utils.java
@@ -0,0 +1,1186 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMProgramRecord;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.io.GATKSAMFileWriter;
+import org.broadinstitute.gatk.utils.text.TextFormattingUtils;
+
+import java.lang.reflect.Array;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: Feb 24, 2009
+ * Time: 10:12:31 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class Utils {
+ /** our log, which we want to capture anything from this class */
+ private static Logger logger = Logger.getLogger(Utils.class);
+
+ public static final float JAVA_DEFAULT_HASH_LOAD_FACTOR = 0.75f;
+
+ /**
+ * Boolean xor operation. Only true if x != y.
+ *
+ * @param x a boolean
+ * @param y a boolean
+ * @return true if x != y
+ */
+ public static boolean xor(final boolean x, final boolean y) {
+ return x != y;
+ }
+
+ /**
+ * Calculates the optimum initial size for a hash table given the maximum number
+ * of elements it will need to hold. The optimum size is the smallest size that
+ * is guaranteed not to result in any rehash/table-resize operations.
+ *
+ * @param maxElements The maximum number of elements you expect the hash table
+ * will need to hold
+ * @return The optimum initial size for the table, given maxElements
+ */
+ public static int optimumHashSize ( int maxElements ) {
+ return (int)(maxElements / JAVA_DEFAULT_HASH_LOAD_FACTOR) + 2;
+ }
+
+ /**
+ * Compares two objects, either of which might be null.
+ *
+ * @param lhs One object to compare.
+ * @param rhs The other object to compare.
+ *
+ * @return True if the two objects are equal, false otherwise.
+ */
+ public static boolean equals(Object lhs, Object rhs) {
+ return lhs == null && rhs == null || lhs != null && lhs.equals(rhs);
+ }
+
+ public static <T> List<T> cons(final T elt, final List<T> l) {
+ List<T> l2 = new ArrayList<T>();
+ l2.add(elt);
+ if (l != null) l2.addAll(l);
+ return l2;
+ }
+
+ public static void warnUser(final String msg) {
+ warnUser(logger, msg);
+ }
+
+ public static void warnUser(final Logger logger, final String msg) {
+ logger.warn(String.format("********************************************************************************"));
+ logger.warn(String.format("* WARNING:"));
+ logger.warn(String.format("*"));
+ prettyPrintWarningMessage(logger, msg);
+ logger.warn(String.format("********************************************************************************"));
+ }
+
+ /**
+ * pretty print the warning message supplied
+ *
+ * @param logger logger for the message
+ * @param message the message
+ */
+ private static void prettyPrintWarningMessage(Logger logger, String message) {
+ StringBuilder builder = new StringBuilder(message);
+ while (builder.length() > 70) {
+ int space = builder.lastIndexOf(" ", 70);
+ if (space <= 0) space = 70;
+ logger.warn(String.format("* %s", builder.substring(0, space)));
+ builder.delete(0, space + 1);
+ }
+ logger.warn(String.format("* %s", builder));
+ }
+
+ /**
+ * join the key value pairs of a map into one string, i.e. myMap = [A->1,B->2,C->3] with a call of:
+ * joinMap("-","*",myMap) -> returns A-1*B-2*C-3
+ *
+ * Be forewarned, if you're not using a map that is aware of the ordering (i.e. HashMap instead of LinkedHashMap)
+ * the ordering of the string you get back might not be what you expect! (i.e. C-3*A-1*B-2 vrs A-1*B-2*C-3)
+ *
+ * @param keyValueSeperator the string to seperate the key-value pairs
+ * @param recordSeperator the string to use to seperate each key-value pair from other key-value pairs
+ * @param map the map to draw from
+ * @param <L> the map's key type
+ * @param <R> the map's value type
+ * @return a string representing the joined map
+ */
+ public static <L,R> String joinMap(String keyValueSeperator, String recordSeperator, Map<L,R> map) {
+ if (map.size() < 1) { return null; }
+ String joinedKeyValues[] = new String[map.size()];
+ int index = 0;
+ for (L key : map.keySet()) {
+ joinedKeyValues[index++] = String.format("%s%s%s",key.toString(),keyValueSeperator,map.get(key).toString());
+ }
+ return join(recordSeperator,joinedKeyValues);
+ }
+
+ /**
+ * Splits a String using indexOf instead of regex to speed things up.
+ *
+ * @param str the string to split.
+ * @param delimiter the delimiter used to split the string.
+ * @return an array of tokens.
+ */
+ public static ArrayList<String> split(String str, String delimiter) {
+ return split(str, delimiter, 10);
+ }
+
+ /**
+ * Splits a String using indexOf instead of regex to speed things up.
+ *
+ * @param str the string to split.
+ * @param delimiter the delimiter used to split the string.
+ * @param expectedNumTokens The number of tokens expected. This is used to initialize the ArrayList.
+ * @return an array of tokens.
+ */
+ public static ArrayList<String> split(String str, String delimiter, int expectedNumTokens) {
+ final ArrayList<String> result = new ArrayList<String>(expectedNumTokens);
+
+ int delimiterIdx = -1;
+ do {
+ final int tokenStartIdx = delimiterIdx + 1;
+ delimiterIdx = str.indexOf(delimiter, tokenStartIdx);
+ final String token = (delimiterIdx != -1 ? str.substring(tokenStartIdx, delimiterIdx) : str.substring(tokenStartIdx) );
+ result.add(token);
+ } while( delimiterIdx != -1 );
+
+ return result;
+ }
+
+
+ /**
+ * join an array of strings given a seperator
+ * @param separator the string to insert between each array element
+ * @param strings the array of strings
+ * @return a string, which is the joining of all array values with the separator
+ */
+ public static String join(String separator, String[] strings) {
+ return join(separator, strings, 0, strings.length);
+ }
+
+ public static String join(String separator, String[] strings, int start, int end) {
+ if ((end - start) == 0) {
+ return "";
+ }
+ StringBuilder ret = new StringBuilder(strings[start]);
+ for (int i = start + 1; i < end; ++i) {
+ ret.append(separator);
+ ret.append(strings[i]);
+ }
+ return ret.toString();
+ }
+
+ public static String join(String separator, int[] ints) {
+ if ( ints == null || ints.length == 0)
+ return "";
+ else {
+ StringBuilder ret = new StringBuilder();
+ ret.append(ints[0]);
+ for (int i = 1; i < ints.length; ++i) {
+ ret.append(separator);
+ ret.append(ints[i]);
+ }
+ return ret.toString();
+ }
+ }
+
+ /**
+ * Create a new list that contains the elements of left along with elements elts
+ * @param left a non-null list of elements
+ * @param elts a varargs vector for elts to append in order to left
+ * @return A newly allocated linked list containing left followed by elts
+ */
+ public static <T> List<T> append(final List<T> left, T ... elts) {
+ final List<T> l = new LinkedList<T>(left);
+ l.addAll(Arrays.asList(elts));
+ return l;
+ }
+
+ /**
+ * Returns a string of the values in joined by separator, such as A,B,C
+ *
+ * @param separator separator character
+ * @param doubles the array with values
+ * @return a string with the values separated by the separator
+ */
+ public static String join(String separator, double[] doubles) {
+ if ( doubles == null || doubles.length == 0)
+ return "";
+ else {
+ StringBuilder ret = new StringBuilder();
+ ret.append(doubles[0]);
+ for (int i = 1; i < doubles.length; ++i) {
+ ret.append(separator);
+ ret.append(doubles[i]);
+ }
+ return ret.toString();
+ }
+ }
+
+ /**
+ * Returns a string of the form elt1.toString() [sep elt2.toString() ... sep elt.toString()] for a collection of
+ * elti objects (note there's no actual space between sep and the elti elements). Returns
+ * "" if collection is empty. If collection contains just elt, then returns elt.toString()
+ *
+ * @param separator the string to use to separate objects
+ * @param objects a collection of objects. the element order is defined by the iterator over objects
+ * @param <T> the type of the objects
+ * @return a non-null string
+ */
+ public static <T> String join(final String separator, final Collection<T> objects) {
+ if (objects.isEmpty()) { // fast path for empty collection
+ return "";
+ } else {
+ final Iterator<T> iter = objects.iterator();
+ final T first = iter.next();
+
+ if ( ! iter.hasNext() ) // fast path for singleton collections
+ return first.toString();
+ else { // full path for 2+ collection that actually need a join
+ final StringBuilder ret = new StringBuilder(first.toString());
+ while(iter.hasNext()) {
+ ret.append(separator);
+ ret.append(iter.next().toString());
+ }
+ return ret.toString();
+ }
+ }
+ }
+
+ /**
+ * Returns a {@link List List<Integer>} representation of an primitive int array.
+ * @param values the primitive int array to represent.
+ * @return never code {@code null}. The returned list will be unmodifiable yet it will reflect changes in values in the original array yet
+ * you cannot change the values
+ */
+ public static List<Integer> asList(final int ... values) {
+ if (values == null)
+ throw new IllegalArgumentException("the input array cannot be null");
+ return new AbstractList<Integer>() {
+
+ @Override
+ public Integer get(final int index) {
+ return values[index];
+ }
+
+ @Override
+ public int size() {
+ return values.length;
+ }
+ };
+ }
+
+ /**
+ * Returns a {@link List List<Double>} representation of an primitive double array.
+ * @param values the primitive int array to represent.
+ * @return never code {@code null}. The returned list will be unmodifiable yet it will reflect changes in values in the original array yet
+ * you cannot change the values.
+ */
+ public static List<Double> asList(final double ... values) {
+ if (values == null)
+ throw new IllegalArgumentException("the input array cannot be null");
+ return new AbstractList<Double>() {
+
+ @Override
+ public Double get(final int index) {
+ return values[index];
+ }
+
+ @Override
+ public int size() {
+ return values.length;
+ }
+ };
+ }
+
+ public static <T> String join(final String separator, final T ... objects) {
+ return join(separator, Arrays.asList(objects));
+ }
+
+ /**
+ * Create a new string thats a n duplicate copies of s
+ * @param s the string to duplicate
+ * @param nCopies how many copies?
+ * @return a string
+ */
+ public static String dupString(final String s, int nCopies) {
+ if ( s == null || s.equals("") ) throw new IllegalArgumentException("Bad s " + s);
+ if ( nCopies < 0 ) throw new IllegalArgumentException("nCopies must be >= 0 but got " + nCopies);
+
+ final StringBuilder b = new StringBuilder();
+ for ( int i = 0; i < nCopies; i++ )
+ b.append(s);
+ return b.toString();
+ }
+
+ public static String dupString(char c, int nCopies) {
+ char[] chars = new char[nCopies];
+ Arrays.fill(chars, c);
+ return new String(chars);
+ }
+
+ public static byte[] dupBytes(byte b, int nCopies) {
+ byte[] bytes = new byte[nCopies];
+ Arrays.fill(bytes, b);
+ return bytes;
+ }
+
+ // trim a string for the given character (i.e. not just whitespace)
+ public static String trim(String str, char ch) {
+ char[] array = str.toCharArray();
+
+
+ int start = 0;
+ while ( start < array.length && array[start] == ch )
+ start++;
+
+ int end = array.length - 1;
+ while ( end > start && array[end] == ch )
+ end--;
+
+ return str.substring(start, end+1);
+ }
+
+ /**
+ * Splits expressions in command args by spaces and returns the array of expressions.
+ * Expressions may use single or double quotes to group any individual expression, but not both.
+ * @param args Arguments to parse.
+ * @return Parsed expressions.
+ */
+ public static String[] escapeExpressions(String args) {
+ // special case for ' and " so we can allow expressions
+ if (args.indexOf('\'') != -1)
+ return escapeExpressions(args, "'");
+ else if (args.indexOf('\"') != -1)
+ return escapeExpressions(args, "\"");
+ else
+ return args.trim().split(" +");
+ }
+
+ /**
+ * Splits expressions in command args by spaces and the supplied delimiter and returns the array of expressions.
+ * @param args Arguments to parse.
+ * @param delimiter Delimiter for grouping expressions.
+ * @return Parsed expressions.
+ */
+ private static String[] escapeExpressions(String args, String delimiter) {
+ String[] command = {};
+ String[] split = args.split(delimiter);
+ String arg;
+ for (int i = 0; i < split.length - 1; i += 2) {
+ arg = split[i].trim();
+ if (arg.length() > 0) // if the unescaped arg has a size
+ command = Utils.concatArrays(command, arg.split(" +"));
+ command = Utils.concatArrays(command, new String[]{split[i + 1]});
+ }
+ arg = split[split.length - 1].trim();
+ if (split.length % 2 == 1) // if the command ends with a delimiter
+ if (arg.length() > 0) // if the last unescaped arg has a size
+ command = Utils.concatArrays(command, arg.split(" +"));
+ return command;
+ }
+
+ /**
+ * Concatenates two String arrays.
+ * @param A First array.
+ * @param B Second array.
+ * @return Concatenation of A then B.
+ */
+ public static String[] concatArrays(String[] A, String[] B) {
+ String[] C = new String[A.length + B.length];
+ System.arraycopy(A, 0, C, 0, A.length);
+ System.arraycopy(B, 0, C, A.length, B.length);
+ return C;
+ }
+
+ /**
+ * Concatenates byte arrays
+ * @return a concat of all bytes in allBytes in order
+ */
+ public static byte[] concat(final byte[] ... allBytes) {
+ int size = 0;
+ for ( final byte[] bytes : allBytes ) size += bytes.length;
+
+ final byte[] c = new byte[size];
+ int offset = 0;
+ for ( final byte[] bytes : allBytes ) {
+ System.arraycopy(bytes, 0, c, offset, bytes.length);
+ offset += bytes.length;
+ }
+
+ return c;
+ }
+
+ /**
+ * Appends String(s) B to array A.
+ * @param A First array.
+ * @param B Strings to append.
+ * @return A with B(s) appended.
+ */
+ public static String[] appendArray(String[] A, String... B) {
+ return concatArrays(A, B);
+ }
+
+ public static <T extends Comparable<T>> List<T> sorted(Collection<T> c) {
+ return sorted(c, false);
+ }
+
+ public static <T extends Comparable<T>> List<T> sorted(Collection<T> c, boolean reverse) {
+ List<T> l = new ArrayList<T>(c);
+ Collections.sort(l);
+ if ( reverse ) Collections.reverse(l);
+ return l;
+ }
+
+ public static <T extends Comparable<T>, V> List<V> sorted(Map<T,V> c) {
+ return sorted(c, false);
+ }
+
+ public static <T extends Comparable<T>, V> List<V> sorted(Map<T,V> c, boolean reverse) {
+ List<T> t = new ArrayList<T>(c.keySet());
+ Collections.sort(t);
+ if ( reverse ) Collections.reverse(t);
+
+ List<V> l = new ArrayList<V>();
+ for ( T k : t ) {
+ l.add(c.get(k));
+ }
+ return l;
+ }
+
+ /**
+ * Reverse a byte array of bases
+ *
+ * @param bases the byte array of bases
+ * @return the reverse of the base byte array
+ */
+ static public byte[] reverse(byte[] bases) {
+ byte[] rcbases = new byte[bases.length];
+
+ for (int i = 0; i < bases.length; i++) {
+ rcbases[i] = bases[bases.length - i - 1];
+ }
+
+ return rcbases;
+ }
+
+ static public <T> List<T> reverse(final List<T> l) {
+ final List<T> newL = new ArrayList<T>(l);
+ Collections.reverse(newL);
+ return newL;
+ }
+
+ /**
+ * Reverse an int array of bases
+ *
+ * @param bases the int array of bases
+ * @return the reverse of the base int array
+ */
+ static public int[] reverse(int[] bases) {
+ int[] rcbases = new int[bases.length];
+
+ for (int i = 0; i < bases.length; i++) {
+ rcbases[i] = bases[bases.length - i - 1];
+ }
+
+ return rcbases;
+ }
+
+ /**
+ * Reverse (NOT reverse-complement!!) a string
+ *
+ * @param bases input string
+ * @return the reversed string
+ */
+ static public String reverse(String bases) {
+ return new String( reverse( bases.getBytes() )) ;
+ }
+
+ public static boolean isFlagSet(int value, int flag) {
+ return ((value & flag) == flag);
+ }
+
+ /**
+ * Helper utility that calls into the InetAddress system to resolve the hostname. If this fails,
+ * unresolvable gets returned instead.
+ */
+ public static String resolveHostname() {
+ try {
+ return InetAddress.getLocalHost().getCanonicalHostName();
+ }
+ catch (java.net.UnknownHostException uhe) { // [beware typo in code sample -dmw]
+ return "unresolvable";
+ // handle exception
+ }
+ }
+
+
+ public static byte [] arrayFromArrayWithLength(byte[] array, int length) {
+ byte [] output = new byte[length];
+ for (int j = 0; j < length; j++)
+ output[j] = array[(j % array.length)];
+ return output;
+ }
+
+ public static void fillArrayWithByte(byte[] array, byte value) {
+ for (int i=0; i<array.length; i++)
+ array[i] = value;
+ }
+
+ /**
+ * Creates a program record for the program, adds it to the list of program records (@PG tags) in the bam file and sets
+ * up the writer with the header and presorted status.
+ *
+ * @param originalHeader original header
+ * @param programRecord the program record for this program
+ */
+ public static SAMFileHeader setupWriter(final SAMFileHeader originalHeader, final SAMProgramRecord programRecord) {
+ final SAMFileHeader header = originalHeader.clone();
+ final List<SAMProgramRecord> oldRecords = header.getProgramRecords();
+ final List<SAMProgramRecord> newRecords = new ArrayList<SAMProgramRecord>(oldRecords.size()+1);
+ for ( SAMProgramRecord record : oldRecords )
+ if ( (programRecord != null && !record.getId().startsWith(programRecord.getId())))
+ newRecords.add(record);
+
+ if (programRecord != null) {
+ newRecords.add(programRecord);
+ header.setProgramRecords(newRecords);
+ }
+ return header;
+ }
+
+ /**
+ * Creates a program record for the program, adds it to the list of program records (@PG tags) in the bam file and returns
+ * the new header to be added to the BAM writer.
+ *
+ * @param toolkit the engine
+ * @param walker the walker object (so we can extract the command line)
+ * @param PROGRAM_RECORD_NAME the name for the PG tag
+ * @return a pre-filled header for the bam writer
+ */
+ public static SAMFileHeader setupWriter(final GenomeAnalysisEngine toolkit, final SAMFileHeader originalHeader, final Object walker, final String PROGRAM_RECORD_NAME) {
+ final SAMProgramRecord programRecord = createProgramRecord(toolkit, walker, PROGRAM_RECORD_NAME);
+ return setupWriter(originalHeader, programRecord);
+ }
+
+ /**
+ * Creates a program record for the program, adds it to the list of program records (@PG tags) in the bam file and sets
+ * up the writer with the header and presorted status.
+ *
+ * @param writer BAM file writer
+ * @param toolkit the engine
+ * @param preSorted whether or not the writer can assume reads are going to be added are already sorted
+ * @param walker the walker object (so we can extract the command line)
+ * @param PROGRAM_RECORD_NAME the name for the PG tag
+ */
+ public static void setupWriter(GATKSAMFileWriter writer, GenomeAnalysisEngine toolkit, SAMFileHeader originalHeader, boolean preSorted, Object walker, String PROGRAM_RECORD_NAME) {
+ SAMFileHeader header = setupWriter(toolkit, originalHeader, walker, PROGRAM_RECORD_NAME);
+ writer.writeHeader(header);
+ writer.setPresorted(preSorted);
+ }
+
+
+ /**
+ * Creates a program record (@PG) tag
+ *
+ * @param toolkit the engine
+ * @param walker the walker object (so we can extract the command line)
+ * @param PROGRAM_RECORD_NAME the name for the PG tag
+ * @return a program record for the tool
+ */
+ public static SAMProgramRecord createProgramRecord(GenomeAnalysisEngine toolkit, Object walker, String PROGRAM_RECORD_NAME) {
+ final SAMProgramRecord programRecord = new SAMProgramRecord(PROGRAM_RECORD_NAME);
+ final ResourceBundle headerInfo = TextFormattingUtils.loadResourceBundle("GATKText");
+ try {
+ final String version = headerInfo.getString("org.broadinstitute.gatk.tools.version");
+ programRecord.setProgramVersion(version);
+ } catch (MissingResourceException e) {
+ // couldn't care less if the resource is missing...
+ }
+ programRecord.setCommandLine(toolkit.createApproximateCommandLineArgumentString(toolkit, walker));
+ return programRecord;
+ }
+
+ /**
+ * Returns the number of combinations represented by this collection
+ * of collection of options.
+ *
+ * For example, if this is [[A, B], [C, D], [E, F, G]] returns 2 * 2 * 3 = 12
+ */
+ @Requires("options != null")
+ public static <T> int nCombinations(final Collection<T>[] options) {
+ int nStates = 1;
+ for ( Collection<T> states : options ) {
+ nStates *= states.size();
+ }
+ return nStates;
+ }
+
+ @Requires("options != null")
+ public static <T> int nCombinations(final List<List<T>> options) {
+ if ( options.isEmpty() )
+ return 0;
+ else {
+ int nStates = 1;
+ for ( Collection<T> states : options ) {
+ nStates *= states.size();
+ }
+ return nStates;
+ }
+ }
+
+ /**
+ * Make all combinations of N size of objects
+ *
+ * if objects = [A, B, C]
+ * if N = 1 => [[A], [B], [C]]
+ * if N = 2 => [[A, A], [B, A], [C, A], [A, B], [B, B], [C, B], [A, C], [B, C], [C, C]]
+ *
+ * @param objects list of objects
+ * @param n size of each combination
+ * @param withReplacement if false, the resulting permutations will only contain unique objects from objects
+ * @return a list with all combinations with size n of objects.
+ */
+ public static <T> List<List<T>> makePermutations(final List<T> objects, final int n, final boolean withReplacement) {
+ final List<List<T>> combinations = new ArrayList<List<T>>();
+
+ if ( n == 1 ) {
+ for ( final T o : objects )
+ combinations.add(Collections.singletonList(o));
+ } else if (n > 1) {
+ final List<List<T>> sub = makePermutations(objects, n - 1, withReplacement);
+ for ( List<T> subI : sub ) {
+ for ( final T a : objects ) {
+ if ( withReplacement || ! subI.contains(a) )
+ combinations.add(Utils.cons(a, subI));
+ }
+ }
+ }
+
+ return combinations;
+ }
+
+ /**
+ * Convenience function that formats the novelty rate as a %.2f string
+ *
+ * @param known number of variants from all that are known
+ * @param all number of all variants
+ * @return a String novelty rate, or NA if all == 0
+ */
+ public static String formattedNoveltyRate(final int known, final int all) {
+ return formattedPercent(all - known, all);
+ }
+
+ /**
+ * Convenience function that formats the novelty rate as a %.2f string
+ *
+ * @param x number of objects part of total that meet some criteria
+ * @param total count of all objects, including x
+ * @return a String percent rate, or NA if total == 0
+ */
+ public static String formattedPercent(final long x, final long total) {
+ return total == 0 ? "NA" : String.format("%.2f", (100.0*x) / total);
+ }
+
+ /**
+ * Convenience function that formats a ratio as a %.2f string
+ *
+ * @param num number of observations in the numerator
+ * @param denom number of observations in the denumerator
+ * @return a String formatted ratio, or NA if all == 0
+ */
+ public static String formattedRatio(final long num, final long denom) {
+ return denom == 0 ? "NA" : String.format("%.2f", num / (1.0 * denom));
+ }
+
+ /**
+ * Adds element from an array into a collection.
+ *
+ * In the event of exception being throw due to some element, <code>dest</code> might have been modified by
+ * the successful addition of element before that one.
+ *
+ * @param dest the destination collection which cannot be <code>null</code> and should be able to accept
+ * the input elements.
+ * @param elements the element to add to <code>dest</code>
+ * @param <T> collection type element.
+ * @throws UnsupportedOperationException if the <tt>add</tt> operation
+ * is not supported by <code>dest</code>.
+ * @throws ClassCastException if the class of any of the elements
+ * prevents it from being added to <code>dest</code>.
+ * @throws NullPointerException if any of the elements is <code>null</code> and <code>dest</code>
+ * does not permit <code>null</code> elements
+ * @throws IllegalArgumentException if some property of any of the elements
+ * prevents it from being added to this collection
+ * @throws IllegalStateException if any of the elements cannot be added at this
+ * time due to insertion restrictions.
+ * @return <code>true</code> if the collection was modified as a result.
+ */
+ public static <T> boolean addAll(Collection<T> dest, T ... elements) {
+ boolean result = false;
+ for (final T e : elements) {
+ result = dest.add(e) | result;
+ }
+ return result;
+ }
+
+ /**
+ * Create a constant map that maps each value in values to itself
+ */
+ public static <T> Map<T, T> makeIdentityFunctionMap(Collection<T> values) {
+ Map<T,T> map = new HashMap<T, T>(values.size());
+ for ( final T value : values )
+ map.put(value, value);
+ return Collections.unmodifiableMap(map);
+ }
+
+ /**
+ * Divides the input list into a list of sublists, which contains group size elements (except potentially the last one)
+ *
+ * list = [A, B, C, D, E]
+ * groupSize = 2
+ * result = [[A, B], [C, D], [E]]
+ *
+ */
+ public static <T> List<List<T>> groupList(final List<T> list, final int groupSize) {
+ if ( groupSize < 1 ) throw new IllegalArgumentException("groupSize >= 1");
+
+ final List<List<T>> subLists = new LinkedList<List<T>>();
+ int n = list.size();
+ for ( int i = 0; i < n; i += groupSize ) {
+ subLists.add(list.subList(i, Math.min(i + groupSize, n)));
+ }
+ return subLists;
+ }
+
+ /**
+ * @see #calcMD5(byte[])
+ */
+ public static String calcMD5(final String s) {
+ return calcMD5(s.getBytes());
+ }
+
+ /**
+ * Calculate the md5 for bytes, and return the result as a 32 character string
+ *
+ * @param bytes the bytes to calculate the md5 of
+ * @return the md5 of bytes, as a 32-character long string
+ */
+ @Ensures({"result != null", "result.length() == 32"})
+ public static String calcMD5(final byte[] bytes) {
+ if ( bytes == null ) throw new IllegalArgumentException("bytes cannot be null");
+ try {
+ final byte[] thedigest = MessageDigest.getInstance("MD5").digest(bytes);
+ final BigInteger bigInt = new BigInteger(1, thedigest);
+
+ String md5String = bigInt.toString(16);
+ while (md5String.length() < 32) md5String = "0" + md5String; // pad to length 32
+ return md5String;
+ }
+ catch ( NoSuchAlgorithmException e ) {
+ throw new IllegalStateException("MD5 digest algorithm not present");
+ }
+ }
+
+ /**
+ * Does big end with the exact sequence of bytes in suffix?
+ *
+ * @param big a non-null byte[] to test if it a prefix + suffix
+ * @param suffix a non-null byte[] to test if it's a suffix of big
+ * @return true if big is proper byte[] composed of some prefix + suffix
+ */
+ public static boolean endsWith(final byte[] big, final byte[] suffix) {
+ if ( big == null ) throw new IllegalArgumentException("big cannot be null");
+ if ( suffix == null ) throw new IllegalArgumentException("suffix cannot be null");
+ return new String(big).endsWith(new String(suffix));
+ }
+
+ /**
+ * Get the length of the longest common prefix of seq1 and seq2
+ * @param seq1 non-null byte array
+ * @param seq2 non-null byte array
+ * @param maxLength the maximum allowed length to return
+ * @return the length of the longest common prefix of seq1 and seq2, >= 0
+ */
+ public static int longestCommonPrefix(final byte[] seq1, final byte[] seq2, final int maxLength) {
+ if ( seq1 == null ) throw new IllegalArgumentException("seq1 is null");
+ if ( seq2 == null ) throw new IllegalArgumentException("seq2 is null");
+ if ( maxLength < 0 ) throw new IllegalArgumentException("maxLength < 0 " + maxLength);
+
+ final int end = Math.min(seq1.length, Math.min(seq2.length, maxLength));
+ for ( int i = 0; i < end; i++ ) {
+ if ( seq1[i] != seq2[i] )
+ return i;
+ }
+ return end;
+ }
+
+ /**
+ * Get the length of the longest common suffix of seq1 and seq2
+ * @param seq1 non-null byte array
+ * @param seq2 non-null byte array
+ * @param maxLength the maximum allowed length to return
+ * @return the length of the longest common suffix of seq1 and seq2, >= 0
+ */
+ public static int longestCommonSuffix(final byte[] seq1, final byte[] seq2, final int maxLength) {
+ if ( seq1 == null ) throw new IllegalArgumentException("seq1 is null");
+ if ( seq2 == null ) throw new IllegalArgumentException("seq2 is null");
+ if ( maxLength < 0 ) throw new IllegalArgumentException("maxLength < 0 " + maxLength);
+
+ final int end = Math.min(seq1.length, Math.min(seq2.length, maxLength));
+ for ( int i = 0; i < end; i++ ) {
+ if ( seq1[seq1.length - i - 1] != seq2[seq2.length - i - 1] )
+ return i;
+ }
+ return end;
+ }
+
+ /**
+ * Trim any number of bases from the front and/or back of an array
+ *
+ * @param seq the sequence to trim
+ * @param trimFromFront how much to trim from the front
+ * @param trimFromBack how much to trim from the back
+ * @return a non-null array; can be the original array (i.e. not a copy)
+ */
+ public static byte[] trimArray(final byte[] seq, final int trimFromFront, final int trimFromBack) {
+ if ( trimFromFront + trimFromBack > seq.length )
+ throw new IllegalArgumentException("trimming total is larger than the original array");
+
+ // don't perform array copies if we need to copy everything anyways
+ return ( trimFromFront == 0 && trimFromBack == 0 ) ? seq : Arrays.copyOfRange(seq, trimFromFront, seq.length - trimFromBack);
+ }
+
+ /**
+ * Simple wrapper for sticking elements of a int[] array into a List<Integer>
+ * @param ar - the array whose elements should be listified
+ * @return - a List<Integer> where each element has the same value as the corresponding index in @ar
+ */
+ public static List<Integer> listFromPrimitives(final int[] ar) {
+ final ArrayList<Integer> lst = new ArrayList<>(ar.length);
+ for ( final int d : ar ) {
+ lst.add(d);
+ }
+
+ return lst;
+ }
+
+ /**
+ * Compares sections from to byte arrays to verify whether they contain the same values.
+ *
+ * @param left first array to compare.
+ * @param leftOffset first position of the first array to compare.
+ * @param right second array to compare.
+ * @param rightOffset first position of the second array to compare.
+ * @param length number of positions to compare.
+ *
+ * @throws IllegalArgumentException if <ul>
+ * <li>either {@code left} or {@code right} is {@code null} or</li>
+ * <li>any off the offset or length combine point outside any of the two arrays</li>
+ * </ul>
+ * @return {@code true} iff {@code length} is 0 or all the bytes in both ranges are the same two-by-two.
+ */
+ public static boolean equalRange(final byte[] left, final int leftOffset, byte[] right, final int rightOffset, final int length) {
+ if (left == null) throw new IllegalArgumentException("left cannot be null");
+ if (right == null) throw new IllegalArgumentException("right cannot be null");
+ if (length < 0) throw new IllegalArgumentException("the length cannot be negative");
+ if (leftOffset < 0) throw new IllegalArgumentException("left offset cannot be negative");
+ if (leftOffset + length > left.length) throw new IllegalArgumentException("length goes beyond end of left array");
+ if (rightOffset < 0) throw new IllegalArgumentException("right offset cannot be negative");
+ if (rightOffset + length > right.length) throw new IllegalArgumentException("length goes beyond end of right array");
+
+ for (int i = 0; i < length; i++)
+ if (left[leftOffset + i] != right[rightOffset + i])
+ return false;
+ return true;
+ }
+
+ /**
+ * Skims out positions of an array returning a shorter one with the remaning positions in the same order.
+ * @param original the original array to splice.
+ * @param remove for each position in {@code original} indicates whether it should be spliced away ({@code true}),
+ * or retained ({@code false})
+ *
+ * @param <T> the array type.
+ *
+ * @throws IllegalArgumentException if either {@code original} or {@code remove} is {@code null},
+ * or {@code remove length is different to {@code original}'s}, or {@code original} is not in
+ * fact an array.
+ *
+ * @return never {@code null}.
+ */
+ public static <T> T skimArray(final T original, final boolean[] remove) {
+ return skimArray(original,0,null,0,remove,0);
+ }
+
+ /**
+ * Skims out positions of an array returning a shorter one with the remaning positions in the same order.
+ *
+ * <p>
+ * If the {@code dest} array provide is not long enough a new one will be created and returned with the
+ * same component type. All elements before {@code destOffset} will be copied from the input to the
+ * result array. If {@code dest} is {@code null}, a brand-new array large enough will be created where
+ * the position preceding {@code destOffset} will be left with the default value. The component type
+ * Will match the one of the {@code source} array.
+ * </p>
+ *
+ * @param source the original array to splice.
+ * @param sourceOffset the first position to skim.
+ * @param dest the destination array.
+ * @param destOffset the first position where to copy the skimed array values.
+ * @param remove for each position in {@code original} indicates whether it should be spliced away ({@code true}),
+ * or retained ({@code false})
+ * @param removeOffset the first position in the remove index array to consider.
+ *
+ * @param <T> the array type.
+ *
+ * @throws IllegalArgumentException if either {@code original} or {@code remove} is {@code null},
+ * or {@code remove length is different to {@code original}'s}, or {@code original} is not in
+ * fact an array.
+ *
+ * @return never {@code null}.
+ */
+ public static <T> T skimArray(final T source, final int sourceOffset, final T dest, final int destOffset, final boolean[] remove, final int removeOffset) {
+ if (source == null)
+ throw new IllegalArgumentException("the source array cannot be null");
+ @SuppressWarnings("unchecked")
+ final Class<T> sourceClazz = (Class<T>) source.getClass();
+
+ if (!sourceClazz.isArray())
+ throw new IllegalArgumentException("the source array is not in fact an array instance");
+ final int length = Array.getLength(source) - sourceOffset;
+ if (length < 0)
+ throw new IllegalArgumentException("the source offset goes beyond the source array length");
+ return skimArray(source,sourceOffset,dest,destOffset,remove,removeOffset,length);
+ }
+
+ /**
+ * Skims out positions of an array returning a shorter one with the remaning positions in the same order.
+ *
+ * <p>
+ * If the {@code dest} array provide is not long enough a new one will be created and returned with the
+ * same component type. All elements before {@code destOffset} will be copied from the input to the
+ * result array. If {@code dest} is {@code null}, a brand-new array large enough will be created where
+ * the position preceding {@code destOffset} will be left with the default value. The component type
+ * Will match the one of the {@code source} array.
+ * </p>
+ *
+ * @param source the original array to splice.
+ * @param sourceOffset the first position to skim.
+ * @param dest the destination array.
+ * @param destOffset the first position where to copy the skimed array values.
+ * @param remove for each position in {@code original} indicates whether it should be spliced away ({@code true}),
+ * or retained ({@code false})
+ * @param removeOffset the first position in the remove index array to consider.
+ * @param length the total number of position in {@code source} to consider. Thus only the {@code sourceOffset} to
+ * {@code sourceOffset + length - 1} region will be skimmed.
+ *
+ * @param <T> the array type.
+ *
+ * @throws IllegalArgumentException if either {@code original} or {@code remove} is {@code null},
+ * or {@code remove length is different to {@code original}'s}, or {@code original} is not in
+ * fact an array.
+ *
+ * @return never {@code null}.
+ */
+ public static <T> T skimArray(final T source, final int sourceOffset, final T dest, final int destOffset,
+ final boolean[] remove, final int removeOffset, final int length) {
+ if (source == null)
+ throw new IllegalArgumentException("the source array cannot be null");
+ if (remove == null)
+ throw new IllegalArgumentException("the remove array cannot be null");
+ if (sourceOffset < 0)
+ throw new IllegalArgumentException("the source array offset cannot be negative");
+ if (destOffset < 0)
+ throw new IllegalArgumentException("the destination array offset cannot be negative");
+ if (removeOffset < 0)
+ throw new IllegalArgumentException("the remove array offset cannot be negative");
+ if (length < 0)
+ throw new IllegalArgumentException("the length provided cannot be negative");
+
+ final int removeLength = Math.min(remove.length - removeOffset,length);
+
+ if (removeLength < 0)
+ throw new IllegalArgumentException("the remove offset provided falls beyond the remove array end");
+
+
+ @SuppressWarnings("unchecked")
+ final Class<T> sourceClazz = (Class<T>) source.getClass();
+
+ if (!sourceClazz.isArray())
+ throw new IllegalArgumentException("the source array is not in fact an array instance");
+
+ final Class<T> destClazz = skimArrayDetermineDestArrayClass(dest, sourceClazz);
+
+ final int sourceLength = Array.getLength(source);
+
+ if (sourceLength < length + sourceOffset)
+ throw new IllegalArgumentException("the source array is too small considering length and offset");
+
+ // count how many positions are to be removed.
+
+ int removeCount = 0;
+
+ final int removeEnd = removeLength + removeOffset;
+ for (int i = removeOffset; i < removeEnd; i++)
+ if (remove[i]) removeCount++;
+
+
+ final int newLength = length - removeCount;
+
+
+ @SuppressWarnings("unchecked")
+ final T result = skimArrayBuildResultArray(dest, destOffset, destClazz, newLength);
+ // No removals, just copy the whole thing.
+
+ if (removeCount == 0)
+ System.arraycopy(source,sourceOffset,result,destOffset,length);
+ else if (length > 0) { // if length == 0 nothing to do.
+ int nextOriginalIndex = 0;
+ int nextNewIndex = 0;
+ int nextRemoveIndex = removeOffset;
+ while (nextOriginalIndex < length && nextNewIndex < newLength) {
+ while (nextRemoveIndex < removeEnd && remove[nextRemoveIndex++]) { nextOriginalIndex++; } // skip positions to be spliced.
+ // Since we make the nextNewIndex < newLength check in the while condition
+ // there is no need to include the following break, as is guaranteed not to be true:
+ // if (nextOriginalIndex >= length) break; // we reach the final (last positions are to be spliced.
+ final int copyStart = nextOriginalIndex;
+ while (++nextOriginalIndex < length && (nextRemoveIndex >= removeEnd || !remove[nextRemoveIndex])) { nextRemoveIndex++; }
+ final int copyEnd = nextOriginalIndex;
+ final int copyLength = copyEnd - copyStart;
+ System.arraycopy(source, sourceOffset + copyStart, result, destOffset + nextNewIndex, copyLength);
+ nextNewIndex += copyLength;
+ }
+ }
+ return result;
+ }
+
+ private static <T> T skimArrayBuildResultArray(final T dest, final int destOffset, final Class<T> destClazz, final int newLength) {
+ @SuppressWarnings("unchecked")
+ final T result;
+
+ if (dest == null)
+ result = (T) Array.newInstance(destClazz.getComponentType(), newLength + destOffset);
+ else if (Array.getLength(dest) < newLength + destOffset) {
+ result = (T) Array.newInstance(destClazz.getComponentType(),newLength + destOffset);
+ if (destOffset > 0) System.arraycopy(dest,0,result,0,destOffset);
+ } else
+ result = dest;
+ return result;
+ }
+
+ private static <T> Class<T> skimArrayDetermineDestArrayClass(final T dest, Class<T> sourceClazz) {
+ final Class<T> destClazz;
+ if (dest == null)
+ destClazz = sourceClazz;
+ else {
+ destClazz = (Class<T>) dest.getClass();
+ if (destClazz != sourceClazz) {
+ if (!destClazz.isArray())
+ throw new IllegalArgumentException("the destination array class must be an array");
+ if (sourceClazz.getComponentType().isAssignableFrom(destClazz.getComponentType()))
+ throw new IllegalArgumentException("the provided destination array class cannot contain values from the source due to type incompatibility");
+ }
+ }
+ return destClazz;
+ }
+
+ /**
+ * Makes a deep clone of the array provided.
+ *
+ * <p>
+ * When you can use {@link Arrays#copyOf} or an array {@link Object#clone()} to create a copy of itself,
+ * if it is multi-dimentional each sub array or matrix would be cloned.
+ * </p>
+ *
+ * <p>
+ * Notice however that if the base type is an Object type, the base elements themselves wont be cloned.
+ * </p>
+ *
+ * @param array the array to deep-clone.
+ * @param <T> type of the array.
+ *
+ * @throws IllegalArgumentException if {@code array} is {@code null} or is not an array.
+ */
+ public static <T> T deepCloneArray(final T array) {
+
+ if (array == null)
+ throw new IllegalArgumentException("");
+
+ @SuppressWarnings("unchecked")
+ final Class<T> clazz = (Class<T>) array.getClass();
+
+
+ if (!clazz.isArray())
+ throw new IllegalArgumentException("the input is not an array");
+
+ final int dimension = calculateArrayDimensions(clazz);
+
+ return deepCloneArrayUnchecked(array,clazz, dimension);
+ }
+
+ private static int calculateArrayDimensions(final Class<?> clazz) {
+ if (clazz.isArray())
+ return calculateArrayDimensions(clazz.getComponentType()) + 1;
+ else
+ return 0;
+ }
+
+ private static <T> T deepCloneArrayUnchecked(final T array, final Class<T> clazz, final int dimension) {
+
+
+ final int length = Array.getLength(array);
+
+ final Class componentClass = clazz.getComponentType();
+
+ final T result = (T) Array.newInstance(componentClass,length);
+
+ if (dimension <= 1) {
+ System.arraycopy(array, 0, result, 0, length);
+ return result;
+ }
+
+
+ final int dimensionMinus1 = dimension - 1;
+
+ for (int i = 0; i < length; i++)
+ Array.set(result,i,deepCloneArrayUnchecked(Array.get(array,i),componentClass,dimensionMinus1));
+
+ return result;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActiveRegion.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActiveRegion.java
new file mode 100644
index 0000000..86a89c1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActiveRegion.java
@@ -0,0 +1,500 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.activeregion;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Invariant;
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.HasGenomeLocation;
+import org.broadinstitute.gatk.utils.clipping.ReadClipper;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+import java.util.*;
+
+/**
+ * Represents a single active region created by the Active Region Traversal for processing
+ *
+ * An active region is a single contiguous span of bases on the genome that should be operated
+ * on as a single unit for the active region traversal. The action may contains a list of
+ * reads that overlap the region (may because there may be no reads in the region). The region
+ * is tagged as being either active or inactive, depending on the probabilities provided by
+ * the isActiveProb results from the ART walker. Each region carries with it the
+ * exact span of the region (bases which are the core of the isActiveProbs from the walker) as
+ * well as an extended size, that includes the ART walker's extension size. Reads in the region
+ * provided by ART include all reads overlapping the extended span, not the raw span.
+ *
+ * User: rpoplin
+ * Date: 1/4/12
+ */
+ at Invariant({
+ "extension >= 0",
+ "activeRegionLoc != null",
+ "genomeLocParser != null",
+ "spanIncludingReads != null",
+ "extendedLoc != null"
+})
+public class ActiveRegion implements HasGenomeLocation {
+ /**
+ * The reads included in this active region. May be empty upon creation, and expand / contract
+ * as reads are added or removed from this region.
+ */
+ private final List<GATKSAMRecord> reads = new ArrayList<GATKSAMRecord>();
+
+ /**
+ * An ordered list (by genomic coordinate) of the ActivityProfileStates that went
+ * into this active region. May be empty, which says that no supporting states were
+ * provided when this region was created.
+ */
+ private final List<ActivityProfileState> supportingStates;
+
+ /**
+ * The raw span of this active region, not including the active region extension
+ */
+ private final GenomeLoc activeRegionLoc;
+
+ /**
+ * The span of this active region on the genome, including the active region extension
+ */
+ private final GenomeLoc extendedLoc;
+
+ /**
+ * The extension, in bp, of this active region.
+ */
+ private final int extension;
+
+ /**
+ * A genomeLocParser so we can create genomeLocs
+ */
+ private final GenomeLocParser genomeLocParser;
+
+ /**
+ * Does this region represent an active region (all isActiveProbs above threshold) or
+ * an inactive region (all isActiveProbs below threshold)?
+ */
+ private final boolean isActive;
+
+ /**
+ * The span of this active region, including the bp covered by all reads in this
+ * region. This union of extensionLoc and the loc of all reads in this region.
+ *
+ * Must be at least as large as extendedLoc, but may be larger when reads
+ * partially overlap this region.
+ */
+ private GenomeLoc spanIncludingReads;
+
+
+ /**
+ * Indicates whether the active region has been finalized
+ */
+ private boolean hasBeenFinalized;
+
+ /**
+ * Create a new ActiveRegion containing no reads
+ *
+ * @param activeRegionLoc the span of this active region
+ * @param supportingStates the states that went into creating this region, or null / empty if none are available.
+ * If not empty, must have exactly one state for each bp in activeRegionLoc
+ * @param isActive indicates whether this is an active region, or an inactve one
+ * @param genomeLocParser a non-null parser to let us create new genome locs
+ * @param extension the active region extension to use for this active region
+ */
+ public ActiveRegion( final GenomeLoc activeRegionLoc, final List<ActivityProfileState> supportingStates, final boolean isActive, final GenomeLocParser genomeLocParser, final int extension ) {
+ if ( activeRegionLoc == null ) throw new IllegalArgumentException("activeRegionLoc cannot be null");
+ if ( activeRegionLoc.size() == 0 ) throw new IllegalArgumentException("Active region cannot be of zero size, but got " + activeRegionLoc);
+ if ( genomeLocParser == null ) throw new IllegalArgumentException("genomeLocParser cannot be null");
+ if ( extension < 0 ) throw new IllegalArgumentException("extension cannot be < 0 but got " + extension);
+
+ this.activeRegionLoc = activeRegionLoc;
+ this.supportingStates = supportingStates == null ? Collections.<ActivityProfileState>emptyList() : new ArrayList<ActivityProfileState>(supportingStates);
+ this.isActive = isActive;
+ this.genomeLocParser = genomeLocParser;
+ this.extension = extension;
+ this.extendedLoc = genomeLocParser.createGenomeLocOnContig(activeRegionLoc.getContig(), activeRegionLoc.getStart() - extension, activeRegionLoc.getStop() + extension);
+ this.spanIncludingReads = extendedLoc;
+
+ if ( ! this.supportingStates.isEmpty() ) {
+ if ( this.supportingStates.size() != activeRegionLoc.size() )
+ throw new IllegalArgumentException("Supporting states wasn't empty but it doesn't have exactly one state per bp in the active region: states " + this.supportingStates.size() + " vs. bp in region = " + activeRegionLoc.size());
+ GenomeLoc lastStateLoc = null;
+ for ( final ActivityProfileState state : this.supportingStates ) {
+ if ( lastStateLoc != null ) {
+ if ( state.getLoc().getStart() != lastStateLoc.getStart() + 1 || state.getLoc().getContigIndex() != lastStateLoc.getContigIndex())
+ throw new IllegalArgumentException("Supporting state has an invalid sequence: last state was " + lastStateLoc + " but next state was " + state);
+ }
+ lastStateLoc = state.getLoc();
+ }
+ }
+ }
+
+ /**
+ * Simple interface to create an active region that isActive without any profile state
+ */
+ public ActiveRegion( final GenomeLoc activeRegionLoc, final GenomeLocParser genomeLocParser, final int extension ) {
+ this(activeRegionLoc, Collections.<ActivityProfileState>emptyList(), true, genomeLocParser, extension);
+ }
+
+ @Override
+ public String toString() {
+ return "ActiveRegion " + activeRegionLoc.toString() + " active?=" + isActive() + " nReads=" + reads.size();
+ }
+
+ /**
+ * See #getActiveRegionReference but with padding == 0
+ */
+ public byte[] getActiveRegionReference( final IndexedFastaSequenceFile referenceReader ) {
+ return getActiveRegionReference(referenceReader, 0);
+ }
+
+ /**
+ * Get the reference bases from referenceReader spanned by the extended location of this active region,
+ * including additional padding bp on either side. If this expanded region would exceed the boundaries
+ * of the active region's contig, the returned result will be truncated to only include on-genome reference
+ * bases
+ * @param referenceReader the source of the reference genome bases
+ * @param padding the padding, in BP, we want to add to either side of this active region extended region
+ * @return a non-null array of bytes holding the reference bases in referenceReader
+ */
+ @Ensures("result != null")
+ public byte[] getActiveRegionReference( final IndexedFastaSequenceFile referenceReader, final int padding ) {
+ return getReference(referenceReader, padding, extendedLoc);
+ }
+
+ /**
+ * See #getActiveRegionReference but using the span including regions not the extended span
+ */
+ public byte[] getFullReference( final IndexedFastaSequenceFile referenceReader ) {
+ return getFullReference(referenceReader, 0);
+ }
+
+ /**
+ * See #getActiveRegionReference but using the span including regions not the extended span
+ */
+ public byte[] getFullReference( final IndexedFastaSequenceFile referenceReader, final int padding ) {
+ return getReference(referenceReader, padding, spanIncludingReads);
+ }
+
+ /**
+ * Get the reference bases from referenceReader spanned by the extended location of this active region,
+ * including additional padding bp on either side. If this expanded region would exceed the boundaries
+ * of the active region's contig, the returned result will be truncated to only include on-genome reference
+ * bases
+ * @param referenceReader the source of the reference genome bases
+ * @param padding the padding, in BP, we want to add to either side of this active region extended region
+ * @param genomeLoc a non-null genome loc indicating the base span of the bp we'd like to get the reference for
+ * @return a non-null array of bytes holding the reference bases in referenceReader
+ */
+ @Ensures("result != null")
+ public byte[] getReference( final IndexedFastaSequenceFile referenceReader, final int padding, final GenomeLoc genomeLoc ) {
+ if ( referenceReader == null ) throw new IllegalArgumentException("referenceReader cannot be null");
+ if ( padding < 0 ) throw new IllegalArgumentException("padding must be a positive integer but got " + padding);
+ if ( genomeLoc == null ) throw new IllegalArgumentException("genomeLoc cannot be null");
+ if ( genomeLoc.size() == 0 ) throw new IllegalArgumentException("GenomeLoc must have size > 0 but got " + genomeLoc);
+
+ final byte[] reference = referenceReader.getSubsequenceAt( genomeLoc.getContig(),
+ Math.max(1, genomeLoc.getStart() - padding),
+ Math.min(referenceReader.getSequenceDictionary().getSequence(genomeLoc.getContig()).getSequenceLength(), genomeLoc.getStop() + padding) ).getBases();
+
+ return reference;
+ }
+
+ /**
+ * Get the raw span of this active region (excluding the extension)
+ * @return a non-null genome loc
+ */
+ @Override
+ @Ensures("result != null")
+ public GenomeLoc getLocation() { return activeRegionLoc; }
+
+ /**
+ * Get the span of this active region including the extension value
+ * @return a non-null GenomeLoc
+ */
+ @Ensures("result != null")
+ public GenomeLoc getExtendedLoc() { return extendedLoc; }
+
+ /**
+ * Get the span of this active region including the extension and the projects on the
+ * genome of all reads in this active region. That is, returns the bp covered by this
+ * region and all reads in the region.
+ * @return a non-null genome loc
+ */
+ @Ensures("result != null")
+ public GenomeLoc getReadSpanLoc() { return spanIncludingReads; }
+
+ /**
+ * Get the active profile states that went into creating this region, if possible
+ * @return an unmodifiable list of states that led to the creation of this region, or an empty
+ * list if none were provided
+ */
+ @Ensures("result != null")
+ public List<ActivityProfileState> getSupportingStates() {
+ return Collections.unmodifiableList(supportingStates);
+ }
+
+ /**
+ * Get the active region extension applied to this region
+ *
+ * The extension is >= 0 bp in size, and indicates how much padding this art walker wanted for its regions
+ *
+ * @return the size in bp of the region extension
+ */
+ @Ensures("result >= 0")
+ public int getExtension() { return extension; }
+
+ /**
+ * Get an unmodifiable list of reads currently in this active region.
+ *
+ * The reads are sorted by their coordinate position
+ *
+ * @return an unmodifiable list of reads in this active region
+ */
+ @Ensures("result != null")
+ public List<GATKSAMRecord> getReads() {
+ return Collections.unmodifiableList(reads);
+ }
+
+ /**
+ * Get the number of reads currently in this active region
+ * @return an integer >= 0
+ */
+ @Ensures("result >= 0")
+ public int size() { return reads.size(); }
+
+ /**
+ * Add read to this active region
+ *
+ * Read must have alignment start >= than the last read currently in this active region.
+ *
+ * @throws IllegalArgumentException if read doesn't overlap the extended region of this active region
+ *
+ * @param read a non-null GATKSAMRecord
+ */
+ @Ensures("reads.size() == old(reads.size()) + 1")
+ public void add( final GATKSAMRecord read ) {
+ if ( read == null ) throw new IllegalArgumentException("Read cannot be null");
+
+ final GenomeLoc readLoc = genomeLocParser.createGenomeLoc( read );
+ if ( ! readOverlapsRegion(read) )
+ throw new IllegalArgumentException("Read location " + readLoc + " doesn't overlap with active region extended span " + extendedLoc);
+
+ spanIncludingReads = spanIncludingReads.union( readLoc );
+
+ if ( ! reads.isEmpty() ) {
+ final GATKSAMRecord lastRead = reads.get(size() - 1);
+ if ( ! lastRead.getReferenceIndex().equals(read.getReferenceIndex()) )
+ throw new IllegalArgumentException("Attempting to add a read to ActiveRegion not on the same contig as other reads: lastRead " + lastRead + " attempting to add " + read);
+
+ if ( read.getAlignmentStart() < lastRead.getAlignmentStart() )
+ throw new IllegalArgumentException("Attempting to add a read to ActiveRegion out of order w.r.t. other reads: lastRead " + lastRead + " at " + lastRead.getAlignmentStart() + " attempting to add " + read + " at " + read.getAlignmentStart());
+ }
+
+ reads.add( read );
+ }
+
+ /**
+ * Returns true if read would overlap the extended extent of this region
+ * @param read the read we want to test
+ * @return true if read can be added to this region, false otherwise
+ */
+ public boolean readOverlapsRegion(final GATKSAMRecord read) {
+ final GenomeLoc readLoc = genomeLocParser.createGenomeLoc( read );
+ return readLoc.overlapsP(extendedLoc);
+ }
+
+ /**
+ * Add all reads to this active region
+ * @param reads a collection of reads to add to this active region
+ */
+ public void addAll(final Collection<GATKSAMRecord> reads) {
+ if ( reads == null ) throw new IllegalArgumentException("reads cannot be null");
+ for ( final GATKSAMRecord read : reads )
+ add(read);
+ }
+
+ /**
+ * Clear all of the reads currently in this active region
+ */
+ @Ensures("size() == 0")
+ public void clearReads() {
+ spanIncludingReads = extendedLoc;
+ reads.clear();
+ }
+
+ /**
+ * Remove all of the reads in readsToRemove from this active region
+ * @param readsToRemove the set of reads we want to remove
+ */
+ public void removeAll( final Set<GATKSAMRecord> readsToRemove ) {
+ final Iterator<GATKSAMRecord> it = reads.iterator();
+ spanIncludingReads = extendedLoc;
+ while ( it.hasNext() ) {
+ final GATKSAMRecord read = it.next();
+ if ( readsToRemove.contains(read) )
+ it.remove();
+ else
+ spanIncludingReads = spanIncludingReads.union( genomeLocParser.createGenomeLoc(read) );
+ }
+ }
+
+ /**
+ * Is this region equal to other, excluding any reads in either region in the comparison
+ * @param other the other active region we want to test
+ * @return true if this region is equal, excluding any reads and derived values, to other
+ */
+ protected boolean equalExceptReads(final ActiveRegion other) {
+ if ( activeRegionLoc.compareTo(other.activeRegionLoc) != 0 ) return false;
+ if ( isActive() != other.isActive()) return false;
+ if ( genomeLocParser != other.genomeLocParser ) return false;
+ if ( extension != other.extension ) return false;
+ if ( extendedLoc.compareTo(other.extendedLoc) != 0 ) return false;
+ return true;
+ }
+
+ /**
+ * Does this region represent an active region (all isActiveProbs above threshold) or
+ * an inactive region (all isActiveProbs below threshold)?
+ */
+ public boolean isActive() {
+ return isActive;
+ }
+
+ /**
+ * Intersect this active region with the allowed intervals, returning a list of active regions
+ * that only contain locations present in intervals
+ *
+ * Note that the returned list may be empty, if this active region doesn't overlap the set at all
+ *
+ * Note that the resulting regions are all empty, regardless of whether the current active region has reads
+ *
+ * @param intervals a non-null set of intervals that are allowed
+ * @return an ordered list of active region where each interval is contained within intervals
+ */
+ @Ensures("result != null")
+ protected List<ActiveRegion> splitAndTrimToIntervals(final GenomeLocSortedSet intervals) {
+ final List<GenomeLoc> allOverlapping = intervals.getOverlapping(getLocation());
+ final List<ActiveRegion> clippedRegions = new LinkedList<ActiveRegion>();
+
+ for ( final GenomeLoc overlapping : allOverlapping ) {
+ clippedRegions.add(trim(overlapping, extension));
+ }
+
+ return clippedRegions;
+ }
+
+ /**
+ * Trim this active to just the span, producing a new active region without any reads that has only
+ * the extent of newExtend intersected with the current extent
+ * @param span the new extend of the active region we want
+ * @param extension the extension size we want for the newly trimmed active region
+ * @return a non-null, empty active region
+ */
+ public ActiveRegion trim(final GenomeLoc span, final int extension) {
+ if ( span == null ) throw new IllegalArgumentException("Active region extent cannot be null");
+ if ( extension < 0) throw new IllegalArgumentException("the extension size must be 0 or greater");
+ final int extendStart = Math.max(1,span.getStart() - extension);
+ final int maxStop = genomeLocParser.getContigs().getSequence(span.getContigIndex()).getSequenceLength();
+ final int extendStop = Math.min(span.getStop() + extension, maxStop);
+ final GenomeLoc extendedSpan = genomeLocParser.createGenomeLoc(span.getContig(), extendStart, extendStop);
+ return trim(span, extendedSpan);
+
+//TODO - Inconsiste support of substates trimming. Check lack of consistency!!!!
+// final GenomeLoc subLoc = getLocation().intersect(span);
+// final int subStart = subLoc.getStart() - getLocation().getStart();
+// final int subEnd = subStart + subLoc.size();
+// final List<ActivityProfileState> subStates = supportingStates.isEmpty() ? supportingStates : supportingStates.subList(subStart, subEnd);
+// return new ActiveRegion( subLoc, subStates, isActive, genomeLocParser, extension );
+
+ }
+
+ public ActiveRegion trim(final GenomeLoc span) {
+ return trim(span,span);
+ }
+
+ /**
+ * Trim this active to no more than the span, producing a new active region with properly trimmed reads that
+ * attempts to provide the best possible representation of this active region covering the span.
+ *
+ * The challenge here is that span may (1) be larger than can be represented by this active region
+ * + its original extension and (2) the extension must be symmetric on both sides. This algorithm
+ * therefore determines how best to represent span as a subset of the span of this
+ * region with a padding value that captures as much of the span as possible.
+ *
+ * For example, suppose this active region is
+ *
+ * Active: 100-200 with extension of 50, so that the true span is 50-250
+ * NewExtent: 150-225 saying that we'd ideally like to just have bases 150-225
+ *
+ * Here we represent the active region as a active region from 150-200 with 25 bp of padding.
+ *
+ * The overall constraint is that the active region can never exceed the original active region, and
+ * the extension is chosen to maximize overlap with the desired region
+ *
+ * @param span the new extend of the active region we want
+ * @return a non-null, empty active region
+ */
+ public ActiveRegion trim(final GenomeLoc span, final GenomeLoc extendedSpan) {
+ if ( span == null ) throw new IllegalArgumentException("Active region extent cannot be null");
+ if ( extendedSpan == null ) throw new IllegalArgumentException("Active region extended span cannot be null");
+ if ( ! extendedSpan.containsP(span))
+ throw new IllegalArgumentException("The requested extended must fully contain the requested span");
+
+ final GenomeLoc subActive = getLocation().intersect(span);
+ final int requiredOnRight = Math.max(extendedSpan.getStop() - subActive.getStop(), 0);
+ final int requiredOnLeft = Math.max(subActive.getStart() - extendedSpan.getStart(), 0);
+ final int requiredExtension = Math.min(Math.max(requiredOnLeft, requiredOnRight), getExtension());
+
+ final ActiveRegion result = new ActiveRegion( subActive, Collections.<ActivityProfileState>emptyList(), isActive, genomeLocParser, requiredExtension );
+
+ final List<GATKSAMRecord> myReads = getReads();
+ final GenomeLoc resultExtendedLoc = result.getExtendedLoc();
+ final int resultExtendedLocStart = resultExtendedLoc.getStart();
+ final int resultExtendedLocStop = resultExtendedLoc.getStop();
+
+ final List<GATKSAMRecord> trimmedReads = new ArrayList<>(myReads.size());
+ for( final GATKSAMRecord read : myReads ) {
+ final GATKSAMRecord clippedRead = ReadClipper.hardClipToRegion(read,
+ resultExtendedLocStart, resultExtendedLocStop);
+ if( result.readOverlapsRegion(clippedRead) && clippedRead.getReadLength() > 0 )
+ trimmedReads.add(clippedRead);
+ }
+ result.clearReads();
+ result.addAll(ReadUtils.sortReadsByCoordinate(trimmedReads));
+ return result;
+ }
+
+ public void setFinalized(final boolean value) {
+ hasBeenFinalized = value;
+ }
+
+ public boolean isFinalized() {
+ return hasBeenFinalized;
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActiveRegionReadState.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActiveRegionReadState.java
new file mode 100644
index 0000000..76b4eb6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActiveRegionReadState.java
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.activeregion;
+
+/**
+ * Describes how a read relates to an assigned ActiveRegion
+ *
+ * User: thibault
+ * Date: 11/26/12
+ * Time: 2:35 PM
+ */
+public enum ActiveRegionReadState {
+ PRIMARY, // This is the read's primary region
+ NONPRIMARY, // This region overlaps the read, but it is not primary
+ EXTENDED, // This region would overlap the read if it were extended
+ UNMAPPED // This read is not mapped
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfile.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfile.java
new file mode 100644
index 0000000..2d97f69
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfile.java
@@ -0,0 +1,520 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.activeregion;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+
+import java.util.*;
+
+/**
+ * Class holding information about per-base activity scores for the
+ * active region traversal
+ *
+ * @author Mark DePristo
+ * @since Date created
+ */
+public class ActivityProfile {
+ protected final List<ActivityProfileState> stateList;
+ protected final GenomeLocParser parser;
+ protected final GenomeLocSortedSet restrictToIntervals;
+
+ protected final int maxProbPropagationDistance;
+ protected final double activeProbThreshold;
+
+ protected GenomeLoc regionStartLoc = null;
+ protected GenomeLoc regionStopLoc = null;
+
+ /**
+ * A cached value of the regionStartLoc contig length, to make calls to
+ * getCurrentContigLength efficient
+ */
+ protected int contigLength = -1;
+
+ /**
+ * Create a new empty ActivityProfile
+ * @param parser the parser we can use to create genome locs, cannot be null
+ * @param maxProbPropagationDistance region probability propagation distance beyond it's maximum size
+ * @param activeProbThreshold threshold for the probability of am active profile state being active
+ */
+ public ActivityProfile(final GenomeLocParser parser, final int maxProbPropagationDistance, final double activeProbThreshold) {
+ this(parser, maxProbPropagationDistance, activeProbThreshold, null);
+ }
+
+ /**
+ * Create a empty ActivityProfile, restricting output to profiles overlapping intervals, if not null
+ * @param parser the parser we can use to create genome locs, cannot be null
+ * @param maxProbPropagationDistance region probability propagation distance beyond it's maximum size
+ * @param activeProbThreshold threshold for the probability of a profile state being active
+ * @param intervals only include states that are within these intervals, if not null
+ */
+ public ActivityProfile(final GenomeLocParser parser, final int maxProbPropagationDistance, final double activeProbThreshold, final GenomeLocSortedSet intervals) {
+ if ( parser == null ) throw new IllegalArgumentException("parser cannot be null");
+
+ this.parser = parser;
+ this.stateList = new ArrayList<ActivityProfileState>();
+ this.restrictToIntervals = intervals;
+ this.maxProbPropagationDistance = maxProbPropagationDistance;
+ this.activeProbThreshold = activeProbThreshold;
+ }
+
+ @Override
+ public String toString() {
+ return "ActivityProfile{" +
+ "start=" + regionStartLoc +
+ ", stop=" + regionStopLoc +
+ '}';
+ }
+
+ /**
+ * How far away can probability mass be moved around in this profile?
+ *
+ * This distance puts an upper limit on how far, in bp, we will ever propagate probability max around
+ * when adding a new ActivityProfileState. For example, if the value of this function is
+ * 10, and you are looking at a state at bp 5, and we know that no states beyond 5 + 10 will have
+ * their probability propagated back to that state.
+ *
+ * @return a positive integer distance in bp
+ */
+ @Ensures("result >= 0")
+ public int getMaxProbPropagationDistance() {
+ return maxProbPropagationDistance;
+ }
+
+ /**
+ * How many profile results are in this profile?
+ * @return the number of profile results
+ */
+ @Ensures("result >= 0")
+ public int size() {
+ return stateList.size();
+ }
+
+ /**
+ * Is this profile empty?
+ * @return true if the profile is empty
+ */
+ @Ensures("isEmpty() == (size() == 0)")
+ public boolean isEmpty() {
+ return stateList.isEmpty();
+ }
+
+ /**
+ * Get the span of this activity profile, which is from the start of the first state to the stop of the last
+ * @return a potentially null GenomeLoc. Will be null if this profile is empty
+ */
+ public GenomeLoc getSpan() {
+ return isEmpty() ? null : regionStartLoc.endpointSpan(regionStopLoc);
+ }
+
+ @Requires("! isEmpty()")
+ public int getContigIndex() {
+ return regionStartLoc.getContigIndex();
+ }
+
+ @Requires("! isEmpty()")
+ public int getStop() {
+ return regionStopLoc.getStop();
+ }
+
+ /**
+ * Get the list of active profile results in this object
+ * @return a non-null, ordered list of active profile results
+ */
+ @Ensures("result != null")
+ protected List<ActivityProfileState> getStateList() {
+ return stateList;
+ }
+
+ /**
+ * Get the probabilities of the states as a single linear array of doubles
+ * @return a non-null array
+ */
+ @Ensures("result != null")
+ protected double[] getProbabilitiesAsArray() {
+ final double[] probs = new double[getStateList().size()];
+ int i = 0;
+ for ( final ActivityProfileState state : getStateList() )
+ probs[i++] = state.isActiveProb;
+ return probs;
+ }
+
+ /**
+ * Helper function that gets the genome loc for a site offset from relativeLoc, protecting ourselves from
+ * falling off the edge of the contig.
+ *
+ * @param relativeLoc the location offset is relative to
+ * @param offset the offset from relativeLoc where we'd like to create a GenomeLoc
+ * @return a genome loc with relativeLoc.start + offset, if this is on the contig, null otherwise
+ */
+ @Requires("relativeLoc != null")
+ protected GenomeLoc getLocForOffset(final GenomeLoc relativeLoc, final int offset) {
+ final int start = relativeLoc.getStart() + offset;
+ if ( start < 0 || start > getCurrentContigLength() ) {
+ return null;
+ } else {
+ return parser.createGenomeLoc(regionStartLoc.getContig(), regionStartLoc.getContigIndex(), start, start);
+ }
+ }
+
+ /**
+ * Get the length of the current contig
+ * @return the length in bp
+ */
+ @Requires("regionStartLoc != null")
+ @Ensures("result > 0")
+ private int getCurrentContigLength() {
+ return contigLength;
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // routines to add states to a profile
+ //
+ // --------------------------------------------------------------------------------
+
+ /**
+ * Add the next ActivityProfileState to this profile.
+ *
+ * Must be contiguous with the previously added result, or an IllegalArgumentException will be thrown
+ *
+ * @param state a well-formed ActivityProfileState result to incorporate into this profile
+ */
+ @Requires("state != null")
+ public void add(final ActivityProfileState state) {
+ final GenomeLoc loc = state.getLoc();
+
+ if ( regionStartLoc == null ) {
+ regionStartLoc = loc;
+ regionStopLoc = loc;
+ contigLength = parser.getContigInfo(regionStartLoc.getContig()).getSequenceLength();
+ } else {
+ if ( regionStopLoc.getStart() != loc.getStart() - 1 )
+ throw new IllegalArgumentException("Bad add call to ActivityProfile: loc " + loc + " not immediately after last loc " + regionStopLoc );
+ regionStopLoc = loc;
+ }
+
+ final Collection<ActivityProfileState> processedStates = processState(state);
+ for ( final ActivityProfileState processedState : processedStates ) {
+ incorporateSingleState(processedState);
+ }
+ }
+
+ /**
+ * Incorporate a single activity profile state into the current list of states
+ *
+ * If state's position occurs immediately after the last position in this profile, then
+ * the state is appended to the state list. If it's within the existing states list,
+ * the prob of stateToAdd is added to its corresponding state in the list. If the
+ * position would be before the start of this profile, stateToAdd is simply ignored.
+ *
+ * @param stateToAdd the state we want to add to the states list
+ */
+ @Requires("stateToAdd != null")
+ private void incorporateSingleState(final ActivityProfileState stateToAdd) {
+ final int position = stateToAdd.getOffset(regionStartLoc);
+
+ if ( position > size() )
+ // should we allow this? probably not
+ throw new IllegalArgumentException("Must add state contiguous to existing states: adding " + stateToAdd);
+
+ if ( position >= 0 ) {
+ // ignore states starting before this region's start
+ if ( position < size() ) {
+ stateList.get(position).isActiveProb += stateToAdd.isActiveProb;
+ } else {
+ if ( position != size() ) throw new IllegalStateException("position == size but it wasn't");
+ stateList.add(stateToAdd);
+ }
+ }
+ }
+
+ /**
+ * Process justAddedState, returning a collection of derived states that actually be added to the stateList
+ *
+ * The purpose of this function is to transform justAddedStates, if needed, into a series of atomic states
+ * that we actually want to track. For example, if state is for soft clips, we transform that single
+ * state into a list of states that surround the state up to the distance of the soft clip.
+ *
+ * Can be overridden by subclasses to transform states in any way
+ *
+ * There's no particular contract for the output states, except that they can never refer to states
+ * beyond the current end of the stateList unless the explicitly include preceding states before
+ * the reference. So for example if the current state list is [1, 2, 3] this function could return
+ * [1,2,3,4,5] but not [1,2,3,5].
+ *
+ * @param justAddedState the state our client provided to use to add to the list
+ * @return a list of derived states that should actually be added to this profile's state list
+ */
+ protected Collection<ActivityProfileState> processState(final ActivityProfileState justAddedState) {
+ if ( justAddedState.resultState.equals(ActivityProfileState.Type.HIGH_QUALITY_SOFT_CLIPS) ) {
+ // special code to deal with the problem that high quality soft clipped bases aren't added to pileups
+ final List<ActivityProfileState> states = new LinkedList<ActivityProfileState>();
+ // add no more than the max prob propagation distance num HQ clips
+ final int numHQClips = Math.min(justAddedState.resultValue.intValue(), getMaxProbPropagationDistance());
+ for( int jjj = - numHQClips; jjj <= numHQClips; jjj++ ) {
+ final GenomeLoc loc = getLocForOffset(justAddedState.getLoc(), jjj);
+ if ( loc != null )
+ states.add(new ActivityProfileState(loc, justAddedState.isActiveProb));
+ }
+
+ return states;
+ } else {
+ return Collections.singletonList(justAddedState);
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // routines to get active regions from the profile
+ //
+ // --------------------------------------------------------------------------------
+
+ /**
+ * Get the next completed active regions from this profile, and remove all states supporting them from this profile
+ *
+ * Takes the current profile and finds all of the active / inactive from the start of the profile that are
+ * ready. By ready we mean unable to have their probability modified any longer by future additions to the
+ * profile. The regions that are popped off the profile take their states with them, so the start of this
+ * profile will always be after the end of the last region returned here.
+ *
+ * The regions are returned sorted by genomic position.
+ *
+ * This function may not return anything in the list, if no regions are ready
+ *
+ * No returned region will be larger than maxRegionSize.
+ *
+ * @param activeRegionExtension the extension value to provide to the constructed regions
+ * @param minRegionSize the minimum region size, in the case where we have to cut up regions that are too large
+ * @param maxRegionSize the maximize size of the returned region
+ * @param forceConversion if true, we'll return a region whose end isn't sufficiently far from the end of the
+ * stateList. Used to close out the active region when we've hit some kind of end (such
+ * as the end of the contig)
+ * @return a non-null list of active regions
+ */
+ @Ensures("result != null")
+ public List<ActiveRegion> popReadyActiveRegions(final int activeRegionExtension, final int minRegionSize, final int maxRegionSize, final boolean forceConversion) {
+ if ( activeRegionExtension < 0 ) throw new IllegalArgumentException("activeRegionExtension must be >= 0 but got " + activeRegionExtension);
+ if ( minRegionSize < 1 ) throw new IllegalArgumentException("minRegionSize must be >= 1 but got " + minRegionSize);
+ if ( maxRegionSize < 1 ) throw new IllegalArgumentException("maxRegionSize must be >= 1 but got " + maxRegionSize);
+
+ final LinkedList<ActiveRegion> regions = new LinkedList<ActiveRegion>();
+
+ while ( true ) {
+ final ActiveRegion nextRegion = popNextReadyActiveRegion(activeRegionExtension, minRegionSize, maxRegionSize, forceConversion);
+ if ( nextRegion == null )
+ return regions;
+ else {
+ if ( restrictToIntervals == null )
+ regions.add(nextRegion);
+ else
+ regions.addAll(nextRegion.splitAndTrimToIntervals(restrictToIntervals));
+ }
+ }
+ }
+
+ /**
+ * Helper function for popReadyActiveRegions that pops the first ready region off the front of this profile
+ *
+ * If a region is returned, modifies the state of this profile so that states used to make the region are
+ * no longer part of the profile. Associated information (like the region start position) of this profile
+ * are also updated.
+ *
+ * @param activeRegionExtension the extension value to provide to the constructed regions
+ * @param minRegionSize the minimum region size, in the case where we have to cut up regions that are too large
+ * @param maxRegionSize the maximize size of the returned region
+ * @param forceConversion if true, we'll return a region whose end isn't sufficiently far from the end of the
+ * stateList. Used to close out the active region when we've hit some kind of end (such
+ * as the end of the contig)
+ * @return a fully formed active region, or null if none can be made
+ */
+ private ActiveRegion popNextReadyActiveRegion(final int activeRegionExtension, final int minRegionSize, final int maxRegionSize, final boolean forceConversion) {
+ if ( stateList.isEmpty() )
+ return null;
+
+ // If we are flushing the activity profile we need to trim off the excess states so that we don't create regions outside of our current processing interval
+ if( forceConversion ) {
+ final List<ActivityProfileState> statesToTrimAway = new ArrayList<ActivityProfileState>(stateList.subList(getSpan().size(), stateList.size()));
+ stateList.removeAll(statesToTrimAway);
+ }
+
+ final ActivityProfileState first = stateList.get(0);
+ final boolean isActiveRegion = first.isActiveProb > activeProbThreshold;
+ final int offsetOfNextRegionEnd = findEndOfRegion(isActiveRegion, minRegionSize, maxRegionSize, forceConversion);
+ if ( offsetOfNextRegionEnd == -1 )
+ // couldn't find a valid ending offset, so we return null
+ return null;
+
+ // we need to create the active region, and clip out the states we're extracting from this profile
+ final List<ActivityProfileState> sub = stateList.subList(0, offsetOfNextRegionEnd + 1);
+ final List<ActivityProfileState> supportingStates = new ArrayList<ActivityProfileState>(sub);
+ sub.clear();
+
+ // update the start and stop locations as necessary
+ if ( stateList.isEmpty() ) {
+ regionStartLoc = regionStopLoc = null;
+ } else {
+ regionStartLoc = stateList.get(0).getLoc();
+ }
+ final GenomeLoc regionLoc = parser.createGenomeLoc(first.getLoc().getContig(), first.getLoc().getStart(), first.getLoc().getStart() + offsetOfNextRegionEnd);
+ return new ActiveRegion(regionLoc, supportingStates, isActiveRegion, parser, activeRegionExtension);
+ }
+
+ /**
+ * Find the end of the current region, returning the index into the element isActive element, or -1 if the region isn't done
+ *
+ * The current region is defined from the start of the stateList, looking for elements that have the same isActiveRegion
+ * flag (i.e., if isActiveRegion is true we are looking for states with isActiveProb > threshold, or alternatively
+ * for states < threshold). The maximize size of the returned region is maxRegionSize. If forceConversion is
+ * true, then we'll return the region end even if this isn't safely beyond the max prob propagation distance.
+ *
+ * Note that if isActiveRegion is true, and we can construct a active region > maxRegionSize in bp, we
+ * find the further local minimum within that max region, and cut the region there, under the constraint
+ * that the resulting region must be at least minRegionSize in bp.
+ *
+ * @param isActiveRegion is the region we're looking for an active region or inactive region?
+ * @param minRegionSize the minimum region size, in the case where we have to cut up regions that are too large
+ * @param maxRegionSize the maximize size of the returned region
+ * @param forceConversion if true, we'll return a region whose end isn't sufficiently far from the end of the
+ * stateList. Used to close out the active region when we've hit some kind of end (such
+ * as the end of the contig)
+ * @return the index into stateList of the last element of this region, or -1 if it cannot be found
+ */
+ @Ensures({
+ "result >= -1",
+ "result == -1 || result < maxRegionSize",
+ "! (result == -1 && forceConversion)"})
+ private int findEndOfRegion(final boolean isActiveRegion, final int minRegionSize, final int maxRegionSize, final boolean forceConversion) {
+ if ( ! forceConversion && stateList.size() < maxRegionSize + getMaxProbPropagationDistance() ) {
+ // we really haven't finalized at the probability mass that might affect our decision, so keep
+ // waiting until we do before we try to make any decisions
+ return -1;
+ }
+
+ int endOfActiveRegion = findFirstActivityBoundary(isActiveRegion, maxRegionSize);
+
+ if ( isActiveRegion && endOfActiveRegion == maxRegionSize )
+ // we've run to the end of the region, let's find a good place to cut
+ endOfActiveRegion = findBestCutSite(endOfActiveRegion, minRegionSize);
+
+ // we're one past the end, so i must be decremented
+ return endOfActiveRegion - 1;
+ }
+
+ /**
+ * Find the the local minimum within 0 - endOfActiveRegion where we should divide region
+ *
+ * This algorithm finds the global minimum probability state within the region [minRegionSize, endOfActiveRegion)
+ * (exclusive of endOfActiveRegion), and returns the state index of that state.
+ * that it
+ *
+ * @param endOfActiveRegion the last state of the current active region (exclusive)
+ * @param minRegionSize the minimum of the left-most region, after cutting
+ * @return the index of state after the cut site (just like endOfActiveRegion)
+ */
+ @Requires({"endOfActiveRegion >= minRegionSize", "minRegionSize >= 0"})
+ @Ensures({"result >= minRegionSize", "result <= endOfActiveRegion"})
+ private int findBestCutSite(final int endOfActiveRegion, final int minRegionSize) {
+ int minI = endOfActiveRegion - 1;
+ double minP = Double.MAX_VALUE;
+
+ for ( int i = minI; i >= minRegionSize - 1; i-- ) {
+ double cur = getProb(i);
+ if ( cur < minP && isMinimum(i) ) {
+ minP = cur;
+ minI = i;
+ }
+ }
+
+ return minI + 1;
+ }
+
+ /**
+ * Find the first index into the state list where the state is considered ! isActiveRegion
+ *
+ * Note that each state has a probability of being active, and this function thresholds that
+ * value on activeProbThreshold, coloring each state as active or inactive. Finds the
+ * largest contiguous stretch of states starting at the first state (index 0) with the same isActive
+ * state as isActiveRegion. If the entire state list has the same isActive value, then returns
+ * maxRegionSize
+ *
+ * @param isActiveRegion are we looking for a stretch of active states, or inactive ones?
+ * @param maxRegionSize don't look for a boundary that would yield a region of size > maxRegionSize
+ * @return the index of the first state in the state list with isActive value != isActiveRegion, or maxRegionSize
+ * if no such element exists
+ */
+ @Requires({"maxRegionSize > 0"})
+ @Ensures({"result >= 0", "result <= stateList.size()"})
+ private int findFirstActivityBoundary(final boolean isActiveRegion, final int maxRegionSize) {
+ final int nStates = stateList.size();
+ int endOfActiveRegion = 0;
+
+ while ( endOfActiveRegion < nStates && endOfActiveRegion < maxRegionSize ) {
+ if ( getProb(endOfActiveRegion) > activeProbThreshold != isActiveRegion ) {
+ break;
+ }
+ endOfActiveRegion++;
+ }
+
+ return endOfActiveRegion;
+ }
+
+ /**
+ * Helper function to get the probability of the state at offset index
+ * @param index a valid offset into the state list
+ * @return the isActiveProb of the state at index
+ */
+ @Requires({"index >= 0", "index < stateList.size()"})
+ private double getProb(final int index) {
+ return stateList.get(index).isActiveProb;
+ }
+
+ /**
+ * Is the probability at index in a local minimum?
+ *
+ * Checks that the probability at index is <= both the probabilities to either side.
+ * Returns false if index is at the end or the start of the state list.
+ *
+ * @param index the index of the state we want to test
+ * @return true if prob at state is a minimum, false otherwise
+ */
+ @Requires({"index >= 0", "index < stateList.size()"})
+ private boolean isMinimum(final int index) {
+ if ( index == stateList.size() - 1 )
+ // we cannot be at a minimum if the current position is the last in the state list
+ return false;
+ else if ( index < 1 )
+ // we cannot be at a minimum if the current position is the first or second
+ return false;
+ else {
+ final double indexP = getProb(index);
+ return indexP <= getProb(index+1) && indexP < getProb(index-1);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfileState.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfileState.java
new file mode 100644
index 0000000..915db61
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfileState.java
@@ -0,0 +1,112 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.activeregion;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+
+/**
+ * The state of an active region walker's isActive call at a specific locus in the genome
+ *
+ * User: rpoplin
+ * Date: 7/27/12
+ */
+public class ActivityProfileState {
+ final private GenomeLoc loc;
+ public double isActiveProb;
+ public Type resultState;
+ public Number resultValue;
+
+ public enum Type {
+ NONE,
+ HIGH_QUALITY_SOFT_CLIPS
+ }
+
+ /**
+ * Create a new ActivityProfileState at loc with probability of being active of isActiveProb
+ *
+ * @param loc the position of the result profile (for debugging purposes)
+ * @param isActiveProb the probability of being active (between 0 and 1)
+ */
+ @Requires({"loc != null", "isActiveProb >= 0.0 && isActiveProb <= 1.0"})
+ public ActivityProfileState(final GenomeLoc loc, final double isActiveProb) {
+ this(loc, isActiveProb, Type.NONE, null);
+ }
+
+ /**
+ * Create a new ActivityProfileState at loc with probability of being active of isActiveProb that maintains some
+ * information about the result state and value
+ *
+ * The only state value in use is HIGH_QUALITY_SOFT_CLIPS, and here the value is interpreted as the number
+ * of bp affected by the soft clips.
+ *
+ * @param loc the position of the result profile (for debugging purposes)
+ * @param isActiveProb the probability of being active (between 0 and 1)
+ */
+ @Requires({"loc != null", "isActiveProb >= 0.0 && isActiveProb <= 1.0"})
+ public ActivityProfileState(final GenomeLoc loc, final double isActiveProb, final Type resultState, final Number resultValue) {
+ // make sure the location of that activity profile is 1
+ if ( loc.size() != 1 )
+ throw new IllegalArgumentException("Location for an ActivityProfileState must have to size 1 bp but saw " + loc);
+ if ( resultValue != null && resultValue.doubleValue() < 0 )
+ throw new IllegalArgumentException("Result value isn't null and its < 0, which is illegal: " + resultValue);
+
+ this.loc = loc;
+ this.isActiveProb = isActiveProb;
+ this.resultState = resultState;
+ this.resultValue = resultValue;
+ }
+
+ /**
+ * The offset of state w.r.t. our current region's start location
+ * @param regionStartLoc the start of the region, as a genome loc
+ * @return the position of this profile relative to the start of this region
+ */
+ public int getOffset(final GenomeLoc regionStartLoc) {
+ return getLoc().getStart() - regionStartLoc.getStart();
+ }
+
+
+ /**
+ * Get the genome loc associated with the ActivityProfileState
+ * @return the location of this result
+ */
+ @Ensures("result != null")
+ public GenomeLoc getLoc() {
+ return loc;
+ }
+
+ @Override
+ public String toString() {
+ return "ActivityProfileState{" +
+ "loc=" + loc +
+ ", isActiveProb=" + isActiveProb +
+ ", resultState=" + resultState +
+ ", resultValue=" + resultValue +
+ '}';
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/BandPassActivityProfile.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/BandPassActivityProfile.java
new file mode 100644
index 0000000..52437a8
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/activeregion/BandPassActivityProfile.java
@@ -0,0 +1,194 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.activeregion;
+
+import com.google.java.contract.Ensures;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.MathUtils;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+/**
+ * A band pass filtering version of the activity profile
+ *
+ * Applies a band pass filter with a Gaussian kernel to the input state probabilities to smooth
+ * them out of an interval
+ *
+ * @author Mark DePristo
+ * @since 2011
+ */
+public class BandPassActivityProfile extends ActivityProfile {
+ public static final int MAX_FILTER_SIZE = 50;
+ private final static double MIN_PROB_TO_KEEP_IN_FILTER = 1e-5;
+ public static final double DEFAULT_SIGMA = 17.0;
+
+ private final int filterSize;
+ private final double sigma;
+ private final double[] GaussianKernel;
+
+ /**
+ * Create a new BandPassActivityProfile with default sigma and filter sizes
+ *
+ * @see #BandPassActivityProfile(org.broadinstitute.gatk.utils.GenomeLocParser, org.broadinstitute.gatk.utils.GenomeLocSortedSet, int, double, int, double, boolean)
+ */
+ public BandPassActivityProfile(final GenomeLocParser parser, final GenomeLocSortedSet restrictToIntervals,
+ final int maxProbPropagationDistance, final double activeProbThreshold) {
+ this(parser, restrictToIntervals, maxProbPropagationDistance, activeProbThreshold, MAX_FILTER_SIZE, DEFAULT_SIGMA);
+ }
+
+ /**
+ * @see #BandPassActivityProfile(org.broadinstitute.gatk.utils.GenomeLocParser, org.broadinstitute.gatk.utils.GenomeLocSortedSet, int, double, int, double, boolean)
+ *
+ * sets adaptiveFilterSize to true
+ */
+ public BandPassActivityProfile(final GenomeLocParser parser, final GenomeLocSortedSet restrictToIntervals,
+ final int maxProbPropagationDistance, final double activeProbThreshold,
+ final int maxFilterSize, final double sigma) {
+ this(parser, restrictToIntervals, maxProbPropagationDistance, activeProbThreshold, maxFilterSize, sigma, true);
+ }
+
+ /**
+ * Create an activity profile that implements a band pass filter on the states
+ *
+ * @param parser our genome loc parser
+ * @param restrictToIntervals only include states that are within these intervals, if not null
+ * @param maxProbPropagationDistance region probability propagation distance beyond it's maximum size
+ * @param activeProbThreshold threshold for the probability of a profile state being active
+ * @param maxFilterSize the maximum size of the band pass filter we are allowed to create, regardless of sigma
+ * @param sigma the variance of the Gaussian kernel for this band pass filter
+ * @param adaptiveFilterSize if true, use the kernel itself to determine the best filter size
+ */
+ public BandPassActivityProfile(final GenomeLocParser parser, final GenomeLocSortedSet restrictToIntervals, final int maxProbPropagationDistance,
+ final double activeProbThreshold, final int maxFilterSize, final double sigma, final boolean adaptiveFilterSize) {
+ super(parser, maxProbPropagationDistance, activeProbThreshold, restrictToIntervals);
+
+ if ( sigma < 0 ) throw new IllegalArgumentException("Sigma must be greater than or equal to 0 but got " + sigma);
+
+ // setup the Gaussian kernel for the band pass filter
+ this.sigma = sigma;
+ final double[] fullKernel = makeKernel(maxFilterSize, sigma);
+ this.filterSize = adaptiveFilterSize ? determineFilterSize(fullKernel, MIN_PROB_TO_KEEP_IN_FILTER) : maxFilterSize;
+ this.GaussianKernel = makeKernel(this.filterSize, sigma);
+ }
+
+ protected static int determineFilterSize(final double[] kernel, final double minProbToKeepInFilter) {
+ final int middle = (kernel.length - 1) / 2;
+ int filterEnd = middle;
+ while ( filterEnd > 0 ) {
+ if ( kernel[filterEnd - 1] < minProbToKeepInFilter ) {
+ break;
+ }
+ filterEnd--;
+ }
+ return middle - filterEnd;
+ }
+
+ protected static double[] makeKernel(final int filterSize, final double sigma) {
+ final int bandSize = 2 * filterSize + 1;
+ final double[] kernel = new double[bandSize];
+ for( int iii = 0; iii < bandSize; iii++ ) {
+ kernel[iii] = MathUtils.normalDistribution(filterSize, sigma, iii);
+ }
+ return MathUtils.normalizeFromRealSpace(kernel);
+ }
+
+ /**
+ * Our maximize propagation distance is whatever our parent's is, plus our filter size
+ *
+ * Stops the profile from interpreting sites that aren't yet fully determined due to
+ * propagation of the probabilities.
+ *
+ * @return the distance in bp we might move our probabilities around for some site i
+ */
+ @Override
+ public int getMaxProbPropagationDistance() {
+ return super.getMaxProbPropagationDistance() + filterSize;
+ }
+
+ /**
+ * Get the size (in bp) of the band pass filter
+ * @return a positive integer
+ */
+ @Ensures("result >= 1")
+ public int getBandSize() {
+ return 2 * filterSize + 1;
+ }
+
+ /**
+ * Get the filter size (which is the size of each wing of the band, minus the center point)
+ * @return a positive integer
+ */
+ @Ensures("result >= 0")
+ public int getFilteredSize() {
+ return filterSize;
+ }
+
+ /**
+ * Get the Gaussian kernel sigma value
+ * @return a positive double
+ */
+ @Ensures("result >= 0")
+ public double getSigma() {
+ return sigma;
+ }
+
+ /**
+ * Get the kernel of this band pass filter. Do not modify returned result
+ * @return the kernel used in this band pass filter
+ */
+ @Ensures({"result != null", "result.length == getBandSize()"})
+ protected double[] getKernel() {
+ return GaussianKernel;
+ }
+
+ /**
+ * Band pass the probabilities in the ActivityProfile, producing a new profile that's band pass filtered
+ * @return a new double[] that's the band-pass filtered version of this profile
+ */
+ @Override
+ protected Collection<ActivityProfileState> processState(final ActivityProfileState justAddedState) {
+ final Collection<ActivityProfileState> states = new LinkedList<ActivityProfileState>();
+
+ for ( final ActivityProfileState superState : super.processState(justAddedState) ) {
+ if ( superState.isActiveProb > 0.0 ) {
+ for( int jjj = -filterSize; jjj <= filterSize; jjj++ ) {
+ final GenomeLoc loc = getLocForOffset(justAddedState.getLoc(), jjj);
+ if ( loc != null ) {
+ final double newProb = superState.isActiveProb * GaussianKernel[jjj + filterSize];
+ states.add(new ActivityProfileState(loc, newProb));
+ }
+ }
+ } else {
+ states.add(justAddedState);
+ }
+ }
+
+ return states;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/analysis/AminoAcid.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/analysis/AminoAcid.java
new file mode 100644
index 0000000..0416609
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/analysis/AminoAcid.java
@@ -0,0 +1,114 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.analysis;
+
+/*
+ * Copyright (c) 2010 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author chartl
+ * @since June 28, 2010
+ */
+
+public enum AminoAcid {
+
+ Alanine("Alanine","Ala","A",new String[]{"GCA","GCC","GCG","GCT"}),
+ Arganine("Arganine","Arg","R",new String[]{"AGA","AGG","CGA","CGC","CGG","CGT"}),
+ Asparagine("Asparagine","Asn","N",new String[]{"AAC","AAT"}),
+ Aspartic_acid("Aspartic acid","Asp","D",new String[]{"GAT","GAC"}),
+ Cysteine("Cysteine","Cys","C",new String[]{"TGC","TGC"}),
+ Glutamic_acid("Glutamic acid","Glu","E",new String[]{"GAA","GAG"}),
+ Glutamine("Glutamine","Gln","Q",new String[]{"CAA","CAG"}),
+ Glycine("Glycine","Gly","G",new String[]{"GGA","GGC","GGG","GGT"}),
+ Histidine("Histidine","His","H",new String[]{"CAC","CAT"}),
+ Isoleucine("Isoleucine","Ile","I",new String[]{"ATA","ATC","ATT"}),
+ Leucine("Leucine","Leu","L",new String[]{"CTA","CTC","CTG","CTT","TTA","TTG"}),
+ Lysine("Lysine","Lys","K", new String[]{"AAA","AAG"}),
+ Methionine("Methionine","Met","M",new String[]{"ATG"}),
+ Phenylalanine("Phenylalanine","Phe","F",new String[]{"TTC","TTT"}),
+ Proline("Proline","Pro","P",new String[]{"CCA","CCC","CCG","CCT"}),
+ Serine("Serine","Ser","S",new String[]{"AGC","AGT","TCA","TCC","TCG","TCT"}),
+ Stop_codon("Stop codon","Stop","*",new String[]{"TAA","TAG","TGA"}),
+ Threonine("Threonine","Thr","T",new String[]{"ACA","ACC","ACG","ACT"}),
+ Tryptophan("Tryptophan","Trp","W",new String[]{"TGG"}),
+ Tyrosine("Tyrosine","Tyr","Y",new String[]{"TAC","TAT"}),
+ Valine("Valine","Val","V",new String[]{"GTA","GTC","GTG","GTT"});
+
+ String[] codons;
+ String fullName;
+ String code;
+ String letter;
+
+ AminoAcid(String name, String shortName, String abbrev, String[] myCodons) {
+ codons = myCodons;
+ fullName = name;
+ code = shortName;
+ letter = abbrev;
+ }
+
+ public String getName() {
+ return fullName;
+ }
+
+ public String getLetter() {
+ return letter;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public boolean isStop() {
+ return this == Stop_codon;
+ }
+
+ public String toString() {
+ return getName();
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/analysis/AminoAcidTable.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/analysis/AminoAcidTable.java
new file mode 100644
index 0000000..7cd8933
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/analysis/AminoAcidTable.java
@@ -0,0 +1,94 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.analysis;
+
+import java.util.HashMap;
+
+/*
+ * Copyright (c) 2010 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author chartl
+ * @since June 28, 2010
+ */
+
+public class AminoAcidTable {
+ public HashMap<String,AminoAcid> tableByCodon = new HashMap<String,AminoAcid>(21);
+ public HashMap<String,AminoAcid> tableByCode = new HashMap<String,AminoAcid>(21);
+ public AminoAcidTable() {
+ for ( AminoAcid acid : AminoAcid.values() ) {
+ tableByCode.put(acid.getCode(),acid);
+ for ( String codon : acid.codons ) {
+ tableByCodon.put(codon,acid);
+ }
+ }
+ }
+
+ // todo -- these functions are for the genomic annotator and are named too generally -- they are
+ // todo -- actually accessors by codon; thus should be more specific.
+ public AminoAcid getEukaryoticAA(String codon) {
+ return tableByCodon.get(codon.toUpperCase());
+ }
+
+ public AminoAcid getMitochondrialAA(String codon, boolean isFirst) {
+ String upperCodon = codon.toUpperCase();
+ if ( isFirst && upperCodon.equals("ATT") || upperCodon.equals("ATA") ) {
+ return AminoAcid.Methionine;
+ } else if ( upperCodon.equals("AGA") || upperCodon.equals("AGG") ) {
+ return AminoAcid.Stop_codon;
+ } else if ( upperCodon.equals("TGA") ) {
+ return AminoAcid.Tryptophan;
+ } else {
+ return tableByCodon.get(upperCodon);
+ }
+ }
+
+ public AminoAcid getAminoAcidByCode(String code) {
+ return tableByCode.get(code);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/analysis/AminoAcidUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/analysis/AminoAcidUtils.java
new file mode 100644
index 0000000..9213e82
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/analysis/AminoAcidUtils.java
@@ -0,0 +1,77 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.analysis;
+
+/*
+ * Copyright (c) 2010 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author chartl
+ * @since June 28, 2010
+ */
+
+public class AminoAcidUtils {
+
+ public static String[] getAminoAcidNames() {
+ String[] names = new String[AminoAcid.values().length];
+ for ( AminoAcid acid : AminoAcid.values() ) {
+ names[acid.ordinal()] = acid.getName();
+ }
+
+ return names;
+ }
+
+ public static String[] getAminoAcidCodes() {
+ String[] codes = new String[AminoAcid.values().length];
+ for ( AminoAcid acid : AminoAcid.values() ) {
+ codes[acid.ordinal()] = acid.getCode();
+ }
+
+ return codes;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/baq/BAQ.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/baq/BAQ.java
new file mode 100644
index 0000000..da8d00e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/baq/BAQ.java
@@ -0,0 +1,713 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.baq;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequence;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMUtils;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+/*
+ The topology of the profile HMM:
+
+ /\ /\ /\ /\
+ I[1] I[k-1] I[k] I[L]
+ ^ \ \ ^ \ ^ \ \ ^
+ | \ \ | \ | \ \ |
+ M[0] M[1] -> ... -> M[k-1] -> M[k] -> ... -> M[L] M[L+1]
+ \ \/ \/ \/ /
+ \ /\ /\ /\ /
+ -> D[k-1] -> D[k] ->
+
+ M[0] points to every {M,I}[k] and every {M,I}[k] points M[L+1].
+
+ On input, _ref is the reference sequence and _query is the query
+ sequence. Both are sequences of 0/1/2/3/4 where 4 stands for an
+ ambiguous residue. iqual is the base quality. c sets the gap open
+ probability, gap extension probability and band width.
+
+ On output, state and q are arrays of length l_query. The higher 30
+ bits give the reference position the query base is matched to and the
+ lower two bits can be 0 (an alignment match) or 1 (an
+ insertion). q[i] gives the phred scaled posterior probability of
+ state[i] being wrong.
+ */
+public class BAQ {
+ private final static Logger logger = Logger.getLogger(BAQ.class);
+ private final static boolean DEBUG = false;
+
+ public enum CalculationMode {
+ OFF, // don't apply BAQ at all, the default
+ CALCULATE_AS_NECESSARY, // do HMM BAQ calculation on the fly, as necessary, if there's no tag
+ RECALCULATE // do HMM BAQ calculation on the fly, regardless of whether there's a tag present
+ }
+
+ /** these are features that only the walker can override */
+ public enum QualityMode {
+ ADD_TAG, // calculate the BAQ, but write it into the reads as the BAQ tag, leaving QUAL field alone
+ OVERWRITE_QUALS, // overwrite the quality field directly
+ DONT_MODIFY // do the BAQ, but don't modify the quality scores themselves, just return them in the function.
+ }
+
+ public static final String BAQ_TAG = "BQ";
+
+ private static double[] qual2prob = new double[256];
+ static {
+ for (int i = 0; i < 256; ++i)
+ qual2prob[i] = Math.pow(10, -i/10.);
+ }
+
+ // Phred scaled now (changed 1/10/2011)
+ public static final double DEFAULT_GOP = 40;
+
+ /* Takes a Phred Scale quality score and returns the error probability.
+ *
+ * Quick conversion function to maintain internal structure of BAQ calculation on
+ * probability scale, but take the user entered parameter in phred-scale.
+ *
+ * @param x phred scaled score
+ * @return probability of incorrect base call
+ */
+ private double convertFromPhredScale(double x) { return (Math.pow(10,(-x)/10.));}
+
+ public double cd = -1; // gap open probability [1e-3]
+ private double ce = 0.1; // gap extension probability [0.1]
+ private int cb = 7; // band width [7]
+ private boolean includeClippedBases = false;
+
+ public byte getMinBaseQual() {
+ return minBaseQual;
+ }
+
+ /**
+ * Any bases with Q < MIN_BASE_QUAL are raised up to this base quality
+ */
+ private byte minBaseQual = 4;
+
+ public double getGapOpenProb() {
+ return cd;
+ }
+
+ public double getGapExtensionProb() {
+ return ce;
+ }
+
+ public int getBandWidth() {
+ return cb;
+ }
+
+ /**
+ * Use defaults for everything
+ */
+ public BAQ() {
+ this(DEFAULT_GOP);
+ }
+
+ /**
+ * Use defaults for everything
+ */
+ public BAQ(final double gapOpenPenalty) {
+ cd = convertFromPhredScale(gapOpenPenalty);
+ initializeCachedData();
+ }
+
+
+
+ /**
+ * Create a new HmmGlocal object with specified parameters
+ *
+ * @param d gap open prob (not phred scaled!).
+ * @param e gap extension prob.
+ * @param b band width
+ * @param minBaseQual All bases with Q < minBaseQual are up'd to this value
+ */
+ public BAQ(final double d, final double e, final int b, final byte minBaseQual, boolean includeClippedBases) {
+ cd = d; ce = e; cb = b;
+ this.minBaseQual = minBaseQual;
+ this.includeClippedBases = includeClippedBases;
+ initializeCachedData();
+ }
+
+ private final static double EM = 0.33333333333;
+ private final static double EI = 0.25;
+
+ private double[][][] EPSILONS = new double[256][256][SAMUtils.MAX_PHRED_SCORE+1];
+
+ private void initializeCachedData() {
+ for ( int i = 0; i < 256; i++ )
+ for ( int j = 0; j < 256; j++ )
+ for ( int q = 0; q <= SAMUtils.MAX_PHRED_SCORE; q++ ) {
+ EPSILONS[i][j][q] = 1.0;
+ }
+
+ for ( char b1 : "ACGTacgt".toCharArray() ) {
+ for ( char b2 : "ACGTacgt".toCharArray() ) {
+ for ( int q = 0; q <= SAMUtils.MAX_PHRED_SCORE; q++ ) {
+ double qual = qual2prob[q < minBaseQual ? minBaseQual : q];
+ double e = Character.toLowerCase(b1) == Character.toLowerCase(b2) ? 1 - qual : qual * EM;
+ EPSILONS[(byte)b1][(byte)b2][q] = e;
+ }
+ }
+ }
+ }
+
+ protected double calcEpsilon( byte ref, byte read, byte qualB ) {
+ return EPSILONS[ref][read][qualB];
+ }
+
+ // ####################################################################################################
+ //
+ // NOTE -- THIS CODE IS SYNCHRONIZED WITH CODE IN THE SAMTOOLS REPOSITORY. CHANGES TO THIS CODE SHOULD BE
+ // NOTE -- PUSHED BACK TO HENG LI
+ //
+ // ####################################################################################################
+ public int hmm_glocal(final byte[] ref, final byte[] query, int qstart, int l_query, final byte[] _iqual, int[] state, byte[] q) {
+ if ( ref == null ) throw new ReviewedGATKException("BUG: ref sequence is null");
+ if ( query == null ) throw new ReviewedGATKException("BUG: query sequence is null");
+ if ( _iqual == null ) throw new ReviewedGATKException("BUG: query quality vector is null");
+ if ( query.length != _iqual.length ) throw new ReviewedGATKException("BUG: read sequence length != qual length");
+ if ( l_query < 1 ) throw new ReviewedGATKException("BUG: length of query sequence < 0: " + l_query);
+ if ( qstart < 0 ) throw new ReviewedGATKException("BUG: query sequence start < 0: " + qstart);
+
+ //if ( q != null && q.length != state.length ) throw new ReviewedGATKException("BUG: BAQ quality length != read sequence length");
+ //if ( state != null && state.length != l_query ) throw new ReviewedGATKException("BUG: state length != read sequence length");
+
+ int i, k;
+
+ /*** initialization ***/
+ // change coordinates
+ final int l_ref = ref.length;
+
+ // set band width
+ int bw2, bw = l_ref > l_query? l_ref : l_query;
+ if (cb < Math.abs(l_ref - l_query)) {
+ bw = Math.abs(l_ref - l_query) + 3;
+ //System.out.printf("SC cb=%d, bw=%d%n", cb, bw);
+ }
+ if (bw > cb) bw = cb;
+ if (bw < Math.abs(l_ref - l_query)) {
+ //int bwOld = bw;
+ bw = Math.abs(l_ref - l_query);
+ //System.out.printf("old bw is %d, new is %d%n", bwOld, bw);
+ }
+ //System.out.printf("c->bw = %d, bw = %d, l_ref = %d, l_query = %d\n", cb, bw, l_ref, l_query);
+ bw2 = bw * 2 + 1;
+
+ // allocate the forward and backward matrices f[][] and b[][] and the scaling array s[]
+ double[][] f = new double[l_query+1][bw2*3 + 6];
+ double[][] b = new double[l_query+1][bw2*3 + 6];
+ double[] s = new double[l_query+2];
+
+ // initialize transition probabilities
+ double sM, sI, bM, bI;
+ sM = sI = 1. / (2 * l_query + 2);
+ bM = (1 - cd) / l_ref; bI = cd / l_ref; // (bM+bI)*l_ref==1
+
+ double[] m = new double[9];
+ m[0*3+0] = (1 - cd - cd) * (1 - sM); m[0*3+1] = m[0*3+2] = cd * (1 - sM);
+ m[1*3+0] = (1 - ce) * (1 - sI); m[1*3+1] = ce * (1 - sI); m[1*3+2] = 0.;
+ m[2*3+0] = 1 - ce; m[2*3+1] = 0.; m[2*3+2] = ce;
+
+
+ /*** forward ***/
+ // f[0]
+ f[0][set_u(bw, 0, 0)] = s[0] = 1.;
+ { // f[1]
+ double[] fi = f[1];
+ double sum;
+ int beg = 1, end = l_ref < bw + 1? l_ref : bw + 1, _beg, _end;
+ for (k = beg, sum = 0.; k <= end; ++k) {
+ int u;
+ double e = calcEpsilon(ref[k-1], query[qstart], _iqual[qstart]);
+ u = set_u(bw, 1, k);
+ fi[u+0] = e * bM; fi[u+1] = EI * bI;
+ sum += fi[u] + fi[u+1];
+ }
+ // rescale
+ s[1] = sum;
+ _beg = set_u(bw, 1, beg); _end = set_u(bw, 1, end); _end += 2;
+ for (k = _beg; k <= _end; ++k) fi[k] /= sum;
+ }
+
+ // f[2..l_query]
+ for (i = 2; i <= l_query; ++i) {
+ double[] fi = f[i], fi1 = f[i-1];
+ double sum;
+ int beg = 1, end = l_ref, x, _beg, _end;
+ byte qyi = query[qstart+i-1];
+ x = i - bw; beg = beg > x? beg : x; // band start
+ x = i + bw; end = end < x? end : x; // band end
+ for (k = beg, sum = 0.; k <= end; ++k) {
+ int u, v11, v01, v10;
+ double e = calcEpsilon(ref[k-1], qyi, _iqual[qstart+i-1]);
+ u = set_u(bw, i, k); v11 = set_u(bw, i-1, k-1); v10 = set_u(bw, i-1, k); v01 = set_u(bw, i, k-1);
+ fi[u+0] = e * (m[0] * fi1[v11+0] + m[3] * fi1[v11+1] + m[6] * fi1[v11+2]);
+ fi[u+1] = EI * (m[1] * fi1[v10+0] + m[4] * fi1[v10+1]);
+ fi[u+2] = m[2] * fi[v01+0] + m[8] * fi[v01+2];
+ sum += fi[u] + fi[u+1] + fi[u+2];
+ //System.out.println("("+i+","+k+";"+u+"): "+fi[u]+","+fi[u+1]+","+fi[u+2]);
+ }
+ // rescale
+ s[i] = sum;
+ _beg = set_u(bw, i, beg); _end = set_u(bw, i, end); _end += 2;
+ for (k = _beg, sum = 1./sum; k <= _end; ++k) fi[k] *= sum;
+ }
+ { // f[l_query+1]
+ double sum;
+ for (k = 1, sum = 0.; k <= l_ref; ++k) {
+ int u = set_u(bw, l_query, k);
+ if (u < 3 || u >= bw2*3+3) continue;
+ sum += f[l_query][u+0] * sM + f[l_query][u+1] * sI;
+ }
+ s[l_query+1] = sum; // the last scaling factor
+ }
+
+ /*** backward ***/
+ // b[l_query] (b[l_query+1][0]=1 and thus \tilde{b}[][]=1/s[l_query+1]; this is where s[l_query+1] comes from)
+ for (k = 1; k <= l_ref; ++k) {
+ int u = set_u(bw, l_query, k);
+ double[] bi = b[l_query];
+ if (u < 3 || u >= bw2*3+3) continue;
+ bi[u+0] = sM / s[l_query] / s[l_query+1]; bi[u+1] = sI / s[l_query] / s[l_query+1];
+ }
+ // b[l_query-1..1]
+ for (i = l_query - 1; i >= 1; --i) {
+ int beg = 1, end = l_ref, x, _beg, _end;
+ double[] bi = b[i], bi1 = b[i+1];
+ double y = (i > 1)? 1. : 0.;
+ byte qyi1 = query[qstart+i];
+ x = i - bw; beg = beg > x? beg : x;
+ x = i + bw; end = end < x? end : x;
+ for (k = end; k >= beg; --k) {
+ int u, v11, v01, v10;
+ u = set_u(bw, i, k); v11 = set_u(bw, i+1, k+1); v10 = set_u(bw, i+1, k); v01 = set_u(bw, i, k+1);
+ final double e = (k >= l_ref? 0 : calcEpsilon(ref[k], qyi1, _iqual[qstart+i])) * bi1[v11];
+ bi[u+0] = e * m[0] + EI * m[1] * bi1[v10+1] + m[2] * bi[v01+2]; // bi1[v11] has been folded into e.
+ bi[u+1] = e * m[3] + EI * m[4] * bi1[v10+1];
+ bi[u+2] = (e * m[6] + m[8] * bi[v01+2]) * y;
+ }
+ // rescale
+ _beg = set_u(bw, i, beg); _end = set_u(bw, i, end); _end += 2;
+ for (k = _beg, y = 1./s[i]; k <= _end; ++k) bi[k] *= y;
+ }
+
+ double pb;
+ { // b[0]
+ int beg = 1, end = l_ref < bw + 1? l_ref : bw + 1;
+ double sum = 0.;
+ for (k = end; k >= beg; --k) {
+ int u = set_u(bw, 1, k);
+ double e = calcEpsilon(ref[k-1], query[qstart], _iqual[qstart]);
+ if (u < 3 || u >= bw2*3+3) continue;
+ sum += e * b[1][u+0] * bM + EI * b[1][u+1] * bI;
+ }
+ pb = b[0][set_u(bw, 0, 0)] = sum / s[0]; // if everything works as is expected, pb == 1.0
+ }
+
+
+ /*** MAP ***/
+ for (i = 1; i <= l_query; ++i) {
+ double sum = 0., max = 0.;
+ final double[] fi = f[i], bi = b[i];
+ int beg = 1, end = l_ref, x, max_k = -1;
+ x = i - bw; beg = beg > x? beg : x;
+ x = i + bw; end = end < x? end : x;
+ for (k = beg; k <= end; ++k) {
+ final int u = set_u(bw, i, k);
+ double z;
+ sum += (z = fi[u+0] * bi[u+0]); if (z > max) { max = z; max_k = (k-1)<<2 | 0; }
+ sum += (z = fi[u+1] * bi[u+1]); if (z > max) { max = z; max_k = (k-1)<<2 | 1; }
+ }
+ max /= sum; sum *= s[i]; // if everything works as is expected, sum == 1.0
+ if (state != null) state[qstart+i-1] = max_k;
+ if (q != null) {
+ k = (int)(-4.343 * Math.log(1. - max) + .499); // = 10*log10(1-max)
+ q[qstart+i-1] = (byte)(k > 100? 99 : (k < minBaseQual ? minBaseQual : k));
+ }
+ //System.out.println("("+pb+","+sum+")"+" ("+(i-1)+","+(max_k>>2)+","+(max_k&3)+","+max+")");
+ }
+
+ return 0;
+ }
+
+ // ---------------------------------------------------------------------------------------------------------------
+ //
+ // Helper routines
+ //
+ // ---------------------------------------------------------------------------------------------------------------
+
+ /** decode the bit encoded state array values */
+ public static boolean stateIsIndel(int state) {
+ return (state & 3) != 0;
+ }
+
+ /** decode the bit encoded state array values */
+ public static int stateAlignedPosition(int state) {
+ return state >> 2;
+ }
+
+ /**
+ * helper routine for hmm_glocal
+ *
+ * @param b
+ * @param i
+ * @param k
+ * @return
+ */
+ private static int set_u(final int b, final int i, final int k) {
+ int x = i - b;
+ x = x > 0 ? x : 0;
+ return (k + 1 - x) * 3;
+ }
+
+ // ---------------------------------------------------------------------------------------------------------------
+ //
+ // Actually working with the BAQ tag now
+ //
+ // ---------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Get the BAQ attribute from the tag in read. Returns null if no BAQ tag is present.
+ * @param read
+ * @return
+ */
+ public static byte[] getBAQTag(SAMRecord read) {
+ String s = read.getStringAttribute(BAQ_TAG);
+ return s != null ? s.getBytes() : null;
+ }
+
+ public static String encodeBQTag(SAMRecord read, byte[] baq) {
+ // Offset to base alignment quality (BAQ), of the same length as the read sequence.
+ // At the i-th read base, BAQi = Qi - (BQi - 64) where Qi is the i-th base quality.
+ // so BQi = Qi - BAQi + 64
+ byte[] bqTag = new byte[baq.length];
+ for ( int i = 0; i < bqTag.length; i++) {
+ final int bq = (int)read.getBaseQualities()[i] + 64;
+ final int baq_i = (int)baq[i];
+ final int tag = bq - baq_i;
+ // problem with the calculation of the correction factor; this is our problem
+ if ( tag < 0 )
+ throw new ReviewedGATKException("BAQ tag calculation error. BAQ value above base quality at " + read);
+ // the original quality is too high, almost certainly due to using the wrong encoding in the BAM file
+ if ( tag > Byte.MAX_VALUE )
+ throw new UserException.MisencodedBAM(read, "we encountered an extremely high quality score (" + (int)read.getBaseQualities()[i] + ") with BAQ correction factor of " + baq_i);
+ bqTag[i] = (byte)tag;
+ }
+ return new String(bqTag);
+ }
+
+ public static void addBAQTag(SAMRecord read, byte[] baq) {
+ read.setAttribute(BAQ_TAG, encodeBQTag(read, baq));
+ }
+
+
+ /**
+ * Returns true if the read has a BAQ tag, or false otherwise
+ * @param read
+ * @return
+ */
+ public static boolean hasBAQTag(SAMRecord read) {
+ return read.getStringAttribute(BAQ_TAG) != null;
+ }
+
+ /**
+ * Returns a new qual array for read that includes the BAQ adjustment. Does not support on-the-fly BAQ calculation
+ *
+ * @param read the SAMRecord to operate on
+ * @param overwriteOriginalQuals If true, we replace the original qualities scores in the read with their BAQ'd version
+ * @param useRawQualsIfNoBAQTag If useRawQualsIfNoBAQTag is true, then if there's no BAQ annotation we just use the raw quality scores. Throws IllegalStateException is false and no BAQ tag is present
+ * @return
+ */
+ public static byte[] calcBAQFromTag(SAMRecord read, boolean overwriteOriginalQuals, boolean useRawQualsIfNoBAQTag) {
+ byte[] rawQuals = read.getBaseQualities();
+ byte[] newQuals = rawQuals;
+ byte[] baq = getBAQTag(read);
+
+ if ( baq != null ) {
+ // Offset to base alignment quality (BAQ), of the same length as the read sequence.
+ // At the i-th read base, BAQi = Qi - (BQi - 64) where Qi is the i-th base quality.
+ newQuals = overwriteOriginalQuals ? rawQuals : new byte[rawQuals.length];
+ for ( int i = 0; i < rawQuals.length; i++) {
+ int rawQual = (int)rawQuals[i];
+ int baq_delta = (int)baq[i] - 64;
+ int newval = rawQual - baq_delta;
+ if ( newval < 0 )
+ throw new UserException.MalformedBAM(read, "BAQ tag error: the BAQ value is larger than the base quality");
+ newQuals[i] = (byte)newval;
+ }
+ } else if ( ! useRawQualsIfNoBAQTag ) {
+ throw new IllegalStateException("Required BAQ tag to be present, but none was on read " + read.getReadName());
+ }
+
+ return newQuals;
+ }
+
+ /**
+ * Returns the BAQ adjusted quality score for this read at this offset. Does not support on-the-fly BAQ calculation
+ *
+ * @param read the SAMRecord to operate on
+ * @param offset the offset of operate on
+ * @param useRawQualsIfNoBAQTag If useRawQualsIfNoBAQTag is true, then if there's no BAQ annotation we just use the raw quality scores. Throws IllegalStateException is false and no BAQ tag is present
+ * @return
+ */
+ public static byte calcBAQFromTag(SAMRecord read, int offset, boolean useRawQualsIfNoBAQTag) {
+ byte rawQual = read.getBaseQualities()[offset];
+ byte newQual = rawQual;
+ byte[] baq = getBAQTag(read);
+
+ if ( baq != null ) {
+ // Offset to base alignment quality (BAQ), of the same length as the read sequence.
+ // At the i-th read base, BAQi = Qi - (BQi - 64) where Qi is the i-th base quality.
+ int baq_delta = (int)baq[offset] - 64;
+ int newval = rawQual - baq_delta;
+ if ( newval < 0 )
+ throw new UserException.MalformedBAM(read, "BAQ tag error: the BAQ value is larger than the base quality");
+ newQual = (byte)newval;
+
+ } else if ( ! useRawQualsIfNoBAQTag ) {
+ throw new IllegalStateException("Required BAQ tag to be present, but none was on read " + read.getReadName());
+ }
+
+ return newQual;
+ }
+
+ public static class BAQCalculationResult {
+ public byte[] refBases, rawQuals, readBases, bq;
+ public int[] state;
+
+ public BAQCalculationResult(SAMRecord read, byte[] ref) {
+ this(read.getBaseQualities(), read.getReadBases(), ref);
+ }
+
+ public BAQCalculationResult(byte[] bases, byte[] quals, byte[] ref) {
+ // prepares data for calculation
+ rawQuals = quals;
+ readBases = bases;
+
+ // now actually prepare the data structures, and fire up the hmm
+ bq = new byte[rawQuals.length];
+ state = new int[rawQuals.length];
+ this.refBases = ref;
+ }
+ }
+
+ public BAQCalculationResult calcBAQFromHMM(SAMRecord read, IndexedFastaSequenceFile refReader) {
+ // start is alignment start - band width / 2 - size of first I element, if there is one. Stop is similar
+ int offset = getBandWidth() / 2;
+ long readStart = includeClippedBases ? read.getUnclippedStart() : read.getAlignmentStart();
+ long start = Math.max(readStart - offset - ReadUtils.getFirstInsertionOffset(read), 0);
+ long stop = (includeClippedBases ? read.getUnclippedEnd() : read.getAlignmentEnd()) + offset + ReadUtils.getLastInsertionOffset(read);
+
+ if ( stop > refReader.getSequenceDictionary().getSequence(read.getReferenceName()).getSequenceLength() ) {
+ return null;
+ } else {
+ // now that we have the start and stop, get the reference sequence covering it
+ ReferenceSequence refSeq = refReader.getSubsequenceAt(read.getReferenceName(), start, stop);
+ return calcBAQFromHMM(read, refSeq.getBases(), (int)(start - readStart));
+ }
+ }
+
+// final SimpleTimer total = new SimpleTimer();
+// final SimpleTimer local = new SimpleTimer();
+// int n = 0;
+ public BAQCalculationResult calcBAQFromHMM(byte[] ref, byte[] query, byte[] quals, int queryStart, int queryEnd ) {
+// total.restart();
+ if ( queryStart < 0 ) throw new ReviewedGATKException("BUG: queryStart < 0: " + queryStart);
+ if ( queryEnd < 0 ) throw new ReviewedGATKException("BUG: queryEnd < 0: " + queryEnd);
+ if ( queryEnd < queryStart ) throw new ReviewedGATKException("BUG: queryStart < queryEnd : " + queryStart + " end =" + queryEnd);
+
+ // note -- assumes ref is offset from the *CLIPPED* start
+ BAQCalculationResult baqResult = new BAQCalculationResult(query, quals, ref);
+ int queryLen = queryEnd - queryStart;
+// local.restart();
+ hmm_glocal(baqResult.refBases, baqResult.readBases, queryStart, queryLen, baqResult.rawQuals, baqResult.state, baqResult.bq);
+// local.stop();
+// total.stop();
+// if ( n++ % 100000 == 0 )
+// logger.info("n = " + n + ": Total " + total.getElapsedTimeNano() + " local " + local.getElapsedTimeNano());
+ return baqResult;
+ }
+
+
+ /**
+ * Determine the appropriate start and stop offsets in the reads for the bases given the cigar string
+ * @param read
+ * @return
+ */
+ private final Pair<Integer,Integer> calculateQueryRange(SAMRecord read) {
+ int queryStart = -1, queryStop = -1;
+ int readI = 0;
+
+ // iterate over the cigar elements to determine the start and stop of the read bases for the BAQ calculation
+ for ( CigarElement elt : read.getCigar().getCigarElements() ) {
+ switch (elt.getOperator()) {
+ case N: return null; // cannot handle these
+ case H : case P : case D: break; // ignore pads, hard clips, and deletions
+ case I : case S: case M: case EQ: case X:
+ int prev = readI;
+ readI += elt.getLength();
+ if ( includeClippedBases || elt.getOperator() != CigarOperator.S) {
+ if ( queryStart == -1 )
+ queryStart = prev;
+ queryStop = readI;
+ }
+ // in the else case we aren't including soft clipped bases, so we don't update
+ // queryStart or queryStop
+ break;
+ default: throw new ReviewedGATKException("BUG: Unexpected CIGAR element " + elt + " in read " + read.getReadName());
+ }
+ }
+
+ if ( queryStop == queryStart ) {
+ // this read is completely clipped away, and yet is present in the file for some reason
+ // usually they are flagged as non-PF, but it's possible to push them through the BAM
+ //System.err.printf("WARNING -- read is completely clipped away: " + read.format());
+ return null;
+ }
+
+ return new Pair<Integer, Integer>(queryStart, queryStop);
+ }
+
+ // we need to pad ref by at least the bandwidth / 2 on either side
+ public BAQCalculationResult calcBAQFromHMM(SAMRecord read, byte[] ref, int refOffset) {
+ // todo -- need to handle the case where the cigar sum of lengths doesn't cover the whole read
+ Pair<Integer, Integer> queryRange = calculateQueryRange(read);
+ if ( queryRange == null ) return null; // read has Ns, or is completely clipped away
+
+ int queryStart = queryRange.getFirst();
+ int queryEnd = queryRange.getSecond();
+
+ BAQCalculationResult baqResult = calcBAQFromHMM(ref, read.getReadBases(), read.getBaseQualities(), queryStart, queryEnd);
+
+ // cap quals
+ int readI = 0, refI = 0;
+ for ( CigarElement elt : read.getCigar().getCigarElements() ) {
+ int l = elt.getLength();
+ switch (elt.getOperator()) {
+ case N: // cannot handle these
+ return null;
+ case H : case P : // ignore pads and hard clips
+ break;
+ case S : refI += l; // move the reference too, in addition to I
+ case I :
+ // todo -- is it really the case that we want to treat I and S the same?
+ for ( int i = readI; i < readI + l; i++ ) baqResult.bq[i] = baqResult.rawQuals[i];
+ readI += l;
+ break;
+ case D : refI += l; break;
+ case M :
+ for (int i = readI; i < readI + l; i++) {
+ int expectedPos = refI - refOffset + (i - readI);
+ baqResult.bq[i] = capBaseByBAQ( baqResult.rawQuals[i], baqResult.bq[i], baqResult.state[i], expectedPos );
+ }
+ readI += l; refI += l;
+ break;
+ default:
+ throw new ReviewedGATKException("BUG: Unexpected CIGAR element " + elt + " in read " + read.getReadName());
+ }
+ }
+ if ( readI != read.getReadLength() ) // odd cigar string
+ System.arraycopy(baqResult.rawQuals, 0, baqResult.bq, 0, baqResult.bq.length);
+
+ return baqResult;
+ }
+
+ public byte capBaseByBAQ( byte oq, byte bq, int state, int expectedPos ) {
+ byte b;
+ boolean isIndel = stateIsIndel(state);
+ int pos = stateAlignedPosition(state);
+ if ( isIndel || pos != expectedPos ) // we are an indel or we don't align to our best current position
+ b = minBaseQual; // just take b = minBaseQuality
+ else
+ b = bq < oq ? bq : oq;
+
+ return b;
+ }
+
+ /**
+ * Modifies read in place so that the base quality scores are capped by the BAQ calculation. Uses the BAQ
+ * tag if present already and alwaysRecalculate is false, otherwise fires up the HMM and does the BAQ on the fly
+ * using the refReader to obtain the reference bases as needed.
+ *
+ * @param read
+ * @param refReader
+ * @param calculationType
+ * @return BQ qualities for use, in case qmode is DONT_MODIFY
+ */
+ public byte[] baqRead(SAMRecord read, IndexedFastaSequenceFile refReader, CalculationMode calculationType, QualityMode qmode ) {
+ if ( DEBUG ) System.out.printf("BAQ %s read %s%n", calculationType, read.getReadName());
+
+ byte[] BAQQuals = read.getBaseQualities(); // in general we are overwriting quals, so just get a pointer to them
+ if ( calculationType == CalculationMode.OFF) { // we don't want to do anything
+ ; // just fall though
+ } else if ( excludeReadFromBAQ(read) ) {
+ ; // just fall through
+ } else {
+ final boolean readHasBAQTag = hasBAQTag(read);
+
+ if ( calculationType == CalculationMode.RECALCULATE || ! readHasBAQTag ) {
+ if ( DEBUG ) System.out.printf(" Calculating BAQ on the fly%n");
+ BAQCalculationResult hmmResult = calcBAQFromHMM(read, refReader);
+ if ( hmmResult != null ) {
+ switch ( qmode ) {
+ case ADD_TAG: addBAQTag(read, hmmResult.bq); break;
+ case OVERWRITE_QUALS: System.arraycopy(hmmResult.bq, 0, read.getBaseQualities(), 0, hmmResult.bq.length); break;
+ case DONT_MODIFY: BAQQuals = hmmResult.bq; break;
+ default: throw new ReviewedGATKException("BUG: unexpected qmode " + qmode);
+ }
+ } else if ( readHasBAQTag ) {
+ // remove the BAQ tag if it's there because we cannot trust it
+ read.setAttribute(BAQ_TAG, null);
+ }
+ } else if ( qmode == QualityMode.OVERWRITE_QUALS ) { // only makes sense if we are overwriting quals
+ if ( DEBUG ) System.out.printf(" Taking BAQ from tag%n");
+ // this overwrites the original qualities
+ calcBAQFromTag(read, true, false);
+ }
+ }
+
+ return BAQQuals;
+ }
+
+ /**
+ * Returns true if we don't think this read is eligible for the BAQ calculation. Examples include non-PF reads,
+ * duplicates, or unmapped reads. Used by baqRead to determine if a read should fall through the calculation.
+ *
+ * @param read
+ * @return
+ */
+ public boolean excludeReadFromBAQ(SAMRecord read) {
+ // keeping mapped reads, regardless of pairing status, or primary alignment status.
+ return read.getReadUnmappedFlag() || read.getReadFailsVendorQualityCheckFlag() || read.getDuplicateReadFlag();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/baq/BAQReadTransformer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/baq/BAQReadTransformer.java
new file mode 100644
index 0000000..c9192e1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/baq/BAQReadTransformer.java
@@ -0,0 +1,74 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.baq;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.WalkerManager;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.engine.walkers.BAQMode;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+/**
+ * Applies Heng's BAQ calculation to a stream of incoming reads
+ */
+public class BAQReadTransformer extends ReadTransformer {
+ private BAQ baqHMM;
+ private IndexedFastaSequenceFile refReader;
+ private BAQ.CalculationMode cmode;
+ private BAQ.QualityMode qmode;
+
+ @Override
+ public ApplicationTime initializeSub(final GenomeAnalysisEngine engine, final Walker walker) {
+ final BAQMode mode = WalkerManager.getWalkerAnnotation(walker, BAQMode.class);
+ this.refReader = engine.getReferenceDataSource().getReference();
+ this.cmode = engine.getArguments().BAQMode;
+ this.qmode = mode.QualityMode();
+ baqHMM = new BAQ(engine.getArguments().BAQGOP);
+
+ if ( qmode == BAQ.QualityMode.DONT_MODIFY )
+ throw new ReviewedGATKException("BUG: shouldn't create BAQ transformer with quality mode DONT_MODIFY");
+
+ if ( mode.ApplicationTime() == ReadTransformer.ApplicationTime.FORBIDDEN && enabled() )
+ throw new UserException.BadArgumentValue("baq", "Walker cannot accept BAQ'd base qualities, and yet BAQ mode " + cmode + " was requested.");
+
+ return mode.ApplicationTime();
+ }
+
+ @Override
+ public boolean enabled() {
+ return cmode != BAQ.CalculationMode.OFF;
+ }
+
+ @Override
+ public GATKSAMRecord apply(final GATKSAMRecord read) {
+ baqHMM.baqRead(read, refReader, cmode, qmode);
+ return read;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/baq/ReadTransformingIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/baq/ReadTransformingIterator.java
new file mode 100644
index 0000000..18ca02f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/baq/ReadTransformingIterator.java
@@ -0,0 +1,69 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.baq;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Iterator;
+
+/**
+ * Iterator that applies a ReadTransformer to a stream of reads
+ */
+public class ReadTransformingIterator implements GATKSAMIterator {
+ private final GATKSAMIterator it;
+ private final ReadTransformer transformer;
+
+ /**
+ * Creates a new ReadTransforming iterator
+ */
+ @Requires({"it != null", "transformer != null", "transformer.isInitialized()"})
+ public ReadTransformingIterator(final GATKSAMIterator it, final ReadTransformer transformer) {
+ if ( ! transformer.isInitialized() )
+ throw new IllegalStateException("Creating a read transformer stream for an uninitialized read transformer: " + transformer);
+ if ( transformer.getApplicationTime() == ReadTransformer.ApplicationTime.FORBIDDEN )
+ throw new IllegalStateException("Creating a read transformer stream for a forbidden transformer " + transformer);
+
+ this.it = it;
+ this.transformer = transformer;
+ }
+
+ @Requires("hasNext()")
+ @Ensures("result != null")
+ public SAMRecord next() {
+ final GATKSAMRecord read = (GATKSAMRecord)it.next();
+ return transformer.apply(read);
+ }
+
+ public boolean hasNext() { return this.it.hasNext(); }
+ public void remove() { throw new UnsupportedOperationException("Can not remove records from a SAM file via an iterator!"); }
+ public void close() { it.close(); }
+ public Iterator<SAMRecord> iterator() { return this; }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/JVMUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/JVMUtils.java
new file mode 100644
index 0000000..d695543
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/JVMUtils.java
@@ -0,0 +1,309 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.classloader;
+
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.reflections.util.ClasspathHelper;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.*;
+import java.net.URL;
+import java.util.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: hanna
+ * Date: Mar 30, 2009
+ * Time: 5:38:05 PM
+ *
+ * A set of static utility methods for determining information about this runtime environment.
+ * Introspects classes, loads jars, etc.
+ */
+public class JVMUtils {
+ /**
+ * Constructor access disallowed...static utility methods only!
+ */
+ private JVMUtils() { }
+
+ /**
+ * Determines which location contains the specified class.
+ * @param clazz The specified class.
+ * @return Location (either jar file or directory) of path containing class.
+ * @throws IOException when the URI cannot be found.
+ */
+ public static File getLocationFor( Class clazz ) throws IOException {
+ try {
+ java.net.URI locationURI = clazz.getProtectionDomain().getCodeSource().getLocation().toURI();
+ return new File(locationURI);
+ }
+ catch (java.net.URISyntaxException ex) {
+ // a URISyntaxException here must be an IO error; wrap as such.
+ throw new IOException(ex);
+ }
+ catch ( NullPointerException ne ) {
+ throw new IOException("Can not extract code source location for "+clazz.getName());
+ }
+ }
+
+ /**
+ * Is the specified class a concrete implementation of baseClass?
+ * @param clazz Class to check.
+ * @return True if clazz is concrete. False otherwise.
+ */
+ public static boolean isConcrete( Class clazz ) {
+ return !Modifier.isAbstract(clazz.getModifiers()) &&
+ !Modifier.isInterface(clazz.getModifiers());
+ }
+
+ /**
+ * Is the specified class anonymous? The plugin manager (for one) generally requires that
+ * plugin classes be named so that they can easily be specified from the command line.
+ * @param clazz The class on which to perform the anonymous check.
+ * @return True if the class is anonymous; false otherwise.
+ */
+ public static boolean isAnonymous(Class clazz) {
+ return clazz.isAnonymousClass();
+ }
+
+ /**
+ * Retrieve all fields available in this object, regardless of where they are declared or
+ * whether they're accessible.
+ * @param type Type to inspect for fields.
+ * @return A list of all available fields.
+ */
+ public static List<Field> getAllFields(Class type) {
+ List<Field> allFields = new ArrayList<Field>();
+ while( type != null ) {
+ allFields.addAll(Arrays.asList(type.getDeclaredFields()));
+ type = type.getSuperclass();
+ }
+ return allFields;
+ }
+
+ /**
+ * Find the field with the given name in the class. Will inspect all fields, independent
+ * of access level.
+ * @param type Class in which to search for the given field.
+ * @param fieldName Name of the field for which to search.
+ * @return The field, or null if no such field exists.
+ */
+ public static Field findField( Class type, String fieldName ) {
+ while( type != null ) {
+ Field[] fields = type.getDeclaredFields();
+ for( Field field: fields ) {
+ if( field.getName().equals(fieldName) )
+ return field;
+ }
+ type = type.getSuperclass();
+ }
+ return null;
+ }
+
+ /**
+ * Sets the provided field in the given instance to the given value. Circumvents access restrictions:
+ * a field can be private and still set successfully by this function.
+ * @param field Field to set in the given object.
+ * @param instance Instance in which to set the field.
+ * @param value The value to which to set the given field in the given instance.
+ */
+ public static void setFieldValue( Field field, Object instance, Object value ) {
+ try {
+ field.setAccessible(true);
+ field.set(instance, value);
+ }
+ catch( IllegalAccessException ex ) {
+ throw new ReviewedGATKException(String.format("Could not set %s in instance %s to %s",field.getName(),instance.getClass().getName(),value.toString()));
+ }
+ }
+
+ /**
+ * Gets the value stored in the provided field in the given instance.
+ * @param field Field to set in the given object.
+ * @param instance Instance in which to set the field.
+ * @return Value currently stored in the given field.
+ */
+ public static Object getFieldValue( Field field, Object instance ) {
+ try {
+ field.setAccessible(true);
+ return field.get(instance);
+ }
+ catch( IllegalAccessException ex ) {
+ throw new ReviewedGATKException(String.format("Could not retrieve %s in instance %s",field.getName(),instance.getClass().getName()));
+ }
+ }
+
+ /**
+ * Gets a single object in the list matching or type-compatible with the given type. Exceptions out if multiple objects match.
+ * @param objectsToFilter objects to filter.
+ * @param type The desired type.
+ * @param <T> The selected type.
+ * @return A collection of the given arguments with the specified type.
+ */
+ public static <T> T getObjectOfType(Collection<Object> objectsToFilter, Class<T> type) {
+ // TODO: Make JVM utils.
+ Collection<T> selectedObjects = getObjectsOfType(objectsToFilter,type);
+ if(selectedObjects.size() > 1)
+ throw new ReviewedGATKException("User asked for a single instance of the type, multiple were present");
+ if(selectedObjects.size() == 0)
+ throw new ReviewedGATKException("User asked for a single instance of the type, but none were present");
+ return selectedObjects.iterator().next();
+ }
+
+ /**
+ * Gets a collection of all objects in the list matching or type-compatible with the given type.
+ * @param objectsToFilter objects to filter.
+ * @param type The desired type.
+ * @param <T> Again, the desired type. Used so that clients can ignore type safety.
+ * @return A collection of the given arguments with the specified type.
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> Collection<T> getObjectsOfType(Collection<Object> objectsToFilter, Class<T> type) {
+ Collection<T> selectedObjects = new ArrayList<T>();
+ for(Object object: objectsToFilter) {
+ if(type.isAssignableFrom(object.getClass()))
+ selectedObjects.add((T)object);
+ }
+ return selectedObjects;
+ }
+
+ /**
+ * Returns the list of class path urls.
+ * @return the list of class path urls.
+ */
+ public static Set<URL> getClasspathURLs() {
+ return ClasspathHelper.forManifest();
+ }
+
+ /**
+ * Adds all the generic types from a class definition to the collection.
+ * Does not inspect the methods or fields, only the class.
+ * @param classes Set to collect the classes.
+ * @param type Type to inspect.
+ */
+ public static void addGenericTypes(Set<Class<?>> classes, Type type) {
+ if (type instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType)type;
+ for (Type actualType: parameterizedType.getActualTypeArguments())
+ addGenericTypes(classes, actualType);
+ } else if (type instanceof GenericArrayType) {
+ addGenericTypes(classes, ((GenericArrayType)type).getGenericComponentType());
+ } else if (type instanceof WildcardType) {
+ WildcardType wildcardType = (WildcardType)type;
+ for (Type upperType: wildcardType.getUpperBounds())
+ addGenericTypes(classes, upperType);
+ for (Type lowerType: wildcardType.getLowerBounds())
+ addGenericTypes(classes, lowerType);
+ } else if (type instanceof Class<?>) {
+ classes.add((Class<?>) type);
+ } else {
+ throw new GATKException("Unknown type: " + type + " (" + type.getClass().getName() + ")");
+ }
+ }
+
+ public static Class getParameterizedTypeClass(Type t) {
+ if ( t instanceof ParameterizedType ) {
+ ParameterizedType parameterizedType = (ParameterizedType)t;
+ if ( parameterizedType.getActualTypeArguments().length != 1 )
+ throw new ReviewedGATKException("BUG: more than 1 generic type found on class" + t);
+ return (Class)parameterizedType.getActualTypeArguments()[0];
+ } else
+ throw new ReviewedGATKException("BUG: could not find generic type on class " + t);
+ }
+
+ /**
+ * Returns a comma-separated list of the names of the interfaces implemented by this class
+ *
+ * @param covClass class
+ * @return names of interfaces
+ */
+ public static String classInterfaces(final Class covClass) {
+ final List<String> interfaces = new ArrayList<String>();
+ for ( final Class interfaceClass : covClass.getInterfaces() )
+ interfaces.add(interfaceClass.getSimpleName());
+ return Utils.join(", ", interfaces);
+ }
+
+ /**
+ * Returns the Class that invoked the specified "callee" class by examining the runtime stack.
+ * The calling class is defined as the first class below the callee class on the stack.
+ *
+ * For example, given callee == MyClass and the following runtime stack:
+ *
+ * JVMUtils.getCallingClass(MyClass) <-- top
+ * MyClass.foo()
+ * MyClass.bar()
+ * OtherClass.foo()
+ * OtherClass.bar()
+ * etc.
+ *
+ * this method would return OtherClass, since its methods invoked the methods in MyClass.
+ *
+ * Considers only the occurrence of the callee class on the stack that is closest to the top
+ * (even if there are multiple, non-contiguous occurrences).
+ *
+ * @param callee Class object for the class whose calling class we want to locate
+ * @return Class object for the class that invoked the callee class, or null if
+ * no calling class was found
+ * @throws IllegalArgumentException if the callee class is not found on the runtime stack
+ * @throws IllegalStateException if we get an error while trying to load the Class object for the calling
+ * class reported on the runtime stack
+ */
+ public static Class getCallingClass( final Class callee ) {
+ final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
+ final String calleeClassName = callee.getName();
+
+ // Start examining the stack at the second-from-the-top position, to remove
+ // this method call (ie., the call to getCallingClass() itself) from consideration.
+ int stackTraceIndex = 1;
+
+ // Find the first occurrence of the callee on the runtime stack. Need to use String comparison
+ // unfortunately, due to limitations of the StackTraceElement class.
+ while ( stackTraceIndex < stackTrace.length && ! stackTrace[stackTraceIndex].getClassName().equals(calleeClassName) ) {
+ stackTraceIndex++;
+ }
+
+ // Make sure we actually found the callee class on the stack
+ if ( stackTraceIndex == stackTrace.length ) {
+ throw new IllegalArgumentException(String.format("Specified callee %s is not present on the call stack", callee.getSimpleName()));
+ }
+
+ // Now find the caller class, which will be the class below the callee on the stack
+ while ( stackTraceIndex < stackTrace.length && stackTrace[stackTraceIndex].getClassName().equals(calleeClassName) ) {
+ stackTraceIndex++;
+ }
+
+ try {
+ return stackTraceIndex < stackTrace.length ? Class.forName(stackTrace[stackTraceIndex].getClassName()) : null;
+ }
+ catch ( ClassNotFoundException e ) {
+ throw new IllegalStateException(String.format("Could not find caller class %s from the runtime stack in the classpath",
+ stackTrace[stackTraceIndex].getClassName()));
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/PluginManager.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/PluginManager.java
new file mode 100644
index 0000000..7313e19
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/PluginManager.java
@@ -0,0 +1,355 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.classloader;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.WalkerManager;
+import org.broadinstitute.gatk.engine.filters.FilterManager;
+import org.broadinstitute.gatk.utils.exceptions.DynamicClassResolutionException;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.reflections.Reflections;
+import org.reflections.scanners.SubTypesScanner;
+import org.reflections.util.ConfigurationBuilder;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.*;
+
+/**
+ * Manage plugins and plugin configuration.
+ * @author mhanna
+ * @version 0.1
+ */
+public class PluginManager<PluginType> {
+ /**
+ * A reference into our introspection utility.
+ */
+ private static final Reflections defaultReflections;
+
+ static {
+ // turn off logging in the reflections library - they talk too much
+ Reflections.log = null;
+
+ Set<URL> classPathUrls = new LinkedHashSet<URL>();
+
+ URL cwd;
+ try {
+ cwd = new File(".").getAbsoluteFile().toURI().toURL();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+
+ // NOTE: Reflections also scans directories for classes.
+ // Meanwhile some of the jar MANIFEST.MF Bundle-ClassPath properties contain "."
+ // Do NOT let reflections scan the CWD where it often picks up test classes when
+ // they weren't explicitly in the classpath, for example the UninstantiableWalker
+ for (URL url: JVMUtils.getClasspathURLs())
+ if (!url.equals(cwd))
+ classPathUrls.add(url);
+
+ defaultReflections = new Reflections( new ConfigurationBuilder()
+ .setUrls(classPathUrls)
+ .setScanners(new SubTypesScanner()));
+ }
+
+ /**
+ * Defines the category of plugin defined by the subclass.
+ */
+ protected final String pluginCategory;
+
+ /**
+ * Define common strings to trim off the end of the name.
+ */
+ protected final String pluginSuffix;
+
+ /**
+ * Plugins stored based on their name.
+ */
+ private final SortedMap<String, Class<? extends PluginType>> pluginsByName;
+
+ private final List<Class<? extends PluginType>> plugins;
+ private final List<Class<? extends PluginType>> interfaces;
+
+ /**
+ * Create a new plugin manager.
+ * @param pluginType Core type for a plugin.
+ */
+ public PluginManager(Class pluginType) {
+ this(pluginType, pluginType.getSimpleName().toLowerCase(), pluginType.getSimpleName(), null);
+ }
+
+ /**
+ * Create a new plugin manager.
+ * @param pluginType Core type for a plugin.
+ * @param classpath Custom class path to search for classes.
+ */
+ public PluginManager(Class pluginType, List<URL> classpath) {
+ this(pluginType, pluginType.getSimpleName().toLowerCase(), pluginType.getSimpleName(), classpath);
+ }
+
+ /**
+ * Create a new plugin manager.
+ * @param pluginType Core type for a plugin.
+ * @param pluginCategory Provides a category name to the plugin. Must not be null.
+ * @param pluginSuffix Provides a suffix that will be trimmed off when converting to a plugin name. Can be null.
+ */
+ public PluginManager(Class pluginType, String pluginCategory, String pluginSuffix) {
+ this(pluginType, pluginCategory, pluginSuffix, null);
+ }
+
+ /**
+ * Create a new plugin manager.
+ * @param pluginType Core type for a plugin.
+ * @param pluginCategory Provides a category name to the plugin. Must not be null.
+ * @param pluginSuffix Provides a suffix that will be trimmed off when converting to a plugin name. Can be null.
+ * @param classpath Custom class path to search for classes.
+ */
+ public PluginManager(Class pluginType, String pluginCategory, String pluginSuffix, List<URL> classpath) {
+ this.pluginCategory = pluginCategory;
+ this.pluginSuffix = pluginSuffix;
+
+ this.plugins = new ArrayList<Class<? extends PluginType>>();
+ this.interfaces = new ArrayList<Class<? extends PluginType>>();
+
+ Reflections reflections;
+ if (classpath == null) {
+ reflections = defaultReflections;
+ } else {
+ addClasspath(classpath);
+ reflections = new Reflections( new ConfigurationBuilder()
+ .setUrls(classpath)
+ .setScanners(new SubTypesScanner()));
+ }
+
+ // Load all classes types filtering them by concrete.
+ @SuppressWarnings("unchecked")
+ Set<Class<? extends PluginType>> allTypes = reflections.getSubTypesOf(pluginType);
+ for( Class<? extends PluginType> type: allTypes ) {
+ // The plugin manager does not support anonymous classes; to be a plugin, a class must have a name.
+ if(JVMUtils.isAnonymous(type))
+ continue;
+
+ if( JVMUtils.isConcrete(type) )
+ plugins.add(type);
+ else
+ interfaces.add(type);
+ }
+
+ pluginsByName = new TreeMap<String, Class<? extends PluginType>>();
+ for (Class<? extends PluginType> pluginClass : plugins) {
+ String pluginName = getName(pluginClass);
+ pluginsByName.put(pluginName, pluginClass);
+ }
+
+ // sort the plugins so the order of elements is deterministic
+ sortPlugins(plugins);
+ sortPlugins(interfaces);
+ }
+
+ /**
+ * Sorts, in place, the list of plugins according to getName() on each element
+ *
+ * @param unsortedPlugins unsorted plugins
+ */
+ private void sortPlugins(final List<Class<? extends PluginType>> unsortedPlugins) {
+ Collections.sort(unsortedPlugins, new ComparePluginsByName());
+ }
+
+ private final class ComparePluginsByName implements Comparator<Class<? extends PluginType>> {
+ @Override
+ public int compare(final Class<? extends PluginType> aClass, final Class<? extends PluginType> aClass1) {
+ String pluginName1 = getName(aClass);
+ String pluginName2 = getName(aClass1);
+ return pluginName1.compareTo(pluginName2);
+ }
+ }
+
+ /**
+ * Adds the URL to the system class loader classpath using reflection.
+ * HACK: Uses reflection to modify the class path, and assumes loader is a URLClassLoader.
+ * @param urls URLs to add to the system class loader classpath.
+ */
+ private static void addClasspath(List<URL> urls) {
+ Set<URL> existing = JVMUtils.getClasspathURLs();
+ for (URL url : urls) {
+ if (existing.contains(url))
+ continue;
+ try {
+ Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
+ if (!method.isAccessible())
+ method.setAccessible(true);
+ method.invoke(ClassLoader.getSystemClassLoader(), url);
+ } catch (Exception e) {
+ throw new ReviewedGATKException("Error adding url to the current classloader.", e);
+ }
+ }
+ }
+
+ public Map<String, Class<? extends PluginType>> getPluginsByName() {
+ return Collections.unmodifiableMap(pluginsByName);
+ }
+
+ /**
+ * Does a plugin with the given name exist?
+ *
+ * @param pluginName Name of the plugin for which to search.
+ * @return True if the plugin exists, false otherwise.
+ */
+ public boolean exists(String pluginName) {
+ return pluginsByName.containsKey(pluginName);
+ }
+
+ /**
+ * Does a plugin with the given name exist?
+ *
+ * @param plugin Name of the plugin for which to search.
+ * @return True if the plugin exists, false otherwise.
+ */
+ public boolean exists(Class<? extends PluginType> plugin) {
+ return pluginsByName.containsValue(plugin);
+ }
+
+ /**
+ * Returns the plugin classes
+ * @return the plugin classes
+ */
+ public List<Class<? extends PluginType>> getPlugins() {
+ return plugins;
+ }
+
+ /**
+ * Returns the interface classes
+ * @return the interface classes
+ */
+ public List<Class<? extends PluginType>> getInterfaces() {
+ return interfaces;
+ }
+
+ /**
+ * Returns the plugin classes implementing interface or base clase
+ * @param type type of interface or base class
+ * @return the plugin classes implementing interface or base class
+ */
+ public List<Class<? extends PluginType>> getPluginsImplementing(Class<?> type) {
+ List<Class<? extends PluginType>> implementing = new ArrayList<Class<? extends PluginType>>();
+ for (Class<? extends PluginType> plugin: getPlugins())
+ if (type.isAssignableFrom(plugin))
+ implementing.add(plugin);
+ return implementing;
+ }
+
+
+
+ /**
+ * Gets a plugin with the given name
+ *
+ * @param pluginName Name of the plugin to retrieve.
+ * @return The plugin object if found; null otherwise.
+ */
+ public PluginType createByName(String pluginName) {
+ Class<? extends PluginType> plugin = pluginsByName.get(pluginName);
+ if( plugin == null ) {
+ String errorMessage = formatErrorMessage(pluginCategory,pluginName);
+ if ( this.getClass().isAssignableFrom(FilterManager.class) ) {
+ throw new UserException.MalformedReadFilterException(errorMessage);
+ } else if ( this.getClass().isAssignableFrom(WalkerManager.class) ) {
+ throw new UserException.MalformedWalkerArgumentsException(errorMessage);
+ } else {
+ throw new UserException.CommandLineException(errorMessage);
+ }
+ }
+ try {
+ return plugin.newInstance();
+ } catch (Exception e) {
+ throw new DynamicClassResolutionException(plugin, e);
+ }
+ }
+
+ /**
+ * create a plugin with the given type
+ *
+ * @param pluginType type of the plugin to create.
+ * @return The plugin object if created; null otherwise.
+ */
+ public PluginType createByType(Class<? extends PluginType> pluginType) {
+ Logger logger = Logger.getLogger(PluginManager.class);
+ logger.setLevel(Level.ERROR);
+ try {
+ Constructor<? extends PluginType> noArgsConstructor = pluginType.getDeclaredConstructor((Class[])null);
+ noArgsConstructor.setAccessible(true);
+ return noArgsConstructor.newInstance();
+ } catch (Exception e) {
+ logger.error("Couldn't initialize the plugin. Typically this is because of wrong global class variable initializations.");
+ throw new DynamicClassResolutionException(pluginType, e);
+ }
+ }
+
+ /**
+ * Returns concrete instances of the plugins
+ * @return concrete instances of the plugins
+ */
+ public List<PluginType> createAllTypes() {
+ List<PluginType> instances = new ArrayList<PluginType>();
+ for ( Class<? extends PluginType> c : getPlugins() ) {
+ instances.add(createByType(c));
+ }
+ return instances;
+ }
+
+ /**
+ * Create a name for this type of plugin.
+ *
+ * @param pluginType The type of plugin.
+ * @return A name for this type of plugin.
+ */
+ public String getName(Class pluginType) {
+ String pluginName = "";
+
+ if (pluginName.length() == 0) {
+ pluginName = pluginType.getSimpleName();
+ if (pluginSuffix != null && pluginName.endsWith(pluginSuffix))
+ pluginName = pluginName.substring(0, pluginName.lastIndexOf(pluginSuffix));
+ }
+
+ return pluginName;
+ }
+
+ /**
+ * Generate the error message for the plugin manager. The message is allowed to depend on the class.
+ * @param pluginCategory - string, the category of the plugin (e.g. read filter)
+ * @param pluginName - string, what we were trying to match (but failed to)
+ * @return error message text describing the error
+ */
+ protected String formatErrorMessage(String pluginCategory, String pluginName ) {
+ return String.format("Could not find %s with name: %s", pluginCategory,pluginName);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/ProtectedPackageSource.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/ProtectedPackageSource.java
new file mode 100644
index 0000000..7c7a776
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/ProtectedPackageSource.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.classloader;
+
+public interface ProtectedPackageSource {}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/PublicPackageSource.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/PublicPackageSource.java
new file mode 100644
index 0000000..5321466
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/classloader/PublicPackageSource.java
@@ -0,0 +1,28 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.classloader;
+
+public interface PublicPackageSource {}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/clipping/ClippingOp.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/clipping/ClippingOp.java
new file mode 100644
index 0000000..f4ca70e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/clipping/ClippingOp.java
@@ -0,0 +1,617 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.clipping;
+
+import com.google.java.contract.Requires;
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import org.broadinstitute.gatk.utils.recalibration.EventType;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Stack;
+import java.util.Vector;
+
+/**
+ * Represents a clip on a read. It has a type (see the enum) along with a start and stop in the bases
+ * of the read, plus an option extraInfo (useful for carrying info where needed).
+ * <p/>
+ * Also holds the critical apply function that actually execute the clipping operation on a provided read,
+ * according to the wishes of the supplied ClippingAlgorithm enum.
+ */
+public class ClippingOp {
+ public final int start, stop; // inclusive
+
+ public ClippingOp(int start, int stop) {
+ this.start = start;
+ this.stop = stop;
+ }
+
+
+ public int getLength() {
+ return stop - start + 1;
+ }
+
+ /**
+ * Clips the bases in read according to this operation's start and stop. Uses the clipping
+ * representation used is the one provided by algorithm argument.
+ *
+ * @param algorithm clipping algorithm to use
+ * @param originalRead the read to be clipped
+ */
+ public GATKSAMRecord apply(ClippingRepresentation algorithm, GATKSAMRecord originalRead) {
+ GATKSAMRecord read = (GATKSAMRecord) originalRead.clone();
+ byte[] quals = read.getBaseQualities();
+ byte[] bases = read.getReadBases();
+ byte[] newBases = new byte[bases.length];
+ byte[] newQuals = new byte[quals.length];
+
+ switch (algorithm) {
+ // important note:
+ // it's not safe to call read.getReadBases()[i] = 'N' or read.getBaseQualities()[i] = 0
+ // because you're not guaranteed to get a pointer to the actual array of bytes in the GATKSAMRecord
+ case WRITE_NS:
+ for (int i = 0; i < bases.length; i++) {
+ if (i >= start && i <= stop) {
+ newBases[i] = 'N';
+ }
+ else {
+ newBases[i] = bases[i];
+ }
+ }
+ read.setReadBases(newBases);
+ break;
+ case WRITE_Q0S:
+ for (int i = 0; i < quals.length; i++) {
+ if (i >= start && i <= stop) {
+ newQuals[i] = 0;
+ }
+ else {
+ newQuals[i] = quals[i];
+ }
+ }
+ read.setBaseQualities(newQuals);
+ break;
+ case WRITE_NS_Q0S:
+ for (int i = 0; i < bases.length; i++) {
+ if (i >= start && i <= stop) {
+ newQuals[i] = 0;
+ newBases[i] = 'N';
+ }
+ else {
+ newQuals[i] = quals[i];
+ newBases[i] = bases[i];
+ }
+ }
+ read.setBaseQualities(newBases);
+ read.setReadBases(newBases);
+ break;
+ case HARDCLIP_BASES:
+ read = hardClip(read, start, stop);
+ break;
+
+ case SOFTCLIP_BASES:
+ if (read.getReadUnmappedFlag()) {
+ // we can't process unmapped reads
+ throw new UserException("Read Clipper cannot soft clip unmapped reads");
+ }
+
+ //System.out.printf("%d %d %d%n", stop, start, read.getReadLength());
+ int myStop = stop;
+ if ((stop + 1 - start) == read.getReadLength()) {
+ // BAM representation issue -- we can't SOFTCLIP away all bases in a read, just leave it alone
+ //Walker.logger.info(String.format("Warning, read %s has all bases clip but this can't be represented with SOFTCLIP_BASES, just leaving it alone", read.getReadName()));
+ //break;
+ myStop--; // just decrement stop
+ }
+
+ if (start > 0 && myStop != read.getReadLength() - 1)
+ throw new RuntimeException(String.format("Cannot apply soft clipping operator to the middle of a read: %s to be clipped at %d-%d", read.getReadName(), start, myStop));
+
+ Cigar oldCigar = read.getCigar();
+
+ int scLeft = 0, scRight = read.getReadLength();
+ if (start == 0)
+ scLeft = myStop + 1;
+ else
+ scRight = start;
+
+ Cigar newCigar = softClip(oldCigar, scLeft, scRight);
+ read.setCigar(newCigar);
+
+ int newClippedStart = getNewAlignmentStartOffset(newCigar, oldCigar);
+ int newStart = read.getAlignmentStart() + newClippedStart;
+ read.setAlignmentStart(newStart);
+
+ break;
+
+ case REVERT_SOFTCLIPPED_BASES:
+ read = revertSoftClippedBases(read);
+ break;
+
+ default:
+ throw new IllegalStateException("Unexpected Clipping operator type " + algorithm);
+ }
+
+ return read;
+ }
+
+ private GATKSAMRecord revertSoftClippedBases(GATKSAMRecord read) {
+ GATKSAMRecord unclipped = (GATKSAMRecord) read.clone();
+
+ Cigar unclippedCigar = new Cigar();
+ int matchesCount = 0;
+ for (CigarElement element : read.getCigar().getCigarElements()) {
+ if (element.getOperator() == CigarOperator.SOFT_CLIP || element.getOperator() == CigarOperator.MATCH_OR_MISMATCH)
+ matchesCount += element.getLength();
+ else if (matchesCount > 0) {
+ unclippedCigar.add(new CigarElement(matchesCount, CigarOperator.MATCH_OR_MISMATCH));
+ matchesCount = 0;
+ unclippedCigar.add(element);
+ } else
+ unclippedCigar.add(element);
+ }
+ if (matchesCount > 0)
+ unclippedCigar.add(new CigarElement(matchesCount, CigarOperator.MATCH_OR_MISMATCH));
+
+ unclipped.setCigar(unclippedCigar);
+ final int newStart = read.getAlignmentStart() + calculateAlignmentStartShift(read.getCigar(), unclippedCigar);
+ unclipped.setAlignmentStart(newStart);
+
+ if ( newStart <= 0 ) {
+ // if the start of the unclipped read occurs before the contig,
+ // we must hard clip away the bases since we cannot represent reads with
+ // negative or 0 alignment start values in the SAMRecord (e.g., 0 means unaligned)
+ return hardClip(unclipped, 0, - newStart);
+ } else {
+ return unclipped;
+ }
+ }
+
+ /**
+ * Given a cigar string, get the number of bases hard or soft clipped at the start
+ */
+ private int getNewAlignmentStartOffset(final Cigar __cigar, final Cigar __oldCigar) {
+ int num = 0;
+ for (CigarElement e : __cigar.getCigarElements()) {
+ if (!e.getOperator().consumesReferenceBases()) {
+ if (e.getOperator().consumesReadBases()) {
+ num += e.getLength();
+ }
+ } else {
+ break;
+ }
+ }
+
+ int oldNum = 0;
+ int curReadCounter = 0;
+
+ for (CigarElement e : __oldCigar.getCigarElements()) {
+ int curRefLength = e.getLength();
+ int curReadLength = e.getLength();
+ if (!e.getOperator().consumesReadBases()) {
+ curReadLength = 0;
+ }
+
+ boolean truncated = false;
+ if (curReadCounter + curReadLength > num) {
+ curReadLength = num - curReadCounter;
+ curRefLength = num - curReadCounter;
+ truncated = true;
+ }
+
+ if (!e.getOperator().consumesReferenceBases()) {
+ curRefLength = 0;
+ }
+
+ curReadCounter += curReadLength;
+ oldNum += curRefLength;
+
+ if (curReadCounter > num || truncated) {
+ break;
+ }
+ }
+
+ return oldNum;
+ }
+
+ /**
+ * Given a cigar string, soft clip up to startClipEnd and soft clip starting at endClipBegin
+ */
+ private Cigar softClip(final Cigar __cigar, final int __startClipEnd, final int __endClipBegin) {
+ if (__endClipBegin <= __startClipEnd) {
+ //whole thing should be soft clipped
+ int cigarLength = 0;
+ for (CigarElement e : __cigar.getCigarElements()) {
+ cigarLength += e.getLength();
+ }
+
+ Cigar newCigar = new Cigar();
+ newCigar.add(new CigarElement(cigarLength, CigarOperator.SOFT_CLIP));
+ assert newCigar.isValid(null, -1) == null;
+ return newCigar;
+ }
+
+ int curLength = 0;
+ Vector<CigarElement> newElements = new Vector<CigarElement>();
+ for (CigarElement curElem : __cigar.getCigarElements()) {
+ if (!curElem.getOperator().consumesReadBases()) {
+ if (curElem.getOperator() == CigarOperator.HARD_CLIP || curLength > __startClipEnd && curLength < __endClipBegin) {
+ newElements.add(new CigarElement(curElem.getLength(), curElem.getOperator()));
+ }
+ continue;
+ }
+
+ int s = curLength;
+ int e = curLength + curElem.getLength();
+ if (e <= __startClipEnd || s >= __endClipBegin) {
+ //must turn this entire thing into a clip
+ newElements.add(new CigarElement(curElem.getLength(), CigarOperator.SOFT_CLIP));
+ } else if (s >= __startClipEnd && e <= __endClipBegin) {
+ //same thing
+ newElements.add(new CigarElement(curElem.getLength(), curElem.getOperator()));
+ } else {
+ //we are clipping in the middle of this guy
+ CigarElement newStart = null;
+ CigarElement newMid = null;
+ CigarElement newEnd = null;
+
+ int midLength = curElem.getLength();
+ if (s < __startClipEnd) {
+ newStart = new CigarElement(__startClipEnd - s, CigarOperator.SOFT_CLIP);
+ midLength -= newStart.getLength();
+ }
+
+ if (e > __endClipBegin) {
+ newEnd = new CigarElement(e - __endClipBegin, CigarOperator.SOFT_CLIP);
+ midLength -= newEnd.getLength();
+ }
+ assert midLength >= 0;
+ if (midLength > 0) {
+ newMid = new CigarElement(midLength, curElem.getOperator());
+ }
+ if (newStart != null) {
+ newElements.add(newStart);
+ }
+ if (newMid != null) {
+ newElements.add(newMid);
+ }
+ if (newEnd != null) {
+ newElements.add(newEnd);
+ }
+ }
+ curLength += curElem.getLength();
+ }
+
+ Vector<CigarElement> finalNewElements = new Vector<CigarElement>();
+ CigarElement lastElement = null;
+ for (CigarElement elem : newElements) {
+ if (lastElement == null || lastElement.getOperator() != elem.getOperator()) {
+ if (lastElement != null) {
+ finalNewElements.add(lastElement);
+ }
+ lastElement = elem;
+ } else {
+ lastElement = new CigarElement(lastElement.getLength() + elem.getLength(), lastElement.getOperator());
+ }
+ }
+ if (lastElement != null) {
+ finalNewElements.add(lastElement);
+ }
+
+ Cigar newCigar = new Cigar(finalNewElements);
+ assert newCigar.isValid(null, -1) == null;
+ return newCigar;
+ }
+
+ /**
+ * Hard clip bases from read, from start to stop in base coordinates
+ *
+ * If start == 0, then we will clip from the front of the read, otherwise we clip
+ * from the right. If start == 0 and stop == 10, this would clip out the first
+ * 10 bases of the read.
+ *
+ * Note that this function works with reads with negative alignment starts, in order to
+ * allow us to hardClip reads that have had their soft clips reverted and so might have
+ * negative alignment starts
+ *
+ * Works properly with reduced reads and insertion/deletion base qualities
+ *
+ * @param read a non-null read
+ * @param start a start >= 0 and < read.length
+ * @param stop a stop >= 0 and < read.length.
+ * @return a cloned version of read that has been properly trimmed down
+ */
+ private GATKSAMRecord hardClip(GATKSAMRecord read, int start, int stop) {
+
+ // If the read is unmapped there is no Cigar string and neither should we create a new cigar string
+ final CigarShift cigarShift = (read.getReadUnmappedFlag()) ? new CigarShift(new Cigar(), 0, 0) : hardClipCigar(read.getCigar(), start, stop);
+
+ // the cigar may force a shift left or right (or both) in case we are left with insertions
+ // starting or ending the read after applying the hard clip on start/stop.
+ final int newLength = read.getReadLength() - (stop - start + 1) - cigarShift.shiftFromStart - cigarShift.shiftFromEnd;
+ final byte[] newBases = new byte[newLength];
+ final byte[] newQuals = new byte[newLength];
+ final int copyStart = (start == 0) ? stop + 1 + cigarShift.shiftFromStart : cigarShift.shiftFromStart;
+
+ System.arraycopy(read.getReadBases(), copyStart, newBases, 0, newLength);
+ System.arraycopy(read.getBaseQualities(), copyStart, newQuals, 0, newLength);
+
+ final GATKSAMRecord hardClippedRead = (GATKSAMRecord) read.clone();
+
+ hardClippedRead.resetSoftStartAndEnd(); // reset the cached soft start and end because they may have changed now that the read was hard clipped. No need to calculate them now. They'll be lazily calculated on the next call to getSoftStart()/End()
+ hardClippedRead.setBaseQualities(newQuals);
+ hardClippedRead.setReadBases(newBases);
+ hardClippedRead.setCigar(cigarShift.cigar);
+ if (start == 0)
+ hardClippedRead.setAlignmentStart(read.getAlignmentStart() + calculateAlignmentStartShift(read.getCigar(), cigarShift.cigar));
+
+ if (read.hasBaseIndelQualities()) {
+ final byte[] newBaseInsertionQuals = new byte[newLength];
+ final byte[] newBaseDeletionQuals = new byte[newLength];
+ System.arraycopy(read.getBaseInsertionQualities(), copyStart, newBaseInsertionQuals, 0, newLength);
+ System.arraycopy(read.getBaseDeletionQualities(), copyStart, newBaseDeletionQuals, 0, newLength);
+ hardClippedRead.setBaseQualities(newBaseInsertionQuals, EventType.BASE_INSERTION);
+ hardClippedRead.setBaseQualities(newBaseDeletionQuals, EventType.BASE_DELETION);
+ }
+
+ return hardClippedRead;
+
+ }
+
+ @Requires({"!cigar.isEmpty()"})
+ private CigarShift hardClipCigar(Cigar cigar, int start, int stop) {
+ Cigar newCigar = new Cigar();
+ int index = 0;
+ int totalHardClipCount = stop - start + 1;
+ int alignmentShift = 0; // caused by hard clipping deletions
+
+ // hard clip the beginning of the cigar string
+ if (start == 0) {
+ Iterator<CigarElement> cigarElementIterator = cigar.getCigarElements().iterator();
+ CigarElement cigarElement = cigarElementIterator.next();
+ // Skip all leading hard clips
+ while (cigarElement.getOperator() == CigarOperator.HARD_CLIP) {
+ totalHardClipCount += cigarElement.getLength();
+ if (cigarElementIterator.hasNext())
+ cigarElement = cigarElementIterator.next();
+ else
+ throw new ReviewedGATKException("Read is entirely hardclipped, shouldn't be trying to clip it's cigar string");
+ }
+ // keep clipping until we hit stop
+ while (index <= stop) {
+ int shift = 0;
+ if (cigarElement.getOperator().consumesReadBases())
+ shift = cigarElement.getLength();
+
+ // we're still clipping or just finished perfectly
+ if (index + shift == stop + 1) {
+ alignmentShift += calculateHardClippingAlignmentShift(cigarElement, cigarElement.getLength());
+ newCigar.add(new CigarElement(totalHardClipCount + alignmentShift, CigarOperator.HARD_CLIP));
+ }
+ // element goes beyond what we need to clip
+ else if (index + shift > stop + 1) {
+ int elementLengthAfterChopping = cigarElement.getLength() - (stop - index + 1);
+ alignmentShift += calculateHardClippingAlignmentShift(cigarElement, stop - index + 1);
+ newCigar.add(new CigarElement(totalHardClipCount + alignmentShift, CigarOperator.HARD_CLIP));
+ newCigar.add(new CigarElement(elementLengthAfterChopping, cigarElement.getOperator()));
+ }
+ index += shift;
+ alignmentShift += calculateHardClippingAlignmentShift(cigarElement, shift);
+
+ if (index <= stop && cigarElementIterator.hasNext())
+ cigarElement = cigarElementIterator.next();
+ else
+ break;
+ }
+
+ // add the remaining cigar elements
+ while (cigarElementIterator.hasNext()) {
+ cigarElement = cigarElementIterator.next();
+ newCigar.add(new CigarElement(cigarElement.getLength(), cigarElement.getOperator()));
+ }
+ }
+
+ // hard clip the end of the cigar string
+ else {
+ Iterator<CigarElement> cigarElementIterator = cigar.getCigarElements().iterator();
+ CigarElement cigarElement = cigarElementIterator.next();
+
+ // Keep marching on until we find the start
+ while (index < start) {
+ int shift = 0;
+ if (cigarElement.getOperator().consumesReadBases())
+ shift = cigarElement.getLength();
+
+ // we haven't gotten to the start yet, keep everything as is.
+ if (index + shift < start)
+ newCigar.add(new CigarElement(cigarElement.getLength(), cigarElement.getOperator()));
+
+ // element goes beyond our clip starting position
+ else {
+ int elementLengthAfterChopping = start - index;
+ alignmentShift += calculateHardClippingAlignmentShift(cigarElement, cigarElement.getLength() - (start - index));
+
+ // if this last element is a HARD CLIP operator, just merge it with our hard clip operator to be added later
+ if (cigarElement.getOperator() == CigarOperator.HARD_CLIP)
+ totalHardClipCount += elementLengthAfterChopping;
+ // otherwise, maintain what's left of this last operator
+ else
+ newCigar.add(new CigarElement(elementLengthAfterChopping, cigarElement.getOperator()));
+ }
+ index += shift;
+ if (index < start && cigarElementIterator.hasNext())
+ cigarElement = cigarElementIterator.next();
+ else
+ break;
+ }
+
+ // check if we are hard clipping indels
+ while (cigarElementIterator.hasNext()) {
+ cigarElement = cigarElementIterator.next();
+ alignmentShift += calculateHardClippingAlignmentShift(cigarElement, cigarElement.getLength());
+
+ // if the read had a HardClip operator in the end, combine it with the Hard Clip we are adding
+ if (cigarElement.getOperator() == CigarOperator.HARD_CLIP)
+ totalHardClipCount += cigarElement.getLength();
+ }
+ newCigar.add(new CigarElement(totalHardClipCount + alignmentShift, CigarOperator.HARD_CLIP));
+ }
+ return cleanHardClippedCigar(newCigar);
+ }
+
+ /**
+ * Checks if a hard clipped cigar left a read starting or ending with deletions or gap (N)
+ * and cleans it up accordingly.
+ *
+ * @param cigar the original cigar
+ * @return an object with the shifts (see CigarShift class)
+ */
+ private CigarShift cleanHardClippedCigar(final Cigar cigar) {
+ final Cigar cleanCigar = new Cigar();
+ int shiftFromStart = 0;
+ int shiftFromEnd = 0;
+ Stack<CigarElement> cigarStack = new Stack<CigarElement>();
+ final Stack<CigarElement> inverseCigarStack = new Stack<CigarElement>();
+
+ for (final CigarElement cigarElement : cigar.getCigarElements())
+ cigarStack.push(cigarElement);
+
+ for (int i = 1; i <= 2; i++) {
+ int shift = 0;
+ int totalHardClip = 0;
+ boolean readHasStarted = false;
+ boolean addedHardClips = false;
+
+ while (!cigarStack.empty()) {
+ CigarElement cigarElement = cigarStack.pop();
+
+ if (!readHasStarted &&
+ cigarElement.getOperator() != CigarOperator.DELETION &&
+ cigarElement.getOperator() != CigarOperator.SKIPPED_REGION &&
+ cigarElement.getOperator() != CigarOperator.HARD_CLIP)
+ readHasStarted = true;
+
+ else if (!readHasStarted && cigarElement.getOperator() == CigarOperator.HARD_CLIP)
+ totalHardClip += cigarElement.getLength();
+
+ else if (!readHasStarted && cigarElement.getOperator() == CigarOperator.DELETION)
+ totalHardClip += cigarElement.getLength();
+
+ else if (!readHasStarted && cigarElement.getOperator() == CigarOperator.SKIPPED_REGION)
+ totalHardClip += cigarElement.getLength();
+
+ if (readHasStarted) {
+ if (i == 1) {
+ if (!addedHardClips) {
+ if (totalHardClip > 0)
+ inverseCigarStack.push(new CigarElement(totalHardClip, CigarOperator.HARD_CLIP));
+ addedHardClips = true;
+ }
+ inverseCigarStack.push(cigarElement);
+ } else {
+ if (!addedHardClips) {
+ if (totalHardClip > 0)
+ cleanCigar.add(new CigarElement(totalHardClip, CigarOperator.HARD_CLIP));
+ addedHardClips = true;
+ }
+ cleanCigar.add(cigarElement);
+ }
+ }
+ }
+ // first pass (i=1) is from end to start of the cigar elements
+ if (i == 1) {
+ shiftFromEnd = shift;
+ cigarStack = inverseCigarStack;
+ }
+ // second pass (i=2) is from start to end with the end already cleaned
+ else {
+ shiftFromStart = shift;
+ }
+ }
+ return new CigarShift(cleanCigar, shiftFromStart, shiftFromEnd);
+ }
+
+ /**
+ * Compute the offset of the first "real" position in the cigar on the genome
+ *
+ * This is defined as a first position after a run of Hs followed by a run of Ss
+ *
+ * @param cigar A non-null cigar
+ * @return the offset (from 0) of the first on-genome base
+ */
+ private int calcHardSoftOffset(final Cigar cigar) {
+ final List<CigarElement> elements = cigar.getCigarElements();
+
+ int size = 0;
+ int i = 0;
+ while ( i < elements.size() && elements.get(i).getOperator() == CigarOperator.HARD_CLIP ) {
+ size += elements.get(i).getLength();
+ i++;
+ }
+ while ( i < elements.size() && elements.get(i).getOperator() == CigarOperator.SOFT_CLIP ) {
+ size += elements.get(i).getLength();
+ i++;
+ }
+
+ return size;
+ }
+
+ private int calculateAlignmentStartShift(Cigar oldCigar, Cigar newCigar) {
+ final int newShift = calcHardSoftOffset(newCigar);
+ final int oldShift = calcHardSoftOffset(oldCigar);
+ return newShift - oldShift;
+ }
+
+ private int calculateHardClippingAlignmentShift(CigarElement cigarElement, int clippedLength) {
+ // Insertions should be discounted from the total hard clip count
+ if (cigarElement.getOperator() == CigarOperator.INSERTION)
+ return -clippedLength;
+
+ // Deletions and Ns should be added to the total hard clip count (because we want to maintain the original alignment start)
+ else if (cigarElement.getOperator() == CigarOperator.DELETION || cigarElement.getOperator() == CigarOperator.SKIPPED_REGION)
+ return cigarElement.getLength();
+
+ // There is no shift if we are not clipping an indel
+ return 0;
+ }
+
+ private static class CigarShift {
+ private Cigar cigar;
+ private int shiftFromStart;
+ private int shiftFromEnd;
+
+ private CigarShift(Cigar cigar, int shiftFromStart, int shiftFromEnd) {
+ this.cigar = cigar;
+ this.shiftFromStart = shiftFromStart;
+ this.shiftFromEnd = shiftFromEnd;
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/clipping/ClippingRepresentation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/clipping/ClippingRepresentation.java
new file mode 100644
index 0000000..5d86e0b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/clipping/ClippingRepresentation.java
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.clipping;
+
+/**
+ * How should we represent a clipped bases in a read?
+ */
+public enum ClippingRepresentation {
+ /** Clipped bases are changed to Ns */
+ WRITE_NS,
+
+ /** Clipped bases are changed to have Q0 quality score */
+ WRITE_Q0S,
+
+ /** Clipped bases are change to have both an N base and a Q0 quality score */
+ WRITE_NS_Q0S,
+
+ /**
+ * Change the read's cigar string to soft clip (S, see sam-spec) away the bases.
+ * Note that this can only be applied to cases where the clipped bases occur
+ * at the start or end of a read.
+ */
+ SOFTCLIP_BASES,
+
+ /**
+ * WARNING: THIS OPTION IS STILL UNDER DEVELOPMENT AND IS NOT SUPPORTED.
+ *
+ * Change the read's cigar string to hard clip (H, see sam-spec) away the bases.
+ * Hard clipping, unlike soft clipping, actually removes bases from the read,
+ * reducing the resulting file's size but introducing an irrevesible (i.e.,
+ * lossy) operation. Note that this can only be applied to cases where the clipped
+ * bases occur at the start or end of a read.
+ */
+ HARDCLIP_BASES,
+
+ /**
+ * Turn all soft-clipped bases into matches
+ */
+ REVERT_SOFTCLIPPED_BASES,
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/clipping/ReadClipper.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/clipping/ReadClipper.java
new file mode 100644
index 0000000..c31784f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/clipping/ReadClipper.java
@@ -0,0 +1,568 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.clipping;
+
+import com.google.java.contract.Requires;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.recalibration.EventType;
+import org.broadinstitute.gatk.utils.sam.CigarUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A comprehensive clipping tool.
+ *
+ * General Contract:
+ * - All clipping operations return a new read with the clipped bases requested, it never modifies the original read.
+ * - If a read is fully clipped, return an empty GATKSAMRecord, never null.
+ * - When hard clipping, add cigar operator H for every *reference base* removed (i.e. Matches, SoftClips and Deletions, but *not* insertions). See Hard Clipping notes for details.
+ *
+ *
+ * There are several types of clipping to use:
+ *
+ * Write N's:
+ * Change the bases to N's in the desired region. This can be applied anywhere in the read.
+ *
+ * Write Q0's:
+ * Change the quality of the bases in the desired region to Q0. This can be applied anywhere in the read.
+ *
+ * Write both N's and Q0's:
+ * Same as the two independent operations, put together.
+ *
+ * Soft Clipping:
+ * Do not change the read, just mark the reads as soft clipped in the Cigar String
+ * and adjust the alignment start and end of the read.
+ *
+ * Hard Clipping:
+ * Creates a new read without the hard clipped bases (and base qualities). The cigar string
+ * will be updated with the cigar operator H for every reference base removed (i.e. Matches,
+ * Soft clipped bases and deletions, but *not* insertions). This contract with the cigar
+ * is necessary to allow read.getUnclippedStart() / End() to recover the original alignment
+ * of the read (before clipping).
+ *
+ */
+public class ReadClipper {
+ final GATKSAMRecord read;
+ boolean wasClipped;
+ List<ClippingOp> ops = null;
+
+ /**
+ * Initializes a ReadClipper object.
+ *
+ * You can set up your clipping operations using the addOp method. When you're ready to
+ * generate a new read with all the clipping operations, use clipRead().
+ *
+ * Note: Use this if you want to set up multiple operations on the read using the ClippingOp
+ * class. If you just want to apply one of the typical modes of clipping, use the static
+ * clipping functions available in this class instead.
+ *
+ * @param read the read to clip
+ */
+ public ReadClipper(final GATKSAMRecord read) {
+ this.read = read;
+ this.wasClipped = false;
+ }
+
+ /**
+ * Add clipping operation to the read.
+ *
+ * You can add as many operations as necessary to this read before clipping. Beware that the
+ * order in which you add these operations matter. For example, if you hard clip the beginning
+ * of a read first then try to hard clip the end, the indices will have changed. Make sure you
+ * know what you're doing, otherwise just use the static functions below that take care of the
+ * ordering for you.
+ *
+ * Note: You only choose the clipping mode when you use clipRead()
+ *
+ * @param op a ClippingOp object describing the area you want to clip.
+ */
+ public void addOp(ClippingOp op) {
+ if (ops == null) ops = new ArrayList<ClippingOp>();
+ ops.add(op);
+ }
+
+ /**
+ * Check the list of operations set up for this read.
+ *
+ * @return a list of the operations set up for this read.
+ */
+ public List<ClippingOp> getOps() {
+ return ops;
+ }
+
+ /**
+ * Check whether or not this read has been clipped.
+ * @return true if this read has produced a clipped read, false otherwise.
+ */
+ public boolean wasClipped() {
+ return wasClipped;
+ }
+
+ /**
+ * The original read.
+ *
+ * @return returns the read to be clipped (original)
+ */
+ public GATKSAMRecord getRead() {
+ return read;
+ }
+
+ /**
+ * Clips a read according to ops and the chosen algorithm.
+ *
+ * @param algorithm What mode of clipping do you want to apply for the stacked operations.
+ * @return the read with the clipping applied.
+ */
+ public GATKSAMRecord clipRead(ClippingRepresentation algorithm) {
+ if (ops == null)
+ return getRead();
+
+ GATKSAMRecord clippedRead = read;
+ for (ClippingOp op : getOps()) {
+ final int readLength = clippedRead.getReadLength();
+ //check if the clipped read can still be clipped in the range requested
+ if (op.start < readLength) {
+ ClippingOp fixedOperation = op;
+ if (op.stop >= readLength)
+ fixedOperation = new ClippingOp(op.start, readLength - 1);
+
+ clippedRead = fixedOperation.apply(algorithm, clippedRead);
+ }
+ }
+ wasClipped = true;
+ ops.clear();
+ if ( clippedRead.isEmpty() )
+ return GATKSAMRecord.emptyRead(clippedRead);
+ return clippedRead;
+ }
+
+
+ /**
+ * Hard clips the left tail of a read up to (and including) refStop using reference
+ * coordinates.
+ *
+ * @param refStop the last base to be hard clipped in the left tail of the read.
+ * @return a new read, without the left tail.
+ */
+ @Requires("!read.getReadUnmappedFlag()") // can't handle unmapped reads, as we're using reference coordinates to clip
+ private GATKSAMRecord hardClipByReferenceCoordinatesLeftTail(int refStop) {
+ return hardClipByReferenceCoordinates(-1, refStop);
+ }
+ public static GATKSAMRecord hardClipByReferenceCoordinatesLeftTail(GATKSAMRecord read, int refStop) {
+ return (new ReadClipper(read)).hardClipByReferenceCoordinates(-1, refStop);
+ }
+
+
+
+ /**
+ * Hard clips the right tail of a read starting at (and including) refStart using reference
+ * coordinates.
+ *
+ * @param refStart refStop the first base to be hard clipped in the right tail of the read.
+ * @return a new read, without the right tail.
+ */
+ @Requires("!read.getReadUnmappedFlag()") // can't handle unmapped reads, as we're using reference coordinates to clip
+ private GATKSAMRecord hardClipByReferenceCoordinatesRightTail(int refStart) {
+ return hardClipByReferenceCoordinates(refStart, -1);
+ }
+ public static GATKSAMRecord hardClipByReferenceCoordinatesRightTail(GATKSAMRecord read, int refStart) {
+ return (new ReadClipper(read)).hardClipByReferenceCoordinates(refStart, -1);
+ }
+
+ /**
+ * Hard clips a read using read coordinates.
+ *
+ * @param start the first base to clip (inclusive)
+ * @param stop the last base to clip (inclusive)
+ * @return a new read, without the clipped bases
+ */
+ @Requires({"start >= 0 && stop <= read.getReadLength() - 1", // start and stop have to be within the read
+ "start == 0 || stop == read.getReadLength() - 1"}) // cannot clip the middle of the read
+ private GATKSAMRecord hardClipByReadCoordinates(int start, int stop) {
+ if (read.isEmpty() || (start == 0 && stop == read.getReadLength() - 1))
+ return GATKSAMRecord.emptyRead(read);
+
+ this.addOp(new ClippingOp(start, stop));
+ return clipRead(ClippingRepresentation.HARDCLIP_BASES);
+ }
+ public static GATKSAMRecord hardClipByReadCoordinates(GATKSAMRecord read, int start, int stop) {
+ return (new ReadClipper(read)).hardClipByReadCoordinates(start, stop);
+ }
+
+
+ /**
+ * Hard clips both tails of a read.
+ * Left tail goes from the beginning to the 'left' coordinate (inclusive)
+ * Right tail goes from the 'right' coordinate (inclusive) until the end of the read
+ *
+ * @param left the coordinate of the last base to be clipped in the left tail (inclusive)
+ * @param right the coordinate of the first base to be clipped in the right tail (inclusive)
+ * @return a new read, without the clipped bases
+ */
+ @Requires({"left <= right", // tails cannot overlap
+ "left >= read.getAlignmentStart()", // coordinate has to be within the mapped read
+ "right <= read.getAlignmentEnd()"}) // coordinate has to be within the mapped read
+ private GATKSAMRecord hardClipBothEndsByReferenceCoordinates(int left, int right) {
+ if (read.isEmpty() || left == right)
+ return GATKSAMRecord.emptyRead(read);
+ GATKSAMRecord leftTailRead = hardClipByReferenceCoordinates(right, -1);
+
+ // after clipping one tail, it is possible that the consequent hard clipping of adjacent deletions
+ // make the left cut index no longer part of the read. In that case, clip the read entirely.
+ if (left > leftTailRead.getAlignmentEnd())
+ return GATKSAMRecord.emptyRead(read);
+
+ ReadClipper clipper = new ReadClipper(leftTailRead);
+ return clipper.hardClipByReferenceCoordinatesLeftTail(left);
+ }
+ public static GATKSAMRecord hardClipBothEndsByReferenceCoordinates(GATKSAMRecord read, int left, int right) {
+ return (new ReadClipper(read)).hardClipBothEndsByReferenceCoordinates(left, right);
+ }
+
+
+ /**
+ * Clips any contiguous tail (left, right or both) with base quality lower than lowQual using the desired algorithm.
+ *
+ * This function will look for low quality tails and hard clip them away. A low quality tail
+ * ends when a base has base quality greater than lowQual.
+ *
+ * @param algorithm the algorithm to use (HardClip, SoftClip, Write N's,...)
+ * @param lowQual every base quality lower than or equal to this in the tail of the read will be hard clipped
+ * @return a new read without low quality tails
+ */
+ private GATKSAMRecord clipLowQualEnds(ClippingRepresentation algorithm, byte lowQual) {
+ if (read.isEmpty())
+ return read;
+
+ final byte [] quals = read.getBaseQualities();
+ final int readLength = read.getReadLength();
+ int leftClipIndex = 0;
+ int rightClipIndex = readLength - 1;
+
+ // check how far we can clip both sides
+ while (rightClipIndex >= 0 && quals[rightClipIndex] <= lowQual) rightClipIndex--;
+ while (leftClipIndex < readLength && quals[leftClipIndex] <= lowQual) leftClipIndex++;
+
+ // if the entire read should be clipped, then return an empty read.
+ if (leftClipIndex > rightClipIndex)
+ return GATKSAMRecord.emptyRead(read);
+
+ if (rightClipIndex < readLength - 1) {
+ this.addOp(new ClippingOp(rightClipIndex + 1, readLength - 1));
+ }
+ if (leftClipIndex > 0 ) {
+ this.addOp(new ClippingOp(0, leftClipIndex - 1));
+ }
+ return this.clipRead(algorithm);
+ }
+
+ private GATKSAMRecord hardClipLowQualEnds(byte lowQual) {
+ return this.clipLowQualEnds(ClippingRepresentation.HARDCLIP_BASES, lowQual);
+ }
+ public static GATKSAMRecord hardClipLowQualEnds(GATKSAMRecord read, byte lowQual) {
+ return (new ReadClipper(read)).hardClipLowQualEnds(lowQual);
+ }
+ public static GATKSAMRecord clipLowQualEnds(GATKSAMRecord read, byte lowQual, ClippingRepresentation algorithm) {
+ return (new ReadClipper(read)).clipLowQualEnds(algorithm, lowQual);
+ }
+
+
+ /**
+ * Will hard clip every soft clipped bases in the read.
+ *
+ * @return a new read without the soft clipped bases
+ */
+ private GATKSAMRecord hardClipSoftClippedBases () {
+ if (read.isEmpty())
+ return read;
+
+ int readIndex = 0;
+ int cutLeft = -1; // first position to hard clip (inclusive)
+ int cutRight = -1; // first position to hard clip (inclusive)
+ boolean rightTail = false; // trigger to stop clipping the left tail and start cutting the right tail
+
+ for (CigarElement cigarElement : read.getCigar().getCigarElements()) {
+ if (cigarElement.getOperator() == CigarOperator.SOFT_CLIP) {
+ if (rightTail) {
+ cutRight = readIndex;
+ }
+ else {
+ cutLeft = readIndex + cigarElement.getLength() - 1;
+ }
+ }
+ else if (cigarElement.getOperator() != CigarOperator.HARD_CLIP)
+ rightTail = true;
+
+ if (cigarElement.getOperator().consumesReadBases())
+ readIndex += cigarElement.getLength();
+ }
+
+ // It is extremely important that we cut the end first otherwise the read coordinates change.
+ if (cutRight >= 0)
+ this.addOp(new ClippingOp(cutRight, read.getReadLength() - 1));
+ if (cutLeft >= 0)
+ this.addOp(new ClippingOp(0, cutLeft));
+
+ return clipRead(ClippingRepresentation.HARDCLIP_BASES);
+ }
+ public static GATKSAMRecord hardClipSoftClippedBases (GATKSAMRecord read) {
+ return (new ReadClipper(read)).hardClipSoftClippedBases();
+ }
+
+
+ /**
+ * Hard clip the read to the variable region (from refStart to refStop)
+ *
+ * @param read the read to be clipped
+ * @param refStart the beginning of the variant region (inclusive)
+ * @param refStop the end of the variant region (inclusive)
+ * @return the read hard clipped to the variant region
+ */
+ public static GATKSAMRecord hardClipToRegion( final GATKSAMRecord read, final int refStart, final int refStop ) {
+ final int start = read.getAlignmentStart();
+ final int stop = read.getAlignmentEnd();
+ return hardClipToRegion(read, refStart, refStop,start,stop);
+ }
+
+ /**
+ * Hard clip the read to the variable region (from refStart to refStop) processing also the clipped bases
+ *
+ * @param read the read to be clipped
+ * @param refStart the beginning of the variant region (inclusive)
+ * @param refStop the end of the variant region (inclusive)
+ * @return the read hard clipped to the variant region
+ */
+ public static GATKSAMRecord hardClipToRegionIncludingClippedBases( final GATKSAMRecord read, final int refStart, final int refStop ) {
+ final int start = read.getOriginalAlignmentStart();
+ final int stop = start + CigarUtils.countRefBasesBasedOnCigar(read,0,read.getCigarLength()) - 1;
+ return hardClipToRegion(read, refStart, refStop,start,stop);
+ }
+
+ private static GATKSAMRecord hardClipToRegion( final GATKSAMRecord read, final int refStart, final int refStop, final int alignmentStart, final int alignmentStop){
+ // check if the read is contained in region
+ if (alignmentStart <= refStop && alignmentStop >= refStart) {
+ if (alignmentStart < refStart && alignmentStop > refStop)
+ return hardClipBothEndsByReferenceCoordinates(read, refStart - 1, refStop + 1);
+ else if (alignmentStart < refStart)
+ return hardClipByReferenceCoordinatesLeftTail(read, refStart - 1);
+ else if (alignmentStop > refStop)
+ return hardClipByReferenceCoordinatesRightTail(read, refStop + 1);
+ return read;
+ } else
+ return GATKSAMRecord.emptyRead(read);
+
+ }
+
+ public static List<GATKSAMRecord> hardClipToRegion( final List<GATKSAMRecord> reads, final int refStart, final int refStop ) {
+ final List<GATKSAMRecord> returnList = new ArrayList<GATKSAMRecord>( reads.size() );
+ for( final GATKSAMRecord read : reads ) {
+ final GATKSAMRecord clippedRead = hardClipToRegion( read, refStart, refStop );
+ if( !clippedRead.isEmpty() ) {
+ returnList.add( clippedRead );
+ }
+ }
+ return returnList;
+ }
+
+ /**
+ * Checks if a read contains adaptor sequences. If it does, hard clips them out.
+ *
+ * Note: To see how a read is checked for adaptor sequence see ReadUtils.getAdaptorBoundary()
+ *
+ * @return a new read without adaptor sequence
+ */
+ private GATKSAMRecord hardClipAdaptorSequence () {
+ final int adaptorBoundary = ReadUtils.getAdaptorBoundary(read);
+
+ if (adaptorBoundary == ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY || !ReadUtils.isInsideRead(read, adaptorBoundary))
+ return read;
+
+ return read.getReadNegativeStrandFlag() ? hardClipByReferenceCoordinatesLeftTail(adaptorBoundary) : hardClipByReferenceCoordinatesRightTail(adaptorBoundary);
+ }
+ public static GATKSAMRecord hardClipAdaptorSequence (GATKSAMRecord read) {
+ return (new ReadClipper(read)).hardClipAdaptorSequence();
+ }
+
+
+ /**
+ * Hard clips any leading insertions in the read. Only looks at the beginning of the read, not the end.
+ *
+ * @return a new read without leading insertions
+ */
+ private GATKSAMRecord hardClipLeadingInsertions() {
+ if (read.isEmpty())
+ return read;
+
+ for(CigarElement cigarElement : read.getCigar().getCigarElements()) {
+ if (cigarElement.getOperator() != CigarOperator.HARD_CLIP && cigarElement.getOperator() != CigarOperator.SOFT_CLIP &&
+ cigarElement.getOperator() != CigarOperator.INSERTION)
+ break;
+
+ else if (cigarElement.getOperator() == CigarOperator.INSERTION)
+ this.addOp(new ClippingOp(0, cigarElement.getLength() - 1));
+
+ }
+ return clipRead(ClippingRepresentation.HARDCLIP_BASES);
+ }
+ public static GATKSAMRecord hardClipLeadingInsertions(GATKSAMRecord read) {
+ return (new ReadClipper(read)).hardClipLeadingInsertions();
+ }
+
+
+ /**
+ * Turns soft clipped bases into matches
+ * @return a new read with every soft clip turned into a match
+ */
+ private GATKSAMRecord revertSoftClippedBases() {
+ if (read.isEmpty())
+ return read;
+
+ this.addOp(new ClippingOp(0, 0));
+ return this.clipRead(ClippingRepresentation.REVERT_SOFTCLIPPED_BASES);
+ }
+
+ /**
+ * Reverts ALL soft-clipped bases
+ *
+ * @param read the read
+ * @return the read with all soft-clipped bases turned into matches
+ */
+ public static GATKSAMRecord revertSoftClippedBases(GATKSAMRecord read) {
+ return (new ReadClipper(read)).revertSoftClippedBases();
+ }
+
+ /**
+ * Reverts only soft clipped bases with quality score greater than or equal to minQual
+ *
+ * todo -- Note: Will write a temporary field with the number of soft clips that were undone on each side (left: 'SL', right: 'SR') -- THIS HAS BEEN REMOVED TEMPORARILY SHOULD HAPPEN INSIDE THE CLIPPING ROUTINE!
+ *
+ * @param read the read
+ * @param minQual the mininum base quality score to revert the base (inclusive)
+ * @return a new read with high quality soft clips reverted
+ */
+ public static GATKSAMRecord revertSoftClippedBases(GATKSAMRecord read, byte minQual) {
+ return revertSoftClippedBases(hardClipLowQualitySoftClips(read, minQual));
+ }
+
+ /**
+ * Hard clips away soft clipped bases that are below the given quality threshold
+ *
+ * @param read the read
+ * @param minQual the mininum base quality score to revert the base (inclusive)
+ * @return a new read without low quality soft clipped bases
+ */
+ public static GATKSAMRecord hardClipLowQualitySoftClips(GATKSAMRecord read, byte minQual) {
+ int nLeadingSoftClips = read.getAlignmentStart() - read.getSoftStart();
+ if (read.isEmpty() || nLeadingSoftClips > read.getReadLength())
+ return GATKSAMRecord.emptyRead(read);
+
+ byte [] quals = read.getBaseQualities(EventType.BASE_SUBSTITUTION);
+ int left = -1;
+
+ if (nLeadingSoftClips > 0) {
+ for (int i = nLeadingSoftClips - 1; i >= 0; i--) {
+ if (quals[i] >= minQual)
+ left = i;
+ else
+ break;
+ }
+ }
+
+ int right = -1;
+ int nTailingSoftClips = read.getSoftEnd() - read.getAlignmentEnd();
+ if (nTailingSoftClips > 0) {
+ for (int i = read.getReadLength() - nTailingSoftClips; i < read.getReadLength() ; i++) {
+ if (quals[i] >= minQual)
+ right = i;
+ else
+ break;
+ }
+ }
+
+ GATKSAMRecord clippedRead = read;
+ if (right >= 0 && right + 1 < clippedRead.getReadLength()) // only clip if there are softclipped bases (right >= 0) and the first high quality soft clip is not the last base (right+1 < readlength)
+ clippedRead = hardClipByReadCoordinates(clippedRead, right+1, clippedRead.getReadLength()-1); // first we hard clip the low quality soft clips on the right tail
+ if (left >= 0 && left - 1 > 0) // only clip if there are softclipped bases (left >= 0) and the first high quality soft clip is not the last base (left-1 > 0)
+ clippedRead = hardClipByReadCoordinates(clippedRead, 0, left-1); // then we hard clip the low quality soft clips on the left tail
+
+ return clippedRead;
+ }
+
+ /**
+ * Generic functionality to hard clip a read, used internally by hardClipByReferenceCoordinatesLeftTail
+ * and hardClipByReferenceCoordinatesRightTail. Should not be used directly.
+ *
+ * Note, it REQUIRES you to give the directionality of your hard clip (i.e. whether you're clipping the
+ * left of right tail) by specifying either refStart < 0 or refStop < 0.
+ *
+ * @param refStart first base to clip (inclusive)
+ * @param refStop last base to clip (inclusive)
+ * @return a new read, without the clipped bases
+ */
+ @Requires({"!read.getReadUnmappedFlag()", "refStart < 0 || refStop < 0"}) // can't handle unmapped reads, as we're using reference coordinates to clip
+ protected GATKSAMRecord hardClipByReferenceCoordinates(int refStart, int refStop) {
+ if (read.isEmpty())
+ return read;
+
+ int start;
+ int stop;
+
+ // Determine the read coordinate to start and stop hard clipping
+ if (refStart < 0) {
+ if (refStop < 0)
+ throw new ReviewedGATKException("Only one of refStart or refStop must be < 0, not both (" + refStart + ", " + refStop + ")");
+ start = 0;
+ stop = ReadUtils.getReadCoordinateForReferenceCoordinate(read, refStop, ReadUtils.ClippingTail.LEFT_TAIL);
+ }
+ else {
+ if (refStop >= 0)
+ throw new ReviewedGATKException("Either refStart or refStop must be < 0 (" + refStart + ", " + refStop + ")");
+ start = ReadUtils.getReadCoordinateForReferenceCoordinate(read, refStart, ReadUtils.ClippingTail.RIGHT_TAIL);
+ stop = read.getReadLength() - 1;
+ }
+
+ if (start < 0 || stop > read.getReadLength() - 1)
+ throw new ReviewedGATKException("Trying to clip before the start or after the end of a read");
+
+ if ( start > stop )
+ throw new ReviewedGATKException(String.format("START (%d) > (%d) STOP -- this should never happen, please check read: %s (CIGAR: %s)", start, stop, read, read.getCigarString()));
+
+ if ( start > 0 && stop < read.getReadLength() - 1)
+ throw new ReviewedGATKException(String.format("Trying to clip the middle of the read: start %d, stop %d, cigar: %s", start, stop, read.getCigarString()));
+
+ this.addOp(new ClippingOp(start, stop));
+ GATKSAMRecord clippedRead = clipRead(ClippingRepresentation.HARDCLIP_BASES);
+ this.ops = null;
+ return clippedRead;
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/beagle/BeagleCodec.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/beagle/BeagleCodec.java
new file mode 100644
index 0000000..9159003
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/beagle/BeagleCodec.java
@@ -0,0 +1,276 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.beagle;
+/*
+ * Copyright (c) 2010 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+import htsjdk.tribble.AsciiFeatureCodec;
+import htsjdk.tribble.exception.CodecLineParsingException;
+import htsjdk.tribble.readers.LineIterator;
+import org.broadinstitute.gatk.engine.refdata.ReferenceDependentFeatureCodec;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * Codec for Beagle imputation engine
+ *
+ * <p>
+ * Reads in tabular files with site markers and genotype posteriors, genotypes and phasing that Beagle produced
+ * </p>
+ *
+ * <p>
+ * See also: @see <a href="http://faculty.washington.edu/browning/beagle/beagle.html">BEAGLE home page</a><br>
+ * </p>
+
+ * </p>
+ *
+ * <h2>File format example for phased genotypes file</h2>
+ * <pre>
+ * dummy header
+ * 20:60251 T T T T T T
+ * 20:60321 G G G G G G
+ * 20:60467 G G G G G G
+ * </pre>
+ *
+ * <h2>File format example for genotype posteriors</h2>
+ * <pre>
+ * marker alleleA alleleB NA07056 NA07056 NA07056
+ * 20:60251 T C 0.9962 0.0038 0 0.99245 0.00755 0 0.99245 0.00755 0
+ * 20:60321 G T 0.98747 0.01253 0 0.99922 0.00078 0 0.99368 0.00632 0
+ * 20:60467 G C 0.97475 0.02525 0 0.98718 0.01282 0 0.98718 0.01282 0
+ * </pre>
+ *
+ * <h2>File format example for r2 file
+ * <pre>
+ * 20:60251 0.747
+ * 20:60321 0.763
+ * 20:60467 0.524
+ * </pre>
+ * </h2>
+ * @author Mark DePristo
+ * @since 2010
+ */
+public class BeagleCodec extends AsciiFeatureCodec<BeagleFeature> implements ReferenceDependentFeatureCodec {
+ private String[] header;
+ public enum BeagleReaderType {PROBLIKELIHOOD, GENOTYPES, R2};
+ private BeagleReaderType readerType;
+ private int valuesPerSample;
+ private int initialSampleIndex;
+ private int markerPosition;
+ private ArrayList<String> sampleNames;
+ private int expectedTokensPerLine;
+ private final static Set<String> HEADER_IDs = new HashSet<String>(Arrays.asList("marker", "I"));
+
+ private static final String delimiterRegex = "\\s+";
+
+ /**
+ * The parser to use when resolving genome-wide locations.
+ */
+ private GenomeLocParser genomeLocParser;
+
+ public BeagleCodec() {
+ super(BeagleFeature.class);
+ }
+
+ /**
+ * Set the parser to use when resolving genetic data.
+ * @param genomeLocParser The supplied parser.
+ */
+ public void setGenomeLocParser(GenomeLocParser genomeLocParser) {
+ this.genomeLocParser = genomeLocParser;
+ }
+
+ @Override
+ public Object readActualHeader(LineIterator reader) {
+ int[] lineCounter = new int[1];
+ try {
+ header = readHeader(reader, lineCounter);
+
+ Boolean getSamples = true;
+ markerPosition = 0; //default value for all readers
+
+ if (header[0].matches("I")) {
+ // Phased genotype Beagle files start with "I"
+ readerType = BeagleReaderType.GENOTYPES;
+ valuesPerSample = 2;
+ initialSampleIndex = 2;
+ markerPosition = 1;
+ }
+ else if (header[0].matches("marker")) {
+ readerType = BeagleReaderType.PROBLIKELIHOOD;
+ valuesPerSample = 3;
+ initialSampleIndex = 3;
+ }
+ else {
+ readerType = BeagleReaderType.R2;
+ getSamples = false;
+ // signal we don't have a header
+ lineCounter[0] = 0;
+ // not needed, but for consistency:
+ valuesPerSample = 0;
+ initialSampleIndex = 0;
+ }
+
+ sampleNames = new ArrayList<String>();
+
+ if (getSamples) {
+ for (int k = initialSampleIndex; k < header.length; k += valuesPerSample)
+ sampleNames.add(header[k]);
+
+ expectedTokensPerLine = sampleNames.size()*valuesPerSample+initialSampleIndex;
+
+ } else {
+ expectedTokensPerLine = 2;
+ }
+
+
+ } catch(IOException e) {
+ throw new IllegalArgumentException("Unable to read from file.", e);
+ }
+ return header;
+ }
+
+ private static String[] readHeader(final LineIterator source, int[] lineCounter) throws IOException {
+
+ String[] header = null;
+ int numLines = 0;
+
+ //find the 1st line that's non-empty and not a comment
+ while(source.hasNext()) {
+ final String line = source.next();
+ numLines++;
+ if ( line.trim().isEmpty() ) {
+ continue;
+ }
+
+ //parse the header
+ header = line.split(delimiterRegex);
+ break;
+ }
+
+ // check that we found the header
+ if ( header == null ) {
+ throw new IllegalArgumentException("No header in " + source);
+ }
+
+ if(lineCounter != null) {
+ lineCounter[0] = numLines;
+ }
+
+ return header;
+ }
+
+ private static Pattern MARKER_PATTERN = Pattern.compile("(.+):([0-9]+)");
+
+ public BeagleFeature decode(String line) {
+ String[] tokens;
+
+ // split the line
+ tokens = line.split(delimiterRegex);
+ if (tokens.length != expectedTokensPerLine)
+ throw new CodecLineParsingException("Incorrect number of fields in Beagle input on line "+line);
+
+ if ( HEADER_IDs.contains(tokens[0]) )
+ return null;
+
+ BeagleFeature bglFeature = new BeagleFeature();
+
+ final GenomeLoc loc = genomeLocParser.parseGenomeLoc(tokens[markerPosition]); //GenomeLocParser.parseGenomeLoc(values.get(0)); - TODO switch to this
+
+ //parse the location: common to all readers
+ bglFeature.setChr(loc.getContig());
+ bglFeature.setStart((int) loc.getStart());
+ bglFeature.setEnd((int) loc.getStop());
+
+ // Parse R2 if needed
+ if (readerType == BeagleReaderType.R2) {
+ bglFeature.setR2value(Double.valueOf(tokens[1]));
+ }
+ else if (readerType == BeagleReaderType.GENOTYPES) {
+ // read phased Genotype pairs
+ HashMap<String, ArrayList<String>> sampleGenotypes = new HashMap<String, ArrayList<String>>();
+
+ for ( int i = 2; i < tokens.length; i+=2 ) {
+ String sampleName = sampleNames.get(i/2-1);
+ if ( ! sampleGenotypes.containsKey(sampleName) ) {
+ sampleGenotypes.put(sampleName, new ArrayList<String>());
+ }
+
+ sampleGenotypes.get(sampleName).add(tokens[i]);
+ sampleGenotypes.get(sampleName).add(tokens[i+1]);
+ }
+
+ bglFeature.setGenotypes(sampleGenotypes);
+ }
+ else {
+ // read probabilities/likelihood trios and alleles
+ bglFeature.setAlleleA(tokens[1], true);
+ bglFeature.setAlleleB(tokens[2], false);
+ HashMap<String, ArrayList<String>> sampleProbLikelihoods = new HashMap<String, ArrayList<String>>();
+
+ for ( int i = 3; i < tokens.length; i+=3 ) {
+ String sampleName = sampleNames.get(i/3-1);
+ if ( ! sampleProbLikelihoods.containsKey(sampleName) ) {
+ sampleProbLikelihoods.put(sampleName, new ArrayList<String>());
+ }
+
+ sampleProbLikelihoods.get(sampleName).add(tokens[i]);
+ sampleProbLikelihoods.get(sampleName).add(tokens[i+1]);
+ sampleProbLikelihoods.get(sampleName).add(tokens[i+2]);
+ }
+ bglFeature.setProbLikelihoods(sampleProbLikelihoods);
+ }
+
+ return bglFeature;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/beagle/BeagleFeature.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/beagle/BeagleFeature.java
new file mode 100644
index 0000000..bd9e4ef
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/beagle/BeagleFeature.java
@@ -0,0 +1,111 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.beagle;
+
+import htsjdk.tribble.Feature;
+import htsjdk.variant.variantcontext.Allele;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+public class BeagleFeature implements Feature {
+
+ private String chr;
+ private int start;
+ private int end;
+
+ Map<String, ArrayList<String>> sampleGenotypes;
+ private Double r2Value;
+ Map<String, ArrayList<String>> probLikelihoods;
+
+ Allele AlleleA;
+ Allele AlleleB;
+
+
+ public String getChr() {
+ return chr;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public int getEnd() {
+ return end;
+ }
+
+ public Double getR2value() {
+ return r2Value;
+ }
+
+ public Allele getAlleleA() {
+ return AlleleA;
+ }
+
+ public Allele getAlleleB() {
+ return AlleleB;
+ }
+
+ public Map<String, ArrayList<String>> getProbLikelihoods() {
+ return probLikelihoods;
+ }
+
+ public Map<String, ArrayList<String>> getGenotypes() {
+ return sampleGenotypes;
+ }
+
+ protected void setChr(String chr) {
+ this.chr = chr;
+ }
+
+ protected void setStart(int start) {
+ this.start = start;
+ }
+
+ protected void setEnd(int end) {
+ this.end = end;
+ }
+
+ protected void setR2value(double r2) {
+ this.r2Value = r2;
+ }
+
+ protected void setAlleleA(String a, boolean isRef) {
+ this.AlleleA = Allele.create(a, isRef);
+ }
+
+ protected void setAlleleB(String a, boolean isRef) {
+ this.AlleleB = Allele.create(a, isRef);
+ }
+
+ protected void setProbLikelihoods(Map<String, ArrayList<String>> p) {
+ this.probLikelihoods = p;
+ }
+
+ protected void setGenotypes(Map<String, ArrayList<String>> p) {
+ this.sampleGenotypes = p;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/hapmap/RawHapMapCodec.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/hapmap/RawHapMapCodec.java
new file mode 100644
index 0000000..ac50853
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/hapmap/RawHapMapCodec.java
@@ -0,0 +1,125 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.hapmap;
+
+import htsjdk.tribble.AsciiFeatureCodec;
+import htsjdk.tribble.FeatureCodecHeader;
+import htsjdk.tribble.annotation.Strand;
+import htsjdk.tribble.readers.LineIterator;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * A codec for the file types produced by the HapMap consortium
+ *
+ * <p>
+ * The format includes eleven standard fields, plus genotypes for each of the samples included
+ * in the file:
+ *
+ * <pre>
+ * Col1: refSNP rs# identifier at the time of release (NB might merge with another rs# in the future)
+ * Col2: SNP alleles according to dbSNP
+ * Col3: chromosome that SNP maps to
+ * Col4: chromosome position of SNP, in basepairs on reference sequence
+ * Col5: strand of reference sequence that SNP maps to
+ * Col6: version of reference sequence assembly
+ * Col7: HapMap genotype center that produced the genotypes
+ * Col8: LSID for HapMap protocol used for genotyping
+ * Col9: LSID for HapMap assay used for genotyping
+ * Col10: LSID for panel of individuals genotyped
+ * Col11: QC-code, currently 'QC+' for all entries (for future use)
+ * Col12 and on: observed genotypes of samples, one per column, sample identifiers in column headers (Coriell catalog numbers, example: NA10847). Duplicate samples have .dup suffix.
+ * </pre>
+ * </p>
+ *
+ * <p>
+ * See also: @See <a href="http://hapmap.ncbi.nlm.nih.gov/downloads/genotypes/">HapMap genotypes download</a>
+ * </p>
+ *
+ * <h2>File format example</h2>
+ * From <a href="http://hapmap.ncbi.nlm.nih.gov/downloads/genotypes/latest/forward/non-redundant/genotypes_chr1_ASW_r27_nr.b36_fwd.txt.gz">genotypes_chr1_ASW_r27_nr.b36_fwd.txt.gz</a>:
+ * <pre>
+ * rs# alleles chrom pos strand assembly# center protLSID assayLSID panelLSID QCcode NA19625 NA19700 NA19701 NA19702 NA19703 NA19704 NA19705 NA19708 NA19712 NA19711 NA19818 NA19819 NA19828 NA19835 NA19834 NA19836 NA19902 NA19901 NA19900 NA19904 NA19919 NA19908 NA19909 NA19914 NA19915 NA19916 NA19917 NA19918 NA19921 NA20129 NA19713 NA19982 NA19983 NA19714 NA19985 NA20128 NA20126 NA20127 NA20277 NA20276 NA20279 NA20282 NA20281 NA20284 NA20287 NA20288 NA20290 NA20289 NA20291 NA20292 NA2 [...]
+ * rs9629043 C/T chr1 554636 + ncbi_b36 broad urn:LSID:affymetrix.hapmap.org:Protocol:GenomeWideSNP_6.0:3 urn:LSID:broad.hapmap.org:Assay:SNP_A-8575115:3 urn:lsid:dcc.hapmap.org:Panel:US_African-30-trios:3 QC+ CC CC CC CC CC CC CC CC CC CC CC CC NN CC CC CC CT CT CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CT CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC CC
+ * rs28446478 G/T chr1 576058 + ncbi_b36 sanger urn:LSID:illumina.hapmap.org:Protocol:Human_1M_BeadChip:3 urn:LSID:sanger.hapmap.org:Assay:H1Mrs28446478:3 urn:lsid:dcc.hapmap.org:Panel:US_African-30-trios:3 QC+ GT TT GT TT TT TT TT GT GT TT TT TT TT GT GT GT GT TT GT TT GT GT TT GT GT TT TT TT GT GT TT TT TT GT TT GT TT GT GT GT GT GT TT GT TT TT GT GT TT TT TT TT TT TT GT GT GT GT TT TT TT TT GT TT GT TT TT GT TT TT TT GT TT TT TT GT GT TT GT TT GT TT TT
+ * rs12565286 C/G chr1 711153 + ncbi_b36 broad urn:LSID:affymetrix.hapmap.org:Protocol:GenomeWideSNP_6.0:3 urn:LSID:broad.hapmap.org:Assay:SNP_A-8709646:3 urn:lsid:dcc.hapmap.org:Panel:US_African-30-trios:3 QC+ GG GG GG GG GG GG GG GG CG GG GG GG GG GG GG GG GG GG GG CG GG GG GG GG GG GG GG GG GG GG GG GG GG GG GG GG GG GG GG GG CG GG GG GG GG GG GG GG CG CG GG GG GG GG GG GG GG GG GG CG CG GG GG GG GG GG GG GG GG GG GG CG NN GG GG GG GG GG GG NN GG NN NN
+ * </pre>
+ *
+ * @author Mark DePristo
+ * @since 2010
+ */
+public class RawHapMapCodec extends AsciiFeatureCodec<RawHapMapFeature> {
+ // the minimum number of features in the HapMap file line
+ private static final int minimumFeatureCount = 11;
+
+ private String headerLine;
+
+ public RawHapMapCodec() {
+ super(RawHapMapFeature.class);
+ }
+
+ /**
+ * decode the hapmap record
+ * @param line the input line to decode
+ * @return a HapMapFeature, with the given fields
+ */
+ public RawHapMapFeature decode(String line) {
+ String[] array = line.split("\\s+");
+
+ // make sure the split was successful - that we got an appropriate number of fields
+ if (array.length < minimumFeatureCount)
+ throw new IllegalArgumentException("Unable to parse line " + line + ", the length of split features is less than the minimum of " + minimumFeatureCount);
+
+ // create a new feature given the array
+ return new RawHapMapFeature(array[0],
+ array[1].split("/"),
+ array[2],
+ Long.valueOf(array[3]),
+ Strand.toStrand(array[4]),
+ array[5],
+ array[6],
+ array[7],
+ array[8],
+ array[9],
+ array[10],
+ Arrays.copyOfRange(array,11,array.length),
+ headerLine);
+ }
+
+ @Override
+ public Object readActualHeader(final LineIterator lineIterator) {
+ this.headerLine = lineIterator.next();
+ return headerLine;
+ }
+
+ @Override
+ public FeatureCodecHeader readHeader(final LineIterator lineIterator) throws IOException {
+ final String header = (String) readActualHeader(lineIterator);
+ // TODO: This approach may cause issues with files formatted with \r\n-style line-endings.
+ return new FeatureCodecHeader(header, header.length() + 1);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/hapmap/RawHapMapFeature.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/hapmap/RawHapMapFeature.java
new file mode 100644
index 0000000..a9b8788
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/hapmap/RawHapMapFeature.java
@@ -0,0 +1,196 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.hapmap;
+
+import htsjdk.tribble.Feature;
+import htsjdk.tribble.annotation.Strand;
+import htsjdk.variant.variantcontext.Allele;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * a feature returned by the HapMap Codec - it represents contig, position, name,
+ * alleles, other hapmap information, and genotypes for specified samples
+ */
+public class RawHapMapFeature implements Feature {
+
+ public static final String NULL_ALLELE_STRING = "-";
+ public static final String INSERTION = "I";
+ public static final String DELETION = "D";
+
+ // the variables we store internally in the class
+ private final String name;
+ private final String[] alleles;
+ private Map<String, Allele> actualAlleles = null;
+ private final String contig ;
+ private long position;
+ private final Strand strand;
+ private final String assembly;
+ private final String center;
+ private final String protLSID;
+ private final String assayLSID;
+ private final String panelLSID;
+ private final String qccode;
+ private final String[] genotypes;
+
+ // we store the header line, if they'd like to get the samples
+ private final String headerLine;
+
+ /**
+ * create a HapMap Feature, based on all the records available in the hapmap file
+ * @param contig the contig name
+ * @param position the position
+ * @param strand the strand enum
+ * @param assembly what assembly this feature is from
+ * @param center the center that provided this SNP
+ * @param protLSID ??
+ * @param assayLSID ??
+ * @param panelLSID ??
+ * @param qccode ??
+ * @param genotypes a list of strings, representing the genotypes for the list of samples
+ */
+ public RawHapMapFeature(String name,
+ String[] alleles,
+ String contig,
+ Long position,
+ Strand strand,
+ String assembly,
+ String center,
+ String protLSID,
+ String assayLSID,
+ String panelLSID,
+ String qccode,
+ String[] genotypes,
+ String headerLine) {
+ this.name = name;
+ this.alleles = alleles;
+ this.contig = contig;
+ this.position = position;
+ this.strand = strand;
+ this.assembly = assembly;
+ this.center = center;
+ this.protLSID = protLSID ;
+ this.assayLSID = assayLSID ;
+ this.panelLSID = panelLSID ;
+ this.qccode = qccode;
+ this.genotypes = genotypes;
+ this.headerLine = headerLine;
+ }
+
+ /**
+ * get the contig value
+ * @return a string representing the contig
+ */
+ public String getChr() {
+ return contig;
+ }
+
+ /**
+ * get the start position, as an integer
+ * @return an int, representing the start position
+ */
+ public int getStart() {
+ return (int)position;
+ }
+
+ /**
+ * get the end position
+ * @return get the end position as an int
+ */
+ public int getEnd() {
+ return (int)position;
+ }
+
+ /**
+ * Getter methods
+ */
+
+ public Strand getStrand() {
+ return strand;
+ }
+
+ public String getAssembly() {
+ return assembly;
+ }
+
+ public String getCenter() {
+ return center;
+ }
+
+ public String getProtLSID() {
+ return protLSID;
+ }
+
+ public String getAssayLSID() {
+ return assayLSID;
+ }
+
+ public String getPanelLSID() {
+ return panelLSID;
+ }
+
+ public String getQCCode() {
+ return qccode;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String[] getAlleles() {
+ return alleles;
+ }
+
+ public String[] getGenotypes() {
+ return genotypes;
+ }
+
+ // This is necessary because HapMap places insertions in the incorrect position
+ public void updatePosition(long position) {
+ this.position = position;
+ }
+
+ public void setActualAlleles(Map<String, Allele> alleleMap) {
+ actualAlleles = new HashMap<String, Allele>(alleleMap);
+ }
+
+ public Map<String, Allele> getActualAlleles() {
+ return actualAlleles;
+ }
+
+ /**
+ * get a list of the samples from the header (in order)
+ * @return a string array of sample names
+ */
+ public String[] getSampleIDs() {
+ String[] header = headerLine.split("\\s+");
+ String[] sample_ids = new String[header.length-11];
+ for (int i = 11; i < header.length; i++)
+ sample_ids[i-11] = header[i];
+ return sample_ids;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/refseq/RefSeqCodec.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/refseq/RefSeqCodec.java
new file mode 100644
index 0000000..9d60076
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/refseq/RefSeqCodec.java
@@ -0,0 +1,171 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.refseq;
+
+import htsjdk.tribble.AsciiFeatureCodec;
+import htsjdk.tribble.Feature;
+import htsjdk.tribble.TribbleException;
+import htsjdk.tribble.readers.LineIterator;
+import org.broadinstitute.gatk.engine.refdata.ReferenceDependentFeatureCodec;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.ArrayList;
+
+/**
+ * Allows for reading in RefSeq information
+ *
+ * <p>
+ * Parses a sorted UCSC RefSeq file (see below) into relevant features: the gene name, the unique gene name (if multiple transcrips get separate entries), exons, gene start/stop, coding start/stop,
+ * strandedness of transcription.
+ * </p>
+ *
+ * <p>
+ * Instructions for generating a RefSeq file for use with the RefSeq codec can be found on the documentation guide here
+ * <a href="http://www.broadinstitute.org/gatk/guide/article?id=1329">http://www.broadinstitute.org/gatk/guide/article?id=1329</a>
+ * </p>
+ * <h2> Usage </h2>
+ * The RefSeq Rod can be bound as any other rod, and is specified by REFSEQ, for example
+ * <pre>
+ * -refSeqBinding:REFSEQ /path/to/refSeq.txt
+ * </pre>
+ *
+ * You will need to consult individual walkers for the binding name ("refSeqBinding", above)
+ *
+ * <h2>File format example</h2>
+ * If you want to define your own file for use, the format is (tab delimited):
+ * bin, name, chrom, strand, transcription start, transcription end, coding start, coding end, num exons, exon starts, exon ends, id, alt. name, coding start status (complete/incomplete), coding end status (complete,incomplete)
+ * and exon frames, for example:
+ * <pre>
+ * 76 NM_001011874 1 - 3204562 3661579 3206102 3661429 3 3204562,3411782,3660632, 3207049,3411982,3661579, 0 Xkr4 cmpl cmpl 1,2,0,
+ * </pre>
+ * for more information see <a href="http://skip.ucsc.edu/cgi-bin/hgTables?hgsid=5651&hgta_doSchemaDb=mm8&hgta_doSchemaTable=refGene">here</a>
+ * <p>
+ *
+ * </p>
+ *
+ * @author Mark DePristo
+ * @since 2010
+ */
+public class RefSeqCodec extends AsciiFeatureCodec<RefSeqFeature> implements ReferenceDependentFeatureCodec {
+
+ /**
+ * The parser to use when resolving genome-wide locations.
+ */
+ private GenomeLocParser genomeLocParser;
+ private boolean zero_coding_length_user_warned = false;
+
+ public RefSeqCodec() {
+ super(RefSeqFeature.class);
+ }
+
+ /**
+ * Set the parser to use when resolving genetic data.
+ * @param genomeLocParser The supplied parser.
+ */
+ @Override
+ public void setGenomeLocParser(GenomeLocParser genomeLocParser) {
+ this.genomeLocParser = genomeLocParser;
+ }
+
+ @Override
+ public Feature decodeLoc(final LineIterator lineIterator) {
+ final String line = lineIterator.next();
+ if (line.startsWith("#")) return null;
+ String fields[] = line.split("\t");
+ if (fields.length < 3) throw new TribbleException("RefSeq (decodeLoc) : Unable to parse line -> " + line + ", we expected at least 3 columns, we saw " + fields.length);
+ String contig_name = fields[2];
+ try {
+ return new RefSeqFeature(genomeLocParser.createGenomeLoc(contig_name, Integer.parseInt(fields[4])+1, Integer.parseInt(fields[5])));
+ } catch ( UserException.MalformedGenomeLoc e ) {
+ Utils.warnUser("RefSeq file is potentially incorrect, as some transcripts or exons have a negative length ("+fields[2]+")");
+ return null;
+ } catch ( NumberFormatException e ) {
+ throw new UserException.MalformedFile("Could not parse location from line: " + line);
+ }
+ }
+
+ /** Fills this object from a text line in RefSeq (UCSC) text dump file */
+ @Override
+ public RefSeqFeature decode(String line) {
+ if (line.startsWith("#")) return null;
+ String fields[] = line.split("\t");
+
+ // we reference postion 15 in the split array below, make sure we have at least that many columns
+ if (fields.length < 16) throw new TribbleException("RefSeq (decode) : Unable to parse line -> " + line + ", we expected at least 16 columns, we saw " + fields.length);
+ String contig_name = fields[2];
+ RefSeqFeature feature = new RefSeqFeature(genomeLocParser.createGenomeLoc(contig_name, Integer.parseInt(fields[4])+1, Integer.parseInt(fields[5])));
+
+ feature.setTranscript_id(fields[1]);
+ if ( fields[3].length()==1 && fields[3].charAt(0)=='+') feature.setStrand(1);
+ else if ( fields[3].length()==1 && fields[3].charAt(0)=='-') feature.setStrand(-1);
+ else throw new UserException.MalformedFile("Expected strand symbol (+/-), found: "+fields[3] + " for line=" + line);
+
+ int coding_start = Integer.parseInt(fields[6])+1;
+ int coding_stop = Integer.parseInt(fields[7]);
+
+ if ( coding_start > coding_stop ) {
+ if ( ! zero_coding_length_user_warned ) {
+ Utils.warnUser("RefSeq file contains transcripts with zero coding length. "+
+ "Such transcripts will be ignored (this warning is printed only once)");
+ zero_coding_length_user_warned = true;
+ }
+ return null;
+ }
+
+ feature.setTranscript_interval(genomeLocParser.createGenomeLoc(contig_name, Integer.parseInt(fields[4])+1, Integer.parseInt(fields[5])));
+ feature.setTranscript_coding_interval(genomeLocParser.createGenomeLoc(contig_name, coding_start, coding_stop));
+ feature.setGene_name(fields[12]);
+ String[] exon_starts = fields[9].split(",");
+ String[] exon_stops = fields[10].split(",");
+ String[] eframes = fields[15].split(",");
+
+ if ( exon_starts.length != exon_stops.length )
+ throw new UserException.MalformedFile("Data format error: numbers of exon start and stop positions differ for line=" + line);
+ if ( exon_starts.length != eframes.length )
+ throw new UserException.MalformedFile("Data format error: numbers of exons and exon frameshifts differ for line=" + line);
+
+ ArrayList<GenomeLoc> exons = new ArrayList<GenomeLoc>(exon_starts.length);
+ ArrayList<Integer> exon_frames = new ArrayList<Integer>(eframes.length);
+
+ for ( int i = 0 ; i < exon_starts.length ; i++ ) {
+ exons.add(genomeLocParser.createGenomeLoc(contig_name, Integer.parseInt(exon_starts[i])+1, Integer.parseInt(exon_stops[i]) ) );
+ exon_frames.add(Integer.decode(eframes[i]));
+ }
+
+ feature.setExons(exons);
+ feature.setExon_frames(exon_frames);
+ return feature;
+ }
+
+ @Override
+ public Object readActualHeader(LineIterator lineIterator) {
+ // No header for this format
+ return null;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/refseq/RefSeqFeature.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/refseq/RefSeqFeature.java
new file mode 100644
index 0000000..226a353
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/refseq/RefSeqFeature.java
@@ -0,0 +1,323 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.refseq;
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ * the ref seq feature
+ */
+public class RefSeqFeature implements Transcript, Feature {
+
+ private String transcript_id;
+ private int strand;
+ private GenomeLoc transcript_interval;
+ private GenomeLoc transcript_coding_interval;
+ private List<GenomeLoc> exons;
+ private String gene_name;
+ private List<Integer> exon_frames;
+ private String name;
+
+ public RefSeqFeature(GenomeLoc genomeLoc) {
+ this.transcript_interval = genomeLoc;
+ }
+
+ /** Returns id of the transcript (RefSeq NM_* id) */
+ public String getTranscriptId() { return transcript_id; }
+
+ /** Returns coding strand of the transcript, 1 or -1 for positive or negative strand, respectively */
+ public int getStrand() { return strand; }
+
+ /** Returns transcript's full genomic interval (includes all exons with UTRs) */
+ public GenomeLoc getLocation() {
+ return transcript_interval;
+ }
+
+ /** Returns genomic interval of the coding sequence (does not include UTRs, but still includes introns, since it's a single interval on the DNA) */
+ public GenomeLoc getCodingLocation() { return transcript_coding_interval; }
+
+ /** Name of the gene this transcript corresponds to (NOT gene id such as Entrez etc) */
+ public String getGeneName() { return gene_name; }
+
+ /** Number of exons in this transcript */
+ public int getNumExons() { return exons.size(); }
+
+ /** Genomic location of the n-th exon; throws an exception if n is out of bounds */
+ public GenomeLoc getExonLocation(int n) {
+ if ( n >= exons.size() || n < 0 ) throw new ReviewedGATKException("Index out-of-bounds. Transcript has " + exons.size() +" exons; requested: "+n);
+ return exons.get(n);
+ }
+
+ /** Returns the list of all exons in this transcript, as genomic intervals */
+ public List<GenomeLoc> getExons() { return exons; }
+
+ /** Returns all exons falling ::entirely:: inside an interval **/
+ public List<GenomeLoc> getExonsInInterval( GenomeLoc interval ) {
+ List<GenomeLoc> relevantExons = new ArrayList<GenomeLoc>(exons.size());
+ for ( GenomeLoc exon : getExons() ) {
+ if ( interval.containsP(exon) ) {
+ relevantExons.add(exon);
+ }
+ }
+
+ return relevantExons;
+ }
+
+ /** convenience method; returns the numbers of the exons in the interval **/
+ public List<Integer> getExonNumbersInInterval( GenomeLoc interval ) {
+ List<Integer> numbers = new ArrayList<Integer>();
+ int iNo = 0;
+ for ( GenomeLoc exon : getExons() ) {
+ if ( interval.containsP(exon) ) {
+ numbers.add(iNo);
+ }
+ iNo++;
+ }
+
+ return numbers;
+ }
+
+ public String getTranscriptUniqueGeneName() {
+ return String.format("%s(%s)",getGeneName(),getTranscriptId());
+ }
+
+ public String getOverlapString(GenomeLoc position) {
+ boolean is_exon = false;
+ StringBuilder overlapString = new StringBuilder();
+ int exonNo = 1;
+
+ for ( GenomeLoc exon : exons ) {
+ if ( exon.containsP(position) ) {
+ overlapString.append(String.format("exon_%d",exonNo));
+ is_exon = true;
+ break;
+ }
+ exonNo ++;
+ }
+
+ if ( ! is_exon ) {
+ if ( overlapsCodingP(position) ) {
+ overlapString.append("Intron");
+ } else {
+ overlapString.append("UTR");
+ }
+ }
+
+ return overlapString.toString();
+ }
+
+ ArrayList<GenomeLoc> exonInRefOrderCache = null;
+
+ public Integer getSortedOverlapInteger(GenomeLoc position) {
+ int exonNo = -1;
+ ArrayList<GenomeLoc> exonsInReferenceOrder = exonInRefOrderCache != null ? exonInRefOrderCache : new ArrayList<GenomeLoc>(exons);
+ if ( exonInRefOrderCache == null ) {
+ Collections.sort(exonsInReferenceOrder);
+ }
+ exonInRefOrderCache = exonsInReferenceOrder;
+ for ( GenomeLoc exon : exonsInReferenceOrder ) {
+ if ( exon.overlapsP(position) ) {
+ return ++exonNo;
+ }
+ ++exonNo;
+ }
+
+ return -1;
+ }
+
+ public GenomeLoc getSortedExonLoc(int offset) {
+ ArrayList<GenomeLoc> exonsInReferenceOrder = exonInRefOrderCache != null ? exonInRefOrderCache : new ArrayList<GenomeLoc>(exons);
+ if ( exonInRefOrderCache == null ) {
+ Collections.sort(exonsInReferenceOrder);
+ }
+ exonInRefOrderCache = exonsInReferenceOrder;
+ return exonsInReferenceOrder.get(offset);
+ }
+
+ /** Returns true if the specified interval 'that' overlaps with the full genomic interval of this transcript */
+ public boolean overlapsP (GenomeLoc that) {
+ return getLocation().overlapsP(that);
+ }
+
+ /** Returns true if the specified interval 'that' overlaps with the coding genomic interval of this transcript.
+ * NOTE: since "coding interval" is still a single genomic interval, it will not contain UTRs of the outermost exons,
+ * but it will still contain introns and/or exons internal to this genomic locus that are not spliced into this transcript.
+ * @see #overlapsExonP
+ */
+ public boolean overlapsCodingP (GenomeLoc that) {
+ return transcript_coding_interval.overlapsP(that);
+ }
+
+ /** Returns true if the specified interval 'that' overlaps with any of the exons actually spliced into this transcript */
+ public boolean overlapsExonP (GenomeLoc that) {
+ for ( GenomeLoc e : exons ) {
+ if ( e.overlapsP(that) ) return true;
+ }
+ return false;
+ }
+ public String toString() {
+ StringBuilder b = new StringBuilder("000\t"); // first field is unused but required in th ecurrent format; just set to something
+ b.append(transcript_id); // #1
+ b.append('\t');
+ b.append(getLocation().getContig()); // #2
+ b.append('\t');
+ b.append( (strand==1?'+':'-') ); // #3
+ b.append('\t');
+ b.append( (getLocation().getStart() - 1) ); // #4
+ b.append('\t');
+ b.append( getLocation().getStop()); // #5
+ b.append('\t');
+ b.append( (transcript_coding_interval.getStart() - 1) ); // #6
+ b.append('\t');
+ b.append( transcript_coding_interval.getStop()); // #7
+ b.append('\t');
+ b.append(exons.size()); // #8
+ b.append('\t');
+ for ( GenomeLoc loc : exons ) { b.append( (loc.getStart()-1) ); b.append(','); } // #9
+ b.append('\t');
+ for ( GenomeLoc loc : exons ) { b.append( loc.getStop() ); b.append(','); } // #10
+ b.append("\t0\t"); // # 11 - unused?
+ b.append(gene_name); // # 12
+ b.append("\tcmpl\tcmpl\t"); // #13, #14 - unused?
+ for ( Integer f : exon_frames ) { b.append( f ); b.append(','); } // #15
+
+
+ return b.toString();
+ }
+
+ /** Convenience method, which is packaged here for a lack of better place; it is indeed closely related to
+ * rodRefSeq though: takes list of rods (transcripts) overlapping with a given position and determines whether
+ * this position is fully whithin an exon of <i>any</i> of those transcripts. Passing null is safe (will return false).
+ * NOTE: position can be still within a UTR, see #isCoding
+ * @return true if it's an exon
+ */
+ public static boolean isExon(RODRecordList l) {
+
+ if ( l == null ) return false;
+
+ GenomeLoc loc = l.getLocation();
+
+ for ( GATKFeature t : l ) {
+ if ( ((RefSeqFeature)t.getUnderlyingObject()).overlapsExonP(loc) ) return true;
+ }
+ return false;
+
+ }
+
+ /** Convenience method, which is packaged here for a lack of better place; it is indeed closely related to
+ * rodRefSeq though: takes list of rods (transcripts) overlapping with a given position and determines whether
+ * this position is fully whithin a coding region of <i>any</i> of those transcripts.
+ * Passing null is safe (will return false).
+ * NOTE: "coding" interval is defined as a single genomic interval, so it
+ * does not include the UTRs of the outermost exons, but it includes introns between exons spliced into a
+ * transcript, or internal exons that are not spliced into a given transcript. To check that a position is
+ * indeed within an exon but not in UTR, use #isCodingExon().
+ * @return
+ */
+ public static boolean isCoding(RODRecordList l) {
+
+ if ( l == null ) return false;
+
+ GenomeLoc loc = l.getLocation();
+
+ for ( GATKFeature t : l ) {
+ if ( ((RefSeqFeature)t.getUnderlyingObject()).overlapsCodingP(loc) ) return true;
+ }
+ return false;
+
+ }
+
+ /** Convenience method, which is packaged here for a lack of better place; it is indeed closely related to
+ * rodRefSeq though: takes list of rods (transcripts) overlapping with a given position and determines whether
+ * this position is fully whithin a coding exon portion (i.e. true coding sequence) of <i>any</i> of those transcripts.
+ * Passing null is safe (will return false). In other words, this method returns true if the list contains a transcript,
+ * for which the current position is within an exon <i>and</i> within a coding interval simultaneously.
+ * @return
+ */
+ public static boolean isCodingExon(RODRecordList l) {
+
+ if ( l == null ) return false;
+
+ GenomeLoc loc = l.getLocation();
+
+ for ( GATKFeature t : l ) {
+ if ( ((RefSeqFeature)t.getUnderlyingObject()).overlapsCodingP(loc) && ((RefSeqFeature)t.getUnderlyingObject()).overlapsExonP(loc) ) return true;
+ }
+ return false;
+
+ }
+
+
+ public void setTranscript_id(String transcript_id) {
+ this.transcript_id = transcript_id;
+ }
+
+ public void setStrand(int strand) {
+ this.strand = strand;
+ }
+
+ public void setTranscript_interval(GenomeLoc transcript_interval) {
+ this.transcript_interval = transcript_interval;
+ }
+
+ public void setTranscript_coding_interval(GenomeLoc transcript_coding_interval) {
+ this.transcript_coding_interval = transcript_coding_interval;
+ }
+
+ public void setExons(List<GenomeLoc> exons) {
+ this.exons = exons;
+ }
+
+ public void setGene_name(String gene_name) {
+ this.gene_name = gene_name;
+ }
+
+ public void setExon_frames(List<Integer> exon_frames) {
+ this.exon_frames = exon_frames;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getChr() {
+ return transcript_interval.getContig();
+ }
+
+ public int getStart() {
+ return transcript_interval.getStart();
+ }
+
+ public int getEnd() {
+ return transcript_interval.getStop();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/refseq/Transcript.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/refseq/Transcript.java
new file mode 100644
index 0000000..1671c79
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/refseq/Transcript.java
@@ -0,0 +1,78 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.refseq;
+
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.HasGenomeLocation;
+
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: asivache
+ * Date: Sep 22, 2009
+ * Time: 5:22:30 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface Transcript extends HasGenomeLocation {
+
+ /** Returns id of the transcript (RefSeq NM_* id) */
+ public String getTranscriptId();
+ /** Returns coding strand of the transcript, 1 or -1 for positive or negative strand, respectively */
+ public int getStrand();
+ /** Returns transcript's full genomic interval (includes all exons with UTRs) */
+ public GenomeLoc getLocation();
+ /** Returns genomic interval of the coding sequence (does not include
+ * UTRs, but still includes introns, since it's a single interval on the DNA)
+ */
+ public GenomeLoc getCodingLocation();
+ /** Name of the gene this transcript corresponds to (typically NOT gene id such as Entrez etc,
+ * but the implementation can decide otherwise)
+ */
+ public String getGeneName();
+ /** Number of exons in this transcript */
+ public int getNumExons();
+ /** Genomic location of the n-th exon; expected to throw an exception (runtime) if n is out of bounds */
+ public GenomeLoc getExonLocation(int n);
+
+ /** Returns the list of all exons in this transcript, as genomic intervals */
+ public List<GenomeLoc> getExons();
+
+ /** Returns true if the specified interval 'that' overlaps with the full genomic interval of this transcript */
+ public boolean overlapsP (GenomeLoc that);
+
+ /** Returns true if the specified interval 'that' overlaps with the coding genomic interval of this transcript.
+ * NOTE: since "coding interval" is still a single genomic interval, it will not contain UTRs of the outermost exons,
+ * but it will still contain introns and/or exons internal to this genomic locus that are not spliced into this transcript.
+ * @see #overlapsExonP
+ */
+ public boolean overlapsCodingP (GenomeLoc that);
+
+ /** Returns true if the specified interval 'that' overlaps with any of the exons actually spliced into this transcript */
+ public boolean overlapsExonP (GenomeLoc that);
+
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/sampileup/SAMPileupCodec.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/sampileup/SAMPileupCodec.java
new file mode 100644
index 0000000..8c43854
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/sampileup/SAMPileupCodec.java
@@ -0,0 +1,354 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.sampileup;
+
+import htsjdk.tribble.AsciiFeatureCodec;
+import htsjdk.tribble.exception.CodecLineParsingException;
+import htsjdk.tribble.readers.LineIterator;
+import htsjdk.tribble.util.ParsingUtils;
+
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static org.broadinstitute.gatk.utils.codecs.sampileup.SAMPileupFeature.VariantType;
+
+/**
+ * Decoder for SAM pileup data.
+ *
+ * <p>
+ * From the <a href="http://samtools.sourceforge.net/">SAMTools project documentation</a>:
+ * </p>
+ * <p>The Pileup format was first used by Tony Cox and Zemin Ning at
+ * the Sanger Institute. It describes the base-pair information at each chromosomal position. This format
+ * facilitates SNP/indel calling and brief alignment viewing by eye. Note that the pileup program has been replaced
+ * in Samtools by mpileup, which produces a slightly different output format by default.
+ * </p>
+
+ * <h3>Format</h3>
+ * <p>There are two versions of the original pileup format: the current 6-column format produced by Samtools, and the old
+ * 10/13-column "consensus" format which could be obtained by using the -c argument, now deprecated. </p>
+ * <h4>Simple pileup: 6-column format</h4>
+ * <p>
+ * Each line consists of chromosome, 1-based coordinate, reference base, the
+ * number of reads covering the site, read bases and base qualities. At the
+ * read base column, a dot stands for a match to the reference base on the
+ * forward strand, a comma for a match on the reverse strand, `ACGTN' for a mismatch
+ * on the forward strand and `acgtn' for a mismatch on the reverse strand.
+ * A pattern `\+[0-9]+[ACGTNacgtn]+' indicates there is an insertion between
+ * this reference position and the next reference position. The length of the
+ * insertion is given by the integer in the pattern, followed by the inserted sequence.
+ * </p>
+ * <pre>
+ * seq1 272 T 24 ,.$.....,,.,.,...,,,.,..^+. <<<+;<<<<<<<<<<<=<;<;7<&
+ * seq1 273 T 23 ,.....,,.,.,...,,,.,..A <<<;<<<<<<<<<3<=<<<;<<+
+ * seq1 274 T 23 ,.$....,,.,.,...,,,.,... 7<7;<;<<<<<<<<<=<;<;<<6
+ * seq1 275 A 23 ,$....,,.,.,...,,,.,...^l. <+;9*<<<<<<<<<=<<:;<<<<
+ * seq1 276 G 22 ...T,,.,.,...,,,.,.... 33;+<<7=7<<7<&<<1;<<6<
+ * seq1 277 T 22 ....,,.,.,.C.,,,.,..G. +7<;<<<<<<<&<=<<:;<<&<
+ * seq1 278 G 23 ....,,.,.,...,,,.,....^k. %38*<<;<7<<7<=<<<;<<<<<
+ * seq1 279 C 23 A..T,,.,.,...,,,.,..... ;75&<<<<<<<<<=<<<9<<:<<
+ * </pre>
+ * <p>
+ * See the <a href="http://samtools.sourceforge.net/pileup.shtml">Pileup format documentation</a> for more details.
+ * </p>
+ *
+ * <h4>Consensus pileup: 10/13-column format</h4>
+ * <p>The "consensus" or extended pileup consists of the following:
+ * <ul>
+ * <li>original 6 columns as described above</li>
+ * <li>4 extra columns representing consensus values (consensus base, consensus quality, variant quality and maximum mapping quality of the
+ * reads covering the sites) for all sites, inserted before the bases and quality strings</li>
+ * <li>3 extra columns indicating counts of reads supporting indels (just for indel sites)</li>
+ * </ul>
+ * </p>
+ * <h4>Example of consensus pileup for SNP or non-variant sites</h4>
+ * <pre>
+ * seq1 60 T T 66 0 99 13 ...........^~.^~. 9<<55<;<<<<<<
+ * seq1 61 G G 72 0 99 15 .............^~.^y. (;975&;<<<<<<<<
+ * seq1 62 T T 72 0 99 15 .$.............. <;;,55;<<<<<<<<
+ * seq1 63 G G 72 0 99 15 .$.............^~. 4;2;<7:+<<<<<<<
+ * seq1 64 G G 69 0 99 14 .............. 9+5<;;;<<<<<<<
+ * seq1 65 A A 69 0 99 14 .$............. <5-2<;;<<<<<<;
+ * seq1 66 C C 66 0 99 13 ............. &*<;;<<<<<<8<
+ * seq1 67 C C 69 0 99 14 .............^~. ,75<.4<<<<<-<<
+ * seq1 68 C C 69 0 99 14 .............. 576<;7<<<<<8<< *
+ * </pre>
+ *
+ * <h4>Example of consensus pileup for indels</h4>
+ * <pre>
+ * Escherichia_coli_K12 3995037 * *\/* 430 0 37 144 * +A 143 1 0
+ * Escherichia_coli_K12 3995279 * *\/* 202 0 36 68 * +A 67 1 0
+ * Escherichia_coli_K12 3995281 * *\/* 239 0 36 67 * -CG 66 1 0
+ * </pre>
+ * <p>
+ * See <a href="http://samtools.sourceforge.net/cns0.shtml/">Consensus pileup format (deprecated)</a> for more details.
+ * </p>
+ *
+ * <h3>Caveat</h3>
+ * <p>Handling of indels is questionable at the moment. Proceed with care.</p>
+ *
+ *
+ * @author Matt Hanna, Geraldine VdAuwera
+ * @since 2014
+ */
+public class SAMPileupCodec extends AsciiFeatureCodec<SAMPileupFeature> {
+ // number of tokens expected (6 or 10 are valid, anything else is wrong)
+ private static final int basicTokenCount = 6;
+ private static final int consensusSNPTokenCount = 10;
+ private static final int consensusIndelTokenCount = 13;
+ private static final char fldDelim = '\t';
+ // allocate once and don't ever bother creating them again:
+ private static final String baseA = "A";
+ private static final String baseC = "C";
+ private static final String baseG = "G";
+ private static final String baseT = "T";
+ private static final String emptyStr = ""; // we will use this for "reference" allele in insertions
+
+ public SAMPileupCodec() {
+ super(SAMPileupFeature.class);
+ }
+
+ public SAMPileupFeature decode(String line) {
+ //+1 because we want to know if we have more than the max
+ String[] tokens = new String[consensusIndelTokenCount+1];
+
+ // split the line
+ final int count = ParsingUtils.split(line,tokens,fldDelim);
+
+ SAMPileupFeature feature = new SAMPileupFeature();
+
+ /**
+ * Tokens 0, 1, 2 are the same for both formats so they will be interpreted without differentiation.
+ * The 10/13-format has 4 tokens inserted after token 2 compared to the 6-format, plus 3 more tokens added at
+ * the end for indels. We are currently not making any use of the extra indel tokens.
+ *
+ * Any token count other than basicTokenCount, consensusSNPTokenCount or consensusIndelTokenCount is wrong.
+ */
+ final String observedString, bases, quals;
+
+ feature.setChr(tokens[0]);
+ feature.setStart(Integer.parseInt(tokens[1]));
+
+ if(tokens[2].length() != 1) {
+ throw new CodecLineParsingException("The SAM pileup line had unexpected base " + tokens[2] + " on line = " + line);
+ }
+ feature.setRef(tokens[2].charAt(0));
+
+ switch (count) {
+ case basicTokenCount:
+ bases = tokens[4];
+ quals = tokens[5];
+ // parsing is pretty straightforward for 6-col format
+ if ( feature.getRef() == '*' ) { // this indicates an indel -- but it shouldn't occur with vanilla 6-col format
+ throw new CodecLineParsingException("Found an indel on line = " + line + " but it shouldn't happen in simple pileup format");
+ } else {
+ parseBasesAndQuals(feature, bases, quals);
+ feature.setRefBases(tokens[2].toUpperCase());
+ feature.setEnd(feature.getStart());
+ }
+ break;
+ case consensusSNPTokenCount: // pileup called a SNP or a reference base
+ observedString = tokens[3].toUpperCase();
+ feature.setFWDAlleles(new ArrayList<String>(2));
+ feature.setConsensusConfidence(Double.parseDouble(tokens[4]));
+ feature.setVariantConfidence(Double.parseDouble(tokens[5]));
+ bases = tokens[8];
+ quals = tokens[9];
+ // confirm that we have a non-variant, not a mis-parsed indel
+ if ( feature.getRef() == '*' ) {
+ throw new CodecLineParsingException("Line parsing of " + line + " says we have a SNP or non-variant but the ref base is '*', which indicates an indel");
+ }
+ // Parse the SNP or non-variant
+ parseBasesAndQuals(feature, bases, quals);
+ if ( observedString.length() != 1 ) {
+ throw new CodecLineParsingException( "Line parsing of " + line + " says we have a SNP or non-variant but the genotype token is not a single letter: " + observedString);
+ }
+ feature.setRefBases(tokens[2].toUpperCase());
+ feature.setEnd(feature.getStart());
+
+ char ch = observedString.charAt(0);
+
+ switch ( ch ) { // record alleles (decompose ambiguous base codes)
+ case 'A': feature.getFWDAlleles().add(baseA); feature.getFWDAlleles().add(baseA); break;
+ case 'C': feature.getFWDAlleles().add(baseC); feature.getFWDAlleles().add(baseC); break;
+ case 'G': feature.getFWDAlleles().add(baseG); feature.getFWDAlleles().add(baseG); break;
+ case 'T': feature.getFWDAlleles().add(baseT); feature.getFWDAlleles().add(baseT); break;
+ case 'M': feature.getFWDAlleles().add(baseA); feature.getFWDAlleles().add(baseC); break;
+ case 'R': feature.getFWDAlleles().add(baseA); feature.getFWDAlleles().add(baseG); break;
+ case 'W': feature.getFWDAlleles().add(baseA); feature.getFWDAlleles().add(baseT); break;
+ case 'S': feature.getFWDAlleles().add(baseC); feature.getFWDAlleles().add(baseG); break;
+ case 'Y': feature.getFWDAlleles().add(baseC); feature.getFWDAlleles().add(baseT); break;
+ case 'K': feature.getFWDAlleles().add(baseG); feature.getFWDAlleles().add(baseT); break;
+ }
+ if ( feature.getFWDAlleles().get(0).charAt(0) == feature.getRef() && feature.getFWDAlleles().get(1).charAt(0) == feature.getRef() ) feature.setVariantType(VariantType.NONE);
+ else {
+ // we know that at least one allele is non-ref;
+ // if one is ref and the other is non-ref, or if both are non ref but they are the same (i.e.
+ // homozygous non-ref), we still have 2 allelic variants at the site (e.g. one ref and one nonref)
+ feature.setVariantType(VariantType.SNP);
+ if ( feature.getFWDAlleles().get(0).charAt(0) == feature.getRef() ||
+ feature.getFWDAlleles().get(1).charAt(0) == feature.getRef() ||
+ feature.getFWDAlleles().get(0).equals(feature.getFWDAlleles().get(1))
+ ) feature.setNumNonRef(1);
+ else feature.setNumNonRef(2); // if both observations differ from ref and they are not equal to one another, then we get multiallelic site...
+ }
+ break;
+ case consensusIndelTokenCount:
+ observedString = tokens[3].toUpperCase();
+ feature.setFWDAlleles(new ArrayList<String>(2));
+ feature.setConsensusConfidence(Double.parseDouble(tokens[4]));
+ feature.setVariantConfidence(Double.parseDouble(tokens[5]));
+ // confirm that we have an indel, not a mis-parsed SNP or non-variant
+ if ( feature.getRef() != '*' ) {
+ throw new CodecLineParsingException("Line parsing of " + line + " says we have an indel but the ref base is not '*'");
+ }
+ // Parse the indel
+ parseIndels(observedString,feature) ;
+ if ( feature.isDeletion() ) feature.setEnd(feature.getStart()+feature.length()-1);
+ else feature.setEnd(feature.getStart()); // if it's not a deletion and we are biallelic, this has got to be an insertion; otherwise the state is inconsistent!!!!
+ break;
+ default:
+ throw new CodecLineParsingException("The SAM pileup line didn't have the expected number of tokens " +
+ "(expected = " + basicTokenCount + " (basic pileup), " + consensusSNPTokenCount +
+ " (consensus pileup for a SNP or non-variant site) or " + consensusIndelTokenCount +
+ " (consensus pileup for an indel); saw = " + count + " on line = " + line + ")");
+ }
+ return feature;
+ }
+
+ @Override
+ public Object readActualHeader(LineIterator lineIterator) {
+ // No header for this format
+ return null;
+ }
+
+ private void parseIndels(String genotype,SAMPileupFeature feature) {
+ String [] obs = genotype.split("/"); // get observations, now need to tinker with them a bit
+
+ // if reference allele is among the observed alleles, we will need to take special care of it since we do not have direct access to the reference;
+ // if we have an insertion, the "reference" allele is going to be empty; if it it is a deletion, we will deduce the "reference allele" bases
+ // from what we have recorded for the deletion allele (e.g. "-CAC")
+ boolean hasRefAllele = false;
+
+ for ( int i = 0 ; i < obs.length ; i++ ) {
+ if ( obs[i].length() == 1 && obs[i].charAt(0) == '*' ) {
+ hasRefAllele = true;
+ feature.getFWDAlleles().add(emptyStr);
+ continue;
+ }
+
+ String varBases = obs[i].toUpperCase();
+
+ switch ( obs[i].charAt(0) ) {
+ case '+':
+ if (!feature.isReference() && !feature.isInsertion()) feature.setVariantType(VariantType.INDEL);
+ else feature.setVariantType(VariantType.INSERTION);
+ feature.setRefBases(emptyStr);
+ break;
+ case '-' :
+ if (!feature.isReference() && !feature.isDeletion()) feature.setVariantType(VariantType.INDEL);
+ else feature.setVariantType(VariantType.DELETION);
+ feature.setRefBases(varBases); // remember what was deleted, this will be saved as "reference allele"
+ break;
+ default: throw new CodecLineParsingException("Can not interpret observed indel allele record: "+genotype);
+ }
+ feature.getFWDAlleles().add(varBases);
+ feature.setLength(obs[i].length()-1); // inconsistent for non-biallelic indels!!
+ }
+ if ( hasRefAllele ) {
+ // we got at least one ref. allele (out of two recorded)
+ if (feature.isReference()) { // both top theories are actually ref allele;
+ feature.setNumNonRef(0); // no observations of non-reference allele at all
+ feature.setRefBases(emptyStr);
+ } else {
+ feature.setNumNonRef(1); // hasRefAllele = true, so one allele was definitely ref, hence there is only one left
+ }
+ } else {
+ // we observe two non-ref alleles; they better be the same variant, otherwise the site is not bi-allelic and at the moment we
+ // fail to set data in a consistent way.
+ if ( feature.getFWDAlleles().get(0).equals(feature.getFWDAlleles().get(1))) feature.setNumNonRef(1);
+ else feature.setNumNonRef(2);
+ }
+ // DONE with indels
+
+ }
+
+ private void parseBasesAndQuals(SAMPileupFeature feature, final String bases, final String quals)
+ {
+ //System.out.printf("%s%n%s%n", bases, quals);
+
+ // needs to convert the base string with its . and , to the ref base
+ StringBuilder baseBuilder = new StringBuilder();
+ StringBuilder qualBuilder = new StringBuilder();
+ boolean done = false;
+ for ( int i = 0, j = 0; i < bases.length() && ! done; i++ ) {
+ //System.out.printf("%d %d%n", i, j);
+ char c = (char)bases.charAt(i);
+
+ switch ( c ) {
+ case '.': // matches reference
+ case ',': // matches reference
+ baseBuilder.append(feature.getRef());
+ qualBuilder.append(quals.charAt(j++));
+ break;
+ case '$': // end of read
+ break;
+ case '*': // end of indel?
+ j++;
+ break;
+ case '^': // mapping quality
+ i++;
+ break;
+ case '+': // start of indel
+ case '-': // start of indel
+ final Pattern regex = Pattern.compile("([0-9]+).*"); // matches case 1
+ final String rest = bases.substring(i+1);
+ //System.out.printf("sub is %s%n", rest);
+ Matcher match = regex.matcher(rest);
+ if ( ! match.matches() ) {
+ if ( feature.getRef() != '*' )
+ throw new CodecLineParsingException("Bad pileup format: " + bases + " at position " + i);
+ done = true;
+ }
+ else {
+ String g = match.group(1);
+ //System.out.printf("group is %d, match is %s%n", match.groupCount(), g);
+ int l = Integer.parseInt(g);
+ i += l + g.length(); // length of number + that many bases + +/- at the start (included in the next i++)
+ //System.out.printf("remaining is %d => %s%n", l, bases.substring(i+1));
+ }
+ break;
+ default: // non reference base
+ baseBuilder.append(c);
+ qualBuilder.append(quals.charAt(j++));
+ }
+ }
+
+ feature.setPileupBases(baseBuilder.toString());
+ feature.setPileupQuals(qualBuilder.toString());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/sampileup/SAMPileupFeature.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/sampileup/SAMPileupFeature.java
new file mode 100644
index 0000000..89f168b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/sampileup/SAMPileupFeature.java
@@ -0,0 +1,276 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.sampileup;
+
+import htsjdk.samtools.util.StringUtil;
+import htsjdk.tribble.Feature;
+
+import java.util.List;
+
+/**
+ * A tribble feature representing a SAM pileup.
+ *
+ * Allows intake of both simple (6-column) or extended/consensus (10/13-column) pileups. Simple pileup features will
+ * contain only basic information, no observed alleles or variant/genotype inferences, and so shouldn't be used as
+ * input for analysis that requires that information.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class SAMPileupFeature implements Feature {
+ public enum VariantType { NONE, SNP, INSERTION, DELETION, INDEL };
+
+ private String contig; // genomic location of this genotyped site
+ private int start;
+ private int stop;
+
+ private char refBaseChar; // what we have set for the reference base (is set to a '*' for indel!)
+ private String refBases; // the reference base sequence according to NCBI; single base for point mutations, deleted bases for deletions, empty string for insertions
+
+ private String pileupQuals; // the read base qualities
+ private String pileupBases; // the read bases themselves
+
+ private List<String> observedAlleles = null; // The sequences of the observed alleles (e.g. {"A","C"} for point mutation or {"","+CC"} for het. insertion
+ private VariantType varType = VariantType.NONE;
+ private int nNonref = 0; // number of non-reference alleles observed
+ private int eventLength = 0; // number of inserted or deleted bases
+
+ private double consensusScore = 0;
+ private double variantScore = 0;
+
+ /**
+ * create the pileup feature. Default protection so that only other classes in this package can create it.
+ */
+ SAMPileupFeature() {}
+
+ public String getChr() {
+ return contig;
+ }
+
+ protected void setChr(String chr) {
+ this.contig = chr;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ protected void setStart(int start) {
+ this.start = start;
+ }
+
+ public int getEnd() {
+ return stop;
+ }
+
+ protected void setEnd(int end) {
+ this.stop = end;
+ }
+
+ public String getQualsAsString() { return pileupQuals; }
+
+ protected void setPileupQuals(String pileupQuals) {
+ this.pileupQuals = pileupQuals;
+ }
+
+ /** Returns reference base for point genotypes or '*' for indel genotypes, as a char.
+ *
+ */
+ public char getRef() { return refBaseChar; }
+
+ protected void setRef(char ref) {
+ this.refBaseChar = ref;
+ }
+
+ public int size() { return pileupQuals.length(); }
+
+ /** Returns pile of observed bases over the current genomic location.
+ *
+ */
+ public String getBasesAsString() { return pileupBases; }
+
+ protected void setPileupBases(String pileupBases) {
+ this.pileupBases = pileupBases;
+ }
+
+ /** Returns formatted pileup string for the current genomic location as
+ * "location: reference_base observed_base_pile observed_qual_pile"
+ */
+ public String getPileupString()
+ {
+ if(start == stop)
+ return String.format("%s:%d: %s %s %s", getChr(), getStart(), getRef(), getBasesAsString(), getQualsAsString());
+ else
+ return String.format("%s:%d-%d: %s %s %s", getChr(), getStart(), getEnd(), getRef(), getBasesAsString(), getQualsAsString());
+ }
+
+ /**
+ * Gets the bases in byte array form.
+ * @return byte array of the available bases.
+ */
+ public byte[] getBases() {
+ return StringUtil.stringToBytes(getBasesAsString());
+ }
+
+ /**
+ * Gets the Phred base qualities without ASCII offset.
+ * @return Phred base qualities.
+ */
+ public byte[] getQuals() {
+ byte[] quals = StringUtil.stringToBytes(getQualsAsString());
+ for(int i = 0; i < quals.length; i++) quals[i] -= 33;
+ return quals;
+ }
+
+ /** Returns bases in the reference allele as a String. For point genotypes, the string consists of a single
+ * character (reference base). For indel genotypes, the string is empty for insertions into
+ * the reference, or consists of deleted bases for deletions.
+ *
+ * @return reference allele, forward strand
+ */
+ public String getFWDRefBases() {
+ return refBases;
+ }
+
+ protected void setRefBases(String refBases) {
+ this.refBases = refBases;
+ }
+
+ public List<String> getFWDAlleles() {
+ return observedAlleles;
+ }
+
+ protected void setFWDAlleles(List<String> alleles) {
+ this.observedAlleles = alleles;
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // What kind of variant are we?
+ //
+ // ----------------------------------------------------------------------
+ public boolean isSNP() { return varType == VariantType.SNP; }
+ public boolean isInsertion() { return varType == VariantType.INSERTION; }
+ public boolean isDeletion() { return varType == VariantType.DELETION ; }
+ public boolean isIndel() { return isInsertion() || isDeletion() || varType == VariantType.INDEL; }
+ public boolean isReference() { return varType == VariantType.NONE; }
+
+ protected void setVariantType(VariantType variantType) {
+ this.varType = variantType;
+ }
+
+ public boolean isHom() {
+ // implementation-dependent: here we use the fact that for ref and snps we actually use fixed static strings to remember the genotype
+ if ( ! isIndel() ) return ( observedAlleles.get(0).equals(observedAlleles.get(1)) );
+ return ( isInsertion() || isDeletion() ) && observedAlleles.get(0).equals(observedAlleles.get(1) );
+ }
+
+ public boolean isHet() {
+ // implementation-dependent: here we use the fact that for ref and snps we actually use fixed static strings to remember the genotype
+ if ( ! isIndel() ) return ( !(observedAlleles.get(0).equals(observedAlleles.get(1))) );
+ return isIndel() || ( ! observedAlleles.get(0).equals(observedAlleles.get(1) ) );
+ }
+
+ public double getVariantConfidence() {
+ return variantScore;
+ }
+
+ protected void setVariantConfidence(double variantScore) {
+ this.variantScore = variantScore;
+ }
+
+ public boolean isBiallelic() {
+ return nNonref < 2;
+ }
+
+ protected void setNumNonRef(int nNonref) {
+ this.nNonref = nNonref;
+ }
+
+ public double getConsensusConfidence() {
+ return consensusScore;
+ }
+
+ protected void setConsensusConfidence(double consensusScore) {
+ this.consensusScore = consensusScore;
+ }
+
+ public int length() {
+ return eventLength;
+ }
+
+ protected void setLength(int eventLength) {
+ this.eventLength = eventLength;
+ }
+
+ public boolean isIndelGenotype() {
+ return refBaseChar == '*';
+ }
+
+
+ public boolean isPointGenotype() {
+ return ! isIndelGenotype();
+ }
+
+ /** Implements method required by GenotypeList interface. If this object represents
+ * an indel genotype, then it returns itself through this method. If this object is a
+ * point genotype, this method returns null.
+ * @return
+ */
+ public SAMPileupFeature getIndelGenotype() {
+ if ( isIndelGenotype() ) return this;
+ else return null;
+ }
+
+ /** Implements method required by GenotypeList interface. If this object represents
+ * a point genotype, then it returns itself through this method. If this object is an
+ * indel genotype, this method returns null.
+ * @return
+ */
+ public SAMPileupFeature getPointGenotype() {
+ if ( isPointGenotype() ) return this;
+ else return null;
+ }
+
+ /** Returns true if this object \em is an indel genotype (and thus
+ * indel genotype is what it only has).
+ * @return
+ */
+ public boolean hasIndelGenotype() {
+ return isIndelGenotype();
+ }
+
+ /** Returns true if this object \em is a point genotype (and thus
+ * point genotype is what it only has.
+ * @return
+ */
+ public boolean hasPointGenotype() {
+ return isPointGenotype();
+ }
+
+
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/samread/SAMReadCodec.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/samread/SAMReadCodec.java
new file mode 100644
index 0000000..d83ce6d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/samread/SAMReadCodec.java
@@ -0,0 +1,123 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.samread;
+
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.TextCigarCodec;
+import htsjdk.samtools.util.StringUtil;
+import htsjdk.tribble.AsciiFeatureCodec;
+import htsjdk.tribble.exception.CodecLineParsingException;
+import htsjdk.tribble.readers.LineIterator;
+import htsjdk.tribble.util.ParsingUtils;
+
+/**
+ * Decodes a simple SAM text string.
+ *
+ * <p>
+ * Reads in the SAM text version of a BAM file as a ROD. For testing only
+ * </p>
+ *
+ * <p>
+ * See also: @see <a href="http://samtools.sourceforge.net">SAMTools</a> for format specification
+ * </p>
+ *
+ * <h2>File format example</h2>
+ * <pre>
+ * SL-XBC:1:10:628:923#0 16 Escherichia_coli_K12 1 37 76M = 1 0 AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGCTTCTGA B@>87<;A@?@957:>>@AA at B>@A9AB at B>@A@@@@@A;=AAB at BBBBBCBBBB@>A>:ABB at BAABCB=CA at CB
+ * </pre>
+ *
+ * @author Matt Hanna
+ * @since 2009
+ */
+public class SAMReadCodec extends AsciiFeatureCodec<SAMReadFeature> {
+ /* SL-XBC:1:10:628:923#0 16 Escherichia_coli_K12 1 37 76M = 1 0 AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGCTTCTGA B@>87<;A@?@957:>>@AA at B>@A9AB at B>@A@@@@@A;=AAB at BBBBBCBBBB@>A>:ABB at BAABCB=CA at CB */
+
+ // the number of tokens we expect to parse from a read line
+ private static final int expectedTokenCount = 11;
+
+ public SAMReadCodec() {
+ super(SAMReadFeature.class);
+ }
+
+ /**
+ * Decode a single line in a SAM text file.
+ * @param line line to decode.
+ * @return A SAMReadFeature modeling that line.
+ */
+ public SAMReadFeature decode(String line) {
+ // we may be asked to process a header line; ignore it
+ if (line.startsWith("@")) return null;
+
+ String[] tokens = new String[expectedTokenCount];
+
+ // split the line
+ int count = ParsingUtils.splitWhitespace(line,tokens);
+
+ // check to see if we've parsed the string into the right number of tokens (expectedTokenCount)
+ if (count != expectedTokenCount)
+ throw new CodecLineParsingException("the SAM read line didn't have the expected number of tokens " +
+ "(expected = " + expectedTokenCount + ", saw = " + count + " on " +
+ "line = " + line + ")");
+
+ final String readName = tokens[0];
+ final int flags = Integer.parseInt(tokens[1]);
+ final String contigName = tokens[2];
+ final int alignmentStart = Integer.parseInt(tokens[3]);
+ final int mapQ = Integer.parseInt(tokens[4]);
+ final String cigarString = tokens[5];
+ final String mateContigName = tokens[6];
+ final int mateAlignmentStart = Integer.parseInt(tokens[7]);
+ final int inferredInsertSize = Integer.parseInt(tokens[8]);
+ final byte[] bases = StringUtil.stringToBytes(tokens[9]);
+ final byte[] qualities = StringUtil.stringToBytes(tokens[10]);
+
+ // Infer the alignment end.
+ Cigar cigar = TextCigarCodec.getSingleton().decode(cigarString);
+ int alignmentEnd = alignmentStart + cigar.getReferenceLength() - 1;
+
+ // Remove printable character conversion from the qualities.
+ for(byte quality: qualities) quality -= 33;
+
+ return new SAMReadFeature(readName,
+ flags,
+ contigName,
+ alignmentStart,
+ alignmentEnd,
+ mapQ,
+ cigarString,
+ mateContigName,
+ mateAlignmentStart,
+ inferredInsertSize,
+ bases,
+ qualities);
+ }
+
+ @Override
+ public Object readActualHeader(LineIterator lineIterator) {
+ // No header for this format
+ return null;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/samread/SAMReadFeature.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/samread/SAMReadFeature.java
new file mode 100644
index 0000000..129ae6e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/samread/SAMReadFeature.java
@@ -0,0 +1,199 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.samread;
+
+import htsjdk.tribble.Feature;
+
+/**
+ * Represents a SAM record read from a SAM text format file.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class SAMReadFeature implements Feature {
+ /**
+ * Name of this read.
+ */
+ private final String readName;
+
+ /**
+ * Flags associated with this read.
+ */
+ private final int flags;
+
+ /**
+ * Contig to which this read is aligned.
+ */
+ private final String contig;
+
+ /**
+ * Position on contig to which this read is aligned.
+ */
+ private final int alignmentStart;
+
+ /**
+ * Position on contig at which this alignment ends.
+ */
+ private final int alignmentEnd;
+
+ /**
+ * Mapping quality for the read.
+ */
+ private final int mapQ;
+
+ /**
+ * Cigar string matching read to reference.
+ */
+ private final String cigarString;
+
+ /**
+ * Contig to which this read's pair is aligned.
+ */
+ private final String mateContig;
+
+ /**
+ * Position in contig to which this read's pair is aligned.
+ */
+ private final int mateAlignmentStart;
+
+ /**
+ * Size between pairs.
+ */
+ private final int insertSize;
+
+ /**
+ * Bases in this read.
+ */
+ private final byte[] bases;
+
+ /**
+ * Qualities constituting this read.
+ */
+ private final byte[] qualities;
+
+ // Tags are not currently supported.
+
+ /**
+ * create the read feature. Default protection so that only other classes in this package can create it.
+ */
+ SAMReadFeature(final String readName,
+ final int flags,
+ final String contig,
+ final int alignmentStart,
+ final int alignmentEnd,
+ final int mapQ,
+ final String cigarString,
+ final String mateContig,
+ final int mateAlignmentStart,
+ final int insertSize,
+ final byte[] bases,
+ final byte[] qualities) {
+ this.readName = readName;
+ this.flags = flags;
+ this.contig = contig;
+ this.alignmentStart = alignmentStart;
+ this.alignmentEnd = alignmentEnd;
+ this.mapQ = mapQ;
+ this.cigarString = cigarString;
+ this.mateContig = mateContig;
+ this.mateAlignmentStart = mateAlignmentStart;
+ this.insertSize = insertSize;
+ this.bases = bases;
+ this.qualities = qualities;
+ }
+
+ public String getReadName() {
+ return readName;
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
+ public String getReferenceName() {
+ return contig;
+ }
+
+ public int getAlignmentStart() {
+ return alignmentStart;
+ }
+
+ public int getAlignmentEnd() {
+ return alignmentEnd;
+ }
+
+ /**
+ * An alias for getReferenceName, required by Feature interface.
+ * @return Aligned contig name.
+ */
+ public String getChr() {
+ return getReferenceName();
+ }
+
+ /**
+ * An alias for getAlignmentEnd(), required by Feature interface.
+ * @return End of alignment, inclusive.
+ */
+ public int getStart() {
+ return getAlignmentStart();
+ }
+
+ /**
+ * An alias for getAlignmentStart(), required by Feature interface.
+ * @return Aligned position. 1-based.
+ */
+ public int getEnd() {
+ return getAlignmentEnd();
+ }
+
+ public int getMappingQuality() {
+ return mapQ;
+ }
+
+ public String getCigarString() {
+ return cigarString;
+ }
+
+ public String getMateReferenceName() {
+ return mateContig;
+ }
+
+ public int getMateAlignmentStart() {
+ return mateAlignmentStart;
+ }
+
+ public int getInferredInsertSize() {
+ return insertSize;
+ }
+
+ public byte[] getReadBases() {
+ return bases;
+ }
+
+ public byte[] getReadQualities() {
+ return qualities;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/table/BedTableCodec.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/table/BedTableCodec.java
new file mode 100644
index 0000000..9a0115f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/table/BedTableCodec.java
@@ -0,0 +1,59 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.table;
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.engine.refdata.ReferenceDependentFeatureCodec;
+
+import java.util.Arrays;
+
+/**
+ * The standard table codec that expects loci as contig start stop, not contig:start-stop
+ *
+ * <p>
+ * The standard table codec with a slightly different parsing convention
+ * (expects loci as contig start stop, not contig:start-stop)
+ * </p>
+ *
+ * <p>
+ * See also: TableCodec
+ * </p>
+ *
+ * @author Chris Hartl
+ * @since 2010
+ */
+public class BedTableCodec extends TableCodec implements ReferenceDependentFeatureCodec {
+
+ @Override
+ public TableFeature decode(String line) {
+ if (line.startsWith(headerDelimiter) || line.startsWith(commentDelimiter) || line.startsWith(igvHeaderDelimiter))
+ return null;
+ String[] split = line.split(delimiterRegex);
+ if (split.length < 1)
+ throw new IllegalArgumentException("TableCodec line = " + line + " doesn't appear to be a valid table format");
+ return new TableFeature(genomeLocParser.createGenomeLoc(split[0],Integer.parseInt(split[1])-1,Integer.parseInt(split[2])), Arrays.asList(split),header);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/table/TableCodec.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/table/TableCodec.java
new file mode 100644
index 0000000..1058d3e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/table/TableCodec.java
@@ -0,0 +1,126 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.table;
+
+import htsjdk.tribble.AsciiFeatureCodec;
+import htsjdk.tribble.readers.LineIterator;
+import org.broadinstitute.gatk.engine.refdata.ReferenceDependentFeatureCodec;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Reads tab deliminated tabular text files
+ *
+ * <p>
+ * <ul>
+ * <li>Header: must begin with line HEADER or track (for IGV), followed by any number of column names,
+ * separated by whitespace.</li>
+ * <li>Comment lines starting with # are ignored</li>
+ * <li>Each non-header and non-comment line is split into parts by whitespace,
+ * and these parts are assigned as a map to their corresponding column name in the header.
+ * Note that the first element (corresponding to the HEADER column) must be a valid genome loc
+ * such as 1, 1:1 or 1:1-10, which is the position of the Table element on the genome. TableCodec
+ * requires that there be one value for each column in the header, and no more, on all lines.</li>
+ * </ul>
+ * </p>
+ *
+ * </p>
+ *
+ * <h2>File format example</h2>
+ * <pre>
+ * HEADER a b c
+ * 1:1 1 2 3
+ * 1:2 4 5 6
+ * 1:3 7 8 9
+ * </pre>
+ *
+ * @author Mark DePristo
+ * @since 2009
+ */
+public class TableCodec extends AsciiFeatureCodec<TableFeature> implements ReferenceDependentFeatureCodec {
+ final static protected String delimiterRegex = "\\s+";
+ final static protected String headerDelimiter = "HEADER";
+ final static protected String igvHeaderDelimiter = "track";
+ final static protected String commentDelimiter = "#";
+
+ protected ArrayList<String> header = new ArrayList<String>();
+
+ /**
+ * The parser to use when resolving genome-wide locations.
+ */
+ protected GenomeLocParser genomeLocParser;
+
+ public TableCodec() {
+ super(TableFeature.class);
+ }
+
+ /**
+ * Set the parser to use when resolving genetic data.
+ * @param genomeLocParser The supplied parser.
+ */
+ @Override
+ public void setGenomeLocParser(GenomeLocParser genomeLocParser) {
+ this.genomeLocParser = genomeLocParser;
+ }
+
+ @Override
+ public TableFeature decode(String line) {
+ if (line.startsWith(headerDelimiter) || line.startsWith(commentDelimiter) || line.startsWith(igvHeaderDelimiter))
+ return null;
+ String[] split = line.split(delimiterRegex);
+ if (split.length < 1)
+ throw new IllegalArgumentException("TableCodec line = " + line + " doesn't appear to be a valid table format");
+ return new TableFeature(genomeLocParser.parseGenomeLoc(split[0]),Arrays.asList(split), header);
+ }
+
+ @Override
+ public Object readActualHeader(final LineIterator reader) {
+ boolean isFirst = true;
+ while (reader.hasNext()) {
+ final String line = reader.peek(); // Peek to avoid reading non-header data
+ if ( isFirst && ! line.startsWith(headerDelimiter) && ! line.startsWith(commentDelimiter)) {
+ throw new UserException.MalformedFile("TableCodec file does not have a header");
+ }
+ isFirst &= line.startsWith(commentDelimiter);
+ if (line.startsWith(headerDelimiter)) {
+ reader.next(); // "Commit" the peek
+ if (header.size() > 0) throw new IllegalStateException("Input table file seems to have two header lines. The second is = " + line);
+ final String spl[] = line.split(delimiterRegex);
+ Collections.addAll(header, spl);
+ return header;
+ } else if (line.startsWith(commentDelimiter)) {
+ reader.next(); // "Commit" the peek
+ } else {
+ break;
+ }
+ }
+ return header;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/table/TableFeature.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/table/TableFeature.java
new file mode 100644
index 0000000..58b06c9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/codecs/table/TableFeature.java
@@ -0,0 +1,99 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.table;
+
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.Utils;
+
+import java.util.List;
+
+/**
+ * A feature representing a single row out of a text table
+ */
+public class TableFeature implements Feature {
+ // stores the values for the columns seperated out
+ private final List<String> values;
+
+ // if we have column names, we store them here
+ private final List<String> keys;
+
+ // our location
+ private final GenomeLoc position;
+
+ public TableFeature(GenomeLoc position, List<String> values, List<String> keys) {
+ this.values = values;
+ this.keys = keys;
+ this.position = position;
+ }
+
+ @Override
+ public String getChr() {
+ return position.getContig();
+ }
+
+ @Override
+ public int getStart() {
+ return (int)position.getStart();
+ }
+
+ @Override
+ public int getEnd() {
+ return (int)position.getStop();
+ }
+
+ public String getValue(int columnPosition) {
+ if (columnPosition >= values.size()) throw new IllegalArgumentException("We only have " + values.size() + "columns, the requested column = " + columnPosition);
+ return values.get(columnPosition);
+ }
+
+ public String toString() {
+ return String.format("%s\t%s",position.toString(), Utils.join("\t",values));
+ }
+
+ public String get(String columnName) {
+ int position = keys.indexOf(columnName);
+ if (position < 0) throw new IllegalArgumentException("We don't have a column named " + columnName);
+ return values.get(position);
+ }
+
+ public GenomeLoc getLocation() {
+ return this.position;
+ }
+
+ public List<String> getAllValues() {
+ return getValuesTo(values.size());
+ }
+
+ public List<String> getValuesTo(int columnPosition) {
+ return values.subList(0,columnPosition);
+ }
+
+ public List<String> getHeader() {
+ return keys;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/DefaultHashMap.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/DefaultHashMap.java
new file mode 100644
index 0000000..2c543dd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/DefaultHashMap.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.collections;
+
+import java.util.HashMap;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: farjoun
+ * Date: 10/30/12
+ * Time: 3:20 PM
+ * To change this template use File | Settings | File Templates.
+ */
+
+//lifted from http://stackoverflow.com/questions/7519339
+//could also use org.apache.commons.collections.map.DefaultedMap http://commons.apache.org/collections/apidocs/org/apache/commons/collections/map/DefaultedMap.html
+public class DefaultHashMap<K,V> extends HashMap<K,V> {
+
+ public void setDefaultValue(V defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+ protected V defaultValue;
+ public DefaultHashMap(V defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+ @Override
+ public V get(Object k) {
+ V v = super.get(k);
+ return ((v == null) && !this.containsKey(k)) ? this.defaultValue : v;
+ }
+
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/ExpandingArrayList.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/ExpandingArrayList.java
new file mode 100644
index 0000000..b2b23d3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/ExpandingArrayList.java
@@ -0,0 +1,69 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.collections;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class ExpandingArrayList<E> extends ArrayList<E> {
+ public ExpandingArrayList() { super(); }
+ public ExpandingArrayList(Collection<? extends E> c) { super(c); }
+ public ExpandingArrayList(int initialCapacity) { super(initialCapacity); }
+
+ /**
+ * Returns the element at the specified position in this list. If index > size,
+ * returns null. Otherwise tries to access the array
+ * @param index
+ * @return
+ * @throws IndexOutOfBoundsException in index < 0
+ */
+ public E get(int index) throws IndexOutOfBoundsException {
+ if ( index < size() )
+ return super.get(index);
+ else
+ return null;
+ }
+
+ public E expandingGet(int index, E default_value) throws IndexOutOfBoundsException {
+ maybeExpand(index, default_value);
+ return super.get(index);
+ }
+
+ private void maybeExpand(int index, E value) {
+ if ( index >= size() ) {
+ ensureCapacity(index+1); // make sure we have space to hold at least index + 1 elements
+ // We need to add null items until we can safely set index to element
+ for ( int i = size(); i <= index; i++ )
+ add(value);
+ }
+ }
+
+
+ public E set(int index, E element) {
+ maybeExpand(index, null);
+ return super.set(index, element);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/IndexedSet.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/IndexedSet.java
new file mode 100644
index 0000000..2bedb92
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/IndexedSet.java
@@ -0,0 +1,342 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.collections;
+
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+
+import java.util.*;
+
+/**
+* Set set where each element can be reference by a unique integer index that runs from
+* 0 to the size of the set - 1.
+*
+* @author Valentin Ruano-Rubio <valentin at broadinstitute.org>
+*/
+public class IndexedSet<E> extends AbstractSet<E> implements Set<E> {
+
+ /**
+ * Elements stored in an array-list by their index.
+ */
+ private final ArrayList<E> elements;
+
+ /**
+ * A unmodifiable view to the element list. Initially {@code null} it is thread-unsafe lazy instantiated
+ * when requested first time through {@link #asList}. Therefore typically it is shared by invoking code but
+ * there could be some extra copies (rare though) in multi-thread runs.
+ */
+ private transient List<E> unmodifiableElementsListView;
+
+ /**
+ * Quick element to index lookup map.
+ * <p>
+ * Uses a primitive int value map for efficiency sake.
+ * </p>
+ */
+ private final Object2IntMap<E> indexByElement;
+
+ /**
+ * Creates an empty indexed set indicating the expected number of elements.
+ *
+ * @param initialCapacity the initial number of elements.
+ */
+ public IndexedSet(final int initialCapacity) {
+ elements = new ArrayList<>(initialCapacity);
+ indexByElement = new Object2IntOpenHashMap<>(initialCapacity);
+ }
+
+ /**
+ * Creates a new sample list from a existing collection of elements.
+ *
+ * <p>
+ * Elements will be indexed as they appear in the input array. Repeats will be ignored.
+ * </p>
+ *
+ * @param values the original sample list.
+ *
+ * @throws IllegalArgumentException
+ * if {@code values} array is {@code null} itself, or it contains {@code null}.
+ */
+ @SuppressWarnings("unchecked")
+ public IndexedSet(final Collection<E> values) {
+ if (values == null)
+ throw new IllegalArgumentException("input values cannot be null");
+
+ final int initialCapacity = values.size();
+ elements = new ArrayList<>(initialCapacity);
+ indexByElement = new Object2IntOpenHashMap<>(initialCapacity);
+ int nextIndex = 0;
+ for (final E value : values) {
+ if (value == null)
+ throw new IllegalArgumentException("null element not allowed: index == " + nextIndex);
+ if (indexByElement.containsKey(value))
+ continue;
+ indexByElement.put(value, nextIndex++);
+ elements.add(value);
+ }
+ }
+
+ /**
+ * Creates a new sample list from a existing array of elements.
+ *
+ * <p>
+ * Elements will be indexed as they appear in the collection. Repeats will be ignored.
+ * </p>
+ *
+ * @param values the original sample list.
+ *
+ * @throws IllegalArgumentException
+ * if {@code values} collection is {@code null} itself, or it contains {@code null}.
+ */
+ @SuppressWarnings("unchecked")
+ public IndexedSet(final E ... values) {
+ if (values == null)
+ throw new IllegalArgumentException("input values cannot be null");
+
+ final int initialCapacity = values.length;
+ elements = new ArrayList<>(initialCapacity);
+ indexByElement = new Object2IntOpenHashMap<>(initialCapacity);
+ int nextIndex = 0;
+ for (final E value : values) {
+ if (value == null)
+ throw new IllegalArgumentException("null element not allowed: index == " + nextIndex);
+ if (indexByElement.containsKey(value))
+ continue;
+ indexByElement.put(value, nextIndex++);
+ elements.add(value);
+ }
+ }
+
+ /**
+ * Returns a list view of the elements in the set.
+ *
+ * <p>
+ * Elements are sorted by their index within the set.
+ * </p>
+ *
+ * <p>
+ * This view changes as the indexed set changes but it cannot be used to update its contents.
+ * In such case a {@link UnsupportedOperationException} exception will be thrown if the calling
+ * code tries to tho just that.
+ * </p>
+ *
+ * @return never {@code null}.
+ */
+ public List<E> asList() {
+ if (unmodifiableElementsListView == null)
+ unmodifiableElementsListView = Collections.unmodifiableList(elements);
+ return unmodifiableElementsListView;
+ }
+
+ /**
+ * Throws an exception if an index is out of bounds.
+ *
+ * <p>
+ * An element index is valid iff is within [0,{@link #size()}).
+ * </p>
+ *
+ * @param index the query index.
+ *
+ * @throws IllegalArgumentException {@code index} is out of bounds.
+ */
+ protected void checkIndex(final int index) {
+ if (index < 0)
+ throw new IllegalArgumentException("the index cannot be negative: " + index);
+ if (index >= size())
+ throw new IllegalArgumentException("the index is equal or larger than the list length: " + index + " >= " + size());
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return asList().iterator();
+ }
+
+ /**
+ * Returns number of elements in the set.
+ * @return never {@code null}.
+ */
+ @Override
+ public int size() {
+ return elements.size();
+ }
+
+ /**
+ *
+ * @param o
+ * @return {@code true} iff {@code o} is in
+ */
+ @Override
+ @SuppressWarnings("all")
+ public boolean contains(final Object o) {
+ return o != null && indexByElement.containsKey(o);
+ }
+
+ /**
+ * Adds a new element to the set.
+ *
+ * <p>
+ * If the element was already in th set nothing will happen and the method will return {@code false}. However,
+ * if the element is new to this set, it will assigned the next index available (equal to the size before addition).
+ * The method will return {@code true} in this case.
+ * </p>
+ *
+ * @param o the object to add.
+ *
+ * @throw IllegalArgumentException if {@code o} is {@code null}.
+ *
+ * @return {@code true} iff the set was modified by this operation.
+ */
+ @Override
+ public boolean add(final E o) {
+ if (o == null)
+ throw new IllegalArgumentException("the input argument cannot be null");
+ if (contains(o))
+ return false;
+ final int nextIndex = size();
+ elements.add(o);
+ indexByElement.put(o, nextIndex);
+ return true;
+ }
+
+ /**
+ * Removes an element from the set.
+ *
+ * <p>
+ * If the element was not present in the set, nothing happens and the method return false. However,
+ * if the element is new to this set, it will be assigned the next index available (equal to the size
+ * before addition).
+ * The method will return {@code true} in this case.
+ * </p>
+ *
+ * @param o the object to add.
+ *
+ * @throw IllegalArgumentException if {@code o} is {@code null}.
+ *
+ * @return {@code true} iff the set was modified by this operation.
+ */ @Override
+ public boolean remove(final Object o) {
+ final int index = indexByElement.removeInt(o);
+ if (index == -1)
+ return false;
+ elements.remove(index);
+ indexByElement.remove(o);
+ final ListIterator<E> it = elements.listIterator(index);
+ int nextIndex = index;
+ while (it.hasNext())
+ indexByElement.put(it.next(),nextIndex++);
+ return true;
+ }
+
+ /**
+ * Removes all elements in the set.
+ */
+ @Override
+ public void clear() {
+ elements.clear();
+ indexByElement.clear();
+ }
+
+ /**
+ * Compares this with another indexed set.
+ * @param o the other object to compare to.
+ * @return {@code false} unless {@code o} is a indexed-set that contains the same elements in the same order.
+ */
+ @Override
+ public boolean equals(final Object o) {
+ if (o == this)
+ return true;
+ if (o == null)
+ return false;
+ if (!(o instanceof IndexedSet<?>))
+ return false;
+
+ final IndexedSet<?> other = (IndexedSet<?>)o;
+
+ return equals(other);
+ }
+
+ /**
+ * Compare to another indexed set.
+ *
+ * @param other the target indexed set.
+ *
+ * @throws java.lang.IllegalArgumentException if {@code other} is {@code null}.
+ *
+ * @return {@code true} iff {@other} is not {@code null}, and contains exactly the same elements
+ * (as compared using {@link Object#equals} a this set with matching indices.
+ */
+ public boolean equals(final IndexedSet<?> other) {
+ if (other == null)
+ throw new IllegalArgumentException("other cannot be null");
+ final ArrayList<?> otherElements = other.elements;
+
+ final int elementCount = elements.size();
+ if (otherElements.size() != elementCount)
+ return false;
+ for (int i = 0; i < elementCount; i++)
+ if (!elements.get(i).equals(otherElements.get(i)))
+ return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+
+ for (final E element : elements)
+ result = 31 * result + (element == null ? 0 : element.hashCode());
+ return result;
+ }
+
+ /**
+ * Returns the element given its index within the set.
+ * @param index the target element's index.
+ *
+ * @throws IllegalArgumentException if {@code index} is not valid; in [0,{@link #size()}).
+ *
+ * @return never {@code null}; as null is not a valid element.
+ */
+ public E get(final int index) {
+ checkIndex(index);
+ return elements.get(index);
+ }
+
+ /**
+ * Returns the index of an object.
+ * @param o the object of interest.
+ *
+ * @throws IllegalArgumentException if {@code o} is {@code null}.
+ *
+ * @return {@code -1} if such an object is not an element of this set, otherwise is index in the set thus a
+ * values within [0,{@link #size()}).
+ */
+ public int indexOf(final E o) {
+ if (o == null)
+ throw new IllegalArgumentException("the query object cannot be null");
+ return indexByElement.containsKey(o) ? indexByElement.getInt(o) : -1;
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/LoggingNestedIntegerArray.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/LoggingNestedIntegerArray.java
new file mode 100644
index 0000000..3117852
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/LoggingNestedIntegerArray.java
@@ -0,0 +1,120 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.collections;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.PrintStream;
+
+/**
+ * Wrapper around the basic NestedIntegerArray class that logs all updates (ie., all calls to put())
+ * to the provided output stream. For testing/debugging purposes.
+ *
+ * Log entries are of the following form (fields are tab-separated):
+ * LABEL OPERATION VALUE KEY1 KEY2 ... KEY_N
+ *
+ * A header line is written before the log entries giving the dimensions of this NestedIntegerArray.
+ * It has the form:
+ *
+ * # LABEL SIZE_OF_FIRST_DIMENSION SIZE_OF_SECOND_DIMENSION ... SIZE_OF_NTH_DIMENSION
+ *
+ * @author David Roazen
+ */
+public class LoggingNestedIntegerArray<T> extends NestedIntegerArray<T> {
+
+ private PrintStream log;
+ private String logEntryLabel;
+
+ public static final String HEADER_LINE_PREFIX = "# ";
+ public enum NestedIntegerArrayOperation { GET, PUT };
+
+ /**
+ *
+ * @param log output stream to which to log update operations
+ * @param logEntryLabel String that should be prefixed to each log entry
+ * @param dimensions
+ */
+ public LoggingNestedIntegerArray( PrintStream log, String logEntryLabel, final int... dimensions ) {
+ super(dimensions);
+
+ if ( log == null ) {
+ throw new ReviewedGATKException("Log output stream must not be null");
+ }
+ this.log = log;
+ this.logEntryLabel = logEntryLabel != null ? logEntryLabel : "";
+
+ // Write the header line recording the dimensions of this NestedIntegerArray:
+ StringBuilder logHeaderLine = new StringBuilder();
+
+ logHeaderLine.append(HEADER_LINE_PREFIX);
+ logHeaderLine.append(this.logEntryLabel);
+ for ( int dimension : dimensions ) {
+ logHeaderLine.append("\t");
+ logHeaderLine.append(dimension);
+ }
+
+ this.log.println(logHeaderLine.toString());
+ }
+
+ @Override
+ public T get( final int... keys ) {
+ StringBuilder logEntry = new StringBuilder();
+
+ logEntry.append(logEntryLabel);
+ logEntry.append("\t");
+ logEntry.append(NestedIntegerArrayOperation.GET);
+ logEntry.append("\t"); // empty field for the datum value
+
+ for ( int key : keys ) {
+ logEntry.append("\t");
+ logEntry.append(key);
+ }
+
+ log.println(logEntry.toString());
+
+ return super.get(keys);
+ }
+
+ @Override
+ public boolean put( final T value, final int... keys ) {
+ StringBuilder logEntry = new StringBuilder();
+
+ logEntry.append(logEntryLabel);
+ logEntry.append("\t");
+ logEntry.append(NestedIntegerArrayOperation.PUT);
+ logEntry.append("\t");
+ logEntry.append(value);
+ for ( int key : keys ) {
+ logEntry.append("\t");
+ logEntry.append(key);
+ }
+
+ // PrintStream methods all use synchronized blocks internally, so our logging is thread-safe
+ log.println(logEntry.toString());
+
+ return super.put(value, keys);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/NestedIntegerArray.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/NestedIntegerArray.java
new file mode 100644
index 0000000..02dd15a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/NestedIntegerArray.java
@@ -0,0 +1,221 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.collections;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: ebanks
+ * Date: July 1, 2012
+ */
+
+public class NestedIntegerArray<T> {
+
+ private static Logger logger = Logger.getLogger(NestedIntegerArray.class);
+
+ protected final Object[] data;
+
+ protected final int numDimensions;
+ protected final int[] dimensions;
+
+ // Preallocate the first two dimensions to limit contention during tree traversals in put()
+ private static final int NUM_DIMENSIONS_TO_PREALLOCATE = 2;
+
+ public NestedIntegerArray(final int... dimensions) {
+ numDimensions = dimensions.length;
+ if ( numDimensions == 0 )
+ throw new ReviewedGATKException("There must be at least one dimension to an NestedIntegerArray");
+ this.dimensions = dimensions.clone();
+
+ int dimensionsToPreallocate = Math.min(dimensions.length, NUM_DIMENSIONS_TO_PREALLOCATE);
+
+ if ( logger.isDebugEnabled() ) logger.debug(String.format("Creating NestedIntegerArray with dimensions %s", Arrays.toString(dimensions)));
+ if ( logger.isDebugEnabled() ) logger.debug(String.format("Pre-allocating first %d dimensions", dimensionsToPreallocate));
+
+ data = new Object[dimensions[0]];
+ preallocateArray(data, 0, dimensionsToPreallocate);
+
+ if ( logger.isDebugEnabled() ) logger.debug(String.format("Done pre-allocating first %d dimensions", dimensionsToPreallocate));
+ }
+
+ /**
+ * @return the dimensions of this nested integer array. DO NOT MODIFY
+ */
+ public int[] getDimensions() {
+ return dimensions;
+ }
+
+ /**
+ * Recursively allocate the first dimensionsToPreallocate dimensions of the tree
+ *
+ * Pre-allocating the first few dimensions helps limit contention during tree traversals in put()
+ *
+ * @param subarray current node in the tree
+ * @param dimension current level in the tree
+ * @param dimensionsToPreallocate preallocate only this many dimensions (starting from the first)
+ */
+ private void preallocateArray( Object[] subarray, int dimension, int dimensionsToPreallocate ) {
+ if ( dimension >= dimensionsToPreallocate - 1 ) {
+ return;
+ }
+
+ for ( int i = 0; i < subarray.length; i++ ) {
+ subarray[i] = new Object[dimensions[dimension + 1]];
+ preallocateArray((Object[])subarray[i], dimension + 1, dimensionsToPreallocate);
+ }
+ }
+
+ public T get(final int... keys) {
+ final int numNestedDimensions = numDimensions - 1;
+ Object[] myData = data;
+
+ for( int i = 0; i < numNestedDimensions; i++ ) {
+ if ( keys[i] >= dimensions[i] )
+ return null;
+
+ myData = (Object[])myData[keys[i]];
+ if ( myData == null )
+ return null;
+ }
+
+ return (T)myData[keys[numNestedDimensions]];
+ }
+
+ /**
+ * Insert a value at the position specified by the given keys.
+ *
+ * This method is thread-safe, however the caller MUST check the
+ * return value to see if the put succeeded. This method RETURNS FALSE if
+ * the value could not be inserted because there already was a value present
+ * at the specified location. In this case the caller should do a get() to get
+ * the already-existing value and (potentially) update it.
+ *
+ * @param value value to insert
+ * @param keys keys specifying the location of the value in the tree
+ * @return true if the value was inserted, false if it could not be inserted because there was already
+ * a value at the specified position
+ */
+ public boolean put(final T value, final int... keys) { // WARNING! value comes before the keys!
+ if ( keys.length != numDimensions )
+ throw new ReviewedGATKException("Exactly " + numDimensions + " keys should be passed to this NestedIntegerArray but " + keys.length + " were provided");
+
+ final int numNestedDimensions = numDimensions - 1;
+ Object[] myData = data;
+ for ( int i = 0; i < numNestedDimensions; i++ ) {
+ if ( keys[i] >= dimensions[i] )
+ throw new ReviewedGATKException("Key " + keys[i] + " is too large for dimension " + i + " (max is " + (dimensions[i]-1) + ")");
+
+ // If we're at or beyond the last dimension that was pre-allocated, we need to do a synchronized
+ // check to see if the next branch exists, and if it doesn't, create it
+ if ( i >= NUM_DIMENSIONS_TO_PREALLOCATE - 1 ) {
+ synchronized ( myData ) {
+ if ( myData[keys[i]] == null ) {
+ myData[keys[i]] = new Object[dimensions[i + 1]];
+ }
+ }
+ }
+
+ myData = (Object[])myData[keys[i]];
+ }
+
+ synchronized ( myData ) { // lock the bottom row while we examine and (potentially) update it
+
+ // Insert the new value only if there still isn't any existing value in this position
+ if ( myData[keys[numNestedDimensions]] == null ) {
+ myData[keys[numNestedDimensions]] = value;
+ }
+ else {
+ // Already have a value for this leaf (perhaps another thread came along and inserted one
+ // while we traversed the tree), so return false to notify the caller that we didn't put
+ // the item
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public List<T> getAllValues() {
+ final List<T> result = new ArrayList<T>();
+ fillAllValues(data, result);
+ return result;
+ }
+
+ private void fillAllValues(final Object[] array, final List<T> result) {
+ for ( Object value : array ) {
+ if ( value == null )
+ continue;
+ if ( value instanceof Object[] )
+ fillAllValues((Object[])value, result);
+ else
+ result.add((T)value);
+ }
+ }
+
+ public static class Leaf<T> {
+ public final int[] keys;
+ public final T value;
+
+ public Leaf(final int[] keys, final T value) {
+ this.keys = keys;
+ this.value = value;
+ }
+ }
+
+ public List<Leaf<T>> getAllLeaves() {
+ final List<Leaf<T>> result = new ArrayList<Leaf<T>>();
+ fillAllLeaves(data, new int[0], result);
+ return result;
+ }
+
+ private void fillAllLeaves(final Object[] array, final int[] path, final List<Leaf<T>> result) {
+ for ( int key = 0; key < array.length; key++ ) {
+ final Object value = array[key];
+ if ( value == null )
+ continue;
+ final int[] newPath = appendToPath(path, key);
+ if ( value instanceof Object[] ) {
+ fillAllLeaves((Object[]) value, newPath, result);
+ } else {
+ result.add(new Leaf<T>(newPath, (T)value));
+ }
+ }
+ }
+
+ private int[] appendToPath(final int[] path, final int newKey) {
+ final int[] newPath = new int[path.length + 1];
+ for ( int i = 0; i < path.length; i++ )
+ newPath[i] = path[i];
+ newPath[path.length] = newKey;
+ return newPath;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/Pair.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/Pair.java
new file mode 100644
index 0000000..b09c9df
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/Pair.java
@@ -0,0 +1,93 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.collections;
+
+
+public class Pair<X,Y> {
+ // declare public, STL-style for easier and more efficient access:
+ public X first;
+ public Y second;
+
+ public Pair(X x, Y y) { first = x; second = y; }
+
+ public void set(X x, Y y) { first = x; second = y; }
+
+ /** Java-style getter; note that we currently allow direct access to
+ the member field.
+ */
+ public X getFirst() { return first; }
+
+ /** Java-style getter; note that we currently allow direct access to
+ the member field.
+ */
+ public Y getSecond() { return second; }
+
+ /**
+ * Calculate whether this pair object is equal to another object.
+ * @param o The other object (hopefully a pair).
+ * @return True if the two are equal; false otherwise.
+ */
+ @Override
+ public boolean equals( Object o ) {
+ if( o == null )
+ return false;
+ if( !(o instanceof Pair) )
+ return false;
+
+ Pair other = (Pair)o;
+
+ // Check to see whether one is null but not the other.
+ if( this.first == null && other.first != null ) return false;
+ if( this.second == null && other.second != null ) return false;
+
+ // Check to see whether the values are equal.
+ // If the param of equals is null, it should by contract return false.
+ if( this.first != null && !this.first.equals(other.first) ) return false;
+ if( this.second != null && !this.second.equals(other.second) ) return false;
+
+ return true;
+ }
+
+ /**
+ * Basic hashcode function. Assume hashcodes of first and second are
+ * randomly distributed and return the XOR of the two.
+ * @return Randomly distributed hashcode of the pair.
+ */
+ @Override
+ public int hashCode() {
+ if( second == null && first == null )
+ return 0;
+ if( second == null )
+ return first.hashCode();
+ if( first == null )
+ return second.hashCode();
+ return first.hashCode() ^ second.hashCode();
+ }
+
+ public String toString() {
+ return first+","+second;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/Permutation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/Permutation.java
new file mode 100644
index 0000000..53eafe7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/Permutation.java
@@ -0,0 +1,103 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.collections;
+
+import java.util.List;
+
+/**
+ * Represent a permutation of a ordered set or list of elements.
+ *
+ * @author Valentin Ruano-Rubio <valentin at broadinstitute.org>
+ */
+public interface Permutation<E> {
+
+ /**
+ * Checks whether this permutation is a partial one of the original list.
+ *
+ * <p>
+ * A partial permutation is one in that no all original elements take part of.
+ * </p>
+ *
+ * @return {@code true} iff this is a partial permutation.
+ */
+ public boolean isPartial();
+
+ /**
+ * Checks whether this is a trivial permutation where the resulting element list is the same as original.
+ *
+ * @return {@code true} iff the resulting element list is the same as the original.
+ */
+ public boolean isNonPermuted();
+
+ /**
+ * Given an index on the original list, returns the position of tha element in the resulting list.
+ *
+ * @param fromIndex the query original element index.
+ *
+ * @throws IllegalArgumentException if {@code fromIndex} is not a valid index within the original list.
+ *
+ * @return -1 if that element is not part of the result (partial) permutation, otherwise some number between
+ * 0 and {@link #toSize()} - 1.
+ */
+ public int toIndex(final int fromIndex);
+
+ /**
+ * Given an index on the resulting list, it gives you the index of that element on the original list.
+ * @param toIndex the query resulting list index.
+ *
+ * @throws IllegalArgumentException if {@code toIndex} is not a valid index, i.e. in [0,{@link #toSize()}-1).
+ *
+ * @return a value between 0 and {@link #fromSize()} - 1.
+ */
+ public int fromIndex(final int toIndex);
+
+ /**
+ * Length of the original element list.
+ *
+ * @return 0 or greater.
+ */
+ public int fromSize();
+
+ /**
+ * Length of the resulting element list.
+ *
+ * @return 0 or greater.
+ */
+ public int toSize();
+
+ /**
+ * Returns an unmodifiable view to the original element list.
+ * @return never {@code null}.
+ */
+ public List<E> fromList();
+
+ /**
+ * Returns an unmodifiable view to the original element list.
+ *
+ * @return never {@code null}.
+ */
+ public List<E> toList();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/PrimitivePair.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/PrimitivePair.java
new file mode 100644
index 0000000..2b759ce
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/PrimitivePair.java
@@ -0,0 +1,200 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.collections;
+
+
+/** This class is used to group together multiple Pair classes for
+ * primitive types (thanks to generics shortcomings, these implementations
+ * are more efficient then generic ones). This class contains no methods and
+ * no fields, but only declarations of inner classes.
+ */
+
+public class PrimitivePair {
+
+ /** Pair of two integers */
+ public static class Int {
+ // declare public, STL-style for easier and more efficient access:
+ public int first;
+ public int second;
+
+ public Int(int x, int y) { first = x; second = y; }
+ public Int() { first = second = 0; }
+
+ public void set(int x, int y) { first = x; second = y; }
+
+ /** Java-style getter; note that we currently allow direct access to
+ the member field.
+ */
+ public int getFirst() { return first; }
+
+ /** Java-style getter; note that we currently allow direct access to
+ the member field.
+ */
+ public int getSecond() { return second; }
+
+ /** Increments the elements of this pair by the
+ * corresponding elements of the pair <code>p</code> and returns this
+ * pair (modified). This method does not allocate a new pair, but changes
+ * in place the values stored in the object the method is invoked from. The
+ * method is unsafe: if p is null, a runtime exception will be thrown.
+ * @param p
+ * @return
+ */
+ public PrimitivePair.Int add(PrimitivePair.Int p) {
+ first += p.first;
+ second += p.second;
+ return this;
+ }
+
+ /** Decrements the elements of this pair by the
+ * corresponding elements of the pair <code>p</code> and returns this
+ * pair (modified). This method does not allocate a new pair, but changes
+ * in place the values stored in the object the method is invoked from. The
+ * method is unsafe: if p is null, a runtime exception will be thrown.
+ * @param p
+ * @return
+ */
+ public PrimitivePair.Int subtract(PrimitivePair.Int p) {
+ first -= p.first;
+ second -= p.second;
+ return this;
+ }
+
+ /** Copies values from the argument <code>p</code> into the corresponding
+ * elements of this pair and returns this pair (modified).
+ * @param p
+ * @return
+ */
+ public PrimitivePair.Int assignFrom(PrimitivePair.Int p ) {
+ first = p.first;
+ second = p.second;
+ return this;
+ }
+
+
+ }
+
+ public static class Long {
+ // declare public, STL-style for easier and more efficient access:
+ public long first;
+ public long second;
+
+ public Long(long x, long y) { first = x; second = y; }
+ public Long() { first = second = 0; }
+
+ public void set(long x, long y) { first = x; second = y; }
+
+ /** Java-style getter; note that we currently allow direct access to
+ the member field.
+ */
+ public long getFirst() { return first; }
+
+ /** Java-style getter; note that we currently allow direct access to
+ the member field.
+ */
+ public long getSecond() { return second; }
+
+ /** Increments the elements of this pair by the
+ * corresponding elements of the pair <code>p</code> and returns this
+ * pair (modified). This method does not allocate a new pair, but changes
+ * in place the values stored in the object the method is invoked from. The
+ * method is unsafe: if p is null, a runtime exception will be thrown.
+ * @param p
+ * @return
+ */
+ public PrimitivePair.Long add(PrimitivePair.Int p) {
+ first += p.first;
+ second += p.second;
+ return this;
+ }
+
+ /** Increments the elements of this pair by the
+ * corresponding elements of the pair <code>p</code> and returns this
+ * pair (modified). This method does not allocate a new pair, but changes
+ * in place the values stored in the object the method is invoked from. The
+ * method is unsafe: if p is null, a runtime exception will be thrown.
+ * @param p
+ * @return
+ */
+ public PrimitivePair.Long add(PrimitivePair.Long p) {
+ first += p.first;
+ second += p.second;
+ return this;
+ }
+
+ /** Decrements the elements of this pair by the
+ * corresponding elements of the pair <code>p</code> and returns this
+ * pair (modified). This method does not allocate a new pair, but changes
+ * in place the values stored in the object the method is invoked from. The
+ * method is unsafe: if p is null, a runtime exception will be thrown.
+ * @param p
+ * @return
+ */
+ public PrimitivePair.Long subtract(PrimitivePair.Int p) {
+ first -= p.first;
+ second -= p.second;
+ return this;
+ }
+
+ /** Decrements the elements of this pair by the
+ * corresponding elements of the pair <code>p</code> and returns this
+ * pair (modified). This method does not allocate a new pair, but changes
+ * in place the values stored in the object the method is invoked from. The
+ * method is unsafe: if p is null, a runtime exception will be thrown.
+ * @param p
+ * @return
+ */
+ public PrimitivePair.Long subtract(PrimitivePair.Long p) {
+ first -= p.first;
+ second -= p.second;
+ return this;
+ }
+
+ /** Copies values from the argument <code>p</code> into the corresponding
+ * elements of this pair and returns this pair (modified).
+ * @param p
+ * @return
+ */
+ public PrimitivePair.Long assignFrom(PrimitivePair.Long p ) {
+ first = p.first;
+ second = p.second;
+ return this;
+ }
+
+ /** Copies values from the argument <code>p</code> into the corresponding
+ * elements of this pair and returns this pair (modified).
+ * @param p
+ * @return
+ */
+ public PrimitivePair.Long assignFrom(PrimitivePair.Int p ) {
+ first = p.first;
+ second = p.second;
+ return this;
+ }
+
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/RODMergingIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/RODMergingIterator.java
new file mode 100644
index 0000000..7af62bd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/collections/RODMergingIterator.java
@@ -0,0 +1,160 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.collections;
+
+import org.broadinstitute.gatk.engine.refdata.utils.LocationAwareSeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.PriorityQueue;
+
+public class RODMergingIterator implements Iterator<RODRecordList>, Iterable<RODRecordList> {
+ PriorityQueue<Element> queue = new PriorityQueue<Element>();
+
+ private class Element implements Comparable<Element> {
+ public LocationAwareSeekableRODIterator it = null;
+ public GenomeLoc nextLoc = null;
+
+ public Element(Iterator<RODRecordList> it) {
+ if ( it instanceof LocationAwareSeekableRODIterator) {
+ this.it = (LocationAwareSeekableRODIterator)it;
+ if ( ! it.hasNext() ) throw new ReviewedGATKException("Iterator is empty");
+ update();
+ } else {
+ throw new ReviewedGATKException("Iterator passed to RODMergingIterator is not LocationAwareSeekableRODIterator");
+ }
+ }
+
+ public Element update() {
+ // E prev = value;
+ nextLoc = it.peekNextLocation(); // will return null if there is no next location
+ return this;
+ }
+
+ public int compareTo(Element other) {
+ if ( nextLoc == null ) {
+ if ( other.nextLoc != null ) return 1; // null means no more data available, so its after any non-null position
+ return 0;
+ }
+ if ( other.nextLoc == null ) return -1; // we can get to this point only if this.nextLoc != null
+
+ return nextLoc.compareTo(other.nextLoc);
+ }
+
+ public RODRecordList next() {
+ RODRecordList value = it.next();
+ update();
+ return value;
+ }
+ }
+
+ public Iterator<RODRecordList> iterator() {
+ return this;
+ }
+
+ public RODMergingIterator() {
+ ;
+ }
+
+ public RODMergingIterator(Iterator<RODRecordList> it) {
+ add(it);
+ }
+
+ public RODMergingIterator(Collection<Iterator<RODRecordList>> its) {
+ for ( Iterator<RODRecordList> it : its ) {
+ add(it);
+ }
+ }
+
+ /** If the iterator is non-empty (hasNext() is true), put it into the queue. The next location the iterator
+ * will be after a call to next() is peeked into and cached as queue's priority value.
+ * @param it
+ */
+ public void add(Iterator<RODRecordList> it) {
+ if ( it.hasNext() )
+ queue.add(new Element(it));
+ }
+
+ public boolean hasNext() {
+ return ! queue.isEmpty();
+ }
+
+ public RODRecordList next() {
+ Element e = queue.poll();
+ RODRecordList value = e.next(); // next() will also update next location cached by the Element
+
+ if ( e.nextLoc != null ) // we have more data in the track
+ queue.add(e); // add the element back to queue (note: its next location, on which priority is based, was updated
+
+ //System.out.printf("Element is %s%n", e.value);
+ return value;
+ }
+
+ /** Peeks into the genomic location of the record this iterator will return next.
+ *
+ * @return
+ */
+ public GenomeLoc peekLocation() {
+ return queue.peek().nextLoc;
+ }
+
+ public Collection<RODRecordList> allElementsLTE(RODRecordList elt) {
+ return allElementsLTE(elt, true);
+ }
+
+ public Collection<RODRecordList> allElementsLTE(RODRecordList elt, boolean includeElt) {
+ LinkedList<RODRecordList> all = new LinkedList<RODRecordList>();
+
+ if ( includeElt ) all.add(elt);
+
+ while ( hasNext() ) {
+ Element x = queue.peek();
+ //System.out.printf("elt.compareTo(x) == %d%n", elt.compareTo(x));
+ //System.out.printf("In allElementLTE%n");
+ int cmp = elt.getLocation().compareTo(x.nextLoc);
+ //System.out.printf("x=%s%n elt=%s%n => elt.compareTo(x) == %d%n", x, elt, cmp);
+ if ( cmp >= 0 ) {
+ //System.out.printf(" Adding element x=%s, size = %d%n", x, all.size());
+ all.add(next());
+ //System.out.printf(" Added size = %d%n", all.size());
+ }
+ else {
+ //System.out.printf("breaking...%n");
+ break;
+ }
+ }
+
+ return all;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Advanced.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Advanced.java
new file mode 100644
index 0000000..3995ff7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Advanced.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.lang.annotation.*;
+
+/**
+ * Indicates that a walker argument should is considered an advanced option.
+ *
+ * @author Mark DePristo
+ * @version 0.1
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE,ElementType.FIELD})
+public @interface Advanced {
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Argument.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Argument.java
new file mode 100644
index 0000000..66c5629
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Argument.java
@@ -0,0 +1,125 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.lang.annotation.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: hanna
+ * Date: Mar 24, 2009
+ * Time: 11:11:36 AM
+ */
+/**
+ * Annotates fields in objects that should be used as command-line arguments.
+ * Any field annotated with @Argument can appear as a command-line parameter.
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.FIELD)
+public @interface Argument {
+ /**
+ * The full name of the command-line argument. Full names should be
+ * prefixed on the command-line with a double dash (--).
+ * @return Selected full name, or "" to use the default.
+ */
+ String fullName() default "";
+
+ /**
+ * Specified short name of the command. Short names should be prefixed
+ * with a single dash. Argument values can directly abut single-char
+ * short names or be separated from them by a space.
+ * @return Selected short name, or "" for none.
+ */
+ String shortName() default "";
+
+ /**
+ * Documentation for the command-line argument. Should appear when the
+ * --help argument is specified.
+ * @return Doc string associated with this command-line argument.
+ */
+ String doc() default "Undocumented option";
+
+ /**
+ * Is this argument required. If true, the command-line argument system will
+ * make a best guess for populating this argument based on the type descriptor,
+ * and will fail if the type can't be populated.
+ * @return True if the argument is required. False otherwise.
+ */
+ boolean required() default true;
+
+ /**
+ * Should this command-line argument be exclusive of others. Should be
+ * a comma-separated list of names of arguments of which this should be
+ * independent.
+ * @return A comma-separated string listing other arguments of which this
+ * argument should be independent.
+ */
+ String exclusiveOf() default "";
+
+ /**
+ * Provide a regexp-based validation string.
+ * @return Non-empty regexp for validation, blank otherwise.
+ */
+ String validation() default "";
+
+ /**
+ * Hard lower bound on the allowed value for the annotated argument -- generates an exception if violated.
+ * Enforced only for numeric types whose values are explicitly specified on the command line.
+ *
+ * @return Hard lower bound on the allowed value for the annotated argument, or Double.NEGATIVE_INFINITY
+ * if there is none.
+ */
+ double minValue() default Double.NEGATIVE_INFINITY;
+
+ /**
+ * Hard upper bound on the allowed value for the annotated argument -- generates an exception if violated.
+ * Enforced only for numeric types whose values are explicitly specified on the command line.
+ *
+ * @return Hard upper bound on the allowed value for the annotated argument, or Double.POSITIVE_INFINITY
+ * if there is none.
+ */
+ double maxValue() default Double.POSITIVE_INFINITY;
+
+ /**
+ * Soft lower bound on the allowed value for the annotated argument -- generates a warning if violated.
+ * Enforced only for numeric types whose values are explicitly specified on the command line.
+ *
+ * @return Soft lower bound on the allowed value for the annotated argument, or Double.NEGATIVE_INFINITY
+ * if there is none.
+ */
+ double minRecommendedValue() default Double.NEGATIVE_INFINITY;
+
+ /**
+ * Soft upper bound on the allowed value for the annotated argument -- generates a warning if violated.
+ * Enforced only for numeric types whose values are explicitly specified on the command line.
+ *
+ * @return Soft upper bound on the allowed value for the annotated argument, or Double.POSITIVE_INFINITY
+ * if there is none.
+ */
+ double maxRecommendedValue() default Double.POSITIVE_INFINITY;
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentCollection.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentCollection.java
new file mode 100644
index 0000000..c142f06
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentCollection.java
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.lang.annotation.*;
+
+/**
+ * @author aaron
+ * @version 1.0
+ * @date May 8, 2009
+ * <p/>
+ * @interface ArgumentCollection
+ * <p/>
+ * This object represents an class, that is a collection of arguments.
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.FIELD})
+public @interface ArgumentCollection {
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentDefinition.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentDefinition.java
new file mode 100644
index 0000000..f2e7e6e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentDefinition.java
@@ -0,0 +1,297 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+
+/**
+ * A specific argument definition. Maps one-to-one with a field in some class.
+ */
+public class ArgumentDefinition {
+ /**
+ * Whether an argument is an input or an output.
+ */
+ public final ArgumentIOType ioType;
+
+ /**
+ * The class of the argument.
+ */
+ public final Class argumentType;
+
+ /**
+ * Full name of the argument. Must have a value.
+ */
+ public final String fullName;
+
+ /**
+ * Short name of the argument. Can be null.
+ */
+ public final String shortName;
+
+ /**
+ * Doc string for the argument. Displayed in help.
+ */
+ public final String doc;
+
+ /**
+ * Must this argument be specified on the command-line? Note that there's a
+ * critical difference between the meaning of a required argument from the
+ * perspective of the argument source and the perspective of the argument
+ * definition: the argument source's required field indicates that the field
+ * should somehow be populated by the GATK (and fail if there's an error).
+ * The ArgumentDefinition required element means that the required element
+ * must be specified on the command-line.
+ */
+ public final boolean required;
+
+ /**
+ * Is this argument a flag? Users can't specify a value for a flag.
+ */
+ public final boolean isFlag;
+
+ /**
+ * Does this argument support multiple values (repeated "-arg value1 -arg value2"-style structures).
+ */
+ public final boolean isMultiValued;
+
+ /**
+ * The class of the componentType. Not used for scalars.
+ */
+ public final Class componentType;
+
+ /**
+ * Is this argument hidden from the help system?
+ */
+ public final boolean isHidden;
+
+ /**
+ * Is this argument exclusive of other arguments?
+ */
+ public final String exclusiveOf;
+
+ /**
+ * Can we validate this regular expression?
+ */
+ public final String validation;
+
+ /**
+ * A list of valid options for this argument, if there is a compelling subset.
+ */
+ public final List<String> validOptions;
+
+ /**
+ * Creates a new argument definition.
+ * @param ioType Whether the argument is an input or an output.
+ * @param argumentType The class of the field.
+ * @param fullName Full name for this argument definition.
+ * @param shortName Short name for this argument definition.
+ * @param doc Doc string for this argument.
+ * @param required Whether or not this argument is required.
+ * @param isFlag Whether or not this argument should be treated as a flag.
+ * @param isMultiValued Whether or not this argument supports multiple values.
+ * @param isHidden Whether or not this argument should be hidden from the command-line argument system.
+ * @param componentType For multivalued arguments the type of the components.
+ * @param exclusiveOf Whether this command line argument is mutually exclusive of other arguments.
+ * @param validation A regular expression for command-line argument validation.
+ * @param validOptions is there a particular list of options that's valid for this argument definition? List them if so, otherwise set this to null.
+ */
+ public ArgumentDefinition( ArgumentIOType ioType,
+ Class argumentType,
+ String fullName,
+ String shortName,
+ String doc,
+ boolean required,
+ boolean isFlag,
+ boolean isMultiValued,
+ boolean isHidden,
+ Class componentType,
+ String exclusiveOf,
+ String validation,
+ List<String> validOptions) {
+ this.ioType = ioType;
+ this.argumentType = argumentType;
+ this.fullName = fullName;
+ this.shortName = shortName;
+ this.doc = doc;
+ this.required = required;
+ this.isFlag = isFlag;
+ this.isMultiValued = isMultiValued;
+ this.isHidden = isHidden;
+ this.componentType = componentType;
+ this.exclusiveOf = exclusiveOf;
+ this.validation = validation;
+ this.validOptions = validOptions;
+
+ validateName(shortName);
+ validateName(fullName);
+ }
+
+ /**
+ * Creates a new argument definition.
+ * @param annotation The annotation on the field.
+ * @param argumentType The class of the field.
+ * @param defaultFullName Default full name for this argument definition.
+ * @param defaultShortName Default short name for this argument definition.
+ * @param isFlag Whether or not this argument should be treated as a flag.
+ * @param isMultiValued Whether or not this argument supports multiple values.
+ * @param componentType For multivalued arguments the type of the components.
+ * @param isHidden Whether or not this argument should be hidden from the command-line argument system.
+ * @param validOptions is there a particular list of options that's valid for this argument definition? List them if so, otherwise set this to null.
+ */
+ public ArgumentDefinition( Annotation annotation,
+ ArgumentIOType ioType,
+ Class argumentType,
+ String defaultFullName,
+ String defaultShortName,
+ String doc,
+ boolean isRequired,
+ boolean isFlag,
+ boolean isMultiValued,
+ boolean isHidden,
+ Class componentType,
+ String exclusiveOf,
+ String validation,
+ List<String> validOptions) {
+
+ String fullName = (String)CommandLineUtils.getValue(annotation, "fullName");
+ String shortName = (String)CommandLineUtils.getValue(annotation, "shortName");
+ boolean isFullNameProvided = fullName.trim().length() > 0;
+ boolean isShortNameProvided = shortName.trim().length() > 0;
+
+ fullName = isFullNameProvided ? fullName.trim() : defaultFullName;
+
+ // If the short name is provided, use that. If the user hasn't provided any names at all, use
+ // the default. If somewhere in the middle, leave the short name blank.
+ if( isShortNameProvided )
+ shortName = shortName.trim();
+ else if( !isFullNameProvided )
+ shortName = defaultShortName;
+ else
+ shortName = null;
+
+ validateName(shortName);
+ validateName(fullName);
+
+ this.ioType = ioType;
+ this.argumentType = argumentType;
+ this.fullName = fullName;
+ this.shortName = shortName;
+ this.doc = doc;
+ this.required = isRequired;
+ this.isFlag = isFlag;
+ this.isMultiValued = isMultiValued;
+ this.isHidden = isHidden;
+ this.componentType = componentType;
+ this.exclusiveOf = exclusiveOf;
+ this.validation = validation;
+ this.validOptions = validOptions;
+ }
+
+ @Override
+ public int hashCode() {
+ int hashCode = fullName.hashCode();
+ if(shortName != null) hashCode ^= shortName.hashCode();
+ return hashCode;
+ }
+
+ public boolean equals( Object o ) {
+ if( o == null )
+ return false;
+ if( !(o instanceof ArgumentDefinition) )
+ return false;
+
+ ArgumentDefinition other = (ArgumentDefinition)o;
+
+ return Utils.equals(fullName,other.fullName) &&
+ Utils.equals(shortName,other.shortName);
+ }
+
+ /**
+ * Retrieves the full name of the argument, specifiable with the '--' prefix. The full name can be
+ * either specified explicitly with the fullName annotation parameter or implied by the field name.
+ * @param annotation Original field annotation.
+ * @param fieldName Original field name.
+ * @return full name of the argument. Never null.
+ */
+ public static String getFullName( Annotation annotation, String fieldName ) {
+ String fullName = (String)CommandLineUtils.getValue(annotation, "fullName");
+ return fullName.trim().length() > 0 ? fullName.trim() : fieldName.toLowerCase();
+ }
+
+ /**
+ * Retrieves the short name of the argument, specifiable with the '-' prefix. The short name can
+ * be specified or not; if left unspecified, no short name will be present.
+ * @param annotation Original field annotation.
+ * @return short name of the argument. Null if no short name exists.
+ */
+ public static String getShortName( Annotation annotation ) {
+ String shortName = (String)CommandLineUtils.getValue(annotation, "shortName");
+ return shortName.trim().length() > 0 ? shortName.trim() : null;
+ }
+
+ /**
+ * Documentation for this argument. Mandatory field.
+ * @param annotation Original field annotation.
+ * @return Documentation for this argument.
+ */
+ public static String getDoc( Annotation annotation ) {
+ return (String)CommandLineUtils.getValue(annotation, "doc");
+ }
+
+ /**
+ * Specifies other arguments which cannot be used in conjunction with this argument. Comma-separated list.
+ * @param annotation Original field annotation.
+ * @return A comma-separated list of exclusive arguments, or null if none are present.
+ */
+ public static String getExclusiveOf( Annotation annotation ) {
+ String exclusiveOf = (String)CommandLineUtils.getValue(annotation, "exclusiveOf");
+ return exclusiveOf.trim().length() > 0 ? exclusiveOf.trim() : null;
+ }
+
+ /**
+ * A regular expression which can be used for validation.
+ * @param annotation Original field annotation.
+ * @return a JVM regex-compatible regular expression, or null to permit any possible value.
+ */
+ public static String getValidationRegex( Annotation annotation ) {
+ String validation = (String)CommandLineUtils.getValue(annotation, "validation");
+ return validation.trim().length() > 0 ? validation.trim() : null;
+ }
+
+ /**
+ * Make sure the argument's name is valid
+ *
+ * @param name
+ */
+ private void validateName(final String name) {
+ if ( name != null && name.startsWith("-") )
+ throw new ReviewedGATKException("Invalid argument definition: " + name + " begins with a -");
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentDefinitionGroup.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentDefinitionGroup.java
new file mode 100644
index 0000000..b6bb16c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentDefinitionGroup.java
@@ -0,0 +1,99 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A group of argument definitions.
+ */
+public class ArgumentDefinitionGroup implements Iterable<ArgumentDefinition> {
+ /**
+ * Name of this group.
+ */
+ public final String groupName;
+
+ /**
+ * The argument definitions associated with this group.
+ */
+ public final List<ArgumentDefinition> argumentDefinitions;
+
+ public ArgumentDefinitionGroup( String groupName, List<ArgumentDefinition> argumentDefinitions ) {
+ this.groupName = groupName;
+ this.argumentDefinitions = Collections.unmodifiableList( argumentDefinitions );
+ }
+
+ /**
+ * Does the name of this argument group match the name of another?
+ */
+ public boolean groupNameMatches( ArgumentDefinitionGroup other ) {
+ if( this.groupName == null )
+ return other.groupName == null;
+ return this.groupName.equals(other.groupName);
+ }
+
+ /**
+ * Merges another argument group into this argument group. Return a new
+ * group since argument groups are supposed to be immutable. Asserts that
+ * both argument groups have the same name.
+ */
+ public ArgumentDefinitionGroup merge( ArgumentDefinitionGroup other ) {
+ if( !groupNameMatches(other) )
+ throw new ReviewedGATKException("Unable to merge two argument groups with differing names.");
+
+ // Create a merged definition group.
+ List<ArgumentDefinition> mergedDefinitions = new ArrayList<ArgumentDefinition>();
+ mergedDefinitions.addAll(this.argumentDefinitions);
+ mergedDefinitions.addAll(other.argumentDefinitions);
+
+ return new ArgumentDefinitionGroup(groupName,mergedDefinitions);
+ }
+
+ /**
+ * Iterate over the arguments in an argument definition group.
+ * @return
+ */
+ public Iterator<ArgumentDefinition> iterator() {
+ return argumentDefinitions.iterator();
+ }
+
+ /**
+ * Reports whether all the arguments in this group are hidden.
+ * @return True if all are hidden, false if some or none are hidden.
+ */
+ public boolean allHidden() {
+ for(ArgumentDefinition argumentDefinition: argumentDefinitions) {
+ if(!argumentDefinition.isHidden)
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentDefinitions.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentDefinitions.java
new file mode 100644
index 0000000..8bc17d7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentDefinitions.java
@@ -0,0 +1,195 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * A collection of argument definitions.
+ */
+public class ArgumentDefinitions implements Iterable<ArgumentDefinition> {
+ /**
+ * Backing data set of argument stored by short name and long name.
+ */
+ private Set<ArgumentDefinition> argumentDefinitions = new HashSet<ArgumentDefinition>();
+
+ /**
+ * The groupings of argument definitions. Used mainly for help output.
+ */
+ private Set<ArgumentDefinitionGroup> argumentDefinitionGroups = new HashSet<ArgumentDefinitionGroup>();
+
+ /**
+ * Adds an argument to the this argument definition list.
+ * @param argumentDefinitionGroup The group of arguments to add.
+ */
+ public void add( ArgumentDefinitionGroup argumentDefinitionGroup ) {
+ for( ArgumentDefinition definition: argumentDefinitionGroup ) {
+ // Do some basic validation before adding the definition.
+ if( definition.fullName.length() == 0 )
+ throw new IllegalArgumentException( "Argument cannot have 0-length fullname." );
+ if( hasArgumentDefinition( definition.fullName, FullNameDefinitionMatcher ) )
+ throw new ReviewedGATKException("Duplicate definition of argument with full name: " + definition.fullName);
+ if( definition.shortName != null && hasArgumentDefinition( definition.shortName, ShortNameDefinitionMatcher ) )
+ throw new ReviewedGATKException("Duplicate definition of argument with short name: " + definition.shortName);
+
+ argumentDefinitions.add( definition );
+ }
+
+ // Find an existing argument definition group with this name.
+ // If one exists, merge this group into the other.
+ Iterator<ArgumentDefinitionGroup> definitionGroupIterator = argumentDefinitionGroups.iterator();
+ while( definitionGroupIterator.hasNext() ) {
+ ArgumentDefinitionGroup candidate = definitionGroupIterator.next();
+ if( candidate.groupNameMatches(argumentDefinitionGroup) ) {
+ argumentDefinitionGroup = candidate.merge(argumentDefinitionGroup);
+ definitionGroupIterator.remove();
+ }
+ }
+
+ // Otherwise, add the new group.
+ argumentDefinitionGroups.add( argumentDefinitionGroup );
+ }
+
+ /**
+ * Are there any argument definitions matching the given property?
+ * @param property Property to find.
+ * @param matcher Method of matching a given property.
+ * @return True if one or multiple argument definitions match; false otherwise.
+ */
+ public boolean hasArgumentDefinition( Object property, DefinitionMatcher matcher ) {
+ return findArgumentDefinitions( property, matcher ).size() > 0;
+ }
+
+ /**
+ * Find the given definition matching this property.
+ * @param property Property to find.
+ * @param matcher Method of matching a given property.
+ * @return The ArgumentDefinition matching the given property. Null if none matches.
+ * @throws IllegalArgumentException if multiple arguments match this definition.
+ */
+ public ArgumentDefinition findArgumentDefinition( Object property, DefinitionMatcher matcher ) {
+ Collection<ArgumentDefinition> selectedDefinitions = findArgumentDefinitions( property, matcher );
+ if( selectedDefinitions.size() > 1 )
+ throw new IllegalArgumentException("Multiple argument definitions match the selected property: " + property);
+
+ if( selectedDefinitions.size() == 0 )
+ return null;
+
+ return selectedDefinitions.iterator().next();
+ }
+
+ /**
+ * Find all argument definitions matching a certain category.
+ * @param property Property to inspect.
+ * @param matcher Test to see whether property matches.
+ * @return All argument definitions matching a certain object.
+ */
+ public Collection<ArgumentDefinition> findArgumentDefinitions( Object property, DefinitionMatcher matcher ) {
+ Set<ArgumentDefinition> selectedArgumentDefinitions = new HashSet<ArgumentDefinition>();
+ for( ArgumentDefinition argumentDefinition: argumentDefinitions ) {
+ if( matcher.matches( argumentDefinition, property ) )
+ selectedArgumentDefinitions.add( argumentDefinition );
+ }
+ return selectedArgumentDefinitions;
+ }
+
+ /**
+ * Return a list of the available argument groups.
+ * @return All the argument groups that have been added.
+ */
+ public Collection<ArgumentDefinitionGroup> getArgumentDefinitionGroups() {
+ return argumentDefinitionGroups;
+ }
+
+ /**
+ * Iterates through all command-line arguments.
+ * @return an iterator over command-line arguments.
+ */
+ public Iterator<ArgumentDefinition> iterator() {
+ return argumentDefinitions.iterator();
+ }
+
+ /**
+ * Match the full name of a definition.
+ */
+ static DefinitionMatcher FullNameDefinitionMatcher = new DefinitionMatcher() {
+ public boolean matches( ArgumentDefinition definition, Object key ) {
+ if( definition.fullName == null )
+ return key == null;
+ else
+ return definition.fullName.equals( key );
+ }
+ };
+
+ /**
+ * Match the short name of a definition.
+ */
+ static DefinitionMatcher ShortNameDefinitionMatcher = new DefinitionMatcher() {
+ public boolean matches( ArgumentDefinition definition, Object key ) {
+ if( definition.shortName == null )
+ return key == null;
+ else
+ return definition.shortName.equals( key );
+ }
+ };
+
+ /**
+ * Find all required definitions.
+ */
+ static DefinitionMatcher RequiredDefinitionMatcher = new DefinitionMatcher() {
+ public boolean matches( ArgumentDefinition definition, Object key ) {
+ if( !(key instanceof Boolean) )
+ throw new IllegalArgumentException("RequiredDefinitionMatcher requires boolean key");
+ return definition.required == (Boolean)key;
+ }
+ };
+
+ static DefinitionMatcher VerifiableDefinitionMatcher = new DefinitionMatcher() {
+ public boolean matches( ArgumentDefinition definition, Object key ) {
+ // We can perform some sort of validation for anything that isn't a flag or enum.
+ // Because enums can have a default value, it might be valid to specify an enum argument with no value
+ return !definition.isFlag && !definition.argumentType.isEnum();
+ }
+ };
+}
+
+/**
+ * A Comparator-esque interface for finding argument definitions within a collection.
+ */
+interface DefinitionMatcher {
+ /**
+ * Does the given definition match the provided key?
+ * @param definition The definition to inspect.
+ * @param key The value to match.
+ * @return True if the key matches the definition, false otherwise.
+ */
+ boolean matches( ArgumentDefinition definition, Object key );
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentException.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentException.java
new file mode 100644
index 0000000..a55da89
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentException.java
@@ -0,0 +1,38 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+/**
+ * Generic class for handling misc parsing exceptions.
+ */
+public class ArgumentException extends UserException {
+ public ArgumentException( String message ) {
+ super( message );
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentIOType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentIOType.java
new file mode 100644
index 0000000..27b8163
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentIOType.java
@@ -0,0 +1,52 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.lang.annotation.Annotation;
+
+public enum ArgumentIOType {
+ INPUT(Input.class), OUTPUT(Output.class), ARGUMENT(Argument.class);
+
+ public final Class<? extends Annotation> annotationClass;
+
+ ArgumentIOType(Class<? extends Annotation> annotationClass) {
+ this.annotationClass = annotationClass;
+ }
+
+ /**
+ * Returns the ArgumentIOType for the annotation.
+ * @param annotation @Input or @Output
+ * @return ArgumentIOType.Input, Output, or Unknown
+ */
+ public static ArgumentIOType getIOType(Annotation annotation) {
+ for (ArgumentIOType ioType: ArgumentIOType.values())
+ if (ioType.annotationClass.isAssignableFrom(annotation.getClass()))
+ return ioType;
+ throw new ReviewedGATKException("Unknown annotation type: " + annotation);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatch.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatch.java
new file mode 100644
index 0000000..885e02d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatch.java
@@ -0,0 +1,294 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.engine.walkers.Multiplexer;
+
+import java.util.*;
+
+/**
+ * A mapping of all the sites where an argument definition maps to a site on the command line.
+ */
+public class ArgumentMatch implements Iterable<ArgumentMatch> {
+ /**
+ * The argument definition that's been matched.
+ */
+ public final ArgumentDefinition definition;
+
+ /**
+ * The text that's been matched, as it appears in the command line arguments.
+ */
+ public final String label;
+
+ /**
+ * Maps indices of command line arguments to values paired with that argument.
+ */
+ public final SortedMap<ArgumentMatchSite,List<ArgumentMatchValue>> sites = new TreeMap<ArgumentMatchSite,List<ArgumentMatchValue>>();
+
+ /**
+ * An ordered, freeform collection of tags.
+ */
+ public final Tags tags;
+
+ /**
+ * Create a new argument match, defining its properties later. Used to create invalid arguments.
+ */
+ public ArgumentMatch() {
+ this(null,null);
+ }
+
+ /**
+ * Minimal constructor for transform function.
+ * @param label Label of the argument match. Must not be null.
+ * @param definition The associated definition, if one exists. May be null.
+ */
+ private ArgumentMatch(final String label, final ArgumentDefinition definition) {
+ this.label = label;
+ this.definition = definition;
+ this.tags = new Tags();
+ }
+
+ /**
+ * A simple way of indicating that an argument with the given label and definition exists at this site.
+ * @param label Label of the argument match. Must not be null.
+ * @param definition The associated definition, if one exists. May be null.
+ * @param site Position of the argument. Must not be null.
+ * @param tags ordered freeform text tags associated with this argument.
+ */
+ public ArgumentMatch(final String label, final ArgumentDefinition definition, final ArgumentMatchSite site, final Tags tags) {
+ this( label, definition, site, null, tags );
+ }
+
+ /**
+ * A simple way of indicating that an argument with the given label and definition exists at this site.
+ * @param label Label of the argument match. Must not be null.
+ * @param definition The associated definition, if one exists. May be null.
+ * @param site Position of the argument. Must not be null.
+ * @param value Value for the argument at this position.
+ * @param tags ordered freeform text tags associated with this argument.
+ */
+ private ArgumentMatch(final String label, final ArgumentDefinition definition, final ArgumentMatchSite site, final ArgumentMatchValue value, final Tags tags) {
+ this.label = label;
+ this.definition = definition;
+
+ ArrayList<ArgumentMatchValue> values = new ArrayList<ArgumentMatchValue>();
+ if( value != null )
+ values.add(value);
+ sites.put(site,values );
+
+ this.tags = tags;
+ }
+
+ /**
+ * Check to see whether two ArgumentMatch objects are equal.
+ * @param other Object to which this should be compared.
+ * @return True if objects are equal, false if objects are not equal or incomparable.
+ */
+ @Override
+ public boolean equals(Object other) {
+ // this clearly isn't null, since this.equals() when this == null would result in an NPE.
+ if(other == null)
+ return false;
+ if(!(other instanceof ArgumentMatch))
+ return false;
+ ArgumentMatch otherArgumentMatch = (ArgumentMatch)other;
+ return this.definition.equals(otherArgumentMatch.definition) &&
+ this.label.equals(otherArgumentMatch.label) &&
+ this.sites.equals(otherArgumentMatch.sites) &&
+ this.tags.equals(otherArgumentMatch.tags);
+ }
+
+
+ /**
+ * Reformat the given entries with the given multiplexer and key.
+ * TODO: Generify this.
+ * @param multiplexer Multiplexer that controls the transformation process.
+ * @param key Key which specifies the transform.
+ * @return A variant of this ArgumentMatch with all keys transformed.
+ */
+ @SuppressWarnings("unchecked")
+ ArgumentMatch transform(Multiplexer multiplexer, Object key) {
+ SortedMap<ArgumentMatchSite,List<ArgumentMatchValue>> newIndices = new TreeMap<ArgumentMatchSite,List<ArgumentMatchValue>>();
+ for(Map.Entry<ArgumentMatchSite,List<ArgumentMatchValue>> site: sites.entrySet()) {
+ List<ArgumentMatchValue> newEntries = new ArrayList<ArgumentMatchValue>();
+ for(ArgumentMatchValue entry: site.getValue())
+ newEntries.add(new ArgumentMatchStringValue(multiplexer.transformArgument(key,entry.asString())));
+ newIndices.put(site.getKey(),newEntries);
+ }
+ ArgumentMatch newArgumentMatch = new ArgumentMatch(label,definition);
+ newArgumentMatch.sites.putAll(newIndices);
+ return newArgumentMatch;
+ }
+
+ /**
+ * Return a string representation of the given argument match, for debugging purposes.
+ * @return String representation of the match.
+ */
+ public String toString() {
+ return label;
+ }
+
+ /**
+ * Creates an iterator that walks over each individual match at each position of a given argument.
+ * @return An iterator over the individual matches in this argument. Will not be null.
+ */
+ public Iterator<ArgumentMatch> iterator() {
+ return new Iterator<ArgumentMatch>() {
+ /**
+ * Iterate over each the available site.
+ */
+ private Iterator<ArgumentMatchSite> siteIterator = null;
+
+ /**
+ * Iterate over each available token.
+ */
+ private Iterator<ArgumentMatchValue> tokenIterator = null;
+
+ /**
+ * The next site to return. Null if none remain.
+ */
+ ArgumentMatchSite nextSite = null;
+
+ /**
+ * The next token to return. Null if none remain.
+ */
+ ArgumentMatchValue nextToken = null;
+
+ {
+ siteIterator = sites.keySet().iterator();
+ prepareNext();
+ }
+
+ /**
+ * Is there a nextToken available to return?
+ * @return True if there's another token waiting in the wings. False otherwise.
+ */
+ public boolean hasNext() {
+ return nextSite != null;
+ }
+
+ /**
+ * Get the next token, if one exists. If not, throw an IllegalStateException.
+ * @return The next ArgumentMatch in the series. Should never be null.
+ */
+ public ArgumentMatch next() {
+ if( nextSite == null )
+ throw new IllegalStateException( "No more ArgumentMatches are available" );
+
+ ArgumentMatch match = new ArgumentMatch( label, definition, nextSite, nextToken, tags );
+ prepareNext();
+ return match;
+ }
+
+ /**
+ * Initialize the next ArgumentMatch to return. If no ArgumentMatches are available,
+ * initialize nextSite / nextToken to null.
+ */
+ private void prepareNext() {
+ if( tokenIterator != null && tokenIterator.hasNext() ) {
+ nextToken = tokenIterator.next();
+ }
+ else {
+ nextSite = null;
+ nextToken = null;
+
+ // Do a nested loop. While more data is present in the inner loop, grab that data.
+ // Otherwise, troll the outer iterator looking for more data.
+ while( siteIterator.hasNext() ) {
+ nextSite = siteIterator.next();
+ if( sites.get(nextSite) != null ) {
+ tokenIterator = sites.get(nextSite).iterator();
+ nextToken = tokenIterator.hasNext() ? tokenIterator.next() : null;
+ break;
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Remove is unsupported in this context.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("Cannot remove an argument match from the collection while iterating.");
+ }
+ };
+ }
+
+ /**
+ * Merge two ArgumentMatches, so that the values for all arguments go into the
+ * same data structure.
+ * @param other The other match to merge into.
+ */
+ public void mergeInto( ArgumentMatch other ) {
+ sites.putAll(other.sites);
+ }
+
+ /**
+ * Associate a value with this merge maapping.
+ * @param site site of the command-line argument to which this value is mated.
+ * @param value Text representation of value to add.
+ */
+ public void addValue( ArgumentMatchSite site, ArgumentMatchValue value ) {
+ if( !sites.containsKey(site) || sites.get(site) == null )
+ sites.put(site, new ArrayList<ArgumentMatchValue>() );
+ sites.get(site).add(value);
+ }
+
+ /**
+ * Does this argument already have a value at the given site?
+ * Arguments are only allowed to be single-valued per site, and
+ * flags aren't allowed a value at all.
+ * @param site Site at which to check for values.
+ * @return True if the argument has a value at the given site. False otherwise.
+ */
+ public boolean hasValueAtSite( ArgumentMatchSite site ) {
+ return (sites.get(site) != null && sites.get(site).size() >= 1) || isArgumentFlag();
+ }
+
+ /**
+ * Return the values associated with this argument match.
+ * @return A collection of the string representation of these value.
+ */
+ public List<ArgumentMatchValue> values() {
+ final List<ArgumentMatchValue> values = new ArrayList<ArgumentMatchValue>();
+ for ( final List<ArgumentMatchValue> siteValue : sites.values() ) {
+ if ( siteValue != null )
+ values.addAll(siteValue);
+ else
+ values.add(null);
+ }
+ return values;
+ }
+
+ /**
+ * Convenience method returning true if the definition is a flag.
+ * @return True if definition is known to be a flag; false if not known to be a flag.
+ */
+ private boolean isArgumentFlag() {
+ return definition != null && definition.isFlag;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchFileValue.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchFileValue.java
new file mode 100644
index 0000000..3b9c8d3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchFileValue.java
@@ -0,0 +1,52 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.io.File;
+
+/**
+ * Holds a reference to a file as an argument match value.
+ *
+ * This is useful when the type of the stored file may be a subclass of java.io.File,
+ * for example a Queue RemoteFile.
+ */
+public class ArgumentMatchFileValue extends ArgumentMatchValue {
+ private final File file;
+
+ public ArgumentMatchFileValue(File file) {
+ this.file = file;
+ }
+
+ @Override
+ public String asString() {
+ return file == null ? null : file.getAbsolutePath();
+ }
+
+ @Override
+ public File asFile() {
+ return file;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSite.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSite.java
new file mode 100644
index 0000000..967d4c6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSite.java
@@ -0,0 +1,77 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+/**
+ * Which source and the index within the source where an argument match was found.
+ */
+public class ArgumentMatchSite implements Comparable<ArgumentMatchSite> {
+ private final ArgumentMatchSource source;
+ private final int index;
+
+ public ArgumentMatchSite(ArgumentMatchSource source, int index) {
+ this.source = source;
+ this.index = index;
+ }
+
+ public ArgumentMatchSource getSource() {
+ return source;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ArgumentMatchSite that = (ArgumentMatchSite) o;
+
+ return (index == that.index) && (source == null ? that.source == null : source.equals(that.source));
+ }
+
+ @Override
+ public int hashCode() {
+ int result = source != null ? source.hashCode() : 0;
+ // Generated by intellij. No other special reason to this implementation. -ks
+ result = 31 * result + index;
+ return result;
+ }
+
+ @Override
+ public int compareTo(ArgumentMatchSite that) {
+ int comp = this.source.compareTo(that.source);
+ if (comp != 0)
+ return comp;
+
+ // Both files are the same.
+ if (this.index == that.index)
+ return 0;
+ return this.index < that.index ? -1 : 1;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSource.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSource.java
new file mode 100644
index 0000000..a7ce7ba
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSource.java
@@ -0,0 +1,97 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+/**
+ * Where an argument match originated, via the commandline or a custom provider.
+ */
+public class ArgumentMatchSource implements Comparable<ArgumentMatchSource> {
+ public static final ArgumentMatchSource COMMAND_LINE = new ArgumentMatchSource(ArgumentMatchSourceType.CommandLine, null);
+
+ private final ArgumentMatchSourceType type;
+ private final String description;
+
+ /**
+ * Creates an argument match source from the specified file.
+ * @param description Where the arguments originated.
+ */
+ public ArgumentMatchSource(String description) {
+ this(ArgumentMatchSourceType.Provider, description);
+ }
+
+ private ArgumentMatchSource(ArgumentMatchSourceType type, String description) {
+ if (type == ArgumentMatchSourceType.Provider && description == null)
+ throw new IllegalArgumentException("An argument match source provider cannot have a null description.");
+ this.type = type;
+ this.description = description;
+ }
+
+ public ArgumentMatchSourceType getType() {
+ return type;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ArgumentMatchSource that = (ArgumentMatchSource) o;
+
+ return (type == that.type) && (description == null ? that.description == null : description.equals(that.description));
+ }
+
+ @Override
+ public int hashCode() {
+ int result = type != null ? type.hashCode() : 0;
+ result = 31 * result + (description != null ? description.hashCode() : 0);
+ return result;
+ }
+
+ /**
+ * Compares two sources, putting the command line first, then files.
+ */
+ @Override
+ public int compareTo(ArgumentMatchSource that) {
+ int comp = this.type.compareTo(that.type);
+ if (comp != 0)
+ return comp;
+
+ String d1 = this.description;
+ String d2 = that.description;
+
+ if ((d1 == null) ^ (d2 == null)) {
+ // If one of the descriptions is null and the other is not
+ // put the null description first
+ return d1 == null ? -1 : 1;
+ }
+
+ return d1 == null ? 0 : d1.compareTo(d2);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSourceType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSourceType.java
new file mode 100644
index 0000000..9dee5be
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSourceType.java
@@ -0,0 +1,33 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+/**
+ * Type of where an argument match originated, via the commandline or a some other provider.
+ */
+public enum ArgumentMatchSourceType {
+ CommandLine, Provider
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchStringValue.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchStringValue.java
new file mode 100644
index 0000000..9f772bc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchStringValue.java
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.io.File;
+
+/**
+ * Argument values that originated from a string.
+ */
+public class ArgumentMatchStringValue extends ArgumentMatchValue {
+ private final String value;
+
+ public ArgumentMatchStringValue(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String asString() {
+ return value;
+ }
+
+ @Override
+ public File asFile() {
+ return value == null ? null : new File(value);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchValue.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchValue.java
new file mode 100644
index 0000000..f37d538
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchValue.java
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.io.File;
+
+/**
+ * Returns argument values as either strings or values.
+ */
+public abstract class ArgumentMatchValue {
+ /**
+ * @return the value of this argument as a String object.
+ */
+ public abstract String asString();
+
+ /**
+ * @return the value of this argument as a File object.
+ */
+ public abstract File asFile();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatches.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatches.java
new file mode 100644
index 0000000..2d81cfc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatches.java
@@ -0,0 +1,211 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.engine.walkers.Multiplexer;
+
+import java.util.*;
+/**
+ * Represents a list of potential matches between the arguments defined
+ * by the argument sources and the arguments passed in via the command line.
+ */
+public class ArgumentMatches implements Iterable<ArgumentMatch> {
+ /**
+ * Collection matches from argument definition to argument value.
+ * Package protected access is deliberate.
+ */
+ Map<ArgumentMatchSite,ArgumentMatch> argumentMatches = new TreeMap<ArgumentMatchSite,ArgumentMatch>();
+
+ /**
+ * Provide a place to put command-line argument values that don't seem to belong to
+ * any particular command-line option.
+ */
+ ArgumentMatch MissingArgument = new ArgumentMatch();
+
+ /**
+ * Get an iterator cycling through *unique* command-line argument <-> definition matches.
+ * @return Iterator over all argument matches.
+ */
+ public Iterator<ArgumentMatch> iterator() {
+ return getUniqueMatches().iterator();
+ }
+
+ /**
+ * Create an empty ArgumentMatches object.
+ */
+ public ArgumentMatches() {
+ }
+
+ /**
+ * Create a singleton ArgumentMatches object.
+ * @param match Match to incorporate.
+ */
+ public ArgumentMatches( ArgumentMatch match ) {
+ mergeInto( match );
+ }
+
+ /**
+ * Returns the number of matches in this structure.
+ * @return Count of the matches in this structure.
+ */
+ public int size() {
+ return argumentMatches.size();
+ }
+
+ /**
+ * Indicates whether the site contains a matched argument.
+ * @param site Site at which to check.
+ * @return True if the site has a match. False otherwise.
+ */
+ boolean hasMatch( ArgumentMatchSite site ) {
+ return argumentMatches.containsKey( site );
+ }
+
+ /**
+ * Gets the match at a given site.
+ * @param site Site at which to look for a match.
+ * @return The match present at the given site.
+ * @throws IllegalArgumentException if site does not contain a match.
+ */
+ ArgumentMatch getMatch( ArgumentMatchSite site ) {
+ if( !argumentMatches.containsKey(site) )
+ throw new IllegalArgumentException( "Site does not contain an argument: " + site );
+ return argumentMatches.get(site);
+ }
+
+ /**
+ * Does the match collection have a match for this argument definition.
+ * @param definition Definition to match.
+ * @return True if a match exists; false otherwise.
+ */
+ boolean hasMatch( ArgumentDefinition definition ) {
+ return findMatches( definition ).size() > 0;
+ }
+
+ /**
+ * Return all argument matches of this source.
+ * @param parsingEngine Parsing engine.
+ * @param argumentSource Argument source to match.
+ * @return List of all matches.
+ */
+
+ ArgumentMatches findMatches(ParsingEngine parsingEngine, ArgumentSource argumentSource) {
+ List<ArgumentDefinition> sourceDefinitions = parsingEngine.selectBestTypeDescriptor(argumentSource.field.getType()).createArgumentDefinitions(argumentSource);
+
+ ArgumentMatches matches = new ArgumentMatches();
+ for( ArgumentMatch argumentMatch: getUniqueMatches() ) {
+ if( sourceDefinitions.contains(argumentMatch.definition) )
+ matches.mergeInto( argumentMatch );
+ }
+ return matches;
+ }
+
+ /**
+ * Return all argument matches of this definition.
+ * @param definition Argument definition to match.
+ * @return List of all matches.
+ */
+ ArgumentMatches findMatches( ArgumentDefinition definition ) {
+ ArgumentMatches matches = new ArgumentMatches();
+ for( ArgumentMatch argumentMatch: argumentMatches.values() ) {
+ if( argumentMatch.definition == definition )
+ matches.mergeInto( argumentMatch );
+ }
+ return matches;
+ }
+
+ /**
+ * Find all successful matches (a 'successful' match is one paired with a definition).
+ * @return All successful matches.
+ */
+ ArgumentMatches findSuccessfulMatches() {
+ ArgumentMatches matches = new ArgumentMatches();
+ for( ArgumentMatch argumentMatch: argumentMatches.values() ) {
+ if( argumentMatch.definition != null )
+ matches.mergeInto( argumentMatch );
+ }
+ return matches;
+ }
+
+ /**
+ * Find arguments that are unmatched to any definition.
+ * @return Set of matches that have no associated definition.
+ */
+ ArgumentMatches findUnmatched() {
+ ArgumentMatches matches = new ArgumentMatches();
+ for( ArgumentMatch argumentMatch: argumentMatches.values() ) {
+ if( argumentMatch.definition == null )
+ matches.mergeInto( argumentMatch );
+ }
+ return matches;
+ }
+
+ /**
+ * Reformat the given entries with the given multiplexer and key.
+ * TODO: Generify this.
+ * @param multiplexer Multiplexer that controls the transformation process.
+ * @param key Key which specifies the transform.
+ * @return new argument matches.
+ */
+ ArgumentMatches transform(Multiplexer multiplexer, Object key) {
+ ArgumentMatches newArgumentMatches = new ArgumentMatches();
+ for(ArgumentMatch match: argumentMatches.values())
+ newArgumentMatches.mergeInto(match.transform(multiplexer,key));
+ return newArgumentMatches;
+ }
+
+ /**
+ * Merges the given argument match into the set of existing argument matches.
+ * If multiple arguments are present, those arguments will end up grouped.
+ * @param match The match to merge into.
+ */
+ void mergeInto( ArgumentMatch match ) {
+ boolean definitionExists = false;
+
+ // Clone the list of argument matches to avoid ConcurrentModificationExceptions.
+ for( ArgumentMatch argumentMatch: getUniqueMatches() ) {
+ if( argumentMatch.definition == match.definition && argumentMatch.tags.equals(match.tags) ) {
+ argumentMatch.mergeInto( match );
+ for( ArgumentMatchSite site: match.sites.keySet() )
+ argumentMatches.put( site, argumentMatch );
+ definitionExists = true;
+ }
+ }
+
+ if( !definitionExists ) {
+ for( ArgumentMatchSite site: match.sites.keySet() )
+ argumentMatches.put( site, match );
+ }
+ }
+
+ /**
+ * Determines, of the argument matches by position, which are unique and returns that list.
+ * @return A unique set of matches.
+ */
+ private Set<ArgumentMatch> getUniqueMatches() {
+ return new LinkedHashSet<ArgumentMatch>( argumentMatches.values() );
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentSource.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentSource.java
new file mode 100644
index 0000000..79e07a6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentSource.java
@@ -0,0 +1,243 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Describes the source field which defines a command-line argument.
+ * A parsed-object version of the command-line argument will be
+ * injected into an object containing this field.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class ArgumentSource {
+ /**
+ * Field into which to inject command-line arguments.
+ */
+ public final Field[] parentFields;
+
+ /**
+ * Field into which to inject command-line arguments.
+ */
+ public final Field field;
+
+ /**
+ * Type descriptor to use when parsing new argument types.
+ */
+ private final ArgumentTypeDescriptor typeDescriptor;
+
+ /**
+ * Create a new command-line argument target.
+ * @param parentFields Parent fields containing the the field. Field must be annotated with 'ArgumentCollection'.
+ * @param field Field containing the argument. Field must be annotated with 'Input' or 'Output'.
+ * @param typeDescriptor custom type descriptor to use when parsing.
+ */
+ protected ArgumentSource( Field[] parentFields, Field field, ArgumentTypeDescriptor typeDescriptor) {
+ this.parentFields = parentFields;
+ this.field = field;
+ this.typeDescriptor = typeDescriptor;
+ }
+
+ /**
+ * Somewhat hackish copy constructor to track fields with a custom type descriptor.
+ * TODO: Separate type descriptor from ArgumentSource in general usage.
+ * @param typeDescriptor New type descriptor for the object.
+ */
+ public ArgumentSource copyWithCustomTypeDescriptor(final ArgumentTypeDescriptor typeDescriptor) {
+ return new ArgumentSource(parentFields,field,typeDescriptor);
+ }
+
+ /**
+ * True if this argument source equals other.
+ * @param other Another object, possibly an argument source, to test for equality. Any object can
+ * be tested, but only instances of ArgumentSource will result in equals returning true.
+ * @return True if this argument source matches other. False otherwise.
+ */
+ @Override
+ public boolean equals( Object other ) {
+ if( other == null )
+ return false;
+ if( !(other instanceof ArgumentSource) )
+ return false;
+
+ ArgumentSource otherArgumentSource = (ArgumentSource)other;
+ return this.field == otherArgumentSource.field && Arrays.equals(this.parentFields, otherArgumentSource.parentFields);
+ }
+
+ /**
+ * Returns an appropriate hash code for this argument source.
+ * @return A uniformly distributed hashcode representing this argument source.
+ */
+ @Override
+ public int hashCode() {
+ return field.hashCode();
+ }
+
+ /**
+ * Generate a list of all argument definitions to which this argument source maps.
+ * @return A non-null, non-empty list of argument definitions.
+ */
+ public List<ArgumentDefinition> createArgumentDefinitions() {
+ return typeDescriptor.createArgumentDefinitions( this );
+ }
+
+ /**
+ * Parses the specified value based on the specified type.
+ * @param values String representation of all values passed.
+ * @return the parsed value of the object.
+ */
+ public Object parse( ParsingEngine parsingEngine, ArgumentMatches values ) {
+ return typeDescriptor.parse( parsingEngine, this, values );
+ }
+
+ /**
+ * Returns whether this field is required. Note that flag fields are always forced to 'not required'.
+ * @return True if the field is mandatory and not a boolean flag. False otherwise.
+ */
+ public boolean isRequired() {
+ return (Boolean)CommandLineUtils.getValue(ArgumentTypeDescriptor.getArgumentAnnotation(this),"required");
+ }
+
+ /**
+ * Returns true if the argument is a flag (a 0-valued argument).
+ * @return True if argument is a flag; false otherwise.
+ */
+ public boolean isFlag() {
+ return (field.getType() == Boolean.class) || (field.getType() == Boolean.TYPE);
+ }
+
+ /**
+ * Can this argument support multiple values, or just one?
+ * @return True if the argument supports multiple values.
+ */
+ public boolean isMultiValued() {
+ return typeDescriptor.isMultiValued( this );
+ }
+
+ /**
+ * Should the given class be hidden from the command-line argument system.
+ * @return True if so. False otherwise.
+ */
+ public boolean isHidden() {
+ return field.isAnnotationPresent(Hidden.class) || field.isAnnotationPresent(Deprecated.class);
+ }
+
+ /**
+ * Is the given argument considered an advanced option when displaying on the command-line argument system.
+ * @return True if so. False otherwise.
+ */
+ public boolean isAdvanced() {
+ return field.isAnnotationPresent(Advanced.class);
+ }
+
+ /**
+ * Is the given argument an output.
+ * @return True if so. False otherwise.
+ */
+ public boolean isOutput() {
+ return field.isAnnotationPresent(Output.class);
+ }
+
+ /**
+ * Is the given argument an input.
+ * @return True if so. False otherwise.
+ */
+ public boolean isInput() {
+ return field.isAnnotationPresent(Input.class);
+ }
+
+ /**
+ * Is this command-line argument dependent on some primitive argument types?
+ * @return True if this command-line argument depends on other arguments; false otherwise.
+ */
+ public boolean isDependent() {
+ return typeDescriptor instanceof MultiplexArgumentTypeDescriptor;
+ }
+
+ /**
+ * Returns whether the field has been deprecated and should no longer be used.
+ * @return True if field has been deprecated.
+ */
+ public boolean isDeprecated() {
+ return field.isAnnotationPresent(Deprecated.class);
+ }
+
+ /**
+ * Returns whether the field should default to stdout if not provided explicitly on the command-line.
+ * @return True if field should default to stdout.
+ */
+ public boolean defaultsToStdout() {
+ return field.isAnnotationPresent(Output.class) && (Boolean)CommandLineUtils.getValue(ArgumentTypeDescriptor.getArgumentAnnotation(this),"defaultToStdout");
+ }
+
+ /**
+ * Returns false if a type-specific default can be employed.
+ * @return True to throw in a type specific default. False otherwise.
+ */
+ public boolean createsTypeDefault() {
+ return typeDescriptor.createsTypeDefault(this);
+ }
+
+ public String typeDefaultDocString() {
+ return typeDescriptor.typeDefaultDocString(this);
+ }
+
+ /**
+ * Generates a default for the given type.
+ * @param parsingEngine the parsing engine used to validate this argument type descriptor.
+ * @return A default value for the given type.
+ */
+ public Object createTypeDefault(ParsingEngine parsingEngine) {
+ return typeDescriptor.createTypeDefault(parsingEngine,this,field.getGenericType());
+ }
+
+ /**
+ * Builds out a new type descriptor for the given dependent argument as a function
+ * of the containing object.
+ * @param parsingEngine the parsing engine to use when building out this custom type descriptor.
+ * @param containingObject The containing object.
+ * @return An argument type descriptor for the custom derivative field.
+ */
+ public MultiplexArgumentTypeDescriptor createDependentTypeDescriptor(ParsingEngine parsingEngine,Object containingObject) {
+ if(!isDependent())
+ throw new ReviewedGATKException("Field " + field.getName() + " is independent; no dependent type descriptor can be derived.");
+ return ((MultiplexArgumentTypeDescriptor)typeDescriptor).createCustomTypeDescriptor(parsingEngine,this,containingObject);
+ }
+
+ /**
+ * Gets a string representation of the argument source for debugging.
+ * @return String representation of the argument source.
+ */
+ public String toString() {
+ return field.getDeclaringClass().getSimpleName() + ": " + field.getName();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentTypeDescriptor.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentTypeDescriptor.java
new file mode 100644
index 0000000..5bfc516
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ArgumentTypeDescriptor.java
@@ -0,0 +1,1030 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.apache.log4j.Logger;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.engine.refdata.tracks.FeatureManager;
+import org.broadinstitute.gatk.engine.walkers.Multiplex;
+import org.broadinstitute.gatk.engine.walkers.Multiplexer;
+import org.broadinstitute.gatk.utils.classloader.JVMUtils;
+import org.broadinstitute.gatk.utils.exceptions.DynamicClassResolutionException;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * An descriptor capable of providing parsers that can parse any type
+ * of supported command-line argument.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public abstract class ArgumentTypeDescriptor {
+ private static Class[] ARGUMENT_ANNOTATIONS = {Input.class, Output.class, Argument.class};
+
+ /**
+ * our log, which we want to capture anything from org.broadinstitute.gatk
+ */
+ protected static final Logger logger = Logger.getLogger(ArgumentTypeDescriptor.class);
+
+ /**
+ * Fetch the given descriptor from the descriptor repository.
+ * @param descriptors the descriptors from which to select a good match.
+ * @param type Class for which to specify a descriptor.
+ * @return descriptor for the given type.
+ */
+ public static ArgumentTypeDescriptor selectBest( Collection<ArgumentTypeDescriptor> descriptors, Class type ) {
+ for( ArgumentTypeDescriptor descriptor: descriptors ) {
+ if( descriptor.supports(type) )
+ return descriptor;
+ }
+ throw new ReviewedGATKException("Can't process command-line arguments of type: " + type.getName());
+ }
+
+ /**
+ * Does this descriptor support classes of the given type?
+ * @param type The type to check.
+ * @return true if this descriptor supports the given type, false otherwise.
+ */
+ public abstract boolean supports( Class type );
+
+ /**
+ * Returns false if a type-specific default can be employed.
+ * @param source Source of the command-line argument.
+ * @return True to throw in a type specific default. False otherwise.
+ */
+ public boolean createsTypeDefault(ArgumentSource source) { return false; }
+
+ /**
+ * Returns a documentation-friendly value for the default of a type descriptor.
+ * Must be overridden if createsTypeDefault return true. cannot be called otherwise
+ * @param source Source of the command-line argument.
+ * @return Friendly string of the default value, for documentation. If doesn't create a default, throws
+ * and UnsupportedOperationException
+ */
+ public String typeDefaultDocString(ArgumentSource source) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Generates a default for the given type.
+ *
+ * @param parsingEngine the parsing engine used to validate this argument type descriptor.
+ * @param source Source of the command-line argument.
+ * @param type Type of value to create, in case the command-line argument system wants influence.
+ * @return A default value for the given type.
+ */
+ public Object createTypeDefault(ParsingEngine parsingEngine,ArgumentSource source, Type type) { throw new UnsupportedOperationException("Unable to create default for type " + getClass()); }
+
+ /**
+ * Given the given argument source and attributes, synthesize argument definitions for command-line arguments.
+ * @param source Source class and field for the given argument.
+ * @return A list of command-line argument definitions supporting this field.
+ */
+ public List<ArgumentDefinition> createArgumentDefinitions( ArgumentSource source ) {
+ return Collections.singletonList(createDefaultArgumentDefinition(source));
+ }
+
+ /**
+ * Parses an argument source to an object.
+ * WARNING! Mandatory side effect of parsing! Each parse routine should register the tags it finds with the proper CommandLineProgram.
+ * TODO: Fix this, perhaps with an event model indicating that a new argument has been created.
+ *
+ * @param parsingEngine The engine responsible for parsing.
+ * @param source The source used to find the matches.
+ * @param matches The matches for the source.
+ * @return The parsed object.
+ */
+ public Object parse(ParsingEngine parsingEngine, ArgumentSource source, ArgumentMatches matches) {
+ return parse(parsingEngine, source, source.field.getGenericType(), matches);
+ }
+
+ /**
+ * Returns true if the field is a collection or an array.
+ * @param source The argument source to check.
+ * @return true if the field is a collection or an array.
+ */
+ public boolean isMultiValued( ArgumentSource source ) {
+ Class argumentType = source.field.getType();
+ return Collection.class.isAssignableFrom(argumentType) || argumentType.isArray();
+ }
+
+ /**
+ * By default, argument sources create argument definitions with a set of default values.
+ * Use this method to create the one simple argument definition.
+ * @param source argument source for which to create a default definition.
+ * @return The default definition for this argument source.
+ */
+ protected ArgumentDefinition createDefaultArgumentDefinition( ArgumentSource source ) {
+ Annotation argumentAnnotation = getArgumentAnnotation(source);
+ return new ArgumentDefinition( ArgumentIOType.getIOType(argumentAnnotation),
+ source.field.getType(),
+ ArgumentDefinition.getFullName(argumentAnnotation, source.field.getName()),
+ ArgumentDefinition.getShortName(argumentAnnotation),
+ ArgumentDefinition.getDoc(argumentAnnotation),
+ source.isRequired() && !createsTypeDefault(source) && !source.isFlag() && !source.isDeprecated(),
+ source.isFlag(),
+ source.isMultiValued(),
+ source.isHidden(),
+ makeRawTypeIfNecessary(getCollectionComponentType(source.field)),
+ ArgumentDefinition.getExclusiveOf(argumentAnnotation),
+ ArgumentDefinition.getValidationRegex(argumentAnnotation),
+ getValidOptions(source) );
+ }
+
+ /**
+ * Return the component type of a field, or String.class if the type cannot be found.
+ * @param field The reflected field to inspect.
+ * @return The parameterized component type, or String.class if the parameterized type could not be found.
+ * @throws IllegalArgumentException If more than one parameterized type is found on the field.
+ */
+ protected Type getCollectionComponentType( Field field ) {
+ return null;
+ }
+
+ /**
+ * Parses the argument matches for a class type into an object.
+ * @param source The original argument source used to find the matches.
+ * @param type The current class type being inspected. May not match the argument source.field.getType() if this as a collection for example.
+ * @param matches The argument matches for the argument source, or the individual argument match for a scalar if this is being called to help parse a collection.
+ * @return The individual parsed object matching the argument match with Class type.
+ */
+ public abstract Object parse( ParsingEngine parsingEngine, ArgumentSource source, Type type, ArgumentMatches matches );
+
+ /**
+ * If the argument source only accepts a small set of options, populate the returned list with
+ * those options. Otherwise, leave the list empty.
+ * @param source Original field specifying command-line arguments.
+ * @return A list of valid options.
+ */
+ protected List<String> getValidOptions( ArgumentSource source ) {
+ if(!source.field.getType().isEnum())
+ return null;
+ List<String> validOptions = new ArrayList<String>();
+ for(Object constant: source.field.getType().getEnumConstants())
+ validOptions.add(constant.toString());
+ return validOptions;
+ }
+
+ /**
+ * Returns true if the argument with the given full name exists in the collection of ArgumentMatches.
+ * @param definition Definition of the argument for which to find matches.
+ * @param matches The matches for the given argument.
+ * @return true if the argument is present, or false if not present.
+ */
+ protected boolean argumentIsPresent( ArgumentDefinition definition, ArgumentMatches matches ) {
+ for( ArgumentMatch match: matches ) {
+ if( match.definition.equals(definition) )
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Gets the value of an argument with the given full name, from the collection of ArgumentMatches.
+ * If the argument matches multiple values, an exception will be thrown.
+ * @param definition Definition of the argument for which to find matches.
+ * @param matches The matches for the given argument.
+ * @return The value of the argument if available, or null if not present.
+ */
+ protected ArgumentMatchValue getArgumentValue( ArgumentDefinition definition, ArgumentMatches matches ) {
+ Collection<ArgumentMatchValue> argumentValues = getArgumentValues( definition, matches );
+ if( argumentValues.size() > 1 )
+ throw new UserException.CommandLineException("Multiple values associated with given definition, but this argument expects only one: " + definition.fullName);
+ return argumentValues.size() > 0 ? argumentValues.iterator().next() : null;
+ }
+
+ /**
+ * Gets the tags associated with a given command-line argument.
+ * If the argument matches multiple values, an exception will be thrown.
+ * @param matches The matches for the given argument.
+ * @return The value of the argument if available, or null if not present.
+ */
+ protected Tags getArgumentTags(ArgumentMatches matches) {
+ Tags tags = new Tags();
+ for(ArgumentMatch match: matches) {
+ if(!tags.isEmpty() && !match.tags.isEmpty())
+ throw new ReviewedGATKException("BUG: multiple conflicting sets of tags are available, and the type descriptor specifies no way of resolving the conflict.");
+ tags = match.tags;
+ }
+ return tags;
+ }
+
+ /**
+ * Gets the values of an argument with the given full name, from the collection of ArgumentMatches.
+ * @param definition Definition of the argument for which to find matches.
+ * @param matches The matches for the given argument.
+ * @return The value of the argument if available, or an empty collection if not present.
+ */
+ protected Collection<ArgumentMatchValue> getArgumentValues( ArgumentDefinition definition, ArgumentMatches matches ) {
+ Collection<ArgumentMatchValue> values = new ArrayList<ArgumentMatchValue>();
+ for( ArgumentMatch match: matches ) {
+ if( match.definition.equals(definition) )
+ values.addAll(match.values());
+ }
+ return values;
+ }
+
+ /**
+ * Retrieves the argument description from the given argument source. Will throw an exception if
+ * the given ArgumentSource
+ * @param source source of the argument.
+ * @return Argument description annotation associated with the given field.
+ */
+ @SuppressWarnings("unchecked")
+ protected static Annotation getArgumentAnnotation( ArgumentSource source ) {
+ for (Class annotation: ARGUMENT_ANNOTATIONS)
+ if (source.field.isAnnotationPresent(annotation))
+ return source.field.getAnnotation(annotation);
+ throw new ReviewedGATKException("ArgumentAnnotation is not present for the argument field: " + source.field.getName());
+ }
+
+ /**
+ * Returns true if an argument annotation is present
+ * @param field The field to check for an annotation.
+ * @return True if an argument annotation is present on the field.
+ */
+ @SuppressWarnings("unchecked")
+ public static boolean isArgumentAnnotationPresent(Field field) {
+ for (Class annotation: ARGUMENT_ANNOTATIONS)
+ if (field.isAnnotationPresent(annotation))
+ return true;
+ return false;
+ }
+
+ /**
+ * Returns true if the given annotation is hidden from the help system.
+ * @param field Field to test.
+ * @return True if argument should be hidden. False otherwise.
+ */
+ public static boolean isArgumentHidden(Field field) {
+ return field.isAnnotationPresent(Hidden.class);
+ }
+
+ public static Class makeRawTypeIfNecessary(Type t) {
+ if ( t == null )
+ return null;
+ else if ( t instanceof ParameterizedType )
+ return (Class)((ParameterizedType) t).getRawType();
+ else if ( t instanceof Class ) {
+ return (Class)t;
+ } else {
+ throw new IllegalArgumentException("Unable to determine Class-derived component type of field: " + t);
+ }
+ }
+
+ /**
+ * The actual argument parsing method.
+ * @param source source
+ * @param type type to check
+ * @param matches matches
+ * @param tags argument tags
+ * @return the RodBinding/IntervalBinding object depending on the value of createIntervalBinding.
+ */
+ protected Object parseBinding(ArgumentSource source, Type type, ArgumentMatches matches, Tags tags) {
+ ArgumentDefinition defaultDefinition = createDefaultArgumentDefinition(source);
+ ArgumentMatchValue value = getArgumentValue(defaultDefinition, matches);
+ @SuppressWarnings("unchecked")
+ Class<? extends Feature> parameterType = JVMUtils.getParameterizedTypeClass(type);
+ String name = defaultDefinition.fullName;
+
+ return parseBinding(value, parameterType, type, name, tags, source.field.getName());
+ }
+
+ /**
+ *
+ * @param value The source of the binding
+ * @param parameterType The Tribble Feature parameter type
+ * @param bindingClass The class type for the binding (ex: RodBinding, IntervalBinding, etc.) Must have the correct constructor for creating the binding.
+ * @param bindingName The name of the binding passed to the constructor.
+ * @param tags Tags for the binding used for parsing and passed to the constructor.
+ * @param fieldName The name of the field that was parsed. Used for error reporting.
+ * @return The newly created binding object of type bindingClass.
+ */
+ public static Object parseBinding(ArgumentMatchValue value, Class<? extends Feature> parameterType, Type bindingClass,
+ String bindingName, Tags tags, String fieldName) {
+ try {
+ String tribbleType = null;
+ // must have one or two tag values here
+ if ( tags.getPositionalTags().size() > 2 ) {
+ throw new UserException.CommandLineException(
+ String.format("Unexpected number of positional tags for argument %s : %s. " +
+ "Rod bindings only support -X:type and -X:name,type argument styles",
+ value.asString(), fieldName));
+ } else if ( tags.getPositionalTags().size() == 2 ) {
+ // -X:name,type style
+ bindingName = tags.getPositionalTags().get(0);
+ tribbleType = tags.getPositionalTags().get(1);
+
+ FeatureManager manager = new FeatureManager();
+ if ( manager.getByName(tribbleType) == null )
+ throw new UserException.UnknownTribbleType(
+ tribbleType,
+ String.format("Unable to find tribble type '%s' provided on the command line. " +
+ "Please select a correct type from among the supported types:%n%s",
+ tribbleType, manager.userFriendlyListOfAvailableFeatures(parameterType)));
+
+ } else {
+ // case with 0 or 1 positional tags
+ FeatureManager manager = new FeatureManager();
+
+ // -X:type style is a type when we cannot determine the type dynamically
+ String tag1 = tags.getPositionalTags().size() == 1 ? tags.getPositionalTags().get(0) : null;
+ if ( tag1 != null ) {
+ if ( manager.getByName(tag1) != null ) // this a type
+ tribbleType = tag1;
+ else
+ bindingName = tag1;
+ }
+
+ if ( tribbleType == null ) {
+ // try to determine the file type dynamically
+ File file = value.asFile();
+ if ( file.canRead() && file.isFile() ) {
+ FeatureManager.FeatureDescriptor featureDescriptor = manager.getByFiletype(file);
+ if ( featureDescriptor != null ) {
+ tribbleType = featureDescriptor.getName();
+ logger.debug("Dynamically determined type of " + file + " to be " + tribbleType);
+ }
+ }
+
+ if ( tribbleType == null ) {
+ // IntervalBinding can be created from a normal String
+ Class rawType = (makeRawTypeIfNecessary(bindingClass));
+ try {
+ return rawType.getConstructor(String.class).newInstance(value.asString());
+ } catch (NoSuchMethodException e) {
+ /* ignore */
+ }
+
+ if ( ! file.exists() ) {
+ throw new UserException.CouldNotReadInputFile(file, "file does not exist");
+ } else if ( ! file.canRead() || ! file.isFile() ) {
+ throw new UserException.CouldNotReadInputFile(file, "file could not be read");
+ } else {
+ throw new UserException.CommandLineException(
+ String.format("No tribble type was provided on the command line and the type of the file could not be determined dynamically. " +
+ "Please add an explicit type tag :NAME listing the correct type from among the supported types:%n%s",
+ manager.userFriendlyListOfAvailableFeatures(parameterType)));
+ }
+ }
+ }
+ }
+
+ Constructor ctor = (makeRawTypeIfNecessary(bindingClass)).getConstructor(Class.class, String.class, String.class, String.class, Tags.class);
+ return ctor.newInstance(parameterType, bindingName, value.asString(), tribbleType, tags);
+ } catch (Exception e) {
+ if ( e instanceof UserException )
+ throw ((UserException)e);
+ else
+ throw new UserException.CommandLineException(
+ String.format("Failed to parse value %s for argument %s. Message: %s",
+ value, fieldName, e.getMessage()));
+ }
+ }
+
+ /**
+ * Parse the source of a RodBindingCollection, which can be either a file of RodBindings or an actual RodBinding.
+ *
+ * @param parsingEngine the parsing engine used to validate this argument type descriptor
+ * @param source source
+ * @param type type
+ * @param matches matches
+ * @param tags argument tags
+ * @return the newly created binding object
+ */
+ public Object parseRodBindingCollectionSource(final ParsingEngine parsingEngine,
+ final ArgumentSource source,
+ final Type type,
+ final ArgumentMatches matches,
+ final Tags tags) {
+
+ final ArgumentDefinition defaultDefinition = createDefaultArgumentDefinition(source);
+ final ArgumentMatchValue value = getArgumentValue(defaultDefinition, matches);
+ @SuppressWarnings("unchecked")
+ Class<? extends Feature> parameterType = JVMUtils.getParameterizedTypeClass(type);
+ String name = defaultDefinition.fullName;
+
+ // if this a list of files, get those bindings
+ final File file = value.asFile();
+ try {
+ if (file.getAbsolutePath().endsWith(".list")) {
+ return getRodBindingsCollection(file, parsingEngine, parameterType, name, tags, source.field.getName());
+ }
+ } catch (IOException e) {
+ throw new UserException.CouldNotReadInputFile(file, e);
+ }
+
+ // otherwise, treat this as an individual binding
+ final RodBinding binding = (RodBinding)parseBinding(value, parameterType, RodBinding.class, name, tags, source.field.getName());
+ parsingEngine.addTags(binding, tags);
+ parsingEngine.addRodBinding(binding);
+ return RodBindingCollection.createRodBindingCollectionOfType(parameterType, Arrays.asList(binding));
+ }
+
+ /**
+ * Retrieve and parse a collection of RodBindings from the given file.
+ *
+ * If the file contains duplicate entries or is empty, an exception will be thrown.
+ *
+ * @param file the source file
+ * @param parsingEngine the engine responsible for parsing
+ * @param parameterType the Tribble Feature parameter type
+ * @param bindingName the name of the binding passed to the constructor.
+ * @param defaultTags general tags for the binding used for parsing and passed to the constructor.
+ * @param fieldName the name of the field that was parsed. Used for error reporting.
+ * @return the newly created collection of binding objects.
+ */
+ public static Object getRodBindingsCollection(final File file,
+ final ParsingEngine parsingEngine,
+ final Class<? extends Feature> parameterType,
+ final String bindingName,
+ final Tags defaultTags,
+ final String fieldName) throws IOException {
+ final List<RodBinding> bindings = new ArrayList<>();
+
+ // Keep track of the files in this list so that we can check for duplicates and empty files
+ final Set<String> fileValues = new HashSet<>();
+
+ // parse each line separately using the given Tags if none are provided on each line
+ for ( final String line: new XReadLines(file) ) {
+ final String[] tokens = line.split("\\s+");
+ final RodBinding binding;
+
+ if ( tokens.length == 0 ) {
+ continue; // empty line, so do nothing
+ }
+ // use the default tags if none are provided for this binding
+ else if ( tokens.length == 1 ) {
+ final ArgumentMatchValue value = parseAndValidateArgumentMatchValue(tokens[0], fileValues, fieldName, file.getName());
+ binding = (RodBinding)parseBinding(value, parameterType, RodBinding.class, bindingName, defaultTags, fieldName);
+ parsingEngine.addTags(binding, defaultTags);
+
+ }
+ // use the new tags if provided
+ else if ( tokens.length == 2 ) {
+ final Tags tags = ParsingMethod.parseTags(fieldName, tokens[0]);
+ final ArgumentMatchValue value = parseAndValidateArgumentMatchValue(tokens[1], fileValues, fieldName, file.getName());
+ binding = (RodBinding)parseBinding(value, parameterType, RodBinding.class, bindingName, tags, fieldName);
+ parsingEngine.addTags(binding, tags);
+ } else {
+ throw new UserException.BadArgumentValue(fieldName, "data lines should consist of an optional set of tags along with a path to a file; too many tokens are present for line: " + line);
+ }
+
+ bindings.add(binding);
+ parsingEngine.addRodBinding(binding);
+ }
+
+ if (fileValues.isEmpty()) {
+ throw new UserException.BadArgumentValue(fieldName, "The input list " + file.getName() + " is empty.");
+ }
+
+ return RodBindingCollection.createRodBindingCollectionOfType(parameterType, bindings);
+ }
+
+ /**
+ * Validates the resource file name and constructs an ArgumentMatchValue from it.
+ *
+ * If the list name has already been processed in the current list, throws a UserException, otherwise
+ * creates an ArgumentMatchValue to represent the list.
+ *
+ * @param token Name of the ROD resource file.
+ * @param fileValues Set of names of ROD files that have already been processed.
+ * @param fieldName Name of the argument field being populated.
+ * @param listFileName Name of the list file being processed.
+ * @return
+ */
+ private static ArgumentMatchValue parseAndValidateArgumentMatchValue(final String token, final Set<String> fileValues, final String fieldName,
+ final String listFileName) {
+ checkForDuplicateFileName(token, fileValues, fieldName, listFileName);
+ return new ArgumentMatchStringValue(token);
+ }
+
+ /**
+ * Checks to make sure that the current file name to be processed has not already been processed.
+ *
+ * Checks the name of the current file against the names that have already been processed, throwing
+ * an informative BadArgumentValue exception if it has already been seen. As a side effect adds the
+ * current file name to the set of filenames that have already been processed.
+ *
+ * @param currentFile Name of the current file to process
+ * @param processedFiles Set of file names that have already been processed
+ * @param fieldName Name of the argument that is being populated
+ * @param listName Filename of the list that is being processed
+ */
+ protected static void checkForDuplicateFileName(final String currentFile, final Set<String> processedFiles,
+ final String fieldName, final String listName) {
+ if (processedFiles.contains(currentFile)) {
+ throw new UserException.BadArgumentValue(fieldName, "The input list " + listName + " contains file " + currentFile +
+ " multiple times, which isn't allowed. If you are intentionally trying to " +
+ "include the same file more than once, you will need to specify it in separate file lists.");
+ }
+ processedFiles.add(currentFile);
+ }
+}
+
+/**
+ * Parser for RodBinding objects
+ */
+class RodBindingArgumentTypeDescriptor extends ArgumentTypeDescriptor {
+ /**
+ * We only want RodBinding class objects
+ * @param type The type to check.
+ * @return true if the provided class is a RodBinding.class
+ */
+ @Override
+ public boolean supports( Class type ) {
+ return isRodBinding(type);
+ }
+
+ public static boolean isRodBinding( Class type ) {
+ return RodBinding.class.isAssignableFrom(type);
+ }
+
+ @Override
+ public boolean createsTypeDefault(ArgumentSource source) { return ! source.isRequired(); }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object createTypeDefault(ParsingEngine parsingEngine, ArgumentSource source, Type type) {
+ Class parameterType = JVMUtils.getParameterizedTypeClass(type);
+ return RodBinding.makeUnbound((Class<? extends Feature>)parameterType);
+ }
+
+ @Override
+ public String typeDefaultDocString(ArgumentSource source) {
+ return "none";
+ }
+
+ @Override
+ public Object parse(ParsingEngine parsingEngine, ArgumentSource source, Type type, ArgumentMatches matches) {
+ Tags tags = getArgumentTags(matches);
+ RodBinding rbind = (RodBinding)parseBinding(source, type, matches, tags);
+ parsingEngine.addTags(rbind, tags);
+ parsingEngine.addRodBinding(rbind);
+ return rbind;
+ }
+}
+
+/**
+ * Parser for IntervalBinding objects
+ */
+class IntervalBindingArgumentTypeDescriptor extends ArgumentTypeDescriptor {
+ /**
+ * We only want IntervalBinding class objects
+ * @param type The type to check.
+ * @return true if the provided class is an IntervalBinding.class
+ */
+ @Override
+ public boolean supports( Class type ) {
+ return isIntervalBinding(type);
+ }
+
+ public static boolean isIntervalBinding( Class type ) {
+ return IntervalBinding.class.isAssignableFrom(type);
+ }
+
+ /**
+ * See note from RodBindingArgumentTypeDescriptor.parse().
+ *
+ * @param parsingEngine parsing engine
+ * @param source source
+ * @param type type to check
+ * @param matches matches
+ * @return the IntervalBinding object.
+ */
+ @Override
+ public Object parse(ParsingEngine parsingEngine, ArgumentSource source, Type type, ArgumentMatches matches) {
+ return parseBinding(source, type, matches, getArgumentTags(matches));
+ }
+}
+
+/**
+ * Parser for RodBindingCollection objects
+ */
+class RodBindingCollectionArgumentTypeDescriptor extends ArgumentTypeDescriptor {
+ /**
+ * We only want RodBindingCollection class objects
+ * @param type The type to check.
+ * @return true if the provided class is an RodBindingCollection.class
+ */
+ @Override
+ public boolean supports( final Class type ) {
+ return isRodBindingCollection(type);
+ }
+
+ public static boolean isRodBindingCollection( final Class type ) {
+ return RodBindingCollection.class.isAssignableFrom(type);
+ }
+
+ /**
+ * See note from RodBindingArgumentTypeDescriptor.parse().
+ *
+ * @param parsingEngine parsing engine
+ * @param source source
+ * @param type type to check
+ * @param matches matches
+ * @return the IntervalBinding object.
+ */
+ @Override
+ public Object parse(final ParsingEngine parsingEngine, final ArgumentSource source, final Type type, final ArgumentMatches matches) {
+ final Tags tags = getArgumentTags(matches);
+ return parseRodBindingCollectionSource(parsingEngine, source, type, matches, tags);
+ }
+}
+
+/**
+ * Parse simple argument types: java primitives, wrapper classes, and anything that has
+ * a simple String constructor.
+ */
+class SimpleArgumentTypeDescriptor extends ArgumentTypeDescriptor {
+
+ /**
+ * @param type the class type
+ * @return true if this class is a binding type, false otherwise
+ */
+ private boolean isBinding(final Class type) {
+ return RodBindingArgumentTypeDescriptor.isRodBinding(type) ||
+ IntervalBindingArgumentTypeDescriptor.isIntervalBinding(type) ||
+ RodBindingCollectionArgumentTypeDescriptor.isRodBindingCollection(type);
+ }
+
+
+ @Override
+ public boolean supports( Class type ) {
+ if ( isBinding(type) ) return false;
+ if ( type.isPrimitive() ) return true;
+ if ( type.isEnum() ) return true;
+ if ( primitiveToWrapperMap.containsValue(type) ) return true;
+
+ try {
+ type.getConstructor(String.class);
+ return true;
+ }
+ catch( Exception ex ) {
+ // An exception thrown above means that the String constructor either doesn't
+ // exist or can't be accessed. In either case, this descriptor doesn't support this type.
+ return false;
+ }
+ }
+
+ @Override
+ public Object parse(ParsingEngine parsingEngine, ArgumentSource source, Type fulltype, ArgumentMatches matches) {
+ Class type = makeRawTypeIfNecessary(fulltype);
+ if (source.isFlag())
+ return true;
+
+ ArgumentDefinition defaultDefinition = createDefaultArgumentDefinition(source);
+ ArgumentMatchValue value = getArgumentValue(defaultDefinition, matches);
+ Object result;
+ Tags tags = getArgumentTags(matches);
+
+ // lets go through the types we support
+ try {
+ if (type.isPrimitive()) {
+ Method valueOf = primitiveToWrapperMap.get(type).getMethod("valueOf",String.class);
+ if(value == null)
+ throw new MissingArgumentValueException(createDefaultArgumentDefinition(source));
+ result = valueOf.invoke(null,value.asString().trim());
+ } else if (type.isEnum()) {
+ Object[] vals = type.getEnumConstants();
+ Object defaultEnumeration = null; // as we look at options, record the default option if it exists
+ for (Object val : vals) {
+ if (String.valueOf(val).equalsIgnoreCase(value == null ? null : value.asString())) return val;
+ try { if (type.getField(val.toString()).isAnnotationPresent(EnumerationArgumentDefault.class)) defaultEnumeration = val; }
+ catch (NoSuchFieldException e) { throw new ReviewedGATKException("parsing " + type.toString() + "doesn't contain the field " + val.toString()); }
+ }
+ // if their argument has no value (null), and there's a default, return that default for the enum value
+ if (defaultEnumeration != null && value == null)
+ result = defaultEnumeration;
+ // if their argument has no value and there's no default, throw a missing argument value exception.
+ // TODO: Clean this up so that null values never make it to this point. To fix this, we'll have to clean up the implementation of -U.
+ else if (value == null)
+ throw new MissingArgumentValueException(createDefaultArgumentDefinition(source));
+ else
+ throw new UnknownEnumeratedValueException(createDefaultArgumentDefinition(source),value.asString());
+ } else if (type.equals(File.class)) {
+ result = value == null ? null : value.asFile();
+ } else {
+ if (value == null)
+ throw new MissingArgumentValueException(createDefaultArgumentDefinition(source));
+ Constructor ctor = type.getConstructor(String.class);
+ result = ctor.newInstance(value.asString());
+ }
+ } catch (UserException e) {
+ throw e;
+ } catch (InvocationTargetException e) {
+ throw new UserException.CommandLineException(String.format("Failed to parse value %s for argument %s. This is most commonly caused by providing an incorrect data type (e.g. a double when an int is required)",
+ value, source.field.getName()));
+ } catch (Exception e) {
+ throw new DynamicClassResolutionException(String.class, e);
+ }
+
+ // TODO FIXME!
+
+ // WARNING: Side effect!
+ parsingEngine.addTags(result,tags);
+
+ return result;
+ }
+
+
+ /**
+ * A mapping of the primitive types to their associated wrapper classes. Is there really no way to infer
+ * this association available in the JRE?
+ */
+ private static Map<Class,Class> primitiveToWrapperMap = new HashMap<Class,Class>() {
+ {
+ put( Boolean.TYPE, Boolean.class );
+ put( Character.TYPE, Character.class );
+ put( Byte.TYPE, Byte.class );
+ put( Short.TYPE, Short.class );
+ put( Integer.TYPE, Integer.class );
+ put( Long.TYPE, Long.class );
+ put( Float.TYPE, Float.class );
+ put( Double.TYPE, Double.class );
+ }
+ };
+}
+
+/**
+ * Process compound argument types: arrays, and typed and untyped collections.
+ */
+class CompoundArgumentTypeDescriptor extends ArgumentTypeDescriptor {
+ @Override
+ public boolean supports( Class type ) {
+ return ( Collection.class.isAssignableFrom(type) || type.isArray() );
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object parse(ParsingEngine parsingEngine,ArgumentSource source, Type fulltype, ArgumentMatches matches) {
+ Class type = makeRawTypeIfNecessary(fulltype);
+ Type componentType;
+ Object result;
+
+ if( Collection.class.isAssignableFrom(type) ) {
+
+ // If this is a generic interface, pick a concrete implementation to create and pass back.
+ // Because of type erasure, don't worry about creating one of exactly the correct type.
+ if( Modifier.isInterface(type.getModifiers()) || Modifier.isAbstract(type.getModifiers()) )
+ {
+ if( java.util.List.class.isAssignableFrom(type) ) type = ArrayList.class;
+ else if( java.util.Queue.class.isAssignableFrom(type) ) type = java.util.ArrayDeque.class;
+ else if( java.util.Set.class.isAssignableFrom(type) ) type = java.util.TreeSet.class;
+ }
+
+ componentType = getCollectionComponentType( source.field );
+ ArgumentTypeDescriptor componentArgumentParser = parsingEngine.selectBestTypeDescriptor(makeRawTypeIfNecessary(componentType));
+
+ Collection collection;
+ try {
+ collection = (Collection)type.newInstance();
+ }
+ catch (InstantiationException e) {
+ logger.fatal("ArgumentParser: InstantiationException: cannot convert field " + source.field.getName());
+ throw new ReviewedGATKException("constructFromString:InstantiationException: Failed conversion " + e.getMessage());
+ }
+ catch (IllegalAccessException e) {
+ logger.fatal("ArgumentParser: IllegalAccessException: cannot convert field " + source.field.getName());
+ throw new ReviewedGATKException("constructFromString:IllegalAccessException: Failed conversion " + e.getMessage());
+ }
+
+ for( ArgumentMatch match: matches ) {
+ for( ArgumentMatch value: match ) {
+ Object object = componentArgumentParser.parse(parsingEngine,source,componentType,new ArgumentMatches(value));
+ collection.add( object );
+ // WARNING: Side effect!
+ parsingEngine.addTags(object,value.tags);
+ }
+ }
+
+ result = collection;
+
+ }
+ else if( type.isArray() ) {
+ componentType = type.getComponentType();
+ ArgumentTypeDescriptor componentArgumentParser = parsingEngine.selectBestTypeDescriptor(makeRawTypeIfNecessary(componentType));
+
+ // Assemble a collection of individual values used in this computation.
+ Collection<ArgumentMatch> values = new ArrayList<ArgumentMatch>();
+ for( ArgumentMatch match: matches )
+ for( ArgumentMatch value: match )
+ values.add(value);
+
+ result = Array.newInstance(makeRawTypeIfNecessary(componentType),values.size());
+
+ int i = 0;
+ for( ArgumentMatch value: values ) {
+ Object object = componentArgumentParser.parse(parsingEngine,source,componentType,new ArgumentMatches(value));
+ Array.set(result,i++,object);
+ // WARNING: Side effect!
+ parsingEngine.addTags(object,value.tags);
+ }
+ }
+ else
+ throw new ReviewedGATKException("Unsupported compound argument type: " + type);
+
+ return result;
+ }
+
+ /**
+ * Return the component type of a field, or String.class if the type cannot be found.
+ * @param field The reflected field to inspect.
+ * @return The parameterized component type, or String.class if the parameterized type could not be found.
+ * @throws IllegalArgumentException If more than one parameterized type is found on the field.
+ */
+ @Override
+ protected Type getCollectionComponentType( Field field ) {
+ // If this is a parameterized collection, find the contained type. If blow up if more than one type exists.
+ if( field.getGenericType() instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType)field.getGenericType();
+ if( parameterizedType.getActualTypeArguments().length > 1 )
+ throw new IllegalArgumentException("Unable to determine collection type of field: " + field.toString());
+ return parameterizedType.getActualTypeArguments()[0];
+ }
+ else
+ return String.class;
+ }
+}
+
+class MultiplexArgumentTypeDescriptor extends ArgumentTypeDescriptor {
+ /**
+ * The multiplexer controlling how data is split.
+ */
+ private final Multiplexer multiplexer;
+
+ /**
+ * The set of identifiers for the multiplexed entries.
+ */
+ private final Collection<?> multiplexedIds;
+
+ public MultiplexArgumentTypeDescriptor() {
+ this.multiplexer = null;
+ this.multiplexedIds = null;
+ }
+
+ /**
+ * Private constructor to use in creating a closure of the MultiplexArgumentTypeDescriptor specific to the
+ * given set of multiplexed ids.
+ * @param multiplexedIds The collection of multiplexed entries
+ */
+ private MultiplexArgumentTypeDescriptor(final Multiplexer multiplexer, final Collection<?> multiplexedIds) {
+ this.multiplexer = multiplexer;
+ this.multiplexedIds = multiplexedIds;
+ }
+
+ @Override
+ public boolean supports( Class type ) {
+ return ( Map.class.isAssignableFrom(type) );
+ }
+
+ @Override
+ public boolean createsTypeDefault(ArgumentSource source) {
+ // Multiplexing always creates a type default.
+ return true;
+ }
+
+ @Override
+ public Object createTypeDefault(ParsingEngine parsingEngine,ArgumentSource source, Type type) {
+ if(multiplexer == null || multiplexedIds == null)
+ throw new ReviewedGATKException("No multiplexed ids available");
+
+ Map<Object,Object> multiplexedMapping = new HashMap<Object,Object>();
+ Class componentType = makeRawTypeIfNecessary(getCollectionComponentType(source.field));
+ ArgumentTypeDescriptor componentTypeDescriptor = parsingEngine.selectBestTypeDescriptor(componentType);
+
+ for(Object id: multiplexedIds) {
+ Object value = null;
+ if(componentTypeDescriptor.createsTypeDefault(source))
+ value = componentTypeDescriptor.createTypeDefault(parsingEngine,source,componentType);
+ multiplexedMapping.put(id,value);
+ }
+ return multiplexedMapping;
+ }
+
+ @Override
+ public String typeDefaultDocString(ArgumentSource source) {
+ return "None";
+ }
+
+ @Override
+ public Object parse(ParsingEngine parsingEngine, ArgumentSource source, Type type, ArgumentMatches matches) {
+ if(multiplexedIds == null)
+ throw new ReviewedGATKException("Cannot directly parse a MultiplexArgumentTypeDescriptor; must create a derivative type descriptor first.");
+
+ Map<Object,Object> multiplexedMapping = new HashMap<Object,Object>();
+
+ Class componentType = makeRawTypeIfNecessary(getCollectionComponentType(source.field));
+
+
+ for(Object id: multiplexedIds) {
+ Object value = parsingEngine.selectBestTypeDescriptor(componentType).parse(parsingEngine,source,componentType,matches.transform(multiplexer,id));
+ multiplexedMapping.put(id,value);
+ }
+
+ parsingEngine.addTags(multiplexedMapping,getArgumentTags(matches));
+
+ return multiplexedMapping;
+ }
+
+ public MultiplexArgumentTypeDescriptor createCustomTypeDescriptor(ParsingEngine parsingEngine,ArgumentSource dependentArgument,Object containingObject) {
+ String[] sourceFields = dependentArgument.field.getAnnotation(Multiplex.class).arguments();
+
+ List<ArgumentSource> allSources = parsingEngine.extractArgumentSources(containingObject.getClass());
+ Class[] sourceTypes = new Class[sourceFields.length];
+ Object[] sourceValues = new Object[sourceFields.length];
+ int currentField = 0;
+
+ for(String sourceField: sourceFields) {
+ boolean fieldFound = false;
+ for(ArgumentSource source: allSources) {
+ if(!source.field.getName().equals(sourceField))
+ continue;
+ if(source.field.isAnnotationPresent(Multiplex.class))
+ throw new ReviewedGATKException("Command-line arguments can only depend on independent fields");
+ sourceTypes[currentField] = source.field.getType();
+ sourceValues[currentField] = JVMUtils.getFieldValue(source.field,containingObject);
+ currentField++;
+ fieldFound = true;
+ }
+ if(!fieldFound)
+ throw new ReviewedGATKException(String.format("Unable to find source field %s, referred to by dependent field %s",sourceField,dependentArgument.field.getName()));
+ }
+
+ Class<? extends Multiplexer> multiplexerType = dependentArgument.field.getAnnotation(Multiplex.class).value();
+ Constructor<? extends Multiplexer> multiplexerConstructor;
+ try {
+ multiplexerConstructor = multiplexerType.getConstructor(sourceTypes);
+ multiplexerConstructor.setAccessible(true);
+ }
+ catch(NoSuchMethodException ex) {
+ throw new ReviewedGATKException(String.format("Unable to find constructor for class %s with parameters %s",multiplexerType.getName(),Arrays.deepToString(sourceFields)),ex);
+ }
+
+ Multiplexer multiplexer;
+ try {
+ multiplexer = multiplexerConstructor.newInstance(sourceValues);
+ }
+ catch(IllegalAccessException ex) {
+ throw new ReviewedGATKException(String.format("Constructor for class %s with parameters %s is inaccessible",multiplexerType.getName(),Arrays.deepToString(sourceFields)),ex);
+ }
+ catch(InstantiationException ex) {
+ throw new ReviewedGATKException(String.format("Can't create class %s with parameters %s",multiplexerType.getName(),Arrays.deepToString(sourceFields)),ex);
+ }
+ catch(InvocationTargetException ex) {
+ throw new ReviewedGATKException(String.format("Can't invoke constructor of class %s with parameters %s",multiplexerType.getName(),Arrays.deepToString(sourceFields)),ex);
+ }
+
+ return new MultiplexArgumentTypeDescriptor(multiplexer,multiplexer.multiplex());
+ }
+
+ /**
+ * Return the component type of a field, or String.class if the type cannot be found.
+ * @param field The reflected field to inspect.
+ * @return The parameterized component type, or String.class if the parameterized type could not be found.
+ * @throws IllegalArgumentException If more than one parameterized type is found on the field.
+ */
+ @Override
+ protected Type getCollectionComponentType( Field field ) {
+ // Multiplex arguments must resolve to maps from which the clp should extract the second type.
+ if( field.getGenericType() instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType)field.getGenericType();
+ if( parameterizedType.getActualTypeArguments().length != 2 )
+ throw new IllegalArgumentException("Unable to determine collection type of field: " + field.toString());
+ return (Class)parameterizedType.getActualTypeArguments()[1];
+ }
+ else
+ return String.class;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ClassType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ClassType.java
new file mode 100644
index 0000000..d57d326
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ClassType.java
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotates generic fields where the parameterized type is not specified or erased.
+ * Primarily used for Queue traits. Defined in java since scala does not support RetentionPolicy.RUNTIME.
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.FIELD})
+public @interface ClassType {
+ Class value();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/CommandLineProgram.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/CommandLineProgram.java
new file mode 100644
index 0000000..80ebe2c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/CommandLineProgram.java
@@ -0,0 +1,447 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.apache.log4j.FileAppender;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PatternLayout;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.help.ApplicationDetails;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.help.HelpFormatter;
+
+import java.io.IOException;
+import java.util.*;
+
+public abstract class CommandLineProgram {
+
+ /** The command-line program and the arguments it returned. */
+ public ParsingEngine parser = null;
+
+ /**
+ * Setting INFO gets you INFO up to FATAL, setting ERROR gets you ERROR and FATAL level logging, and so on.
+ */
+ @Argument(fullName = "logging_level", shortName = "l", doc = "Set the minimum level of logging", required = false)
+ protected String logging_level = "INFO";
+
+ /**
+ * File to save the logging output.
+ */
+ @Output(fullName = "log_to_file", shortName = "log", doc = "Set the logging location", required = false)
+ protected String toFile = null;
+
+ /**
+ * This will produce a help message in the terminal with general usage information, listing available arguments
+ * as well as tool-specific information if applicable.
+ */
+ @Argument(fullName = "help", shortName = "h", doc = "Generate the help message", required = false)
+ public Boolean help = false;
+
+ /**
+ * Use this to check the version number of the GATK executable you are invoking. Note that the version number is
+ * always included in the output at the start of every run as well as any error message.
+ */
+ @Argument(fullName = "version", shortName = "version", doc ="Output version information", required = false)
+ public Boolean version = false;
+
+
+ /** our logging output patterns */
+ private static final String patternString = "%-5p %d{HH:mm:ss,SSS} %C{1} - %m %n";
+
+ static {
+ /**
+ * The very first thing that any GATK application does is forces the JVM locale into US English, so that we don't have
+ * to think about number formatting issues.
+ */
+ forceJVMLocaleToUSEnglish();
+ // setup a basic log configuration
+ CommandLineUtils.configureConsoleLogging();
+ }
+
+
+ /**
+ * Allows a given application to return a brief description of itself.
+ *
+ * @return An ApplicationDetails object describing the current application. Should not be null.
+ */
+ protected ApplicationDetails getApplicationDetails() {
+ return new ApplicationDetails(ApplicationDetails.createDefaultHeader(getClass()),
+ Collections.<String>emptyList(),
+ ApplicationDetails.createDefaultRunningInstructions(getClass()),
+ null);
+ }
+
+ /**
+ * Subclasses of CommandLinePrograms can provide their own types of command-line arguments.
+ * @return A collection of type descriptors generating implementation-dependent placeholders.
+ */
+ protected Collection<ArgumentTypeDescriptor> getArgumentTypeDescriptors() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Will this application want to vary its argument list dynamically?
+ * If so, parse the command-line options and then prompt the subclass to return
+ * a list of argument providers.
+ *
+ * @return Whether the application should vary command-line arguments dynamically.
+ */
+ protected boolean canAddArgumentsDynamically() { return false; }
+
+ /**
+ * Provide a list of object to inspect, looking for additional command-line arguments.
+ *
+ * @return A list of objects to inspect.
+ */
+ protected Class[] getArgumentSources() {
+ return new Class[]{};
+ }
+
+ /**
+ * Name this argument source. Provides the (full) class name as a default.
+ *
+ * @param source The argument source.
+ *
+ * @return a name for the argument source.
+ */
+ protected String getArgumentSourceName( Class source ) { return source.toString(); }
+
+ /**
+ * Sets the command-line parsing engine. Necessary for unit testing purposes.
+ * @param parser the new command-line parsing engine
+ */
+ public void setParser( ParsingEngine parser ) {
+ this.parser = parser;
+ }
+
+ /**
+ * this is the function that the inheriting class can expect to have called
+ * when all the argument processing is done
+ *
+ * @return the return code to exit the program with
+ * @throws Exception when an exception occurs
+ */
+ protected abstract int execute() throws Exception;
+
+ public static int result = -1;
+
+ @SuppressWarnings("unchecked")
+ public static void start(CommandLineProgram clp, String[] args) throws Exception {
+ start(clp, args, false);
+ }
+
+ /**
+ * This function is called to start processing the command line, and kick
+ * off the execute message of the program.
+ *
+ * @param clp the command line program to execute
+ * @param args the command line arguments passed in
+ * @param dryRun dry run
+ * @throws Exception when an exception occurs
+ */
+ @SuppressWarnings("unchecked")
+ public static void start(CommandLineProgram clp, String[] args, boolean dryRun) throws Exception {
+
+ try {
+ // setup our log layout
+ PatternLayout layout = new PatternLayout();
+
+ Logger logger = CommandLineUtils.getStingLogger();
+
+ // now set the layout of all the loggers to our layout
+ CommandLineUtils.setLayout(logger, layout);
+
+ // Initialize the logger using the defaults.
+ clp.setupLoggerLevel(layout);
+
+ // setup the parser
+ ParsingEngine parser = clp.parser = new ParsingEngine(clp);
+ parser.addArgumentSource(clp.getClass());
+
+ Map<ArgumentMatchSource, ParsedArgs> parsedArgs;
+
+ // process the args
+ if (clp.canAddArgumentsDynamically()) {
+ // if the command-line program can toss in extra args, fetch them and reparse the arguments.
+ parser.parse(args);
+
+ // Allow invalid and missing required arguments to pass this validation step.
+ // - InvalidArgument in case these arguments are specified by plugins.
+ // - MissingRequiredArgument in case the user requested help. Handle that later, once we've
+ // determined the full complement of arguments.
+ if ( ! dryRun )
+ parser.validate(EnumSet.of(ParsingEngine.ValidationType.MissingRequiredArgument,
+ ParsingEngine.ValidationType.InvalidArgument));
+ parser.loadArgumentsIntoObject(clp);
+
+ // Initialize the logger using the loaded command line.
+ clp.setupLoggerLevel(layout);
+
+ Class[] argumentSources = clp.getArgumentSources();
+ for (Class argumentSource : argumentSources)
+ parser.addArgumentSource(clp.getArgumentSourceName(argumentSource), argumentSource);
+ parsedArgs = parser.parse(args);
+
+ if (isVersionPresent(parser))
+ printVersionAndExit();
+
+ if (isHelpPresent(parser))
+ printHelpAndExit(clp, parser);
+
+ if ( ! dryRun ) parser.validate();
+ } else {
+ parsedArgs = parser.parse(args);
+
+ if ( ! dryRun ) {
+ if (isHelpPresent(parser))
+ printHelpAndExit(clp, parser);
+
+ parser.validate();
+ }
+ parser.loadArgumentsIntoObject(clp);
+
+ // Initialize the logger using the loaded command line.
+ clp.setupLoggerLevel(layout);
+ }
+
+ if ( ! dryRun ) {
+ // if they specify a log location, output our data there
+ if (clp.toFile != null) {
+ FileAppender appender;
+ try {
+ appender = new FileAppender(layout, clp.toFile, false);
+ logger.addAppender(appender);
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to re-route log output to " + clp.toFile + " make sure the destination exists");
+ }
+ }
+
+ // regardless of what happens next, generate the header information
+ HelpFormatter.generateHeaderInformation(clp.getApplicationDetails(), parsedArgs);
+
+ // call the execute
+ CommandLineProgram.result = clp.execute();
+ }
+ }
+ catch (ArgumentException e) {
+ //clp.parser.printHelp(clp.getApplicationDetails());
+ // Rethrow the exception to exit with an error.
+ throw e;
+ }
+ }
+
+ /**
+ * Find fields in the object obj that look like command-line arguments, and put command-line
+ * arguments into them.
+ *
+ * @param obj Object to inspect for command line arguments.
+ */
+ public void loadArgumentsIntoObject(Object obj) {
+ parser.loadArgumentsIntoObject(obj);
+ }
+
+ /**
+ * this function checks the logger level passed in on the command line, taking the lowest
+ * level that was provided.
+ * @param layout Pattern layout to format based on the logger level.
+ */
+ private void setupLoggerLevel(PatternLayout layout) {
+ layout.setConversionPattern(patternString);
+
+ // set the default logger level
+ Level par;
+ if (logging_level.toUpperCase().equals("DEBUG")) {
+ par = Level.DEBUG;
+ } else if (logging_level.toUpperCase().equals("INFO")) {
+ par = Level.INFO;
+ } else if (logging_level.toUpperCase().equals("WARN")) {
+ par = Level.WARN;
+ } else if (logging_level.toUpperCase().equals("ERROR")) {
+ par = Level.ERROR;
+ } else if (logging_level.toUpperCase().equals("FATAL")) {
+ par = Level.FATAL;
+ } else if (logging_level.toUpperCase().equals("OFF")) {
+ par = Level.OFF;
+ } else {
+ // we don't understand the logging level, let's get out of here
+ throw new ArgumentException("Unable to match: " + logging_level + " to a logging level, make sure it's a valid level (DEBUG, INFO, WARN, ERROR, FATAL, OFF)");
+ }
+
+ Logger.getRootLogger().setLevel(par);
+ }
+
+ /**
+ * a function used to indicate an error occurred in the command line tool
+ */
+ private static void printDocumentationReference() {
+ errorPrintf("Visit our website and forum for extensive documentation and answers to %n");
+ errorPrintf("commonly asked questions " + HelpConstants.BASE_GATK_URL + "%n");
+ }
+
+
+ /**
+ * Do a cursory search for the given argument.
+ *
+ * @param parser Parser
+ *
+ * @return True if help is present; false otherwise.
+ */
+ private static boolean isHelpPresent(ParsingEngine parser) {
+ return parser.isArgumentPresent("help");
+ }
+
+ /**
+ * Print help and exit.
+ *
+ * @param clp Instance of the command-line program.
+ * @param parser True if help is present; false otherwise.
+ */
+ private static void printHelpAndExit(CommandLineProgram clp, ParsingEngine parser) {
+ parser.printHelp(clp.getApplicationDetails());
+ System.exit(0);
+ }
+
+ /**
+ * Do a cursory search for the argument "version".
+ *
+ * @param parser Parser
+ *
+ * @return True if version is present; false otherwise.
+ */
+ private static boolean isVersionPresent(ParsingEngine parser) {
+ return parser.isArgumentPresent("version");
+ }
+
+ /**
+ * Print help and exit.
+ */
+ private static void printVersionAndExit() {
+ System.out.println(CommandLineGATK.getVersionNumber().toString());
+ System.exit(0);
+ }
+
+
+ private static void errorPrintf(String format, Object... s) {
+ String formatted = String.format(format, s);
+
+ if ( formatted.trim().equals("") )
+ System.err.println("##### ERROR");
+ else {
+ for ( String part : formatted.split("\n") ) {
+ System.err.println("##### ERROR " + part);
+ }
+ }
+ }
+
+
+ /**
+ * used to indicate an error occured
+ *
+ * @param msg the message
+ * @param t the error
+ */
+ public static void exitSystemWithError(String msg, final Throwable t) {
+ errorPrintf("------------------------------------------------------------------------------------------%n");
+ errorPrintf("stack trace %n");
+ t.printStackTrace();
+
+ errorPrintf("------------------------------------------------------------------------------------------%n");
+ errorPrintf("A GATK RUNTIME ERROR has occurred (version %s):%n", CommandLineGATK.getVersionNumber());
+ errorPrintf("%n");
+ errorPrintf("This might be a bug. Please check the documentation guide to see if this is a known problem.%n");
+ errorPrintf("If not, please post the error message, with stack trace, to the GATK forum.%n");
+ printDocumentationReference();
+ if ( msg == null ) // some exceptions don't have detailed messages
+ msg = "Code exception (see stack trace for error itself)";
+ errorPrintf("%n");
+ errorPrintf("MESSAGE: %s%n", msg.trim());
+ errorPrintf("------------------------------------------------------------------------------------------%n");
+ System.exit(1);
+ }
+
+ public static void exitSystemWithUserError(final Exception e) {
+ if ( e.getMessage() == null )
+ throw new ReviewedGATKException("UserException found with no message!", e);
+
+ errorPrintf("------------------------------------------------------------------------------------------%n");
+ errorPrintf("A USER ERROR has occurred (version %s): %n", CommandLineGATK.getVersionNumber());
+ errorPrintf("%n");
+ errorPrintf("This means that one or more arguments or inputs in your command are incorrect.%n");
+ errorPrintf("The error message below tells you what is the problem.%n");
+ errorPrintf("%n");
+ errorPrintf("If the problem is an invalid argument, please check the online documentation guide%n");
+ errorPrintf("(or rerun your command with --help) to view allowable command-line arguments for this tool.%n");
+ errorPrintf("%n");
+ printDocumentationReference();
+ errorPrintf("%n");
+ errorPrintf("Please do NOT post this error to the GATK forum unless you have really tried to fix it yourself.%n");
+ errorPrintf("%n");
+ errorPrintf("MESSAGE: %s%n", e.getMessage().trim());
+ errorPrintf("------------------------------------------------------------------------------------------%n");
+ System.exit(1);
+ }
+
+ public static void exitSystemWithSamError(final Throwable t) {
+ if ( t.getMessage() == null )
+ throw new ReviewedGATKException("SamException found with no message!", t);
+
+ errorPrintf("------------------------------------------------------------------------------------------%n");
+ errorPrintf("A BAM ERROR has occurred (version %s): %n", CommandLineGATK.getVersionNumber());
+ errorPrintf("%n");
+ errorPrintf("This means that there is something wrong with the BAM file(s) you provided.%n");
+ errorPrintf("The error message below tells you what is the problem.%n");
+ errorPrintf("%n");
+ printDocumentationReference();
+ errorPrintf("%n");
+ errorPrintf("Please do NOT post this error to the GATK forum until you have followed these instructions:%n");
+ errorPrintf("- Make sure that your BAM file is well-formed by running Picard's validator on it%n");
+ errorPrintf("(see http://picard.sourceforge.net/command-line-overview.shtml#ValidateSamFile for details)%n");
+ errorPrintf("- Ensure that your BAM index is not corrupted: delete the current one and regenerate it with 'samtools index'%n");
+ errorPrintf("%n");
+ errorPrintf("MESSAGE: %s%n", t.getMessage().trim());
+ errorPrintf("------------------------------------------------------------------------------------------%n");
+ System.exit(1);
+ }
+
+
+ /**
+ * used to indicate an error occured
+ *
+ * @param t the exception that occurred
+ */
+ public static void exitSystemWithError(Throwable t) {
+ exitSystemWithError(t.getMessage(), t);
+ }
+
+ /**
+ * A hack to ensure that numbers are always formatted in the US style.
+ */
+ protected static void forceJVMLocaleToUSEnglish() {
+ Locale.setDefault(Locale.US);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/CommandLineUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/CommandLineUtils.java
new file mode 100644
index 0000000..70f5532
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/CommandLineUtils.java
@@ -0,0 +1,192 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.ConsoleAppender;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PatternLayout;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Static utility methods for working with command-line arguments.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class CommandLineUtils {
+
+ /**
+ * Returns a key-value mapping of the command-line arguments passed into the GATK.
+ * Will be approximate; this class doesn't have all the required data to completely
+ * reconstruct the list of command-line arguments from the given objects.
+ *
+ * @param parsingEngine The parsing engine
+ * @param argumentProviders The providers of command-line arguments.
+ * @return A key-value mapping of argument full names to argument values. Produces best string representation
+ * possible given the information available.
+ */
+ public static Map<String,String> getApproximateCommandLineArguments(ParsingEngine parsingEngine, Object... argumentProviders) {
+ return getApproximateCommandLineArguments(parsingEngine, false, argumentProviders);
+ }
+
+ /**
+ * Returns a key-value mapping of the command-line arguments passed into the GATK.
+ * Will be approximate; this class doesn't have all the required data to completely
+ * reconstruct the list of command-line arguments from the given objects.
+ *
+ * @param parsingEngine The parsing engine
+ * @param skipObjectPointers Should we skip arguments whose values are pointers (and don't print nicely)?
+ * @param argumentProviders The providers of command-line arguments.
+ * @return A key-value mapping of argument full names to argument values. Produces best string representation
+ * possible given the information available.
+ */
+ public static Map<String,String> getApproximateCommandLineArguments(ParsingEngine parsingEngine, boolean skipObjectPointers, Object... argumentProviders) {
+ Map<String,String> commandLineArguments = new LinkedHashMap<String,String>();
+
+ for(Object argumentProvider: argumentProviders) {
+ Map<ArgumentSource, Object> argBindings = parsingEngine.extractArgumentBindings(argumentProvider);
+ for(Map.Entry<ArgumentSource, Object> elt: argBindings.entrySet()) {
+ Object argumentValue = elt.getValue();
+
+ String argumentValueString = argumentValue != null ? argumentValue.toString() : null;
+ if ( skipObjectPointers && isObjectPointer(argumentValueString) )
+ continue;
+
+ for(ArgumentDefinition definition: elt.getKey().createArgumentDefinitions()) {
+ String argumentName = definition.fullName;
+ commandLineArguments.put(argumentName,argumentValueString);
+ }
+ }
+ }
+
+ return commandLineArguments;
+ }
+
+ /**
+ * Create an approximate list of command-line arguments based on the given argument providers.
+ * @param parsingEngine The parsing engine
+ * @param argumentProviders Argument providers to inspect.
+ * @return A string representing the given command-line arguments.
+ */
+ public static String createApproximateCommandLineArgumentString(ParsingEngine parsingEngine, Object... argumentProviders) {
+ return createApproximateCommandLineArgumentString(parsingEngine, true, argumentProviders);
+ }
+
+ /**
+ * Create an approximate list of command-line arguments based on the given argument providers.
+ * @param parsingEngine The parsing engine
+ * @param skipObjectPointers Should we skip arguments whose values are pointers (and don't print nicely)?
+ * @param argumentProviders Argument providers to inspect.
+ * @return A string representing the given command-line arguments.
+ */
+ public static String createApproximateCommandLineArgumentString(ParsingEngine parsingEngine, boolean skipObjectPointers, Object... argumentProviders) {
+ Map<String,String> commandLineArgs = getApproximateCommandLineArguments(parsingEngine, skipObjectPointers, argumentProviders);
+ StringBuffer sb = new StringBuffer();
+
+ boolean first = true;
+ for ( Map.Entry<String, String> commandLineArg : commandLineArgs.entrySet() ) {
+ if ( !first )
+ sb.append(" ");
+ sb.append(commandLineArg.getKey());
+ sb.append("=");
+ sb.append(commandLineArg.getValue());
+ first = false;
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * A hack to get around the fact that Java doesn't like inheritance in Annotations.
+ * @param annotation to run the method on
+ * @param method the method to invoke
+ * @return the return value of the method
+ */
+ public static Object getValue(Annotation annotation, String method) {
+ try {
+ return annotation.getClass().getMethod(method).invoke(annotation);
+ } catch (Exception e) {
+ throw new ReviewedGATKException("Unable to access method " + method + " on annotation " + annotation.getClass(), e);
+ }
+ }
+
+ // The problem here is that some of the fields being output are Objects - and those
+ // Objects don't overload toString() so that the output is just the memory pointer
+ // to the Object. Because those values are non-deterministic, they don't merge well
+ // into BAM/VCF headers (plus, it's just damn ugly). Perhaps there's a better way to
+ // do this, but at least this one works for the moment.
+ private static final String pointerRegexp = ".+@[0-9a-fA-F]+$";
+ private static boolean isObjectPointer(String s) {
+ return s != null && s.matches(pointerRegexp);
+ }
+
+ /**
+ * Returns the root logger for all GATK code.
+ * @return the root logger for all GATK code.
+ */
+ public static Logger getStingLogger() {
+ return Logger.getLogger("org.broadinstitute.gatk");
+ }
+
+ /**
+ * Enables console logging.
+ */
+ @SuppressWarnings("unchecked")
+ public static void configureConsoleLogging() {
+ // Check to see if a console logger has already been enabled.
+ for (Logger logger = getStingLogger(); logger != null; logger = (Logger)logger.getParent()) {
+ Enumeration<Appender> e = (Enumeration<Appender>) logger.getAllAppenders();
+ for (Appender appender: Collections.list(e)) {
+ if (appender instanceof ConsoleAppender)
+ return;
+ }
+ }
+ // Extracted from BasicConfigurator.configure(), but only applied to the GATK logger.
+ Logger.getRootLogger().addAppender(new ConsoleAppender(
+ new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN), ConsoleAppender.SYSTEM_ERR));
+ }
+
+ /**
+ * Sets the layout of the logger.
+ * @param logger The logger.
+ * @param layout The layout.
+ */
+ @SuppressWarnings("unchecked")
+ public static void setLayout(Logger logger, PatternLayout layout) {
+ for (; logger != null; logger = (Logger)logger.getParent()) {
+ Enumeration<Appender> e = (Enumeration<Appender>) logger.getAllAppenders();
+ for (Appender appender: Collections.list(e))
+ appender.setLayout(layout);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/EnumerationArgumentDefault.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/EnumerationArgumentDefault.java
new file mode 100644
index 0000000..3bbdedb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/EnumerationArgumentDefault.java
@@ -0,0 +1,65 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author aaron
+ * <p/>
+ * Annotation EnumerationArgumentDefault
+ * <p/>
+ * Allows the default argument value to be set for an enum; this allows us to treat enums as
+ * booleans on the command line. I.e.
+ *
+ * if we're using an enum Shape,
+ *
+ * enum shape {
+ * SQUARE,
+ * CIRCLE,
+ * @EnumerationArgumentDefault
+ * TRIANGLE
+ * }
+ *
+ * and a command line option -shape, the EnumerationArgumentDefault would allow you to say:
+ * -shape
+ * or
+ * -shape TRIANGLE
+ *
+ * would get -shape set to TRIANGLE, where:
+ *
+ * -shape SQUARE
+ *
+ * would set shape to SQUARE
+ *
+ */
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.FIELD)
+public @interface EnumerationArgumentDefault {
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Gather.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Gather.java
new file mode 100644
index 0000000..b291663
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Gather.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.lang.annotation.*;
+
+/**
+ * Specifies the class type to gather an @Output
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.FIELD})
+public @interface Gather {
+ Class value() default Gather.class;
+ String className() default "";
+ boolean enabled() default true;
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Gatherer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Gatherer.java
new file mode 100644
index 0000000..761611f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Gatherer.java
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Combines a list of files into a single output.
+ */
+public abstract class Gatherer {
+ /**
+ * Gathers a list of files into a single output.
+ * @param inputs Files to combine.
+ * @param output Path to output file.
+ */
+ public abstract void gather(List<File> inputs, File output);
+
+ /**
+ * Returns true if the caller should wait for the input files to propagate over NFS before running gather().
+ * @return true if the caller should wait for the input files to propagate over NFS before running gather().
+ */
+ public boolean waitForInputs() { return true; }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Hidden.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Hidden.java
new file mode 100644
index 0000000..02325a7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Hidden.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.lang.annotation.*;
+
+/**
+ * Indicates that a walker or walker argument should not be presented in the help system.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE,ElementType.FIELD})
+public @interface Hidden {
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Input.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Input.java
new file mode 100644
index 0000000..8ec0483
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Input.java
@@ -0,0 +1,83 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotates fields in objects that should be used as command-line arguments.
+ * Any field annotated with @Input can appear as a command-line parameter.
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.FIELD)
+public @interface Input {
+ /**
+ * The full name of the command-line argument. Full names should be
+ * prefixed on the command-line with a double dash (--).
+ * @return Selected full name, or "" to use the default.
+ */
+ String fullName() default "";
+
+ /**
+ * Specified short name of the command. Short names should be prefixed
+ * with a single dash. Argument values can directly abut single-char
+ * short names or be separated from them by a space.
+ * @return Selected short name, or "" for none.
+ */
+ String shortName() default "";
+
+ /**
+ * Documentation for the command-line argument. Should appear when the
+ * --help argument is specified.
+ * @return Doc string associated with this command-line argument.
+ */
+ String doc() default "Undocumented option";
+
+ /**
+ * Is this argument required. If true, the command-line argument system will
+ * make a best guess for populating this argument based on the type descriptor,
+ * and will fail if the type can't be populated.
+ * @return True if the argument is required. False otherwise.
+ */
+ boolean required() default true;
+
+ /**
+ * Should this command-line argument be exclusive of others. Should be
+ * a comma-separated list of names of arguments of which this should be
+ * independent.
+ * @return A comma-separated string listing other arguments of which this
+ * argument should be independent.
+ */
+ String exclusiveOf() default "";
+
+ /**
+ * Provide a regexp-based validation string.
+ * @return Non-empty regexp for validation, blank otherwise.
+ */
+ String validation() default "";
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/IntervalArgumentCollection.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/IntervalArgumentCollection.java
new file mode 100644
index 0000000..717a077
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/IntervalArgumentCollection.java
@@ -0,0 +1,88 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.interval.IntervalSetRule;
+
+import java.util.List;
+
+public class IntervalArgumentCollection {
+ /**
+ * Use this option to perform the analysis over only part of the genome. This argument can be specified multiple times.
+ * You can use samtools-style intervals either explicitly on the command line (e.g. -L chr1 or -L chr1:100-200) or
+ * by loading in a file containing a list of intervals (e.g. -L myFile.intervals).
+ *
+ * Additionally, you can also specify a ROD file (such as a VCF file) in order to perform the analysis at specific
+ * positions based on the records present in the file (e.g. -L file.vcf).
+ *
+ * Finally, you can also use this to perform the analysis on the reads that are completely unmapped in the BAM file
+ * (i.e. those without a reference contig) by specifying -L unmapped.
+ */
+ @Input(fullName = "intervals", shortName = "L", doc = "One or more genomic intervals over which to operate", required = false)
+ public List<IntervalBinding<Feature>> intervals = null;
+
+ /**
+ * Use this option to exclude certain parts of the genome from the analysis (like -L, but the opposite).
+ * This argument can be specified multiple times. You can use samtools-style intervals either explicitly on the
+ * command line (e.g. -XL chr1 or -XL chr1:100-200) or by loading in a file containing a list of intervals
+ * (e.g. -XL myFile.intervals).
+ *
+ * Additionally, you can also specify a ROD file (such as a VCF file) in order to exclude specific
+ * positions from the analysis based on the records present in the file (e.g. -XL file.vcf).
+ * */
+ @Input(fullName = "excludeIntervals", shortName = "XL", doc = "One or more genomic intervals to exclude from processing", required = false)
+ public List<IntervalBinding<Feature>> excludeIntervals = null;
+
+ /**
+ * By default, the program will take the UNION of all intervals specified using -L and/or -XL. However, you can
+ * change this setting for -L, for example if you want to take the INTERSECTION of the sets instead. E.g. to perform the
+ * analysis on positions for which there is a record in a VCF, but restrict this to just those on chromosome 20,
+ * you would do -L chr20 -L file.vcf -isr INTERSECTION. However, it is not possible to modify the merging approach
+ * for intervals passed using -XL (they will always be merged using UNION).
+ *
+ * Note that if you specify both -L and -XL, the -XL interval set will be subtracted from the -L interval set.
+ */
+ @Argument(fullName = "interval_set_rule", shortName = "isr", doc = "Set merging approach to use for combining interval inputs", required = false)
+ public IntervalSetRule intervalSetRule = IntervalSetRule.UNION;
+
+ /**
+ * By default, the program merges abutting intervals (i.e. intervals that are directly side-by-side but do not
+ * actually overlap) into a single continuous interval. However you can change this behavior if you want them to be
+ * treated as separate intervals instead.
+ */
+ @Argument(fullName = "interval_merging", shortName = "im", doc = "Interval merging rule for abutting intervals", required = false)
+ public IntervalMergingRule intervalMerging = IntervalMergingRule.ALL;
+
+ /**
+ * Use this to add padding to the intervals specified using -L and/or -XL. For example, '-L chr1:100' with a
+ * padding value of 20 would turn into '-L chr1:80-120'. This is typically used to add padding around exons when
+ * analyzing exomes. The general Broad exome calling pipeline uses 100 bp padding by default.
+ */
+ @Argument(fullName = "interval_padding", shortName = "ip", doc = "Amount of padding (in bp) to add to each interval", required = false, minValue = 0)
+ public int intervalPadding = 0;
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/IntervalBinding.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/IntervalBinding.java
new file mode 100644
index 0000000..59048a9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/IntervalBinding.java
@@ -0,0 +1,106 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import com.google.java.contract.Requires;
+import htsjdk.tribble.AbstractFeatureReader;
+import htsjdk.tribble.Feature;
+import htsjdk.tribble.FeatureCodec;
+import htsjdk.tribble.FeatureReader;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.refdata.ReferenceDependentFeatureCodec;
+import org.broadinstitute.gatk.engine.refdata.tracks.FeatureManager;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.interval.IntervalUtils;
+
+import java.util.*;
+
+/**
+ * An IntervalBinding representing a walker argument that gets bound to either a ROD track or interval string.
+ *
+ * The IntervalBinding<T> is a formal GATK argument that bridges between a walker and
+ * the engine to construct intervals for traversal at runtime. The IntervalBinding can
+ * either be a RodBinding<T>, a string of one interval, or a file with interval strings.
+ * The GATK Engine takes care of initializing the binding when appropriate and determining intervals from it.
+ *
+ * Note that this class is immutable.
+ */
+public final class IntervalBinding<T extends Feature> {
+
+ private RodBinding<T> featureIntervals;
+ private String stringIntervals;
+
+ @Requires({"type != null", "rawName != null", "source != null", "tribbleType != null", "tags != null"})
+ public IntervalBinding(Class<T> type, final String rawName, final String source, final String tribbleType, final Tags tags) {
+ featureIntervals = new RodBinding<>(type, rawName, source, tribbleType, tags);
+ }
+
+ @Requires({"intervalArgument != null"})
+ public IntervalBinding(String intervalArgument) {
+ stringIntervals = intervalArgument;
+ }
+
+ public String getSource() {
+ return ( featureIntervals != null ? featureIntervals.getSource() : stringIntervals );
+ }
+
+ public List<GenomeLoc> getIntervals(final GenomeAnalysisEngine toolkit) {
+ return getIntervals(toolkit.getGenomeLocParser());
+ }
+
+ public List<GenomeLoc> getIntervals(final GenomeLocParser genomeLocParser) {
+ List<GenomeLoc> intervals;
+
+ if ( featureIntervals != null ) {
+ intervals = new ArrayList<>();
+
+ // TODO -- after ROD system cleanup, go through the ROD system so that we can handle things like gzipped files
+
+ final FeatureCodec codec = new FeatureManager().getByName(featureIntervals.getTribbleType()).getCodec();
+ if ( codec instanceof ReferenceDependentFeatureCodec )
+ ((ReferenceDependentFeatureCodec)codec).setGenomeLocParser(genomeLocParser);
+ try {
+ FeatureReader<Feature> reader = AbstractFeatureReader.getFeatureReader(featureIntervals.getSource(), codec, false);
+ for ( Feature feature : reader.iterator() )
+ intervals.add(genomeLocParser.createGenomeLoc(feature));
+ } catch (Exception e) {
+ throw new UserException.MalformedFile(featureIntervals.getSource(), "Problem reading the interval file", e);
+ }
+
+ } else {
+ intervals = IntervalUtils.parseIntervalArguments(genomeLocParser, stringIntervals);
+ }
+
+ Collections.sort(intervals);
+ return intervals;
+ }
+
+ public String toString() {
+ return getSource();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/MissingArgumentValueException.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/MissingArgumentValueException.java
new file mode 100644
index 0000000..f8f3895
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/MissingArgumentValueException.java
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.Utils;
+
+/**
+ * Specifies that a value was missing when attempting to populate an argument.
+ */
+public class MissingArgumentValueException extends ArgumentException {
+ public MissingArgumentValueException( ArgumentDefinition... missingArguments ) {
+ super( formatArguments(missingArguments) );
+ }
+
+ private static String formatArguments( ArgumentDefinition... missingArguments ) {
+ StringBuilder sb = new StringBuilder();
+ for( ArgumentDefinition missingArgument: missingArguments ) {
+ if( missingArgument.shortName != null )
+ sb.append( String.format("%nValue for argument with name '--%s' (-%s) is missing.", missingArgument.fullName, missingArgument.shortName) );
+ else
+ sb.append( String.format("%nValue for argument with name '--%s' is missing.", missingArgument.fullName) );
+ if(missingArgument.validOptions != null)
+ sb.append( String.format(" Valid options are (%s).", Utils.join(",",missingArgument.validOptions)));
+ }
+ return sb.toString();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Output.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Output.java
new file mode 100644
index 0000000..88057a2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Output.java
@@ -0,0 +1,90 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.lang.annotation.*;
+
+/**
+ * Annotates fields in objects that should be used as command-line arguments.
+ * Any field annotated with @Argument can appear as a command-line parameter.
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.FIELD)
+public @interface Output {
+ /**
+ * The full name of the command-line argument. Full names should be
+ * prefixed on the command-line with a double dash (--).
+ * @return Selected full name, or "" to use the default.
+ */
+ String fullName() default "out";
+
+ /**
+ * Specified short name of the command. Short names should be prefixed
+ * with a single dash. Argument values can directly abut single-char
+ * short names or be separated from them by a space.
+ * @return Selected short name, or "" for none.
+ */
+ String shortName() default "o";
+
+ /**
+ * Documentation for the command-line argument. Should appear when the
+ * --help argument is specified.
+ * @return Doc string associated with this command-line argument.
+ */
+ String doc() default "An output file created by the walker. Will overwrite contents if file exists";
+
+ /**
+ * Is this argument required. If true, the command-line argument system will
+ * make a best guess for populating this argument based on the type, and will
+ * fail if the type can't be populated.
+ * @return True if the argument is required. False otherwise.
+ */
+ boolean required() default false;
+
+ /**
+ * If this argument is not required, should it default to use stdout if no
+ * output file is explicitly provided on the command-line?
+ * @return True if the argument should default to stdout. False otherwise.
+ */
+ boolean defaultToStdout() default true;
+
+ /**
+ * Should this command-line argument be exclusive of others. Should be
+ * a comma-separated list of names of arguments of which this should be
+ * independent.
+ * @return A comma-separated string listing other arguments of which this
+ * argument should be independent.
+ */
+ String exclusiveOf() default "";
+
+ /**
+ * Provide a regexp-based validation string.
+ * @return Non-empty regexp for validation, blank otherwise.
+ */
+ String validation() default "";
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsedArgs.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsedArgs.java
new file mode 100644
index 0000000..45cc055
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsedArgs.java
@@ -0,0 +1,38 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+/**
+ * Represents a collection of parsed arguments for an argument source.
+ *
+ * Useful for printing out help documents.
+ */
+public abstract class ParsedArgs {
+ /**
+ * @return A compact description of the arguments from an provider/source.
+ */
+ public abstract String getDescription();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsedListArgs.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsedListArgs.java
new file mode 100644
index 0000000..aa9e186
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsedListArgs.java
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A list of string arguments, usually from the command line or an args list file.
+ */
+public class ParsedListArgs extends ParsedArgs {
+ private final List<String> args = new ArrayList<String>();
+
+ public ParsedListArgs() {
+ }
+
+ public ParsedListArgs(List<String> args) {
+ this.args.addAll(args);
+ }
+
+ public void add(String... args) {
+ this.args.addAll(Arrays.asList(args));
+ }
+
+ @Override
+ public String getDescription() {
+ return StringUtils.join(this.args, " ");
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingEngine.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingEngine.java
new file mode 100644
index 0000000..6244b86
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingEngine.java
@@ -0,0 +1,829 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import com.google.java.contract.Requires;
+import org.apache.commons.io.FileUtils;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.classloader.JVMUtils;
+import org.broadinstitute.gatk.utils.classloader.PluginManager;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.help.ApplicationDetails;
+import org.broadinstitute.gatk.utils.help.HelpFormatter;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * A parser for command-line arguments.
+ */
+public class ParsingEngine {
+
+ /**
+ * The loaded argument sources along with their back definitions.
+ */
+ private Map<ArgumentDefinition,ArgumentSource> argumentSourcesByDefinition = new HashMap<ArgumentDefinition,ArgumentSource>();
+
+ /**
+ * A list of defined arguments against which command lines are matched.
+ * Package protected for testing access.
+ */
+ public ArgumentDefinitions argumentDefinitions = new ArgumentDefinitions();
+
+ /**
+ * A list of matches from defined arguments to command-line text.
+ * Indicates as best as possible where command-line text remains unmatched
+ * to existing arguments.
+ */
+ private ArgumentMatches argumentMatches = null;
+
+ /**
+ * Techniques for parsing and for argument lookup.
+ */
+ private List<ParsingMethod> parsingMethods = new ArrayList<ParsingMethod>();
+
+ /**
+ * All of the RodBinding objects we've seen while parsing
+ */
+ private List<RodBinding> rodBindings = new ArrayList<RodBinding>();
+
+ /**
+ * Class reference to the different types of descriptors that the create method can create.
+ * The type of set used must be ordered (but not necessarily sorted).
+ */
+ private static final Set<ArgumentTypeDescriptor> STANDARD_ARGUMENT_TYPE_DESCRIPTORS = new LinkedHashSet<ArgumentTypeDescriptor>( Arrays.asList(new SimpleArgumentTypeDescriptor(),
+ new IntervalBindingArgumentTypeDescriptor(),
+ new RodBindingArgumentTypeDescriptor(),
+ new RodBindingCollectionArgumentTypeDescriptor(),
+ new CompoundArgumentTypeDescriptor(),
+ new MultiplexArgumentTypeDescriptor()) );
+
+ private Set<ArgumentTypeDescriptor> argumentTypeDescriptors = new LinkedHashSet<ArgumentTypeDescriptor>();
+
+ /**
+ * List of tags associated with the given instantiation of the command-line argument.
+ */
+ private final Map<Object,Tags> tags = new IdentityHashMap<Object,Tags>();
+
+ private PluginManager<ParsingEngineArgumentProvider> argumentProviderPluginManager =
+ new PluginManager<ParsingEngineArgumentProvider>(ParsingEngineArgumentProvider.class);
+
+ /**
+ * our log, which we want to capture anything from org.broadinstitute.gatk
+ */
+ protected static Logger logger = Logger.getLogger(ParsingEngine.class);
+
+ public ParsingEngine( CommandLineProgram clp ) {
+ RodBinding.resetNameCounter();
+ parsingMethods.add( ParsingMethod.FullNameParsingMethod );
+ parsingMethods.add( ParsingMethod.ShortNameParsingMethod );
+
+ // Order matters here! Make sure the clp's new type descriptors go in before the original type descriptors.
+ if(clp != null)
+ argumentTypeDescriptors.addAll(clp.getArgumentTypeDescriptors());
+ argumentTypeDescriptors.addAll(STANDARD_ARGUMENT_TYPE_DESCRIPTORS);
+
+ List<Class<? extends ParsingEngineArgumentProvider>> providers = argumentProviderPluginManager.getPlugins();
+ for (Class<? extends ParsingEngineArgumentProvider> provider: providers) {
+ addArgumentSource(provider);
+ }
+ }
+
+ /**
+ * Add a main argument source. Argument sources are expected to have
+ * any number of fields with an @Argument annotation attached.
+ * @param source An argument source from which to extract command-line arguments.
+ */
+ public void addArgumentSource( Class source ) {
+ addArgumentSource(null, source);
+ }
+
+ public ArgumentMatches getArgumentMatches() {
+ return argumentMatches;
+ }
+
+ /**
+ * Add an argument source. Argument sources are expected to have
+ * any number of fields with an @Argument annotation attached.
+ * @param sourceName name for this argument source. 'Null' indicates that this source should be treated
+ * as the main module.
+ * @param sourceClass A class containing argument sources from which to extract command-line arguments.
+ */
+ public void addArgumentSource( String sourceName, Class sourceClass ) {
+ List<ArgumentDefinition> argumentsFromSource = new ArrayList<ArgumentDefinition>();
+ for( ArgumentSource argumentSource: extractArgumentSources(sourceClass) ) {
+ List<ArgumentDefinition> argumentDefinitions = argumentSource.createArgumentDefinitions();
+ for(ArgumentDefinition argumentDefinition: argumentDefinitions) {
+ argumentSourcesByDefinition.put(argumentDefinition,argumentSource);
+ argumentsFromSource.add( argumentDefinition );
+ }
+ }
+ argumentDefinitions.add( new ArgumentDefinitionGroup(sourceName, argumentsFromSource) );
+ }
+
+ /**
+ * Do a cursory search to see if an argument with the given name is present.
+ * @param argumentFullName full name of the argument.
+ * @return True if the argument is present. False otherwise.
+ */
+ public boolean isArgumentPresent( String argumentFullName ) {
+ ArgumentDefinition definition =
+ argumentDefinitions.findArgumentDefinition(argumentFullName,ArgumentDefinitions.FullNameDefinitionMatcher);
+ return argumentMatches.hasMatch(definition);
+
+ }
+
+ /**
+ * Parse the given set of command-line arguments, returning
+ * an ArgumentMatches object describing the best fit of these
+ * command-line arguments to the arguments that are actually
+ * required.
+ * @param tokens Tokens passed on the command line.
+ * @return The parsed arguments by file.
+ */
+ public SortedMap<ArgumentMatchSource, ParsedArgs> parse( String[] tokens ) {
+ argumentMatches = new ArgumentMatches();
+ SortedMap<ArgumentMatchSource, ParsedArgs> parsedArgs = new TreeMap<ArgumentMatchSource, ParsedArgs>();
+
+ List<String> cmdLineTokens = Arrays.asList(tokens);
+ parse(ArgumentMatchSource.COMMAND_LINE, cmdLineTokens, argumentMatches, parsedArgs);
+
+ List<ParsingEngineArgumentProvider> providers = argumentProviderPluginManager.createAllTypes();
+
+ for (ParsingEngineArgumentProvider provider: providers) {
+ // Load the arguments ONLY into the provider.
+ // Validation may optionally run on the rest of the arguments.
+ loadArgumentsIntoObject(provider);
+ }
+
+ for (ParsingEngineArgumentProvider provider: providers) {
+ provider.parse(this, parsedArgs);
+ }
+
+ return parsedArgs;
+ }
+
+ public void parse(ArgumentMatchSource matchSource, List<String> tokens,
+ ArgumentMatches argumentMatches, SortedMap<ArgumentMatchSource, ParsedArgs> parsedArgs) {
+ ArgumentMatchSite lastArgumentMatchSite = new ArgumentMatchSite(matchSource, -1);
+
+ int i = 0;
+ for (String token: tokens) {
+ // If the token is of argument form, parse it into its own argument match.
+ // Otherwise, pair it with the most recently used argument discovered.
+ ArgumentMatchSite site = new ArgumentMatchSite(matchSource, i);
+ if( isArgumentForm(token) ) {
+ ArgumentMatch argumentMatch = parseArgument( token, site );
+ if( argumentMatch != null ) {
+ argumentMatches.mergeInto( argumentMatch );
+ lastArgumentMatchSite = site;
+ }
+ }
+ else {
+ if( argumentMatches.hasMatch(lastArgumentMatchSite) &&
+ !argumentMatches.getMatch(lastArgumentMatchSite).hasValueAtSite(lastArgumentMatchSite))
+ argumentMatches.getMatch(lastArgumentMatchSite).addValue( lastArgumentMatchSite, new ArgumentMatchStringValue(token) );
+ else
+ argumentMatches.MissingArgument.addValue( site, new ArgumentMatchStringValue(token) );
+
+ }
+ i++;
+ }
+
+ parsedArgs.put(matchSource, new ParsedListArgs(tokens));
+ }
+
+ public void parsePairs(ArgumentMatchSource matchSource, List<Pair<String, ArgumentMatchValue>> tokens,
+ ArgumentMatches argumentMatches, ParsedArgs matchSourceArgs,
+ SortedMap<ArgumentMatchSource, ParsedArgs> parsedArgs) {
+ int i = 0;
+ for (Pair<String, ArgumentMatchValue> pair: tokens) {
+
+ ArgumentMatchSite site = new ArgumentMatchSite(matchSource, i);
+ List<DefinitionMatcher> matchers = Arrays.asList(ArgumentDefinitions.FullNameDefinitionMatcher, ArgumentDefinitions.ShortNameDefinitionMatcher);
+ ArgumentDefinition definition = null;
+ for (DefinitionMatcher matcher: matchers) {
+ definition = argumentDefinitions.findArgumentDefinition( pair.getFirst(), matcher );
+ if (definition != null)
+ break;
+ }
+ if (definition == null)
+ continue;
+ ArgumentMatch argumentMatch = new ArgumentMatch(pair.getFirst(), definition, site, new Tags());
+ argumentMatches.mergeInto(argumentMatch);
+ argumentMatch.addValue(site, pair.getSecond());
+ i++;
+ }
+
+ parsedArgs.put(matchSource, matchSourceArgs);
+ }
+
+ protected List<String> getArguments(File file) {
+ try {
+ if (file.getAbsolutePath().endsWith(".list")) {
+ return getListArguments(file);
+ }
+ } catch (IOException e) {
+ throw new UserException.CouldNotReadInputFile(file, e);
+ }
+ throw new UserException.CouldNotReadInputFile(file, "file extension is not .list");
+ }
+
+ private List<String> getListArguments(File file) throws IOException {
+ ArrayList<String> argsList = new ArrayList<String>();
+ for (String line: FileUtils.readLines(file))
+ argsList.addAll(Arrays.asList(Utils.escapeExpressions(line)));
+ return argsList;
+ }
+
+ public enum ValidationType { MissingRequiredArgument,
+ InvalidArgument,
+ InvalidArgumentValue,
+ ValueMissingArgument,
+ TooManyValuesForArgument,
+ MutuallyExclusive }
+
+ /**
+ * Validates the list of command-line argument matches.
+ */
+ public void validate() {
+ validate( EnumSet.noneOf(ValidationType.class) );
+ }
+
+ /**
+ * Validates the list of command-line argument matches. On failure throws an exception with detailed info about the
+ * particular failures. Takes an EnumSet indicating which validation checks to skip.
+ * @param skipValidationOf List of validation checks to skip.
+ */
+ public void validate( EnumSet<ValidationType> skipValidationOf ) {
+ // Find missing required arguments.
+ if( !skipValidationOf.contains(ValidationType.MissingRequiredArgument) ) {
+ Collection<ArgumentDefinition> requiredArguments =
+ argumentDefinitions.findArgumentDefinitions( true, ArgumentDefinitions.RequiredDefinitionMatcher );
+ Collection<ArgumentDefinition> missingArguments = new ArrayList<ArgumentDefinition>();
+ for( ArgumentDefinition requiredArgument: requiredArguments ) {
+ if( !argumentMatches.hasMatch(requiredArgument) )
+ missingArguments.add( requiredArgument );
+ }
+
+ if( missingArguments.size() > 0 )
+ throw new MissingArgumentException( missingArguments );
+ }
+
+ // Find invalid arguments. Invalid arguments will have a null argument definition.
+ if( !skipValidationOf.contains(ValidationType.InvalidArgument) ) {
+ ArgumentMatches invalidArguments = argumentMatches.findUnmatched();
+ if( invalidArguments.size() > 0 )
+ throw new InvalidArgumentException( invalidArguments );
+ }
+
+ // Find invalid argument values -- invalid arguments are either completely missing or fail the specified 'validation' regular expression.
+ if( !skipValidationOf.contains(ValidationType.InvalidArgumentValue) ) {
+ Collection<ArgumentDefinition> verifiableArguments =
+ argumentDefinitions.findArgumentDefinitions( null, ArgumentDefinitions.VerifiableDefinitionMatcher );
+ Collection<Pair<ArgumentDefinition,String>> invalidValues = new ArrayList<Pair<ArgumentDefinition,String>>();
+ for( ArgumentDefinition verifiableArgument: verifiableArguments ) {
+ ArgumentMatches verifiableMatches = argumentMatches.findMatches( verifiableArgument );
+ // Check to see whether an argument value was specified. Argument values must be provided
+ // when the argument name is specified and the argument is not a flag type.
+ for(ArgumentMatch verifiableMatch: verifiableMatches) {
+ ArgumentSource argumentSource = argumentSourcesByDefinition.get(verifiableArgument);
+ if(verifiableMatch.values().size() == 0 && !verifiableArgument.isFlag && !argumentSource.createsTypeDefault())
+ invalidValues.add(new Pair<ArgumentDefinition,String>(verifiableArgument,null));
+ }
+
+ // Ensure that the field contents meet the validation criteria specified by the regular expression.
+ for( ArgumentMatch verifiableMatch: verifiableMatches ) {
+ for( ArgumentMatchValue value: verifiableMatch.values() ) {
+ if( verifiableArgument.validation != null && !value.asString().matches(verifiableArgument.validation) )
+ invalidValues.add( new Pair<ArgumentDefinition,String>(verifiableArgument, value.asString()) );
+ }
+ }
+ }
+
+ if( invalidValues.size() > 0 )
+ throw new InvalidArgumentValueException( invalidValues );
+ }
+
+ // Find values without an associated mate.
+ if( !skipValidationOf.contains(ValidationType.ValueMissingArgument) ) {
+ if( argumentMatches.MissingArgument.values().size() > 0 )
+ throw new UnmatchedArgumentException( argumentMatches.MissingArgument );
+ }
+
+ // Find arguments with too many values.
+ if( !skipValidationOf.contains(ValidationType.TooManyValuesForArgument)) {
+ Collection<ArgumentMatch> overvaluedArguments = new ArrayList<ArgumentMatch>();
+ for( ArgumentMatch argumentMatch: argumentMatches.findSuccessfulMatches() ) {
+ // Warning: assumes that definition is not null (asserted by checks above).
+ if( !argumentMatch.definition.isMultiValued && argumentMatch.values().size() > 1 )
+ overvaluedArguments.add(argumentMatch);
+ }
+
+ if( !overvaluedArguments.isEmpty() )
+ throw new TooManyValuesForArgumentException(overvaluedArguments);
+ }
+
+ // Find sets of options that are supposed to be mutually exclusive.
+ if( !skipValidationOf.contains(ValidationType.MutuallyExclusive)) {
+ Collection<Pair<ArgumentMatch,ArgumentMatch>> invalidPairs = new ArrayList<Pair<ArgumentMatch,ArgumentMatch>>();
+ for( ArgumentMatch argumentMatch: argumentMatches.findSuccessfulMatches() ) {
+ if( argumentMatch.definition.exclusiveOf != null ) {
+ for( ArgumentMatch conflictingMatch: argumentMatches.findSuccessfulMatches() ) {
+ // Skip over the current element.
+ if( argumentMatch == conflictingMatch )
+ continue;
+ if( argumentMatch.definition.exclusiveOf.equals(conflictingMatch.definition.fullName) ||
+ argumentMatch.definition.exclusiveOf.equals(conflictingMatch.definition.shortName))
+ invalidPairs.add( new Pair<ArgumentMatch,ArgumentMatch>(argumentMatch, conflictingMatch) );
+ }
+ }
+ }
+
+ if( !invalidPairs.isEmpty() )
+ throw new ArgumentsAreMutuallyExclusiveException( invalidPairs );
+ }
+ }
+
+ /**
+ * Loads a set of matched command-line arguments into the given object.
+ * @param object Object into which to add arguments.
+ */
+ public void loadArgumentsIntoObject( Object object ) {
+ loadArgumentsIntoObject(object, true);
+ }
+
+ /**
+ * Loads a set of matched command-line arguments into the given object.
+ * @param object Object into which to add arguments.
+ * @param enforceArgumentRanges If true, check that the argument value is within the range specified
+ * in the corresponding Argument annotation by min/max value attributes. This
+ * check is only performed for numeric types, and only when a min and/or
+ * max value is actually defined in the annotation. It is also only performed
+ * for values actually specified on the command line, and not for default values.
+ */
+ public void loadArgumentsIntoObject( Object object, boolean enforceArgumentRanges ) {
+ List<ArgumentSource> argumentSources = extractArgumentSources(object.getClass());
+
+ List<ArgumentSource> dependentArguments = new ArrayList<ArgumentSource>();
+
+ for( ArgumentSource argumentSource: argumentSources ) {
+ if(argumentSource.isDeprecated() && argumentMatches.findMatches(this,argumentSource).size() > 0)
+ notifyDeprecatedCommandLineArgument(argumentSource);
+
+ // If this argument source depends on other command-line arguments, skip it and make a note to process it later.
+ if(argumentSource.isDependent()) {
+ dependentArguments.add(argumentSource);
+ continue;
+ }
+ loadValueIntoObject(argumentSource, object, argumentMatches.findMatches(this,argumentSource), enforceArgumentRanges);
+ }
+
+ for(ArgumentSource dependentArgument: dependentArguments) {
+ MultiplexArgumentTypeDescriptor dependentDescriptor = dependentArgument.createDependentTypeDescriptor(this,object);
+ ArgumentSource dependentSource = dependentArgument.copyWithCustomTypeDescriptor(dependentDescriptor);
+ loadValueIntoObject(dependentSource,object,argumentMatches.findMatches(this,dependentSource), enforceArgumentRanges);
+ }
+ }
+
+ /**
+ * Notify the user that tags have been created.
+ * @param key The key created.
+ * @param tags List of tags, or empty list if no tags are present.
+ */
+ public void addTags(Object key, final Tags tags) {
+ this.tags.put(key,tags);
+ }
+
+ /**
+ * Gets the tags associated with a given object.
+ * @param key Key for which to find a tag.
+ * @return List of tags associated with this key.
+ */
+ public Tags getTags(Object key) {
+ if(!tags.containsKey(key))
+ return new Tags();
+ return tags.get(key);
+ }
+
+ /**
+ * Add a RodBinding type argument to this parser. Called during parsing to allow
+ * us to track all of the RodBindings discovered in the command line.
+ * @param rodBinding the rodbinding to add. Must not be added twice
+ */
+ @Requires("rodBinding != null")
+ public void addRodBinding(final RodBinding rodBinding) {
+ rodBindings.add(rodBinding);
+ }
+
+ /**
+ * Notify the user that a deprecated command-line argument has been used.
+ * @param argumentSource Deprecated argument source specified by user.
+ */
+ private void notifyDeprecatedCommandLineArgument(ArgumentSource argumentSource) {
+ // Grab the first argument definition and report that one as the failure. Theoretically, we should notify of all failures.
+ List<ArgumentDefinition> definitions = argumentSource.createArgumentDefinitions();
+ if(definitions.size() < 1)
+ throw new ReviewedGATKException("Internal error. Argument source creates no definitions.");
+ ArgumentDefinition definition = definitions.get(0);
+ throw new UserException.DeprecatedArgument(definition.fullName,definition.doc);
+ }
+
+ /**
+ * Loads a single argument into the object and that objects children.
+ * @param argumentMatches Argument matches to load into the object.
+ * @param source Argument source to load into the object.
+ * @param instance Object into which to inject the value. The target might be in a container within the instance.
+ * @param enforceArgumentRanges If true, check that the argument value is within the range specified
+ * in the corresponding Argument annotation by min/max value attributes. This
+ * check is only performed for numeric types, and only when a min and/or
+ * max value is actually defined in the annotation. It is also only performed
+ * for values actually specified on the command line, and not for default values.
+ */
+ private void loadValueIntoObject( ArgumentSource source, Object instance, ArgumentMatches argumentMatches, boolean enforceArgumentRanges ) {
+ // Nothing to load
+ if( argumentMatches.size() == 0 && ! source.createsTypeDefault() )
+ return;
+
+ // Target instance into which to inject the value.
+ Collection<Object> targets = findTargets( source, instance );
+
+ // Abort if no home is found for the object.
+ if( targets.size() == 0 )
+ throw new ReviewedGATKException("Internal command-line parser error: unable to find a home for argument matches " + argumentMatches);
+
+ for( Object target: targets ) {
+ Object value;
+ boolean usedTypeDefault = false;
+ if ( argumentMatches.size() != 0 ) {
+ value = source.parse(this,argumentMatches);
+ }
+ else {
+ value = source.createTypeDefault(this);
+ usedTypeDefault = true;
+ }
+
+ // Only check argument ranges if a check was requested AND we used a value from the command line rather
+ // than the type default
+ if ( enforceArgumentRanges && ! usedTypeDefault ) {
+ checkArgumentRange(source, value);
+ }
+
+ JVMUtils.setFieldValue(source.field,target,value);
+ }
+ }
+
+ /**
+ * Check the provided value against any range constraints specified in the Argument annotation
+ * for the corresponding field. Throw an exception if hard limits are violated, or emit a warning
+ * if soft limits are violated.
+ *
+ * Only checks numeric types (int, double, etc.)
+ * Only checks fields with an actual @Argument annotation
+ * Only checks manually-specified constraints (there are no default constraints).
+ *
+ * @param argumentSource The source field for the command-line argument
+ * @param argumentValue The value we're considering putting in that source field
+ */
+ private void checkArgumentRange( final ArgumentSource argumentSource, final Object argumentValue ) {
+ // Only validate numeric types
+ if ( ! (argumentValue instanceof Number) ) {
+ return;
+ }
+ final double argumentDoubleValue = ((Number)argumentValue).doubleValue();
+
+ // Only validate fields with an @Argument annotation
+ final Annotation argumentAnnotation = argumentSource.field.getAnnotation(Argument.class);
+ if ( argumentAnnotation == null ) {
+ return;
+ }
+
+ final double minValue = (Double)CommandLineUtils.getValue(argumentAnnotation, "minValue");
+ final double maxValue = (Double)CommandLineUtils.getValue(argumentAnnotation, "maxValue");
+ final double minRecommendedValue = (Double)CommandLineUtils.getValue(argumentAnnotation, "minRecommendedValue");
+ final double maxRecommendedValue = (Double)CommandLineUtils.getValue(argumentAnnotation, "maxRecommendedValue");
+ final String argumentName = (String)CommandLineUtils.getValue(argumentAnnotation, "fullName");
+
+ // Check hard limits first, if specified
+ if ( minValue != Double.NEGATIVE_INFINITY && argumentDoubleValue < minValue ) {
+ throw new ArgumentValueOutOfRangeException(argumentName, argumentDoubleValue, minValue, "minimum");
+ }
+
+ if ( maxValue != Double.POSITIVE_INFINITY && argumentDoubleValue > maxValue ) {
+ throw new ArgumentValueOutOfRangeException(argumentName, argumentDoubleValue, maxValue, "maximum");
+ }
+
+ // Then check soft limits, if specified
+ if ( minRecommendedValue != Double.NEGATIVE_INFINITY && argumentDoubleValue < minRecommendedValue ) {
+ logger.warn(String.format("WARNING: argument --%s has value %.2f, but minimum recommended value is %.2f",
+ argumentName, argumentDoubleValue, minRecommendedValue));
+ }
+
+ if ( maxRecommendedValue != Double.POSITIVE_INFINITY && argumentDoubleValue > maxRecommendedValue ) {
+ logger.warn(String.format("WARNING: argument --%s has value %.2f, but maximum recommended value is %.2f",
+ argumentName, argumentDoubleValue, maxRecommendedValue));
+ }
+ }
+
+ public Collection<RodBinding> getRodBindings() {
+ return Collections.unmodifiableCollection(rodBindings);
+ }
+
+ /**
+ * Gets a collection of the container instances of the given type stored within the given target.
+ * @param source Argument source.
+ * @param instance Container.
+ * @return A collection of containers matching the given argument source.
+ */
+ private Collection<Object> findTargets(ArgumentSource source, Object instance) {
+ LinkedHashSet<Object> targets = new LinkedHashSet<Object>();
+ for( Class clazz = instance.getClass(); clazz != null; clazz = clazz.getSuperclass() ) {
+ for( Field field: clazz.getDeclaredFields() ) {
+ if( field.equals(source.field) ) {
+ targets.add(instance);
+ } else if( field.isAnnotationPresent(ArgumentCollection.class) ) {
+ targets.addAll(findTargets(source, JVMUtils.getFieldValue(field, instance)));
+ }
+ }
+ }
+ return targets;
+ }
+
+ /**
+ * Prints out the help associated with these command-line argument definitions.
+ * @param applicationDetails Details about the specific GATK-based application being run.
+ */
+ public void printHelp( ApplicationDetails applicationDetails ) {
+ new HelpFormatter().printHelp(applicationDetails,argumentDefinitions);
+ }
+
+ /**
+ * Extract all the argument sources from a given object.
+ * @param sourceClass class to act as sources for other arguments.
+ * @return A list of sources associated with this object and its aggregated objects.
+ */
+ public List<ArgumentSource> extractArgumentSources(Class sourceClass) {
+ return extractArgumentSources(sourceClass, new Field[0]);
+ }
+
+ /**
+ * Fetch the best command-line argument descriptor for the given class.
+ * @param type Class for which to specify a descriptor.
+ * @return descriptor for the given type.
+ */
+ public ArgumentTypeDescriptor selectBestTypeDescriptor(Class type) {
+ return ArgumentTypeDescriptor.selectBest(argumentTypeDescriptors,type);
+ }
+
+ private List<ArgumentSource> extractArgumentSources(Class sourceClass, Field[] parentFields) {
+ // now simply call into the truly general routine extract argument bindings but with a null
+ // object so bindings aren't computed
+ Map<ArgumentSource, Object> bindings = extractArgumentBindings(null, sourceClass, parentFields);
+ return new ArrayList<ArgumentSource>(bindings.keySet());
+ }
+
+ public Map<ArgumentSource, Object> extractArgumentBindings(Object obj) {
+ if ( obj == null ) throw new IllegalArgumentException("Incoming object cannot be null");
+ return extractArgumentBindings(obj, obj.getClass(), new Field[0]);
+ }
+
+ /**
+ * Extract all the argument sources from a given object, along with their bindings if obj != null .
+ * @param obj the object corresponding to the sourceClass
+ * @param sourceClass class to act as sources for other arguments.
+ * @param parentFields Parent Fields
+ * @return A map of sources associated with this object and its aggregated objects and bindings to their bindings values
+ */
+ private Map<ArgumentSource, Object> extractArgumentBindings(Object obj, Class sourceClass, Field[] parentFields) {
+ Map<ArgumentSource, Object> bindings = new LinkedHashMap<ArgumentSource, Object>();
+
+ while( sourceClass != null ) {
+ Field[] fields = sourceClass.getDeclaredFields();
+ for( Field field: fields ) {
+ if( ArgumentTypeDescriptor.isArgumentAnnotationPresent(field) ) {
+ Object val = obj != null ? JVMUtils.getFieldValue(field, obj) : null;
+ bindings.put( new ArgumentSource(parentFields, field, selectBestTypeDescriptor(field.getType())), val );
+ }
+ if( field.isAnnotationPresent(ArgumentCollection.class) ) {
+ Object val = obj != null ? JVMUtils.getFieldValue(field, obj) : null;
+ Field[] newParentFields = Arrays.copyOf(parentFields, parentFields.length + 1);
+ newParentFields[parentFields.length] = field;
+ bindings.putAll( extractArgumentBindings(val, field.getType(), newParentFields) );
+ }
+ }
+
+ sourceClass = sourceClass.getSuperclass();
+ }
+
+ return bindings;
+ }
+
+ /**
+ * Determines whether a token looks like the name of an argument.
+ * @param token Token to inspect. Can be surrounded by whitespace.
+ * @return True if token is of short name form.
+ */
+ private boolean isArgumentForm( String token ) {
+ for( ParsingMethod parsingMethod: parsingMethods ) {
+ if( parsingMethod.matches(token) )
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Parse a short name into an ArgumentMatch.
+ * @param token The token to parse. The token should pass the isLongArgumentForm test.
+ * @param position The position of the token in question.
+ * @return ArgumentMatch associated with this token, or null if no match exists.
+ */
+ private ArgumentMatch parseArgument( String token, ArgumentMatchSite position ) {
+ if( !isArgumentForm(token) )
+ throw new IllegalArgumentException( "Token is not recognizable as an argument: " + token );
+
+ for( ParsingMethod parsingMethod: parsingMethods ) {
+ if( parsingMethod.matches( token ) )
+ return parsingMethod.match( argumentDefinitions, token, position );
+ }
+
+ // No parse results found.
+ return null;
+ }
+}
+
+/**
+ * An exception indicating that some required arguments are missing.
+ */
+class MissingArgumentException extends ArgumentException {
+ public MissingArgumentException( Collection<ArgumentDefinition> missingArguments ) {
+ super( formatArguments(missingArguments) );
+ }
+
+ private static String formatArguments( Collection<ArgumentDefinition> missingArguments ) {
+ StringBuilder sb = new StringBuilder();
+ for( ArgumentDefinition missingArgument: missingArguments ) {
+ if( missingArgument.shortName != null )
+ sb.append( String.format("%nArgument with name '--%s' (-%s) is missing.", missingArgument.fullName, missingArgument.shortName) );
+ else
+ sb.append( String.format("%nArgument with name '--%s' is missing.", missingArgument.fullName) );
+ }
+ return sb.toString();
+ }
+}
+
+/**
+ * An exception for undefined arguments.
+ */
+class InvalidArgumentException extends ArgumentException {
+ public InvalidArgumentException( ArgumentMatches invalidArguments ) {
+ super( formatArguments(invalidArguments) );
+ }
+
+ private static String formatArguments( ArgumentMatches invalidArguments ) {
+ StringBuilder sb = new StringBuilder();
+ for( ArgumentMatch invalidArgument: invalidArguments )
+ sb.append( String.format("%nArgument with name '%s' isn't defined.", invalidArgument.label) );
+ return sb.toString();
+ }
+}
+
+/**
+ * An exception for values whose format is invalid.
+ */
+class InvalidArgumentValueException extends ArgumentException {
+ public InvalidArgumentValueException( Collection<Pair<ArgumentDefinition,String>> invalidArgumentValues ) {
+ super( formatArguments(invalidArgumentValues) );
+ }
+
+ private static String formatArguments( Collection<Pair<ArgumentDefinition,String>> invalidArgumentValues ) {
+ StringBuilder sb = new StringBuilder();
+ for( Pair<ArgumentDefinition,String> invalidValue: invalidArgumentValues ) {
+ if(invalidValue.getSecond() == null)
+ sb.append( String.format("%nArgument '--%s' requires a value but none was provided",
+ invalidValue.first.fullName) );
+ else
+ sb.append( String.format("%nArgument '--%s' has value of incorrect format: %s (should match %s)",
+ invalidValue.first.fullName,
+ invalidValue.second,
+ invalidValue.first.validation) );
+ }
+ return sb.toString();
+ }
+}
+
+class ArgumentValueOutOfRangeException extends ArgumentException {
+ public ArgumentValueOutOfRangeException( final String argumentName, final double argumentActualValue,
+ final double argumentBoundaryValue, final String argumentBoundaryType ) {
+ super(String.format("Argument --%s has value %.2f, but %s allowed value is %.2f",
+ argumentName, argumentActualValue, argumentBoundaryType, argumentBoundaryValue));
+ }
+}
+
+/**
+ * An exception for values that can't be mated with any argument.
+ */
+class UnmatchedArgumentException extends ArgumentException {
+ public UnmatchedArgumentException( ArgumentMatch invalidValues ) {
+ super( formatArguments(invalidValues) );
+ }
+
+ private static String formatArguments( ArgumentMatch invalidValues ) {
+ StringBuilder sb = new StringBuilder();
+ for( ArgumentMatchSite site: invalidValues.sites.keySet() )
+ for( ArgumentMatchValue value: invalidValues.sites.get(site) ) {
+ switch (site.getSource().getType()) {
+ case CommandLine:
+ sb.append( String.format("%nInvalid argument value '%s' at position %d.",
+ value.asString(), site.getIndex()) );
+ break;
+ case Provider:
+ sb.append( String.format("%nInvalid argument value '%s' in %s at position %d.",
+ value.asString(), site.getSource().getDescription(), site.getIndex()) );
+ break;
+ default:
+ throw new RuntimeException( String.format("Unexpected argument match source type: %s",
+ site.getSource().getType()));
+ }
+ if(value.asString() != null && Utils.dupString(' ',value.asString().length()).equals(value.asString()))
+ sb.append(" Please make sure any line continuation backslashes on your command line are not followed by whitespace.");
+ }
+ return sb.toString();
+ }
+}
+
+/**
+ * An exception indicating that too many values have been provided for the given argument.
+ */
+class TooManyValuesForArgumentException extends ArgumentException {
+ public TooManyValuesForArgumentException( Collection<ArgumentMatch> arguments ) {
+ super( formatArguments(arguments) );
+ }
+
+ private static String formatArguments( Collection<ArgumentMatch> arguments ) {
+ StringBuilder sb = new StringBuilder();
+ for( ArgumentMatch argument: arguments )
+ sb.append( String.format("%nArgument '%s' has too many values: %s.", argument.label, Arrays.deepToString(argument.values().toArray())) );
+ return sb.toString();
+ }
+}
+
+/**
+ * An exception indicating that mutually exclusive options have been passed in the same command line.
+ */
+class ArgumentsAreMutuallyExclusiveException extends ArgumentException {
+ public ArgumentsAreMutuallyExclusiveException( Collection<Pair<ArgumentMatch,ArgumentMatch>> arguments ) {
+ super( formatArguments(arguments) );
+ }
+
+ private static String formatArguments( Collection<Pair<ArgumentMatch,ArgumentMatch>> arguments ) {
+ StringBuilder sb = new StringBuilder();
+ for( Pair<ArgumentMatch,ArgumentMatch> argument: arguments )
+ sb.append( String.format("%nArguments '%s' and '%s' are mutually exclusive.", argument.first.definition.fullName, argument.second.definition.fullName ) );
+ return sb.toString();
+ }
+
+}
+
+
+/**
+ * An exception for when an argument doesn't match an of the enumerated options for that var type
+ */
+class UnknownEnumeratedValueException extends ArgumentException {
+ public UnknownEnumeratedValueException(ArgumentDefinition definition, String argumentPassed) {
+ super( formatArguments(definition,argumentPassed) );
+ }
+
+ private static String formatArguments(ArgumentDefinition definition, String argumentPassed) {
+ return String.format("Invalid value %s specified for argument %s; valid options are (%s).", argumentPassed, definition.fullName, Utils.join(",",definition.validOptions));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingEngineArgumentFiles.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingEngineArgumentFiles.java
new file mode 100644
index 0000000..0361c4c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingEngineArgumentFiles.java
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+
+/**
+ * Container class to store the list of argument files.
+ * The files will be parsed after the command line arguments.
+ */
+public class ParsingEngineArgumentFiles extends ParsingEngineArgumentProvider {
+ @Argument(fullName = "arg_file", shortName = "args", doc = "Reads arguments from the specified file", required = false)
+ public List<File> files = new ArrayList<File>();
+
+ @Override
+ public void parse(ParsingEngine parsingEngine, SortedMap<ArgumentMatchSource, ParsedArgs> parsedArgs) {
+ ArgumentMatches argumentMatches = parsingEngine.getArgumentMatches();
+ for (File file: this.files) {
+ List<String> fileTokens = parsingEngine.getArguments(file);
+ parsingEngine.parse(new ArgumentMatchFileSource(file), fileTokens, argumentMatches, parsedArgs);
+ }
+ }
+}
+
+class ArgumentMatchFileSource extends ArgumentMatchSource {
+ ArgumentMatchFileSource(File file) {
+ super("file " + file.getAbsolutePath());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingEngineArgumentProvider.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingEngineArgumentProvider.java
new file mode 100644
index 0000000..d53a36c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingEngineArgumentProvider.java
@@ -0,0 +1,37 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.util.List;
+import java.util.SortedMap;
+
+/**
+ * A class that can parse arguments for the engine
+ */
+public abstract class ParsingEngineArgumentProvider {
+ public abstract void parse(ParsingEngine parsingEngine, SortedMap<ArgumentMatchSource, ParsedArgs> parsedArgs);
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingMethod.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingMethod.java
new file mode 100644
index 0000000..a939742
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/ParsingMethod.java
@@ -0,0 +1,127 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.Utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Holds a pattern, along with how to get to the argument definitions that could match that pattern.
+ */
+public abstract class ParsingMethod {
+ private final Pattern pattern;
+ private final DefinitionMatcher definitionMatcher;
+
+ /**
+ * Create a new parsing method with the given identifying / validating pattern and definition matcher.
+ * @param pattern The pattern
+ * @param definitionMatcher The definition matcher.
+ */
+ private ParsingMethod( Pattern pattern, DefinitionMatcher definitionMatcher ) {
+ this.pattern = pattern;
+ this.definitionMatcher = definitionMatcher;
+ }
+
+ /**
+ * Can the given token be parsed by this parsing method?
+ * @param token Token to validate.
+ * @return True if the given token matches.
+ */
+ public boolean matches( String token ) {
+ Matcher matcher = pattern.matcher(token);
+ return matcher.matches();
+ }
+
+ /**
+ * Find the best match for a given token at a given position from among the provided
+ * argument definitions.
+ * @param definitions List of argument definitions.
+ * @param token The token from the command line to match. Should be validated using
+ * ParsingMethod's matches() tester.
+ * @param position Position at which this command-line argument occurs. Will be used
+ * for validation later.
+ * @return An argument match. Definition field will be populated if a match was found or
+ * empty if no appropriate definition could be found.
+ */
+ public ArgumentMatch match( ArgumentDefinitions definitions, String token, ArgumentMatchSite position ) {
+ // If the argument is valid, parse out the argument.
+ Matcher matcher = pattern.matcher(token);
+
+ // Didn't match? Must be bad input.
+ if( !matcher.matches() )
+ throw new IllegalArgumentException( String.format("Unable to parse token %s with pattern %s", token, pattern.pattern()) );
+
+ String argument = matcher.group(1).trim();
+
+ Tags tags = parseTags(argument, matcher.group(2));
+
+ // Find the most appropriate argument definition for the given argument.
+ ArgumentDefinition argumentDefinition = definitions.findArgumentDefinition( argument, definitionMatcher );
+
+ // Try to find a matching argument. If found, label that as the match. If not found, add the argument
+ // with a null definition.
+ return new ArgumentMatch(argument,argumentDefinition,position,tags);
+ }
+
+ public static Tags parseTags(String argument, String tagString) {
+ Tags tags = new Tags();
+ if (tagString != null) {
+ for(String tag: Utils.split(tagString, ",")) {
+ // Check for presence of an '=' sign, indicating a key-value pair in the tag line.
+ int equalDelimiterPos = tag.indexOf('=');
+ if(equalDelimiterPos >= 0) {
+ // Sanity check; ensure that there aren't multiple '=' in this key-value pair.
+ if(tag.indexOf('=',equalDelimiterPos+1) >= 0)
+ throw new ArgumentException(String.format("Tag %s passed to argument %s is malformed. Please ensure that " +
+ "key-value tags are of the form <key>=<value>, and neither key " +
+ "nor value contain the '=' character", tag, argument));
+ tags.addKeyValueTag(tag.substring(0,equalDelimiterPos),tag.substring(equalDelimiterPos+1));
+ }
+ else
+ tags.addPositionalTag(tag);
+
+ }
+ }
+ return tags;
+ }
+
+ /**
+ * A command-line argument always starts with an alphabetical character or underscore followed by any word character.
+ */
+ private static final String ARGUMENT_TEXT = "[A-Za-z_][\\w\\-\\.]*";
+
+ /**
+ * Tags, on the other hand, can start with any word character.
+ */
+ private static final String TAG_TEXT = "[\\w\\-\\.\\=]*";
+
+ public static final ParsingMethod FullNameParsingMethod = new ParsingMethod(Pattern.compile(String.format("\\s*--(%1$s)(?:\\:(%2$s(?:,%2$s)*))?\\s*",ARGUMENT_TEXT,TAG_TEXT)),
+ ArgumentDefinitions.FullNameDefinitionMatcher) {};
+ public static final ParsingMethod ShortNameParsingMethod = new ParsingMethod(Pattern.compile(String.format("\\s*-(%1$s)(?:\\:(%2$s(?:,%2$s)*))?\\s*",ARGUMENT_TEXT,TAG_TEXT)),
+ ArgumentDefinitions.ShortNameDefinitionMatcher) {};
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/RodBinding.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/RodBinding.java
new file mode 100644
index 0000000..2c55787
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/RodBinding.java
@@ -0,0 +1,197 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.tribble.Feature;
+
+import java.util.*;
+
+/**
+ * A RodBinding represents a walker argument that gets bound to a ROD track.
+ *
+ * The RodBinding<T> is a formal GATK argument that bridges between a walker and
+ * the RefMetaDataTracker to obtain data about this rod track at runtime. The RodBinding
+ * is explicitly typed with type of the Tribble.Feature expected to be produced by this
+ * argument. The GATK Engine takes care of initializing the binding and connecting it
+ * to the RMD system.
+ *
+ * It is recommended that optional RodBindings be initialized to the value returned
+ * by the static method makeUnbound().
+ *
+ * Note that this class is immutable.
+ */
+public final class RodBinding<T extends Feature> {
+ protected final static String UNBOUND_VARIABLE_NAME = "";
+ protected final static String UNBOUND_SOURCE = "UNBOUND";
+ protected final static String UNBOUND_TRIBBLE_TYPE = "";
+
+ /**
+ * Create an unbound Rodbinding of type. This is the correct programming
+ * style for an optional RodBinding<T>
+ *
+ * At Input()
+ * RodBinding<T> x = RodBinding.makeUnbound(T.class)
+ *
+ * The unbound binding is guaranteed to never match any binding. It uniquely
+ * returns false to isBound().
+ *
+ * @param type the Class type produced by this unbound object
+ * @param <T> any class extending Tribble Feature
+ * @return the UNBOUND RodBinding producing objects of type T
+ */
+ @Requires("type != null")
+ protected final static <T extends Feature> RodBinding<T> makeUnbound(Class<T> type) {
+ return new RodBinding<T>(type);
+ }
+
+ /** The name of this binding. Often the name of the field itself, but can be overridden on cmdline */
+ final private String name;
+ /** where the data for this ROD is coming from. A file or special value if coming from stdin */
+ final private String source;
+ /** the string name of the tribble type, such as vcf, bed, etc. */
+ final private String tribbleType;
+ /** The command line tags associated with this RodBinding */
+ final private Tags tags;
+ /** The Java class expected for this RodBinding. Must correspond to the type emitted by Tribble */
+ final private Class<T> type;
+ /** True for all RodBindings except the special UNBOUND binding, which is the default for optional arguments */
+ final private boolean bound;
+
+ /**
+ * The name counter. This is how we create unique names for collections of RodBindings
+ * on the command line. If you have provide the GATK with -X file1 and -X file2 to a
+ * RodBinding argument as List<RodBinding<T>> then each binding will receive automatically
+ * the name of X and X2.
+ */
+ final private static Map<String, Integer> nameCounter = new HashMap<String, Integer>();
+
+ /** for UnitTests */
+ final public static void resetNameCounter() {
+ nameCounter.clear();
+ }
+
+ @Requires("rawName != null")
+ @Ensures("result != null")
+ final private static synchronized String countedVariableName(final String rawName) {
+ Integer count = nameCounter.get(rawName);
+ if ( count == null ) {
+ nameCounter.put(rawName, 1);
+ return rawName;
+ } else {
+ nameCounter.put(rawName, count + 1);
+ return rawName + (count + 1);
+ }
+ }
+
+ @Requires({"type != null", "rawName != null", "source != null", "tribbleType != null", "tags != null"})
+ public RodBinding(Class<T> type, final String rawName, final String source, final String tribbleType, final Tags tags) {
+ this.type = type;
+ this.name = countedVariableName(rawName);
+ this.source = source;
+ this.tribbleType = tribbleType;
+ this.tags = tags;
+ this.bound = true;
+ }
+
+ /**
+ * For testing purposes only. Creates a RodBinding sufficient for looking up associations to rawName
+ * @param type
+ * @param rawName
+ */
+ public RodBinding(Class<T> type, final String rawName) {
+ this(type, rawName, "missing", type.getSimpleName(), new Tags());
+ }
+
+ /**
+ * Make an unbound RodBinding<T>. Only available for creating the globally unique UNBOUND object
+ * @param type class this unbound RodBinding creates
+ */
+ @Requires({"type != null"})
+ private RodBinding(Class<T> type) {
+ this.type = type;
+ this.name = UNBOUND_VARIABLE_NAME; // special value can never be found in RefMetaDataTracker
+ this.source = UNBOUND_SOURCE;
+ this.tribbleType = UNBOUND_TRIBBLE_TYPE;
+ this.tags = new Tags();
+ this.bound = false;
+ }
+
+
+ /**
+ * @return True for all RodBindings except the special UNBOUND binding, which is the default for optional arguments
+ */
+ final public boolean isBound() {
+ return bound;
+ }
+
+ /**
+ * @return The name of this binding. Often the name of the field itself, but can be overridden on cmdline
+ */
+ @Ensures({"result != null"})
+ final public String getName() {
+ return name;
+ }
+
+ /**
+ * @return the string name of the tribble type, such as vcf, bed, etc.
+ */
+ @Ensures({"result != null"})
+ final public Class<T> getType() {
+ return type;
+ }
+
+ /**
+ * @return where the data for this ROD is coming from. A file or special value if coming from stdin
+ */
+ @Ensures({"result != null"})
+ final public String getSource() {
+ return source;
+ }
+
+ /**
+ * @return The command line tags associated with this RodBinding. Will include the tags used to
+ * determine the name and type of this RodBinding
+ */
+ @Ensures({"result != null"})
+ final public Tags getTags() {
+ return tags;
+ }
+
+ /**
+ * @return The Java class expected for this RodBinding. Must correspond to the type emited by Tribble
+ */
+ @Ensures({"result != null"})
+ final public String getTribbleType() {
+ return tribbleType;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("(RodBinding name=%s source=%s)", getName(), getSource());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/RodBindingCollection.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/RodBindingCollection.java
new file mode 100644
index 0000000..faf4565
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/RodBindingCollection.java
@@ -0,0 +1,89 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import com.google.java.contract.Ensures;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+
+/**
+ * A RodBindingCollection represents a collection of RodBindings.
+ *
+ * The RodBindingCollection<T> is a formal GATK argument that is used to specify a file of RodBindings.
+ *
+ */
+public final class RodBindingCollection<T extends Feature> {
+
+ /** The Java class expected for this RodBinding. Must correspond to the type emitted by Tribble */
+ final private Class<T> type;
+
+ private Collection<RodBinding<T>> rodBindings;
+
+ public RodBindingCollection(final Class<T> type, final Collection<RodBinding<T>> rodBindings) {
+ this.type = type;
+ this.rodBindings = Collections.unmodifiableCollection(rodBindings);
+ }
+
+ /**
+ * @return the collection of RodBindings
+ */
+ final public Collection<RodBinding<T>> getRodBindings() {
+ return rodBindings;
+ }
+
+ /**
+ * @return the string name of the tribble type, such as vcf, bed, etc.
+ */
+ @Ensures({"result != null"})
+ final public Class<T> getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("(RodBindingCollection %s)", getRodBindings());
+ }
+
+ /**
+ * Utility method to help construct a RodBindingCollection of the given Feature type
+ *
+ * @param type the Feature type
+ * @param rodBindings the rod bindings to put into the collection
+ * @return a new RodBindingCollection object
+ */
+ public static Object createRodBindingCollectionOfType(final Class<? extends Feature> type, final Collection<RodBinding> rodBindings) {
+ try {
+ final Constructor ctor = RodBindingCollection.class.getConstructor(Class.class, Collection.class);
+ return ctor.newInstance(type, rodBindings);
+ } catch (final Exception e) {
+ throw new IllegalStateException("Failed to create a RodBindingCollection for type " + type);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Tags.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Tags.java
new file mode 100644
index 0000000..2b1c7f7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/Tags.java
@@ -0,0 +1,112 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.util.*;
+
+/**
+ * Models the tags that can appear after command-line arguments
+ * in the GATK.
+ */
+public class Tags {
+ /**
+ * Storage for the ordered, unkeyed, positional tags.
+ */
+ private final List<String> positionalTags = new ArrayList<String>();
+
+ /**
+ * Storage for key-value tags of the form <key>=<value>
+ */
+ private Map<String,String> keyValueTags = new HashMap<String,String>();
+
+ /**
+ * Tests to see whether two tag sets are equal.
+ * @param other Other object to test for equality.
+ * @return True if objects are the same. False if objects differ.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if(other == null)
+ return false;
+
+ if(!(other instanceof Tags))
+ return false;
+
+ Tags otherTags = (Tags)other;
+ return this.positionalTags.equals(otherTags.positionalTags) && this.keyValueTags.equals(otherTags.keyValueTags);
+ }
+
+ /**
+ * Returns whether any tags are specified on the command-line for this operation.
+ * @return True if the tags are empty; false otherwise.
+ */
+ public boolean isEmpty() {
+ return positionalTags.isEmpty() && keyValueTags.isEmpty();
+ }
+
+ /**
+ * Retrieves the list of all positional tags associated with this argument.
+ * @return A list of positional tags.
+ */
+ public List<String> getPositionalTags() {
+ return Collections.unmodifiableList(positionalTags);
+ }
+
+ /**
+ * Gets the value associated with a given <key>=<value> argument tag.
+ * @param key The key for which to retrieve the value.
+ * @return The value paired with the given key, or null if no such element exists.
+ */
+ public String getValue(final String key) {
+ return keyValueTags.get(key);
+ }
+
+ /**
+ * Returns true if tags contains given key
+ * @param key The key for which to check existence.
+ * @return true if tags contains given key
+ */
+ public boolean containsKey(final String key) {
+ return keyValueTags.containsKey(key);
+ }
+
+ /**
+ * Adds positional tag(s) to the tag object.
+ * @param tags The tag strings to add.
+ */
+ protected void addPositionalTag(final String... tags) {
+ positionalTags.addAll(Arrays.asList(tags));
+ }
+
+ /**
+ * Adds a <key>-<value> tag to this tag library.
+ * @param key key tag to add.
+ * @param value value to associate with this key.
+ */
+ protected void addKeyValueTag(final String key, final String value) {
+ keyValueTags.put(key,value);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/package-info.java
new file mode 100644
index 0000000..f572d34
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/commandline/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/crypt/CryptUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/crypt/CryptUtils.java
new file mode 100644
index 0000000..d6ccd32
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/crypt/CryptUtils.java
@@ -0,0 +1,391 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.crypt;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.io.IOUtils;
+
+import javax.crypto.Cipher;
+import java.io.File;
+import java.io.InputStream;
+import java.security.*;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+
+/**
+ * A set of cryptographic utility methods and constants.
+ *
+ * Contains methods to:
+ *
+ * -Create a public/private key pair
+ * -Read and write public/private keys to/from files/streams
+ * -Load the GATK master private/public keys
+ * -Encrypt/decrypt data
+ *
+ * Also contains constants that control the cryptographic defaults
+ * throughout the GATK.
+ *
+ * @author David Roazen
+ */
+public class CryptUtils {
+
+ // ---------------------------------------------------------------------------------
+ // Constants (these control the default cryptographic settings throughout the GATK):
+ // ---------------------------------------------------------------------------------
+
+ /**
+ * Default key length in bits of newly-created keys. 2048 bits provides a good balance between
+ * security and speed.
+ */
+ public static final int DEFAULT_KEY_LENGTH = 2048;
+
+ /**
+ * Default encryption algorithm to use, when none is specified.
+ */
+ public static final String DEFAULT_ENCRYPTION_ALGORITHM = "RSA";
+
+ /**
+ * Default random-number generation algorithm to use, when none is specified.
+ */
+ public static final String DEFAULT_RANDOM_NUMBER_GENERATION_ALGORITHM = "SHA1PRNG";
+
+ /**
+ * Name of the public key file distributed with the GATK. This file is packaged
+ * into the GATK jar, and we use the system ClassLoader to find it.
+ */
+ public static final String GATK_DISTRIBUTED_PUBLIC_KEY_FILE_NAME = "GATK_public.key";
+
+ /**
+ * Location of the master copy of the GATK private key.
+ */
+ public static final String GATK_MASTER_PRIVATE_KEY_FILE = "/humgen/gsa-hpprojects/GATK/data/gatk_master_keys/GATK_private.key";
+
+ /**
+ * Location of the master copy of the GATK public key. This file should always be the same as
+ * the public key file distributed with the GATK (and there are automated tests to ensure that it is).
+ */
+ public static final String GATK_MASTER_PUBLIC_KEY_FILE = "/humgen/gsa-hpprojects/GATK/data/gatk_master_keys/GATK_public.key";
+
+ /**
+ * Directory where generated GATK user keys are stored. See the GATKKey class for more information.
+ */
+ public static final String GATK_USER_KEY_DIRECTORY = "/humgen/gsa-hpprojects/GATK/data/gatk_user_keys/";
+
+
+ // -----------------------
+ // Utility Methods:
+ // -----------------------
+
+ /**
+ * Generate a new public/private key pair using the default encryption settings defined above.
+ *
+ * @return A new public/private key pair created using the default settings
+ */
+ public static KeyPair generateKeyPair() {
+ return generateKeyPair(DEFAULT_KEY_LENGTH, DEFAULT_ENCRYPTION_ALGORITHM, DEFAULT_RANDOM_NUMBER_GENERATION_ALGORITHM);
+ }
+
+ /**
+ * Generate a new public/private key pair using custom encryption settings.
+ *
+ * @param keyLength Length of the key in bits
+ * @param encryptionAlgorithm Encryption algorithm to use
+ * @param randNumberAlgorithm Random-number generation algorithm to use
+ * @return A new public/private key pair, created according to the specified parameters
+ */
+ public static KeyPair generateKeyPair( int keyLength, String encryptionAlgorithm, String randNumberAlgorithm ) {
+ try {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance(encryptionAlgorithm);
+ SecureRandom randomnessSource = createRandomnessSource(randNumberAlgorithm);
+
+ keyGen.initialize(keyLength, randomnessSource);
+ return keyGen.generateKeyPair();
+ }
+ catch ( NoSuchAlgorithmException e ) {
+ throw new ReviewedGATKException(String.format("Could not find an implementation of the requested encryption algorithm %s", encryptionAlgorithm), e);
+ }
+ catch ( Exception e ) {
+ throw new ReviewedGATKException("Error while generating key pair", e);
+ }
+ }
+
+ /**
+ * Create a source of randomness using the default random-number generation algorithm.
+ *
+ * @return A randomness source that uses the default algorithm
+ */
+ public static SecureRandom createRandomnessSource() {
+ return createRandomnessSource(DEFAULT_RANDOM_NUMBER_GENERATION_ALGORITHM);
+ }
+
+ /**
+ * Create a source of randomness using a custom random-number generation algorithm.
+ *
+ * @param randAlgorithm The random-number generation algorithm to use
+ * @return A randomness sources that uses the specified algorithm
+ */
+ public static SecureRandom createRandomnessSource ( String randAlgorithm ) {
+ try {
+ return SecureRandom.getInstance(randAlgorithm);
+ }
+ catch ( NoSuchAlgorithmException e ) {
+ throw new ReviewedGATKException(String.format("Could not find an implementation of the requested random-number generation algorithm %s", randAlgorithm), e);
+ }
+ }
+
+ /**
+ * Writes a public/private key pair to disk
+ *
+ * @param keyPair The key pair we're writing to disk
+ * @param privateKeyFile Location to write the private key
+ * @param publicKeyFile Location to write the public key
+ */
+ public static void writeKeyPair ( KeyPair keyPair, File privateKeyFile, File publicKeyFile ) {
+ writeKey(keyPair.getPrivate(), privateKeyFile);
+ writeKey(keyPair.getPublic(), publicKeyFile);
+ }
+
+ /**
+ * Writes an arbitrary key to disk
+ *
+ * @param key The key to write
+ * @param destination Location to write the key to
+ */
+ public static void writeKey ( Key key, File destination ) {
+ IOUtils.writeByteArrayToFile(key.getEncoded(), destination);
+ }
+
+ /**
+ * Reads in a public key created using the default encryption algorithm from a file.
+ *
+ * @param source File containing the public key
+ * @return The public key read
+ */
+ public static PublicKey readPublicKey ( File source ) {
+ return decodePublicKey(IOUtils.readFileIntoByteArray(source), DEFAULT_ENCRYPTION_ALGORITHM);
+ }
+
+ /**
+ * Reads in a public key created using the default encryption algorithm from a stream.
+ *
+ * @param source Stream attached to the public key
+ * @return The public key read
+ */
+ public static PublicKey readPublicKey ( InputStream source ) {
+ return decodePublicKey(IOUtils.readStreamIntoByteArray(source), DEFAULT_ENCRYPTION_ALGORITHM);
+ }
+
+ /**
+ * Decodes the raw bytes of a public key into a usable object.
+ *
+ * @param rawKey The encoded bytes of a public key as read from, eg., a file. The
+ * key must be in the standard X.509 format for a public key.
+ * @param encryptionAlgorithm The encryption algorithm used to create the public key
+ * @return The public key as a usable object
+ */
+ public static PublicKey decodePublicKey ( byte[] rawKey, String encryptionAlgorithm ) {
+ try {
+ KeySpec keySpec = new X509EncodedKeySpec(rawKey);
+ KeyFactory keyFactory = KeyFactory.getInstance(encryptionAlgorithm);
+ return keyFactory.generatePublic(keySpec);
+ }
+ catch ( NoSuchAlgorithmException e ) {
+ throw new ReviewedGATKException(String.format("Could not find an implementation of the requested encryption algorithm %s", encryptionAlgorithm), e);
+ }
+ catch ( InvalidKeySpecException e ) {
+ throw new ReviewedGATKException("Unable to use X.509 key specification to decode the given key", e);
+ }
+ }
+
+ /**
+ * Reads in a private key created using the default encryption algorithm from a file.
+ *
+ * @param source File containing the private key
+ * @return The private key read
+ */
+ public static PrivateKey readPrivateKey ( File source ) {
+ return decodePrivateKey(IOUtils.readFileIntoByteArray(source), DEFAULT_ENCRYPTION_ALGORITHM);
+ }
+
+ /**
+ * Reads in a private key created using the default encryption algorithm from a stream.
+ *
+ * @param source Stream attached to the private key
+ * @return The private key read
+ */
+ public static PrivateKey readPrivateKey ( InputStream source ) {
+ return decodePrivateKey(IOUtils.readStreamIntoByteArray(source), DEFAULT_ENCRYPTION_ALGORITHM);
+ }
+
+ /**
+ * Decodes the raw bytes of a private key into a usable object.
+ *
+ * @param rawKey The encoded bytes of a private key as read from, eg., a file. The
+ * key must be in the standard PKCS #8 format for a private key.
+ * @param encryptionAlgorithm The encryption algorithm used to create the private key
+ * @return The private key as a usable object
+ */
+ public static PrivateKey decodePrivateKey ( byte[] rawKey, String encryptionAlgorithm ) {
+ try {
+ KeySpec keySpec = new PKCS8EncodedKeySpec(rawKey);
+ KeyFactory keyFactory = KeyFactory.getInstance(encryptionAlgorithm);
+ return keyFactory.generatePrivate(keySpec);
+ }
+ catch ( NoSuchAlgorithmException e ) {
+ throw new ReviewedGATKException(String.format("Could not find an implementation of the requested encryption algorithm %s", encryptionAlgorithm), e);
+ }
+ catch ( InvalidKeySpecException e ) {
+ throw new ReviewedGATKException("Unable to use the PKCS #8 key specification to decode the given key", e);
+ }
+ }
+
+ /**
+ * Loads the copy of the GATK public key that is distributed with the GATK. Uses the system
+ * ClassLoader to locate the public key file, which should be stored at the root of the GATK
+ * jar file.
+ *
+ * @return The GATK public key as a usable object
+ */
+ public static PublicKey loadGATKDistributedPublicKey() {
+ InputStream publicKeyInputStream = ClassLoader.getSystemResourceAsStream(GATK_DISTRIBUTED_PUBLIC_KEY_FILE_NAME);
+
+ if ( publicKeyInputStream == null ) {
+ throw new ReviewedGATKException(String.format("Could not locate the GATK public key %s in the classpath",
+ GATK_DISTRIBUTED_PUBLIC_KEY_FILE_NAME));
+ }
+
+ return readPublicKey(publicKeyInputStream);
+ }
+
+ /**
+ * Loads the master copy of the GATK private key. You must have the appropriate UNIX permissions
+ * to do this!
+ *
+ * @return The GATK master private key as a usable object
+ */
+ public static PrivateKey loadGATKMasterPrivateKey() {
+ return readPrivateKey(new File(GATK_MASTER_PRIVATE_KEY_FILE));
+ }
+
+ /**
+ * Loads the master copy of the GATK public key. This should always be the same as the
+ * public key distributed with the GATK returned by loadGATKDistributedPublicKey().
+ *
+ * @return The GATK master public key as a usable object
+ */
+ public static PublicKey loadGATKMasterPublicKey() {
+ return readPublicKey(new File(GATK_MASTER_PUBLIC_KEY_FILE));
+ }
+
+ /**
+ * Encrypts the given data using the key provided.
+ *
+ * @param data The data to encrypt, as a byte array
+ * @param encryptKey The key with which to encrypt the data
+ * @return The encrypted version of the provided data
+ */
+ public static byte[] encryptData ( byte[] data, Key encryptKey ) {
+ return transformDataUsingCipher(data, encryptKey, Cipher.ENCRYPT_MODE);
+ }
+
+ /**
+ * Decrypts the given data using the key provided.
+ *
+ * @param encryptedData Data to decrypt, as a byte array
+ * @param decryptKey The key with which to decrypt the data
+ * @return The decrypted version of the provided data
+ */
+ public static byte[] decryptData ( byte[] encryptedData, Key decryptKey ) {
+ return transformDataUsingCipher(encryptedData, decryptKey, Cipher.DECRYPT_MODE);
+ }
+
+ /**
+ * Helper method for encryption/decryption that takes data and processes it using
+ * the given key
+ *
+ * @param data Data to encrypt/decrypt
+ * @param key Key to use to encrypt/decrypt the data
+ * @param cipherMode Specifies whether we are encrypting or decrypting
+ * @return The encrypted/decrypted data
+ */
+ private static byte[] transformDataUsingCipher ( byte[] data, Key key, int cipherMode ) {
+ try {
+ Cipher cipher = Cipher.getInstance(key.getAlgorithm());
+ cipher.init(cipherMode, key);
+ return cipher.doFinal(data);
+ }
+ catch ( NoSuchAlgorithmException e ) {
+ throw new ReviewedGATKException(String.format("Could not find an implementation of the requested algorithm %s",
+ key.getAlgorithm()), e);
+ }
+ catch ( InvalidKeyException e ) {
+ throw new ReviewedGATKException("Key is invalid", e);
+ }
+ catch ( GeneralSecurityException e ) {
+ throw new ReviewedGATKException("Error during encryption", e);
+ }
+ }
+
+ /**
+ * Tests whether the public/private keys provided can each decrypt data encrypted by
+ * the other key -- ie., tests whether these two keys are part of the same public/private
+ * key pair.
+ *
+ * @param privateKey The private key to test
+ * @param publicKey The public key to test
+ * @return True if the keys are part of the same key pair and can decrypt each other's
+ * encrypted data, otherwise false.
+ */
+ public static boolean keysDecryptEachOther ( PrivateKey privateKey, PublicKey publicKey ) {
+ byte[] plainText = "Test PlainText".getBytes();
+
+ byte[] dataEncryptedUsingPrivateKey = CryptUtils.encryptData(plainText, privateKey);
+ byte[] dataEncryptedUsingPublicKey = CryptUtils.encryptData(plainText, publicKey);
+
+ byte[] privateKeyDataDecryptedWithPublicKey = CryptUtils.decryptData(dataEncryptedUsingPrivateKey, publicKey);
+ byte[] publicKeyDataDecryptedWithPrivateKey = CryptUtils.decryptData(dataEncryptedUsingPublicKey, privateKey);
+
+ // Make sure we actually transformed the data during encryption:
+ if ( Arrays.equals(plainText, dataEncryptedUsingPrivateKey) ||
+ Arrays.equals(plainText, dataEncryptedUsingPublicKey) ||
+ Arrays.equals(dataEncryptedUsingPrivateKey, dataEncryptedUsingPublicKey) ) {
+ return false;
+ }
+
+ // Make sure that we were able to recreate the original plaintext using
+ // both the public key on the private-key-encrypted data and the private
+ // key on the public-key-encrypted data:
+ if ( ! Arrays.equals(plainText, privateKeyDataDecryptedWithPublicKey) ||
+ ! Arrays.equals(plainText, publicKeyDataDecryptedWithPrivateKey) ) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/crypt/GATKKey.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/crypt/GATKKey.java
new file mode 100644
index 0000000..ab21a2a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/crypt/GATKKey.java
@@ -0,0 +1,350 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.crypt;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.io.IOUtils;
+
+import java.io.*;
+import java.security.*;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * Class to represent a GATK user key.
+ *
+ * A GATK user key contains an email address and a cryptographic signature.
+ * The signature is the SHA-1 hash of the email address encrypted using
+ * the GATK master private key. The GATK master public key (distributed
+ * with the GATK) is used to decrypt the signature and validate the key
+ * at the start of each GATK run that requires a key.
+ *
+ * Keys are cryptographically secure in that valid keys definitely come
+ * from us and cannot be fabricated, however nothing prevents keys from
+ * being shared between users.
+ *
+ * GATK user keys have the following on-disk format:
+ *
+ * GZIP Container:
+ * Email address
+ * NUL byte (delimiter)
+ * Cryptographic Signature (encrypted SHA-1 hash of email address)
+ *
+ * The key data is wrapped within a GZIP container to placate over-zealous
+ * email filters (since keys must often be emailed) and also to provide an
+ * additional integrity check via the built-in GZIP CRC.
+ *
+ * @author David Roazen
+ */
+public class GATKKey {
+
+ /**
+ * Private key used to sign the GATK key. Required only when creating a new
+ * key from scratch, not when loading an existing key from disk.
+ */
+ private PrivateKey privateKey;
+
+ /**
+ * Public key used to validate the GATK key.
+ */
+ private PublicKey publicKey;
+
+ /**
+ * The user's email address, stored within the key and signed.
+ */
+ private String emailAddress;
+
+ /**
+ * The cryptographic signature of the email address. By default, this is
+ * the SHA-1 hash of the email address encrypted using the RSA algorithm.
+ */
+ private byte[] signature;
+
+ /**
+ * The combination of hash/encryption algorithms to use to generate the signature.
+ * By default this is "SHA1withRSA"
+ */
+ private String signingAlgorithm;
+
+ /**
+ * Default hash/encryption algorithms to use to sign the key.
+ */
+ public static final String DEFAULT_SIGNING_ALGORITHM = "SHA1withRSA";
+
+ /**
+ * Byte value used to separate the email address from its signature in the key file.
+ */
+ public static final byte GATK_KEY_SECTIONAL_DELIMITER = 0;
+
+
+ // -----------------------
+ // Constructors:
+ // -----------------------
+
+ /**
+ * Constructor to create a new GATK key from scratch using an email address
+ * and public/private key pair. The private key is used for signing, and the
+ * public key is used to validate the newly-created key.
+ *
+ * @param privateKey Private key used to sign the new GATK key
+ * @param publicKey Public key used to validate the new GATK key
+ * @param emailAddress The user's email address, which we will store in the key and sign
+ */
+ public GATKKey ( PrivateKey privateKey, PublicKey publicKey, String emailAddress ) {
+ this(privateKey, publicKey, emailAddress, DEFAULT_SIGNING_ALGORITHM);
+ }
+
+ /**
+ * Constructor to create a new GATK key from scratch using an email address
+ * and public/private key pair, and additionally specify the signing algorithm
+ * to use. The private key is used for signing, and the public key is used to
+ * validate the newly-created key.
+ *
+ * @param privateKey Private key used to sign the new GATK key
+ * @param publicKey Public key used to validate the new GATK key
+ * @param emailAddress The user's email address, which we will store in the key and sign
+ * @param signingAlgorithm The combination of hash and encryption algorithms to use to sign the key
+ */
+ public GATKKey ( PrivateKey privateKey, PublicKey publicKey, String emailAddress, String signingAlgorithm ) {
+ if ( privateKey == null || publicKey == null || emailAddress == null || emailAddress.length() == 0 || signingAlgorithm == null ) {
+ throw new ReviewedGATKException("Cannot construct GATKKey using null/empty arguments");
+ }
+
+ this.privateKey = privateKey;
+ this.publicKey = publicKey;
+ this.emailAddress = emailAddress;
+ this.signingAlgorithm = signingAlgorithm;
+
+ validateEmailAddress();
+ generateSignature();
+
+ if ( ! isValid() ) {
+ throw new ReviewedGATKException("Newly-generated GATK key fails validation -- this should never happen!");
+ }
+ }
+
+ /**
+ * Constructor to load an existing GATK key from a file.
+ *
+ * During loading, the key file is checked for integrity, but not cryptographic
+ * validity (which must be done through a subsequent call to isValid()).
+ *
+ * @param publicKey Public key that will be used to validate the loaded GATK key
+ * in subsequent calls to isValid()
+ * @param keyFile File containing the GATK key to load
+ */
+ public GATKKey ( PublicKey publicKey, File keyFile ) {
+ this(publicKey, keyFile, DEFAULT_SIGNING_ALGORITHM);
+ }
+
+ /**
+ * Constructor to load an existing GATK key from a file, and additionally specify
+ * the signing algorithm used to sign the key being loaded.
+ *
+ * During loading, the key file is checked for integrity, but not cryptographic
+ * validity (which must be done through a subsequent call to isValid()).
+ *
+ * @param publicKey Public key that will be used to validate the loaded GATK key
+ * in subsequent calls to isValid()
+ * @param keyFile File containing the GATK key to load
+ * @param signingAlgorithm The combination of hash and encryption algorithms used to sign the key
+ */
+ public GATKKey ( PublicKey publicKey, File keyFile, String signingAlgorithm ) {
+ if ( publicKey == null || keyFile == null || signingAlgorithm == null ) {
+ throw new ReviewedGATKException("Cannot construct GATKKey using null arguments");
+ }
+
+ this.publicKey = publicKey;
+ this.signingAlgorithm = signingAlgorithm;
+
+ readKey(keyFile);
+ }
+
+ // -----------------------
+ // Public API Methods:
+ // -----------------------
+
+ /**
+ * Writes out this key to a file in the format described at the top of this class,
+ * encapsulating the key within a GZIP container.
+ *
+ * @param destination File to write the key to
+ */
+ public void writeKey ( File destination ) {
+ try {
+ byte[] keyBytes = marshalKeyData();
+ IOUtils.writeByteArrayToStream(keyBytes, new GZIPOutputStream(new FileOutputStream(destination)));
+ }
+ catch ( IOException e ) {
+ throw new UserException.CouldNotCreateOutputFile(destination, e);
+ }
+ }
+
+ /**
+ * Checks whether the signature of this key is cryptographically valid (ie., can be
+ * decrypted by the public key to produce a valid SHA-1 hash of the email address
+ * in the key).
+ *
+ * @return True if the key's signature passes validation, otherwise false
+ */
+ public boolean isValid() {
+ try {
+ Signature sig = Signature.getInstance(signingAlgorithm);
+ sig.initVerify(publicKey);
+ sig.update(emailAddress.getBytes());
+ return sig.verify(signature);
+ }
+ catch ( NoSuchAlgorithmException e ) {
+ throw new ReviewedGATKException(String.format("Signing algorithm %s not found", signingAlgorithm), e);
+ }
+ catch ( InvalidKeyException e ) {
+ // If the GATK public key is invalid, it's likely our problem, not the user's:
+ throw new ReviewedGATKException(String.format("Public key %s is invalid", publicKey), e);
+ }
+ catch ( SignatureException e ) {
+ throw new UserException.UnreadableKeyException("Signature is invalid or signing algorithm was unable to process the input data", e);
+ }
+ }
+
+ // -----------------------
+ // Private Helper Methods:
+ // -----------------------
+
+ /**
+ * Helper method that creates a signature for this key using the combination of
+ * hash/encryption algorithms specified at construction time.
+ */
+ private void generateSignature() {
+ try {
+ Signature sig = Signature.getInstance(signingAlgorithm);
+ sig.initSign(privateKey, CryptUtils.createRandomnessSource());
+ sig.update(emailAddress.getBytes());
+ signature = sig.sign();
+ }
+ catch ( NoSuchAlgorithmException e ) {
+ throw new ReviewedGATKException(String.format("Signing algorithm %s not found", signingAlgorithm), e);
+ }
+ catch ( InvalidKeyException e ) {
+ throw new ReviewedGATKException(String.format("Private key %s is invalid", privateKey), e);
+ }
+ catch ( SignatureException e ) {
+ throw new ReviewedGATKException(String.format("Error creating signature for email address %s", emailAddress), e);
+ }
+ }
+
+ /**
+ * Helper method that reads in a GATK key from a file. Should not be called directly --
+ * use the appropriate constructor above.
+ *
+ * @param source File to read the key from
+ */
+ private void readKey ( File source ) {
+ try {
+ byte[] keyBytes = IOUtils.readStreamIntoByteArray(new GZIPInputStream(new FileInputStream(source)));
+
+ // As a sanity check, compare the number of bytes read to the uncompressed file size
+ // stored in the GZIP ISIZE field. If they don't match, the key must be corrupt:
+ if ( keyBytes.length != IOUtils.getGZIPFileUncompressedSize(source) ) {
+ throw new UserException.UnreadableKeyException("Number of bytes read does not match the uncompressed size specified in the GZIP ISIZE field");
+ }
+
+ unmarshalKeyData(keyBytes);
+ }
+ catch ( FileNotFoundException e ) {
+ throw new UserException.CouldNotReadInputFile(source, e);
+ }
+ catch ( IOException e ) {
+ throw new UserException.UnreadableKeyException(source, e);
+ }
+ catch ( UserException.CouldNotReadInputFile e ) {
+ throw new UserException.UnreadableKeyException(source, e);
+ }
+ }
+
+ /**
+ * Helper method that assembles the email address and signature into a format
+ * suitable for writing to disk.
+ *
+ * @return The aggregated key data, ready to be written to disk
+ */
+ private byte[] marshalKeyData() {
+ byte[] emailAddressBytes = emailAddress.getBytes();
+ byte[] assembledKey = new byte[emailAddressBytes.length + 1 + signature.length];
+
+ System.arraycopy(emailAddressBytes, 0, assembledKey, 0, emailAddressBytes.length);
+ assembledKey[emailAddressBytes.length] = GATK_KEY_SECTIONAL_DELIMITER;
+ System.arraycopy(signature, 0, assembledKey, emailAddressBytes.length + 1, signature.length);
+
+ return assembledKey;
+ }
+
+ /**
+ * Helper method that parses the raw key data from disk into its component
+ * email address and signature. Performs some basic validation in the process.
+ *
+ * @param keyBytes The raw, uncompressed key data read from disk
+ */
+ private void unmarshalKeyData ( byte[] keyBytes ) {
+ int delimiterPosition = -1;
+
+ for ( int i = 0; i < keyBytes.length; i++ ) {
+ if ( keyBytes[i] == GATK_KEY_SECTIONAL_DELIMITER ) {
+ delimiterPosition = i;
+ break;
+ }
+ }
+
+ if ( delimiterPosition == -1 ) {
+ throw new UserException.UnreadableKeyException("Malformed GATK key contains no sectional delimiter");
+ }
+ else if ( delimiterPosition == 0 ) {
+ throw new UserException.UnreadableKeyException("Malformed GATK key contains no email address");
+ }
+ else if ( delimiterPosition == keyBytes.length - 1 ) {
+ throw new UserException.UnreadableKeyException("Malformed GATK key contains no signature");
+ }
+
+ byte[] emailAddressBytes = new byte[delimiterPosition];
+ System.arraycopy(keyBytes, 0, emailAddressBytes, 0, delimiterPosition);
+ emailAddress = new String(emailAddressBytes);
+
+ signature = new byte[keyBytes.length - delimiterPosition - 1];
+ System.arraycopy(keyBytes, delimiterPosition + 1, signature, 0, keyBytes.length - delimiterPosition - 1);
+ }
+
+ /**
+ * Helper method that ensures that the user's email address does not contain the NUL byte, which we
+ * reserve as a delimiter within each key file.
+ */
+ private void validateEmailAddress() {
+ for ( byte b : emailAddress.getBytes() ) {
+ if ( b == GATK_KEY_SECTIONAL_DELIMITER ) {
+ throw new UserException(String.format("Email address must not contain a byte with value %d", GATK_KEY_SECTIONAL_DELIMITER));
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/duplicates/DupUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/duplicates/DupUtils.java
new file mode 100644
index 0000000..3d27407
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/duplicates/DupUtils.java
@@ -0,0 +1,142 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.duplicates;
+
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.QualityUtils;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileupImpl;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class DupUtils {
+ private static GATKSAMRecord tmpCopyRead(GATKSAMRecord read) {
+ return (GATKSAMRecord)read.clone();
+ }
+
+ public static GATKSAMRecord combineDuplicates(GenomeLocParser genomeLocParser,List<GATKSAMRecord> duplicates, int maxQScore) {
+ if ( duplicates.size() == 0 )
+ return null;
+
+ // make the combined read by copying the first read and setting the
+ // bases and quals to new arrays
+ GATKSAMRecord comb = tmpCopyRead(duplicates.get(0));
+ //GATKSAMRecord comb = tmpCopyRead(duplicates.get(0));
+ comb.setDuplicateReadFlag(false);
+ int readLen = comb.getReadBases().length;
+ byte[] bases = new byte[readLen];
+ byte[] quals = new byte[readLen];
+
+ for ( int i = 0; i < readLen; i++ ) {
+ //System.out.printf("I is %d%n", i);
+ //for ( GATKSAMRecord read : duplicates ) {
+ // System.out.printf("dup base %c %d%n", (char)read.getReadBases()[i], read.getBaseQualities()[i]);
+ //}
+ Pair<Byte, Byte> baseAndQual = combineBaseProbs(genomeLocParser,duplicates, i, maxQScore);
+ bases[i] = baseAndQual.getFirst();
+ quals[i] = baseAndQual.getSecond();
+ }
+
+
+ comb.setBaseQualities(quals);
+ comb.setReadBases(bases);
+
+ return comb;
+ }
+
+ private static Pair<Byte, Byte> baseProbs2BaseAndQual(double[] probs, int maxQScore) {
+ byte bestBase = 0;
+ double bestProb = Double.NEGATIVE_INFINITY;
+ double sumProbs = 0;
+
+ for ( int i = 0; i < 4; i++ ) {
+ sumProbs += Math.pow(10, probs[i]);
+ //System.out.printf("Bestprob is %f > %f%n", bestProb, probs[i]);
+ if ( probs[i] > bestProb ) {
+ bestBase = BaseUtils.baseIndexToSimpleBase(i);
+ bestProb = probs[i];
+ }
+ }
+
+ Arrays.sort(probs);
+ double normalizedP = Math.pow(10, bestProb) / sumProbs;
+ byte qual = QualityUtils.trueProbToQual(normalizedP, maxQScore);
+// if ( false ) {
+// System.out.printf("Best base is %s %.8f%n", bestBase, bestProb);
+// System.out.printf("2nd base is %.8f%n", probs[1]);
+// System.out.printf("normalized P %.8f%n", normalizedP);
+// System.out.printf("normalized Q %.8f%n", 1 - normalizedP);
+// System.out.printf("max Q %2d%n", maxQScore);
+// System.out.printf("eps %.8f%n", eps);
+// System.out.printf("encoded Q %2d%n", qual);
+// }
+
+ return new Pair<Byte, Byte>(bestBase, qual);
+ }
+
+ private static void print4BaseQuals(String header, double[] probs) {
+ System.out.printf("%s log10(P(b)) is ", header);
+ for ( int i = 0; i < 4; i++ ) {
+ System.out.printf("%c=%+.8f ", (char)BaseUtils.baseIndexToSimpleBase(i), probs[i]);
+ }
+ System.out.printf("%n");
+ }
+
+ private static Pair<Byte, Byte> combineBaseProbs(GenomeLocParser genomeLocParser,List<GATKSAMRecord> duplicates, int readOffset, int maxQScore) {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc(duplicates.get(0));
+ ReadBackedPileup pileup = new ReadBackedPileupImpl(loc, duplicates, readOffset);
+
+ final boolean debug = false;
+
+ // calculate base probs
+ double[] qualSums = {0.0, 0.0, 0.0, 0.0};
+ if ( debug ) print4BaseQuals("start", qualSums);
+
+ for (PileupElement e : pileup ) {
+ int baseIndex = e.getBaseIndex();
+ byte qual = e.getQual();
+ double pqual = QualityUtils.qualToProb(qual);
+ for ( int j = 0; j < 4; j++) {
+ qualSums[j] += Math.log10(j == baseIndex ? pqual : (1 - pqual)/3);
+ }
+
+ if ( debug ) print4BaseQuals(String.format("%c Q%2d", e.getBase(), qual), qualSums);
+ }
+ if ( debug ) print4BaseQuals("final", qualSums);
+
+ Pair<Byte, Byte> combined = baseProbs2BaseAndQual(qualSums, maxQScore);
+ if ( debug ) System.out.printf("%s => %c Q%s%n", pileup.getPileupString('N'), (char)(byte)combined.getFirst(), combined.getSecond());
+
+ return combined;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/duplicates/DuplicateComp.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/duplicates/DuplicateComp.java
new file mode 100644
index 0000000..9213a3e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/duplicates/DuplicateComp.java
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.duplicates;
+
+public class DuplicateComp {
+ public int getQLarger() {
+ return qLarger;
+ }
+
+ public void setQLarger(int qLarger) {
+ this.qLarger = qLarger;
+ }
+
+ public int getQSmaller() {
+ return qSmaller;
+ }
+
+ public void setQSmaller(int qSmaller) {
+ this.qSmaller = qSmaller;
+ }
+
+ public boolean isMismatchP() {
+ return mismatchP;
+ }
+
+ public void setMismatchP(boolean mismatchP) {
+ this.mismatchP = mismatchP;
+ }
+
+ private int qLarger;
+ private int qSmaller;
+ private boolean mismatchP;
+
+ public DuplicateComp(int qLarger, int qSmaller, boolean misMatchP) {
+ this.qLarger = qLarger;
+ this.qSmaller = qSmaller;
+ this.mismatchP = misMatchP;
+ }
+
+ public String toString() {
+ return String.format("%d %d %b", qLarger, qSmaller, mismatchP);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/exceptions/DynamicClassResolutionException.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/exceptions/DynamicClassResolutionException.java
new file mode 100644
index 0000000..1c53420
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/exceptions/DynamicClassResolutionException.java
@@ -0,0 +1,54 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.exceptions;
+
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Class for handling common failures of dynamic class resolution
+ */
+public class DynamicClassResolutionException extends UserException {
+ public DynamicClassResolutionException(Class c, Exception ex) {
+ super(String.format("Could not create module %s because %s caused by exception %s",
+ c.getSimpleName(), moreInfo(ex), ex.getMessage()));
+ }
+
+ private static String moreInfo(Exception ex) {
+ try {
+ throw ex;
+ } catch (InstantiationException e) {
+ return "BUG: cannot instantiate class: must be concrete class";
+ } catch (NoSuchMethodException e) {
+ return "BUG: Cannot find expected constructor for class";
+ } catch (IllegalAccessException e) {
+ return "Cannot instantiate class (Illegal Access)";
+ } catch (InvocationTargetException e) {
+ return "Cannot instantiate class (Invocation failure)";
+ } catch ( Exception e ) {
+ return String.format("an exception of type %s occurred",e.getClass().getSimpleName());
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/exceptions/UserException.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/exceptions/UserException.java
new file mode 100644
index 0000000..07db4fc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/exceptions/UserException.java
@@ -0,0 +1,485 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.exceptions;
+
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMSequenceDictionary;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.help.DocumentedGATKFeature;
+import org.broadinstitute.gatk.utils.help.HelpConstants;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVCFIndexType;
+import htsjdk.variant.variantcontext.VariantContext;
+
+import java.io.File;
+
+/**
+ * Represents the common user errors detected by GATK
+ *
+ * Root class for all GATK user errors, as well as the container for errors themselves
+ */
+ at DocumentedGATKFeature(
+ groupName = HelpConstants.DOCS_CAT_USRERR,
+ summary = "Errors caused by incorrect user behavior, such as bad files, bad arguments, etc." )
+public class UserException extends ReviewedGATKException {
+ /**
+ * The URL where people can get help messages. Printed when an error occurs
+ */
+ public static final String PHONE_HOME_DOCS_URL = "http://gatkforums.broadinstitute.org/discussion/1250/what-is-phone-home-and-how-does-it-affect-me#latest";
+
+ public UserException(String msg) { super(msg); }
+ public UserException(String msg, Throwable e) { super(msg, e); }
+ private UserException(Throwable e) { super("", e); } // cannot be called, private access
+
+ protected static String getMessage(Throwable t) {
+ String message = t.getMessage();
+ return message != null ? message : t.getClass().getName();
+ }
+
+ public static class CommandLineException extends UserException {
+ public CommandLineException(String message) {
+ super(String.format("Invalid command line: %s", message));
+ }
+ }
+
+ public static class MalformedReadFilterException extends CommandLineException {
+ public MalformedReadFilterException(String message) {
+ super(String.format("Malformed read filter: %s",message));
+ }
+ }
+
+ public static class IncompatibleReadFiltersException extends CommandLineException {
+ public IncompatibleReadFiltersException(final String filter1, final String filter2) {
+ super(String.format("Two read filters are enabled that are incompatible and cannot be used simultaneously: %s and %s", filter1, filter2));
+ }
+ }
+
+ public static class MalformedWalkerArgumentsException extends CommandLineException {
+ public MalformedWalkerArgumentsException(String message) {
+ super(String.format("Malformed walker argument: %s",message));
+ }
+ }
+
+ public static class UnsupportedCigarOperatorException extends UserException {
+ public UnsupportedCigarOperatorException(final CigarOperator co, final SAMRecord read, final String message) {
+ super(String.format(
+ "Unsupported CIGAR operator %s in read %s at %s:%d. %s",
+ co,
+ read.getReadName(),
+ read.getReferenceName(),
+ read.getAlignmentStart(),
+ message));
+ }
+ }
+
+
+ public static class MalformedGenomeLoc extends UserException {
+ public MalformedGenomeLoc(String message, GenomeLoc loc) {
+ super(String.format("Badly formed genome loc: %s: %s", message, loc));
+ }
+
+ public MalformedGenomeLoc(String message) {
+ super(String.format("Badly formed genome loc: %s", message));
+ }
+ }
+
+ public static class BadInput extends UserException {
+ public BadInput(String message) {
+ super(String.format("Bad input: %s", message));
+ }
+ }
+
+ // todo -- fix up exception cause passing
+ public static class MissingArgument extends CommandLineException {
+ public MissingArgument(String arg, String message) {
+ super(String.format("Argument %s was missing: %s", arg, message));
+ }
+ }
+
+ public static class BadArgumentValue extends CommandLineException {
+ public BadArgumentValue(String arg, String message) {
+ super(String.format("Argument %s has a bad value: %s", arg, message));
+ }
+ }
+
+ public static class UnknownTribbleType extends CommandLineException {
+ public UnknownTribbleType(String type, String message) {
+ super(String.format("Unknown tribble type %s: %s", type, message));
+ }
+ }
+
+
+ public static class BadTmpDir extends UserException {
+ public BadTmpDir(String message) {
+ super(String.format("Failure working with the tmp directory %s. Override with -Djava.io.tmpdir=X on the command line to a bigger/better file system. Exact error was %s", System.getProperties().get("java.io.tmpdir"), message));
+ }
+ }
+
+ public static class TooManyOpenFiles extends UserException {
+ public TooManyOpenFiles() {
+ super(String.format("There was a failure because there are too many files open concurrently; your system's open file handle limit is too small. See the unix ulimit command to adjust this limit"));
+ }
+ }
+
+ public static class LocalParallelizationProblem extends UserException {
+ public LocalParallelizationProblem(final File file) {
+ super(String.format("There was a failure because temporary file %s could not be found while running the GATK with more than one thread. Possible causes for this problem include: your system's open file handle limit is too small, your output or temp directories do not have sufficient space, or just an isolated file system blip", file.getAbsolutePath()));
+ }
+ }
+
+ public static class NotEnoughMemory extends UserException {
+ public NotEnoughMemory() {
+ super(String.format("There was a failure because you did not provide enough memory to run this program. See the -Xmx JVM argument to adjust the maximum heap size provided to Java"));
+ }
+ }
+
+ public static class ErrorWritingBamFile extends UserException {
+ public ErrorWritingBamFile(String message) {
+ super(String.format("An error occurred when trying to write the BAM file. Usually this happens when there is not enough space in the directory to which the data is being written (generally the temp directory) or when your system's open file handle limit is too small. To tell Java to use a bigger/better file system use -Djava.io.tmpdir=X on the command line. The exact error was %s", message));
+ }
+ }
+
+ public static class NoSpaceOnDevice extends UserException {
+ public NoSpaceOnDevice() {
+ super("There is no space left on the device, so writing failed");
+ }
+ }
+
+ public static class CouldNotReadInputFile extends UserException {
+ public CouldNotReadInputFile(String message, Exception e) {
+ super(String.format("Couldn't read file because %s caused by %s", message, getMessage(e)));
+ }
+
+ public CouldNotReadInputFile(File file) {
+ super(String.format("Couldn't read file %s", file.getAbsolutePath()));
+ }
+
+ public CouldNotReadInputFile(File file, String message) {
+ super(String.format("Couldn't read file %s because %s", file.getAbsolutePath(), message));
+ }
+
+ public CouldNotReadInputFile(String file, String message) {
+ super(String.format("Couldn't read file %s because %s", file, message));
+ }
+
+ public CouldNotReadInputFile(File file, String message, Exception e) {
+ super(String.format("Couldn't read file %s because %s with exception %s", file.getAbsolutePath(), message, getMessage(e)));
+ }
+
+ public CouldNotReadInputFile(File file, Exception e) {
+ this(file, getMessage(e));
+ }
+
+ public CouldNotReadInputFile(String message) {
+ super(message);
+ }
+ }
+
+
+ public static class CouldNotCreateOutputFile extends UserException {
+ public CouldNotCreateOutputFile(File file, String message, Exception e) {
+ super(String.format("Couldn't write file %s because %s with exception %s", file.getAbsolutePath(), message, getMessage(e)));
+ }
+
+ public CouldNotCreateOutputFile(File file, String message) {
+ super(String.format("Couldn't write file %s because %s", file.getAbsolutePath(), message));
+ }
+
+ public CouldNotCreateOutputFile(String filename, String message, Exception e) {
+ super(String.format("Couldn't write file %s because %s with exception %s", filename, message, getMessage(e)));
+ }
+
+ public CouldNotCreateOutputFile(File file, Exception e) {
+ super(String.format("Couldn't write file %s because exception %s", file.getAbsolutePath(), getMessage(e)));
+ }
+
+ public CouldNotCreateOutputFile(String message, Exception e) {
+ super(message, e);
+ }
+ }
+
+ public static class MissortedBAM extends UserException {
+ public MissortedBAM(SAMFileHeader.SortOrder order, File file, SAMFileHeader header) {
+ super(String.format("Missorted Input SAM/BAM files: %s is must be sorted in %s order but order was: %s", file, order, header.getSortOrder()));
+ }
+
+ public MissortedBAM(SAMFileHeader.SortOrder order, String message) {
+ super(String.format("Missorted Input SAM/BAM files: files are not sorted in %s order; %s", order, message));
+ }
+
+ public MissortedBAM(SAMFileHeader.SortOrder order, SAMRecord read, String message) {
+ super(String.format("Missorted Input SAM/BAM file %s: file sorted in %s order but %s is required; %s",
+ read.getFileSource().getReader(), read.getHeader().getSortOrder(), order, message));
+ }
+
+ public MissortedBAM(String message) {
+ super(String.format("Missorted Input SAM/BAM files: %s", message));
+ }
+ }
+
+ public static class MalformedBAM extends UserException {
+ public MalformedBAM(SAMRecord read, String message) {
+ this(read.getFileSource() != null ? read.getFileSource().getReader().toString() : "(none)", message);
+ }
+
+ public MalformedBAM(File file, String message) {
+ this(file.toString(), message);
+ }
+
+ public MalformedBAM(String source, String message) {
+ super(String.format("SAM/BAM file %s is malformed: %s", source, message));
+ }
+ }
+
+ public static class MisencodedBAM extends UserException {
+ public MisencodedBAM(SAMRecord read, String message) {
+ this(read.getFileSource() != null ? read.getFileSource().getReader().toString() : "(none)", message);
+ }
+
+ public MisencodedBAM(String source, String message) {
+ super(String.format("SAM/BAM file %s appears to be using the wrong encoding for quality scores: %s; please see the GATK --help documentation for options related to this error", source, message));
+ }
+ }
+
+ public static class MalformedVCF extends UserException {
+ public MalformedVCF(String message, String line) {
+ super(String.format("The provided VCF file is malformed at line %s: %s", line, message));
+ }
+
+ public MalformedVCF(String message) {
+ super(String.format("The provided VCF file is malformed: %s", message));
+ }
+
+ public MalformedVCF(String message, int lineNo) {
+ super(String.format("The provided VCF file is malformed at approximately line number %d: %s", lineNo, message));
+ }
+ }
+
+ public static class MalformedBCF2 extends UserException {
+ public MalformedBCF2( String message ) {
+ super(String.format("Malformed BCF2 file: %s", message));
+ }
+ }
+
+ public static class MalformedVCFHeader extends UserException {
+ public MalformedVCFHeader(String message) {
+ super(String.format("The provided VCF file has a malformed header: %s", message));
+ }
+ }
+
+ public static class ReadMissingReadGroup extends MalformedBAM {
+ public ReadMissingReadGroup(final SAMRecord read) {
+ super(read, String.format("Read %s is missing the read group (RG) tag, which is required by the GATK. Please use " + HelpConstants.forumPost("discussion/59/companion-utilities-replacereadgroups to fix this problem"), read.getReadName()));
+ }
+ }
+
+ public static class ReadHasUndefinedReadGroup extends MalformedBAM {
+ public ReadHasUndefinedReadGroup(final SAMRecord read, final String rgID) {
+ super(read, String.format("Read %s uses a read group (%s) that is not defined in the BAM header, which is not valid. Please use " + HelpConstants.forumPost("discussion/59/companion-utilities-replacereadgroups to fix this problem"), read.getReadName(), rgID));
+ }
+ }
+
+ public static class VariantContextMissingRequiredField extends UserException {
+ public VariantContextMissingRequiredField(String field, VariantContext vc) {
+ super(String.format("Variant at %s:%d is is missing the required field %s", vc.getChr(), vc.getStart(), field));
+ }
+ }
+
+ public static class MissortedFile extends UserException {
+ public MissortedFile(File file, String message, Exception e) {
+ super(String.format("Missorted Input file: %s is must be sorted in coordinate order. %s and got error %s", file, message, getMessage(e)));
+ }
+ }
+
+ public static class FailsStrictValidation extends UserException {
+ public FailsStrictValidation(File f, String message) {
+ super(String.format("File %s fails strict validation: %s", f.getAbsolutePath(), message));
+ }
+ }
+
+ public static class MalformedFile extends UserException {
+ public MalformedFile(String message) {
+ super(String.format("Unknown file is malformed: %s", message));
+ }
+
+ public MalformedFile(String message, Exception e) {
+ super(String.format("Unknown file is malformed: %s caused by %s", message, getMessage(e)));
+ }
+
+ public MalformedFile(File f, String message) {
+ super(String.format("File %s is malformed: %s", f.getAbsolutePath(), message));
+ }
+
+ public MalformedFile(File f, String message, Exception e) {
+ super(String.format("File %s is malformed: %s caused by %s", f.getAbsolutePath(), message, getMessage(e)));
+ }
+
+ public MalformedFile(String name, String message) {
+ super(String.format("File associated with name %s is malformed: %s", name, message));
+ }
+
+ public MalformedFile(String name, String message, Exception e) {
+ super(String.format("File associated with name %s is malformed: %s caused by %s", name, message, getMessage(e)));
+ }
+ }
+
+ public static class CannotExecuteRScript extends UserException {
+ public CannotExecuteRScript(String message) {
+ super(String.format("Unable to execute RScript command: " + message));
+ }
+ public CannotExecuteRScript(String message, Exception e) {
+ super(String.format("Unable to execute RScript command: " + message), e);
+ }
+ }
+
+ public static class DeprecatedArgument extends CommandLineException {
+ public DeprecatedArgument(String param, String doc) {
+ super(String.format("The parameter %s is deprecated. %s",param,doc));
+ }
+ }
+
+
+ public static class IncompatibleSequenceDictionaries extends UserException {
+ public IncompatibleSequenceDictionaries(String message, String name1, SAMSequenceDictionary dict1, String name2, SAMSequenceDictionary dict2) {
+ super(String.format("Input files %s and %s have incompatible contigs: %s.\n %s contigs = %s\n %s contigs = %s",
+ name1, name2, message, name1, ReadUtils.prettyPrintSequenceRecords(dict1), name2, ReadUtils.prettyPrintSequenceRecords(dict2)));
+ }
+ }
+
+ public static class LexicographicallySortedSequenceDictionary extends UserException {
+ public LexicographicallySortedSequenceDictionary(String name, SAMSequenceDictionary dict) {
+ super(String.format("Lexicographically sorted human genome sequence detected in %s."
+ + "\nFor safety's sake the GATK requires human contigs in karyotypic order: 1, 2, ..., 10, 11, ..., 20, 21, 22, X, Y with M either leading or trailing these contigs."
+ + "\nThis is because all distributed GATK resources are sorted in karyotypic order, and your processing will fail when you need to use these files."
+ + "\nYou can use the ReorderSam utility to fix this problem: " + HelpConstants.forumPost("discussion/58/companion-utilities-reordersam")
+ + "\n %s contigs = %s",
+ name, name, ReadUtils.prettyPrintSequenceRecords(dict)));
+ }
+ }
+
+ public static class DeprecatedWalker extends UserException {
+ public DeprecatedWalker(String walkerName, String version) {
+ super(String.format("Walker %s is no longer available in the GATK; it has been deprecated since version %s", walkerName, version));
+ }
+ }
+
+ public static class DeprecatedAnnotation extends UserException {
+ public DeprecatedAnnotation(String annotationName, String version) {
+ super(String.format("Annotation %s is no longer available in the GATK; it has been deprecated since version %s", annotationName, version));
+ }
+ }
+
+ public static class CannotExecuteQScript extends UserException {
+ public CannotExecuteQScript(String message) {
+ super(String.format("Unable to execute QScript: " + message));
+ }
+ public CannotExecuteQScript(String message, Exception e) {
+ super(String.format("Unable to execute QScript: " + message), e);
+ }
+ }
+
+ public static class CannotHandleGzippedRef extends UserException {
+ public CannotHandleGzippedRef() {
+ super("The GATK cannot process compressed (.gz) reference sequences. Please unzip the file and try again. Sorry for the inconvenience.");
+ }
+ }
+
+ public static class MissingReferenceFaiFile extends UserException {
+ public MissingReferenceFaiFile( final File indexFile, final File fastaFile ) {
+ super(String.format("Fasta index file %s for reference %s does not exist. Please see %s for help creating it.",
+ indexFile.getAbsolutePath(), fastaFile.getAbsolutePath(),
+ HelpConstants.forumPost("discussion/1601/how-can-i-prepare-a-fasta-file-to-use-as-reference")));
+ }
+ }
+
+ public static class MissingReferenceDictFile extends UserException {
+ public MissingReferenceDictFile( final File dictFile, final File fastaFile ) {
+ super(String.format("Fasta dict file %s for reference %s does not exist. Please see %s for help creating it.",
+ dictFile.getAbsolutePath(), fastaFile.getAbsolutePath(),
+ HelpConstants.forumPost("discussion/1601/how-can-i-prepare-a-fasta-file-to-use-as-reference")));
+ }
+ }
+
+ public static class UnreadableKeyException extends UserException {
+ public UnreadableKeyException ( File f, Exception e ) {
+ super(String.format("Key file %s cannot be read (possibly the key file is corrupt?). Error was: %s. " +
+ "Please see %s for help.",
+ f.getAbsolutePath(), getMessage(e), PHONE_HOME_DOCS_URL));
+ }
+
+ public UnreadableKeyException ( String message, Exception e ) {
+ this(String.format("%s. Error was: %s", message, getMessage(e)));
+ }
+
+ public UnreadableKeyException ( String message ) {
+ super(String.format("Key file cannot be read (possibly the key file is corrupt?): %s. " +
+ "Please see %s for help.",
+ message, PHONE_HOME_DOCS_URL));
+ }
+ }
+
+ public static class KeySignatureVerificationException extends UserException {
+ public KeySignatureVerificationException ( File f ) {
+ super(String.format("The signature in key file %s failed cryptographic verification. " +
+ "If this key was valid in the past, it's likely been revoked. " +
+ "Please see %s for help.",
+ f.getAbsolutePath(), PHONE_HOME_DOCS_URL));
+ }
+ }
+
+ public static class GVCFIndexException extends UserException {
+ public GVCFIndexException (GATKVCFIndexType indexType, int indexParameter) {
+ super(String.format("GVCF output requires a specific indexing strategy. Please re-run including the arguments " +
+ "-variant_index_type %s -variant_index_parameter %d.",
+ indexType, indexParameter));
+ }
+ }
+
+ /**
+ * A special exception that happens only in the case where
+ * the filesystem, by design or configuration, is completely unable
+ * to handle locking. This exception will specifically NOT be thrown
+ * in the case where the filesystem handles locking but is unable to
+ * acquire a lock due to concurrency.
+ */
+ public static class FileSystemInabilityToLockException extends UserException {
+ public FileSystemInabilityToLockException( String message ) {
+ super(message);
+ }
+
+ public FileSystemInabilityToLockException( String message, Exception innerException ) {
+ super(message,innerException);
+ }
+ }
+
+ public static class IncompatibleRecalibrationTableParameters extends UserException {
+ public IncompatibleRecalibrationTableParameters(String s) {
+ super(s);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fasta/ArtificialFastaUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fasta/ArtificialFastaUtils.java
new file mode 100644
index 0000000..bf03ec6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fasta/ArtificialFastaUtils.java
@@ -0,0 +1,154 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.fasta;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.List;
+
+
+/**
+ * @author aaron
+ * <p/>
+ * Class ArtificialFastaUtils
+ * <p/>
+ * artificial fasta utility class, for generating fake fastas.
+ */
+public class ArtificialFastaUtils {
+ public enum BASE_PATTERN {
+ RANDOM, ALL_A, ALL_T, ALL_C, ALL_G;
+ }
+
+ // what bases we support
+ public enum BASES {
+ A, T, C, G;
+ }
+
+ // create an artificial fasta file
+ public static void createArtificialFasta(String fileName,
+ List<String> contigNames,
+ List<Integer> contigSizes,
+ BASE_PATTERN pattern) {
+ PrintStream s;
+ try {
+ s = new PrintStream(new FileOutputStream(fileName));
+ } catch (FileNotFoundException e) {
+ throw new ReviewedGATKException("Filename " + fileName + " passed to the ArtificialFastaUtils generated a FileNotFound exception", e);
+ }
+ generateFakeFasta(contigNames, contigSizes, pattern, s);
+ }
+
+ // create an artificial fasta file
+ public static void createArtificialFasta(PrintStream stream,
+ List<String> contigNames,
+ List<Integer> contigSizes,
+ BASE_PATTERN pattern) {
+
+ generateFakeFasta(contigNames, contigSizes, pattern, stream);
+ }
+
+ /**
+ * create a fake fasta file
+ *
+ * @param contigNames the pile of contig names
+ * @param contigSizes the pile of contig sizes
+ * @param pattern the pattern to use for the base distrobution
+ * @param s the print stream to write to
+ */
+ private static void generateFakeFasta(List<String> contigNames, List<Integer> contigSizes, BASE_PATTERN pattern, PrintStream s) {
+ if (contigNames.size() != contigSizes.size()) {
+ throw new ReviewedGATKException("ArtificialContig name and size arrays are not equal sizes");
+ }
+ for (int x = 0; x < contigNames.size(); x++) {
+ ArtificialContig tig = new ArtificialContig(contigNames.get(x), contigSizes.get(x), pattern);
+ tig.write(s);
+ }
+ s.close();
+ }
+
+}
+
+
+/** the fake contig class, a fasta is made up of these */
+class ArtificialContig {
+ public static final int COLUMN_WIDTH = 80;
+
+ final protected String mName;
+ final protected int mSize;
+ final protected ArtificialFastaUtils.BASE_PATTERN mPattern;
+
+ public ArtificialContig(String name, int size, ArtificialFastaUtils.BASE_PATTERN pat) {
+ this.mName = name;
+ this.mSize = size;
+ this.mPattern = pat;
+ }
+
+ /**
+ * write out the contig to a stream
+ *
+ * @param stream
+ */
+ public void write(PrintStream stream) {
+ stream.println(">" + mName);
+ int count = 0;
+ while (count < mSize) {
+ for (int x = 0; x < COLUMN_WIDTH; x++) {
+ stream.print(generateAppropriateBase());
+ count++;
+ if (count >= mSize) {
+ break;
+ }
+ }
+ stream.println();
+ }
+ }
+
+ /**
+ * generate the appropriate base, given the BASE_PATTERN
+ *
+ * @return a base, as a string
+ */
+ public String generateAppropriateBase() {
+ switch (mPattern) {
+ case RANDOM:
+ return (ArtificialFastaUtils.BASES.values()[(int) Math.round(Math.random() * 4)]).toString();
+ case ALL_A:
+ return "A";
+ case ALL_T:
+ return "T";
+ case ALL_C:
+ return "C";
+ case ALL_G:
+ return "G";
+ default:
+ throw new ReviewedGATKException("Unknown base pattern");
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fasta/CachingIndexedFastaSequenceFile.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fasta/CachingIndexedFastaSequenceFile.java
new file mode 100644
index 0000000..05f2ccf
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fasta/CachingIndexedFastaSequenceFile.java
@@ -0,0 +1,311 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.fasta;
+
+import picard.PicardException;
+import htsjdk.samtools.reference.FastaSequenceIndex;
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequence;
+import htsjdk.samtools.SAMSequenceRecord;
+import htsjdk.samtools.util.StringUtil;
+import org.apache.log4j.Priority;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.BaseUtils;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+
+/**
+ * A caching version of the IndexedFastaSequenceFile that avoids going to disk as often as the raw indexer.
+ *
+ * Thread-safe! Uses a thread-local cache.
+ *
+ * Automatically upper-cases the bases coming in, unless the flag preserveCase is explicitly set.
+ * Automatically converts IUPAC bases to Ns, unless the flag preserveIUPAC is explicitly set.
+ */
+public class CachingIndexedFastaSequenceFile extends IndexedFastaSequenceFile {
+ protected static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(CachingIndexedFastaSequenceFile.class);
+
+ /** do we want to print debugging information about cache efficiency? */
+ private static final boolean PRINT_EFFICIENCY = false;
+
+ /** If we are printing efficiency info, what frequency should we do it at? */
+ private static final int PRINT_FREQUENCY = 10000;
+
+ /** The default cache size in bp */
+ public static final long DEFAULT_CACHE_SIZE = 1000000;
+
+ /** The cache size of this CachingIndexedFastaSequenceFile */
+ private final long cacheSize;
+
+ /** When we have a cache miss at position X, we load sequence from X - cacheMissBackup */
+ private final long cacheMissBackup;
+
+ /**
+ * If true, we will preserve the case of the original base in the genome
+ */
+ private final boolean preserveCase;
+
+ /**
+ * If true, we will preserve the IUPAC bases in the genome
+ */
+ private final boolean preserveIUPAC;
+
+ // information about checking efficiency
+ long cacheHits = 0;
+ long cacheMisses = 0;
+
+ /** Represents a specific cached sequence, with a specific start and stop, as well as the bases */
+ private static class Cache {
+ long start = -1, stop = -1;
+ ReferenceSequence seq = null;
+ }
+
+ /**
+ * Thread local cache to allow multi-threaded use of this class
+ */
+ private ThreadLocal<Cache> cache;
+ {
+ cache = new ThreadLocal<Cache> () {
+ @Override protected Cache initialValue() {
+ return new Cache();
+ }
+ };
+ }
+
+ /**
+ * Same as general constructor but allows one to override the default cacheSize
+ *
+ * @param fasta the file we will read our FASTA sequence from.
+ * @param index the index of the fasta file, used for efficient random access
+ * @param cacheSize the size in bp of the cache we will use for this reader
+ * @param preserveCase If true, we will keep the case of the underlying bases in the FASTA, otherwise everything is converted to upper case
+ * @param preserveIUPAC If true, we will keep the IUPAC bases in the FASTA, otherwise they are converted to Ns
+ */
+ public CachingIndexedFastaSequenceFile(final File fasta, final FastaSequenceIndex index, final long cacheSize, final boolean preserveCase, final boolean preserveIUPAC) {
+ super(fasta, index);
+ if ( cacheSize < 0 ) throw new IllegalArgumentException("cacheSize must be > 0");
+ this.cacheSize = cacheSize;
+ this.cacheMissBackup = Math.max(cacheSize / 1000, 1);
+ this.preserveCase = preserveCase;
+ this.preserveIUPAC = preserveIUPAC;
+ }
+
+ /**
+ * Open the given indexed fasta sequence file. Throw an exception if the file cannot be opened.
+ *
+ * Looks for a index file for fasta on disk
+ * Uses provided cacheSize instead of the default
+ *
+ * @param fasta The file to open.
+ * @param cacheSize the size of the cache to use in this CachingIndexedFastaReader, must be >= 0
+ * @param preserveCase If true, we will keep the case of the underlying bases in the FASTA, otherwise everything is converted to upper case
+ */
+ public CachingIndexedFastaSequenceFile(final File fasta, final long cacheSize, final boolean preserveCase, final boolean preserveIUPAC) throws FileNotFoundException {
+ super(fasta);
+ if ( cacheSize < 0 ) throw new IllegalArgumentException("cacheSize must be > 0");
+ this.cacheSize = cacheSize;
+ this.cacheMissBackup = Math.max(cacheSize / 1000, 1);
+ this.preserveCase = preserveCase;
+ this.preserveIUPAC = preserveIUPAC;
+ }
+
+ /**
+ * Same as general constructor but allows one to override the default cacheSize
+ *
+ * By default, this CachingIndexedFastaReader converts all incoming bases to upper case
+ *
+ * @param fasta the file we will read our FASTA sequence from.
+ * @param index the index of the fasta file, used for efficient random access
+ * @param cacheSize the size in bp of the cache we will use for this reader
+ */
+ public CachingIndexedFastaSequenceFile(final File fasta, final FastaSequenceIndex index, final long cacheSize) {
+ this(fasta, index, cacheSize, false, false);
+ }
+
+ /**
+ * Open the given indexed fasta sequence file. Throw an exception if the file cannot be opened.
+ *
+ * Looks for a index file for fasta on disk.
+ * This CachingIndexedFastaReader will convert all FASTA bases to upper cases under the hood
+ *
+ * @param fasta The file to open.
+ */
+ public CachingIndexedFastaSequenceFile(final File fasta) throws FileNotFoundException {
+ this(fasta, false);
+ }
+
+ /**
+ * Open the given indexed fasta sequence file. Throw an exception if the file cannot be opened.
+ *
+ * Looks for a index file for fasta on disk
+ *
+ * @param fasta The file to open.
+ * @param preserveCase If true, we will keep the case of the underlying bases in the FASTA, otherwise everything is converted to upper case
+ */
+ public CachingIndexedFastaSequenceFile(final File fasta, final boolean preserveCase) throws FileNotFoundException {
+ this(fasta, DEFAULT_CACHE_SIZE, preserveCase, false);
+ }
+
+ /**
+ * Open the given indexed fasta sequence file. Throw an exception if the file cannot be opened.
+ *
+ * Looks for a index file for fasta on disk
+ * Uses provided cacheSize instead of the default
+ *
+ * @param fasta The file to open.
+ * @param cacheSize the size of the cache to use in this CachingIndexedFastaReader, must be >= 0
+ */
+ public CachingIndexedFastaSequenceFile(final File fasta, final long cacheSize ) throws FileNotFoundException {
+ this(fasta, cacheSize, false, false);
+ }
+
+ /**
+ * Print the efficiency (hits / queries) to logger with priority
+ */
+ public void printEfficiency(final Priority priority) {
+ logger.log(priority, String.format("### CachingIndexedFastaReader: hits=%d misses=%d efficiency %.6f%%", cacheHits, cacheMisses, calcEfficiency()));
+ }
+
+ /**
+ * Returns the efficiency (% of hits of all queries) of this object
+ * @return
+ */
+ public double calcEfficiency() {
+ return 100.0 * cacheHits / (cacheMisses + cacheHits * 1.0);
+ }
+
+ /**
+ * @return the number of cache hits that have occurred
+ */
+ public long getCacheHits() {
+ return cacheHits;
+ }
+
+ /**
+ * @return the number of cache misses that have occurred
+ */
+ public long getCacheMisses() {
+ return cacheMisses;
+ }
+
+ /**
+ * @return the size of the cache we are using
+ */
+ public long getCacheSize() {
+ return cacheSize;
+ }
+
+ /**
+ * Is this CachingIndexedFastaReader keeping the original case of bases in the fasta, or is
+ * everything being made upper case?
+ *
+ * @return true if the bases coming from this reader are in the original case in the fasta, false if they are all upper cased
+ */
+ public boolean isPreservingCase() {
+ return preserveCase;
+ }
+
+ /**
+ * Is uppercasing bases?
+ *
+ * @return true if bases coming from this CachingIndexedFastaSequenceFile are all upper cased, false if this reader are in the original case in the fasta
+ */
+ public boolean isUppercasingBases() {
+ return ! isPreservingCase();
+ }
+
+ /**
+ * Is this CachingIndexedFastaReader keeping the IUPAC bases in the fasta, or is it turning them into Ns?
+ *
+ * @return true if the IUPAC bases coming from this reader are not modified
+ */
+ public boolean isPreservingIUPAC() {
+ return preserveIUPAC;
+ }
+
+ /**
+ * Gets the subsequence of the contig in the range [start,stop]
+ *
+ * Uses the sequence cache if possible, or updates the cache to handle the request. If the range
+ * is larger than the cache itself, just loads the sequence directly, not changing the cache at all
+ *
+ * @param contig Contig whose subsequence to retrieve.
+ * @param start inclusive, 1-based start of region.
+ * @param stop inclusive, 1-based stop of region.
+ * @return The partial reference sequence associated with this range. If preserveCase is false, then
+ * all of the bases in the ReferenceSequence returned by this method will be upper cased.
+ */
+ @Override
+ public ReferenceSequence getSubsequenceAt( final String contig, long start, final long stop ) {
+ final ReferenceSequence result;
+ final Cache myCache = cache.get();
+
+ if ( (stop - start) >= cacheSize ) {
+ cacheMisses++;
+ result = super.getSubsequenceAt(contig, start, stop);
+ if ( ! preserveCase ) StringUtil.toUpperCase(result.getBases());
+ if ( ! preserveIUPAC ) BaseUtils.convertIUPACtoN(result.getBases(), true, start < 1);
+ } else {
+ // todo -- potential optimization is to check if contig.name == contig, as this in general will be true
+ SAMSequenceRecord contigInfo = super.getSequenceDictionary().getSequence(contig);
+
+ if (stop > contigInfo.getSequenceLength())
+ throw new PicardException("Query asks for data past end of contig");
+
+ if ( start < myCache.start || stop > myCache.stop || myCache.seq == null || myCache.seq.getContigIndex() != contigInfo.getSequenceIndex() ) {
+ cacheMisses++;
+ myCache.start = Math.max(start - cacheMissBackup, 0);
+ myCache.stop = Math.min(start + cacheSize + cacheMissBackup, contigInfo.getSequenceLength());
+ myCache.seq = super.getSubsequenceAt(contig, myCache.start, myCache.stop);
+
+ // convert all of the bases in the sequence to upper case if we aren't preserving cases
+ if ( ! preserveCase ) StringUtil.toUpperCase(myCache.seq.getBases());
+ if ( ! preserveIUPAC ) BaseUtils.convertIUPACtoN(myCache.seq.getBases(), true, myCache.start == 0);
+ } else {
+ cacheHits++;
+ }
+
+ // at this point we determine where in the cache we want to extract the requested subsequence
+ final int cacheOffsetStart = (int)(start - myCache.start);
+ final int cacheOffsetStop = (int)(stop - start + cacheOffsetStart + 1);
+
+ try {
+ result = new ReferenceSequence(myCache.seq.getName(), myCache.seq.getContigIndex(), Arrays.copyOfRange(myCache.seq.getBases(), cacheOffsetStart, cacheOffsetStop));
+ } catch ( ArrayIndexOutOfBoundsException e ) {
+ throw new ReviewedGATKException(String.format("BUG: bad array indexing. Cache start %d and end %d, request start %d end %d, offset start %d and end %d, base size %d",
+ myCache.start, myCache.stop, start, stop, cacheOffsetStart, cacheOffsetStop, myCache.seq.getBases().length), e);
+ }
+ }
+
+ // for debugging -- print out our efficiency if requested
+ if ( PRINT_EFFICIENCY && (getCacheHits() + getCacheMisses()) % PRINT_FREQUENCY == 0 )
+ printEfficiency(Priority.INFO);
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fasta/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fasta/package-info.java
new file mode 100644
index 0000000..ec94dac
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fasta/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.fasta;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/file/FSLockWithShared.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/file/FSLockWithShared.java
new file mode 100644
index 0000000..934a022
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/file/FSLockWithShared.java
@@ -0,0 +1,293 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.file;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.*;
+import java.util.concurrent.*;
+
+/**
+ * a quick implementation of a file based lock, using the Java NIO classes
+ */
+public class FSLockWithShared {
+ // connect to the logger
+ private final static Logger logger = Logger.getLogger(FSLockWithShared.class);
+
+ // the file we're attempting to lock
+ private final File file;
+
+ // the file lock
+ private FileLock lock = null;
+
+ // the file channel we open
+ private FileChannel channel = null;
+
+ // Timeout (in milliseconds) before we give up during non-blocking lock-acquisition calls.
+ // Necessary because these "non-blocking" calls can hang if there's a problem with the
+ // OS file locking support.
+ private int lockAcquisitionTimeout;
+
+ // Default value for lockAcquisitionTimeout when none is explicitly provided
+ public static final int DEFAULT_LOCK_ACQUISITION_TIMEOUT_IN_MILLISECONDS = 30 * 1000;
+
+ // Amount of time to wait when trying to shut down the lock-acquisition thread before giving up
+ public static final int THREAD_TERMINATION_TIMEOUT_IN_MILLISECONDS = 30 * 1000;
+
+ /**
+ * Create a lock associated with the specified File. Use the default lock
+ * acquisition timeout of 30 seconds.
+ *
+ * @param file file to lock
+ */
+ public FSLockWithShared( final File file ) {
+ this.file = file;
+ lockAcquisitionTimeout = DEFAULT_LOCK_ACQUISITION_TIMEOUT_IN_MILLISECONDS;
+ }
+
+ /**
+ * Create a lock associated with the specified File, and set a custom lock
+ * acquisition timeout.
+ *
+ * @param file file to lock
+ * @param lockAcquisitionTimeout maximum number of milliseconds to wait during non-blocking
+ * lock acquisition calls before concluding that there's a
+ * problem with the OS file locking support and throwing an error.
+ */
+ public FSLockWithShared( final File file, final int lockAcquisitionTimeout ) {
+ this.file = file;
+ this.lockAcquisitionTimeout = lockAcquisitionTimeout;
+ }
+
+ /**
+ * Get a shared (read) lock on a file. Does not block, and returns immediately
+ * under normal conditions with the result of the lock acquisition attempt. Will
+ * throw an exception if there's a problem with the OS file locking support.
+ *
+ * @return boolean true if we obtained a lock, false if we failed to obtain one
+ */
+ public boolean sharedLock() {
+ return acquireLockWithTimeout(true);
+ }
+
+ /**
+ * Get an exclusive (read-write) lock on a file. Does not block, and returns immediately
+ * under normal conditions with the result of the lock acquisition attempt. Will
+ * throw an exception if there's a problem with the OS file locking support.
+ *
+ * @return boolean true if we obtained a lock, false if we failed to obtain one
+ */
+ public boolean exclusiveLock() {
+ return acquireLockWithTimeout(false);
+ }
+
+ /**
+ * Attempt to acquire a lock of the specified type on the file in a background thread.
+ * Uses non-blocking lock-acquisition calls that should return immediately, but may
+ * get stuck if there's a problem with the OS file locking support. If the call gets
+ * stuck and the timeout elapses, throws a UserException, since it's not safe to
+ * proceed with a stuck lock acquisition thread (and there's no way to reliably
+ * interrupt it once the underlying system call hangs).
+ *
+ * @param acquireSharedLock if true, request a shared lock rather than an exclusive lock
+ * @return true if a lock was acquired, false if we failed
+ */
+ private boolean acquireLockWithTimeout( final boolean acquireSharedLock ) {
+ // Use daemon threads so that hopelessly stuck lock acquisition threads won't prevent the JVM from exiting
+ final ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
+ public Thread newThread( Runnable r ) {
+ Thread lockAcquisitionThread = new Thread(r);
+ lockAcquisitionThread.setDaemon(true);
+ return lockAcquisitionThread;
+ }
+ });
+ final FutureTask<Boolean> lockAcquisitionTask = new FutureTask<Boolean>(new LockAcquisitionTask(acquireSharedLock));
+ boolean lockAcquired = false;
+
+ try {
+ executor.execute(lockAcquisitionTask);
+
+ // Wait at most lockAcquisitionTimeout milliseconds for the lock acquisition task to finish.
+ lockAcquired = lockAcquisitionTask.get(lockAcquisitionTimeout, TimeUnit.MILLISECONDS);
+ }
+ // Lock acquisition timeout elapsed. Since we're using NON-BLOCKING lock-acquisition calls,
+ // this implies that there's a problem with the OS locking daemon, or locks are not supported.
+ // Since it's not safe to proceed with a potentially stuck lock acquisition thread, we need to
+ // shut down the JVM in order to kill it.
+ catch ( TimeoutException e ) {
+ throw new UserException.FileSystemInabilityToLockException(
+ String.format("Timeout of %d milliseconds was reached while trying to acquire a lock on file %s. " +
+ "Since the GATK uses non-blocking lock acquisition calls that are not supposed to wait, " +
+ "this implies a problem with the file locking support in your operating system.",
+ lockAcquisitionTimeout, file.getAbsolutePath()));
+ }
+ // Lock acquisition thread threw an exception. Need to unpack it via e.getCause()
+ catch ( ExecutionException e ) {
+ logger.warn(String.format("WARNING: Unable to lock file %s because exception %s occurred with error message %s",
+ file.getAbsolutePath(),
+ e.getCause() != null ? e.getCause().getClass().getSimpleName() : "unknown",
+ e.getCause() != null ? e.getCause().getMessage() : "none"));
+ lockAcquired = false;
+ }
+ // Interrupted while waiting for the lock acquisition thread -- not likely to happen
+ catch ( InterruptedException e ) {
+ logger.warn(String.format("WARNING: interrupted while attempting to acquire a lock for file %s", file.getAbsolutePath()));
+ lockAcquired = false;
+ }
+ catch ( Exception e ) {
+ logger.warn(String.format("WARNING: error while attempting to acquire a lock for file %s. Error message: %s",
+ file.getAbsolutePath(), e.getMessage()));
+ lockAcquired = false;
+ }
+
+ shutdownLockAcquisitionTask(executor);
+
+ // Upon failure to acquire a lock, we always call unlock() to close the FileChannel if it was opened
+ // and to deal with very hypothetical edge cases where a lock might actually have been acquired despite the
+ // lock acquisition thread returning false.
+ if ( ! lockAcquired ) {
+ unlock();
+ }
+
+ return lockAcquired;
+ }
+
+ /**
+ * Ensures that the lock acquisition task running in the provided executor has cleanly terminated.
+ * Throws a UserException if unable to shut it down within the period defined by the THREAD_TERMINATION_TIMEOUT.
+ *
+ * @param executor ExecutorService executing the lock-acquisition thread
+ */
+ private void shutdownLockAcquisitionTask( final ExecutorService executor ) {
+ boolean shutdownAttemptSucceeded;
+
+ try {
+ executor.shutdownNow();
+ shutdownAttemptSucceeded = executor.awaitTermination(THREAD_TERMINATION_TIMEOUT_IN_MILLISECONDS, TimeUnit.MILLISECONDS);
+ }
+ catch ( InterruptedException e ) {
+ shutdownAttemptSucceeded = false;
+ }
+
+ if ( ! shutdownAttemptSucceeded ) {
+ throw new UserException(String.format("Failed to terminate lock acquisition thread while trying to lock file %s. " +
+ "Exiting because it's not safe to proceed with this run of the GATK.",
+ file.getAbsolutePath()));
+ }
+ }
+
+ /**
+ * Background task that attempts to acquire a lock of the specified type, and returns a boolean
+ * indicating success/failure. Uses a non-blocking tryLock() call that should return immediately
+ * (but may get stuck if there's a problem with the OS locking daemon).
+ */
+ private class LockAcquisitionTask implements Callable<Boolean> {
+ private final boolean acquireSharedLock;
+
+ public LockAcquisitionTask( final boolean acquireSharedLock ) {
+ this.acquireSharedLock = acquireSharedLock;
+ }
+
+ public Boolean call() {
+ // Get a read-only or read-write file channel, depending on the type of lock
+ try {
+ channel = new RandomAccessFile(file, acquireSharedLock ? "r" : "rw").getChannel();
+ }
+ catch ( IOException e ) {
+ logger.warn(String.format("WARNING: Unable to lock file %s because we could not open a file channel", file.getAbsolutePath()));
+ return false;
+ }
+
+ boolean lockAcquired = false;
+
+ try {
+ // Non-blocking lock-acquisition call, should return right away. If it doesn't return immediately
+ // due to problems with the OS locking daemon, it will potentially be timed-out and interrupted.
+ lock = channel.tryLock(0, Long.MAX_VALUE, acquireSharedLock);
+ lockAcquired = lock != null;
+ }
+ catch ( AsynchronousCloseException e ) {
+ logger.warn(String.format("WARNING: Unable to lock file %s because the file channel was closed by another thread", file.getAbsolutePath()));
+ lockAcquired = false;
+ }
+ catch ( ClosedChannelException e ) {
+ logger.warn(String.format("WARNING: Unable to lock file %s because the file channel is closed.", file.getAbsolutePath()));
+ lockAcquired = false;
+ }
+ catch ( OverlappingFileLockException e ) {
+ logger.warn(String.format("WARNING: Unable to lock file %s because you already have a lock on this file.", file.getAbsolutePath()));
+ lockAcquired = false;
+ }
+ catch ( FileLockInterruptionException e ) {
+ logger.warn(String.format("WARNING: Interrupted while attempting to lock file %s", file.getAbsolutePath()));
+ lockAcquired = false;
+ }
+ catch ( IOException e ) {
+ logger.warn(String.format("WARNING: Unable to lock file %s because an IOException occurred with message: %s.", file.getAbsolutePath(), e.getMessage()));
+ lockAcquired = false;
+ }
+
+ return lockAcquired;
+ }
+ }
+
+ /**
+ * Unlock the file
+ *
+ * note: this allows unlocking a file that failed to lock (no required user checks on null locks).
+ */
+ public void unlock() {
+ releaseLock();
+ closeChannel();
+ }
+
+ private void releaseLock() {
+ try {
+ if ( lock != null )
+ lock.release();
+ }
+ catch ( ClosedChannelException e ) {
+ // if the channel was already closed we don't have to worry
+ }
+ catch ( IOException e ) {
+ throw new UserException(String.format("An error occurred while releasing the lock for file %s", file.getAbsolutePath()), e);
+ }
+ }
+
+ private void closeChannel() {
+ try {
+ if ( channel != null )
+ channel.close();
+ }
+ catch ( IOException e ) {
+ throw new UserException(String.format("An error occurred while closing channel for file %s", file.getAbsolutePath()), e);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fragments/FragmentCollection.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fragments/FragmentCollection.java
new file mode 100644
index 0000000..67d55ff
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fragments/FragmentCollection.java
@@ -0,0 +1,67 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.fragments;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Useful helper class to represent the results of the reads -> fragment calculation.
+ *
+ * Contains singleton -- objects whose underlying reads do not overlap their mate pair
+ * Contains overlappingPairs -- objects whose underlying reads do overlap their mate pair
+ *
+ * User: ebanks, depristo
+ * Date: Jan 10, 2011
+ */
+public class FragmentCollection<T> {
+ Collection<T> singletons;
+ Collection<List<T>> overlappingPairs;
+
+ public FragmentCollection(final Collection<T> singletons, final Collection<List<T>> overlappingPairs) {
+ this.singletons = singletons == null ? Collections.<T>emptyList() : singletons;
+ this.overlappingPairs = overlappingPairs == null ? Collections.<List<T>>emptyList() : overlappingPairs;
+ }
+
+ /**
+ * Gets the T elements not containing overlapping elements, in no particular order
+ *
+ * @return
+ */
+ public Collection<T> getSingletonReads() {
+ return singletons;
+ }
+
+ /**
+ * Gets the T elements containing overlapping elements, in no particular order
+ *
+ * @return
+ */
+ public Collection<List<T>> getOverlappingPairs() {
+ return overlappingPairs;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fragments/FragmentUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fragments/FragmentUtils.java
new file mode 100644
index 0000000..689fdf6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/fragments/FragmentUtils.java
@@ -0,0 +1,377 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.fragments;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.util.QualityUtil;
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.clipping.ReadClipper;
+import org.broadinstitute.gatk.utils.recalibration.EventType;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+import java.util.*;
+
+/**
+ * An easy to access fragment-based pileup, which contains two separate pileups. The first
+ * is a regular collection of PileupElements containing all of the reads in the original RBP
+ * that uniquely info about a fragment. The second are TwoReadPileupElements that, as the
+ * name suggests, contain two reads that are sequenced from the same underlying fragment.
+ *
+ * Based on the original code by E. Banks
+ *
+ * Oct 21: note that the order of the oneReadPileup and twoReadPileups are not
+ * defined. The algorithms that produce these lists are in fact producing
+ * lists of Pileup elements *NOT* sorted by alignment start position of the underlying
+ * reads.
+ *
+ * User: depristo
+ * Date: 3/26/11
+ * Time: 10:09 PM
+ */
+public final class FragmentUtils {
+
+ public final static double DEFAULT_PCR_ERROR_RATE = 1e-4;
+ public final static int DEFAULT_PCR_ERROR_QUAL = QualityUtil.getPhredScoreFromErrorProbability(DEFAULT_PCR_ERROR_RATE);
+ public final static int HALF_OF_DEFAULT_PCR_ERROR_QUAL = DEFAULT_PCR_ERROR_QUAL / 2;
+
+ protected final static byte MIN_QUAL_BAD_OVERLAP = 16;
+ private FragmentUtils() {} // private constructor
+
+ /**
+ * A getter function that takes an Object of type T and returns its associated SAMRecord.
+ *
+ * Allows us to write a generic T -> Fragment algorithm that works with any object containing
+ * a read.
+ *
+ * @param <T> The type of the object that contains a GATKSAMRecord
+ */
+ public interface ReadGetter<T> {
+ /**
+ * Get the GATKSAMRecord associated with object
+ *
+ * @param object the thing that contains the read
+ * @return a non-null GATKSAMRecord read
+ */
+ public GATKSAMRecord get(T object);
+ }
+
+ /**
+ * Identify getter for SAMRecords themselves
+ */
+ private final static ReadGetter<GATKSAMRecord> SamRecordGetter = new ReadGetter<GATKSAMRecord>() {
+ @Override public GATKSAMRecord get(final GATKSAMRecord object) { return object; }
+ };
+
+ /**
+ * Gets the SAMRecord in a PileupElement
+ */
+ private final static ReadGetter<PileupElement> PileupElementGetter = new ReadGetter<PileupElement>() {
+ @Override public GATKSAMRecord get(final PileupElement object) { return object.getRead(); }
+ };
+
+
+ /**
+ * Generic algorithm that takes an iterable over T objects, a getter routine to extract the reads in T,
+ * and returns a FragmentCollection that contains the T objects whose underlying reads either overlap (or
+ * not) with their mate pairs.
+ *
+ * @param readContainingObjects An iterator of objects that contain GATKSAMRecords
+ * @param nElements the number of elements to be provided by the iterator, which is usually known upfront and
+ * greatly improves the efficiency of the fragment calculation
+ * @param getter a helper function that takes an object of type T and returns is associated GATKSAMRecord
+ * @param <T>
+ * @return a fragment collection
+ */
+ @Requires({
+ "readContainingObjects != null",
+ "nElements >= 0",
+ "getter != null"
+ })
+ @Ensures("result != null")
+ private static <T> FragmentCollection<T> create(final Iterable<T> readContainingObjects, final int nElements, final ReadGetter<T> getter) {
+ Collection<T> singletons = null;
+ Collection<List<T>> overlapping = null;
+ Map<String, T> nameMap = null;
+
+ int lastStart = -1;
+
+ // build an initial map, grabbing all of the multi-read fragments
+ for ( final T p : readContainingObjects ) {
+ final SAMRecord read = getter.get(p);
+
+ if ( read.getAlignmentStart() < lastStart ) {
+ throw new IllegalArgumentException(String.format(
+ "FragmentUtils.create assumes that the incoming objects are ordered by " +
+ "SAMRecord alignment start, but saw a read %s with alignment start " +
+ "%d before the previous start %d", read.getSAMString(), read.getAlignmentStart(), lastStart));
+ }
+ lastStart = read.getAlignmentStart();
+
+ final int mateStart = read.getMateAlignmentStart();
+ if ( mateStart == 0 || mateStart > read.getAlignmentEnd() ) {
+ // if we know that this read won't overlap its mate, or doesn't have one, jump out early
+ if ( singletons == null ) singletons = new ArrayList<T>(nElements); // lazy init
+ singletons.add(p);
+ } else {
+ // the read might overlap it's mate, or is the rightmost read of a pair
+ final String readName = read.getReadName();
+ final T pe1 = nameMap == null ? null : nameMap.get(readName);
+ if ( pe1 != null ) {
+ // assumes we have at most 2 reads per fragment
+ if ( overlapping == null ) overlapping = new ArrayList<List<T>>(); // lazy init
+ overlapping.add(Arrays.asList(pe1, p));
+ nameMap.remove(readName);
+ } else {
+ if ( nameMap == null ) nameMap = new HashMap<String, T>(nElements); // lazy init
+ nameMap.put(readName, p);
+ }
+ }
+ }
+
+ // add all of the reads that are potentially overlapping but whose mate never showed
+ // up to the oneReadPile
+ if ( nameMap != null && ! nameMap.isEmpty() ) {
+ if ( singletons == null )
+ singletons = nameMap.values();
+ else
+ singletons.addAll(nameMap.values());
+ }
+
+ return new FragmentCollection<T>(singletons, overlapping);
+ }
+
+ /**
+ * Create a FragmentCollection containing PileupElements from the ReadBackedPileup rbp
+ * @param rbp a non-null read-backed pileup. The elements in this ReadBackedPileup must be ordered
+ * @return a non-null FragmentCollection
+ */
+ @Ensures("result != null")
+ public static FragmentCollection<PileupElement> create(final ReadBackedPileup rbp) {
+ if ( rbp == null ) throw new IllegalArgumentException("Pileup cannot be null");
+ return create(rbp, rbp.getNumberOfElements(), PileupElementGetter);
+ }
+
+ /**
+ * Create a FragmentCollection containing GATKSAMRecords from a list of reads
+ *
+ * @param reads a non-null list of reads, ordered by their start location
+ * @return a non-null FragmentCollection
+ */
+ @Ensures("result != null")
+ public static FragmentCollection<GATKSAMRecord> create(final List<GATKSAMRecord> reads) {
+ if ( reads == null ) throw new IllegalArgumentException("Pileup cannot be null");
+ return create(reads, reads.size(), SamRecordGetter);
+ }
+
+ public static void adjustQualsOfOverlappingPairedFragments( final List<GATKSAMRecord> overlappingPair ) {
+ if( overlappingPair.size() != 2 ) { throw new ReviewedGATKException("Found overlapping pair with " + overlappingPair.size() + " reads, but expecting exactly 2."); }
+
+ final GATKSAMRecord firstRead = overlappingPair.get(0);
+ final GATKSAMRecord secondRead = overlappingPair.get(1);
+
+ if ( secondRead.getSoftStart() < firstRead.getSoftStart() ) {
+ adjustQualsOfOverlappingPairedFragments(secondRead, firstRead);
+ } else {
+ adjustQualsOfOverlappingPairedFragments(firstRead, secondRead);
+ }
+ }
+
+ /**
+ * Fix two overlapping reads from the same fragment by adjusting base qualities, if possible
+ *
+ * firstRead and secondRead must be part of the same fragment (though this isn't checked). Looks
+ * at the bases and alignment, and tries its best to create adjusted base qualities so that the observations
+ * are not treated independently.
+ *
+ * Assumes that firstRead starts before secondRead (according to their soft clipped starts)
+ *
+ * @param clippedFirstRead the left most read
+ * @param clippedSecondRead the right most read
+ *
+ * @return a strandless merged read of first and second, or null if the algorithm cannot create a meaningful one
+ */
+ public static void adjustQualsOfOverlappingPairedFragments(final GATKSAMRecord clippedFirstRead, final GATKSAMRecord clippedSecondRead) {
+ if ( clippedFirstRead == null ) throw new IllegalArgumentException("clippedFirstRead cannot be null");
+ if ( clippedSecondRead == null ) throw new IllegalArgumentException("clippedSecondRead cannot be null");
+ if ( ! clippedFirstRead.getReadName().equals(clippedSecondRead.getReadName()) ) throw new IllegalArgumentException("attempting to merge two reads with different names " + clippedFirstRead + " and " + clippedSecondRead);
+
+ // don't adjust fragments that do not overlap
+ if ( clippedFirstRead.getAlignmentEnd() < clippedSecondRead.getAlignmentStart() || !clippedFirstRead.getReferenceIndex().equals(clippedSecondRead.getReferenceIndex()) )
+ return;
+
+ final Pair<Integer, Boolean> pair = ReadUtils.getReadCoordinateForReferenceCoordinate(clippedFirstRead, clippedSecondRead.getAlignmentStart());
+ final int firstReadStop = ( pair.getSecond() ? pair.getFirst() + 1 : pair.getFirst() );
+ final int numOverlappingBases = Math.min(clippedFirstRead.getReadLength() - firstReadStop, clippedSecondRead.getReadLength());
+
+ final byte[] firstReadBases = clippedFirstRead.getReadBases();
+ final byte[] firstReadQuals = clippedFirstRead.getBaseQualities();
+ final byte[] secondReadBases = clippedSecondRead.getReadBases();
+ final byte[] secondReadQuals = clippedSecondRead.getBaseQualities();
+
+ for ( int i = 0; i < numOverlappingBases; i++ ) {
+ final int firstReadIndex = firstReadStop + i;
+ final byte firstReadBase = firstReadBases[firstReadIndex];
+ final byte secondReadBase = secondReadBases[i];
+
+ if ( firstReadBase == secondReadBase ) {
+ firstReadQuals[firstReadIndex] = (byte) Math.min(firstReadQuals[firstReadIndex], HALF_OF_DEFAULT_PCR_ERROR_QUAL);
+ secondReadQuals[i] = (byte) Math.min(secondReadQuals[i], HALF_OF_DEFAULT_PCR_ERROR_QUAL);
+ } else {
+ // TODO -- use the proper statistical treatment of the quals from DiploidSNPGenotypeLikelihoods.java
+ firstReadQuals[firstReadIndex] = 0;
+ secondReadQuals[i] = 0;
+ }
+ }
+
+ clippedFirstRead.setBaseQualities(firstReadQuals);
+ clippedSecondRead.setBaseQualities(secondReadQuals);
+ }
+
+ public static List<GATKSAMRecord> mergeOverlappingPairedFragments( final List<GATKSAMRecord> overlappingPair ) {
+ if( overlappingPair.size() != 2 ) { throw new ReviewedGATKException("Found overlapping pair with " + overlappingPair.size() + " reads, but expecting exactly 2."); }
+
+ final GATKSAMRecord firstRead = overlappingPair.get(0);
+ final GATKSAMRecord secondRead = overlappingPair.get(1);
+
+ final GATKSAMRecord merged;
+ if( !(secondRead.getSoftStart() <= firstRead.getSoftEnd() && secondRead.getSoftStart() >= firstRead.getSoftStart() && secondRead.getSoftEnd() >= firstRead.getSoftEnd()) ) {
+ merged = mergeOverlappingPairedFragments(secondRead, firstRead);
+ } else {
+ merged = mergeOverlappingPairedFragments(firstRead, secondRead);
+ }
+
+ return merged == null ? overlappingPair : Collections.singletonList(merged);
+ }
+
+ /**
+ * Merge two overlapping reads from the same fragment into a single super read, if possible
+ *
+ * firstRead and secondRead must be part of the same fragment (though this isn't checked). Looks
+ * at the bases and alignment, and tries its best to create a meaningful synthetic single super read
+ * that represents the entire sequenced fragment.
+ *
+ * Assumes that firstRead starts before secondRead (according to their soft clipped starts)
+ *
+ * @param unclippedFirstRead the left most read
+ * @param unclippedSecondRead the right most read
+ *
+ * @return a strandless merged read of first and second, or null if the algorithm cannot create a meaningful one
+ */
+ public static GATKSAMRecord mergeOverlappingPairedFragments(final GATKSAMRecord unclippedFirstRead, final GATKSAMRecord unclippedSecondRead) {
+ if ( unclippedFirstRead == null ) throw new IllegalArgumentException("unclippedFirstRead cannot be null");
+ if ( unclippedSecondRead == null ) throw new IllegalArgumentException("unclippedSecondRead cannot be null");
+ if ( ! unclippedFirstRead.getReadName().equals(unclippedSecondRead.getReadName()) ) throw new IllegalArgumentException("attempting to merge two reads with different names " + unclippedFirstRead + " and " + unclippedSecondRead);
+
+ if( unclippedFirstRead.getCigarString().contains("I") || unclippedFirstRead.getCigarString().contains("D") || unclippedSecondRead.getCigarString().contains("I") || unclippedSecondRead.getCigarString().contains("D") ) {
+ return null; // fragments contain indels so don't merge them
+ }
+
+ final GATKSAMRecord firstRead = ReadClipper.hardClipAdaptorSequence(ReadClipper.revertSoftClippedBases(unclippedFirstRead));
+ final GATKSAMRecord secondRead = ReadClipper.hardClipAdaptorSequence(ReadClipper.revertSoftClippedBases(unclippedSecondRead));
+
+ if( !(secondRead.getSoftStart() <= firstRead.getSoftEnd() && secondRead.getSoftStart() >= firstRead.getSoftStart() && secondRead.getSoftEnd() >= firstRead.getSoftEnd()) ) {
+ return null; // can't merge them, yet: AAAAAAAAAAA-BBBBBBBBBBB-AAAAAAAAAAAAAA, B is contained entirely inside A
+ }
+
+ final Pair<Integer, Boolean> pair = ReadUtils.getReadCoordinateForReferenceCoordinate(firstRead, secondRead.getAlignmentStart());
+
+ final int firstReadStop = ( pair.getSecond() ? pair.getFirst() + 1 : pair.getFirst() );
+ final int numBases = firstReadStop + secondRead.getReadLength();
+ final byte[] bases = new byte[numBases];
+ final byte[] quals = new byte[numBases];
+ final byte[] insertionQuals = new byte[numBases];
+ final byte[] deletionQuals = new byte[numBases];
+ final byte[] firstReadBases = firstRead.getReadBases();
+ final byte[] firstReadQuals = firstRead.getBaseQualities();
+ final byte[] secondReadBases = secondRead.getReadBases();
+ final byte[] secondReadQuals = secondRead.getBaseQualities();
+
+ for(int iii = 0; iii < firstReadStop; iii++) {
+ bases[iii] = firstReadBases[iii];
+ quals[iii] = firstReadQuals[iii];
+ }
+ for(int iii = firstReadStop; iii < firstRead.getReadLength(); iii++) {
+ if( firstReadQuals[iii] > MIN_QUAL_BAD_OVERLAP && secondReadQuals[iii-firstReadStop] > MIN_QUAL_BAD_OVERLAP && firstReadBases[iii] != secondReadBases[iii-firstReadStop] ) {
+ return null; // high qual bases don't match exactly, probably indel in only one of the fragments, so don't merge them
+ }
+ if( firstReadQuals[iii] < MIN_QUAL_BAD_OVERLAP && secondReadQuals[iii-firstReadStop] < MIN_QUAL_BAD_OVERLAP ) {
+ return null; // both reads have low qual bases in the overlap region so don't merge them because don't know what is going on
+ }
+ bases[iii] = ( firstReadQuals[iii] > secondReadQuals[iii-firstReadStop] ? firstReadBases[iii] : secondReadBases[iii-firstReadStop] );
+ quals[iii] = ( firstReadQuals[iii] > secondReadQuals[iii-firstReadStop] ? firstReadQuals[iii] : secondReadQuals[iii-firstReadStop] );
+ }
+ for(int iii = firstRead.getReadLength(); iii < numBases; iii++) {
+ bases[iii] = secondReadBases[iii-firstReadStop];
+ quals[iii] = secondReadQuals[iii-firstReadStop];
+ }
+
+ final GATKSAMRecord returnRead = new GATKSAMRecord( firstRead.getHeader() );
+ returnRead.setIsStrandless(true);
+ returnRead.setAlignmentStart( firstRead.getAlignmentStart() );
+ returnRead.setReadBases( bases );
+ returnRead.setBaseQualities( quals );
+ returnRead.setReadGroup( firstRead.getReadGroup() );
+ returnRead.setReferenceName( firstRead.getReferenceName() );
+ returnRead.setReadName( firstRead.getReadName() );
+ final CigarElement c = new CigarElement(bases.length, CigarOperator.M);
+ final ArrayList<CigarElement> cList = new ArrayList<CigarElement>();
+ cList.add(c);
+ returnRead.setCigar( new Cigar( cList ));
+ returnRead.setMappingQuality( firstRead.getMappingQuality() );
+
+ if( firstRead.hasBaseIndelQualities() || secondRead.hasBaseIndelQualities() ) {
+ final byte[] firstReadInsertionQuals = firstRead.getBaseInsertionQualities();
+ final byte[] firstReadDeletionQuals = firstRead.getBaseDeletionQualities();
+ final byte[] secondReadInsertionQuals = secondRead.getBaseInsertionQualities();
+ final byte[] secondReadDeletionQuals = secondRead.getBaseDeletionQualities();
+ for(int iii = 0; iii < firstReadStop; iii++) {
+ insertionQuals[iii] = firstReadInsertionQuals[iii];
+ deletionQuals[iii] = firstReadDeletionQuals[iii];
+ }
+ for(int iii = firstReadStop; iii < firstRead.getReadLength(); iii++) {
+ insertionQuals[iii] = ( firstReadQuals[iii] > secondReadQuals[iii-firstReadStop] ? firstReadInsertionQuals[iii] : secondReadInsertionQuals[iii-firstReadStop] ); // Purposefully checking the highest *base* quality score
+ deletionQuals[iii] = ( firstReadQuals[iii] > secondReadQuals[iii-firstReadStop] ? firstReadDeletionQuals[iii] : secondReadDeletionQuals[iii-firstReadStop] ); // Purposefully checking the highest *base* quality score
+ }
+ for(int iii = firstRead.getReadLength(); iii < numBases; iii++) {
+ insertionQuals[iii] = secondReadInsertionQuals[iii-firstReadStop];
+ deletionQuals[iii] = secondReadDeletionQuals[iii-firstReadStop];
+ }
+ returnRead.setBaseQualities( insertionQuals, EventType.BASE_INSERTION );
+ returnRead.setBaseQualities( deletionQuals, EventType.BASE_DELETION );
+ }
+
+ return returnRead;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/DiploidGenotype.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/DiploidGenotype.java
new file mode 100644
index 0000000..f836f44
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/DiploidGenotype.java
@@ -0,0 +1,125 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.genotyper;
+
+import org.broadinstitute.gatk.utils.BaseUtils;
+
+public enum DiploidGenotype {
+ AA ('A', 'A'),
+ AC ('A', 'C'),
+ CC ('C', 'C'),
+ AG ('A', 'G'),
+ CG ('C', 'G'),
+ GG ('G', 'G'),
+ AT ('A', 'T'),
+ CT ('C', 'T'),
+ GT ('G', 'T'),
+ TT ('T', 'T');
+
+ public byte base1, base2;
+
+ @Deprecated
+ private DiploidGenotype(char base1, char base2) {
+ this((byte)base1, (byte)base2);
+ }
+
+ private DiploidGenotype(byte base1, byte base2) {
+ this.base1 = base1;
+ this.base2 = base2;
+ }
+
+ public boolean isHomRef(byte r) {
+ return isHom() && r == base1;
+ }
+
+ public boolean isHomVar(byte r) {
+ return isHom() && r != base1;
+ }
+
+ public boolean isHetRef(byte r) {
+ if ( base1 == r )
+ return r != base2;
+ else
+ return base2 == r;
+ }
+
+ public boolean isHom() {
+ return ! isHet();
+ }
+
+ public boolean isHet() {
+ return base1 != base2;
+ }
+
+ /**
+ * create a diploid genotype, given a character to make into a hom genotype
+ * @param hom the character to turn into a hom genotype, i.e. if it is A, then returned will be AA
+ * @return the diploid genotype
+ */
+ public static DiploidGenotype createHomGenotype(byte hom) {
+ int index = BaseUtils.simpleBaseToBaseIndex(hom);
+ if ( index == -1 )
+ throw new IllegalArgumentException(hom + " is not a valid base character");
+ return conversionMatrix[index][index];
+ }
+
+ /**
+ * create a diploid genotype, given 2 chars which may not necessarily be ordered correctly
+ * @param base1 base1
+ * @param base2 base2
+ * @return the diploid genotype
+ */
+ public static DiploidGenotype createDiploidGenotype(byte base1, byte base2) {
+ int index1 = BaseUtils.simpleBaseToBaseIndex(base1);
+ if ( index1 == -1 )
+ throw new IllegalArgumentException(base1 + " is not a valid base character");
+ int index2 = BaseUtils.simpleBaseToBaseIndex(base2);
+ if ( index2 == -1 )
+ throw new IllegalArgumentException(base2 + " is not a valid base character");
+ return conversionMatrix[index1][index2];
+ }
+
+ /**
+ * create a diploid genotype, given 2 base indexes which may not necessarily be ordered correctly
+ * @param baseIndex1 base1
+ * @param baseIndex2 base2
+ * @return the diploid genotype
+ */
+ public static DiploidGenotype createDiploidGenotype(int baseIndex1, int baseIndex2) {
+ if ( baseIndex1 == -1 )
+ throw new IllegalArgumentException(baseIndex1 + " does not represent a valid base character");
+ if ( baseIndex2 == -1 )
+ throw new IllegalArgumentException(baseIndex2 + " does not represent a valid base character");
+ return conversionMatrix[baseIndex1][baseIndex2];
+ }
+
+ private static final DiploidGenotype[][] conversionMatrix = {
+ { DiploidGenotype.AA, DiploidGenotype.AC, DiploidGenotype.AG, DiploidGenotype.AT },
+ { DiploidGenotype.AC, DiploidGenotype.CC, DiploidGenotype.CG, DiploidGenotype.CT },
+ { DiploidGenotype.AG, DiploidGenotype.CG, DiploidGenotype.GG, DiploidGenotype.GT },
+ { DiploidGenotype.AT, DiploidGenotype.CT, DiploidGenotype.GT, DiploidGenotype.TT }
+ };
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/MostLikelyAllele.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/MostLikelyAllele.java
new file mode 100644
index 0000000..65c1fd0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/MostLikelyAllele.java
@@ -0,0 +1,134 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.genotyper;
+
+import org.broadinstitute.gatk.utils.MathUtils;
+import htsjdk.variant.variantcontext.Allele;
+
+/**
+ * Stores the most likely and second most likely alleles, along with a threshold
+ * for assuming computing that a read is informative.
+ *
+ * If the difference between the most-likely allele and the next-most-likely allele is < INFORMATIVE_LIKELIHOOD_THRESHOLD
+ * then the most likely allele is set to "no call", and isInformative will return false. This constant can be
+ * overridden simply by using one of the version of these calls that accepts informative threshold as an argument.
+ *
+ * For convenience, there are functions called getAlleleIfInformative that return either the most likely allele, or
+ * NO_CALL if two or more alleles have likelihoods within INFORMATIVE_LIKELIHOOD_THRESHOLD of one another.
+ *
+ * By default empty allele maps will return NO_CALL, and allele maps with a single entry will return the
+ * corresponding key
+ *
+ * User: depristo
+ * Date: 3/24/13
+ * Time: 1:39 PM
+ */
+public final class MostLikelyAllele {
+ public static final double INFORMATIVE_LIKELIHOOD_THRESHOLD = 0.2;
+
+ final Allele mostLikely;
+ final Allele secondLikely;
+ final double log10LikelihoodOfMostLikely;
+ final double log10LikelihoodOfSecondBest;
+
+ /**
+ * Create a new MostLikelyAllele
+ *
+ * If there's a meaningful most likely allele, allele should be a real allele. If none can be determined,
+ * mostLikely should be a NO_CALL allele.
+ *
+ * @param mostLikely the most likely allele
+ * @param secondMostLikely the most likely allele after mostLikely
+ * @param log10LikelihoodOfMostLikely the log10 likelihood of the most likely allele
+ * @param log10LikelihoodOfSecondBest the log10 likelihood of the next most likely allele (should be NEGATIVE_INFINITY if none is available)
+ */
+ public MostLikelyAllele(final Allele mostLikely, final Allele secondMostLikely, double log10LikelihoodOfMostLikely, double log10LikelihoodOfSecondBest) {
+ if ( mostLikely == null ) throw new IllegalArgumentException("mostLikely allele cannot be null");
+ if ( log10LikelihoodOfMostLikely != Double.NEGATIVE_INFINITY && ! MathUtils.goodLog10Probability(log10LikelihoodOfMostLikely) )
+ throw new IllegalArgumentException("log10LikelihoodOfMostLikely must be either -Infinity or a good log10 prob but got " + log10LikelihoodOfMostLikely);
+ if ( log10LikelihoodOfSecondBest != Double.NEGATIVE_INFINITY && ! MathUtils.goodLog10Probability(log10LikelihoodOfSecondBest) )
+ throw new IllegalArgumentException("log10LikelihoodOfSecondBest must be either -Infinity or a good log10 prob but got " + log10LikelihoodOfSecondBest);
+ if ( log10LikelihoodOfMostLikely < log10LikelihoodOfSecondBest )
+ throw new IllegalArgumentException("log10LikelihoodOfMostLikely must be <= log10LikelihoodOfSecondBest but got " + log10LikelihoodOfMostLikely + " vs 2nd " + log10LikelihoodOfSecondBest);
+
+ this.mostLikely = mostLikely;
+ this.secondLikely = secondMostLikely;
+ this.log10LikelihoodOfMostLikely = log10LikelihoodOfMostLikely;
+ this.log10LikelihoodOfSecondBest = log10LikelihoodOfSecondBest;
+ }
+
+ public Allele getMostLikelyAllele() {
+ return mostLikely;
+ }
+
+ public Allele getSecondMostLikelyAllele() {
+ return secondLikely;
+ }
+
+ public double getLog10LikelihoodOfMostLikely() {
+ return log10LikelihoodOfMostLikely;
+ }
+
+ public double getLog10LikelihoodOfSecondBest() {
+ return log10LikelihoodOfSecondBest;
+ }
+
+ /**
+ * @see #isInformative(double) with threshold of INFORMATIVE_LIKELIHOOD_THRESHOLD
+ */
+ public boolean isInformative() {
+ return isInformative(INFORMATIVE_LIKELIHOOD_THRESHOLD);
+ }
+
+ /**
+ * Was this allele selected from an object that was specifically informative about the allele?
+ *
+ * The calculation that implements this is whether the likelihood of the most likely allele is larger
+ * than the second most likely by at least the log10ThresholdForInformative
+ *
+ * @return true if so, false if not
+ */
+ public boolean isInformative(final double log10ThresholdForInformative) {
+ return getLog10LikelihoodOfMostLikely() - getLog10LikelihoodOfSecondBest() > log10ThresholdForInformative;
+ }
+
+ /**
+ * @see #getAlleleIfInformative(double) with threshold of INFORMATIVE_LIKELIHOOD_THRESHOLD
+ */
+ public Allele getAlleleIfInformative() {
+ return getAlleleIfInformative(INFORMATIVE_LIKELIHOOD_THRESHOLD);
+ }
+
+ /**
+ * Get the most likely allele if isInformative(log10ThresholdForInformative) is true, or NO_CALL otherwise
+ *
+ * @param log10ThresholdForInformative a log10 threshold to determine if the most likely allele was informative
+ * @return a non-null allele
+ */
+ public Allele getAlleleIfInformative(final double log10ThresholdForInformative) {
+ return isInformative(log10ThresholdForInformative) ? getMostLikelyAllele() : Allele.NO_CALL;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/PerReadAlleleLikelihoodMap.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/PerReadAlleleLikelihoodMap.java
new file mode 100644
index 0000000..1dd8a8a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/PerReadAlleleLikelihoodMap.java
@@ -0,0 +1,413 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.genotyper;
+
+
+import com.google.java.contract.Ensures;
+import org.broadinstitute.gatk.engine.downsampling.AlleleBiasedDownsamplingUtils;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.haplotype.Haplotype;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import org.broadinstitute.gatk.utils.sam.AlignmentUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import htsjdk.variant.variantcontext.Allele;
+
+import java.util.*;
+
+/**
+ * Wrapper class that holds a set of maps of the form (Read -> Map(Allele->Double))
+ * For each read, this holds underlying alleles represented by an aligned read, and corresponding relative likelihood.
+ */
+public class PerReadAlleleLikelihoodMap {
+ /** A set of all of the allele, so we can efficiently determine if an allele is already present */
+ private final Map<Allele,Integer> allelesSet = new HashMap<>();
+ /** A list of the unique allele, as an ArrayList so we can call get(i) efficiently */
+ protected final List<Allele> alleles = new ArrayList<>();
+
+
+
+ protected final Map<GATKSAMRecord, Map<Allele, Double>> likelihoodReadMap = new LinkedHashMap<>();
+
+ public PerReadAlleleLikelihoodMap() { }
+
+ /**
+ * Add a new entry into the Read -> ( Allele -> Likelihood ) map of maps.
+ * @param read - the GATKSAMRecord that was evaluated
+ * @param a - the Allele against which the GATKSAMRecord was evaluated
+ * @param likelihood - the likelihood score resulting from the evaluation of "read" against "a"
+ */
+ public void add(final GATKSAMRecord read, final Allele a, final Double likelihood) {
+ if ( read == null ) throw new IllegalArgumentException("Cannot add a null read to the allele likelihood map");
+ if ( a == null ) throw new IllegalArgumentException("Cannot add a null allele to the allele likelihood map");
+ if ( likelihood == null ) throw new IllegalArgumentException("Likelihood cannot be null");
+ if ( likelihood > 0.0 ) throw new IllegalArgumentException("Likelihood must be negative (L = log(p))");
+
+ if (!allelesSet.containsKey(a)) {
+ allelesSet.put(a,alleles.size());
+ alleles.add(a);
+ }
+ Map<Allele,Double> likelihoodMap = likelihoodReadMap.get(read);
+ if (likelihoodMap == null){
+ // LinkedHashMap will ensure iterating through alleles will be in consistent order
+ likelihoodMap = new LinkedHashMap<>();
+ likelihoodReadMap.put(read,likelihoodMap);
+ }
+
+ likelihoodMap.put(a,likelihood);
+
+
+ }
+
+ public ReadBackedPileup createPerAlleleDownsampledBasePileup(final ReadBackedPileup pileup, final double downsamplingFraction) {
+ return AlleleBiasedDownsamplingUtils.createAlleleBiasedBasePileup(pileup, downsamplingFraction);
+ }
+
+ /**
+ * For each allele "a" , identify those reads whose most likely allele is "a", and remove a "downsamplingFraction" proportion
+ * of those reads from the "likelihoodReadMap". This is used for e.g. sample contamination
+ * @param downsamplingFraction - the fraction of supporting reads to remove from each allele. If <=0 all reads kept, if >=1 all reads tossed.
+ */
+ public void performPerAlleleDownsampling(final double downsamplingFraction) {
+ // special case removal of all or no reads
+ if ( downsamplingFraction <= 0.0 )
+ return;
+ if ( downsamplingFraction >= 1.0 ) {
+ likelihoodReadMap.clear();
+ return;
+ }
+
+ // start by stratifying the reads by the alleles they represent at this position
+ final Map<Allele, List<GATKSAMRecord>> alleleReadMap = getAlleleStratifiedReadMap();
+
+ // compute the reads to remove and actually remove them
+ final List<GATKSAMRecord> readsToRemove = AlleleBiasedDownsamplingUtils.selectAlleleBiasedReads(alleleReadMap, downsamplingFraction);
+ for ( final GATKSAMRecord read : readsToRemove )
+ likelihoodReadMap.remove(read);
+ }
+
+ /**
+ * Convert the @likelihoodReadMap to a map of alleles to reads, where each read is mapped uniquely to the allele
+ * for which it has the greatest associated likelihood
+ * @return a map from each allele to a list of reads that 'support' the allele
+ */
+ protected Map<Allele,List<GATKSAMRecord>> getAlleleStratifiedReadMap() {
+ final Map<Allele, List<GATKSAMRecord>> alleleReadMap = new HashMap<>(alleles.size());
+ for ( final Allele allele : alleles )
+ alleleReadMap.put(allele, new ArrayList<GATKSAMRecord>());
+
+ for ( final Map.Entry<GATKSAMRecord, Map<Allele, Double>> entry : likelihoodReadMap.entrySet() ) {
+ final MostLikelyAllele bestAllele = getMostLikelyAllele(entry.getValue());
+ if ( bestAllele.isInformative() )
+ alleleReadMap.get(bestAllele.getMostLikelyAllele()).add(entry.getKey());
+ }
+
+ return alleleReadMap;
+ }
+
+ @Ensures("result >=0")
+ public int size() {
+ return likelihoodReadMap.size();
+ }
+
+ /**
+ * Helper function to add the read underneath a pileup element to the map
+ * @param p Pileup element
+ * @param a Corresponding allele
+ * @param likelihood Allele likelihood
+ */
+ public void add(PileupElement p, Allele a, Double likelihood) {
+ if (p==null)
+ throw new IllegalArgumentException("Pileup element cannot be null");
+ if ( p.getRead()==null )
+ throw new IllegalArgumentException("Read underlying pileup element cannot be null");
+ if ( a == null )
+ throw new IllegalArgumentException("Allele for add() cannot be null");
+
+ add(p.getRead(), a, likelihood);
+ }
+
+ /**
+ * Does the current map contain the key associated with a particular SAM record in pileup?
+ * @param p Pileup element
+ * @return true if the map contains pileup element, else false
+ */
+ public boolean containsPileupElement(final PileupElement p) {
+ return likelihoodReadMap.containsKey(p.getRead());
+ }
+
+ public boolean isEmpty() {
+ return likelihoodReadMap.isEmpty();
+ }
+
+ public Map<GATKSAMRecord,Map<Allele,Double>> getLikelihoodReadMap() {
+ return likelihoodReadMap;
+ }
+
+ public void clear() {
+ allelesSet.clear();
+ alleles.clear();
+ likelihoodReadMap.clear();
+ }
+
+ public Set<GATKSAMRecord> getStoredElements() {
+ return likelihoodReadMap.keySet();
+ }
+
+// public Collection<Map<Allele,Double>> getLikelihoodMapValues() {
+// return likelihoodReadMap.values();
+// }
+
+ public int getNumberOfStoredElements() {
+ return likelihoodReadMap.size();
+ }
+
+ public Map<Allele,Double> getLikelihoodsAssociatedWithPileupElement(final PileupElement p) {
+ if (!likelihoodReadMap.containsKey(p.getRead()))
+ return null;
+
+ return likelihoodReadMap.get(p.getRead());
+ }
+
+
+ /**
+ * Get the log10 likelihood associated with an individual read/allele
+ *
+ * @param read the read whose likelihood we want
+ * @param allele the allele whose likelihood we want
+ * @return the log10 likelihood that this read matches this allele
+ */
+ public double getLikelihoodAssociatedWithReadAndAllele(final GATKSAMRecord read, final Allele allele){
+ if (!allelesSet.containsKey(allele) || !likelihoodReadMap.containsKey(read))
+ return 0.0;
+
+ return likelihoodReadMap.get(read).get(allele);
+ }
+
+ /**
+ * Get the most likely alleles estimated across all reads in this object
+ *
+ * Takes the most likely two alleles according to their diploid genotype likelihoods. That is, for
+ * each allele i and j we compute p(D | i,j) where D is the read likelihoods. We track the maximum
+ * i,j likelihood and return an object that contains the alleles i and j as well as the max likelihood.
+ *
+ * Note that the second most likely diploid genotype is not tracked so the resulting MostLikelyAllele
+ * doesn't have a meaningful get best likelihood.
+ *
+ * @return a MostLikelyAllele object, or null if this map is empty
+ */
+ public MostLikelyAllele getMostLikelyDiploidAlleles() {
+ if ( isEmpty() ) return null;
+
+ int hap1 = 0;
+ int hap2 = 0;
+ double maxElement = Double.NEGATIVE_INFINITY;
+ for( int iii = 0; iii < alleles.size(); iii++ ) {
+ final Allele iii_allele = alleles.get(iii);
+ for( int jjj = 0; jjj <= iii; jjj++ ) {
+ final Allele jjj_allele = alleles.get(jjj);
+
+ double haplotypeLikelihood = 0.0;
+ for( final Map.Entry<GATKSAMRecord, Map<Allele,Double>> entry : likelihoodReadMap.entrySet() ) {
+ // Compute log10(10^x1/2 + 10^x2/2) = log10(10^x1+10^x2)-log10(2)
+ final double likelihood_iii = entry.getValue().get(iii_allele);
+ final double likelihood_jjj = entry.getValue().get(jjj_allele);
+ haplotypeLikelihood += MathUtils.approximateLog10SumLog10(likelihood_iii, likelihood_jjj) + MathUtils.LOG_ONE_HALF;
+
+ // fast exit. If this diploid pair is already worse than the max, just stop and look at the next pair
+ if ( haplotypeLikelihood < maxElement ) break;
+ }
+
+ // keep track of the max element and associated indices
+ if ( haplotypeLikelihood > maxElement ) {
+ hap1 = iii;
+ hap2 = jjj;
+ maxElement = haplotypeLikelihood;
+ }
+ }
+ }
+
+ if ( maxElement == Double.NEGATIVE_INFINITY )
+ throw new IllegalStateException("max likelihood is " + maxElement + " indicating something has gone wrong");
+
+ return new MostLikelyAllele(alleles.get(hap1), alleles.get(hap2), maxElement, maxElement);
+ }
+
+ /**
+ * Given a map from alleles to likelihoods, find the allele with the largest likelihood.
+ *
+ * @param alleleMap - a map from alleles to likelihoods
+ * @return - a MostLikelyAllele object
+ */
+ @Ensures("result != null")
+ public static MostLikelyAllele getMostLikelyAllele( final Map<Allele,Double> alleleMap ) {
+ return getMostLikelyAllele(alleleMap, null);
+ }
+
+ /**
+ * Given a map from alleles to likelihoods, find the allele with the largest likelihood.
+ *
+ * @param alleleMap - a map from alleles to likelihoods
+ * @param onlyConsiderTheseAlleles if not null, we will only consider alleles in this set for being one of the best.
+ * this is useful for the case where you've selected a subset of the alleles that
+ * the reads have been computed for further analysis. If null totally ignored
+ * @return - a MostLikelyAllele object
+ */
+ public static MostLikelyAllele getMostLikelyAllele( final Map<Allele,Double> alleleMap, final Set<Allele> onlyConsiderTheseAlleles ) {
+ if ( alleleMap == null ) throw new IllegalArgumentException("The allele to likelihood map cannot be null");
+ double maxLike = Double.NEGATIVE_INFINITY;
+ double prevMaxLike = Double.NEGATIVE_INFINITY;
+ Allele mostLikelyAllele = Allele.NO_CALL;
+ Allele secondMostLikely = null;
+
+ for (final Map.Entry<Allele,Double> el : alleleMap.entrySet()) {
+ if ( onlyConsiderTheseAlleles != null && ! onlyConsiderTheseAlleles.contains(el.getKey()) )
+ continue;
+
+ if (el.getValue() > maxLike) {
+ prevMaxLike = maxLike;
+ maxLike = el.getValue();
+ secondMostLikely = mostLikelyAllele;
+ mostLikelyAllele = el.getKey();
+ } else if( el.getValue() > prevMaxLike ) {
+ secondMostLikely = el.getKey();
+ prevMaxLike = el.getValue();
+ }
+ }
+
+ return new MostLikelyAllele(mostLikelyAllele, secondMostLikely, maxLike, prevMaxLike);
+ }
+
+ /**
+ * Debug method to dump contents of object into string for display
+ */
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+
+ sb.append("Alelles in map:");
+ for (final Allele a:alleles) {
+ sb.append(a.getDisplayString()+",");
+ }
+ sb.append("\n");
+ for (final Map.Entry <GATKSAMRecord, Map<Allele, Double>> el : getLikelihoodReadMap().entrySet() ) {
+ for (final Map.Entry<Allele,Double> eli : el.getValue().entrySet()) {
+ sb.append("Read "+el.getKey().getReadName()+". Allele:"+eli.getKey().getDisplayString()+" has likelihood="+Double.toString(eli.getValue())+"\n");
+ }
+
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Remove reads from this map that are poorly modelled w.r.t. their per allele likelihoods
+ *
+ * Goes through each read in this map, and if it is poorly modelled removes it from the map.
+ *
+ * @see #readIsPoorlyModelled(org.broadinstitute.gatk.utils.sam.GATKSAMRecord, java.util.Collection, double)
+ * for more information about the poorly modelled test.
+ *
+ * @param maxErrorRatePerBase see equivalent parameter in #readIsPoorlyModelled
+ * @return the list of reads removed from this map because they are poorly modelled
+ */
+ public List<GATKSAMRecord> filterPoorlyModelledReads(final double maxErrorRatePerBase) {
+ final List<GATKSAMRecord> removedReads = new LinkedList<>();
+ final Iterator<Map.Entry<GATKSAMRecord, Map<Allele, Double>>> it = likelihoodReadMap.entrySet().iterator();
+ while ( it.hasNext() ) {
+ final Map.Entry<GATKSAMRecord, Map<Allele, Double>> record = it.next();
+ if ( readIsPoorlyModelled(record.getKey(), record.getValue().values(), maxErrorRatePerBase) ) {
+ it.remove();
+ removedReads.add(record.getKey());
+ }
+ }
+
+ return removedReads;
+ }
+
+ /**
+ * Is this read poorly modelled by all of the alleles in this map?
+ *
+ * A read is poorly modeled when it's likelihood is below what would be expected for a read
+ * originating from one of the alleles given the maxErrorRatePerBase of the reads in general.
+ *
+ * This function makes a number of key assumptions. First, that the likelihoods reflect the total likelihood
+ * of the read. In other words, that the read would be fully explained by one of the alleles. This means
+ * that the allele should be something like the full haplotype from which the read might originate.
+ *
+ * It further assumes that each error in the read occurs with likelihood of -3 (Q30 confidence per base). So
+ * a read with a 10% error rate with Q30 bases that's 100 bp long we'd expect to see 10 real Q30 errors
+ * even against the true haplotype. So for this read to be well modelled by at least one allele we'd expect
+ * a likelihood to be >= 10 * -3.
+ *
+ * @param read the read we want to evaluate
+ * @param log10Likelihoods a list of the log10 likelihoods of the read against a set of haplotypes.
+ * @param maxErrorRatePerBase the maximum error rate we'd expect for this read per base, in real space. So
+ * 0.01 means a 1% error rate
+ * @return true if none of the log10 likelihoods imply that the read truly originated from one of the haplotypes
+ */
+ protected boolean readIsPoorlyModelled(final GATKSAMRecord read, final Collection<Double> log10Likelihoods, final double maxErrorRatePerBase) {
+ final double maxErrorsForRead = Math.min(2.0, Math.ceil(read.getReadLength() * maxErrorRatePerBase));
+ final double log10QualPerBase = -4.0;
+ final double log10MaxLikelihoodForTrueAllele = maxErrorsForRead * log10QualPerBase;
+
+ for ( final double log10Likelihood : log10Likelihoods )
+ if ( log10Likelihood >= log10MaxLikelihoodForTrueAllele )
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Get an unmodifiable set of the unique alleles in this PerReadAlleleLikelihoodMap
+ * @return a non-null unmodifiable map
+ */
+ public Set<Allele> getAllelesSet() {
+ return Collections.unmodifiableSet(allelesSet.keySet());
+ }
+
+ /**
+ * Loop over all of the reads in this likelihood map and realign them to its most likely haplotype
+ * @param haplotypes the collection of haplotypes
+ * @param paddedReferenceLoc the active region
+ */
+ public void realignReadsToMostLikelyHaplotype(final Collection<Haplotype> haplotypes, final GenomeLoc paddedReferenceLoc) {
+
+ // we need to remap the Alleles back to the Haplotypes; inefficient but unfortunately this is a requirement currently
+ final Map<Allele, Haplotype> alleleToHaplotypeMap = new HashMap<>(haplotypes.size());
+ for ( final Haplotype haplotype : haplotypes )
+ alleleToHaplotypeMap.put(Allele.create(haplotype.getBases()), haplotype);
+
+ final Map<GATKSAMRecord, Map<Allele, Double>> newLikelihoodReadMap = new LinkedHashMap<>(likelihoodReadMap.size());
+ for( final Map.Entry<GATKSAMRecord, Map<Allele, Double>> entry : likelihoodReadMap.entrySet() ) {
+ final MostLikelyAllele bestAllele = PerReadAlleleLikelihoodMap.getMostLikelyAllele(entry.getValue());
+ final GATKSAMRecord alignedToRef = AlignmentUtils.createReadAlignedToRef(entry.getKey(), alleleToHaplotypeMap.get(bestAllele.getMostLikelyAllele()), paddedReferenceLoc.getStart(), bestAllele.isInformative());
+ newLikelihoodReadMap.put(alignedToRef, entry.getValue());
+ }
+
+ likelihoodReadMap.clear();
+ likelihoodReadMap.putAll(newLikelihoodReadMap);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/ReadLikelihoods.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/ReadLikelihoods.java
new file mode 100644
index 0000000..fa9fc30
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/genotyper/ReadLikelihoods.java
@@ -0,0 +1,1587 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.genotyper;
+
+import htsjdk.variant.variantcontext.Allele;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import org.broadinstitute.gatk.engine.downsampling.AlleleBiasedDownsamplingUtils;
+import org.broadinstitute.gatk.tools.walkers.genotyper.*;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+
+import java.util.*;
+
+/**
+ * Read-likelihoods container implementation based on integer indexed arrays.
+ *
+ * @param <A> the type of the allele the likelihood makes reference to.
+ *
+ * @author Valentin Ruano-Rubio <valentin at broadinstitute.org>
+ */
+public class ReadLikelihoods<A extends Allele> implements SampleList, AlleleList<A>, Cloneable {
+
+ /**
+ * Reads by sample index. Each sub array contains reference to the reads of the ith sample.
+ */
+ private GATKSAMRecord[][] readsBySampleIndex;
+
+ /**
+ * Indexed per sample, allele and finally read (within sample).
+ * <p>
+ * valuesBySampleIndex[s][a][r] == lnLk(R_r | A_a) where R_r comes from Sample s.
+ * </p>
+ */
+ private double[][][] valuesBySampleIndex;
+
+ /**
+ * Sample list
+ */
+ private final SampleList samples;
+
+ /**
+ * Allele list
+ */
+ private AlleleList<A> alleles;
+
+ /**
+ * Cached allele list.
+ */
+ private List<A> alleleList;
+
+ /**
+ * Cached sample list.
+ */
+ private List<String> sampleList;
+
+ /**
+ * Maps from each read to its index within the sample.
+ *
+ * <p>In order to save CPU time the indices contained in this array (not the array itself) is
+ * lazily initialized by invoking {@link #readIndexBySampleIndex(int)}.</p>
+ */
+ private final Object2IntMap<GATKSAMRecord>[] readIndexBySampleIndex;
+
+ /**
+ * Index of the reference allele if any, otherwise -1
+ */
+ private int referenceAlleleIndex = -1;
+
+ /**
+ * Caches the read-list per sample list returned by {@link #sampleReads}
+ */
+ private final List<GATKSAMRecord>[] readListBySampleIndex;
+
+ /**
+ * Sample matrices lazily initialized (the elements not the array) by invoking {@link #sampleMatrix(int)}.
+ */
+ private final Matrix<A>[] sampleMatrices;
+
+ /**
+ * Constructs a new read-likelihood collection.
+ *
+ * <p>
+ * The initial likelihoods for all allele-read combinations are
+ * 0.
+ * </p>
+ *
+ * @param samples all supported samples in the collection.
+ * @param alleles all supported alleles in the collection.
+ * @param reads reads stratified per sample.
+ *
+ * @throws IllegalArgumentException if any of {@code allele}, {@code samples}
+ * or {@code reads} is {@code null},
+ * or if they contain null values.
+ */
+ @SuppressWarnings("unchecked")
+ public ReadLikelihoods(final SampleList samples, final AlleleList<A> alleles,
+ final Map<String, List<GATKSAMRecord>> reads) {
+ if (alleles == null)
+ throw new IllegalArgumentException("allele list cannot be null");
+ if (samples == null)
+ throw new IllegalArgumentException("sample list cannot be null");
+ if (reads == null)
+ throw new IllegalArgumentException("read map cannot be null");
+
+ this.samples = samples;
+ this.alleles = alleles;
+
+ final int sampleCount = samples.sampleCount();
+ final int alleleCount = alleles.alleleCount();
+
+ readsBySampleIndex = new GATKSAMRecord[sampleCount][];
+ readListBySampleIndex = new List[sampleCount];
+ valuesBySampleIndex = new double[sampleCount][][];
+ referenceAlleleIndex = findReferenceAllele(alleles);
+
+ readIndexBySampleIndex = new Object2IntMap[sampleCount];
+
+ setupIndexes(reads, sampleCount, alleleCount);
+
+ sampleMatrices = (Matrix<A>[]) new Matrix[sampleCount];
+ }
+
+ // Add all the indices to alleles, sample and reads in the look-up maps.
+ private void setupIndexes(final Map<String, List<GATKSAMRecord>> reads, final int sampleCount, final int alleleCount) {
+ for (int i = 0; i < sampleCount; i++)
+ setupSampleData(i, reads, alleleCount);
+ }
+
+ // Assumes that {@link #samples} has been initialized with the sample names.
+ private void setupSampleData(final int sampleIndex, final Map<String, List<GATKSAMRecord>> readsBySample,
+ final int alleleCount) {
+ final String sample = samples.sampleAt(sampleIndex);
+
+ final List<GATKSAMRecord> reads = readsBySample.get(sample);
+ readsBySampleIndex[sampleIndex] = reads == null
+ ? new GATKSAMRecord[0]
+ : reads.toArray(new GATKSAMRecord[reads.size()]);
+ final int sampleReadCount = readsBySampleIndex[sampleIndex].length;
+
+ final double[][] sampleValues = new double[alleleCount][sampleReadCount];
+ valuesBySampleIndex[sampleIndex] = sampleValues;
+ }
+
+ /**
+ * Create an independent copy of this read-likelihoods collection
+ */
+ public ReadLikelihoods<A> clone() {
+
+ final int sampleCount = samples.sampleCount();
+ final int alleleCount = alleles.alleleCount();
+
+ final double[][][] newLikelihoodValues = new double[sampleCount][alleleCount][];
+
+ @SuppressWarnings("unchecked")
+ final Object2IntMap<GATKSAMRecord>[] newReadIndexBySampleIndex = new Object2IntMap[sampleCount];
+ final GATKSAMRecord[][] newReadsBySampleIndex = new GATKSAMRecord[sampleCount][];
+
+ for (int s = 0; s < sampleCount; s++) {
+ newReadsBySampleIndex[s] = readsBySampleIndex[s].clone();
+ for (int a = 0; a < alleleCount; a++)
+ newLikelihoodValues[s][a] = valuesBySampleIndex[s][a].clone();
+ }
+
+ // Finally we create the new read-likelihood
+ return new ReadLikelihoods<>(alleles, samples,
+ newReadsBySampleIndex,
+ newReadIndexBySampleIndex, newLikelihoodValues);
+ }
+
+ // Internally used constructor.
+ @SuppressWarnings("unchecked")
+ private ReadLikelihoods(final AlleleList alleles, final SampleList samples,
+ final GATKSAMRecord[][] readsBySampleIndex, final Object2IntMap<GATKSAMRecord>[] readIndex,
+ final double[][][] values) {
+ this.samples = samples;
+ this.alleles = alleles;
+ this.readsBySampleIndex = readsBySampleIndex;
+ this.valuesBySampleIndex = values;
+ this.readIndexBySampleIndex = readIndex;
+ final int sampleCount = samples.sampleCount();
+ this.readListBySampleIndex = new List[sampleCount];
+
+ referenceAlleleIndex = findReferenceAllele(alleles);
+ sampleMatrices = (Matrix<A>[]) new Matrix[sampleCount];
+ }
+
+ // Search for the reference allele, if not found the index is -1.
+ private int findReferenceAllele(final AlleleList<A> alleles) {
+ final int alleleCount = alleles.alleleCount();
+ for (int i = 0; i < alleleCount; i++)
+ if (alleles.alleleAt(i).isReference())
+ return i;
+ return -1;
+ }
+
+ /**
+ * Returns the index of a sample within the likelihood collection.
+ *
+ * @param sample the query sample.
+ *
+ * @throws IllegalArgumentException if {@code sample} is {@code null}.
+ * @return -1 if the allele is not included, 0 or greater otherwise.
+ */
+ public int sampleIndex(final String sample) {
+ return samples.sampleIndex(sample);
+ }
+
+ /**
+ * Number of samples included in the likelihood collection.
+ * @return 0 or greater.
+ */
+ public int sampleCount() {
+ return samples.sampleCount();
+ }
+
+ /**
+ * Returns sample name given its index.
+ *
+ * @param sampleIndex query index.
+ *
+ * @throws IllegalArgumentException if {@code sampleIndex} is negative.
+ *
+ * @return never {@code null}.
+ */
+ public String sampleAt(final int sampleIndex) {
+ return samples.sampleAt(sampleIndex);
+ }
+
+ /**
+ * Returns the index of an allele within the likelihood collection.
+ *
+ * @param allele the query allele.
+ *
+ * @throws IllegalArgumentException if {@code allele} is {@code null}.
+ *
+ * @return -1 if the allele is not included, 0 or greater otherwise.
+ */
+ public int alleleIndex(final A allele) {
+ return alleles.alleleIndex(allele);
+ }
+
+ /**
+ * Returns number of alleles in the collection.
+ * @return 0 or greater.
+ */
+ @SuppressWarnings("unused")
+ public int alleleCount() {
+ return alleles.alleleCount();
+ }
+
+ /**
+ * Returns the allele given its index.
+ *
+ * @param alleleIndex the allele index.
+ *
+ * @throws IllegalArgumentException the allele index is {@code null}.
+ *
+ * @return never {@code null}.
+ */
+ public A alleleAt(final int alleleIndex) {
+ return alleles.alleleAt(alleleIndex);
+ }
+
+ /**
+ * Returns the reads that belong to a sample sorted by their index (within that sample).
+ *
+ * @param sampleIndex the requested sample.
+ * @return never {@code null} but perhaps a zero-length array if there is no reads in sample. No element in
+ * the array will be null.
+ */
+ public List<GATKSAMRecord> sampleReads(final int sampleIndex) {
+ checkSampleIndex(sampleIndex);
+ final List<GATKSAMRecord> extantList = readListBySampleIndex[sampleIndex];
+ if (extantList == null)
+ return readListBySampleIndex[sampleIndex] = Collections.unmodifiableList(Arrays.asList(readsBySampleIndex[sampleIndex]));
+ else
+ return extantList;
+ }
+
+ /**
+ * Returns a read vs allele likelihood matrix corresponding to a sample.
+ *
+ * @param sampleIndex target sample.
+ *
+ * @throws IllegalArgumentException if {@code sampleIndex} is not null.
+ *
+ * @return never {@code null}
+ */
+ public Matrix<A> sampleMatrix(final int sampleIndex) {
+ checkSampleIndex(sampleIndex);
+ final Matrix<A> extantResult = sampleMatrices[sampleIndex];
+ if (extantResult != null)
+ return extantResult;
+ else
+ return sampleMatrices[sampleIndex] = new SampleMatrix(sampleIndex);
+ }
+
+ /**
+ * Adjusts likelihoods so that for each read, the best allele likelihood is 0 and caps the minimum likelihood
+ * of any allele for each read based on the maximum alternative allele likelihood.
+ *
+ * @param bestToZero set the best likelihood to 0, others will be subtracted the same amount.
+ * @param maximumLikelihoodDifferenceCap maximum difference between the best alternative allele likelihood
+ * and any other likelihood.
+ *
+ * @throws IllegalArgumentException if {@code maximumDifferenceWithBestAlternative} is not 0 or less.
+ */
+ public void normalizeLikelihoods(final boolean bestToZero, final double maximumLikelihoodDifferenceCap) {
+ if (maximumLikelihoodDifferenceCap >= 0.0 || Double.isNaN(maximumLikelihoodDifferenceCap))
+ throw new IllegalArgumentException("the minimum reference likelihood fall cannot be positive");
+
+ if (maximumLikelihoodDifferenceCap == Double.NEGATIVE_INFINITY && !bestToZero)
+ return;
+
+ final int alleleCount = alleles.alleleCount();
+ if (alleleCount == 0) // trivial case there is no alleles.
+ return;
+ else if (alleleCount == 1 && !bestToZero)
+ return;
+
+ for (int s = 0; s < valuesBySampleIndex.length; s++) {
+ final double[][] sampleValues = valuesBySampleIndex[s];
+ final int readCount = readsBySampleIndex[s].length;
+ for (int r = 0; r < readCount; r++)
+ normalizeLikelihoodsPerRead(bestToZero, maximumLikelihoodDifferenceCap, sampleValues, s, r);
+ }
+ }
+
+ // Does the normalizeLikelihoods job for each read.
+ private void normalizeLikelihoodsPerRead(final boolean bestToZero, final double maximumBestAltLikelihoodDifference,
+ final double[][] sampleValues, final int sampleIndex, final int readIndex) {
+
+ final BestAllele bestAlternativeAllele = searchBestAllele(sampleIndex,readIndex,false);
+
+ final double worstLikelihoodCap = bestAlternativeAllele.likelihood + maximumBestAltLikelihoodDifference;
+
+ final double referenceLikelihood = referenceAlleleIndex == -1 ? Double.NEGATIVE_INFINITY :
+ sampleValues[referenceAlleleIndex][readIndex];
+
+
+ final double bestAbsoluteLikelihood = Math.max(bestAlternativeAllele.likelihood,referenceLikelihood);
+
+ final int alleleCount = alleles.alleleCount();
+ if (bestToZero) {
+ if (bestAbsoluteLikelihood == Double.NEGATIVE_INFINITY)
+ for (int a = 0; a < alleleCount; a++)
+ sampleValues[a][readIndex] = 0;
+ else if (worstLikelihoodCap != Double.NEGATIVE_INFINITY)
+ for (int a = 0; a < alleleCount; a++)
+ sampleValues[a][readIndex] = (sampleValues[a][readIndex] < worstLikelihoodCap ? worstLikelihoodCap : sampleValues[a][readIndex]) - bestAbsoluteLikelihood;
+ else
+ for (int a = 0; a < alleleCount; a++)
+ sampleValues[a][readIndex] -= bestAbsoluteLikelihood;
+ } else // else if (maximumReferenceLikelihoodFall != Double.NEGATIVE_INFINITY ) { //
+ // Guarantee to be the case by enclosing code.
+ for (int a = 0; a < alleleCount; a++)
+ if (sampleValues[a][readIndex] < worstLikelihoodCap)
+ sampleValues[a][readIndex] = worstLikelihoodCap;
+ }
+
+ /**
+ * Returns the samples in this read-likelihood collection.
+ * <p>
+ * Samples are sorted by their index in the collection.
+ * </p>
+ *
+ * <p>
+ * The returned list is an unmodifiable view on the read-likelihoods sample list.
+ * </p>
+ *
+ * @return never {@code null}.
+ */
+ public List<String> samples() {
+ return sampleList == null ? sampleList = SampleListUtils.asList(samples) : sampleList;
+
+ }
+
+ /**
+ * Returns the samples in this read-likelihood collection.
+ * <p>
+ * Samples are sorted by their index in the collection.
+ * </p>
+ *
+ * <p>
+ * The returned list is an unmodifiable. It will not be updated if the collection
+ * allele list changes.
+ * </p>
+ *
+ * @return never {@code null}.
+ */
+ public List<A> alleles() {
+ return alleleList == null ? alleleList = AlleleListUtils.asList(alleles) : alleleList;
+ }
+
+
+ /**
+ * Search the best allele for a read.
+ *
+ * @param sampleIndex including sample index.
+ * @param readIndex target read index.
+ *
+ * @return never {@code null}, but with {@link BestAllele#allele allele} == {@code null}
+ * if non-could be found.
+ */
+ private BestAllele searchBestAllele(final int sampleIndex, final int readIndex, final boolean canBeReference) {
+ final int alleleCount = alleles.alleleCount();
+ if (alleleCount == 0 || (alleleCount == 1 && referenceAlleleIndex == 0 && !canBeReference))
+ return new BestAllele(sampleIndex,readIndex,-1,Double.NEGATIVE_INFINITY,Double.NEGATIVE_INFINITY);
+
+ final double[][] sampleValues = valuesBySampleIndex[sampleIndex];
+ int bestAlleleIndex = canBeReference || referenceAlleleIndex != 0 ? 0 : 1;
+
+ double bestLikelihood = sampleValues[bestAlleleIndex][readIndex];
+ double secondBestLikelihood = Double.NEGATIVE_INFINITY;
+ for (int a = bestAlleleIndex + 1; a < alleleCount; a++) {
+ if (!canBeReference && referenceAlleleIndex == a)
+ continue;
+ final double candidateLikelihood = sampleValues[a][readIndex];
+ if (candidateLikelihood > bestLikelihood) {
+ bestAlleleIndex = a;
+ secondBestLikelihood = bestLikelihood;
+ bestLikelihood = candidateLikelihood;
+ } else if (candidateLikelihood > secondBestLikelihood) {
+ secondBestLikelihood = candidateLikelihood;
+ }
+ }
+ return new BestAllele(sampleIndex,readIndex,bestAlleleIndex,bestLikelihood,secondBestLikelihood);
+ }
+
+ public void changeReads(final Map<GATKSAMRecord, GATKSAMRecord> readRealignments) {
+ final int sampleCount = samples.sampleCount();
+ for (int s = 0; s < sampleCount; s++) {
+ final GATKSAMRecord[] sampleReads = readsBySampleIndex[s];
+ final Object2IntMap<GATKSAMRecord> readIndex = readIndexBySampleIndex[s];
+ final int sampleReadCount = sampleReads.length;
+ for (int r = 0; r < sampleReadCount; r++) {
+ final GATKSAMRecord read = sampleReads[r];
+ final GATKSAMRecord replacement = readRealignments.get(read);
+ if (replacement == null)
+ continue;
+ sampleReads[r] = replacement;
+ if (readIndex != null) {
+ readIndex.remove(read);
+ readIndex.put(replacement, r);
+ }
+ }
+ }
+ }
+
+ /**
+ * Add alleles that are missing in the read-likelihoods collection giving all reads a default
+ * likelihood value.
+ * @param candidateAlleles the potentially missing alleles.
+ * @param defaultLikelihood the default read likelihood value for that allele.
+ *
+ * @throws IllegalArgumentException if {@code candidateAlleles} is {@code null} or there is more than
+ * one missing allele that is a reference or there is one but the collection already has
+ * a reference allele.
+ */
+ public void addMissingAlleles(final Collection<A> candidateAlleles, final double defaultLikelihood) {
+ if (candidateAlleles == null)
+ throw new IllegalArgumentException("the candidateAlleles list cannot be null");
+ if (candidateAlleles.isEmpty())
+ return;
+ final List<A> allelesToAdd = new ArrayList<>(candidateAlleles.size());
+ for (final A allele : candidateAlleles)
+ if (alleles.alleleIndex(allele) == -1)
+ allelesToAdd.add(allele);
+
+ if (allelesToAdd.isEmpty())
+ return;
+
+ final int oldAlleleCount = alleles.alleleCount();
+ final int newAlleleCount = alleles.alleleCount() + allelesToAdd.size();
+
+ alleleList = null;
+ int referenceIndex = this.referenceAlleleIndex;
+ @SuppressWarnings("unchecked")
+ final A[] newAlleles = (A[]) new Allele[newAlleleCount];
+ for (int a = 0; a < oldAlleleCount; a++)
+ newAlleles[a] = this.alleleAt(a);
+ int newIndex = oldAlleleCount;
+ for (final A allele : allelesToAdd) {
+ if (allele.isReference()) {
+ if (referenceIndex != -1)
+ throw new IllegalArgumentException("there cannot be more than one reference allele");
+ referenceIndex = newIndex;
+ }
+ newAlleles[newIndex++] = allele;
+ }
+
+ alleles = new IndexedAlleleList<>(newAlleles);
+
+ if (referenceIndex != -1)
+ referenceAlleleIndex = referenceIndex;
+
+ final int sampleCount = samples.sampleCount();
+ for (int s = 0; s < sampleCount; s++) {
+ final int sampleReadCount = readsBySampleIndex[s].length;
+ final double[][] newValuesBySampleIndex = Arrays.copyOf(valuesBySampleIndex[s],newAlleleCount);
+ for (int a = oldAlleleCount; a < newAlleleCount; a++) {
+ newValuesBySampleIndex[a] = new double[sampleReadCount];
+ if (defaultLikelihood != 0.0)
+ Arrays.fill(newValuesBySampleIndex[a],defaultLikelihood);
+ }
+ valuesBySampleIndex[s] = newValuesBySampleIndex;
+ }
+ }
+
+ /**
+ * Likelihood matrix between a set of alleles and reads.
+ * @param <A> the allele-type.
+ */
+ public interface Matrix<A extends Allele> extends AlleleList<A> {
+
+ /**
+ * List of reads in the matrix sorted by their index therein.
+ * @return never {@code null}.
+ */
+ public List<GATKSAMRecord> reads();
+
+ /**
+ * List of alleles in the matrix sorted by their index in the collection.
+ * @return never {@code null}.
+ */
+ public List<A> alleles();
+
+ /**
+ * Set the likelihood of a read given an allele through their indices.
+ *
+ * @param alleleIndex the target allele index.
+ * @param readIndex the target read index.
+ * @param value new likelihood value for the target read give the target allele.
+ *
+ * @throws IllegalArgumentException if {@code alleleIndex} or {@code readIndex}
+ * are not valid allele and read indices respectively.
+ */
+ public void set(final int alleleIndex, final int readIndex, final double value);
+
+ /**
+ * Returns the likelihood of a read given a haplotype.
+ *
+ * @param alleleIndex the index of the given haplotype.
+ * @param readIndex the index of the target read.
+ *
+ * @throws IllegalArgumentException if {@code alleleIndex} or {@code readIndex} is not a
+ * valid allele or read index respectively.
+ *
+ * @return the requested likelihood, whatever value was provided using {@link #set(int,int,double) set}
+ * or 0.0 if none was set.
+ */
+ public double get(final int alleleIndex, final int readIndex);
+
+ /**
+ * Queries the index of an allele in the matrix.
+ *
+ * @param allele the target allele.
+ *
+ * @throws IllegalArgumentException if {@code allele} is {@code null}.
+ * @return -1 if such allele does not exist, otherwise its index which 0 or greater.
+ */
+ @SuppressWarnings("unused")
+ public int alleleIndex(final A allele);
+
+ /**
+ * Queries the index of a read in the matrix.
+ *
+ * @param read the target read.
+ *
+ * @throws IllegalArgumentException if {@code read} is {@code null}.
+ *
+ * @return -1 if there is not such a read in the matrix, otherwise its index
+ * which is 0 or greater.
+ */
+ @SuppressWarnings("unused")
+ public int readIndex(final GATKSAMRecord read);
+
+ /**
+ * Number of allele in the matrix.
+ * @return never negative.
+ */
+ public int alleleCount();
+
+ /**
+ * Number of reads in the matrix.
+ * @return never negative.
+ */
+ public int readCount();
+
+ /**
+ * Returns the allele given its index.
+ *
+ * @param alleleIndex the target allele index.
+ *
+ * @throws IllegalArgumentException if {@code alleleIndex} is not a valid allele index.
+ * @return never {@code null}.
+ */
+ public A alleleAt(final int alleleIndex);
+
+ /**
+ * Returns the allele given its index.
+ *
+ * @param readIndex the target allele index.
+ *
+ * @throws IllegalArgumentException if {@code readIndex} is not a valid read index.
+ * @return never {@code null}.
+ */
+ public GATKSAMRecord readAt(final int readIndex);
+
+
+ /**
+ * Copies the likelihood of all the reads for a given allele into an array from a particular offset.
+ * @param alleleIndex the targeted allele
+ * @param dest the destination array.
+ * @param offset the copy offset within the destination allele
+ */
+ public void copyAlleleLikelihoods(final int alleleIndex, final double[] dest, final int offset);
+ }
+
+ /**
+ * Perform marginalization from an allele set to another (smaller one) taking the maximum value
+ * for each read in the original allele subset.
+ *
+ * @param newToOldAlleleMap map where the keys are the new alleles and the value list the original
+ * alleles that correspond to the new one.
+ * @return never {@code null}. The result will have the requested set of new alleles (keys in {@code newToOldAlleleMap}, and
+ * the same set of samples and reads as the original.
+ *
+ * @throws IllegalArgumentException is {@code newToOldAlleleMap} is {@code null} or contains {@code null} values,
+ * or its values contain reference to non-existing alleles in this read-likelihood collection. Also no new allele
+ * can have zero old alleles mapping nor two new alleles can make reference to the same old allele.
+ */
+ public <B extends Allele> ReadLikelihoods<B> marginalize(final Map<B, List<A>> newToOldAlleleMap) {
+
+ if (newToOldAlleleMap == null)
+ throw new IllegalArgumentException("the input allele mapping cannot be null");
+
+ @SuppressWarnings("unchecked")
+ final B[] newAlleles = newToOldAlleleMap.keySet().toArray((B[]) new Allele[newToOldAlleleMap.size()]);
+ final int oldAlleleCount = alleles.alleleCount();
+ final int newAlleleCount = newAlleles.length;
+
+ // we get the index correspondence between new old -> new allele, -1 entries mean that the old
+ // allele does not map to any new; supported but typically not the case.
+ final int[] oldToNewAlleleIndexMap = oldToNewAlleleIndexMap(newToOldAlleleMap, newAlleles, oldAlleleCount, newAlleleCount);
+
+ // We calculate the marginal likelihoods.
+
+ final double[][][] newLikelihoodValues = marginalLikelihoods(oldAlleleCount, newAlleleCount, oldToNewAlleleIndexMap, null);
+
+ final int sampleCount = samples.sampleCount();
+
+ @SuppressWarnings("unchecked")
+ final Object2IntMap<GATKSAMRecord>[] newReadIndexBySampleIndex = new Object2IntMap[sampleCount];
+ final GATKSAMRecord[][] newReadsBySampleIndex = new GATKSAMRecord[sampleCount][];
+
+ for (int s = 0; s < sampleCount; s++) {
+ newReadsBySampleIndex[s] = readsBySampleIndex[s].clone();
+ }
+
+ // Finally we create the new read-likelihood
+ return new ReadLikelihoods<>(new IndexedAlleleList(newAlleles), samples,
+ newReadsBySampleIndex,
+ newReadIndexBySampleIndex, newLikelihoodValues);
+ }
+
+
+ /**
+ * Perform marginalization from an allele set to another (smaller one) taking the maximum value
+ * for each read in the original allele subset.
+ *
+ * @param newToOldAlleleMap map where the keys are the new alleles and the value list the original
+ * alleles that correspond to the new one.
+ * @return never {@code null}. The result will have the requested set of new alleles (keys in {@code newToOldAlleleMap}, and
+ * the same set of samples and reads as the original.
+ *
+ * @param overlap if not {@code null}, only reads that overlap the location (with unclipping) will be present in
+ * the output read-collection.
+ *
+ * @throws IllegalArgumentException is {@code newToOldAlleleMap} is {@code null} or contains {@code null} values,
+ * or its values contain reference to non-existing alleles in this read-likelihood collection. Also no new allele
+ * can have zero old alleles mapping nor two new alleles can make reference to the same old allele.
+ */
+ public <B extends Allele> ReadLikelihoods<B> marginalize(final Map<B, List<A>> newToOldAlleleMap, final GenomeLoc overlap) {
+
+ if (overlap == null)
+ return marginalize(newToOldAlleleMap);
+
+ if (newToOldAlleleMap == null)
+ throw new IllegalArgumentException("the input allele mapping cannot be null");
+
+ @SuppressWarnings("unchecked")
+ final B[] newAlleles = newToOldAlleleMap.keySet().toArray((B[]) new Allele[newToOldAlleleMap.size()]);
+ final int oldAlleleCount = alleles.alleleCount();
+ final int newAlleleCount = newAlleles.length;
+
+ // we get the index correspondence between new old -> new allele, -1 entries mean that the old
+ // allele does not map to any new; supported but typically not the case.
+ final int[] oldToNewAlleleIndexMap = oldToNewAlleleIndexMap(newToOldAlleleMap, newAlleles, oldAlleleCount, newAlleleCount);
+
+ final int[][] readsToKeep = overlappingReadIndicesBySampleIndex(overlap);
+ // We calculate the marginal likelihoods.
+
+ final double[][][] newLikelihoodValues = marginalLikelihoods(oldAlleleCount, newAlleleCount, oldToNewAlleleIndexMap, readsToKeep);
+
+ final int sampleCount = samples.sampleCount();
+
+ @SuppressWarnings("unchecked")
+ final Object2IntMap<GATKSAMRecord>[] newReadIndexBySampleIndex = new Object2IntMap[sampleCount];
+ final GATKSAMRecord[][] newReadsBySampleIndex = new GATKSAMRecord[sampleCount][];
+
+ for (int s = 0; s < sampleCount; s++) {
+ final int[] sampleReadsToKeep = readsToKeep[s];
+ final GATKSAMRecord[] oldSampleReads = readsBySampleIndex[s];
+ final int oldSampleReadCount = oldSampleReads.length;
+ final int newSampleReadCount = sampleReadsToKeep.length;
+ if (newSampleReadCount == oldSampleReadCount) {
+ newReadsBySampleIndex[s] = oldSampleReads.clone();
+ } else {
+ newReadsBySampleIndex[s] = new GATKSAMRecord[newSampleReadCount];
+ for (int i = 0; i < newSampleReadCount; i++)
+ newReadsBySampleIndex[s][i] = oldSampleReads[sampleReadsToKeep[i]];
+ }
+ }
+
+ // Finally we create the new read-likelihood
+ return new ReadLikelihoods<>(new IndexedAlleleList(newAlleles), samples,
+ newReadsBySampleIndex,
+ newReadIndexBySampleIndex, newLikelihoodValues);
+ }
+
+ private int[][] overlappingReadIndicesBySampleIndex(final GenomeLoc overlap) {
+ if (overlap == null)
+ return null;
+ final int sampleCount = samples.sampleCount();
+ final int[][] result = new int[sampleCount][];
+ final IntArrayList buffer = new IntArrayList(200);
+ final int referenceIndex = overlap.getContigIndex();
+ final int overlapStart = overlap.getStart();
+ final int overlapEnd = overlap.getStop();
+ for (int s = 0; s < sampleCount; s++) {
+ buffer.clear();
+ final GATKSAMRecord[] sampleReads = readsBySampleIndex[s];
+ final int sampleReadCount = sampleReads.length;
+ buffer.ensureCapacity(sampleReadCount);
+ for (int r = 0; r < sampleReadCount; r++)
+ if (unclippedReadOverlapsRegion(sampleReads[r], referenceIndex, overlapStart, overlapEnd))
+ buffer.add(r);
+ result[s] = buffer.toIntArray();
+ }
+ return result;
+ }
+
+ public static boolean unclippedReadOverlapsRegion(final GATKSAMRecord read, final GenomeLoc region) {
+ return unclippedReadOverlapsRegion(read, region.getContigIndex(), region.getStart(), region.getStop());
+ }
+
+ private static boolean unclippedReadOverlapsRegion(final GATKSAMRecord sampleRead, final int referenceIndex, final int start, final int end) {
+ final int readReference = sampleRead.getReferenceIndex();
+ if (readReference != referenceIndex)
+ return false;
+
+ final int readStart = sampleRead.getUnclippedStart();
+ if (readStart > end)
+ return false;
+
+ final int readEnd = sampleRead.getReadUnmappedFlag() ? sampleRead.getUnclippedEnd()
+ : Math.max(sampleRead.getUnclippedEnd(), sampleRead.getUnclippedStart());
+ return readEnd >= start;
+ }
+
+ // Calculate the marginal likelihoods considering the old -> new allele index mapping.
+ private double[][][] marginalLikelihoods(final int oldAlleleCount, final int newAlleleCount, final int[] oldToNewAlleleIndexMap, final int[][] readsToKeep) {
+
+ final int sampleCount = samples.sampleCount();
+ final double[][][] result = new double[sampleCount][][];
+
+ for (int s = 0; s < sampleCount; s++) {
+ final int sampleReadCount = readsBySampleIndex[s].length;
+ final double[][] oldSampleValues = valuesBySampleIndex[s];
+ final int[] sampleReadToKeep = readsToKeep == null || readsToKeep[s].length == sampleReadCount ? null : readsToKeep[s];
+ final int newSampleReadCount = sampleReadToKeep == null ? sampleReadCount : sampleReadToKeep.length;
+ final double[][] newSampleValues = result[s] = new double[newAlleleCount][newSampleReadCount];
+ // We initiate all likelihoods to -Inf.
+ for (int a = 0; a < newAlleleCount; a++)
+ Arrays.fill(newSampleValues[a], Double.NEGATIVE_INFINITY);
+ // For each old allele and read we update the new table keeping the maximum likelihood.
+ for (int r = 0; r < newSampleReadCount; r++) {
+ for (int a = 0; a < oldAlleleCount; a++) {
+ final int oldReadIndex = newSampleReadCount == sampleReadCount ? r : sampleReadToKeep[r];
+ final int newAlleleIndex = oldToNewAlleleIndexMap[a];
+ if (newAlleleIndex == -1)
+ continue;
+ final double likelihood = oldSampleValues[a][oldReadIndex];
+ if (likelihood > newSampleValues[newAlleleIndex][r])
+ newSampleValues[newAlleleIndex][r] = likelihood;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Given a collection of likelihood in the old map format, it creates the corresponding read-likelihoods collection.
+ *
+ * @param map the likelihoods to transform.
+ *
+ * @throws IllegalArgumentException if {@code map} is {@code null}.
+ *
+ * @return never {@code null}.
+ */
+ public static ReadLikelihoods<Allele> fromPerAlleleReadLikelihoodsMap(final Map<String,PerReadAlleleLikelihoodMap> map) {
+
+ // First we need to create the read-likelihood collection with all required alleles, samples and reads.
+ final SampleList sampleList = new IndexedSampleList(map.keySet());
+ final Set<Allele> alleles = new LinkedHashSet<>(10);
+ final Map<String,List<GATKSAMRecord>> sampleToReads = new HashMap<>(sampleList.sampleCount());
+ for (final Map.Entry<String,PerReadAlleleLikelihoodMap> entry : map.entrySet()) {
+ final String sample = entry.getKey();
+ final PerReadAlleleLikelihoodMap sampleLikelihoods = entry.getValue();
+ alleles.addAll(sampleLikelihoods.getAllelesSet());
+ sampleToReads.put(sample,new ArrayList<>(sampleLikelihoods.getLikelihoodReadMap().keySet()));
+ }
+
+ final AlleleList<Allele> alleleList = new IndexedAlleleList<>(alleles);
+ final ReadLikelihoods<Allele> result = new ReadLikelihoods<>(sampleList,alleleList,sampleToReads);
+
+ // Now set the likelihoods.
+ for (final Map.Entry<String,PerReadAlleleLikelihoodMap> sampleEntry : map.entrySet()) {
+ final ReadLikelihoods.Matrix<Allele> sampleMatrix = result.sampleMatrix(result.sampleIndex(sampleEntry.getKey()));
+ for (final Map.Entry<GATKSAMRecord,Map<Allele,Double>> readEntry : sampleEntry.getValue().getLikelihoodReadMap().entrySet()) {
+ final GATKSAMRecord read = readEntry.getKey();
+ final int readIndex = sampleMatrix.readIndex(read);
+ for (final Map.Entry<Allele,Double> alleleEntry : readEntry.getValue().entrySet()) {
+ final int alleleIndex = result.alleleIndex(alleleEntry.getKey());
+ sampleMatrix.set(alleleIndex,readIndex,alleleEntry.getValue());
+ }
+ }
+ }
+ return result;
+ }
+
+ // calculates an old to new allele index map array.
+ private <B extends Allele> int[] oldToNewAlleleIndexMap(final Map<B, List<A>> newToOldAlleleMap, final B[] newAlleles,
+ final int oldAlleleCount, final int newAlleleCount) {
+
+ final int[] oldToNewAlleleIndexMap = new int[oldAlleleCount];
+ Arrays.fill(oldToNewAlleleIndexMap, -1); // -1 indicate that there is no new allele that make reference to that old one.
+
+ for (int i = 0; i < newAlleleCount; i++) {
+ final B newAllele = newAlleles[i];
+ if (newAllele == null)
+ throw new IllegalArgumentException("input alleles cannot be null");
+ final List<A> oldAlleles = newToOldAlleleMap.get(newAllele);
+ if (oldAlleles == null)
+ throw new IllegalArgumentException("no new allele list can be null");
+ for (final A oldAllele : oldAlleles) {
+ if (oldAllele == null)
+ throw new IllegalArgumentException("old alleles cannot be null");
+ final int oldAlleleIndex = alleleIndex(oldAllele);
+ if (oldAlleleIndex == -1)
+ throw new IllegalArgumentException("missing old allele " + oldAllele + " in likelihood collection ");
+ if (oldToNewAlleleIndexMap[oldAlleleIndex] != -1)
+ throw new IllegalArgumentException("collision: two new alleles make reference to the same old allele");
+ oldToNewAlleleIndexMap[oldAlleleIndex] = i;
+ }
+ }
+ return oldToNewAlleleIndexMap;
+ }
+
+ /**
+ * Remove those reads that do not overlap certain genomic location.
+ *
+ * <p>
+ * This method modifies the current read-likelihoods collection.
+ * </p>
+ *
+ * @param location the target location.
+ *
+ * @throws IllegalArgumentException the location cannot be {@code null} nor unmapped.
+ */
+ @SuppressWarnings("unused")
+ public void filterToOnlyOverlappingUnclippedReads(final GenomeLoc location) {
+ if (location == null)
+ throw new IllegalArgumentException("the location cannot be null");
+ if (location.isUnmapped())
+ throw new IllegalArgumentException("the location cannot be unmapped");
+
+ final int sampleCount = samples.sampleCount();
+
+ final int locContig = location.getContigIndex();
+ final int locStart = location.getStart();
+ final int locEnd = location.getStop();
+
+ final int alleleCount = alleles.alleleCount();
+ final IntArrayList removeIndices = new IntArrayList(10);
+ for (int s = 0; s < sampleCount; s++) {
+ int readRemoveCount = 0;
+ final GATKSAMRecord[] sampleReads = readsBySampleIndex[s];
+ final int sampleReadCount = sampleReads.length;
+ for (int r = 0; r < sampleReadCount; r++)
+ if (!unclippedReadOverlapsRegion(sampleReads[r], locContig, locStart, locEnd))
+ removeIndices.add(r);
+ removeSampleReads(s,removeIndices,alleleCount);
+ removeIndices.clear();
+ }
+ }
+
+ // Compare the read coordinates to the location of interest.
+ private boolean readOverlapsLocation(final String contig, final int locStart,
+ final int locEnd, final GATKSAMRecord read) {
+ final boolean overlaps;
+
+ if (read.getReadUnmappedFlag())
+ overlaps = false;
+ else if (!read.getReferenceName().equals(contig))
+ overlaps = false;
+ else {
+ int alnStart = read.getAlignmentStart();
+ int alnStop = read.getAlignmentEnd();
+ if (alnStart > alnStop) { // Paranoia? based on GLP.createGenomeLoc(Read) this can happen?.
+ final int end = alnStart;
+ alnStart = alnStop;
+ alnStop = end;
+ }
+ overlaps = !(alnStop < locStart || alnStart > locEnd);
+ }
+ return overlaps;
+ }
+
+ /**
+ * Removes those read that the best possible likelihood given any allele is just too low.
+ *
+ * <p>
+ * This is determined by a maximum error per read-base against the best likelihood possible.
+ * </p>
+ *
+ * @param maximumErrorPerBase the minimum acceptable error rate per read base, must be
+ * a positive number.
+ *
+ * @throws IllegalStateException is not supported for read-likelihood that do not contain alleles.
+ *
+ * @throws IllegalArgumentException if {@code maximumErrorPerBase} is negative.
+ */
+ public void filterPoorlyModeledReads(final double maximumErrorPerBase) {
+ if (alleles.alleleCount() == 0)
+ throw new IllegalStateException("unsupported for read-likelihood collections with no alleles");
+ if (Double.isNaN(maximumErrorPerBase) || maximumErrorPerBase <= 0.0)
+ throw new IllegalArgumentException("the maximum error per base must be a positive number");
+ final int sampleCount = samples.sampleCount();
+
+ final int alleleCount = alleles.alleleCount();
+ final IntArrayList removeIndices = new IntArrayList(10);
+ for (int s = 0; s < sampleCount; s++) {
+ final GATKSAMRecord[] sampleReads = readsBySampleIndex[s];
+ final int sampleReadCount = sampleReads.length;
+ for (int r = 0; r < sampleReadCount; r++) {
+ final GATKSAMRecord read = sampleReads[r];
+ if (readIsPoorlyModelled(s,r,read, maximumErrorPerBase))
+ removeIndices.add(r);
+ }
+ removeSampleReads(s, removeIndices, alleleCount);
+ removeIndices.clear();
+ }
+ }
+
+ // Check whether the read is poorly modelled.
+ protected boolean readIsPoorlyModelled(final int sampleIndex, final int readIndex, final GATKSAMRecord read, final double maxErrorRatePerBase) {
+ final double maxErrorsForRead = Math.min(2.0, Math.ceil(read.getReadLength() * maxErrorRatePerBase));
+ final double log10QualPerBase = -4.0;
+ final double log10MaxLikelihoodForTrueAllele = maxErrorsForRead * log10QualPerBase;
+
+ final int alleleCount = alleles.alleleCount();
+ final double[][] sampleValues = valuesBySampleIndex[sampleIndex];
+ for (int a = 0; a < alleleCount; a++)
+ if (sampleValues[a][readIndex] >= log10MaxLikelihoodForTrueAllele)
+ return false;
+ return true;
+ }
+
+
+ /**
+ * Add more reads to the collection.
+ *
+ * @param readsBySample reads to add.
+ * @param initialLikelihood the likelihood for the new entries.
+ *
+ * @throws IllegalArgumentException if {@code readsBySample} is {@code null} or {@code readsBySample} contains
+ * {@code null} reads, or {@code readsBySample} contains read that are already present in the read-likelihood
+ * collection.
+ */
+ public void addReads(final Map<String,List<GATKSAMRecord>> readsBySample, final double initialLikelihood) {
+
+ for (final Map.Entry<String,List<GATKSAMRecord>> entry : readsBySample.entrySet()) {
+
+ final String sample = entry.getKey();
+ final List<GATKSAMRecord> newSampleReads = entry.getValue();
+ final int sampleIndex = samples.sampleIndex(sample);
+
+ if (sampleIndex == -1)
+ throw new IllegalArgumentException("input sample " + sample +
+ " is not part of the read-likelihoods collection");
+
+ if (newSampleReads == null || newSampleReads.size() == 0)
+ continue;
+
+ final int sampleReadCount = readsBySampleIndex[sampleIndex].length;
+ final int newSampleReadCount = sampleReadCount + newSampleReads.size();
+
+ appendReads(newSampleReads, sampleIndex, sampleReadCount, newSampleReadCount);
+ extendsLikelihoodArrays(initialLikelihood, sampleIndex, sampleReadCount, newSampleReadCount);
+ }
+ }
+
+ // Extends the likelihood arrays-matrices.
+ private void extendsLikelihoodArrays(double initialLikelihood, int sampleIndex, int sampleReadCount, int newSampleReadCount) {
+ final double[][] sampleValues = valuesBySampleIndex[sampleIndex];
+ final int alleleCount = alleles.alleleCount();
+ for (int a = 0; a < alleleCount; a++)
+ sampleValues[a] = Arrays.copyOf(sampleValues[a], newSampleReadCount);
+ if (initialLikelihood != 0.0) // the default array new value.
+ for (int a = 0; a < alleleCount; a++)
+ Arrays.fill(sampleValues[a],sampleReadCount,newSampleReadCount,initialLikelihood);
+ }
+
+ // Append the new read reference into the structure per-sample.
+ private void appendReads(final List<GATKSAMRecord> newSampleReads, final int sampleIndex,
+ final int sampleReadCount, final int newSampleReadCount) {
+ final GATKSAMRecord[] sampleReads = readsBySampleIndex[sampleIndex] =
+ Arrays.copyOf(readsBySampleIndex[sampleIndex], newSampleReadCount);
+
+ int nextReadIndex = sampleReadCount;
+ final Object2IntMap<GATKSAMRecord> sampleReadIndex = readIndexBySampleIndex[sampleIndex];
+ for (final GATKSAMRecord newRead : newSampleReads) {
+ // if (sampleReadIndex.containsKey(newRead)) // might be worth handle this without exception (ignore the read?) but in practice should never be the case.
+ // throw new IllegalArgumentException("you cannot add reads that are already in read-likelihood collection");
+ if (sampleReadIndex != null ) sampleReadIndex.put(newRead,nextReadIndex);
+ sampleReads[nextReadIndex++] = newRead;
+ }
+ }
+
+ /**
+ * Adds the non-reference allele to the read-likelihood collection setting each read likelihood to the second
+ * best found (or best one if only one allele has likelihood).
+ *
+ * <p>Nothing will happen if the read-likelihoods collection already includes the non-ref allele</p>
+ *
+ * <p>
+ * <i>Implementation note: even when strictly speaking we do not need to demand the calling code to pass
+ * the reference the non-ref allele, we still demand it in order to lead the
+ * the calling code to use the right generic type for this likelihoods
+ * collection {@link Allele}.</i>
+ * </p>
+ *
+ * @param nonRefAllele the non-ref allele.
+ *
+ * @throws IllegalArgumentException if {@code nonRefAllele} is anything but the designated <NON_REF>
+ * symbolic allele {@link GATKVariantContextUtils#NON_REF_SYMBOLIC_ALLELE}.
+ */
+ public void addNonReferenceAllele(final A nonRefAllele) {
+
+ if (nonRefAllele == null)
+ throw new IllegalArgumentException("non-ref allele cannot be null");
+ if (!nonRefAllele.equals(GATKVariantContextUtils.NON_REF_SYMBOLIC_ALLELE))
+ throw new IllegalArgumentException("the non-ref allele is not valid");
+ // Already present?
+ if (alleles.alleleIndex(nonRefAllele) != -1)
+ return;
+
+ final int oldAlleleCount = alleles.alleleCount();
+ final int newAlleleCount = oldAlleleCount + 1;
+ @SuppressWarnings("unchecked")
+ final A[] newAlleles = (A[]) new Allele[newAlleleCount];
+ for (int a = 0; a < oldAlleleCount; a++)
+ newAlleles[a] = alleles.alleleAt(a);
+ newAlleles[oldAlleleCount] = nonRefAllele;
+ alleles = new IndexedAlleleList<>(newAlleles);
+ alleleList = null; // remove the cached alleleList.
+
+ final int sampleCount = samples.sampleCount();
+ for (int s = 0; s < sampleCount; s++)
+ addNonReferenceAlleleLikelihoodsPerSample(oldAlleleCount, newAlleleCount, s);
+ }
+
+ // Updates per-sample structures according to the addition of the NON_REF allele.
+ private void addNonReferenceAlleleLikelihoodsPerSample(final int alleleCount, final int newAlleleCount, final int sampleIndex) {
+ final double[][] sampleValues = valuesBySampleIndex[sampleIndex] = Arrays.copyOf(valuesBySampleIndex[sampleIndex], newAlleleCount);
+ final int sampleReadCount = readsBySampleIndex[sampleIndex].length;
+
+ final double[] nonRefAlleleLikelihoods = sampleValues[alleleCount] = new double [sampleReadCount];
+ Arrays.fill(nonRefAlleleLikelihoods,Double.NEGATIVE_INFINITY);
+ for (int r = 0; r < sampleReadCount; r++) {
+ final BestAllele bestAllele = searchBestAllele(sampleIndex,r,true);
+ final double secondBestLikelihood = Double.isInfinite(bestAllele.confidence) ? bestAllele.likelihood
+ : bestAllele.likelihood - bestAllele.confidence;
+ nonRefAlleleLikelihoods[r] = secondBestLikelihood;
+ }
+ }
+
+ /**
+ * Downsamples reads based on contamination fractions making sure that all alleles are affected proportionally.
+ *
+ * @param perSampleDownsamplingFraction contamination sample map where the sample name are the keys and the
+ * fractions are the values.
+ *
+ * @throws IllegalArgumentException if {@code perSampleDownsamplingFraction} is {@code null}.
+ */
+ public void contaminationDownsampling(final Map<String, Double> perSampleDownsamplingFraction) {
+
+ final int sampleCount = samples.sampleCount();
+ final IntArrayList readsToRemove = new IntArrayList(10); // blind estimate, can be improved?
+ final int alleleCount = alleles.alleleCount();
+ for (int s = 0; s < sampleCount; s++) {
+ final String sample = samples.sampleAt(s);
+ final Double fractionDouble = perSampleDownsamplingFraction.get(sample);
+ if (fractionDouble == null)
+ continue;
+ final double fraction = fractionDouble;
+ if (Double.isNaN(fraction) || fraction <= 0.0)
+ continue;
+ if (fraction >= 1.0) {
+ final int sampleReadCount = readsBySampleIndex[s].length;
+ readsToRemove.ensureCapacity(sampleReadCount);
+ for (int r = 0; r < sampleReadCount; r++)
+ readsToRemove.add(r);
+ removeSampleReads(s,readsToRemove,alleleCount);
+ readsToRemove.clear();
+ }
+ else {
+ final Map<A,List<GATKSAMRecord>> readsByBestAllelesMap = readsByBestAlleleMap(s);
+ removeSampleReads(s,AlleleBiasedDownsamplingUtils.selectAlleleBiasedReads(readsByBestAllelesMap, fraction),alleleCount);
+ }
+ }
+ }
+
+ /**
+ * Given a collection of likelihood in the old map format, it creates the corresponding read-likelihoods collection.
+ *
+ * @param alleleList the target list of alleles.
+ * @param map the likelihoods to transform.
+ *
+ *
+ * @throws IllegalArgumentException if {@code map} is {@code null}, or {@code map} does not contain likelihoods for all read vs allele combinations.
+ *
+ * @return never {@code null}.
+ */
+ public static ReadLikelihoods<Allele> fromPerAlleleReadLikelihoodsMap(final AlleleList<Allele> alleleList, final Map<String,PerReadAlleleLikelihoodMap> map) {
+
+ //TODO add test code for this method.
+ // First we need to create the read-likelihood collection with all required alleles, samples and reads.
+ final SampleList sampleList = new IndexedSampleList(map.keySet());
+ final int alleleCount = alleleList.alleleCount();
+ final Map<String,List<GATKSAMRecord>> sampleToReads = new HashMap<>(sampleList.sampleCount());
+ for (final Map.Entry<String,PerReadAlleleLikelihoodMap> entry : map.entrySet()) {
+ final String sample = entry.getKey();
+ final PerReadAlleleLikelihoodMap sampleLikelihoods = entry.getValue();
+ sampleToReads.put(sample,new ArrayList<>(sampleLikelihoods.getLikelihoodReadMap().keySet()));
+ }
+
+ final ReadLikelihoods<Allele> result = new ReadLikelihoods<>(sampleList,alleleList,sampleToReads);
+
+ // Now set the likelihoods.
+ for (final Map.Entry<String,PerReadAlleleLikelihoodMap> sampleEntry : map.entrySet()) {
+ final ReadLikelihoods.Matrix<Allele> sampleMatrix = result.sampleMatrix(result.sampleIndex(sampleEntry.getKey()));
+ for (final Map.Entry<GATKSAMRecord,Map<Allele,Double>> readEntry : sampleEntry.getValue().getLikelihoodReadMap().entrySet()) {
+ final GATKSAMRecord read = readEntry.getKey();
+ final int readIndex = sampleMatrix.readIndex(read);
+ final Map<Allele,Double> alleleToLikelihoodMap = readEntry.getValue();
+ for (int a = 0; a < alleleCount; a++) {
+ final Allele allele = alleleList.alleleAt(a);
+ final Double likelihood = alleleToLikelihoodMap.get(allele);
+ if (likelihood == null)
+ throw new IllegalArgumentException("there is no likelihood for allele " + allele + " and read " + read);
+ sampleMatrix.set(a,readIndex,likelihood);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the collection of best allele estimates for the reads based on the read-likelihoods.
+ *
+ * @throws IllegalStateException if there is no alleles.
+ *
+ * @return never {@code null}, one element per read in the read-likelihoods collection.
+ */
+ public Collection<BestAllele> bestAlleles() {
+ final List<BestAllele> result = new ArrayList<>(100); // blind estimate.
+ final int sampleCount = samples.sampleCount();
+ for (int s = 0; s < sampleCount; s++) {
+ final GATKSAMRecord[] sampleReads = readsBySampleIndex[s];
+ final int readCount = sampleReads.length;
+ for (int r = 0; r < readCount; r++)
+ result.add(searchBestAllele(s,r,true));
+ }
+ return result;
+ }
+
+ /**
+ * Returns reads stratified by their best allele.
+ * @param sampleIndex the target sample.
+ * @return never {@code null}, perhaps empty.
+ */
+ public Map<A,List<GATKSAMRecord>> readsByBestAlleleMap(final int sampleIndex) {
+ checkSampleIndex(sampleIndex);
+ final int alleleCount = alleles.alleleCount();
+ final int sampleReadCount = readsBySampleIndex[sampleIndex].length;
+ final Map<A,List<GATKSAMRecord>> result = new HashMap<>(alleleCount);
+ for (int a = 0; a < alleleCount; a++)
+ result.put(alleles.alleleAt(a),new ArrayList<GATKSAMRecord>(sampleReadCount));
+ readsByBestAlleleMap(sampleIndex,result);
+ return result;
+ }
+
+ /**
+ * Returns reads stratified by their best allele.
+ * @return never {@code null}, perhaps empty.
+ */
+ @SuppressWarnings("unused")
+ public Map<A,List<GATKSAMRecord>> readsByBestAlleleMap() {
+ final int alleleCount = alleles.alleleCount();
+ final Map<A,List<GATKSAMRecord>> result = new HashMap<>(alleleCount);
+ final int totalReadCount = readCount();
+ for (int a = 0; a < alleleCount; a++)
+ result.put(alleles.alleleAt(a),new ArrayList<GATKSAMRecord>(totalReadCount));
+ final int sampleCount = samples.sampleCount();
+ for (int s = 0; s < sampleCount; s++)
+ readsByBestAlleleMap(s,result);
+ return result;
+ }
+
+ private void readsByBestAlleleMap(final int sampleIndex, final Map<A,List<GATKSAMRecord>> result) {
+ final GATKSAMRecord[] reads = readsBySampleIndex[sampleIndex];
+ final int readCount = reads.length;
+
+ for (int r = 0; r < readCount; r++) {
+ final BestAllele bestAllele = searchBestAllele(sampleIndex,r,true);
+ if (!bestAllele.isInformative())
+ continue;
+ result.get(bestAllele.allele).add(bestAllele.read);
+ }
+ }
+
+ /**
+ * Returns the index of a read within a sample read-likelihood sub collection.
+ * @param sampleIndex the sample index.
+ * @param read the query read.
+ * @return -1 if there is no such read in that sample, 0 or greater otherwise.
+ */
+ @SuppressWarnings("unused")
+ public int readIndex(final int sampleIndex, final GATKSAMRecord read) {
+ final Object2IntMap<GATKSAMRecord> readIndex = readIndexBySampleIndex(sampleIndex);
+ if (readIndex.containsKey(read))
+ return readIndexBySampleIndex(sampleIndex).getInt(read);
+ else
+ return -1;
+ }
+
+ /**
+ * Returns the total number of reads in the read-likelihood collection.
+ *
+ * @return never {@code null}
+ */
+ public int readCount() {
+ int sum = 0;
+ final int sampleCount = samples.sampleCount();
+ for (int i = 0; i < sampleCount; i++)
+ sum += readsBySampleIndex[i].length;
+ return sum;
+ }
+
+ /**
+ * Returns the number of reads that belong to a sample in the read-likelihood collection.
+ * @param sampleIndex the query sample index.
+ *
+ * @throws IllegalArgumentException if {@code sampleIndex} is not a valid sample index.
+ * @return 0 or greater.
+ */
+ public int sampleReadCount(int sampleIndex) {
+ checkSampleIndex(sampleIndex);
+ return readsBySampleIndex[sampleIndex].length;
+ }
+
+ /**
+ * Contains information about the best allele for a read search result.
+ */
+ public class BestAllele {
+ public static final double INFORMATIVE_THRESHOLD = 0.2;
+
+ /**
+ * Null if there is no possible match (no allele?).
+ */
+ public final A allele;
+
+ /**
+ * The containing sample.
+ */
+ public final String sample;
+
+ /**
+ * The query read.
+ */
+ public final GATKSAMRecord read;
+
+ /**
+ * If allele != null, the indicates the likelihood of the read.
+ */
+ public final double likelihood;
+
+ /**
+ * Confidence that the read actually was generated under that likelihood.
+ * This is equal to the difference between this and the second best allele match.
+ */
+ public final double confidence;
+
+ private BestAllele(final int sampleIndex, final int readIndex, final int bestAlleleIndex,
+ final double likelihood, final double secondBestLikelihood) {
+ allele = bestAlleleIndex == -1 ? null : alleles.alleleAt(bestAlleleIndex);
+ this.likelihood = likelihood;
+ sample = samples.sampleAt(sampleIndex);
+ read = readsBySampleIndex[sampleIndex][readIndex];
+ confidence = likelihood == secondBestLikelihood ? 0 : likelihood - secondBestLikelihood;
+ }
+
+ public boolean isInformative() {
+ return confidence > INFORMATIVE_THRESHOLD;
+ }
+ }
+
+ private void removeSampleReads(final int sampleIndex, final IntArrayList indexToRemove, final int alleleCount) {
+ final int removeCount = indexToRemove.size();
+ if (removeCount == 0)
+ return;
+
+ final GATKSAMRecord[] sampleReads = readsBySampleIndex[sampleIndex];
+ final int sampleReadCount = sampleReads.length;
+
+ final Object2IntMap<GATKSAMRecord> indexByRead = readIndexBySampleIndex[sampleIndex];
+ if (indexByRead != null)
+ for (int i = 0; i < removeCount; i++)
+ indexByRead.remove(sampleReads[indexToRemove.getInt(i)]);
+ final boolean[] removeIndex = new boolean[sampleReadCount];
+ int firstDeleted = indexToRemove.get(0);
+ for (int i = 0; i < removeCount; i++)
+ removeIndex[indexToRemove.get(i)] = true;
+
+ final int newSampleReadCount = sampleReadCount - removeCount;
+
+ // Now we skim out the removed reads from the read array.
+ final GATKSAMRecord[] oldSampleReads = readsBySampleIndex[sampleIndex];
+ final GATKSAMRecord[] newSampleReads = new GATKSAMRecord[newSampleReadCount];
+
+ System.arraycopy(oldSampleReads,0,newSampleReads,0,firstDeleted);
+ Utils.skimArray(oldSampleReads,firstDeleted, newSampleReads, firstDeleted, removeIndex, firstDeleted);
+
+ // Then we skim out the likelihoods of the removed reads.
+ final double[][] oldSampleValues = valuesBySampleIndex[sampleIndex];
+ final double[][] newSampleValues = new double[alleleCount][newSampleReadCount];
+ for (int a = 0; a < alleleCount; a++) {
+ System.arraycopy(oldSampleValues[a],0,newSampleValues[a],0,firstDeleted);
+ Utils.skimArray(oldSampleValues[a], firstDeleted, newSampleValues[a], firstDeleted, removeIndex, firstDeleted);
+ }
+ valuesBySampleIndex[sampleIndex] = newSampleValues;
+ readsBySampleIndex[sampleIndex] = newSampleReads;
+ readListBySampleIndex[sampleIndex] = null; // reset the unmodifiable list.
+ }
+
+
+ // Requires that the collection passed iterator can remove elements, and it can be modified.
+ private void removeSampleReads(final int sampleIndex, final Collection<GATKSAMRecord> readsToRemove, final int alleleCount) {
+ final GATKSAMRecord[] sampleReads = readsBySampleIndex[sampleIndex];
+ final int sampleReadCount = sampleReads.length;
+
+ final Object2IntMap<GATKSAMRecord> indexByRead = readIndexBySampleIndex(sampleIndex);
+ // Count how many we are going to remove, which ones (indexes) and remove entry from the read-index map.
+ final boolean[] removeIndex = new boolean[sampleReadCount];
+ int removeCount = 0; // captures the number of deletions.
+ int firstDeleted = sampleReadCount; // captures the first position that was deleted.
+
+ final Iterator<GATKSAMRecord> readsToRemoveIterator = readsToRemove.iterator();
+ while (readsToRemoveIterator.hasNext()) {
+ final GATKSAMRecord read = readsToRemoveIterator.next();
+ if (indexByRead.containsKey(read)) {
+ final int index = indexByRead.getInt(read);
+ if (firstDeleted > index)
+ firstDeleted = index;
+ removeCount++;
+ removeIndex[index] = true;
+ readsToRemoveIterator.remove();
+ indexByRead.remove(read);
+ }
+ }
+
+ // Nothing to remove we just finish here.
+ if (removeCount == 0)
+ return;
+
+ final int newSampleReadCount = sampleReadCount - removeCount;
+
+ // Now we skim out the removed reads from the read array.
+ final GATKSAMRecord[] oldSampleReads = readsBySampleIndex[sampleIndex];
+ final GATKSAMRecord[] newSampleReads = new GATKSAMRecord[newSampleReadCount];
+
+ System.arraycopy(oldSampleReads,0,newSampleReads,0,firstDeleted);
+ Utils.skimArray(oldSampleReads,firstDeleted, newSampleReads, firstDeleted, removeIndex, firstDeleted);
+
+ // Update the indices for the extant reads from the first deletion onwards.
+ for (int r = firstDeleted; r < newSampleReadCount; r++) {
+ indexByRead.put(newSampleReads[r], r);
+ }
+
+ // Then we skim out the likelihoods of the removed reads.
+ final double[][] oldSampleValues = valuesBySampleIndex[sampleIndex];
+ final double[][] newSampleValues = new double[alleleCount][newSampleReadCount];
+ for (int a = 0; a < alleleCount; a++) {
+ System.arraycopy(oldSampleValues[a],0,newSampleValues[a],0,firstDeleted);
+ Utils.skimArray(oldSampleValues[a], firstDeleted, newSampleValues[a], firstDeleted, removeIndex, firstDeleted);
+ }
+ valuesBySampleIndex[sampleIndex] = newSampleValues;
+ readsBySampleIndex[sampleIndex] = newSampleReads;
+ readListBySampleIndex[sampleIndex] = null; // reset the unmodifiable list.
+ }
+
+ private Object2IntMap<GATKSAMRecord> readIndexBySampleIndex(final int sampleIndex) {
+ if (readIndexBySampleIndex[sampleIndex] == null) {
+ final GATKSAMRecord[] sampleReads = readsBySampleIndex[sampleIndex];
+ final int sampleReadCount = sampleReads.length;
+ readIndexBySampleIndex[sampleIndex] = new Object2IntOpenHashMap<>(sampleReadCount);
+ for (int r = 0; r < sampleReadCount; r++)
+ readIndexBySampleIndex[sampleIndex].put(sampleReads[r],r);
+ }
+ return readIndexBySampleIndex[sampleIndex];
+ }
+
+ /**
+ * Transform into a multi-sample HashMap backed {@link PerReadAlleleLikelihoodMap} type.
+ * @return never {@code null}.
+ *
+ * @deprecated
+ *
+ * This method should eventually disappear once we have removed PerReadAlleleLikelihoodMap class completelly.
+ */
+ @Deprecated
+ @SuppressWarnings("all")
+ public Map<String, PerReadAlleleLikelihoodMap> toPerReadAlleleLikelihoodMap() {
+ final int sampleCount = samples.sampleCount();
+ final Map<String, PerReadAlleleLikelihoodMap> result = new HashMap<>(sampleCount);
+ for (int s = 0; s < sampleCount; s++)
+ result.put(samples.sampleAt(s),toPerReadAlleleLikelihoodMap(s));
+ return result;
+ }
+
+ /**
+ * Transform into a single-sample HashMap backed {@link PerReadAlleleLikelihoodMap} type.
+ *
+ * @return never {@code null}.
+ */
+ @Deprecated
+ public PerReadAlleleLikelihoodMap toPerReadAlleleLikelihoodMap(final int sampleIndex) {
+ checkSampleIndex(sampleIndex);
+ final PerReadAlleleLikelihoodMap result = new PerReadAlleleLikelihoodMap();
+ final int alleleCount = alleles.alleleCount();
+ final GATKSAMRecord[] sampleReads = readsBySampleIndex[sampleIndex];
+ final int sampleReadCount = sampleReads.length;
+ for (int a = 0; a < alleleCount; a++) {
+ final A allele = alleles.alleleAt(a);
+ final double[] readLikelihoods = valuesBySampleIndex[sampleIndex][a];
+ for (int r = 0; r < sampleReadCount; r++)
+ result.add(sampleReads[r], allele, readLikelihoods[r]);
+ }
+ return result;
+ }
+
+ /**
+ * Implements a likelihood matrix per sample given its index.
+ */
+ private class SampleMatrix implements Matrix<A> {
+
+ private final int sampleIndex;
+
+ private SampleMatrix(final int sampleIndex) {
+ this.sampleIndex = sampleIndex;
+ }
+
+ @Override
+ public List<GATKSAMRecord> reads() {
+ return sampleReads(sampleIndex);
+ }
+
+ @Override
+ public List<A> alleles() {
+ return ReadLikelihoods.this.alleles();
+ }
+
+ @Override
+ public void set(final int alleleIndex, final int readIndex, final double value) {
+ valuesBySampleIndex[sampleIndex][alleleIndex][readIndex] = value;
+ }
+
+ @Override
+ public double get(final int alleleIndex, final int readIndex) {
+ return valuesBySampleIndex[sampleIndex][alleleIndex][readIndex];
+ }
+
+ @Override
+ public int alleleIndex(final A allele) {
+ return ReadLikelihoods.this.alleleIndex(allele);
+ }
+
+ @Override
+ public int readIndex(final GATKSAMRecord read) {
+ return ReadLikelihoods.this.readIndex(sampleIndex, read);
+ }
+
+ @Override
+ public int alleleCount() {
+ return alleles.alleleCount();
+ }
+
+ @Override
+ public int readCount() {
+ return readsBySampleIndex[sampleIndex].length;
+ }
+
+ @Override
+ public A alleleAt(int alleleIndex) {
+ return ReadLikelihoods.this.alleleAt(alleleIndex);
+ }
+
+ @Override
+ public GATKSAMRecord readAt(final int readIndex) {
+ if (readIndex < 0)
+ throw new IllegalArgumentException("the read-index cannot be negative");
+ final GATKSAMRecord[] sampleReads = readsBySampleIndex[sampleIndex];
+ if (readIndex >= sampleReads.length)
+ throw new IllegalArgumentException("the read-index is beyond the read count of the sample");
+ return sampleReads[readIndex];
+ }
+
+ @Override
+ public void copyAlleleLikelihoods(final int alleleIndex, final double[] dest, final int offset) {
+ System.arraycopy(valuesBySampleIndex[sampleIndex][alleleIndex],0,dest,offset,readCount());
+ }
+ }
+
+ /**
+ * Checks whether the provide sample index is valid.
+ * <p>
+ * If not, it throws an exception.
+ * </p>
+ * @param sampleIndex the target sample index.
+ *
+ * @throws IllegalArgumentException if {@code sampleIndex} is invalid, i.e. outside the range [0,{@link #sampleCount}).
+ */
+ private void checkSampleIndex(final int sampleIndex) {
+ if (sampleIndex < 0 || sampleIndex >= samples.sampleCount())
+ throw new IllegalArgumentException("invalid sample index: " + sampleIndex);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/EventMap.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/EventMap.java
new file mode 100644
index 0000000..e5eee12
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/EventMap.java
@@ -0,0 +1,423 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.haplotype;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.sam.AlignmentUtils;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+
+import java.util.*;
+
+/**
+ * Extract simple VariantContext events from a single haplotype
+ *
+ * User: depristo
+ * Date: 3/27/13
+ * Time: 8:35 AM
+ */
+public class EventMap extends TreeMap<Integer, VariantContext> {
+ private final static Logger logger = Logger.getLogger(EventMap.class);
+ protected final static int MIN_NUMBER_OF_EVENTS_TO_COMBINE_INTO_BLOCK_SUBSTITUTION = 3;
+ private static final int MAX_EVENTS_PER_HAPLOTYPE = 3;
+ private static final int MAX_INDELS_PER_HAPLOTYPE = 2;
+ public final static Allele SYMBOLIC_UNASSEMBLED_EVENT_ALLELE = Allele.create("<UNASSEMBLED_EVENT>", false);
+
+ private final Haplotype haplotype;
+ private final byte[] ref;
+ private final GenomeLoc refLoc;
+ private final String sourceNameToAdd;
+
+ public EventMap(final Haplotype haplotype, final byte[] ref, final GenomeLoc refLoc, final String sourceNameToAdd) {
+ super();
+ this.haplotype = haplotype;
+ this.ref = ref;
+ this.refLoc = refLoc;
+ this.sourceNameToAdd = sourceNameToAdd;
+
+ processCigarForInitialEvents();
+ }
+
+ /**
+ * For testing. Let's you set up a explicit configuration without having to process a haplotype and reference
+ * @param stateForTesting
+ */
+ public EventMap(final Collection<VariantContext> stateForTesting) {
+ haplotype = null;
+ ref = null;
+ refLoc = null;
+ sourceNameToAdd = null;
+ for ( final VariantContext vc : stateForTesting )
+ addVC(vc);
+ }
+
+ protected void processCigarForInitialEvents() {
+ final Cigar cigar = haplotype.getCigar();
+ final byte[] alignment = haplotype.getBases();
+
+ int refPos = haplotype.getAlignmentStartHapwrtRef();
+ if( refPos < 0 ) {
+ return;
+ } // Protection against SW failures
+
+ final List<VariantContext> proposedEvents = new ArrayList<>();
+
+ int alignmentPos = 0;
+
+ for( int cigarIndex = 0; cigarIndex < cigar.numCigarElements(); cigarIndex++ ) {
+ final CigarElement ce = cigar.getCigarElement(cigarIndex);
+ final int elementLength = ce.getLength();
+ switch( ce.getOperator() ) {
+ case I:
+ {
+ if( refPos > 0 ) { // protect against trying to create insertions/deletions at the beginning of a contig
+ final List<Allele> insertionAlleles = new ArrayList<Allele>();
+ final int insertionStart = refLoc.getStart() + refPos - 1;
+ final byte refByte = ref[refPos-1];
+ if( BaseUtils.isRegularBase(refByte) ) {
+ insertionAlleles.add( Allele.create(refByte, true) );
+ }
+ if( cigarIndex == 0 || cigarIndex == cigar.getCigarElements().size() - 1 ) {
+ // if the insertion isn't completely resolved in the haplotype, skip it
+ // note this used to emit SYMBOLIC_UNASSEMBLED_EVENT_ALLELE but that seems dangerous
+ } else {
+ byte[] insertionBases = new byte[]{};
+ insertionBases = ArrayUtils.add(insertionBases, ref[refPos - 1]); // add the padding base
+ insertionBases = ArrayUtils.addAll(insertionBases, Arrays.copyOfRange(alignment, alignmentPos, alignmentPos + elementLength));
+ if( BaseUtils.isAllRegularBases(insertionBases) ) {
+ insertionAlleles.add( Allele.create(insertionBases, false) );
+ }
+ }
+ if( insertionAlleles.size() == 2 ) { // found a proper ref and alt allele
+ proposedEvents.add(new VariantContextBuilder(sourceNameToAdd, refLoc.getContig(), insertionStart, insertionStart, insertionAlleles).make());
+ }
+ }
+ alignmentPos += elementLength;
+ break;
+ }
+ case S:
+ {
+ alignmentPos += elementLength;
+ break;
+ }
+ case D:
+ {
+ if( refPos > 0 ) { // protect against trying to create insertions/deletions at the beginning of a contig
+ final byte[] deletionBases = Arrays.copyOfRange( ref, refPos - 1, refPos + elementLength ); // add padding base
+ final List<Allele> deletionAlleles = new ArrayList<Allele>();
+ final int deletionStart = refLoc.getStart() + refPos - 1;
+ final byte refByte = ref[refPos-1];
+ if( BaseUtils.isRegularBase(refByte) && BaseUtils.isAllRegularBases(deletionBases) ) {
+ deletionAlleles.add( Allele.create(deletionBases, true) );
+ deletionAlleles.add( Allele.create(refByte, false) );
+ proposedEvents.add(new VariantContextBuilder(sourceNameToAdd, refLoc.getContig(), deletionStart, deletionStart + elementLength, deletionAlleles).make());
+ }
+ }
+ refPos += elementLength;
+ break;
+ }
+ case M:
+ case EQ:
+ case X:
+ {
+ for( int iii = 0; iii < elementLength; iii++ ) {
+ final byte refByte = ref[refPos];
+ final byte altByte = alignment[alignmentPos];
+ if( refByte != altByte ) { // SNP!
+ if( BaseUtils.isRegularBase(refByte) && BaseUtils.isRegularBase(altByte) ) {
+ final List<Allele> snpAlleles = new ArrayList<Allele>();
+ snpAlleles.add( Allele.create( refByte, true ) );
+ snpAlleles.add( Allele.create( altByte, false ) );
+ proposedEvents.add(new VariantContextBuilder(sourceNameToAdd, refLoc.getContig(), refLoc.getStart() + refPos, refLoc.getStart() + refPos, snpAlleles).make());
+ }
+ }
+ refPos++;
+ alignmentPos++;
+ }
+ break;
+ }
+ case N:
+ case H:
+ case P:
+ default:
+ throw new ReviewedGATKException( "Unsupported cigar operator created during SW alignment: " + ce.getOperator() );
+ }
+ }
+
+ for ( final VariantContext proposedEvent : proposedEvents )
+ addVC(proposedEvent, true);
+ }
+
+ /**
+ * Add VariantContext vc to this map, merging events with the same start sites if necessary
+ * @param vc the variant context to add
+ */
+ protected void addVC(final VariantContext vc) {
+ addVC(vc, true);
+ }
+
+ /**
+ * Add VariantContext vc to this map
+ * @param vc the variant context to add
+ * @param merge should we attempt to merge it with an already existing element, or should we throw an error in that case?
+ */
+ protected void addVC(final VariantContext vc, final boolean merge) {
+ if ( vc == null ) throw new IllegalArgumentException("vc cannot be null");
+
+ if ( containsKey(vc.getStart()) ) {
+ if ( merge ) {
+ final VariantContext prev = get(vc.getStart());
+ put(vc.getStart(), makeBlock(prev, vc));
+ } else {
+ throw new IllegalStateException("Will not merge previously bound variant contexts as merge is false at " + vc);
+ }
+ } else
+ put(vc.getStart(), vc);
+ }
+
+ /**
+ * Create a block substitution out of two variant contexts that start at the same position
+ *
+ * vc1 can be SNP, and vc2 can then be either a insertion or deletion.
+ * If vc1 is an indel, then vc2 must be the opposite type (vc1 deletion => vc2 must be an insertion)
+ *
+ * @param vc1 the first variant context we want to merge
+ * @param vc2 the second
+ * @return a block substitution that represents the composite substitution implied by vc1 and vc2
+ */
+ protected VariantContext makeBlock(final VariantContext vc1, final VariantContext vc2) {
+ if ( vc1.getStart() != vc2.getStart() ) throw new IllegalArgumentException("vc1 and 2 must have the same start but got " + vc1 + " and " + vc2);
+ if ( ! vc1.isBiallelic() ) throw new IllegalArgumentException("vc1 must be biallelic");
+ if ( ! vc1.isSNP() ) {
+ if ( ! ((vc1.isSimpleDeletion() && vc2.isSimpleInsertion()) || (vc1.isSimpleInsertion() && vc2.isSimpleDeletion())))
+ throw new IllegalArgumentException("Can only merge single insertion with deletion (or vice versa) but got " + vc1 + " merging with " + vc2);
+ } else if ( vc2.isSNP() ) {
+ throw new IllegalArgumentException("vc1 is " + vc1 + " but vc2 is a SNP, which implies there's been some terrible bug in the cigar " + vc2);
+ }
+
+ final Allele ref, alt;
+ final VariantContextBuilder b = new VariantContextBuilder(vc1);
+ if ( vc1.isSNP() ) {
+ // we have to repair the first base, so SNP case is special cased
+ if ( vc1.getReference().equals(vc2.getReference()) ) {
+ // we've got an insertion, so we just update the alt to have the prev alt
+ ref = vc1.getReference();
+ alt = Allele.create(vc1.getAlternateAllele(0).getDisplayString() + vc2.getAlternateAllele(0).getDisplayString().substring(1), false);
+ } else {
+ // we're dealing with a deletion, so we patch the ref
+ ref = vc2.getReference();
+ alt = vc1.getAlternateAllele(0);
+ b.stop(vc2.getEnd());
+ }
+ } else {
+ final VariantContext insertion = vc1.isSimpleInsertion() ? vc1 : vc2;
+ final VariantContext deletion = vc1.isSimpleInsertion() ? vc2 : vc1;
+ ref = deletion.getReference();
+ alt = insertion.getAlternateAllele(0);
+ b.stop(deletion.getEnd());
+ }
+
+ return b.alleles(Arrays.asList(ref, alt)).make();
+ }
+
+ // TODO -- warning this is an O(N^3) algorithm because I'm just lazy. If it's valuable we need to reengineer it
+ @Requires("getNumberOfEvents() > 0")
+ protected void replaceClumpedEventsWithBlockSubstitutions() {
+ if ( getNumberOfEvents() >= MIN_NUMBER_OF_EVENTS_TO_COMBINE_INTO_BLOCK_SUBSTITUTION) {
+ int lastStart = -1;
+ for ( boolean foundOne = true; foundOne; ) {
+ foundOne = false;
+ for ( final VariantContext vc : getVariantContexts() ) {
+ if ( vc.getStart() > lastStart ) {
+ lastStart = vc.getStart();
+ final List<VariantContext> neighborhood = getNeighborhood(vc, 10);
+ if ( updateToBlockSubstitutionIfBetter(neighborhood) ) {
+ foundOne = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ protected boolean updateToBlockSubstitutionIfBetter(final List<VariantContext> neighbors) {
+ if (neighbors.size() < MIN_NUMBER_OF_EVENTS_TO_COMBINE_INTO_BLOCK_SUBSTITUTION)
+ return false;
+ // TODO -- need more tests to decide if this is really so good
+
+ final VariantContext first = neighbors.get(0);
+ final int refStartOffset = first.getStart() - refLoc.getStart();
+ final int refEndOffset = neighbors.get(neighbors.size() - 1).getEnd() - refLoc.getStart();
+
+ final byte[] refBases = Arrays.copyOfRange(ref, refStartOffset, refEndOffset + 1);
+ final byte[] hapBases = AlignmentUtils.getBasesCoveringRefInterval(refStartOffset, refEndOffset, haplotype.getBases(), haplotype.getAlignmentStartHapwrtRef(), haplotype.getCigar());
+
+ final VariantContextBuilder builder = new VariantContextBuilder(first);
+ builder.stop(first.getStart() + refBases.length - 1);
+ builder.alleles(Arrays.asList(Allele.create(refBases, true), Allele.create(hapBases)));
+ final VariantContext block = builder.make();
+
+ // remove all merged events
+ for ( final VariantContext merged : neighbors ) {
+ if ( remove(merged.getStart()) == null )
+ throw new IllegalArgumentException("Expected to remove variant context from the event map but remove said there wasn't any element there: " + merged);
+ }
+
+ // note must be after we remove the previous events as the treeset only allows one key per start
+ logger.info("Transforming into block substitution at " + block);
+ addVC(block, false);
+
+ return true;
+ }
+
+ /**
+ * Get all of the variant contexts starting at leftMost that are within maxBP of each other
+ *
+ * @param leftMost the left most (smallest position) variant context that will start the neighborhood
+ * @param maxBPBetweenEvents the maximum distance in BP between the end of one event the start of the next
+ * to be included the the resulting list
+ * @return a list that contains at least one element (leftMost)
+ */
+ @Requires({"leftMost != null", "maxBPBetweenEvents >= 0"})
+ @Ensures({"result != null", "! result.isEmpty()"})
+ protected List<VariantContext> getNeighborhood(final VariantContext leftMost, final int maxBPBetweenEvents) {
+ final List<VariantContext> neighbors = new LinkedList<VariantContext>();
+
+ VariantContext left = leftMost;
+ for ( final VariantContext vc : getVariantContexts() ) {
+ if ( vc.getStart() < leftMost.getStart() )
+ continue;
+
+ if ( vc.getStart() - left.getEnd() < maxBPBetweenEvents ) {
+ // this vc is within max distance to the end of the left event, so accumulate it
+ neighbors.add(vc);
+ left = vc;
+ }
+ }
+
+ return neighbors;
+ }
+
+ /**
+ * Get the starting positions of events in this event map
+ * @return
+ */
+ public Set<Integer> getStartPositions() {
+ return keySet();
+ }
+
+ /**
+ * Get the variant contexts in order of start position in this event map
+ * @return
+ */
+ public Collection<VariantContext> getVariantContexts() {
+ return values();
+ }
+
+ /**
+ * How many events do we have?
+ * @return
+ */
+ public int getNumberOfEvents() {
+ return size();
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder b = new StringBuilder("EventMap{");
+ for ( final VariantContext vc : getVariantContexts() )
+ b.append(String.format("%s:%d-%d %s,", vc.getChr(), vc.getStart(), vc.getEnd(), vc.getAlleles()));
+ b.append("}");
+ return b.toString();
+ }
+
+ /**
+ * Build event maps for each haplotype, returning the sorted set of all of the starting positions of all
+ * events across all haplotypes
+ *
+ * @param haplotypes a list of haplotypes
+ * @param ref the reference bases
+ * @param refLoc the span of the reference bases
+ * @param debug if true, we'll emit debugging information during this operation
+ * @return a sorted set of start positions of all events among all haplotypes
+ */
+ public static TreeSet<Integer> buildEventMapsForHaplotypes( final List<Haplotype> haplotypes,
+ final byte[] ref,
+ final GenomeLoc refLoc,
+ final boolean debug) {
+ // Using the cigar from each called haplotype figure out what events need to be written out in a VCF file
+ final TreeSet<Integer> startPosKeySet = new TreeSet<Integer>();
+ int hapNumber = 0;
+
+ if( debug ) logger.info("=== Best Haplotypes ===");
+ for( final Haplotype h : haplotypes ) {
+ // Walk along the alignment and turn any difference from the reference into an event
+ h.setEventMap( new EventMap( h, ref, refLoc, "HC" + hapNumber++ ) );
+ startPosKeySet.addAll(h.getEventMap().getStartPositions());
+
+ if( debug ) {
+ logger.info(h.toString());
+ logger.info("> Cigar = " + h.getCigar());
+ logger.info(">> Events = " + h.getEventMap());
+ }
+ }
+
+ return startPosKeySet;
+ }
+
+ private static class VariantContextComparator implements Comparator<VariantContext> {
+ @Override
+ public int compare(VariantContext vc1, VariantContext vc2) {
+ return vc1.getStart() - vc2.getStart();
+ }
+ }
+
+ /**
+ * Get all of the VariantContexts in the event maps for all haplotypes, sorted by their start position
+ * @param haplotypes the set of haplotypes to grab the VCs from
+ * @return a sorted set of variant contexts
+ */
+ public static TreeSet<VariantContext> getAllVariantContexts( final List<Haplotype> haplotypes ) {
+ // Using the cigar from each called haplotype figure out what events need to be written out in a VCF file
+ final TreeSet<VariantContext> vcs = new TreeSet<VariantContext>(new VariantContextComparator());
+
+ for( final Haplotype h : haplotypes ) {
+ vcs.addAll(h.getEventMap().getVariantContexts());
+ }
+
+ return vcs;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/Haplotype.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/Haplotype.java
new file mode 100644
index 0000000..7b31b2a
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/Haplotype.java
@@ -0,0 +1,343 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.haplotype;
+
+import com.google.java.contract.Requires;
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import org.apache.commons.lang.ArrayUtils;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.sam.AlignmentUtils;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+import htsjdk.variant.variantcontext.Allele;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+public class Haplotype extends Allele {
+
+
+ private GenomeLoc genomeLocation = null;
+ private EventMap eventMap = null;
+ private Cigar cigar;
+ private int alignmentStartHapwrtRef;
+ private double score = Double.NaN;
+
+ /**
+ * Main constructor
+ *
+ * @param bases a non-null array of bases
+ * @param isRef is this the reference haplotype?
+ */
+ public Haplotype( final byte[] bases, final boolean isRef ) {
+ super(bases.clone(), isRef);
+ }
+
+ /**
+ * Create a new non-ref haplotype
+ *
+ * @param bases a non-null array of bases
+ */
+ public Haplotype( final byte[] bases ) {
+ this(bases, false);
+ }
+
+ /**
+ * Create a new haplotype with bases
+ *
+ * Requires bases.length == cigar.getReadLength()
+ *
+ * @param bases a non-null array of bases
+ * @param isRef is this the reference haplotype?
+ * @param alignmentStartHapwrtRef offset of this haplotype w.r.t. the reference
+ * @param cigar the cigar that maps this haplotype to the reference sequence
+ */
+ public Haplotype( final byte[] bases, final boolean isRef, final int alignmentStartHapwrtRef, final Cigar cigar) {
+ this(bases, isRef);
+ this.alignmentStartHapwrtRef = alignmentStartHapwrtRef;
+ setCigar(cigar);
+ }
+
+ /**
+ * Copy constructor. Note the ref state of the provided allele is ignored!
+ *
+ * @param allele allele to copy
+ */
+ public Haplotype( final Allele allele ) {
+ super(allele, true);
+ }
+
+ public Haplotype( final byte[] bases, final GenomeLoc loc ) {
+ this(bases, false);
+ this.genomeLocation = loc;
+ }
+
+ /**
+ * Create a new Haplotype derived from this one that exactly spans the provided location
+ *
+ * Note that this haplotype must have a contain a genome loc for this operation to be successful. If no
+ * GenomeLoc is contained than @throws an IllegalStateException
+ *
+ * Also loc must be fully contained within this Haplotype's genomeLoc. If not an IllegalArgumentException is
+ * thrown.
+ *
+ * @param loc a location completely contained within this Haplotype's location
+ * @return a new Haplotype within only the bases spanning the provided location, or null for some reason the haplotype would be malformed if
+ */
+ public Haplotype trim(final GenomeLoc loc) {
+ if ( loc == null ) throw new IllegalArgumentException("Loc cannot be null");
+ if ( genomeLocation == null ) throw new IllegalStateException("Cannot trim a Haplotype without containing GenomeLoc");
+ if ( ! genomeLocation.containsP(loc) ) throw new IllegalArgumentException("Can only trim a Haplotype to a containing span. My loc is " + genomeLocation + " but wanted trim to " + loc);
+ if ( getCigar() == null ) throw new IllegalArgumentException("Cannot trim haplotype without a cigar " + this);
+
+ final int newStart = loc.getStart() - this.genomeLocation.getStart();
+ final int newStop = newStart + loc.size() - 1;
+ final byte[] newBases = AlignmentUtils.getBasesCoveringRefInterval(newStart, newStop, getBases(), 0, getCigar());
+ final Cigar newCigar = AlignmentUtils.trimCigarByReference(getCigar(), newStart, newStop);
+
+ if ( newBases == null || AlignmentUtils.startsOrEndsWithInsertionOrDeletion(newCigar) )
+ // we cannot meaningfully chop down the haplotype, so return null
+ return null;
+
+ final Haplotype ret = new Haplotype(newBases, isReference());
+ ret.setCigar(newCigar);
+ ret.setGenomeLocation(loc);
+ ret.setAlignmentStartHapwrtRef(newStart + getAlignmentStartHapwrtRef());
+ return ret;
+ }
+
+ @Override
+ public boolean equals( Object h ) {
+ return h instanceof Haplotype && Arrays.equals(getBases(), ((Haplotype) h).getBases());
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(getBases());
+ }
+
+ public EventMap getEventMap() {
+ return eventMap;
+ }
+
+ public void setEventMap( final EventMap eventMap ) {
+ this.eventMap = eventMap;
+ }
+
+ @Override
+ public String toString() {
+ return getDisplayString();
+ }
+
+ /**
+ * Get the span of this haplotype (may be null)
+ * @return a potentially null genome loc
+ */
+ public GenomeLoc getGenomeLocation() {
+ return genomeLocation;
+ }
+
+ public void setGenomeLocation(GenomeLoc genomeLocation) {
+ this.genomeLocation = genomeLocation;
+ }
+
+ public long getStartPosition() {
+ return genomeLocation.getStart();
+ }
+
+ public long getStopPosition() {
+ return genomeLocation.getStop();
+ }
+
+ public int getAlignmentStartHapwrtRef() {
+ return alignmentStartHapwrtRef;
+ }
+
+ public void setAlignmentStartHapwrtRef( final int alignmentStartHapwrtRef ) {
+ this.alignmentStartHapwrtRef = alignmentStartHapwrtRef;
+ }
+
+ /**
+ * Get the cigar for this haplotype. Note that the cigar is guaranteed to be consolidated
+ * in that multiple adjacent equal operates will have been merged
+ * @return the cigar of this haplotype
+ */
+ public Cigar getCigar() {
+ return cigar;
+ }
+
+ /**
+ * Get the haplotype cigar extended by padSize M at the tail, consolidated into a clean cigar
+ *
+ * @param padSize how many additional Ms should be appended to the end of this cigar. Must be >= 0
+ * @return a newly allocated Cigar that consolidate(getCigar + padSize + M)
+ */
+ public Cigar getConsolidatedPaddedCigar(final int padSize) {
+ if ( padSize < 0 ) throw new IllegalArgumentException("padSize must be >= 0 but got " + padSize);
+ final Cigar extendedHaplotypeCigar = new Cigar(getCigar().getCigarElements());
+ if ( padSize > 0 ) extendedHaplotypeCigar.add(new CigarElement(padSize, CigarOperator.M));
+ return AlignmentUtils.consolidateCigar(extendedHaplotypeCigar);
+ }
+
+ /**
+ * Set the cigar of this haplotype to cigar.
+ *
+ * Note that this function consolidates the cigar, so that 1M1M1I1M1M => 2M1I2M
+ *
+ * @param cigar a cigar whose readLength == length()
+ */
+ public void setCigar( final Cigar cigar ) {
+ this.cigar = AlignmentUtils.consolidateCigar(cigar);
+ if ( this.cigar.getReadLength() != length() )
+ throw new IllegalArgumentException("Read length " + length() + " not equal to the read length of the cigar " + cigar.getReadLength() + " " + this.cigar);
+ }
+
+ @Requires({"refInsertLocation >= 0"})
+ public Haplotype insertAllele( final Allele refAllele, final Allele altAllele, final int refInsertLocation, final int genomicInsertLocation ) {
+ // refInsertLocation is in ref haplotype offset coordinates NOT genomic coordinates
+ final int haplotypeInsertLocation = ReadUtils.getReadCoordinateForReferenceCoordinate(alignmentStartHapwrtRef, cigar, refInsertLocation, ReadUtils.ClippingTail.RIGHT_TAIL, true);
+ final byte[] myBases = this.getBases();
+ if( haplotypeInsertLocation == -1 || haplotypeInsertLocation + refAllele.length() >= myBases.length ) { // desired change falls inside deletion so don't bother creating a new haplotype
+ return null;
+ }
+
+ byte[] newHaplotypeBases = new byte[]{};
+ newHaplotypeBases = ArrayUtils.addAll(newHaplotypeBases, ArrayUtils.subarray(myBases, 0, haplotypeInsertLocation)); // bases before the variant
+ newHaplotypeBases = ArrayUtils.addAll(newHaplotypeBases, altAllele.getBases()); // the alt allele of the variant
+ newHaplotypeBases = ArrayUtils.addAll(newHaplotypeBases, ArrayUtils.subarray(myBases, haplotypeInsertLocation + refAllele.length(), myBases.length)); // bases after the variant
+ return new Haplotype(newHaplotypeBases);
+ }
+
+ public static LinkedHashMap<Allele,Haplotype> makeHaplotypeListFromAlleles(final List<Allele> alleleList,
+ final int startPos,
+ final ReferenceContext ref,
+ final int haplotypeSize,
+ final int numPrefBases) {
+
+ LinkedHashMap<Allele,Haplotype> haplotypeMap = new LinkedHashMap<Allele,Haplotype>();
+
+ Allele refAllele = null;
+
+ for (Allele a:alleleList) {
+ if (a.isReference()) {
+ refAllele = a;
+ break;
+ }
+ }
+
+ if (refAllele == null)
+ throw new ReviewedGATKException("BUG: no ref alleles in input to makeHaplotypeListfrom Alleles at loc: "+ startPos);
+
+ final byte[] refBases = ref.getBases();
+
+ final int startIdxInReference = 1 + startPos - numPrefBases - ref.getWindow().getStart();
+ final String basesBeforeVariant = new String(Arrays.copyOfRange(refBases, startIdxInReference, startIdxInReference + numPrefBases));
+
+ // protect against long events that overrun available reference context
+ final int startAfter = Math.min(startIdxInReference + numPrefBases + refAllele.getBases().length - 1, refBases.length);
+ final String basesAfterVariant = new String(Arrays.copyOfRange(refBases, startAfter, refBases.length));
+
+ // Create location for all haplotypes
+ final int startLoc = ref.getWindow().getStart() + startIdxInReference;
+ final int stopLoc = startLoc + haplotypeSize-1;
+
+ final GenomeLoc locus = ref.getGenomeLocParser().createGenomeLoc(ref.getLocus().getContig(),startLoc,stopLoc);
+
+ for (final Allele a : alleleList) {
+
+ final byte[] alleleBases = a.getBases();
+ // use string concatenation
+ String haplotypeString = basesBeforeVariant + new String(Arrays.copyOfRange(alleleBases, 1, alleleBases.length)) + basesAfterVariant;
+ haplotypeString = haplotypeString.substring(0,haplotypeSize);
+
+ haplotypeMap.put(a,new Haplotype(haplotypeString.getBytes(), locus));
+ }
+
+ return haplotypeMap;
+ }
+
+ private static class Event {
+ public Allele ref;
+ public Allele alt;
+ public int pos;
+
+ public Event( final Allele ref, final Allele alt, final int pos ) {
+ this.ref = ref;
+ this.alt = alt;
+ this.pos = pos;
+ }
+ }
+
+ /**
+ * Get the score (an estimate of the support) of this haplotype
+ * @return a double, where higher values are better
+ */
+ public double getScore() {
+ return score;
+ }
+
+ /**
+ * Set the score (an estimate of the support) of this haplotype.
+ *
+ * Note that if this is the reference haplotype it is always given Double.MAX_VALUE score
+ *
+ * @param score a double, where higher values are better
+ */
+ public void setScore(double score) {
+ this.score = score;
+ }
+
+ /**
+ * Comparator used to sort haplotypes, alphanumerically.
+ *
+ * <p>
+ * If one haplotype is the prefix of the other, the shorter one comes first.
+ * </p>
+ */
+ public static final Comparator<Haplotype> ALPHANUMERICAL_COMPARATOR = new Comparator<Haplotype>() {
+
+ @Override
+ public int compare(final Haplotype o1, final Haplotype o2) {
+ if (o1 == o2)
+ return 0;
+ final byte[] bases1 = o1.getBases();
+ final byte[] bases2 = o2.getBases();
+ final int iLimit = Math.min(bases1.length, bases2.length);
+ for (int i = 0; i < iLimit; i++) {
+ final int cmp = Byte.compare(bases1[i], bases2[i]);
+ if (cmp != 0) return cmp;
+ }
+ if (bases1.length == bases2.length) return 0;
+ return (bases1.length > bases2.length) ? -1 : 1; // is a bit better to get the longest haplotypes first.
+ }
+ };
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeBaseComparator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeBaseComparator.java
new file mode 100644
index 0000000..8d1dfff
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeBaseComparator.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.haplotype;
+
+import java.util.Comparator;
+
+/**
+ * Compares two haplotypes in the lexicographic order of their bases
+ *
+ * User: depristo
+ * Date: 3/29/13
+ * Time: 11:09 AM
+ */
+public class HaplotypeBaseComparator implements Comparator<Haplotype> {
+ @Override
+ public int compare( final Haplotype hap1, final Haplotype hap2 ) {
+ return hap1.getBaseString().compareTo(hap2.getBaseString());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeScoreComparator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeScoreComparator.java
new file mode 100644
index 0000000..7818d3e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeScoreComparator.java
@@ -0,0 +1,39 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.haplotype;
+
+import java.util.Comparator;
+
+/**
+ * A comparator that sorts haplotypes in decreasing order of score, so that the best supported
+ * haplotypes are at the top
+ */
+public class HaplotypeScoreComparator implements Comparator<Haplotype> {
+ @Override
+ public int compare(Haplotype o1, Haplotype o2) {
+ return -1 * Double.valueOf(o1.getScore()).compareTo(o2.getScore());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeSizeAndBaseComparator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeSizeAndBaseComparator.java
new file mode 100644
index 0000000..4818068
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeSizeAndBaseComparator.java
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.haplotype;
+
+import java.util.Comparator;
+
+/**
+ * Compares two haplotypes first by their lengths and then by lexicographic order of their bases.
+ *
+ * User: btaylor
+ * Date: 8/1/13
+ * Time: 11:09 AM
+ */
+public class HaplotypeSizeAndBaseComparator implements Comparator<Haplotype> {
+ @Override
+ public int compare( final Haplotype hap1, final Haplotype hap2 ) {
+ if (hap1.getBases().length < hap2.getBases().length)
+ return -1;
+ else if (hap1.getBases().length > hap2.getBases().length)
+ return 1;
+ else
+ return hap1.getBaseString().compareTo(hap2.getBaseString());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ApplicationDetails.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ApplicationDetails.java
new file mode 100644
index 0000000..a0c7afb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ApplicationDetails.java
@@ -0,0 +1,95 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+import org.broadinstitute.gatk.utils.classloader.JVMUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Contains details additional details that the program can
+ * supply about itself.
+ *
+ * @author hanna
+ * @version 0.1
+ */
+
+public class ApplicationDetails {
+ /**
+ * Retrieve key information about the application (name, who to contact for support, etc.).
+ */
+ final List<String> applicationHeader;
+
+ /**
+ * Stores additional attribution for a given walker.
+ */
+ final List<String> attribution;
+
+ /**
+ * Extract details covering exactly how to run this executable.
+ */
+ final String runningInstructions;
+
+ /**
+ * Additional help particular to this command-line application.
+ */
+ final String additionalHelp;
+
+ public ApplicationDetails( List<String> applicationHeader, List<String> attribution, String runningInstructions, String additionalHelp ) {
+ this.applicationHeader = applicationHeader;
+ this.attribution = attribution;
+ this.runningInstructions = runningInstructions;
+ this.additionalHelp = additionalHelp;
+ }
+
+ public static List<String> createDefaultHeader(Class<? extends CommandLineProgram> application) {
+ return Collections.singletonList("Program Name: " + application.getName());
+ }
+
+ public static String createDefaultRunningInstructions(Class<? extends CommandLineProgram> application) {
+ // Default implementation to find a command line that makes sense.
+ // If the user is running from a jar, return '-jar <jarname>'; otherwise
+ // return the full class name.
+ String runningInstructions = null;
+ try {
+ runningInstructions = JVMUtils.getLocationFor( application ).getName();
+ }
+ catch( IOException ex ) {
+ throw new ReviewedGATKException("Unable to determine running instructions", ex);
+ }
+
+ if( runningInstructions.endsWith(".jar") )
+ runningInstructions = String.format("-jar %s", runningInstructions);
+ else
+ runningInstructions = application.getName();
+
+ return runningInstructions;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocletUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocletUtils.java
new file mode 100644
index 0000000..324fcfc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocletUtils.java
@@ -0,0 +1,76 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import com.sun.javadoc.FieldDoc;
+import com.sun.javadoc.PackageDoc;
+import com.sun.javadoc.ProgramElementDoc;
+import org.broadinstitute.gatk.utils.classloader.JVMUtils;
+
+import java.lang.reflect.Field;
+
+/**
+ * Methods in the class must ONLY be used by doclets, since the com.sun.javadoc.* classes are not
+ * available on all systems, and we don't want the GATK proper to depend on them.
+ */
+public class DocletUtils {
+
+ protected static boolean assignableToClass(ProgramElementDoc classDoc, Class lhsClass, boolean requireConcrete) {
+ try {
+ Class type = getClassForDoc(classDoc);
+ return lhsClass.isAssignableFrom(type) && (!requireConcrete || JVMUtils.isConcrete(type));
+ } catch (Throwable t) {
+ // Ignore errors.
+ return false;
+ }
+ }
+
+ protected static Class getClassForDoc(ProgramElementDoc doc) throws ClassNotFoundException {
+ return Class.forName(getClassName(doc));
+ }
+
+ protected static Field getFieldForFieldDoc(FieldDoc fieldDoc) {
+ try {
+ Class clazz = getClassForDoc(fieldDoc.containingClass());
+ return JVMUtils.findField(clazz, fieldDoc.name());
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Reconstitute the class name from the given class JavaDoc object.
+ *
+ * @param doc the Javadoc model for the given class.
+ * @return The (string) class name of the given class.
+ */
+ protected static String getClassName(ProgramElementDoc doc) {
+ PackageDoc containingPackage = doc.containingPackage();
+ return containingPackage.name().length() > 0 ?
+ String.format("%s.%s", containingPackage.name(), doc.name()) :
+ String.format("%s", doc.name());
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocumentedGATKFeature.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocumentedGATKFeature.java
new file mode 100644
index 0000000..eed95b4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocumentedGATKFeature.java
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import java.lang.annotation.*;
+
+/**
+ * An annotation to identify a class as a GATK capability for documentation
+ *
+ * @author depristo
+ */
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface DocumentedGATKFeature {
+ /** Should we actually document this feature, even though it's annotated? */
+ public boolean enable() default true;
+ /** The overall group name (walkers, readfilters) this feature is associated with */
+ public String groupName();
+ /** A human readable summary of the purpose of this group of features */
+ public String summary() default "";
+ /** Are there links to other docs that we should include? CommandLineGATK.class for walkers, for example? */
+ public Class[] extraDocs() default {};
+ /** Who is the go-to developer for operation/documentation issues? */
+ public String gotoDev() default "NA";
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocumentedGATKFeatureHandler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocumentedGATKFeatureHandler.java
new file mode 100644
index 0000000..e81ab21
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocumentedGATKFeatureHandler.java
@@ -0,0 +1,99 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.RootDoc;
+
+import java.io.*;
+import java.util.Set;
+
+/**
+ * Extend this class to provide a documentation handler for GATKdocs
+ */
+public abstract class DocumentedGATKFeatureHandler {
+ private GATKDoclet doclet;
+
+ /**
+ * @return the javadoc RootDoc of this javadoc run
+ */
+ protected RootDoc getRootDoc() {
+ return this.doclet.rootDoc;
+ }
+
+ /** Set the master doclet driving this handler */
+ public void setDoclet(GATKDoclet doclet) {
+ this.doclet = doclet;
+ }
+
+ /**
+ * @return the GATKDoclet driving this documentation run
+ */
+ public GATKDoclet getDoclet() {
+ return doclet;
+ }
+
+ /**
+ * Should return false iff this handler wants GATKDoclet to skip documenting
+ * this ClassDoc.
+ * @param doc that is being considered for inclusion in the docs
+ * @return true if the doclet should document ClassDoc doc
+ */
+ public boolean includeInDocs(ClassDoc doc) { return true; }
+
+ /**
+ * Return the flat filename (no paths) that the handler would like the Doclet to
+ * write out the documentation for ClassDoc doc and its associated Class clazz
+ * @param doc
+ * @param clazz
+ * @return
+ */
+ public String getDestinationFilename(ClassDoc doc, Class clazz) {
+ return GATKDocUtils.phpFilenameForClass(clazz);
+ }
+
+ /**
+ * Return the name of the FreeMarker template we will use to process ClassDoc doc.
+ *
+ * Note this is a flat filename relative to settings/helpTemplates in the GATK source tree
+ * @param doc
+ * @return
+ * @throws IOException
+ */
+ public abstract String getTemplateName(ClassDoc doc) throws IOException;
+
+ /**
+ * Actually generate the documentation map associated with toProcess
+ *
+ * Can use all to provide references and rootDoc for additional information, if necessary.
+ * Implementing methods should end with a call to setHandlerContext on toProcess, as in:
+ *
+ * toProcess.setHandlerContent(summary, rootMap);
+ *
+ * @param toProcess
+ */
+ public abstract void processOne(GATKDocWorkUnit toProcess);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocumentedGATKFeatureObject.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocumentedGATKFeatureObject.java
new file mode 100644
index 0000000..45f0c14
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/DocumentedGATKFeatureObject.java
@@ -0,0 +1,61 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+/**
+ * Documentation unit. Effectively a class version of the DocumentedGATKFeature.
+ * Immutable data structure.
+ *
+ * @author depristo
+ */
+class DocumentedGATKFeatureObject {
+ /** Which class are we documenting. Specific to each class being documented */
+ private final Class classToDoc;
+ /** Are we enabled? */
+ private final boolean enable;
+ private final String groupName, summary, gotoDev;
+ private final Class[] extraDocs;
+
+ public DocumentedGATKFeatureObject(Class classToDoc, final boolean enable, final String groupName, final String summary, final Class[] extraDocs, final String gotoDev) {
+ this.classToDoc = classToDoc;
+ this.enable = enable;
+ this.groupName = groupName;
+ this.summary = summary;
+ this.extraDocs = extraDocs;
+ this.gotoDev = gotoDev;
+ }
+
+ public DocumentedGATKFeatureObject(Class classToDoc, final String groupName, final String summary, final String gotoDev) {
+ this(classToDoc, true, groupName, summary, new Class[]{}, gotoDev);
+ }
+
+ public Class getClassToDoc() { return classToDoc; }
+ public boolean enable() { return enable; }
+ public String groupName() { return groupName; }
+ public String summary() { return summary; }
+ public Class[] extraDocs() { return extraDocs; }
+ public String gotoDev() { return gotoDev; }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ForumAPIUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ForumAPIUtils.java
new file mode 100644
index 0000000..fbf6528
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ForumAPIUtils.java
@@ -0,0 +1,173 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import com.google.gson.Gson;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ForumAPIUtils {
+ /**
+ * How we post to the forum
+ */
+ final private static String ACCESS_TOKEN = "access_token=";
+
+ public static List<String> getPostedTools(String forumKey) {
+ Gson gson = new Gson();
+ List<String> output = new ArrayList<String>();
+
+ String text = httpGet(HelpConstants.GATK_FORUM_API_URL + "categories.json?CategoryIdentifier=tool-bulletin&page=1-100000&" + ACCESS_TOKEN + forumKey);
+
+ APIQuery details = gson.fromJson(text, APIQuery.class);
+ ForumDiscussion[] discussions = details.Discussions;
+
+ for (ForumDiscussion post : discussions) {
+ output.add(post.Name);
+ }
+
+ /*
+ System.out.println(details.isJsonArray());
+ System.out.println(details.isJsonNull());
+ System.out.println(details.isJsonObject());
+ System.out.println(details.isJsonPrimitive());
+
+ JsonArray posted = details.getAsJsonPrimitive().get("Discussions").getAsJsonArray();
+
+ for ( JsonElement post : posted ) {
+ output.add( post.getAsJsonObject().get("Name").getAsString());
+ }
+ */
+ return output;
+ }
+
+
+ private static String httpGet(String urlStr) {
+ String output = "";
+
+ try {
+
+ DefaultHttpClient httpClient = new DefaultHttpClient();
+ HttpGet getRequest = new HttpGet(urlStr);
+ getRequest.addHeader("accept", "application/json");
+
+ HttpResponse response = httpClient.execute(getRequest);
+
+ if (response.getStatusLine().getStatusCode() != 200) {
+ throw new RuntimeException("Failed : HTTP error code : "
+ + response.getStatusLine().getStatusCode());
+ }
+
+ output = IOUtils.toString(response.getEntity().getContent());
+
+ httpClient.getConnectionManager().shutdown();
+
+ } catch (ClientProtocolException e) {
+
+ e.printStackTrace();
+
+ } catch (IOException e) {
+
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+ private static String httpPost(String data, String URL) {
+ try {
+
+ DefaultHttpClient httpClient = new DefaultHttpClient();
+ HttpPost postRequest = new HttpPost(URL);
+
+ StringEntity input = new StringEntity(data);
+ input.setContentType("application/json");
+ postRequest.setEntity(input);
+
+ HttpResponse response = httpClient.execute(postRequest);
+
+ if (response.getStatusLine().getStatusCode() != 200) {
+ throw new RuntimeException("Failed : HTTP error code : "
+ + response.getStatusLine().getStatusCode());
+ }
+
+ BufferedReader br = new BufferedReader(
+ new InputStreamReader((response.getEntity().getContent())));
+
+ String output = "";
+ String line;
+ System.out.println("Output from Server .... \n");
+ while ((line = br.readLine()) != null) {
+ output += (line + '\n');
+ System.out.println(line);
+ }
+
+ br.close();
+ httpClient.getConnectionManager().shutdown();
+ return output;
+
+ } catch (MalformedURLException e) {
+
+ e.printStackTrace();
+
+ } catch (IOException e) {
+
+ e.printStackTrace();
+
+ }
+ return null;
+ }
+
+ public static void postToForum(GATKDocWorkUnit tool, final String forumKey) {
+
+
+ ForumDiscussion post = new ForumDiscussion(tool);
+
+ Gson gson = new Gson();
+
+ String data = gson.toJson(post.getPostData());
+ httpPost(data, HelpConstants.GATK_FORUM_API_URL + "post/discussion.json?" + ACCESS_TOKEN + forumKey);
+
+
+ }
+
+ class APIQuery {
+ ForumDiscussion[] Discussions;
+
+ public APIQuery() {}
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ForumDiscussion.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ForumDiscussion.java
new file mode 100644
index 0000000..7b95b50
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ForumDiscussion.java
@@ -0,0 +1,84 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class ForumDiscussion {
+
+ final private static String POST_TEMPLATE = "<p>A new tool has been released!</p><p>Check out the documentation at <a href='%s'>%s</a>.</p>";
+
+ final int Announce;
+ final String Body;
+ final String Category;
+ final int Closed;
+ final String Format;
+ final String Name;
+ final int Sink;
+ final String Tags;
+ final String Type;
+
+ public ForumDiscussion(String name, String body, String format, String category,
+ String tagsCSV, String type, int closed, int announce, int sink) {
+ this.Name = name;
+ this.Body = body;
+ this.Format = format;
+ this.Category = category;
+ this.Tags = tagsCSV;
+ this.Type = type;
+ this.Closed = closed;
+ this.Announce = announce;
+ this.Sink = sink;
+ }
+
+ public ForumDiscussion(GATKDocWorkUnit tool) {
+ this(tool.name,
+ String.format(POST_TEMPLATE, GATKDocUtils.URL_ROOT_FOR_RELEASE_GATKDOCS + tool.filename, tool.name),
+ "Html", "tool-bulletin", tool.name + "," + tool.group + ",gatkdocs", "Discussion", 0, -1, -1);
+ }
+
+ public Map<String, String> getPostData() {
+ Map<String, String> output = new HashMap<String, String>();
+
+ output.put("Name", Name);
+ output.put("Body", Body);
+ output.put("Format", Format);
+ output.put("Category", Category);
+ if (Tags != null)
+ output.put("Tags", Tags);
+ if (Type != null)
+ output.put("Type", Type);
+ if (Closed != -1)
+ output.put("Closed", Closed == 1 ? "1" : "0");
+ if (Announce != -1)
+ output.put("Announce", Announce == 1 ? "1" : "0");
+ if (Sink != -1)
+ output.put("Sink", Sink == 1 ? "1" : "0");
+
+ return output;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GATKDocUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GATKDocUtils.java
new file mode 100644
index 0000000..72aba4d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GATKDocUtils.java
@@ -0,0 +1,71 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+public class GATKDocUtils {
+ /**
+ * The URL root for RELEASED GATKDOC units
+ */
+ public final static String URL_ROOT_FOR_RELEASE_GATKDOCS = HelpConstants.GATK_DOCS_URL;
+ /**
+ * The URL root for STABLE GATKDOC units //TODO: do sthing with this or remove -- URL goes nowhere
+ */
+ public final static String URL_ROOT_FOR_STABLE_GATKDOCS = "http://iwww.broadinstitute.org/gsa/gatkdocs/stable/";
+ /**
+ * The URL root for UNSTABLE GATKDOC units //TODO: do sthing with this or remove -- URL goes nowhere
+ */
+ public final static String URL_ROOT_FOR_UNSTABLE_GATKDOCS = "http://iwww.broadinstitute.org/gsa/gatkdocs/unstable/";
+
+ /**
+ * Return the filename of the GATKDoc PHP that would be generated for Class. This
+ * does not guarantee that the docs exist, or that docs would actually be generated
+ * for class (might not be annotated for documentation, for example). But if
+ * this class is documented, GATKDocs will write the docs to a file named as returned
+ * by this function.
+ *
+ * @param c
+ * @return
+ */
+ public static String phpFilenameForClass(Class c) {
+ return c.getName().replace(".", "_") + ".php";
+ }
+
+ /**
+ * Returns a full URL http://etc/ linking to the documentation for class (assuming it
+ * exists). Currently points to the RELEASE doc path only. //TODO: do sthing with other paths or remove ?
+ *
+ * @param c
+ * @return
+ */
+ public static String helpLinksToGATKDocs(Class c) {
+ String classPath = phpFilenameForClass(c);
+ StringBuilder b = new StringBuilder();
+ b.append(URL_ROOT_FOR_RELEASE_GATKDOCS).append(classPath);
+ //b.append("stable version: ").append(URL_ROOT_FOR_STABLE_GATKDOCS).append(classPath).append("\n");
+ //b.append("unstable version: ").append(URL_ROOT_FOR_UNSTABLE_GATKDOCS).append(classPath).append("\n");
+ return b.toString();
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GATKDocWorkUnit.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GATKDocWorkUnit.java
new file mode 100644
index 0000000..005d900
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GATKDocWorkUnit.java
@@ -0,0 +1,127 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import com.sun.javadoc.ClassDoc;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Simple collection of all relevant information about something the GATKDoclet can document
+ * <p/>
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: 7/24/11
+ * Time: 7:59 PM
+ */
+class GATKDocWorkUnit implements Comparable<GATKDocWorkUnit> {
+ /**
+ * The class that's being documented
+ */
+ final Class clazz;
+ /**
+ * The name of the thing we are documenting
+ */
+ final String name;
+ /**
+ * the filename where we will be writing the docs for this class
+ */
+ final String filename;
+ /**
+ * The name of the documentation group (e.g., walkers, read filters) class belongs to
+ */
+ final String group;
+ /**
+ * The documentation handler for this class
+ */
+ final DocumentedGATKFeatureHandler handler;
+ /**
+ * The javadoc documentation for clazz
+ */
+ final ClassDoc classDoc;
+ /**
+ * The annotation that lead to this Class being in GATKDoc
+ */
+ final DocumentedGATKFeatureObject annotation;
+ /**
+ * When was this walker built, and what's the absolute version number
+ */
+ final String buildTimestamp, absoluteVersion;
+
+ // set by the handler
+ String summary;
+ Map<String, Object> forTemplate; // this is where the actual doc content gets stored
+
+ public GATKDocWorkUnit(String name, String filename, String group, DocumentedGATKFeatureObject annotation,
+ DocumentedGATKFeatureHandler handler, ClassDoc classDoc, Class clazz,
+ String buildTimestamp, String absoluteVersion) {
+ this.annotation = annotation;
+ this.name = name;
+ this.filename = filename;
+ this.group = group;
+ this.handler = handler;
+ this.classDoc = classDoc;
+ this.clazz = clazz;
+ this.buildTimestamp = buildTimestamp;
+ this.absoluteVersion = absoluteVersion;
+ }
+
+ /**
+ * Called by the GATKDoclet to set handler provided context for this work unit
+ *
+ * @param summary
+ * @param forTemplate
+ */
+ public void setHandlerContent(String summary, Map<String, Object> forTemplate) {
+ this.summary = summary;
+ this.forTemplate = forTemplate;
+ }
+
+ /**
+ * Return a String -> String map suitable for FreeMarker to create an index to this WorkUnit
+ *
+ * @return
+ */
+ public Map<String, String> indexDataMap() {
+ Map<String, String> data = new HashMap<String, String>();
+ data.put("name", name);
+ data.put("summary", summary);
+ data.put("filename", filename);
+ data.put("group", group);
+ return data;
+ }
+
+ /**
+ * Sort in order of the name of this WorkUnit
+ *
+ * @param other
+ * @return
+ */
+ public int compareTo(GATKDocWorkUnit other) {
+ return this.name.compareTo(other.name);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GATKDoclet.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GATKDoclet.java
new file mode 100644
index 0000000..bd03add
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GATKDoclet.java
@@ -0,0 +1,576 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import com.google.gson.ExclusionStrategy;
+import com.google.gson.FieldAttributes;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.annotations.Expose;
+import com.google.gson.stream.JsonWriter;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.RootDoc;
+import freemarker.template.Configuration;
+import freemarker.template.DefaultObjectWrapper;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+import org.apache.commons.io.FileUtils;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.FeatureCodec;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.tools.walkers.qc.DocumentationTest;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Javadoc Doclet that combines javadoc, GATK ParsingEngine annotations, and FreeMarker
+ * templates to produce PHP formatted GATKDocs for walkers
+ * and other classes.
+ * <p/>
+ * This document has the following workflow:
+ * <p/>
+ * 1 -- walk the javadoc hierarchy, looking for class that have the
+ * DocumentedGATKFeature annotation or are in the type hierarchy in the
+ * static list of things to document, and are to be documented
+ * 2 -- construct for each a GATKDocWorkUnit, resulting in the complete
+ * set of things to document
+ * 3 -- for each unit, actually generate a PHP page documenting it
+ * as well as links to related features via their units. Writing
+ * of a specific class PHP is accomplished by a generate DocumentationHandler
+ * 4 -- write out an index of all units, organized by group
+ * 5 -- emit JSON version of GATKDocs using Google GSON (currently incomplete but workable)
+ * <p/>
+ * The documented classes are restricted to only those with @DocumentedGATKFeature
+ * annotation or are in the STATIC_DOCS class.
+ */
+public class GATKDoclet {
+ final protected static Logger logger = Logger.getLogger(GATKDoclet.class);
+
+ /**
+ * Where we find the help FreeMarker templates
+ */
+ final protected static File SETTINGS_DIR = new File("settings/helpTemplates");
+
+ /**
+ * Where we write the GATKDoc PHP directory
+ */
+ final protected static File DESTINATION_DIR = new File("gatkdocs");
+
+ final private static String FORUM_KEY_PATH = "/local/gsa-engineering/gatkdocs_publisher/forum.key";
+ // ----------------------------------------------------------------------
+ //
+ // Global variables that are set on the command line by javadoc
+ //
+ // ----------------------------------------------------------------------
+ protected static File settingsDir = SETTINGS_DIR;
+ protected static File destinationDir = DESTINATION_DIR;
+ protected static String forumKeyPath = FORUM_KEY_PATH;
+ protected static String buildTimestamp = null, absoluteVersion = null;
+ protected static boolean showHiddenFeatures = false;
+
+ protected static boolean testOnly = false;
+
+ /**
+ * Any class that's in this list will be included in the documentation
+ * when the -test argument is provided. Useful for debugging.
+ */
+ private static final List<Class<?>> testOnlyKeepers = Arrays.asList(
+ DocumentationTest.class, CommandLineGATK.class, UserException.class);
+
+ /**
+ * The javadoc root doc
+ */
+ RootDoc rootDoc;
+
+ /**
+ * The set of all things we are going to document
+ */
+ Set<GATKDocWorkUnit> myWorkUnits;
+
+ /**
+ * A static list of DocumentedGATKFeatureObjects. Any class that is as or extends
+ * one of the DocumentedGATKFeatureObjects.clazz of this collection will also
+ * be documented, even if it doesn't have the @DocumentedGATKFeature annotation. Useful
+ * when you want to document things that implement an interface (annotations on java
+ * interfaces aren't inherited) or whose base class isn't under your control (tribble
+ * codecs).
+ */
+ final static Collection<DocumentedGATKFeatureObject> STATIC_DOCS = new ArrayList<DocumentedGATKFeatureObject>();
+
+ static {
+ STATIC_DOCS.add(new DocumentedGATKFeatureObject(FeatureCodec.class,
+ HelpConstants.DOCS_CAT_RODCODECS,
+ "Tribble codecs for reading reference ordered data (ROD) files such as VCF or BED",
+ "NA"));
+ }
+
+ /**
+ * Extracts the contents of certain types of javadoc and adds them to an XML file.
+ *
+ * @param rootDoc The documentation root.
+ * @return Whether the JavaDoc run succeeded.
+ * @throws java.io.IOException if output can't be written.
+ */
+ public static boolean start(RootDoc rootDoc) throws IOException {
+ logger.setLevel(Level.INFO);
+
+ // load arguments
+ for (String[] options : rootDoc.options()) {
+ if (options[0].equals("-settings-dir"))
+ settingsDir = new File(options[1]);
+ if (options[0].equals("-destination-dir"))
+ destinationDir = new File(options[1]);
+ if (options[0].equals("-forum-key-path"))
+ forumKeyPath = options[1];
+ if (options[0].equals("-build-timestamp"))
+ buildTimestamp = options[1];
+ if (options[0].equals("-absolute-version"))
+ absoluteVersion = options[1];
+ if (options[0].equals("-include-hidden"))
+ showHiddenFeatures = true;
+ if (options[0].equals("-test"))
+ testOnly = true;
+ }
+
+ if (!settingsDir.exists())
+ throw new RuntimeException("-settings-dir " + settingsDir.getPath() + " does not exist");
+ else if (!settingsDir.isDirectory())
+ throw new RuntimeException("-settings-dir " + settingsDir.getPath() + " is not a directory");
+
+ // process the docs
+ new GATKDoclet().processDocs(rootDoc);
+
+ return true;
+ }
+
+ /**
+ * Validate the given options against options supported by this doclet.
+ *
+ * @param option Option to validate.
+ * @return Number of potential parameters; 0 if not supported.
+ */
+ public static int optionLength(String option) {
+ if (option.equals("-settings-dir") ||
+ option.equals("-destination-dir") ||
+ option.equals("-forum-key-path") ||
+ option.equals("-build-timestamp") ||
+ option.equals("-absolute-version") ||
+ option.equals("-include-hidden")) {
+ return 2;
+ } else if (option.equals("-test"))
+ return 1;
+ else
+ return 0;
+ }
+
+ /**
+ * Are we supposed to include @Hidden annotations in our documented output?
+ *
+ * @return
+ */
+ public boolean showHiddenFeatures() {
+ return showHiddenFeatures;
+ }
+
+ /**
+ * @param rootDoc
+ */
+ private void processDocs(RootDoc rootDoc) {
+ // setup the global access to the root
+ this.rootDoc = rootDoc;
+
+ try {
+ // print the Version number
+ FileUtils.writeByteArrayToFile(new File(destinationDir + "/current.version.txt"), getSimpleVersion(absoluteVersion).getBytes());
+
+ /* ------------------------------------------------------------------- */
+ /* You should do this ONLY ONCE in the whole application life-cycle: */
+
+ Configuration cfg = new Configuration();
+ // Specify the data source where the template files come from.
+ cfg.setDirectoryForTemplateLoading(settingsDir);
+ // Specify how templates will see the data-model. This is an advanced topic...
+ cfg.setObjectWrapper(new DefaultObjectWrapper());
+
+ myWorkUnits = computeWorkUnits();
+
+ List<Map<String, String>> groups = new ArrayList<Map<String, String>>();
+ Set<String> seenDocumentationFeatures = new HashSet<String>();
+ List<Map<String, String>> data = new ArrayList<Map<String, String>>();
+ for (GATKDocWorkUnit workUnit : myWorkUnits) {
+ data.add(workUnit.indexDataMap());
+ if (!seenDocumentationFeatures.contains(workUnit.annotation.groupName())) {
+ groups.add(toMap(workUnit.annotation));
+ seenDocumentationFeatures.add(workUnit.annotation.groupName());
+ }
+ }
+
+ for (GATKDocWorkUnit workUnit : myWorkUnits) {
+ processDocWorkUnit(cfg, workUnit, groups, data);
+ }
+
+ processIndex(cfg, new ArrayList<GATKDocWorkUnit>(myWorkUnits));
+
+ File forumKeyFile = new File(forumKeyPath);
+ if (forumKeyFile.exists()) {
+ String forumKey = null;
+ // Read in a one-line file so we can do a for loop
+ for (String line : new XReadLines(forumKeyFile))
+ forumKey = line;
+ updateForum(myWorkUnits, forumKey);
+ }
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void updateForum(Set<GATKDocWorkUnit> docWorkUnits, String forumKey) {
+ //first get list of posts that need to be added
+ List<String> old = ForumAPIUtils.getPostedTools(forumKey);
+
+ for (String s : old)
+ System.out.println(s);
+
+ System.out.printf("Forum has %d items%n", old.size());
+ System.out.printf("Docs have %d items%n", docWorkUnits.size());
+
+ List<GATKDocWorkUnit> toAdd = new ArrayList<GATKDocWorkUnit>();
+ for (GATKDocWorkUnit tool : docWorkUnits) {
+ if (!old.contains(tool.name)) {
+ System.out.println("WILL POST: " + tool.name + " TO FORUM");
+ toAdd.add(tool);
+ }
+ }
+
+ //update using list
+ for (GATKDocWorkUnit tool : toAdd) {
+ //if ( tool.name.equals("ApplyRecalibration") )
+ ForumAPIUtils.postToForum(tool, forumKey);
+ }
+ }
+
+ /**
+ * Returns the set of all GATKDocWorkUnits that we are going to generate docs for.
+ *
+ * @return
+ */
+ private Set<GATKDocWorkUnit> computeWorkUnits() {
+ TreeSet<GATKDocWorkUnit> m = new TreeSet<GATKDocWorkUnit>();
+
+ for (ClassDoc doc : rootDoc.classes()) {
+ //logger.debug("Considering " + doc);
+ Class clazz = getClassForClassDoc(doc);
+
+ // don't add anything that's not DocumentationTest if we are in test mode
+ if (clazz != null && testOnly && !testOnlyKeepers.contains(clazz))
+ continue;
+
+ //if ( clazz != null && clazz.getName().equals("org.broadinstitute.gatk.tools.walkers.annotator.AlleleBalance"))
+ // logger.debug("foo");
+
+ DocumentedGATKFeatureObject feature = getFeatureForClassDoc(doc);
+ DocumentedGATKFeatureHandler handler = createHandler(doc, feature);
+ if (handler != null && handler.includeInDocs(doc)) {
+ //logger.info("Generating documentation for class " + doc);
+ String filename = handler.getDestinationFilename(doc, clazz);
+ GATKDocWorkUnit unit = new GATKDocWorkUnit(doc.name(),
+ filename, feature.groupName(), feature, handler, doc, clazz,
+ buildTimestamp, absoluteVersion);
+ m.add(unit);
+ }
+ }
+
+ return m;
+ }
+
+ /**
+ * Create a handler capable of documenting the class doc according to feature. Returns
+ * null if no appropriate handler is found or doc shouldn't be documented at all.
+ *
+ * @param doc
+ * @param feature
+ * @return
+ */
+ private DocumentedGATKFeatureHandler createHandler(ClassDoc doc, DocumentedGATKFeatureObject feature) {
+ if (feature != null) {
+ if (feature.enable()) {
+ DocumentedGATKFeatureHandler handler = new GenericDocumentationHandler();
+ handler.setDoclet(this);
+ return handler;
+ } else {
+ logger.info("Skipping disabled Documentation for " + doc);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the instantiated DocumentedGATKFeatureObject that describes the GATKDoc
+ * structure we will apply to Doc.
+ *
+ * @param doc
+ * @return null if this proves inappropriate or doc shouldn't be documented
+ */
+ private DocumentedGATKFeatureObject getFeatureForClassDoc(ClassDoc doc) {
+ Class<? extends Object> docClass = getClassForClassDoc(doc);
+
+ if (docClass == null)
+ return null; // not annotated so it shouldn't be documented
+
+ if (docClass.isAnnotationPresent(DocumentedGATKFeature.class)) {
+ DocumentedGATKFeature f = docClass.getAnnotation(DocumentedGATKFeature.class);
+ return new DocumentedGATKFeatureObject(docClass, f.enable(), f.groupName(), f.summary(), f.extraDocs(), f.gotoDev());
+ } else {
+ for (DocumentedGATKFeatureObject staticDocs : STATIC_DOCS) {
+ if (staticDocs.getClassToDoc().isAssignableFrom(docClass)) {
+ return new DocumentedGATKFeatureObject(docClass, staticDocs.enable(), staticDocs.groupName(), staticDocs.summary(), staticDocs.extraDocs(), staticDocs.gotoDev());
+ }
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Return the Java class described by the ClassDoc doc
+ *
+ * @param doc
+ * @return
+ */
+ private Class<? extends Object> getClassForClassDoc(ClassDoc doc) {
+ try {
+ // todo -- what do I need the ? extends Object to pass the compiler?
+ return (Class<? extends Object>) DocletUtils.getClassForDoc(doc);
+ } catch (ClassNotFoundException e) {
+ //logger.warn("Couldn't find class for ClassDoc " + doc);
+ // we got a classdoc for a class we can't find. Maybe in a library or something
+ return null;
+ } catch (NoClassDefFoundError e) {
+ return null;
+ } catch (UnsatisfiedLinkError e) {
+ return null; // naughty BWA bindings
+ }
+ }
+
+ /**
+ * Create the php index listing all of the GATKDocs features
+ *
+ * @param cfg
+ * @param indexData
+ * @throws IOException
+ */
+ private void processIndex(Configuration cfg, List<GATKDocWorkUnit> indexData) throws IOException {
+ /* Get or create a template */
+ Template temp = cfg.getTemplate("generic.index.template.html");
+
+ /* Merge data-model with template */
+ Writer out = new OutputStreamWriter(new FileOutputStream(new File(destinationDir + "/index.php")));
+ try {
+ temp.process(groupIndexData(indexData), out);
+ out.flush();
+ } catch (TemplateException e) {
+ throw new ReviewedGATKException("Failed to create GATK documentation", e);
+ }
+ }
+
+ /**
+ * Helpful function to create the php index. Given all of the already run GATKDocWorkUnits,
+ * create the high-level grouping data listing individual features by group.
+ *
+ * @param indexData
+ * @return
+ */
+ private Map<String, Object> groupIndexData(List<GATKDocWorkUnit> indexData) {
+ //
+ // root -> data -> { summary -> y, filename -> z }, etc
+ // -> groups -> group1, group2, etc.
+ Map<String, Object> root = new HashMap<String, Object>();
+
+
+ Collections.sort(indexData);
+
+ List<Map<String, String>> groups = new ArrayList<Map<String, String>>();
+ Set<String> seenDocumentationFeatures = new HashSet<String>();
+ List<Map<String, String>> data = new ArrayList<Map<String, String>>();
+ for (GATKDocWorkUnit workUnit : indexData) {
+ data.add(workUnit.indexDataMap());
+ if (!seenDocumentationFeatures.contains(workUnit.annotation.groupName())) {
+ groups.add(toMap(workUnit.annotation));
+ seenDocumentationFeatures.add(workUnit.annotation.groupName());
+ }
+ }
+
+ //System.out.printf(groups.toString());
+
+ root.put("data", data);
+ root.put("groups", groups);
+ root.put("timestamp", buildTimestamp);
+ root.put("version", absoluteVersion);
+
+ return root;
+ }
+
+ /**
+ * Trivial helper routine that returns the map of name and summary given the annotation
+ * AND adds a super-category so that we can custom-order the categories in the index
+ *
+ * @param annotation
+ * @return
+ */
+ private static final Map<String, String> toMap(DocumentedGATKFeatureObject annotation) {
+ Map<String, String> root = new HashMap<String, String>();
+ root.put("id", annotation.groupName().replaceAll("\\W", ""));
+ root.put("name", annotation.groupName());
+ root.put("summary", annotation.summary());
+
+ /**
+ * Add-on super-category definitions. The assignments depend on parsing the names
+ * defined in HelpConstants.java so be careful of changing anything.
+ * Also, the super-category value strings need to be the same as used in the
+ * Freemarker template. This is all fairly clunky but the best I could do without
+ * making major changes to the DocumentedGATKFeatureObject. Doesn't help that
+ * Freemarker makes any scripting horribly awkward.
+ */
+ final String supercatValue;
+ if (annotation.groupName().endsWith(" Tools")) supercatValue = "tools";
+ else if (annotation.groupName().endsWith(" Utilities")) supercatValue = "utilities";
+ else if (annotation.groupName().startsWith("Engine ")) supercatValue = "engine";
+ else if (annotation.groupName().endsWith(" (DevZone)")) supercatValue = "dev";
+ else supercatValue = "other";
+
+ root.put("supercat", supercatValue);
+
+ return root;
+ }
+
+ /**
+ * Helper function that finding the GATKDocWorkUnit associated with class from among all of the work units
+ *
+ * @param c the class we are looking for
+ * @return the GATKDocWorkUnit whose .clazz.equals(c), or null if none could be found
+ */
+ public final GATKDocWorkUnit findWorkUnitForClass(Class c) {
+ for (final GATKDocWorkUnit unit : this.myWorkUnits)
+ if (unit.clazz.equals(c))
+ return unit;
+ return null;
+ }
+
+ /**
+ * Return the ClassDoc associated with clazz
+ *
+ * @param clazz
+ * @return
+ */
+ public ClassDoc getClassDocForClass(Class clazz) {
+ return rootDoc.classNamed(clazz.getName());
+ }
+
+ /**
+ * High-level function that processes a single DocWorkUnit unit using its handler
+ *
+ * @param cfg
+ * @param unit
+ * @param data
+ * @throws IOException
+ */
+ private void processDocWorkUnit(Configuration cfg, GATKDocWorkUnit unit, List<Map<String, String>> groups, List<Map<String, String>> data)
+ throws IOException {
+ //System.out.printf("Processing documentation for class %s%n", unit.classDoc);
+ unit.handler.processOne(unit);
+ unit.forTemplate.put("groups", groups);
+ unit.forTemplate.put("data", data);
+ // Get or create a template
+ Template temp = cfg.getTemplate(unit.handler.getTemplateName(unit.classDoc));
+
+ // Merge data-model with template
+ File outputPath = new File(destinationDir + "/" + unit.filename);
+ try {
+ Writer out = new OutputStreamWriter(new FileOutputStream(outputPath));
+ temp.process(unit.forTemplate, out);
+ out.flush();
+ } catch (TemplateException e) {
+ throw new ReviewedGATKException("Failed to create GATK documentation", e);
+ }
+
+ // Create GSON-friendly object from unit.forTemplate
+ GSONWorkUnit gsonworkunit = new GSONWorkUnit();
+ gsonworkunit.populate( unit.forTemplate.get("summary").toString(),
+ unit.forTemplate.get("parallel"),
+ unit.forTemplate.get("activeregion"),
+ unit.forTemplate.get("partitiontype").toString(),
+ unit.forTemplate.get("walkertype").toString(),
+ unit.forTemplate.get("gson-arguments"),
+ unit.forTemplate.get("refwindow"),
+ unit.forTemplate.get("description").toString(),
+ unit.forTemplate.get("name").toString(),
+ unit.forTemplate.get("annotinfo").toString(),
+ unit.forTemplate.get("readfilters"),
+ unit.forTemplate.get("downsampling"),
+ unit.forTemplate.get("group").toString(),
+ unit.forTemplate.get("annotfield").toString(),
+ unit.forTemplate.get("annotdescript")
+ );
+
+ // Prepare to write JSON entry to file
+ File outputPathForJSON = new File(destinationDir + "/" + unit.filename + ".json");
+
+ try {
+ BufferedWriter outJSON = new BufferedWriter(new FileWriter(outputPathForJSON));
+ // Convert object to JSON
+ Gson gson = new GsonBuilder()
+ .serializeSpecialFloatingPointValues()
+ .setPrettyPrinting()
+ .create();
+ String json = gson.toJson(gsonworkunit); // was run on unit.forTemplate
+ outJSON.write(json);
+ outJSON.close();
+
+ } catch (Exception e) {
+ throw new ReviewedGATKException("Failed to create JSON entry", e);
+ }
+ }
+
+ private static String getSimpleVersion(String absoluteVersion) {
+ String[] parts = absoluteVersion.split("-");
+
+ // by skipping i=0, there is no trailing separator
+ for (int i = 1; i < 2; i++) {
+ parts[0] = parts[0].concat("-");
+ parts[0] = parts[0].concat(parts[i]);
+ }
+
+ return parts[0];
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GSONArgument.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GSONArgument.java
new file mode 100644
index 0000000..db214b9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GSONArgument.java
@@ -0,0 +1,83 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * GSON-friendly version of the argument bindings
+ */
+public class GSONArgument {
+
+ String summary;
+ String name;
+ String synonyms;
+ String type;
+ String required;
+ String fulltext;
+ String defaultValue;
+ String minValue;
+ String maxValue;
+ String minRecValue;
+ String maxRecValue;
+ String rodTypes;
+ String kind;
+ List<Map<String, Object>> options;
+
+ public void populate( String summary,
+ String name,
+ String synonyms,
+ String type,
+ String required,
+ String fulltext,
+ String defaultValue,
+ String minValue,
+ String maxValue,
+ String minRecValue,
+ String maxRecValue,
+ String rodTypes,
+ String kind,
+ List<Map<String, Object>> options
+ ) {
+ this.summary = summary;
+ this.name = name;
+ this.synonyms = synonyms;
+ this.type = type;
+ this.required = required;
+ this.fulltext = fulltext;
+ this.defaultValue = defaultValue;
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ this.minRecValue = minRecValue;
+ this.maxRecValue = maxRecValue;
+ this.rodTypes = rodTypes;
+ this.kind = kind;
+ this.options = options;
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GSONWorkUnit.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GSONWorkUnit.java
new file mode 100644
index 0000000..c4481c0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GSONWorkUnit.java
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * GSON-friendly version of the GATKDocWorkUnit
+ */
+public class GSONWorkUnit {
+
+ String summary;
+ Object parallel;
+ Object activeregion;
+ String partitiontype;
+ String walkertype;
+ Object arguments;
+ Object refwindow;
+ String description;
+ String name;
+ String annotinfo;
+ Object readfilters;
+ Object downsampling;
+ String group;
+ String annotfield;
+ Object annotdescript;
+
+ public void populate(String summary,
+ Object parallel,
+ Object activeregion,
+ String partitiontype,
+ String walkertype,
+ Object arguments,
+ Object refwindow,
+ String description,
+ String name,
+ String annotinfo,
+ Object readfilters,
+ Object downsampling,
+ String group,
+ String annotfield,
+ Object annotdescript
+ ) {
+ this.summary = summary;
+ this.parallel = parallel;
+ this.activeregion = activeregion;
+ this.partitiontype = partitiontype;
+ this.walkertype = walkertype;
+ this.arguments = arguments;
+ this.refwindow = refwindow;
+ this.description = description;
+ this.name = name;
+ this.annotinfo = annotinfo;
+ this.readfilters = readfilters;
+ this.downsampling = downsampling;
+ this.group = group;
+ this.annotfield = annotfield;
+ this.annotdescript = annotdescript;
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GenericDocumentationHandler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GenericDocumentationHandler.java
new file mode 100644
index 0000000..fea1496
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/GenericDocumentationHandler.java
@@ -0,0 +1,1008 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import com.sun.javadoc.ClassDoc;
+import com.sun.javadoc.FieldDoc;
+import com.sun.javadoc.Tag;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.engine.walkers.*;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.refdata.tracks.FeatureManager;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.GenotypeAnnotation;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.InfoFieldAnnotation;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.classloader.JVMUtils;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ *
+ */
+public class GenericDocumentationHandler extends DocumentedGATKFeatureHandler {
+ private static Logger logger = Logger.getLogger(GenericDocumentationHandler.class);
+
+ /**
+ * The max. length of the longest of --fullName -shortName argument name
+ * before we prefer the shorter option.
+ */
+ private static final int MAX_DISPLAY_NAME = 30;
+
+ /**
+ * The Class we are documenting
+ */
+ private GATKDocWorkUnit toProcess;
+
+ @Override
+ public boolean includeInDocs(ClassDoc doc) {
+ try {
+ Class type = DocletUtils.getClassForDoc(doc);
+ boolean hidden = !getDoclet().showHiddenFeatures() && type.isAnnotationPresent(Hidden.class);
+ return !hidden && JVMUtils.isConcrete(type);
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+
+
+ @Override
+ public String getTemplateName(ClassDoc doc) throws IOException {
+ return "generic.template.html";
+ }
+
+ @Override
+ public void processOne(GATKDocWorkUnit toProcessArg) {
+ this.toProcess = toProcessArg;
+
+ //System.out.printf("%s class %s%n", toProcess.group, toProcess.classDoc);
+ Map<String, Object> root = new HashMap<String, Object>();
+
+ addHighLevelBindings(root);
+ addArgumentBindings(root);
+ addRelatedBindings(root);
+ root.put("group", toProcess.group);
+
+ // Adding in retrieval of peripheral info (rf annotations etc)
+ getClazzAnnotations(toProcess.clazz, root);
+
+ toProcess.setHandlerContent((String) root.get("summary"), root);
+ }
+
+ /**
+ * Add high-level summary information about toProcess to root, such as its
+ * name, summary, description, version, etc.
+ *
+ * @param root
+ */
+ protected void addHighLevelBindings(Map<String, Object> root) {
+ root.put("name", toProcess.classDoc.name());
+
+ // Extract overrides from the doc tags.
+ StringBuilder summaryBuilder = new StringBuilder();
+ for (Tag tag : toProcess.classDoc.firstSentenceTags())
+ summaryBuilder.append(tag.text());
+ root.put("summary", summaryBuilder.toString());
+ root.put("description", toProcess.classDoc.commentText().substring(summaryBuilder.toString().length()));
+ root.put("timestamp", toProcess.buildTimestamp);
+ root.put("version", toProcess.absoluteVersion);
+
+ for (Tag tag : toProcess.classDoc.tags()) {
+ root.put(tag.name(), tag.text());
+ }
+
+ root.put("gotoDev", toProcess.annotation.gotoDev());
+ }
+
+ /**
+ * Add bindings describing related GATK capabilites to toProcess
+ *
+ * @param root
+ */
+ protected void addRelatedBindings(Map<String, Object> root) {
+ List<Map<String, Object>> extraDocsData = new ArrayList<Map<String, Object>>();
+
+ // add in all of the explicitly related items
+ for (final Class extraDocClass : toProcess.annotation.extraDocs()) {
+ final GATKDocWorkUnit otherUnit = getDoclet().findWorkUnitForClass(extraDocClass);
+ if (otherUnit == null)
+ throw new ReviewedGATKException("Requested extraDocs for class without any documentation: " + extraDocClass);
+ extraDocsData.add(
+ new HashMap<String, Object>() {{
+ put("filename", otherUnit.filename);
+ put("name", otherUnit.name);
+ }});
+ }
+ root.put("extradocs", extraDocsData);
+ }
+
+ /**
+ * Add information about all of the arguments available to toProcess to root
+ *
+ * @param root
+ */
+ protected void addArgumentBindings(Map<String, Object> root) {
+ ParsingEngine parsingEngine = createStandardGATKParsingEngine();
+
+ Map<String, List<Map<String, Object>>> args = createArgumentMap();
+ root.put("arguments", args);
+ try {
+ // loop over all of the arguments according to the parsing engine
+ for (final ArgumentSource argumentSource : parsingEngine.extractArgumentSources(DocletUtils.getClassForDoc(toProcess.classDoc))) {
+ ArgumentDefinition argDef = argumentSource.createArgumentDefinitions().get(0);
+ FieldDoc fieldDoc = getFieldDoc(toProcess.classDoc, argumentSource.field.getName());
+ Map<String, Object> argBindings = docForArgument(fieldDoc, argumentSource, argDef);
+ if (!argumentSource.isHidden() || getDoclet().showHiddenFeatures()) {
+ final String kind = docKindOfArg(argumentSource);
+ argBindings.put("kind", kind);
+ // Retrieve default value
+ final Object value = argumentValue(toProcess.clazz, argumentSource);
+ if (value != null) {
+ argBindings.put("defaultValue", prettyPrintValueString(value));
+ } else {
+ argBindings.put("defaultValue", "NA");
+ }
+ // Retrieve min and max / hard and soft value thresholds for numeric args
+ if (value instanceof Number) {
+ if (argumentSource.field.isAnnotationPresent(Argument.class)) {
+ argBindings.put("minValue", argumentSource.field.getAnnotation(Argument.class).minValue());
+ argBindings.put("maxValue", argumentSource.field.getAnnotation(Argument.class).maxValue());
+ if (argumentSource.field.getAnnotation(Argument.class).minRecommendedValue() != Double.NEGATIVE_INFINITY) {
+ argBindings.put("minRecValue", argumentSource.field.getAnnotation(Argument.class).minRecommendedValue());
+ } else {
+ argBindings.put("minRecValue", "NA");
+ }
+ if (argumentSource.field.getAnnotation(Argument.class).maxRecommendedValue() != Double.POSITIVE_INFINITY) {
+ argBindings.put("maxRecValue", argumentSource.field.getAnnotation(Argument.class).maxRecommendedValue());
+ } else {
+ argBindings.put("maxRecValue", "NA");
+ }
+ }
+ } else {
+ argBindings.put("minValue", "NA");
+ argBindings.put("maxValue", "NA");
+ argBindings.put("minRecValue", "NA");
+ argBindings.put("maxRecValue", "NA");
+ argBindings.put("defaultValue", "NA");
+ }
+ // Finalize argument bindings
+ args.get(kind).add(argBindings);
+ args.get("all").add(argBindings);
+ }
+ }
+
+ // sort the arguments
+ for (Map.Entry<String, List<Map<String, Object>>> entry : args.entrySet()) {
+ entry.setValue(sortArguments(entry.getValue()));
+ }
+ // make a GSON-friendly map of arguments -- uses some hacky casting
+ List<GSONArgument> allGSONArgs = new ArrayList<GSONArgument>();
+ for ( Map<String, Object> item : args.get("all")) {
+ GSONArgument itemGSONArg = new GSONArgument();
+
+ itemGSONArg.populate(item.get("summary").toString(),
+ item.get("name").toString(),
+ item.get("synonyms").toString(),
+ item.get("type").toString(),
+ item.get("required").toString(),
+ item.get("fulltext").toString(),
+ item.get("defaultValue").toString(),
+ item.get("minValue").toString(),
+ item.get("maxValue").toString(),
+ item.get("minRecValue").toString(),
+ item.get("maxRecValue").toString(),
+ item.get("rodTypes").toString(),
+ item.get("kind").toString(),
+ (List<Map<String, Object>>)item.get("options")
+ );
+ allGSONArgs.add(itemGSONArg);
+ }
+ root.put("gson-arguments", allGSONArgs);
+
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Return the argument kind (required, advanced, hidden, etc) of this argumentSource
+ *
+ * @param argumentSource
+ * @return
+ */
+ @Requires("argumentSource != null")
+ @Ensures("result != null")
+ private String docKindOfArg(ArgumentSource argumentSource) {
+ if (argumentSource.isRequired()) {
+ if (argumentSource.isInput()) return "required_in";
+ else if (argumentSource.isOutput()) return "required_out";
+ else if (argumentSource.isFlag()) return "required_flag";
+ else return "required_param";
+ }
+ else if (argumentSource.isAdvanced()) {
+ if (argumentSource.isInput()) return "advanced_in";
+ else if (argumentSource.isOutput()) return "advanced_out";
+ else if (argumentSource.isFlag()) return "advanced_flag";
+ else return "advanced_param";
+ }
+ else if (argumentSource.isHidden()) return "hidden";
+ else if (argumentSource.isDeprecated()) return "deprecated";
+ else {
+ if (argumentSource.isInput()) return "optional_in";
+ else if (argumentSource.isOutput()) return "optional_out";
+ else if (argumentSource.isFlag()) return "optional_flag";
+ else return "optional_param";
+ }
+ }
+
+ /**
+ * Attempts to determine the value of argumentSource in an instantiated version of c
+ *
+ * @param c
+ * @param argumentSource
+ * @return value of argumentSource, or null if this isn't possible
+ */
+ @Requires({"c != null", "argumentSource != null"})
+ private Object argumentValue(Class c, ArgumentSource argumentSource) {
+ // get the value of the field
+ // attempt to instantiate the class
+ final Object instance = makeInstanceIfPossible(toProcess.clazz);
+ if (instance != null) {
+ final Object value = getFieldValue(instance, argumentSource.field.getName());
+ if (value != null)
+ return value;
+
+ if (argumentSource.createsTypeDefault()) {
+ try { // handle the case where there's an implicit default
+ return argumentSource.typeDefaultDocString();
+ } catch (ReviewedGATKException e) {
+ ; // failed to create type default, don't worry about it
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Create the argument map for holding class arguments
+ *
+ * @return
+ */
+ private Map<String, List<Map<String, Object>>> createArgumentMap() {
+ Map<String, List<Map<String, Object>>> args = new HashMap<String, List<Map<String, Object>>>();
+ args.put("all", new ArrayList<Map<String, Object>>());
+ args.put("required_in", new ArrayList<Map<String, Object>>());
+ args.put("required_out", new ArrayList<Map<String, Object>>());
+ args.put("required_param", new ArrayList<Map<String, Object>>());
+ args.put("required_flag", new ArrayList<Map<String, Object>>());
+ args.put("optional_in", new ArrayList<Map<String, Object>>());
+ args.put("optional_out", new ArrayList<Map<String, Object>>());
+ args.put("optional_param", new ArrayList<Map<String, Object>>());
+ args.put("optional_flag", new ArrayList<Map<String, Object>>());
+ args.put("advanced_in", new ArrayList<Map<String, Object>>());
+ args.put("advanced_out", new ArrayList<Map<String, Object>>());
+ args.put("advanced_param", new ArrayList<Map<String, Object>>());
+ args.put("advanced_flag", new ArrayList<Map<String, Object>>());
+ args.put("hidden", new ArrayList<Map<String, Object>>());
+ args.put("deprecated", new ArrayList<Map<String, Object>>());
+ return args;
+ }
+
+
+ /**
+ * Sorts the individual argument list in unsorted according to CompareArgumentsByName
+ *
+ * @param unsorted
+ * @return
+ */
+ private List<Map<String, Object>> sortArguments(List<Map<String, Object>> unsorted) {
+ Collections.sort(unsorted, new CompareArgumentsByName());
+ return unsorted;
+ }
+
+ /**
+ * Sort arguments by case-insensitive comparison ignoring the -- and - prefixes
+ */
+ private class CompareArgumentsByName implements Comparator<Map<String, Object>> {
+ public int compare(Map<String, Object> x, Map<String, Object> y) {
+ return elt(x).compareTo(elt(y));
+ }
+
+ private String elt(Map<String, Object> m) {
+ String v = m.get("name").toString().toLowerCase();
+ if (v.startsWith("--"))
+ return v.substring(2);
+ else if (v.startsWith("-"))
+ return v.substring(1);
+ else
+ throw new RuntimeException("Expect to see arguments beginning with at least one -, but found " + v);
+ }
+ }
+
+ /**
+ * Umbrella function that groups the collection of values for specific annotations applied to an
+ * instance of class c. Lists of collected values are added directly to the "toProcess" object.
+ * Requires being able to instantiate the class.
+ *
+ * @param classToProcess the object to instantiate and query for the annotation
+ * @param root the root of the document handler, to which we'll store collected annotations
+ */
+ private void getClazzAnnotations(Class classToProcess, Map<String, Object> root) {
+ //
+ // attempt to instantiate the class
+ final Object instance = makeInstanceIfPossible(classToProcess);
+ if (instance != null) {
+ final Class myClass = instance.getClass();
+ // Get parallelism options
+ final HashSet<HashMap<String, Object>> parallelOptions = getParallelism(myClass, new HashSet<HashMap<String, Object>>());
+ root.put("parallel", parallelOptions);
+ // Get annotation info (what type of annotation, standard etc.)
+ final HashSet<String> annotInfo = getAnnotInfo(myClass, new HashSet<String>());
+ root.put("annotinfo", StringUtils.join(annotInfo, ", "));
+ // Get annotation field (whether it goes in INFO or FORMAT)
+ root.put("annotfield", getAnnotField(myClass));
+ // Get walker type if applicable
+ root.put("walkertype", getWalkerType(myClass));
+ // Get partition type if applicable
+ root.put("partitiontype", getPartitionType(myClass));
+ // Get read filter annotations (ReadFilters) if applicable
+ final HashSet<HashMap<String, Object>> bucket= getReadFilters(myClass, new HashSet<HashMap<String, Object>>());
+ root.put("readfilters", bucket);
+ // Get default downsampling settings
+ final HashMap<String, Object> dsSettings = getDownSamplingSettings(myClass, new HashMap<String, Object>());
+ root.put("downsampling", dsSettings);
+ // Get reference window size settings
+ final HashMap<String, Object> refwindow = getRefWindow(myClass, new HashMap<String, Object>());
+ root.put("refwindow", refwindow);
+ // Get ActiveRegion size settings
+ final HashMap<String, Object> activeRegion = getActiveRegion(myClass, new HashMap<String, Object>());
+ root.put("activeregion", activeRegion);
+ // Get annotation header line description if applicable
+ final Object annotDescriptLines = getAnnotDescript(instance, myClass);
+ root.put("annotdescript", annotDescriptLines);
+
+ // anything else?
+ } else {
+ // put empty items to avoid blowups
+ root.put("parallel", new HashSet<String>());
+ root.put("annotinfo", "");
+ root.put("annotfield", "");
+ root.put("walkertype", "");
+ root.put("partitiontype", "");
+ root.put("readfilters", new HashSet<HashMap<String, Object>>());
+ root.put("downsampling", new HashMap<String, Object>());
+ root.put("refwindow", new HashMap<String, Object>());
+ root.put("activeregion", new HashMap<String, Object>());
+ root.put("annotdescript", new ArrayList<HashMap<String, Object>>());
+ }
+ }
+
+ /**
+ * Utility function that looks up annotation descriptions if applicable.
+ *
+ * @param myClass the class to query
+ * @return a hash map of descriptions, otherwise an empty map
+ */
+ private Object getAnnotDescript(Object instance, Class myClass) {
+ //
+ // Check if the class has the method we want
+ for (Method classMethod : myClass.getMethods()) {
+ if (classMethod.toString().contains("getDescriptions") && classMethod.toString().contains("annotator")) {
+ try {
+ return classMethod.invoke(instance);
+ } catch (IllegalArgumentException e) {
+ } catch (IllegalAccessException e) {
+ } catch (InvocationTargetException e) {
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Utility function that checks which parallelism options are available for an instance of class c.
+ *
+ * @param myClass the class to query for the interfaces
+ * @param parallelOptions an empty HashSet in which to collect the info
+ * @return a hash set of parallelism options, otherwise an empty set
+ */
+ private HashSet<HashMap<String, Object>> getParallelism(Class myClass, HashSet<HashMap<String, Object>> parallelOptions) {
+ //
+ // Retrieve interfaces
+ Class[] implementedInterfaces = myClass.getInterfaces();
+ for (Class intfClass : implementedInterfaces) {
+ final HashMap<String, Object> nugget = new HashMap<String, Object>();
+ if (intfClass.getSimpleName().equals("TreeReducible")) {
+ nugget.put("name", intfClass.getSimpleName());
+ nugget.put("arg", HelpConstants.ARG_TREEREDUCIBLE);
+ nugget.put("link", HelpConstants.CMDLINE_GATK_URL + "#" + HelpConstants.ARG_TREEREDUCIBLE);
+ } else if (intfClass.getSimpleName().equals("NanoSchedulable")) {
+ nugget.put("name", intfClass.getSimpleName());
+ nugget.put("arg", HelpConstants.ARG_NANOSCHEDULABLE);
+ nugget.put("link", HelpConstants.CMDLINE_GATK_URL + "#" + HelpConstants.ARG_NANOSCHEDULABLE);
+ } else {
+ continue;
+ }
+ parallelOptions.add(nugget);
+ }
+ // Look up superclasses recursively
+ final Class mySuperClass = myClass.getSuperclass();
+ if (mySuperClass.getSimpleName().equals("Object")) {
+ return parallelOptions;
+ }
+ return getParallelism(mySuperClass, parallelOptions);
+ }
+
+ /**
+ * Utility function that looks up whether the annotation goes in INFO or FORMAT field.
+ *
+ * @param myClass the class to query for the interfaces
+ * @return a String specifying the annotation field
+ */
+ private final String getAnnotField(Class myClass) {
+ //
+ // Look up superclasses recursively until we find either
+ // GenotypeAnnotation or InfoFieldAnnotation
+ final Class mySuperClass = myClass.getSuperclass();
+ if (mySuperClass == InfoFieldAnnotation.class) {
+ return "INFO (variant-level)";
+ } else if (mySuperClass == GenotypeAnnotation.class) {
+ return "FORMAT (sample genotype-level)";
+ } else if (mySuperClass.getSimpleName().equals("Object")) {
+ return "";
+ }
+ return getAnnotField(mySuperClass);
+ }
+
+ /**
+ * Utility function that determines the annotation type for an instance of class c.
+ *
+ * @param myClass the class to query for the interfaces
+ * @param annotInfo an empty HashSet in which to collect the info
+ * @return a hash set of the annotation types, otherwise an empty set
+ */
+ private HashSet<String> getAnnotInfo(Class myClass, HashSet<String> annotInfo) {
+ //
+ // Retrieve interfaces
+ Class[] implementedInterfaces = myClass.getInterfaces();
+ for (Class intfClass : implementedInterfaces) {
+ if (intfClass.getName().contains("Annotation")) {
+ annotInfo.add(intfClass.getSimpleName());
+ }
+ }
+ // Look up superclasses recursively
+ final Class mySuperClass = myClass.getSuperclass();
+ if (mySuperClass.getSimpleName().equals("Object")) {
+ return annotInfo;
+ }
+ return getAnnotInfo(mySuperClass, annotInfo);
+ }
+
+ /**
+ * Utility function that determines the default downsampling settings for an instance of class c.
+ *
+ * @param myClass the class to query for the settings
+ * @param dsSettings an empty HashMap in which to collect the info
+ * @return a hash set of the downsampling settings, otherwise an empty set
+ */
+ private HashMap<String, Object> getDownSamplingSettings(Class myClass, HashMap<String, Object> dsSettings) {
+ //
+ // Retrieve annotation
+ if (myClass.isAnnotationPresent(Downsample.class)) {
+ final Annotation thisAnnotation = myClass.getAnnotation(Downsample.class);
+ if(thisAnnotation instanceof Downsample) {
+ final Downsample dsAnnotation = (Downsample) thisAnnotation;
+ dsSettings.put("by", dsAnnotation.by().toString());
+ dsSettings.put("to_cov", dsAnnotation.toCoverage());
+ }
+ }
+ return dsSettings;
+ }
+
+ /**
+ * Utility function that determines the reference window size for an instance of class c.
+ *
+ * @param myClass the class to query for the settings
+ * @param refWindow an empty HashMap in which to collect the info
+ * @return a HashMap of the window start and stop, otherwise an empty HashMap
+ */
+ private HashMap<String, Object> getRefWindow(Class myClass, HashMap<String, Object> refWindow) {
+ //
+ // Retrieve annotation
+ if (myClass.isAnnotationPresent(Reference.class)) {
+ final Annotation thisAnnotation = myClass.getAnnotation(Reference.class);
+ if(thisAnnotation instanceof Reference) {
+ final Reference refAnnotation = (Reference) thisAnnotation;
+ refWindow.put("start", refAnnotation.window().start());
+ refWindow.put("stop", refAnnotation.window().stop());
+ }
+ }
+ return refWindow;
+ }
+
+ /**
+ * Utility function that determines the ActiveRegion settings for an instance of class c.
+ *
+ * @param myClass the class to query for the settings
+ * @param activeRegion an empty HashMap in which to collect the info
+ * @return a HashMap of the ActiveRegion parameters, otherwise an empty HashMap
+ */
+ private HashMap<String, Object> getActiveRegion(Class myClass, HashMap<String, Object> activeRegion) {
+ //
+ // Retrieve annotation
+ if (myClass.isAnnotationPresent(ActiveRegionTraversalParameters.class)) {
+ final Annotation thisAnnotation = myClass.getAnnotation(ActiveRegionTraversalParameters.class);
+ if(thisAnnotation instanceof ActiveRegionTraversalParameters) {
+ final ActiveRegionTraversalParameters arAnnotation = (ActiveRegionTraversalParameters) thisAnnotation;
+ activeRegion.put("ext", arAnnotation.extension());
+ activeRegion.put("max", arAnnotation.maxRegion());
+ activeRegion.put("min", arAnnotation.minRegion());
+ }
+ }
+ return activeRegion;
+ }
+
+ /**
+ * Utility function that determines the partition type of an instance of class c.
+ *
+ * @param myClass the class to query for the annotation
+ * @return the partition type if applicable, otherwise an empty string
+ */
+ private String getPartitionType(Class myClass) {
+ //
+ // Retrieve annotation
+ if (myClass.isAnnotationPresent(PartitionBy.class)) {
+ final Annotation thisAnnotation = myClass.getAnnotation(PartitionBy.class);
+ if(thisAnnotation instanceof PartitionBy) {
+ final PartitionBy partAnnotation = (PartitionBy) thisAnnotation;
+ return partAnnotation.value().toString();
+ }
+ }
+ return "";
+ }
+
+ /**
+ * Utility function that determines the type of walker subclassed by an instance of class c.
+ *
+ * @param myClass the class to query for the annotation
+ * @return the type of walker if applicable, otherwise an empty string
+ */
+ private String getWalkerType(Class myClass) {
+ //
+ // Look up superclasses recursively until we find either Walker or Object
+ final Class mySuperClass = myClass.getSuperclass();
+ if (mySuperClass.getSimpleName().equals("Walker")) {
+ return myClass.getSimpleName();
+ } else if (mySuperClass.getSimpleName().equals("Object")) {
+ return "";
+ }
+ return getWalkerType(mySuperClass);
+ }
+
+ /**
+ * Utility function that finds the values of ReadFilters annotation applied to an instance of class c.
+ *
+ * @param myClass the class to query for the annotation
+ * @param bucket a container in which we store the annotations collected
+ * @return a hash set of values, otherwise an empty set
+ */
+ private HashSet<HashMap<String, Object>> getReadFilters(Class myClass, HashSet<HashMap<String, Object>> bucket) {
+ //
+ // Retrieve annotation
+ if (myClass.isAnnotationPresent(ReadFilters.class)) {
+ final Annotation thisAnnotation = myClass.getAnnotation(ReadFilters.class);
+ if(thisAnnotation instanceof ReadFilters) {
+ final ReadFilters rfAnnotation = (ReadFilters) thisAnnotation;
+ for (Class<?> filter : rfAnnotation.value()) {
+ // make hashmap of simplename and url
+ final HashMap<String, Object> nugget = new HashMap<String, Object>();
+ nugget.put("name", filter.getSimpleName());
+ nugget.put("filename", GATKDocUtils.phpFilenameForClass(filter));
+ bucket.add(nugget);
+ }
+ }
+ }
+ // Look up superclasses recursively
+ final Class mySuperClass = myClass.getSuperclass();
+ if (mySuperClass.getSimpleName().equals("Object")) {
+ return bucket;
+ }
+ return getReadFilters(mySuperClass, bucket);
+ }
+
+
+ /**
+ * Utility function that finds the value of fieldName in any fields of ArgumentCollection fields in
+ * instance of class c.
+ *
+ * @param instance the object to query for the field value
+ * @param fieldName the name of the field we are looking for in instance
+ * @return The value assigned to field in the ArgumentCollection, otherwise null
+ */
+ private Object getFieldValue(Object instance, String fieldName) {
+ //
+ // subtle note. If you have a field named X that is an ArgumentCollection that
+ // contains a field X as well, you need only consider fields in the argumentCollection, not
+ // matching the argument itself.
+ //
+ // @ArgumentCollection
+ // protected DbsnpArgumentCollection dbsnp = new DbsnpArgumentCollection();
+ //
+
+ for (Field field : JVMUtils.getAllFields(instance.getClass())) {
+ if (field.isAnnotationPresent(ArgumentCollection.class)) {
+ //System.out.printf("Searching for %s in argument collection field %s%n", fieldName, field);
+ Object fieldValue = JVMUtils.getFieldValue(field, instance);
+ Object value = getFieldValue(fieldValue, fieldName);
+ if (value != null)
+ return value;
+ } else if (field.getName().equals(fieldName)) {
+ return JVMUtils.getFieldValue(field, instance);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Pretty prints value
+ * <p/>
+ * Assumes value != null
+ *
+ * @param value
+ * @return
+ */
+ private Object prettyPrintValueString(Object value) {
+ if (value.getClass().isArray()) {
+ Class type = value.getClass().getComponentType();
+ if (boolean.class.isAssignableFrom(type))
+ return Arrays.toString((boolean[]) value);
+ if (byte.class.isAssignableFrom(type))
+ return Arrays.toString((byte[]) value);
+ if (char.class.isAssignableFrom(type))
+ return Arrays.toString((char[]) value);
+ if (double.class.isAssignableFrom(type))
+ return Arrays.toString((double[]) value);
+ if (float.class.isAssignableFrom(type))
+ return Arrays.toString((float[]) value);
+ if (int.class.isAssignableFrom(type))
+ return Arrays.toString((int[]) value);
+ if (long.class.isAssignableFrom(type))
+ return Arrays.toString((long[]) value);
+ if (short.class.isAssignableFrom(type))
+ return Arrays.toString((short[]) value);
+ if (Object.class.isAssignableFrom(type))
+ return Arrays.toString((Object[]) value);
+ else
+ throw new RuntimeException("Unexpected array type in prettyPrintValue. Value was " + value + " type is " + type);
+ } else if (RodBinding.class.isAssignableFrom(value.getClass())) {
+ // annoying special case to handle the UnBound() constructor
+ return "none";
+ } else if (value instanceof String) {
+ return value.equals("") ? "\"\"" : value;
+ } else {
+ return value.toString();
+ }
+ }
+
+ /**
+ * Attempt to instantiate class c, if possible. Returns null if this proves impossible.
+ *
+ * @param c
+ * @return
+ */
+ private Object makeInstanceIfPossible(Class c) {
+ Object instance = null;
+ try {
+ // don't try to make something where we will obviously fail
+ if (!c.isEnum() && !c.isAnnotation() && !c.isAnonymousClass() &&
+ !c.isArray() && !c.isPrimitive() & JVMUtils.isConcrete(c)) {
+ instance = c.newInstance();
+ //System.out.printf("Created object of class %s => %s%n", c, instance);
+ return instance;
+ } else
+ return null;
+ } catch (IllegalAccessException e) {
+ } catch (InstantiationException e) {
+ } catch (ExceptionInInitializerError e) {
+ } catch (SecurityException e) {
+ }
+ // this last one is super dangerous, but some of these methods catch ClassNotFoundExceptions
+ // and rethrow then as RuntimeExceptions
+ catch (RuntimeException e) {
+ }
+
+ return instance;
+ }
+
+
+ /**
+ * Create an instance of the GATK parsing engine, for argument processing with GATKDoclet
+ *
+ * @return
+ */
+ private ParsingEngine createStandardGATKParsingEngine() {
+ CommandLineProgram clp = new CommandLineGATK();
+ try {
+ CommandLineProgram.start(clp, new String[]{}, true);
+ return clp.parser;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Gets the javadocs associated with field name in classDoc. Throws a
+ * runtime exception if this proves impossible.
+ *
+ * @param classDoc
+ * @param name
+ * @return
+ */
+ private FieldDoc getFieldDoc(ClassDoc classDoc, String name) {
+ return getFieldDoc(classDoc, name, true);
+ }
+
+ /**
+ * Recursive helper routine to getFieldDoc()
+ *
+ * @param classDoc
+ * @param name
+ * @param primary
+ * @return
+ */
+ private FieldDoc getFieldDoc(ClassDoc classDoc, String name, boolean primary) {
+ //System.out.printf("Looking for %s in %s%n", name, classDoc.name());
+ for (FieldDoc fieldDoc : classDoc.fields(false)) {
+ //System.out.printf("fieldDoc " + fieldDoc + " name " + fieldDoc.name());
+ if (fieldDoc.name().equals(name))
+ return fieldDoc;
+
+ Field field = DocletUtils.getFieldForFieldDoc(fieldDoc);
+ if (field == null)
+ throw new RuntimeException("Could not find the field corresponding to " + fieldDoc + ", presumably because the field is inaccessible");
+ if (field.isAnnotationPresent(ArgumentCollection.class)) {
+ ClassDoc typeDoc = getRootDoc().classNamed(fieldDoc.type().qualifiedTypeName());
+ if (typeDoc == null)
+ throw new ReviewedGATKException("Tried to get javadocs for ArgumentCollection field " + fieldDoc + " but could't find the class in the RootDoc");
+ else {
+ FieldDoc result = getFieldDoc(typeDoc, name, false);
+ if (result != null)
+ return result;
+ // else keep searching
+ }
+ }
+ }
+
+ // if we didn't find it here, wander up to the superclass to find the field
+ if (classDoc.superclass() != null) {
+ return getFieldDoc(classDoc.superclass(), name, false);
+ }
+
+ if (primary)
+ throw new RuntimeException("No field found for expected field " + name);
+ else
+ return null;
+ }
+
+ /**
+ * Returns a Pair of (main, synonym) names for argument with fullName s1 and
+ * shortName s2.
+ *
+ * Previously we had it so the main name was selected to be the longest of the two, provided
+ * it didn't exceed MAX_DISPLAY_NAME, in which case the shorter was taken. But we now disable
+ * the length-based name rearrangement in order to maintain consistency in the GATKDocs table.
+ *
+ * This may cause messed up spacing in the CLI-help display but we don't care as much about that
+ * since more users use the online GATKDocs for looking up arguments.
+ *
+ * @param s1 the short argument name without -, or null if not provided
+ * @param s2 the long argument name without --, or null if not provided
+ * @return A pair of fully qualified names (with - or --) for the argument. The first
+ * element is the primary display name while the second (potentially null) is a
+ * synonymous name.
+ */
+ Pair<String, String> displayNames(String s1, String s2) {
+ s1 = s1 == null ? null : "-" + s1;
+ s2 = s2 == null ? null : "--" + s2;
+
+ if (s1 == null) return new Pair<String, String>(s2, null);
+ if (s2 == null) return new Pair<String, String>(s1, null);
+
+ return new Pair<String, String>(s2, s1);
+ }
+
+ /**
+ * Returns a human readable string that describes the Type type of a GATK argument.
+ * <p/>
+ * This will include parameterized types, so that Set{T} shows up as Set(T) and not
+ * just Set in the docs.
+ *
+ * @param type
+ * @return
+ */
+ protected String argumentTypeString(Type type) {
+ if (type instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType) type;
+ List<String> subs = new ArrayList<String>();
+ for (Type actualType : parameterizedType.getActualTypeArguments())
+ subs.add(argumentTypeString(actualType));
+ return argumentTypeString(((ParameterizedType) type).getRawType()) + "[" + Utils.join(",", subs) + "]";
+ } else if (type instanceof GenericArrayType) {
+ return argumentTypeString(((GenericArrayType) type).getGenericComponentType()) + "[]";
+ } else if (type instanceof WildcardType) {
+ throw new RuntimeException("We don't support wildcards in arguments: " + type);
+ } else if (type instanceof Class<?>) {
+ return ((Class) type).getSimpleName();
+ } else {
+ throw new GATKException("Unknown type: " + type);
+ }
+ }
+
+ /**
+ * Helper routine that returns the Feature.class required by a RodBinding,
+ * either T for RodBinding{T} or List{RodBinding{T}}. Returns null if
+ * the Type doesn't fit either model.
+ *
+ * @param type
+ * @return
+ */
+ protected Class<? extends Feature> getFeatureTypeIfPossible(Type type) {
+ if (type instanceof ParameterizedType) {
+ ParameterizedType paramType = (ParameterizedType) type;
+ if (RodBinding.class.isAssignableFrom((Class<?>) paramType.getRawType())) {
+ return (Class<? extends Feature>) JVMUtils.getParameterizedTypeClass(type);
+ } else {
+ for (Type paramtype : paramType.getActualTypeArguments()) {
+ Class<? extends Feature> x = getFeatureTypeIfPossible(paramtype);
+ if (x != null)
+ return x;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * High-level entry point for creating a FreeMarker map describing the GATK argument
+ * source with definition def, with associated javadoc fieldDoc.
+ *
+ * @param fieldDoc
+ * @param source
+ * @param def
+ * @return a non-null Map binding argument keys with their values
+ */
+ protected Map<String, Object> docForArgument(FieldDoc fieldDoc, ArgumentSource source, ArgumentDefinition def) {
+ Map<String, Object> root = new HashMap<String, Object>();
+ Pair<String, String> names = displayNames(def.shortName, def.fullName);
+
+ root.put("name", names.getFirst());
+
+ if (names.getSecond() != null) {
+ root.put("synonyms", names.getSecond());
+ } else {
+ root.put("synonyms", "NA");
+ }
+
+ root.put("required", def.required ? "yes" : "no");
+
+ // type of the field
+ root.put("type", argumentTypeString(source.field.getGenericType()));
+
+ Class<? extends Feature> featureClass = getFeatureTypeIfPossible(source.field.getGenericType());
+ if (featureClass != null) {
+ // deal with the allowable types
+ FeatureManager manager = new FeatureManager();
+ List<String> rodTypes = new ArrayList<String>();
+ for (FeatureManager.FeatureDescriptor descriptor : manager.getByFeature(featureClass)) {
+ rodTypes.add(String.format("<a href=%s>%s</a>",
+ GATKDocUtils.phpFilenameForClass(descriptor.getCodecClass()),
+ descriptor.getName()));
+ }
+
+ root.put("rodTypes", Utils.join(", ", rodTypes));
+ } else {
+ root.put("rodTypes", "NA");
+ }
+
+ // summary and fulltext
+ root.put("summary", def.doc != null ? def.doc : "");
+ root.put("fulltext", fieldDoc.commentText());
+
+ // What are our enum options?
+ if (def.validOptions != null) {
+ root.put("options", docForEnumArgument(source.field.getType()));
+ } else {
+ root.put("options", new ArrayList());
+ }
+ // general attributes
+ List<String> attributes = new ArrayList<String>();
+ if (def.required) attributes.add("required");
+ if (source.isDeprecated()) attributes.add("deprecated");
+ if (attributes.size() > 0) {
+ root.put("attributes", Utils.join(", ", attributes));
+ } else {
+ root.put("attributes", "NA");
+ }
+ return root;
+ }
+
+ /**
+ * Helper routine that provides a FreeMarker map for an enumClass, grabbing the
+ * values of the enum and their associated javadoc documentation.
+ *
+ * @param enumClass
+ * @return
+ */
+ @Requires("enumClass.isEnum()")
+ private List<Map<String, Object>> docForEnumArgument(final Class enumClass) {
+ final ClassDoc doc = this.getDoclet().getClassDocForClass(enumClass);
+ if ( doc == null )
+ throw new RuntimeException("Tried to get docs for enum " + enumClass + " but got null instead");
+
+ final Set<String> enumConstantFieldNames = enumConstantsNames(enumClass);
+
+ final List<Map<String, Object>> bindings = new ArrayList<Map<String, Object>>();
+ for (final FieldDoc fieldDoc : doc.fields(false)) {
+ if (enumConstantFieldNames.contains(fieldDoc.name()) )
+ bindings.add(
+ new HashMap<String, Object>() {{
+ put("name", fieldDoc.name());
+ put("summary", fieldDoc.commentText());
+ }});
+ }
+
+ return bindings;
+ }
+
+ /**
+ * Returns the name of the fields that are enum constants according to reflection
+ *
+ * @return a non-null set of fields that are enum constants
+ */
+ private Set<String> enumConstantsNames(final Class enumClass) {
+ final Set<String> enumConstantFieldNames = new HashSet<String>();
+
+ for ( final Field field : enumClass.getFields() ) {
+ if ( field.isEnumConstant() )
+ enumConstantFieldNames.add(field.getName());
+ }
+
+ return enumConstantFieldNames;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/HelpConstants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/HelpConstants.java
new file mode 100644
index 0000000..16257c6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/HelpConstants.java
@@ -0,0 +1,83 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+public class HelpConstants {
+
+ public final static String BASE_GATK_URL = "http://www.broadinstitute.org/gatk";
+ public final static String GATK_DOCS_URL = BASE_GATK_URL + "/tooldocs/";
+ public final static String GATK_FORUM_URL = "http://gatkforums.broadinstitute.org/";
+ public final static String GATK_FORUM_API_URL = "https://gatkforums.broadinstitute.org/api/v1/";
+
+ /**
+ * Arguments for parallelism options
+ */
+ public final static String ARG_TREEREDUCIBLE = "-nt";
+ public final static String ARG_NANOSCHEDULABLE = "-nct";
+ public final static String CMDLINE_GATK_URL = GATK_DOCS_URL + "org_broadinstitute_gatk_engine_CommandLineGATK.php";
+
+ /**
+ * Definition of the group names / categories of tools.
+ * The names get parsed to make supercategories in the doc index,
+ * so be careful when making big changes -- see GATKDoclet.java toMap()
+ */
+ public final static String DOCS_CAT_DATA = "Sequence Data Processing Tools";
+ public final static String DOCS_CAT_QC = "Diagnostics and Quality Control Tools";
+ public final static String DOCS_CAT_ENGINE = "Engine Parameters (available to all tools)";
+ public final static String DOCS_CAT_RF = "Read Filters";
+ public final static String DOCS_CAT_REFUTILS = "Reference Utilities";
+ public final static String DOCS_CAT_RODCODECS = "ROD Codecs";
+ public final static String DOCS_CAT_USRERR = "User Exceptions (DevZone)";
+ public final static String DOCS_CAT_VALIDATION = "Validation Utilities";
+ public final static String DOCS_CAT_ANNOT = "Variant Annotations";
+ public final static String DOCS_CAT_VARDISC = "Variant Discovery Tools";
+ public final static String DOCS_CAT_VARMANIP = "Variant Evaluation and Manipulation Tools";
+ public final static String DOCS_CAT_TOY = "Toy Walkers (DevZone)";
+ public final static String DOCS_CAT_HELPUTILS = "Help Utilities";
+
+ public static String forumPost(String post) {
+ return GATK_FORUM_URL + post;
+ }
+
+ /**
+ * Go-to developer name codes for tracking and display purposes. Only current team members should be in this list.
+ * When someone leaves, their charges should be redistributed. The actual string should be closest to the dev's
+ * abbreviated name or two/three-letter nickname as possible. The code can be something else if necessary to
+ * disambiguate from other variable.
+ */
+ public final static String MC = "MC"; // Mauricio Carneiro
+ public final static String EB = "EB"; // Eric Banks
+ public final static String RP = "RP"; // Ryan Poplin
+ public final static String GVDA = "GG"; // Geraldine Van der Auwera
+ public final static String VRR = "VRR"; // Valentin Ruano-Rubio
+ public final static String ALM = "ALM"; // Ami Levy-Moonshine
+ public final static String BH = "BH"; // Bertrand Haas
+ public final static String JoT = "JT"; // Joel Thibault
+ public final static String DR = "DR"; // David Roazen
+ public final static String KS = "KS"; // Khalid Shakir
+
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/HelpFormatter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/HelpFormatter.java
new file mode 100644
index 0000000..a8d4693
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/HelpFormatter.java
@@ -0,0 +1,336 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.text.TextFormattingUtils;
+
+import java.net.InetAddress;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+/**
+ * Print out help for GATK command-line applications.
+ */
+
+public class HelpFormatter {
+ /** our log, which we want to capture anything from org.broadinstitute.gatk */
+ private static Logger logger = Logger.getLogger(HelpFormatter.class);
+
+ public static final int FIELD_SEPARATION_WIDTH = 3;
+
+ /**
+ * Prints the help, given a collection of argument definitions.
+ * @param applicationDetails Application details
+ * @param argumentDefinitions Argument definitions for which help should be printed.
+ */
+ public void printHelp( ApplicationDetails applicationDetails, ArgumentDefinitions argumentDefinitions ) {
+ List<ArgumentDefinitionGroup> argumentGroups = prepareArgumentGroups( argumentDefinitions );
+
+ List<String> header = applicationDetails.applicationHeader;
+ String barrier = createBarrier(header);
+
+ System.out.printf("%s%n",barrier);
+ for(String headerLine: header)
+ System.out.printf("%s%n",headerLine);
+ System.out.printf("%s%n",barrier);
+ for(String attributionLine: applicationDetails.attribution)
+ System.out.printf("%s%n",attributionLine);
+ System.out.printf("%s%n",barrier);
+
+ String synopsis = getSynopsis(applicationDetails.runningInstructions,argumentGroups);
+ String additionalDetails = applicationDetails.additionalHelp != null ? applicationDetails.additionalHelp : "";
+ String detailedDescription = getDetailed(argumentGroups);
+
+ System.out.printf("%s%n%s%n%s%n",synopsis,detailedDescription,additionalDetails );
+ }
+
+ /**
+ * Gets the synopsis: the actual command to run.
+ * @param runningInstructions Instructions on how to run hte application.
+ * @param argumentGroups Program arguments sorted in order of definition group displays.
+ * @return A synopsis line.
+ */
+ private String getSynopsis( String runningInstructions,
+ List<ArgumentDefinitionGroup> argumentGroups ) {
+ // Build out the synopsis all as one long line.
+ StringBuilder lineBuilder = new StringBuilder();
+ Formatter lineFormatter = new Formatter( lineBuilder );
+
+ lineFormatter.format("java %s", runningInstructions);
+
+ for( ArgumentDefinitionGroup argumentGroup: argumentGroups ) {
+ for( ArgumentDefinition argumentDefinition: argumentGroup.argumentDefinitions ) {
+ if(argumentDefinition.isHidden)
+ continue;
+ lineFormatter.format(" ");
+ if( !argumentDefinition.required ) lineFormatter.format("[");
+ if( argumentDefinition.shortName != null )
+ lineFormatter.format("-%s", argumentDefinition.shortName);
+ else
+ lineFormatter.format("--%s", argumentDefinition.fullName);
+ if( !argumentDefinition.isFlag )
+ lineFormatter.format(" <%s>", argumentDefinition.fullName);
+ if( !argumentDefinition.required ) lineFormatter.format("]");
+ }
+ }
+
+ // Word wrap the synopsis.
+ List<String> wrappedSynopsis = TextFormattingUtils.wordWrap( lineBuilder.toString(), TextFormattingUtils.DEFAULT_LINE_WIDTH );
+
+ String header = "usage: ";
+ int headerLength = header.length();
+
+ StringBuilder synopsisBuilder = new StringBuilder();
+ Formatter synopsisFormatter = new Formatter(synopsisBuilder);
+ for( String synopsisLine: wrappedSynopsis ) {
+ synopsisFormatter.format("%" + headerLength + "s%s%n", header, synopsisLine);
+ header = "";
+ }
+
+ return synopsisBuilder.toString();
+ }
+
+ /**
+ * Gets detailed output about each argument type.
+ * @param argumentGroups Collection of program arguments sorted according to how they should be shown.
+ * @return Detailed text about all arguments.
+ */
+ private String getDetailed( List<ArgumentDefinitionGroup> argumentGroups ) {
+ StringBuilder builder = new StringBuilder();
+
+ for( ArgumentDefinitionGroup argumentGroup: argumentGroups )
+ builder.append( getDetailForGroup( argumentGroup ) );
+
+ return builder.toString();
+ }
+
+ /**
+ * Gets a detailed description for a given argument group.
+ * @param argumentDefinitionGroup The group of argument definitions to render.
+ * @return A string giving detailed info about the contents of this group.
+ */
+ private String getDetailForGroup( ArgumentDefinitionGroup argumentDefinitionGroup ) {
+ if(argumentDefinitionGroup.allHidden())
+ return "";
+
+ StringBuilder builder = new StringBuilder();
+ Formatter formatter = new Formatter( builder );
+
+ if( argumentDefinitionGroup.groupName != null && argumentDefinitionGroup.argumentDefinitions.size() != 0 )
+ builder.append( String.format("%nArguments for %s:%n", argumentDefinitionGroup.groupName ) );
+
+ List<ArgumentDefinition> argumentDefinitions = new ArrayList<ArgumentDefinition>();
+ for(ArgumentDefinition argumentDefinition: argumentDefinitionGroup.argumentDefinitions) {
+ if(!argumentDefinition.isHidden)
+ argumentDefinitions.add(argumentDefinition);
+ }
+
+ // Try to fit the entire argument definition across the screen, but impose an arbitrary cap of 3/4 *
+ // LINE_WIDTH in case the length of the arguments gets out of control.
+ int argWidth = Math.min( findLongestArgumentCallingInfo(argumentDefinitions), (TextFormattingUtils.DEFAULT_LINE_WIDTH*3)/4 - FIELD_SEPARATION_WIDTH );
+ int docWidth = TextFormattingUtils.DEFAULT_LINE_WIDTH - argWidth - FIELD_SEPARATION_WIDTH;
+
+ for( ArgumentDefinition argumentDefinition: argumentDefinitions ) {
+ Iterator<String> wordWrappedArgs = TextFormattingUtils.wordWrap( getArgumentCallingInfo(argumentDefinition), argWidth ).iterator();
+ Iterator<String> wordWrappedDoc = TextFormattingUtils.wordWrap( getArgumentDoc(argumentDefinition), docWidth ).iterator();
+
+ while( wordWrappedArgs.hasNext() || wordWrappedDoc.hasNext() ) {
+ String arg = wordWrappedArgs.hasNext() ? wordWrappedArgs.next() : "";
+ String doc = wordWrappedDoc.hasNext() ? wordWrappedDoc.next() : "";
+
+ String formatString = "%-" + argWidth + "s%" + FIELD_SEPARATION_WIDTH + "s%s%n";
+ formatter.format( formatString, arg, "", doc );
+ }
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Gets a string indicating how this argument should be passed to the application.
+ * @param argumentDefinition Argument definition for which help should be printed.
+ * @return Calling information for this argument.
+ */
+ private String getArgumentCallingInfo( ArgumentDefinition argumentDefinition ) {
+ StringBuilder builder = new StringBuilder();
+ Formatter formatter = new Formatter( builder );
+
+ formatter.format(" ");
+ if( argumentDefinition.shortName != null )
+ formatter.format("-%s,", argumentDefinition.shortName);
+ formatter.format("--%s", argumentDefinition.fullName);
+ if( !argumentDefinition.isFlag )
+ formatter.format(" <%s>", argumentDefinition.fullName);
+
+ return builder.toString();
+ }
+
+ /**
+ * Gets a string of argument documentation.
+ * @param argumentDefinition Argument definition for which help should be printed.
+ * @return Brief description for this argument.
+ */
+ private String getArgumentDoc( ArgumentDefinition argumentDefinition ) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(argumentDefinition.doc);
+ if( argumentDefinition.validOptions != null ) {
+ builder.append(" (");
+ builder.append(Utils.join("|",argumentDefinition.validOptions));
+ builder.append(")");
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Crude implementation which finds the longest argument portion
+ * given a set of arguments.
+ * @param argumentDefinitions argument definitions to inspect.
+ * @return longest argument length.
+ */
+ private int findLongestArgumentCallingInfo( Collection<ArgumentDefinition> argumentDefinitions ) {
+ int longest = 0;
+ for( ArgumentDefinition argumentDefinition: argumentDefinitions ) {
+ String argumentText = getArgumentCallingInfo( argumentDefinition );
+ if( longest < argumentText.length() )
+ longest = argumentText.length();
+ }
+ return longest;
+ }
+
+ /**
+ * Extract the argument definition groups from the argument definitions and arrange them appropriately.
+ * For help, we want the arguments sorted as they are declared in the class. However, required arguments
+ * should appear before optional arguments.
+ * @param argumentDefinitions Argument definitions from which to extract argument groups.
+ * @return A list of argument groups sorted in display order.
+ */
+ private List<ArgumentDefinitionGroup> prepareArgumentGroups( ArgumentDefinitions argumentDefinitions ) {
+ // Sort the list of argument definitions according to how they should be shown.
+ // Put the sorted results into a new cloned data structure.
+ Comparator<ArgumentDefinition> definitionComparator = new Comparator<ArgumentDefinition>() {
+ public int compare( ArgumentDefinition lhs, ArgumentDefinition rhs ) {
+ if( lhs.required && rhs.required ) return 0;
+ if( lhs.required ) return -1;
+ if( rhs.required ) return 1;
+ return 0;
+ }
+ };
+
+ List<ArgumentDefinitionGroup> argumentGroups = new ArrayList<ArgumentDefinitionGroup>();
+ for( ArgumentDefinitionGroup argumentGroup: argumentDefinitions.getArgumentDefinitionGroups() ) {
+ List<ArgumentDefinition> sortedDefinitions = new ArrayList<ArgumentDefinition>( argumentGroup.argumentDefinitions );
+ Collections.sort( sortedDefinitions, definitionComparator );
+ argumentGroups.add( new ArgumentDefinitionGroup(argumentGroup.groupName,sortedDefinitions) );
+ }
+
+ // Sort the argument groups themselves with main arguments first, followed by plugins sorted in name order.
+ Comparator<ArgumentDefinitionGroup> groupComparator = new Comparator<ArgumentDefinitionGroup>() {
+ public int compare( ArgumentDefinitionGroup lhs, ArgumentDefinitionGroup rhs ) {
+ if( lhs.groupName == null && rhs.groupName == null ) return 0;
+ if( lhs.groupName == null ) return -1;
+ if( rhs.groupName == null ) return 1;
+ return lhs.groupName.compareTo(rhs.groupName);
+ }
+ };
+ Collections.sort( argumentGroups, groupComparator );
+
+
+ return argumentGroups;
+ }
+
+ /**
+ * generateHeaderInformation
+ * <p/>
+ * <p/>
+ * Generate a standard header for the logger
+ *
+ * @param applicationDetails details of the application to run.
+ * @param parsedArgs the arguments passed in
+ */
+ public static void generateHeaderInformation(ApplicationDetails applicationDetails, Map<ArgumentMatchSource, ParsedArgs> parsedArgs) {
+
+ DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+ java.util.Date date = new java.util.Date();
+
+ String barrier = createBarrier(applicationDetails.applicationHeader);
+
+ logger.info(barrier);
+ for (String headerLine : applicationDetails.applicationHeader)
+ logger.info(headerLine);
+ logger.debug("Current directory: " + System.getProperty("user.dir"));
+ for (Map.Entry<ArgumentMatchSource, ParsedArgs> entry: parsedArgs.entrySet()) {
+ ArgumentMatchSource matchSource = entry.getKey();
+ final String sourceName;
+ switch (matchSource.getType()) {
+ case CommandLine: sourceName = "Program"; break;
+ case Provider: sourceName = matchSource.getDescription(); break;
+ default: throw new RuntimeException("Unexpected argument match source type: " + matchSource.getType());
+ }
+
+ String output = sourceName + " Args: " + entry.getValue().getDescription();
+ logger.info(output);
+ }
+ logger.info(generateUserHelpData());
+ logger.info("Date/Time: " + dateFormat.format(date));
+ logger.info(barrier);
+
+ for(String attribution: applicationDetails.attribution)
+ logger.info(attribution);
+ logger.info(barrier);
+ }
+
+ /**
+ * Create the user-related help information.
+ * @return a non-null, non-empty String with the relevant information.
+ */
+ private static String generateUserHelpData() {
+ try {
+ return "Executing as " +
+ System.getProperty("user.name") + "@" + InetAddress.getLocalHost().getHostName() +
+ " on " + System.getProperty("os.name") + " " + System.getProperty("os.version") +
+ " " + System.getProperty("os.arch") + "; " + System.getProperty("java.vm.name") +
+ " " + System.getProperty("java.runtime.version") + ".";
+ } catch (Exception e) {
+ // don't fail
+ return "";
+ }
+ }
+
+ /**
+ * Create a barrier to use to distinguish the header from the rest of the output.
+ * @param text A collection of lines to output as part of a header.
+ * @return A barrier consisting of the '-' character.
+ */
+ private static String createBarrier(List<String> text) {
+ int barrierWidth = 0;
+ for(String headerLine: text)
+ barrierWidth = Math.max(headerLine.length(),barrierWidth);
+ return String.format("%0" + barrierWidth + "d",0).replace('0','-');
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/HelpUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/HelpUtils.java
new file mode 100644
index 0000000..1011a49
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/HelpUtils.java
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.AnnotationType;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.GenotypeAnnotation;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.InfoFieldAnnotation;
+import org.broadinstitute.gatk.tools.walkers.annotator.interfaces.StandardAnnotation;
+import org.broadinstitute.gatk.utils.classloader.PluginManager;
+
+import java.util.List;
+
+/**
+ * NON-javadoc/doclet help-related utility methods should go here. Anything with a com.sun.javadoc.* dependency
+ * should go into DocletUtils for use only by doclets.
+ */
+public class HelpUtils {
+
+ /**
+ * Simple method to print a list of available annotations.
+ */
+ public static void listAnnotations() {
+ System.out.println("\nThis is a list of available Variant Annotations for use with tools such as UnifiedGenotyper, HaplotypeCaller and VariantAnnotator. Please see the Technical Documentation for more details about these annotations:");
+ System.out.println("http://www.broadinstitute.org/gatk/tooldocs/");
+ System.out.println("\nStandard annotations in the list below are marked with a '*'.");
+ List<Class<? extends InfoFieldAnnotation>> infoAnnotationClasses = new PluginManager<InfoFieldAnnotation>(InfoFieldAnnotation.class).getPlugins();
+ System.out.println("\nAvailable annotations for the VCF INFO field:");
+ for (int i = 0; i < infoAnnotationClasses.size(); i++)
+ System.out.println("\t" + (StandardAnnotation.class.isAssignableFrom(infoAnnotationClasses.get(i)) ? "*" : "") + infoAnnotationClasses.get(i).getSimpleName());
+ System.out.println();
+ List<Class<? extends GenotypeAnnotation>> genotypeAnnotationClasses = new PluginManager<GenotypeAnnotation>(GenotypeAnnotation.class).getPlugins();
+ System.out.println("\nAvailable annotations for the VCF FORMAT field:");
+ for (int i = 0; i < genotypeAnnotationClasses.size(); i++)
+ System.out.println("\t" + (StandardAnnotation.class.isAssignableFrom(genotypeAnnotationClasses.get(i)) ? "*" : "") + genotypeAnnotationClasses.get(i).getSimpleName());
+ System.out.println();
+ System.out.println("\nAvailable classes/groups of annotations:");
+ for ( Class c : new PluginManager<AnnotationType>(AnnotationType.class).getInterfaces() )
+ System.out.println("\t" + c.getSimpleName());
+ System.out.println();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ResourceBundleExtractorDoclet.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ResourceBundleExtractorDoclet.java
new file mode 100644
index 0000000..f28130b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/help/ResourceBundleExtractorDoclet.java
@@ -0,0 +1,228 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.help;
+
+import com.sun.javadoc.*;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.Utils;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Extracts certain types of javadoc (specifically package and class descriptions) and makes them available
+ * to applications at runtime.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class ResourceBundleExtractorDoclet {
+ /**
+ * Taglet for the particular version number.
+ */
+ public static final String VERSION_TAGLET_NAME = "version";
+ public static final String SUMMARY_TAGLET_NAME = "help.summary";
+ public static final String DESCRIPTION_TAGLET_NAME = "help.description";
+
+ /**
+ * Maintains a collection of resources in memory as they're accumulated.
+ */
+ protected final Properties resourceText = new Properties();
+
+ /**
+ * Maintains a collection of classes that should really be documented.
+ */
+ protected final Set<String> undocumentedWalkers = new HashSet<String>();
+
+ protected String buildTimestamp = null, absoluteVersion = null;
+
+ /**
+ * Extracts the contents of certain types of javadoc and adds them to an XML file.
+ * @param rootDoc The documentation root.
+ * @return Whether the JavaDoc run succeeded.
+ * @throws IOException if output can't be written.
+ */
+ public static boolean start(RootDoc rootDoc) throws IOException {
+ ResourceBundleExtractorDoclet doclet = new ResourceBundleExtractorDoclet();
+ PrintStream out = doclet.loadData(rootDoc, true);
+ doclet.processDocs(rootDoc, out);
+ return true;
+ }
+
+ protected PrintStream loadData(RootDoc rootDoc, boolean overwriteResourcesFile) {
+ PrintStream out = System.out;
+
+ for(String[] options: rootDoc.options()) {
+ if(options[0].equals("-out")) {
+ try {
+ loadExistingResourceFile(options[1], rootDoc);
+ if ( overwriteResourcesFile )
+ out = new PrintStream(options[1]);
+ } catch ( FileNotFoundException e ) {
+ throw new RuntimeException(e);
+ } catch ( IOException e ) {
+ throw new RuntimeException(e);
+ }
+ }
+ if(options[0].equals("-build-timestamp"))
+ buildTimestamp = options[1];
+ if (options[0].equals("-absolute-version"))
+ absoluteVersion = options[1];
+ }
+
+ resourceText.setProperty("build.timestamp",buildTimestamp);
+ return out;
+ }
+
+ protected void processDocs(RootDoc rootDoc, PrintStream out) {
+ // Cache packages as we see them, since there's no direct way to iterate over packages.
+ Set<PackageDoc> packages = new HashSet<PackageDoc>();
+
+ for(ClassDoc currentClass: rootDoc.classes()) {
+ PackageDoc containingPackage = currentClass.containingPackage();
+ packages.add(containingPackage);
+
+ if(isRequiredJavadocMissing(currentClass) && isWalker(currentClass))
+ undocumentedWalkers.add(currentClass.name());
+
+ renderHelpText(DocletUtils.getClassName(currentClass),currentClass);
+ }
+
+ for(PackageDoc currentPackage: packages)
+ renderHelpText(currentPackage.name(),currentPackage);
+
+ try {
+ resourceText.store(out,"Strings displayed by the GATK help system");
+ } catch ( FileNotFoundException e ) {
+ throw new RuntimeException(e);
+ } catch ( IOException e ) {
+ throw new RuntimeException(e);
+ }
+
+ // ASCII codes for making text blink
+ final String blink = "\u001B\u005B\u0035\u006D";
+ final String reset = "\u001B\u005B\u006D";
+
+ if(undocumentedWalkers.size() > 0)
+ Utils.warnUser(String.format("The following walkers are currently undocumented: %s%s%s", blink, Utils.join(" ",undocumentedWalkers), reset));
+ }
+
+ /**
+ * Validate the given options against options supported by this doclet.
+ * @param option Option to validate.
+ * @return Number of potential parameters; 0 if not supported.
+ */
+ public static int optionLength(String option) {
+ if(option.equals("-build-timestamp") || option.equals("-out") || option.equals("-absolute-version") ) {
+ return 2;
+ }
+ return 0;
+ }
+
+ /**
+ * Attempts to load the contents of the resource file named by resourceFileName into
+ * our in-memory resource collection resourceText. If the resource file doesn't exist,
+ * prints a notice to the user but does not throw an exception back to the calling method,
+ * since we'll just create a new resource file from scratch in that case.
+ * @param resourceFileName name of the resource file to attempt to load.
+ * @param rootDoc the documentation root.
+ * @throws IOException if there is an I/O-related error other than FileNotFoundException
+ * while attempting to read the resource file.
+ */
+ private void loadExistingResourceFile( String resourceFileName, RootDoc rootDoc ) throws IOException {
+ try {
+ BufferedReader resourceFile = new BufferedReader(new FileReader(resourceFileName));
+ try {
+ resourceText.load(resourceFile);
+ }
+ finally {
+ resourceFile.close();
+ }
+ }
+ catch ( FileNotFoundException e ) {
+ rootDoc.printNotice("Resource file not found -- generating a new one from scratch.");
+ }
+ }
+
+ /**
+ * Determine whether a given class is a walker.
+ * @param classDoc the type of the given class.
+ * @return True if the class of the given name is a walker. False otherwise.
+ */
+ protected static boolean isWalker(ClassDoc classDoc) {
+ return DocletUtils.assignableToClass(classDoc, Walker.class, true);
+ }
+
+ /**
+ * Is the javadoc for the given class missing?
+ * @param classDoc Class for which to inspect the JavaDoc.
+ * @return True if the JavaDoc is missing. False otherwise.
+ */
+ private static boolean isRequiredJavadocMissing(ClassDoc classDoc) {
+ return classDoc.commentText().length() == 0 || classDoc.commentText().contains("Created by IntelliJ");
+ }
+
+ /**
+ * Renders all the help text required for a given name.
+ * @param elementName element name to use as the key
+ * @param element Doc element to process.
+ */
+ private void renderHelpText(String elementName, Doc element) {
+ StringBuilder summaryBuilder = new StringBuilder();
+ for(Tag tag: element.firstSentenceTags())
+ summaryBuilder.append(tag.text());
+ String summary = summaryBuilder.toString();
+ String description = element.commentText();
+
+ // this might seem unnecessary, but the GATK command line program uses this tag to determine the version when running
+ if(absoluteVersion != null)
+ resourceText.setProperty(String.format("%s.%s",elementName,VERSION_TAGLET_NAME),absoluteVersion);
+
+ // Write out an alternate element summary, if exists.
+ resourceText.setProperty(String.format("%s.%s",elementName,SUMMARY_TAGLET_NAME),formatText(summary));
+
+ // Write out an alternate description, if present.
+ resourceText.setProperty(String.format("%s.%s",elementName,DESCRIPTION_TAGLET_NAME),formatText(description));
+ }
+
+ /**
+ * Format text for consumption by the properties file.
+ * @param text Text to format.
+ * @return Formatted text; string trimmed, newlines removed.
+ */
+ private static String formatText(String text) {
+ Scanner scanner = new Scanner(text);
+ StringBuilder output = new StringBuilder();
+
+ while(scanner.hasNextLine()) {
+ if(output.length() > 0)
+ output.append(' ');
+ output.append(scanner.nextLine().trim());
+ }
+
+ return output.toString();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/instrumentation/Sizeof.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/instrumentation/Sizeof.java
new file mode 100644
index 0000000..a31c498
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/instrumentation/Sizeof.java
@@ -0,0 +1,146 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.instrumentation;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.lang.instrument.Instrumentation;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.IdentityHashMap;
+
+/**
+ * A sizeof implementation for Java. Relies on the Java instrumentation API, so
+ * it must be added as an agent to function properly.
+ *
+ * To run, add -javaagent:$STING_HOME/dist/StingUtils.jar as a command-line
+ * JVM argument.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class Sizeof {
+ /**
+ * Instrumentation object. Registered by the JVM via the premain() method.
+ */
+ private static Instrumentation instrumentation;
+
+ /**
+ * Called by the JVM before the agent is started.
+ * @param args Arguments?
+ * @param inst Instrumentation object, used to perform instrumentation in the JVM.
+ */
+ public static void premain(String args, Instrumentation inst) {
+ instrumentation = inst;
+ }
+
+ /**
+ * Is this Sizeof operator enabled? To enable, add the -javaagent directive listed in the class-level javadoc.
+ * @return True if sizeof() is enabled. If false, any calls to utility methods of this class will throw an exception.
+ */
+ public static boolean isEnabled() {
+ return instrumentation != null;
+ }
+
+ /**
+ * Gets the size of the given object. Retrieves the size for only this object; any reference fields in the object will only be
+ * counted as single pointers.
+ * @param o The object to sizeof().
+ * @return Gets the best possible approximation we can get of the size of the object in memory. On Sun JVM, includes some object padding.
+ */
+ public static long getObjectSize(Object o) {
+ if(!isEnabled())
+ throw new ReviewedGATKException("Sizeof operator is currently disabled! To enable, review the documentation in Sizeof.java");
+ return instrumentation.getObjectSize(o);
+ }
+
+ /**
+ * Gets the size of the given object, including the size of the objects to which this object refers.
+ * @param o The object to sizeof().
+ * @return Gets the best possible approximation we can get of the size of the object in memory, including all references within each object.
+ */
+ public static long getObjectGraphSize(Object o) {
+ if(!isEnabled())
+ throw new ReviewedGATKException("Sizeof operator is currently disabled! To enable, review the documentation in Sizeof.java");
+ IdentityHashMap<Object,Object> objectsSeen = new IdentityHashMap<Object,Object>();
+ return getObjectGraphSize(o,objectsSeen);
+ }
+
+ /**
+ * The engine for walking the graph of all objects and their children.
+ * @param o The object to traverse.
+ * @param objectsSeen A list of all objects already seen.
+ * @return Gets the best possible approximation we can get of the size of the object in memory, including all references within each object.
+ */
+ private static long getObjectGraphSize(Object o,IdentityHashMap<Object,Object> objectsSeen) {
+ // Size of a null object itself (as opposed to the reference to the null object) is 0.
+ if(o == null)
+ return 0;
+
+ // Don't allow repeated traversals of the same object.
+ if(objectsSeen.containsKey(o))
+ return 0;
+ objectsSeen.put(o,o);
+
+ // Get the size of the object itself, plus all contained primitives.
+ long totalSize = instrumentation.getObjectSize(o);
+
+ // Get the size of (non-primitive) array elements.
+ Class<?> classToInspect = o.getClass();
+ if(classToInspect.isArray()) {
+ if(!classToInspect.getComponentType().isPrimitive()) {
+ for(int i = 0; i < Array.getLength(o); i++)
+ totalSize += getObjectGraphSize(Array.get(o,i),objectsSeen);
+ }
+ }
+
+ // Walk the descendents of each field of this class. Be sure to avoid synthetic fields like this$0 -- these
+ // are back references to the parent of the object contained in the inner class.
+ // Potential BUG: Are there other types of synthetic fields we should be tracking?
+ while(classToInspect != null) {
+ for(Field field: classToInspect.getDeclaredFields()) {
+ if(field.getType().isPrimitive())
+ continue;
+ if(Modifier.isStatic(field.getModifiers()))
+ continue;
+ if(field.isSynthetic())
+ continue;
+ field.setAccessible(true);
+ Object fieldValue;
+ try {
+ fieldValue = field.get(o);
+ }
+ catch(IllegalAccessException ex) {
+ throw new ReviewedGATKException("Unable to access field " + field.getName(),ex);
+ }
+ totalSize += getObjectGraphSize(fieldValue,objectsSeen);
+ }
+ classToInspect = classToInspect.getSuperclass();
+ }
+ return totalSize;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/interval/IntervalMergingRule.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/interval/IntervalMergingRule.java
new file mode 100644
index 0000000..3e5eb45
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/interval/IntervalMergingRule.java
@@ -0,0 +1,35 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.interval;
+
+
+/**
+ * a class we use to determine the merging rules for intervals passed to the GATK
+ */
+public enum IntervalMergingRule {
+ ALL, // we merge both overlapping intervals and abutting intervals
+ OVERLAPPING_ONLY // We merge intervals that are overlapping, but NOT ones that only abut each other
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/interval/IntervalSetRule.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/interval/IntervalSetRule.java
new file mode 100644
index 0000000..e9d20ee
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/interval/IntervalSetRule.java
@@ -0,0 +1,36 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.interval;
+
+/**
+ * set operators for combining lists of intervals
+ */
+public enum IntervalSetRule {
+ /** Take the union of all intervals */
+ UNION,
+ /** Take the intersection of intervals (the subset that overlaps all intervals specified) */
+ INTERSECTION;
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/interval/IntervalUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/interval/IntervalUtils.java
new file mode 100644
index 0000000..7fffb12
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/interval/IntervalUtils.java
@@ -0,0 +1,890 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.interval;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.util.Interval;
+import htsjdk.samtools.util.IntervalList;
+import htsjdk.samtools.SAMFileHeader;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.IntervalArgumentCollection;
+import org.broadinstitute.gatk.utils.commandline.IntervalBinding;
+import org.broadinstitute.gatk.engine.datasources.reference.ReferenceDataSource;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.text.XReadLines;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Parse text representations of interval strings that
+ * can appear in GATK-based applications.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class IntervalUtils {
+ private static Logger logger = Logger.getLogger(IntervalUtils.class);
+
+ /**
+ * Turns a set of strings describing intervals into a parsed set of intervals. Valid string elements can be files,
+ * intervals in samtools notation (chrA:B-C), or some combination of the above separated by semicolons. Additionally,
+ * 'all' can be supplied to indicate all possible intervals, but 'all' must be exclusive of all other interval
+ * specifications.
+ *
+ * @param parser Genome loc parser.
+ * @param argList A list of strings containing interval data.
+ * @return an unsorted, unmerged representation of the given intervals. Null is used to indicate that all intervals should be used.
+ */
+ public static List<GenomeLoc> parseIntervalArguments(GenomeLocParser parser, List<String> argList) {
+ List<GenomeLoc> rawIntervals = new ArrayList<GenomeLoc>(); // running list of raw GenomeLocs
+
+ if (argList != null) { // now that we can be in this function if only the ROD-to-Intervals was provided, we need to
+ // ensure that the arg list isn't null before looping.
+ for (String argument : argList) {
+ rawIntervals.addAll(parseIntervalArguments(parser, argument));
+ }
+ }
+
+ return rawIntervals;
+ }
+
+ public static List<GenomeLoc> parseIntervalArguments(GenomeLocParser parser, String arg) {
+ List<GenomeLoc> rawIntervals = new ArrayList<GenomeLoc>(); // running list of raw GenomeLocs
+
+ if ( arg.indexOf(';') != -1 ) {
+ throw new UserException.BadArgumentValue("-L " + arg, "The legacy -L \"interval1;interval2\" syntax " +
+ "is no longer supported. Please use one -L argument for each " +
+ "interval or an interval file instead.");
+ }
+
+ // if any argument is 'unmapped', "parse" it to a null entry. A null in this case means 'all the intervals with no alignment data'.
+ if (isUnmapped(arg))
+ rawIntervals.add(GenomeLoc.UNMAPPED);
+ // if it's a file, add items to raw interval list
+ else if (isIntervalFile(arg)) {
+ try {
+ rawIntervals.addAll(intervalFileToList(parser, arg));
+ }
+ catch ( UserException.MalformedGenomeLoc e ) {
+ throw e;
+ }
+ catch ( Exception e ) {
+ throw new UserException.MalformedFile(arg, "Interval file could not be parsed in any supported format.", e);
+ }
+ }
+ // otherwise treat as an interval -> parse and add to raw interval list
+ else {
+ rawIntervals.add(parser.parseGenomeLoc(arg));
+ }
+
+ return rawIntervals;
+ }
+
+ /**
+ * Read a file of genome locations to process. The file may be in BED, Picard,
+ * or GATK interval format.
+ *
+ * @param glParser GenomeLocParser
+ * @param file_name interval file
+ * @return List<GenomeLoc> List of Genome Locs that have been parsed from file
+ */
+ public static List<GenomeLoc> intervalFileToList(final GenomeLocParser glParser, final String file_name) {
+ // try to open file
+ File inputFile = new File(file_name);
+ List<GenomeLoc> ret = new ArrayList<GenomeLoc>();
+
+ // case: BED file
+ if ( file_name.toUpperCase().endsWith(".BED") ) {
+ // this is now supported in Tribble
+ throw new ReviewedGATKException("BED files must be parsed through Tribble; parsing them as intervals through the GATK engine is no longer supported");
+ }
+ else {
+ /**
+ * IF not a BED file:
+ * first try to read it as a Picard interval file since that's well structured
+ * we'll fail quickly if it's not a valid file.
+ */
+ boolean isPicardInterval = false;
+ try {
+ // Note: Picard will skip over intervals with contigs not in the sequence dictionary
+ IntervalList il = IntervalList.fromFile(inputFile);
+ isPicardInterval = true;
+
+ int nInvalidIntervals = 0;
+ for (Interval interval : il.getIntervals()) {
+ if ( glParser.isValidGenomeLoc(interval.getSequence(), interval.getStart(), interval.getEnd(), true))
+ ret.add(glParser.createGenomeLoc(interval.getSequence(), interval.getStart(), interval.getEnd(), true));
+ else {
+ nInvalidIntervals++;
+ }
+ }
+ if ( nInvalidIntervals > 0 )
+ logger.warn("Ignoring " + nInvalidIntervals + " invalid intervals from " + inputFile);
+ }
+
+ // if that didn't work, try parsing file as a GATK interval file
+ catch (Exception e) {
+ if ( isPicardInterval ) // definitely a picard file, but we failed to parse
+ throw new UserException.CouldNotReadInputFile(inputFile, e);
+ else {
+ try {
+ XReadLines reader = new XReadLines(new File(file_name));
+ for(String line: reader) {
+ if ( line.trim().length() > 0 ) {
+ ret.add(glParser.parseGenomeLoc(line));
+ }
+ }
+ reader.close();
+ }
+ catch (IOException e2) {
+ throw new UserException.CouldNotReadInputFile(inputFile, e2);
+ }
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ * Returns true if the interval string is the "unmapped" interval
+ * @param interval Interval to check
+ * @return true if the interval string is the "unmapped" interval
+ */
+ public static boolean isUnmapped(String interval) {
+ return (interval != null && interval.trim().toLowerCase().equals("unmapped"));
+ }
+
+ /**
+ * merge two interval lists, using an interval set rule
+ * @param setOne a list of genomeLocs, in order (cannot be NULL)
+ * @param setTwo a list of genomeLocs, also in order (cannot be NULL)
+ * @param rule the rule to use for merging, i.e. union, intersection, etc
+ * @return a list, correctly merged using the specified rule
+ */
+ public static List<GenomeLoc> mergeListsBySetOperator(List<GenomeLoc> setOne, List<GenomeLoc> setTwo, IntervalSetRule rule) {
+ // shortcut, if either set is zero, return the other set
+ if (setOne == null || setOne.size() == 0 || setTwo == null || setTwo.size() == 0)
+ return Collections.unmodifiableList((setOne == null || setOne.size() == 0) ? setTwo : setOne);
+
+ // our master list, since we can't guarantee removal time in a generic list
+ LinkedList<GenomeLoc> retList = new LinkedList<GenomeLoc>();
+
+ // if we're set to UNION, just add them all
+ if (rule == null || rule == IntervalSetRule.UNION) {
+ retList.addAll(setOne);
+ retList.addAll(setTwo);
+ return Collections.unmodifiableList(retList);
+ }
+
+ // else we're INTERSECTION, create two indexes into the lists
+ int iOne = 0;
+ int iTwo = 0;
+
+ // merge the second into the first using the rule
+ while (iTwo < setTwo.size() && iOne < setOne.size())
+ // if the first list is ahead, drop items off the second until we overlap
+ if (setTwo.get(iTwo).isBefore(setOne.get(iOne)))
+ iTwo++;
+ // if the second is ahead, drop intervals off the first until we overlap
+ else if (setOne.get(iOne).isBefore(setTwo.get(iTwo)))
+ iOne++;
+ // we overlap, intersect the two intervals and add the result. Then remove the interval that ends first.
+ else {
+ retList.add(setOne.get(iOne).intersect(setTwo.get(iTwo)));
+ if (setOne.get(iOne).getStop() < setTwo.get(iTwo).getStop()) iOne++;
+ else iTwo++;
+ }
+
+ //if we have an empty list, throw an exception. If they specified intersection and there are no items, this is bad.
+ if (retList.size() == 0)
+ throw new UserException.BadInput("The INTERSECTION of your -L options produced no intervals.");
+
+ // we don't need to add the rest of remaining locations, since we know they don't overlap. return what we have
+ return Collections.unmodifiableList(retList);
+ }
+
+ /**
+ * Sorts and merges an interval list. Multiple techniques are available for merging: ALL, which combines
+ * all overlapping and abutting intervals into an interval that spans the union of all covered bases, and
+ * OVERLAPPING_ONLY, which unions overlapping intervals but keeps abutting intervals separate.
+ *
+ * @param parser Genome loc parser for the intervals.
+ * @param intervals A collection of intervals to merge.
+ * @param mergingRule A descriptor for the type of merging to perform.
+ * @return A sorted, merged version of the intervals passed in.
+ */
+ public static GenomeLocSortedSet sortAndMergeIntervals(GenomeLocParser parser, List<GenomeLoc> intervals, IntervalMergingRule mergingRule) {
+ // Make a copy of the (potentially unmodifiable) list to be sorted
+ intervals = new ArrayList<GenomeLoc>(intervals);
+ // sort raw interval list
+ Collections.sort(intervals);
+ // now merge raw interval list
+ intervals = mergeIntervalLocations(intervals, mergingRule);
+
+ return GenomeLocSortedSet.createSetFromList(parser,intervals);
+ }
+
+ /**
+ * computes whether the test interval list is equivalent to master. To be equivalent, test must
+ * contain GenomeLocs covering every base in master, exactly once. Note that this algorithm
+ * assumes that master genomelocs are all discontiguous (i.e., we don't have locs like 1-3 and 4-6 but
+ * rather just 1-6). In order to use this algorithm with contiguous genomelocs first merge them. The algorithm
+ * doesn't assume that test has discontinuous genomelocs.
+ *
+ * Returns a null string if there are no differences, otherwise returns a string describing the difference
+ * (useful for UnitTests). Assumes both lists are sorted
+ *
+ * @param masterArg sorted master genome locs
+ * @param testArg sorted test genome locs
+ * @return null string if there are no difference, otherwise a string describing the difference
+ */
+ public static String equateIntervals(List<GenomeLoc> masterArg, List<GenomeLoc> testArg) {
+ LinkedList<GenomeLoc> master = new LinkedList<GenomeLoc>(masterArg);
+ LinkedList<GenomeLoc> test = new LinkedList<GenomeLoc>(testArg);
+
+ while ( ! master.isEmpty() ) { // there's still unchecked bases in master
+ final GenomeLoc masterHead = master.pop();
+ final GenomeLoc testHead = test.pop();
+
+ if ( testHead.overlapsP(masterHead) ) {
+ // remove the parts of test that overlap master, and push the remaining
+ // parts onto master for further comparison.
+ for ( final GenomeLoc masterPart : Utils.reverse(masterHead.subtract(testHead)) ) {
+ master.push(masterPart);
+ }
+ } else {
+ // testHead is incompatible with masterHead, so we must have extra bases in testHead
+ // that aren't in master
+ return "Incompatible locs detected masterHead=" + masterHead + ", testHead=" + testHead;
+ }
+ }
+
+ if ( test.isEmpty() ) // everything is equal
+ return null; // no differences
+ else
+ return "Remaining elements found in test: first=" + test.peek();
+ }
+
+
+ /**
+ * Check if string argument was intented as a file
+ * Accepted file extensions: .bed .list, .picard, .interval_list, .intervals.
+ * @param str token to identify as a filename.
+ * @return true if the token looks like a filename, or false otherwise.
+ */
+ public static boolean isIntervalFile(String str) {
+ return isIntervalFile(str, true);
+ }
+
+ /**
+ * Check if string argument was intented as a file
+ * Accepted file extensions: .bed .list, .picard, .interval_list, .intervals.
+ * @param str token to identify as a filename.
+ * @param checkExists if true throws an exception if the file doesn't exist.
+ * @return true if the token looks like a filename, or false otherwise.
+ */
+ public static boolean isIntervalFile(String str, boolean checkExists) {
+ // should we define list of file extensions as a public array somewhere?
+ // is regex or endsiwth better?
+ File file = new File(str);
+ if (str.toUpperCase().endsWith(".BED") || str.toUpperCase().endsWith(".LIST") ||
+ str.toUpperCase().endsWith(".PICARD") || str.toUpperCase().endsWith(".INTERVAL_LIST")
+ || str.toUpperCase().endsWith(".INTERVALS")) {
+ if (!checkExists)
+ return true;
+ else if (file.exists())
+ return true;
+ else
+ throw new UserException.CouldNotReadInputFile(file, "The interval file does not exist.");
+ }
+
+ if(file.exists())
+ throw new UserException.CouldNotReadInputFile(file, String.format("The interval file %s does not have one of " +
+ "the supported extensions (.bed, .list, .picard, .interval_list, or .intervals). " +
+ "Please rename your file with the appropriate extension. If %s is NOT supposed to be a file, " +
+ "please move or rename the file at location %s", str, str, file.getAbsolutePath()));
+
+ else return false;
+ }
+
+ /**
+ * Returns a map of contig names with their sizes.
+ * @param reference The reference for the intervals.
+ * @return A map of contig names with their sizes.
+ */
+ public static Map<String, Integer> getContigSizes(File reference) {
+ ReferenceDataSource referenceSource = new ReferenceDataSource(reference);
+ List<GenomeLoc> locs = GenomeLocSortedSet.createSetFromSequenceDictionary(referenceSource.getReference().getSequenceDictionary()).toList();
+ Map<String, Integer> lengths = new LinkedHashMap<String, Integer>();
+ for (GenomeLoc loc: locs)
+ lengths.put(loc.getContig(), loc.size());
+ return lengths;
+ }
+
+ /**
+ * Splits an interval list into multiple files.
+ * @param fileHeader The sam file header.
+ * @param locs The genome locs to split.
+ * @param scatterParts The output interval lists to write to.
+ */
+ public static void scatterContigIntervals(SAMFileHeader fileHeader, List<GenomeLoc> locs, List<File> scatterParts) {
+
+ // Contract: must divide locs up so that each of scatterParts gets a sublist such that:
+ // (a) all locs concerning a particular contig go to the same part
+ // (b) locs are not split or combined, and remain in the same order (so scatterParts[0] + ... + scatterParts[n] == locs)
+
+ // Locs are already sorted.
+
+ long totalBases = 0;
+ for(GenomeLoc loc : locs)
+ totalBases += loc.size();
+
+ long idealBasesPerPart = totalBases / scatterParts.size();
+ if(idealBasesPerPart == 0)
+ throw new UserException.BadInput(String.format("Genome region is too short (%d bases) to split into %d parts", totalBases, scatterParts.size()));
+
+ // Find the indices in locs where we switch from one contig to the next.
+ ArrayList<Integer> contigStartLocs = new ArrayList<Integer>();
+ String prevContig = null;
+
+ for(int i = 0; i < locs.size(); ++i) {
+
+ GenomeLoc loc = locs.get(i);
+ if(prevContig == null || !loc.getContig().equals(prevContig))
+ contigStartLocs.add(i);
+ prevContig = loc.getContig();
+
+ }
+
+ if(contigStartLocs.size() < scatterParts.size())
+ throw new UserException.BadInput(String.format("Input genome region has too few contigs (%d) to split into %d parts", contigStartLocs.size(), scatterParts.size()));
+
+ long thisPartBases = 0;
+ int partIdx = 0;
+ IntervalList outList = new IntervalList(fileHeader);
+
+ for(int i = 0; i < locs.size(); ++i) {
+
+ GenomeLoc loc = locs.get(i);
+ thisPartBases += loc.getStop() - loc.getStart();
+
+ outList.add(toInterval(loc, i));
+
+ boolean partMustStop = false;
+
+ if(partIdx < (scatterParts.size() - 1)) {
+
+ // If there are n contigs and n parts remaining then we must split here,
+ // otherwise we will run out of contigs.
+
+ int nextPart = partIdx + 1;
+ int nextPartMustStartBy = contigStartLocs.get(nextPart + (contigStartLocs.size() - scatterParts.size()));
+ if(i + 1 == nextPartMustStartBy)
+ partMustStop = true;
+
+ }
+ else if(i == locs.size() - 1) {
+
+ // We're done! Write the last scatter file.
+ partMustStop = true;
+
+ }
+
+ if(partMustStop || thisPartBases > idealBasesPerPart) {
+
+ // Ideally we would split here. However, we must make sure to do so
+ // on a contig boundary. Test always passes with partMustStop == true
+ // since that indicates we're at a contig boundary.
+
+ GenomeLoc nextLoc = null;
+ if((i + 1) < locs.size())
+ nextLoc = locs.get(i+1);
+
+ if(nextLoc == null || !nextLoc.getContig().equals(loc.getContig())) {
+
+ // Write out this part:
+ outList.write(scatterParts.get(partIdx));
+
+ // Reset. If this part ran long, leave the excess in thisPartBases
+ // and the next will be a little shorter to compensate.
+ outList = new IntervalList(fileHeader);
+ thisPartBases -= idealBasesPerPart;
+ ++partIdx;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /**
+ * Splits an interval list into multiple sublists.
+ * @param locs The genome locs to split.
+ * @param splits The stop points for the genome locs returned by splitFixedIntervals.
+ * @return A list of lists of genome locs, split according to splits
+ */
+ public static List<List<GenomeLoc>> splitIntervalsToSubLists(List<GenomeLoc> locs, List<Integer> splits) {
+ int start = 0;
+ List<List<GenomeLoc>> sublists = new ArrayList<List<GenomeLoc>>(splits.size());
+ for (Integer stop: splits) {
+ List<GenomeLoc> curList = new ArrayList<GenomeLoc>();
+ for (int i = start; i < stop; i++)
+ curList.add(locs.get(i));
+ start = stop;
+ sublists.add(curList);
+ }
+
+ return sublists;
+ }
+
+
+ /**
+ * Splits an interval list into multiple files.
+ * @param fileHeader The sam file header.
+ * @param splits Pre-divided genome locs returned by splitFixedIntervals.
+ * @param scatterParts The output interval lists to write to.
+ */
+ public static void scatterFixedIntervals(SAMFileHeader fileHeader, List<List<GenomeLoc>> splits, List<File> scatterParts) {
+ if (splits.size() != scatterParts.size())
+ throw new UserException.BadArgumentValue("splits", String.format("Split points %d does not equal the number of scatter parts %d.", splits.size(), scatterParts.size()));
+
+ int fileIndex = 0;
+ int locIndex = 1;
+ for (final List<GenomeLoc> split : splits) {
+ IntervalList intervalList = new IntervalList(fileHeader);
+ for (final GenomeLoc loc : split)
+ intervalList.add(toInterval(loc, locIndex++));
+ intervalList.write(scatterParts.get(fileIndex++));
+ }
+ }
+
+ /**
+ * Splits the genome locs up by size.
+ * @param locs Genome locs to split.
+ * @param numParts Number of parts to split the locs into.
+ * @return The stop points to split the genome locs.
+ */
+ public static List<List<GenomeLoc>> splitFixedIntervals(List<GenomeLoc> locs, int numParts) {
+ if (locs.size() < numParts)
+ throw new UserException.BadArgumentValue("scatterParts", String.format("Cannot scatter %d locs into %d parts.", locs.size(), numParts));
+ final long locsSize = intervalSize(locs);
+ final List<Integer> splitPoints = new ArrayList<Integer>();
+ addFixedSplit(splitPoints, locs, locsSize, 0, locs.size(), numParts);
+ Collections.sort(splitPoints);
+ splitPoints.add(locs.size());
+ return splitIntervalsToSubLists(locs, splitPoints);
+ }
+
+ @Requires({"locs != null", "numParts > 0"})
+ @Ensures("result != null")
+ public static List<List<GenomeLoc>> splitLocusIntervals(List<GenomeLoc> locs, int numParts) {
+ // the ideal size of each split
+ final long bp = IntervalUtils.intervalSize(locs);
+ final long idealSplitSize = Math.max((long)Math.floor(bp / (1.0*numParts)), 1);
+
+ // algorithm:
+ // split = ()
+ // set size = 0
+ // pop the head H off locs.
+ // If size + size(H) < splitSize:
+ // add H to split, continue
+ // If size + size(H) == splitSize:
+ // done with split, put in splits, restart
+ // if size + size(H) > splitSize:
+ // cut H into two pieces, first of which has splitSize - size bp
+ // push both pieces onto locs, continue
+ // The last split is special -- when you have only one split left, it gets all of the remaining locs
+ // to deal with rounding issues
+ final List<List<GenomeLoc>> splits = new ArrayList<List<GenomeLoc>>(numParts);
+
+ LinkedList<GenomeLoc> locsLinkedList = new LinkedList<GenomeLoc>(locs);
+ while ( ! locsLinkedList.isEmpty() ) {
+ if ( splits.size() + 1 == numParts ) {
+ // the last one gets all of the remaining parts
+ splits.add(new ArrayList<GenomeLoc>(locsLinkedList));
+ locsLinkedList.clear();
+ } else {
+ final SplitLocusRecursive one = splitLocusIntervals1(locsLinkedList, idealSplitSize);
+ splits.add(one.split);
+ locsLinkedList = one.remaining;
+ }
+ }
+
+ return splits;
+ }
+
+ @Requires({"remaining != null", "!remaining.isEmpty()", "idealSplitSize > 0"})
+ @Ensures({"result != null"})
+ static SplitLocusRecursive splitLocusIntervals1(LinkedList<GenomeLoc> remaining, long idealSplitSize) {
+ final List<GenomeLoc> split = new ArrayList<GenomeLoc>();
+ long size = 0;
+
+ while ( ! remaining.isEmpty() ) {
+ GenomeLoc head = remaining.pop();
+ final long newSize = size + head.size();
+
+ if ( newSize == idealSplitSize ) {
+ split.add(head);
+ break; // we are done
+ } else if ( newSize > idealSplitSize ) {
+ final long remainingBp = idealSplitSize - size;
+ final long cutPoint = head.getStart() + remainingBp;
+ GenomeLoc[] parts = head.split((int)cutPoint);
+ remaining.push(parts[1]);
+ remaining.push(parts[0]);
+ // when we go around, head.size' = idealSplitSize - size
+ // so newSize' = splitSize + head.size' = size + (idealSplitSize - size) = idealSplitSize
+ } else {
+ split.add(head);
+ size = newSize;
+ }
+ }
+
+ return new SplitLocusRecursive(split, remaining);
+ }
+
+ /**
+ * Setup the intervals to be processed
+ */
+ public static GenomeLocSortedSet parseIntervalBindings(
+ final ReferenceDataSource referenceDataSource,
+ final List<IntervalBinding<Feature>> intervals,
+ final IntervalSetRule intervalSetRule, final IntervalMergingRule intervalMergingRule, final int intervalPadding,
+ final List<IntervalBinding<Feature>> excludeIntervals) {
+
+ Pair<GenomeLocSortedSet, GenomeLocSortedSet> includeExcludePair = parseIntervalBindingsPair(
+ referenceDataSource, intervals, intervalSetRule, intervalMergingRule, intervalPadding, excludeIntervals);
+
+ GenomeLocSortedSet includeSortedSet = includeExcludePair.getFirst();
+ GenomeLocSortedSet excludeSortedSet = includeExcludePair.getSecond();
+
+ if (excludeSortedSet != null) {
+ return includeSortedSet.subtractRegions(excludeSortedSet);
+ } else {
+ return includeSortedSet;
+ }
+ }
+
+ public static GenomeLocSortedSet parseIntervalArguments(final ReferenceDataSource referenceDataSource, IntervalArgumentCollection argCollection) {
+ GenomeLocSortedSet intervals = null;
+
+ // return if no interval arguments at all
+ if ( argCollection.intervals == null && argCollection.excludeIntervals == null )
+ return intervals;
+
+ // Note that the use of '-L all' is no longer supported.
+
+ // if include argument isn't given, create new set of all possible intervals
+
+ final Pair<GenomeLocSortedSet, GenomeLocSortedSet> includeExcludePair = IntervalUtils.parseIntervalBindingsPair(
+ referenceDataSource,
+ argCollection.intervals,
+ argCollection.intervalSetRule, argCollection.intervalMerging, argCollection.intervalPadding,
+ argCollection.excludeIntervals);
+
+ final GenomeLocSortedSet includeSortedSet = includeExcludePair.getFirst();
+ final GenomeLocSortedSet excludeSortedSet = includeExcludePair.getSecond();
+
+ // if no exclude arguments, can return parseIntervalArguments directly
+ if ( excludeSortedSet == null )
+ intervals = includeSortedSet;
+
+ // otherwise there are exclude arguments => must merge include and exclude GenomeLocSortedSets
+ else {
+ intervals = includeSortedSet.subtractRegions(excludeSortedSet);
+
+ // logging messages only printed when exclude (-XL) arguments are given
+ final long toPruneSize = includeSortedSet.coveredSize();
+ final long toExcludeSize = excludeSortedSet.coveredSize();
+ final long intervalSize = intervals.coveredSize();
+ logger.info(String.format("Initial include intervals span %d loci; exclude intervals span %d loci", toPruneSize, toExcludeSize));
+ logger.info(String.format("Excluding %d loci from original intervals (%.2f%% reduction)",
+ toPruneSize - intervalSize, (toPruneSize - intervalSize) / (0.01 * toPruneSize)));
+ }
+
+ logger.info(String.format("Processing %d bp from intervals", intervals.coveredSize()));
+ return intervals;
+ }
+
+ public static Pair<GenomeLocSortedSet, GenomeLocSortedSet> parseIntervalBindingsPair(
+ final ReferenceDataSource referenceDataSource,
+ final List<IntervalBinding<Feature>> intervals,
+ final IntervalSetRule intervalSetRule, final IntervalMergingRule intervalMergingRule, final int intervalPadding,
+ final List<IntervalBinding<Feature>> excludeIntervals) {
+ GenomeLocParser genomeLocParser = new GenomeLocParser(referenceDataSource.getReference());
+
+ // if include argument isn't given, create new set of all possible intervals
+ GenomeLocSortedSet includeSortedSet = ((intervals == null || intervals.size() == 0) ?
+ GenomeLocSortedSet.createSetFromSequenceDictionary(referenceDataSource.getReference().getSequenceDictionary()) :
+ loadIntervals(intervals, intervalSetRule, intervalMergingRule, intervalPadding, genomeLocParser));
+
+ GenomeLocSortedSet excludeSortedSet = null;
+ if (excludeIntervals != null && excludeIntervals.size() > 0) {
+ excludeSortedSet = loadIntervals(excludeIntervals, IntervalSetRule.UNION, intervalMergingRule, 0, genomeLocParser);
+ }
+ return new Pair<GenomeLocSortedSet, GenomeLocSortedSet>(includeSortedSet, excludeSortedSet);
+ }
+
+ public static GenomeLocSortedSet loadIntervals(
+ final List<IntervalBinding<Feature>> intervalBindings,
+ final IntervalSetRule rule, final IntervalMergingRule intervalMergingRule, final int padding,
+ final GenomeLocParser genomeLocParser) {
+ List<GenomeLoc> allIntervals = new ArrayList<GenomeLoc>();
+ for ( IntervalBinding intervalBinding : intervalBindings) {
+ @SuppressWarnings("unchecked")
+ List<GenomeLoc> intervals = intervalBinding.getIntervals(genomeLocParser);
+
+ if ( intervals.isEmpty() ) {
+ logger.warn("The interval file " + intervalBinding.getSource() + " contains no intervals that could be parsed.");
+ }
+
+ if ( padding > 0 ) {
+ intervals = getIntervalsWithFlanks(genomeLocParser, intervals, padding);
+ }
+
+ allIntervals = mergeListsBySetOperator(intervals, allIntervals, rule);
+ }
+
+ return sortAndMergeIntervals(genomeLocParser, allIntervals, intervalMergingRule);
+ }
+
+ private final static class SplitLocusRecursive {
+ final List<GenomeLoc> split;
+ final LinkedList<GenomeLoc> remaining;
+
+ @Requires({"split != null", "remaining != null"})
+ private SplitLocusRecursive(final List<GenomeLoc> split, final LinkedList<GenomeLoc> remaining) {
+ this.split = split;
+ this.remaining = remaining;
+ }
+ }
+
+ public static List<GenomeLoc> flattenSplitIntervals(List<List<GenomeLoc>> splits) {
+ final List<GenomeLoc> locs = new ArrayList<GenomeLoc>();
+ for ( final List<GenomeLoc> split : splits )
+ locs.addAll(split);
+ return locs;
+ }
+
+ private static void addFixedSplit(List<Integer> splitPoints, List<GenomeLoc> locs, long locsSize, int startIndex, int stopIndex, int numParts) {
+ if (numParts < 2)
+ return;
+ int halfParts = (numParts + 1) / 2;
+ Pair<Integer, Long> splitPoint = getFixedSplit(locs, locsSize, startIndex, stopIndex, halfParts, numParts - halfParts);
+ int splitIndex = splitPoint.first;
+ long splitSize = splitPoint.second;
+ splitPoints.add(splitIndex);
+ addFixedSplit(splitPoints, locs, splitSize, startIndex, splitIndex, halfParts);
+ addFixedSplit(splitPoints, locs, locsSize - splitSize, splitIndex, stopIndex, numParts - halfParts);
+ }
+
+ private static Pair<Integer, Long> getFixedSplit(List<GenomeLoc> locs, long locsSize, int startIndex, int stopIndex, int minLocs, int maxLocs) {
+ int splitIndex = startIndex;
+ long splitSize = 0;
+ for (int i = 0; i < minLocs; i++) {
+ splitSize += locs.get(splitIndex).size();
+ splitIndex++;
+ }
+ long halfSize = locsSize / 2;
+ while (splitIndex < (stopIndex - maxLocs) && splitSize < halfSize) {
+ splitSize += locs.get(splitIndex).size();
+ splitIndex++;
+ }
+ return new Pair<Integer, Long>(splitIndex, splitSize);
+ }
+
+ /**
+ * Converts a GenomeLoc to a picard interval.
+ * @param loc The GenomeLoc.
+ * @param locIndex The loc index for use in the file.
+ * @return The picard interval.
+ */
+ private static htsjdk.samtools.util.Interval toInterval(GenomeLoc loc, int locIndex) {
+ return new htsjdk.samtools.util.Interval(loc.getContig(), loc.getStart(), loc.getStop(), false, "interval_" + locIndex);
+ }
+
+ /**
+ * merge a list of genome locs that may be overlapping, returning the list of unique genomic locations
+ *
+ * @param raw the unchecked genome loc list
+ * @param rule the merging rule we're using
+ *
+ * @return the list of merged locations
+ */
+ public static List<GenomeLoc> mergeIntervalLocations(final List<GenomeLoc> raw, IntervalMergingRule rule) {
+ if (raw.size() <= 1)
+ return Collections.unmodifiableList(raw);
+ else {
+ ArrayList<GenomeLoc> merged = new ArrayList<GenomeLoc>();
+ Iterator<GenomeLoc> it = raw.iterator();
+ GenomeLoc prev = it.next();
+ while (it.hasNext()) {
+ GenomeLoc curr = it.next();
+ if (prev.overlapsP(curr)) {
+ prev = prev.merge(curr);
+ } else if (prev.contiguousP(curr) && (rule == null || rule == IntervalMergingRule.ALL)) {
+ prev = prev.merge(curr);
+ } else {
+ merged.add(prev);
+ prev = curr;
+ }
+ }
+ merged.add(prev);
+ return Collections.unmodifiableList(merged);
+ }
+ }
+
+ public static long intervalSize(final List<GenomeLoc> locs) {
+ long size = 0;
+ for ( final GenomeLoc loc : locs )
+ size += loc.size();
+ return size;
+ }
+
+ public static void writeFlankingIntervals(File reference, File inputIntervals, File flankingIntervals, int basePairs) {
+ ReferenceDataSource referenceDataSource = new ReferenceDataSource(reference);
+ GenomeLocParser parser = new GenomeLocParser(referenceDataSource.getReference());
+ List<GenomeLoc> originalList = intervalFileToList(parser, inputIntervals.getAbsolutePath());
+
+ if (originalList.isEmpty())
+ throw new UserException.MalformedFile(inputIntervals, "File contains no intervals");
+
+ List<GenomeLoc> flankingList = getFlankingIntervals(parser, originalList, basePairs);
+
+ if (flankingList.isEmpty())
+ throw new UserException.MalformedFile(inputIntervals, "Unable to produce any flanks for the intervals");
+
+ SAMFileHeader samFileHeader = new SAMFileHeader();
+ samFileHeader.setSequenceDictionary(referenceDataSource.getReference().getSequenceDictionary());
+ IntervalList intervalList = new IntervalList(samFileHeader);
+ int i = 0;
+ for (GenomeLoc loc: flankingList)
+ intervalList.add(toInterval(loc, ++i));
+ intervalList.write(flankingIntervals);
+ }
+
+ /**
+ * Returns a list of intervals between the passed int locs. Does not extend UNMAPPED locs.
+ * @param parser A genome loc parser for creating the new intervals
+ * @param locs Original genome locs
+ * @param basePairs Number of base pairs on each side of loc
+ * @return The list of intervals between the locs
+ */
+ public static List<GenomeLoc> getFlankingIntervals(final GenomeLocParser parser, final List<GenomeLoc> locs, final int basePairs) {
+ List<GenomeLoc> sorted = sortAndMergeIntervals(parser, locs, IntervalMergingRule.ALL).toList();
+
+ if (sorted.size() == 0)
+ return Collections.emptyList();
+
+ LinkedHashMap<String, List<GenomeLoc>> locsByContig = splitByContig(sorted);
+ List<GenomeLoc> expanded = new ArrayList<GenomeLoc>();
+ for (Map.Entry<String, List<GenomeLoc>> contig: locsByContig.entrySet()) {
+ List<GenomeLoc> contigLocs = contig.getValue();
+ int contigLocsSize = contigLocs.size();
+
+ GenomeLoc startLoc, stopLoc;
+
+ // Create loc at start of the list
+ startLoc = parser.createGenomeLocAtStart(contigLocs.get(0), basePairs);
+ if (startLoc != null)
+ expanded.add(startLoc);
+
+ // Create locs between each loc[i] and loc[i+1]
+ for (int i = 0; i < contigLocsSize - 1; i++) {
+ stopLoc = parser.createGenomeLocAtStop(contigLocs.get(i), basePairs);
+ startLoc = parser.createGenomeLocAtStart(contigLocs.get(i + 1), basePairs);
+ if (stopLoc.getStop() + 1 >= startLoc.getStart()) {
+ // NOTE: This is different than GenomeLoc.merge()
+ // merge() returns a loc which covers the entire range of stop and start,
+ // possibly returning positions inside loc(i) or loc(i+1)
+ // We want to make sure that the start of the stopLoc is used, and the stop of the startLoc
+ GenomeLoc merged = parser.createGenomeLoc(
+ stopLoc.getContig(), stopLoc.getStart(), startLoc.getStop());
+ expanded.add(merged);
+ } else {
+ expanded.add(stopLoc);
+ expanded.add(startLoc);
+ }
+ }
+
+ // Create loc at the end of the list
+ stopLoc = parser.createGenomeLocAtStop(contigLocs.get(contigLocsSize - 1), basePairs);
+ if (stopLoc != null)
+ expanded.add(stopLoc);
+ }
+ return expanded;
+ }
+
+ /**
+ * Returns a list of intervals between the passed int locs. Does not extend UNMAPPED locs.
+ * @param parser A genome loc parser for creating the new intervals
+ * @param locs Original genome locs
+ * @param basePairs Number of base pairs on each side of loc
+ * @return The list of intervals between the locs
+ */
+ public static List<GenomeLoc> getIntervalsWithFlanks(final GenomeLocParser parser, final List<GenomeLoc> locs, final int basePairs) {
+
+ if (locs.size() == 0)
+ return Collections.emptyList();
+
+ final List<GenomeLoc> expanded = new ArrayList<GenomeLoc>();
+ for ( final GenomeLoc loc : locs ) {
+ expanded.add(parser.createPaddedGenomeLoc(loc, basePairs));
+ }
+
+ return sortAndMergeIntervals(parser, expanded, IntervalMergingRule.ALL).toList();
+ }
+
+ private static LinkedHashMap<String, List<GenomeLoc>> splitByContig(List<GenomeLoc> sorted) {
+ LinkedHashMap<String, List<GenomeLoc>> splits = new LinkedHashMap<String, List<GenomeLoc>>();
+ GenomeLoc last = null;
+ List<GenomeLoc> contigLocs = null;
+ for (GenomeLoc loc: sorted) {
+ if (GenomeLoc.isUnmapped(loc))
+ continue;
+ if (last == null || !last.onSameContig(loc)) {
+ contigLocs = new ArrayList<GenomeLoc>();
+ splits.put(loc.getContig(), contigLocs);
+ }
+ contigLocs.add(loc);
+ last = loc;
+ }
+ return splits;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/FileExtension.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/FileExtension.java
new file mode 100644
index 0000000..e099a45
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/FileExtension.java
@@ -0,0 +1,37 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.io;
+
+import java.io.File;
+
+public interface FileExtension {
+ /**
+ * Returns a clone of the FileExtension with a new path.
+ * @param path New path.
+ * @return New FileExtension
+ */
+ public File withPath(String path);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/HardThresholdingOutputStream.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/HardThresholdingOutputStream.java
new file mode 100644
index 0000000..1d041b6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/HardThresholdingOutputStream.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.io;
+
+import org.apache.commons.io.output.ThresholdingOutputStream;
+
+import java.io.IOException;
+
+/**
+ * An output stream which stops at the threshold
+ * instead of potentially triggering early.
+ */
+public abstract class HardThresholdingOutputStream extends ThresholdingOutputStream {
+ protected HardThresholdingOutputStream(int threshold) {
+ super(threshold);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ int remaining = this.getThreshold() - (int)this.getByteCount();
+ if (!isThresholdExceeded() && len > remaining) {
+ super.write(b, off, remaining);
+ super.write(b, off + remaining, len - remaining);
+ } else {
+ super.write(b, off, len);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/IOUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/IOUtils.java
new file mode 100644
index 0000000..7defcea
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/IOUtils.java
@@ -0,0 +1,575 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.io;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.LineIterator;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.*;
+
+public class IOUtils {
+ private static Logger logger = Logger.getLogger(IOUtils.class);
+ private static final File DEV_DIR = new File("/dev");
+
+ /**
+ * Checks if the temp directory has been setup and throws an exception if they user hasn't set it correctly.
+ *
+ * @param tempDir Temporary directory.
+ */
+ public static void checkTempDir(File tempDir) {
+ if (isDefaultTempDir(tempDir))
+ throw new UserException.BadTmpDir("java.io.tmpdir must be explicitly set");
+ if (!tempDir.exists() && !tempDir.mkdirs())
+ throw new UserException.BadTmpDir("Could not create directory: " + tempDir.getAbsolutePath());
+ }
+
+ /**
+ * Returns true if the directory is a default temporary directory.
+ * @param tempDir the directory to check.
+ * @return true if the directory is a default temporary directory.
+ */
+ public static boolean isDefaultTempDir(File tempDir) {
+ String tempDirPath = tempDir.getAbsolutePath();
+ // Keeps the user from leaving the temp directory as the default, and on Macs from having pluses
+ // in the path which can cause problems with the Google Reflections library.
+ // see also: http://benjchristensen.com/2009/09/22/mac-osx-10-6-java-java-io-tmpdir/
+ return (tempDirPath.startsWith("/var/folders/") || (tempDirPath.equals("/tmp")) || (tempDirPath.equals("/tmp/")));
+ }
+
+ /**
+ * Creates a temp directory with the prefix and optional suffix.
+ *
+ * @param prefix Prefix for the directory name.
+ * @param suffix Optional suffix for the directory name.
+ * @return The created temporary directory.
+ */
+ public static File tempDir(String prefix, String suffix) {
+ return tempDir(prefix, suffix, null);
+ }
+
+ /**
+ * Creates a temp directory with the prefix and optional suffix.
+ *
+ * @param prefix Prefix for the directory name.
+ * @param suffix Optional suffix for the directory name.
+ * @param tempDirParent Parent directory for the temp directory.
+ * @return The created temporary directory.
+ */
+ public static File tempDir(String prefix, String suffix, File tempDirParent) {
+ try {
+ if (tempDirParent == null)
+ tempDirParent = FileUtils.getTempDirectory();
+ if (!tempDirParent.exists() && !tempDirParent.mkdirs())
+ throw new UserException.BadTmpDir("Could not create temp directory: " + tempDirParent);
+ File temp = File.createTempFile(prefix, suffix, tempDirParent);
+ if (!temp.delete())
+ throw new UserException.BadTmpDir("Could not delete sub file: " + temp.getAbsolutePath());
+ if (!temp.mkdir())
+ throw new UserException.BadTmpDir("Could not create sub directory: " + temp.getAbsolutePath());
+ return absolute(temp);
+ } catch (IOException e) {
+ throw new UserException.BadTmpDir(e.getMessage());
+ }
+ }
+
+ /**
+ * Writes content to a temp file and returns the path to the temporary file.
+ *
+ * @param content to write.
+ * @param prefix Prefix for the temp file.
+ * @param suffix Suffix for the temp file.
+ * @return the path to the temp file.
+ */
+ public static File writeTempFile(String content, String prefix, String suffix) {
+ return writeTempFile(content, prefix, suffix, null);
+ }
+
+ /**
+ * Writes content to a temp file and returns the path to the temporary file.
+ *
+ * @param content to write.
+ * @param prefix Prefix for the temp file.
+ * @param suffix Suffix for the temp file.
+ * @param directory Directory for the temp file.
+ * @return the path to the temp file.
+ */
+ public static File writeTempFile(String content, String prefix, String suffix, File directory) {
+ try {
+ File tempFile = absolute(File.createTempFile(prefix, suffix, directory));
+ FileUtils.writeStringToFile(tempFile, content);
+ return tempFile;
+ } catch (IOException e) {
+ throw new UserException.BadTmpDir(e.getMessage());
+ }
+ }
+
+ /**
+ * Waits for NFS to propagate a file creation, imposing a timeout.
+ *
+ * Based on Apache Commons IO FileUtils.waitFor()
+ *
+ * @param file The file to wait for.
+ * @param seconds The maximum time in seconds to wait.
+ * @return true if the file exists
+ */
+ public static boolean waitFor(File file, int seconds) {
+ return waitFor(Collections.singletonList(file), seconds).isEmpty();
+ }
+
+ /**
+ * Waits for NFS to propagate a file creation, imposing a timeout.
+ *
+ * Based on Apache Commons IO FileUtils.waitFor()
+ *
+ * @param files The list of files to wait for.
+ * @param seconds The maximum time in seconds to wait.
+ * @return Files that still do not exists at the end of the timeout, or a empty list if all files exists.
+ */
+ public static List<File> waitFor(Collection<File> files, int seconds) {
+ long timeout = 0;
+ long tick = 0;
+ List<File> missingFiles = new ArrayList<File>();
+ for (File file : files)
+ if (!file.exists())
+ missingFiles.add(file);
+
+ while (!missingFiles.isEmpty() && timeout <= seconds) {
+ if (tick >= 10) {
+ tick = 0;
+ timeout++;
+ }
+ tick++;
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ignore) {
+ }
+ List<File> newMissingFiles = new ArrayList<File>();
+ for (File file : missingFiles)
+ if (!file.exists())
+ newMissingFiles.add(file);
+ missingFiles = newMissingFiles;
+ }
+ return missingFiles;
+ }
+
+ /**
+ * Returns the directory at the number of levels deep.
+ * For example 2 levels of /path/to/dir will return /path/to
+ *
+ * @param dir Directory path.
+ * @param level how many levels deep from the root.
+ * @return The path to the parent directory that is level-levels deep.
+ */
+ public static File dirLevel(File dir, int level) {
+ List<File> directories = new ArrayList<File>();
+ File parentDir = absolute(dir);
+ while (parentDir != null) {
+ directories.add(0, parentDir);
+ parentDir = parentDir.getParentFile();
+ }
+ if (directories.size() <= level)
+ return directories.get(directories.size() - 1);
+ else
+ return directories.get(level);
+ }
+
+ /**
+ * Returns the sub path rooted at the parent.
+ *
+ * @param parent The parent directory.
+ * @param path The sub path to append to the parent, if the path is not absolute.
+ * @return The absolute path to the file in the parent dir if the path was not absolute, otherwise the original path.
+ */
+ public static File absolute(File parent, String path) {
+ return absolute(parent, new File(path));
+ }
+
+ /**
+ * Returns the sub path rooted at the parent.
+ *
+ * @param parent The parent directory.
+ * @param file The sub path to append to the parent, if the path is not absolute.
+ * @return The absolute path to the file in the parent dir if the path was not absolute, otherwise the original path.
+ */
+ public static File absolute(File parent, File file) {
+ String newPath;
+ if (file.isAbsolute())
+ newPath = absolutePath(file);
+ else
+ newPath = absolutePath(new File(parent, file.getPath()));
+ return replacePath(file, newPath);
+ }
+
+ /**
+ * A mix of getCanonicalFile and getAbsoluteFile that returns the
+ * absolute path to the file without deferencing symbolic links.
+ *
+ * @param file the file.
+ * @return the absolute path to the file.
+ */
+ public static File absolute(File file) {
+ return replacePath(file, absolutePath(file));
+ }
+
+ private static String absolutePath(File file) {
+ File fileAbs = file.getAbsoluteFile();
+ LinkedList<String> names = new LinkedList<String>();
+ while (fileAbs != null) {
+ String name = fileAbs.getName();
+ fileAbs = fileAbs.getParentFile();
+
+ if (".".equals(name)) {
+ /* skip */
+
+ /* TODO: What do we do for ".."?
+ } else if (name == "..") {
+
+ CentOS tcsh says use getCanonicalFile:
+ ~ $ mkdir -p test1/test2
+ ~ $ ln -s test1/test2 test3
+ ~ $ cd test3/..
+ ~/test1 $
+
+ Mac bash says keep going with getAbsoluteFile:
+ ~ $ mkdir -p test1/test2
+ ~ $ ln -s test1/test2 test3
+ ~ $ cd test3/..
+ ~ $
+
+ For now, leave it and let the shell figure it out.
+ */
+ } else {
+ names.add(0, name);
+ }
+ }
+
+ return ("/" + StringUtils.join(names, "/"));
+ }
+
+ private static File replacePath(File file, String path) {
+ if (file instanceof FileExtension)
+ return ((FileExtension)file).withPath(path);
+ if (!File.class.equals(file.getClass()))
+ throw new GATKException("Sub classes of java.io.File must also implement FileExtension");
+ return new File(path);
+ }
+
+ /**
+ * Returns the last lines of the file.
+ * NOTE: This is only safe to run on smaller files!
+ *
+ * @param file File to read.
+ * @param count Maximum number of lines to return.
+ * @return The last count lines from file.
+ * @throws IOException When unable to read the file.
+ */
+ public static List<String> tail(File file, int count) throws IOException {
+ LinkedList<String> tailLines = new LinkedList<String>();
+ FileReader reader = new FileReader(file);
+ try {
+ LineIterator iterator = org.apache.commons.io.IOUtils.lineIterator(reader);
+ int lineCount = 0;
+ while (iterator.hasNext()) {
+ String line = iterator.nextLine();
+ lineCount++;
+ if (lineCount > count)
+ tailLines.removeFirst();
+ tailLines.offer(line);
+ }
+ } finally {
+ org.apache.commons.io.IOUtils.closeQuietly(reader);
+ }
+ return tailLines;
+ }
+
+ /**
+ * Tries to delete a file. Emits a warning if the file
+ * is not a special file and was unable to be deleted.
+ *
+ * @param file File to delete.
+ * @return true if the file was deleted.
+ */
+ public static boolean tryDelete(File file) {
+ if (isSpecialFile(file)) {
+ logger.debug("Not trying to delete " + file);
+ return false;
+ }
+ boolean deleted = FileUtils.deleteQuietly(file);
+ if (deleted)
+ logger.debug("Deleted " + file);
+ else if (file.exists())
+ logger.warn("Unable to delete " + file);
+ return deleted;
+ }
+
+ /**
+ * Writes the an embedded resource to a temp file.
+ * File is not scheduled for deletion and must be cleaned up by the caller.
+ * @param resource Embedded resource.
+ * @return Path to the temp file with the contents of the resource.
+ */
+ public static File writeTempResource(Resource resource) {
+ File temp;
+ try {
+ temp = File.createTempFile(FilenameUtils.getBaseName(resource.getPath()) + ".", "." + FilenameUtils.getExtension(resource.getPath()));
+ } catch (IOException e) {
+ throw new UserException.BadTmpDir(e.getMessage());
+ }
+ writeResource(resource, temp);
+ return temp;
+ }
+
+ /**
+ * Writes the an embedded resource to a file.
+ * File is not scheduled for deletion and must be cleaned up by the caller.
+ * @param resource Embedded resource.
+ * @param file File path to write.
+ */
+ public static void writeResource(Resource resource, File file) {
+ String path = resource.getPath();
+ InputStream inputStream = resource.getResourceContentsAsStream();
+ OutputStream outputStream = null;
+ try {
+ outputStream = FileUtils.openOutputStream(file);
+ org.apache.commons.io.IOUtils.copy(inputStream, outputStream);
+ } catch (IOException e) {
+ throw new GATKException(String.format("Unable to copy resource '%s' to '%s'", path, file), e);
+ } finally {
+ org.apache.commons.io.IOUtils.closeQuietly(inputStream);
+ org.apache.commons.io.IOUtils.closeQuietly(outputStream);
+ }
+ }
+
+ /**
+ * Returns a file throwing a UserException if the file cannot be read.
+ * @param path File path
+ * @return LineIterator
+ */
+ public static LineIterator lineIterator(String path) {
+ return lineIterator(new File(path));
+ }
+
+ /**
+ * Returns a file throwing a UserException if the file cannot be read.
+ * @param file File
+ * @return LineIterator
+ */
+ public static LineIterator lineIterator(File file) {
+ try {
+ return FileUtils.lineIterator(file);
+ } catch (IOException e) {
+ throw new UserException.CouldNotReadInputFile(file, e);
+ }
+
+ }
+
+ /**
+ * Returns true if the file is a special file.
+ * @param file File path to check.
+ * @return true if the file is a special file.
+ */
+ public static boolean isSpecialFile(File file) {
+ return file != null && (file.getAbsolutePath().startsWith("/dev/") || file.equals(DEV_DIR));
+ }
+
+ /**
+ * Reads the entirety of the given file into a byte array. Uses a read buffer size of 4096 bytes.
+ *
+ * @param source File to read
+ * @return The contents of the file as a byte array
+ */
+ public static byte[] readFileIntoByteArray ( File source ) {
+ return readFileIntoByteArray(source, 4096);
+ }
+
+ /**
+ * Reads the entirety of the given file into a byte array using the requested read buffer size.
+ *
+ * @param source File to read
+ * @param readBufferSize Number of bytes to read in at one time
+ * @return The contents of the file as a byte array
+ */
+ public static byte[] readFileIntoByteArray ( File source, int readBufferSize ) {
+ if ( source == null ) {
+ throw new ReviewedGATKException("Source file was null");
+ }
+
+ byte[] fileContents;
+
+ try {
+ fileContents = readStreamIntoByteArray(new FileInputStream(source), readBufferSize);
+ }
+ catch ( FileNotFoundException e ) {
+ throw new UserException.CouldNotReadInputFile(source, e);
+ }
+
+ if ( fileContents.length != source.length() ) {
+ throw new UserException.CouldNotReadInputFile(String.format("Unable to completely read file %s: read only %d/%d bytes",
+ source.getAbsolutePath(), fileContents.length, source.length()));
+ }
+
+ return fileContents;
+ }
+
+ /**
+ * Reads all data from the given stream into a byte array. Uses a read buffer size of 4096 bytes.
+ *
+ * @param in Stream to read data from
+ * @return The contents of the stream as a byte array
+ */
+ public static byte[] readStreamIntoByteArray ( InputStream in ) {
+ return readStreamIntoByteArray(in, 4096);
+ }
+
+ /**
+ * Reads all data from the given stream into a byte array using the requested read buffer size.
+ *
+ * @param in Stream to read data from
+ * @param readBufferSize Number of bytes to read in at one time
+ * @return The contents of the stream as a byte array
+ */
+ public static byte[] readStreamIntoByteArray ( InputStream in, int readBufferSize ) {
+ if ( in == null ) {
+ throw new ReviewedGATKException("Input stream was null");
+ }
+ else if ( readBufferSize <= 0 ) {
+ throw new ReviewedGATKException("Read buffer size must be > 0");
+ }
+
+ // Use a fixed-size buffer for each read, but a dynamically-growing buffer
+ // to hold the accumulated contents of the file/stream:
+ byte[] readBuffer = new byte[readBufferSize];
+ ByteArrayOutputStream fileBuffer = new ByteArrayOutputStream(readBufferSize * 4);
+
+ try {
+ try {
+ int currentBytesRead;
+
+ while ( (currentBytesRead = in.read(readBuffer, 0, readBuffer.length)) >= 0 ) {
+ fileBuffer.write(readBuffer, 0, currentBytesRead);
+ }
+ }
+ finally {
+ in.close();
+ }
+ }
+ catch ( IOException e ) {
+ throw new UserException.CouldNotReadInputFile("I/O error reading from input stream", e);
+ }
+
+ return fileBuffer.toByteArray();
+ }
+
+ /**
+ * Writes the given array of bytes to a file
+ *
+ * @param bytes Data to write
+ * @param destination File to write the data to
+ */
+ public static void writeByteArrayToFile ( byte[] bytes, File destination ) {
+ if ( destination == null ) {
+ throw new ReviewedGATKException("Destination file was null");
+ }
+
+ try {
+ writeByteArrayToStream(bytes, new FileOutputStream(destination));
+ }
+ catch ( FileNotFoundException e ) {
+ throw new UserException.CouldNotCreateOutputFile(destination, e);
+ }
+ }
+
+ /**
+ * Writes the given array of bytes to a stream
+ *
+ * @param bytes Data to write
+ * @param out Stream to write the data to
+ */
+ public static void writeByteArrayToStream ( byte[] bytes, OutputStream out ) {
+ if ( bytes == null || out == null ) {
+ throw new ReviewedGATKException("Data to write or output stream was null");
+ }
+
+ try {
+ try {
+ out.write(bytes);
+ }
+ finally {
+ out.close();
+ }
+ }
+ catch ( IOException e ) {
+ throw new UserException.CouldNotCreateOutputFile("I/O error writing to output stream", e);
+ }
+ }
+
+ /**
+ * Determines the uncompressed size of a GZIP file. Uses the GZIP ISIZE field in the last
+ * 4 bytes of the file to get this information.
+ *
+ * @param gzipFile GZIP-format file whose uncompressed size to determine
+ * @return The uncompressed size (in bytes) of the GZIP file
+ */
+ public static int getGZIPFileUncompressedSize ( File gzipFile ) {
+ if ( gzipFile == null ) {
+ throw new ReviewedGATKException("GZIP file to examine was null");
+ }
+
+ try {
+ // The GZIP ISIZE field holds the uncompressed size of the compressed data.
+ // It occupies the last 4 bytes of any GZIP file:
+ RandomAccessFile in = new RandomAccessFile(gzipFile, "r");
+ in.seek(gzipFile.length() - 4);
+ byte[] sizeBytes = new byte[4];
+ in.read(sizeBytes, 0, 4);
+
+ ByteBuffer byteBuf = ByteBuffer.wrap(sizeBytes);
+ byteBuf.order(ByteOrder.LITTLE_ENDIAN); // The GZIP spec mandates little-endian byte order
+ int uncompressedSize = byteBuf.getInt();
+
+ // If the size read in is negative, we've overflowed our signed integer:
+ if ( uncompressedSize < 0 ) {
+ throw new UserException.CouldNotReadInputFile(String.format("Cannot accurately determine the uncompressed size of file %s " +
+ "because it's either larger than %d bytes or the GZIP ISIZE field is corrupt",
+ gzipFile.getAbsolutePath(), Integer.MAX_VALUE));
+ }
+
+ return uncompressedSize;
+ }
+ catch ( IOException e ) {
+ throw new UserException.CouldNotReadInputFile(gzipFile, e);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/Resource.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/Resource.java
new file mode 100644
index 0000000..abebe52
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/io/Resource.java
@@ -0,0 +1,91 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.io;
+
+import java.io.File;
+import java.io.InputStream;
+
+/**
+ * Stores a resource by path and a relative class.
+ */
+public class Resource {
+ private final String path;
+ private final Class<?> relativeClass;
+
+ /**
+ * Create a resource with a path and a relative class.
+ * @param path Relative or absolute path to the class.
+ * @param relativeClass Relative class to use as a class loader and for a relative package.
+ *
+ * If the relative class is null then the system classloader will be used and the path must be absolute.
+ */
+ public Resource(String path, Class<?> relativeClass) {
+ this.path = path;
+ this.relativeClass = relativeClass;
+ }
+
+ public Class<?> getRelativeClass() {
+ return relativeClass;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public String getFullPath() {
+ if (relativeClass == null)
+ return path;
+ if (new File(path).isAbsolute())
+ return path;
+ return String.format("%s%s%s",
+ relativeClass.getPackage().getName().replace('.', File.separatorChar),
+ File.separator,
+ path);
+ }
+
+ /**
+ * Get the contents of this resource as an InputStream
+ * @throws IllegalArgumentException if resource cannot be read
+ * @return an input stream that will read the contents of this resource
+ */
+ public InputStream getResourceContentsAsStream() {
+ final Class<?> clazz = getRelativeClass();
+
+ final InputStream inputStream;
+ if (clazz == null) {
+ inputStream = ClassLoader.getSystemResourceAsStream(path);
+ if (inputStream == null)
+ throw new IllegalArgumentException("Resource not found: " + path);
+ } else {
+ inputStream = clazz.getResourceAsStream(path);
+ if (inputStream == null)
+ throw new IllegalArgumentException("Resource not found relative to " + clazz + ": " + path);
+
+ }
+
+ return inputStream;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/clibrary/JNAUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/clibrary/JNAUtils.java
new file mode 100644
index 0000000..0c14ffa
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/clibrary/JNAUtils.java
@@ -0,0 +1,59 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.clibrary;
+
+import com.sun.jna.Platform;
+
+/**
+ * Collection of functions that are in the standard CLibrary but are associated with different headers on different platforms.
+ */
+public class JNAUtils {
+ /**
+ * Defined in different places on different systems, this is currently 256 on mac and 64 everywhere else.
+ */
+ public static final int MAXHOSTNAMELEN;
+
+ /**
+ * Maximum path length.
+ */
+ public static final int MAXPATHLEN = 1024;
+
+ static {
+ int maxhostnamelen = 64;
+ if (Platform.isMac())
+ maxhostnamelen = 256;
+ MAXHOSTNAMELEN = maxhostnamelen;
+ }
+
+ /**
+ * Converts a non-zero int to true, otherwise false.
+ * @param val int to check.
+ * @return true if val is non-zero.
+ */
+ public static boolean toBoolean(int val) {
+ return val != 0;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/clibrary/LibC.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/clibrary/LibC.java
new file mode 100644
index 0000000..dd2d7e7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/clibrary/LibC.java
@@ -0,0 +1,200 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.clibrary;
+
+import com.sun.jna.LastErrorException;
+import com.sun.jna.Native;
+import com.sun.jna.NativeLong;
+import com.sun.jna.Structure;
+import com.sun.jna.ptr.NativeLongByReference;
+
+/**
+ * Sparse port of the Standard C Library libc -lc.
+ */
+ at SuppressWarnings("unused")
+public class LibC {
+
+ static {
+ Native.register("c");
+ }
+
+ /** Operation not permitted */
+ public static final int EPERM = 1;
+
+ /** No such file or directory */
+ public static final int ENOENT = 2;
+
+ /** No such process */
+ public static final int ESRCH = 3;
+
+ /** Interrupted system call */
+ public static final int EINTR = 4;
+
+ /** I/O error */
+ public static final int EIO = 5;
+
+ /** No such device or address */
+ public static final int ENXIO = 6;
+
+ /** Argument list too long */
+ public static final int E2BIG = 7;
+
+ /** Exec format error */
+ public static final int ENOEXEC = 8;
+
+ /** Bad file number */
+ public static final int EBADF = 9;
+
+ /** No child processes */
+ public static final int ECHILD = 10;
+
+ /** Try again */
+ public static final int EAGAIN = 11;
+
+ /** Out of memory */
+ public static final int ENOMEM = 12;
+
+ /** Permission denied */
+ public static final int EACCES = 13;
+
+ /** Bad address */
+ public static final int EFAULT = 14;
+
+ /** Block device required */
+ public static final int ENOTBLK = 15;
+
+ /** Device or resource busy */
+ public static final int EBUSY = 16;
+
+ /** File exists */
+ public static final int EEXIST = 17;
+
+ /** Cross-device link */
+ public static final int EXDEV = 18;
+
+ /** No such device */
+ public static final int ENODEV = 19;
+
+ /** Not a directory */
+ public static final int ENOTDIR = 20;
+
+ /** Is a directory */
+ public static final int EISDIR = 21;
+
+ /** Invalid argument */
+ public static final int EINVAL = 22;
+
+ /** File table overflow */
+ public static final int ENFILE = 23;
+
+ /** Too many open files */
+ public static final int EMFILE = 24;
+
+ /** Not a typewriter */
+ public static final int ENOTTY = 25;
+
+ /** Text file busy */
+ public static final int ETXTBSY = 26;
+
+ /** File too large */
+ public static final int EFBIG = 27;
+
+ /** No space left on device */
+ public static final int ENOSPC = 28;
+
+ /** Illegal seek */
+ public static final int ESPIPE = 29;
+
+ /** Read-only file system */
+ public static final int EROFS = 30;
+
+ /** Too many links */
+ public static final int EMLINK = 31;
+
+ /** Broken pipe */
+ public static final int EPIPE = 32;
+
+ /** Math argument out of domain of func */
+ public static final int EDOM = 33;
+
+ /** Math result not representable */
+ public static final int ERANGE = 34;
+
+ /**
+ * Inserts or resets the environment variable name in the current environment list. If the variable name does not exist
+ * in the list, it is inserted with the given value. If the variable does exist, the argument overwrite is tested; if overwrite is zero, the
+ * variable is not reset, otherwise it is reset to the given value.
+ * @param name the environment variable name
+ * @param value the given value
+ * @param overwrite if overwrite is zero, the variable is not reset, otherwise it is reset to the given value
+ * @return the value 0 if successful; otherwise the value -1 is returned and the global variable errno is set to indicate the error.
+ * @throws LastErrorException [ENOMEM] The function failed because it was unable to allocate memory for the environment.
+ */
+ public static native int setenv(String name, String value, int overwrite) throws LastErrorException;
+
+ /**
+ * Obtains the current value of the environment variable, name.
+ * @param name the environment variable name
+ * @return the value of the environment variable as a NUL-terminated string. If the variable name is not in the current environment, NULL is returned.
+ */
+ public static native String getenv(String name);
+
+ /**
+ * The unsetenv() function deletes all instances of the variable name pointed to by name from the list. Note that only the variable name
+ * (e.g., "NAME") should be given; "NAME=value" will not work.
+ * @param name the environment variable name
+ * @return the value 0 if successful; otherwise the value -1 is returned and the global variable errno is set to indicate the error.
+ * @throws LastErrorException The function failed.
+ */
+ public static native int unsetenv(String name) throws LastErrorException;
+
+ public static class timeval extends Structure {
+ public static class ByReference extends timeval implements Structure.ByReference {
+ }
+
+ public static class ByValue extends timeval implements Structure.ByValue {
+ }
+
+ public NativeLong tv_sec;
+ public NativeLong tv_usec;
+ }
+
+ /**
+ * The time() function returns the value of time in seconds since 0 hours, 0 minutes, 0 seconds, January 1, 1970, Coordinated Universal Time, without including leap seconds. If an error occurs, time() returns the value (time_t)-1.
+ * The return value is also stored in *tloc, provided that t is non-null.
+ * @param t the value of time in seconds, provided that t is non-null.
+ * @return the value of time in seconds
+ */
+ public static native NativeLong time(NativeLongByReference t);
+
+ /**
+ * Returns the difference between two calendar times, (time1 - time0), expressed in seconds.
+ * @param time1 Time 1
+ * @param time0 Time 0
+ * @return the difference between two calendar times, (time1 - time0), expressed in seconds.
+ */
+ public static native double difftime(NativeLong time1, NativeLong time0);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaJobInfo.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaJobInfo.java
new file mode 100644
index 0000000..1a99bfa
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaJobInfo.java
@@ -0,0 +1,101 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.drmaa.v1_0;
+
+import org.ggf.drmaa.DrmaaException;
+import org.ggf.drmaa.JobInfo;
+
+import java.util.Map;
+
+/**
+ * JNA mapping from Java to C DRMAA binding.
+ */
+public class JnaJobInfo implements JobInfo {
+
+ private final String jobId;
+ private final Map<String, String> rusage;
+ private final boolean hasExited;
+ private final int exitStatus;
+ private final boolean hasSignaled;
+ private final String terminatingSignal;
+ private final boolean hasCoreDump;
+ private final boolean wasAborted;
+
+ public JnaJobInfo(String jobId, Map<String, String> rusage, boolean hasExited, int exitStatus, boolean hasSignaled, String terminatingSignal, boolean hasCoreDump, boolean wasAborted) {
+ this.jobId = jobId;
+ this.rusage = rusage;
+ this.hasExited = hasExited;
+ this.exitStatus = exitStatus;
+ this.hasSignaled = hasSignaled;
+ this.terminatingSignal = terminatingSignal;
+ this.hasCoreDump = hasCoreDump;
+ this.wasAborted = wasAborted;
+ }
+
+ @Override
+ public String getJobId() throws DrmaaException {
+ return this.jobId;
+ }
+
+ @Override
+ public Map getResourceUsage() throws DrmaaException {
+ return rusage;
+ }
+
+ @Override
+ public boolean hasExited() throws DrmaaException {
+ return hasExited;
+ }
+
+ @Override
+ public int getExitStatus() throws DrmaaException {
+ if (!hasExited)
+ throw new IllegalStateException("job has not exited");
+ return exitStatus;
+ }
+
+ @Override
+ public boolean hasSignaled() throws DrmaaException {
+ return hasSignaled;
+ }
+
+ @Override
+ public String getTerminatingSignal() throws DrmaaException {
+ if (!hasSignaled)
+ throw new IllegalStateException("job has not signaled");
+ return terminatingSignal;
+ }
+
+ @Override
+ public boolean hasCoreDump() throws DrmaaException {
+ return hasCoreDump;
+ }
+
+ @Override
+ public boolean wasAborted() throws DrmaaException {
+ return wasAborted;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaJobTemplate.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaJobTemplate.java
new file mode 100644
index 0000000..b8add99
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaJobTemplate.java
@@ -0,0 +1,316 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.drmaa.v1_0;
+
+import com.sun.jna.Pointer;
+import org.ggf.drmaa.*;
+
+import java.util.*;
+
+/**
+ * JNA mapping from Java to C DRMAA binding.
+ */
+public class JnaJobTemplate implements JobTemplate {
+ private final JnaSession session;
+ private final Pointer jt;
+
+ public JnaJobTemplate(JnaSession session, Pointer jt) {
+ this.session = session;
+ this.jt = jt;
+ }
+
+ public Pointer getPointer() {
+ return jt;
+ }
+
+ @Override
+ public void setRemoteCommand(String s) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_REMOTE_COMMAND, s);
+ }
+
+ @Override
+ public String getRemoteCommand() throws DrmaaException {
+ return JnaSession.getAttribute(jt, LibDrmaa.DRMAA_REMOTE_COMMAND);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void setArgs(List list) throws DrmaaException {
+ JnaSession.setVectorAttribute(jt, LibDrmaa.DRMAA_V_ARGV, list);
+ }
+
+ @Override
+ public List getArgs() throws DrmaaException {
+ return JnaSession.getVectorAttribute(jt, LibDrmaa.DRMAA_V_ARGV);
+ }
+
+ @Override
+ public void setJobSubmissionState(int state) throws DrmaaException {
+ String stateString;
+ if (state == JobTemplate.HOLD_STATE)
+ stateString = LibDrmaa.DRMAA_SUBMISSION_STATE_HOLD;
+ else if (state == JobTemplate.ACTIVE_STATE)
+ stateString = LibDrmaa.DRMAA_SUBMISSION_STATE_ACTIVE;
+ else
+ throw new InvalidAttributeValueException("jobSubmissionState attribute is invalid");
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_JS_STATE, stateString);
+ }
+
+ @Override
+ public int getJobSubmissionState() throws DrmaaException {
+ int state;
+ String stateString = JnaSession.getAttribute(jt, LibDrmaa.DRMAA_JS_STATE);
+ if (LibDrmaa.DRMAA_SUBMISSION_STATE_HOLD.equals(stateString))
+ state = JobTemplate.HOLD_STATE;
+ else if (LibDrmaa.DRMAA_SUBMISSION_STATE_ACTIVE.equals(stateString))
+ state = JobTemplate.ACTIVE_STATE;
+ else
+ throw new InvalidAttributeValueException("jobSubmissionState attribute is invalid");
+ return state;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void setJobEnvironment(Map env) throws DrmaaException {
+ JnaSession.setVectorAttribute(jt, LibDrmaa.DRMAA_V_ENV, JnaSession.mapToCollection(env));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Map getJobEnvironment() throws DrmaaException {
+ return JnaSession.collectionToMap(JnaSession.getVectorAttribute(jt, LibDrmaa.DRMAA_V_ENV));
+ }
+
+ @Override
+ public void setWorkingDirectory(String s) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_WD, s);
+ }
+
+ @Override
+ public String getWorkingDirectory() throws DrmaaException {
+ return JnaSession.getAttribute(jt, LibDrmaa.DRMAA_WD);
+ }
+
+ @Override
+ public void setJobCategory(String s) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_JOB_CATEGORY, s);
+ }
+
+ @Override
+ public String getJobCategory() throws DrmaaException {
+ return JnaSession.getAttribute(jt, LibDrmaa.DRMAA_JOB_CATEGORY);
+ }
+
+ @Override
+ public void setNativeSpecification(String s) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_NATIVE_SPECIFICATION, s);
+ }
+
+ @Override
+ public String getNativeSpecification() throws DrmaaException {
+ return JnaSession.getAttribute(jt, LibDrmaa.DRMAA_NATIVE_SPECIFICATION);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void setEmail(Set set) throws DrmaaException {
+ JnaSession.setVectorAttribute(jt, LibDrmaa.DRMAA_V_EMAIL, set);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Set getEmail() throws DrmaaException {
+ return new LinkedHashSet<String>(JnaSession.getVectorAttribute(jt, LibDrmaa.DRMAA_V_EMAIL));
+ }
+
+ @Override
+ public void setBlockEmail(boolean b) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_BLOCK_EMAIL, b ? "1" : "0");
+ }
+
+ @Override
+ public boolean getBlockEmail() throws DrmaaException {
+ return "1".equals(JnaSession.getAttribute(jt, LibDrmaa.DRMAA_BLOCK_EMAIL));
+ }
+
+ @Override
+ public void setStartTime(PartialTimestamp partialTimestamp) throws DrmaaException {
+ JnaSession.setPartialTime(jt, LibDrmaa.DRMAA_START_TIME, partialTimestamp);
+ }
+
+ @Override
+ public PartialTimestamp getStartTime() throws DrmaaException {
+ return JnaSession.getPartialTime(jt, LibDrmaa.DRMAA_START_TIME);
+ }
+
+ @Override
+ public void setJobName(String s) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_JOB_NAME, s);
+ }
+
+ @Override
+ public String getJobName() throws DrmaaException {
+ return JnaSession.getAttribute(jt, LibDrmaa.DRMAA_JOB_NAME);
+ }
+
+ @Override
+ public void setInputPath(String s) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_INPUT_PATH, s);
+ }
+
+ @Override
+ public String getInputPath() throws DrmaaException {
+ return JnaSession.getAttribute(jt, LibDrmaa.DRMAA_INPUT_PATH);
+ }
+
+ @Override
+ public void setOutputPath(String s) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_OUTPUT_PATH, s);
+ }
+
+ @Override
+ public String getOutputPath() throws DrmaaException {
+ return JnaSession.getAttribute(jt, LibDrmaa.DRMAA_OUTPUT_PATH);
+ }
+
+ @Override
+ public void setErrorPath(String s) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_ERROR_PATH, s);
+ }
+
+ @Override
+ public String getErrorPath() throws DrmaaException {
+ return JnaSession.getAttribute(jt, LibDrmaa.DRMAA_ERROR_PATH);
+ }
+
+ @Override
+ public void setJoinFiles(boolean b) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_JOIN_FILES, b ? "y" : "n");
+ }
+
+ @Override
+ public boolean getJoinFiles() throws DrmaaException {
+ return "y".equals(JnaSession.getAttribute(jt, LibDrmaa.DRMAA_JOIN_FILES));
+ }
+
+ @Override
+ public void setTransferFiles(FileTransferMode fileTransferMode) throws DrmaaException {
+ StringBuilder buf = new StringBuilder();
+
+ if (fileTransferMode.getInputStream())
+ buf.append('i');
+
+ if (fileTransferMode.getOutputStream())
+ buf.append('o');
+
+ if (fileTransferMode.getErrorStream())
+ buf.append('e');
+
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_TRANSFER_FILES, buf.toString());
+ }
+
+ @Override
+ public FileTransferMode getTransferFiles() throws DrmaaException {
+ String mode = JnaSession.getAttribute(jt, LibDrmaa.DRMAA_TRANSFER_FILES);
+
+ if (mode == null)
+ return null;
+
+ FileTransferMode fileTransferMode = new FileTransferMode();
+ fileTransferMode.setInputStream(mode.indexOf('i') >= 0);
+ fileTransferMode.setOutputStream(mode.indexOf('o') >= 0);
+ fileTransferMode.setErrorStream(mode.indexOf('e') >= 0);
+ return fileTransferMode;
+ }
+
+ @Override
+ public void setDeadlineTime(PartialTimestamp partialTimestamp) throws DrmaaException {
+ JnaSession.setPartialTime(jt, LibDrmaa.DRMAA_DEADLINE_TIME, partialTimestamp);
+ }
+
+ @Override
+ public PartialTimestamp getDeadlineTime() throws DrmaaException {
+ return JnaSession.getPartialTime(jt, LibDrmaa.DRMAA_DEADLINE_TIME);
+ }
+
+ @Override
+ public void setHardWallclockTimeLimit(long l) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_WCT_HLIMIT, JnaSession.formatLimit(l));
+ }
+
+ @Override
+ public long getHardWallclockTimeLimit() throws DrmaaException {
+ return JnaSession.parseLimit(JnaSession.getAttribute(jt, LibDrmaa.DRMAA_WCT_HLIMIT));
+ }
+
+ @Override
+ public void setSoftWallclockTimeLimit(long l) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_WCT_SLIMIT, JnaSession.formatLimit(l));
+ }
+
+ @Override
+ public long getSoftWallclockTimeLimit() throws DrmaaException {
+ return JnaSession.parseLimit(JnaSession.getAttribute(jt, LibDrmaa.DRMAA_WCT_SLIMIT));
+ }
+
+ @Override
+ public void setHardRunDurationLimit(long l) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_DURATION_HLIMIT, JnaSession.formatLimit(l));
+ }
+
+ @Override
+ public long getHardRunDurationLimit() throws DrmaaException {
+ return JnaSession.parseLimit(JnaSession.getAttribute(jt, LibDrmaa.DRMAA_DURATION_HLIMIT));
+ }
+
+ @Override
+ public void setSoftRunDurationLimit(long l) throws DrmaaException {
+ JnaSession.setAttribute(jt, LibDrmaa.DRMAA_DURATION_SLIMIT, JnaSession.formatLimit(l));
+ }
+
+ @Override
+ public long getSoftRunDurationLimit() throws DrmaaException {
+ return JnaSession.parseLimit(JnaSession.getAttribute(jt, LibDrmaa.DRMAA_DURATION_SLIMIT));
+ }
+
+ @Override
+ public Set getAttributeNames() throws DrmaaException {
+ return JnaSession.getAttrNames();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof JnaJobTemplate))
+ return false;
+ JnaJobTemplate other = (JnaJobTemplate) obj;
+ return this.jt.equals(other.jt) && this.session.equals(other.session);
+ }
+
+ @Override
+ public int hashCode() {
+ return jt.hashCode();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaSession.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaSession.java
new file mode 100644
index 0000000..67eaad7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaSession.java
@@ -0,0 +1,461 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.drmaa.v1_0;
+
+import com.sun.jna.Memory;
+import com.sun.jna.NativeLong;
+import com.sun.jna.Pointer;
+import com.sun.jna.StringArray;
+import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.ptr.PointerByReference;
+import org.ggf.drmaa.*;
+
+import java.text.ParseException;
+import java.util.*;
+
+/**
+ * JNA mapping from Java to C DRMAA binding.
+ * See: Java and C Binding Documents on http://drmaa.org
+ */
+public class JnaSession implements Session {
+ private static final PartialTimestampFormat PARTIAL_TIMESTAMP_FORMAT = new PartialTimestampFormat();
+ private static final ThreadLocal<Memory> threadError = new ThreadLocal<Memory>() {
+ @Override
+ protected Memory initialValue() {
+ return new Memory(LibDrmaa.DRMAA_ERROR_STRING_BUFFER);
+ }
+ };
+
+ @Override
+ public void init(String contact) throws DrmaaException {
+ checkError(LibDrmaa.drmaa_init(contact, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ }
+
+ @Override
+ public void exit() throws DrmaaException {
+ checkError(LibDrmaa.drmaa_exit(getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ }
+
+ @Override
+ public JobTemplate createJobTemplate() throws DrmaaException {
+ PointerByReference jtRef = new PointerByReference();
+ checkError(LibDrmaa.drmaa_allocate_job_template(jtRef, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ return new JnaJobTemplate(this, jtRef.getValue());
+ }
+
+ @Override
+ public void deleteJobTemplate(JobTemplate jobTemplate) throws DrmaaException {
+ JnaJobTemplate jnaJobTemplate = (JnaJobTemplate) jobTemplate;
+ checkError(LibDrmaa.drmaa_delete_job_template(jnaJobTemplate.getPointer(), getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ }
+
+ @Override
+ public String runJob(JobTemplate jobTemplate) throws DrmaaException {
+ Memory jobId = new Memory(LibDrmaa.DRMAA_JOBNAME_BUFFER);
+ JnaJobTemplate jnaJobTemplate = (JnaJobTemplate) jobTemplate;
+ checkError(LibDrmaa.drmaa_run_job(jobId, LibDrmaa.DRMAA_JOBNAME_BUFFER_LEN, jnaJobTemplate.getPointer(), getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ return jobId.getString(0);
+ }
+
+ @Override
+ public List runBulkJobs(JobTemplate jobTemplate, int start, int end, int incr) throws DrmaaException {
+ PointerByReference jobIds = new PointerByReference();
+ JnaJobTemplate jnaJobTemplate = (JnaJobTemplate) jobTemplate;
+ checkError(LibDrmaa.drmaa_run_bulk_jobs(jobIds, jnaJobTemplate.getPointer(), start, end, incr, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ try {
+ return getJobIds(jobIds);
+ } finally {
+ releaseJobIds(jobIds);
+ }
+ }
+
+ @Override
+ public void control(String jobId, int action) throws DrmaaException {
+ checkError(LibDrmaa.drmaa_control(jobId, action, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void synchronize(List list, long timeout, boolean dispose) throws DrmaaException {
+ StringArray jobIds = new StringArray((String[]) list.toArray(new String[list.size()]));
+ checkError(LibDrmaa.drmaa_synchronize(jobIds, new NativeLong(timeout), dispose ? 1 : 0, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ }
+
+ @Override
+ public JobInfo wait(String jobId, long timeout) throws DrmaaException {
+ Memory jobIdOut = new Memory(LibDrmaa.DRMAA_JOBNAME_BUFFER);
+ IntByReference stat = new IntByReference();
+ PointerByReference rusage = new PointerByReference();
+ IntByReference exited = new IntByReference();
+ IntByReference exitStatus = new IntByReference();
+ IntByReference signaled = new IntByReference();
+ Memory signal = new Memory(LibDrmaa.DRMAA_SIGNAL_BUFFER);
+ IntByReference coreDumped = new IntByReference();
+ IntByReference aborted = new IntByReference();
+
+ int errnum;
+
+ errnum = LibDrmaa.drmaa_wait(jobId, jobIdOut, LibDrmaa.DRMAA_JOBNAME_BUFFER_LEN, stat, new NativeLong(timeout), rusage, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ Map<String, String> rusageMap;
+ if (errnum == LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_NO_RUSAGE) {
+ rusageMap = null;
+ } else {
+ try {
+ rusageMap = collectionToMap(getAttrValues(rusage));
+ } finally {
+ releaseAttrValues(rusage);
+ }
+ }
+
+ checkError(LibDrmaa.drmaa_wifexited(exited, stat.getValue(), getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+
+ if (exited.getValue() != 0) {
+ checkError(LibDrmaa.drmaa_wexitstatus(exitStatus, stat.getValue(), getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ }
+
+ checkError(LibDrmaa.drmaa_wifsignaled(signaled, stat.getValue(), getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+
+ if (signaled.getValue() != 0) {
+ checkError(LibDrmaa.drmaa_wtermsig(signal, LibDrmaa.DRMAA_SIGNAL_BUFFER_LEN, stat.getValue(), getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ checkError(LibDrmaa.drmaa_wcoredump(coreDumped, stat.getValue(), getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ }
+
+ checkError(LibDrmaa.drmaa_wifaborted(aborted, stat.getValue(), getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+
+ return new JnaJobInfo(jobIdOut.getString(0), rusageMap, exited.getValue() != 0, exitStatus.getValue(),
+ signaled.getValue() != 0, signal.getString(0), coreDumped.getValue() != 0, aborted.getValue() != 0);
+ }
+
+ @Override
+ public int getJobProgramStatus(String jobId) throws DrmaaException {
+ IntByReference remotePs = new IntByReference();
+ checkError(LibDrmaa.drmaa_job_ps(jobId, remotePs, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ return remotePs.getValue();
+ }
+
+ @Override
+ public String getContact() {
+ Memory contact = new Memory(LibDrmaa.DRMAA_CONTACT_BUFFER);
+ try {
+ checkError(LibDrmaa.drmaa_get_contact(contact, LibDrmaa.DRMAA_CONTACT_BUFFER_LEN, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ } catch (DrmaaException e) {
+ // DRMAA spec says this method should throw DrmaaException.
+ // Why doesn't interface implement this?
+ throw new RuntimeException(e);
+ }
+ return contact.getString(0);
+ }
+
+ @Override
+ public Version getVersion() {
+ IntByReference major = new IntByReference();
+ IntByReference minor = new IntByReference();
+ try {
+ checkError(LibDrmaa.drmaa_version(major, minor, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ } catch (DrmaaException e) {
+ // DRMAA spec says this method should throw DrmaaException.
+ // Why doesn't interface implement this?
+ throw new RuntimeException(e);
+ }
+ return new Version(major.getValue(), minor.getValue());
+ }
+
+ @Override
+ public String getDrmSystem() {
+ Memory drmSystem = new Memory(LibDrmaa.DRMAA_DRM_SYSTEM_BUFFER);
+ try {
+ checkError(LibDrmaa.drmaa_get_DRM_system(drmSystem, LibDrmaa.DRMAA_DRM_SYSTEM_BUFFER_LEN, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ } catch (DrmaaException e) {
+ // DRMAA spec says this method should throw DrmaaException.
+ // Why doesn't interface implement this?
+ throw new RuntimeException(e);
+ }
+ return drmSystem.getString(0);
+ }
+
+ @Override
+ public String getDrmaaImplementation() {
+ Memory drmaaImplementation = new Memory(LibDrmaa.DRMAA_DRMAA_IMPLEMENTATION_BUFFER);
+ try {
+ checkError(LibDrmaa.drmaa_get_DRMAA_implementation(drmaaImplementation, LibDrmaa.DRMAA_DRMAA_IMPLEMENTATION_BUFFER_LEN, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ } catch (DrmaaException e) {
+ // DRMAA spec says this method should throw DrmaaException.
+ // Why doesn't interface implement this?
+ throw new RuntimeException(e);
+ }
+ return drmaaImplementation.getString(0);
+ }
+
+ public static void setAttribute(Pointer jt, String name, String value) throws DrmaaException {
+ if (getAttrNames().contains(name)) {
+ checkError(LibDrmaa.drmaa_set_attribute(jt, name, value, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ }
+ else {
+ throw new InvalidAttributeValueException("Attribute " + name + " is not supported by this implementation of DRMAA");
+ }
+ }
+
+ public static String getAttribute(Pointer jt, String name) throws DrmaaException {
+ if (getAttrNames().contains(name)) {
+ Memory attrBuffer = new Memory(LibDrmaa.DRMAA_ATTR_BUFFER);
+ checkError(LibDrmaa.drmaa_get_attribute(jt, name, attrBuffer, LibDrmaa.DRMAA_ATTR_BUFFER_LEN, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ return attrBuffer.getString(0);
+ }
+ else {
+ throw new InvalidAttributeValueException("Attribute " + name + " is not supported by this implementation of DRMAA");
+ }
+ }
+
+ public static void setVectorAttribute(Pointer jt, String name, Collection<String> values) throws DrmaaException {
+ StringArray valuesArray = new StringArray(values.toArray(new String[values.size()]));
+ checkError(LibDrmaa.drmaa_set_vector_attribute(jt, name, valuesArray, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ }
+
+ public static List<String> getVectorAttribute(Pointer jt, String name) throws DrmaaException {
+ PointerByReference values = new PointerByReference();
+ checkError(LibDrmaa.drmaa_get_vector_attribute(jt, name, values, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ try {
+ return getAttrValues(values);
+ } finally {
+ releaseAttrValues(values);
+ }
+ }
+
+ public static void setPartialTime(Pointer jt, String name, PartialTimestamp partialTimestamp) throws DrmaaException {
+ setAttribute(jt, name, PARTIAL_TIMESTAMP_FORMAT.format(partialTimestamp));
+ }
+
+ public static PartialTimestamp getPartialTime(Pointer jt, String name) throws DrmaaException {
+ String time = getAttribute(jt, name);
+ if (time == null)
+ return null;
+ try {
+ return PARTIAL_TIMESTAMP_FORMAT.parse(time);
+ } catch (ParseException e) {
+ throw new InternalException(name + " property is unparsable");
+ }
+ }
+
+ public static Set<String> getAttrNames() throws DrmaaException {
+ PointerByReference values = new PointerByReference();
+ checkError(LibDrmaa.drmaa_get_attribute_names(values, getError(), LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN));
+ try {
+ return new LinkedHashSet<String>(getAttrNames(values));
+ } finally {
+ releaseAttrNames(values);
+ }
+ }
+
+ public static Collection<String> mapToCollection(Map<String, String> map) {
+ Collection<String> collection = new LinkedHashSet<String>();
+ for (Map.Entry<String, String> entry: map.entrySet())
+ collection.add(entry.getKey() + "=" + entry.getValue());
+ return collection;
+ }
+
+ public static Map<String, String> collectionToMap(Collection<String> list) {
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ for (String entry: list) {
+ if (entry == null)
+ continue;
+ int equals = entry.indexOf('=');
+ if (equals < 0)
+ continue;
+ map.put(entry.substring(0, equals), entry.substring(equals + 1));
+ }
+ return map;
+ }
+
+ public static String formatLimit(long secs) {
+ long seconds = (secs % 60);
+ long minutes = (secs / 60) % 60;
+ long hours = (secs / 3600);
+ return String.format("%d:%02d:%02d", hours, minutes, seconds);
+ }
+
+ public static long parseLimit(String limit) {
+ long seconds = 0;
+ if (limit != null) {
+ for (String token: limit.split(":")) {
+ seconds *= 60;
+ seconds += Long.parseLong(token);
+ }
+ }
+ return seconds;
+ }
+
+ private static List<String> getAttrNames(PointerByReference names) throws DrmaaException {
+ List<String> namesList = new ArrayList<String>();
+ IntByReference size = new IntByReference();
+ int errnum;
+
+ errnum = LibDrmaa.drmaa_get_num_attr_names(names.getValue(), size);
+ checkError(errnum, "unable to get attribute names");
+ int num = size.getValue();
+
+ Memory value = new Memory(LibDrmaa.DRMAA_ATTR_BUFFER);
+ for (int i = 1; i <= num; i++) {
+ errnum = LibDrmaa.drmaa_get_next_attr_name(names.getValue(), value, LibDrmaa.DRMAA_ATTR_BUFFER_LEN);
+ checkError(errnum, "unable to get attribute name " + i);
+ if (errnum == LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_NO_MORE_ELEMENTS)
+ break;
+ namesList.add(value.getString(0));
+ }
+
+ return namesList;
+ }
+
+ private static List<String> getAttrValues(PointerByReference values) throws DrmaaException {
+ List<String> valuesList = new ArrayList<String>();
+ IntByReference size = new IntByReference();
+ int errnum;
+
+ errnum = LibDrmaa.drmaa_get_num_attr_values(values.getValue(), size);
+ checkError(errnum, "unable to get attribute values");
+ int num = size.getValue();
+
+ Memory value = new Memory(LibDrmaa.DRMAA_ATTR_BUFFER);
+ for (int i = 1; i <= num; i++) {
+ errnum = LibDrmaa.drmaa_get_next_attr_value(values.getValue(), value, LibDrmaa.DRMAA_ATTR_BUFFER_LEN);
+ checkError(errnum, "unable to get attribute value " + i);
+ if (errnum == LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_NO_MORE_ELEMENTS)
+ break;
+ valuesList.add(value.getString(0));
+ }
+
+ return valuesList;
+ }
+
+ private static List<String> getJobIds(PointerByReference jobIds) throws DrmaaException {
+ List<String> jobIdsList = new ArrayList<String>();
+ IntByReference size = new IntByReference();
+ int errnum;
+
+ errnum = LibDrmaa.drmaa_get_num_job_ids(jobIds.getValue(), size);
+ checkError(errnum, "unable to get jobIds");
+ int num = size.getValue();
+
+ Memory value = new Memory(LibDrmaa.DRMAA_JOBNAME_BUFFER);
+ for (int i = 1; i <= num; i++) {
+ errnum = LibDrmaa.drmaa_get_next_job_id(jobIds.getValue(), value, LibDrmaa.DRMAA_JOBNAME_BUFFER_LEN);
+ checkError(errnum, "unable to get jobId " + i);
+ if (errnum == LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_NO_MORE_ELEMENTS)
+ break;
+ jobIdsList.add(value.getString(0));
+ }
+
+ return jobIdsList;
+ }
+
+ private static void releaseAttrNames(PointerByReference names) throws DrmaaException {
+ LibDrmaa.drmaa_release_attr_names(names.getValue());
+ }
+
+ private static void releaseAttrValues(PointerByReference values) throws DrmaaException {
+ LibDrmaa.drmaa_release_attr_values(values.getValue());
+ }
+
+ private static void releaseJobIds(PointerByReference jobIds) throws DrmaaException {
+ LibDrmaa.drmaa_release_job_ids(jobIds.getValue());
+ }
+
+ private static Memory getError() {
+ return threadError.get();
+ }
+
+ private static void checkError(int errnum) throws DrmaaException {
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ checkError(errnum, getError().getString(0));
+ }
+
+ private static void checkError(int errnum, String error) throws DrmaaException {
+ switch (errnum) {
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS:
+ break;
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_INTERNAL_ERROR:
+ throw new InternalException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_DRM_COMMUNICATION_FAILURE:
+ throw new DrmCommunicationException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_AUTH_FAILURE:
+ throw new AuthorizationException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_INVALID_ARGUMENT:
+ throw new IllegalArgumentException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_NO_ACTIVE_SESSION:
+ throw new NoActiveSessionException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_NO_MEMORY:
+ throw new OutOfMemoryError(error);
+
+ /* -------------- init and exit specific --------------- */
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_INVALID_CONTACT_STRING:
+ throw new InvalidContactStringException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_DEFAULT_CONTACT_STRING_ERROR:
+ throw new DefaultContactStringException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_NO_DEFAULT_CONTACT_STRING_SELECTED:
+ throw new NoDefaultContactStringException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_DRMS_INIT_FAILED:
+ throw new DrmsInitException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_ALREADY_ACTIVE_SESSION:
+ throw new AlreadyActiveSessionException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_DRMS_EXIT_ERROR:
+ throw new DrmsExitException(error);
+
+ /* ---------------- job attributes specific -------------- */
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_INVALID_ATTRIBUTE_FORMAT:
+ throw new InvalidAttributeFormatException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_INVALID_ATTRIBUTE_VALUE:
+ throw new InvalidAttributeValueException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_CONFLICTING_ATTRIBUTE_VALUES:
+ throw new ConflictingAttributeValuesException(error);
+
+ /* --------------------- job submission specific -------------- */
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_TRY_LATER:
+ throw new TryLaterException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_DENIED_BY_DRM:
+ throw new DeniedByDrmException(error);
+
+ /* ------------------------------- job control specific ---------------- */
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_INVALID_JOB:
+ throw new InvalidJobException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_RESUME_INCONSISTENT_STATE:
+ throw new ResumeInconsistentStateException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUSPEND_INCONSISTENT_STATE:
+ throw new SuspendInconsistentStateException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_HOLD_INCONSISTENT_STATE:
+ throw new HoldInconsistentStateException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_RELEASE_INCONSISTENT_STATE:
+ throw new ReleaseInconsistentStateException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_EXIT_TIMEOUT:
+ throw new ExitTimeoutException(error);
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_NO_RUSAGE:
+ break;
+ case LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_NO_MORE_ELEMENTS:
+ break;
+ default:
+ throw new IllegalArgumentException(String.format("Unknown error code %d: %s", errnum, error));
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaSessionFactory.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaSessionFactory.java
new file mode 100644
index 0000000..f4dbc98
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaSessionFactory.java
@@ -0,0 +1,40 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.drmaa.v1_0;
+
+import org.ggf.drmaa.Session;
+import org.ggf.drmaa.SessionFactory;
+
+/**
+ * JNA mapping from Java to C DRMAA binding.
+ */
+ at SuppressWarnings("unused")
+public class JnaSessionFactory extends SessionFactory {
+ @Override
+ public Session getSession() {
+ return new JnaSession();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/LibDrmaa.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/LibDrmaa.java
new file mode 100644
index 0000000..3e5c4e4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/LibDrmaa.java
@@ -0,0 +1,723 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.drmaa.v1_0;
+
+import com.sun.jna.*;
+import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.ptr.PointerByReference;
+
+ at SuppressWarnings("unused")
+public class LibDrmaa {
+ static {
+ Native.register("drmaa");
+ }
+
+/* see www.drmaa.org for more details on the DRMAA specification */
+/****** DRMAA/-DRMAA_Interface *************************************************
+* NAME
+* DRMAA_Interface -- DRMAA interface
+*
+* FUNCTION
+* The enlisted functions specify the C/C++ binding of the DRMAA interface
+* specification.
+*
+* SEE ALSO
+* DRMAA/drmaa_get_next_attr_name()
+* DRMAA/drmaa_get_next_attr_value()
+* DRMAA/drmaa_get_next_job_id()
+* DRMAA/drmaa_release_attr_names()
+* DRMAA/drmaa_release_attr_values()
+* DRMAA/drmaa_release_job_ids()
+* DRMAA/drmaa_init()
+* DRMAA/drmaa_exit()
+* DRMAA/drmaa_allocate_job_template()
+* DRMAA/drmaa_delete_job_template()
+* DRMAA/drmaa_set_attribute()
+* DRMAA/drmaa_get_attribute()
+* DRMAA/drmaa_set_vector_attribute()
+* DRMAA/drmaa_get_vector_attribute()
+* DRMAA/drmaa_get_attribute_names()
+* DRMAA/drmaa_get_vector_attribute_names()
+* DRMAA/drmaa_run_job()
+* DRMAA/drmaa_run_bulk_jobs()
+* DRMAA/drmaa_control()
+* DRMAA/drmaa_synchronize()
+* DRMAA/drmaa_wait()
+* DRMAA/drmaa_wifexited()
+* DRMAA/drmaa_wexitstatus()
+* DRMAA/drmaa_wifsignaled()
+* DRMAA/drmaa_wtermsig()
+* DRMAA/drmaa_wcoredump()
+* DRMAA/drmaa_wifaborted()
+* DRMAA/drmaa_job_ps()
+* DRMAA/drmaa_strerror()
+* DRMAA/drmaa_get_contact()
+* DRMAA/drmaa_version()
+* DRMAA/drmaa_get_DRM_system()
+*******************************************************************************/
+
+/* ------------------- Constants ------------------- */
+/*
+ * some not yet agreed buffer length constants
+ * these are recommended minimum values
+ */
+
+/* drmaa_get_attribute() */
+public static final long DRMAA_ATTR_BUFFER = 1024;
+public static final NativeLong DRMAA_ATTR_BUFFER_LEN = new NativeLong(DRMAA_ATTR_BUFFER - 1);
+
+/* drmaa_get_contact() */
+public static final long DRMAA_CONTACT_BUFFER = 1024;
+public static final NativeLong DRMAA_CONTACT_BUFFER_LEN = new NativeLong(DRMAA_CONTACT_BUFFER - 1);
+
+/* drmaa_get_DRM_system() */
+public static final long DRMAA_DRM_SYSTEM_BUFFER = 1024;
+public static final NativeLong DRMAA_DRM_SYSTEM_BUFFER_LEN = new NativeLong(DRMAA_DRM_SYSTEM_BUFFER - 1);
+
+/* drmaa_get_DRM_system() */
+public static final long DRMAA_DRMAA_IMPLEMENTATION_BUFFER = 1024;
+public static final NativeLong DRMAA_DRMAA_IMPLEMENTATION_BUFFER_LEN = new NativeLong(DRMAA_DRMAA_IMPLEMENTATION_BUFFER - 1);
+
+/*
+ * Agreed buffer length constants
+ * these are recommended minimum values
+ */
+public static final long DRMAA_ERROR_STRING_BUFFER = 1024;
+public static final long DRMAA_JOBNAME_BUFFER = 1024;
+public static final long DRMAA_SIGNAL_BUFFER = 32;
+
+public static final NativeLong DRMAA_ERROR_STRING_BUFFER_LEN = new NativeLong(DRMAA_ERROR_STRING_BUFFER - 1);
+public static final NativeLong DRMAA_JOBNAME_BUFFER_LEN = new NativeLong(DRMAA_JOBNAME_BUFFER - 1);
+public static final NativeLong DRMAA_SIGNAL_BUFFER_LEN = new NativeLong(DRMAA_SIGNAL_BUFFER - 1);
+
+/*
+ * Agreed constants
+ */
+public static final NativeLong DRMAA_TIMEOUT_WAIT_FOREVER = new NativeLong(-1);
+public static final NativeLong DRMAA_TIMEOUT_NO_WAIT = new NativeLong(0);
+
+public static final String DRMAA_JOB_IDS_SESSION_ANY = "DRMAA_JOB_IDS_SESSION_ANY";
+public static final String DRMAA_JOB_IDS_SESSION_ALL = "DRMAA_JOB_IDS_SESSION_ALL";
+
+public static final String DRMAA_SUBMISSION_STATE_ACTIVE = "drmaa_active";
+public static final String DRMAA_SUBMISSION_STATE_HOLD = "drmaa_hold";
+
+/*
+ * Agreed placeholder names
+ */
+public static final String DRMAA_PLACEHOLDER_INCR = "$drmaa_incr_ph$";
+public static final String DRMAA_PLACEHOLDER_HD = "$drmaa_hd_ph$";
+public static final String DRMAA_PLACEHOLDER_WD = "$drmaa_wd_ph$";
+
+/*
+ * Agreed names of job template attributes
+ */
+public static final String DRMAA_REMOTE_COMMAND = "drmaa_remote_command";
+public static final String DRMAA_JS_STATE = "drmaa_js_state";
+public static final String DRMAA_WD = "drmaa_wd";
+public static final String DRMAA_JOB_CATEGORY = "drmaa_job_category";
+public static final String DRMAA_NATIVE_SPECIFICATION = "drmaa_native_specification";
+public static final String DRMAA_BLOCK_EMAIL = "drmaa_block_email";
+public static final String DRMAA_START_TIME = "drmaa_start_time";
+public static final String DRMAA_JOB_NAME = "drmaa_job_name";
+public static final String DRMAA_INPUT_PATH = "drmaa_input_path";
+public static final String DRMAA_OUTPUT_PATH = "drmaa_output_path";
+public static final String DRMAA_ERROR_PATH = "drmaa_error_path";
+public static final String DRMAA_JOIN_FILES = "drmaa_join_files";
+public static final String DRMAA_TRANSFER_FILES = "drmaa_transfer_files";
+public static final String DRMAA_DEADLINE_TIME = "drmaa_deadline_time";
+public static final String DRMAA_WCT_HLIMIT = "drmaa_wct_hlimit";
+public static final String DRMAA_WCT_SLIMIT = "drmaa_wct_slimit";
+public static final String DRMAA_DURATION_HLIMIT = "drmaa_duration_hlimit";
+public static final String DRMAA_DURATION_SLIMIT = "drmaa_duration_slimit";
+
+/* names of job template vector attributes */
+public static final String DRMAA_V_ARGV = "drmaa_v_argv";
+public static final String DRMAA_V_ENV = "drmaa_v_env";
+public static final String DRMAA_V_EMAIL = "drmaa_v_email";
+
+/*
+ * DRMAA errno values
+ *
+ * do not touch these values are agreed !!!
+ */
+public static interface DRMAA_ERRNO {
+ /* -------------- these are relevant to all sections ---------------- */
+ public static final int DRMAA_ERRNO_SUCCESS = 0; /* Routine returned normally with success. */
+ public static final int DRMAA_ERRNO_INTERNAL_ERROR = 1; /* Unexpected or internal DRMAA error like memory allocation, system call failure, etc. */
+ public static final int DRMAA_ERRNO_DRM_COMMUNICATION_FAILURE = 2; /* Could not contact DRM system for this request. */
+ public static final int DRMAA_ERRNO_AUTH_FAILURE = 3; /* The specified request is not processed successfully due to authorization failure. */
+ public static final int DRMAA_ERRNO_INVALID_ARGUMENT = 4; /* The input value for an argument is invalid. */
+ public static final int DRMAA_ERRNO_NO_ACTIVE_SESSION = 5; /* Exit routine failed because there is no active session */
+ public static final int DRMAA_ERRNO_NO_MEMORY = 6; /* failed allocating memory */
+
+ /* -------------- init and exit specific --------------- */
+ public static final int DRMAA_ERRNO_INVALID_CONTACT_STRING = 7; /* Initialization failed due to invalid contact string. */
+ public static final int DRMAA_ERRNO_DEFAULT_CONTACT_STRING_ERROR = 8; /* DRMAA could not use the default contact string to connect to DRM system. */
+ public static final int DRMAA_ERRNO_NO_DEFAULT_CONTACT_STRING_SELECTED = 9; /* No default contact string was provided or selected. DRMAA requires that the default contact string is selected when there is more than one default contact string due to multiple DRMAA implementation contained in the binary module. */
+ public static final int DRMAA_ERRNO_DRMS_INIT_FAILED = 10; /* Initialization failed due to failure to init DRM system. */
+ public static final int DRMAA_ERRNO_ALREADY_ACTIVE_SESSION = 11; /* Initialization failed due to existing DRMAA session. */
+ public static final int DRMAA_ERRNO_DRMS_EXIT_ERROR = 12; /* DRM system disengagement failed. */
+
+ /* ---------------- job attributes specific -------------- */
+ public static final int DRMAA_ERRNO_INVALID_ATTRIBUTE_FORMAT = 13; /* The format for the job attribute value is invalid. */
+ public static final int DRMAA_ERRNO_INVALID_ATTRIBUTE_VALUE = 14; /* The value for the job attribute is invalid. */
+ public static final int DRMAA_ERRNO_CONFLICTING_ATTRIBUTE_VALUES = 15; /* The value of this attribute is conflicting with a previously set attributes. */
+
+ /* --------------------- job submission specific -------------- */
+ public static final int DRMAA_ERRNO_TRY_LATER = 16; /* Could not pass job now to DRM system. A retry may succeed however (saturation). */
+ public static final int DRMAA_ERRNO_DENIED_BY_DRM = 17; /* The DRM system rejected the job. The job will never be accepted due to DRM configuration or job template settings. */
+
+ /* ------------------------------- job control specific ---------------- */
+ public static final int DRMAA_ERRNO_INVALID_JOB = 18; /* The job specified by the 'jobid' does not exist. */
+ public static final int DRMAA_ERRNO_RESUME_INCONSISTENT_STATE = 19; /* The job has not been suspended. The RESUME request will not be processed. */
+ public static final int DRMAA_ERRNO_SUSPEND_INCONSISTENT_STATE = 20; /* The job has not been running, and it cannot be suspended. */
+ public static final int DRMAA_ERRNO_HOLD_INCONSISTENT_STATE = 21; /* The job cannot be moved to a HOLD state. */
+ public static final int DRMAA_ERRNO_RELEASE_INCONSISTENT_STATE = 22; /* The job is not in a HOLD state. */
+ public static final int DRMAA_ERRNO_EXIT_TIMEOUT = 23; /* We have encountered a time-out condition for drmaa_synchronize or drmaa_wait. */
+ public static final int DRMAA_ERRNO_NO_RUSAGE = 24; /* This error code is returned by drmaa_wait() when a job has finished but no rusage and stat data could be provided. */
+ public static final int DRMAA_ERRNO_NO_MORE_ELEMENTS = 25; /* There are no more elements in the opaque string vector. */
+
+ public static final int DRMAA_NO_ERRNO = 26;
+}
+
+/*
+ * Agreed DRMAA job states as returned by drmaa_job_ps()
+ */
+public static interface DRMAA_PS {
+ public static final int DRMAA_PS_UNDETERMINED = 0x00; /* process status cannot be determined */
+ public static final int DRMAA_PS_QUEUED_ACTIVE = 0x10; /* job is queued and active */
+ public static final int DRMAA_PS_SYSTEM_ON_HOLD = 0x11; /* job is queued and in system hold */
+ public static final int DRMAA_PS_USER_ON_HOLD = 0x12; /* job is queued and in user hold */
+ public static final int DRMAA_PS_USER_SYSTEM_ON_HOLD = 0x13; /* job is queued and in user and system hold */
+ public static final int DRMAA_PS_RUNNING = 0x20; /* job is running */
+ public static final int DRMAA_PS_SYSTEM_SUSPENDED = 0x21; /* job is system suspended */
+ public static final int DRMAA_PS_USER_SUSPENDED = 0x22; /* job is user suspended */
+ public static final int DRMAA_PS_USER_SYSTEM_SUSPENDED = 0x23; /* job is user and system suspended */
+ public static final int DRMAA_PS_DONE = 0x30; /* job finished normally */
+ public static final int DRMAA_PS_FAILED = 0x40; /* job finished, but failed */
+}
+
+/*
+ * Agreed DRMAA actions for drmaa_control()
+ */
+public static interface DRMAA_CONTROL {
+ public static final int DRMAA_CONTROL_SUSPEND = 0;
+ public static final int DRMAA_CONTROL_RESUME = 1;
+ public static final int DRMAA_CONTROL_HOLD = 2;
+ public static final int DRMAA_CONTROL_RELEASE = 3;
+ public static final int DRMAA_CONTROL_TERMINATE = 4;
+}
+
+/* ------------------- Data types ------------------- */
+/*
+ * Agreed opaque DRMAA job template
+ * struct drmaa_job_template_s is in japiP.h
+ */
+//typedef struct drmaa_job_template_s drmaa_job_template_t;
+
+/* ---------- C/C++ language binding specific interfaces -------- */
+
+//typedef struct drmaa_attr_names_s drmaa_attr_names_t;
+//typedef struct drmaa_attr_values_s drmaa_attr_values_t;
+//typedef struct drmaa_job_ids_s drmaa_job_ids_t;
+
+/*
+ * get next string attribute from iterator
+ *
+ * returns DRMAA_ERRNO_SUCCESS or DRMAA_ERRNO_INVALID_ATTRIBUTE_VALUE
+ * if no such exists
+ */
+
+public static native int drmaa_get_next_attr_name(/* drmaa_attr_names_t* */ Pointer values, Pointer value,
+ NativeLong value_len);
+public static native int drmaa_get_next_attr_value(/* drmaa_attr_names_t* */ Pointer values, Pointer value,
+ NativeLong value_len);
+public static native int drmaa_get_next_job_id(/* drmaa_job_ids_t* */ Pointer values, Pointer value,
+ NativeLong value_len);
+
+/*
+ * get element count of opaque string vector
+ *
+ * Gives the number of elements in the opaque string vector. Useful for
+ * copying the contents into an array.
+ */
+public static native int drmaa_get_num_attr_names(/* drmaa_attr_names_t* */ Pointer values, IntByReference size);
+public static native int drmaa_get_num_attr_values(/* drmaa_attr_values_t* */ Pointer values, IntByReference size);
+public static native int drmaa_get_num_job_ids(/* drmaa_job_ids_t* */ Pointer values, IntByReference size);
+
+/*
+ * release opaque string vector
+ *
+ * Opaque string vectors can be used without any constraint
+ * until the release function has been called.
+ */
+public static native void drmaa_release_attr_names(/* drmaa_attr_names_t* */ Pointer values);
+public static native void drmaa_release_attr_values(/* drmaa_attr_values_t* */ Pointer values);
+public static native void drmaa_release_job_ids(/* drmaa_job_ids_t* */ Pointer values);
+
+/* ------------------- init/exit routines ------------------- */
+/*
+ * Initialize DRMAA API library and create a new DRMAA Session. 'Contact'
+ * is an implementation dependent string which MAY be used to specify
+ * which DRM system to use. This routine MUST be called before any
+ * other DRMAA calls, except for drmaa_version().
+ * If 'contact' is NULL, the default DRM system SHALL be used provided there is
+ * only one DRMAA implementation in the provided binary module. When these is
+ * more than one DRMAA implementation in the binary module, drmaa_init() SHALL
+ * return the DRMAA_ERRNO_NO_DEFAULT_CONTACT_STRING_SELECTED error. drmaa_init()
+ * SHOULD be called by only one of the threads. The main thread is RECOMMENDED.
+ * A call by another thread SHALL return DRMAA_ERRNO_ALREADY_ACTIVE_SESSION.
+ * When 'contact' is a a semi-colon separated list of name=value strings, the
+ * strings will be parsed and interpreted. The current list of accepted names
+ * is:
+ * session -- the id of the session to which to reconnect
+#if 0
+ * sge_root -- the SGE_ROOT to use
+ * sge_cell -- the SGE_CELL to use
+#endif
+ *
+ * drmaa_init() SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_INVALID_CONTACT_STRING,
+ * DRMAA_ERRNO_NO_MEMORY,
+ * DRMAA_ERRNO_ALREADY_ACTIVE_SESSION,
+ * DRMAA_ERRNO_NO_DEFAULT_CONTACT_STRING_SELECTED, or
+ * DRMAA_ERRNO_DEFAULT_CONTACT_STRING_ERROR.
+ */
+public static native int drmaa_init(String contact, Pointer error_diagnosis, NativeLong error_diag_len);
+
+
+/*
+ * Disengage from DRMAA library and allow the DRMAA library to perform
+ * any necessary internal clean up.
+ * This routine SHALL end the current DRMAA Session, but SHALL NOT effect any
+ * jobs (e.g., queued and running jobs SHALL remain queued and running).
+ * drmaa_exit() SHOULD be called by only one of the threads. Other thread calls
+ * to drmaa_exit() MAY fail since there is no active session.
+ *
+ * drmaa_exit() SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_DRMS_EXIT_ERROR or
+ * DRMAA_ERRNO_NO_ACTIVE_SESSION.
+ */
+public static native int drmaa_exit(Pointer error_diagnosis, NativeLong error_diag_len);
+
+/* ------------------- job template routines ------------------- */
+
+/*
+ * Allocate a new job template.
+ *
+ * drmaa_allocate_job_template() SHALL return DRMAA_ERRNO_SUCCESS on success,
+ * otherwise:
+ * DRMAA_ERRNO_DRM_COMMUNICATION_FAILURE,
+ * DRMAA_ERRNO_INTERNAL_ERROR or
+ * DRMAA_ERRNO_NO_MEMORY.
+ */
+public static native int drmaa_allocate_job_template(/* drmaa_job_template_t** */ PointerByReference jt, Pointer error_diagnosis, NativeLong error_diag_len);
+
+/*
+ * Deallocate a job template. This routine has no effect on jobs.
+ *
+ * drmaa_delete_job_template() SHALL return DRMAA_ERRNO_SUCCESS on success,
+ * otherwise:
+ * DRMAA_ERRNO_DRM_COMMUNICATION_FAILURE or
+ * DRMAA_ERRNO_INTERNAL_ERROR.
+ */
+public static native int drmaa_delete_job_template(/* drmaa_job_template_t* */ Pointer jt, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+
+/*
+ * Adds ('name', 'value') pair to list of attributes in job template 'jt'.
+ * Only non-vector attributes SHALL be passed.
+ *
+ * drmaa_set_attribute() SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_INVALID_ATTRIBUTE_FORMAT,
+ * DRMAA_ERRNO_INVALID_ARGUMENT,
+ * DRMAA_ERRNO_NO_MEMORY,
+ * DRMAA_ERRNO_INVALID_ATTRIBUTE_VALUE or
+ * DRMAA_ERRNO_CONFLICTING_ATTRIBUTE_VALUES.
+ */
+public static native int drmaa_set_attribute(/* drmaa_job_template_t* */ Pointer jt, String name,
+ String value, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+
+/*
+ * If 'name' is an existing non-vector attribute name in the job
+ * template 'jt', then the value of 'name' SHALL be returned; otherwise,
+ * NULL is returned.
+ *
+ * drmaa_get_attribute() SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_INVALID_ATTRIBUTE_VALUE.
+ */
+public static native int drmaa_get_attribute(/* drmaa_job_template_t* */ Pointer jt, String name, Pointer value,
+ NativeLong value_len, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+/* Adds ('name', 'values') pair to list of vector attributes in job template
+ * 'jt'. Only vector attributes SHALL be passed.
+ * A 'value' string vector containing n elements must be n+1 elements long, with
+ * the nth value, i.e. value[n], being set to NULL as a delimitor.
+ *
+ * drmaa_set_vector_attribute() SHALL return DRMAA_ERRNO_SUCCESS on success,
+ * otherwise:
+ * DRMAA_ERRNO_INVALID_ATTRIBUTE_FORMAT,
+ * DRMAA_ERRNO_INVALID_ARGUMENT,
+ * DRMAA_ERRNO_NO_MEMORY,
+ * DRMAA_ERRNO_CONFLICTING_ATTRIBUTE_VALUES.
+ */
+public static native int drmaa_set_vector_attribute(/* drmaa_job_template_t* */ Pointer jt, String name,
+ Pointer value, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+
+/*
+ * If 'name' is an existing vector attribute name in the job template 'jt',
+ * then the values of 'name' are returned; otherwise, NULL is returned.
+ *
+ * drmaa_get_vector_attribute() SHALL return DRMAA_ERRNO_SUCCESS on success,
+ * otherwise:
+ * DRMAA_ERRNO_INVALID_ATTRIBUTE_VALUE.
+ */
+public static native int drmaa_get_vector_attribute(/* drmaa_job_template_t* */ Pointer jt, String name,
+ /* drmaa_attr_values_t ** */ PointerByReference values,
+ Pointer error_diagnosis, NativeLong error_diag_len);
+
+
+/*
+ * SHALL return the set of supported attribute names whose associated
+ * value type is String. This set SHALL include supported DRMAA reserved
+ * attribute names and native attribute names.
+ *
+ * drmaa_get_attribute_names() SHALL return DRMAA_ERRNO_SUCCESS on success,
+ * otherwise:
+ * DRMAA_ERRNO_NO_MEMORY.
+ */
+public static native int drmaa_get_attribute_names(/* drmaa_attr_names_t ** */ PointerByReference values,
+ Pointer error_diagnosis, NativeLong error_diag_len);
+
+/*
+ * SHALL return the set of supported attribute names whose associated
+ * value type is String Vector. This set SHALL include supported DRMAA reserved
+ * attribute names and native attribute names.
+ *
+ * drmaa_get_vector_attribute_names() SHALL return DRMAA_ERRNO_SUCCESS on
+ * success, otherwise:
+ * DRMAA_ERRNO_NO_MEMORY.
+ */
+public static native int drmaa_get_vector_attribute_names(/* drmaa_attr_names_t ** */ PointerByReference values,
+ Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+/* ------------------- job submission routines ------------------- */
+
+/*
+ * Submit a job with attributes defined in the job template 'jt'.
+ * The job identifier 'job_id' is a printable, NULL terminated string,
+ * identical to that returned by the underlying DRM system.
+ *
+ * drmaa_run_job() SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_TRY_LATER,
+ * DRMAA_ERRNO_DENIED_BY_DRM,
+ * DRMAA_ERRNO_NO_MEMORY,
+ * DRMAA_ERRNO_DRM_COMMUNICATION_FAILURE or
+ * DRMAA_ERRNO_AUTH_FAILURE.
+ */
+public static native int drmaa_run_job(Pointer job_id, NativeLong job_id_len,
+ /* drmaa_job_template_t * */ Pointer jt, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+/*
+ * Submit a set of parametric jobs, dependent on the implied loop index, each
+ * with attributes defined in the job template 'jt'.
+ * The job identifiers 'job_ids' SHALL all be printable,
+ * NULL terminated strings, identical to those returned by the underlying
+ * DRM system. Nonnegative loop bounds SHALL NOT use file names
+ * that start with minus sign like command line options.
+ * DRMAA defines a special index placeholder, drmaa_incr_ph, (which has the
+ * value "$incr_pl$") that is used to construct parametric job templates.
+ * For example:
+ * //C++ string syntax used
+ * drmaa_set_attribute(pjt, "stderr", drmaa_incr_ph + ".err" );
+ *
+ * drmaa_run_bulk_jobs() SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_TRY_LATER,
+ * DRMAA_ERRNO_DENIED_BY_DRM,
+ * DRMAA_ERRNO_NO_MEMORY,
+ * DRMAA_ERRNO_DRM_COMMUNICATION_FAILURE or
+ * DRMAA_ERRNO_AUTH_FAILURE.
+ */
+public static native int drmaa_run_bulk_jobs(/* drmaa_job_ids_t ** */ PointerByReference jobids,
+ /* drmaa_job_template_t * */ Pointer jt, int start, int end,
+ int incr, Pointer error_diagnosis, NativeLong error_diag_len);
+
+/* ------------------- job control routines ------------------- */
+
+/*
+ * Start, stop, restart, or kill the job identified by 'job_id'.
+ * If 'job_id' is DRMAA_JOB_IDS_SESSION_ALL then this routine
+ * acts on all jobs *submitted* during this DRMAA session.
+ * The legal values for 'action' and their meanings SHALL be:
+ * DRMAA_CONTROL_SUSPEND: stop the job,
+ * DRMAA_CONTROL_RESUME: (re)start the job,
+ * DRMAA_CONTROL_HOLD: put the job on-hold,
+ * DRMAA_CONTROL_RELEASE: release the hold on the job, and
+ * DRMAA_CONTROL_TERMINATE: kill the job.
+ *
+ * This routine SHALL return once the action has been acknowledged by
+ * the DRM system, but does not necessarily wait until the action
+ * has been completed.
+ *
+ * drmaa_control() SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_DRM_COMMUNICATION_FAILURE,
+ * DRMAA_ERRNO_AUTH_FAILURE,
+ * DRMAA_ERRNO_NO_MEMORY,
+ * DRMAA_ERRNO_RESUME_INCONSISTENT_STATE,
+ * DRMAA_ERRNO_SUSPEND_INCONSISTENT_STATE,
+ * DRMAA_ERRNO_HOLD_INCONSISTENT_STATE,
+ * DRMAA_ERRNO_RELEASE_INCONSISTENT_STATE or
+ * DRMAA_ERRNO_INVALID_JOB.
+ */
+public static native int drmaa_control(String jobid, int action, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+
+/*
+ * Wait until all jobs specified by 'job_ids' have finished
+ * execution. If 'job_ids' is DRMAA_JOB_IDS_SESSION_ALL then this routine
+ * waits for all jobs *submitted* during this DRMAA session. The timeout value
+ * is used to specify the number of seconds to wait for the job to fail finish
+ * before returning if a result is not immediately available. The value
+ * DRMAA_TIMEOUT_WAIT_FOREVER can be used to specify that routine should wait
+ * indefinitely for a result. The value DRMAA_TIMEOUT_NO_WAIT can be used to
+ * specify that the routine should return immediately if no result is available.
+ * If the call exits before timeout, all the jobs have
+ * been waited on or there was an interrupt.
+ * If the invocation exits on timeout, the return code is
+ * DRMAA_ERRNO_EXIT_TIMEOUT. The caller SHOULD check system time before and
+ * after this call in order to check how much time has passed.
+ *
+ * The dispose parameter specifies how to treat reaping information:
+ * True=1 "fake reap", i.e. dispose of the rusage data
+ * False=0 do not reap
+ *
+ * A 'job_ids' string vector containing n elements must be n+1 elements long,
+ * with the nth value, i.e. job_ids[n], being set to NULL as a delimitor.
+ *
+ * drmaa_synchronize() SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_DRM_COMMUNICATION_FAILURE,
+ * DRMAA_ERRNO_AUTH_FAILURE,
+ * DRMAA_ERRNO_NO_MEMORY,
+ * DRMAA_ERRNO_EXIT_TIMEOUT or
+ * DRMAA_ERRNO_INVALID_JOB.
+ */
+public static native int drmaa_synchronize(Pointer job_ids, NativeLong timeout, int dispose,
+ Pointer error_diagnosis, NativeLong error_diag_len);
+
+
+/*
+ * This routine SHALL wait for a job with job_id to fail or finish execution. If
+ * the special string, DRMAA_JOB_IDS_SESSION_ANY is provided as the job_id,
+ * this routine SHALL wait for any job from the session. This routine is modeled
+ * on the wait3 POSIX routine. The timeout value is used to specify the number
+ * of seconds to wait for the job to fail finish before returning if a result is
+ * not immediately available. The value DRMAA_TIMEOUT_WAIT_FOREVER can be
+ * used to specify that routine should wait indefinitely for a result. The value
+ * DRMAA_TIMEOUT_NO_WAIT may be specified that the routine should return
+ * immediately if no result is available.
+ * If the call exits before timeout ,the job has been waited on
+ * successfully or there was an interrupt.
+ * If the invocation exits on timeout, the return code is
+ * DRMAA_ERRNO_EXIT_TIMEOUT. The caller SHOULD check system time before and
+ * after this call in order to check how much time has passed.
+ * The routine reaps jobs on a successful call, so any subsequent calls
+ * to drmaa_wait SHOULD fail returning an error DRMAA_ERRNO_INVALID_JOB meaning
+ * that the job has been already reaped. This error is the same as if the job
+ * was unknown. Failing due to an elapsed timeout has an effect that it is
+ * possible to issue drmaa_wait multiple times for the same job_id. When
+ * successful, the rusage information SHALL be provided as an array of strings,
+ * where each string complies with the format <name>=<value>. The string portion
+ * <value> contains the amount of resources consumed by the job and is opaque.
+ * The 'stat' drmaa_wait parameter is used in the drmaa_w* functions for
+ * providing more detailed information about job termination if available. An
+ * analogous set of macros is defined in POSIX for analyzing the wait3(2) OUT
+ * parameter 'stat'.
+ *
+ * drmaa_wait() SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_DRM_COMMUNICATION_FAILURE,
+ * DRMAA_ERRNO_AUTH_FAILURE,
+ * DRMAA_ERRNO_NO_RUSAGE,
+ * DRMAA_ERRNO_NO_MEMORY,
+ * DRMAA_ERRNO_EXIT_TIMEOUT or
+ * DRMAA_ERRNO_INVALID_JOB.
+ */
+public static native int drmaa_wait(String job_id, Pointer job_id_out, NativeLong job_id_out_len,
+ IntByReference stat, NativeLong timeout, /* drmaa_attr_values_t ** */ PointerByReference rusage,
+ Pointer error_diagnosis, NativeLong error_diag_len);
+
+/*
+ * Evaluates into 'exited' a non-zero value if stat was returned for a
+ * job that terminated normally. A zero value can also indicate that
+ * altough the job has terminated normally an exit status is not available
+ * or that it is not known whether the job terminated normally. In both
+ * cases drmaa_wexitstatus() SHALL NOT provide exit status information.
+ * A non-zero 'exited' value indicates more detailed diagnosis can be provided
+ * by means of drmaa_wifsignaled(), drmaa_wtermsig() and drmaa_wcoredump().
+ */
+public static native int drmaa_wifexited(IntByReference exited, int stat, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+/*
+ * If the OUT parameter 'exited' of drmaa_wifexited() is non-zero,
+ * this function evaluates into 'exit_code' the exit code that the
+ * job passed to _exit() (see exit(2)) or exit(3C), or the value that
+ * the child process returned from main.
+ */
+public static native int drmaa_wexitstatus(IntByReference exit_status, int stat, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+/*
+ * Evaluates into 'signaled' a non-zero value if status was returned
+ * for a job that terminated due to the receipt of a signal. A zero value
+ * can also indicate that altough the job has terminated due to the receipt
+ * of a signal the signal is not available or that it is not known whether
+ * the job terminated due to the receipt of a signal. In both cases
+ * drmaa_wtermsig() SHALL NOT provide signal information.
+ */
+public static native int drmaa_wifsignaled(IntByReference signaled, int stat, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+/*
+ * If the OUT parameter 'signaled' of drmaa_wifsignaled(stat) is
+ * non-zero, this function evaluates into signal a string representation of the
+ * signal that caused the termination of the job. For signals declared by POSIX,
+ * the symbolic names SHALL be returned (e.g., SIGABRT, SIGALRM).
+ * For signals not declared by POSIX, any other string MAY be returned.
+ */
+public static native int drmaa_wtermsig(Pointer signal, NativeLong signal_len, int stat,
+ Pointer error_diagnosis, NativeLong error_diag_len);
+
+/*
+ * If the OUT parameter 'signaled' of drmaa_wifsignaled(stat) is
+ * non-zero, this function evaluates into 'core_dumped' a non-zero value
+ * if a core image of the terminated job was created.
+ */
+public static native int drmaa_wcoredump(IntByReference core_dumped, int stat, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+/*
+ * Evaluates into 'aborted' a non-zero value if 'stat'
+ * was returned for a job that ended before entering the running state.
+ */
+public static native int drmaa_wifaborted(IntByReference aborted, int stat, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+
+
+/*
+ * Get the program status of the job identified by 'job_id'.
+ * The possible values returned in 'remote_ps' and their meanings SHALL be:
+ *
+ * DRMAA_PS_UNDETERMINED = 0x00: process status cannot be determined
+ * DRMAA_PS_QUEUED_ACTIVE = 0x10: job is queued and active
+ * DRMAA_PS_SYSTEM_ON_HOLD = 0x11: job is queued and in system hold
+ * DRMAA_PS_USER_ON_HOLD = 0x12: job is queued and in user hold
+ * DRMAA_PS_USER_SYSTEM_ON_HOLD = 0x13: job is queued and in user and system
+ * hold
+ * DRMAA_PS_RUNNING = 0x20: job is running
+ * DRMAA_PS_SYSTEM_SUSPENDED = 0x21: job is system suspended
+ * DRMAA_PS_USER_SUSPENDED = 0x22: job is user suspended
+ * DRMAA_PS_USER_SYSTEM_SUSPENDED = 0x23: job is user and system suspended
+ * DRMAA_PS_DONE = 0x30: job finished normally
+ * DRMAA_PS_FAILED = 0x40: job finished, but failed
+ *
+ * DRMAA SHOULD always get the status of job_id from DRM system, unless the
+ * previous status has been DRMAA_PS_FAILED or DRMAA_PS_DONE and the status has
+ * been successfully cached. Terminated jobs get DRMAA_PS_FAILED status.
+ *
+ * drmaa_synchronize() SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_DRM_COMMUNICATION_FAILURE,
+ * DRMAA_ERRNO_AUTH_FAILURE,
+ * DRMAA_ERRNO_NO_MEMORY or
+ * DRMAA_ERRNO_INVALID_JOB.
+ */
+public static native int drmaa_job_ps(String job_id, IntByReference remote_ps, Pointer error_diagnosis,
+ NativeLong error_diag_len);
+
+/* ------------------- auxiliary routines ------------------- */
+
+/*
+ * SHALL return the error message text associated with the errno number. The
+ * routine SHALL return null string if called with invalid ERRNO number.
+ */
+public static native String drmaa_strerror(int drmaa_errno);
+
+/*
+ * If called before drmaa_init(), it SHALL return a comma delimited default
+ * DRMAA implementation contacts string, one per each DRM system provided
+ * implementation. If called after drmaa_init(), it SHALL return the selected
+ * contact string. The output string is Implementation dependent.
+ * drmaa_get_contact() SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_INTERNAL_ERROR.
+ */
+public static native int drmaa_get_contact(Pointer contact, NativeLong contact_len,
+ Pointer error_diagnosis, NativeLong error_diag_len);
+
+/*
+ * OUT major - major version number (non-negative integer)
+ * OUT minor - minor version number (non-negative integer)
+ * SHALL return the major and minor version numbers of the DRMAA library;
+ * for DRMAA 1.0, 'major' is 1 and 'minor' is 0.
+ */
+public static native int drmaa_version(IntByReference major, IntByReference minor,
+ Pointer error_diagnosis, NativeLong error_diag_len);
+
+
+/*
+ * If called before drmaa_init(), it SHALL return a comma delimited DRM systems
+ * string, one per each DRM system provided implementation. If called after
+ * drmaa_init(), it SHALL return the selected DRM system. The output string is
+ * implementation dependent.
+ *
+ * drmaa_get_DRM_system() SHALL return DRMAA_ERRNO_SUCCESS on success,
+ * otherwise:
+ * DRMAA_ERRNO_INTERNAL_ERROR.
+ */
+public static native int drmaa_get_DRM_system(Pointer drm_system, NativeLong drm_system_len,
+ Pointer error_diagnosis, NativeLong error_diag_len);
+
+
+/*
+ * If called before drmaa_init(), it SHALL return a comma delimited DRMAA
+ * implementations string, one per each DRM system provided implementation. If
+ * called after drmaa_init(), it SHALL return the selected DRMAA implementation.
+ * The output (string) is implementation dependent. drmaa_get_DRM_implementation
+ * routine SHALL return DRMAA_ERRNO_SUCCESS on success, otherwise:
+ * DRMAA_ERRNO_INTERNAL_ERROR.
+ */
+public static native int drmaa_get_DRMAA_implementation(Pointer drmaa_impl, NativeLong drmaa_impl_len,
+ Pointer error_diagnosis, NativeLong error_diag_len);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/lsf/v7_0_6/LibBat.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/lsf/v7_0_6/LibBat.java
new file mode 100644
index 0000000..e66a40d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/lsf/v7_0_6/LibBat.java
@@ -0,0 +1,20014 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.lsf.v7_0_6;
+
+import com.sun.jna.*;
+import com.sun.jna.ptr.*;
+import org.broadinstitute.gatk.utils.jna.clibrary.JNAUtils;
+import org.broadinstitute.gatk.utils.jna.clibrary.LibC;
+
+/*
+ NOTE: This library uses Pointer for some Struct.ByReference members going
+ against the JNA recommendations at http://jna.java.net/#structure_use
+ Instead stuct arrays are Pointers and each structure contains a
+ constructor that can accept the Pointer iff the size of the array is
+ known to be greater than zero.
+
+ This was especially problematic in jobInfoEnt->items->resName. When
+ jobInfo->reserveCnt was zero jobInfoItems->items was not necessarily null.
+
+ LSF will often reuse memory for structure arrays but will set the
+ array size / count (reserveCnt above) to zero when the array should
+ not be accessed. When LSF has reused memory and points to a non-null
+ structure pointer (items) the inner structure may contain further
+ garbage pointers (especially items->resName).
+
+ When JNA sees a non-null Structure.ByReference it will autoRead() the
+ member. When autoRead() eventually gets to the items->resName trying
+ to run strlen on the bad memory address causes a SIGSEGV.
+
+ By using a Pointer instead of the Structure.ByReference JNA will not
+ automatically autoRead(), and the API user will have to pass the
+ pointer to the Structure on their own.
+*/
+
+/**
+ * JNA wrappers for LSF's lsbatch.h and -lbat
+ *
+ * $Id: lsbatch.h,v 2.1043 2009/08/06 16:50:49 bxia Exp $
+ * -----------------------------------------------------------------
+ *
+ * Lsbatch Distributed Batch Utility --
+ *
+ * Header file for all lsbatch components: applications, lsblib,
+ * mbatchd and sbatchd
+ *
+ * ------------------------------------------------------------------
+ */
+ at SuppressWarnings("unused")
+public class LibBat {
+
+ static {
+ // via Platform LSF Configuration Reference, by default quiet the BSUB output.
+ if ("Y".equals(System.getProperty("BSUB_QUIET", "Y")))
+ LibC.setenv("BSUB_QUIET", "Y", 1);
+ String lsfLibDir = System.getenv("LSF_LIBDIR");
+ if (lsfLibDir != null) {
+ NativeLibrary.addSearchPath("lsf", lsfLibDir);
+ NativeLibrary.addSearchPath("bat", lsfLibDir);
+ }
+ /*
+ LSF 7.0.6 on the mac is missing the unsatisfied exported symbol for environ which was removed on MacOS X 10.5+.
+ nm $LSF_LIBDIR/liblsf.dylib | grep environ
+ See "man environ" for more info, along with http://lists.apple.com/archives/java-dev/2007/Dec/msg00096.html
+ For now, we export environ ourselves using libenvironhack.dylib available in c/libenvironhack.
+ */
+ if (Platform.isMac())
+ NativeLibrary.getInstance("environhack");
+ NativeLibrary liblsf = NativeLibrary.getInstance("lsf");
+ Native.register("bat");
+ // HACK: Running into a weird error:
+ // java.lang.UnsatisfiedLinkError: Unable to load library 'bat': <$LSF_LIBDIR>/libbat.so: undefined symbol: xdr_resourceInfoReq
+ // This function is very clearly unsatisfied by running 'nm $LSF_LIBDIR/libbat.so | grep xdr_resourceInfoReq' but is
+ // found in liblsf.so when running 'nm $LSF_LIBDIR/liblsf.so | grep xdr_resourceInfoReq'. For now holding on to a reference
+ // to the LSF lib just in case this is a problem with the NativeLibrary's internal WeakReferences and the library being unloaded?
+ liblsf.getFunction("xdr_resourceInfoReq").getName();
+ }
+
+ // Via support at platform.com:
+ // For equivalent api of bsub -a "xxx aaa qqq", option -a is not in struct submit, we
+ // have to use setOption_ to set it. setOption_ can be used in user program by including
+ // cmd.h or opensource.h of LSF opensource. You can refer to cmd.sub.c in opensource.
+ //
+ // Here is a demonstration on the api for bsub -a
+ // =========================================================================
+ // /*define external setOption_ function*/
+ // extern int setOption_(int argc, char **argv, char *template,
+ // struct submit *req, int mask, int mask2, char **errMsg);
+ //
+ // int setEsub(char *esub, struct submit *req) {
+ // int x;
+ // char *template, *arg[3];
+ // /*set esub with the following strings and set array length*/
+ // arg[0] = "blah";
+ // arg[1] = "-a";
+ // arg[2] = test;
+ // /* -a "test", You can add additional esubs in here. Just make sure they're space delimited. ie. "test mpich lammpi" */
+ // x=3;
+ // /*set template*/
+ // template = "a:"
+ // /*run setOption_()*/
+ // if (setOption_(x, arg, template, req, ~0, ~0, ~0, NULL) == -1) {
+ // return(-1);
+ // }
+ // else {
+ // return(0);
+ // }
+ // }
+ // =========================================================================
+
+ /**
+ * Used for setting esub and other options not in struct submit.
+ * Via support at platform.com
+ *
+ * @param argc number of args
+ * @param argv arguments including a first argument that will not be used
+ * @param template a colon delimited list of arguments in getopt format
+ * @param jobSubReq the lsf submit
+ * @param mask unknown
+ * @param mask2 unknown
+ * @param mask3 unknown
+ * @param errMsg unknown
+ * @return -1 if the option setting failed
+ */
+ public static native int setOption_(int argc, Pointer argv, String template, submit jobSubReq, int mask, int mask2, int mask3, Pointer errMsg);
+
+ /** Max job name length as defined by 'man bsub'. */
+ public static final int MAX_JOB_NAME_LEN = 4094;
+
+/* if only everyone had <paths.h> */
+ public static final String _PATH_NULL = "/dev/null";
+
+ //public static int SKIP_SPACES (int word) { while (word[0] == ' ' ) word++; }
+
+ //public static void FREEUP_ARRAY(int num, Pointer vector) { FREE_STRING_VECTOR_ENTRIES(num, vector); FREEUP(vector); }
+
+
+/* event log version:
+* each new major release requires to add a new line
+ */
+ public static final float LSB_EVENT_VERSION3_0 = 3.0f;
+ public static final float LSB_EVENT_VERSION3_1 = 3.1f;
+ public static final float LSB_EVENT_VERSION3_2 = 3.2f;
+ public static final float LSB_EVENT_VERSION4_0 = 4.0f;
+ public static final float LSB_EVENT_VERSION4_1 = 4.1f;
+ public static final float LSB_EVENT_VERSION4_2 = 4.2f;
+ public static final float LSB_EVENT_VERSION5_0 = 5.0f;
+ public static final float LSB_EVENT_VERSION5_1 = 5.1f;
+ public static final float LSB_EVENT_VERSION6_0 = 6.0f;
+ public static final float LSB_EVENT_VERSION6_1 = 6.1f;
+ public static final float LSB_EVENT_VERSION6_2 = 6.2f;
+ public static final float LSB_EVENT_VERSION7_0 = 7.0f;
+ public static final float LSB_EVENT_VERSION7_0_1 = 7.01f;
+ public static final float LSB_EVENT_VERSION7_0_2 = 7.02f;
+ public static final float LSB_EVENT_VERSION7_0_3 = 7.03f;
+ public static final float LSB_EVENT_VERSION7_0_4 = 7.04f;
+ public static final float LSB_EVENT_VERSION7_0_5 = 7.05f;
+ public static final float LSB_EVENT_VERSION7_0_6 = 7.06f;
+
+/* current event version number of the mbatchd */
+ public static final String THIS_VERSION = "7.06";
+
+ public static final int MAX_VERSION_LEN = 12;
+
+/* num of users per host partition */
+ public static final int MAX_HPART_USERS = 100;
+
+/* max byte limit, OS independent */
+ public static final int MAX_CHARLEN = 20;
+
+/* the max length of name */
+ public static final int MAX_LSB_NAME_LEN = 60;
+
+/*the max length of user group*/
+ public static final int MAX_LSB_UG_NAME_LEN = 512;
+
+/*Maximum levels that a user group hierachy can have*/
+ public static final int MAX_LSB_UG_HIERDEPTH = 64;
+
+/* the max length of command */
+ public static final int MAX_CMD_DESC_LEN = 512;
+
+/* for the local cluster */
+ public static final int MAX_CALENDARS = 256;
+
+/* max num of user equivalent entries */
+ public static final int MAX_USER_EQUIVALENT = 128;
+
+/* max num of user mapping entries */
+ public static final int MAX_USER_MAPPING = 128;
+
+/* max external msg's description length */
+ public static final int MAXDESCLEN = 20 * 512;
+
+/* num of user or host group */
+ public static final int MAX_GROUPS = 1024;
+
+/*
+* RFC #725
+ */
+
+/* max len. of a filename */
+ public static final int MAXFULLFILENAMELEN = 4096;
+ public static final int MAXFULLPATHNAMELEN = 2 * MAXFULLFILENAMELEN;
+ public static final int FILENAMEPADDING = 128;
+
+ public static final String DEFAULT_MSG_DESC = "no description";
+
+ public static final int MSGSIZE = 4096;
+
+/* RFC #725
+* extend the MSG size to 4*max filename len
+ */
+ public static final int MAXFULLMSGSIZE = 4 * MAXFULLFILENAMELEN;
+
+/* host status (hStatus) bits */
+ /**
+ * \addtogroup host_status host_status
+ * The status of the host. It is the bitwise inclusive OR of some of the following:
+ */
+
+ /**
+ * < Ready to accept and run jobs
+ */
+ public static final int HOST_STAT_OK = 0x0;
+
+/* Load is not good enough */
+ public static final int HOST_STAT_BUSY = 0x01;
+ /**
+ * < The host load is greater than a scheduling threshold. In this status, no new job will be scheduled to run on this host.
+ */
+
+/* Run windows are closed */
+ public static final int HOST_STAT_WIND = 0x02;
+ /**
+ * < The host dispatch window is closed. In this status, no new job will be accepted.
+ */
+
+/* Disabled by admin */
+ public static final int HOST_STAT_DISABLED = 0x04;
+ /**
+ * < The host has been disabled by the LSF administrator and will not accept jobs. In this status, no new job will be scheduled to run on this host.
+ */
+
+/* Lim locked by admin */
+ public static final int HOST_STAT_LOCKED = 0x08;
+ /**< The host is locked by a exclusive task. In this status, no new job will be scheduled to run on this host.*/
+
+ /**
+ * < Great than job limit
+ */
+ public static final int HOST_STAT_FULL = 0x10;
+ /**< The host has reached its job limit. In this status, no new job will be scheduled to run on this host.*/
+
+ /**
+ * < The sbatchd on this host is unreachable.
+ */
+ public static final int HOST_STAT_UNREACH = 0x20;
+
+ /**
+ * < The LIM and sbatchd on this host are unavailable.
+ */
+ public static final int HOST_STAT_UNAVAIL = 0x40;
+
+ /**
+ * < The host does not have an LSF license.
+ */
+ public static final int HOST_STAT_UNLICENSED = 0x80;
+
+ /**
+ * < The host is running an sbatchd but not a LIM.
+ */
+ public static final int HOST_STAT_NO_LIM = 0x100;
+
+ /**
+ * < Running exclusive job
+ */
+ public static final int HOST_STAT_EXCLUSIVE = 0x200;
+
+ /**
+ * < Lim locked by master LIM
+ */
+ public static final int HOST_STAT_LOCKED_MASTER = 0x400;
+
+ /**
+ * < Close a remote lease host. This flag is used together with HOST_STAT_DISABLED.
+ */
+ public static final int HOST_STAT_REMOTE_DISABLED = 0x800;
+
+ /**
+ * < Close a remote lease host due to the lease is renewing or terminating.
+ */
+ public static final int HOST_STAT_LEASE_INACTIVE = 0x1000;
+
+/* if LSF_HPC_EXTENTIONS="LSB_HCLOSE_BY_RES" is set in lsf.conf
+* host will be closed if RES is unavailable.
+ */
+
+ /**
+ * < Host is disabled by RES
+ */
+ public static final int HOST_STAT_DISABLED_RES = 0x4000;
+
+/* Kite#29531 a bit set in hData->hStatus
+* to show whether the host is closed by
+* admin or closed because RMS is not available.
+ */
+
+ /**
+ * < Host is disabled by RMS
+ */
+ public static final int HOST_STAT_DISABLED_RMS = 0x8000;
+
+/* lsf70 project scheduling, a removed host from mbatchd move into
+* a new status HOST_STAT_LOCKED_EGO
+ */
+
+ /**
+ * < The host is disabled by EGO
+ */
+ public static final int HOST_STAT_LOCKED_EGO = 0x10000;
+
+ /**
+ * < If none of the above hold, hStatus is set to HOST_STAT_OK to indicate that the host is ready to accept and run jobs.
+ */
+ public static final int HOST_CLOSED_BY_ADMIN = 0x20000;
+
+ /**
+ * < Running cu exclusive job
+ */
+ public static final int HOST_STAT_CU_EXCLUSIVE = 0x40000;
+
+/* host is ok */
+
+ public static boolean LSB_HOST_OK(int status) {
+ return (status == HOST_STAT_OK);
+ }
+
+/* host is busy */
+
+ public static boolean LSB_HOST_BUSY(int status) {
+ return ((status & HOST_STAT_BUSY) != 0);
+ }
+
+/* host is closed */
+
+ public static boolean LSB_HOST_CLOSED(int status) {
+ return ((status & (HOST_STAT_WIND | HOST_STAT_DISABLED | HOST_STAT_LOCKED | HOST_STAT_LOCKED_MASTER | HOST_STAT_FULL | HOST_STAT_CU_EXCLUSIVE | HOST_STAT_EXCLUSIVE | HOST_STAT_LEASE_INACTIVE | HOST_STAT_NO_LIM)) != 0);
+ }
+
+/* host is full */
+
+ public static boolean LSB_HOST_FULL(int status) {
+ return ((status & HOST_STAT_FULL) != 0);
+ }
+
+/* host is unlicensed */
+
+ public static boolean LSB_HOST_UNLICENSED(int status) {
+ return ((status & HOST_STAT_UNLICENSED) != 0);
+ }
+
+/* host is unreach */
+
+ public static boolean LSB_HOST_UNREACH(int status) {
+ return ((status & HOST_STAT_UNREACH) != 0);
+ }
+
+/* host is unavail */
+
+ public static boolean LSB_HOST_UNAVAIL(int status) {
+ return ((status & HOST_STAT_UNAVAIL) != 0);
+ }
+
+
+ /* host busy reason bits */
+ /**
+ * \addtogroup host_load_BusyReason host_load_BusyReason
+ * If hStatus is HOST_STAT_BUSY, these indicate the host loadSched or loadStop
+ * busy reason. If none of the thresholds have been exceeded, the value is
+ * HOST_BUSY_NOT. Otherwise the value is the bitwise inclusive OR of some of the
+ * following:
+ */
+
+ /**
+ * < Host not busy
+ */
+ public static final int HOST_BUSY_NOT = 0x000;
+
+ /**
+ * < The 15 second average CPU run queue length is too high.
+ */
+ public static final int HOST_BUSY_R15S = 0x001;
+
+ /**
+ * < The 1 minute average CPU run queue length is too high.
+ */
+ public static final int HOST_BUSY_R1M = 0x002;
+
+ /**
+ * < The 15 minute average CPU run queue length is too high.
+ */
+ public static final int HOST_BUSY_R15M = 0x004;
+
+ /**
+ * < The CPU utilization is too high.
+ */
+ public static final int HOST_BUSY_UT = 0x008;
+
+ /**
+ * < The paging rate is too high.
+ */
+ public static final int HOST_BUSY_PG = 0x010;
+
+ /**
+ * < The I/O rate is too high.
+ */
+ public static final int HOST_BUSY_IO = 0x020;
+
+ /**
+ * < There are too many login sessions.
+ */
+ public static final int HOST_BUSY_LS = 0x040;
+
+ /**
+ * < Host has not been idle long enough.
+ */
+ public static final int HOST_BUSY_IT = 0x080;
+
+ /**
+ * < There is not enough free space in the file system containing /tmp.
+ */
+ public static final int HOST_BUSY_TMP = 0x100;
+
+ /**
+ * < There is not enough free swap space.
+ */
+ public static final int HOST_BUSY_SWP = 0x200;
+
+ /**
+ * < There is not enough free memory.
+ */
+ public static final int HOST_BUSY_MEM = 0x400;
+
+/* host is busy */
+
+ public static boolean LSB_ISBUSYON(int[] status, int index) {
+ return (((status[(index) / LibLsf.INTEGER_BITS]) & (1 << (index) % LibLsf.INTEGER_BITS)) != 0);
+ }
+
+
+/* queue status (qStatus) bits */
+ /**
+ * \addtogroup queue_status queue_status
+ * queue status (qStatus) bits
+ */
+
+ /**
+ * < The queue is open to accept newly submitted jobs.
+ */
+ public static final int QUEUE_STAT_OPEN = 0x01;
+
+ /**
+ * < The queue is actively dispatching jobs. The queue can be inactivated and reactivated by the LSF administrator using \ref lsb_queuecontrol. The queue will also be inactivated when its run or dispatch window is closed. In this case it cannot be reactivated manually; it will be reactivated by the LSF system when its run and dispatch windows reopen.
+ */
+ public static final int QUEUE_STAT_ACTIVE = 0x02;
+
+ /**
+ * < The queue run and dispatch windows are open. The initial state of a queue at LSF boot time is open and either active or inactive, depending on its run and dispatch windows.
+ */
+ public static final int QUEUE_STAT_RUN = 0x04;
+
+ /**
+ * < Remote queue rejecting jobs.
+ */
+ public static final int QUEUE_STAT_NOPERM = 0x08;
+
+ /**
+ * < Remote queue status is disconnected.
+ */
+ public static final int QUEUE_STAT_DISC = 0x10;
+
+ /**
+ * < Queue run windows are closed.
+ */
+ public static final int QUEUE_STAT_RUNWIN_CLOSE = 0x20;
+
+/* queue attribute (QAttrib) bits */
+ /**
+ * \addtogroup queue_attribute queue_attribute
+ * queue attribute (QAttrib) bits.
+ */
+
+ /**
+ * < This queue accepts jobs which request exclusive execution.
+ */
+ public static final int Q_ATTRIB_EXCLUSIVE = 0x01;
+
+ /**
+ * < This queue is a default LSF queue.
+ */
+ public static final int Q_ATTRIB_DEFAULT = 0x02;
+
+ /**
+ * < This queue uses the FAIRSHARE scheduling policy. The user shares are given in userShares.
+ */
+ public static final int Q_ATTRIB_FAIRSHARE = 0x04;
+
+ /**
+ * < This queue uses the PREEMPTIVE scheduling policy.
+ */
+ public static final int Q_ATTRIB_PREEMPTIVE = 0x08;
+
+ /**
+ * < This is an NQS forward queue. The target NQS queues are given in nqsQueues. For NQS forward queues, the hostList, procJobLimit, windows, mig and windowsD fields are meaningless.
+ */
+ public static final int Q_ATTRIB_NQS = 0x10;
+
+ /**
+ * < This queue can receive jobs from other clusters
+ */
+ public static final int Q_ATTRIB_RECEIVE = 0x20;
+
+ /**
+ * < This queue uses a preemptable scheduling policy.
+ */
+ public static final int Q_ATTRIB_PREEMPTABLE = 0x40;
+
+ /**
+ * < This queue uses a backfilling policy.
+ */
+ public static final int Q_ATTRIB_BACKFILL = 0x80;
+
+ /**
+ * < This queue uses a host preference policy.
+ */
+ public static final int Q_ATTRIB_HOST_PREFER = 0x100;
+
+ /**
+ * < This queue can't preempt any other another queue.
+ */
+ public static final int Q_ATTRIB_NONPREEMPTIVE = 0x200;
+
+ /**
+ * < This queue can't be preempted from any queue.
+ */
+ public static final int Q_ATTRIB_NONPREEMPTABLE = 0x400;
+
+ /**
+ * < This queue does not accept batch interactive jobs.
+ */
+ public static final int Q_ATTRIB_NO_INTERACTIVE = 0x800;
+
+ /**
+ * < This queue only accepts batch interactive jobs.
+ */
+ public static final int Q_ATTRIB_ONLY_INTERACTIVE = 0x1000;
+
+ /**
+ * < No host type related resource name specified in resource requirement.
+ */
+ public static final int Q_ATTRIB_NO_HOST_TYPE = 0x2000;
+
+ /**
+ * < This queue disables deadline constrained resource scheduling.
+ */
+ public static final int Q_ATTRIB_IGNORE_DEADLINE = 0x4000;
+
+ /**
+ * < Jobs may run as chkpntable.
+ */
+ public static final int Q_ATTRIB_CHKPNT = 0x8000;
+
+ /**
+ * < Jobs may run as rerunnable.
+ */
+ public static final int Q_ATTRIB_RERUNNABLE = 0x10000;
+
+ /**
+ * < Excluding remote jobs when local jobs are present in the queue.
+ */
+ public static final int Q_ATTRIB_EXCL_RMTJOB = 0x20000;
+
+ /**
+ * < Turn on a multicluster fast scheduling policy.
+ */
+ public static final int Q_ATTRIB_MC_FAST_SCHEDULE = 0x40000;
+
+ /**
+ * < Push interactive jobs in front of other jobs in queue.
+ */
+ public static final int Q_ATTRIB_ENQUE_INTERACTIVE_AHEAD = 0x80000;
+
+/* Only one of the following four flags could be TRUE. By default, the queue
+* is a local queue only(none of them is set.)
+* 0x100000 - 0xf00000 is used for MC attribute
+ */
+
+
+ /**
+ * < Flags used by MultiCluster.
+ */
+ public static final int Q_MC_FLAG = 0xf00000;
+
+ /**
+ * < Lease and local.
+ */
+ public static final int Q_ATTRIB_LEASE_LOCAL = 0x100000;
+
+ /**
+ * < Lease only; no local.
+ */
+ public static final int Q_ATTRIB_LEASE_ONLY = 0x200000;
+
+ /**
+ * < Remote batch and local.
+ */
+ public static final int Q_ATTRIB_RMT_BATCH_LOCAL = 0x300000;
+
+ /**
+ * < Remote batch only.
+ */
+ public static final int Q_ATTRIB_RMT_BATCH_ONLY = 0x400000;
+
+
+ /**
+ * < Memory reservation.
+ */
+ public static final int Q_ATTRIB_RESOURCE_RESERVE = 0x1000000;
+
+ /**
+ * < Cross-queue fairshare.
+ */
+ public static final int Q_ATTRIB_FS_DISPATCH_ORDER_QUEUE = 0x2000000;
+
+ /**
+ * < Batch queue/partition
+ */
+ public static final int Q_ATTRIB_BATCH = 0x4000000;
+
+ /**
+ * < Online partition
+ */
+ public static final int Q_ATTRIB_ONLINE = 0x8000000;
+
+ /**
+ * < Interruptible backfill
+ */
+ public static final int Q_ATTRIB_INTERRUPTIBLE_BACKFILL = 0x10000000;
+
+ /**
+ * < Absolute Priority scheduling (APS) value.
+ */
+ public static final int Q_ATTRIB_APS = 0x20000000;
+
+ /**
+ * < No queue with RESOURCE_RESERVE or SLOT_RESERVE has higher priority than this queue.
+ */
+ public static final int Q_ATTRIB_NO_HIGHER_RESERVE = 0x40000000;
+
+ /**
+ * < No host valid
+ */
+ public static final int Q_ATTRIB_NO_HOST_VALID = 0x80000000;
+
+
+/* macros to check queue near real time attributes */
+
+ public static int IS_ONLINE_QUEUE(queueInfoEnt Q) {
+ return (Q.qAttrib & Q_ATTRIB_ONLINE);
+ }
+
+ public static int IS_BATCH_QUEUE(queueInfoEnt Q) {
+ return (Q.qAttrib & Q_ATTRIB_BATCH);
+ }
+
+/* macros to check queue remote attributes */
+
+ public static boolean IS_LEASE_LOCAL_QUEUE(queueInfoEnt Q) {
+ return ((Q.qAttrib & Q_MC_FLAG) == Q_ATTRIB_LEASE_LOCAL);
+ }
+
+ public static boolean IS_LEASE_ONLY_QUEUE(queueInfoEnt Q) {
+ return ((Q.qAttrib & Q_MC_FLAG) == Q_ATTRIB_LEASE_ONLY);
+ }
+
+ public static boolean IS_RMT_BATCH_LOCAL_QUEUE(queueInfoEnt Q) {
+ return ((Q.qAttrib & Q_MC_FLAG) == Q_ATTRIB_RMT_BATCH_LOCAL);
+ }
+
+ public static boolean IS_RMT_BATCH_ONLY_QUEUE(queueInfoEnt Q) {
+ return ((Q.qAttrib & Q_MC_FLAG) == Q_ATTRIB_RMT_BATCH_ONLY);
+ }
+
+ public static boolean IS_LEASE_QUEUE(queueInfoEnt Q) {
+ return (IS_LEASE_LOCAL_QUEUE(Q) || IS_LEASE_ONLY_QUEUE(Q));
+ }
+
+ public static boolean IS_RMT_BATCH_QUEUE(queueInfoEnt Q) {
+ return (IS_RMT_BATCH_LOCAL_QUEUE(Q) || IS_RMT_BATCH_ONLY_QUEUE(Q));
+ }
+
+ public static boolean IS_MC_QUEUE(queueInfoEnt Q) {
+ return (IS_LEASE_QUEUE(Q) || IS_RMT_BATCH_QUEUE(Q));
+ }
+
+ public static int SET_LEASE_LOCAL_QUEUE(queueInfoEnt Q) {
+ return (Q.qAttrib |= Q_ATTRIB_LEASE_LOCAL);
+ }
+
+ public static int SET_LEASE_ONLY_QUEUE(queueInfoEnt Q) {
+ return (Q.qAttrib |= Q_ATTRIB_LEASE_ONLY);
+ }
+
+ public static int SET_RMT_BATCH_LOCAL_QUEUE(queueInfoEnt Q) {
+ return (Q.qAttrib |= Q_ATTRIB_RMT_BATCH_LOCAL);
+ }
+
+ public static int SET_RMT_BATCH_ONLY_QUEUE(queueInfoEnt Q) {
+ return (Q.qAttrib |= Q_ATTRIB_RMT_BATCH_ONLY);
+ }
+
+ public static int CLR_MC_QUEUE_FLAG(queueInfoEnt Q) {
+ return (Q.qAttrib &= ~Q_MC_FLAG);
+ }
+
+
+/* the bits 0x10000000 to 0x80000000 is reserved for internal use (daemons.h) */
+
+/* exit code for mbatchd */
+ public static final int MASTER_NULL = 200;
+ public static final int MASTER_RESIGN = 201;
+ public static final int MASTER_RECONFIG = 202;
+ public static final int MASTER_FATAL = 203;
+ public static final int MASTER_MEM = 204;
+ public static final int MASTER_CONF = 205;
+ public static final int MASTER_EVENT = 206;
+ public static final int MASTER_DISABLE = 207;
+
+/* sub type of mbatchd die */
+ public static final int MBD_USER_CMD = 1;
+ public static final int MBD_NON_USER_CMD = 2;
+
+ /**
+ * \addtogroup job_states job_states
+ * define job states
+ */
+
+ /**
+ * < State null
+ */
+ public static final int JOB_STAT_NULL = 0x00;
+
+ /**
+ * < The job is pending, i.e., it has not been dispatched yet.
+ */
+ public static final int JOB_STAT_PEND = 0x01;
+
+ /**
+ * < The pending job was suspended by its owner or the LSF system administrator.
+ */
+ public static final int JOB_STAT_PSUSP = 0x02;
+
+ /**
+ * < The job is running.
+ */
+ public static final int JOB_STAT_RUN = 0x04;
+
+ /**
+ * < The running job was suspended by the system because an execution host was overloaded or the queue run window closed. (see \ref lsb_queueinfo, \ref lsb_hostinfo, and lsb.queues.)
+ */
+ public static final int JOB_STAT_SSUSP = 0x08;
+
+ /**
+ * < The running job was suspended by its owner or the LSF systemadministrator.
+ */
+ public static final int JOB_STAT_USUSP = 0x10;
+
+ /**
+ * < The job has terminated with a non-zero status - it may have been aborted due to an error in its execution, or killed by its owner or by the LSF system administrator.
+ */
+ public static final int JOB_STAT_EXIT = 0x20;
+
+ /**
+ * < The job has terminated with status 0.
+ */
+ public static final int JOB_STAT_DONE = 0x40;
+
+ /**
+ * < Post job process done successfully
+ */
+ public static final int JOB_STAT_PDONE = (0x80);
+
+ /**
+ * < Post job process has error
+ */
+ public static final int JOB_STAT_PERR = (0x100);
+
+ /**
+ * < Chunk job waiting its turn to exec
+ */
+ public static final int JOB_STAT_WAIT = (0x200);
+
+ /**
+ * < The slave batch daemon (sbatchd) on the host on which the job is processed has lost contact with the master batch daemon (mbatchd).
+ */
+ public static final int JOB_STAT_UNKWN = 0x10000;
+
+ /**
+ * \addtogroup event_types event_types
+ * define statements used by \ref lsb_geteventrec. Events logged in lsb.events file
+ */
+
+ /**
+ * < Submit a new job
+ */
+ public static final int EVENT_JOB_NEW = 1;
+
+ /**
+ * < mbatchd is trying to start a job
+ */
+ public static final int EVENT_JOB_START = 2;
+
+ /**
+ * < Job's status change event
+ */
+ public static final int EVENT_JOB_STATUS = 3;
+
+ /**
+ * < Job switched to another queue
+ */
+ public static final int EVENT_JOB_SWITCH = 4;
+
+ /**
+ * < Move a pending job's position within a queue
+ */
+ public static final int EVENT_JOB_MOVE = 5;
+
+ /**
+ * < Queue's status changed by Platform LSF administrator (bhc operation)
+ */
+ public static final int EVENT_QUEUE_CTRL = 6;
+
+ /**
+ * < Host status changed by Platform LSF administrator (bhc operation)
+ */
+ public static final int EVENT_HOST_CTRL = 7;
+
+ /**
+ * < Log parameters before mbatchd died
+ */
+ public static final int EVENT_MBD_DIE = 8;
+
+ /**
+ * < Action that was not taken because the mbatchd was unable to contact the sbatchd on the job's execution host
+ */
+ public static final int EVENT_MBD_UNFULFILL = 9;
+
+ /**
+ * < Job finished (Logged in lsb.acct)
+ */
+ public static final int EVENT_JOB_FINISH = 10;
+
+ /**
+ * < The complete list of load indices, including external load indices
+ */
+ public static final int EVENT_LOAD_INDEX = 11;
+
+ /**
+ * < Job checkpointed.
+ */
+ public static final int EVENT_CHKPNT = 12;
+
+ /**
+ * < Job migrated
+ */
+ public static final int EVENT_MIG = 13;
+
+ /**
+ * < The pre-execution command started
+ */
+ public static final int EVENT_PRE_EXEC_START = 14;
+
+ /**
+ * < New mbatchd start event
+ */
+ public static final int EVENT_MBD_START = 15;
+
+ /**
+ * < The job has been routed to NQS
+ */
+ public static final int EVENT_JOB_ROUTE = 16;
+
+ /**
+ * < Job modification request
+ */
+ public static final int EVENT_JOB_MODIFY = 17;
+
+ /**
+ * < Signal/delete a job
+ */
+ public static final int EVENT_JOB_SIGNAL = 18;
+
+ /**
+ * < Add new calendar to the system
+ */
+ public static final int EVENT_CAL_NEW = 19;
+
+ /**
+ * < Calendar modified
+ */
+ public static final int EVENT_CAL_MODIFY = 20;
+
+ /**
+ * < Delete a calendar in the system
+ */
+ public static final int EVENT_CAL_DELETE = 21;
+
+ /**
+ * < Job forwarded to another cluster
+ */
+ public static final int EVENT_JOB_FORWARD = 22;
+
+ /**
+ * < Job from a remote cluster dispatched
+ */
+ public static final int EVENT_JOB_ACCEPT = 23;
+
+ /**
+ * < Job status successfully sent to submission cluster
+ */
+ public static final int EVENT_STATUS_ACK = 24;
+
+ /**
+ * < Job started successfully on the execution host
+ */
+ public static final int EVENT_JOB_EXECUTE = 25;
+
+ /**
+ * < Send a message to a job
+ */
+ public static final int EVENT_JOB_MSG = 26;
+
+ /**
+ * < The message has been delivered
+ */
+ public static final int EVENT_JOB_MSG_ACK = 27;
+
+ /**
+ * < Job is requeued
+ */
+ public static final int EVENT_JOB_REQUEUE = 28;
+
+ /**
+ * < Submission mbatchd logs this after sending an occupy request to execution mbatchd
+ */
+ public static final int EVENT_JOB_OCCUPY_REQ = 29;
+
+ /**
+ * < Submission mbatchd logs this event after all execution mbatchds have vacated the occupied hosts for the job
+ */
+ public static final int EVENT_JOB_VACATED = 30;
+
+ /**
+ * < A signal action on a job has been initiated or finished
+ */
+ public static final int EVENT_JOB_SIGACT = 32;
+
+ /**
+ * < sbatchd's new job status
+ */
+ public static final int EVENT_SBD_JOB_STATUS = 34;
+
+ /**
+ * < sbatchd accepts job start
+ */
+ public static final int EVENT_JOB_START_ACCEPT = 35;
+
+ /**
+ * < Undelete a calendar in the system
+ */
+ public static final int EVENT_CAL_UNDELETE = 36;
+
+ /**
+ * < Job is cleaned out of the core
+ */
+ public static final int EVENT_JOB_CLEAN = 37;
+
+ /**
+ * < Job exception was detected
+ */
+ public static final int EVENT_JOB_EXCEPTION = 38;
+
+ /**
+ * < Adding a new job group
+ */
+ public static final int EVENT_JGRP_ADD = 39;
+
+ /**
+ * < Modifying a job group
+ */
+ public static final int EVENT_JGRP_MOD = 40;
+
+ /**
+ * < Controlling a job group
+ */
+ public static final int EVENT_JGRP_CTRL = 41;
+
+ /**
+ * < Forcing a job to start on specified hosts (brun operation)
+ */
+ public static final int EVENT_JOB_FORCE = 42;
+
+ /**
+ * < Switching the event file lsb.events
+ */
+ public static final int EVENT_LOG_SWITCH = 43;
+
+ /**
+ * < Job modification request
+ */
+ public static final int EVENT_JOB_MODIFY2 = 44;
+
+ /**
+ * < Log job group status
+ */
+ public static final int EVENT_JGRP_STATUS = 45;
+
+ /**
+ * < Job attributes have been set
+ */
+ public static final int EVENT_JOB_ATTR_SET = 46;
+
+ /**
+ * < Send an external message to a job
+ */
+ public static final int EVENT_JOB_EXT_MSG = 47;
+
+ /**
+ * < Update data status of a message for a job
+ */
+ public static final int EVENT_JOB_ATTA_DATA = 48;
+
+ /**
+ * < Insert one job to a chunk
+ */
+ public static final int EVENT_JOB_CHUNK = 49;
+
+ /**
+ * < Save unreported sbatchd status
+ */
+ public static final int EVENT_SBD_UNREPORTED_STATUS = 50;
+
+ /**
+ * < Reservation finished
+ */
+ public static final int EVENT_ADRSV_FINISH = 51;
+
+ /**
+ * < Dynamic host group control
+ */
+ public static final int EVENT_HGHOST_CTRL = 52;
+
+ /**
+ * < Saved current CPU allocation on service partition
+ */
+ public static final int EVENT_CPUPROFILE_STATUS = 53;
+
+ /**
+ * < Write out data logging file
+ */
+ public static final int EVENT_DATA_LOGGING = 54;
+
+ /**
+ * < Write job rusage in lsb.stream
+ */
+ public static final int EVENT_JOB_RUN_RUSAGE = 55;
+
+ /**
+ * < Stream closed and new stream opened.
+ */
+ public static final int EVENT_END_OF_STREAM = 56;
+
+ /**
+ * < SLA goal is reavaluated
+ */
+ public static final int EVENT_SLA_RECOMPUTE = 57;
+
+ /**
+ * < Write performance metrics to lsb.stream
+ */
+ public static final int EVENT_METRIC_LOG = 58;
+
+ /**
+ * < Write task finish log to ssched.acct
+ */
+ public static final int EVENT_TASK_FINISH = 59;
+
+ /**
+ * < Resize allocation is made
+ */
+ public static final int EVENT_JOB_RESIZE_NOTIFY_START = 60;
+
+ /**
+ * < Resize notification action initialized
+ */
+ public static final int EVENT_JOB_RESIZE_NOTIFY_ACCEPT = 61;
+
+ /**
+ * < Resize notification action completed
+ */
+ public static final int EVENT_JOB_RESIZE_NOTIFY_DONE = 62;
+
+ /**
+ * < Job resize release request is received
+ */
+ public static final int EVENT_JOB_RESIZE_RELEASE = 63;
+
+ /**
+ * < Job resize cancel request is received
+ */
+ public static final int EVENT_JOB_RESIZE_CANCEL = 64;
+
+ /**
+ * < Job resize event for lsb.acct
+ */
+ public static final int EVENT_JOB_RESIZE = 65;
+
+ /**
+ * < Saved array element's resource consumption for LSF simulator
+ */
+ public static final int EVENT_JOB_ARRAY_ELEMENT = 66;
+
+ /**
+ * < Saved LSF simulator status
+ */
+ public static final int EVENT_MBD_SIM_STATUS = 67;
+
+/* event kind
+ */
+
+ /**
+ * < it is a job related event
+ */
+ public static final int EVENT_JOB_RELATED = 1;
+
+ /**
+ * < it is a non job related event
+ */
+ public static final int EVENT_NON_JOB_RELATED = 0;
+
+ /*
+ * EXCLUSIVE PENDING REASONS
+ * a job must stay pending as long as ONE of the exclusive reasons exists
+ */
+
+/* Job Related Reasons (001 - 300)
+ */
+ /**
+ * \addtogroup pending_reasons pending_reasons
+ * \brief Each entry in the table contains one of the following pending reasons
+ */
+
+ /**
+ * < Virtual code; not a reason
+ */
+ public static final int PEND_JOB_REASON = 0;
+
+ /**
+ * < A new job is waiting to be scheduled
+ */
+ public static final int PEND_JOB_NEW = 1;
+
+ /**
+ * < The job is held until its specified start time
+ */
+ public static final int PEND_JOB_START_TIME = 2;
+
+ /**
+ * < The job is waiting for its dependency condition(s) to be satisfied
+ */
+ public static final int PEND_JOB_DEPEND = 3;
+
+ /**
+ * < The dependency condition is invalid or never satisfied
+ */
+ public static final int PEND_JOB_DEP_INVALID = 4;
+
+ /**
+ * < The migrating job is waiting to be rescheduled
+ */
+ public static final int PEND_JOB_MIG = 5;
+
+ /**
+ * < The job's pre-exec command exited with non-zero status
+ */
+ public static final int PEND_JOB_PRE_EXEC = 6;
+
+ /**
+ * < Unable to access jobfile
+ */
+ public static final int PEND_JOB_NO_FILE = 7;
+
+ /**
+ * < Unable to set job's environment variables
+ */
+ public static final int PEND_JOB_ENV = 8;
+
+ /**
+ * < Unable to determine the job's home or working directories
+ */
+ public static final int PEND_JOB_PATHS = 9;
+
+ /**
+ * < Unable to open the job's input and output files
+ */
+ public static final int PEND_JOB_OPEN_FILES = 10;
+
+ /**
+ * < Job execution initialization failed
+ */
+ public static final int PEND_JOB_EXEC_INIT = 11;
+
+ /**
+ * < Unable to copy restarting job's checkpoint files
+ */
+ public static final int PEND_JOB_RESTART_FILE = 12;
+
+ /**
+ * < Scheduling of the job is delayed
+ */
+ public static final int PEND_JOB_DELAY_SCHED = 13;
+
+ /**
+ * < Waiting for the re-scheduling of the job after switching queues
+ */
+ public static final int PEND_JOB_SWITCH = 14;
+
+ /**
+ * < An event is rejected by eeventd due to a syntax error
+ */
+ public static final int PEND_JOB_DEP_REJECT = 15;
+
+ /**
+ * < A JobScheduler feature is not enabled
+ */
+ public static final int PEND_JOB_JS_DISABLED = 16;
+
+ /**
+ * < Failed to get user password
+ */
+ public static final int PEND_JOB_NO_PASSWD = 17;
+
+ /**
+ * < The job is pending due to logon failure
+ */
+ public static final int PEND_JOB_LOGON_FAIL = 18;
+
+ /**
+ * < The job is waiting to be re-scheduled after its parameters have been changed
+ */
+ public static final int PEND_JOB_MODIFY = 19;
+
+ /**
+ * < The job time event is invalid
+ */
+ public static final int PEND_JOB_TIME_INVALID = 20;
+
+ /**
+ * < The job time event has expired
+ */
+ public static final int PEND_TIME_EXPIRED = 21;
+
+ /**
+ * < The job has been requeued
+ */
+ public static final int PEND_JOB_REQUEUED = 23;
+
+ /**
+ * < Waiting for the next time event
+ */
+ public static final int PEND_WAIT_NEXT = 24;
+
+ /**
+ * < The parent group is held
+ */
+ public static final int PEND_JGRP_HOLD = 25;
+
+ /**
+ * < The parent group is inactive
+ */
+ public static final int PEND_JGRP_INACT = 26;
+
+ /**
+ * < The group is waiting for scheduling
+ */
+ public static final int PEND_JGRP_WAIT = 27;
+
+ /**
+ * < The remote cluster(s) are unreachable
+ */
+ public static final int PEND_JOB_RCLUS_UNREACH = 28;
+
+ /**
+ * < SNDJOBS_TO queue rejected by remote clusters
+ */
+ public static final int PEND_JOB_QUE_REJECT = 29;
+
+ /**
+ * < Waiting for new remote scheduling session
+ */
+ public static final int PEND_JOB_RSCHED_START = 30;
+
+ /**
+ * < Waiting for allocation reply from remote clusters
+ */
+ public static final int PEND_JOB_RSCHED_ALLOC = 31;
+
+ /**
+ * < The job is forwarded to a remote cluster
+ */
+ public static final int PEND_JOB_FORWARDED = 32;
+
+ /**
+ * < The job running remotely is in a zombie state
+ */
+ public static final int PEND_JOB_RMT_ZOMBIE = 33;
+
+ /**
+ * < Job's enforced user group share account not selected
+ */
+ public static final int PEND_JOB_ENFUGRP = 34;
+
+ /**
+ * < The system is unable to schedule the job
+ */
+ public static final int PEND_SYS_UNABLE = 35;
+
+ /**
+ * < The parent group has just been released
+ */
+ public static final int PEND_JGRP_RELEASE = 36;
+
+ /**
+ * < The job has run since group active
+ */
+ public static final int PEND_HAS_RUN = 37;
+
+ /**
+ * < The job has reached its running element limit
+ */
+ public static final int PEND_JOB_ARRAY_JLIMIT = 38;
+
+ /**
+ * < Checkpoint directory is invalid
+ */
+ public static final int PEND_CHKPNT_DIR = 39;
+
+ /**
+ * < The first job in the chunk failed (all other jobs in the chunk are set to PEND)
+ */
+ public static final int PEND_CHUNK_FAIL = 40;
+
+ /**
+ * < Optimum number of running jobs for SLA has been reached
+ */
+ public static final int PEND_JOB_SLA_MET = 41;
+
+ /**
+ * < Specified application profile does not exist
+ */
+ public static final int PEND_JOB_APP_NOEXIST = 42;
+
+ /**
+ * < Job no longer satisfies application PROCLIMIT configuration
+ */
+ public static final int PEND_APP_PROCLIMIT = 43;
+
+ /**
+ * < No hosts for the job from EGO
+ */
+ public static final int PEND_EGO_NO_HOSTS = 44;
+
+ /**
+ * < The specified job group has reached its job limit
+ */
+ public static final int PEND_JGRP_JLIMIT = 45;
+
+ /**
+ * < Job pre-exec retry limit
+ */
+ public static final int PEND_PREEXEC_LIMIT = 46;
+
+ /**
+ * < Job re-queue limit
+ */
+ public static final int PEND_REQUEUE_LIMIT = 47;
+
+ /**
+ * < Job has bad res req
+ */
+ public static final int PEND_BAD_RESREQ = 48;
+
+ /**
+ * < Job's reservation is inactive
+ */
+ public static final int PEND_RSV_INACTIVE = 49;
+
+ /**
+ * < Job was in PSUSP with bad res req, after successful bmod waiting for the user to bresume
+ */
+ public static final int PEND_WAITING_RESUME = 50;
+
+ /**
+ * < Job slot request cannot satisfy compound resource requirement
+ */
+ public static final int PEND_SLOT_COMPOUND = 51;
+
+/*
+* Queue and System Related Reasons (301 - 599)
+ */
+
+ /**
+ * < The queue is inactivated by the administrator
+ */
+ public static final int PEND_QUE_INACT = 301;
+
+ /**
+ * < The queue is inactivated by its time windows
+ */
+ public static final int PEND_QUE_WINDOW = 302;
+
+ /**
+ * < The queue has reached its job slot limit
+ */
+ public static final int PEND_QUE_JOB_LIMIT = 303;
+
+ /**
+ * < The user has reached the per-user job slot limit of the queue
+ */
+ public static final int PEND_QUE_USR_JLIMIT = 304;
+
+ /**
+ * < Not enough per-user job slots of the queue for the parallel job
+ */
+ public static final int PEND_QUE_USR_PJLIMIT = 305;
+
+ /**
+ * < The queue's pre-exec command exited with non-zero status
+ */
+ public static final int PEND_QUE_PRE_FAIL = 306;
+
+ /**
+ * < The job was not accepted by the NQS host, Attempt again later
+ */
+ public static final int PEND_NQS_RETRY = 307;
+
+ /**
+ * < Unable to send the job to an NQS host
+ */
+ public static final int PEND_NQS_REASONS = 308;
+
+ /**
+ * < Unable to contact NQS host
+ */
+ public static final int PEND_NQS_FUN_OFF = 309;
+
+ /**
+ * < The system is not ready for scheduling after reconfiguration
+ */
+ public static final int PEND_SYS_NOT_READY = 310;
+
+ /**
+ * < The requeued job is waiting for rescheduling
+ */
+ public static final int PEND_SBD_JOB_REQUEUE = 311;
+
+ /**
+ * < Not enough hosts to meet the job's spanning requirement
+ */
+ public static final int PEND_JOB_SPREAD_TASK = 312;
+
+ /**
+ * < Not enough hosts to meet the queue's spanning requirement
+ */
+ public static final int PEND_QUE_SPREAD_TASK = 313;
+
+ /**
+ * < The queue has not enough job slots for the parallel job
+ */
+ public static final int PEND_QUE_PJOB_LIMIT = 314;
+
+ /**
+ * < The job will not finish before queue's run window is closed
+ */
+ public static final int PEND_QUE_WINDOW_WILL_CLOSE = 315;
+
+ /**
+ * < Job no longer satisfies queue PROCLIMIT configuration
+ */
+ public static final int PEND_QUE_PROCLIMIT = 316;
+
+ /**
+ * < Job requeued due to plug-in failure
+ */
+ public static final int PEND_SBD_PLUGIN = 317;
+
+ /**
+ * < Waiting for lease signing
+ */
+ public static final int PEND_WAIT_SIGN_LEASE = 318;
+
+/* waitint for scheduling for SLOT_SHARE*/
+ public static final int PEND_WAIT_SLOT_SHARE = 319;
+
+/*
+* User Related Reasons (601 - 800)
+ */
+
+ /**
+ * < The job slot limit is reached
+ */
+ public static final int PEND_USER_JOB_LIMIT = 601;
+
+ /**
+ * < A user group has reached its job slot limit
+ */
+ public static final int PEND_UGRP_JOB_LIMIT = 602;
+
+ /**
+ * < The job slot limit for the parallel job is reached
+ */
+ public static final int PEND_USER_PJOB_LIMIT = 603;
+
+ /**
+ * < A user group has reached its job slot limit for the parallel job
+ */
+ public static final int PEND_UGRP_PJOB_LIMIT = 604;
+
+ /**
+ * < Waiting for scheduling after resumed by user
+ */
+ public static final int PEND_USER_RESUME = 605;
+
+ /**
+ * < The job was suspended by the user while pending
+ */
+ public static final int PEND_USER_STOP = 607;
+
+ /**
+ * < Unable to determine user account for execution
+ */
+ public static final int PEND_NO_MAPPING = 608;
+
+ /**
+ * < The user has no permission to run the job on remote host/cluster
+ */
+ public static final int PEND_RMT_PERMISSION = 609;
+
+ /**
+ * < The job was suspended by LSF admin or root while pending
+ */
+ public static final int PEND_ADMIN_STOP = 610;
+
+ /**
+ * < The requested label is not valid
+ */
+ public static final int PEND_MLS_INVALID = 611;
+
+ /**
+ * < The requested label is above user allowed range
+ */
+ public static final int PEND_MLS_CLEARANCE = 612;
+
+ /**
+ * < The requested label rejected by /etc/rhost.conf
+ */
+ public static final int PEND_MLS_RHOST = 613;
+
+ /**
+ * < The requested label does not dominate current label
+ */
+ public static final int PEND_MLS_DOMINATE = 614;
+
+ /**
+ * < The requested label problem
+ */
+ public static final int PEND_MLS_FATAL = 615;
+
+ /**
+ * < LSF internally bstoped a pending job
+ */
+ public static final int PEND_INTERNAL_STOP = 616;
+
+/*
+* NON-EXCLUSIVE PENDING REASONS
+* A job may still start even though non-exclusive reasons exist.
+ */
+
+/*
+* Host(sbatchd)-Job Related Reasons (1001 - 1300)
+ */
+
+ /**
+ * < The job's resource requirements not satisfied
+ */
+ public static final int PEND_HOST_RES_REQ = 1001;
+
+ /**
+ * < The job's requirement for exclusive execution not satisfied
+ */
+ public static final int PEND_HOST_NONEXCLUSIVE = 1002;
+
+ /**
+ * < Higher or equal priority jobs already suspended by system
+ */
+ public static final int PEND_HOST_JOB_SSUSP = 1003;
+
+ /**
+ * < The job failed to compete with other jobs on host partition
+ */
+ public static final int PEND_HOST_PART_PRIO = 1004;
+
+ /**
+ * < Unable to get the PID of the restarting job
+ */
+ public static final int PEND_SBD_GETPID = 1005;
+
+ /**
+ * < Unable to lock the host for exclusively executing the job
+ */
+ public static final int PEND_SBD_LOCK = 1006;
+
+ /**
+ * < Cleaning up zombie job
+ */
+ public static final int PEND_SBD_ZOMBIE = 1007;
+
+ /**
+ * < Can't run jobs submitted by root. The job is rejected by the sbatchd
+ */
+ public static final int PEND_SBD_ROOT = 1008;
+
+ /**
+ * < Job can't finish on the host before queue's run window is closed
+ */
+ public static final int PEND_HOST_WIN_WILL_CLOSE = 1009;
+
+ /**
+ * < Job can't finish on the host before job's termination deadline
+ */
+ public static final int PEND_HOST_MISS_DEADLINE = 1010;
+
+ /**
+ * < The specified first execution host is not eligible for this job at this time
+ */
+ public static final int PEND_FIRST_HOST_INELIGIBLE = 1011;
+
+ /**
+ * < Exclusive job reserves slots on host
+ */
+ public static final int PEND_HOST_EXCLUSIVE_RESERVE = 1012;
+
+ /**
+ * < Resized shadow job or non-first resReq of a compound resReq job try to reuse the first execution host
+ */
+ public static final int PEND_FIRST_HOST_REUSE = 1013;
+/*
+* Host Related Reasons (1301 - 1600)
+ */
+
+ /**
+ * < The host is closed by the LSF administrator
+ */
+ public static final int PEND_HOST_DISABLED = 1301;
+
+ /**
+ * < The host is locked by the LSF administrator
+ */
+ public static final int PEND_HOST_LOCKED = 1302;
+
+ /**
+ * < Not enough job slots for the parallel job
+ */
+ public static final int PEND_HOST_LESS_SLOTS = 1303;
+
+ /**
+ * < Dispatch windows are closed
+ */
+ public static final int PEND_HOST_WINDOW = 1304;
+
+ /**
+ * < The job slot limit reached
+ */
+ public static final int PEND_HOST_JOB_LIMIT = 1305;
+
+ /**
+ * < The queue's per-CPU job slot limit is reached
+ */
+ public static final int PEND_QUE_PROC_JLIMIT = 1306;
+
+ /**
+ * < The queue's per-host job slot limit is reached
+ */
+ public static final int PEND_QUE_HOST_JLIMIT = 1307;
+
+ /**
+ * < The user's per-CPU job slot limit is reached
+ */
+ public static final int PEND_USER_PROC_JLIMIT = 1308;
+
+ /**
+ * < The host's per-user job slot limit is reached
+ */
+ public static final int PEND_HOST_USR_JLIMIT = 1309;
+
+ /**
+ * < Not a member of the queue
+ */
+ public static final int PEND_HOST_QUE_MEMB = 1310;
+
+ /**
+ * < Not a user-specified host
+ */
+ public static final int PEND_HOST_USR_SPEC = 1311;
+
+ /**
+ * < The user has no access to the host partition
+ */
+ public static final int PEND_HOST_PART_USER = 1312;
+
+ /**
+ * < There is no such user account
+ */
+ public static final int PEND_HOST_NO_USER = 1313;
+
+ /**
+ * < Just started a job recently
+ */
+ public static final int PEND_HOST_ACCPT_ONE = 1314;
+
+ /**
+ * < Load info unavailable
+ */
+ public static final int PEND_LOAD_UNAVAIL = 1315;
+
+ /**
+ * < The LIM is unreachable by the sbatchd
+ */
+ public static final int PEND_HOST_NO_LIM = 1316;
+
+ /**
+ * < The host does not have a valid LSF software license
+ */
+ public static final int PEND_HOST_UNLICENSED = 1317;
+
+ /**
+ * < The queue's resource requirements are not satisfied
+ */
+ public static final int PEND_HOST_QUE_RESREQ = 1318;
+
+ /**
+ * < The submission host type is not the same
+ */
+ public static final int PEND_HOST_SCHED_TYPE = 1319;
+
+ /**
+ * < There are not enough processors to meet the job's spanning requirement. The job level locality is unsatisfied.
+ */
+ public static final int PEND_JOB_NO_SPAN = 1320;
+
+ /**
+ * < There are not enough processors to meet the queue's spanning requirement. The queue level locality is unsatisfied.
+ */
+ public static final int PEND_QUE_NO_SPAN = 1321;
+
+ /**
+ * < An exclusive job is running
+ */
+ public static final int PEND_HOST_EXCLUSIVE = 1322;
+
+ /**
+ * < Job Scheduler is disabled on the host. It is not licensed to accept repetitive jobs.
+ */
+ public static final int PEND_HOST_JS_DISABLED = 1323;
+
+ /**
+ * < The user group's per-CPU job slot limit is reached
+ */
+ public static final int PEND_UGRP_PROC_JLIMIT = 1324;
+
+ /**
+ * < Incorrect host, group or cluster name
+ */
+ public static final int PEND_BAD_HOST = 1325;
+
+ /**
+ * < Host is not used by the queue
+ */
+ public static final int PEND_QUEUE_HOST = 1326;
+
+ /**
+ * < Host is locked by master LIM
+ */
+ public static final int PEND_HOST_LOCKED_MASTER = 1327;
+
+ /**
+ * < Not enough reserved job slots at this time for specified reservation ID
+ */
+ public static final int PEND_HOST_LESS_RSVSLOTS = 1328;
+
+ /**
+ * < Not enough slots or resources for whole duration of the job
+ */
+ public static final int PEND_HOST_LESS_DURATION = 1329;
+
+ /**
+ * < Specified reservation has expired or has been deleted
+ */
+ public static final int PEND_HOST_NO_RSVID = 1330;
+
+ /**
+ * < The host is closed due to lease is inactive
+ */
+ public static final int PEND_HOST_LEASE_INACTIVE = 1331;
+
+ /**
+ * < Not enough job slot(s) while advance reservation is active
+ */
+ public static final int PEND_HOST_ADRSV_ACTIVE = 1332;
+
+ /**
+ * < This queue is not configured to send jobs to the cluster specified in the advance
+ */
+ public static final int PEND_QUE_RSVID_NOMATCH = 1333;
+
+ /**
+ * < Individual host based reasons
+ */
+ public static final int PEND_HOST_GENERAL = 1334;
+
+ /**
+ * < Host does not belong to the specified advance reservation
+ */
+ public static final int PEND_HOST_RSV = 1335;
+
+ /**
+ * < Host does not belong to a compute unit of the required type
+ */
+ public static final int PEND_HOST_NOT_CU = 1336;
+
+ /**
+ * < A compute unit containing the host is used exclusively
+ */
+ public static final int PEND_HOST_CU_EXCL = 1337;
+
+ /**
+ * < CU-level excl. job cannot start since CU is occupied
+ */
+ public static final int PEND_HOST_CU_OCCUPIED = 1338;
+
+ /**
+ * < Insufficiently many usable slots on the host's compute unit
+ */
+ public static final int PEND_HOST_USABLE_CU = 1339;
+
+ /**
+ * < No first execution compute unit satisfies CU 'usablepercu' requirement.
+ */
+ public static final int PEND_JOB_FIRST_CU = 1340;
+
+ /**
+ * < A CU containing the host is reserved exclusively
+ */
+ public static final int PEND_HOST_CU_EXCL_RSV = 1341;
+
+ /**
+ * < Maxcus cannot be satisfied
+ */
+ public static final int PEND_JOB_CU_MAXCUS = 1342;
+
+ /**
+ * < Balance cannot be satisfied
+ */
+ public static final int PEND_JOB_CU_BALANCE = 1343;
+
+ /**
+ * < Cu not supported on toplib integration hosts
+ */
+ public static final int PEND_CU_TOPLIB_HOST = 1344;
+
+/*
+* sbatchd Related Reasons (1601 - 1900)
+ */
+
+ /**
+ * < Cannot reach sbatchd
+ */
+ public static final int PEND_SBD_UNREACH = 1601;
+
+ /**
+ * < Number of jobs exceed quota
+ */
+ public static final int PEND_SBD_JOB_QUOTA = 1602;
+
+ /**
+ * < The job failed in talking to the server to start the job
+ */
+ public static final int PEND_JOB_START_FAIL = 1603;
+
+ /**
+ * < Failed in receiving the reply from the server when starting the job
+ */
+ public static final int PEND_JOB_START_UNKNWN = 1604;
+
+ /**
+ * < Unable to allocate memory to run job. There is no memory on the sbatchd.
+ */
+ public static final int PEND_SBD_NO_MEM = 1605;
+
+ /**
+ * < Unable to fork process to run the job. There are no more processes on the sbatchd.
+ */
+ public static final int PEND_SBD_NO_PROCESS = 1606;
+
+ /**
+ * < Unable to communicate with the job process
+ */
+ public static final int PEND_SBD_SOCKETPAIR = 1607;
+
+ /**
+ * < The slave batch server failed to accept the job
+ */
+ public static final int PEND_SBD_JOB_ACCEPT = 1608;
+
+ /**
+ * < Lease job remote dispatch failed
+ */
+ public static final int PEND_LEASE_JOB_REMOTE_DISPATCH = 1609;
+
+ /**
+ * < Failed to restart job from last checkpoint
+ */
+ public static final int PEND_JOB_RESTART_FAIL = 1610;
+/*
+* Load Related Reasons (2001 - 2300)
+ */
+
+ /**
+ * < The load threshold is reached
+ */
+ public static final int PEND_HOST_LOAD = 2001;
+
+/*
+* Queue Resource Reservation Related Reasons (2301 - 2600)
+ */
+
+ /**
+ * < The queue's requirements for resource reservation are not satisfied.
+ */
+ public static final int PEND_HOST_QUE_RUSAGE = 2301;
+
+/*
+* Jobs Resource Reservation Related Reasons (2601 - 2900)
+ */
+
+ /**
+ * < The job's requirements for resource reservation are not satisfied.
+ */
+ public static final int PEND_HOST_JOB_RUSAGE = 2601;
+
+/*
+* Remote Forwarding Related Reasons (2901 - 3200)
+ */
+
+ /**
+ * < Remote job not recongized by remote cluster, waiting for rescheduling
+ */
+ public static final int PEND_RMT_JOB_FORGOTTEN = 2901;
+
+ /**
+ * < Remote import limit reached, waiting for rescheduling
+ */
+ public static final int PEND_RMT_IMPT_JOBBKLG = 2902;
+
+ /**
+ * < Remote schedule time reached, waiting for rescheduling
+ */
+ public static final int PEND_RMT_MAX_RSCHED_TIME = 2903;
+
+ /**
+ * < Remote pre-exec retry limit reached, waiting for rescheduling
+ */
+ public static final int PEND_RMT_MAX_PREEXEC_RETRY = 2904;
+
+ /**
+ * < Remote queue is closed
+ */
+ public static final int PEND_RMT_QUEUE_CLOSED = 2905;
+
+ /**
+ * < Remote queue is inactive
+ */
+ public static final int PEND_RMT_QUEUE_INACTIVE = 2906;
+
+ /**
+ * < Remote queue is congested
+ */
+ public static final int PEND_RMT_QUEUE_CONGESTED = 2907;
+
+ /**
+ * < Remote queue is disconnected
+ */
+ public static final int PEND_RMT_QUEUE_DISCONNECT = 2908;
+
+ /**
+ * < Remote queue is not configured to accept jobs from this cluster
+ */
+ public static final int PEND_RMT_QUEUE_NOPERMISSION = 2909;
+
+ /**
+ * < Job's termination time exceeds the job creation time on remote cluster
+ */
+ public static final int PEND_RMT_BAD_TIME = 2910;
+
+ /**
+ * < Permission denied on the execution cluster
+ */
+ public static final int PEND_RMT_PERMISSIONS = 2911;
+
+ /**
+ * < Job's required on number of processors cannot be satisfied on the remote cluster
+ */
+ public static final int PEND_RMT_PROC_NUM = 2912;
+
+ /**
+ * < User is not defined in the fairshare policy of the remote queue
+ */
+ public static final int PEND_RMT_QUEUE_USE = 2913;
+
+ /**
+ * < Remote queue is a non-interactive queue
+ */
+ public static final int PEND_RMT_NO_INTERACTIVE = 2914;
+
+ /**
+ * < Remote queue is an interactive-only queue
+ */
+ public static final int PEND_RMT_ONLY_INTERACTIVE = 2915;
+
+ /**
+ * < Job's required maximum number of processors is less then the minimum number
+ */
+ public static final int PEND_RMT_PROC_LESS = 2916;
+
+ /**
+ * < Job's required resource limit exceeds that of the remote queue
+ */
+ public static final int PEND_RMT_OVER_LIMIT = 2917;
+
+ /**
+ * < Job's resource requirements do not match with those of the remote queue
+ */
+ public static final int PEND_RMT_BAD_RESREQ = 2918;
+
+ /**
+ * < Job failed to be created on the remote cluster
+ */
+ public static final int PEND_RMT_CREATE_JOB = 2919;
+
+ /**
+ * < Job is requeued for rerun on the execution cluster
+ */
+ public static final int PEND_RMT_RERUN = 2920;
+
+ /**
+ * < Job is requeued on the execution cluster due to exit value
+ */
+ public static final int PEND_RMT_EXIT_REQUEUE = 2921;
+
+ /**
+ * < Job was killed and requeued on the execution cluster
+ */
+ public static final int PEND_RMT_REQUEUE = 2922;
+
+ /**
+ * < Job was forwarded to remote cluster
+ */
+ public static final int PEND_RMT_JOB_FORWARDING = 2923;
+
+ /**
+ * < Remote import queue defined for the job in lsb.queues is either not ready or not valid
+ */
+ public static final int PEND_RMT_QUEUE_INVALID = 2924;
+
+ /**
+ * < Remote queue is a non-exclusive queue
+ */
+ public static final int PEND_RMT_QUEUE_NO_EXCLUSIVE = 2925;
+
+ /**
+ * < Job was rejected; submitter does not belong to the specified User Group in the remote cluster or the user group does not exist in the remote cluster
+ */
+ public static final int PEND_RMT_UGROUP_MEMBER = 2926;
+
+ /**
+ * < Remote queue is rerunnable: can not accept interactive jobs
+ */
+ public static final int PEND_RMT_INTERACTIVE_RERUN = 2927;
+
+ /**
+ * < Remote cluster failed in talking to server to start the job
+ */
+ public static final int PEND_RMT_JOB_START_FAIL = 2928;
+
+ /**
+ * < Job was rejected; submitter does not belong to the specified User Group in the remote cluster or the user group does not exist in the remote cluster
+ */
+ public static final int PEND_RMT_FORWARD_FAIL_UGROUP_MEMBER = 2930;
+
+ /**
+ * < Specified remote reservation has expired or has been deleted
+ */
+ public static final int PEND_RMT_HOST_NO_RSVID = 2931;
+
+ /**
+ * < Application profile could not be found in the remote cluster.
+ */
+ public static final int PEND_RMT_APP_NULL = 2932;
+
+ /**
+ * < Job's required RUNLIMIT exceeds RUNTIME* JOB_RUNLIMIT_RATIO of the remote cluster.
+ */
+ public static final int PEND_RMT_BAD_RUNLIMIT = 2933;
+
+ /**
+ * < Job's required RUNTIME exceeds the hard runtime limit in the remote queue.
+ */
+ public static final int PEND_RMT_OVER_QUEUE_LIMIT = 2934;
+
+ /**
+ * < Job will be pend when no slots available among remote queues.
+ */
+ public static final int PEND_RMT_WHEN_NO_SLOTS = 2935;
+/* SUSPENDING REASONS */
+
+/*
+* General Resource Limits Related Reasons ( 3201 - 4800)
+ */
+
+ /**
+ * < Resource limit defined on user or user group has been reached.
+ */
+ public static final int PEND_GENERAL_LIMIT_USER = 3201;
+
+ /**
+ * < Resource (%s) limit defined on queue has been reached.
+ */
+ public static final int PEND_GENERAL_LIMIT_QUEUE = 3501;
+
+ /**
+ * < Resource limit defined on project has been reached.
+ */
+ public static final int PEND_GENERAL_LIMIT_PROJECT = 3801;
+
+ /**
+ * < Resource (%s) limit defined cluster wide has been reached.
+ */
+ public static final int PEND_GENERAL_LIMIT_CLUSTER = 4101;
+
+ /**
+ * < Resource (%s) limit defined on host and/or host group has been reached.
+ */
+ public static final int PEND_GENERAL_LIMIT_HOST = 4401;
+
+ /**
+ * < JOBS limit defined for the user or user group has been reached.
+ */
+ public static final int PEND_GENERAL_LIMIT_JOBS_USER = 4701;
+
+ /**
+ * < JOBS limit defined for the queue has been reached.
+ */
+ public static final int PEND_GENERAL_LIMIT_JOBS_QUEUE = 4702;
+
+ /**
+ * < JOBS limit defined for the project has been reached.
+ */
+ public static final int PEND_GENERAL_LIMIT_JOBS_PROJECT = 4703;
+
+ /**
+ * < JOBS limit defined cluster-wide has been reached.
+ */
+ public static final int PEND_GENERAL_LIMIT_JOBS_CLUSTER = 4704;
+
+ /**
+ * < JOBS limit defined on host or host group has been reached.
+ */
+ public static final int PEND_GENERAL_LIMIT_JOBS_HOST = 4705;
+
+/* LSF2 Presto RLA-related reasons (4900 - 4989) */
+
+ /**
+ * < RMS scheduler plugin internal error.
+ */
+ public static final int PEND_RMS_PLUGIN_INTERNAL = 4900;
+
+ /**
+ * < RLA communication failure.
+ */
+ public static final int PEND_RMS_PLUGIN_RLA_COMM = 4901;
+
+ /**
+ * < RMS is not available.
+ */
+ public static final int PEND_RMS_NOT_AVAILABLE = 4902;
+
+ /**
+ * < Cannot satisfy the topology requirement.
+ */
+ public static final int PEND_RMS_FAIL_TOPOLOGY = 4903;
+
+ /**
+ * < Cannot allocate an RMS resource.
+ */
+ public static final int PEND_RMS_FAIL_ALLOC = 4904;
+
+ /**
+ * < RMS job with special topology requirements cannot be preemptive or backfill job.
+ */
+ public static final int PEND_RMS_SPECIAL_NO_PREEMPT_BACKFILL = 4905;
+
+ /**
+ * < RMS job with special topology requirements cannot reserve slots.
+ */
+ public static final int PEND_RMS_SPECIAL_NO_RESERVE = 4906;
+
+ /**
+ * < RLA internal error.
+ */
+ public static final int PEND_RMS_RLA_INTERNAL = 4907;
+
+ /**
+ * < Not enough slots for job. Job with RMS topology requirements cannot reserve slots, be preemptive, or be a backfill job.
+ */
+ public static final int PEND_RMS_NO_SLOTS_SPECIAL = 4908;
+
+ /**
+ * < User account does not exist on the execution host.
+ */
+ public static final int PEND_RMS_RLA_NO_SUCH_USER = 4909;
+
+ /**
+ * < Unknown host and/or partition unavailable.
+ */
+ public static final int PEND_RMS_RLA_NO_SUCH_HOST = 4910;
+
+ /**
+ * < Cannot schedule chunk jobs to RMS hosts.
+ */
+ public static final int PEND_RMS_CHUNKJOB = 4911;
+
+ /**
+ * < RLA protocol mismatch.
+ */
+ public static final int PEND_RLA_PROTOMISMATCH = 4912;
+
+ /**
+ * < Contradictory topology requirements specified.
+ */
+ public static final int PEND_RMS_BAD_TOPOLOGY = 4913;
+
+ /**
+ * < Not enough slots to satisfy manditory contiguous requirement.
+ */
+ public static final int PEND_RMS_RESREQ_MCONT = 4914;
+
+ /**
+ * < Not enough slots to satisfy RMS ptile requirement.
+ */
+ public static final int PEND_RMS_RESREQ_PTILE = 4915;
+
+ /**
+ * < Not enough slots to satisfy RMS nodes requirement.
+ */
+ public static final int PEND_RMS_RESREQ_NODES = 4916;
+
+ /**
+ * < Cannot satisfy RMS base node requirement.
+ */
+ public static final int PEND_RMS_RESREQ_BASE = 4917;
+
+ /**
+ * < Cannot satisfy RMS rails requirement.
+ */
+ public static final int PEND_RMS_RESREQ_RAILS = 4918;
+
+ /**
+ * < Cannot satisfy RMS railmask requirement.
+ */
+ public static final int PEND_RMS_RESREQ_RAILMASK = 4919;
+
+
+/*
+* Maui Integration Related Reasons ( 5000 - 5100)
+ */
+
+ /**
+ * < Unable to communicate with external Maui scheduler.
+ */
+ public static final int PEND_MAUI_UNREACH = 5000;
+
+ /**
+ * < Job is pending at external Maui scheduler.
+ */
+ public static final int PEND_MAUI_FORWARD = 5001;
+
+ /**
+ * < External Maui scheduler sets detail reason.
+ */
+ public static final int PEND_MAUI_REASON = 5030;
+
+/*
+* SGI CPUSET Integration Related Reasons ( 5200 - 5299)
+ */
+
+ /**
+ * < CPUSET attach failed. Job requeued
+ */
+ public static final int PEND_CPUSET_ATTACH = 5200;
+
+ /**
+ * < Not a cpuset host
+ */
+ public static final int PEND_CPUSET_NOT_CPUSETHOST = 5201;
+
+ /**
+ * < Topd initialization failed
+ */
+ public static final int PEND_CPUSET_TOPD_INIT = 5202;
+
+ /**
+ * < Topd communication timeout
+ */
+ public static final int PEND_CPUSET_TOPD_TIME_OUT = 5203;
+
+ /**
+ * < Cannot satisfy the cpuset allocation requirement
+ */
+ public static final int PEND_CPUSET_TOPD_FAIL_ALLOC = 5204;
+
+ /**
+ * < Bad cpuset allocation request
+ */
+ public static final int PEND_CPUSET_TOPD_BAD_REQUEST = 5205;
+
+ /**
+ * < Topd internal error
+ */
+ public static final int PEND_CPUSET_TOPD_INTERNAL = 5206;
+
+ /**
+ * < Cpuset system API failure
+ */
+ public static final int PEND_CPUSET_TOPD_SYSAPI_ERR = 5207;
+
+ /**
+ * < Specified static cpuset does not exist on the host
+ */
+ public static final int PEND_CPUSET_TOPD_NOSUCH_NAME = 5208;
+
+ /**
+ * < Cpuset is already allocated for this job
+ */
+ public static final int PEND_CPUSET_TOPD_JOB_EXIST = 5209;
+
+ /**
+ * < Topd malloc failure
+ */
+ public static final int PEND_CPUSET_TOPD_NO_MEMORY = 5210;
+
+ /**
+ * < User account does not exist on the cpuset host
+ */
+ public static final int PEND_CPUSET_TOPD_INVALID_USER = 5211;
+
+ /**
+ * < User does not have permission to run job within cpuset
+ */
+ public static final int PEND_CPUSET_TOPD_PERM_DENY = 5212;
+
+ /**
+ * < Topd is not available
+ */
+ public static final int PEND_CPUSET_TOPD_UNREACH = 5213;
+
+ /**
+ * < Topd communication failure
+ */
+ public static final int PEND_CPUSET_TOPD_COMM_ERR = 5214;
+
+
+ /**
+ * < CPUSET scheduler plugin internal error
+ */
+ public static final int PEND_CPUSET_PLUGIN_INTERNAL = 5215;
+
+ /**
+ * < Cannot schedule chunk jobs to cpuset hosts
+ */
+ public static final int PEND_CPUSET_CHUNKJOB = 5216;
+
+ /**
+ * < Can't satisfy CPU_LIST requirement
+ */
+ public static final int PEND_CPUSET_CPULIST = 5217;
+
+ /**
+ * < Cannot satisfy CPUSET MAX_RADIUS requirement
+ */
+ public static final int PEND_CPUSET_MAXRADIUS = 5218;
+
+/* Bproc integration related reasons (5300 - 5320)
+ */
+
+ /**
+ * < Node allocation failed
+ */
+ public static final int PEND_NODE_ALLOC_FAIL = 5300;
+
+/* Eagle pending reasons (5400 - 5449) */
+
+ /**
+ * < RMS resource is not available
+ */
+ public static final int PEND_RMSRID_UNAVAIL = 5400;
+
+
+ /**
+ * < Not enough free cpus to satisfy job requirements
+ */
+ public static final int PEND_NO_FREE_CPUS = 5450;
+
+ /**
+ * < Topology unknown or recently changed
+ */
+ public static final int PEND_TOPOLOGY_UNKNOWN = 5451;
+
+ /**
+ * < Contradictory topology requirement specified
+ */
+ public static final int PEND_BAD_TOPOLOGY = 5452;
+
+ /**
+ * < RLA communications failure
+ */
+ public static final int PEND_RLA_COMM = 5453;
+
+ /**
+ * < User account does not exist on execution host
+ */
+ public static final int PEND_RLA_NO_SUCH_USER = 5454;
+
+ /**
+ * < RLA internal error
+ */
+ public static final int PEND_RLA_INTERNAL = 5455;
+
+ /**
+ * < Unknown host and/or partition unavailable
+ */
+ public static final int PEND_RLA_NO_SUCH_HOST = 5456;
+
+ /**
+ * < Too few slots for specified topology requirement
+ */
+ public static final int PEND_RESREQ_TOOFEWSLOTS = 5457;
+
+/* PSET pending reasons (5500 - 5549) */
+
+ /**
+ * < PSET scheduler plugin internal error
+ */
+ public static final int PEND_PSET_PLUGIN_INTERNAL = 5500;
+
+ /**
+ * < Cannot satisfy PSET ptile requirement
+ */
+ public static final int PEND_PSET_RESREQ_PTILE = 5501;
+
+ /**
+ * < Cannot satisfy PSET cells requirement
+ */
+ public static final int PEND_PSET_RESREQ_CELLS = 5502;
+
+ /**
+ * < Cannot schedule chunk jobs to PSET hosts
+ */
+ public static final int PEND_PSET_CHUNKJOB = 5503;
+
+ /**
+ * < Host does not support processor set functionality
+ */
+ public static final int PEND_PSET_NOTSUPPORT = 5504;
+
+ /**
+ * < PSET bind failed. Job requeued
+ */
+ public static final int PEND_PSET_BIND_FAIL = 5505;
+
+ /**
+ * < Cannot satisfy PSET CELL_LIST requirement
+ */
+ public static final int PEND_PSET_RESREQ_CELLLIST = 5506;
+
+
+/* SLURM pending reasons (5550 - 5599) */
+
+ /**
+ * < SLURM scheduler plugin internal error
+ */
+ public static final int PEND_SLURM_PLUGIN_INTERNAL = 5550;
+
+ /**
+ * < Not enough resource to satisfy SLURM nodes requirment
+ */
+ public static final int PEND_SLURM_RESREQ_NODES = 5551;
+
+ /**
+ * < Not enough resource to satisfy SLURM node attributes requirment.
+ */
+ public static final int PEND_SLURM_RESREQ_NODE_ATTR = 5552;
+
+ /**
+ * < Not enough resource to satisfy SLURM exclude requirment.
+ */
+ public static final int PEND_SLURM_RESREQ_EXCLUDE = 5553;
+
+ /**
+ * < Not enough resource to satisfy SLURM nodelist requirment.
+ */
+ public static final int PEND_SLURM_RESREQ_NODELIST = 5554;
+
+ /**
+ * < Not enough resource to satisfy SLURM contiguous requirment.
+ */
+ public static final int PEND_SLURM_RESREQ_CONTIGUOUS = 5555;
+
+ /**
+ * < SLURM allocation is not available. Job requeued.
+ */
+ public static final int PEND_SLURM_ALLOC_UNAVAIL = 5556;
+
+ /**
+ * < Invalid grammar in SLURM constraints option, job will never run.
+ */
+ public static final int PEND_SLURM_RESREQ_BAD_CONSTRAINT = 5557;
+
+/* Cray X1 pending reasons (5600 - 5649) */
+
+ /**
+ * < Not enough SSPs for job
+ */
+ public static final int PEND_CRAYX1_SSP = 5600;
+
+ /**
+ * < Not enough MSPs for job
+ */
+ public static final int PEND_CRAYX1_MSP = 5601;
+
+ /**
+ * < Unable to pass limit information to psched.
+ */
+ public static final int PEND_CRAYX1_PASS_LIMIT = 5602;
+
+/* Cray XT3 pending reasons (5650 - 5699) */
+
+ /**
+ * < Unable to create or assign a partition by CPA
+ */
+ public static final int PEND_CRAYXT3_ASSIGN_FAIL = 5650;
+
+/* BlueGene pending reasons (5700 - 5749) */
+
+ /**
+ * < BG/L: Scheduler plug-in internal error.
+ */
+ public static final int PEND_BLUEGENE_PLUGIN_INTERNAL = 5700;
+
+ /**
+ * < BG/L: Allocation is not available. Job requeued.
+ */
+ public static final int PEND_BLUEGENE_ALLOC_UNAVAIL = 5701;
+
+ /**
+ * < BG/L: No free base partitions available for a full block allocation.
+ */
+ public static final int PEND_BLUEGENE_NOFREEMIDPLANES = 5702;
+
+ /**
+ * < BG/L: No free quarters available for a small block allocation.
+ */
+ public static final int PEND_BLUEGENE_NOFREEQUARTERS = 5703;
+
+ /**
+ * < BG/L: No free node cards available for a small block allocation.
+ */
+ public static final int PEND_BLUEGENE_NOFREENODECARDS = 5704;
+
+/* resize enhancement releated pending reasons */
+
+ /**
+ * < First execution host unavailable
+ */
+ public static final int PEND_RESIZE_FIRSTHOSTUNAVAIL = 5705;
+
+ /**
+ * < Master is not in the RUN state
+ */
+ public static final int PEND_RESIZE_MASTERSUSP = 5706;
+
+ /**
+ * < Host is not same as for master
+ */
+ public static final int PEND_RESIZE_MASTER_SAME = 5707;
+
+ /**
+ * < Host already used by master
+ */
+ public static final int PEND_RESIZE_SPAN_PTILE = 5708;
+
+ /**
+ * < The job can only use first host
+ */
+ public static final int PEND_RESIZE_SPAN_HOSTS = 5709;
+
+ /**
+ * < The job cannot get slots on remote hosts
+ */
+ public static final int PEND_RESIZE_LEASE_HOST = 5710;
+
+/* compound resreq related pending reasons (5800 - ??) */
+
+ /**
+ * < The job cannot get slots on pre-7Update5 remote hosts
+ */
+ public static final int PEND_COMPOUND_RESREQ_OLD_LEASE_HOST = 5800;
+
+ /**
+ * < Hosts using LSF HPC system integrations do not support compound resource requirements.
+ */
+ public static final int PEND_COMPOUND_RESREQ_TOPLIB_HOST = 5801;
+/* multi-phase resreq related pending reasons (5900 - ??) */
+
+ /**
+ * < The job cannot get slots on pre-7Update6 remote hosts
+ */
+ public static final int PEND_MULTIPHASE_RESREQ_OLD_LEASE_HOST = 5900;
+
+/* EGO-Enabled SLA pending reasons (5750 - 5799) */
+
+ /**
+ * < Host does not have enough slots for this SLA job.
+ */
+ public static final int PEND_PS_PLUGIN_INTERNAL = 5750;
+
+ /**
+ * < EGO SLA: Failed to synchronize resource with MBD.
+ */
+ public static final int PEND_PS_MBD_SYNC = 5751;
+
+
+/* PLATFORM reserves pending reason number from 1 - 20000.
+* External plugin is suggested to use platform's reserved pending reason
+* number. However, they can use pending reason number between 20001 - 25000
+* as customer specific pending reasons. In this case, bjobs -p will only show
+* the reason number without detailed message
+ */
+
+ /**
+ * < Customized pending reason number between min and max.
+ */
+ public static final int PEND_CUSTOMER_MIN = 20001;
+
+ /**
+ * < Customized pending reason number between min and max.
+ */
+ public static final int PEND_CUSTOMER_MAX = 25000;
+
+
+ /**
+ * < The maximum number of reasons
+ */
+ public static final int PEND_MAX_REASONS = 25001;
+
+ /**
+ * \addtogroup suspending_reasons suspending_reasons
+ * suspending_reasons is part of pending_reasons
+ */
+/* SUSPENDING REASONS */
+
+/* User related reasons */
+
+ /**
+ * < Virtual code. Not a reason
+ */
+ public static final int SUSP_USER_REASON = 0x00000000;
+
+ /**
+ * < The job is waiting to be re-scheduled after being resumed by the user.
+ */
+ public static final int SUSP_USER_RESUME = 0x00000001;
+
+ /**
+ * < The user suspended the job.
+ */
+ public static final int SUSP_USER_STOP = 0x00000002;
+
+/* Queue and system related reasons */
+
+ /**
+ * < Virtual code. Not a reason
+ */
+ public static final int SUSP_QUEUE_REASON = 0x00000004;
+
+ /**
+ * < The run window of the queue is closed.
+ */
+ public static final int SUSP_QUEUE_WINDOW = 0x00000008;
+
+ /**
+ * < Suspended after preemption. The system needs to re-allocate CPU utilization by job priority.
+ */
+ public static final int SUSP_RESCHED_PREEMPT = 0x00000010;
+
+ /**
+ * < The LSF administrator has locked the execution host.
+ */
+ public static final int SUSP_HOST_LOCK = 0x00000020;
+
+ /**
+ * < A load index exceeds its threshold. The subreasons field indicates which indices.
+ */
+ public static final int SUSP_LOAD_REASON = 0x00000040;
+
+ /**
+ * < The job was preempted by mbatchd because of a higher priorty job.
+ */
+ public static final int SUSP_MBD_PREEMPT = 0x00000080;
+
+ /**
+ * < Preempted by sbatchd. The job limit of the host/user has been reached.
+ */
+ public static final int SUSP_SBD_PREEMPT = 0x00000100;
+
+ /**
+ * < The suspend conditions of the queue, as specified by the STOP_COND parameter in lsb.queues, are true.
+ */
+ public static final int SUSP_QUE_STOP_COND = 0x00000200;
+
+ /**
+ * < The resume conditions of the queue, as specified by the RESUME_COND parameter in lsb.queues, are false.
+ */
+ public static final int SUSP_QUE_RESUME_COND = 0x00000400;
+
+ /**
+ * < The job was suspended due to the paging rate and the host is not idle yet.
+ */
+ public static final int SUSP_PG_IT = 0x00000800;
+
+ /**
+ * < Resets the previous reason.
+ */
+ public static final int SUSP_REASON_RESET = 0x00001000;
+
+ /**
+ * < Load information on the execution hosts is unavailable.
+ */
+ public static final int SUSP_LOAD_UNAVAIL = 0x00002000;
+
+ /**
+ * < The job was suspened by root or the LSF administrator.
+ */
+ public static final int SUSP_ADMIN_STOP = 0x00004000;
+
+ /**
+ * < The job is terminated due to resource limit.
+ */
+ public static final int SUSP_RES_RESERVE = 0x00008000;
+
+ /**
+ * < The job is locked by the mbatchd.
+ */
+ public static final int SUSP_MBD_LOCK = 0x00010000;
+
+ /**
+ * < The job's requirements for resource reservation are not satisfied.
+ */
+ public static final int SUSP_RES_LIMIT = 0x00020000;
+
+ /**
+ * < The job is suspended while the sbatchd is restarting.
+ */
+ public static final int SUSP_SBD_STARTUP = 0x00040000;
+
+ /**
+ * < The execution host is locked by the master LIM.
+ */
+ public static final int SUSP_HOST_LOCK_MASTER = 0x00080000;
+
+ /**
+ * < An advance reservation using the host is active
+ */
+ public static final int SUSP_HOST_RSVACTIVE = 0x00100000;
+
+ /**
+ * < There is a detailed reason in the subreason field
+ */
+ public static final int SUSP_DETAILED_SUBREASON = 0x00200000;
+ /* GLB suspending reason */
+
+ /**
+ * < The job is preempted by glb
+ */
+ public static final int SUSP_GLB_LICENSE_PREEMPT = 0x00400000;
+
+ /* Cray X1 suspend reasons */
+
+ /**
+ * < Job not placed by Cray X1 psched
+ */
+ public static final int SUSP_CRAYX1_POSTED = 0x00800000;
+
+ /**
+ * < Job suspended when its advance reservation expired
+ */
+ public static final int SUSP_ADVRSV_EXPIRED = 0x01000000;
+
+ /**
+ * \addtogroup suspending_subreasons suspending_subreasons
+ * suspending_subreasons has the following options:
+ */
+
+ /**
+ * < Sub reason of SUSP_RES_LIMIT: RUNLIMIT is reached.
+ */
+ public static final int SUB_REASON_RUNLIMIT = 0x00000001;
+
+ /**
+ * < Sub reason of SUSP_RES_LIMIT: DEADLINE is reached.
+ */
+ public static final int SUB_REASON_DEADLINE = 0x00000002;
+
+ /**
+ * < Sub reason of SUSP_RES_LIMIT: PROCESSLIMIT is reached.
+ */
+ public static final int SUB_REASON_PROCESSLIMIT = 0x00000004;
+
+ /**
+ * < Sub reason of SUSP_RES_LIMIT: CPULIMIT is reached.
+ */
+ public static final int SUB_REASON_CPULIMIT = 0x00000008;
+
+ /**
+ * < Sub reason of SUSP_RES_LIMIT: MEMLIMIT is reached.
+ */
+ public static final int SUB_REASON_MEMLIMIT = 0x00000010;
+
+ /**
+ * < Sub reason of SUSP_RES_LIMIT: THREADLIMIT is reached.
+ */
+ public static final int SUB_REASON_THREADLIMIT = 0x00000020;
+
+ /**
+ * < Sub reason of SUSP_RES_LIMIT: SWAPLIMIT is reached.
+ */
+ public static final int SUB_REASON_SWAPLIMIT = 0x00000040;
+
+ /**
+ * < Account ID does not match those allowed by the gate
+ */
+ public static final int SUB_REASON_CRAYX1_ACCOUNTID = 0x00000001;
+
+ /**
+ * < Attribute does not match those allowed by the gate
+ */
+ public static final int SUB_REASON_CRAYX1_ATTRIBUTE = 0x00000002;
+
+ /**
+ * < Blocked by one or more gates
+ */
+ public static final int SUB_REASON_CRAYX1_BLOCKED = 0x00000004;
+
+ /**
+ * < Application is in the process of being restarted and it is under the control of CPR
+ */
+ public static final int SUB_REASON_CRAYX1_RESTART = 0x00000008;
+
+ /**
+ * < Depth does not match those allowed by the gate
+ */
+ public static final int SUB_REASON_CRAYX1_DEPTH = 0x00000010;
+
+ /**
+ * < GID does not match those allowed by the gate
+ */
+ public static final int SUB_REASON_CRAYX1_GID = 0x00000020;
+
+ /**
+ * < No GASID is available
+ */
+ public static final int SUB_REASON_CRAYX1_GASID = 0x00000040;
+
+ /**
+ * < Hard label does not match those allowed by the gate
+ */
+ public static final int SUB_REASON_CRAYX1_HARDLABEL = 0x00000080;
+
+ /**
+ * < Limit exceeded in regions or domains
+ */
+ public static final int SUB_REASON_CRAYX1_LIMIT = 0x00000100;
+
+ /**
+ * < Memory size does not match those allowed by the gate
+ */
+ public static final int SUB_REASON_CRAYX1_MEMORY = 0x00000200;
+
+ /**
+ * < Soft label does not match those allowed by the gate
+ */
+ public static final int SUB_REASON_CRAYX1_SOFTLABEL = 0x00000400;
+
+ /**
+ * < Size gate (width times depth larger than gate allows)
+ */
+ public static final int SUB_REASON_CRAYX1_SIZE = 0x00000800;
+
+ /**
+ * < Time limit does not match those allowed by the gate
+ */
+ public static final int SUB_REASON_CRAYX1_TIME = 0x00001000;
+
+ /**
+ * < UID does not match those allowed by the gate
+ */
+ public static final int SUB_REASON_CRAYX1_UID = 0x00002000;
+
+ /**
+ * < Width does not match those allowed by the gate
+ */
+ public static final int SUB_REASON_CRAYX1_WIDTH = 0x00004000;
+/*
+* EXITING REASONS: currently only to indicate exited due to
+* 1) rerunnable job being restart from last chkpnt;
+* 2) being killed while execution host is unavailable
+ */
+
+ /** Job finished normally */
+ public static final int EXIT_NORMAL = 0x00000000;
+
+ /** Rerunnable job to be restarted */
+ public static final int EXIT_RESTART = 0x00000001;
+
+ /** Job killed while host unavailable */
+ public static final int EXIT_ZOMBIE = 0x00000002;
+
+ /** Job is finished and put into pend list */
+ public static final int FINISH_PEND = 0x00000004;
+
+ /** The job is killed while the execution host is unreach */
+ public static final int EXIT_KILL_ZOMBIE = 0x00000008;
+
+ /** The job in ZOMBIE is removed */
+ public static final int EXIT_ZOMBIE_JOB = 0x00000010;
+
+ /** Rerun a job without creating a ZOMBIE job */
+ public static final int EXIT_RERUN = 0x00000020;
+
+ /** Remote job has no mapping user name here */
+ public static final int EXIT_NO_MAPPING = 0x00000040;
+
+ /** Remote job has no permission running here */
+ public static final int EXIT_REMOTE_PERMISSION = 0x00000080;
+
+ /** Remote job cannot run locally because of environment problem */
+ public static final int EXIT_INIT_ENVIRON = 0x00000100;
+
+ /** Remote job failed in pre_exec command */
+ public static final int EXIT_PRE_EXEC = 0x00000200;
+
+ /** The job is killed and will be later requeued */
+ public static final int EXIT_REQUEUE = 0x00000400;
+
+ /** Job could not be killed but was removed from system */
+ public static final int EXIT_REMOVE = 0x00000800;
+
+ /** Requeue by exit value */
+ public static final int EXIT_VALUE_REQUEUE = 0x00001000;
+
+ /** Cancel request received from remote cluster. */
+ public static final int EXIT_CANCEL = 0x00002000;
+
+ /** MED killed job on web server */
+ public static final int EXIT_MED_KILLED = 0x00004000;
+
+ /** Remote lease job exit on execution, side, return to pend on submission */
+ public static final int EXIT_REMOTE_LEASE_JOB = 0x00008000;
+
+ /** Exit when cwd does not exist*/
+ public static final int EXIT_CWD_NOTEXIST = 0x00010000;
+
+
+ /** Mode indicating running in batch, js, or batch-js mode */
+ public static final int LSB_MODE_BATCH = 0x1;
+ public static final int LSB_MODE_JS = 0x2;
+ public static final int LSB_MODE_BATCH_RD = 0x4;
+
+ public static final int RLIMIT_CPU = 0;
+ public static final int RLIMIT_FSIZE = 1;
+ public static final int RLIMIT_DATA = 2;
+ public static final int RLIMIT_STACK = 3;
+ public static final int RLIMIT_CORE = 4;
+ public static final int RLIMIT_RSS = 5;
+ public static final int RLIM_INFINITY = 0x7fffffff;
+
+/*
+* Error codes for lsblib calls
+* Each error code has its corresponding error message defined in lsb.err.c
+* The code number is just the position number of its message.
+* Adding a new code here must add its message there in the corresponding
+* position. Changing any code number here must change the position there.
+ */
+/* Error codes related to job */
+
+ /** No error at all */
+ public static final int LSBE_NO_ERROR = 0;
+
+ /** No matching job found */
+ public static final int LSBE_NO_JOB = 1;
+
+ /** Job not started yet */
+ public static final int LSBE_NOT_STARTED = 2;
+
+ /** Job already started */
+ public static final int LSBE_JOB_STARTED = 3;
+
+ /** Job already finished */
+ public static final int LSBE_JOB_FINISH = 4;
+
+ /** Ask sbatchd to stop the wrong job */
+ public static final int LSBE_STOP_JOB = 5;
+
+ /** Depend_cond syntax error */
+ public static final int LSBE_DEPEND_SYNTAX = 6;
+
+ /** Queue doesn't accept EXCLUSIVE job */
+ public static final int LSBE_EXCLUSIVE = 7;
+
+ /** Root is not allowed to submit jobs */
+ public static final int LSBE_ROOT = 8;
+
+ /** Job is already being migrated */
+ public static final int LSBE_MIGRATION = 9;
+
+ /** Job is not chkpntable */
+ public static final int LSBE_J_UNCHKPNTABLE = 10;
+
+ /** Job has no output so far */
+ public static final int LSBE_NO_OUTPUT = 11;
+
+ /** No jobId can be used now */
+ public static final int LSBE_NO_JOBID = 12;
+
+ /** Queue only accepts bsub -I job */
+ public static final int LSBE_ONLY_INTERACTIVE = 13;
+
+ /** Queue doesn't accept bsub -I job */
+ public static final int LSBE_NO_INTERACTIVE = 14;
+
+/** Error codes related to user, queue and host */
+
+ /** No user defined in lsb.users file */
+ public static final int LSBE_NO_USER = 15;
+
+ /** Bad user name */
+ public static final int LSBE_BAD_USER = 16;
+
+ /** User permission denied */
+ public static final int LSBE_PERMISSION = 17;
+
+ /** No such queue in the system */
+ public static final int LSBE_BAD_QUEUE = 18;
+
+ /** Queue name should be given */
+ public static final int LSBE_QUEUE_NAME = 19;
+
+ /** Queue has been closed */
+ public static final int LSBE_QUEUE_CLOSED = 20;
+
+ /** Queue windows are closed */
+ public static final int LSBE_QUEUE_WINDOW = 21;
+
+ /** User cannot use the queue */
+ public static final int LSBE_QUEUE_USE = 22;
+
+ /** Bad host name or host group name" */
+ public static final int LSBE_BAD_HOST = 23;
+
+ /** Too many processors requested */
+ public static final int LSBE_PROC_NUM = 24;
+
+ /** No host partition in the system */
+ public static final int LSBE_NO_HPART = 25;
+
+ /** Bad host partition name */
+ public static final int LSBE_BAD_HPART = 26;
+
+ /** No group defined in the system */
+ public static final int LSBE_NO_GROUP = 27;
+
+ /** Bad host/user group name */
+ public static final int LSBE_BAD_GROUP = 28;
+
+ /** Host is not used by the queue */
+ public static final int LSBE_QUEUE_HOST = 29;
+
+ /** User reach UJOB_LIMIT of the queue */
+ public static final int LSBE_UJOB_LIMIT = 30;
+
+ /** No host available for migration */
+ public static final int LSBE_NO_HOST = 31;
+
+
+ /** chklog is corrupted */
+ public static final int LSBE_BAD_CHKLOG = 32;
+
+ /** User reach PJOB_LIMIT of the queue */
+ public static final int LSBE_PJOB_LIMIT = 33;
+
+ /** request from non LSF host rejected*/
+ public static final int LSBE_NOLSF_HOST = 34;
+
+/** Error codes related to input arguments of lsblib call */
+
+ /** Bad argument for lsblib call */
+ public static final int LSBE_BAD_ARG = 35;
+
+ /** Bad time spec for lsblib call */
+ public static final int LSBE_BAD_TIME = 36;
+
+ /** Start time is later than end time */
+ public static final int LSBE_START_TIME = 37;
+
+ /** Bad CPU limit specification */
+ public static final int LSBE_BAD_LIMIT = 38;
+
+ /** Over hard limit of queue */
+ public static final int LSBE_OVER_LIMIT = 39;
+
+ /** Empty job (command) */
+ public static final int LSBE_BAD_CMD = 40;
+
+ /** Bad signal value; not supported */
+ public static final int LSBE_BAD_SIGNAL = 41;
+
+ /** Bad job name */
+ public static final int LSBE_BAD_JOB = 42;
+
+ /** Queue reach QJOB_LIMIT of the queue */
+ public static final int LSBE_QJOB_LIMIT = 43;
+
+ /** Expired job terminate time*/
+ public static final int LSBE_BAD_TERM = 44;
+/** 44 is reserved for future use */
+
+/** Error codes related to lsb.events file */
+
+ /** Unknown event in event log file */
+ public static final int LSBE_UNKNOWN_EVENT = 45;
+
+ /** bad event format in event log file */
+ public static final int LSBE_EVENT_FORMAT = 46;
+
+ /** End of file */
+ public static final int LSBE_EOF = 47;
+/** 48-49 are reserved for future use */
+
+/** Error codes related to system failure */
+
+ /** mbatchd internal error */
+ public static final int LSBE_MBATCHD = 50;
+
+ /** sbatchd internal error */
+ public static final int LSBE_SBATCHD = 51;
+
+ /** lsbatch lib internal error */
+ public static final int LSBE_LSBLIB = 52;
+
+ /** LSLIB call fails */
+ public static final int LSBE_LSLIB = 53;
+
+ /** System call fails */
+ public static final int LSBE_SYS_CALL = 54;
+
+ /** Cannot alloc memory */
+ public static final int LSBE_NO_MEM = 55;
+
+ /** Lsbatch service not registered */
+ public static final int LSBE_SERVICE = 56;
+
+ /** LSB_SHAREDIR not defined */
+ public static final int LSBE_NO_ENV = 57;
+
+ /** chkpnt system call fail */
+ public static final int LSBE_CHKPNT_CALL = 58;
+
+ /** mbatchd cannot fork */
+ public static final int LSBE_NO_FORK = 59;
+
+/** Error codes related to communication between mbatchd/lsblib/sbatchd */
+
+ /** LSBATCH protocol error */
+ public static final int LSBE_PROTOCOL = 60;
+
+ /** XDR en/decode error */
+ public static final int LSBE_XDR = 61;
+
+ /** No appropriate port can be bound */
+ public static final int LSBE_PORT = 62;
+
+ /** Timeout in contacting mbatchd */
+ public static final int LSBE_TIME_OUT = 63;
+
+ /** Timeout on connect() call */
+ public static final int LSBE_CONN_TIMEOUT = 64;
+
+ /** Connection refused by server */
+ public static final int LSBE_CONN_REFUSED = 65;
+
+ /** server connection already exists */
+ public static final int LSBE_CONN_EXIST = 66;
+
+ /** server is not connected */
+ public static final int LSBE_CONN_NONEXIST = 67;
+
+ /** sbatchd cannot be reached */
+ public static final int LSBE_SBD_UNREACH = 68;
+
+ // Search for any ; \s+ /** and fix the comments
+ /** Operation cannot be performed right now, op. will be retried. */
+ public static final int LSBE_OP_RETRY = 69;
+
+ /** user has no enough job slots */
+ public static final int LSBE_USER_JLIMIT = 70;
+/** 71 is reserved for future use */
+
+/** Error codes related to NQS */
+
+ /** Bad specification for a NQS job */
+ public static final int LSBE_NQS_BAD_PAR = 72;
+
+
+ /** Client host has no license */
+ public static final int LSBE_NO_LICENSE = 73;
+
+/** Error codes related to calendar */
+
+ /** Bad calendar name */
+ public static final int LSBE_BAD_CALENDAR = 74;
+
+ /** No calendar found */
+ public static final int LSBE_NOMATCH_CALENDAR = 75;
+
+ /** No calendar in system */
+ public static final int LSBE_NO_CALENDAR = 76;
+
+ /** Bad calendar time events */
+ public static final int LSBE_BAD_TIMEEVENT = 77;
+
+ /** Calendar exist already */
+ public static final int LSBE_CAL_EXIST = 78;
+
+ /** Calendar function is not enabled*/
+ public static final int LSBE_CAL_DISABLED = 79;
+
+/** Error codes related to modify job's parameters */
+
+ /** the job's params cannot be changed */
+ public static final int LSBE_JOB_MODIFY = 80;
+ /** the changed once parameters are not used */
+ public static final int LSBE_JOB_MODIFY_ONCE = 81;
+
+
+ /** the job is not a repetitive job */
+ public static final int LSBE_J_UNREPETITIVE = 82;
+
+ /** bad cluster name */
+ public static final int LSBE_BAD_CLUSTER = 83;
+
+/** Error codes related jobs driven by calendar */
+
+ /** Job can not be killed in pending */
+ public static final int LSBE_PEND_CAL_JOB = 84;
+ /** This Running turn is being terminated */
+ public static final int LSBE_RUN_CAL_JOB = 85;
+
+
+ /** Modified parameters are being used */
+ public static final int LSBE_JOB_MODIFY_USED = 86;
+
+ /** Can not get user's token */
+ public static final int LSBE_AFS_TOKENS = 87;
+
+/** Error codes related to event */
+
+ /** Bad event name */
+ public static final int LSBE_BAD_EVENT = 88;
+
+ /** No event found */
+ public static final int LSBE_NOMATCH_EVENT = 89;
+
+ /** No event in system */
+ public static final int LSBE_NO_EVENT = 90;
+
+/** Error codes related to user, queue and host */
+
+ /** User reach HJOB_LIMIT of the queue */
+ public static final int LSBE_HJOB_LIMIT = 91;
+
+/** Error codes related to bmsg */
+
+ /** Message delivered */
+ public static final int LSBE_MSG_DELIVERED = 92;
+ /** MBD could not find the message that SBD mentions about */
+ public static final int LSBE_NO_JOBMSG = 93;
+
+ /** x */
+ public static final int LSBE_MSG_RETRY = 94;
+
+/** Error codes related to resource requirement */
+
+ /** Bad resource requirement */
+ public static final int LSBE_BAD_RESREQ = 95;
+
+
+ /** No enough hosts */
+ public static final int LSBE_NO_ENOUGH_HOST = 96;
+
+/** Error codes related to configuration lsblib call */
+
+ /** Fatal error in reading conf files */
+ public static final int LSBE_CONF_FATAL = 97;
+
+ /** Warning error in reading conf files */
+ public static final int LSBE_CONF_WARNING = 98;
+
+
+ /** CONF used calendar cannot be modified */
+ public static final int LSBE_CAL_MODIFY = 99;
+
+ /** Job created calendar cannot be modified */
+ public static final int LSBE_JOB_CAL_MODIFY = 100;
+ /** FAIRSHARE queue or HPART defined */
+ public static final int LSBE_HP_FAIRSHARE_DEF = 101;
+
+ /** No resource specified */
+ public static final int LSBE_NO_RESOURCE = 102;
+
+ /** Bad resource name */
+ public static final int LSBE_BAD_RESOURCE = 103;
+ /** Calendar not allowed for interactive job */
+ public static final int LSBE_INTERACTIVE_CAL = 104;
+ /** Interactive job cannot be rerunnable */
+ public static final int LSBE_INTERACTIVE_RERUN = 105;
+
+ /** PTY and infile specified */
+ public static final int LSBE_PTY_INFILE = 106;
+
+ /** JobScheduler is disabled */
+ public static final int LSBE_JS_DISABLED = 107;
+
+ /** Submission host and its host type can not be found any more */
+ public static final int LSBE_BAD_SUBMISSION_HOST = 108;
+ /** Lock the job so that it cann't be resume by sbatchd */
+ public static final int LSBE_LOCK_JOB = 109;
+
+ /** user not in the user group */
+ public static final int LSBE_UGROUP_MEMBER = 110;
+ /** Operation not supported for a Multicluster job */
+ public static final int LSBE_UNSUPPORTED_MC = 111;
+ /** Operation permission denied for a Multicluster job */
+ public static final int LSBE_PERMISSION_MC = 112;
+
+ /** System Calendar exist already */
+ public static final int LSBE_SYSCAL_EXIST = 113;
+
+ /** exceed q's resource reservation */
+ public static final int LSBE_OVER_RUSAGE = 114;
+
+ /** bad host spec of run/cpu limits */
+ public static final int LSBE_BAD_HOST_SPEC = 115;
+
+ /** calendar syntax error */
+ public static final int LSBE_SYNTAX_CALENDAR = 116;
+
+ /** delete a used calendar */
+ public static final int LSBE_CAL_USED = 117;
+
+ /** cyclic calednar dependence */
+ public static final int LSBE_CAL_CYC = 118;
+
+ /** bad user group name */
+ public static final int LSBE_BAD_UGROUP = 119;
+
+ /** esub aborted request */
+ public static final int LSBE_ESUB_ABORT = 120;
+
+ /** Bad exception handler syntax */
+ public static final int LSBE_EXCEPT_SYNTAX = 121;
+ /** Bad exception condition specification */
+ public static final int LSBE_EXCEPT_COND = 122;
+ /** Bad or invalid action specification */
+ public static final int LSBE_EXCEPT_ACTION = 123;
+
+ /** job dependence, not deleted immed */
+ public static final int LSBE_JOB_DEP = 124;
+/** error codes for job group */
+
+ /** the job group exists */
+ public static final int LSBE_JGRP_EXIST = 125;
+
+ /** the job group doesn't exist */
+ public static final int LSBE_JGRP_NULL = 126;
+
+ /** the group contains jobs */
+ public static final int LSBE_JGRP_HASJOB = 127;
+
+ /** the unknown group control signal */
+ public static final int LSBE_JGRP_CTRL_UNKWN = 128;
+
+ /** Bad Job Group name */
+ public static final int LSBE_JGRP_BAD = 129;
+
+ /** Job Array */
+ public static final int LSBE_JOB_ARRAY = 130;
+
+ /** Suspended job not supported */
+ public static final int LSBE_JOB_SUSP = 131;
+
+ /** Forwarded job not suported */
+ public static final int LSBE_JOB_FORW = 132;
+
+ /** parent group is held */
+ public static final int LSBE_JGRP_HOLD = 133;
+
+ /** bad index */
+ public static final int LSBE_BAD_IDX = 134;
+
+ /** index too big */
+ public static final int LSBE_BIG_IDX = 135;
+
+ /** job array not exist*/
+ public static final int LSBE_ARRAY_NULL = 136;
+
+ /** Void calendar */
+ public static final int LSBE_CAL_VOID = 137;
+
+ /** the job exists */
+ public static final int LSBE_JOB_EXIST = 138;
+
+ /** Job Element fail */
+ public static final int LSBE_JOB_ELEMENT = 139;
+
+ /** Bad jobId */
+ public static final int LSBE_BAD_JOBID = 140;
+
+ /** cannot change job name */
+ public static final int LSBE_MOD_JOB_NAME = 141;
+
+/** error codes for frame job */
+
+ /** Bad frame expression */
+ public static final int LSBE_BAD_FRAME = 142;
+
+ /** Frame index too long */
+ public static final int LSBE_FRAME_BIG_IDX = 143;
+
+ /** Frame index syntax error */
+ public static final int LSBE_FRAME_BAD_IDX = 144;
+
+
+ /** child process died */
+ public static final int LSBE_PREMATURE = 145;
+
+/** error code for user not in project group */
+
+ /** Invoker is not in project group */
+ public static final int LSBE_BAD_PROJECT_GROUP = 146;
+
+/** error code for user group / host group */
+
+ /** No host group defined in the system */
+ public static final int LSBE_NO_HOST_GROUP = 147;
+
+ /** No user group defined in the system */
+ public static final int LSBE_NO_USER_GROUP = 148;
+
+ /** Bad jobid index file format */
+ public static final int LSBE_INDEX_FORMAT = 149;
+
+/** error codes for IO_SPOOL facility */
+
+ /** source file does not exist */
+ public static final int LSBE_SP_SRC_NOT_SEEN = 150;
+
+ /** Number of failed spool hosts reached max */
+ public static final int LSBE_SP_FAILED_HOSTS_LIM = 151;
+
+ /** spool copy failed for this host*/
+ public static final int LSBE_SP_COPY_FAILED = 152;
+
+ /** fork failed */
+ public static final int LSBE_SP_FORK_FAILED = 153;
+
+ /** status of child is not available */
+ public static final int LSBE_SP_CHILD_DIES = 154;
+
+ /** child terminated with failure */
+ public static final int LSBE_SP_CHILD_FAILED = 155;
+
+ /** Unable to find a host for spooling */
+ public static final int LSBE_SP_FIND_HOST_FAILED = 156;
+
+ /** Cannot get $JOB_SPOOLDIR for this host */
+ public static final int LSBE_SP_SPOOLDIR_FAILED = 157;
+
+ /** Cannot delete spool file for this host */
+ public static final int LSBE_SP_DELETE_FAILED = 158;
+
+
+ /** Bad user priority */
+ public static final int LSBE_BAD_USER_PRIORITY = 159;
+
+ /** Job priority control undefined */
+ public static final int LSBE_NO_JOB_PRIORITY = 160;
+
+ /** Job has been killed & requeued */
+ public static final int LSBE_JOB_REQUEUED = 161;
+
+ /** Remote job cannot kill-requeued */
+ public static final int LSBE_JOB_REQUEUE_REMOTE = 162;
+
+ /** Cannot submit job array to a NQS queue */
+ public static final int LSBE_NQS_NO_ARRJOB = 163;
+
+/** error codes for EXT_JOB_STATUS */
+
+ /** No message available */
+ public static final int LSBE_BAD_EXT_MSGID = 164;
+
+ /** Not a regular file */
+ public static final int LSBE_NO_IFREG = 165;
+
+ /** MBD fail to create files in the directory*/
+ public static final int LSBE_BAD_ATTA_DIR = 166;
+
+ /** Fail to transfer data */
+ public static final int LSBE_COPY_DATA = 167;
+
+ /** exceed the limit on data transferring of a msg*/
+ public static final int LSBE_JOB_ATTA_LIMIT = 168;
+
+ /** cannot resize a chunk job, cannot bswitch a run/wait job */
+ public static final int LSBE_CHUNK_JOB = 169;
+
+/** Error code used in communications with dlogd */
+
+
+ /** dlogd is already connected */
+ public static final int LSBE_DLOGD_ISCONN = 170;
+
+/** Error code for LANL3_1ST_HOST */
+
+ /** Multiple first execution host */
+ public static final int LSBE_MULTI_FIRST_HOST = 171;
+
+ /** Host group as first execution host */
+ public static final int LSBE_HG_FIRST_HOST = 172;
+
+ /** Host partition as first execution host */
+ public static final int LSBE_HP_FIRST_HOST = 173;
+
+ /** "others" as first execution host */
+ public static final int LSBE_OTHERS_FIRST_HOST = 174;
+
+/** error code for multi-cluster: remote only queue */
+
+ /** cannot specify exec host */
+ public static final int LSBE_MC_HOST = 175;
+
+ /** cannot specify repetitive job */
+ public static final int LSBE_MC_REPETITIVE = 176;
+
+ /** cannot be a chkpnt job */
+ public static final int LSBE_MC_CHKPNT = 177;
+
+ /** cannot specify exception */
+ public static final int LSBE_MC_EXCEPTION = 178;
+
+ /** cannot specify time event */
+ public static final int LSBE_MC_TIMEEVENT = 179;
+
+ /** Too few processors requested */
+ public static final int LSBE_PROC_LESS = 180;
+ /** bmod pending options and running options together towards running job */
+ public static final int LSBE_MOD_MIX_OPTS = 181;
+
+ /** cannot bmod remote running job */
+ public static final int LSBE_MOD_REMOTE = 182;
+ /** cannot bmod cpulimit without LSB_JOB_CPULIMIT defined */
+ public static final int LSBE_MOD_CPULIMIT = 183;
+ /** cannot bmod memlimit without LSB_JOB_MEMLIMIT defined */
+ public static final int LSBE_MOD_MEMLIMIT = 184;
+
+ /** cannot bmod err file name */
+ public static final int LSBE_MOD_ERRFILE = 185;
+
+ /** host is locked by master LIM*/
+ public static final int LSBE_LOCKED_MASTER = 186;
+ /** warning time period is invalid */
+ public static final int LSBE_WARNING_INVALID_TIME_PERIOD = 187;
+ /** either warning time period or warning action is not specified */
+ public static final int LSBE_WARNING_MISSING = 188;
+ /** The job arrays involved in one to one dependency do not have the same size. */
+ public static final int LSBE_DEP_ARRAY_SIZE = 189;
+
+ /** Not enough processors to be reserved (lsb_addreservation()) */
+ public static final int LSBE_FEWER_PROCS = 190;
+
+ /** Bad reservation ID */
+ public static final int LSBE_BAD_RSVID = 191;
+
+ /** No more reservation IDs can be used now */
+ public static final int LSBE_NO_RSVID = 192;
+
+ /** No hosts are exported */
+ public static final int LSBE_NO_EXPORT_HOST = 193;
+
+ /** Trying to control remote hosts*/
+ public static final int LSBE_REMOTE_HOST_CONTROL = 194;
+
+/*Can't open a remote host closed by the remote cluster admin */
+ public static final int LSBE_REMOTE_CLOSED = 195;
+
+ /** User suspended job */
+ public static final int LSBE_USER_SUSPENDED = 196;
+
+ /** Admin suspended job */
+ public static final int LSBE_ADMIN_SUSPENDED = 197;
+
+ /** Not a local host name in bhost -e command */
+ public static final int LSBE_NOT_LOCAL_HOST = 198;
+
+ /** The host's lease is not active. */
+ public static final int LSBE_LEASE_INACTIVE = 199;
+
+ /** The advance reserved host is not on queue. */
+ public static final int LSBE_QUEUE_ADRSV = 200;
+
+ /** The specified host(s) is not exported. */
+ public static final int LSBE_HOST_NOT_EXPORTED = 201;
+
+ /** The user specified host is not inn advance reservation */
+ public static final int LSBE_HOST_ADRSV = 202;
+
+ /** The remote cluster is not connected */
+ public static final int LSBE_MC_CONN_NONEXIST = 203;
+
+ /** The general resource limit broken */
+ public static final int LSBE_RL_BREAK = 204;
+
+/** ---- The following RMS errors are obsoleted in Eagle */
+
+ /** cannot submit a job with special topology requirement to a preemptive queue*/
+ public static final int LSBE_LSF2TP_PREEMPT = 205;
+
+ /** cannot submit a job with special topology requirement to a queue with slot reservation*/
+ public static final int LSBE_LSF2TP_RESERVE = 206;
+ /** cannot submit a job with special topology requirement to a queue with backill */
+ public static final int LSBE_LSF2TP_BACKFILL = 207;
+ /** ---- The above RMS errors are obsoleted in Eagle */
+
+ /** none existed policy name */
+ public static final int LSBE_RSV_POLICY_NAME_BAD = 208;
+
+ /** All normal user has no privilege */
+ public static final int LSBE_RSV_POLICY_PERMISSION_DENIED = 209;
+
+ /** user has no privilege */
+ public static final int LSBE_RSV_POLICY_USER = 210;
+
+ /** user has no privilege to create reservation on host */
+ public static final int LSBE_RSV_POLICY_HOST = 211;
+
+ /** time window is not allowed by policy */
+ public static final int LSBE_RSV_POLICY_TIMEWINDOW = 212;
+
+ /** the feature is disabled */
+ public static final int LSBE_RSV_POLICY_DISABLED = 213;
+ /** the general limit related errors */
+
+ /** There are no general limit defined */
+ public static final int LSBE_LIM_NO_GENERAL_LIMIT = 214;
+
+ /** There are no resource usage */
+ public static final int LSBE_LIM_NO_RSRC_USAGE = 215;
+
+ /** Convert data error */
+ public static final int LSBE_LIM_CONVERT_ERROR = 216;
+
+ /** There are no qualified host found in cluster*/
+ public static final int LSBE_RSV_NO_HOST = 217;
+
+ /** Cannot modify job group on element of job array */
+ public static final int LSBE_MOD_JGRP_ARRAY = 218;
+
+ /** Cannot combine modify job group or service class option with others */
+ public static final int LSBE_MOD_MIX = 219;
+
+ /** the service class doesn't exist */
+ public static final int LSBE_SLA_NULL = 220;
+
+ /** Modify job group for job in service class is not supported*/
+ public static final int LSBE_MOD_JGRP_SLA = 221;
+
+ /** User or user group is not a member of the specified service class */
+ public static final int LSBE_SLA_MEMBER = 222;
+
+ /** There is no exceptional host found */
+ public static final int LSBE_NO_EXCEPTIONAL_HOST = 223;
+
+ /** warning action (signal) is invalid */
+ public static final int LSBE_WARNING_INVALID_ACTION = 224;
+
+
+ /** Extsched option syntax error */
+ public static final int LSBE_EXTSCHED_SYNTAX = 225;
+
+ /** SLA doesn't work with remote only queues */
+ public static final int LSBE_SLA_RMT_ONLY_QUEUE = 226;
+
+ /** Cannot modify service class on element of job array */
+ public static final int LSBE_MOD_SLA_ARRAY = 227;
+
+ /** Modify service class for job in job group is not supported*/
+ public static final int LSBE_MOD_SLA_JGRP = 228;
+
+ /** Max. Pending job error */
+ public static final int LSBE_MAX_PEND = 229;
+
+ /** System concurrent query exceeded */
+ public static final int LSBE_CONCURRENT = 230;
+
+ /** Requested feature not enabled */
+ public static final int LSBE_FEATURE_NULL = 231;
+
+
+ /** Host is already member of group */
+ public static final int LSBE_DYNGRP_MEMBER = 232;
+
+ /** Host is not a dynamic host */
+ public static final int LSBE_BAD_DYN_HOST = 233;
+
+ /** Host was not added with badmin hghostadd */
+ public static final int LSBE_NO_GRP_MEMBER = 234;
+
+ /** Cannot create job info file */
+ public static final int LSBE_JOB_INFO_FILE = 235;
+
+ /** Cannot modify rusage to a new || (or) expression after the job is dispatched */
+ public static final int LSBE_MOD_OR_RUSAGE = 236;
+
+ /** Bad host group name */
+ public static final int LSBE_BAD_GROUP_NAME = 237;
+
+ /** Bad host name */
+ public static final int LSBE_BAD_HOST_NAME = 238;
+
+ /** Bsub is not permitted on DT cluster */
+ public static final int LSBE_DT_BSUB = 239;
+
+
+ /** The parent symphony job/group was gone when submitting jobs*/
+ public static final int LSBE_PARENT_SYM_JOB = 240;
+
+ /** The partition has no cpu alllocated */
+ public static final int LSBE_PARTITION_NO_CPU = 241;
+
+ /** batch partition does not accept online jobs: obsolete */
+ public static final int LSBE_PARTITION_BATCH = 242;
+
+ /** online partition does not accept batch jobs */
+ public static final int LSBE_PARTITION_ONLINE = 243;
+
+ /** no batch licenses */
+ public static final int LSBE_NOLICENSE_BATCH = 244;
+
+ /** no online licenses */
+ public static final int LSBE_NOLICENSE_ONLINE = 245;
+
+ /** signal is not supported for service job */
+ public static final int LSBE_SIGNAL_SRVJOB = 246;
+
+ /** the begin time is not later than current time. */
+ public static final int LSBE_BEGIN_TIME_INVALID = 247;
+
+ /** the end time is not later than current time. */
+ public static final int LSBE_END_TIME_INVALID = 248;
+
+ /** Bad regular expression */
+ public static final int LSBE_BAD_REG_EXPR = 249;
+
+
+ /** Host group has regular expression */
+ public static final int LSBE_GRP_REG_EXPR = 250;
+
+ /** Host group have no member */
+ public static final int LSBE_GRP_HAVE_NO_MEMB = 251;
+
+ /** the application doesn't exist */
+ public static final int LSBE_APP_NULL = 252;
+
+ /** job's proclimit rejected by App */
+ public static final int LSBE_PROC_JOB_APP = 253;
+
+ /** app's proclimit rejected by Queue */
+ public static final int LSBE_PROC_APP_QUE = 254;
+
+ /** application name is too long */
+ public static final int LSBE_BAD_APPNAME = 255;
+
+ /** Over hard limit of queue */
+ public static final int LSBE_APP_OVER_LIMIT = 256;
+
+ /** Cannot remove default application */
+ public static final int LSBE_REMOVE_DEF_APP = 257;
+
+ /** Host is disabled by EGO */
+ public static final int LSBE_EGO_DISABLED = 258;
+
+ /** Host is a remote host. Remote hosts cannot be added to a local host group. */
+ public static final int LSBE_REMOTE_HOST = 259;
+
+ /** SLA is exclusive, only accept exclusive job. */
+ public static final int LSBE_SLA_EXCLUSIVE = 260;
+
+ /** SLA is non-exclusive, only accept non-exclusive job */
+ public static final int LSBE_SLA_NONEXCLUSIVE = 261;
+
+ /** The feature has already been started */
+ public static final int LSBE_PERFMON_STARTED = 262;
+
+ /** The Featurn has already been turn down */
+ public static final int LSBE_PERFMON_STOPED = 263;
+
+ /** Current sampling period is already set to %%s,seconds. Ignored*/
+ public static final int LSBE_PERFMON_PERIOD_SET = 264;
+
+ /** Default spool dir is disabled */
+ public static final int LSBE_DEFAULT_SPOOL_DIR_DISABLED = 265;
+
+ /** job belongs to an APS queue and cannot be moved */
+ public static final int LSBE_APS_QUEUE_JOB = 266;
+
+ /** job is not in an absolute priority enabled queue */
+ public static final int LSBE_BAD_APS_JOB = 267;
+
+ /** Wrong aps admin value */
+ public static final int LSBE_BAD_APS_VAL = 268;
+
+ /** Trying to delete a non-existent APS string */
+ public static final int LSBE_APS_STRING_UNDEF = 269;
+
+ /** A job cannot be assigned an SLA and an APS queue with factor FS */
+ public static final int LSBE_SLA_JOB_APS_QUEUE = 270;
+
+ /** bmod -aps | -apsn option cannot be mixed with other option */
+ public static final int LSBE_MOD_MIX_APS = 271;
+
+ /** specified ADMIN factor/system APS value out of range */
+ public static final int LSBE_APS_RANGE = 272;
+
+ /** specified ADMIN factor/system APS value is zero */
+ public static final int LSBE_APS_ZERO = 273;
+
+
+ /** res port is unknown */
+ public static final int LSBE_DJOB_RES_PORT_UNKNOWN = 274;
+
+ /** timeout on res communication */
+ public static final int LSBE_DJOB_RES_TIMEOUT = 275;
+
+ /** I/O error on remote stream */
+ public static final int LSBE_DJOB_RES_IOERR = 276;
+
+ /** res internal failure */
+ public static final int LSBE_DJOB_RES_INTERNAL_FAILURE = 277;
+
+
+ /** can not run outside LSF */
+ public static final int LSBE_DJOB_CAN_NOT_RUN = 278;
+
+ /** distributed job's validation failed due to incorrect job ID or index */
+ public static final int LSBE_DJOB_VALIDATION_BAD_JOBID = 279;
+
+ /** distributed job's validation failed due to incorrect host selection */
+ public static final int LSBE_DJOB_VALIDATION_BAD_HOST = 280;
+
+ /** distributed job's validation failed due to incorrect user */
+ public static final int LSBE_DJOB_VALIDATION_BAD_USER = 281;
+
+ /** failed while executing tasks */
+ public static final int LSBE_DJOB_EXECUTE_TASK = 282;
+
+ /** failed while waiting for tasks to finish*/
+ public static final int LSBE_DJOB_WAIT_TASK = 283;
+
+
+ /** HPC License not exist */
+ public static final int LSBE_APS_HPC = 284;
+
+ /** Integrity check of bsub command failed */
+ public static final int LSBE_DIGEST_CHECK_BSUB = 285;
+
+ /** Distributed Application Framework disabled */
+ public static final int LSBE_DJOB_DISABLED = 286;
+
+/** Error codes related to runtime estimation and cwd */
+
+ /** Bad runtime specification */
+ public static final int LSBE_BAD_RUNTIME = 287;
+
+ /** RUNLIMIT: Cannot exceed RUNTIME*JOB_RUNLIMIT_RATIO */
+ public static final int LSBE_BAD_RUNLIMIT = 288;
+
+ /** RUNTIME: Cannot exceed the hard runtime limit in the queue */
+ public static final int LSBE_OVER_QUEUE_LIMIT = 289;
+
+ /** RUNLIMIT: Is not set by command line */
+ public static final int LSBE_SET_BY_RATIO = 290;
+
+ /** current working directory name too long */
+ public static final int LSBE_BAD_CWD = 291;
+
+
+ /** Job group limit is greater than its parent group */
+ public static final int LSBE_JGRP_LIMIT_GRTR_THAN_PARENT = 292;
+
+ /** Job group limit is less than its children groups */
+ public static final int LSBE_JGRP_LIMIT_LESS_THAN_CHILDREN = 293;
+
+ /** Job Array end index should be specified explicitly */
+ public static final int LSBE_NO_ARRAY_END_INDEX = 294;
+
+ /** cannot bmod runtime without LSB_MOD_ALL_JOBS=y defined */
+ public static final int LSBE_MOD_RUNTIME = 295;
+
+ /** EP3 */
+ public static final int LSBE_BAD_SUCCESS_EXIT_VALUES = 296;
+ public static final int LSBE_DUP_SUCCESS_EXIT_VALUES = 297;
+ public static final int LSBE_NO_SUCCESS_EXIT_VALUES = 298;
+
+ public static final int LSBE_JOB_REQUEUE_BADARG = 299;
+ public static final int LSBE_JOB_REQUEUE_DUPLICATED = 300;
+
+ /** "all" with number */
+ public static final int LSBE_JOB_REQUEUE_INVALID_DIGIT = 301;
+
+ /** ~digit without "all" */
+ public static final int LSBE_JOB_REQUEUE_INVALID_TILDE = 302;
+ public static final int LSBE_JOB_REQUEUE_NOVALID = 303;
+
+
+ /** No matching job group found */
+ public static final int LSBE_NO_JGRP = 304;
+ public static final int LSBE_NOT_CONSUMABLE = 305;
+
+/** AR pre/post */
+
+ /** Cannot parse an Advance Reservation -exec string */
+ public static final int LSBE_RSV_BAD_EXEC = 306;
+
+ /** Unknown AR event type */
+ public static final int LSBE_RSV_EVENTTYPE = 307;
+
+ /** pre/post cannot have postive offset */
+ public static final int LSBE_RSV_SHIFT = 308;
+
+ /** pre-AR command cannot have offset < 0 in user-created AR */
+ public static final int LSBE_RSV_USHIFT = 309;
+
+ /** only one pre- and one post- cmd permitted per AR */
+ public static final int LSBE_RSV_NUMEVENTS = 310;
+
+/*Error codes related to AR Modification*/
+
+ /** ID does not correspond to a known AR. */
+ public static final int LSBE_ADRSV_ID_VALID = 311;
+
+ /** disable non-recurrent AR. */
+ public static final int LSBE_ADRSV_DISABLE_NONRECUR = 312;
+
+ /** modification is rejected because AR is activated. */
+ public static final int LSBE_ADRSV_MOD_ACTINSTANCE = 313;
+
+ /** modification is rejected because host slots is not available. */
+ public static final int LSBE_ADRSV_HOST_NOTAVAIL = 314;
+
+ /** the time of the AR cannot be modified since resource is not available. */
+ public static final int LSBE_ADRSV_TIME_MOD_FAIL = 315;
+
+ /** resource requirement (-R) must be followed a slot requirment (-n) */
+ public static final int LSBE_ADRSV_R_AND_N = 316;
+
+/*modification is rejected because trying to empty the AR. */
+ public static final int LSBE_ADRSV_EMPTY = 317;
+
+/*modification is rejected because switching AR type. */
+ public static final int LSBE_ADRSV_SWITCHTYPE = 318;
+
+/*modification is rejected because specifying -n for system AR. */
+ public static final int LSBE_ADRSV_SYS_N = 319;
+
+ /** disable string is not valid. */
+ public static final int LSBE_ADRSV_DISABLE = 320;
+
+ /** Unique AR ID required */
+ public static final int LSBE_ADRSV_ID_UNIQUE = 321;
+
+ /** Bad reservation name */
+ public static final int LSBE_BAD_RSVNAME = 322;
+
+ /** Cannot change the start time of an active reservation. */
+ public static final int LSBE_ADVRSV_ACTIVESTART = 323;
+
+ /** AR ID is refernced by a job */
+ public static final int LSBE_ADRSV_ID_USED = 324;
+
+ /** the disable period has already been disabled */
+ public static final int LSBE_ADRSV_PREVDISABLED = 325;
+
+ /** an active period of a recurring reservation cannot be disabled */
+ public static final int LSBE_ADRSV_DISABLECURR = 326;
+
+ /** modification is rejected because specified hosts or host groups do not belong to the reservation */
+ public static final int LSBE_ADRSV_NOT_RSV_HOST = 327;
+
+/*new parser */
+
+/*checking resreq return ok */
+ public static final int LSBE_RESREQ_OK = 328;
+
+/*checking resreq return error */
+ public static final int LSBE_RESREQ_ERR = 329;
+
+
+ /** modification is rejected because reservation has running jobs on the specified hosts or host groups */
+ public static final int LSBE_ADRSV_HOST_USED = 330;
+
+
+ /** The checkpoint directory is too long */
+ public static final int LSBE_BAD_CHKPNTDIR = 331;
+
+ /** trying to modify in a remote cluster */
+ public static final int LSBE_ADRSV_MOD_REMOTE = 332;
+ public static final int LSBE_JOB_REQUEUE_BADEXCLUDE = 333;
+
+ /** trying to disable for a date in the past */
+ public static final int LSBE_ADRSV_DISABLE_DATE = 334;
+
+ /** cannot mix the -Un option with others for started jobs */
+ public static final int LSBE_ADRSV_DETACH_MIX = 335;
+
+ /** cannot detach a started job when the reservation is active */
+ public static final int LSBE_ADRSV_DETACH_ACTIVE = 336;
+
+ /** invalid time expression: must specify day for both start and end time */
+ public static final int LSBE_MISSING_START_END_TIME = 337;
+
+ /** Queue level limitation */
+ public static final int LSBE_JOB_RUSAGE_EXCEED_LIMIT = 338;
+
+ /** Queue level limitation */
+ public static final int LSBE_APP_RUSAGE_EXCEED_LIMIT = 339;
+
+ /** Hosts and host groups specified by -m are not used by the queue */
+ public static final int LSBE_CANDIDATE_HOST_EMPTY = 340;
+
+ /** An int must follow an open bracket */
+ public static final int LSBE_HS_BAD_AFTER_BRACKT = 341;
+
+ /** An end index must follow a dash */
+ public static final int LSBE_HS_NO_END_INDEX = 342;
+
+ /** Integers must come before and after the comma */
+ public static final int LSBE_HS_BAD_COMMA = 343;
+
+ /** Incorrect condensed host specification */
+ public static final int LSBE_HS_BAD_FORMAT = 344;
+
+ /** The start index must be less than end index */
+ public static final int LSBE_HS_BAD_ORDER = 345;
+
+ /** The end index must be less than 10 digits */
+ public static final int LSBE_HS_BAD_MANY_DIGITS = 346;
+
+ /** Number of digits in the start index must be less than that of end index */
+ public static final int LSBE_HS_BAD_NUM_DIGITS = 347;
+
+ /** The end index cannot start with zero (0) */
+ public static final int LSBE_HS_BAD_END_INDEX = 348;
+
+ /** Index must be an integer or a range */
+ public static final int LSBE_HS_BAD_INDEX = 349;
+
+/** host group admin*/
+
+ /** When a Host Group Admin (badmin hclose or hopen) closes or opens a host, the usage of the -C "message" option must be compulsory, as is the logging of the name of the person performing the action. */
+ public static final int LSBE_COMMENTS = 350;
+
+
+ /** First hosts specified by -m are not used by the queue */
+ public static final int LSBE_FIRST_HOSTS_NOT_IN_QUEUE = 351;
+
+
+ /** The job is not started */
+ public static final int LSBE_JOB_NOTSTART = 352;
+
+ /** Accumulated runtime of the job is not available */
+ public static final int LSBE_RUNTIME_INVAL = 353;
+
+ /** SSH feature can only be used for interactive job */
+ public static final int LSBE_SSH_NOT_INTERACTIVE = 354;
+
+ /** Run time specification is less than the accumulated run time */
+ public static final int LSBE_LESS_RUNTIME = 355;
+
+ /** Resize job notification command */
+ public static final int LSBE_RESIZE_NOTIFY_CMD_LEN = 356;
+
+ /** Job is not resizable */
+ public static final int LSBE_JOB_RESIZABLE = 357;
+
+ /** Bad bresize release host spec */
+ public static final int LSBE_RESIZE_RELEASE_HOSTSPEC = 358;
+
+ /** no resize notify matches in mbatchd*/
+ public static final int LSBE_NO_RESIZE_NOTIFY = 359;
+
+ /** Can't release first exec host */
+ public static final int LSBE_RESIZE_RELEASE_FRISTHOST = 360;
+
+ /** resize event in progress */
+ public static final int LSBE_RESIZE_EVENT_INPROGRESS = 361;
+
+ /** too few or too many slots */
+ public static final int LSBE_RESIZE_BAD_SLOTS = 362;
+
+ /** No active resize request */
+ public static final int LSBE_RESIZE_NO_ACTIVE_REQUEST = 363;
+
+ /** specified host not part of the job's allocation*/
+ public static final int LSBE_HOST_NOT_IN_ALLOC = 364;
+
+ /** nothing released */
+ public static final int LSBE_RESIZE_RELEASE_NOOP = 365;
+
+ /** Can't resize a brun job */
+ public static final int LSBE_RESIZE_URGENT_JOB = 366;
+ public static final int LSBE_RESIZE_EGO_SLA_COEXIST = 367;
+
+ /** hpc jobs can't be resized */
+ public static final int LSBE_HOST_NOT_SUPPORT_RESIZE = 368;
+
+ /** Application doesn't allow resizable */
+ public static final int LSBE_APP_RESIZABLE = 369;
+
+ /** can't operate on lost & found hosts*/
+ public static final int LSBE_RESIZE_LOST_AND_FOUND = 370;
+
+ /** can't resize while the first host is lost & found*/
+ public static final int LSBE_RESIZE_FIRSTHOST_LOST_AND_FOUND = 371;
+
+ /** bad host name (for resize) */
+ public static final int LSBE_RESIZE_BAD_HOST = 372;
+
+ /** proper app is required by an auto-resizable job */
+ public static final int LSBE_AUTORESIZE_APP = 373;
+
+ /** cannot resize job because there is a pedning resize request */
+ public static final int LSBE_RESIZE_PENDING_REQUEST = 374;
+
+ /** number of hosts specified by -m exceeding configuration */
+ public static final int LSBE_ASKED_HOSTS_NUMBER = 375;
+
+ /** All hosts reserved by advanced reservation are invalid in intersected hosts */
+ public static final int LSBE_AR_HOST_EMPTY = 376;
+
+ /** First hosts specified by -m are not used by advanced reservation */
+ public static final int LSBE_AR_FIRST_HOST_EMPTY = 377;
+
+ /** Internal jobbroker error */
+ public static final int LSBE_JB = 378;
+
+ /** Internal jobbroker database library error */
+ public static final int LSBE_JB_DBLIB = 379;
+
+ /** Jobbroker cannot reach database */
+ public static final int LSBE_JB_DB_UNREACH = 380;
+
+ /** Jobbroker cannot reach mbatchd */
+ public static final int LSBE_JB_MBD_UNREACH = 381;
+
+ /** BES server returned an error */
+ public static final int LSBE_JB_BES = 382;
+
+ /** Unsupported BES operation */
+ public static final int LSBE_JB_BES_UNSUPPORTED_OP = 383;
+
+ /** invalid LS project name*/
+ public static final int LSBE_LS_PROJECT_NAME = 384;
+
+ /** the end time is not later than start time. */
+ public static final int LSBE_END_TIME_INVALID_COMPARE_START = 385;
+
+ /** one host cannot be defined in more than one host partition.*/
+ public static final int LSBE_HP_REDUNDANT_HOST = 386;
+
+ /** The application level compound resreq causes slots requirements conflict */
+ public static final int LSBE_COMPOUND_APP_SLOTS = 387;
+
+ /** The queue level compound resreq causes slots requirements conflict */
+ public static final int LSBE_COMPOUND_QUEUE_SLOTS = 388;
+
+ /** Resizable job cannot work with compound resreq */
+ public static final int LSBE_COMPOUND_RESIZE = 389;
+/** compute unit support */
+
+ /** Compute units cannot have overlapping hosts */
+ public static final int LSBE_CU_OVERLAPPING_HOST = 390;
+
+ /** The compute unit cannot contain other compute units */
+ public static final int LSBE_CU_BAD_HOST = 391;
+
+ /** The compute unit cannot contain host or host group as a member */
+ public static final int LSBE_CU_HOST_NOT_ALLOWED = 392;
+
+ /** Only lowest level compute units are allowed to add hosts as a member */
+ public static final int LSBE_CU_NOT_LOWEST_LEVEL = 393;
+
+ /** You cannot modify a compute unit resource requirement when a job is already running */
+ public static final int LSBE_CU_MOD_RESREQ = 394;
+
+ /** A compute unit resource requirement cannot be specified for auto resizable jobs */
+ public static final int LSBE_CU_AUTORESIZE = 395;
+
+ /** No COMPUTE_UNIT_TYPES are specified in lsb.params */
+ public static final int LSBE_NO_COMPUTE_UNIT_TYPES = 396;
+
+ /** No compute unit defined in the system */
+ public static final int LSBE_NO_COMPUTE_UNIT = 397;
+
+ /** No such compute unit defined in the system */
+ public static final int LSBE_BAD_COMPUTE_UNIT = 398;
+
+ /** The queue is not configured to accept exclusive compute unit jobs */
+ public static final int LSBE_CU_EXCLUSIVE = 399;
+
+ /** The queue is not configured to accept higher level of exclusive compute unit jobs */
+ public static final int LSBE_CU_EXCLUSIVE_LEVEL = 400;
+
+ /** Job cannot be switched due to the exclusive compute unit reqirement */
+ public static final int LSBE_CU_SWITCH = 401;
+
+ /** Job level compound resreq causes slots requirements conflict */
+ public static final int LSBE_COMPOUND_JOB_SLOTS = 402;
+
+ /** "||" used in rusage[] of queue resource requirement. It's conflict with job level compound resource requirement */
+ public static final int LSBE_COMPOUND_QUEUE_RUSAGE_OR = 403;
+
+ /** balance and usablecuslots cannot both be used in a compute unit resource requirement */
+ public static final int LSBE_CU_BALANCE_USABLECUSLOTS = 404;
+
+ /** TS jobs cannot use compound resource requirement (application level) */
+ public static final int LSBE_COMPOUND_TSJOB_APP = 405;
+
+ /** TS jobs cannot use compound resource requirement (queue level) */
+ public static final int LSBE_COMPOUND_TSJOB_QUEUE = 406;
+ /** Job dependency conditions using a job name or job name wild-card exceed limitation set by MAX_JOB_NAME_DEP in lsb.params */
+ public static final int LSBE_EXCEED_MAX_JOB_NAME_DEP = 407;
+
+ /** "is waiting for the remote cluster to synchronize." */
+ public static final int LSBE_WAIT_FOR_MC_SYNC = 408;
+
+ /** Job cannot exceed queue level RESRSV_LIMIT limitation */
+ public static final int LSBE_RUSAGE_EXCEED_RESRSV_LIMIT = 409;
+
+ /** job description too long */
+ public static final int LSBE_JOB_DESCRIPTION_LEN = 410;
+
+ /** Cannot use simulation options */
+ public static final int LSBE_NOT_IN_SIMMODE = 411;
+
+ /** Value of runtime simulation is incorrect */
+ public static final int LSBE_SIM_OPT_RUNTIME = 412;
+
+ /** Value of cputime simulation is incorrect */
+ public static final int LSBE_SIM_OPT_CPUTIME = 413;
+
+ /** Incorrect maxmem simulation opt */
+ public static final int LSBE_SIM_OPT_MAXMEM = 414;
+
+ /** Incorrect job exitstatus simulation opt */
+ public static final int LSBE_SIM_OPT_EXITSTATUS = 415;
+
+ /** Incorrect job simulation option syntax */
+ public static final int LSBE_SIM_OPT_SYNTAX = 416;
+
+ /** Number of the above error codes */
+ public static final int LSBE_NUM_ERR = 417;
+
+ /**
+ * *****************************************************
+ */
+
+/* op codes for hand shake protocol between client/server */
+ public static final int PREPARE_FOR_OP = 1024;
+ public static final int READY_FOR_OP = 1023;
+
+/*
+* Data structures for lsblib interface
+ */
+
+
+ /**
+ * \addtogroup lsb_submit_options lsb_submit_options
+ * define statements used by lsb_submit.
+ */
+
+/* lsb_submit() options */
+ /**
+ * < Flag to indicate jobName parameter has data. Equivalent to bsub -J command line option existence.
+ */
+ public static final int SUB_JOB_NAME = 0x01;
+ /**
+ * < Flag to indicate queue parameter has data. Equivalent to bsub -q command line option existence.
+ */
+ public static final int SUB_QUEUE = 0x02;
+ /**
+ * < Flat to indicate numAskedHosts parameter has data. Equivalent to bsub -m command line option existence.
+ */
+ public static final int SUB_HOST = 0x04;
+ /**
+ * < Flag to indicate inFile parameter has data. Equivalent to bsub -i command line option existence.
+ */
+ public static final int SUB_IN_FILE = 0x08;
+ /**
+ * < Flag to indicate outFile parameter has data. Equivalent to bsub -o command line option existence.
+ */
+ public static final int SUB_OUT_FILE = 0x10;
+ /**
+ * < Flag to indicate errFile parameter has data. Equivalent to bsub -e command line option existence.
+ */
+ public static final int SUB_ERR_FILE = 0x20;
+ /**
+ * < Flag to indicate execution of a job on a host by itself requested. Equivalent to bsub -x command line option existence.
+ */
+ public static final int SUB_EXCLUSIVE = 0x40;
+ /**
+ * < Flag to indicate whether to send mail to the user when the job finishes. Equivalent to bsub -N command line option existence.
+ */
+ public static final int SUB_NOTIFY_END = 0x80;
+ /**
+ * < Flag to indicate whether to send mail to the user when the job is dispatched. Equivalent to bsub -B command line option existence.
+ */
+ public static final int SUB_NOTIFY_BEGIN = 0x100;
+ /**
+ * < Flag to indicate userGroup name parameter has data. Equivalent to bsub -G command line option existence.
+ */
+ public static final int SUB_USER_GROUP = 0x200;
+ /**
+ * < Flag to indicatechkpntPeriod parameter has data . Equivalent to bsub -k command line option existence.
+ */
+ public static final int SUB_CHKPNT_PERIOD = 0x400;
+ /**
+ * < Flag to indicate chkpntDir parameter has data. Equivalent to bsub -k command line option existence.
+ */
+ public static final int SUB_CHKPNT_DIR = 0x800;
+ /**
+ * < Indicates the job is checkpointable. Equivalent to bsub -k command line option.
+ */
+ public static final int SUB_CHKPNTABLE = SUB_CHKPNT_DIR;
+ /**
+ * < Flag to indicate whether to force the job to restart even if non-restartable conditions exist. These conditions are operating system specific. Equivalent to brestart() -f command line option existence.
+ */
+ public static final int SUB_RESTART_FORCE = 0x1000;
+ /**
+ * < Flag to indicate restart of a
+ * checkpointed job. Only jobs that have been successfully checkpointed
+ * can be restarted. Jobs are re-submitted and assigned a new job ID.
+ * By default, jobs are restarted with the same output file, file
+ * transfer specifications, job name, window signal value, checkpoint
+ * directory and period, and rerun options as the original job. To
+ * restart a job on another host, both hosts must be binary compatible,
+ * run the same OS version, have access to the executable, have access
+ * to all open files (LSF must locate them with an absolute path name),
+ * and have access to the checkpoint directory. Equivalent to bsub -k
+ * command line option existence.
+ */
+ public static final int SUB_RESTART = 0x2000;
+ /**
+ * < Indicates the job is re-runnable.
+ * If the execution host of the job is considered down, the batch
+ * system will re-queue this job in the same job queue, and re-run
+ * it from the beginning when a suitable host is found. Everything
+ * will be as if it were submitted as a new job, and a new job ID will
+ * be assigned. The user who submitted the failed job will receive a
+ * mail notice of the job failure, requeueing of the job, and the
+ * new job ID.
+ * <p/>
+ * For a job that was checkpointed before the execution host went down,
+ * the job will be restarted from the last checkpoint. Equivalent to
+ * bsub -r command line option existence.
+ */
+ public static final int SUB_RERUNNABLE = 0x4000;
+ /**
+ * < Flag to indicate sigValue parameter
+ * has data. Sends a signal as the queue window closes.
+ */
+ public static final int SUB_WINDOW_SIG = 0x8000;
+ /**
+ * < Flag to indicate hostSpec parameter
+ * has data.
+ */
+ public static final int SUB_HOST_SPEC = 0x10000;
+ /**
+ * < Flag to indicate dependCond parameter
+ * has data. Equivalent to bsub -w command line option existence.
+ */
+ public static final int SUB_DEPEND_COND = 0x20000;
+ /**
+ * < Flag to indicate resReq parameter
+ * has data. Equivalent to bsub -R command line option existence.
+ */
+ public static final int SUB_RES_REQ = 0x40000;
+ /**
+ * < Flag to indicate nxf parameter and structure xf have data.
+ */
+ public static final int SUB_OTHER_FILES = 0x80000;
+ /**
+ * < Flag to indicate preExecCmd
+ * parameter has data. Equivalent to bsub -E command line option
+ * existence.
+ */
+ public static final int SUB_PRE_EXEC = 0x100000;
+ /**
+ * < Equivalent to bsub -L command line option existence.
+ */
+ public static final int SUB_LOGIN_SHELL = 0x200000;
+ /**
+ * < Flag to indicate mailUser parameter has data.
+ */
+ public static final int SUB_MAIL_USER = 0x400000;
+ /**
+ * < Flag to indicate newCommand parameter has data. Equivalent to bmod bsub_options existence.
+ */
+ public static final int SUB_MODIFY = 0x800000;
+ /**
+ * < Flag to indicate modify option once.
+ */
+ public static final int SUB_MODIFY_ONCE = 0x1000000;
+ /**
+ * < Flag to indicate ProjectName
+ * parameter has data . Equivalent to bsub -P command line option
+ * existence.
+ */
+ public static final int SUB_PROJECT_NAME = 0x2000000;
+ /**
+ * < Indicates that the job is submitted
+ * as a batch interactive job. When this flag is given, \ref lsb_submit
+ * does not return unless an error occurs during the submission process.
+ * When the job is started, the user can interact with the job's
+ * standard input and output via the terminal. See the -I option
+ * in bsub for the description of a batch interactive job. Unless
+ * the SUB_PTY flag is specified, the job will run without a
+ * pseudo-terminal. Equivalent to bsub -I command line option.
+ */
+ public static final int SUB_INTERACTIVE = 0x4000000;
+ /**
+ * < Requests pseudo-terminal support
+ * for a job submitted with the SUB_INTERACTIVE flag. This flag is
+ * ignored if SUB_INTERACTIVE is not specified. A pseudo-terminal
+ * is required to run some applications (such as: vi). Equivalent to
+ * bsub -Ip command line option.
+ */
+ public static final int SUB_PTY = 0x8000000;
+ /**< Requests pseudo-terminal shell
+ * mode support for a job submitted with the SUB_INTERACTIVE and
+ * SUB_PTY flags. This flag is ignored if SUB_INTERACTIVE and SUB_PTY
+ * are not specified. This flag should be specified for submitting
+ * interactive shells, or applications which redefine the ctrl-C and
+ * ctrl-Z keys (such as: jove). Equivalent to bsub -Is
+ * command line option. */
+ public static final int SUB_PTY_SHELL = 0x10000000;
+
+ /**
+ * < Exception handler for job.
+ */
+ public static final int SUB_EXCEPT = 0x20000000;
+
+ /**
+ * < Specifies time_event.
+ */
+ public static final int SUB_TIME_EVENT = 0x40000000;
+/* the last bit 0x80000000 is reserved for internal use */
+
+ /**
+ * \addtogroup lsb_submit_options2 lsb_submit_options2
+ * define statements used by \ref lsb_submit.
+ */
+
+ /**< Hold the job after it is submitted. The job will be in PSUSP status. Equivalent to bsub -H command line option. */
+ public static final int SUB2_HOLD = 0x01;
+
+ /**
+ * < New cmd for bmod.
+ */
+ public static final int SUB2_MODIFY_CMD = 0x02;
+
+ /**//* Removed access to SUB2_BSUB_BLOCK since it exits the process (including the JVM) with the exit code of the submitted job. -kshakir December 14, 2010
+ * < Submit a job in a synchronous
+ * mode so that submission does not return until the job terminates.
+ * Note once this flag is set, the \ref lsb_submit will never return if
+ * the job is accepted by LSF. Programs that wishes to know the status
+ * of the submission needs to fork, with the child process invoking the
+ * API call in the blocking mode and the parent process wait on the
+ * child process (see wait() for details.
+ */
+ //public static final int SUB2_BSUB_BLOCK = 0x04;
+
+ /**
+ * < Submit from NT.
+ */
+ public static final int SUB2_HOST_NT = 0x08;
+
+ /**
+ * < Submit fom UNIX.
+ */
+ public static final int SUB2_HOST_UX = 0x10;
+
+ /**
+ * < Submit to a chkpntable queue.
+ */
+ public static final int SUB2_QUEUE_CHKPNT = 0x20;
+
+ /**
+ * < Submit to a rerunnable queue.
+ */
+ public static final int SUB2_QUEUE_RERUNNABLE = 0x40;
+
+ /**
+ * < Spool job command.
+ */
+ public static final int SUB2_IN_FILE_SPOOL = 0x80;
+
+ /**
+ * < Inputs the specified file with spooling
+ */
+ public static final int SUB2_JOB_CMD_SPOOL = 0x100;
+
+ /**
+ * < Submits job with priority.
+ */
+ public static final int SUB2_JOB_PRIORITY = 0x200;
+
+ /**
+ * < Job submitted without -n, use queue's default proclimit
+ */
+ public static final int SUB2_USE_DEF_PROCLIMIT = 0x400;
+
+ /**
+ * < bmod -c/-M/-W/-o/-e
+ */
+ public static final int SUB2_MODIFY_RUN_JOB = 0x800;
+
+ /**
+ * < bmod options only to pending jobs
+ */
+ public static final int SUB2_MODIFY_PEND_JOB = 0x1000;
+
+ /**
+ * < Job action warning time. Equivalent to bsub or bmod -wt.
+ */
+ public static final int SUB2_WARNING_TIME_PERIOD = 0x2000;
+
+ /**
+ * < Job action to be taken before a job control action occurs. Equivalent to bsub or bmod -wa.
+ */
+ public static final int SUB2_WARNING_ACTION = 0x4000;
+
+ /**
+ * < Use an advance reservation created with the brsvadd command. Equivalent to bsub -U.
+ */
+ public static final int SUB2_USE_RSV = 0x8000;
+
+ /**
+ * < Windows Terminal Services job
+ */
+ public static final int SUB2_TSJOB = 0x10000;
+
+/* SUB2_LSF2TP is obsolete in Eagle. We keep it here for backward
+* compatibility */
+
+ /**
+ * < Parameter is deprecated
+ */
+ public static final int SUB2_LSF2TP = 0x20000;
+
+ /**
+ * < Submit into a job group
+ */
+ public static final int SUB2_JOB_GROUP = 0x40000;
+
+ /**
+ * < Submit into a service class
+ */
+ public static final int SUB2_SLA = 0x80000;
+
+ /**
+ * < Submit with -extsched options
+ */
+ public static final int SUB2_EXTSCHED = 0x100000;
+
+ /**
+ * < License Scheduler project
+ */
+ public static final int SUB2_LICENSE_PROJECT = 0x200000;
+
+ /**
+ * < Overwrite the standard output of the job. Equivalent to bsub -oo.
+ */
+ public static final int SUB2_OVERWRITE_OUT_FILE = 0x400000;
+
+ /**
+ * < Overwrites the standard error output of the job. Equivalent to bsub -eo.
+ */
+ public static final int SUB2_OVERWRITE_ERR_FILE = 0x800000;
+
+/* Following are for symphony submission definition.
+* Note that SYM_GRP is an LSF job, which represents a symphony group.
+ */
+
+ /**
+ * < (symphony) session job
+ */
+ public static final int SUB2_SSM_JOB = 0x1000000;
+
+ /**
+ * < (symphony) symphony job
+ */
+ public static final int SUB2_SYM_JOB = 0x2000000;
+
+ /**
+ * < (symphony) service(LSF) job
+ */
+ public static final int SUB2_SRV_JOB = 0x4000000;
+
+ /**
+ * < (symphony) "group" job
+ */
+ public static final int SUB2_SYM_GRP = 0x8000000;
+
+ /**
+ * < (symphony) symphony job has child symphony job
+ */
+ public static final int SUB2_SYM_JOB_PARENT = 0x10000000;
+
+ /**
+ * < (symphony) symphony job has real time feature
+ */
+ public static final int SUB2_SYM_JOB_REALTIME = 0x20000000;
+
+ /**
+ * < (symphony) symphony job has dummy feature to hold all persistent service jobs.
+ */
+ public static final int SUB2_SYM_JOB_PERSIST_SRV = 0x40000000;
+
+ /**
+ * < Persistent session job
+ */
+ public static final int SUB2_SSM_JOB_PERSIST = 0x80000000;
+
+ /**
+ * \addtogroup lsb_submit_options3 lsb_submit_options3
+ * define statements used by \ref lsb_submit.
+ */
+
+ /**
+ * < Application profile name. Equivalent to bsub -app.
+ */
+ public static final int SUB3_APP = 0x01;
+
+ /**
+ * < Job rerunable because of application profile
+ */
+ public static final int SUB3_APP_RERUNNABLE = 0x02;
+
+ /**
+ * < Job modified with absolute priority. Equivalent to bmod -aps.
+ */
+ public static final int SUB3_ABSOLUTE_PRIORITY = 0x04;
+
+ /**
+ * < Submit into a default job group. Equivalent to bsub -g.
+ */
+ public static final int SUB3_DEFAULT_JOBGROUP = 0x08;
+
+ /**
+ * < Run the specified post-execution command on the execution host after the job finishes. Equivalent to bsub -Ep.
+ */
+ public static final int SUB3_POST_EXEC = 0x10;
+ /**
+ * < Pass user shell limits to execution host. Equivalent to bsub -ul.
+ */
+ public static final int SUB3_USER_SHELL_LIMITS = 0x20;
+ /**
+ * < Current working directory specified on the command line with bsub -cwd
+ */
+ public static final int SUB3_CWD = 0x40;
+ /**< Runtime estimate. Equivalent to bsub -We. Use in conjunction with SUB3_RUNTIME_ESTIMATION_ACC and SUB3_RUNTIME_ESTIMATION_PERC. */
+ public static final int SUB3_RUNTIME_ESTIMATION = 0x80;
+
+ /**
+ * < Job is not rerunnable. Equivalent to bsub -rn.
+ */
+ public static final int SUB3_NOT_RERUNNABLE = 0x100;
+
+ /**
+ * < Job level requeue exit values.
+ */
+ public static final int SUB3_JOB_REQUEUE = 0x200;
+ /**
+ * < Initial checkpoint period. Equivalent to bsub -k initial_checkpoint_period.
+ */
+ public static final int SUB3_INIT_CHKPNT_PERIOD = 0x400;
+ /**< Job migration threshold. Equivalent to bsub -mig migration_threshold. */
+ public static final int SUB3_MIG_THRESHOLD = 0x800;
+
+ /**
+ * < Checkpoint dir was set by application profile
+ */
+ public static final int SUB3_APP_CHKPNT_DIR = 0x1000;
+ /**
+ * < Value of BSUB_CHK_RESREQ environment variable, used for select section resource requirement string syntax checking with bsub -R. bsub only checks the resreq syntax.
+ */
+ public static final int SUB3_BSUB_CHK_RESREQ = 0x2000;
+ /**
+ * < Runtime estimate that is the accumulated run time plus the runtime estimate. Equivalent to bmod -We+. Use in conjunction with SUB3_RUNTIME_ESTIMATION.
+ */
+ public static final int SUB3_RUNTIME_ESTIMATION_ACC = 0x4000;
+ /**
+ * < Runtime estimate in percentage of completion. Equivalent to bmod -Wep. Two digits after the decimal point are suported. The highest eight bits of runtimeEstimation in the submit structure are used for the integer; the remaining bits are used for the fraction. Use in conjunction with SUB3_RUNTIME_ESTIMATION.
+ */
+ public static final int SUB3_RUNTIME_ESTIMATION_PERC = 0x8000;
+
+ /**
+ * < Protects the sessions of interactive jobs with SSH encryption. Equivalent to bsub -IS|-ISp|-ISs.
+ */
+ public static final int SUB3_INTERACTIVE_SSH = 0x10000;
+ /**< Protect the sessions of interactive x-window job with SSH encryption. Equivalent to bsub -IX.*/
+ public static final int SUB3_XJOB_SSH = 0x20000;
+
+ /**
+ * < If set the submitted job is auto-resizable
+ */
+ public static final int SUB3_AUTO_RESIZE = 0x40000;
+
+ /**
+ * < If set, the resize notify cmd specified
+ */
+ public static final int SUB3_RESIZE_NOTIFY_CMD = 0x80000;
+
+
+ /**
+ * < Job broker bulk submit
+ */
+ public static final int SUB3_BULK_SUBMIT = 0x100000;
+
+ /**
+ * < tty mode for interactive job
+ */
+ public static final int SUB3_INTERACTIVE_TTY = 0x200000;
+
+ /**
+ * < Job submitted from floating client
+ */
+ public static final int SUB3_FLOATING_CLIENT = 0x400000;
+
+ /**
+ * < ssh X11 forwarding (bsub -XF)
+ */
+ public static final int SUB3_XFJOB = 0x800000;
+
+ /**
+ * < ssh X11 forwarding (bsub -XF) without bsub -I...
+ */
+ public static final int SUB3_XFJOB_EXCLUSIVE = 0x1000000;
+
+ /**
+ * < Job description.
+ */
+ public static final int SUB3_JOB_DESCRIPTION = 0x2000000;
+
+ /**
+ * < Job submitted from floating client
+ */
+ public static final int SUB3_SIMULATION = 0x4000000;
+
+/* Check whether a job is symphony job. These macros should be used by all
+* components, including ("submit" actually):
+* - mbatchd: jData->submitReq
+* - sbatchd: jobCard->jobSpecs
+* - API: lsb_submit() and lsb_readjobinfo()
+ */
+
+ public static boolean IS_SSM_JOB(int option) {
+ return JNAUtils.toBoolean((option) & SUB2_SSM_JOB);
+ }
+
+ public static boolean IS_SSM_JOB_PERSIST(int option) {
+ return JNAUtils.toBoolean((option) & SUB2_SSM_JOB_PERSIST);
+ }
+
+ public static boolean IS_SYM_JOB(int option) {
+ return JNAUtils.toBoolean((option) & SUB2_SYM_JOB);
+ }
+
+ public static boolean IS_SYM_JOB_PARENT(int option) {
+ return JNAUtils.toBoolean((option) & SUB2_SYM_JOB_PARENT);
+ }
+
+ public static boolean IS_SYM_JOB_REALTIME(int option) {
+ return JNAUtils.toBoolean((option) & SUB2_SYM_JOB_REALTIME);
+ }
+
+ public static boolean IS_SYM_JOB_PERSIST_SRV(int option) {
+ return JNAUtils.toBoolean((option) & SUB2_SYM_JOB_PERSIST_SRV);
+ }
+
+ public static boolean IS_SRV_JOB(int option) {
+ return JNAUtils.toBoolean((option) & SUB2_SRV_JOB);
+ }
+
+ public static boolean IS_SYM_GRP(int option) {
+ return JNAUtils.toBoolean((option) & SUB2_SYM_GRP);
+ }
+
+ public static boolean IS_SYM_JOB_OR_SYM_GRP (int option) { return (IS_SYM_JOB(option) || IS_SYM_GRP(option)); }
+/* symphony job for which resource usage should be collected */
+ public static boolean IS_REAL_SYM_JOB (int option) { return (IS_SYM_JOB(option) && !IS_SYM_JOB_PERSIST_SRV(option)); }
+
+ public static boolean IS_WLM_JOB (int option) { return (IS_SSM_JOB(option) || IS_SYM_JOB(option) || IS_SRV_JOB(option) || IS_SYM_GRP(option)); }
+ public static boolean IS_BATCH_JOB (int option) { return (!IS_WLM_JOB(option)); }
+/* job for which resource usage should be collected */
+ public static boolean IS_JOB_FOR_ACCT (int option) { return (IS_REAL_SYM_JOB(option) || IS_BATCH_JOB(option)); }
+
+ public static boolean IS_JOB_FOR_SYM (int option) { return (IS_SYM_JOB(option) || IS_SRV_JOB(option) || IS_SYM_GRP(option)); }
+
+/* Don't send IS_SYM_JOB/IS_SYM_GRP jobs to scheduler;
+* neither publish events nor brun the job allowed.
+ */
+ // NOTE: Don't know what this jp struct is.
+ //public static boolean IS_SYM_JOB_OR_GRP (int jp) { return ( (jp) != null && (jp)->shared != null && ( IS_SYM_JOB((jp)->shared->jobBill.options2) ||IS_SYM_GRP((jp)->shared->jobBill.options2))); }
+
+/* name of the lost and find queue and host */
+ public static final String LOST_AND_FOUND = "lost_and_found";
+
+ public static final int DELETE_NUMBER = -2;
+ public static final int DEL_NUMPRO = LibLsf.INFINIT_INT;
+ public static final int DEFAULT_NUMPRO = LibLsf.INFINIT_INT - 1;
+ /**
+ * \addtogroup calendar_command calendar_command
+ * options for user calendar commands
+ */
+
+ /**
+ * < Add calenda
+ */
+ public static final int CALADD = 1;
+
+ /**
+ * < Modify calenda
+ */
+ public static final int CALMOD = 2;
+
+ /**
+ * < Delete calenda
+ */
+ public static final int CALDEL = 3;
+
+ /**
+ * < Undelete calenda
+ */
+ public static final int CALUNDEL = 4;
+
+ /**
+ * < Calenda occs
+ */
+ public static final int CALOCCS = 5;
+
+/* for user event commands */
+ public static final int EVEADD = 1;
+ public static final int EVEMOD = 2;
+ public static final int EVEDEL = 3;
+
+ public static final int PLUGIN_REQUEUE = 126;
+ public static final int PLUGIN_EXIT = 125;
+
+ /**
+ * \brief xFile
+ */
+ public static class xFile extends Structure {
+ public static class ByReference extends xFile implements Structure.ByReference {}
+ public static class ByValue extends xFile implements Structure.ByValue {}
+ public xFile() {}
+ public xFile(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Pathname at submission host
+ */
+ public String subFn;
+
+ /**
+ * < Pathname at execution host
+ */
+ public String execFn;
+ /**
+ * \addtogroup defs_lsb_XF_OP defs_lsb_XF_OP
+ * options xFile operation
+ */
+
+ /**
+ * < Transfer files from submit peer to execution peer
+ */
+ public static final int XF_OP_SUB2EXEC = 0x1;
+
+ /**
+ * < Transfer files from execution peer to submit peer
+ */
+ public static final int XF_OP_EXEC2SUB = 0x2;
+
+ /**
+ * < Transfer files from submit peer to execution peer with appending mode
+ */
+ public static final int XF_OP_SUB2EXEC_APPEND = 0x4;
+
+ /**
+ * < Transfer files from execution peer to submit peer with appending mode
+ */
+ public static final int XF_OP_EXEC2SUB_APPEND = 0x8;
+ public static final int XF_OP_URL_SOURCE = 0x10;
+
+ /**
+ * < Defined in \ref defs_lsb_XF_OP
+ */
+ public int options;
+ }
+
+
+
+ /* For NQS */
+ public static final int NQS_ROUTE = 0x1;
+ public static final int NQS_SIG = 0x2;
+ public static final int NQS_SERVER = 0x4;
+
+
+ public static final int MAXNFA = 1024;
+ public static final int MAXTAG = 10;
+
+ public static final int OKP = 1;
+ public static final int NOP = 0;
+
+ public static final int CHR = 1;
+ public static final int ANY = 2;
+ public static final int CCL = 3;
+ public static final int BOL = 4;
+ public static final int EOL = 5;
+ public static final int BOT = 6;
+ public static final int EOT = 7;
+ public static final int BOW = 8;
+ public static final int EOW = 9;
+ public static final int REF = 10;
+ public static final int CLO = 11;
+
+ public static final int END = 0;
+
+ /**
+ * The following defines are not meant to be changeable.
+ * They are for readability only.
+ */
+
+ public static final int MAXCHR = 128;
+ public static final int CHRBIT = 8;
+ public static final int BITBLK = MAXCHR / CHRBIT;
+ public static final int BLKIND = 0xAA;
+ public static final int BITIND = 0x7;
+
+ public static final int ASCIIB = 0x7F;
+
+ /**
+ * byte classification table for word boundary operators BOW
+ * and EOW. the reason for not using ctype macros is that we can
+ * let the user add into our own table. see re_modw. This table
+ * is not in the bitset form, since we may wish to extend it in the
+ * future for other byte classifications.
+ *
+ * TRUE for 0-9 A-Z a-z _
+ */
+
+ public static final byte[] chrtyp = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0, 1, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 0, 0, 0, 0, 0
+ };
+
+ public static int inascii(int x) {
+ return (0x7F & (x));
+ }
+
+ public static int iswordc(int x) {
+ return chrtyp[inascii(x)];
+ }
+
+/*
+* skip values for CLO XXX to skip past the closure
+ */
+
+
+/* [CLO] ANY END ... */
+ public static final int ANYSKIP = 2;
+
+/* [CLO] CHR chr END ... */
+ public static final int CHRSKIP = 3;
+
+/* [CLO] CCL 16bytes END ... */
+ public static final int CCLSKIP = 18;
+
+/* In LSF7.0.6, we introduce submit_ext structure to support
+* extended fields for furture added submit options.
+* Each new options should have a unique key defined here.
+* The new defined key should be bigger than 1000.
+* Keys below 1000 are used for internal use.
+ */
+
+/* submit_ext test */
+ public static final int JDATA_EXT_TEST = 1001;
+
+/* LSF simulator: simReq */
+ public static final int JDATA_EXT_SIMREQ = 1002;
+
+/* structure for lsb_submit() call */
+
+ /**
+ * \extend submit data structure
+ */
+ public static class submit_ext extends Structure {
+ public static class ByReference extends submit_ext implements Structure.ByReference {}
+ public static class ByValue extends submit_ext implements Structure.ByValue {}
+ public submit_ext() {}
+ public submit_ext(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < number of key value pairs.
+ */
+ public int num;
+
+ /**
+ * < Array of keys of the extended fields.
+ */
+ public Pointer keys;
+
+ /**
+ * < Array of values of the extended fields
+ */
+ public Pointer values;
+ }
+
+
+
+
+ /**
+ * \brief submit request structure.
+ */
+ public static class submit extends Structure {
+ public static class ByReference extends submit implements Structure.ByReference {}
+ public static class ByValue extends submit implements Structure.ByValue {}
+ public submit() {}
+ public submit(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < <lsf/lsbatch.h> defines the flags in \ref lsb_submit_options constructed from bits. These flags correspond to some of the options of the bsub command line. Use the bitwise OR to set more than one flag.
+ */
+ public int options;
+
+
+ /**
+ * < Extended bitwise inclusive OR of some of the flags in \ref lsb_submit_options2.
+ */
+ public int options2;
+
+
+ /**
+ * < The job name. If jobName is null, command is used as the job name.
+ */
+ public String jobName;
+
+ /**
+ * < Submit the job to this queue. If queue is null, submit the job to a system default queue.
+ */
+ public String queue;
+
+ /**
+ * < The number of invoker specified candidate hosts for running the job. If numAskedHosts is 0, all qualified hosts will be considered.
+ */
+ public int numAskedHosts;
+
+ /**
+ * < The array of names of invoker specified candidate hosts. The number of hosts is given by numAskedHosts.
+ */
+ public Pointer askedHosts;
+
+ /**
+ * < The resource requirements of the job. If resReq is null, the batch system will try to obtain resource requirements for command from the remote task lists (see \ref ls_task ). If the task does not appear in the remote task lists, then the default resource requirement is to run on host() of the same type.
+ */
+ public String resReq;
+
+ /**
+ * < Limits on the consumption of system resources by all processes belonging to this job. See getrlimit() for details. If an element of the array is -1, there is no limit for that resource. For the constants used to index the array, see \ref lsb_queueinfo .
+ */
+ public int[] rLimits = new int[LibLsf.LSF_RLIM_NLIMITS];
+
+ /**
+ * < Specify the host model to use for scaling rLimits[LSF_RLIMIT_CPU] and rLimits[LSF_RLIMIT_RUN]. (See \ref lsb_queueinfo). If hostSpec is null, the local host is assumed.
+ */
+ public String hostSpec;
+
+ /**
+ * < The initial number of processors needed by a (parallel) job. The default is 1.
+ */
+ public int numProcessors;
+
+ /**
+ * < The job dependency condition.
+ */
+ public String dependCond;
+
+ /**
+ * < Time event string
+ */
+ public String timeEvent;
+
+ /**
+ * < Dispatch the job on or after beginTime, where beginTime is the number of seconds since 00:00:00 GMT, Jan. 1, 1970 (See time(), ctime()). If beginTime is 0, start the job as soon as possible.
+ */
+ public NativeLong beginTime;
+
+ /**
+ * < The job termination deadline. If the job is still running at termTime, it will be sent a USR2 signal. If the job does not terminate within 10 minutes after being sent this signal, it will be ended. termTime has the same representation as beginTime. If termTime is 0, allow the job to run until it reaches a resource limit.
+ */
+ public NativeLong termTime;
+
+ /**
+ * < Applies to jobs submitted to a queue that has a run window (See \ref lsb_queueinfo). Send signal sigValue to the job 10 minutes before the run window is going to close. This allows the job to clean up or checkpoint itself, if desired. If the job does not terminate 10 minutes after being sent this signal, it will be suspended.
+ */
+ public int sigValue;
+
+ /**
+ * < The path name of the job's standard input file. If inFile is null, use /dev/null as the default.
+ */
+ public String inFile;
+
+ /**
+ * < The path name of the job's standard output file. If outFile is null, the job's output will be mailed to the submitter
+ */
+ public String outFile;
+
+ /**
+ * < The path name of the job's standard error output file. If errFile is null, the standard error output will be merged with the standard output of the job.
+ */
+ public String errFile;
+
+ /**
+ * < When submitting a job, the command line of the job. When modifying a job, a mandatory parameter that should be set to jobId in string format.
+ */
+ public String command;
+
+ /**
+ * < New command line for bmod.
+ */
+ public String newCommand;
+
+ /**
+ * < The job is checkpointable with a period of chkpntPeriod seconds. The value 0 disables periodic checkpointing.
+ */
+ public NativeLong chkpntPeriod;
+
+ /**
+ * < The directory where the chk directory for this job checkpoint files will be created. When a job is checkpointed, its checkpoint files are placed in chkpntDir/chk. chkpntDir can be a relative or absolute path name.
+ */
+ public String chkpntDir;
+
+ /**
+ * < The number of files to transfer.
+ */
+ public int nxf;
+
+ /**
+ * < The array of file transfer specifications. (The xFile structure is defined in <lsf/lsbatch.h>.)
+ */
+ public Pointer /* xFile.ByReference */ xf;
+
+ /**
+ * < The job pre-execution command.
+ */
+ public String preExecCmd;
+
+ /**
+ * < The user that results are mailed to.
+ */
+ public String mailUser;
+
+ /**
+ * < Delete options in options field.
+ */
+ public int delOptions;
+
+ /**
+ * < Extended delete options in options2 field.
+ */
+ public int delOptions2;
+
+ /**
+ * < The name of the project the job will be charged to.
+ */
+ public String projectName;
+
+ /**
+ * < Maximum number of processors required to run the job.
+ */
+ public int maxNumProcessors;
+
+ /**
+ * < Specified login shell used to initialize the execution environment for the job (see the -L option of bsub).
+ */
+ public String loginShell;
+
+ /**
+ * < The name of the LSF user group (see lsb.users) to which the job will belong. (see the -G option of bsub)
+ */
+ public String userGroup;
+
+ /**
+ * < Passes the exception handlers to mbatchd during a job. (see the -X option of bsub). Specifies execption handlers that tell the system how to respond to an exceptional condition for a job. An action is performed when any one of the following exceptions is detected: - \b missched - A job has not been scheduled within the time event specified in the -T option. - \b overrun - A job did not finish in its maximum time (maxtime). - \b underrun - A job finished before it reaches its [...]
+ */
+ public String exceptList;
+
+
+ /**
+ * < User priority for fairshare scheduling.
+ */
+ public int userPriority;
+
+ /**
+ * < Reservation ID for advance reservation.
+ */
+ public String rsvId;
+
+ /**
+ * < Job group under which the job runs.
+ */
+ public String jobGroup;
+
+ /**
+ * < SLA under which the job runs.
+ */
+ public String sla;
+
+ /**
+ * < External scheduler options.
+ */
+ public String extsched;
+
+ /**
+ * < Warning time period in seconds, -1 if unspecified.
+ */
+ public int warningTimePeriod;
+
+ /**
+ * < Warning action, SIGNAL | CHKPNT | command, null if unspecified.
+ */
+ public String warningAction;
+
+ /**
+ * < License Scheduler project name.
+ */
+ public String licenseProject;
+
+ /**
+ * < Extended bitwise inclusive OR of options flags in \ref lsb_submit_options3.
+ */
+ public int options3;
+
+ /**
+ * < Extended delete options in options3 field.
+ */
+ public int delOptions3;
+
+ /**
+ * < Application profile under which the job runs.
+ */
+ public String app;
+
+ /**
+ * < -1 if no -jsdl and -jsdl_strict options. - 0 -jsdl_strict option - 1 -jsdl option
+ */
+ public int jsdlFlag;
+
+ /**
+ * < JSDL filename
+ */
+ public String jsdlDoc;
+
+ /**
+ * < ARM correlator
+ */
+ public Pointer correlator;
+
+ /**
+ * < Absolute priority scheduling string set by administrators to denote static system APS value or ADMIN factor APS value. This field is ignored by \ref lsb_submit.
+ */
+ public String apsString;
+
+ /**
+ * < Post-execution commands specified by -Ep option of bsub and bmod.
+ */
+ public String postExecCmd;
+
+ /**
+ * < Current working directory specified by -cwd option of bsub and bmod.
+ */
+ public String cwd;
+
+ /**
+ * < Runtime estimate specified by -We option of bsub and bmod.
+ */
+ public int runtimeEstimation;
+
+ /**
+ * < Job-level requeue exit values specified by -Q option of bsub and bmod.
+ */
+ public String requeueEValues;
+
+ /**
+ * < Initial checkpoint period specified by -k option of bsub and bmod.
+ */
+ public int initChkpntPeriod;
+
+ /**
+ * < Job migration threshold specified by -mig option of bsub and bmod.
+ */
+ public int migThreshold;
+
+ /**
+ * < Job resize notification command to be invoked on the first execution host when a resize request has been satisfied.
+ */
+ public String notifyCmd;
+
+ /**
+ * < Job description.
+ */
+ public String jobDescription;
+/* #if defined(LSF_SIMULATOR)
+
+/**< simulation related options */
+ /*public String simReq;*/
+ /* #endif */
+
+ /**
+ * < For new options in future
+ */
+ public submit_ext.ByReference submitExt;
+ }
+
+
+
+
+ /**
+ * \brief submit reply.
+ */
+ public static class submitReply extends Structure {
+ public static class ByReference extends submitReply implements Structure.ByReference {}
+ public static class ByValue extends submitReply implements Structure.ByValue {}
+ public submitReply() {}
+ public submitReply(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The queue the job was submitted to.
+ */
+ public String queue;
+
+ /**
+ * < DependCond contained badJobId but badJobId does not exist in the system.
+ */
+ public long badJobId;
+
+ /**
+ * < DependCond contained badJobName but badJobName does not exist in the system. If the environment variable BSUB_CHK_RESREQ is set, the value of lsberrno is either LSBE_RESREQ_OK or LSBE_RESREQ_ERR, depending on the result of resource requirement string checking. The badJobName field contains the detailed error message.
+ */
+ public String badJobName;
+
+ /**< If lsberrno is LSBE_BAD_HOST,
+ * (**askedHosts)[badReqIndx] is not a host known to the system.
+ * If lsberrno is LSBE_QUEUE_HOST, (**askedHosts)[badReqIndx]
+ * is not a host used by the specified queue. If lsberrno is
+ * LSBE_OVER_LIMIT, (*rLimits)[badReqIndx] exceeds the queue's
+ * limit for the resource. */
+ public int badReqIndx;
+ }
+
+
+
+ /**
+ * \brief submit migration request.
+ */
+ public static class submig extends Structure {
+ public static class ByReference extends submig implements Structure.ByReference {}
+ public static class ByValue extends submig implements Structure.ByValue {}
+ public submig() {}
+ public submig(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The job ID of the job to be migrated.
+ */
+ public long jobId;
+
+ /**
+ * < Please refer to \ref lsb_submit_options.
+ */
+ public int options;
+
+ /**
+ * < The number of hosts supplied as candidates for migration.
+ */
+ public int numAskedHosts;
+
+ /**
+ * < An array of pointers to the names of candidate hosts for migration.
+ */
+ public Pointer askedHosts;
+ }
+
+
+
+/* structure for lsb_addjgrp() call */
+
+ public static class jgrpAdd extends Structure {
+ public static class ByReference extends jgrpAdd implements Structure.ByReference {}
+ public static class ByValue extends jgrpAdd implements Structure.ByValue {}
+ public jgrpAdd() {}
+ public jgrpAdd(Pointer p) { super(p); read(); }
+
+ public String groupSpec;
+ public String timeEvent;
+ public String depCond;
+ public String sla;
+ public int maxJLimit;
+ }
+
+
+
+/* structure for lsb_modjgrp() call */
+
+ public static class jgrpMod extends Structure {
+ public static class ByReference extends jgrpMod implements Structure.ByReference {}
+ public static class ByValue extends jgrpMod implements Structure.ByValue {}
+ public jgrpMod() {}
+ public jgrpMod(Pointer p) { super(p); read(); }
+
+ public String destSpec;
+ public jgrpAdd jgrp;
+ }
+
+
+
+/* structure for lsb_addjgrp() and lsb_modjgrp() call reply */
+
+ public static class jgrpReply extends Structure {
+ public static class ByReference extends jgrpReply implements Structure.ByReference {}
+ public static class ByValue extends jgrpReply implements Structure.ByValue {}
+ public jgrpReply() {}
+ public jgrpReply(Pointer p) { super(p); read(); }
+
+ public String badJgrpName;
+ public int num;
+ public Pointer delJgrpList;
+ }
+
+
+
+ /**
+ * \brief Signal a group of jobs.
+ */
+ public static class signalBulkJobs extends Structure {
+ public static class ByReference extends signalBulkJobs implements Structure.ByReference {}
+ public static class ByValue extends signalBulkJobs implements Structure.ByValue {}
+ public signalBulkJobs() {}
+ public signalBulkJobs(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Signal type
+ */
+ public int signal;
+
+ /**
+ * < Number of jobs
+ */
+ public int njobs;
+
+ /**
+ * < Jobids list
+ */
+ public Pointer jobs;
+
+ /**
+ * < Flags
+ */
+ public int flags;
+ }
+
+
+
+/* structure for lsb_ctrljgrp() call */
+
+ public static class jgrpCtrl extends Structure {
+ public static class ByReference extends jgrpCtrl implements Structure.ByReference {}
+ public static class ByValue extends jgrpCtrl implements Structure.ByValue {}
+ public jgrpCtrl() {}
+ public jgrpCtrl(Pointer p) { super(p); read(); }
+
+ public String groupSpec;
+ public String userSpec;
+ public int options;
+
+/* JGRP_RELEASE, JGRP_HOLD, JGRP_DEL */
+ public int ctrlOp;
+ }
+
+
+
+
+/* Indicate no change in chkpnt period for lsb_chkpntjob() */
+ public static final int LSB_CHKPERIOD_NOCHNG = -1;
+
+ /**
+ * \addtogroup chkpnt_job_option chkpnt_job_option
+ * checkpoint job options()
+ */
+
+ /**
+ * < Kill process if successfully chkpnted
+ */
+ public static final int LSB_CHKPNT_KILL = 0x1;
+
+ /**
+ * < Force chkpnt even if non-chkpntable conditions exist.
+ */
+ public static final int LSB_CHKPNT_FORCE = 0x2;
+
+ /**
+ * < Copy all regular files in use by the checkpointed process to the checkpoint directory.
+ */
+ public static final int LSB_CHKPNT_COPY = 0x3;
+
+ /**
+ * < Chkpnt for the purpose of migration
+ */
+ public static final int LSB_CHKPNT_MIG = 0x4;
+
+ /**
+ * < Stop process if successfully chkpnted
+ */
+ public static final int LSB_CHKPNT_STOP = 0x8;
+
+ /**
+ * \addtogroup kill_requeue kill_requeue
+ * kill and requeue a job options()
+ */
+
+ /**
+ * < Kill then re-queue a job
+ */
+ public static final int LSB_KILL_REQUEUE = 0x10;
+
+/* options for lsb_openjobinfo() */
+ /**
+ * \addtogroup defs_lsb_openjobinfo defs_lsb_openjobinfo
+ * Information options about job.
+ */
+
+ /**
+ * < Reserved user name
+ */
+ public static final String ALL_USERS = "all";
+ /**
+ * \defgroup defs_lsb_openjobinfo_a defs_lsb_openjobinfo_a
+ * defs_lsb_openjobinfo_a is part of defs_lsb_openjobinfo
+ */
+ public static final int ALL_JOB = 0x0001;
+ /**
+ * < Information about all jobs, including unfinished jobs (pending, running or suspended) and recently finished jobs. LSF remembers jobs finished within the preceding period. This period is set by the parameter CLEAN_PERIOD in the lsb.params file. The default is 3600 seconds (1 hour). (See lsb.params). The command line equivalent is bjobs -a./
+ * <p/>
+ * /**< Information about recently finished jobs.
+ */
+ public static final int DONE_JOB = 0x0002;
+
+ /**
+ * < Information about pending jobs.
+ */
+ public static final int PEND_JOB = 0x0004;
+
+ /**
+ * < Information about suspended jobs.
+ */
+ public static final int SUSP_JOB = 0x0008;
+
+ /**
+ * < Information about all unfinished jobs.
+ */
+ public static final int CUR_JOB = 0x0010;
+
+ /**
+ * < Information about the last submitted job.
+ */
+ public static final int LAST_JOB = 0x0020;
+
+ /**
+ * < Information about all running jobs
+ */
+ public static final int RUN_JOB = 0x0040;
+
+ /**
+ * < Information about JobId only.
+ */
+ public static final int JOBID_ONLY = 0x0080;
+
+ /**
+ * < Internal use only.
+ */
+ public static final int HOST_NAME = 0x0100;
+
+ /**
+ * < Exclude pending jobs.
+ */
+ public static final int NO_PEND_REASONS = 0x0200;
+
+ /**
+ * < Return group info structures
+ */
+ public static final int JGRP_INFO = 0x0400;
+
+ /**
+ * < Recursively search job group tree
+ */
+ public static final int JGRP_RECURSIVE = 0x0800;
+
+ /**
+ * < Return job array info structures
+ */
+ public static final int JGRP_ARRAY_INFO = 0x1000;
+
+ /**
+ * < All jobs in the core
+ */
+ public static final int JOBID_ONLY_ALL = 0x02000;
+
+ /**
+ * < All zombie jobs
+ */
+ public static final int ZOMBIE_JOB = 0x04000;
+
+ /**
+ * < Display remote jobs by their submission jobid.
+ */
+ public static final int TRANSPARENT_MC = 0x08000;
+
+ /**
+ * < Exceptional jobs
+ */
+ public static final int EXCEPT_JOB = 0x10000;
+
+ /**
+ * < Display for murex jobs
+ */
+ public static final int MUREX_JOB = 0x20000;
+
+
+ /**
+ * < To symphony UA
+ */
+ public static final int TO_SYM_UA = 0x40000;
+
+ /**
+ * < Only show top-level symphony job
+ */
+ public static final int SYM_TOP_LEVEL_ONLY = 0x80000;
+
+ /**
+ * < For internal use only
+ */
+ public static final int JGRP_NAME = 0x100000;
+
+ /**
+ * < Condensed host group
+ */
+ public static final int COND_HOSTNAME = 0x200000;
+
+ /**
+ * < Called from command, for internal use only
+ */
+ public static final int FROM_BJOBSCMD = 0x400000;
+
+ /**
+ * < -l in command parameter, for internal use only
+ */
+ public static final int WITH_LOPTION = 0x800000;
+
+ /**
+ * < Jobs submitted to aps queue
+ */
+ public static final int APS_JOB = 0x1000000;
+
+ /**
+ * < Information about user group.
+ */
+ public static final int UGRP_INFO = 0x2000000;
+ /** RFC#1531: -G option support*/
+
+ /**
+ * < -WL
+ */
+ public static final int TIME_LEFT = 0x4000000;
+ /**
+ * < Estimated time remaining based on the runtime estimate or runlimit.
+ */
+
+/* -WF*/
+ public static final int FINISH_TIME = 0x8000000;
+ /**
+ * < Estimated finish time based on the runtime estimate or runlimit.
+ */
+
+/* -WP*/
+ public static final int COM_PERCENTAGE = 0x10000000;
+ /**
+ * < Estimated completion percentage based on the runtime estimate or runlimit. If options is 0, default to CUR_JOB.
+ */
+
+/* -ss option */
+ public static final int SSCHED_JOB = 0x20000000;
+
+/* -G option */
+ public static final int KILL_JGRP_RECURSIVE = 0x40000000;
+
+ /**
+ * \addtogroup group_nodetypes group_nodetypes
+ * define statements group node types.
+ */
+
+ /**
+ * < Job
+ */
+ public static final int JGRP_NODE_JOB = 1;
+
+ /**
+ * < Group
+ */
+ public static final int JGRP_NODE_GROUP = 2;
+
+ /**
+ * < Array
+ */
+ public static final int JGRP_NODE_ARRAY = 3;
+
+ /**
+ * < SLA
+ */
+ public static final int JGRP_NODE_SLA = 4;
+
+/* jobId macros */
+ public static final long LSB_MAX_ARRAY_JOBID = 0x0FFFFFFFFL;
+ public static final long LSB_MAX_ARRAY_IDX = 0x07FFFFFFFL;
+ public static final int LSB_MAX_SEDJOB_RUNID = (0x0F);
+ public static long LSB_JOBID (int array_jobId, int array_idx) { return (((long)array_idx << 32) | array_jobId); }
+ public static int LSB_ARRAY_IDX (long jobId) { return (((jobId) == -1) ? (0) : (int)(((long)jobId >> 32) & LSB_MAX_ARRAY_IDX)); }
+ public static int LSB_ARRAY_JOBID (long jobId) { return (((jobId) == -1) ? (-1) : (int)(jobId)); }
+ //public static int LSB_ARRAY_JOBID (long jobId) { return (((jobId) == -1) ? (-1) : (int)(jobId & LSB_MAX_ARRAY_JOBID)); }
+
+/* Status of a job group */
+
+ public static final int JGRP_INACTIVE = 0;
+ public static final int JGRP_ACTIVE = 1;
+ public static final int JGRP_UNDEFINED = -1;
+
+ /**
+ * \addtogroup jobgroup_controltypes jobgroup_controltypes
+ * define statements job group control types.
+ */
+
+
+ /**
+ * < bgrelease
+ */
+ public static final int JGRP_RELEASE = 1;
+
+ /**
+ * < bghold
+ */
+ public static final int JGRP_HOLD = 2;
+
+ /**
+ * < bgdel
+ */
+ public static final int JGRP_DEL = 3;
+
+ /**
+ * \addtogroup jobgroup_counterIndex jobgroup_counterIndex
+ * Following can be used to index into 'counters' array.
+ */
+
+ /**
+ * < Total jobs in the array
+ */
+ public static final int JGRP_COUNT_NJOBS = 0;
+
+ /**
+ * < Number of pending jobs in the array
+ */
+ public static final int JGRP_COUNT_PEND = 1;
+
+ /**
+ * < Number of held jobs in the array
+ */
+ public static final int JGRP_COUNT_NPSUSP = 2;
+
+ /**
+ * < Number of running jobs in the array
+ */
+ public static final int JGRP_COUNT_NRUN = 3;
+
+ /**
+ * < Number of jobs suspended by the system in the array
+ */
+ public static final int JGRP_COUNT_NSSUSP = 4;
+
+ /**
+ * < Number of jobs suspended by the user in the array
+ */
+ public static final int JGRP_COUNT_NUSUSP = 5;
+
+ /**
+ * < Number of exited jobs in the array
+ */
+ public static final int JGRP_COUNT_NEXIT = 6;
+
+ /**
+ * < Number of successfully completed jobs
+ */
+ public static final int JGRP_COUNT_NDONE = 7;
+
+ /**
+ * < Total slots in the array
+ */
+ public static final int JGRP_COUNT_NJOBS_SLOTS = 8;
+
+ /**
+ * < Number of pending slots in the array
+ */
+ public static final int JGRP_COUNT_PEND_SLOTS = 9;
+
+ /**
+ * < Number of running slots in the array
+ */
+ public static final int JGRP_COUNT_RUN_SLOTS = 10;
+
+ /**
+ * < Number of slots suspended by the system in the array
+ */
+ public static final int JGRP_COUNT_SSUSP_SLOTS = 11;
+
+ /**
+ * < Number of slots suspended by the user in the array
+ */
+ public static final int JGRP_COUNT_USUSP_SLOTS = 12;
+
+ /**
+ * < Number of reserverd slots in the array
+ */
+ public static final int JGRP_COUNT_RESV_SLOTS = 13;
+
+/* job group modification types */
+ public static final int JGRP_MOD_LIMIT = 0x1;
+
+/*the number of counters of job group
+* based on job level
+*/
+ public static final int NUM_JGRP_JOB_COUNTERS = 8;
+/* the number of all counters of job group,
+* including job level and slot level
+*/
+/* {njobs, npend, npsusp, nrun, nssusp nususp, nexit, ndone} */
+ public static final int NUM_JGRP_COUNTERS = 14;
+
+/* job group is created explicitly */
+ public static final int JGRP_CREATE_EXP = 0x01;
+
+/* job group is created implicitly */
+ public static final int JGRP_CREATE_IMP = 0x02;
+/* The LSF job group.
+ */
+
+ public static class jgrp extends Structure {
+ public static class ByReference extends jgrp implements Structure.ByReference {}
+ public static class ByValue extends jgrp implements Structure.ByValue {}
+ public jgrp() {}
+ public jgrp(Pointer p) { super(p); read(); }
+
+ public String name;
+ public String path;
+ public String user;
+ public String sla;
+ public int[] counters = new int[NUM_JGRP_COUNTERS];
+ public int maxJLimit;
+ }
+
+
+
+/* Structure for lsb_setjobattr() call */
+
+ public static class jobAttrInfoEnt extends Structure {
+ public static class ByReference extends jobAttrInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends jobAttrInfoEnt implements Structure.ByValue {}
+ public jobAttrInfoEnt() {}
+ public jobAttrInfoEnt(Pointer p) { super(p); read(); }
+
+
+/* id of the job */
+ public long jobId;
+
+/* port number of the job */
+ public short port;
+
+/* first executing host of the job */
+ public byte[] hostname = new byte[LibLsf.MAXHOSTNAMELEN];
+ }
+
+
+
+ /**
+ * \brief job attribute setting log.
+ */
+ public static class jobAttrSetLog extends Structure {
+ public static class ByReference extends jobAttrSetLog implements Structure.ByReference {}
+ public static class ByValue extends jobAttrSetLog implements Structure.ByValue {}
+ public jobAttrSetLog() {}
+ public jobAttrSetLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < The user who requested the action
+ */
+ public int uid;
+
+ /**
+ * < Job attributes
+ */
+ public int port;
+
+ /**
+ * < Name of the host
+ */
+ public String hostname;
+ }
+
+
+
+ /**
+ * \brief job information head.
+ */
+ public static class jobInfoHead extends Structure {
+ public static class ByReference extends jobInfoHead implements Structure.ByReference {}
+ public static class ByValue extends jobInfoHead implements Structure.ByValue {}
+ public jobInfoHead() {}
+ public jobInfoHead(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The number of jobs in the connection
+ */
+ public int numJobs;
+
+ /**
+ * < An array of job identification numbers in the conection
+ */
+ public NativeLongByReference jobIds;
+
+ /**
+ * < The number of hosts in the connection
+ */
+ public int numHosts;
+
+ /**
+ * < An array of host names in the connection
+ */
+ public Pointer hostNames;
+
+ /**
+ * < The number of clusters in the connection
+ */
+ public int numClusters;
+
+ /**
+ * < An array of cluster names in the connection
+ */
+ public Pointer clusterNames;
+
+ /**
+ * < The number of remoteHosts in the connection
+ */
+ public IntByReference numRemoteHosts;
+
+ /**
+ * < An array of remoteHost names in the connection
+ */
+ public PointerByReference remoteHosts;
+ }
+
+
+
+ /**
+ * \brief job Information head extent
+ */
+ public static class jobInfoHeadExt extends Structure {
+ public static class ByReference extends jobInfoHeadExt implements Structure.ByReference {}
+ public static class ByValue extends jobInfoHeadExt implements Structure.ByValue {}
+ public jobInfoHeadExt() {}
+ public jobInfoHeadExt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Job Information header
+ */
+ public jobInfoHead.ByReference jobInfoHead;
+
+ /**
+ * < Group Information returned
+ */
+ public Pointer groupInfo;
+ }
+
+
+
+ /**
+ * \brief structure reserveItem
+ */
+ public static class reserveItem extends Structure {
+ public static class ByReference extends reserveItem implements Structure.ByReference {}
+ public static class ByValue extends reserveItem implements Structure.ByValue {}
+ public reserveItem() {}
+ public reserveItem(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Name of the resource to reserve.
+ */
+ public String resName;
+
+ /**
+ * < The number of hosts to reserve this resource.
+ */
+ public int nHost;
+
+ /**
+ * < Amount of reservation is made on each host. Some hosts may reserve 0.
+ */
+ public FloatByReference value;
+
+ /**
+ * < Flag of shared or host-base resource
+ */
+ public int shared;
+ }
+
+
+
+ /**
+ * \brief job information entry.
+ */
+ public static class jobInfoEnt extends Structure {
+ public static class ByReference extends jobInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends jobInfoEnt implements Structure.ByValue {}
+ public jobInfoEnt() {}
+ public jobInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The job ID that the LSF system assigned to the job.
+ */
+ public long jobId;
+
+ /**
+ * < The name of the user who submitted the job.
+ */
+ public String user;
+
+ /**
+ * < The current status of the job.Possible values areshown in job_states
+ */
+ public int status;
+
+ /**
+ * < Pending or suspending reasons of the job
+ */
+ public IntByReference reasonTb;
+
+ /**
+ * < Length of reasonTb[]
+ */
+ public int numReasons;
+
+ /**
+ * < The reason a job is pending or suspended.
+ */
+ public int reasons;
+
+ /**
+ * < The reason a job is pending or suspended. If status is JOB_STAT_PEND, the values of reasons and subreasons are explained by \ref lsb_pendreason. If status is JOB_STAT_PSUSP, the values of reasons and subreasons are explained by \ref lsb_suspreason. When reasons is PEND_HOST_LOAD or SUSP_LOAD_REASON, subreasons indicates the load indices that are out of bounds. If reasons is PEND_HOST_LOAD, subreasons is the same as busySched in the hostInfoEnt structure; if reasons is SUS [...]
+ */
+ public int subreasons;
+
+ /**
+ * < The job process ID.
+ */
+ public int jobPid;
+
+ /**
+ * < The time the job was submitted, in seconds since 00:00:00 GMT, Jan. 1, 1970.
+ */
+ public NativeLong submitTime;
+
+ /**
+ * < Time when job slots are reserved
+ */
+ public NativeLong reserveTime;
+
+ /**
+ * < The time that the job started running, if it has been dispatched.
+ */
+ public NativeLong startTime;
+
+ /**
+ * < Job's predicted start time
+ */
+ public NativeLong predictedStartTime;
+
+ /**
+ * < The termination time of the job, if it has completed.
+ */
+ public NativeLong endTime;
+
+ /**
+ * < Last time event
+ */
+ public NativeLong lastEvent;
+
+ /**
+ * < Next time event
+ */
+ public NativeLong nextEvent;
+
+ /**
+ * < Duration time (minutes)
+ */
+ public int duration;
+
+ /**
+ * < CPU time consumed by the job
+ */
+ public float cpuTime;
+
+ /**
+ * < The file creation mask when the job was submitted.
+ */
+ public int umask;
+
+ /**
+ * < The current working directory when the job was submitted.
+ */
+ public String cwd;
+
+ /**
+ * < Home directory on submission host.
+ */
+ public String subHomeDir;
+
+ /**
+ * < The name of the host from which the job was submitted.
+ */
+ public String fromHost;
+
+ /**
+ * < The array of names of hosts on which the job executes.
+ */
+ public Pointer exHosts;
+
+ /**
+ * < The number of hosts on which the job executes.
+ */
+ public int numExHosts;
+
+ /**
+ * < The CPU factor for normalizing CPU and wall clock time limits.
+ */
+ public float cpuFactor;
+
+ /**
+ * < The number of load indices in the loadSched and loadStop arrays.
+ */
+ public int nIdx;
+
+ /**
+ * < The values in the loadSched array specify the thresholds for the corresponding load indices. Only if the current values of all specified load indices of a host are within (below or above, depending on the meaning of the load index) their corresponding thresholds may the suspended job be resumed on this host. For an explanation of the entries in the loadSched, see \ref lsb_hostinfo.
+ */
+ public FloatByReference loadSched;
+
+ /**
+ * < The values in the loadStop array specify the thresholds for job suspension; if any of the current load index values of the host crosses its threshold, the job will be suspended. For an explanation of the entries in the loadStop, see \ref lsb_hostinfo.
+ */
+ public FloatByReference loadStop;
+
+ /**
+ * < Structure for \ref lsb_submit call.
+ */
+ public submit submit;
+
+ /**
+ * < Job exit status.
+ */
+ public int exitStatus;
+
+ /**
+ * < Mapped UNIX user ID on the execution host.
+ */
+ public int execUid;
+
+ /**
+ * < Home directory for the job on the execution host.
+ */
+ public String execHome;
+
+ /**
+ * < Current working directory for the job on the execution host.
+ */
+ public String execCwd;
+
+ /**
+ * < Mapped user name on the execution host.
+ */
+ public String execUsername;
+
+ /**
+ * < Time of the last job resource usage update.
+ */
+ public NativeLong jRusageUpdateTime;
+
+ /**
+ * < Contains resource usage information for the job.
+ */
+ public LibLsf.jRusage runRusage;
+
+ /**
+ * < Job type.N_JOB, N_GROUP, N_HEAD
+ */
+ public int jType;
+
+ /**
+ * < The parent job group of a job or job group.
+ */
+ public String parentGroup;
+
+ /**
+ * < If jType is JGRP_NODE_GROUP, then it is the job group name. Otherwise, it is thejob name.
+ */
+ public String jName;
+
+ /**
+ * < Index into the counter array, only used for job arrays. Possible index values are shown in \ref jobgroup_counterIndex
+ */
+ public int[] counter = new int[NUM_JGRP_COUNTERS];
+
+ /**
+ * < Service port of the job.
+ */
+ public short port;
+
+ /**
+ * < Job dynamic priority
+ */
+ public int jobPriority;
+
+ /**
+ * < The number of external messages in the job.
+ */
+ public int numExternalMsg;
+
+ /**
+ * < This structure contains the information required to define an external message reply.
+ */
+ public Pointer externalMsg;
+
+ /**
+ * < MultiCluster cluster ID. If clusterId is greater than or equal to 0, the job is a pending remote job, and \ref lsb_readjobinfo checks for host_name\@cluster_name. If host name is needed, it should be found in jInfoH->remoteHosts. If the remote host name is not available, the constant string remoteHost is used.
+ */
+ public int clusterId;
+
+ /**
+ * < Detail reason field
+ */
+ public String detailReason;
+
+ /**
+ * < Idle factor for job exception handling. If the job idle factor is less than the specified threshold, LSF invokes LSF_SERVERDIR/eadmin to trigger the action for a job idle exception.
+ */
+ public float idleFactor;
+
+ /**
+ * < Job exception handling mask
+ */
+ public int exceptMask;
+
+
+ /**
+ * < Placement information of LSF HPC jobs.Placement information of LSF HPC jobs.Arbitrary information of a job stored as a string currently used by rms_rid and rms_alloc
+ */
+ public String additionalInfo;
+
+ /**
+ * < Job termination reason. See lsbatch.h.
+ */
+ public int exitInfo;
+
+ /**
+ * < Job warning time period in seconds; -1 if unspecified.
+ */
+ public int warningTimePeriod;
+
+ /**
+ * < Warning action, SIGNAL | CHKPNT |command, null if unspecified
+ */
+ public String warningAction;
+
+ /**
+ * < SAAP charged for job
+ */
+ public String chargedSAAP;
+
+ /**
+ * < The rusage satisfied at job runtime
+ */
+ public String execRusage;
+
+ /**
+ * < The time when advance reservation expired or was deleted.
+ */
+ public NativeLong rsvInActive;
+
+ /**
+ * < The number of licenses reported from License Scheduler.
+ */
+ public int numLicense;
+
+ /**
+ * < License Scheduler license names.
+ */
+ public Pointer licenseNames;
+
+ /**
+ * < Absolute priority scheduling (APS) priority value.
+ */
+ public float aps;
+
+ /**
+ * < Absolute priority scheduling (APS) string set by administrators to denote static system APS value
+ */
+ public float adminAps;
+
+ /**
+ * < The real runtime on the execution host.
+ */
+ public int runTime;
+
+ /**
+ * < How many kinds of resource are reserved by this job
+ */
+ public int reserveCnt;
+
+ /**
+ * < Detail reservation information for each kind of resource
+ */
+ public Pointer /* reserveItem.ByReference */ items;
+
+ /**
+ * < Absolute priority scheduling (APS) string set by administrators to denote ADMIN factor APS value.
+ */
+ public float adminFactorVal;
+
+ /**
+ * < Pending resize min. 0, if no resize pending.
+ */
+ public int resizeMin;
+
+ /**
+ * < Pending resize max. 0, if no resize pending
+ */
+ public int resizeMax;
+
+ /**
+ * < Time when pending request was issued
+ */
+ public NativeLong resizeReqTime;
+
+ /**
+ * < Number of hosts when job starts
+ */
+ public int jStartNumExHosts;
+
+ /**
+ * < Host list when job starts
+ */
+ public Pointer jStartExHosts;
+
+ /**
+ * < Last time when job allocation changed
+ */
+ public NativeLong lastResizeTime;
+ }
+
+
+/* the bit set for jobInfoEnt->exceptMask */
+ public static final int J_EXCEPT_OVERRUN = 0x02;
+ public static final int J_EXCEPT_UNDERUN = 0x04;
+ public static final int J_EXCEPT_IDLE = 0x80;
+ public static final int J_EXCEPT_RUNTIME_EST_EXCEEDED = 0x100;
+
+/* exception showed by bjobs -l and bacct -l*/
+ public static final String OVERRUN = "overrun";
+ public static final String UNDERRUN = "underrun";
+ public static final String IDLE = "idle";
+ public static final String SPACE = " ";
+ public static final String RUNTIME_EST_EXCEEDED = "runtime_est_exceeded";
+
+/* LSF7.0 moved jobInfoReq structure definition from
+* daemonout.h to lsbatch.h. This structure will work
+* with new API \ref lsb_openjobinfo_req
+ */
+
+ /**
+ * \brief job Information Request
+ */
+ public static class jobInfoReq extends Structure {
+ public static class ByReference extends jobInfoReq implements Structure.ByReference {}
+ public static class ByValue extends jobInfoReq implements Structure.ByValue {}
+ public jobInfoReq() {}
+ public jobInfoReq(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Options defined in \ref defs_lsb_openjobinfo
+ */
+ public int options;
+
+ /**
+ * < Name of user whose jobs to be checked
+ */
+ public String userName;
+
+ /**
+ * < Job id, 0 means all jobs
+ */
+ public long jobId;
+
+ /**
+ * < Job name
+ */
+ public String jobName;
+
+ /**
+ * < Queue name
+ */
+ public String queue;
+
+ /**
+ * < Check jobs running on this host
+ */
+ public String host;
+
+ /**
+ * < Job application
+ */
+ public String app;
+
+ /**
+ * < Job description
+ */
+ public String jobDescription;
+
+ /**
+ * < For new options in future
+ */
+ public submit_ext.ByReference submitExt;
+ }
+
+
+
+ /**
+ * \brief user information entry.
+ */
+ public static class userInfoEnt extends Structure {
+ public static class ByReference extends userInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends userInfoEnt implements Structure.ByValue {}
+ public userInfoEnt() {}
+ public userInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Name of the user or user group
+ */
+ public String user;
+
+ /**
+ * < The maximum number of job slots the user or user group can use on each processor. The job slots can be used by started jobs or reserved for PEND jobs.
+ */
+ public float procJobLimit;
+
+ /**
+ * < The maximum number of job slots that the user or user group can use simultaneously in the local LSF cluster. The job slots can be used by started jobs or reserved for PEND jobs.
+ */
+ public int maxJobs;
+
+ /**
+ * < The current number of job slots used by running and suspended jobs belonging to the user or user group.
+ */
+ public int numStartJobs;
+
+ /**
+ * < The total number of job slots in the LSF cluster for the jobs submitted by the user or user group.
+ */
+ public int numJobs;
+
+ /**
+ * < The number of job slots the user or user group has for pending jobs.
+ */
+ public int numPEND;
+
+ /**
+ * < The number of job slots the user or user group has for running jobs.
+ */
+ public int numRUN;
+
+ /**
+ * < The number of job slots for the jobs belonging to the user or user group that have been suspended by the system.
+ */
+ public int numSSUSP;
+
+ /**
+ * < The number of job slots for the jobs belonging to the user or user group that have been suspended by the user or the LSF system administrator.
+ */
+ public int numUSUSP;
+
+ /**
+ * < The number of job slots reserved for the pending jobs belonging to the user or user group.
+ */
+ public int numRESERVE;
+
+ /**
+ * < The maximum number of pending jobs allowed.
+ */
+ public int maxPendJobs;
+ }
+
+
+
+/* UserEquivalent info */
+
+ public static class userEquivalentInfoEnt extends Structure {
+ public static class ByReference extends userEquivalentInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends userEquivalentInfoEnt implements Structure.ByValue {}
+ public userEquivalentInfoEnt() {}
+ public userEquivalentInfoEnt(Pointer p) { super(p); read(); }
+
+ public String equivalentUsers;
+ }
+
+
+
+/* UserMapping info */
+
+ public static class userMappingInfoEnt extends Structure {
+ public static class ByReference extends userMappingInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends userMappingInfoEnt implements Structure.ByValue {}
+ public userMappingInfoEnt() {}
+ public userMappingInfoEnt(Pointer p) { super(p); read(); }
+
+
+/* Users in the local cluster */
+ public String localUsers;
+
+/* Users in remote clusters */
+ public String remoteUsers;
+
+/* "export" or "import" */
+ public String direction;
+ }
+
+
+
+
+/* APS structures used for mapping between factors */
+
+ /**
+ * \brief APS structures used for mapping between factors
+ */
+ public static class apsFactorMap extends Structure {
+ public static class ByReference extends apsFactorMap implements Structure.ByReference {}
+ public static class ByValue extends apsFactorMap implements Structure.ByValue {}
+ public apsFactorMap() {}
+ public apsFactorMap(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Name of factor.
+ */
+ public String factorName;
+
+ /**
+ * < SubFactor names.
+ */
+ public String subFactorNames;
+ }
+
+
+
+ /**
+ * \brief APS structures used for mapping between factors
+ */
+ public static class apsLongNameMap extends Structure {
+ public static class ByReference extends apsLongNameMap implements Structure.ByReference {}
+ public static class ByValue extends apsLongNameMap implements Structure.ByValue {}
+ public apsLongNameMap() {}
+ public apsLongNameMap(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Short name
+ */
+ public String shortName;
+
+ /**
+ * < Long name
+ */
+ public String longName;
+ }
+
+
+
+
+/* options for lsb_queueinfo() , some values should not
+* conflict with the option values for lsb_usergrpinfo() and lsb_hostinfo_ex()
+* since they share the same xdr_infoReq()
+*/
+
+/* for compatibility for 2.0 */
+ public static final int ALL_QUEUE = 0x01;
+
+/* for compatibility for 2.0 */
+ public static final int DFT_QUEUE = 0x02;
+ public static final int CHECK_HOST = 0x80;
+ public static final int CHECK_USER = 0x100;
+ public static final int SORT_HOST = 0x200;
+
+/* not bqueues -l or -r */
+ public static final int QUEUE_SHORT_FORMAT = 0x400;
+/* expand hostname into official hostname in lsb_queueinfo */
+ public static final int EXPAND_HOSTNAME = 0x800;
+
+/* only retrieve batch partitions */
+ public static final int RETRIEVE_BATCH = 0x1000;
+
+/* Signal number in each version LSB_SIG_NUM must be equal to
+* signal number in the latest version.
+ */
+ public static final int LSB_SIG_NUM_40 = 25;
+ public static final int LSB_SIG_NUM_41 = 26;
+
+/* Solutions #38347 */
+ public static final int LSB_SIG_NUM_51 = 30;
+ public static final int LSB_SIG_NUM_60 = 30;
+ public static final int LSB_SIG_NUM = 30;
+
+/* Dynamic CPU provision
+* to indicate whether a SP can lend or borrow hosts
+ */
+ public static final int DCP_LEND_HOSTS = 0x0001;
+ public static final int DCP_BORROW_HOSTS = 0x0002;
+
+/* status to indicate the current situation of Dynamic CPU provision
+* DCP_UNDER_ALLOC_AND_STARVING means a partition is under allocation
+* of dynamic cpu and its pending jobs are starving for more cpus.
+ */
+ public static final int DCP_ALLOC_CPU_OK = 0x0;
+ public static final int DCP_UNDER_ALLOC_CPU = 0x0001;
+ public static final int DCP_JOB_WAIT_FOR_CPU = 0x0002;
+ public static final int DCP_ALLOC_CPU_BUSY = 0x0004;
+
+/* Structure for lsb_queueinfo() call */
+/* !!! IMPORTANT !!!
+* If you change queueInfoEnt, you have to change Intlib/ade.lsbatch.h too!
+ */
+
+ /**
+ * queueInfoEnt queue information entry.
+ */
+ public static class queueInfoEnt extends Structure {
+ public static class ByReference extends queueInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends queueInfoEnt implements Structure.ByValue {}
+ public queueInfoEnt() {}
+ public queueInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The name of the queue.
+ */
+ public String queue;
+
+ /**
+ * < Describes the typical use of the queue.
+ */
+ public String description;
+
+ /**
+ * < Defines the priority of the queue. This determines the order in which the job queues are searched at job dispatch time: queues with higher priority values are searched first. (This is contrary to UNIX process priority ordering.)
+ */
+ public int priority;
+
+ /**
+ * < Defines the nice value at which jobs in this queue will be run.
+ */
+ public short nice;
+
+ /**
+ * < A blank-separated list of names of users allowed to submit jobs to this queue.
+ */
+ public String userList;
+
+ /**
+ * < A blank-separated list of names of hosts to which jobs in this queue may be dispatched.
+ */
+ public String hostList;
+
+ /**
+ * < Original HOSTS string in case "-" is used.
+ */
+ public String hostStr;
+
+ /**
+ * < The number of load indices in the loadSched and loadStop arrays.
+ */
+ public int nIdx;
+
+ /**
+ * < The queue and host loadSched and loadStop arrays control batch job dispatch, suspension, and resumption. The values in the loadSched array specify thresholds for the corresponding load indices. Only if the current values of all specified load indices of a host are within (below or above, depending on the meaning of the load index) the corresponding thresholds of this queue, will jobs in this queue be dispatched to the host. The same conditions are used to resume jobs dispatc [...]
+ */
+ public FloatByReference loadSched;
+
+ /**
+ * < The values in the loadStop array specify the thresholds for job suspension. If any of the current load index values of a host goes beyond a queue's threshold, jobs from the queue will be suspended. For an explanation of the fields in the loadSched and loadStop arrays, see \ref lsb_hostinfo.
+ */
+ public FloatByReference loadStop;
+
+ /**
+ * < Per-user limit on the number of jobs that can be dispatched from this queue and executed concurrently.
+ */
+ public int userJobLimit;
+
+ /**
+ * < Per-processor limit on the number of jobs that can be dispatched from this queue and executed concurrently.
+ */
+ public float procJobLimit;
+
+ /**
+ * < A blank-separated list of time windows describing the run window of the queue. When a queue's run window is closed, no job from this queue will be dispatched. When the run window closes, any running jobs from this queue will be suspended until the run window reopens, when they will be resumed. The default is no restriction, or always open (i.e., 24 hours a day, seven days a week). A time window has the format begin_time-end_time. Time is specified in the format [day:]hour[:m [...]
+ */
+ public String windows;
+
+ /**
+ * < The per-process UNIX hard resource limits for all jobs submitted to this queue (see getrlimit() and lsb.queues). The default values for the resource limits are unlimited, indicated by -1. The constants used to index the rLimits array and the corresponding resource limits are listed below. <br> LSF_RLIMIT_CPU (CPULIMIT) <br> LSF_RLIMIT_FSIZE (FILELIMIT) <br> LSF_RLIMIT_DATA (DATALIMIT) <br> LSF_RLIMIT_STACK (STACKLIMIT) <br> LSF_RLIMIT_CORE (CORELIMIT) <br> LSF_RLIMIT_ [...]
+ */
+ public int[] rLimits = new int[LibLsf.LSF_RLIM_NLIMITS];
+
+ /**
+ * < A host name or host model name. If the queue CPULIMIT or RUNLIMIT gives a host specification, hostSpec will be that specification. Otherwise, if defaultHostSpec (see below) is not null, hostSpec will be defaultHostSpec. Otherwise, if DEFAULT_HOST_SPEC is defined in the lsb.params file, (see lsb.params), hostSpec will be this value. Otherwise, hostSpec will be the name of the host with the largest CPU factor in the cluster.
+ */
+ public String hostSpec;
+
+ /**
+ * < The attributes of the queue.
+ */
+ public int qAttrib;
+
+ /**
+ * < The status of the queue.
+ */
+ public int qStatus;
+
+ /**
+ * < The maximum number of jobs dispatched by the queue and not yet finished.
+ */
+ public int maxJobs;
+
+ /**
+ * < Number of jobs in the queue, including pending, running, and suspended jobs.
+ */
+ public int numJobs;
+
+ /**
+ * < Number of pending jobs in the queue.
+ */
+ public int numPEND;
+
+ /**
+ * < Number of running jobs in the queue.
+ */
+ public int numRUN;
+
+ /**
+ * < Number of system suspended jobs in the queue.
+ */
+ public int numSSUSP;
+
+ /**
+ * < Number of user suspended jobs in the queue.
+ */
+ public int numUSUSP;
+
+ /**
+ * < The queue migration threshold in minutes.
+ */
+ public int mig;
+
+ /**
+ * < The number of seconds that a new job waits, before being scheduled. A value of zero (0) means the job is scheduled without any delay.
+ */
+ public int schedDelay;
+
+ /**
+ * < The number of seconds for a host to wait after dispatching a job to a host, before accepting a second job to dispatch to the same host.
+ */
+ public int acceptIntvl;
+
+ /**
+ * < A blank-separated list of time windows describing the dispatch window of the queue. When a queue's dispatch window is closed, no job from this queue will be dispatched.The default is no restriction, or always open (i.e., 24 hours a day, seven days a week). For the time window format, see windows (above).
+ */
+ public String windowsD;
+
+ /**
+ * < A blank-separated list of queue specifiers. Each queue specifier is of the form queue\@host where host is an NQS host name and queue is the name of a queue on that host.
+ */
+ public String nqsQueues;
+
+ /**
+ * < A blank-separated list of user shares. Each share is of the form [user, share] where user is a user name, a user group name, the reserved word default or the reserved word others, and share is the number of shares the user gets.
+ */
+ public String userShares;
+
+ /**
+ * < The value of DEFAULT_HOST_SPEC in the Queue section for this queue in the lsb.queues file.
+ */
+ public String defaultHostSpec;
+
+ /**
+ * < An LSF resource limit used to limit the number of job slots (processors) a (parallel) job in the queue will use. A job submitted to this queue must specify a number of processors not greater than this limit.
+ */
+ public int procLimit;
+
+ /**
+ * < A list of administrators of the queue. The users whose names are here are allowed to operate on the jobs in the queue and on the queue itself.
+ */
+ public String admins;
+
+ /**
+ * < Queue's pre-exec command. The command is executed before the real batch job is run on the execution host (or on the first host selected for a parallel batch job).
+ */
+ public String preCmd;
+
+ /**
+ * < Queue's post-exec command. The command is run when a job terminates.
+ */
+ public String postCmd;
+
+ /**
+ * < Jobs that exit with these values are automatically requeued.
+ */
+ public String requeueEValues;
+
+ /**
+ * < The maximum number of job slots a host can process from this queue, including job slots of dispatched jobs which have not finished yet and reserved slots for some PEND jobs. This limit controls the number of jobs sent to each host, regardless of a uniprocessor host or multiprocessor host. Default value for this limit is infinity.
+ */
+ public int hostJobLimit;
+
+ /**
+ * < Resource requirement string used to determine eligible hosts for a job.
+ */
+ public String resReq;
+
+ /**
+ * < Number of reserved job slots for pending jobs.
+ */
+ public int numRESERVE;
+
+ /**
+ * < The time used to hold the reserved job slots for a PEND job in this queue.
+ */
+ public int slotHoldTime;
+
+ /**
+ * < Remote MultiCluster send-jobs queues to forward jobs to.
+ */
+ public String sndJobsTo;
+
+ /**
+ * < Remote MultiCluster receive-jobs queues that can forward to this queue.
+ */
+ public String rcvJobsFrom;
+
+ /**
+ * < Resume threshold conditions for a suspended job in this queue.
+ */
+ public String resumeCond;
+
+ /**
+ * < Stop threshold conditions for a running job in this queue.
+ */
+ public String stopCond;
+
+ /**
+ * < Job starter command for a running job in this queue
+ */
+ public String jobStarter;
+
+ /**
+ * < Command configured for the SUSPEND action.
+ */
+ public String suspendActCmd;
+
+ /**
+ * < Command configured for the RESUME action.
+ */
+ public String resumeActCmd;
+
+ /**
+ * < Command configured for the TERMINATE action.
+ */
+ public String terminateActCmd;
+
+ /**
+ * < Configurable signal mapping
+ */
+ public int[] sigMap = new int[LSB_SIG_NUM];
+
+ /**
+ * < Preemptive scheduling and preemption policy specified for the queue.
+ */
+ public String preemption;
+
+ /**
+ * < Time period for a remote cluster to schedule a job. MultiCluster job forwarding model only. Determines how long a MultiCluster job stays pending in the execution cluster before returning to the submission cluster. The remote timeout limit in seconds is: \li MAX_RSCHED_TIME.ByReference MBD_SLEEP_TIME=timeout
+ */
+ public int maxRschedTime;
+
+
+ /**
+ * < Number of share accounts in the queue.
+ */
+ public int numOfSAccts;
+
+ /**
+ * < (Only used for queues with fairshare policy) a share account vector capturing the fairshare information of the users using the queue. The storage for the array of queueInfoEnt structures will be reused by the next call.
+ */
+ public Pointer /* shareAcctInfoEnt.ByReference */ shareAccts;
+
+ /**
+ * < The directory where the checkpoint files are created.
+ */
+ public String chkpntDir;
+
+ /**
+ * < The checkpoint period in minutes.
+ */
+ public int chkpntPeriod;
+
+ /**
+ * < MultiCluster job forwarding model only. Specifies the MultiCluster pending job limit for a receive-jobs queue. This represents the maximum number of MultiCluster import jobs that can be pending in the queue; once the limit has been reached, the queue stops accepting jobs from remote clusters.
+ */
+ public int imptJobBklg;
+
+ /**
+ * < The default (soft) resource limits for all jobs submitted to this queue (see getrlimit() and lsb.queues).
+ */
+ public int[] defLimits = new int[LibLsf.LSF_RLIM_NLIMITS];
+
+ /**
+ * < The maximum number of jobs allowed to be dispatched together in one job chunk. Must be a positive integer greater than 1.
+ */
+ public int chunkJobSize;
+
+ /**
+ * < The minimum number of job slots (processors) that a job in the queue will use.
+ */
+ public int minProcLimit;
+
+ /**
+ * < The default (soft) limit on the number of job slots (processors) that a job in the queue will use.
+ */
+ public int defProcLimit;
+
+ /**
+ * < The list of queues for cross-queue fairshare.
+ */
+ public String fairshareQueues;
+
+ /**
+ * < Default external scheduling for the queue.
+ */
+ public String defExtSched;
+
+ /**
+ * < Mandatory external scheduling options for the queue.
+ */
+ public String mandExtSched;
+
+ /**
+ * < Share of job slots for queue-based fairshare. Represents the percentage of running jobs (job slots) in use from the queue. SLOT_SHARE must be greater than zero (0) and less than or equal to 100. The sum of SLOT_SHARE for all queues in the pool does not need to be 100%. It can be more or less, depending on your needs.
+ */
+ public int slotShare;
+
+ /**
+ * < Name of the pool of job slots the queue belongs to for queue-based fairshare. A queue can only belong to one pool. All queues in the pool must share the same set of hosts. Specify any ASCII string up to 60 chars long. You can use letters, digits, underscores (_) or dashes (-). You cannot use blank spaces.
+ */
+ public String slotPool;
+
+ /**
+ * < Specifies a threshold for job underrun exception handling. If a job exits before the specified number of minutes, LSF invokes LSF_SERVERDIR/eadmin to trigger the action for a job underrun exception.
+ */
+ public int underRCond;
+
+ /**
+ * < Specifies a threshold for job overrun exception handling. If a job runs longer than the specified run time, LSF invokes LSF_SERVERDIR/eadmin to trigger the action for a job overrun exception.
+ */
+ public int overRCond;
+
+ /**
+ * < Specifies a threshold for idle job exception handling. The value should be a number between 0.0 and 1.0 representing CPU time/runtime. If the job idle factor is less than the specified threshold, LSF invokes LSF_SERVERDIR/eadmin to trigger the action for a job idle exception.
+ */
+ public float idleCond;
+
+ /**
+ * < The number of underrun jobs in the queue.
+ */
+ public int underRJobs;
+
+ /**
+ * < The number of overrun jobs in the queue.
+ */
+ public int overRJobs;
+
+ /**
+ * < The number of idle jobs in the queue.
+ */
+ public int idleJobs;
+
+ /**
+ * < Specifies the amount of time before a job control action occurs that a job warning action is to be taken. For example, 2 minutes before the job reaches run time limit or termination deadline, or the queue's run window is closed, an URG signal is sent to the job. Job action warning time is not normalized. A job action warning time must be specified with a job warning action in order for job warning to take effect.
+ */
+ public int warningTimePeriod;
+
+ /**
+ * < Specifies the job action to be taken before a job control action occurs. For example, 2 minutes before the job reaches run time limit or termination deadline, or the queue's run window is closed, an URG signal is sent to the job. A job warning action must be specified with a job action warning time in order for job warning to take effect. If specified, LSF sends the warning action to the job before the actual control action is taken. This allows the job time to save its resu [...]
+ */
+ public String warningAction;
+
+ /**
+ * < AdminAction - queue control message
+ */
+ public String qCtrlMsg;
+
+ /**
+ * < Acept resource request.
+ */
+ public String acResReq;
+
+ /**
+ * < Limit of running session scheduler jobs.
+ */
+ public int symJobLimit;
+
+ /**
+ * < cpu_req for service partition of session scheduler
+ */
+ public String cpuReq;
+
+ /**
+ * < Indicate whether it would be willing to donate/borrow.
+ */
+ public int proAttr;
+
+ /**
+ * < The maximum number of hosts to lend.
+ */
+ public int lendLimit;
+
+ /**
+ * < The grace period to lend/return idle hosts.
+ */
+ public int hostReallocInterval;
+
+ /**
+ * < Number of CPUs required by CPU provision.
+ */
+ public int numCPURequired;
+
+ /**
+ * < Number of CPUs actually allocated.
+ */
+ public int numCPUAllocated;
+
+ /**
+ * < Number of CPUs borrowed.
+ */
+ public int numCPUBorrowed;
+
+ /**
+ * < Number of CPUs lent.
+ */
+ public int numCPULent;
+ /* the number of reserved cpu(numCPUReserved) = numCPUAllocated - numCPUBorrowed + numCPULent */
+
+
+ /* the following fields are for real-time app(ex. murex) of symphony */
+
+ /**
+ * < Scheduling granularity. in milliseconds.
+ */
+ public int schGranularity;
+
+ /**
+ * < The grace period for stopping session scheduler tasks.
+ */
+ public int symTaskGracePeriod;
+
+ /**
+ * < Minimum number of SSMs.
+ */
+ public int minOfSsm;
+
+ /**
+ * < Maximum number of SSMs.
+ */
+ public int maxOfSsm;
+
+ /**
+ * < Number of allocated slots.
+ */
+ public int numOfAllocSlots;
+
+ /**
+ * < Service preemptin policy.
+ */
+ public String servicePreemption;
+
+
+ /**
+ * < Dynamic cpu provision status.
+ */
+ public int provisionStatus;
+
+ /**
+ * < The minimum time for preemption and backfill, in seconds.
+ */
+ public int minTimeSlice;
+
+ /**
+ * < List of queues defined in a queue group for absolute priority scheduling (APS) across multiple queues.
+ */
+ public String queueGroup;
+
+ /**
+ * < The number of calculation factors for absolute priority scheduling (APS).
+ */
+ public int numApsFactors;
+
+ /**
+ * < List of calculation factors for absolute priority scheduling (APS)
+ */
+ public Pointer /* apsFactorInfo.ByReference */ apsFactorInfoList;
+
+ /**
+ * < The mapping of factors to subfactors for absolute priority scheduling (APS).
+ */
+ public Pointer /* apsFactorMap.ByReference */ apsFactorMaps;
+
+ /**
+ * < The mapping of factors to their long names for absolute priority scheduling (APS).
+ */
+ public Pointer /* apsLongNameMap.ByReference */ apsLongNames;
+
+ /**
+ * < Maximum number of job preempted times.
+ */
+ public int maxJobPreempt;
+
+ /**
+ * < Maximum number of pre-exec retry times.
+ */
+ public int maxPreExecRetry;
+
+ /**
+ * < Maximum number of pre-exec retry times for local cluster
+ */
+ public int localMaxPreExecRetry;
+
+ /**
+ * < Maximum number of job re-queue times.
+ */
+ public int maxJobRequeue;
+
+ /**
+ * < Use Linux-PAM
+ */
+ public int usePam;
+ /* compute unit exclusive */
+
+ /**
+ * < Compute unit type
+ */
+ public int cu_type_exclusive;
+
+ /**
+ * < A string specified in EXCLUSIVE=CU[\<string>]
+ */
+ public String cu_str_exclusive;
+
+ /**
+ * < Resource reservation limit
+ */
+ public String resRsvLimit;
+
+ }
+
+
+
+ /**
+ * \addtogroup signal_action signal_action
+ * define status for signal action
+ */
+
+ /**
+ * < No action
+ */
+ public static final int ACT_NO = 0;
+
+ /**
+ * < Start
+ */
+ public static final int ACT_START = 1;
+
+ /**
+ * < Preempt
+ */
+ public static final int ACT_PREEMPT = 2;
+
+ /**
+ * < Done
+ */
+ public static final int ACT_DONE = 3;
+
+ /**
+ * < Fail
+ */
+ public static final int ACT_FAIL = 4;
+
+ /**
+ * \brief host information entry.
+ */
+ public static class hostInfoEnt extends Structure {
+ public static class ByReference extends hostInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends hostInfoEnt implements Structure.ByValue {}
+ public hostInfoEnt() {}
+ public hostInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The name of the host.
+ */
+ public String host;
+
+ /**
+ * < The status of the host. It is the bitwise inclusive OR. see \ref host_status
+ */
+ public int hStatus;
+
+ /**
+ * < Indicate host loadSched busy reason
+ */
+ public IntByReference busySched;
+
+ /**
+ * < Indicate host loadStop busy reason.
+ */
+ public IntByReference busyStop;
+
+ /**
+ * < The host CPU factor used to scale CPU load values to account for differences in CPU speeds. The faster the CPU, the larger the CPU factor.
+ */
+ public float cpuFactor;
+
+ /**
+ * < The number of load indices in the load, loadSched and loadStop arrays.
+ */
+ public int nIdx;
+
+ /**
+ * < Load information array on a host. This array gives the load information that is used for scheduling batch jobs. This load information is the effective load information from \ref ls_loadofhosts (see \ref ls_loadofhosts) plus the load reserved for running jobs (see lsb.queues for details on resource reservation). The load array is indexed the same as loadSched and loadStop (see loadSched and loadStop below).
+ */
+ public FloatByReference load;
+
+ /**
+ * < Stop scheduling new jobs if over
+ */
+ public FloatByReference loadSched;
+
+ /**
+ * < Stop jobs if over this load. The loadSched and loadStop arrays control batch job scheduling, suspension, and resumption. The values in the loadSched array specify the scheduling thresholds for the corresponding load indices. Only if the current values of all specified load indices of this host are within (below or above, depending on the meaning of the load index) the corresponding thresholds of this host, will jobs be scheduled to run on this host. Similarly, the values in [...]
+ */
+ public FloatByReference loadStop;
+
+ /**
+ * < ASCII desp of run windows.One or more time windows in a week during which batch jobs may be dispatched to run on this host . The default is no restriction, or always open (i.e., 24 hours a day seven days a week). These windows are similar to the dispatch windows of batch job queues. See \ref lsb_queueinfo.
+ */
+ public String windows;
+
+ /**
+ * < The maximum number of job slots any user is allowed to use on this host.
+ */
+ public int userJobLimit;
+
+ /**
+ * < The maximum number of job slots that the host can process concurrently.
+ */
+ public int maxJobs;
+
+ /**
+ * < The number of job slots running or suspended on the host.
+ */
+ public int numJobs;
+
+ /**
+ * < The number of job slots running on the host.
+ */
+ public int numRUN;
+
+ /**
+ * < The number of job slots suspended by the batch daemon on the host.
+ */
+ public int numSSUSP;
+
+ /**
+ * < The number of job slots suspended by the job submitter or the LSF system administrator.
+ */
+ public int numUSUSP;
+
+ /**
+ * < The migration threshold in minutes after which a suspended job will be considered for migration.
+ */
+ public int mig;
+
+
+ /**
+ * < The host attributes; the bitwise inclusive OR of some of \ref host_attributes
+ */
+ public int attr;
+ /**
+ * \addtogroup host_attributes host_attributes
+ * The host attributes
+ */
+
+ /**
+ * < This host can checkpoint jobs
+ */
+ public static final int H_ATTR_CHKPNTABLE = 0x1;
+
+ /**
+ * < This host provides kernel support for checkpoint copy.
+ */
+ public static final int H_ATTR_CHKPNT_COPY = 0x2;
+
+ /**
+ * < The effective load of the host.
+ */
+ public FloatByReference realLoad;
+
+ /**
+ * < The number of job slots reserved by LSF for the PEND jobs.
+ */
+ public int numRESERVE;
+
+ /**
+ * < If attr has an H_ATTR_CHKPNT_COPY attribute, chkSig is set to the signal which triggers checkpoint and copy operation. Otherwise, chkSig is set to the signal which triggers checkpoint operation on the host
+ */
+ public int chkSig;
+
+
+ /**
+ * < Num of resource used by the consumer
+ */
+ public float cnsmrUsage;
+
+ /**
+ * < Num of resource used by the provider
+ */
+ public float prvdrUsage;
+
+ /**
+ * < Num of resource available for the consumer to use
+ */
+ public float cnsmrAvail;
+
+ /**
+ * < Num of resource available for the provider to use
+ */
+ public float prvdrAvail;
+
+ /**
+ * < Num maximum of resource available in total
+ */
+ public float maxAvail;
+
+ /**
+ * < The job exit rate threshold on the host
+ */
+ public float maxExitRate;
+
+ /**
+ * < Number of job exit rate on the host
+ */
+ public float numExitRate;
+
+ /**
+ * < AdminAction - host control message
+ */
+ public String hCtrlMsg;
+
+ }
+
+
+
+ /**
+ * \brief Host information condition entry.
+ */
+ public static class condHostInfoEnt extends Structure {
+ public static class ByReference extends condHostInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends condHostInfoEnt implements Structure.ByValue {}
+ public condHostInfoEnt() {}
+ public condHostInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Host name
+ */
+ public String name;
+
+
+ /**
+ * < How many hosts are in the ok status
+ */
+ public int howManyOk;
+
+ /**
+ * < How many hosts are in the busy status
+ */
+ public int howManyBusy;
+
+ /**
+ * < How many hosts are in the closed status
+ */
+ public int howManyClosed;
+
+ /**
+ * < How many hosts are in the full status
+ */
+ public int howManyFull;
+
+ /**
+ * < How many hosts are in the unreach status
+ */
+ public int howManyUnreach;
+
+ /**
+ * < How many hosts are in the unavail status
+ */
+ public int howManyUnavail;
+
+
+ /**
+ * < The status of each host in the host group
+ */
+ public Pointer /* hostInfoEnt.ByReference */ hostInfo;
+
+ }
+
+
+
+ public static class adjustParam extends Structure {
+ public static class ByReference extends adjustParam implements Structure.ByReference {}
+ public static class ByValue extends adjustParam implements Structure.ByValue {}
+ public adjustParam() {}
+ public adjustParam(Pointer p) { super(p); read(); }
+
+
+/* key name of share adjustment */
+ public String key;
+
+/* value of the key */
+ public float value;
+ }
+
+
+
+
+/* cpu time factor */
+ public static final int FAIR_ADJUST_CPU_TIME_FACTOR = 0;
+
+/* run time factor */
+ public static final int FAIR_ADJUST_RUN_TIME_FACTOR = 1;
+
+/* run job factor */
+ public static final int FAIR_ADJUST_RUN_JOB_FACTOR = 2;
+
+/* committed run time factor */
+ public static final int FAIR_ADJUST_COMMITTED_RUN_TIME_FACTOR = 3;
+
+/* enable hist run time */
+ public static final int FAIR_ADJUST_ENABLE_HIST_RUN_TIME = 4;
+
+/* cpu time of finished jobs with decay */
+ public static final int FAIR_ADJUST_HIST_CPU_TIME = 5;
+
+/* cpu time of finished jobs within decay */
+ public static final int FAIR_ADJUST_NEW_USED_CPU_TIME = 6;
+
+/* total time that job spend in RUN state */
+ public static final int FAIR_ADJUST_RUN_TIME = 7;
+
+/* historical run time of finished jobs */
+ public static final int FAIR_ADJUST_HIST_RUN_TIME = 8;
+
+/* committed run time of started jobs */
+ public static final int FAIR_ADJUST_COMMITTED_RUN_TIME = 9;
+
+/* number of job slots used by started jobs */
+ public static final int FAIR_ADJUST_NUM_START_JOBS = 10;
+
+/* number of reserved slots used by pending jobs */
+ public static final int FAIR_ADJUST_NUM_RESERVE_JOBS = 11;
+
+/* total amount of memory used by started jobs */
+ public static final int FAIR_ADJUST_MEM_USED = 12;
+
+/* average memory allocated per slot */
+ public static final int FAIR_ADJUST_MEM_ALLOCATED = 13;
+
+/* total number of fairshare adjustment key value pairs */
+ public static final int FAIR_ADJUST_KVPS_SUM = 14;
+
+ //public String[] FairAdjustPairArrayName = new String[FAIR_ADJUST_KVPS_SUM];
+
+ public static class shareAdjustPair extends Structure {
+ public static class ByReference extends shareAdjustPair implements Structure.ByReference {}
+ public static class ByValue extends shareAdjustPair implements Structure.ByValue {}
+ public shareAdjustPair() {}
+ public shareAdjustPair(Pointer p) { super(p); read(); }
+
+
+/* queue share account */
+ public static int SHAREACCTTYPEQUEUE = 0x01;
+
+/* host partition share account */
+ public static final int SHAREACCTTYPEHP = 0x02;
+
+/* SLA share account */
+ public static final int SHAREACCTTYPESLA = 0x04;
+
+/* type of share account*/
+ public int shareAcctType;
+
+/* name of the share holder that use the share */
+ public String holderName;
+
+/* name of the provider policy name(name of queue, host partition or SLA) */
+ public String providerName;
+
+/* number of share adjustment key value pair */
+ public int numPair;
+
+/* share adjustment key value pair */
+ public Pointer /* adjustParam.ByReference */ adjustParam;
+ }
+
+
+
+ // NOTE: Not in libbat
+ //public static native float fairshare_adjustment(shareAdjustPair shareAdjustPair1);
+
+/* For lsb_hostpartinfo() call */
+
+ /**
+ * \brief gets user information about host partitions.
+ */
+ public static class hostPartUserInfo extends Structure {
+ public static class ByReference extends hostPartUserInfo implements Structure.ByReference {}
+ public static class ByValue extends hostPartUserInfo implements Structure.ByValue {}
+ public hostPartUserInfo() {}
+ public hostPartUserInfo(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The user name or user group name. See \ref lsb_userinfo and \ref lsb_usergrpinfo
+ */
+ public String user;
+
+ /**
+ * < The number of shares assigned to the user or user group, as configured in the file lsb.hosts. (See lsb.hosts.)
+ */
+ public int shares;
+
+ /**
+ * < The priority of the user or user group to use the host partition. Bigger values represent higher priorities. Jobs belonging to the user or user group with the highest priority are considered first for dispatch when resources in the host partition are being contended for. In general, a user or user group with more shares, fewer numStartJobs and less histCpuTime has higher priority. The storage for the array of hostPartInfoEnt structures will be reused by the next call.
+ */
+ public float priority;
+
+ /**
+ * < The number of job slots belonging to the user or user group that are running or suspended in the host partition.
+ */
+ public int numStartJobs;
+
+ /**
+ * < The normalized CPU time accumulated in the host partition during the recent period by finished jobs belonging to the user or user group. The period may be configured in the file lsb.params (see lsb.params), with a default value of five (5) hours.
+ */
+ public float histCpuTime;
+
+ /**
+ * < The number of job slots that are reserved for the PEND jobs belonging to the user or user group in the host partition.
+ */
+ public int numReserveJobs;
+
+ /**
+ * < The time unfinished jobs spend in RUN state
+ */
+ public int runTime;
+
+ /**
+ * < The fairshare adjustment value from the fairshare plugin (libfairshareadjust.ByReference ). The adjustment is enabled and weighted by setting the value of FAIRSHARE_ADJUSTMENT_FACTOR in lsb.params.
+ */
+ public float shareAdjustment;
+ }
+
+
+
+/* For lsb_hostpartinfo() call */
+
+ /**
+ * \brief gets information entry about host partitions.
+ */
+ public static class hostPartInfoEnt extends Structure {
+ public static class ByReference extends hostPartInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends hostPartInfoEnt implements Structure.ByValue {}
+ public hostPartInfoEnt() {}
+ public hostPartInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The name of the host partition
+ */
+ public byte[] hostPart = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < A blank-separated list of names of hosts and host groups which are members of the host partition. The name of a host group has a '/' appended. see \ref lsb_hostgrpinfo.
+ */
+ public String hostList;
+
+ /**
+ * < The number of users in this host partition. i.e., the number of hostPartUserInfo structures.
+ */
+ public int numUsers;
+
+ /**
+ * < An array of hostPartUserInfo structures which hold information on users in this host partition.
+ */
+ public Pointer /* hostPartUserInfo.ByReference */ users;
+ }
+
+
+
+/* Library rappresentation of the share account */
+
+ /**
+ * \brief Library rappresentation of the share account
+ */
+ public static class shareAcctInfoEnt extends Structure {
+ public static class ByReference extends shareAcctInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends shareAcctInfoEnt implements Structure.ByValue {}
+ public shareAcctInfoEnt() {}
+ public shareAcctInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The user name or user group name. (See \ref lsb_userinfo and \ref lsb_usergrpinfo.)
+ */
+ public String shareAcctPath;
+
+ /**
+ * < The number of shares assigned to the user or user group, as configured in the file lsb.queues.
+ */
+ public int shares;
+
+ /**
+ * < The priority of the user or user group in the fairshare queue. Larger values represent higher priorities. Job belonging to the user or user group with the highest priority are considered first for dispatch in the fairshare queue. In general, a user or user group with more shares, fewer numStartJobs and less histCpuTime has higher priority.
+ */
+ public float priority;
+
+ /**
+ * < The number of job slots (belonging to the user or user group) that are running or suspended in the fairshare queue.
+ */
+ public int numStartJobs;
+
+ /**
+ * < The normalized CPU time accumulated in the fairshare queue by jobs belonging to the user or user group, over the time period configured in the file lsb.params. The default time period is 5 hours.
+ */
+ public float histCpuTime;
+
+ /**
+ * < The number of job slots that are reserved for the PEND jobs belonging to the user or user group in the host partition.
+ */
+ public int numReserveJobs;
+
+ /**
+ * < The time unfinished jobs spend in the RUN state.
+ */
+ public int runTime;
+
+ /**
+ * < The fairshare adjustment value from the fairshare plugin (libfairshareadjust.SOEXT). The adjustment is enabled and weighted by setting the value of FAIRSHARE_ADJUSTMENT_FACTOR in lsb.params.
+ */
+ public float shareAdjustment;
+ }
+
+
+
+/* boundaries and default value used by mbatchd for the maxJobId */
+ public static final int DEF_MAX_JOBID = 999999;
+ public static final int MAX_JOBID_LOW = 999999;
+ public static final int MAX_JOBID_HIGH = (LibLsf.INFINIT_INT - 1);
+
+
+/* default preemption wait time */
+ public static final int DEF_PREEMPTION_WAIT_TIME = 300;
+
+/* default number of hosts specified by -m */
+ public static final int DEF_MAX_ASKED_HOSTS = 512;
+
+/* For lsb_parameterinfo() call */
+
+ /**
+ * \brief The parameterInfo structure contains the following fields:
+ */
+ public static class parameterInfo extends Structure {
+ public static class ByReference extends parameterInfo implements Structure.ByReference {}
+ public static class ByValue extends parameterInfo implements Structure.ByValue {}
+ public parameterInfo() {}
+ public parameterInfo(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < DEFAULT_QUEUE: A blank_separated list of queue names for automatic queue selection.
+ */
+ public String defaultQueues;
+
+ /**
+ * < DEFAULT_HOST_SPEC: The host name or host model name used as the system default for scaling CPULIMIT and RUNLIMIT.
+ */
+ public String defaultHostSpec;
+
+ /**
+ * < MBD_SLEEP_TIME: The interval in seconds at which the mbatchd dispatches jobs.
+ */
+ public int mbatchdInterval;
+
+ /**
+ * < SBD_SLEEP_TIME: The interval in seconds at which the sbatchd suspends or resumes jobs.
+ */
+ public int sbatchdInterval;
+
+ /**
+ * < JOB_ACCEPT_INTERVAL: The interval at which a host accepts two successive jobs. (In units of SBD_SLEEP_TIME.)
+ */
+ public int jobAcceptInterval;
+
+ /**
+ * < MAX_RETRY: The maximum number of retries for dispatching a job.
+ */
+ public int maxDispRetries;
+
+ /**
+ * < MAX_SBD_FAIL: The maximum number of retries for reaching an sbatchd.
+ */
+ public int maxSbdRetries;
+
+ /**
+ * < PREEM_PERIOD: The interval in seconds for preempting jobs running on the same host.
+ */
+ public int preemptPeriod;
+
+ /**
+ * < CLEAN_PERIOD: The interval in seconds during which finished jobs are kept in core.
+ */
+ public int cleanPeriod;
+
+ /**
+ * < MAX_JOB_NUM: The maximum number of finished jobs that are logged in the current event file.
+ */
+ public int maxNumJobs;
+
+ /**
+ * < HIST_HOURS: The number of hours of resource consumption history used for fair share scheduling and scheduling within a host partition.
+ */
+ public float historyHours;
+
+ /**
+ * < PG_SUSP_IT: The interval a host must be idle before resuming a job suspended for excessive paging.
+ */
+ public int pgSuspendIt;
+
+ /**
+ * < The default project assigned to jobs.
+ */
+ public String defaultProject;
+
+ /**
+ * < Job submission retry interval
+ */
+ public int retryIntvl;
+
+ /**
+ * < For Cray NQS compatiblilty only. Used by LSF to get the NQS queue information
+ */
+ public int nqsQueuesFlags;
+
+ /**
+ * < nqsRequestsFlags
+ */
+ public int nqsRequestsFlags;
+
+ /**
+ * < The maximum number of times to attempt the preexecution command of a job from a remote cluster ( MultiCluster only)
+ */
+ public int maxPreExecRetry;
+
+ /**
+ * < Maximum number of pre-exec retry times for local cluster
+ */
+ public int localMaxPreExecRetry;
+
+ /**
+ * < Event watching Interval in seconds
+ */
+ public int eventWatchTime;
+
+ /**
+ * < Run time weighting factor for fairshare scheduling
+ */
+ public float runTimeFactor;
+
+ /**
+ * < Used for calcultion of the fairshare scheduling formula
+ */
+ public float waitTimeFactor;
+
+ /**
+ * < Job slots weighting factor for fairshare scheduling
+ */
+ public float runJobFactor;
+
+ /**
+ * < Default check interval
+ */
+ public int eEventCheckIntvl;
+
+ /**
+ * < sbatchd report every sbd_sleep_time
+ */
+ public int rusageUpdateRate;
+
+ /**
+ * < sbatchd updates jobs jRusage in mbatchd if more than 10% changes
+ */
+ public int rusageUpdatePercent;
+
+ /**
+ * < Time period to check for reconfig
+ */
+ public int condCheckTime;
+
+ /**
+ * < The maximum number of connections between master and slave batch daemons
+ */
+ public int maxSbdConnections;
+
+ /**
+ * < The interval for rescheduling jobs
+ */
+ public int rschedInterval;
+
+ /**
+ * < Max time mbatchd stays in scheduling routine, after which take a breather
+ */
+ public int maxSchedStay;
+
+ /**
+ * < During which load remains fresh
+ */
+ public int freshPeriod;
+
+ /**
+ * < The preemption behavior, GROUP_MAX, GROUP_JLP, USER_JLP, HOST_JLU,MINI_JOB, LEAST_RUN_TIME
+ */
+ public int preemptFor;
+
+ /**
+ * < Flags whether users can resume their jobs when suspended by the LSF administrator
+ */
+ public int adminSuspend;
+
+ /**
+ * < Flags to enable/disable normal user to create advance reservation
+ */
+ public int userReservation;
+
+ /**
+ * < CPU time weighting factor for fairshare scheduling
+ */
+ public float cpuTimeFactor;
+
+ /**
+ * < The starting month for a fiscal year
+ */
+ public int fyStart;
+
+ /**
+ * < The maximum number of jobs in a job array
+ */
+ public int maxJobArraySize;
+
+ /**
+ * < Replay period for exceptions, in seconds
+ */
+ public NativeLong exceptReplayPeriod;
+
+ /**
+ * < The interval to terminate a job
+ */
+ public int jobTerminateInterval;
+
+ /**
+ * < User level account mapping for remote jobs is disabled
+ */
+ public int disableUAcctMap;
+
+ /**
+ * < If set to TRUE, Project name for a job will be considerred when doing fairshare scheduling, i.e., as if user has submitted jobs using -G
+ */
+ public int enforceFSProj;
+
+ /**
+ * < Enforces the check to see if the invoker of bsub is in the specifed group when the -P option is used
+ */
+ public int enforceProjCheck;
+
+ /**
+ * < Run time for a job
+ */
+ public int jobRunTimes;
+
+ /**
+ * < Event table Job default interval
+ */
+ public int dbDefaultIntval;
+
+ /**
+ * < Event table Job Host Count
+ */
+ public int dbHjobCountIntval;
+
+ /**
+ * < Event table Job Queue Count
+ */
+ public int dbQjobCountIntval;
+
+ /**
+ * < Event table Job User Count
+ */
+ public int dbUjobCountIntval;
+
+ /**
+ * < Event table Job Resource Interval
+ */
+ public int dbJobResUsageIntval;
+
+ /**
+ * < Event table Resource Load Interval
+ */
+ public int dbLoadIntval;
+
+ /**
+ * < Event table Job Info
+ */
+ public int dbJobInfoIntval;
+
+ /**
+ * < Used with job dependency scheduling
+ */
+ public int jobDepLastSub;
+
+ /**
+ * < Used with job dependency scheduling, deprecated
+ */
+ public int maxJobNameDep;
+
+ /**
+ * < Select resources to be logged
+ */
+ public String dbSelectLoad;
+
+ /**
+ * < Job synchronizes its group status
+ */
+ public int jobSynJgrp;
+
+ /**
+ * < The batch jobs' temporary output directory
+ */
+ public String pjobSpoolDir;
+
+
+ /**
+ * < Maximal job priority defined for all users
+ */
+ public int maxUserPriority;
+
+ /**
+ * < Job priority is increased by the system dynamically based on waiting time
+ */
+ public int jobPriorityValue;
+
+ /**
+ * < Waiting time to increase Job priority by the system dynamically
+ */
+ public int jobPriorityTime;
+
+ /**
+ * < Enable internal statistical adjustment
+ */
+ public int enableAutoAdjust;
+
+ /**
+ * < Start to autoadjust when the user has this number of pending jobs
+ */
+ public int autoAdjustAtNumPend;
+
+ /**
+ * < If this number of jobs has been visited skip the user
+ */
+ public float autoAdjustAtPercent;
+
+ /**
+ * < Static shared resource update interval for the cluster actor
+ */
+ public int sharedResourceUpdFactor;
+
+ /**
+ * < Schedule job based on raw load info
+ */
+ public int scheRawLoad;
+
+ /**
+ * < The batch jobs' external storage for attached data
+ */
+ public String jobAttaDir;
+
+ /**
+ * < Maximum message number for each job
+ */
+ public int maxJobMsgNum;
+
+ /**
+ * < Maximum attached data size to be transferred for each message
+ */
+ public int maxJobAttaSize;
+
+ /**
+ * < The life time of a child MBD to serve queries in the MT way
+ */
+ public int mbdRefreshTime;
+
+ /**
+ * < The interval of the execution cluster updating the job's resource usage
+ */
+ public int updJobRusageInterval;
+
+ /**
+ * < The account to which all windows workgroup users are to be mapped
+ */
+ public String sysMapAcct;
+
+ /**
+ * < Dispatch delay internal
+ */
+ public int preExecDelay;
+
+ /**
+ * < Update duplicate event interval
+ */
+ public int updEventUpdateInterval;
+
+ /**
+ * < Resources are reserved for parallel jobs on a per-slot basis
+ */
+ public int resourceReservePerSlot;
+
+ /**
+ * < Maximum job id --- read from the lsb.params
+ */
+ public int maxJobId;
+
+ /**
+ * < Define a list of preemptable resource names
+ */
+ public String preemptResourceList;
+
+ /**
+ * < The preemption wait time
+ */
+ public int preemptionWaitTime;
+
+ /**
+ * < Maximum number of rollover lsb.acct files kept by mbatchd.
+ */
+ public int maxAcctArchiveNum;
+
+ /**
+ * < mbatchd Archive Interval
+ */
+ public int acctArchiveInDays;
+
+ /**
+ * < mbatchd Archive threshold
+ */
+ public int acctArchiveInSize;
+
+ /**
+ * < Committed run time weighting factor
+ */
+ public float committedRunTimeFactor;
+
+ /**
+ * < Enable the use of historical run time in the calculation of fairshare scheduling priority, Disable the use of historical run time in the calculation of fairshare scheduling priority
+ */
+ public int enableHistRunTime;
+
+/*#ifdef PS_SXNQS */
+/**< NQS resource usage update interval */
+/* public int nqsUpdateInterval;*/
+/*#endif */
+
+ /**
+ * < Open lease reclaim time
+ */
+ public int mcbOlmReclaimTimeDelay;
+
+ /**
+ * < Enable chunk job dispatch for jobs with CPU limit or run limits
+ */
+ public int chunkJobDuration;
+
+ /**
+ * < The interval for scheduling jobs by scheduler daemon
+ */
+ public int sessionInterval;
+
+ /**
+ * < The number of jobs per user per queue whose pending reason is published at the PEND_REASON_UPDATE_INTERVAL interval
+ */
+ public int publishReasonJobNum;
+
+ /**
+ * < The interval for publishing job pending reason by scheduler daemon
+ */
+ public int publishReasonInterval;
+
+ /**
+ * < Interval(in seconds) of pending reason publish for all jobs
+ */
+ public int publishReason4AllJobInterval;
+
+ /**
+ * < MC pending reason update interval (0 means no updates)
+ */
+ public int mcUpdPendingReasonInterval;
+
+ /**
+ * < MC pending reason update package size (0 means no limit)
+ */
+ public int mcUpdPendingReasonPkgSize;
+
+ /**
+ * < No preemption if the run time is greater than the value defined in here
+ */
+ public int noPreemptRunTime;
+
+ /**
+ * < No preemption if the finish time is less than the value defined in here
+ */
+ public int noPreemptFinishTime;
+
+ /**
+ * < mbatchd Archive Time
+ */
+ public String acctArchiveAt;
+
+ /**
+ * < Absolute run limit for job
+ */
+ public int absoluteRunLimit;
+
+ /**
+ * < The job exit rate duration
+ */
+ public int lsbExitRateDuration;
+
+ /**
+ * < The duration to trigger eadmin
+ */
+ public int lsbTriggerDuration;
+
+ /**
+ * < Maximum time for job information query commands (for example,with bjobs) to wait
+ */
+ public int maxJobinfoQueryPeriod;
+
+ /**
+ * < Job submission retrial interval for client
+ */
+ public int jobSubRetryInterval;
+
+ /**
+ * < System wide max pending jobs
+ */
+ public int pendingJobThreshold;
+
+
+ /**
+ * < Max number of concurrent query
+ */
+ public int maxConcurrentJobQuery;
+
+ /**
+ * < Min event switch time period
+ */
+ public int minSwitchPeriod;
+
+
+ /**
+ * < Condense pending reasons enabled
+ */
+ public int condensePendingReasons;
+
+ /**
+ * < Schedule Parallel jobs based on slots instead of CPUs
+ */
+ public int slotBasedParallelSched;
+
+ /**
+ * < Disable user job movement operations, like btop/bbot.
+ */
+ public int disableUserJobMovement;
+
+ /**
+ * < Detect and report idle jobs only after specified minutes.
+ */
+ public int detectIdleJobAfter;
+ public int useSymbolPriority;
+ /**
+ * < Use symbolic when specifing priority of symphony jobs/
+ * <p/>
+ * /**< Priority rounding for symphony jobs
+ */
+ public int JobPriorityRound;
+
+ /**
+ * < The mapping of the symbolic priority for symphony jobs
+ */
+ public String priorityMapping;
+
+ /**
+ * < Maximum number of subdirectories under LSB_SHAREDIR/cluster/logdir/info
+ */
+ public int maxInfoDirs;
+
+ /**
+ * < The minimum period of a child MBD to serve queries in the MT way
+ */
+ public int minMbdRefreshTime;
+
+ /**
+ * < Stop asking license to LS not due to lack license
+ */
+ public int enableStopAskingLicenses2LS;
+
+ /**
+ * < Expire time for finished job which will not taken into account when calculating queue fairshare priority
+ */
+ public int expiredTime;
+
+ /**
+ * < MBD child query processes will only run on the following CPUs
+ */
+ public String mbdQueryCPUs;
+
+ /**
+ * < The default application profile assigned to jobs
+ */
+ public String defaultApp;
+
+ /**
+ * < Enable or disable data streaming
+ */
+ public int enableStream;
+
+ /**
+ * < File to which lsbatch data is streamed
+ */
+ public String streamFile;
+
+ /**
+ * < File size in MB to which lsbatch data is streamed
+ */
+ public int streamSize;
+
+ /**
+ * < Sync up host status with master LIM is enabled
+ */
+ public int syncUpHostStatusWithLIM;
+
+ /**
+ * < Project schedulign default SLA
+ */
+ public String defaultSLA;
+
+ /**
+ * < EGO Enabled SLA scheduling timer period
+ */
+ public int slaTimer;
+
+ /**
+ * < EGO Enabled SLA scheduling time to live
+ */
+ public int mbdEgoTtl;
+
+ /**
+ * < EGO Enabled SLA scheduling connection timeout
+ */
+ public int mbdEgoConnTimeout;
+
+ /**
+ * < EGO Enabled SLA scheduling read timeout
+ */
+ public int mbdEgoReadTimeout;
+
+ /**
+ * < EGO Enabled SLA scheduling use MXJ flag
+ */
+ public int mbdUseEgoMXJ;
+
+ /**
+ * < EGO Enabled SLA scheduling reclaim by queue
+ */
+ public int mbdEgoReclaimByQueue;
+
+ /**
+ * < EGO Enabled SLA scheduling default velocity
+ */
+ public int defaultSLAvelocity;
+
+ /**
+ * < Type of host exit rate exception handling types: EXIT_RATE_TYPE
+ */
+ public String exitRateTypes;
+
+ /**
+ * < Type of host exit rate exception handling types: GLOBAL_EXIT_RATE
+ */
+ public float globalJobExitRate;
+
+ /**
+ * < Type of host exit rate exception handling types ENABLE_EXIT_RATE_PER_SLOT
+ */
+ public int enableJobExitRatePerSlot;
+
+ /**
+ * < Performance metrics monitor is enabled flag
+ */
+ public int enableMetric;
+
+ /**
+ * < Performance metrics monitor sample period flag
+ */
+ public int schMetricsSample;
+
+ /**
+ * < Used to bound: (1) factors, (2) weights, and (3) APS values
+ */
+ public float maxApsValue;
+
+ /**
+ * < Child mbatchd gets updated information about new jobs from the parent mbatchd
+ */
+ public int newjobRefresh;
+
+ /**
+ * < Job type to preempt, PREEMPT_JOBTYPE_BACKFILL, PREEMPT_JOBTYPE_EXCLUSIVE
+ */
+ public int preemptJobType;
+
+ /**
+ * < The default job group assigned to jobs
+ */
+ public String defaultJgrp;
+
+ /**
+ * < Max ratio between run limit and runtime estimation
+ */
+ public int jobRunlimitRatio;
+
+ /**
+ * < Enable the post-execution processing of the job to be included as part of the job flag
+ */
+ public int jobIncludePostproc;
+
+ /**
+ * < Timeout of post-execution processing
+ */
+ public int jobPostprocTimeout;
+
+ /**
+ * < The interval, in seconds, for updating the session scheduler status summary
+ */
+ public int sschedUpdateSummaryInterval;
+
+ /**
+ * < The number of completed tasks for updating the session scheduler status summary
+ */
+ public int sschedUpdateSummaryByTask;
+
+ /**
+ * < The maximum number of times a task can be requeued via requeue exit values
+ */
+ public int sschedRequeueLimit;
+
+ /**
+ * < The maximum number of times a task can be retried after a dispatch error
+ */
+ public int sschedRetryLimit;
+
+ /**
+ * < The maximum number of tasks that can be submitted in one session
+ */
+ public int sschedMaxTasks;
+
+ /**
+ * < The maximum run time of a single task
+ */
+ public int sschedMaxRuntime;
+
+ /**
+ * < The output directory for task accounting files
+ */
+ public String sschedAcctDir;
+
+ /**
+ * < If TRUE enable the job group automatic deletion functionality (default is FALSE).
+ */
+ public int jgrpAutoDel;
+
+ /**
+ * < Maximum number of job preempted times
+ */
+ public int maxJobPreempt;
+
+ /**
+ * < Maximum number of job re-queue times
+ */
+ public int maxJobRequeue;
+
+ /**
+ * < No preempt run time percent
+ */
+ public int noPreemptRunTimePercent;
+
+ /**
+ * < No preempt finish time percent
+ */
+ public int noPreemptFinishTimePercent;
+
+
+ /**
+ * < The reservation request being within JL/U.
+ */
+ public int slotReserveQueueLimit;
+
+ /**
+ * < Job accept limit percentage.
+ */
+ public int maxJobPercentagePerSession;
+
+ /**
+ * < The low priority job will use the slots freed by preempted jobs.
+ */
+ public int useSuspSlots;
+
+
+ /**
+ * < Maximum number of the backup stream.utc files
+ */
+ public int maxStreamFileNum;
+
+ /**
+ * < If enforced only admin can use bkill -r option
+ */
+ public int privilegedUserForceBkill;
+
+ /**
+ * < It controls the remote queue selection flow.
+ */
+ public int mcSchedulingEnhance;
+
+ /**
+ * < It controls update interval of the counters and other original data in MC implementation
+ */
+ public int mcUpdateInterval;
+
+ /**
+ * < Jobs run on only on hosts belonging to the intersection of the queue the job was submitted to, advance reservation hosts, and any hosts specified by bsub -m at the time of submission.
+ */
+ public int intersectCandidateHosts;
+
+ /**
+ * < Enforces the limitations of a single specified user group.
+ */
+ public int enforceOneUGLimit;
+
+ /**
+ * < Enable or disable logging runtime estimation exceeded event
+ */
+ public int logRuntimeESTExceeded;
+
+ /**
+ * < Compute unit types.
+ */
+ public String computeUnitTypes;
+
+ /**
+ * < Fairshare adjustment weighting factor
+ */
+ public float fairAdjustFactor;
+
+ /**
+ * < abs runtime and cputime for LSF simulator
+ */
+ public int simAbsoluteTime;
+
+ /**
+ * < switch for job exception enhancement
+ */
+ public int extendJobException;
+ }
+
+ /* parameterInfo */
+
+
+/* Bits for preemptFor parameter */
+ public static final int GROUP_MAX = 0x0001;
+ public static final int GROUP_JLP = 0x0002;
+ public static final int USER_JLP = 0x0004;
+ public static final int HOST_JLU = 0x0008;
+
+/* minimum of job */
+ public static final int MINI_JOB = 0x0010;
+
+/* least run time */
+ public static final int LEAST_RUN_TIME = 0x0020;
+
+/* optimal mini job */
+ public static final int OPTIMAL_MINI_JOB = 0x0040;
+
+/* Bits for mcSchedulingEnhance parameter */
+ public static final int RESOURCE_ONLY = 0x0001;
+ public static final int COUNT_PREEMPTABLE = 0x0002;
+ public static final int HIGH_QUEUE_PRIORITY = 0x0004;
+ public static final int PREEMPTABLE_QUEUE_PRIORITY = 0x0008;
+ public static final int PENDING_WHEN_NOSLOTS = 0x0010;
+
+/* options for bcaladd, bcalmod, bcaldel */
+ public static final int CAL_FORCE = 0x0001;
+
+/* Bits for preemptJobType parameter,
+* used to enable backfill and exclusive
+* preemption */
+ public static final int PREEMPT_JOBTYPE_EXCLUSIVE = 0x0001;
+ public static final int PREEMPT_JOBTYPE_BACKFILL = 0x0002;
+
+/* For lsb_calendarinfo() call */
+
+ /**
+ * \brief calendar Information Entry.
+ */
+ public static class calendarInfoEnt extends Structure {
+ public static class ByReference extends calendarInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends calendarInfoEnt implements Structure.ByValue {}
+ public calendarInfoEnt() {}
+ public calendarInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < A pointer to the name of the calendar.
+ */
+ public String name;
+
+ /**
+ * < A description string associated with the calendar.
+ */
+ public String desc;
+
+ /**
+ * < Calendar Expression
+ */
+ public String calExpr;
+
+ /**
+ * < User name
+ */
+ public String userName;
+
+ /**
+ * < Calendar status
+ */
+ public int status;
+
+ /**
+ * < For future use
+ */
+ public int options;
+
+ /**
+ * < Last time event of the calendar
+ */
+ public int lastDay;
+
+ /**
+ * < Next time event of the calendar
+ */
+ public int nextDay;
+
+ /**
+ * < Create Time
+ */
+ public NativeLong creatTime;
+
+ /**
+ * < Last Modify Time
+ */
+ public NativeLong lastModifyTime;
+
+ /**
+ * < Type of calendar, etc.
+ */
+ public int flags;
+ }
+
+
+
+ public static final int ALL_CALENDARS = 0x1;
+
+ public static final int EVE_HIST = 0x1;
+ public static final int EVENT_ACTIVE = 1;
+ public static final int EVENT_INACTIVE = 2;
+ public static final int EVENT_REJECT = 3;
+
+ public static final int EVENT_TYPE_UNKNOWN = 0;
+ public static final int EVENT_TYPE_LATCHED = 1;
+ public static final int EVENT_TYPE_PULSEALL = 2;
+ public static final int EVENT_TYPE_PULSE = 3;
+ public static final int EVENT_TYPE_EXCLUSIVE = 4;
+
+/* define event types */
+ public static final int EV_UNDEF = 0;
+ public static final int EV_FILE = 1;
+ public static final int EV_EXCEPT = 2;
+ public static final int EV_USER = 3;
+
+ public static class loadInfoEnt extends Structure {
+ public static class ByReference extends loadInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends loadInfoEnt implements Structure.ByValue {}
+ public loadInfoEnt() {}
+ public loadInfoEnt(Pointer p) { super(p); read(); }
+
+ public String hostName;
+ public int status;
+ public FloatByReference load;
+ }
+
+
+
+ public static class queuePairEnt extends Structure {
+ public static class ByReference extends queuePairEnt implements Structure.ByReference {}
+ public static class ByValue extends queuePairEnt implements Structure.ByValue {}
+ public queuePairEnt() {}
+ public queuePairEnt(Pointer p) { super(p); read(); }
+
+ public String local;
+ public String remote;
+ public int send;
+ public int status;
+ }
+
+
+
+ public static class rmbCluAppEnt extends Structure {
+ public static class ByReference extends rmbCluAppEnt implements Structure.ByReference {}
+ public static class ByValue extends rmbCluAppEnt implements Structure.ByValue {}
+ public rmbCluAppEnt() {}
+ public rmbCluAppEnt(Pointer p) { super(p); read(); }
+
+ public String name;
+ public String description;
+ }
+
+
+
+/* define 'cluster status' in lease model
+* for bclusters command
+ */
+
+
+/* disconnection */
+ public static final int LEASE_CLU_STAT_DISC = 1;
+
+/* policy is exchanged but no lease is signed */
+ public static final int LEASE_CLU_STAT_CONN = 2;
+
+/* there are leases signed between two clusters */
+ public static final int LEASE_CLU_STAT_OK = 3;
+ public static final int LEASE_CLU_STAT_NUMBER = 3;
+/* consumer cluster status in lease model */
+
+ public static class consumerCluEnt extends Structure {
+ public static class ByReference extends consumerCluEnt implements Structure.ByReference {}
+ public static class ByValue extends consumerCluEnt implements Structure.ByValue {}
+ public consumerCluEnt() {}
+ public consumerCluEnt(Pointer p) { super(p); read(); }
+
+
+/* consumer cluster name */
+ public String cluName;
+
+/* cluster status, Ref- 'cluster status' definitions */
+ public int status;
+ }
+
+
+/* provider cluster status in lease model */
+
+ public static class providerCluEnt extends Structure {
+ public static class ByReference extends providerCluEnt implements Structure.ByReference {}
+ public static class ByValue extends providerCluEnt implements Structure.ByValue {}
+ public providerCluEnt() {}
+ public providerCluEnt(Pointer p) { super(p); read(); }
+
+
+/* provider cluster name */
+ public String cluName;
+
+/* cluster status, Ref- 'cluster status' definitions */
+ public int status;
+ }
+
+
+/* for remote batch model, its definition is same as clusterInfoEnt*/
+
+ public static class rmbCluInfoEnt extends Structure {
+ public static class ByReference extends rmbCluInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends rmbCluInfoEnt implements Structure.ByValue {}
+ public rmbCluInfoEnt() {}
+ public rmbCluInfoEnt(Pointer p) { super(p); read(); }
+
+ public String cluster;
+ public int numPairs;
+ public Pointer /* queuePairEnt.ByReference */ queues;
+ public int numApps;
+ public Pointer /* rmbCluAppEnt.ByReference */ apps;
+ }
+
+
+
+/* for leasing model */
+
+ public static class leaseCluInfoEnt extends Structure {
+ public static class ByReference extends leaseCluInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends leaseCluInfoEnt implements Structure.ByValue {}
+ public leaseCluInfoEnt() {}
+ public leaseCluInfoEnt(Pointer p) { super(p); read(); }
+
+
+/* 1, import from all if "allremote" defined in lease queue*/
+ public int flags;
+
+/* the array size of consumer cluster array */
+ public int numConsumer;
+
+/* the consumer cluster array */
+ public Pointer /* consumerCluEnt.ByReference */ consumerClus;
+
+/* the array size of provider cluster array */
+ public int numProvider;
+
+/* the provider cluster array */
+ public Pointer /* providerCluEnt.ByReference */ providerClus;
+ }
+
+
+
+/* This is the old data structure, we
+* leave it here to keep backward compatibility.
+* It's definition is same as structure rmbCluInfoEnt.
+* It is to transfer cluster status between mbatchd with
+* old(4.x) bclusters command and old API-lsb_clusterinfo()
+ */
+
+ public static class clusterInfoEnt extends Structure {
+ public static class ByReference extends clusterInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends clusterInfoEnt implements Structure.ByValue {}
+ public clusterInfoEnt() {}
+ public clusterInfoEnt(Pointer p) { super(p); read(); }
+
+ public String cluster;
+ public int numPairs;
+ public Pointer /* queuePairEnt.ByReference */ queues;
+ public int numApps;
+ public Pointer /* rmbCluAppEnt.ByReference */ apps;
+ }
+
+
+/* the new data structure to transfer cluster status between mbatchd with
+* new(5.0) bclusters command and new API-lsb_clusterinfoEx()
+ */
+
+ public static class clusterInfoEntEx extends Structure {
+ public static class ByReference extends clusterInfoEntEx implements Structure.ByReference {}
+ public static class ByValue extends clusterInfoEntEx implements Structure.ByValue {}
+ public clusterInfoEntEx() {}
+ public clusterInfoEntEx(Pointer p) { super(p); read(); }
+
+
+/* cluster status related to remote batch*/
+ public rmbCluInfoEnt.ByReference rmbCluInfo;
+
+/* cluster status related to resource lease*/
+ public leaseCluInfoEnt leaseCluInfo;
+ }
+
+
+
+ public static class eventInfoEnt extends Structure {
+ public static class ByReference extends eventInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends eventInfoEnt implements Structure.ByValue {}
+ public eventInfoEnt() {}
+ public eventInfoEnt(Pointer p) { super(p); read(); }
+
+
+/* name of event */
+ public String name;
+
+/* one of ACTIVE or INACTIVE */
+ public int status;
+
+/* one of LATCHED, PULSE and EXCLUSIVE */
+ public int type;
+
+/* one of FILE, ALARM, USER */
+ public int eType;
+
+/* user who created the event */
+ public String userName;
+
+/* event's attributes sent back from eeventd */
+ public String attributes;
+
+/* number of expression dependent on the event */
+ public int numDependents;
+
+/* last time when eeventd sent back message */
+ public NativeLong updateTime;
+
+/* last dispatched job dependent on the event */
+ public long lastDisJob;
+
+/* the time when the last job was dispatched */
+ public NativeLong lastDisTime;
+ }
+
+
+ public static final int ALL_EVENTS = 0x01;
+
+ /**
+ * \addtogroup groupinfo_define groupinfo_define
+ * define options for \ref lsb_usergrpinfo and \ref lsb_hostgrpinfo calls
+ */
+
+ /**
+ * < User group
+ */
+ public static final int USER_GRP = 0x1;
+
+ /**
+ * < Host group
+ */
+ public static final int HOST_GRP = 0x2;
+
+ /**
+ * < Host part group
+ */
+ public static final int HPART_HGRP = 0x4;
+ /**
+ * \defgroup group_membership_option group_membership_option
+ * \ingroup groupinfo_define
+ * group membership options
+ */
+
+ /**
+ * < Expand the group membership recursively. That is, if a member of a group is itself a group, give the names of its members recursively, rather than its name, which is the default.
+ */
+ public static final int GRP_RECURSIVE = 0x8;
+
+ /**
+ * < Get membership of all groups.
+ */
+ public static final int GRP_ALL = 0x10;
+
+ /**
+ * < NQSQ_GRP
+ */
+ public static final int NQSQ_GRP = 0x20;
+
+ /**
+ * < Group shares
+ */
+ public static final int GRP_SHARES = 0x40;
+
+ /**
+ * < Dynamic group
+ */
+ public static final int DYNAMIC_GRP = 0x800;
+
+ /**
+ * < Group cu
+ */
+ public static final int GRP_CU = 0x1000;
+
+ /**
+ * \brief Structure for representing the shares assigned to a user group.
+ */
+ public static class userShares extends Structure {
+ public static class ByReference extends userShares implements Structure.ByReference {}
+ public static class ByValue extends userShares implements Structure.ByValue {}
+ public userShares() {}
+ public userShares(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < This can be a user or a keyword "default" or others
+ */
+ public String user;
+
+ /**
+ * < The number of shares assigned to the user
+ */
+ public int shares;
+ }
+
+
+
+
+ /**
+ * \brief group information entry.
+ */
+ public static class groupInfoEnt extends Structure {
+ public static class ByReference extends groupInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends groupInfoEnt implements Structure.ByValue {}
+ public groupInfoEnt() {}
+ public groupInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Group name
+ */
+ public String group;
+
+ /**
+ * < ASCII list of member names
+ */
+ public String memberList;
+
+ /**
+ * < ASCII list of admin member names
+ */
+ public String adminMemberList;
+
+ /**
+ * < The number of users with shares
+ */
+ public int numUserShares;
+
+ /**
+ * < The user shares rappresentation
+ */
+ public Pointer /* userShares.ByReference */ userShares;
+
+ /**
+ * \addtogroup group_define group_define
+ * group define statements
+ */
+
+ /**
+ * < Group output is in regular (uncondensed) format.
+ */
+ public static final int GRP_NO_CONDENSE_OUTPUT = 0x01;
+
+ /**
+ * < Group output is in condensed format.
+ */
+ public static final int GRP_CONDENSE_OUTPUT = 0x02;
+
+ /**
+ * < Group have regular expresion
+ */
+ public static final int GRP_HAVE_REG_EXP = 0x04;
+
+ /**
+ * < Group is a service class.
+ */
+ public static final int GRP_SERVICE_CLASS = 0x08;
+
+ /**
+ * < Group is a compute unit.
+ */
+ public static final int GRP_IS_CU = 0x10;
+
+ /**
+ * < Options.see \ref group_define
+ */
+ public int options;
+
+ /**
+ * < Host membership pattern
+ */
+ public String pattern;
+
+ /**
+ * < Negation membership pattern
+ */
+ public String neg_pattern;
+
+ /**
+ * < Compute unit type
+ */
+ public int cu_type;
+ }
+
+
+
+ /**
+ * \brief run job request.
+ */
+ public static class runJobRequest extends Structure {
+ public static class ByReference extends runJobRequest implements Structure.ByReference {}
+ public static class ByValue extends runJobRequest implements Structure.ByValue {}
+ public runJobRequest() {}
+ public runJobRequest(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Jobid of the requested job
+ */
+ public long jobId;
+
+ /**
+ * < The number of hosts
+ */
+ public int numHosts;
+
+ /**
+ * < Vector of hostnames
+ */
+ public Pointer hostname;
+ /**
+ * \addtogroup runjob_option runjob_option
+ * Options used for lsb_runjob:
+ */
+
+
+ /**
+ * < Normal jobs
+ */
+ public static final int RUNJOB_OPT_NORMAL = 0x01;
+
+ /**
+ * < Nostop jobs
+ */
+ public static final int RUNJOB_OPT_NOSTOP = 0x02;
+
+ /**
+ * < Pending jobs only, no finished jobs
+ */
+ public static final int RUNJOB_OPT_PENDONLY = 0x04;
+
+ /**
+ * < Check point job only, from beginning
+ */
+ public static final int RUNJOB_OPT_FROM_BEGIN = 0x08;
+
+ /**
+ * < brun to use free CPUs only
+ */
+ public static final int RUNJOB_OPT_FREE = 0x10;
+
+ /**
+ * < brun ignoring rusage
+ */
+ public static final int RUNJOB_OPT_IGNORE_RUSAGE = 0x20;
+
+ /**
+ * < Run job request options, see \ref runjob_option
+ */
+ public int options;
+
+ /**
+ * < Vector of number of slots per host
+ */
+ public IntByReference slots;
+ }
+
+
+
+ /**
+ * \addtogroup external_msg_processing external_msg_processing
+ * options for \ref lsb_readjobmsg call
+ */
+
+ /**
+ * \defgroup external_msg_post external_msg_post
+ * options specifying if the message has an attachment to be posted
+ */
+
+ /**
+ * < Post the external job message. There is no attached data file.
+ */
+ public static final int EXT_MSG_POST = 0x01;
+
+ /**
+ * < Post the external job message and data file posted to the job.
+ */
+ public static final int EXT_ATTA_POST = 0x02;
+
+ /**
+ * <Read the external job message. There is no attached data file.
+ */
+ public static final int EXT_MSG_READ = 0x04;
+
+ /**
+ * < Read the external job message and data file posted to the job.If there is no data file attached, the error message "The attached data of the message is not available" is displayed, and the external job message is displayed.
+ */
+ public static final int EXT_ATTA_READ = 0x08;
+
+ /**
+ * < Replay the external message
+ */
+ public static final int EXT_MSG_REPLAY = 0x10;
+
+ /**
+ * < Post the external job noevent message
+ */
+ public static final int EXT_MSG_POST_NOEVENT = 0x20;
+
+
+ /**
+ * \brief structure jobExternalMsgReq contains the information required to
+ * define an external message of a job.
+ */
+ public static class jobExternalMsgReq extends Structure {
+ public static class ByReference extends jobExternalMsgReq implements Structure.ByReference {}
+ public static class ByValue extends jobExternalMsgReq implements Structure.ByValue {}
+ public jobExternalMsgReq() {}
+ public jobExternalMsgReq(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Specifies if the message has an attachment to be read.<lsf/lsbatch.h> defines the following flags constructed from bits. These flags correspond to options.\n EXT_MSG_READ\n Read the external job message. There is no attached data file.\n EXT_ATTA_READ\n Read the external job message and data file posted to the job.\n If there is no data file attached, the error message "The attached data of the message is not available" is displayed, and the external job message is displayed.
+ */
+ public int options;
+
+ /**
+ * < The system generated job Id of the job.
+ */
+ public long jobId;
+
+ /**
+ * < The name of the job if jobId is undefined (<=0)
+ */
+ public String jobName;
+
+ /**
+ * < The message index. A job can have more than one message. Use msgIdx in an array to index messages.
+ */
+ public int msgIdx;
+
+ /**
+ * < Text description of the msg
+ */
+ public String desc;
+
+ /**
+ * < The userId of the author of the message.
+ */
+ public int userId;
+
+ /**
+ * < The size of the data file. If no data file is attached, the size is 0.
+ */
+ public NativeLong dataSize;
+
+ /**
+ * < The time the author posted the message.
+ */
+ public NativeLong postTime;
+
+ /**
+ * < The author of the message.
+ */
+ public String userName;
+ }
+
+
+
+ /**
+ * \addtogroup ext_data_status ext_data_status
+ */
+
+ /**
+ * < Transferring the message's data file.
+ */
+ public static final int EXT_DATA_UNKNOWN = 0;
+
+ /**
+ * < The message does not have an attached data file.
+ */
+ public static final int EXT_DATA_NOEXIST = 1;
+
+ /**
+ * < The message's data file is available.
+ */
+ public static final int EXT_DATA_AVAIL = 2;
+
+ /**
+ * < The message's data file is corrupt.
+ */
+ public static final int EXT_DATA_UNAVAIL = 3;
+
+ /**
+ * \brief structure jobExternalMsgReply contains the information required to
+ * define an external message reply.
+ */
+ public static class jobExternalMsgReply extends Structure {
+ public static class ByReference extends jobExternalMsgReply implements Structure.ByReference {}
+ public static class ByValue extends jobExternalMsgReply implements Structure.ByValue {}
+ public jobExternalMsgReply() {}
+ public jobExternalMsgReply(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The system generated job Id of the job associated with the message.
+ */
+ public long jobId;
+
+ /**
+ * < The message index. A job can have more than one message. Use msgIdx in an array to index messages.
+ */
+ public int msgIdx;
+
+ /**
+ * < The message you want to read.
+ */
+ public String desc;
+
+ /**
+ * < The user Id of the author of the message.
+ */
+ public int userId;
+
+ /**
+ * < The size of the data file attached. If no data file is attached, the size is 0.
+ */
+ public NativeLong dataSize;
+
+ /**
+ * < The time the message was posted.
+ */
+ public NativeLong postTime;
+
+ /**
+ * < The status of the attached data file. The status of the data file can be one of the following:\n EXT_DATA_UNKNOWN\n Transferring the message's data file.\n EXT_DATA_NOEXIST\n The message does not have an attached data file.\n EXT_DATA_AVAIL\n The message's data file is available. \n EXT_DATA_UNAVAIL\n The message's data file is corrupt.
+ */
+ public int dataStatus;
+
+ /**
+ * < The author of the msg
+ */
+ public String userName;
+ }
+
+
+
+
+ /**
+ * Data structures representing the symphony job status update request.
+ */
+ public static class symJobInfo extends Structure {
+ public static class ByReference extends symJobInfo implements Structure.ByReference {}
+ public static class ByValue extends symJobInfo implements Structure.ByValue {}
+ public symJobInfo() {}
+ public symJobInfo(Pointer p) { super(p); read(); }
+
+
+/* the service parititon that SSM works for */
+ public String partition;
+
+/* the priority of the symphony job */
+ public int priority;
+
+/* the full name that indicates the job relationship */
+ public String jobFullName;
+
+/* the auxiliary description to help updating command info */
+ public String auxCmdDesc;
+
+/* the auxiliary description to help updating job description info */
+ public String auxJobDesc;
+ }
+
+
+
+ public static class symJobStatus extends Structure {
+ public static class ByReference extends symJobStatus implements Structure.ByReference {}
+ public static class ByValue extends symJobStatus implements Structure.ByValue {}
+ public symJobStatus() {}
+ public symJobStatus(Pointer p) { super(p); read(); }
+
+
+/* text description of the symphony job status */
+ public String desc;
+ }
+
+
+
+ public static class symJobProgress extends Structure {
+ public static class ByReference extends symJobProgress implements Structure.ByReference {}
+ public static class ByValue extends symJobProgress implements Structure.ByValue {}
+ public symJobProgress() {}
+ public symJobProgress(Pointer p) { super(p); read(); }
+
+
+/* text description of the symphony job progress */
+ public String desc;
+ }
+
+
+
+
+ public static class symJobStatusUpdateReq extends Structure {
+ public static class ByReference extends symJobStatusUpdateReq implements Structure.ByReference {}
+ public static class ByValue extends symJobStatusUpdateReq implements Structure.ByValue {}
+ public symJobStatusUpdateReq() {}
+ public symJobStatusUpdateReq(Pointer p) { super(p); read(); }
+
+
+/* the job to be update info into MBD */
+ public long jobId;
+
+ public static final int SYM_JOB_UPDATE_NONE = 0x0;
+ public static final int SYM_JOB_UPDATE_INFO = 0x1;
+ public static final int SYM_JOB_UPDATE_STATUS = 0x2;
+ public static final int SYM_JOB_UPDATE_PROGRESS = 0x4;
+
+/* the option to update the info */
+ public int bitOption;
+ public symJobInfo info;
+ public int numOfJobStatus;
+ public Pointer /* symJobStatus.ByReference */ status;
+ public symJobProgress progress;
+ }
+
+
+
+ public static class symJobStatusUpdateReqArray extends Structure {
+ public static class ByReference extends symJobStatusUpdateReqArray implements Structure.ByReference {}
+ public static class ByValue extends symJobStatusUpdateReqArray implements Structure.ByValue {}
+ public symJobStatusUpdateReqArray() {}
+ public symJobStatusUpdateReqArray(Pointer p) { super(p); read(); }
+
+ public int numOfJobReq;
+ public Pointer /* symJobStatusUpdateReq.ByReference */ symJobReqs;
+ }
+
+
+
+
+ /**
+ * Data structures representing the symphony job status update reply.
+ */
+
+ public static class symJobUpdateAck extends Structure {
+ public static class ByReference extends symJobUpdateAck implements Structure.ByReference {}
+ public static class ByValue extends symJobUpdateAck implements Structure.ByValue {}
+ public symJobUpdateAck() {}
+ public symJobUpdateAck(Pointer p) { super(p); read(); }
+
+ public static int SYM_UPDATE_ACK_OK = 0;
+ public static final int SYM_UPDATE_ACK_ERR = 1;
+ public int ackCode;
+
+/* text description of job info update acknowledgement */
+ public String desc;
+ }
+
+
+
+ public static class symJobStatusUpdateReply extends Structure {
+ public static class ByReference extends symJobStatusUpdateReply implements Structure.ByReference {}
+ public static class ByValue extends symJobStatusUpdateReply implements Structure.ByValue {}
+ public symJobStatusUpdateReply() {}
+ public symJobStatusUpdateReply(Pointer p) { super(p); read(); }
+
+
+/* the job to be update info into MBD */
+ public long jobId;
+ public static final int SYM_UPDATE_INFO_IDX = 0;
+ public static final int SYM_UPDATE_STATUS_IDX = 1;
+ public static final int SYM_UPDATE_PROGRESS_IDX = 2;
+ public static final int NUM_SYM_UPDATE_ACK = 3;
+ public symJobUpdateAck[] acks = new symJobUpdateAck[NUM_SYM_UPDATE_ACK];
+ }
+
+
+
+ public static class symJobStatusUpdateReplyArray extends Structure {
+ public static class ByReference extends symJobStatusUpdateReplyArray implements Structure.ByReference {}
+ public static class ByValue extends symJobStatusUpdateReplyArray implements Structure.ByValue {}
+ public symJobStatusUpdateReplyArray() {}
+ public symJobStatusUpdateReplyArray(Pointer p) { super(p); read(); }
+
+ public int numOfJobReply;
+ public Pointer /* symJobStatusUpdateReply.ByReference */ symJobReplys;
+ }
+
+
+
+
+/* Data structure representing the job array requeue operation.
+* o jobId is the Lsbatch id of the job array to be requeued
+* o status is the desired requeue status of the job, by default
+* it is JOB_STAT_PEND, or user specified JOB_STAT_PSUSP
+* o options specifies the status of the array elements that have
+* to be requeued.
+*
+* The function that operates on the data is lsb_requeuejob()
+ */
+
+ /**
+ * \addtogroup requeuejob_options requeuejob_options
+ * define statements used by \ref lsb_requeuejob.
+ */
+
+ /**
+ * < Requeues jobs that have finished running. Jobs that have exited are not re-run. Equivalent to brequeue -d command line option.
+ */
+ public static final int REQUEUE_DONE = 0x1;
+
+ /**
+ * < Requeues jobs that have exited. Finished jobs are not re-run. Equivalent to brequeue -e command line option.
+ */
+ public static final int REQUEUE_EXIT = 0x2;
+
+ /**
+ * < Requeues running jobs and puts them in PEND state. Equivalent to brequeue -r command line option.
+ */
+ public static final int REQUEUE_RUN = 0x4;
+
+ /**
+ * \brief requeued job
+ */
+ public static class jobrequeue extends Structure {
+ public static class ByReference extends jobrequeue implements Structure.ByReference {}
+ public static class ByValue extends jobrequeue implements Structure.ByValue {}
+ public jobrequeue() {}
+ public jobrequeue(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Specifies the jobid of a single job or an array of jobs.
+ */
+ public long jobId;
+
+ /**
+ * < Specifies the lsbatch status of the requeued job after it has been requeued. The job status can be JOB_STAT_PEND or JOB_STATE_PSUSP. The default status is JOB_STAT_PEND.
+ */
+ public int status;
+
+ /**
+ * < Specifies the array elements to be requeued. see \ref requeuejob_options
+ */
+ public int options;
+ }
+
+
+
+ public static class requeueEStruct extends Structure {
+ public static class ByReference extends requeueEStruct implements Structure.ByReference {}
+ public static class ByValue extends requeueEStruct implements Structure.ByValue {}
+ public requeueEStruct() {}
+ public requeueEStruct(Pointer p) { super(p); read(); }
+
+
+/* requeue type: normal, exclude, other, prefer_other, etc. */
+ public int type;
+
+/* requeue type: normal - as in 2.2 */
+ public static final int RQE_NORMAL = 0;
+
+/* requeue type: exclude */
+ public static final int RQE_EXCLUDE = 1;
+
+/* indicate the end of the list */
+ public static final int RQE_END = 255;
+
+/* requeue exit value */
+ public int value;
+
+/* requeue interval */
+ public int interval;
+ }
+
+
+
+ public static class requeue extends Structure {
+ public static class ByReference extends requeue implements Structure.ByReference {}
+ public static class ByValue extends requeue implements Structure.ByValue {}
+ public requeue() {}
+ public requeue(Pointer p) { super(p); read(); }
+
+ public int numReqValues;
+ public Pointer /* requeueEStruct.ByReference */ reqValues;
+ }
+
+
+
+/* The Service Level Agreement in LSF
+ */
+
+
+/* This is the library representation of the
+* service class.
+ */
+
+ public static class serviceClass extends Structure {
+ public static class ByReference extends serviceClass implements Structure.ByReference {}
+ public static class ByValue extends serviceClass implements Structure.ByValue {}
+ public serviceClass() {}
+ public serviceClass(Pointer p) { super(p); read(); }
+
+
+/* SLA name */
+ public String name;
+
+/* SLA priority */
+ public float priority;
+
+/* The number of goals */
+ public int ngoals;
+
+/* The array of goals */
+ public Pointer /* objective.ByReference */ goals;
+
+/* Users allowed to use the SLA */
+ public String userGroups;
+
+/* SLA description */
+ public String description;
+
+/* SLA control action */
+ public String controlAction;
+
+/* Finished jobs per CLEAN_PERIOD */
+ public float throughput;
+
+/* Job counters */
+ public int[] counters = new int[NUM_JGRP_COUNTERS + 1];
+
+/* project scheduling enabled sla */
+ public String consumer;
+
+/* SLA EGO control parameters */
+ public slaControl.ByReference ctrl;
+
+/* SLA EGO control parameters */
+ public slaControlExt.ByReference ctrlExt;
+ }
+
+
+
+/* This is the library representation of the
+* Service Level Objective.
+ */
+
+ public static final int GOAL_WINDOW_OPEN = 0x1;
+ public static final int GOAL_WINDOW_CLOSED = 0x2;
+ public static final int GOAL_ONTIME = 0x4;
+ public static final int GOAL_DELAYED = 0x8;
+ public static final int GOAL_DISABLED = 0x10;
+
+/* Enumerate all the possible performance goals
+* for a service class.
+ */
+
+ public static interface objectives {
+ public static int GOAL_DEADLINE = 0;
+ public static int GOAL_VELOCITY = 1;
+ public static int GOAL_THROUGHPUT = 2;
+ }
+
+
+
+/* The objective of a goal, also called SLO, is represented
+* by this data structure.
+ */
+
+ public static class objective extends Structure {
+ public static class ByReference extends objective implements Structure.ByReference {}
+ public static class ByValue extends objective implements Structure.ByValue {}
+ public objective() {}
+ public objective(Pointer p) { super(p); read(); }
+
+
+/* goal specs from lsb.serviceclasses */
+ public String spec;
+
+/* goal type */
+ public int type;
+
+/* the state of the goal OnTime || Delayed */
+ public int state;
+
+/* the configured value */
+ public int goal;
+
+/* the actual value */
+ public int actual;
+
+/* the optimum value */
+ public int optimum;
+
+/* the minimum value */
+ public int minimum;
+ }
+
+
+
+/* Control parameters for SLA management of hosts belonging
+* to the EGO cluster. The control parameters are for each
+* SLA that gets its hosts from EGO.
+ */
+
+ public static class slaControl extends Structure {
+ public static class ByReference extends slaControl implements Structure.ByReference {}
+ public static class ByValue extends slaControl implements Structure.ByValue {}
+ public slaControl() {}
+ public slaControl(Pointer p) { super(p); read(); }
+
+
+/* sla name */
+ public String sla;
+
+/* EGO consumer the sla is mapped to */
+ public String consumer;
+
+/* timeout for returning hosts to EGO */
+ public int maxHostIdleTime;
+
+/* timeout left before EGO forcefully reclaims */
+ public int recallTimeout;
+
+/* number of hosts beign recalled */
+ public int numHostRecalled;
+
+/* EGO resource requirement */
+ public String egoResReq;
+ }
+
+
+
+ public static class slaControlExt extends Structure {
+ public static class ByReference extends slaControlExt implements Structure.ByReference {}
+ public static class ByValue extends slaControlExt implements Structure.ByValue {}
+ public slaControlExt() {}
+ public slaControlExt(Pointer p) { super(p); read(); }
+
+
+/* whether exclusive allocation */
+ public int allocflags;
+
+/* tile parameter */
+ public int tile;
+ }
+
+
+
+/* Application Encapsulation in LSF
+*
+* This is the library representation of the
+* application.
+ */
+
+ public static class appInfoEnt extends Structure {
+ public static class ByReference extends appInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends appInfoEnt implements Structure.ByValue {}
+ public appInfoEnt() {}
+ public appInfoEnt(Pointer p) { super(p); read(); }
+
+
+/* app name */
+ public String name;
+
+/* app description */
+ public String description;
+
+/* num of total jobs */
+ public int numJobs;
+
+/* num of pending slots */
+ public int numPEND;
+
+/* num of running slots */
+ public int numRUN;
+
+/* num of suspend slots */
+ public int numSSUSP;
+
+/* num of ususp slots */
+ public int numUSUSP;
+
+/* reserved job slots */
+ public int numRESERVE;
+
+/* app attributes */
+ public int aAttrib;
+
+/* number of jobs in one chunk */
+ public int chunkJobSize;
+
+/* requeue exit values */
+ public String requeueEValues;
+
+/* success exit values */
+ public String successEValues;
+
+/* app pre execution */
+ public String preCmd;
+
+/* app post execution */
+ public String postCmd;
+
+/* Job starter command(s) */
+ public String jobStarter;
+
+/* suspend action command */
+ public String suspendActCmd;
+
+/* resume action command */
+ public String resumeActCmd;
+
+/* terimate action command */
+ public String terminateActCmd;
+
+/*memory limit level type */
+ public int memLimitType;
+
+/* LSF resource limits (soft)*/
+ public int[] defLimits = new int[LibLsf.LSF_RLIM_NLIMITS];
+
+/* host spec from CPULIMIT or RUNLIMIT */
+ public String hostSpec;
+
+/* resource requirement string */
+ public String resReq;
+
+/* maximal processor limit */
+ public int maxProcLimit;
+
+/* default processor limit */
+ public int defProcLimit;
+
+/* minimal processor limit */
+ public int minProcLimit;
+
+/* estimated run time */
+ public int runTime;
+
+/* include postproc as part of job */
+ public int jobIncludePostProc;
+
+/* time window for postproc */
+ public int jobPostProcTimeOut;
+
+/* remote task gone action */
+ public String rTaskGoneAction;
+
+/* pathname of pjob env script */
+ public String djobEnvScript;
+
+/* DJOB rusage interval */
+ public int djobRuInterval;
+
+/* DJOB heartbeat interval */
+ public int djobHbInterval;
+
+/* DJOB communication fail action */
+ public String djobCommfailAction;
+
+/* disable Distributed Application Framework */
+ public int djobDisabled;
+
+/* grace period (in seconds) before terminating tasks when a job shrinks*/
+ public int djobResizeGracePeriod;
+
+/* chkpnt directory */
+ public String chkpntDir;
+
+/* chlpnt method */
+ public String chkpntMethod;
+
+/* chkpnt period */
+ public int chkpntPeriod;
+
+/* initial chkpnt period */
+ public int initChkpntPeriod;
+
+/* migration threshold */
+ public int migThreshold;
+
+/* maximum number of job preempted times */
+ public int maxJobPreempt;
+
+/* maximum number of pre-exec retry times */
+ public int maxPreExecRetry;
+
+/* maximum number of pre-exec retry times for local cluster */
+ public int localMaxPreExecRetry;
+
+/* maximum number of job re-queue times */
+ public int maxJobRequeue;
+
+/* no preempt run time */
+ public int noPreemptRunTime;
+
+/* no preempt finish time */
+ public int noPreemptFinishTime;
+
+/* no preempt run time percent */
+ public int noPreemptRunTimePercent;
+
+/* no preempt finish time percent */
+ public int noPreemptFinishTimePercent;
+
+/* use Linux-PAM */
+ public int usePam;
+
+/* processor binding options */
+ public int bindingOption;
+
+/* persistent same hosts and same order */
+ public int persistHostOrder;
+
+/* job resize notification cmd */
+ public String resizeNotifyCmd;
+ }
+
+
+
+/* application attributes
+ */
+
+/* rerunnable application */
+ public static final int A_ATTRIB_RERUNNABLE = 0x01;
+
+/* non rerunnable application */
+ public static final int A_ATTRIB_NONRERUNNABLE = 0x02;
+
+/* default application */
+ public static final int A_ATTRIB_DEFAULT = 0x04;
+
+/* runtime is absolute */
+ public static final int A_ATTRIB_ABS_RUNLIMIT = 0x08;
+
+/* process binding application */
+ public static final int A_ATTRIB_JOBBINDING = 0x10;
+
+/* process binding application */
+ public static final int A_ATTRIB_NONJOBBINDING = 0x20;
+
+/* checkpointable application */
+ public static final int A_ATTRIB_CHKPNT = 0x40;
+
+/* Job can be resizable manually */
+ public static final int A_ATTRIB_RESIZABLE = 0x80;
+
+/* Job can be resized automatically */
+ public static final int A_ATTRIB_AUTO_RESIZABLE = 0x100;
+
+
+/* processor binding options */
+ public static final int BINDING_OPTION_BALANCE = 0x1;
+ public static final int BINDING_OPTION_PACK = 0x2;
+ public static final int BINDING_OPTION_ANY = 0x4;
+ public static final int BINDING_OPTION_USER = 0x8;
+ public static final int BINDING_OPTION_USER_CPU_LIST = 0x10;
+ public static final int BINDING_OPTION_NONE = 0x20;
+
+ /**
+ * \addtogroup movejob_options movejob_options
+ * options for \ref lsb_movejob call
+ */
+
+ /**
+ * < To top
+ */
+ public static final int TO_TOP = 1;
+
+ /**
+ * < To bottom
+ */
+ public static final int TO_BOTTOM = 2;
+
+ /**
+ * \addtogroup queue_ctrl_option queue_ctrl_option
+ * options for \ref lsb_queuecontrol call
+ */
+
+ /**
+ * < Open the queue to accept jobs.
+ */
+ public static final int QUEUE_OPEN = 1;
+
+ /**
+ * < Close the queue so it will not accept jobs.
+ */
+ public static final int QUEUE_CLOSED = 2;
+
+ /**
+ * < Activate the queue to dispatch jobs.
+ */
+ public static final int QUEUE_ACTIVATE = 3;
+
+ /**
+ * < Inactivate the queue so it will not dispatch jobs.
+ */
+ public static final int QUEUE_INACTIVATE = 4;
+
+ /**
+ * < Clean the queue
+ */
+ public static final int QUEUE_CLEAN = 5;
+
+ /**
+ * \brief The structure of queueCtrlReq
+ */
+ public static class queueCtrlReq extends Structure {
+ public static class ByReference extends queueCtrlReq implements Structure.ByReference {}
+ public static class ByValue extends queueCtrlReq implements Structure.ByValue {}
+ public queueCtrlReq() {}
+ public queueCtrlReq(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The name of the queue to be controlled.
+ */
+ public String queue;
+
+ /**
+ * < Operations to be applied, for example, QUEUE_OPEN. You can refer to \ref queue_ctrl_option for more options.
+ */
+ public int opCode;
+
+ /**
+ * < The message attached by the admin
+ */
+ public String message;
+ }
+
+
+
+/* options for lsb_hostcontrol() call */
+ /**
+ * \addtogroup host_ctrl_option host_ctrl_option
+ * options operations to be applied
+ */
+
+ /**
+ * < Opens the host to accept jobs.
+ */
+ public static final int HOST_OPEN = 1;
+
+ /**
+ * < Closes the host so that no jobs can be dispatched to it.
+ */
+ public static final int HOST_CLOSE = 2;
+
+ /**
+ * < Restarts sbatchd on the host. sbatchd will receive a request from mbatchd and re-execute. This permits the sbatchd binary to be updated. This operation fails if no sbatchd is running on the specified host.
+ */
+ public static final int HOST_REBOOT = 3;
+
+ /**
+ * < The sbatchd on the host will exit.
+ */
+ public static final int HOST_SHUTDOWN = 4;
+
+ /**
+ * < Used for closing leased host on the submission cluster
+ */
+ public static final int HOST_CLOSE_REMOTE = 5;
+
+ /**
+ * \brief Host control request.
+ */
+ public static class hostCtrlReq extends Structure {
+ public static class ByReference extends hostCtrlReq implements Structure.ByReference {}
+ public static class ByValue extends hostCtrlReq implements Structure.ByValue {}
+ public hostCtrlReq() {}
+ public hostCtrlReq(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The host to be controlled. If host is null, the local host is assumed.
+ */
+ public String host;
+
+ /**
+ * < Operations to be applied in \ref host_ctrl_option.
+ */
+ public int opCode;
+
+ /**
+ * < Message attached by the administrator.
+ */
+ public String message;
+ }
+
+
+
+/* options for lsb_hgcontrol() call */
+ public static final int HGHOST_ADD = 1;
+ public static final int HGHOST_DEL = 2;
+
+ public static class hgCtrlReq extends Structure {
+ public static class ByReference extends hgCtrlReq implements Structure.ByReference {}
+ public static class ByValue extends hgCtrlReq implements Structure.ByValue {}
+ public hgCtrlReq() {}
+ public hgCtrlReq(Pointer p) { super(p); read(); }
+
+ public int opCode;
+ public String grpname;
+ public int numhosts;
+ public Pointer hosts;
+ public String message;
+ }
+
+
+
+ public static class hgCtrlReply extends Structure {
+ public static class ByReference extends hgCtrlReply implements Structure.ByReference {}
+ public static class ByValue extends hgCtrlReply implements Structure.ByValue {}
+ public hgCtrlReply() {}
+ public hgCtrlReply(Pointer p) { super(p); read(); }
+
+ public int numsucc;
+ public int numfail;
+ public Pointer succHosts;
+ public Pointer failHosts;
+ public IntByReference failReasons;
+ }
+
+
+
+/* options for lsb_reconfig() call */
+ /**
+ * \addtogroup mbd_operation mbd_operation
+ * options for \ref lsb_reconfig call
+ */
+
+ /**
+ * < mbatchd restart
+ */
+ public static final int MBD_RESTART = 0;
+
+ /**
+ * < mbatchd reread configuration files
+ */
+ public static final int MBD_RECONFIG = 1;
+
+ /**
+ * < mbatchd check validity of configuration files
+ */
+ public static final int MBD_CKCONFIG = 2;
+
+ /**
+ * \brief mbatchd control request.
+ */
+ public static class mbdCtrlReq extends Structure {
+ public static class ByReference extends mbdCtrlReq implements Structure.ByReference {}
+ public static class ByValue extends mbdCtrlReq implements Structure.ByValue {}
+ public mbdCtrlReq() {}
+ public mbdCtrlReq(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Operation applied, defined in \ref mbd_operation
+ */
+ public int opCode;
+
+ /**
+ * < Not used so far
+ */
+ public String name;
+
+ /**
+ * < The message attached by the admin
+ */
+ public String message;
+ }
+
+
+
+/* opcode for turn on or off the perfmon monitor */
+ public static final int PERFMON_START = 1;
+ public static final int PERFMON_STOP = 2;
+ public static final int PERFMON_SET_PERIOD = 3;
+
+
+/* defualt sample period 60 */
+ public static final int DEF_PERFMON_PERIOD = 60;
+
+
+ public static class perfmonMetricsEnt extends Structure {
+ public static class ByReference extends perfmonMetricsEnt implements Structure.ByReference {}
+ public static class ByValue extends perfmonMetricsEnt implements Structure.ByValue {}
+ public perfmonMetricsEnt() {}
+ public perfmonMetricsEnt(Pointer p) { super(p); read(); }
+
+/* metrice name */
+ public String name;
+
+/* last period counters */
+ public NativeLong current;
+
+/* max of (counter/interval)*sample period for one period */
+ public NativeLong max;
+
+/* min of (counter/interval)*sample period for one period */
+ public NativeLong min;
+
+/* avg of (total/interval)*sample period for one period */
+ public NativeLong avg;
+
+/* total counters from performance monitor turn on */
+ public String total;
+ }
+
+
+
+/*performance monitor info*/
+
+ public static class perfmonInfo extends Structure {
+ public static class ByReference extends perfmonInfo implements Structure.ByReference {}
+ public static class ByValue extends perfmonInfo implements Structure.ByValue {}
+ public perfmonInfo() {}
+ public perfmonInfo(Pointer p) { super(p); read(); }
+
+/* number of metrics*/
+ public int num;
+
+/* array of metrics counter */
+ public Pointer /* perfmonMetricsEnt.ByReference */ record;
+
+/* sample period */
+ public int period;
+
+/* time when the performance moniter turn on */
+ public NativeLong start;
+
+/* time when the performance moniter turn off */
+ public NativeLong end;
+ }
+
+
+
+/* options for lsb_reljgrp() call */
+ public static final int JGRP_RELEASE_PARENTONLY = 0x01;
+
+
+ /**
+ * \brief Records of logged events
+ */
+ public static class logSwitchLog extends Structure {
+ public static class ByReference extends logSwitchLog implements Structure.ByReference {}
+ public static class ByValue extends logSwitchLog implements Structure.ByValue {}
+ public logSwitchLog() {}
+ public logSwitchLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The last jobId so far
+ */
+ public int lastJobId;
+/*#if defined(LSF_SIMULATOR)*/
+
+/**< last trace record time */
+/* public NativeLong lastTraceTime;*/
+
+ /**< last trace record type */
+/*public int lastTraceType;*
+
+ /**< last trace record info */
+/*public String lastTraceInfo;*/
+ /*#endif*/
+ }
+
+
+
+ /**
+ * \brief Records of job CPU data logged event
+ */
+ public static class dataLoggingLog extends Structure {
+ public static class ByReference extends dataLoggingLog implements Structure.ByReference {}
+ public static class ByValue extends dataLoggingLog implements Structure.ByValue {}
+ public dataLoggingLog() {}
+ public dataLoggingLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The time of last job cpu data logging
+ */
+ public NativeLong loggingTime;
+ }
+
+
+
+ /**
+ * \brief new job group log.
+ */
+ public static class jgrpNewLog extends Structure {
+ public static class ByReference extends jgrpNewLog implements Structure.ByReference {}
+ public static class ByValue extends jgrpNewLog implements Structure.ByValue {}
+ public jgrpNewLog() {}
+ public jgrpNewLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The job submission time
+ */
+ public NativeLong submitTime;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < The job dependency condition
+ */
+ public String depCond;
+
+ /**
+ * < Time event string
+ */
+ public String timeEvent;
+
+ /**
+ * < Job group name
+ */
+ public String groupSpec;
+
+ /**
+ * < New job group name
+ */
+ public String destSpec;
+
+ /**
+ * < Delete options in options field
+ */
+ public int delOptions;
+
+ /**
+ * < Extended Delete options in options2 field
+ */
+ public int delOptions2;
+
+ /**
+ * < Platform type: such as Unix, Windows
+ */
+ public int fromPlatform;
+
+ /**
+ * < SLA service class name under which the job runs
+ */
+ public String sla;
+
+ /**
+ * < Max job group slots limit
+ */
+ public int maxJLimit;
+
+ /**
+ * < Job group creation method: implicit or explicit
+ */
+ public int options;
+ }
+
+
+
+ /**
+ * \brief job group control log.
+ */
+ public static class jgrpCtrlLog extends Structure {
+ public static class ByReference extends jgrpCtrlLog implements Structure.ByReference {}
+ public static class ByValue extends jgrpCtrlLog implements Structure.ByValue {}
+ public jgrpCtrlLog() {}
+ public jgrpCtrlLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < Job group name
+ */
+ public String groupSpec;
+
+ /**
+ * < Options
+ */
+ public int options;
+
+ /**
+ * < Job control JGRP_RELEASE, JGRP_HOLD, JGRP_DEL
+ */
+ public int ctrlOp;
+ }
+
+
+
+ /**
+ * \brief job group status log.
+ */
+ public static class jgrpStatusLog extends Structure {
+ public static class ByReference extends jgrpStatusLog implements Structure.ByReference {}
+ public static class ByValue extends jgrpStatusLog implements Structure.ByValue {}
+ public jgrpStatusLog() {}
+ public jgrpStatusLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The full group path name for the job group
+ */
+ public String groupSpec;
+
+ /**
+ * < Job group status
+ */
+ public int status;
+
+ /**
+ * < Prior status
+ */
+ public int oldStatus;
+ }
+
+
+
+ /**
+ * \brief jobNewLog logged in lsb.events when a job is submitted.
+ */
+ public static class jobNewLog extends Structure {
+ public static class ByReference extends jobNewLog implements Structure.ByReference {}
+ public static class ByValue extends jobNewLog implements Structure.ByValue {}
+ public jobNewLog() {}
+ public jobNewLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The job ID that the LSF assigned to the job
+ */
+ public int jobId;
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < Job submission options. see \ref lsb_submit.
+ */
+ public int options;
+
+ /**
+ * < Job submission options. see \ref lsb_submit.
+ */
+ public int options2;
+
+ /**
+ * < The number of processors requested for execution
+ */
+ public int numProcessors;
+
+ /**
+ * < The job submission time
+ */
+ public NativeLong submitTime;
+
+ /**
+ * < The job should be started on or after this time
+ */
+ public NativeLong beginTime;
+
+ /**
+ * < If the job has not finished by this time, it will be killed
+ */
+ public NativeLong termTime;
+
+ /**
+ * < The signal value sent to the job 10 minutes before its run window closes
+ */
+ public int sigValue;
+
+ /**
+ * < The checkpointing period
+ */
+ public int chkpntPeriod;
+
+ /**
+ * < The process ID assigned to the job when it was restarted
+ */
+ public int restartPid;
+
+ /**
+ * < The user's resource limits
+ */
+ public int[] rLimits = new int[LibLsf.LSF_RLIM_NLIMITS];
+
+ /**
+ * < The model, host name or host type for scaling CPULIMIT and RUNLIMIT
+ */
+ public byte[] hostSpec = new byte[LibLsf.MAXHOSTNAMELEN];
+
+ /**
+ * < The CPU factor for the above model, host name or host type
+ */
+ public float hostFactor;
+
+ /**
+ * < The file creation mask for this job
+ */
+ public int umask;
+
+ /**
+ * < The name of the queue to which this job was submitted
+ */
+ public byte[] queue = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < The resource requirements of the job
+ */
+ public String resReq;
+
+ /**
+ * < The submission host name
+ */
+ public byte[] fromHost = new byte[LibLsf.MAXHOSTNAMELEN];
+
+ /**
+ * < The current working directory
+ */
+ public String cwd;
+
+ /**
+ * < The checkpoint directory
+ */
+ public String chkpntDir;
+
+ /**
+ * < The input file name
+ */
+ public String inFile;
+
+ /**
+ * < The output file name
+ */
+ public String outFile;
+
+ /**
+ * < The error output file name
+ */
+ public String errFile;
+
+ /**
+ * < Job spool input file
+ */
+ public String inFileSpool;
+
+ /**
+ * < Job spool command file
+ */
+ public String commandSpool;
+
+ /**
+ * < Job spool directory
+ */
+ public String jobSpoolDir;
+
+ /**
+ * < The home directory of the submitter
+ */
+ public String subHomeDir;
+
+ /**
+ * < The job file name
+ */
+ public String jobFile;
+
+ /**
+ * < The number of hosts considered for dispatching this job
+ */
+ public int numAskedHosts;
+
+ /**
+ * < The array of names of hosts considered for dispatching this job
+ */
+ public Pointer askedHosts;
+
+ /**
+ * < The job dependency condition
+ */
+ public String dependCond;
+
+ /**
+ * < Time event string
+ */
+ public String timeEvent;
+
+ /**
+ * < The job name
+ */
+ public String jobName;
+
+ /**
+ * < The job command
+ */
+ public String command;
+
+ /**
+ * < The number of files to transfer
+ */
+ public int nxf;
+
+ /**
+ * < The array of file transfer specifications. (The xFile structure is defined in <lsf/lsbatch.h>)
+ */
+ public Pointer /* xFile.ByReference */ xf;
+
+ /**
+ * < The command string to be pre_executed
+ */
+ public String preExecCmd;
+
+ /**
+ * < User option mail string
+ */
+ public String mailUser;
+
+ /**
+ * < The project name for this job, used for accounting purposes
+ */
+ public String projectName;
+
+ /**
+ * < Port to be used for interactive jobs
+ */
+ public int niosPort;
+
+ /**
+ * < Maximum number of processors
+ */
+ public int maxNumProcessors;
+
+ /**
+ * < Execution host type
+ */
+ public String schedHostType;
+
+ /**
+ * < Login shell specified by user
+ */
+ public String loginShell;
+
+ /**
+ * < The user group name for this job
+ */
+ public String userGroup;
+
+ /**
+ * < List of alarm conditions for job
+ */
+ public String exceptList;
+
+ /**
+ * < Array idx, must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < User priority
+ */
+ public int userPriority;
+
+ /**
+ * < Advance reservation ID
+ */
+ public String rsvId;
+
+ /**
+ * < The job group under which the job runs.
+ */
+ public String jobGroup;
+
+ /**
+ * < External scheduling options
+ */
+ public String extsched;
+
+ /**
+ * < Warning time period in seconds, -1 if unspecified
+ */
+ public int warningTimePeriod;
+
+ /**
+ * < Warning action, SIGNAL | CHKPNT | command, null if unspecified
+ */
+ public String warningAction;
+
+ /**
+ * < The service class under which the job runs.
+ */
+ public String sla;
+
+ /**
+ * < The absolute run limit of the job
+ */
+ public int SLArunLimit;
+
+ /**
+ * < License Project
+ */
+ public String licenseProject;
+
+ /**
+ * < Extended bitwise inclusive OR of options flags. See \ref lsb_submit.
+ */
+ public int options3;
+
+ /**
+ * < Application profile under which the job runs.
+ */
+ public String app;
+
+ /**
+ * < Post-execution commands.
+ */
+ public String postExecCmd;
+
+ /**
+ * < Runtime estimate specified.
+ */
+ public int runtimeEstimation;
+
+ /**
+ * < Job-level requeue exit values.
+ */
+ public String requeueEValues;
+
+ /**
+ * < Initial checkpoint period
+ */
+ public int initChkpntPeriod;
+
+ /**
+ * < Job migration threshold.
+ */
+ public int migThreshold;
+
+ /**
+ * < Resize notify command
+ */
+ public String notifyCmd;
+
+ /**
+ * < Job description.
+ */
+ public String jobDescription;
+
+ /**
+ * < For new options in future
+ */
+ public submit_ext.ByReference submitExt;
+
+/*#if defined(LSF_SIMULATOR)*/
+
+/**< maximum memory */
+ /*public int maxmem;*/
+
+ /**< exit status */
+ /*public int exitstatus;*/
+
+ /**< job run time */
+ /*public int runtime;*/
+
+ /**< system cpu time */
+ /*public int cputime;*/
+
+ /**< allocated slots */
+ /*public int slots;*/
+
+ /**< cpu factor */
+ /*public float cpufactor;*/
+
+ /*#endif*/
+ }
+
+
+
+/*
+#if defined(LSF_SIMULATOR)
+public static class jobArrayElementLog extends Structure {
+public static class ByReference extends jobArrayElementLog implements Structure.ByReference {}
+public static class ByValue extends jobArrayElementLog implements Structure.ByValue {}
+
+ public int jobId;
+*/
+/* Copy LSF simulator related fields from jobNewLog */
+/*
+ public int idx;
+ public int maxmem;
+ public int exitstatus;
+ public int runtime;
+ public int cputime;
+ public int slots;
+ public float cpufactor;
+ };
+ #endif
+ */
+
+ /**
+ * \brief job modified log.
+ */
+ public static class jobModLog extends Structure {
+ public static class ByReference extends jobModLog implements Structure.ByReference {}
+ public static class ByValue extends jobModLog implements Structure.ByValue {}
+ public jobModLog() {}
+ public jobModLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < JobId or jobName in String/
+ * public String jobIdStr;
+ * <p/>
+ * /**< Job submission options(See \ref lsb_submit)
+ */
+ public int options;
+
+ /**
+ * < Job submission options(See \ref lsb_submit)
+ */
+ public int options2;
+
+ /**
+ * < Delete options in options field
+ */
+ public int delOptions;
+
+ /**
+ * < Extended delete options in options2 field .
+ */
+ public int delOptions2;
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The name of the submitter
+ */
+ public String userName;
+
+ /**
+ * < The job submission time
+ */
+ public int submitTime;
+
+ /**
+ * < The file creation mask for this job
+ */
+ public int umask;
+
+ /**
+ * < The number of processors requested for execution
+ */
+ public int numProcessors;
+
+ /**
+ * < The job should be started on or after this time
+ */
+ public NativeLong beginTime;
+
+ /**
+ * < If the job has not finished by this time, it will be killed
+ */
+ public NativeLong termTime;
+
+ /**
+ * < The signal value sent to the job 10 minutes before its run window closes
+ */
+ public int sigValue;
+
+ /**
+ * < The process ID assigned to the job when it was restarted
+ */
+ public int restartPid;
+
+
+ /**
+ * < The job name
+ */
+ public String jobName;
+
+ /**
+ * < The name of the queue to which this job was submitted
+ */
+ public String queue;
+
+
+ /**
+ * < The number of hosts considered for dispatching this job
+ */
+ public int numAskedHosts;
+
+ /**
+ * < List of asked hosts
+ */
+ public Pointer askedHosts;
+
+
+ /**
+ * < The resource requirements of the job
+ */
+ public String resReq;
+
+ /**
+ * < User's resource limits (soft)
+ */
+ public int[] rLimits = new int[LibLsf.LSF_RLIM_NLIMITS];
+
+ /**
+ * < The model, host name or host type for scaling CPULIMIT and RUNLIMIT
+ */
+ public String hostSpec;
+
+
+ /**
+ * < The job dependency condition
+ */
+ public String dependCond;
+
+ /**
+ * < Time event string.
+ */
+ public String timeEvent;
+
+
+ /**
+ * < The home directory of the submitter
+ */
+ public String subHomeDir;
+
+ /**
+ * < The input file name
+ */
+ public String inFile;
+
+ /**
+ * < The output file name
+ */
+ public String outFile;
+
+ /**
+ * < The error output file name
+ */
+ public String errFile;
+
+ /**
+ * < Command description - this is really a job description field
+ */
+ public String command;
+
+ /**
+ * < Job spool input file
+ */
+ public String inFileSpool;
+
+ /**
+ * < Job spool command file
+ */
+ public String commandSpool;
+
+ /**
+ * < The checkpointing period
+ */
+ public int chkpntPeriod;
+
+ /**
+ * < The checkpoint directory
+ */
+ public String chkpntDir;
+
+ /**
+ * < The number of files to transfer
+ */
+ public int nxf;
+
+ /**
+ * < The array of file transfer specifications. (The xFile structure is defined in <lsf/lsbatch.h>)
+ */
+ public Pointer /* xFile.ByReference */ xf;
+
+
+ /**
+ * < The job file name: If == '\\0', indicate let mbatchd make up name, otherwise, mbatchd will use given name. It is '\\0' if it is a regular job,non-nil means it is a restart job.
+ */
+ public String jobFile;
+
+ /**
+ * < The submission host name
+ */
+ public String fromHost;
+
+ /**
+ * < The current working directory
+ */
+ public String cwd;
+
+
+ /**
+ * < The pre-execution command
+ */
+ public String preExecCmd;
+
+ /**
+ * < User option mail string
+ */
+ public String mailUser;
+
+ /**
+ * < Project name for the job; used for accounting purposes
+ */
+ public String projectName;
+
+
+ /**
+ * < NIOS callback port to be used for interactive jobs
+ */
+ public int niosPort;
+
+ /**
+ * < Maximum number of processors
+ */
+ public int maxNumProcessors;
+
+
+ /**
+ * < The login shell specified by user
+ */
+ public String loginShell;
+
+ /**
+ * < Restart job's submission host type
+ */
+ public String schedHostType;
+
+ /**
+ * < The user group name for this job
+ */
+ public String userGroup;
+
+ /**
+ * < List of job exception conditions
+ */
+ public String exceptList;
+
+ /**
+ * < User priority
+ */
+ public int userPriority;
+
+ /**
+ * < Advance reservation ID
+ */
+ public String rsvId;
+
+ /**
+ * < External scheduling options
+ */
+ public String extsched;
+
+ /**
+ * < Job warning time period in seconds; -1 if unspecified
+ */
+ public int warningTimePeriod;
+
+ /**
+ * < Job warning action: SIGNAL | CHKPNT | command; null if unspecified
+ */
+ public String warningAction;
+
+ /**
+ * < The job group under which the job runs
+ */
+ public String jobGroup;
+
+ /**
+ * < SLA service class name under which the job runs
+ */
+ public String sla;
+
+ /**
+ * < LSF License Scheduler project name
+ */
+ public String licenseProject;
+
+ /**
+ * < Extended bitwise inclusive OR of options flags. see \ref lsb_submit.
+ */
+ public int options3;
+
+ /**
+ * < Extended delete options in options3 field.
+ */
+ public int delOptions3;
+
+ /**
+ * < Application profile under which the job runs.
+ */
+ public String app;
+
+ /**
+ * < Absolute priority scheduling string set by administrators to denote static system APS value or ADMIN factor APS value.
+ */
+ public String apsString;
+
+ /**
+ * < Post-execution commands.
+ */
+ public String postExecCmd;
+
+ /**
+ * < Runtime estimate.
+ */
+ public int runtimeEstimation;
+
+ /**
+ * < Job-level requeue exit values.
+ */
+ public String requeueEValues;
+
+ /**
+ * < Initial checkpoint period
+ */
+ public int initChkpntPeriod;
+
+ /**
+ * < Job migration threshold.
+ */
+ public int migThreshold;
+
+ /**
+ * < Resize notify command
+ */
+ public String notifyCmd;
+
+ /**
+ * < Job description.
+ */
+ public String jobDescription;
+
+ /**
+ * < For new options in future
+ */
+ public submit_ext.ByReference submitExt;
+ }
+
+
+
+ /**
+ * \brief logged in lsb.events when a job is started.
+ */
+ public static class jobStartLog extends Structure {
+ public static class ByReference extends jobStartLog implements Structure.ByReference {}
+ public static class ByValue extends jobStartLog implements Structure.ByValue {}
+ public jobStartLog() {}
+ public jobStartLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < The status of the job (see \ref lsb_readjobinfo )
+ */
+ public int jStatus;
+
+ /**
+ * < The job process ID
+ */
+ public int jobPid;
+
+ /**
+ * < The job process group ID
+ */
+ public int jobPGid;
+
+ /**
+ * < The CPU factor of the first execution host
+ */
+ public float hostFactor;
+
+ /**
+ * < The number of processors used for execution
+ */
+ public int numExHosts;
+
+ /**
+ * < The array of execution host names
+ */
+ public Pointer execHosts;
+
+ /**
+ * < Pre-execution command defined in the queue
+ */
+ public String queuePreCmd;
+
+ /**
+ * < Post-execution command defined in the queue
+ */
+ public String queuePostCmd;
+
+ /**
+ * < Job processing flags
+ */
+ public int jFlags;
+
+ /**
+ * < The user group name for this job
+ */
+ public String userGroup;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < Placement information of LSF HPC jobs
+ */
+ public String additionalInfo;
+
+ /**
+ * < How long a backfilled job can run; used for preemption backfill jobs
+ */
+ public int duration4PreemptBackfill;
+
+ /**
+ * < Job Flags2
+ */
+ public int jFlags2;
+ }
+
+
+
+ /**
+ * \brief logged in lsb.events when a job start request is accepted.
+ */
+ public static class jobStartAcceptLog extends Structure {
+ public static class ByReference extends jobStartAcceptLog implements Structure.ByReference {}
+ public static class ByValue extends jobStartAcceptLog implements Structure.ByValue {}
+ public jobStartAcceptLog() {}
+ public jobStartAcceptLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < The job process ID
+ */
+ public int jobPid;
+
+ /**
+ * < The job process group ID
+ */
+ public int jobPGid;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+ }
+
+
+
+ /**
+ * \brief logged in lsb.events when a job is executed.
+ */
+ public static class jobExecuteLog extends Structure {
+ public static class ByReference extends jobExecuteLog implements Structure.ByReference {}
+ public static class ByValue extends jobExecuteLog implements Structure.ByValue {}
+ public jobExecuteLog() {}
+ public jobExecuteLog(Pointer p) { super(p); read(); }
+
+ /* logged in lsb.events when a job is executed */
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < User ID under which the job is running
+ */
+ public int execUid;
+
+ /**
+ * < Home directory of the user denoted by execUid
+ */
+ public String execHome;
+
+ /**
+ * < Current working directory where job is running
+ */
+ public String execCwd;
+
+ /**
+ * < The job process group ID
+ */
+ public int jobPGid;
+
+ /**
+ * < User name under which the job is running
+ */
+ public String execUsername;
+
+ /**
+ * < The job process ID
+ */
+ public int jobPid;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < Placement information of LSF HPC jobs
+ */
+ public String additionalInfo;
+
+ /**
+ * < The run limit scaled by the exec host
+ */
+ public int SLAscaledRunLimit;
+
+ /**
+ * < The position of the job
+ */
+ public int position;
+
+ /**
+ * < The rusage satisfied at job runtime
+ */
+ public String execRusage;
+
+ /**
+ * < The duration for preemptive backfill class in seconds
+ */
+ public int duration4PreemptBackfill;
+ }
+
+
+
+
+ /**
+ * \brief logged when a job's status is changed.
+ */
+ public static class jobStatusLog extends Structure {
+ public static class ByReference extends jobStatusLog implements Structure.ByReference {}
+ public static class ByValue extends jobStatusLog implements Structure.ByValue {}
+ public jobStatusLog() {}
+ public jobStatusLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < The job status (see \ref lsb_readjobinfo )
+ */
+ public int jStatus;
+
+ /**
+ * < The reason the job is pending or suspended (see \ref lsb_pendreason and \ref lsb_suspreason )
+ */
+ public int reason;
+
+ /**
+ * < The load indices that have overloaded the host (see \ref lsb_pendreason and \ref lsb_suspreason )
+ */
+ public int subreasons;
+
+ /**
+ * < The CPU time consumed before this event occurred
+ */
+ public float cpuTime;
+
+ /**
+ * < The job completion time
+ */
+ public NativeLong endTime;
+
+ /**
+ * < Boolean indicating lsfRusage is logged
+ */
+ public int ru;
+
+ /**
+ * < Resource usage statisticsThe lsfRusage structure is defined in <lsf/lsf.h>. Note that the availability of certain fields depends on the platform on which the sbatchd runs. The fields that do not make sense on the platform will be logged as -1.0.
+ */
+ public LibLsf.lsfRusage lsfRusage;
+
+ /**
+ * < Job exit status
+ */
+ public int jFlags;
+
+ /**
+ * < Job's exit status
+ */
+ public int exitStatus;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < Job termination reason, see <lsf/lsbatch.h>
+ */
+ public int exitInfo;
+ }
+
+
+
+
+ /**
+ * \brief logged when a job's status is changed
+ */
+ public static class sbdJobStatusLog extends Structure {
+ public static class ByReference extends sbdJobStatusLog implements Structure.ByReference {}
+ public static class ByValue extends sbdJobStatusLog implements Structure.ByValue {}
+ public sbdJobStatusLog() {}
+ public sbdJobStatusLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < The status of the job (see \ref lsb_readjobinfo)
+ */
+ public int jStatus;
+
+ /**
+ * < The reason the job is pending or suspended (See \ref lsb_pendreason and \ref lsb_suspreason)
+ */
+ public int reasons;
+
+ /**
+ * < The load indices that have overloaded the host (See \ref lsb_pendreason and \ref lsb_suspreason)
+ */
+ public int subreasons;
+
+ /**
+ * < Action process ID
+ */
+ public int actPid;
+
+ /**
+ * < Action Value SIG_CHKPNT | SIG_CHKPNT_COPY | SIG_WARNING
+ */
+ public int actValue;
+
+ /**
+ * < Action period
+ */
+ public NativeLong actPeriod;
+
+ /**
+ * < Action flag
+ */
+ public int actFlags;
+
+ /**
+ * < Action logging status
+ */
+ public int actStatus;
+
+ /**
+ * < Action Reason SUSP_MBD_LOCK | SUSP_USER_STOP | SUSP_USER_RESUME | SUSP_SBD_STARTUP
+ */
+ public int actReasons;
+
+ /**
+ * < Sub Reason SUB_REASON_RUNLIMIT | SUB_REASON_DEADLINE |SUB_REASON_PROCESSLIMIT | SUB_REASON_MEMLIMIT |SUB_REASON_CPULIMIT
+ */
+ public int actSubReasons;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < The signal value
+ */
+ public int sigValue;
+
+ /**
+ * < The termination reason of a job
+ */
+ public int exitInfo;
+ }
+
+
+
+ /**
+ * \brief job status that we could send to MBD
+ */
+ public static class sbdUnreportedStatusLog extends Structure {
+ public static class ByReference extends sbdUnreportedStatusLog implements Structure.ByReference {}
+ public static class ByValue extends sbdUnreportedStatusLog implements Structure.ByValue {}
+ public sbdUnreportedStatusLog() {}
+ public sbdUnreportedStatusLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < Action process ID
+ */
+ public int actPid;
+
+ /**
+ * < The job process ID
+ */
+ public int jobPid;
+
+ /**
+ * < The job process group ID
+ */
+ public int jobPGid;
+
+ /**
+ * < New status of the job
+ */
+ public int newStatus;
+
+ /**
+ * < Pending or suspending reason code
+ */
+ public int reason;
+
+ /**
+ * < Pending or suspending subreason code
+ */
+ public int subreasons;
+
+ /**
+ * < Resource usage information for the job (see jobFinishLog)
+ */
+ public LibLsf.lsfRusage lsfRusage;
+
+ /**
+ * < User ID under which the job is running
+ */
+ public int execUid;
+
+ /**
+ * < Job exit status
+ */
+ public int exitStatus;
+
+ /**
+ * < Current working directory where job is running
+ */
+ public String execCwd;
+
+ /**
+ * < Home directory of the user denoted by execUid
+ */
+ public String execHome;
+
+ /**
+ * < User name under which the job is running
+ */
+ public String execUsername;
+
+ /**
+ * < Message index
+ */
+ public int msgId;
+
+ /**
+ * < Job's resource usage
+ */
+ public LibLsf.jRusage runRusage;
+
+ /**
+ * < Signal value
+ */
+ public int sigValue;
+
+ /**
+ * < Action logging status
+ */
+ public int actStatus;
+
+ /**
+ * < Sequence status of the job
+ */
+ public int seq;
+
+ /**
+ * < Job array index
+ */
+ public int idx;
+
+ /**
+ * < The termination reason of a job
+ */
+ public int exitInfo;
+ }
+
+
+
+ /**
+ * \brief logged when a job is switched to another queue
+ */
+ public static class jobSwitchLog extends Structure {
+ public static class ByReference extends jobSwitchLog implements Structure.ByReference {}
+ public static class ByValue extends jobSwitchLog implements Structure.ByValue {}
+ public jobSwitchLog() {}
+ public jobSwitchLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The unique ID of the job
+ */
+ public int jobId;
+
+ /**
+ * < The name of the queue the job has been switched to
+ */
+ public byte[] queue = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+ }
+
+
+
+ /**
+ * \brief logged when a job is moved to another position
+ */
+ public static class jobMoveLog extends Structure {
+ public static class ByReference extends jobMoveLog implements Structure.ByReference {}
+ public static class ByValue extends jobMoveLog implements Structure.ByValue {}
+ public jobMoveLog() {}
+ public jobMoveLog(Pointer p) { super(p); read(); }
+
+ /* logged when a job is moved to another position */
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The unique ID of the job
+ */
+ public int jobId;
+
+ /**
+ * < The new position of the job
+ */
+ public int position;
+
+ /**
+ * < The operation code for the move (see \ref lsb_movejob)
+ */
+ public int base;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+ }
+
+
+
+ /**
+ * \brief check point log.
+ */
+ public static class chkpntLog extends Structure {
+ public static class ByReference extends chkpntLog implements Structure.ByReference {}
+ public static class ByValue extends chkpntLog implements Structure.ByValue {}
+ public chkpntLog() {}
+ public chkpntLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID of the job
+ */
+ public int jobId;
+
+ /**
+ * < The new checkpointing period
+ */
+ public NativeLong period;
+
+ /**
+ * < The process ID of the checkpointing process (a child sbatchd)
+ */
+ public int pid;
+
+ /**
+ * < 0: checkpoint started; 1: checkpoint succeeded
+ */
+ public int ok;
+
+ /**
+ * < One of the following: \n LSB_CHKPNT_KILL : Kill process if checkpoint successful \n LSB_CHKPNT_FORCE : Force checkpoint even if non-checkpointable conditions exist \n LSB_CHKPNT_MIG : Checkpoint for the purpose of migration
+ */
+ public int flags;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+ }
+
+
+
+ /**
+ * \brief job requeue log.
+ */
+ public static class jobRequeueLog extends Structure {
+ public static class ByReference extends jobRequeueLog implements Structure.ByReference {}
+ public static class ByValue extends jobRequeueLog implements Structure.ByValue {}
+ public jobRequeueLog() {}
+ public jobRequeueLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID of the job
+ */
+ public int jobId;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+ }
+
+
+
+ /**
+ * \brief job clean log.
+ */
+ public static class jobCleanLog extends Structure {
+ public static class ByReference extends jobCleanLog implements Structure.ByReference {}
+ public static class ByValue extends jobCleanLog implements Structure.ByValue {}
+ public jobCleanLog() {}
+ public jobCleanLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+ }
+
+
+
+ /**
+ * \brief job exception log.
+ */
+ public static class jobExceptionLog extends Structure {
+ public static class ByReference extends jobExceptionLog implements Structure.ByReference {}
+ public static class ByValue extends jobExceptionLog implements Structure.ByValue {}
+ public jobExceptionLog() {}
+ public jobExceptionLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < Job exception handling mask
+ */
+ public int exceptMask;
+
+ /**
+ * < Action Id (kill | alarm | rerun | setexcept)
+ */
+ public int actMask;
+
+ /**
+ * < Time event string
+ */
+ public NativeLong timeEvent;
+
+ /**
+ * < Except Info, pending reason for missched or cantrun exception, the exit code of thejob for the abend exception, otherwise 0.
+ */
+ public int exceptInfo;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+ }
+
+
+
+ /**
+ * \brief signal action log.
+ */
+ public static class sigactLog extends Structure {
+ public static class ByReference extends sigactLog implements Structure.ByReference {}
+ public static class ByValue extends sigactLog implements Structure.ByValue {}
+ public sigactLog() {}
+ public sigactLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID of the job
+ */
+ public int jobId;
+
+ /**
+ * < Action period
+ */
+ public NativeLong period;
+
+ /**
+ * < Action process ID
+ */
+ public int pid;
+
+ /**
+ * < Job status
+ */
+ public int jStatus;
+
+ /**
+ * < Pending reasons
+ */
+ public int reasons;
+
+ /**
+ * < Action flag
+ */
+ public int flags;
+
+ /**
+ * < Signal symbol from the set: DELETEJOB | KILL | KILLREQUEUE |REQUEUE_DONE | REQUEUE_EXIT | REQUEUE_PEND |REQUEUE_PSUSP_ADMIN | REQUEUE_PSUSP_USER | SIG_CHKPNT | SIG_CHKPNT_COPY
+ */
+ public String signalSymbol;
+
+ /**
+ * < Action logging status (ACT_NO | ACT_START | ACT_PREEMPT | ACT_DONE | ACT_FAIL) .Shown in signal_action
+ */
+ public int actStatus;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+ }
+
+
+
+ /**
+ * \brief migration log.
+ */
+ public static class migLog extends Structure {
+ public static class ByReference extends migLog implements Structure.ByReference {}
+ public static class ByValue extends migLog implements Structure.ByValue {}
+ public migLog() {}
+ public migLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The job to be migrated
+ */
+ public int jobId;
+
+ /**
+ * < The number of candidate hosts for migration
+ */
+ public int numAskedHosts;
+
+ /**
+ * < The array of candidate host names
+ */
+ public Pointer askedHosts;
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < The user name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+ }
+
+
+
+ /**
+ * \brief signal log.
+ */
+ public static class signalLog extends Structure {
+ public static class ByReference extends signalLog implements Structure.ByReference {}
+ public static class ByValue extends signalLog implements Structure.ByValue {}
+ public signalLog() {}
+ public signalLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The unique ID of the job
+ */
+ public int jobId;
+
+ /**
+ * < Signal symbol from the set: DELETEJOB | KILL | KILLREQUEUE |REQUEUE_DONE | REQUEUE_EXIT | REQUEUE_PEND |REQUEUE_PSUSP_ADMIN | REQUEUE_PSUSP_USER | SIG_CHKPNT | SIG_CHKPNT_COPY
+ */
+ public String signalSymbol;
+
+ /**
+ * < The number of running times
+ */
+ public int runCount;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+ }
+
+
+
+ /**
+ * \brief logged when bqc command is invoked.
+ */
+ public static class queueCtrlLog extends Structure {
+ public static class ByReference extends queueCtrlLog implements Structure.ByReference {}
+ public static class ByValue extends queueCtrlLog implements Structure.ByValue {}
+ public queueCtrlLog() {}
+ public queueCtrlLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The queue control operation (see \ref lsb_queuecontrol)
+ */
+ public int opCode;
+
+ /**
+ * < The name of the queue
+ */
+ public byte[] queue = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < Queue control message
+ */
+ public byte[] message = new byte[LibLsf.MAXLINELEN];
+ }
+
+
+
+/*
+* \brief new debug log.
+ */
+
+ public static class newDebugLog extends Structure {
+ public static class ByReference extends newDebugLog implements Structure.ByReference {}
+ public static class ByValue extends newDebugLog implements Structure.ByValue {}
+ public newDebugLog() {}
+ public newDebugLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The queue control operation
+ */
+ public int opCode;
+
+ /**
+ * < Debug level
+ */
+ public int level;
+
+ /**
+ * < Class of log
+ */
+ public int _logclass;
+
+ /**
+ * < Log enabled, disabled
+ */
+ public int turnOff;
+
+ /**
+ * < Name of log file
+ */
+ public byte[] logFileName = new byte[LibLsf.MAXLSFNAMELEN];
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+ }
+
+
+
+ /**
+ * \brief log the host control information.
+ */
+ public static class hostCtrlLog extends Structure {
+ public static class ByReference extends hostCtrlLog implements Structure.ByReference {}
+ public static class ByValue extends hostCtrlLog implements Structure.ByValue {}
+ public hostCtrlLog() {}
+ public hostCtrlLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The host control operation (See \ref lsb_hostcontrol)
+ */
+ public int opCode;
+
+ /**
+ * < The name of the host
+ */
+ public byte[] host = new byte[LibLsf.MAXHOSTNAMELEN];
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < Host control message
+ */
+ public byte[] message = new byte[LibLsf.MAXLINELEN];
+ }
+
+
+
+ /**
+ * \brief logged when dynamic hosts are added to group.
+ */
+ public static class hgCtrlLog extends Structure {
+ public static class ByReference extends hgCtrlLog implements Structure.ByReference {}
+ public static class ByValue extends hgCtrlLog implements Structure.ByValue {}
+ public hgCtrlLog() {}
+ public hgCtrlLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The host control operation (see \ref lsb_hostcontrol)
+ */
+ public int opCode;
+
+ /**
+ * < The name of the host
+ */
+ public byte[] host = new byte[LibLsf.MAXHOSTNAMELEN];
+
+ /**
+ * < The name of the host group
+ */
+ public byte[] grpname = new byte[LibLsf.MAXHOSTNAMELEN];
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < Host group control message
+ */
+ public byte[] message = new byte[LibLsf.MAXLINELEN];
+ }
+
+
+
+
+/* simulator is ready to schedule jobs */
+ public static final int SIMU_STATUS_READYSCHEDULE = 0x01;
+
+ /**
+ * \brief mbatchd start log.
+ */
+ public static class mbdStartLog extends Structure {
+ public static class ByReference extends mbdStartLog implements Structure.ByReference {}
+ public static class ByValue extends mbdStartLog implements Structure.ByValue {}
+ public mbdStartLog() {}
+ public mbdStartLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The master host name
+ */
+ public byte[] master = new byte[LibLsf.MAXHOSTNAMELEN];
+
+ /**
+ * < The cluster name
+ */
+ public byte[] cluster = new byte[LibLsf.MAXLSFNAMELEN];
+
+ /**
+ * < The number of hosts in the cluster
+ */
+ public int numHosts;
+
+ /**
+ * < The number of queues in the cluster
+ */
+ public int numQueues;
+/*
+ public int simDiffTime;
+ public int pendJobsThreshold;
+ public int simStatus;
+*/
+ }
+
+
+
+ public static class mbdSimStatusLog extends Structure {
+ public static class ByReference extends mbdSimStatusLog implements Structure.ByReference {}
+ public static class ByValue extends mbdSimStatusLog implements Structure.ByValue {}
+ public mbdSimStatusLog() {}
+ public mbdSimStatusLog(Pointer p) { super(p); read(); }
+
+
+/* simulator status */
+ public int simStatus;
+ }
+
+
+
+ /**
+ * \brief mbatchd die log.
+ */
+ public static class mbdDieLog extends Structure {
+ public static class ByReference extends mbdDieLog implements Structure.ByReference {}
+ public static class ByValue extends mbdDieLog implements Structure.ByValue {}
+ public mbdDieLog() {}
+ public mbdDieLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The master host name
+ */
+ public byte[] master = new byte[LibLsf.MAXHOSTNAMELEN];
+
+ /**
+ * < The number of finished jobs that have been removed from the system and logged in the current event file
+ */
+ public int numRemoveJobs;
+
+ /**
+ * < The exit code from the master batch daemon
+ */
+ public int exitCode;
+
+ /**
+ * < mbatchd administrator control message
+ */
+ public byte[] message = new byte[LibLsf.MAXLINELEN];
+ }
+
+
+
+ /**
+ * \brief logged before mbatchd dies.
+ */
+ public static class unfulfillLog extends Structure {
+ public static class ByReference extends unfulfillLog implements Structure.ByReference {}
+ public static class ByValue extends unfulfillLog implements Structure.ByValue {}
+ public unfulfillLog() {}
+ public unfulfillLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The job ID.
+ */
+ public int jobId;
+
+ /**
+ * < The mbatchd has switched the job to a new queue but the sbatchd has not been informed of the switch
+ */
+ public int notSwitched;
+
+ /**
+ * < This signal was not sent to the job
+ */
+ public int sig;
+
+ /**
+ * < The job was not signaled to checkpoint itself
+ */
+ public int sig1;
+
+ /**
+ * < Checkpoint flags. see the chkpntLog structure below.
+ */
+ public int sig1Flags;
+
+ /**
+ * < The new checkpoint period for the job
+ */
+ public NativeLong chkPeriod;
+
+ /**
+ * < Flag for bmod running job's parameters
+ */
+ public int notModified;
+
+ /**
+ * < Job array index
+ */
+ public int idx;
+
+ /**
+ * < Option flags for pending job signals
+ */
+ public int miscOpts4PendSig;
+ }
+
+
+
+ public static final int TERM_UNKNOWN = 0;
+ public static final int TERM_PREEMPT = 1;
+ public static final int TERM_WINDOW = 2;
+ public static final int TERM_LOAD = 3;
+ public static final int TERM_OTHER = 4;
+ public static final int TERM_RUNLIMIT = 5;
+ public static final int TERM_DEADLINE = 6;
+ public static final int TERM_PROCESSLIMIT = 7;
+ public static final int TERM_FORCE_OWNER = 8;
+ public static final int TERM_FORCE_ADMIN = 9;
+ public static final int TERM_REQUEUE_OWNER = 10;
+ public static final int TERM_REQUEUE_ADMIN = 11;
+ public static final int TERM_CPULIMIT = 12;
+ public static final int TERM_CHKPNT = 13;
+ public static final int TERM_OWNER = 14;
+ public static final int TERM_ADMIN = 15;
+ public static final int TERM_MEMLIMIT = 16;
+ public static final int TERM_EXTERNAL_SIGNAL = 17;
+ public static final int TERM_RMS = 18;
+ public static final int TERM_ZOMBIE = 19;
+ public static final int TERM_SWAP = 20;
+ public static final int TERM_THREADLIMIT = 21;
+ public static final int TERM_SLURM = 22;
+ public static final int TERM_BUCKET_KILL = 23;
+ public static final int TERM_CTRL_PID = 24;
+ public static final int TERM_CWD_NOTEXIST = 25;
+
+ /**
+ * \brief logged in lsb.acct when a job finished.
+ */
+ public static class jobFinishLog extends Structure {
+ public static class ByReference extends jobFinishLog implements Structure.ByReference {}
+ public static class ByValue extends jobFinishLog implements Structure.ByValue {}
+ public jobFinishLog() {}
+ public jobFinishLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The user name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < Job submission options (see \ref lsb_submit)
+ */
+ public int options;
+
+ /**
+ * < The number of processors requested for execution
+ */
+ public int numProcessors;
+
+ /**
+ * < The status of the job (See \ref lsb_readjobinfo)
+ */
+ public int jStatus;
+
+ /**
+ * < Job submission time
+ */
+ public NativeLong submitTime;
+
+ /**
+ * < The job started at or after this time
+ */
+ public NativeLong beginTime;
+
+ /**
+ * < If the job was not finished by this time, it was killed
+ */
+ public NativeLong termTime;
+
+ /**
+ * < Job dispatch time
+ */
+ public NativeLong startTime;
+
+ /**
+ * < The time the job finished
+ */
+ public NativeLong endTime;
+
+ /**
+ * < The name of the queue to which this job was submitted
+ */
+ public byte[] queue = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < Resource requirements
+ */
+ public String resReq;
+
+ /**
+ * < Submission host name
+ */
+ public byte[] fromHost = new byte[LibLsf.MAXHOSTNAMELEN];
+
+ /**
+ * < Current working directory
+ */
+ public String cwd;
+
+ /**
+ * < Input file name
+ */
+ public String inFile;
+
+ /**
+ * < Output file name
+ */
+ public String outFile;
+
+ /**
+ * < Error output file name
+ */
+ public String errFile;
+
+ /**
+ * < Job spool input file
+ */
+ public String inFileSpool;
+
+ /**
+ * < Job spool command file
+ */
+ public String commandSpool;
+
+ /**
+ * < Job file name
+ */
+ public String jobFile;
+
+ /**
+ * < The number of hosts considered for dispatching this job
+ */
+ public int numAskedHosts;
+
+ /**
+ * < The array of names of hosts considered for dispatching this job
+ */
+ public Pointer askedHosts;
+
+ /**
+ * < The CPU factor of the first execution host
+ */
+ public float hostFactor;
+
+ /**
+ * < The number of processors used for execution
+ */
+ public int numExHosts;
+
+ /**
+ * < The array of names of execution hosts
+ */
+ public Pointer execHosts;
+
+ /**
+ * < The total CPU time consumed by the job
+ */
+ public float cpuTime;
+
+ /**
+ * < Job name
+ */
+ public String jobName;
+
+ /**
+ * < Job command
+ */
+ public String command;
+
+ /**
+ * < Resource usage statistics.The lsfRusage structure is defined in <lsf/lsf.h>. Note that the availability of certain fields depends on the platform on which the sbatchd runs. The fields that do not make sense on this platform will be logged as -1.0.
+ */
+ public LibLsf.lsfRusage lsfRusage;
+
+ /**
+ * < The job dependency condition
+ */
+ public String dependCond;
+
+ /**
+ * < Time event string
+ */
+ public String timeEvent;
+
+ /**
+ * < The pre-execution command
+ */
+ public String preExecCmd;
+
+ /**
+ * < Name of the user to whom job related mail was sent
+ */
+ public String mailUser;
+
+ /**
+ * < The project name, used for accounting purposes.
+ */
+ public String projectName;
+
+ /**
+ * < Job's exit status
+ */
+ public int exitStatus;
+
+ /**
+ * < Maximum number of processors specified for the job
+ */
+ public int maxNumProcessors;
+
+ /**
+ * < Login shell specified by user
+ */
+ public String loginShell;
+
+ /**
+ * < Job array index
+ */
+ public int idx;
+
+ /**
+ * < Maximum memory used by job
+ */
+ public int maxRMem;
+
+ /**
+ * < Maximum swap used by job
+ */
+ public int maxRSwap;
+
+ /**
+ * < Advanced reservation ID
+ */
+ public String rsvId;
+
+ /**
+ * < Service class of the job
+ */
+ public String sla;
+
+ /**
+ * < Job exception handling mask
+ */
+ public int exceptMask;
+
+ /**
+ * < Placement information of LSF HPC jobs
+ */
+ public String additionalInfo;
+
+ /**
+ * < Job termination reason, see <lsf/lsbatch.h>
+ */
+ public int exitInfo;
+
+ /**
+ * < Job warning time period in seconds; -1 if unspecified
+ */
+ public int warningTimePeriod;
+
+ /**
+ * < Warning action, SIGNAL | CHKPNT | command, null if unspecified
+ */
+ public String warningAction;
+
+ /**
+ * < SAAP charged for job
+ */
+ public String chargedSAAP;
+
+ /**
+ * < LSF License Scheduler project name
+ */
+ public String licenseProject;
+
+ /**
+ * < Application profile under which the job runs.
+ */
+ public String app;
+
+ /**
+ * < Post-execution commands.
+ */
+ public String postExecCmd;
+
+ /**
+ * < Runtime estimate specified.
+ */
+ public int runtimeEstimation;
+
+ /**
+ * < Job group name
+ */
+ public String jgroup;
+
+ /**
+ * < Option2
+ */
+ public int options2;
+
+ /**
+ * < Job requeue exit values
+ */
+ public String requeueEValues;
+
+ /**
+ * < Resize notify command
+ */
+ public String notifyCmd;
+
+ /**
+ * < Last resize start time
+ */
+ public NativeLong lastResizeTime;
+
+ /**
+ * < Job description.
+ */
+ public String jobDescription;
+
+ /**
+ * < For new options in future
+ */
+ public submit_ext.ByReference submitExt;
+ }
+
+
+
+
+ /**
+ * \brief load index log.
+ */
+
+ public static class loadIndexLog extends Structure {
+ public static class ByReference extends loadIndexLog implements Structure.ByReference {}
+ public static class ByValue extends loadIndexLog implements Structure.ByValue {}
+ public loadIndexLog() {}
+ public loadIndexLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The number of load indices
+ */
+ public int nIdx;
+
+ /**
+ * < The array of load index names
+ */
+ public Pointer name;
+ }
+
+
+
+ /**
+ * \brief calendar log.
+ */
+ public static class calendarLog extends Structure {
+ public static class ByReference extends calendarLog implements Structure.ByReference {}
+ public static class ByValue extends calendarLog implements Structure.ByValue {}
+ public calendarLog() {}
+ public calendarLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Reserved for future use
+ */
+ public int options;
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The name of the calendar
+ */
+ public String name;
+
+ /**
+ * < Description
+ */
+ public String desc;
+
+ /**
+ * < Calendar expression
+ */
+ public String calExpr;
+ }
+
+
+
+ /**
+ * \brief job forward log.
+ */
+ public static class jobForwardLog extends Structure {
+ public static class ByReference extends jobForwardLog implements Structure.ByReference {}
+ public static class ByValue extends jobForwardLog implements Structure.ByValue {}
+ public jobForwardLog() {}
+ public jobForwardLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID of the job
+ */
+ public int jobId;
+
+ /**
+ * < The cluster name
+ */
+ public String cluster;
+
+ /**
+ * < Number of Reserved Hosts
+ */
+ public int numReserHosts;
+
+ /**
+ * < Reserved Host Names
+ */
+ public Pointer reserHosts;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < Remote job attributes from: \n JOB_FORWARD Remote batch job on submission side \n JOB_LEASE Lease job on submission side \n JOB_REMOTE_BATCH Remote batch job on execution side \n JOB_REMOTE_LEASE Lease job on execution side \n JOB_LEASE_RESYNC Lease job resync during restart \n JOB_REMOTE_RERUNNABLE Remote batch job rerunnable on execution cluster
+ */
+ public int jobRmtAttr;
+ }
+
+
+
+ /**
+ * \brief job accept log.
+ */
+ public static class jobAcceptLog extends Structure {
+ public static class ByReference extends jobAcceptLog implements Structure.ByReference {}
+ public static class ByValue extends jobAcceptLog implements Structure.ByValue {}
+ public jobAcceptLog() {}
+ public jobAcceptLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID of the job
+ */
+ public int jobId;
+
+ /**
+ * < The unique ID of the remote job
+ */
+ public long remoteJid;
+
+ /**
+ * < The cluster name
+ */
+ public String cluster;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < Remote job attributes from: \n JOB_FORWARD Remote batch job on submission side \n JOB_LEASE Lease job on submission side \n JOB_REMOTE_BATCH Remote batch job on execution side \n JOB_REMOTE_LEASE Lease job on execution side \n JOB_LEASE_RESYNC Lease job resync during restart \n JOB_REMOTE_RERUNNABLE Remote batch job rerunnable on execution cluster
+ */
+ public int jobRmtAttr;
+ }
+
+
+
+ /**
+ * \brief status Ack log.
+ */
+ public static class statusAckLog extends Structure {
+ public static class ByReference extends statusAckLog implements Structure.ByReference {}
+ public static class ByValue extends statusAckLog implements Structure.ByValue {}
+ public statusAckLog() {}
+ public statusAckLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID of the job
+ */
+ public int jobId;
+
+ /**
+ * < Line number of Status
+ */
+ public int statusNum;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+ }
+
+
+
+ /**
+ * \brief job message log.
+ */
+ public static class jobMsgLog extends Structure {
+ public static class ByReference extends jobMsgLog implements Structure.ByReference {}
+ public static class ByValue extends jobMsgLog implements Structure.ByValue {}
+ public jobMsgLog() {}
+ public jobMsgLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int usrId;
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < Message index
+ */
+ public int msgId;
+
+ /**
+ * < Message type
+ */
+ public int type;
+
+ /**
+ * < Message source
+ */
+ public String src;
+
+ /**
+ * < Message destination
+ */
+ public String dest;
+
+ /**
+ * < Message
+ */
+ public String msg;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+ }
+
+
+
+ /**
+ * \brief job message ack log.
+ */
+ public static class jobMsgAckLog extends Structure {
+ public static class ByReference extends jobMsgAckLog implements Structure.ByReference {}
+ public static class ByValue extends jobMsgAckLog implements Structure.ByValue {}
+ public jobMsgAckLog() {}
+ public jobMsgAckLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int usrId;
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < Message index
+ */
+ public int msgId;
+
+ /**
+ * < Message type
+ */
+ public int type;
+
+ /**
+ * < Message source
+ */
+ public String src;
+
+ /**
+ * < Message destination
+ */
+ public String dest;
+
+ /**
+ * < Message
+ */
+ public String msg;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+ }
+
+
+
+ /**
+ * \brief job occupy request log. jobOccupyReqLog is for future use.
+ */
+ public static class jobOccupyReqLog extends Structure {
+ public static class ByReference extends jobOccupyReqLog implements Structure.ByReference {}
+ public static class ByValue extends jobOccupyReqLog implements Structure.ByValue {}
+ public jobOccupyReqLog() {}
+ public jobOccupyReqLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < Number of Jobs Slots desired
+ */
+ public int numOccupyRequests;
+
+ /**
+ * < List of slots occupied
+ */
+ public Pointer occupyReqList;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+ }
+
+
+
+ /**
+ * \brief job vacate log.jobVacatedLog is for future use.
+ */
+ public static class jobVacatedLog extends Structure {
+ public static class ByReference extends jobVacatedLog implements Structure.ByReference {}
+ public static class ByValue extends jobVacatedLog implements Structure.ByValue {}
+ public jobVacatedLog() {}
+ public jobVacatedLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+ }
+
+
+
+ /**
+ * \brief job force request log.
+ */
+ public static class jobForceRequestLog extends Structure {
+ public static class ByReference extends jobForceRequestLog implements Structure.ByReference {}
+ public static class ByValue extends jobForceRequestLog implements Structure.ByValue {}
+ public jobForceRequestLog() {}
+ public jobForceRequestLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < >1 for local/lease jobs; 0 for remote batch model
+ */
+ public int numExecHosts;
+
+ /**
+ * < The array of execution host names
+ */
+ public Pointer execHosts;
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < Job run options (RUNJOB_OPT_NOSTOP | JFLAG_URGENT_NOSTOP |JFLAG_URGENT)
+ */
+ public int options;
+
+ /**
+ * < The name of the submitter
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < The name of the queue to which this job was submitted
+ */
+ public String queue;
+ }
+
+
+
+ /**
+ * \brief job chunck log.
+ */
+ public static class jobChunkLog extends Structure {
+ public static class ByReference extends jobChunkLog implements Structure.ByReference {}
+ public static class ByValue extends jobChunkLog implements Structure.ByValue {}
+ public jobChunkLog() {}
+ public jobChunkLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Size of array membJobId
+ */
+ public NativeLong membSize;
+
+ /**
+ * < Job ids of jobs in the chunk
+ */
+ public LongByReference membJobId;
+
+ /**
+ * < The number of processors used for execution
+ */
+ public NativeLong numExHosts;
+
+ /**
+ * < The array of names of execution hosts
+ */
+ public Pointer execHosts;
+ }
+
+
+
+ /**
+ * \brief job external message log.
+ */
+ public static class jobExternalMsgLog extends Structure {
+ public static class ByReference extends jobExternalMsgLog implements Structure.ByReference {}
+ public static class ByValue extends jobExternalMsgLog implements Structure.ByValue {}
+ public jobExternalMsgLog() {}
+ public jobExternalMsgLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID for the job
+ */
+ public int jobId;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < The message index
+ */
+ public int msgIdx;
+
+ /**
+ * < Message description
+ */
+ public String desc;
+
+ /**
+ * < The user ID of the submitter
+ */
+ public int userId;
+
+ /**
+ * < Size of the message
+ */
+ public NativeLong dataSize;
+
+ /**
+ * < The time the author posted the message.
+ */
+ public NativeLong postTime;
+
+ /**
+ * < The status of the message
+ */
+ public int dataStatus;
+
+ /**
+ * < Name of attached data file. If no file is attached, use null.
+ */
+ public String fileName;
+
+ /**
+ * < The author of the message
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+ }
+
+
+
+ /**
+ * \brief reservation request.
+ */
+ public static class rsvRes extends Structure {
+ public static class ByReference extends rsvRes implements Structure.ByReference {}
+ public static class ByValue extends rsvRes implements Structure.ByValue {}
+ public rsvRes() {}
+ public rsvRes(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Name of the resource (currently: host)
+ */
+ public String resName;
+
+ /**
+ * < Reserved counter (currently: cpu number)
+ */
+ public int count;
+
+ /**
+ * < Used of the reserved counter (not used)
+ */
+ public int usedAmt;
+ }
+
+
+
+ /**
+ * \brief for advanced reservation.
+ */
+ public static class rsvFinishLog extends Structure {
+ public static class ByReference extends rsvFinishLog implements Structure.ByReference {}
+ public static class ByValue extends rsvFinishLog implements Structure.ByValue {}
+ public rsvFinishLog() {}
+ public rsvFinishLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Time when the reservation is required
+ */
+ public NativeLong rsvReqTime;
+
+ /**
+ * < Same as the options field in the addRsvRequest(lsbatch.h)
+ */
+ public int options;
+
+ /**
+ * < The user who creat the reservation
+ */
+ public int uid;
+
+ /**
+ * < Reservation ID
+ */
+ public String rsvId;
+
+ /**
+ * < Client of the reservation
+ */
+ public String name;
+
+ /**
+ * < Number of resources reserved
+ */
+ public int numReses;
+
+ /**
+ * < Allocation vector
+ */
+ public Pointer /* rsvRes.ByReference */ alloc;
+
+ /**
+ * < Time window within which the reservation is active \n Two forms: int1-int2 or [day1]:hour1:0-[day2]:hour2:0
+ */
+ public String timeWindow;
+
+ /**
+ * < Duration in seconds. duration = to - from : when the reservation expired
+ */
+ public NativeLong duration;
+
+ /**
+ * < Creator of the reservation
+ */
+ public String creator;
+ }
+
+
+
+ /**
+ * \brief CPU Profile Log
+ */
+ public static class cpuProfileLog extends Structure {
+ public static class ByReference extends cpuProfileLog implements Structure.ByReference {}
+ public static class ByValue extends cpuProfileLog implements Structure.ByValue {}
+ public cpuProfileLog() {}
+ public cpuProfileLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Queue name
+ */
+ public byte[] servicePartition = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < The number of CPU required
+ */
+ public int slotsRequired;
+
+ /**
+ * < The number of CPU actually allocated
+ */
+ public int slotsAllocated;
+
+ /**
+ * < The number of CPU borrowed
+ */
+ public int slotsBorrowed;
+
+ /**
+ * < The number of CPU lent
+ */
+ public int slotsLent;
+ /** note: the number of CPU reserved = slotsAllocated - slotsBorrowed + slotsLent */
+ }
+
+
+
+ /**
+ * \brief job resize start notify log.
+ */
+ public static class jobResizeNotifyStartLog extends Structure {
+ public static class ByReference extends jobResizeNotifyStartLog implements Structure.ByReference {}
+ public static class ByValue extends jobResizeNotifyStartLog implements Structure.ByValue {}
+ public jobResizeNotifyStartLog() {}
+ public jobResizeNotifyStartLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < JobId
+ */
+ public int jobId;
+
+ /**
+ * < Index
+ */
+ public int idx;
+
+ /**
+ * < Notify Id
+ */
+ public int notifyId;
+
+ /**
+ * < Number of resized hosts.
+ */
+ public int numResizeHosts;
+
+ /**
+ * < Resize Hosts
+ */
+ public Pointer resizeHosts;
+ }
+
+
+
+ /**
+ * \brief job resize accept notify log.
+ */
+ public static class jobResizeNotifyAcceptLog extends Structure {
+ public static class ByReference extends jobResizeNotifyAcceptLog implements Structure.ByReference {}
+ public static class ByValue extends jobResizeNotifyAcceptLog implements Structure.ByValue {}
+ public jobResizeNotifyAcceptLog() {}
+ public jobResizeNotifyAcceptLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < JobId
+ */
+ public int jobId;
+
+ /**
+ * < Index
+ */
+ public int idx;
+
+ /**
+ * < Notify Id
+ */
+ public int notifyId;
+
+ /**
+ * < Resize Notify command pid
+ */
+ public int resizeNotifyCmdPid;
+
+ /**
+ * < Resize Notify command pgid
+ */
+ public int resizeNotifyCmdPGid;
+
+ /**
+ * < Status
+ */
+ public int status;
+ }
+
+
+
+ /**
+ * \brief job resize done notify log.
+ */
+ public static class jobResizeNotifyDoneLog extends Structure {
+ public static class ByReference extends jobResizeNotifyDoneLog implements Structure.ByReference {}
+ public static class ByValue extends jobResizeNotifyDoneLog implements Structure.ByValue {}
+ public jobResizeNotifyDoneLog() {}
+ public jobResizeNotifyDoneLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < JobId
+ */
+ public int jobId;
+
+ /**
+ * < Index
+ */
+ public int idx;
+
+ /**
+ * < Notify Id
+ */
+ public int notifyId;
+
+ /**
+ * < Status
+ */
+ public int status;
+ }
+
+
+
+ /**
+ * \brief job resize release log.
+ */
+ public static class jobResizeReleaseLog extends Structure {
+ public static class ByReference extends jobResizeReleaseLog implements Structure.ByReference {}
+ public static class ByValue extends jobResizeReleaseLog implements Structure.ByValue {}
+ public jobResizeReleaseLog() {}
+ public jobResizeReleaseLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < JobId
+ */
+ public int jobId;
+
+ /**
+ * < Index
+ */
+ public int idx;
+
+ /**
+ * < Request Id
+ */
+ public int reqId;
+
+ /**
+ * < Options
+ */
+ public int options;
+
+ /**
+ * < User Id
+ */
+ public int userId;
+
+ /**
+ * < User Name
+ */
+ public String userName;
+
+ /**
+ * < Resize Notify command
+ */
+ public String resizeNotifyCmd;
+
+ /**
+ * < Number of resized hosts
+ */
+ public int numResizeHosts;
+
+ /**
+ * < Resized hosts
+ */
+ public Pointer resizeHosts;
+ }
+
+
+
+ /**
+ * \brief job resize cancel log.
+ */
+ public static class jobResizeCancelLog extends Structure {
+ public static class ByReference extends jobResizeCancelLog implements Structure.ByReference {}
+ public static class ByValue extends jobResizeCancelLog implements Structure.ByValue {}
+ public jobResizeCancelLog() {}
+ public jobResizeCancelLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < JobId
+ */
+ public int jobId;
+
+ /**
+ * < Index
+ */
+ public int idx;
+
+ /**
+ * < User Id
+ */
+ public int userId;
+
+ /**
+ * < User name
+ */
+ public String userName;
+ }
+
+
+
+ /**
+ * \brief log the running rusage of a job in the lsb.stream file
+ */
+ public static class jobRunRusageLog extends Structure {
+ public static class ByReference extends jobRunRusageLog implements Structure.ByReference {}
+ public static class ByValue extends jobRunRusageLog implements Structure.ByValue {}
+ public jobRunRusageLog() {}
+ public jobRunRusageLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The unique ID of the job
+ */
+ public int jobid;
+
+ /**
+ * < Job array index; must be 0 in JOB_NEW
+ */
+ public int idx;
+
+ /**
+ * < jrusage
+ */
+ public LibLsf.jRusage jrusage;
+ }
+
+
+
+ /**
+ * \brief SLA event log.
+ */
+ public static class slaLog extends Structure {
+ public static class ByReference extends slaLog implements Structure.ByReference {}
+ public static class ByValue extends slaLog implements Structure.ByValue {}
+ public slaLog() {}
+ public slaLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Service class name
+ */
+ public String name;
+
+ /**
+ * < Consumer name associated with the service class
+ */
+ public String consumer;
+
+ /**
+ * < Objectives
+ */
+ public int goaltype;
+
+ /**
+ * < The service class state (ontime, delayed)
+ */
+ public int state;
+
+ /**
+ * < Optimum number of job slots (or concurrently running jobs) needed for the service class to meet its service-level goals
+ */
+ public int optimum;
+
+ /**
+ * < Job counters for the service class
+ */
+ public int[] counters = new int[NUM_JGRP_COUNTERS];
+ }
+
+
+
+ /**
+ * \brief a wrap of structure perfmonLog for performance metrics project
+ */
+ public static class perfmonLogInfo extends Structure {
+ public static class ByReference extends perfmonLogInfo implements Structure.ByReference {}
+ public static class ByValue extends perfmonLogInfo implements Structure.ByValue {}
+ public perfmonLogInfo() {}
+ public perfmonLogInfo(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Sample period
+ */
+ public int samplePeriod;
+
+ /**
+ * < Metrics
+ */
+ public IntByReference metrics;
+
+ /**
+ * < Start time
+ */
+ public NativeLong startTime;
+
+ /**
+ * < Log time
+ */
+ public NativeLong logTime;
+ }
+
+
+
+ /**
+ * \brief performance metrics log in lsb.stream
+ */
+ public static class perfmonLog extends Structure {
+ public static class ByReference extends perfmonLog implements Structure.ByReference {}
+ public static class ByValue extends perfmonLog implements Structure.ByValue {}
+ public perfmonLog() {}
+ public perfmonLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Sample rate
+ */
+ public int samplePeriod;
+
+ /**
+ * < Number of Queries
+ */
+ public int totalQueries;
+
+ /**
+ * < Number of Job Query
+ */
+ public int jobQuries;
+
+ /**
+ * < Number of Queue Query
+ */
+ public int queueQuries;
+
+ /**
+ * < Number of Host Query
+ */
+ public int hostQuries;
+
+ /**
+ * < Number of Submission Requests
+ */
+ public int submissionRequest;
+
+ /**
+ * < Number of Jobs Submitted
+ */
+ public int jobSubmitted;
+
+ /**
+ * < Number of Dispatched Jobs
+ */
+ public int dispatchedjobs;
+
+ /**
+ * < Number of Job Completed
+ */
+ public int jobcompleted;
+
+ /**
+ * < Number of MultiCluster Jobs Sent
+ */
+ public int jobMCSend;
+
+ /**
+ * < Number of MultiCluster Jobs Received
+ */
+ public int jobMCReceive;
+
+ /**
+ * < Start Time
+ */
+ public NativeLong startTime;
+ }
+
+
+
+ /**
+ * \brief task finish log.Task accounting record in ssched.acct
+ */
+ public static class taskFinishLog extends Structure {
+ public static class ByReference extends taskFinishLog implements Structure.ByReference {}
+ public static class ByValue extends taskFinishLog implements Structure.ByValue {}
+ public taskFinishLog() {}
+ public taskFinishLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Job finish event
+ */
+ public jobFinishLog jobFinishLog;
+
+ /**
+ * < Task ID
+ */
+ public int taskId;
+
+ /**
+ * < Task index
+ */
+ public int taskIdx;
+
+ /**
+ * < Name of task
+ */
+ public String taskName;
+
+ /**
+ * < Bit mask of task options: \n TASK_IN_FILE (0x01)-specify input file \n TASK_OUT_FILE (0x02)-specify output file \n TASK_ERR_FILE (0x04)-specify error file \n TASK_PRE_EXEC (0x08)-specify pre-exec command \n TASK_POST_EXEC (0x10)-specify post-exec command \n TASK_NAME (0x20)-specify task name
+ */
+ public int taskOptions;
+
+ /**
+ * < Task Exit Reason \n TASK_EXIT_NORMAL = 0- normal exit \n TASK_EXIT_INIT = 1-generic task initialization failure \n TASK_EXIT_PATH = 2-failed to initialize path \n TASK_EXIT_NO_FILE = 3-failed to create task file \n TASK_EXIT_PRE_EXEC = 4- task pre-exec failed \n TASK_EXIT_NO_PROCESS = 5-fork failed \n TASK_EXIT_XDR = 6-xdr communication error \n TASK_EXIT_NOMEM = 7- no memory \n TASK_EXIT_SYS = 8-system call failed \n TASK_EXIT_TSCHILD_EXEC = 9-failed to run sschild \n TASK_ [...]
+ */
+ public int taskExitReason;
+ }
+
+
+
+ /**
+ * \brief End of stream event. The stream is moved to lsb.stream.0 and
+ * a new lsb.stream is opened. Readers of lsb.stream when encounter
+ * the event EVENT_END_OF_STREAM should close and reopen the
+ * lsb.stream file.
+ */
+ public static class eventEOSLog extends Structure {
+ public static class ByReference extends eventEOSLog implements Structure.ByReference {}
+ public static class ByValue extends eventEOSLog implements Structure.ByValue {}
+ public eventEOSLog() {}
+ public eventEOSLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Event end of stream
+ */
+ public int eos;
+ }
+
+
+
+ /**
+ * \brief job resize event: indicating a realized job allocation change
+ */
+ public static class jobResizeLog extends Structure {
+ public static class ByReference extends jobResizeLog implements Structure.ByReference {}
+ public static class ByValue extends jobResizeLog implements Structure.ByValue {}
+ public jobResizeLog() {}
+ public jobResizeLog(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < JobId
+ */
+ public int jobId;
+
+ /**
+ * < Index
+ */
+ public int idx;
+
+ /**
+ * < Start time
+ */
+ public NativeLong startTime;
+
+ /**
+ * < User Id
+ */
+ public int userId;
+
+ /**
+ * < User name
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < 0 grow, 1 shrink
+ */
+ public int resizeType;
+
+ /**
+ * < The start time of last allocation
+ */
+ public NativeLong lastResizeStartTime;
+
+ /**
+ * < The finish time of last allocation
+ */
+ public NativeLong lastResizeFinishTime;
+
+ /**
+ * < Allocation before the resize
+ */
+ public int numExecHosts;
+
+ /**
+ * < Execute hosts
+ */
+ public Pointer execHosts;
+
+ /**
+ * < The delta of the allocation change
+ */
+ public int numResizeHosts;
+
+ /**
+ * < Resize hosts
+ */
+ public Pointer resizeHosts;
+ }
+
+
+
+ /**
+ * \brief Log event types.
+ */
+ public static class eventLog extends Union {
+ /**
+ * < Job new event
+ */
+ public jobNewLog jobNewLog;
+
+ /**
+ * < Job start event
+ */
+ public jobStartLog jobStartLog;
+
+ /**
+ * < Job status event
+ */
+ public jobStatusLog jobStatusLog;
+
+ /**
+ * < sbatchd job status event
+ */
+ public sbdJobStatusLog sbdJobStatusLog;
+
+ /**
+ * < Job switch event
+ */
+ public jobSwitchLog jobSwitchLog;
+
+ /**
+ * < Job move event
+ */
+ public jobMoveLog jobMoveLog;
+
+ /**
+ * < Queue control event
+ */
+ public queueCtrlLog queueCtrlLog;
+
+/* New debug event*/
+ public newDebugLog newDebugLog;
+
+ /**
+ * < Host control event
+ */
+ public hostCtrlLog hostCtrlLog;
+
+ /**
+ * < mbatchd start event
+ */
+ public mbdStartLog mbdStartLog;
+
+ /**
+ * < mbatchd die event
+ */
+ public mbdDieLog mbdDieLog;
+
+ /**
+ * < Unfulfill event
+ */
+ public unfulfillLog unfulfillLog;
+
+ /**
+ * < Job finish event
+ */
+ public jobFinishLog jobFinishLog;
+
+ /**
+ * < Load index event
+ */
+ public loadIndexLog loadIndexLog;
+
+ /**
+ * < Migration initiated event
+ */
+ public migLog migLog;
+
+ /**
+ * < Calendar event
+ */
+ public calendarLog calendarLog;
+
+ /**
+ * < Job forward event
+ */
+ public jobForwardLog jobForwardLog;
+
+ /**
+ * < Job accept event
+ */
+ public jobAcceptLog jobAcceptLog;
+
+ /**
+ * < Job accepted from another cluster event
+ */
+ public statusAckLog statusAckLog;
+
+ /**
+ * < Job signal event
+ */
+ public signalLog signalLog;
+
+ /**
+ * < Job execution event
+ */
+ public jobExecuteLog jobExecuteLog;
+
+ /**
+ * < Job message event
+ */
+ public jobMsgLog jobMsgLog;
+
+ /**
+ * < Job message ackknowledge event
+ */
+ public jobMsgAckLog jobMsgAckLog;
+
+ /**
+ * < Job requeue event
+ */
+ public jobRequeueLog jobRequeueLog;
+
+ /**
+ * < Checkpoint event
+ */
+ public chkpntLog chkpntLog;
+
+ /**
+ * < Signal with action event
+ */
+ public sigactLog sigactLog;
+
+ /**
+ * < Job occupy request event
+ */
+ public jobOccupyReqLog jobOccupyReqLog;
+
+ /**
+ * < Job vacate event
+ */
+ public jobVacatedLog jobVacatedLog;
+
+ /**
+ * < Job start accept event
+ */
+ public jobStartAcceptLog jobStartAcceptLog;
+
+ /**
+ * < Job clean event
+ */
+ public jobCleanLog jobCleanLog;
+
+ /**
+ * < Job exception event
+ */
+ public jobExceptionLog jobExceptionLog;
+
+ /**
+ * < Job group new event
+ */
+ public jgrpNewLog jgrpNewLog;
+
+ /**
+ * < Job group Ctrl event
+ */
+ public jgrpCtrlLog jgrpCtrlLog;
+
+ /**
+ * < Job Force Request event
+ */
+ public jobForceRequestLog jobForceRequestLog;
+
+ /**
+ * < Event switch event
+ */
+ public logSwitchLog logSwitchLog;
+
+ /**
+ * < Job modify event
+ */
+ public jobModLog jobModLog;
+
+ /**
+ * < Job group stratus event
+ */
+ public jgrpStatusLog jgrpStatusLog;
+
+ /**
+ * < Job attribute setting event
+ */
+ public jobAttrSetLog jobAttrSetLog;
+
+ /**
+ * < Job external message event
+ */
+ public jobExternalMsgLog jobExternalMsgLog;
+
+ /**
+ * < Job chunk event
+ */
+ public jobChunkLog jobChunkLog;
+
+ /**
+ * < sbatchd unreported status event
+ */
+ public sbdUnreportedStatusLog sbdUnreportedStatusLog;
+
+ /**
+ * < Reservation finish event
+ */
+ public rsvFinishLog rsvFinishLog;
+
+ /**
+ * < Host group control Log
+ */
+ public hgCtrlLog hgCtrlLog;
+
+ /**
+ * < cpu profile event
+ */
+ public cpuProfileLog cpuProfileLog;
+
+ /**
+ * < Data logging event
+ */
+ public dataLoggingLog dataLoggingLog;
+
+ /**
+ * < Job run rusage event
+ */
+ public jobRunRusageLog jobRunRusageLog;
+
+ /**
+ * < Event EOS event
+ */
+ public eventEOSLog eventEOSLog;
+
+ /**
+ * < SLA event
+ */
+ public slaLog slaLog;
+
+ /**
+ * < Performance event
+ */
+ public perfmonLog perfmonLog;
+
+ /**
+ * < Task finish event
+ */
+ public taskFinishLog taskFinishLog;
+
+ /**
+ * < Job resize notify start event
+ */
+ public jobResizeNotifyStartLog jobResizeNotifyStartLog;
+
+ /**
+ * < Job resize notify accept event
+ */
+ public jobResizeNotifyAcceptLog jobResizeNotifyAcceptLog;
+
+ /**
+ * < Job resize notify done event
+ */
+ public jobResizeNotifyDoneLog jobResizeNotifyDoneLog;
+
+ /**
+ * < Job resize release event
+ */
+ public jobResizeReleaseLog jobResizeReleaseLog;
+
+ /**
+ * < Job resize cancel event
+ */
+ public jobResizeCancelLog jobResizeCancelLog;
+
+ /**
+ * < Job resize event
+ */
+ public jobResizeLog jobResizeLog;
+
+/*#if defined(LSF_SIMULATOR)*/
+/**< Job array element event */
+ /*public jobArrayElementLog jobArrayElementLog;*/
+
+ /**< LSF simulator status event */
+ /*public mbdSimStatusLog mbdSimStatusLog;*/
+ /*#endif*/
+ }
+
+
+
+
+ /**
+ * \brief event records.
+ */
+ public static class eventRec extends Structure {
+ public static class ByReference extends eventRec implements Structure.ByReference {}
+ public static class ByValue extends eventRec implements Structure.ByValue {}
+ public eventRec() {}
+ public eventRec(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The mbatchd version number
+ */
+ public byte[] version = new byte[MAX_VERSION_LEN];
+
+ /**
+ * < Event type in \ref event_types
+ */
+ public int type;
+
+ /**
+ * < The time the event occurred
+ */
+ public NativeLong eventTime;
+
+ /**
+ * < The information for this type of event, contained in a structure corresponding to type
+ */
+ public eventLog eventLog;
+ }
+
+
+
+ public static class eventLogFile extends Structure {
+ public static class ByReference extends eventLogFile implements Structure.ByReference {}
+ public static class ByValue extends eventLogFile implements Structure.ByValue {}
+ public eventLogFile() {}
+ public eventLogFile(Pointer p) { super(p); read(); }
+
+
+/* event file directory */
+ public byte[] eventDir = new byte[LibLsf.MAXFILENAMELEN];
+
+/* start and end event time */
+ public NativeLong beginTime, endTime;
+ }
+
+
+
+ public static class eventLogHandle extends Structure {
+ public static class ByReference extends eventLogHandle implements Structure.ByReference {}
+ public static class ByValue extends eventLogHandle implements Structure.ByValue {}
+ public eventLogHandle() {}
+ public eventLogHandle(Pointer p) { super(p); read(); }
+
+
+/* open event file pointer */
+ public Pointer fp;
+
+/* current open events file name */
+ public byte[] openEventFile = new byte[LibLsf.MAXFILENAMELEN];
+
+/* current open event file number */
+ public int curOpenFile;
+ public int lastOpenFile; /* last open event file number, 0
+ means lsb.events */
+ }
+
+
+
+
+ public static final String LSF_JOBIDINDEX_FILENAME = "lsb.events.index";
+ public static final String LSF_JOBIDINDEX_FILETAG = "#LSF_JOBID_INDEX_FILE";
+
+/* structures used to handle jobId index file */
+
+ public static class jobIdIndexS extends Structure {
+ public static class ByReference extends jobIdIndexS implements Structure.ByReference {}
+ public static class ByValue extends jobIdIndexS implements Structure.ByValue {}
+ public jobIdIndexS() {}
+ public jobIdIndexS(Pointer p) { super(p); read(); }
+
+
+/* the index file name */
+ public byte[] fileName = new byte[LibLsf.MAXFILENAMELEN];
+
+/* open index file pointer */
+ public Pointer fp;
+
+/* version number for future use */
+ public float version;
+
+/* total number of rows(files) indices */
+ public int totalRows;
+
+/* last update time */
+ public NativeLong lastUpdate;
+
+/* current rows */
+ public int curRow;
+ /* the event file currently handled is */
+ /* (totalRows - curRow + 1) */
+
+/* time stamp of current row */
+ public NativeLong timeStamp;
+
+/* min jobId in that row */
+ public long minJobId;
+
+/* max jobId in that row */
+ public long maxJobId;
+
+/* total number of jobIds */
+ public int totalJobIds;
+
+/* jobId array of current row */
+ public IntByReference jobIds;
+ }
+
+
+
+/* structures used to hold one element of sorted int list */
+
+ public static class sortIntList extends Structure {
+ public static class ByReference extends sortIntList implements Structure.ByReference {}
+ public static class ByValue extends sortIntList implements Structure.ByValue {}
+ public sortIntList() {}
+ public sortIntList(Pointer p) { super(p); read(); }
+
+ public int value;
+
+/* points to next element */
+ public sortIntList.ByReference forw;
+
+/* points to prior element */
+ public sortIntList.ByReference back;
+ }
+
+
+
+ public static class nqsStatusReq extends Structure {
+ public static class ByReference extends nqsStatusReq implements Structure.ByReference {}
+ public static class ByValue extends nqsStatusReq implements Structure.ByValue {}
+ public nqsStatusReq() {}
+ public nqsStatusReq(Pointer p) { super(p); read(); }
+
+ public long jobId;
+ public int opCode;
+ public int reportCode;
+ public String nqsQueue;
+ public int fromUid;
+ public String fromUserName;
+ public String fromHostName;
+ public int idx;
+ }
+
+
+
+ public static class nqsStatusReply extends Structure {
+ public static class ByReference extends nqsStatusReply implements Structure.ByReference {}
+ public static class ByValue extends nqsStatusReply implements Structure.ByValue {}
+ public nqsStatusReply() {}
+ public nqsStatusReply(Pointer p) { super(p); read(); }
+
+ public String orgHost;
+ public String orgUser;
+ public NativeLong startTime;
+ public String jobName;
+ public String nqsQueue;
+ public String lsbManager;
+ public int options;
+ public String outFile;
+ public String errFile;
+ }
+
+
+
+/*
+* SBD uses the following data structure to communicate with
+* the resource manager.
+*
+ */
+ public static final int LSB_MAX_SD_LENGTH = 128;
+
+ public static class lsbMsgHdr extends Structure {
+ public static class ByReference extends lsbMsgHdr implements Structure.ByReference {}
+ public static class ByValue extends lsbMsgHdr implements Structure.ByValue {}
+ public lsbMsgHdr() {}
+ public lsbMsgHdr(Pointer p) { super(p); read(); }
+
+ public int usrId;
+ public long jobId;
+ public int msgId;
+ public int type;
+ public String src;
+ public String dest;
+ }
+
+
+
+ public static class lsbMsg extends Structure {
+ public static class ByReference extends lsbMsg implements Structure.ByReference {}
+ public static class ByValue extends lsbMsg implements Structure.ByValue {}
+ public lsbMsg() {}
+ public lsbMsg(Pointer p) { super(p); read(); }
+
+ public lsbMsgHdr.ByReference header;
+ public String msg;
+ }
+
+
+
+/* data structures related to API_CONF */
+
+ public static final int CONF_NO_CHECK = 0x00;
+ public static final int CONF_CHECK = 0x01;
+ public static final int CONF_EXPAND = 0X02;
+ public static final int CONF_RETURN_HOSTSPEC = 0X04;
+ public static final int CONF_NO_EXPAND = 0X08;
+ public static final int CONF_HAS_CU = 0X10;
+
+ public static class paramConf extends Structure {
+ public static class ByReference extends paramConf implements Structure.ByReference {}
+ public static class ByValue extends paramConf implements Structure.ByValue {}
+ public paramConf() {}
+ public paramConf(Pointer p) { super(p); read(); }
+
+ public parameterInfo.ByReference param;
+ }
+
+
+
+ public static class userConf extends Structure {
+ public static class ByReference extends userConf implements Structure.ByReference {}
+ public static class ByValue extends userConf implements Structure.ByValue {}
+ public userConf() {}
+ public userConf(Pointer p) { super(p); read(); }
+
+ public int numUgroups;
+ public Pointer /* groupInfoEnt.ByReference */ ugroups;
+ public int numUsers;
+ public Pointer /* userInfoEnt.ByReference */ users;
+ public int numUserEquivalent;
+ public Pointer /* userEquivalentInfoEnt.ByReference */ userEquivalent;
+ public int numUserMapping;
+ public Pointer /* userMappingInfoEnt.ByReference */ userMapping;
+ }
+
+
+
+ public static class hostConf extends Structure {
+ public static class ByReference extends hostConf implements Structure.ByReference {}
+ public static class ByValue extends hostConf implements Structure.ByValue {}
+ public hostConf() {}
+ public hostConf(Pointer p) { super(p); read(); }
+
+ public int numHosts;
+ public Pointer /* hostInfoEnt.ByReference */ hosts;
+ public int numHparts;
+ public Pointer /* hostPartInfoEnt.ByReference */ hparts;
+ public int numHgroups;
+ public Pointer /* groupInfoEnt.ByReference */ hgroups;
+ }
+
+
+
+ /**
+ * \brief lsb shared resource Instance.
+ */
+ public static class lsbSharedResourceInstance extends Structure {
+ public static class ByReference extends lsbSharedResourceInstance implements Structure.ByReference {}
+ public static class ByValue extends lsbSharedResourceInstance implements Structure.ByValue {}
+ public lsbSharedResourceInstance() {}
+ public lsbSharedResourceInstance(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Value used by mbatchd
+ */
+ public String totalValue;
+
+ /**
+ * < Reserved value
+ */
+ public String rsvValue;
+
+ /**
+ * < Number of Hosts associated with the resource.
+ */
+ public int nHosts;
+
+ /**
+ * < Hosts list
+ */
+ public Pointer hostList;
+ }
+
+
+
+ /**
+ * \brief lsb shared resource information.
+ */
+ public static class lsbSharedResourceInfo extends Structure {
+ public static class ByReference extends lsbSharedResourceInfo implements Structure.ByReference {}
+ public static class ByValue extends lsbSharedResourceInfo implements Structure.ByValue {}
+ public lsbSharedResourceInfo() {}
+ public lsbSharedResourceInfo(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Resource name
+ */
+ public String resourceName;
+
+ /**
+ * < Number of instances
+ */
+ public int nInstances;
+
+ /**
+ * < List of instances
+ */
+ public Pointer /* lsbSharedResourceInstance.ByReference */ instances;
+ }
+
+
+
+ public static class queueConf extends Structure {
+ public static class ByReference extends queueConf implements Structure.ByReference {}
+ public static class ByValue extends queueConf implements Structure.ByValue {}
+ public queueConf() {}
+ public queueConf(Pointer p) { super(p); read(); }
+
+ public int numQueues;
+ public Pointer /* queueInfoEnt.ByReference */ queues;
+ }
+
+
+
+ /**
+ * \brief frame element information.
+ */
+ public static class frameElementInfo extends Structure {
+ public static class ByReference extends frameElementInfo implements Structure.ByReference {}
+ public static class ByValue extends frameElementInfo implements Structure.ByValue {}
+ public frameElementInfo() {}
+ public frameElementInfo(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The job index in the frame job array.
+ */
+ public int jobindex;
+
+ /**
+ * < The job status.
+ */
+ public int jobState;
+
+ /**
+ * < The start frame of this frame job.
+ */
+ public int start;
+
+ /**
+ * < The end frame of this frame job.
+ */
+ public int end;
+
+ /**
+ * < The step of this frame job.
+ */
+ public int step;
+
+ /**
+ * < The chunk size of this frame job.
+ */
+ public int chunk;
+ }
+
+
+
+ /**
+ * \brief frame job Infomation.
+ */
+ public static class frameJobInfo extends Structure {
+ public static class ByReference extends frameJobInfo implements Structure.ByReference {}
+ public static class ByValue extends frameJobInfo implements Structure.ByValue {}
+ public frameJobInfo() {}
+ public frameJobInfo(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < The job ID that the LSF system assigned to the frame job array.
+ */
+ public long jobGid;
+
+ /**
+ * < The max job number in one frame job array.
+ */
+ public int maxJob;
+
+ /**
+ * < The user submitted the frame job array.
+ */
+ public byte[] userName = new byte[MAX_LSB_NAME_LEN];
+
+ /**
+ * < Full job name
+ */
+ public byte[] jobName = new byte[LibLsf.MAXLINELEN];
+
+ /**
+ * < The full job name of the frame job array. frameElementPtr The pointer to frame ob array table.
+ */
+ public frameElementInfo.ByReference frameElementPtr;
+ }
+
+
+
+ public static class nqsRusageReq extends Structure {
+ public static class ByReference extends nqsRusageReq implements Structure.ByReference {}
+ public static class ByValue extends nqsRusageReq implements Structure.ByValue {}
+ public nqsRusageReq() {}
+ public nqsRusageReq(Pointer p) { super(p); read(); }
+
+ public long jobId;
+ public int mem;
+ public float cpuTime;
+ }
+
+
+
+ public static class nqsRusageReply extends Structure {
+ public static class ByReference extends nqsRusageReply implements Structure.ByReference {}
+ public static class ByValue extends nqsRusageReply implements Structure.ByValue {}
+ public nqsRusageReply() {}
+ public nqsRusageReply(Pointer p) { super(p); read(); }
+
+ public int status;
+ }
+
+
+
+/* end of data structures related to API_CONF */
+
+/*
+* Structure used for the Advance Reservation API
+*
+* MBD allows the LSF administration to make advance reservation on
+* behalf of a user, group or or for system maintenance purposes.
+* Clients can add a reservation, remove a reservation and show
+* reservation statuses. The following data structures are used to
+* encapsulate these requests
+*
+* addRsvRequest: to add a reservation
+* rmRsvRequest: to remove a reservation
+* rsvInfoEnt: to display reservation information
+*
+ */
+
+ public static class _rsvEventInfo_prePost_t extends Structure {
+ public static class ByReference extends _rsvEventInfo_prePost_t implements Structure.ByReference {}
+ public static class ByValue extends _rsvEventInfo_prePost_t implements Structure.ByValue {}
+ public _rsvEventInfo_prePost_t() {}
+ public _rsvEventInfo_prePost_t(Pointer p) { super(p); read(); }
+
+ public int shift;
+ }
+
+
+
+ public static final int RSV_EXECEVENTTYPE_PRE = 1;
+ public static final int RSV_EXECEVENTTYPE_POST = 2;
+
+ public static final String RSV_EXECEVENTNAME_PRE = "pre";
+ public static final String RSV_EXECEVENTNAME_POST = "post";
+
+ /**
+ * \brief reservation excution event
+ */
+ public static class _rsvExecEvent_t extends Structure {
+ public static class ByReference extends _rsvExecEvent_t implements Structure.ByReference {}
+ public static class ByValue extends _rsvExecEvent_t implements Structure.ByValue {}
+ public _rsvExecEvent_t() {}
+ public _rsvExecEvent_t(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Event type
+ */
+ public int type;
+
+ /**
+ * < Boolean: is there additional info?
+ */
+ public int infoAttached;
+
+ /**
+ * < Info pertaining to event, such as offset
+ */
+ public Pointer info;
+ }
+
+
+
+ /**
+ * \brief reservation excution command
+ */
+ public static class _rsvExecCmd_t extends Structure {
+ public static class ByReference extends _rsvExecCmd_t implements Structure.ByReference {}
+ public static class ByValue extends _rsvExecCmd_t implements Structure.ByValue {}
+ public _rsvExecCmd_t() {}
+ public _rsvExecCmd_t(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Full path to the command name
+ */
+ public String path;
+
+ /**
+ * < Size of events array
+ */
+ public int numEvents;
+
+ /**
+ * < Array of events that trigger -exec command
+ */
+ public Pointer /* _rsvExecEvent_t.ByReference */ events;
+ }
+
+
+
+ /**
+ * \addtogroup reservation_option reservation_option
+ * definitions of reservation options.
+ */
+
+ /**
+ * < User
+ */
+ public static final int RSV_OPTION_USER = 0x0001;
+
+ /**
+ * < Group
+ */
+ public static final int RSV_OPTION_GROUP = 0x0002;
+
+ /**
+ * < System
+ */
+ public static final int RSV_OPTION_SYSTEM = 0x0004;
+
+ /**
+ * < Recur
+ */
+ public static final int RSV_OPTION_RECUR = 0x0008;
+
+ /**
+ * < Resource requirement
+ */
+ public static final int RSV_OPTION_RESREQ = 0x0010;
+
+ /**
+ * < Host
+ */
+ public static final int RSV_OPTION_HOST = 0x0020;
+
+ /**
+ * < Open
+ */
+ public static final int RSV_OPTION_OPEN = 0x0040;
+
+ /**
+ * < Delete
+ */
+ public static final int RSV_OPTION_DELETE = 0x0080;
+
+ /**
+ * < Close
+ */
+ public static final int RSV_OPTION_CLOSED = 0x0100;
+
+ /**
+ * < Execute
+ */
+ public static final int RSV_OPTION_EXEC = 0x0200;
+
+ /**
+ * < Remote execute
+ */
+ public static final int RSV_OPTION_RMEXEC = 0x0400;
+
+ /**
+ * < Next instance
+ */
+ public static final int RSV_OPTION_NEXTINSTANCE = 0x0800;
+
+ /**
+ * < Disable
+ */
+ public static final int RSV_OPTION_DISABLE = 0x1000;
+
+ /**
+ * < Add host
+ */
+ public static final int RSV_OPTION_ADDHOST = 0x2000;
+
+ /**
+ * < Remote host
+ */
+ public static final int RSV_OPTION_RMHOST = 0x4000;
+
+ /**
+ * < Description
+ */
+ public static final int RSV_OPTION_DESCRIPTION = 0x8000;
+
+ /**
+ * < Timewindow mode
+ */
+ public static final int RSV_OPTION_TWMOD = 0x10000;
+
+ /**
+ * < Switch open/close
+ */
+ public static final int RSV_OPTION_SWITCHOPENCLOSE = 0x20000;
+
+ /**
+ * < User mode
+ */
+ public static final int RSV_OPTION_USERMOD = 0x40000;
+
+ /**
+ * < Reservation name
+ */
+ public static final int RSV_OPTION_RSVNAME = 0x80000;
+
+ /**
+ * < Expired
+ */
+ public static final int RSV_OPTION_EXPIRED = 0x100000;
+
+ /**
+ * \brief add reservation request.
+ */
+ public static class addRsvRequest extends Structure {
+ public static class ByReference extends addRsvRequest implements Structure.ByReference {}
+ public static class ByValue extends addRsvRequest implements Structure.ByValue {}
+ public addRsvRequest() {}
+ public addRsvRequest(Pointer p) { super(p); read(); }
+
+
+ /**
+ * <Reservation options \ref reservation_option
+ */
+ public int options;
+
+ /**
+ * < User or group for which the reservation is made
+ */
+ public String name;
+
+ /**
+ * < Minimum number of processors the required to run the job. See the -g option of brsvadd.
+ */
+ public int minNumProcs;
+
+ /**
+ * < Maximum number of processors the required to run the job.
+ */
+ public int maxNumProcs;
+
+ /**< Range of number of processors */
+ //struct procRange;
+
+ /**
+ * < The number of invoker specified hosts for the reservation. If numAskedHosts is 0, all qualified hosts will be considered.
+ */
+ public int numAskedHosts;
+
+ /**
+ * < The array of names of invoker specified hosts hosts for the reservation. The number of hosts is given by numAskedHosts. See the -m option of brsvadd.
+ */
+ public Pointer askedHosts;
+
+ /**
+ * < The resource requirements of the reservation. See the -R option of brsvadd.
+ */
+ public String resReq;
+
+ /**
+ * < Active time window for a recurring reservation. See the -t option of brsvadd.
+ */
+ public String timeWindow;
+
+ /**
+ * < Info for the -exec option.
+ */
+ public _rsvExecCmd_t.ByReference execCmd;
+
+ /**
+ * < Description for the reservation to be created. The description must be provided as a double quoted text string. The maximum length is 512 chars. Equivalent to the value of brsvadd -d.
+ */
+ public String desc;
+
+ /**
+ * < User-defined advance reservation name unique in an LSF cluster. The name is a string of letters, numeric chars, underscores, and dashes beginning with a letter. The maximum length of the name is 39 chars. Equivalent to the value of brsvadd -N.
+ */
+ public String rsvName;
+ }
+
+
+
+ /**
+ * \brief remove reservation request.
+ */
+ public static class rmRsvRequest extends Structure {
+ public static class ByReference extends rmRsvRequest implements Structure.ByReference {}
+ public static class ByValue extends rmRsvRequest implements Structure.ByValue {}
+ public rmRsvRequest() {}
+ public rmRsvRequest(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Reservation ID of the reservation that you wish to remove.
+ */
+ public String rsvId;
+ }
+
+
+
+ /**
+ * \brief modifiy reservation request
+ */
+ public static class modRsvRequest extends Structure {
+ public static class ByReference extends modRsvRequest implements Structure.ByReference {}
+ public static class ByValue extends modRsvRequest implements Structure.ByValue {}
+ public modRsvRequest() {}
+ public modRsvRequest(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Reservation ID of the reservation that you wish to modify.
+ */
+ public String rsvId;
+
+ /**
+ * < LSF user name for the reservation. See the -g option of brsvadd. .
+ */
+ public addRsvRequest fieldsFromAddReq;
+
+ /**
+ * < Disabled time duration
+ */
+ public String disabledDuration;
+ }
+
+
+
+ /**
+ * \brief host reservation infromation entry.
+ */
+ public static class hostRsvInfoEnt extends Structure {
+ public static class ByReference extends hostRsvInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends hostRsvInfoEnt implements Structure.ByValue {}
+ public hostRsvInfoEnt() {}
+ public hostRsvInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Host name.
+ */
+ public String host;
+
+ /**
+ * < Number of CPUs reserved on the host.
+ */
+ public int numCPUs;
+
+ /**
+ * < Number of job slots reserved on the host.
+ */
+ public int numSlots;
+
+ /**
+ * < Number of processors reserved on the host.
+ */
+ public int numRsvProcs;
+
+ /**
+ * < Count for used + suspended from reserved slots
+ */
+ public int numusedRsvProcs;
+
+ /**
+ * < Number of processors in use on the host.
+ */
+ public int numUsedProcs;
+ }
+
+
+
+ /**
+ * \brief reservation information entry.
+ */
+ public static class rsvInfoEnt extends Structure {
+ public static class ByReference extends rsvInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends rsvInfoEnt implements Structure.ByValue {}
+ public rsvInfoEnt() {}
+ public rsvInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Reservation options, see \ref reservation_option
+ */
+ public int options;
+
+ /**
+ * < Reservation ID returned from mbatchd. If the reservation fails, this is null. The memory for rsvid is allocated by the caller.
+ */
+ public String rsvId;
+
+ /**
+ * < LSF user group name for the reservation. See the -g option of brsvadd.
+ */
+ public String name;
+
+ /**
+ * < Number of hosts reserved
+ */
+ public int numRsvHosts;
+
+ /**
+ * < Info about the reserved hosts
+ */
+ public Pointer /* hostRsvInfoEnt.ByReference */ rsvHosts;
+
+ /**
+ * < Active time window for a recurring reservation. See the -t option of brsvadd.
+ */
+ public String timeWindow;
+
+ /**
+ * < Number of jobs running in the reservation.
+ */
+ public int numRsvJobs;
+
+ /**
+ * < Job IDs of jobs running in the reservation.
+ */
+ public LongByReference jobIds;
+
+ /**
+ * < Status of jobs running in the reservation.
+ */
+ public IntByReference jobStatus;
+
+ /**
+ * < Description for the reservation to be created. The description must be provided as a double quoted text string. The maximum length is 512 chars. Equivalent to thevalue of brsvadd -d.
+ */
+ public String desc;
+
+ /**
+ * < Null-terminated list of disabled durations
+ */
+ public Pointer disabledDurations;
+
+ /**
+ * < The current state of the reservation - active or inactive.
+ */
+ public int state;
+
+ /**
+ * < The time of the next instance of a recurring reservation.
+ */
+ public String nextInstance;
+
+ /**
+ * < Creator of the reservation.
+ */
+ public String creator;
+ }
+
+
+
+/* backfill window related data structures and functions */
+
+ public static class slotInfoRequest extends Structure {
+ public static class ByReference extends slotInfoRequest implements Structure.ByReference {}
+ public static class ByValue extends slotInfoRequest implements Structure.ByValue {}
+ public slotInfoRequest() {}
+ public slotInfoRequest(Pointer p) { super(p); read(); }
+
+ /* options mask */
+
+/* Option -R */
+ public static int SLOT_OPTION_RESREQ = 0X001;
+
+ public int options;
+
+/* Resource requirement string */
+ public String resReq;
+ }
+
+
+
+/*copy from SRInfo*/
+
+ public static class SRInfoEnt extends Structure {
+ public static class ByReference extends SRInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends SRInfoEnt implements Structure.ByValue {}
+ public SRInfoEnt() {}
+ public SRInfoEnt(Pointer p) { super(p); read(); }
+
+
+/*number of reserved slots*/
+ public int numReserved;
+
+/* job's predicted start time */
+ public NativeLong predictedStartTime;
+ }
+
+
+
+ public static class hostSRInfoEnt extends Structure {
+ public static class ByReference extends hostSRInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends hostSRInfoEnt implements Structure.ByValue {}
+ public hostSRInfoEnt() {}
+ public hostSRInfoEnt(Pointer p) { super(p); read(); }
+
+ public String host;
+ public int hStatus;
+ public int userJobLimit;
+ public int maxJobs;
+ public int numJobs;
+ public int numRUN;
+ public int numSSUSP;
+ public int numUSUSP;
+ public int numRESERVE;
+ public int numSR;
+ public Pointer /* SRInfoEnt.ByReference */ SRInfo;
+ }
+
+
+
+ public static class slotInfoReply extends Structure {
+ public static class ByReference extends slotInfoReply implements Structure.ByReference {}
+ public static class ByValue extends slotInfoReply implements Structure.ByValue {}
+ public slotInfoReply() {}
+ public slotInfoReply(Pointer p) { super(p); read(); }
+
+
+/* to store the time of Master host */
+ public NativeLong masterTime;
+ public int numHosts;
+ public Pointer /* hostSRInfoEnt.ByReference */ hostInfo;
+ public int numAR;
+ public Pointer /* rsvInfoEnt.ByReference */ ARInfo;
+ }
+
+
+
+
+/* the general limit related data structures and functions */
+
+
+ public static final int LSB_RSRC_LIMIT_TYPE_SLOTS = 0;
+ public static final int LSB_RSRC_LIMIT_TYPE_SLOT_PERPSR = 1;
+ public static final int LSB_RSRC_LIMIT_TYPE_MEM = 2;
+ public static final int LSB_RSRC_LIMIT_TYPE_MEM_PERCENT = 3;
+ public static final int LSB_RSRC_LIMIT_TYPE_SWP = 4;
+ public static final int LSB_RSRC_LIMIT_TYPE_SWP_PERCENT = 5;
+ public static final int LSB_RSRC_LIMIT_TYPE_TMP = 6;
+ public static final int LSB_RSRC_LIMIT_TYPE_TMP_PERCENT = 7;
+ public static final int LSB_RSRC_LIMIT_TYPE_JOBS = 8;
+
+/* all external resources */
+ public static final int LSB_RSRC_LIMIT_TYPE_EXT_RSRC = 9;
+
+ /**
+ * \addtogroup _consumertype _consumertype
+ * consumer types
+ */
+ public static interface consumerType {
+ /**
+ * < Queues
+ */
+ public static final int LIMIT_QUEUES = 1;
+
+ /**
+ * < Per-queue
+ */
+ public static final int LIMIT_PER_QUEUE = 2;
+
+ /**
+ * < Users
+ */
+ public static final int LIMIT_USERS = 3;
+
+ /**
+ * < Per-users
+ */
+ public static final int LIMIT_PER_USER = 4;
+
+ /**
+ * < Hosts
+ */
+ public static final int LIMIT_HOSTS = 5;
+
+ /**
+ * < Per-host
+ */
+ public static final int LIMIT_PER_HOST = 6;
+
+ /**
+ * < Projects
+ */
+ public static final int LIMIT_PROJECTS = 7;
+
+ /**
+ * < Per-project
+ */
+ public static final int LIMIT_PER_PROJECT = 8;
+ }
+
+
+ /**< Type definitions */
+
+ /**
+ * \brief limit consumer
+ */
+ public static class _limitConsumer extends Structure {
+ public static class ByReference extends _limitConsumer implements Structure.ByReference {}
+ public static class ByValue extends _limitConsumer implements Structure.ByValue {}
+ public _limitConsumer() {}
+ public _limitConsumer(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Consumer type ( _consumertype ): - Queues per-queue - Users and per-user - Hosts and per-host - Projects and per-project
+ */
+ public int type;
+
+ /**
+ * < Consumer name
+ */
+ public String name;
+ }
+
+
+
+ /**
+ * \brief limit resource.
+ */
+ public static class _limitResource extends Structure {
+ public static class ByReference extends _limitResource implements Structure.ByReference {}
+ public static class ByValue extends _limitResource implements Structure.ByValue {}
+ public _limitResource() {}
+ public _limitResource(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Resource name
+ */
+ public String name;
+
+ /**
+ * < Resource type
+ */
+ public int type;
+
+ /**
+ * < Resource val
+ */
+ public float val;
+ }
+
+
+
+ /**
+ * \brief limit information request
+ */
+ public static class _limitInfoReq extends Structure {
+ public static class ByReference extends _limitInfoReq implements Structure.ByReference {}
+ public static class ByValue extends _limitInfoReq implements Structure.ByValue {}
+ public _limitInfoReq() {}
+ public _limitInfoReq(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Limit policy name given by the user.
+ */
+ public String name;
+
+ /**
+ * < Number of consumers
+ */
+ public int consumerC;
+
+ /**
+ * < Consumer name, queue/host/user/project
+ */
+ public Pointer /* _limitConsumer.ByReference */ consumerV;
+ }
+
+
+
+ /**
+ * \brief limit item.
+ */
+ public static class _limitItem extends Structure {
+ public static class ByReference extends _limitItem implements Structure.ByReference {}
+ public static class ByValue extends _limitItem implements Structure.ByValue {}
+ public _limitItem() {}
+ public _limitItem(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Number of consumers
+ */
+ public int consumerC;
+
+ /**
+ * < Consumers, such as queue, host, user or project
+ */
+ public Pointer /* _limitConsumer.ByReference */ consumerV;
+
+ /**
+ * < Number of resources
+ */
+ public int resourceC;
+
+ /**
+ * < Resources list
+ */
+ public Pointer /* _limitResource.ByReference */ resourceV;
+ }
+
+
+
+ /**
+ * \brief limit information entry .
+ */
+ public static class _limitInfoEnt extends Structure {
+ public static class ByReference extends _limitInfoEnt implements Structure.ByReference {}
+ public static class ByValue extends _limitInfoEnt implements Structure.ByValue {}
+ public _limitInfoEnt() {}
+ public _limitInfoEnt(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Limit policy name given by the user
+ */
+ public String name;
+
+ /**
+ * < Limit configuration
+ */
+ public _limitItem confInfo;
+
+ /**
+ * < Size of limit dynamic usage info array
+ */
+ public int usageC;
+
+ /**
+ * < Limit dynamic usage info array
+ */
+ public Pointer /* _limitItem.ByReference */ usageInfo;
+
+ }
+
+
+
+/* action code for threshold based on type/model, is used for
+* predefinedThresholdTypeModel().
+ */
+
+ public static final int ADD_THRESHOLD = 1;
+ public static final int GET_THRESHOLD = 2;
+ public static final int DEL_THRESHOLD = 3;
+
+/* Structure to hold thresholds defined based on host's type/model */
+
+ public static class thresholdEntry extends Structure {
+ public static class ByReference extends thresholdEntry implements Structure.ByReference {}
+ public static class ByValue extends thresholdEntry implements Structure.ByValue {}
+ public thresholdEntry() {}
+ public thresholdEntry(Pointer p) { super(p); read(); }
+
+
+/* Name of type or model */
+ public String attr;
+
+/* Pointer to hostInfo */
+ public hostInfoEnt.ByReference hostEntryPtr;
+ }
+
+
+
+ /**
+ * \page lsb_limitInfo lsb_limitInfo
+ * \brief gets resource allocation limit configuration and dynamic usage
+ * information.
+ * <p/>
+ * Displays current usage of resource allocation limits configured in Limit
+ * sections in lsb.resources:
+ * \li Configured limit policy name
+ * \li Users
+ * \li Queues
+ * \li Hosts
+ * \li Project names
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_limitInfo( limitInfoReq.ByReference req, limitInfoEnt.ByReference[] limitItemRef,
+ * IntByReference size, lsInfo.ByReference lsInfo)</b>
+ *
+ * @return int:-1
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * blimits
+ * <p/>
+ * \b Files
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.queues \n
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.users \n
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.hosts \n
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.resources
+ * @param req input, the user request for limit information
+ * @param limitItemRef output, the limit information array
+ * @param size output, the size of the limit information array
+ * @param lsInfo Please refer to the \ref lsInfo structure.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * _limitInfoReq
+ * \n _limitConsumer
+ * \n _limitInfoEnt
+ * \n _limitItem
+ * \n _limitResource
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref _consumertype
+ * #see \ref lsb_freeLimitInfoEnt
+ */
+ public static native int lsb_limitInfo(_limitInfoReq req, Pointer limitItemRef, IntByReference size, LibLsf.lsInfo lsInfo);
+
+ /**
+ * \page lsb_freeLimitInfoEnt lsb_freeLimitInfoEnt
+ * \brief Frees the memory allocated by \ref lsb_limitInfo.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * void lsb_freeLimitInfoEnt(limitInfoEnt.ByReference ent, int size)</b>
+ *
+ * @param size input, the size of the limit information array
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * _limitInfoEnt
+ * \n _limitItem
+ * \n _limitConsumer
+ * \n _limitResource
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref _consumertype
+ * return void
+ * \n There's no return value.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * blimits
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.queues \n
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.users \n
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.hosts \n
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.resources
+ * @param ent input, the array of limit information
+ * #see \ref lsb_limitInfo
+ */
+
+ public static native void lsb_freeLimitInfoEnt(_limitInfoEnt ent, int size);
+
+ /**
+ * \addtogroup resizablejob_related resizablejob_related
+ * Resizable job related definitions.
+ */
+
+ /**
+ * < Means release no slots
+ */
+ public static final int LSB_RESIZE_REL_NONE = 0x0;
+
+ /**
+ * < Means release all slots-In this case, nHosts, hosts and slots indicate the slots that are not released
+ */
+ public static final int LSB_RESIZE_REL_ALL = 0x01;
+
+ /**
+ * < Means cancel any pending resize request
+ */
+ public static final int LSB_RESIZE_REL_CANCEL = 0x02;
+
+ /**
+ * < Means execute no resize notification command
+ */
+ public static final int LSB_RESIZE_REL_NO_NOTIFY = 0x04;
+
+ /**
+ * \brief job resize release.
+ */
+ public static class job_resize_release extends Structure {
+ public static class ByReference extends job_resize_release implements Structure.ByReference {}
+ public static class ByValue extends job_resize_release implements Structure.ByValue {}
+ public job_resize_release() {}
+ public job_resize_release(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < LSF job ID
+ */
+ public long jobId;
+
+ /**
+ * < Options is constructed from the bitwise inclusive OR of zero or more of the flags, as defined in \ref resizablejob_related .
+ */
+ public int options;
+
+ /**
+ * < Number of hosts in the hosts list, if no hosts are to be specified this should be zero
+ */
+ public int nHosts;
+
+ /**
+ * < Specified hosts list, nHosts number of elements
+ */
+ public Pointer hosts;
+
+ /**
+ * < Slots list, each element specifies the number of slots per corresponding host (0 implies all), nHosts number of elements
+ */
+ public IntByReference slots;
+
+ /**
+ * < Name and location of notification command
+ */
+ public String notifyCmd;
+ }
+
+
+
+ public static class job_resize_request extends Structure {
+ public static class ByReference extends job_resize_request implements Structure.ByReference {}
+ public static class ByValue extends job_resize_request implements Structure.ByValue {}
+ public job_resize_request() {}
+ public job_resize_request(Pointer p) { super(p); read(); }
+
+ public long jobId;
+ public int options;
+
+/* array size */
+ public int nHosts;
+
+/* array of hosts */
+ public Pointer hosts;
+
+/* notifocation command */
+ public String notifyCmd;
+ }
+
+
+
+/*
+* End of resizable job related definitions
+ */
+
+/* Job Dependency Display */
+
+
+/* Job Dependency Display */
+/* for options */
+ /**
+ * \addtogroup query_depend query_depend
+ * Job Dependency Display for options
+ */
+
+ /**
+ * < Recursively
+ */
+ public static final int QUERY_DEPEND_RECURSIVELY = 0x1;
+
+ /**
+ * < Detail
+ */
+ public static final int QUERY_DEPEND_DETAIL = 0x2;
+
+ /**
+ * < Unsatisfied
+ */
+ public static final int QUERY_DEPEND_UNSATISFIED = 0x4;
+
+ /**
+ * < Child
+ */
+ public static final int QUERY_DEPEND_CHILD = 0x8;
+
+ /**
+ * \brief job dependent request.
+ */
+
+ public static class jobDepRequest extends Structure {
+ public static class ByReference extends jobDepRequest implements Structure.ByReference {}
+ public static class ByValue extends jobDepRequest implements Structure.ByValue {}
+ public jobDepRequest() {}
+ public jobDepRequest(Pointer p) { super(p); read(); }
+
+ /**
+ * < Job ID of the queried job or job array.
+ */
+ public long jobId;
+
+ /**
+ * < You can set the following bits into this field:\n QUERY_DEPEND_RECURSIVELY\n Query the dependency information recursively.\n QUERY_DEPEND_DETAIL\n Query the detailed dependency information.\n QUERY_DEPEND_UNSATISFIED\n Query the jobs that cause this job pend.\n QUERY_DEPEND_CHILD\n Query child jobs.
+ */
+ public int options;
+
+ /**
+ * < The level when you set QUERY_DEPEND_RECURSIVELY.
+ */
+ public int level;
+ }
+
+
+
+
+ /**
+ * \brief queried jobs.
+ */
+ public static class queriedJobs extends Structure {
+ public static class ByReference extends queriedJobs implements Structure.ByReference {}
+ public static class ByValue extends queriedJobs implements Structure.ByValue {}
+ public queriedJobs() {}
+ public queriedJobs(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Job ID of the queried job or job array.
+ */
+ public long jobId;
+
+ /**
+ * < The whole dependency condition of the job.
+ */
+ public String dependcondition;
+
+ /**
+ * < Whether the condition is satisfied.
+ */
+ public int satisfied;
+ }
+
+
+
+/* for hasDependency */
+ /**
+ * \addtogroup job_has_depend job_has_depend
+ * options for hasDependency
+ */
+
+ /**
+ * < Job has dependency
+ */
+ public static final int JOB_HAS_DEPENDENCY = 0x1;
+
+ /**
+ * < Job has individual condition.
+ */
+ public static final int JOB_HAS_INDIVIDUAL_CONDITION = 0x2;
+
+ /**
+ * \brief dependency jobs.
+ */
+
+ public static class dependJobs extends Structure {
+ public static class ByReference extends dependJobs implements Structure.ByReference {}
+ public static class ByValue extends dependJobs implements Structure.ByValue {}
+ public dependJobs() {}
+ public dependJobs(Pointer p) { super(p); read(); }
+
+ /**
+ * < Job ID. By default, it is the parent job of the queried job. Modify to child job by setting QUERY_DEPEND_CHILD in options of JobDepRequest.
+ */
+ public long jobId;
+
+ /**
+ * < The job name associated with the job ID.
+ */
+ public String jobname;
+
+ /**
+ * < The number of degrees of separation from the original job.
+ */
+ public int level;
+
+ /**
+ * < Job status of the job.
+ */
+ public int jobstatus;
+
+ /**
+ * < Whether the job ID has a dependency or not. When you set QUERY_DEPEND_RECURSIVELY in options of JobDepRequest, 0 indicates job ID does not have a dependency. Otherwise, one or more of the following bits displays:- JOB_HAS_DEPENDENCY: Job has a dependency.- JOB_HAS_INDIVIDUAL_CONDITION: Job has an individual dependency condition when it is an element of job array.
+ */
+ public int hasDependency;
+
+ /**
+ * < When you set "QUERY_DEPEND_DETAIL" into options, it is dependency condition of jobId. It is "" when you do not set "QUERY_DEPEND_DETAIL".
+ */
+ public String condition;
+
+ /**
+ * < Whether the condition is satisfied.
+ */
+ public int satisfied;
+
+ /**
+ * < Job ID. By default, it is the child job. Modify to parent job by setting QUERY_DEPEND_CHILD in options of JobDepRequest
+ */
+ public long depJobId;
+ }
+
+
+
+ /**
+ * \brief job dependent information.
+ */
+
+ public static class jobDependInfo extends Structure {
+ public static class ByReference extends jobDependInfo implements Structure.ByReference {}
+ public static class ByValue extends jobDependInfo implements Structure.ByValue {}
+ public jobDependInfo() {}
+ public jobDependInfo(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < You can set the following bits into this field:\n QUERY_DEPEND_RECURSIVELY\n Query the dependency information recursively.\n QUERY_DEPEND_DETAIL\n Query the detailed dependency information.\n QUERY_DEPEND_UNSATISFIED\n Query the jobs that cause this job pend.\n QUERY_DEPEND_CHILD\n Query child jobs.
+ */
+ public int options;
+
+ /**
+ * < The number of jobs you queried. By default, the value is 1. However, when you set QUERY_DEPEND_DETAIL in the options and you query a job array where some elements have a dependency condition that has changed, the value is the number of the changed element + 1.
+ */
+ public int numQueriedJobs;
+
+ /**
+ * < The jobs you queried.
+ */
+ public Pointer /* queriedJobs.ByReference */ queriedJobs;
+
+ /**
+ * < The number of levels returned.
+ */
+ public int level;
+
+ /**
+ * < The number of jobs returned.
+ */
+ public int numJobs;
+
+ /**
+ * < The returned dependency jobs.
+ */
+ public Pointer /* dependJobs.ByReference */ depJobs;
+ }
+
+
+
+
+/*
+* Functional prototypes of the Advance Reservation API
+ */
+
+
+/* Macros */
+
+ public static boolean IS_PEND(int s) {
+ return (JNAUtils.toBoolean((s) & JOB_STAT_PEND) || JNAUtils.toBoolean((s) & JOB_STAT_PSUSP));
+ }
+
+/* Do not test JOB_STAT_UNKWN in IS_START() */
+
+ public static boolean IS_START(int s) {
+ return (JNAUtils.toBoolean((s) & JOB_STAT_RUN) || JNAUtils.toBoolean((s) & JOB_STAT_SSUSP) || JNAUtils.toBoolean((s) & JOB_STAT_USUSP));
+ }
+
+ public static boolean IS_FINISH(int s) {
+ return (JNAUtils.toBoolean((s) & JOB_STAT_DONE) || JNAUtils.toBoolean((s) & JOB_STAT_EXIT));
+ }
+
+ public static boolean IS_SUSP(int s) {
+ return (JNAUtils.toBoolean((s) & JOB_STAT_PSUSP) || JNAUtils.toBoolean((s) & JOB_STAT_SSUSP) || JNAUtils.toBoolean((s) & JOB_STAT_USUSP));
+ }
+
+/* Macro for checking post job process. (IO_SPOOL) */
+
+ public static boolean IS_POST_DONE(int s) {
+ return (((s) & JOB_STAT_PDONE) == JOB_STAT_PDONE);
+ }
+
+ public static boolean IS_POST_ERR(int s) {
+ return (((s) & JOB_STAT_PERR) == JOB_STAT_PERR);
+ }
+
+ public static boolean IS_POST_FINISH(int s) {
+ return (IS_POST_DONE(s) || IS_POST_ERR(s));
+ }
+
+/*On windows ,for dll library ,need to use _declspec(dllexport) to export
+*a symbol .but if do so ,static library will can not work .so we are going
+*to change lsberrno to a function.
+*/
+
+ public static int lsberrno() {
+ return lsb_errno().getValue();
+ }
+
+
+
+
+/*
+* Version of the mbatchd that was last contacted.
+* -1 indicates the mbatchd has not been contacted.
+ */
+ //public int lsb_mbd_version;
+
+/*
+* The data definition for host name list operations
+ */
+ public static final int PRINT_SHORT_NAMELIST = 0x01;
+ public static final int PRINT_LONG_NAMELIST = 0x02;
+ public static final int PRINT_MCPU_HOSTS = 0x04;
+
+ public static class nameList extends Structure {
+ public static class ByReference extends nameList implements Structure.ByReference {}
+ public static class ByValue extends nameList implements Structure.ByValue {}
+ public nameList() {}
+ public nameList(Pointer p) { super(p); read(); }
+
+
+/* number of names */
+ public int listSize;
+
+/* a group of names */
+ public Pointer names;
+
+/* the ocurrent of corresponding name */
+ public IntByReference counter;
+ }
+
+
+
+ public static native nameList.ByReference lsb_parseShortStr(String string1, int int1);
+
+ public static native nameList.ByReference lsb_parseLongStr(String string1);
+
+ public static native String lsb_printNameList(nameList namelist1, int int1);
+
+ public static native nameList.ByReference lsb_compressStrList(Pointer stringArray1, int int1);
+
+ public static native String lsb_splitName(String string1, IntByReference int1);
+
+ public static native IntByReference lsb_errno();
+
+
+/* external routines related to API_CONF */
+
+ public static native paramConf.ByReference lsb_readparam(LibLsf.lsConf lsConf1);
+
+ public static native userConf.ByReference lsb_readuser(LibLsf.lsConf lsConf1, int int1, LibLsf.clusterConf clusterConf1);
+
+ public static native userConf.ByReference lsb_readuser_ex(LibLsf.lsConf lsConf1, int int1, LibLsf.clusterConf clusterConf1, LibLsf.sharedConf sharedConf1);
+
+ public static native hostConf.ByReference lsb_readhost(LibLsf.lsConf lsConf1, LibLsf.lsInfo lsInfo1, int int1, LibLsf.clusterConf clusterConf1);
+
+ public static native queueConf.ByReference lsb_readqueue(LibLsf.lsConf lsConf1, LibLsf.lsInfo lsInfo1, int int1, LibLsf.sharedConf sharedConf1, LibLsf.clusterConf clusterConf1);
+
+ public static native void updateClusterConf(LibLsf.clusterConf clusterConf1);
+
+/* end of external routines related to API_CONF */
+
+ /**
+ * \page lsb_hostpartinfo lsb_hostpartinfo
+ * Returns informaton about host partitions.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * hostPartInfoEnt.ByReference lsb_hostpartinfo (String[] hostParts,
+ * IntByReference numHostParts)</b> @param hostParts An array of host partition names.
+ *
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * <b>Errors:</b>
+ * \par
+ * If the function fails, lsberrno is set to indicate the error. If lsberrno is
+ * LSBE_BAD_HPART, (*hostParts)[*numHostParts] is not a host partition known
+ * to the LSF system. Otherwise, if.ByReference numHostParts is less than its original value,
+ * * numHostParts is the actual number of host partitions found.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.hosts
+ * @param numHostHosts The number of host partition names.
+ * To get information on all host partitions, set hostParts to null;* numHostParts
+ * will be the actual number of host partitions when this call returns.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * hostPartInfoEnt
+ * \n hostPartUserInfo
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * #see \ref lsb_usergrpinfo
+ * #see \ref lsb_hostgrpinfo
+ * @param stringArray1 stringArray1
+ */
+ public static native hostPartInfoEnt.ByReference lsb_hostpartinfo(Pointer stringArray1, IntByReference numHostHosts);
+
+ /**
+ * \page lsb_init lsb_init
+ * \brief Initializes the LSF batch library (LSBLIB), and gets the
+ * configuration environment.
+ * <p/>
+ * You must use \ref lsb_init before any other LSBLIB library routine in your
+ * application.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_init(String appname)</b>
+ *
+ * @return int:-1 \n
+ * The function failed.
+ * <p/>
+ * <b>Errors:</b>
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param appName The name of your application.
+ * If appName holds the name of your application, a logfile with the same
+ * name as
+ * your application receives LSBLIB transaction information.
+ * If appName is null, the logfile $LSF_LOGDIR/bcmd receives LSBLIB
+ * transaction information.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * see none
+ */
+ public static native int lsb_init(String appName);
+
+ public static native int sch_lsb_init();
+
+ /**
+ * \page lsb_openjobinfo lsb_openjobinfo
+ * \brief Returns the number of jobs in the master batch daemon.
+ * <p/>
+ * \ref lsb_openjobinfo accesses information about pending, running and
+ * suspended jobs in the master batch daemon. Use \ref lsb_openjobinfo to
+ * create a connection to the master batch daemon. Next, use \ref lsb_readjobinfo
+ * to read job records.Close the connection using \ref lsb_closejobinfo.
+ * <p/>
+ * \ref lsb_openjobinfo opens a connection with mbatchd and returns the total
+ * number of records in the connection on success.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_openjobinfo(long jobId, String jobName,
+ * String userName, String queueName, String hostName,
+ * int options)</b>
+ *
+ * @param jobId Passes information about jobs with the given job ID.
+ * If jobId is 0, \ref lsb_openjobinfo looks to another parameter to return
+ * information about jobs.If a member of a job array is to be passed, use
+ * the array form jobID[ i ] where jobID is the job array name, and i is
+ * the index value.
+ * @param options <lsf/lsbatch.h> defines the flags shown in
+ * \ref defs_lsb_openjobinfo constructed from bits. Use the bitwise OR to set more
+ * than one flag.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref defs_lsb_openjobinfo_a
+ * \n \ref defs_lsb_openjobinfo
+ * @return int:-1 \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * bjobs
+ * <p/>
+ * \b Files:
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param jobName Passes information about jobs with the given job name.
+ * If jobName is null, \ref lsb_openjobinfo looks to another parameter to return
+ * information about jobs.
+ * @param userName Passes information about jobs submitted by the named user
+ * or user group, or by all users if user is all. If user is null,
+ * \ref lsb_openjobinfo assumes the user is invoking this call.
+ * @param queueName Passes information about jobs belonging to the named
+ * queue. If queue is null,jobs in all the queues of the batch system are counted.
+ * @param hostName Passes information about jobs on the named host, host
+ * group or cluster name. If host is null, jobs on all hosts of the batch
+ * system will be considered.
+ * #see \ref lsb_openjobinfo_a
+ * #see \ref lsb_openjobinfo_a_ext
+ * #see \ref lsb_openjobinfo_req
+ * #see \ref lsb_closejobinfo
+ * #see \ref lsb_readjobinfo
+ * #see \ref lsb_readframejob
+ */
+ public static native int lsb_openjobinfo(long jobId, String jobName, String userName, String queueName, String hostName, int options);
+
+ /**
+ * \page lsb_openjobinfo_a lsb_openjobinfo_a
+ * \brief Provides the name and number of jobs and hosts in the master batch
+ * daemon.
+ * <p/>
+ * \ref lsb_openjobinfo_a provides more information on pending, running and
+ * suspended jobs than \ref lsb_openjobinfo. Use \ref lsb_openjobinfo_a to create a
+ * connection to the master batch daemon. Next, use \ref lsb_readjobinfo to read
+ * job records. Close the connection using \ref lsb_closejobinfo.
+ * <p/>
+ * \ref lsb_openjobinfo_a passes information about jobs based on the value of
+ * jobId,jobName, userName, queueName, or hostName. Only one parameter can be
+ * chosen. The other parameters must be null or 0.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * jobInfoHead.ByReference lsb_openjobinfo_a(long jobId,
+ * String jobName,
+ * String userName,
+ * String queueName,
+ * String hostName,
+ * int options)</b>
+ *
+ * @param jobId Passes information about jobs with the given job ID. If jobId
+ * is 0, \ref lsb_openjobinfo looks to another parameter to return information
+ * about jobs.
+ * If information about a member of a job array is to be passed, use the array
+ * form jobID[ i ] where jobID is the job array name, and i is the index value.
+ * @param options <lsf/lsbatch.h> defines the flags shown in def_lsb_openjobinfo_a
+ * constructed from bits. Use the bitwise OR to set more than one flag.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * jobInfoHead
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref defs_lsb_openjobinfo_a
+ * @return null \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * bjobs
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf \n
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * @param jobName Passes information about jobs with the given job name. If
+ * jobName is null, \ref lsb_openjobinfo looks to another parameter to return
+ * information about jobs.
+ * @param userName Passes information about jobs submitted by the named user
+ * or user group, or by all users if userName is all. If userName is null,
+ * \ref lsb_openjobinfo_a assumes the user is invoking this call.
+ * @param queueName Passes information about jobs belonging to the named queue.
+ * If queueName is null, jobs in all queues of the batch system will be
+ * considered.
+ * @param hostName Passes information about jobs on the named host, host group
+ * or cluster name. If hostName is null, jobs on all hosts of the batch system
+ * will be considered.
+ * #see \ref lsb_openjobinfo
+ * #see \ref lsb_closejobinfo
+ * #see \ref lsb_readjobinfo
+ * #see \ref lsb_readframejob
+ */
+ public static native jobInfoHead.ByReference lsb_openjobinfo_a(long jobId, String jobName, String userName, String queueName, String hostName, int options);
+
+ /**
+ * \page lsb_openjobinfo_a_ext lsb_openjobinfo_a_ext
+ * \brief Returns the name and number of jobs and hosts in the master batch
+ * daemon with additional host group information.
+ * <p/>
+ * \ref lsb_openjobinfo_a_ext is run from \ref lsb_openjobinfo_a using the same
+ * parameters and provides the same information as \ref lsb_openjobinfo_a, but with
+ * additional host group information.
+ * <p/>
+ * \ref lsb_openjobinfo_a_ext passes information about jobs based on the value of
+ * jobId, jobName, userName, queueName, or hostName. Only one parameter can be
+ * chosen. The other parameters must be null or 0.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * jobInfoHeadExt.ByReference
+ * lsb_openjobinfo_a_ext (long jobId, String jobName,
+ * String userName, String queueName,
+ * String hostName, int options)</b>
+ *
+ * @param jobId Passes information about jobs with the given job ID. If jobId
+ * is 0, \ref lsb_openjobinfo_a_ext looks to another parameter to return information
+ * about jobs. If information about a member of a job array is to be passed, use
+ * the array form jobID[ i ] where jobID is the job array name, and i is the
+ * index value.
+ * @param options <lsf/lsbatch.h> defines the flags shown in
+ * def_lsb_openjobinfo_a constructed from bits. Use the bitwise OR to set more
+ * than one flag.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * jobInfoHeadExt
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref defs_lsb_openjobinfo_a
+ * @return null \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * bjobs
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf \n
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * @param jobName Passes information about jobs with the given job name. If
+ * jobName is null, \ref lsb_openjobinfo_a_ext looks to another parameter to return
+ * information about jobs.
+ * @param userName Passes information about jobs submitted by the named user
+ * or user group, or by all users if userName is all. If userName is null,
+ * \ref lsb_openjobinfo_a_ext assumes the user is invoking this call.
+ * @param queueName Passes information about jobs belonging to the named queue.
+ * If queueName is null, jobs in all queues of the batch system will be considered.
+ * @param hostName Passes information about jobs on the named host, host group
+ * or cluster name. If hostName is null, jobs on all hosts of the batch system
+ * will be considered.
+ * #see \ref lsb_openjobinfo
+ * #see \ref lsb_closejobinfo
+ * #see \ref lsb_readjobinfo
+ * #see \ref lsb_readframejob
+ */
+ public static native jobInfoHeadExt.ByReference lsb_openjobinfo_a_ext(long jobId, String jobName, String userName, String queueName, String hostName, int options);
+
+ /**
+ * \page lsb_openjobinfo_req lsb_openjobinfo_req
+ * \brief Extensible API.
+ * <p/>
+ * Instead of submitting individual requests this API defines
+ * all job info requests as objects, and can easily be enhanced to include
+ * additinal requests.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * jobInfoHeadExt.ByReference lsb_openjobinfo_req (jobInfoReq.ByReference req)</b>
+ *
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * none
+ * <p/>
+ * \b Files:
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param req job information request.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * jobInfoReq
+ * \n \ref jobInfoHeadExt
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref defs_lsb_openjobinfo_a
+ * \n \ref defs_lsb_openjobinfo
+ * #see \ref lsb_openjobinfo_a
+ * #see \ref lsb_openjobinfo_a_ext
+ * #see \ref lsb_closejobinfo
+ * #see \ref lsb_readjobinfo
+ * #see \ref lsb_readframejob
+ */
+ public static native jobInfoHeadExt.ByReference lsb_openjobinfo_req(jobInfoReq req);
+
+ public static native int lsb_queryjobinfo(int int1, NativeLongByReference long1, String string1);
+
+ public static native jobInfoEnt.ByReference lsb_fetchjobinfo(IntByReference int1, int int2, NativeLongByReference long1, String string1);
+
+ public static native jobInfoEnt.ByReference lsb_fetchjobinfo_ext(IntByReference int1, int int2, NativeLongByReference long1, String string1, jobInfoHeadExt jobInfoHeadExt);
+
+ /**
+ * \page lsb_readjobinfo lsb_readjobinfo
+ * \brief Returns the next job information record in mbatchd.
+ * <p/>
+ * \ref lsb_readjobinfo reads the number of records defined by the more parameter.
+ * The more parameter receives its value from either \ref lsb_openjobinfo or
+ * \ref lsb_openjobinfo_a. Each time \ref lsb_readjobinfo is called, it returns one
+ * record from mbatchd. Use \ref lsb_readjobinfo in a loop and use more to
+ * determine how many times to repeat the loop to retrieve job information records.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * \n \#include <time.h>
+ * \n \#include <lsf/lsf.h>
+ * <p/>
+ * jobInfoEnt.ByReference lsb_readjobinfo(IntByReference more)</b>
+ *
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If there are no more records, then lsberrno is set to LSBE_EOF.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.queues
+ * @param more Number of job records in the master batch daemon.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * jobInfoEnt
+ * \n jobExternalMsgReply
+ * \n jRusage
+ * \n pidInfo
+ * \n reserveItem
+ * \n submit
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref job_states
+ * \n \ref jobgroup_counterIndex
+ * \n \ref group_nodetypes
+ * #see \ref lsb_openjobinfo
+ * #see \ref lsb_openjobinfo_a
+ * #see \ref lsb_closejobinfo
+ * #see \ref lsb_hostinfo
+ * #see \ref lsb_pendreason
+ * #see \ref lsb_queueinfo
+ * #see \ref lsb_suspreason
+ */
+ public static native jobInfoEnt.ByReference lsb_readjobinfo(IntByReference more);
+
+ /**
+ * \page lsb_submit lsb_submit
+ * Submits or restarts a job in the batch system.
+ * <p/>
+ * \ref lsb_submit submits or restarts a job in the batch system according to the
+ * jobSubReq specification.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * long lsb_submit (submit.ByReference jobSubReq,
+ * submitReply.ByReference jobSubReply)</b>
+ *
+ * @return long:-1 \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * If the environment variable BSUB_CHK_RESREQ is set, the value of lsberrno is
+ * either LSBE_RESREQ_OK or LSBE_RESREQ_ERR, depending on the result of
+ * resource requirement string checking. The badJobName field in the submitReply
+ * structure contains the detailed error message.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * bsub
+ * \n brestart
+ * <p/>
+ * \b Files:
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param jobSubReq
+ * Describes the requirements for job submission to the batch system.
+ * A job that does not meet these requirements is not submitted to the
+ * batch system and an error is returned.
+ * @param jobSubReply
+ * Describes the results of the job submission to the batch system.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * submit
+ * \n submitReply
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref lsb_submit_options
+ * \n \ref lsb_submit_options2
+ * \n \ref lsb_submit_options3
+ * #see \ref lsb_modify
+ * #see \ref ls_info
+ * #see \ref lsb_queueinfo
+ */
+ public static native long lsb_submit(submit jobSubReq, submitReply jobSubReply);
+
+ /**
+ * \page lsb_readjobinfo_cond lsb_readjobinfo_cond
+ * \brief Returns the next job information record for condensed host groups
+ * in mbatchd.
+ * <p/>
+ * \ref lsb_readjobinfo_cond reads the number of records defined by the more
+ * parameter. The more parameter receives its value from either \ref lsb_openjobinfo
+ * or \ref lsb_openjobinfo_a. Each time \ref lsb_readjobinfo_cond is called, it
+ * returns one record from mbatchd. Use \ref lsb_readjobinfo_cond in a loop and use
+ * more to determine how many times to repeat the loop to retrieve job information
+ * records.
+ * <p/>
+ * \ref lsb_readjobinfo_cond differs from \ref lsb_readjobinfo in that if jInfoHExt
+ * is not null, \ref lsb_readjobinfo_cond substitutes hostGroup (if it is a condensed
+ * host group) for job execution hosts.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * \n \#include <time.h>
+ * \n \#include <lsf/lsf.h>
+ * <p/>
+ * jobInfoEnt.ByReference lsb_readjobinfo_cond(IntByReference more,
+ * jobInfoHeadExt.ByReference jInfoHExt);</b>
+ *
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If there are no more records, then lsberrno is set to LSBE_EOF.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.queues
+ * @param more Number of job records in the master batch daemon.
+ * @param jInfoHExt Job information header info for the condensed host group.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * jobInfoEnt
+ * \n jobExternalMsgReply
+ * \n jRusage
+ * \n pidInfo
+ * \n reserveItem
+ * \n submit
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref external_msg_processing
+ * \n \ref group_nodetypes
+ * #see \ref lsb_openjobinfo
+ * #see \ref lsb_openjobinfo_a
+ * #see \ref lsb_closejobinfo
+ * #see \ref lsb_hostinfo
+ * #see \ref lsb_pendreason
+ * #see \ref lsb_queueinfo
+ * #see \ref lsb_readjobinfo
+ * #see \ref lsb_suspreason
+ */
+ public static native jobInfoEnt.ByReference lsb_readjobinfo_cond(IntByReference more, jobInfoHeadExt jInfoHExt);
+
+ /**
+ * \page lsb_readframejob lsb_readframejob
+ * \brief Returns all frame jobs information which matchs the specified
+ * parameters and fills related information into the frame job information table.
+ * <p/>
+ * \ref lsb_readframejob gets all frame jobs information that matches the specified
+ * parameters and fills related information into the frame job information table.
+ * \ref lsb_readframejob is a wrapper of \ref lsb_openjobinfo, \ref lsb_readjobinfo, and
+ * \ref lsb_closejobinfo. Memory allocated in frameJobInfoTbl will be freed by
+ * user.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_readframejob(long jobId, String frameName,
+ * String user, String queue, String host, int options,
+ * frameJobInfo.ByReference[] frameJobInfoTbl)</b>
+ *
+ * @param jobId Get information about the frame jobs with the given job ID.
+ * If jobID is 0, get information about frame jobs which satisfy the other
+ * specifications. If a job in a job array is to be modified, use the array
+ * form jobID[i] where jobID is the job array name, and i is the index value.
+ * @param options <lsf/lsbatch.h> defines the following flags \ref defs_lsb_openjobinfo_a
+ * constructed from bits. Use the bitwise OR to set more than one flag.
+ * @return int:-1
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param frameName Get information about frame jobs with the given frame name.
+ * @param user Get information about frame jobs submitted by the named user
+ * or user group, or by all users if user is all. If user is null, the user
+ * invoking this routine is assumed.
+ * @param queue Get information about frame jobs belonging to the named queue.
+ * If queue is null,jobs in all queues of the batch system will be considered.
+ * @param host Get information about frame jobs on the named host, host
+ * group or cluster name.If host is null, jobs on all hosts of the batch
+ * system will be considered.
+ * @param frameJobInfoTbl The result of all frame jobs information.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * \n frameJobInfo
+ * \n frameElementInfo
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * #see \ref lsb_openjobinfo
+ * #see \ref lsb_readjobinfo
+ * #see \ref lsb_closejobinfo
+ */
+
+ public static native int lsb_readframejob(long jobId, String frameName, String user, String queue, String host, int options, Pointer frameJobInfoTbl);
+
+ /**
+ * \page lsb_closejobinfo lsb_closejobinfo
+ * \brief Closes job information connection with the master batch daemon.
+ * <p/>
+ * Use \ref lsb_closejobinfo to close the connection to the master batch daemon
+ * after opening a job information connection with \ref lsb_openjobinfo and reading
+ * job records with \ref lsb_readjobinfo.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * void lsb_closejobinfo()</b>
+ *
+ * param void \n
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * return void
+ * \n There's no returns value.
+ * <p/>
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * #see \ref lsb_openjobinfo
+ * #see \ref lsb_openjobinfo_a
+ * #see \ref lsb_readjobinfo
+ */
+
+ public static native void lsb_closejobinfo();
+
+ /**
+ * \page lsb_hostcontrol lsb_hostcontrol
+ * Opens or closes a host, or restarts or shuts down its slave batch daemon.
+ * <p/>
+ * \ref lsb_hostcontrol opens or closes a host, or restarts or shuts down its
+ * slave batch daemon. Any program using this API must be setuid to root if
+ * LSF_AUTH is not defined in the lsf.conf file.
+ * <p/>
+ * To restart the master batch daemon, mbatchd, in order to use updated
+ * batch LSF configuration files, use \ref lsb_reconfig.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_hostcontrol (hostCtrlReq.ByReference req)</b>
+ *
+ * @return int:-1 \n
+ * Function failed.
+ * <p/>
+ * <b>Errors:</b>
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param req The host control request.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * hostCtrlReq
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref host_ctrl_option
+ * #see \ref lsb_reconfig
+ */
+ public static native int lsb_hostcontrol(hostCtrlReq req);
+
+ public static native int lsb_hghostcontrol(hgCtrlReq hostCtrlReq1, hgCtrlReply reply);
+
+ /**
+ * \page lsb_queueinfo lsb_queueinfo
+ * \brief Returns information about batch queues.
+ * <p/>
+ * \ref lsb_queueinfo gets information about batch queues. See lsb.queues for more
+ * information about queue parameters.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * queueInfoEnt.ByReference lsb_queueinfo(String[] queues,
+ * IntByReference numQueues, String hosts, String users,
+ * int options)</b>
+ *
+ * @param options Reserved for future use; supply 0.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * queueInfoEnt
+ * \n shareAcctInfoEnt
+ * \n apsFactorInfo
+ * \n apsFactorMap
+ * \n apsLongNameMap
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref queue_status
+ * \n \ref queue_attribute
+ * @return null
+ * \n Function Failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * If lsberrno is LSBE_BAD_QUEUE, (*queues)[*numQueues] is not a queue known
+ * to the LSF system. Otherwise, if.ByReference numQueues is less than its original value,
+ * * numQueues is the actual number of queues found.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * bqueues
+ * <p/>
+ * \b Files:
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.queues
+ * @param queues An array of names of queues of interest.
+ * @param numQueues The number of queue names. To get information on all queues,
+ * set.ByReference numQueues to 0;* numQueues will be updated to the actual number of
+ * queues when this call returns.If.ByReference numQueues is 1 and queues is null,
+ * information on the system default queue is returned.
+ * @param hosts The host or cluster names. If hosts is not null, then only
+ * the queues that are enabled for the hosts are of interest.
+ * @param user The name of user. If user is not null, then only the queues
+ * that are enabled for the user are of interest.
+ * #see \ref lsb_hostinfo
+ * #see \ref lsb_userinfo
+ * #see \ref lsb_usergrpinfo
+ */
+ public static native queueInfoEnt.ByReference lsb_queueinfo(Pointer queues, IntByReference numQueues, String hosts, String user, int options);
+
+ /**
+ * \page lsb_reconfig lsb_reconfig
+ * \brief Dynamically reconfigures an LSF batch system.
+ * <p/>
+ * \ref lsb_reconfig dynamically reconfigures an LSF batch system to pick up new
+ * configuration parameters and changes to the job queue setup since system
+ * startup or the last reconfiguration (see lsb.queues).
+ * <p/>
+ * To restart a slave batch daemon, use \ref lsb_hostcontrol. This call is
+ * successfully invoked only by root or by the LSF administrator.
+ * <p/>
+ * Any program using this API must be setuid to root if LSF_AUTH is not
+ * defined in the lsf.conf file.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_reconfig (mbdCtrlReq.ByReference req)</b>
+ *
+ * @return int:-1 \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * badmin reconfig
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param req mbatchd control request.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * mbdCtrlReq
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref mbd_operation
+ * #see \ref lsb_openjobinfo
+ */
+ public static native int lsb_reconfig(mbdCtrlReq req);
+
+ /**
+ * \page lsb_signaljob lsb_signaljob
+ * \brief Sends a signal to a job.
+ * <p/>
+ * Use \ref lsb_signaljob when migrating a job from one host to another. Use
+ * \ref lsb_signaljob to stop or kill a job on a host before using \ref lsb_mig to
+ * migrate the job. Next, use \ref lsb_signaljob to continue the stopped job at
+ * the specified host.
+ * <p/>
+ * Generally, use \ref lsb_signaljob to apply any UNIX signal to a job or process.
+ * <p/>
+ * Any program using this API must be setuid to root if LSF_AUTH is not defined
+ * in the lsf.conf file.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_signaljob (long jobId, int sigValue)</b>
+ *
+ * @param jobId The job to be signaled. If a job in a job array is to be
+ * signaled, use the array form jobID[ i ] where jobID is the job array name,
+ * and i is the index value.
+ * @param sigValue SIGSTOP, SIGCONT, SIGKILL or some other UNIX signal.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * @return int:-1 \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * bkill \n
+ * bstop \n
+ * bresume
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * #see \ref lsb_chkpntjob
+ * #see \ref lsb_forcekilljob
+ * #see \ref lsb_mig
+ */
+
+ public static native int lsb_signaljob(long jobId, int sigValue);
+
+ /**
+ * \page lsb_killbulkjobs lsb_killbulkjobs
+ * \brief Kills bulk jobs as soon as possible.
+ * <p/>
+ * Use \ref lsb_killbulkjobs to kill bulk jobs on a local host immediately, or
+ * to kill other jobs as soon as possible. If mbatchd rejects the request, it
+ * issues null as the reservation ID.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_killbulkjobs(signalBulkJobs.ByReference s)</b>
+ *
+ * @return int:-1 \n
+ * The bulk jobs were not killed.
+ * <p/>
+ * \b Error:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * bkill -b
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param s The signal to a group of jobs.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * signalBulkJobs
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * see none
+ */
+
+ public static native int lsb_killbulkjobs(signalBulkJobs s);
+
+ public static native int lsb_msgjob(long long1, String s);
+
+ /**
+ * \page lsb_chkpntjob lsb_chkpntjob
+ * \brief Checkpoints a job.
+ * <p/>
+ * Checkpoints a job.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_chkpntjob(long jobId, int period, int options)</b>
+ *
+ * @param jobId The job to be checkpointed.
+ * @param period The checkpoint period in seconds. The value 0
+ * disables periodic checkpointing.
+ * @param options The bitwise inclusive OR of some of the following:
+ * \n LSB_CHKPNT_KILL
+ * Checkpoint and kill the job as an atomic action.
+ * \n LSB_CHKPNT_FORCE
+ * Checkpoint the job even if non-checkpointable conditions exist.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref chkpnt_job_option
+ * @return int:-1 \n
+ * The function failed.
+ * <p/>
+ * \note Any program using this API must be setuid to root if LSF_AUTH
+ * is not defined in the lsf.conf file.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * bchkpnt
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * see none
+ */
+ public static native int lsb_chkpntjob(long jobId, NativeLong period, int options);
+
+ /**
+ * \page lsb_deletejob lsb_deletejob
+ * \brief Kills a job in a queue
+ * <p/>
+ * Use \ref lsb_deletejob to send a signal to kill a running, user-suspended,
+ * or system-suspended job. The job can be requeued or deleted from the batch
+ * system.If the job is requeued, it retains its submit time but it is dispatched
+ * according to its requeue time. When the job is requeued, it is assigned the
+ * PEND status and re-run.If the job is deleted from the batch system, it is
+ * no longer available to be requeued.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_deletejob (long jobId, int times, int options)</b>
+ *
+ * @param jobId The job to be killed. If an element of a job array is to be
+ * killed, use the array form jobID[i] where jobID is the job array name,
+ * and i is the index value.
+ * @param times Original job submit time.
+ * @param options If the preprocessor macro LSB_KILL_REQUEUE in lsbatch.h is
+ * compared with options and found true, then requeue the job using the same job ID.
+ * If the preprocessor macro LSB_KILL_REQUEUE in lsbatch.h is compared with
+ * options and found false, then the job is deleted from the batch system.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref kill_requeue
+ * @return int:-1 \n
+ * The function failed.
+ * <p/>
+ * \note Any program using this API must be setuid to root if LSF_AUTH is not defined in the
+ * \n lsf.conf file.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * bkill
+ * \n brequeue -J
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * #see \ref lsb_signaljob
+ * #see \ref lsb_chkpntjob
+ */
+ public static native int lsb_deletejob(long jobId, int times, int options);
+
+ /**
+ * \page lsb_forcekilljob lsb_forcekilljob
+ * \brief This function is used to send special force kill signal.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_forcekilljob(long jobId)</b>
+ *
+ * @param jobId which job is to be killed.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * @return int:-1
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * #see \ref lsb_signaljob
+ */
+ public static native int lsb_forcekilljob(long jobId);
+
+ /**
+ * \page lsb_submitframe lsb_submitframe
+ * \brief Submits a frame job to the batch system.
+ * <p/>
+ * \ref lsb_submitframe submits a frame job to the batch system according to the
+ * jobSubReq specification and frameExp.
+ * <p/>
+ * Any program using this API must be setuid to root if LSF_AUTH is not defined
+ * in the lsf.conf file.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_submitframe (submit.ByReference jobSubReq, String frameExp,
+ * submitReply.ByReference jobSubReply)</b>
+ *
+ * @return int:-1 \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error and jobSubReply gives
+ * additional information about the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param jobSubReq Describes the requirements for job submission to the
+ * batch system. A job that does not meet these requirements is not submitted
+ * to the batch system and an error is returned. \n
+ * See \ref lsb_submit for descriptions of the submit structure fields.
+ * @param frameExp The syntax of frameExp is: \n
+ * <b>frame_name[indexlist]</b> \n
+ * frame_name is any name consisting of alphanumerics, periods, forward slashes,
+ * dashes or underscores. indexlist is a list of one or more frame indexes,
+ * separated by commas. These indexes can each be either a single integer or
+ * a range, specified in the following format: \n
+ * <b>start-end[xstep[:chunk]]</b> \n
+ * start, end, step, and chunk are integers, but chunk must be positive.
+ * If step and
+ * chunk are ommitted, the default value is 1.\n
+ * An example of a valid expression for frameExp is:\n
+ * <b>Frame_job_1[5,10-15,20-30x2:3]</b>
+ * @param jobSubReply Describes the results of the job submission to the
+ * batch system. \n
+ * See \ref lsb_submit for descriptions of the submitReply structure
+ * fields.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * submit
+ * \n submitReply
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref lsb_submit_options
+ * \n \ref lsb_submit_options2
+ * \n \ref lsb_submit_options3
+ * see none
+ */
+ public static native int lsb_submitframe(submit jobSubReq, String frameExp, submitReply jobSubReply);
+
+ /**
+ * \page lsb_requeuejob lsb_requeuejob
+ * \brief Requeues job arrays, jobs in job arrays, and individual jobs.
+ * <p/>
+ * Use \ref lsb_requeuejob to requeue job arrays, jobs in job arrays, and individual
+ * jobs that are running, pending, done, or exited. In a job array, you can
+ * requeue all the jobs or requeue individual jobs of the array.
+ * <p/>
+ * \ref lsb_requeuejob requeues jobs as if the jobs were in an array. A job not in an
+ * array is considered to be a job array composed of one job.
+ * <p/>
+ * Jobs in a job array can be requeued independently of each other regardless of
+ * any job's status (running, pending, exited, done). A requeued job is requeued
+ * to the same queue it was originally submitted from or switched to. The job
+ * submission time does not change so a requeued job is placed at the top of the
+ * queue. Use \ref lsb_movejob to place a job at the bottom or any other position
+ * in a queue.
+ * <p/>
+ * If a clean period is reached before \ref lsb_requeuejob is called, the cleaned
+ * jobs cannot be requeued. Set the variable CLEAN_PERIOD in your lsb.params file
+ * to determine the amount of time that job records are kept in MBD core memory
+ * after jobs have finished or terminated.
+ * <p/>
+ * To requeue a job assign values to the data members of the jobrequeue data
+ * structure, process command line options in case the user has specified a
+ * different job, and call \ref lsb_requeuejob to requeue the job array.
+ * <p/>
+ * Assign values to the jobID, status, and options data members of the jobrequeue
+ * data structure. Assign the job identification number to jobID. Assign
+ * JOB_STAT_PEND or JOB_STAT_PSUSP to status. Assign REQUEUE_DONE, REQUEUE_EXIT,
+ * and or REQUEUE_RUN to requeue running jobs.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_requeuejob(jobrequeue.ByReference reqPtr)</b>
+ *
+ * @return int:-1 \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * brequeue -d
+ * \n brequeue -e
+ * \n brequeue -a
+ * \n brequeue -r
+ * \n brequeue -H
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * \n $LSB_SHAREDIR
+ * @param reqPtr This structure contains the information required to requeue a job.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * jobrequeue
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref requeuejob_options
+ * #see \ref lsb_movejob
+ * #see \ref lsb_pendreason
+ */
+ public static native int lsb_requeuejob(jobrequeue reqPtr);
+
+ /**
+ * \page lsb_sysmsg lsb_sysmsg
+ * \brief Returns a pointer to static data.
+ * <p/>
+ * \ref lsb_sysmsg returns a pointer to static data which stores the batch error
+ * message corresponding to lsberrno. The global variable lsberrno maintained
+ * by LSBLIB holds the error number from the most recent LSBLIB call that caused
+ * an error. If lsberrno == LSBE_SYS_CALL, then the system error message defined
+ * by errno is also returned. If lsberrno == LSBE_LSLIB, then the error message
+ * returned by \ref ls_sysmsg is returned.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * String lsb_sysmsg ()</b>
+ *
+ * param void \n
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * #see \ref ls_perror
+ * #see \ref ls_sysmsg
+ */
+ public static native String lsb_sysmsg();
+
+ /**
+ * \page lsb_perror lsb_perror
+ * \brief Prints a batch LSF error message on stderr.
+ * <p/>
+ * \ref lsb_perror prints a batch LSF error message on stderr. The usrMsg is
+ * printed out first, followed by a ":" and the batch error message corresponding
+ * to lsberrno.
+ * <p/>
+ * \ref lsb_perror - Print LSBATCH error message on stderr. In addition
+ * to the error message defined by lsberrno, user supplied message usrMsg1
+ * is printed out first and a ':' is added to separate.ByReference usrMsg1 and LSBATCH
+ * error message.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * void lsb_perror (String usrMsg)</b>
+ *
+ * return void \n
+ * Prints out the user supplied error message.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * none
+ * <p/>
+ * \b Files:
+ * \par
+ * none
+ * @param usrMsg A user supplied error message.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * see none
+ */
+ public static native void lsb_perror(String usrMsg);
+
+ public static native void lsb_errorByCmd(String string1, String string2, int int1);
+
+ public static native String lsb_sperror(String string1);
+
+ /**
+ * \page lsb_peekjob lsb_peekjob
+ * \brief Returns the base name of the file related to the job ID
+ * <p/>
+ * \ref lsb_peekjob retrieves the name of a job file.
+ * <p/>
+ * Only the submitter can peek at job output.
+ * <p/>
+ * The storage for the file name will be reused by the next call.
+ * <p/>
+ * Any program using this API must be setuid to root if LSF_AUTH
+ * is not defined in the lsf.conf file.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * String lsb_peekjob (long jobId)</b>
+ *
+ * @param jobId The job ID that the LSF system assigned to the job. If a job
+ * in a job array is to be returned, use the array form jobID[i] where jobID
+ * is the job array name, and i is the index value.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * bpeek
+ * <p/>
+ * \b Files:
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * see none
+ */
+ public static native String lsb_peekjob(long jobId);
+
+ /**
+ * \page lsb_mig lsb_mig
+ * \brief Migrates a job from one host to another.
+ * <p/>
+ * \ref lsb_mig migrates a job from one host to another. Any program using
+ * this API must be setuid to root if LSF_AUTH is not defined
+ * in the lsf.conf file.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_mig(submig.ByReference mig, IntByReference badHostIdx)</b>
+ *
+ * @return int:-1 \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error and badHostIdx indicates
+ * which askedHost is not acceptable.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * none
+ * <p/>
+ * \b Files:
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param mig The job to be migrated.
+ * @param badHostIdx If the call fails, (**askedHosts)[*badHostIdx] is not a
+ * host known to the LSF system.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * submig
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * #see \ref lsb_submit
+ */
+ public static native int lsb_mig(submig mig, IntByReference badHostIdx);
+
+ public static native clusterInfoEnt.ByReference lsb_clusterinfo(IntByReference int1, Pointer stringArray1, int int2);
+
+ public static native clusterInfoEntEx.ByReference lsb_clusterinfoEx(IntByReference int1, Pointer stringArray1, int int2);
+
+ /**
+ * \page lsb_hostinfo lsb_hostinfo
+ * Returns information about job server hosts.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * hostInfoEnt.ByReference lsb_hostinfo(String[] hosts, IntByReference numHosts)</b>
+ *
+ * @return hostInfoEnt.ByReference :null
+ * \n Function failed.
+ * <p/>
+ * <b>Errors:</b>
+ * \par
+ * If the function fails, lsberrno is set to indicate the error. If lsberrno is
+ * LSBE_BAD_HOST, (*hosts)[*numHosts] is not a host known to the batch system.
+ * Otherwise, if.ByReference numHosts is less than its original value,* numHosts is the actual
+ * number of hosts found.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * bhosts
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.hosts
+ * @param hosts
+ * An array of host or cluster names.
+ * @param numHosts
+ * The number of host names.
+ * To get information on all hosts, set.ByReference numHosts to 0;* numHosts will be set to the
+ * actual number of hostInfoEnt structures when this call returns.
+ * If.ByReference numHosts is 1 and hosts is null, information on the local host is returned.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * hostInfoEnt
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref host_status
+ * \n \ref host_load_BusyReason
+ * \n \ref host_attributes
+ * #see \ref lsb_hostinfo_ex
+ * #see \ref ls_info
+ * #see \ref ls_loadofhosts
+ * #see \ref lsb_queueinfo
+ * #see \ref lsb_userinfo
+ */
+ public static native hostInfoEnt.ByReference lsb_hostinfo(Pointer hosts, IntByReference numHosts);
+
+ /**
+ * \page lsb_hostinfo_ex lsb_hostinfo_ex
+ * Returns informaton about job server hosts that satisfy specified resource
+ * requirements. \ref lsb_hostinfo_ex returns information about job server hosts
+ * that satisfy the specified resource requirements.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * hostInfoEnt.ByReference lsb_hostinfo_ex(String[] hosts,
+ * IntByReference numHosts, String resReq, int options)</b> @param hosts An array of host or cluster names.
+ *
+ * @param options Options is reserved for the future use.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * hostInfoEnt
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref host_status
+ * \n \ref host_load_BusyReason
+ * \n \ref host_attributes
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * <b>Errors:</b>
+ * \par
+ * If the function fails, lsberrno is set to indicate the error. If lsberrno is
+ * LSBE_BAD_HOST, (*hosts)[*numHosts] is not a host known to the batch system.
+ * Otherwise, if.ByReference numHosts is less than its original value,* numHosts is the actual
+ * number of hosts found.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.hosts
+ * @param numHosts The number of host names.
+ * To get information on all hosts, set.ByReference numHosts to 0;* numHosts will be set
+ * to the actual number of hostInfoEnt structures when this call returns.
+ * If.ByReference numHosts is 1 and hosts is null, information on the local host is returned.
+ * @param resReq Resource requirements.
+ * If this option is specified, then only host information for those hosts
+ * that satisfy the resource requirements is returned. Returned hosts are
+ * sorted according to the load on the resource() given in resReq, or by
+ * default according to CPU and paging load.
+ * #see \ref ls_info
+ * #see \ref ls_loadofhosts
+ * #see \ref lsb_hostinfo
+ * #see \ref lsb_queueinfo
+ * #see \ref lsb_userinfo
+ * @param string1 string1
+ */
+
+ public static native hostInfoEnt.ByReference lsb_hostinfo_ex(Pointer resReq, IntByReference numHosts, String string1, int options);
+
+ /**
+ * \page lsb_hostinfo_cond lsb_hostinfo_cond
+ * Returns condensed information about job server hosts.
+ * <p/>
+ * \ref lsb_hostinfo_cond returns condensed information about job server hosts.
+ * While \ref lsb_hostinfo returns specific information about individual hosts,
+ * \ref lsb_hostinfo_cond returns the number of jobs in each state within the
+ * entire host group. The condHostInfoEnt structure contains counters that
+ * indicate how many hosts are in the ok, busy, closed, full, unreach, and
+ * unavail states and an array of hostInfoEnt structures that indicate the
+ * status of each host in the host
+ * group.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * condHostInfoEnt.ByReference lsb_hostinfo_cond
+ * (String[] hosts, IntByReference numHosts,
+ * String resReq, int options)</b>
+ *
+ * @param options Any options called with the function.
+ * <p/>
+ * <b>Data Structures</b>
+ * \par
+ * condHostInfoEnt
+ * \n hostInfoEnt
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * <b Errors:</b>
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param hosts An array of host names belonging to the host group.
+ * @param numHosts The number of host names in the host group.
+ * To get information on all hosts in the host group, set.ByReference numHosts to 0;
+ * * numHosts will be set to the actual number of hostInfoEnt structures in
+ * the host group when this call returns.
+ * @param resReq Any resource requirements called with the function.
+ * #see \ref lsb_hostinfo
+ */
+ public static native condHostInfoEnt.ByReference lsb_hostinfo_cond(Pointer hosts, IntByReference numHosts, String resReq, int options);
+
+ /**
+ * \page lsb_movejob lsb_movejob
+ * \brief Changes the position of a pending job in a queue.
+ * <p/>
+ * Use \ref lsb_movejob to move a pending job to a new position that you specify
+ * in a queue. Position the job in a queue by first specifying the job ID.
+ * Next, count, beginning at 1, from either the top or the bottom of the queue,
+ * to the position you want to place the job.
+ * <p/>
+ * To position a job at the top of a queue, choose the top of a queue parameter
+ * and a postion of 1.To position a job at the bottom of a queue, choose the
+ * bottom of the queue parameter and a position of 1.
+ * <p/>
+ * By default, LSF dispatches
+ * jobs in a queue in order of their arrival (such as first-come-first-served),
+ * subject to the availability of suitable server hosts.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_movejob (long jobId, IntByReference position, int opCode)</b>
+ *
+ * @param jobId The job ID that the LSF system assigns to the job. If a job
+ * in a job array is to be moved, use the array form jobID[ i ] where jobID is
+ * the job array name, and i is the index value.
+ * @param opCode The top or bottom position of a queue.
+ * \n \b TO_TOP
+ * \n The top position of a queue.
+ * \n \b TO_BOTTOM
+ * \n The bottom position of a queue.
+ * \n If an opCode is not specified for the top or bottom position, the
+ * function fails.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref movejob_options
+ * @return int:-1 \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * btop
+ * \n bbot
+ * \n bjobs -q
+ * <p/>
+ * \b Files:
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param position The new position of the job in a queue. position must be
+ * a value of 1 or more.
+ * #see \ref lsb_pendreason
+ */
+
+ public static native int lsb_movejob(long jobId, IntByReference opCode, int position);
+
+ /**
+ * \page lsb_switchjob lsb_switchjob
+ * \brief Switches an unfinished job to another queue.
+ * <p/>
+ * \ref lsb_switchjob switches an unfinished job to another queue. Effectively,
+ * the job is removed from its current queue and re-queued in the new queue.
+ * <p/>
+ * The switch operation can be performed only when the job is acceptable to
+ * the new queue. If the switch operation is unsuccessful, the job will stay
+ * where it is.A user can only switch his/her own unfinished jobs, but root
+ * and the LSF administrator can switch any unfinished job.
+ * <p/>
+ * Any program using this API must be setuid to root if LSF_AUTH is not defined
+ * in the lsf.conf file.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_switchjob (long jobId, String queue)</b>
+ *
+ * @param jobId The job to be switched. If an element of a job array is to
+ * be switched, use the array form jobID[i] where jobID is the job array name,
+ * and i is the index value.
+ * @return int:-1 \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * bswitch
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param queue The new queue for the job.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * see none
+ */
+ public static native int lsb_switchjob(long jobId, String queue);
+
+ /**
+ * \page lsb_queuecontrol lsb_queuecontrol
+ * \brief Changes the status of a queue.
+ * <p/>
+ * \ref lsb_queuecontrol changes the status of a queue.
+ * <p/>
+ * Any program using this API must be setuid to root if LSF_AUTH is not defined
+ * in the lsf.conf file.
+ * <p/>
+ * If a queue is inactivated by its dispatch window (see lsb.queues), then it
+ * cannot be re-activated by this call.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_queuecontrol (queueCtrlReq.ByReference req)</b>
+ *
+ * @return int:-1 \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * \b Files:
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param req queue control request.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * queueCtrlReq
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref queue_ctrl_option
+ * #see \ref lsb_queueinfo
+ */
+ public static native int lsb_queuecontrol(queueCtrlReq req);
+
+ /**
+ * \page lsb_userinfo lsb_userinfo
+ * \brief Returns the maximum number of job slots that a user can use
+ * simultaneously on any host and in the whole local LSF cluster.
+ * <p/>
+ * \ref lsb_userinfo gets the maximum number of job slots that a user can use
+ * simultaneously on any host and in the whole local LSF cluster, as well as
+ * the current number of job slots used by running and suspended jobs or
+ * reserved for pending jobs. The maximum numbers of job slots are defined
+ * in the LSF configuration file lsb.users (see lsb.users). The reserved
+ * user name default, defined in the lsb.users configuration file, matches
+ * users not listed in the lsb.users file who have no jobs started in the
+ * system.
+ * <p/>
+ * The returned array will be overwritten by the next call.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * userInfoEnt.ByReference lsb_userinfo(String[] users, IntByReference numUsers)</b>
+ *
+ * @return null \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error. If lsberrno is
+ * LSBE_BAD_USER, (*users)[*numUsers] is not a user known to the LSF system.
+ * Otherwise, if.ByReference numUsers is less than its original value,* numUsers is the actual
+ * number of users found.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * busers
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.users
+ * @param users An array of user names.
+ * @param numUsers The number of user names.
+ * To get information about all users, set.ByReference numUsers = 0;* numUsers will
+ * be updated to the actual number of users when this call returns. To get
+ * information on the invoker, set users = null,* numUsers = 1.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * userInfoEnt
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * #see \ref lsb_hostinfo
+ * #see \ref lsb_queueinfo
+ */
+ public static native userInfoEnt.ByReference lsb_userinfo(Pointer users, IntByReference numUsers);
+
+ /**
+ * \page lsb_hostgrpinfo lsb_hostgrpinfo
+ * Returns LSF host group membership.
+ * <p/>
+ * \ref lsb_hostgrpinfo gets LSF host group membership.
+ * <p/>
+ * LSF host group is defined in the configuration file lsb.hosts.
+ * <p/>
+ * The storage for the array of groupInfoEnt structures will be reused by
+ * the next call.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * groupInfoEnt.ByReference lsb_hostgrpinfo (String[] groups,IntByReference numGroups,
+ * int options)</b>
+ *
+ * @param options The bitwise inclusive OR of some of the following flags:
+ * \n GRP_RECURSIVE
+ * \n Expand the group membership recursively. That is, if a member of a
+ * group is itself a group, give the names of its members recursively, rather
+ * than its name, which is the default.
+ * \n GRP_ALL
+ * \n Get membership of all groups.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * groupInfoEnt
+ * \n userShares
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref group_membership_option
+ * \n \ref group_define
+ * @return null \n
+ * Function failed.
+ * <p/>
+ * <b>Errors:</b>
+ * \par
+ * On failure, returns null and sets lsberrno to indicate the error. If there
+ * are invalid groups specified, the function returns the groups up to the
+ * invalid ones and then sets lsberrno to LSBE_BAD_GROUP, which means that
+ * the specified (*groups)[*numGroups] is not a group known to the LSF system.
+ * If the first group specified is invalid, the function returns null.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.hosts \n
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.users
+ * @param groups An array of group names.
+ * @param numGroups The number of group names.* numGroups will be updated
+ * to the actual number of groups when this call returns.
+ * #see \ref lsb_usergrpinfo
+ */
+ public static native groupInfoEnt.ByReference lsb_hostgrpinfo(Pointer groups, IntByReference numGroups, int options);
+
+ /**
+ * \page lsb_usergrpinfo lsb_usergrpinfo
+ * \brief Returns LSF user group membership.
+ * <p/>
+ * \ref lsb_usergrpinfo gets LSF user group membership.
+ * LSF user group is defined in the configuration file lsb.users.
+ * The storage for the array of groupInfoEnt structures will be reused by
+ * the next call.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * groupInfoEnt.ByReference lsb_usergrpinfo (String[] groups,
+ * IntByReference numGroups, int options)</b>
+ *
+ * @param options The bitwise inclusive OR of some of flags in \ref group_membership_option
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * groupInfoEnt
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref group_membership_option
+ * \n \ref group_define
+ * @return null \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, returns null and sets lsberrno to indicate the error. If there
+ * are invalid groups specified, the function returns the groups up to the
+ * invalid ones. It then set lsberrno to LSBE_BAD_GROUP, that is the specified
+ * (*groups)[*numGroups] is not a group known to the LSF system. If the first
+ * group is invalid, the function returns null.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.hosts
+ * \n $LSB_CONFDIR/cluster_name/configdir/lsb.users
+ * @param groups An array of group names.
+ * @param numGroups The number of group names.* numGroups will be updated
+ * to the actual number of groups when this call returns.
+ * #see \ref lsb_hostgrpinfo
+ */
+ public static native groupInfoEnt.ByReference lsb_usergrpinfo(Pointer groups, IntByReference numGroups, int options);
+
+ /**
+ * \page lsb_parameterinfo lsb_parameterinfo
+ * \brief Returns information about the LSF cluster.
+ * <p/>
+ * \ref lsb_parameterinfo gets information about the LSF cluster.
+ * <p/>
+ * The static storage for the parameterInfo structure is reused on the next call.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * parameterInfo.ByReference lsb_parameterinfo(String[] names,
+ * IntByReference numUsers, int options)</b>
+ *
+ * @param options Reserved but not used; supply 0.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * \ref parameterInfo
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * @return null \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * none
+ * <p/>
+ * \b Files:
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * @param names Reserved but not used; supply null.
+ * @param numUsers Reserved but not used; supply null.
+ * see none
+ */
+ public static native parameterInfo.ByReference lsb_parameterinfo(Pointer names, IntByReference numUsers, int options);
+
+ /**
+ * \page lsb_modify lsb_modify
+ * \brief Modifies a submitted job's parameters.
+ * <p/>
+ * lsb_modify() allows for the modification of a submitted job's parameters.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * long lsb_modify (submit.ByReference jobsubReq,
+ * submitReply.ByReference jobSubReply,
+ * long jobId)</b>
+ *
+ * @param jobId The job to be modified. If an element of a job array is to
+ * be modified, use the array form jobID[i] where jobID is the job array name,
+ * and i is the index value.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * \ref submit
+ * \n \ref submitReply
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * @return long:-1 \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command :</b>
+ * \par
+ * bmod
+ * <p/>
+ * \b Files:
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param jobSubReq Describes the requirements for job modification to the
+ * batch system. A job that does not meet these requirements is not submitted
+ * to the batch system and an error is returned.
+ * @param jobSubReply Describes the results of the job modification to the
+ * batch system.
+ * #see \ref lsb_submit
+ * #see \ref ls_info
+ * #see \ref ls_rtask
+ * #see \ref lsb_queueinfo
+ */
+ public static native long lsb_modify(submit jobSubReq, submitReply jobSubReply, long jobId);
+
+ public static native FloatByReference getCpuFactor(String string1, int int1);
+
+ /**
+ * \page lsb_suspreason lsb_suspreason
+ * \brief Explains why a job was suspended.
+ * <p/>
+ * Using the SBD, \ref lsb_suspreason explains why system-suspended and
+ * user-suspended jobs were suspended.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * String lsb_suspreason(int reasons, int subreasons,
+ * loadIndexLog.ByReference ld)</b>
+ *
+ * @param reasons Reasons a job suspends.
+ * @param subreasons If reasons is SUSP_LOAD_REASON, subreasons indicates
+ * the load indices that are out of bounds. The integer values for the load
+ * indices are found in lsf.h.If reasons is SUSP_RES_LIMIT, subreasons
+ * indicates the job's requirements for resource reservation are not satisfied.
+ * The integer values for the job's requirements for resource reservation are
+ * found in lsbatch.h.
+ * \n Subreasons a job suspends if reasons is SUSP_LOAD_REASON:
+ * - \b R15S
+ * \n 15 second CPU run queue length
+ * - \b R1M
+ * \n 1 minute CPU run queue length
+ * - \b R15M
+ * \n 15 minute CPU run queue length
+ * - \b UT
+ * \n 1 minute CPU utilization
+ * - \b PG
+ * \n Paging rate
+ * - \b IO
+ * \n Disk IO rate
+ * - \b LS
+ * \n Number of log in sessions
+ * - \b IT
+ * \n Idle time
+ * - \b TMP
+ * \n Available temporary space
+ * - \b SWP
+ * \n Available swap space
+ * - \b MEM
+ * \n Available memory
+ * - \b USR1
+ * \n USR1 is used to describe unavailable or out of bounds user defined load
+ * information of an external dynamic load indice on execution hosts.
+ * - \b USR2
+ * \n USR2 is used to describe unavailable or out of bounds user defined load
+ * information of an external dynamic load indice on execution hosts.
+ * @return null \n
+ * The function failed. The reason code is bad.
+ * <p/>
+ * \b Errors:
+ * \par
+ * No error handling
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * bjobs -s
+ * <p/>
+ * <b>Environment Variable:</b>
+ * \par
+ * LSB_SUSP_REASONS
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.queues \n
+ * $LSB_SHAREDIR/cluster_name/logdir/lsb.events
+ * @param ld When reasons is SUSP_LOAD_REASON, ld is used to determine the
+ * name of any external load indices. ld uses the most recent load index log
+ * in the lsb.events file.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * loadIndexLog
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref suspending_reasons \n
+ * \ref suspending_subreasons
+ * #see \ref lsb_pendreason
+ */
+ public static native String lsb_suspreason(int reasons, int subreasons, loadIndexLog ld);
+
+ /**
+ * \page lsb_pendreason lsb_pendreason
+ * \brief Explains why a job is pending.
+ * <p/>
+ * Use \ref lsb_pendreason to determine why a job is pending. Each pending reason is
+ * associated with one or more hosts.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * String lsb_pendreason (int numReasons, IntByReference rsTb,
+ * jobInfoHead.ByReference jInfoH,
+ * loadIndexLog.ByReference ld, int clusterId)</b>
+ *
+ * @param numReasons The number of reasons in the rsTb reason table.
+ * @param clusterId MultiCluster cluster ID. If clusterId is greater than or
+ * equal to 0, the job is a pending remote job, and \ref lsb_pendreason checks for
+ * host_name\@cluster_name. If host name is needed, it should be found in
+ * jInfoH->remoteHosts. If the remote host name is not available, the constant
+ * string remoteHost is used.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * \ref jobInfoHead
+ * \n \ref loadIndexLog
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref pending_reasons
+ * \n \ref suspending_reasons
+ * \n \ref suspending_subreasons
+ * @return null \n
+ * The function fails. The reason code is bad.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If no PEND reason is found, the function fails and lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * bjobs -p
+ * <p/>
+ * \b Files:
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * @param rsTb The reason table. Each entry in the table contains one of \ref pending_reasons
+ * @param jInfoH jInfoH contains job information.
+ * @param ld From \ref lsb_suspreason, when reasons is SUSP_LOAD_REASON, ld is used to
+ * determine the name of any external load indices. ld uses the most recent load
+ * index log in the lsb.events file.
+ * #see \ref lsb_geteventrec
+ */
+ public static native String lsb_pendreason(int numReasons, IntByReference rsTb, jobInfoHead jInfoH, loadIndexLog ld, int clusterId);
+
+ /**
+ * \page lsb_calendarinfo lsb_calendarinfo
+ * \brief Gets information about calendars defined in the batch system.
+ * <p/>
+ * \ref lsb_calendarinfo gets information about calendars defined in the batch system.
+ * <p/>
+ * On success, this routine returns a pointer to an array of calendarInfoEnt
+ * structures which stores the information about the returned calendars and
+ * numCalendars gives number of calendars returned. On failure null is returned
+ * and lsberrno is set to indicate the error.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * calendarInfoEnt.ByReference lsb_calendarinfo(String[] calendars,
+ * IntByReference numCalendars, String user)</b>
+ *
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param calendars calendars is a pointer to an array of calendar names.
+ * @param numCalendars numCalendars gives the number of calendar names. If
+ * * numCalendars is 0, then information about all calendars is returned.
+ * By default, only the invokers calendars are considered.
+ * @param user Setting the user parameter will cause the given users calendars
+ * to be considered.Use the reserved user name all to get calendars of all users.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * calendarInfoEnt
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * #see \ref lsb_calendarop
+ */
+ public static native calendarInfoEnt.ByReference lsb_calendarinfo(Pointer calendars, IntByReference numCalendars, String user);
+
+ public static native int lsb_calExprOccs(String string1, int int1, int int2, String string2, PointerByReference int3);
+
+ /**
+ * \page lsb_calendarop lsb_calendarop
+ * \brief Adds, modifies or deletes a calendar.
+ * <p/>
+ * \ref lsb_calendarop is used to add, modify or delete a calendar. The oper
+ * parameter is one of CALADD, CALMOD, or CALDEL. When the operation CALADD
+ * is specified, the first element of the names array is used as the name of
+ * the calendar to add. The desc and calExpr parameters should point to the
+ * description string and the time expression list, respectively. See bcaladd()
+ * for a description of time expressions.
+ * <p/>
+ * CALMOD permits the modification of the
+ * description or time expression list associated with an existing calendar. The
+ * first name in the names array indicates the calendar to be modified. The desc
+ * and calExpr parameters can be set to the updated value or to null to
+ * indicate that the existing value should be maintained.
+ * <p/>
+ * If the operation is
+ * CALDEL then the names parameter points to an array of calendar names to be
+ * deleted. numNames gives the number of names in the array. options is
+ * reserved for the future use.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * IntByReference lsb_calendarop(int oper, int numNames, String[] names, byte
+ * * desc, String calExpr, int options, String[] badStr)</b>
+ *
+ * @param oper One of CALADD, CALMOD, or CALDEL. Depending on which one is
+ * chosen, adds, modifies, or deletes a calendar.Defined in \ref calendar_command.
+ * @param numNames The number of names in the array.
+ * @param options Currently unused.
+ * @return int:-1
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error. If error
+ * is related to bad calendar name or time expression, the routine returns
+ * the name or expression in badStr.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param names Depending on oper, it defines the name of the calendar is going
+ * to be added, modified or deleted.
+ * @param desc The calendar's description list.
+ * @param calExpr A calendar expression.
+ * @param badStr Return from mbatchd indicating bad name or event time of calendar.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref calendar_command
+ * #see \ref lsb_calendarinfo
+ */
+ public static native int lsb_calendarop(int oper, int numNames, Pointer names, String desc, String calExpr, int options, String badStr);
+
+ /**
+ * \page lsb_puteventrec lsb_puteventrec
+ * \brief Puts information of an eventRec structure pointed to by logPtr
+ * into a log file.
+ * <p/>
+ * \ref lsb_puteventrec puts information of an eventRec structure pointed to by
+ * logPtr into a log file. log_fp is a pointer pointing to the log file name
+ * that could be either event a log file or job log file.
+ * <p/>
+ * See \ref lsb_geteventrec for detailed information about parameters.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_puteventrec(Pointer log_fp, eventRec.ByReference logPtr)</b>
+ *
+ * @return int:-1 \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_SHAREDIR/cluster_name/logdir/lsb.events
+ * @param logPtr The eventRec structure pointed to by logPtr into a log file.
+ * @param log_fp A pointer pointing to the log file name that could be either
+ * event a log file or job log file.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * eventRec
+ * \n eventLog
+ * \n xFile
+ * \n jobAttrSetLog
+ * \n logSwitchLog
+ * \n dataLoggingLog
+ * \n jgrpNewLog
+ * \n jgrpCtrlLog
+ * \n jgrpStatusLog
+ * \n jobNewLog
+ * \n jobModLog
+ * \n jobStartLog
+ * \n jobStartAcceptLog
+ * \n jobExecuteLog
+ * \n jobStatusLog
+ * \n sbdJobStatusLog
+ * \n sbdUnreportedStatusLog
+ * \n jobSwitchLog
+ * \n jobMoveLog
+ * \n chkpntLog
+ * \n jobRequeueLog
+ * \n jobCleanLog
+ * \n jobExceptionLog
+ * \n sigactLog
+ * \n migLog
+ * \n signalLog
+ * \n queueCtrlLog
+ * \n hostCtrlLog
+ * \n hgCtrlLog
+ * \n mbdStartLog
+ * \n mbdDieLog
+ * \n unfulfillLog
+ * \n jobFinishLog
+ * \n loadIndexLog
+ * \n calendarLog
+ * \n jobForwardLog
+ * \n jobAcceptLog
+ * \n statusAckLog
+ * \n jobMsgLog
+ * \n jobMsgAckLog
+ * \n jobOccupyReqLog
+ * \n jobVacatedLog
+ * \n jobForceRequestLog
+ * \n jobChunkLog
+ * \n jobExternalMsgLog
+ * \n rsvRes
+ * \n rsvFinishLog
+ * \n cpuProfileLog
+ * \n jobRunRusageLog
+ * \n slaLog
+ * \n perfmonLogInfo
+ * \n perfmonLog
+ * \n taskFinishLog
+ * \n eventEOSLog
+ * \n jobResizeNotifyStartLog
+ * \n jobResizeNotifyAcceptLog
+ * \n jobResizeNotifyDoneLog
+ * \n jobResizeReleaseLog
+ * \n jobResizeCancelLog
+ * \n jobResizeLog
+ * \n jRusage
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref event_types
+ * \n \ref defs_lsb_XF_OP
+ * \n \ref jobgroup_controltypes
+ * \n \ref signal_action
+ * #see \ref lsb_geteventrec
+ */
+ public static native int lsb_puteventrec(Pointer logPtr, eventRec log_fp);
+
+ public static native int lsb_puteventrecRaw(Pointer pointer1, eventRec eventRec1, String string1);
+
+ /**
+ * \page lsb_geteventrec lsb_geteventrec
+ * \brief Get an event record from a log file
+ * <p/>
+ * \ref lsb_geteventrec returns an eventRec from a log file.
+ * <p/>
+ * The storage for the eventRec structure returned by \ref lsb_geteventrec will be
+ * reused by the next call.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * eventRec.ByReference lsb_geteventrec(Pointer log_fp,IntByReference lineNum)</b>
+ *
+ * @return null \n
+ * Function failed.If there are no more records, returns null and sets
+ * lsberrno to LSBE_EOF.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_SHAREDIR/cluster_name/logdir/lsb.acct
+ * \n $LSB_SHAREDIR/cluster_name/logdir/lsb.events
+ * \n $LSB_SHAREDIR/cluster_name/logdir/lsb.rsv.ids
+ * \n $LSB_SHAREDIR/cluster_name/logdir/lsb.rsv.state
+ * @param log_fp Either an event log file or a job log file.
+ * @param lineNum The number of the event record.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * eventRec
+ * \n eventLog
+ * \n xFile
+ * \n jobAttrSetLog
+ * \n logSwitchLog
+ * \n dataLoggingLog
+ * \n jgrpNewLog
+ * \n jgrpCtrlLog
+ * \n jgrpStatusLog
+ * \n jobNewLog
+ * \n jobModLog
+ * \n jobStartLog
+ * \n jobStartAcceptLog
+ * \n jobExecuteLog
+ * \n jobStatusLog
+ * \n sbdJobStatusLog
+ * \n sbdUnreportedStatusLog
+ * \n jobSwitchLog
+ * \n jobMoveLog
+ * \n chkpntLog
+ * \n jobRequeueLog
+ * \n jobCleanLog
+ * \n jobExceptionLog
+ * \n sigactLog
+ * \n migLog
+ * \n signalLog
+ * \n queueCtrlLog
+ * \n hostCtrlLog
+ * \n hgCtrlLog
+ * \n mbdStartLog
+ * \n mbdDieLog
+ * \n unfulfillLog
+ * \n jobFinishLog
+ * \n loadIndexLog
+ * \n calendarLog
+ * \n jobForwardLog
+ * \n jobAcceptLog
+ * \n statusAckLog
+ * \n jobMsgLog
+ * \n jobMsgAckLog
+ * \n jobOccupyReqLog
+ * \n jobVacatedLog
+ * \n jobForceRequestLog
+ * \n jobChunkLog
+ * \n jobExternalMsgLog
+ * \n rsvRes
+ * \n rsvFinishLog
+ * \n cpuProfileLog
+ * \n jobRunRusageLog
+ * \n slaLog
+ * \n perfmonLogInfo
+ * \n perfmonLog
+ * \n taskFinishLog
+ * \n eventEOSLog
+ * \n jobResizeNotifyStartLog
+ * \n jobResizeNotifyAcceptLog
+ * \n jobResizeNotifyDoneLog
+ * \n jobResizeReleaseLog
+ * \n jobResizeCancelLog
+ * \n jobResizeLog
+ * \n jRusage
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref event_types
+ * \n \ref defs_lsb_XF_OP
+ * \n \ref jobgroup_controltypes
+ * \n \ref signal_action
+ * #see \ref lsb_hostcontrol
+ * #see \ref lsb_movejob
+ * #see \ref lsb_pendreason
+ * #see \ref lsb_puteventrec
+ * #see \ref lsb_queuecontrol
+ * #see \ref lsb_readjobinfo
+ * #see \ref lsb_submit
+ * #see \ref lsb_suspreason
+ */
+ public static native eventRec.ByReference lsb_geteventrec(Pointer log_fp, IntByReference lineNum);
+
+ public static native eventRec.ByReference lsb_geteventrec_decrypt(Pointer pointer1, IntByReference int1);
+
+ public static native eventRec.ByReference lsb_geteventrecord(Pointer pointer1, IntByReference int1);
+
+ public static native eventRec.ByReference lsb_geteventrecordEx(Pointer pointer1, IntByReference int1, Pointer stringArray1);
+
+ public static native eventRec.ByReference lsb_getnewjob_from_string(String string1);
+
+ public static native eventInfoEnt.ByReference lsb_eventinfo(Pointer stringArray1, IntByReference int1, String string1);
+
+ /**
+ * \page lsb_sharedresourceinfo lsb_sharedresourceinfo
+ * \brief Returns the requested shared resource information in dynamic values.
+ * <p/>
+ * \ref lsb_sharedresourceinfo returns the requested shared resource information in
+ * dynamic values. The result of this call is a chained data structure as
+ * defined in <lsf/lsbatch.h>, which contains requested information.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * LSB_SHARED_RESOURCE_INFO_T.ByReference lsb_sharedresourceinfo(
+ * String[] resources,
+ * IntByReference numResources,
+ * String hostName, int options)</b>
+ *
+ * @param options options is reserved for future use. Currently, it should be set to 0.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * lsbSharedResourceInfo
+ * \n lsbSharedResourceInstance
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * @return null \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSF_CONFDIR/lsf.shared
+ * \n $LSF_CONFDIR/lsf.cluster.cluster_name
+ * @param resources resources is an null terminated string array storing
+ * requesting resource names.Setting resources to point to null returns all
+ * shared resources.
+ * @param numResources numResources is an input/output parameter. On input
+ * it indicates how many resources are requested. Value 0 means requesting
+ * all shared resources. On return it contains qualified resource number.
+ * @param hostName hostName is a string containing a host name. Only shared resource
+ * available on the specified host will be returned. If hostName is a null,
+ * shared resource available on all hosts will be returned.
+ * #see \ref ls_sharedresourceinfo
+ */
+ public static native Pointer lsb_sharedresourceinfo(Pointer resources, IntByReference numResources, String hostName, int options);
+
+ /**
+ * \page lsb_geteventrecbyline lsb_geteventrecbyline
+ * Parse an event line and put the result in an event record structure.
+ * The \ref lsb_geteventrecbyline function parses an event line and puts the result
+ * in an event record structure.
+ * <p/>
+ * If the line to be parsed is a comment line, \ref lsb_geteventrecbyline sets errno to
+ * bad event format and logs an error.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_geteventrecbyline(String line, eventRec.ByReference logRec)</b>
+ *
+ * @return int:-1
+ * \n Function failed and lserrno was set.
+ * <p/>
+ * \b Errors:
+ * \par
+ * none
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param line
+ * Buffer containing a line of event text string
+ * @param logRec
+ * Pointer to an eventRec structure
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * eventRec
+ * \n eventLog
+ * \n xFile
+ * \n jobAttrSetLog
+ * \n logSwitchLog
+ * \n dataLoggingLog
+ * \n jgrpNewLog
+ * \n jgrpCtrlLog
+ * \n jgrpStatusLog
+ * \n jobNewLog
+ * \n jobModLog
+ * \n jobStartLog
+ * \n jobStartAcceptLog
+ * \n jobExecuteLog
+ * \n jobStatusLog
+ * \n sbdJobStatusLog
+ * \n sbdUnreportedStatusLog
+ * \n jobSwitchLog
+ * \n jobMoveLog
+ * \n chkpntLog
+ * \n jobRequeueLog
+ * \n jobCleanLog
+ * \n jobExceptionLog
+ * \n sigactLog
+ * \n migLog
+ * \n signalLog
+ * \n queueCtrlLog
+ * \n hostCtrlLog
+ * \n hgCtrlLog
+ * \n mbdStartLog
+ * \n mbdDieLog
+ * \n unfulfillLog
+ * \n jobFinishLog
+ * \n loadIndexLog
+ * \n calendarLog
+ * \n jobForwardLog
+ * \n jobAcceptLog
+ * \n statusAckLog
+ * \n jobMsgLog
+ * \n jobMsgAckLog
+ * \n jobOccupyReqLog
+ * \n jobVacatedLog
+ * \n jobForceRequestLog
+ * \n jobChunkLog
+ * \n jobExternalMsgLog
+ * \n rsvRes
+ * \n rsvFinishLog
+ * \n cpuProfileLog
+ * \n jobRunRusageLog
+ * \n slaLog
+ * \n perfmonLogInfo
+ * \n perfmonLog
+ * \n taskFinishLog
+ * \n eventEOSLog
+ * \n jobResizeNotifyStartLog
+ * \n jobResizeNotifyAcceptLog
+ * \n jobResizeNotifyDoneLog
+ * \n jobResizeReleaseLog
+ * \n jobResizeCancelLog
+ * \n jobResizeLog
+ * \n jRusage
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Pre-Conditions:</b>
+ * \par
+ * The event record structure must have been initialized outside the
+ * \ref lsb_geteventrecbyline function.
+ * see none
+ */
+
+ public static native int lsb_geteventrecbyline(String line, eventRec logRec);
+/* Retain lsb_connect for now */
+
+ public static int lsb_connect(int a) {
+ return lsb_rcvconnect();
+ }
+
+ public static native int lsb_rcvconnect();
+
+ public static native int lsb_sndmsg(lsbMsgHdr lsbMsgHdr1, String string1, int int1);
+
+ public static native int lsb_rcvmsg(lsbMsgHdr lsbMsgHdr1, Pointer stringArray1, int int1);
+
+ /**
+ * \page lsb_runjob lsb_runjob
+ * Starts a batch job immediately on a set of specified host().
+ * \ref lsb_runjob starts a batch job immediately on a set of specified host().
+ * The job must have been submitted and is in PEND or FINISHED status. Only
+ * the LSF administrator or the owner of the job can start the job. If the
+ * options is set to RUNJOB_OPT_NOSTOP, then the job will not be suspended by
+ * the queue's RUNWINDOW,loadStop and STOP_COND and the hosts' RUNWINDOW and
+ * loadStop conditions. By default, these conditions apply to the job as do
+ * to other normal jobs.
+ * <p/>
+ * Any program using this API must be setuid to root
+ * if LSF_AUTH is not defined in the lsf.conf file.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_runjob(runJobRequest.ByReference runJobRequest)</b>
+ *
+ * @param runJobRequest The job-starting request.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * runJobRequest
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref runjob_option
+ * @return int:-1 \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * brun
+ * <p/>
+ * \b Files:
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * see none
+ */
+ public static native int lsb_runjob(runJobRequest runJobRequest);
+
+/* API for job group */
+
+ public static native int lsb_addjgrp(jgrpAdd jgrpAdd1, Pointer jgrpReply1);
+
+ public static native int lsb_modjgrp(jgrpMod jgrpMod1, Pointer jgrpReply1);
+
+ public static native int lsb_holdjgrp(String string1, int int1, Pointer jgrpReply1);
+
+ public static native int lsb_reljgrp(String string1, int int1, Pointer jgrpReply1);
+
+ public static native int lsb_deljgrp(String string1, int int1, Pointer jgrpReply1);
+
+ public static native int lsb_deljgrp_ext(jgrpCtrl jgrpCtrl1, Pointer jgrpReply1);
+
+ public static native jgrp.ByReference lsb_listjgrp(IntByReference int1);
+
+ public static native serviceClass.ByReference lsb_serviceClassInfo(IntByReference int1);
+
+/* API for Application Encapsulation */
+
+ public static native appInfoEnt.ByReference lsb_appInfo(IntByReference int1);
+
+ public static native void lsb_freeAppInfoEnts(int int1, appInfoEnt appInfoEnt1);
+
+/* routine to convert the job id to string */
+
+ public static native String lsb_jobid2str(long long1);
+
+ public static native String lsb_jobid2str_r(long long1, byte[] byte1);
+
+ public static native String lsb_jobidinstr(long long1);
+/* routine to compose and decompose 64bit jobId */
+
+ public static native void jobId32To64(LongByReference long1, int int1, int int2);
+
+ public static native void jobId64To32(long long1, IntByReference int1, IntByReference int2);
+/* API for job attribute operations */
+
+ public static native int lsb_setjobattr(int int1, jobAttrInfoEnt jobAttrInfoEnt1);
+
+/* API for remote task execution */
+
+ public static native long lsb_rexecv(int int1, Pointer stringArray1, Pointer stringArray2, IntByReference int2, int int3);
+
+
+ public static interface lsb_catchCallback extends Callback {
+ int invoke(Pointer pointer);
+ }
+
+ public static native int lsb_catch(String string1, lsb_catchCallback callback);
+
+ public static native void lsb_throw(String string1, Pointer pointer1);
+
+/* API for job external message */
+
+ /**
+ * \page lsb_postjobmsg lsb_postjobmsg
+ * \brief Sends messages and data posted to a job.
+ *
+ * Use \ref lsb_postjobmsg to post a message and data to a job, open a TCP
+ * connection, and transfer attached message and data from the mbatchd. Use
+ * \ref lsb_readjobmsg to display messages and copy data files posted by
+ * \ref lsb_postjobmsg.
+ *
+ * While you can post multiple messages and attached data files to a job,
+ * you must call \ref lsb_postjobmsg for each message and attached data file
+ * you want to post. By default, \ref lsb_postjobmsg posts a message to position
+ * 0 of the message index (msgId) (see PARAMETERS) of the specified job.
+ * To post additional messages to a job, call \ref lsb_postjobmsg and increment
+ * the message index.
+ *
+ * \ref lsb_readjobmsg reads posted job messages by their
+ * position in the message index.
+ *
+ * If a data file is attached to a message and the flag EXT_ATTA_POST is set,
+ * use the JOB_ATTA_DIR parameter in lsb.params(5) to specify the directory
+ * where attachment data fies are saved. The directory must have at least 1MB
+ * of free space.The mbatchd checks for available space in the job attachment
+ * directory before transferring the file.
+ *
+ * Use the MAX_JOB_ATTA_SIZE parameter in lsb.params(5) to set a maximum size
+ * for job message attachments.
+ *
+ * Users can only send messages and data from their own jobs. Root and LSF
+ * administrators can also send messages of jobs submtted by other users, but
+ * they cannot attach data files to jobs owned by other users.
+ *
+ * You can post messages and data to a job until it is cleaned from the system.
+ * You cannot send messages and data to finished or exited jobs.
+ *
+ * <b>\#include <lsf/lsbatch.h> \n
+ * \#include <time.h>
+ *
+ * int lsb_postjobmsg(jobExternalMsgReq.ByReference jobExternalMsg,
+ * String filename)</b>
+ *
+ * @param jobExternalMsg This structure contains the information required to
+ * define an external message of a job.
+ * @param filename Name of attached data file. If no file is attached, use null.
+ *
+ * <b>Data Structures:</b>
+ * \par
+ * \ref jobExternalMsgReq
+ *
+ * <b>Define Statements:</b>
+ * \par
+ * \ref external_msg_post
+ *
+ * @return int:value \n
+ * The successful function returns a socket number.
+ * return int:0 \n
+ * The EXT_ATTA_POST bit of options is not set or there is no attached data.
+ * return int:-1 \n
+ * The function failed.
+ *
+ * \b Errors:
+ * \par
+ * If the function fails, lserrno is set to indicate the error.
+ *
+ * <b>Equivalent line command:</b>
+ * \par
+ * bpost
+ *
+ * \b Files:
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * \n $JOB_ATTA_DIR
+ * \n $LSB_SHAREDIR/info
+ *
+ * #see \ref lsb_readjobmsg
+ *
+ */
+
+ public static native int lsb_postjobmsg(jobExternalMsgReq jobExternalMsg, String filename);
+ /**
+ * \page lsb_readjobmsg lsb_readjobmsg
+ * \brief Reads messages and data posted to a job.
+ *
+ * Use \ref lsb_readjobmsg to open a TCP connection, receive attached messages and
+ * data from the mbatchd, and display the messages posted by \ref lsb_postjobmsg.
+ *
+ * By default, \ref lsb_readjobmsg displays the message "no description" or the
+ * message at index position 0 of the specified job. To read other messages,
+ * choose another index position. The index is populated by \ref lsb_postjobmsg.
+ *
+ * If a data file is attached to a message and the flag EXT_ATTA_READ is set,
+ * \ref lsb_readjobmsg gets the message and copies its data file to the default
+ * directory JOB_ATTA_DIR, overwriting the specified file if it already exists.
+ * If there is no file attached, the system reports an error.
+ *
+ * Users can only read messages and data from their own jobs. Root and LSF
+ * administrators can also read messages of jobs submtted by other users,
+ * but they cannot read data files attached to jobs owned by other users.
+ *
+ * You can read messages and data from a job until it is cleaned from the
+ * system. You cannot read messages and data from done or exited jobs.
+ *
+ * <b>\#include <lsf/lsbatch.h> \n
+ * \#include <time.h> \n
+ * int lsb_readjobmsg(jobExternalMsgReq.ByReference jobExternalMsg,
+ * jobExternalMsgReply.ByReference jobExternalMsgReply)</b>
+ *
+ * @param jobExternalMsg the information required to define an external
+ * message of a job.
+ * @param jobExternalMsgReply the information required to define an
+ * external message reply.
+ *
+ * <b>Data Structures:</b>
+ * \par
+ * jobExternalMsgReq
+ * \n jobExternalMsgReply
+ *
+ * <b>Define Statements:</b>
+ * \par
+ * \ref external_msg_processing
+ * \n \ref ext_data_status
+ *
+ * @return int:value \n
+ * The successful function returns a socket number.
+ * return int:0 \n
+ * The EXT_ATTA_READ bit of options is not set or there is no
+ * attached data.
+ * return int:-1 \n
+ * The function failed.
+ *
+ * \b Errors:
+ * \par
+ * If the function fails, lserrno is set to indicate the error.
+ *
+ * <b>Equivalent line commands:</b>
+ * \par
+ * bread
+ *
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * \n $JOB_ATTA_DIR
+ * \n $LSB_SHAREDIR/info
+ * #see \ref lsb_postjobmsg
+ */
+
+ public static native int lsb_readjobmsg(jobExternalMsgReq jobExternalMsg, jobExternalMsgReply jobExternalMsgReply);
+
+/* API for symphony job information update in bulk mode */
+
+ public static native int lsb_bulkJobInfoUpdate(symJobStatusUpdateReqArray symJobStatusUpdateReqArray1, symJobStatusUpdateReplyArray symJobStatusUpdateReplyArray1);
+
+/* API for advance reservation */
+
+ /**
+ * \page lsb_addreservation lsb_addreservation
+ * \brief Makes an advance reservation.
+ * <p/>
+ * Use \ref lsb_addreservation to send a reservation request to mbatchd. If
+ * mbatchd grants the reservation, it issues the reservation ID. If mbatchd
+ * rejects the request, it issues null as the reservation ID.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_addreservation (addRsvRequest.ByReference request, String rsvId)</b>
+ *
+ * @return int:-1 \n
+ * The reservation failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * brsvadd
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param request The reservation request
+ * @param rsvId Reservation ID returned from mbatchd. If the reservation
+ * fails, this is null. The
+ * memory for rsvid is allocated by the caller.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * addRsvRequest
+ * \n _rsvExecCmd_t
+ * \n _rsvExecEvent_t
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref reservation_option
+ * #see \ref lsb_removereservation
+ * #see \ref lsb_modreservation
+ * #see \ref lsb_reservationinfo
+ */
+ public static native int lsb_addreservation(addRsvRequest request, String rsvId);
+
+ /**
+ * \page lsb_removereservation lsb_removereservation
+ * \brief Removes a reservation.
+ * <p/>
+ * Use \ref lsb_removereservation to remove a reservation. mbatchd removes the
+ * reservation with the specified reservation ID.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_removereservation(String rsvId)</b>
+ *
+ * @return int:-1 \n
+ * The reservation removal failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * brsvdel
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param rsvId Reservation ID of the reservation that you wish to remove.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * #see \ref lsb_addreservation
+ * #see \ref lsb_modreservation
+ * #see \ref lsb_reservationinfo
+ */
+ public static native int lsb_removereservation(String rsvId);
+
+ /**
+ * \page lsb_reservationinfo lsb_reservationinfo
+ * \brief Retrieve reservation information to display active advance reservations.
+ * <p/>
+ * Use \ref lsb_reservationinfo to retrieve reservation information from mbatchd.
+ * This function allocates memory that the caller should free.
+ * <p/>
+ * If the \ref lsb_reservationinfo function succeeds, it returns the reservation
+ * records pertaining to a particular reservation ID (rsvId) as an array of
+ * rsvInfoEnt structs.
+ * <p/>
+ * If rsvId is null, all reservation information will be returned. If a
+ * particular rsvId is specified:
+ * \li If found, the reservation record pertaining to a particular rsvId is
+ * returned
+ * \li If not found, the number of reservation records is set to zero and
+ * the lsberrno is set appropiately
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * rsvInfoEnt.ByReference lsb_reservationinfo(String rsvId, IntByReference numEnts,
+ * int options)</b>
+ *
+ * @param options The parameter options is currently ignored.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * rsvInfoEnt
+ * \n hostRsvInfoEnt
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * brsvs
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param rsvId Reservation ID of the requested reservation.
+ * @param numEnts Number of reservation entries that mbatchd returns.
+ * #see \ref lsb_addreservation
+ * #see \ref lsb_modreservation
+ * #see \ref lsb_removereservation
+ */
+
+ public static native rsvInfoEnt.ByReference lsb_reservationinfo(String rsvId, IntByReference numEnts, int options);
+
+ public static native int lsb_freeRsvExecCmd(Pointer _rsvExecCmd_tArray1);
+
+ public static native _rsvExecCmd_t.ByReference lsb_dupRsvExecCmd(_rsvExecCmd_t _rsvExecCmd_t1);
+
+ public static native int lsb_parseRsvExecOption(String string1, Pointer _rsvExecCmd_tArray1);
+
+ /**
+ * \page lsb_modreservation lsb_modreservation
+ * \brief Modifies an advance reservation.
+ * <p/>
+ * Use \ref lsb_modreservation to modify an advance reservation. mbatchd receives
+ * the modification request and modifies the reservation with the specified
+ * reservation ID.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_modreservation(modRsvRequest.ByReference request)</b>
+ *
+ * @return int:-1 \n
+ * The reservation modification failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * brsvmod
+ * <p/>
+ * \b Files:
+ * \par
+ * none
+ * @param request modify reservation request.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * modRsvRequest
+ * \n addRsvRequest
+ * \n _rsvExecCmd_t
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * #see \ref lsb_addreservation
+ * #see \ref lsb_removereservation
+ * #see \ref lsb_reservationinfo
+ */
+
+ public static native int lsb_modreservation(modRsvRequest request);
+
+/* routines for sorted integer list */
+ /*
+ sortIntList.ByReference initSortIntList(int);
+ int insertSortIntList(sortIntList.ByReference , int);
+ sortIntList.ByReference getNextSortIntList(sortIntList.ByReference , sortIntList.ByReference , IntByReference );
+ void freeSortIntList(sortIntList.ByReference );
+ int getMinSortIntList(sortIntList.ByReference , IntByReference );
+ int getMaxSortIntList(sortIntList.ByReference , IntByReference );
+ int getTotalSortIntList(sortIntList.ByReference );
+
+ int updateJobIdIndexFile (String string1, String string1, int);
+ */
+
+/* Structures and routine for obtaining subset of info about jobs
+* This is being used by Maui integration.
+ */
+
+ public static class jobExtschInfoReq extends Structure {
+ public static class ByReference extends jobExtschInfoReq implements Structure.ByReference {}
+ public static class ByValue extends jobExtschInfoReq implements Structure.ByValue {}
+ public jobExtschInfoReq() {}
+ public jobExtschInfoReq(Pointer p) { super(p); read(); }
+
+ public int qCnt;
+ public Pointer queues;
+ }
+
+
+
+ public static class jobExtschInfo extends Structure {
+ public static class ByReference extends jobExtschInfo implements Structure.ByReference {}
+ public static class ByValue extends jobExtschInfo implements Structure.ByValue {}
+ public jobExtschInfo() {}
+ public jobExtschInfo(Pointer p) { super(p); read(); }
+
+ public long jobId;
+ public int status;
+ public NativeLong jRusageUpdateTime;
+ public LibLsf.jRusage runRusage;
+ }
+
+
+
+ public static class jobExtschInfoReply extends Structure {
+ public static class ByReference extends jobExtschInfoReply implements Structure.ByReference {}
+ public static class ByValue extends jobExtschInfoReply implements Structure.ByValue {}
+ public jobExtschInfoReply() {}
+ public jobExtschInfoReply(Pointer p) { super(p); read(); }
+
+ public int jobCnt;
+ public PointerByReference jobs;
+ }
+
+
+
+ public static native int getjobinfo4queues(jobExtschInfoReq jobExtschInfoReq1, jobExtschInfoReply jobExtschInfoReply1);
+
+ public static native void free_jobExtschInfoReply(jobExtschInfoReply jobExtschInfoReply1);
+
+ public static native void free_jobExtschInfoReq(jobExtschInfoReq jobExtschInfoReq1);
+
+/* For RFC 725 */
+
+ public static native String longer_strcpy(String dest, String src);
+
+/* Structures and API for job diagnostics. These are applicable only if
+* CONDENSE_PENDING_REASONS is enabled in lsb.params.
+ */
+
+ public static class diagnoseJobReq extends Structure {
+ public static class ByReference extends diagnoseJobReq implements Structure.ByReference {}
+ public static class ByValue extends diagnoseJobReq implements Structure.ByValue {}
+ public diagnoseJobReq() {}
+ public diagnoseJobReq(Pointer p) { super(p); read(); }
+
+ public int jobCnt;
+ public LongByReference jobId;
+ }
+
+
+
+ public static native int lsb_diagnosejob(diagnoseJobReq diagnoseJobReq1);
+
+ public static final int SIM_STATUS_RUN = 0x01;
+ public static final int SIM_STATUS_SUSPEND = 0x02;
+
+/* simulator status reply
+ */
+
+ public static class simStatusReply extends Structure {
+ public static class ByReference extends simStatusReply implements Structure.ByReference {}
+ public static class ByValue extends simStatusReply implements Structure.ByValue {}
+ public simStatusReply() {}
+ public simStatusReply(Pointer p) { super(p); read(); }
+
+ public int simStatus;
+ public NativeLong curTime;
+ }
+
+
+
+ public static native simStatusReply.ByReference lsb_simstatus();
+
+ public static native void free_simStatusReply(simStatusReply simStatusReply1);
+
+/* batch command options flag for lease */
+ public static final int LSB_HOST_OPTION_EXPORT = 0x1;
+/* bhosts -x option */
+ public static final int LSB_HOST_OPTION_EXCEPT = 0x2;
+/* retrieve hosts that belong to batch partition */
+ public static final int LSB_HOST_OPTION_BATCH = 0x4;
+
+
+/* Display condensed host output */
+ public static final int LSB_HOST_OPTION_CONDENSED = 0x08;
+
+/* error codes, structures and routines for syntax check of RMS external scheduler options */
+
+/* non-rms option shown up in RMS[] */
+ public static final int RMS_NON_RMS_OPTIONS_ERR = (-1);
+
+/* nodes and ptile co-exist */
+ public static final int RMS_NODE_PTILE_ERR = (-2);
+
+/* rails and railmask co-exist */
+ public static final int RMS_RAIL_RAILMASK_ERR = (-3);
+
+/* nodes is out of range 1..LSB_RMS_MAXNUMNODES */
+ public static final int RMS_NODES_OUT_BOUND_ERR = (-4);
+
+/* ptile is out of range 1..LSB_RMS_MAXPTILE */
+ public static final int RMS_PTILE_OUT_BOUND_ERR = (-5);
+
+/* rails is out of range 1..LSB_RMS_MAXNUMRAILS */
+ public static final int RMS_RAIL_OUT_BOUND_ERR = (-6);
+
+/* railmask syntax error */
+ public static final int RMS_RAILMASK_OUT_BOUND_ERR = (-7);
+
+/* nodes syntax error */
+ public static final int RMS_NODES_SYNTAX_ERR = (-8);
+
+/* ptile syntax error */
+ public static final int RMS_PTILE_SYNTAX_ERR = (-9);
+
+/* rails syntax error */
+ public static final int RMS_RAIL_SYNTAX_ERR = (-10);
+
+/* railmask syntax error */
+ public static final int RMS_RAILMASK_SYNTAX_ERR = (-11);
+
+/* base syntax error */
+ public static final int RMS_BASE_SYNTAX_ERR = (-12);
+
+/* base string too NativeLong*/
+ public static final int RMS_BASE_TOO_LONG = (-13);
+
+/* >=1 allocation types are specified */
+ public static final int RMS_TOO_MANY_ALLOCTYPE_ERR = (-14);
+
+/* =1 allocation types are specified */
+ public static final int RMS_NO_LSF_EXTSCHED_Y_ERR = (-15);
+
+/* error reading env from lsf.conf inside syntax check */
+ public static final int RMS_READ_ENV_ERR = (-20);
+
+/* memory allocation problems inside syntax check function */
+ public static final int RMS_MEM_ALLOC_ERR = (-21);
+
+/* [] mis-matched in RMS[] */
+ public static final int RMS_BRACKETS_MISMATCH_ERR = (-22);
+
+ public static interface rmsAllocType_t {
+ public static final int RMS_ALLOC_TYPE_UNKNOWN = 0;
+ public static final int RMS_ALLOC_TYPE_SLOAD = 1;
+ public static final int RMS_ALLOC_TYPE_SNODE = 2;
+ public static final int RMS_ALLOC_TYPE_MCONT = 3;
+ }
+
+
+
+ public static interface rmsTopology_t {
+ public static final int RMS_TOPOLOGY_UNKNOWN = 0;
+ public static final int RMS_TOPOLOGY_PTILE = 1;
+ public static final int RMS_TOPOLOGY_NODES = 2;
+ }
+
+
+
+ public static interface rmsFlags_t {
+ public static final int RMS_FLAGS_UNKNOWN = 0;
+ public static final int RMS_FLAGS_RAILS = 1;
+ public static final int RMS_FLAGS_RAILMASK = 2;
+ }
+
+
+
+ public static class rmsextschedoption extends Structure {
+ public static class ByReference extends rmsextschedoption implements Structure.ByReference {}
+ public static class ByValue extends rmsextschedoption implements Structure.ByValue {}
+ public rmsextschedoption() {}
+ public rmsextschedoption(Pointer p) { super(p); read(); }
+
+ public /*rmsAllocType_t*/ int alloc_type;
+ public /*rmsTopology_t*/ int topology;
+ public int topology_value;
+ public int set_base;
+ public byte[] base = new byte[LibLsf.MAXHOSTNAMELEN];
+ public /*rmsFlags_t*/ int flags;
+ public int flags_value;
+ }
+
+
+
+ public static native int parseRmsOptions(String string1, rmsextschedoption rmsextschedoption1, LibLsf.config_param config_param1);
+
+/* Stream interface.
+* By default the stream lsb.stream is located in a subdirectory
+* stream of the cluster working directory i.e.:
+* work/<clustername>/logdir/stream and the size of
+* lsb.stream is 1024MB
+ */
+ public static final int MBD_DEF_STREAM_SIZE = (1024 * 1024 * 1024);
+
+/* default maximum number of backup stream.utc file */
+ public static final int DEF_MAX_STREAM_FILE_NUMBER = 10;
+
+ /**
+ * \brief Stream interface.
+ */
+ public static class lsbStream extends Structure {
+ public static class ByReference extends lsbStream implements Structure.ByReference {}
+ public static class ByValue extends lsbStream implements Structure.ByValue {}
+ public lsbStream() {}
+ public lsbStream(Pointer p) { super(p); read(); }
+
+ public static interface trsFunc extends Callback {
+ int invoke(String string1);
+ }
+
+ /**
+ * < Pointer to full path to the stream file
+ */
+ public String streamFile;
+
+ /**
+ * < Max size of the stream file
+ */
+ public int maxStreamSize;
+
+ /**
+ * < Max number of backup stream files
+ */
+ public int maxStreamFileNum;
+
+ /**
+ * < Set to 1 to enable trace of the stream
+ */
+ public int trace;
+
+ /**
+ * < Pointer to a function that the library invokes, passing a trace buffer.
+ */
+ public trsFunc trs;
+ }
+
+
+
+ /**//*
+ * \page lsb_openstream lsb_openstream
+ * \brief Open and create an lsb_stream file.
+ * <p/>
+ * \ref lsb_openstream opens the streamFile .
+ * <p/>
+ * This API function is inside liblsbstream.so.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_openstream(lsbStream.ByReference params)</b>
+ *
+ * @return int:-1 or null \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * @param params Parameters.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * \ref lsbStream
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * #see \ref lsb_closestream
+ * #see \ref lsb_readstreamline
+ * #see \ref lsb_writestream
+ * #see \ref lsb_readstream
+ * #see \ref lsb_streamversion
+ */
+ // NOTE: Not in libbat
+ //public static native int lsb_openstream(lsbStream params);
+
+ /**//*
+ * \page lsb_closestream lsb_closestream
+ * \brief Close an lsb_stream file.
+ * <p/>
+ * \ref lsb_closestream closes the streamFile.
+ * <p/>
+ * This API function is inside liblsbstream.so.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_closestream(String config)</b>
+ *
+ * @return int:-1 \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * @param config Pointer to the handle of the stream file.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * #see \ref lsb_openstream
+ * #see \ref lsb_readstreamline
+ * #see \ref lsb_writestream
+ * #see \ref lsb_readstream
+ * #see \ref lsb_streamversion
+ */
+ // NOTE: Not in libbat
+ //public static native int lsb_closestream(String config);
+
+ /**//*
+ * \page lsb_streamversion lsb_streamversion
+ * \brief Version of the current event type supported by mbatchd.
+ * <p/>
+ * \ref lsb_streamversion returns the event version number of mbatchd, which is the
+ * version of the events to be written to the stream file. This API function
+ * is inside liblsbstream.so.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * String lsb_streamversion()</b>
+ *
+ * param void \n
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * #see \ref lsb_closestream
+ * #see \ref lsb_geteventrec
+ * #see \ref lsb_openstream
+ * #see \ref lsb_puteventrec
+ * #see \ref lsb_readstreamline
+ * #see \ref lsb_writestream
+ * #see \ref lsb_readstream
+ */
+ // NOTE: Not in libbat
+ //public static native String lsb_streamversion();
+
+ /**//*
+ * \page lsb_writestream lsb_writestream
+ * \brief Writes a current version eventRec structure into the lsb_stream file.
+ * <p/>
+ * \ref lsb_writestream writes an eventrRec to the open streamFile.
+ * This API function is inside liblsbstream.so.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_writestream(eventRec.ByReference logPtr)</b>
+ *
+ * @return int:-1 \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * @param logPtr Pointer to the eventRec structure.
+ * \n see \ref lsb_geteventrec for details on the eventRec structure.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * eventRec
+ * \n eventLog
+ * \n xFile
+ * \n jobAttrSetLog
+ * \n logSwitchLog
+ * \n dataLoggingLog
+ * \n jgrpNewLog
+ * \n jgrpCtrlLog
+ * \n jgrpStatusLog
+ * \n jobNewLog
+ * \n jobModLog
+ * \n jobStartLog
+ * \n jobStartAcceptLog
+ * \n jobExecuteLog
+ * \n jobStatusLog
+ * \n sbdJobStatusLog
+ * \n sbdUnreportedStatusLog
+ * \n jobSwitchLog
+ * \n jobMoveLog
+ * \n chkpntLog
+ * \n jobRequeueLog
+ * \n jobCleanLog
+ * \n jobExceptionLog
+ * \n sigactLog
+ * \n migLog
+ * \n signalLog
+ * \n queueCtrlLog
+ * \n hostCtrlLog
+ * \n hgCtrlLog
+ * \n mbdStartLog
+ * \n mbdDieLog
+ * \n unfulfillLog
+ * \n jobFinishLog
+ * \n loadIndexLog
+ * \n calendarLog
+ * \n jobForwardLog
+ * \n jobAcceptLog
+ * \n statusAckLog
+ * \n jobMsgLog
+ * \n jobMsgAckLog
+ * \n jobOccupyReqLog
+ * \n jobVacatedLog
+ * \n jobForceRequestLog
+ * \n jobChunkLog
+ * \n jobExternalMsgLog
+ * \n rsvRes
+ * \n rsvFinishLog
+ * \n cpuProfileLog
+ * \n jobRunRusageLog
+ * \n slaLog
+ * \n perfmonLogInfo
+ * \n perfmonLog
+ * \n taskFinishLog
+ * \n eventEOSLog
+ * \n jobResizeNotifyStartLog
+ * \n jobResizeNotifyAcceptLog
+ * \n jobResizeNotifyDoneLog
+ * \n jobResizeReleaseLog
+ * \n jobResizeCancelLog
+ * \n jobResizeLog
+ * \n jRusage
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref event_types
+ * \n \ref defs_lsb_XF_OP
+ * \n \ref jobgroup_controltypes
+ * \n \ref signal_action
+ * #see \ref lsb_closestream
+ * #see \ref lsb_geteventrec
+ * #see \ref lsb_openstream
+ * #see \ref lsb_puteventrec
+ * #see \ref lsb_readstreamline
+ * #see \ref lsb_streamversion
+ * #see \ref lsb_readstream
+ */
+ // NOTE: Not in libbat
+ //public static native int lsb_writestream(eventRec logPtr);
+
+ /**//*
+ * \page lsb_readstream lsb_readstream
+ * \brief Reads a current version eventRec structure from the lsb_stream file.
+ * <p/>
+ * \ref lsb_readstream reads an eventrRec from the open streamFile.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * eventRec lsb_readstream(IntByReference nline)</b>
+ *
+ * @return int:-1 \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * @param nline Line number in the stream file to be read.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * eventRec
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * #see \ref lsb_closestream
+ * #see \ref lsb_geteventrec
+ * #see \ref lsb_openstream
+ * #see \ref lsb_puteventrec
+ * #see \ref lsb_readstreamline
+ * #see \ref lsb_streamversion
+ * #see \ref lsb_writestream
+ */
+ // NOTE: Not in libbat
+ //public static native eventRec.ByReference lsb_readstream(IntByReference nline);
+
+ /**//*
+ * \page lsb_readstreamline lsb_readstreamline
+ * \brief Reads a current version eventRec structure from the lsb_stream file.
+ * <p/>
+ * \ref lsb_readstreamline reads an eventrRec from the open streamFile
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * eventRec.ByReference lsb_readstreamline(String line)</b>
+ *
+ * @return null \n
+ * The function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * On failure, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * $LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * @param line Line number in the stream file to be read.
+ * See \ref lsb_puteventrec and \ref lsb_geteventrec for details on the eventRec structure.
+ * Additionally, there are three additional event types supported.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * eventRec
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * #see \ref lsb_closestream
+ * #see \ref lsb_geteventrec
+ * #see \ref lsb_openstream
+ * #see \ref lsb_puteventrec
+ * #see \ref lsb_readstream
+ * #see \ref lsb_streamversion
+ * #see \ref lsb_writestream
+ */
+ // NOTE: Not in libbat
+ //public static native eventRec.ByReference lsb_readstreamline(String line);
+
+ public static final int NUM_EXITRATE_TYPES = 4;
+
+/* options for exit rate type */
+
+
+/* all exited jobs */
+ public static final int JOB_EXIT = 0x01;
+
+/* jobs failed to start due to initialization problem on execution host*/
+ public static final int JOB_INIT = 0x02;
+
+/* jobs failed to start due to HPC specific initialization problem on execution host*/
+ public static final int HPC_INIT = 0x04;
+
+/* jobs exited not related to reasons set by LSF */
+ public static final int JOB_EXIT_NONLSF = 0x08;
+
+ /**
+ * \brief APS factor information
+ */
+ public static class apsFactorInfo extends Structure {
+ public static class ByReference extends apsFactorInfo implements Structure.ByReference {}
+ public static class ByValue extends apsFactorInfo implements Structure.ByValue {}
+ public apsFactorInfo() {}
+ public apsFactorInfo(Pointer p) { super(p); read(); }
+
+
+ /**
+ * < Name
+ */
+ public String name;
+
+ /**
+ * < Weight
+ */
+ public float weight;
+
+ /**
+ * < Limit
+ */
+ public float limit;
+
+ /**
+ * < Grace period
+ */
+ public int gracePeriod;
+ }
+
+
+
+/* options for job group delete */
+
+/* delete the specified user's all empty job groups*/
+ public static final int JGRP_DEL_USER_GROUPS = 0x01;
+
+/* delete one job group's all empty children groups including itself*/
+ public static final int JGRP_DEL_CHILD_GROUPS = 0x02;
+
+/* delete all empty job groups */
+ public static final int JGRP_DEL_ALL = 0x04;
+
+ /**
+ * ------------------------------------------------------------------------
+ * lsb_getallocFromHhostfile
+ * <p/>
+ * Read the specified hostfile and return the host list. If path is null
+ * then read the hostfile specified by LSB_DJOB_HOSTFILE. The hostfile
+ * is assumed to be in simple format of one host per line. A host
+ * can be repeated.
+ * <p/>
+ * This function will allocate the memory for hostlist.
+ * It is the responsibility of the caller to free the lists when no longer
+ * needed. On success hostlist will be a list of strings.
+ * Before freeing hostlist the individual
+ * elements must be freed.
+ * <p/>
+ * Parameters:
+ * @param hostlist [OUT]
+ * @param path [IN] path to hostfile, if null check LSB_DJOB_HOSTFILE
+ * <p/>
+ * @return Value:
+ * >0 success, length of hostlist not including the null last element
+ * -1 failure, lsberrno is set
+ * -------------------------------------------------------------------------
+ */
+ public static native int lsb_getallocFromHostfile(Pointer hostlist, String path);
+
+
+ /**
+ * \addtogroup defs_lsb_launch defs_lsb_launch
+ * lsb_launch() Valid options are:
+ */
+
+ /**
+ * < Disable standard input and redirect input from the special device /dev/null. This is equivalent to blaunch -n.
+ */
+ public static final int LSF_DJOB_DISABLE_STDIN = 0x01;
+
+ /**
+ * < Replace existing enviornment variable values with envp.
+ */
+ public static final int LSF_DJOB_REPLACE_ENV = 0x02;
+
+ /**
+ * < Non-blocking mode; the parallel job does not wait once all tasks start. This forces \ref lsb_launch not to wait for its tasks to finish.
+ */
+ public static final int LSF_DJOB_NOWAIT = 0x04;
+
+ /**
+ * < Display standard error messages with a corresponding host name where the message was generated.Cannot be specified with LSF_DJOB_NOWAIT.
+ */
+ public static final int LSF_DJOB_STDERR_WITH_HOSTNAME = 0x08;
+
+ /**
+ * < Display standard output messages with a corresponding host name where the message was generated. Cannot be specified with LSF_DJOB_NOWAIT.
+ */
+ public static final int LSF_DJOB_STDOUT_WITH_HOSTNAME = 0x10;
+
+ /**
+ * < Use user's login shell to launch tasks
+ */
+ public static final int LSF_DJOB_USE_LOGIN_SHELL = 0x20;
+
+ /**
+ * < Use /bin/sh to launch tasks
+ */
+ public static final int LSF_DJOB_USE_BOURNE_SHELL = 0x40;
+
+ /**
+ * < Separate stderr from stdout
+ */
+ public static final int LSF_DJOB_STDERR = 0x80;
+
+/*
+* -------------------------------------------------------------------------
+* lsb_launch (where, argv, options, envp)
+*
+* DESCRIPTION:
+*
+* The specified command (i.e., argv) will be launched on the remote
+* nodes in parallel
+*
+* ARGUMENTS:
+* where [IN]:
+* A null terminated list of hosts.
+* If this parameter is null then the environment variable
+* LSB_MCPU_HOSTS will be used.
+* A task will be launched for each slot.
+* options [IN]:
+* options value obtained by ORing
+* Envp [IN]:
+* A Null terminated list of environment variables (in 'variable=value'
+* format).
+* The environment to set for each task.
+* If this parameter is null then the same environment used to start
+* the first task will be used.
+* If non-null, it is appended to the environment used for the
+* first task.
+* If LSF_DJOB_REPLACE_ENV is specified, Envp entries will overwrite
+* existing values except those LSF needs.
+*
+* RETURN:
+* < 0 on failure
+* > 0 upon success (i.e., number of tasks issued)
+*
+ */
+
+ /**
+ * \page lsb_launch lsb_launch
+ * \brief Launch commands on remote hosts in parallel.
+ * <p/>
+ * \ref lsb_launch is a synchronous API call to allow source level integration with
+ * vendor MPI implementations. This API will launch the specified command (argv)
+ * on the remote nodes in parallel.
+ * \n LSF must be installed before integrating your MPI implementation with
+ * \ref lsb_launch. The \ref lsb_launch API requires the full set of liblsf.so,
+ * libbat.so (or liblsf.a, libbat.a).
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_launch (String[] where, String[] argv, int userOptions, String[] envp)</b>
+ *
+ * @param userOptions [IN] Options to modify the behavior of \ref lsb_launch
+ * Multiple option values can be specified. For example option values can be
+ * separated by OR (|):
+ * \n \ref lsb_launch (where, argv, LSF_DJOB_REPLACE_ENV | LSF_DJOB_DISABLE_STDIN, envp);
+ * @return < 0 \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line command:</b>
+ * \par
+ * blaunch
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param where [IN] A null-terminated list of hosts. A task will be launched
+ * for each slot.If this parameter is null then the environment variable
+ * LSB_MCPU_HOSTS will be used.
+ * @param argv [IN] The command to be executed
+ * @param envp [IN] A null-terminated list of environment variables specifying
+ * the environment to set for each task.If envp is null, \ref lsb_launch uses the
+ * same environment used to start the first task on the first execution host.
+ * If non-null, envp values are appended to the environment used for the first
+ * task.If the LSF_DJOB_REPLACE_ENV option is specified, envp entries will
+ * overwrite all existing environment values except those needed by LSF.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref defs_lsb_launch
+ * see none
+ */
+ public static native int lsb_launch(Pointer where, Pointer argv, int userOptions, Pointer envp);
+
+/*
+* -------------------------------------------------------------------------
+* lsb_getalloc
+*
+* This function will allocate the memory for hostlist.
+*
+* It is the responsibility of the caller to free the lists when no longer
+* needed. On success hostlist will be a list of strings.
+* Before freeing hostlist the individual
+* elements must be freed.
+*
+* Parameters:
+* hostlist [OUT] null terminated list of hosts
+*
+* Returns:
+* >0 success, length of hostlist not including the null last element
+* -1 failure, lsberrno is set
+*
+* -------------------------------------------------------------------------
+ */
+
+ /**
+ * \page lsb_getalloc lsb_getalloc
+ * \brief Allocates memory for a host list to be used for launching parallel
+ * tasks through blaunch and the \ref lsb_launch API.
+ * <p/>
+ * It is the responsibility of the caller to free the host list when it is
+ * no longer needed.On success, the host list will be a list of strings.
+ * Before freeing host list, the individual elements must be freed.
+ * <p/>
+ * An application using the \ref lsb_getalloc API is assumed to be part of an
+ * LSF job, and that LSB_MCPU_HOSTS is set in the environment.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_getalloc(String[][] hostlist)</b>
+ *
+ * @return < 0 \n
+ * Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * If the function fails, lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param hostlist [OUT] A null-terminated list of host names
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * see none
+ */
+ public static native int lsb_getalloc(Pointer hostlist);
+
+ /**
+ * \page lsb_resize_cancel lsb_resize_cancel
+ * \brief Cancels a pending job resize allocation request.
+ * <p/>
+ * Use \ref lsb_resize_cancel to cancel a pending allocation request for a
+ * resizable job. A running job can only have one pending request at any
+ * particular time. If one request is still pending, additional requests
+ * are rejected with a proper error code.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_resize_cancel(long jobId);</b>
+ *
+ * @param jobId LSF job ID
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ * @return int:-1 \n
+ * On failure, returns -1.
+ * <p/>
+ * \b Errors:
+ * \par
+ * lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * bresize cancel job_ID
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * #see \ref lsb_resize_release
+ */
+
+ public static native int lsb_resize_cancel(long jobId);
+
+ /**
+ * \page lsb_resize_release lsb_resize_release
+ * \brief Releases part of the allocation of a running resizable job.
+ * <p/>
+ * Use \ref lsb_resize_release to release part of a running job allocation.
+ * A running job can only have one pending request at any particular time.
+ * If one request is still pending, additional requests are rejected with
+ * a proper error code.
+ * <p/>
+ * If a notification command is defined through job submission, application
+ * profile,or the \ref lsb_resize_release API, the notification command is invoked
+ * on the first execution host of the job allocation once allocation resize
+ * requests have been satisfied.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * int lsb_resize_release(job_resize_release.ByReference req);</b>
+ *
+ * @return int:-1 \n
+ * On failure, returns -1.
+ * <p/>
+ * \b Errors:
+ * \par
+ * lsberrno is set to indicate the error.
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * release [-c] [-rnc resize_notification_cmd | -rncn] released_host_specification job_ID
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param req job resize release request.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * job_resize_release
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref resizablejob_related
+ * #see \ref lsb_resize_cancel
+ */
+ public static native int lsb_resize_release(job_resize_release req);
+
+ public static native int lsb_resize_request(job_resize_request job_resize_request1);
+
+ /**
+ * \page lsb_getjobdepinfo lsb_getjobdepinfo
+ * Returns the job dependency information.
+ * <p/>
+ * \ref lsb_getjobdepinfo returns information about jobs (including job arrays) when
+ * a job has one or more dependencies on it.
+ * <p/>
+ * <b>\#include <lsf/lsbatch.h>
+ * <p/>
+ * jobDependInfo.ByReference
+ * lsb_getjobdepinfo(jobDepRequest.ByReference jobdepReq)</b>
+ *
+ * @return null
+ * \n Function failed.
+ * <p/>
+ * \b Errors:
+ * \par
+ * none
+ * <p/>
+ * <b>Equivalent line commands:</b>
+ * \par
+ * none
+ * <p/>
+ * <b>Files:</b>
+ * \par
+ * none
+ * @param jobdepReq Job dependent Request.
+ * <p/>
+ * <b>Data Structures:</b>
+ * \par
+ * dependJobs
+ * \n queriedJobs
+ * \n jobDependInfo
+ * \n jobDepRequest
+ * <p/>
+ * <b>Define Statements:</b>
+ * \par
+ * \ref job_has_depend
+ * \n \ref query_depend
+ */
+ public static native jobDependInfo.ByReference lsb_getjobdepinfo(jobDepRequest jobdepReq);
+
+
+ /**
+ * \page lsb_jsdl2submit lsb_jsdl2submit
+ * \brief Accepts a JSDL job submission file as input and converts the file
+ * for use with LSF.
+ *
+ * \ref lsb_jsdl2submit converts parameters specified in the JSDL file and merges
+ * them with the other command line and job script options. The merged submit
+ * request is then sent to mbatchd for processing.
+ *
+ * Code must link to LSF_LIBDIR/libbat.jsdl.lib
+ *
+ * <b>\#include <lsf/lsbatch.h>
+ *
+ * int lsb_jsdl2submit(submit.ByReference req, String template);</b>
+ *
+ * @param req Reads the specified JSDL options and maps them to the
+ * submitReq structure. Code must specify either jsdl or jsdl_strict.
+ * @param template The default template, which contains all of the bsub
+ * submission options.
+ *
+ * <b>Data Structures:</b>
+ * \par
+ * submit
+ *
+ * <b>Define Statements:</b>
+ * \par
+ * none
+ *
+ * @return int:0 \n
+ * Function completed successfully.
+ * @return int:-1 \n
+ * Function failed.
+ *
+ * <b>Errors:</b>
+ * \par
+ * On failure, sets lsberrno to indicate the error.
+ *
+ * <b>Equivalent line command:</b>
+ * \par
+ * bsub with options
+ *
+ * <b>Files:</b>
+ * \par
+ * $LSF_LIBDIR/jsdl.xsd
+ * \n $LSF_LIBDIR/jsdl-posix.xsd
+ * \n $LSF_LIBDIR/jsdl-lsf.xsd
+ *
+ * @see \ref lsb_submit
+ * @see \ref lsb_modify
+ */
+
+ /**
+ * \page lsblib lsblib
+ * \brief Application Programming Interface (API) library functions for batch jobs
+ *
+ * LSBLIB functions allow application programs to get information about the hosts,
+ * queues, users, jobs and configuration of the batch system. Application programs
+ * can also submit jobs and control hosts, queues and jobs. Finally, application
+ * programs can read batch log files and write batch error messages.
+ *
+ * \note
+ * \par
+ * All LSBLIB APIs require that the batch header file <lsf/lsbatch.h> be included.
+ * \par
+ * Many LSBLIB APIs return a pointer to an array or structure. These data structures
+ * are in static storage or on the heap. The next time the API is called, the storage
+ * is overwritten or freed.
+ * \par
+ * Any program using LSBLIB APIs that change the state of the batch system (that
+ * is, except for APIs that just get information about the system) must be setuid
+ * to root if LSF_AUTH is not defined in the lsf.conf file.
+ * \par
+ * On systems which have both System V and BSD programming interfaces, LSBLIB
+ * typically requires the BSD programming interface. On System V-based versions of
+ * UNIX, for example SGI IRIX, it is normally necessary to link applications using
+ * LSBLIB with the BSD compatibility library.
+ * \par
+ * On AFS systems, the following needs to be added to the end of your linkage
+ * specifications when linking with LSBLIB (assuming your AFS library path is
+ * /usr/afsws):
+ * \par
+ * For HP-UX and Solaris,
+ * \par
+ * -lc -L/usr/afsws/lib -L/usr/afsws/lib/afs -lsys -lrx -llwp /usr/afsws/lib/afs/util.a
+ * \par
+ * For other platforms,
+ * \par
+ * -lc -L/usr/afsws/lib -L/usr/afsws/lib/afs -lsys -lrx -llwp
+ *
+ * \b Files:
+ * \par
+ * ${LSF_ENVDIR:-/etc}/lsf.conf
+ * \n $LSF_CONFDIR/lsf.shared
+ * \n $LSF_CONFDIR/lsf.cluster.cluster_name
+ * \n $LSF_CONFDIR/lsf.task
+ * \n $LSF_CONFDIR/lsf.task.cluster_name
+ * \n $LSB_CONFDIR/cluster_name/configdir/lsb.hosts
+ * \n $$LSB_CONFDIR/cluster_name/configdir/lsb.params
+ * \n $LSB_CONFDIR/cluster_name/configdir/lsb.queues
+ * \n $LSB_CONFDIR/cluster_name/configdir/lsb.users
+ *
+ * @see lsblibapis
+ */
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/lsf/v7_0_6/LibLsf.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/lsf/v7_0_6/LibLsf.java
new file mode 100644
index 0000000..cc4721d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/jna/lsf/v7_0_6/LibLsf.java
@@ -0,0 +1,1780 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.lsf.v7_0_6;
+
+import com.sun.jna.*;
+import com.sun.jna.ptr.FloatByReference;
+import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.ptr.PointerByReference;
+import org.broadinstitute.gatk.utils.jna.clibrary.JNAUtils;
+import org.broadinstitute.gatk.utils.jna.clibrary.LibC.timeval;
+
+/*
+ NOTE: This library uses Pointer for some Struct.ByReference members going
+ against the JNA recommendations at http://jna.java.net/#structure_use
+ Instead stuct arrays are Pointers and each structure contains a
+ constructor that can accept the Pointer iff the size of the array is
+ known to be greater than zero.
+
+ This was especially problematic in jobInfoEnt->items->resName. When
+ jobInfo->reserveCnt was zero jobInfoItems->items was not necessarily null.
+
+ LSF will often reuse memory for structure arrays but will set the
+ array size / count (reserveCnt above) to zero when the array should
+ not be accessed. When LSF has reused memory and points to a non-null
+ structure pointer (items) the inner structure may contain further
+ garbage pointers (especially items->resName).
+
+ When JNA sees a non-null Structure.ByReference it will autoRead() the
+ member. When autoRead() eventually gets to the items->resName trying
+ to run strlen on the bad memory address causes a SIGSEGV.
+
+ By using a Pointer instead of the Structure.ByReference JNA will not
+ automatically autoRead(), and the API user will have to pass the
+ pointer to the Structure on their own.
+*/
+
+/**
+ * JNA wrappers for LSF's lsf.h and -llsf
+ *
+ * $Id: base.h,v 1.25.6.12.2.5.2.11.2.15 2009/08/17 07:25:05 qlnie Exp $
+ ****************************************************************************
+ *
+ * Load Sharing Facility
+ *
+ * Header file for all components of load sharing facility.
+ *
+ ****************************************************************************/
+ at SuppressWarnings("unused")
+public class LibLsf {
+
+ static {
+ /*
+ LSF 7.0.6 on the mac is missing the unsatisfied exported symbol for environ which was removed on MacOS X 10.5+.
+ nm $LSF_LIBDIR/liblsf.dylib | grep environ
+ See "man environ" for more info, along with http://lists.apple.com/archives/java-dev/2007/Dec/msg00096.html
+ For now, we export environ ourselves using libenvironhack.dylib available in c/libenvironhack.
+ */
+ if (Platform.isMac())
+ NativeLibrary.getInstance("environhack");
+ String lsfLibDir = System.getenv("LSF_LIBDIR");
+ if (lsfLibDir != null) {
+ NativeLibrary.addSearchPath("lsf", lsfLibDir);
+ }
+ Native.register("lsf");
+ }
+
+ public static final String PASSWD_FILE_LS = "passwd.lsfuser";
+ public static final int PASSWORD_LEN = 64;
+ public static final int MAXHOSTNAMELEN = JNAUtils.MAXHOSTNAMELEN;
+ public static final int MAXPATHLEN = JNAUtils.MAXPATHLEN;
+
+
+ public static final int LOG_EMERG = 0;
+ public static final int LOG_ALERT = 1;
+ public static final int LOG_CRIT = 2;
+ public static final int LOG_ERR = 3;
+ public static final int LOG_WARNING = 4;
+ public static final int LOG_NOTICE = 5;
+ public static final int LOG_INFO = 6;
+ public static final int LOG_DEBUG = 7;
+
+ public static final int INVALID_SOCKET = -1;
+
+ public static boolean SOCK_INVALID(int c) {
+ return ((c) == INVALID_SOCKET);
+ }
+
+ public static class rlimit extends Structure {
+ public static class ByReference extends rlimit implements Structure.ByReference {}
+ public static class ByValue extends rlimit implements Structure.ByValue {}
+ public rlimit() {}
+ public rlimit(Pointer p) { super(p); read(); }
+
+ public NativeLong rlim_cur;
+ public NativeLong rlim_max;
+ }
+
+
+
+ public static class rusage extends Structure {
+ public static class ByReference extends rusage implements Structure.ByReference {}
+ public static class ByValue extends rusage implements Structure.ByValue {}
+ public rusage() {}
+ public rusage(Pointer p) { super(p); read(); }
+
+ public timeval ru_utime;
+ public timeval ru_stime;
+
+
+ public NativeLong ru_maxrss;
+ //public static final int ru_first = ru_ixrss;
+ public NativeLong ru_ixrss;
+ public NativeLong ru_idrss;
+ public NativeLong ru_isrss;
+ public NativeLong ru_minflt;
+ public NativeLong ru_majflt;
+ public NativeLong ru_nswap;
+ public NativeLong ru_inblock;
+ public NativeLong ru_oublock;
+ public NativeLong ru_msgsnd;
+ public NativeLong ru_msgrcv;
+ public NativeLong ru_nsignals;
+ public NativeLong ru_nvcsw;
+ public NativeLong ru_nivcsw;
+ //public static final int ru_last = ru_nivcsw;
+ // Listed in lsf.h but not present in structure.
+ //public NativeLong ru_ioch;
+ }
+
+
+
+
+ public static final String _VERSION_STR_ = "Platform LSF 7.0";
+ public static final String _WORKGROUP_STR_ = "";
+ public static final String _MINOR_STR_ = "";
+ public static final String _BUILD_STR_ = "";
+ public static final String _NOTE_STR_ = "";
+ public static final String _HOTFIX_STR_ = "";
+ public static final String _OS_STR_ = "";
+
+ public static final String _DATE_STR_ = "";
+ public static final String _BUILD_INFO_ = _MINOR_STR_ + "" + _BUILD_STR_ + "" + _WORKGROUP_STR_ + ", " + _DATE_STR_ + "\nCopyright 1992-2009 Platform Computing Corporation\n\n" + _OS_STR_ + _NOTE_STR_ + _HOTFIX_STR_;
+ public static final String _LS_VERSION_ = (_VERSION_STR_ + "" + _BUILD_INFO_);
+
+ //public static int XDR_SETPOS (int xdrs, int pos) { (*(xdrs)->x_ops->x_setpostn)(xdrs, 0); return (*(xdrs)->x_ops->x_setpostn)(xdrs, pos); }
+ //public static int xdr_setpos (int xdrs, int pos) { (*(xdrs)->x_ops->x_setpostn)(xdrs, 0); return (*(xdrs)->x_ops->x_setpostn)(xdrs, pos); }
+
+
+ public static final int LSF_XDR_VERSION2_0 = 1;
+ public static final int LSF_XDR_VERSION2_1 = 2;
+ public static final int LSF_XDR_VERSION2_2 = 3;
+ public static final int LSF_XDR_VERSION3_0 = 4;
+ public static final int LSF_XDR_VERSION3_1 = 5;
+ public static final int LSF_XDR_VERSION3_2 = 6;
+ public static final int LSF_XDR_VERSION3_2_2 = 7;
+ public static final int LSF_XDR_VERSION4_0 = 8;
+ public static final int LSF_XDR_VERSION4_1 = 9;
+ public static final int LSF_XDR_VERSION4_2 = 10;
+ public static final int LSF_XDR_VERSION5_0 = 11;
+ public static final int LSF_XDR_VERSION5_1 = 12;
+ public static final int LSF_XDR_VERSION6_0 = 13;
+ public static final int LSF_XDR_VERSION6_1 = 14;
+ public static final int LSF_XDR_VERSION6_2 = 15;
+ public static final int EGO_XDR_VERSION_1_1 = 16;
+ public static final int LSF_XDR_VERSION7_0 = 17;
+ public static final int EGO_XDR_VERSION_1_2 = LSF_XDR_VERSION7_0;
+ public static final int LSF_XDR_VERSION7_0_EP1 = 18;
+ public static final int LSF_XDR_VERSION7_0_EP2 = 19;
+ public static final int LSF_XDR_VERSION7_0_EP3 = 20;
+ public static final int LSF_XDR_VERSION7_0_EP4 = 21;
+ public static final int LSF_XDR_VERSION7_0_EP5 = 22;
+ public static final int LSF_XDR_VERSION7_0_EP6 = 23;
+ public static final int EGO_XDR_VERSION_1_2_2 = LSF_XDR_VERSION7_0_EP1;
+ public static final int EGO_XDR_VERSION_1_2_3 = LSF_XDR_VERSION7_0_EP2;
+
+ public static final int EGO_XDR_VERSION = LSF_XDR_VERSION7_0_EP2;
+
+ //public String LOG_VERSION;
+
+ public static final int LSF_DEFAULT_SOCKS = 15;
+ public static final int MAXLINELEN = 512;
+ public static final int MAXLSFNAMELEN = 40;
+ public static final int MAXLSFNAMELEN_70_EP1 = 128;
+
+ public static final int MAXSRES = 32;
+ public static final int MAXRESDESLEN = 256;
+ public static final int NBUILTINDEX = 11;
+ public static final int MAXTYPES = 128;
+ public static final int MAXMODELS = 1024 + 2;
+ public static final int MAXMODELS_70 = 128;
+ public static final int MAXTYPES_31 = 25;
+ public static final int MAXMODELS_31 = 30;
+ public static final int MAXFILENAMELEN = 256;
+ public static final int MAXEVARS = 30;
+
+ public static final int GENMALLOCPACE = 1024;
+
+
+ public static final int FIRST_RES_SOCK = 20;
+
+
+ public static final int R15S = 0;
+ public static final int R1M = 1;
+ public static final int R15M = 2;
+ public static final int UT = 3;
+ public static final int PG = 4;
+ public static final int IO = 5;
+ public static final int LS = 6;
+ public static final int IT = 7;
+ public static final int TMP = 8;
+ public static final int SWP = 9;
+ public static final int MEM = 10;
+ public static final int USR1 = 11;
+ public static final int USR2 = 12;
+
+
+ public static final float INFINIT_LOAD = (float) (0x7fffffff);
+ public static final float INFINIT_FLOAT = (float) (0x7fffffff);
+
+ public static final int INFINIT_INT = 0x7fffffff;
+ public static final long INFINIT_LONG_INT = 0x7fffffffffffffffL;
+ public static final short INFINIT_SHORT = 0x7fff;
+
+ public static final int DEFAULT_RLIMIT = -1;
+
+ public static final int LSF_RLIMIT_CPU = 0;
+ public static final int LSF_RLIMIT_FSIZE = 1;
+ public static final int LSF_RLIMIT_DATA = 2;
+ public static final int LSF_RLIMIT_STACK = 3;
+ public static final int LSF_RLIMIT_CORE = 4;
+ public static final int LSF_RLIMIT_RSS = 5;
+ public static final int LSF_RLIMIT_NOFILE = 6;
+ public static final int LSF_RLIMIT_OPEN_MAX = 7;
+ public static final int LSF_RLIMIT_VMEM = 8;
+ public static final int LSF_RLIMIT_SWAP = LSF_RLIMIT_VMEM;
+ public static final int LSF_RLIMIT_RUN = 9;
+ public static final int LSF_RLIMIT_PROCESS = 10;
+ public static final int LSF_RLIMIT_THREAD = 11;
+ public static final int LSF_RLIM_NLIMITS = 12;
+
+ public static final int LSF_RLIM_NLIMITS5_1 = 11;
+
+ //public static int seteuid (int x) { return setresuid(-1,x,-1); }
+ //public static int setegid (int x) { return setresgid(-1,x,-1); }
+
+ public static final int LSF_NULL_MODE = 0;
+ public static final int LSF_LOCAL_MODE = 1;
+ public static final int LSF_REMOTE_MODE = 2;
+
+
+ public static final int RF_MAXHOSTS = 5;
+
+
+ public static final int RF_CMD_MAXHOSTS = 0;
+
+
+ public static final int RF_CMD_RXFLAGS = 2;
+
+
+ public static final int STATUS_TIMEOUT = 125;
+ public static final int STATUS_IOERR = 124;
+ public static final int STATUS_EXCESS = 123;
+ public static final int STATUS_REX_NOMEM = 122;
+ public static final int STATUS_REX_FATAL = 121;
+ public static final int STATUS_REX_CWD = 120;
+ public static final int STATUS_REX_PTY = 119;
+ public static final int STATUS_REX_SP = 118;
+ public static final int STATUS_REX_FORK = 117;
+ public static final int STATUS_REX_AFS = 116;
+ public static final int STATUS_REX_UNKNOWN = 115;
+ public static final int STATUS_REX_NOVCL = 114;
+ public static final int STATUS_REX_NOSYM = 113;
+ public static final int STATUS_REX_VCL_INIT = 112;
+ public static final int STATUS_REX_VCL_SPAWN = 111;
+ public static final int STATUS_REX_EXEC = 110;
+ public static final int STATUS_REX_MLS_INVAL = 109;
+ public static final int STATUS_REX_MLS_CLEAR = 108;
+ public static final int STATUS_REX_MLS_RHOST = 107;
+ public static final int STATUS_REX_MLS_DOMIN = 106;
+ public static final int STATUS_DENIED = 105;
+
+
+ public static boolean REX_FATAL_ERROR(int s) {
+ return (((s) == STATUS_REX_NOVCL) || ((s) == STATUS_REX_NOSYM) || ((s) == STATUS_REX_NOMEM) || ((s) == STATUS_REX_FATAL) || ((s) == STATUS_REX_CWD) || ((s) == STATUS_REX_PTY) || ((s) == STATUS_REX_VCL_INIT) || ((s) == STATUS_REX_VCL_SPAWN) || ((s) == STATUS_REX_MLS_INVAL) || ((s) == STATUS_REX_MLS_CLEAR) || ((s) == STATUS_REX_MLS_RHOST) || ((s) == STATUS_REX_MLS_DOMIN));
+ }
+
+
+ public static final int REXF_USEPTY = 0x00000001;
+ public static final int REXF_CLNTDIR = 0x00000002;
+ public static final int REXF_TASKPORT = 0x00000004;
+ public static final int REXF_SHMODE = 0x00000008;
+ public static final int REXF_TASKINFO = 0x00000010;
+ public static final int REXF_REQVCL = 0x00000020;
+ public static final int REXF_SYNCNIOS = 0x00000040;
+ public static final int REXF_TTYASYNC = 0x00000080;
+ public static final int REXF_STDERR = 0x00000100;
+
+
+ public static final int EXACT = 0x01;
+ public static final int OK_ONLY = 0x02;
+ public static final int NORMALIZE = 0x04;
+ public static final int LOCALITY = 0x08;
+ public static final int IGNORE_RES = 0x10;
+ public static final int LOCAL_ONLY = 0x20;
+ public static final int DFT_FROMTYPE = 0x40;
+ public static final int ALL_CLUSTERS = 0x80;
+ public static final int EFFECTIVE = 0x100;
+
+
+ public static final int RECV_FROM_CLUSTERS = 0x200;
+ public static final int NEED_MY_CLUSTER_NAME = 0x400;
+
+
+ public static final int SEND_TO_CLUSTERS = 0x400;
+
+
+ public static final int NO_SORT = 0x800;
+
+
+ public static final int EXCLUSIVE_RESOURCE = 0x1000;
+
+ public static final int DT_CLUSTER_LOAD = 0x2000;
+
+
+ public static final int FROM_MASTER = 0x01;
+
+
+ public static final int KEEPUID = 0x01;
+
+
+ public static final int RES_CMD_REBOOT = 1;
+
+ public static final int RES_CMD_SHUTDOWN = 2;
+
+ public static final int RES_CMD_LOGON = 3;
+
+ public static final int RES_CMD_LOGOFF = 4;
+
+
+ public static final int LIM_CMD_REBOOT = 1;
+ public static final int LIM_CMD_SHUTDOWN = 2;
+ public static final int LIM_CMD_REMOVEHOST = 3;
+ public static final int LIM_CMD_ACTIVATE = 4;
+ public static final int LIM_CMD_DEACTIVATE = 5;
+ public static final int LIM_CMD_ELIM_ENV = 6;
+
+
+ public static class connectEnt extends Structure {
+ public static class ByReference extends connectEnt implements Structure.ByReference {}
+ public static class ByValue extends connectEnt implements Structure.ByValue {}
+ public connectEnt() {}
+ public connectEnt(Pointer p) { super(p); read(); }
+
+ public String hostname;
+ public int[] csock = new int[2];
+ }
+
+
+
+ public static final int INTEGER_BITS = 32;
+
+ public static int GET_INTNUM(int i) {
+ return ((i) / INTEGER_BITS + 1);
+ }
+
+
+ public static final int LIM_UNAVAIL = 0x00010000;
+ public static final int LIM_LOCKEDU = 0x00020000;
+ public static final int LIM_LOCKEDW = 0x00040000;
+ public static final int LIM_BUSY = 0x00080000;
+ public static final int LIM_RESDOWN = 0x00100000;
+ public static final int LIM_UNLICENSED = 0x00200000;
+ public static final int LIM_SBDDOWN = 0x00400000;
+ public static final int LIM_LOCKEDM = 0x00800000;
+
+ public static final int LIM_OK_MASK = 0x00bf0000;
+ public static final int LIM_PEMDOWN = 0x01000000;
+ public static final int LIM_LOCKEDU_RMS = 0x80000000;
+
+
+ public static boolean LS_ISUNAVAIL(int[] status) {
+ return (((status) != null) && (((status[0]) & LIM_UNAVAIL) != 0));
+ }
+
+
+ public static boolean LS_ISBUSYON(int[] status, int index) {
+ return (((status) != null) && (((status[1 + (index) / INTEGER_BITS]) & (1 << (index) % INTEGER_BITS)) != 0));
+ }
+
+ public static boolean LS_ISBUSY(int[] status) {
+ return (((status) != null) && (((status[0]) & LIM_BUSY) != 0));
+ }
+
+
+ public static boolean LS_ISRMSLOCK(int[] status) {
+ return (((status) != null) && (((status[0]) & LIM_LOCKEDU_RMS) != 0));
+ }
+
+
+ public static boolean LS_ISLOCKEDU(int[] status) {
+ return (((status) != null) && (((status[0]) & LIM_LOCKEDU) != 0));
+ }
+
+
+ public static boolean LS_ISLOCKEDW(int[] status) {
+ return (((status) != null) && (((status[0]) & LIM_LOCKEDW) != 0));
+ }
+
+
+ public static boolean LS_ISLOCKEDM(int[] status) {
+ return (((status) != null) && (((status[0]) & LIM_LOCKEDM) != 0));
+ }
+
+
+ public static boolean LS_ISLOCKED(int[] status) {
+ return (((status) != null) && (((status[0]) & (LIM_LOCKEDU | LIM_LOCKEDW | LIM_LOCKEDM)) != 0));
+ }
+
+
+ public static boolean LS_ISRESDOWN(int[] status) {
+ return (((status) != null) && (((status[0]) & LIM_RESDOWN) != 0));
+ }
+
+
+ public static boolean LS_ISSBDDOWN(int[] status) {
+ return (((status) != null) && (((status[0]) & LIM_SBDDOWN) != 0));
+ }
+
+ public static boolean LS_ISPEMDOWN(int[] status) {
+ return (((status[0]) & LIM_PEMDOWN) != 0);
+ }
+
+
+ public static boolean LS_ISUNLICENSED(int[] status) {
+ return (((status) != null) && (((status[0]) & LIM_UNLICENSED) != 0));
+ }
+
+
+ public static boolean LS_ISOK(int[] status) {
+ return (((status) != null) && ((status[0] & LIM_OK_MASK) == 0));
+ }
+
+
+ public static boolean LS_ISOKNRES(int[] status) {
+ return (((status) != null) && (((status[0] & ~(LIM_LOCKEDU_RMS)) & ~(LIM_RESDOWN | LIM_SBDDOWN | LIM_PEMDOWN)) == 0));
+ }
+
+
+ public static class placeInfo extends Structure {
+ public static class ByReference extends placeInfo implements Structure.ByReference {}
+ public static class ByValue extends placeInfo implements Structure.ByValue {}
+ public placeInfo() {}
+ public placeInfo(Pointer p) { super(p); read(); }
+
+ public byte[] hostName = new byte[MAXHOSTNAMELEN];
+ public int numtask;
+ }
+
+
+
+
+ public static class hostLoad extends Structure {
+ public static class ByReference extends hostLoad implements Structure.ByReference {}
+ public static class ByValue extends hostLoad implements Structure.ByValue {}
+ public hostLoad() {}
+ public hostLoad(Pointer p) { super(p); read(); }
+
+ public byte[] hostName = new byte[MAXHOSTNAMELEN];
+ public IntByReference status;
+ public FloatByReference li;
+ }
+
+
+
+
+ public static interface valueType {
+ public static final int LS_BOOLEAN = 0;
+ public static final int LS_NUMERIC = 1;
+ public static final int LS_STRING = 2;
+ public static final int LS_EXTERNAL = 3;
+ }
+
+
+
+ public static interface orderType {
+ public static final int INCR = 0;
+ public static final int DECR = 1;
+ public static final int NA = 2;
+ }
+
+
+
+
+ public static final int RESF_BUILTIN = 0x01;
+ public static final int RESF_DYNAMIC = 0x02;
+ public static final int RESF_GLOBAL = 0x04;
+ public static final int RESF_SHARED = 0x08;
+ public static final int RESF_LIC = 0x10;
+ public static final int RESF_EXTERNAL = 0x20;
+ public static final int RESF_RELEASE = 0x40;
+ public static final int RESF_DEFINED_IN_RESOURCEMAP = 0x80;
+
+ public static final int RESF_NON_CONSUMABLE = 0x100;
+ public static final int RESF_REDEFINABLE = 0x200;
+ public static final int RESF_ESRES = 0x400;
+
+
+ public static class resItem extends Structure {
+ public static class ByReference extends resItem implements Structure.ByReference {}
+ public static class ByValue extends resItem implements Structure.ByValue {}
+ public resItem() {}
+ public resItem(Pointer p) { super(p); read(); }
+
+ public byte[] name = new byte[MAXLSFNAMELEN];
+ public byte[] des = new byte[MAXRESDESLEN];
+ public /*valueType*/ int valueType;
+ public /*orderType*/ int orderType;
+ public int flags;
+ public int interval;
+ }
+
+
+
+
+ public static class lsInfo extends Structure {
+ public static class ByReference extends lsInfo implements Structure.ByReference {}
+ public static class ByValue extends lsInfo implements Structure.ByValue {}
+ public lsInfo() {}
+ public lsInfo(Pointer p) { super(p); read(); }
+
+ // The current version of JNA's Structure.getNativeAlignment passes a "null" to
+ // Native.getNativeSize() when accessing the contents of a 2D array.
+ // Although the method is marked as protected, there are also multiple "TO DO"
+ // comments so when we upgrade don't want to have specialized code floating around.
+
+ public int nRes;
+ public Pointer /* resItem.ByReference */ resTable;
+ public int nTypes;
+ public byte[] hostTypes = new byte[MAXTYPES * MAXLSFNAMELEN];
+ public int nModels;
+ public byte[] hostModels = new byte[MAXMODELS * MAXLSFNAMELEN];
+ public byte[] hostArchs = new byte[MAXMODELS * MAXLSFNAMELEN_70_EP1];
+ public int[] modelRefs = new int[MAXMODELS];
+ public float[] cpuFactor = new float[MAXMODELS];
+ public int numIndx;
+ public int numUsrIndx;
+ }
+
+
+
+
+ public static final int CLUST_STAT_OK = 0x01;
+ public static final int CLUST_STAT_UNAVAIL = 0x02;
+ public static final int CLUST_STAT_RECV_FROM = 0x04;
+ public static final int CLUST_STAT_SEND_TO = 0x08;
+
+
+ public static boolean IS_DEFAULT_AUTH(byte[] auth) {
+ return (auth == null || auth[0] == '\0');
+ }
+
+
+ public static class clusterInfo extends Structure {
+ public static class ByReference extends clusterInfo implements Structure.ByReference {}
+ public static class ByValue extends clusterInfo implements Structure.ByValue {}
+ public clusterInfo() {}
+ public clusterInfo(Pointer p) { super(p); read(); }
+
+ public byte[] clusterName = new byte[MAXLSFNAMELEN];
+ public int status;
+ public byte[] masterName = new byte[MAXHOSTNAMELEN];
+ public byte[] managerName = new byte[MAXLSFNAMELEN];
+ public int managerId;
+ public int numServers;
+ public int numClients;
+ public int nRes;
+ public Pointer resources;
+ public int nTypes;
+ public Pointer hostTypes;
+ public int nModels;
+ public Pointer hostModels;
+ public int nAdmins;
+ public IntByReference adminIds;
+ public Pointer admins;
+ public int analyzerLicFlag;
+ public int jsLicFlag;
+ public byte[] afterHoursWindow = new byte[MAXLINELEN];
+ public byte[] preferAuthName = new byte[MAXLSFNAMELEN];
+ public byte[] inUseAuthName = new byte[MAXLSFNAMELEN];
+ }
+
+
+ public static class hostInfo extends Structure {
+ public static class ByReference extends hostInfo implements Structure.ByReference {}
+ public static class ByValue extends hostInfo implements Structure.ByValue {}
+ public hostInfo() {}
+ public hostInfo(Pointer p) { super(p); read(); }
+
+ public byte[] hostName = new byte[MAXHOSTNAMELEN];
+ public String hostType;
+ public String hostModel;
+ public float cpuFactor;
+ public int maxCpus;
+ public int maxMem;
+ public int maxSwap;
+ public int maxTmp;
+ public int nDisks;
+ public int nRes;
+ public Pointer resources;
+ public int nDRes;
+ public Pointer DResources;
+ public String windows;
+ public int numIndx;
+ public FloatByReference busyThreshold;
+ public byte isServer;
+ public byte licensed;
+ public int rexPriority;
+ public int licFeaturesNeeded;
+
+
+ public static final int LSF_BASE_LIC = 0;
+ public static final int LSF_BATCH_LIC_OBSOLETE = 1;
+ public static final int LSF_JS_SCHEDULER_LIC = 2;
+ public static final int LSF_JS_LIC = 3;
+ public static final int LSF_CLIENT_LIC = 4;
+ public static final int LSF_MC_LIC = 5;
+ public static final int LSF_ANALYZER_SERVER_LIC = 6;
+ public static final int LSF_MAKE_LIC = 7;
+
+ public static final int LSF_PARALLEL_LIC = 8;
+ public static final int LSF_FLOAT_CLIENT_LIC = 9;
+ public static final int LSF_FTA_LIC = 10;
+ public static final int LSF_AFTER_HOURS_LIC = 11;
+ public static final int LSF_RESOURCE_PREEMPT_LIC = 12;
+ public static final int LSF_BACCT_LIC = 13;
+ public static final int LSF_SCHED_FAIRSHARE_LIC = 14;
+ public static final int LSF_SCHED_RESERVE_LIC = 15;
+ public static final int LSF_SCHED_PREEMPTION_LIC = 16;
+ public static final int LSF_SCHED_PARALLEL_LIC = 17;
+ public static final int LSF_SCHED_ADVRSV_LIC = 18;
+ public static final int LSF_API_CLIENT_LIC = 19;
+
+ public static final int CLUSTERWARE_MANAGER_LIC = 20;
+ public static final int LSF_MANAGER_LIC = 21;
+ public static final int LSF_PCC_HPC_LIC = 22;
+ public static final int sCLUSTERWARE_LIC = 23;
+ public static final int OTTAWA_MANAGER_LIC = 24;
+
+ public static final int SYMPHONY_MANAGER_ONLINE_LIC = 25;
+ public static final int SYMPHONY_MANAGER_BATCH_LIC = 26;
+ public static final int SYMPHONY_SCHED_JOB_PRIORITY_LIC = 27;
+ public static final int LSF_DUALCORE_X86_LIC = 28;
+ public static final int LSF_TSCHED_LIC = 29;
+ public static final int LSF_WORKGROUP_LIC = 30;
+ public static final int LSF_NUM_LIC_TYPE = 31;
+ public static final int LSF_WG_NUM_LIC_TYPE = 2;
+ public static final int LSF_NO_NEED_LIC = 32;
+
+ public int licClass;
+ public int cores;
+ public static final int INET6_ADDRSTRLEN = 46;
+ public byte[] hostAddr = new byte[INET6_ADDRSTRLEN];
+ public int pprocs;
+
+ public int cores_per_proc;
+ public int threads_per_core;
+ }
+
+ public static boolean HAS_BATCH_LICENSES(int featureEnabled) {
+ return (JNAUtils.toBoolean(featureEnabled & (1 << hostInfo.CLUSTERWARE_MANAGER_LIC)) || JNAUtils.toBoolean(featureEnabled & (1 << hostInfo.LSF_MANAGER_LIC)) || JNAUtils.toBoolean(featureEnabled & (1 << hostInfo.LSF_WORKGROUP_LIC)) || JNAUtils.toBoolean(featureEnabled & (1 << hostInfo.SYMPHONY_MANAGER_ONLINE_LIC)) || JNAUtils.toBoolean(featureEnabled & (1 << hostInfo.SYMPHONY_MANAGER_BATCH_LIC)));
+ }
+
+ public static boolean HAS_SYMPHONY_LICENSES(int featureEnabled) {
+ return (JNAUtils.toBoolean(featureEnabled & (1 << hostInfo.SYMPHONY_MANAGER_ONLINE_LIC)) || JNAUtils.toBoolean(featureEnabled & (1 << hostInfo.SYMPHONY_MANAGER_BATCH_LIC)));
+ }
+
+
+ public static class config_param extends Structure {
+ public static class ByReference extends config_param implements Structure.ByReference {}
+ public static class ByValue extends config_param implements Structure.ByValue {}
+ public config_param() {}
+ public config_param(Pointer p) { super(p); read(); }
+
+ public String paramName;
+ public String paramValue;
+ }
+
+
+
+ public static class lsfRusage extends Structure {
+ public static class ByReference extends lsfRusage implements Structure.ByReference {}
+ public static class ByValue extends lsfRusage implements Structure.ByValue {}
+ public lsfRusage() {}
+ public lsfRusage(Pointer p) { super(p); read(); }
+
+ public double ru_utime;
+ public double ru_stime;
+ public double ru_maxrss;
+ public double ru_ixrss;
+ public double ru_ismrss;
+ public double ru_idrss;
+ public double ru_isrss;
+ public double ru_minflt;
+ public double ru_majflt;
+ public double ru_nswap;
+ public double ru_inblock;
+ public double ru_oublock;
+ public double ru_ioch;
+ public double ru_msgsnd;
+ public double ru_msgrcv;
+ public double ru_nsignals;
+ public double ru_nvcsw;
+ public double ru_nivcsw;
+ public double ru_exutime;
+ }
+
+
+
+
+ public static class lsfAcctRec extends Structure {
+ public static class ByReference extends lsfAcctRec implements Structure.ByReference {}
+ public static class ByValue extends lsfAcctRec implements Structure.ByValue {}
+ public lsfAcctRec() {}
+ public lsfAcctRec(Pointer p) { super(p); read(); }
+
+ public int pid;
+ public String username;
+ public int exitStatus;
+ public NativeLong dispTime;
+ public NativeLong termTime;
+ public String fromHost;
+ public String execHost;
+ public String cwd;
+ public String cmdln;
+ public lsfRusage lsfRu;
+ }
+
+
+
+
+ public static class confNode extends Structure {
+ public static class ByReference extends confNode implements Structure.ByReference {}
+ public static class ByValue extends confNode implements Structure.ByValue {}
+ public confNode() {}
+ public confNode(Pointer p) { super(p); read(); }
+
+ public confNode.ByReference leftPtr;
+ public confNode.ByReference rightPtr;
+ public confNode.ByReference fwPtr;
+ public String cond;
+ public int beginLineNum;
+ public int numLines;
+ public Pointer lines;
+ public byte tag;
+ }
+
+
+
+ public static class pStack extends Structure {
+ public static class ByReference extends pStack implements Structure.ByReference {}
+ public static class ByValue extends pStack implements Structure.ByValue {}
+ public pStack() {}
+ public pStack(Pointer p) { super(p); read(); }
+
+ public int top;
+ public int size;
+ public PointerByReference nodes;
+ }
+
+
+
+ public static class confHandle extends Structure {
+ public static class ByReference extends confHandle implements Structure.ByReference {}
+ public static class ByValue extends confHandle implements Structure.ByValue {}
+ public confHandle() {}
+ public confHandle(Pointer p) { super(p); read(); }
+
+ public confNode.ByReference rootNode;
+ public String fname;
+ public confNode.ByReference curNode;
+ public int lineCount;
+ public pStack.ByReference ptrStack;
+ }
+
+
+
+ public static class lsConf extends Structure {
+ public static class ByReference extends lsConf implements Structure.ByReference {}
+ public static class ByValue extends lsConf implements Structure.ByValue {}
+ public lsConf() {}
+ public lsConf(Pointer p) { super(p); read(); }
+
+ public confHandle.ByReference confhandle;
+ public int numConds;
+ public Pointer conds;
+ public IntByReference values;
+ }
+
+
+
+ public static class sharedConf extends Structure {
+ public static class ByReference extends sharedConf implements Structure.ByReference {}
+ public static class ByValue extends sharedConf implements Structure.ByValue {}
+ public sharedConf() {}
+ public sharedConf(Pointer p) { super(p); read(); }
+
+ public lsInfo.ByReference lsinfo;
+ public int numCls;
+ public Pointer clusterNames;
+ public Pointer servers;
+ }
+
+
+
+
+ public static class lsSharedResourceInstance extends Structure {
+ public static class ByReference extends lsSharedResourceInstance implements Structure.ByReference {}
+ public static class ByValue extends lsSharedResourceInstance implements Structure.ByValue {}
+ public lsSharedResourceInstance() {}
+ public lsSharedResourceInstance(Pointer p) { super(p); read(); }
+
+ public String value;
+ public int nHosts;
+ public Pointer hostList;
+
+ }
+
+
+
+
+ public static class lsSharedResourceInfo extends Structure {
+ public static class ByReference extends lsSharedResourceInfo implements Structure.ByReference {}
+ public static class ByValue extends lsSharedResourceInfo implements Structure.ByValue {}
+ public lsSharedResourceInfo() {}
+ public lsSharedResourceInfo(Pointer p) { super(p); read(); }
+
+ public String resourceName;
+ public int nInstances;
+ public Pointer /* lsSharedResourceInstance.ByReference */ instances;
+ }
+
+
+
+ public static class clusterConf extends Structure {
+ public static class ByReference extends clusterConf implements Structure.ByReference {}
+ public static class ByValue extends clusterConf implements Structure.ByValue {}
+ public clusterConf() {}
+ public clusterConf(Pointer p) { super(p); read(); }
+
+ public clusterInfo.ByReference clinfo;
+ public int numHosts;
+ public Pointer /* hostInfo.ByReference */ hosts;
+ public int defaultFeatures;
+ public int numShareRes;
+ public Pointer /* lsSharedResourceInfo.ByReference */ shareRes;
+ }
+
+
+
+
+ public static class pidInfo extends Structure {
+ public static class ByReference extends pidInfo implements Structure.ByReference {}
+ public static class ByValue extends pidInfo implements Structure.ByValue {}
+ public pidInfo() {}
+ public pidInfo(Pointer p) { super(p); read(); }
+
+ public int pid;
+ public int ppid;
+ public int pgid;
+ public int jobid;
+ }
+
+
+
+
+ public static class jRusage extends Structure {
+ public static class ByReference extends jRusage implements Structure.ByReference {}
+ public static class ByValue extends jRusage implements Structure.ByValue {}
+ public jRusage() {}
+ public jRusage(Pointer p) { super(p); read(); }
+
+ public int mem;
+ public int swap;
+ public int utime;
+ public int stime;
+ public int npids;
+ public Pointer /* pidInfo.ByReference */ pidInfo;
+
+ public int npgids;
+ public IntByReference pgid;
+ public int nthreads;
+ }
+
+
+
+
+ public static final int NUM_SUBS = 2;
+ public static final int LEN_SUBS = 64;
+ public static final int NUM_CLASS_TYPE = 3;
+
+ public static class licUsage extends Structure {
+ public static class ByReference extends licUsage implements Structure.ByReference {}
+ public static class ByValue extends licUsage implements Structure.ByValue {}
+ public licUsage() {}
+ public licUsage(Pointer p) { super(p); read(); }
+
+ public int licDisplayMask;
+ public int usingDemoLicense;
+ public float[] total = new float[hostInfo.LSF_NUM_LIC_TYPE];
+ public float[] inUse = new float[hostInfo.LSF_NUM_LIC_TYPE];
+ }
+
+
+
+ public static class hostClassInfo extends Structure {
+ public static class ByReference extends hostClassInfo implements Structure.ByReference {}
+ public static class ByValue extends hostClassInfo implements Structure.ByValue {}
+ public hostClassInfo() {}
+ public hostClassInfo(Pointer p) { super(p); read(); }
+
+ public int numHosts;
+ public int numCpus;
+ public int numCores;
+ }
+
+
+
+ public static class lsfLicUsage extends Structure {
+ public static class ByReference extends lsfLicUsage implements Structure.ByReference {}
+ public static class ByValue extends lsfLicUsage implements Structure.ByValue {}
+ public lsfLicUsage() {}
+ public lsfLicUsage(Pointer p) { super(p); read(); }
+
+ public licUsage licUsage;
+ public hostClassInfo[] hostInfo = new hostClassInfo[NUM_CLASS_TYPE];
+ // The current version of JNA's Structure.getNativeAlignment passes a "null" to
+ // Native.getNativeSize() when accessing the contents of a 2D array.
+ // Although the method is marked as protected, there are also multiple "TO DO"
+ // comments so when we upgrade don't want to have specialized code floating around.
+ public byte[] substitution = new byte[NUM_SUBS * LEN_SUBS];
+ public byte[] cluster = new byte[MAXFILENAMELEN];
+ }
+
+
+ public static class param_entry extends Structure {
+ public static class ByReference extends param_entry implements Structure.ByReference {}
+ public static class ByValue extends param_entry implements Structure.ByValue {}
+ public param_entry() {}
+ public param_entry(Pointer p) { super(p); read(); }
+
+ public static int HAS_PARAM_VALUE = 0x001;
+ public static final int HAS_PARAM_DEFAULT = 0x002;
+
+ public int flags;
+ public String key;
+ public String value;
+ public String default_value;
+ }
+
+
+
+ public static class params_key_value_pair extends Structure {
+ public static class ByReference extends params_key_value_pair implements Structure.ByReference {}
+ public static class ByValue extends params_key_value_pair implements Structure.ByValue {}
+ public params_key_value_pair() {}
+ public params_key_value_pair(Pointer p) { super(p); read(); }
+
+ public int num_params;
+ public String daemon_time;
+ public Pointer /* param_entry.ByReference */ param;
+ }
+
+
+
+
+ public static final int LSE_NO_ERR = 0;
+ public static final int LSE_BAD_XDR = 1;
+ public static final int LSE_MSG_SYS = 2;
+ public static final int LSE_BAD_ARGS = 3;
+ public static final int LSE_MASTR_UNKNW = 4;
+ public static final int LSE_LIM_DOWN = 5;
+ public static final int LSE_PROTOC_LIM = 6;
+ public static final int LSE_SOCK_SYS = 7;
+ public static final int LSE_ACCEPT_SYS = 8;
+ public static final int LSE_BAD_TASKF = 9;
+ public static final int LSE_NO_HOST = 10;
+ public static final int LSE_NO_ELHOST = 11;
+ public static final int LSE_TIME_OUT = 12;
+ public static final int LSE_NIOS_DOWN = 13;
+ public static final int LSE_LIM_DENIED = 14;
+ public static final int LSE_LIM_IGNORE = 15;
+ public static final int LSE_LIM_BADHOST = 16;
+ public static final int LSE_LIM_ALOCKED = 17;
+ public static final int LSE_LIM_NLOCKED = 18;
+ public static final int LSE_LIM_BADMOD = 19;
+ public static final int LSE_SIG_SYS = 20;
+ public static final int LSE_BAD_EXP = 21;
+ public static final int LSE_NORCHILD = 22;
+ public static final int LSE_MALLOC = 23;
+ public static final int LSE_LSFCONF = 24;
+ public static final int LSE_BAD_ENV = 25;
+ public static final int LSE_LIM_NREG = 26;
+ public static final int LSE_RES_NREG = 27;
+ public static final int LSE_RES_NOMORECONN = 28;
+ public static final int LSE_BADUSER = 29;
+ public static final int LSE_RES_ROOTSECURE = 30;
+ public static final int LSE_RES_DENIED = 31;
+ public static final int LSE_BAD_OPCODE = 32;
+ public static final int LSE_PROTOC_RES = 33;
+ public static final int LSE_RES_CALLBACK = 34;
+ public static final int LSE_RES_NOMEM = 35;
+ public static final int LSE_RES_FATAL = 36;
+ public static final int LSE_RES_PTY = 37;
+ public static final int LSE_RES_SOCK = 38;
+ public static final int LSE_RES_FORK = 39;
+ public static final int LSE_NOMORE_SOCK = 40;
+ public static final int LSE_WDIR = 41;
+ public static final int LSE_LOSTCON = 42;
+ public static final int LSE_RES_INVCHILD = 43;
+ public static final int LSE_RES_KILL = 44;
+ public static final int LSE_PTYMODE = 45;
+ public static final int LSE_BAD_HOST = 46;
+ public static final int LSE_PROTOC_NIOS = 47;
+ public static final int LSE_WAIT_SYS = 48;
+ public static final int LSE_SETPARAM = 49;
+ public static final int LSE_RPIDLISTLEN = 50;
+ public static final int LSE_BAD_CLUSTER = 51;
+ public static final int LSE_RES_VERSION = 52;
+ public static final int LSE_EXECV_SYS = 53;
+ public static final int LSE_RES_DIR = 54;
+ public static final int LSE_RES_DIRW = 55;
+ public static final int LSE_BAD_SERVID = 56;
+ public static final int LSE_NLSF_HOST = 57;
+ public static final int LSE_UNKWN_RESNAME = 58;
+ public static final int LSE_UNKWN_RESVALUE = 59;
+ public static final int LSE_TASKEXIST = 60;
+ public static final int LSE_BAD_TID = 61;
+ public static final int LSE_TOOMANYTASK = 62;
+ public static final int LSE_LIMIT_SYS = 63;
+ public static final int LSE_BAD_NAMELIST = 64;
+ public static final int LSE_NO_LICENSE = 65;
+ public static final int LSE_LIM_NOMEM = 66;
+ public static final int LSE_NIO_INIT = 67;
+ public static final int LSE_CONF_SYNTAX = 68;
+ public static final int LSE_FILE_SYS = 69;
+ public static final int LSE_CONN_SYS = 70;
+ public static final int LSE_SELECT_SYS = 71;
+ public static final int LSE_EOF = 72;
+ public static final int LSE_ACCT_FORMAT = 73;
+ public static final int LSE_BAD_TIME = 74;
+ public static final int LSE_FORK = 75;
+ public static final int LSE_PIPE = 76;
+ public static final int LSE_ESUB = 77;
+ public static final int LSE_DCE_EXEC = 78;
+ public static final int LSE_EAUTH = 79;
+ public static final int LSE_NO_FILE = 80;
+ public static final int LSE_NO_CHAN = 81;
+ public static final int LSE_BAD_CHAN = 82;
+ public static final int LSE_INTERNAL = 83;
+ public static final int LSE_PROTOCOL = 84;
+ public static final int LSE_THRD_SYS = 85;
+ public static final int LSE_MISC_SYS = 86;
+ public static final int LSE_LOGON_FAIL = 87;
+ public static final int LSE_RES_RUSAGE = 88;
+ public static final int LSE_NO_RESOURCE = 89;
+ public static final int LSE_BAD_RESOURCE = 90;
+ public static final int LSE_RES_PARENT = 91;
+ public static final int LSE_NO_PASSWD = 92;
+ public static final int LSE_SUDOERS_CONF = 93;
+ public static final int LSE_SUDOERS_ROOT = 94;
+ public static final int LSE_I18N_SETLC = 95;
+ public static final int LSE_I18N_CATOPEN = 96;
+ public static final int LSE_I18N_NOMEM = 97;
+ public static final int LSE_NO_MEM = 98;
+ public static final int LSE_REGISTRY_SYS = 99;
+ public static final int LSE_FILE_CLOSE = 100;
+ public static final int LSE_LIMCONF_NOTREADY = 101;
+ public static final int LSE_MASTER_LIM_DOWN = 102;
+ public static final int LSE_MLS_INVALID = 103;
+ public static final int LSE_MLS_CLEARANCE = 104;
+ public static final int LSE_MLS_RHOST = 105;
+ public static final int LSE_MLS_DOMINATE = 106;
+ public static final int LSE_NO_CAL = 107;
+ public static final int LSE_NO_NETWORK = 108;
+ public static final int LSE_GETCONF_FAILED = 109;
+ public static final int LSE_TSSINIT = 110;
+ public static final int LSE_DYNM_DENIED = 111;
+ public static final int LSE_LIC_OVERUSE = 112;
+ public static final int LSE_EGOCONF = 113;
+ public static final int LSE_BAD_EGO_ENV = 114;
+ public static final int LSE_EGO_CONF_SYNTAX = 115;
+ public static final int LSE_EGO_GETCONF_FAILED = 116;
+ public static final int LSE_NS_LOOKUP = 117;
+ public static final int LSE_BAD_PASSWD = 118;
+
+ public static final int LSE_UNKWN_USER = 119;
+ public static final int LSE_NOT_WINHOST = 120;
+ public static final int LSE_NOT_MASTERCAND = 121;
+ public static final int LSE_HOST_UNAUTH = 122;
+ public static final int LSE_UNRESOLVALBE_HOST = 123;
+ public static final int LSE_RESOURCE_NOT_CONSUMABLE = 124;
+ public static final int LSE_SHUTDOWN = 125;
+ public static final int LSE_BAD_SYNTAX = 126;
+ public static final int LSE_NERR = 127;
+
+
+ public static boolean LSE_ISBAD_RESREQ(int s) {
+ return (((s) == LSE_BAD_EXP) || ((s) == LSE_UNKWN_RESNAME) || ((s) == LSE_UNKWN_RESVALUE));
+ }
+
+ public static boolean LSE_SYSCALL(int s) {
+ return (((s) == LSE_SELECT_SYS) || ((s) == LSE_CONN_SYS) || ((s) == LSE_FILE_SYS) || ((s) == LSE_MSG_SYS) || ((s) == LSE_SOCK_SYS) || ((s) == LSE_ACCEPT_SYS) || ((s) == LSE_SIG_SYS) || ((s) == LSE_WAIT_SYS) || ((s) == LSE_EXECV_SYS) || ((s) == LSE_LIMIT_SYS) || ((s) == LSE_PIPE) || ((s) == LSE_ESUB) || ((s) == LSE_REGISTRY_SYS) || ((s) == LSE_MISC_SYS));
+ }
+
+
+ /*
+ public static void TIMEVAL (int level, int func, int val) {
+ if (timinglevel > level) {
+ timeval before, after;
+ timezone tz;
+ gettimeofday(&before, &tz);
+ func;
+ gettimeofday(&after, &tz);
+ val = (int)((after.tv_sec - before.tv_sec)*1000 + (after.tv_usec-before.tv_usec)/1000);
+ } else {
+ func;
+ val = 0;
+ }
+ }
+ */
+
+ public static class ls_timeval extends Structure {
+ public static class ByReference extends ls_timeval implements Structure.ByReference {}
+ public static class ByValue extends ls_timeval implements Structure.ByValue {}
+ public ls_timeval() {}
+ public ls_timeval(Pointer p) { super(p); read(); }
+
+ public float rtime;
+ public float utime;
+ public float stime;
+ }
+
+
+
+ /*
+ public static void LS_TIMEVAL_ZERO(ls_timeval tv) { tv.rtime = 0.0; tv.utime = 0.0; tv.stime = 0.0; }
+
+ public static int LS_TIMEVAL_INC (ls_timeval tv, int newtv) { tv.rtime += newtv.rtime; tv.utime += newtv.utime; tv.stime += newtv.stime; }
+
+ public static void LOG_TIME_MSG(int level, String name, ls_timeval tv, int count, String msg) { if (timinglevel > level) { ls_syslog(LOG_INFO, "L%d %s rtime %.2f ms, utime %.2f ms, stime %.2f ms, count %d %s", level, name, tv.rtime, tv.utime, tv.stime, count, msg); } }; }
+
+ public static void TIMEIT (int level, String func, String name) {
+ if (timinglevel > level && clockticks > 0) {
+ timeval _before, _after;
+ timezone _tz;
+ tms _buf, _buf2;
+ gettimeofday(&_before, &_tz);
+ times(&_buf);
+ func;
+ gettimeofday(&_after, &_tz);
+ times(&_buf2);
+ ls_syslog(LOG_INFO,"L%d %s rtime %.2f ms, utime %.2f ms, stime %.2f ms", level, name, (_after.tv_sec - _before.tv_sec)*1000.0 + (_after.tv_usec - _before.tv_usec)/1000.0, 1000.0*((_buf2.tms_utime - _buf.tms_utime)/clockticks), 1000.0*((_buf2.tms_stime - _buf.tms_stime)/clockticks));
+ } else {
+ func;
+ }
+ }
+
+ public static int TIMEVAL2 (int level, String func, ls_timeval tv) {
+ if (timinglevel > level && clockticks > 0) {
+ timeval _before, _after;
+ timezone _tz;
+ tms _buf, _buf2;
+ gettimeofday(&_before, &_tz);
+ times(&_buf);
+ func;
+ gettimeofday(&_after, &_tz);
+ times(&_buf2);
+ tv.rtime = (_after.tv_sec - _before.tv_sec)*1000.0 + (_after.tv_usec - _before.tv_usec)/1000.0;
+ tv.utime = 1000.0*((_buf2.tms_utime - _buf.tms_utime)/clockticks);
+ tv.stime = 1000.0*((_buf2.tms_stime - _buf.tms_stime)/clockticks);
+ } else {
+ func;
+ tv.rtime = 0.0;
+ tv.utime = 0.0;
+ tv.stime = 0.0;
+ }
+ }
+
+ public static int TIMEIT_START_BLOCK (int level) {
+ tms _buf, _buf2;
+ timeval _before, _after;
+ timezone _tz;
+ if (timinglevel > level) {
+ gettimeofday(&_before, &_tz);
+ times(&_buf);
+ }
+ }
+
+ public static int TIMEIT_END_BLOCK (int level, String name) {
+ if (timinglevel > level) {
+ float rt, ut, st;
+ gettimeofday(&_after, &_tz);
+ times(&_buf2);
+ rt = (_after.tv_sec - _before.tv_sec)*1000.0 + (_after.tv_usec - _before.tv_usec)/1000.0;
+ ut = 1000.0*((_buf2.tms_utime - _buf.tms_utime)/clockticks);
+ st = 1000.0*((_buf2.tms_stime - _buf.tms_stime)/clockticks);
+ ls_syslog(LOG_INFO,"L%d %s rtime %.2f ms, utime %.2f ms, stime %.2f ms", level, name, rt, ut, st);
+ }
+ }
+ */
+
+ public static final int LC_SCHED = 0x00000001;
+ public static final int LC_EXEC = 0x00000002;
+ public static final int LC_TRACE = 0x00000004;
+ public static final int LC_COMM = 0x00000008;
+ public static final int LC_XDR = 0x00000010;
+ public static final int LC_CHKPNT = 0x00000020;
+ public static final int LC_LICENCE = 0x00000040;
+ public static final int LC_LICENSE = 0x00000040;
+ public static final int LC_FILE = 0x00000080;
+ public static final int LC_AFS = 0x00000100;
+ public static final int LC_AUTH = 0x00000200;
+ public static final int LC_HANG = 0x00000400;
+ public static final int LC_MULTI = 0x00000800;
+ public static final int LC_SIGNAL = 0x00001000;
+ public static final int LC_DCE = 0x00002000;
+ public static final int LC_PIM = 0x00004000;
+ public static final int LC_MEMORY = 0x00004000;
+ public static final int LC_SYS = 0x00008000;
+ public static final int LC_JLIMIT = 0x00010000;
+ public static final int LC_FAIR = 0x00020000;
+ public static final int LC_PREEMPT = 0x00040000;
+ public static final int LC_PEND = 0x00080000;
+ public static final int LC_EEVENTD = 0x00100000;
+ public static final int LC_LOADINDX = 0x00200000;
+ public static final int LC_RESOURCE = 0x00200000;
+
+ public static final int LC_JGRP = 0x00400000;
+ public static final int LC_JARRAY = 0x00800000;
+ public static final int LC_MPI = 0x01000000;
+ public static final int LC_ELIM = 0x02000000;
+ public static final int LC_M_LOG = 0x04000000;
+ public static final int LC_PERFM = 0x08000000;
+ public static final int LC_DLOG = 0x10000000;
+ public static final int LC_HPC = 0x20000000;
+ public static final int LC_LICSCHED = 0x40000000;
+
+ public static final int LC_XDRVERSION = 0x80000000;
+ public static final int LC_FLEX = 0x80000000;
+
+ public static final int LC_ADVRSV = LC_DLOG;
+ public static final int LC_RESREQ = LC_M_LOG;
+
+
+ public static final int LOG_DEBUG1 = LOG_DEBUG + 1;
+ public static final int LOG_DEBUG2 = LOG_DEBUG + 2;
+ public static final int LOG_DEBUG3 = LOG_DEBUG + 3;
+
+
+ public static final int LSF_EVENT_LIM_DOWN = 1;
+ public static final int LSF_EVENT_RES_DOWN = 2;
+ public static final int LSF_EVENT_SBD_DOWN = 3;
+ public static final int LSF_EVENT_HOST_UNLIC = 4;
+ public static final int LSF_EVENT_MASTER_ELECT = 5;
+ public static final int LSF_EVENT_MASTER_RESIGN = 6;
+ public static final int LSF_EVENT_MBD_UP = 7;
+ public static final int LSF_EVENT_MBD_DOWN = 8;
+ public static final int LSF_EVENT_MBD_RECONFIG = 9;
+ public static final int LSF_EVENT_WORKDIR_FULL = 10;
+ public static final int LSF_EVENT_HOST_OPENED = 11;
+ public static final int LSF_EVENT_HOST_CLOSED = 12;
+ public static final int LSF_EVENT_QUEUE_OPENED = 13;
+ public static final int LSF_EVENT_QUEUE_CLOSED = 14;
+ public static final int LSF_EVENT_SCH_DOWN = 15;
+ public static final int LSF_EVENT_LIC_OVERUSE = 16;
+
+ public static final int LSF_NIOS_REQUEUE = 127;
+
+
+ /*
+ public int lserrno;
+ public int masterLimDown;
+ public int ls_nerr;
+ public String[] ls_errmsg;
+ public int logclass;
+ public int timinglevel;
+ public int clockticks;
+
+
+ public int lsf_lim_version;
+ */
+
+
+ public static native int ls_readconfenv(config_param config_param1, String string);
+
+
+ public static native Pointer ls_placereq(String resreq, IntByReference numhosts, int options, String fromhost);
+
+
+ public static native Pointer ls_placeofhosts(String resreq, IntByReference numhosts, int options, String fromhost, Pointer hostlist, int listsize);
+
+ // NOTE: Not in liblsf
+ //public static native Pointer ls_placeoftype(String resreq, IntByReference numhosts, int options, String fromhost, String hosttype);
+
+
+ public static native hostLoad.ByReference ls_load(String resreq, IntByReference numhosts, int options, String fromhost);
+
+
+ public static native hostLoad.ByReference ls_loadofhosts(String resreq, IntByReference numhosts, int options, String fromhost, Pointer hostlist, int listsize);
+
+ // NOTE: Not in liblsf
+ //public static native hostLoad.ByReference ls_loadoftype(String resreq, IntByReference numhosts, int options, String fromhost, String hosttype);
+
+
+ public static native hostLoad.ByReference ls_loadinfo(String resreq, IntByReference numhosts, int options, String fromhost, Pointer hostlist, int listsize, Pointer indxnamelist);
+
+
+ public static native int ls_loadadj(String resreq, placeInfo hostlist, int listsize);
+
+
+ public static native int ls_eligible(String task, String resreqstr, byte mode);
+
+
+ public static native String ls_resreq(String task);
+
+
+ public static native int ls_insertrtask(String task);
+
+
+ public static native int ls_insertltask(String task);
+
+
+ public static native int ls_deletertask(String task);
+
+
+ public static native int ls_deleteltask(String task);
+
+
+ public static native int ls_listrtask(Pointer taskList, int sortflag);
+
+
+ public static native int ls_listltask(Pointer taskList, int sortflag);
+
+
+ public static native Pointer ls_findmyconnections();
+
+
+ public static native int ls_isconnected(String hostName);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_lostconnection();
+
+
+ public static native String ls_getclustername();
+
+
+ public static native clusterInfo.ByReference ls_clusterinfo(String string1, IntByReference int1, Pointer stringArray1, int int2, int int3);
+
+
+ public static native lsSharedResourceInfo.ByReference ls_sharedresourceinfo(Pointer stringArray1, IntByReference int1, String string1, int int2);
+
+
+ public static native String ls_getmastername();
+
+
+ public static native String ls_getmyhostname();
+
+
+ public static native String ls_getmyhostname2();
+
+
+ public static native hostInfo.ByReference ls_gethostinfo(String string1, IntByReference int1, Pointer stringArray1, int int2, int int3);
+
+ public static native String ls_getISVmode();
+
+ public static native int ls_isshutdown();
+
+ public static native int ls_isPartialLicensingEnabled();
+
+ /* NOTE: ls_getLicenseUsage() is not supported by LSF v8.x
+ * Wei Xing, ICR
+ */
+// public static native lsfLicUsage.ByReference ls_getLicenseUsage();
+
+ public static native lsInfo.ByReference ls_info();
+
+ public static native Pointer ls_indexnames(lsInfo lsInfo1);
+
+ public static native int ls_isclustername(String string);
+
+
+ public static native String ls_gethosttype(String hostname);
+
+
+ public static native FloatByReference ls_getmodelfactor(String modelname);
+
+
+ public static native FloatByReference ls_gethostfactor(String hostname);
+
+
+ public static native String ls_gethostmodel(String hostname);
+
+ // NOTE: Not in liblsf
+ //public static native IntByReference ls_gethostrespriority(String hostname);
+
+
+ public static native int ls_lockhost(NativeLong duration);
+
+
+ public static native int ls_unlockhost();
+
+
+ public static native int ls_limcontrol(String hostname, int opCode);
+
+ public static native void ls_remtty(int ind, int enableIntSus);
+
+ public static native void ls_loctty(int ind);
+
+
+ public static native String ls_sysmsg();
+
+
+ public static native void ls_perror(String usrMsg);
+
+
+ public static native lsConf.ByReference ls_getconf(String string);
+
+ public static native void ls_freeconf(lsConf lsConf1);
+
+ public static native sharedConf.ByReference ls_readshared(String string1);
+
+ public static native clusterConf.ByReference ls_readcluster(String string1, lsInfo lsInfo1);
+
+ public static native clusterConf.ByReference ls_readcluster_ex(String string1, lsInfo lsInfo1, int int1);
+
+
+ public static native int _ls_initdebug(String appName);
+
+ public static native void ls_syslog(int level, String fmt, Pointer args);
+
+ public static native void ls_errlog(Pointer fp, String fmt, Pointer args);
+
+ // NOTE: va_list is too compiler specific. Skipping this function.
+ //public static native void ls_verrlog (Pointer fp, String fmt, va_list ap);
+
+ public static native int ls_fdbusy(int fd);
+
+
+ public static native String ls_getmnthost(String fn);
+
+ public static native int ls_servavail(int int1, int int2);
+
+ public static native int ls_getpriority(IntByReference priority);
+
+ public static native int ls_setpriority(int newPriority);
+
+ public static native void ls_ruunix2lsf(rusage rusage, lsfRusage lsfRusage);
+
+ public static native void ls_rulsf2unix(lsfRusage lsfRusage, rusage rusage);
+
+ public static native void cleanLsfRusage(lsfRusage lsfRusage1);
+
+ public static native void cleanRusage(rusage rusage1);
+
+
+ // NOTE: Not in liblsf
+ //public static native int getBEtime(String string1, byte byte1, NativeLongByReference long1);
+
+
+ public static native int ls_postevent(int int1, String string1, Pointer stringArray1, int int2);
+
+ public static native int ls_postmultievent(int int1, String string1, Pointer stringArray1, int int2, int int3);
+
+ public static class extResInfo extends Structure {
+ public static class ByReference extends extResInfo implements Structure.ByReference {}
+ public static class ByValue extends extResInfo implements Structure.ByValue {}
+ public extResInfo() {}
+ public extResInfo(Pointer p) { super(p); read(); }
+
+ public String name;
+ public String type;
+ public String interval;
+ public String increasing;
+ public String des;
+ }
+
+
+
+
+ // NOTE: Not in liblsf
+ //public static native int lim_vcl_get_eres_version();
+
+ // NOTE: Not in liblsf
+ //public static native extResInfo.ByReference lim_vcl_get_eres_def(String string1);
+
+ // NOTE: Not in liblsf
+ //public static native String lim_vcl_get_eres_loc(String string1);
+
+ // NOTE: Not in liblsf
+ //public static native String lim_vcl_get_eres_val(String string1);
+
+
+ public static int isspace(byte c) {
+ return ((c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0b || c == 0x0c || c == 0x0d) ? 8 : 0);
+ }
+
+ public static final int LSF_VERSION = LSF_XDR_VERSION7_0_EP6;
+ public static final String LSF_CURRENT_VERSION = "7.06";
+
+
+ public static final String LSF_PRODUCT_COPYRIGHT_STR = "Copyright 1992-2009 Platform Computing Corp.";
+
+
+ public static final String LSF_NAME_STR = "Platform LSF";
+ public static final String LSF_IDENTIFIER_STR = "";
+ public static final String LSF_PRODUCT_NAME_STR = LSF_NAME_STR + LSF_IDENTIFIER_STR;
+
+
+ public static final String LSF_PRODUCT_COMMENT_STR = "";
+
+
+ public static final String LSF_PRODUCT_BUILD_STR = "";
+
+
+ public static final String LSF_PRODUCT_BUILD_DATE_STR = "";
+
+
+ public static final int LSF_PRODUCT_MAJOR_VERSION = 7;
+ public static final int LSF_PRODUCT_MINOR_VERSION = 0;
+ public static final int LSF_PRODUCT_MAINTAIN_VERSION = 6;
+
+ public static final String LSF_PRODUCT_MAJOR_VERSION_STR = "7";
+ public static final String LSF_PRODUCT_MINOR_VERSION_STR = "0";
+ public static final String LSF_PRODUCT_MAINTAIN_VERSION_STR = "6";
+
+ public static final String LSF_PRODUCT_VERSION_STR = LSF_PRODUCT_MAJOR_VERSION_STR + "." + LSF_PRODUCT_MINOR_VERSION_STR + "." + LSF_PRODUCT_MAINTAIN_VERSION_STR;
+ public static final String LSF_FILE_VERSION_STR = LSF_PRODUCT_MAJOR_VERSION_STR + "." + LSF_PRODUCT_MINOR_VERSION_STR + "." + LSF_PRODUCT_MAINTAIN_VERSION_STR;
+
+
+ public static final String _VERSION_STR_LSID_ = "Platform LSF HPC 7";
+ public static final String _LSID_VERSION_ = (_VERSION_STR_LSID_ + " Update " + _MINOR_STR_ + ", " + _DATE_STR_ + "\nCopyright 1992-2009 Platform Computing Corporation\n");
+
+
+ /* Removing since the ls_nio functions which use fd_set, etc. are not in liblsf.
+
+ public static final int NIO_STDIN_ON = 0x01;
+ public static final int NIO_STDIN_OFF = 0x02;
+ public static final int NIO_TAGSTDOUT_ON = 0x03;
+ public static final int NIO_TAGSTDOUT_OFF = 0x04;
+
+ public static final int NIO_TASK_STDINON = 0x01;
+ public static final int NIO_TASK_STDINOFF = 0x02;
+ public static final int NIO_TASK_ALL = 0x03;
+ public static final int NIO_TASK_CONNECTED = 0x04;
+
+ public static interface nioType {
+ public static final int NIO_STATUS = 0;
+ public static final int NIO_STDOUT = 1;
+ public static final int NIO_EOF = 2;
+ public static final int NIO_IOERR = 3;
+ public static final int NIO_REQUEUE = 4;
+ public static final int NIO_STDERR = 5;
+ }
+
+
+
+ public static class nioEvent extends Structure {
+ public static class ByReference extends nioEvent implements Structure.ByReference {}
+ public static class ByValue extends nioEvent implements Structure.ByValue {}
+ public nioEvent() {}
+ public nioEvent(Pointer p) { super(p); read(); }
+
+ public int tid;
+ public *//*nioType*//* int type;
+ public int status;
+ }
+
+
+
+ public static class nioInfo extends Structure {
+ public static class ByReference extends nioInfo implements Structure.ByReference {}
+ public static class ByValue extends nioInfo implements Structure.ByValue {}
+ public nioInfo() {}
+ public nioInfo(Pointer p) { super(p); read(); }
+
+ public int num;
+ public Pointer / * nioEvent.ByReference * / ioTask;
+ }
+
+
+ public static final int FD_SETSIZE = 64;
+
+ public static class fd_set extends Structure {
+ public static class ByReference extends fd_set implements Structure.ByReference {}
+ public static class ByValue extends fd_set implements Structure.ByValue {}
+ public fd_set() {}
+ public fd_set(Pointer p) { super(p); read(); }
+
+ public int count;
+ public int[] fd = new int[FD_SETSIZE];
+ }
+ */
+
+ public static native int ls_initdebug(String appName);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_nioinit(int sock);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_nioselect(int int1, fd_set fd_set1, fd_set fd_set2, fd_set fd_set3, Pointer nioInfoArray1, timeval timeval1);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_nioctl(int int1, int int2);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_nionewtask(int int1, int int2);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_nioremovetask(int int1);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_niowrite(String string1, int int1);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_nioclose();
+
+ // NOTE: Not in liblsf
+ //public static native int ls_nioread(int int1, String string1, int int2);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_niotasks(int int1, IntByReference int2, int int3);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_niostatus(int int1, IntByReference int2, rusage rusage1);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_niokill(int int1);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_niosetdebug(int int2);
+
+ // NOTE: Not in liblsf
+ //public static native int ls_niodump(int int1, int int2, int int3, String string1);
+
+
+ public int lsf_res_version;
+
+
+ public static native int ls_initrex(int a, int b);
+
+ public static int ls_init(int a, int b) {
+ return ls_initrex(a, b);
+ }
+
+
+ public static native int ls_donerex();
+
+ public static native int ls_niossync(int int1);
+
+
+ public static native int ls_setstdin(int on, IntByReference rpidlist, int len);
+
+
+ public static native int ls_getstdin(int on, IntByReference rpidlist, int maxlen);
+
+ public static native int ls_setstdout(int on, String format);
+
+
+ public static native int ls_stdinmode(int onoff);
+
+
+ public static native int ls_stoprex();
+
+
+ public static native int ls_chdir(String string1, String string2);
+
+
+ public static native int ls_connect(String string1);
+
+
+ public static native int ls_rkill(int int1, int int2);
+
+
+ public static native int ls_rsetenv(String host, Pointer env);
+
+ public static native int ls_rsetenv_async(String host, Pointer env);
+
+
+ public static native int ls_rescontrol(String host, int opcode, int options);
+
+
+ public static native lsfAcctRec.ByReference ls_getacctrec(Pointer pointer1, IntByReference int1);
+
+ public static native int ls_putacctrec(Pointer pointer1, lsfAcctRec lsfAcctRec1);
+
+
+ // NOTE: No idea what resLogRecord is.
+ //public static native resLogRecord.ByReference ls_readrexlog (Pointer );
+
+
+ public static native int ls_rexecv(String string1, Pointer string2, int int1);
+
+
+ public static native int ls_rexecve(String string1, Pointer stringArray1, int int1, Pointer stringArray2);
+
+ public static native int ls_rexecv2(String string1, Pointer stringArray1, int int1);
+
+ public static native int ls_startserver(String string1, Pointer stringArray1, int int1);
+
+
+ public static native int ls_rtask(String string1, Pointer stringArray1, int int1);
+
+
+ public static native int ls_rtaske(String string1, Pointer stringArray1, int int1, Pointer stringArray2);
+
+ public static native int ls_rtask2(String string1, Pointer stringArray1, int int1, Pointer stringArray2);
+
+
+ public static native int ls_rwait(IntByReference int1, int int2, rusage rusage1);
+
+
+ public static native int ls_rwaittid(int int1, IntByReference int2, int int3, rusage rusage1);
+
+
+ public static native int ls_conntaskport(int tid);
+
+
+ public static native int ls_ropen(String host, String fn, int flags, int mode);
+
+
+ public static native int ls_rclose(int rfd);
+
+
+ public static native int ls_rwrite(int rfd, String buf, int len);
+
+
+ public static native int ls_rread(int rfd, String buf, int len);
+
+
+ public static native NativeLong ls_rlseek(int rfd, NativeLong offset, int whence);
+
+
+ public static native int ls_runlink(String host, String fn);
+
+ public static native int ls_rfstat(int rfd, Pointer buf);
+
+ public static native int ls_rstat(String host, String fn, Pointer buf);
+
+
+ public static native String ls_rgetmnthost(String host, String fn);
+
+
+ public static native int ls_rfcontrol(int command, int arg);
+
+
+ public static native int ls_rfterminate(String host);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/AlignmentStateMachine.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/AlignmentStateMachine.java
new file mode 100644
index 0000000..f940386
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/AlignmentStateMachine.java
@@ -0,0 +1,370 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Invariant;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+/**
+ * Steps a single read along its alignment to the genome
+ *
+ * The logical model for generating extended events is as follows: the "record state"
+ * implements the traversal along the reference; thus stepForwardOnGenome() returns
+ * on every and only on actual reference bases. This can be a (mis)match or a deletion
+ * (in the latter case, we still return on every individual reference base the deletion spans).
+ *
+ * User: depristo
+ * Date: 1/5/13
+ * Time: 1:08 PM
+ */
+ at Invariant({
+ "nCigarElements >= 0",
+ "cigar != null",
+ "read != null",
+ "currentCigarElementOffset >= -1",
+ "currentCigarElementOffset <= nCigarElements"
+})
+public class AlignmentStateMachine {
+ /**
+ * Our read
+ */
+ private final GATKSAMRecord read;
+ private final Cigar cigar;
+ private final int nCigarElements;
+ private int currentCigarElementOffset = -1;
+
+ /**
+ * how far are we offset from the start of the read bases?
+ */
+ private int readOffset;
+
+ /**
+ * how far are we offset from the alignment start on the genome?
+ */
+ private int genomeOffset;
+
+ /**
+ * Our cigar element
+ */
+ private CigarElement currentElement;
+
+ /**
+ * how far are we into our cigarElement?
+ */
+ private int offsetIntoCurrentCigarElement;
+
+ @Requires({"read != null", "read.getAlignmentStart() != -1", "read.getCigar() != null"})
+ public AlignmentStateMachine(final GATKSAMRecord read) {
+ this.read = read;
+ this.cigar = read.getCigar();
+ this.nCigarElements = cigar.numCigarElements();
+ initializeAsLeftEdge();
+ }
+
+ /**
+ * Initialize the state variables to put this machine one bp before the
+ * start of the alignment, so that a call to stepForwardOnGenome() will advance
+ * us to the first proper location
+ */
+ @Ensures("isLeftEdge()")
+ private void initializeAsLeftEdge() {
+ readOffset = offsetIntoCurrentCigarElement = genomeOffset = -1;
+ currentElement = null;
+ }
+
+ /**
+ * Get the read we are aligning to the genome
+ * @return a non-null GATKSAMRecord
+ */
+ @Ensures("result != null")
+ public GATKSAMRecord getRead() {
+ return read;
+ }
+
+ /**
+ * Get the reference index of the underlying read
+ *
+ * @return the reference index of the read
+ */
+ @Ensures("result == getRead().getReferenceIndex()")
+ public int getReferenceIndex() {
+ return getRead().getReferenceIndex();
+ }
+
+ /**
+ * Is this the left edge state? I.e., one that is before or after the current read?
+ * @return true if this state is an edge state, false otherwise
+ */
+ public boolean isLeftEdge() {
+ return readOffset == -1;
+ }
+
+ /**
+ * Are we on the right edge? I.e., is the current state off the right of the alignment?
+ * @return true if off the right edge, false if otherwise
+ */
+ public boolean isRightEdge() {
+ return readOffset == read.getReadLength();
+ }
+
+ /**
+ * What is our current offset in the read's bases that aligns us with the reference genome?
+ *
+ * @return the current read offset position. If an edge will be == -1
+ */
+ @Ensures("result >= -1")
+ public int getReadOffset() {
+ return readOffset;
+ }
+
+ /**
+ * What is the current offset w.r.t. the alignment state that aligns us to the readOffset?
+ *
+ * @return the current offset from the alignment start on the genome. If this state is
+ * at the left edge the result will be -1;
+ */
+ @Ensures("result >= -1")
+ public int getGenomeOffset() {
+ return genomeOffset;
+ }
+
+ /**
+ * Get the position (1-based as standard) of the current alignment on the genome w.r.t. the read's alignment start
+ * @return the position on the genome of the current state in absolute coordinates
+ */
+ @Ensures("result > 0")
+ public int getGenomePosition() {
+ return read.getAlignmentStart() + getGenomeOffset();
+ }
+
+ /**
+ * Gets #getGenomePosition but as a 1 bp GenomeLoc
+ * @param genomeLocParser the parser to use to create the genome loc
+ * @return a non-null genome location with start position of getGenomePosition
+ */
+ @Requires("genomeLocParser != null")
+ @Ensures("result != null")
+ public GenomeLoc getLocation(final GenomeLocParser genomeLocParser) {
+ // TODO -- may return wonky results if on an edge (could be 0 or could be beyond genome location)
+ return genomeLocParser.createGenomeLoc(read.getReferenceName(), getGenomePosition());
+ }
+
+ /**
+ * Get the cigar element we're currently aligning with.
+ *
+ * For example, if the cigar string is 2M2D2M and we're in the second step of the
+ * first 2M, then this function returns the element 2M. After calling stepForwardOnGenome
+ * this function would return 2D.
+ *
+ * @return the cigar element, or null if we're the left edge
+ */
+ @Ensures("result != null || isLeftEdge() || isRightEdge()")
+ public CigarElement getCurrentCigarElement() {
+ return currentElement;
+ }
+
+ /**
+ * Get the offset of the current cigar element among all cigar elements in the read
+ *
+ * Suppose our read's cigar is 1M2D3M, and we're at the first 1M. This would
+ * return 0. Stepping forward puts us in the 2D, so our offset is 1. Another
+ * step forward would result in a 1 again (we're in the second position of the 2D).
+ * Finally, one more step forward brings us to 2 (for the 3M element)
+ *
+ * @return the offset of the current cigar element in the reads's cigar. Will return -1 for
+ * when the state is on the left edge, and be == the number of cigar elements in the
+ * read when we're past the last position on the genome
+ */
+ @Ensures({"result >= -1", "result <= nCigarElements"})
+ public int getCurrentCigarElementOffset() {
+ return currentCigarElementOffset;
+ }
+
+ /**
+ * Get the offset of the current state into the current cigar element
+ *
+ * That is, suppose we have a read with cigar 2M3D4M, and we're right at
+ * the second M position. offsetIntoCurrentCigarElement would be 1, as
+ * it's two elements into the 2M cigar. Now stepping forward we'd be
+ * in cigar element 3D, and our offsetIntoCurrentCigarElement would be 0.
+ *
+ * @return the offset (from 0) of the current state in the current cigar element.
+ * Will be 0 on the right edge, and -1 on the left.
+ */
+ @Ensures({"result >= 0 || (result == -1 && isLeftEdge())", "!isRightEdge() || result == 0"})
+ public int getOffsetIntoCurrentCigarElement() {
+ return offsetIntoCurrentCigarElement;
+ }
+
+ /**
+ * Convenience accessor of the CigarOperator of the current cigar element
+ *
+ * Robust to the case where we're on the edge, and currentElement is null, in which
+ * case this function returns null as well
+ *
+ * @return null if this is an edge state
+ */
+ @Ensures("result != null || isLeftEdge() || isRightEdge()")
+ public CigarOperator getCigarOperator() {
+ return currentElement == null ? null : currentElement.getOperator();
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s ro=%d go=%d cec=%d %s", read.getReadName(), readOffset, genomeOffset, offsetIntoCurrentCigarElement, currentElement);
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ //
+ // Code for setting up prev / next states
+ //
+ // -----------------------------------------------------------------------------------------------
+
+ /**
+ * Step the state machine forward one unit
+ *
+ * Takes the current state of this machine, and advances the state until the next on-genome
+ * cigar element (M, X, =, D) is encountered, at which point this function returns with the
+ * cigar operator of the current element.
+ *
+ * Assumes that the AlignmentStateMachine is in the left edge state at the start, so that
+ * stepForwardOnGenome() can be called to move the machine to the first alignment position. That
+ * is, the normal use of this code is:
+ *
+ * AlignmentStateMachine machine = new AlignmentStateMachine(read)
+ * machine.stepForwardOnGenome()
+ * // now the machine is at the first position on the genome
+ *
+ * When stepForwardOnGenome() advances off the right edge of the read, the state machine is
+ * left in a state such that isRightEdge() returns true and returns null, indicating the
+ * the machine cannot advance further. The machine may explode, though this is not contracted,
+ * if stepForwardOnGenome() is called after a previous call returned null.
+ *
+ * @return the operator of the cigar element that machine stopped at, null if we advanced off the end of the read
+ */
+ @Ensures("result != null || isRightEdge()")
+ public CigarOperator stepForwardOnGenome() {
+ // loop until we either find a cigar element step that moves us one base on the genome, or we run
+ // out of cigar elements
+ while ( true ) {
+ // we enter this method with readOffset = index of the last processed base on the read
+ // (-1 if we did not process a single base yet); this can be last matching base,
+ // or last base of an insertion
+ if (currentElement == null || (offsetIntoCurrentCigarElement + 1) >= currentElement.getLength()) {
+ currentCigarElementOffset++;
+ if (currentCigarElementOffset < nCigarElements) {
+ currentElement = cigar.getCigarElement(currentCigarElementOffset);
+ offsetIntoCurrentCigarElement = -1;
+ // next line: guards against cigar elements of length 0; when new cigar element is retrieved,
+ // we reenter in order to re-check offsetIntoCurrentCigarElement against currentElement's length
+ continue;
+ } else {
+ if (currentElement != null && currentElement.getOperator() == CigarOperator.D)
+ throw new UserException.MalformedBAM(read, "read ends with deletion. Cigar: " + read.getCigarString() + ". Although the SAM spec technically permits such reads, this is often indicative of malformed files. If you are sure you want to use this file, re-run your analysis with the extra option: -rf BadCigar");
+
+ // we're done, so set the offset of the cigar to 0 for cleanliness, as well as the current element
+ offsetIntoCurrentCigarElement = 0;
+ readOffset = read.getReadLength();
+ currentElement = null;
+
+ // Reads that contain indels model the genomeOffset as the following base in the reference. Because
+ // we fall into this else block only when indels end the read, increment genomeOffset such that the
+ // current offset of this read is the next ref base after the end of the indel. This position will
+ // model a point on the reference somewhere after the end of the read.
+ genomeOffset++; // extended events need that. Logically, it's legal to advance the genomic offset here:
+
+ // we do step forward on the ref, and by returning null we also indicate that we are past the read end.
+ return null;
+ }
+ }
+
+ offsetIntoCurrentCigarElement++;
+ boolean done = false;
+ switch (currentElement.getOperator()) {
+ case H: // ignore hard clips
+ case P: // ignore pads
+ offsetIntoCurrentCigarElement = currentElement.getLength();
+ break;
+ case I: // insertion w.r.t. the reference
+ case S: // soft clip
+ offsetIntoCurrentCigarElement = currentElement.getLength();
+ readOffset += currentElement.getLength();
+ break;
+ case D: // deletion w.r.t. the reference
+ if (readOffset < 0) // we don't want reads starting with deletion, this is a malformed cigar string
+ throw new UserException.MalformedBAM(read, "read starts with deletion. Cigar: " + read.getCigarString() + ". Although the SAM spec technically permits such reads, this is often indicative of malformed files. If you are sure you want to use this file, re-run your analysis with the extra option: -rf BadCigar");
+ // should be the same as N case
+ genomeOffset++;
+ done = true;
+ break;
+ case N: // reference skip (looks and gets processed just like a "deletion", just different logical meaning)
+ genomeOffset++;
+ done = true;
+ break;
+ case M:
+ case EQ:
+ case X:
+ readOffset++;
+ genomeOffset++;
+ done = true;
+ break;
+ default:
+ throw new IllegalStateException("Case statement didn't deal with cigar op: " + currentElement.getOperator());
+ }
+
+ if ( done )
+ return currentElement.getOperator();
+ }
+ }
+
+ /**
+ * Create a new PileupElement based on the current state of this element
+ *
+ * Must not be a left or right edge
+ *
+ * @return a pileup element
+ */
+ @Ensures("result != null")
+ public final PileupElement makePileupElement() {
+ if ( isLeftEdge() || isRightEdge() )
+ throw new IllegalStateException("Cannot make a pileup element from an edge alignment state");
+ return new PileupElement(read,
+ getReadOffset(),
+ getCurrentCigarElement(),
+ getCurrentCigarElementOffset(),
+ getOffsetIntoCurrentCigarElement());
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LIBSDownsamplingInfo.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LIBSDownsamplingInfo.java
new file mode 100644
index 0000000..01bf17d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LIBSDownsamplingInfo.java
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+/**
+ * Simple wrapper about the information LIBS needs about downsampling
+ *
+ * User: depristo
+ * Date: 1/5/13
+ * Time: 1:26 PM
+ */
+class LIBSDownsamplingInfo {
+ final private boolean performDownsampling;
+ final private int toCoverage;
+
+ public LIBSDownsamplingInfo(boolean performDownsampling, int toCoverage) {
+ this.performDownsampling = performDownsampling;
+ this.toCoverage = toCoverage;
+ }
+
+ public boolean isPerformDownsampling() {
+ return performDownsampling;
+ }
+
+ public int getToCoverage() {
+ return toCoverage;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LIBSPerformance.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LIBSPerformance.java
new file mode 100644
index 0000000..d9b158f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LIBSPerformance.java
@@ -0,0 +1,198 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecordIterator;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.CommandLineProgram;
+import org.broadinstitute.gatk.utils.commandline.Input;
+import org.broadinstitute.gatk.engine.ReadProperties;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMRecordIterator;
+import org.broadinstitute.gatk.utils.*;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.GATKSamRecordFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Caliper microbenchmark of fragment pileup
+ */
+public class LIBSPerformance extends CommandLineProgram {
+ private static Logger logger = Logger.getLogger(LIBSPerformance.class);
+
+ @Input(fullName = "input_file", shortName = "I", doc = "SAM or BAM file(s)", required = true)
+ public File samFile = null;
+
+ @Input(fullName = "reference_sequence", shortName = "R", doc = "Reference sequence file", required = true)
+ public File referenceFile = null;
+
+ @Argument(fullName = "L", shortName = "L", doc = "Query location", required = false)
+ public String location = null;
+
+ @Argument(fullName = "dt", shortName = "dt", doc = "Enable downsampling", required = false)
+ public boolean downsample = false;
+
+ @Override
+ public int execute() throws IOException {
+ final IndexedFastaSequenceFile reference = new CachingIndexedFastaSequenceFile(referenceFile);
+ final GenomeLocParser genomeLocParser = new GenomeLocParser(reference);
+
+ final SAMFileReader reader = new SAMFileReader(samFile);
+ reader.setSAMRecordFactory(new GATKSamRecordFactory());
+
+ SAMRecordIterator rawIterator;
+ if ( location == null )
+ rawIterator = reader.iterator();
+ else {
+ final GenomeLoc loc = genomeLocParser.parseGenomeLoc(location);
+ rawIterator = reader.query(loc.getContig(), loc.getStart(), loc.getStop(), false);
+ }
+
+ final GATKSAMRecordIterator iterator = new GATKSAMRecordIterator(rawIterator);
+
+ final Set<String> samples = new HashSet<String>();
+ for ( final SAMReadGroupRecord rg : reader.getFileHeader().getReadGroups() )
+ samples.add(rg.getSample());
+
+ final LIBSDownsamplingInfo ds = new LIBSDownsamplingInfo(downsample, 250);
+
+ final LocusIteratorByState libs =
+ new LocusIteratorByState(
+ iterator,
+ ds,
+ true,
+ genomeLocParser,
+ samples,
+ false);
+
+ final SimpleTimer timer = new SimpleTimer().start();
+ int bp = 0;
+ double lastElapsed = 0;
+ while ( libs.hasNext() ) {
+ AlignmentContext context = libs.next();
+ bp++;
+ if ( timer.getElapsedTime() - lastElapsed > 10 ) {
+ logger.info(bp + " iterations at " + context.getLocation());
+ lastElapsed = timer.getElapsedTime();
+ }
+ }
+ logger.info(String.format("runtime in seconds: %.2f", timer.getElapsedTime()));
+
+ return 0;
+ }
+
+// private void syntheticTests() {
+// final int readLength = 101;
+// final int nReads = 10000;
+// final int locus = 1;
+//
+// SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000);
+// final GenomeLocParser genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+//
+// int nIterations = 0;
+// for ( final String cigar : Arrays.asList("101M", "50M10I40M", "50M10D40M") ) {
+// GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read", 0, locus, readLength);
+// read.setReadBases(Utils.dupBytes((byte) 'A', readLength));
+// final byte[] quals = new byte[readLength];
+// for ( int i = 0; i < readLength; i++ )
+// quals[i] = (byte)(i % QualityUtils.MAX_SAM_QUAL_SCORE);
+// read.setBaseQualities(quals);
+// read.setCigarString(cigar);
+//
+// for ( int j = 0; j < nReads; j++ ) {
+// for ( int i = 0; i < rep; i++ ) {
+// switch ( op ) {
+// case NEW_STATE:
+// {
+// final AlignmentStateMachine alignmentStateMachine = new AlignmentStateMachine(read);
+// while ( alignmentStateMachine.stepForwardOnGenome() != null ) {
+// nIterations++;
+// }
+// }
+// break;
+//// case OLD_STATE:
+//// {
+//// final SAMRecordAlignmentState alignmentStateMachine = new SAMRecordAlignmentState(read);
+//// while ( alignmentStateMachine.stepForwardOnGenome() != null ) {
+//// alignmentStateMachine.getRead();
+//// nIterations++;
+//// }
+//// }
+//// break;
+// case NEW_LIBS:
+// {
+// final List<GATKSAMRecord> reads = Collections.nCopies(30, read);
+// final org.broadinstitute.gatk.utils.locusiterator.LocusIteratorByState libs =
+// new org.broadinstitute.gatk.utils.locusiterator.LocusIteratorByState(
+// new LocusIteratorByStateBaseTest.FakeCloseableIterator<GATKSAMRecord>(reads.iterator()),
+// LocusIteratorByStateBaseTest.createTestReadProperties(),
+// genomeLocParser,
+// LocusIteratorByState.sampleListForSAMWithoutReadGroups());
+//
+// while ( libs.hasNext() ) {
+// AlignmentContext context = libs.next();
+// }
+// }
+// }
+// }
+// }
+// }
+//
+// System.out.printf("iterations %d%n", nIterations);
+// }
+
+ /**
+ * Required main method implementation.
+ * @param argv Command-line argument text.
+ * @throws Exception on error.
+ */
+ public static void main(String[] argv) throws Exception {
+ int returnCode = 0;
+ try {
+ LIBSPerformance instance = new LIBSPerformance();
+ start(instance, argv);
+ returnCode = 0;
+ } catch(Exception ex) {
+ returnCode = 1;
+ ex.printStackTrace();
+ throw ex;
+ } finally {
+ System.exit(returnCode);
+ }
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LocusIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LocusIterator.java
new file mode 100644
index 0000000..72764e4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LocusIterator.java
@@ -0,0 +1,62 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import htsjdk.samtools.util.CloseableIterator;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+
+import java.util.Iterator;
+
+/**
+ * Iterator that traverses a SAM File, accumulating information on a per-locus basis
+ */
+public abstract class LocusIterator implements Iterable<AlignmentContext>, CloseableIterator<AlignmentContext> {
+ public Iterator<AlignmentContext> iterator() {
+ return this;
+ }
+
+ public void close() {
+ //this.it.close();
+ }
+
+ public abstract boolean hasNext();
+ public abstract AlignmentContext next();
+
+ /**
+ * Get, if possible, the underlying LocusIteratorByState from this LocusIterator.
+ *
+ * @throws UnsupportedOperationException if we don't support this operation
+ *
+ * @return a non-null locus iterator by state
+ */
+ public LocusIteratorByState getLIBS() {
+ throw new UnsupportedOperationException("This locus iterator does not support getting the underlying LocusIteratorByState");
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Can not remove records from a SAM file via an iterator!");
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorByState.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorByState.java
new file mode 100644
index 0000000..aaf6190
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorByState.java
@@ -0,0 +1,454 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.CloseableIterator;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.ReadProperties;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMRecordIterator;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileupImpl;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.ReadUtils;
+
+import java.util.*;
+
+/**
+ * Iterator that traverses a SAM File, accumulating information on a per-locus basis
+ *
+ * Produces AlignmentContext objects, that contain ReadBackedPileups of PileupElements. This
+ * class has its core job of converting an iterator of ordered SAMRecords into those
+ * RBPs.
+ *
+ * There are a few constraints on required and ensured by LIBS:
+ *
+ * -- Requires the Iterator<GATKSAMRecord> to returns reads in coordinate sorted order, consistent with the ordering
+ * defined by the SAM file format. That that for performance reasons this constraint isn't actually enforced.
+ * The behavior of LIBS is undefined in the case where the reads are badly ordered.
+ * -- The reads in the ReadBackedPileup are themselves in the order of appearance of the reads from the iterator.
+ * That is, the pileup is ordered in a way consistent with the SAM coordinate ordering
+ * -- Only aligned reads with at least one on-genomic cigar operator are passed on in the pileups. That is,
+ * unmapped reads or reads that are all insertions (10I) or soft clipped (10S) are not passed on.
+ * -- LIBS can perform per-sample downsampling of a variety of kinds.
+ * -- Because of downsampling there's no guarantee that:
+ * -- A read that could be aligned to a position will actually occur in the pileup (downsampled away)
+ * -- A read that appears in a previous pileup that could align to a future position will actually occur
+ * in that pileup. That is, a read might show up at position i but be downsampled away in the pileup at j
+ * -- LIBS can optionally capture all of the reads that come off the iterator, before any leveling downsampling
+ * occurs, if requested. This allows users of LIBS to see both a ReadBackedPileup view of the data as well as
+ * a stream of unique, sorted reads
+ */
+public final class LocusIteratorByState extends LocusIterator {
+ /** Indicates that we shouldn't do any downsampling */
+ public final static LIBSDownsamplingInfo NO_DOWNSAMPLING = new LIBSDownsamplingInfo(false, -1);
+
+ /**
+ * our log, which we want to capture anything from this class
+ */
+ private final static Logger logger = Logger.getLogger(LocusIteratorByState.class);
+
+ // -----------------------------------------------------------------------------------------------------------------
+ //
+ // member fields
+ //
+ // -----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Used to create new GenomeLocs as needed
+ */
+ private final GenomeLocParser genomeLocParser;
+
+ /**
+ * A complete list of all samples that may come out of the reads. Must be
+ * comprehensive.
+ */
+ private final ArrayList<String> samples;
+
+ /**
+ * The system that maps incoming reads from the iterator to their pileup states
+ */
+ private final ReadStateManager readStates;
+
+ /**
+ * Should we include reads in the pileup which are aligned with a deletion operator to the reference?
+ */
+ private final boolean includeReadsWithDeletionAtLoci;
+
+ /**
+ * The next alignment context. A non-null value means that a
+ * context is waiting from hasNext() for sending off to the next next() call. A null
+ * value means that either hasNext() has not been called at all or that
+ * the underlying iterator is exhausted
+ */
+ private AlignmentContext nextAlignmentContext;
+
+ // -----------------------------------------------------------------------------------------------------------------
+ //
+ // constructors and other basic operations
+ //
+ // -----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Create a new LocusIteratorByState
+ *
+ * @param samIterator the iterator of reads to process into pileups. Reads must be ordered
+ * according to standard coordinate-sorted BAM conventions
+ * @param readInformation meta-information about how to process the reads (i.e., should we do downsampling?)
+ * @param genomeLocParser used to create genome locs
+ * @param samples a complete list of samples present in the read groups for the reads coming from samIterator.
+ * This is generally just the set of read group sample fields in the SAMFileHeader. This
+ * list of samples may contain a null element, and all reads without read groups will
+ * be mapped to this null sample
+ */
+ public LocusIteratorByState(final Iterator<GATKSAMRecord> samIterator,
+ final ReadProperties readInformation,
+ final GenomeLocParser genomeLocParser,
+ final Collection<String> samples) {
+ this(samIterator,
+ toDownsamplingInfo(readInformation),
+ readInformation.includeReadsWithDeletionAtLoci(),
+ genomeLocParser,
+ samples,
+ readInformation.keepUniqueReadListInLIBS());
+ }
+
+ /**
+ * Create a new LocusIteratorByState based on a SAMFileReader using reads in an iterator it
+ *
+ * Simple constructor that uses the samples in the reader, doesn't do any downsampling,
+ * and makes a new GenomeLocParser using the reader. This constructor will be slow(ish)
+ * if you continually invoke this constructor, but it's easy to make.
+ *
+ * @param reader a non-null reader
+ * @param it an iterator from reader that has the reads we want to use to create ReadBackPileups
+ */
+ public LocusIteratorByState(final SAMFileReader reader, final CloseableIterator<SAMRecord> it) {
+ this(new GATKSAMRecordIterator(it),
+ new LIBSDownsamplingInfo(false, 0),
+ true,
+ new GenomeLocParser(reader.getFileHeader().getSequenceDictionary()),
+ SampleUtils.getSAMFileSamples(reader.getFileHeader()),
+ false);
+ }
+
+ /**
+ * Create a new LocusIteratorByState
+ *
+ * @param samIterator the iterator of reads to process into pileups. Reads must be ordered
+ * according to standard coordinate-sorted BAM conventions
+ * @param downsamplingInfo meta-information about how to downsampling the reads
+ * @param genomeLocParser used to create genome locs
+ * @param samples a complete list of samples present in the read groups for the reads coming from samIterator.
+ * This is generally just the set of read group sample fields in the SAMFileHeader. This
+ * list of samples may contain a null element, and all reads without read groups will
+ * be mapped to this null sample
+ * @param maintainUniqueReadsList if true, we will keep the unique reads from off the samIterator and make them
+ * available via the transferReadsFromAllPreviousPileups interface
+ */
+ public LocusIteratorByState(final Iterator<GATKSAMRecord> samIterator,
+ final LIBSDownsamplingInfo downsamplingInfo,
+ final boolean includeReadsWithDeletionAtLoci,
+ final GenomeLocParser genomeLocParser,
+ final Collection<String> samples,
+ final boolean maintainUniqueReadsList) {
+ if ( samIterator == null ) throw new IllegalArgumentException("samIterator cannot be null");
+ if ( downsamplingInfo == null ) throw new IllegalArgumentException("downsamplingInfo cannot be null");
+ if ( genomeLocParser == null ) throw new IllegalArgumentException("genomeLocParser cannot be null");
+ if ( samples == null ) throw new IllegalArgumentException("Samples cannot be null");
+
+ // currently the GATK expects this LocusIteratorByState to accept empty sample lists, when
+ // there's no read data. So we need to throw this error only when samIterator.hasNext() is true
+ if (samples.isEmpty() && samIterator.hasNext()) {
+ throw new IllegalArgumentException("samples list must not be empty");
+ }
+
+ this.genomeLocParser = genomeLocParser;
+ this.includeReadsWithDeletionAtLoci = includeReadsWithDeletionAtLoci;
+ this.samples = new ArrayList<String>(samples);
+ this.readStates = new ReadStateManager(samIterator, this.samples, downsamplingInfo, maintainUniqueReadsList);
+ }
+
+ @Override
+ public Iterator<AlignmentContext> iterator() {
+ return this;
+ }
+
+ /**
+ * Get the current location (i.e., the bp of the center of the pileup) of the pileup, or null if not anywhere yet
+ *
+ * Assumes that read states is updated to reflect the current pileup position, but not advanced to the
+ * next location.
+ *
+ * @return the location of the current pileup, or null if we're after all reads
+ */
+ private GenomeLoc getLocation() {
+ return readStates.isEmpty() ? null : readStates.getFirst().getLocation(genomeLocParser);
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ //
+ // next() routine and associated collection operations
+ //
+ // -----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Is there another pileup available?
+ * @return
+ */
+ @Override
+ public boolean hasNext() {
+ lazyLoadNextAlignmentContext();
+ return nextAlignmentContext != null;
+ }
+
+ /**
+ * Get the next AlignmentContext available from the reads.
+ *
+ * @return a non-null AlignmentContext of the pileup after to the next genomic position covered by
+ * at least one read.
+ */
+ @Override
+ public AlignmentContext next() {
+ lazyLoadNextAlignmentContext();
+ if (!hasNext())
+ throw new NoSuchElementException("LocusIteratorByState: out of elements.");
+ AlignmentContext currentAlignmentContext = nextAlignmentContext;
+ nextAlignmentContext = null;
+ return currentAlignmentContext;
+ }
+
+ /**
+ * Move this LIBS until we are over position
+ *
+ * Will return null if cannot reach position (because we run out of data in the locus)
+ *
+ * @param position the start position of the AlignmentContext we want back
+ * @param stopAtFirstNonEmptySiteAfterPosition if true, we will stop as soon as we find a context with data with
+ * position >= position, otherwise we will return a null value
+ * and consume the data for the next position. This means that without
+ * specifying this value the LIBS will be in an indeterminate state
+ * after calling this function, and should be reconstructed from scratch
+ * for subsequent use
+ * @return a AlignmentContext at position, or null if this isn't possible
+ */
+ public AlignmentContext advanceToLocus(final int position, final boolean stopAtFirstNonEmptySiteAfterPosition) {
+ while ( hasNext() ) {
+ final AlignmentContext context = next();
+
+ if ( context == null )
+ // we ran out of data
+ return null;
+
+ if ( context.getPosition() == position )
+ return context;
+
+ if ( context.getPosition() > position)
+ return stopAtFirstNonEmptySiteAfterPosition ? context : null;
+ }
+
+ return null;
+ }
+
+ /**
+ * Creates the next alignment context from the given state. Note that this is implemented as a
+ * lazy load method. nextAlignmentContext MUST BE null in order for this method to advance to the
+ * next entry.
+ */
+ private void lazyLoadNextAlignmentContext() {
+ while (nextAlignmentContext == null && readStates.hasNext()) {
+ readStates.collectPendingReads();
+
+ final GenomeLoc location = getLocation();
+ final Map<String, ReadBackedPileupImpl> fullPileup = new HashMap<String, ReadBackedPileupImpl>();
+
+ for (final Map.Entry<String, PerSampleReadStateManager> sampleStatePair : readStates ) {
+ final String sample = sampleStatePair.getKey();
+ final PerSampleReadStateManager readState = sampleStatePair.getValue();
+ final Iterator<AlignmentStateMachine> iterator = readState.iterator();
+ final List<PileupElement> pile = new ArrayList<PileupElement>(readState.size());
+
+ while (iterator.hasNext()) {
+ // state object with the read/offset information
+ final AlignmentStateMachine state = iterator.next();
+ final GATKSAMRecord read = state.getRead();
+ final CigarOperator op = state.getCigarOperator();
+
+ if (op == CigarOperator.N) // N's are never added to any pileup
+ continue;
+
+ if (!dontIncludeReadInPileup(read, location.getStart())) {
+ if ( ! includeReadsWithDeletionAtLoci && op == CigarOperator.D ) {
+ continue;
+ }
+
+ pile.add(state.makePileupElement());
+ }
+ }
+
+ if (! pile.isEmpty() ) // if this pileup added at least one base, add it to the full pileup
+ fullPileup.put(sample, new ReadBackedPileupImpl(location, pile));
+ }
+
+ readStates.updateReadStates(); // critical - must be called after we get the current state offsets and location
+ if (!fullPileup.isEmpty()) // if we got reads with non-D/N over the current position, we are done
+ nextAlignmentContext = new AlignmentContext(location, new ReadBackedPileupImpl(location, fullPileup), false);
+ }
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ //
+ // getting the list of reads
+ //
+ // -----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Transfer current list of all unique reads that have ever been used in any pileup, clearing old list
+ *
+ * This list is guaranteed to only contain unique reads, even across calls to the this function. It is
+ * literally the unique set of reads ever seen.
+ *
+ * The list occurs in the same order as they are encountered in the underlying iterator.
+ *
+ * Takes the maintained list of submitted reads, and transfers it to the caller of this
+ * function. The old list of set to a new, cleanly allocated list so the caller officially
+ * owns the list returned by this call. This is the only way to clear the tracking
+ * of submitted reads, if enabled.
+ *
+ * The purpose of this function is allow users of LIBS to keep track of all of the reads pulled off the
+ * underlying GATKSAMRecord iterator and that appeared at any point in the list of SAMRecordAlignmentState for
+ * any reads. This function is intended to allow users to efficiently reconstruct the unique set of reads
+ * used across all pileups. This is necessary for LIBS to handle because attempting to do
+ * so from the pileups coming out of LIBS is extremely expensive.
+ *
+ * This functionality is only available if LIBS was created with the argument to track the reads
+ *
+ * @throws UnsupportedOperationException if called when keepingSubmittedReads is false
+ *
+ * @return the current list
+ */
+ @Ensures("result != null")
+ public List<GATKSAMRecord> transferReadsFromAllPreviousPileups() {
+ return readStates.transferSubmittedReads();
+ }
+
+ /**
+ * Get the underlying list of tracked reads. For testing only
+ * @return a non-null list
+ */
+ @Ensures("result != null")
+ protected List<GATKSAMRecord> getReadsFromAllPreviousPileups() {
+ return readStates.getSubmittedReads();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ //
+ // utility functions
+ //
+ // -----------------------------------------------------------------------------------------------------------------
+
+ /**
+ * Should this read be excluded from the pileup?
+ *
+ * Generic place to put per-base filters appropriate to LocusIteratorByState
+ *
+ * @param rec the read to potentially exclude
+ * @param pos the genomic position of the current alignment
+ * @return true if the read should be excluded from the pileup, false otherwise
+ */
+ @Requires({"rec != null", "pos > 0"})
+ private boolean dontIncludeReadInPileup(final GATKSAMRecord rec, final long pos) {
+ return ReadUtils.isBaseInsideAdaptor(rec, pos);
+ }
+
+ /**
+ * Create a LIBSDownsamplingInfo object from the requested info in ReadProperties
+ *
+ * LIBS will invoke the Reservoir and Leveling downsamplers on the read stream if we're
+ * downsampling to coverage by sample. SAMDataSource will have refrained from applying
+ * any downsamplers to the read stream in this case, in the expectation that LIBS will
+ * manage the downsampling. The reason for this is twofold: performance (don't have to
+ * split/re-assemble the read stream in SAMDataSource), and to enable partial downsampling
+ * of reads (eg., using half of a read, and throwing the rest away).
+ *
+ * @param readInfo GATK engine information about what should be done to the reads
+ * @return a LIBS specific info holder about downsampling only
+ */
+ @Requires("readInfo != null")
+ @Ensures("result != null")
+ private static LIBSDownsamplingInfo toDownsamplingInfo(final ReadProperties readInfo) {
+ final boolean performDownsampling = readInfo.getDownsamplingMethod() != null &&
+ readInfo.getDownsamplingMethod().type == DownsampleType.BY_SAMPLE &&
+ readInfo.getDownsamplingMethod().toCoverage != null;
+ final int coverage = performDownsampling ? readInfo.getDownsamplingMethod().toCoverage : 0;
+
+ return new LIBSDownsamplingInfo(performDownsampling, coverage);
+ }
+
+ /**
+ * Create a pileup element for read at offset
+ *
+ * offset must correspond to a valid read offset given the read's cigar, or an IllegalStateException will be throw
+ *
+ * @param read a read
+ * @param offset the offset into the bases we'd like to use in the pileup
+ * @return a valid PileupElement with read and at offset
+ */
+ @Ensures("result != null")
+ public static PileupElement createPileupForReadAndOffset(final GATKSAMRecord read, final int offset) {
+ if ( read == null ) throw new IllegalArgumentException("read cannot be null");
+ if ( offset < 0 || offset >= read.getReadLength() ) throw new IllegalArgumentException("Invalid offset " + offset + " outside of bounds 0 and " + read.getReadLength());
+
+ final AlignmentStateMachine stateMachine = new AlignmentStateMachine(read);
+
+ while ( stateMachine.stepForwardOnGenome() != null ) {
+ if ( stateMachine.getReadOffset() == offset )
+ return stateMachine.makePileupElement();
+ }
+
+ throw new IllegalStateException("Tried to create a pileup for read " + read + " with offset " + offset +
+ " but we never saw such an offset in the alignment state machine");
+ }
+
+ /**
+ * For testing only. Assumes that the incoming SAMRecords have no read groups, so creates a dummy sample list
+ * for the system.
+ */
+ public static List<String> sampleListForSAMWithoutReadGroups() {
+ List<String> samples = new ArrayList<String>();
+ samples.add(null);
+ return samples;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/PerSampleReadStateManager.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/PerSampleReadStateManager.java
new file mode 100644
index 0000000..e6d49c3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/PerSampleReadStateManager.java
@@ -0,0 +1,261 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Invariant;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.CigarOperator;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.downsampling.Downsampler;
+import org.broadinstitute.gatk.engine.downsampling.LevelingDownsampler;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * ReadStateManager for a single sample
+ *
+ * User: depristo
+ * Date: 1/13/13
+ * Time: 12:28 PM
+ */
+ at Invariant({
+ "readStartsAreWellOrdered()",
+ "! isDownsampling() || downsamplingTarget > 0",
+ "nSites >= 0",
+ "nSitesNeedingDownsampling >= 0",
+ "nSitesNeedingDownsampling <= nSites"
+})
+final class PerSampleReadStateManager implements Iterable<AlignmentStateMachine> {
+ private final static Logger logger = Logger.getLogger(ReadStateManager.class);
+ private final static boolean CAPTURE_DOWNSAMPLING_STATS = false;
+
+ /**
+ * A list (potentially empty) of alignment state machines.
+ *
+ * The state machines must be ordered by the alignment start of their underlying reads, with the
+ * lowest alignment starts on the left, and the largest on the right
+ */
+ private LinkedList<AlignmentStateMachine> readStatesByAlignmentStart = new LinkedList<AlignmentStateMachine>();
+
+ private final Downsampler<LinkedList<AlignmentStateMachine>> levelingDownsampler;
+ private final int downsamplingTarget;
+
+ /**
+ * The number of sites where downsampling has been invoked
+ */
+ private int nSitesNeedingDownsampling = 0;
+
+ /**
+ * The number of sites we've visited
+ */
+ private int nSites = 0;
+
+ /**
+ * Create a new PerSampleReadStateManager with downsampling parameters as requested by LIBSDownsamplingInfo
+ * @param LIBSDownsamplingInfo the downsampling params we want to use
+ */
+ public PerSampleReadStateManager(final LIBSDownsamplingInfo LIBSDownsamplingInfo) {
+ this.downsamplingTarget = LIBSDownsamplingInfo.isPerformDownsampling() ? LIBSDownsamplingInfo.getToCoverage() : -1;
+ this.levelingDownsampler = LIBSDownsamplingInfo.isPerformDownsampling()
+ ? new LevelingDownsampler<LinkedList<AlignmentStateMachine>, AlignmentStateMachine>(LIBSDownsamplingInfo.getToCoverage())
+ : null;
+ }
+
+ /**
+ * Group the underlying readStatesByAlignmentStart into a list of list of alignment state machines,
+ * where each list contains machines with a unique genome site. The outer list is ordered
+ * by alignment start.
+ *
+ * For example, if the flat list has alignment starts [10, 10, 11, 12, 12, 13] then
+ * the resulting grouping will be [[10, 10], [11], [12, 12], [13]].
+ *
+ * @return a non-null list of lists
+ */
+ @Ensures("result != null")
+ private List<LinkedList<AlignmentStateMachine>> groupByAlignmentStart() {
+ final LinkedList<LinkedList<AlignmentStateMachine>> grouped = new LinkedList<LinkedList<AlignmentStateMachine>>();
+
+ AlignmentStateMachine last = null;
+ for ( final AlignmentStateMachine stateMachine : readStatesByAlignmentStart ) {
+ if ( last == null || stateMachine.getGenomeOffset() != last.getGenomeOffset() ) {
+ // we've advanced to a place where the state machine has a different state,
+ // so start a new list
+ grouped.add(new LinkedList<AlignmentStateMachine>());
+ last = stateMachine;
+ }
+ grouped.getLast().add(stateMachine);
+ }
+
+ return grouped;
+ }
+
+ /**
+ * Flattens the grouped list of list of alignment state machines into a single list in order
+ * @return a non-null list contains the state machines
+ */
+ @Ensures("result != null")
+ private LinkedList<AlignmentStateMachine> flattenByAlignmentStart(final List<LinkedList<AlignmentStateMachine>> grouped) {
+ final LinkedList<AlignmentStateMachine> flat = new LinkedList<AlignmentStateMachine>();
+ for ( final List<AlignmentStateMachine> l : grouped )
+ flat.addAll(l);
+ return flat;
+ }
+
+ /**
+ * Test that the reads are ordered by their alignment starts
+ * @return true if well ordered, false otherwise
+ */
+ private boolean readStartsAreWellOrdered() {
+ int lastStart = -1;
+ for ( final AlignmentStateMachine machine : readStatesByAlignmentStart ) {
+ if ( lastStart > machine.getRead().getAlignmentStart() )
+ return false;
+ lastStart = machine.getRead().getAlignmentStart();
+ }
+ return true;
+ }
+
+ /**
+ * Assumes it can just keep the states linked lists without making a copy
+ * @param states the new states to add to this manager
+ * @return The change in the number of states, after including states and potentially downsampling. Note
+ * that this return result might be negative, if downsampling is enabled, as we might drop
+ * more sites than have been added by the downsampler
+ */
+ @Requires("states != null")
+ public int addStatesAtNextAlignmentStart(final LinkedList<AlignmentStateMachine> states) {
+ if ( states.isEmpty() ) {
+ return 0;
+ }
+
+ readStatesByAlignmentStart.addAll(states);
+ int nStatesAdded = states.size();
+
+ if ( isDownsampling() && readStatesByAlignmentStart.size() > downsamplingTarget ) {
+ // only go into the downsampling branch if we are downsampling and the coverage > the target
+ captureDownsamplingStats();
+ levelingDownsampler.submit(groupByAlignmentStart());
+ levelingDownsampler.signalEndOfInput();
+
+ nStatesAdded -= levelingDownsampler.getNumberOfDiscardedItems();
+
+ // use returned List directly rather than make a copy, for efficiency's sake
+ readStatesByAlignmentStart = flattenByAlignmentStart(levelingDownsampler.consumeFinalizedItems());
+ levelingDownsampler.resetStats();
+ }
+
+ return nStatesAdded;
+ }
+
+ /**
+ * Is downsampling enabled for this manager?
+ * @return true if we are downsampling, false otherwise
+ */
+ private boolean isDownsampling() {
+ return levelingDownsampler != null;
+ }
+
+ /**
+ * Get the leftmost alignment state machine, or null if the read states is empty
+ * @return a potentially null AlignmentStateMachine
+ */
+ public AlignmentStateMachine getFirst() {
+ return isEmpty() ? null : readStatesByAlignmentStart.getFirst();
+ }
+
+ /**
+ * Capture some statistics about the behavior of the downsampling, but only if CAPTURE_DOWNSAMPLING_STATS is true
+ */
+ @Requires("isDownsampling()")
+ private void captureDownsamplingStats() {
+ if ( CAPTURE_DOWNSAMPLING_STATS ) {
+ nSites++;
+ final int loc = getFirst().getGenomePosition();
+ String message = "Pass through";
+ final boolean downsampling = size() > downsamplingTarget;
+ if ( downsampling ) {
+ nSitesNeedingDownsampling++;
+ message = "Downsampling";
+ }
+
+ if ( downsampling || nSites % 10000 == 0 )
+ logger.info(String.format("%20s at %s: coverage=%d, max=%d, fraction of downsampled sites=%.2e",
+ message, loc, size(), downsamplingTarget, (1.0 * nSitesNeedingDownsampling / nSites)));
+ }
+ }
+
+ /**
+ * Is there at least one alignment for this sample in this manager?
+ * @return true if there's at least one alignment, false otherwise
+ */
+ public boolean isEmpty() {
+ return readStatesByAlignmentStart.isEmpty();
+ }
+
+ /**
+ * Get the number of read states currently in this manager
+ * @return the number of read states
+ */
+ @Ensures("result >= 0")
+ public int size() {
+ return readStatesByAlignmentStart.size();
+ }
+
+ /**
+ * Advances all read states forward by one element, removing states that are
+ * no long aligned to the current position.
+ * @return the number of states we're removed after advancing
+ */
+ public int updateReadStates() {
+ int nRemoved = 0;
+ final Iterator<AlignmentStateMachine> it = iterator();
+ while (it.hasNext()) {
+ final AlignmentStateMachine state = it.next();
+ final CigarOperator op = state.stepForwardOnGenome();
+ if (op == null) {
+ // we discard the read only when we are past its end AND indel at the end of the read (if any) was
+ // already processed. Keeping the read state that returned null upon stepForwardOnGenome() is safe
+ // as the next call to stepForwardOnGenome() will return null again AND will clear hadIndel() flag.
+ it.remove(); // we've stepped off the end of the object
+ nRemoved++;
+ }
+ }
+
+ return nRemoved;
+ }
+
+ /**
+ * Iterate over the AlignmentStateMachine in this manager in alignment start order.
+ * @return a valid iterator
+ */
+ @Ensures("result != null")
+ public Iterator<AlignmentStateMachine> iterator() {
+ return readStatesByAlignmentStart.iterator();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/ReadStateManager.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/ReadStateManager.java
new file mode 100644
index 0000000..0014753
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/ReadStateManager.java
@@ -0,0 +1,289 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.util.PeekableIterator;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.*;
+
+/**
+ * Manages and updates mapping from sample -> List of SAMRecordAlignmentState
+ *
+ * Optionally can keep track of all of the reads pulled off the iterator and
+ * that appeared at any point in the list of SAMRecordAlignmentState for any reads.
+ * This functionaly is only possible at this stage, as this object does the popping of
+ * reads off the underlying source iterator, and presents only a pileup-like interface
+ * of samples -> SAMRecordAlignmentStates. Reconstructing the unique set of reads
+ * used across all pileups is extremely expensive from that data structure.
+ *
+ * User: depristo
+ * Date: 1/5/13
+ * Time: 2:02 PM
+ */
+final class ReadStateManager implements Iterable<Map.Entry<String, PerSampleReadStateManager>> {
+ private final List<String> samples;
+ private final PeekableIterator<GATKSAMRecord> iterator;
+ private final SamplePartitioner<GATKSAMRecord> samplePartitioner;
+
+ /**
+ * A mapping from sample name -> the per sample read state manager that manages
+ *
+ * IT IS CRITICAL THAT THIS BE A LINKED HASH MAP, SO THAT THE ITERATION OF THE MAP OCCURS IN THE SAME
+ * ORDER AS THE ORIGINL SAMPLES
+ */
+ private final Map<String, PerSampleReadStateManager> readStatesBySample = new LinkedHashMap<String, PerSampleReadStateManager>();
+
+ private LinkedList<GATKSAMRecord> submittedReads;
+ private final boolean keepSubmittedReads;
+
+ private int totalReadStates = 0;
+
+ public ReadStateManager(final Iterator<GATKSAMRecord> source,
+ final List<String> samples,
+ final LIBSDownsamplingInfo LIBSDownsamplingInfo,
+ final boolean keepSubmittedReads) {
+ this.samples = samples;
+ this.iterator = new PeekableIterator<GATKSAMRecord>(source);
+
+ this.keepSubmittedReads = keepSubmittedReads;
+ this.submittedReads = new LinkedList<GATKSAMRecord>();
+
+ for (final String sample : samples) {
+ // because this is a linked hash map the order of iteration will be in sample order
+ readStatesBySample.put(sample, new PerSampleReadStateManager(LIBSDownsamplingInfo));
+ }
+
+ samplePartitioner = new SamplePartitioner<GATKSAMRecord>(LIBSDownsamplingInfo, samples);
+ }
+
+ /**
+ * Returns a iterator over all the sample -> per-sample read state managers with each sample in this read state manager.
+ *
+ * The order of iteration is the same as the order of the samples provided upon construction to this
+ * ReadStateManager.
+ *
+ * @return Iterator over sample + per sample read state manager pairs for this read state manager.
+ */
+ @Override
+ public Iterator<Map.Entry<String, PerSampleReadStateManager>> iterator() {
+ return readStatesBySample.entrySet().iterator();
+ }
+
+ public boolean isEmpty() {
+ return totalReadStates == 0;
+ }
+
+ /**
+ * Retrieves the total number of reads in the manager across all samples.
+ *
+ * @return Total number of reads over all samples.
+ */
+ public int size() {
+ return totalReadStates;
+ }
+
+ /**
+ * Retrieves the total number of reads in the manager in the given sample.
+ *
+ * @param sample The sample.
+ * @return Total number of reads in the given sample.
+ */
+ public int size(final String sample) {
+ return readStatesBySample.get(sample).size();
+ }
+
+ public AlignmentStateMachine getFirst() {
+ for ( final PerSampleReadStateManager manager : readStatesBySample.values() ) {
+ if ( ! manager.isEmpty() )
+ return manager.getFirst();
+ }
+ return null;
+ }
+
+ public boolean hasNext() {
+ return totalReadStates > 0 || iterator.hasNext();
+ }
+
+ /**
+ * Advances all fo the read states by one bp. After this call the read states are reflective
+ * of the next pileup.
+ */
+ public void updateReadStates() {
+ for (final PerSampleReadStateManager perSampleReadStateManager : readStatesBySample.values() ) {
+ totalReadStates -= perSampleReadStateManager.updateReadStates();
+ }
+ }
+
+ /**
+ * Does read start at the same position as described by currentContextIndex and currentAlignmentStart?
+ *
+ * @param read the read we want to test
+ * @param currentContigIndex the contig index (from the read's getReferenceIndex) of the reads in this state manager
+ * @param currentAlignmentStart the alignment start of the of the left-most position on the
+ * genome of the reads in this read state manager
+ * @return true if read has contig index and start equal to the current ones
+ */
+ private boolean readStartsAtCurrentPosition(final GATKSAMRecord read, final int currentContigIndex, final int currentAlignmentStart) {
+ return read.getAlignmentStart() == currentAlignmentStart && read.getReferenceIndex() == currentContigIndex;
+ }
+
+ /**
+ * Pull all of the reads off the iterator that overlap the left-most position among all
+ * reads this ReadStateManager
+ */
+ public void collectPendingReads() {
+ if (!iterator.hasNext())
+ return;
+
+ // determine the left-most boundary that determines which reads to keep in this new pileup
+ final int firstContigIndex;
+ final int firstAlignmentStart;
+ if ( isEmpty() ) {
+ // there are no reads here, so our next state is the next read in the stream
+ firstContigIndex = iterator.peek().getReferenceIndex();
+ firstAlignmentStart = iterator.peek().getAlignmentStart();
+ } else {
+ // there's a read in the system, so it's our targeted first read
+ final AlignmentStateMachine firstState = getFirst();
+ firstContigIndex = firstState.getReferenceIndex();
+ // note this isn't the alignment start of the read, but rather the alignment start position
+ firstAlignmentStart = firstState.getGenomePosition();
+ }
+
+ while ( iterator.hasNext() && readStartsAtCurrentPosition(iterator.peek(), firstContigIndex, firstAlignmentStart) ) {
+ submitRead(iterator.next());
+ }
+
+ samplePartitioner.doneSubmittingReads();
+
+ for (final String sample : samples) {
+ final Collection<GATKSAMRecord> newReads = samplePartitioner.getReadsForSample(sample);
+
+ // if we're keeping reads, take the (potentially downsampled) list of new reads for this sample
+ // and add to the list of reads. Note this may reorder the list of reads someone (it groups them
+ // by sample, but it cannot change their absolute position on the genome as they all must
+ // start at the current location
+ if ( keepSubmittedReads )
+ submittedReads.addAll(newReads);
+
+ final PerSampleReadStateManager statesBySample = readStatesBySample.get(sample);
+ addReadsToSample(statesBySample, newReads);
+ }
+
+ samplePartitioner.reset();
+ }
+
+ /**
+ * Add a read to the sample partitioner, potentially adding it to all submitted reads, if appropriate
+ * @param read a non-null read
+ */
+ @Requires("read != null")
+ protected void submitRead(final GATKSAMRecord read) {
+ samplePartitioner.submitRead(read);
+ }
+
+ /**
+ * Transfer current list of submitted reads, clearing old list
+ *
+ * Takes the maintained list of submitted reads, and transfers it to the caller of this
+ * function. The old list of set to a new, cleanly allocated list so the caller officially
+ * owns the list returned by this call. This is the only way to clear the tracking
+ * of submitted reads, if enabled.
+ *
+ * How to use this function:
+ *
+ * while ( doing some work unit, such as creating pileup at some locus ):
+ * interact with ReadStateManager in some way to make work unit
+ * readsUsedInPileup = transferSubmittedReads)
+ *
+ * @throws UnsupportedOperationException if called when keepSubmittedReads is false
+ *
+ * @return the current list of submitted reads
+ */
+ @Ensures({
+ "result != null",
+ "result != submittedReads" // result and previous submitted reads are not == objects
+ })
+ public List<GATKSAMRecord> transferSubmittedReads() {
+ if ( ! keepSubmittedReads ) throw new UnsupportedOperationException("cannot transferSubmittedReads if you aren't keeping them");
+
+ final List<GATKSAMRecord> prevSubmittedReads = submittedReads;
+ this.submittedReads = new LinkedList<GATKSAMRecord>();
+
+ return prevSubmittedReads;
+ }
+
+ /**
+ * Are we keeping submitted reads, or not?
+ * @return true if we are keeping them, false otherwise
+ */
+ public boolean isKeepingSubmittedReads() {
+ return keepSubmittedReads;
+ }
+
+ /**
+ * Obtain a pointer to the list of submitted reads.
+ *
+ * This is not a copy of the list; it is shared with this ReadStateManager. It should
+ * not be modified. Updates to this ReadStateManager may change the contains of the
+ * list entirely.
+ *
+ * For testing purposes only.
+ *
+ * Will always be empty if we are are not keepSubmittedReads
+ *
+ * @return a non-null list of reads that have been submitted to this ReadStateManager
+ */
+ @Ensures({"result != null","keepSubmittedReads || result.isEmpty()"})
+ protected List<GATKSAMRecord> getSubmittedReads() {
+ return submittedReads;
+ }
+
+ /**
+ * Add reads with the given sample name to the given hanger entry.
+ *
+ * @param readStates The list of read states to add this collection of reads.
+ * @param reads Reads to add. Selected reads will be pulled from this source.
+ */
+ private void addReadsToSample(final PerSampleReadStateManager readStates, final Collection<GATKSAMRecord> reads) {
+ if (reads.isEmpty())
+ return;
+
+ final LinkedList<AlignmentStateMachine> newReadStates = new LinkedList<AlignmentStateMachine>();
+
+ for (final GATKSAMRecord read : reads) {
+ final AlignmentStateMachine state = new AlignmentStateMachine(read);
+ if ( state.stepForwardOnGenome() != null ) // todo -- should be an assertion not a skip
+ // explicitly filter out reads that are all insertions / soft clips
+ newReadStates.add(state);
+ }
+
+ totalReadStates += readStates.addStatesAtNextAlignmentStart(newReadStates);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/SamplePartitioner.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/SamplePartitioner.java
new file mode 100644
index 0000000..825cb35
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/locusiterator/SamplePartitioner.java
@@ -0,0 +1,172 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.downsampling.Downsampler;
+import org.broadinstitute.gatk.engine.downsampling.PassThroughDownsampler;
+import org.broadinstitute.gatk.engine.downsampling.ReservoirDownsampler;
+
+import java.util.*;
+
+/**
+ * Divides reads by sample and (if requested) does a preliminary downsampling pass
+ * with a ReservoirDownsampler.
+ *
+ * Note: stores reads by sample ID string, not by sample object
+ */
+class SamplePartitioner<T extends SAMRecord> {
+ /**
+ * Map from sample name (as a string) to a downsampler of reads for that sample
+ */
+ final private Map<String, Downsampler<T>> readsBySample;
+
+ /**
+ * Are we in a state where we're done submitting reads and have semi-finalized the
+ * underlying per sample downsampler?
+ */
+ boolean doneSubmittingReads = false;
+
+ /**
+ * Create a new SamplePartitioner capable of splitting reads up into buckets of reads for
+ * each sample in samples, and perform a preliminary downsampling of these reads
+ * (separately for each sample) if downsampling is requested in LIBSDownsamplingInfo
+ *
+ * Note that samples must be comprehensive, in that all reads every submitted to this
+ * partitioner must come from one of the samples provided here. If not, submitRead
+ * will throw an exception. Duplicates in the list of samples will be ignored
+ *
+ * @param LIBSDownsamplingInfo do we want to downsample, and if so to what coverage?
+ * @param samples the complete list of samples we're going to partition reads into. Can be
+ * empty, but in that case this code cannot function properly if you
+ * attempt to add data to it.
+ */
+ @Ensures({
+ "readsBySample != null",
+ "readsBySample.size() == new HashSet(samples).size()"
+ })
+ public SamplePartitioner(final LIBSDownsamplingInfo LIBSDownsamplingInfo, final List<String> samples) {
+ if ( LIBSDownsamplingInfo == null ) throw new IllegalArgumentException("LIBSDownsamplingInfo cannot be null");
+ if ( samples == null ) throw new IllegalArgumentException("samples must be a non-null list");
+
+ readsBySample = new LinkedHashMap<String, Downsampler<T>>(samples.size());
+ for ( final String sample : samples ) {
+ readsBySample.put(sample, createDownsampler(LIBSDownsamplingInfo));
+ }
+ }
+
+ /**
+ * Create a new, ready to use downsampler based on the parameters in LIBSDownsamplingInfo
+ * @param LIBSDownsamplingInfo the parameters to use in creating the downsampler
+ * @return a downsampler appropriate for LIBSDownsamplingInfo. If no downsampling is requested,
+ * uses the PassThroughDownsampler, which does nothing at all.
+ */
+ @Requires("LIBSDownsamplingInfo != null")
+ @Ensures("result != null")
+ private Downsampler<T> createDownsampler(final LIBSDownsamplingInfo LIBSDownsamplingInfo) {
+ return LIBSDownsamplingInfo.isPerformDownsampling()
+ ? new ReservoirDownsampler<T>(LIBSDownsamplingInfo.getToCoverage(), true)
+ : new PassThroughDownsampler<T>();
+ }
+
+ /**
+ * Offer this read to the partitioner, putting it into the bucket of reads for the sample
+ * of read (obtained via the read's read group).
+ *
+ * If the read group is missing, uses the special "null" read group
+ *
+ * @throws IllegalStateException if the sample of read wasn't present in the original
+ * set of samples provided to this SamplePartitioner at construction
+ *
+ * @param read the read to add to the sample's list of reads
+ */
+ @Requires("read != null")
+ @Ensures("doneSubmittingReads == false")
+ public void submitRead(final T read) {
+ final String sampleName = read.getReadGroup() != null ? read.getReadGroup().getSample() : null;
+ final Downsampler<T> downsampler = readsBySample.get(sampleName);
+ if ( downsampler == null )
+ throw new IllegalStateException("Offered read with sample name " + sampleName + " to SamplePartitioner " +
+ "but this sample wasn't provided as one of possible samples at construction");
+
+ downsampler.submit(read);
+ doneSubmittingReads = false;
+ }
+
+ /**
+ * Tell this partitioner that all reads in this cycle have been submitted, so that we
+ * can finalize whatever downsampling is required by each sample.
+ *
+ * Note that we *must* call this function before getReadsForSample, or else that
+ * function will exception out.
+ */
+ @Ensures("doneSubmittingReads == true")
+ public void doneSubmittingReads() {
+ for ( final Downsampler<T> downsampler : readsBySample.values() ) {
+ downsampler.signalEndOfInput();
+ }
+ doneSubmittingReads = true;
+ }
+
+ /**
+ * Get the final collection of reads for this sample for this cycle
+ *
+ * The cycle is defined as all of the reads that occur between
+ * the first call to submitRead until doneSubmittingReads is called. At that
+ * point additional downsampling may occur (depending on construction arguments)
+ * and that set of reads is returned here.
+ *
+ * Note that this function can only be called once per cycle, as underlying
+ * collection of reads is cleared.
+ *
+ * @param sampleName the sample we want reads for, must be present in the original samples
+ * @return a non-null collection of reads for sample in this cycle
+ */
+ @Ensures("result != null")
+ public Collection<T> getReadsForSample(final String sampleName) {
+ if ( ! doneSubmittingReads ) throw new IllegalStateException("getReadsForSample called before doneSubmittingReads was called");
+
+ final Downsampler<T> downsampler = readsBySample.get(sampleName);
+ if ( downsampler == null ) throw new NoSuchElementException("Sample name not found");
+
+ return downsampler.consumeFinalizedItems();
+ }
+
+ /**
+ * Resets this SamplePartitioner, indicating that we're starting a new
+ * cycle of adding reads to each underlying downsampler.
+ */
+ @Ensures("doneSubmittingReads == false")
+ public void reset() {
+ for ( final Downsampler<T> downsampler : readsBySample.values() ) {
+ downsampler.clearItems();
+ downsampler.resetStats();
+ }
+ doneSubmittingReads = false;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/EOFMarkedValue.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/EOFMarkedValue.java
new file mode 100644
index 0000000..c5255e4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/EOFMarkedValue.java
@@ -0,0 +1,105 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+/**
+ * Wrapper to hold data that distinguishing an special EOF marker from a real object
+ *
+ * The only way to tell in a consumer thread that a blocking queue has no more data ever
+ * coming down the pipe is to pass in a "poison" or EOF object. This class provides
+ * a generic capacity for that...
+ *
+ * The use case looks like this:
+ *
+ * BlockingQueue q
+ * producer:
+ * while ( x has items )
+ * q.put(new EOFMarkedValue(x))
+ * q.put(new EOFMarkedValue())
+ *
+ * Consumer:
+ * while ( true )
+ * value = q.take()
+ * if ( value.isEOFMarker() )
+ * break
+ * else
+ * do something useful with value
+ *
+ *
+ * User: depristo
+ * Date: 9/6/12
+ * Time: 3:08 PM
+ */
+//@Invariant("! isEOFMarker() || value == null")
+class EOFMarkedValue<T> {
+ /**
+ * True if this is the EOF marker object
+ */
+ final private boolean isLast;
+
+ /**
+ * Our value, if we aren't the EOF marker
+ */
+ final private T value;
+
+ /**
+ * Create a new EOFMarkedValue containing a real value, where last is false
+ * @param value
+ */
+ EOFMarkedValue(final T value) {
+ isLast = false;
+ this.value = value;
+ }
+
+ /**
+ * Create a new EOFMarkedValue that is the last item
+ */
+ EOFMarkedValue() {
+ isLast = true;
+ this.value = null;
+ }
+
+ /**
+ * Is this the EOF marker?
+ *
+ * @return true if so, else false
+ */
+ public boolean isEOFMarker() {
+ return isLast;
+ }
+
+ /**
+ * Get the value held by this EOFMarkedValue
+ *
+ * @return the value
+ * @throws IllegalStateException if this is the last item
+ */
+ public T getValue() {
+ if ( isEOFMarker() )
+ throw new IllegalStateException("Cannot get value for last object");
+ return value;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/InputProducer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/InputProducer.java
new file mode 100644
index 0000000..3a67b43
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/InputProducer.java
@@ -0,0 +1,217 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+import org.apache.log4j.Logger;
+
+import java.util.Iterator;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Helper class that allows multiple threads to reads input values from
+ * an iterator, and track the number of items read from that iterator.
+ */
+class InputProducer<InputType> {
+ private final static Logger logger = Logger.getLogger(InputProducer.class);
+
+ /**
+ * The iterator we are using to get data from
+ */
+ final Iterator<InputType> inputReader;
+
+ /**
+ * Have we read the last value from inputReader?
+ *
+ * Must be a local variable, as inputReader.hasNext() can actually end up doing a lot
+ * of work, and the method getNumInputValues() is supposed to be called not in the
+ * thread executing the reading of values but in the thread enqueuing results
+ */
+ boolean readLastValue = false;
+
+ /**
+ * Once we've readLastValue, lastValue contains a continually
+ * updating InputValue where EOF is true. It's not necessarily
+ * a single value, as each read updates lastValue with the
+ * next EOF marker
+ */
+ private InputValue lastValue = null;
+
+ int nRead = 0;
+ int inputID = -1;
+
+ public InputProducer(final Iterator<InputType> inputReader) {
+ if ( inputReader == null ) throw new IllegalArgumentException("inputReader cannot be null");
+ this.inputReader = inputReader;
+ }
+
+ /**
+ * Returns the number of elements in the input stream, AFTER we've read all of the values.
+ * If we haven't read them all yet, returns -1
+ *
+ * @return the total number of elements in input stream, or -1 if some are still to be read
+ */
+ public synchronized int getNumInputValues() {
+ return allInputsHaveBeenRead() ? nRead : -1;
+ }
+
+ /**
+ * Returns true if all of the elements have been read from the input stream
+ *
+ * @return true if all of the elements have been read from the input stream
+ */
+ public synchronized boolean allInputsHaveBeenRead() {
+ return readLastValue;
+ }
+
+ /**
+ * Read the next item from the input stream, if possible
+ *
+ * If the inputReader has values, returns them, otherwise return null.
+ *
+ * This method is synchronized, as it manipulates local state accessed across multiple threads.
+ *
+ * @return the next input stream value, or null if the stream contains no more elements
+ */
+ private synchronized InputType readNextItem() {
+ if ( ! inputReader.hasNext() ) {
+ // we are done, mark ourselves as such and return null
+ readLastValue = true;
+ return null;
+ } else {
+ // get the next value, and return it
+ final InputType input = inputReader.next();
+ if ( input == null )
+ throw new IllegalStateException("inputReader.next() returned a null value, breaking our contract");
+ nRead++;
+ return input;
+ }
+ }
+
+ /**
+ * Are there currently more values in the iterator?
+ *
+ * Note the word currently. It's possible that some already submitted
+ * job will read a value from this InputProvider, so in some sense
+ * there are no more values and in the future there'll be no next
+ * value. That said, once this returns false it means that all
+ * of the possible values have been read
+ *
+ * @return true if a future call to next might return a non-EOF value, false if
+ * the underlying iterator is definitely empty
+ */
+ public synchronized boolean hasNext() {
+ return ! allInputsHaveBeenRead();
+ }
+
+ /**
+ * Get the next InputValue from this producer. The next value is
+ * either (1) the next value from the iterator, in which case the
+ * the return value is an InputValue containing that value, or (2)
+ * an InputValue with the EOF marker, indicating that the underlying
+ * iterator has been exhausted.
+ *
+ * This function never fails -- it can be called endlessly and
+ * while the underlying iterator has values it returns them, and then
+ * it returns a succession of EOF marking input values.
+ *
+ * @return an InputValue containing the next value in the underlying
+ * iterator, or one with EOF marker, if the iterator is exhausted
+ */
+ public synchronized InputValue next() {
+ if ( readLastValue ) {
+ // we read the last value, so our value is the next
+ // EOF marker based on the last value. Make sure to
+ // update the last value so the markers keep incrementing
+ // their job ids
+ lastValue = lastValue.nextEOF();
+ return lastValue;
+ } else {
+ final InputType value = readNextItem();
+
+ if ( value == null ) {
+ if ( ! readLastValue )
+ throw new IllegalStateException("value == null but readLastValue is false!");
+
+ // add the EOF object so our consumer knows we are done in all inputs
+ // note that we do not increase inputID here, so that variable indicates the ID
+ // of the last real value read from the queue
+ lastValue = new InputValue(inputID + 1);
+ return lastValue;
+ } else {
+ // add the actual value to the outputQueue
+ return new InputValue(++inputID, value);
+ }
+ }
+ }
+
+ /**
+ * Helper class that contains a read value suitable for EOF marking in a BlockingQueue
+ *
+ * This class also contains an ID, an integer incrementing from 0 to N, for N total
+ * values in the input stream. This ID indicates which element in the element stream this
+ * InputValue corresponds to. Necessary for tracking and ordering results by input position.
+ *
+ * Note that EOF markers have IDs > N, and ID values >> N can occur if many EOF markers
+ * are enqueued in the outputQueue.
+ */
+ class InputValue extends EOFMarkedValue<InputType> {
+ final int id;
+
+ private InputValue(final int id, InputType datum) {
+ super(datum);
+ if ( id < 0 ) throw new IllegalArgumentException("id must be >= 0");
+ this.id = id;
+ }
+ private InputValue(final int id) {
+ super();
+ if ( id < 0 ) throw new IllegalArgumentException("id must be >= 0");
+ this.id = id;
+ }
+
+ /**
+ * Returns the ID of this input marker
+ * @return id >= 0
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Create another EOF marker with ID + 1 to this one.
+ *
+ * Useful in the case where we need to enqueue another EOF marker for future jobs and we
+ * want them to have a meaningful ID, one greater than the last one.
+ *
+ * @return ID
+ */
+ //@Ensures({"result.isEOFMarker()", "result.getId() == getId() + 1"})
+ public InputValue nextEOF() {
+ if ( ! isEOFMarker() )
+ throw new IllegalArgumentException("Cannot request next EOF marker for non-EOF marker InputValue");
+ return new InputValue(getId() + 1);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/MapResult.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/MapResult.java
new file mode 100644
index 0000000..d6628a5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/MapResult.java
@@ -0,0 +1,75 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+/**
+ * Holds the results of a map job suitable for producer/consumer threading
+ * via a BlockingQueue
+ */
+class MapResult<MapType> extends EOFMarkedValue<MapType> implements Comparable<MapResult<MapType>> {
+ final int jobID;
+
+ /**
+ * Create a new MapResult with value datum and jod jobID ID
+ *
+ * @param datum the value produced by the map job
+ * @param jobID the id of the map job (for correctness testing)
+ */
+ MapResult(final MapType datum, final int jobID) {
+ super(datum);
+ this.jobID = jobID;
+ if ( jobID < 0 ) throw new IllegalArgumentException("JobID must be >= 0");
+ }
+
+ MapResult(final int jobID) {
+ super();
+ this.jobID = jobID;
+ if ( jobID < 0 ) throw new IllegalArgumentException("JobID must be >= 0");
+ }
+
+ /**
+ * @return the job ID of the map job that produced this MapResult
+ */
+ public int getJobID() {
+ return jobID;
+ }
+
+ /**
+ * Compare these MapResults in order of JobID.
+ *
+ * @param o
+ * @return
+ */
+ @Override
+ public int compareTo(MapResult<MapType> o) {
+ return Integer.valueOf(jobID).compareTo(o.getJobID());
+ }
+
+ @Override
+ public String toString() {
+ return "[MapResult id=" + jobID + "]";
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/MapResultsQueue.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/MapResultsQueue.java
new file mode 100644
index 0000000..afeafb5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/MapResultsQueue.java
@@ -0,0 +1,116 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+import org.broadinstitute.gatk.utils.collections.ExpandingArrayList;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: depristo
+ * Date: 12/19/12
+ * Time: 3:53 PM
+ *
+ * This class makes some critical assumptions. First is that the jobID of the first
+ * job is 0. If this isn't true the MapResultsQueue will certainly fail.
+ */
+public class MapResultsQueue<MapType> {
+ //private final static boolean DEBUG = false;
+ //private final static Logger logger = Logger.getLogger(MapResultsQueue.class);
+
+ /**
+ * Although naturally stored as priority blocking queue, this is actually quite expensive
+ * due to the O(n log n) sorting calculation. Since we know that the job ids start
+ * at 0 and increment by 1 in each successive job, we store an array instead. The
+ * array is indexed by jobID, and contains the MapResult for that job id. Because elements
+ * can be added to the queue in any order, we need to use an expanding array list to
+ * store the elements.
+ */
+ final ExpandingArrayList<MapResult<MapType>> queue = new ExpandingArrayList<MapResult<MapType>>(10000);
+
+ /**
+ * The jobID of the last job we've seen
+ */
+ int prevJobID = -1; // no jobs observed
+
+ /**
+ * Put mapResult into this MapResultsQueue, associated with its jobID
+ * @param mapResult a non-null map result
+ */
+ public synchronized void put(final MapResult<MapType> mapResult) {
+ if ( mapResult == null ) throw new IllegalArgumentException("mapResult cannot be null");
+
+ // make sure that nothing is at the job id for map
+ assert queue.size() < mapResult.getJobID() || queue.get(mapResult.getJobID()) == null;
+
+ queue.set(mapResult.getJobID(), mapResult);
+ }
+
+ /**
+ * Should we reduce the next value in the mapResultQueue?
+ *
+ * @return true if we should reduce
+ */
+ public synchronized boolean nextValueIsAvailable() {
+ final MapResult<MapType> nextMapResult = queue.get(nextJobID());
+
+ if ( nextMapResult == null ) {
+ // natural case -- the next job hasn't had a value added yet
+ return false;
+ } else if ( nextMapResult.getJobID() != nextJobID() ) {
+ // sanity check -- the job id at next isn't the one we expect
+ throw new IllegalStateException("Next job ID " + nextMapResult.getJobID() + " is not == previous job id " + prevJobID + " + 1");
+ } else {
+ // there's a value at the next job id, so return true
+ return true;
+ }
+ }
+
+ /**
+ * Get the next job ID'd be expect to see given our previous job id
+ * @return the next job id we'd fetch to reduce
+ */
+ private int nextJobID() {
+ return prevJobID + 1;
+ }
+
+ /**
+ * Can only be called when nextValueIsAvailable is true
+ * @return
+ * @throws InterruptedException
+ */
+ // TODO -- does this have to be synchronized? -- I think the answer is no
+ public synchronized MapResult<MapType> take() throws InterruptedException {
+ final MapResult<MapType> result = queue.get(nextJobID());
+
+ // make sure the value we've fetched has the right id
+ assert result.getJobID() == nextJobID();
+
+ prevJobID = result.getJobID();
+ queue.set(prevJobID, null);
+
+ return result;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NSMapFunction.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NSMapFunction.java
new file mode 100644
index 0000000..dbd58b4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NSMapFunction.java
@@ -0,0 +1,44 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+/**
+ * A function that maps from InputType -> ResultType
+ *
+ * For use with the NanoScheduler
+ *
+ * User: depristo
+ * Date: 8/24/12
+ * Time: 9:49 AM
+ */
+public interface NSMapFunction<InputType, ResultType> {
+ /**
+ * Return function on input, returning a value of ResultType
+ * @param input
+ * @return
+ */
+ public ResultType apply(final InputType input);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NSProgressFunction.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NSProgressFunction.java
new file mode 100644
index 0000000..27d713e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NSProgressFunction.java
@@ -0,0 +1,37 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: depristo
+ * Date: 9/4/12
+ * Time: 2:10 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface NSProgressFunction<InputType> {
+ public void progress(final InputType lastMapInput);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NSReduceFunction.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NSReduceFunction.java
new file mode 100644
index 0000000..acb0a78
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NSReduceFunction.java
@@ -0,0 +1,43 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+/**
+ * A function that combines a value of MapType with an existing ReduceValue into a new ResultType
+ *
+ * User: depristo
+ * Date: 8/24/12
+ * Time: 9:49 AM
+ */
+public interface NSReduceFunction<MapType, ReduceType> {
+ /**
+ * Combine one with sum into a new ReduceType
+ * @param one the result of a map call on an input element
+ * @param sum the cumulative reduce result over all previous map calls
+ * @return
+ */
+ public ReduceType apply(MapType one, ReduceType sum);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NanoScheduler.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NanoScheduler.java
new file mode 100644
index 0000000..8b02721
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/NanoScheduler.java
@@ -0,0 +1,494 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.MultiThreadedErrorTracker;
+import org.broadinstitute.gatk.utils.threading.NamedThreadFactory;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * Framework for very fine grained MapReduce parallelism
+ *
+ * The overall framework works like this
+ *
+ * nano <- new Nanoschedule(bufferSize, numberOfMapElementsToProcessTogether, nThreads)
+ * List[Input] outerData : outerDataLoop )
+ * result = nano.execute(outerData.iterator(), map, reduce)
+ *
+ * bufferSize determines how many elements from the input stream are read in one go by the
+ * nanoscheduler. The scheduler may hold up to bufferSize in memory at one time, as well
+ * as up to bufferSize map results as well.
+ *
+ * numberOfMapElementsToProcessTogether determines how many input elements are processed
+ * together each thread cycle. For example, if this value is 10, then the input data
+ * is grouped together in units of 10 elements each, and map called on each in term. The more
+ * heavy-weight the map function is, in terms of CPU costs, the more it makes sense to
+ * have this number be small. The lighter the CPU cost per element, though, the more this
+ * parameter introduces overhead due to need to context switch among threads to process
+ * each input element. A value of -1 lets the nanoscheduler guess at a reasonable trade-off value.
+ *
+ * nThreads is a bit obvious yes? Note though that the nanoscheduler assumes that it gets 1 thread
+ * from its client during the execute call, as this call blocks until all work is done. The caller
+ * thread is put to work by execute to help with the processing of the data. So in reality the
+ * nanoScheduler only spawn nThreads - 1 additional workers (if this is > 1).
+ *
+ * User: depristo
+ * Date: 8/24/12
+ * Time: 9:47 AM
+ */
+public class NanoScheduler<InputType, MapType, ReduceType> {
+ private final static Logger logger = Logger.getLogger(NanoScheduler.class);
+ private final static boolean ALLOW_SINGLE_THREAD_FASTPATH = true;
+ protected final static int UPDATE_PROGRESS_FREQ = 100;
+
+ /**
+ * Currently not used, but kept because it's conceptual reasonable to have a buffer
+ */
+ final int bufferSize;
+
+ /**
+ * The number of threads we're using to execute the map jobs in this nano scheduler
+ */
+ final int nThreads;
+
+ final ExecutorService masterExecutor;
+ final ExecutorService mapExecutor;
+ final MultiThreadedErrorTracker errorTracker = new MultiThreadedErrorTracker();
+
+ boolean shutdown = false;
+ boolean debug = false;
+ private NSProgressFunction<InputType> progressFunction = null;
+
+ /**
+ * Create a new nanoscheduler with the desire characteristics requested by the argument
+ *
+ * @param nThreads the number of threads to use to get work done, in addition to the
+ * thread calling execute
+ */
+ public NanoScheduler(final int nThreads) {
+ this(nThreads*100, nThreads);
+ }
+
+ protected NanoScheduler(final int bufferSize, final int nThreads) {
+ if ( bufferSize < 1 ) throw new IllegalArgumentException("bufferSize must be >= 1, got " + bufferSize);
+ if ( nThreads < 1 ) throw new IllegalArgumentException("nThreads must be >= 1, got " + nThreads);
+
+ this.bufferSize = bufferSize;
+ this.nThreads = nThreads;
+
+ if ( nThreads == 1 ) {
+ this.mapExecutor = this.masterExecutor = null;
+ } else {
+ this.masterExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("NS-master-thread-%d"));
+ this.mapExecutor = Executors.newFixedThreadPool(nThreads, new NamedThreadFactory("NS-map-thread-%d"));
+ }
+ }
+
+ /**
+ * The number of parallel map threads in use with this NanoScheduler
+ * @return
+ */
+ @Ensures("result > 0")
+ public int getnThreads() {
+ return nThreads;
+ }
+
+ /**
+ * The input buffer size used by this NanoScheduler
+ * @return
+ */
+ @Ensures("result > 0")
+ public int getBufferSize() {
+ return this.bufferSize;
+ }
+
+ /**
+ * Tells this nanoScheduler to shutdown immediately, releasing all its resources.
+ *
+ * After this call, execute cannot be invoked without throwing an error
+ */
+ public void shutdown() {
+ if ( nThreads > 1 ) {
+ shutdownExecutor("mapExecutor", mapExecutor);
+ shutdownExecutor("masterExecutor", masterExecutor);
+ }
+
+ shutdown = true;
+ }
+
+ /**
+ * Helper function to cleanly shutdown an execution service, checking that the execution
+ * state is clean when it's done.
+ *
+ * @param name a string name for error messages for the executorService we are shutting down
+ * @param executorService the executorService to shut down
+ */
+ @Requires({"name != null", "executorService != null"})
+ @Ensures("executorService.isShutdown()")
+ private void shutdownExecutor(final String name, final ExecutorService executorService) {
+ if ( executorService.isShutdown() || executorService.isTerminated() )
+ throw new IllegalStateException("Executor service " + name + " is already shut down!");
+
+ final List<Runnable> remaining = executorService.shutdownNow();
+ if ( ! remaining.isEmpty() )
+ throw new IllegalStateException(remaining.size() + " remaining tasks found in an executor " + name + ", unexpected behavior!");
+ }
+
+ /**
+ * @return true if this nanoScheduler is shutdown, or false if its still open for business
+ */
+ public boolean isShutdown() {
+ return shutdown;
+ }
+
+ /**
+ * @return are we displaying verbose debugging information about the scheduling?
+ */
+ public boolean isDebug() {
+ return debug;
+ }
+
+ /**
+ * Helper function to display a String.formatted message if we are doing verbose debugging
+ *
+ * @param format the format argument suitable for String.format
+ * @param args the arguments for String.format
+ */
+ @Requires("format != null")
+ protected void debugPrint(final String format, Object ... args) {
+ if ( isDebug() )
+ logger.warn("Thread " + Thread.currentThread().getId() + ":" + String.format(format, args));
+ }
+
+ /**
+ * Turn on/off verbose debugging
+ *
+ * @param debug true if we want verbose debugging
+ */
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ /**
+ * Set the progress callback function to progressFunction
+ *
+ * The progress callback is invoked after each buffer size elements have been processed by map/reduce
+ *
+ * @param progressFunction a progress function to call, or null if you don't want any progress callback
+ */
+ public void setProgressFunction(final NSProgressFunction<InputType> progressFunction) {
+ this.progressFunction = progressFunction;
+ }
+
+ /**
+ * Execute a map/reduce job with this nanoScheduler
+ *
+ * Data comes from inputReader. Will be read until hasNext() == false.
+ * map is called on each element provided by inputReader. No order of operations is guarenteed
+ * reduce is called in order of the input data provided by inputReader on the result of map() applied
+ * to each element.
+ *
+ * Note that the caller thread is put to work with this function call. The call doesn't return
+ * until all elements have been processes.
+ *
+ * It is safe to call this function repeatedly on a single nanoScheduler, at least until the
+ * shutdown method is called.
+ *
+ * Note that this function goes through a single threaded fast path if the number of threads
+ * is 1.
+ *
+ * @param inputReader an iterator providing us with the input data to nanoSchedule map/reduce over
+ * @param map the map function from input type -> map type, will be applied in parallel to each input
+ * @param reduce the reduce function from map type + reduce type -> reduce type to be applied in order to map results
+ * @return the last reduce value
+ */
+ public ReduceType execute(final Iterator<InputType> inputReader,
+ final NSMapFunction<InputType, MapType> map,
+ final ReduceType initialValue,
+ final NSReduceFunction<MapType, ReduceType> reduce) {
+ if ( isShutdown() ) throw new IllegalStateException("execute called on already shutdown NanoScheduler");
+ if ( inputReader == null ) throw new IllegalArgumentException("inputReader cannot be null");
+ if ( map == null ) throw new IllegalArgumentException("map function cannot be null");
+ if ( reduce == null ) throw new IllegalArgumentException("reduce function cannot be null");
+
+ ReduceType result;
+ if ( ALLOW_SINGLE_THREAD_FASTPATH && getnThreads() == 1 ) {
+ result = executeSingleThreaded(inputReader, map, initialValue, reduce);
+ } else {
+ result = executeMultiThreaded(inputReader, map, initialValue, reduce);
+ }
+
+ return result;
+ }
+
+ /**
+ * Simple efficient reference implementation for single threaded execution.
+ *
+ * @return the reduce result of this map/reduce job
+ */
+ @Requires({"inputReader != null", "map != null", "reduce != null"})
+ private ReduceType executeSingleThreaded(final Iterator<InputType> inputReader,
+ final NSMapFunction<InputType, MapType> map,
+ final ReduceType initialValue,
+ final NSReduceFunction<MapType, ReduceType> reduce) {
+ ReduceType sum = initialValue;
+ int i = 0;
+
+ while ( true ) {
+ // start timer to ensure that both hasNext and next are caught by the timer
+ if ( ! inputReader.hasNext() ) {
+ break;
+ } else {
+ final InputType input = inputReader.next();
+
+ // map
+ final MapType mapValue = map.apply(input);
+
+ updateProgress(i++, input);
+
+ // reduce
+ sum = reduce.apply(mapValue, sum);
+ }
+ }
+
+ return sum;
+ }
+
+ /**
+ * Maybe update the progress meter (maybe because we don't want to do so so often that it costs cpu time)
+ * @param counter increasing counter to use to cut down on updates
+ * @param input the input we're currently at
+ */
+ private void updateProgress(final int counter, final InputType input) {
+ if ( progressFunction != null && counter % UPDATE_PROGRESS_FREQ == 0 )
+ progressFunction.progress(input);
+ }
+
+ /**
+ * Efficient parallel version of Map/Reduce
+ *
+ * @return the reduce result of this map/reduce job
+ */
+ @Requires({"inputReader != null", "map != null", "reduce != null"})
+ private ReduceType executeMultiThreaded(final Iterator<InputType> inputReader,
+ final NSMapFunction<InputType, MapType> map,
+ final ReduceType initialValue,
+ final NSReduceFunction<MapType, ReduceType> reduce) {
+ debugPrint("Executing nanoScheduler");
+
+ // start up the master job
+ final MasterJob masterJob = new MasterJob(inputReader, map, initialValue, reduce);
+ final Future<ReduceType> reduceResult = masterExecutor.submit(masterJob);
+
+ while ( true ) {
+ // check that no errors occurred while we were waiting
+ handleErrors();
+// checkForDeadlocks();
+
+ try {
+ final ReduceType result = reduceResult.get(100, TimeUnit.MILLISECONDS);
+
+ // in case an error occurred in the reduce
+ handleErrors();
+
+ // return our final reduce result
+ return result;
+ } catch (final TimeoutException ex ) {
+ // a normal case -- we just aren't done
+ } catch (final InterruptedException ex) {
+ errorTracker.notifyOfError(ex);
+ // will handle error in the next round of the for loop
+ } catch (final ExecutionException ex) {
+ errorTracker.notifyOfError(ex);
+ // will handle error in the next round of the for loop
+ }
+ }
+ }
+
+// private void checkForDeadlocks() {
+// if ( deadLockCheckCounter++ % 100 == 0 ) {
+// logger.info("Checking for deadlocks...");
+// final ThreadMXBean bean = ManagementFactory.getThreadMXBean();
+// final long[] threadIds = bean.findDeadlockedThreads(); // Returns null if no threads are deadlocked.
+//
+// if (threadIds != null) {
+// final ThreadInfo[] infos = bean.getThreadInfo(threadIds);
+//
+// logger.error("!!! Deadlock detected !!!!");
+// for (final ThreadInfo info : infos) {
+// logger.error("Thread " + info);
+// for ( final StackTraceElement elt : info.getStackTrace() ) {
+// logger.error("\t" + elt.toString());
+// }
+// }
+// }
+// }
+// }
+
+ private void handleErrors() {
+ if ( errorTracker.hasAnErrorOccurred() ) {
+ masterExecutor.shutdownNow();
+ mapExecutor.shutdownNow();
+ errorTracker.throwErrorIfPending();
+ }
+ }
+
+ /**
+ * MasterJob has the task to enqueue Map jobs and wait for the final reduce
+ *
+ * It must be run in a separate thread in order to properly handle errors that may occur
+ * in the input, map, or reduce jobs without deadlocking.
+ *
+ * The result of this callable is the final reduce value for the input / map / reduce jobs
+ */
+ private class MasterJob implements Callable<ReduceType> {
+ final Iterator<InputType> inputReader;
+ final NSMapFunction<InputType, MapType> map;
+ final ReduceType initialValue;
+ final NSReduceFunction<MapType, ReduceType> reduce;
+
+ private MasterJob(Iterator<InputType> inputReader, NSMapFunction<InputType, MapType> map, ReduceType initialValue, NSReduceFunction<MapType, ReduceType> reduce) {
+ this.inputReader = inputReader;
+ this.map = map;
+ this.initialValue = initialValue;
+ this.reduce = reduce;
+ }
+
+ @Override
+ public ReduceType call() {
+ // Create the input producer and start it running
+ final InputProducer<InputType> inputProducer = new InputProducer<InputType>(inputReader);
+
+ // create the MapResultsQueue to store results of map jobs.
+ final MapResultsQueue<MapType> mapResultQueue = new MapResultsQueue<MapType>();
+
+ // create the reducer we'll use for this nano scheduling run
+ final Reducer<MapType, ReduceType> reducer = new Reducer<MapType, ReduceType>(reduce, errorTracker, initialValue);
+
+ final CountDownLatch runningMapJobs = new CountDownLatch(nThreads);
+
+ try {
+ // create and submit the info needed by the read/map/reduce threads to do their work
+ for ( int i = 0; i < nThreads; i++ ) {
+ mapExecutor.submit(new ReadMapReduceJob(inputProducer, mapResultQueue, runningMapJobs, map, reducer));
+ }
+
+ // wait for all of the input and map threads to finish
+ return waitForCompletion(mapResultQueue, runningMapJobs, reducer);
+ } catch (Throwable ex) {
+ errorTracker.notifyOfError(ex);
+ return initialValue;
+ }
+ }
+
+ /**
+ * Wait until the input thread and all map threads have completed running, and return the final reduce result
+ */
+ private ReduceType waitForCompletion(final MapResultsQueue<MapType> mapResultsQueue,
+ final CountDownLatch runningMapJobs,
+ final Reducer<MapType, ReduceType> reducer) throws InterruptedException {
+ // wait for all the map threads to finish by waiting on the runningMapJobs latch
+ runningMapJobs.await();
+
+ // do a final reduce here. This is critically important because the InputMapReduce jobs
+ // no longer block on reducing, so it's possible for all the threads to end with a few
+ // reduce jobs on the queue still to do. This call ensures that we reduce everything
+ reducer.reduceAsMuchAsPossible(mapResultsQueue, true);
+
+ // wait until we have a final reduce result
+ final ReduceType finalSum = reducer.getReduceResult();
+
+ // everything is finally shutdown, return the final reduce value
+ return finalSum;
+ }
+ }
+
+ private class ReadMapReduceJob implements Runnable {
+ final InputProducer<InputType> inputProducer;
+ final MapResultsQueue<MapType> mapResultQueue;
+ final NSMapFunction<InputType, MapType> map;
+ final Reducer<MapType, ReduceType> reducer;
+ final CountDownLatch runningMapJobs;
+
+ private ReadMapReduceJob(final InputProducer<InputType> inputProducer,
+ final MapResultsQueue<MapType> mapResultQueue,
+ final CountDownLatch runningMapJobs,
+ final NSMapFunction<InputType, MapType> map,
+ final Reducer<MapType, ReduceType> reducer) {
+ this.inputProducer = inputProducer;
+ this.mapResultQueue = mapResultQueue;
+ this.runningMapJobs = runningMapJobs;
+ this.map = map;
+ this.reducer = reducer;
+ }
+
+ @Override
+ public void run() {
+ try {
+ boolean done = false;
+ while ( ! done ) {
+ // get the next item from the input producer
+ final InputProducer<InputType>.InputValue inputWrapper = inputProducer.next();
+
+ // depending on inputWrapper, actually do some work or not, putting result input result object
+ final MapResult<MapType> result;
+ if ( ! inputWrapper.isEOFMarker() ) {
+ // just skip doing anything if we don't have work to do, which is possible
+ // because we don't necessarily know how much input there is when we queue
+ // up our jobs
+ final InputType input = inputWrapper.getValue();
+
+ // actually execute the map
+ final MapType mapValue = map.apply(input);
+
+ // enqueue the result into the mapResultQueue
+ result = new MapResult<MapType>(mapValue, inputWrapper.getId());
+
+ mapResultQueue.put(result);
+
+ // reduce as much as possible, without blocking, if another thread is already doing reduces
+ final int nReduced = reducer.reduceAsMuchAsPossible(mapResultQueue, false);
+
+ updateProgress(inputWrapper.getId(), input);
+ } else {
+ done = true;
+ }
+ }
+ } catch (Throwable ex) {
+ errorTracker.notifyOfError(ex);
+ } finally {
+ // we finished a map job, release the job queue semaphore
+ runningMapJobs.countDown();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/Reducer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/Reducer.java
new file mode 100644
index 0000000..41b612f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/nanoScheduler/Reducer.java
@@ -0,0 +1,169 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+import com.google.java.contract.Ensures;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.MultiThreadedErrorTracker;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Reducer supporting multi-threaded reduce of the map/reduce.
+ *
+ * reduceAsMuchAsPossible is the key function. Multiple threads can call into this, providing
+ * the map results queue, and this class accumulates the result of calling reduce
+ * on the maps objects. reduceAsMuchAsPossible isn't directly synchronized, but manages multi-threading
+ * directly with a lock. Threads can request either to block on the reduce call until it can be
+ * executed, or immediately exit if the lock isn't available. That allows multi-threaded users
+ * to avoid piling up waiting to reduce while one thread is reducing. They can instead immediately
+ * leave to go do something else productive
+ *
+ * @author depristo
+ * @since 2012
+ */
+class Reducer<MapType, ReduceType> {
+ private final static Logger logger = Logger.getLogger(Reducer.class);
+
+ /**
+ * The reduce function to execute
+ */
+ private final NSReduceFunction<MapType, ReduceType> reduce;
+
+ /**
+ * Used to communicate errors to the outer master thread
+ */
+ private final MultiThreadedErrorTracker errorTracker;
+
+ /**
+ * Lock used to protect the call reduceAsMuchAsPossible from race conditions
+ */
+ private final Lock reduceLock = new ReentrantLock();
+
+ /**
+ * The sum of the reduce function applied to all MapResults. After this Reducer
+ * is done sum contains the final reduce result.
+ */
+ ReduceType sum;
+
+ /**
+ * Create a new Reducer that will apply the reduce function with initialSum value
+ * to values via reduceAsMuchAsPossible, timing the reduce function call costs with
+ * reduceTimer
+ *
+ * @param reduce the reduce function to apply
+ * @param initialSum the initial reduce sum
+ */
+ public Reducer(final NSReduceFunction<MapType, ReduceType> reduce,
+ final MultiThreadedErrorTracker errorTracker,
+ final ReduceType initialSum) {
+ if ( errorTracker == null ) throw new IllegalArgumentException("Error tracker cannot be null");
+ if ( reduce == null ) throw new IllegalArgumentException("Reduce function cannot be null");
+
+ this.errorTracker = errorTracker;
+ this.reduce = reduce;
+ this.sum = initialSum;
+ }
+
+ /**
+ * Reduce as much data as possible in mapResultQueue, returning the number of reduce calls completed
+ *
+ * As much as possible is defined as all of the MapResults in the queue are in order starting from the
+ * numSubmittedJobs we reduced previously, up to the either the queue being empty or where the next MapResult
+ * doesn't have JobID == prevJobID + 1.
+ *
+ * @param mapResultQueue a queue of MapResults in jobID order
+ * @return the number of reduces run, from 0 >
+ * @throws InterruptedException
+ */
+ @Ensures("result >= 0")
+ public int reduceAsMuchAsPossible(final MapResultsQueue<MapType> mapResultQueue, final boolean waitForLock) {
+ if ( mapResultQueue == null ) throw new IllegalArgumentException("mapResultQueue cannot be null");
+ int nReducesNow = 0;
+
+ final boolean haveLock = acquireReduceLock(waitForLock);
+ try {
+ if ( haveLock ) {
+ while ( mapResultQueue.nextValueIsAvailable() ) {
+ final MapResult<MapType> result = mapResultQueue.take();
+
+ if ( ! result.isEOFMarker() ) {
+ nReducesNow++;
+
+ // apply reduce, keeping track of sum
+ sum = reduce.apply(result.getValue(), sum);
+ }
+ }
+ }
+ } catch (Exception ex) {
+ errorTracker.notifyOfError(ex);
+ } finally {
+ if ( haveLock ) // if we acquired the lock, unlock it
+ releaseReduceLock();
+ }
+
+ return nReducesNow;
+ }
+
+ /**
+ * Acquire the reduce lock, either returning immediately if not possible or blocking until the lock is available
+ *
+ * @param blockUntilAvailable if true, we will block until the lock is available, otherwise we return immediately
+ * without acquiring the lock
+ * @return true if the lock has been acquired, false otherwise
+ */
+ protected boolean acquireReduceLock(final boolean blockUntilAvailable) {
+ if ( blockUntilAvailable ) {
+ reduceLock.lock();
+ return true;
+ } else {
+ return reduceLock.tryLock();
+ }
+ }
+
+ /**
+ * Free the reduce lock.
+ *
+ * Assumes that the invoking thread actually previously acquired the lock (it's a problem if not).
+ */
+ protected void releaseReduceLock() {
+ reduceLock.unlock();
+ }
+
+ /**
+ * Get the current reduce result resulting from applying reduce(...) to all MapResult elements.
+ *
+ * Note that this method cannot know if future reduce calls are coming in. So it simply gets
+ * the current reduce result. It is up to the caller to know whether the returned value is
+ * a partial result, or the full final value
+ *
+ * @return the total reduce result across all jobs
+ */
+ public ReduceType getReduceResult() {
+ return sum;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/BatchPairHMM.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/BatchPairHMM.java
new file mode 100644
index 0000000..2311564
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/BatchPairHMM.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pairhmm;
+
+import org.broadinstitute.gatk.utils.haplotype.Haplotype;
+
+import java.util.List;
+
+public interface BatchPairHMM {
+ public void batchAdd(final List<Haplotype> haplotypes,
+ final byte[] readBases,
+ final byte[] readQuals,
+ final byte[] insertionGOP,
+ final byte[] deletionGOP,
+ final byte[] overallGCP);
+
+ public double[] batchGetResult();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/Log10PairHMM.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/Log10PairHMM.java
new file mode 100644
index 0000000..4d84fc5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/Log10PairHMM.java
@@ -0,0 +1,220 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pairhmm;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.QualityUtils;
+
+import java.util.Arrays;
+
+import static java.lang.Math.log10;
+import static org.broadinstitute.gatk.utils.pairhmm.PairHMMModel.*;
+
+/**
+ * Util class for performing the pair HMM for local alignment. Figure 4.3 in Durbin 1998 book.
+ *
+ * User: rpoplin, carneiro
+ * Date: 3/1/12
+ */
+public class Log10PairHMM extends N2MemoryPairHMM {
+ /**
+ * Should we use exact log10 calculation (true), or an approximation (false)?
+ */
+ private final boolean doExactLog10;
+
+
+ // we divide e by 3 because the observed base could have come from any of the non-observed alleles
+ protected final static double log10_3 = log10(3.0);
+
+ /**
+ * Create an uninitialized PairHMM
+ *
+ * @param doExactLog10 should the log10 calculations be exact (slow) or approximate (faster)
+ */
+ public Log10PairHMM(final boolean doExactLog10) {
+ this.doExactLog10 = doExactLog10;
+ }
+
+ /**
+ * Is this HMM using exact log10 calculations?
+ * @return true if exact, false if approximate
+ */
+ public boolean isDoingExactLog10Calculations() {
+ return doExactLog10;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void initialize(final int readMaxLength, final int haplotypeMaxLength ) {
+ super.initialize(readMaxLength, haplotypeMaxLength);
+
+ for( int iii=0; iii < paddedMaxReadLength; iii++ ) {
+ Arrays.fill(matchMatrix[iii], Double.NEGATIVE_INFINITY);
+ Arrays.fill(insertionMatrix[iii], Double.NEGATIVE_INFINITY);
+ Arrays.fill(deletionMatrix[iii], Double.NEGATIVE_INFINITY);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public double subComputeReadLikelihoodGivenHaplotypeLog10( final byte[] haplotypeBases,
+ final byte[] readBases,
+ final byte[] readQuals,
+ final byte[] insertionGOP,
+ final byte[] deletionGOP,
+ final byte[] overallGCP,
+ final int hapStartIndex,
+ final boolean recacheReadValues,
+ final int nextHapStartIndex) {
+
+
+ if ( ! constantsAreInitialized || recacheReadValues )
+ initializeProbabilities(insertionGOP, deletionGOP, overallGCP);
+ initializePriors(haplotypeBases, readBases, readQuals, hapStartIndex);
+ if (previousHaplotypeBases == null || previousHaplotypeBases.length != haplotypeBases.length) {
+ // set the initial value (free deletions in the beginning) for the first row in the deletion matrix
+ initializeMatrixValues(haplotypeBases);
+ }
+
+ for (int i = 1; i < paddedReadLength; i++) {
+ // +1 here is because hapStartIndex is 0-based, but our matrices are 1 based
+ for (int j = hapStartIndex+1; j < paddedHaplotypeLength; j++) {
+ updateCell(i, j, prior[i][j], transition[i]);
+ }
+ }
+
+ // final probability is the log10 sum of the last element in the Match and Insertion state arrays
+ // this way we ignore all paths that ended in deletions! (huge)
+ // but we have to sum all the paths ending in the M and I matrices, because they're no longer extended.
+ return finalLikelihoodCalculation();
+ }
+
+ protected void initializeMatrixValues(final byte[] haplotypeBases) {
+ final double initialValue = Math.log10(1.0 / haplotypeBases.length);
+ for( int j = 0; j < paddedHaplotypeLength; j++ ) {
+ deletionMatrix[0][j] = initialValue;
+ }
+ }
+
+ protected double finalLikelihoodCalculation() {
+ final int endI = paddedReadLength - 1;
+ double finalSumProbabilities = myLog10SumLog10(new double[]{matchMatrix[endI][1], insertionMatrix[endI][1]});
+ for (int j = 2; j < paddedHaplotypeLength; j++)
+ finalSumProbabilities = myLog10SumLog10(new double[]{finalSumProbabilities, matchMatrix[endI][j], insertionMatrix[endI][j]});
+ return finalSumProbabilities;
+ }
+
+
+ /**
+ * Initializes the matrix that holds all the constants related to the editing
+ * distance between the read and the haplotype.
+ *
+ * @param haplotypeBases the bases of the haplotype
+ * @param readBases the bases of the read
+ * @param readQuals the base quality scores of the read
+ * @param startIndex where to start updating the distanceMatrix (in case this read is similar to the previous read)
+ */
+ public void initializePriors(final byte[] haplotypeBases, final byte[] readBases, final byte[] readQuals, final int startIndex) {
+
+ // initialize the pBaseReadLog10 matrix for all combinations of read x haplotype bases
+ // Abusing the fact that java initializes arrays with 0.0, so no need to fill in rows and columns below 2.
+
+ for (int i = 0; i < readBases.length; i++) {
+ final byte x = readBases[i];
+ final byte qual = readQuals[i];
+ for (int j = startIndex; j < haplotypeBases.length; j++) {
+ final byte y = haplotypeBases[j];
+ prior[i+1][j+1] = ( x == y || x == (byte) 'N' || y == (byte) 'N' ?
+ QualityUtils.qualToProbLog10(qual) : (QualityUtils.qualToErrorProbLog10(qual) - (doNotUseTristateCorrection ? 0.0 : log10_3)) );
+ }
+ }
+ }
+
+ /**
+ * Initializes the matrix that holds all the constants related to quality scores.
+ *
+ * @param insertionGOP insertion quality scores of the read
+ * @param deletionGOP deletion quality scores of the read
+ * @param overallGCP overall gap continuation penalty
+ */
+ @Requires({
+ "insertionGOP != null",
+ "deletionGOP != null",
+ "overallGCP != null"
+ })
+ @Ensures("constantsAreInitialized")
+ protected void initializeProbabilities(final byte[] insertionGOP, final byte[] deletionGOP, final byte[] overallGCP) {
+ PairHMMModel.qualToTransProbsLog10(transition,insertionGOP,deletionGOP,overallGCP);
+ // note that we initialized the constants
+ constantsAreInitialized = true;
+ }
+
+
+ /**
+ * Compute the log10SumLog10 of the values
+ *
+ * NOTE NOTE NOTE
+ *
+ * Log10PairHMM depends critically on this function tolerating values that are all -Infinity
+ * and the sum returning -Infinity. Note good. Needs to be fixed.
+ *
+ * NOTE NOTE NOTE
+ *
+ * @param values an array of log10 probabilities that need to be summed
+ * @return the log10 of the sum of the probabilities
+ */
+ @Requires("values != null")
+ protected double myLog10SumLog10(final double[] values) {
+ return doExactLog10 ? MathUtils.log10sumLog10(values) : MathUtils.approximateLog10SumLog10(values);
+ }
+
+ /**
+ * Updates a cell in the HMM matrix
+ *
+ * The read and haplotype indices are offset by one because the state arrays have an extra column to hold the
+ * initial conditions
+
+ * @param indI row index in the matrices to update
+ * @param indJ column index in the matrices to update
+ * @param prior the likelihood editing distance matrix for the read x haplotype
+ * @param transition an array with the six transition relevant to this location
+ */
+ protected void updateCell( final int indI, final int indJ, final double prior, final double[] transition) {
+
+ matchMatrix[indI][indJ] = prior +
+ myLog10SumLog10(new double[]{matchMatrix[indI - 1][indJ - 1] + transition[matchToMatch],
+ insertionMatrix[indI - 1][indJ - 1] + transition[indelToMatch],
+ deletionMatrix[indI - 1][indJ - 1] + transition[indelToMatch]});
+ insertionMatrix[indI][indJ] = myLog10SumLog10(new double[] {matchMatrix[indI - 1][indJ] + transition[matchToInsertion], insertionMatrix[indI - 1][indJ] + transition[insertionToInsertion]});
+ deletionMatrix[indI][indJ] = myLog10SumLog10(new double[] {matchMatrix[indI][indJ - 1] + transition[matchToDeletion], deletionMatrix[indI][indJ - 1] + transition[deletionToDeletion]});
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/N2MemoryPairHMM.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/N2MemoryPairHMM.java
new file mode 100644
index 0000000..0e0ffb5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/N2MemoryPairHMM.java
@@ -0,0 +1,98 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pairhmm;
+
+import com.google.java.contract.Requires;
+
+/**
+ * Superclass for PairHMM that want to use a full read x haplotype matrix for their match, insertion, and deletion matrix
+ *
+ * User: rpoplin
+ * Date: 10/16/12
+ */
+abstract class N2MemoryPairHMM extends PairHMM {
+ protected double[][] transition = null; // The transition probabilities cache
+ protected double[][] prior = null; // The prior probabilities cache
+ protected double[][] matchMatrix = null;
+ protected double[][] insertionMatrix = null;
+ protected double[][] deletionMatrix = null;
+
+ // only used for debugging purposes
+ protected boolean doNotUseTristateCorrection = false;
+
+ public void doNotUseTristateCorrection() {
+ doNotUseTristateCorrection = true;
+ }
+
+ /**
+ * Initialize this PairHMM, making it suitable to run against a read and haplotype with given lengths
+ *
+ * Note: Do not worry about padding, just provide the true max length of the read and haplotype. The HMM will take care of the padding.
+ *
+ * @param haplotypeMaxLength the max length of haplotypes we want to use with this PairHMM
+ * @param readMaxLength the max length of reads we want to use with this PairHMM
+ */
+ @Override
+ public void initialize( final int readMaxLength, final int haplotypeMaxLength ) {
+ super.initialize(readMaxLength, haplotypeMaxLength);
+
+ matchMatrix = new double[paddedMaxReadLength][paddedMaxHaplotypeLength];
+ insertionMatrix = new double[paddedMaxReadLength][paddedMaxHaplotypeLength];
+ deletionMatrix = new double[paddedMaxReadLength][paddedMaxHaplotypeLength];
+
+ transition = PairHMMModel.createTransitionMatrix(maxReadLength);
+ prior = new double[paddedMaxReadLength][paddedMaxHaplotypeLength];
+ }
+
+ /**
+ * Print out the core hmm matrices for debugging
+ */
+ protected void dumpMatrices() {
+ dumpMatrix("matchMetricArray", matchMatrix);
+ dumpMatrix("insertionMatrix", insertionMatrix);
+ dumpMatrix("deletionMatrix", deletionMatrix);
+ }
+
+ /**
+ * Print out in a human readable form the matrix for debugging
+ * @param name the name of this matrix
+ * @param matrix the matrix of values
+ */
+ @Requires({"name != null", "matrix != null"})
+ private void dumpMatrix(final String name, final double[][] matrix) {
+ System.out.printf("%s%n", name);
+ for ( int i = 0; i < matrix.length; i++) {
+ System.out.printf("\t%s[%d]", name, i);
+ for ( int j = 0; j < matrix[i].length; j++ ) {
+ if ( Double.isInfinite(matrix[i][j]) )
+ System.out.printf(" %15s", String.format("%f", matrix[i][j]));
+ else
+ System.out.printf(" % 15.5e", matrix[i][j]);
+ }
+ System.out.println();
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMM.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMM.java
new file mode 100644
index 0000000..6c4460c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMM.java
@@ -0,0 +1,357 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pairhmm;
+
+import com.google.java.contract.Requires;
+import htsjdk.variant.variantcontext.Allele;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.genotyper.ReadLikelihoods;
+import org.broadinstitute.gatk.utils.haplotype.Haplotype;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+/**
+ * Util class for performing the pair HMM for local alignment. Figure 4.3 in Durbin 1998 book.
+ *
+ * User: rpoplin
+ * Date: 10/16/12
+ */
+public abstract class PairHMM {
+ protected final static Logger logger = Logger.getLogger(PairHMM.class);
+
+ protected boolean constantsAreInitialized = false;
+
+ protected byte[] previousHaplotypeBases;
+ protected int hapStartIndex;
+
+ public enum HMM_IMPLEMENTATION {
+ /* Very slow implementation which uses very accurate log10 sum functions. Only meant to be used as a reference test implementation */
+ EXACT,
+ /* PairHMM as implemented for the UnifiedGenotyper. Uses log10 sum functions accurate to only 1E-4 */
+ ORIGINAL,
+ /* Optimized version of the PairHMM which caches per-read computations and operations in real space to avoid costly sums of log10'ed likelihoods */
+ LOGLESS_CACHING,
+ /* Optimized AVX implementation of LOGLESS_CACHING called through JNI */
+ VECTOR_LOGLESS_CACHING,
+ /* Debugging for vector implementation of LOGLESS_CACHING */
+ DEBUG_VECTOR_LOGLESS_CACHING,
+ /* Logless caching PairHMM that stores computations in 1D arrays instead of matrices, and which proceeds diagonally over the (read x haplotype) intersection matrix */
+ ARRAY_LOGLESS
+ }
+
+ protected int maxHaplotypeLength, maxReadLength;
+ protected int paddedMaxReadLength, paddedMaxHaplotypeLength;
+ protected int paddedReadLength, paddedHaplotypeLength;
+ protected boolean initialized = false;
+
+ // only used for debugging purposes
+ protected boolean doNotUseTristateCorrection = false;
+ protected void doNotUseTristateCorrection() { doNotUseTristateCorrection = true; }
+
+ //debug array
+ protected double[] mLikelihoodArray;
+
+ //profiling information
+ protected static Boolean doProfiling = true;
+ protected static long pairHMMComputeTime = 0;
+ protected long threadLocalPairHMMComputeTimeDiff = 0;
+ protected long startTime = 0;
+
+ /**
+ * Initialize this PairHMM, making it suitable to run against a read and haplotype with given lengths
+ *
+ * Note: Do not worry about padding, just provide the true max length of the read and haplotype. The HMM will take care of the padding.
+ *
+ * @param haplotypeMaxLength the max length of haplotypes we want to use with this PairHMM
+ * @param readMaxLength the max length of reads we want to use with this PairHMM
+ */
+ public void initialize( final int readMaxLength, final int haplotypeMaxLength ) {
+ if ( readMaxLength <= 0 ) throw new IllegalArgumentException("READ_MAX_LENGTH must be > 0 but got " + readMaxLength);
+ if ( haplotypeMaxLength <= 0 ) throw new IllegalArgumentException("HAPLOTYPE_MAX_LENGTH must be > 0 but got " + haplotypeMaxLength);
+
+ maxHaplotypeLength = haplotypeMaxLength;
+ maxReadLength = readMaxLength;
+
+ // M, X, and Y arrays are of size read and haplotype + 1 because of an extra column for initial conditions and + 1 to consider the final base in a non-global alignment
+ paddedMaxReadLength = readMaxLength + 1;
+ paddedMaxHaplotypeLength = haplotypeMaxLength + 1;
+
+ previousHaplotypeBases = null;
+
+ constantsAreInitialized = false;
+ initialized = true;
+ }
+
+ /**
+ * Called at the end of PairHMM for a region - mostly used by the JNI implementations
+ */
+ public void finalizeRegion()
+ {
+ ;
+ }
+
+ /**
+ * Initialize this PairHMM, making it suitable to run against a read and haplotype with given lengths
+ * This function is used by the JNI implementations to transfer all data once to the native code
+ * @param haplotypes the list of haplotypes
+ * @param perSampleReadList map from sample name to list of reads
+ * @param haplotypeMaxLength the max length of haplotypes we want to use with this PairHMM
+ * @param readMaxLength the max length of reads we want to use with this PairHMM
+ */
+ public void initialize( final List<Haplotype> haplotypes, final Map<String, List<GATKSAMRecord>> perSampleReadList, final int readMaxLength, final int haplotypeMaxLength ) {
+ initialize(readMaxLength, haplotypeMaxLength);
+ }
+
+ private int findMaxReadLength(final GATKSAMRecord ... reads) {
+ int max = 0;
+ for (final GATKSAMRecord read : reads) {
+ final int readLength = read.getReadLength();
+ if (max < readLength)
+ max = readLength;
+ }
+ return max;
+ }
+
+ private int findMaxAlleleLength(final List<? extends Allele> alleles) {
+ int max = 0;
+ for (final Allele allele : alleles) {
+ final int alleleLength = allele.length();
+ if (max < alleleLength)
+ max = alleleLength;
+ }
+ return max;
+ }
+
+ protected int findMaxReadLength(final List<GATKSAMRecord> reads) {
+ int listMaxReadLength = 0;
+ for(GATKSAMRecord read : reads){
+ final int readLength = read.getReadLength();
+ if( readLength > listMaxReadLength ) { listMaxReadLength = readLength; }
+ }
+ return listMaxReadLength;
+ }
+
+ protected int findMaxHaplotypeLength(final Collection<Haplotype> haplotypes) {
+ int listMaxHaplotypeLength = 0;
+ for( final Haplotype h : haplotypes) {
+ final int haplotypeLength = h.getBases().length;
+ if( haplotypeLength > listMaxHaplotypeLength ) { listMaxHaplotypeLength = haplotypeLength; }
+ }
+ return listMaxHaplotypeLength;
+ }
+
+ /**
+ * Given a list of reads and haplotypes, for every read compute the total probability of said read arising from
+ * each haplotype given base substitution, insertion, and deletion probabilities.
+ *
+ * @param processedReads reads to analyze instead of the ones present in the destination read-likelihoods.
+ * @param likelihoods where to store the likelihoods where position [a][r] is reserved for the likelihood of {@code reads[r]}
+ * conditional to {@code alleles[a]}.
+ * @param gcp penalty for gap continuations base array map for processed reads.
+ *
+ * @throws IllegalArgumentException
+ *
+ * @return never {@code null}.
+ */
+ public void computeLikelihoods(final ReadLikelihoods.Matrix<Haplotype> likelihoods,
+ final List<GATKSAMRecord> processedReads,
+ final Map<GATKSAMRecord,byte[]> gcp) {
+ if (processedReads.isEmpty())
+ return;
+ if(doProfiling)
+ startTime = System.nanoTime();
+ // (re)initialize the pairHMM only if necessary
+ final int readMaxLength = findMaxReadLength(processedReads);
+ final int haplotypeMaxLength = findMaxAlleleLength(likelihoods.alleles());
+ if (!initialized || readMaxLength > maxReadLength || haplotypeMaxLength > maxHaplotypeLength)
+ initialize(readMaxLength, haplotypeMaxLength);
+
+ final int readCount = processedReads.size();
+ final List<Haplotype> alleles = likelihoods.alleles();
+ final int alleleCount = alleles.size();
+ mLikelihoodArray = new double[readCount * alleleCount];
+ int idx = 0;
+ int readIndex = 0;
+ for(final GATKSAMRecord read : processedReads){
+ final byte[] readBases = read.getReadBases();
+ final byte[] readQuals = read.getBaseQualities();
+ final byte[] readInsQuals = read.getBaseInsertionQualities();
+ final byte[] readDelQuals = read.getBaseDeletionQualities();
+ final byte[] overallGCP = gcp.get(read);
+
+ // peak at the next haplotype in the list (necessary to get nextHaplotypeBases, which is required for caching in the array implementation)
+ final boolean isFirstHaplotype = true;
+ for (int a = 0; a < alleleCount; a++) {
+ final Allele allele = alleles.get(a);
+ final byte[] alleleBases = allele.getBases();
+ final byte[] nextAlleleBases = a == alleles.size() - 1 ? null : alleles.get(a + 1).getBases();
+ final double lk = computeReadLikelihoodGivenHaplotypeLog10(alleleBases,
+ readBases, readQuals, readInsQuals, readDelQuals, overallGCP, isFirstHaplotype, nextAlleleBases);
+ likelihoods.set(a, readIndex, lk);
+ mLikelihoodArray[idx++] = lk;
+ }
+ readIndex++;
+ }
+ if(doProfiling) {
+ threadLocalPairHMMComputeTimeDiff = (System.nanoTime() - startTime);
+ //synchronized(doProfiling)
+ {
+ pairHMMComputeTime += threadLocalPairHMMComputeTimeDiff;
+ }
+ }
+ }
+
+ /**
+ * Compute the total probability of read arising from haplotypeBases given base substitution, insertion, and deletion
+ * probabilities.
+ *
+ * Note on using hapStartIndex. This allows you to compute the exact true likelihood of a full haplotypes
+ * given a read, assuming that the previous calculation read over a full haplotype, recaching the read values,
+ * starting only at the place where the new haplotype bases and the previous haplotype bases different. This
+ * index is 0-based, and can be computed with findFirstPositionWhereHaplotypesDiffer given the two haplotypes.
+ * Note that this assumes that the read and all associated quals values are the same.
+ *
+ * @param haplotypeBases the full sequence (in standard SAM encoding) of the haplotype, must be >= than read bases in length
+ * @param readBases the bases (in standard encoding) of the read, must be <= haplotype bases in length
+ * @param readQuals the phred-scaled per base substitution quality scores of read. Must be the same length as readBases
+ * @param insertionGOP the phred-scaled per base insertion quality scores of read. Must be the same length as readBases
+ * @param deletionGOP the phred-scaled per base deletion quality scores of read. Must be the same length as readBases
+ * @param overallGCP the phred-scaled gap continuation penalties scores of read. Must be the same length as readBases
+ * @param recacheReadValues if false, we don't recalculate any cached results, assuming that readBases and its associated
+ * parameters are the same, and only the haplotype bases are changing underneath us
+ * @return the log10 probability of read coming from the haplotype under the provided error model
+ */
+ protected final double computeReadLikelihoodGivenHaplotypeLog10( final byte[] haplotypeBases,
+ final byte[] readBases,
+ final byte[] readQuals,
+ final byte[] insertionGOP,
+ final byte[] deletionGOP,
+ final byte[] overallGCP,
+ final boolean recacheReadValues,
+ final byte[] nextHaploytpeBases) {
+
+ if ( ! initialized ) throw new IllegalStateException("Must call initialize before calling computeReadLikelihoodGivenHaplotypeLog10");
+ if ( haplotypeBases == null ) throw new IllegalArgumentException("haplotypeBases cannot be null");
+ if ( haplotypeBases.length > maxHaplotypeLength ) throw new IllegalArgumentException("Haplotype bases is too long, got " + haplotypeBases.length + " but max is " + maxHaplotypeLength);
+ if ( readBases == null ) throw new IllegalArgumentException("readBases cannot be null");
+ if ( readBases.length > maxReadLength ) throw new IllegalArgumentException("readBases is too long, got " + readBases.length + " but max is " + maxReadLength);
+ if ( readQuals.length != readBases.length ) throw new IllegalArgumentException("Read bases and read quals aren't the same size: " + readBases.length + " vs " + readQuals.length);
+ if ( insertionGOP.length != readBases.length ) throw new IllegalArgumentException("Read bases and read insertion quals aren't the same size: " + readBases.length + " vs " + insertionGOP.length);
+ if ( deletionGOP.length != readBases.length ) throw new IllegalArgumentException("Read bases and read deletion quals aren't the same size: " + readBases.length + " vs " + deletionGOP.length);
+ if ( overallGCP.length != readBases.length ) throw new IllegalArgumentException("Read bases and overall GCP aren't the same size: " + readBases.length + " vs " + overallGCP.length);
+
+ paddedReadLength = readBases.length + 1;
+ paddedHaplotypeLength = haplotypeBases.length + 1;
+
+ hapStartIndex = (recacheReadValues) ? 0 : hapStartIndex;
+
+ // Pre-compute the difference between the current haplotype and the next one to be run
+ // Looking ahead is necessary for the ArrayLoglessPairHMM implementation
+ final int nextHapStartIndex = (nextHaploytpeBases == null || haplotypeBases.length != nextHaploytpeBases.length) ? 0 : findFirstPositionWhereHaplotypesDiffer(haplotypeBases, nextHaploytpeBases);
+
+ double result = subComputeReadLikelihoodGivenHaplotypeLog10(haplotypeBases, readBases, readQuals, insertionGOP, deletionGOP, overallGCP, hapStartIndex, recacheReadValues, nextHapStartIndex);
+
+ if ( result > 0.0)
+ throw new IllegalStateException("PairHMM Log Probability cannot be greater than 0: " + String.format("haplotype: %s, read: %s, result: %f, PairHMM: %s", new String(haplotypeBases), new String(readBases), result, this.getClass().getSimpleName()));
+ else if (!MathUtils.goodLog10Probability(result))
+ throw new IllegalStateException("Invalid Log Probability: " + result);
+
+ // Warning: Careful if using the PairHMM in parallel! (this update has to be taken care of).
+ // Warning: This assumes no downstream modification of the haplotype bases (saves us from copying the array). It is okay for the haplotype caller and the Unified Genotyper.
+ previousHaplotypeBases = haplotypeBases;
+
+ // For the next iteration, the hapStartIndex for the next haploytpe becomes the index for the current haplotype
+ // The array implementation has to look ahead to the next haplotype to store caching info. It cannot do this if nextHapStart is before hapStart
+ hapStartIndex = (nextHapStartIndex < hapStartIndex) ? 0: nextHapStartIndex;
+
+ return result;
+ }
+
+ /**
+ * To be overloaded by subclasses to actually do calculation for #computeReadLikelihoodGivenHaplotypeLog10
+ */
+ @Requires({"readBases.length == readQuals.length", "readBases.length == insertionGOP.length", "readBases.length == deletionGOP.length",
+ "readBases.length == overallGCP.length", "matchMatrix!=null", "insertionMatrix!=null", "deletionMatrix!=null"})
+ protected abstract double subComputeReadLikelihoodGivenHaplotypeLog10( final byte[] haplotypeBases,
+ final byte[] readBases,
+ final byte[] readQuals,
+ final byte[] insertionGOP,
+ final byte[] deletionGOP,
+ final byte[] overallGCP,
+ final int hapStartIndex,
+ final boolean recacheReadValues,
+ final int nextHapStartIndex);
+
+ /**
+ * Compute the first position at which two haplotypes differ
+ *
+ * If the haplotypes are exact copies of each other, returns the min length of the two haplotypes.
+ *
+ * @param haplotype1 the first haplotype1
+ * @param haplotype2 the second haplotype1
+ * @return the index of the first position in haplotype1 and haplotype2 where the byte isn't the same
+ */
+ public static int findFirstPositionWhereHaplotypesDiffer(final byte[] haplotype1, final byte[] haplotype2) {
+ if ( haplotype1 == null || haplotype1.length == 0 ) throw new IllegalArgumentException("Haplotype1 is bad " + Arrays.toString(haplotype1));
+ if ( haplotype2 == null || haplotype2.length == 0 ) throw new IllegalArgumentException("Haplotype2 is bad " + Arrays.toString(haplotype2));
+
+ for( int iii = 0; iii < haplotype1.length && iii < haplotype2.length; iii++ ) {
+ if( haplotype1[iii] != haplotype2[iii] ) {
+ return iii;
+ }
+ }
+
+ return Math.min(haplotype1.length, haplotype2.length);
+ }
+
+ /**
+ * Use number of threads to set doProfiling flag - doProfiling iff numThreads == 1
+ * This function should be called only during initialization phase - single thread phase of HC
+ */
+ public static void setNumberOfThreads(final int numThreads)
+ {
+ doProfiling = (numThreads == 1);
+ if(numThreads > 1)
+ logger.info("Performance profiling for PairHMM is disabled because HaplotypeCaller is being run with multiple threads (-nct>1) option\nProfiling is enabled only when running in single thread mode\n");
+ }
+
+ /**
+ * Return the results of the computeLikelihoods function
+ */
+ public double[] getLikelihoodArray() { return mLikelihoodArray; }
+ /**
+ * Called at the end of the program to close files, print profiling information etc
+ */
+ public void close()
+ {
+ if(doProfiling)
+ System.out.println("Total compute time in PairHMM computeLikelihoods() : "+(pairHMMComputeTime*1e-9));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMMModel.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMMModel.java
new file mode 100644
index 0000000..1cd8865
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMMModel.java
@@ -0,0 +1,435 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pairhmm;
+
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.QualityUtils;
+
+/**
+ * Helper class that implement calculations required to implement the PairHMM Finite State Automation (FSA) model.
+ *
+ * @author Valentin Ruano-Rubio <valentin at broadinstitute.org>
+ */
+public class PairHMMModel {
+
+
+ /**
+ * Prevents instantiation of this class
+ */
+ private PairHMMModel() {
+
+ }
+
+ /**
+ * Length of the standard transition probability array.
+ */
+ public static final int TRANS_PROB_ARRAY_LENGTH = 6;
+
+ /**
+ * Position in the transition probability array for the Match-to-Match transition.
+ */
+ public static final int matchToMatch = 0;
+
+ /**
+ * Position in the transition probability array for the Indel-to-Match transition.
+ */
+ public static final int indelToMatch = 1;
+
+ /**
+ * Position in the transition probability array for the Match-to-Insertion transition.
+ */
+ public static final int matchToInsertion = 2;
+
+ /**
+ * Position in the transition probability array for the Insertion-to-Insertion transition.
+ */
+ public static final int insertionToInsertion = 3;
+
+ /**
+ * Position in the transition probability array for the Match-to-Deletion transition.
+ */
+ public static final int matchToDeletion = 4;
+
+ /**
+ * Position in the transition probability array for the Deletion-to-Deletion transition.
+ */
+ public static final int deletionToDeletion = 5;
+
+ /**
+ * Convenient ln10 constant.
+ */
+ private static double LN10 = Math.log(10);
+
+ /**
+ * Convenient (ln10)^-1 constant.
+ */
+ private static double INV_LN10 = 1.0 / LN10;
+
+ /**
+ * Holds pre-calculated the matchToMath probability values in linear scale.
+ *
+ * <p/>
+ * This is a triangular matrix stored in a unidimentional array like so:
+ * <p/>
+ * (0,0), (0,1), (1,1), (0,2), (1,2), (2,2), (0,3) ... ({@link QualityUtils#MAX_QUAL},{@link QualityUtils#MAX_QUAL})
+ */
+ private static double[] matchToMatchProb = new double[((QualityUtils.MAX_QUAL + 1) * (QualityUtils.MAX_QUAL + 2)) >> 1];
+
+ /**
+ * Holds pre-calculated the matchToMath probability values in log10 scale.
+ *
+ * <p/>
+ * This is a triangular matrix stored in a unidimentional array like so:
+ * <p/>
+ * (0,0), (0,1), (1,1), (0,2), (1,2), (2,2), (0,3) ... ({@link QualityUtils#MAX_QUAL},{@link QualityUtils#MAX_QUAL})
+ */
+ private static double[] matchToMatchLog10 = new double[((QualityUtils.MAX_QUAL + 1) * (QualityUtils.MAX_QUAL + 2)) >> 1];
+
+ /**
+ * Initialize matchToMatch cache tables {@link #matchToMatch} and {@link #matchToMatchLog10}
+ */
+ static {
+ for (int i = 0, offset = 0; i <= QualityUtils.MAX_QUAL; offset += ++i)
+ for (int j = 0; j <= i; j++) {
+ final double log10Sum = MathUtils.approximateLog10SumLog10(-0.1 * i,-0.1 * j);
+ matchToMatchLog10[offset + j] =
+ Math.log1p( - Math.min(1,Math.pow(10,log10Sum))) * INV_LN10;
+ matchToMatchProb[offset + j] = Math.pow(10,matchToMatchLog10[offset + j]);
+ }
+ }
+
+ /**
+ * Fills a transition probability array given the different quality scores affecting a read site
+ *
+ * @param insQual the insertion quality score as a byte.
+ * @param delQual the deletion quality score as a byte.
+ * @param gcp the gap-continuation-penalty score as a byte.
+ *
+ * @throws NullPointerException if {@code dest} is {@code null}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dest} is not large enough.
+ * @throws IllegalArgumentException if {@code insQual}, {@code delQual} or {@code gcp} is less than negative.
+ */
+ public static void qualToTransProbs(final double[] dest, final byte insQual, final byte delQual, final byte gcp) {
+ if (insQual < 0) throw new IllegalArgumentException("insert quality cannot less than 0: " + insQual);
+ if (delQual < 0) throw new IllegalArgumentException("deletion quality cannot be less than 0: " + delQual);
+ if (gcp < 0) throw new IllegalArgumentException("gcp cannot be less than 0: " + gcp);
+ dest[matchToMatch] = matchToMatchProb(insQual, delQual);
+ dest[matchToInsertion] = QualityUtils.qualToErrorProb(insQual);
+ dest[matchToDeletion] = QualityUtils.qualToErrorProb(delQual);
+ dest[indelToMatch] = QualityUtils.qualToProb(gcp);
+ dest[insertionToInsertion] = dest[deletionToDeletion] = QualityUtils.qualToErrorProb(gcp);
+ }
+
+ /**
+ * Returns a transition probability array given the different quality scores affecting a read site.
+ *
+ * @param insQual the insertion quality score as a byte.
+ * @param delQual the deletion quality score as a byte.
+ * @param gcp the gap-continuation-penalty score as a byte.
+ *
+ * @throws NullPointerException if {@code dest} is {@code null}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dest} is not large enough.
+ * @throws IllegalArgumentException if {@code insQual}, {@code delQual} or {@code gcp} is less than negative.
+ *
+ * @return never {@code null}. An array of length {@link #TRANS_PROB_ARRAY_LENGTH}.
+ */
+ @SuppressWarnings("unused")
+ public static double[] qualToTransProbs(final byte insQual, final byte delQual, final byte gcp) {
+ final double[] dest = new double[TRANS_PROB_ARRAY_LENGTH];
+ qualToTransProbs(dest,insQual,delQual,gcp);
+ return dest;
+ }
+
+ /**
+ * Fills ax matrix with the transition probabilities for a number of bases.
+ *
+ * <p/>
+ * The first dimension of the matrix correspond to the different bases where the first one is stored in position 1.
+ * Thus the position 0 is left empty and the length of the resulting matrix is actually {@code insQual.length + 1}.
+ * <p/>
+ * Each entry is the transition probability array for that base with a length of {@link #TRANS_PROB_ARRAY_LENGTH}.
+ *
+ * @param dest the matrix to update
+ * @param insQuals insertion qualities.
+ * @param delQuals deletion qualities.
+ * @param gcps gap-continuation penalty qualities.
+ *
+ * @throws NullPointerException if any of the input arrays, matrices is {@code null} or any entry in {@code dest} is {@code null}.
+ * @throws IllegalArgumentException if {@code IllegalArgumentException}
+ * if the input array don't have the same length.
+ * @throws ArrayIndexOutOfBoundsException if {@code dest} or any of its elements is not large enough to contain the
+ * transition matrix.
+ */
+ @SuppressWarnings("unused")
+ public static void qualToTransProbs(final double[][] dest, final byte[] insQuals, final byte[] delQuals, final byte[] gcps) {
+ final int readLength = insQuals.length;
+ if (delQuals.length != readLength) throw new IllegalArgumentException("deletion quality array length does not match insert quality array length: " + readLength + " != " + delQuals.length);
+ if (gcps.length != readLength) throw new IllegalArgumentException("deletion quality array length does not match insert quality array length: " + readLength + " != " + gcps.length);
+
+ if (dest.length < readLength + 1) throw new IllegalArgumentException("destination length is not enough for the read length: " + dest.length + " < " + readLength + " + 1");
+
+ for (int i = 0; i < readLength; i++)
+ qualToTransProbs(dest[i + 1], insQuals[i], delQuals[i], gcps[i]);
+ }
+
+ /**
+ * Returns a matrix with the transition probabilities for a number of bases.
+ *
+ * <p/>
+ * The first dimension of the matrix correspond to the different bases where the first one is stored in position 1.
+ * Thus the position 0 is left empty and the length of the resulting matrix is actually {@code insQual.length + 1}.
+ * <p/>
+ * Each entry is the transition probability array for that base with a length of {@link #TRANS_PROB_ARRAY_LENGTH}.
+ *
+ * @param insQuals insertion qualities.
+ * @param delQuals deletion qualities.
+ * @param gcps gap-continuation penalty qualities.
+ *
+ * @throws NullPointerException if any of the input arrays is {@code null}.
+ * @throws IllegalArgumentException if {@code IllegalArgumentException}
+ * if the input array don't have the same length.
+ *
+ * @return never {@code null}, an matrix of the dimensions explained above.
+ */
+ @SuppressWarnings("unused")
+ public static double[][] qualToTransProbs(final byte[] insQuals, final byte[] delQuals, final byte[] gcps) {
+ final double[][] dest = createTransitionMatrix(insQuals.length);
+ qualToTransProbs(dest,insQuals,delQuals,gcps);
+ return dest;
+ }
+
+ /**
+ * Fills a transition log10 probability array given the different quality scores affecting a read site.
+ *
+ * @param insQual the insertion quality score as a byte.
+ * @param delQual the deletion quality score as a byte.
+ * @param gcp the gap-continuation-penalty score as a byte.
+ *
+ * @throws NullPointerException if {@code dest} is {@code null}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dest} is not large enough.
+ * @throws IllegalArgumentException if {@code insQual}, {@code delQual} or {@code gcp} is less than negative.
+ */
+ public static void qualToTransProbsLog10(final double[] dest, final byte insQual, final byte delQual, final byte gcp) {
+ if (insQual < 0) throw new IllegalArgumentException("insert quality cannot less than 0: " + insQual);
+ if (delQual < 0) throw new IllegalArgumentException("deletion quality cannot be less than 0: " + delQual);
+ if (gcp < 0) throw new IllegalArgumentException("gcp cannot be less than 0: " + gcp);
+ dest[matchToMatch] = matchToMatchProbLog10(insQual, delQual);
+ dest[matchToInsertion] = QualityUtils.qualToErrorProbLog10(insQual);
+ dest[matchToDeletion] = QualityUtils.qualToErrorProbLog10(delQual);
+ dest[indelToMatch] = QualityUtils.qualToProbLog10(gcp);
+ dest[insertionToInsertion] = dest[deletionToDeletion] = QualityUtils.qualToErrorProbLog10(gcp);
+ }
+
+ /**
+ * Returns a transition log10 probability array given the different quality scores affecting a read site.
+ *
+ * @param insQual the insertion quality score as a byte.
+ * @param delQual the deletion quality score as a byte.
+ * @param gcp the gap-continuation-penalty score as a byte.
+ *
+ * @throws NullPointerException if {@code dest} is {@code null}.
+ * @throws ArrayIndexOutOfBoundsException if {@code dest} is not large enough.
+ * @throws IllegalArgumentException if {@code insQual}, {@code delQual} or {@code gcp} is less than negative.
+ *
+ * @return never {@code null}. An array of length {@link #TRANS_PROB_ARRAY_LENGTH}.
+ */
+ @SuppressWarnings("unused")
+ public static double[] qualToTransProbsLog10(final byte insQual, final byte delQual, final byte gcp) {
+ final double[] dest = new double[TRANS_PROB_ARRAY_LENGTH];
+ qualToTransProbsLog10(dest,insQual,delQual,gcp);
+ return dest;
+ }
+
+ /**
+ * Fills a matrix with the log10 transition probabilities for a number of bases.
+ *
+ * <p/>
+ * The first dimension of the matrix correspond to the different bases where the first one is stored in position 1.
+ * Thus the position 0 is left empty and the length of the resulting matrix is actually {@code insQual.length + 1}.
+ * <p/>
+ * Each entry is the transition probability array for that base with a length of {@link #TRANS_PROB_ARRAY_LENGTH}.
+ *
+ * @param insQuals insertion qualities.
+ * @param delQuals deletion qualities.
+ * @param gcps gap-continuation penalty qualities.
+ *
+ * @throws NullPointerException if any of the input arrays, matrices is {@code null} or any entry in {@code dest} is {@code null}.
+ * @throws IllegalArgumentException if {@code IllegalArgumentException}
+ * if the input array don't have the same length.
+ * @throws ArrayIndexOutOfBoundsException if {@code dest} or any of its elements is not large enough to contain the
+ * transition matrix.
+ */
+ @SuppressWarnings("unused")
+ public static void qualToTransProbsLog10(final double[][] dest, final byte[] insQuals, final byte[] delQuals, final byte[] gcps) {
+ final int readLength = insQuals.length;
+ if (delQuals.length != readLength) throw new IllegalArgumentException("deletion quality array length does not match insert quality array length: " + readLength + " != " + delQuals.length);
+ if (gcps.length != readLength) throw new IllegalArgumentException("deletion quality array length does not match insert quality array length: " + readLength + " != " + gcps.length);
+ if (dest.length < readLength + 1) throw new IllegalArgumentException("destination length is not enough for the read length: " + dest.length + " < " + readLength + " + 1");
+
+ for (int i = 0; i < readLength; i++)
+ qualToTransProbsLog10(dest[i+1],insQuals[i],delQuals[i],gcps[i]);
+ }
+
+ /**
+ * Returns a matrix with the log10 transition probabilities for a number of bases.
+ *
+ * <p/>
+ * The first dimension of the matrix correspond to the different bases where the first one is stored in position 1.
+ * Thus the position 0 is left empty and the length of the resulting matrix is actually {@code insQual.length + 1}.
+ * <p/>
+ * Each entry is the transition probability array for that base with a length of {@link #TRANS_PROB_ARRAY_LENGTH}.
+ *
+ * @param insQuals insertion qualities.
+ * @param delQuals deletion qualities.
+ * @param gcps gap-continuation penalty qualities.
+ *
+ * @throws NullPointerException if any of the input arrays is {@code null}.
+ * @throws IllegalArgumentException if {@code IllegalArgumentException}
+ * if the input array don't have the same length.
+ *
+ * @return never {@code null}, an matrix of the dimensions explained above.
+ */
+ @SuppressWarnings("unused")
+ public static double[][] qualToTransProbsLog10(final byte[] insQuals, final byte[] delQuals, final byte[] gcps) {
+ final double[][] dest = createTransitionMatrix(insQuals.length);
+ qualToTransProbsLog10(dest,insQuals,delQuals,gcps);
+ return dest;
+ }
+
+ /**
+ * Creates a transition probability matrix large enough to work with sequences of a particular length.
+ *
+ * @param maxReadLength the maximum read length for the transition matrix.
+ *
+ * @return never {@code null}. A matrix of {@code maxReadLength + 1} by {@link #TRANS_PROB_ARRAY_LENGTH} positions.
+ */
+ public static double[][] createTransitionMatrix(final int maxReadLength) {
+ return new double[maxReadLength + 1][TRANS_PROB_ARRAY_LENGTH];
+ }
+
+ /**
+ * Returns the probability that neither of two event takes place.
+ * <p/>
+ *
+ * We assume that both event never occur together and that delQual is the conditional probability
+ * (qual. encoded) of the second event, given the first event didn't took place. So that the
+ * probability of no event is: <br/>
+ *
+ * We assume that both event never occur together so that the probability of no event is: <br/>
+ *
+ * <code>1 - ProbErr(insQual) - ProbErr(delQual)</code> <br/>
+ *
+ * @param insQual PhRED scaled quality/probability of the first event.
+ * @param delQual PhRED scaled quality/probability of the second event.
+ *
+ * @return a value between 0 and 1.
+ */
+ public static double matchToMatchProb(final byte insQual, final byte delQual) {
+ return matchToMatchProb((insQual & 0xFF), (delQual & 0xFF));
+ }
+
+ /**
+ * Returns the probability (log 10 scaled) that neither of two event, insertion and deletion, takes place.
+ * <p/>
+ *
+ * We assume that both event never occur together so that the probability of no event is: <br/>
+ *
+ * <code>1 - ProbErr(insQual) - ProbErr(delQual)</code> <br/>
+ *
+ * @param insQual PhRED scaled quality/probability of an insertion.
+ * @param delQual PhRED scaled quality/probability of a deletion.
+ *
+ * @return a value between 0 and -Inf.
+ */
+ public static double matchToMatchProbLog10(final byte insQual, final byte delQual) {
+ return matchToMatchProbLog10((insQual & 0xFF), (delQual & 0xFF));
+ }
+
+ /**
+ * Returns the probability that neither of two events, insertion and deletion, takes place.
+ * <p/>
+ *
+ * We assume that both event never occur together and that delQual is the conditional probability
+ * (qual. encoded) of the second event, given the first event didn't took place. So that the
+ * probability of no event is: <br/>
+ *
+ * We assume that both event never occur together so that the probability of no event is: <br/>
+ *
+ * <code>1 - ProbErr(insQual) - ProbErr(delQual)</code> <br/>
+ *
+ * @param insQual PhRED scaled quality/probability of an insertion.
+ * @param delQual PhRED scaled quality/probability of a deletion.
+ * @return a value between 0 and 1.
+ */
+ public static double matchToMatchProb(final int insQual, final int delQual) {
+ final int minQual;
+ final int maxQual;
+ if (insQual <= delQual) {
+ minQual = insQual;
+ maxQual = delQual;
+ } else {
+ minQual = delQual;
+ maxQual = insQual;
+ }
+
+ if (minQual < 0) throw new IllegalArgumentException("quality cannot be negative: " + minQual + " and " + maxQual);
+
+ return (QualityUtils.MAX_QUAL < maxQual) ? 1.0 - Math.pow(10, MathUtils.approximateLog10SumLog10(-0.1 * minQual, -0.1 * maxQual)) :
+ matchToMatchProb[((maxQual * (maxQual + 1)) >> 1) + minQual];
+ }
+
+ /**
+ * Returns the probability (log 10 scaled) that neither of two event takes place.
+ * <p/>
+ *
+ * We assume that both event never occur together and that delQual is the conditional probability (qual. encoded)
+ * of the second event, given the first event didn't took place. So that the probability of no event is: <br/>
+ *
+ * We assume that both event never occur together so that the probability of no event is: <br/>
+ *
+ * <code>1 - ProbErr(insQual) - ProbErr(delQual)</code> <br/>
+ *
+ * @param insQual PhRED scaled quality/probability of an insertion.
+ * @param delQual PhRED scaled quality/probability of a deletion.
+ *
+ * @return a value between 0 and -Inf.
+ */
+ public static double matchToMatchProbLog10(final int insQual, final int delQual) {
+ final int minQual;
+ final int maxQual;
+ if (insQual <= delQual) {
+ minQual = insQual;
+ maxQual = delQual;
+ } else {
+ minQual = delQual;
+ maxQual = insQual;
+ }
+ return (QualityUtils.MAX_QUAL < maxQual) ? Math.log1p (
+ - Math.min(1,Math.pow(10,
+ MathUtils.approximateLog10SumLog10(-.1 * minQual, -.1 * maxQual)))) * INV_LN10 :
+ matchToMatchLog10[((maxQual * (maxQual + 1)) >> 1) + minQual];
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMMReadyHaplotypes.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMMReadyHaplotypes.java
new file mode 100644
index 0000000..2948404
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pairhmm/PairHMMReadyHaplotypes.java
@@ -0,0 +1,182 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pairhmm;
+
+import java.util.*;
+
+/**
+ * Collection of haplotypes sorted in a conveniently way to be run efficiently by the PairHMM.
+ *
+ * TODO not yet in use but likely to be as part of making graph-base likelihood run faster.
+ * TODO this could be extended to the classical PairHMM implementation simplifyling the PairHMM API.
+ */
+public class PairHMMReadyHaplotypes implements Iterable<PairHMMReadyHaplotypes.Entry> {
+
+
+ public class Entry {
+
+ private final byte[] bases;
+
+ private double likelihood = Double.NaN;
+
+ protected Entry(final byte[] bases) {
+ this.bases = bases;
+ }
+
+ protected byte[] getBases() {
+ return bases;
+ }
+
+ public void setLikelihood(final double lk) {
+ likelihood = lk;
+ }
+
+ public double getLikelihood() {
+ return likelihood;
+ }
+
+ }
+
+ private Map<Entry,Map<Entry,Integer>> commonPrefixLength;
+
+ private SortedSet<Entry> entries;
+
+ private int capacity;
+
+ private final Comparator<Entry> comparator = new Comparator<Entry>() {
+ @Override
+ public int compare(final Entry o1, final Entry o2) {
+ final byte[] b1 = o1.bases;
+ final byte[] b2 = o2.bases;
+ Map<Entry,Integer> b1map = commonPrefixLength.get(o1);
+ if (b1map == null)
+ commonPrefixLength.put(o1, b1map = new HashMap<>(capacity));
+ Map<Entry,Integer> b2map = commonPrefixLength.get(o2);
+ if (b2map == null)
+ commonPrefixLength.put(o2, b2map = new HashMap<>(capacity));
+ final Integer previousI = b1map.get(o2) == null ? null : b1map.get(o2);
+ int i;
+ int result;
+ final int iLimit = Math.min(b1.length,b2.length);
+ if (previousI == null) {
+ for (i = 0; i < iLimit; i++)
+ if (b1[i] != b2[i])
+ break;
+ b1map.put(o2,i);
+ b2map.put(o1,i);
+ } else
+ i = previousI;
+
+ if (i < iLimit)
+ result = Byte.compare(b1[i],b2[i]);
+ else if (b1.length == b2.length)
+ result = 0;
+ else
+ result = b1.length < b2.length ? -1 : 1;
+ return result;
+ }
+ };
+
+ public PairHMMReadyHaplotypes(final int capacity) {
+ commonPrefixLength = new HashMap<>(capacity);
+ entries = new TreeSet<>(comparator);
+ }
+
+ public void add(final byte[] bases) {
+ final Entry entry = new Entry(bases);
+ entries.add(entry);
+ }
+
+ public int size() {
+ return entries.size();
+ }
+
+ @Override
+ public Iterator iterator() {
+ return new Iterator();
+ }
+
+ public class Iterator implements java.util.Iterator<Entry> {
+
+ private java.util.Iterator<Entry> actualIterator;
+ private Entry previousEntry;
+ private Entry currentEntry;
+ private int startIndex;
+ private int cmp;
+
+ private Iterator() {
+ actualIterator = entries.iterator();
+ }
+
+ public boolean hasNext() {
+ return actualIterator.hasNext();
+ }
+
+ public Entry next() {
+ previousEntry = currentEntry;
+ final Entry result = currentEntry = actualIterator.next();
+ startIndex = -1;
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public byte[] bases() {
+ if (currentEntry == null)
+ throw new NoSuchElementException();
+ return currentEntry.bases;
+ }
+
+ public int startIndex() {
+ if (startIndex >= 0)
+ return startIndex;
+ else if (previousEntry == null)
+ return startIndex = 0;
+ else {
+ // The comparator will make sure the common-prefix-length is updated.
+ // The result in a field so that we avoid dead code elimination.
+ // perhaps I a bit paranohic but it does not harm to prevent.
+ cmp = comparator.compare(previousEntry,currentEntry);
+ return startIndex = commonPrefixLength.get(previousEntry).get(currentEntry);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + " cmp = " + cmp;
+ }
+
+ public void setLikelihood(final double likelihood) {
+ if (currentEntry == null)
+ throw new NoSuchElementException();
+ currentEntry.setLikelihood(likelihood);
+ }
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/MergingPileupElementIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/MergingPileupElementIterator.java
new file mode 100644
index 0000000..d36d355
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/MergingPileupElementIterator.java
@@ -0,0 +1,76 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pileup;
+
+import htsjdk.samtools.util.PeekableIterator;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.PriorityQueue;
+
+/**
+ * Merges multiple pileups broken down by sample.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+class MergingPileupElementIterator<PE extends PileupElement> implements Iterator<PE> {
+ private final PriorityQueue<PeekableIterator<PE>> perSampleIterators;
+
+ public MergingPileupElementIterator(PerSamplePileupElementTracker<PE> tracker) {
+ perSampleIterators = new PriorityQueue<PeekableIterator<PE>>(Math.max(1,tracker.getSamples().size()),new PileupElementIteratorComparator());
+ for(final String sample: tracker.getSamples()) {
+ PileupElementTracker<PE> trackerPerSample = tracker.getElements(sample);
+ if(trackerPerSample.size() != 0)
+ perSampleIterators.add(new PeekableIterator<PE>(trackerPerSample.iterator()));
+ }
+ }
+
+ public boolean hasNext() {
+ return !perSampleIterators.isEmpty();
+ }
+
+ public PE next() {
+ PeekableIterator<PE> currentIterator = perSampleIterators.remove();
+ PE current = currentIterator.next();
+ if(currentIterator.hasNext())
+ perSampleIterators.add(currentIterator);
+ return current;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Cannot remove from a merging iterator.");
+ }
+
+ /**
+ * Compares two peekable iterators consisting of pileup elements.
+ */
+ private class PileupElementIteratorComparator implements Comparator<PeekableIterator<PE>> {
+ public int compare(PeekableIterator<PE> lhs, PeekableIterator<PE> rhs) {
+ return rhs.peek().getOffset() - lhs.peek().getOffset();
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/PileupElement.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/PileupElement.java
new file mode 100644
index 0000000..4db0927
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/PileupElement.java
@@ -0,0 +1,539 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pileup;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: Apr 14, 2009
+ * Time: 8:54:05 AM
+ */
+public class PileupElement implements Comparable<PileupElement> {
+ private final static LinkedList<CigarElement> EMPTY_LINKED_LIST = new LinkedList<>();
+
+ private final static EnumSet<CigarOperator> ON_GENOME_OPERATORS =
+ EnumSet.of(CigarOperator.M, CigarOperator.EQ, CigarOperator.X, CigarOperator.D);
+
+ public static final byte DELETION_BASE = BaseUtils.Base.D.base;
+ public static final byte DELETION_QUAL = (byte) 16;
+ public static final byte A_FOLLOWED_BY_INSERTION_BASE = (byte) 87;
+ public static final byte C_FOLLOWED_BY_INSERTION_BASE = (byte) 88;
+ public static final byte T_FOLLOWED_BY_INSERTION_BASE = (byte) 89;
+ public static final byte G_FOLLOWED_BY_INSERTION_BASE = (byte) 90;
+
+ protected final GATKSAMRecord read; // the read this base belongs to
+ protected final int offset; // the offset in the bases array for this base
+
+ private final CigarElement currentCigarElement;
+ private final int currentCigarOffset;
+ private final int offsetInCurrentCigar;
+
+ /**
+ * Create a new pileup element
+ *
+ * @param read a non-null read to pileup
+ * @param baseOffset the offset into the read's base / qual vector aligned to this position on the genome. If the
+ * current cigar element is a deletion, offset should be the offset of the last M/=/X position.
+ * @param currentElement a non-null CigarElement that indicates the cigar element aligning the read to the genome
+ * @param currentCigarOffset the offset of currentElement in read.getCigar().getElement(currentCigarOffset) == currentElement)
+ * @param offsetInCurrentCigar how far into the currentElement are we in our alignment to the genome?
+ */
+ public PileupElement(final GATKSAMRecord read, final int baseOffset,
+ final CigarElement currentElement, final int currentCigarOffset,
+ final int offsetInCurrentCigar) {
+ assert currentElement != null;
+
+ this.read = read;
+ this.offset = baseOffset;
+ this.currentCigarElement = currentElement;
+ this.currentCigarOffset = currentCigarOffset;
+ this.offsetInCurrentCigar = offsetInCurrentCigar;
+
+ // for performance regions these are assertions
+ assert this.read != null;
+ assert this.offset >= 0 && this.offset < this.read.getReadLength();
+ assert this.currentCigarOffset >= 0;
+ assert this.currentCigarOffset < read.getCigarLength();
+ assert this.offsetInCurrentCigar >= 0;
+ assert this.offsetInCurrentCigar < currentElement.getLength();
+ }
+
+ /**
+ * Create a new PileupElement that's a copy of toCopy
+ * @param toCopy the element we want to copy
+ */
+ public PileupElement(final PileupElement toCopy) {
+ this(toCopy.read, toCopy.offset, toCopy.currentCigarElement, toCopy.currentCigarOffset, toCopy.offsetInCurrentCigar);
+ }
+
+ /**
+ * Is this element a deletion w.r.t. the reference genome?
+ *
+ * @return true if this is a deletion, false otherwise
+ */
+ public boolean isDeletion() {
+ return currentCigarElement.getOperator() == CigarOperator.D;
+ }
+
+ /**
+ * Is the current element immediately before a deletion, but itself not a deletion?
+ *
+ * Suppose we are aligning a read with cigar 3M2D1M. This function is true
+ * if we are in the last cigar position of the 3M, but not if we are in the 2D itself.
+ *
+ * @return true if the next alignment position is a deletion w.r.t. the reference genome
+ */
+ public boolean isBeforeDeletionStart() {
+ return ! isDeletion() && atEndOfCurrentCigar() && hasOperator(getNextOnGenomeCigarElement(), CigarOperator.D);
+ }
+
+ /**
+ * Is the current element immediately after a deletion, but itself not a deletion?
+ *
+ * Suppose we are aligning a read with cigar 1M2D3M. This function is true
+ * if we are in the first cigar position of the 3M, but not if we are in the 2D itself or
+ * in any but the first position of the 3M.
+ *
+ * @return true if the previous alignment position is a deletion w.r.t. the reference genome
+ */
+ public boolean isAfterDeletionEnd() {
+ return ! isDeletion() && atStartOfCurrentCigar() && hasOperator(getPreviousOnGenomeCigarElement(), CigarOperator.D);
+ }
+
+ /**
+ * Get the read for this pileup element
+ * @return a non-null GATKSAMRecord
+ */
+ @Ensures("result != null")
+ public GATKSAMRecord getRead() {
+ return read;
+ }
+
+ /**
+ * Get the offset of the this element into the read that aligns that read's base to this genomic position.
+ *
+ * If the current element is a deletion then offset is the offset of the last base containing offset.
+ *
+ * @return a valid offset into the read's bases
+ */
+ @Ensures({"result >= 0", "result <= read.getReadLength()"})
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Get the base aligned to the genome at this location
+ *
+ * If the current element is a deletion returns DELETION_BASE
+ *
+ * @return a base encoded as a byte
+ */
+ @Ensures("result != DELETION_BASE || (isDeletion() && result == DELETION_BASE)")
+ public byte getBase() {
+ return isDeletion() ? DELETION_BASE : read.getReadBases()[offset];
+ }
+
+ @Deprecated
+ public int getBaseIndex() {
+ return BaseUtils.simpleBaseToBaseIndex(getBase());
+ }
+
+ /**
+ * Get the base quality score of the base at this aligned position on the genome
+ * @return a phred-scaled quality score as a byte
+ */
+ public byte getQual() {
+ return isDeletion() ? DELETION_QUAL : read.getBaseQualities()[offset];
+ }
+
+ /**
+ * Get the Base Insertion quality at this pileup position
+ * @return a phred-scaled quality score as a byte
+ */
+ public byte getBaseInsertionQual() {
+ return isDeletion() ? DELETION_QUAL : read.getBaseInsertionQualities()[offset];
+ }
+
+ /**
+ * Get the Base Deletion quality at this pileup position
+ * @return a phred-scaled quality score as a byte
+ */
+ public byte getBaseDeletionQual() {
+ return isDeletion() ? DELETION_QUAL : read.getBaseDeletionQualities()[offset];
+ }
+
+ /**
+ * Get the length of an immediately following insertion or deletion event, or 0 if no such event exists
+ *
+ * Only returns a positive value when this pileup element is immediately before an indel. Being
+ * immediately before a deletion means that this pileup element isn't an deletion, and that the
+ * next genomic alignment for this read is a deletion. For the insertion case, this means
+ * that an insertion cigar occurs immediately after this element, between this one and the
+ * next genomic position.
+ *
+ * Note this function may be expensive, so multiple uses should be cached by the caller
+ *
+ * @return length of the event (number of inserted or deleted bases), or 0
+ */
+ @Ensures("result >= 0")
+ public int getLengthOfImmediatelyFollowingIndel() {
+ final CigarElement element = getNextIndelCigarElement();
+ return element == null ? 0 : element.getLength();
+ }
+
+ /**
+ * Helpful function to get the immediately following cigar element, for an insertion or deletion
+ *
+ * if this state precedes a deletion (i.e., next position on genome) or insertion (immediately between
+ * this and the next position) returns the CigarElement corresponding to this event. Otherwise returns
+ * null.
+ *
+ * @return a CigarElement, or null if the next alignment state ins't an insertion or deletion.
+ */
+ private CigarElement getNextIndelCigarElement() {
+ if ( isBeforeDeletionStart() ) {
+ final CigarElement element = getNextOnGenomeCigarElement();
+ if ( element == null || element.getOperator() != CigarOperator.D )
+ throw new IllegalStateException("Immediately before deletion but the next cigar element isn't a deletion " + element);
+ return element;
+ } else if ( isBeforeInsertion() ) {
+ final CigarElement element = getBetweenNextPosition().get(0);
+ if ( element.getOperator() != CigarOperator.I )
+ throw new IllegalStateException("Immediately before insertion but the next cigar element isn't an insertion " + element);
+ return element;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the bases for an insertion that immediately follows this alignment state, or null if none exists
+ *
+ * @see #getLengthOfImmediatelyFollowingIndel() for details on the meaning of immediately.
+ *
+ * If the immediately following state isn't an insertion, returns null
+ *
+ * @return actual sequence of inserted bases, or a null if the event is a deletion or if there is no event in the associated read.
+ */
+ @Ensures("result == null || result.length() == getLengthOfImmediatelyFollowingIndel()")
+ public String getBasesOfImmediatelyFollowingInsertion() {
+ final CigarElement element = getNextIndelCigarElement();
+ if ( element != null && element.getOperator() == CigarOperator.I ) {
+ final int getFrom = offset + 1;
+ final byte[] bases = Arrays.copyOfRange(read.getReadBases(), getFrom, getFrom + element.getLength());
+ return new String(bases);
+ } else
+ return null;
+ }
+
+ /**
+ * Get the mapping quality of the read of this element
+ * @return the mapping quality of the underlying SAM record
+ */
+ public int getMappingQual() {
+ return read.getMappingQuality();
+ }
+
+ @Ensures("result != null")
+ public String toString() {
+ return String.format("%s @ %d = %c Q%d", getRead().getReadName(), getOffset(), (char) getBase(), getQual());
+ }
+
+ @Override
+ public int compareTo(final PileupElement pileupElement) {
+ if (offset < pileupElement.offset)
+ return -1;
+ else if (offset > pileupElement.offset)
+ return 1;
+ else if (read.getAlignmentStart() < pileupElement.read.getAlignmentStart())
+ return -1;
+ else if (read.getAlignmentStart() > pileupElement.read.getAlignmentStart())
+ return 1;
+ else
+ return 0;
+ }
+
+ // --------------------------------------------------------------------------
+ //
+ // Reduced read accessors
+ //
+ // --------------------------------------------------------------------------
+
+ /**
+ * Get the cigar element aligning this element to the genome
+ * @return a non-null CigarElement
+ */
+ @Ensures("result != null")
+ public CigarElement getCurrentCigarElement() {
+ return currentCigarElement;
+ }
+
+ /**
+ * Get the offset of this cigar element in the Cigar of the current read (0-based)
+ *
+ * Suppose the cigar is 1M2D3I4D. If we are in the 1M state this function returns
+ * 0. If we are in 2D, the result is 1. If we are in the 4D, the result is 3.
+ *
+ * @return an offset into the read.getCigar() that brings us to the current cigar element
+ */
+ public int getCurrentCigarOffset() {
+ return currentCigarOffset;
+ }
+
+ /**
+ * Get the offset into the *current* cigar element for this alignment position
+ *
+ * We can be anywhere from offset 0 (first position) to length - 1 of the current
+ * cigar element aligning us to this genomic position.
+ *
+ * @return a valid offset into the current cigar element
+ */
+ @Ensures({"result >= 0", "result < getCurrentCigarElement().getLength()"})
+ public int getOffsetInCurrentCigar() {
+ return offsetInCurrentCigar;
+ }
+
+ /**
+ * Get the cigar elements that occur before the current position but after the previous position on the genome
+ *
+ * For example, if we are in the 3M state of 1M2I3M state then 2I occurs before this position.
+ *
+ * Note that this function does not care where we are in the current cigar element. In the previous
+ * example this list of elements contains the 2I state regardless of where you are in the 3M.
+ *
+ * Note this returns the list of all elements that occur between this and the prev site, so for
+ * example we might have 5S10I2M and this function would return [5S, 10I].
+ *
+ * @return a non-null list of CigarElements
+ */
+ @Ensures("result != null")
+ public LinkedList<CigarElement> getBetweenPrevPosition() {
+ return atStartOfCurrentCigar() ? getBetween(Direction.PREV) : EMPTY_LINKED_LIST;
+ }
+
+ /**
+ * Get the cigar elements that occur after the current position but before the next position on the genome
+ *
+ * @see #getBetweenPrevPosition() for more details
+ *
+ * @return a non-null list of CigarElements
+ */
+ @Ensures("result != null")
+ public LinkedList<CigarElement> getBetweenNextPosition() {
+ return atEndOfCurrentCigar() ? getBetween(Direction.NEXT) : EMPTY_LINKED_LIST;
+ }
+
+ /** for some helper functions */
+ private enum Direction { PREV, NEXT }
+
+ /**
+ * Helper function to get cigar elements between this and either the prev or next genomic position
+ *
+ * @param direction PREVIOUS if we want before, NEXT if we want after
+ * @return a non-null list of cigar elements between this and the neighboring position in direction
+ */
+ @Ensures("result != null")
+ private LinkedList<CigarElement> getBetween(final Direction direction) {
+ final int increment = direction == Direction.NEXT ? 1 : -1;
+ LinkedList<CigarElement> elements = null;
+ final int nCigarElements = read.getCigarLength();
+ for ( int i = currentCigarOffset + increment; i >= 0 && i < nCigarElements; i += increment) {
+ final CigarElement elt = read.getCigar().getCigarElement(i);
+ if ( ON_GENOME_OPERATORS.contains(elt.getOperator()) )
+ break;
+ else {
+ // optimization: don't allocate list if not necessary
+ if ( elements == null )
+ elements = new LinkedList<CigarElement>();
+
+ if ( increment > 0 )
+ // to keep the list in the right order, if we are incrementing positively add to the end
+ elements.add(elt);
+ else
+ // counting down => add to front
+ elements.addFirst(elt);
+ }
+ }
+
+ // optimization: elements is null because nothing got added, just return the empty list
+ return elements == null ? EMPTY_LINKED_LIST : elements;
+ }
+
+ /**
+ * Get the cigar element of the previous genomic aligned position
+ *
+ * For example, we might have 1M2I3M, and be sitting at the someone in the 3M. This
+ * function would return 1M, as the 2I isn't on the genome. Note this function skips
+ * all of the positions that would occur in the current element. So the result
+ * is always 1M regardless of whether we're in the first, second, or third position of the 3M
+ * cigar.
+ *
+ * @return a CigarElement, or null (indicating that no previous element exists)
+ */
+ @Ensures("result == null || ON_GENOME_OPERATORS.contains(result.getOperator())")
+ public CigarElement getPreviousOnGenomeCigarElement() {
+ return getNeighboringOnGenomeCigarElement(Direction.PREV);
+ }
+
+ /**
+ * Get the cigar element of the next genomic aligned position
+ *
+ * @see #getPreviousOnGenomeCigarElement() for more details
+ *
+ * @return a CigarElement, or null (indicating that no next element exists)
+ */
+ @Ensures("result == null || ON_GENOME_OPERATORS.contains(result.getOperator())")
+ public CigarElement getNextOnGenomeCigarElement() {
+ return getNeighboringOnGenomeCigarElement(Direction.NEXT);
+ }
+
+ /**
+ * Helper function to get the cigar element of the next or previous genomic position
+ * @param direction the direction to look in
+ * @return a CigarElement, or null if no such element exists
+ */
+ @Ensures("result == null || ON_GENOME_OPERATORS.contains(result.getOperator())")
+ private CigarElement getNeighboringOnGenomeCigarElement(final Direction direction) {
+ final int increment = direction == Direction.NEXT ? 1 : -1;
+ final int nCigarElements = read.getCigarLength();
+
+ for ( int i = currentCigarOffset + increment; i >= 0 && i < nCigarElements; i += increment) {
+ final CigarElement elt = read.getCigar().getCigarElement(i);
+ if ( ON_GENOME_OPERATORS.contains(elt.getOperator()) )
+ return elt;
+ }
+
+ // getting here means that you didn't find anything
+ return null;
+ }
+
+ /**
+ * Does the cigar element (which may be null) have operation toMatch?
+ *
+ * @param maybeCigarElement a CigarElement that might be null
+ * @param toMatch a CigarOperator we want to match against the one in maybeCigarElement
+ * @return true if maybeCigarElement isn't null and has operator toMatch
+ */
+ @Requires("toMatch != null")
+ private boolean hasOperator(final CigarElement maybeCigarElement, final CigarOperator toMatch) {
+ return maybeCigarElement != null && maybeCigarElement.getOperator() == toMatch;
+ }
+
+ /**
+ * Does an insertion occur immediately before the current position on the genome?
+ *
+ * @return true if yes, false if no
+ */
+ public boolean isAfterInsertion() { return isAfter(getBetweenPrevPosition(), CigarOperator.I); }
+
+ /**
+ * Does an insertion occur immediately after the current position on the genome?
+ *
+ * @return true if yes, false if no
+ */
+ public boolean isBeforeInsertion() { return isBefore(getBetweenNextPosition(), CigarOperator.I); }
+
+ /**
+ * Does a soft-clipping event occur immediately before the current position on the genome?
+ *
+ * @return true if yes, false if no
+ */
+ public boolean isAfterSoftClip() { return isAfter(getBetweenPrevPosition(), CigarOperator.S); }
+
+ /**
+ * Does a soft-clipping event occur immediately after the current position on the genome?
+ *
+ * @return true if yes, false if no
+ */
+ public boolean isBeforeSoftClip() { return isBefore(getBetweenNextPosition(), CigarOperator.S); }
+
+ /**
+ * Does a soft-clipping event occur immediately before or after the current position on the genome?
+ *
+ * @return true if yes, false if no
+ */
+ public boolean isNextToSoftClip() { return isAfterSoftClip() || isBeforeSoftClip(); }
+
+ /**
+ * Is the current position at the end of the current cigar?
+ *
+ * For example, if we are in element 3M, this function returns true if we are at offsetInCurrentCigar
+ * of 2, but not 0 or 1.
+ *
+ * @return true if we're at the end of the current cigar
+ */
+ public boolean atEndOfCurrentCigar() {
+ return offsetInCurrentCigar == currentCigarElement.getLength() - 1;
+ }
+
+ /**
+ * Is the current position at the start of the current cigar?
+ *
+ * For example, if we are in element 3M, this function returns true if we are at offsetInCurrentCigar
+ * of 0, but not 1 or 2.
+ *
+ * @return true if we're at the start of the current cigar
+ */
+ public boolean atStartOfCurrentCigar() {
+ return offsetInCurrentCigar == 0;
+ }
+
+ /**
+ * Is op the last element in the list of elements?
+ *
+ * @param elements the elements to examine
+ * @param op the op we want the last element's op to equal
+ * @return true if op == last(elements).op
+ */
+ @Requires({"elements != null", "op != null"})
+ private boolean isAfter(final LinkedList<CigarElement> elements, final CigarOperator op) {
+ return ! elements.isEmpty() && elements.peekLast().getOperator() == op;
+ }
+
+ /**
+ * Is op the first element in the list of elements?
+ *
+ * @param elements the elements to examine
+ * @param op the op we want the last element's op to equal
+ * @return true if op == first(elements).op
+ */
+ @Requires({"elements != null", "op != null"})
+ private boolean isBefore(final List<CigarElement> elements, final CigarOperator op) {
+ return ! elements.isEmpty() && elements.get(0).getOperator() == op;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/PileupElementFilter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/PileupElementFilter.java
new file mode 100644
index 0000000..7f82709
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/PileupElementFilter.java
@@ -0,0 +1,36 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pileup;
+
+/**
+ * A filtering interface for pileup elements.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public interface PileupElementFilter {
+ public boolean allow(final PileupElement pileupElement);
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/PileupElementTracker.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/PileupElementTracker.java
new file mode 100644
index 0000000..7d49fcc
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/PileupElementTracker.java
@@ -0,0 +1,154 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pileup;
+
+import org.apache.commons.collections.iterators.IteratorChain;
+
+import java.util.*;
+
+/**
+ * Javadoc goes here.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+abstract class PileupElementTracker<PE extends PileupElement> implements Iterable<PE> {
+ public abstract int size();
+
+ /**
+ * Iterate through the PEs here, but in any order, which may improve performance
+ * if you don't care about the underlying order the reads are coming to you in.
+ * @return an iteratable over all pileup elements in this tracker
+ */
+ public abstract Iterable<PE> unorderedIterable();
+
+ /**
+ * Same as @see #unorderedIterable but the actual iterator itself
+ * @return
+ */
+ public Iterator<PE> unorderedIterator() { return unorderedIterable().iterator(); }
+
+ public abstract PileupElementTracker<PE> copy();
+}
+
+class UnifiedPileupElementTracker<PE extends PileupElement> extends PileupElementTracker<PE> {
+ private final List<PE> pileup;
+
+ @Override
+ public UnifiedPileupElementTracker<PE> copy() {
+ UnifiedPileupElementTracker<PE> result = new UnifiedPileupElementTracker<PE>();
+ for(PE element : pileup)
+ result.add(element);
+ return result;
+ }
+
+ public UnifiedPileupElementTracker() { pileup = new LinkedList<PE>(); }
+ public UnifiedPileupElementTracker(List<PE> pileup) { this.pileup = pileup; }
+
+ public void add(PE element) {
+ pileup.add(element);
+ }
+
+ public PE get(int index) {
+ return pileup.get(index);
+ }
+
+ public int size() {
+ return pileup.size();
+ }
+
+ public Iterator<PE> iterator() { return pileup.iterator(); }
+ public Iterable<PE> unorderedIterable() { return this; }
+}
+
+class PerSamplePileupElementTracker<PE extends PileupElement> extends PileupElementTracker<PE> {
+ private final Map<String,PileupElementTracker<PE>> pileup;
+ private int size = 0;
+
+ public PerSamplePileupElementTracker() {
+ pileup = new HashMap<String,PileupElementTracker<PE>>();
+ }
+
+ public PerSamplePileupElementTracker<PE> copy() {
+ PerSamplePileupElementTracker<PE> result = new PerSamplePileupElementTracker<PE>();
+ for (Map.Entry<String, PileupElementTracker<PE>> entry : pileup.entrySet())
+ result.addElements(entry.getKey(), entry.getValue());
+
+ return result;
+ }
+
+ /**
+ * Gets a list of all the samples stored in this pileup.
+ * @return List of samples in this pileup.
+ */
+ public Collection<String> getSamples() {
+ return pileup.keySet();
+ }
+
+ public PileupElementTracker<PE> getElements(final String sample) {
+ return pileup.get(sample);
+ }
+
+ public PileupElementTracker<PE> getElements(final Collection<String> selectSampleNames) {
+ PerSamplePileupElementTracker<PE> result = new PerSamplePileupElementTracker<PE>();
+ for (final String sample : selectSampleNames) {
+ result.addElements(sample, pileup.get(sample));
+ }
+ return result;
+ }
+
+ public void addElements(final String sample, PileupElementTracker<PE> elements) {
+ pileup.put(sample,elements);
+ size += elements.size();
+ }
+
+ public Iterator<PE> iterator() { return new MergingPileupElementIterator<PE>(this); }
+
+ public int size() {
+ return size;
+ }
+
+
+ public Iterable<PE> unorderedIterable() {
+ return new Iterable<PE>() {
+ @Override
+ public Iterator<PE> iterator() {
+ return new Iterator<PE>() {
+ final private IteratorChain chain = new IteratorChain();
+
+ { // initialize the chain with the unordered iterators of the per sample pileups
+ for ( PileupElementTracker<PE> pet : pileup.values() ) {
+ chain.addIterator(pet.unorderedIterator());
+ }
+ }
+ @Override public boolean hasNext() { return chain.hasNext(); }
+ @Override public PE next() { return (PE)chain.next(); }
+ @Override public void remove() { throw new UnsupportedOperationException("Cannot remove"); }
+ };
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/ReadBackedPileup.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/ReadBackedPileup.java
new file mode 100644
index 0000000..e4394f1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/ReadBackedPileup.java
@@ -0,0 +1,295 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pileup;
+
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.HasGenomeLocation;
+import org.broadinstitute.gatk.utils.fragments.FragmentCollection;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A data retrieval interface for accessing parts of the pileup.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public interface ReadBackedPileup extends Iterable<PileupElement>, HasGenomeLocation {
+ /**
+ * Returns a new ReadBackedPileup that is free of deletion spanning reads in this pileup. Note that this
+ * does not copy the data, so both ReadBackedPileups should not be changed. Doesn't make an unnecessary copy
+ * of the pileup (just returns this) if there are no deletions in the pileup.
+ *
+ * @return
+ */
+ public ReadBackedPileup getPileupWithoutDeletions();
+
+ /**
+ * Returns a new ReadBackedPileup where only one read from an overlapping read
+ * pair is retained. If the two reads in question disagree to their basecall,
+ * neither read is retained. If they agree on the base, the read with the higher
+ * quality observation is retained
+ *
+ * @return the newly filtered pileup
+ */
+ public ReadBackedPileup getOverlappingFragmentFilteredPileup();
+
+ /**
+ * Returns a new ReadBackedPileup where only one read from an overlapping read
+ * pair is retained. If discardDiscordant and the two reads in question disagree to their basecall,
+ * neither read is retained. Otherwise, the read with the higher
+ * quality (base or mapping, depending on baseQualNotMapQual) observation is retained
+ *
+ * @return the newly filtered pileup
+ */
+ public ReadBackedPileup getOverlappingFragmentFilteredPileup(boolean discardDiscordant, boolean baseQualNotMapQual);
+
+ /**
+ * Returns a new ReadBackedPileup that is free of mapping quality zero reads in this pileup. Note that this
+ * does not copy the data, so both ReadBackedPileups should not be changed. Doesn't make an unnecessary copy
+ * of the pileup (just returns this) if there are no MQ0 reads in the pileup.
+ *
+ * @return
+ */
+ public ReadBackedPileup getPileupWithoutMappingQualityZeroReads();
+
+ /**
+ * Gets the pileup consisting of only reads on the positive strand.
+ * @return A read-backed pileup consisting only of reads on the positive strand.
+ */
+ public ReadBackedPileup getPositiveStrandPileup();
+
+ /**
+ * Gets the pileup consisting of only reads on the negative strand.
+ * @return A read-backed pileup consisting only of reads on the negative strand.
+ */
+ public ReadBackedPileup getNegativeStrandPileup();
+
+ /**
+ * Gets a pileup consisting of all those elements passed by a given filter.
+ * @param filter Filter to use when testing for elements.
+ * @return a pileup without the given filtered elements.
+ */
+ public ReadBackedPileup getFilteredPileup(PileupElementFilter filter);
+
+ /** Returns subset of this pileup that contains only bases with quality >= minBaseQ, coming from
+ * reads with mapping qualities >= minMapQ. This method allocates and returns a new instance of ReadBackedPileup.
+ * @param minBaseQ
+ * @param minMapQ
+ * @return
+ */
+ public ReadBackedPileup getBaseAndMappingFilteredPileup( int minBaseQ, int minMapQ );
+
+ /** Returns subset of this pileup that contains only bases with quality >= minBaseQ.
+ * This method allocates and returns a new instance of ReadBackedPileup.
+ * @param minBaseQ
+ * @return
+ */
+ public ReadBackedPileup getBaseFilteredPileup( int minBaseQ );
+
+ /** Returns subset of this pileup that contains only bases coming from reads with mapping quality >= minMapQ.
+ * This method allocates and returns a new instance of ReadBackedPileup.
+ * @param minMapQ
+ * @return
+ */
+ public ReadBackedPileup getMappingFilteredPileup( int minMapQ );
+
+ /**
+ * Returns a pileup randomly downsampled to the desiredCoverage.
+ *
+ * @param desiredCoverage
+ * @return
+ */
+ public ReadBackedPileup getDownsampledPileup(int desiredCoverage);
+
+ /**
+ * Gets a collection of all the read groups represented in this pileup.
+ * @return A collection of all the read group ids represented in this pileup.
+ */
+ public Collection<String> getReadGroups();
+
+ /**
+ * Gets all the reads associated with a given read group.
+ * @param readGroupId Identifier for the read group.
+ * @return A pileup containing only the reads in the given read group.
+ */
+ public ReadBackedPileup getPileupForReadGroup(String readGroupId);
+
+ /**
+ * Gets all the reads associated with a given read groups.
+ * @param rgSet Set of identifiers for the read group.
+ * @return A pileup containing only the reads in the given read groups.
+ */
+ public ReadBackedPileup getPileupForReadGroups(final HashSet<String> rgSet);
+
+ /**
+ * Gets all reads in a given lane id. (Lane ID is the read group
+ * id stripped of the last .XX sample identifier added by the GATK).
+ * @param laneID The read group ID without the sample identifier added by the GATK.
+ * @return A pileup containing the reads from all samples in the given lane.
+ */
+ public ReadBackedPileup getPileupForLane(String laneID);
+
+ /**
+ * Gets a collection of *names* of all the samples stored in this pileup.
+ * @return Collection of names
+ */
+ public Collection<String> getSamples();
+
+
+ /**
+ * Gets the particular subset of this pileup for all the given sample names.
+ * @param sampleNames Name of the sample to use.
+ * @return A subset of this pileup containing only reads with the given sample.
+ */
+ public ReadBackedPileup getPileupForSamples(Collection<String> sampleNames);
+
+ /**
+ * Gets the particular subset of this pileup for each given sample name.
+ *
+ * Same as calling getPileupForSample for all samples, but in O(n) instead of O(n^2).
+ *
+ * @param sampleNames Name of the sample to use.
+ * @return A subset of this pileup containing only reads with the given sample.
+ */
+ public Map<String, ReadBackedPileup> getPileupsForSamples(Collection<String> sampleNames);
+
+
+ /**
+ * Gets the particular subset of this pileup with the given sample name.
+ * @param sampleName Name of the sample to use.
+ * @return A subset of this pileup containing only reads with the given sample.
+ */
+ public ReadBackedPileup getPileupForSample(String sampleName);
+
+ /**
+ * Simple useful routine to count the number of deletion bases in this pileup
+ *
+ * @return
+ */
+ public int getNumberOfDeletions();
+
+ /**
+ * Simple useful routine to count the number of deletion bases in at the next position this pileup
+ *
+ * @return
+ */
+ public int getNumberOfDeletionsAfterThisElement();
+
+ /**
+ * Simple useful routine to count the number of insertions right after this pileup
+ *
+ * @return
+ */
+ public int getNumberOfInsertionsAfterThisElement();
+
+ public int getNumberOfMappingQualityZeroReads();
+
+ /**
+ * @return the number of physical elements in this pileup (a reduced read is counted just once)
+ */
+ public int getNumberOfElements();
+
+ /**
+ * @return the number of abstract elements in this pileup (reduced reads are expanded to count all reads that they represent)
+ */
+ public int depthOfCoverage();
+
+ /**
+ * @return true if there are 0 elements in the pileup, false otherwise
+ */
+ public boolean isEmpty();
+
+ /**
+ * @return the location of this pileup
+ */
+ public GenomeLoc getLocation();
+
+ /**
+ * Get counts of A, C, G, T in order, which returns a int[4] vector with counts according
+ * to BaseUtils.simpleBaseToBaseIndex for each base.
+ *
+ * @return
+ */
+ public int[] getBaseCounts();
+
+ public String getPileupString(Character ref);
+
+ /**
+ * Returns a list of the reads in this pileup. Note this call costs O(n) and allocates fresh lists each time
+ * @return
+ */
+ public List<GATKSAMRecord> getReads();
+
+ /**
+ * Returns a list of the offsets in this pileup. Note this call costs O(n) and allocates fresh lists each time
+ * @return
+ */
+ public List<Integer> getOffsets();
+
+ /**
+ * Returns an array of the bases in this pileup. Note this call costs O(n) and allocates fresh array each time
+ * @return
+ */
+ public byte[] getBases();
+
+ /**
+ * Returns an array of the quals in this pileup. Note this call costs O(n) and allocates fresh array each time
+ * @return
+ */
+ public byte[] getQuals();
+
+ /**
+ * Get an array of the mapping qualities
+ * @return
+ */
+ public int[] getMappingQuals();
+
+ /**
+ * Returns a new ReadBackedPileup that is sorted by start coordinate of the reads.
+ *
+ * @return
+ */
+ public ReadBackedPileup getStartSortedPileup();
+
+ /**
+ * Converts this pileup into a FragmentCollection (see FragmentUtils for documentation)
+ * @return
+ */
+ public FragmentCollection<PileupElement> toFragments();
+
+ /**
+ * Creates a full copy (not shallow) of the ReadBacked Pileup
+ *
+ * @return
+ */
+ public ReadBackedPileup copy();
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/ReadBackedPileupImpl.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/ReadBackedPileupImpl.java
new file mode 100644
index 0000000..840fbeb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup/ReadBackedPileupImpl.java
@@ -0,0 +1,1040 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pileup;
+
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.fragments.FragmentCollection;
+import org.broadinstitute.gatk.utils.fragments.FragmentUtils;
+import org.broadinstitute.gatk.utils.locusiterator.LocusIteratorByState;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.BaseUtils;
+
+import java.util.*;
+
+public class ReadBackedPileupImpl implements ReadBackedPileup {
+ protected final GenomeLoc loc;
+ protected final PileupElementTracker<PileupElement> pileupElementTracker;
+
+ private final static int UNINITIALIZED_CACHED_INT_VALUE = -1;
+
+ /**
+ * Different then number of elements due to reduced reads
+ */
+ private int depthOfCoverage = UNINITIALIZED_CACHED_INT_VALUE;
+ private int nDeletions = UNINITIALIZED_CACHED_INT_VALUE; // cached value of the number of deletions
+ private int nMQ0Reads = UNINITIALIZED_CACHED_INT_VALUE; // cached value of the number of MQ0 reads
+
+ /**
+ * Create a new version of a read backed pileup at loc, using the reads and their corresponding
+ * offsets. This pileup will contain a list, in order of the reads, of the piled bases at
+ * reads[i] for all i in offsets. Does not make a copy of the data, so it's not safe to
+ * go changing the reads.
+ *
+ * @param loc The genome loc to associate reads wotj
+ * @param reads
+ * @param offsets
+ */
+ public ReadBackedPileupImpl(GenomeLoc loc, List<GATKSAMRecord> reads, List<Integer> offsets) {
+ this.loc = loc;
+ this.pileupElementTracker = readsOffsets2Pileup(reads, offsets);
+ }
+
+
+ /**
+ * Create a new version of a read backed pileup at loc without any aligned reads
+ */
+ public ReadBackedPileupImpl(GenomeLoc loc) {
+ this(loc, new UnifiedPileupElementTracker<PileupElement>());
+ }
+
+ /**
+ * Create a new version of a read backed pileup at loc, using the reads and their corresponding
+ * offsets. This lower level constructure assumes pileup is well-formed and merely keeps a
+ * pointer to pileup. Don't go changing the data in pileup.
+ */
+ public ReadBackedPileupImpl(GenomeLoc loc, List<PileupElement> pileup) {
+ if (loc == null) throw new ReviewedGATKException("Illegal null genomeloc in ReadBackedPileup");
+ if (pileup == null) throw new ReviewedGATKException("Illegal null pileup in ReadBackedPileup");
+
+ this.loc = loc;
+ this.pileupElementTracker = new UnifiedPileupElementTracker<PileupElement>(pileup);
+ }
+
+ /**
+ * Optimization of above constructor where all of the cached data is provided
+ *
+ * @param loc
+ * @param pileup
+ */
+ @Deprecated
+ public ReadBackedPileupImpl(GenomeLoc loc, List<PileupElement> pileup, int size, int nDeletions, int nMQ0Reads) {
+ this(loc, pileup);
+ }
+
+ protected ReadBackedPileupImpl(GenomeLoc loc, PileupElementTracker<PileupElement> tracker) {
+ this.loc = loc;
+ this.pileupElementTracker = tracker;
+ }
+
+ public ReadBackedPileupImpl(GenomeLoc loc, Map<String, ReadBackedPileupImpl> pileupsBySample) {
+ this.loc = loc;
+ PerSamplePileupElementTracker<PileupElement> tracker = new PerSamplePileupElementTracker<PileupElement>();
+ for (Map.Entry<String, ReadBackedPileupImpl> pileupEntry : pileupsBySample.entrySet()) {
+ tracker.addElements(pileupEntry.getKey(), pileupEntry.getValue().pileupElementTracker);
+ }
+ this.pileupElementTracker = tracker;
+ }
+
+ public ReadBackedPileupImpl(GenomeLoc loc, List<GATKSAMRecord> reads, int offset) {
+ this.loc = loc;
+ this.pileupElementTracker = readsOffsets2Pileup(reads, offset);
+ }
+
+ /**
+ * Helper routine for converting reads and offset lists to a PileupElement list.
+ *
+ * @param reads
+ * @param offsets
+ * @return
+ */
+ private PileupElementTracker<PileupElement> readsOffsets2Pileup(List<GATKSAMRecord> reads, List<Integer> offsets) {
+ if (reads == null) throw new ReviewedGATKException("Illegal null read list in UnifiedReadBackedPileup");
+ if (offsets == null) throw new ReviewedGATKException("Illegal null offsets list in UnifiedReadBackedPileup");
+ if (reads.size() != offsets.size())
+ throw new ReviewedGATKException("Reads and offset lists have different sizes!");
+
+ UnifiedPileupElementTracker<PileupElement> pileup = new UnifiedPileupElementTracker<PileupElement>();
+ for (int i = 0; i < reads.size(); i++) {
+ GATKSAMRecord read = reads.get(i);
+ int offset = offsets.get(i);
+ pileup.add(createNewPileupElement(read, offset)); // only used to create fake pileups for testing so ancillary information is not important
+ }
+
+ return pileup;
+ }
+
+ /**
+ * Helper routine for converting reads and a single offset to a PileupElement list.
+ *
+ * @param reads
+ * @param offset
+ * @return
+ */
+ private PileupElementTracker<PileupElement> readsOffsets2Pileup(List<GATKSAMRecord> reads, int offset) {
+ if (reads == null) throw new ReviewedGATKException("Illegal null read list in UnifiedReadBackedPileup");
+ if (offset < 0) throw new ReviewedGATKException("Illegal offset < 0 UnifiedReadBackedPileup");
+
+ UnifiedPileupElementTracker<PileupElement> pileup = new UnifiedPileupElementTracker<PileupElement>();
+ for (GATKSAMRecord read : reads) {
+ pileup.add(createNewPileupElement(read, offset)); // only used to create fake pileups for testing so ancillary information is not important
+ }
+
+ return pileup;
+ }
+
+ protected ReadBackedPileupImpl createNewPileup(GenomeLoc loc, PileupElementTracker<PileupElement> tracker) {
+ return new ReadBackedPileupImpl(loc, tracker);
+ }
+
+ protected PileupElement createNewPileupElement(GATKSAMRecord read, int offset) {
+ return LocusIteratorByState.createPileupForReadAndOffset(read, offset);
+ }
+
+ // --------------------------------------------------------
+ //
+ // Special 'constructors'
+ //
+ // --------------------------------------------------------
+
+ /**
+ * Returns a new ReadBackedPileup that is free of deletion spanning reads in this pileup. Note that this
+ * does not copy the data, so both ReadBackedPileups should not be changed. Doesn't make an unnecessary copy
+ * of the pileup (just returns this) if there are no deletions in the pileup.
+ *
+ * @return
+ */
+ @Override
+ public ReadBackedPileupImpl getPileupWithoutDeletions() {
+ if (getNumberOfDeletions() > 0) {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PerSamplePileupElementTracker<PileupElement> filteredTracker = new PerSamplePileupElementTracker<PileupElement>();
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+ ReadBackedPileupImpl pileup = createNewPileup(loc, perSampleElements).getPileupWithoutDeletions();
+ filteredTracker.addElements(sample, pileup.pileupElementTracker);
+ }
+ return createNewPileup(loc, filteredTracker);
+
+ } else {
+ UnifiedPileupElementTracker<PileupElement> tracker = (UnifiedPileupElementTracker<PileupElement>) pileupElementTracker;
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+
+ for (PileupElement p : tracker) {
+ if (!p.isDeletion()) {
+ filteredTracker.add(p);
+ }
+ }
+ return createNewPileup(loc, filteredTracker);
+ }
+ } else {
+ return this;
+ }
+ }
+
+ /**
+ * Returns a new ReadBackedPileup where only one read from an overlapping read
+ * pair is retained. If the two reads in question disagree to their basecall,
+ * neither read is retained. If they agree on the base, the read with the higher
+ * base quality observation is retained
+ *
+ * @return the newly filtered pileup
+ */
+ @Override
+ public ReadBackedPileup getOverlappingFragmentFilteredPileup() {
+ return getOverlappingFragmentFilteredPileup(true, true);
+ }
+
+ /**
+ * Returns a new ReadBackedPileup where only one read from an overlapping read
+ * pair is retained. If discardDiscordant and the two reads in question disagree to their basecall,
+ * neither read is retained. Otherwise, the read with the higher
+ * quality (base or mapping, depending on baseQualNotMapQual) observation is retained
+ *
+ * @return the newly filtered pileup
+ */
+ @Override
+ public ReadBackedPileupImpl getOverlappingFragmentFilteredPileup(boolean discardDiscordant, boolean baseQualNotMapQual) {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PerSamplePileupElementTracker<PileupElement> filteredTracker = new PerSamplePileupElementTracker<PileupElement>();
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+ ReadBackedPileupImpl pileup = createNewPileup(loc, perSampleElements).getOverlappingFragmentFilteredPileup(discardDiscordant, baseQualNotMapQual);
+ filteredTracker.addElements(sample, pileup.pileupElementTracker);
+ }
+ return createNewPileup(loc, filteredTracker);
+ } else {
+ Map<String, PileupElement> filteredPileup = new HashMap<String, PileupElement>();
+
+ for (PileupElement p : pileupElementTracker) {
+ String readName = p.getRead().getReadName();
+
+ // if we've never seen this read before, life is good
+ if (!filteredPileup.containsKey(readName)) {
+ filteredPileup.put(readName, p);
+ } else {
+ PileupElement existing = filteredPileup.get(readName);
+
+ // if the reads disagree at this position, throw them both out. Otherwise
+ // keep the element with the higher quality score
+ if (discardDiscordant && existing.getBase() != p.getBase()) {
+ filteredPileup.remove(readName);
+ } else {
+ if (baseQualNotMapQual) {
+ if (existing.getQual() < p.getQual())
+ filteredPileup.put(readName, p);
+ }
+ else {
+ if (existing.getMappingQual() < p.getMappingQual())
+ filteredPileup.put(readName, p);
+ }
+ }
+ }
+ }
+
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+ for (PileupElement filteredElement : filteredPileup.values())
+ filteredTracker.add(filteredElement);
+
+ return createNewPileup(loc, filteredTracker);
+ }
+ }
+
+
+ /**
+ * Returns a new ReadBackedPileup that is free of mapping quality zero reads in this pileup. Note that this
+ * does not copy the data, so both ReadBackedPileups should not be changed. Doesn't make an unnecessary copy
+ * of the pileup (just returns this) if there are no MQ0 reads in the pileup.
+ *
+ * @return
+ */
+ @Override
+ public ReadBackedPileupImpl getPileupWithoutMappingQualityZeroReads() {
+ if (getNumberOfMappingQualityZeroReads() > 0) {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PerSamplePileupElementTracker<PileupElement> filteredTracker = new PerSamplePileupElementTracker<PileupElement>();
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+ ReadBackedPileupImpl pileup = createNewPileup(loc, perSampleElements).getPileupWithoutMappingQualityZeroReads();
+ filteredTracker.addElements(sample, pileup.pileupElementTracker);
+ }
+ return createNewPileup(loc, filteredTracker);
+
+ } else {
+ UnifiedPileupElementTracker<PileupElement> tracker = (UnifiedPileupElementTracker<PileupElement>) pileupElementTracker;
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+
+ for (PileupElement p : tracker) {
+ if (p.getRead().getMappingQuality() > 0) {
+ filteredTracker.add(p);
+ }
+ }
+ return createNewPileup(loc, filteredTracker);
+ }
+ } else {
+ return this;
+ }
+ }
+
+ public ReadBackedPileupImpl getPositiveStrandPileup() {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PerSamplePileupElementTracker<PileupElement> filteredTracker = new PerSamplePileupElementTracker<PileupElement>();
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+ ReadBackedPileupImpl pileup = createNewPileup(loc, perSampleElements).getPositiveStrandPileup();
+ filteredTracker.addElements(sample, pileup.pileupElementTracker);
+ }
+ return createNewPileup(loc, filteredTracker);
+ } else {
+ UnifiedPileupElementTracker<PileupElement> tracker = (UnifiedPileupElementTracker<PileupElement>) pileupElementTracker;
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+
+ for (PileupElement p : tracker) {
+ if (!p.getRead().getReadNegativeStrandFlag()) {
+ filteredTracker.add(p);
+ }
+ }
+ return createNewPileup(loc, filteredTracker);
+ }
+ }
+
+ /**
+ * Gets the pileup consisting of only reads on the negative strand.
+ *
+ * @return A read-backed pileup consisting only of reads on the negative strand.
+ */
+ public ReadBackedPileupImpl getNegativeStrandPileup() {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PerSamplePileupElementTracker<PileupElement> filteredTracker = new PerSamplePileupElementTracker<PileupElement>();
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+ ReadBackedPileupImpl pileup = createNewPileup(loc, perSampleElements).getNegativeStrandPileup();
+ filteredTracker.addElements(sample, pileup.pileupElementTracker);
+ }
+ return createNewPileup(loc, filteredTracker);
+ } else {
+ UnifiedPileupElementTracker<PileupElement> tracker = (UnifiedPileupElementTracker<PileupElement>) pileupElementTracker;
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+
+ for (PileupElement p : tracker) {
+ if (p.getRead().getReadNegativeStrandFlag()) {
+ filteredTracker.add(p);
+ }
+ }
+ return createNewPileup(loc, filteredTracker);
+ }
+ }
+
+ /**
+ * Gets a pileup consisting of all those elements passed by a given filter.
+ *
+ * @param filter Filter to use when testing for elements.
+ * @return a pileup without the given filtered elements.
+ */
+ public ReadBackedPileupImpl getFilteredPileup(PileupElementFilter filter) {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PerSamplePileupElementTracker<PileupElement> filteredTracker = new PerSamplePileupElementTracker<PileupElement>();
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+ ReadBackedPileupImpl pileup = createNewPileup(loc, perSampleElements).getFilteredPileup(filter);
+ filteredTracker.addElements(sample, pileup.pileupElementTracker);
+ }
+
+ return createNewPileup(loc, filteredTracker);
+ } else {
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+
+ for (PileupElement p : pileupElementTracker) {
+ if (filter.allow(p))
+ filteredTracker.add(p);
+ }
+
+ return createNewPileup(loc, filteredTracker);
+ }
+ }
+
+ /**
+ * Returns subset of this pileup that contains only bases with quality >= minBaseQ, coming from
+ * reads with mapping qualities >= minMapQ. This method allocates and returns a new instance of ReadBackedPileup.
+ *
+ * @param minBaseQ
+ * @param minMapQ
+ * @return
+ */
+ @Override
+ public ReadBackedPileupImpl getBaseAndMappingFilteredPileup(int minBaseQ, int minMapQ) {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PerSamplePileupElementTracker<PileupElement> filteredTracker = new PerSamplePileupElementTracker<PileupElement>();
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+ ReadBackedPileupImpl pileup = createNewPileup(loc, perSampleElements).getBaseAndMappingFilteredPileup(minBaseQ, minMapQ);
+ filteredTracker.addElements(sample, pileup.pileupElementTracker);
+ }
+
+ return createNewPileup(loc, filteredTracker);
+ } else {
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+
+ for (PileupElement p : pileupElementTracker) {
+ if (p.getRead().getMappingQuality() >= minMapQ && (p.isDeletion() || p.getQual() >= minBaseQ)) {
+ filteredTracker.add(p);
+ }
+ }
+
+ return createNewPileup(loc, filteredTracker);
+ }
+ }
+
+ /**
+ * Returns subset of this pileup that contains only bases with quality >= minBaseQ.
+ * This method allocates and returns a new instance of ReadBackedPileup.
+ *
+ * @param minBaseQ
+ * @return
+ */
+ @Override
+ public ReadBackedPileup getBaseFilteredPileup(int minBaseQ) {
+ return getBaseAndMappingFilteredPileup(minBaseQ, -1);
+ }
+
+ /**
+ * Returns subset of this pileup that contains only bases coming from reads with mapping quality >= minMapQ.
+ * This method allocates and returns a new instance of ReadBackedPileup.
+ *
+ * @param minMapQ
+ * @return
+ */
+ @Override
+ public ReadBackedPileup getMappingFilteredPileup(int minMapQ) {
+ return getBaseAndMappingFilteredPileup(-1, minMapQ);
+ }
+
+ /**
+ * Gets a list of the read groups represented in this pileup.
+ *
+ * @return
+ */
+ @Override
+ public Collection<String> getReadGroups() {
+ Set<String> readGroups = new HashSet<String>();
+ for (PileupElement pileupElement : this)
+ readGroups.add(pileupElement.getRead().getReadGroup().getReadGroupId());
+ return readGroups;
+ }
+
+ /**
+ * Gets the pileup for a given read group. Horrendously inefficient at this point.
+ *
+ * @param targetReadGroupId Identifier for the read group.
+ * @return A read-backed pileup containing only the reads in the given read group.
+ */
+ @Override
+ public ReadBackedPileupImpl getPileupForReadGroup(String targetReadGroupId) {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PerSamplePileupElementTracker<PileupElement> filteredTracker = new PerSamplePileupElementTracker<PileupElement>();
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+ ReadBackedPileupImpl pileup = createNewPileup(loc, perSampleElements).getPileupForReadGroup(targetReadGroupId);
+ if (pileup != null)
+ filteredTracker.addElements(sample, pileup.pileupElementTracker);
+ }
+ return filteredTracker.size() > 0 ? createNewPileup(loc, filteredTracker) : null;
+ } else {
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+ for (PileupElement p : pileupElementTracker) {
+ GATKSAMRecord read = p.getRead();
+ if (targetReadGroupId != null) {
+ if (read.getReadGroup() != null && targetReadGroupId.equals(read.getReadGroup().getReadGroupId()))
+ filteredTracker.add(p);
+ } else {
+ if (read.getReadGroup() == null || read.getReadGroup().getReadGroupId() == null)
+ filteredTracker.add(p);
+ }
+ }
+ return filteredTracker.size() > 0 ? createNewPileup(loc, filteredTracker) : null;
+ }
+ }
+
+ /**
+ * Gets the pileup for a set of read groups. Horrendously inefficient at this point.
+ *
+ * @param rgSet List of identifiers for the read groups.
+ * @return A read-backed pileup containing only the reads in the given read groups.
+ */
+ @Override
+ public ReadBackedPileupImpl getPileupForReadGroups(final HashSet<String> rgSet) {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PerSamplePileupElementTracker<PileupElement> filteredTracker = new PerSamplePileupElementTracker<PileupElement>();
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+ ReadBackedPileupImpl pileup = createNewPileup(loc, perSampleElements).getPileupForReadGroups(rgSet);
+ if (pileup != null)
+ filteredTracker.addElements(sample, pileup.pileupElementTracker);
+ }
+ return filteredTracker.size() > 0 ? createNewPileup(loc, filteredTracker) : null;
+ } else {
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+ for (PileupElement p : pileupElementTracker) {
+ GATKSAMRecord read = p.getRead();
+ if (rgSet != null && !rgSet.isEmpty()) {
+ if (read.getReadGroup() != null && rgSet.contains(read.getReadGroup().getReadGroupId()))
+ filteredTracker.add(p);
+ } else {
+ if (read.getReadGroup() == null || read.getReadGroup().getReadGroupId() == null)
+ filteredTracker.add(p);
+ }
+ }
+ return filteredTracker.size() > 0 ? createNewPileup(loc, filteredTracker) : null;
+ }
+ }
+
+ @Override
+ public ReadBackedPileupImpl getPileupForLane(String laneID) {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PerSamplePileupElementTracker<PileupElement> filteredTracker = new PerSamplePileupElementTracker<PileupElement>();
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+ ReadBackedPileupImpl pileup = createNewPileup(loc, perSampleElements).getPileupForLane(laneID);
+ if (pileup != null)
+ filteredTracker.addElements(sample, pileup.pileupElementTracker);
+ }
+ return filteredTracker.size() > 0 ? createNewPileup(loc, filteredTracker) : null;
+ } else {
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+ for (PileupElement p : pileupElementTracker) {
+ GATKSAMRecord read = p.getRead();
+ if (laneID != null) {
+ if (read.getReadGroup() != null &&
+ (read.getReadGroup().getReadGroupId().startsWith(laneID + ".")) || // lane is the same, but sample identifier is different
+ (read.getReadGroup().getReadGroupId().equals(laneID))) // in case there is no sample identifier, they have to be exactly the same
+ filteredTracker.add(p);
+ } else {
+ if (read.getReadGroup() == null || read.getReadGroup().getReadGroupId() == null)
+ filteredTracker.add(p);
+ }
+ }
+ return filteredTracker.size() > 0 ? createNewPileup(loc, filteredTracker) : null;
+ }
+ }
+
+ public Collection<String> getSamples() {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ return new HashSet<String>(tracker.getSamples());
+ } else {
+ Collection<String> sampleNames = new HashSet<String>();
+ for (PileupElement p : this) {
+ GATKSAMRecord read = p.getRead();
+ String sampleName = read.getReadGroup() != null ? read.getReadGroup().getSample() : null;
+ sampleNames.add(sampleName);
+ }
+ return sampleNames;
+ }
+ }
+
+ /**
+ * Returns a pileup randomly downsampled to the desiredCoverage.
+ *
+ * TODO: delete this once the experimental downsampler stabilizes
+ *
+ * @param desiredCoverage
+ * @return
+ */
+ @Override
+ public ReadBackedPileup getDownsampledPileup(int desiredCoverage) {
+ if (getNumberOfElements() <= desiredCoverage)
+ return this;
+
+ // randomly choose numbers corresponding to positions in the reads list
+ TreeSet<Integer> positions = new TreeSet<Integer>();
+ for (int i = 0; i < desiredCoverage; /* no update */) {
+ if (positions.add(GenomeAnalysisEngine.getRandomGenerator().nextInt(getNumberOfElements())))
+ i++;
+ }
+
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PerSamplePileupElementTracker<PileupElement> filteredTracker = new PerSamplePileupElementTracker<PileupElement>();
+
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+
+ int current = 0;
+ UnifiedPileupElementTracker<PileupElement> filteredPileup = new UnifiedPileupElementTracker<PileupElement>();
+ for (PileupElement p : perSampleElements) {
+ if (positions.contains(current))
+ filteredPileup.add(p);
+ current++;
+
+ }
+ filteredTracker.addElements(sample, filteredPileup);
+ }
+
+ return createNewPileup(loc, filteredTracker);
+ } else {
+ UnifiedPileupElementTracker<PileupElement> tracker = (UnifiedPileupElementTracker<PileupElement>) pileupElementTracker;
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+
+ Iterator positionIter = positions.iterator();
+
+ while (positionIter.hasNext()) {
+ int nextReadToKeep = (Integer) positionIter.next();
+ filteredTracker.add(tracker.get(nextReadToKeep));
+ }
+
+ return createNewPileup(getLocation(), filteredTracker);
+ }
+ }
+
+ @Override
+ public ReadBackedPileup getPileupForSamples(Collection<String> sampleNames) {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PileupElementTracker<PileupElement> filteredElements = tracker.getElements(sampleNames);
+ return filteredElements != null ? createNewPileup(loc, filteredElements) : null;
+ } else {
+ HashSet<String> hashSampleNames = new HashSet<String>(sampleNames); // to speed up the "contains" access in the for loop
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+ for (PileupElement p : pileupElementTracker) {
+ GATKSAMRecord read = p.getRead();
+ if (sampleNames != null) { // still checking on sampleNames because hashSampleNames will never be null. And empty means something else.
+ if (read.getReadGroup() != null && hashSampleNames.contains(read.getReadGroup().getSample()))
+ filteredTracker.add(p);
+ } else {
+ if (read.getReadGroup() == null || read.getReadGroup().getSample() == null)
+ filteredTracker.add(p);
+ }
+ }
+ return filteredTracker.size() > 0 ? createNewPileup(loc, filteredTracker) : null;
+ }
+ }
+
+ @Override
+ public Map<String, ReadBackedPileup> getPileupsForSamples(Collection<String> sampleNames) {
+ Map<String, ReadBackedPileup> result = new HashMap<String, ReadBackedPileup>();
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ for (String sample : sampleNames) {
+ PileupElementTracker<PileupElement> filteredElements = tracker.getElements(sample);
+ if (filteredElements != null)
+ result.put(sample, createNewPileup(loc, filteredElements));
+ }
+ } else {
+ Map<String, UnifiedPileupElementTracker<PileupElement>> trackerMap = new HashMap<String, UnifiedPileupElementTracker<PileupElement>>();
+
+ for (String sample : sampleNames) { // initialize pileups for each sample
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+ trackerMap.put(sample, filteredTracker);
+ }
+ for (PileupElement p : pileupElementTracker) { // go through all pileup elements only once and add them to the respective sample's pileup
+ GATKSAMRecord read = p.getRead();
+ if (read.getReadGroup() != null) {
+ String sample = read.getReadGroup().getSample();
+ UnifiedPileupElementTracker<PileupElement> tracker = trackerMap.get(sample);
+ if (tracker != null) // we only add the pileup the requested samples. Completely ignore the rest
+ tracker.add(p);
+ }
+ }
+ for (Map.Entry<String, UnifiedPileupElementTracker<PileupElement>> entry : trackerMap.entrySet()) // create the ReadBackedPileup for each sample
+ result.put(entry.getKey(), createNewPileup(loc, entry.getValue()));
+ }
+ return result;
+ }
+
+
+ @Override
+ public ReadBackedPileup getPileupForSample(String sampleName) {
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ PileupElementTracker<PileupElement> filteredElements = tracker.getElements(sampleName);
+ return filteredElements != null ? createNewPileup(loc, filteredElements) : null;
+ } else {
+ UnifiedPileupElementTracker<PileupElement> filteredTracker = new UnifiedPileupElementTracker<PileupElement>();
+ for (PileupElement p : pileupElementTracker) {
+ GATKSAMRecord read = p.getRead();
+ if (sampleName != null) {
+ if (read.getReadGroup() != null && sampleName.equals(read.getReadGroup().getSample()))
+ filteredTracker.add(p);
+ } else {
+ if (read.getReadGroup() == null || read.getReadGroup().getSample() == null)
+ filteredTracker.add(p);
+ }
+ }
+ return filteredTracker.size() > 0 ? createNewPileup(loc, filteredTracker) : null;
+ }
+ }
+
+ // --------------------------------------------------------
+ //
+ // iterators
+ //
+ // --------------------------------------------------------
+
+ /**
+ * The best way to access PileupElements where you only care about the bases and quals in the pileup.
+ * <p/>
+ * for (PileupElement p : this) { doSomething(p); }
+ * <p/>
+ * Provides efficient iteration of the data.
+ *
+ * @return
+ */
+ @Override
+ public Iterator<PileupElement> iterator() {
+ return new Iterator<PileupElement>() {
+ private final Iterator<PileupElement> wrappedIterator = pileupElementTracker.iterator();
+
+ public boolean hasNext() {
+ return wrappedIterator.hasNext();
+ }
+
+ public PileupElement next() {
+ return wrappedIterator.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Cannot remove from a pileup element iterator");
+ }
+ };
+ }
+
+ /**
+ * The best way to access PileupElements where you only care not only about bases and quals in the pileup
+ * but also need access to the index of the pileup element in the pile.
+ *
+ * for (ExtendedPileupElement p : this) { doSomething(p); }
+ *
+ * Provides efficient iteration of the data.
+ *
+ * @return
+ */
+
+ /**
+ * Simple useful routine to count the number of deletion bases in this pileup
+ *
+ * @return
+ */
+ @Override
+ public int getNumberOfDeletions() {
+ if ( nDeletions == UNINITIALIZED_CACHED_INT_VALUE ) {
+ nDeletions = 0;
+ for (PileupElement p : pileupElementTracker.unorderedIterable() ) {
+ if (p.isDeletion()) {
+ nDeletions++;
+ }
+ }
+ }
+ return nDeletions;
+ }
+
+ @Override
+ public int getNumberOfMappingQualityZeroReads() {
+ if ( nMQ0Reads == UNINITIALIZED_CACHED_INT_VALUE ) {
+ nMQ0Reads = 0;
+
+ for (PileupElement p : pileupElementTracker.unorderedIterable()) {
+ if (p.getRead().getMappingQuality() == 0) {
+ nMQ0Reads++;
+ }
+ }
+ }
+
+ return nMQ0Reads;
+ }
+
+ /**
+ * @return the number of physical elements in this pileup
+ */
+ @Override
+ public int getNumberOfElements() {
+ return pileupElementTracker.size();
+ }
+
+ /**
+ * @return the number of abstract elements in this pileup
+ */
+ @Override
+ public int depthOfCoverage() {
+ if (depthOfCoverage == UNINITIALIZED_CACHED_INT_VALUE) {
+ depthOfCoverage = pileupElementTracker.size();
+ }
+ return depthOfCoverage;
+ }
+
+ /**
+ * @return true if there are 0 elements in the pileup, false otherwise
+ */
+ @Override
+ public boolean isEmpty() {
+ return getNumberOfElements() == 0;
+ }
+
+
+ /**
+ * @return the location of this pileup
+ */
+ @Override
+ public GenomeLoc getLocation() {
+ return loc;
+ }
+
+ /**
+ * Get counts of A, C, G, T in order, which returns a int[4] vector with counts according
+ * to BaseUtils.simpleBaseToBaseIndex for each base.
+ *
+ * @return
+ */
+ @Override
+ public int[] getBaseCounts() {
+ int[] counts = new int[4];
+
+ // TODO -- can be optimized with .unorderedIterable()
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+ for (final String sample : tracker.getSamples()) {
+ int[] countsBySample = createNewPileup(loc, tracker.getElements(sample)).getBaseCounts();
+ for (int i = 0; i < counts.length; i++)
+ counts[i] += countsBySample[i];
+ }
+ } else {
+ for (PileupElement pile : this) {
+ // skip deletion sites
+ if (!pile.isDeletion()) {
+ int index = BaseUtils.simpleBaseToBaseIndex((char) pile.getBase());
+ if (index != -1)
+ counts[index]++;
+ }
+ }
+ }
+
+ return counts;
+ }
+
+ @Override
+ public String getPileupString(Character ref) {
+ // In the pileup format, each line represents a genomic position, consisting of chromosome name,
+ // coordinate, reference base, read bases, read qualities and alignment mapping qualities.
+ return String.format("%s %s %c %s %s",
+ getLocation().getContig(), getLocation().getStart(), // chromosome name and coordinate
+ ref, // reference base
+ new String(getBases()),
+ getQualsString());
+ }
+
+ // --------------------------------------------------------
+ //
+ // Convenience functions that may be slow
+ //
+ // --------------------------------------------------------
+
+ /**
+ * Returns a list of the reads in this pileup. Note this call costs O(n) and allocates fresh lists each time
+ *
+ * @return
+ */
+ @Override
+ public List<GATKSAMRecord> getReads() {
+ List<GATKSAMRecord> reads = new ArrayList<GATKSAMRecord>(getNumberOfElements());
+ for (PileupElement pile : this) {
+ reads.add(pile.getRead());
+ }
+ return reads;
+ }
+
+ @Override
+ public int getNumberOfDeletionsAfterThisElement() {
+ int count = 0;
+ for (PileupElement p : pileupElementTracker.unorderedIterable()) {
+ if (p.isBeforeDeletionStart())
+ count++;
+ }
+ return count;
+ }
+
+ @Override
+ public int getNumberOfInsertionsAfterThisElement() {
+ int count = 0;
+ for (PileupElement p : pileupElementTracker.unorderedIterable()) {
+ if (p.isBeforeInsertion())
+ count++;
+ }
+ return count;
+
+ }
+ /**
+ * Returns a list of the offsets in this pileup. Note this call costs O(n) and allocates fresh lists each time
+ *
+ * @return
+ */
+ @Override
+ public List<Integer> getOffsets() {
+ List<Integer> offsets = new ArrayList<Integer>(getNumberOfElements());
+ for (PileupElement pile : pileupElementTracker.unorderedIterable()) {
+ offsets.add(pile.getOffset());
+ }
+ return offsets;
+ }
+
+ /**
+ * Returns an array of the bases in this pileup. Note this call costs O(n) and allocates fresh array each time
+ *
+ * @return
+ */
+ @Override
+ public byte[] getBases() {
+ byte[] v = new byte[getNumberOfElements()];
+ int pos = 0;
+ for (PileupElement pile : pileupElementTracker) {
+ v[pos++] = pile.getBase();
+ }
+ return v;
+ }
+
+ /**
+ * Returns an array of the quals in this pileup. Note this call costs O(n) and allocates fresh array each time
+ *
+ * @return
+ */
+ @Override
+ public byte[] getQuals() {
+ byte[] v = new byte[getNumberOfElements()];
+ int pos = 0;
+ for (PileupElement pile : pileupElementTracker) {
+ v[pos++] = pile.getQual();
+ }
+ return v;
+ }
+
+ /**
+ * Get an array of the mapping qualities
+ *
+ * @return
+ */
+ @Override
+ public int[] getMappingQuals() {
+ final int[] v = new int[getNumberOfElements()];
+ int pos = 0;
+ for ( final PileupElement pile : pileupElementTracker ) {
+ v[pos++] = pile.getRead().getMappingQuality();
+ }
+ return v;
+ }
+
+ static String quals2String(byte[] quals) {
+ StringBuilder qualStr = new StringBuilder();
+ for (int qual : quals) {
+ qual = Math.min(qual, 63); // todo: fixme, this isn't a good idea
+ char qualChar = (char) (33 + qual); // todo: warning, this is illegal for qual > 63
+ qualStr.append(qualChar);
+ }
+
+ return qualStr.toString();
+ }
+
+ private String getQualsString() {
+ return quals2String(getQuals());
+ }
+
+ /**
+ * Returns a new ReadBackedPileup that is sorted by start coordinate of the reads.
+ *
+ * @return
+ */
+ @Override
+ public ReadBackedPileup getStartSortedPileup() {
+
+ final TreeSet<PileupElement> sortedElements = new TreeSet<PileupElement>(new Comparator<PileupElement>() {
+ @Override
+ public int compare(PileupElement element1, PileupElement element2) {
+ final int difference = element1.getRead().getAlignmentStart() - element2.getRead().getAlignmentStart();
+ return difference != 0 ? difference : element1.getRead().getReadName().compareTo(element2.getRead().getReadName());
+ }
+ });
+
+ if (pileupElementTracker instanceof PerSamplePileupElementTracker) {
+ PerSamplePileupElementTracker<PileupElement> tracker = (PerSamplePileupElementTracker<PileupElement>) pileupElementTracker;
+
+ for (final String sample : tracker.getSamples()) {
+ PileupElementTracker<PileupElement> perSampleElements = tracker.getElements(sample);
+ for (PileupElement pile : perSampleElements)
+ sortedElements.add(pile);
+ }
+ }
+ else {
+ UnifiedPileupElementTracker<PileupElement> tracker = (UnifiedPileupElementTracker<PileupElement>) pileupElementTracker;
+ for (PileupElement pile : tracker)
+ sortedElements.add(pile);
+ }
+
+ UnifiedPileupElementTracker<PileupElement> sortedTracker = new UnifiedPileupElementTracker<PileupElement>();
+ for (PileupElement pile : sortedElements)
+ sortedTracker.add(pile);
+
+ return createNewPileup(loc, sortedTracker);
+ }
+
+ @Override
+ public FragmentCollection<PileupElement> toFragments() {
+ return FragmentUtils.create(this);
+ }
+
+ @Override
+ public ReadBackedPileup copy() {
+ return new ReadBackedPileupImpl(loc, pileupElementTracker.copy());
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup2/Notes b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup2/Notes
new file mode 100644
index 0000000..0d989fa
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/pileup2/Notes
@@ -0,0 +1,34 @@
+Features needed:
+
+- intrinsic support for samples. Pileups are tree based data structures whose leaves are actual
+pile ups of a single "sample" and whose nodes are collections of multiple sub pileups. This will
+make join and split operations very cheap.
+
+- should be light-weight to create, and hold only minimal cached data to avoid unnecessary overhead.
+Things like the number of deletions, insertions, etc shouldn't be required information. Size will
+continue to be a key cached value. Could create a simple caching data structure that calculations lots of metrics about the pileup and was somehow
+cached internally, via a "CachedRBP" structure. This will make it very cheap and easy to filter
+pileups on the fly, costing O(N) to create the filtered context.
+
+- immutable
+
+- support for holding neighboring reads to the left and right of the pileup itself
+
+- unified picture for "regular" and "extended" events. ExtendedEvents are really a special
+call from the engine and have nothing to do with the data itself.
+
+- Where should algorithms operating on the pileups go? Two options are in the interface itself,
+making it very heavy-weight but easy to access, vs. in an associated PileupOps static methods, a
+la Collections.
+
+- The Pileup2 should support in the fly filtering, so that read filters can be added at the top level
+and applied at all levels of the tree. Basically a filtering pileup would just create a new
+mirrored tree with filtering applied to each node. Very low overhead.
+
+- Sizes could be cached as needed, so that only one pass is ever needed over the size of any pileup
+
+- Fundamentally pileups are just collections of read-backed data. The PileupElements contain
+all of the smarts -- regular, indel, fragment-based. We need to be able to create pileups containing
+multiple subtype elements, which by necessity will need to declare their own static consensusType. How is it
+best to do this in Java? Have a single global ENUM that enumerates all of the possible types at
+compile time? Perhaps something more dynamic?
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeter.java
new file mode 100644
index 0000000..f77ac04
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeter.java
@@ -0,0 +1,465 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.progressmeter;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Invariant;
+import com.google.java.contract.Requires;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.*;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A meter measuring progress on a calculation through a set of genomic regions that can
+ * print a few key metrics to a logger and optionally to a file
+ *
+ * The key information for assessing progress is a set of genome locs describing the total
+ * set of regions we will process. Whenever (at reasonable intervals) the processing unit
+ * can called notifyOfProgress and this logger may, depending on the metering delay, print
+ * a log message with the following metrics:
+ *
+ * -- Number of processed X (X = processing units)
+ * -- Runtime per.1M X
+ * -- Percent of regions to be processed completed
+ * -- The estimated total runtime based on previous performance
+ * -- The estimated time remaining for the entire process
+ *
+ * The optional file log an expanded set of metrics in tabular format
+ * suitable for subsequent analysis in R.
+ *
+ * This class is -- and MUST BE -- thread-safe for use in the GATK. Multiple independent
+ * threads executing processors will be calling notifyOfProgress() simultaneously and this
+ * class does (and MUST) properly sort out the timings of logs without interlacing outputs
+ * because of these threads.
+ *
+ * Consequently, the fundamental model for when to print the logs is time based. We basically
+ * print a meter message every X seconds, minutes, hours, whatever is appropriate based on the
+ * estimated remaining runtime.
+ *
+ * @author depristo
+ * @since 2010 maybe, but written in 09/12 for clarity
+ */
+ at Invariant({
+ "targetSizeInBP >= 0",
+ "progressPrintFrequency > 0"
+})
+public class ProgressMeter {
+ protected static final Logger logger = Logger.getLogger(ProgressMeter.class);
+
+ // --------------------------------------------------------------------------------
+ // static constants controlling overall system behavior
+ // --------------------------------------------------------------------------------
+
+ /**
+ * Min. milliseconds after we start up the meter before we will print our first meter message
+ */
+ private final static long MIN_ELAPSED_TIME_BEFORE_FIRST_PROGRESS = 30 * 1000;
+
+ /**
+ * How often should we print performance logging information, when we are sending this
+ * information to a file? Not dynamically updated as the logger meter is.
+ */
+ private final static long PERFORMANCE_LOG_PRINT_FREQUENCY = 10 * 1000;
+
+ private final static double TWO_HOURS_IN_SECONDS = 2.0 * 60.0 * 60.0;
+ private final static double TWELVE_HOURS_IN_SECONDS = 12.0 * 60.0 * 60.0;
+
+ // --------------------------------------------------------------------------------
+ // Variables we updating during running
+ // --------------------------------------------------------------------------------
+
+ /**
+ * When was the last time we printed progress log? In milleseconds
+ */
+ private long lastProgressPrintTime = -1;
+
+ /**
+ * How frequently should we be printing our meter messages? Dynamically updated
+ * depending on how long we think the run has left.
+ */
+ private long progressPrintFrequency = 10 * 1000; // default value
+
+ /**
+ * When was the last time we printed to the performance log? In millseconds
+ */
+ private long lastPerformanceLogPrintTime = -1;
+
+ // --------------------------------------------------------------------------------
+ // final variables fixed at object creation time
+ // --------------------------------------------------------------------------------
+
+ /**
+ * The set of genome locs describing the total region we are processing with
+ * this GATK run. Used to determine how close we are to completing the run
+ */
+ private final GenomeLocSortedSet regionsBeingProcessed;
+
+ /**
+ * Size, in bp, of the area we are processing, derived from regionsBeingProcessed.
+ * Updated once in the system in initial for performance reasons
+ */
+ private final long targetSizeInBP;
+
+ /**
+ * A string describing the type of units being processes, so we can say things like
+ * "we are running at X processingUnitName per second"
+ */
+ private final String processingUnitName;
+
+ /**
+ * The space allocated to #processingUnitName in the output
+ */
+ private final int processingUnitWidth;
+
+ /**
+ * The format string used for progress lines
+ */
+ private final String progressFormatString;
+
+ /**
+ * A potentially null file where we print a supplementary, R readable performance log
+ * file.
+ */
+ private final PrintStream performanceLog;
+
+ /** We use the SimpleTimer to time our run */
+ private final SimpleTimer timer = new SimpleTimer();
+
+ private GenomeLoc maxGenomeLoc = null;
+ private Position position = new Position(PositionStatus.STARTING);
+ private long nTotalRecordsProcessed = 0;
+
+ /**
+ * The elapsed time in nanosecond, updated by the daemon thread, so that
+ * we don't pay any system call overhead to determine the the elapsed time.
+ */
+ private long elapsedTimeInNanosecondUpdatedByDaemon = 0;
+
+ final ProgressMeterDaemon progressMeterDaemon;
+
+ /**
+ * Create a new ProgressMeter
+ *
+ * Note that progress meter isn't started until the client calls start()
+ *
+ * @param performanceLogFile an optional performance log file where a table of performance logs will be written
+ * @param processingUnitName the name of the unit type being processed, suitable for saying X seconds per processingUnitName
+ * @param processingIntervals the intervals being processed
+ */
+ public ProgressMeter(final File performanceLogFile,
+ final String processingUnitName,
+ final GenomeLocSortedSet processingIntervals) {
+ this(performanceLogFile, processingUnitName, processingIntervals, ProgressMeterDaemon.DEFAULT_POLL_FREQUENCY_MILLISECONDS);
+ }
+
+ protected ProgressMeter(final File performanceLogFile,
+ final String processingUnitName,
+ final GenomeLocSortedSet processingIntervals,
+ final long pollingFrequency) {
+ if ( processingUnitName == null ) throw new IllegalArgumentException("processingUnitName cannot be null");
+ if ( processingIntervals == null ) throw new IllegalArgumentException("Target intervals cannot be null");
+
+ this.processingUnitName = processingUnitName;
+ this.regionsBeingProcessed = processingIntervals;
+ this.processingUnitWidth = Math.max(processingUnitName.length(), "processed".length());
+ this.progressFormatString = String.format("%%15s %%%1$ds %%7s %%%1$ds %%5.1f%%%% %%7s %%9s", processingUnitWidth);
+
+ // setup the performance logger output, if requested
+ if ( performanceLogFile != null ) {
+ try {
+ this.performanceLog = new PrintStream(new FileOutputStream(performanceLogFile));
+ final List<String> pLogHeader = Arrays.asList("elapsed.time", "units.processed", "processing.speed",
+ "bp.processed", "bp.speed", "genome.fraction.complete", "est.total.runtime", "est.time.remaining");
+ performanceLog.println(Utils.join("\t", pLogHeader));
+ } catch (FileNotFoundException e) {
+ throw new UserException.CouldNotCreateOutputFile(performanceLogFile, e);
+ }
+ } else {
+ performanceLog = null;
+ }
+
+ // cached for performance reasons
+ targetSizeInBP = processingIntervals.coveredSize();
+
+ // start up the timer
+ progressMeterDaemon = new ProgressMeterDaemon(this, pollingFrequency);
+ }
+
+ public ProgressMeterDaemon getProgressMeterDaemon() {
+ return progressMeterDaemon;
+ }
+
+ /**
+ * Start up the progress meter, printing initialization message and starting up the
+ * daemon thread for periodic printing.
+ */
+ @Requires("progressMeterDaemon != null")
+ public synchronized void start() {
+ timer.start();
+ lastProgressPrintTime = timer.currentTime();
+ final String formatString = String.format("%%15s | %%%1$ds | %%7s | %%%1$ds | %%9s | %%7s | %%9s", processingUnitWidth);
+
+ logger.info("[INITIALIZATION COMPLETE; STARTING PROCESSING]");
+ logger.info(String.format(formatString, "", "processed", "time", "per 1M", "", "total", "remaining"));
+ logger.info(String.format(formatString, "Location", processingUnitName, "elapsed", processingUnitName,
+ "completed", "runtime", "runtime"));
+
+ progressMeterDaemon.start();
+ }
+
+ /**
+ * @return the current runtime in nanoseconds
+ */
+ @Ensures("result >= 0")
+ public long getRuntimeInNanoseconds() {
+ return timer.getElapsedTimeNano();
+ }
+
+ /**
+ * This function is just like getRuntimeInNanoseconds but it doesn't actually query the
+ * system timer to determine the value, but rather uses a local variable in this meter
+ * that is updated by the daemon thread. This means that the result is ridiculously imprecise
+ * for a nanosecond value (as it's only updated each pollingFrequency of the daemon) but
+ * it is free for clients to access, which can be critical when one wants to do tests like:
+ *
+ * for some work unit:
+ * do unit if getRuntimeInNanosecondsUpdatedPeriodically < X
+ *
+ * and have this operation eventually timeout but don't want to pay the system call time to
+ * ensure that the loop exits as soon as the elapsed time exceeds X
+ *
+ * @return the current runtime in nanoseconds
+ */
+ @Ensures("result >= 0")
+ public long getRuntimeInNanosecondsUpdatedPeriodically() {
+ return elapsedTimeInNanosecondUpdatedByDaemon;
+ }
+
+ /**
+ * Update the period runtime variable to the current runtime in nanoseconds. Should only
+ * be called by the daemon thread
+ */
+ protected void updateElapsedTimeInNanoseconds() {
+ elapsedTimeInNanosecondUpdatedByDaemon = getRuntimeInNanoseconds();
+ }
+
+
+
+ /**
+ * Utility routine that prints out process information (including timing) every N records or
+ * every M seconds, for N and M set in global variables.
+ *
+ * Synchronized to ensure that even with multiple threads calling notifyOfProgress we still
+ * get one clean stream of meter logs.
+ *
+ * Note this thread doesn't actually print progress, unless must print is true, but just registers
+ * the progress itself. A separate printing daemon periodically polls the meter to print out
+ * progress
+ *
+ * @param loc Current location, can be null if you are at the end of the processing unit. Must
+ * have size == 1 (cannot be multiple bases in size).
+ * @param nTotalRecordsProcessed the total number of records we've processed
+ */
+ public synchronized void notifyOfProgress(final GenomeLoc loc, final long nTotalRecordsProcessed) {
+ if ( nTotalRecordsProcessed < 0 ) throw new IllegalArgumentException("nTotalRecordsProcessed must be >= 0");
+ if ( loc.size() != 1 ) throw new IllegalArgumentException("GenomeLoc must have size == 1 but got " + loc);
+
+ // weird comparison to ensure that loc == null (in unmapped reads) is keep before maxGenomeLoc == null (on startup)
+ this.maxGenomeLoc = loc == null ? loc : (maxGenomeLoc == null ? loc : loc.max(maxGenomeLoc));
+ this.nTotalRecordsProcessed = Math.max(this.nTotalRecordsProcessed, nTotalRecordsProcessed);
+
+ // a pretty name for our position
+ this.position = maxGenomeLoc == null ? new Position(PositionStatus.IN_UNMAPPED_READS) : new Position(maxGenomeLoc);
+ }
+
+ /**
+ * Describes the status of this position marker, such as starting up, done, in the unmapped reads,
+ * or somewhere on the genome
+ */
+ private enum PositionStatus {
+ STARTING("Starting"),
+ DONE("done"),
+ IN_UNMAPPED_READS("unmapped reads"),
+ ON_GENOME(null);
+
+ public final String message;
+
+ private PositionStatus(String message) {
+ this.message = message;
+ }
+ }
+
+ /**
+ * A pair of position status and the genome loc, if necessary. Used to get a
+ * status update message as needed, without the computational cost of formatting
+ * the genome loc string every time a progress notification happens (which is almost
+ * always not printed)
+ */
+ private class Position {
+ final PositionStatus type;
+ final GenomeLoc maybeLoc;
+
+ /**
+ * Create a position object of any type != ON_GENOME
+ * @param type
+ */
+ @Requires({"type != null", "type != PositionStatus.ON_GENOME"})
+ private Position(PositionStatus type) {
+ this.type = type;
+ this.maybeLoc = null;
+ }
+
+ /**
+ * Create a position object of type ON_GENOME at genomeloc loc
+ * @param loc
+ */
+ @Requires("loc != null")
+ private Position(GenomeLoc loc) {
+ this.type = PositionStatus.ON_GENOME;
+ this.maybeLoc = loc;
+ }
+
+ /**
+ * @return a human-readable representation of this position
+ */
+ private String getMessage() {
+ if ( type == PositionStatus.ON_GENOME )
+ return maxGenomeLoc.getContig() + ":" + maxGenomeLoc.getStart();
+ else
+ return type.message;
+ }
+ }
+
+ /**
+ * Actually try to print out progress
+ *
+ * This function may print out if the progress print is due, but if not enough time has elapsed
+ * since the last print we will not print out information.
+ *
+ * @param mustPrint if true, progress will be printed regardless of the last time we printed progress
+ */
+ protected synchronized void printProgress(final boolean mustPrint) {
+ final long curTime = timer.currentTime();
+ final boolean printProgress = mustPrint || maxElapsedIntervalForPrinting(curTime, lastProgressPrintTime, progressPrintFrequency);
+ final boolean printLog = performanceLog != null && maxElapsedIntervalForPrinting(curTime, lastPerformanceLogPrintTime, PERFORMANCE_LOG_PRINT_FREQUENCY);
+
+ if ( printProgress || printLog ) {
+ final ProgressMeterData progressData = takeProgressSnapshot(maxGenomeLoc, nTotalRecordsProcessed);
+
+ final AutoFormattingTime elapsed = new AutoFormattingTime(progressData.getElapsedSeconds(), 5, 1);
+ final AutoFormattingTime bpRate = new AutoFormattingTime(progressData.secondsPerMillionBP());
+ final AutoFormattingTime unitRate = new AutoFormattingTime(progressData.secondsPerMillionElements());
+ final double fractionGenomeTargetCompleted = progressData.calculateFractionGenomeTargetCompleted(targetSizeInBP);
+ final AutoFormattingTime estTotalRuntime = new AutoFormattingTime(elapsed.getTimeInSeconds() / fractionGenomeTargetCompleted, 5, 1);
+ final AutoFormattingTime timeToCompletion = new AutoFormattingTime(estTotalRuntime.getTimeInSeconds() - elapsed.getTimeInSeconds());
+
+ if ( printProgress ) {
+ lastProgressPrintTime = curTime;
+ updateLoggerPrintFrequency(estTotalRuntime.getTimeInSeconds());
+
+ logger.info(String.format(progressFormatString,
+ position.getMessage(), progressData.getUnitsProcessed()*1.0, elapsed, unitRate,
+ 100*fractionGenomeTargetCompleted, estTotalRuntime, timeToCompletion));
+
+ }
+
+ if ( printLog ) {
+ lastPerformanceLogPrintTime = curTime;
+ performanceLog.printf("%.2f\t%d\t%.2e\t%d\t%.2e\t%.2e\t%.2f\t%.2f%n",
+ elapsed.getTimeInSeconds(), progressData.getUnitsProcessed(), unitRate.getTimeInSeconds(),
+ progressData.getBpProcessed(), bpRate.getTimeInSeconds(),
+ fractionGenomeTargetCompleted, estTotalRuntime.getTimeInSeconds(),
+ timeToCompletion.getTimeInSeconds());
+ }
+ }
+ }
+
+ /**
+ * Determine, based on remaining runtime, how often to print the meter
+ *
+ * @param totalRuntimeSeconds kinda obvious, no?
+ */
+ private void updateLoggerPrintFrequency(final double totalRuntimeSeconds) {
+ // dynamically change the update rate so that short running jobs receive frequent updates while longer jobs receive fewer updates
+ if ( totalRuntimeSeconds > TWELVE_HOURS_IN_SECONDS )
+ progressPrintFrequency = 60 * 1000; // in milliseconds
+ else if ( totalRuntimeSeconds > TWO_HOURS_IN_SECONDS )
+ progressPrintFrequency = 30 * 1000; // in milliseconds
+ else
+ progressPrintFrequency = 10 * 1000; // in milliseconds
+ }
+
+ /**
+ * Creates a new ProgressData object recording a snapshot of our progress at this instant
+ *
+ * @param loc our current position. If null, assumes we are done traversing
+ * @param nTotalRecordsProcessed the total number of records we've processed
+ * @return
+ */
+ private ProgressMeterData takeProgressSnapshot(final GenomeLoc loc, final long nTotalRecordsProcessed) {
+ // null -> end of processing
+ final long bpProcessed = loc == null ? targetSizeInBP : regionsBeingProcessed.sizeBeforeLoc(loc);
+ return new ProgressMeterData(timer.getElapsedTime(), nTotalRecordsProcessed, bpProcessed);
+ }
+
+ /**
+ * Should be called when processing is done
+ */
+ public void notifyDone(final long nTotalRecordsProcessed) {
+ // print out the progress meter
+ this.nTotalRecordsProcessed = nTotalRecordsProcessed;
+ this.position = new Position(PositionStatus.DONE);
+ printProgress(true);
+
+ logger.info(String.format("Total runtime %.2f secs, %.2f min, %.2f hours",
+ timer.getElapsedTime(), timer.getElapsedTime() / 60, timer.getElapsedTime() / 3600));
+
+ if ( performanceLog != null )
+ performanceLog.close();
+
+ // shutdown our daemon thread
+ progressMeterDaemon.done();
+ }
+
+ /**
+ * @param curTime (current runtime, in millisecs)
+ * @param lastPrintTime the last time we printed, in machine milliseconds
+ * @param printFreq maximum permitted difference between last print and current times
+ *
+ * @return true if the maximum interval (in millisecs) has passed since the last printing
+ */
+ private boolean maxElapsedIntervalForPrinting(final long curTime, long lastPrintTime, long printFreq) {
+ final long elapsed = curTime - lastPrintTime;
+ return elapsed > printFreq && elapsed > MIN_ELAPSED_TIME_BEFORE_FIRST_PROGRESS;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterDaemon.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterDaemon.java
new file mode 100644
index 0000000..f1f48e6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterDaemon.java
@@ -0,0 +1,111 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.progressmeter;
+
+/**
+ * Daemon thread that periodically prints the progress of the progress meter
+ *
+ * User: depristo
+ * Date: 12/4/12
+ * Time: 9:16 PM
+ */
+public final class ProgressMeterDaemon extends Thread {
+ public final static long DEFAULT_POLL_FREQUENCY_MILLISECONDS = 10 * 1000;
+
+ /**
+ * How frequently should we poll and print progress?
+ */
+ private final long pollFrequencyMilliseconds;
+
+ /**
+ * How long are we waiting between print progress calls are issued?
+ * @return the time in milliseconds between progress meter calls
+ */
+ private long getPollFrequencyMilliseconds() {
+ return pollFrequencyMilliseconds;
+ }
+
+ /**
+ * Are we to continue periodically printing status, or should we shut down?
+ */
+ boolean done = false;
+
+ /**
+ * The meter we will call print on
+ */
+ final ProgressMeter meter;
+
+ /**
+ * Create a new ProgressMeterDaemon printing progress for meter
+ * @param meter the progress meter to print progress of
+ */
+ public ProgressMeterDaemon(final ProgressMeter meter, final long pollFrequencyMilliseconds) {
+ if ( meter == null ) throw new IllegalArgumentException("meter cannot be null");
+ if ( pollFrequencyMilliseconds <= 0 ) throw new IllegalArgumentException("pollFrequencyMilliseconds must be greater than 0 but got " + pollFrequencyMilliseconds);
+
+ this.meter = meter;
+ this.pollFrequencyMilliseconds = pollFrequencyMilliseconds;
+ setDaemon(true);
+ setName("ProgressMeterDaemon");
+ }
+
+ public ProgressMeterDaemon(final ProgressMeter meter) {
+ this(meter, DEFAULT_POLL_FREQUENCY_MILLISECONDS);
+ }
+
+ /**
+ * Tells this daemon thread to shutdown at the next opportunity, as the progress
+ * metering is complete.
+ */
+ public final void done() {
+ this.done = true;
+ }
+
+ /**
+ * Is this daemon thread done?
+ * @return true if done, false otherwise
+ */
+ public boolean isDone() {
+ return done;
+ }
+
+ /**
+ * Start up the ProgressMeterDaemon, polling every tens of seconds to print, if
+ * necessary, the provided progress meter. Never exits until the JVM is complete,
+ * or done() is called, as the thread is a daemon thread
+ */
+ public void run() {
+ while (! done) {
+ meter.printProgress(false);
+ meter.updateElapsedTimeInNanoseconds();
+ try {
+ Thread.sleep(getPollFrequencyMilliseconds());
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterData.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterData.java
new file mode 100644
index 0000000..6804032
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterData.java
@@ -0,0 +1,79 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.progressmeter;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+
+/**
+ * a snapshot of our performance, suitable for storage and later analysis
+ */
+class ProgressMeterData {
+ private final double elapsedSeconds;
+ private final long unitsProcessed;
+ private final long bpProcessed;
+
+ @Requires({"unitsProcessed >= 0", "bpProcessed >= 0", "elapsedSeconds >= 0"})
+ public ProgressMeterData(double elapsedSeconds, long unitsProcessed, long bpProcessed) {
+ this.elapsedSeconds = elapsedSeconds;
+ this.unitsProcessed = unitsProcessed;
+ this.bpProcessed = bpProcessed;
+ }
+
+ @Ensures("result >= 0.0")
+ public double getElapsedSeconds() {
+ return elapsedSeconds;
+ }
+
+ @Ensures("result >= 0")
+ public long getUnitsProcessed() {
+ return unitsProcessed;
+ }
+
+ @Ensures("result >= 0")
+ public long getBpProcessed() {
+ return bpProcessed;
+ }
+
+ /** How long in seconds to process 1M traversal units? */
+ @Ensures("result >= 0.0")
+ public double secondsPerMillionElements() {
+ return (elapsedSeconds * 1000000.0) / Math.max(unitsProcessed, 1);
+ }
+
+ /** How long in seconds to process 1M bp on the genome? */
+ @Ensures("result >= 0.0")
+ public double secondsPerMillionBP() {
+ return (elapsedSeconds * 1000000.0) / Math.max(bpProcessed, 1);
+ }
+
+ /** What fraction of the target intervals have we covered? */
+ @Requires("targetSize >= 0")
+ @Ensures({"result >= 0.0", "result <= 1.0"})
+ public double calculateFractionGenomeTargetCompleted(final long targetSize) {
+ return (1.0*bpProcessed) / Math.max(targetSize, 1);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/recalibration/BQSRArgumentSet.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/recalibration/BQSRArgumentSet.java
new file mode 100644
index 0000000..cc41bc5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/recalibration/BQSRArgumentSet.java
@@ -0,0 +1,85 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.recalibration;
+
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+
+import java.io.File;
+
+public class BQSRArgumentSet {
+ // declare public, STL-style for easier and more efficient access:
+ private File BQSR_RECAL_FILE;
+ private int quantizationLevels;
+ private boolean disableIndelQuals;
+ private boolean emitOriginalQuals;
+ private int PRESERVE_QSCORES_LESS_THAN;
+ private double globalQScorePrior;
+
+ public BQSRArgumentSet(final GATKArgumentCollection args) {
+ this.BQSR_RECAL_FILE = args.BQSR_RECAL_FILE;
+ this.quantizationLevels = args.quantizationLevels;
+ this.disableIndelQuals = args.disableIndelQuals;
+ this.emitOriginalQuals = args.emitOriginalQuals;
+ this.PRESERVE_QSCORES_LESS_THAN = args.PRESERVE_QSCORES_LESS_THAN;
+ this.globalQScorePrior = args.globalQScorePrior;
+ }
+
+ public File getRecalFile() { return BQSR_RECAL_FILE; }
+
+ public int getQuantizationLevels() { return quantizationLevels; }
+
+ public boolean shouldDisableIndelQuals() { return disableIndelQuals; }
+
+ public boolean shouldEmitOriginalQuals() { return emitOriginalQuals; }
+
+ public int getPreserveQscoresLessThan() { return PRESERVE_QSCORES_LESS_THAN; }
+
+ public double getGlobalQScorePrior() { return globalQScorePrior; }
+
+ public void setRecalFile(final File BQSR_RECAL_FILE) {
+ this.BQSR_RECAL_FILE = BQSR_RECAL_FILE;
+ }
+
+ public void setQuantizationLevels(final int quantizationLevels) {
+ this.quantizationLevels = quantizationLevels;
+ }
+
+ public void setDisableIndelQuals(final boolean disableIndelQuals) {
+ this.disableIndelQuals = disableIndelQuals;
+ }
+
+ public void setEmitOriginalQuals(final boolean emitOriginalQuals) {
+ this.emitOriginalQuals = emitOriginalQuals;
+ }
+
+ public void setPreserveQscoresLessThan(final int PRESERVE_QSCORES_LESS_THAN) {
+ this.PRESERVE_QSCORES_LESS_THAN = PRESERVE_QSCORES_LESS_THAN;
+ }
+
+ public void setGlobalQScorePrior(final double globalQScorePrior) {
+ this.globalQScorePrior = globalQScorePrior;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/recalibration/BQSRMode.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/recalibration/BQSRMode.java
new file mode 100644
index 0000000..a742ed4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/recalibration/BQSRMode.java
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.recalibration;
+
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+
+import java.lang.annotation.*;
+
+/**
+ * User: hanna
+ * Date: May 14, 2009
+ * Time: 1:51:22 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Allows the walker to indicate what type of data it wants to consume.
+ */
+
+ at Documented
+ at Inherited
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target(ElementType.TYPE)
+public @interface BQSRMode {
+ public abstract ReadTransformer.ApplicationTime ApplicationTime() default ReadTransformer.ApplicationTime.ON_INPUT;
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/recalibration/EventType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/recalibration/EventType.java
new file mode 100644
index 0000000..84ab785
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/recalibration/EventType.java
@@ -0,0 +1,72 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.recalibration;
+
+public enum EventType {
+ BASE_SUBSTITUTION("M", "Base Substitution"),
+ BASE_INSERTION("I", "Base Insertion"),
+ BASE_DELETION("D", "Base Deletion");
+
+ private final String representation;
+ private final String longRepresentation;
+
+ private EventType(String representation, String longRepresentation) {
+ this.representation = representation;
+ this.longRepresentation = longRepresentation;
+ }
+
+ /**
+ * Get the EventType corresponding to its ordinal index
+ * @param index an ordinal index
+ * @return the event type corresponding to ordinal index
+ */
+ public static EventType eventFrom(int index) {
+ return EventType.values()[index];
+ }
+
+ /**
+ * Get the EventType with short string representation
+ * @throws IllegalArgumentException if representation doesn't correspond to one of EventType
+ * @param representation short string representation of the event
+ * @return an EventType
+ */
+ public static EventType eventFrom(String representation) {
+ for (EventType eventType : EventType.values())
+ if (eventType.representation.equals(representation))
+ return eventType;
+
+ throw new IllegalArgumentException(String.format("Event %s does not exist.", representation));
+ }
+
+ @Override
+ public String toString() {
+ return representation;
+ }
+
+ public String prettyPrint() {
+ return longRepresentation;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/CapturedStreamOutput.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/CapturedStreamOutput.java
new file mode 100644
index 0000000..0166e98
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/CapturedStreamOutput.java
@@ -0,0 +1,134 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.runtime;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.NullOutputStream;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.io.HardThresholdingOutputStream;
+
+import java.io.*;
+import java.util.EnumMap;
+
+/**
+ * Stream output captured from a stream.
+ */
+public class CapturedStreamOutput extends StreamOutput {
+ private final InputStream processStream;
+ private final EnumMap<StreamLocation, OutputStream> outputStreams = new EnumMap<StreamLocation, OutputStream>(StreamLocation.class);
+
+ /**
+ * The byte stream to capture content or null if no output string content was requested.
+ */
+ private final ByteArrayOutputStream bufferStream;
+
+ /**
+ * True if the buffer is truncated.
+ */
+ private boolean bufferTruncated = false;
+
+ /**
+ * @param settings Settings that define what to capture.
+ * @param processStream Stream to capture output.
+ * @param standardStream Stream to write debug output.
+ */
+ public CapturedStreamOutput(OutputStreamSettings settings, InputStream processStream, PrintStream standardStream) {
+ this.processStream = processStream;
+ int bufferSize = settings.getBufferSize();
+ this.bufferStream = (bufferSize < 0) ? new ByteArrayOutputStream() : new ByteArrayOutputStream(bufferSize);
+
+ for (StreamLocation location : settings.getStreamLocations()) {
+ OutputStream outputStream;
+ switch (location) {
+ case Buffer:
+ if (bufferSize < 0) {
+ outputStream = this.bufferStream;
+ } else {
+ outputStream = new HardThresholdingOutputStream(bufferSize) {
+ @Override
+ protected OutputStream getStream() throws IOException {
+ return bufferTruncated ? NullOutputStream.NULL_OUTPUT_STREAM : bufferStream;
+ }
+
+ @Override
+ protected void thresholdReached() throws IOException {
+ bufferTruncated = true;
+ }
+ };
+ }
+ break;
+ case File:
+ try {
+ outputStream = new FileOutputStream(settings.getOutputFile(), settings.isAppendFile());
+ } catch (IOException e) {
+ throw new UserException.BadInput(e.getMessage());
+ }
+ break;
+ case Standard:
+ outputStream = standardStream;
+ break;
+ default:
+ throw new ReviewedGATKException("Unexpected stream location: " + location);
+ }
+ this.outputStreams.put(location, outputStream);
+ }
+ }
+
+ @Override
+ public byte[] getBufferBytes() {
+ return bufferStream.toByteArray();
+ }
+
+ @Override
+ public boolean isBufferTruncated() {
+ return bufferTruncated;
+ }
+
+ /**
+ * Drain the input stream to keep the process from backing up until it's empty.
+ * File streams will be closed automatically when this method returns.
+ *
+ * @throws java.io.IOException When unable to read or write.
+ */
+ public void readAndClose() throws IOException {
+ try {
+ byte[] buf = new byte[4096];
+ int readCount;
+ while ((readCount = processStream.read(buf)) >= 0)
+ for (OutputStream outputStream : this.outputStreams.values()) {
+ outputStream.write(buf, 0, readCount);
+ }
+ } finally {
+ for (StreamLocation location : this.outputStreams.keySet()) {
+ OutputStream outputStream = this.outputStreams.get(location);
+ outputStream.flush();
+ if (location != StreamLocation.Standard)
+ IOUtils.closeQuietly(outputStream);
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/InputStreamSettings.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/InputStreamSettings.java
new file mode 100644
index 0000000..56bfabd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/InputStreamSettings.java
@@ -0,0 +1,116 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.runtime;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * Settings that define text to write to the process stdin.
+ */
+public class InputStreamSettings {
+ private final EnumSet<StreamLocation> streamLocations = EnumSet.noneOf(StreamLocation.class);
+ private byte[] inputBuffer;
+ private File inputFile;
+
+ public InputStreamSettings() {
+ }
+
+ /**
+ * @param inputBuffer String to write to stdin.
+ */
+ public InputStreamSettings(String inputBuffer) {
+ setInputBuffer(inputBuffer);
+ }
+
+ /**
+ * @param inputFile File to write to stdin.
+ */
+ public InputStreamSettings(File inputFile) {
+ setInputFile(inputFile);
+ }
+
+ /**
+ * @param inputBuffer String to write to stdin.
+ * @param inputFile File to write to stdin.
+ */
+ public InputStreamSettings(byte[] inputBuffer, File inputFile) {
+ setInputBuffer(inputBuffer);
+ setInputFile(inputFile);
+ }
+
+ public Set<StreamLocation> getStreamLocations() {
+ return Collections.unmodifiableSet(streamLocations);
+ }
+
+ public byte[] getInputBuffer() {
+ return inputBuffer;
+ }
+
+ public void setInputBuffer(String inputBuffer) {
+ if (inputBuffer == null)
+ throw new IllegalArgumentException("inputBuffer cannot be null");
+ this.streamLocations.add(StreamLocation.Buffer);
+ this.inputBuffer = inputBuffer.getBytes();
+ }
+
+ public void setInputBuffer(byte[] inputBuffer) {
+ if (inputBuffer == null)
+ throw new IllegalArgumentException("inputBuffer cannot be null");
+ this.streamLocations.add(StreamLocation.Buffer);
+ this.inputBuffer = inputBuffer;
+ }
+
+ public void clearInputBuffer() {
+ this.streamLocations.remove(StreamLocation.Buffer);
+ this.inputBuffer = null;
+ }
+
+ public File getInputFile() {
+ return inputFile;
+ }
+
+ public void setInputFile(File inputFile) {
+ if (inputFile == null)
+ throw new IllegalArgumentException("inputFile cannot be null");
+ this.streamLocations.add(StreamLocation.File);
+ this.inputFile = inputFile;
+ }
+
+ public void clearInputFile() {
+ this.streamLocations.remove(StreamLocation.File);
+ this.inputFile = null;
+ }
+
+ public void setInputStandard(boolean inputStandard) {
+ if (inputStandard)
+ this.streamLocations.add(StreamLocation.Standard);
+ else
+ this.streamLocations.remove(StreamLocation.Standard);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/OutputStreamSettings.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/OutputStreamSettings.java
new file mode 100644
index 0000000..bc92291
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/OutputStreamSettings.java
@@ -0,0 +1,127 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.runtime;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * Settings that define text to capture from a process stream.
+ */
+public class OutputStreamSettings {
+ private final EnumSet<StreamLocation> streamLocations = EnumSet.noneOf(StreamLocation.class);
+ private int bufferSize;
+ private File outputFile;
+ private boolean appendFile;
+
+ public OutputStreamSettings() {
+ }
+
+ /**
+ * @param bufferSize The number of bytes to capture, or -1 for unlimited.
+ */
+ public OutputStreamSettings(int bufferSize) {
+ setBufferSize(bufferSize);
+ }
+
+ /**
+ * @param outputFile The file to write output to.
+ */
+ public OutputStreamSettings(File outputFile) {
+ setOutputFile(outputFile);
+ }
+
+ /**
+ * @param outputFile The file to write output to.
+ * @param append true if the output file should be appended to.
+ */
+ public OutputStreamSettings(File outputFile, boolean append) {
+ setOutputFile(outputFile, append);
+ }
+
+ public OutputStreamSettings(int bufferSize, File outputFile, boolean appendFile) {
+ setBufferSize(bufferSize);
+ setOutputFile(outputFile, appendFile);
+ }
+
+ public Set<StreamLocation> getStreamLocations() {
+ return Collections.unmodifiableSet(streamLocations);
+ }
+
+ public int getBufferSize() {
+ return bufferSize;
+ }
+
+ public void setBufferSize(int bufferSize) {
+ this.streamLocations.add(StreamLocation.Buffer);
+ this.bufferSize = bufferSize;
+ }
+
+ public void clearBufferSize() {
+ this.streamLocations.remove(StreamLocation.Buffer);
+ this.bufferSize = 0;
+ }
+
+ public File getOutputFile() {
+ return outputFile;
+ }
+
+ public boolean isAppendFile() {
+ return appendFile;
+ }
+
+ /**
+ * Overwrites the outputFile with the process output.
+ *
+ * @param outputFile File to overwrite.
+ */
+ public void setOutputFile(File outputFile) {
+ setOutputFile(outputFile, false);
+ }
+
+ public void setOutputFile(File outputFile, boolean append) {
+ if (outputFile == null)
+ throw new IllegalArgumentException("outputFile cannot be null");
+ streamLocations.add(StreamLocation.File);
+ this.outputFile = outputFile;
+ this.appendFile = append;
+ }
+
+ public void clearOutputFile() {
+ streamLocations.remove(StreamLocation.File);
+ this.outputFile = null;
+ this.appendFile = false;
+ }
+
+ public void printStandard(boolean print) {
+ if (print)
+ this.streamLocations.add(StreamLocation.Standard);
+ else
+ this.streamLocations.remove(StreamLocation.Standard);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/ProcessController.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/ProcessController.java
new file mode 100644
index 0000000..3955817
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/ProcessController.java
@@ -0,0 +1,387 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.runtime;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.*;
+
+/**
+ * Facade to Runtime.exec() and java.lang.Process. Handles
+ * running a process to completion and returns stdout and stderr
+ * as strings. Creates separate threads for reading stdout and stderr,
+ * then reuses those threads for each process most efficient use is
+ * to create one of these and use it repeatedly. Instances are not
+ * thread-safe, however.
+ *
+ * TODO: java.io sometimes zombies the backround threads locking up on read().
+ * Supposedly NIO has better ways of interrupting a blocked stream but will
+ * require a little bit of refactoring.
+ *
+ * @author Michael Koehrsen
+ * @author Khalid Shakir
+ */
+public class ProcessController {
+ private static Logger logger = Logger.getLogger(ProcessController.class);
+
+ private static enum ProcessStream {Stdout, Stderr}
+
+ // Tracks running processes.
+ private static final Set<ProcessController> running = Collections.synchronizedSet(new HashSet<ProcessController>());
+
+ // Tracks this running process.
+ private Process process;
+
+ // Threads that capture stdout and stderr
+ private final OutputCapture stdoutCapture;
+ private final OutputCapture stderrCapture;
+
+ // When a caller destroyes a controller a new thread local version will be created
+ private boolean destroyed = false;
+
+ // Communication channels with output capture threads
+
+ // Holds the stdout and stderr sent to the background capture threads
+ private final Map<ProcessStream, CapturedStreamOutput> toCapture =
+ new EnumMap<ProcessStream, CapturedStreamOutput>(ProcessStream.class);
+
+ // Holds the results of the capture from the background capture threads.
+ // May be the content via toCapture or an StreamOutput.EMPTY if the capture was interrupted.
+ private final Map<ProcessStream, StreamOutput> fromCapture =
+ new EnumMap<ProcessStream, StreamOutput>(ProcessStream.class);
+
+ // Useful for debugging if background threads have shut down correctly
+ private static int nextControllerId = 0;
+ private final int controllerId;
+
+ public ProcessController() {
+ // Start the background threads for this controller.
+ synchronized (running) {
+ controllerId = nextControllerId++;
+ }
+ stdoutCapture = new OutputCapture(ProcessStream.Stdout, controllerId);
+ stderrCapture = new OutputCapture(ProcessStream.Stderr, controllerId);
+ stdoutCapture.start();
+ stderrCapture.start();
+ }
+
+ /**
+ * Returns a thread local ProcessController.
+ * Should NOT be closed when finished so it can be reused by the thread.
+ *
+ * @return a thread local ProcessController.
+ */
+ public static ProcessController getThreadLocal() {
+ // If the local controller was destroyed get a fresh instance.
+ if (threadProcessController.get().destroyed)
+ threadProcessController.remove();
+ return threadProcessController.get();
+ }
+
+ /**
+ * Thread local process controller container.
+ */
+ private static final ThreadLocal<ProcessController> threadProcessController =
+ new ThreadLocal<ProcessController>() {
+ @Override
+ protected ProcessController initialValue() {
+ return new ProcessController();
+ }
+ };
+
+ /**
+ * Similar to Runtime.exec() but drains the output and error streams.
+ *
+ * @param command Command to run.
+ * @return The result code.
+ */
+ public static int exec(String[] command) {
+ ProcessController controller = ProcessController.getThreadLocal();
+ return controller.exec(new ProcessSettings(command)).getExitValue();
+ }
+
+ /**
+ * Executes a command line program with the settings and waits for it to return,
+ * processing the output on a background thread.
+ *
+ * @param settings Settings to be run.
+ * @return The output of the command.
+ */
+ public ProcessOutput exec(ProcessSettings settings) {
+ if (destroyed)
+ throw new IllegalStateException("This controller was destroyed");
+
+ ProcessBuilder builder = new ProcessBuilder(settings.getCommand());
+ builder.directory(settings.getDirectory());
+
+ Map<String, String> settingsEnvironment = settings.getEnvironment();
+ if (settingsEnvironment != null) {
+ Map<String, String> builderEnvironment = builder.environment();
+ builderEnvironment.clear();
+ builderEnvironment.putAll(settingsEnvironment);
+ }
+
+ builder.redirectErrorStream(settings.isRedirectErrorStream());
+
+ StreamOutput stdout = null;
+ StreamOutput stderr = null;
+
+ // Start the process running.
+
+ try {
+ synchronized (toCapture) {
+ process = builder.start();
+ }
+ running.add(this);
+ } catch (IOException e) {
+ String message = String.format("Unable to start command: %s\nReason: %s",
+ StringUtils.join(builder.command(), " "),
+ e.getMessage());
+ throw new ReviewedGATKException(message);
+ }
+
+ int exitCode;
+
+ try {
+ // Notify the background threads to start capturing.
+ synchronized (toCapture) {
+ toCapture.put(ProcessStream.Stdout,
+ new CapturedStreamOutput(settings.getStdoutSettings(), process.getInputStream(), System.out));
+ toCapture.put(ProcessStream.Stderr,
+ new CapturedStreamOutput(settings.getStderrSettings(), process.getErrorStream(), System.err));
+ toCapture.notifyAll();
+ }
+
+ // Write stdin content
+ InputStreamSettings stdinSettings = settings.getStdinSettings();
+ Set<StreamLocation> streamLocations = stdinSettings.getStreamLocations();
+ if (!streamLocations.isEmpty()) {
+ try {
+ OutputStream stdinStream = process.getOutputStream();
+ for (StreamLocation location : streamLocations) {
+ InputStream inputStream;
+ switch (location) {
+ case Buffer:
+ inputStream = new ByteArrayInputStream(stdinSettings.getInputBuffer());
+ break;
+ case File:
+ try {
+ inputStream = FileUtils.openInputStream(stdinSettings.getInputFile());
+ } catch (IOException e) {
+ throw new UserException.BadInput(e.getMessage());
+ }
+ break;
+ case Standard:
+ inputStream = System.in;
+ break;
+ default:
+ throw new ReviewedGATKException("Unexpected stream location: " + location);
+ }
+ try {
+ IOUtils.copy(inputStream, stdinStream);
+ } finally {
+ if (location != StreamLocation.Standard)
+ IOUtils.closeQuietly(inputStream);
+ }
+ }
+ stdinStream.flush();
+ } catch (IOException e) {
+ throw new ReviewedGATKException("Error writing to stdin on command: " + StringUtils.join(builder.command(), " "), e);
+ }
+ }
+
+ // Wait for the process to complete.
+ try {
+ process.getOutputStream().close();
+ process.waitFor();
+ } catch (IOException e) {
+ throw new ReviewedGATKException("Unable to close stdin on command: " + StringUtils.join(builder.command(), " "), e);
+ } catch (InterruptedException e) {
+ throw new ReviewedGATKException("Process interrupted", e);
+ } finally {
+ while (!destroyed && stdout == null || stderr == null) {
+ synchronized (fromCapture) {
+ if (fromCapture.containsKey(ProcessStream.Stdout))
+ stdout = fromCapture.remove(ProcessStream.Stdout);
+ if (fromCapture.containsKey(ProcessStream.Stderr))
+ stderr = fromCapture.remove(ProcessStream.Stderr);
+ try {
+ if (stdout == null || stderr == null)
+ fromCapture.wait();
+ } catch (InterruptedException e) {
+ // Log the error, ignore the interrupt and wait patiently
+ // for the OutputCaptures to (via finally) return their
+ // stdout and stderr.
+ logger.error(e);
+ }
+ }
+ }
+
+ if (destroyed) {
+ if (stdout == null)
+ stdout = StreamOutput.EMPTY;
+ if (stderr == null)
+ stderr = StreamOutput.EMPTY;
+ }
+ }
+ } finally {
+ synchronized (toCapture) {
+ exitCode = process.exitValue();
+ process = null;
+ }
+ running.remove(this);
+ }
+
+ return new ProcessOutput(exitCode, stdout, stderr);
+ }
+
+ /**
+ * Executes a command line program with the settings and waits for it to return,
+ * processing the output on a background thread.
+ *
+ * Throws an IOException if the ProcessOutput exit code is nonzero
+ *
+ * @param settings Settings to be run.
+ */
+ public ProcessOutput execAndCheck(ProcessSettings settings) throws IOException {
+ ProcessOutput po = exec(settings);
+ if (po.getExitValue() != 0) {
+ String message = String.format("Process exited with %d\nCommand Line: %s",
+ po.getExitValue(),
+ Utils.join(" ", settings.getCommand()));
+ throw new IOException(message);
+ }
+ return po;
+ }
+
+ /**
+ * @return The set of still running processes.
+ */
+ public static Set<ProcessController> getRunning() {
+ synchronized (running) {
+ return new HashSet<ProcessController>(running);
+ }
+ }
+
+ /**
+ * Stops the process from running and tries to ensure process is cleaned up properly.
+ * NOTE: sub-processes started by process may be zombied with their parents set to pid 1.
+ * NOTE: capture threads may block on read.
+ * TODO: Try to use NIO to interrupt streams.
+ */
+ public void tryDestroy() {
+ destroyed = true;
+ synchronized (toCapture) {
+ if (process != null) {
+ process.destroy();
+ IOUtils.closeQuietly(process.getInputStream());
+ IOUtils.closeQuietly(process.getErrorStream());
+ }
+ stdoutCapture.interrupt();
+ stderrCapture.interrupt();
+ toCapture.notifyAll();
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ tryDestroy();
+ } catch (Exception e) {
+ logger.error(e);
+ }
+ super.finalize();
+ }
+
+ private class OutputCapture extends Thread {
+ private final int controllerId;
+ private final ProcessStream key;
+
+ /**
+ * Reads in the output of a stream on a background thread to keep the output pipe from backing up and freezing the called process.
+ *
+ * @param key The stdout or stderr key for this output capture.
+ * @param controllerId Unique id of the controller.
+ */
+ public OutputCapture(ProcessStream key, int controllerId) {
+ super(String.format("OutputCapture-%d-%s-%s-%d", controllerId, key.name().toLowerCase(),
+ Thread.currentThread().getName(), Thread.currentThread().getId()));
+ this.controllerId = controllerId;
+ this.key = key;
+ setDaemon(true);
+ }
+
+ /**
+ * Runs the capture.
+ */
+ @Override
+ public void run() {
+ while (!destroyed) {
+ StreamOutput processStream = StreamOutput.EMPTY;
+ try {
+ // Wait for a new input stream to be passed from this process controller.
+ CapturedStreamOutput capturedProcessStream = null;
+ while (!destroyed && capturedProcessStream == null) {
+ synchronized (toCapture) {
+ if (toCapture.containsKey(key)) {
+ capturedProcessStream = toCapture.remove(key);
+ } else {
+ toCapture.wait();
+ }
+ }
+ }
+
+ if (!destroyed) {
+ // Read in the input stream
+ processStream = capturedProcessStream;
+ capturedProcessStream.readAndClose();
+ }
+ } catch (InterruptedException e) {
+ logger.info("OutputCapture interrupted, exiting");
+ break;
+ } catch (IOException e) {
+ logger.error("Error reading process output", e);
+ } finally {
+ // Send the string back to the process controller.
+ synchronized (fromCapture) {
+ fromCapture.put(key, processStream);
+ fromCapture.notify();
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/ProcessOutput.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/ProcessOutput.java
new file mode 100644
index 0000000..9276de7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/ProcessOutput.java
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.runtime;
+
+public class ProcessOutput {
+ private final int exitValue;
+ private final StreamOutput stdout;
+ private final StreamOutput stderr;
+
+ /**
+ * The output of a process.
+ *
+ * @param exitValue The exit value.
+ * @param stdout The capture of stdout as defined by the stdout OutputStreamSettings.
+ * @param stderr The capture of stderr as defined by the stderr OutputStreamSettings.
+ */
+ public ProcessOutput(int exitValue, StreamOutput stdout, StreamOutput stderr) {
+ this.exitValue = exitValue;
+ this.stdout = stdout;
+ this.stderr = stderr;
+ }
+
+ public int getExitValue() {
+ return exitValue;
+ }
+
+ public StreamOutput getStdout() {
+ return stdout;
+ }
+
+ public StreamOutput getStderr() {
+ return stderr;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/ProcessSettings.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/ProcessSettings.java
new file mode 100644
index 0000000..7027b9d
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/ProcessSettings.java
@@ -0,0 +1,140 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.runtime;
+
+
+import java.io.File;
+import java.util.Map;
+
+public class ProcessSettings {
+ private String[] command;
+ private Map<String, String> environment;
+ private File directory;
+ private boolean redirectErrorStream;
+ private InputStreamSettings stdinSettings;
+ private OutputStreamSettings stdoutSettings;
+ private OutputStreamSettings stderrSettings;
+
+ /**
+ * @param command Command line to run.
+ */
+ public ProcessSettings(String[] command) {
+ this(command, false, null, null, null, null, null);
+ }
+
+ /**
+ * @param command Command line to run.
+ * @param redirectErrorStream true if stderr should be sent to stdout.
+ * @param environment Environment settings to override System.getEnv, or null to use System.getEnv.
+ * @param directory The directory to run the command in, or null to run in the current directory.
+ * @param stdinSettings Settings for writing to the process stdin.
+ * @param stdoutSettings Settings for capturing the process stdout.
+ * @param stderrSettings Setting for capturing the process stderr.
+ */
+ public ProcessSettings(String[] command, boolean redirectErrorStream, File directory, Map<String, String> environment,
+ InputStreamSettings stdinSettings, OutputStreamSettings stdoutSettings, OutputStreamSettings stderrSettings) {
+ this.command = checkCommand(command);
+ this.redirectErrorStream = redirectErrorStream;
+ this.directory = directory;
+ this.environment = environment;
+ this.stdinSettings = checkSettings(stdinSettings);
+ this.stdoutSettings = checkSettings(stdoutSettings);
+ this.stderrSettings = checkSettings(stderrSettings);
+ }
+
+ public String[] getCommand() {
+ return command;
+ }
+
+ public void setCommand(String[] command) {
+ this.command = checkCommand(command);
+ }
+
+ public boolean isRedirectErrorStream() {
+ return redirectErrorStream;
+ }
+
+ public void setRedirectErrorStream(boolean redirectErrorStream) {
+ this.redirectErrorStream = redirectErrorStream;
+ }
+
+ public File getDirectory() {
+ return directory;
+ }
+
+ public void setDirectory(File directory) {
+ this.directory = directory;
+ }
+
+ public Map<String, String> getEnvironment() {
+ return environment;
+ }
+
+ public void setEnvironment(Map<String, String> environment) {
+ this.environment = environment;
+ }
+
+ public InputStreamSettings getStdinSettings() {
+ return stdinSettings;
+ }
+
+ public void setStdinSettings(InputStreamSettings stdinSettings) {
+ this.stdinSettings = checkSettings(stdinSettings);
+ }
+
+ public OutputStreamSettings getStdoutSettings() {
+ return stdoutSettings;
+ }
+
+ public void setStdoutSettings(OutputStreamSettings stdoutSettings) {
+ this.stdoutSettings = checkSettings(stdoutSettings);
+ }
+
+ public OutputStreamSettings getStderrSettings() {
+ return stderrSettings;
+ }
+
+ public void setStderrSettings(OutputStreamSettings stderrSettings) {
+ this.stderrSettings = checkSettings(stderrSettings);
+ }
+
+ protected String[] checkCommand(String[] command) {
+ if (command == null)
+ throw new IllegalArgumentException("Command is not allowed to be null");
+ for (String s: command)
+ if (s == null)
+ throw new IllegalArgumentException("Command is not allowed to contain nulls");
+ return command;
+ }
+
+ protected InputStreamSettings checkSettings(InputStreamSettings settings) {
+ return settings == null ? new InputStreamSettings() : settings;
+ }
+
+ protected OutputStreamSettings checkSettings(OutputStreamSettings settings) {
+ return settings == null ? new OutputStreamSettings() : settings;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/RuntimeUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/RuntimeUtils.java
new file mode 100644
index 0000000..7a982dd
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/RuntimeUtils.java
@@ -0,0 +1,77 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.runtime;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class RuntimeUtils {
+ public static final String[] PATHS;
+
+ static {
+ String path = System.getenv("PATH");
+ if (path == null)
+ path = System.getenv("path");
+ if (path == null) {
+ PATHS = new String[0];
+ } else {
+ PATHS = StringUtils.split(path, File.pathSeparatorChar);
+ }
+ }
+
+ /**
+ * Returns the path to an executable or null if it doesn't exist.
+ * @param executable Relative path
+ * @return The absolute file path.
+ */
+ public static File which(String executable) {
+ for (String path: PATHS) {
+ File file = new File(path, executable);
+ if (file.exists())
+ return file.getAbsoluteFile();
+ }
+ return null;
+ }
+
+ /**
+ * Return the current classpath as a list of absolute paths
+ * @return
+ */
+ public static List<String> getAbsoluteClassPaths() {
+ final String[] relativeClassPaths = System.getProperty("java.class.path").split(File.pathSeparator);
+ final List<String> absoluteClassPaths = new ArrayList<>(relativeClassPaths.length);
+ for (String classPath : relativeClassPaths) {
+ File cp = new File(classPath);
+ if (cp.exists())
+ absoluteClassPaths.add(cp.getAbsolutePath());
+ }
+
+ return absoluteClassPaths;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/StreamLocation.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/StreamLocation.java
new file mode 100644
index 0000000..37d66f0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/StreamLocation.java
@@ -0,0 +1,33 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.runtime;
+
+/**
+ * Where to read/write a stream
+ */
+public enum StreamLocation {
+ Buffer, File, Standard
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/StreamOutput.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/StreamOutput.java
new file mode 100644
index 0000000..9ce039e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/runtime/StreamOutput.java
@@ -0,0 +1,69 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.runtime;
+
+/**
+ * The content of stdout or stderr.
+ */
+public abstract class StreamOutput {
+ /**
+ * Empty stream output when no output is captured due to an error.
+ */
+ public static final StreamOutput EMPTY = new StreamOutput() {
+ @Override
+ public byte[] getBufferBytes() {
+ return new byte[0];
+ }
+
+ @Override
+ public boolean isBufferTruncated() {
+ return false;
+ }
+ };
+
+ /**
+ * Returns the content as a string.
+ *
+ * @return The content as a string.
+ */
+ public String getBufferString() {
+ return new String(getBufferBytes());
+ }
+
+ /**
+ * Returns the content as a string.
+ *
+ * @return The content as a string.
+ */
+ public abstract byte[] getBufferBytes();
+
+ /**
+ * Returns true if the buffer was truncated.
+ *
+ * @return true if the buffer was truncated.
+ */
+ public abstract boolean isBufferTruncated();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/AlignmentStartComparator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/AlignmentStartComparator.java
new file mode 100644
index 0000000..7e926d5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/AlignmentStartComparator.java
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMRecord;
+
+import java.util.Comparator;
+
+/**
+ * Compares two SAMRecords only the basis on alignment start. Note that
+ * comparisons are performed ONLY on the basis of alignment start; any
+ * two SAM records with the same alignment start will be considered equal.
+ *
+ * Unmapped alignments will all be considered equal.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class AlignmentStartComparator implements Comparator<SAMRecord> {
+ public int compare(SAMRecord lhs, SAMRecord rhs) {
+ if(!lhs.getReferenceIndex().equals(rhs.getReferenceIndex()))
+ return lhs.getReferenceIndex() - rhs.getReferenceIndex();
+
+ // Note: no integer overflow here because alignment starts are >= 0.
+ return lhs.getAlignmentStart() - rhs.getAlignmentStart();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/AlignmentStartWithNoTiesComparator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/AlignmentStartWithNoTiesComparator.java
new file mode 100644
index 0000000..db3f458
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/AlignmentStartWithNoTiesComparator.java
@@ -0,0 +1,73 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.SAMRecord;
+
+import java.util.Comparator;
+
+public class AlignmentStartWithNoTiesComparator implements Comparator<SAMRecord> {
+ @Requires("c1 >= 0 && c2 >= 0")
+ @Ensures("result == 0 || result == 1 || result == -1")
+ private int compareContigs(int c1, int c2) {
+ if (c1 == c2)
+ return 0;
+ else if (c1 > c2)
+ return 1;
+ return -1;
+ }
+
+ @Requires("r1 != null && r2 != null")
+ @Ensures("result == 0 || result == 1 || result == -1")
+ public int compare(SAMRecord r1, SAMRecord r2) {
+ int result;
+
+ if (r1 == r2)
+ result = 0;
+
+ else if (r1.getReadUnmappedFlag())
+ result = 1;
+ else if (r2.getReadUnmappedFlag())
+ result = -1;
+ else {
+ final int cmpContig = compareContigs(r1.getReferenceIndex(), r2.getReferenceIndex());
+
+ if (cmpContig != 0)
+ result = cmpContig;
+
+ else {
+ if (r1.getAlignmentStart() < r2.getAlignmentStart())
+ result = -1;
+ else
+ result = 1;
+ }
+ }
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/AlignmentUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/AlignmentUtils.java
new file mode 100644
index 0000000..4c9a444
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/AlignmentUtils.java
@@ -0,0 +1,1337 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.haplotype.Haplotype;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.recalibration.EventType;
+import org.broadinstitute.gatk.utils.smithwaterman.SWPairwiseAlignment;
+
+import java.util.*;
+
+
+public final class AlignmentUtils {
+ private final static EnumSet<CigarOperator> ALIGNED_TO_GENOME_OPERATORS = EnumSet.of(CigarOperator.M, CigarOperator.EQ, CigarOperator.X);
+ private final static EnumSet<CigarOperator> ALIGNED_TO_GENOME_PLUS_SOFTCLIPS = EnumSet.of(CigarOperator.M, CigarOperator.EQ, CigarOperator.X, CigarOperator.S);
+ public final static String HAPLOTYPE_TAG = "HC";
+
+ // cannot be instantiated
+ private AlignmentUtils() { }
+
+ /**
+ * Does cigar start or end with a deletion operation?
+ *
+ * @param cigar a non-null cigar to test
+ * @return true if the first or last operator of cigar is a D
+ */
+ public static boolean startsOrEndsWithInsertionOrDeletion(final Cigar cigar) {
+ if ( cigar == null ) throw new IllegalArgumentException("Cigar cannot be null");
+
+ if ( cigar.isEmpty() )
+ return false;
+
+ final CigarOperator first = cigar.getCigarElement(0).getOperator();
+ final CigarOperator last = cigar.getCigarElement(cigar.numCigarElements()-1).getOperator();
+ return first == CigarOperator.D || first == CigarOperator.I || last == CigarOperator.D || last == CigarOperator.I;
+ }
+
+ /**
+ * Aligns reads the haplotype, and then projects this alignment of read -> hap onto the reference
+ * via the alignment of haplotype (via its getCigar) method.
+ *
+ * @param originalRead the read we want to write aligned to the reference genome
+ * @param haplotype the haplotype that the read should be aligned to, before aligning to the reference
+ * @param referenceStart the start of the reference that haplotype is aligned to. Provides global coordinate frame.
+ * @param isInformative true if the read is differentially informative for one of the haplotypes
+ *
+ * @throws IllegalArgumentException if {@code originalRead} is {@code null} or {@code haplotype} is {@code null} or it
+ * does not have a Cigar or the {@code referenceStart} is invalid (less than 1).
+ *
+ * @return a GATKSAMRecord aligned to reference. Never {@code null}.
+ */
+ public static GATKSAMRecord createReadAlignedToRef(final GATKSAMRecord originalRead,
+ final Haplotype haplotype,
+ final int referenceStart,
+ final boolean isInformative) {
+ if ( originalRead == null ) throw new IllegalArgumentException("originalRead cannot be null");
+ if ( haplotype == null ) throw new IllegalArgumentException("haplotype cannot be null");
+ if ( haplotype.getCigar() == null ) throw new IllegalArgumentException("Haplotype cigar not set " + haplotype);
+ if ( referenceStart < 1 ) throw new IllegalArgumentException("reference start much be >= 1 but got " + referenceStart);
+
+ // compute the smith-waterman alignment of read -> haplotype
+ final SWPairwiseAlignment swPairwiseAlignment = new SWPairwiseAlignment(haplotype.getBases(), originalRead.getReadBases(), CigarUtils.NEW_SW_PARAMETERS);
+ if ( swPairwiseAlignment.getAlignmentStart2wrt1() == -1 )
+ // sw can fail (reasons not clear) so if it happens just don't realign the read
+ return originalRead;
+ final Cigar swCigar = consolidateCigar(swPairwiseAlignment.getCigar());
+
+ // since we're modifying the read we need to clone it
+ final GATKSAMRecord read = (GATKSAMRecord)originalRead.clone();
+
+ // only informative reads are given the haplotype tag to enhance visualization
+ if ( isInformative )
+ read.setAttribute(HAPLOTYPE_TAG, haplotype.hashCode());
+
+ // compute here the read starts w.r.t. the reference from the SW result and the hap -> ref cigar
+ final Cigar extendedHaplotypeCigar = haplotype.getConsolidatedPaddedCigar(1000);
+ final int readStartOnHaplotype = calcFirstBaseMatchingReferenceInCigar(extendedHaplotypeCigar, swPairwiseAlignment.getAlignmentStart2wrt1());
+ final int readStartOnReference = referenceStart + haplotype.getAlignmentStartHapwrtRef() + readStartOnHaplotype;
+ read.setAlignmentStart(readStartOnReference);
+ read.resetSoftStartAndEnd();
+
+ // compute the read -> ref alignment by mapping read -> hap -> ref from the
+ // SW of read -> hap mapped through the given by hap -> ref
+ final Cigar haplotypeToRef = trimCigarByBases(extendedHaplotypeCigar, swPairwiseAlignment.getAlignmentStart2wrt1(), extendedHaplotypeCigar.getReadLength() - 1);
+ final Cigar readToRefCigarRaw = applyCigarToCigar(swCigar, haplotypeToRef);
+ final Cigar readToRefCigarClean = cleanUpCigar(readToRefCigarRaw);
+ final Cigar readToRefCigar = leftAlignIndel(readToRefCigarClean, haplotype.getBases(),
+ originalRead.getReadBases(), swPairwiseAlignment.getAlignmentStart2wrt1(), 0, true);
+
+ read.setCigar(readToRefCigar);
+
+ if ( readToRefCigar.getReadLength() != read.getReadLength() )
+ throw new IllegalStateException("Cigar " + readToRefCigar + " with read length " + readToRefCigar.getReadLength()
+ + " != read length " + read.getReadLength() + " for read " + read.format() + "\nhapToRef " + haplotypeToRef + " length " + haplotypeToRef.getReadLength() + "/" + haplotypeToRef.getReferenceLength()
+ + "\nreadToHap " + swCigar + " length " + swCigar.getReadLength() + "/" + swCigar.getReferenceLength());
+
+ return read;
+ }
+
+
+
+ /**
+ * Get the byte[] from bases that cover the reference interval refStart -> refEnd given the
+ * alignment of bases to the reference (basesToRefCigar) and the start offset of the bases on the reference
+ *
+ * refStart and refEnd are 0 based offsets that we want to obtain. In the client code, if the reference
+ * bases start at position X and you want Y -> Z, refStart should be Y - X and refEnd should be Z - X.
+ *
+ * If refStart or refEnd would start or end the new bases within a deletion, this function will return null
+ *
+ * @param bases
+ * @param refStart
+ * @param refEnd
+ * @param basesStartOnRef where does the bases array start w.r.t. the reference start? For example, bases[0] of
+ * could be at refStart == 0 if basesStartOnRef == 0, but it could just as easily be at
+ * 10 (meaning bases doesn't fully span the reference), which would be indicated by basesStartOnRef == 10.
+ * It's not trivial to eliminate this parameter because it's tied up with the cigar
+ * @param basesToRefCigar the cigar that maps the bases to the reference genome
+ * @return a byte[] containing the bases covering this interval, or null if we would start or end within a deletion
+ */
+ public static byte[] getBasesCoveringRefInterval(final int refStart, final int refEnd, final byte[] bases, final int basesStartOnRef, final Cigar basesToRefCigar) {
+ if ( refStart < 0 || refEnd < refStart ) throw new IllegalArgumentException("Bad start " + refStart + " and/or stop " + refEnd);
+ if ( basesStartOnRef < 0 ) throw new IllegalArgumentException("BasesStartOnRef must be >= 0 but got " + basesStartOnRef);
+ if ( bases == null ) throw new IllegalArgumentException("Bases cannot be null");
+ if ( basesToRefCigar == null ) throw new IllegalArgumentException("basesToRefCigar cannot be null");
+ if ( bases.length != basesToRefCigar.getReadLength() ) throw new IllegalArgumentException("Mismatch in length between reference bases " + bases.length + " and cigar length " + basesToRefCigar);
+
+ int refPos = basesStartOnRef;
+ int basesPos = 0;
+ int basesStart = -1;
+ int basesStop = -1;
+ boolean done = false;
+
+ for ( int iii = 0; ! done && iii < basesToRefCigar.numCigarElements(); iii++ ) {
+ final CigarElement ce = basesToRefCigar.getCigarElement(iii);
+ switch ( ce.getOperator() ) {
+ case I:
+ basesPos += ce.getLength();
+ break;
+ case M: case X: case EQ:
+ for ( int i = 0; i < ce.getLength(); i++ ) {
+ if ( refPos == refStart )
+ basesStart = basesPos;
+ if ( refPos == refEnd ) {
+ basesStop = basesPos;
+ done = true;
+ break;
+ }
+ refPos++;
+ basesPos++;
+ }
+ break;
+ case D:
+ for ( int i = 0; i < ce.getLength(); i++ ) {
+ if ( refPos == refEnd || refPos == refStart ) {
+ // if we ever reach a ref position that is either a start or an end, we fail
+ return null;
+ }
+ refPos++;
+ }
+ break;
+ default:
+ throw new IllegalStateException("Unsupported operator " + ce);
+ }
+ }
+
+ if ( basesStart == -1 || basesStop == -1 )
+ throw new IllegalStateException("Never found start " + basesStart + " or stop " + basesStop + " given cigar " + basesToRefCigar);
+
+ return Arrays.copyOfRange(bases, basesStart, basesStop + 1);
+ }
+
+ /**
+ * Get the number of bases at which refSeq and readSeq differ, given their alignment
+ *
+ * @param cigar the alignment of readSeq to refSeq
+ * @param refSeq the bases of the reference sequence
+ * @param readSeq the bases of the read sequence
+ * @return the number of bases that differ between refSeq and readSeq
+ */
+ public static int calcNumDifferentBases(final Cigar cigar, final byte[] refSeq, final byte[] readSeq) {
+ int refIndex = 0, readIdx = 0, delta = 0;
+
+ for (final CigarElement ce : cigar.getCigarElements()) {
+ final int elementLength = ce.getLength();
+ switch (ce.getOperator()) {
+ case X:case EQ:case M:
+ for (int j = 0; j < elementLength; j++, refIndex++, readIdx++)
+ delta += refSeq[refIndex] != readSeq[readIdx] ? 1 : 0;
+ break;
+ case I:
+ delta += elementLength;
+ case S:
+ readIdx += elementLength;
+ break;
+ case D:
+ delta += elementLength;
+ case N:
+ refIndex += elementLength;
+ break;
+ case H:
+ case P:
+ break;
+ default:
+ throw new ReviewedGATKException("The " + ce.getOperator() + " cigar element is not currently supported");
+ }
+ }
+
+ return delta;
+ }
+
+ public static class MismatchCount {
+ public int numMismatches = 0;
+ public long mismatchQualities = 0;
+ }
+
+ public static long mismatchingQualities(GATKSAMRecord r, byte[] refSeq, int refIndex) {
+ return getMismatchCount(r, refSeq, refIndex).mismatchQualities;
+ }
+
+ /**
+ * @see #getMismatchCount(GATKSAMRecord, byte[], int, int, int) with startOnRead == 0 and nReadBases == read.getReadLength()
+ */
+ public static MismatchCount getMismatchCount(GATKSAMRecord r, byte[] refSeq, int refIndex) {
+ return getMismatchCount(r, refSeq, refIndex, 0, r.getReadLength());
+ }
+
+ // todo -- this code and mismatchesInRefWindow should be combined and optimized into a single
+ // todo -- high performance implementation. We can do a lot better than this right now
+
+ /**
+ * Count how many bases mismatch the reference. Indels are not considered mismatching.
+ *
+ * @param r the sam record to check against
+ * @param refSeq the byte array representing the reference sequence
+ * @param refIndex the index in the reference byte array of the read's first base (the reference index
+ * is matching the alignment start, there may be tons of soft-clipped bases before/after
+ * that so it's wrong to compare with getReadLength() here.). Note that refIndex is
+ * zero based, not 1 based
+ * @param startOnRead the index in the read's bases from which we start counting
+ * @param nReadBases the number of bases after (but including) startOnRead that we check
+ * @return non-null object representing the mismatch count
+ */
+ @Ensures("result != null")
+ public static MismatchCount getMismatchCount(GATKSAMRecord r, byte[] refSeq, int refIndex, int startOnRead, int nReadBases) {
+ if ( r == null ) throw new IllegalArgumentException("attempting to calculate the mismatch count from a read that is null");
+ if ( refSeq == null ) throw new IllegalArgumentException("attempting to calculate the mismatch count with a reference sequence that is null");
+ if ( refIndex < 0 ) throw new IllegalArgumentException("attempting to calculate the mismatch count with a reference index that is negative");
+ if ( startOnRead < 0 ) throw new IllegalArgumentException("attempting to calculate the mismatch count with a read start that is negative");
+ if ( nReadBases < 0 ) throw new IllegalArgumentException("attempting to calculate the mismatch count for a negative number of read bases");
+ if ( refSeq.length - refIndex < (r.getAlignmentEnd() - r.getAlignmentStart()) )
+ throw new IllegalArgumentException("attempting to calculate the mismatch count against a reference string that is smaller than the read");
+
+ MismatchCount mc = new MismatchCount();
+
+ int readIdx = 0;
+ final int endOnRead = startOnRead + nReadBases - 1; // index of the last base on read we want to count (note we are including soft-clipped bases with this math)
+ final byte[] readSeq = r.getReadBases();
+ final Cigar c = r.getCigar();
+ final byte[] readQuals = r.getBaseQualities();
+ for (final CigarElement ce : c.getCigarElements()) {
+
+ if (readIdx > endOnRead)
+ break;
+
+ final int elementLength = ce.getLength();
+ switch (ce.getOperator()) {
+ case X:
+ mc.numMismatches += elementLength;
+ for (int j = 0; j < elementLength; j++)
+ mc.mismatchQualities += readQuals[readIdx+j];
+ case EQ:
+ refIndex += elementLength;
+ readIdx += elementLength;
+ break;
+ case M:
+ for (int j = 0; j < elementLength; j++, refIndex++, readIdx++) {
+ if (refIndex >= refSeq.length)
+ continue; // TODO : It should never happen, we should throw exception here
+ if (readIdx < startOnRead) continue;
+ if (readIdx > endOnRead) break;
+ byte refChr = refSeq[refIndex];
+ byte readChr = readSeq[readIdx];
+ // Note: we need to count X/N's as mismatches because that's what SAM requires
+ //if ( BaseUtils.simpleBaseToBaseIndex(readChr) == -1 ||
+ // BaseUtils.simpleBaseToBaseIndex(refChr) == -1 )
+ // continue; // do not count Ns/Xs/etc ?
+ if (readChr != refChr) {
+ mc.numMismatches++;
+ mc.mismatchQualities += readQuals[readIdx];
+ }
+ }
+ break;
+ case I:
+ case S:
+ readIdx += elementLength;
+ break;
+ case D:
+ case N:
+ refIndex += elementLength;
+ break;
+ case H:
+ case P:
+ break;
+ default:
+ throw new ReviewedGATKException("The " + ce.getOperator() + " cigar element is not currently supported");
+ }
+
+ }
+ return mc;
+ }
+
+ /**
+ * Returns number of alignment blocks (continuous stretches of aligned bases) in the specified alignment.
+ * This method follows closely the SAMRecord::getAlignmentBlocks() implemented in samtools library, but
+ * it only counts blocks without actually allocating and filling the list of blocks themselves. Hence, this method is
+ * a much more efficient alternative to r.getAlignmentBlocks.size() in the situations when this number is all that is needed.
+ * Formally, this method simply returns the number of M elements in the cigar.
+ *
+ * @param r alignment
+ * @return number of continuous alignment blocks (i.e. 'M' elements of the cigar; all indel and clipping elements are ignored).
+ */
+ @Ensures("result >= 0")
+ public static int getNumAlignmentBlocks(final SAMRecord r) {
+ if ( r == null ) throw new IllegalArgumentException("read cannot be null");
+ final Cigar cigar = r.getCigar();
+ if (cigar == null) return 0;
+
+ int n = 0;
+ for (final CigarElement e : cigar.getCigarElements()) {
+ if (ALIGNED_TO_GENOME_OPERATORS.contains(e.getOperator()))
+ n++;
+ }
+
+ return n;
+ }
+
+
+ /**
+ * Get the number of bases aligned to the genome, including soft clips
+ *
+ * If read is not mapped (i.e., doesn't have a cigar) returns 0
+ *
+ * @param r a non-null GATKSAMRecord
+ * @return the number of bases aligned to the genome in R, including soft clipped bases
+ */
+ public static int getNumAlignedBasesCountingSoftClips(final GATKSAMRecord r) {
+ int n = 0;
+ final Cigar cigar = r.getCigar();
+ if (cigar == null) return 0;
+
+ for (final CigarElement e : cigar.getCigarElements())
+ if (ALIGNED_TO_GENOME_PLUS_SOFTCLIPS.contains(e.getOperator()))
+ n += e.getLength();
+
+ return n;
+ }
+
+ /**
+ * Count the number of bases hard clipped from read
+ *
+ * If read's cigar is null, return 0
+ *
+ * @param r a non-null read
+ * @return a positive integer
+ */
+ @Ensures("result >= 0")
+ public static int getNumHardClippedBases(final SAMRecord r) {
+ if ( r == null ) throw new IllegalArgumentException("Read cannot be null");
+
+ int n = 0;
+ final Cigar cigar = r.getCigar();
+ if (cigar == null) return 0;
+
+ for (final CigarElement e : cigar.getCigarElements())
+ if (e.getOperator() == CigarOperator.H)
+ n += e.getLength();
+
+ return n;
+ }
+
+ /**
+ * Calculate the number of bases that are soft clipped in read with quality score greater than threshold
+ *
+ * Handles the case where the cigar is null (i.e., the read is unmapped), returning 0
+ *
+ * @param read a non-null GATKSAMRecord.
+ * @param qualThreshold consider bases with quals > this value as high quality. Must be >= 0
+ * @return positive integer
+ */
+ @Ensures("result >= 0")
+ public static int calcNumHighQualitySoftClips( final GATKSAMRecord read, final byte qualThreshold ) {
+ if ( read == null ) throw new IllegalArgumentException("Read cannot be null");
+ if ( qualThreshold < 0 ) throw new IllegalArgumentException("Expected qualThreshold to be a positive byte but saw " + qualThreshold);
+
+ if ( read.getCigar() == null ) // the read is unmapped
+ return 0;
+
+ final byte[] qual = read.getBaseQualities( EventType.BASE_SUBSTITUTION );
+
+ int numHQSoftClips = 0;
+ int alignPos = 0;
+ for ( final CigarElement ce : read.getCigar().getCigarElements() ) {
+ final int elementLength = ce.getLength();
+
+ switch( ce.getOperator() ) {
+ case S:
+ for( int jjj = 0; jjj < elementLength; jjj++ ) {
+ if( qual[alignPos++] > qualThreshold ) { numHQSoftClips++; }
+ }
+ break;
+ case M: case I: case EQ: case X:
+ alignPos += elementLength;
+ break;
+ case H: case P: case D: case N:
+ break;
+ default:
+ throw new IllegalStateException("Unsupported cigar operator: " + ce.getOperator());
+ }
+ }
+
+ return numHQSoftClips;
+ }
+
+ public static int calcAlignmentByteArrayOffset(final Cigar cigar, final PileupElement pileupElement, final int alignmentStart, final int refLocus) {
+ return calcAlignmentByteArrayOffset( cigar, pileupElement.getOffset(), pileupElement.isDeletion(), alignmentStart, refLocus );
+ }
+
+ /**
+ * Calculate the index into the read's bases of the beginning of the encompassing cigar element for a given cigar and offset
+ *
+ * @param cigar the read's CIGAR -- cannot be null
+ * @param offset the offset to use for the calculation or -1 if in the middle of a deletion
+ * @param isDeletion are we in the middle of a deletion?
+ * @param alignmentStart the alignment start of the read
+ * @param refLocus the reference position of the offset
+ * @return a non-negative int index
+ */
+ @Ensures("result >= 0")
+ public static int calcAlignmentByteArrayOffset(final Cigar cigar, final int offset, final boolean isDeletion, final int alignmentStart, final int refLocus) {
+ if ( cigar == null ) throw new IllegalArgumentException("attempting to find the alignment position from a CIGAR that is null");
+ if ( offset < -1 ) throw new IllegalArgumentException("attempting to find the alignment position with an offset that is negative (and not -1)");
+ if ( alignmentStart < 0 ) throw new IllegalArgumentException("attempting to find the alignment position from an alignment start that is negative");
+ if ( refLocus < 0 ) throw new IllegalArgumentException("attempting to find the alignment position from a reference position that is negative");
+ if ( offset >= cigar.getReadLength() ) throw new IllegalArgumentException("attempting to find the alignment position of an offset than is larger than the read length");
+
+ int pileupOffset = offset;
+
+ // Reassign the offset if we are in the middle of a deletion because of the modified representation of the read bases
+ if (isDeletion) {
+ pileupOffset = refLocus - alignmentStart;
+ final CigarElement ce = cigar.getCigarElement(0);
+ if (ce.getOperator() == CigarOperator.S) {
+ pileupOffset += ce.getLength();
+ }
+ }
+
+ int pos = 0;
+ int alignmentPos = 0;
+
+ for (int iii = 0; iii < cigar.numCigarElements(); iii++) {
+ final CigarElement ce = cigar.getCigarElement(iii);
+ final int elementLength = ce.getLength();
+
+ switch (ce.getOperator()) {
+ case I:
+ case S: // TODO -- I don't think that soft clips should be treated the same as inserted bases here. Investigation needed.
+ pos += elementLength;
+ if (pos >= pileupOffset) {
+ return alignmentPos;
+ }
+ break;
+ case D:
+ if (!isDeletion) {
+ alignmentPos += elementLength;
+ } else {
+ if (pos + elementLength - 1 >= pileupOffset) {
+ return alignmentPos + (pileupOffset - pos);
+ } else {
+ pos += elementLength;
+ alignmentPos += elementLength;
+ }
+ }
+ break;
+ case M:
+ case EQ:
+ case X:
+ if (pos + elementLength - 1 >= pileupOffset) {
+ return alignmentPos + (pileupOffset - pos);
+ } else {
+ pos += elementLength;
+ alignmentPos += elementLength;
+ }
+ break;
+ case H:
+ case P:
+ case N:
+ break;
+ default:
+ throw new ReviewedGATKException("Unsupported cigar operator: " + ce.getOperator());
+ }
+ }
+
+ return alignmentPos;
+ }
+
+ /**
+ * Generate an array of bases for just those that are aligned to the reference (i.e. no clips or insertions)
+ *
+ * @param cigar the read's CIGAR -- cannot be null
+ * @param read the read's base array
+ * @return a non-null array of bases (bytes)
+ */
+ @Ensures("result != null")
+ public static byte[] readToAlignmentByteArray(final Cigar cigar, final byte[] read) {
+ if ( cigar == null ) throw new IllegalArgumentException("attempting to generate an alignment from a CIGAR that is null");
+ if ( read == null ) throw new IllegalArgumentException("attempting to generate an alignment from a read sequence that is null");
+
+ final int alignmentLength = cigar.getReferenceLength();
+ final byte[] alignment = new byte[alignmentLength];
+ int alignPos = 0;
+ int readPos = 0;
+ for (int iii = 0; iii < cigar.numCigarElements(); iii++) {
+
+ final CigarElement ce = cigar.getCigarElement(iii);
+ final int elementLength = ce.getLength();
+
+ switch (ce.getOperator()) {
+ case I:
+ if (alignPos > 0) {
+ final int prevPos = alignPos - 1;
+ if (alignment[prevPos] == BaseUtils.Base.A.base) {
+ alignment[prevPos] = PileupElement.A_FOLLOWED_BY_INSERTION_BASE;
+ } else if (alignment[prevPos] == BaseUtils.Base.C.base) {
+ alignment[prevPos] = PileupElement.C_FOLLOWED_BY_INSERTION_BASE;
+ } else if (alignment[prevPos] == BaseUtils.Base.T.base) {
+ alignment[prevPos] = PileupElement.T_FOLLOWED_BY_INSERTION_BASE;
+ } else if (alignment[prevPos] == BaseUtils.Base.G.base) {
+ alignment[prevPos] = PileupElement.G_FOLLOWED_BY_INSERTION_BASE;
+ }
+ }
+ case S:
+ readPos += elementLength;
+ break;
+ case D:
+ case N:
+ for (int jjj = 0; jjj < elementLength; jjj++) {
+ alignment[alignPos++] = PileupElement.DELETION_BASE;
+ }
+ break;
+ case M:
+ case EQ:
+ case X:
+ for (int jjj = 0; jjj < elementLength; jjj++) {
+ alignment[alignPos++] = read[readPos++];
+ }
+ break;
+ case H:
+ case P:
+ break;
+ default:
+ throw new ReviewedGATKException("Unsupported cigar operator: " + ce.getOperator());
+ }
+ }
+ return alignment;
+ }
+
+ /**
+ * Returns true if the read does not belong to a contig, i.e. it's location is GenomeLoc.UNMAPPED.
+ * NOTE: A read can have a mapped GenomeLoc and still have an unmapped flag!
+ *
+ * @param r record
+ * @return true if read is unmapped to a genome loc
+ */
+ public static boolean isReadGenomeLocUnmapped(final SAMRecord r) {
+ return SAMRecord.NO_ALIGNMENT_REFERENCE_NAME.equals(r.getReferenceName());
+ }
+
+ /**
+ * Due to (unfortunate) multiple ways to indicate that read is unmapped allowed by SAM format
+ * specification, one may need this convenience shortcut. Checks both 'read unmapped' flag and
+ * alignment reference index/start.
+ *
+ * Our life would be so much easier if all sam files followed the specs. In reality,
+ * sam files (including those generated by maq or bwa) miss headers altogether. When
+ * reading such a SAM file, reference name is set, but since there is no sequence dictionary,
+ * null is always returned for referenceIndex. Let's be paranoid here, and make sure that
+ * we do not call the read "unmapped" when it has only reference name set with ref. index missing
+ * or vice versa.
+ *
+ * @param r a non-null record
+ * @return true if read is unmapped
+ */
+ public static boolean isReadUnmapped(final SAMRecord r) {
+ if ( r == null )
+ throw new IllegalArgumentException("Read cannot be null");
+
+ return r.getReadUnmappedFlag() ||
+ !((r.getReferenceIndex() != null && r.getReferenceIndex() != SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX ||
+ r.getReferenceName() != null && !r.getReferenceName().equals(SAMRecord.NO_ALIGNMENT_REFERENCE_NAME)) &&
+ r.getAlignmentStart() != SAMRecord.NO_ALIGNMENT_START);
+
+ }
+
+ /**
+ * Need a well-formed, consolidated Cigar string so that the left aligning code works properly.
+ * For example, 1M1M1M1D2M1M --> 3M1D3M
+ * If the given cigar is empty then the returned cigar will also be empty
+ *
+ * Note that this routine collapses cigar elements of size 0, so 2M0M => 2M
+ *
+ * @param c the cigar to consolidate
+ * @return a non-null cigar with consecutive matching operators merged into single operators.
+ */
+ @Ensures({"result != null"})
+ public static Cigar consolidateCigar( final Cigar c ) {
+ if ( c == null ) { throw new IllegalArgumentException("Cigar cannot be null"); }
+
+ // fast check to determine if there's anything worth doing before we create new Cigar and actually do some work
+ if ( ! needsConsolidation(c) )
+ return c;
+
+ final Cigar returnCigar = new Cigar();
+ int sumLength = 0;
+ CigarElement lastElement = null;
+
+ for( final CigarElement cur : c.getCigarElements() ) {
+ if ( cur.getLength() == 0 )
+ continue; // don't add elements of 0 length
+
+ if ( lastElement != null && lastElement.getOperator() != cur.getOperator() ) {
+ returnCigar.add(new CigarElement(sumLength, lastElement.getOperator()));
+ sumLength = 0;
+ }
+
+ sumLength += cur.getLength();
+ lastElement = cur;
+ }
+
+ if ( sumLength > 0 ) {
+ returnCigar.add(new CigarElement(sumLength, lastElement.getOperator()));
+ }
+
+ return returnCigar;
+ }
+
+ /**
+ * Does the cigar C need to be consolidated?
+ *
+ * @param c a non-null cigar
+ * @return true if so
+ */
+ private static boolean needsConsolidation(final Cigar c) {
+ if ( c.numCigarElements() <= 1 )
+ return false; // fast path for empty or single cigar
+
+ CigarOperator lastOp = null;
+ for( final CigarElement cur : c.getCigarElements() ) {
+ if ( cur.getLength() == 0 || lastOp == cur.getOperator() )
+ return true;
+ lastOp = cur.getOperator();
+ }
+
+ return false;
+ }
+
+ /**
+ * Takes the alignment of the read sequence <code>readSeq</code> to the reference sequence <code>refSeq</code>
+ * starting at 0-based position <code>refIndex</code> on the <code>refSeq</code> and specified by its <code>cigar</code>.
+ * The last argument <code>readIndex</code> specifies 0-based position on the read where the alignment described by the
+ * <code>cigar</code> starts. Usually cigars specify alignments of the whole read to the ref, so that readIndex is normally 0.
+ * Use non-zero readIndex only when the alignment cigar represents alignment of a part of the read. The refIndex in this case
+ * should be the position where the alignment of that part of the read starts at. In other words, both refIndex and readIndex are
+ * always the positions where the cigar starts on the ref and on the read, respectively.
+ * <p/>
+ * If the alignment has one or more indels, this method attempts to move them left across a stretch of repetitive bases.
+ * For instance, if the original cigar specifies that (any) one AT is deleted from a repeat sequence TATATATA, the output
+ * cigar will always mark the leftmost AT as deleted. If there is no indel in the original cigar or if the indel position
+ * is determined unambiguously (i.e. inserted/deleted sequence is not repeated), the original cigar is returned.
+ *
+ * Note that currently we do not actually support the case where there is more than one indel in the alignment. We will throw
+ * an exception if there is -- unless the
+ *
+ * @param cigar structure of the original alignment
+ * @param refSeq reference sequence the read is aligned to
+ * @param readSeq read sequence
+ * @param refIndex 0-based alignment start position on ref
+ * @param readIndex 0-based alignment start position on read
+ * @param doNotThrowExceptionForMultipleIndels if true we will not throw an exception if we encounter multiple indels in the alignment will instead will return the original cigar
+ * @return a non-null cigar, in which the indels are guaranteed to be placed at the leftmost possible position across a repeat (if any)
+ */
+ @Ensures("result != null")
+ public static Cigar leftAlignIndel(Cigar cigar, final byte[] refSeq, final byte[] readSeq, final int refIndex, final int readIndex, final boolean doNotThrowExceptionForMultipleIndels) {
+ ensureLeftAlignmentHasGoodArguments(cigar, refSeq, readSeq, refIndex, readIndex);
+
+ final int numIndels = countIndelElements(cigar);
+ if ( numIndels == 0 )
+ return cigar;
+ if ( numIndels == 1 )
+ return leftAlignSingleIndel(cigar, refSeq, readSeq, refIndex, readIndex, true);
+
+ // if we got here then there is more than 1 indel in the alignment
+ if ( doNotThrowExceptionForMultipleIndels )
+ return cigar;
+
+ throw new UnsupportedOperationException("attempting to left align a CIGAR that has more than 1 indel in its alignment but this functionality has not been implemented yet");
+ }
+
+ private static void ensureLeftAlignmentHasGoodArguments(final Cigar cigar, final byte[] refSeq, final byte[] readSeq, final int refIndex, final int readIndex) {
+ if ( cigar == null ) throw new IllegalArgumentException("attempting to left align a CIGAR that is null");
+ if ( refSeq == null ) throw new IllegalArgumentException("attempting to left align a reference sequence that is null");
+ if ( readSeq == null ) throw new IllegalArgumentException("attempting to left align a read sequence that is null");
+ if ( refIndex < 0 ) throw new IllegalArgumentException("attempting to left align with a reference index less than 0");
+ if ( readIndex < 0 ) throw new IllegalArgumentException("attempting to left align with a read index less than 0");
+ }
+
+ /**
+ * Counts the number of I/D operators
+ *
+ * @param cigar cigar to check -- cannot be null
+ * @return non-negative count of indel operators
+ */
+ @Requires("cigar != null")
+ @Ensures("result >= 0")
+ private static int countIndelElements(final Cigar cigar) {
+ int indelCount = 0;
+ for ( CigarElement ce : cigar.getCigarElements() ) {
+ if ( ce.getOperator() == CigarOperator.D || ce.getOperator() == CigarOperator.I )
+ indelCount++;
+ }
+ return indelCount;
+ }
+
+ /**
+ * See the documentation for AlignmentUtils.leftAlignIndel() for more details.
+ *
+ * This flavor of the left alignment works if and only if the alignment has one - and only one - indel.
+ * An exception is thrown if there are no indels or more than 1 indel in the alignment.
+ *
+ * @param cigar structure of the original alignment -- cannot be null
+ * @param refSeq reference sequence the read is aligned to
+ * @param readSeq read sequence
+ * @param refIndex 0-based alignment start position on ref
+ * @param readIndex 0-based alignment start position on read
+ * @param cleanupCigar if true, we'll cleanup the resulting cigar element, removing 0 length elements and deletions from the first cigar position
+ * @return a non-null cigar, in which the single indel is guaranteed to be placed at the leftmost possible position across a repeat (if any)
+ */
+ @Ensures("result != null")
+ public static Cigar leftAlignSingleIndel(Cigar cigar, final byte[] refSeq, final byte[] readSeq, final int refIndex, final int readIndex, final boolean cleanupCigar) {
+ ensureLeftAlignmentHasGoodArguments(cigar, refSeq, readSeq, refIndex, readIndex);
+
+ int indexOfIndel = -1;
+ for (int i = 0; i < cigar.numCigarElements(); i++) {
+ CigarElement ce = cigar.getCigarElement(i);
+ if (ce.getOperator() == CigarOperator.D || ce.getOperator() == CigarOperator.I) {
+ // if there is more than 1 indel, exception out
+ if (indexOfIndel != -1)
+ throw new IllegalArgumentException("attempting to left align a CIGAR that has more than 1 indel in its alignment");
+ indexOfIndel = i;
+ }
+ }
+
+ // if there is no indel, exception out
+ if ( indexOfIndel == -1 )
+ throw new IllegalArgumentException("attempting to left align a CIGAR that has no indels in its alignment");
+ // if the alignment starts with an insertion (so that there is no place on the read to move that insertion further left), we are done
+ if ( indexOfIndel == 0 )
+ return cigar;
+
+ final int indelLength = cigar.getCigarElement(indexOfIndel).getLength();
+
+ byte[] altString = createIndelString(cigar, indexOfIndel, refSeq, readSeq, refIndex, readIndex);
+ if (altString == null)
+ return cigar;
+
+ Cigar newCigar = cigar;
+ for (int i = 0; i < indelLength; i++) {
+ newCigar = moveCigarLeft(newCigar, indexOfIndel);
+ byte[] newAltString = createIndelString(newCigar, indexOfIndel, refSeq, readSeq, refIndex, readIndex);
+
+ // check to make sure we haven't run off the end of the read
+ boolean reachedEndOfRead = cigarHasZeroSizeElement(newCigar);
+
+ if (Arrays.equals(altString, newAltString)) {
+ cigar = newCigar;
+ i = -1;
+ if (reachedEndOfRead)
+ cigar = cleanupCigar ? cleanUpCigar(cigar) : cigar;
+ }
+
+ if (reachedEndOfRead)
+ break;
+ }
+
+ return cigar;
+ }
+
+ /**
+ * Does one of the elements in cigar have a 0 length?
+ *
+ * @param c a non-null cigar
+ * @return true if any element has 0 size
+ */
+ @Requires("c != null")
+ protected static boolean cigarHasZeroSizeElement(final Cigar c) {
+ for (final CigarElement ce : c.getCigarElements()) {
+ if (ce.getLength() == 0)
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Clean up the incoming cigar
+ *
+ * Removes elements with zero size
+ * Clips away beginning deletion operators
+ *
+ * @param c the cigar string we want to clean up
+ * @return a newly allocated, cleaned up Cigar
+ */
+ @Requires("c != null")
+ @Ensures("result != null")
+ public static Cigar cleanUpCigar(final Cigar c) {
+ final List<CigarElement> elements = new ArrayList<CigarElement>(c.numCigarElements() - 1);
+
+ for (final CigarElement ce : c.getCigarElements()) {
+ if (ce.getLength() != 0 && (! elements.isEmpty() || ce.getOperator() != CigarOperator.D)) {
+ elements.add(ce);
+ }
+ }
+
+ return new Cigar(elements);
+ }
+
+ /**
+ * Removing a trailing deletion from the incoming cigar if present
+ *
+ * @param c the cigar we want to update
+ * @return a non-null Cigar
+ */
+ @Requires("c != null")
+ @Ensures("result != null")
+ public static Cigar removeTrailingDeletions(final Cigar c) {
+
+ final List<CigarElement> elements = c.getCigarElements();
+ if ( elements.get(elements.size() - 1).getOperator() != CigarOperator.D )
+ return c;
+
+ return new Cigar(elements.subList(0, elements.size() - 1));
+ }
+
+ /**
+ * Move the indel in a given cigar string one base to the left
+ *
+ * @param cigar original cigar
+ * @param indexOfIndel the index of the indel cigar element
+ * @return non-null cigar with indel moved one base to the left
+ */
+ @Requires("cigar != null && indexOfIndel >= 0 && indexOfIndel < cigar.numCigarElements()")
+ @Ensures("result != null")
+ private static Cigar moveCigarLeft(Cigar cigar, int indexOfIndel) {
+ // get the first few elements
+ ArrayList<CigarElement> elements = new ArrayList<CigarElement>(cigar.numCigarElements());
+ for (int i = 0; i < indexOfIndel - 1; i++)
+ elements.add(cigar.getCigarElement(i));
+
+ // get the indel element and move it left one base
+ CigarElement ce = cigar.getCigarElement(indexOfIndel - 1);
+ elements.add(new CigarElement(Math.max(ce.getLength() - 1, 0), ce.getOperator()));
+ elements.add(cigar.getCigarElement(indexOfIndel));
+ if (indexOfIndel + 1 < cigar.numCigarElements()) {
+ ce = cigar.getCigarElement(indexOfIndel + 1);
+ elements.add(new CigarElement(ce.getLength() + 1, ce.getOperator()));
+ } else {
+ elements.add(new CigarElement(1, CigarOperator.M));
+ }
+
+ // get the last few elements
+ for (int i = indexOfIndel + 2; i < cigar.numCigarElements(); i++)
+ elements.add(cigar.getCigarElement(i));
+ return new Cigar(elements);
+ }
+
+ /**
+ * Create the string (really a byte array) representation of an indel-containing cigar against the reference.
+ *
+ * @param cigar the indel-containing cigar
+ * @param indexOfIndel the index of the indel cigar element
+ * @param refSeq the reference sequence
+ * @param readSeq the read sequence for the cigar
+ * @param refIndex the starting reference index into refSeq
+ * @param readIndex the starting read index into readSeq
+ * @return non-null byte array which is the indel representation against the reference
+ */
+ @Requires("cigar != null && indexOfIndel >= 0 && indexOfIndel < cigar.numCigarElements() && refSeq != null && readSeq != null && refIndex >= 0 && readIndex >= 0")
+ @Ensures("result != null")
+ private static byte[] createIndelString(final Cigar cigar, final int indexOfIndel, final byte[] refSeq, final byte[] readSeq, int refIndex, int readIndex) {
+ CigarElement indel = cigar.getCigarElement(indexOfIndel);
+ int indelLength = indel.getLength();
+
+ int totalRefBases = 0;
+ for (int i = 0; i < indexOfIndel; i++) {
+ CigarElement ce = cigar.getCigarElement(i);
+ int length = ce.getLength();
+
+ switch (ce.getOperator()) {
+ case M:
+ case EQ:
+ case X:
+ readIndex += length;
+ refIndex += length;
+ totalRefBases += length;
+ break;
+ case S:
+ readIndex += length;
+ break;
+ case N:
+ refIndex += length;
+ totalRefBases += length;
+ break;
+ default:
+ break;
+ }
+ }
+
+ // sometimes, when there are very large known indels, we won't have enough reference sequence to cover them
+ if (totalRefBases + indelLength > refSeq.length)
+ indelLength -= (totalRefBases + indelLength - refSeq.length);
+
+ // the indel-based reference string
+ byte[] alt = new byte[refSeq.length + (indelLength * (indel.getOperator() == CigarOperator.D ? -1 : 1))];
+
+ // add the bases before the indel, making sure it's not aligned off the end of the reference
+ if (refIndex > alt.length || refIndex > refSeq.length)
+ return null;
+ System.arraycopy(refSeq, 0, alt, 0, refIndex);
+ int currentPos = refIndex;
+
+ // take care of the indel
+ if (indel.getOperator() == CigarOperator.D) {
+ refIndex += indelLength;
+ } else {
+ System.arraycopy(readSeq, readIndex, alt, currentPos, indelLength);
+ currentPos += indelLength;
+ }
+
+ // add the bases after the indel, making sure it's not aligned off the end of the reference
+ if (refSeq.length - refIndex > alt.length - currentPos)
+ return null;
+ System.arraycopy(refSeq, refIndex, alt, currentPos, refSeq.length - refIndex);
+
+ return alt;
+ }
+
+
+ /**
+ * Trim cigar down to one that starts at start reference on the left and extends to end on the reference
+ *
+ * @param cigar a non-null Cigar to trim down
+ * @param start Where should we start keeping bases on the reference? The first position is 0
+ * @param end Where should we stop keeping bases on the reference? The maximum value is cigar.getReferenceLength()
+ * @return a new Cigar with reference length == start - end + 1
+ */
+ public static Cigar trimCigarByReference(final Cigar cigar, final int start, final int end) {
+ if ( start < 0 ) throw new IllegalArgumentException("Start must be >= 0 but got " + start);
+ if ( end < start ) throw new IllegalArgumentException("End " + end + " is < start start " + start);
+ if ( end > cigar.getReferenceLength() ) throw new IllegalArgumentException("End is beyond the cigar's reference length " + end + " for cigar " + cigar );
+
+ final Cigar result = trimCigar(cigar, start, end, true);
+
+ if ( result.getReferenceLength() != end - start + 1)
+ throw new IllegalStateException("trimCigarByReference failure: start " + start + " end " + end + " for " + cigar + " resulted in cigar with wrong size " + result);
+ return result;
+ }
+
+ /**
+ * Trim cigar down to one that starts at start base in the cigar and extends to (inclusive) end base
+ *
+ * @param cigar a non-null Cigar to trim down
+ * @param start Where should we start keeping bases in the cigar? The first position is 0
+ * @param end Where should we stop keeping bases in the cigar? The maximum value is cigar.getReadLength()
+ * @return a new Cigar containing == start - end + 1 reads
+ */
+ public static Cigar trimCigarByBases(final Cigar cigar, final int start, final int end) {
+ if ( start < 0 ) throw new IllegalArgumentException("Start must be >= 0 but got " + start);
+ if ( end < start ) throw new IllegalArgumentException("End " + end + " is < start = " + start);
+ if ( end > cigar.getReadLength() ) throw new IllegalArgumentException("End is beyond the cigar's read length " + end + " for cigar " + cigar );
+
+ final Cigar result = trimCigar(cigar, start, end, false);
+
+ final int expectedSize = end - start + 1;
+ if ( result.getReadLength() != expectedSize)
+ throw new IllegalStateException("trimCigarByBases failure: start " + start + " end " + end + " for " + cigar + " resulted in cigar with wrong size " + result + " with size " + result.getReadLength() + " expected " + expectedSize + " for input cigar " + cigar);
+ return result;
+ }
+
+
+ /**
+ * Workhorse for trimCigarByBases and trimCigarByReference
+ *
+ * @param cigar a non-null Cigar to trim down
+ * @param start Where should we start keeping bases in the cigar? The first position is 0
+ * @param end Where should we stop keeping bases in the cigar? The maximum value is cigar.getReadLength()
+ * @param byReference should start and end be intrepreted as position in the reference or the read to trim to/from?
+ * @return a non-null cigar
+ */
+ @Requires({"cigar != null", "start >= 0", "start <= end"})
+ @Ensures("result != null")
+ private static Cigar trimCigar(final Cigar cigar, final int start, final int end, final boolean byReference) {
+ final List<CigarElement> newElements = new LinkedList<CigarElement>();
+
+ int pos = 0;
+ for ( final CigarElement elt : cigar.getCigarElements() ) {
+ if ( pos > end && (byReference || elt.getOperator() != CigarOperator.D) ) break;
+
+ switch ( elt.getOperator() ) {
+ case D:
+ if ( ! byReference ) {
+ if ( pos >= start )
+ newElements.add(elt);
+ break;
+ }
+ // otherwise fall through to the next case
+ case EQ: case M: case X:
+ pos = addCigarElements(newElements, pos, start, end, elt);
+ break;
+ case S: case I:
+ if ( byReference ) {
+ if ( pos >= start )
+ newElements.add(elt);
+ } else {
+ pos = addCigarElements(newElements, pos, start, end, elt);
+ }
+ break;
+ default:
+ throw new IllegalStateException("Cannot handle " + elt);
+ }
+ }
+
+ return AlignmentUtils.consolidateCigar(new Cigar(newElements));
+ }
+
+ /**
+ * Helper function for trimCigar that adds cigar elements (of total length X) of elt.op to dest for
+ * X bases that fall between start and end, where the last position of the base is pos.
+ *
+ * The primary use of this function is to create a new cigar element list that contains only
+ * elements that occur between start and end bases in an initial cigar.
+ *
+ * Note that this function may return multiple cigar elements (1M1M etc) that are best consolidated
+ * after the fact into a single simpler representation.
+ *
+ * @param dest we will append our cigar elements to this list
+ * @param pos the position (0 indexed) where elt started
+ * @param start only include bases that occur >= this position
+ * @param end only include bases that occur <= this position
+ * @param elt the element we are slicing down
+ * @return the position after we've traversed all elt.length bases of elt
+ */
+ protected static int addCigarElements(final List<CigarElement> dest, int pos, final int start, final int end, final CigarElement elt) {
+ final int length = Math.min(pos + elt.getLength() - 1, end) - Math.max(pos, start) + 1;
+ if ( length > 0 )
+ dest.add(new CigarElement(length, elt.getOperator()));
+ return pos + elt.getLength();
+ }
+
+ /**
+ * Get the offset (base 0) of the first reference aligned base in Cigar that occurs after readStartByBaseOfCigar base of the cigar
+ *
+ * The main purpose of this routine is to find a good start position for a read given it's cigar. The real
+ * challenge is that the starting base might be inside an insertion, in which case the read actually starts
+ * at the next M/EQ/X operator.
+ *
+ * @param cigar a non-null cigar
+ * @param readStartByBaseOfCigar finds the first base after this (0 indexed) that aligns to the reference genome (M, EQ, X)
+ * @throws IllegalStateException if no such base can be found
+ * @return an offset into cigar
+ */
+ public static int calcFirstBaseMatchingReferenceInCigar(final Cigar cigar, int readStartByBaseOfCigar) {
+ if ( cigar == null ) throw new IllegalArgumentException("cigar cannot be null");
+ if ( readStartByBaseOfCigar >= cigar.getReadLength() ) throw new IllegalArgumentException("readStartByBaseOfCigar " + readStartByBaseOfCigar + " must be <= readLength " + cigar.getReadLength());
+
+ int hapOffset = 0, refOffset = 0;
+ for ( final CigarElement ce : cigar.getCigarElements() ) {
+ for ( int i = 0; i < ce.getLength(); i++ ) {
+ switch ( ce.getOperator() ) {
+ case M:case EQ:case X:
+ if ( hapOffset >= readStartByBaseOfCigar )
+ return refOffset;
+ hapOffset++;
+ refOffset++;
+ break;
+ case I: case S:
+ hapOffset++;
+ break;
+ case D:
+ refOffset++;
+ break;
+ default:
+ throw new IllegalStateException("calcFirstBaseMatchingReferenceInCigar does not support cigar " + ce.getOperator() + " in cigar " + cigar);
+ }
+ }
+ }
+
+ throw new IllegalStateException("Never found appropriate matching state for cigar " + cigar + " given start of " + readStartByBaseOfCigar);
+ }
+
+ /**
+ * Generate a new Cigar that maps the operations of the first cigar through those in a second
+ *
+ * For example, if first is 5M and the second is 2M1I2M then the result is 2M1I2M.
+ * However, if first is 1M2D3M and second is 2M1I3M this results in a cigar X
+ *
+ * ref : AC-GTA
+ * hap : ACxGTA - 2M1I3M
+ * read : A--GTA - 1M2D3M
+ * result: A--GTA => 1M1D3M
+ *
+ * ref : ACxG-TA
+ * hap : AC-G-TA - 2M1D3M
+ * read : AC-GxTA - 3M1I2M
+ * result: AC-GxTA => 2M1D1M1I2M
+ *
+ * ref : ACGTA
+ * hap : ACGTA - 5M
+ * read : A-GTA - 1M1I3M
+ * result: A-GTA => 1M1I3M
+ *
+ * ref : ACGTAC
+ * hap : AC---C - 2M3D1M
+ * read : AC---C - 3M
+ * result: AG---C => 2M3D
+ *
+ * The constraint here is that both cigars should imply that the result have the same number of
+ * reference bases (i.e.g, cigar.getReferenceLength() are equals).
+ *
+ * @param firstToSecond the cigar mapping hap1 -> hap2
+ * @param secondToThird the cigar mapping hap2 -> hap3
+ * @return A cigar mapping hap1 -> hap3
+ */
+ public static Cigar applyCigarToCigar(final Cigar firstToSecond, final Cigar secondToThird) {
+ final boolean DEBUG = false;
+
+ final List<CigarElement> newElements = new LinkedList<CigarElement>();
+ final int nElements12 = firstToSecond.getCigarElements().size();
+ final int nElements23 = secondToThird.getCigarElements().size();
+
+ int cigar12I = 0, cigar23I = 0;
+ int elt12I = 0, elt23I = 0;
+
+ while ( cigar12I < nElements12 && cigar23I < nElements23 ) {
+ final CigarElement elt12 = firstToSecond.getCigarElement(cigar12I);
+ final CigarElement elt23 = secondToThird.getCigarElement(cigar23I);
+
+ final CigarPairTransform transform = getTransformer(elt12.getOperator(), elt23.getOperator());
+
+ if ( DEBUG )
+ System.out.printf("Transform %s => %s with elt1 = %d %s @ %d elt2 = %d %s @ %d with transform %s%n",
+ firstToSecond, secondToThird, cigar12I, elt12.getOperator(), elt12I, cigar23I, elt23.getOperator(), elt23I, transform);
+
+ if ( transform.op13 != null ) // skip no ops
+ newElements.add(new CigarElement(1, transform.op13));
+
+ elt12I += transform.advance12;
+ elt23I += transform.advance23;
+
+ // if have exhausted our current element, advance to the next one
+ if ( elt12I == elt12.getLength() ) { cigar12I++; elt12I = 0; }
+ if ( elt23I == elt23.getLength() ) { cigar23I++; elt23I = 0; }
+ }
+
+ return AlignmentUtils.consolidateCigar(new Cigar(newElements));
+ }
+
+ private static CigarPairTransform getTransformer(final CigarOperator op12, final CigarOperator op23) {
+ for ( final CigarPairTransform transform : cigarPairTransformers) {
+ if ( transform.op12.contains(op12) && transform.op23.contains(op23) )
+ return transform;
+ }
+
+ throw new IllegalStateException("No transformer for operators " + op12 + " and " + op23);
+ }
+
+ /**
+ * transformations that project one alignment state through another
+ *
+ * Think about this as a state machine, where we have:
+ *
+ * bases3 : xxx A zzz
+ * bases2 : xxx B zzz
+ * bases1 : xxx C zzz
+ *
+ * where A, B and C are alignment states of a three way alignment. We want to capture
+ * the transition from operation mapping 1 -> 2 and an operation mapping 2 -> 3 and its
+ * associated mapping from 1 -> 3 and the advancement of the cigar states of 1->2 and 2->3.
+ *
+ * Imagine that A, B, and C are all equivalent (so that op12 = M and op23 = M). This implies
+ * a mapping of 1->3 of M, and in this case the next states to consider in the 3 way alignment
+ * are the subsequent states in 1 and 2 (so that advance12 and advance23 are both 1).
+ *
+ * Obviously not all of the states and their associated transitions are so simple. Suppose instead
+ * that op12 = I, and op23 = M. What does this look like:
+ *
+ * bases3 : xxx - A zzz
+ * bases2 : xxx - B zzz
+ * bases1 : xxx I C zzz
+ *
+ * It means that op13 must be an insertion (as we have an extra base in 1 thats not present in 2 and
+ * so not present in 3). We advance the cigar in 1 by 1 (as we've consumed one base in 1 for the I)
+ * but we haven't yet found the base corresponding to the M of op23. So we don't advance23.
+ */
+ private static class CigarPairTransform {
+ private final EnumSet<CigarOperator> op12, op23;
+ private final CigarOperator op13;
+ private final int advance12, advance23;
+
+ private CigarPairTransform(CigarOperator op12, CigarOperator op23, CigarOperator op13, int advance12, int advance23) {
+ this.op12 = getCigarSet(op12);
+ this.op23 = getCigarSet(op23);
+ this.op13 = op13;
+ this.advance12 = advance12;
+ this.advance23 = advance23;
+ }
+
+ private static EnumSet<CigarOperator> getCigarSet(final CigarOperator masterOp) {
+ switch ( masterOp ) {
+ case M: return EnumSet.of(CigarOperator.M, CigarOperator.EQ, CigarOperator.X);
+ case I: return EnumSet.of(CigarOperator.I, CigarOperator.S);
+ case D: return EnumSet.of(CigarOperator.D);
+ default: throw new IllegalStateException("Unexpected state " + masterOp);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "CigarPairTransform{" +
+ "op12=" + op12 +
+ ", op23=" + op23 +
+ ", op13=" + op13 +
+ ", advance12=" + advance12 +
+ ", advance23=" + advance23 +
+ '}';
+ }
+ }
+
+
+ private final static List<CigarPairTransform> cigarPairTransformers = Arrays.asList(
+ //
+ // op12 is a match
+ //
+ // 3: xxx B yyy
+ // ^^^^^^^^^^^^
+ // 2: xxx M yyy
+ // 1: xxx M yyy
+ new CigarPairTransform(CigarOperator.M, CigarOperator.M, CigarOperator.M, 1, 1),
+ // 3: xxx I yyy
+ // ^^^^^^^^^^^^
+ // 2: xxx I yyy
+ // 1: xxx M yyy
+ new CigarPairTransform(CigarOperator.M, CigarOperator.I, CigarOperator.I, 1, 1),
+ // 3: xxx D yyy
+ // ^^^^^^^^^^^^
+ // 2: xxx D yyy
+ // 1: xxx M yyy
+ new CigarPairTransform(CigarOperator.M, CigarOperator.D, CigarOperator.D, 0, 1),
+
+ //
+ // op12 is a deletion
+ //
+ // 3: xxx D M yyy
+ // ^^^^^^^^^^^^
+ // 2: xxx M yyy
+ // 1: xxx D yyy
+ new CigarPairTransform(CigarOperator.D, CigarOperator.M, CigarOperator.D, 1, 1),
+ // 3: xxx D1 D2 yyy
+ // ^^^^^^^^^^^^
+ // 2: xxx D2 yyy
+ // 1: xxx D1 yyy
+ new CigarPairTransform(CigarOperator.D, CigarOperator.D, CigarOperator.D, 1, 0),
+ // 3: xxx X yyy => no-op, we skip emitting anything here
+ // ^^^^^^^^^^^^
+ // 2: xxx I yyy
+ // 1: xxx D yyy
+ new CigarPairTransform(CigarOperator.D, CigarOperator.I, null, 1, 1),
+
+ //
+ // op12 is a insertion
+ //
+ // 3: xxx I M yyy
+ // ^^^^^^^^^^^^
+ // 2: xxx M yyy
+ // 1: xxx I yyy
+ new CigarPairTransform(CigarOperator.I, CigarOperator.M, CigarOperator.I, 1, 0),
+ // 3: xxx I D yyy
+ // ^^^^^^^^^^^^
+ // 2: xxx D yyy
+ // 1: xxx I yyy
+ new CigarPairTransform(CigarOperator.I, CigarOperator.D, CigarOperator.I, 1, 0),
+ // 3: xxx I1 I2 yyy
+ // ^^^^^^^^^^^^
+ // 2: xxx I2 yyy
+ // 1: xxx I1 yyy
+ new CigarPairTransform(CigarOperator.I, CigarOperator.I, CigarOperator.I, 1, 0)
+ );
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialBAMBuilder.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialBAMBuilder.java
new file mode 100644
index 0000000..8233252
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialBAMBuilder.java
@@ -0,0 +1,242 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.NGSPlatform;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Easy to use creator of artificial BAM files for testing
+ *
+ * Allows us to make a stream of reads or an index BAM file with read having the following properties
+ *
+ * - coming from n samples
+ * - of fixed read length and aligned to the genome with M operator
+ * - having N reads per alignment start
+ * - skipping N bases between each alignment start
+ * - starting at a given alignment start
+ *
+ * User: depristo
+ * Date: 1/15/13
+ * Time: 9:22 AM
+ */
+public class ArtificialBAMBuilder {
+ public final static int BAM_SHARD_SIZE = 16384;
+
+ private final IndexedFastaSequenceFile reference;
+ private final GenomeLocParser parser;
+
+ final int nReadsPerLocus;
+ final int nLoci;
+
+ int skipNLoci = 0;
+ int alignmentStart = 1;
+ int readLength = 10;
+ private final ArrayList<String> samples = new ArrayList<String>();
+ private List<GATKSAMRecord> createdReads = null;
+
+ private LinkedList<GATKSAMRecord> additionalReads = new LinkedList<GATKSAMRecord>();
+
+ final SAMFileWriterFactory factory = new SAMFileWriterFactory();
+ {
+ factory.setCreateIndex(true);
+ }
+
+ SAMFileHeader header;
+
+ public ArtificialBAMBuilder(final IndexedFastaSequenceFile reference, int nReadsPerLocus, int nLoci) {
+ this.nReadsPerLocus = nReadsPerLocus;
+ this.nLoci = nLoci;
+
+ this.reference = reference;
+ this.parser = new GenomeLocParser(reference);
+ createAndSetHeader(1);
+ }
+
+ public ArtificialBAMBuilder(int nReadsPerLocus, int nLoci) {
+ this(ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000000).getSequenceDictionary(), nReadsPerLocus, nLoci);
+ }
+
+ public ArtificialBAMBuilder(final SAMSequenceDictionary dict, int nReadsPerLocus, int nLoci) {
+ this.nReadsPerLocus = nReadsPerLocus;
+ this.nLoci = nLoci;
+ this.reference = null;
+ this.parser = new GenomeLocParser(dict);
+ createAndSetHeader(1);
+ }
+
+ public IndexedFastaSequenceFile getReference() {
+ return reference;
+ }
+
+ public GenomeLocParser getGenomeLocParser() {
+ return parser;
+ }
+
+ public ArtificialBAMBuilder createAndSetHeader(final int nSamples) {
+ createdReads = null;
+ this.header = new SAMFileHeader();
+ header.setSortOrder(SAMFileHeader.SortOrder.coordinate);
+ header.setSequenceDictionary(parser.getContigs());
+ samples.clear();
+
+ for ( int i = 0; i < nSamples; i++ ) {
+ final GATKSAMReadGroupRecord rg = new GATKSAMReadGroupRecord("rg" + i);
+ final String sample = "sample" + i;
+ samples.add(sample);
+ rg.setSample(sample);
+ rg.setPlatform(NGSPlatform.ILLUMINA.getDefaultPlatform());
+ header.addReadGroup(rg);
+ }
+
+ return this;
+ }
+
+ public void addReads(final GATKSAMRecord readToAdd) {
+ createdReads = null;
+ additionalReads.add(readToAdd);
+ }
+
+ public void addReads(final Collection<GATKSAMRecord> readsToAdd) {
+ createdReads = null;
+ additionalReads.addAll(readsToAdd);
+ }
+
+ public List<String> getSamples() {
+ return samples;
+ }
+
+ /**
+ * Create a read stream based on the parameters. The cigar string for each
+ * read will be *M, where * is the length of the read.
+ *
+ * Useful for testing things like LocusIteratorBystate
+ *
+ * @return a ordered list of reads
+ */
+ public List<GATKSAMRecord> makeReads() {
+ if ( createdReads == null ) {
+ final String baseName = "read";
+ final LinkedList<GATKSAMReadGroupRecord> readGroups = new LinkedList<GATKSAMReadGroupRecord>();
+ for ( final SAMReadGroupRecord rg : header.getReadGroups())
+ readGroups.add(new GATKSAMReadGroupRecord(rg));
+
+ List<GATKSAMRecord> reads = new ArrayList<GATKSAMRecord>(nReadsPerLocus*nLoci);
+ for ( int locusI = 0; locusI < nLoci; locusI++) {
+ final int locus = locusI * (skipNLoci + 1);
+ for ( int readI = 0; readI < nReadsPerLocus; readI++ ) {
+ for ( final GATKSAMReadGroupRecord rg : readGroups ) {
+ final String readName = String.format("%s.%d.%d.%s", baseName, locus, readI, rg.getId());
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, readName, 0, alignmentStart + locus, readLength);
+ read.setReadGroup(rg);
+ reads.add(read);
+ }
+ }
+ }
+
+ if ( ! additionalReads.isEmpty() ) {
+ reads.addAll(additionalReads);
+ Collections.sort(reads, new SAMRecordCoordinateComparator());
+ }
+
+ createdReads = new ArrayList<GATKSAMRecord>(reads);
+ }
+
+ return createdReads;
+ }
+
+ /**
+ * Make an indexed BAM file contains the reads in the builder, marking it for deleteOnExit()
+ * @return the BAM file
+ */
+ public File makeTemporarilyBAMFile() {
+ try {
+ final File file = File.createTempFile("tempBAM", ".bam");
+ file.deleteOnExit();
+
+ // Register the bam index file for deletion on exit as well:
+ new File(file.getAbsolutePath().replace(".bam", ".bai")).deleteOnExit();
+ new File(file.getAbsolutePath() + ".bai").deleteOnExit();
+
+ return makeBAMFile(file);
+ } catch ( IOException e ) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Write the reads from this builder to output, creating an index as well
+ * @param output the output BAM file we want to use
+ * @return
+ */
+ public File makeBAMFile(final File output) {
+ final SAMFileWriter writer = factory.makeBAMWriter(header, true, output, 0);
+ for ( final GATKSAMRecord read : makeReads() )
+ writer.addAlignment(read);
+ writer.close();
+ return output;
+ }
+
+ public int getnReadsPerLocus() { return nReadsPerLocus; }
+ public int getnLoci() { return nLoci; }
+ public int getSkipNLoci() { return skipNLoci; }
+ public ArtificialBAMBuilder setSkipNLoci(int skipNLoci) { this.skipNLoci = skipNLoci; createdReads = null; return this; }
+ public int getAlignmentStart() { return alignmentStart; }
+ public ArtificialBAMBuilder setAlignmentStart(int alignmentStart) { this.alignmentStart = alignmentStart; createdReads = null; return this; }
+ public int getReadLength() { return readLength; }
+ public ArtificialBAMBuilder setReadLength(int readLength) { this.readLength = readLength; createdReads = null; return this; }
+ public SAMFileHeader getHeader() { return header; }
+ public ArtificialBAMBuilder setHeader(SAMFileHeader header) { this.header = header; createdReads = null; return this; }
+
+ public int getAlignmentEnd() {
+ return alignmentStart + nLoci * (skipNLoci + 1) + readLength;
+ }
+
+
+ public int getNSamples() { return samples.size(); }
+
+ public int expectedNumberOfReads() {
+ return nLoci * nReadsPerLocus * header.getReadGroups().size();
+ }
+
+ @Override
+ public String toString() {
+ return "ArtificialBAMBuilder{" +
+ "samples=" + samples +
+ ", readLength=" + readLength +
+ ", alignmentStart=" + alignmentStart +
+ ", skipNLoci=" + skipNLoci +
+ ", nLoci=" + nLoci +
+ ", nReadsPerLocus=" + nReadsPerLocus +
+ '}';
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialGATKSAMFileWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialGATKSAMFileWriter.java
new file mode 100644
index 0000000..0821f46
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialGATKSAMFileWriter.java
@@ -0,0 +1,130 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.ProgressLoggerInterface;
+import org.broadinstitute.gatk.engine.io.GATKSAMFileWriter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author aaron
+ * <p/>
+ * Class ArtificialGATKSAMFileWriter
+ * <p/>
+ * generates a fake samwriter, that you can get the output reads
+ * from when you're done.
+ */
+public class ArtificialGATKSAMFileWriter implements GATKSAMFileWriter {
+
+ // are we closed
+ private boolean closed = false;
+
+ // the SAMRecords we've added to this writer
+ List<SAMRecord> records = new ArrayList<SAMRecord>();
+
+ public void addAlignment( SAMRecord alignment ) {
+ records.add(alignment);
+ }
+
+ public SAMFileHeader getFileHeader() {
+ if (records.size() > 0) {
+ return records.get(0).getHeader();
+ }
+ return null;
+ }
+
+ /** not much to do when we're fake */
+ public void close() {
+ closed = true;
+ }
+
+ /**
+ * are we closed?
+ *
+ * @return true if we're closed
+ */
+ public boolean isClosed() {
+ return closed;
+ }
+
+ /**
+ * get the records we've seen
+ * @return
+ */
+ public List<SAMRecord> getRecords() {
+ return records;
+ }
+
+ @Override
+ public void writeHeader(SAMFileHeader header) {
+ }
+
+ @Override
+ public void setPresorted(boolean presorted) {
+ }
+
+ @Override
+ public void setMaxRecordsInRam(int maxRecordsInRam) {
+ }
+
+ /**
+ * @throws java.lang.UnsupportedOperationException No progress logging in this implementation.
+ */
+ @Override
+ public void setProgressLogger(final ProgressLoggerInterface logger) {
+ throw new UnsupportedOperationException("Progress logging not supported");
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialMultiSampleReadStream.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialMultiSampleReadStream.java
new file mode 100644
index 0000000..84978c1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialMultiSampleReadStream.java
@@ -0,0 +1,87 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.MergingSamRecordIterator;
+import htsjdk.samtools.SamFileHeaderMerger;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIteratorAdapter;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.*;
+
+/**
+ * Simple wrapper class that multiplexes multiple ArtificialSingleSampleReadStreams into a single stream of reads
+ *
+ * @author David Roazen
+ */
+public class ArtificialMultiSampleReadStream implements Iterable<SAMRecord> {
+
+ private Collection<ArtificialSingleSampleReadStream> perSampleArtificialReadStreams;
+ private MergingSamRecordIterator mergingIterator;
+
+ public ArtificialMultiSampleReadStream( Collection<ArtificialSingleSampleReadStream> perSampleArtificialReadStreams ) {
+ if ( perSampleArtificialReadStreams == null || perSampleArtificialReadStreams.isEmpty() ) {
+ throw new ReviewedGATKException("Can't create an ArtificialMultiSampleReadStream out of 0 ArtificialSingleSampleReadStreams");
+ }
+
+ this.perSampleArtificialReadStreams = perSampleArtificialReadStreams;
+ }
+
+ public Iterator<SAMRecord> iterator() {
+ // lazy initialization to prevent reads from being created until they're needed
+ initialize();
+
+ return mergingIterator;
+ }
+
+ public GATKSAMIterator getGATKSAMIterator() {
+ // lazy initialization to prevent reads from being created until they're needed
+ initialize();
+
+ return GATKSAMIteratorAdapter.adapt(mergingIterator);
+ }
+
+ private void initialize() {
+ Collection<SAMFileReader> perSampleSAMReaders = new ArrayList<SAMFileReader>(perSampleArtificialReadStreams.size());
+ Collection<SAMFileHeader> headers = new ArrayList<SAMFileHeader>(perSampleArtificialReadStreams.size());
+
+ for ( ArtificialSingleSampleReadStream readStream : perSampleArtificialReadStreams ) {
+ Collection<SAMRecord> thisStreamReads = readStream.makeReads();
+
+ SAMFileReader reader = new ArtificialSAMFileReader(readStream.getHeader(),
+ thisStreamReads.toArray(new SAMRecord[thisStreamReads.size()]));
+ perSampleSAMReaders.add(reader);
+ headers.add(reader.getFileHeader());
+ }
+
+ SamFileHeaderMerger headerMerger = new SamFileHeaderMerger(SAMFileHeader.SortOrder.coordinate, headers, true);
+ mergingIterator = new MergingSamRecordIterator(headerMerger, perSampleSAMReaders, true);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialPatternedSAMIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialPatternedSAMIterator.java
new file mode 100644
index 0000000..8434e15
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialPatternedSAMIterator.java
@@ -0,0 +1,172 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author aaron
+ *
+ * Class ArtificialPatternedSAMIterator
+ *
+ * This class allows you to pattern the artificial sam iterator, asking for reads
+ * in order or out of order.
+ */
+public class ArtificialPatternedSAMIterator extends ArtificialSAMIterator {
+
+ /** the pattern we're implementing */
+ public enum PATTERN {
+ RANDOM_READS, IN_ORDER_READS;
+ }
+
+ // our pattern
+ private final PATTERN mPattern;
+
+ /**
+ * this is pretty heavy (and it could be extremely heavy, given the amount of reads they request, but it
+ * allows us to give them each read once, reguardless of the order specified
+ */
+ private final int[] reads;
+ private final int readCount;
+
+ /**
+ * create the fake iterator, given the mapping of chromosomes and read counts. If pattern
+ * is specified to be random, it will generate reads that are randomly placed on the current chromosome
+ *
+ * @param startingChr the starting chromosome
+ * @param endingChr the ending chromosome
+ * @param readCount the number of reads in each chromosome
+ * @param header the associated header
+ * @param pattern the pattern to implement
+ */
+ ArtificialPatternedSAMIterator( int startingChr, int endingChr, int readCount, int unmappedReadCount, SAMFileHeader header, PATTERN pattern ) {
+ super(startingChr, endingChr, readCount, unmappedReadCount, header);
+ mPattern = pattern;
+ this.readCount = readCount;
+ reads = new int[readCount];
+
+ for (int x = 0; x < readCount; x++) {
+ reads[x] = x+1;
+ }
+ if (pattern == PATTERN.RANDOM_READS) {
+ // scramble a bunch of the reads
+ for (int y = 0; y < readCount; y++) {
+ int ranOne = (int) Math.round(Math.random() * ( readCount - 1 ));
+ int ranTwo = (int) Math.round(Math.random() * ( readCount - 1 ));
+ int temp = reads[ranOne];
+ reads[ranOne] = reads[ranTwo];
+ reads[ranTwo] = temp;
+ }
+ /**
+ * up to this point there's no garauntee that the random() has made the reads out of order (though it's
+ * extremely extremely unlikely it's failed). Let's make sure there at least out of order:
+ */
+ if (this.reads[0] < this.reads[reads.length - 1]) {
+ int temp = reads[0];
+ reads[0] = reads[reads.length - 1];
+ reads[reads.length - 1] = temp;
+ }
+
+ }
+
+ }
+
+ /**
+ * override the default ArtificialSAMIterator createNextRead method, which creates the next read
+ *
+ * @return
+ */
+ protected boolean createNextRead() {
+ if (currentRead > rCount) {
+ currentChromo++;
+ currentRead = 1;
+ }
+ // check for end condition, have we finished the chromosome listing, and have no unmapped reads
+ if (currentChromo >= eChromosomeCount) {
+ if (unmappedRemaining < 1) {
+ this.next = null;
+ return false;
+ } else {
+ ++totalReadCount;
+ this.next = ArtificialSAMUtils.createArtificialRead(this.header,
+ String.valueOf(totalReadCount),
+ SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX,
+ SAMRecord.NO_ALIGNMENT_START,
+ 50);
+ --unmappedRemaining;
+ return true;
+ }
+ }
+ ++totalReadCount;
+ this.next = getNextRecord(currentRead);
+
+ ++currentRead;
+ return true;
+ }
+
+
+ /**
+ * get the next read, given it's index in the chromosome
+ *
+ * @param read the read index in the chromosome
+ *
+ * @return a SAMRecord
+ */
+ private SAMRecord getNextRecord( int read ) {
+ if (read > this.readCount) {
+ return ArtificialSAMUtils.createArtificialRead(this.header, String.valueOf(reads[readCount - 1]), currentChromo, reads[readCount - 1], 50);
+ }
+ return ArtificialSAMUtils.createArtificialRead(this.header, String.valueOf(reads[read-1]), currentChromo, reads[read-1], 50);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialReadsTraversal.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialReadsTraversal.java
new file mode 100644
index 0000000..54c2b87
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialReadsTraversal.java
@@ -0,0 +1,140 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.datasources.providers.ShardDataProvider;
+import org.broadinstitute.gatk.engine.traversals.TraversalEngine;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author aaron
+ *
+ * this class acts as a fake reads traversal engine for testing out reads based traversals.
+ */
+public class ArtificialReadsTraversal<M,T> extends TraversalEngine<M,T,Walker<M,T>,ShardDataProvider> {
+
+ public int startingChr = 1;
+ public int endingChr = 5;
+ public int readsPerChr = 100;
+ public int unMappedReads = 1000;
+ private int DEFAULT_READ_LENGTH = ArtificialSAMUtils.DEFAULT_READ_LENGTH;
+ private ArtificialPatternedSAMIterator iter;
+ /** our log, which we want to capture anything from this class */
+ protected static Logger logger = Logger.getLogger(ArtificialReadsTraversal.class);
+
+ /** Creates a new, uninitialized ArtificialReadsTraversal */
+ public ArtificialReadsTraversal() {
+ }
+
+ // what read ordering are we using
+ private ArtificialPatternedSAMIterator.PATTERN readOrder = ArtificialPatternedSAMIterator.PATTERN.IN_ORDER_READS;
+
+
+ /**
+ * set the read ordering of the reads given to the walker
+ *
+ * @param readOrdering
+ */
+ public void setReadOrder( ArtificialPatternedSAMIterator.PATTERN readOrdering ) {
+ readOrder = readOrdering;
+ }
+
+ @Override
+ public String getTraversalUnits() {
+ return "reads";
+ }
+
+ /**
+ * Traverse by reads, given the data and the walker
+ *
+ * @param walker the walker to traverse with
+ * @param dataProvider the provider of the reads data
+ * @param sum the value of type T, specified by the walker, to feed to the walkers reduce function
+ *
+ * @return the reduce variable of the read walker
+ */
+ public T traverse( Walker<M, T> walker,
+ ShardDataProvider dataProvider,
+ T sum ) {
+
+ if (!( walker instanceof ReadWalker ))
+ throw new IllegalArgumentException("Walker isn't a read walker!");
+
+ ReadWalker<M, T> readWalker = (ReadWalker<M, T>) walker;
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(( endingChr - startingChr ) + 1, startingChr, readsPerChr + DEFAULT_READ_LENGTH);
+ iter = new ArtificialPatternedSAMIterator(this.startingChr,
+ this.endingChr,
+ this.readsPerChr,
+ this.unMappedReads,
+ header,
+ this.readOrder);
+
+ // while we still have more reads
+ for (SAMRecord read : iter) {
+
+ // an array of characters that represent the reference
+ ReferenceContext refSeq = null;
+
+ final boolean keepMeP = readWalker.filter(refSeq, (GATKSAMRecord) read);
+ if (keepMeP) {
+ M x = readWalker.map(refSeq, (GATKSAMRecord) read, null); // TODO: fix me at some point, it would be nice to fake out ROD data too
+ sum = readWalker.reduce(x, sum);
+ }
+ }
+ return sum;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMFileReader.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMFileReader.java
new file mode 100644
index 0000000..427b12e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMFileReader.java
@@ -0,0 +1,156 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+/**
+ * User: hanna
+ * Date: Jun 11, 2009
+ * Time: 9:35:31 AM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Pass specified reads into the given walker.
+ */
+
+public class ArtificialSAMFileReader extends SAMFileReader {
+ /**
+ * The parser, for GenomeLocs.
+ */
+ private final GenomeLocParser genomeLocParser;
+
+ /**
+ * Backing data store of reads.
+ */
+ private final List<SAMRecord> reads;
+
+ private SAMFileHeader customHeader = null;
+
+ /**
+ * Construct an artificial SAM file reader.
+ * @param sequenceDictionary sequence dictionary used to initialize our GenomeLocParser
+ * @param reads Reads to use as backing data source.
+ */
+ public ArtificialSAMFileReader(SAMSequenceDictionary sequenceDictionary,SAMRecord... reads) {
+ super( createEmptyInputStream(),true );
+ this.genomeLocParser = new GenomeLocParser(sequenceDictionary);
+ this.reads = Arrays.asList(reads);
+ }
+
+ /**
+ * Construct an artificial SAM file reader with the given SAM file header
+ *
+ * @param customHeader Header that should be returned by calls to getFileHeader() on this reader
+ * @param reads Reads to use as backing data source.
+ */
+ public ArtificialSAMFileReader( SAMFileHeader customHeader, SAMRecord... reads ) {
+ super(createEmptyInputStream(),true);
+
+ this.customHeader = customHeader;
+ this.genomeLocParser = new GenomeLocParser(customHeader.getSequenceDictionary());
+ this.reads = Arrays.asList(reads);
+ }
+
+
+ @Override
+ public SAMFileHeader getFileHeader() {
+ if ( customHeader != null ) {
+ return customHeader;
+ }
+
+ return super.getFileHeader();
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ @Override
+ public SAMRecordIterator query(final String sequence, final int start, final int end, final boolean contained) {
+ GenomeLoc region = genomeLocParser.createGenomeLoc(sequence, start, end);
+ List<SAMRecord> coveredSubset = new ArrayList<SAMRecord>();
+
+ for( SAMRecord read: reads ) {
+ GenomeLoc readPosition = genomeLocParser.createGenomeLoc(read);
+ if( contained && region.containsP(readPosition) ) coveredSubset.add(read);
+ else if( !contained && readPosition.overlapsP(region) ) coveredSubset.add(read);
+ }
+
+ final Iterator<SAMRecord> iterator = coveredSubset.iterator();
+ return new SAMRecordIterator() {
+ public boolean hasNext() { return iterator.hasNext(); }
+ public SAMRecord next() { return iterator.next(); }
+ public void close() {}
+ public void remove() { iterator.remove(); }
+ public SAMRecordIterator assertSorted(SAMFileHeader.SortOrder sortOrder) { return this; }
+ };
+ }
+
+ @Override
+ public SAMRecordIterator iterator() {
+ return new SAMRecordIterator() {
+ private final Iterator<SAMRecord> iterator = reads.iterator();
+ public boolean hasNext() { return iterator.hasNext(); }
+ public SAMRecord next() { return iterator.next(); }
+ public void close() {}
+ public void remove() { iterator.remove(); }
+ public SAMRecordIterator assertSorted(SAMFileHeader.SortOrder sortOrder) { return this; }
+ };
+ }
+
+ /**
+ * Builds an empty input stream for faking out the sam file reader.
+ * Derive it from a string so that, in the future, it might be possible
+ * to fake the text of a sam file from samtools output, et.c
+ * @return Stream that returns no characters.
+ */
+ private static InputStream createEmptyInputStream() {
+ try {
+ byte[] byteArray = "".getBytes("ISO-8859-1");
+ return new ByteArrayInputStream(byteArray);
+ }
+ catch( UnsupportedEncodingException ex ) {
+ throw new ReviewedGATKException("Unable to build empty input stream",ex);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMIterator.java
new file mode 100644
index 0000000..b133e9c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMIterator.java
@@ -0,0 +1,212 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+
+import java.util.Iterator;
+
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/** this fake iterator allows us to look at how specific piles of reads are handled */
+public class ArtificialSAMIterator implements GATKSAMIterator {
+
+
+ protected int currentChromo = 0;
+ protected int currentRead = 1;
+ protected int totalReadCount = 0;
+ protected int unmappedRemaining = 0;
+ protected boolean done = false;
+ // the next record
+ protected SAMRecord next = null;
+ protected SAMFileHeader header = null;
+
+ // the passed in parameters
+ protected final int sChr;
+ protected final int eChromosomeCount;
+ protected final int rCount;
+ protected final int unmappedReadCount;
+
+ // let us know to make a read, we need this to help out the fake sam query iterator
+ private boolean initialized = false;
+
+ /**
+ * Is this iterator currently open or closed? Closed iterators can be reused.
+ */
+ protected boolean open = false;
+
+ /**
+ * create the fake iterator, given the mapping of chromosomes and read counts
+ *
+ * @param startingChr the starting chromosome
+ * @param endingChr the ending chromosome
+ * @param readCount the number of reads in each chromosome
+ * @param header the associated header
+ */
+ ArtificialSAMIterator( int startingChr, int endingChr, int readCount, SAMFileHeader header ) {
+ sChr = startingChr;
+ eChromosomeCount = (endingChr - startingChr) + 1;
+ rCount = readCount;
+ this.header = header;
+ unmappedReadCount = 0;
+ reset();
+ }
+
+ protected void reset() {
+ this.currentChromo = 0;
+ this.currentRead = 1;
+ this.totalReadCount = 0;
+ this.done = false;
+ this.next = null;
+ this.initialized = false;
+ this.unmappedRemaining = unmappedReadCount;
+ }
+
+ /**
+ * create the fake iterator, given the mapping of chromosomes and read counts
+ *
+ * @param startingChr the starting chromosome
+ * @param endingChr the ending chromosome
+ * @param readCount the number of reads in each chromosome
+ * @param header the associated header
+ */
+ ArtificialSAMIterator( int startingChr, int endingChr, int readCount, int unmappedReadCount, SAMFileHeader header ) {
+ sChr = startingChr;
+ eChromosomeCount = (endingChr - startingChr) + 1;
+ rCount = readCount;
+ this.header = header;
+ this.currentChromo = 0;
+ this.unmappedReadCount = unmappedReadCount;
+ reset();
+ }
+
+ public void close() {
+ open = false;
+ }
+
+ public boolean hasNext() {
+ open = true;
+
+ if (!initialized){
+ initialized = true;
+ createNextRead();
+ }
+ if (this.next != null) {
+ return true;
+ }
+ return false;
+ }
+
+ protected boolean createNextRead() {
+ if (currentRead > rCount) {
+ currentChromo++;
+ currentRead = 1;
+ }
+ // check for end condition, have we finished the chromosome listing, and have no unmapped reads
+ if (currentChromo >= eChromosomeCount) {
+ if (unmappedRemaining < 1) {
+ this.next = null;
+ return false;
+ } else {
+ ++totalReadCount;
+ this.next = ArtificialSAMUtils.createArtificialRead(this.header,
+ String.valueOf(totalReadCount),
+ SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX,
+ SAMRecord.NO_ALIGNMENT_START,
+ 50);
+ --unmappedRemaining;
+ return true;
+ }
+ }
+ ++totalReadCount;
+ this.next = ArtificialSAMUtils.createArtificialRead(this.header, String.valueOf(totalReadCount), currentChromo, currentRead, 50);
+ ++currentRead;
+ return true;
+ }
+
+
+ public SAMRecord next() {
+ open = true;
+
+ SAMRecord ret = next;
+ createNextRead();
+ return ret;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("You've tried to remove on a GATKSAMIterator (unsupported), not to mention that this is a fake iterator.");
+ }
+
+ /**
+ * return this iterator, for the iterable interface
+ * @return
+ */
+ public Iterator<SAMRecord> iterator() {
+ return this;
+ }
+
+ /**
+ * some instrumentation methods
+ */
+ public int readsTaken() {
+ return totalReadCount;
+ }
+
+ /**
+ * peek at the next sam record
+ *
+ * @return
+ */
+ public SAMRecord peek() {
+ return this.next;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMQueryIterator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMQueryIterator.java
new file mode 100644
index 0000000..fe7f7b0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMQueryIterator.java
@@ -0,0 +1,259 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.List;
+
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author aaron
+ *
+ * allows query calls to the artificial sam iterator, which allows you
+ * to test out classes that use specific itervals. The reads returned will
+ * all lie in order in the specified interval.
+ */
+public class ArtificialSAMQueryIterator extends ArtificialSAMIterator {
+
+ // get the next positon
+ protected int finalPos = 0;
+ protected int startPos = 0;
+ protected int contigIndex = -1;
+ protected boolean overlapping = false;
+ protected int startingChr = 0;
+ protected boolean seeked = false;
+
+ /**
+ * create the fake iterator, given the mapping of chromosomes and read counts
+ *
+ * @param startingChr the starting chromosome
+ * @param endingChr the ending chromosome
+ * @param readCount the number of reads in each chromosome
+ * @param header the associated header
+ */
+ ArtificialSAMQueryIterator( int startingChr, int endingChr, int readCount, int unmappedReadCount, SAMFileHeader header ) {
+ super(startingChr, endingChr, readCount, unmappedReadCount, header);
+ this.startingChr = startingChr;
+ }
+
+ @Override
+ protected void reset() {
+ this.startPos = 0;
+ this.finalPos = 0;
+ this.contigIndex = -1;
+ // Doesn't make sense to reset the overlapping flag, because we rely on its state later on.
+ // TODO: Make this a bit more direct.
+ //overlapping = false;
+ this.startingChr = 0;
+ this.seeked = false;
+ super.reset();
+ }
+
+ /**
+ * query containing - get reads contained by the specified interval
+ *
+ * @param contig the contig index string
+ * @param start the start position
+ * @param stop the stop position
+ */
+ public void queryContained( String contig, int start, int stop ) {
+ this.overlapping = false;
+ initialize(contig, start, stop);
+ }
+
+ /**
+ * query containing - get reads contained by the specified interval
+ *
+ * @param contig the contig index string
+ * @param start the start position
+ * @param stop the stop position
+ */
+ public void queryOverlapping( String contig, int start, int stop ) {
+ this.overlapping = true;
+ initialize(contig, start, stop);
+ }
+
+ public void query( String contig, int start, int stop, boolean contained ) {
+ if (contained)
+ queryContained(contig, start, stop);
+ else
+ queryOverlapping(contig, start, stop);
+ }
+
+ public void queryUnmappedReads() {
+ initializeUnmapped();
+ }
+
+ /**
+ * initialize the iterator to an unmapped read position
+ */
+ public void initializeUnmapped() {
+ // throw away data from the previous invocation, if one exists.
+ ensureUntouched();
+ reset();
+
+ while (super.hasNext() && this.peek().getReferenceIndex() >= 0) {
+ super.next();
+ }
+ // sanity check that we have an actual matching read next
+ SAMRecord rec = this.peek();
+ if (rec == null) {
+ throw new ReviewedGATKException("The next read doesn't match");
+ }
+ // set the seeked variable to true
+ seeked = true;
+ }
+
+
+
+
+ /**
+ * initialize the query iterator
+ *
+ * @param contig the contig
+ * @param start the start position
+ * @param stop the stop postition
+ */
+ private void initialize( String contig, int start, int stop ) {
+ // throw away data from the previous invocation, if one exists.
+ ensureUntouched();
+ reset();
+
+ finalPos = stop;
+ startPos = start;
+ if (finalPos < 0) {
+ finalPos = Integer.MAX_VALUE;
+ }
+ // sanity check that we have the contig
+ contigIndex = -1;
+ List<SAMSequenceRecord> list = header.getSequenceDictionary().getSequences();
+ for (SAMSequenceRecord rec : list) {
+ if (rec.getSequenceName().equals(contig)) {
+ contigIndex = rec.getSequenceIndex();
+ }
+ }
+ if (contigIndex < 0) { throw new IllegalArgumentException("ArtificialContig" + contig + " doesn't exist"); }
+ while (super.hasNext() && this.peek().getReferenceIndex() < contigIndex) {
+ super.next();
+ }
+ if (!super.hasNext()) {
+ throw new ReviewedGATKException("Unable to find the target chromosome");
+ }
+ while (super.hasNext() && this.peek().getAlignmentStart() < start) {
+ super.next();
+ }
+ // sanity check that we have an actual matching read next
+ SAMRecord rec = this.peek();
+ if (!matches(rec)) {
+ throw new ReviewedGATKException("The next read doesn't match");
+ }
+ // set the seeked variable to true
+ seeked = true;
+ }
+
+ /**
+ * given a read and the query type, check if it matches our regions
+ *
+ * @param rec the read
+ *
+ * @return true if it belongs in our region
+ */
+ public boolean matches( SAMRecord rec ) {
+ if (rec.getReferenceIndex() != this.contigIndex) {
+ return false;
+ }
+ // if we have an unmapped read, matching the contig is good enough for us
+ if (rec.getReferenceIndex() < 0) {
+ return true;
+ }
+
+ if (!overlapping) {
+ // if the start or the end are somewhere within our range
+ if (( rec.getAlignmentStart() >= startPos && rec.getAlignmentEnd() <= finalPos )) {
+ return true;
+ }
+ } else {
+ if (( rec.getAlignmentStart() <= finalPos && rec.getAlignmentStart() >= startPos ) ||
+ ( rec.getAlignmentEnd() <= finalPos && rec.getAlignmentEnd() >= startPos )) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * override the hasNext, to incorportate our limiting factor
+ *
+ * @return
+ */
+ public boolean hasNext() {
+ boolean res = super.hasNext();
+ if (!seeked) {
+ return res;
+ }
+ if (res && matches(this.next)) {
+ return true;
+ }
+ return false;
+ }
+
+ /** make sure we haven't been used as an iterator yet; this is to miror the MergingSamIterator2 action. */
+ public void ensureUntouched() {
+ if (open) {
+ throw new UnsupportedOperationException("We've already been used as an iterator; you can't query after that");
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMUtils.java
new file mode 100644
index 0000000..7fb43ef
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMUtils.java
@@ -0,0 +1,484 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.locusiterator.LocusIteratorByState;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileupImpl;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * @author aaron
+ * @version 1.0
+ */
+public class ArtificialSAMUtils {
+ public static final int DEFAULT_READ_LENGTH = 50;
+
+ /**
+ * create an artificial sam file
+ *
+ * @param filename the filename to write to
+ * @param numberOfChromosomes the number of chromosomes
+ * @param startingChromosome where to start counting
+ * @param chromosomeSize how large each chromosome is
+ * @param readsPerChomosome how many reads to make in each chromosome. They'll be aligned from position 1 to x (which is the number of reads)
+ */
+ public static void createArtificialBamFile(String filename, int numberOfChromosomes, int startingChromosome, int chromosomeSize, int readsPerChomosome) {
+ SAMFileHeader header = createArtificialSamHeader(numberOfChromosomes, startingChromosome, chromosomeSize);
+ File outFile = new File(filename);
+
+ SAMFileWriter out = new SAMFileWriterFactory().makeBAMWriter(header, true, outFile);
+
+ for (int x = startingChromosome; x < startingChromosome + numberOfChromosomes; x++) {
+ for (int readNumber = 1; readNumber < readsPerChomosome; readNumber++) {
+ out.addAlignment(createArtificialRead(header, "Read_" + readNumber, x - startingChromosome, readNumber, DEFAULT_READ_LENGTH));
+ }
+ }
+
+ out.close();
+ }
+
+ /**
+ * create an artificial sam file
+ *
+ * @param filename the filename to write to
+ * @param numberOfChromosomes the number of chromosomes
+ * @param startingChromosome where to start counting
+ * @param chromosomeSize how large each chromosome is
+ * @param readsPerChomosome how many reads to make in each chromosome. They'll be aligned from position 1 to x (which is the number of reads)
+ */
+ public static void createArtificialSamFile(String filename, int numberOfChromosomes, int startingChromosome, int chromosomeSize, int readsPerChomosome) {
+ SAMFileHeader header = createArtificialSamHeader(numberOfChromosomes, startingChromosome, chromosomeSize);
+ File outFile = new File(filename);
+
+ SAMFileWriter out = new SAMFileWriterFactory().makeSAMWriter(header, false, outFile);
+
+ for (int x = startingChromosome; x < startingChromosome + numberOfChromosomes; x++) {
+ for (int readNumber = 1; readNumber <= readsPerChomosome; readNumber++) {
+ out.addAlignment(createArtificialRead(header, "Read_" + readNumber, x - startingChromosome, readNumber, 100));
+ }
+ }
+
+ out.close();
+ }
+
+ /**
+ * Creates an artificial sam header, matching the parameters, chromosomes which will be labeled chr1, chr2, etc
+ *
+ * @param numberOfChromosomes the number of chromosomes to create
+ * @param startingChromosome the starting number for the chromosome (most likely set to 1)
+ * @param chromosomeSize the length of each chromosome
+ * @return
+ */
+ public static SAMFileHeader createArtificialSamHeader(int numberOfChromosomes, int startingChromosome, int chromosomeSize) {
+ SAMFileHeader header = new SAMFileHeader();
+ header.setSortOrder(htsjdk.samtools.SAMFileHeader.SortOrder.coordinate);
+ SAMSequenceDictionary dict = new SAMSequenceDictionary();
+ // make up some sequence records
+ for (int x = startingChromosome; x < startingChromosome + numberOfChromosomes; x++) {
+ SAMSequenceRecord rec = new SAMSequenceRecord("chr" + (x), chromosomeSize /* size */);
+ rec.setSequenceLength(chromosomeSize);
+ dict.addSequence(rec);
+ }
+ header.setSequenceDictionary(dict);
+ return header;
+ }
+
+ /**
+ * Creates an artificial sam header based on the sequence dictionary dict
+ *
+ * @return a new sam header
+ */
+ public static SAMFileHeader createArtificialSamHeader(final SAMSequenceDictionary dict) {
+ SAMFileHeader header = new SAMFileHeader();
+ header.setSortOrder(htsjdk.samtools.SAMFileHeader.SortOrder.coordinate);
+ header.setSequenceDictionary(dict);
+ return header;
+ }
+
+ /**
+ * Creates an artificial sam header with standard test parameters
+ *
+ * @return the sam header
+ */
+ public static SAMFileHeader createArtificialSamHeader() {
+ return createArtificialSamHeader(1, 1, 1000000);
+ }
+
+ /**
+ * setup a default read group for a SAMFileHeader
+ *
+ * @param header the header to set
+ * @param readGroupID the read group ID tag
+ * @param sampleName the sample name
+ * @return the adjusted SAMFileHeader
+ */
+ public static SAMFileHeader createDefaultReadGroup(SAMFileHeader header, String readGroupID, String sampleName) {
+ SAMReadGroupRecord rec = new SAMReadGroupRecord(readGroupID);
+ rec.setSample(sampleName);
+ List<SAMReadGroupRecord> readGroups = new ArrayList<SAMReadGroupRecord>();
+ readGroups.add(rec);
+ header.setReadGroups(readGroups);
+ return header;
+ }
+
+ /**
+ * setup read groups for the specified read groups and sample names
+ *
+ * @param header the header to set
+ * @param readGroupIDs the read group ID tags
+ * @param sampleNames the sample names
+ * @return the adjusted SAMFileHeader
+ */
+ public static SAMFileHeader createEnumeratedReadGroups(SAMFileHeader header, List<String> readGroupIDs, List<String> sampleNames) {
+ if (readGroupIDs.size() != sampleNames.size()) {
+ throw new ReviewedGATKException("read group count and sample name count must be the same");
+ }
+
+ List<SAMReadGroupRecord> readGroups = new ArrayList<SAMReadGroupRecord>();
+
+ int x = 0;
+ for (; x < readGroupIDs.size(); x++) {
+ SAMReadGroupRecord rec = new SAMReadGroupRecord(readGroupIDs.get(x));
+ rec.setSample(sampleNames.get(x));
+ readGroups.add(rec);
+ }
+ header.setReadGroups(readGroups);
+ return header;
+ }
+
+
+ /**
+ * Create an artificial read based on the parameters. The cigar string will be *M, where * is the length of the read
+ *
+ * @param header the SAM header to associate the read with
+ * @param name the name of the read
+ * @param refIndex the reference index, i.e. what chromosome to associate it with
+ * @param alignmentStart where to start the alignment
+ * @param length the length of the read
+ * @return the artificial read
+ */
+ public static GATKSAMRecord createArtificialRead(SAMFileHeader header, String name, int refIndex, int alignmentStart, int length) {
+ if ((refIndex == SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX && alignmentStart != SAMRecord.NO_ALIGNMENT_START) ||
+ (refIndex != SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX && alignmentStart == SAMRecord.NO_ALIGNMENT_START))
+ throw new ReviewedGATKException("Invalid alignment start for artificial read, start = " + alignmentStart);
+ GATKSAMRecord record = new GATKSAMRecord(header);
+ record.setReadName(name);
+ record.setReferenceIndex(refIndex);
+ record.setAlignmentStart(alignmentStart);
+ List<CigarElement> elements = new ArrayList<CigarElement>();
+ elements.add(new CigarElement(length, CigarOperator.characterToEnum('M')));
+ record.setCigar(new Cigar(elements));
+ record.setProperPairFlag(false);
+
+ // our reads and quals are all 'A's by default
+ byte[] c = new byte[length];
+ byte[] q = new byte[length];
+ for (int x = 0; x < length; x++)
+ c[x] = q[x] = 'A';
+ record.setReadBases(c);
+ record.setBaseQualities(q);
+
+ if (refIndex == SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX) {
+ record.setReadUnmappedFlag(true);
+ }
+
+ return record;
+ }
+
+ /**
+ * Create an artificial read based on the parameters. The cigar string will be *M, where * is the length of the read
+ *
+ * @param header the SAM header to associate the read with
+ * @param name the name of the read
+ * @param refIndex the reference index, i.e. what chromosome to associate it with
+ * @param alignmentStart where to start the alignment
+ * @param bases the sequence of the read
+ * @param qual the qualities of the read
+ * @return the artificial read
+ */
+ public static GATKSAMRecord createArtificialRead(SAMFileHeader header, String name, int refIndex, int alignmentStart, byte[] bases, byte[] qual) {
+ if (bases.length != qual.length) {
+ throw new ReviewedGATKException("Passed in read string is different length then the quality array");
+ }
+ GATKSAMRecord rec = createArtificialRead(header, name, refIndex, alignmentStart, bases.length);
+ rec.setReadBases(bases);
+ rec.setBaseQualities(qual);
+ rec.setReadGroup(new GATKSAMReadGroupRecord("x"));
+ if (refIndex == -1) {
+ rec.setReadUnmappedFlag(true);
+ }
+
+ return rec;
+ }
+
+ /**
+ * Create an artificial read based on the parameters
+ *
+ * @param header the SAM header to associate the read with
+ * @param name the name of the read
+ * @param refIndex the reference index, i.e. what chromosome to associate it with
+ * @param alignmentStart where to start the alignment
+ * @param bases the sequence of the read
+ * @param qual the qualities of the read
+ * @param cigar the cigar string of the read
+ * @return the artificial read
+ */
+ public static GATKSAMRecord createArtificialRead(SAMFileHeader header, String name, int refIndex, int alignmentStart, byte[] bases, byte[] qual, String cigar) {
+ GATKSAMRecord rec = createArtificialRead(header, name, refIndex, alignmentStart, bases, qual);
+ rec.setCigarString(cigar);
+ return rec;
+ }
+
+ /**
+ * Create an artificial read with the following default parameters :
+ * header:
+ * numberOfChromosomes = 1
+ * startingChromosome = 1
+ * chromosomeSize = 1000000
+ * read:
+ * name = "default_read"
+ * refIndex = 0
+ * alignmentStart = 1
+ *
+ * @param bases the sequence of the read
+ * @param qual the qualities of the read
+ * @param cigar the cigar string of the read
+ * @return the artificial read
+ */
+ public static GATKSAMRecord createArtificialRead(byte[] bases, byte[] qual, String cigar) {
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader();
+ return ArtificialSAMUtils.createArtificialRead(header, "default_read", 0, 10000, bases, qual, cigar);
+ }
+
+ public static GATKSAMRecord createArtificialRead(Cigar cigar) {
+ int length = cigar.getReadLength();
+ byte [] base = {'A'};
+ byte [] qual = {30};
+ byte [] bases = Utils.arrayFromArrayWithLength(base, length);
+ byte [] quals = Utils.arrayFromArrayWithLength(qual, length);
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader();
+ return ArtificialSAMUtils.createArtificialRead(header, "default_read", 0, 10000, bases, quals, cigar.toString());
+ }
+
+
+ public final static List<GATKSAMRecord> createPair(SAMFileHeader header, String name, int readLen, int leftStart, int rightStart, boolean leftIsFirst, boolean leftIsNegative) {
+ GATKSAMRecord left = ArtificialSAMUtils.createArtificialRead(header, name, 0, leftStart, readLen);
+ GATKSAMRecord right = ArtificialSAMUtils.createArtificialRead(header, name, 0, rightStart, readLen);
+
+ left.setReadPairedFlag(true);
+ right.setReadPairedFlag(true);
+
+ left.setProperPairFlag(true);
+ right.setProperPairFlag(true);
+
+ left.setFirstOfPairFlag(leftIsFirst);
+ right.setFirstOfPairFlag(!leftIsFirst);
+
+ left.setReadNegativeStrandFlag(leftIsNegative);
+ left.setMateNegativeStrandFlag(!leftIsNegative);
+ right.setReadNegativeStrandFlag(!leftIsNegative);
+ right.setMateNegativeStrandFlag(leftIsNegative);
+
+ left.setMateAlignmentStart(right.getAlignmentStart());
+ right.setMateAlignmentStart(left.getAlignmentStart());
+
+ left.setMateReferenceIndex(0);
+ right.setMateReferenceIndex(0);
+
+ int isize = rightStart + readLen - leftStart;
+ left.setInferredInsertSize(isize);
+ right.setInferredInsertSize(-isize);
+
+ return Arrays.asList(left, right);
+ }
+
+ /**
+ * Create a collection of identical artificial reads based on the parameters. The cigar string for each
+ * read will be *M, where * is the length of the read.
+ *
+ * Useful for testing things like positional downsampling where you care only about the position and
+ * number of reads, and not the other attributes.
+ *
+ * @param stackSize number of identical reads to create
+ * @param header the SAM header to associate each read with
+ * @param name name associated with each read
+ * @param refIndex the reference index, i.e. what chromosome to associate them with
+ * @param alignmentStart where to start each alignment
+ * @param length the length of each read
+ *
+ * @return a collection of stackSize reads all sharing the above properties
+ */
+ public static Collection<GATKSAMRecord> createStackOfIdenticalArtificialReads( int stackSize, SAMFileHeader header, String name, int refIndex, int alignmentStart, int length ) {
+ Collection<GATKSAMRecord> stack = new ArrayList<GATKSAMRecord>(stackSize);
+ for ( int i = 1; i <= stackSize; i++ ) {
+ stack.add(createArtificialRead(header, name, refIndex, alignmentStart, length));
+ }
+ return stack;
+ }
+
+ /**
+ * create an iterator containing the specified read piles
+ *
+ * @param startingChr the chromosome (reference ID) to start from
+ * @param endingChr the id to end with
+ * @param readCount the number of reads per chromosome
+ * @return GATKSAMIterator representing the specified amount of fake data
+ */
+ public static GATKSAMIterator mappedReadIterator(int startingChr, int endingChr, int readCount) {
+ SAMFileHeader header = createArtificialSamHeader((endingChr - startingChr) + 1, startingChr, readCount + DEFAULT_READ_LENGTH);
+
+ return new ArtificialSAMQueryIterator(startingChr, endingChr, readCount, 0, header);
+ }
+
+ /**
+ * create an iterator containing the specified read piles
+ *
+ * @param startingChr the chromosome (reference ID) to start from
+ * @param endingChr the id to end with
+ * @param readCount the number of reads per chromosome
+ * @param unmappedReadCount the count of unmapped reads to place at the end of the iterator, like in a sorted bam file
+ * @return GATKSAMIterator representing the specified amount of fake data
+ */
+ public static GATKSAMIterator mappedAndUnmappedReadIterator(int startingChr, int endingChr, int readCount, int unmappedReadCount) {
+ SAMFileHeader header = createArtificialSamHeader((endingChr - startingChr) + 1, startingChr, readCount + DEFAULT_READ_LENGTH);
+
+ return new ArtificialSAMQueryIterator(startingChr, endingChr, readCount, unmappedReadCount, header);
+ }
+
+ /**
+ * create an ArtificialSAMQueryIterator containing the specified read piles
+ *
+ * @param startingChr the chromosome (reference ID) to start from
+ * @param endingChr the id to end with
+ * @param readCount the number of reads per chromosome
+ * @return GATKSAMIterator representing the specified amount of fake data
+ */
+ public static ArtificialSAMQueryIterator queryReadIterator(int startingChr, int endingChr, int readCount) {
+ SAMFileHeader header = createArtificialSamHeader((endingChr - startingChr) + 1, startingChr, readCount + DEFAULT_READ_LENGTH);
+
+ return new ArtificialSAMQueryIterator(startingChr, endingChr, readCount, 0, header);
+ }
+
+ /**
+ * create an ArtificialSAMQueryIterator containing the specified read piles
+ *
+ * @param startingChr the chromosome (reference ID) to start from
+ * @param endingChr the id to end with
+ * @param readCount the number of reads per chromosome
+ * @param unmappedReadCount the count of unmapped reads to place at the end of the iterator, like in a sorted bam file
+ * @return GATKSAMIterator representing the specified amount of fake data
+ */
+ public static GATKSAMIterator queryReadIterator(int startingChr, int endingChr, int readCount, int unmappedReadCount) {
+ SAMFileHeader header = createArtificialSamHeader((endingChr - startingChr) + 1, startingChr, readCount + DEFAULT_READ_LENGTH);
+
+ return new ArtificialSAMQueryIterator(startingChr, endingChr, readCount, unmappedReadCount, header);
+ }
+
+ /**
+ * Create an iterator containing the specified reads
+ *
+ * @param reads the reads
+ * @return iterator for the reads
+ */
+ public static GATKSAMIterator createReadIterator(SAMRecord... reads) {
+ return createReadIterator(Arrays.asList(reads));
+ }
+
+ /**
+ * Create an iterator containing the specified reads
+ *
+ * @param reads the reads
+ * @return iterator for the reads
+ */
+ public static GATKSAMIterator createReadIterator(List<SAMRecord> reads) {
+ final Iterator<SAMRecord> iter = reads.iterator();
+ return new GATKSAMIterator() {
+ @Override public void close() {}
+ @Override public Iterator<SAMRecord> iterator() { return iter; }
+ @Override public boolean hasNext() { return iter.hasNext(); }
+ @Override public SAMRecord next() { return iter.next(); }
+ @Override public void remove() { iter.remove(); }
+ };
+ }
+
+ private final static int ranIntInclusive(Random ran, int start, int stop) {
+ final int range = stop - start;
+ return ran.nextInt(range) + start;
+ }
+
+ /**
+ * Creates a read backed pileup containing up to pileupSize reads at refID 0 from header at loc with
+ * reads created that have readLen bases. Pairs are sampled from a gaussian distribution with mean insert
+ * size of insertSize and variation of insertSize / 10. The first read will be in the pileup, and the second
+ * may be, depending on where this sampled insertSize puts it.
+ *
+ * @param header
+ * @param loc
+ * @param readLen
+ * @param insertSize
+ * @param pileupSize
+ * @return
+ */
+ public static ReadBackedPileup createReadBackedPileup(final SAMFileHeader header, final GenomeLoc loc, final int readLen, final int insertSize, final int pileupSize) {
+ final Random ran = new Random();
+ final boolean leftIsFirst = true;
+ final boolean leftIsNegative = false;
+ final int insertSizeVariation = insertSize / 10;
+ final int pos = loc.getStart();
+
+ final List<PileupElement> pileupElements = new ArrayList<PileupElement>();
+ for (int i = 0; i < pileupSize / 2; i++) {
+ final String readName = "read" + i;
+ final int leftStart = ranIntInclusive(ran, 1, pos);
+ final int fragmentSize = (int) (ran.nextGaussian() * insertSizeVariation + insertSize);
+ final int rightStart = leftStart + fragmentSize - readLen;
+
+ if (rightStart <= 0) continue;
+
+ List<GATKSAMRecord> pair = createPair(header, readName, readLen, leftStart, rightStart, leftIsFirst, leftIsNegative);
+ final GATKSAMRecord left = pair.get(0);
+ final GATKSAMRecord right = pair.get(1);
+
+ pileupElements.add(LocusIteratorByState.createPileupForReadAndOffset(left, pos - leftStart));
+
+ if (pos >= right.getAlignmentStart() && pos <= right.getAlignmentEnd()) {
+ pileupElements.add(LocusIteratorByState.createPileupForReadAndOffset(right, pos - rightStart));
+ }
+ }
+
+ Collections.sort(pileupElements);
+ return new ReadBackedPileupImpl(loc, pileupElements);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSingleSampleReadStream.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSingleSampleReadStream.java
new file mode 100644
index 0000000..27e25d3
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSingleSampleReadStream.java
@@ -0,0 +1,213 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIteratorAdapter;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * An artificial stream of reads from a single read group/sample with configurable characteristics
+ * such as:
+ *
+ * -the number of contigs that the reads should be distributed across
+ * -number of "stacks" of reads sharing the same alignment start position per contig
+ * -the min/max number of reads in each stack (exact values chosen randomly from this range)
+ * -the min/max distance between stack start positions (exact values chosen randomly from this range)
+ * -the min/max length of each read (exact values chosen randomly from this range)
+ * -the number of unmapped reads
+ *
+ * The cigar string for all reads will be *M, where * is the length of the read.
+ *
+ * @author David Roazen
+ */
+public class ArtificialSingleSampleReadStream implements Iterable<SAMRecord> {
+ private SAMFileHeader header;
+ private String readGroupID;
+ private int numContigs;
+ private int numStacksPerContig;
+ private int minReadsPerStack;
+ private int maxReadsPerStack;
+ private int minDistanceBetweenStacks;
+ private int maxDistanceBetweenStacks;
+ private int minReadLength;
+ private int maxReadLength;
+ private int numUnmappedReads;
+
+ private static final String READ_GROUP_TAG = "RG";
+
+ public ArtificialSingleSampleReadStream( SAMFileHeader header,
+ String readGroupID,
+ int numContigs,
+ int numStacksPerContig,
+ int minReadsPerStack,
+ int maxReadsPerStack,
+ int minDistanceBetweenStacks,
+ int maxDistanceBetweenStacks,
+ int minReadLength,
+ int maxReadLength,
+ int numUnmappedReads ) {
+ this.header = header;
+ this.readGroupID = readGroupID;
+ this.numContigs = numContigs;
+ this.numStacksPerContig = numStacksPerContig;
+ this.minReadsPerStack = minReadsPerStack;
+ this.maxReadsPerStack = maxReadsPerStack;
+ this.minDistanceBetweenStacks = minDistanceBetweenStacks;
+ this.maxDistanceBetweenStacks = maxDistanceBetweenStacks;
+ this.minReadLength = minReadLength;
+ this.maxReadLength = maxReadLength;
+ this.numUnmappedReads = numUnmappedReads;
+
+ validateStreamParameters();
+ }
+
+ private void validateStreamParameters() {
+ if ( header == null || readGroupID == null ) {
+ throw new ReviewedGATKException("null SAMFileHeader or read group ID") ;
+ }
+
+ if ( header.getReadGroup(readGroupID) == null ) {
+ throw new ReviewedGATKException(String.format("Read group %s not found in SAMFileHeader", readGroupID));
+ }
+
+ if ( numContigs < 0 || numStacksPerContig < 0 || minReadsPerStack < 0 || maxReadsPerStack < 0 ||
+ minDistanceBetweenStacks < 0 || maxDistanceBetweenStacks < 0 || minReadLength < 0 || maxReadLength < 0 ||
+ numUnmappedReads < 0 ) {
+ throw new ReviewedGATKException("Read stream parameters must be >= 0");
+ }
+
+ if ( (numContigs == 0 && numStacksPerContig != 0) || (numContigs != 0 && numStacksPerContig == 0) ) {
+ throw new ReviewedGATKException("numContigs and numStacksPerContig must either both be > 0, or both be 0");
+ }
+
+ if ( minReadsPerStack > maxReadsPerStack ) {
+ throw new ReviewedGATKException("minReadsPerStack > maxReadsPerStack");
+ }
+
+ if ( minDistanceBetweenStacks > maxDistanceBetweenStacks ) {
+ throw new ReviewedGATKException("minDistanceBetweenStacks > maxDistanceBetweenStacks");
+ }
+
+ if ( minReadLength > maxReadLength ) {
+ throw new ReviewedGATKException("minReadLength > maxReadLength");
+ }
+ }
+
+ public Iterator<SAMRecord> iterator() {
+ return makeReads().iterator();
+ }
+
+ public GATKSAMIterator getGATKSAMIterator() {
+ return GATKSAMIteratorAdapter.adapt(iterator());
+ }
+
+ public Collection<SAMRecord> makeReads() {
+ Collection<SAMRecord> reads = new ArrayList<SAMRecord>(numContigs * numStacksPerContig * maxReadsPerStack);
+
+ for ( int contig = 0; contig < numContigs; contig++ ) {
+ int alignmentStart = 1;
+
+ for ( int stack = 0; stack < numStacksPerContig; stack++ ) {
+ reads.addAll(makeReadStack(contig, alignmentStart, MathUtils.randomIntegerInRange(minReadsPerStack, maxReadsPerStack)));
+ alignmentStart += MathUtils.randomIntegerInRange(minDistanceBetweenStacks, maxDistanceBetweenStacks);
+ }
+ }
+
+ if ( numUnmappedReads > 0 ) {
+ reads.addAll(makeReadStack(SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX, SAMRecord.NO_ALIGNMENT_START, numUnmappedReads));
+ }
+
+ return reads;
+ }
+
+ private Collection<SAMRecord> makeReadStack( int contig, int alignmentStart, int stackSize ) {
+ Collection<SAMRecord> readStack = new ArrayList<SAMRecord>(stackSize);
+
+ for ( int i = 0; i < stackSize; i++ ) {
+ SAMRecord read = ArtificialSAMUtils.createArtificialRead(header,
+ "foo",
+ contig,
+ alignmentStart,
+ MathUtils.randomIntegerInRange(minReadLength, maxReadLength));
+ read.setAttribute(READ_GROUP_TAG, readGroupID);
+ readStack.add(read);
+ }
+
+ return readStack;
+ }
+
+ public SAMFileHeader getHeader() {
+ return header;
+ }
+
+ public String getReadGroupID() {
+ return readGroupID;
+ }
+
+ public int getNumContigs() {
+ return numContigs;
+ }
+
+ public int getNumStacksPerContig() {
+ return numStacksPerContig;
+ }
+
+ public int getMinReadsPerStack() {
+ return minReadsPerStack;
+ }
+
+ public int getMaxReadsPerStack() {
+ return maxReadsPerStack;
+ }
+
+ public int getMinDistanceBetweenStacks() {
+ return minDistanceBetweenStacks;
+ }
+
+ public int getMaxDistanceBetweenStacks() {
+ return maxDistanceBetweenStacks;
+ }
+
+ public int getMinReadLength() {
+ return minReadLength;
+ }
+
+ public int getMaxReadLength() {
+ return maxReadLength;
+ }
+
+ public int getNumUnmappedReads() {
+ return numUnmappedReads;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSingleSampleReadStreamAnalyzer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSingleSampleReadStreamAnalyzer.java
new file mode 100644
index 0000000..196fa71
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ArtificialSingleSampleReadStreamAnalyzer.java
@@ -0,0 +1,282 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class for analyzing and validating the read stream produced by an ArtificialSingleSampleReadStream.
+ *
+ * Collects various statistics about the stream of reads it's fed, and validates the stream
+ * by checking whether the collected statistics match the nominal properties of the stream.
+ *
+ * Subclasses are expected to override the validate() method in order to check whether an artificial
+ * read stream has been *transformed* in some way (eg., by downsampling or some other process), rather
+ * than merely checking whether the stream matches its original properties.
+ *
+ * Usage is simple:
+ *
+ * ArtificialSingleSampleReadStreamAnalyzer analyzer = new ArtificialSingleSampleReadStreamAnalyzer(originalStream);
+ * analyzer.analyze(originalOrTransformedStream);
+ * analyzer.validate(); // override this method if you want to check whether the stream has been transformed
+ * // in a certain way relative to the original stream
+ *
+ * @author David Roazen
+ */
+public class ArtificialSingleSampleReadStreamAnalyzer {
+ protected ArtificialSingleSampleReadStream originalStream;
+ protected SAMRecord lastRead;
+ protected int totalReads;
+ protected boolean allSamplesMatch;
+ protected int numContigs;
+ protected List<Integer> stacksPerContig;
+ protected Integer minReadsPerStack;
+ protected Integer maxReadsPerStack;
+ protected Integer minDistanceBetweenStacks;
+ protected Integer maxDistanceBetweenStacks;
+ protected Integer minReadLength;
+ protected Integer maxReadLength;
+ protected int numUnmappedReads;
+
+ protected int currentContigNumStacks;
+ protected int currentStackNumReads;
+
+ /**
+ * Construct a new read stream analyzer, providing an ArtificialSingleSampleReadStream that will
+ * serve as the basis for comparison after the analysis is complete.
+ *
+ * @param originalStream the original ArtificialSingleSampleReadStream upon which the stream
+ * that will be fed to the analyzer is based
+ */
+ public ArtificialSingleSampleReadStreamAnalyzer( ArtificialSingleSampleReadStream originalStream ) {
+ this.originalStream = originalStream;
+ reset();
+ }
+
+ /**
+ * Reset all read stream statistics collected by this analyzer to prepare for a fresh run
+ */
+ public void reset() {
+ lastRead = null;
+ totalReads = 0;
+ allSamplesMatch = true;
+ numContigs = 0;
+ stacksPerContig = new ArrayList<Integer>();
+ minReadsPerStack = null;
+ maxReadsPerStack = null;
+ minDistanceBetweenStacks = null;
+ maxDistanceBetweenStacks = null;
+ minReadLength = null;
+ maxReadLength = null;
+ numUnmappedReads = 0;
+ currentContigNumStacks = 0;
+ currentStackNumReads = 0;
+ }
+
+ /**
+ * Collect statistics on the stream of reads passed in
+ *
+ * @param stream the stream of reads to analyze
+ */
+ public void analyze( Iterable<SAMRecord> stream ) {
+ for ( SAMRecord read : stream ) {
+ update(read);
+ }
+ finalizeStats();
+ }
+
+ /**
+ * Validate the stream by checking whether our collected statistics match the properties of the
+ * original stream. Throws a ReviewedGATKException if the stream is invalid.
+ *
+ * Override this method if you want to check whether the stream has been transformed in some
+ * way relative to the original stream.
+ */
+ public void validate() {
+ if ( (originalStream.getNumContigs() == 0 || originalStream.getNumStacksPerContig() == 0) && originalStream.getNumUnmappedReads() == 0 ) {
+ if ( totalReads != 0 ) {
+ throw new ReviewedGATKException("got reads from the stream, but the stream was configured to have 0 reads");
+ }
+ return; // no further validation needed for the 0-reads case
+ }
+ else if ( totalReads == 0 ) {
+ throw new ReviewedGATKException("got no reads from the stream, but the stream was configured to have > 0 reads");
+ }
+
+ if ( ! allSamplesMatch ) {
+ throw new ReviewedGATKException("some reads had the wrong sample");
+ }
+
+ if ( numContigs != originalStream.getNumContigs() ) {
+ throw new ReviewedGATKException("number of contigs not correct");
+ }
+
+ if ( stacksPerContig.size() != originalStream.getNumContigs() ) {
+ throw new ReviewedGATKException(String.format("bug in analyzer code: calculated sizes for %d contigs even though there were only %d contigs",
+ stacksPerContig.size(), originalStream.getNumContigs()));
+ }
+
+ for ( int contigStackCount : stacksPerContig ) {
+ if ( contigStackCount != originalStream.getNumStacksPerContig() ) {
+ throw new ReviewedGATKException("contig had incorrect number of stacks");
+ }
+ }
+
+ if ( originalStream.getNumStacksPerContig() > 0 ) {
+ if ( minReadsPerStack < originalStream.getMinReadsPerStack() ) {
+ throw new ReviewedGATKException("stack had fewer than the minimum number of reads");
+ }
+ if ( maxReadsPerStack > originalStream.getMaxReadsPerStack() ) {
+ throw new ReviewedGATKException("stack had more than the maximum number of reads");
+ }
+ }
+ else if ( minReadsPerStack != null || maxReadsPerStack != null ) {
+ throw new ReviewedGATKException("bug in analyzer code: reads per stack was calculated even though 0 stacks per contig was specified");
+ }
+
+ if ( originalStream.getNumStacksPerContig() > 1 ) {
+ if ( minDistanceBetweenStacks < originalStream.getMinDistanceBetweenStacks() ) {
+ throw new ReviewedGATKException("stacks were separated by less than the minimum distance");
+ }
+ if ( maxDistanceBetweenStacks > originalStream.getMaxDistanceBetweenStacks() ) {
+ throw new ReviewedGATKException("stacks were separated by more than the maximum distance");
+ }
+ }
+ else if ( minDistanceBetweenStacks != null || maxDistanceBetweenStacks != null ) {
+ throw new ReviewedGATKException("bug in analyzer code: distance between stacks was calculated even though numStacksPerContig was <= 1");
+ }
+
+ if ( minReadLength < originalStream.getMinReadLength() ) {
+ throw new ReviewedGATKException("read was shorter than the minimum allowed length");
+ }
+ if ( maxReadLength > originalStream.getMaxReadLength() ) {
+ throw new ReviewedGATKException("read was longer than the maximum allowed length");
+ }
+
+ if ( numUnmappedReads != originalStream.getNumUnmappedReads() ) {
+ throw new ReviewedGATKException(String.format("wrong number of unmapped reads: requested %d but saw %d",
+ originalStream.getNumUnmappedReads(), numUnmappedReads));
+ }
+
+ if ( (originalStream.getNumContigs() == 0 || originalStream.getNumStacksPerContig() == 0) &&
+ numUnmappedReads != totalReads ) {
+ throw new ReviewedGATKException("stream should have consisted only of unmapped reads, but saw some mapped reads");
+ }
+ }
+
+ public void update( SAMRecord read ) {
+ if ( read.getReadUnmappedFlag() ) {
+ numUnmappedReads++;
+
+ if ( numUnmappedReads == 1 && lastRead != null ) {
+ processContigChange();
+ numContigs--;
+ }
+ }
+ else if ( lastRead == null ) {
+ numContigs = 1;
+ currentContigNumStacks = 1;
+ currentStackNumReads = 1;
+ }
+ else if ( ! read.getReferenceIndex().equals(lastRead.getReferenceIndex()) ) {
+ processContigChange();
+ }
+ else if ( read.getAlignmentStart() != lastRead.getAlignmentStart() ) {
+ processStackChangeWithinContig(read);
+ }
+ else {
+ currentStackNumReads++;
+ }
+
+ updateReadLength(read.getReadLength());
+ allSamplesMatch = allSamplesMatch && readHasCorrectSample(read);
+ totalReads++;
+
+ lastRead = read;
+ }
+
+
+ private void processContigChange() {
+ numContigs++;
+
+ stacksPerContig.add(currentContigNumStacks);
+ currentContigNumStacks = 1;
+
+ updateReadsPerStack(currentStackNumReads);
+ currentStackNumReads = 1;
+ }
+
+ private void processStackChangeWithinContig( SAMRecord read ) {
+ currentContigNumStacks++;
+
+ updateReadsPerStack(currentStackNumReads);
+ currentStackNumReads = 1;
+
+ updateDistanceBetweenStacks(read.getAlignmentStart() - lastRead.getAlignmentStart());
+ }
+
+ private void updateReadsPerStack( int stackReadCount ) {
+ if ( minReadsPerStack == null || stackReadCount < minReadsPerStack ) {
+ minReadsPerStack = stackReadCount;
+ }
+ if ( maxReadsPerStack == null || stackReadCount > maxReadsPerStack ) {
+ maxReadsPerStack = stackReadCount;
+ }
+ }
+
+ private void updateDistanceBetweenStacks( int stackDistance ) {
+ if ( minDistanceBetweenStacks == null || stackDistance < minDistanceBetweenStacks ) {
+ minDistanceBetweenStacks = stackDistance;
+ }
+ if ( maxDistanceBetweenStacks == null || stackDistance > maxDistanceBetweenStacks ) {
+ maxDistanceBetweenStacks = stackDistance;
+ }
+ }
+
+ private void updateReadLength( int readLength ) {
+ if ( minReadLength == null || readLength < minReadLength ) {
+ minReadLength = readLength;
+ }
+ if ( maxReadLength == null || readLength > maxReadLength ) {
+ maxReadLength = readLength;
+ }
+ }
+
+ private boolean readHasCorrectSample( SAMRecord read ) {
+ return originalStream.getReadGroupID().equals(read.getAttribute("RG"));
+ }
+
+ public void finalizeStats() {
+ if ( lastRead != null && ! lastRead.getReadUnmappedFlag() ) {
+ stacksPerContig.add(currentContigNumStacks);
+ updateReadsPerStack(currentStackNumReads);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/BySampleSAMFileWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/BySampleSAMFileWriter.java
new file mode 100644
index 0000000..e212bd9
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/BySampleSAMFileWriter.java
@@ -0,0 +1,70 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMProgramRecord;
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: carneiro
+ * Date: Nov 13
+ */
+public class BySampleSAMFileWriter extends NWaySAMFileWriter{
+
+ private final Map<String, SAMReaderID> sampleToWriterMap;
+
+ public BySampleSAMFileWriter(GenomeAnalysisEngine toolkit, String ext, SAMFileHeader.SortOrder order, boolean presorted, boolean indexOnTheFly, boolean generateMD5, SAMProgramRecord pRecord, boolean keep_records) {
+ super(toolkit, ext, order, presorted, indexOnTheFly, generateMD5, pRecord, keep_records);
+
+ sampleToWriterMap = new HashMap<String, SAMReaderID>(toolkit.getSAMFileHeader().getReadGroups().size() * 2);
+
+ for (SAMReaderID readerID : toolkit.getReadsDataSource().getReaderIDs()) {
+ for (SAMReadGroupRecord rg : toolkit.getReadsDataSource().getHeader(readerID).getReadGroups()) {
+ String sample = rg.getSample();
+ if (sampleToWriterMap.containsKey(sample) && sampleToWriterMap.get(sample) != readerID) {
+ throw new ReviewedGATKException("The same sample appears in multiple files, this input cannot be multiplexed using the BySampleSAMFileWriter, try NWaySAMFileWriter instead.");
+ }
+ else {
+ sampleToWriterMap.put(sample, readerID);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void addAlignment(SAMRecord samRecord) {
+ super.addAlignment(samRecord, sampleToWriterMap.get(samRecord.getReadGroup().getSample()));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/CigarUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/CigarUtils.java
new file mode 100644
index 0000000..cd492fe
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/CigarUtils.java
@@ -0,0 +1,273 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import com.google.java.contract.Ensures;
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.TextCigarCodec;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.smithwaterman.Parameters;
+import org.broadinstitute.gatk.utils.smithwaterman.SWPairwiseAlignment;
+import org.broadinstitute.gatk.utils.smithwaterman.SmithWaterman;
+
+import java.util.Arrays;
+import java.util.Stack;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: ami
+ * Date: 11/26/13
+ * Time: 11:33 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class CigarUtils {
+
+ /**
+ * Combines equal adjacent elements of a Cigar object
+ *
+ * @param rawCigar the cigar object
+ * @return a combined cigar object
+ */
+ public static Cigar combineAdjacentCigarElements(Cigar rawCigar) {
+ Cigar combinedCigar = new Cigar();
+ CigarElement lastElement = null;
+ int lastElementLength = 0;
+ for (CigarElement cigarElement : rawCigar.getCigarElements()) {
+ if (lastElement != null &&
+ ((lastElement.getOperator() == cigarElement.getOperator()) ||
+ (lastElement.getOperator() == CigarOperator.I && cigarElement.getOperator() == CigarOperator.D) ||
+ (lastElement.getOperator() == CigarOperator.D && cigarElement.getOperator() == CigarOperator.I)))
+ lastElementLength += cigarElement.getLength();
+ else
+ {
+ if (lastElement != null)
+ combinedCigar.add(new CigarElement(lastElementLength, lastElement.getOperator()));
+
+ lastElement = cigarElement;
+ lastElementLength = cigarElement.getLength();
+ }
+ }
+ if (lastElement != null)
+ combinedCigar.add(new CigarElement(lastElementLength, lastElement.getOperator()));
+
+ return combinedCigar;
+ }
+
+ public static Cigar invertCigar (Cigar cigar) {
+ Stack<CigarElement> cigarStack = new Stack<CigarElement>();
+ for (CigarElement cigarElement : cigar.getCigarElements())
+ cigarStack.push(cigarElement);
+
+ Cigar invertedCigar = new Cigar();
+ while (!cigarStack.isEmpty())
+ invertedCigar.add(cigarStack.pop());
+
+ return invertedCigar;
+ }
+
+ /**
+ * Checks whether or not the read has any cigar element that is not H or S
+ *
+ * @param read the read
+ * @return true if it has any M, I or D, false otherwise
+ */
+ public static boolean readHasNonClippedBases(GATKSAMRecord read) {
+ for (CigarElement cigarElement : read.getCigar().getCigarElements())
+ if (cigarElement.getOperator() != CigarOperator.SOFT_CLIP && cigarElement.getOperator() != CigarOperator.HARD_CLIP)
+ return true;
+ return false;
+ }
+
+ public static Cigar cigarFromString(String cigarString) {
+ return TextCigarCodec.getSingleton().decode(cigarString);
+ }
+
+ /**
+ * A valid cigar object obeys the following rules:
+ * - No Hard/Soft clips in the middle of the read
+ * - No deletions in the beginning / end of the read
+ * - No repeated adjacent element (e.g. 1M2M -> this should be 3M)
+ * - No consecutive I/D elements
+ **/
+ public static boolean isCigarValid(Cigar cigar) {
+ if (cigar.isValid(null, -1) == null) { // This should take care of most invalid Cigar Strings (picard's "exhaustive" implementation)
+
+ Stack<CigarElement> cigarElementStack = new Stack<CigarElement>(); // Stack to invert cigar string to find ending operator
+ CigarOperator startingOp = null;
+ CigarOperator endingOp = null;
+
+ // check if it doesn't start with deletions
+ boolean readHasStarted = false; // search the list of elements for the starting operator
+ for (CigarElement cigarElement : cigar.getCigarElements()) {
+ if (!readHasStarted) {
+ if (cigarElement.getOperator() != CigarOperator.SOFT_CLIP && cigarElement.getOperator() != CigarOperator.HARD_CLIP) {
+ readHasStarted = true;
+ startingOp = cigarElement.getOperator();
+ }
+ }
+ cigarElementStack.push(cigarElement);
+ }
+
+ while (!cigarElementStack.empty()) {
+ CigarElement cigarElement = cigarElementStack.pop();
+ if (cigarElement.getOperator() != CigarOperator.SOFT_CLIP && cigarElement.getOperator() != CigarOperator.HARD_CLIP) {
+ endingOp = cigarElement.getOperator();
+ break;
+ }
+ }
+
+ if (startingOp != CigarOperator.DELETION && endingOp != CigarOperator.DELETION && startingOp != CigarOperator.SKIPPED_REGION && endingOp != CigarOperator.SKIPPED_REGION)
+ return true; // we don't accept reads starting or ending in deletions (add any other constraint here)
+ }
+
+ return false;
+ }
+
+ public static final int countRefBasesBasedOnCigar(final GATKSAMRecord read, final int cigarStartIndex, final int cigarEndIndex){
+ int result = 0;
+ for(int i = cigarStartIndex; i<cigarEndIndex;i++){
+ final CigarElement cigarElement = read.getCigar().getCigarElement(i);
+ switch (cigarElement.getOperator()) {
+ case M:
+ case S:
+ case D:
+ case N:
+ case H:
+ result += cigarElement.getLength();
+ break;
+ case I:
+ break;
+ default:
+ throw new ReviewedGATKException("Unsupported cigar operator: " + cigarElement.getOperator());
+ }
+ }
+ return result;
+ }
+
+ // used in the bubble state machine to apply Smith-Waterman to the bubble sequence
+ // these values were chosen via optimization against the NA12878 knowledge base
+ public static final Parameters NEW_SW_PARAMETERS = new Parameters(200, -150, -260, -11);
+
+ private final static String SW_PAD = "NNNNNNNNNN";
+
+ /**
+ * Calculate the cigar elements for this path against the reference sequence
+ *
+ * @param refSeq the reference sequence that all of the bases in this path should align to
+ * @return a Cigar mapping this path to refSeq, or null if no reasonable alignment could be found
+ */
+ public static Cigar calculateCigar(final byte[] refSeq, final byte[] altSeq) {
+ if ( altSeq.length == 0 ) {
+ // horrible edge case from the unit tests, where this path has no bases
+ return new Cigar(Arrays.asList(new CigarElement(refSeq.length, CigarOperator.D)));
+ }
+
+ final Cigar nonStandard;
+
+ final String paddedRef = SW_PAD + new String(refSeq) + SW_PAD;
+ final String paddedPath = SW_PAD + new String(altSeq) + SW_PAD;
+ final SmithWaterman alignment = new SWPairwiseAlignment( paddedRef.getBytes(), paddedPath.getBytes(), NEW_SW_PARAMETERS);
+
+ if ( isSWFailure(alignment) ) {
+ return null;
+ }
+
+
+ // cut off the padding bases
+ final int baseStart = SW_PAD.length();
+ final int baseEnd = paddedPath.length() - SW_PAD.length() - 1; // -1 because it's inclusive
+ nonStandard = AlignmentUtils.trimCigarByBases(alignment.getCigar(), baseStart, baseEnd);
+
+ if ( nonStandard.getReferenceLength() != refSeq.length ) {
+ nonStandard.add(new CigarElement(refSeq.length - nonStandard.getReferenceLength(), CigarOperator.D));
+ }
+
+ // finally, return the cigar with all indels left aligned
+ return leftAlignCigarSequentially(nonStandard, refSeq, altSeq, 0, 0);
+ }
+
+ /**
+ * Make sure that the SW didn't fail in some terrible way, and throw exception if it did
+ */
+ private static boolean isSWFailure(final SmithWaterman alignment) {
+ // check that the alignment starts at the first base, which it should given the padding
+ if ( alignment.getAlignmentStart2wrt1() > 0 ) {
+ return true;
+// throw new IllegalStateException("SW failure ref " + paddedRef + " vs. " + paddedPath + " should always start at 0, but got " + alignment.getAlignmentStart2wrt1() + " with cigar " + alignment.getCigar());
+ }
+
+ // check that we aren't getting any S operators (which would be very bad downstream)
+ for ( final CigarElement ce : alignment.getCigar().getCigarElements() ) {
+ if ( ce.getOperator() == CigarOperator.S )
+ return true;
+ // soft clips at the end of the alignment are really insertions
+// throw new IllegalStateException("SW failure ref " + paddedRef + " vs. " + paddedPath + " should never contain S operators but got cigar " + alignment.getCigar());
+ }
+
+ return false;
+ }
+
+ /**
+ * Left align the given cigar sequentially. This is needed because AlignmentUtils doesn't accept cigars with more than one indel in them.
+ * This is a target of future work to incorporate and generalize into AlignmentUtils for use by others.
+ * @param cigar the cigar to left align
+ * @param refSeq the reference byte array
+ * @param readSeq the read byte array
+ * @param refIndex 0-based alignment start position on ref
+ * @param readIndex 0-based alignment start position on read
+ * @return the left-aligned cigar
+ */
+ @Ensures({"cigar != null", "refSeq != null", "readSeq != null", "refIndex >= 0", "readIndex >= 0"})
+ public static Cigar leftAlignCigarSequentially(final Cigar cigar, final byte[] refSeq, final byte[] readSeq, int refIndex, int readIndex) {
+ final Cigar cigarToReturn = new Cigar();
+ Cigar cigarToAlign = new Cigar();
+ for (int i = 0; i < cigar.numCigarElements(); i++) {
+ final CigarElement ce = cigar.getCigarElement(i);
+ if (ce.getOperator() == CigarOperator.D || ce.getOperator() == CigarOperator.I) {
+ cigarToAlign.add(ce);
+ final Cigar leftAligned = AlignmentUtils.leftAlignSingleIndel(cigarToAlign, refSeq, readSeq, refIndex, readIndex, false);
+ for ( final CigarElement toAdd : leftAligned.getCigarElements() ) { cigarToReturn.add(toAdd); }
+ refIndex += cigarToAlign.getReferenceLength();
+ readIndex += cigarToAlign.getReadLength();
+ cigarToAlign = new Cigar();
+ } else {
+ cigarToAlign.add(ce);
+ }
+ }
+ if( !cigarToAlign.isEmpty() ) {
+ for( final CigarElement toAdd : cigarToAlign.getCigarElements() ) {
+ cigarToReturn.add(toAdd);
+ }
+ }
+
+ final Cigar result = AlignmentUtils.consolidateCigar(cigarToReturn);
+ if( result.getReferenceLength() != cigar.getReferenceLength() )
+ throw new IllegalStateException("leftAlignCigarSequentially failed to produce a valid CIGAR. Reference lengths differ. Initial cigar " + cigar + " left aligned into " + result);
+ return result;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/GATKSAMReadGroupRecord.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/GATKSAMReadGroupRecord.java
new file mode 100644
index 0000000..6af9059
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/GATKSAMReadGroupRecord.java
@@ -0,0 +1,116 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.utils.NGSPlatform;
+
+/**
+ * @author ebanks
+ * GATKSAMReadGroupRecord
+ *
+ * this class extends the samtools SAMReadGroupRecord class and caches important
+ * (and oft-accessed) data that's not already cached by the SAMReadGroupRecord class
+ *
+ */
+public class GATKSAMReadGroupRecord extends SAMReadGroupRecord {
+ // the SAMReadGroupRecord data we're caching
+ private String mSample = null;
+ private String mPlatform = null;
+ private NGSPlatform mNGSPlatform = null;
+
+ // because some values can be null, we don't want to duplicate effort
+ private boolean retrievedSample = false;
+ private boolean retrievedPlatform = false;
+ private boolean retrievedNGSPlatform = false;
+
+ public GATKSAMReadGroupRecord(final String id) {
+ super(id);
+ }
+
+ public GATKSAMReadGroupRecord(SAMReadGroupRecord record) {
+ super(record.getReadGroupId(), record);
+ }
+
+ /**
+ * Get the NGSPlatform enum telling us the platform of this read group
+ *
+ * This function call is caching, so subsequent calls to it are free, while
+ * the first time it's called there's a bit of work to resolve the enum
+ *
+ * @return an NGSPlatform enum value
+ */
+ public NGSPlatform getNGSPlatform() {
+ if ( ! retrievedNGSPlatform ) {
+ mNGSPlatform = NGSPlatform.fromReadGroupPL(getPlatform());
+ retrievedNGSPlatform = true;
+ }
+
+ return mNGSPlatform;
+ }
+
+ @Override
+ public String toString() {
+ return "GATKSAMReadGroupRecord @RG:" + getReadGroupId();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // *** The following methods are overloaded to cache the appropriate data ***//
+ ///////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public String getSample() {
+ if ( !retrievedSample ) {
+ mSample = super.getSample();
+ retrievedSample = true;
+ }
+ return mSample;
+ }
+
+ @Override
+ public void setSample(String s) {
+ super.setSample(s);
+ mSample = s;
+ retrievedSample = true;
+ }
+
+ @Override
+ public String getPlatform() {
+ if ( !retrievedPlatform ) {
+ mPlatform = super.getPlatform();
+ retrievedPlatform = true;
+ }
+ return mPlatform;
+ }
+
+ @Override
+ public void setPlatform(String s) {
+ super.setPlatform(s);
+ mPlatform = s;
+ retrievedPlatform = true;
+ retrievedNGSPlatform = false; // recalculate the NGSPlatform
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/GATKSAMRecord.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/GATKSAMRecord.java
new file mode 100644
index 0000000..0080f01
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/GATKSAMRecord.java
@@ -0,0 +1,631 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import com.google.java.contract.Ensures;
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.NGSPlatform;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.recalibration.EventType;
+
+import java.util.*;
+
+/**
+ * @author ebanks, depristo
+ * GATKSAMRecord
+ *
+ * this class extends the samtools BAMRecord class (and SAMRecord) and caches important
+ * (and oft-accessed) data that's not already cached by the SAMRecord class
+ *
+ * IMPORTANT NOTE: Because ReadGroups are not set through the SAMRecord,
+ * if they are ever modified externally then one must also invoke the
+ * setReadGroup() method here to ensure that the cache is kept up-to-date.
+ *
+ * WARNING -- GATKSAMRecords cache several values (that are expensive to compute)
+ * that depending on the inferred insert size and alignment starts and stops of this read and its mate.
+ * Changing these values in any way will invalidate the cached value. However, we do not monitor those setter
+ * functions, so modifying a GATKSAMRecord in any way may result in stale cached values.
+ */
+public class GATKSAMRecord extends BAMRecord implements Cloneable {
+ // Base Quality Score Recalibrator specific attribute tags
+ public static final String BQSR_BASE_INSERTION_QUALITIES = "BI"; // base qualities for insertions
+ public static final String BQSR_BASE_DELETION_QUALITIES = "BD"; // base qualities for deletions
+
+ /**
+ * The default quality score for an insertion or deletion, if
+ * none are provided for this read.
+ */
+ public static final byte DEFAULT_INSERTION_DELETION_QUAL = (byte)45;
+
+ // the SAMRecord data we're caching
+ private String mReadString = null;
+ private GATKSAMReadGroupRecord mReadGroup = null;
+ private final static int UNINITIALIZED = -1;
+ private int softStart = UNINITIALIZED;
+ private int softEnd = UNINITIALIZED;
+ private Integer adapterBoundary = null;
+
+ private boolean isStrandlessRead = false;
+
+ // because some values can be null, we don't want to duplicate effort
+ private boolean retrievedReadGroup = false;
+
+ // These temporary attributes were added here to make life easier for
+ // certain algorithms by providing a way to label or attach arbitrary data to
+ // individual GATKSAMRecords.
+ // These attributes exist in memory only, and are never written to disk.
+ private Map<Object, Object> temporaryAttributes;
+
+ /**
+ * HACK TO CREATE GATKSAMRECORD WITH ONLY A HEADER FOR TESTING PURPOSES ONLY
+ * @param header
+ */
+ public GATKSAMRecord(final SAMFileHeader header) {
+ this(new SAMRecord(header));
+ }
+
+ /**
+ * HACK TO CREATE GATKSAMRECORD BASED ONLY A SAMRECORD FOR TESTING PURPOSES ONLY
+ * @param read
+ */
+ public GATKSAMRecord(final SAMRecord read) {
+ super(read.getHeader(),
+ read.getReferenceIndex(),
+ read.getAlignmentStart(),
+ read.getReadName() != null ? (short)read.getReadNameLength() : 0,
+ (short)read.getMappingQuality(),
+ 0,
+ read.getCigarLength(),
+ read.getFlags(),
+ read.getReadLength(),
+ read.getMateReferenceIndex(),
+ read.getMateAlignmentStart(),
+ read.getInferredInsertSize(),
+ null);
+ SAMReadGroupRecord samRG = read.getReadGroup();
+ clearAttributes();
+ if (samRG != null) {
+ GATKSAMReadGroupRecord rg = new GATKSAMReadGroupRecord(samRG);
+ setReadGroup(rg);
+ }
+ }
+
+ public GATKSAMRecord(final SAMFileHeader header,
+ final int referenceSequenceIndex,
+ final int alignmentStart,
+ final short readNameLength,
+ final short mappingQuality,
+ final int indexingBin,
+ final int cigarLen,
+ final int flags,
+ final int readLen,
+ final int mateReferenceSequenceIndex,
+ final int mateAlignmentStart,
+ final int insertSize,
+ final byte[] variableLengthBlock) {
+ super(header, referenceSequenceIndex, alignmentStart, readNameLength, mappingQuality, indexingBin, cigarLen,
+ flags, readLen, mateReferenceSequenceIndex, mateAlignmentStart, insertSize, variableLengthBlock);
+ }
+
+ public static GATKSAMRecord createRandomRead(int length) {
+ List<CigarElement> cigarElements = new LinkedList<>();
+ cigarElements.add(new CigarElement(length, CigarOperator.M));
+ Cigar cigar = new Cigar(cigarElements);
+ return ArtificialSAMUtils.createArtificialRead(cigar);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // *** support for reads without meaningful strand information ***//
+ ///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Does this read have a meaningful strandedness value?
+ *
+ * Some advanced types of reads, such as reads coming from merged fragments,
+ * don't have meaningful strandedness values, as they are composites of multiple
+ * other reads. Strandless reads need to be handled specially by code that cares about
+ * stranded information, such as FS.
+ *
+ * @return true if this read doesn't have meaningful strand information
+ */
+ public boolean isStrandless() {
+ return isStrandlessRead;
+ }
+
+ /**
+ * Set the strandless state of this read to isStrandless
+ * @param isStrandless true if this read doesn't have a meaningful strandedness value
+ */
+ public void setIsStrandless(final boolean isStrandless) {
+ this.isStrandlessRead = isStrandless;
+ }
+
+ @Override
+ public boolean getReadNegativeStrandFlag() {
+ return ! isStrandless() && super.getReadNegativeStrandFlag();
+ }
+
+ @Override
+ public void setReadNegativeStrandFlag(final boolean flag) {
+ if ( isStrandless() )
+ throw new IllegalStateException("Cannot set the strand of a strandless read");
+ super.setReadNegativeStrandFlag(flag);
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // *** The following methods are overloaded to cache the appropriate data ***//
+ ///////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public String getReadString() {
+ if ( mReadString == null )
+ mReadString = super.getReadString();
+ return mReadString;
+ }
+
+ @Override
+ public void setReadString(String s) {
+ super.setReadString(s);
+ mReadString = s;
+ }
+
+ /**
+ * Get the GATKSAMReadGroupRecord of this read
+ * @return a non-null GATKSAMReadGroupRecord
+ */
+ @Override
+ public GATKSAMReadGroupRecord getReadGroup() {
+ if ( ! retrievedReadGroup ) {
+ final SAMReadGroupRecord rg = super.getReadGroup();
+
+ // three cases: rg may be null (no rg, rg may already be a GATKSAMReadGroupRecord, or it may be
+ // a regular SAMReadGroupRecord in which case we have to make it a GATKSAMReadGroupRecord
+ if ( rg == null )
+ mReadGroup = null;
+ else if ( rg instanceof GATKSAMReadGroupRecord )
+ mReadGroup = (GATKSAMReadGroupRecord)rg;
+ else
+ mReadGroup = new GATKSAMReadGroupRecord(rg);
+
+ retrievedReadGroup = true;
+ }
+ return mReadGroup;
+ }
+
+ public void setReadGroup( final GATKSAMReadGroupRecord readGroup ) {
+ mReadGroup = readGroup;
+ retrievedReadGroup = true;
+ setAttribute("RG", mReadGroup.getId()); // todo -- this should be standardized, but we don't have access to SAMTagUtils!
+ }
+
+
+ @Override
+ public int hashCode() {
+ return super.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+
+ if (!(o instanceof GATKSAMRecord)) return false;
+
+ // note that we do not consider the GATKSAMRecord internal state at all
+ return super.equals(o);
+ }
+
+ /**
+ * Setters and Accessors for base insertion and base deletion quality scores
+ */
+ public void setBaseQualities( final byte[] quals, final EventType errorModel ) {
+ switch( errorModel ) {
+ case BASE_SUBSTITUTION:
+ setBaseQualities(quals);
+ break;
+ case BASE_INSERTION:
+ setAttribute( GATKSAMRecord.BQSR_BASE_INSERTION_QUALITIES, quals == null ? null : SAMUtils.phredToFastq(quals) );
+ break;
+ case BASE_DELETION:
+ setAttribute( GATKSAMRecord.BQSR_BASE_DELETION_QUALITIES, quals == null ? null : SAMUtils.phredToFastq(quals) );
+ break;
+ default:
+ throw new ReviewedGATKException("Unrecognized Base Recalibration type: " + errorModel );
+ }
+ }
+
+ public byte[] getBaseQualities( final EventType errorModel ) {
+ switch( errorModel ) {
+ case BASE_SUBSTITUTION:
+ return getBaseQualities();
+ case BASE_INSERTION:
+ return getBaseInsertionQualities();
+ case BASE_DELETION:
+ return getBaseDeletionQualities();
+ default:
+ throw new ReviewedGATKException("Unrecognized Base Recalibration type: " + errorModel );
+ }
+ }
+
+ /**
+ * @return whether or not this read has base insertion or deletion qualities (one of the two is sufficient to return true)
+ */
+ public boolean hasBaseIndelQualities() {
+ return getAttribute( BQSR_BASE_INSERTION_QUALITIES ) != null || getAttribute( BQSR_BASE_DELETION_QUALITIES ) != null;
+ }
+
+ /**
+ * @return the base deletion quality or null if read doesn't have one
+ */
+ public byte[] getExistingBaseInsertionQualities() {
+ return SAMUtils.fastqToPhred( getStringAttribute(BQSR_BASE_INSERTION_QUALITIES));
+ }
+
+ /**
+ * @return the base deletion quality or null if read doesn't have one
+ */
+ public byte[] getExistingBaseDeletionQualities() {
+ return SAMUtils.fastqToPhred( getStringAttribute(BQSR_BASE_DELETION_QUALITIES));
+ }
+
+ /**
+ * Default utility to query the base insertion quality of a read. If the read doesn't have one, it creates an array of default qualities (currently Q45)
+ * and assigns it to the read.
+ *
+ * @return the base insertion quality array
+ */
+ public byte[] getBaseInsertionQualities() {
+ byte [] quals = getExistingBaseInsertionQualities();
+ if( quals == null ) {
+ quals = new byte[getBaseQualities().length];
+ Arrays.fill(quals, DEFAULT_INSERTION_DELETION_QUAL); // Some day in the future when base insertion and base deletion quals exist the samtools API will
+ // be updated and the original quals will be pulled here, but for now we assume the original quality is a flat Q45
+ }
+ return quals;
+ }
+
+ /**
+ * Default utility to query the base deletion quality of a read. If the read doesn't have one, it creates an array of default qualities (currently Q45)
+ * and assigns it to the read.
+ *
+ * @return the base deletion quality array
+ */
+ public byte[] getBaseDeletionQualities() {
+ byte[] quals = getExistingBaseDeletionQualities();
+ if( quals == null ) {
+ quals = new byte[getBaseQualities().length];
+ Arrays.fill(quals, DEFAULT_INSERTION_DELETION_QUAL); // Some day in the future when base insertion and base deletion quals exist the samtools API will
+ // be updated and the original quals will be pulled here, but for now we assume the original quality is a flat Q45
+ }
+ return quals;
+ }
+
+ /**
+ * Efficient caching accessor that returns the GATK NGSPlatform of this read
+ * @return
+ */
+ public NGSPlatform getNGSPlatform() {
+ return getReadGroup().getNGSPlatform();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // *** GATKSAMRecord specific methods ***//
+ ///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Checks whether an attribute has been set for the given key.
+ *
+ * Temporary attributes provide a way to label or attach arbitrary data to
+ * individual GATKSAMRecords. These attributes exist in memory only,
+ * and are never written to disk.
+ *
+ * @param key key
+ * @return True if an attribute has been set for this key.
+ */
+ public boolean containsTemporaryAttribute(Object key) {
+ return temporaryAttributes != null && temporaryAttributes.containsKey(key);
+ }
+
+ /**
+ * Sets the key to the given value, replacing any previous value. The previous
+ * value is returned.
+ *
+ * Temporary attributes provide a way to label or attach arbitrary data to
+ * individual GATKSAMRecords. These attributes exist in memory only,
+ * and are never written to disk.
+ *
+ * @param key key
+ * @param value value
+ * @return attribute
+ */
+ public Object setTemporaryAttribute(Object key, Object value) {
+ if(temporaryAttributes == null) {
+ temporaryAttributes = new HashMap<>();
+ }
+ return temporaryAttributes.put(key, value);
+ }
+
+ /**
+ * Looks up the value associated with the given key.
+ *
+ * Temporary attributes provide a way to label or attach arbitrary data to
+ * individual GATKSAMRecords. These attributes exist in memory only,
+ * and are never written to disk.
+ *
+ * @param key key
+ * @return The value, or null.
+ */
+ public Object getTemporaryAttribute(Object key) {
+ if(temporaryAttributes != null) {
+ return temporaryAttributes.get(key);
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether if the read has any bases.
+ *
+ * Empty reads can be dangerous as it may have no cigar strings, no read names and
+ * other missing attributes.
+ *
+ * @return true if the read has no bases
+ */
+ public boolean isEmpty() {
+ return super.getReadBases() == null || super.getReadLength() == 0;
+ }
+
+ /**
+ * Clears all attributes except ReadGroup of the read.
+ */
+ public GATKSAMRecord simplify () {
+ GATKSAMReadGroupRecord rg = getReadGroup(); // save the read group information
+ byte[] insQuals = (this.getAttribute(BQSR_BASE_INSERTION_QUALITIES) == null) ? null : getBaseInsertionQualities();
+ byte[] delQuals = (this.getAttribute(BQSR_BASE_DELETION_QUALITIES) == null) ? null : getBaseDeletionQualities();
+ this.clearAttributes(); // clear all attributes from the read
+ this.setReadGroup(rg); // restore read group
+ if (insQuals != null)
+ this.setBaseQualities(insQuals, EventType.BASE_INSERTION); // restore base insertion if we had any
+ if (delQuals != null)
+ this.setBaseQualities(delQuals, EventType.BASE_DELETION); // restore base deletion if we had any
+ return this;
+ }
+
+ /**
+ * Calculates the reference coordinate for the beginning of the read taking into account soft clips but not hard clips.
+ *
+ * Note: getUnclippedStart() adds soft and hard clips, this function only adds soft clips.
+ *
+ * @return the unclipped start of the read taking soft clips (but not hard clips) into account
+ */
+ public int getSoftStart() {
+ if ( softStart == UNINITIALIZED ) {
+ softStart = getAlignmentStart();
+ for (final CigarElement cig : getCigar().getCigarElements()) {
+ final CigarOperator op = cig.getOperator();
+
+ if (op == CigarOperator.SOFT_CLIP)
+ softStart -= cig.getLength();
+ else if (op != CigarOperator.HARD_CLIP)
+ break;
+ }
+ }
+ return softStart;
+ }
+
+ /**
+ * Calculates the reference coordinate for the end of the read taking into account soft clips but not hard clips.
+ *
+ * Note: getUnclippedEnd() adds soft and hard clips, this function only adds soft clips.
+ *
+ * @return the unclipped end of the read taking soft clips (but not hard clips) into account
+ */
+ public int getSoftEnd() {
+ if ( softEnd == UNINITIALIZED ) {
+ boolean foundAlignedBase = false;
+ softEnd = getAlignmentEnd();
+ final List<CigarElement> cigs = getCigar().getCigarElements();
+ for (int i = cigs.size() - 1; i >= 0; --i) {
+ final CigarElement cig = cigs.get(i);
+ final CigarOperator op = cig.getOperator();
+
+ if (op == CigarOperator.SOFT_CLIP) // assumes the soft clip that we found is at the end of the aligned read
+ softEnd += cig.getLength();
+ else if (op != CigarOperator.HARD_CLIP) {
+ foundAlignedBase = true;
+ break;
+ }
+ }
+ if( !foundAlignedBase ) { // for example 64H14S, the soft end is actually the same as the alignment end
+ softEnd = getAlignmentEnd();
+ }
+ }
+
+ return softEnd;
+ }
+
+ /**
+ * If the read is hard clipped, the soft start and end will change. You can set manually or just reset the cache
+ * so that the next call to getSoftStart/End will recalculate it lazily.
+ */
+ public void resetSoftStartAndEnd() {
+ softStart = -1;
+ softEnd = -1;
+ }
+
+ /**
+ * If the read is hard clipped, the soft start and end will change. You can set manually or just reset the cache
+ * so that the next call to getSoftStart/End will recalculate it lazily.
+ */
+ public void resetSoftStartAndEnd(int softStart, int softEnd) {
+ this.softStart = softStart;
+ this.softEnd = softEnd;
+ }
+
+ /**
+ * Determines the original alignment start of a previously clipped read.
+ *
+ * This is useful for reads that have been trimmed to a variant region and lost the information of it's original alignment end
+ *
+ * @return the alignment start of a read before it was clipped
+ */
+ public int getOriginalAlignmentStart() {
+ return getUnclippedStart();
+ }
+
+ /**
+ * Determines the original alignment end of a previously clipped read.
+ *
+ * This is useful for reads that have been trimmed to a variant region and lost the information of it's original alignment end
+ *
+ * @return the alignment end of a read before it was clipped
+ */
+ public int getOriginalAlignmentEnd() {
+ return getUnclippedEnd();
+ }
+
+ /**
+ * Creates an empty GATKSAMRecord with the read's header, read group and mate
+ * information, but empty (not-null) fields:
+ * - Cigar String
+ * - Read Bases
+ * - Base Qualities
+ *
+ * Use this method if you want to create a new empty GATKSAMRecord based on
+ * another GATKSAMRecord
+ *
+ * @param read a read to copy the header from
+ * @return a read with no bases but safe for the GATK
+ */
+ public static GATKSAMRecord emptyRead(GATKSAMRecord read) {
+ GATKSAMRecord emptyRead = new GATKSAMRecord(read.getHeader(),
+ read.getReferenceIndex(),
+ 0,
+ (short) 0,
+ (short) 0,
+ 0,
+ 0,
+ read.getFlags(),
+ 0,
+ read.getMateReferenceIndex(),
+ read.getMateAlignmentStart(),
+ read.getInferredInsertSize(),
+ null);
+
+ emptyRead.setCigarString("");
+ emptyRead.setReadBases(new byte[0]);
+ emptyRead.setBaseQualities(new byte[0]);
+
+ SAMReadGroupRecord samRG = read.getReadGroup();
+ emptyRead.clearAttributes();
+ if (samRG != null) {
+ GATKSAMReadGroupRecord rg = new GATKSAMReadGroupRecord(samRG);
+ emptyRead.setReadGroup(rg);
+ }
+
+ return emptyRead;
+ }
+
+ /**
+ * Creates a new GATKSAMRecord with the source read's header, read group and mate
+ * information, but with the following fields set to user-supplied values:
+ * - Read Bases
+ * - Base Qualities
+ * - Base Insertion Qualities
+ * - Base Deletion Qualities
+ *
+ * Cigar string is empty (not-null)
+ *
+ * Use this method if you want to create a new GATKSAMRecord based on
+ * another GATKSAMRecord, but with modified bases and qualities
+ *
+ * @param read a read to copy the header from
+ * @param readBases an array containing the new bases you wish use in place of the originals
+ * @param baseQualities an array containing the new base qualities you wish use in place of the originals
+ * @param baseInsertionQualities an array containing the new base insertion qaulities
+ * @param baseDeletionQualities an array containing the new base deletion qualities
+ * @return a read with modified bases and qualities, safe for the GATK
+ */
+ public static GATKSAMRecord createQualityModifiedRead(final GATKSAMRecord read,
+ final byte[] readBases,
+ final byte[] baseQualities,
+ final byte[] baseInsertionQualities,
+ final byte[] baseDeletionQualities) {
+ if ( baseQualities.length != readBases.length || baseInsertionQualities.length != readBases.length || baseDeletionQualities.length != readBases.length )
+ throw new IllegalArgumentException("Read bases and read quality arrays aren't the same size: Bases:" + readBases.length
+ + " vs Base Q's:" + baseQualities.length
+ + " vs Insert Q's:" + baseInsertionQualities.length
+ + " vs Delete Q's:" + baseDeletionQualities.length);
+
+ final GATKSAMRecord processedRead = GATKSAMRecord.emptyRead(read);
+ processedRead.setReadBases(readBases);
+ processedRead.setBaseQualities(baseQualities, EventType.BASE_SUBSTITUTION);
+ processedRead.setBaseQualities(baseInsertionQualities, EventType.BASE_INSERTION);
+ processedRead.setBaseQualities(baseDeletionQualities, EventType.BASE_DELETION);
+
+ return processedRead;
+ }
+
+ /**
+ * Shallow copy of everything, except for the attribute list and the temporary attributes.
+ * A new list of the attributes is created for both, but the attributes themselves are copied by reference.
+ * This should be safe because callers should never modify a mutable value returned by any of the get() methods anyway.
+ *
+ * @return a shallow copy of the GATKSAMRecord
+ */
+ @Override
+ public Object clone() {
+ try {
+ final GATKSAMRecord clone = (GATKSAMRecord) super.clone();
+ if (temporaryAttributes != null) {
+ clone.temporaryAttributes = new HashMap<>();
+ for (Object attribute : temporaryAttributes.keySet())
+ clone.setTemporaryAttribute(attribute, temporaryAttributes.get(attribute));
+ }
+ return clone;
+ } catch (final CloneNotSupportedException e) {
+ throw new RuntimeException( e );
+ }
+ }
+
+ /**
+ * A caching version of ReadUtils.getAdaptorBoundary()
+ *
+ * see #ReadUtils.getAdaptorBoundary(SAMRecord) for more information about the meaning of this function
+ *
+ * WARNING -- this function caches a value depending on the inferred insert size and alignment starts
+ * and stops of this read and its mate. Changing these values in any way will invalidate the cached value.
+ * However, we do not monitor those setter functions, so modifying a GATKSAMRecord in any way may
+ * result in stale cached values.
+ *
+ * @return the result of calling ReadUtils.getAdaptorBoundary on this read
+ */
+ @Ensures("result == ReadUtils.getAdaptorBoundary(this)")
+ public int getAdaptorBoundary() {
+ if ( adapterBoundary == null )
+ adapterBoundary = ReadUtils.getAdaptorBoundary(this);
+ return adapterBoundary;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/GATKSamRecordFactory.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/GATKSamRecordFactory.java
new file mode 100644
index 0000000..1e5ad1e
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/GATKSamRecordFactory.java
@@ -0,0 +1,75 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMRecordFactory;
+import htsjdk.samtools.BAMRecord;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+/**
+ * Factory interface implementation used to create GATKSamRecords
+ * from SAMFileReaders with SAM-JDK
+ *
+ * @author Mark DePristo
+ */
+public class GATKSamRecordFactory implements SAMRecordFactory {
+
+ /** Create a new SAMRecord to be filled in */
+ public SAMRecord createSAMRecord(SAMFileHeader header) {
+ throw new UserException.BadInput("The GATK now longer supports input SAM files");
+ }
+
+ /** Create a new BAM Record. */
+ public BAMRecord createBAMRecord(final SAMFileHeader header,
+ final int referenceSequenceIndex,
+ final int alignmentStart,
+ final short readNameLength,
+ final short mappingQuality,
+ final int indexingBin,
+ final int cigarLen,
+ final int flags,
+ final int readLen,
+ final int mateReferenceSequenceIndex,
+ final int mateAlignmentStart,
+ final int insertSize,
+ final byte[] variableLengthBlock) {
+ return new GATKSAMRecord(header,
+ referenceSequenceIndex,
+ alignmentStart,
+ readNameLength,
+ mappingQuality,
+ indexingBin,
+ cigarLen,
+ flags,
+ readLen,
+ mateReferenceSequenceIndex,
+ mateAlignmentStart,
+ insertSize,
+ variableLengthBlock);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/MisencodedBaseQualityReadTransformer.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/MisencodedBaseQualityReadTransformer.java
new file mode 100644
index 0000000..35146f0
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/MisencodedBaseQualityReadTransformer.java
@@ -0,0 +1,94 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.QualityUtils;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+/**
+ * Checks for and errors out (or fixes if requested) when it detects reads with base qualities that are not encoded with
+ * phred-scaled quality scores. Q0 == ASCII 33 according to the SAM specification, whereas Illumina encoding starts at
+ * Q64. The idea here is simple: if we are asked to fix the scores then we just subtract 31 from every quality score.
+ * Otherwise, we randomly sample reads (for efficiency) and error out if we encounter a qual that's too high.
+ */
+public class MisencodedBaseQualityReadTransformer extends ReadTransformer {
+
+ private static final int samplingFrequency = 1000; // sample 1 read for every 1000 encountered
+ private static final int encodingFixValue = 31; // Illumina_64 - PHRED_33
+
+ private boolean disabled;
+ private boolean fixQuals;
+ protected static int currentReadCounter = 0;
+
+ @Override
+ public ApplicationTime initializeSub(final GenomeAnalysisEngine engine, final Walker walker) {
+ fixQuals = engine.getArguments().FIX_MISENCODED_QUALS;
+ disabled = !fixQuals && engine.getArguments().ALLOW_POTENTIALLY_MISENCODED_QUALS;
+
+ return ReadTransformer.ApplicationTime.ON_INPUT;
+ }
+
+ @Override
+ public boolean enabled() {
+ return !disabled;
+ }
+
+ @Override
+ public GATKSAMRecord apply(final GATKSAMRecord read) {
+ if ( fixQuals )
+ return fixMisencodedQuals(read);
+
+ checkForMisencodedQuals(read);
+ return read;
+ }
+
+ protected static GATKSAMRecord fixMisencodedQuals(final GATKSAMRecord read) {
+ final byte[] quals = read.getBaseQualities();
+ for ( int i = 0; i < quals.length; i++ ) {
+ quals[i] -= encodingFixValue;
+ if ( quals[i] < 0 )
+ throw new UserException.BadInput("while fixing mis-encoded base qualities we encountered a read that was correctly encoded; we cannot handle such a mixture of reads so unfortunately the BAM must be fixed with some other tool");
+ }
+ read.setBaseQualities(quals);
+ return read;
+ }
+
+ protected static void checkForMisencodedQuals(final GATKSAMRecord read) {
+ // sample reads randomly for checking
+ if ( ++currentReadCounter >= samplingFrequency ) {
+ currentReadCounter = 0;
+
+ final byte[] quals = read.getBaseQualities();
+ for ( final byte qual : quals ) {
+ if ( qual > QualityUtils.MAX_REASONABLE_Q_SCORE )
+ throw new UserException.MisencodedBAM(read, "we encountered an extremely high quality score of " + (int)qual);
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/NWaySAMFileWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/NWaySAMFileWriter.java
new file mode 100644
index 0000000..abf70d5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/NWaySAMFileWriter.java
@@ -0,0 +1,185 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.*;
+import htsjdk.samtools.util.ProgressLoggerInterface;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: asivache
+ * Date: May 31, 2011
+ * Time: 3:52:49 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class NWaySAMFileWriter implements SAMFileWriter {
+
+ private Map<SAMReaderID,SAMFileWriter> writerMap = null;
+ private boolean presorted ;
+ GenomeAnalysisEngine toolkit;
+ boolean KEEP_ALL_PG_RECORDS = false;
+
+ public NWaySAMFileWriter(GenomeAnalysisEngine toolkit, Map<String,String> in2out, SAMFileHeader.SortOrder order,
+ boolean presorted, boolean indexOnTheFly, boolean generateMD5, SAMProgramRecord pRecord, boolean keep_records) {
+ this.presorted = presorted;
+ this.toolkit = toolkit;
+ this.KEEP_ALL_PG_RECORDS = keep_records;
+ writerMap = new HashMap<SAMReaderID,SAMFileWriter>();
+ setupByReader(toolkit,in2out,order, presorted, indexOnTheFly, generateMD5, pRecord);
+ }
+
+ public NWaySAMFileWriter(GenomeAnalysisEngine toolkit, String ext, SAMFileHeader.SortOrder order,
+ boolean presorted, boolean indexOnTheFly , boolean generateMD5, SAMProgramRecord pRecord, boolean keep_records) {
+ this.presorted = presorted;
+ this.toolkit = toolkit;
+ this.KEEP_ALL_PG_RECORDS = keep_records;
+ writerMap = new HashMap<SAMReaderID,SAMFileWriter>();
+ setupByReader(toolkit,ext,order, presorted, indexOnTheFly, generateMD5, pRecord);
+ }
+
+ public NWaySAMFileWriter(GenomeAnalysisEngine toolkit, Map<String,String> in2out, SAMFileHeader.SortOrder order,
+ boolean presorted, boolean indexOnTheFly, boolean generateMD5) {
+ this(toolkit, in2out, order, presorted, indexOnTheFly, generateMD5, null,false);
+ }
+
+ public NWaySAMFileWriter(GenomeAnalysisEngine toolkit, String ext, SAMFileHeader.SortOrder order,
+ boolean presorted, boolean indexOnTheFly , boolean generateMD5) {
+ this(toolkit, ext, order, presorted, indexOnTheFly, generateMD5, null,false);
+ }
+
+ /**
+ * Instantiates multiple underlying SAM writes, one per input SAM reader registered with GATK engine (those will be retrieved
+ * from <code>toolkit</code>). The <code>in2out</code> map must contain an entry for each input filename and map it
+ * onto a unique output file name.
+ * @param toolkit
+ * @param in2out
+ */
+ public void setupByReader(GenomeAnalysisEngine toolkit, Map<String,String> in2out, SAMFileHeader.SortOrder order,
+ boolean presorted, boolean indexOnTheFly, boolean generateMD5, SAMProgramRecord pRecord) {
+ if ( in2out==null ) throw new GATKException("input-output bam filename map for n-way-out writing is NULL");
+ for ( SAMReaderID rid : toolkit.getReadsDataSource().getReaderIDs() ) {
+
+ String fName = toolkit.getReadsDataSource().getSAMFile(rid).getName();
+
+ String outName;
+ if ( ! in2out.containsKey(fName) )
+ throw new UserException.BadInput("Input-output bam filename map does not contain an entry for the input file "+fName);
+ outName = in2out.get(fName);
+
+ if ( writerMap.containsKey( rid ) )
+ throw new GATKException("nWayOut mode: Reader id for input sam file "+fName+" is already registered; "+
+ "map file likely contains multiple entries for this input file");
+
+ addWriter(rid,outName, order, presorted, indexOnTheFly, generateMD5, pRecord);
+ }
+
+ }
+
+ /**
+ * Instantiates multiple underlying SAM writes, one per input SAM reader registered with GATK engine (those will be retrieved
+ * from <code>toolkit</code>). The output file names will be generated automatically by stripping ".sam" or ".bam" off the
+ * input file name and adding ext instead (e.g. ".cleaned.bam").
+ * onto a unique output file name.
+ * @param toolkit
+ * @param ext
+ */
+ public void setupByReader(GenomeAnalysisEngine toolkit, String ext, SAMFileHeader.SortOrder order,
+ boolean presorted, boolean indexOnTheFly, boolean generateMD5, SAMProgramRecord pRecord) {
+ for ( SAMReaderID rid : toolkit.getReadsDataSource().getReaderIDs() ) {
+
+ String fName = toolkit.getReadsDataSource().getSAMFile(rid).getName();
+
+ String outName;
+ int pos ;
+ if ( fName.toUpperCase().endsWith(".BAM") ) pos = fName.toUpperCase().lastIndexOf(".BAM");
+ else {
+ if ( fName.toUpperCase().endsWith(".SAM") ) pos = fName.toUpperCase().lastIndexOf(".SAM");
+ else throw new UserException.BadInput("Input file name "+fName+" does not end with .sam or .bam");
+ }
+ String prefix = fName.substring(0,pos);
+ outName = prefix+ext;
+
+ if ( writerMap.containsKey( rid ) )
+ throw new GATKException("nWayOut mode: Reader id for input sam file "+fName+" is already registered");
+ addWriter(rid,outName, order, presorted, indexOnTheFly, generateMD5, pRecord);
+ }
+
+ }
+
+ private void addWriter(SAMReaderID id , String outName, SAMFileHeader.SortOrder order, boolean presorted,
+ boolean indexOnTheFly, boolean generateMD5, SAMProgramRecord programRecord) {
+ File f = new File(outName);
+ SAMFileHeader header = Utils.setupWriter(toolkit.getSAMFileHeader(id), programRecord);
+ SAMFileWriterFactory factory = new SAMFileWriterFactory();
+ factory.setCreateIndex(indexOnTheFly);
+ factory.setCreateMd5File(generateMD5);
+ SAMFileWriter sw = factory.makeSAMOrBAMWriter(header, presorted, f);
+ writerMap.put(id,sw);
+ }
+
+ public Collection<SAMFileWriter> getWriters() {
+ return writerMap.values();
+ }
+
+ public void addAlignment(SAMRecord samRecord) {
+ final SAMReaderID id = toolkit.getReaderIDForRead(samRecord);
+ String rg = samRecord.getStringAttribute("RG");
+ if ( rg != null ) {
+ String rg_orig = toolkit.getReadsDataSource().getOriginalReadGroupId(rg);
+ samRecord.setAttribute("RG",rg_orig);
+ }
+ addAlignment(samRecord, id);
+ }
+
+ public void addAlignment(SAMRecord samRecord, SAMReaderID readerID) {
+ writerMap.get(readerID).addAlignment(samRecord);
+ }
+
+ public SAMFileHeader getFileHeader() {
+ return toolkit.getSAMFileHeader();
+ }
+
+ public void close() {
+ for ( SAMFileWriter w : writerMap.values() ) w.close();
+ }
+
+ @Override
+ public void setProgressLogger(final ProgressLoggerInterface logger) {
+ for (final SAMFileWriter writer: writerMap.values()) {
+ writer.setProgressLogger(logger);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ReadUnclippedStartWithNoTiesComparator.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ReadUnclippedStartWithNoTiesComparator.java
new file mode 100644
index 0000000..9d2a391
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ReadUnclippedStartWithNoTiesComparator.java
@@ -0,0 +1,73 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.SAMRecord;
+
+import java.util.Comparator;
+
+public class ReadUnclippedStartWithNoTiesComparator implements Comparator<SAMRecord> {
+ @Requires("c1 >= 0 && c2 >= 0")
+ @Ensures("result == 0 || result == 1 || result == -1")
+ private int compareContigs(int c1, int c2) {
+ if (c1 == c2)
+ return 0;
+ else if (c1 > c2)
+ return 1;
+ return -1;
+ }
+
+ @Requires("r1 != null && r2 != null")
+ @Ensures("result == 0 || result == 1 || result == -1")
+ public int compare(SAMRecord r1, SAMRecord r2) {
+ int result;
+
+ if (r1 == r2)
+ result = 0;
+
+ else if (r1.getReadUnmappedFlag())
+ result = 1;
+ else if (r2.getReadUnmappedFlag())
+ result = -1;
+ else {
+ final int cmpContig = compareContigs(r1.getReferenceIndex(), r2.getReferenceIndex());
+
+ if (cmpContig != 0)
+ result = cmpContig;
+
+ else {
+ if (r1.getUnclippedStart() < r2.getUnclippedStart())
+ result = -1;
+ else
+ result = 1;
+ }
+ }
+
+ return result;
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ReadUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ReadUtils.java
new file mode 100644
index 0000000..7fc1b40
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/ReadUtils.java
@@ -0,0 +1,964 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.*;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.io.stubs.SAMFileWriterStub;
+import org.broadinstitute.gatk.utils.*;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * A miscellaneous collection of utilities for working with SAM files, headers, etc.
+ * Static methods only, please.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class ReadUtils {
+ private final static Logger logger = Logger.getLogger(ReadUtils.class);
+
+ private static final String OFFSET_OUT_OF_BOUNDS_EXCEPTION = "Offset cannot be greater than read length %d : %d";
+ private static final String OFFSET_NOT_ZERO_EXCEPTION = "We ran past the end of the read and never found the offset, something went wrong!";
+
+ private ReadUtils() {
+ }
+
+ private static final int DEFAULT_ADAPTOR_SIZE = 100;
+ public static final int CLIPPING_GOAL_NOT_REACHED = -1;
+
+ /**
+ * A marker to tell which end of the read has been clipped
+ */
+ public enum ClippingTail {
+ LEFT_TAIL,
+ RIGHT_TAIL
+ }
+
+ /**
+ * A HashMap of the SAM spec read flag names
+ *
+ * Note: This is not being used right now, but can be useful in the future
+ */
+ private static final Map<Integer, String> readFlagNames = new HashMap<Integer, String>();
+
+ static {
+ readFlagNames.put(0x1, "Paired");
+ readFlagNames.put(0x2, "Proper");
+ readFlagNames.put(0x4, "Unmapped");
+ readFlagNames.put(0x8, "MateUnmapped");
+ readFlagNames.put(0x10, "Forward");
+ //readFlagNames.put(0x20, "MateForward");
+ readFlagNames.put(0x40, "FirstOfPair");
+ readFlagNames.put(0x80, "SecondOfPair");
+ readFlagNames.put(0x100, "NotPrimary");
+ readFlagNames.put(0x200, "NON-PF");
+ readFlagNames.put(0x400, "Duplicate");
+ }
+
+ /**
+ * This enum represents all the different ways in which a read can overlap an interval.
+ *
+ * NO_OVERLAP_CONTIG:
+ * read and interval are in different contigs.
+ *
+ * NO_OVERLAP_LEFT:
+ * the read does not overlap the interval.
+ *
+ * |----------------| (interval)
+ * <----------------> (read)
+ *
+ * NO_OVERLAP_RIGHT:
+ * the read does not overlap the interval.
+ *
+ * |----------------| (interval)
+ * <----------------> (read)
+ *
+ * OVERLAP_LEFT:
+ * the read starts before the beginning of the interval but ends inside of it
+ *
+ * |----------------| (interval)
+ * <----------------> (read)
+ *
+ * OVERLAP_RIGHT:
+ * the read starts inside the interval but ends outside of it
+ *
+ * |----------------| (interval)
+ * <----------------> (read)
+ *
+ * OVERLAP_LEFT_AND_RIGHT:
+ * the read starts before the interval and ends after the interval
+ *
+ * |-----------| (interval)
+ * <-------------------> (read)
+ *
+ * OVERLAP_CONTAINED:
+ * the read starts and ends inside the interval
+ *
+ * |----------------| (interval)
+ * <--------> (read)
+ */
+ public enum ReadAndIntervalOverlap {NO_OVERLAP_CONTIG, NO_OVERLAP_LEFT, NO_OVERLAP_RIGHT, NO_OVERLAP_HARDCLIPPED_LEFT, NO_OVERLAP_HARDCLIPPED_RIGHT, OVERLAP_LEFT, OVERLAP_RIGHT, OVERLAP_LEFT_AND_RIGHT, OVERLAP_CONTAINED}
+
+ /**
+ * Creates a SAMFileWriter using all of the features currently set in the engine (command line arguments, ReadTransformers, etc)
+ * @param file the filename to write to
+ * @param engine the engine
+ * @return a SAMFileWriter with the correct options set
+ */
+ public static SAMFileWriter createSAMFileWriter(final String file, final GenomeAnalysisEngine engine) {
+ final SAMFileWriterStub output = new SAMFileWriterStub(engine, new File(file));
+ output.processArguments(engine.getArguments());
+ return output;
+ }
+
+ /**
+ * As {@link #createSAMFileWriter(String, org.broadinstitute.gatk.engine.GenomeAnalysisEngine)}, but also sets the header
+ */
+ public static SAMFileWriter createSAMFileWriter(final String file, final GenomeAnalysisEngine engine, final SAMFileHeader header) {
+ final SAMFileWriterStub output = (SAMFileWriterStub) createSAMFileWriter(file, engine);
+ output.writeHeader(header);
+ return output;
+ }
+
+ /**
+ * is this base inside the adaptor of the read?
+ *
+ * There are two cases to treat here:
+ *
+ * 1) Read is in the negative strand => Adaptor boundary is on the left tail
+ * 2) Read is in the positive strand => Adaptor boundary is on the right tail
+ *
+ * Note: We return false to all reads that are UNMAPPED or have an weird big insert size (probably due to mismapping or bigger event)
+ *
+ * @param read the read to test
+ * @param basePos base position in REFERENCE coordinates (not read coordinates)
+ * @return whether or not the base is in the adaptor
+ */
+ public static boolean isBaseInsideAdaptor(final GATKSAMRecord read, long basePos) {
+ final int adaptorBoundary = read.getAdaptorBoundary();
+ if (adaptorBoundary == CANNOT_COMPUTE_ADAPTOR_BOUNDARY || read.getInferredInsertSize() > DEFAULT_ADAPTOR_SIZE)
+ return false;
+
+ return read.getReadNegativeStrandFlag() ? basePos <= adaptorBoundary : basePos >= adaptorBoundary;
+ }
+
+ /**
+ * Finds the adaptor boundary around the read and returns the first base inside the adaptor that is closest to
+ * the read boundary. If the read is in the positive strand, this is the first base after the end of the
+ * fragment (Picard calls it 'insert'), if the read is in the negative strand, this is the first base before the
+ * beginning of the fragment.
+ *
+ * There are two cases we need to treat here:
+ *
+ * 1) Our read is in the reverse strand :
+ *
+ * <----------------------| *
+ * |--------------------->
+ *
+ * in these cases, the adaptor boundary is at the mate start (minus one)
+ *
+ * 2) Our read is in the forward strand :
+ *
+ * |----------------------> *
+ * <----------------------|
+ *
+ * in these cases the adaptor boundary is at the start of the read plus the inferred insert size (plus one)
+ *
+ * @param read the read being tested for the adaptor boundary
+ * @return the reference coordinate for the adaptor boundary (effectively the first base IN the adaptor, closest to the read.
+ * CANNOT_COMPUTE_ADAPTOR_BOUNDARY if the read is unmapped or the mate is mapped to another contig.
+ */
+ public static int getAdaptorBoundary(final SAMRecord read) {
+ if ( ! hasWellDefinedFragmentSize(read) ) {
+ return CANNOT_COMPUTE_ADAPTOR_BOUNDARY;
+ } else if ( read.getReadNegativeStrandFlag() ) {
+ return read.getMateAlignmentStart() - 1; // case 1 (see header)
+ } else {
+ final int insertSize = Math.abs(read.getInferredInsertSize()); // the inferred insert size can be negative if the mate is mapped before the read (so we take the absolute value)
+ return read.getAlignmentStart() + insertSize + 1; // case 2 (see header)
+ }
+ }
+
+ public static int CANNOT_COMPUTE_ADAPTOR_BOUNDARY = Integer.MIN_VALUE;
+
+ /**
+ * Can the adaptor sequence of read be reliably removed from the read based on the alignment of
+ * read and its mate?
+ *
+ * @param read the read to check
+ * @return true if it can, false otherwise
+ */
+ public static boolean hasWellDefinedFragmentSize(final SAMRecord read) {
+ if ( read.getInferredInsertSize() == 0 )
+ // no adaptors in reads with mates in another chromosome or unmapped pairs
+ return false;
+ if ( ! read.getReadPairedFlag() )
+ // only reads that are paired can be adaptor trimmed
+ return false;
+ if ( read.getReadUnmappedFlag() || read.getMateUnmappedFlag() )
+ // only reads when both reads are mapped can be trimmed
+ return false;
+// if ( ! read.getProperPairFlag() )
+// // note this flag isn't always set properly in BAMs, can will stop us from eliminating some proper pairs
+// // reads that aren't part of a proper pair (i.e., have strange alignments) can't be trimmed
+// return false;
+ if ( read.getReadNegativeStrandFlag() == read.getMateNegativeStrandFlag() )
+ // sanity check on getProperPairFlag to ensure that read1 and read2 aren't on the same strand
+ return false;
+
+ if ( read.getReadNegativeStrandFlag() ) {
+ // we're on the negative strand, so our read runs right to left
+ return read.getAlignmentEnd() > read.getMateAlignmentStart();
+ } else {
+ // we're on the positive strand, so our mate should be to our right (his start + insert size should be past our start)
+ return read.getAlignmentStart() <= read.getMateAlignmentStart() + read.getInferredInsertSize();
+ }
+ }
+
+ /**
+ * is the read a 454 read?
+ *
+ * @param read the read to test
+ * @return checks the read group tag PL for the default 454 tag
+ */
+ public static boolean is454Read(GATKSAMRecord read) {
+ return NGSPlatform.fromRead(read) == NGSPlatform.LS454;
+ }
+
+ /**
+ * is the read an IonTorrent read?
+ *
+ * @param read the read to test
+ * @return checks the read group tag PL for the default ion tag
+ */
+ public static boolean isIonRead(GATKSAMRecord read) {
+ return NGSPlatform.fromRead(read) == NGSPlatform.ION_TORRENT;
+ }
+
+ /**
+ * is the read a SOLiD read?
+ *
+ * @param read the read to test
+ * @return checks the read group tag PL for the default SOLiD tag
+ */
+ public static boolean isSOLiDRead(GATKSAMRecord read) {
+ return NGSPlatform.fromRead(read) == NGSPlatform.SOLID;
+ }
+
+ /**
+ * is the read a SLX read?
+ *
+ * @param read the read to test
+ * @return checks the read group tag PL for the default SLX tag
+ */
+ public static boolean isIlluminaRead(GATKSAMRecord read) {
+ return NGSPlatform.fromRead(read) == NGSPlatform.ILLUMINA;
+ }
+
+ /**
+ * checks if the read has a platform tag in the readgroup equal to 'name'.
+ * Assumes that 'name' is upper-cased.
+ *
+ * @param read the read to test
+ * @param name the upper-cased platform name to test
+ * @return whether or not name == PL tag in the read group of read
+ */
+ public static boolean isPlatformRead(GATKSAMRecord read, String name) {
+
+ SAMReadGroupRecord readGroup = read.getReadGroup();
+ if (readGroup != null) {
+ Object readPlatformAttr = readGroup.getAttribute("PL");
+ if (readPlatformAttr != null)
+ return readPlatformAttr.toString().toUpperCase().contains(name);
+ }
+ return false;
+ }
+
+
+ /**
+ * Returns the collections of reads sorted in coordinate order, according to the order defined
+ * in the reads themselves
+ *
+ * @param reads
+ * @return
+ */
+ public final static List<GATKSAMRecord> sortReadsByCoordinate(List<GATKSAMRecord> reads) {
+ final SAMRecordComparator comparer = new SAMRecordCoordinateComparator();
+ Collections.sort(reads, comparer);
+ return reads;
+ }
+
+ /**
+ * If a read starts in INSERTION, returns the first element length.
+ *
+ * Warning: If the read has Hard or Soft clips before the insertion this function will return 0.
+ *
+ * @param read
+ * @return the length of the first insertion, or 0 if there is none (see warning).
+ */
+ public final static int getFirstInsertionOffset(SAMRecord read) {
+ CigarElement e = read.getCigar().getCigarElement(0);
+ if ( e.getOperator() == CigarOperator.I )
+ return e.getLength();
+ else
+ return 0;
+ }
+
+ /**
+ * If a read ends in INSERTION, returns the last element length.
+ *
+ * Warning: If the read has Hard or Soft clips after the insertion this function will return 0.
+ *
+ * @param read
+ * @return the length of the last insertion, or 0 if there is none (see warning).
+ */
+ public final static int getLastInsertionOffset(SAMRecord read) {
+ CigarElement e = read.getCigar().getCigarElement(read.getCigarLength() - 1);
+ if ( e.getOperator() == CigarOperator.I )
+ return e.getLength();
+ else
+ return 0;
+ }
+
+ /**
+ * Determines what is the position of the read in relation to the interval.
+ * Note: This function uses the UNCLIPPED ENDS of the reads for the comparison.
+ * @param read the read
+ * @param interval the interval
+ * @return the overlap type as described by ReadAndIntervalOverlap enum (see above)
+ */
+ public static ReadAndIntervalOverlap getReadAndIntervalOverlapType(GATKSAMRecord read, GenomeLoc interval) {
+
+ int sStart = read.getSoftStart();
+ int sStop = read.getSoftEnd();
+ int uStart = read.getUnclippedStart();
+ int uStop = read.getUnclippedEnd();
+
+ if ( !read.getReferenceName().equals(interval.getContig()) )
+ return ReadAndIntervalOverlap.NO_OVERLAP_CONTIG;
+
+ else if ( uStop < interval.getStart() )
+ return ReadAndIntervalOverlap.NO_OVERLAP_LEFT;
+
+ else if ( uStart > interval.getStop() )
+ return ReadAndIntervalOverlap.NO_OVERLAP_RIGHT;
+
+ else if ( sStop < interval.getStart() )
+ return ReadAndIntervalOverlap.NO_OVERLAP_HARDCLIPPED_LEFT;
+
+ else if ( sStart > interval.getStop() )
+ return ReadAndIntervalOverlap.NO_OVERLAP_HARDCLIPPED_RIGHT;
+
+ else if ( (sStart >= interval.getStart()) &&
+ (sStop <= interval.getStop()) )
+ return ReadAndIntervalOverlap.OVERLAP_CONTAINED;
+
+ else if ( (sStart < interval.getStart()) &&
+ (sStop > interval.getStop()) )
+ return ReadAndIntervalOverlap.OVERLAP_LEFT_AND_RIGHT;
+
+ else if ( (sStart < interval.getStart()) )
+ return ReadAndIntervalOverlap.OVERLAP_LEFT;
+
+ else
+ return ReadAndIntervalOverlap.OVERLAP_RIGHT;
+ }
+
+ /**
+ * Pre-processes the results of getReadCoordinateForReferenceCoordinate(GATKSAMRecord, int) to take care of
+ * two corner cases:
+ *
+ * 1. If clipping the right tail (end of the read) getReadCoordinateForReferenceCoordinate and fall inside
+ * a deletion return the base after the deletion. If clipping the left tail (beginning of the read) it
+ * doesn't matter because it already returns the previous base by default.
+ *
+ * 2. If clipping the left tail (beginning of the read) getReadCoordinateForReferenceCoordinate and the
+ * read starts with an insertion, and you're requesting the first read based coordinate, it will skip
+ * the leading insertion (because it has the same reference coordinate as the following base).
+ *
+ * @param read
+ * @param refCoord
+ * @param tail
+ * @return the read coordinate corresponding to the requested reference coordinate for clipping.
+ */
+ @Requires({"refCoord >= read.getUnclippedStart()", "refCoord <= read.getUnclippedEnd() || (read.getUnclippedEnd() < read.getUnclippedStart())"})
+ @Ensures({"result >= 0", "result < read.getReadLength()"})
+ public static int getReadCoordinateForReferenceCoordinate(GATKSAMRecord read, int refCoord, ClippingTail tail) {
+ return getReadCoordinateForReferenceCoordinate(read.getSoftStart(), read.getCigar(), refCoord, tail, false);
+ }
+
+ public static int getReadCoordinateForReferenceCoordinateUpToEndOfRead(GATKSAMRecord read, int refCoord, ClippingTail tail) {
+ final int leftmostSafeVariantPosition = Math.max(read.getSoftStart(), refCoord);
+ return getReadCoordinateForReferenceCoordinate(read.getSoftStart(), read.getCigar(), leftmostSafeVariantPosition, tail, false);
+ }
+
+ public static int getReadCoordinateForReferenceCoordinate(final int alignmentStart, final Cigar cigar, final int refCoord, final ClippingTail tail, final boolean allowGoalNotReached) {
+ Pair<Integer, Boolean> result = getReadCoordinateForReferenceCoordinate(alignmentStart, cigar, refCoord, allowGoalNotReached);
+ int readCoord = result.getFirst();
+
+ // Corner case one: clipping the right tail and falls on deletion, move to the next
+ // read coordinate. It is not a problem for the left tail because the default answer
+ // from getReadCoordinateForReferenceCoordinate is to give the previous read coordinate.
+ if (result.getSecond() && tail == ClippingTail.RIGHT_TAIL)
+ readCoord++;
+
+ // clipping the left tail and first base is insertion, go to the next read coordinate
+ // with the same reference coordinate. Advance to the next cigar element, or to the
+ // end of the read if there is no next element.
+ final CigarElement firstElementIsInsertion = readStartsWithInsertion(cigar);
+ if (readCoord == 0 && tail == ClippingTail.LEFT_TAIL && firstElementIsInsertion != null)
+ readCoord = Math.min(firstElementIsInsertion.getLength(), cigar.getReadLength() - 1);
+
+ return readCoord;
+ }
+
+ /**
+ * Returns the read coordinate corresponding to the requested reference coordinate.
+ *
+ * WARNING: if the requested reference coordinate happens to fall inside or just before a deletion (or skipped region) in the read, this function
+ * will return the last read base before the deletion (or skipped region). This function returns a
+ * Pair(int readCoord, boolean fallsInsideOrJustBeforeDeletionOrSkippedRegion) so you can choose which readCoordinate to use when faced with
+ * a deletion (or skipped region).
+ *
+ * SUGGESTION: Use getReadCoordinateForReferenceCoordinate(GATKSAMRecord, int, ClippingTail) instead to get a
+ * pre-processed result according to normal clipping needs. Or you can use this function and tailor the
+ * behavior to your needs.
+ *
+ * @param read
+ * @param refCoord the requested reference coordinate
+ * @return the read coordinate corresponding to the requested reference coordinate. (see warning!)
+ */
+ @Requires({"refCoord >= read.getSoftStart()", "refCoord <= read.getSoftEnd()"})
+ @Ensures({"result.getFirst() >= 0", "result.getFirst() < read.getReadLength()"})
+ //TODO since we do not have contracts any more, should we check for the requirements in the method code?
+ public static Pair<Integer, Boolean> getReadCoordinateForReferenceCoordinate(GATKSAMRecord read, int refCoord) {
+ return getReadCoordinateForReferenceCoordinate(read.getSoftStart(), read.getCigar(), refCoord, false);
+ }
+
+ public static Pair<Integer, Boolean> getReadCoordinateForReferenceCoordinate(final int alignmentStart, final Cigar cigar, final int refCoord, final boolean allowGoalNotReached) {
+ int readBases = 0;
+ int refBases = 0;
+ boolean fallsInsideDeletionOrSkippedRegion = false;
+ boolean endJustBeforeDeletionOrSkippedRegion = false;
+ boolean fallsInsideOrJustBeforeDeletionOrSkippedRegion = false;
+
+ final int goal = refCoord - alignmentStart; // The goal is to move this many reference bases
+ if (goal < 0) {
+ if (allowGoalNotReached) {
+ return new Pair<Integer, Boolean>(CLIPPING_GOAL_NOT_REACHED, false);
+ } else {
+ throw new ReviewedGATKException("Somehow the requested coordinate is not covered by the read. Too many deletions?");
+ }
+ }
+ boolean goalReached = refBases == goal;
+
+ Iterator<CigarElement> cigarElementIterator = cigar.getCigarElements().iterator();
+ while (!goalReached && cigarElementIterator.hasNext()) {
+ final CigarElement cigarElement = cigarElementIterator.next();
+ int shift = 0;
+
+ if (cigarElement.getOperator().consumesReferenceBases() || cigarElement.getOperator() == CigarOperator.SOFT_CLIP) {
+ if (refBases + cigarElement.getLength() < goal)
+ shift = cigarElement.getLength();
+ else
+ shift = goal - refBases;
+
+ refBases += shift;
+ }
+ goalReached = refBases == goal;
+
+ if (!goalReached && cigarElement.getOperator().consumesReadBases())
+ readBases += cigarElement.getLength();
+
+ if (goalReached) {
+ // Is this base's reference position within this cigar element? Or did we use it all?
+ final boolean endsWithinCigar = shift < cigarElement.getLength();
+
+ // If it isn't, we need to check the next one. There should *ALWAYS* be a next one
+ // since we checked if the goal coordinate is within the read length, so this is just a sanity check.
+ if (!endsWithinCigar && !cigarElementIterator.hasNext()) {
+ if (allowGoalNotReached) {
+ return new Pair<Integer, Boolean>(CLIPPING_GOAL_NOT_REACHED, false);
+ } else {
+ throw new ReviewedGATKException(String.format("Reference coordinate corresponds to a non-existent base in the read. This should never happen -- check read with alignment start: %s and cigar: %s", alignmentStart, cigar));
+ }
+ }
+
+ CigarElement nextCigarElement = null;
+
+ // if we end inside the current cigar element, we just have to check if it is a deletion (or skipped region)
+ if (endsWithinCigar)
+ fallsInsideDeletionOrSkippedRegion = (cigarElement.getOperator() == CigarOperator.DELETION || cigarElement.getOperator() == CigarOperator.SKIPPED_REGION) ;
+
+ // if we end outside the current cigar element, we need to check if the next element is an insertion, deletion or skipped region.
+ else {
+ nextCigarElement = cigarElementIterator.next();
+
+ // if it's an insertion, we need to clip the whole insertion before looking at the next element
+ if (nextCigarElement.getOperator() == CigarOperator.INSERTION) {
+ readBases += nextCigarElement.getLength();
+ if (!cigarElementIterator.hasNext()) {
+ if (allowGoalNotReached) {
+ return new Pair<Integer, Boolean>(CLIPPING_GOAL_NOT_REACHED, false);
+ } else {
+ throw new ReviewedGATKException(String.format("Reference coordinate corresponds to a non-existent base in the read. This should never happen -- check read with alignment start: %s and cigar: %s", alignmentStart, cigar));
+ }
+ }
+
+ nextCigarElement = cigarElementIterator.next();
+ }
+
+ // if it's a deletion (or skipped region), we will pass the information on to be handled downstream.
+ endJustBeforeDeletionOrSkippedRegion = (nextCigarElement.getOperator() == CigarOperator.DELETION || nextCigarElement.getOperator() == CigarOperator.SKIPPED_REGION);
+ }
+
+ fallsInsideOrJustBeforeDeletionOrSkippedRegion = endJustBeforeDeletionOrSkippedRegion || fallsInsideDeletionOrSkippedRegion;
+
+ // If we reached our goal outside a deletion (or skipped region), add the shift
+ if (!fallsInsideOrJustBeforeDeletionOrSkippedRegion && cigarElement.getOperator().consumesReadBases())
+ readBases += shift;
+
+ // If we reached our goal just before a deletion (or skipped region) we need
+ // to add the shift of the current cigar element but go back to it's last element to return the last
+ // base before the deletion (or skipped region) (see warning in function contracts)
+ else if (endJustBeforeDeletionOrSkippedRegion && cigarElement.getOperator().consumesReadBases())
+ readBases += shift - 1;
+
+ // If we reached our goal inside a deletion (or skipped region), or just between a deletion and a skipped region,
+ // then we must backtrack to the last base before the deletion (or skipped region)
+ else if (fallsInsideDeletionOrSkippedRegion ||
+ (endJustBeforeDeletionOrSkippedRegion && nextCigarElement.getOperator().equals(CigarOperator.N)) ||
+ (endJustBeforeDeletionOrSkippedRegion && nextCigarElement.getOperator().equals(CigarOperator.D)))
+ readBases--;
+ }
+ }
+
+ if (!goalReached) {
+ if (allowGoalNotReached) {
+ return new Pair<Integer, Boolean>(CLIPPING_GOAL_NOT_REACHED, false);
+ } else {
+ throw new ReviewedGATKException("Somehow the requested coordinate is not covered by the read. Alignment " + alignmentStart + " | " + cigar);
+ }
+ }
+
+ return new Pair<Integer, Boolean>(readBases, fallsInsideOrJustBeforeDeletionOrSkippedRegion);
+ }
+
+ /**
+ * Compares two SAMRecords only the basis on alignment start. Note that
+ * comparisons are performed ONLY on the basis of alignment start; any
+ * two SAM records with the same alignment start will be considered equal.
+ *
+ * Unmapped alignments will all be considered equal.
+ */
+
+ @Requires({"read1 != null", "read2 != null"})
+ public static int compareSAMRecords(GATKSAMRecord read1, GATKSAMRecord read2) {
+ AlignmentStartComparator comp = new AlignmentStartComparator();
+ return comp.compare(read1, read2);
+ }
+
+ /**
+ * Is a base inside a read?
+ *
+ * @param read the read to evaluate
+ * @param referenceCoordinate the reference coordinate of the base to test
+ * @return true if it is inside the read, false otherwise.
+ */
+ public static boolean isInsideRead(final GATKSAMRecord read, final int referenceCoordinate) {
+ return referenceCoordinate >= read.getAlignmentStart() && referenceCoordinate <= read.getAlignmentEnd();
+ }
+
+ /**
+ * Is this read all insertion?
+ *
+ * @param read
+ * @return whether or not the only element in the cigar string is an Insertion
+ */
+ public static boolean readIsEntirelyInsertion(GATKSAMRecord read) {
+ for (CigarElement cigarElement : read.getCigar().getCigarElements()) {
+ if (cigarElement.getOperator() != CigarOperator.INSERTION)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @see #readStartsWithInsertion(htsjdk.samtools.Cigar, boolean) with ignoreClipOps set to true
+ */
+ public static CigarElement readStartsWithInsertion(final Cigar cigarForRead) {
+ return readStartsWithInsertion(cigarForRead, true);
+ }
+
+ /**
+ * Checks if a read starts with an insertion.
+ *
+ * @param cigarForRead the CIGAR to evaluate
+ * @param ignoreSoftClipOps should we ignore S operators when evaluating whether an I operator is at the beginning? Note that H operators are always ignored.
+ * @return the element if it's a leading insertion or null otherwise
+ */
+ public static CigarElement readStartsWithInsertion(final Cigar cigarForRead, final boolean ignoreSoftClipOps) {
+ for ( final CigarElement cigarElement : cigarForRead.getCigarElements() ) {
+ if ( cigarElement.getOperator() == CigarOperator.INSERTION )
+ return cigarElement;
+
+ else if ( cigarElement.getOperator() != CigarOperator.HARD_CLIP && ( !ignoreSoftClipOps || cigarElement.getOperator() != CigarOperator.SOFT_CLIP) )
+ break;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the coverage distribution of a list of reads within the desired region.
+ *
+ * See getCoverageDistributionOfRead for information on how the coverage is calculated.
+ *
+ * @param list the list of reads covering the region
+ * @param startLocation the first reference coordinate of the region (inclusive)
+ * @param stopLocation the last reference coordinate of the region (inclusive)
+ * @return an array with the coverage of each position from startLocation to stopLocation
+ */
+ public static int [] getCoverageDistributionOfReads(List<GATKSAMRecord> list, int startLocation, int stopLocation) {
+ int [] totalCoverage = new int[stopLocation - startLocation + 1];
+
+ for (GATKSAMRecord read : list) {
+ int [] readCoverage = getCoverageDistributionOfRead(read, startLocation, stopLocation);
+ totalCoverage = MathUtils.addArrays(totalCoverage, readCoverage);
+ }
+
+ return totalCoverage;
+ }
+
+ /**
+ * Returns the coverage distribution of a single read within the desired region.
+ *
+ * Note: This function counts DELETIONS as coverage (since the main purpose is to downsample
+ * reads for variant regions, and deletions count as variants)
+ *
+ * @param read the read to get the coverage distribution of
+ * @param startLocation the first reference coordinate of the region (inclusive)
+ * @param stopLocation the last reference coordinate of the region (inclusive)
+ * @return an array with the coverage of each position from startLocation to stopLocation
+ */
+ public static int [] getCoverageDistributionOfRead(GATKSAMRecord read, int startLocation, int stopLocation) {
+ int [] coverage = new int[stopLocation - startLocation + 1];
+ int refLocation = read.getSoftStart();
+ for (CigarElement cigarElement : read.getCigar().getCigarElements()) {
+ switch (cigarElement.getOperator()) {
+ case S:
+ case M:
+ case EQ:
+ case N:
+ case X:
+ case D:
+ for (int i = 0; i < cigarElement.getLength(); i++) {
+ if (refLocation >= startLocation && refLocation <= stopLocation) {
+ coverage[refLocation - startLocation]++;
+ }
+ refLocation++;
+ }
+ break;
+
+ case P:
+ case I:
+ case H:
+ break;
+ }
+
+ if (refLocation > stopLocation)
+ break;
+ }
+ return coverage;
+ }
+
+ /**
+ * Makes association maps for the reads and loci coverage as described below :
+ *
+ * - First: locusToReadMap -- a HashMap that describes for each locus, which reads contribute to its coverage.
+ * Note: Locus is in reference coordinates.
+ * Example: Locus => {read1, read2, ..., readN}
+ *
+ * - Second: readToLocusMap -- a HashMap that describes for each read what loci it contributes to the coverage.
+ * Note: Locus is a boolean array, indexed from 0 (= startLocation) to N (= stopLocation), with value==true meaning it contributes to the coverage.
+ * Example: Read => {true, true, false, ... false}
+ *
+ * @param readList the list of reads to generate the association mappings
+ * @param startLocation the first reference coordinate of the region (inclusive)
+ * @param stopLocation the last reference coordinate of the region (inclusive)
+ * @return the two hashmaps described above
+ */
+ public static Pair<HashMap<Integer, HashSet<GATKSAMRecord>> , HashMap<GATKSAMRecord, Boolean[]>> getBothReadToLociMappings (List<GATKSAMRecord> readList, int startLocation, int stopLocation) {
+ int arraySize = stopLocation - startLocation + 1;
+
+ HashMap<Integer, HashSet<GATKSAMRecord>> locusToReadMap = new HashMap<Integer, HashSet<GATKSAMRecord>>(2*(stopLocation - startLocation + 1), 0.5f);
+ HashMap<GATKSAMRecord, Boolean[]> readToLocusMap = new HashMap<GATKSAMRecord, Boolean[]>(2*readList.size(), 0.5f);
+
+ for (int i = startLocation; i <= stopLocation; i++)
+ locusToReadMap.put(i, new HashSet<GATKSAMRecord>()); // Initialize the locusToRead map with empty lists
+
+ for (GATKSAMRecord read : readList) {
+ readToLocusMap.put(read, new Boolean[arraySize]); // Initialize the readToLocus map with empty arrays
+
+ int [] readCoverage = getCoverageDistributionOfRead(read, startLocation, stopLocation);
+
+ for (int i = 0; i < readCoverage.length; i++) {
+ int refLocation = i + startLocation;
+ if (readCoverage[i] > 0) {
+ // Update the hash for this locus
+ HashSet<GATKSAMRecord> readSet = locusToReadMap.get(refLocation);
+ readSet.add(read);
+
+ // Add this locus to the read hash
+ readToLocusMap.get(read)[refLocation - startLocation] = true;
+ }
+ else
+ // Update the boolean array with a 'no coverage' from this read to this locus
+ readToLocusMap.get(read)[refLocation-startLocation] = false;
+ }
+ }
+ return new Pair<HashMap<Integer, HashSet<GATKSAMRecord>>, HashMap<GATKSAMRecord, Boolean[]>>(locusToReadMap, readToLocusMap);
+ }
+
+ /**
+ * Create random read qualities
+ *
+ * @param length the length of the read
+ * @return an array with randomized base qualities between 0 and 50
+ */
+ public static byte[] createRandomReadQuals(int length) {
+ Random random = GenomeAnalysisEngine.getRandomGenerator();
+ byte[] quals = new byte[length];
+ for (int i = 0; i < length; i++)
+ quals[i] = (byte) random.nextInt(50);
+ return quals;
+ }
+
+ /**
+ * Create random read qualities
+ *
+ * @param length the length of the read
+ * @param allowNs whether or not to allow N's in the read
+ * @return an array with randomized bases (A-N) with equal probability
+ */
+ public static byte[] createRandomReadBases(int length, boolean allowNs) {
+ Random random = GenomeAnalysisEngine.getRandomGenerator();
+ int numberOfBases = allowNs ? 5 : 4;
+ byte[] bases = new byte[length];
+ for (int i = 0; i < length; i++) {
+ switch (random.nextInt(numberOfBases)) {
+ case 0:
+ bases[i] = 'A';
+ break;
+ case 1:
+ bases[i] = 'C';
+ break;
+ case 2:
+ bases[i] = 'G';
+ break;
+ case 3:
+ bases[i] = 'T';
+ break;
+ case 4:
+ bases[i] = 'N';
+ break;
+ default:
+ throw new ReviewedGATKException("Something went wrong, this is just impossible");
+ }
+ }
+ return bases;
+ }
+
+ public static GATKSAMRecord createRandomRead(int length) {
+ return createRandomRead(length, true);
+ }
+
+ public static GATKSAMRecord createRandomRead(int length, boolean allowNs) {
+ byte[] quals = ReadUtils.createRandomReadQuals(length);
+ byte[] bbases = ReadUtils.createRandomReadBases(length, allowNs);
+ return ArtificialSAMUtils.createArtificialRead(bbases, quals, bbases.length + "M");
+ }
+
+
+ public static String prettyPrintSequenceRecords ( SAMSequenceDictionary sequenceDictionary ) {
+ String[] sequenceRecordNames = new String[sequenceDictionary.size()];
+ int sequenceRecordIndex = 0;
+ for (SAMSequenceRecord sequenceRecord : sequenceDictionary.getSequences())
+ sequenceRecordNames[sequenceRecordIndex++] = sequenceRecord.getSequenceName();
+ return Arrays.deepToString(sequenceRecordNames);
+ }
+
+ /**
+ * Calculates the reference coordinate for a read coordinate
+ *
+ * @param read the read
+ * @param offset the base in the read (coordinate in the read)
+ * @return the reference coordinate correspondent to this base
+ */
+ public static long getReferenceCoordinateForReadCoordinate(GATKSAMRecord read, int offset) {
+ if (offset > read.getReadLength())
+ throw new ReviewedGATKException(String.format(OFFSET_OUT_OF_BOUNDS_EXCEPTION, offset, read.getReadLength()));
+
+ long location = read.getAlignmentStart();
+ Iterator<CigarElement> cigarElementIterator = read.getCigar().getCigarElements().iterator();
+ while (offset > 0 && cigarElementIterator.hasNext()) {
+ CigarElement cigarElement = cigarElementIterator.next();
+ long move = 0;
+ if (cigarElement.getOperator().consumesReferenceBases())
+ move = (long) Math.min(cigarElement.getLength(), offset);
+ location += move;
+ offset -= move;
+ }
+ if (offset > 0 && !cigarElementIterator.hasNext())
+ throw new ReviewedGATKException(OFFSET_NOT_ZERO_EXCEPTION);
+
+ return location;
+ }
+
+ /**
+ * Creates a map with each event in the read (cigar operator) and the read coordinate where it happened.
+ *
+ * Example:
+ * D -> 2, 34, 75
+ * I -> 55
+ * S -> 0, 101
+ * H -> 101
+ *
+ * @param read the read
+ * @return a map with the properties described above. See example
+ */
+ public static Map<CigarOperator, ArrayList<Integer>> getCigarOperatorForAllBases (GATKSAMRecord read) {
+ Map<CigarOperator, ArrayList<Integer>> events = new HashMap<CigarOperator, ArrayList<Integer>>();
+
+ int position = 0;
+ for (CigarElement cigarElement : read.getCigar().getCigarElements()) {
+ CigarOperator op = cigarElement.getOperator();
+ if (op.consumesReadBases()) {
+ ArrayList<Integer> list = events.get(op);
+ if (list == null) {
+ list = new ArrayList<Integer>();
+ events.put(op, list);
+ }
+ for (int i = position; i < cigarElement.getLength(); i++)
+ list.add(position++);
+ }
+ else {
+ ArrayList<Integer> list = events.get(op);
+ if (list == null) {
+ list = new ArrayList<Integer>();
+ events.put(op, list);
+ }
+ list.add(position);
+ }
+ }
+ return events;
+ }
+
+ /**
+ * Given a read, outputs the read bases in a string format
+ *
+ * @param read the read
+ * @return a string representation of the read bases
+ */
+ public static String convertReadBasesToString(GATKSAMRecord read) {
+ String bases = "";
+ for (byte b : read.getReadBases()) {
+ bases += (char) b;
+ }
+ return bases.toUpperCase();
+ }
+
+ /**
+ * Given a read, outputs the base qualities in a string format
+ *
+ * @param quals the read qualities
+ * @return a string representation of the base qualities
+ */
+ public static String convertReadQualToString(byte[] quals) {
+ String result = "";
+ for (byte b : quals) {
+ result += (char) (33 + b);
+ }
+ return result;
+ }
+
+ /**
+ * Given a read, outputs the base qualities in a string format
+ *
+ * @param read the read
+ * @return a string representation of the base qualities
+ */
+ public static String convertReadQualToString(GATKSAMRecord read) {
+ return convertReadQualToString(read.getBaseQualities());
+ }
+
+ /**
+ * Returns the reverse complement of the read bases
+ *
+ * @param bases the read bases
+ * @return the reverse complement of the read bases
+ */
+ public static String getBasesReverseComplement(byte[] bases) {
+ String reverse = "";
+ for (int i = bases.length-1; i >=0; i--) {
+ reverse += (char) BaseUtils.getComplement(bases[i]);
+ }
+ return reverse;
+ }
+
+ /**
+ * Returns the reverse complement of the read bases
+ *
+ * @param read the read
+ * @return the reverse complement of the read bases
+ */
+ public static String getBasesReverseComplement(GATKSAMRecord read) {
+ return getBasesReverseComplement(read.getReadBases());
+ }
+
+ /**
+ * Calculate the maximum read length from the given list of reads.
+ * @param reads list of reads
+ * @return non-negative integer
+ */
+ @Ensures({"result >= 0"})
+ public static int getMaxReadLength( final List<GATKSAMRecord> reads ) {
+ if( reads == null ) { throw new IllegalArgumentException("Attempting to check a null list of reads."); }
+
+ int maxReadLength = 0;
+ for( final GATKSAMRecord read : reads ) {
+ maxReadLength = Math.max(maxReadLength, read.getReadLength());
+ }
+ return maxReadLength;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/SAMFileReaderBuilder.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/SAMFileReaderBuilder.java
new file mode 100644
index 0000000..2c5ea5f
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/SAMFileReaderBuilder.java
@@ -0,0 +1,84 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.ValidationStringency;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+
+/**
+ * Allows the user to steadily accumulate information about what
+ * components go into a SAM file writer, ultimately using this
+ * information to create a SAM file writer on demand.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class SAMFileReaderBuilder {
+ /**
+ * To which file should output be written?
+ */
+ private File samFile = null;
+
+ /**
+ * What compression level should be used when building this file?
+ */
+ private ValidationStringency validationStringency = null;
+
+ /**
+ * Sets the handle of the sam file to which data should be written.
+ * @param samFile The SAM file into which data should flow.
+ */
+ public void setSAMFile( File samFile ) {
+ this.samFile = samFile;
+ }
+
+ /**
+ * Sets the validation stringency to apply when reading this sam file.
+ * @param validationStringency Stringency to apply. Must not be null.
+ */
+ public void setValidationStringency( ValidationStringency validationStringency ) {
+ this.validationStringency = validationStringency;
+ }
+
+ /**
+ * Create the SAM writer, given the constituent parts accrued.
+ * @return Newly minted SAM file writer.
+ */
+ public SAMFileReader build() {
+ if( samFile == null )
+ throw new ReviewedGATKException( "Filename for output sam file must be supplied.");
+ if( validationStringency == null )
+ throw new ReviewedGATKException( "Header for output sam file must be supplied.");
+
+ SAMFileReader reader = new SAMFileReader( samFile );
+ reader.setValidationStringency( validationStringency );
+
+ return reader;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/SimplifyingSAMFileWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/SimplifyingSAMFileWriter.java
new file mode 100644
index 0000000..4214619
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/SimplifyingSAMFileWriter.java
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMFileWriter;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.ProgressLoggerInterface;
+
+/**
+ * XXX
+ */
+public class SimplifyingSAMFileWriter implements SAMFileWriter {
+ final SAMFileWriter dest;
+
+ public SimplifyingSAMFileWriter(final SAMFileWriter finalDestination) {
+ this.dest = finalDestination;
+ }
+
+ public void addAlignment( SAMRecord read ) {
+ if ( keepRead(read) ) {
+ dest.addAlignment(simplifyRead(read));
+
+ }
+ }
+
+ /**
+ * Retrieves the header to use when creating the new SAM file.
+ * @return header to use when creating the new SAM file.
+ */
+ public SAMFileHeader getFileHeader() {
+ return dest.getFileHeader();
+ }
+
+ /**
+ * @{inheritDoc}
+ */
+ public void close() {
+ dest.close();
+ }
+
+
+ public static final boolean keepRead(SAMRecord read) {
+ return ! excludeRead(read);
+ }
+
+ public static final boolean excludeRead(SAMRecord read) {
+ return read.getReadUnmappedFlag() || read.getReadFailsVendorQualityCheckFlag() || read.getDuplicateReadFlag() || read.getNotPrimaryAlignmentFlag();
+ }
+
+ public static final SAMRecord simplifyRead(SAMRecord read) {
+ // the only attribute we keep is the RG
+ Object rg = read.getAttribute("RG");
+ read.clearAttributes();
+ read.setAttribute("RG", rg);
+ return read;
+ }
+
+ @Override
+ public void setProgressLogger(final ProgressLoggerInterface logger) {
+ dest.setProgressLogger(logger);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/package-info.java
new file mode 100644
index 0000000..ee2bcec
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/sam/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/GlobalEdgeGreedySWPairwiseAlignment.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/GlobalEdgeGreedySWPairwiseAlignment.java
new file mode 100644
index 0000000..666ca8b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/GlobalEdgeGreedySWPairwiseAlignment.java
@@ -0,0 +1,208 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.smithwaterman;
+
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.sam.AlignmentUtils;
+
+import java.util.*;
+
+/**
+ * Pairwise discrete Smith-Waterman alignment with an edge greedy implementation
+ *
+ * ************************************************************************
+ * **** IMPORTANT NOTE: ****
+ * **** This class assumes that all bytes come from UPPERCASED chars! ****
+ * ************************************************************************
+ *
+ * User: ebanks
+ */
+public final class GlobalEdgeGreedySWPairwiseAlignment extends SWPairwiseAlignment {
+
+ private final static boolean DEBUG_MODE = false;
+
+ /**
+ * Create a new greedy SW pairwise aligner
+ *
+ * @param reference the reference sequence we want to align
+ * @param alternate the alternate sequence we want to align
+ * @param parameters the SW parameters to use
+ */
+ public GlobalEdgeGreedySWPairwiseAlignment(final byte[] reference, final byte[] alternate, final Parameters parameters) {
+ super(reference, alternate, parameters);
+ }
+
+ /**
+ * Create a new SW pairwise aligner
+ *
+ * After creating the object the two sequences are aligned with an internal call to align(seq1, seq2)
+ *
+ * @param reference the reference sequence we want to align
+ * @param alternate the alternate sequence we want to align
+ * @param namedParameters the named parameter set to get our parameters from
+ */
+ public GlobalEdgeGreedySWPairwiseAlignment(final byte[] reference, final byte[] alternate, final SWParameterSet namedParameters) {
+ this(reference, alternate, namedParameters.parameters);
+ }
+
+ /**
+ * @see #GlobalEdgeGreedySWPairwiseAlignment(byte[], byte[], SWParameterSet) with original default parameters
+ */
+ public GlobalEdgeGreedySWPairwiseAlignment(byte[] reference, byte[] alternate) {
+ this(reference, alternate, SWParameterSet.ORIGINAL_DEFAULT);
+ }
+
+ /**
+ * Aligns the alternate sequence to the reference sequence
+ *
+ * @param reference ref sequence
+ * @param alternate alt sequence
+ */
+ @Override
+ protected void align(final byte[] reference, final byte[] alternate) {
+ if ( reference == null || reference.length == 0 )
+ throw new IllegalArgumentException("Non-null, non-empty reference sequences are required for the Smith-Waterman calculation");
+ if ( alternate == null || alternate.length == 0 )
+ throw new IllegalArgumentException("Non-null, non-empty alternate sequences are required for the Smith-Waterman calculation");
+
+ final int forwardEdgeMatch = Utils.longestCommonPrefix(reference, alternate, Integer.MAX_VALUE);
+
+ // edge case: one sequence is a strict prefix of the other
+ if ( forwardEdgeMatch == reference.length || forwardEdgeMatch == alternate.length ) {
+ alignmentResult = new SWPairwiseAlignmentResult(makeCigarForStrictPrefixAndSuffix(reference, alternate, forwardEdgeMatch, 0), 0);
+ return;
+ }
+
+ int reverseEdgeMatch = Utils.longestCommonSuffix(reference, alternate, Integer.MAX_VALUE);
+
+ // edge case: one sequence is a strict suffix of the other
+ if ( reverseEdgeMatch == reference.length || reverseEdgeMatch == alternate.length ) {
+ alignmentResult = new SWPairwiseAlignmentResult(makeCigarForStrictPrefixAndSuffix(reference, alternate, 0, reverseEdgeMatch), 0);
+ return;
+ }
+
+ final int sizeOfRefToAlign = reference.length - forwardEdgeMatch - reverseEdgeMatch;
+ final int sizeOfAltToAlign = alternate.length - forwardEdgeMatch - reverseEdgeMatch;
+
+ // edge case: one sequence is a strict subset of the other accounting for both prefix and suffix
+ final int minSizeToAlign = Math.min(sizeOfRefToAlign, sizeOfAltToAlign);
+ if ( minSizeToAlign < 0 )
+ reverseEdgeMatch += minSizeToAlign;
+ if ( sizeOfRefToAlign <= 0 || sizeOfAltToAlign <= 0 ) {
+ alignmentResult = new SWPairwiseAlignmentResult(makeCigarForStrictPrefixAndSuffix(reference, alternate, forwardEdgeMatch, reverseEdgeMatch), 0);
+ return;
+ }
+
+ final byte[] refToAlign = Utils.trimArray(reference, forwardEdgeMatch, reverseEdgeMatch);
+ final byte[] altToAlign = Utils.trimArray(alternate, forwardEdgeMatch, reverseEdgeMatch);
+
+ final int[][] sw = new int[(sizeOfRefToAlign+1)][(sizeOfAltToAlign+1)];
+ if ( keepScoringMatrix ) SW = sw;
+ final int[][] btrack = new int[(sizeOfRefToAlign+1)][(sizeOfAltToAlign+1)];
+
+ calculateMatrix(refToAlign, altToAlign, sw, btrack, OVERHANG_STRATEGY.INDEL);
+
+ if ( DEBUG_MODE ) {
+ System.out.println(new String(refToAlign) + " vs. " + new String(altToAlign));
+ debugMatrix(sw);
+ System.out.println("----");
+ debugMatrix(btrack);
+ System.out.println();
+ }
+
+ alignmentResult = calculateCigar(forwardEdgeMatch, reverseEdgeMatch, sw, btrack);
+ }
+
+
+ private void debugMatrix(final int[][] matrix) {
+ for ( int i = 0; i < matrix.length; i++ ) {
+ int [] cur = matrix[i];
+ for ( int j = 0; j < cur.length; j++ )
+ System.out.print(cur[j] + " ");
+ System.out.println();
+ }
+ }
+
+ /**
+ * Creates a CIGAR for the case where the prefix/suffix match combination encompasses an entire sequence
+ *
+ * @param reference the reference sequence
+ * @param alternate the alternate sequence
+ * @param matchingPrefix the prefix match size
+ * @param matchingSuffix the suffix match size
+ * @return non-null CIGAR
+ */
+ private Cigar makeCigarForStrictPrefixAndSuffix(final byte[] reference, final byte[] alternate, final int matchingPrefix, final int matchingSuffix) {
+
+ final List<CigarElement> result = new ArrayList<CigarElement>();
+
+ // edge case: no D or I element
+ if ( reference.length == alternate.length ) {
+ result.add(makeElement(State.MATCH, matchingPrefix + matchingSuffix));
+ } else {
+ // add the first M element
+ if ( matchingPrefix > 0 )
+ result.add(makeElement(State.MATCH, matchingPrefix));
+
+ // add the D or I element
+ if ( alternate.length > reference.length )
+ result.add(makeElement(State.INSERTION, alternate.length - reference.length));
+ else // if ( reference.length > alternate.length )
+ result.add(makeElement(State.DELETION, reference.length - alternate.length));
+
+ // add the last M element
+ if ( matchingSuffix > 0 )
+ result.add(makeElement(State.MATCH, matchingSuffix));
+ }
+
+ return new Cigar(result);
+ }
+
+ /**
+ * Calculates the CIGAR for the alignment from the back track matrix
+ *
+ * @param matchingPrefix the prefix match size
+ * @param matchingSuffix the suffix match size
+ * @param sw the Smith-Waterman matrix to use
+ * @param btrack the back track matrix to use
+ * @return non-null SWPairwiseAlignmentResult object
+ */
+ protected SWPairwiseAlignmentResult calculateCigar(final int matchingPrefix, final int matchingSuffix,
+ final int[][] sw, final int[][] btrack) {
+
+ final SWPairwiseAlignmentResult SW_result = calculateCigar(sw, btrack, OVERHANG_STRATEGY.INDEL);
+
+ final LinkedList<CigarElement> lce = new LinkedList<CigarElement>(SW_result.cigar.getCigarElements());
+ if ( matchingPrefix > 0 )
+ lce.addFirst(makeElement(State.MATCH, matchingPrefix));
+ if ( matchingSuffix > 0 )
+ lce.addLast(makeElement(State.MATCH, matchingSuffix));
+
+ return new SWPairwiseAlignmentResult(AlignmentUtils.consolidateCigar(new Cigar(lce)), 0);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/Parameters.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/Parameters.java
new file mode 100644
index 0000000..46cb8be
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/Parameters.java
@@ -0,0 +1,62 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.smithwaterman;
+
+/**
+ * Holds the core Smith-Waterman alignment parameters of
+ *
+ * match value, and mismatch, gap open and gap extension penalties
+ *
+ * User: depristo
+ * Date: 4/11/13
+ * Time: 12:03 PM
+ */
+public final class Parameters {
+ public final int w_match;
+ public final int w_mismatch;
+ public final int w_open;
+ public final int w_extend;
+
+ /**
+ * Create a new set of SW parameters
+ * @param w_match the match score
+ * @param w_mismatch the mismatch penalty
+ * @param w_open the gap open penalty
+ * @param w_extend the gap extension penalty
+
+ */
+ public Parameters(final int w_match, final int w_mismatch, final int w_open, final int w_extend) {
+ if ( w_mismatch > 0 ) throw new IllegalArgumentException("w_mismatch must be <= 0 but got " + w_mismatch);
+ if ( w_open> 0 ) throw new IllegalArgumentException("w_open must be <= 0 but got " + w_open);
+ if ( w_extend> 0 ) throw new IllegalArgumentException("w_extend must be <= 0 but got " + w_extend);
+
+ this.w_match = w_match;
+ this.w_mismatch = w_mismatch;
+ this.w_open = w_open;
+ this.w_extend = w_extend;
+ }
+
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SWPairwiseAlignment.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SWPairwiseAlignment.java
new file mode 100644
index 0000000..aa38c06
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SWPairwiseAlignment.java
@@ -0,0 +1,599 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.smithwaterman;
+
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.broadinstitute.gatk.utils.sam.AlignmentUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Pairwise discrete smith-waterman alignment
+ *
+ * ************************************************************************
+ * **** IMPORTANT NOTE: ****
+ * **** This class assumes that all bytes come from UPPERCASED chars! ****
+ * ************************************************************************
+ *
+ * User: asivache
+ * Date: Mar 23, 2009
+ * Time: 1:54:54 PM
+ */
+public class SWPairwiseAlignment implements SmithWaterman {
+
+ protected SWPairwiseAlignmentResult alignmentResult;
+
+ protected final Parameters parameters;
+
+ /**
+ * The state of a trace step through the matrix
+ */
+ protected enum State {
+ MATCH,
+ INSERTION,
+ DELETION,
+ CLIP
+ }
+
+ /**
+ * What strategy should we use when the best path does not start/end at the corners of the matrix?
+ */
+ public enum OVERHANG_STRATEGY {
+ /*
+ * Add softclips for the overhangs
+ */
+ SOFTCLIP,
+
+ /*
+ * Treat the overhangs as proper insertions/deletions
+ */
+ INDEL,
+
+ /*
+ * Treat the overhangs as proper insertions/deletions for leading (but not trailing) overhangs.
+ * This is useful e.g. when we want to merge dangling tails in an assembly graph: because we don't
+ * expect the dangling tail to reach the end of the reference path we are okay ignoring trailing
+ * deletions - but leading indels are still very much relevant.
+ */
+ LEADING_INDEL,
+
+ /*
+ * Just ignore the overhangs
+ */
+ IGNORE
+ }
+
+ protected static boolean cutoff = false;
+
+ protected OVERHANG_STRATEGY overhang_strategy = OVERHANG_STRATEGY.SOFTCLIP;
+
+ /**
+ * The SW scoring matrix, stored for debugging purposes if keepScoringMatrix is true
+ */
+ protected int[][] SW = null;
+
+ /**
+ * Only for testing purposes in the SWPairwiseAlignmentMain function
+ * set to true to keep SW scoring matrix after align call
+ */
+ protected static boolean keepScoringMatrix = false;
+
+ /**
+ * Create a new SW pairwise aligner.
+ *
+ * @deprecated in favor of constructors using the Parameter or ParameterSet class
+ */
+ @Deprecated
+ public SWPairwiseAlignment(byte[] seq1, byte[] seq2, int match, int mismatch, int open, int extend ) {
+ this(seq1, seq2, new Parameters(match, mismatch, open, extend));
+ }
+
+ /**
+ * Create a new SW pairwise aligner
+ *
+ * After creating the object the two sequences are aligned with an internal call to align(seq1, seq2)
+ *
+ * @param seq1 the first sequence we want to align
+ * @param seq2 the second sequence we want to align
+ * @param parameters the SW parameters to use
+ */
+ public SWPairwiseAlignment(byte[] seq1, byte[] seq2, Parameters parameters) {
+ this(parameters);
+ align(seq1,seq2);
+ }
+
+ /**
+ * Create a new SW pairwise aligner
+ *
+ * After creating the object the two sequences are aligned with an internal call to align(seq1, seq2)
+ *
+ * @param seq1 the first sequence we want to align
+ * @param seq2 the second sequence we want to align
+ * @param parameters the SW parameters to use
+ * @param strategy the overhang strategy to use
+ */
+ public SWPairwiseAlignment(final byte[] seq1, final byte[] seq2, final SWParameterSet parameters, final OVERHANG_STRATEGY strategy) {
+ this(parameters.parameters);
+ overhang_strategy = strategy;
+ align(seq1, seq2);
+ }
+
+ /**
+ * Create a new SW pairwise aligner, without actually doing any alignment yet
+ *
+ * @param parameters the SW parameters to use
+ */
+ protected SWPairwiseAlignment(final Parameters parameters) {
+ this.parameters = parameters;
+ }
+
+ /**
+ * Create a new SW pairwise aligner
+ *
+ * After creating the object the two sequences are aligned with an internal call to align(seq1, seq2)
+ *
+ * @param seq1 the first sequence we want to align
+ * @param seq2 the second sequence we want to align
+ * @param namedParameters the named parameter set to get our parameters from
+ */
+ public SWPairwiseAlignment(byte[] seq1, byte[] seq2, SWParameterSet namedParameters) {
+ this(seq1, seq2, namedParameters.parameters);
+ }
+
+ public SWPairwiseAlignment(byte[] seq1, byte[] seq2) {
+ this(seq1,seq2,SWParameterSet.ORIGINAL_DEFAULT);
+ }
+
+ @Override
+ public Cigar getCigar() { return alignmentResult.cigar ; }
+
+ @Override
+ public int getAlignmentStart2wrt1() { return alignmentResult.alignment_offset; }
+
+ /**
+ * Aligns the alternate sequence to the reference sequence
+ *
+ * @param reference ref sequence
+ * @param alternate alt sequence
+ */
+ protected void align(final byte[] reference, final byte[] alternate) {
+ if ( reference == null || reference.length == 0 || alternate == null || alternate.length == 0 )
+ throw new IllegalArgumentException("Non-null, non-empty sequences are required for the Smith-Waterman calculation");
+
+ final int n = reference.length+1;
+ final int m = alternate.length+1;
+ int[][] sw = new int[n][m];
+ if ( keepScoringMatrix ) SW = sw;
+ int[][] btrack=new int[n][m];
+
+ calculateMatrix(reference, alternate, sw, btrack);
+ alignmentResult = calculateCigar(sw, btrack, overhang_strategy); // length of the segment (continuous matches, insertions or deletions)
+ }
+
+ /**
+ * Calculates the SW matrices for the given sequences
+ *
+ * @param reference ref sequence
+ * @param alternate alt sequence
+ * @param sw the Smith-Waterman matrix to populate
+ * @param btrack the back track matrix to populate
+ */
+ protected void calculateMatrix(final byte[] reference, final byte[] alternate, final int[][] sw, final int[][] btrack) {
+ calculateMatrix(reference, alternate, sw, btrack, overhang_strategy);
+ }
+
+ /**
+ * Calculates the SW matrices for the given sequences
+ *
+ * @param reference ref sequence
+ * @param alternate alt sequence
+ * @param sw the Smith-Waterman matrix to populate
+ * @param btrack the back track matrix to populate
+ * @param overhang_strategy the strategy to use for dealing with overhangs
+ */
+ protected void calculateMatrix(final byte[] reference, final byte[] alternate, final int[][] sw, final int[][] btrack, final OVERHANG_STRATEGY overhang_strategy) {
+ if ( reference.length == 0 || alternate.length == 0 )
+ throw new IllegalArgumentException("Non-null, non-empty sequences are required for the Smith-Waterman calculation");
+
+ final int ncol = sw[0].length;//alternate.length+1; formerly m
+ final int nrow = sw.length;// reference.length+1; formerly n
+
+ final int MATRIX_MIN_CUTOFF; // never let matrix elements drop below this cutoff
+ if ( cutoff ) MATRIX_MIN_CUTOFF = 0;
+ else MATRIX_MIN_CUTOFF = (int) -1e8;
+
+ int lowInitValue=Integer.MIN_VALUE/2;
+ final int[] best_gap_v = new int[ncol+1];
+ Arrays.fill(best_gap_v, lowInitValue);
+ final int[] gap_size_v = new int[ncol+1];
+ final int[] best_gap_h = new int[nrow+1];
+ Arrays.fill(best_gap_h,lowInitValue);
+ final int[] gap_size_h = new int[nrow+1];
+
+ // we need to initialize the SW matrix with gap penalties if we want to keep track of indels at the edges of alignments
+ if ( overhang_strategy == OVERHANG_STRATEGY.INDEL || overhang_strategy == OVERHANG_STRATEGY.LEADING_INDEL ) {
+ // initialize the first row
+ int[] topRow=sw[0];
+ topRow[1]=parameters.w_open;
+ int currentValue = parameters.w_open;
+ for ( int i = 2; i < topRow.length; i++ ) {
+ currentValue += parameters.w_extend;
+ topRow[i]=currentValue;
+ }
+ // initialize the first column
+ sw[1][0]=parameters.w_open;
+ currentValue = parameters.w_open;
+ for ( int i = 2; i < sw.length; i++ ) {
+ currentValue += parameters.w_extend;
+ sw[i][0]=currentValue;
+ }
+ }
+ // build smith-waterman matrix and keep backtrack info:
+ int[] curRow=sw[0];
+ for ( int i = 1; i <sw.length ; i++ ) {
+ final byte a_base = reference[i-1]; // letter in a at the current pos
+ final int[] lastRow=curRow;
+ curRow=sw[i];
+ final int[] curBackTrackRow=btrack[i];
+ for ( int j = 1; j < curRow.length; j++) {
+ final byte b_base = alternate[j-1]; // letter in b at the current pos
+ // in other words, step_diag = sw[i-1][j-1] + wd(a_base,b_base);
+ final int step_diag = lastRow[j-1] + wd(a_base,b_base);
+
+ // optimized "traversal" of all the matrix cells above the current one (i.e. traversing
+ // all 'step down' events that would end in the current cell. The optimized code
+ // does exactly the same thing as the commented out loop below. IMPORTANT:
+ // the optimization works ONLY for linear w(k)=wopen+(k-1)*wextend!!!!
+
+ // if a gap (length 1) was just opened above, this is the cost of arriving to the current cell:
+ int prev_gap = lastRow[j]+parameters.w_open;
+ best_gap_v[j] += parameters.w_extend; // for the gaps that were already opened earlier, extending them by 1 costs w_extend
+ if ( prev_gap > best_gap_v[j] ) {
+ // opening a gap just before the current cell results in better score than extending by one
+ // the best previously opened gap. This will hold for ALL cells below: since any gap
+ // once opened always costs w_extend to extend by another base, we will always get a better score
+ // by arriving to any cell below from the gap we just opened (prev_gap) rather than from the previous best gap
+ best_gap_v[j] = prev_gap;
+ gap_size_v[j] = 1; // remember that the best step-down gap from above has length 1 (we just opened it)
+ } else {
+ // previous best gap is still the best, even after extension by another base, so we just record that extension:
+ gap_size_v[j]++;
+ }
+
+ final int step_down = best_gap_v[j] ;
+ final int kd = gap_size_v[j];
+
+ // optimized "traversal" of all the matrix cells to the left of the current one (i.e. traversing
+ // all 'step right' events that would end in the current cell. The optimized code
+ // does exactly the same thing as the commented out loop below. IMPORTANT:
+ // the optimization works ONLY for linear w(k)=wopen+(k-1)*wextend!!!!
+
+ prev_gap =curRow[j-1] + parameters.w_open; // what would it cost us to open length 1 gap just to the left from current cell
+ best_gap_h[i] += parameters.w_extend; // previous best gap would cost us that much if extended by another base
+ if ( prev_gap > best_gap_h[i] ) {
+ // newly opened gap is better (score-wise) than any previous gap with the same row index i; since
+ // gap penalty is linear with k, this new gap location is going to remain better than any previous ones
+ best_gap_h[i] = prev_gap;
+ gap_size_h[i] = 1;
+ } else {
+ gap_size_h[i]++;
+ }
+
+ final int step_right = best_gap_h[i];
+ final int ki = gap_size_h[i];
+
+ //priority here will be step diagonal, step right, step down
+ final boolean diagHighestOrEqual = (step_diag >= step_down)
+ && (step_diag >= step_right);
+
+ if ( diagHighestOrEqual ) {
+ curRow[j]=Math.max(MATRIX_MIN_CUTOFF,step_diag);
+ curBackTrackRow[j]=0;
+ }
+ else if(step_right>=step_down) { //moving right is the highest
+ curRow[j]=Math.max(MATRIX_MIN_CUTOFF,step_right);
+ curBackTrackRow[j]=-ki; // negative = horizontal
+ }
+ else {
+ curRow[j]=Math.max(MATRIX_MIN_CUTOFF,step_down);
+ curBackTrackRow[j]= kd; // positive=vertical
+ }
+ }
+ }
+ }
+
+ /*
+ * Class to store the result of calculating the CIGAR from the back track matrix
+ */
+ protected final class SWPairwiseAlignmentResult {
+ public final Cigar cigar;
+ public final int alignment_offset;
+ public SWPairwiseAlignmentResult(final Cigar cigar, final int alignment_offset) {
+ this.cigar = cigar;
+ this.alignment_offset = alignment_offset;
+ }
+ }
+
+ /**
+ * Calculates the CIGAR for the alignment from the back track matrix
+ *
+ * @param sw the Smith-Waterman matrix to use
+ * @param btrack the back track matrix to use
+ * @param overhang_strategy the strategy to use for dealing with overhangs
+ * @return non-null SWPairwiseAlignmentResult object
+ */
+ protected SWPairwiseAlignmentResult calculateCigar(final int[][] sw, final int[][] btrack, final OVERHANG_STRATEGY overhang_strategy) {
+ // p holds the position we start backtracking from; we will be assembling a cigar in the backwards order
+ int p1 = 0, p2 = 0;
+
+ int refLength = sw.length-1;
+ int altLength = sw[0].length-1;
+
+ int maxscore = Integer.MIN_VALUE; // sw scores are allowed to be negative
+ int segment_length = 0; // length of the segment (continuous matches, insertions or deletions)
+
+ // if we want to consider overhangs as legitimate operators, then just start from the corner of the matrix
+ if ( overhang_strategy == OVERHANG_STRATEGY.INDEL ) {
+ p1 = refLength;
+ p2 = altLength;
+ } else {
+ // look for the largest score on the rightmost column. we use >= combined with the traversal direction
+ // to ensure that if two scores are equal, the one closer to diagonal gets picked
+ //Note: this is not technically smith-waterman, as by only looking for max values on the right we are
+ //excluding high scoring local alignments
+ p2=altLength;
+
+ for(int i=1;i<sw.length;i++) {
+ final int curScore = sw[i][altLength];
+ if (curScore >= maxscore ) {
+ p1 = i;
+ maxscore = curScore;
+ }
+ }
+ // now look for a larger score on the bottom-most row
+ if ( overhang_strategy != OVERHANG_STRATEGY.LEADING_INDEL ) {
+ final int[] bottomRow=sw[refLength];
+ for ( int j = 1 ; j < bottomRow.length; j++) {
+ int curScore=bottomRow[j];
+ // data_offset is the offset of [n][j]
+ if ( curScore > maxscore ||
+ (curScore == maxscore && Math.abs(refLength-j) < Math.abs(p1 - p2) ) ) {
+ p1 = refLength;
+ p2 = j ;
+ maxscore = curScore;
+ segment_length = altLength - j ; // end of sequence 2 is overhanging; we will just record it as 'M' segment
+ }
+ }
+ }
+ }
+ final List<CigarElement> lce = new ArrayList<CigarElement>(5);
+ if ( segment_length > 0 && overhang_strategy == OVERHANG_STRATEGY.SOFTCLIP ) {
+ lce.add(makeElement(State.CLIP, segment_length));
+ segment_length = 0;
+ }
+
+ // we will be placing all insertions and deletions into sequence b, so the states are named w/regard
+ // to that sequence
+
+ State state = State.MATCH;
+ do {
+ int btr = btrack[p1][p2];
+ State new_state;
+ int step_length = 1;
+ if ( btr > 0 ) {
+ new_state = State.DELETION;
+ step_length = btr;
+ } else if ( btr < 0 ) {
+ new_state = State.INSERTION;
+ step_length = (-btr);
+ } else new_state = State.MATCH; // and step_length =1, already set above
+
+ // move to next best location in the sw matrix:
+ switch( new_state ) {
+ case MATCH: p1--; p2--; break; // move back along the diag in the sw matrix
+ case INSERTION: p2 -= step_length; break; // move left
+ case DELETION: p1 -= step_length; break; // move up
+ }
+
+ // now let's see if the state actually changed:
+ if ( new_state == state ) segment_length+=step_length;
+ else {
+ // state changed, lets emit previous segment, whatever it was (Insertion Deletion, or (Mis)Match).
+ lce.add(makeElement(state, segment_length));
+ segment_length = step_length;
+ state = new_state;
+ }
+ // next condition is equivalent to while ( sw[p1][p2] != 0 ) (with modified p1 and/or p2:
+ } while ( p1 > 0 && p2 > 0 );
+
+ // post-process the last segment we are still keeping;
+ // NOTE: if reads "overhangs" the ref on the left (i.e. if p2>0) we are counting
+ // those extra bases sticking out of the ref into the first cigar element if DO_SOFTCLIP is false;
+ // otherwise they will be softclipped. For instance,
+ // if read length is 5 and alignment starts at offset -2 (i.e. read starts before the ref, and only
+ // last 3 bases of the read overlap with/align to the ref), the cigar will be still 5M if
+ // DO_SOFTCLIP is false or 2S3M if DO_SOFTCLIP is true.
+ // The consumers need to check for the alignment offset and deal with it properly.
+ final int alignment_offset;
+ if ( overhang_strategy == OVERHANG_STRATEGY.SOFTCLIP ) {
+ lce.add(makeElement(state, segment_length));
+ if ( p2 > 0 ) lce.add(makeElement(State.CLIP, p2));
+ alignment_offset = p1;
+ } else if ( overhang_strategy == OVERHANG_STRATEGY.IGNORE ) {
+ lce.add(makeElement(state, segment_length + p2));
+ alignment_offset = p1 - p2;
+ } else { // overhang_strategy == OVERHANG_STRATEGY.INDEL || overhang_strategy == OVERHANG_STRATEGY.LEADING_INDEL
+
+ // take care of the actual alignment
+ lce.add(makeElement(state, segment_length));
+
+ // take care of overhangs at the beginning of the alignment
+ if ( p1 > 0 )
+ lce.add(makeElement(State.DELETION, p1));
+ else if ( p2 > 0 )
+ lce.add(makeElement(State.INSERTION, p2));
+
+ alignment_offset = 0;
+ }
+
+ Collections.reverse(lce);
+ return new SWPairwiseAlignmentResult(AlignmentUtils.consolidateCigar(new Cigar(lce)), alignment_offset);
+ }
+
+ protected CigarElement makeElement(final State state, final int length) {
+ CigarOperator op = null;
+ switch (state) {
+ case MATCH: op = CigarOperator.M; break;
+ case INSERTION: op = CigarOperator.I; break;
+ case DELETION: op = CigarOperator.D; break;
+ case CLIP: op = CigarOperator.S; break;
+ }
+ return new CigarElement(length, op);
+ }
+
+
+ private int wd(final byte x, final byte y) {
+ return (x == y ? parameters.w_match : parameters.w_mismatch);
+ }
+
+ public void printAlignment(byte[] ref, byte[] read) {
+ printAlignment(ref,read,100);
+ }
+
+ public void printAlignment(byte[] ref, byte[] read, int width) {
+ StringBuilder bread = new StringBuilder();
+ StringBuilder bref = new StringBuilder();
+ StringBuilder match = new StringBuilder();
+
+ int i = 0;
+ int j = 0;
+
+ final int offset = getAlignmentStart2wrt1();
+
+ Cigar cigar = getCigar();
+
+ if ( overhang_strategy != OVERHANG_STRATEGY.SOFTCLIP ) {
+
+ // we need to go through all the hassle below only if we do not do softclipping;
+ // otherwise offset is never negative
+ if ( offset < 0 ) {
+ for ( ; j < (-offset) ; j++ ) {
+ bread.append((char)read[j]);
+ bref.append(' ');
+ match.append(' ');
+ }
+ // at negative offsets, our cigar's first element carries overhanging bases
+ // that we have just printed above. Tweak the first element to
+ // exclude those bases. Here we create a new list of cigar elements, so the original
+ // list/original cigar are unchanged (they are unmodifiable anyway!)
+
+ List<CigarElement> tweaked = new ArrayList<CigarElement>();
+ tweaked.addAll(cigar.getCigarElements());
+ tweaked.set(0,new CigarElement(cigar.getCigarElement(0).getLength()+offset,
+ cigar.getCigarElement(0).getOperator()));
+ cigar = new Cigar(tweaked);
+ }
+ }
+
+ if ( offset > 0 ) { // note: the way this implementation works, cigar will ever start from S *only* if read starts before the ref, i.e. offset = 0
+ for ( ; i < getAlignmentStart2wrt1() ; i++ ) {
+ bref.append((char)ref[i]);
+ bread.append(' ');
+ match.append(' ');
+ }
+ }
+
+ for ( CigarElement e : cigar.getCigarElements() ) {
+ switch (e.getOperator()) {
+ case M :
+ for ( int z = 0 ; z < e.getLength() ; z++, i++, j++ ) {
+ bref.append((i<ref.length)?(char)ref[i]:' ');
+ bread.append((j < read.length)?(char)read[j]:' ');
+ match.append( ( i<ref.length && j < read.length ) ? (ref[i] == read[j] ? '.':'*' ) : ' ' );
+ }
+ break;
+ case I :
+ for ( int z = 0 ; z < e.getLength(); z++, j++ ) {
+ bref.append('-');
+ bread.append((char)read[j]);
+ match.append('I');
+ }
+ break;
+ case S :
+ for ( int z = 0 ; z < e.getLength(); z++, j++ ) {
+ bref.append(' ');
+ bread.append((char)read[j]);
+ match.append('S');
+ }
+ break;
+ case D:
+ for ( int z = 0 ; z < e.getLength(); z++ , i++ ) {
+ bref.append((char)ref[i]);
+ bread.append('-');
+ match.append('D');
+ }
+ break;
+ default:
+ throw new GATKException("Unexpected Cigar element:" + e.getOperator());
+ }
+ }
+ for ( ; i < ref.length; i++ ) bref.append((char)ref[i]);
+ for ( ; j < read.length; j++ ) bread.append((char)read[j]);
+
+ int pos = 0 ;
+ int maxlength = Math.max(match.length(),Math.max(bread.length(),bref.length()));
+ while ( pos < maxlength ) {
+ print_cautiously(match,pos,width);
+ print_cautiously(bread,pos,width);
+ print_cautiously(bref,pos,width);
+ System.out.println();
+ pos += width;
+ }
+ }
+
+ /** String builder's substring is extremely stupid: instead of trimming and/or returning an empty
+ * string when one end/both ends of the interval are out of range, it crashes with an
+ * exception. This utility function simply prints the substring if the interval is within the index range
+ * or trims accordingly if it is not.
+ * @param s
+ * @param start
+ * @param width
+ */
+ private static void print_cautiously(StringBuilder s, int start, int width) {
+ if ( start >= s.length() ) {
+ System.out.println();
+ return;
+ }
+ int end = Math.min(start+width,s.length());
+ System.out.println(s.substring(start,end));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SWPairwiseAlignmentMain.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SWPairwiseAlignmentMain.java
new file mode 100644
index 0000000..3d2ddd1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SWPairwiseAlignmentMain.java
@@ -0,0 +1,221 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.smithwaterman;
+
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.collections.Pair;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Simple program to run SW performance test.
+ *
+ * // TODO -- should be replaced with Caliper before using again
+ *
+ * User: depristo
+ * Date: 2/28/13
+ * Time: 4:54 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class SWPairwiseAlignmentMain {
+ // BELOW: main() method for testing; old implementations of the core methods are commented out below;
+// uncomment everything through the end of the file if benchmarking of new vs old implementations is needed.
+
+ public static void main(String argv[]) {
+// String ref="CACGAGCATATGTGTACATGAATTTGTATTGCACATGTGTTTAATGCGAACACGTGTCATGTGTATGTGTTCACATGCATGTGTGTCT";
+// String read = "GCATATGTTTACATGAATTTGTATTGCACATGTGTTTAATGCGAACACGTGTCATGTGTGTGTTCACATGCATGTG";
+
+ String ref = null;
+ String read = null;
+
+ Map<String,List<String>> args = processArgs(argv);
+
+ List<String> l = args.get("SEQ");
+ args.remove("SEQ");
+ if ( l == null ) {
+ System.err.println("SEQ argument is missing. Two input sequences must be provided");
+ System.exit(1);
+ }
+ if ( l.size() != 2 ) {
+ System.err.println("Two input sequences (SEQ arguments) must be provided. Found "+l.size()+" instead");
+ System.exit(1);
+ }
+
+ ref = l.get(0);
+ read = l.get(1);
+
+ Double m = extractSingleDoubleArg("MATCH",args);
+ Double mm = extractSingleDoubleArg("MISMATCH",args);
+ Double open = extractSingleDoubleArg("OPEN",args);
+ Double ext = extractSingleDoubleArg("EXTEND",args);
+
+ Boolean reverse = extractSingleBooleanArg("REVERSE",args);
+ if ( reverse != null && reverse.booleanValue() == true ) {
+ ref = Utils.reverse(ref);
+ read = Utils.reverse(read);
+ }
+
+ Boolean print_mat = extractSingleBooleanArg("PRINT_MATRIX",args);
+ Boolean cut = extractSingleBooleanArg("CUTOFF",args);
+ if ( cut != null ) SWPairwiseAlignment.cutoff = cut;
+
+ if ( args.size() != 0 ) {
+ System.err.println("Unknown argument on the command line: "+args.keySet().iterator().next());
+ System.exit(1);
+ }
+
+ final int w_match, w_mismatch, w_open, w_extend;
+
+ w_match = (m == null ? 30 : m.intValue());
+ w_mismatch = (mm == null ? -10 : mm.intValue());
+ w_open = (open == null ? -10 : open.intValue());
+ w_extend = (ext == null ? -2 : ext.intValue());
+
+
+ SWPairwiseAlignment.keepScoringMatrix = true;
+ SWPairwiseAlignment a = new SWPairwiseAlignment(ref.getBytes(),read.getBytes(),w_match,w_mismatch,w_open,w_extend);
+
+ System.out.println("start="+a.getAlignmentStart2wrt1()+", cigar="+a.getCigar()+
+ " length1="+ref.length()+" length2="+read.length());
+
+
+ System.out.println();
+ a.printAlignment(ref.getBytes(),read.getBytes());
+
+ System.out.println();
+ if ( print_mat != null && print_mat == true ) {
+ print(a.SW,ref.getBytes(),read.getBytes());
+ }
+ }
+
+ private static void print(final int[][] s, final byte[] a, final byte[] b) {
+ int n = a.length+1;
+ int m = b.length+1;
+ System.out.print(" ");
+ for ( int j = 1 ; j < m ; j++) System.out.printf(" %5c",(char)b[j-1]) ;
+ System.out.println();
+
+ for ( int i = 0 ; i < n ; i++) {
+ if ( i > 0 ) System.out.print((char)a[i-1]);
+ else System.out.print(' ');
+ System.out.print(" ");
+ for ( int j = 0; j < m ; j++ ) {
+ System.out.printf(" %5.1f",s[i][j]);
+ }
+ System.out.println();
+ }
+ }
+
+
+ static Pair<String,Integer> getArg(String prefix, String argv[], int i) {
+ String arg = null;
+ if ( argv[i].startsWith(prefix) ) {
+ arg = argv[i].substring(prefix.length());
+ if( arg.length() == 0 ) {
+ i++;
+ if ( i < argv.length ) arg = argv[i];
+ else {
+ System.err.println("No value found after " + prefix + " argument tag");
+ System.exit(1);
+ }
+ }
+ i++;
+ }
+ return new Pair<String,Integer>(arg,i);
+ }
+
+ static Map<String,List<String>> processArgs(String argv[]) {
+ Map<String,List<String>> args = new HashMap<String,List<String>>();
+
+ for ( int i = 0; i < argv.length ; i++ ) {
+ String arg = argv[i];
+ int pos = arg.indexOf('=');
+ if ( pos < 0 ) {
+ System.err.println("Argument "+arg+" is not of the form <ARG>=<VAL>");
+ System.exit(1);
+ }
+ String val = arg.substring(pos+1);
+ if ( val.length() == 0 ) {
+ // there was a space between '=' and the value
+ i++;
+ if ( i < argv.length ) val = argv[i];
+ else {
+ System.err.println("No value found after " + arg + " argument tag");
+ System.exit(1);
+ }
+ }
+ arg = arg.substring(0,pos);
+
+ List<String> l = args.get(arg);
+ if ( l == null ) {
+ l = new ArrayList<String>();
+ args.put(arg,l);
+ }
+ l.add(val);
+ }
+ return args;
+ }
+
+ static Double extractSingleDoubleArg(String argname, Map<String,List<String>> args) {
+ List<String> l = args.get(argname);
+ args.remove(argname);
+ if ( l == null ) return null;
+
+ if ( l.size() > 1 ) {
+ System.err.println("Only one "+argname+" argument is allowed");
+ System.exit(1);
+ }
+ double d=0;
+ try {
+ d = Double.parseDouble(l.get(0));
+ } catch ( NumberFormatException e) {
+ System.err.println("Can not parse value provided for "+argname+" argument ("+l.get(0)+")");
+ System.exit(1);
+ }
+ System.out.println("Argument "+argname+" set to "+d);
+ return new Double(d);
+ }
+
+
+ static Boolean extractSingleBooleanArg(String argname, Map<String,List<String>> args) {
+ List<String> l = args.get(argname);
+ args.remove(argname);
+ if ( l == null ) return null;
+
+ if ( l.size() > 1 ) {
+ System.err.println("Only one "+argname+" argument is allowed");
+ System.exit(1);
+ }
+ if ( l.get(0).equals("true") ) return Boolean.valueOf(true);
+ if ( l.get(0).equals("false") ) return Boolean.valueOf(false);
+ System.err.println("Can not parse value provided for "+argname+" argument ("+l.get(0)+"); true/false are allowed");
+ System.exit(1);
+ return Boolean.valueOf(false); // This value isn't used because it is preceded by System.exit(1)
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SWParameterSet.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SWParameterSet.java
new file mode 100644
index 0000000..7226a98
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SWParameterSet.java
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.smithwaterman;
+
+/**
+ * Handy named collection of common Smith-waterman parameter sets
+ *
+ * User: depristo
+ * Date: 4/11/13
+ * Time: 12:02 PM
+ */
+public enum SWParameterSet {
+ // match=1, mismatch = -1/3, gap=-(1+k/3)
+ ORIGINAL_DEFAULT(new Parameters(3,-1,-4,-3)),
+
+ /**
+ * A standard set of values for NGS alignments
+ */
+ STANDARD_NGS(new Parameters(25, -50, -110, -6));
+
+ protected Parameters parameters;
+
+ SWParameterSet(final Parameters parameters) {
+ if ( parameters == null ) throw new IllegalArgumentException("parameters cannot be null");
+
+ this.parameters = parameters;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SmithWaterman.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SmithWaterman.java
new file mode 100644
index 0000000..c4184e1
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/smithwaterman/SmithWaterman.java
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.smithwaterman;
+
+import htsjdk.samtools.Cigar;
+
+/**
+ * Generic interface for SmithWaterman calculations
+ *
+ * This interface allows clients to use a generic SmithWaterman variable, without propagating the specific
+ * implementation of SmithWaterman throughout their code:
+ *
+ * SmithWaterman sw = new SpecificSmithWatermanImplementation(ref, read, params)
+ * sw.getCigar()
+ * sw.getAlignmentStart2wrt1()
+ *
+ * User: depristo
+ * Date: 4/26/13
+ * Time: 8:24 AM
+ */
+public interface SmithWaterman {
+
+ /**
+ * Get the cigar string for the alignment of this SmithWaterman class
+ * @return a non-null cigar
+ */
+ public Cigar getCigar();
+
+ /**
+ * Get the starting position of the read sequence in the reference sequence
+ * @return a positive integer >= 0
+ */
+ public int getAlignmentStart2wrt1();
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/text/ListFileUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/text/ListFileUtils.java
new file mode 100644
index 0000000..d6e1bcb
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/text/ListFileUtils.java
@@ -0,0 +1,344 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.text;
+
+import org.broadinstitute.gatk.utils.commandline.ParsingEngine;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.broadinstitute.gatk.engine.refdata.tracks.FeatureManager;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * A collection of convenience methods for working with list files.
+ */
+public class ListFileUtils {
+ /**
+ * Lines starting with this String in .list files are considered comments.
+ */
+ public static final String LIST_FILE_COMMENT_START = "#";
+
+ /**
+ * Unpack the bam files to be processed, given a list of files. That list of files can
+ * itself contain entries which are lists of other files to be read (note: you cannot have lists
+ * of lists of lists). Lines in .list files containing only whitespace or which begin with
+ * LIST_FILE_COMMENT_START are ignored.
+ *
+ * @param samFiles The sam files, in string format.
+ * @param parser Parser
+ * @return a flattened list of the bam files provided
+ */
+ public static List<SAMReaderID> unpackBAMFileList(final List<String> samFiles, final ParsingEngine parser) {
+ List<SAMReaderID> unpackedReads = new ArrayList<SAMReaderID>();
+ for( String inputFileName: samFiles ) {
+ Tags inputFileNameTags = parser.getTags(inputFileName);
+ inputFileName = expandFileName(inputFileName);
+ if (inputFileName.toLowerCase().endsWith(".list") ) {
+ try {
+ for ( String fileName : new XReadLines(new File(inputFileName), true, LIST_FILE_COMMENT_START) ) {
+ unpackedReads.add(new SAMReaderID(fileName,parser.getTags(inputFileName)));
+ }
+ }
+ catch( FileNotFoundException ex ) {
+ throw new UserException.CouldNotReadInputFile(new File(inputFileName), "Unable to find file while unpacking reads", ex);
+ }
+ }
+ else if(inputFileName.toLowerCase().endsWith(".bam")) {
+ unpackedReads.add(new SAMReaderID(inputFileName,inputFileNameTags));
+ }
+ else if(inputFileName.endsWith("stdin")) {
+ unpackedReads.add(new SAMReaderID(inputFileName,inputFileNameTags));
+ }
+ else {
+ throw new UserException.CommandLineException(String.format("The GATK reads argument (-I, --input_file) supports only BAM files with the .bam extension and lists of BAM files " +
+ "with the .list extension, but the file %s has neither extension. Please ensure that your BAM file or list " +
+ "of BAM files is in the correct format, update the extension, and try again.",inputFileName));
+ }
+ }
+ return unpackedReads;
+ }
+
+ /**
+ * Convert command-line argument representation of ROD bindings to something more easily understandable by the engine.
+ * @param RODBindings a text equivale
+ * @param parser Parser
+ * @return a list of expanded, bound RODs.
+ */
+ @Deprecated
+ @SuppressWarnings("unused") // TODO: Who is still using this? External walkers?
+ public static Collection<RMDTriplet> unpackRODBindingsOldStyle(final Collection<String> RODBindings, final ParsingEngine parser) {
+ // todo -- this is a strange home for this code. Move into ROD system
+ Collection<RMDTriplet> rodBindings = new ArrayList<RMDTriplet>();
+
+ for (String fileName: RODBindings) {
+ final Tags tags = parser.getTags(fileName);
+ fileName = expandFileName(fileName);
+
+ List<String> positionalTags = tags.getPositionalTags();
+ if(positionalTags.size() != 2)
+ throw new UserException("Invalid syntax for -B (reference-ordered data) input flag. " +
+ "Please use the following syntax when providing reference-ordered " +
+ "data: -B:<name>,<type> <filename>.");
+ // Assume that if tags are present, those tags are name and type.
+ // Name is always first, followed by type.
+ String name = positionalTags.get(0);
+ String type = positionalTags.get(1);
+
+ RMDTriplet.RMDStorageType storageType;
+ if(tags.getValue("storage") != null)
+ storageType = Enum.valueOf(RMDTriplet.RMDStorageType.class,tags.getValue("storage"));
+ else if(fileName.toLowerCase().endsWith("stdin"))
+ storageType = RMDTriplet.RMDStorageType.STREAM;
+ else
+ storageType = RMDTriplet.RMDStorageType.FILE;
+
+ rodBindings.add(new RMDTriplet(name,type,fileName,storageType,tags));
+ }
+
+ return rodBindings;
+ }
+
+ /**
+ * Convert command-line argument representation of ROD bindings to something more easily understandable by the engine.
+ * @param RODBindings a text equivale
+ * @param parser Parser
+ * @return a list of expanded, bound RODs.
+ */
+ @SuppressWarnings("unchecked")
+ public static Collection<RMDTriplet> unpackRODBindings(final Collection<RodBinding> RODBindings, @SuppressWarnings("unused") final ParsingEngine parser) {
+ // todo -- this is a strange home for this code. Move into ROD system
+ Collection<RMDTriplet> rodBindings = new ArrayList<RMDTriplet>();
+ FeatureManager builderForValidation = new FeatureManager();
+
+ for (RodBinding rodBinding: RODBindings) {
+ String argValue = rodBinding.getSource();
+ String fileName = expandFileName(argValue);
+ String name = rodBinding.getName();
+ String type = rodBinding.getTribbleType();
+
+ RMDTriplet.RMDStorageType storageType;
+ if(rodBinding.getTags().getValue("storage") != null)
+ storageType = Enum.valueOf(RMDTriplet.RMDStorageType.class,rodBinding.getTags().getValue("storage"));
+ else if(fileName.toLowerCase().endsWith("stdin"))
+ storageType = RMDTriplet.RMDStorageType.STREAM;
+ else
+ storageType = RMDTriplet.RMDStorageType.FILE;
+
+ RMDTriplet triplet = new RMDTriplet(name,type,fileName,storageType,rodBinding.getTags());
+
+ // validate triplet type
+ FeatureManager.FeatureDescriptor descriptor = builderForValidation.getByTriplet(triplet);
+ if ( descriptor == null )
+ throw new UserException.UnknownTribbleType(rodBinding.getTribbleType(),
+ String.format("Field %s had provided type %s but there's no such Tribble type. The compatible types are: %n%s",
+ rodBinding.getName(), rodBinding.getTribbleType(), builderForValidation.userFriendlyListOfAvailableFeatures(rodBinding.getType())));
+ if ( ! rodBinding.getType().isAssignableFrom(descriptor.getFeatureClass()) )
+ throw new UserException.BadArgumentValue(rodBinding.getName(),
+ String.format("Field %s expects Features of type %s, but the input file produces Features of type %s. The compatible types are: %n%s",
+ rodBinding.getName(), rodBinding.getType().getSimpleName(), descriptor.getSimpleFeatureName(),
+ builderForValidation.userFriendlyListOfAvailableFeatures(rodBinding.getType())));
+
+
+ rodBindings.add(triplet);
+ }
+
+ return rodBindings;
+ }
+
+ /**
+ * Expand any special characters that appear in the filename. Right now, '-' is expanded to
+ * '/dev/stdin' only, but in the future, special characters like '~' and '*' that are passed
+ * directly to the command line in some circumstances could be expanded as well. Be careful
+ * when adding UNIX-isms.
+ * @param argument the text appearing on the command-line.
+ * @return An expanded string suitable for opening by Java/UNIX file handling utilities.
+ */
+ private static String expandFileName(String argument) {
+ if(argument.trim().equals("-"))
+ return "/dev/stdin";
+ return argument;
+ }
+
+ /**
+ * Returns a new set of values, containing a final set of values expanded from values
+ * <p/>
+ * Each element E of values can either be a literal string or a file ending in .list.
+ * For each E ending in .list we try to read a file named E from disk, and if possible
+ * all lines from that file are expanded into unique values.
+ *
+ * @param values Original values
+ * @return entries from values or the files listed in values
+ */
+ public static Set<String> unpackSet(Collection<String> values) {
+ if (values == null)
+ throw new NullPointerException("values cannot be null");
+ Set<String> unpackedValues = new LinkedHashSet<String>();
+ // Let's first go through the list and see if we were given any files.
+ // We'll add every entry in the file to our set, and treat the entries as
+ // if they had been specified on the command line.
+ for (String value : values) {
+ File file = new File(value);
+ if (value.toLowerCase().endsWith(".list") && file.exists()) {
+ try {
+ unpackedValues.addAll(new XReadLines(file, true, LIST_FILE_COMMENT_START).readLines());
+ } catch (IOException e) {
+ throw new UserException.CouldNotReadInputFile(file, e);
+ }
+ } else {
+ unpackedValues.add(value);
+ }
+ }
+ return unpackedValues;
+ }
+
+ /**
+ * Returns a new set of values including only values listed by filters
+ * <p/>
+ * Each element E of values can either be a literal string or a file. For each E,
+ * we try to read a file named E from disk, and if possible all lines from that file are expanded
+ * into unique names.
+ * <p/>
+ * Filters may also be a file of filters.
+ *
+ * @param values Values or files with values
+ * @param filters Filters or files with filters
+ * @param exactMatch If true match filters exactly, otherwise use as both exact and regular expressions
+ * @return entries from values or the files listed in values, filtered by filters
+ */
+ public static Set<String> includeMatching(Collection<String> values, Collection<String> filters, boolean exactMatch) {
+ return includeMatching(values, IDENTITY_STRING_CONVERTER, filters, exactMatch);
+ }
+
+ /**
+ * Converts a type T to a String representation.
+ *
+ * @param <T> Type to convert to a String.
+ */
+ public static interface StringConverter<T> {
+ String convert(T value);
+ }
+
+ /**
+ * Returns a new set of values including only values matching filters
+ * <p/>
+ * Filters may also be a file of filters.
+ * <p/>
+ * The converter should convert T to a unique String for each value in the set.
+ *
+ * @param values Values or files with values
+ * @param converter Converts values to strings
+ * @param filters Filters or files with filters
+ * @param exactMatch If true match filters exactly, otherwise use as both exact and regular expressions
+ * @return entries from values including only values matching filters
+ */
+ public static <T> Set<T> includeMatching(Collection<T> values, StringConverter<T> converter, Collection<String> filters, boolean exactMatch) {
+ if (values == null)
+ throw new NullPointerException("values cannot be null");
+ if (converter == null)
+ throw new NullPointerException("converter cannot be null");
+ if (filters == null)
+ throw new NullPointerException("filters cannot be null");
+
+ Set<String> unpackedFilters = unpackSet(filters);
+ Set<T> filteredValues = new LinkedHashSet<T>();
+ Collection<Pattern> patterns = null;
+ if (!exactMatch)
+ patterns = compilePatterns(unpackedFilters);
+ for (T value : values) {
+ String converted = converter.convert(value);
+ if (unpackedFilters.contains(converted)) {
+ filteredValues.add(value);
+ } else if (!exactMatch) {
+ for (Pattern pattern : patterns)
+ if (pattern.matcher(converted).find())
+ filteredValues.add(value);
+ }
+ }
+ return filteredValues;
+ }
+
+ /**
+ * Returns a new set of values excluding any values matching filters.
+ * <p/>
+ * Filters may also be a file of filters.
+ * <p/>
+ * The converter should convert T to a unique String for each value in the set.
+ *
+ * @param values Values or files with values
+ * @param converter Converts values to strings
+ * @param filters Filters or files with filters
+ * @param exactMatch If true match filters exactly, otherwise use as both exact and regular expressions
+ * @return entries from values exluding any values matching filters
+ */
+ public static <T> Set<T> excludeMatching(Collection<T> values, StringConverter<T> converter, Collection<String> filters, boolean exactMatch) {
+ if (values == null)
+ throw new NullPointerException("values cannot be null");
+ if (converter == null)
+ throw new NullPointerException("converter cannot be null");
+ if (filters == null)
+ throw new NullPointerException("filters cannot be null");
+
+ Set<String> unpackedFilters = unpackSet(filters);
+ Set<T> filteredValues = new LinkedHashSet<T>();
+ filteredValues.addAll(values);
+ Collection<Pattern> patterns = null;
+ if (!exactMatch)
+ patterns = compilePatterns(unpackedFilters);
+ for (T value : values) {
+ String converted = converter.convert(value);
+ if (unpackedFilters.contains(converted)) {
+ filteredValues.remove(value);
+ } else if (!exactMatch) {
+ for (Pattern pattern : patterns)
+ if (pattern.matcher(converted).find())
+ filteredValues.remove(value);
+ }
+ }
+ return filteredValues;
+ }
+
+ private static Collection<Pattern> compilePatterns(Collection<String> filters) {
+ Collection<Pattern> patterns = new ArrayList<Pattern>();
+ for (String filter: filters) {
+ patterns.add(Pattern.compile(filter));
+ }
+ return patterns;
+ }
+
+ protected static final StringConverter<String> IDENTITY_STRING_CONVERTER = new StringConverter<String>() {
+ @Override
+ public String convert(String value) {
+ return value;
+ }
+ };
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/text/TextFormattingUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/text/TextFormattingUtils.java
new file mode 100644
index 0000000..65fb970
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/text/TextFormattingUtils.java
@@ -0,0 +1,172 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.text;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Common utilities for dealing with text formatting.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class TextFormattingUtils {
+ /**
+ * our log, which we want to capture anything from this class
+ */
+ private static Logger logger = Logger.getLogger(TextFormattingUtils.class);
+
+ /**
+ * The default line width, for GATK output written to the screen.
+ */
+ public static final int DEFAULT_LINE_WIDTH = 120;
+
+ /**
+ * Simple implementation of word-wrap for a line of text. Idea and
+ * regexp shamelessly stolen from http://joust.kano.net/weblog/archives/000060.html.
+ * Regexp can probably be simplified for our application.
+ * @param text Text to wrap.
+ * @param width Maximum line width.
+ * @return A list of word-wrapped lines.
+ */
+ public static List<String> wordWrap( String text, int width ) {
+ Pattern wrapper = Pattern.compile( String.format(".{0,%d}(?:\\S(?:[\\s|]|$)|$)", width-1) );
+ Matcher matcher = wrapper.matcher( text );
+
+ List<String> wrapped = new ArrayList<String>();
+ while( matcher.find() ) {
+ // Regular expression is supersensitive to whitespace.
+ // Assert that content is present before adding the line.
+ String line = matcher.group().trim();
+ if( line.length() > 0 )
+ wrapped.add( matcher.group() );
+ }
+ return wrapped;
+ }
+
+ /**
+ * Compares two strings independently of case sensitivity.
+ */
+ public static class CaseInsensitiveComparator implements Comparator<String> {
+ /**
+ * Compares the order of lhs to rhs, not taking case into account.
+ * @param lhs First object to compare.
+ * @param rhs Second object to compare.
+ * @return 0 if objects are identical; -1 if lhs is before rhs, 1 if rhs is before lhs. Nulls are treated as after everything else.
+ */
+ public int compare(String lhs, String rhs) {
+ if(lhs == null && rhs == null) return 0;
+ if(lhs == null) return 1;
+ if(rhs == null) return -1;
+ return lhs.toLowerCase().compareTo(rhs.toLowerCase());
+ }
+ }
+
+ /**
+ * Load the contents of a resource bundle with the given name. If no such resource exists, warn the user
+ * and create an empty bundle.
+ * @param bundleName The name of the bundle to load.
+ * @return The best resource bundle that can be found matching the given name.
+ */
+ public static ResourceBundle loadResourceBundle(String bundleName) {
+ ResourceBundle bundle;
+ try {
+ bundle = ResourceBundle.getBundle(bundleName);
+ }
+ catch(MissingResourceException ex) {
+ //logger.warn("Unable to load help text. Help output will be sparse.");
+ // Generate an empty resource bundle.
+ try {
+ bundle = new PropertyResourceBundle(new StringReader(""));
+ }
+ catch(IOException ioe) {
+ throw new ReviewedGATKException("No resource bundle found, and unable to create an empty placeholder.",ioe);
+ }
+ }
+ return bundle;
+ }
+
+
+ /**
+ * Returns the word starting positions within line, excluding the first position 0.
+ * The returned list is compatible with splitFixedWidth.
+ * @param line Text to parse.
+ * @return the word starting positions within line, excluding the first position 0.
+ */
+ public static List<Integer> getWordStarts(String line) {
+ if (line == null)
+ throw new ReviewedGATKException("line is null");
+ List<Integer> starts = new ArrayList<Integer>();
+ int stop = line.length();
+ for (int i = 1; i < stop; i++)
+ if (Character.isWhitespace(line.charAt(i-1)))
+ if(!Character.isWhitespace(line.charAt(i)))
+ starts.add(i);
+ return starts;
+ }
+
+ /**
+ * Parses a fixed width line of text.
+ * @param line Text to parse.
+ * @param columnStarts the column starting positions within line, excluding the first position 0.
+ * @return The parsed string array with each entry trimmed.
+ */
+ public static String[] splitFixedWidth(String line, List<Integer> columnStarts) {
+ if (line == null)
+ throw new ReviewedGATKException("line is null");
+ if (columnStarts == null)
+ throw new ReviewedGATKException("columnStarts is null");
+ int startCount = columnStarts.size();
+ String[] row = new String[startCount + 1];
+ if (startCount == 0) {
+ row[0] = line.trim();
+ } else {
+ row[0] = line.substring(0, columnStarts.get(0)).trim();
+ for (int i = 1; i < startCount; i++)
+ row[i] = line.substring(columnStarts.get(i - 1), columnStarts.get(i)).trim();
+ row[startCount] = line.substring(columnStarts.get(startCount - 1)).trim();
+ }
+ return row;
+ }
+
+ /**
+ * Parses a line of text by whitespace.
+ * @param line Text to parse.
+ * @return The parsed string array.
+ */
+ public static String[] splitWhiteSpace(String line) {
+ if (line == null)
+ throw new ReviewedGATKException("line is null");
+ return line.trim().split("\\s+");
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/text/XReadLines.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/text/XReadLines.java
new file mode 100644
index 0000000..f410156
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/text/XReadLines.java
@@ -0,0 +1,208 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.text;
+
+import java.io.*;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Support for Python-like xreadlines() function as a class. This is an iterator and iterable over
+ * Strings, each corresponding a line in the file (minus newline). Enables the very simple accessing
+ * of lines in a file as:
+ *
+ * xReadLines reader = new xReadLines(new File(file_name));
+ * List<String> lines = reader.readLines();
+ * reader.close();
+ *
+ * or
+ *
+ * for ( String line : new xReadLines(new File(file_name)) {
+ * doSomeWork(line);
+ * }
+ *
+ * For the love of god, please use this system for reading lines in a file.
+ */
+public class XReadLines implements Iterator<String>, Iterable<String> {
+ private final BufferedReader in; // The stream we're reading from
+ private String nextLine = null; // Return value of next call to next()
+ private final boolean trimWhitespace;
+ private final String commentPrefix;
+
+ public XReadLines(final File filename) throws FileNotFoundException {
+ this(new FileReader(filename), true, null);
+ }
+
+ public XReadLines(final File filename, final boolean trimWhitespace) throws FileNotFoundException {
+ this(new FileReader(filename), trimWhitespace, null);
+ }
+
+ /**
+ * Creates a new xReadLines object to read lines from filename
+ *
+ * @param filename file name
+ * @param trimWhitespace trim whitespace
+ * @param commentPrefix prefix for comments or null if no prefix is set
+ * @throws FileNotFoundException when the file is not found
+ */
+ public XReadLines(final File filename, final boolean trimWhitespace, final String commentPrefix) throws FileNotFoundException {
+ this(new FileReader(filename), trimWhitespace, commentPrefix);
+ }
+
+ public XReadLines(final InputStream inputStream) throws FileNotFoundException {
+ this(new InputStreamReader(inputStream), true, null);
+ }
+
+ public XReadLines(final InputStream inputStream, final boolean trimWhitespace) {
+ this(new InputStreamReader(inputStream), trimWhitespace, null);
+ }
+
+ /**
+ * Creates a new xReadLines object to read lines from an input stream
+ *
+ * @param inputStream input stream
+ * @param trimWhitespace trim whitespace
+ * @param commentPrefix prefix for comments or null if no prefix is set
+ */
+ public XReadLines(final InputStream inputStream, final boolean trimWhitespace, final String commentPrefix) {
+ this(new InputStreamReader(inputStream), trimWhitespace, commentPrefix);
+ }
+
+
+ /**
+ * Creates a new xReadLines object to read lines from a reader
+ *
+ * @param reader reader
+ */
+ public XReadLines(final Reader reader) {
+ this(reader, true, null);
+ }
+
+ /**
+ * Creates a new xReadLines object to read lines from an reader
+ *
+ * @param reader reader
+ * @param trimWhitespace trim whitespace
+ */
+ public XReadLines(final Reader reader, final boolean trimWhitespace) {
+ this(reader, trimWhitespace, null);
+ }
+
+ /**
+ * Creates a new xReadLines object to read lines from an bufferedReader
+ *
+ * @param reader file name
+ * @param trimWhitespace trim whitespace
+ * @param commentPrefix prefix for comments or null if no prefix is set
+ */
+ public XReadLines(final Reader reader, final boolean trimWhitespace, final String commentPrefix) {
+ this.in = (reader instanceof BufferedReader) ? (BufferedReader)reader : new BufferedReader(reader);
+ this.trimWhitespace = trimWhitespace;
+ this.commentPrefix = commentPrefix;
+ try {
+ this.nextLine = readNextLine();
+ } catch(IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Reads all of the lines in the file, and returns them as a list of strings
+ *
+ * @return all of the lines in the file.
+ */
+ public List<String> readLines() {
+ List<String> lines = new LinkedList<String>();
+ for ( String line : this ) {
+ lines.add(line);
+ }
+ return lines;
+ }
+
+ /**
+ * I'm an iterator too...
+ * @return an iterator
+ */
+ public Iterator<String> iterator() {
+ return this;
+ }
+
+ public boolean hasNext() {
+ return this.nextLine != null;
+ }
+
+ /**
+ * Actually reads the next line from the stream, not accessible publicly
+ * @return the next line or null
+ * @throws IOException if an error occurs
+ */
+ private String readNextLine() throws IOException {
+ String nextLine;
+ while ((nextLine = this.in.readLine()) != null) {
+ if (this.trimWhitespace) {
+ nextLine = nextLine.trim();
+ if (nextLine.length() == 0)
+ continue;
+ }
+ if (this.commentPrefix != null)
+ if (nextLine.startsWith(this.commentPrefix))
+ continue;
+ break;
+ }
+ return nextLine;
+ }
+
+ /**
+ * Returns the next line (optionally minus whitespace)
+ * @return the next line
+ */
+ public String next() {
+ try {
+ String result = this.nextLine;
+ this.nextLine = readNextLine();
+
+ // If we haven't reached EOF yet
+ if (this.nextLine == null) {
+ in.close(); // And close on EOF
+ }
+
+ // Return the line we read last time through.
+ return result;
+ } catch(IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ // The file is read-only; we don't allow lines to be removed.
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void close() throws IOException {
+ this.in.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/EfficiencyMonitoringThreadFactory.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/EfficiencyMonitoringThreadFactory.java
new file mode 100644
index 0000000..7282083
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/EfficiencyMonitoringThreadFactory.java
@@ -0,0 +1,160 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.threading;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Invariant;
+import com.google.java.contract.Requires;
+import org.apache.log4j.Logger;
+import org.apache.log4j.Priority;
+import org.broadinstitute.gatk.utils.AutoFormattingTime;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.ArrayList;
+import java.util.EnumMap;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Creates threads that automatically monitor their efficiency via the parent ThreadEfficiencyMonitor
+ *
+ * User: depristo
+ * Date: 8/14/12
+ * Time: 8:47 AM
+ */
+ at Invariant({
+ "activeThreads.size() <= nThreadsToCreate",
+ "countDownLatch.getCount() <= nThreadsToCreate",
+ "nThreadsCreated <= nThreadsToCreate"
+})
+public class EfficiencyMonitoringThreadFactory extends ThreadEfficiencyMonitor implements ThreadFactory {
+ final int nThreadsToCreate;
+ final List<Thread> activeThreads;
+
+ int nThreadsCreated = 0;
+
+ /**
+ * Counts down the number of active activeThreads whose runtime info hasn't been incorporated into
+ * times. Counts down from nThreadsToCreate to 0, at which point any code waiting
+ * on the final times is freed to run.
+ */
+ final CountDownLatch countDownLatch;
+
+ /**
+ * Create a new factory generating threads whose runtime and contention
+ * behavior is tracked in this factory.
+ *
+ * @param nThreadsToCreate the number of threads we will create in the factory before it's considered complete
+ */
+ public EfficiencyMonitoringThreadFactory(final int nThreadsToCreate) {
+ super();
+ if ( nThreadsToCreate <= 0 ) throw new IllegalArgumentException("nThreadsToCreate <= 0: " + nThreadsToCreate);
+
+ this.nThreadsToCreate = nThreadsToCreate;
+ activeThreads = new ArrayList<Thread>(nThreadsToCreate);
+ countDownLatch = new CountDownLatch(nThreadsToCreate);
+ }
+
+ /**
+ * How many threads have been created by this factory so far?
+ * @return
+ */
+ @Ensures("result >= 0")
+ public int getNThreadsCreated() {
+ return nThreadsCreated;
+ }
+
+ /**
+ * Only useful for testing, so that we can wait for all of the threads in the factory to complete running
+ *
+ * @throws InterruptedException
+ */
+ protected void waitForAllThreadsToComplete() throws InterruptedException {
+ countDownLatch.await();
+ }
+
+ @Ensures({
+ "activeThreads.size() <= old(activeThreads.size())",
+ "! activeThreads.contains(thread)",
+ "countDownLatch.getCount() <= old(countDownLatch.getCount())"
+ })
+ @Override
+ public synchronized void threadIsDone(final Thread thread) {
+ nThreadsAnalyzed++;
+
+ if ( DEBUG ) logger.warn(" Countdown " + countDownLatch.getCount() + " in thread " + Thread.currentThread().getName());
+
+ super.threadIsDone(thread);
+
+ // remove the thread from the list of active activeThreads, if it's in there, and decrement the countdown latch
+ if ( activeThreads.remove(thread) ) {
+ // one less thread is live for those blocking on all activeThreads to be complete
+ countDownLatch.countDown();
+ if ( DEBUG ) logger.warn(" -> Countdown " + countDownLatch.getCount() + " in thread " + Thread.currentThread().getName());
+ }
+ }
+
+ /**
+ * Create a new thread from this factory
+ *
+ * @param runnable
+ * @return
+ */
+ @Override
+ @Ensures({
+ "activeThreads.size() > old(activeThreads.size())",
+ "activeThreads.contains(result)",
+ "nThreadsCreated == old(nThreadsCreated) + 1"
+ })
+ public synchronized Thread newThread(final Runnable runnable) {
+ if ( activeThreads.size() >= nThreadsToCreate)
+ throw new IllegalStateException("Attempting to create more activeThreads than allowed by constructor argument nThreadsToCreate " + nThreadsToCreate);
+
+ nThreadsCreated++;
+ final Thread myThread = new TrackingThread(runnable);
+ activeThreads.add(myThread);
+ return myThread;
+ }
+
+ /**
+ * A wrapper around Thread that tracks the runtime of the thread and calls threadIsDone() when complete
+ */
+ private class TrackingThread extends Thread {
+ private TrackingThread(Runnable runnable) {
+ super(runnable);
+ }
+
+ @Override
+ public void run() {
+ super.run();
+ threadIsDone(this);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/NamedThreadFactory.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/NamedThreadFactory.java
new file mode 100644
index 0000000..6c84086
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/NamedThreadFactory.java
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.threading;
+
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * Thread factor that produces threads with a given name pattern
+ *
+ * User: depristo
+ * Date: 9/5/12
+ * Time: 9:22 PM
+ *
+ */
+public class NamedThreadFactory implements ThreadFactory {
+ static int id = 0;
+ final String format;
+
+ public NamedThreadFactory(String format) {
+ this.format = format;
+ String.format(format, id); // test the name
+ }
+
+ @Override
+ public Thread newThread(Runnable r) {
+ return new Thread(r, String.format(format, id++));
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/ThreadEfficiencyMonitor.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/ThreadEfficiencyMonitor.java
new file mode 100644
index 0000000..cee91a4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/ThreadEfficiencyMonitor.java
@@ -0,0 +1,232 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.threading;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Invariant;
+import com.google.java.contract.Requires;
+import org.apache.log4j.Logger;
+import org.apache.log4j.Priority;
+import org.broadinstitute.gatk.utils.AutoFormattingTime;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.ThreadInfo;
+import java.lang.management.ThreadMXBean;
+import java.util.EnumMap;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Uses an MXBean to monitor thread efficiency
+ *
+ * Once the monitor is created, calls to threadIsDone() can be used to add information
+ * about the efficiency of the provided thread to this monitor.
+ *
+ * Provides simple print() for displaying efficiency information to a logger
+ *
+ * User: depristo
+ * Date: 8/22/12
+ * Time: 10:48 AM
+ */
+ at Invariant({"nThreadsAnalyzed >= 0"})
+public class ThreadEfficiencyMonitor {
+ protected static final boolean DEBUG = false;
+ protected static Logger logger = Logger.getLogger(EfficiencyMonitoringThreadFactory.class);
+ final EnumMap<State, Long> times = new EnumMap<State, Long>(State.class);
+
+ /**
+ * The number of threads we've included in our efficiency monitoring
+ */
+ int nThreadsAnalyzed = 0;
+
+ /**
+ * The bean used to get the thread info about blocked and waiting times
+ */
+ final ThreadMXBean bean;
+
+ public ThreadEfficiencyMonitor() {
+ bean = ManagementFactory.getThreadMXBean();
+
+ // get the bean, and start tracking
+ if ( bean.isThreadContentionMonitoringSupported() )
+ bean.setThreadContentionMonitoringEnabled(true);
+ else
+ logger.warn("Thread contention monitoring not supported, we cannot track GATK multi-threaded efficiency");
+ //bean.setThreadCpuTimeEnabled(true);
+
+ if ( bean.isThreadCpuTimeSupported() )
+ bean.setThreadCpuTimeEnabled(true);
+ else
+ logger.warn("Thread CPU monitoring not supported, we cannot track GATK multi-threaded efficiency");
+
+ // initialize times to 0
+ for ( final State state : State.values() )
+ times.put(state, 0l);
+ }
+
+ private static long nanoToMilli(final long timeInNano) {
+ return TimeUnit.NANOSECONDS.toMillis(timeInNano);
+ }
+
+ /**
+ * Get the time spent in state across all threads created by this factory
+ *
+ * @param state to get information about
+ * @return the time in milliseconds
+ */
+ @Ensures({"result >= 0"})
+ public synchronized long getStateTime(final State state) {
+ return times.get(state);
+ }
+
+ /**
+ * Get the total time spent in all states across all threads created by this factory
+ *
+ * @return the time in milliseconds
+ */
+ @Ensures({"result >= 0"})
+ public synchronized long getTotalTime() {
+ long total = 0;
+ for ( final long time : times.values() )
+ total += time;
+ return total;
+ }
+
+ /**
+ * Get the fraction of time spent in state across all threads created by this factory
+ *
+ * @return the percentage (0.0-100.0) of time spent in state over all state times of all threads
+ */
+ @Ensures({"result >= 0.0", "result <= 100.0"})
+ public synchronized double getStatePercent(final State state) {
+ return (100.0 * getStateTime(state)) / Math.max(getTotalTime(), 1);
+ }
+
+ public int getnThreadsAnalyzed() {
+ return nThreadsAnalyzed;
+ }
+
+ @Override
+ public synchronized String toString() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("total ").append(getTotalTime()).append(" ");
+ for ( final State state : State.values() ) {
+ b.append(state).append(" ").append(getStateTime(state)).append(" ");
+ }
+
+ return b.toString();
+ }
+
+ /**
+ * Print usage information about threads from this factory to logger
+ * with the INFO priority
+ *
+ * @param logger
+ */
+ public synchronized void printUsageInformation(final Logger logger) {
+ printUsageInformation(logger, Priority.INFO);
+ }
+
+ /**
+ * Print usage information about threads from this factory to logger
+ * with the provided priority
+ *
+ * @param logger
+ */
+ public synchronized void printUsageInformation(final Logger logger, final Priority priority) {
+ logger.debug("Number of threads monitored: " + getnThreadsAnalyzed());
+ logger.debug("Total runtime " + new AutoFormattingTime(TimeUnit.MILLISECONDS.toNanos(getTotalTime())));
+ for ( final State state : State.values() ) {
+ logger.debug(String.format("\tPercent of time spent %s is %.2f", state.getUserFriendlyName(), getStatePercent(state)));
+ }
+ logger.log(priority, String.format("CPU efficiency : %6.2f%% of time spent %s", getStatePercent(State.USER_CPU), State.USER_CPU.getUserFriendlyName()));
+ logger.log(priority, String.format("Walker inefficiency : %6.2f%% of time spent %s", getStatePercent(State.BLOCKING), State.BLOCKING.getUserFriendlyName()));
+ logger.log(priority, String.format("I/O inefficiency : %6.2f%% of time spent %s", getStatePercent(State.WAITING_FOR_IO), State.WAITING_FOR_IO.getUserFriendlyName()));
+ logger.log(priority, String.format("Thread inefficiency : %6.2f%% of time spent %s", getStatePercent(State.WAITING), State.WAITING.getUserFriendlyName()));
+ }
+
+ /**
+ * Update the information about completed thread that ran for runtime in milliseconds
+ *
+ * This method updates all of the key timing and tracking information in the factory so that
+ * thread can be retired. After this call the factory shouldn't have a pointer to the thread any longer
+ *
+ * @param thread the thread whose information we are updating
+ */
+ @Ensures({
+ "getTotalTime() >= old(getTotalTime())"
+ })
+ public synchronized void threadIsDone(final Thread thread) {
+ nThreadsAnalyzed++;
+
+ if ( DEBUG ) logger.warn("UpdateThreadInfo called");
+
+ final long threadID = thread.getId();
+ final ThreadInfo info = bean.getThreadInfo(thread.getId());
+ final long totalTimeNano = bean.getThreadCpuTime(threadID);
+ final long userTimeNano = bean.getThreadUserTime(threadID);
+ final long systemTimeNano = totalTimeNano - userTimeNano;
+ final long userTimeInMilliseconds = nanoToMilli(userTimeNano);
+ final long systemTimeInMilliseconds = nanoToMilli(systemTimeNano);
+
+ if ( info != null ) {
+ if ( DEBUG ) logger.warn("Updating thread with user runtime " + userTimeInMilliseconds + " and system runtime " + systemTimeInMilliseconds + " of which blocked " + info.getBlockedTime() + " and waiting " + info.getWaitedTime());
+ incTimes(State.BLOCKING, info.getBlockedTime());
+ incTimes(State.WAITING, info.getWaitedTime());
+ incTimes(State.USER_CPU, userTimeInMilliseconds);
+ incTimes(State.WAITING_FOR_IO, systemTimeInMilliseconds);
+ }
+ }
+
+ /**
+ * Helper function that increments the times counter by by for state
+ *
+ * @param state
+ * @param by
+ */
+ @Requires({"state != null", "by >= 0"})
+ @Ensures("getTotalTime() == old(getTotalTime()) + by")
+ private synchronized void incTimes(final State state, final long by) {
+ times.put(state, times.get(state) + by);
+ }
+
+ public enum State {
+ BLOCKING("blocking on synchronized data structures"),
+ WAITING("waiting on some other thread"),
+ USER_CPU("doing productive CPU work"),
+ WAITING_FOR_IO("waiting for I/O");
+
+ private final String userFriendlyName;
+
+ private State(String userFriendlyName) {
+ this.userFriendlyName = userFriendlyName;
+ }
+
+ public String getUserFriendlyName() {
+ return userFriendlyName;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/ThreadLocalArray.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/ThreadLocalArray.java
new file mode 100644
index 0000000..b8dea06
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/ThreadLocalArray.java
@@ -0,0 +1,65 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.threading;
+
+import java.lang.reflect.Array;
+
+/**
+ * ThreadLocal implementation for arrays
+ *
+ * Example usage:
+ *
+ * private ThreadLocal<byte[]> threadLocalByteArray = new ThreadLocalArray<byte[]>(length, byte.class);
+ * ....
+ * byte[] byteArray = threadLocalByteArray.get();
+ *
+ * @param <T> the type of the array itself (eg., int[], double[], etc.)
+ *
+ * @author David Roazen
+ */
+public class ThreadLocalArray<T> extends ThreadLocal<T> {
+ private int arraySize;
+ private Class arrayElementType;
+
+ /**
+ * Create a new ThreadLocalArray
+ *
+ * @param arraySize desired length of the array
+ * @param arrayElementType type of the elements within the array (eg., Byte.class, Integer.class, etc.)
+ */
+ public ThreadLocalArray( int arraySize, Class arrayElementType ) {
+ super();
+
+ this.arraySize = arraySize;
+ this.arrayElementType = arrayElementType;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected T initialValue() {
+ return (T)Array.newInstance(arrayElementType, arraySize);
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/ThreadPoolMonitor.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/ThreadPoolMonitor.java
new file mode 100644
index 0000000..9261870
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/ThreadPoolMonitor.java
@@ -0,0 +1,77 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.threading;
+
+import org.apache.log4j.Logger;
+/**
+ * User: hanna
+ * Date: Apr 29, 2009
+ * Time: 4:27:58 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Waits for a signal to come through that the thread pool has run
+ * a given task and therefore has a free slot.
+ *
+ * Make sure, that, when using, the submit and the run are both
+ * protected by the same synchronized(monitor) lock. See the test
+ * case for an example.
+ */
+public class ThreadPoolMonitor implements Runnable {
+ /**
+ * Logger for reporting interruptions, etc.
+ */
+ private static Logger logger = Logger.getLogger(ThreadPoolMonitor.class);
+
+ /**
+ * Watch the monitor
+ */
+ public synchronized void watch() {
+ try {
+ wait();
+ }
+ catch( InterruptedException ex ) {
+ logger.error("ThreadPoolMonitor interrupted:" + ex.getStackTrace());
+ throw new RuntimeException("ThreadPoolMonitor interrupted", ex);
+ }
+ }
+
+ /**
+ * Instruct the monitor that the thread pool has run for the class.
+ * Only the thread pool should execute this method.
+ */
+ public synchronized void run() {
+ notify();
+ }
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/package-info.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/package-info.java
new file mode 100644
index 0000000..83093ba
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/threading/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.threading;
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/GATKVCFIndexType.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/GATKVCFIndexType.java
new file mode 100644
index 0000000..f142da2
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/GATKVCFIndexType.java
@@ -0,0 +1,39 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.variant;
+
+import org.broadinstitute.gatk.utils.commandline.EnumerationArgumentDefault;
+
+/**
+ * Choose the Tribble indexing strategy
+ */
+public enum GATKVCFIndexType {
+ @EnumerationArgumentDefault
+ DYNAMIC_SEEK, // use DynamicIndexCreator(IndexFactory.IndexBalanceApproach.FOR_SEEK_TIME)
+ DYNAMIC_SIZE, // use DynamicIndexCreator(IndexFactory.IndexBalanceApproach.FOR_SIZE)
+ LINEAR, // use LinearIndexCreator()
+ INTERVAL // use IntervalIndexCreator()
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/GATKVCFUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/GATKVCFUtils.java
new file mode 100644
index 0000000..6baa7b6
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/GATKVCFUtils.java
@@ -0,0 +1,316 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.variant;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.Feature;
+import htsjdk.tribble.FeatureCodec;
+import htsjdk.tribble.FeatureCodecHeader;
+import htsjdk.tribble.index.DynamicIndexCreator;
+import htsjdk.tribble.index.IndexCreator;
+import htsjdk.tribble.index.IndexFactory;
+import htsjdk.tribble.index.interval.IntervalIndexCreator;
+import htsjdk.tribble.index.linear.LinearIndexCreator;
+import htsjdk.tribble.index.tabix.TabixFormat;
+import htsjdk.tribble.index.tabix.TabixIndexCreator;
+import htsjdk.tribble.readers.LineIterator;
+import htsjdk.tribble.readers.PositionalBufferedStream;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.io.stubs.VCFWriterArgumentTypeDescriptor;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.vcf.*;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.*;
+
+
+/**
+ * A set of GATK-specific static utility methods for common operations on VCF files/records.
+ */
+public class GATKVCFUtils {
+
+ /**
+ * Constructor access disallowed...static utility methods only!
+ */
+ private GATKVCFUtils() { }
+
+ public static final Logger logger = Logger.getLogger(GATKVCFUtils.class);
+ public final static String GATK_COMMAND_LINE_KEY = "GATKCommandLine";
+
+ public final static GATKVCFIndexType DEFAULT_INDEX_TYPE = GATKVCFIndexType.DYNAMIC_SEEK; // by default, optimize for seek time. All indices prior to Nov 2013 used this type.
+ public final static Integer DEFAULT_INDEX_PARAMETER = -1; // the default DYNAMIC_SEEK does not use a parameter
+
+ /**
+ * Gets the appropriately formatted header for a VCF file describing this GATK run
+ *
+ * @param engine the GATK engine that holds the walker name, GATK version, and other information
+ * @param argumentSources contains information on the argument values provided to the GATK for converting to a
+ * command line string. Should be provided from the data in the parsing engine. Can be
+ * empty in which case the command line will be the empty string.
+ * @return VCF header line describing this run of the GATK.
+ */
+ public static VCFHeaderLine getCommandLineArgumentHeaderLine(final GenomeAnalysisEngine engine, final Collection<Object> argumentSources) {
+ if ( engine == null ) throw new IllegalArgumentException("engine cannot be null");
+ if ( argumentSources == null ) throw new IllegalArgumentException("argumentSources cannot be null");
+
+ final Map<String, String> attributes = new LinkedHashMap<>();
+ attributes.put("ID", engine.getWalkerName());
+ attributes.put("Version", CommandLineGATK.getVersionNumber());
+ final Date date = new Date();
+ attributes.put("Date", date.toString());
+ attributes.put("Epoch", Long.toString(date.getTime()));
+ attributes.put("CommandLineOptions", engine.createApproximateCommandLineArgumentString(argumentSources.toArray()));
+ return new VCFSimpleHeaderLine(GATK_COMMAND_LINE_KEY, attributes);
+ }
+
+ public static <T extends Feature> Map<String, VCFHeader> getVCFHeadersFromRods(GenomeAnalysisEngine toolkit, List<RodBinding<T>> rodBindings) {
+ // Collect the eval rod names
+ final Set<String> names = new TreeSet<String>();
+ for ( final RodBinding<T> evalRod : rodBindings )
+ names.add(evalRod.getName());
+ return getVCFHeadersFromRods(toolkit, names);
+ }
+
+ public static Map<String, VCFHeader> getVCFHeadersFromRods(GenomeAnalysisEngine toolkit) {
+ return getVCFHeadersFromRods(toolkit, (Collection<String>)null);
+ }
+
+ public static Map<String, VCFHeader> getVCFHeadersFromRods(GenomeAnalysisEngine toolkit, Collection<String> rodNames) {
+ Map<String, VCFHeader> data = new HashMap<String, VCFHeader>();
+
+ // iterate to get all of the sample names
+ List<ReferenceOrderedDataSource> dataSources = toolkit.getRodDataSources();
+ for ( ReferenceOrderedDataSource source : dataSources ) {
+ // ignore the rod if it's not in our list
+ if ( rodNames != null && !rodNames.contains(source.getName()) )
+ continue;
+
+ if ( source.getHeader() != null && source.getHeader() instanceof VCFHeader )
+ data.put(source.getName(), (VCFHeader)source.getHeader());
+ }
+
+ return data;
+ }
+
+ public static Map<String,VCFHeader> getVCFHeadersFromRodPrefix(GenomeAnalysisEngine toolkit,String prefix) {
+ Map<String, VCFHeader> data = new HashMap<String, VCFHeader>();
+
+ // iterate to get all of the sample names
+ List<ReferenceOrderedDataSource> dataSources = toolkit.getRodDataSources();
+ for ( ReferenceOrderedDataSource source : dataSources ) {
+ // ignore the rod if lacks the prefix
+ if ( ! source.getName().startsWith(prefix) )
+ continue;
+
+ if ( source.getHeader() != null && source.getHeader() instanceof VCFHeader )
+ data.put(source.getName(), (VCFHeader)source.getHeader());
+ }
+
+ return data;
+ }
+
+ /**
+ * Gets the header fields from all VCF rods input by the user
+ *
+ * @param toolkit GATK engine
+ *
+ * @return a set of all fields
+ */
+ public static Set<VCFHeaderLine> getHeaderFields(GenomeAnalysisEngine toolkit) {
+ return getHeaderFields(toolkit, null);
+ }
+
+ /**
+ * Gets the header fields from all VCF rods input by the user
+ *
+ * @param toolkit GATK engine
+ * @param rodNames names of rods to use, or null if we should use all possible ones
+ *
+ * @return a set of all fields
+ */
+ public static Set<VCFHeaderLine> getHeaderFields(GenomeAnalysisEngine toolkit, Collection<String> rodNames) {
+
+ // keep a map of sample name to occurrences encountered
+ TreeSet<VCFHeaderLine> fields = new TreeSet<VCFHeaderLine>();
+
+ // iterate to get all of the sample names
+ List<ReferenceOrderedDataSource> dataSources = toolkit.getRodDataSources();
+ for ( ReferenceOrderedDataSource source : dataSources ) {
+ // ignore the rod if it's not in our list
+ if ( rodNames != null && !rodNames.contains(source.getName()) )
+ continue;
+
+ if ( source.getRecordType().equals(VariantContext.class)) {
+ VCFHeader header = (VCFHeader)source.getHeader();
+ if ( header != null )
+ fields.addAll(header.getMetaDataInSortedOrder());
+ }
+ }
+
+ return fields;
+ }
+
+ /**
+ * Add / replace the contig header lines in the VCFHeader with the information in the GATK engine
+ *
+ * @param header the header to update
+ * @param engine the GATK engine containing command line arguments and the master sequence dictionary
+ */
+ public static VCFHeader withUpdatedContigs(final VCFHeader header, final GenomeAnalysisEngine engine) {
+ return VCFUtils.withUpdatedContigs(header, engine.getArguments().referenceFile, engine.getMasterSequenceDictionary());
+ }
+
+ /**
+ * Create and return an IndexCreator
+ * @param type
+ * @param parameter
+ * @param outFile
+ * @return
+ */
+ public static IndexCreator getIndexCreator(GATKVCFIndexType type, int parameter, File outFile) {
+ return getIndexCreator(type, parameter, outFile, null);
+ }
+
+ /**
+ * Create and return an IndexCreator
+ * @param type
+ * @param parameter
+ * @param outFile
+ * @param sequenceDictionary
+ * @return
+ */
+ public static IndexCreator getIndexCreator(GATKVCFIndexType type, int parameter, File outFile, SAMSequenceDictionary sequenceDictionary) {
+ if (VCFWriterArgumentTypeDescriptor.isCompressed(outFile.toString())) {
+ if (type != GATKVCFUtils.DEFAULT_INDEX_TYPE || parameter != GATKVCFUtils.DEFAULT_INDEX_PARAMETER)
+ logger.warn("Creating Tabix index for " + outFile + ", ignoring user-specified index type and parameter");
+
+ if (sequenceDictionary == null)
+ return new TabixIndexCreator(TabixFormat.VCF);
+ else
+ return new TabixIndexCreator(sequenceDictionary, TabixFormat.VCF);
+ }
+
+ IndexCreator idxCreator;
+ switch (type) {
+ case DYNAMIC_SEEK: idxCreator = new DynamicIndexCreator(outFile, IndexFactory.IndexBalanceApproach.FOR_SEEK_TIME); break;
+ case DYNAMIC_SIZE: idxCreator = new DynamicIndexCreator(outFile, IndexFactory.IndexBalanceApproach.FOR_SIZE); break;
+ case LINEAR: idxCreator = new LinearIndexCreator(outFile, parameter); break;
+ case INTERVAL: idxCreator = new IntervalIndexCreator(outFile, parameter); break;
+ default: throw new IllegalArgumentException("Unknown IndexCreator type: " + type);
+ }
+
+ return idxCreator;
+ }
+
+ /**
+ * Utility class to read all of the VC records from a file
+ *
+ * @param file
+ * @param codec
+ * @return
+ * @throws IOException
+ */
+ public final static <SOURCE> Pair<VCFHeader, VCIterable<SOURCE>> readAllVCs( final File file, final FeatureCodec<VariantContext, SOURCE> codec) throws IOException {
+ // read in the features
+ SOURCE source = codec.makeSourceFromStream(new FileInputStream(file));
+ FeatureCodecHeader header = codec.readHeader(source);
+ final VCFHeader vcfHeader = (VCFHeader)header.getHeaderValue();
+ return new Pair<>(vcfHeader, new VCIterable<>(source, codec, vcfHeader));
+ }
+
+ public static class VCIterable<SOURCE> implements Iterable<VariantContext>, Iterator<VariantContext> {
+ final SOURCE source;
+ final FeatureCodec<VariantContext, SOURCE> codec;
+ final VCFHeader header;
+
+ private VCIterable(final SOURCE source, final FeatureCodec<VariantContext, SOURCE> codec, final VCFHeader header) {
+ this.source = source;
+ this.codec = codec;
+ this.header = header;
+ }
+
+ @Override
+ public Iterator<VariantContext> iterator() {
+ return this;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return ! codec.isDone(source);
+ }
+
+ @Override
+ public VariantContext next() {
+ try {
+ final VariantContext vc = codec.decode(source);
+ return vc == null ? null : vc.fullyDecode(header, false);
+ } catch ( IOException e ) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void remove() {
+ }
+ }
+
+ /**
+ * Read all of the VCF records from source into memory, returning the header and the VariantContexts
+ *
+ * SHOULD ONLY BE USED FOR UNIT/INTEGRATION TESTING PURPOSES!
+ *
+ * @param source the file to read, must be in VCF4 format
+ * @return
+ * @throws java.io.IOException
+ */
+ public static Pair<VCFHeader, List<VariantContext>> readVCF(final File source) throws IOException {
+ // read in the features
+ final List<VariantContext> vcs = new ArrayList<VariantContext>();
+ final VCFCodec codec = new VCFCodec();
+ PositionalBufferedStream pbs = new PositionalBufferedStream(new FileInputStream(source));
+ final LineIterator vcfSource = codec.makeSourceFromStream(pbs);
+ try {
+ final VCFHeader vcfHeader = (VCFHeader) codec.readActualHeader(vcfSource);
+
+ while (vcfSource.hasNext()) {
+ final VariantContext vc = codec.decode(vcfSource);
+ if ( vc != null )
+ vcs.add(vc);
+ }
+
+ return new Pair<VCFHeader, List<VariantContext>>(vcfHeader, vcs);
+ } finally {
+ codec.close(vcfSource);
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/GATKVariantContextUtils.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/GATKVariantContextUtils.java
new file mode 100644
index 0000000..a099d8c
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/GATKVariantContextUtils.java
@@ -0,0 +1,1960 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.variant;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.tribble.TribbleException;
+import htsjdk.tribble.util.popgen.HardyWeinbergCalculation;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.vcf.VCFConstants;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.*;
+import org.broadinstitute.gatk.utils.collections.Pair;
+
+import java.io.Serializable;
+import java.util.*;
+
+public class GATKVariantContextUtils {
+
+ private static Logger logger = Logger.getLogger(GATKVariantContextUtils.class);
+
+ public static final int DEFAULT_PLOIDY = HomoSapiensConstants.DEFAULT_PLOIDY;
+
+ public static final double SUM_GL_THRESH_NOCALL = -0.1; // if sum(gl) is bigger than this threshold, we treat GL's as non-informative and will force a no-call.
+
+ /**
+ * Diploid NO_CALL allele list...
+ *
+ * @deprecated you should use {@link #noCallAlleles(int)} instead. It indicates the presence of a hardcoded diploid assumption which is bad.
+ */
+ @Deprecated
+ public final static List<Allele> NO_CALL_ALLELES = Arrays.asList(Allele.NO_CALL, Allele.NO_CALL);
+
+ public final static String NON_REF_SYMBOLIC_ALLELE_NAME = "NON_REF";
+ public final static Allele NON_REF_SYMBOLIC_ALLELE = Allele.create("<"+NON_REF_SYMBOLIC_ALLELE_NAME+">", false); // represents any possible non-ref allele at this site
+
+ public final static String MERGE_FILTER_PREFIX = "filterIn";
+ public final static String MERGE_REF_IN_ALL = "ReferenceInAll";
+ public final static String MERGE_FILTER_IN_ALL = "FilteredInAll";
+ public final static String MERGE_INTERSECTION = "Intersection";
+
+ /**
+ * Checks whether a variant-context overlaps with a region.
+ *
+ * <p>
+ * No event overlaps an unmapped region.
+ * </p>
+ *
+ * @param variantContext variant-context to test the overlap with.
+ * @param region region to test the overlap with.
+ *
+ * @throws IllegalArgumentException if either region or event is {@code null}.
+ *
+ * @return {@code true} if there is an overlap between the event described and the active region provided.
+ */
+ public static boolean overlapsRegion(final VariantContext variantContext, final GenomeLoc region) {
+ if (region == null) throw new IllegalArgumentException("the active region provided cannot be null");
+ if (variantContext == null) throw new IllegalArgumentException("the variant context provided cannot be null");
+ if (region.isUnmapped())
+ return false;
+ if (variantContext.getEnd() < region.getStart())
+ return false;
+ if (variantContext.getStart() > region.getStop())
+ return false;
+ if (!variantContext.getChr().equals(region.getContig()))
+ return false;
+ return true;
+ }
+
+ /**
+ * Returns a homozygous call allele list given the only allele and the ploidy.
+ *
+ * @param allele the only allele in the allele list.
+ * @param ploidy the ploidy of the resulting allele list.
+ *
+ * @throws IllegalArgumentException if {@code allele} is {@code null} or ploidy is negative.
+ *
+ * @return never {@code null}.
+ */
+ public static List<Allele> homozygousAlleleList(final Allele allele, final int ploidy) {
+ if (allele == null || ploidy < 0)
+ throw new IllegalArgumentException();
+
+ // Use a tailored inner class to implement the list:
+ return Collections.nCopies(ploidy,allele);
+ }
+
+ private static boolean hasPLIncompatibleAlleles(final Collection<Allele> alleleSet1, final Collection<Allele> alleleSet2) {
+ final Iterator<Allele> it1 = alleleSet1.iterator();
+ final Iterator<Allele> it2 = alleleSet2.iterator();
+
+ while ( it1.hasNext() && it2.hasNext() ) {
+ final Allele a1 = it1.next();
+ final Allele a2 = it2.next();
+ if ( ! a1.equals(a2) )
+ return true;
+ }
+
+ // by this point, at least one of the iterators is empty. All of the elements
+ // we've compared are equal up until this point. But it's possible that the
+ // sets aren't the same size, which is indicated by the test below. If they
+ // are of the same size, though, the sets are compatible
+ return it1.hasNext() || it2.hasNext();
+ }
+
+ /**
+ * Determines the common reference allele
+ *
+ * @param VCs the list of VariantContexts
+ * @param loc if not null, ignore records that do not begin at this start location
+ * @return possibly null Allele
+ */
+ protected static Allele determineReferenceAllele(final List<VariantContext> VCs, final GenomeLoc loc) {
+ Allele ref = null;
+
+ for ( final VariantContext vc : VCs ) {
+ if ( contextMatchesLoc(vc, loc) ) {
+ final Allele myRef = vc.getReference();
+ if ( ref == null || ref.length() < myRef.length() )
+ ref = myRef;
+ else if ( ref.length() == myRef.length() && ! ref.equals(myRef) )
+ throw new TribbleException(String.format("The provided variant file(s) have inconsistent references for the same position(s) at %s:%d, %s vs. %s", vc.getChr(), vc.getStart(), ref, myRef));
+ }
+ }
+
+ return ref;
+ }
+
+ /**
+ * Calculates the total ploidy of a variant context as the sum of all plodies across genotypes.
+ * @param vc the target variant context.
+ * @param defaultPloidy the default ploidy to be assume when there is no ploidy information for a genotype.
+ * @return never {@code null}.
+ */
+ public static int totalPloidy(final VariantContext vc, final int defaultPloidy) {
+ if (vc == null)
+ throw new IllegalArgumentException("the vc provided cannot be null");
+ if (defaultPloidy < 0)
+ throw new IllegalArgumentException("the default ploidy must 0 or greater");
+ int result = 0;
+ for (final Genotype genotype : vc.getGenotypes()) {
+ final int declaredPloidy = genotype.getPloidy();
+ result += declaredPloidy <= 0 ? defaultPloidy : declaredPloidy;
+ }
+
+ return result;
+ }
+
+ public enum GenotypeMergeType {
+ /**
+ * Make all sample genotypes unique by file. Each sample shared across RODs gets named sample.ROD.
+ */
+ UNIQUIFY,
+ /**
+ * Take genotypes in priority order (see the priority argument).
+ */
+ PRIORITIZE,
+ /**
+ * Take the genotypes in any order.
+ */
+ UNSORTED,
+ /**
+ * Require that all samples/genotypes be unique between all inputs.
+ */
+ REQUIRE_UNIQUE
+ }
+
+ public enum FilteredRecordMergeType {
+ /**
+ * Union - leaves the record if any record is unfiltered.
+ */
+ KEEP_IF_ANY_UNFILTERED,
+ /**
+ * Requires all records present at site to be unfiltered. VCF files that don't contain the record don't influence this.
+ */
+ KEEP_IF_ALL_UNFILTERED,
+ /**
+ * If any record is present at this site (regardless of possibly being filtered), then all such records are kept and the filters are reset.
+ */
+ KEEP_UNCONDITIONAL
+ }
+
+ public enum MultipleAllelesMergeType {
+ /**
+ * Combine only alleles of the same type (SNP, indel, etc.) into a single VCF record.
+ */
+ BY_TYPE,
+ /**
+ * Merge all allele types at the same start position into the same VCF record.
+ */
+ MIX_TYPES
+ }
+
+ /**
+ * Refactored out of the AverageAltAlleleLength annotation class
+ * @param vc the variant context
+ * @return the average length of the alt allele (a double)
+ */
+ public static double getMeanAltAlleleLength(VariantContext vc) {
+ double averageLength = 1.0;
+ if ( ! vc.isSNP() && ! vc.isSymbolic() ) {
+ // adjust for the event length
+ int averageLengthNum = 0;
+ int averageLengthDenom = 0;
+ int refLength = vc.getReference().length();
+ for ( final Allele a : vc.getAlternateAlleles() ) {
+ int numAllele = vc.getCalledChrCount(a);
+ int alleleSize;
+ if ( a.length() == refLength ) {
+ // SNP or MNP
+ byte[] a_bases = a.getBases();
+ byte[] ref_bases = vc.getReference().getBases();
+ int n_mismatch = 0;
+ for ( int idx = 0; idx < a_bases.length; idx++ ) {
+ if ( a_bases[idx] != ref_bases[idx] )
+ n_mismatch++;
+ }
+ alleleSize = n_mismatch;
+ }
+ else if ( a.isSymbolic() ) {
+ alleleSize = 1;
+ } else {
+ alleleSize = Math.abs(refLength-a.length());
+ }
+ averageLengthNum += alleleSize*numAllele;
+ averageLengthDenom += numAllele;
+ }
+ averageLength = ( (double) averageLengthNum )/averageLengthDenom;
+ }
+
+ return averageLength;
+ }
+
+ /**
+ * create a genome location, given a variant context
+ * @param genomeLocParser parser
+ * @param vc the variant context
+ * @return the genomeLoc
+ */
+ public static final GenomeLoc getLocation(GenomeLocParser genomeLocParser,VariantContext vc) {
+ return genomeLocParser.createGenomeLoc(vc.getChr(), vc.getStart(), vc.getEnd(), true);
+ }
+
+ public static BaseUtils.BaseSubstitutionType getSNPSubstitutionType(VariantContext context) {
+ if (!context.isSNP() || !context.isBiallelic())
+ throw new IllegalStateException("Requested SNP substitution type for bialleic non-SNP " + context);
+ return BaseUtils.SNPSubstitutionType(context.getReference().getBases()[0], context.getAlternateAllele(0).getBases()[0]);
+ }
+
+ /**
+ * If this is a BiAllelic SNP, is it a transition?
+ */
+ public static boolean isTransition(VariantContext context) {
+ return getSNPSubstitutionType(context) == BaseUtils.BaseSubstitutionType.TRANSITION;
+ }
+
+ /**
+ * If this is a BiAllelic SNP, is it a transversion?
+ */
+ public static boolean isTransversion(VariantContext context) {
+ return getSNPSubstitutionType(context) == BaseUtils.BaseSubstitutionType.TRANSVERSION;
+ }
+
+ public static boolean isTransition(Allele ref, Allele alt) {
+ return BaseUtils.SNPSubstitutionType(ref.getBases()[0], alt.getBases()[0]) == BaseUtils.BaseSubstitutionType.TRANSITION;
+ }
+
+ public static boolean isTransversion(Allele ref, Allele alt) {
+ return BaseUtils.SNPSubstitutionType(ref.getBases()[0], alt.getBases()[0]) == BaseUtils.BaseSubstitutionType.TRANSVERSION;
+ }
+
+ /**
+ * Returns a context identical to this with the REF and ALT alleles reverse complemented.
+ *
+ * @param vc variant context
+ * @return new vc
+ */
+ public static VariantContext reverseComplement(VariantContext vc) {
+ // create a mapping from original allele to reverse complemented allele
+ HashMap<Allele, Allele> alleleMap = new HashMap<>(vc.getAlleles().size());
+ for ( final Allele originalAllele : vc.getAlleles() ) {
+ Allele newAllele;
+ if ( originalAllele.isNoCall() )
+ newAllele = originalAllele;
+ else
+ newAllele = Allele.create(BaseUtils.simpleReverseComplement(originalAllele.getBases()), originalAllele.isReference());
+ alleleMap.put(originalAllele, newAllele);
+ }
+
+ // create new Genotype objects
+ GenotypesContext newGenotypes = GenotypesContext.create(vc.getNSamples());
+ for ( final Genotype genotype : vc.getGenotypes() ) {
+ List<Allele> newAlleles = new ArrayList<>();
+ for ( final Allele allele : genotype.getAlleles() ) {
+ Allele newAllele = alleleMap.get(allele);
+ if ( newAllele == null )
+ newAllele = Allele.NO_CALL;
+ newAlleles.add(newAllele);
+ }
+ newGenotypes.add(new GenotypeBuilder(genotype).alleles(newAlleles).make());
+ }
+
+ return new VariantContextBuilder(vc).alleles(alleleMap.values()).genotypes(newGenotypes).make();
+ }
+
+ /**
+ * Returns true iff VC is an non-complex indel where every allele represents an expansion or
+ * contraction of a series of identical bases in the reference.
+ *
+ * For example, suppose the ref bases are CTCTCTGA, which includes a 3x repeat of CTCTCT
+ *
+ * If VC = -/CT, then this function returns true because the CT insertion matches exactly the
+ * upcoming reference.
+ * If VC = -/CTA then this function returns false because the CTA isn't a perfect match
+ *
+ * Now consider deletions:
+ *
+ * If VC = CT/- then again the same logic applies and this returns true
+ * The case of CTA/- makes no sense because it doesn't actually match the reference bases.
+ *
+ * The logic of this function is pretty simple. Take all of the non-null alleles in VC. For
+ * each insertion allele of n bases, check if that allele matches the next n reference bases.
+ * For each deletion allele of n bases, check if this matches the reference bases at n - 2 n,
+ * as it must necessarily match the first n bases. If this test returns true for all
+ * alleles you are a tandem repeat, otherwise you are not.
+ *
+ * @param vc
+ * @param refBasesStartingAtVCWithPad not this is assumed to include the PADDED reference
+ * @return
+ */
+ @Requires({"vc != null", "refBasesStartingAtVCWithPad != null && refBasesStartingAtVCWithPad.length > 0"})
+ public static boolean isTandemRepeat(final VariantContext vc, final byte[] refBasesStartingAtVCWithPad) {
+ final String refBasesStartingAtVCWithoutPad = new String(refBasesStartingAtVCWithPad).substring(1);
+ if ( ! vc.isIndel() ) // only indels are tandem repeats
+ return false;
+
+ final Allele ref = vc.getReference();
+
+ for ( final Allele allele : vc.getAlternateAlleles() ) {
+ if ( ! isRepeatAllele(ref, allele, refBasesStartingAtVCWithoutPad) )
+ return false;
+ }
+
+ // we've passed all of the tests, so we are a repeat
+ return true;
+ }
+
+ /**
+ *
+ * @param vc
+ * @param refBasesStartingAtVCWithPad
+ * @return
+ */
+ @Requires({"vc != null", "refBasesStartingAtVCWithPad != null && refBasesStartingAtVCWithPad.length > 0"})
+ public static Pair<List<Integer>,byte[]> getNumTandemRepeatUnits(final VariantContext vc, final byte[] refBasesStartingAtVCWithPad) {
+ final boolean VERBOSE = false;
+ final String refBasesStartingAtVCWithoutPad = new String(refBasesStartingAtVCWithPad).substring(1);
+ if ( ! vc.isIndel() ) // only indels are tandem repeats
+ return null;
+
+ final Allele refAllele = vc.getReference();
+ final byte[] refAlleleBases = Arrays.copyOfRange(refAllele.getBases(), 1, refAllele.length());
+
+ byte[] repeatUnit = null;
+ final ArrayList<Integer> lengths = new ArrayList<>();
+
+ for ( final Allele allele : vc.getAlternateAlleles() ) {
+ Pair<int[],byte[]> result = getNumTandemRepeatUnits(refAlleleBases, Arrays.copyOfRange(allele.getBases(), 1, allele.length()), refBasesStartingAtVCWithoutPad.getBytes());
+
+ final int[] repetitionCount = result.first;
+ // repetition count = 0 means allele is not a tandem expansion of context
+ if (repetitionCount[0] == 0 || repetitionCount[1] == 0)
+ return null;
+
+ if (lengths.size() == 0) {
+ lengths.add(repetitionCount[0]); // add ref allele length only once
+ }
+ lengths.add(repetitionCount[1]); // add this alt allele's length
+
+ repeatUnit = result.second;
+ if (VERBOSE) {
+ System.out.println("RefContext:"+refBasesStartingAtVCWithoutPad);
+ System.out.println("Ref:"+refAllele.toString()+" Count:" + String.valueOf(repetitionCount[0]));
+ System.out.println("Allele:"+allele.toString()+" Count:" + String.valueOf(repetitionCount[1]));
+ System.out.println("RU:"+new String(repeatUnit));
+ }
+ }
+
+ return new Pair<List<Integer>, byte[]>(lengths,repeatUnit);
+ }
+
+ public static Pair<int[],byte[]> getNumTandemRepeatUnits(final byte[] refBases, final byte[] altBases, final byte[] remainingRefContext) {
+ /* we can't exactly apply same logic as in basesAreRepeated() to compute tandem unit and number of repeated units.
+ Consider case where ref =ATATAT and we have an insertion of ATAT. Natural description is (AT)3 -> (AT)2.
+ */
+
+ byte[] longB;
+ // find first repeat unit based on either ref or alt, whichever is longer
+ if (altBases.length > refBases.length)
+ longB = altBases;
+ else
+ longB = refBases;
+
+ // see if non-null allele (either ref or alt, whichever is longer) can be decomposed into several identical tandem units
+ // for example, -*,CACA needs to first be decomposed into (CA)2
+ final int repeatUnitLength = findRepeatedSubstring(longB);
+ final byte[] repeatUnit = Arrays.copyOf(longB, repeatUnitLength);
+
+ final int[] repetitionCount = new int[2];
+ // look for repetitions forward on the ref bases (i.e. starting at beginning of ref bases)
+ int repetitionsInRef = findNumberOfRepetitions(repeatUnit, refBases, true);
+ repetitionCount[0] = findNumberOfRepetitions(repeatUnit, ArrayUtils.addAll(refBases, remainingRefContext), true)-repetitionsInRef;
+ repetitionCount[1] = findNumberOfRepetitions(repeatUnit, ArrayUtils.addAll(altBases, remainingRefContext), true)-repetitionsInRef;
+
+ return new Pair<>(repetitionCount, repeatUnit);
+
+ }
+
+ /**
+ * Find out if a string can be represented as a tandem number of substrings.
+ * For example ACTACT is a 2-tandem of ACT,
+ * but ACTACA is not.
+ *
+ * @param bases String to be tested
+ * @return Length of repeat unit, if string can be represented as tandem of substring (if it can't
+ * be represented as one, it will be just the length of the input string)
+ */
+ public static int findRepeatedSubstring(byte[] bases) {
+
+ int repLength;
+ for (repLength=1; repLength <=bases.length; repLength++) {
+ final byte[] candidateRepeatUnit = Arrays.copyOf(bases,repLength);
+ boolean allBasesMatch = true;
+ for (int start = repLength; start < bases.length; start += repLength ) {
+ // check that remaining of string is exactly equal to repeat unit
+ final byte[] basePiece = Arrays.copyOfRange(bases,start,start+candidateRepeatUnit.length);
+ if (!Arrays.equals(candidateRepeatUnit, basePiece)) {
+ allBasesMatch = false;
+ break;
+ }
+ }
+ if (allBasesMatch)
+ return repLength;
+ }
+
+ return repLength;
+ }
+
+ /**
+ * Helper routine that finds number of repetitions a string consists of.
+ * For example, for string ATAT and repeat unit AT, number of repetitions = 2
+ * @param repeatUnit Substring
+ * @param testString String to test
+ * @oaram lookForward Look for repetitions forward (at beginning of string) or backward (at end of string)
+ * @return Number of repetitions (0 if testString is not a concatenation of n repeatUnit's
+ */
+ public static int findNumberOfRepetitions(byte[] repeatUnit, byte[] testString, boolean lookForward) {
+ int numRepeats = 0;
+ if (lookForward) {
+ // look forward on the test string
+ for (int start = 0; start < testString.length; start += repeatUnit.length) {
+ int end = start + repeatUnit.length;
+ byte[] unit = Arrays.copyOfRange(testString,start, end);
+ if(Arrays.equals(unit,repeatUnit))
+ numRepeats++;
+ else
+ break;
+ }
+ return numRepeats;
+ }
+
+ // look backward. For example, if repeatUnit = AT and testString = GATAT, number of repeat units is still 2
+ // look forward on the test string
+ for (int start = testString.length - repeatUnit.length; start >= 0; start -= repeatUnit.length) {
+ int end = start + repeatUnit.length;
+ byte[] unit = Arrays.copyOfRange(testString,start, end);
+ if(Arrays.equals(unit,repeatUnit))
+ numRepeats++;
+ else
+ break;
+ }
+ return numRepeats;
+ }
+
+ /**
+ * Helper function for isTandemRepeat that checks that allele matches somewhere on the reference
+ * @param ref
+ * @param alt
+ * @param refBasesStartingAtVCWithoutPad
+ * @return
+ */
+ protected static boolean isRepeatAllele(final Allele ref, final Allele alt, final String refBasesStartingAtVCWithoutPad) {
+ if ( ! Allele.oneIsPrefixOfOther(ref, alt) )
+ return false; // we require one allele be a prefix of another
+
+ if ( ref.length() > alt.length() ) { // we are a deletion
+ return basesAreRepeated(ref.getBaseString(), alt.getBaseString(), refBasesStartingAtVCWithoutPad, 2);
+ } else { // we are an insertion
+ return basesAreRepeated(alt.getBaseString(), ref.getBaseString(), refBasesStartingAtVCWithoutPad, 1);
+ }
+ }
+
+ protected static boolean basesAreRepeated(final String l, final String s, final String ref, final int minNumberOfMatches) {
+ final String potentialRepeat = l.substring(s.length()); // skip s bases
+
+ for ( int i = 0; i < minNumberOfMatches; i++) {
+ final int start = i * potentialRepeat.length();
+ final int end = (i+1) * potentialRepeat.length();
+ if ( ref.length() < end )
+ return false; // we ran out of bases to test
+ final String refSub = ref.substring(start, end);
+ if ( ! refSub.equals(potentialRepeat) )
+ return false; // repeat didn't match, fail
+ }
+
+ return true; // we passed all tests, we matched
+ }
+
+ public enum GenotypeAssignmentMethod {
+ /**
+ * set all of the genotype GT values to NO_CALL
+ */
+ SET_TO_NO_CALL,
+
+ /**
+ * Use the subsetted PLs to greedily assigned genotypes
+ */
+ USE_PLS_TO_ASSIGN,
+
+ /**
+ * Try to match the original GT calls, if at all possible
+ *
+ * Suppose I have 3 alleles: A/B/C and the following samples:
+ *
+ * original_GT best_match to A/B best_match to A/C
+ * S1 => A/A A/A A/A
+ * S2 => A/B A/B A/A
+ * S3 => B/B B/B A/A
+ * S4 => B/C A/B A/C
+ * S5 => C/C A/A C/C
+ *
+ * Basically, all alleles not in the subset map to ref. It means that het-alt genotypes
+ * when split into 2 bi-allelic variants will be het in each, which is good in some cases,
+ * rather than the undetermined behavior when using the PLs to assign, which could result
+ * in hom-var or hom-ref for each, depending on the exact PL values.
+ */
+ BEST_MATCH_TO_ORIGINAL,
+
+ /**
+ * do not even bother changing the GTs
+ */
+ DO_NOT_ASSIGN_GENOTYPES
+ }
+
+ /**
+ * subset the Variant Context to the specific set of alleles passed in (pruning the PLs appropriately)
+ *
+ * @param vc variant context with genotype likelihoods
+ * @param allelesToUse which alleles from the vc are okay to use; *** must be in the same relative order as those in the original VC ***
+ * @param assignGenotypes assignment strategy for the (subsetted) PLs
+ * @return a new non-null GenotypesContext
+ */
+ public static GenotypesContext subsetDiploidAlleles(final VariantContext vc,
+ final List<Allele> allelesToUse,
+ final GenotypeAssignmentMethod assignGenotypes) {
+ if ( allelesToUse.get(0).isNonReference() ) throw new IllegalArgumentException("First allele must be the reference allele");
+ if ( allelesToUse.size() == 1 ) throw new IllegalArgumentException("Cannot subset to only 1 alt allele");
+
+ // optimization: if no input genotypes, just exit
+ if (vc.getGenotypes().isEmpty()) return GenotypesContext.create();
+
+ // we need to determine which of the alternate alleles (and hence the likelihoods) to use and carry forward
+ final List<Integer> likelihoodIndexesToUse = determineLikelihoodIndexesToUse(vc, allelesToUse);
+
+ // create the new genotypes
+ return createGenotypesWithSubsettedLikelihoods(vc.getGenotypes(), vc, allelesToUse, likelihoodIndexesToUse, assignGenotypes);
+ }
+
+ /**
+ * Figure out which likelihood indexes to use for a selected down set of alleles
+ *
+ * @param originalVC the original VariantContext
+ * @param allelesToUse the subset of alleles to use
+ * @return a list of PL indexes to use or null if none
+ */
+ private static List<Integer> determineLikelihoodIndexesToUse(final VariantContext originalVC, final List<Allele> allelesToUse) {
+
+ // the bitset representing the allele indexes we want to keep
+ final boolean[] alleleIndexesToUse = getAlleleIndexBitset(originalVC, allelesToUse);
+
+ // an optimization: if we are supposed to use all (or none in the case of a ref call) of the alleles,
+ // then we can keep the PLs as is; otherwise, we determine which ones to keep
+ if ( MathUtils.countOccurrences(true, alleleIndexesToUse) == alleleIndexesToUse.length )
+ return null;
+
+ return getLikelihoodIndexes(originalVC, alleleIndexesToUse);
+ }
+
+ /**
+ * Get the actual likelihoods indexes to use given the corresponding allele indexes
+ *
+ * @param originalVC the original VariantContext
+ * @param alleleIndexesToUse the bitset representing the alleles to use (@see #getAlleleIndexBitset)
+ * @return a non-null List
+ */
+ private static List<Integer> getLikelihoodIndexes(final VariantContext originalVC, final boolean[] alleleIndexesToUse) {
+
+ final List<Integer> result = new ArrayList<>(30);
+
+ // numLikelihoods takes total # of alleles. Use default # of chromosomes (ploidy) = 2
+ final int numLikelihoods = GenotypeLikelihoods.numLikelihoods(originalVC.getNAlleles(), DEFAULT_PLOIDY);
+
+ for ( int PLindex = 0; PLindex < numLikelihoods; PLindex++ ) {
+ final GenotypeLikelihoods.GenotypeLikelihoodsAllelePair alleles = GenotypeLikelihoods.getAllelePair(PLindex);
+ // consider this entry only if both of the alleles are good
+ if ( alleleIndexesToUse[alleles.alleleIndex1] && alleleIndexesToUse[alleles.alleleIndex2] )
+ result.add(PLindex);
+ }
+
+ return result;
+ }
+
+ /**
+ * Given an original VariantContext and a list of alleles from that VC to keep,
+ * returns a bitset representing which allele indexes should be kept
+ *
+ * @param originalVC the original VC
+ * @param allelesToKeep the list of alleles to keep
+ * @return non-null bitset
+ */
+ private static boolean[] getAlleleIndexBitset(final VariantContext originalVC, final List<Allele> allelesToKeep) {
+ final int numOriginalAltAlleles = originalVC.getNAlleles() - 1;
+ final boolean[] alleleIndexesToKeep = new boolean[numOriginalAltAlleles + 1];
+
+ // the reference Allele is definitely still used
+ alleleIndexesToKeep[0] = true;
+ for ( int i = 0; i < numOriginalAltAlleles; i++ ) {
+ if ( allelesToKeep.contains(originalVC.getAlternateAllele(i)) )
+ alleleIndexesToKeep[i+1] = true;
+ }
+
+ return alleleIndexesToKeep;
+ }
+
+ /**
+ * Create the new GenotypesContext with the subsetted PLs and ADs
+ *
+ * @param originalGs the original GenotypesContext
+ * @param vc the original VariantContext
+ * @param allelesToUse the actual alleles to use with the new Genotypes
+ * @param likelihoodIndexesToUse the indexes in the PL to use given the allelesToUse (@see #determineLikelihoodIndexesToUse())
+ * @param assignGenotypes assignment strategy for the (subsetted) PLs
+ * @return a new non-null GenotypesContext
+ */
+ private static GenotypesContext createGenotypesWithSubsettedLikelihoods(final GenotypesContext originalGs,
+ final VariantContext vc,
+ final List<Allele> allelesToUse,
+ final List<Integer> likelihoodIndexesToUse,
+ final GenotypeAssignmentMethod assignGenotypes) {
+ // the new genotypes to create
+ final GenotypesContext newGTs = GenotypesContext.create(originalGs.size());
+
+ // make sure we are seeing the expected number of likelihoods per sample
+ final int expectedNumLikelihoods = GenotypeLikelihoods.numLikelihoods(vc.getNAlleles(), 2);
+
+ // the samples
+ final List<String> sampleIndices = originalGs.getSampleNamesOrderedByName();
+
+ // create the new genotypes
+ for ( int k = 0; k < originalGs.size(); k++ ) {
+ final Genotype g = originalGs.get(sampleIndices.get(k));
+ final GenotypeBuilder gb = new GenotypeBuilder(g);
+
+ // create the new likelihoods array from the alleles we are allowed to use
+ double[] newLikelihoods;
+ if ( !g.hasLikelihoods() ) {
+ // we don't have any likelihoods, so we null out PLs and make G ./.
+ newLikelihoods = null;
+ gb.noPL();
+ } else {
+ final double[] originalLikelihoods = g.getLikelihoods().getAsVector();
+ if ( likelihoodIndexesToUse == null ) {
+ newLikelihoods = originalLikelihoods;
+ } else if ( originalLikelihoods.length != expectedNumLikelihoods ) {
+ logger.debug("Wrong number of likelihoods in sample " + g.getSampleName() + " at " + vc + " got " + g.getLikelihoodsString() + " but expected " + expectedNumLikelihoods);
+ newLikelihoods = null;
+ } else {
+ newLikelihoods = new double[likelihoodIndexesToUse.size()];
+ int newIndex = 0;
+ for ( final int oldIndex : likelihoodIndexesToUse )
+ newLikelihoods[newIndex++] = originalLikelihoods[oldIndex];
+
+ // might need to re-normalize
+ newLikelihoods = MathUtils.normalizeFromLog10(newLikelihoods, false, true);
+ }
+
+ if ( newLikelihoods == null || likelihoodsAreUninformative(newLikelihoods) )
+ gb.noPL();
+ else
+ gb.PL(newLikelihoods);
+ }
+
+ updateGenotypeAfterSubsetting(g.getAlleles(), gb, assignGenotypes, newLikelihoods, allelesToUse);
+ newGTs.add(gb.make());
+ }
+
+ return fixADFromSubsettedAlleles(newGTs, vc, allelesToUse);
+ }
+
+ private static boolean likelihoodsAreUninformative(final double[] likelihoods) {
+ return MathUtils.sum(likelihoods) > SUM_GL_THRESH_NOCALL;
+ }
+
+ /**
+ * Add the genotype call (GT) field to GenotypeBuilder using the requested algorithm assignmentMethod
+ *
+ * @param originalGT the original genotype calls, cannot be null
+ * @param gb the builder where we should put our newly called alleles, cannot be null
+ * @param assignmentMethod the method to use to do the assignment, cannot be null
+ * @param newLikelihoods a vector of likelihoods to use if the method requires PLs, should be log10 likelihoods, cannot be null
+ * @param allelesToUse the alleles we are using for our subsetting
+ */
+ public static void updateGenotypeAfterSubsetting(final List<Allele> originalGT,
+ final GenotypeBuilder gb,
+ final GenotypeAssignmentMethod assignmentMethod,
+ final double[] newLikelihoods,
+ final List<Allele> allelesToUse) {
+ switch ( assignmentMethod ) {
+ case DO_NOT_ASSIGN_GENOTYPES:
+ break;
+ case SET_TO_NO_CALL:
+ gb.alleles(NO_CALL_ALLELES);
+ gb.noGQ();
+ break;
+ case USE_PLS_TO_ASSIGN:
+ if ( newLikelihoods == null || likelihoodsAreUninformative(newLikelihoods) ) {
+ // if there is no mass on the (new) likelihoods, then just no-call the sample
+ gb.alleles(NO_CALL_ALLELES);
+ gb.noGQ();
+ } else {
+ // find the genotype with maximum likelihoods
+ final int PLindex = MathUtils.maxElementIndex(newLikelihoods);
+ GenotypeLikelihoods.GenotypeLikelihoodsAllelePair alleles = GenotypeLikelihoods.getAllelePair(PLindex);
+ gb.alleles(Arrays.asList(allelesToUse.get(alleles.alleleIndex1), allelesToUse.get(alleles.alleleIndex2)));
+ gb.log10PError(GenotypeLikelihoods.getGQLog10FromLikelihoods(PLindex, newLikelihoods));
+ }
+ break;
+ case BEST_MATCH_TO_ORIGINAL:
+ final List<Allele> best = new LinkedList<>();
+ final Allele ref = allelesToUse.get(0); // WARNING -- should be checked in input argument
+ for ( final Allele originalAllele : originalGT ) {
+ best.add(allelesToUse.contains(originalAllele) ? originalAllele : ref);
+ }
+ gb.noGQ();
+ gb.noPL();
+ gb.alleles(best);
+ break;
+ }
+ }
+
+ /**
+ * Subset the samples in VC to reference only information with ref call alleles
+ *
+ * Preserves DP if present
+ *
+ * @param vc the variant context to subset down to
+ * @param ploidy ploidy to use if a genotype doesn't have any alleles
+ * @return a GenotypesContext
+ */
+ public static GenotypesContext subsetToRefOnly(final VariantContext vc, final int ploidy) {
+ if ( vc == null ) throw new IllegalArgumentException("vc cannot be null");
+ if ( ploidy < 1 ) throw new IllegalArgumentException("ploidy must be >= 1 but got " + ploidy);
+
+ // the genotypes with PLs
+ final GenotypesContext oldGTs = vc.getGenotypes();
+
+ // optimization: if no input genotypes, just exit
+ if (oldGTs.isEmpty()) return oldGTs;
+
+ // the new genotypes to create
+ final GenotypesContext newGTs = GenotypesContext.create(oldGTs.size());
+
+ final Allele ref = vc.getReference();
+ final List<Allele> diploidRefAlleles = Arrays.asList(ref, ref);
+
+ // create the new genotypes
+ for ( final Genotype g : vc.getGenotypes() ) {
+ final int gPloidy = g.getPloidy() == 0 ? ploidy : g.getPloidy();
+ final List<Allele> refAlleles = gPloidy == 2 ? diploidRefAlleles : Collections.nCopies(gPloidy, ref);
+ final GenotypeBuilder gb = new GenotypeBuilder(g.getSampleName(), refAlleles);
+ if ( g.hasDP() ) gb.DP(g.getDP());
+ if ( g.hasGQ() ) gb.GQ(g.getGQ());
+ newGTs.add(gb.make());
+ }
+
+ return newGTs;
+ }
+
+ /**
+ * Assign genotypes (GTs) to the samples in the Variant Context greedily based on the PLs
+ *
+ * @param vc variant context with genotype likelihoods
+ * @return genotypes context
+ */
+ public static GenotypesContext assignDiploidGenotypes(final VariantContext vc) {
+ return subsetDiploidAlleles(vc, vc.getAlleles(), GenotypeAssignmentMethod.USE_PLS_TO_ASSIGN);
+ }
+
+ /**
+ * Split variant context into its biallelic components if there are more than 2 alleles
+ *
+ * For VC has A/B/C alleles, returns A/B and A/C contexts.
+ * Genotypes are all no-calls now (it's not possible to fix them easily)
+ * Alleles are right trimmed to satisfy VCF conventions
+ *
+ * If vc is biallelic or non-variant it is just returned
+ *
+ * Chromosome counts are updated (but they are by definition 0)
+ *
+ * @param vc a potentially multi-allelic variant context
+ * @return a list of bi-allelic (or monomorphic) variant context
+ */
+ public static List<VariantContext> splitVariantContextToBiallelics(final VariantContext vc) {
+ return splitVariantContextToBiallelics(vc, false, GenotypeAssignmentMethod.SET_TO_NO_CALL);
+ }
+
+ /**
+ * Split variant context into its biallelic components if there are more than 2 alleles
+ *
+ * For VC has A/B/C alleles, returns A/B and A/C contexts.
+ * Genotypes are all no-calls now (it's not possible to fix them easily)
+ * Alleles are right trimmed to satisfy VCF conventions
+ *
+ * If vc is biallelic or non-variant it is just returned
+ *
+ * Chromosome counts are updated (but they are by definition 0)
+ *
+ * @param vc a potentially multi-allelic variant context
+ * @param trimLeft if true, we will also left trim alleles, potentially moving the resulting vcs forward on the genome
+ * @return a list of bi-allelic (or monomorphic) variant context
+ */
+ public static List<VariantContext> splitVariantContextToBiallelics(final VariantContext vc, final boolean trimLeft, final GenotypeAssignmentMethod genotypeAssignmentMethod) {
+ if ( ! vc.isVariant() || vc.isBiallelic() )
+ // non variant or biallelics already satisfy the contract
+ return Collections.singletonList(vc);
+ else {
+ final List<VariantContext> biallelics = new LinkedList<>();
+
+ for ( final Allele alt : vc.getAlternateAlleles() ) {
+ VariantContextBuilder builder = new VariantContextBuilder(vc);
+ final List<Allele> alleles = Arrays.asList(vc.getReference(), alt);
+ builder.alleles(alleles);
+ builder.genotypes(subsetDiploidAlleles(vc, alleles, genotypeAssignmentMethod));
+ VariantContextUtils.calculateChromosomeCounts(builder, true);
+ final VariantContext trimmed = trimAlleles(builder.make(), trimLeft, true);
+ biallelics.add(trimmed);
+ }
+
+ return biallelics;
+ }
+ }
+
+ public static Genotype removePLsAndAD(final Genotype g) {
+ return ( g.hasLikelihoods() || g.hasAD() ) ? new GenotypeBuilder(g).noPL().noAD().make() : g;
+ }
+
+ //TODO consider refactor variant-context merging code so that we share as much as possible between
+ //TODO simpleMerge and referenceConfidenceMerge
+ //TODO likely using a separate helper class or hierarchy.
+ /**
+ * Merges VariantContexts into a single hybrid. Takes genotypes for common samples in priority order, if provided.
+ * If uniquifySamples is true, the priority order is ignored and names are created by concatenating the VC name with
+ * the sample name
+ *
+ * @param unsortedVCs collection of unsorted VCs
+ * @param priorityListOfVCs priority list detailing the order in which we should grab the VCs
+ * @param filteredRecordMergeType merge type for filtered records
+ * @param genotypeMergeOptions merge option for genotypes
+ * @param annotateOrigin should we annotate the set it came from?
+ * @param printMessages should we print messages?
+ * @param setKey the key name of the set
+ * @param filteredAreUncalled are filtered records uncalled?
+ * @param mergeInfoWithMaxAC should we merge in info from the VC with maximum allele count?
+ * @return new VariantContext representing the merge of unsortedVCs
+ */
+ public static VariantContext simpleMerge(final Collection<VariantContext> unsortedVCs,
+ final List<String> priorityListOfVCs,
+ final FilteredRecordMergeType filteredRecordMergeType,
+ final GenotypeMergeType genotypeMergeOptions,
+ final boolean annotateOrigin,
+ final boolean printMessages,
+ final String setKey,
+ final boolean filteredAreUncalled,
+ final boolean mergeInfoWithMaxAC ) {
+ int originalNumOfVCs = priorityListOfVCs == null ? 0 : priorityListOfVCs.size();
+ return simpleMerge(unsortedVCs, priorityListOfVCs, originalNumOfVCs, filteredRecordMergeType, genotypeMergeOptions, annotateOrigin, printMessages, setKey, filteredAreUncalled, mergeInfoWithMaxAC);
+ }
+
+ /**
+ * Merges VariantContexts into a single hybrid. Takes genotypes for common samples in priority order, if provided.
+ * If uniquifySamples is true, the priority order is ignored and names are created by concatenating the VC name with
+ * the sample name.
+ * simpleMerge does not verify any more unique sample names EVEN if genotypeMergeOptions == GenotypeMergeType.REQUIRE_UNIQUE. One should use
+ * SampleUtils.verifyUniqueSamplesNames to check that before using simpleMerge.
+ *
+ * For more information on this method see: http://www.thedistractionnetwork.com/programmer-problem/
+ *
+ * @param unsortedVCs collection of unsorted VCs
+ * @param priorityListOfVCs priority list detailing the order in which we should grab the VCs
+ * @param filteredRecordMergeType merge type for filtered records
+ * @param genotypeMergeOptions merge option for genotypes
+ * @param annotateOrigin should we annotate the set it came from?
+ * @param printMessages should we print messages?
+ * @param setKey the key name of the set
+ * @param filteredAreUncalled are filtered records uncalled?
+ * @param mergeInfoWithMaxAC should we merge in info from the VC with maximum allele count?
+ * @return new VariantContext representing the merge of unsortedVCs
+ */
+ public static VariantContext simpleMerge(final Collection<VariantContext> unsortedVCs,
+ final List<String> priorityListOfVCs,
+ final int originalNumOfVCs,
+ final FilteredRecordMergeType filteredRecordMergeType,
+ final GenotypeMergeType genotypeMergeOptions,
+ final boolean annotateOrigin,
+ final boolean printMessages,
+ final String setKey,
+ final boolean filteredAreUncalled,
+ final boolean mergeInfoWithMaxAC ) {
+ if ( unsortedVCs == null || unsortedVCs.size() == 0 )
+ return null;
+
+ if (priorityListOfVCs != null && originalNumOfVCs != priorityListOfVCs.size())
+ throw new IllegalArgumentException("the number of the original VariantContexts must be the same as the number of VariantContexts in the priority list");
+
+ if ( annotateOrigin && priorityListOfVCs == null && originalNumOfVCs == 0)
+ throw new IllegalArgumentException("Cannot merge calls and annotate their origins without a complete priority list of VariantContexts or the number of original VariantContexts");
+
+ final List<VariantContext> preFilteredVCs = sortVariantContextsByPriority(unsortedVCs, priorityListOfVCs, genotypeMergeOptions);
+ // Make sure all variant contexts are padded with reference base in case of indels if necessary
+ List<VariantContext> VCs = new ArrayList<>();
+
+ for (final VariantContext vc : preFilteredVCs) {
+ if ( ! filteredAreUncalled || vc.isNotFiltered() )
+ VCs.add(vc);
+ }
+
+ if ( VCs.size() == 0 ) // everything is filtered out and we're filteredAreUncalled
+ return null;
+
+ // establish the baseline info from the first VC
+ final VariantContext first = VCs.get(0);
+ final String name = first.getSource();
+ final Allele refAllele = determineReferenceAllele(VCs);
+
+ final LinkedHashSet<Allele> alleles = new LinkedHashSet<>();
+ final Set<String> filters = new HashSet<>();
+ final Map<String, Object> attributes = new LinkedHashMap<>();
+ final Set<String> inconsistentAttributes = new HashSet<>();
+ final Set<String> variantSources = new HashSet<>(); // contains the set of sources we found in our set of VCs that are variant
+ final Set<String> rsIDs = new LinkedHashSet<>(1); // most of the time there's one id
+
+ VariantContext longestVC = first;
+ int depth = 0;
+ int maxAC = -1;
+ final Map<String, Object> attributesWithMaxAC = new LinkedHashMap<>();
+ double log10PError = CommonInfo.NO_LOG10_PERROR;
+ boolean anyVCHadFiltersApplied = false;
+ VariantContext vcWithMaxAC = null;
+ GenotypesContext genotypes = GenotypesContext.create();
+
+ // counting the number of filtered and variant VCs
+ int nFiltered = 0;
+
+ boolean remapped = false;
+
+ // cycle through and add info from the other VCs, making sure the loc/reference matches
+ for ( final VariantContext vc : VCs ) {
+ if ( longestVC.getStart() != vc.getStart() )
+ throw new IllegalStateException("BUG: attempting to merge VariantContexts with different start sites: first="+ first.toString() + " second=" + vc.toString());
+
+ if ( VariantContextUtils.getSize(vc) > VariantContextUtils.getSize(longestVC) )
+ longestVC = vc; // get the longest location
+
+ nFiltered += vc.isFiltered() ? 1 : 0;
+ if ( vc.isVariant() ) variantSources.add(vc.getSource());
+
+ AlleleMapper alleleMapping = resolveIncompatibleAlleles(refAllele, vc, alleles);
+ remapped = remapped || alleleMapping.needsRemapping();
+
+ alleles.addAll(alleleMapping.values());
+
+ mergeGenotypes(genotypes, vc, alleleMapping, genotypeMergeOptions == GenotypeMergeType.UNIQUIFY);
+
+ // We always take the QUAL of the first VC with a non-MISSING qual for the combined value
+ if ( log10PError == CommonInfo.NO_LOG10_PERROR )
+ log10PError = vc.getLog10PError();
+
+ filters.addAll(vc.getFilters());
+ anyVCHadFiltersApplied |= vc.filtersWereApplied();
+
+ //
+ // add attributes
+ //
+ // special case DP (add it up) and ID (just preserve it)
+ //
+ if (vc.hasAttribute(VCFConstants.DEPTH_KEY))
+ depth += vc.getAttributeAsInt(VCFConstants.DEPTH_KEY, 0);
+ if ( vc.hasID() ) rsIDs.add(vc.getID());
+ if (mergeInfoWithMaxAC && vc.hasAttribute(VCFConstants.ALLELE_COUNT_KEY)) {
+ String rawAlleleCounts = vc.getAttributeAsString(VCFConstants.ALLELE_COUNT_KEY, null);
+ // lets see if the string contains a "," separator
+ if (rawAlleleCounts.contains(VCFConstants.INFO_FIELD_ARRAY_SEPARATOR)) {
+ final List<String> alleleCountArray = Arrays.asList(rawAlleleCounts.substring(1, rawAlleleCounts.length() - 1).split(VCFConstants.INFO_FIELD_ARRAY_SEPARATOR));
+ for (final String alleleCount : alleleCountArray) {
+ final int ac = Integer.valueOf(alleleCount.trim());
+ if (ac > maxAC) {
+ maxAC = ac;
+ vcWithMaxAC = vc;
+ }
+ }
+ } else {
+ final int ac = Integer.valueOf(rawAlleleCounts);
+ if (ac > maxAC) {
+ maxAC = ac;
+ vcWithMaxAC = vc;
+ }
+ }
+ }
+
+ for (final Map.Entry<String, Object> p : vc.getAttributes().entrySet()) {
+ final String key = p.getKey();
+ final Object value = p.getValue();
+ // only output annotations that have the same value in every input VC
+ // if we don't like the key already, don't go anywhere
+ if ( ! inconsistentAttributes.contains(key) ) {
+ final boolean alreadyFound = attributes.containsKey(key);
+ final Object boundValue = attributes.get(key);
+ final boolean boundIsMissingValue = alreadyFound && boundValue.equals(VCFConstants.MISSING_VALUE_v4);
+
+ if ( alreadyFound && ! boundValue.equals(value) && ! boundIsMissingValue ) {
+ // we found the value but we're inconsistent, put it in the exclude list
+ inconsistentAttributes.add(key);
+ attributes.remove(key);
+ } else if ( ! alreadyFound || boundIsMissingValue ) { // no value
+ attributes.put(key, value);
+ }
+ }
+ }
+ }
+
+ // if we have more alternate alleles in the merged VC than in one or more of the
+ // original VCs, we need to strip out the GL/PLs (because they are no longer accurate), as well as allele-dependent attributes like AC,AF, and AD
+ for ( final VariantContext vc : VCs ) {
+ if (vc.getAlleles().size() == 1)
+ continue;
+ if ( hasPLIncompatibleAlleles(alleles, vc.getAlleles())) {
+ if ( ! genotypes.isEmpty() ) {
+ logger.debug(String.format("Stripping PLs at %s:%d-%d due to incompatible alleles merged=%s vs. single=%s",
+ vc.getChr(), vc.getStart(), vc.getEnd(), alleles, vc.getAlleles()));
+ }
+ genotypes = stripPLsAndAD(genotypes);
+ // this will remove stale AC,AF attributed from vc
+ VariantContextUtils.calculateChromosomeCounts(vc, attributes, true);
+ break;
+ }
+ }
+
+ // take the VC with the maxAC and pull the attributes into a modifiable map
+ if ( mergeInfoWithMaxAC && vcWithMaxAC != null ) {
+ attributesWithMaxAC.putAll(vcWithMaxAC.getAttributes());
+ }
+
+ // if at least one record was unfiltered and we want a union, clear all of the filters
+ if ( (filteredRecordMergeType == FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED && nFiltered != VCs.size()) || filteredRecordMergeType == FilteredRecordMergeType.KEEP_UNCONDITIONAL )
+ filters.clear();
+
+
+ if ( annotateOrigin ) { // we care about where the call came from
+ String setValue;
+ if ( nFiltered == 0 && variantSources.size() == originalNumOfVCs ) // nothing was unfiltered
+ setValue = MERGE_INTERSECTION;
+ else if ( nFiltered == VCs.size() ) // everything was filtered out
+ setValue = MERGE_FILTER_IN_ALL;
+ else if ( variantSources.isEmpty() ) // everyone was reference
+ setValue = MERGE_REF_IN_ALL;
+ else {
+ final LinkedHashSet<String> s = new LinkedHashSet<>();
+ for ( final VariantContext vc : VCs )
+ if ( vc.isVariant() )
+ s.add( vc.isFiltered() ? MERGE_FILTER_PREFIX + vc.getSource() : vc.getSource() );
+ setValue = Utils.join("-", s);
+ }
+
+ if ( setKey != null ) {
+ attributes.put(setKey, setValue);
+ if( mergeInfoWithMaxAC && vcWithMaxAC != null ) {
+ attributesWithMaxAC.put(setKey, setValue);
+ }
+ }
+ }
+
+ if ( depth > 0 )
+ attributes.put(VCFConstants.DEPTH_KEY, String.valueOf(depth));
+
+ final String ID = rsIDs.isEmpty() ? VCFConstants.EMPTY_ID_FIELD : Utils.join(",", rsIDs);
+
+ final VariantContextBuilder builder = new VariantContextBuilder().source(name).id(ID);
+ builder.loc(longestVC.getChr(), longestVC.getStart(), longestVC.getEnd());
+ builder.alleles(alleles);
+ builder.genotypes(genotypes);
+ builder.log10PError(log10PError);
+ if ( anyVCHadFiltersApplied ) {
+ builder.filters(filters.isEmpty() ? filters : new TreeSet<>(filters));
+ }
+ builder.attributes(new TreeMap<>(mergeInfoWithMaxAC ? attributesWithMaxAC : attributes));
+
+ // Trim the padded bases of all alleles if necessary
+ final VariantContext merged = builder.make();
+ if ( printMessages && remapped ) System.out.printf("Remapped => %s%n", merged);
+ return merged;
+ }
+
+ //TODO as part of a larger refactoring effort remapAlleles can be merged with createAlleleMapping.
+
+ public static GenotypesContext stripPLsAndAD(final GenotypesContext genotypes) {
+ final GenotypesContext newGs = GenotypesContext.create(genotypes.size());
+
+ for ( final Genotype g : genotypes ) {
+ newGs.add(removePLsAndAD(g));
+ }
+
+ return newGs;
+ }
+
+ /**
+ * Updates the PLs and AD of the Genotypes in the newly selected VariantContext to reflect the fact that some alleles
+ * from the original VariantContext are no longer present.
+ *
+ * @param selectedVC the selected (new) VariantContext
+ * @param originalVC the original VariantContext
+ * @return a new non-null GenotypesContext
+ */
+ public static GenotypesContext updatePLsAndAD(final VariantContext selectedVC, final VariantContext originalVC) {
+ final int numNewAlleles = selectedVC.getAlleles().size();
+ final int numOriginalAlleles = originalVC.getAlleles().size();
+
+ // if we have more alternate alleles in the selected VC than in the original VC, then something is wrong
+ if ( numNewAlleles > numOriginalAlleles )
+ throw new IllegalArgumentException("Attempting to fix PLs and AD from what appears to be a *combined* VCF and not a selected one");
+
+ final GenotypesContext oldGs = selectedVC.getGenotypes();
+
+ // if we have the same number of alternate alleles in the selected VC as in the original VC, then we don't need to fix anything
+ if ( numNewAlleles == numOriginalAlleles )
+ return oldGs;
+
+ return fixGenotypesFromSubsettedAlleles(oldGs, originalVC, selectedVC.getAlleles());
+ }
+
+ /**
+ * Fix the PLs and ADs for the GenotypesContext of a VariantContext that has been subset
+ *
+ * @param originalGs the original GenotypesContext
+ * @param originalVC the original VariantContext
+ * @param allelesToUse the new (sub)set of alleles to use
+ * @return a new non-null GenotypesContext
+ */
+ static private GenotypesContext fixGenotypesFromSubsettedAlleles(final GenotypesContext originalGs, final VariantContext originalVC, final List<Allele> allelesToUse) {
+
+ // we need to determine which of the alternate alleles (and hence the likelihoods) to use and carry forward
+ final List<Integer> likelihoodIndexesToUse = determineLikelihoodIndexesToUse(originalVC, allelesToUse);
+
+ // create the new genotypes
+ return createGenotypesWithSubsettedLikelihoods(originalGs, originalVC, allelesToUse, likelihoodIndexesToUse, GenotypeAssignmentMethod.DO_NOT_ASSIGN_GENOTYPES);
+ }
+
+ /**
+ * Fix the AD for the GenotypesContext of a VariantContext that has been subset
+ *
+ * @param originalGs the original GenotypesContext
+ * @param originalVC the original VariantContext
+ * @param allelesToUse the new (sub)set of alleles to use
+ * @return a new non-null GenotypesContext
+ */
+ static private GenotypesContext fixADFromSubsettedAlleles(final GenotypesContext originalGs, final VariantContext originalVC, final List<Allele> allelesToUse) {
+
+ // the bitset representing the allele indexes we want to keep
+ final boolean[] alleleIndexesToUse = getAlleleIndexBitset(originalVC, allelesToUse);
+
+ // the new genotypes to create
+ final GenotypesContext newGTs = GenotypesContext.create(originalGs.size());
+
+ // the samples
+ final List<String> sampleIndices = originalGs.getSampleNamesOrderedByName();
+
+ // create the new genotypes
+ for ( int k = 0; k < originalGs.size(); k++ ) {
+ final Genotype g = originalGs.get(sampleIndices.get(k));
+ newGTs.add(fixAD(g, alleleIndexesToUse, allelesToUse.size()));
+ }
+
+ return newGTs;
+ }
+
+ /**
+ * Fix the AD for the given Genotype
+ *
+ * @param genotype the original Genotype
+ * @param alleleIndexesToUse a bitset describing whether or not to keep a given index
+ * @param nAllelesToUse how many alleles we are keeping
+ * @return a non-null Genotype
+ */
+ private static Genotype fixAD(final Genotype genotype, final boolean[] alleleIndexesToUse, final int nAllelesToUse) {
+ // if it ain't broke don't fix it
+ if ( !genotype.hasAD() )
+ return genotype;
+
+ final GenotypeBuilder builder = new GenotypeBuilder(genotype);
+
+ final int[] oldAD = genotype.getAD();
+ if ( oldAD.length != alleleIndexesToUse.length ) {
+ builder.noAD();
+ } else {
+ final int[] newAD = new int[nAllelesToUse];
+ int currentIndex = 0;
+ for ( int i = 0; i < oldAD.length; i++ ) {
+ if ( alleleIndexesToUse[i] )
+ newAD[currentIndex++] = oldAD[i];
+ }
+ builder.AD(newAD);
+ }
+ return builder.make();
+ }
+
+ private static Allele determineReferenceAllele(final List<VariantContext> VCs) {
+ return determineReferenceAllele(VCs, null);
+ }
+
+ public static boolean contextMatchesLoc(final VariantContext vc, final GenomeLoc loc) {
+ return loc == null || loc.getStart() == vc.getStart();
+ }
+
+ static private AlleleMapper resolveIncompatibleAlleles(final Allele refAllele, final VariantContext vc, final LinkedHashSet<Allele> allAlleles) {
+ if ( refAllele.equals(vc.getReference()) )
+ return new AlleleMapper(vc);
+ else {
+ final Map<Allele, Allele> map = createAlleleMapping(refAllele, vc, allAlleles);
+ map.put(vc.getReference(), refAllele);
+ return new AlleleMapper(map);
+ }
+ }
+
+ //TODO as part of a larger refactoring effort {@link #createAlleleMapping} can be merged with {@link ReferenceConfidenceVariantContextMerger#remapAlleles}.
+ /**
+ * Create an allele mapping for the given context where its reference allele must (potentially) be extended to the given allele
+ *
+ * The refAllele is the longest reference allele seen at this start site.
+ * So imagine it is:
+ * refAllele: ACGTGA
+ * myRef: ACGT
+ * myAlt: A
+ *
+ * We need to remap all of the alleles in vc to include the extra GA so that
+ * myRef => refAllele and myAlt => AGA
+ *
+ * @param refAllele the new (extended) reference allele
+ * @param oneVC the Variant Context to extend
+ * @param currentAlleles the list of alleles already created
+ * @return a non-null mapping of original alleles to new (extended) ones
+ */
+ private static Map<Allele, Allele> createAlleleMapping(final Allele refAllele,
+ final VariantContext oneVC,
+ final Collection<Allele> currentAlleles) {
+ final Allele myRef = oneVC.getReference();
+ if ( refAllele.length() <= myRef.length() ) throw new IllegalStateException("BUG: myRef="+myRef+" is longer than refAllele="+refAllele);
+
+ final byte[] extraBases = Arrays.copyOfRange(refAllele.getBases(), myRef.length(), refAllele.length());
+
+ final Map<Allele, Allele> map = new HashMap<>();
+ for ( final Allele a : oneVC.getAlternateAlleles() ) {
+ if ( isUsableAlternateAllele(a) ) {
+ Allele extended = Allele.extend(a, extraBases);
+ for ( final Allele b : currentAlleles )
+ if ( extended.equals(b) )
+ extended = b;
+ map.put(a, extended);
+ }
+ }
+
+ return map;
+ }
+
+ static private boolean isUsableAlternateAllele(final Allele allele) {
+ return ! (allele.isReference() || allele.isSymbolic() );
+ }
+
+ public static List<VariantContext> sortVariantContextsByPriority(Collection<VariantContext> unsortedVCs, List<String> priorityListOfVCs, GenotypeMergeType mergeOption ) {
+ if ( mergeOption == GenotypeMergeType.PRIORITIZE && priorityListOfVCs == null )
+ throw new IllegalArgumentException("Cannot merge calls by priority with a null priority list");
+
+ if ( priorityListOfVCs == null || mergeOption == GenotypeMergeType.UNSORTED )
+ return new ArrayList<>(unsortedVCs);
+ else {
+ ArrayList<VariantContext> sorted = new ArrayList<>(unsortedVCs);
+ Collections.sort(sorted, new CompareByPriority(priorityListOfVCs));
+ return sorted;
+ }
+ }
+
+ private static void mergeGenotypes(GenotypesContext mergedGenotypes, VariantContext oneVC, AlleleMapper alleleMapping, boolean uniquifySamples) {
+ //TODO: should we add a check for cases when the genotypeMergeOption is REQUIRE_UNIQUE
+ for ( final Genotype g : oneVC.getGenotypes() ) {
+ final String name = mergedSampleName(oneVC.getSource(), g.getSampleName(), uniquifySamples);
+ if ( ! mergedGenotypes.containsSample(name) ) {
+ // only add if the name is new
+ Genotype newG = g;
+
+ if ( uniquifySamples || alleleMapping.needsRemapping() ) {
+ final List<Allele> alleles = alleleMapping.needsRemapping() ? alleleMapping.remap(g.getAlleles()) : g.getAlleles();
+ newG = new GenotypeBuilder(g).name(name).alleles(alleles).make();
+ }
+
+ mergedGenotypes.add(newG);
+ }
+ }
+ }
+
+ /**
+ * Cached NO_CALL immutable lists where the position ith contains the list with i elements.
+ */
+ private static List<Allele>[] NOCALL_LISTS = new List[] {
+ Collections.emptyList(),
+ Collections.singletonList(Allele.NO_CALL),
+ Collections.nCopies(2,Allele.NO_CALL)
+ };
+
+ /**
+ * Synchronized code to ensure that {@link #NOCALL_LISTS} has enough entries beyod the requested ploidy
+ * @param capacity the requested ploidy.
+ */
+ private static synchronized void ensureNoCallListsCapacity(final int capacity) {
+ final int currentCapacity = NOCALL_LISTS.length - 1;
+ if (currentCapacity >= capacity)
+ return;
+ NOCALL_LISTS = Arrays.copyOf(NOCALL_LISTS,Math.max(capacity,currentCapacity << 1) + 1);
+ for (int i = currentCapacity + 1; i < NOCALL_LISTS.length; i++)
+ NOCALL_LISTS[i] = Collections.nCopies(i,Allele.NO_CALL);
+ }
+
+ /**
+ * Returns a {@link Allele#NO_CALL NO_CALL} allele list provided the ploidy.
+ *
+ * @param ploidy the required ploidy.
+ *
+ * @return never {@code null}, but an empty list if {@code ploidy} is equal or less than 0. The returned list
+ * might or might not be mutable.
+ */
+ public static List<Allele> noCallAlleles(final int ploidy) {
+ if (NOCALL_LISTS.length <= ploidy)
+ ensureNoCallListsCapacity(ploidy);
+ return NOCALL_LISTS[ploidy];
+ }
+
+
+ /**
+ * This is just a safe wrapper around GenotypeLikelihoods.calculatePLindex()
+ *
+ * @param originalIndex1 the index of the first allele
+ * @param originalIndex2 the index of the second allele
+ * @return the PL index
+ */
+ protected static int calculatePLindexFromUnorderedIndexes(final int originalIndex1, final int originalIndex2) {
+ // we need to make sure they are ordered correctly
+ return ( originalIndex2 < originalIndex1 ) ? GenotypeLikelihoods.calculatePLindex(originalIndex2, originalIndex1) : GenotypeLikelihoods.calculatePLindex(originalIndex1, originalIndex2);
+ }
+
+ public static String mergedSampleName(String trackName, String sampleName, boolean uniquify ) {
+ return uniquify ? sampleName + "." + trackName : sampleName;
+ }
+
+ /**
+ * Trim the alleles in inputVC from the reverse direction
+ *
+ * @param inputVC a non-null input VC whose alleles might need a haircut
+ * @return a non-null VariantContext (may be == to inputVC) with alleles trimmed up
+ */
+ public static VariantContext reverseTrimAlleles( final VariantContext inputVC ) {
+ return trimAlleles(inputVC, false, true);
+ }
+
+ /**
+ * Trim the alleles in inputVC from the forward direction
+ *
+ * @param inputVC a non-null input VC whose alleles might need a haircut
+ * @return a non-null VariantContext (may be == to inputVC) with alleles trimmed up
+ */
+ public static VariantContext forwardTrimAlleles( final VariantContext inputVC ) {
+ return trimAlleles(inputVC, true, false);
+ }
+
+ /**
+ * Trim the alleles in inputVC forward and reverse, as requested
+ *
+ * @param inputVC a non-null input VC whose alleles might need a haircut
+ * @param trimForward should we trim up the alleles from the forward direction?
+ * @param trimReverse should we trim up the alleles from the reverse direction?
+ * @return a non-null VariantContext (may be == to inputVC) with trimmed up alleles
+ */
+ @Ensures("result != null")
+ public static VariantContext trimAlleles(final VariantContext inputVC, final boolean trimForward, final boolean trimReverse) {
+ if ( inputVC == null ) throw new IllegalArgumentException("inputVC cannot be null");
+
+ if ( inputVC.getNAlleles() <= 1 || inputVC.isSNP() )
+ return inputVC;
+
+ // see whether we need to trim common reference base from all alleles
+ final int revTrim = trimReverse ? computeReverseClipping(inputVC.getAlleles(), inputVC.getReference().getDisplayString().getBytes()) : 0;
+ final VariantContext revTrimVC = trimAlleles(inputVC, -1, revTrim);
+ final int fwdTrim = trimForward ? computeForwardClipping(revTrimVC.getAlleles()) : -1;
+ final VariantContext vc= trimAlleles(revTrimVC, fwdTrim, 0);
+ return vc;
+ }
+
+ /**
+ * Trim up alleles in inputVC, cutting out all bases up to fwdTrimEnd inclusive and
+ * the last revTrim bases from the end
+ *
+ * @param inputVC a non-null input VC
+ * @param fwdTrimEnd bases up to this index (can be -1) will be removed from the start of all alleles
+ * @param revTrim the last revTrim bases of each allele will be clipped off as well
+ * @return a non-null VariantContext (may be == to inputVC) with trimmed up alleles
+ */
+ @Requires({"inputVC != null"})
+ @Ensures("result != null")
+ protected static VariantContext trimAlleles(final VariantContext inputVC,
+ final int fwdTrimEnd,
+ final int revTrim) {
+ if( fwdTrimEnd == -1 && revTrim == 0 ) // nothing to do, so just return inputVC unmodified
+ return inputVC;
+
+ final List<Allele> alleles = new LinkedList<>();
+ final Map<Allele, Allele> originalToTrimmedAlleleMap = new HashMap<>();
+
+ for (final Allele a : inputVC.getAlleles()) {
+ if (a.isSymbolic()) {
+ alleles.add(a);
+ originalToTrimmedAlleleMap.put(a, a);
+ } else {
+ // get bases for current allele and create a new one with trimmed bases
+ final byte[] newBases = Arrays.copyOfRange(a.getBases(), fwdTrimEnd+1, a.length()-revTrim);
+ final Allele trimmedAllele = Allele.create(newBases, a.isReference());
+ alleles.add(trimmedAllele);
+ originalToTrimmedAlleleMap.put(a, trimmedAllele);
+ }
+ }
+
+ // now we can recreate new genotypes with trimmed alleles
+ final AlleleMapper alleleMapper = new AlleleMapper(originalToTrimmedAlleleMap);
+ final GenotypesContext genotypes = updateGenotypesWithMappedAlleles(inputVC.getGenotypes(), alleleMapper);
+
+ final int start = inputVC.getStart() + (fwdTrimEnd + 1);
+ final VariantContextBuilder builder = new VariantContextBuilder(inputVC);
+ builder.start(start);
+ builder.stop(start + alleles.get(0).length() - 1);
+ builder.alleles(alleles);
+ builder.genotypes(genotypes);
+ return builder.make();
+ }
+
+ @Requires("originalGenotypes != null && alleleMapper != null")
+ protected static GenotypesContext updateGenotypesWithMappedAlleles(final GenotypesContext originalGenotypes, final AlleleMapper alleleMapper) {
+ final GenotypesContext updatedGenotypes = GenotypesContext.create(originalGenotypes.size());
+
+ for ( final Genotype genotype : originalGenotypes ) {
+ final List<Allele> updatedAlleles = alleleMapper.remap(genotype.getAlleles());
+ updatedGenotypes.add(new GenotypeBuilder(genotype).alleles(updatedAlleles).make());
+ }
+
+ return updatedGenotypes;
+ }
+
+ public static int computeReverseClipping(final List<Allele> unclippedAlleles, final byte[] ref) {
+ int clipping = 0;
+ boolean stillClipping = true;
+
+ while ( stillClipping ) {
+ for ( final Allele a : unclippedAlleles ) {
+ if ( a.isSymbolic() )
+ continue;
+
+ // we need to ensure that we don't reverse clip out all of the bases from an allele because we then will have the wrong
+ // position set for the VariantContext (although it's okay to forward clip it all out, because the position will be fine).
+ if ( a.length() - clipping == 0 )
+ return clipping - 1;
+
+ if ( a.length() - clipping <= 0 || a.length() == 0 ) {
+ stillClipping = false;
+ }
+ else if ( ref.length == clipping ) {
+ return -1;
+ }
+ else if ( a.getBases()[a.length()-clipping-1] != ref[ref.length-clipping-1] ) {
+ stillClipping = false;
+ }
+ }
+ if ( stillClipping )
+ clipping++;
+ }
+
+ return clipping;
+ }
+
+ /**
+ * Clip out any unnecessary bases off the front of the alleles
+ *
+ * The VCF spec represents alleles as block substitutions, replacing AC with A for a
+ * 1 bp deletion of the C. However, it's possible that we'd end up with alleles that
+ * contain extra bases on the left, such as GAC/GA to represent the same 1 bp deletion.
+ * This routine finds an offset among all alleles that can be safely trimmed
+ * off the left of each allele and still represent the same block substitution.
+ *
+ * A/C => A/C
+ * AC/A => AC/A
+ * ACC/AC => CC/C
+ * AGT/CAT => AGT/CAT
+ * <DEL>/C => <DEL>/C
+ *
+ * @param unclippedAlleles a non-null list of alleles that we want to clip
+ * @return the offset into the alleles where we can safely clip, inclusive, or
+ * -1 if no clipping is tolerated. So, if the result is 0, then we can remove
+ * the first base of every allele. If the result is 1, we can remove the
+ * second base.
+ */
+ public static int computeForwardClipping(final List<Allele> unclippedAlleles) {
+ // cannot clip unless there's at least 1 alt allele
+ if ( unclippedAlleles.size() <= 1 )
+ return -1;
+
+ // we cannot forward clip any set of alleles containing a symbolic allele
+ int minAlleleLength = Integer.MAX_VALUE;
+ for ( final Allele a : unclippedAlleles ) {
+ if ( a.isSymbolic() )
+ return -1;
+ minAlleleLength = Math.min(minAlleleLength, a.length());
+ }
+
+ final byte[] firstAlleleBases = unclippedAlleles.get(0).getBases();
+ int indexOflastSharedBase = -1;
+
+ // the -1 to the stop is that we can never clip off the right most base
+ for ( int i = 0; i < minAlleleLength - 1; i++) {
+ final byte base = firstAlleleBases[i];
+
+ for ( final Allele allele : unclippedAlleles ) {
+ if ( allele.getBases()[i] != base )
+ return indexOflastSharedBase;
+ }
+
+ indexOflastSharedBase = i;
+ }
+
+ return indexOflastSharedBase;
+ }
+
+ public static double computeHardyWeinbergPvalue(VariantContext vc) {
+ if ( vc.getCalledChrCount() == 0 )
+ return 0.0;
+ return HardyWeinbergCalculation.hwCalculate(vc.getHomRefCount(), vc.getHetCount(), vc.getHomVarCount());
+ }
+
+ public static boolean requiresPaddingBase(final List<String> alleles) {
+
+ // see whether one of the alleles would be null if trimmed through
+
+ for ( final String allele : alleles ) {
+ if ( allele.isEmpty() )
+ return true;
+ }
+
+ int clipping = 0;
+ Character currentBase = null;
+
+ while ( true ) {
+ for ( final String allele : alleles ) {
+ if ( allele.length() - clipping == 0 )
+ return true;
+
+ char myBase = allele.charAt(clipping);
+ if ( currentBase == null )
+ currentBase = myBase;
+ else if ( currentBase != myBase )
+ return false;
+ }
+
+ clipping++;
+ currentBase = null;
+ }
+ }
+
+ private final static Map<String, Object> subsetAttributes(final CommonInfo igc, final Collection<String> keysToPreserve) {
+ Map<String, Object> attributes = new HashMap<>(keysToPreserve.size());
+ for ( final String key : keysToPreserve ) {
+ if ( igc.hasAttribute(key) )
+ attributes.put(key, igc.getAttribute(key));
+ }
+ return attributes;
+ }
+
+ /**
+ * @deprecated use variant context builder version instead
+ * @param vc the variant context
+ * @param keysToPreserve the keys to preserve
+ * @return a pruned version of the original variant context
+ */
+ @Deprecated
+ public static VariantContext pruneVariantContext(final VariantContext vc, Collection<String> keysToPreserve ) {
+ return pruneVariantContext(new VariantContextBuilder(vc), keysToPreserve).make();
+ }
+
+ public static VariantContextBuilder pruneVariantContext(final VariantContextBuilder builder, Collection<String> keysToPreserve ) {
+ final VariantContext vc = builder.make();
+ if ( keysToPreserve == null ) keysToPreserve = Collections.emptyList();
+
+ // VC info
+ final Map<String, Object> attributes = subsetAttributes(vc.getCommonInfo(), keysToPreserve);
+
+ // Genotypes
+ final GenotypesContext genotypes = GenotypesContext.create(vc.getNSamples());
+ for ( final Genotype g : vc.getGenotypes() ) {
+ final GenotypeBuilder gb = new GenotypeBuilder(g);
+ // remove AD, DP, PL, and all extended attributes, keeping just GT and GQ
+ gb.noAD().noDP().noPL().noAttributes();
+ genotypes.add(gb.make());
+ }
+
+ return builder.genotypes(genotypes).attributes(attributes);
+ }
+
+ public static boolean allelesAreSubset(VariantContext vc1, VariantContext vc2) {
+ // if all alleles of vc1 are a contained in alleles of vc2, return true
+ if (!vc1.getReference().equals(vc2.getReference()))
+ return false;
+
+ for (final Allele a :vc1.getAlternateAlleles()) {
+ if (!vc2.getAlternateAlleles().contains(a))
+ return false;
+ }
+
+ return true;
+ }
+
+ public static Map<VariantContext.Type, List<VariantContext>> separateVariantContextsByType( final Collection<VariantContext> VCs ) {
+ if( VCs == null ) { throw new IllegalArgumentException("VCs cannot be null."); }
+
+ final HashMap<VariantContext.Type, List<VariantContext>> mappedVCs = new HashMap<>();
+ for ( final VariantContext vc : VCs ) {
+ VariantContext.Type vcType = vc.getType();
+
+ // look at previous variant contexts of different type. If:
+ // a) otherVC has alleles which are subset of vc, remove otherVC from its list and add otherVC to vc's list
+ // b) vc has alleles which are subset of otherVC. Then, add vc to otherVC's type list (rather, do nothing since vc will be added automatically to its list)
+ // c) neither: do nothing, just add vc to its own list
+ boolean addtoOwnList = true;
+ for (final VariantContext.Type type : VariantContext.Type.values()) {
+ if (type.equals(vcType))
+ continue;
+
+ if (!mappedVCs.containsKey(type))
+ continue;
+
+ List<VariantContext> vcList = mappedVCs.get(type);
+ for (int k=0; k < vcList.size(); k++) {
+ VariantContext otherVC = vcList.get(k);
+ if (allelesAreSubset(otherVC,vc)) {
+ // otherVC has a type different than vc and its alleles are a subset of vc: remove otherVC from its list and add it to vc's type list
+ vcList.remove(k);
+ // avoid having empty lists
+ if (vcList.size() == 0)
+ mappedVCs.remove(type);
+ if ( !mappedVCs.containsKey(vcType) )
+ mappedVCs.put(vcType, new ArrayList<VariantContext>());
+ mappedVCs.get(vcType).add(otherVC);
+ break;
+ }
+ else if (allelesAreSubset(vc,otherVC)) {
+ // vc has a type different than otherVC and its alleles are a subset of VC: add vc to otherVC's type list and don't add to its own
+ mappedVCs.get(type).add(vc);
+ addtoOwnList = false;
+ break;
+ }
+ }
+ }
+ if (addtoOwnList) {
+ if ( !mappedVCs.containsKey(vcType) )
+ mappedVCs.put(vcType, new ArrayList<VariantContext>());
+ mappedVCs.get(vcType).add(vc);
+ }
+ }
+
+ return mappedVCs;
+ }
+
+ public static VariantContext purgeUnallowedGenotypeAttributes(VariantContext vc, Set<String> allowedAttributes) {
+ if ( allowedAttributes == null )
+ return vc;
+
+ final GenotypesContext newGenotypes = GenotypesContext.create(vc.getNSamples());
+ for ( final Genotype genotype : vc.getGenotypes() ) {
+ final Map<String, Object> attrs = new HashMap<>();
+ for ( final Map.Entry<String, Object> attr : genotype.getExtendedAttributes().entrySet() ) {
+ if ( allowedAttributes.contains(attr.getKey()) )
+ attrs.put(attr.getKey(), attr.getValue());
+ }
+ newGenotypes.add(new GenotypeBuilder(genotype).attributes(attrs).make());
+ }
+
+ return new VariantContextBuilder(vc).genotypes(newGenotypes).make();
+ }
+
+ protected static class AlleleMapper {
+ private VariantContext vc = null;
+ private Map<Allele, Allele> map = null;
+ public AlleleMapper(VariantContext vc) { this.vc = vc; }
+ public AlleleMapper(Map<Allele, Allele> map) { this.map = map; }
+ public boolean needsRemapping() { return this.map != null; }
+ public Collection<Allele> values() { return map != null ? map.values() : vc.getAlleles(); }
+ public Allele remap(Allele a) { return map != null && map.containsKey(a) ? map.get(a) : a; }
+
+ public List<Allele> remap(List<Allele> as) {
+ List<Allele> newAs = new ArrayList<>();
+ for ( final Allele a : as ) {
+ //System.out.printf(" Remapping %s => %s%n", a, remap(a));
+ newAs.add(remap(a));
+ }
+ return newAs;
+ }
+
+ /**
+ * @return the list of unique values
+ */
+ public List<Allele> getUniqueMappedAlleles() {
+ if ( map == null )
+ return Collections.emptyList();
+ return new ArrayList<>(new HashSet<>(map.values()));
+ }
+ }
+
+ private static class CompareByPriority implements Comparator<VariantContext>, Serializable {
+ List<String> priorityListOfVCs;
+ public CompareByPriority(List<String> priorityListOfVCs) {
+ this.priorityListOfVCs = priorityListOfVCs;
+ }
+
+ private int getIndex(VariantContext vc) {
+ int i = priorityListOfVCs.indexOf(vc.getSource());
+ if ( i == -1 ) throw new IllegalArgumentException("Priority list " + priorityListOfVCs + " doesn't contain variant context " + vc.getSource());
+ return i;
+ }
+
+ public int compare(VariantContext vc1, VariantContext vc2) {
+ return Integer.valueOf(getIndex(vc1)).compareTo(getIndex(vc2));
+ }
+ }
+
+ /**
+ * For testing purposes only. Create a site-only VariantContext at contig:start containing alleles
+ *
+ * @param name the name of the VC
+ * @param contig the contig for the VC
+ * @param start the start of the VC
+ * @param alleleStrings a non-null, non-empty list of strings for the alleles. The first will be the ref allele, and others the
+ * alt. Will compute the stop of the VC from the length of the reference allele
+ * @return a non-null VariantContext
+ */
+ public static VariantContext makeFromAlleles(final String name, final String contig, final int start, final List<String> alleleStrings) {
+ if ( alleleStrings == null || alleleStrings.isEmpty() )
+ throw new IllegalArgumentException("alleleStrings must be non-empty, non-null list");
+
+ final List<Allele> alleles = new LinkedList<>();
+ final int length = alleleStrings.get(0).length();
+
+ boolean first = true;
+ for ( final String alleleString : alleleStrings ) {
+ alleles.add(Allele.create(alleleString, first));
+ first = false;
+ }
+ return new VariantContextBuilder(name, contig, start, start+length-1, alleles).make();
+ }
+
+ /**
+ * Splits the alleles for the provided variant context into its primitive parts.
+ * Requires that the input VC be bi-allelic, so calling methods should first call splitVariantContextToBiallelics() if needed.
+ * Currently works only for MNPs.
+ *
+ * @param vc the non-null VC to split
+ * @return a non-empty list of VCs split into primitive parts or the original VC otherwise
+ */
+ public static List<VariantContext> splitIntoPrimitiveAlleles(final VariantContext vc) {
+ if ( vc == null )
+ throw new IllegalArgumentException("Trying to break a null Variant Context into primitive parts");
+
+ if ( !vc.isBiallelic() )
+ throw new IllegalArgumentException("Trying to break a multi-allelic Variant Context into primitive parts");
+
+ // currently only works for MNPs
+ if ( !vc.isMNP() )
+ return Arrays.asList(vc);
+
+ final byte[] ref = vc.getReference().getBases();
+ final byte[] alt = vc.getAlternateAllele(0).getBases();
+
+ if ( ref.length != alt.length )
+ throw new IllegalStateException("ref and alt alleles for MNP have different lengths");
+
+ final List<VariantContext> result = new ArrayList<>(ref.length);
+
+ for ( int i = 0; i < ref.length; i++ ) {
+
+ // if the ref and alt bases are different at a given position, create a new SNP record (otherwise do nothing)
+ if ( ref[i] != alt[i] ) {
+
+ // create the ref and alt SNP alleles
+ final Allele newRefAllele = Allele.create(ref[i], true);
+ final Allele newAltAllele = Allele.create(alt[i], false);
+
+ // create a new VariantContext with the new SNP alleles
+ final VariantContextBuilder newVC = new VariantContextBuilder(vc).start(vc.getStart() + i).stop(vc.getStart() + i).alleles(Arrays.asList(newRefAllele, newAltAllele));
+
+ // create new genotypes with updated alleles
+ final Map<Allele, Allele> alleleMap = new HashMap<>();
+ alleleMap.put(vc.getReference(), newRefAllele);
+ alleleMap.put(vc.getAlternateAllele(0), newAltAllele);
+ final GenotypesContext newGenotypes = updateGenotypesWithMappedAlleles(vc.getGenotypes(), new AlleleMapper(alleleMap));
+
+ result.add(newVC.genotypes(newGenotypes).make());
+ }
+ }
+
+ if ( result.isEmpty() )
+ result.add(vc);
+
+ return result;
+ }
+
+ /**
+ * Are vc1 and 2 equal including their position and alleles?
+ * @param vc1 non-null VariantContext
+ * @param vc2 non-null VariantContext
+ * @return true if vc1 and vc2 are equal, false otherwise
+ */
+ public static boolean equalSites(final VariantContext vc1, final VariantContext vc2) {
+ if ( vc1 == null ) throw new IllegalArgumentException("vc1 cannot be null");
+ if ( vc2 == null ) throw new IllegalArgumentException("vc2 cannot be null");
+
+ if ( vc1.getStart() != vc2.getStart() ) return false;
+ if ( vc1.getEnd() != vc2.getEnd() ) return false;
+ if ( ! vc1.getChr().equals(vc2.getChr())) return false;
+ if ( ! vc1.getAlleles().equals(vc2.getAlleles()) ) return false;
+ return true;
+ }
+
+ /**
+ * Returns the absolute 0-based index of an allele.
+ *
+ * <p/>
+ * If the allele is equal to the reference, the result is 0, if it equal to the first alternative the result is 1
+ * and so forth.
+ * <p/>
+ * Therefore if you want the 0-based index within the alternative alleles you need to do the following:
+ *
+ * <p/>
+ * You can indicate whether the Java object reference comparator {@code ==} can be safelly used by setting {@code useEquals} to {@code false}.
+ *
+ * @param vc the target variant context.
+ * @param allele the target allele.
+ * @param ignoreRefState whether the reference states of the allele is important at all. Has no effect if {@code useEquals} is {@code false}.
+ * @param considerRefAllele whether the reference allele should be considered. You should set it to {@code false} if you are only interested in alternative alleles.
+ * @param useEquals whether equal method should be used in the search: {@link Allele#equals(Allele,boolean)}.
+ *
+ * @throws IllegalArgumentException if {@code allele} is {@code null}.
+ * @return {@code -1} if there is no such allele that satify those criteria, a value between 0 and {@link VariantContext#getNAlleles()} {@code -1} otherwise.
+ */
+ public static int indexOfAllele(final VariantContext vc, final Allele allele, final boolean ignoreRefState, final boolean considerRefAllele, final boolean useEquals) {
+ if (allele == null) throw new IllegalArgumentException();
+ return useEquals ? indexOfEqualAllele(vc,allele,ignoreRefState,considerRefAllele) : indexOfSameAllele(vc,allele,considerRefAllele);
+ }
+
+ /**
+ * Returns the relative 0-based index of an alternative allele.
+ * <p/>
+ * The the query allele is the same as the first alternative allele, the result is 0,
+ * if it is equal to the second 1 and so forth.
+ *
+ *
+ * <p/>
+ * Notice that the ref-status of the query {@code allele} is ignored.
+ *
+ * @param vc the target variant context.
+ * @param allele the query allele.
+ * @param useEquals whether equal method should be used in the search: {@link Allele#equals(Allele,boolean)}.
+ *
+ * @throws IllegalArgumentException if {@code allele} is {@code null}.
+ *
+ * @return {@code -1} if there is no such allele that satify those criteria, a value between 0 and the number
+ * of alternative alleles - 1.
+ */
+ public static int indexOfAltAllele(final VariantContext vc, final Allele allele, final boolean useEquals) {
+ final int absoluteIndex = indexOfAllele(vc,allele,true,false,useEquals);
+ return absoluteIndex == -1 ? -1 : absoluteIndex - 1;
+ }
+
+ // Impements index search using equals.
+ private static int indexOfEqualAllele(final VariantContext vc, final Allele allele, final boolean ignoreRefState,
+ final boolean considerRefAllele) {
+ int i = 0;
+ for (final Allele a : vc.getAlleles())
+ if (a.equals(allele,ignoreRefState))
+ return i == 0 ? (considerRefAllele ? 0 : -1) : i;
+ else
+ i++;
+ return -1;
+ }
+
+ // Implements index search using ==.
+ private static int indexOfSameAllele(final VariantContext vc, final Allele allele, final boolean considerRefAllele) {
+ int i = 0;
+
+ for (final Allele a : vc.getAlleles())
+ if (a == allele)
+ return i == 0 ? (considerRefAllele ? 0 : -1) : i;
+ else
+ i++;
+
+ return -1;
+ }
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/HomoSapiensConstants.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/HomoSapiensConstants.java
new file mode 100644
index 0000000..0b1543b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/variant/HomoSapiensConstants.java
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.variant;
+
+/**
+ * <i>Homo sapiens</i> genome constants.
+ *
+ * <p>NOTE: reference to these constants is an indication that your code is (human) species assumption dependant.</p>
+ *
+ * @author Valentin Ruano-Rubio <valentin at broadinstitute.org>
+ */
+public class HomoSapiensConstants {
+
+ /**
+ * Standard heterozygous rate for SNP variation.
+ */
+ public static final double SNP_HETEROZYGOSITY = 1e-3;
+
+ /**
+ * Standard heterozygous rate for INDEL variation.
+ */
+ public static final double INDEL_HETEROZYGOSITY = 1.0/8000;
+
+ /**
+ * Standard ploidy for autosomal chromosomes.
+ */
+ public static final int DEFAULT_PLOIDY = 2;
+}
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/wiggle/WiggleHeader.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/wiggle/WiggleHeader.java
new file mode 100644
index 0000000..85681c4
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/wiggle/WiggleHeader.java
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.wiggle;
+
+/**
+ * A class for defining the header values for a wiggle graph file (see UCSC). The optional fields are:
+ * name, description, visibility, color, altColor, priority, autoscale, alwaysZero, gridDefault,
+ * maxHeightPixels,graphType,viewLimits,yLineMark,yLineOnOff,windowingFunction,smoothingWindow
+ *
+ * For now only support name, description
+ *
+ * @Author chartl
+ * @Date Jul 21, 2010
+ */
+public class WiggleHeader {
+ static String type = "wiggle_0";
+ // defines the type of the track (for IGV or UCSC), wiggle_0 is the 'only' type of wiggle
+ private String name;
+ // a label for the track
+ private String description;
+ // a description of what the track is
+
+ public WiggleHeader(String name, String description) {
+ this.name = name;
+ this.description = description;
+ }
+
+ public String toString() {
+ return String.format("track type=%s name=\"%s\" description=\"%s\"",type,name,description);
+ }
+
+}
+
diff --git a/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/wiggle/WiggleWriter.java b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/wiggle/WiggleWriter.java
new file mode 100644
index 0000000..af9268b
--- /dev/null
+++ b/public/gatk-tools-public/src/main/java/org/broadinstitute/gatk/utils/wiggle/WiggleWriter.java
@@ -0,0 +1,117 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.wiggle;
+
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import java.io.*;
+
+/**
+ * Manages the output of wiggle files. Due to the wiggle spec (each wiggle file must be one chromosome), this writer
+ * will throw exceptions (or output multiple files?)
+ *
+ * todo -- currently no support for fixed step (special case of variable step)
+ * todo -- currently no support for span, start, or step
+ *
+ * @Author chartl
+ * @Date Jul 21, 2010
+ */
+public class WiggleWriter {
+
+ enum StepType {
+ fixed("fixedStep"),variable("variableStep");
+
+ String repr;
+
+ StepType(String repr) {
+ this.repr = repr;
+ }
+
+ public String toString() {
+ return repr;
+ }
+ }
+
+ private WiggleHeader wHeader = null;
+ // the header that we need to write prior to the file; and on future files (if multiple outputs ??)
+ private BufferedWriter wWriter = null;
+ // the file to which we are writing
+ private GenomeLoc firstLoc = null;
+ // the first genome loc the writer saw; need to cache this to compare contigs to preserve spec
+ private StepType type = StepType.variable;
+ // the type of step for the wiggle file, todo -- allow this to change
+
+ private String myFile = "unknown";
+
+ public WiggleWriter(File outputFile) {
+ myFile = outputFile.getAbsolutePath();
+ FileOutputStream outputStream;
+ try {
+ outputStream = new FileOutputStream(outputFile);
+ } catch ( FileNotFoundException e ) {
+ throw new UserException.CouldNotCreateOutputFile(outputFile, "Unable to create a wiggle file ", e);
+ }
+
+ wWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
+ }
+
+ public WiggleWriter(OutputStream out) {
+ wWriter = new BufferedWriter(new OutputStreamWriter(out));
+ }
+
+ public void writeHeader(WiggleHeader header) {
+ wHeader = header;
+ write(wWriter,header.toString());
+ }
+
+ public void writeData(GenomeLoc loc, Object dataPoint) {
+ if ( this.firstLoc == null ) {
+ firstLoc = loc;
+ write(wWriter,String.format("%n"));
+ write(wWriter,String.format("%s\tchrom=%s",type.toString(),firstLoc.getContig()));
+ write(wWriter,String.format("%n"));
+ write(wWriter,String.format("%d\t%s",loc.getStart(),dataPoint.toString()));
+ } else if ( loc.compareContigs(firstLoc) == 0 ) {
+ write(wWriter,String.format("%n"));
+ write(wWriter,String.format("%d\t%s",loc.getStart(),dataPoint.toString()));
+ } else {
+ // todo -- maybe allow this to open a new file for the new chromosome?
+ throw new ReviewedGATKException("Attempting to write multiple contigs into wiggle file, first contig was "+firstLoc.getContig()+" most recent "+loc.getContig());
+ }
+ }
+
+ private void write(BufferedWriter w, String s) {
+ try {
+ w.write(s);
+ w.flush();
+ // flush required so writing to output stream will work
+ } catch (IOException e) {
+ throw new UserException.CouldNotCreateOutputFile(myFile, String.format("Error writing the wiggle line %s", s), e);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/main/resources/GATK_public.key b/public/gatk-tools-public/src/main/resources/GATK_public.key
new file mode 100644
index 0000000..05cdde1
Binary files /dev/null and b/public/gatk-tools-public/src/main/resources/GATK_public.key differ
diff --git a/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/engine/phonehome/resources/GATK_AWS_access.key b/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/engine/phonehome/resources/GATK_AWS_access.key
new file mode 100644
index 0000000..28f2cd0
Binary files /dev/null and b/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/engine/phonehome/resources/GATK_AWS_access.key differ
diff --git a/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/engine/phonehome/resources/GATK_AWS_secret.key b/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/engine/phonehome/resources/GATK_AWS_secret.key
new file mode 100644
index 0000000..5c289a8
Binary files /dev/null and b/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/engine/phonehome/resources/GATK_AWS_secret.key differ
diff --git a/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/tools/walkers/variantrecalibration/plot_Tranches.R b/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/tools/walkers/variantrecalibration/plot_Tranches.R
new file mode 100755
index 0000000..d96add7
--- /dev/null
+++ b/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/tools/walkers/variantrecalibration/plot_Tranches.R
@@ -0,0 +1,93 @@
+#!/bin/env Rscript
+
+library(tools)
+
+args <- commandArgs(TRUE)
+verbose = TRUE
+
+tranchesFile = args[1]
+targetTITV = as.numeric(args[2])
+targetSensitivity = as.numeric(args[3])
+suppressLegend = ! is.na(args[4])
+
+# -----------------------------------------------------------------------------------------------
+# Useful general routines
+# -----------------------------------------------------------------------------------------------
+
+MIN_FP_RATE = 0.001 # 1 / 1000 is min error rate
+
+titvFPEst <- function(titvExpected, titvObserved) {
+ max(min(1 - (titvObserved - 0.5) / (titvExpected - 0.5), 1), MIN_FP_RATE)
+}
+
+titvFPEstV <- function(titvExpected, titvs) {
+ sapply(titvs, function(x) titvFPEst(titvExpected, x))
+}
+
+nTPFP <- function(nVariants, FDR) {
+ return(list(TP = nVariants * (1 - FDR/100), FP = nVariants * (FDR / 100)))
+}
+
+leftShift <- function(x, leftValue = 0) {
+ r = rep(leftValue, length(x))
+ for ( i in 1:(length(x)-1) ) {
+ #print(list(i=i))
+ r[i] = x[i+1]
+ }
+ r
+}
+
+# -----------------------------------------------------------------------------------------------
+# Tranches plot
+# -----------------------------------------------------------------------------------------------
+data2 = read.table(tranchesFile,sep=",",head=T)
+data2 = data2[order(data2$novelTiTv, decreasing=F),]
+#data2 = data2[order(data2$FDRtranche, decreasing=T),]
+cols = c("cornflowerblue", "cornflowerblue", "darkorange", "darkorange")
+density=c(20, -1, -1, 20)
+outfile = paste(tranchesFile, ".pdf", sep="")
+pdf(outfile, height=5, width=8)
+par(mar = c(5, 5, 4, 2) + 0.1)
+novelTiTv = c(data2$novelTITV,data2$novelTiTv)
+alpha = 1 - titvFPEstV(targetTITV, novelTiTv)
+#print(alpha)
+
+numGood = round(alpha * data2$numNovel);
+
+#numGood = round(data2$numNovel * (1-data2$targetTruthSensitivity/100))
+numBad = data2$numNovel - numGood;
+
+numPrevGood = leftShift(numGood, 0)
+numNewGood = numGood - numPrevGood
+numPrevBad = leftShift(numBad, 0)
+numNewBad = numBad - numPrevBad
+
+d=matrix(c(numPrevGood,numNewGood, numNewBad, numPrevBad),4,byrow=TRUE)
+#print(d)
+barplot(d/1000,horiz=TRUE,col=cols,space=0.2,xlab="Number of Novel Variants (1000s)", density=density, cex.axis=1.25, cex.lab=1.25) # , xlim=c(250000,350000))
+#abline(v= d[2,dim(d)[2]], lty=2)
+#abline(v= d[1,3], lty=2)
+if ( ! suppressLegend )
+ legend(3, length(data2$targetTruthSensitivity)/3 +1, c('Cumulative TPs','Tranch-specific TPs', 'Tranch-specific FPs', 'Cumulative FPs' ), fill=cols, density=density, bg='white', cex=1.25)
+
+mtext("Ti/Tv",2,line=2.25,at=length(data2$targetTruthSensitivity)*1.2,las=1, cex=1)
+mtext("truth",2,line=0,at=length(data2$targetTruthSensitivity)*1.2,las=1, cex=1)
+axis(2,line=-1,at=0.7+(0:(length(data2$targetTruthSensitivity)-1))*1.2,tick=FALSE,labels=data2$targetTruthSensitivity, las=1, cex.axis=1.0)
+axis(2,line=1,at=0.7+(0:(length(data2$targetTruthSensitivity)-1))*1.2,tick=FALSE,labels=round(novelTiTv,3), las=1, cex.axis=1.0)
+
+# plot sensitivity vs. specificity
+sensitivity = data2$truthSensitivity
+if ( ! is.null(sensitivity) ) {
+ #specificity = titvFPEstV(targetTITV, novelTiTv)
+ specificity = novelTiTv
+ plot(sensitivity, specificity, type="b", col="cornflowerblue", xlab="Tranche truth sensitivity", ylab="Specificity (Novel Ti/Tv ratio)")
+ abline(h=targetTITV, lty=2)
+ abline(v=targetSensitivity, lty=2)
+ #text(max(sensitivity), targetTITV-0.05, labels="Expected novel Ti/Tv", pos=2)
+}
+
+dev.off()
+
+if (exists('compactPDF')) {
+ compactPDF(outfile)
+}
diff --git a/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/utils/recalibration/BQSR.R b/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/utils/recalibration/BQSR.R
new file mode 100644
index 0000000..93474a5
--- /dev/null
+++ b/public/gatk-tools-public/src/main/resources/org/broadinstitute/gatk/utils/recalibration/BQSR.R
@@ -0,0 +1,159 @@
+library("ggplot2")
+library(gplots)
+library("reshape")
+library("grid")
+library("tools") #For compactPDF in R 2.13+
+library(gsalib)
+
+
+
+if ( interactive() ) {
+ args <- c("NA12878.6.1.dedup.realign.recal.bqsr.grp.csv", "NA12878.6.1.dedup.realign.recal.bqsr.grp", NA)
+} else {
+ args <- commandArgs(TRUE)
+}
+
+data <- read.csv(args[1])
+
+data$Recalibration = as.factor(sapply(as.character(data$Recalibration),function(x) {
+ xu = toupper(x);
+ if (xu == "ORIGINAL") "BEFORE" else
+ if (xu == "RECALIBRATED") "AFTER" else
+ if (xu == "RECALIBRATION") "BQSR" else
+ xu }));
+
+gsa.report <- gsa.read.gatkreport(args[2])
+
+gsa.report$Arguments$Value = as.character(gsa.report$Arguments$Value);
+gsa.report$Arguments = subset(gsa.report$Arguments,subset= Argument != "plot_pdf_file");
+if (length(levels(data$Recalibration)) > 1) {
+ gsa.report$Arguments = subset(gsa.report$Arguments,subset= Argument != "recalibration_report");
+}
+gsa.report$Arguments$Value[gsa.report$Argument$Value == "null"] = "None";
+
+gsa.report.covariate.argnum = gsa.report$Arguments$Argument == "covariate";
+gsa.report$Arguments$Value[gsa.report.covariate.argnum] = sapply(strsplit(gsa.report$Arguments$Value[gsa.report.covariate.argnum],","),function(x) {
+ y = sub("(^.+)Covariate","\\1",x); paste(y,collapse=",") } );
+
+data <- within(data, EventType <- factor(EventType, levels = rev(levels(EventType))))
+
+numRG = length(unique(data$ReadGroup))
+blankTheme = theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_blank(), axis.ticks = element_blank())
+
+# Viewport (layout 2 graphs top to bottom)
+distributeGraphRows <- function(graphs, heights = c()) {
+ if (length(heights) == 0) {
+ heights <- rep.int(1, length(graphs))
+ }
+ heights <- heights[!is.na(graphs)]
+ graphs <- graphs[!is.na(graphs)]
+ numGraphs <- length(graphs)
+ Layout <- grid.layout(nrow = numGraphs, ncol = 1, heights=heights)
+ grid.newpage()
+ pushViewport(viewport(layout = Layout))
+ subplot <- function(x) viewport(layout.pos.row = x, layout.pos.col = 1)
+ for (i in 1:numGraphs) {
+ print(graphs[[i]], vp = subplot(i))
+ }
+}
+
+
+for(cov in levels(data$CovariateName)) { # for each covariate in turn
+ d = data[data$CovariateName==cov,] # pull out just the data for this covariate so we can treat the non-numeric values appropriately
+ if( cov == "Context" ) {
+ d$CovariateValue = as.character(d$CovariateValue)
+ d$CovariateValue = substring(d$CovariateValue,nchar(d$CovariateValue)-2,nchar(d$CovariateValue))
+ } else {
+ d$CovariateValue = as.numeric(levels(d$CovariateValue))[as.integer(d$CovariateValue)] # efficient way to convert factors back to their real values
+ }
+ #d=subset(d,Observations>2000) # only show bins which have enough data to actually estimate the quality
+ dSub=subset(d,EventType=="Base Substitution")
+ dIns=subset(d,EventType=="Base Insertion")
+ dDel=subset(d,EventType=="Base Deletion")
+ dSub=dSub[sample.int(length(dSub[,1]),min(length(dSub[,1]),2000)),] # don't plot too many values because it makes the PDFs too massive
+ dIns=dIns[sample.int(length(dIns[,1]),min(length(dIns[,1]),2000)),] # don't plot too many values because it makes the PDFs too massive
+ dDel=dDel[sample.int(length(dDel[,1]),min(length(dDel[,1]),2000)),] # don't plot too many values because it makes the PDFs too massive
+ d=rbind(dSub, dIns, dDel)
+
+ if( cov != "QualityScore" ) {
+ p <- ggplot(d, aes(x=CovariateValue,y=Accuracy,alpha=log10(Observations))) + ylim(min(-10,d$Accuracy),max(10,d$Accuracy)) +
+ geom_abline(intercept=0, slope=0, linetype=2) +
+ xlab(paste(cov,"Covariate")) +
+ ylab("Quality Score Accuracy") +
+ blankTheme
+ if(cov == "Cycle") {
+ b <- p + geom_point(aes(color=Recalibration)) + scale_color_manual(values=c("BEFORE"="maroon1","AFTER"="blue","BQSR"="black")) + facet_grid(.~EventType) +
+ theme(axis.text.x=element_text(angle=90, hjust=0))
+
+ p <- ggplot(d, aes(x=CovariateValue,y=AverageReportedQuality,alpha=log10(Observations))) +
+ xlab(paste(cov,"Covariate")) +
+ ylab("Mean Quality Score") + ylim(0,max(42,d$AverageReportedQuality)) +
+ blankTheme
+ e <- p + geom_point(aes(color=Recalibration)) + scale_color_manual(values=c("BEFORE"="maroon1","AFTER"="blue","BQSR"="black")) + facet_grid(.~EventType) +
+ theme(axis.text.x=element_text(angle=90, hjust=0))
+
+
+ } else {
+ c <- p + geom_point(aes(color=Recalibration)) + scale_color_manual(values=c("BEFORE"="maroon1","AFTER"="blue","BQSR"="black")) + facet_grid(.~EventType) +
+ theme(axis.text.x=element_text(angle=90, hjust=0)) + xlab(paste(cov,"Covariate (3 base suffix)"))
+ p <- ggplot(d, aes(x=CovariateValue,y=AverageReportedQuality,alpha=log10(Observations))) +
+ xlab(paste(cov,"Covariate (3 base suffix)")) +
+ ylab("Mean Quality Score") +
+ blankTheme
+ f <- p + geom_point(aes(color=Recalibration)) + scale_color_manual(values=c("BEFORE"="maroon1","AFTER"="blue","BQSR"="black")) + facet_grid(.~EventType) +
+ theme(axis.text.x=element_text(angle=90, hjust=0))
+
+ }
+ } else {
+ p <- ggplot(d, aes(x=AverageReportedQuality,y=EmpiricalQuality,alpha=log10(Observations))) +
+ geom_abline(intercept=0, slope=1, linetype=2) +
+ xlab("Reported Quality Score") +
+ ylab("Empirical Quality Score") +
+ blankTheme
+ a <- p + geom_point(aes(color=Recalibration)) + scale_color_manual(values=c("BEFORE"="maroon1","AFTER"="blue","BQSR"="black")) + facet_grid(.~EventType)
+
+ p <- ggplot(d, aes(x=CovariateValue)) +
+ xlab(paste(cov,"Covariate")) +
+ ylab("No. of Observations (area normalized)") +
+ blankTheme
+ d <- p + geom_histogram(aes(fill=Recalibration,weight=Observations,y=..ndensity..),alpha=0.6,binwidth=1,position="identity")
+ d <- d + scale_fill_manual(values=c("BEFORE"="maroon1","AFTER"="blue","BQSR"="black"))
+ d <- d + facet_grid(.~EventType)
+ # d <- d + scale_y_continuous(formatter="comma")
+ }
+}
+
+if ( ! is.na(args[3]) )
+ pdf(args[3],height=9,width=15)
+
+#frame()
+textplot(gsa.report$Arguments, show.rownames=F)
+title(
+ main="GATK BaseRecalibration report",
+ sub=date())
+
+distributeGraphRows(list(a,b,c), c(1,1,1))
+distributeGraphRows(list(d,e,f), c(1,1,1))
+
+# format the overall information
+rt0 <- data.frame(
+ ReadGroup = gsa.report$RecalTable0$ReadGroup,
+ EventType = gsa.report$RecalTable0$EventType,
+ EmpiricalQuality = sprintf("%.1f", gsa.report$RecalTable0$EmpiricalQuality),
+ EstimatedQReported = sprintf("%.1f", gsa.report$RecalTable0$EstimatedQReported),
+ Observations = sprintf("%.2e", gsa.report$RecalTable0$Observations),
+ Errors = sprintf("%.2e", gsa.report$RecalTable0$Errors))
+textplot(t(rt0), show.colnames=F)
+title("Overall error rates by event type")
+
+# plot per quality score recalibration table
+textplot(gsa.report$RecalTable1, show.rownames=F)
+title("Error rates by event type and initial quality score")
+
+if ( ! is.na(args[3]) ) {
+ dev.off()
+ if (exists('compactPDF')) {
+ compactPDF(args[2])
+ }
+}
+
diff --git a/public/gatk-tools-public/src/test/java/htsjdk/samtools/GATKBAMFileSpanUnitTest.java b/public/gatk-tools-public/src/test/java/htsjdk/samtools/GATKBAMFileSpanUnitTest.java
new file mode 100644
index 0000000..aaa20c0
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/htsjdk/samtools/GATKBAMFileSpanUnitTest.java
@@ -0,0 +1,254 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package htsjdk.samtools;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Tests of functionality of union, intersection operators.
+ */
+public class GATKBAMFileSpanUnitTest {
+ @Test
+ public void testUnionOfEmptyFileSpans() {
+ GATKBAMFileSpan empty1 = new GATKBAMFileSpan();
+ GATKBAMFileSpan empty2 = new GATKBAMFileSpan();
+ GATKBAMFileSpan union = empty1.union(empty2);
+ Assert.assertEquals(union.getGATKChunks().size(),0,"Elements inserted in union of two empty sets");
+ }
+
+ @Test
+ public void testUnionOfNonOverlappingFileSpans() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,65535));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(1<<16,(1<<16)|65535));
+ GATKBAMFileSpan union = regionOne.union(regionTwo);
+ Assert.assertEquals(union.getGATKChunks().size(),2,"Discontiguous elements were merged");
+ Assert.assertEquals(union.getGATKChunks().get(0),regionOne.getGATKChunks().get(0),"Wrong chunk was first in list");
+ Assert.assertEquals(union.getGATKChunks().get(1),regionTwo.getGATKChunks().get(0),"Wrong chunk was second in list");
+ }
+
+ @Test
+ public void testUnionOfContiguousFileSpans() {
+ // Region 1 ends at position adjacent to Region 2 start:
+ // |---1----|---2----|
+
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,1<<16));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(1<<16,(1<<16)|65535));
+ GATKBAMFileSpan union = regionOne.union(regionTwo);
+ Assert.assertEquals(union.getGATKChunks().size(),1,"Elements to be merged were not.");
+ Assert.assertEquals(union.getGATKChunks().get(0),new GATKChunk(0,(1<<16)|65535));
+ }
+
+ @Test
+ public void testUnionOfFileSpansFirstRegionEndsWithinSecondRegion() {
+ // Region 1 ends within Region 2:
+ // |---2----|
+ // |---1----|
+
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,(1<<16)|32767));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(1<<16,(1<<16)|65535));
+ GATKBAMFileSpan union = regionOne.union(regionTwo);
+ Assert.assertEquals(union.getGATKChunks().size(),1,"Elements to be merged were not.");
+ Assert.assertEquals(union.getGATKChunks().get(0),new GATKChunk(0,(1<<16)|65535));
+ }
+
+ @Test
+ public void testUnionOfFileSpansFirstRegionEndsAtSecondRegionEnd() {
+ // Region 1 ends at Region 2 end:
+ // |---2----|
+ // |---1-----------|
+
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,(1<<16)|65535));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(1<<16,(1<<16)|65535));
+ GATKBAMFileSpan union = regionOne.union(regionTwo);
+ Assert.assertEquals(union.getGATKChunks().size(),1,"Elements to be merged were not.");
+ Assert.assertEquals(union.getGATKChunks().get(0),new GATKChunk(0,(1<<16)|65535));
+ }
+
+ @Test
+ public void testUnionOfFileSpansFirstRegionEndsAfterSecondRegionEnd() {
+ // Region 1 ends after Region 2 end:
+ // |---2----|
+ // |---1---------------|
+
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,(1<<16)|65535));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(1<<16,(1<<16)|32767));
+ GATKBAMFileSpan union = regionOne.union(regionTwo);
+ Assert.assertEquals(union.getGATKChunks().size(),1,"Elements to be merged were not.");
+ Assert.assertEquals(union.getGATKChunks().get(0),new GATKChunk(0,(1<<16)|65535));
+ }
+
+ @Test
+ public void testUnionOfFileSpansFirstRegionStartsAtSecondRegionStart() {
+ // Region 1 starts at Region 2 start, but ends before Region 2:
+ // |---2--------|
+ // |---1----|
+
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(1<<16,(1<<16)|32767));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(1<<16,(1<<16)|65535));
+ GATKBAMFileSpan union = regionOne.union(regionTwo);
+ Assert.assertEquals(union.getGATKChunks().size(),1,"Elements to be merged were not.");
+ Assert.assertEquals(union.getGATKChunks().get(0),new GATKChunk(1<<16,(1<<16)|65535));
+ }
+
+ @Test
+ public void testUnionOfFileSpansFirstRegionEqualToSecondRegion() {
+ // Region 1 and Region 2 represent the same region:
+ // |---2----|
+ // |---1----|
+
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(1<<16,(1<<16)|65535));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(1<<16,(1<<16)|65535));
+ GATKBAMFileSpan union = regionOne.union(regionTwo);
+ Assert.assertEquals(union.getGATKChunks().size(),1,"Elements to be merged were not.");
+ Assert.assertEquals(union.getGATKChunks().get(0),new GATKChunk(1<<16,(1<<16)|65535));
+ }
+
+ @Test
+ public void testUnionOfStringOfFileSpans() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk[] { new GATKChunk(0,1<<16), new GATKChunk(2<<16,3<<16) });
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(1<<16,2<<16));
+ GATKBAMFileSpan union = regionOne.union(regionTwo);
+ Assert.assertEquals(union.getGATKChunks().size(),1,"Elements to be merged were not.");
+ Assert.assertEquals(union.getGATKChunks().get(0),new GATKChunk(0,3<<16));
+ }
+
+ @Test
+ public void testUnionAllFileSpansAdded() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk[] { new GATKChunk(0,1<<16), new GATKChunk(2<<16,3<<16), new GATKChunk(20<<16,21<<16) });
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(1<<16,2<<16));
+ GATKBAMFileSpan union = regionOne.union(regionTwo);
+ Assert.assertEquals(union.getGATKChunks().size(),2,"Elements to be merged were not.");
+ Assert.assertEquals(union.getGATKChunks().get(0),new GATKChunk(0,3<<16));
+ Assert.assertEquals(union.getGATKChunks().get(1),new GATKChunk(20<<16,21<<16));
+ }
+
+ @Test
+ public void testIntersectionOfEmptyFileSpans() {
+ GATKBAMFileSpan empty1 = new GATKBAMFileSpan();
+ GATKBAMFileSpan empty2 = new GATKBAMFileSpan();
+ GATKBAMFileSpan intersection = empty1.intersection(empty2);
+ Assert.assertEquals(intersection.getGATKChunks().size(),0,"Elements inserted in intersection of two empty sets");
+ }
+
+ @Test
+ public void testIntersectionOfNonOverlappingFileSpans() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,1<<16));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(1<<16,2<<16));
+ GATKBAMFileSpan intersection = regionOne.intersection(regionTwo);
+ Assert.assertEquals(intersection.getGATKChunks().size(),0,"Elements inserted in intersection of two non-intersecting filespans");
+ }
+
+ @Test
+ public void testIntersectionOfSmallOverlapInFileSpans() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,1<<16));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(65535,2<<16));
+ GATKBAMFileSpan intersection = regionOne.intersection(regionTwo);
+ Assert.assertEquals(intersection.getGATKChunks().size(),1,"No intersection found between two partially overlapping filespans");
+ Assert.assertEquals(intersection.getGATKChunks().get(0),new GATKChunk(65535,1<<16),"Determined intersection is incorrect.");
+ }
+
+ @Test
+ public void testIntersectionOfStrictSubset() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,1<<16));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(0,2<<16));
+ GATKBAMFileSpan intersection = regionOne.intersection(regionTwo);
+ Assert.assertEquals(intersection.getGATKChunks().size(),1,"No intersection found between two partially overlapping filespans");
+ Assert.assertEquals(intersection.getGATKChunks().get(0),new GATKChunk(0<<16,1<<16),"Determined intersection is incorrect.");
+
+ // Make sure intersection is symmetric
+ intersection = regionTwo.intersection(regionOne);
+ Assert.assertEquals(intersection.getGATKChunks().size(),1,"No intersection found between two partially overlapping filespans");
+ Assert.assertEquals(intersection.getGATKChunks().get(0),new GATKChunk(0<<16,1<<16),"Determined intersection is incorrect.");
+ }
+
+ @Test
+ public void testIntersectionOfPartialOverlap() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,2<<16));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(0<<16|32768,1<<16|32768));
+ GATKBAMFileSpan intersection = regionOne.intersection(regionTwo);
+ Assert.assertEquals(intersection.getGATKChunks().size(),1,"No intersection found between two partially overlapping filespans");
+ Assert.assertEquals(intersection.getGATKChunks().get(0),new GATKChunk(0<<16|32768,1<<16|32768),"Determined intersection is incorrect.");
+ }
+
+ @Test
+ public void testIntersectionOfChunkLists() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,5<<16));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk[] { new GATKChunk(1<<16,2<<16), new GATKChunk(3<<16,4<<16) });
+ GATKBAMFileSpan intersection = regionOne.intersection(regionTwo);
+ Assert.assertEquals(intersection.getGATKChunks().size(),2,"Wrong number of intersections found.");
+ Assert.assertEquals(intersection.getGATKChunks().get(0),new GATKChunk(1<<16,2<<16),"Determined intersection is incorrect.");
+ Assert.assertEquals(intersection.getGATKChunks().get(1),new GATKChunk(3<<16,4<<16),"Determined intersection is incorrect.");
+
+ // Make sure intersection is symmetric
+ intersection = regionTwo.intersection(regionOne);
+ Assert.assertEquals(intersection.getGATKChunks().size(),2,"Wrong number of intersections found.");
+ Assert.assertEquals(intersection.getGATKChunks().get(0),new GATKChunk(1<<16,2<<16),"Determined intersection is incorrect.");
+ Assert.assertEquals(intersection.getGATKChunks().get(1),new GATKChunk(3<<16,4<<16),"Determined intersection is incorrect.");
+ }
+
+ @Test
+ public void testSubtractionOfEmptyChunkLists() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan();
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan();
+ GATKBAMFileSpan subtraction = regionOne.minus(regionTwo);
+ Assert.assertEquals(subtraction.getGATKChunks().size(),0,"Elements inserted in subtraction of two empty sets");
+ }
+
+ @Test
+ public void testSingleIntervalSubtractedAway() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,1<<16));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(0,1<<16));
+ GATKBAMFileSpan subtraction = regionOne.minus(regionTwo);
+ Assert.assertEquals(subtraction.getGATKChunks().size(),0,"Elements inserted in complete subtraction of region");
+ }
+
+ @Test
+ public void testMultipleIntervalsSubtractedAway() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk[] { new GATKChunk(0,1<<16), new GATKChunk(2<<16,3<<16) });
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk[] { new GATKChunk(0,1<<16), new GATKChunk(2<<16,3<<16) });
+ GATKBAMFileSpan subtraction = regionOne.minus(regionTwo);
+ Assert.assertEquals(subtraction.getGATKChunks().size(),0,"Elements inserted in complete subtraction of region");
+ }
+
+ @Test
+ public void testSubtractionOfStrictSubset() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,2<<16));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(0,1<<16));
+ GATKBAMFileSpan subtraction = regionOne.minus(regionTwo);
+ Assert.assertEquals(subtraction.getGATKChunks().size(),1,"Incorrect size in strict subset subtraction of region");
+ Assert.assertEquals(subtraction.getGATKChunks().get(0),new GATKChunk(1<<16,2<<16),"Determined subtraction is incorrect.");
+ }
+
+ @Test
+ public void testSubtractionOfPartialOverlap() {
+ GATKBAMFileSpan regionOne = new GATKBAMFileSpan(new GATKChunk(0,2<<16));
+ GATKBAMFileSpan regionTwo = new GATKBAMFileSpan(new GATKChunk(1<<16,3<<16));
+ GATKBAMFileSpan subtraction = regionOne.minus(regionTwo);
+ Assert.assertEquals(subtraction.getGATKChunks().size(),1,"Incorrect size in partial subset subtraction of region");
+ Assert.assertEquals(subtraction.getGATKChunks().get(0),new GATKChunk(0<<16,1<<16),"Determined subtraction is incorrect.");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/htsjdk/samtools/GATKChunkUnitTest.java b/public/gatk-tools-public/src/test/java/htsjdk/samtools/GATKChunkUnitTest.java
new file mode 100644
index 0000000..2b08fc4
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/htsjdk/samtools/GATKChunkUnitTest.java
@@ -0,0 +1,71 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package htsjdk.samtools;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Test basic functionality of the GATK chunk, giving informative size capabilities, etc.
+ */
+public class GATKChunkUnitTest {
+ private static final int FULL_BLOCK_COMPRESSED_SIZE = 25559;
+ private static final int FULL_BLOCK_UNCOMPRESSED_SIZE = 65536;
+ private static final int HALF_BLOCK_UNCOMPRESSED_SIZE = FULL_BLOCK_UNCOMPRESSED_SIZE/2;
+
+ @Test
+ public void testSizeOfEmptyChunk() {
+ GATKChunk chunk = new GATKChunk(0,0);
+ Assert.assertEquals(chunk.size(),0,"Empty chunk's size is not equal to 0.");
+ }
+
+ @Test
+ public void testSizeOfChunkWithinSingleBlock() {
+ GATKChunk chunk = new GATKChunk(0,FULL_BLOCK_UNCOMPRESSED_SIZE-1);
+ Assert.assertEquals(chunk.size(),FULL_BLOCK_UNCOMPRESSED_SIZE-1,"Chunk spanning limits of block is returning wrong size.");
+
+ chunk = new GATKChunk(0,HALF_BLOCK_UNCOMPRESSED_SIZE);
+ Assert.assertEquals(chunk.size(),HALF_BLOCK_UNCOMPRESSED_SIZE,"Chunk spanning 1/2 block is returning the wrong size.");
+ }
+
+ @Test
+ public void testSizeOfSingleBlock() {
+ GATKChunk chunk = new GATKChunk(0,FULL_BLOCK_COMPRESSED_SIZE<<16);
+ Assert.assertEquals(chunk.size(),FULL_BLOCK_UNCOMPRESSED_SIZE,"Chunk spanning complete block returns incorrect size.");
+ }
+
+ @Test
+ public void testSizeOfBlockAndAHalf() {
+ GATKChunk chunk = new GATKChunk(0,(FULL_BLOCK_COMPRESSED_SIZE<<16)+HALF_BLOCK_UNCOMPRESSED_SIZE);
+ Assert.assertEquals(chunk.size(),FULL_BLOCK_UNCOMPRESSED_SIZE+HALF_BLOCK_UNCOMPRESSED_SIZE,"Chunk spanning 1.5 blocks returns incorrect size.");
+ }
+
+ @Test
+ public void testSizeOfHalfBlock() {
+ GATKChunk chunk = new GATKChunk(HALF_BLOCK_UNCOMPRESSED_SIZE,FULL_BLOCK_COMPRESSED_SIZE<<16);
+ Assert.assertEquals(chunk.size(),HALF_BLOCK_UNCOMPRESSED_SIZE,"Chunk spanning 0.5 blocks returns incorrect size.");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/CommandLineGATKUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/CommandLineGATKUnitTest.java
new file mode 100644
index 0000000..dc3e996
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/CommandLineGATKUnitTest.java
@@ -0,0 +1,68 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import htsjdk.samtools.SAMFileReader;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.File;
+
+/**
+ * @author Eric Banks
+ * @since 7/18/12
+ */
+public class CommandLineGATKUnitTest extends BaseTest {
+
+ @Test(enabled = true)
+ public void testSamTextFileError1() {
+ final File samFile = new File(publicTestDir + "testfile.sam");
+ final File indexFile = new File(publicTestDir + "HiSeq.1mb.1RG.bai");
+ try {
+ final SAMFileReader reader = new SAMFileReader(samFile, indexFile, false);
+
+ // we shouldn't get here
+ Assert.fail("We should have exceptioned out when trying to create a reader with an index for a textual SAM file");
+ } catch (RuntimeException e) {
+ Assert.assertTrue(e.getMessage().indexOf(CommandLineGATK.PICARD_TEXT_SAM_FILE_ERROR_1) != -1);
+ }
+ }
+
+ @Test(enabled = true)
+ public void testSamTextFileError2() {
+ File samFile = new File(publicTestDir + "testfile.sam");
+ try {
+ final SAMFileReader reader = new SAMFileReader(samFile);
+ reader.getFilePointerSpanningReads();
+
+ // we shouldn't get here
+ Assert.fail("We should have exceptioned out when trying to call getFilePointerSpanningReads() for a textual SAM file");
+ } catch (RuntimeException e) {
+ Assert.assertTrue(e.getMessage().indexOf(CommandLineGATK.PICARD_TEXT_SAM_FILE_ERROR_2) != -1);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/EngineFeaturesIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/EngineFeaturesIntegrationTest.java
new file mode 100644
index 0000000..6596cf3
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/EngineFeaturesIntegrationTest.java
@@ -0,0 +1,736 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import htsjdk.samtools.*;
+import htsjdk.samtools.util.CloseableIterator;
+import htsjdk.tribble.readers.LineIterator;
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.broadinstitute.gatk.utils.commandline.*;
+import org.broadinstitute.gatk.engine.arguments.StandardVariantContextInputArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.datasources.reference.ReferenceDataSource;
+import org.broadinstitute.gatk.engine.filters.MappingQualityUnavailableFilter;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrack;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrackBuilder;
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.engine.walkers.ReadFilters;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.tools.walkers.qc.ErrorThrowing;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.GATKSamRecordFactory;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import htsjdk.variant.vcf.VCFCodec;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ *
+ */
+public class EngineFeaturesIntegrationTest extends WalkerTest {
+ private void testBadRODBindingInput(String type, String name, Class c) {
+ WalkerTestSpec spec = new WalkerTestSpec("-T SelectVariants -L 1:1 --variant:variant," + type + " "
+ + b37dbSNP132 + " -R " + b37KGReference + " -o %s",
+ 1, c);
+ executeTest(name, spec);
+ }
+
+ @Test() private void testBadRODBindingInputType1() {
+ testBadRODBindingInput("beagle", "BEAGLE input to VCF expecting walker", UserException.BadArgumentValue.class);
+ }
+
+ @Test() private void testBadRODBindingInputType3() {
+ testBadRODBindingInput("bed", "Bed input to VCF expecting walker", UserException.BadArgumentValue.class);
+ }
+
+ @Test() private void testBadRODBindingInputTypeUnknownType() {
+ testBadRODBindingInput("bedXXX", "Unknown input to VCF expecting walker", UserException.UnknownTribbleType.class);
+ }
+
+ private void testMissingFile(String name, String missingBinding) {
+ WalkerTestSpec spec = new WalkerTestSpec(missingBinding + " -R " + b37KGReference + " -o %s",
+ 1, UserException.CouldNotReadInputFile.class);
+ executeTest(name, spec);
+ }
+
+ @Test() private void testMissingBAMnt1() {
+ testMissingFile("missing BAM", "-T PrintReads -I missing.bam -nt 1");
+ }
+ @Test() private void testMissingBAMnt4() {
+ testMissingFile("missing BAM", "-T PrintReads -I missing.bam -nt 4");
+ }
+ @Test() private void testMissingVCF() {
+ testMissingFile("missing VCF", "-T SelectVariants -V missing.vcf");
+ }
+ @Test() private void testMissingInterval() {
+ testMissingFile("missing interval", "-T PrintReads -L missing.interval_list -I " + b37GoodBAM);
+ }
+
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test that our exceptions are coming back as we expect
+ //
+ // --------------------------------------------------------------------------------
+
+ private class EngineErrorHandlingTestProvider extends TestDataProvider {
+ final Class expectedException;
+ final String args;
+ final int iterationsToTest;
+
+ public EngineErrorHandlingTestProvider(Class exceptedException, final String args) {
+ super(EngineErrorHandlingTestProvider.class);
+ this.expectedException = exceptedException;
+ this.args = args;
+ this.iterationsToTest = args.equals("") ? 1 : 10;
+ setName(String.format("Engine error handling: expected %s with args %s", exceptedException, args));
+ }
+ }
+
+ @DataProvider(name = "EngineErrorHandlingTestProvider")
+ public Object[][] makeEngineErrorHandlingTestProvider() {
+ for ( final ErrorThrowing.FailMethod failMethod : ErrorThrowing.FailMethod.values() ) {
+ if ( failMethod == ErrorThrowing.FailMethod.TREE_REDUCE )
+ continue; // cannot reliably throw errors in TREE_REDUCE
+
+ final String failArg = " -fail " + failMethod.name();
+ for ( final String args : Arrays.asList("", " -nt 2", " -nct 2") ) {
+ new EngineErrorHandlingTestProvider(NullPointerException.class, failArg + args);
+ new EngineErrorHandlingTestProvider(UserException.class, failArg + args);
+ new EngineErrorHandlingTestProvider(ReviewedGATKException.class, failArg + args);
+ }
+ }
+
+ return EngineErrorHandlingTestProvider.getTests(EngineErrorHandlingTestProvider.class);
+ }
+
+ //
+ // Loop over errors to throw, make sure they are the errors we get back from the engine, regardless of NT type
+ //
+ @Test(enabled = true, dataProvider = "EngineErrorHandlingTestProvider", timeOut = 60 * 1000 )
+ public void testEngineErrorHandlingTestProvider(final EngineErrorHandlingTestProvider cfg) {
+ for ( int i = 0; i < cfg.iterationsToTest; i++ ) {
+ final String root = "-T ErrorThrowing -R " + exampleFASTA;
+ final String args = root + cfg.args + " -E " + cfg.expectedException.getSimpleName();
+ WalkerTestSpec spec = new WalkerTestSpec(args, 0, cfg.expectedException);
+
+ executeTest(cfg.toString(), spec);
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test that read filters are being applied in the order we expect
+ //
+ // --------------------------------------------------------------------------------
+
+ @ReadFilters({MappingQualityUnavailableFilter.class})
+ public static class DummyReadWalkerWithMapqUnavailableFilter extends ReadWalker<Integer, Integer> {
+ @Output
+ PrintStream out;
+
+ @Override
+ public Integer map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker metaDataTracker) {
+ return 1;
+ }
+
+ @Override
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ @Override
+ public Integer reduce(Integer value, Integer sum) {
+ return value + sum;
+ }
+
+ @Override
+ public void onTraversalDone(Integer result) {
+ out.println(result);
+ }
+ }
+
+ @Test(enabled = true)
+ public void testUserReadFilterAppliedBeforeWalker() {
+ WalkerTestSpec spec = new WalkerTestSpec("-R " + b37KGReference + " -I " + privateTestDir + "allMAPQ255.bam"
+ + " -T DummyReadWalkerWithMapqUnavailableFilter -o %s -L MT -rf ReassignMappingQuality",
+ 1, Arrays.asList("ecf27a776cdfc771defab1c5d19de9ab"));
+ executeTest("testUserReadFilterAppliedBeforeWalker", spec);
+ }
+
+ @Test
+ public void testNegativeCompress() {
+ testBadCompressArgument(-1);
+ }
+
+ @Test
+ public void testTooBigCompress() {
+ testBadCompressArgument(100);
+ }
+
+ private void testBadCompressArgument(final int compress) {
+ WalkerTestSpec spec = new WalkerTestSpec("-T PrintReads -R " + b37KGReference + " -I " + privateTestDir + "NA12878.1_10mb_2_10mb.bam -o %s -compress " + compress,
+ 1, UserException.class);
+ executeTest("badCompress " + compress, spec);
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test that the VCF version key is what we expect
+ //
+ // --------------------------------------------------------------------------------
+ @Test(enabled = true)
+ public void testGATKVersionInVCF() throws Exception {
+ WalkerTestSpec spec = new WalkerTestSpec("-T SelectVariants -R " + b37KGReference +
+ " -V " + privateTestDir + "NA12878.WGS.b37.chr20.firstMB.vcf"
+ + " -o %s -L 20:61098",
+ 1, Arrays.asList(""));
+ spec.disableShadowBCF();
+ final File vcf = executeTest("testGATKVersionInVCF", spec).first.get(0);
+ final VCFCodec codec = new VCFCodec();
+ final VCFHeader header = (VCFHeader) codec.readActualHeader(codec.makeSourceFromStream(new FileInputStream(vcf)));
+ final VCFHeaderLine versionLine = header.getMetaDataLine(GATKVCFUtils.GATK_COMMAND_LINE_KEY);
+ Assert.assertNotNull(versionLine);
+ Assert.assertTrue(versionLine.toString().contains("SelectVariants"));
+ }
+
+ @Test(enabled = true)
+ public void testMultipleGATKVersionsInVCF() throws Exception {
+ WalkerTestSpec spec = new WalkerTestSpec("-T SelectVariants -R " + b37KGReference +
+ " -V " + privateTestDir + "gatkCommandLineInHeader.vcf"
+ + " -o %s",
+ 1, Arrays.asList(""));
+ spec.disableShadowBCF();
+ final File vcf = executeTest("testMultipleGATKVersionsInVCF", spec).first.get(0);
+ final VCFCodec codec = new VCFCodec();
+ final VCFHeader header = (VCFHeader) codec.readActualHeader(codec.makeSourceFromStream(new FileInputStream(vcf)));
+
+ boolean foundHC = false;
+ boolean foundSV = false;
+ for ( final VCFHeaderLine line : header.getMetaDataInInputOrder() ) {
+ if ( line.getKey().equals(GATKVCFUtils.GATK_COMMAND_LINE_KEY) ) {
+ if ( line.toString().contains("HaplotypeCaller") ) {
+ Assert.assertFalse(foundHC);
+ foundHC = true;
+ }
+ if ( line.toString().contains("SelectVariants") ) {
+ Assert.assertFalse(foundSV);
+ foundSV = true;
+ }
+ }
+ }
+
+ Assert.assertTrue(foundHC, "Didn't find HaplotypeCaller command line header field");
+ Assert.assertTrue(foundSV, "Didn't find SelectVariants command line header field");
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test that defaultBaseQualities actually works
+ //
+ // --------------------------------------------------------------------------------
+
+ public WalkerTestSpec testDefaultBaseQualities(final Integer value, final String md5) {
+ return new WalkerTestSpec("-T PrintReads -R " + b37KGReference + " -I " + privateTestDir + "/baseQualitiesToFix.bam -o %s"
+ + (value != null ? " --defaultBaseQualities " + value : ""),
+ 1, Arrays.asList(md5));
+ }
+
+ @Test()
+ public void testDefaultBaseQualities20() {
+ executeTest("testDefaultBaseQualities20", testDefaultBaseQualities(20, "7d254a9d0ec59c66ee3e137f56f4c78f"));
+ }
+
+ @Test()
+ public void testDefaultBaseQualities30() {
+ executeTest("testDefaultBaseQualities30", testDefaultBaseQualities(30, "0f50def6cbbbd8ccd4739e2b3998e503"));
+ }
+
+ @Test(expectedExceptions = Exception.class)
+ public void testDefaultBaseQualitiesNoneProvided() {
+ executeTest("testDefaultBaseQualitiesNoneProvided", testDefaultBaseQualities(null, ""));
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test engine-level cigar consolidation
+ //
+ // --------------------------------------------------------------------------------
+
+ @Test
+ public void testGATKEngineConsolidatesCigars() {
+ final WalkerTestSpec spec = new WalkerTestSpec(" -T PrintReads" +
+ " -R " + b37KGReference +
+ " -I " + privateTestDir + "zero_length_cigar_elements.bam" +
+ " -o %s",
+ 1, Arrays.asList("")); // No MD5s; we only want to check the cigar
+
+ final File outputBam = executeTest("testGATKEngineConsolidatesCigars", spec).first.get(0);
+ final SAMFileReader reader = new SAMFileReader(outputBam);
+ reader.setValidationStringency(ValidationStringency.SILENT);
+ reader.setSAMRecordFactory(new GATKSamRecordFactory());
+
+ final SAMRecord read = reader.iterator().next();
+ reader.close();
+
+ // Original cigar was 0M3M0M8M. Check that it's been consolidated after running through the GATK engine:
+ Assert.assertEquals(read.getCigarString(), "11M", "Cigar 0M3M0M8M not consolidated correctly by the engine");
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test on-the-fly sample renaming
+ //
+ // --------------------------------------------------------------------------------
+
+ // On-the-fly sample renaming test case: one single-sample bam with multiple read groups
+ @Test
+ public void testOnTheFlySampleRenamingWithSingleBamFile() throws IOException {
+ final File sampleRenameMapFile = createTestSampleRenameMapFile(
+ Arrays.asList(privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12878.HEADERONLY.bam myNewSampleName"));
+
+ final WalkerTestSpec spec = new WalkerTestSpec(" -T PrintReads" +
+ " -R " + b37KGReference +
+ " -I " + privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12878.HEADERONLY.bam" +
+ " --sample_rename_mapping_file " + sampleRenameMapFile.getAbsolutePath() +
+ " -o %s",
+ 1, Arrays.asList("")); // No MD5s; we only want to check the read groups
+
+ final File outputBam = executeTest("testOnTheFlySampleRenamingWithSingleBamFile", spec).first.get(0);
+ final SAMFileReader reader = new SAMFileReader(outputBam);
+
+ for ( final SAMReadGroupRecord readGroup : reader.getFileHeader().getReadGroups() ) {
+ Assert.assertEquals(readGroup.getSample(), "myNewSampleName", String.format("Sample for read group %s not renamed correctly", readGroup.getId()));
+ }
+
+ reader.close();
+ }
+
+ // On-the-fly sample renaming test case: three single-sample bams with multiple read groups per bam
+ @Test
+ public void testOnTheFlySampleRenamingWithMultipleBamFiles() throws IOException {
+ final File sampleRenameMapFile = createTestSampleRenameMapFile(
+ Arrays.asList(privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12878.HEADERONLY.bam newSampleFor12878",
+ privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12891.HEADERONLY.bam newSampleFor12891",
+ privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12892.HEADERONLY.bam newSampleFor12892"));
+
+ final Map<String, String> readGroupToNewSampleMap = new HashMap<>();
+ for ( String inputBamID : Arrays.asList("12878", "12891", "12892") ) {
+ final File inputBam = new File(privateTestDir + String.format("CEUTrio.HiSeq.WGS.b37.NA%s.HEADERONLY.bam", inputBamID));
+ final SAMFileReader inputBamReader = new SAMFileReader(inputBam);
+ final String newSampleName = String.format("newSampleFor%s", inputBamID);
+ for ( final SAMReadGroupRecord readGroup : inputBamReader.getFileHeader().getReadGroups() ) {
+ readGroupToNewSampleMap.put(readGroup.getId(), newSampleName);
+ }
+ inputBamReader.close();
+ }
+
+ final WalkerTestSpec spec = new WalkerTestSpec(" -T PrintReads" +
+ " -R " + b37KGReference +
+ " -I " + privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12878.HEADERONLY.bam" +
+ " -I " + privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12891.HEADERONLY.bam" +
+ " -I " + privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12892.HEADERONLY.bam" +
+ " --sample_rename_mapping_file " + sampleRenameMapFile.getAbsolutePath() +
+ " -o %s",
+ 1, Arrays.asList("")); // No MD5s; we only want to check the read groups
+
+ final File outputBam = executeTest("testOnTheFlySampleRenamingWithMultipleBamFiles", spec).first.get(0);
+ final SAMFileReader outputBamReader = new SAMFileReader(outputBam);
+
+ int totalReadGroupsSeen = 0;
+ for ( final SAMReadGroupRecord readGroup : outputBamReader.getFileHeader().getReadGroups() ) {
+ Assert.assertEquals(readGroup.getSample(), readGroupToNewSampleMap.get(readGroup.getId()),
+ String.format("Wrong sample for read group %s after on-the-fly renaming", readGroup.getId()));
+ totalReadGroupsSeen++;
+ }
+
+ Assert.assertEquals(totalReadGroupsSeen, readGroupToNewSampleMap.size(), "Wrong number of read groups encountered in output bam file");
+
+ outputBamReader.close();
+ }
+
+ // On-the-fly sample renaming test case: three single-sample bams with multiple read groups per bam,
+ // performing renaming in only SOME of the bams
+ @Test
+ public void testOnTheFlySampleRenamingWithMultipleBamFilesPartialRename() throws IOException {
+ // Rename samples for NA12878 and NA12892, but not for NA12891
+ final File sampleRenameMapFile = createTestSampleRenameMapFile(
+ Arrays.asList(privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12878.HEADERONLY.bam newSampleFor12878",
+ privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12892.HEADERONLY.bam newSampleFor12892"));
+
+ final Map<String, String> readGroupToNewSampleMap = new HashMap<>();
+ for ( String inputBamID : Arrays.asList("12878", "12891", "12892") ) {
+ final File inputBam = new File(privateTestDir + String.format("CEUTrio.HiSeq.WGS.b37.NA%s.HEADERONLY.bam", inputBamID));
+ final SAMFileReader inputBamReader = new SAMFileReader(inputBam);
+
+ // Special-case NA12891, which we're not renaming:
+ final String newSampleName = inputBamID.equals("12891") ? "NA12891" : String.format("newSampleFor%s", inputBamID);
+
+ for ( final SAMReadGroupRecord readGroup : inputBamReader.getFileHeader().getReadGroups() ) {
+ readGroupToNewSampleMap.put(readGroup.getId(), newSampleName);
+ }
+ inputBamReader.close();
+ }
+
+ final WalkerTestSpec spec = new WalkerTestSpec(" -T PrintReads" +
+ " -R " + b37KGReference +
+ " -I " + privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12878.HEADERONLY.bam" +
+ " -I " + privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12891.HEADERONLY.bam" +
+ " -I " + privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12892.HEADERONLY.bam" +
+ " --sample_rename_mapping_file " + sampleRenameMapFile.getAbsolutePath() +
+ " -o %s",
+ 1, Arrays.asList("")); // No MD5s; we only want to check the read groups
+
+ final File outputBam = executeTest("testOnTheFlySampleRenamingWithMultipleBamFilesPartialRename", spec).first.get(0);
+ final SAMFileReader outputBamReader = new SAMFileReader(outputBam);
+
+ int totalReadGroupsSeen = 0;
+ for ( final SAMReadGroupRecord readGroup : outputBamReader.getFileHeader().getReadGroups() ) {
+ Assert.assertEquals(readGroup.getSample(), readGroupToNewSampleMap.get(readGroup.getId()),
+ String.format("Wrong sample for read group %s after on-the-fly renaming", readGroup.getId()));
+ totalReadGroupsSeen++;
+ }
+
+ Assert.assertEquals(totalReadGroupsSeen, readGroupToNewSampleMap.size(), "Wrong number of read groups encountered in output bam file");
+
+ outputBamReader.close();
+ }
+
+ // On-the-fly sample renaming test case: two single-sample bams with read group collisions
+ @Test
+ public void testOnTheFlySampleRenamingWithReadGroupCollisions() throws IOException {
+ final File sampleRenameMapFile = createTestSampleRenameMapFile(
+ Arrays.asList(privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12878.HEADERONLY.bam newSampleFor12878",
+ privateTestDir + "CEUTrio.HiSeq.WGS.b37.READ_GROUP_COLLISIONS_WITH_NA12878.HEADERONLY.bam newSampleForNot12878"));
+
+ final Set<String> na12878ReadGroups = new HashSet<>();
+ final SAMFileReader inputBamReader = new SAMFileReader(new File(privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12878.HEADERONLY.bam"));
+ for ( final SAMReadGroupRecord readGroup : inputBamReader.getFileHeader().getReadGroups() ) {
+ na12878ReadGroups.add(readGroup.getId());
+ }
+ inputBamReader.close();
+
+ final WalkerTestSpec spec = new WalkerTestSpec(" -T PrintReads" +
+ " -R " + b37KGReference +
+ " -I " + privateTestDir + "CEUTrio.HiSeq.WGS.b37.NA12878.HEADERONLY.bam" +
+ " -I " + privateTestDir + "CEUTrio.HiSeq.WGS.b37.READ_GROUP_COLLISIONS_WITH_NA12878.HEADERONLY.bam" +
+ " --sample_rename_mapping_file " + sampleRenameMapFile.getAbsolutePath() +
+ " -o %s",
+ 1, Arrays.asList("")); // No MD5s; we only want to check the read groups
+
+ final File outputBam = executeTest("testOnTheFlySampleRenamingWithReadGroupCollisions", spec).first.get(0);
+ final SAMFileReader outputBamReader = new SAMFileReader(outputBam);
+
+ int totalReadGroupsSeen = 0;
+ for ( final SAMReadGroupRecord readGroup : outputBamReader.getFileHeader().getReadGroups() ) {
+ String expectedSampleName = "";
+ if ( na12878ReadGroups.contains(readGroup.getId()) ) {
+ expectedSampleName = "newSampleFor12878";
+ }
+ else {
+ expectedSampleName = "newSampleForNot12878";
+ }
+
+ Assert.assertEquals(readGroup.getSample(), expectedSampleName,
+ String.format("Wrong sample for read group %s after on-the-fly renaming", readGroup.getId()));
+ totalReadGroupsSeen++;
+ }
+
+ Assert.assertEquals(totalReadGroupsSeen, na12878ReadGroups.size() * 2, "Wrong number of read groups encountered in output bam file");
+
+ outputBamReader.close();
+ }
+
+ // On-the-fly sample renaming test case: a multi-sample bam (this should generate a UserException)
+ @Test
+ public void testOnTheFlySampleRenamingWithMultiSampleBam() throws IOException {
+ final File sampleRenameMapFile = createTestSampleRenameMapFile(
+ Arrays.asList(privateTestDir + "CEUTrio.HiSeq.WGS.b37.MERGED.HEADERONLY.bam myNewSampleName"));
+
+ final WalkerTestSpec spec = new WalkerTestSpec(" -T PrintReads" +
+ " -R " + b37KGReference +
+ " -I " + privateTestDir + "CEUTrio.HiSeq.WGS.b37.MERGED.HEADERONLY.bam" +
+ " --sample_rename_mapping_file " + sampleRenameMapFile.getAbsolutePath() +
+ " -o %s",
+ 1,
+ UserException.class); // expecting a UserException here
+
+ executeTest("testOnTheFlySampleRenamingWithMultiSampleBam", spec);
+ }
+
+ // On-the-fly sample renaming test case: ensure that walkers can see the remapped sample names in individual reads
+ @Test
+ public void testOnTheFlySampleRenamingVerifyWalkerSeesNewSamplesInReads() throws IOException {
+ final File sampleRenameMapFile = createTestSampleRenameMapFile(
+ Arrays.asList(privateTestDir + "NA12878.HiSeq.b37.chr20.10_11mb.bam myNewSampleName"));
+
+ final WalkerTestSpec spec = new WalkerTestSpec(" -T OnTheFlySampleRenamingVerifyingTestWalker" +
+ " -R " + b37KGReference +
+ " -I " + privateTestDir + "NA12878.HiSeq.b37.chr20.10_11mb.bam" +
+ " --sample_rename_mapping_file " + sampleRenameMapFile.getAbsolutePath() +
+ " --newSampleName myNewSampleName" +
+ " -L 20:10000000-10001000",
+ 1, Arrays.asList(""));
+
+ // Test is a success if our custom walker doesn't throw an exception
+ executeTest("testOnTheFlySampleRenamingVerifyWalkerSeesNewSamplesInReads", spec);
+ }
+
+ @Test
+ public void testOnTheFlySampleRenamingSingleSampleVCF() throws IOException {
+ final File sampleRenameMapFile = createTestSampleRenameMapFile(
+ Arrays.asList(privateTestDir + "NA12878.WGS.b37.chr20.firstMB.vcf newSampleForNA12878"));
+
+ final WalkerTestSpec spec = new WalkerTestSpec(" -T CombineVariants" +
+ " -R " + b37KGReference +
+ " -V " + privateTestDir + "NA12878.WGS.b37.chr20.firstMB.vcf" +
+ " --sample_rename_mapping_file " + sampleRenameMapFile.getAbsolutePath() +
+ " -o %s",
+ 1,
+ Arrays.asList("")); // No MD5s -- we will inspect the output file manually
+
+ final File outputVCF = executeTest("testOnTheFlySampleRenamingSingleSampleVCF", spec).first.get(0);
+ verifySampleRenaming(outputVCF, "newSampleForNA12878");
+ }
+
+ private void verifySampleRenaming( final File outputVCF, final String newSampleName ) throws IOException {
+ final Pair<VCFHeader, GATKVCFUtils.VCIterable<LineIterator>> headerAndVCIter = GATKVCFUtils.readAllVCs(outputVCF, new VCFCodec());
+ final VCFHeader header = headerAndVCIter.getFirst();
+ final GATKVCFUtils.VCIterable<LineIterator> iter = headerAndVCIter.getSecond();
+
+ // Verify that sample renaming occurred at both the header and record levels (checking only the first 10 records):
+
+ Assert.assertEquals(header.getGenotypeSamples().size(), 1, "Wrong number of samples in output vcf header");
+ Assert.assertEquals(header.getGenotypeSamples().get(0), newSampleName, "Wrong sample name in output vcf header");
+
+ int recordCount = 0;
+ while ( iter.hasNext() && recordCount < 10 ) {
+ final VariantContext vcfRecord = iter.next();
+ Assert.assertEquals(vcfRecord.getSampleNames().size(), 1, "Wrong number of samples in output vcf record");
+ Assert.assertEquals(vcfRecord.getSampleNames().iterator().next(), newSampleName, "Wrong sample name in output vcf record");
+ recordCount++;
+ }
+ }
+
+ @Test
+ public void testOnTheFlySampleRenamingVerifyWalkerSeesNewSamplesInVCFRecords() throws Exception {
+ final File sampleRenameMapFile = createTestSampleRenameMapFile(
+ Arrays.asList(privateTestDir + "samplerenametest_single_sample_gvcf.vcf FOOSAMPLE"));
+
+ final WalkerTestSpec spec = new WalkerTestSpec(" -T OnTheFlySampleRenamingVerifyingRodWalker" +
+ " -R " + hg19Reference +
+ " -V " + privateTestDir + "samplerenametest_single_sample_gvcf.vcf" +
+ " --sample_rename_mapping_file " + sampleRenameMapFile.getAbsolutePath() +
+ " --expectedSampleName FOOSAMPLE" +
+ " -o %s",
+ 1,
+ Arrays.asList("")); // No MD5s -- custom walker will throw an exception if there's a problem
+
+ executeTest("testOnTheFlySampleRenamingVerifyWalkerSeesNewSamplesInVCFRecords", spec);
+ }
+
+ @Test
+ public void testOnTheFlySampleRenamingMultiSampleVCF() throws Exception {
+ final File sampleRenameMapFile = createTestSampleRenameMapFile(
+ Arrays.asList(privateTestDir + "vcf/vcfWithGenotypes.vcf badSample"));
+
+ final WalkerTestSpec spec = new WalkerTestSpec(" -T CombineVariants" +
+ " -R " + b37KGReference +
+ " -V " + privateTestDir + "vcf/vcfWithGenotypes.vcf" +
+ " --sample_rename_mapping_file " + sampleRenameMapFile.getAbsolutePath() +
+ " -o %s",
+ 1,
+ UserException.class); // expecting a UserException here
+
+ executeTest("testOnTheFlySampleRenamingMultiSampleVCF", spec);
+ }
+
+ @Test
+ public void testOnTheFlySampleRenamingSitesOnlyVCF() throws Exception {
+ final File sampleRenameMapFile = createTestSampleRenameMapFile(
+ Arrays.asList(privateTestDir + "vcf/vcfWithoutGenotypes.vcf badSample"));
+
+ final WalkerTestSpec spec = new WalkerTestSpec(" -T CombineVariants" +
+ " -R " + b37KGReference +
+ " -V " + privateTestDir + "vcf/vcfWithoutGenotypes.vcf" +
+ " --sample_rename_mapping_file " + sampleRenameMapFile.getAbsolutePath() +
+ " -o %s",
+ 1,
+ UserException.class); // expecting a UserException here
+
+ executeTest("testOnTheFlySampleRenamingSitesOnlyVCF", spec);
+ }
+
+ private File createTestSampleRenameMapFile( final List<String> contents ) throws IOException {
+ final File mapFile = createTempFile("TestSampleRenameMapFile", ".tmp");
+ final PrintWriter writer = new PrintWriter(mapFile);
+
+ for ( final String line : contents ) {
+ writer.println(line);
+ }
+ writer.close();
+
+ return mapFile;
+ }
+
+ public static class OnTheFlySampleRenamingVerifyingTestWalker extends ReadWalker<Integer, Integer> {
+ @Argument(fullName = "newSampleName", shortName = "newSampleName", doc = "", required = true)
+ String newSampleName = null;
+
+ public Integer map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker metaDataTracker) {
+ if ( ! newSampleName.equals(read.getReadGroup().getSample()) ) {
+ throw new IllegalStateException(String.format("Encountered read with the wrong sample name. Expected %s found %s",
+ newSampleName, read.getReadGroup().getSample()));
+ }
+
+ return 1;
+ }
+
+ public Integer reduceInit() { return 0; }
+ public Integer reduce(Integer value, Integer sum) { return value + sum; }
+ }
+
+ public static class OnTheFlySampleRenamingVerifyingRodWalker extends RodWalker<Integer, Integer> {
+ @Argument(fullName = "expectedSampleName", shortName = "expectedSampleName", doc = "", required = true)
+ String expectedSampleName = null;
+
+ @Output
+ PrintStream out;
+
+ @Input(fullName="variant", shortName = "V", doc="Input VCF file", required=true)
+ public RodBinding<VariantContext> variants;
+
+ public Integer map( RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context ) {
+ if ( tracker == null ) {
+ return 0;
+ }
+
+ for ( final VariantContext vc : tracker.getValues(variants, context.getLocation()) ) {
+ if ( vc.getSampleNames().size() != 1 ) {
+ throw new IllegalStateException("Encountered a vcf record with num samples != 1");
+ }
+
+ final String actualSampleName = vc.getSampleNames().iterator().next();
+ if ( ! expectedSampleName.equals(actualSampleName)) {
+ throw new IllegalStateException(String.format("Encountered vcf record with wrong sample name. Expected %s found %s",
+ expectedSampleName, actualSampleName));
+ }
+ }
+
+ return 1;
+ }
+
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ public Integer reduce(Integer counter, Integer sum) {
+ return counter + sum;
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test output file-specific options
+ //
+ // --------------------------------------------------------------------------------
+
+ //Returns the output file
+ private File testBAMFeatures(final String args, final String md5) {
+ WalkerTestSpec spec = new WalkerTestSpec("-T PrintReads -R " + b37KGReference +
+ " -I " + privateTestDir + "NA20313.highCoverageRegion.bam"
+ + " --no_pg_tag -o %s " + args,
+ 1, Arrays.asList(".bam"), Arrays.asList(md5));
+ return executeTest("testBAMFeatures: "+args, spec).first.get(0);
+ }
+
+ @Test
+ public void testSAMWriterFeatures() {
+ testBAMFeatures("-compress 0", "bb4b55b1f80423970bb9384cbf0d8793");
+ testBAMFeatures("-compress 9", "b85ee1636d62e1bb8ed65a245c307167");
+ testBAMFeatures("-simplifyBAM", "38f9c30a27dfbc085a2ff52a1617d579");
+
+ //Validate MD5
+ final String expectedMD5 = "6627b9ea33293a0083983feb94948c1d";
+ final File md5Target = testBAMFeatures("--generate_md5", expectedMD5);
+ final File md5File = new File(md5Target.getAbsoluteFile() + ".md5");
+ md5File.deleteOnExit();
+ Assert.assertTrue(md5File.exists(), "MD5 wasn't created");
+ try {
+ String md5 = new BufferedReader(new FileReader(md5File)).readLine();
+ Assert.assertEquals(md5, expectedMD5, "Generated MD5 doesn't match expected");
+ } catch (IOException e) {
+ Assert.fail("Can't parse MD5 file", e);
+ }
+
+ //Validate that index isn't created
+ final String unindexedBAM = testBAMFeatures("--disable_bam_indexing", expectedMD5).getAbsolutePath();
+ Assert.assertTrue(!(new File(unindexedBAM+".bai").exists()) &&
+ !(new File(unindexedBAM.replace(".bam", ".bai")).exists()),
+ "BAM index was created even though it was disabled");
+ }
+
+ private void testVCFFeatures(final String args, final String md5) {
+ WalkerTestSpec spec = new WalkerTestSpec("-T SelectVariants -R " + b37KGReference +
+ " -V " + privateTestDir + "CEUtrioTest.vcf"
+ + " --no_cmdline_in_header -o %s " + args,
+ 1, Arrays.asList(md5));
+ executeTest("testVCFFeatures: "+args, spec);
+ }
+
+ private void testVCFFormatHandling(final boolean writeFullFormat, final String md5) {
+ WalkerTestSpec spec = new WalkerTestSpec("-T SelectVariants -R " + b37KGReference +
+ " -V " + privateTestDir + "ILLUMINA.wex.broad_phase2_baseline.20111114.both.exome.genotypes.1000.vcf"
+ + " --no_cmdline_in_header -o %s "
+ + " --fullyDecode " //Without this parameter, the FORMAT fields will be emitted unchanged. Oops
+ + (writeFullFormat ? "-writeFullFormat" : "") ,
+ 1, Arrays.asList(md5));
+ executeTest("testVCFFormatHandling: "+(writeFullFormat ? "Untrimmed" : "Trimmed"), spec);
+ }
+
+ @Test
+ public void testVCFWriterFeatures() {
+ testVCFFeatures("--sites_only", "94bf1f2c0946e933515e4322323a5716");
+ testVCFFeatures("--bcf", "03f2d6988f54a332da48803c78f9c4b3");
+ testVCFFormatHandling(true, "2b0fa660b0cef4b0f45a10febb453b6c");
+ testVCFFormatHandling(false, "5960311fdd9ee6db88587efaaf4055a0");
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/GenomeAnalysisEngineUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/GenomeAnalysisEngineUnitTest.java
new file mode 100644
index 0000000..ff60ae3
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/GenomeAnalysisEngineUnitTest.java
@@ -0,0 +1,273 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.tools.walkers.qc.CountReads;
+import org.broadinstitute.gatk.tools.walkers.readutils.PrintReads;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.*;
+
+/**
+ * Tests selected functionality in the GenomeAnalysisEngine class
+ */
+public class GenomeAnalysisEngineUnitTest extends BaseTest {
+
+ @Test(expectedExceptions=UserException.class)
+ public void testEmptySamFileListHandling() throws Exception {
+ GenomeAnalysisEngine testEngine = new GenomeAnalysisEngine();
+ testEngine.setWalker(new CountReads()); //generalizable to any walker requiring reads
+
+ //supply command line args so validateSuppliedReads() knows whether reads were passed in
+ GATKArgumentCollection testArgs = new GATKArgumentCollection();
+ testArgs.samFiles.add("empty.list");
+ testEngine.setArguments(testArgs);
+
+ //represents the empty list of samFiles read in from empty.list by CommandLineExecutable
+ Collection<SAMReaderID> samFiles = new ArrayList<SAMReaderID>();
+
+ testEngine.setSAMFileIDs(samFiles);
+ testEngine.validateSuppliedReads();
+ }
+
+ @Test(expectedExceptions=UserException.class)
+ public void testDuplicateSamFileHandlingSingleDuplicate() throws Exception {
+ GenomeAnalysisEngine testEngine = new GenomeAnalysisEngine();
+
+ Collection<SAMReaderID> samFiles = new ArrayList<SAMReaderID>();
+ samFiles.add(new SAMReaderID(new File(publicTestDir + "exampleBAM.bam"), new Tags()));
+ samFiles.add(new SAMReaderID(new File(publicTestDir + "exampleBAM.bam"), new Tags()));
+
+ testEngine.setSAMFileIDs(samFiles);
+ testEngine.checkForDuplicateSamFiles();
+ }
+
+ @Test(expectedExceptions=UserException.class)
+ public void testDuplicateSamFileHandlingMultipleDuplicates() throws Exception {
+ GenomeAnalysisEngine testEngine = new GenomeAnalysisEngine();
+
+ Collection<SAMReaderID> samFiles = new ArrayList<SAMReaderID>();
+ samFiles.add(new SAMReaderID(new File(publicTestDir + "exampleBAM.bam"), new Tags()));
+ samFiles.add(new SAMReaderID(new File(publicTestDir + "exampleNORG.bam"), new Tags()));
+ samFiles.add(new SAMReaderID(new File(publicTestDir + "exampleBAM.bam"), new Tags()));
+ samFiles.add(new SAMReaderID(new File(publicTestDir + "exampleNORG.bam"), new Tags()));
+
+ testEngine.setSAMFileIDs(samFiles);
+ testEngine.checkForDuplicateSamFiles();
+ }
+
+ @Test(expectedExceptions=UserException.class)
+ public void testDuplicateSamFileHandlingAbsoluteVsRelativePath() {
+ GenomeAnalysisEngine testEngine = new GenomeAnalysisEngine();
+
+ final File relativePathToBAMFile = new File(publicTestDir + "exampleBAM.bam");
+ final File absolutePathToBAMFile = new File(relativePathToBAMFile.getAbsolutePath());
+ Collection<SAMReaderID> samFiles = new ArrayList<SAMReaderID>();
+ samFiles.add(new SAMReaderID(relativePathToBAMFile, new Tags()));
+ samFiles.add(new SAMReaderID(absolutePathToBAMFile, new Tags()));
+
+ testEngine.setSAMFileIDs(samFiles);
+ testEngine.checkForDuplicateSamFiles();
+ }
+
+ @Test
+ public void testEmptyIntervalSetHandling() throws Exception {
+ GenomeLocParser genomeLocParser = new GenomeLocParser(ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000).getSequenceDictionary());
+
+ GenomeAnalysisEngine testEngine = new GenomeAnalysisEngine();
+
+ testEngine.setWalker(new PrintReads());
+ testEngine.setIntervals(new GenomeLocSortedSet(genomeLocParser));
+
+ testEngine.validateSuppliedIntervals();
+ }
+
+ @Test
+ public void testLoadWellFormedSampleRenameMapFile() throws IOException {
+ final File mapFile = createTestSampleRenameMapFile(Arrays.asList("/foo/bar/first.bam newSample1",
+ "/foo/bar/second.bam newSample2",
+ "/foo/bar2/third.bam newSample3",
+ "/foo/bar2/fourth.bam new sample 4",
+ "/foo/bar2/fifth.bam new sample 5 "));
+ final GenomeAnalysisEngine engine = new GenomeAnalysisEngine();
+ final Map<String, String> renameMap = engine.loadSampleRenameMap(mapFile);
+
+ Assert.assertEquals(renameMap.size(), 5, "Sample rename map was wrong size after loading from file");
+
+ final Iterator<String> expectedResultsIterator = Arrays.asList(
+ "/foo/bar/first.bam", "newSample1",
+ "/foo/bar/second.bam", "newSample2",
+ "/foo/bar2/third.bam", "newSample3",
+ "/foo/bar2/fourth.bam", "new sample 4",
+ "/foo/bar2/fifth.bam", "new sample 5"
+ ).iterator();
+ while ( expectedResultsIterator.hasNext() ) {
+ final String expectedKey = expectedResultsIterator.next();
+ final String expectedValue = expectedResultsIterator.next();
+
+ Assert.assertNotNull(renameMap.get(expectedKey), String.format("Entry for %s not found in sample rename map", expectedKey));
+ Assert.assertEquals(renameMap.get(expectedKey), expectedValue, "Wrong value in sample rename map for " + expectedKey);
+ }
+ }
+
+ @DataProvider(name = "MalformedSampleRenameMapFileDataProvider")
+ public Object[][] generateMalformedSampleRenameMapFiles() throws IOException {
+ final List<Object[]> tests = new ArrayList<Object[]>();
+
+ tests.add(new Object[]{"testLoadSampleRenameMapFileNonExistentFile",
+ new File("/foo/bar/nonexistent")});
+ tests.add(new Object[]{"testLoadSampleRenameMapFileMalformedLine",
+ createTestSampleRenameMapFile(Arrays.asList("/path/to/foo.bam"))});
+ tests.add(new Object[]{"testLoadSampleRenameMapFileNonAbsoluteBamPath",
+ createTestSampleRenameMapFile(Arrays.asList("relative/path/to/foo.bam newSample"))});
+ tests.add(new Object[]{"testLoadSampleRenameMapFileDuplicateBamPath",
+ createTestSampleRenameMapFile(Arrays.asList("/path/to/dupe.bam newSample1",
+ "/path/to/dupe.bam newSample2"))});
+ tests.add(new Object[]{"testLoadSampleRenameMapFileTabInSampleName",
+ createTestSampleRenameMapFile(Arrays.asList("/path/to/stuff.bam some wonky\tsample "))});
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "MalformedSampleRenameMapFileDataProvider", expectedExceptions = UserException.class)
+ public void testLoadMalformedSampleRenameMapFile( final String testName, final File mapFile ) {
+ logger.info("Executing test " + testName);
+
+ final GenomeAnalysisEngine engine = new GenomeAnalysisEngine();
+ final Map<String, String> renameMap = engine.loadSampleRenameMap(mapFile);
+ }
+
+ private File createTestSampleRenameMapFile( final List<String> contents ) throws IOException {
+ final File mapFile = createTempFile("TestSampleRenameMapFile", ".tmp");
+ final PrintWriter writer = new PrintWriter(mapFile);
+
+ for ( final String line : contents ) {
+ writer.println(line);
+ }
+ writer.close();
+
+ return mapFile;
+ }
+
+ ///////////////////////////////////////////////////
+ // Test the ReadTransformer ordering enforcement //
+ ///////////////////////////////////////////////////
+
+ public static class TestReadTransformer extends ReadTransformer {
+
+ private OrderingConstraint orderingConstraint = OrderingConstraint.DO_NOT_CARE;
+ private boolean enabled;
+
+ protected TestReadTransformer(final OrderingConstraint orderingConstraint) {
+ this.orderingConstraint = orderingConstraint;
+ enabled = true;
+ }
+
+ // need this because PackageUtils will pick up this class as a possible ReadTransformer
+ protected TestReadTransformer() {
+ enabled = false;
+ }
+
+ @Override
+ public OrderingConstraint getOrderingConstraint() { return orderingConstraint; }
+
+ @Override
+ public ApplicationTime initializeSub(final GenomeAnalysisEngine engine, final Walker walker) { return ApplicationTime.HANDLED_IN_WALKER; }
+
+ @Override
+ public boolean enabled() { return enabled; }
+
+ @Override
+ public GATKSAMRecord apply(final GATKSAMRecord read) { return read; }
+
+ }
+
+ @DataProvider(name = "ReadTransformerData")
+ public Object[][] makeReadTransformerData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final ReadTransformer.OrderingConstraint orderingConstraint1 : ReadTransformer.OrderingConstraint.values() ) {
+ for ( final ReadTransformer.OrderingConstraint orderingConstraint2 : ReadTransformer.OrderingConstraint.values() ) {
+ for ( final ReadTransformer.OrderingConstraint orderingConstraint3 : ReadTransformer.OrderingConstraint.values() ) {
+ tests.add(new Object[]{orderingConstraint1, orderingConstraint2, orderingConstraint3});
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "ReadTransformerData")
+ public void testReadTransformer(final ReadTransformer.OrderingConstraint oc1, final ReadTransformer.OrderingConstraint oc2, final ReadTransformer.OrderingConstraint oc3) {
+
+ final GenomeAnalysisEngine testEngine = new GenomeAnalysisEngine();
+ final List<ReadTransformer> readTransformers = new ArrayList<ReadTransformer>(3);
+ readTransformers.add(new TestReadTransformer(oc1));
+ readTransformers.add(new TestReadTransformer(oc2));
+ readTransformers.add(new TestReadTransformer(oc3));
+
+ final boolean shouldThrowException = numWithConstraint(ReadTransformer.OrderingConstraint.MUST_BE_FIRST, oc1, oc2, oc3) > 1 ||
+ numWithConstraint(ReadTransformer.OrderingConstraint.MUST_BE_LAST, oc1, oc2, oc3) > 1;
+
+ try {
+ testEngine.setReadTransformers(readTransformers);
+
+ Assert.assertFalse(shouldThrowException);
+ Assert.assertEquals(testEngine.getReadTransformers().size(), 3);
+
+ Assert.assertTrue(testEngine.getReadTransformers().get(1).getOrderingConstraint() != ReadTransformer.OrderingConstraint.MUST_BE_FIRST);
+ Assert.assertTrue(testEngine.getReadTransformers().get(2).getOrderingConstraint() != ReadTransformer.OrderingConstraint.MUST_BE_FIRST);
+ Assert.assertTrue(testEngine.getReadTransformers().get(0).getOrderingConstraint() != ReadTransformer.OrderingConstraint.MUST_BE_LAST);
+ Assert.assertTrue(testEngine.getReadTransformers().get(1).getOrderingConstraint() != ReadTransformer.OrderingConstraint.MUST_BE_LAST);
+ } catch (UserException.IncompatibleReadFiltersException e) {
+ Assert.assertTrue(shouldThrowException);
+ }
+ }
+
+ private int numWithConstraint(final ReadTransformer.OrderingConstraint target, final ReadTransformer.OrderingConstraint... constraints ) {
+ int count = 0;
+ for ( final ReadTransformer.OrderingConstraint constraint : constraints ) {
+ if ( constraint == target )
+ count++;
+ }
+ return count;
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/MaxRuntimeIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/MaxRuntimeIntegrationTest.java
new file mode 100644
index 0000000..27b6c1c
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/MaxRuntimeIntegrationTest.java
@@ -0,0 +1,151 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.broadinstitute.gatk.utils.commandline.Argument;
+import org.broadinstitute.gatk.utils.commandline.Output;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.LocusWalker;
+import org.broadinstitute.gatk.utils.SimpleTimer;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *
+ */
+public class MaxRuntimeIntegrationTest extends WalkerTest {
+ public static class SleepingWalker extends LocusWalker<Integer, Integer> {
+ @Output PrintStream out;
+
+ @Argument(fullName="sleepTime",shortName="sleepTime",doc="x", required=false)
+ public int sleepTime = 100;
+
+ @Override
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ try {Thread.sleep(sleepTime);} catch (InterruptedException e) {};
+ return 1;
+ }
+
+ @Override public Integer reduceInit() { return 0; }
+ @Override public Integer reduce(Integer value, Integer sum) { return sum + value; }
+
+ @Override
+ public void onTraversalDone(Integer result) {
+ out.println(result);
+ }
+ }
+
+ private static final long STARTUP_TIME = TimeUnit.NANOSECONDS.convert(60, TimeUnit.SECONDS);
+
+ private class MaxRuntimeTestProvider extends TestDataProvider {
+ final long maxRuntime;
+ final TimeUnit unit;
+
+ public MaxRuntimeTestProvider(final long maxRuntime, final TimeUnit unit) {
+ super(MaxRuntimeTestProvider.class);
+ this.maxRuntime = maxRuntime;
+ this.unit = unit;
+ setName(String.format("Max runtime test : %d of %s", maxRuntime, unit));
+ }
+
+ public long expectedMaxRuntimeNano() {
+ return TimeUnit.NANOSECONDS.convert(maxRuntime, unit) + STARTUP_TIME;
+ }
+ }
+
+ @DataProvider(name = "MaxRuntimeProvider")
+ public Object[][] makeMaxRuntimeProvider() {
+ for ( final TimeUnit requestedUnits : Arrays.asList(TimeUnit.NANOSECONDS, TimeUnit.MILLISECONDS, TimeUnit.SECONDS, TimeUnit.MINUTES) )
+ new MaxRuntimeTestProvider(requestedUnits.convert(30, TimeUnit.SECONDS), requestedUnits);
+
+ return MaxRuntimeTestProvider.getTests(MaxRuntimeTestProvider.class);
+ }
+
+ //
+ // Loop over errors to throw, make sure they are the errors we get back from the engine, regardless of NT type
+ //
+ @Test(enabled = true, dataProvider = "MaxRuntimeProvider", timeOut = 120 * 1000)
+ public void testMaxRuntime(final MaxRuntimeTestProvider cfg) {
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T PrintReads -R " + hg18Reference
+ + " -I " + validationDataLocation + "NA12878.WEx.downsampled20x.bam -o /dev/null"
+ + " -maxRuntime " + cfg.maxRuntime + " -maxRuntimeUnits " + cfg.unit, 0,
+ Collections.<String>emptyList());
+ final SimpleTimer timer = new SimpleTimer().start();
+ executeTest("Max runtime " + cfg, spec);
+ final long actualRuntimeNano = timer.getElapsedTimeNano();
+
+ Assert.assertTrue(actualRuntimeNano < cfg.expectedMaxRuntimeNano(),
+ "Actual runtime " + TimeUnit.SECONDS.convert(actualRuntimeNano, TimeUnit.NANOSECONDS)
+ + " exceeded max. tolerated runtime " + TimeUnit.SECONDS.convert(cfg.expectedMaxRuntimeNano(), TimeUnit.NANOSECONDS)
+ + " given requested runtime " + cfg.maxRuntime + " " + cfg.unit);
+ }
+
+ @DataProvider(name = "SubshardProvider")
+ public Object[][] makeSubshardProvider() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ tests.add(new Object[]{10});
+ tests.add(new Object[]{100});
+ tests.add(new Object[]{500});
+ tests.add(new Object[]{1000});
+ tests.add(new Object[]{2000});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = true, dataProvider = "SubshardProvider", timeOut = 120 * 1000)
+ public void testSubshardTimeout(final int sleepTime) throws Exception {
+ final int maxRuntime = 5000;
+
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T SleepingWalker -R " + b37KGReference
+ + " -I " + privateTestDir + "NA12878.100kb.BQSRv2.example.bam -o %s"
+ + " -maxRuntime " + maxRuntime + " -maxRuntimeUnits MILLISECONDS -sleepTime " + sleepTime, 1,
+ Collections.singletonList(""));
+ final File result = executeTest("Subshard max runtime ", spec).getFirst().get(0);
+ final int cycle = Integer.valueOf(new BufferedReader(new FileReader(result)).readLine());
+
+ final int maxCycles = (int)Math.ceil((maxRuntime * 5) / sleepTime);
+ logger.warn(String.format("Max cycles %d saw %d in file %s with sleepTime %d and maxRuntime %d", maxCycles, cycle, result, sleepTime, maxRuntime));
+ Assert.assertTrue(cycle < maxCycles, "Too many cycles seen -- saw " + cycle + " in file " + result + " but max should have been " + maxCycles);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/ReadMetricsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/ReadMetricsUnitTest.java
new file mode 100644
index 0000000..1153bcc
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/ReadMetricsUnitTest.java
@@ -0,0 +1,371 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.datasources.providers.LocusShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.providers.ReadShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.reads.*;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.executive.WindowMaker;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.engine.traversals.*;
+import org.broadinstitute.gatk.engine.walkers.*;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.activeregion.ActiveRegion;
+import org.broadinstitute.gatk.utils.activeregion.ActivityProfileState;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.sam.*;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+public class ReadMetricsUnitTest extends BaseTest {
+
+ @Test
+ public void testReadsSeenDoNotOverflowInt() {
+
+ final ReadMetrics metrics = new ReadMetrics();
+
+ final long moreThanMaxInt = ((long)Integer.MAX_VALUE) + 1L;
+
+ for ( long i = 0L; i < moreThanMaxInt; i++ ) {
+ metrics.incrementNumReadsSeen();
+ }
+
+ Assert.assertEquals(metrics.getNumReadsSeen(), moreThanMaxInt);
+ Assert.assertTrue(metrics.getNumReadsSeen() > (long) Integer.MAX_VALUE);
+
+ logger.warn(String.format("%d %d %d", Integer.MAX_VALUE, moreThanMaxInt, Long.MAX_VALUE));
+ }
+
+
+ // Test the accuracy of the read metrics
+
+ private IndexedFastaSequenceFile reference;
+ private SAMSequenceDictionary dictionary;
+ private SAMFileHeader header;
+ private GATKSAMReadGroupRecord readGroup;
+ private GenomeLocParser genomeLocParser;
+ private File testBAM;
+
+ private static final int numReadsPerContig = 250000;
+ private static final List<String> contigs = Arrays.asList("1", "2", "3");
+
+ @BeforeClass
+ private void init() throws IOException {
+ reference = new CachingIndexedFastaSequenceFile(new File(b37KGReference));
+ dictionary = reference.getSequenceDictionary();
+ genomeLocParser = new GenomeLocParser(dictionary);
+ header = ArtificialSAMUtils.createDefaultReadGroup(new SAMFileHeader(), "test", "test");
+ header.setSequenceDictionary(dictionary);
+ header.setSortOrder(SAMFileHeader.SortOrder.coordinate);
+ readGroup = new GATKSAMReadGroupRecord(header.getReadGroup("test"));
+
+ final List<GATKSAMRecord> reads = new ArrayList<>();
+ for ( final String contig : contigs ) {
+ for ( int i = 1; i <= numReadsPerContig; i++ ) {
+ reads.add(buildSAMRecord("read" + contig + "_" + i, contig, i));
+ }
+ }
+
+ createBAM(reads);
+ }
+
+ private void createBAM(final List<GATKSAMRecord> reads) throws IOException {
+ testBAM = createTempFile("TraverseActiveRegionsUnitTest", ".bam");
+
+ SAMFileWriter out = new SAMFileWriterFactory().setCreateIndex(true).makeBAMWriter(reads.get(0).getHeader(), true, testBAM);
+ for (GATKSAMRecord read : reads ) {
+ out.addAlignment(read);
+ }
+ out.close();
+
+ new File(testBAM.getAbsolutePath().replace(".bam", ".bai")).deleteOnExit();
+ new File(testBAM.getAbsolutePath() + ".bai").deleteOnExit();
+ }
+
+ // copied from LocusViewTemplate
+ protected GATKSAMRecord buildSAMRecord(final String readName, final String contig, final int alignmentStart) {
+ GATKSAMRecord record = new GATKSAMRecord(header);
+
+ record.setReadName(readName);
+ record.setReferenceIndex(dictionary.getSequenceIndex(contig));
+ record.setAlignmentStart(alignmentStart);
+
+ record.setCigarString("1M");
+ record.setReadString("A");
+ record.setBaseQualityString("A");
+ record.setReadGroup(readGroup);
+
+ return record;
+ }
+
+ @Test
+ public void testCountsFromReadTraversal() {
+ final GenomeAnalysisEngine engine = new GenomeAnalysisEngine();
+ engine.setGenomeLocParser(genomeLocParser);
+
+ final Collection<SAMReaderID> samFiles = new ArrayList<>();
+ final SAMReaderID readerID = new SAMReaderID(testBAM, new Tags());
+ samFiles.add(readerID);
+
+ final SAMDataSource dataSource = new SAMDataSource(samFiles, new ThreadAllocation(), null, genomeLocParser,
+ false,
+ ValidationStringency.STRICT,
+ null,
+ null,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ new ArrayList<ReadTransformer>(),
+ false, (byte)30, false, true, null, IntervalMergingRule.ALL);
+
+ engine.setReadsDataSource(dataSource);
+
+ final TraverseReadsNano traverseReadsNano = new TraverseReadsNano(1);
+ final DummyReadWalker walker = new DummyReadWalker();
+ traverseReadsNano.initialize(engine, walker, null);
+
+ for ( final Shard shard : dataSource.createShardIteratorOverAllReads(new ReadShardBalancer()) ) {
+ final ReadShardDataProvider dataProvider = new ReadShardDataProvider(shard, engine.getGenomeLocParser(), dataSource.seek(shard), reference, new ArrayList<ReferenceOrderedDataSource>());
+ traverseReadsNano.traverse(walker, dataProvider, 0);
+ dataProvider.close();
+ }
+
+ Assert.assertEquals(engine.getCumulativeMetrics().getNumReadsSeen(), contigs.size() * numReadsPerContig);
+ Assert.assertEquals(engine.getCumulativeMetrics().getNumIterations(), contigs.size() * numReadsPerContig);
+ }
+
+ @Test
+ public void testCountsFromLocusTraversal() {
+ final GenomeAnalysisEngine engine = new GenomeAnalysisEngine();
+ engine.setGenomeLocParser(genomeLocParser);
+
+ final Collection<SAMReaderID> samFiles = new ArrayList<>();
+ final SAMReaderID readerID = new SAMReaderID(testBAM, new Tags());
+ samFiles.add(readerID);
+
+ final SAMDataSource dataSource = new SAMDataSource(samFiles, new ThreadAllocation(), null, genomeLocParser,
+ false,
+ ValidationStringency.STRICT,
+ null,
+ null,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ new ArrayList<ReadTransformer>(),
+ false, (byte)30, false, true, null, IntervalMergingRule.ALL);
+
+ engine.setReadsDataSource(dataSource);
+ final Set<String> samples = SampleUtils.getSAMFileSamples(dataSource.getHeader());
+
+ final TraverseLociNano traverseLociNano = new TraverseLociNano(1);
+ final DummyLocusWalker walker = new DummyLocusWalker();
+ traverseLociNano.initialize(engine, walker, null);
+
+ for ( final Shard shard : dataSource.createShardIteratorOverAllReads(new LocusShardBalancer()) ) {
+ final WindowMaker windowMaker = new WindowMaker(shard, genomeLocParser, dataSource.seek(shard), shard.getGenomeLocs(), samples);
+ for ( WindowMaker.WindowMakerIterator window : windowMaker ) {
+ final LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, shard.getReadProperties(), genomeLocParser, window.getLocus(), window, reference, new ArrayList<ReferenceOrderedDataSource>());
+ traverseLociNano.traverse(walker, dataProvider, 0);
+ dataProvider.close();
+ }
+ windowMaker.close();
+ }
+
+ //dataSource.close();
+ Assert.assertEquals(engine.getCumulativeMetrics().getNumReadsSeen(), contigs.size() * numReadsPerContig);
+ Assert.assertEquals(engine.getCumulativeMetrics().getNumIterations(), contigs.size() * numReadsPerContig);
+ }
+
+ @Test
+ public void testCountsFromActiveRegionTraversal() {
+ final GenomeAnalysisEngine engine = new GenomeAnalysisEngine();
+ engine.setGenomeLocParser(genomeLocParser);
+
+ final Collection<SAMReaderID> samFiles = new ArrayList<>();
+ final SAMReaderID readerID = new SAMReaderID(testBAM, new Tags());
+ samFiles.add(readerID);
+
+ final SAMDataSource dataSource = new SAMDataSource(samFiles, new ThreadAllocation(), null, genomeLocParser,
+ false,
+ ValidationStringency.STRICT,
+ null,
+ null,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ new ArrayList<ReadTransformer>(),
+ false, (byte)30, false, true, null, IntervalMergingRule.ALL);
+
+ engine.setReadsDataSource(dataSource);
+ final Set<String> samples = SampleUtils.getSAMFileSamples(dataSource.getHeader());
+
+ final List<GenomeLoc> intervals = new ArrayList<>(contigs.size());
+ for ( final String contig : contigs )
+ intervals.add(genomeLocParser.createGenomeLoc(contig, 1, numReadsPerContig));
+
+ final TraverseActiveRegions traverseActiveRegions = new TraverseActiveRegions();
+ final DummyActiveRegionWalker walker = new DummyActiveRegionWalker();
+ traverseActiveRegions.initialize(engine, walker, null);
+
+ for ( final Shard shard : dataSource.createShardIteratorOverIntervals(new GenomeLocSortedSet(genomeLocParser, intervals), new ActiveRegionShardBalancer()) ) {
+ final WindowMaker windowMaker = new WindowMaker(shard, genomeLocParser, dataSource.seek(shard), shard.getGenomeLocs(), samples);
+ for ( WindowMaker.WindowMakerIterator window : windowMaker ) {
+ final LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, shard.getReadProperties(), genomeLocParser, window.getLocus(), window, reference, new ArrayList<ReferenceOrderedDataSource>());
+ traverseActiveRegions.traverse(walker, dataProvider, 0);
+ dataProvider.close();
+ }
+ windowMaker.close();
+ }
+
+ Assert.assertEquals(engine.getCumulativeMetrics().getNumReadsSeen(), contigs.size() * numReadsPerContig);
+ Assert.assertEquals(engine.getCumulativeMetrics().getNumIterations(), contigs.size() * numReadsPerContig);
+ }
+
+ @Test
+ public void testFilteredCounts() {
+ final GenomeAnalysisEngine engine = new GenomeAnalysisEngine();
+ engine.setGenomeLocParser(genomeLocParser);
+
+ final Collection<SAMReaderID> samFiles = new ArrayList<>();
+ final SAMReaderID readerID = new SAMReaderID(testBAM, new Tags());
+ samFiles.add(readerID);
+
+ final List<ReadFilter> filters = new ArrayList<>();
+ filters.add(new EveryTenthReadFilter());
+
+ final SAMDataSource dataSource = new SAMDataSource(samFiles, new ThreadAllocation(), null, genomeLocParser,
+ false,
+ ValidationStringency.STRICT,
+ null,
+ null,
+ new ValidationExclusion(),
+ filters,
+ new ArrayList<ReadTransformer>(),
+ false, (byte)30, false, true, null, IntervalMergingRule.ALL);
+
+ engine.setReadsDataSource(dataSource);
+
+ final TraverseReadsNano traverseReadsNano = new TraverseReadsNano(1);
+ final DummyReadWalker walker = new DummyReadWalker();
+ traverseReadsNano.initialize(engine, walker, null);
+
+ for ( final Shard shard : dataSource.createShardIteratorOverAllReads(new ReadShardBalancer()) ) {
+ final ReadShardDataProvider dataProvider = new ReadShardDataProvider(shard, engine.getGenomeLocParser(), dataSource.seek(shard), reference, new ArrayList<ReferenceOrderedDataSource>());
+ traverseReadsNano.traverse(walker, dataProvider, 0);
+ dataProvider.close();
+ }
+
+ Assert.assertEquals((long)engine.getCumulativeMetrics().getCountsByFilter().get(EveryTenthReadFilter.class.getSimpleName()), contigs.size() * numReadsPerContig / 10);
+ }
+
+ class DummyLocusWalker extends LocusWalker<Integer, Integer> {
+ @Override
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ return 0;
+ }
+
+ @Override
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ @Override
+ public Integer reduce(Integer value, Integer sum) {
+ return 0;
+ }
+ }
+
+ class DummyReadWalker extends ReadWalker<Integer, Integer> {
+ @Override
+ public Integer map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker metaDataTracker) {
+ return 0;
+ }
+
+ @Override
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ @Override
+ public Integer reduce(Integer value, Integer sum) {
+ return 0;
+ }
+ }
+
+ class DummyActiveRegionWalker extends ActiveRegionWalker<Integer, Integer> {
+ @Override
+ public ActivityProfileState isActive(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ return new ActivityProfileState(ref.getLocus(), 0.0);
+ }
+
+ @Override
+ public Integer map(ActiveRegion activeRegion, RefMetaDataTracker metaDataTracker) {
+ return 0;
+ }
+
+ @Override
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ @Override
+ public Integer reduce(Integer value, Integer sum) {
+ return 0;
+ }
+ }
+
+ private final class EveryTenthReadFilter extends ReadFilter {
+
+ private int myCounter = 0;
+
+ @Override
+ public boolean filterOut(final SAMRecord record) {
+ if ( ++myCounter == 10 ) {
+ myCounter = 0;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/WalkerManagerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/WalkerManagerUnitTest.java
new file mode 100644
index 0000000..62348ef
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/WalkerManagerUnitTest.java
@@ -0,0 +1,71 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine;
+
+import org.broadinstitute.gatk.utils.commandline.Hidden;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.tools.walkers.qc.CountLoci;
+import org.broadinstitute.gatk.utils.exceptions.DynamicClassResolutionException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ * Tests basic functionality of the walker manager.
+ */
+public class WalkerManagerUnitTest {
+ private static WalkerManager walkerManager;
+
+ @BeforeClass
+ public void setUp() {
+ walkerManager = new WalkerManager();
+ }
+
+ @Test
+ public void testPresentWalker() {
+ Walker countLociWalker = walkerManager.createByName("CountLoci");
+ Assert.assertEquals(CountLoci.class,countLociWalker.getClass());
+ }
+
+ @Test(expectedExceptions=UserException.class)
+ public void testAbsentWalker() {
+ walkerManager.createByName("Missing");
+ }
+
+ @Test(expectedExceptions=DynamicClassResolutionException.class)
+ public void testUninstantiableWalker() {
+ walkerManager.createByName("UninstantiableWalker");
+ }
+}
+
+ at Hidden
+class UninstantiableWalker extends Walker<Integer,Long> {
+ // Private constructor will generate uninstantiable message
+ private UninstantiableWalker() {}
+ public Long reduceInit() { return 0L; }
+ public Long reduce(Integer value, Long accum) { return 0L; }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/AllLocusViewUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/AllLocusViewUnitTest.java
new file mode 100644
index 0000000..f9d9dfe
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/AllLocusViewUnitTest.java
@@ -0,0 +1,90 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+
+import java.util.List;
+/**
+ * User: hanna
+ * Date: May 12, 2009
+ * Time: 2:34:46 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Test the view of all loci.
+ */
+public class AllLocusViewUnitTest extends LocusViewTemplate {
+
+ @Override
+ protected LocusView createView(LocusShardDataProvider provider) {
+ return new AllLocusView(provider);
+ }
+
+ /**
+ * Test the reads according to an independently derived context.
+ * @param view
+ * @param range
+ * @param reads
+ */
+ @Override
+ protected void testReadsInContext( LocusView view, List<GenomeLoc> range, List<GATKSAMRecord> reads ) {
+ AllLocusView allLocusView = (AllLocusView)view;
+
+ // TODO: Should skip over loci not in the given range.
+ GenomeLoc firstLoc = range.get(0);
+ GenomeLoc lastLoc = range.get(range.size()-1);
+ GenomeLoc bounds = genomeLocParser.createGenomeLoc(firstLoc.getContig(),firstLoc.getStart(),lastLoc.getStop());
+
+ for( int i = bounds.getStart(); i <= bounds.getStop(); i++ ) {
+ GenomeLoc site = genomeLocParser.createGenomeLoc("chr1",i);
+ AlignmentContext locusContext = allLocusView.next();
+ Assert.assertEquals(locusContext.getLocation(), site, "Locus context location is incorrect");
+ int expectedReadsAtSite = 0;
+
+ for( GATKSAMRecord read: reads ) {
+ if(genomeLocParser.createGenomeLoc(read).containsP(locusContext.getLocation())) {
+ Assert.assertTrue(locusContext.getReads().contains(read),"Target locus context does not contain reads");
+ expectedReadsAtSite++;
+ }
+ }
+
+ Assert.assertEquals(locusContext.getReads().size(), expectedReadsAtSite, "Found wrong number of reads at site");
+ }
+
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/CoveredLocusViewUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/CoveredLocusViewUnitTest.java
new file mode 100644
index 0000000..8914a48
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/CoveredLocusViewUnitTest.java
@@ -0,0 +1,103 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+
+import java.util.List;
+/**
+ * User: hanna
+ * Date: May 12, 2009
+ * Time: 2:34:46 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Test the CoveredLocusView.
+ */
+public class CoveredLocusViewUnitTest extends LocusViewTemplate {
+
+ /**
+ * Retrieve a covered locus view.
+ */
+ @Override
+ protected LocusView createView(LocusShardDataProvider provider) {
+ return new CoveredLocusView(provider);
+ }
+
+ /**
+ * Test the reads according to an independently derived context.
+ * @param view
+ * @param range
+ * @param reads
+ */
+ @Override
+ protected void testReadsInContext( LocusView view, List<GenomeLoc> range, List<GATKSAMRecord> reads ) {
+ CoveredLocusView coveredLocusView = (CoveredLocusView)view;
+
+ // TODO: Should skip over loci not in the given range.
+ GenomeLoc firstLoc = range.get(0);
+ GenomeLoc lastLoc = range.get(range.size()-1);
+ GenomeLoc bounds = genomeLocParser.createGenomeLoc(firstLoc.getContig(),firstLoc.getStart(),lastLoc.getStop());
+
+ for( int i = bounds.getStart(); i <= bounds.getStop(); i++ ) {
+ GenomeLoc site = genomeLocParser.createGenomeLoc("chr1",i);
+
+ int expectedReadsAtSite = 0;
+ for( GATKSAMRecord read: reads ) {
+ if( genomeLocParser.createGenomeLoc(read).containsP(site) )
+ expectedReadsAtSite++;
+ }
+
+ if( expectedReadsAtSite < 1 )
+ continue;
+
+ Assert.assertTrue(coveredLocusView.hasNext(),"Incorrect number of loci in view");
+
+ AlignmentContext locusContext = coveredLocusView.next();
+ Assert.assertEquals(locusContext.getLocation(), site, "Target locus context location is incorrect");
+ Assert.assertEquals(locusContext.getReads().size(), expectedReadsAtSite, "Found wrong number of reads at site");
+
+ for( GATKSAMRecord read: reads ) {
+ if(genomeLocParser.createGenomeLoc(read).containsP(locusContext.getLocation()))
+ Assert.assertTrue(locusContext.getReads().contains(read),"Target locus context does not contain reads");
+ }
+ }
+
+ Assert.assertFalse(coveredLocusView.hasNext(),"Iterator is not bounded at boundaries of shard");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/IntervalReferenceOrderedViewUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/IntervalReferenceOrderedViewUnitTest.java
new file mode 100644
index 0000000..29ccbd6
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/IntervalReferenceOrderedViewUnitTest.java
@@ -0,0 +1,366 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.samtools.util.PeekableIterator;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.tribble.BasicFeature;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.engine.refdata.RODRecordListImpl;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+/**
+ * @author depristo
+ */
+public class IntervalReferenceOrderedViewUnitTest extends BaseTest {
+ private static int startingChr = 1;
+ private static int endingChr = 2;
+ private static int readCount = 100;
+ private static int DEFAULT_READ_LENGTH = ArtificialSAMUtils.DEFAULT_READ_LENGTH;
+ private static String contig;
+ private static SAMFileHeader header;
+
+ private GenomeLocParser genomeLocParser;
+
+ @BeforeClass
+ public void beforeClass() {
+ header = ArtificialSAMUtils.createArtificialSamHeader((endingChr - startingChr) + 1, startingChr, readCount + DEFAULT_READ_LENGTH);
+ contig = header.getSequence(0).getSequenceName();
+ genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+
+ initializeTests();
+ }
+
+ private class CompareFeatures implements Comparator<Feature> {
+ @Override
+ public int compare(Feature o1, Feature o2) {
+ return genomeLocParser.createGenomeLoc(o1).compareTo(genomeLocParser.createGenomeLoc(o2));
+ }
+ }
+
+ private class ReadMetaDataTrackerRODStreamTest extends TestDataProvider {
+ final List<Feature> allFeatures;
+ final List<GenomeLoc> intervals;
+
+ public ReadMetaDataTrackerRODStreamTest(final List<Feature> allFeatures, final GenomeLoc interval) {
+ this(allFeatures, Collections.singletonList(interval));
+ }
+
+ public ReadMetaDataTrackerRODStreamTest(final List<Feature> allFeatures, final List<GenomeLoc> intervals) {
+ super(ReadMetaDataTrackerRODStreamTest.class);
+ this.allFeatures = new ArrayList<Feature>(allFeatures);
+ Collections.sort(this.allFeatures, new CompareFeatures());
+ this.intervals = new ArrayList<GenomeLoc>(intervals);
+ Collections.sort(this.intervals);
+ setName(String.format("%s nFeatures %d intervals %s", getClass().getSimpleName(), allFeatures.size(),
+ intervals.size() == 1 ? intervals.get(0) : "size " + intervals.size()));
+ }
+
+ public PeekableIterator<RODRecordList> getIterator(final String name) {
+ return new PeekableIterator<RODRecordList>(new TribbleIteratorFromCollection(name, genomeLocParser, allFeatures));
+ }
+
+ public Set<Feature> getExpectedOverlaps(final GenomeLoc interval) {
+ final Set<Feature> overlapping = new HashSet<Feature>();
+ for ( final Feature f : allFeatures )
+ if ( genomeLocParser.createGenomeLoc(f).overlapsP(interval) )
+ overlapping.add(f);
+ return overlapping;
+ }
+ }
+
+ public void initializeTests() {
+ final List<Feature> handPickedFeatures = new ArrayList<Feature>();
+
+ handPickedFeatures.add(new BasicFeature(contig, 1, 1));
+ handPickedFeatures.add(new BasicFeature(contig, 2, 5));
+ handPickedFeatures.add(new BasicFeature(contig, 4, 4));
+ handPickedFeatures.add(new BasicFeature(contig, 6, 6));
+ handPickedFeatures.add(new BasicFeature(contig, 9, 10));
+ handPickedFeatures.add(new BasicFeature(contig, 10, 10));
+ handPickedFeatures.add(new BasicFeature(contig, 10, 11));
+ handPickedFeatures.add(new BasicFeature(contig, 13, 20));
+
+ createTestsForFeatures(handPickedFeatures);
+
+ // test in the present of a large spanning element
+ {
+ List<Feature> oneLargeSpan = new ArrayList<Feature>(handPickedFeatures);
+ oneLargeSpan.add(new BasicFeature(contig, 1, 30));
+ createTestsForFeatures(oneLargeSpan);
+ }
+
+ // test in the presence of a partially spanning element
+ {
+ List<Feature> partialSpanStart = new ArrayList<Feature>(handPickedFeatures);
+ partialSpanStart.add(new BasicFeature(contig, 1, 6));
+ createTestsForFeatures(partialSpanStart);
+ }
+
+ // test in the presence of a partially spanning element at the end
+ {
+ List<Feature> partialSpanEnd = new ArrayList<Feature>(handPickedFeatures);
+ partialSpanEnd.add(new BasicFeature(contig, 10, 30));
+ createTestsForFeatures(partialSpanEnd);
+ }
+
+ // no data at all
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(contig, 5, 5);
+ new ReadMetaDataTrackerRODStreamTest(Collections.<Feature>emptyList(), loc);
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // tests for the lower level IntervalOverlappingRODsFromStream
+ //
+ // --------------------------------------------------------------------------------
+
+ @DataProvider(name = "ReadMetaDataTrackerRODStreamTest")
+ public Object[][] createReadMetaDataTrackerRODStreamTest() {
+ return ReadMetaDataTrackerRODStreamTest.getTests(ReadMetaDataTrackerRODStreamTest.class);
+ }
+
+ private GenomeLoc span(final List<GenomeLoc> features) {
+ int featuresStart = 1; for ( final GenomeLoc f : features ) featuresStart = Math.min(featuresStart, f.getStart());
+ int featuresStop = 1; for ( final GenomeLoc f : features ) featuresStop = Math.max(featuresStop, f.getStop());
+ return genomeLocParser.createGenomeLoc(contig, featuresStart, featuresStop);
+ }
+
+ private void createTestsForFeatures(final List<Feature> features) {
+ int featuresStart = 1; for ( final Feature f : features ) featuresStart = Math.min(featuresStart, f.getStart());
+ int featuresStop = 1; for ( final Feature f : features ) featuresStop = Math.max(featuresStop, f.getEnd());
+
+ for ( final int size : Arrays.asList(1, 5, 10, 100) ) {
+ final List<GenomeLoc> allIntervals = new ArrayList<GenomeLoc>();
+ // regularly spaced
+ for ( int start = featuresStart; start < featuresStop; start++) {
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(contig, start, start + size - 1);
+ allIntervals.add(loc);
+ new ReadMetaDataTrackerRODStreamTest(features, loc);
+ }
+
+ // starting and stopping at every feature
+ for ( final Feature f : features ) {
+ // just at the feature
+ allIntervals.add(genomeLocParser.createGenomeLoc(contig, f.getStart(), f.getEnd()));
+ new ReadMetaDataTrackerRODStreamTest(features, allIntervals.get(allIntervals.size() - 1));
+
+ // up to end
+ allIntervals.add(genomeLocParser.createGenomeLoc(contig, f.getStart() - 1, f.getEnd()));
+ new ReadMetaDataTrackerRODStreamTest(features, allIntervals.get(allIntervals.size() - 1));
+
+ // missing by 1
+ allIntervals.add(genomeLocParser.createGenomeLoc(contig, f.getStart() + 1, f.getEnd() + 1));
+ new ReadMetaDataTrackerRODStreamTest(features, allIntervals.get(allIntervals.size() - 1));
+
+ // just spanning
+ allIntervals.add(genomeLocParser.createGenomeLoc(contig, f.getStart() - 1, f.getEnd() + 1));
+ new ReadMetaDataTrackerRODStreamTest(features, allIntervals.get(allIntervals.size() - 1));
+ }
+
+ new ReadMetaDataTrackerRODStreamTest(features, allIntervals);
+ }
+ }
+
+ @Test(enabled = true, dataProvider = "ReadMetaDataTrackerRODStreamTest")
+ public void runReadMetaDataTrackerRODStreamTest_singleQuery(final ReadMetaDataTrackerRODStreamTest data) {
+ if ( data.intervals.size() == 1 ) {
+ final String name = "testName";
+ final PeekableIterator<RODRecordList> iterator = data.getIterator(name);
+ final IntervalOverlappingRODsFromStream stream = new IntervalOverlappingRODsFromStream(name, iterator);
+ testRODStream(data, stream, Collections.singletonList(data.intervals.get(0)));
+ }
+ }
+
+ @Test(enabled = true, dataProvider = "ReadMetaDataTrackerRODStreamTest", dependsOnMethods = "runReadMetaDataTrackerRODStreamTest_singleQuery")
+ public void runReadMetaDataTrackerRODStreamTest_multipleQueries(final ReadMetaDataTrackerRODStreamTest data) {
+ if ( data.intervals.size() > 1 ) {
+ final String name = "testName";
+ final PeekableIterator<RODRecordList> iterator = data.getIterator(name);
+ final IntervalOverlappingRODsFromStream stream = new IntervalOverlappingRODsFromStream(name, iterator);
+ testRODStream(data, stream, data.intervals);
+ }
+ }
+
+ private void testRODStream(final ReadMetaDataTrackerRODStreamTest test, final IntervalOverlappingRODsFromStream stream, final List<GenomeLoc> intervals) {
+ for ( final GenomeLoc interval : intervals ) {
+ final RODRecordList query = stream.getOverlapping(interval);
+ final HashSet<Feature> queryFeatures = new HashSet<Feature>();
+ for ( final GATKFeature f : query ) queryFeatures.add((Feature)f.getUnderlyingObject());
+ final Set<Feature> overlaps = test.getExpectedOverlaps(interval);
+
+ Assert.assertEquals(queryFeatures.size(), overlaps.size(), "IntervalOverlappingRODsFromStream didn't return the expected set of overlapping features." +
+ " Expected size = " + overlaps.size() + " but saw " + queryFeatures.size());
+
+ BaseTest.assertEqualsSet(queryFeatures, overlaps, "IntervalOverlappingRODsFromStream didn't return the expected set of overlapping features." +
+ " Expected = " + Utils.join(",", overlaps) + " but saw " + Utils.join(",", queryFeatures));
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // tests for the higher level tracker itself
+ //
+ // --------------------------------------------------------------------------------
+
+ @DataProvider(name = "ReadMetaDataTrackerTests")
+ public Object[][] createTrackerTests() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final Object[][] singleTests = ReadMetaDataTrackerRODStreamTest.getTests(ReadMetaDataTrackerRODStreamTest.class);
+ final List<ReadMetaDataTrackerRODStreamTest> multiSiteTests = new ArrayList<ReadMetaDataTrackerRODStreamTest>();
+ for ( final Object[] singleTest : singleTests ) {
+ if ( ((ReadMetaDataTrackerRODStreamTest)singleTest[0]).intervals.size() > 1 )
+ multiSiteTests.add((ReadMetaDataTrackerRODStreamTest)singleTest[0]);
+ }
+
+ for ( final boolean testStateless : Arrays.asList(true, false) ) {
+ // all pairwise tests
+ for ( List<ReadMetaDataTrackerRODStreamTest> singleTest : Utils.makePermutations(multiSiteTests, 2, false)) {
+ tests.add(new Object[]{singleTest, testStateless});
+ }
+
+ // all 3 way pairwise tests
+ //for ( List<ReadMetaDataTrackerRODStreamTest> singleTest : Utils.makePermutations(multiSiteTests, 3, false)) {
+ // tests.add(new Object[]{singleTest, testStateless});
+ //}
+ }
+
+ logger.warn("Creating " + tests.size() + " tests for ReadMetaDataTrackerTests");
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = true, dataProvider = "ReadMetaDataTrackerTests", dependsOnMethods = "runReadMetaDataTrackerRODStreamTest_multipleQueries")
+ public void runReadMetaDataTrackerTest(final List<ReadMetaDataTrackerRODStreamTest> RODs, final boolean testStateless) {
+ final List<String> names = new ArrayList<String>();
+ final List<PeekableIterator<RODRecordList>> iterators = new ArrayList<PeekableIterator<RODRecordList>>();
+ final List<GenomeLoc> intervals = new ArrayList<GenomeLoc>();
+ final List<RodBinding<Feature>> rodBindings = new ArrayList<RodBinding<Feature>>();
+
+ for ( int i = 0; i < RODs.size(); i++ ) {
+ final RodBinding<Feature> rodBinding = new RodBinding<Feature>(Feature.class, "name"+i);
+ rodBindings.add(rodBinding);
+ final String name = rodBinding.getName();
+ names.add(name);
+ iterators.add(RODs.get(i).getIterator(name));
+ intervals.addAll(RODs.get(i).intervals);
+ }
+
+ Collections.sort(intervals);
+ final GenomeLoc span = span(intervals);
+ final IntervalReferenceOrderedView view = new IntervalReferenceOrderedView(genomeLocParser, span, names, iterators);
+
+ if ( testStateless ) {
+ // test each tracker is well formed, as each is created
+ for ( final GenomeLoc interval : intervals ) {
+ final RefMetaDataTracker tracker = view.getReferenceOrderedDataForInterval(interval);
+ testMetaDataTrackerBindings(tracker, interval, RODs, rodBindings);
+ }
+ } else {
+ // tests all trackers are correct after reading them into an array
+ // this checks that the trackers are be safely stored away and analyzed later (critical for nano-scheduling)
+ final List<RefMetaDataTracker> trackers = new ArrayList<RefMetaDataTracker>();
+ for ( final GenomeLoc interval : intervals ) {
+ final RefMetaDataTracker tracker = view.getReferenceOrderedDataForInterval(interval);
+ trackers.add(tracker);
+ }
+
+ for ( int i = 0; i < trackers.size(); i++) {
+ testMetaDataTrackerBindings(trackers.get(i), intervals.get(i), RODs, rodBindings);
+ }
+ }
+ }
+
+ private void testMetaDataTrackerBindings(final RefMetaDataTracker tracker,
+ final GenomeLoc interval,
+ final List<ReadMetaDataTrackerRODStreamTest> RODs,
+ final List<RodBinding<Feature>> rodBindings) {
+ for ( int i = 0; i < RODs.size(); i++ ) {
+ final ReadMetaDataTrackerRODStreamTest test = RODs.get(i);
+ final List<Feature> queryFeaturesList = tracker.getValues(rodBindings.get(i));
+ final Set<Feature> queryFeatures = new HashSet<Feature>(queryFeaturesList);
+ final Set<Feature> overlaps = test.getExpectedOverlaps(interval);
+
+ Assert.assertEquals(queryFeatures.size(), overlaps.size(), "IntervalOverlappingRODsFromStream didn't return the expected set of overlapping features." +
+ " Expected size = " + overlaps.size() + " but saw " + queryFeatures.size());
+
+ BaseTest.assertEqualsSet(queryFeatures, overlaps, "IntervalOverlappingRODsFromStream didn't return the expected set of overlapping features." +
+ " Expected = " + Utils.join(",", overlaps) + " but saw " + Utils.join(",", queryFeatures));
+ }
+ }
+
+ static class TribbleIteratorFromCollection implements Iterator<RODRecordList> {
+ // current location
+ private final String name;
+ final Queue<GATKFeature> gatkFeatures;
+
+ public TribbleIteratorFromCollection(final String name, final GenomeLocParser genomeLocParser, final List<Feature> features) {
+ this.name = name;
+
+ this.gatkFeatures = new LinkedList<GATKFeature>();
+ for ( final Feature f : features )
+ gatkFeatures.add(new GATKFeature.TribbleGATKFeature(genomeLocParser, f, name));
+ }
+
+ @Override
+ public boolean hasNext() {
+ return ! gatkFeatures.isEmpty();
+ }
+
+ @Override
+ public RODRecordList next() {
+ final GATKFeature first = gatkFeatures.poll();
+ final Collection<GATKFeature> myFeatures = new LinkedList<GATKFeature>();
+ myFeatures.add(first);
+ while ( gatkFeatures.peek() != null && gatkFeatures.peek().getLocation().getStart() == first.getStart() )
+ myFeatures.add(gatkFeatures.poll());
+
+ GenomeLoc loc = first.getLocation();
+ for ( final GATKFeature feature : myFeatures )
+ loc = loc.merge(feature.getLocation());
+
+ return new RODRecordListImpl(name, myFeatures, loc); // is this safe?
+ }
+
+ @Override public void remove() { throw new IllegalStateException("GRRR"); }
+ }
+}
+
+
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/LocusReferenceViewUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/LocusReferenceViewUnitTest.java
new file mode 100644
index 0000000..5eb9c7a
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/LocusReferenceViewUnitTest.java
@@ -0,0 +1,143 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.engine.datasources.reads.MockLocusShard;
+import org.broadinstitute.gatk.engine.iterators.GenomeLocusIterator;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+
+import htsjdk.samtools.reference.ReferenceSequence;
+import htsjdk.samtools.util.StringUtil;
+
+import java.util.Collections;
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/** Tests for viewing the reference from the perspective of a locus. */
+
+public class LocusReferenceViewUnitTest extends ReferenceViewTemplate {
+
+//
+// /** Multiple-base pair queries should generate exceptions. */
+// @Test(expectedExceptions=InvalidPositionException.class)
+// public void testSingleBPFailure() {
+// Shard shard = new LocusShard(GenomeLocParser.createGenomeLoc(0, 1, 50));
+//
+// ShardDataProvider dataProvider = new ShardDataProvider(shard, null, sequenceFile, null);
+// LocusReferenceView view = new LocusReferenceView(dataProvider);
+//
+// view.getReferenceContext(shard.getGenomeLoc()).getBase();
+// }
+
+ @Test
+ public void testOverlappingReferenceBases() {
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc(sequenceFile.getSequenceDictionary().getSequence(0).getSequenceName(),
+ sequenceFile.getSequence("chrM").length() - 10,
+ sequenceFile.getSequence("chrM").length())));
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, null, genomeLocParser, shard.getGenomeLocs().get(0), null, sequenceFile, null);
+ LocusReferenceView view = new LocusReferenceView(dataProvider);
+
+ byte[] results = view.getReferenceBases(genomeLocParser.createGenomeLoc(sequenceFile.getSequenceDictionary().getSequence(0).getSequenceName(),
+ sequenceFile.getSequence("chrM").length() - 10,
+ sequenceFile.getSequence("chrM").length() + 9));
+ System.out.printf("results are %s%n", new String(results));
+ Assert.assertEquals(results.length, 20);
+ for (int x = 0; x < results.length; x++) {
+ if (x <= 10) Assert.assertTrue(results[x] != 'X');
+ else Assert.assertTrue(results[x] == 'X');
+ }
+ }
+
+
+ /** Queries outside the bounds of the shard should result in reference context window trimmed at the shard boundary. */
+ @Test
+ public void testBoundsFailure() {
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc(sequenceFile.getSequenceDictionary().getSequence(0).getSequenceName(), 1, 50)));
+
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, null, genomeLocParser, shard.getGenomeLocs().get(0), null, sequenceFile, null);
+ LocusReferenceView view = new LocusReferenceView(dataProvider);
+
+ GenomeLoc locus = genomeLocParser.createGenomeLoc(sequenceFile.getSequenceDictionary().getSequence(0).getSequenceName(), 50, 51);
+
+ ReferenceContext rc = view.getReferenceContext(locus);
+ Assert.assertTrue(rc.getLocus().equals(locus));
+ Assert.assertTrue(rc.getWindow().equals(genomeLocParser.createGenomeLoc(sequenceFile.getSequenceDictionary().getSequence(0).getSequenceName(),50)));
+ Assert.assertTrue(rc.getBases().length == 1);
+ }
+
+
+ /**
+ * Compares the contents of the fasta and view at a specified location.
+ *
+ * @param loc
+ */
+ protected void validateLocation( GenomeLoc loc ) {
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(loc));
+ GenomeLocusIterator shardIterator = new GenomeLocusIterator(genomeLocParser,loc);
+
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, null, genomeLocParser, loc, null, sequenceFile, null);
+ LocusReferenceView view = new LocusReferenceView(dataProvider);
+
+ while (shardIterator.hasNext()) {
+ GenomeLoc locus = shardIterator.next();
+
+ ReferenceSequence expectedAsSeq = sequenceFile.getSubsequenceAt(locus.getContig(), locus.getStart(), locus.getStop());
+ char expected = Character.toUpperCase(StringUtil.bytesToString(expectedAsSeq.getBases()).charAt(0));
+ char actual = view.getReferenceContext(locus).getBaseAsChar();
+
+ Assert.assertEquals(actual, expected, String.format("Value of base at position %s in shard %s does not match expected", locus.toString(), shard.getGenomeLocs())
+ );
+ }
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/LocusViewTemplate.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/LocusViewTemplate.java
new file mode 100644
index 0000000..650b146
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/LocusViewTemplate.java
@@ -0,0 +1,405 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.samtools.reference.ReferenceSequence;
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.datasources.reads.MockLocusShard;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.engine.executive.WindowMaker;
+import org.broadinstitute.gatk.engine.datasources.reads.LocusShard;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMDataSource;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.*;
+/**
+ * User: hanna
+ * Date: May 13, 2009
+ * Time: 4:29:08 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/** Base support for testing variants of the LocusView family of classes. */
+
+public abstract class LocusViewTemplate extends BaseTest {
+ protected static ReferenceSequenceFile sequenceSourceFile = null;
+ protected GenomeLocParser genomeLocParser = null;
+
+ @BeforeClass
+ public void setupGenomeLoc() throws FileNotFoundException {
+ sequenceSourceFile = fakeReferenceSequenceFile();
+ genomeLocParser = new GenomeLocParser(sequenceSourceFile);
+ }
+
+ @Test
+ public void emptyAlignmentContextTest() {
+ SAMRecordIterator iterator = new SAMRecordIterator();
+
+ GenomeLoc shardBounds = genomeLocParser.createGenomeLoc("chr1", 1, 5);
+ Shard shard = new LocusShard(genomeLocParser, new SAMDataSource(Collections.<SAMReaderID>emptyList(),new ThreadAllocation(),null,genomeLocParser),Collections.singletonList(shardBounds),Collections.<SAMReaderID,SAMFileSpan>emptyMap());
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, null, genomeLocParser, window.getLocus(), window, null, null);
+
+ LocusView view = createView(dataProvider);
+
+ testReadsInContext(view, shard.getGenomeLocs(), Collections.<GATKSAMRecord>emptyList());
+ }
+
+ @Test
+ public void singleReadTest() {
+ GATKSAMRecord read = buildSAMRecord("read1","chr1", 1, 5);
+ SAMRecordIterator iterator = new SAMRecordIterator(read);
+
+ GenomeLoc shardBounds = genomeLocParser.createGenomeLoc("chr1", 1, 5);
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(shardBounds));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+
+ LocusView view = createView(dataProvider);
+
+ testReadsInContext(view, shard.getGenomeLocs(), Collections.singletonList(read));
+ }
+
+ @Test
+ public void readCoveringFirstPartTest() {
+ GATKSAMRecord read = buildSAMRecord("read1","chr1", 1, 5);
+ SAMRecordIterator iterator = new SAMRecordIterator(read);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chr1", 1, 10)));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+ LocusView view = createView(dataProvider);
+
+ testReadsInContext(view, shard.getGenomeLocs(), Collections.singletonList(read));
+ }
+
+ @Test
+ public void readCoveringLastPartTest() {
+ GATKSAMRecord read = buildSAMRecord("read1","chr1", 6, 10);
+ SAMRecordIterator iterator = new SAMRecordIterator(read);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chr1", 1, 10)));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+ LocusView view = createView(dataProvider);
+
+ testReadsInContext(view, shard.getGenomeLocs(), Collections.singletonList(read));
+ }
+
+ @Test
+ public void readCoveringMiddleTest() {
+ GATKSAMRecord read = buildSAMRecord("read1","chr1", 3, 7);
+ SAMRecordIterator iterator = new SAMRecordIterator(read);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chr1", 1, 10)));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+ LocusView view = createView(dataProvider);
+
+ testReadsInContext(view, shard.getGenomeLocs(), Collections.singletonList(read));
+ }
+
+ @Test
+ public void readAndLocusOverlapAtLastBase() {
+ GATKSAMRecord read = buildSAMRecord("read1","chr1", 1, 5);
+ SAMRecordIterator iterator = new SAMRecordIterator(read);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chr1", 5, 5)));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+ LocusView view = createView(dataProvider);
+
+ testReadsInContext(view, shard.getGenomeLocs(), Collections.singletonList(read));
+ }
+
+ @Test
+ public void readOverlappingStartTest() {
+ GATKSAMRecord read = buildSAMRecord("read1","chr1", 1, 10);
+ SAMRecordIterator iterator = new SAMRecordIterator(read);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chr1", 6, 15)));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+ LocusView view = createView(dataProvider);
+
+ testReadsInContext(view, shard.getGenomeLocs(), Collections.singletonList(read));
+ }
+
+ @Test
+ public void readOverlappingEndTest() {
+ GATKSAMRecord read = buildSAMRecord("read1","chr1", 6, 15);
+ SAMRecordIterator iterator = new SAMRecordIterator(read);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chr1", 1, 10)));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+ LocusView view = createView(dataProvider);
+
+ testReadsInContext(view, shard.getGenomeLocs(), Collections.singletonList(read));
+ }
+
+ @Test
+ public void readsSpanningTest() {
+ GATKSAMRecord read1 = buildSAMRecord("read1","chr1", 1, 5);
+ GATKSAMRecord read2 = buildSAMRecord("read2","chr1", 6, 10);
+ SAMRecordIterator iterator = new SAMRecordIterator(read1, read2);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chr1", 1, 10)));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+ LocusView view = createView(dataProvider);
+
+ List<GATKSAMRecord> expectedReads = new ArrayList<GATKSAMRecord>();
+ Collections.addAll(expectedReads, read1, read2);
+ testReadsInContext(view, shard.getGenomeLocs(), expectedReads);
+ }
+
+ @Test
+ public void duplicateReadsTest() {
+ GATKSAMRecord read1 = buildSAMRecord("read1","chr1", 1, 5);
+ GATKSAMRecord read2 = buildSAMRecord("read2","chr1", 1, 5);
+ GATKSAMRecord read3 = buildSAMRecord("read3","chr1", 6, 10);
+ GATKSAMRecord read4 = buildSAMRecord("read4","chr1", 6, 10);
+ SAMRecordIterator iterator = new SAMRecordIterator(read1, read2, read3, read4);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chr1", 1, 10)));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+ LocusView view = createView(dataProvider);
+
+ List<GATKSAMRecord> expectedReads = new ArrayList<GATKSAMRecord>();
+ Collections.addAll(expectedReads, read1, read2, read3, read4);
+ testReadsInContext(view, shard.getGenomeLocs(), expectedReads);
+ }
+
+ @Test
+ public void cascadingReadsWithinBoundsTest() {
+ GATKSAMRecord read1 = buildSAMRecord("read1","chr1", 2, 6);
+ GATKSAMRecord read2 = buildSAMRecord("read2","chr1", 3, 7);
+ GATKSAMRecord read3 = buildSAMRecord("read3","chr1", 4, 8);
+ GATKSAMRecord read4 = buildSAMRecord("read4","chr1", 5, 9);
+ SAMRecordIterator iterator = new SAMRecordIterator(read1, read2, read3, read4);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chr1", 1, 10)));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+ LocusView view = createView(dataProvider);
+
+ List<GATKSAMRecord> expectedReads = new ArrayList<GATKSAMRecord>();
+ Collections.addAll(expectedReads, read1, read2, read3, read4);
+ testReadsInContext(view, shard.getGenomeLocs(), expectedReads);
+ }
+
+ @Test
+ public void cascadingReadsAtBoundsTest() {
+ GATKSAMRecord read1 = buildSAMRecord("read1","chr1", 1, 5);
+ GATKSAMRecord read2 = buildSAMRecord("read2","chr1", 2, 6);
+ GATKSAMRecord read3 = buildSAMRecord("read3","chr1", 3, 7);
+ GATKSAMRecord read4 = buildSAMRecord("read4","chr1", 4, 8);
+ GATKSAMRecord read5 = buildSAMRecord("read5","chr1", 5, 9);
+ GATKSAMRecord read6 = buildSAMRecord("read6","chr1", 6, 10);
+ SAMRecordIterator iterator = new SAMRecordIterator(read1, read2, read3, read4, read5, read6);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chr1", 1, 10)));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+ LocusView view = createView(dataProvider);
+
+ List<GATKSAMRecord> expectedReads = new ArrayList<GATKSAMRecord>();
+ Collections.addAll(expectedReads, read1, read2, read3, read4, read5, read6);
+ testReadsInContext(view, shard.getGenomeLocs(), expectedReads);
+ }
+
+ @Test
+ public void cascadingReadsOverlappingBoundsTest() {
+ GATKSAMRecord read01 = buildSAMRecord("read1","chr1", 1, 5);
+ GATKSAMRecord read02 = buildSAMRecord("read2","chr1", 2, 6);
+ GATKSAMRecord read03 = buildSAMRecord("read3","chr1", 3, 7);
+ GATKSAMRecord read04 = buildSAMRecord("read4","chr1", 4, 8);
+ GATKSAMRecord read05 = buildSAMRecord("read5","chr1", 5, 9);
+ GATKSAMRecord read06 = buildSAMRecord("read6","chr1", 6, 10);
+ GATKSAMRecord read07 = buildSAMRecord("read7","chr1", 7, 11);
+ GATKSAMRecord read08 = buildSAMRecord("read8","chr1", 8, 12);
+ GATKSAMRecord read09 = buildSAMRecord("read9","chr1", 9, 13);
+ GATKSAMRecord read10 = buildSAMRecord("read10","chr1", 10, 14);
+ GATKSAMRecord read11 = buildSAMRecord("read11","chr1", 11, 15);
+ GATKSAMRecord read12 = buildSAMRecord("read12","chr1", 12, 16);
+ SAMRecordIterator iterator = new SAMRecordIterator(read01, read02, read03, read04, read05, read06,
+ read07, read08, read09, read10, read11, read12);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chr1", 6, 15)));
+ WindowMaker windowMaker = new WindowMaker(shard,genomeLocParser,iterator,shard.getGenomeLocs());
+ WindowMaker.WindowMakerIterator window = windowMaker.next();
+ LocusShardDataProvider dataProvider = new LocusShardDataProvider(shard, window.getSourceInfo(), genomeLocParser, window.getLocus(), window, null, null);
+ LocusView view = createView(dataProvider);
+
+ List<GATKSAMRecord> expectedReads = new ArrayList<GATKSAMRecord>();
+ Collections.addAll(expectedReads, read01, read02, read03, read04, read05, read06,
+ read07, read08, read09, read10, read11, read12);
+ testReadsInContext(view, shard.getGenomeLocs(), expectedReads);
+ }
+
+ /**
+ * Creates a view of the type required for testing.
+ *
+ * @return The correct view to test.
+ */
+ protected abstract LocusView createView(LocusShardDataProvider provider);
+
+ /**
+ * Test the reads according to an independently derived context.
+ *
+ * @param view
+ * @param bounds
+ * @param reads
+ */
+ protected abstract void testReadsInContext(LocusView view, List<GenomeLoc> bounds, List<GATKSAMRecord> reads);
+
+ /**
+ * Fake a reference sequence file. Essentially, seek a header with a bunch of dummy data.
+ *
+ * @return A 'fake' reference sequence file
+ */
+ private static ReferenceSequenceFile fakeReferenceSequenceFile() {
+ return new ReferenceSequenceFile() {
+ public SAMSequenceDictionary getSequenceDictionary() {
+ SAMSequenceRecord sequenceRecord = new SAMSequenceRecord("chr1", 1000000);
+ SAMSequenceDictionary dictionary = new SAMSequenceDictionary(Collections.singletonList(sequenceRecord));
+ return dictionary;
+ }
+
+ public boolean isIndexed() { return false; }
+
+ public ReferenceSequence nextSequence() {
+ throw new UnsupportedOperationException("Fake implementation doesn't support a getter");
+ }
+
+ public ReferenceSequence getSequence( String contig ) {
+ throw new UnsupportedOperationException("Fake implementation doesn't support a getter");
+ }
+
+ public ReferenceSequence getSubsequenceAt( String contig, long start, long stop ) {
+ throw new UnsupportedOperationException("Fake implementation doesn't support a getter");
+ }
+
+ public void reset() {
+ return;
+ }
+
+ public void close() throws IOException {
+ }
+ };
+ }
+
+ /**
+ * Build a SAM record featuring the absolute minimum required dataset.
+ *
+ * @param contig Contig to populate.
+ * @param alignmentStart start of alignment
+ * @param alignmentEnd end of alignment
+ *
+ * @return New SAM Record
+ */
+ protected GATKSAMRecord buildSAMRecord(String readName, String contig, int alignmentStart, int alignmentEnd) {
+ SAMFileHeader header = new SAMFileHeader();
+ header.setSequenceDictionary(sequenceSourceFile.getSequenceDictionary());
+
+ GATKSAMRecord record = new GATKSAMRecord(header);
+
+ record.setReadName(readName);
+ record.setReferenceIndex(sequenceSourceFile.getSequenceDictionary().getSequenceIndex(contig));
+ record.setAlignmentStart(alignmentStart);
+ Cigar cigar = new Cigar();
+ int len = alignmentEnd - alignmentStart + 1;
+ cigar.add(new CigarElement(len, CigarOperator.M));
+ record.setCigar(cigar);
+ record.setReadBases(new byte[len]);
+ record.setBaseQualities(new byte[len]);
+ return record;
+ }
+
+ /** A simple iterator which iterates over a list of reads. */
+ protected class SAMRecordIterator implements GATKSAMIterator {
+ private Iterator<SAMRecord> backingIterator = null;
+
+ public SAMRecordIterator(SAMRecord... reads) {
+ List<SAMRecord> backingList = new ArrayList<SAMRecord>();
+ backingList.addAll(Arrays.asList(reads));
+ backingIterator = backingList.iterator();
+ }
+
+ public boolean hasNext() {
+ return backingIterator.hasNext();
+ }
+
+ public SAMRecord next() {
+ return backingIterator.next();
+ }
+
+ public Iterator<SAMRecord> iterator() {
+ return this;
+ }
+
+ public void close() {
+ // NO-OP.
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Can't remove from a read-only iterator");
+ }
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ReadReferenceViewUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ReadReferenceViewUnitTest.java
new file mode 100644
index 0000000..8bf4f41
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ReadReferenceViewUnitTest.java
@@ -0,0 +1,160 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+
+import org.testng.annotations.Test;
+
+import htsjdk.samtools.*;
+import htsjdk.samtools.reference.ReferenceSequence;
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * User: hanna
+ * Date: May 27, 2009
+ * Time: 1:04:27 PM
+ *
+ */
+
+/**
+ * Test reading the reference for a given read.
+ */
+
+public class ReadReferenceViewUnitTest extends ReferenceViewTemplate {
+
+
+ /**
+ * tests that the ReadReferenceView correctly generates X's when a read overhangs the
+ * end of a contig
+ */
+ @Test
+ public void testOverhangingRead() {
+ testOverhangingGivenSize(25,0);
+ testOverhangingGivenSize(25,12);
+ testOverhangingGivenSize(25,24);
+ }
+
+
+ /**
+ * a private method, that tests getting the read sequence for reads that overlap the end of the
+ * contig
+ * @param readLength the length of the read
+ * @param overlap the amount of overlap
+ */
+ private void testOverhangingGivenSize(int readLength, int overlap) {
+ SAMSequenceRecord selectedContig = sequenceFile.getSequenceDictionary().getSequences().get(sequenceFile.getSequenceDictionary().getSequences().size()-1);
+ final long contigStart = selectedContig.getSequenceLength() - (readLength - overlap - 1);
+ final long contigStop = selectedContig.getSequenceLength() + overlap;
+
+ ReadShardDataProvider dataProvider = new ReadShardDataProvider(null,genomeLocParser,null,sequenceFile,null);
+ ReadReferenceView view = new ReadReferenceView(dataProvider);
+
+ SAMRecord rec = buildSAMRecord(selectedContig.getSequenceName(),(int)contigStart,(int)contigStop);
+ ReferenceSequence expectedAsSeq = sequenceFile.getSubsequenceAt(selectedContig.getSequenceName(),(int)contigStart,selectedContig.getSequenceLength());
+ //char[] expected = StringUtil.bytesToString(expectedAsSeq.getBases()).toCharArray();
+ byte[] expected = expectedAsSeq.getBases();
+ byte[] actual = view.getReferenceBases(rec);
+
+ Assert.assertEquals((readLength - overlap), expected.length);
+ Assert.assertEquals(readLength, actual.length);
+ int xRange = 0;
+ for (; xRange < (readLength - overlap); xRange++) {
+ Assert.assertTrue(actual[xRange] != 'X');
+ }
+ for (; xRange < actual.length; xRange++) {
+ Assert.assertTrue(actual[xRange] == 'X');
+ }
+ }
+
+
+ /**
+ * Compares the contents of the fasta and view at a specified location.
+ * @param loc the location to validate
+ */
+ protected void validateLocation( GenomeLoc loc ) {
+ SAMRecord read = buildSAMRecord( loc.getContig(), (int)loc.getStart(), (int)loc.getStop() );
+
+ ReadShardDataProvider dataProvider = new ReadShardDataProvider(null,genomeLocParser,null,sequenceFile,null);
+ ReadReferenceView view = new ReadReferenceView(dataProvider);
+
+ ReferenceSequence expectedAsSeq = sequenceFile.getSubsequenceAt(loc.getContig(),loc.getStart(),loc.getStop());
+ byte[] expected = expectedAsSeq.getBases();
+ byte[] actual = view.getReferenceBases(read);
+
+ org.testng.Assert.assertEquals(actual,expected,String.format("Base array at in shard %s does not match expected",loc.toString()));
+ }
+
+
+ /**
+ * Build a SAM record featuring the absolute minimum required dataset.
+ * TODO: Blatantly copied from LocusViewTemplate. Refactor these into a set of tools.
+ * @param contig Contig to populate.
+ * @param alignmentStart start of alignment
+ * @param alignmentEnd end of alignment
+ * @return New SAM Record
+ */
+ protected SAMRecord buildSAMRecord( String contig, int alignmentStart, int alignmentEnd ) {
+ SAMFileHeader header = new SAMFileHeader();
+ header.setSequenceDictionary(sequenceFile.getSequenceDictionary());
+
+ SAMRecord record = new SAMRecord(header);
+
+ record.setReferenceIndex(sequenceFile.getSequenceDictionary().getSequenceIndex(contig));
+ record.setAlignmentStart(alignmentStart);
+ Cigar cigar = new Cigar();
+ cigar.add(new CigarElement(alignmentEnd-alignmentStart+1, CigarOperator.M));
+ record.setCigar(cigar);
+ return record;
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceOrderedViewUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceOrderedViewUnitTest.java
new file mode 100644
index 0000000..fdec858
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceOrderedViewUnitTest.java
@@ -0,0 +1,157 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.datasources.reads.MockLocusShard;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrackBuilder;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.datasources.reads.Shard;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.utils.codecs.table.TableFeature;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet.RMDStorageType;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.Collections;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+/**
+ * User: hanna
+ * Date: May 27, 2009
+ * Time: 3:07:23 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Test the transparent view into the reference-ordered data. At the moment, just do some basic bindings and make
+ * sure the data comes through correctly.
+ */
+public class ReferenceOrderedViewUnitTest extends BaseTest {
+ /**
+ * Sequence file.
+ */
+ private static IndexedFastaSequenceFile seq;
+ private GenomeLocParser genomeLocParser;
+
+ /**
+ * our track builder
+ */
+ RMDTrackBuilder builder = null;
+
+ @BeforeClass
+ public void init() throws FileNotFoundException {
+ // sequence
+ seq = new CachingIndexedFastaSequenceFile(new File(hg18Reference));
+ genomeLocParser = new GenomeLocParser(seq);
+ // disable auto-index creation/locking in the RMDTrackBuilder for tests
+ builder = new RMDTrackBuilder(seq.getSequenceDictionary(),genomeLocParser,null,true,null);
+ }
+
+ /**
+ * Make sure binding to an empty list produces an empty tracker.
+ */
+ @Test
+ public void testNoBindings() {
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chrM",1,30)));
+ LocusShardDataProvider provider = new LocusShardDataProvider(shard, null, genomeLocParser, shard.getGenomeLocs().get(0), null, seq, Collections.<ReferenceOrderedDataSource>emptyList());
+ ReferenceOrderedView view = new ManagingReferenceOrderedView( provider );
+
+ RefMetaDataTracker tracker = view.getReferenceOrderedDataAtLocus(genomeLocParser.createGenomeLoc("chrM",10));
+ Assert.assertEquals(tracker.getValues(Feature.class).size(), 0, "The tracker should not have produced any data");
+ }
+
+ /**
+ * Test a single ROD binding.
+ */
+ @Test
+ public void testSingleBinding() {
+ String fileName = privateTestDir + "TabularDataTest.dat";
+ RMDTriplet triplet = new RMDTriplet("tableTest","Table",fileName,RMDStorageType.FILE,new Tags());
+ ReferenceOrderedDataSource dataSource = new ReferenceOrderedDataSource(triplet,builder,seq.getSequenceDictionary(),genomeLocParser,false);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chrM",1,30)));
+
+ LocusShardDataProvider provider = new LocusShardDataProvider(shard, null, genomeLocParser, shard.getGenomeLocs().get(0), null, seq, Collections.singletonList(dataSource));
+ ReferenceOrderedView view = new ManagingReferenceOrderedView( provider );
+
+ RefMetaDataTracker tracker = view.getReferenceOrderedDataAtLocus(genomeLocParser.createGenomeLoc("chrM",20));
+ TableFeature datum = tracker.getFirstValue(new RodBinding<TableFeature>(TableFeature.class, "tableTest"));
+
+ Assert.assertEquals(datum.get("COL1"),"C","datum parameter for COL1 is incorrect");
+ Assert.assertEquals(datum.get("COL2"),"D","datum parameter for COL2 is incorrect");
+ Assert.assertEquals(datum.get("COL3"),"E","datum parameter for COL3 is incorrect");
+ }
+
+ /**
+ * Make sure multiple bindings are visible from the view.
+ */
+ @Test
+ public void testMultipleBinding() {
+ File file = new File(privateTestDir + "TabularDataTest.dat");
+
+ RMDTriplet testTriplet1 = new RMDTriplet("tableTest1","Table",file.getAbsolutePath(),RMDStorageType.FILE,new Tags());
+ ReferenceOrderedDataSource dataSource1 = new ReferenceOrderedDataSource(testTriplet1,builder,seq.getSequenceDictionary(),genomeLocParser,false);
+
+ RMDTriplet testTriplet2 = new RMDTriplet("tableTest2","Table",file.getAbsolutePath(),RMDStorageType.FILE,new Tags());
+ ReferenceOrderedDataSource dataSource2 = new ReferenceOrderedDataSource(testTriplet2,builder,seq.getSequenceDictionary(),genomeLocParser,false);
+
+ Shard shard = new MockLocusShard(genomeLocParser,Collections.singletonList(genomeLocParser.createGenomeLoc("chrM",1,30)));
+
+ LocusShardDataProvider provider = new LocusShardDataProvider(shard, null, genomeLocParser, shard.getGenomeLocs().get(0), null, seq, Arrays.asList(dataSource1,dataSource2));
+ ReferenceOrderedView view = new ManagingReferenceOrderedView( provider );
+
+ RefMetaDataTracker tracker = view.getReferenceOrderedDataAtLocus(genomeLocParser.createGenomeLoc("chrM",20));
+ TableFeature datum1 = tracker.getFirstValue(new RodBinding<TableFeature>(TableFeature.class, "tableTest1"));
+
+ Assert.assertEquals(datum1.get("COL1"),"C","datum1 parameter for COL1 is incorrect");
+ Assert.assertEquals(datum1.get("COL2"),"D","datum1 parameter for COL2 is incorrect");
+ Assert.assertEquals(datum1.get("COL3"),"E","datum1 parameter for COL3 is incorrect");
+
+ TableFeature datum2 = tracker.getFirstValue(new RodBinding<TableFeature>(TableFeature.class, "tableTest2"));
+
+ Assert.assertEquals(datum2.get("COL1"),"C","datum2 parameter for COL1 is incorrect");
+ Assert.assertEquals(datum2.get("COL2"),"D","datum2 parameter for COL2 is incorrect");
+ Assert.assertEquals(datum2.get("COL3"),"E","datum2 parameter for COL3 is incorrect");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceViewTemplate.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceViewTemplate.java
new file mode 100644
index 0000000..bffd23d
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ReferenceViewTemplate.java
@@ -0,0 +1,122 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import htsjdk.samtools.SAMSequenceRecord;
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+/**
+ * User: hanna
+ * Date: May 27, 2009
+ * Time: 1:12:35 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Template for testing reference views (ReadReferenceView and LocusReferenceView).
+ */
+
+public abstract class ReferenceViewTemplate extends BaseTest {
+ /**
+ * The fasta, for comparison.
+ */
+ protected IndexedFastaSequenceFile sequenceFile = null;
+ protected GenomeLocParser genomeLocParser = null;
+
+ //
+ // The bulk of sequence retrieval is tested by IndexedFastaSequenceFile, but we'll run a few spot
+ // checks here to make sure that data is flowing through the LocusReferenceView.
+
+ /**
+ * Initialize the fasta.
+ */
+ @BeforeClass
+ public void initialize() throws FileNotFoundException {
+ sequenceFile = new CachingIndexedFastaSequenceFile( new File(hg18Reference) );
+ genomeLocParser = new GenomeLocParser(sequenceFile);
+ }
+
+ /**
+ * Test the initial fasta location.
+ */
+ @Test
+ public void testReferenceStart() {
+ validateLocation( genomeLocParser.createGenomeLoc(sequenceFile.getSequenceDictionary().getSequence(0).getSequenceName(),1,25) );
+ }
+
+ /**
+ * Test the end of a contig.
+ */
+ @Test
+ public void testReferenceEnd() {
+ // Test the last 25 bases of the first contig.
+ SAMSequenceRecord selectedContig = sequenceFile.getSequenceDictionary().getSequences().get(sequenceFile.getSequenceDictionary().getSequences().size()-1);
+ final int contigStart = selectedContig.getSequenceLength() - 24;
+ final int contigStop = selectedContig.getSequenceLength();
+ validateLocation( genomeLocParser.createGenomeLoc(selectedContig.getSequenceName(),contigStart,contigStop) );
+ }
+
+ /**
+ * Test the start of the middle contig.
+ */
+ @Test
+ public void testContigStart() {
+ // Test the last 25 bases of the first contig.
+ int contigPosition = sequenceFile.getSequenceDictionary().getSequences().size()/2;
+ SAMSequenceRecord selectedContig = sequenceFile.getSequenceDictionary().getSequences().get(contigPosition);
+ validateLocation( genomeLocParser.createGenomeLoc(selectedContig.getSequenceName(),1,25) );
+ }
+
+
+ /**
+ * Test the end of the middle contig.
+ */
+ @Test
+ public void testContigEnd() {
+ // Test the last 25 bases of the first contig.
+ int contigPosition = sequenceFile.getSequenceDictionary().getSequences().size()/2;
+ SAMSequenceRecord selectedContig = sequenceFile.getSequenceDictionary().getSequences().get(contigPosition);
+ final int contigStart = selectedContig.getSequenceLength() - 24;
+ final int contigStop = selectedContig.getSequenceLength();
+ validateLocation( genomeLocParser.createGenomeLoc(selectedContig.getSequenceName(),contigStart,contigStop) );
+ }
+
+ protected abstract void validateLocation( GenomeLoc loc );
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ShardDataProviderUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ShardDataProviderUnitTest.java
new file mode 100644
index 0000000..251eec4
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/providers/ShardDataProviderUnitTest.java
@@ -0,0 +1,152 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.providers;
+
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.testng.annotations.BeforeMethod;
+
+
+import org.testng.annotations.Test;
+import org.broadinstitute.gatk.utils.BaseTest;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Arrays;
+/**
+ * User: hanna
+ * Date: May 27, 2009
+ * Time: 1:56:02 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Test basic functionality of the shard data provider.
+ */
+
+public class ShardDataProviderUnitTest extends BaseTest {
+ /**
+ * Provider to test. Should be recreated for every test.
+ */
+ private ShardDataProvider provider = null;
+
+ @BeforeMethod
+ public void createProvider() {
+ provider = new LocusShardDataProvider( null,null,null,null,null,null,null );
+ }
+
+ /**
+ * Test whether views are closed when the provider closes.
+ */
+ @Test
+ public void testClose() {
+ TestView testView = new TestView( provider );
+ Assert.assertFalse(testView.closed,"View is currently closed but should be open");
+
+ provider.close();
+ Assert.assertTrue(testView.closed,"View is currently open but should be closed");
+ }
+
+ /**
+ * Test whether multiple of the same view can be registered and all get a close method.
+ */
+ @Test
+ public void testMultipleClose() {
+ Collection<TestView> testViews = Arrays.asList(new TestView(provider),new TestView(provider));
+ for( TestView testView: testViews )
+ Assert.assertFalse(testView.closed,"View is currently closed but should be open");
+
+ provider.close();
+ for( TestView testView: testViews )
+ Assert.assertTrue(testView.closed,"View is currently open but should be closed");
+ }
+
+ /**
+ * Try adding a view which conflicts with some other view that's already been registered.
+ */
+ @Test(expectedExceptions= ReviewedGATKException.class)
+ public void testAddViewWithExistingConflict() {
+ View initial = new ConflictingTestView( provider );
+ View conflictsWithInitial = new TestView( provider );
+ }
+
+ /**
+ * Try adding a view which has a conflict with a previously registered view.
+ */
+ @Test(expectedExceptions= ReviewedGATKException.class)
+ public void testAddViewWithNewConflict() {
+ View conflictsWithInitial = new TestView( provider );
+ View initial = new ConflictingTestView( provider );
+ }
+
+ /**
+ * A simple view for testing interactions between views attached to the ShardDataProvider.
+ */
+ private class TestView implements View {
+ /**
+ * Is the test view currently closed.
+ */
+ private boolean closed = false;
+
+ /**
+ * Create a new test view wrapping the given provider.
+ * @param provider
+ */
+ public TestView( ShardDataProvider provider ) {
+ provider.register(this);
+ }
+
+ /**
+ * Gets conflicting views. In this case, none conflict.
+ * @return
+ */
+ public Collection<Class<? extends View>> getConflictingViews() { return Collections.emptyList(); }
+
+ /**
+ * Close this view.
+ */
+ public void close() { this.closed = true; }
+ }
+
+ /**
+ * Another view that conflicts with the one above.
+ */
+ private class ConflictingTestView implements View {
+ public ConflictingTestView( ShardDataProvider provider ) { provider.register(this); }
+
+ public Collection<Class<? extends View>> getConflictingViews() {
+ return Collections.<Class<? extends View>>singleton(TestView.class);
+ }
+
+ public void close() {}
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/ActiveRegionShardBalancerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/ActiveRegionShardBalancerUnitTest.java
new file mode 100644
index 0000000..f1ee6ab
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/ActiveRegionShardBalancerUnitTest.java
@@ -0,0 +1,102 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMFileSpan;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.io.FileNotFoundException;
+import java.util.*;
+
+public class ActiveRegionShardBalancerUnitTest extends BaseTest {
+ // example genome loc parser for this test, can be deleted if you don't use the reference
+ private GenomeLocParser genomeLocParser;
+ protected SAMDataSource readsDataSource;
+
+ @BeforeClass
+ public void setup() throws FileNotFoundException {
+ // sequence
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(10, 0, 10000);
+ genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ readsDataSource = null;
+ }
+
+ @Test
+ public void testMergingManyContigs() {
+ executeTest(genomeLocParser.getContigs().getSequences());
+ }
+
+ @Test
+ public void testMergingAllPointersOnSingleContig() {
+ executeTest(Arrays.asList(genomeLocParser.getContigs().getSequences().get(1)));
+ }
+
+ @Test
+ public void testMergingMultipleDiscontinuousContigs() {
+ final List<SAMSequenceRecord> all = genomeLocParser.getContigs().getSequences();
+ executeTest(Arrays.asList(all.get(1), all.get(3)));
+ }
+
+ private void executeTest(final Collection<SAMSequenceRecord> records) {
+ final ActiveRegionShardBalancer balancer = new ActiveRegionShardBalancer();
+
+ final List<Set<GenomeLoc>> expectedLocs = new LinkedList<>();
+ final List<FilePointer> pointers = new LinkedList<>();
+
+ for ( final SAMSequenceRecord record : records ) {
+ final int size = 10;
+ int end = 0;
+ for ( int i = 0; i < record.getSequenceLength(); i += size) {
+ final int myEnd = i + size - 1;
+ end = myEnd;
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(record.getSequenceName(), i, myEnd);
+ final Map<SAMReaderID, SAMFileSpan> fileSpans = Collections.emptyMap();
+ final FilePointer fp = new FilePointer(fileSpans, IntervalMergingRule.ALL, Collections.singletonList(loc));
+ pointers.add(fp);
+ }
+ expectedLocs.add(Collections.singleton(genomeLocParser.createGenomeLoc(record.getSequenceName(), 0, end)));
+ }
+
+ balancer.initialize(readsDataSource, pointers.iterator(), genomeLocParser);
+
+ int i = 0;
+ int nShardsFound = 0;
+ for ( final Shard shard : balancer ) {
+ nShardsFound++;
+ Assert.assertEquals(new HashSet<>(shard.getGenomeLocs()), expectedLocs.get(i++));
+ }
+ Assert.assertEquals(nShardsFound, records.size(), "Didn't find exactly one shard for each contig in the sequence dictionary");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/DownsamplerBenchmark.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/DownsamplerBenchmark.java
new file mode 100644
index 0000000..27c287c
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/DownsamplerBenchmark.java
@@ -0,0 +1,94 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import com.google.caliper.Param;
+import org.broadinstitute.gatk.engine.WalkerManager;
+import org.broadinstitute.gatk.engine.downsampling.DownsamplingMethod;
+import org.broadinstitute.gatk.engine.walkers.LocusWalker;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mhanna
+ * Date: Apr 22, 2011
+ * Time: 4:02:56 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class DownsamplerBenchmark extends ReadProcessingBenchmark {
+ @Param
+ private String bamFile;
+
+ @Param
+ private Integer maxReads;
+
+ @Override
+ public String getBAMFile() { return bamFile; }
+
+ @Override
+ public Integer getMaxReads() { return maxReads; }
+
+ @Param
+ private Downsampling downsampling;
+
+// public void timeDownsampling(int reps) {
+// for(int i = 0; i < reps; i++) {
+// SAMFileReader reader = new SAMFileReader(inputFile);
+// ReadProperties readProperties = new ReadProperties(Collections.<SAMReaderID>singletonList(new SAMReaderID(inputFile,new Tags())),
+// reader.getFileHeader(),
+// SAMFileHeader.SortOrder.coordinate,
+// false,
+// SAMFileReader.ValidationStringency.SILENT,
+// downsampling.create(),
+// new ValidationExclusion(Collections.singletonList(ValidationExclusion.TYPE.ALL)),
+// Collections.<ReadFilter>emptyList(),
+// Collections.<ReadTransformer>emptyList(),
+// false,
+// (byte)0,
+// false);
+//
+// GenomeLocParser genomeLocParser = new GenomeLocParser(reader.getFileHeader().getSequenceDictionary());
+// // Filter unmapped reads. TODO: is this always strictly necessary? Who in the GATK normally filters these out?
+// Iterator<SAMRecord> readIterator = new FilteringIterator(reader.iterator(),new UnmappedReadFilter());
+// LegacyLocusIteratorByState locusIteratorByState = new LegacyLocusIteratorByState(readIterator,readProperties,genomeLocParser, LegacyLocusIteratorByState.sampleListForSAMWithoutReadGroups());
+// while(locusIteratorByState.hasNext()) {
+// locusIteratorByState.next().getLocation();
+// }
+// reader.close();
+// }
+// }
+
+ private enum Downsampling {
+ NONE {
+ @Override
+ DownsamplingMethod create() { return DownsamplingMethod.NONE; }
+ },
+ PER_SAMPLE {
+ @Override
+ DownsamplingMethod create() { return WalkerManager.getDownsamplingMethod(LocusWalker.class); }
+ };
+ abstract DownsamplingMethod create();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/FilePointerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/FilePointerUnitTest.java
new file mode 100644
index 0000000..e35f1d5
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/FilePointerUnitTest.java
@@ -0,0 +1,129 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.GATKBAMFileSpan;
+import htsjdk.samtools.GATKChunk;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ *
+ */
+public class FilePointerUnitTest extends BaseTest {
+ private IndexedFastaSequenceFile seq;
+ private GenomeLocParser genomeLocParser;
+ private SAMReaderID readerID = new SAMReaderID("samFile",new Tags());
+
+ /**
+ * This function does the setup of our parser, before each method call.
+ * <p/>
+ * Called before every test case method.
+ */
+ @BeforeMethod
+ public void doForEachTest() throws FileNotFoundException {
+ // sequence
+ seq = new CachingIndexedFastaSequenceFile(new File(hg18Reference));
+ genomeLocParser = new GenomeLocParser(seq.getSequenceDictionary());
+ }
+
+ @Test
+ public void testFilePointerCombineDisjoint() {
+ FilePointer one = new FilePointer(IntervalMergingRule.ALL, genomeLocParser.createGenomeLoc("chr1",1,5));
+ one.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(0,1)));
+ FilePointer two = new FilePointer(IntervalMergingRule.ALL, genomeLocParser.createGenomeLoc("chr1",6,10));
+ two.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(1,2)));
+
+ FilePointer result = new FilePointer(IntervalMergingRule.ALL, genomeLocParser.createGenomeLoc("chr1",1,10));
+ result.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(0,2)));
+
+ Assert.assertEquals(one.combine(genomeLocParser,two),result,"Combination of two file pointers is incorrect");
+ Assert.assertEquals(two.combine(genomeLocParser,one),result,"Combination of two file pointers is incorrect");
+
+ //Now test that adjacent (but disjoint) intervals are properly handled with OVERLAPPING_ONLY
+ one = new FilePointer(IntervalMergingRule.OVERLAPPING_ONLY, genomeLocParser.createGenomeLoc("chr1",1,5));
+ one.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(0,1)));
+ two = new FilePointer(IntervalMergingRule.OVERLAPPING_ONLY, genomeLocParser.createGenomeLoc("chr1",6,10));
+ two.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(1,2)));
+
+ result = new FilePointer(IntervalMergingRule.OVERLAPPING_ONLY,
+ genomeLocParser.createGenomeLoc("chr1",1,5),
+ genomeLocParser.createGenomeLoc("chr1",6,10));
+ result.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(0,2)));
+
+ Assert.assertEquals(one.combine(genomeLocParser,two),result,"Combination of two file pointers is incorrect");
+ Assert.assertEquals(two.combine(genomeLocParser,one),result,"Combination of two file pointers is incorrect");
+ }
+
+ @Test
+ public void testFilePointerCombineJoint() {
+ FilePointer one = new FilePointer(IntervalMergingRule.ALL, genomeLocParser.createGenomeLoc("chr1",1,5));
+ one.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(0,2)));
+ FilePointer two = new FilePointer(IntervalMergingRule.ALL, genomeLocParser.createGenomeLoc("chr1",2,6));
+ two.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(1,3)));
+
+ FilePointer result = new FilePointer(IntervalMergingRule.ALL, genomeLocParser.createGenomeLoc("chr1",1,6));
+ result.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(0,3)));
+
+ Assert.assertEquals(one.combine(genomeLocParser,two),result,"Combination of two file pointers is incorrect");
+ Assert.assertEquals(two.combine(genomeLocParser,one),result,"Combination of two file pointers is incorrect");
+
+ //Repeat the tests for OVERLAPPING_ONLY
+ one = new FilePointer(IntervalMergingRule.OVERLAPPING_ONLY, genomeLocParser.createGenomeLoc("chr1",1,5));
+ one.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(0,2)));
+ two = new FilePointer(IntervalMergingRule.OVERLAPPING_ONLY, genomeLocParser.createGenomeLoc("chr1",2,6));
+ two.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(1,3)));
+
+ result = new FilePointer(IntervalMergingRule.OVERLAPPING_ONLY, genomeLocParser.createGenomeLoc("chr1",1,6));
+ result.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(0,3)));
+
+ Assert.assertEquals(one.combine(genomeLocParser,two),result,"Combination of two file pointers is incorrect");
+ Assert.assertEquals(two.combine(genomeLocParser,one),result,"Combination of two file pointers is incorrect");
+ }
+
+ @Test
+ public void testFilePointerCombineOneSided() {
+ FilePointer filePointer = new FilePointer(IntervalMergingRule.ALL, genomeLocParser.createGenomeLoc("chr1",1,5));
+ filePointer.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(0,1)));
+ FilePointer empty = new FilePointer(IntervalMergingRule.ALL, genomeLocParser.createGenomeLoc("chr1",6,10));
+ // Do not add file spans to empty result
+
+ FilePointer result = new FilePointer(IntervalMergingRule.ALL, genomeLocParser.createGenomeLoc("chr1",1,10));
+ result.addFileSpans(readerID,new GATKBAMFileSpan(new GATKChunk(0,1)));
+ Assert.assertEquals(filePointer.combine(genomeLocParser,empty),result,"Combination of two file pointers is incorrect");
+ Assert.assertEquals(empty.combine(genomeLocParser,filePointer),result,"Combination of two file pointers is incorrect");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/GATKBAMIndexUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/GATKBAMIndexUnitTest.java
new file mode 100644
index 0000000..289a10c
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/GATKBAMIndexUnitTest.java
@@ -0,0 +1,108 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMSequenceDictionary;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * Test basic functionality in the GATK's implementation of the BAM index classes.
+ */
+public class GATKBAMIndexUnitTest extends BaseTest {
+ private static File bamFile = new File(validationDataLocation+"MV1994.selected.bam");
+
+ /**
+ * Index file forming the source of all unit tests.
+ */
+ private static File bamIndexFile = new File(validationDataLocation+"MV1994.selected.bam.bai");
+
+ /**
+ * Storage for the index itself.
+ */
+ private GATKBAMIndex bamIndex;
+
+
+ @BeforeClass
+ public void init() throws FileNotFoundException {
+ SAMFileReader reader = new SAMFileReader(bamFile);
+ SAMSequenceDictionary sequenceDictionary = reader.getFileHeader().getSequenceDictionary();
+ reader.close();
+
+ bamIndex = new GATKBAMIndex(bamIndexFile);
+ }
+
+ @Test
+ public void testNumberAndSizeOfIndexLevels() {
+ // The correct values for this test are pulled directly from the
+ // SAM Format Specification v1.3-r882, Section 4.1.1, last paragraph.
+ Assert.assertEquals(GATKBAMIndex.getNumIndexLevels(),6,"Incorrect number of levels in BAM index");
+
+ // Level 0
+ Assert.assertEquals(GATKBAMIndex.getFirstBinInLevel(0),0);
+ Assert.assertEquals(bamIndex.getLevelSize(0),1);
+
+ // Level 1
+ Assert.assertEquals(GATKBAMIndex.getFirstBinInLevel(1),1);
+ Assert.assertEquals(bamIndex.getLevelSize(1),8-1+1);
+
+ // Level 2
+ Assert.assertEquals(GATKBAMIndex.getFirstBinInLevel(2),9);
+ Assert.assertEquals(bamIndex.getLevelSize(2),72-9+1);
+
+ // Level 3
+ Assert.assertEquals(GATKBAMIndex.getFirstBinInLevel(3),73);
+ Assert.assertEquals(bamIndex.getLevelSize(3),584-73+1);
+
+ // Level 4
+ Assert.assertEquals(GATKBAMIndex.getFirstBinInLevel(4),585);
+ Assert.assertEquals(bamIndex.getLevelSize(4),4680-585+1);
+
+ // Level 5
+ Assert.assertEquals(GATKBAMIndex.getFirstBinInLevel(5),4681);
+ Assert.assertEquals(bamIndex.getLevelSize(5),37448-4681+1);
+ }
+
+ @Test( expectedExceptions = UserException.MalformedFile.class )
+ public void testDetectTruncatedBamIndexWordBoundary() {
+ GATKBAMIndex index = new GATKBAMIndex(new File(privateTestDir + "truncated_at_word_boundary.bai"));
+ index.readReferenceSequence(0);
+ }
+
+ @Test( expectedExceptions = UserException.MalformedFile.class )
+ public void testDetectTruncatedBamIndexNonWordBoundary() {
+ GATKBAMIndex index = new GATKBAMIndex(new File(privateTestDir + "truncated_at_non_word_boundary.bai"));
+ index.readReferenceSequence(0);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/GATKWalkerBenchmark.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/GATKWalkerBenchmark.java
new file mode 100644
index 0000000..30eaeb6
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/GATKWalkerBenchmark.java
@@ -0,0 +1,141 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import com.google.caliper.Param;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.filters.UnmappedReadFilter;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.tools.walkers.qc.CountLoci;
+import org.broadinstitute.gatk.tools.walkers.qc.CountReads;
+import org.broadinstitute.gatk.utils.classloader.JVMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.io.File;
+import java.util.Collections;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mhanna
+ * Date: Feb 25, 2011
+ * Time: 10:16:54 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class GATKWalkerBenchmark extends ReadProcessingBenchmark {
+ @Param
+ private String bamFile;
+
+ @Param
+ private Integer maxReads;
+
+ @Param
+ private String referenceFile;
+
+ @Param
+ private WalkerType walkerType;
+
+ @Override
+ public String getBAMFile() { return bamFile; }
+
+ @Override
+ public Integer getMaxReads() { return maxReads; }
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ }
+
+ public void timeWalkerPerformance(final int reps) {
+ for(int i = 0; i < reps; i++) {
+ GenomeAnalysisEngine engine = new GenomeAnalysisEngine();
+
+ // Establish the argument collection
+ GATKArgumentCollection argCollection = new GATKArgumentCollection();
+ argCollection.referenceFile = new File(referenceFile);
+ argCollection.samFiles = Collections.singletonList(inputFile.getAbsolutePath());
+
+ engine.setArguments(argCollection);
+ // Bugs in the engine mean that this has to be set twice.
+ engine.setSAMFileIDs(Collections.singletonList(new SAMReaderID(inputFile,new Tags())));
+ engine.setFilters(Collections.<ReadFilter>singletonList(new UnmappedReadFilter()));
+ engine.setReferenceMetaDataFiles(Collections.<RMDTriplet>emptyList());
+
+ // Create the walker
+ engine.setWalker(walkerType.create());
+
+ engine.execute();
+ }
+ }
+
+ private enum WalkerType {
+ COUNT_READS {
+ @Override
+ Walker create() { return new CountReads(); }
+ },
+ COUNT_BASES_IN_READ {
+ @Override
+ Walker create() { return new CountBasesInReadPerformanceWalker(); }
+ },
+ COUNT_LOCI {
+ @Override
+ Walker create() {
+ CountLoci walker = new CountLoci();
+ JVMUtils.setFieldValue(JVMUtils.findField(CountLoci.class,"out"),walker,System.out);
+ return walker;
+ }
+ };
+ abstract Walker create();
+ }
+}
+
+class CountBasesInReadPerformanceWalker extends ReadWalker<Integer,Long> {
+ private long As;
+ private long Cs;
+ private long Gs;
+ private long Ts;
+
+ public Integer map(ReferenceContext ref, GATKSAMRecord read, RefMetaDataTracker tracker) {
+ for(byte base: read.getReadBases()) {
+ switch(base) {
+ case 'A': As++; break;
+ case 'C': Cs++; break;
+ case 'G': Gs++; break;
+ case 'T': Ts++; break;
+ }
+ }
+ return 1;
+ }
+
+ public Long reduceInit() { return 0L; }
+ public Long reduce(Integer value, Long accum) { return value + accum; }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/IntervalOverlapFilteringIteratorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/IntervalOverlapFilteringIteratorUnitTest.java
new file mode 100644
index 0000000..90ac754
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/IntervalOverlapFilteringIteratorUnitTest.java
@@ -0,0 +1,150 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class IntervalOverlapFilteringIteratorUnitTest {
+
+ private SAMFileHeader header;
+ private GenomeLoc firstContig;
+ private GenomeLoc secondContig;
+
+ /** Basic aligned and mapped read. */
+ private SAMRecord readMapped;
+
+ /** Read with no contig specified in the read, -L UNMAPPED */
+ private SAMRecord readNoReference;
+
+ /** This read has a start position, but is flagged that it's not mapped. */
+ private SAMRecord readUnmappedFlag;
+
+ /** This read is from the second contig. */
+ private SAMRecord readSecondContig;
+
+ /** This read says it's aligned, but actually has an unknown start. */
+ private SAMRecord readUnknownStart;
+
+ /** The above reads in the order one would expect to find them in a sorted BAM. */
+ private List<SAMRecord> testReads;
+
+ @BeforeClass
+ public void init() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(3, 1, ArtificialSAMUtils.DEFAULT_READ_LENGTH * 2);
+ GenomeLocParser genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ SAMSequenceRecord record;
+
+ record = header.getSequence(0);
+ firstContig = genomeLocParser.createGenomeLoc(record.getSequenceName(), 1, record.getSequenceLength());
+ record = header.getSequence(1);
+ secondContig = genomeLocParser.createGenomeLoc(record.getSequenceName(), 1, record.getSequenceLength());
+
+ readMapped = createMappedRead("mapped", 1);
+
+ readUnmappedFlag = createMappedRead("unmappedFlagged", 2);
+ readUnmappedFlag.setReadUnmappedFlag(true);
+
+ readSecondContig = createMappedRead("secondContig", 3);
+ readSecondContig.setReferenceName(secondContig.getContig());
+
+ /* This read says it's aligned, but to a contig not in the header. */
+ SAMRecord readUnknownContig = createMappedRead("unknownContig", 4);
+ readUnknownContig.setReferenceName("unknownContig");
+
+ readUnknownStart = createMappedRead("unknownStart", 1);
+ readUnknownStart.setAlignmentStart(SAMRecord.NO_ALIGNMENT_START);
+
+ readNoReference = createUnmappedRead("unmappedNoReference");
+
+ testReads = new ArrayList<SAMRecord>();
+ testReads.add(readMapped);
+ testReads.add(readUnmappedFlag);
+ testReads.add(readUnknownStart);
+ testReads.add(readSecondContig);
+ testReads.add(readUnknownContig);
+ testReads.add(readNoReference);
+ }
+
+ @DataProvider(name = "filteringIteratorTestData")
+ public Object[][] getFilteringIteratorTestData() {
+ return new Object[][] {
+ new Object[] {Arrays.asList(firstContig), Arrays.asList(readMapped, readUnmappedFlag, readUnknownStart)},
+ new Object[] {Arrays.asList(GenomeLoc.UNMAPPED), Arrays.asList(readNoReference)},
+ new Object[] {Arrays.asList(firstContig, secondContig), Arrays.asList(readMapped, readUnmappedFlag, readUnknownStart, readSecondContig)}
+ };
+ }
+
+ @Test(dataProvider = "filteringIteratorTestData")
+ public void testFilteringIterator(List<GenomeLoc> locs, List<SAMRecord> expected) {
+ IntervalOverlapFilteringIterator filterIter = new IntervalOverlapFilteringIterator(
+ ArtificialSAMUtils.createReadIterator(testReads), locs);
+
+ List<SAMRecord> actual = new ArrayList<SAMRecord>();
+ while (filterIter.hasNext()) {
+ actual.add(filterIter.next());
+ }
+ Assert.assertEquals(actual, expected);
+ }
+
+ @Test(expectedExceptions = ReviewedGATKException.class)
+ public void testMappedAndUnmapped() {
+ new IntervalOverlapFilteringIterator(
+ ArtificialSAMUtils.createReadIterator(testReads),
+ Arrays.asList(firstContig, GenomeLoc.UNMAPPED));
+ }
+
+ private SAMRecord createUnmappedRead(String name) {
+ return ArtificialSAMUtils.createArtificialRead(
+ header,
+ name,
+ SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX,
+ SAMRecord.NO_ALIGNMENT_START,
+ ArtificialSAMUtils.DEFAULT_READ_LENGTH);
+ }
+
+ private SAMRecord createMappedRead(String name, int start) {
+ return ArtificialSAMUtils.createArtificialRead(
+ header,
+ name,
+ 0,
+ start,
+ ArtificialSAMUtils.DEFAULT_READ_LENGTH);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/MockLocusShard.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/MockLocusShard.java
new file mode 100644
index 0000000..eb3c894
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/MockLocusShard.java
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import org.broadinstitute.gatk.engine.datasources.reads.LocusShard;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMDataSource;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+import java.util.List;
+import java.util.Collections;
+
+/**
+ * A mock locus shard, usable for infrastructure that requires a shard to behave properly.
+ *
+ * @author mhanna
+ * @version 0.1
+ */
+public class MockLocusShard extends LocusShard {
+ public MockLocusShard(final GenomeLocParser genomeLocParser,final List<GenomeLoc> intervals) {
+ super( genomeLocParser,
+ new SAMDataSource(Collections.<SAMReaderID>emptyList(),new ThreadAllocation(),null,genomeLocParser),
+ intervals,
+ null);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/PicardBaselineBenchmark.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/PicardBaselineBenchmark.java
new file mode 100644
index 0000000..f96a35a
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/PicardBaselineBenchmark.java
@@ -0,0 +1,101 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import htsjdk.samtools.util.SamLocusIterator;
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.CloseableIterator;
+
+import java.io.File;
+import java.util.Iterator;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mhanna
+ * Date: Apr 22, 2011
+ * Time: 3:51:06 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class PicardBaselineBenchmark extends ReadProcessingBenchmark {
+ @Param
+ private String bamFile;
+
+ @Param
+ private Integer maxReads;
+
+ @Override
+ public String getBAMFile() { return bamFile; }
+
+ @Override
+ public Integer getMaxReads() { return maxReads; }
+
+ public void timeDecompressBamFile(int reps) {
+ for(int i = 0; i < reps; i++) {
+ SAMFileReader reader = new SAMFileReader(inputFile);
+ CloseableIterator<SAMRecord> iterator = reader.iterator();
+ while(iterator.hasNext())
+ iterator.next();
+ iterator.close();
+ reader.close();
+ }
+ }
+
+ public void timeExtractTag(int reps) {
+ for(int i = 0; i < reps; i++) {
+ SAMFileReader reader = new SAMFileReader(inputFile);
+ CloseableIterator<SAMRecord> iterator = reader.iterator();
+ while(iterator.hasNext()) {
+ SAMRecord read = iterator.next();
+ read.getAttribute("OQ");
+ }
+ iterator.close();
+ reader.close();
+ }
+ }
+
+ public void timeSamLocusIterator(int reps) {
+ for(int i = 0; i < reps; i++) {
+ SAMFileReader reader = new SAMFileReader(inputFile);
+ long loci = 0;
+
+ SamLocusIterator samLocusIterator = new SamLocusIterator(reader);
+ samLocusIterator.setEmitUncoveredLoci(false);
+ Iterator<SamLocusIterator.LocusInfo> workhorseIterator = samLocusIterator.iterator();
+
+ while(workhorseIterator.hasNext()) {
+ SamLocusIterator.LocusInfo locusInfo = workhorseIterator.next();
+ // Use the value of locusInfo to avoid optimization.
+ if(locusInfo != null) loci++;
+ }
+ System.out.printf("Total loci = %d%n",loci);
+
+ reader.close();
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/ReadProcessingBenchmark.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/ReadProcessingBenchmark.java
new file mode 100644
index 0000000..71fc81a
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/ReadProcessingBenchmark.java
@@ -0,0 +1,83 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMFileWriter;
+import htsjdk.samtools.SAMFileWriterFactory;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mhanna
+ * Date: Apr 22, 2011
+ * Time: 4:04:38 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public abstract class ReadProcessingBenchmark extends SimpleBenchmark {
+ protected abstract String getBAMFile();
+ protected abstract Integer getMaxReads();
+
+ protected File inputFile;
+
+ @Override
+ public void setUp() {
+ SAMFileReader fullInputFile = new SAMFileReader(new File(getBAMFile()));
+
+ File tempFile = null;
+ try {
+ tempFile = File.createTempFile("testfile_"+getMaxReads(),".bam");
+ }
+ catch(IOException ex) {
+ throw new ReviewedGATKException("Unable to create temporary BAM",ex);
+ }
+ SAMFileWriterFactory factory = new SAMFileWriterFactory();
+ factory.setCreateIndex(true);
+ SAMFileWriter writer = factory.makeBAMWriter(fullInputFile.getFileHeader(),true,tempFile);
+
+ long numReads = 0;
+ for(SAMRecord read: fullInputFile) {
+ if(numReads++ >= getMaxReads())
+ break;
+ writer.addAlignment(read);
+ }
+
+ writer.close();
+
+ inputFile = tempFile;
+ }
+
+ @Override
+ public void tearDown() {
+ inputFile.delete();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/ReadShardBalancerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/ReadShardBalancerUnitTest.java
new file mode 100644
index 0000000..be48194
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/ReadShardBalancerUnitTest.java
@@ -0,0 +1,195 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+import org.broadinstitute.gatk.engine.downsampling.DownsamplingMethod;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.ArtificialSingleSampleReadStream;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class ReadShardBalancerUnitTest extends BaseTest {
+
+ /**
+ * Tests to ensure that ReadShardBalancer works as expected and does not place shard boundaries
+ * at inappropriate places, such as within an alignment start position
+ */
+ private static class ReadShardBalancerTest extends TestDataProvider {
+ private int numContigs;
+ private int numStacksPerContig;
+ private int stackSize;
+ private int numUnmappedReads;
+ private DownsamplingMethod downsamplingMethod;
+ private int expectedReadCount;
+
+ private SAMFileHeader header;
+ private SAMReaderID testBAM;
+
+ public ReadShardBalancerTest( int numContigs,
+ int numStacksPerContig,
+ int stackSize,
+ int numUnmappedReads,
+ int downsamplingTargetCoverage ) {
+ super(ReadShardBalancerTest.class);
+
+ this.numContigs = numContigs;
+ this.numStacksPerContig = numStacksPerContig;
+ this.stackSize = stackSize;
+ this.numUnmappedReads = numUnmappedReads;
+
+ this.downsamplingMethod = new DownsamplingMethod(DownsampleType.BY_SAMPLE, downsamplingTargetCoverage, null);
+ this.expectedReadCount = Math.min(stackSize, downsamplingTargetCoverage) * numStacksPerContig * numContigs + numUnmappedReads;
+
+ setName(String.format("%s: numContigs=%d numStacksPerContig=%d stackSize=%d numUnmappedReads=%d downsamplingTargetCoverage=%d",
+ getClass().getSimpleName(), numContigs, numStacksPerContig, stackSize, numUnmappedReads, downsamplingTargetCoverage));
+ }
+
+ public void run() {
+ createTestBAM();
+
+ SAMDataSource dataSource = new SAMDataSource(Arrays.asList(testBAM),
+ new ThreadAllocation(),
+ null,
+ new GenomeLocParser(header.getSequenceDictionary()),
+ false,
+ ValidationStringency.SILENT,
+ ReadShard.DEFAULT_MAX_READS, // reset ReadShard.MAX_READS to ReadShard.DEFAULT_MAX_READS for each test
+ downsamplingMethod,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ false);
+
+ Iterable<Shard> shardIterator = dataSource.createShardIteratorOverAllReads(new ReadShardBalancer());
+
+ SAMRecord readAtEndOfLastShard = null;
+ int totalReadsSeen = 0;
+
+ for ( Shard shard : shardIterator ) {
+ int numContigsThisShard = 0;
+ SAMRecord lastRead = null;
+
+ for ( SAMRecord read : shard.iterator() ) {
+ totalReadsSeen++;
+
+ if ( lastRead == null ) {
+ numContigsThisShard = 1;
+ }
+ else if ( ! read.getReadUnmappedFlag() && ! lastRead.getReferenceIndex().equals(read.getReferenceIndex()) ) {
+ numContigsThisShard++;
+ }
+
+ // If the last read from the previous shard is not unmapped, we have to make sure
+ // that no reads in this shard start at the same position
+ if ( readAtEndOfLastShard != null && ! readAtEndOfLastShard.getReadUnmappedFlag() ) {
+ Assert.assertFalse(readAtEndOfLastShard.getReferenceIndex().equals(read.getReferenceIndex()) &&
+ readAtEndOfLastShard.getAlignmentStart() == read.getAlignmentStart(),
+ String.format("Reads from alignment start position %d:%d are split across multiple shards",
+ read.getReferenceIndex(), read.getAlignmentStart()));
+ }
+
+ lastRead = read;
+ }
+
+ // There should never be reads from more than 1 contig in a shard (ignoring unmapped reads)
+ Assert.assertTrue(numContigsThisShard == 1, "found a shard with reads from multiple contigs");
+
+ readAtEndOfLastShard = lastRead;
+ }
+
+ Assert.assertEquals(totalReadsSeen, expectedReadCount, "did not encounter the expected number of reads");
+ }
+
+ private void createTestBAM() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(numContigs, 1, 100000);
+ SAMReadGroupRecord readGroup = new SAMReadGroupRecord("foo");
+ readGroup.setSample("testSample");
+ header.addReadGroup(readGroup);
+ ArtificialSingleSampleReadStream artificialReads = new ArtificialSingleSampleReadStream(header,
+ "foo",
+ numContigs,
+ numStacksPerContig,
+ stackSize,
+ stackSize,
+ 1,
+ 100,
+ 50,
+ 150,
+ numUnmappedReads);
+
+ final File testBAMFile = createTempFile("SAMDataSourceFillShardBoundaryTest", ".bam");
+
+ SAMFileWriter bamWriter = new SAMFileWriterFactory().setCreateIndex(true).makeBAMWriter(header, true, testBAMFile);
+ for ( SAMRecord read : artificialReads ) {
+ bamWriter.addAlignment(read);
+ }
+ bamWriter.close();
+
+ testBAM = new SAMReaderID(testBAMFile, new Tags());
+
+ new File(testBAM.getSamFilePath().replace(".bam", ".bai")).deleteOnExit();
+ new File(testBAM.getSamFilePath() + ".bai").deleteOnExit();
+ }
+ }
+
+ @DataProvider(name = "ReadShardBalancerTestDataProvider")
+ public Object[][] createReadShardBalancerTests() {
+ for ( int numContigs = 1; numContigs <= 3; numContigs++ ) {
+ for ( int numStacksPerContig : Arrays.asList(1, 2, 4) ) {
+ // Use crucial read shard boundary values as the stack sizes
+ for ( int stackSize : Arrays.asList(ReadShard.DEFAULT_MAX_READS / 2, ReadShard.DEFAULT_MAX_READS / 2 + 10, ReadShard.DEFAULT_MAX_READS, ReadShard.DEFAULT_MAX_READS - 1, ReadShard.DEFAULT_MAX_READS + 1, ReadShard.DEFAULT_MAX_READS * 2) ) {
+ for ( int numUnmappedReads : Arrays.asList(0, ReadShard.DEFAULT_MAX_READS / 2, ReadShard.DEFAULT_MAX_READS * 2) ) {
+ // The first value will result in no downsampling at all, the others in some downsampling
+ for ( int downsamplingTargetCoverage : Arrays.asList(ReadShard.DEFAULT_MAX_READS * 10, ReadShard.DEFAULT_MAX_READS, ReadShard.DEFAULT_MAX_READS / 2) ) {
+ new ReadShardBalancerTest(numContigs, numStacksPerContig, stackSize, numUnmappedReads, downsamplingTargetCoverage);
+ }
+ }
+ }
+ }
+ }
+
+ return ReadShardBalancerTest.getTests(ReadShardBalancerTest.class);
+ }
+
+ @Test(dataProvider = "ReadShardBalancerTestDataProvider")
+ public void runReadShardBalancerTest( ReadShardBalancerTest test ) {
+ logger.warn("Running test: " + test);
+
+ test.run();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/SAMDataSourceUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/SAMDataSourceUnitTest.java
new file mode 100644
index 0000000..526b8ce
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/SAMDataSourceUnitTest.java
@@ -0,0 +1,253 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static org.testng.Assert.*;
+
+/**
+ * <p/>
+ * Class SAMDataSourceUnitTest
+ * <p/>
+ * The test of the SAMBAM simple data source.
+ */
+public class SAMDataSourceUnitTest extends BaseTest {
+
+ // TODO: These legacy tests should really be replaced with a more comprehensive suite of tests for SAMDataSource
+
+ private List<SAMReaderID> readers;
+ private IndexedFastaSequenceFile seq;
+ private GenomeLocParser genomeLocParser;
+
+ /**
+ * This function does the setup of our parser, before each method call.
+ * <p/>
+ * Called before every test case method.
+ */
+ @BeforeMethod
+ public void doForEachTest() throws FileNotFoundException {
+ readers = new ArrayList<SAMReaderID>();
+
+ // sequence
+ seq = new CachingIndexedFastaSequenceFile(new File(b36KGReference));
+ genomeLocParser = new GenomeLocParser(seq.getSequenceDictionary());
+ }
+
+ /**
+ * Tears down the test fixture after each call.
+ * <p/>
+ * Called after every test case method.
+ */
+ @AfterMethod
+ public void undoForEachTest() {
+ seq = null;
+ readers.clear();
+ }
+
+
+ /** Test out that we can shard the file and iterate over every read */
+ @Test
+ public void testLinearBreakIterateAll() {
+ logger.warn("Executing testLinearBreakIterateAll");
+
+ // setup the data
+ readers.add(new SAMReaderID(new File(validationDataLocation+"/NA12878.chrom6.SLX.SRP000032.2009_06.selected.bam"),new Tags()));
+
+ // the sharding strat.
+ SAMDataSource data = new SAMDataSource(readers,
+ new ThreadAllocation(),
+ null,
+ genomeLocParser,
+ false,
+ ValidationStringency.SILENT,
+ null,
+ null,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ false);
+
+ Iterable<Shard> strat = data.createShardIteratorOverMappedReads(new LocusShardBalancer());
+ int count = 0;
+
+ try {
+ for (Shard sh : strat) {
+ int readCount = 0;
+ count++;
+
+ GenomeLoc firstLocus = sh.getGenomeLocs().get(0), lastLocus = sh.getGenomeLocs().get(sh.getGenomeLocs().size()-1);
+ logger.debug("Start : " + firstLocus.getStart() + " stop : " + lastLocus.getStop() + " contig " + firstLocus.getContig());
+ logger.debug("count = " + count);
+ GATKSAMIterator datum = data.seek(sh);
+
+ // for the first couple of shards make sure we can see the reads
+ if (count < 5) {
+ for (SAMRecord r : datum) {
+ }
+ readCount++;
+ }
+ datum.close();
+
+ // if we're over 100 shards, break out
+ if (count > 100) {
+ break;
+ }
+ }
+ }
+ catch (UserException.CouldNotReadInputFile e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ fail("testLinearBreakIterateAll: We Should get a UserException.CouldNotReadInputFile exception");
+ }
+ }
+
+ /** Test that we clear program records when requested */
+ @Test
+ public void testRemoveProgramRecords() {
+ logger.warn("Executing testRemoveProgramRecords");
+
+ // setup the data
+ readers.add(new SAMReaderID(new File(b37GoodBAM),new Tags()));
+
+ // use defaults
+ SAMDataSource data = new SAMDataSource(readers,
+ new ThreadAllocation(),
+ null,
+ genomeLocParser,
+ false,
+ ValidationStringency.SILENT,
+ null,
+ null,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ false);
+
+ List<SAMProgramRecord> defaultProgramRecords = data.getHeader().getProgramRecords();
+ assertTrue(defaultProgramRecords.size() != 0, "testRemoveProgramRecords: No program records found when using default constructor");
+
+ boolean removeProgramRecords = false;
+ data = new SAMDataSource(readers,
+ new ThreadAllocation(),
+ null,
+ genomeLocParser,
+ false,
+ ValidationStringency.SILENT,
+ null,
+ null,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ Collections.<ReadTransformer>emptyList(),
+ false,
+ (byte) -1,
+ removeProgramRecords,
+ false,
+ null, IntervalMergingRule.ALL);
+
+ List<SAMProgramRecord> dontRemoveProgramRecords = data.getHeader().getProgramRecords();
+ assertEquals(dontRemoveProgramRecords, defaultProgramRecords, "testRemoveProgramRecords: default program records differ from removeProgramRecords = false");
+
+ removeProgramRecords = true;
+ data = new SAMDataSource(readers,
+ new ThreadAllocation(),
+ null,
+ genomeLocParser,
+ false,
+ ValidationStringency.SILENT,
+ null,
+ null,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ Collections.<ReadTransformer>emptyList(),
+ false,
+ (byte) -1,
+ removeProgramRecords,
+ false,
+ null, IntervalMergingRule.ALL);
+
+ List<SAMProgramRecord> doRemoveProgramRecords = data.getHeader().getProgramRecords();
+ assertTrue(doRemoveProgramRecords.isEmpty(), "testRemoveProgramRecords: program records not cleared when removeProgramRecords = true");
+ }
+
+ @Test(expectedExceptions = UserException.class)
+ public void testFailOnReducedReads() {
+ readers.add(new SAMReaderID(new File(privateTestDir + "old.reduced.bam"), new Tags()));
+
+ SAMDataSource data = new SAMDataSource(readers,
+ new ThreadAllocation(),
+ null,
+ genomeLocParser,
+ false,
+ ValidationStringency.SILENT,
+ null,
+ null,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ false);
+ }
+
+ @Test(expectedExceptions = UserException.class)
+ public void testFailOnReducedReadsRemovingProgramRecords() {
+ readers.add(new SAMReaderID(new File(privateTestDir + "old.reduced.bam"), new Tags()));
+
+ SAMDataSource data = new SAMDataSource(readers,
+ new ThreadAllocation(),
+ null,
+ genomeLocParser,
+ false,
+ ValidationStringency.SILENT,
+ null,
+ null,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ Collections.<ReadTransformer>emptyList(),
+ false,
+ (byte) -1,
+ true,
+ false,
+ null, IntervalMergingRule.ALL);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/SAMReaderIDUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/SAMReaderIDUnitTest.java
new file mode 100644
index 0000000..bb1cd75
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/SAMReaderIDUnitTest.java
@@ -0,0 +1,49 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.File;
+
+public class SAMReaderIDUnitTest extends BaseTest {
+
+ @Test
+ public void testSAMReaderIDHashingAndEquality() {
+ // Test to make sure that two SAMReaderIDs that point at the same file via an absolute vs. relative
+ // path are equal according to equals() and have the same hash code
+ final File relativePathToBAMFile = new File(publicTestDir + "exampleBAM.bam");
+ final File absolutePathToBAMFile = new File(relativePathToBAMFile.getAbsolutePath());
+ final SAMReaderID relativePathSAMReaderID = new SAMReaderID(relativePathToBAMFile, new Tags());
+ final SAMReaderID absolutePathSAMReaderID = new SAMReaderID(absolutePathToBAMFile, new Tags());
+
+ Assert.assertEquals(relativePathSAMReaderID, absolutePathSAMReaderID, "Absolute-path and relative-path SAMReaderIDs not equal according to equals()");
+ Assert.assertEquals(relativePathSAMReaderID.hashCode(), absolutePathSAMReaderID.hashCode(), "Absolute-path and relative-path SAMReaderIDs have different hash codes");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/SeekableBufferedStreamUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/SeekableBufferedStreamUnitTest.java
new file mode 100644
index 0000000..c24a21a
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/SeekableBufferedStreamUnitTest.java
@@ -0,0 +1,101 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import htsjdk.samtools.seekablestream.SeekableBufferedStream;
+import htsjdk.samtools.seekablestream.SeekableFileStream;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Test basic functionality in SeekableBufferedStream.
+ */
+public class SeekableBufferedStreamUnitTest extends BaseTest {
+ private static File InputFile = new File(validationDataLocation + "megabyteZeros.dat");
+
+ final private int BUFFERED_STREAM_BUFFER_SIZE = 100;
+ private byte buffer[] = new byte[BUFFERED_STREAM_BUFFER_SIZE * 10];
+
+
+ @DataProvider(name = "BasicArgumentsDivisible")
+ public Integer[][] DivisableReads() {
+ return new Integer[][]{{1}, {4}, {5}, {10}, {20}, {50}, {100}};
+ }
+
+ @DataProvider(name = "BasicArgumentsIndivisibleAndSmall")
+ public Integer[][] InDivisableReadsSmall() {
+ return new Integer[][]{{3}, {11}, {31}, {51}, {77}, {99}};
+ }
+
+ @DataProvider(name = "BasicArgumentsIndivisibleYetLarge")
+ public Integer[][] InDivisableReadsLarge() {
+ return new Integer[][]{{101}, {151}, {205}, {251}, {301}};
+ }
+
+
+ private void testReadsLength(int length) throws IOException {
+ final int READ_SIZE=100000; //file is 10^6, so make this smaller to be safe.
+
+ SeekableFileStream fileStream = new SeekableFileStream(InputFile);
+ SeekableBufferedStream bufferedStream = new SeekableBufferedStream(fileStream, BUFFERED_STREAM_BUFFER_SIZE);
+
+ for (int i = 0; i < READ_SIZE / length; ++i) {
+ Assert.assertEquals(bufferedStream.read(buffer, 0, length), length);
+ }
+
+ }
+
+ // These tests fail because SeekableBuffered stream may return _less_ than the amount you are asking for.
+ // make sure that you wrap reads with while-loops. If these test start failing (meaning that the reads work properly,
+ // the layer of protection built into GATKBamIndex can be removed.
+
+ @Test(dataProvider = "BasicArgumentsIndivisibleAndSmall", enabled = true, expectedExceptions = java.lang.AssertionError.class)
+ public void testIndivisableSmallReadsFAIL(Integer readLength) throws IOException {
+ testReadsLength(readLength);
+ }
+
+ //Evidently, if you ask for a read length that's larger than the inernal buffer,
+ //SeekableBufferedStreamdoes something else and gives you what you asked for
+
+ @Test(dataProvider = "BasicArgumentsIndivisibleYetLarge", enabled = true)
+ public void testIndivisableLargeReadsPASS(Integer readLength) throws IOException {
+ testReadsLength(readLength);
+ }
+
+ // if the readlength divides the buffer, there are no failures
+ @Test(dataProvider = "BasicArgumentsDivisible", enabled = true)
+ public void testDivisableReadsPASS(Integer readLength) throws IOException {
+ testReadsLength(readLength);
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/TheoreticalMinimaBenchmark.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/TheoreticalMinimaBenchmark.java
new file mode 100644
index 0000000..aa66f17
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reads/TheoreticalMinimaBenchmark.java
@@ -0,0 +1,114 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reads;
+
+import com.google.caliper.Param;
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.CloseableIterator;
+
+import java.io.File;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mhanna
+ * Date: Apr 22, 2011
+ * Time: 4:01:23 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class TheoreticalMinimaBenchmark extends ReadProcessingBenchmark {
+ @Param
+ private String bamFile;
+
+ @Param
+ private Integer maxReads;
+
+ @Override
+ public String getBAMFile() { return bamFile; }
+
+ @Override
+ public Integer getMaxReads() { return maxReads; }
+
+ public void timeIterateOverEachBase(int reps) {
+ System.out.printf("Processing " + inputFile);
+ for(int i = 0; i < reps; i++) {
+ SAMFileReader reader = new SAMFileReader(inputFile);
+ CloseableIterator<SAMRecord> iterator = reader.iterator();
+
+ long As=0,Cs=0,Gs=0,Ts=0;
+ while(iterator.hasNext()) {
+ SAMRecord read = iterator.next();
+ for(byte base: read.getReadBases()) {
+ switch(base) {
+ case 'A': As++; break;
+ case 'C': Cs++; break;
+ case 'G': Gs++; break;
+ case 'T': Ts++; break;
+ }
+ }
+ }
+ System.out.printf("As = %d; Cs = %d; Gs = %d; Ts = %d; total = %d%n",As,Cs,Gs,Ts,As+Cs+Gs+Ts);
+ iterator.close();
+ reader.close();
+ }
+ }
+
+ public void timeIterateOverCigarString(int reps) {
+ for(int i = 0; i < reps; i++) {
+ long matchMismatches = 0;
+ long insertions = 0;
+ long deletions = 0;
+ long others = 0;
+
+ SAMFileReader reader = new SAMFileReader(inputFile);
+ CloseableIterator<SAMRecord> iterator = reader.iterator();
+ while(iterator.hasNext()) {
+ SAMRecord read = iterator.next();
+
+ Cigar cigar = read.getCigar();
+ for(CigarElement cigarElement: cigar.getCigarElements()) {
+ int elementSize = cigarElement.getLength();
+ while(elementSize > 0) {
+ switch(cigarElement.getOperator()) {
+ case M: case EQ: case X: matchMismatches++; break;
+ case I: insertions++; break;
+ case D: deletions++; break;
+ default: others++; break;
+ }
+ elementSize--;
+ }
+ }
+ }
+ System.out.printf("Ms = %d; Is = %d; Ds = %d; others = %d; total = %d%n",matchMismatches,insertions,deletions,others,matchMismatches+insertions+deletions+others);
+
+ iterator.close();
+ reader.close();
+ }
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reference/ReferenceDataSourceIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reference/ReferenceDataSourceIntegrationTest.java
new file mode 100644
index 0000000..46a4cb5
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/reference/ReferenceDataSourceIntegrationTest.java
@@ -0,0 +1,75 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.reference;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.io.File;
+import java.io.IOException;
+
+public class ReferenceDataSourceIntegrationTest extends WalkerTest {
+
+ @Test
+ public void testReferenceWithMissingFaiFile() throws IOException {
+ final File dummyReference = createTempFile("dummy", ".fasta");
+ final File dictFile = new File(dummyReference.getAbsolutePath().replace(".fasta", ".dict"));
+ dictFile.deleteOnExit();
+ Assert.assertTrue(dictFile.createNewFile());
+
+ final WalkerTestSpec spec = new WalkerTestSpec(
+ " -T PrintReads" +
+ " -R " + dummyReference.getAbsolutePath() +
+ " -I " + privateTestDir + "NA12878.4.snippet.bam" +
+ " -o %s",
+ 1,
+ UserException.MissingReferenceFaiFile.class
+ );
+
+ executeTest("testReferenceWithMissingFaiFile", spec);
+ }
+
+ @Test
+ public void testReferenceWithMissingDictFile() throws IOException {
+ final File dummyReference = createTempFile("dummy", ".fasta");
+ final File faiFile = new File(dummyReference.getAbsolutePath() + ".fai");
+ faiFile.deleteOnExit();
+ Assert.assertTrue(faiFile.createNewFile());
+
+ final WalkerTestSpec spec = new WalkerTestSpec(
+ " -T PrintReads" +
+ " -R " + dummyReference.getAbsolutePath() +
+ " -I " + privateTestDir + "NA12878.4.snippet.bam" +
+ " -o %s",
+ 1,
+ UserException.MissingReferenceDictFile.class
+ );
+
+ executeTest("testReferenceWithMissingDictFile", spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedDataPoolUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedDataPoolUnitTest.java
new file mode 100644
index 0000000..baa2af0
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedDataPoolUnitTest.java
@@ -0,0 +1,208 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.rmd;
+
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrackBuilder;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.codecs.table.TableFeature;
+import org.broadinstitute.gatk.engine.refdata.utils.LocationAwareSeekableRODIterator;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet;
+import org.broadinstitute.gatk.engine.refdata.utils.RMDTriplet.RMDStorageType;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+
+import static org.testng.Assert.assertTrue;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+/**
+ * User: hanna
+ * Date: May 21, 2009
+ * Time: 11:03:04 AM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Test the contents and number of iterators in the pool.
+ */
+
+public class ReferenceOrderedDataPoolUnitTest extends BaseTest {
+
+ private RMDTriplet triplet = null;
+ private RMDTrackBuilder builder = null;
+
+ private IndexedFastaSequenceFile seq;
+ private GenomeLocParser genomeLocParser;
+
+ private GenomeLoc testSite1;
+ private GenomeLoc testSite2;
+ private GenomeLoc testSite3;
+
+ private GenomeLoc testInterval1; // an interval matching testSite1 -> testSite2 for queries
+ private GenomeLoc testInterval2; // an interval matching testSite2 -> testSite3 for queries
+
+
+ @BeforeClass
+ public void init() throws FileNotFoundException {
+ seq = new CachingIndexedFastaSequenceFile(new File(hg18Reference));
+ genomeLocParser = new GenomeLocParser(seq);
+
+ testSite1 = genomeLocParser.createGenomeLoc("chrM",10);
+ testSite2 = genomeLocParser.createGenomeLoc("chrM",20);
+ testSite3 = genomeLocParser.createGenomeLoc("chrM",30);
+ testInterval1 = genomeLocParser.createGenomeLoc("chrM",10,20);
+ testInterval2 = genomeLocParser.createGenomeLoc("chrM",20,30);
+ }
+
+ @BeforeMethod
+ public void setUp() {
+ String fileName = privateTestDir + "TabularDataTest.dat";
+
+ triplet = new RMDTriplet("tableTest","Table",fileName,RMDStorageType.FILE,new Tags());
+ // disable auto-index creation/locking in the RMDTrackBuilder for tests
+ builder = new RMDTrackBuilder(seq.getSequenceDictionary(),genomeLocParser,null,true,null);
+ }
+
+ @Test
+ public void testCreateSingleIterator() {
+ ResourcePool iteratorPool = new ReferenceOrderedDataPool(triplet,builder,seq.getSequenceDictionary(),genomeLocParser,false);
+ LocationAwareSeekableRODIterator iterator = (LocationAwareSeekableRODIterator)iteratorPool.iterator( new MappedStreamSegment(testSite1) );
+
+ Assert.assertEquals(iteratorPool.numIterators(), 1, "Number of iterators in the pool is incorrect");
+ Assert.assertEquals(iteratorPool.numAvailableIterators(), 0, "Number of available iterators in the pool is incorrect");
+
+ TableFeature datum = (TableFeature)iterator.next().get(0).getUnderlyingObject();
+
+ assertTrue(datum.getLocation().equals(testSite1));
+ assertTrue(datum.get("COL1").equals("A"));
+ assertTrue(datum.get("COL2").equals("B"));
+ assertTrue(datum.get("COL3").equals("C"));
+
+ iteratorPool.release(iterator);
+
+ Assert.assertEquals(iteratorPool.numIterators(), 1, "Number of iterators in the pool is incorrect");
+ Assert.assertEquals(iteratorPool.numAvailableIterators(), 1, "Number of available iterators in the pool is incorrect");
+ }
+
+ @Test
+ public void testCreateMultipleIterators() {
+ ReferenceOrderedQueryDataPool iteratorPool = new ReferenceOrderedQueryDataPool(triplet,builder,seq.getSequenceDictionary(),genomeLocParser);
+ LocationAwareSeekableRODIterator iterator1 = iteratorPool.iterator( new MappedStreamSegment(testInterval1) );
+
+ // Create a new iterator at position 2.
+ LocationAwareSeekableRODIterator iterator2 = iteratorPool.iterator( new MappedStreamSegment(testInterval2) );
+
+ Assert.assertEquals(iteratorPool.numIterators(), 2, "Number of iterators in the pool is incorrect");
+ Assert.assertEquals(iteratorPool.numAvailableIterators(), 0, "Number of available iterators in the pool is incorrect");
+
+ // Test out-of-order access: first iterator2, then iterator1.
+ // Ugh...first call to a region needs to be a seek.
+ TableFeature datum = (TableFeature)iterator2.seekForward(testSite2).get(0).getUnderlyingObject();
+ assertTrue(datum.getLocation().equals(testSite2));
+ assertTrue(datum.get("COL1").equals("C"));
+ assertTrue(datum.get("COL2").equals("D"));
+ assertTrue(datum.get("COL3").equals("E"));
+
+ datum = (TableFeature)iterator1.next().get(0).getUnderlyingObject();
+ assertTrue(datum.getLocation().equals(testSite1));
+ assertTrue(datum.get("COL1").equals("A"));
+ assertTrue(datum.get("COL2").equals("B"));
+ assertTrue(datum.get("COL3").equals("C"));
+
+ // Advance iterator2, and make sure both iterator's contents are still correct.
+ datum = (TableFeature)iterator2.next().get(0).getUnderlyingObject();
+ assertTrue(datum.getLocation().equals(testSite3));
+ assertTrue(datum.get("COL1").equals("F"));
+ assertTrue(datum.get("COL2").equals("G"));
+ assertTrue(datum.get("COL3").equals("H"));
+
+ datum = (TableFeature)iterator1.next().get(0).getUnderlyingObject();
+ assertTrue(datum.getLocation().equals(testSite2));
+ assertTrue(datum.get("COL1").equals("C"));
+ assertTrue(datum.get("COL2").equals("D"));
+ assertTrue(datum.get("COL3").equals("E"));
+
+ // Cleanup, and make sure the number of iterators dies appropriately.
+ iteratorPool.release(iterator1);
+
+ Assert.assertEquals(iteratorPool.numIterators(), 2, "Number of iterators in the pool is incorrect");
+ Assert.assertEquals(iteratorPool.numAvailableIterators(), 1, "Number of available iterators in the pool is incorrect");
+
+ iteratorPool.release(iterator2);
+
+ Assert.assertEquals(iteratorPool.numIterators(), 2, "Number of iterators in the pool is incorrect");
+ Assert.assertEquals(iteratorPool.numAvailableIterators(), 2, "Number of available iterators in the pool is incorrect");
+ }
+
+ @Test
+ public void testIteratorConservation() {
+ ReferenceOrderedDataPool iteratorPool = new ReferenceOrderedDataPool(triplet,builder,seq.getSequenceDictionary(),genomeLocParser,false);
+ LocationAwareSeekableRODIterator iterator = iteratorPool.iterator( new MappedStreamSegment(testSite1) );
+
+ Assert.assertEquals(iteratorPool.numIterators(), 1, "Number of iterators in the pool is incorrect");
+ Assert.assertEquals(iteratorPool.numAvailableIterators(), 0, "Number of available iterators in the pool is incorrect");
+
+ TableFeature datum = (TableFeature)iterator.next().get(0).getUnderlyingObject();
+ assertTrue(datum.getLocation().equals(testSite1));
+ assertTrue(datum.get("COL1").equals("A"));
+ assertTrue(datum.get("COL2").equals("B"));
+ assertTrue(datum.get("COL3").equals("C"));
+
+ iteratorPool.release(iterator);
+
+ // Create another iterator after the current iterator.
+ iterator = iteratorPool.iterator( new MappedStreamSegment(testSite3) );
+
+ // Make sure that the previously acquired iterator was reused.
+ Assert.assertEquals(iteratorPool.numIterators(), 1, "Number of iterators in the pool is incorrect");
+ Assert.assertEquals(iteratorPool.numAvailableIterators(), 0, "Number of available iterators in the pool is incorrect");
+
+ datum = (TableFeature)iterator.seekForward(testSite3).get(0).getUnderlyingObject();
+ assertTrue(datum.getLocation().equals(testSite3));
+ assertTrue(datum.get("COL1").equals("F"));
+ assertTrue(datum.get("COL2").equals("G"));
+ assertTrue(datum.get("COL3").equals("H"));
+
+ iteratorPool.release(iterator);
+
+ Assert.assertEquals(iteratorPool.numIterators(), 1, "Number of iterators in the pool is incorrect");
+ Assert.assertEquals(iteratorPool.numAvailableIterators(), 1, "Number of available iterators in the pool is incorrect");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedQueryDataPoolUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedQueryDataPoolUnitTest.java
new file mode 100644
index 0000000..6c403cd
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/datasources/rmd/ReferenceOrderedQueryDataPoolUnitTest.java
@@ -0,0 +1,89 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.datasources.rmd;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.refdata.utils.*;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+public class ReferenceOrderedQueryDataPoolUnitTest extends BaseTest{
+ @Test
+ public void testCloseFilePointers() throws IOException {
+ // Build up query parameters
+ File file = new File(BaseTest.privateTestDir + "NA12878.hg19.example1.vcf");
+ RMDTriplet triplet = new RMDTriplet("test", "VCF", file.getAbsolutePath(), RMDTriplet.RMDStorageType.FILE, new Tags());
+ IndexedFastaSequenceFile seq = new CachingIndexedFastaSequenceFile(new File(BaseTest.hg19Reference));
+ GenomeLocParser parser = new GenomeLocParser(seq);
+ GenomeLoc loc = parser.createGenomeLoc("20", 1, 100000);
+ TestRMDTrackBuilder builder = new TestRMDTrackBuilder(seq.getSequenceDictionary(), parser);
+
+ // Create the query data pool
+ ReferenceOrderedQueryDataPool pool = new ReferenceOrderedQueryDataPool(triplet, builder, seq.getSequenceDictionary(), parser);
+
+ for (int i = 0; i < 3; i++) {
+ // Ensure our tribble iterators are closed.
+ CheckableCloseableTribbleIterator.clearThreadIterators();
+ Assert.assertTrue(CheckableCloseableTribbleIterator.getThreadIterators().isEmpty(), "Tribble iterators list was not cleared.");
+
+ // Request the the rodIterator
+ LocationAwareSeekableRODIterator rodIterator = pool.iterator(new MappedStreamSegment(loc));
+
+ // Run normal iteration over rodIterator
+ Assert.assertTrue(rodIterator.hasNext(), "Rod iterator does not have a next value.");
+ GenomeLoc rodIteratorLocation = rodIterator.next().getLocation();
+ Assert.assertEquals(rodIteratorLocation.getContig(), "20", "Instead of chr 20 rod iterator was at location " + rodIteratorLocation);
+
+ // Check that the underlying tribbleIterators are still open.
+ List<CheckableCloseableTribbleIterator<? extends Feature>> tribbleIterators = CheckableCloseableTribbleIterator.getThreadIterators();
+ Assert.assertFalse(tribbleIterators.isEmpty(), "Tribble iterators list is empty");
+ for (CheckableCloseableTribbleIterator<? extends Feature> tribbleIterator: tribbleIterators) {
+ Assert.assertFalse(tribbleIterator.isClosed(), "Tribble iterator is closed but should be still open.");
+ }
+
+ // Releasing the rodIterator should close the underlying tribbleIterator.
+ pool.release(rodIterator);
+
+ // Check that the underlying tribbleIterators are now closed.
+ for (CheckableCloseableTribbleIterator<? extends Feature> tribbleIterator: tribbleIterators) {
+ Assert.assertTrue(tribbleIterator.isClosed(), "Tribble iterator is open but should be now closed.");
+ }
+ }
+
+ // Extra cleanup.
+ CheckableCloseableTribbleIterator.clearThreadIterators();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/AlleleBiasedDownsamplingUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/AlleleBiasedDownsamplingUtilsUnitTest.java
new file mode 100644
index 0000000..2d86f73
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/AlleleBiasedDownsamplingUtilsUnitTest.java
@@ -0,0 +1,219 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.SAMFileHeader;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.*;
+
+
+/**
+ * Basic unit test for AlleleBiasedDownsamplingUtils
+ */
+public class AlleleBiasedDownsamplingUtilsUnitTest extends BaseTest {
+
+
+ @Test
+ public void testSmartDownsampling() {
+
+ final int[] idealHetAlleleCounts = new int[]{0, 50, 0, 50};
+ final int[] idealHomAlleleCounts = new int[]{0, 100, 0, 0};
+
+ // no contamination, no removal
+ testOneCase(0, 0, 0, 0, 0.1, 100, idealHetAlleleCounts, idealHetAlleleCounts);
+ testOneCase(0, 0, 0, 0, 0.1, 100, idealHomAlleleCounts, idealHomAlleleCounts);
+
+ // hom sample, het contaminant, different alleles
+ testOneCase(5, 0, 0, 0, 0.1, 100, idealHomAlleleCounts, idealHomAlleleCounts);
+ testOneCase(0, 0, 5, 0, 0.1, 100, idealHomAlleleCounts, idealHomAlleleCounts);
+ testOneCase(0, 0, 0, 5, 0.1, 100, idealHomAlleleCounts, idealHomAlleleCounts);
+
+ // hom sample, hom contaminant, different alleles
+ testOneCase(10, 0, 0, 0, 0.1, 100, idealHomAlleleCounts, idealHomAlleleCounts);
+ testOneCase(0, 0, 10, 0, 0.1, 100, idealHomAlleleCounts, idealHomAlleleCounts);
+ testOneCase(0, 0, 0, 10, 0.1, 100, idealHomAlleleCounts, idealHomAlleleCounts);
+
+ // het sample, het contaminant, different alleles
+ testOneCase(5, 0, 0, 0, 0.1, 100, idealHetAlleleCounts, idealHetAlleleCounts);
+ testOneCase(0, 0, 5, 0, 0.1, 100, idealHetAlleleCounts, idealHetAlleleCounts);
+
+ // het sample, hom contaminant, different alleles
+ testOneCase(10, 0, 0, 0, 0.1, 100, idealHetAlleleCounts, idealHetAlleleCounts);
+ testOneCase(0, 0, 10, 0, 0.1, 100, idealHetAlleleCounts, idealHetAlleleCounts);
+
+ // hom sample, het contaminant, overlapping alleles
+ final int[] enhancedHomAlleleCounts = new int[]{0, 105, 0, 0};
+ testOneCase(5, 5, 0, 0, 0.1, 100, idealHomAlleleCounts, enhancedHomAlleleCounts);
+ testOneCase(0, 5, 5, 0, 0.1, 100, idealHomAlleleCounts, enhancedHomAlleleCounts);
+ testOneCase(0, 5, 0, 5, 0.1, 100, idealHomAlleleCounts, enhancedHomAlleleCounts);
+
+ // hom sample, hom contaminant, overlapping alleles
+ testOneCase(0, 10, 0, 0, 0.1, 100, idealHomAlleleCounts, new int[]{0, 110, 0, 0});
+
+ // het sample, het contaminant, overlapping alleles
+ testOneCase(5, 5, 0, 0, 0.1, 100, idealHetAlleleCounts, idealHetAlleleCounts);
+ testOneCase(0, 5, 5, 0, 0.1, 100, idealHetAlleleCounts, idealHetAlleleCounts);
+ testOneCase(0, 5, 0, 5, 0.1, 100, idealHetAlleleCounts, new int[]{0, 55, 0, 55});
+ testOneCase(5, 0, 0, 5, 0.1, 100, idealHetAlleleCounts, idealHetAlleleCounts);
+ testOneCase(0, 0, 5, 5, 0.1, 100, idealHetAlleleCounts, idealHetAlleleCounts);
+
+ // het sample, hom contaminant, overlapping alleles
+ testOneCase(0, 10, 0, 0, 0.1, 100, idealHetAlleleCounts, idealHetAlleleCounts);
+ testOneCase(0, 0, 0, 10, 0.1, 100, idealHetAlleleCounts, idealHetAlleleCounts);
+ }
+
+ private static void testOneCase(final int addA, final int addC, final int addG, final int addT, final double contaminationFraction,
+ final int pileupSize, final int[] initialCounts, final int[] targetCounts) {
+
+ final int[] actualCounts = initialCounts.clone();
+ actualCounts[0] += addA;
+ actualCounts[1] += addC;
+ actualCounts[2] += addG;
+ actualCounts[3] += addT;
+
+ final int[] results = AlleleBiasedDownsamplingUtils.runSmartDownsampling(actualCounts, (int)(pileupSize * contaminationFraction));
+ Assert.assertTrue(countsAreEqual(results, targetCounts));
+ }
+
+ private static boolean countsAreEqual(final int[] counts1, final int[] counts2) {
+ for ( int i = 0; i < 4; i++ ) {
+ if ( counts1[i] != counts2[i] )
+ return false;
+ }
+ return true;
+ }
+
+ @DataProvider(name = "BiasedDownsamplingTest")
+ public Object[][] makeBiasedDownsamplingTest() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000);
+
+ for ( final int originalCount : Arrays.asList(1, 2, 10, 1000) ) {
+ for ( final int toRemove : Arrays.asList(0, 1, 2, 10, 1000) ) {
+ if ( toRemove <= originalCount )
+ tests.add(new Object[]{header, originalCount, toRemove});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "BiasedDownsamplingTest")
+ public void testBiasedDownsampling(final SAMFileHeader header, final int originalCount, final int toRemove) {
+
+ final LinkedList<PileupElement> elements = new LinkedList<>();
+ for ( int i = 0; i < originalCount; i++ ) {
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read", 0, 1, 1);
+ elements.add(new PileupElement(read, 0, new CigarElement(1, CigarOperator.M), 0, 0));
+ }
+
+ final List<PileupElement> result = AlleleBiasedDownsamplingUtils.downsampleElements(elements, originalCount, toRemove);
+
+ Assert.assertEquals(result.size(), toRemove);
+ }
+
+ @Test
+ public void testLoadContaminationFileDetails(){
+ Logger logger=org.apache.log4j.Logger.getRootLogger();
+
+ final String ArtificalBAMLocation = privateTestDir + "ArtificallyContaminatedBams/";
+ final File ContamFile1=new File(ArtificalBAMLocation+"contamination.case.1.txt");
+
+ Map<String,Double> Contam1=new HashMap<String,Double>();
+ Set<String> Samples1=new HashSet<String>();
+
+ Contam1.put("NA11918",0.15);
+ Samples1.addAll(Contam1.keySet());
+ testLoadFile(ContamFile1,Samples1,Contam1,logger);
+
+ Contam1.put("NA12842",0.13);
+ Samples1.addAll(Contam1.keySet());
+ testLoadFile(ContamFile1,Samples1,Contam1,logger);
+
+ Samples1.add("DUMMY");
+ testLoadFile(ContamFile1,Samples1,Contam1,logger);
+ }
+
+ private static void testLoadFile(final File file, final Set<String> Samples, final Map<String,Double> map, Logger logger){
+ Map<String,Double> loadedMap = AlleleBiasedDownsamplingUtils.loadContaminationFile(file,0.0,Samples,logger);
+ Assert.assertTrue(loadedMap.equals(map));
+ }
+
+ @DataProvider(name = "goodContaminationFiles")
+ public Integer[][] goodContaminationFiles() {
+ return new Integer[][]{
+ {1, 2},
+ {2, 3},
+ {3, 2},
+ {4, 2},
+ {5, 3},
+ {6, 2},
+ {7, 2},
+ {8, 2}
+ };
+ }
+
+ @Test(dataProvider = "goodContaminationFiles")
+ public void testLoadContaminationFile(final Integer ArtificalBAMnumber, final Integer numberOfSamples) {
+ final String ArtificialBAM = String.format("ArtificallyContaminatedBams/contamination.case.%d.txt", ArtificalBAMnumber);
+ Logger logger = org.apache.log4j.Logger.getRootLogger();
+
+ File ContamFile = new File(privateTestDir, ArtificialBAM);
+ Assert.assertTrue(AlleleBiasedDownsamplingUtils.loadContaminationFile(ContamFile, 0.0, null, logger).size() == numberOfSamples);
+
+ }
+
+
+ @DataProvider(name = "badContaminationFiles")
+ public Integer[][] badContaminationFiles() {
+ return new Integer[][]{{1}, {2}, {3}, {4}, {5}};
+ }
+
+ @Test(dataProvider = "badContaminationFiles", expectedExceptions = UserException.MalformedFile.class)
+ public void testLoadBrokenContaminationFile(final int i) {
+ Logger logger = org.apache.log4j.Logger.getRootLogger();
+ final String ArtificalBAMLocation = privateTestDir + "ArtificallyContaminatedBams/";
+
+ File ContaminationFile = new File(ArtificalBAMLocation + String.format("contamination.case.broken.%d.txt", i));
+ AlleleBiasedDownsamplingUtils.loadContaminationFile(ContaminationFile, 0.0, null, logger);
+
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingIntegrationTest.java
new file mode 100644
index 0000000..2f171de
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingIntegrationTest.java
@@ -0,0 +1,44 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.annotations.Test;
+
+public class DownsamplingIntegrationTest extends WalkerTest {
+
+ @Test
+ public void testDetectLowDcovValueWithLocusTraversal() {
+ final WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci -R " + publicTestDir + "exampleFASTA.fasta -I " + publicTestDir + "exampleBAM.bam -o %s " +
+ "-dcov " + (DownsamplingMethod.MINIMUM_SAFE_COVERAGE_TARGET_FOR_LOCUS_BASED_TRAVERSALS - 1),
+ 1,
+ UserException.class
+ );
+ executeTest("testDetectLowDcovValueWithLocusTraversal", spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingReadsIteratorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingReadsIteratorUnitTest.java
new file mode 100644
index 0000000..19eec62
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/DownsamplingReadsIteratorUnitTest.java
@@ -0,0 +1,139 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.ArtificialSingleSampleReadStream;
+import org.broadinstitute.gatk.utils.sam.ArtificialSingleSampleReadStreamAnalyzer;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+public class DownsamplingReadsIteratorUnitTest extends BaseTest {
+
+ private static class DownsamplingReadsIteratorTest extends TestDataProvider {
+ private DownsamplingReadsIterator downsamplingIter;
+ private int targetCoverage;
+ private ArtificialSingleSampleReadStream stream;
+ private ArtificialSingleSampleReadStreamAnalyzer streamAnalyzer;
+
+ public DownsamplingReadsIteratorTest( ArtificialSingleSampleReadStream stream, int targetCoverage ) {
+ super(DownsamplingReadsIteratorTest.class);
+
+ this.stream = stream;
+ this.targetCoverage = targetCoverage;
+
+ setName(String.format("%s: targetCoverage=%d numContigs=%d stacksPerContig=%d readsPerStack=%d-%d distanceBetweenStacks=%d-%d readLength=%d-%d unmappedReads=%d",
+ getClass().getSimpleName(),
+ targetCoverage,
+ stream.getNumContigs(),
+ stream.getNumStacksPerContig(),
+ stream.getMinReadsPerStack(),
+ stream.getMaxReadsPerStack(),
+ stream.getMinDistanceBetweenStacks(),
+ stream.getMaxDistanceBetweenStacks(),
+ stream.getMinReadLength(),
+ stream.getMaxReadLength(),
+ stream.getNumUnmappedReads()));
+ }
+
+ public void run() {
+ streamAnalyzer = new PositionallyDownsampledArtificialSingleSampleReadStreamAnalyzer(stream, targetCoverage);
+ downsamplingIter = new DownsamplingReadsIterator(stream.getGATKSAMIterator(), new SimplePositionalDownsampler<SAMRecord>(targetCoverage));
+
+ streamAnalyzer.analyze(downsamplingIter);
+
+ // Check whether the observed properties of the downsampled stream are what they should be
+ streamAnalyzer.validate();
+
+ // Allow memory used by this test to be reclaimed
+ stream = null;
+ streamAnalyzer = null;
+ downsamplingIter = null;
+ }
+ }
+
+ @DataProvider(name = "DownsamplingReadsIteratorTestDataProvider")
+ public Object[][] createDownsamplingReadsIteratorTests() {
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(5, 1, 10000);
+ String readGroupID = "testReadGroup";
+ SAMReadGroupRecord readGroup = new SAMReadGroupRecord(readGroupID);
+ readGroup.setSample("testSample");
+ header.addReadGroup(readGroup);
+
+ // Values that don't vary across tests
+ int targetCoverage = 10;
+ int minReadLength = 50;
+ int maxReadLength = 100;
+ int minDistanceBetweenStacks = 1;
+ int maxDistanceBetweenStacks = maxReadLength + 1;
+
+ GenomeAnalysisEngine.resetRandomGenerator();
+
+ // brute force testing!
+ for ( int numContigs : Arrays.asList(1, 2, 5) ) {
+ for ( int stacksPerContig : Arrays.asList(1, 2, 10) ) {
+ for ( int minReadsPerStack : Arrays.asList(1, targetCoverage / 2, targetCoverage, targetCoverage - 1, targetCoverage + 1, targetCoverage * 2) ) {
+ for ( int maxReadsPerStack : Arrays.asList(1, targetCoverage / 2, targetCoverage, targetCoverage - 1, targetCoverage + 1, targetCoverage * 2) ) {
+ for ( int numUnmappedReads : Arrays.asList(0, 1, targetCoverage, targetCoverage * 2) ) {
+ // Only interested in sane read stream configurations here
+ if ( minReadsPerStack <= maxReadsPerStack ) {
+ new DownsamplingReadsIteratorTest(new ArtificialSingleSampleReadStream(header,
+ readGroupID,
+ numContigs,
+ stacksPerContig,
+ minReadsPerStack,
+ maxReadsPerStack,
+ minDistanceBetweenStacks,
+ maxDistanceBetweenStacks,
+ minReadLength,
+ maxReadLength,
+ numUnmappedReads),
+ targetCoverage);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return DownsamplingReadsIteratorTest.getTests(DownsamplingReadsIteratorTest.class);
+ }
+
+ @Test(dataProvider = "DownsamplingReadsIteratorTestDataProvider")
+ public void runDownsamplingReadsIteratorTest( DownsamplingReadsIteratorTest test ) {
+ logger.warn("Running test: " + test);
+
+ GenomeAnalysisEngine.resetRandomGenerator();
+ test.run();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/FractionalDownsamplerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/FractionalDownsamplerUnitTest.java
new file mode 100644
index 0000000..9185374
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/FractionalDownsamplerUnitTest.java
@@ -0,0 +1,158 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+public class FractionalDownsamplerUnitTest extends BaseTest {
+
+ private static class FractionalDownsamplerTest extends TestDataProvider {
+ double fraction;
+ int totalReads;
+ int expectedMinNumReadsAfterDownsampling;
+ int expectedMaxNumReadsAfterDownsampling;
+ int expectedMinDiscardedItems;
+ int expectedMaxDiscardedItems;
+
+ private static final double EXPECTED_ACCURACY = 0.05; // should be accurate to within +/- this percent
+
+ public FractionalDownsamplerTest( double fraction, int totalReads ) {
+ super(FractionalDownsamplerTest.class);
+
+ this.fraction = fraction;
+ this.totalReads = totalReads;
+
+ calculateExpectations();
+
+ setName(String.format("%s: fraction=%.2f totalReads=%d expectedMinNumReadsAfterDownsampling=%d expectedMaxNumReadsAfterDownsampling=%d",
+ getClass().getSimpleName(), fraction, totalReads, expectedMinNumReadsAfterDownsampling, expectedMaxNumReadsAfterDownsampling));
+ }
+
+ private void calculateExpectations() {
+ // Require an exact match in the 0% and 100% cases
+ if ( fraction == 0.0 ) {
+ expectedMinNumReadsAfterDownsampling = expectedMaxNumReadsAfterDownsampling = 0;
+ expectedMinDiscardedItems = expectedMaxDiscardedItems = totalReads;
+ }
+ else if ( fraction == 1.0 ) {
+ expectedMinNumReadsAfterDownsampling = expectedMaxNumReadsAfterDownsampling = totalReads;
+ expectedMinDiscardedItems = expectedMaxDiscardedItems = 0;
+ }
+ else {
+ expectedMinNumReadsAfterDownsampling = Math.max((int)((fraction - EXPECTED_ACCURACY) * totalReads), 0);
+ expectedMaxNumReadsAfterDownsampling = Math.min((int) ((fraction + EXPECTED_ACCURACY) * totalReads), totalReads);
+ expectedMinDiscardedItems = totalReads - expectedMaxNumReadsAfterDownsampling;
+ expectedMaxDiscardedItems = totalReads - expectedMinNumReadsAfterDownsampling;
+ }
+ }
+
+ public Collection<SAMRecord> createReads() {
+ Collection<SAMRecord> reads = new ArrayList<SAMRecord>(totalReads);
+
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000000);
+ reads.addAll(ArtificialSAMUtils.createStackOfIdenticalArtificialReads(totalReads, header, "foo", 0, 1, 100));
+
+ return reads;
+ }
+ }
+
+ @DataProvider(name = "FractionalDownsamplerTestDataProvider")
+ public Object[][] createFractionalDownsamplerTestData() {
+ for ( double fraction : Arrays.asList(0.0, 0.25, 0.5, 0.75, 1.0) ) {
+ for ( int totalReads : Arrays.asList(0, 1000, 10000) ) {
+ new FractionalDownsamplerTest(fraction, totalReads);
+ }
+ }
+
+ return FractionalDownsamplerTest.getTests(FractionalDownsamplerTest.class);
+ }
+
+ @Test(dataProvider = "FractionalDownsamplerTestDataProvider")
+ public void runFractionalDownsamplerTest( FractionalDownsamplerTest test ) {
+ logger.warn("Running test: " + test);
+
+ GenomeAnalysisEngine.resetRandomGenerator();
+
+ ReadsDownsampler<SAMRecord> downsampler = new FractionalDownsampler<SAMRecord>(test.fraction);
+
+ downsampler.submit(test.createReads());
+
+ if ( test.totalReads > 0 ) {
+ if ( test.fraction > FractionalDownsamplerTest.EXPECTED_ACCURACY ) {
+ Assert.assertTrue(downsampler.hasFinalizedItems());
+ Assert.assertTrue(downsampler.peekFinalized() != null);
+ }
+ Assert.assertFalse(downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekPending() == null);
+ }
+ else {
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+ }
+
+ downsampler.signalEndOfInput();
+
+ if ( test.totalReads > 0 ) {
+ if ( test.fraction > FractionalDownsamplerTest.EXPECTED_ACCURACY ) {
+ Assert.assertTrue(downsampler.hasFinalizedItems());
+ Assert.assertTrue(downsampler.peekFinalized() != null);
+ }
+ Assert.assertFalse(downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekPending() == null);
+ }
+ else {
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+ }
+
+ List<SAMRecord> downsampledReads = downsampler.consumeFinalizedItems();
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+
+ Assert.assertTrue(downsampledReads.size() >= test.expectedMinNumReadsAfterDownsampling &&
+ downsampledReads.size() <= test.expectedMaxNumReadsAfterDownsampling);
+
+ Assert.assertTrue(downsampler.getNumberOfDiscardedItems() >= test.expectedMinDiscardedItems &&
+ downsampler.getNumberOfDiscardedItems() <= test.expectedMaxDiscardedItems);
+
+ Assert.assertEquals(downsampler.getNumberOfDiscardedItems(), test.totalReads - downsampledReads.size());
+
+ downsampler.resetStats();
+ Assert.assertEquals(downsampler.getNumberOfDiscardedItems(), 0);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/LevelingDownsamplerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/LevelingDownsamplerUnitTest.java
new file mode 100644
index 0000000..2544b72
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/LevelingDownsamplerUnitTest.java
@@ -0,0 +1,163 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import org.testng.Assert;
+
+import java.util.*;
+
+public class LevelingDownsamplerUnitTest extends BaseTest {
+
+ private static class LevelingDownsamplerUniformStacksTest extends TestDataProvider {
+ public enum DataStructure { LINKED_LIST, ARRAY_LIST }
+
+ int targetSize;
+ int numStacks;
+ int stackSize;
+ DataStructure dataStructure;
+ int expectedSize;
+
+ public LevelingDownsamplerUniformStacksTest( int targetSize, int numStacks, int stackSize, DataStructure dataStructure ) {
+ super(LevelingDownsamplerUniformStacksTest.class);
+
+ this.targetSize = targetSize;
+ this.numStacks = numStacks;
+ this.stackSize = stackSize;
+ this.dataStructure = dataStructure;
+ expectedSize = calculateExpectedDownsampledStackSize();
+
+ setName(String.format("%s: targetSize=%d numStacks=%d stackSize=%d dataStructure=%s expectedSize=%d",
+ getClass().getSimpleName(), targetSize, numStacks, stackSize, dataStructure, expectedSize));
+ }
+
+ public Collection<List<Object>> createStacks() {
+ Collection<List<Object>> stacks = new ArrayList<List<Object>>();
+
+ for ( int i = 1; i <= numStacks; i++ ) {
+ List<Object> stack = dataStructure == DataStructure.LINKED_LIST ? new LinkedList<Object>() : new ArrayList<Object>();
+
+ for ( int j = 1; j <= stackSize; j++ ) {
+ stack.add(new Object());
+ }
+
+ stacks.add(stack);
+ }
+
+ return stacks;
+ }
+
+ private int calculateExpectedDownsampledStackSize() {
+ int numItemsToRemove = numStacks * stackSize - targetSize;
+
+ if ( numStacks == 0 ) {
+ return 0;
+ }
+ else if ( numItemsToRemove <= 0 ) {
+ return stackSize;
+ }
+
+ return Math.max(1, stackSize - (numItemsToRemove / numStacks));
+ }
+ }
+
+ @DataProvider(name = "UniformStacksDataProvider")
+ public Object[][] createUniformStacksTestData() {
+ for ( int targetSize = 1; targetSize <= 10000; targetSize *= 10 ) {
+ for ( int numStacks = 0; numStacks <= 10; numStacks++ ) {
+ for ( int stackSize = 1; stackSize <= 1000; stackSize *= 10 ) {
+ for ( LevelingDownsamplerUniformStacksTest.DataStructure dataStructure : LevelingDownsamplerUniformStacksTest.DataStructure.values() ) {
+ new LevelingDownsamplerUniformStacksTest(targetSize, numStacks, stackSize, dataStructure);
+ }
+ }
+ }
+ }
+
+ return LevelingDownsamplerUniformStacksTest.getTests(LevelingDownsamplerUniformStacksTest.class);
+ }
+
+ @Test( dataProvider = "UniformStacksDataProvider" )
+ public void testLevelingDownsamplerWithUniformStacks( LevelingDownsamplerUniformStacksTest test ) {
+ logger.warn("Running test: " + test);
+
+ GenomeAnalysisEngine.resetRandomGenerator();
+
+ Downsampler<List<Object>> downsampler = new LevelingDownsampler<List<Object>, Object>(test.targetSize);
+
+ downsampler.submit(test.createStacks());
+
+ if ( test.numStacks > 0 ) {
+ Assert.assertFalse(downsampler.hasFinalizedItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null);
+ Assert.assertTrue(downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekPending() != null);
+ }
+ else {
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+ }
+
+ downsampler.signalEndOfInput();
+
+ if ( test.numStacks > 0 ) {
+ Assert.assertTrue(downsampler.hasFinalizedItems());
+ Assert.assertTrue(downsampler.peekFinalized() != null);
+ Assert.assertFalse(downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekPending() == null);
+ }
+ else {
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+ }
+
+ final int sizeFromDownsampler = downsampler.size();
+ List<List<Object>> downsampledStacks = downsampler.consumeFinalizedItems();
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+
+ Assert.assertEquals(downsampledStacks.size(), test.numStacks);
+
+ int totalRemainingItems = 0;
+ for ( List<Object> stack : downsampledStacks ) {
+ Assert.assertTrue(Math.abs(stack.size() - test.expectedSize) <= 1);
+ totalRemainingItems += stack.size();
+ }
+
+ Assert.assertEquals(sizeFromDownsampler, totalRemainingItems);
+ int numItemsReportedDiscarded = downsampler.getNumberOfDiscardedItems();
+ int numItemsActuallyDiscarded = test.numStacks * test.stackSize - totalRemainingItems;
+
+ Assert.assertEquals(numItemsReportedDiscarded, numItemsActuallyDiscarded);
+
+ downsampler.resetStats();
+ Assert.assertEquals(downsampler.getNumberOfDiscardedItems(), 0);
+
+ Assert.assertTrue(totalRemainingItems <= Math.max(test.targetSize, test.numStacks));
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/PerSampleDownsamplingReadsIteratorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/PerSampleDownsamplingReadsIteratorUnitTest.java
new file mode 100644
index 0000000..2606a01
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/PerSampleDownsamplingReadsIteratorUnitTest.java
@@ -0,0 +1,299 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMReadGroupRecord;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import org.broadinstitute.gatk.engine.iterators.VerifyingSamIterator;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.sam.ArtificialMultiSampleReadStream;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.ArtificialSingleSampleReadStream;
+import org.broadinstitute.gatk.utils.sam.ArtificialSingleSampleReadStreamAnalyzer;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+public class PerSampleDownsamplingReadsIteratorUnitTest extends BaseTest {
+
+ private static class PerSampleDownsamplingReadsIteratorTest extends TestDataProvider {
+
+ // TODO: tests should distinguish between variance across samples and variance within a sample
+
+ private enum StreamDensity {
+ SPARSE (MAX_READ_LENGTH, MAX_READ_LENGTH * 2),
+ DENSE (1, MIN_READ_LENGTH),
+ MIXED (1, MAX_READ_LENGTH * 2),
+ UNIFORM_DENSE (1, 1),
+ UNIFORM_SPARSE (MAX_READ_LENGTH * 2, MAX_READ_LENGTH * 2);
+
+ int minDistanceBetweenStacks;
+ int maxDistanceBetweenStacks;
+
+ StreamDensity( int minDistanceBetweenStacks, int maxDistanceBetweenStacks ) {
+ this.minDistanceBetweenStacks = minDistanceBetweenStacks;
+ this.maxDistanceBetweenStacks = maxDistanceBetweenStacks;
+ }
+
+ public String toString() {
+ return String.format("StreamDensity:%d-%d", minDistanceBetweenStacks, maxDistanceBetweenStacks);
+ }
+ }
+
+ private enum StreamStackDepth {
+ NON_UNIFORM_LOW (1, 5),
+ NON_UNIFORM_HIGH (15, 20),
+ NON_UNIFORM_MIXED (1, 20),
+ UNIFORM_SINGLE (1, 1),
+ UNIFORM_LOW (2, 2),
+ UNIFORM_HIGH (20, 20),
+ UNIFORM_MEDIUM (10, 10); // should set target coverage to this value for testing
+
+ int minReadsPerStack;
+ int maxReadsPerStack;
+
+ StreamStackDepth( int minReadsPerStack, int maxReadsPerStack ) {
+ this.minReadsPerStack = minReadsPerStack;
+ this.maxReadsPerStack = maxReadsPerStack;
+ }
+
+ public boolean isUniform() {
+ return minReadsPerStack == maxReadsPerStack;
+ }
+
+ public String toString() {
+ return String.format("StreamStackDepth:%d-%d", minReadsPerStack, maxReadsPerStack);
+ }
+ }
+
+ private enum StreamStacksPerContig {
+ UNIFORM(20, 20),
+ NON_UNIFORM(1, 30);
+
+ int minStacksPerContig;
+ int maxStacksPerContig;
+
+ StreamStacksPerContig( int minStacksPerContig, int maxStacksPerContig ) {
+ this.minStacksPerContig = minStacksPerContig;
+ this.maxStacksPerContig = maxStacksPerContig;
+ }
+
+ public boolean isUniform() {
+ return minStacksPerContig == maxStacksPerContig;
+ }
+
+ public String toString() {
+ return String.format("StreamStacksPerContig:%d-%d", minStacksPerContig, maxStacksPerContig);
+ }
+ }
+
+ // Not interested in testing multiple ranges for the read lengths, as none of our current
+ // downsamplers are affected by read length
+ private static final int MIN_READ_LENGTH = 50;
+ private static final int MAX_READ_LENGTH = 150;
+
+ private ReadsDownsamplerFactory<SAMRecord> downsamplerFactory;
+ private int targetCoverage;
+ private int numSamples;
+ private int minContigs;
+ private int maxContigs;
+ private StreamDensity streamDensity;
+ private StreamStackDepth streamStackDepth;
+ private StreamStacksPerContig streamStacksPerContig;
+ private double unmappedReadsFraction;
+ private int unmappedReadsCount;
+ private boolean verifySortedness;
+
+ private ArtificialMultiSampleReadStream mergedReadStream;
+ private Map<String, ArtificialSingleSampleReadStream> perSampleArtificialReadStreams;
+ private Map<String, ArtificialSingleSampleReadStreamAnalyzer> perSampleStreamAnalyzers;
+ private SAMFileHeader header;
+
+ public PerSampleDownsamplingReadsIteratorTest( ReadsDownsamplerFactory<SAMRecord> downsamplerFactory,
+ int targetCoverage,
+ int numSamples,
+ int minContigs,
+ int maxContigs,
+ StreamDensity streamDensity,
+ StreamStackDepth streamStackDepth,
+ StreamStacksPerContig streamStacksPerContig,
+ double unmappedReadsFraction,
+ int unmappedReadsCount,
+ boolean verifySortedness ) {
+ super(PerSampleDownsamplingReadsIteratorTest.class);
+
+ this.downsamplerFactory = downsamplerFactory;
+ this.targetCoverage = targetCoverage;
+ this.numSamples = numSamples;
+ this.minContigs = minContigs;
+ this.maxContigs = maxContigs;
+ this.streamDensity = streamDensity;
+ this.streamStackDepth = streamStackDepth;
+ this.streamStacksPerContig = streamStacksPerContig;
+ this.unmappedReadsFraction = unmappedReadsFraction;
+ this.unmappedReadsCount = unmappedReadsCount;
+ this.verifySortedness = verifySortedness;
+
+ header = createHeader();
+ createReadStreams();
+
+ setName(String.format("%s: targetCoverage=%d numSamples=%d minContigs=%d maxContigs=%d %s %s %s unmappedReadsFraction=%.2f unmappedReadsCount=%d verifySortedness=%b",
+ getClass().getSimpleName(), targetCoverage, numSamples, minContigs, maxContigs, streamDensity, streamStackDepth, streamStacksPerContig, unmappedReadsFraction, unmappedReadsCount, verifySortedness));
+ }
+
+ private SAMFileHeader createHeader() {
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(maxContigs, 1, (streamDensity.maxDistanceBetweenStacks + MAX_READ_LENGTH) * streamStacksPerContig.maxStacksPerContig + 100000);
+ List<String> readGroups = new ArrayList<String>(numSamples);
+ List<String> sampleNames = new ArrayList<String>(numSamples);
+
+ for ( int i = 0; i < numSamples; i++ ) {
+ readGroups.add("ReadGroup" + i);
+ sampleNames.add("Sample" + i);
+ }
+
+ return ArtificialSAMUtils.createEnumeratedReadGroups(header, readGroups, sampleNames);
+ }
+
+ private void createReadStreams() {
+ perSampleArtificialReadStreams = new HashMap<String, ArtificialSingleSampleReadStream>(numSamples);
+ perSampleStreamAnalyzers = new HashMap<String, ArtificialSingleSampleReadStreamAnalyzer>(numSamples);
+
+ for (SAMReadGroupRecord readGroup : header.getReadGroups() ) {
+ String readGroupID = readGroup.getReadGroupId();
+ String sampleName = readGroup.getSample();
+
+ int thisSampleNumContigs = MathUtils.randomIntegerInRange(minContigs, maxContigs);
+ int thisSampleStacksPerContig = MathUtils.randomIntegerInRange(streamStacksPerContig.minStacksPerContig, streamStacksPerContig.maxStacksPerContig);
+
+ int thisSampleNumUnmappedReads = GenomeAnalysisEngine.getRandomGenerator().nextDouble() < unmappedReadsFraction ? unmappedReadsCount : 0;
+
+ ArtificialSingleSampleReadStream thisSampleStream = new ArtificialSingleSampleReadStream(header,
+ readGroupID,
+ thisSampleNumContigs,
+ thisSampleStacksPerContig,
+ streamStackDepth.minReadsPerStack,
+ streamStackDepth.maxReadsPerStack,
+ streamDensity.minDistanceBetweenStacks,
+ streamDensity.maxDistanceBetweenStacks,
+ MIN_READ_LENGTH,
+ MAX_READ_LENGTH,
+ thisSampleNumUnmappedReads);
+ perSampleArtificialReadStreams.put(sampleName, thisSampleStream);
+ perSampleStreamAnalyzers.put(sampleName, new PositionallyDownsampledArtificialSingleSampleReadStreamAnalyzer(thisSampleStream, targetCoverage));
+ }
+
+ mergedReadStream = new ArtificialMultiSampleReadStream(perSampleArtificialReadStreams.values());
+ }
+
+ public void run() {
+ GATKSAMIterator downsamplingIter = new PerSampleDownsamplingReadsIterator(mergedReadStream.getGATKSAMIterator(), downsamplerFactory);
+
+ if ( verifySortedness ) {
+ downsamplingIter = new VerifyingSamIterator(downsamplingIter);
+ }
+
+ while ( downsamplingIter.hasNext() ) {
+ SAMRecord read = downsamplingIter.next();
+ String sampleName = read.getReadGroup() != null ? read.getReadGroup().getSample() : null;
+
+ ArtificialSingleSampleReadStreamAnalyzer analyzer = perSampleStreamAnalyzers.get(sampleName);
+ if ( analyzer != null ) {
+ analyzer.update(read);
+ }
+ else {
+ throw new ReviewedGATKException("bug: stream analyzer for sample " + sampleName + " not found");
+ }
+ }
+
+ for ( Map.Entry<String, ArtificialSingleSampleReadStreamAnalyzer> analyzerEntry : perSampleStreamAnalyzers.entrySet() ) {
+ ArtificialSingleSampleReadStreamAnalyzer analyzer = analyzerEntry.getValue();
+ analyzer.finalizeStats();
+
+ // Validate the downsampled read stream for each sample individually
+ analyzer.validate();
+ }
+
+ // Allow memory used by this test to be reclaimed:
+ mergedReadStream = null;
+ perSampleArtificialReadStreams = null;
+ perSampleStreamAnalyzers = null;
+ }
+ }
+
+ @DataProvider(name = "PerSampleDownsamplingReadsIteratorTestDataProvider")
+ public Object[][] createPerSampleDownsamplingReadsIteratorTests() {
+
+ GenomeAnalysisEngine.resetRandomGenerator();
+
+ // Some values don't vary across tests
+ int targetCoverage = PerSampleDownsamplingReadsIteratorTest.StreamStackDepth.UNIFORM_MEDIUM.minReadsPerStack;
+ ReadsDownsamplerFactory<SAMRecord> downsamplerFactory = new SimplePositionalDownsamplerFactory<SAMRecord>(targetCoverage);
+ int maxContigs = 3;
+ boolean verifySortedness = true;
+
+ for ( int numSamples : Arrays.asList(1, 2, 10) ) {
+ for ( int minContigs = 1; minContigs <= maxContigs; minContigs++ ) {
+ for ( PerSampleDownsamplingReadsIteratorTest.StreamDensity streamDensity : PerSampleDownsamplingReadsIteratorTest.StreamDensity.values() ) {
+ for ( PerSampleDownsamplingReadsIteratorTest.StreamStackDepth streamStackDepth : PerSampleDownsamplingReadsIteratorTest.StreamStackDepth.values() ) {
+ for (PerSampleDownsamplingReadsIteratorTest.StreamStacksPerContig streamStacksPerContig : PerSampleDownsamplingReadsIteratorTest.StreamStacksPerContig.values() ) {
+ for ( double unmappedReadsFraction : Arrays.asList(0.0, 1.0, 0.5) ) {
+ for ( int unmappedReadsCount : Arrays.asList(1, 50) ) {
+ new PerSampleDownsamplingReadsIteratorTest(downsamplerFactory,
+ targetCoverage,
+ numSamples,
+ minContigs,
+ maxContigs,
+ streamDensity,
+ streamStackDepth,
+ streamStacksPerContig,
+ unmappedReadsFraction,
+ unmappedReadsCount,
+ verifySortedness);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return PerSampleDownsamplingReadsIteratorTest.getTests(PerSampleDownsamplingReadsIteratorTest.class);
+ }
+
+ @Test(dataProvider = "PerSampleDownsamplingReadsIteratorTestDataProvider")
+ public void runPerSampleDownsamplingReadsIteratorTest( PerSampleDownsamplingReadsIteratorTest test ) {
+ logger.warn("Running test: " + test);
+
+ GenomeAnalysisEngine.resetRandomGenerator();
+ test.run();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/PositionallyDownsampledArtificialSingleSampleReadStreamAnalyzer.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/PositionallyDownsampledArtificialSingleSampleReadStreamAnalyzer.java
new file mode 100644
index 0000000..b8a57e7
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/PositionallyDownsampledArtificialSingleSampleReadStreamAnalyzer.java
@@ -0,0 +1,127 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.sam.ArtificialSingleSampleReadStream;
+import org.broadinstitute.gatk.utils.sam.ArtificialSingleSampleReadStreamAnalyzer;
+
+/**
+ * Class for analyzing an artificial read stream that has been positionally downsampled, and verifying
+ * that the downsampling was done correctly without changing the stream in unexpected ways.
+ *
+ * @author David Roazen
+ */
+public class PositionallyDownsampledArtificialSingleSampleReadStreamAnalyzer extends ArtificialSingleSampleReadStreamAnalyzer {
+ private int targetCoverage;
+
+ public PositionallyDownsampledArtificialSingleSampleReadStreamAnalyzer( ArtificialSingleSampleReadStream originalStream, int targetCoverage ) {
+ super(originalStream);
+ this.targetCoverage = targetCoverage;
+ }
+
+ /**
+ * Overridden validate() method that checks for the effects of positional downsampling in addition to checking
+ * for whether the original properties of the stream not affected by downsampling have been preserved
+ */
+ @Override
+ public void validate() {
+ if ( (originalStream.getNumContigs() == 0 || originalStream.getNumStacksPerContig() == 0) && originalStream.getNumUnmappedReads() == 0 ) {
+ if ( totalReads != 0 ) {
+ throw new ReviewedGATKException("got reads from the stream, but the stream was configured to have 0 reads");
+ }
+ return; // no further validation needed for the 0-reads case
+ }
+ else if ( totalReads == 0 ) {
+ throw new ReviewedGATKException("got no reads from the stream, but the stream was configured to have > 0 reads");
+ }
+
+ if ( ! allSamplesMatch ) {
+ throw new ReviewedGATKException("some reads had the wrong sample");
+ }
+
+ if ( numContigs != originalStream.getNumContigs() ) {
+ throw new ReviewedGATKException("number of contigs not correct");
+ }
+
+ if ( stacksPerContig.size() != originalStream.getNumContigs() ) {
+ throw new ReviewedGATKException(String.format("bug in analyzer code: calculated sizes for %d contigs even though there were only %d contigs",
+ stacksPerContig.size(), originalStream.getNumContigs()));
+ }
+
+ for ( int contigStackCount : stacksPerContig ) {
+ if ( contigStackCount != originalStream.getNumStacksPerContig() ) {
+ throw new ReviewedGATKException("contig had incorrect number of stacks");
+ }
+ }
+
+ if ( originalStream.getNumStacksPerContig() > 0 ) {
+
+ // Check for the effects of positional downsampling:
+ int stackMinimumAfterDownsampling = Math.min(targetCoverage, originalStream.getMinReadsPerStack());
+ int stackMaximumAfterDownsampling = targetCoverage;
+
+ if ( minReadsPerStack < stackMinimumAfterDownsampling ) {
+ throw new ReviewedGATKException("stack had fewer than the minimum number of reads after downsampling");
+ }
+ if ( maxReadsPerStack > stackMaximumAfterDownsampling ) {
+ throw new ReviewedGATKException("stack had more than the maximum number of reads after downsampling");
+ }
+ }
+ else if ( minReadsPerStack != null || maxReadsPerStack != null ) {
+ throw new ReviewedGATKException("bug in analyzer code: reads per stack was calculated even though 0 stacks per contig was specified");
+ }
+
+ if ( originalStream.getNumStacksPerContig() > 1 ) {
+ if ( minDistanceBetweenStacks < originalStream.getMinDistanceBetweenStacks() ) {
+ throw new ReviewedGATKException("stacks were separated by less than the minimum distance");
+ }
+ if ( maxDistanceBetweenStacks > originalStream.getMaxDistanceBetweenStacks() ) {
+ throw new ReviewedGATKException("stacks were separated by more than the maximum distance");
+ }
+ }
+ else if ( minDistanceBetweenStacks != null || maxDistanceBetweenStacks != null ) {
+ throw new ReviewedGATKException("bug in analyzer code: distance between stacks was calculated even though numStacksPerContig was <= 1");
+ }
+
+ if ( minReadLength < originalStream.getMinReadLength() ) {
+ throw new ReviewedGATKException("read was shorter than the minimum allowed length");
+ }
+ if ( maxReadLength > originalStream.getMaxReadLength() ) {
+ throw new ReviewedGATKException("read was longer than the maximum allowed length");
+ }
+
+ if ( numUnmappedReads != originalStream.getNumUnmappedReads() ) {
+ throw new ReviewedGATKException(String.format("wrong number of unmapped reads: requested %d but saw %d",
+ originalStream.getNumUnmappedReads(), numUnmappedReads));
+ }
+
+ if ( (originalStream.getNumContigs() == 0 || originalStream.getNumStacksPerContig() == 0) &&
+ numUnmappedReads != totalReads ) {
+ throw new ReviewedGATKException("stream should have consisted only of unmapped reads, but saw some mapped reads");
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/ReservoirDownsamplerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/ReservoirDownsamplerUnitTest.java
new file mode 100644
index 0000000..4e6f157
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/ReservoirDownsamplerUnitTest.java
@@ -0,0 +1,131 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public class ReservoirDownsamplerUnitTest extends BaseTest {
+
+ private static class ReservoirDownsamplerTest extends TestDataProvider {
+ int reservoirSize;
+ int totalReads;
+ int expectedNumReadsAfterDownsampling;
+ int expectedNumDiscardedItems;
+
+ public ReservoirDownsamplerTest( int reservoirSize, int totalReads ) {
+ super(ReservoirDownsamplerTest.class);
+
+ this.reservoirSize = reservoirSize;
+ this.totalReads = totalReads;
+
+ expectedNumReadsAfterDownsampling = Math.min(reservoirSize, totalReads);
+ expectedNumDiscardedItems = totalReads <= reservoirSize ? 0 : totalReads - reservoirSize;
+
+ setName(String.format("%s: reservoirSize=%d totalReads=%d expectedNumReadsAfterDownsampling=%d expectedNumDiscardedItems=%d",
+ getClass().getSimpleName(), reservoirSize, totalReads, expectedNumReadsAfterDownsampling, expectedNumDiscardedItems));
+ }
+
+ public Collection<SAMRecord> createReads() {
+ Collection<SAMRecord> reads = new ArrayList<SAMRecord>(totalReads);
+
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000000);
+ reads.addAll(ArtificialSAMUtils.createStackOfIdenticalArtificialReads(totalReads, header, "foo", 0, 1, 100));
+
+ return reads;
+ }
+ }
+
+ @DataProvider(name = "ReservoirDownsamplerTestDataProvider")
+ public Object[][] createReservoirDownsamplerTestData() {
+ for ( int reservoirSize = 1; reservoirSize <= 10000; reservoirSize *= 10 ) {
+ new ReservoirDownsamplerTest(reservoirSize, 0);
+ for ( int totalReads = 1; totalReads <= 10000; totalReads *= 10 ) {
+ new ReservoirDownsamplerTest(reservoirSize, totalReads);
+ }
+ }
+
+ return ReservoirDownsamplerTest.getTests(ReservoirDownsamplerTest.class);
+ }
+
+ @Test(dataProvider = "ReservoirDownsamplerTestDataProvider")
+ public void testReservoirDownsampler( ReservoirDownsamplerTest test ) {
+ logger.warn("Running test: " + test);
+
+ GenomeAnalysisEngine.resetRandomGenerator();
+
+ ReadsDownsampler<SAMRecord> downsampler = new ReservoirDownsampler<SAMRecord>(test.reservoirSize);
+
+ downsampler.submit(test.createReads());
+
+ if ( test.totalReads > 0 ) {
+ Assert.assertTrue(downsampler.hasFinalizedItems());
+ Assert.assertTrue(downsampler.peekFinalized() != null);
+ Assert.assertFalse(downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekPending() == null);
+ }
+ else {
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+ }
+
+ downsampler.signalEndOfInput();
+
+ if ( test.totalReads > 0 ) {
+ Assert.assertTrue(downsampler.hasFinalizedItems());
+ Assert.assertTrue(downsampler.peekFinalized() != null);
+ Assert.assertFalse(downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekPending() == null);
+ }
+ else {
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+ }
+
+ Assert.assertEquals(downsampler.size(), test.expectedNumReadsAfterDownsampling);
+ List<SAMRecord> downsampledReads = downsampler.consumeFinalizedItems();
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+
+ Assert.assertEquals(downsampledReads.size(), test.expectedNumReadsAfterDownsampling);
+
+ Assert.assertEquals(downsampler.getNumberOfDiscardedItems(), test.expectedNumDiscardedItems);
+ Assert.assertEquals(test.totalReads - downsampledReads.size(), test.expectedNumDiscardedItems);
+
+ downsampler.resetStats();
+ Assert.assertEquals(downsampler.getNumberOfDiscardedItems(), 0);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/SimplePositionalDownsamplerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/SimplePositionalDownsamplerUnitTest.java
new file mode 100644
index 0000000..e04c347
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/downsampling/SimplePositionalDownsamplerUnitTest.java
@@ -0,0 +1,331 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.downsampling;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.util.*;
+
+public class SimplePositionalDownsamplerUnitTest extends BaseTest {
+
+ private static class SimplePositionalDownsamplerTest extends TestDataProvider {
+ int targetCoverage;
+ int numStacks;
+ List<Integer> stackSizes;
+ List<Integer> expectedStackSizes;
+ boolean multipleContigs;
+ int totalInitialReads;
+
+ public SimplePositionalDownsamplerTest( int targetCoverage, List<Integer> stackSizes, boolean multipleContigs ) {
+ super(SimplePositionalDownsamplerTest.class);
+
+ this.targetCoverage = targetCoverage;
+ this.numStacks = stackSizes.size();
+ this.stackSizes = stackSizes;
+ this.multipleContigs = multipleContigs;
+
+ calculateExpectedDownsampledStackSizes();
+
+ totalInitialReads = 0;
+ for ( Integer stackSize : stackSizes ) {
+ totalInitialReads += stackSize;
+ }
+
+ setName(String.format("%s: targetCoverage=%d numStacks=%d stackSizes=%s expectedSizes=%s multipleContigs=%b",
+ getClass().getSimpleName(), targetCoverage, numStacks, stackSizes, expectedStackSizes, multipleContigs));
+ }
+
+ public Collection<SAMRecord> createReads() {
+ Collection<SAMRecord> reads = new ArrayList<SAMRecord>();
+ SAMFileHeader header = multipleContigs ?
+ ArtificialSAMUtils.createArtificialSamHeader(2, 1, 1000000) :
+ ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000000);
+
+ int refIndex = 0;
+ int alignmentStart = 1;
+ int readLength = 100;
+
+ for ( int i = 0; i < numStacks; i++ ) {
+ if ( multipleContigs && refIndex == 0 && i >= numStacks / 2 ) {
+ refIndex++;
+ }
+
+ reads.addAll(ArtificialSAMUtils.createStackOfIdenticalArtificialReads(stackSizes.get(i), header, "foo",
+ refIndex, alignmentStart, readLength));
+
+ alignmentStart += 10;
+ }
+
+ return reads;
+ }
+
+ private void calculateExpectedDownsampledStackSizes() {
+ expectedStackSizes = new ArrayList<Integer>(numStacks);
+
+ for ( Integer stackSize : stackSizes ) {
+ int expectedSize = targetCoverage >= stackSize ? stackSize : targetCoverage;
+ expectedStackSizes.add(expectedSize);
+ }
+ }
+ }
+
+ @DataProvider(name = "SimplePositionalDownsamplerTestDataProvider")
+ public Object[][] createSimplePositionalDownsamplerTestData() {
+ GenomeAnalysisEngine.resetRandomGenerator();
+
+ for ( int targetCoverage = 1; targetCoverage <= 10000; targetCoverage *= 10 ) {
+ for ( int contigs = 1; contigs <= 2; contigs++ ) {
+ for ( int numStacks = 0; numStacks <= 10; numStacks++ ) {
+ List<Integer> stackSizes = new ArrayList<Integer>(numStacks);
+ for ( int stack = 1; stack <= numStacks; stack++ ) {
+ stackSizes.add(GenomeAnalysisEngine.getRandomGenerator().nextInt(targetCoverage * 2) + 1);
+ }
+ new SimplePositionalDownsamplerTest(targetCoverage, stackSizes, contigs > 1);
+ }
+ }
+ }
+
+ return SimplePositionalDownsamplerTest.getTests(SimplePositionalDownsamplerTest.class);
+ }
+
+ @Test( dataProvider = "SimplePositionalDownsamplerTestDataProvider" )
+ public void testSimplePostionalDownsampler( SimplePositionalDownsamplerTest test ) {
+ logger.warn("Running test: " + test);
+
+ GenomeAnalysisEngine.resetRandomGenerator();
+
+ ReadsDownsampler<SAMRecord> downsampler = new SimplePositionalDownsampler<SAMRecord>(test.targetCoverage);
+
+ downsampler.submit(test.createReads());
+
+ if ( test.numStacks > 1 ) {
+ Assert.assertTrue(downsampler.hasFinalizedItems());
+ Assert.assertTrue(downsampler.peekFinalized() != null);
+ Assert.assertTrue(downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekPending() != null);
+ }
+ else if ( test.numStacks == 1 ) {
+ Assert.assertFalse(downsampler.hasFinalizedItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null);
+ Assert.assertTrue(downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekPending() != null);
+ }
+ else {
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+ }
+
+ downsampler.signalEndOfInput();
+
+ if ( test.numStacks > 0 ) {
+ Assert.assertTrue(downsampler.hasFinalizedItems());
+ Assert.assertTrue(downsampler.peekFinalized() != null);
+ Assert.assertFalse(downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekPending() == null);
+ }
+ else {
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+ }
+
+ List<SAMRecord> downsampledReads = downsampler.consumeFinalizedItems();
+ Assert.assertFalse(downsampler.hasFinalizedItems() || downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null && downsampler.peekPending() == null);
+
+ if ( test.numStacks == 0 ) {
+ Assert.assertTrue(downsampledReads.isEmpty());
+ }
+ else {
+ List<Integer> downsampledStackSizes = getDownsampledStackSizesAndVerifySortedness(downsampledReads);
+
+ Assert.assertEquals(downsampledStackSizes.size(), test.numStacks);
+ Assert.assertEquals(downsampledStackSizes, test.expectedStackSizes);
+
+ int numReadsActuallyEliminated = test.totalInitialReads - downsampledReads.size();
+ int numReadsReportedEliminated = downsampler.getNumberOfDiscardedItems();
+ Assert.assertEquals(numReadsActuallyEliminated, numReadsReportedEliminated);
+ }
+
+ downsampler.resetStats();
+ Assert.assertEquals(downsampler.getNumberOfDiscardedItems(), 0);
+ }
+
+ private List<Integer> getDownsampledStackSizesAndVerifySortedness( List<SAMRecord> downsampledReads ) {
+ List<Integer> stackSizes = new ArrayList<Integer>();
+
+ if ( downsampledReads.isEmpty() ) {
+ return stackSizes;
+ }
+
+ Iterator<SAMRecord> iter = downsampledReads.iterator();
+ Assert.assertTrue(iter.hasNext());
+
+ SAMRecord previousRead = iter.next();
+ int currentStackSize = 1;
+
+ while ( iter.hasNext() ) {
+ SAMRecord currentRead = iter.next();
+
+ if ( currentRead.getReferenceIndex() > previousRead.getReferenceIndex() || currentRead.getAlignmentStart() > previousRead.getAlignmentStart() ) {
+ stackSizes.add(currentStackSize);
+ currentStackSize = 1;
+ }
+ else if ( currentRead.getReferenceIndex() < previousRead.getReferenceIndex() || currentRead.getAlignmentStart() < previousRead.getAlignmentStart() ) {
+ Assert.fail(String.format("Reads are out of order: %s %s", previousRead, currentRead));
+ }
+ else {
+ currentStackSize++;
+ }
+
+ previousRead = currentRead;
+ }
+
+ stackSizes.add(currentStackSize);
+ return stackSizes;
+ }
+
+ @Test
+ public void testSimplePositionalDownsamplerSignalNoMoreReadsBefore() {
+ ReadsDownsampler<SAMRecord> downsampler = new SimplePositionalDownsampler<SAMRecord>(1000);
+
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000000);
+
+ Collection<SAMRecord> readStack = new ArrayList<SAMRecord>();
+ readStack.addAll(ArtificialSAMUtils.createStackOfIdenticalArtificialReads(50, header, "foo", 0, 1, 100));
+ downsampler.submit(readStack);
+
+ Assert.assertFalse(downsampler.hasFinalizedItems());
+ Assert.assertTrue(downsampler.peekFinalized() == null);
+ Assert.assertTrue(downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekPending() != null);
+
+ SAMRecord laterRead = ArtificialSAMUtils.createArtificialRead(header, "foo", 0, 2, 100);
+ downsampler.signalNoMoreReadsBefore(laterRead);
+
+ Assert.assertTrue(downsampler.hasFinalizedItems());
+ Assert.assertTrue(downsampler.peekFinalized() != null);
+ Assert.assertFalse(downsampler.hasPendingItems());
+ Assert.assertTrue(downsampler.peekPending() == null);
+
+ List<SAMRecord> downsampledReads = downsampler.consumeFinalizedItems();
+
+ Assert.assertEquals(downsampledReads.size(), readStack.size());
+ }
+
+ @Test
+ public void testBasicUnmappedReadsSupport() {
+ ReadsDownsampler<SAMRecord> downsampler = new SimplePositionalDownsampler<SAMRecord>(100);
+
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000000);
+
+ Collection<SAMRecord> readStack = new ArrayList<SAMRecord>();
+ readStack.addAll(ArtificialSAMUtils.createStackOfIdenticalArtificialReads(200, header, "foo", SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX,
+ SAMRecord.NO_ALIGNMENT_START, 100));
+ for ( SAMRecord read : readStack ) {
+ Assert.assertTrue(read.getReadUnmappedFlag());
+ }
+
+ downsampler.submit(readStack);
+ downsampler.signalEndOfInput();
+
+ List<SAMRecord> downsampledReads = downsampler.consumeFinalizedItems();
+
+ // Unmapped reads should not get downsampled at all by the SimplePositionalDownsampler
+ Assert.assertEquals(downsampledReads.size(), readStack.size());
+
+ for ( SAMRecord read: downsampledReads ) {
+ Assert.assertTrue(read.getReadUnmappedFlag());
+ }
+ }
+
+ @Test
+ public void testMixedMappedAndUnmappedReadsSupport() {
+ ReadsDownsampler<SAMRecord> downsampler = new SimplePositionalDownsampler<SAMRecord>(100);
+
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000000);
+
+ Collection<SAMRecord> mappedReadStack = new ArrayList<SAMRecord>();
+ mappedReadStack.addAll(ArtificialSAMUtils.createStackOfIdenticalArtificialReads(200, header, "foo", 0, 1, 100));
+ for ( SAMRecord read : mappedReadStack ) {
+ Assert.assertFalse(read.getReadUnmappedFlag());
+ }
+
+ Collection<SAMRecord> unmappedReadStack = new ArrayList<SAMRecord>();
+ unmappedReadStack.addAll(ArtificialSAMUtils.createStackOfIdenticalArtificialReads(200, header, "foo", SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX,
+ SAMRecord.NO_ALIGNMENT_START, 100));
+ for ( SAMRecord read : unmappedReadStack ) {
+ Assert.assertTrue(read.getReadUnmappedFlag());
+ }
+
+ downsampler.submit(mappedReadStack);
+ downsampler.submit(unmappedReadStack);
+ downsampler.signalEndOfInput();
+
+ List<SAMRecord> downsampledReads = downsampler.consumeFinalizedItems();
+
+ // Unmapped reads should not get downsampled at all by the SimplePositionalDownsampler
+ Assert.assertEquals(downsampledReads.size(), 300);
+ Assert.assertEquals(downsampler.getNumberOfDiscardedItems(), 100);
+
+ int count = 1;
+ for ( SAMRecord read: downsampledReads ) {
+ if ( count <= 100 ) {
+ Assert.assertFalse(read.getReadUnmappedFlag());
+ }
+ else {
+ Assert.assertTrue(read.getReadUnmappedFlag());
+ }
+
+ count++;
+ }
+ }
+
+ @Test
+ public void testGATKSAMRecordSupport() {
+ ReadsDownsampler<GATKSAMRecord> downsampler = new SimplePositionalDownsampler<GATKSAMRecord>(1000);
+
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000000);
+
+ List<GATKSAMRecord> reads = new ArrayList<GATKSAMRecord>();
+ for ( int i = 0; i < 10; i++ ) {
+ reads.add(ArtificialSAMUtils.createArtificialRead(header, "foo", 0, 10, 20 * i + 10));
+ }
+
+ downsampler.submit(reads);
+ downsampler.signalEndOfInput();
+ List<GATKSAMRecord> downsampledReads = downsampler.consumeFinalizedItems();
+
+ Assert.assertEquals(downsampledReads.size(), 10);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/executive/ReduceTreeUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/executive/ReduceTreeUnitTest.java
new file mode 100644
index 0000000..50f21a6
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/executive/ReduceTreeUnitTest.java
@@ -0,0 +1,254 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.executive;
+
+
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ExecutionException;
+import java.util.List;
+import java.util.ArrayList;
+/**
+ * User: hanna
+ * Date: Apr 29, 2009
+ * Time: 10:40:49 AM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Make sure the reduce tree organizes reduces in the correct way.
+ */
+
+public class ReduceTreeUnitTest extends BaseTest implements ReduceTree.TreeReduceNotifier {
+
+ /**
+ * The tree indicating reduce order.
+ */
+ private ReduceTree reduceTree = null;
+
+ /**
+ *
+ */
+ private List<List<Integer>> reduces = new ArrayList<List<Integer>>();
+
+ @BeforeMethod
+ public void createTree() {
+ reduceTree = new ReduceTree( this );
+ }
+
+ @AfterMethod
+ public void destroyTree() {
+ reduceTree = null;
+ reduces.clear();
+ }
+
+ @Test
+ public void testNoValueReduce()
+ throws InterruptedException, ExecutionException {
+ reduceTree.complete();
+ Assert.assertEquals(reduceTree.getResult(), null, "Single-value reduce failed");
+ }
+
+ @Test
+ public void testSingleValueReduce()
+ throws InterruptedException, ExecutionException {
+ reduceTree.addEntry( getReduceTestEntry(1) );
+ reduceTree.complete();
+ Assert.assertEquals(reduceTree.getResult().get(), 1, "Single-value reduce failed");
+ }
+
+ @Test(expectedExceptions=IllegalStateException.class)
+ public void testIncompleteReduce()
+ throws InterruptedException, ExecutionException {
+ reduceTree.addEntry( getReduceTestEntry(1) );
+ reduceTree.getResult().get();
+ }
+
+ @Test
+ public void testDualValueReduce()
+ throws InterruptedException, ExecutionException {
+ reduceTree.addEntry( getReduceTestEntry(1) );
+ reduceTree.addEntry( getReduceTestEntry(2) );
+ reduceTree.complete();
+
+ List<Integer> expected = new ArrayList<Integer>();
+ expected.add( 1 );
+ expected.add( 2 );
+
+ // Test the result
+ Assert.assertEquals(reduceTree.getResult().get(), expected, "Dual-value reduce failed");
+
+ // Test the intermediate steps
+ Assert.assertEquals(reduces.size(), 1, "Size of incoming tree reduces incorrect");
+ Assert.assertEquals(reduces.get(0), expected, "Incoming tree reduce incorrect");
+ }
+
+ @Test
+ public void testThreeValueReduce()
+ throws InterruptedException, ExecutionException {
+ List<Integer> firstExpected = new ArrayList<Integer>();
+ firstExpected.add(1);
+ firstExpected.add(2);
+
+ List<Integer> finalExpected = new ArrayList<Integer>();
+ finalExpected.addAll( firstExpected );
+ finalExpected.add(3);
+
+ reduceTree.addEntry( getReduceTestEntry(1) );
+
+ Assert.assertEquals(reduces.size(), 0, "Reduce queue should be empty after entering a single element");
+
+ reduceTree.addEntry( getReduceTestEntry(2) );
+
+ Assert.assertEquals(reduces.size(), 1, "Reduce queue should have one element after two entries");
+ Assert.assertEquals(reduces.get(0), firstExpected, "Reduce queue element is incorrect after two entries");
+
+ reduceTree.addEntry( getReduceTestEntry(3) );
+
+ Assert.assertEquals(reduces.size(), 1, "Reduce queue should have one element after three entries");
+ Assert.assertEquals(reduces.get(0), firstExpected, "Reduce queue element is incorrect after three entries");
+
+ reduceTree.complete();
+
+ // Test the result
+ Assert.assertEquals(reduceTree.getResult().get(), finalExpected, "Three value reduce failed");
+
+ Assert.assertEquals(reduces.size(), 2, "Reduce queue should have two elements after three entries (complete)");
+ Assert.assertEquals(reduces.get(0), firstExpected, "Reduce queue element is incorrect after three entries");
+ Assert.assertEquals(reduces.get(1), finalExpected, "Reduce queue element is incorrect after three entries");
+ }
+
+ @Test
+ public void testFourValueReduce()
+ throws InterruptedException, ExecutionException {
+ List<Integer> lhsExpected = new ArrayList<Integer>();
+ lhsExpected.add(1);
+ lhsExpected.add(2);
+
+ List<Integer> rhsExpected = new ArrayList<Integer>();
+ rhsExpected.add(3);
+ rhsExpected.add(4);
+
+ List<Integer> finalExpected = new ArrayList<Integer>();
+ finalExpected.addAll(lhsExpected);
+ finalExpected.addAll(rhsExpected);
+
+ reduceTree.addEntry( getReduceTestEntry(1) );
+
+ Assert.assertEquals(reduces.size(), 0, "Reduce queue should be empty after entering a single element");
+
+ reduceTree.addEntry( getReduceTestEntry(2) );
+
+ Assert.assertEquals(reduces.size(), 1, "Reduce queue should have one element after two entries");
+ Assert.assertEquals(reduces.get(0), lhsExpected, "Reduce queue element is incorrect after two entries");
+
+ reduceTree.addEntry( getReduceTestEntry(3) );
+
+ Assert.assertEquals(reduces.size(), 1, "Reduce queue should have one element after three entries");
+ Assert.assertEquals(reduces.get(0), lhsExpected, "Reduce queue element is incorrect after three entries");
+
+ reduceTree.addEntry( getReduceTestEntry(4) );
+
+ Assert.assertEquals(reduces.size(), 3, "Reduce queue should have three elements after four entries");
+ Assert.assertEquals(reduces.get(0), lhsExpected, "Reduce queue element 0 is incorrect after three entries");
+ Assert.assertEquals(reduces.get(1), rhsExpected, "Reduce queue element 1 is incorrect after three entries");
+ Assert.assertEquals(reduces.get(2), finalExpected, "Reduce queue element 2 is incorrect after three entries");
+
+ reduceTree.complete();
+
+ // Test the result
+ Assert.assertEquals(reduceTree.getResult().get(), finalExpected, "Four-valued reduce failed");
+
+ // Test the working tree
+ Assert.assertEquals(reduces.size(), 3, "Didn't see correct number of reduces");
+ Assert.assertEquals(reduces.get(0), lhsExpected, "lhs of four value reduce failed");
+ Assert.assertEquals(reduces.get(1), rhsExpected, "rhs of four value reduce failed");
+ Assert.assertEquals(reduces.get(2), finalExpected, "final value four value reduce failed");
+ }
+
+
+ private Future getReduceTestEntry( Object value ) {
+ // Create a task and run it, assuring that the tests won't block on a get.
+ FutureTask task = new FutureTask( new ReduceTestEntry( value ) );
+ task.run();
+ return task;
+ }
+
+ public Future notifyReduce( Future lhs, Future rhs ) {
+ List<Integer> reduce = new ArrayList<Integer>();
+
+ try {
+ if( lhs == null && rhs == null )
+ throw new IllegalStateException("lhs and rhs are null");
+
+ if( lhs.get() instanceof List )
+ reduce.addAll((List)lhs.get());
+ else
+ reduce.add((Integer)lhs.get());
+
+ if( rhs != null ) {
+ if( rhs.get() instanceof List )
+ reduce.addAll((List)rhs.get());
+ else
+ reduce.add((Integer)rhs.get());
+ }
+ }
+ catch( Exception ex ) {
+ // just rethrow any exceptions
+ throw new RuntimeException(ex);
+ }
+
+ reduces.add( reduce );
+
+ return getReduceTestEntry( reduce );
+ }
+
+ private class ReduceTestEntry implements Callable {
+ private Object data;
+
+ public ReduceTestEntry( Object data ) {
+ this.data = data;
+ }
+
+ public Object call() {
+ return data;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/AllowNCigarMalformedReadFilterUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/AllowNCigarMalformedReadFilterUnitTest.java
new file mode 100644
index 0000000..7a01220
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/AllowNCigarMalformedReadFilterUnitTest.java
@@ -0,0 +1,77 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.Collections;
+
+
+/**
+ * Tests for the {@link MalformedReadFilter} when the unsafe flag
+ * {@link ValidationExclusion.TYPE#ALLOW_N_CIGAR_READS} is set.
+ *
+ * @author Valentin Ruano-Rubio
+ * @since 6/6/13
+ */
+public class AllowNCigarMalformedReadFilterUnitTest extends MalformedReadFilterUnitTest {
+
+
+ @Override
+ protected ValidationExclusion composeValidationExclusion() {
+ return new ValidationExclusion(Collections.singletonList(ValidationExclusion.TYPE.ALLOW_N_CIGAR_READS));
+ }
+
+
+ @Test(enabled = true,
+ dataProvider= "UnsupportedCigarOperatorDataProvider")
+ @CigarOperatorTest(CigarOperatorTest.Outcome.IGNORE)
+ public void testCigarNOperatorFilterIgnore(final String cigarString) {
+
+ final MalformedReadFilter filter = buildMalformedReadFilter(false);
+ final SAMRecord nContainingCigarRead = buildSAMRecord(cigarString);
+ Assert.assertFalse(filter.filterOut(nContainingCigarRead),
+ "filters out N containing Cigar when it should ignore the fact");
+ }
+
+ @Test(enabled = false)
+ @Override
+ public void testCigarNOperatorFilterException(final String cigarString) {
+ // Nothing to do here.
+ // Just deactivates the parents test case.
+ }
+
+
+
+
+
+
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/BadCigarFilterUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/BadCigarFilterUnitTest.java
new file mode 100644
index 0000000..bdb194c
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/BadCigarFilterUnitTest.java
@@ -0,0 +1,91 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.Cigar;
+import org.broadinstitute.gatk.utils.clipping.ReadClipperTestUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+/**
+ * Checks that the Bad Cigar filter works for all kinds of wonky cigars
+ *
+ * @author Mauricio Carneiro
+ * @since 3/20/12
+ */
+public class BadCigarFilterUnitTest {
+
+ public static final String[] BAD_CIGAR_LIST = {
+ "2D4M", // starting with multiple deletions
+ "4M2D", // ending with multiple deletions
+ "3M1I1D", // adjacent indels AND ends in deletion
+ "1M1I1D2M", // adjacent indels I->D
+ "1M1D2I1M", // adjacent indels D->I
+ "1M1I2M1D", // ends in single deletion with insertion in the middle
+ "4M1D", // ends in single deletion
+ "1D4M", // starts with single deletion
+ "2M1D1D2M", // adjacent D's
+ "1M1I1I1M", // adjacent I's
+ "1H1D4M", // starting with deletion after H
+ "1S1D3M", // starting with deletion after S
+ "1H1S1D3M", // starting with deletion after HS
+ "4M1D1H", // ending with deletion before H
+ "3M1D1S", // ending with deletion before S
+ "3M1D1S1H", // ending with deletion before HS
+ "10M2H10M", // H in the middle
+ "10M2S10M", // S in the middle
+ "1H1S10M2S10M1S1H", // deceiving S in the middle
+ "1H1S10M2H10M1S1H" // deceiving H in the middle
+ };
+
+ BadCigarFilter filter;
+
+ @BeforeClass
+ public void init() {
+ filter = new BadCigarFilter();
+ }
+
+ @Test(enabled = true)
+ public void testWonkyCigars () {
+ for (String cigarString : BAD_CIGAR_LIST) {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigarString);
+ Assert.assertTrue(filter.filterOut(read), read.getCigarString());
+ }
+ }
+
+ @Test(enabled = true)
+ public void testGoodCigars() {
+ List<Cigar> cigarList = ReadClipperTestUtils.generateCigarList(10);
+ for (Cigar cigar : cigarList) {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ Assert.assertFalse(filter.filterOut(read), read.getCigarString());
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/BadReadGroupsIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/BadReadGroupsIntegrationTest.java
new file mode 100644
index 0000000..3ff8ed4
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/BadReadGroupsIntegrationTest.java
@@ -0,0 +1,52 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.annotations.Test;
+
+
+public class BadReadGroupsIntegrationTest extends WalkerTest {
+
+ @Test
+ public void testMissingReadGroup() {
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T PrintReads -R " + b36KGReference + " -I " + privateTestDir + "missingReadGroup.bam -o /dev/null",
+ 0,
+ UserException.ReadMissingReadGroup.class);
+ executeTest("test Missing Read Group", spec);
+ }
+
+ @Test
+ public void testUndefinedReadGroup() {
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T PrintReads -R " + b36KGReference + " -I " + privateTestDir + "undefinedReadGroup.bam -o /dev/null",
+ 0,
+ UserException.ReadHasUndefinedReadGroup.class);
+ executeTest("test Undefined Read Group", spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/MalformedReadFilterUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/MalformedReadFilterUnitTest.java
new file mode 100644
index 0000000..d25db50
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/MalformedReadFilterUnitTest.java
@@ -0,0 +1,246 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.TextCigarCodec;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMDataSource;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.exceptions.UserException.UnsupportedCigarOperatorException;
+
+import java.lang.annotation.*;
+import java.lang.reflect.Method;
+import java.util.*;
+
+
+/**
+ * Tests for the MalformedReadFilter
+ *
+ * @author Eric Banks
+ * @since 3/14/13
+ */
+public class MalformedReadFilterUnitTest extends ReadFilterTest {
+
+ //////////////////////////////////////
+ // Test the checkSeqStored() method //
+ //////////////////////////////////////
+
+ @Test(enabled = true)
+ public void testCheckSeqStored () {
+
+ final GATKSAMRecord goodRead = ArtificialSAMUtils.createArtificialRead(new byte[]{(byte)'A'}, new byte[]{(byte)'A'}, "1M");
+ final GATKSAMRecord badRead = ArtificialSAMUtils.createArtificialRead(new byte[]{}, new byte[]{}, "1M");
+ badRead.setReadString("*");
+
+ Assert.assertTrue(MalformedReadFilter.checkSeqStored(goodRead, true));
+ Assert.assertFalse(MalformedReadFilter.checkSeqStored(badRead, true));
+
+ try {
+ MalformedReadFilter.checkSeqStored(badRead, false);
+ Assert.assertTrue(false, "We should have exceptioned out in the previous line");
+ } catch (UserException e) { }
+ }
+
+ @Test(enabled = true, dataProvider= "UnsupportedCigarOperatorDataProvider")
+ @CigarOperatorTest(CigarOperatorTest.Outcome.FILTER)
+ public void testCigarNOperatorFilterTruePositive(String cigarString) {
+
+ final MalformedReadFilter filter = buildMalformedReadFilter(true);
+ final SAMRecord nContainingCigarRead = buildSAMRecord(cigarString);
+ Assert.assertTrue(filter.filterOut(nContainingCigarRead),
+ " Did not filtered out a N containing CIGAR read");
+ }
+
+ @Test(enabled = true, dataProvider= "UnsupportedCigarOperatorDataProvider")
+ @CigarOperatorTest(CigarOperatorTest.Outcome.ACCEPT)
+ public void testCigarNOperatorFilterTrueNegative(String cigarString) {
+
+ final MalformedReadFilter filter = buildMalformedReadFilter(true);
+ final SAMRecord nonNContainingCigarRead = buildSAMRecord(cigarString);
+ Assert.assertFalse(filter.filterOut(nonNContainingCigarRead),
+ " Filtered out a non-N containing CIGAR read");
+ }
+
+ @Test(enabled = true,
+ expectedExceptions = UnsupportedCigarOperatorException.class,
+ dataProvider= "UnsupportedCigarOperatorDataProvider")
+ @CigarOperatorTest(CigarOperatorTest.Outcome.EXCEPTION)
+ public void testCigarNOperatorFilterException(final String cigarString) {
+
+ final MalformedReadFilter filter = buildMalformedReadFilter(false);
+ final SAMRecord nContainingCigarRead = buildSAMRecord(cigarString);
+
+ filter.filterOut(nContainingCigarRead);
+ }
+
+ @Test(enabled = true, dataProvider="UnsupportedCigarOperatorDataProvider")
+ @CigarOperatorTest(CigarOperatorTest.Outcome.ACCEPT)
+ public void testCigarNOperatorFilterControl(final String cigarString) {
+
+ final MalformedReadFilter filter = buildMalformedReadFilter(false);
+ final SAMRecord nonNContainingCigarRead = buildSAMRecord(cigarString);
+
+ Assert.assertFalse(filter.filterOut(nonNContainingCigarRead));
+ }
+
+ protected SAMRecord buildSAMRecord(final String cigarString) {
+ final Cigar nContainingCigar = TextCigarCodec.getSingleton().decode(cigarString);
+ return this.createRead(nContainingCigar, 1, 0, 10);
+ }
+
+ protected MalformedReadFilter buildMalformedReadFilter(final boolean filterRNO) {
+ return buildMalformedReadFiter(filterRNO,new ValidationExclusion.TYPE[] {});
+ }
+
+ protected MalformedReadFilter buildMalformedReadFiter(boolean filterRNO, final ValidationExclusion.TYPE... excl) {
+ final ValidationExclusion ve = new ValidationExclusion(Arrays.asList(excl));
+
+ final MalformedReadFilter filter = new MalformedReadFilter();
+
+ final SAMFileHeader h = getHeader();
+ final SAMDataSource ds = getDataSource();
+
+ final GenomeAnalysisEngine gae = new GenomeAnalysisEngine() {
+ @Override
+ public SAMFileHeader getSAMFileHeader() {
+ return h;
+ }
+
+ @Override
+ public SAMDataSource getReadsDataSource() {
+ return ds;
+ }
+ };
+ filter.initialize(gae);
+ filter.filterReadsWithNCigar = filterRNO;
+ return filter;
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target(ElementType.METHOD)
+ @Inherited
+ protected @interface CigarOperatorTest {
+
+ enum Outcome {
+ ANY,ACCEPT,FILTER,EXCEPTION,IGNORE;
+
+ public boolean appliesTo (String cigar) {
+ boolean hasN = cigar.indexOf('N') != -1;
+ switch (this) {
+ case ANY: return true;
+ case ACCEPT: return !hasN;
+ case IGNORE: return hasN;
+ case FILTER:
+ case EXCEPTION:
+ default:
+ return hasN;
+
+ }
+ }
+ }
+
+ Outcome value() default Outcome.ANY;
+ }
+
+ /**
+ * Cigar test data for unsupported operator test.
+ * Each element of this array corresponds to a test case. In turn the first element of the test case array is the
+ * Cigar string for that test case and the second indicates whether it should be filtered due to the presence of a
+ * unsupported operator
+ */
+ private static final String[] TEST_CIGARS = {
+ "101M10D20I10M",
+ "6M14N5M",
+ "1N",
+ "101M",
+ "110N",
+ "2N4M",
+ "4M2N",
+ "3M1I1M",
+ "1M2I2M",
+ "1M10N1I1M",
+ "1M1I1D",
+ "11N12M1I34M12N"
+ };
+
+ @DataProvider(name= "UnsupportedCigarOperatorDataProvider")
+ public Iterator<Object[]> unsupportedOperatorDataProvider(final Method testMethod) {
+ final CigarOperatorTest a = resolveCigarOperatorTestAnnotation(testMethod);
+ final List<Object[]> result = new LinkedList<Object[]>();
+ for (final String cigarString : TEST_CIGARS) {
+ if (a == null || a.value().appliesTo(cigarString)) {
+ result.add(new Object[] { cigarString });
+ }
+ }
+ return result.iterator();
+ }
+
+ /**
+ * Gets the most specific {@link CigarOperatorTest} annotation for the
+ * signature of the test method provided.
+ * <p/>
+ * This in-house implementation is required due to the fact that method
+ * annotations do not have inheritance.
+ *
+ * @param m targeted test method.
+ * @return <code>null</code> if there is no {@link CigarOperatorTest}
+ * annotation in this or overridden methods.
+ */
+ private CigarOperatorTest resolveCigarOperatorTestAnnotation(final Method m) {
+ CigarOperatorTest res = m.getAnnotation(CigarOperatorTest.class);
+ if (res != null) {
+ return res;
+ }
+ Class<?> c = this.getClass();
+ Class<?> p = c.getSuperclass();
+ while (p != null && p != Object.class) {
+ try {
+ final Method met = p.getDeclaredMethod(m.getName(),
+ m.getParameterTypes());
+ res = met.getAnnotation(CigarOperatorTest.class);
+ if (res != null) {
+ break;
+ }
+ } catch (NoSuchMethodException e) {
+ // Its ok; nothing to do here, just keep looking.
+ }
+ c = p;
+ p = c.getSuperclass();
+ }
+ return res;
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/NDNCigarReadTransformerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/NDNCigarReadTransformerUnitTest.java
new file mode 100644
index 0000000..beb4123
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/NDNCigarReadTransformerUnitTest.java
@@ -0,0 +1,70 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.Cigar;
+import org.broadinstitute.gatk.utils.sam.CigarUtils;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author ami
+ * @since 04/22/14
+ */
+public class NDNCigarReadTransformerUnitTest {
+
+
+ @DataProvider(name = "filteringIteratorTestData")
+ public String[][] getFilteringIteratorTestData() {
+ return new String[][] {
+ {"1M1N1N1M","1M1N1N1M"}, // NN elements
+ {"1M1N1D4M","1M1N1D4M"}, // ND
+ {"1M1N3M","1M1N3M"}, // N
+ {"1M1N2I1N3M","1M1N2I1N3M"}, // NIN
+ {"1M1N3D2N1M","1M6N1M"},
+ {"1M2N2D2N1M1D3N1D1N1M2H","1M6N1M1D5N1M2H"},
+ {"1H2S1M1N3D2N1M","1H2S1M6N1M"},
+ {"10M628N2D203N90M","10M833N90M"}
+ };
+ }
+
+ NDNCigarReadTransformer filter;
+
+ @BeforeClass
+ public void init() {
+ filter = new NDNCigarReadTransformer();
+ }
+
+ @Test(dataProvider = "filteringIteratorTestData")
+ public void testCigarRefactoring (final String originalCigarString, final String expectedString) {
+ Cigar originalCigar = CigarUtils.cigarFromString(originalCigarString);
+ String actualString = filter.refactorNDNtoN(originalCigar).toString();
+ Assert.assertEquals(actualString, expectedString, "ciagr string "+ originalCigarString+" should become: "+expectedString+" but got: "+actualString);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/ReadFilterTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/ReadFilterTest.java
new file mode 100644
index 0000000..0f61de2
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/ReadFilterTest.java
@@ -0,0 +1,370 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMDataSource;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.broadinstitute.gatk.engine.downsampling.DownsamplingMethod;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+
+import java.util.*;
+
+/**
+ * Class ReadBaseTest
+ * <p/>
+ * This is the base test class for read filter test classes. All read
+ * filter test cases should extend from this
+ * class; it sets ups a header mock up to test read filtering.
+ *
+ * Feel free to override non-final method to modify the behavior
+ * (i.e. change how read group id are formatted, or complete a header).
+ *
+ * <p/>
+ * You can statically determine the number of read-group involved
+ * in the test by calling {@link #ReadFilterTest(int)} in you constructor.
+ * <p/>
+ *
+ * Notice that the same header object is shared by all test and
+ * it is initialized by Junit (calling {@link #beforeClass()}.
+ *
+ * @author Valentin Ruano Rubio
+ * @date May 23, 2013
+ */
+public class ReadFilterTest extends BaseTest {
+
+ private static final int DEFAULT_READ_GROUP_COUNT = 5;
+ private static final int DEFAULT_READER_COUNT = 1;
+ private static final String DEFAULT_READ_GROUP_PREFIX = "ReadGroup";
+ private static final String DEFAULT_PLATFORM_UNIT_PREFIX = "Lane";
+ private static final String DEFAULT_SAMPLE_NAME_PREFIX = "Sample";
+ private static final String DEFAULT_PLATFORM_PREFIX = "Platform";
+ private static final int DEFAULT_CHROMOSOME_COUNT = 1;
+ private static final int DEFAULT_CHROMOSOME_START_INDEX = 1;
+ private static final int DEFAULT_CHROMOSOME_SIZE = 1000;
+ private static final String DEFAULT_SAM_FILE_FORMAT = "readfile-%3d.bam";
+
+ private final int groupCount;
+
+ private SAMFileHeader header;
+
+ private SAMDataSource dataSource;
+
+ /**
+ * Constructs a new read-filter test providing the number of read
+ * groups in the file.
+ *
+ * @param groupCount number of read-group in the fictional SAM file,
+ * must be equal or greater than 1.
+ */
+ protected ReadFilterTest(final int groupCount) {
+ if (groupCount < 1) {
+ throw new IllegalArgumentException(
+ "the read group count must at least be 1");
+ }
+ this.groupCount = groupCount;
+ }
+
+
+ /**
+ * Gets the data source.
+ *
+ * @throws IllegalStateException if the data source was not initialized
+ * invoking {@link #beforeClass()}
+ * @return never <code>null</code>
+ */
+ protected final SAMDataSource getDataSource() {
+ checkDataSourceExists();
+ return dataSource;
+ }
+
+ /**
+ * Returns the mock-up SAM file header for testing.
+ *
+ * @throws IllegalStateException if the header was not initialized
+ * invoking {@link #beforeClass()}
+ * @return never <code>null</code>
+ */
+ protected final SAMFileHeader getHeader() {
+ checkHeaderExists();
+ return header;
+ }
+
+ /**
+ * Construct a read filter test with the default number of groups
+ * ({@link #DEFAULT_READ_GROUP_COUNT}.
+ */
+ public ReadFilterTest() {
+ this(DEFAULT_READ_GROUP_COUNT);
+ }
+
+ /**
+ * Return the number of read groups involved in the test
+ * @return <code>1</code> or greater.
+ */
+ protected final int getReadGroupCount() {
+ return groupCount;
+ }
+
+ /**
+ * Composes the Id for the read group given its index.
+ *
+ * This methods must return a unique distinct ID for each possible index and
+ * it must be the same value each time it is invoked.
+ *
+ * @param index the index of the targeted read group in the range
+ * [1,{@link #getReadGroupCount()}]
+ * @return never <code>null</code> and must be unique to each possible
+ * read group index.
+ */
+ protected String composeReadGroupId(final int index) {
+ checkReadGroupIndex(index);
+ return DEFAULT_READ_GROUP_PREFIX + index;
+ }
+
+ /**
+ * Composes the Platform name for the read group given its index.
+ *
+ * This method must always return the same value give an index.
+ *
+ * @param index the index of the targeted read group in the range
+ * [1,{@link #getReadGroupCount()}]
+ * @return never <code>null</code>.
+ */
+ protected String composePlatformName(final int index) {
+ checkReadGroupIndex(index);
+ return DEFAULT_PLATFORM_PREFIX + (((index-1)%2)+1);
+ }
+
+
+ /**
+ * Composes the Platform unit name for the read group given its index.
+ *
+ * @param index the index of the targeted read group in the range
+ * [1,{@link #getReadGroupCount()}]
+ * @return never <code>null</code>.
+ */
+ protected String composePlatformUnitName(final int index) {
+ checkReadGroupIndex(index);
+ return DEFAULT_PLATFORM_UNIT_PREFIX + (((index-1)%3)+1);
+ }
+
+
+
+ /**
+ * Checks the correctness of a given read group index.
+ *
+ * A correct index is any value in the range [1,{@link #getReadGroupCount()}].
+ *
+ * @param index the target index.
+ * @throws IllegalArgumentException if the input index is not correct.
+ */
+ protected final void checkReadGroupIndex(final int index) {
+ checkIndex(index,groupCount,"read group");
+ }
+
+
+ private void checkIndex(final int index, final int max, CharSequence name) {
+ if (index < 1 || index > max) {
+ throw new IllegalArgumentException(
+ name + " index ("
+ + index
+ + ") is out of bounds [1," + max + "]");
+ }
+ }
+
+
+ /**
+ * Checks whether the header was initialized.
+ *
+ * @throws IllegalStateException if the header was not yet initialized.
+ */
+ protected final void checkHeaderExists() {
+ if (header == null) {
+ throw new IllegalArgumentException(
+ "header has not been initialized;"
+ + " beforeClass() was not invoked");
+ }
+ }
+
+ /**
+ * Checks whether the data source was initialized.
+ *
+ * @throws IllegalStateException if the data source was not yet initialized.
+ */
+ protected final void checkDataSourceExists() {
+ if (header == null) {
+ throw new IllegalArgumentException(
+ "data source has not been initialized;"
+ + " beforeClass() was not invoked");
+ }
+ }
+
+ /**
+ * Returns the ID for a read group given its index.
+ *
+ * @param index the index of the targeted read group in the range
+ * [1,{@link #getReadGroupCount()}]
+ * @return never <code>null</code> and must be unique to each
+ * possible read group index.
+ */
+ protected final String getReadGroupId(final int index) {
+ checkReadGroupIndex(index);
+ return getHeader().getReadGroups().get(index - 1).getReadGroupId();
+ }
+
+ /**
+ * Returns the platform name for a read group given its index.
+ *
+ * @param group the index of the targeted read group in the range
+ * [1,{@link #getReadGroupCount()}]
+ * @return never <code>null</code>.
+ */
+ protected final String getPlatformName(final int group) {
+ checkReadGroupIndex(group);
+ return getHeader().getReadGroups().get(group - 1).getPlatform();
+ }
+
+ /**
+ * Returns the platform unit for a read group given its index.
+ *
+ * @param group the index of the targeted read group in the range
+ * [1,{@link #getReadGroupCount()}]
+ * @return never <code>null</code>.
+ */
+ protected final String getPlatformUnit(final int group) {
+ checkReadGroupIndex(group);
+ return getHeader().getReadGroups().get(group - 1).getPlatformUnit();
+ }
+
+
+ /**
+ * Composes the mock up SAM file header.
+ *
+ * It must return an equivalent (equal) value each time it is invoked.
+ *
+ * @return never <code>null</code>.
+ */
+ protected SAMFileHeader composeHeader() {
+
+ return ArtificialSAMUtils.createArtificialSamHeader(
+ DEFAULT_CHROMOSOME_COUNT, DEFAULT_CHROMOSOME_START_INDEX,
+ DEFAULT_CHROMOSOME_SIZE);
+ }
+
+ @BeforeClass
+ public void beforeClass() {
+
+ header = composeHeader();
+ dataSource = composeDataSource();
+ final List<String> readGroupIDs = new ArrayList<String>();
+ final List<String> sampleNames = new ArrayList<String>();
+
+ for (int i = 1; i <= getReadGroupCount(); i++) {
+ final String readGroupId = composeReadGroupId(i);
+ readGroupIDs.add(readGroupId);
+ sampleNames.add(readGroupId);
+ }
+
+ ArtificialSAMUtils.createEnumeratedReadGroups(
+ header, readGroupIDs, sampleNames);
+
+ for (int i = 1; i <= getReadGroupCount(); i++) {
+ final String readGroupId = readGroupIDs.get(i-1);
+ final SAMReadGroupRecord groupRecord = header.getReadGroup(readGroupId);
+ groupRecord.setAttribute("PL", composePlatformName(i));
+ groupRecord.setAttribute("PU", composePlatformUnitName(i));
+ }
+
+ }
+
+ protected ValidationExclusion composeValidationExclusion() {
+ return new ValidationExclusion();
+ }
+
+ protected SAMDataSource composeDataSource() {
+ checkHeaderExists();
+ final Set<SAMReaderID> readerIDs = new HashSet<>(1);
+ final ThreadAllocation ta = new ThreadAllocation();
+ final Integer numFileHandles = 1; // I believe that any value would do but need to confirm.
+ final boolean useOriginalBaseQualities = true;
+ final ValidationStringency strictness = ValidationStringency.LENIENT;
+ final Integer readBufferSize = 1; // not relevant.
+ final DownsamplingMethod downsamplingMethod = DownsamplingMethod.NONE;
+ final ValidationExclusion exclusionList = composeValidationExclusion();
+ final Collection<ReadFilter> supplementalFilters = Collections.EMPTY_SET;
+ final boolean includeReadsWithDeletionAtLoci = true;
+
+ final GenomeLocParser glp = new GenomeLocParser(header.getSequenceDictionary());
+ final SAMDataSource res = new SAMDataSource(
+ readerIDs,
+ ta,
+ numFileHandles,
+ glp,
+ useOriginalBaseQualities,
+ strictness,
+ readBufferSize,
+ downsamplingMethod,
+ exclusionList,
+ supplementalFilters,
+ includeReadsWithDeletionAtLoci);
+
+ return res;
+ }
+
+ @AfterClass
+ public void afterClass() {
+ header = null;
+ dataSource = null;
+ }
+
+ /**
+ * Creates a read record.
+ *
+ * @param cigar the new record CIGAR.
+ * @param group the new record group index that must be in the range \
+ * [1,{@link #getReadGroupCount()}]
+ * @param reference the reference sequence index (0-based)
+ * @param start the start position of the read alignment in the reference
+ * (1-based)
+ * @return never <code>null</code>
+ */
+ protected SAMRecord createRead(final Cigar cigar, final int group, final int reference, final int start) {
+ final SAMRecord record = ArtificialSAMUtils.createArtificialRead(cigar);
+ record.setHeader(getHeader());
+ record.setAlignmentStart(start);
+ record.setReferenceIndex(reference);
+ record.setAttribute(SAMTag.RG.toString(), getReadGroupId(group));
+ return record;
+
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/ReadGroupBlackListFilterUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/ReadGroupBlackListFilterUnitTest.java
new file mode 100644
index 0000000..3a0fc6e
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/ReadGroupBlackListFilterUnitTest.java
@@ -0,0 +1,247 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.annotations.Test;
+
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMReadGroupRecord;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+
+public class ReadGroupBlackListFilterUnitTest extends ReadFilterTest {
+
+ @Test(expectedExceptions=ReviewedGATKException.class)
+ public void testBadFilter() {
+ List<String> badFilters = Collections.singletonList("bad");
+ new ReadGroupBlackListFilter(badFilters);
+ }
+ @Test(expectedExceptions=ReviewedGATKException.class)
+ public void testBadFilterTag() {
+ List<String> badFilters = Collections.singletonList("bad:filter");
+ new ReadGroupBlackListFilter(badFilters);
+ }
+
+ @Test(expectedExceptions=ReviewedGATKException.class)
+ public void testBadFilterFile() {
+ List<String> badFilters = Collections.singletonList("/foo/bar/rgbl.txt");
+ new ReadGroupBlackListFilter(badFilters);
+ }
+
+ @Test
+ public void testFilterReadGroup() {
+ SAMRecord filteredRecord = ArtificialSAMUtils.createArtificialRead(getHeader(), "readUno", 0, 1, 20);
+ filteredRecord.setAttribute("RG", getReadGroupId(1));
+
+ SAMRecord unfilteredRecord = ArtificialSAMUtils.createArtificialRead(getHeader(), "readDos", 0, 2, 20);
+ unfilteredRecord.setAttribute("RG", getReadGroupId(2));
+
+ List<String> filterList = new ArrayList<String>();
+ filterList.add("RG:" + getReadGroupId(1));
+
+ ReadGroupBlackListFilter filter = new ReadGroupBlackListFilter(filterList);
+ Assert.assertTrue(filter.filterOut(filteredRecord));
+ Assert.assertFalse(filter.filterOut(unfilteredRecord));
+ }
+
+ @Test
+ public void testFilterPlatformUnit() {
+ SAMRecord filteredRecord = ArtificialSAMUtils.createArtificialRead(getHeader(), "readUno", 0, 1, 20);
+ filteredRecord.setAttribute("RG", getReadGroupId(1));
+
+ SAMRecord unfilteredRecord = ArtificialSAMUtils.createArtificialRead(getHeader(), "readDos", 0, 2, 20);
+ unfilteredRecord.setAttribute("RG", getReadGroupId(2));
+
+ List<String> filterList = new ArrayList<String>();
+ filterList.add("PU:" + getPlatformUnit(1));
+
+ ReadGroupBlackListFilter filter = new ReadGroupBlackListFilter(filterList);
+ Assert.assertTrue(filter.filterOut(filteredRecord));
+ Assert.assertFalse(filter.filterOut(unfilteredRecord));
+ }
+
+ @Test
+ public void testFilterOutByReadGroup() {
+ int recordsPerGroup = 3;
+ List<SAMRecord> records = new ArrayList<SAMRecord>();
+ int alignmentStart = 0;
+ for (int x = 1; x <= getReadGroupCount(); x++) {
+ SAMReadGroupRecord groupRecord = getHeader().getReadGroup(getReadGroupId(x));
+ for (int y = 1; y <= recordsPerGroup; y++) {
+ SAMRecord record = ArtificialSAMUtils.createArtificialRead(getHeader(), "readUno", 0, ++alignmentStart, 20);
+ record.setAttribute("RG", groupRecord.getReadGroupId());
+ records.add(record);
+ }
+ }
+
+ List<String> filterList = new ArrayList<String>();
+ filterList.add("RG:" + getReadGroupId(1));
+ filterList.add("RG:" + getReadGroupId(3));
+
+ ReadGroupBlackListFilter filter = new ReadGroupBlackListFilter(filterList);
+ int filtered = 0;
+ int unfiltered = 0;
+ for (SAMRecord record : records) {
+ String readGroupName = record.getReadGroup().getReadGroupId();
+ if (filter.filterOut(record)) {
+ if (!filterList.contains("RG:" + readGroupName))
+ Assert.fail("Read group " + readGroupName + " was filtered");
+ filtered++;
+ } else {
+ if (filterList.contains("RG:" + readGroupName))
+ Assert.fail("Read group " + readGroupName + " was not filtered");
+ unfiltered++;
+ }
+ }
+
+ int filteredExpected = recordsPerGroup * 2;
+ int unfilteredExpected = recordsPerGroup * (getReadGroupCount() - 2);
+ Assert.assertEquals(filtered, filteredExpected, "Filtered");
+ Assert.assertEquals(unfiltered, unfilteredExpected, "Uniltered");
+ }
+
+ @Test
+ public void testFilterOutByAttribute() {
+ int recordsPerGroup = 3;
+ List<SAMRecord> records = new ArrayList<SAMRecord>();
+ int alignmentStart = 0;
+ for (int x = 1; x <= getReadGroupCount(); x++) {
+ SAMReadGroupRecord groupRecord = getHeader().getReadGroup(getReadGroupId(x));
+ for (int y = 1; y <= recordsPerGroup; y++) {
+ SAMRecord record = ArtificialSAMUtils.createArtificialRead(getHeader(), "readUno", 0, ++alignmentStart, 20);
+ record.setAttribute("RG", groupRecord.getReadGroupId());
+ records.add(record);
+ }
+ }
+
+ List<String> filterList = new ArrayList<String>();
+ filterList.add("PU:" + getPlatformUnit(1));
+
+ ReadGroupBlackListFilter filter = new ReadGroupBlackListFilter(filterList);
+ int filtered = 0;
+ int unfiltered = 0;
+ for (SAMRecord record : records) {
+ String platformUnit = (String) record.getReadGroup().getAttribute("PU");
+ if (filter.filterOut(record)) {
+ if (!filterList.contains("PU:" + platformUnit))
+ Assert.fail("Platform unit " + platformUnit + " was filtered");
+ filtered++;
+ } else {
+ if (filterList.contains("PU:" + platformUnit))
+ Assert.fail("Platform unit " + platformUnit + " was not filtered");
+ unfiltered++;
+ }
+ }
+
+ int filteredExpected = 6;
+ int unfilteredExpected = 9;
+ Assert.assertEquals(filtered, filteredExpected, "Filtered");
+ Assert.assertEquals(unfiltered, unfilteredExpected, "Uniltered");
+ }
+
+ @Test
+ public void testFilterOutByFile() {
+ int recordsPerGroup = 3;
+ List<SAMRecord> records = new ArrayList<SAMRecord>();
+ int alignmentStart = 0;
+ for (int x = 1; x <= getReadGroupCount(); x++) {
+ SAMReadGroupRecord groupRecord = getHeader().getReadGroup(getReadGroupId(x));
+ for (int y = 1; y <= recordsPerGroup; y++) {
+ SAMRecord record = ArtificialSAMUtils.createArtificialRead(getHeader(), "readUno", 0, ++alignmentStart, 20);
+ record.setAttribute("RG", groupRecord.getReadGroupId());
+ records.add(record);
+ }
+ }
+
+ List<String> filterList = new ArrayList<String>();
+ filterList.add(privateTestDir + "readgroupblacklisttest.txt");
+
+ ReadGroupBlackListFilter filter = new ReadGroupBlackListFilter(filterList);
+ int filtered = 0;
+ int unfiltered = 0;
+ for (SAMRecord record : records) {
+ String readGroup = record.getReadGroup().getReadGroupId();
+ if (filter.filterOut(record)) {
+ if (!("ReadGroup3".equals(readGroup) || "ReadGroup4".equals(readGroup)))
+ Assert.fail("Read group " + readGroup + " was filtered");
+ filtered++;
+ } else {
+ if ("ReadGroup3".equals(readGroup) || "ReadGroup4".equals(readGroup))
+ Assert.fail("Read group " + readGroup + " was not filtered");
+ unfiltered++;
+ }
+ }
+
+ int filteredExpected = recordsPerGroup * 2;
+ int unfilteredExpected = recordsPerGroup * (getReadGroupCount() - 2);
+ Assert.assertEquals(filtered, filteredExpected, "Filtered");
+ Assert.assertEquals(unfiltered, unfilteredExpected, "Uniltered");
+ }
+
+ @Test
+ public void testFilterOutByListFile() {
+ int recordsPerGroup = 3;
+ List<SAMRecord> records = new ArrayList<SAMRecord>();
+ int alignmentStart = 0;
+ for (int x = 1; x <= getReadGroupCount(); x++) {
+ SAMReadGroupRecord groupRecord = getHeader().getReadGroup(getReadGroupId(x));
+ for (int y = 1; y <= recordsPerGroup; y++) {
+ SAMRecord record = ArtificialSAMUtils.createArtificialRead(getHeader(), "readUno", 0, ++alignmentStart, 20);
+ record.setAttribute("RG", groupRecord.getReadGroupId());
+ records.add(record);
+ }
+ }
+
+ List<String> filterList = new ArrayList<String>();
+ filterList.add(privateTestDir + "readgroupblacklisttestlist.txt");
+
+ ReadGroupBlackListFilter filter = new ReadGroupBlackListFilter(filterList);
+ int filtered = 0;
+ int unfiltered = 0;
+ for (SAMRecord record : records) {
+ String readGroup = record.getReadGroup().getReadGroupId();
+ if (filter.filterOut(record)) {
+ if (!("ReadGroup3".equals(readGroup) || "ReadGroup4".equals(readGroup)))
+ Assert.fail("Read group " + readGroup + " was filtered");
+ filtered++;
+ } else {
+ if ("ReadGroup3".equals(readGroup) || "ReadGroup4".equals(readGroup))
+ Assert.fail("Read group " + readGroup + " was not filtered");
+ unfiltered++;
+ }
+ }
+
+ int filteredExpected = recordsPerGroup * 2;
+ int unfilteredExpected = recordsPerGroup * (getReadGroupCount() - 2);
+ Assert.assertEquals(filtered, filteredExpected, "Filtered");
+ Assert.assertEquals(unfiltered, unfilteredExpected, "Uniltered");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/UnsafeMalformedReadFilterUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/UnsafeMalformedReadFilterUnitTest.java
new file mode 100644
index 0000000..a00f0a0
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/filters/UnsafeMalformedReadFilterUnitTest.java
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.filters;
+
+
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+
+import java.util.Collections;
+
+
+/**
+ * Tests for the {@link MalformedReadFilter} when the unsafe flag
+ * {@link ValidationExclusion.TYPE#ALL} is set.
+ *
+ * @author Valentin Ruano-Rubio
+ * @since 6/6/13
+ */
+public class UnsafeMalformedReadFilterUnitTest extends AllowNCigarMalformedReadFilterUnitTest {
+
+
+ @Override
+ protected ValidationExclusion composeValidationExclusion() {
+ return new ValidationExclusion(Collections.singletonList(ValidationExclusion.TYPE.ALL));
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/io/OutputTrackerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/io/OutputTrackerUnitTest.java
new file mode 100644
index 0000000..479e19e
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/io/OutputTrackerUnitTest.java
@@ -0,0 +1,84 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.io;
+
+import org.broadinstitute.gatk.engine.io.stubs.OutputStreamStub;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+
+public class OutputTrackerUnitTest extends BaseTest {
+
+ private final OutputTracker tracker = new DirectOutputTracker();
+ private File unwriteableDir = null;
+ private File untraversableDir = null;
+
+ @BeforeClass
+ public void createDirectories() {
+ unwriteableDir = new File("unwriteable");
+ unwriteableDir.deleteOnExit();
+ unwriteableDir.mkdir();
+ unwriteableDir.setWritable(false);
+
+ untraversableDir = new File("untraversable");
+ untraversableDir.deleteOnExit();
+ untraversableDir.mkdir();
+ untraversableDir.setExecutable(false);
+ }
+
+ @DataProvider(name = "BadOutputPaths")
+ public Object[][] makeBadOutputPaths() {
+ return new Object[][] {new String[] {"thisDirectoryDoesNotExist/stub.txt"},
+ new String[] {"/thisDirectoryDoesNotExist/dummy.txt"},
+ new String[] {unwriteableDir.getAbsolutePath()+"/dummy.txt"},
+ new String[] {untraversableDir.getAbsolutePath()+"/dummy.txt"}};
+ }
+
+ @DataProvider(name = "GoodOutputPaths")
+ public Object[][] makeGoodOutputPaths() {
+ return new Object[][] {new String[] {publicTestDir+"stub.txt"},
+ new String[] {"dummy.txt"}};
+ }
+
+ @Test(dataProvider = "BadOutputPaths", expectedExceptions = UserException.CouldNotCreateOutputFile.class)
+ public void testInvalidOutputPath(final String path) {
+ tracker.validateOutputPath(new OutputStreamStub(new File(path)));
+ }
+
+ @Test(dataProvider = "GoodOutputPaths")
+ public void testValidOutputPath(final String path) {
+ tracker.validateOutputPath(new OutputStreamStub(new File(path)));
+ }
+
+ @Test
+ public void testOutputPathWithNullFile() {
+ tracker.validateOutputPath(new OutputStreamStub(System.out));
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/BoundedReadIteratorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/BoundedReadIteratorUnitTest.java
new file mode 100644
index 0000000..7c3aca2
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/BoundedReadIteratorUnitTest.java
@@ -0,0 +1,145 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import static org.testng.Assert.fail;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+
+import org.testng.annotations.BeforeMethod;
+
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author aaron
+ * @version 1.0
+ * @date Apr 14, 2009
+ * <p/>
+ * Class BoundedReadIteratorUnitTest
+ * <p/>
+ * tests for the bounded read iterator.
+ */
+public class BoundedReadIteratorUnitTest extends BaseTest {
+
+ /** the file list and the fasta sequence */
+ private List<File> fl;
+ private ReferenceSequenceFile seq;
+
+ /**
+ * This function does the setup of our parser, before each method call.
+ * <p/>
+ * Called before every test case method.
+ */
+ @BeforeMethod
+ public void doForEachTest() throws FileNotFoundException {
+ fl = new ArrayList<File>();
+ }
+
+
+ /** Test out that we can shard the file and iterate over every read */
+ @Test
+ public void testBounding() {
+ logger.warn("Executing testBounding");
+ // total reads expected
+ final int expected = 20;
+ // bound by ten reads
+ BoundedReadIterator iter = new BoundedReadIterator(new testIterator(), expected);
+
+ int count = 0;
+ for (SAMRecord rec: iter) {
+ count++;
+ }
+
+ Assert.assertEquals(count, expected);
+ }
+}
+
+class testIterator implements GATKSAMIterator {
+ SAMFileHeader header;
+ testIterator() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(1,1,2000);
+ }
+
+ public void close() {
+
+ }
+
+ public boolean hasNext() {
+ return true;
+ }
+
+ public SAMRecord next() {
+ return ArtificialSAMUtils.createArtificialRead(header,"blah",0,1,100);
+ }
+
+ public void remove() {
+ }
+
+ public Iterator<SAMRecord> iterator() {
+ return this;
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/GATKSAMIteratorAdapterUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/GATKSAMIteratorAdapterUnitTest.java
new file mode 100644
index 0000000..6cbd4fd
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/GATKSAMIteratorAdapterUnitTest.java
@@ -0,0 +1,176 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.util.CloseableIterator;
+import org.broadinstitute.gatk.utils.BaseTest;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Test;
+
+import java.util.Iterator;
+
+/**
+ *
+ * User: aaron
+ * Date: May 13, 2009
+ * Time: 6:58:21 PM
+ *
+ * The Broad Institute
+ * SOFTWARE COPYRIGHT NOTICE AGREEMENT
+ * This software and its documentation are copyright 2009 by the
+ * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
+ *
+ * This software is supplied without any warranty or guaranteed support whatsoever. Neither
+ * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
+ *
+ */
+
+
+/**
+ * @author aaron
+ * @version 1.0
+ * @date May 13, 2009
+ * <p/>
+ * Class GATKSAMIteratorTest
+ * <p/>
+ * Tests the GATKSAMIteratorAdapter class.
+ */
+public class GATKSAMIteratorAdapterUnitTest extends BaseTest {
+
+ class MyTestIterator implements Iterator<SAMRecord> {
+
+ public int count = 0;
+
+ public MyTestIterator() {
+ count = 0;
+ }
+
+ public boolean hasNext() {
+ if (count < 100) {
+ ++count;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public SAMRecord next() {
+ return null;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Unsupported");
+ }
+ }
+
+ class MyTestCloseableIterator implements CloseableIterator<SAMRecord> {
+ public int count = 0;
+
+ public MyTestCloseableIterator() {
+ count = 0;
+ }
+
+ public boolean hasNext() {
+ if (count < 100) {
+ ++count;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public SAMRecord next() {
+ return null;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Unsupported");
+ }
+
+ public void close() {
+ count = -1;
+ }
+ }
+
+
+ @Test
+ public void testNormalIterator() {
+ final int COUNT = 100;
+ MyTestIterator it = new MyTestIterator();
+
+ GATKSAMIterator samIt = GATKSAMIteratorAdapter.adapt(it);
+ int countCheck = 0;
+ while (samIt.hasNext()) {
+ samIt.next();
+ ++countCheck;
+ //logger.warn("cnt = " + countCheck);
+ }
+
+ assertEquals(countCheck, COUNT);
+
+ assertEquals(countCheck, COUNT);
+ }
+
+ @Test
+ public void testCloseableIterator() {
+ final int COUNT = 100;
+
+ MyTestCloseableIterator it = new MyTestCloseableIterator();
+
+ GATKSAMIterator samIt = GATKSAMIteratorAdapter.adapt(it);
+
+ int countCheck = 0;
+ while (samIt.hasNext()) {
+ samIt.next();
+ ++countCheck;
+ }
+
+ assertEquals(countCheck, COUNT);
+ }
+
+ @Test
+ public void testCloseOnCloseableIterator() {
+ final int COUNT = 100;
+
+ MyTestCloseableIterator it = new MyTestCloseableIterator();
+
+ GATKSAMIterator samIt = GATKSAMIteratorAdapter.adapt(it);
+
+
+ int countCheck = 0;
+ while (samIt.hasNext()) {
+ samIt.next();
+ ++countCheck;
+ }
+
+ assertEquals(countCheck, COUNT);
+
+ // check to see that the count get's set to -1
+ samIt.close();
+ assertEquals(it.count, -1);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/ReadFormattingIteratorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/ReadFormattingIteratorUnitTest.java
new file mode 100644
index 0000000..c926d06
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/ReadFormattingIteratorUnitTest.java
@@ -0,0 +1,50 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+
+public class ReadFormattingIteratorUnitTest extends BaseTest {
+
+ @Test
+ public void testIteratorConsolidatesCigars() {
+ final Cigar unconsolidatedCigar = TextCigarCodec.getSingleton().decode("3M0M5M0M");
+ final SAMRecord unconsolidatedRead = ArtificialSAMUtils.createArtificialRead(unconsolidatedCigar);
+
+ final GATKSAMIterator readIterator = GATKSAMIteratorAdapter.adapt(Arrays.asList(unconsolidatedRead).iterator());
+ final ReadFormattingIterator formattingIterator = new ReadFormattingIterator(readIterator, false, (byte)-1);
+ final SAMRecord postIterationRead = formattingIterator.next();
+
+ Assert.assertEquals(postIterationRead.getCigarString(), "8M", "Cigar 3M0M5M0M not consolidated correctly by ReadFormattingIterator");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/VerifyingSamIteratorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/VerifyingSamIteratorUnitTest.java
new file mode 100644
index 0000000..371f94f
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/iterators/VerifyingSamIteratorUnitTest.java
@@ -0,0 +1,128 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.iterators;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mhanna
+ * Date: Mar 2, 2011
+ * Time: 9:48:10 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class VerifyingSamIteratorUnitTest {
+ private SAMFileHeader samFileHeader;
+
+ @BeforeClass
+ public void init() {
+ SAMSequenceDictionary sequenceDictionary = new SAMSequenceDictionary();
+ sequenceDictionary.addSequence(new SAMSequenceRecord("1",500));
+ sequenceDictionary.addSequence(new SAMSequenceRecord("2",500));
+
+ samFileHeader = new SAMFileHeader();
+ samFileHeader.setSequenceDictionary(sequenceDictionary);
+ }
+
+ @Test
+ public void testSortedReadsBasic() {
+ SAMRecord read1 = ArtificialSAMUtils.createArtificialRead(samFileHeader,"read1",getContig(0).getSequenceIndex(),1,10);
+ SAMRecord read2 = ArtificialSAMUtils.createArtificialRead(samFileHeader,"read2",getContig(0).getSequenceIndex(),2,10);
+ List<SAMRecord> reads = Arrays.asList(read1,read2);
+
+ VerifyingSamIterator iterator = new VerifyingSamIterator(GATKSAMIteratorAdapter.adapt(reads.iterator()));
+
+ Assert.assertTrue(iterator.hasNext(),"Insufficient reads");
+ Assert.assertSame(iterator.next(),read1,"Incorrect read in read 1 position");
+ Assert.assertTrue(iterator.hasNext(),"Insufficient reads");
+ Assert.assertSame(iterator.next(),read2,"Incorrect read in read 2 position");
+ Assert.assertFalse(iterator.hasNext(),"Too many reads in iterator");
+ }
+
+ @Test
+ public void testSortedReadsAcrossContigs() {
+ SAMRecord read1 = ArtificialSAMUtils.createArtificialRead(samFileHeader,"read1",getContig(0).getSequenceIndex(),2,10);
+ SAMRecord read2 = ArtificialSAMUtils.createArtificialRead(samFileHeader,"read2",getContig(1).getSequenceIndex(),1,10);
+ List<SAMRecord> reads = Arrays.asList(read1,read2);
+
+ VerifyingSamIterator iterator = new VerifyingSamIterator(GATKSAMIteratorAdapter.adapt(reads.iterator()));
+
+ Assert.assertTrue(iterator.hasNext(),"Insufficient reads");
+ Assert.assertSame(iterator.next(),read1,"Incorrect read in read 1 position");
+ Assert.assertTrue(iterator.hasNext(),"Insufficient reads");
+ Assert.assertSame(iterator.next(),read2,"Incorrect read in read 2 position");
+ Assert.assertFalse(iterator.hasNext(),"Too many reads in iterator");
+ }
+
+ @Test(expectedExceptions=UserException.MissortedBAM.class)
+ public void testImproperlySortedReads() {
+ SAMRecord read1 = ArtificialSAMUtils.createArtificialRead(samFileHeader,"read1",getContig(0).getSequenceIndex(),2,10);
+ SAMRecord read2 = ArtificialSAMUtils.createArtificialRead(samFileHeader,"read2",getContig(0).getSequenceIndex(),1,10);
+ List<SAMRecord> reads = Arrays.asList(read1,read2);
+
+ VerifyingSamIterator iterator = new VerifyingSamIterator(GATKSAMIteratorAdapter.adapt(reads.iterator()));
+
+ Assert.assertTrue(iterator.hasNext(),"Insufficient reads");
+ Assert.assertSame(iterator.next(),read1,"Incorrect read in read 1 position");
+ Assert.assertTrue(iterator.hasNext(),"Insufficient reads");
+
+ // Should trigger MissortedBAM exception.
+ iterator.next();
+ }
+
+ @Test(expectedExceptions=UserException.MalformedBAM.class)
+ public void testInvalidAlignment() {
+ // Create an invalid alignment state.
+ SAMRecord read1 = ArtificialSAMUtils.createArtificialRead(samFileHeader,"read1",getContig(0).getSequenceIndex(),1,10);
+ SAMRecord read2 = ArtificialSAMUtils.createArtificialRead(samFileHeader,"read1",getContig(0).getSequenceIndex(),2,10);
+ read1.setReferenceIndex(SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX);
+ List<SAMRecord> reads = Arrays.asList(read1,read2);
+
+ VerifyingSamIterator iterator = new VerifyingSamIterator(GATKSAMIteratorAdapter.adapt(reads.iterator()));
+
+ Assert.assertTrue(iterator.hasNext(),"Insufficient reads");
+ Assert.assertSame(iterator.next(),read1,"Incorrect read in read 1 position");
+ Assert.assertTrue(iterator.hasNext(),"Insufficient reads");
+
+ // Should trigger MalformedBAM exception.
+ iterator.next();
+ }
+
+ private SAMSequenceRecord getContig(final int contigIndex) {
+ return samFileHeader.getSequence(contigIndex);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/phonehome/GATKRunReportUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/phonehome/GATKRunReportUnitTest.java
new file mode 100644
index 0000000..d7b9b3d
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/phonehome/GATKRunReportUnitTest.java
@@ -0,0 +1,310 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.phonehome;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.ActiveRegionWalker;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.tools.walkers.qc.CountLoci;
+import org.broadinstitute.gatk.tools.walkers.qc.CountRODs;
+import org.broadinstitute.gatk.tools.walkers.qc.CountReads;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.activeregion.ActiveRegion;
+import org.broadinstitute.gatk.utils.activeregion.ActivityProfileState;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.jets3t.service.S3Service;
+import org.jets3t.service.S3ServiceException;
+import org.jets3t.service.ServiceException;
+import org.jets3t.service.model.S3Object;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+public class GATKRunReportUnitTest extends BaseTest {
+ private final static boolean DEBUG = false;
+ private static final long S3_PUT_TIMEOUT_IN_MILLISECONDS_FOR_TESTING = 30 * 1000;
+ private static final String AWS_DOWNLOADER_CREDENTIALS_PROPERTIES_FILE = privateTestDir + "phonehome/awsDownloaderCredentials.properties";
+
+ private Walker walker;
+ private Exception exception;
+ private GenomeAnalysisEngine engine;
+ private String downloaderAccessKey;
+ private String downloaderSecretKey;
+
+ @BeforeClass
+ public void setup() throws Exception {
+ walker = new CountReads();
+ exception = new IllegalArgumentException("javaException");
+ engine = new GenomeAnalysisEngine();
+ engine.setArguments(new GATKArgumentCollection());
+
+ Properties awsProperties = new Properties();
+ awsProperties.load(new FileInputStream(AWS_DOWNLOADER_CREDENTIALS_PROPERTIES_FILE));
+ downloaderAccessKey = awsProperties.getProperty("accessKey");
+ downloaderSecretKey = awsProperties.getProperty("secretKey");
+ }
+
+ @Test(enabled = ! DEBUG)
+ public void testAWSKeysAreValid() {
+ // throws an exception if they aren't
+ GATKRunReport.checkAWSAreValid();
+ }
+
+ @Test(enabled = ! DEBUG)
+ public void testAccessKey() throws Exception {
+ testAWSKey(GATKRunReport.getAWSUploadAccessKey(), GATKRunReport.AWS_ACCESS_KEY_MD5);
+ }
+
+ @Test(enabled = ! DEBUG)
+ public void testSecretKey() throws Exception {
+ testAWSKey(GATKRunReport.getAWSUploadSecretKey(), GATKRunReport.AWS_SECRET_KEY_MD5);
+ }
+
+ private void testAWSKey(final String accessKey, final String expectedMD5) throws Exception {
+ Assert.assertNotNull(accessKey, "AccessKey should not be null");
+ final String actualmd5 = Utils.calcMD5(accessKey);
+ Assert.assertEquals(actualmd5, expectedMD5);
+ }
+
+ @DataProvider(name = "GATKReportCreationTest")
+ public Object[][] makeGATKReportCreationTest() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final Walker readWalker = new CountReads();
+ final Walker lociWalker = new CountLoci();
+ final Walker rodWalker = new CountRODs();
+ final Walker artWalker = new RunReportDummyActiveRegionWalker();
+
+ final Exception noException = null;
+ final Exception javaException = new IllegalArgumentException("javaException");
+ final Exception stingException = new ReviewedGATKException("GATKException");
+ final Exception userException = new UserException("userException");
+
+ final GenomeAnalysisEngine engine = new GenomeAnalysisEngine();
+ engine.setArguments(new GATKArgumentCollection());
+
+ for ( final Walker walker : Arrays.asList(readWalker, lociWalker, rodWalker, artWalker) ) {
+ for ( final Exception exception : Arrays.asList(noException, javaException, stingException, userException) ) {
+ tests.add(new Object[]{walker, exception, engine});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "GATKReportCreationTest")
+ public void testGATKReportCreationReadingAndWriting(final Walker walker, final Exception exception, final GenomeAnalysisEngine engine) throws Exception {
+ final GATKRunReport report = new GATKRunReport(walker, exception, engine, GATKRunReport.PhoneHomeOption.STDOUT);
+ final ByteArrayOutputStream captureStream = new ByteArrayOutputStream();
+ final boolean succeeded = report.postReportToStream(captureStream);
+ Assert.assertTrue(succeeded, "Failed to write report to stream");
+ Assert.assertFalse(report.exceptionOccurredDuringPost(), "Post succeeded but report says it failed");
+ Assert.assertNull(report.getErrorMessage(), "Post succeeded but there was an error message");
+ Assert.assertNull(report.getErrorThrown(), "Post succeeded but there was an error message");
+ final InputStream readStream = new ByteArrayInputStream(captureStream.toByteArray());
+
+ GATKRunReport deserialized = null;
+ try {
+ deserialized = GATKRunReport.deserializeReport(readStream);
+ } catch ( Exception e ) {
+ final String reportString = new String(captureStream.toByteArray());
+ Assert.fail("Failed to deserialize GATK report " + reportString + " with exception " + e);
+ }
+
+ if ( deserialized != null )
+ Assert.assertEquals(report, deserialized);
+ }
+
+ @DataProvider(name = "GATKAWSReportMode")
+ public Object[][] makeGATKAWSReportMode() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final GATKRunReport.AWSMode mode : GATKRunReport.AWSMode.values() ) {
+ tests.add(new Object[]{mode});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ // Will fail with timeout if AWS time out isn't working
+ // Will fail with exception if AWS doesn't protect itself from errors
+ @Test(enabled = ! DEBUG, dataProvider = "GATKAWSReportMode", timeOut = S3_PUT_TIMEOUT_IN_MILLISECONDS_FOR_TESTING * 2)
+ public void testAWS(final GATKRunReport.AWSMode awsMode) {
+ logger.warn("Starting testAWS mode=" + awsMode);
+
+ // Use a shorter timeout than usual when we're testing GATKRunReport.AWSMode.TIMEOUT
+ final long thisTestS3Timeout = awsMode == GATKRunReport.AWSMode.TIMEOUT ? 30 * 1000 : S3_PUT_TIMEOUT_IN_MILLISECONDS_FOR_TESTING;
+ final GATKRunReport report = new GATKRunReport(walker, exception, engine, GATKRunReport.PhoneHomeOption.AWS, thisTestS3Timeout);
+ report.sendAWSToTestBucket();
+ report.setAwsMode(awsMode);
+ final S3Object s3Object = report.postReportToAWSS3();
+
+ if ( awsMode == GATKRunReport.AWSMode.NORMAL ) {
+ Assert.assertNotNull(s3Object, "Upload to AWS failed, s3Object was null. error was " + report.formatError());
+ Assert.assertFalse(report.exceptionOccurredDuringPost(), "The upload should have succeeded but the report says it didn't. Error was " + report.formatError());
+ Assert.assertNull(report.getErrorMessage(), "Report succeeded but an error message was found");
+ Assert.assertNull(report.getErrorThrown(), "Report succeeded but an thrown error was found");
+ try {
+ final GATKRunReport deserialized = GATKRunReport.deserializeReport(downloaderAccessKey, downloaderSecretKey, report.getS3ReportBucket(), s3Object);
+ Assert.assertEquals(report, deserialized);
+ deleteFromS3(report);
+ } catch ( Exception e ) {
+ Assert.fail("Failed to read, deserialize, or delete GATK report " + s3Object.getName() + " with exception " + e);
+ }
+ } else {
+ Assert.assertNull(s3Object, "AWS upload should have failed for mode " + awsMode + " but got non-null s3 object back " + s3Object + " error was " + report.formatError());
+ Assert.assertTrue(report.exceptionOccurredDuringPost(), "S3 object was null but the report says that the upload succeeded");
+ Assert.assertNotNull(report.getErrorMessage(), "Report succeeded but an error message wasn't found");
+ if ( awsMode == GATKRunReport.AWSMode.FAIL_WITH_EXCEPTION )
+ Assert.assertNotNull(report.getErrorThrown());
+ }
+ }
+
+ private void deleteFromS3(final GATKRunReport report) throws Exception {
+ final S3Service s3Service = GATKRunReport.initializeAWSService(downloaderAccessKey, downloaderSecretKey);
+ // Retrieve the whole data object we created previously
+ s3Service.deleteObject(report.getS3ReportBucket(), report.getReportFileName());
+ }
+
+ @DataProvider(name = "PostReportByType")
+ public Object[][] makePostReportByType() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final GATKRunReport.PhoneHomeOption et : GATKRunReport.PhoneHomeOption.values() ) {
+ tests.add(new Object[]{et});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = ! DEBUG, dataProvider = "PostReportByType", timeOut = S3_PUT_TIMEOUT_IN_MILLISECONDS_FOR_TESTING * 2)
+ public void testPostReportByType(final GATKRunReport.PhoneHomeOption type) {
+ final GATKRunReport report = new GATKRunReport(walker, exception, engine, GATKRunReport.PhoneHomeOption.AWS, S3_PUT_TIMEOUT_IN_MILLISECONDS_FOR_TESTING);
+ Assert.assertFalse(report.exceptionOccurredDuringPost(), "An exception occurred during posting the report");
+ final boolean succeeded = report.postReport(type);
+
+ if ( type == GATKRunReport.PhoneHomeOption.NO_ET )
+ Assert.assertFalse(succeeded, "NO_ET option shouldn't write a report");
+ else {
+ Assert.assertTrue(succeeded, "Any non NO_ET option should succeed in writing a report");
+
+ if ( type == GATKRunReport.PhoneHomeOption.STDOUT ) {
+ // nothing to do
+ } else {
+ // must have gone to AWS
+ try {
+ Assert.assertTrue(report.wentToAWS(), "The report should have gone to AWS but the report says it wasn't");
+ deleteFromS3(report);
+ } catch ( Exception e ) {
+ Assert.fail("Failed delete GATK report " + report.getReportFileName() + " with exception " + e);
+ }
+ }
+ }
+ }
+
+ public interface S3Op {
+ public void apply() throws ServiceException;
+ }
+
+ // Will fail with timeout if AWS time out isn't working
+ // Will fail with exception if AWS doesn't protect itself from errors
+ @Test(timeOut = S3_PUT_TIMEOUT_IN_MILLISECONDS_FOR_TESTING * 2)
+ public void testAWSPublicKeyHasAccessControls() throws Exception {
+ final GATKRunReport report = new GATKRunReport(walker, exception, engine, GATKRunReport.PhoneHomeOption.AWS, S3_PUT_TIMEOUT_IN_MILLISECONDS_FOR_TESTING);
+ report.sendAWSToTestBucket();
+ final S3Object s3Object = report.postReportToAWSS3();
+ Assert.assertNotNull(s3Object, "Upload to AWS failed, s3Object was null. error was " + report.formatError());
+
+ // create a service with the public key, and make sure it cannot list or delete
+ final S3Service s3Service = GATKRunReport.initializeAWSService(GATKRunReport.getAWSUploadAccessKey(), GATKRunReport.getAWSUploadSecretKey());
+ assertOperationNotAllowed("listAllBuckets", new S3Op() {
+ @Override
+ public void apply() throws S3ServiceException {
+ s3Service.listAllBuckets();
+ }
+ });
+ assertOperationNotAllowed("listBucket", new S3Op() {
+ @Override
+ public void apply() throws S3ServiceException { s3Service.listObjects(report.getS3ReportBucket()); }
+ });
+ assertOperationNotAllowed("createBucket", new S3Op() {
+ @Override
+ public void apply() throws S3ServiceException { s3Service.createBucket("ShouldNotCreate"); }
+ });
+ assertOperationNotAllowed("deleteObject", new S3Op() {
+ @Override
+ public void apply() throws ServiceException { s3Service.deleteObject(report.getS3ReportBucket(), report.getReportFileName()); }
+ });
+ }
+
+ private void assertOperationNotAllowed(final String name, final S3Op op) {
+ try {
+ op.apply();
+ // only gets here if the operation was successful
+ Assert.fail("Operation " + name + " ran successfully but we expected to it fail");
+ } catch ( ServiceException e ) {
+ Assert.assertEquals(e.getErrorCode(), "AccessDenied");
+ }
+ }
+
+ class RunReportDummyActiveRegionWalker extends ActiveRegionWalker<Integer, Integer> {
+ @Override
+ public ActivityProfileState isActive(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ return new ActivityProfileState(ref.getLocus(), 0.0);
+ }
+
+ @Override
+ public Integer map(ActiveRegion activeRegion, RefMetaDataTracker metaDataTracker) {
+ return 0;
+ }
+
+ @Override
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ @Override
+ public Integer reduce(Integer value, Integer sum) {
+ return 0;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/RefMetaDataTrackerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/RefMetaDataTrackerUnitTest.java
new file mode 100644
index 0000000..f25ab8d
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/RefMetaDataTrackerUnitTest.java
@@ -0,0 +1,290 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata;
+
+import htsjdk.samtools.SAMFileHeader;
+import org.apache.log4j.Logger;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.commandline.RodBinding;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.utils.codecs.table.TableFeature;
+import org.broadinstitute.gatk.engine.refdata.utils.GATKFeature;
+import org.broadinstitute.gatk.engine.refdata.utils.RODRecordList;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+import org.testng.Assert;
+import org.testng.annotations.*;
+import java.util.*;
+import java.util.List;
+
+public class RefMetaDataTrackerUnitTest {
+ final protected static Logger logger = Logger.getLogger(RefMetaDataTrackerUnitTest.class);
+ private static SAMFileHeader header;
+ private ReferenceContext context;
+ private GenomeLocParser genomeLocParser;
+ private GenomeLoc locus;
+ private final static int START_POS = 10;
+ Allele A,C,G,T;
+ VariantContext AC_SNP, AG_SNP, AT_SNP;
+ TableFeature span10_10, span1_20, span10_20;
+
+ @BeforeClass
+ public void beforeClass() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 100);
+ genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ locus = genomeLocParser.createGenomeLoc("chr1", START_POS, START_POS);
+ context = new ReferenceContext(genomeLocParser, locus, (byte)'A');
+ A = Allele.create("A", true);
+ C = Allele.create("C");
+ G = Allele.create("G");
+ T = Allele.create("T");
+ AC_SNP = new VariantContextBuilder("x", "chr1", START_POS, START_POS, Arrays.asList(A, C)).make();
+ AG_SNP = new VariantContextBuilder("x", "chr1", START_POS, START_POS, Arrays.asList(A, G)).make();
+ AT_SNP = new VariantContextBuilder("x", "chr1", START_POS, START_POS, Arrays.asList(A, T)).make();
+ span10_10 = makeSpan(10, 10);
+ span1_20 = makeSpan(1, 20);
+ span10_20 = makeSpan(10, 20);
+ }
+
+ @BeforeMethod
+ public void reset() {
+ RodBinding.resetNameCounter();
+ }
+
+ private class MyTest extends BaseTest.TestDataProvider {
+ public RODRecordList AValues, BValues;
+
+ private MyTest(Class c, final List<? extends Feature> AValues, final List<? extends Feature> BValues) {
+ super(c);
+ this.AValues = AValues == null ? null : makeRODRecord("A", AValues);
+ this.BValues = BValues == null ? null : makeRODRecord("B", BValues);
+ }
+
+ private MyTest(final List<? extends Feature> AValues, final List<? extends Feature> BValues) {
+ super(MyTest.class);
+ this.AValues = AValues == null ? null : makeRODRecord("A", AValues);
+ this.BValues = BValues == null ? null : makeRODRecord("B", BValues);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("A=%s, B=%s", AValues, BValues);
+ }
+
+ private final RODRecordList makeRODRecord(String name, List<? extends Feature> features) {
+ List<GATKFeature> x = new ArrayList<GATKFeature>();
+ for ( Feature f : features )
+ x.add(new GATKFeature.TribbleGATKFeature(genomeLocParser, f, name));
+ return new RODRecordListImpl(name, x, locus);
+ }
+
+ public List<GATKFeature> expected(String name) {
+ if ( name.equals("A+B") ) return allValues();
+ if ( name.equals("A") ) return expectedAValues();
+ if ( name.equals("B") ) return expectedBValues();
+ throw new RuntimeException("FAIL");
+ }
+
+ public List<GATKFeature> allValues() {
+ List<GATKFeature> x = new ArrayList<GATKFeature>();
+ x.addAll(expectedAValues());
+ x.addAll(expectedBValues());
+ return x;
+ }
+
+ public List<GATKFeature> expectedAValues() {
+ return AValues == null ? Collections.<GATKFeature>emptyList() : AValues;
+ }
+
+ public List<GATKFeature> expectedBValues() {
+ return BValues == null ? Collections.<GATKFeature>emptyList() : BValues;
+ }
+
+ public RefMetaDataTracker makeTracker() {
+ List<RODRecordList> x = new ArrayList<RODRecordList>();
+ if ( AValues != null ) x.add(AValues);
+ if ( BValues != null ) x.add(BValues);
+ return new RefMetaDataTracker(x);
+ }
+
+ public int nBoundTracks() {
+ int n = 0;
+ if ( AValues != null ) n++;
+ if ( BValues != null ) n++;
+ return n;
+ }
+ }
+
+ private final TableFeature makeSpan(int start, int stop) {
+ return new TableFeature(genomeLocParser.createGenomeLoc("chr1", start, stop),
+ Collections.<String>emptyList(), Collections.<String>emptyList());
+ }
+
+ @DataProvider(name = "tests")
+ public Object[][] createTests() {
+ new MyTest(null, null);
+ new MyTest(Arrays.asList(AC_SNP), null);
+ new MyTest(Arrays.asList(AC_SNP, AT_SNP), null);
+ new MyTest(Arrays.asList(AC_SNP), Arrays.asList(AG_SNP));
+ new MyTest(Arrays.asList(AC_SNP, AT_SNP), Arrays.asList(AG_SNP));
+ new MyTest(Arrays.asList(AC_SNP, AT_SNP), Arrays.asList(span10_10));
+ new MyTest(Arrays.asList(AC_SNP, AT_SNP), Arrays.asList(span10_10, span10_20));
+ new MyTest(Arrays.asList(AC_SNP, AT_SNP), Arrays.asList(span10_10, span10_20, span1_20));
+
+ // for requires starts
+ new MyTest(Arrays.asList(span1_20), null);
+ new MyTest(Arrays.asList(span10_10, span10_20), null);
+ new MyTest(Arrays.asList(span10_10, span10_20, span1_20), null);
+
+ return MyTest.getTests(MyTest.class);
+ }
+
+ @Test(enabled = true, dataProvider = "tests")
+ public void testRawBindings(MyTest test) {
+ logger.warn("Testing " + test + " for number of bound tracks");
+ RefMetaDataTracker tracker = test.makeTracker();
+ Assert.assertEquals(tracker.getNTracksWithBoundFeatures(), test.nBoundTracks());
+
+ testSimpleBindings("A", tracker, test.AValues);
+ testSimpleBindings("B", tracker, test.BValues);
+ }
+
+ private <T> void testSimpleBindings(String name, RefMetaDataTracker tracker, RODRecordList expected) {
+ List<Feature> asValues = tracker.getValues(Feature.class, name);
+
+ Assert.assertEquals(tracker.hasValues(name), expected != null);
+ Assert.assertEquals(asValues.size(), expected == null ? 0 : expected.size());
+
+ if ( expected != null ) {
+ for ( GATKFeature e : expected ) {
+ boolean foundValue = false;
+ for ( Feature f : asValues ) {
+ if ( e.getUnderlyingObject() == f ) foundValue = true;
+ }
+ Assert.assertTrue(foundValue, "Never found expected value of " + e.getUnderlyingObject() + " bound to " + name + " in " + tracker);
+ }
+ }
+ }
+
+ @Test(enabled = true, dataProvider = "tests")
+ public void testGettersAsString(MyTest test) {
+ logger.warn("Testing " + test + " for get() methods");
+ RefMetaDataTracker tracker = test.makeTracker();
+
+ for ( String name : Arrays.asList("A+B", "A", "B") ) {
+ List<Feature> v1 = name.equals("A+B") ? tracker.getValues(Feature.class) : tracker.getValues(Feature.class, name);
+ testGetter(name, v1, test.expected(name), true, tracker);
+
+ List<Feature> v2 = name.equals("A+B") ? tracker.getValues(Feature.class, locus) : tracker.getValues(Feature.class, name, locus);
+ testGetter(name, v2, startingHere(test.expected(name)), true, tracker);
+
+ Feature v3 = name.equals("A+B") ? tracker.getFirstValue(Feature.class) : tracker.getFirstValue(Feature.class, name);
+ testGetter(name, Arrays.asList(v3), test.expected(name), false, tracker);
+
+ Feature v4 = name.equals("A+B") ? tracker.getFirstValue(Feature.class, locus) : tracker.getFirstValue(Feature.class, name, locus);
+ testGetter(name, Arrays.asList(v4), startingHere(test.expected(name)), false, tracker);
+ }
+ }
+
+ @Test(enabled = true, dataProvider = "tests")
+ public void testGettersAsRodBindings(MyTest test) {
+ logger.warn("Testing " + test + " for get() methods as RodBindings");
+ RefMetaDataTracker tracker = test.makeTracker();
+
+ for ( String nameAsString : Arrays.asList("A", "B") ) {
+ RodBinding<Feature> binding = new RodBinding<Feature>(Feature.class, nameAsString, "none", "vcf", new Tags());
+ List<Feature> v1 = tracker.getValues(binding);
+ testGetter(nameAsString, v1, test.expected(nameAsString), true, tracker);
+
+ List<Feature> v2 = tracker.getValues(binding, locus);
+ testGetter(nameAsString, v2, startingHere(test.expected(nameAsString)), true, tracker);
+
+ Feature v3 = tracker.getFirstValue(binding);
+ testGetter(nameAsString, Arrays.asList(v3), test.expected(nameAsString), false, tracker);
+
+ Feature v4 = tracker.getFirstValue(binding, locus);
+ testGetter(nameAsString, Arrays.asList(v4), startingHere(test.expected(nameAsString)), false, tracker);
+ }
+ }
+
+ @Test(enabled = true, dataProvider = "tests")
+ public void testGettersAsListOfRodBindings(MyTest test) {
+ logger.warn("Testing " + test + " for get() methods for List<RodBindings>");
+ RefMetaDataTracker tracker = test.makeTracker();
+
+ String nameAsString = "A+B";
+ RodBinding<Feature> A = new RodBinding<Feature>(Feature.class, "A", "none", "vcf", new Tags());
+ RodBinding<Feature> B = new RodBinding<Feature>(Feature.class, "B", "none", "vcf", new Tags());
+ List<RodBinding<Feature>> binding = Arrays.asList(A, B);
+
+ List<Feature> v1 = tracker.getValues(binding);
+ testGetter(nameAsString, v1, test.expected(nameAsString), true, tracker);
+
+ List<Feature> v2 = tracker.getValues(binding, locus);
+ testGetter(nameAsString, v2, startingHere(test.expected(nameAsString)), true, tracker);
+
+ Feature v3 = tracker.getFirstValue(binding);
+ testGetter(nameAsString, Arrays.asList(v3), test.expected(nameAsString), false, tracker);
+
+ Feature v4 = tracker.getFirstValue(binding, locus);
+ testGetter(nameAsString, Arrays.asList(v4), startingHere(test.expected(nameAsString)), false, tracker);
+ }
+
+ private List<GATKFeature> startingHere(List<GATKFeature> l) {
+ List<GATKFeature> x = new ArrayList<GATKFeature>();
+ for ( GATKFeature f : l ) if ( f.getStart() == locus.getStart() ) x.add(f);
+ return x;
+ }
+
+ private void testGetter(String name, List<Feature> got, List<GATKFeature> expected, boolean requireExact, RefMetaDataTracker tracker) {
+ if ( got.size() == 1 && got.get(0) == null )
+ got = Collections.emptyList();
+
+ if ( requireExact )
+ Assert.assertEquals(got.size(), expected.size());
+
+ boolean foundAny = false;
+ for ( GATKFeature e : expected ) {
+ boolean found1 = false;
+ for ( Feature got1 : got ) {
+ if ( e.getUnderlyingObject() == got1 )
+ found1 = true;
+ }
+ if ( requireExact )
+ Assert.assertTrue(found1, "Never found expected GATKFeature " + e + " bound to " + name + " in " + tracker);
+ foundAny = found1 || foundAny;
+ }
+
+ if ( ! requireExact && ! expected.isEmpty() )
+ Assert.assertTrue(foundAny, "Never found any got values matching one of the expected values bound to " + name + " in " + tracker);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/tracks/FeatureManagerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/tracks/FeatureManagerUnitTest.java
new file mode 100644
index 0000000..ec3b470
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/tracks/FeatureManagerUnitTest.java
@@ -0,0 +1,163 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.tracks;
+
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.tribble.Feature;
+import htsjdk.tribble.FeatureCodec;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.codecs.table.BedTableCodec;
+import org.broadinstitute.gatk.utils.codecs.table.TableFeature;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import htsjdk.variant.vcf.VCF3Codec;
+import htsjdk.variant.vcf.VCFCodec;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import htsjdk.variant.variantcontext.VariantContext;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.*;
+import java.util.*;
+
+
+/**
+ * @author depristo
+ *
+ * UnitTests for RMD FeatureManager
+ */
+public class FeatureManagerUnitTest extends BaseTest {
+ private static final File RANDOM_FILE = new File(publicTestDir+ "exampleGATKReport.eval");
+ private static final File VCF3_FILE = new File(privateTestDir + "vcf3.vcf");
+ private static final File VCF4_FILE = new File(privateTestDir + "HiSeq.10000.vcf");
+ private static final File VCF4_FILE_GZ = new File(privateTestDir + "HiSeq.10000.vcf.gz");
+ private static final File VCF4_FILE_BGZIP = new File(privateTestDir + "HiSeq.10000.bgzip.vcf.gz");
+
+ private FeatureManager manager;
+ private GenomeLocParser genomeLocParser;
+
+ @BeforeMethod
+ public void setup() {
+ File referenceFile = new File(b36KGReference);
+ try {
+ IndexedFastaSequenceFile seq = new CachingIndexedFastaSequenceFile(referenceFile);
+ genomeLocParser = new GenomeLocParser(seq);
+ manager = new FeatureManager();
+ }
+ catch(FileNotFoundException ex) {
+ throw new UserException.CouldNotReadInputFile(referenceFile,ex);
+ }
+ }
+
+ @Test
+ public void testManagerCreation() {
+ Assert.assertTrue(manager.getFeatureDescriptors().size() > 0);
+ }
+
+ private class FMTest extends BaseTest.TestDataProvider {
+ public Class codec;
+ public Class<? extends Feature> feature;
+ public String name;
+ public File associatedFile;
+
+ private FMTest(final Class feature, final Class codec, final String name, final File file) {
+ super(FMTest.class);
+ this.codec = codec;
+ this.feature = feature;
+ this.name = name;
+ this.associatedFile = file;
+ }
+
+ public void assertExpected(FeatureManager.FeatureDescriptor featureDescriptor) {
+ Assert.assertEquals(featureDescriptor.getCodecClass(), codec);
+ Assert.assertEquals(featureDescriptor.getFeatureClass(), feature);
+ Assert.assertEquals(featureDescriptor.getName().toLowerCase(), name.toLowerCase());
+ }
+
+ public String toString() {
+ return String.format("FMTest name=%s codec=%s feature=%s file=%s",
+ name, codec.getSimpleName(), feature.getSimpleName(), associatedFile);
+ }
+ }
+
+ @DataProvider(name = "tests")
+ public Object[][] createTests() {
+ new FMTest(VariantContext.class, VCF3Codec.class, "VCF3", VCF3_FILE);
+ new FMTest(VariantContext.class, VCFCodec.class, "VCF", VCF4_FILE);
+ new FMTest(VariantContext.class, VCFCodec.class, "VCF", VCF4_FILE_GZ);
+ new FMTest(VariantContext.class, VCFCodec.class, "VCF", VCF4_FILE_BGZIP);
+ new FMTest(TableFeature.class, BedTableCodec.class, "bedtable", null);
+ return FMTest.getTests(FMTest.class);
+ }
+
+ @Test(dataProvider = "tests")
+ public void testGetByFile(FMTest params) {
+ if ( params.associatedFile != null ) {
+ FeatureManager.FeatureDescriptor byFile = manager.getByFiletype(params.associatedFile);
+ Assert.assertNotNull(byFile, "Couldn't find any type associated with file " + params.associatedFile);
+ params.assertExpected(byFile);
+ }
+ }
+
+ @Test
+ public void testGetByFileNoMatch() {
+ FeatureManager.FeatureDescriptor byFile = manager.getByFiletype(RANDOM_FILE);
+ Assert.assertNull(byFile, "Found type " + byFile + " associated with RANDOM, non-Tribble file " + RANDOM_FILE);
+ }
+
+ @Test(dataProvider = "tests")
+ public void testGetters(FMTest params) {
+ params.assertExpected(manager.getByCodec(params.codec));
+ params.assertExpected(manager.getByName(params.name));
+ params.assertExpected(manager.getByName(params.name.toLowerCase()));
+ params.assertExpected(manager.getByName(params.name.toUpperCase()));
+
+ Collection<FeatureManager.FeatureDescriptor> descriptors = manager.getByFeature(params.feature);
+ Assert.assertTrue(descriptors.size() > 0, "Look up by FeatureClass failed");
+ }
+
+ @Test
+ public void testUserFriendlyList() {
+ Assert.assertTrue(manager.userFriendlyListOfAvailableFeatures().length() > 0, "Expected at least one codec to be listed");
+ Assert.assertTrue(manager.userFriendlyListOfAvailableFeatures().split(",").length > 0, "Expected at least two codecs, but only saw one");
+ }
+
+ @Test
+ public void testCodecCreation() {
+ FeatureManager.FeatureDescriptor descriptor = manager.getByName("vcf");
+ Assert.assertNotNull(descriptor, "Couldn't find VCF feature descriptor!");
+
+ FeatureCodec c = manager.createCodec(descriptor, "foo", genomeLocParser, null);
+ Assert.assertNotNull(c, "Couldn't create codec");
+ Assert.assertEquals(c.getClass(), descriptor.getCodecClass());
+ Assert.assertEquals(c.getFeatureType(), descriptor.getFeatureClass());
+ }
+
+}
+
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/tracks/RMDTrackBuilderUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/tracks/RMDTrackBuilderUnitTest.java
new file mode 100644
index 0000000..a64773a
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/tracks/RMDTrackBuilderUnitTest.java
@@ -0,0 +1,190 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.tracks;
+
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.tribble.Tribble;
+import htsjdk.tribble.index.Index;
+import htsjdk.tribble.util.LittleEndianOutputStream;
+import htsjdk.variant.vcf.VCFCodec;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+
+import org.testng.annotations.BeforeMethod;
+
+import org.testng.annotations.Test;
+
+import java.io.*;
+import java.nio.channels.FileChannel;
+
+
+/**
+ * @author aaron
+ * <p/>
+ * Class RMDTrackBuilderUnitTest
+ * <p/>
+ * Testing out the builder for tribble Tracks
+ */
+public class RMDTrackBuilderUnitTest extends BaseTest {
+ private RMDTrackBuilder builder;
+ private IndexedFastaSequenceFile seq;
+ private GenomeLocParser genomeLocParser;
+
+ @BeforeMethod
+ public void setup() {
+ File referenceFile = new File(b37KGReference);
+ try {
+ seq = new CachingIndexedFastaSequenceFile(referenceFile);
+ }
+ catch(FileNotFoundException ex) {
+ throw new UserException.CouldNotReadInputFile(referenceFile,ex);
+ }
+ genomeLocParser = new GenomeLocParser(seq);
+
+ // We have to disable auto-index creation/locking in the RMDTrackBuilder for tests,
+ // as the lock acquisition calls were intermittently hanging on our farm. This unfortunately
+ // means that we can't include tests for the auto-index creation feature.
+ builder = new RMDTrackBuilder(seq.getSequenceDictionary(),genomeLocParser,null,true,null);
+ }
+
+ @Test
+ public void testBuilder() {
+ Assert.assertTrue(builder.getFeatureManager().getFeatureDescriptors().size() > 0);
+ }
+
+ @Test
+ public void testDisableAutoIndexGeneration() throws IOException {
+ final File unindexedVCF = new File(privateTestDir + "unindexed.vcf");
+ final File unindexedVCFIndex = Tribble.indexFile(unindexedVCF);
+
+ Index index = builder.loadIndex(unindexedVCF, new VCFCodec());
+
+ Assert.assertFalse(unindexedVCFIndex.exists());
+ Assert.assertNotNull(index);
+ }
+
+ @Test
+ public void testLoadOnDiskIndex() {
+ final File originalVCF = new File(privateTestDir + "vcf4.1.example.vcf");
+ final File tempVCFWithCorrectIndex = createTempVCFFileAndIndex(originalVCF, false);
+ final File tempVCFIndexFile = Tribble.indexFile(tempVCFWithCorrectIndex);
+
+ final Index index = builder.loadFromDisk(tempVCFWithCorrectIndex, tempVCFIndexFile);
+
+ Assert.assertNotNull(index);
+ Assert.assertTrue(tempVCFIndexFile.exists());
+
+ final Index inMemoryIndex = builder.createIndexInMemory(tempVCFWithCorrectIndex, new VCFCodec());
+ Assert.assertTrue(index.equalsIgnoreProperties(inMemoryIndex));
+ }
+
+ @Test
+ public void testLoadOnDiskOutdatedIndex() {
+ final File originalVCF = new File(privateTestDir + "vcf4.1.example.vcf");
+ final File tempVCFWithOutdatedIndex = createTempVCFFileAndIndex(originalVCF, true);
+ final File tempVCFIndexFile = Tribble.indexFile(tempVCFWithOutdatedIndex);
+
+ final Index index = builder.loadFromDisk(tempVCFWithOutdatedIndex, tempVCFIndexFile);
+
+ // loadFromDisk() should return null to indicate that the index is outdated and should not be used,
+ // but should not delete the index since our builder has disableAutoIndexCreation set to true
+ Assert.assertNull(index);
+ Assert.assertTrue(tempVCFIndexFile.exists());
+ }
+
+ /**
+ * Create a temporary vcf file and an associated index file, which may be set to be out-of-date
+ * relative to the vcf
+ *
+ * @param vcfFile the vcf file
+ * @param createOutOfDateIndex if true, ensure that the temporary vcf file is modified after the index
+ * @return a file pointing to the new tmp location, with accompanying index
+ */
+ private File createTempVCFFileAndIndex( final File vcfFile, final boolean createOutOfDateIndex ) {
+ try {
+ final File tmpFile = createTempFile("RMDTrackBuilderUnitTest", "");
+ final File tmpIndex = Tribble.indexFile(tmpFile);
+ tmpIndex.deleteOnExit();
+
+ copyFile(vcfFile, tmpFile);
+ final Index inMemoryIndex = builder.createIndexInMemory(tmpFile, new VCFCodec());
+ final LittleEndianOutputStream indexOutputStream = new LittleEndianOutputStream(new FileOutputStream(tmpIndex));
+
+ // If requested, modify the tribble file after the index. Otherwise, modify the index last.
+ if ( createOutOfDateIndex ) {
+ inMemoryIndex.write(indexOutputStream);
+ indexOutputStream.close();
+ Thread.sleep(2000);
+ copyFile(vcfFile, tmpFile);
+ }
+ else {
+ copyFile(vcfFile, tmpFile);
+ Thread.sleep(2000);
+ inMemoryIndex.write(indexOutputStream);
+ indexOutputStream.close();
+ }
+
+ return tmpFile;
+ } catch (IOException e) {
+ Assert.fail("Unable to create temperary file");
+ } catch (InterruptedException e) {
+ Assert.fail("Somehow our thread got interrupted");
+ }
+ return null;
+ }
+
+ /**
+ * copy a file, from http://www.exampledepot.com/egs/java.nio/File2File.html
+ *
+ * @param srFile the source file
+ * @param dtFile the destination file
+ */
+ private static void copyFile(File srFile, File dtFile) {
+ try {
+ // Create channel on the source
+ FileChannel srcChannel = new FileInputStream(srFile).getChannel();
+
+ // Create channel on the destination
+ FileChannel dstChannel = new FileOutputStream(dtFile).getChannel();
+
+ // Copy file contents from source to destination
+ dstChannel.transferFrom(srcChannel, 0, srcChannel.size());
+
+ // Close the channels
+ srcChannel.close();
+ dstChannel.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ Assert.fail("Unable to process copy " + e.getMessage());
+ }
+ }
+
+}
+
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/CheckableCloseableTribbleIterator.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/CheckableCloseableTribbleIterator.java
new file mode 100644
index 0000000..e77c079
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/CheckableCloseableTribbleIterator.java
@@ -0,0 +1,90 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.utils;
+
+import htsjdk.tribble.CloseableTribbleIterator;
+import htsjdk.tribble.Feature;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Adapter to allow checking if the wrapped iterator was closed.
+ * Creating an CCTI also adds it to the list returned from getThreadIterators().
+ * @param <T> feature
+ */
+public class CheckableCloseableTribbleIterator<T extends Feature> implements CloseableTribbleIterator<T> {
+ private final CloseableTribbleIterator<T> iterator;
+ private boolean closed = false;
+
+ private static ThreadLocal<List<CheckableCloseableTribbleIterator<? extends Feature>>> threadIterators =
+ new ThreadLocal<List<CheckableCloseableTribbleIterator<? extends Feature>>>() {
+ @Override
+ protected List<CheckableCloseableTribbleIterator<? extends Feature>> initialValue() {
+ return new ArrayList<CheckableCloseableTribbleIterator<? extends Feature>>();
+ }
+ };
+
+ public CheckableCloseableTribbleIterator(CloseableTribbleIterator<T> iterator) {
+ this.iterator = iterator;
+ threadIterators.get().add(this);
+ }
+
+ /**
+ * Returns the list of iterators created on this thread since the last time clearCreatedIterators() was called.
+ * @return the list of iterators created on this thread since the last time clearCreatedIterators() was called.
+ */
+ public static List<CheckableCloseableTribbleIterator<? extends Feature>> getThreadIterators() {
+ return threadIterators.get();
+ }
+
+ /**
+ * Clears the tracked list of iterators created on this thread.
+ */
+ public static void clearThreadIterators() {
+ threadIterators.get().clear();
+ }
+
+ @Override
+ public void close() {
+ iterator.close();
+ this.closed = true;
+ }
+
+ /**
+ * Returns true if this iterator was properly closed.
+ * @return true if this iterator was properly closed.
+ */
+ public boolean isClosed() {
+ return closed;
+ }
+
+ @Override public Iterator<T> iterator() { return this; }
+ @Override public boolean hasNext() { return iterator.hasNext(); }
+ @Override public T next() { return iterator.next(); }
+ @Override public void remove() { iterator.remove(); }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/FeatureToGATKFeatureIteratorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/FeatureToGATKFeatureIteratorUnitTest.java
new file mode 100644
index 0000000..d95c320
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/FeatureToGATKFeatureIteratorUnitTest.java
@@ -0,0 +1,61 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.utils;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import htsjdk.variant.vcf.VCFCodec;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+public class FeatureToGATKFeatureIteratorUnitTest extends BaseTest {
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testCloseFilePointers() throws IOException {
+ final String chr = "20";
+ IndexedFastaSequenceFile seq = new CachingIndexedFastaSequenceFile(new File(BaseTest.hg19Reference));
+ GenomeLocParser parser = new GenomeLocParser(seq);
+ File file = new File(privateTestDir + "NA12878.hg19.example1.vcf");
+ VCFCodec codec = new VCFCodec();
+ TestFeatureReader reader = new TestFeatureReader(file.getAbsolutePath(), codec);
+ CheckableCloseableTribbleIterator<Feature> tribbleIterator = reader.query(chr, 1, 100000);
+ FeatureToGATKFeatureIterator gatkIterator = new FeatureToGATKFeatureIterator(parser, tribbleIterator, "test");
+ Assert.assertTrue(gatkIterator.hasNext(), "GATK feature iterator does not have a next value.");
+ GenomeLoc gatkLocation = gatkIterator.next().getLocation();
+ Assert.assertEquals(gatkLocation.getContig(), chr, "Instead of chr 20 rod iterator was at location " + gatkLocation);
+ Assert.assertFalse(tribbleIterator.isClosed(), "Tribble iterator is closed but should be still open.");
+ gatkIterator.close();
+ Assert.assertTrue(tribbleIterator.isClosed(), "Tribble iterator is open but should be now closed.");
+ reader.close();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/FlashBackIteratorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/FlashBackIteratorUnitTest.java
new file mode 100644
index 0000000..7aa07ef
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/FlashBackIteratorUnitTest.java
@@ -0,0 +1,364 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.utils;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMSequenceDictionary;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.refdata.ReferenceOrderedDatum;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+
+import org.testng.annotations.BeforeMethod;
+
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * @author aaron
+ * <p/>
+ * Class FlashBackIteratorUnitTest
+ * <p/>
+ * just like a greatful dead show...this will be prone to flashbacks
+ */
+public class FlashBackIteratorUnitTest extends BaseTest {
+ private SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(NUMBER_OF_CHROMOSOMES, STARTING_CHROMOSOME, CHROMOSOME_SIZE);
+ private static final int NUMBER_OF_CHROMOSOMES = 5;
+ private static final int STARTING_CHROMOSOME = 1;
+ private static final int CHROMOSOME_SIZE = 1000;
+
+ private String firstContig;
+ private GenomeLocParser genomeLocParser;
+
+ @BeforeMethod
+ public void setup() {
+ genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ firstContig = header.getSequenceDictionary().getSequence(0).getSequenceName();
+ }
+
+ @Test
+ public void testBasicIteration() {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc(firstContig, 0, 0);
+ FlashBackIterator iter = new FlashBackIterator(new FakeSeekableRODIterator(genomeLocParser,loc));
+ GenomeLoc lastLocation = null;
+ for (int x = 0; x < 10; x++) {
+ iter.next();
+ GenomeLoc cur = iter.position();
+ if (lastLocation != null) {
+ Assert.assertTrue(lastLocation.isBefore(cur));
+ }
+ lastLocation = cur;
+ }
+ }
+
+ @Test
+ public void testBasicIterationThenFlashBack() {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc(firstContig, 0, 0);
+ FlashBackIterator iter = new FlashBackIterator(new FakeSeekableRODIterator(genomeLocParser,loc));
+ GenomeLoc lastLocation = null;
+ for (int x = 0; x < 10; x++) {
+ iter.next();
+ GenomeLoc cur = iter.position();
+ if (lastLocation != null) {
+ Assert.assertTrue(lastLocation.isBefore(cur));
+ }
+ lastLocation = cur;
+ }
+ iter.flashBackTo(genomeLocParser.createGenomeLoc(firstContig, 2));
+ }
+
+ @Test
+ public void testBasicIterationThenFlashBackThenIterate() {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc(firstContig, 0, 0);
+ FlashBackIterator iter = new FlashBackIterator(new FakeSeekableRODIterator(genomeLocParser,loc));
+ GenomeLoc lastLocation = null;
+ for (int x = 0; x < 10; x++) {
+ iter.next();
+ GenomeLoc cur = iter.position();
+ if (lastLocation != null) {
+ Assert.assertTrue(lastLocation.isBefore(cur));
+ }
+ lastLocation = cur;
+ }
+ iter.flashBackTo(genomeLocParser.createGenomeLoc(firstContig, 1));
+ int count = 0;
+ while (iter.hasNext()) {
+ count++;
+ iter.next();
+ }
+ Assert.assertEquals(count, 10);
+ }
+
+
+ @Test
+ public void testFlashBackTruth() {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc(firstContig, 0, 0);
+ LocationAwareSeekableRODIterator backIter = new FakeSeekableRODIterator(genomeLocParser,loc);
+ // remove the first three records
+ backIter.next();
+ backIter.next();
+ backIter.next();
+ FlashBackIterator iter = new FlashBackIterator(backIter);
+ GenomeLoc lastLocation = null;
+ for (int x = 0; x < 10; x++) {
+ iter.next();
+ GenomeLoc cur = iter.position();
+ if (lastLocation != null) {
+ Assert.assertTrue(lastLocation.isBefore(cur));
+ }
+ lastLocation = cur;
+ }
+ Assert.assertTrue(iter.canFlashBackTo(genomeLocParser.createGenomeLoc(firstContig, 5)));
+ Assert.assertTrue(iter.canFlashBackTo(genomeLocParser.createGenomeLoc(firstContig, 15)));
+ Assert.assertTrue(!iter.canFlashBackTo(genomeLocParser.createGenomeLoc(firstContig, 2)));
+ Assert.assertTrue(!iter.canFlashBackTo(genomeLocParser.createGenomeLoc(firstContig, 1)));
+ }
+
+ @Test
+ public void testBasicIterationThenFlashBackHalfWayThenIterate() {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc(firstContig, 0, 0);
+ FlashBackIterator iter = new FlashBackIterator(new FakeSeekableRODIterator(genomeLocParser,loc));
+ GenomeLoc lastLocation = null;
+ for (int x = 0; x < 10; x++) {
+ iter.next();
+ GenomeLoc cur = iter.position();
+ if (lastLocation != null) {
+ Assert.assertTrue(lastLocation.isBefore(cur));
+ }
+ lastLocation = cur;
+ }
+ iter.flashBackTo(genomeLocParser.createGenomeLoc(firstContig, 5));
+ int count = 0;
+ while (iter.hasNext()) {
+ count++;
+ iter.next();
+ }
+ Assert.assertEquals(count, 6); // chr1:5, 6, 7, 8, 9, and 10
+ }
+}
+
+
+class FakeSeekableRODIterator implements LocationAwareSeekableRODIterator {
+ private GenomeLocParser genomeLocParser;
+
+ // current location
+ private GenomeLoc location;
+ private FakeRODatum curROD;
+ private int recordCount = 10;
+
+ public FakeSeekableRODIterator(GenomeLocParser genomeLocParser,GenomeLoc startingLoc) {
+ this.genomeLocParser = genomeLocParser;
+ this.location = genomeLocParser.createGenomeLoc(startingLoc.getContig(), startingLoc.getStart() + 1, startingLoc.getStop() + 1);
+ }
+
+ /**
+ * Gets the header associated with the backing input stream.
+ * @return the ROD header.
+ */
+ @Override
+ public Object getHeader() {
+ return null;
+ }
+
+ /**
+ * Gets the sequence dictionary associated with the backing input stream.
+ * @return sequence dictionary from the ROD header.
+ */
+ @Override
+ public SAMSequenceDictionary getSequenceDictionary() {
+ return null;
+ }
+
+
+ @Override
+ public GenomeLoc peekNextLocation() {
+ System.err.println("Peek Next -> " + location);
+ return location;
+ }
+
+ @Override
+ public GenomeLoc position() {
+ return location;
+ }
+
+ @Override
+ public RODRecordList seekForward(GenomeLoc interval) {
+ this.location = interval;
+ return next();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return (recordCount > 0);
+ }
+
+ @Override
+ public RODRecordList next() {
+ RODRecordList list = new FakeRODRecordList();
+ curROD = new FakeRODatum("STUPIDNAME", location);
+ location = genomeLocParser.createGenomeLoc(location.getContig(), location.getStart() + 1, location.getStop() + 1);
+ list.add(curROD);
+ recordCount--;
+ return list;
+ }
+
+ @Override
+ public void remove() {
+ throw new IllegalStateException("GRRR");
+ }
+
+ @Override
+ public void close() {
+ // nothing to do
+ }
+}
+
+
+/** for testing only */
+class FakeRODatum extends GATKFeature implements ReferenceOrderedDatum {
+
+ final GenomeLoc location;
+
+ public FakeRODatum(String name, GenomeLoc location) {
+ super(name);
+ this.location = location;
+ }
+
+ @Override
+ public String getName() {
+ return "false";
+ }
+
+ @Override
+ public boolean parseLine(Object header, String[] parts) throws IOException {
+ return false;
+ }
+
+ @Override
+ public String toSimpleString() {
+ return "";
+ }
+
+ @Override
+ public String repl() {
+ return "";
+ }
+
+ /**
+ * Used by the ROD system to determine how to split input lines
+ *
+ * @return Regex string delimiter separating fields
+ */
+ @Override
+ public String delimiterRegex() {
+ return "";
+ }
+
+ @Override
+ public GenomeLoc getLocation() {
+ return location;
+ }
+
+ @Override
+ public Object getUnderlyingObject() {
+ return this;
+ }
+
+ @Override
+ public int compareTo(ReferenceOrderedDatum that) {
+ return location.compareTo(that.getLocation());
+ }
+
+ /**
+ * Backdoor hook to read header, meta-data, etc. associated with the file. Will be
+ * called by the ROD system before streaming starts
+ *
+ * @param source source data file on disk from which this rod stream will be pulled
+ *
+ * @return a header object that will be passed to parseLine command
+ */
+ @Override
+ public Object initialize(File source) throws FileNotFoundException {
+ return null;
+ }
+
+ @Override
+ public String getChr() {
+ return location.getContig();
+ }
+
+ @Override
+ public int getStart() {
+ return (int)location.getStart();
+ }
+
+ @Override
+ public int getEnd() {
+ return (int)location.getStop();
+ }
+}
+
+class FakeRODRecordList extends AbstractList<GATKFeature> implements RODRecordList {
+ private final List<GATKFeature> list = new ArrayList<GATKFeature>();
+
+ public boolean add(GATKFeature data) {
+ return list.add(data);
+ }
+
+ @Override
+ public GATKFeature get(int i) {
+ return list.get(i);
+ }
+
+ @Override
+ public int size() {
+ return list.size();
+ }
+
+ @Override
+ public GenomeLoc getLocation() {
+ return list.get(0).getLocation();
+ }
+
+ @Override
+ public String getName() {
+ return "test";
+ }
+
+ @Override
+ public int compareTo(RODRecordList rodRecordList) {
+ return this.list.get(0).getLocation().compareTo(rodRecordList.getLocation());
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/TestFeatureReader.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/TestFeatureReader.java
new file mode 100644
index 0000000..90b5e7a
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/TestFeatureReader.java
@@ -0,0 +1,53 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.utils;
+
+import htsjdk.tribble.Feature;
+import htsjdk.tribble.FeatureCodec;
+import htsjdk.tribble.TribbleIndexedFeatureReader;
+
+import java.io.IOException;
+
+/**
+ * Feature reader with additional test utilities. The iterators can be checked to see if they are closed.
+ */
+public class TestFeatureReader extends TribbleIndexedFeatureReader<Feature, Object> {
+ public TestFeatureReader(String featurePath, FeatureCodec codec) throws IOException {
+ super(featurePath, codec, true);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public CheckableCloseableTribbleIterator<Feature> iterator() throws IOException {
+ return new CheckableCloseableTribbleIterator<Feature>(super.iterator());
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public CheckableCloseableTribbleIterator<Feature> query(String chr, int start, int end) throws IOException {
+ return new CheckableCloseableTribbleIterator<Feature>(super.query(chr, start, end));
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/TestRMDTrackBuilder.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/TestRMDTrackBuilder.java
new file mode 100644
index 0000000..17179f3
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/refdata/utils/TestRMDTrackBuilder.java
@@ -0,0 +1,71 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.refdata.utils;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.tribble.FeatureCodec;
+import htsjdk.tribble.Tribble;
+import htsjdk.tribble.index.Index;
+import org.broadinstitute.gatk.engine.refdata.tracks.FeatureManager;
+import org.broadinstitute.gatk.engine.refdata.tracks.IndexDictionaryUtils;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrack;
+import org.broadinstitute.gatk.engine.refdata.tracks.RMDTrackBuilder;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Extension of RMDTrackBuilder that creates TestFeatureReader's which in turn create CheckableCloseableTribbleIterator's.
+ */
+public class TestRMDTrackBuilder extends RMDTrackBuilder {
+ private GenomeLocParser genomeLocParser;
+
+ public TestRMDTrackBuilder(SAMSequenceDictionary dict, GenomeLocParser genomeLocParser) {
+ // disable auto-index creation/locking in the RMDTrackBuilder for tests
+ super(dict, genomeLocParser, null, true, null);
+ this.genomeLocParser = genomeLocParser;
+ }
+
+ @Override
+ public RMDTrack createInstanceOfTrack(RMDTriplet fileDescriptor) {
+ String name = fileDescriptor.getName();
+ File inputFile = new File(fileDescriptor.getFile());
+ FeatureManager.FeatureDescriptor descriptor = getFeatureManager().getByTriplet(fileDescriptor);
+ FeatureCodec codec = getFeatureManager().createCodec(descriptor, name, genomeLocParser, null);
+ TestFeatureReader featureReader;
+ Index index;
+ try {
+ // Create a feature reader that creates checkable tribble iterators.
+ index = loadIndex(inputFile, codec);
+ featureReader = new TestFeatureReader(inputFile.getAbsolutePath(), codec);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ SAMSequenceDictionary sequenceDictionary = IndexDictionaryUtils.getSequenceDictionaryFromProperties(index);
+ return new RMDTrack(descriptor.getCodecClass(), name, inputFile, featureReader, sequenceDictionary, genomeLocParser, codec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/report/GATKReportUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/report/GATKReportUnitTest.java
new file mode 100644
index 0000000..c28e901
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/report/GATKReportUnitTest.java
@@ -0,0 +1,285 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.report;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Random;
+import java.io.FileInputStream;
+import java.io.DataInputStream;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+
+public class GATKReportUnitTest extends BaseTest {
+ @Test
+ public void testParse() throws Exception {
+ String reportPath = publicTestDir + "exampleGATKReportv2.tbl";
+ GATKReport report = new GATKReport(reportPath);
+ Assert.assertEquals(report.getVersion(), GATKReportVersion.V1_1);
+ Assert.assertEquals(report.getTables().size(), 5);
+
+ GATKReportTable countVariants = report.getTable("CountVariants");
+ Assert.assertEquals(countVariants.get(0, "nProcessedLoci"), "63025520");
+ Assert.assertEquals(countVariants.get(0, "nNoCalls"), "0");
+ Assert.assertEquals(countVariants.get(0, "heterozygosity"), 4.73e-06);
+
+ GATKReportTable validationReport = report.getTable("ValidationReport");
+ Assert.assertEquals(validationReport.get(2, "PPV"), Double.NaN);
+ }
+
+ @DataProvider(name = "rightAlignValues")
+ public Object[][] getRightAlignValues() {
+ return new Object[][]{
+ new Object[]{null, true},
+ new Object[]{"null", true},
+ new Object[]{"NA", true},
+ new Object[]{"0", true},
+ new Object[]{"0.0", true},
+ new Object[]{"-0", true},
+ new Object[]{"-0.0", true},
+ new Object[]{String.valueOf(Long.MAX_VALUE), true},
+ new Object[]{String.valueOf(Long.MIN_VALUE), true},
+ new Object[]{String.valueOf(Float.MIN_NORMAL), true},
+ new Object[]{String.valueOf(Double.MAX_VALUE), true},
+ new Object[]{String.valueOf(Double.MIN_VALUE), true},
+ new Object[]{String.valueOf(Double.POSITIVE_INFINITY), true},
+ new Object[]{String.valueOf(Double.NEGATIVE_INFINITY), true},
+ new Object[]{String.valueOf(Double.NaN), true},
+ new Object[]{"hello", false}
+ };
+ }
+
+ @Test(dataProvider = "rightAlignValues")
+ public void testIsRightAlign(String value, boolean expected) {
+ Assert.assertEquals(GATKReportColumn.isRightAlign(value), expected, "right align of '" + value + "'");
+ }
+
+ private GATKReportTable getTableWithRandomValues() {
+ Random number = new Random(123L);
+ final int VALUESRANGE = 10;
+
+ GATKReport report = GATKReport.newSimpleReport("TableName", "col1", "col2", "col3");
+ GATKReportTable table = new GATKReportTable("testSortingTable", "table with random values sorted by columns", 3, GATKReportTable.TableSortingWay.SORT_BY_COLUMN );
+
+ final int NUMROWS = 100;
+ for (int x = 0; x < NUMROWS; x++) {
+ report.addRow(number.nextInt(VALUESRANGE), number.nextInt(VALUESRANGE), number.nextInt(VALUESRANGE));
+ }
+ return table;
+ }
+
+ @Test(enabled = true)
+ public void testSortingByColumn() {
+ Assert.assertEquals(isSorted(getTableWithRandomValues()), true);
+ }
+
+ private boolean isSorted(GATKReportTable table) {
+ boolean result = true;
+ File testingSortingTableFile = new File("testSortingFile.txt");
+
+ try {
+ // Connect print stream to the output stream
+ PrintStream ps = new PrintStream(testingSortingTableFile);
+ table.write(ps);
+ ps.close();
+ }
+ catch (Exception e){
+ System.err.println ("Error: " + e.getMessage());
+ }
+
+ ArrayList<int[]> rows = new ArrayList<int[]>();
+ try {
+ // Open the file
+ FileInputStream fStream = new FileInputStream(testingSortingTableFile);
+ // Get the object of DataInputStream
+ DataInputStream in = new DataInputStream(fStream);
+ BufferedReader br = new BufferedReader(new InputStreamReader(in));
+ String strLine;
+ //Read File Line By Line
+ while ((strLine = br.readLine()) != null) {
+
+ String[] parts = strLine.split(" ");
+ int l = parts.length;
+ int[] row = new int[l];
+ for(int n = 0; n < l; n++) {
+ row[n] = Integer.parseInt(parts[n]);
+ }
+ rows.add(row);
+ }
+ //Close the input stream
+ in.close();
+ } catch (Exception e){//Catch exception if any
+ System.err.println("Error: " + e.getMessage());
+ }
+ for (int x = 1; x < rows.size() && result; x++) {
+ result = checkRowOrder(rows.get(x - 1), rows.get(x));
+ }
+ return result;
+ }
+
+ private boolean checkRowOrder(int[] row1, int[] row2) {
+ int l = row1.length;
+ final int EQUAL = 0;
+
+ int result = EQUAL;
+
+ for(int x = 0; x < l && ( result <= EQUAL); x++) {
+ result = ((Integer)row1[x]).compareTo(row2[x]);
+ }
+ if (result <= EQUAL) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private GATKReportTable makeBasicTable() {
+ GATKReport report = GATKReport.newSimpleReport("TableName", "sample", "value");
+ GATKReportTable table = report.getTable("TableName");
+ report.addRow("foo.1", "hello");
+ report.addRow("foo.2", "world");
+ return table;
+ }
+
+ @Test
+ public void testDottedSampleName() {
+ GATKReportTable table = makeBasicTable();
+ Assert.assertEquals(table.get(0, "value"), "hello");
+ Assert.assertEquals(table.get(1, "value"), "world");
+ }
+
+ @Test
+ public void testSimpleGATKReport() {
+ // Create a new simple GATK report named "TableName" with columns: Roger, is, and Awesome
+ GATKReport report = GATKReport.newSimpleReport("TableName", "Roger", "is", "Awesome");
+
+ // Add data to simple GATK report
+ report.addRow(12, 23.45, true);
+ report.addRow("ans", '3', 24.5);
+ report.addRow("hi", "", 2.3);
+
+ // Print the report to console
+ //report.print(System.out);
+
+ try {
+ File file = createTempFile("GATKReportGatherer-UnitTest", ".tbl");
+ //System.out.format("The temporary file" + " has been created: %s%n", file);
+ PrintStream ps = new PrintStream(file);
+ report.print(ps);
+ //System.out.println("File succesfully outputed!");
+ GATKReport inputRead = new GATKReport(file);
+ //System.out.println("File succesfully read!");
+ //inputRead.print(System.out);
+ Assert.assertTrue(report.isSameFormat(inputRead));
+
+ } catch (IOException x) {
+ System.err.format("IOException: %s%n", x);
+ }
+
+ }
+
+ @Test
+ public void testGATKReportGatherer() {
+
+ GATKReport report1, report2, report3;
+ report1 = new GATKReport();
+ report1.addTable("TableName", "Description", 2);
+ report1.getTable("TableName").addColumn("colA", "%s");
+ report1.getTable("TableName").addColumn("colB", "%c");
+ report1.getTable("TableName").set(0, "colA", "NotNum");
+ report1.getTable("TableName").set(0, "colB", (char) 64);
+
+ report2 = new GATKReport();
+ report2.addTable("TableName", "Description", 2);
+ report2.getTable("TableName").addColumn("colA", "%s");
+ report2.getTable("TableName").addColumn("colB", "%c");
+ report2.getTable("TableName").set(0, "colA", "df3");
+ report2.getTable("TableName").set(0, "colB", 'A');
+
+ report3 = new GATKReport();
+ report3.addTable("TableName", "Description", 2);
+ report3.getTable("TableName").addColumn("colA", "%s");
+ report3.getTable("TableName").addColumn("colB", "%c");
+ report3.getTable("TableName").set(0, "colA", "df5f");
+ report3.getTable("TableName").set(0, "colB", 'c');
+
+ report1.concat(report2);
+ report1.concat(report3);
+
+ report1.addTable("Table2", "To contain some more data types", 3);
+ GATKReportTable table = report1.getTable("Table2");
+ table.addColumn("SomeInt", "%d");
+ table.addColumn("SomeFloat", "%.16E");
+ table.addColumn("TrueFalse", "%B");
+ table.addRowIDMapping("12df", 0);
+ table.addRowIDMapping("5f", 1);
+ table.addRowIDMapping("RZ", 2);
+ table.set("12df", "SomeInt", Byte.MAX_VALUE);
+ table.set("12df", "SomeFloat", 34.0);
+ table.set("12df", "TrueFalse", true);
+ table.set("5f", "SomeInt", Short.MAX_VALUE);
+ table.set("5f", "SomeFloat", Double.MAX_VALUE);
+ table.set("5f", "TrueFalse", false);
+ table.set("RZ", "SomeInt", Long.MAX_VALUE);
+ table.set("RZ", "SomeFloat", 535646345.657453464576);
+ table.set("RZ", "TrueFalse", true);
+
+ report1.addTable("Table3", "blah", 1, GATKReportTable.TableSortingWay.SORT_BY_ROW);
+ report1.getTable("Table3").addColumn("a");
+ report1.getTable("Table3").addRowIDMapping("q", 2);
+ report1.getTable("Table3").addRowIDMapping("5", 3);
+ report1.getTable("Table3").addRowIDMapping("573s", 0);
+ report1.getTable("Table3").addRowIDMapping("ZZZ", 1);
+ report1.getTable("Table3").set("q", "a", "34");
+ report1.getTable("Table3").set("5", "a", "c4g34");
+ report1.getTable("Table3").set("573s", "a", "fDlwueg");
+ report1.getTable("Table3").set("ZZZ", "a", "Dfs");
+
+ try {
+ File file = createTempFile("GATKReportGatherer-UnitTest", ".tbl");
+ //System.out.format("The temporary file" + " has been created: %s%n", file);
+ PrintStream ps = new PrintStream(file);
+ report1.print(ps);
+ //System.out.println("File succesfully outputed!");
+ GATKReport inputRead = new GATKReport(file);
+ //System.out.println("File succesfully read!");
+ //inputRead.print(System.out);
+ Assert.assertTrue(report1.isSameFormat(inputRead));
+ Assert.assertTrue(report1.equals(inputRead));
+
+ } catch (IOException x) {
+ System.err.format("IOException: %s%n", x);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/samples/PedReaderUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/samples/PedReaderUnitTest.java
new file mode 100644
index 0000000..cd6014b
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/samples/PedReaderUnitTest.java
@@ -0,0 +1,354 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.samples;
+
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.StringReader;
+import java.util.*;
+
+/**
+ * UnitTest for PedReader
+ *
+ * @author Mark DePristo
+ * @since 2011
+ */
+public class PedReaderUnitTest extends BaseTest {
+ private static Logger logger = Logger.getLogger(PedReaderUnitTest.class);
+
+ private class PedReaderTest extends TestDataProvider {
+ public String fileContents;
+ public List<Sample> expectedSamples;
+ EnumSet<PedReader.MissingPedField> missing;
+
+ private PedReaderTest(final String name, final List<Sample> expectedSamples, final String fileContents) {
+ super(PedReaderTest.class, name);
+ this.fileContents = fileContents;
+ this.expectedSamples = expectedSamples;
+ }
+ }
+
+// Family ID
+// Individual ID
+// Paternal ID
+// Maternal ID
+// Sex (1=male; 2=female; other=unknown)
+// Phenotype
+//
+// -9 missing
+// 0 missing
+// 1 unaffected
+// 2 affected
+
+ @DataProvider(name = "readerTest")
+ public Object[][] createPEDFiles() {
+ new PedReaderTest("singleRecordMale",
+ Arrays.asList(new Sample("kid", "fam1", null, null, Gender.MALE, Affection.UNAFFECTED)),
+ "fam1 kid 0 0 1 1");
+
+ new PedReaderTest("singleRecordFemale",
+ Arrays.asList(new Sample("kid", "fam1", null, null, Gender.FEMALE, Affection.UNAFFECTED)),
+ "fam1 kid 0 0 2 1");
+
+ new PedReaderTest("singleRecordMissingGender",
+ Arrays.asList(new Sample("kid", "fam1", null, null, Gender.UNKNOWN, Affection.UNKNOWN)),
+ "fam1 kid 0 0 0 0");
+
+ // Affection
+ new PedReaderTest("singleRecordAffected",
+ Arrays.asList(new Sample("kid", "fam1", null, null, Gender.MALE, Affection.AFFECTED)),
+ "fam1 kid 0 0 1 2");
+
+ new PedReaderTest("singleRecordUnaffected",
+ Arrays.asList(new Sample("kid", "fam1", null, null, Gender.MALE, Affection.UNAFFECTED)),
+ "fam1 kid 0 0 1 1");
+
+ new PedReaderTest("singleRecordMissingAffection-9",
+ Arrays.asList(new Sample("kid", "fam1", null, null, Gender.MALE, Affection.UNKNOWN)),
+ "fam1 kid 0 0 1 -9");
+
+ new PedReaderTest("singleRecordMissingAffection0",
+ Arrays.asList(new Sample("kid", "fam1", null, null, Gender.MALE, Affection.UNKNOWN)),
+ "fam1 kid 0 0 1 0");
+
+ new PedReaderTest("multipleUnrelated",
+ Arrays.asList(
+ new Sample("s1", "fam1", null, null, Gender.MALE, Affection.UNAFFECTED),
+ new Sample("s2", "fam2", null, null, Gender.FEMALE, Affection.AFFECTED)),
+ String.format("%s%n%s",
+ "fam1 s1 0 0 1 1",
+ "fam2 s2 0 0 2 2"));
+
+ new PedReaderTest("multipleUnrelatedExtraLine",
+ Arrays.asList(
+ new Sample("s1", "fam1", null, null, Gender.MALE, Affection.UNAFFECTED),
+ new Sample("s2", "fam2", null, null, Gender.FEMALE, Affection.AFFECTED)),
+ String.format("%s%n%s%n %n", // note extra newlines and whitespace
+ "fam1 s1 0 0 1 1",
+ "fam2 s2 0 0 2 2"));
+
+ new PedReaderTest("explicitTrio",
+ Arrays.asList(
+ new Sample("kid", "fam1", "dad", "mom", Gender.MALE, Affection.AFFECTED),
+ new Sample("dad", "fam1", null, null, Gender.MALE, Affection.UNAFFECTED),
+ new Sample("mom", "fam1", null, null, Gender.FEMALE, Affection.AFFECTED)),
+ String.format("%s%n%s%n%s",
+ "fam1 kid dad mom 1 2",
+ "fam1 dad 0 0 1 1",
+ "fam1 mom 0 0 2 2"));
+
+ new PedReaderTest("implicitTrio",
+ Arrays.asList(
+ new Sample("kid", "fam1", "dad", "mom", Gender.MALE, Affection.AFFECTED),
+ new Sample("dad", "fam1", null, null, Gender.MALE, Affection.UNKNOWN),
+ new Sample("mom", "fam1", null, null, Gender.FEMALE, Affection.UNKNOWN)),
+ "fam1 kid dad mom 1 2");
+
+ new PedReaderTest("partialTrio",
+ Arrays.asList(
+ new Sample("kid", "fam1", "dad", "mom", Gender.MALE, Affection.AFFECTED),
+ new Sample("dad", "fam1", null, null, Gender.MALE, Affection.UNAFFECTED),
+ new Sample("mom", "fam1", null, null, Gender.FEMALE, Affection.UNKNOWN)),
+ String.format("%s%n%s",
+ "fam1 kid dad mom 1 2",
+ "fam1 dad 0 0 1 1"));
+
+ new PedReaderTest("bigPedigree",
+ Arrays.asList(
+ new Sample("kid", "fam1", "dad", "mom", Gender.MALE, Affection.AFFECTED),
+ new Sample("dad", "fam1", "granddad1", "grandma1", Gender.MALE, Affection.UNAFFECTED),
+ new Sample("granddad1", "fam1", null, null, Gender.MALE, Affection.UNKNOWN),
+ new Sample("grandma1", "fam1", null, null, Gender.FEMALE, Affection.UNKNOWN),
+ new Sample("mom", "fam1", "granddad2", "grandma2", Gender.FEMALE, Affection.AFFECTED),
+ new Sample("granddad2", "fam1", null, null, Gender.MALE, Affection.UNKNOWN),
+ new Sample("grandma2", "fam1", null, null, Gender.FEMALE, Affection.UNKNOWN)),
+ String.format("%s%n%s%n%s",
+ "fam1 kid dad mom 1 2",
+ "fam1 dad granddad1 grandma1 1 1",
+ "fam1 mom granddad2 grandma2 2 2"));
+
+ // Quantitative trait
+ new PedReaderTest("OtherPhenotype",
+ Arrays.asList(
+ new Sample("s1", "fam1", null, null, Gender.MALE, Affection.OTHER, "1"),
+ new Sample("s2", "fam2", null, null, Gender.FEMALE, Affection.OTHER, "10.0")),
+ String.format("%s%n%s",
+ "fam1 s1 0 0 1 1",
+ "fam2 s2 0 0 2 10.0"));
+
+ new PedReaderTest("OtherPhenotypeWithMissing",
+ Arrays.asList(
+ new Sample("s1", "fam1", null, null, Gender.MALE, Affection.UNKNOWN, Sample.UNSET_QT),
+ new Sample("s2", "fam2", null, null, Gender.FEMALE, Affection.OTHER, "10.0")),
+ String.format("%s%n%s",
+ "fam1 s1 0 0 1 -9",
+ "fam2 s2 0 0 2 10.0"));
+
+ new PedReaderTest("OtherPhenotypeOnlyInts",
+ Arrays.asList(
+ new Sample("s1", "fam1", null, null, Gender.MALE, Affection.OTHER, "1"),
+ new Sample("s2", "fam2", null, null, Gender.FEMALE, Affection.OTHER, "10")),
+ String.format("%s%n%s",
+ "fam1 s1 0 0 1 1",
+ "fam2 s2 0 0 2 10"));
+
+ return PedReaderTest.getTests(PedReaderTest.class);
+ }
+
+ private static final void runTest(PedReaderTest test, String myFileContents, EnumSet<PedReader.MissingPedField> missing) {
+ logger.warn("Test " + test);
+ PedReader reader = new PedReader();
+ SampleDB sampleDB = new SampleDB();
+ List<Sample> readSamples = reader.parse(myFileContents, missing, sampleDB);
+ Assert.assertEquals(new HashSet<Sample>(test.expectedSamples), new HashSet<Sample>(readSamples));
+ }
+
+ @Test(enabled = true, dataProvider = "readerTest")
+ public void testPedReader(PedReaderTest test) {
+ runTest(test, test.fileContents, EnumSet.noneOf(PedReader.MissingPedField.class));
+ }
+
+ @Test(enabled = true, dataProvider = "readerTest")
+ public void testPedReaderWithComments(PedReaderTest test) {
+ runTest(test, String.format("#comment%n%s", test.fileContents), EnumSet.noneOf(PedReader.MissingPedField.class));
+ }
+
+ @Test(enabled = true, dataProvider = "readerTest")
+ public void testPedReaderWithSemicolons(PedReaderTest test) {
+ runTest(test,
+ test.fileContents.replace(String.format("%n"), ";"),
+ EnumSet.noneOf(PedReader.MissingPedField.class));
+ }
+
+ // -----------------------------------------------------------------
+ // missing format field tests
+ // -----------------------------------------------------------------
+
+ private class PedReaderTestMissing extends TestDataProvider {
+ public EnumSet<PedReader.MissingPedField> missingDesc;
+ public EnumSet<PedReader.Field> missingFields;
+ public final String fileContents;
+ public Sample expected;
+
+
+ private PedReaderTestMissing(final String name, final String fileContents,
+ EnumSet<PedReader.MissingPedField> missingDesc,
+ EnumSet<PedReader.Field> missingFields,
+ final Sample expected) {
+ super(PedReaderTestMissing.class, name);
+ this.fileContents = fileContents;
+ this.missingDesc = missingDesc;
+ this.missingFields = missingFields;
+ this.expected = expected;
+ }
+ }
+
+ @DataProvider(name = "readerTestMissing")
+ public Object[][] createPEDFilesWithMissing() {
+ new PedReaderTestMissing("missingFam",
+ "fam1 kid dad mom 1 2",
+ EnumSet.of(PedReader.MissingPedField.NO_FAMILY_ID),
+ EnumSet.of(PedReader.Field.FAMILY_ID),
+ new Sample("kid", null, "dad", "mom", Gender.MALE, Affection.AFFECTED));
+
+ new PedReaderTestMissing("missingParents",
+ "fam1 kid dad mom 1 2",
+ EnumSet.of(PedReader.MissingPedField.NO_PARENTS),
+ EnumSet.of(PedReader.Field.PATERNAL_ID, PedReader.Field.MATERNAL_ID),
+ new Sample("kid", "fam1", null, null, Gender.MALE, Affection.AFFECTED));
+
+ new PedReaderTestMissing("missingSex",
+ "fam1 kid dad mom 1 2",
+ EnumSet.of(PedReader.MissingPedField.NO_SEX),
+ EnumSet.of(PedReader.Field.GENDER),
+ new Sample("kid", "fam1", "dad", "mom", Gender.UNKNOWN, Affection.AFFECTED));
+
+ new PedReaderTestMissing("missingPhenotype",
+ "fam1 kid dad mom 1 2",
+ EnumSet.of(PedReader.MissingPedField.NO_PHENOTYPE),
+ EnumSet.of(PedReader.Field.PHENOTYPE),
+ new Sample("kid", "fam1", "dad", "mom", Gender.MALE, Affection.UNKNOWN));
+
+ new PedReaderTestMissing("missingEverythingButGender",
+ "fam1 kid dad mom 1 2",
+ EnumSet.of(PedReader.MissingPedField.NO_PHENOTYPE, PedReader.MissingPedField.NO_PARENTS, PedReader.MissingPedField.NO_FAMILY_ID),
+ EnumSet.of(PedReader.Field.FAMILY_ID, PedReader.Field.PATERNAL_ID, PedReader.Field.MATERNAL_ID, PedReader.Field.PHENOTYPE),
+ new Sample("kid", null, null, null, Gender.MALE, Affection.UNKNOWN));
+
+
+ return PedReaderTestMissing.getTests(PedReaderTestMissing.class);
+ }
+
+ @Test(enabled = true, dataProvider = "readerTestMissing")
+ public void testPedReaderWithMissing(PedReaderTestMissing test) {
+ final String contents = sliceContents(test.missingFields, test.fileContents);
+ logger.warn("Test " + test);
+ PedReader reader = new PedReader();
+ SampleDB sampleDB = new SampleDB();
+ reader.parse(new StringReader(contents), test.missingDesc, sampleDB);
+ final Sample missingSample = sampleDB.getSample("kid");
+ Assert.assertEquals(test.expected, missingSample, "Missing field value not expected value for " + test);
+ }
+
+ private final static String sliceContents(EnumSet<PedReader.Field> missingFieldsSet, String full) {
+ List<String> parts = new ArrayList<String>(Arrays.asList(full.split("\\s+")));
+ final List<PedReader.Field> missingFields = new ArrayList<PedReader.Field>(missingFieldsSet);
+ Collections.reverse(missingFields);
+ for ( PedReader.Field field : missingFields )
+ parts.remove(field.ordinal());
+ return Utils.join("\t", parts);
+ }
+
+ // -----------------------------------------------------------------
+ // parsing tags
+ // -----------------------------------------------------------------
+
+ private class PedReaderTestTagParsing extends TestDataProvider {
+ public EnumSet<PedReader.MissingPedField> expected;
+ public final List<String> tags;
+
+ private PedReaderTestTagParsing(final List<String> tags, EnumSet<PedReader.MissingPedField> missingDesc) {
+ super(PedReaderTestTagParsing.class);
+ this.tags = tags;
+ this.expected = missingDesc;
+ }
+ }
+
+ @DataProvider(name = "readerTestTagParsing")
+ public Object[][] createReaderTestTagParsing() {
+ new PedReaderTestTagParsing(
+ Collections.<String>emptyList(),
+ EnumSet.noneOf(PedReader.MissingPedField.class));
+
+ new PedReaderTestTagParsing(
+ Arrays.asList("NO_FAMILY_ID"),
+ EnumSet.of(PedReader.MissingPedField.NO_FAMILY_ID));
+
+ new PedReaderTestTagParsing(
+ Arrays.asList("NO_PARENTS"),
+ EnumSet.of(PedReader.MissingPedField.NO_PARENTS));
+
+ new PedReaderTestTagParsing(
+ Arrays.asList("NO_PHENOTYPE"),
+ EnumSet.of(PedReader.MissingPedField.NO_PHENOTYPE));
+
+ new PedReaderTestTagParsing(
+ Arrays.asList("NO_SEX"),
+ EnumSet.of(PedReader.MissingPedField.NO_SEX));
+
+ new PedReaderTestTagParsing(
+ Arrays.asList("NO_SEX", "NO_PHENOTYPE"),
+ EnumSet.of(PedReader.MissingPedField.NO_SEX, PedReader.MissingPedField.NO_PHENOTYPE));
+
+ new PedReaderTestTagParsing(
+ Arrays.asList("NO_SEX", "NO_PHENOTYPE", "NO_PARENTS"),
+ EnumSet.of(PedReader.MissingPedField.NO_SEX, PedReader.MissingPedField.NO_PHENOTYPE, PedReader.MissingPedField.NO_PARENTS));
+
+ return PedReaderTestTagParsing.getTests(PedReaderTestTagParsing.class);
+ }
+
+ @Test(enabled = true, dataProvider = "readerTestTagParsing")
+ public void testPedReaderTagParsing(PedReaderTestTagParsing test) {
+ EnumSet<PedReader.MissingPedField> parsed = PedReader.parseMissingFieldTags("test", test.tags);
+ Assert.assertEquals(test.expected, parsed, "Failed to properly parse tags " + test.tags);
+ }
+
+ @Test(enabled = true, expectedExceptions = UserException.class)
+ public void testPedReaderTagParsing1() {
+ EnumSet<PedReader.MissingPedField> parsed = PedReader.parseMissingFieldTags("test", Arrays.asList("XXX"));
+ }
+
+ @Test(enabled = true, expectedExceptions = UserException.class)
+ public void testPedReaderTagParsing2() {
+ EnumSet<PedReader.MissingPedField> parsed = PedReader.parseMissingFieldTags("test", Arrays.asList("NO_SEX", "XXX"));
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/samples/SampleDBUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/samples/SampleDBUnitTest.java
new file mode 100644
index 0000000..fc934ef
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/samples/SampleDBUnitTest.java
@@ -0,0 +1,251 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.samples;
+
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: brett
+ * Date: Sep 9, 2010
+ * Time: 8:21:00 AM
+ */
+public class SampleDBUnitTest extends BaseTest {
+ private static SampleDBBuilder builder;
+ // all the test sample files are located here
+ private File testPED = new File(privateTestDir + "testtrio.ped");
+
+ private static final Set<Sample> testPEDSamples = new HashSet<Sample>(Arrays.asList(
+ new Sample("kid", "fam1", "dad", "mom", Gender.MALE, Affection.AFFECTED),
+ new Sample("dad", "fam1", null, null, Gender.MALE, Affection.UNAFFECTED),
+ new Sample("mom", "fam1", null, null, Gender.FEMALE, Affection.AFFECTED)));
+
+ private static final Set<Sample> testPEDFamilyF2 = new HashSet<Sample>(Arrays.asList(
+ new Sample("s2", "fam2", "d2", "m2", Gender.FEMALE, Affection.AFFECTED),
+ new Sample("d2", "fam2", null, null, Gender.MALE, Affection.UNKNOWN),
+ new Sample("m2", "fam2", null, null, Gender.FEMALE, Affection.UNKNOWN)
+ ));
+
+ private static final Set<Sample> testPEDFamilyF3 = new HashSet<Sample>(Arrays.asList(
+ new Sample("s1", "fam3", "d1", "m1", Gender.FEMALE, Affection.AFFECTED),
+ new Sample("d1", "fam3", null, null, Gender.MALE, Affection.UNKNOWN),
+ new Sample("m1", "fam3", null, null, Gender.FEMALE, Affection.UNKNOWN)
+ ));
+
+ private static final Set<Sample> testSAMSamples = new HashSet<Sample>(Arrays.asList(
+ new Sample("kid", null, null, null, Gender.UNKNOWN, Affection.UNKNOWN),
+ new Sample("mom", null, null, null, Gender.UNKNOWN, Affection.UNKNOWN),
+ new Sample("dad", null, null, null, Gender.UNKNOWN, Affection.UNKNOWN)));
+
+ private static final HashMap<String, Set<Sample>> testGetFamilies = new HashMap<String,Set<Sample>>();
+ static {
+ testGetFamilies.put("fam1", testPEDSamples);
+ testGetFamilies.put("fam2", testPEDFamilyF2);
+ testGetFamilies.put("fam3", testPEDFamilyF3);
+ }
+
+ private static final Set<Sample> testKidsWithParentsFamilies2 = new HashSet<Sample>(Arrays.asList(
+ new Sample("kid", "fam1", "dad", "mom", Gender.MALE, Affection.AFFECTED),
+ new Sample("kid3", "fam5", "dad2", "mom2", Gender.MALE, Affection.AFFECTED),
+ new Sample("kid2", "fam5", "dad2", "mom2", Gender.MALE, Affection.AFFECTED)));
+
+ private static final HashSet<String> testGetPartialFamiliesIds = new HashSet<String>(Arrays.asList("kid","s1"));
+ private static final HashMap<String, Set<Sample>> testGetPartialFamilies = new HashMap<String,Set<Sample>>();
+ static {
+ testGetPartialFamilies.put("fam1", new HashSet<Sample>(Arrays.asList(new Sample("kid", "fam1", "dad", "mom", Gender.MALE, Affection.AFFECTED))));
+ testGetPartialFamilies.put("fam3", new HashSet<Sample>(Arrays.asList(new Sample("s1", "fam3", "d1", "m1", Gender.FEMALE, Affection.AFFECTED))));
+ }
+
+ private static final String testPEDString =
+ String.format("%s%n%s%n%s",
+ "fam1 kid dad mom 1 2",
+ "fam1 dad 0 0 1 1",
+ "fam1 mom 0 0 2 2");
+
+ private static final String testPEDMultipleFamilies =
+ String.format("%s%n%s%n%s%n%s%n%s",
+ "fam1 kid dad mom 1 2",
+ "fam1 dad 0 0 1 1",
+ "fam1 mom 0 0 2 2",
+ "fam3 s1 d1 m1 2 2",
+ "fam2 s2 d2 m2 2 2");
+
+ private static final String testPEDMultipleFamilies2 =
+ String.format("%s%n%s%n%s%n%s%n%s%n%s%n%s%n%s%n%s",
+ "fam1 kid dad mom 1 2",
+ "fam1 dad 0 0 1 1",
+ "fam1 mom 0 0 2 2",
+ "fam4 kid4 dad4 0 1 2",
+ "fam4 dad4 0 0 1 1",
+ "fam5 kid2 dad2 mom2 1 2",
+ "fam5 kid3 dad2 mom2 1 2",
+ "fam5 dad2 0 0 1 1",
+ "fam5 mom2 0 0 2 2");
+
+ private static final String testPEDStringInconsistentGender =
+ "fam1 kid 0 0 2 2";
+
+ private static final Set<Sample> testPEDSamplesAsSet =
+ new HashSet<Sample>(testPEDSamples);
+
+
+ @BeforeMethod
+ public void before() {
+ builder = new SampleDBBuilder(PedigreeValidationType.STRICT);
+ }
+
+ @Test()
+ public void loadPEDFile() {
+ builder.addSamplesFromPedigreeFiles(Arrays.asList(testPED));
+ SampleDB db = builder.getFinalSampleDB();
+ Assert.assertEquals(testPEDSamplesAsSet, db.getSamples());
+ }
+
+ @Test()
+ public void loadPEDString() {
+ builder.addSamplesFromPedigreeStrings(Arrays.asList(testPEDString));
+ SampleDB db = builder.getFinalSampleDB();
+ Assert.assertEquals(testPEDSamplesAsSet, db.getSamples());
+ }
+
+ private static final void addSAMHeader() {
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 10);
+ ArtificialSAMUtils.createEnumeratedReadGroups(header, Arrays.asList("1", "2", "3"),
+ Arrays.asList("kid", "mom", "dad"));
+ builder.addSamplesFromSAMHeader(header);
+ }
+
+ @Test()
+ public void loadSAMHeader() {
+ addSAMHeader();
+ SampleDB db = builder.getFinalSampleDB();
+ Assert.assertEquals(testSAMSamples, db.getSamples());
+ }
+
+ @Test()
+ public void loadSAMHeaderPlusPED() {
+ addSAMHeader();
+ builder.addSamplesFromPedigreeFiles(Arrays.asList(testPED));
+ SampleDB db = builder.getFinalSampleDB();
+ Assert.assertEquals(testPEDSamples, db.getSamples());
+ }
+
+ @Test()
+ public void loadDuplicateData() {
+ builder.addSamplesFromPedigreeFiles(Arrays.asList(testPED));
+ builder.addSamplesFromPedigreeFiles(Arrays.asList(testPED));
+ SampleDB db = builder.getFinalSampleDB();
+ Assert.assertEquals(testPEDSamples, db.getSamples());
+ }
+
+ @Test(expectedExceptions = UserException.class)
+ public void loadNonExistentFile() {
+ builder.addSamplesFromPedigreeFiles(Arrays.asList(new File("non-existence-file.txt")));
+ SampleDB db = builder.getFinalSampleDB();
+ Assert.assertEquals(testSAMSamples, db.getSamples());
+ }
+
+ @Test(expectedExceptions = UserException.class)
+ public void loadInconsistentData() {
+ builder = new SampleDBBuilder(PedigreeValidationType.STRICT);
+ builder.addSamplesFromPedigreeFiles(Arrays.asList(testPED));
+ builder.addSamplesFromPedigreeStrings(Arrays.asList(testPEDStringInconsistentGender));
+ builder.getFinalSampleDB();
+ }
+
+ @Test(expectedExceptions = UserException.class)
+ public void sampleInSAMHeaderNotInSamplesDB() {
+ addSAMHeader();
+ builder.addSamplesFromPedigreeStrings(Arrays.asList(testPEDStringInconsistentGender));
+ builder.getFinalSampleDB();
+ }
+
+ @Test()
+ public void getFamilyIDs() {
+ builder.addSamplesFromPedigreeStrings(Arrays.asList(testPEDMultipleFamilies));
+ SampleDB db = builder.getFinalSampleDB();
+ Assert.assertEquals(db.getFamilyIDs(), new TreeSet<String>(Arrays.asList("fam1", "fam2", "fam3")));
+ }
+
+ @Test()
+ public void getFamily() {
+ builder.addSamplesFromPedigreeStrings(Arrays.asList(testPEDMultipleFamilies));
+ SampleDB db = builder.getFinalSampleDB();
+ Assert.assertEquals(db.getFamily("fam1"), testPEDSamplesAsSet);
+ }
+
+ @Test()
+ public void getFamilies(){
+ builder.addSamplesFromPedigreeStrings(Arrays.asList(testPEDMultipleFamilies));
+ SampleDB db = builder.getFinalSampleDB();
+ Assert.assertEquals(db.getFamilies(),testGetFamilies);
+ Assert.assertEquals(db.getFamilies(null),testGetFamilies);
+ Assert.assertEquals(db.getFamilies(testGetPartialFamiliesIds),testGetPartialFamilies);
+ }
+
+ @Test()
+ public void testGetChildrenWithParents()
+ {
+ builder.addSamplesFromPedigreeStrings(Arrays.asList(testPEDMultipleFamilies2));
+ SampleDB db = builder.getFinalSampleDB();
+ Assert.assertEquals(db.getChildrenWithParents(), testKidsWithParentsFamilies2);
+ Assert.assertEquals(db.getChildrenWithParents(false), testKidsWithParentsFamilies2);
+ Assert.assertEquals(db.getChildrenWithParents(true), new HashSet<Sample>(Arrays.asList(new Sample("kid", "fam1", "dad", "mom", Gender.MALE, Affection.AFFECTED))));
+ }
+
+ @Test()
+ public void testGetFounderIds(){
+ builder.addSamplesFromPedigreeStrings(Arrays.asList(testPEDMultipleFamilies2));
+ SampleDB db = builder.getFinalSampleDB();
+ Assert.assertEquals(db.getFounderIds(), new HashSet<String>(Arrays.asList("dad","mom","dad2","mom2","dad4")));
+ }
+
+ @Test()
+ public void loadFamilyIDs() {
+ builder.addSamplesFromPedigreeStrings(Arrays.asList(testPEDMultipleFamilies));
+ SampleDB db = builder.getFinalSampleDB();
+ Map<String, Set<Sample>> families = db.getFamilies();
+ Assert.assertEquals(families.size(), 3);
+ Assert.assertEquals(families.keySet(), new TreeSet<String>(Arrays.asList("fam1", "fam2", "fam3")));
+
+ for ( final String famID : families.keySet() ) {
+ final Set<Sample> fam = families.get(famID);
+ Assert.assertEquals(fam.size(), 3);
+ for ( final Sample sample : fam ) {
+ Assert.assertEquals(sample.getFamilyID(), famID);
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/samples/SampleUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/samples/SampleUnitTest.java
new file mode 100644
index 0000000..b1b09db
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/samples/SampleUnitTest.java
@@ -0,0 +1,89 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.samples;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+/**
+ *
+ */
+public class SampleUnitTest extends BaseTest {
+ SampleDB db;
+ static Sample fam1A, fam1B, fam1C;
+ static Sample s1, s2;
+ static Sample trait1, trait2, trait3, trait4, trait5;
+
+ @BeforeClass
+ public void init() {
+ db = new SampleDB();
+
+ fam1A = new Sample("1A", db, "fam1", "1B", "1C", Gender.UNKNOWN);
+ fam1B = new Sample("1B", db, "fam1", null, null, Gender.MALE);
+ fam1C = new Sample("1C", db, "fam1", null, null, Gender.FEMALE);
+
+ s1 = new Sample("s1", db);
+ s2 = new Sample("s2", db);
+
+ trait1 = new Sample("t1", db, Affection.AFFECTED, Sample.UNSET_QT);
+ trait2 = new Sample("t2", db, Affection.UNAFFECTED, Sample.UNSET_QT);
+ trait3 = new Sample("t3", db, Affection.UNKNOWN, Sample.UNSET_QT);
+ trait4 = new Sample("t4", db, Affection.OTHER, "1.0");
+ trait5 = new Sample("t4", db, Affection.OTHER, "CEU");
+ }
+
+ /**
+ * Now basic getters
+ */
+ @Test()
+ public void normalGettersTest() {
+ Assert.assertEquals("1A", fam1A.getID());
+ Assert.assertEquals("fam1", fam1A.getFamilyID());
+ Assert.assertEquals("1B", fam1A.getPaternalID());
+ Assert.assertEquals("1C", fam1A.getMaternalID());
+ Assert.assertEquals(null, fam1B.getPaternalID());
+ Assert.assertEquals(null, fam1B.getMaternalID());
+
+ Assert.assertEquals(Affection.AFFECTED, trait1.getAffection());
+ Assert.assertEquals(Sample.UNSET_QT, trait1.getOtherPhenotype());
+ Assert.assertEquals(Affection.UNAFFECTED, trait2.getAffection());
+ Assert.assertEquals(Sample.UNSET_QT, trait2.getOtherPhenotype());
+ Assert.assertEquals(Affection.UNKNOWN, trait3.getAffection());
+ Assert.assertEquals(Sample.UNSET_QT, trait3.getOtherPhenotype());
+ Assert.assertEquals(Affection.OTHER, trait4.getAffection());
+ Assert.assertEquals("1.0", trait4.getOtherPhenotype());
+ Assert.assertEquals("CEU", trait5.getOtherPhenotype());
+ }
+
+ @Test()
+ public void testGenders() {
+ Assert.assertTrue(fam1A.getGender() == Gender.UNKNOWN);
+ Assert.assertTrue(fam1B.getGender() == Gender.MALE);
+ Assert.assertTrue(fam1C.getGender() == Gender.FEMALE);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/DummyActiveRegionWalker.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/DummyActiveRegionWalker.java
new file mode 100644
index 0000000..e1d81b5
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/DummyActiveRegionWalker.java
@@ -0,0 +1,116 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.ActiveRegionWalker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.activeregion.ActiveRegion;
+import org.broadinstitute.gatk.utils.activeregion.ActiveRegionReadState;
+import org.broadinstitute.gatk.utils.activeregion.ActivityProfileState;
+
+import java.util.*;
+
+/**
+ * ActiveRegionWalker for unit testing
+ *
+ * User: depristo
+ * Date: 1/15/13
+ * Time: 1:28 PM
+ */
+class DummyActiveRegionWalker extends ActiveRegionWalker<Integer, Integer> {
+ private final double prob;
+ private EnumSet<ActiveRegionReadState> states = super.desiredReadStates();
+ private GenomeLocSortedSet activeRegions = null;
+
+ protected List<GenomeLoc> isActiveCalls = new ArrayList<GenomeLoc>();
+ protected Map<GenomeLoc, ActiveRegion> mappedActiveRegions = new LinkedHashMap<GenomeLoc, ActiveRegion>();
+ private boolean declareHavingPresetRegions = false;
+
+ public DummyActiveRegionWalker() {
+ this(1.0);
+ }
+
+ public DummyActiveRegionWalker(double constProb) {
+ this.prob = constProb;
+ }
+
+ public DummyActiveRegionWalker(GenomeLocSortedSet activeRegions, EnumSet<ActiveRegionReadState> wantStates, final boolean declareHavingPresetRegions) {
+ this(activeRegions, declareHavingPresetRegions);
+ this.states = wantStates;
+ }
+
+ public DummyActiveRegionWalker(GenomeLocSortedSet activeRegions, final boolean declareHavingPresetRegions) {
+ this(1.0);
+ this.activeRegions = activeRegions;
+ this.declareHavingPresetRegions = declareHavingPresetRegions;
+ }
+
+ public void setStates(EnumSet<ActiveRegionReadState> states) {
+ this.states = states;
+ }
+
+ @Override
+ public boolean hasPresetActiveRegions() {
+ return declareHavingPresetRegions;
+ }
+
+ @Override
+ public GenomeLocSortedSet getPresetActiveRegions() {
+ return declareHavingPresetRegions ? activeRegions : null;
+ }
+
+ @Override
+ public EnumSet<ActiveRegionReadState> desiredReadStates() {
+ return states;
+ }
+
+ @Override
+ public ActivityProfileState isActive(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) {
+ isActiveCalls.add(ref.getLocus());
+ final double p = activeRegions == null || activeRegions.overlaps(ref.getLocus()) ? prob : 0.0;
+ return new ActivityProfileState(ref.getLocus(), p);
+ }
+
+ @Override
+ public Integer map(ActiveRegion activeRegion, RefMetaDataTracker metaDataTracker) {
+ mappedActiveRegions.put(activeRegion.getLocation(), activeRegion);
+ return 0;
+ }
+
+ @Override
+ public Integer reduceInit() {
+ return 0;
+ }
+
+ @Override
+ public Integer reduce(Integer value, Integer sum) {
+ return 0;
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TAROrderedReadCacheUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TAROrderedReadCacheUnitTest.java
new file mode 100644
index 0000000..75c669c
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TAROrderedReadCacheUnitTest.java
@@ -0,0 +1,111 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.sam.ArtificialBAMBuilder;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class TAROrderedReadCacheUnitTest extends BaseTest {
+ // example fasta index file, can be deleted if you don't use the reference
+ private IndexedFastaSequenceFile seq;
+
+ @BeforeClass
+ public void setup() throws FileNotFoundException {
+ // sequence
+ seq = new CachingIndexedFastaSequenceFile(new File(b37KGReference));
+ }
+
+ @DataProvider(name = "ReadCacheTestData")
+ public Object[][] makeReadCacheTestData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final int nReadsPerLocus : Arrays.asList(0, 1, 10, 100) ) {
+ for ( final int nLoci : Arrays.asList(1, 10, 100) ) {
+ for ( final int max : Arrays.asList(10, 50, 1000) ) {
+ for ( final boolean addAllAtOnce : Arrays.asList(true, false) ) {
+ tests.add(new Object[]{nReadsPerLocus, nLoci, max, addAllAtOnce});
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "ReadCacheTestData")
+ public void testReadCache(final int nReadsPerLocus, final int nLoci, final int max, final boolean addAllAtOnce) {
+ final TAROrderedReadCache cache = new TAROrderedReadCache(max);
+
+ Assert.assertEquals(cache.getMaxCapacity(), max);
+ Assert.assertEquals(cache.getNumDiscarded(), 0);
+ Assert.assertEquals(cache.size(), 0);
+
+ final ArtificialBAMBuilder bamBuilder = new ArtificialBAMBuilder(seq, nReadsPerLocus, nLoci);
+ final List<GATKSAMRecord> reads = bamBuilder.makeReads();
+
+ if ( addAllAtOnce ) {
+ cache.addAll(reads);
+ } else {
+ for ( final GATKSAMRecord read : reads ) {
+ cache.add(read);
+ }
+ }
+
+ final int nTotalReads = reads.size();
+ final int nExpectedToKeep = Math.min(nTotalReads, max);
+ final int nExpectedToDiscard = nTotalReads - nExpectedToKeep;
+ Assert.assertEquals(cache.getNumDiscarded(), nExpectedToDiscard, "wrong number of reads discarded");
+ Assert.assertEquals(cache.size(), nExpectedToKeep, "wrong number of reads kept");
+
+ final List<GATKSAMRecord> cacheReads = cache.popCurrentReads();
+ Assert.assertEquals(cache.size(), 0, "Should be no reads left");
+ Assert.assertEquals(cache.getNumDiscarded(), 0, "should have reset stats");
+ Assert.assertEquals(cacheReads.size(), nExpectedToKeep, "should have 1 read for every read we expected to keep");
+
+ verifySortednessOfReads(cacheReads);
+ }
+
+ private void verifySortednessOfReads( final List<GATKSAMRecord> reads) {
+ int lastStart = -1;
+ for ( GATKSAMRecord read : reads ) {
+ Assert.assertTrue(lastStart <= read.getAlignmentStart(), "Reads should be sorted but weren't. Found read with start " + read.getAlignmentStart() + " while last was " + lastStart);
+ lastStart = read.getAlignmentStart();
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TraverseActiveRegionsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TraverseActiveRegionsUnitTest.java
new file mode 100644
index 0000000..50eb496
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TraverseActiveRegionsUnitTest.java
@@ -0,0 +1,679 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import com.google.java.contract.PreconditionError;
+import htsjdk.samtools.*;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.datasources.reads.*;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.SampleUtils;
+import org.broadinstitute.gatk.utils.activeregion.ActiveRegionReadState;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.interval.IntervalUtils;
+import org.broadinstitute.gatk.utils.sam.*;
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.datasources.providers.LocusShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.executive.WindowMaker;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.activeregion.ActiveRegion;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: thibault
+ * Date: 11/13/12
+ * Time: 2:47 PM
+ *
+ * Test the Active Region Traversal Contract
+ * http://iwww.broadinstitute.org/gsa/wiki/index.php/Active_Region_Traversal_Contract
+ */
+public class TraverseActiveRegionsUnitTest extends BaseTest {
+ private final static boolean ENFORCE_CONTRACTS = false;
+ private final static boolean DEBUG = false;
+
+ @DataProvider(name = "TraversalEngineProvider")
+ public Object[][] makeTraversals() {
+ final List<Object[]> traversals = new LinkedList<Object[]>();
+ traversals.add(new Object[]{new TraverseActiveRegions<>()});
+ return traversals.toArray(new Object[][]{});
+ }
+
+ private IndexedFastaSequenceFile reference;
+ private SAMSequenceDictionary dictionary;
+ private GenomeLocParser genomeLocParser;
+
+ private List<GenomeLoc> intervals;
+
+ private File testBAM;
+
+ @BeforeClass
+ private void init() throws IOException {
+ //reference = new CachingIndexedFastaSequenceFile(new File("/Users/depristo/Desktop/broadLocal/localData/human_g1k_v37.fasta")); // hg19Reference));
+ reference = new CachingIndexedFastaSequenceFile(new File(hg19Reference));
+ dictionary = reference.getSequenceDictionary();
+ genomeLocParser = new GenomeLocParser(dictionary);
+
+ // TODO: reads with indels
+ // TODO: reads which span many regions
+ // TODO: reads which are partially between intervals (in/outside extension)
+ // TODO: duplicate reads
+ // TODO: read at the end of a contig
+ // TODO: reads which are completely outside intervals but within extension
+ // TODO: test the extension itself
+ // TODO: unmapped reads
+
+ intervals = new ArrayList<GenomeLoc>();
+ intervals.add(genomeLocParser.createGenomeLoc("1", 10, 20));
+ intervals.add(genomeLocParser.createGenomeLoc("1", 1, 999));
+ intervals.add(genomeLocParser.createGenomeLoc("1", 1000, 1999));
+ intervals.add(genomeLocParser.createGenomeLoc("1", 2000, 2999));
+ intervals.add(genomeLocParser.createGenomeLoc("1", 10000, 20000));
+ intervals.add(genomeLocParser.createGenomeLoc("2", 1, 100));
+ intervals.add(genomeLocParser.createGenomeLoc("20", 10000, 10100));
+ intervals = IntervalUtils.sortAndMergeIntervals(genomeLocParser, intervals, IntervalMergingRule.OVERLAPPING_ONLY).toList();
+
+ List<GATKSAMRecord> reads = new ArrayList<GATKSAMRecord>();
+ reads.add(buildSAMRecord("simple", "1", 100, 200));
+ reads.add(buildSAMRecord("overlap_equal", "1", 10, 20));
+ reads.add(buildSAMRecord("overlap_unequal", "1", 10, 21));
+ reads.add(buildSAMRecord("boundary_equal", "1", 1990, 2009));
+ reads.add(buildSAMRecord("boundary_unequal", "1", 1990, 2008));
+ reads.add(buildSAMRecord("boundary_1_pre", "1", 1950, 2000));
+ reads.add(buildSAMRecord("boundary_1_post", "1", 1999, 2050));
+ reads.add(buildSAMRecord("extended_and_np", "1", 990, 1990));
+ reads.add(buildSAMRecord("outside_intervals", "1", 5000, 6000));
+ reads.add(buildSAMRecord("shard_boundary_1_pre", "1", 16300, 16385));
+ reads.add(buildSAMRecord("shard_boundary_1_post", "1", 16384, 16400));
+ reads.add(buildSAMRecord("shard_boundary_equal", "1", 16355, 16414));
+ reads.add(buildSAMRecord("simple20", "20", 10025, 10075));
+
+ createBAM(reads);
+ }
+
+ private void createBAM(List<GATKSAMRecord> reads) throws IOException {
+ testBAM = createTempFile("TraverseActiveRegionsUnitTest", ".bam");
+
+ SAMFileWriter out = new SAMFileWriterFactory().setCreateIndex(true).makeBAMWriter(reads.get(0).getHeader(), true, testBAM);
+ for (GATKSAMRecord read : ReadUtils.sortReadsByCoordinate(reads)) {
+ out.addAlignment(read);
+ }
+ out.close();
+
+ new File(testBAM.getAbsolutePath().replace(".bam", ".bai")).deleteOnExit();
+ new File(testBAM.getAbsolutePath() + ".bai").deleteOnExit();
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "TraversalEngineProvider")
+ public void testAllBasesSeen(TraverseActiveRegions t) {
+ DummyActiveRegionWalker walker = new DummyActiveRegionWalker();
+
+ List<GenomeLoc> activeIntervals = getIsActiveIntervals(t, walker, intervals);
+ // Contract: Every genome position in the analysis interval(s) is processed by the walker's isActive() call
+ verifyEqualIntervals(intervals, activeIntervals);
+ }
+
+ private List<GenomeLoc> getIsActiveIntervals(final TraverseActiveRegions t, DummyActiveRegionWalker walker, List<GenomeLoc> intervals) {
+ List<GenomeLoc> activeIntervals = new ArrayList<GenomeLoc>();
+ for (LocusShardDataProvider dataProvider : createDataProviders(t, walker, intervals, testBAM)) {
+ t.traverse(walker, dataProvider, 0);
+ activeIntervals.addAll(walker.isActiveCalls);
+ }
+
+ return activeIntervals;
+ }
+
+ @Test (enabled = ENFORCE_CONTRACTS, dataProvider = "TraversalEngineProvider", expectedExceptions = PreconditionError.class)
+ public void testIsActiveRangeLow (TraverseActiveRegions t) {
+ DummyActiveRegionWalker walker = new DummyActiveRegionWalker(-0.1);
+ getActiveRegions(t, walker, intervals).values();
+ }
+
+ @Test (enabled = ENFORCE_CONTRACTS, dataProvider = "TraversalEngineProvider", expectedExceptions = PreconditionError.class)
+ public void testIsActiveRangeHigh (TraverseActiveRegions t) {
+ DummyActiveRegionWalker walker = new DummyActiveRegionWalker(1.1);
+ getActiveRegions(t, walker, intervals).values();
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "TraversalEngineProvider")
+ public void testActiveRegionCoverage(TraverseActiveRegions t) {
+ DummyActiveRegionWalker walker = new DummyActiveRegionWalker(new GenomeLocSortedSet(genomeLocParser, intervals), true);
+
+ Collection<ActiveRegion> activeRegions = getActiveRegions(t, walker, intervals).values();
+ verifyActiveRegionCoverage(intervals, activeRegions);
+ }
+
+ private void verifyActiveRegionCoverage(List<GenomeLoc> intervals, Collection<ActiveRegion> activeRegions) {
+ List<GenomeLoc> intervalStarts = new ArrayList<GenomeLoc>();
+ List<GenomeLoc> intervalStops = new ArrayList<GenomeLoc>();
+
+ for (GenomeLoc interval : intervals) {
+ intervalStarts.add(interval.getStartLocation());
+ intervalStops.add(interval.getStopLocation());
+ }
+
+ Map<GenomeLoc, ActiveRegion> baseRegionMap = new HashMap<GenomeLoc, ActiveRegion>();
+
+ for (ActiveRegion activeRegion : activeRegions) {
+ for (GenomeLoc activeLoc : toSingleBaseLocs(activeRegion.getLocation())) {
+ // Contract: Regions do not overlap
+ Assert.assertFalse(baseRegionMap.containsKey(activeLoc), "Genome location " + activeLoc + " is assigned to more than one region");
+ baseRegionMap.put(activeLoc, activeRegion);
+ }
+
+ GenomeLoc start = activeRegion.getLocation().getStartLocation();
+ if (intervalStarts.contains(start))
+ intervalStarts.remove(start);
+
+ GenomeLoc stop = activeRegion.getLocation().getStopLocation();
+ if (intervalStops.contains(stop))
+ intervalStops.remove(stop);
+ }
+
+ for (GenomeLoc baseLoc : toSingleBaseLocs(intervals)) {
+ // Contract: Each location in the interval(s) is in exactly one region
+ // Contract: The total set of regions exactly matches the analysis interval(s)
+ Assert.assertTrue(baseRegionMap.containsKey(baseLoc), "Genome location " + baseLoc + " is not assigned to any region");
+ baseRegionMap.remove(baseLoc);
+ }
+
+ // Contract: The total set of regions exactly matches the analysis interval(s)
+ Assert.assertEquals(baseRegionMap.size(), 0, "Active regions contain base(s) outside of the given intervals");
+
+ // Contract: All explicit interval boundaries must also be region boundaries
+ Assert.assertEquals(intervalStarts.size(), 0, "Interval start location does not match an active region start location");
+ Assert.assertEquals(intervalStops.size(), 0, "Interval stop location does not match an active region stop location");
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "TraversalEngineProvider")
+ public void testActiveRegionExtensionOnContig(TraverseActiveRegions t) {
+ DummyActiveRegionWalker walker = new DummyActiveRegionWalker();
+
+ Collection<ActiveRegion> activeRegions = getActiveRegions(t, walker, intervals).values();
+ for (ActiveRegion activeRegion : activeRegions) {
+ GenomeLoc loc = activeRegion.getExtendedLoc();
+
+ // Contract: active region extensions must stay on the contig
+ Assert.assertTrue(loc.getStart() > 0, "Active region extension begins at location " + loc.getStart() + ", past the left end of the contig");
+ int refLen = dictionary.getSequence(loc.getContigIndex()).getSequenceLength();
+ Assert.assertTrue(loc.getStop() <= refLen, "Active region extension ends at location " + loc.getStop() + ", past the right end of the contig");
+ }
+ }
+
+ @Test(enabled = true && !DEBUG, dataProvider = "TraversalEngineProvider")
+ public void testPrimaryReadMapping(TraverseActiveRegions t) {
+ DummyActiveRegionWalker walker = new DummyActiveRegionWalker(new GenomeLocSortedSet(genomeLocParser, intervals),
+ EnumSet.of(ActiveRegionReadState.PRIMARY),
+ true);
+
+ // Contract: Each read has the Primary state in a single region (or none)
+ // This is the region of maximum overlap for the read (earlier if tied)
+
+ // simple: Primary in 1:1-999
+ // overlap_equal: Primary in 1:1-999
+ // overlap_unequal: Primary in 1:1-999
+ // boundary_equal: Primary in 1:1000-1999, Non-Primary in 1:2000-2999
+ // boundary_unequal: Primary in 1:1000-1999, Non-Primary in 1:2000-2999
+ // boundary_1_pre: Primary in 1:1000-1999, Non-Primary in 1:2000-2999
+ // boundary_1_post: Primary in 1:1000-1999, Non-Primary in 1:2000-2999
+ // extended_and_np: Primary in 1:1-999, Non-Primary in 1:1000-1999, Extended in 1:2000-2999
+ // outside_intervals: none
+ // shard_boundary_1_pre: Primary in 1:14908-16384, Non-Primary in 1:16385-16927
+ // shard_boundary_1_post: Primary in 1:14908-16384, Non-Primary in 1:16385-16927
+ // shard_boundary_equal: Primary in 1:14908-16384, Non-Primary in 1:16385-16927
+ // simple20: Primary in 20:10000-10100
+
+ Map<GenomeLoc, ActiveRegion> activeRegions = getActiveRegions(t, walker, intervals);
+ ActiveRegion region;
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 1, 999));
+ verifyReadMapping(region, "simple", "overlap_equal", "overlap_unequal", "extended_and_np");
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 1000, 1999));
+ verifyReadMapping(region, "boundary_unequal", "boundary_1_pre", "boundary_equal", "boundary_1_post");
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 2000, 2999));
+ verifyReadMapping(region);
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 10000, 20000));
+ verifyReadMapping(region, "shard_boundary_1_pre", "shard_boundary_1_post", "shard_boundary_equal");
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("20", 10000, 10100));
+ verifyReadMapping(region, "simple20");
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "TraversalEngineProvider")
+ public void testNonPrimaryReadMapping(TraverseActiveRegions t) {
+ DummyActiveRegionWalker walker = new DummyActiveRegionWalker(new GenomeLocSortedSet(genomeLocParser, intervals),
+ EnumSet.of(ActiveRegionReadState.PRIMARY, ActiveRegionReadState.NONPRIMARY),
+ true);
+
+ // Contract: Each read has the Primary state in a single region (or none)
+ // This is the region of maximum overlap for the read (earlier if tied)
+
+ // Contract: Each read has the Non-Primary state in all other regions it overlaps
+
+ // simple: Primary in 1:1-999
+ // overlap_equal: Primary in 1:1-999
+ // overlap_unequal: Primary in 1:1-999
+ // boundary_equal: Primary in 1:1000-1999, Non-Primary in 1:2000-2999
+ // boundary_unequal: Primary in 1:1000-1999, Non-Primary in 1:2000-2999
+ // boundary_1_pre: Primary in 1:1000-1999, Non-Primary in 1:2000-2999
+ // boundary_1_post: Primary in 1:1000-1999, Non-Primary in 1:2000-2999
+ // extended_and_np: Primary in 1:1-999, Non-Primary in 1:1000-1999, Extended in 1:2000-2999
+ // outside_intervals: none
+ // shard_boundary_1_pre: Primary in 1:14908-16384, Non-Primary in 1:16385-16927
+ // shard_boundary_1_post: Primary in 1:14908-16384, Non-Primary in 1:16385-16927
+ // shard_boundary_equal: Primary in 1:14908-16384, Non-Primary in 1:16385-16927
+ // simple20: Primary in 20:10000-10100
+
+ Map<GenomeLoc, ActiveRegion> activeRegions = getActiveRegions(t, walker, intervals);
+ ActiveRegion region;
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 1, 999));
+ verifyReadMapping(region, "simple", "overlap_equal", "overlap_unequal", "extended_and_np");
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 1000, 1999));
+ verifyReadMapping(region, "boundary_equal", "boundary_unequal", "extended_and_np", "boundary_1_pre", "boundary_1_post");
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 2000, 2999));
+ verifyReadMapping(region, "boundary_equal", "boundary_unequal", "boundary_1_pre", "boundary_1_post");
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 10000, 20000));
+ verifyReadMapping(region, "shard_boundary_1_pre", "shard_boundary_1_post", "shard_boundary_equal");
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("20", 10000, 10100));
+ verifyReadMapping(region, "simple20");
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "TraversalEngineProvider")
+ public void testExtendedReadMapping(TraverseActiveRegions t) {
+ DummyActiveRegionWalker walker = new DummyActiveRegionWalker(new GenomeLocSortedSet(genomeLocParser, intervals),
+ EnumSet.of(ActiveRegionReadState.PRIMARY, ActiveRegionReadState.NONPRIMARY, ActiveRegionReadState.EXTENDED),
+ true);
+
+ // Contract: Each read has the Primary state in a single region (or none)
+ // This is the region of maximum overlap for the read (earlier if tied)
+
+ // Contract: Each read has the Non-Primary state in all other regions it overlaps
+ // Contract: Each read has the Extended state in regions where it only overlaps if the region is extended
+
+ // simple: Primary in 1:1-999
+ // overlap_equal: Primary in 1:1-999
+ // overlap_unequal: Primary in 1:1-999
+ // boundary_equal: Non-Primary in 1:1000-1999, Primary in 1:2000-2999
+ // boundary_unequal: Primary in 1:1000-1999, Non-Primary in 1:2000-2999
+ // boundary_1_pre: Primary in 1:1000-1999, Non-Primary in 1:2000-2999
+ // boundary_1_post: Non-Primary in 1:1000-1999, Primary in 1:2000-2999
+ // extended_and_np: Non-Primary in 1:1-999, Primary in 1:1000-1999, Extended in 1:2000-2999
+ // outside_intervals: none
+ // shard_boundary_1_pre: Primary in 1:14908-16384, Non-Primary in 1:16385-16927
+ // shard_boundary_1_post: Non-Primary in 1:14908-16384, Primary in 1:16385-16927
+ // shard_boundary_equal: Non-Primary in 1:14908-16384, Primary in 1:16385-16927
+ // simple20: Primary in 20:10000-10100
+
+ Map<GenomeLoc, ActiveRegion> activeRegions = getActiveRegions(t, walker, intervals);
+ ActiveRegion region;
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 1, 999));
+ verifyReadMapping(region, "simple", "overlap_equal", "overlap_unequal", "extended_and_np");
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 1000, 1999));
+ verifyReadMapping(region, "boundary_equal", "boundary_unequal", "extended_and_np", "boundary_1_pre", "boundary_1_post");
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 2000, 2999));
+ verifyReadMapping(region, "boundary_equal", "boundary_unequal", "extended_and_np", "boundary_1_pre", "boundary_1_post");
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("1", 10000, 20000));
+ verifyReadMapping(region, "shard_boundary_1_pre", "shard_boundary_1_post", "shard_boundary_equal");
+
+ region = activeRegions.get(genomeLocParser.createGenomeLoc("20", 10000, 10100));
+ verifyReadMapping(region, "simple20");
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "TraversalEngineProvider")
+ public void testUnmappedReads(TraverseActiveRegions t) {
+ // TODO
+ }
+
+ private void verifyReadMapping(ActiveRegion region, String... reads) {
+ Assert.assertNotNull(region, "Region was unexpectedly null");
+ final Set<String> regionReads = new HashSet<String>();
+ for (SAMRecord read : region.getReads()) {
+ Assert.assertFalse(regionReads.contains(read.getReadName()), "Duplicate reads detected in region " + region + " read " + read.getReadName());
+ regionReads.add(read.getReadName());
+ }
+
+ Collection<String> wantReads = new ArrayList<String>(Arrays.asList(reads));
+ for (SAMRecord read : region.getReads()) {
+ String regionReadName = read.getReadName();
+ Assert.assertTrue(wantReads.contains(regionReadName), "Read " + regionReadName + " incorrectly assigned to active region " + region);
+ wantReads.remove(regionReadName);
+ }
+
+ Assert.assertTrue(wantReads.isEmpty(), "Reads missing in active region " + region + ", wanted " + (wantReads.isEmpty() ? "" : wantReads.iterator().next()));
+ }
+
+ private Map<GenomeLoc, ActiveRegion> getActiveRegions(TraverseActiveRegions t, DummyActiveRegionWalker walker, List<GenomeLoc> intervals) {
+ return getActiveRegions(t, walker, intervals, testBAM);
+ }
+
+ private Map<GenomeLoc, ActiveRegion> getActiveRegions(TraverseActiveRegions t, DummyActiveRegionWalker walker, List<GenomeLoc> intervals, final File bam) {
+ for (LocusShardDataProvider dataProvider : createDataProviders(t, walker, intervals, bam))
+ t.traverse(walker, dataProvider, 0);
+
+ return walker.mappedActiveRegions;
+ }
+
+ private Collection<GenomeLoc> toSingleBaseLocs(GenomeLoc interval) {
+ List<GenomeLoc> bases = new ArrayList<GenomeLoc>();
+ if (interval.size() == 1)
+ bases.add(interval);
+ else {
+ for (int location = interval.getStart(); location <= interval.getStop(); location++)
+ bases.add(genomeLocParser.createGenomeLoc(interval.getContig(), location, location));
+ }
+
+ return bases;
+ }
+
+ private Collection<GenomeLoc> toSingleBaseLocs(List<GenomeLoc> intervals) {
+ Set<GenomeLoc> bases = new TreeSet<GenomeLoc>(); // for sorting and uniqueness
+ for (GenomeLoc interval : intervals)
+ bases.addAll(toSingleBaseLocs(interval));
+
+ return bases;
+ }
+
+ private void verifyEqualIntervals(List<GenomeLoc> aIntervals, List<GenomeLoc> bIntervals) {
+ Collection<GenomeLoc> aBases = toSingleBaseLocs(aIntervals);
+ Collection<GenomeLoc> bBases = toSingleBaseLocs(bIntervals);
+
+ Assert.assertTrue(aBases.size() == bBases.size(), "Interval lists have a differing number of bases: " + aBases.size() + " vs. " + bBases.size());
+
+ Iterator<GenomeLoc> aIter = aBases.iterator();
+ Iterator<GenomeLoc> bIter = bBases.iterator();
+ while (aIter.hasNext() && bIter.hasNext()) {
+ GenomeLoc aLoc = aIter.next();
+ GenomeLoc bLoc = bIter.next();
+ Assert.assertTrue(aLoc.equals(bLoc), "Interval locations do not match: " + aLoc + " vs. " + bLoc);
+ }
+ }
+
+ // copied from LocusViewTemplate
+ protected GATKSAMRecord buildSAMRecord(String readName, String contig, int alignmentStart, int alignmentEnd) {
+ SAMFileHeader header = ArtificialSAMUtils.createDefaultReadGroup(new SAMFileHeader(), "test", "test");
+ header.setSequenceDictionary(dictionary);
+ header.setSortOrder(SAMFileHeader.SortOrder.coordinate);
+ GATKSAMRecord record = new GATKSAMRecord(header);
+
+ record.setReadName(readName);
+ record.setReferenceIndex(dictionary.getSequenceIndex(contig));
+ record.setAlignmentStart(alignmentStart);
+
+ Cigar cigar = new Cigar();
+ int len = alignmentEnd - alignmentStart + 1;
+ cigar.add(new CigarElement(len, CigarOperator.M));
+ record.setCigar(cigar);
+ record.setReadString(new String(new char[len]).replace("\0", "A"));
+ record.setBaseQualities(new byte[len]);
+ record.setReadGroup(new GATKSAMReadGroupRecord(header.getReadGroup("test")));
+
+ return record;
+ }
+
+ private List<LocusShardDataProvider> createDataProviders(TraverseActiveRegions traverseActiveRegions, final Walker walker, List<GenomeLoc> intervals, File bamFile) {
+ GenomeAnalysisEngine engine = new GenomeAnalysisEngine();
+ engine.setGenomeLocParser(genomeLocParser);
+
+ Collection<SAMReaderID> samFiles = new ArrayList<SAMReaderID>();
+ SAMReaderID readerID = new SAMReaderID(bamFile, new Tags());
+ samFiles.add(readerID);
+
+ SAMDataSource dataSource = new SAMDataSource(samFiles, new ThreadAllocation(), null, genomeLocParser,
+ false,
+ ValidationStringency.STRICT,
+ null,
+ null,
+ new ValidationExclusion(),
+ new ArrayList<ReadFilter>(),
+ new ArrayList<ReadTransformer>(),
+ false, (byte)30, false, true, null, IntervalMergingRule.ALL);
+
+ engine.setReadsDataSource(dataSource);
+ final Set<String> samples = SampleUtils.getSAMFileSamples(dataSource.getHeader());
+
+ traverseActiveRegions.initialize(engine, walker);
+ List<LocusShardDataProvider> providers = new ArrayList<LocusShardDataProvider>();
+ for (Shard shard : dataSource.createShardIteratorOverIntervals(new GenomeLocSortedSet(genomeLocParser, intervals), new ActiveRegionShardBalancer())) {
+ for (WindowMaker.WindowMakerIterator window : new WindowMaker(shard, genomeLocParser, dataSource.seek(shard), shard.getGenomeLocs(), samples)) {
+ providers.add(new LocusShardDataProvider(shard, shard.getReadProperties(), genomeLocParser, window.getLocus(), window, reference, new ArrayList<ReferenceOrderedDataSource>()));
+ }
+ }
+
+ return providers;
+ }
+
+ // ---------------------------------------------------------------------------------------------------------
+ //
+ // Combinatorial tests to ensure reads are going into the right regions
+ //
+ // ---------------------------------------------------------------------------------------------------------
+
+ @DataProvider(name = "CombinatorialARTTilingProvider")
+ public Object[][] makeCombinatorialARTTilingProvider() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ final List<Integer> starts = Arrays.asList(
+ 1, // very start of the chromosome
+ ArtificialBAMBuilder.BAM_SHARD_SIZE - 100, // right before the shard boundary
+ ArtificialBAMBuilder.BAM_SHARD_SIZE + 100 // right after the shard boundary
+ );
+
+ final List<EnumSet<ActiveRegionReadState>> allReadStates = Arrays.asList(
+ EnumSet.of(ActiveRegionReadState.PRIMARY),
+ EnumSet.of(ActiveRegionReadState.PRIMARY, ActiveRegionReadState.NONPRIMARY),
+ EnumSet.of(ActiveRegionReadState.PRIMARY, ActiveRegionReadState.NONPRIMARY, ActiveRegionReadState.EXTENDED)
+ );
+
+ final int maxTests = Integer.MAX_VALUE;
+ int nTests = 0;
+ for ( final int readLength : Arrays.asList(100) ) {
+ for ( final int skips : Arrays.asList(0, 10) ) {
+ for ( final int start : starts ) {
+ for ( final int nReadsPerLocus : Arrays.asList(1, 2) ) {
+ for ( final int nLoci : Arrays.asList(1, 1000) ) {
+ final ArtificialBAMBuilder bamBuilder = new ArtificialBAMBuilder(reference, nReadsPerLocus, nLoci);
+ bamBuilder.setReadLength(readLength);
+ bamBuilder.setSkipNLoci(skips);
+ bamBuilder.setAlignmentStart(start);
+ for ( EnumSet<ActiveRegionReadState> readStates : allReadStates ) {
+ for ( final GenomeLocSortedSet activeRegions : enumerateActiveRegions(bamBuilder.getAlignmentStart(), bamBuilder.getAlignmentEnd())) {
+ nTests++;
+ if ( nTests < maxTests ) // && nTests == 1238 )
+ tests.add(new Object[]{new TraverseActiveRegions<>(), nTests, activeRegions, readStates, bamBuilder});
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ private Collection<GenomeLocSortedSet> enumerateActiveRegions(final int start, final int stop) {
+ // should basically cut up entire region into equal sized chunks, of
+ // size 10, 20, 50, 100, etc, alternating skipping pieces so they are inactive
+ // Need to make sure we include some edge cases:
+ final List<GenomeLocSortedSet> activeRegions = new LinkedList<GenomeLocSortedSet>();
+
+ for ( final int stepSize : Arrays.asList(11, 29, 53, 97) ) {
+ for ( final boolean startWithActive : Arrays.asList(true, false) ) {
+ activeRegions.add(makeActiveRegionMask(start, stop, stepSize, startWithActive));
+ }
+ }
+
+ // active region is the whole interval
+ activeRegions.add(new GenomeLocSortedSet(genomeLocParser, genomeLocParser.createGenomeLoc("1", start, stop)));
+
+ // active region extends up to the end of the data, but doesn't include start
+ activeRegions.add(new GenomeLocSortedSet(genomeLocParser, genomeLocParser.createGenomeLoc("1", start+10, stop)));
+
+ return activeRegions;
+ }
+
+ private GenomeLocSortedSet makeActiveRegionMask(final int start, final int stop, final int stepSize, final boolean startWithActive) {
+ final GenomeLocSortedSet active = new GenomeLocSortedSet(genomeLocParser);
+
+ boolean includeRegion = startWithActive;
+ for ( int left = start; left < stop; left += stepSize) {
+ final int right = left + stepSize;
+ final GenomeLoc region = genomeLocParser.createGenomeLoc("1", left, right);
+ if ( includeRegion )
+ active.add(region);
+ includeRegion = ! includeRegion;
+ }
+
+ return active;
+ }
+
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "CombinatorialARTTilingProvider")
+ public void testARTReadsInActiveRegions(final TraverseActiveRegions<Integer, Integer> traversal, final int id, final GenomeLocSortedSet activeRegions, final EnumSet<ActiveRegionReadState> readStates, final ArtificialBAMBuilder bamBuilder) {
+ logger.warn("Running testARTReadsInActiveRegions id=" + id + " locs " + activeRegions + " against bam " + bamBuilder);
+ final List<GenomeLoc> intervals = Arrays.asList(
+ genomeLocParser.createGenomeLoc("1", bamBuilder.getAlignmentStart(), bamBuilder.getAlignmentEnd())
+ );
+
+ final DummyActiveRegionWalker walker = new DummyActiveRegionWalker(activeRegions, false);
+ walker.setStates(readStates);
+
+ final Map<GenomeLoc, ActiveRegion> activeRegionsMap = getActiveRegions(traversal, walker, intervals, bamBuilder.makeTemporarilyBAMFile());
+
+ final Set<String> alreadySeenReads = new HashSet<String>(); // for use with the primary / non-primary
+ for ( final ActiveRegion region : activeRegionsMap.values() ) {
+ final Set<String> readNamesInRegion = readNamesInRegion(region);
+ int nReadsExpectedInRegion = 0;
+ for ( final GATKSAMRecord read : bamBuilder.makeReads() ) {
+ final GenomeLoc readLoc = genomeLocParser.createGenomeLoc(read);
+
+ boolean shouldBeInRegion = readStates.contains(ActiveRegionReadState.EXTENDED)
+ ? region.getExtendedLoc().overlapsP(readLoc)
+ : region.getLocation().overlapsP(readLoc);
+
+ if ( ! readStates.contains(ActiveRegionReadState.NONPRIMARY) ) {
+ if ( alreadySeenReads.contains(read.getReadName()) )
+ shouldBeInRegion = false;
+ else if ( shouldBeInRegion )
+ alreadySeenReads.add(read.getReadName());
+ }
+
+ String msg = readNamesInRegion.contains(read.getReadName()) == shouldBeInRegion ? "" : "Region " + region +
+ " failed contains read check: read " + read + " with span " + readLoc + " should be in region is " + shouldBeInRegion + " but I got the opposite";
+ Assert.assertEquals(readNamesInRegion.contains(read.getReadName()), shouldBeInRegion, msg);
+
+ nReadsExpectedInRegion += shouldBeInRegion ? 1 : 0;
+ }
+
+ Assert.assertEquals(region.size(), nReadsExpectedInRegion, "There are more reads in active region " + region + "than expected");
+ }
+ }
+
+ private Set<String> readNamesInRegion(final ActiveRegion region) {
+ final Set<String> readNames = new LinkedHashSet<String>(region.getReads().size());
+ for ( final SAMRecord read : region.getReads() )
+ readNames.add(read.getReadName());
+ return readNames;
+ }
+
+ // ---------------------------------------------------------------------------------------------------------
+ //
+ // Make sure all insertion reads are properly included in the active regions
+ //
+ // ---------------------------------------------------------------------------------------------------------
+
+ @Test(dataProvider = "TraversalEngineProvider", enabled = true && ! DEBUG)
+ public void ensureAllInsertionReadsAreInActiveRegions(final TraverseActiveRegions<Integer, Integer> traversal) {
+
+ final int readLength = 10;
+ final int start = 20;
+ final int nReadsPerLocus = 10;
+ final int nLoci = 3;
+
+ final ArtificialBAMBuilder bamBuilder = new ArtificialBAMBuilder(reference, nReadsPerLocus, nLoci);
+ bamBuilder.setReadLength(readLength);
+ bamBuilder.setAlignmentStart(start);
+
+ // note that the position must be +1 as the read's all I cigar puts the end 1 bp before start, leaving it out of the region
+ GATKSAMRecord allI = ArtificialSAMUtils.createArtificialRead(bamBuilder.getHeader(),"allI",0,start+1,readLength);
+ allI.setCigarString(readLength + "I");
+ allI.setReadGroup(new GATKSAMReadGroupRecord(bamBuilder.getHeader().getReadGroups().get(0)));
+
+ bamBuilder.addReads(allI);
+
+ final GenomeLocSortedSet activeRegions = new GenomeLocSortedSet(bamBuilder.getGenomeLocParser());
+ activeRegions.add(bamBuilder.getGenomeLocParser().createGenomeLoc("1", 10, 30));
+ final List<GenomeLoc> intervals = Arrays.asList(
+ genomeLocParser.createGenomeLoc("1", bamBuilder.getAlignmentStart(), bamBuilder.getAlignmentEnd())
+ );
+
+ final DummyActiveRegionWalker walker = new DummyActiveRegionWalker(activeRegions, false);
+
+ final Map<GenomeLoc, ActiveRegion> activeRegionsMap = getActiveRegions(traversal, walker, intervals, bamBuilder.makeTemporarilyBAMFile());
+
+ final ActiveRegion region = activeRegionsMap.values().iterator().next();
+ int nReadsExpectedInRegion = 0;
+
+ final Set<String> readNamesInRegion = readNamesInRegion(region);
+ for ( final GATKSAMRecord read : bamBuilder.makeReads() ) {
+ Assert.assertTrue(readNamesInRegion.contains(read.getReadName()),
+ "Region " + region + " should contain read " + read + " with cigar " + read.getCigarString() + " but it wasn't");
+ nReadsExpectedInRegion++;
+ }
+
+ Assert.assertEquals(region.size(), nReadsExpectedInRegion, "There are more reads in active region " + region + "than expected");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TraverseDuplicatesUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TraverseDuplicatesUnitTest.java
new file mode 100644
index 0000000..a332be1
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TraverseDuplicatesUnitTest.java
@@ -0,0 +1,162 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+
+import org.testng.annotations.BeforeMethod;
+
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+
+/**
+ * @author aaron
+ * <p/>
+ * Class TraverseDuplicatesUnitTest
+ * <p/>
+ * test the meat of the traverse dupplicates.
+ */
+public class TraverseDuplicatesUnitTest extends BaseTest {
+
+ private TraverseDuplicates obj = new TraverseDuplicates();
+ private SAMFileHeader header;
+ private GenomeLocParser genomeLocParser;
+ private GenomeAnalysisEngine engine;
+ private File refFile = new File(validationDataLocation + "Homo_sapiens_assembly17.fasta");
+
+
+ @BeforeMethod
+ public void doBefore() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000);
+ genomeLocParser =new GenomeLocParser(header.getSequenceDictionary());
+
+ engine = new GenomeAnalysisEngine();
+ engine.setReferenceDataSource(refFile);
+ engine.setGenomeLocParser(genomeLocParser);
+
+ obj.initialize(engine, null);
+ }
+
+ @Test
+ public void testAllDuplicatesNoPairs() {
+ List<SAMRecord> list = new ArrayList<SAMRecord>();
+ for (int x = 0; x < 10; x++) {
+ SAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "SWEET_READ" + x, 0, 1, 100);
+ read.setDuplicateReadFlag(true);
+ list.add(read);
+ }
+ Set<List<SAMRecord>> myPairings = obj.uniqueReadSets(list);
+ Assert.assertEquals(myPairings.size(), 1);
+ Assert.assertEquals(myPairings.iterator().next().size(), 10); // dup's
+ }
+
+ @Test
+ public void testNoDuplicatesNoPairs() {
+ List<SAMRecord> list = new ArrayList<SAMRecord>();
+ for (int x = 0; x < 10; x++) {
+ SAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "SWEET_READ" + x, 0, 1, 100);
+ read.setDuplicateReadFlag(false);
+ list.add(read);
+ }
+
+ Set<List<SAMRecord>> myPairing = obj.uniqueReadSets(list);
+ Assert.assertEquals(myPairing.size(), 10); // unique
+ }
+
+ @Test
+ public void testFiftyFiftyNoPairs() {
+ List<SAMRecord> list = new ArrayList<SAMRecord>();
+ for (int x = 0; x < 5; x++) {
+ SAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "SWEET_READ" + x, 0, 1, 100);
+ read.setDuplicateReadFlag(true);
+ list.add(read);
+ }
+ for (int x = 10; x < 15; x++)
+ list.add(ArtificialSAMUtils.createArtificialRead(header, String.valueOf(x), 0, x, 100));
+
+ Set<List<SAMRecord>> myPairing = obj.uniqueReadSets(list);
+ Assert.assertEquals(myPairing.size(), 6); // unique
+ }
+
+ @Test
+ public void testAllDuplicatesAllPairs() {
+ List<SAMRecord> list = new ArrayList<SAMRecord>();
+ for (int x = 0; x < 10; x++) {
+ SAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "SWEET_READ"+ x, 0, 1, 100);
+ read.setDuplicateReadFlag(true);
+ read.setMateAlignmentStart(100);
+ read.setMateReferenceIndex(0);
+ read.setReadPairedFlag(true);
+ list.add(read);
+ }
+
+ Set<List<SAMRecord>> myPairing = obj.uniqueReadSets(list);
+ Assert.assertEquals(myPairing.size(), 1); // unique
+ }
+
+ @Test
+ public void testNoDuplicatesAllPairs() {
+ List<SAMRecord> list = new ArrayList<SAMRecord>();
+ for (int x = 0; x < 10; x++) {
+ SAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "SWEET_READ"+ x, 0, 1, 100);
+ if (x == 0) read.setDuplicateReadFlag(true); // one is a dup but (next line)
+ read.setMateAlignmentStart(100); // they all have a shared start and mate start so they're dup's
+ read.setMateReferenceIndex(0);
+ read.setReadPairedFlag(true);
+ list.add(read);
+ }
+
+ Set<List<SAMRecord>> myPairing = obj.uniqueReadSets(list);
+ Assert.assertEquals(myPairing.size(), 1); // unique
+ }
+
+ @Test
+ public void testAllDuplicatesAllPairsDifferentPairedEnd() {
+ List<SAMRecord> list = new ArrayList<SAMRecord>();
+ for (int x = 0; x < 10; x++) {
+ SAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "SWEET_READ" + x, 0, 1, 100);
+ if (x == 0) read.setDuplicateReadFlag(true); // one is a dup
+ read.setMateAlignmentStart(100 + x);
+ read.setMateReferenceIndex(0);
+ read.setReadPairedFlag(true);
+ list.add(read);
+ }
+
+ Set<List<SAMRecord>> myPairing = obj.uniqueReadSets(list);
+ Assert.assertEquals(myPairing.size(), 10); // unique
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TraverseReadsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TraverseReadsUnitTest.java
new file mode 100644
index 0000000..70336a2
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/traversals/TraverseReadsUnitTest.java
@@ -0,0 +1,166 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.traversals;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.datasources.providers.ReadShardDataProvider;
+import org.broadinstitute.gatk.engine.datasources.reads.*;
+import org.broadinstitute.gatk.engine.datasources.rmd.ReferenceOrderedDataSource;
+import org.broadinstitute.gatk.engine.resourcemanagement.ThreadAllocation;
+import org.broadinstitute.gatk.engine.walkers.ReadWalker;
+import org.broadinstitute.gatk.tools.walkers.qc.CountReads;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static org.testng.Assert.fail;
+
+/**
+ *
+ * User: aaron
+ * Date: Apr 24, 2009
+ * Time: 3:42:16 PM
+ *
+ * The Broad Institute
+ * SOFTWARE COPYRIGHT NOTICE AGREEMENT
+ * This software and its documentation are copyright 2009 by the
+ * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
+ *
+ * This software is supplied without any warranty or guaranteed support whatsoever. Neither
+ * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
+ *
+ */
+
+
+/**
+ * @author aaron
+ * @version 1.0
+ * @date Apr 24, 2009
+ * <p/>
+ * Class TraverseReadsUnitTest
+ * <p/>
+ * test traversing reads
+ */
+public class TraverseReadsUnitTest extends BaseTest {
+
+ private ReferenceSequenceFile seq;
+ private SAMReaderID bam = new SAMReaderID(new File(validationDataLocation + "index_test.bam"),new Tags()); // TCGA-06-0188.aligned.duplicates_marked.bam");
+ private File refFile = new File(validationDataLocation + "Homo_sapiens_assembly17.fasta");
+ private List<SAMReaderID> bamList;
+ private ReadWalker countReadWalker;
+ private File output;
+ private TraverseReadsNano traversalEngine = null;
+
+ private IndexedFastaSequenceFile ref = null;
+ private GenomeLocParser genomeLocParser = null;
+ private GenomeAnalysisEngine engine = null;
+
+ @BeforeClass
+ public void doOnce() {
+ try {
+ ref = new CachingIndexedFastaSequenceFile(refFile);
+ }
+ catch(FileNotFoundException ex) {
+ throw new UserException.CouldNotReadInputFile(refFile,ex);
+ }
+ genomeLocParser = new GenomeLocParser(ref);
+
+ engine = new GenomeAnalysisEngine();
+ engine.setReferenceDataSource(refFile);
+ engine.setGenomeLocParser(genomeLocParser);
+ }
+
+ /**
+ * This function does the setup of our parser, before each method call.
+ * <p/>
+ * Called before every test case method.
+ */
+ @BeforeMethod
+ public void doForEachTest() {
+ output = new File("testOut.txt");
+ FileOutputStream out = null;
+ PrintStream ps; // declare a print stream object
+
+ try {
+ out = new FileOutputStream(output);
+ } catch (FileNotFoundException e) {
+ e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
+ fail("Couldn't open the output file");
+ }
+
+ bamList = new ArrayList<SAMReaderID>();
+ bamList.add(bam);
+ countReadWalker = new CountReads();
+
+ traversalEngine = new TraverseReadsNano(1);
+ traversalEngine.initialize(engine, countReadWalker);
+ }
+
+ /** Test out that we can shard the file and iterate over every read */
+ @Test
+ public void testUnmappedReadCount() {
+ SAMDataSource dataSource = new SAMDataSource(bamList,new ThreadAllocation(),null,genomeLocParser);
+ Iterable<Shard> shardStrategy = dataSource.createShardIteratorOverAllReads(new ReadShardBalancer());
+
+ countReadWalker.initialize();
+ Object accumulator = countReadWalker.reduceInit();
+
+ for(Shard shard: shardStrategy) {
+ if (shard == null) {
+ fail("Shard == null");
+ }
+
+ ReadShardDataProvider dataProvider = new ReadShardDataProvider(shard,genomeLocParser,dataSource.seek(shard),null, Collections.<ReferenceOrderedDataSource>emptyList());
+ accumulator = traversalEngine.traverse(countReadWalker, dataProvider, accumulator);
+ dataProvider.close();
+ }
+
+ countReadWalker.onTraversalDone(accumulator);
+
+ if (!(accumulator instanceof Long)) {
+ fail("Count read walker should return a Long.");
+ }
+ if (!accumulator.equals(new Long(10000))) {
+ fail("there should be 10000 mapped reads in the index file, there was " + (accumulator));
+ }
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/walkers/WalkerTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/walkers/WalkerTest.java
new file mode 100644
index 0000000..a4c896e
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/engine/walkers/WalkerTest.java
@@ -0,0 +1,455 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.engine.walkers;
+
+import htsjdk.tribble.Tribble;
+import htsjdk.tribble.index.Index;
+import htsjdk.tribble.index.IndexFactory;
+import htsjdk.variant.bcf2.BCF2Utils;
+import htsjdk.variant.vcf.VCFCodec;
+import org.apache.commons.lang.StringUtils;
+import org.broadinstitute.gatk.engine.CommandLineExecutable;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.phonehome.GATKRunReport;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.MD5DB;
+import org.broadinstitute.gatk.utils.MD5Mismatch;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.classloader.JVMUtils;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.exceptions.GATKException;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.testng.Assert;
+import org.testng.annotations.AfterSuite;
+import org.testng.annotations.BeforeMethod;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.PrintStream;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+public class WalkerTest extends BaseTest {
+ private static final boolean GENERATE_SHADOW_BCF = true;
+ private static final boolean ENABLE_PHONE_HOME_FOR_TESTS = false;
+ private static final boolean ENABLE_ON_THE_FLY_CHECK_FOR_VCF_INDEX = false;
+ private static final boolean ENABLE_AUTO_INDEX_CREATION_AND_LOCKING_FOR_TESTS = false;
+
+ private static MD5DB md5DB = new MD5DB();
+
+ @BeforeMethod
+ public void initializeWalkerTests() {
+ logger.debug("Initializing walker tests");
+ GenomeAnalysisEngine.resetRandomGenerator();
+ }
+
+ @AfterSuite
+ public void finalizeWalkerTests() {
+ logger.debug("Finalizing walker tests");
+ md5DB.close();
+ }
+
+ public static MD5DB getMd5DB() {
+ return md5DB;
+ }
+
+ public void validateOutputBCFIfPossible(final String name, final File resultFile) {
+ final File bcfFile = BCF2Utils.shadowBCF(resultFile);
+ if ( bcfFile != null && bcfFile.exists() ) {
+ logger.warn("Checking shadow BCF output file " + bcfFile + " against VCF file " + resultFile);
+ try {
+ assertVCFandBCFFilesAreTheSame(resultFile, bcfFile);
+ logger.warn(" Shadow BCF PASSED!");
+ } catch ( Exception e ) {
+ Assert.fail("Exception received reading shadow BCFFile " + bcfFile + " for test " + name, e);
+ }
+ }
+ }
+
+ public void validateOutputIndex(final String name, final File resultFile) {
+ if ( !ENABLE_ON_THE_FLY_CHECK_FOR_VCF_INDEX )
+ return;
+
+ File indexFile = Tribble.indexFile(resultFile);
+ //System.out.println("Putative index file is " + indexFile);
+ if ( indexFile.exists() ) {
+ if ( resultFile.getAbsolutePath().contains(".vcf") ) {
+ // todo -- currently we only understand VCF files! Blow up since we can't test them
+ throw new GATKException("Found an index created for file " + resultFile + " but we can only validate VCF files. Extend this code!");
+ }
+
+ System.out.println("Verifying on-the-fly index " + indexFile + " for test " + name + " using file " + resultFile);
+ Index indexFromOutputFile = IndexFactory.createDynamicIndex(resultFile, new VCFCodec());
+ Index dynamicIndex = IndexFactory.loadIndex(indexFile.getAbsolutePath());
+
+ if ( ! indexFromOutputFile.equalsIgnoreProperties(dynamicIndex) ) {
+ Assert.fail(String.format("Index on disk from indexing on the fly not equal to the index created after the run completed. FileIndex %s vs. on-the-fly %s%n",
+ indexFromOutputFile.getProperties(),
+ dynamicIndex.getProperties()));
+ }
+ }
+ }
+
+ public List<String> assertMatchingMD5s(final String testName, final String testClassName, List<File> resultFiles, List<String> expectedMD5s) {
+ List<String> md5s = new ArrayList<String>();
+ List<MD5DB.MD5Match> fails = new ArrayList<MD5DB.MD5Match>();
+
+ for (int i = 0; i < resultFiles.size(); i++) {
+ MD5DB.MD5Match result = getMd5DB().testFileMD5(testName, testClassName, resultFiles.get(i), expectedMD5s.get(i), parameterize());
+ validateOutputBCFIfPossible(testName, resultFiles.get(i));
+ if ( ! result.failed ) {
+ validateOutputIndex(testName, resultFiles.get(i));
+ md5s.add(result.expectedMD5);
+ } else {
+ fails.add(result);
+ }
+ }
+
+ if ( ! fails.isEmpty() ) {
+ List<String> actuals = new ArrayList<String>();
+ List<String> expecteds = new ArrayList<String>();
+ List<String> diffEngineOutputs = new ArrayList<String>();
+
+ for ( final MD5DB.MD5Match fail : fails ) {
+ actuals.add(fail.actualMD5);
+ expecteds.add(fail.expectedMD5);
+ diffEngineOutputs.add(fail.diffEngineOutput);
+ logger.warn("Fail: " + fail.failMessage);
+ }
+
+ final MD5Mismatch failure = new MD5Mismatch(actuals, expecteds, diffEngineOutputs);
+ Assert.fail(failure.toString());
+ }
+
+ return md5s;
+ }
+
+ public String buildCommandLine(String... arguments) {
+ String cmdline = "";
+
+ for ( int argIndex = 0; argIndex < arguments.length; argIndex++ ) {
+ cmdline += arguments[argIndex];
+
+ if (argIndex < arguments.length - 1) {
+ cmdline += " ";
+ }
+ }
+
+ return cmdline;
+ }
+
+ public class WalkerTestSpec {
+ // Arguments implicitly included in all Walker command lines, unless explicitly
+ // disabled using the disableImplicitArgs() method below.
+ String args = "";
+ int nOutputFiles = -1;
+ List<String> md5s = null;
+ List<String> exts = null;
+ Class expectedException = null;
+ boolean includeImplicitArgs = true;
+ boolean includeShadowBCF = true;
+
+ // Name of the test class that created this test case
+ private Class testClass;
+
+ // the default output path for the integration test
+ private File outputFileLocation = null;
+
+ protected Map<String, File> auxillaryFiles = new HashMap<String, File>();
+
+ public WalkerTestSpec(String args, List<String> md5s) {
+ this(args, -1, md5s);
+ }
+
+ public WalkerTestSpec(String args, int nOutputFiles, List<String> md5s) {
+ this.args = args;
+ this.nOutputFiles = md5s.size();
+ this.md5s = md5s;
+ this.testClass = getCallingTestClass();
+ }
+
+ public WalkerTestSpec(String args, List<String> exts, List<String> md5s) {
+ this(args, -1, exts, md5s);
+ }
+
+ public WalkerTestSpec(String args, int nOutputFiles, List<String> exts, List<String> md5s) {
+ this.args = args;
+ this.nOutputFiles = md5s.size();
+ this.md5s = md5s;
+ this.exts = exts;
+ this.testClass = getCallingTestClass();
+ }
+
+ // @Test(expectedExceptions) doesn't work in integration tests, so use this instead
+ public WalkerTestSpec(String args, int nOutputFiles, Class expectedException) {
+ this.args = args;
+ this.nOutputFiles = nOutputFiles;
+ this.expectedException = expectedException;
+ this.testClass = getCallingTestClass();
+ }
+
+ private Class getCallingTestClass() {
+ return JVMUtils.getCallingClass(getClass());
+ }
+
+ public String getTestClassName() {
+ return testClass.getSimpleName();
+ }
+
+ public String getArgsWithImplicitArgs() {
+ String args = this.args;
+ if ( includeImplicitArgs ) {
+ args = args + (ENABLE_PHONE_HOME_FOR_TESTS ?
+ String.format(" -et %s ", GATKRunReport.PhoneHomeOption.AWS) :
+ String.format(" -et %s -K %s ", GATKRunReport.PhoneHomeOption.NO_ET, gatkKeyFile));
+ if ( includeShadowBCF && GENERATE_SHADOW_BCF )
+ args = args + " --generateShadowBCF ";
+ if ( ! ENABLE_AUTO_INDEX_CREATION_AND_LOCKING_FOR_TESTS )
+ args = args + " --disable_auto_index_creation_and_locking_when_reading_rods ";
+ }
+
+ return args;
+ }
+
+ /**
+ * In the case where the input VCF files are malformed and cannot be fixed
+ * this function tells the engine to not try to generate a shadow BCF
+ * which will ultimately blow up...
+ */
+ public void disableShadowBCF() { this.includeShadowBCF = false; }
+ public void setOutputFileLocation(File outputFileLocation) {
+ this.outputFileLocation = outputFileLocation;
+ }
+
+ protected File getOutputFileLocation() {
+ return outputFileLocation;
+ }
+
+ public boolean expectsException() {
+ return expectedException != null;
+ }
+
+ public Class getExpectedException() {
+ if ( ! expectsException() ) throw new ReviewedGATKException("Tried to get expection for walker test that doesn't expect one");
+ return expectedException;
+ }
+
+ public void addAuxFile(String expectededMD5sum, File outputfile) {
+ auxillaryFiles.put(expectededMD5sum, outputfile);
+ }
+
+ public void disableImplicitArgs() {
+ includeImplicitArgs = false;
+ }
+ }
+
+ protected boolean parameterize() {
+ return false;
+ }
+
+ public enum ParallelTestType {
+ TREE_REDUCIBLE,
+ NANO_SCHEDULED,
+ BOTH
+ }
+
+ protected Pair<List<File>, List<String>> executeTestParallel(final String name, WalkerTestSpec spec, ParallelTestType testType) {
+ final List<Integer> ntThreads = testType == ParallelTestType.TREE_REDUCIBLE || testType == ParallelTestType.BOTH ? Arrays.asList(1, 4) : Collections.<Integer>emptyList();
+ final List<Integer> cntThreads = testType == ParallelTestType.NANO_SCHEDULED || testType == ParallelTestType.BOTH ? Arrays.asList(1, 4) : Collections.<Integer>emptyList();
+
+ return executeTest(name, spec, ntThreads, cntThreads);
+ }
+
+ protected Pair<List<File>, List<String>> executeTestParallel(final String name, WalkerTestSpec spec) {
+ return executeTestParallel(name, spec, ParallelTestType.TREE_REDUCIBLE);
+ }
+
+ protected Pair<List<File>, List<String>> executeTest(final String name, WalkerTestSpec spec, List<Integer> ntThreads, List<Integer> cpuThreads) {
+ String originalArgs = spec.args;
+ Pair<List<File>, List<String>> results = null;
+
+ boolean ran1 = false;
+ for ( int nt : ntThreads ) {
+ String extra = nt == 1 ? "" : (" -nt " + nt);
+ ran1 = ran1 || nt == 1;
+ spec.args = originalArgs + extra;
+ results = executeTest(name + "-nt-" + nt, spec);
+ }
+
+ for ( int nct : cpuThreads ) {
+ if ( nct != 1 ) {
+ String extra = " -nct " + nct;
+ spec.args = originalArgs + extra;
+ results = executeTest(name + "-cnt-" + nct, spec);
+ }
+ }
+
+ return results;
+ }
+
+ protected Pair<List<File>, List<String>> executeTest(final String name, WalkerTestSpec spec) {
+ List<File> tmpFiles = new ArrayList<File>();
+ for (int i = 0; i < spec.nOutputFiles; i++) {
+ String ext = spec.exts == null ? ".tmp" : "." + spec.exts.get(i);
+ File fl = createTempFile(String.format("walktest.tmp_param.%d", i), ext);
+
+ // Cleanup any potential shadow BCFs on exit too, if we're generating them
+ if ( spec.includeShadowBCF && GENERATE_SHADOW_BCF ) {
+ final File potentalShadowBCFFile = BCF2Utils.shadowBCF(fl);
+ potentalShadowBCFFile.deleteOnExit();
+ new File(potentalShadowBCFFile.getAbsolutePath() + Tribble.STANDARD_INDEX_EXTENSION).deleteOnExit();
+ }
+
+ tmpFiles.add(fl);
+ }
+
+ final String args = String.format(spec.getArgsWithImplicitArgs(), tmpFiles.toArray());
+ System.out.println(Utils.dupString('-', 80));
+
+ if ( spec.expectsException() ) {
+ // this branch handles the case were we are testing that a walker will fail as expected
+ return executeTest(name, spec.getTestClassName(), spec.getOutputFileLocation(), null, tmpFiles, args, spec.getExpectedException());
+ } else {
+ List<String> md5s = new LinkedList<String>();
+ md5s.addAll(spec.md5s);
+
+ // check to see if they included any auxillary files, if so add them to the list and set them to be deleted on exit
+ for (String md5 : spec.auxillaryFiles.keySet()) {
+ md5s.add(md5);
+ final File auxFile = spec.auxillaryFiles.get(md5);
+ auxFile.deleteOnExit();
+ tmpFiles.add(auxFile);
+ }
+ return executeTest(name, spec.getTestClassName(), spec.getOutputFileLocation(), md5s, tmpFiles, args, null);
+ }
+ }
+
+ private void qcMD5s(String name, List<String> md5s) {
+ final String exampleMD5 = "709a1f482cce68992c637da3cff824a8";
+ for (String md5 : md5s) {
+ if ( md5 == null )
+ throw new IllegalArgumentException("Null MD5 found in test " + name);
+ if ( md5.equals("") ) // ok
+ continue;
+ if ( ! StringUtils.isAlphanumeric(md5) )
+ throw new IllegalArgumentException("MD5 contains non-alphanumeric characters test " + name + " md5=" + md5);
+ if ( md5.length() != exampleMD5.length() )
+ throw new IllegalArgumentException("Non-empty MD5 of unexpected number of characters test " + name + " md5=" + md5);
+ }
+ }
+
+
+ /**
+ * execute the test, given the following:
+ * @param testName the name of the test
+ * @param testClassName the name of the class that contains the test
+ * @param md5s the list of md5s
+ * @param tmpFiles the temp file corresponding to the md5 list
+ * @param args the argument list
+ * @param expectedException the expected exception or null
+ * @return a pair of file and string lists
+ */
+ private Pair<List<File>, List<String>> executeTest(String testName, String testClassName, File outputFileLocation, List<String> md5s, List<File> tmpFiles, String args, Class expectedException) {
+ if ( md5s != null ) qcMD5s(testName, md5s);
+
+ if (outputFileLocation != null)
+ args += " -o " + outputFileLocation.getAbsolutePath();
+ executeTest(testName, testClassName, args, expectedException);
+
+ if ( expectedException != null ) {
+ return null;
+ } else {
+ // we need to check MD5s
+ return new Pair<List<File>, List<String>>(tmpFiles, assertMatchingMD5s(testName, testClassName, tmpFiles, md5s));
+ }
+ }
+
+ /**
+ * execute the test, given the following:
+ * @param testName the name of the test
+ * @param testClassName the name of the class that contains the test
+ * @param args the argument list
+ * @param expectedException the expected exception or null
+ */
+ private void executeTest(String testName, String testClassName, String args, Class expectedException) {
+ CommandLineGATK instance = new CommandLineGATK();
+ String[] command = Utils.escapeExpressions(args);
+ // run the executable
+ boolean gotAnException = false;
+ try {
+ final String now = new SimpleDateFormat("HH:mm:ss").format(new Date());
+ final String cmdline = Utils.join(" ",command);
+ System.out.println(String.format("[%s] Executing test %s:%s with GATK arguments: %s", now, testClassName, testName, cmdline));
+ // also write the command line to the HTML log for convenient follow-up
+ // do the replaceAll so paths become relative to the current
+ BaseTest.log(cmdline.replaceAll(publicTestDirRoot, "").replaceAll(privateTestDirRoot, ""));
+ CommandLineExecutable.start(instance, command);
+ } catch (Exception e) {
+ gotAnException = true;
+ if ( expectedException != null ) {
+ // we expect an exception
+ //System.out.println(String.format("Wanted exception %s, saw %s", expectedException, e.getClass()));
+ if ( expectedException.isInstance(e) ) {
+ // it's the type we expected
+ //System.out.println(String.format(" => %s PASSED", name));
+ } else {
+ final String message = String.format("Test %s:%s expected exception %s but instead got %s with error message %s",
+ testClassName, testName, expectedException, e.getClass(), e.getMessage());
+ if ( e.getCause() != null ) {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final PrintStream ps = new PrintStream(baos);
+ e.getCause().printStackTrace(ps);
+ BaseTest.log(message);
+ BaseTest.log(baos.toString());
+ }
+ Assert.fail(message);
+ }
+ } else {
+ // we didn't expect an exception but we got one :-(
+ throw new RuntimeException(e);
+ }
+ }
+
+ // catch failures from the integration test
+ if ( expectedException != null ) {
+ if ( ! gotAnException )
+ // we expected an exception but didn't see it
+ Assert.fail(String.format("Test %s:%s expected exception %s but none was thrown", testClassName, testName, expectedException.toString()));
+ } else {
+ if ( CommandLineExecutable.result != 0) {
+ throw new RuntimeException("Error running the GATK with arguments: " + args);
+ }
+ }
+ }
+
+
+ protected File createTempFileFromBase(final String name) {
+ File fl = new File(name);
+ fl.deleteOnExit();
+ return fl;
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/CatVariantsIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/CatVariantsIntegrationTest.java
new file mode 100644
index 0000000..f1b8d6e
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/CatVariantsIntegrationTest.java
@@ -0,0 +1,145 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools;
+
+import org.apache.commons.lang.StringUtils;
+import htsjdk.tribble.AbstractFeatureReader;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.MD5DB;
+import org.broadinstitute.gatk.utils.MD5Mismatch;
+import org.broadinstitute.gatk.utils.runtime.ProcessController;
+import org.broadinstitute.gatk.utils.runtime.ProcessSettings;
+import org.broadinstitute.gatk.utils.runtime.RuntimeUtils;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+public class CatVariantsIntegrationTest {
+ private final MD5DB md5db = new MD5DB();
+ private final File CatVariantsDir = new File(BaseTest.privateTestDir, "CatVariants");
+ private final File CatVariantsVcf1 = new File(CatVariantsDir, "CatVariantsTest1.vcf");
+ private final File CatVariantsVcf2 = new File(CatVariantsDir, "CatVariantsTest2.vcf");
+ private final File CatVariantsBcf1 = new File(CatVariantsDir, "CatVariantsTest1.bcf");
+ private final File CatVariantsBcf2 = new File(CatVariantsDir, "CatVariantsTest2.bcf");
+
+ private class CatVariantsTestProvider extends BaseTest.TestDataProvider {
+ private final File file1;
+ private final File file2;
+ public final File outputFile;
+ public final String md5;
+
+ private CatVariantsTestProvider(final File file1, final File file2, final File outputFile, final String md5) {
+ super(CatVariantsTestProvider.class);
+
+ this.file1 = file1;
+ this.file2 = file2;
+ this.outputFile = outputFile;
+ this.md5 = md5;
+ }
+
+ public final String getCmdLine() {
+ return String.format("java -cp %s %s -R %s -V %s -V %s -out %s",
+ StringUtils.join(RuntimeUtils.getAbsoluteClassPaths(), File.pathSeparatorChar),
+ CatVariants.class.getCanonicalName(), BaseTest.b37KGReference, file1, file2, outputFile);
+ }
+
+ public String toString() {
+ return "CatVariantsTestProvider " + outputFile;
+ }
+ }
+
+ @DataProvider(name = "ExtensionsTest")
+ public Object[][] makeExtensionsTestProvider() {
+ final File catVariantsTempList1 = BaseTest.createTempListFile("CatVariantsTest1", CatVariantsVcf1.getAbsolutePath());
+ final File catVariantsTempList2 = BaseTest.createTempListFile("CatVariantsTest2", CatVariantsVcf2.getAbsolutePath());
+
+ new CatVariantsTestProvider(CatVariantsVcf1, CatVariantsVcf2, BaseTest.createTempFile("CatVariantsTest", ".vcf"), "d0d81eb7fd3905256c4ac7c0fc480094");
+ new CatVariantsTestProvider(CatVariantsBcf1, CatVariantsBcf2, BaseTest.createTempFile("CatVariantsTest", ".bcf"), "6a57fcbbf3cae490896d13a288670d83");
+
+ for (String extension : AbstractFeatureReader.BLOCK_COMPRESSED_EXTENSIONS) {
+ final File file1 = new File(CatVariantsDir, "CatVariantsTest1.vcf" + extension);
+ final File file2 = new File(CatVariantsDir, "CatVariantsTest2.vcf" + extension);
+ final File outputFile = BaseTest.createTempFile("CatVariantsTest", ".vcf" + extension);
+ new CatVariantsTestProvider(file1, file2, outputFile, "33f728ac5c70ce2994f3619a27f47088");
+ }
+
+ //Test list parsing functionality
+ new CatVariantsTestProvider(catVariantsTempList1, CatVariantsVcf2, BaseTest.createTempFile("CatVariantsTest", ".vcf"), "d0d81eb7fd3905256c4ac7c0fc480094");
+ new CatVariantsTestProvider(CatVariantsVcf1, catVariantsTempList2, BaseTest.createTempFile("CatVariantsTest", ".vcf"), "d0d81eb7fd3905256c4ac7c0fc480094");
+ new CatVariantsTestProvider(catVariantsTempList1, catVariantsTempList2, BaseTest.createTempFile("CatVariantsTest", ".vcf"), "d0d81eb7fd3905256c4ac7c0fc480094");
+
+ return CatVariantsTestProvider.getTests(CatVariantsTestProvider.class);
+ }
+
+ @Test(dataProvider = "ExtensionsTest")
+ public void testExtensions(final CatVariantsTestProvider cfg) throws IOException {
+
+ ProcessController pc = ProcessController.getThreadLocal();
+ ProcessSettings ps = new ProcessSettings(cfg.getCmdLine().split("\\s+"));
+ pc.execAndCheck(ps);
+
+ MD5DB.MD5Match result = md5db.testFileMD5("testExtensions", "CatVariantsTestProvider", cfg.outputFile, cfg.md5, false);
+ if(result.failed) {
+ final MD5Mismatch failure = new MD5Mismatch(result.actualMD5, result.expectedMD5, result.diffEngineOutput);
+ Assert.fail(failure.toString());
+ }
+ }
+
+ @Test(expectedExceptions = IOException.class)
+ public void testMismatchedExtensions1() throws IOException {
+
+ String cmdLine = String.format("java -cp %s %s -R %s -V %s -V %s -out %s",
+ StringUtils.join(RuntimeUtils.getAbsoluteClassPaths(), File.pathSeparatorChar),
+ CatVariants.class.getCanonicalName(),
+ BaseTest.b37KGReference,
+ CatVariantsVcf1,
+ CatVariantsVcf2,
+ BaseTest.createTempFile("CatVariantsTest", ".bcf"));
+
+ ProcessController pc = ProcessController.getThreadLocal();
+ ProcessSettings ps = new ProcessSettings(cmdLine.split("\\s+"));
+ pc.execAndCheck(ps);
+ }
+
+ @Test(expectedExceptions = IOException.class)
+ public void testMismatchedExtensions2() throws IOException {
+
+ String cmdLine = String.format("java -cp %s %s -R %s -V %s -V %s -out %s",
+ StringUtils.join(RuntimeUtils.getAbsoluteClassPaths(), File.pathSeparatorChar),
+ CatVariants.class.getCanonicalName(),
+ BaseTest.b37KGReference,
+ CatVariantsVcf1,
+ CatVariantsBcf2,
+ BaseTest.createTempFile("CatVariantsTest", ".vcf"));
+
+ ProcessController pc = ProcessController.getThreadLocal();
+ ProcessSettings ps = new ProcessSettings(cmdLine.split("\\s+"));
+ pc.execAndCheck(ps);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/BAQIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/BAQIntegrationTest.java
new file mode 100644
index 0000000..68451ef
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/BAQIntegrationTest.java
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+public class BAQIntegrationTest extends WalkerTest {
+ private final static String baseCommand = "-T PrintReads -R " + b36KGReference +
+ " -I " + validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.allTechs.bam" +
+ " -o %s" +
+ " -L 1:10,000,000-10,100,000";
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // testing BAQ with SLX, 454, and SOLID data
+ //
+ // --------------------------------------------------------------------------------------------------------------
+ @Test
+ public void testPrintReadsNoBAQ() {
+ WalkerTestSpec spec = new WalkerTestSpec( baseCommand +" -baq OFF", 1, Arrays.asList("d1f74074e718c82810512bf40dbc7f72"));
+ executeTest(String.format("testPrintReadsNoBAQ"), spec);
+ }
+
+ @Test
+ public void testPrintReadsRecalBAQ() {
+ WalkerTestSpec spec = new WalkerTestSpec( baseCommand +" -baq RECALCULATE", 1, Arrays.asList("96ec97cf92f1f660bd5244c6b44539b3"));
+ executeTest(String.format("testPrintReadsRecalBAQ"), spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/CNV/SymbolicAllelesIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/CNV/SymbolicAllelesIntegrationTest.java
new file mode 100644
index 0000000..16e47cd
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/CNV/SymbolicAllelesIntegrationTest.java
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.CNV;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+public class SymbolicAllelesIntegrationTest extends WalkerTest {
+
+ public static String baseTestString(String reference, String VCF) {
+ return "-T CombineVariants" +
+ " -R " + reference +
+ " --variant:vcf " + privateTestDir + VCF +
+ " -filteredRecordsMergeType KEEP_IF_ANY_UNFILTERED" +
+ " -genotypeMergeOptions REQUIRE_UNIQUE" +
+ " -setKey null" +
+ " -o %s" +
+ " --no_cmdline_in_header";
+ }
+
+ @Test(enabled = true)
+ public void test1() {
+ WalkerTestSpec spec = new WalkerTestSpec(
+ baseTestString(b36KGReference, "symbolic_alleles_1.vcf"),
+ 1,
+ Arrays.asList("5bafc5a99ea839e686e55de93f91fd5c"));
+ executeTest("Test symbolic alleles", spec);
+ }
+
+ @Test(enabled = true)
+ public void test2() {
+ WalkerTestSpec spec = new WalkerTestSpec(
+ baseTestString(b36KGReference, "symbolic_alleles_2.vcf"),
+ 1,
+ Arrays.asList("30f66a097987330d42e87da8bcd6be21"));
+ executeTest("Test symbolic alleles mixed in with non-symbolic alleles", spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/annotator/SnpEffUtilUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/annotator/SnpEffUtilUnitTest.java
new file mode 100644
index 0000000..ec10d7d
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/annotator/SnpEffUtilUnitTest.java
@@ -0,0 +1,111 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.annotator;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: farjoun
+ * Date: 6/5/13
+ * Time: 2:31 PM
+ * To change this template use File | Settings | File Templates.
+ */
+
+
+import org.broadinstitute.gatk.tools.walkers.annotator.SnpEff.EffectType;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SnpEffUtilUnitTest {
+
+
+ @DataProvider(name="effects")
+ public Object[][] childParentpairs() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ tests.add(new Object[]{EffectType.GENE,EffectType.CHROMOSOME});
+ tests.add(new Object[]{EffectType.UTR_3_PRIME,EffectType.TRANSCRIPT});
+ tests.add(new Object[]{EffectType.CODON_CHANGE,EffectType.CDS});
+ tests.add(new Object[]{EffectType.STOP_GAINED,EffectType.EXON});
+ tests.add(new Object[]{EffectType.SYNONYMOUS_START,EffectType.TRANSCRIPT});
+ tests.add(new Object[]{EffectType.FRAME_SHIFT,EffectType.CDS});
+ tests.add(new Object[]{EffectType.UPSTREAM,EffectType.INTERGENIC});
+ tests.add(new Object[]{EffectType.SPLICE_SITE_DONOR,EffectType.INTRON});
+ tests.add(new Object[]{EffectType.SPLICE_SITE_ACCEPTOR,EffectType.INTRON});
+ tests.add(new Object[]{EffectType.STOP_LOST,EffectType.NON_SYNONYMOUS_CODING});
+ return tests.toArray(new Object[][]{});
+ }
+
+ @DataProvider(name="self")
+ public Object[][] childEqualsParentpairs() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for(EffectType type:EffectType.values()){
+ tests.add(new Object[]{type,type});
+ }
+ return tests.toArray(new Object[][]{});
+ }
+
+ @DataProvider(name="noneffects")
+ public Object[][] nonchildParentpairs() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ tests.add(new Object[]{EffectType.START_GAINED,EffectType.NON_SYNONYMOUS_CODING});
+ tests.add(new Object[]{EffectType.GENE,EffectType.NONE});
+ tests.add(new Object[]{EffectType.UTR_3_PRIME,EffectType.CDS});
+ tests.add(new Object[]{EffectType.CODON_CHANGE,EffectType.REGULATION});
+ tests.add(new Object[]{EffectType.DOWNSTREAM,EffectType.REGULATION});
+ tests.add(new Object[]{EffectType.SPLICE_SITE_ACCEPTOR,EffectType.EXON});
+ tests.add(new Object[]{EffectType.START_GAINED,EffectType.SYNONYMOUS_START});
+ tests.add(new Object[]{EffectType.NON_SYNONYMOUS_CODING,EffectType.DOWNSTREAM});
+ tests.add(new Object[]{EffectType.CODON_DELETION,EffectType.INTRON});
+ tests.add(new Object[]{EffectType.UTR_5_PRIME,EffectType.EXON_DELETED});
+ tests.add(new Object[]{EffectType.INTRON,EffectType.NONE});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "effects")
+ public void testSubType(EffectType subType,EffectType parentType) {
+ Assert.assertTrue(SnpEffUtil.isSubTypeOf(subType,parentType),String.format("testing that %s is subtype of %s.",subType,parentType));
+ }
+ @Test(dataProvider = "self")
+ public void testSubTypeSelf(EffectType subType,EffectType parentType) {
+ Assert.assertTrue(SnpEffUtil.isSubTypeOf(subType,parentType),String.format("testing that %s is subtype of %s.",subType,parentType));
+ }
+ @Test(dataProvider = "effects")
+ public void testNonSubTypeSelf(EffectType parentType,EffectType subType) {
+ Assert.assertTrue(!SnpEffUtil.isSubTypeOf(subType,parentType),String.format("testing that %s is subtype of %s.",subType,parentType));
+ }
+ @Test(dataProvider = "noneffects")
+ public void testNonSubType(EffectType subType,EffectType parentType) {
+ Assert.assertTrue(!SnpEffUtil.isSubTypeOf(subType, parentType), String.format("testing that %s is NOT subtype of %s.", subType, parentType));
+ Assert.assertTrue(!SnpEffUtil.isSubTypeOf(parentType,subType), String.format("testing that %s is NOT subtype of %s.", parentType,subType));
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/CallableLociIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/CallableLociIntegrationTest.java
new file mode 100644
index 0000000..b597947
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/CallableLociIntegrationTest.java
@@ -0,0 +1,69 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.coverage;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+public class CallableLociIntegrationTest extends WalkerTest {
+ final static String commonArgs = "-R " + b36KGReference + " -T CallableLoci -I " + validationDataLocation + "/NA12878.1kg.p2.chr1_10mb_11_mb.SLX.bam -o %s";
+
+ final static String SUMMARY_MD5 = "a6f5963669f19d9d137ced87d65834b0";
+
+ @Test
+ public void testCallableLociWalkerBed() {
+ String gatk_args = commonArgs + " -format BED -L 1:10,000,000-11,000,000 -summary %s";
+ WalkerTestSpec spec = new WalkerTestSpec(gatk_args, 2,
+ Arrays.asList("9b4ffea1dbcfefadeb1c9fa74b0e0e59", SUMMARY_MD5));
+ executeTest("formatBed", spec);
+ }
+
+ @Test
+ public void testCallableLociWalkerPerBase() {
+ String gatk_args = commonArgs + " -format STATE_PER_BASE -L 1:10,000,000-11,000,000 -summary %s";
+ WalkerTestSpec spec = new WalkerTestSpec(gatk_args, 2,
+ Arrays.asList("d6505e489899e80c08a7168777f6e07b", SUMMARY_MD5));
+ executeTest("format_state_per_base", spec);
+ }
+
+ @Test
+ public void testCallableLociWalker2() {
+ String gatk_args = commonArgs + " -format BED -L 1:10,000,000-10,000,100 -L 1:10,000,110-10,000,120 -summary %s";
+ WalkerTestSpec spec = new WalkerTestSpec(gatk_args, 2,
+ Arrays.asList("330f476085533db92a9dbdb3a127c041", "d287510eac04acf5a56f5cde2cba0e4a"));
+ executeTest("formatBed by interval", spec);
+ }
+
+ @Test
+ public void testCallableLociWalker3() {
+ String gatk_args = commonArgs + " -format BED -L 1:10,000,000-11,000,000 -minDepth 10 -maxDepth 100 --minBaseQuality 10 --minMappingQuality 20 -summary %s";
+ WalkerTestSpec spec = new WalkerTestSpec(gatk_args, 2,
+ Arrays.asList("7f79ad8195c4161060463eeb21d2bb11", "7ee269e5f4581a924529a356cc806e55"));
+ executeTest("formatBed lots of arguments", spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/CompareCallableLociWalkerIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/CompareCallableLociWalkerIntegrationTest.java
new file mode 100644
index 0000000..ccfd743
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/CompareCallableLociWalkerIntegrationTest.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.coverage;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+public class CompareCallableLociWalkerIntegrationTest extends WalkerTest {
+ final static String commonArgs = "-R " + hg18Reference + " -T CompareCallableLoci --comp1:Bed " + validationDataLocation + "1kg_slx.chr1_10mb.callable.bed --comp2:Bed " + validationDataLocation + "ga2_slx.chr1_10mb.callable.bed -o %s";
+
+ @Test
+ public void testCompareCallableLociWalker1() {
+ String gatk_args = commonArgs + " -L chr1:1-10,000,000";
+ WalkerTestSpec spec = new WalkerTestSpec(gatk_args, 1, Arrays.asList("70efebac55ff210bb022e9e22ed80a95"));
+ executeTest("CompareCallableLoci Walker", spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverageB36IntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverageB36IntegrationTest.java
new file mode 100644
index 0000000..447515d
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverageB36IntegrationTest.java
@@ -0,0 +1,111 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.coverage;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * IF THERE IS NO JAVADOC RIGHT HERE, YELL AT chartl
+ *
+ * @Author chartl
+ * @Date May 20, 2010
+ */
+public class DepthOfCoverageB36IntegrationTest extends WalkerTest {
+
+ private boolean RUN_TESTS = true;
+ private String root = "-T DepthOfCoverage ";
+
+ private String buildRootCmd(String ref, List<String> bams, List<String> intervals) {
+ StringBuilder bamBuilder = new StringBuilder();
+ do {
+ bamBuilder.append(" -I ");
+ bamBuilder.append(bams.remove(0));
+ } while ( bams.size() > 0 );
+
+ StringBuilder intervalBuilder = new StringBuilder();
+ do {
+ intervalBuilder.append(" -L ");
+ intervalBuilder.append(intervals.remove(0));
+ } while ( intervals.size() > 0 );
+
+
+ return root + "-R "+ref+bamBuilder.toString()+intervalBuilder.toString();
+ }
+
+ private void execute(String name, WalkerTest.WalkerTestSpec spec) {
+ if ( RUN_TESTS ) {
+ executeTest(name,spec);
+ }
+ }
+
+ @Test
+ public void testMapQ0Only() {
+ String[] intervals = {"1:10,000,000-10,002,000","1:10,003,000-10,004,000"};
+ String[] bams = {"/humgen/gsa-hpprojects/GATK/data/Validation_Data/NA12878.1kg.p2.chr1_10mb_11_mb.allTechs.bam"};
+
+ String cmd = buildRootCmd(b36KGReference,new ArrayList<String>(Arrays.asList(bams)), new ArrayList<String>(Arrays.asList(intervals))) + " --maxMappingQuality 0";
+
+ WalkerTestSpec spec = new WalkerTestSpec(cmd,0,new ArrayList<String>());
+
+ // our base file
+ final File baseOutputFile = createTempFile("depthofcoveragemapq0",".tmp");
+
+ spec.setOutputFileLocation(baseOutputFile);
+ spec.addAuxFile("f39af6ad99520fd4fb27b409ab0344a0",baseOutputFile);
+ spec.addAuxFile("6b15f5330414b6d4e2f6caea42139fa1", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_cumulative_coverage_counts"));
+ spec.addAuxFile("cc6640d82077991dde8a2b523935cdff", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_cumulative_coverage_proportions"));
+ spec.addAuxFile("0fb627234599c258a3fee1b2703e164a", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_interval_statistics"));
+ spec.addAuxFile("cb73a0fa0cee50f1fb8f249315d38128", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_interval_summary"));
+ spec.addAuxFile("347b47ef73fbd4e277704ddbd7834f69", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_statistics"));
+ spec.addAuxFile("4ec920335d4b9573f695c39d62748089", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_summary"));
+
+
+ execute("testMapQ0Only",spec);
+ }
+
+ @Test
+ public void testLotsOfSamples() {
+ final String[] intervals = {"1:1105290-1105295"};
+ final String[] bams = {"/humgen/gsa-hpprojects/GATK/data/Validation_Data/pilot3.CEU+TSI.5loci.bam"};
+ final String cmd = buildRootCmd(b36KGReference, new ArrayList<String>(Arrays.asList(bams)), new ArrayList<String>(Arrays.asList(intervals)));
+
+ final WalkerTestSpec spec = new WalkerTestSpec(cmd,0,new ArrayList<String>());
+
+ final File baseOutputFile = createTempFile("testManySamples",".tmp");
+
+ spec.setOutputFileLocation(baseOutputFile);
+ spec.addAuxFile("c9561b52344536d2b06ab97b0bb1a234",baseOutputFile);
+
+ execute("testLotsOfSamples",spec);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverageIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverageIntegrationTest.java
new file mode 100644
index 0000000..61785e8
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/coverage/DepthOfCoverageIntegrationTest.java
@@ -0,0 +1,181 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.coverage;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Integration tests for the Depth of Coverage walker
+ *
+ * @Author chartl
+ * @Date Feb 25, 2010
+ */
+public class DepthOfCoverageIntegrationTest extends WalkerTest {
+
+ private boolean RUN_TESTS = true;
+ private String root = "-T DepthOfCoverage ";
+
+ private String buildRootCmd(String ref, List<String> bams, List<String> intervals) {
+ StringBuilder bamBuilder = new StringBuilder();
+ do {
+ bamBuilder.append(" -I ");
+ bamBuilder.append(bams.remove(0));
+ } while ( bams.size() > 0 );
+
+ StringBuilder intervalBuilder = new StringBuilder();
+ do {
+ intervalBuilder.append(" -L ");
+ intervalBuilder.append(intervals.remove(0));
+ } while ( intervals.size() > 0 );
+
+
+ return root + "-R "+ref+bamBuilder.toString()+intervalBuilder.toString();
+ }
+
+ private void execute(String name, WalkerTestSpec spec) {
+ if ( RUN_TESTS ) {
+ executeTest(name,spec);
+ }
+ }
+
+ @Test
+ public void testBaseOutputNoFiltering() {
+ final String[] intervals = {"/humgen/gsa-hpprojects/GATK/data/Validation_Data/fhs_jhs_30_targts.interval_list"};
+ final String[] bams = {"/humgen/gsa-hpprojects/GATK/data/Validation_Data/FHS_indexed_subset.bam"};
+
+ final String cmd = buildRootCmd(hg18Reference,new ArrayList<>(Arrays.asList(bams)),new ArrayList<>(Arrays.asList(intervals))) + " -mmq 0 -mbq 0 -dels -baseCounts -pt readgroup -pt sample -pt library --outputFormat csv -ct 10 -ct 15 -ct 20 -ct 25";
+ final WalkerTestSpec spec = new WalkerTestSpec(cmd,0, new ArrayList<String>());
+
+ // our base file
+ final File baseOutputFile = createTempFile("depthofcoveragenofiltering",".tmp");
+ spec.setOutputFileLocation(baseOutputFile);
+
+ // now add the expected files that get generated
+ spec.addAuxFile("0f9603eb1ca4a26828e82d8c8f4991f6", baseOutputFile);
+ spec.addAuxFile("51e6c09a307654f43811af35238fb179", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".library_cumulative_coverage_counts"));
+ spec.addAuxFile("520720a88ae7608257af51bc41c06b87", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".library_cumulative_coverage_proportions"));
+ spec.addAuxFile("9cd395f47b329b9dd00ad024fcac9929", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".library_interval_statistics"));
+ spec.addAuxFile("6958004a8156f3f267caa6b04cf90f5f", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".library_interval_summary"));
+ spec.addAuxFile("ebbfc9b9f4e12ac989c127061948c565", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".library_statistics"));
+ spec.addAuxFile("e003bef6762833a5cebca25d94194616", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".library_summary"));
+ spec.addAuxFile("a836b92ac17b8ff9788e2aaa9116b5d4", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".read_group_cumulative_coverage_counts"));
+ spec.addAuxFile("0732b6d2db9c94b0fcf18ca1f19772a8", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".read_group_cumulative_coverage_proportions"));
+ spec.addAuxFile("7b9d0e93bf5b5313995be7010ef1f528", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".read_group_interval_statistics"));
+ spec.addAuxFile("3522f7380554b926c71a7258250c1d63", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".read_group_interval_summary"));
+ spec.addAuxFile("2cd9d8c5e37584edd62ca6938659cf59", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".read_group_statistics"));
+ spec.addAuxFile("78fdd35a63a7a4c6b3a043b946b04730", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".read_group_summary"));
+ spec.addAuxFile("6909d50a7da337cd294828b32b945eb8", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_cumulative_coverage_counts"));
+ spec.addAuxFile("aa00e3652dd518ccbae2caa00171835b", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_cumulative_coverage_proportions"));
+ spec.addAuxFile("df0ba76e0e6082c0d29fcfd68efc6b77", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_interval_statistics"));
+ spec.addAuxFile("0ce5ebfa46b081820d013bdbbfe42d34", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_interval_summary"));
+ spec.addAuxFile("c7c5bad6c6818995c634f350aa66fde9", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_statistics"));
+ spec.addAuxFile("949c9ce745753cd98f337600d3931d09", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_summary"));
+
+ execute("testBaseOutputNoFiltering",spec);
+ }
+
+ @Test
+ public void testNoCoverageDueToFiltering() {
+ String[] intervals = {"/humgen/gsa-hpprojects/GATK/data/Validation_Data/fhs_jhs_30_targts.interval_list"};
+ String[] bams = {"/humgen/gsa-hpprojects/GATK/data/Validation_Data/FHS_indexed_subset.bam"};
+
+ String cmd = buildRootCmd(hg18Reference,new ArrayList<String>(Arrays.asList(bams)),new ArrayList<String>(Arrays.asList(intervals))) + " -mmq 0 -mbq 5 --maxBaseQuality 4 -dels -baseCounts -pt readgroup -pt sample -pt library --outputFormat csv";
+ WalkerTestSpec spec = new WalkerTestSpec(cmd,0, new ArrayList<String>());
+
+ File baseOutputFile = createTempFile("depthofcoveragenofiltering",".tmp");
+ spec.setOutputFileLocation(baseOutputFile);
+
+ spec.addAuxFile("6ccd7d8970ba98cb95fe41636a070c1c",baseOutputFile);
+ spec.addAuxFile("4429d33ce8836c09ba2b5ddfae2f998e",createTempFileFromBase(baseOutputFile.getAbsolutePath()+".library_interval_summary"));
+
+ execute("testNoCoverageDueToFiltering",spec);
+ }
+
+ @Test
+ public void testAdjacentIntervals() {
+ String[] intervals = {"chr1:1-999", "chr1:1000-65536", "chr1:65537-80000", "chr1:80001-81000"};
+ String[] bams = {publicTestDir+"exampleBAM.bam"};
+
+ String cmd = buildRootCmd(exampleFASTA, new ArrayList<String>(Arrays.asList(bams)), new ArrayList<String>(Arrays.asList(intervals))) + " -im OVERLAPPING_ONLY";
+ WalkerTestSpec spec = new WalkerTestSpec(cmd, 0, new ArrayList<String>());
+
+ File baseOutputFile = WalkerTest.createTempFile("depthofcoverageadjinterval", ".tmp");
+ spec.setOutputFileLocation(baseOutputFile);
+
+ spec.addAuxFile("84b95d62f53e28919d1b5286558a1cae", baseOutputFile);
+ spec.addAuxFile("e445d4529dd3e3caa486ab8f5ec63e49", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_cumulative_coverage_counts"));
+ spec.addAuxFile("b69c89ba8b0c393b735616c2bc3aea76", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_cumulative_coverage_proportions"));
+ spec.addAuxFile("788988dac6119a02de2c8d4dfb06b727", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_interval_statistics"));
+ spec.addAuxFile("3769ed40ab3ccd2ed94a9dc05cc2bc2f", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_interval_summary"));
+ spec.addAuxFile("1281605e022d7462fbbcd14de53d1ca3", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_statistics"));
+ spec.addAuxFile("4b41d6ff88aa2662697cb7e4b5346cb8", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_summary"));
+
+ execute("testAdjacentIntervals", spec);
+ }
+
+
+ @Test
+ public void testSortOrder() {
+ // This test came from a user who discovered that the columns and data in the gene_summary file didn't align for the specific
+ // sample names in these files.
+ String[] intervals = {"1:1600000-1700000"};
+ String[] bams = {privateTestDir+"badHashName1.bam", privateTestDir+"badHashName2.bam"};
+
+ String cmd = buildRootCmd(b37KGReference, new ArrayList<String>(Arrays.asList(bams)), new ArrayList<String>(Arrays.asList(intervals))) +
+ " -geneList "+privateTestDir+"refGene_CDK11B.txt";
+ WalkerTestSpec spec = new WalkerTestSpec(cmd, 0, new ArrayList<String>());
+
+ File baseOutputFile = WalkerTest.createTempFile("depthofcoveragesortorder", ".tmp");
+ spec.setOutputFileLocation(baseOutputFile);
+
+ spec.addAuxFile("a148e50f9db207adfd5d5f0f29eb54d8", baseOutputFile);
+ spec.addAuxFile("7ccd5193a3c035d1cc856cbc89e3daf4", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_cumulative_coverage_counts"));
+ spec.addAuxFile("2efe59c20721ce61bc5b334a26d11720", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_cumulative_coverage_proportions"));
+ spec.addAuxFile("9194cec953e0fe0b84a681f9bb63ffbe", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_gene_summary"));
+ spec.addAuxFile("cf62d95ec1f459fbbe35370c3f0ca481", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_interval_statistics"));
+ spec.addAuxFile("b4fcb739b7f9e309e38a7d5e7e4ebb9f", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_interval_summary"));
+ spec.addAuxFile("6bf63f9c62071e850c6f0b6356fb63eb", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_statistics"));
+ spec.addAuxFile("e53e6a494bf1cf817762b74917c6f0c9", createTempFileFromBase(baseOutputFile.getAbsolutePath()+".sample_summary"));
+
+ execute("testSortOrder", spec);
+ }
+
+ public void testRefNHandling(boolean includeNs, final String md5) {
+ String command = "-R " + b37KGReference + " -L 20:26,319,565-26,319,575 -I " + validationDataLocation + "NA12878.HiSeq.WGS.bwa.cleaned.recal.hg19.20.bam -T DepthOfCoverage -baseCounts --omitIntervalStatistics --omitLocusTable --omitPerSampleStats -o %s";
+ if ( includeNs ) command += " --includeRefNSites";
+ WalkerTestSpec spec = new WalkerTestSpec(command, 1, Arrays.asList(md5));
+ executeTest("Testing DoC " + (includeNs ? "with" : "without") + " reference Ns", spec);
+ }
+
+ @Test public void testRefNWithNs() { testRefNHandling(true, "24cd2da2e4323ce6fd76217ba6dc2834"); }
+ @Test public void testRefNWithoutNs() { testRefNHandling(false, "4fc0f1a2e968f777d693abcefd4fb7af"); }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/CheckPileupIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/CheckPileupIntegrationTest.java
new file mode 100644
index 0000000..eae4dec
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/CheckPileupIntegrationTest.java
@@ -0,0 +1,70 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.testng.annotations.Test;
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+
+import java.util.Collections;
+
+/**
+ * Run validating pileup across a set of core data as proof of the integrity of the GATK core.
+ *
+ * Tests both types of old-school pileup formats (basic and consensus).
+ *
+ * @author mhanna, vdauwera
+ * @version 0.2
+ */
+public class CheckPileupIntegrationTest extends WalkerTest {
+ /**
+ * This test runs on a consensus pileup containing 10-column lines for SNPs and 13-column lines for indels
+ */
+ @Test(enabled = true)
+ public void testEcoliConsensusPileup() {
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CheckPileup" +
+ " -I " + validationDataLocation + "MV1994.selected.bam" +
+ " -R " + validationDataLocation + "Escherichia_coli_K12_MG1655.fasta" +
+ " --pileup:SAMPileup "+ validationDataLocation + "MV1994.selected.pileup" +
+ " -S SILENT -nt 8",0, Collections.<String>emptyList());
+ executeTest("testEcoliConsensusPileup",spec);
+ }
+
+ /**
+ * This test runs on a basic pileup containing 6-column lines for all variants TODO
+ */
+ @Test
+ public void testEcoliBasicPileup() {
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CheckPileup" +
+ " -I " + validationDataLocation + "MV1994.selected.bam" +
+ " -R " + validationDataLocation + "Escherichia_coli_K12_MG1655.fasta" +
+ " --pileup:SAMPileup "+ validationDataLocation + "MV1994.basic.pileup" +
+ " -L Escherichia_coli_K12:1-49" +
+ " -S SILENT -nt 8",0, Collections.<String>emptyList());
+ executeTest("testEcoliBasicPileup",spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/CountReadsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/CountReadsUnitTest.java
new file mode 100644
index 0000000..e79edfd
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/CountReadsUnitTest.java
@@ -0,0 +1,51 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class CountReadsUnitTest extends BaseTest {
+
+ @Test
+ public void testReadsDoNotOverflowInt() {
+
+ final CountReads walker = new CountReads();
+
+ final long moreThanMaxInt = ((long)Integer.MAX_VALUE) + 1L;
+
+ Long sum = walker.reduceInit();
+
+ for ( long i = 0L; i < moreThanMaxInt; i++ ) {
+ final Integer x = walker.map(null, null, null);
+ sum = walker.reduce(x, sum);
+ }
+
+ Assert.assertEquals(sum.longValue(), moreThanMaxInt);
+ Assert.assertTrue(sum.longValue() > (long) Integer.MAX_VALUE);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/DictionaryConsistencyIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/DictionaryConsistencyIntegrationTest.java
new file mode 100644
index 0000000..69e623e
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/DictionaryConsistencyIntegrationTest.java
@@ -0,0 +1,82 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.annotations.Test;
+
+/**
+ *
+ */
+public class DictionaryConsistencyIntegrationTest extends WalkerTest {
+ private static final String callsHG18 = BaseTest.validationDataLocation + "HiSeq.WGS.cleaned.ug.snpfiltered.indelfiltered.optimized.cut.vcf";
+ private static final String callsB36 = BaseTest.validationDataLocation + "lowpass.N3.chr1.raw.vcf";
+ private static final String lexHG18 = BaseTest.validationDataLocation + "lexFasta/lex.hg18.fasta";
+ private static final String b36BAM = BaseTest.validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.allTechs.bam";
+ private static final String hg18BAM = BaseTest.validationDataLocation + "NA12878.WEx.downsampled20x.bam";
+
+ // testing hg18 calls
+ @Test public void fail1() { executeTest("b36xhg18", testVCF(b36KGReference, callsHG18)); }
+ @Test public void fail2() { executeTest("b37xhg18", testVCF(b37KGReference, callsHG18)); }
+ @Test public void fail3() { executeTest("hg19xhg18", testVCF(hg19Reference, callsHG18)); }
+ @Test public void fail4() { executeTest("hg18lex-v-hg18", testVCF(lexHG18, callsHG18, UserException.LexicographicallySortedSequenceDictionary.class)); }
+
+ // testing b36 calls
+ @Test public void fail5() { executeTest("b36xb36", testVCF(hg18Reference, callsB36)); }
+ @Test public void fail6() { executeTest("b37xb36", testVCF(b37KGReference, callsB36)); }
+ @Test public void fail7() { executeTest("hg19xb36", testVCF(hg19Reference, callsB36)); }
+ @Test public void fail8() { executeTest("hg18lex-v-b36", testVCF(lexHG18, callsB36, UserException.LexicographicallySortedSequenceDictionary.class)); }
+
+ private WalkerTest.WalkerTestSpec testVCF(String ref, String vcf) {
+ return testVCF(ref, vcf, UserException.IncompatibleSequenceDictionaries.class);
+ }
+
+ private WalkerTest.WalkerTestSpec testVCF(String ref, String vcf, Class c) {
+ return new WalkerTest.WalkerTestSpec("-T VariantsToTable -M 10 --variant:vcf "
+ + vcf + " -F POS,CHROM -R "
+ + ref + " -o %s",
+ 1, c);
+
+ }
+
+ @Test public void failBAM1() { executeTest("b36bam-v-b37", testBAM(b37KGReference, b36BAM, "1", UserException.IncompatibleSequenceDictionaries.class)); }
+ @Test public void failBAM2() { executeTest("b36bam-v-hg18", testBAM(hg18Reference, b36BAM, "chr1", UserException.IncompatibleSequenceDictionaries.class)); }
+ @Test public void failBAM3() { executeTest("b36bam-v-hg19", testBAM(hg19Reference, b36BAM, "1", UserException.IncompatibleSequenceDictionaries.class)); }
+ @Test public void failBAM4() { executeTest("b36bam-v-lexhg18", testBAM(lexHG18, b36BAM, "chr1", UserException.LexicographicallySortedSequenceDictionary.class)); }
+
+ @Test public void failBAM5() { executeTest("hg18bam-v-b36", testBAM(b36KGReference, hg18BAM, "1", UserException.IncompatibleSequenceDictionaries.class)); }
+ @Test public void failBAM6() { executeTest("hg18bam-v-b37", testBAM(b37KGReference, hg18BAM, "1", UserException.IncompatibleSequenceDictionaries.class)); }
+ @Test public void failBAM7() { executeTest("hg18bam-v-hg19", testBAM(hg19Reference, hg18BAM, "1", UserException.IncompatibleSequenceDictionaries.class)); }
+ @Test public void failBAM8() { executeTest("hg18bam-v-lexhg18", testBAM(lexHG18, hg18BAM, "chr1", UserException.LexicographicallySortedSequenceDictionary.class)); }
+
+ private WalkerTest.WalkerTestSpec testBAM(String ref, String bam, String contig, Class c) {
+ return new WalkerTest.WalkerTestSpec("-T PrintReads -I " + bam + " -R " + ref + " -L " + contig + ":10,000,000-11,000,000 -o %s",
+ 1, c);
+
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/FlagStatIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/FlagStatIntegrationTest.java
new file mode 100644
index 0000000..7a88681
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/FlagStatIntegrationTest.java
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+public class FlagStatIntegrationTest extends WalkerTest {
+
+ @Test
+ public void testFlagStat() {
+ String md5 = "9c4039662f24bfd23ccf67973cb5df29";
+
+ WalkerTestSpec spec = new WalkerTestSpec(
+ "-T FlagStat -R " + b36KGReference + " -I " + validationDataLocation + "NA12878.1kg.p2.chr1_10mb_11_mb.SLX.bam -L 1:10,000,000-10,050,000 -o %s",
+ 1,
+ Arrays.asList(md5));
+ executeTest("test flag stat", spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/PileupWalkerIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/PileupWalkerIntegrationTest.java
new file mode 100644
index 0000000..38154bd
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/qc/PileupWalkerIntegrationTest.java
@@ -0,0 +1,123 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.qc;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class PileupWalkerIntegrationTest extends WalkerTest {
+
+ @Test
+ public void testGnarleyFHSPileup() {
+ String gatk_args = "-T Pileup -I " + validationDataLocation + "FHS_Pileup_Test.bam "
+ + "-R " + hg18Reference
+ + " -L chr15:46,347,148 -o %s";
+ String expected_md5 = "526c93b0fa660d6b953b57103e59fe98";
+ WalkerTestSpec spec = new WalkerTestSpec(gatk_args, 1, Arrays.asList(expected_md5));
+ executeTest("Testing the standard (no-indel) pileup on three merged FHS pools with 27 deletions in 969 bases", spec);
+ }
+
+
+
+ private final static String SingleReadAligningOffChromosome1MD5 = "4a45fe1f85aaa8c4158782f2b6dee2bd";
+ @Test
+ public void testSingleReadAligningOffChromosome1() {
+ String gatk_args = "-T Pileup "
+ + " -I " + privateTestDir + "readOffb37contig1.bam"
+ + " -R " + b37KGReference
+ + " -o %s";
+ WalkerTestSpec spec = new WalkerTestSpec(gatk_args, 1, Arrays.asList(SingleReadAligningOffChromosome1MD5));
+ executeTest("Testing single read spanning off chromosome 1", spec);
+ }
+
+ @Test
+ public void testSingleReadAligningOffChromosome1NoIndex() {
+ String gatk_args = "-T Pileup "
+ + " -I " + privateTestDir + "readOffb37contig1.noIndex.bam"
+ + " -R " + b37KGReference
+ + " -U ALLOW_UNINDEXED_BAM"
+ + " -o %s";
+ WalkerTestSpec spec = new WalkerTestSpec(gatk_args, 1, Arrays.asList(SingleReadAligningOffChromosome1MD5));
+ executeTest("Testing single read spanning off chromosome 1 unindexed", spec);
+ }
+
+ /************************/
+
+ //testing speedup to GATKBAMIndex
+
+
+ @DataProvider(name="GATKBAMIndexTest")
+ public Object[][] makeMyDataProvider() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+ tests.add(new Object[]{"-L 20:1-76,050","8702701350de11a6d28204acefdc4775"});
+ tests.add(new Object[]{"-L 20:10,000,000-10,001,100","818cf5a8229efe6f89fc1cd8145ccbe3"});
+ tests.add(new Object[]{"-L 20:62,954,114-63,025,520","22471ea4a12e5139aef62bf8ff2a5b63"});
+ tests.add(new Object[]{"-L 20:1-76,050 -L 20:20,000,000-20,000,100 -L 20:40,000,000-40,000,100 -L 20:30,000,000-30,000,100 -L 20:50,000,000-50,000,100 -L 20:62,954,114-63,025,520 ","08d899ed7c5a76ef3947bf67338acda1"});
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "GATKBAMIndexTest")
+ public void testGATKBAMIndexSpeedup(final String intervals, final String md5){
+ final String gatkArgs="-T Pileup -I " + validationDataLocation + "NA12878.HiSeq.WGS.bwa.cleaned.recal.hg19.20.bam "
+ + "-R " + hg19Reference + " -o %s ";
+
+ WalkerTestSpec spec = new WalkerTestSpec(gatkArgs + intervals, 1, Arrays.asList(md5));
+ executeTest("Testing with intervals="+intervals, spec);
+ }
+
+
+ /***********************/
+
+ // testing hidden option -outputInsertLength
+ private final static String SingleReadAligningOffChromosome1withInsertLengthMD5 = "279e2ec8832e540f47a6e2bdf4cef5ea";
+ @Test
+ public void testSingleReadAligningOffChromosome1withInsertLength() {
+ String gatk_args = "-T Pileup "
+ + " -I " + privateTestDir + "readOffb37contig1.bam"
+ + " -R " + b37KGReference
+ + " -outputInsertLength"
+ + " -o %s";
+ WalkerTestSpec spec = new WalkerTestSpec(gatk_args, 1, Arrays.asList(SingleReadAligningOffChromosome1withInsertLengthMD5));
+ executeTest("Testing single read spanning off chromosome 1 (with insert length)", spec);
+ }
+
+ @Test
+ public void testGnarleyFHSPileupwithInsertLength() {
+ String gatk_args = "-T Pileup -I " + validationDataLocation + "FHS_Pileup_Test.bam "
+ + "-R " + hg18Reference
+ + " -outputInsertLength"
+ + " -L chr15:46,347,148 -o %s";
+ String expected_md5 = "53ced173768f3d4d90b8a8206e72eae5";
+ WalkerTestSpec spec = new WalkerTestSpec(gatk_args, 1, Arrays.asList(expected_md5));
+ executeTest("Testing the standard (no-indel) pileup on three merged FHS pools with 27 deletions in 969 bases (with insert length)", spec);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/ClipReadsWalkersIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/ClipReadsWalkersIntegrationTest.java
new file mode 100644
index 0000000..29f4621
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/ClipReadsWalkersIntegrationTest.java
@@ -0,0 +1,80 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.readutils;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
+public class ClipReadsWalkersIntegrationTest extends WalkerTest {
+ public void testClipper(String name, String args, String md51, String md52) {
+ WalkerTestSpec spec = new WalkerTestSpec(
+ "-R " + hg18Reference +
+ " -T ClipReads " +
+ "-I " + privateTestDir + "clippingReadsTest.withRG.bam " +
+ "-os %s " +
+ "-o %s " + args,
+ 2, // just one output file
+ Arrays.asList("tmp", "bam"),
+ Arrays.asList(md51, md52));
+ List<File> result = executeTest(name, spec).getFirst();
+ }
+
+ final static String Q10ClipOutput = "b29c5bc1cb9006ed9306d826a11d444f";
+ @Test public void testQClip0() { testClipper("clipQSum0", "-QT 0", "117a4760b54308f81789c39b1c9de578", "12be03c817d94bab88457e5afe74256a"); }
+ @Test public void testQClip2() { testClipper("clipQSum2", "-QT 2", Q10ClipOutput, "1cfc9da4867765c1e5b5bd6326984634"); }
+ @Test public void testQClip10() { testClipper("clipQSum10", "-QT 10", "b29c5bc1cb9006ed9306d826a11d444f", "1cfc9da4867765c1e5b5bd6326984634"); }
+ @Test public void testQClip20() { testClipper("clipQSum20", "-QT 20", "6c3434dce66ae5c9eeea502f10fb9bee", "0bcfd177fe4be422898eda8e161ebd6c"); }
+
+ @Test public void testClipRange1() { testClipper("clipRange1", "-CT 1-5", "b5acd753226e25b1e088838c1aab9117", "aed836c97c6383dd80e39a093cc25e08"); }
+ @Test public void testClipRange2() { testClipper("clipRange2", "-CT 1-5,11-15", "be4fcad5b666a5540028b774169cbad7", "5f6e08bd44d6faf5b85cde5d4ec1a36f"); }
+
+ @Test public void testClipSeq() { testClipper("clipSeqX", "-X CCCCC", "db199bd06561c9f2122f6ffb07941fbc", "f3cb42759428df80d06e9789f9f9f762"); }
+ @Test public void testClipSeqFile() { testClipper("clipSeqXF", "-XF " + privateTestDir + "seqsToClip.fasta", "d011a3152b31822475afbe0281491f8d", "44658c018378467f809b443d047d5778"); }
+
+ @Test public void testClipMulti() { testClipper("clipSeqMulti", "-QT 10 -CT 1-5 -XF " + privateTestDir + "seqsToClip.fasta -X CCCCC", "a23187bd9bfb06557f799706d98441de", "bae38f83eb9b63857f5e6e3c6e62f80c"); }
+
+ @Test public void testClipNs() { testClipper("testClipNs", "-QT 10 -CR WRITE_NS", Q10ClipOutput, "1cfc9da4867765c1e5b5bd6326984634"); }
+ @Test public void testClipQ0s() { testClipper("testClipQs", "-QT 10 -CR WRITE_Q0S", Q10ClipOutput, "3b32da2eaab7a2d4729fdb486cedbb2f"); }
+ @Test public void testClipSoft() { testClipper("testClipSoft", "-QT 10 -CR SOFTCLIP_BASES", Q10ClipOutput, "9d355b0f6d2076178e92bd7fcd8f5adb"); }
+
+ @Test
+ public void testUseOriginalQuals() {
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-R " + hg18Reference +
+ " -T ClipReads" +
+ " -I " + privateTestDir + "originalQuals.chr1.1-1K.bam" +
+ " -L chr1:1-1,000" +
+ " -OQ -QT 4 -CR WRITE_Q0S" +
+ " -o %s -os %s",
+ 2,
+ Arrays.asList("c83b4e2ade8654a2818fe9d405f07662", "55c01ccc2e84481b22d3632cdb06c8ba"));
+ executeTest("clipOriginalQuals", spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReadsIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReadsIntegrationTest.java
new file mode 100644
index 0000000..0213940
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReadsIntegrationTest.java
@@ -0,0 +1,136 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.readutils;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class PrintReadsIntegrationTest extends WalkerTest {
+ private static class PRTest {
+ final String reference;
+ final List<String> bam;
+ final String args;
+ final String md5;
+
+ private PRTest(String reference, String[] bam, String args, String md5) {
+ this.reference = reference;
+ this.bam = new ArrayList<>();
+ this.args = args;
+ this.md5 = md5;
+ this.bam.addAll(Arrays.asList(bam));
+ }
+
+ @Override
+ public String toString() {
+ return String.format("PRTest(bam='%s', args='%s')", bam, args);
+ }
+ }
+
+ @DataProvider(name = "PRTest")
+ public Object[][] createPrintReadsTestData() {
+ return new Object[][]{
+ {new PRTest(hg18Reference, new String[]{"HiSeq.1mb.bam"}, "", "fa9c66f66299fe5405512ac36ec9d0f2")},
+ {new PRTest(hg18Reference, new String[]{"HiSeq.1mb.bam"}, " -compress 0", "488eb22abc31c6af7cbb1a3d41da1507")},
+ {new PRTest(hg18Reference, new String[]{"HiSeq.1mb.bam"}, " -simplifyBAM", "1510dc4429f3ed49caf96da41e8ed396")},
+ {new PRTest(hg18Reference, new String[]{"HiSeq.1mb.bam"}, " -n 10", "0e3d1748ad1cb523e3295cab9d09d8fc")},
+ // See: GATKBAMIndex.getStartOfLastLinearBin(), BAMScheduler.advance(), IntervalOverlapFilteringIterator.advance()
+ {new PRTest(b37KGReference, new String[]{"unmappedFlagReadsInLastLinearBin.bam"}, "", "d7f23fd77d7dc7cb50d3397f644c6d8a")},
+ {new PRTest(b37KGReference, new String[]{"unmappedFlagReadsInLastLinearBin.bam"}, " -L 1", "c601db95b20248d012b0085347fcb6d1")},
+ {new PRTest(b37KGReference, new String[]{"unmappedFlagReadsInLastLinearBin.bam"}, " -L unmapped", "2d32440e47e8d9d329902fe573ad94ce")},
+ {new PRTest(b37KGReference, new String[]{"unmappedFlagReadsInLastLinearBin.bam"}, " -L 1 -L unmapped", "c601db95b20248d012b0085347fcb6d1")},
+ {new PRTest(b37KGReference, new String[]{"oneReadAllInsertion.bam"}, "", "349650b6aa9e574b48a2a62627f37c7d")},
+ {new PRTest(b37KGReference, new String[]{"NA12878.1_10mb_2_10mb.bam"}, "", "0c1cbe67296637a85e80e7a182f828ab")},
+ // Tests for filtering options
+ {new PRTest(b37KGReference, new String[]{"NA12878.1_10mb_2_10mb.bam", "NA20313.highCoverageRegion.bam"},
+ "", "b3ae15c8af33fd5badc1a29e089bdaac")},
+ {new PRTest(b37KGReference, new String[]{"NA12878.1_10mb_2_10mb.bam", "NA20313.highCoverageRegion.bam"},
+ " -readGroup SRR359098", "8bd867b30539524daa7181efd9835a8f")},
+ {new PRTest(b37KGReference, new String[]{"NA12878.1_10mb_2_10mb.bam", "NA20313.highCoverageRegion.bam"},
+ " -readGroup 20FUK.3 -sn NA12878", "93a7bc1b2b1cd27815ed1666cbb4d0cb")},
+ {new PRTest(b37KGReference, new String[]{"NA12878.1_10mb_2_10mb.bam", "NA20313.highCoverageRegion.bam"},
+ " -sn na12878", "52e99cfcf03ff46285d1ba302f8df964")},
+ };
+ }
+
+ @Test(dataProvider = "PRTest")
+ public void testPrintReads(PRTest params) {
+
+ StringBuilder inputs = new StringBuilder();
+ for (String bam : params.bam) {
+ inputs.append(" -I ");
+ inputs.append(privateTestDir);
+ inputs.append(bam);
+ }
+
+ WalkerTestSpec spec = new WalkerTestSpec(
+ "-T PrintReads" +
+ " -R " + params.reference +
+ inputs.toString() +
+ params.args +
+ " --no_pg_tag" +
+ " -o %s",
+ Arrays.asList(params.md5));
+ executeTest("testPrintReads-"+params.args, spec).getFirst();
+ }
+
+ @DataProvider(name = "PRExceptionTest")
+ public Object[][] createPrintReadsExceptionTestData() {
+ return new Object[][]{
+ {new PRTest(b37KGReference, new String[]{"NA12878.1_10mb_2_10mb.bam", "NA20313.highCoverageRegion.bam"},
+ "-platform illum", "")},
+ {new PRTest(b37KGReference, new String[]{"NA12878.1_10mb_2_10mb.bam", "NA20313.highCoverageRegion.bam"},
+ " -sn NotASample", "")},
+ };
+ }
+
+ @Test(dataProvider = "PRExceptionTest")
+ public void testPrintReadsException(PRTest params) {
+
+ StringBuilder inputs = new StringBuilder();
+ for (String bam : params.bam) {
+ inputs.append(" -I ");
+ inputs.append(privateTestDir);
+ inputs.append(bam);
+ }
+
+ WalkerTestSpec spec = new WalkerTestSpec(
+ "-T PrintReads" +
+ " -R " + params.reference +
+ inputs.toString() +
+ params.args +
+ " --no_pg_tag" +
+ " -o %s",
+ 1, UserException.class);
+ executeTest("testPrintReadsException-"+params.args, spec);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReadsLargeScaleTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReadsLargeScaleTest.java
new file mode 100644
index 0000000..956d70f
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReadsLargeScaleTest.java
@@ -0,0 +1,45 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.readutils;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+
+public class PrintReadsLargeScaleTest extends WalkerTest {
+ @Test( timeOut = 1000 * 60 * 60 * 20 ) // 60 seconds * 60 seconds / minute * 20 minutes
+ public void testRealignerTargetCreator() {
+ WalkerTestSpec spec = new WalkerTestSpec(
+ "-R " + b37KGReference +
+ " -T PrintReads" +
+ " -I " + evaluationDataLocation + "CEUTrio.HiSeq.WEx.b37.NA12892.clean.dedup.recal.1.bam" +
+ " -o /dev/null",
+ 0,
+ new ArrayList<String>(0));
+ executeTest("testPrintReadsWholeExomeChr1", spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReadsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReadsUnitTest.java
new file mode 100644
index 0000000..53b6d42
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/PrintReadsUnitTest.java
@@ -0,0 +1,123 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.readutils;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.utils.sam.ArtificialReadsTraversal;
+import org.broadinstitute.gatk.utils.sam.ArtificialGATKSAMFileWriter;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author aaron
+ * <p/>
+ * Class PrintReadsUnitTest
+ * <p/>
+ * This tests the print reads walker, using the artificial reads traversal
+ */
+public class PrintReadsUnitTest extends BaseTest {
+
+ /**
+ * our private fake reads traversal. This traversal seeds the
+ * the walker with a specified number of fake reads, which are named sequentially
+ */
+ private ArtificialReadsTraversal trav;
+ private int readTotal = 0;
+ //private char bases[] = {'a', 't'};
+ private ReferenceContext bases = null;
+ //private ReferenceContext ref = new ReferenceContext()
+
+ org.broadinstitute.gatk.tools.walkers.readutils.PrintReads walker;
+ ArtificialGATKSAMFileWriter writer;
+
+ @BeforeMethod
+ public void before() {
+ trav = new ArtificialReadsTraversal();
+ readTotal = ( ( trav.endingChr - trav.startingChr ) + 1 ) * trav.readsPerChr + trav.unMappedReads;
+
+ walker = new org.broadinstitute.gatk.tools.walkers.readutils.PrintReads();
+ writer = new ArtificialGATKSAMFileWriter();
+ walker.initialize();
+ }
+
+ /** test that we get out the same number of reads we put in */
+ @Test
+ public void testReadCount() {
+ trav.traverse(walker, null, writer);
+ assertEquals(writer.getRecords().size(), readTotal);
+ }
+
+ /** test that we're ok with a null read */
+ @Test
+ public void testNullRead() {
+ SAMRecord rec = walker.map(bases, null, null);
+ assertTrue(rec == null);
+ }
+
+ /** tes that we get the read we put into the map function */
+ @Test
+ public void testReturnRead() {
+ SAMFileHeader head = ArtificialSAMUtils.createArtificialSamHeader(3,1,1000);
+ GATKSAMRecord rec = ArtificialSAMUtils.createArtificialRead(head, "FakeRead", 1, 1, 50);
+ SAMRecord ret = walker.map(bases, rec, null);
+ assertTrue(ret == rec);
+ assertTrue(ret.getReadName().equals(rec.getReadName()));
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/ReadAdaptorTrimmerIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/ReadAdaptorTrimmerIntegrationTest.java
new file mode 100644
index 0000000..65ca2e7
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/readutils/ReadAdaptorTrimmerIntegrationTest.java
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.readutils;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: delangel
+ * Date: 4/13/13
+ * Time: 7:28 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ReadAdaptorTrimmerIntegrationTest extends WalkerTest {
+ private String getBaseCommand(final String BAM) {
+ return "-T ReadAdaptorTrimmer -R " + b37KGReference +
+ " -I " + privateTestDir + BAM +
+ " -o %s";
+ }
+
+ @Test
+ public void testBasicTrimmer() {
+ WalkerTestSpec spec = new WalkerTestSpec( getBaseCommand("shortInsertTest.bam"), 1, Arrays.asList("1d42414e12b45d44e6f396d97d0f60fe"));
+ executeTest(String.format("testBasicTrimmer"), spec);
+ }
+
+ @Test
+ public void testSkippingBadPairs() {
+ WalkerTestSpec spec = new WalkerTestSpec( getBaseCommand("shortInsertTest2.bam")+" -removeUnpairedReads", 1, Arrays.asList("5e796345502fbfc31134f7736ce68868"));
+ executeTest(String.format("testSkippingBadPairs"), spec);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/variantutils/FilterLiftedVariantsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/variantutils/FilterLiftedVariantsUnitTest.java
new file mode 100644
index 0000000..847c8f1
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/variantutils/FilterLiftedVariantsUnitTest.java
@@ -0,0 +1,54 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class FilterLiftedVariantsUnitTest extends BaseTest {
+
+ @Test
+ public void testIndelAtEndOfContig() {
+
+ final List<Allele> alleles = new ArrayList<>(2);
+ alleles.add(Allele.create("AAAAA", true));
+ alleles.add(Allele.create("A", false));
+ final VariantContext vc = new VariantContextBuilder("test", "1", 10, 14, alleles).make();
+
+ final FilterLiftedVariants filter = new FilterLiftedVariants();
+
+ Assert.assertFalse(filter.filterOrWrite(new byte[]{'A'}, vc));
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/variantutils/SelectVariantsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/variantutils/SelectVariantsUnitTest.java
new file mode 100644
index 0000000..117f507
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/tools/walkers/variantutils/SelectVariantsUnitTest.java
@@ -0,0 +1,88 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.tools.walkers.variantutils;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.Utils;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+
+public class SelectVariantsUnitTest extends BaseTest {
+
+ //////////////////////////////////////////
+ // Tests for maxIndelSize functionality //
+ //////////////////////////////////////////
+
+ @DataProvider(name = "MaxIndelSize")
+ public Object[][] MaxIndelSizeTestData() {
+
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final int size : Arrays.asList(1, 3, 10, 100) ) {
+ for ( final int otherSize : Arrays.asList(0, 1) ) {
+ for ( final int max : Arrays.asList(0, 1, 5, 50, 100000) ) {
+ for ( final String op : Arrays.asList("D", "I") ) {
+ tests.add(new Object[]{size, otherSize, max, op});
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "MaxIndelSize")
+ public void maxIndelSizeTest(final int size, final int otherSize, final int max, final String op) {
+
+ final byte[] largerAllele = Utils.dupBytes((byte) 'A', size+1);
+ final byte[] smallerAllele = Utils.dupBytes((byte) 'A', 1);
+
+ final List<Allele> alleles = new ArrayList<Allele>(2);
+ final Allele ref = Allele.create(op.equals("I") ? smallerAllele : largerAllele, true);
+ final Allele alt = Allele.create(op.equals("D") ? smallerAllele : largerAllele, false);
+ alleles.add(ref);
+ alleles.add(alt);
+ if ( otherSize > 0 && otherSize != size ) {
+ final Allele otherAlt = Allele.create(op.equals("D") ? Utils.dupBytes((byte) 'A', size-otherSize+1) : Utils.dupBytes((byte) 'A', otherSize+1), false);
+ alleles.add(otherAlt);
+ }
+
+ final VariantContext vc = new VariantContextBuilder("test", "1", 10, 10 + ref.length() - 1, alleles).make();
+
+ boolean hasTooLargeIndel = SelectVariants.containsIndelLargerThan(vc, max);
+ Assert.assertEquals(hasTooLargeIndel, size > max);
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/AutoFormattingTimeUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/AutoFormattingTimeUnitTest.java
new file mode 100644
index 0000000..22e9517
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/AutoFormattingTimeUnitTest.java
@@ -0,0 +1,118 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.AutoFormattingTime;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * UnitTests for the AutoFormatting
+ *
+ * User: depristo
+ * Date: 8/24/12
+ * Time: 11:25 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class AutoFormattingTimeUnitTest extends BaseTest {
+ @DataProvider(name = "AutoFormattingTimeUnitSelection")
+ public Object[][] makeTimeData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+ tests.add(new Object[]{TimeUnit.SECONDS.toNanos(10), "s"});
+ tests.add(new Object[]{TimeUnit.MINUTES.toNanos(10), "m"});
+ tests.add(new Object[]{TimeUnit.HOURS.toNanos(10), "h"});
+ tests.add(new Object[]{TimeUnit.DAYS.toNanos(10), "d"});
+ tests.add(new Object[]{TimeUnit.DAYS.toNanos(1000), "w"});
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "AutoFormattingTimeUnitSelection")
+ public void testUnitSelection(final long nano, final String expectedUnit) throws InterruptedException {
+ final AutoFormattingTime time = new AutoFormattingTime(nano);
+ testBasic(time, nano, time.getWidth(), time.getPrecision());
+ Assert.assertTrue(time.toString().endsWith(expectedUnit), "TimeUnit " + time.toString() + " didn't contain expected time unit " + expectedUnit);
+ }
+
+ @Test(dataProvider = "AutoFormattingTimeUnitSelection")
+ public void testSecondsAsDouble(final long nano, final String expectedUnit) throws InterruptedException {
+ final double inSeconds = nano * 1e-9;
+ final long nanoFromSeconds = (long)(inSeconds * 1e9);
+ final AutoFormattingTime time = new AutoFormattingTime(inSeconds);
+ testBasic(time, nanoFromSeconds, time.getWidth(), time.getPrecision());
+ }
+
+ @DataProvider(name = "AutoFormattingTimeWidthAndPrecision")
+ public Object[][] makeTimeWidthAndPrecision() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+ for ( final int width : Arrays.asList(-1, 1, 2, 6, 20) ) {
+ for ( final int precision : Arrays.asList(1, 2) ) {
+ tests.add(new Object[]{100.123456 * 1e9, width, precision});
+ tests.add(new Object[]{0.123456 * 1e9, width, precision});
+ }
+ }
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "AutoFormattingTimeWidthAndPrecision")
+ public void testWidthAndPrecision(final double inSeconds, final int width, final int precision) throws InterruptedException {
+ final AutoFormattingTime time = new AutoFormattingTime(inSeconds, width, precision);
+ final long nanoFromSeconds = (long)(inSeconds * 1e9);
+ testBasic(time, nanoFromSeconds, width, precision);
+ final Matcher match = matchToString(time);
+ match.matches();
+ final String widthString = match.group(1);
+ final String precisionString = match.group(2);
+ if ( width != -1 ) {
+ final int actualWidth = widthString.length() + 1 + precisionString.length();
+ Assert.assertTrue(actualWidth >= width, "width string '" + widthString + "' not >= the expected width " + width);
+ }
+ Assert.assertEquals(precisionString.length(), precision, "precision string '" + precisionString + "' not the expected precision " + precision);
+ }
+
+ private static Matcher matchToString(final AutoFormattingTime time) {
+ Pattern pattern = Pattern.compile("(\\s*\\d*)\\.(\\d*) \\w");
+ return pattern.matcher(time.toString());
+ }
+
+ private static void testBasic(final AutoFormattingTime aft, final long nano, final int expectedWidth, final int expectedPrecision) {
+ Assert.assertEquals(aft.getTimeInNanoSeconds(), nano);
+ assertEqualsDoubleSmart(aft.getTimeInSeconds(), nano * 1e-9, 1e-3, "Time in seconds not within tolerance of nanoSeconds");
+ Assert.assertEquals(aft.getWidth(), expectedWidth);
+ Assert.assertEquals(aft.getPrecision(), expectedPrecision);
+ Assert.assertNotNull(aft.toString(), "TimeUnit toString returned null");
+ final Matcher match = matchToString(aft);
+ Assert.assertTrue(match.matches(), "toString " + aft.toString() + " doesn't match our expected format");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/BaseTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/BaseTest.java
new file mode 100644
index 0000000..ca57922
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/BaseTest.java
@@ -0,0 +1,568 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import htsjdk.tribble.Tribble;
+import htsjdk.tribble.readers.LineIterator;
+import htsjdk.tribble.readers.PositionalBufferedStream;
+import htsjdk.tribble.util.TabixUtils;
+import htsjdk.variant.bcf2.BCF2Codec;
+import htsjdk.variant.variantcontext.Genotype;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.vcf.VCFCodec;
+import htsjdk.variant.vcf.VCFConstants;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PatternLayout;
+import org.apache.log4j.spi.LoggingEvent;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.commandline.CommandLineUtils;
+import org.broadinstitute.gatk.utils.crypt.CryptUtils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.io.IOUtils;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import org.testng.Assert;
+import org.testng.Reporter;
+import org.testng.SkipException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.*;
+
+/**
+ *
+ * User: aaron
+ * Date: Apr 14, 2009
+ * Time: 10:24:30 AM
+ *
+ * The Broad Institute
+ * SOFTWARE COPYRIGHT NOTICE AGREEMENT
+ * This software and its documentation are copyright 2009 by the
+ * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
+ *
+ * This software is supplied without any warranty or guaranteed support whatsoever. Neither
+ * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
+ *
+ */
+
+
+/**
+ * @author aaron
+ * @version 1.0
+ * @date Apr 14, 2009
+ * <p/>
+ * Class BaseTest
+ * <p/>
+ * This is the base test class for all of our test cases. All test cases should extend from this
+ * class; it sets up the logger, and resolves the location of directories that we rely on.
+ */
+ at SuppressWarnings("unchecked")
+public abstract class BaseTest {
+ /** our log, which we want to capture anything from org.broadinstitute.sting */
+ public static final Logger logger = CommandLineUtils.getStingLogger();
+
+ private static final String CURRENT_DIRECTORY = System.getProperty("user.dir");
+ public static final String gatkDirectory = System.getProperty("gatkdir", CURRENT_DIRECTORY) + "/";
+ public static final String baseDirectory = System.getProperty("basedir", CURRENT_DIRECTORY) + "/";
+ public static final String testType = System.getProperty("testType"); // May be null
+ public static final String testTypeSubDirectory = testType == null ? "" : ("/" + testType); // May be empty
+
+ public static final String hg18Reference = "/seq/references/Homo_sapiens_assembly18/v0/Homo_sapiens_assembly18.fasta";
+ public static final String hg19Reference = "/seq/references/Homo_sapiens_assembly19/v1/Homo_sapiens_assembly19.fasta";
+ public static final String b36KGReference = "/humgen/1kg/reference/human_b36_both.fasta";
+ //public static final String b37KGReference = "/Users/depristo/Desktop/broadLocal/localData/human_g1k_v37.fasta";
+ public static final String b37KGReference = "/humgen/1kg/reference/human_g1k_v37.fasta";
+ public static final String b37KGReferenceWithDecoy = "/humgen/gsa-hpprojects/GATK/bundle/current/b37/human_g1k_v37_decoy.fasta";
+ public static final String hg19RefereneWithChrPrefixInChromosomeNames = "/humgen/gsa-hpprojects/GATK/bundle/current/hg19/ucsc.hg19.fasta";
+ public static final String GATKDataLocation = "/humgen/gsa-hpprojects/GATK/data/";
+ public static final String validationDataLocation = GATKDataLocation + "Validation_Data/";
+ public static final String evaluationDataLocation = GATKDataLocation + "Evaluation_Data/";
+ public static final String comparisonDataLocation = GATKDataLocation + "Comparisons/";
+ public static final String annotationDataLocation = GATKDataLocation + "Annotations/";
+
+ public static final String b37GoodBAM = validationDataLocation + "/CEUTrio.HiSeq.b37.chr20.10_11mb.bam";
+ public static final String b37GoodNA12878BAM = validationDataLocation + "/NA12878.HiSeq.WGS.bwa.cleaned.recal.hg19.20.bam";
+ public static final String b37_NA12878_OMNI = validationDataLocation + "/NA12878.omni.vcf";
+
+ public static final String dbsnpDataLocation = GATKDataLocation;
+ public static final String b36dbSNP129 = dbsnpDataLocation + "dbsnp_129_b36.vcf";
+ public static final String b37dbSNP129 = dbsnpDataLocation + "dbsnp_129_b37.vcf";
+ public static final String b37dbSNP132 = dbsnpDataLocation + "dbsnp_132_b37.vcf";
+ public static final String b37dbSNP138 = "/humgen/gsa-hpprojects/GATK/bundle/current/b37/dbsnp_138.b37.vcf";
+ public static final String hg18dbSNP132 = dbsnpDataLocation + "dbsnp_132.hg18.vcf";
+
+ public static final String hapmapDataLocation = comparisonDataLocation + "Validated/HapMap/3.3/";
+ public static final String b37hapmapGenotypes = hapmapDataLocation + "genotypes_r27_nr.b37_fwd.vcf";
+
+ public static final String intervalsLocation = "/seq/references/HybSelOligos/whole_exome_agilent_1.1_refseq_plus_3_boosters/";
+ public static final String hg19Intervals = intervalsLocation + "whole_exome_agilent_1.1_refseq_plus_3_boosters.Homo_sapiens_assembly19.targets.interval_list";
+ public static final String hg19Chr20Intervals = GATKDataLocation + "whole_exome_agilent_1.1_refseq_plus_3_boosters.Homo_sapiens_assembly19.targets.chr20.interval_list";
+
+ public static final boolean REQUIRE_NETWORK_CONNECTION = false;
+ private static final String networkTempDirRoot = "/broad/hptmp/";
+ private static final boolean networkTempDirRootExists = new File(networkTempDirRoot).exists();
+ private static final File networkTempDirFile;
+
+ private static final String privateTestDirRelative = "private/gatk-tools-private/src/test/resources/";
+ public static final String privateTestDir = new File(gatkDirectory, privateTestDirRelative).getAbsolutePath() + "/";
+ protected static final String privateTestDirRoot = privateTestDir.replace(privateTestDirRelative, "");
+
+ private static final String publicTestDirRelative = "public/gatk-engine/src/test/resources/";
+ public static final String publicTestDir = new File(gatkDirectory, publicTestDirRelative).getAbsolutePath() + "/";
+ protected static final String publicTestDirRoot = publicTestDir.replace(publicTestDirRelative, "");
+
+ public static final String keysDataLocation = validationDataLocation + "keys/";
+
+ public static final String gatkKeyFile = CryptUtils.GATK_USER_KEY_DIRECTORY + "gsamembers_broadinstitute.org.key";
+
+ public static final String exampleFASTA = publicTestDir + "exampleFASTA.fasta";
+
+ public final static String NA12878_PCRFREE = privateTestDir + "PCRFree.2x250.Illumina.20_10_11.bam";
+ public final static String NA12878_WEx = privateTestDir + "CEUTrio.HiSeq.WEx.b37_decoy.NA12878.20_10_11mb.bam";
+
+ public static final boolean queueTestRunModeIsSet = System.getProperty("queuetest.run", "").equals("true");
+
+ /** before the class starts up */
+ static {
+ // setup a basic log configuration
+ CommandLineUtils.configureConsoleLogging();
+
+ // setup our log layout
+ PatternLayout layout = new PatternLayout();
+ layout.setConversionPattern("TEST %C{1}.%M - %d{HH:mm:ss,SSS} - %m%n");
+
+ // now set the layout of all the loggers to our layout
+ CommandLineUtils.setLayout(logger, layout);
+
+ // Set the Root logger to only output warnings.
+ logger.setLevel(Level.WARN);
+
+ if (networkTempDirRootExists) {
+ networkTempDirFile = IOUtils.tempDir("temp.", ".dir", new File(networkTempDirRoot + System.getProperty("user.name")));
+ networkTempDirFile.deleteOnExit();
+ } else {
+ networkTempDirFile = null;
+ }
+
+
+ if ( REQUIRE_NETWORK_CONNECTION ) {
+ // find our file sources
+ if (!fileExist(hg18Reference) || !fileExist(hg19Reference) || !fileExist(b36KGReference)) {
+ logger.fatal("We can't locate the reference directories. Aborting!");
+ throw new RuntimeException("BaseTest setup failed: unable to locate the reference directories");
+ }
+ }
+ }
+
+ /**
+ * Simple generic utility class to creating TestNG data providers:
+ *
+ * 1: inherit this class, as in
+ *
+ * private class SummarizeDifferenceTest extends TestDataProvider {
+ * public SummarizeDifferenceTest() {
+ * super(SummarizeDifferenceTest.class);
+ * }
+ * ...
+ * }
+ *
+ * Provide a reference to your class to the TestDataProvider constructor.
+ *
+ * 2: Create instances of your subclass. Return from it the call to getTests, providing
+ * the class type of your test
+ *
+ * <code>
+ * {@literal @}DataProvider(name = "summaries")
+ * public Object[][] createSummaries() {
+ * new SummarizeDifferenceTest().addDiff("A", "A").addSummary("A:2");
+ * new SummarizeDifferenceTest().addDiff("A", "B").addSummary("A:1", "B:1");
+ * return SummarizeDifferenceTest.getTests(SummarizeDifferenceTest.class);
+ * }
+ * </code>
+ *
+ * This class magically tracks created objects of this
+ */
+ public static class TestDataProvider {
+ private static final Map<Class, List<Object>> tests = new HashMap<>();
+ protected String name;
+
+ /**
+ * Create a new TestDataProvider instance bound to the class variable C
+ */
+ public TestDataProvider(Class c, String name) {
+ if ( ! tests.containsKey(c) )
+ tests.put(c, new ArrayList<>());
+ tests.get(c).add(this);
+ this.name = name;
+ }
+
+ public TestDataProvider(Class c) {
+ this(c, "");
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ /**
+ * Return all of the data providers in the form expected by TestNG of type class C
+ * @param c
+ * @return
+ */
+ public static Object[][] getTests(Class c) {
+ List<Object[]> params2 = new ArrayList<Object[]>();
+ for ( Object x : tests.get(c) ) params2.add(new Object[]{x});
+ return params2.toArray(new Object[][]{});
+ }
+
+ @Override
+ public String toString() {
+ return "TestDataProvider("+name+")";
+ }
+ }
+
+ /**
+ * test if the file exists
+ *
+ * @param file name as a string
+ * @return true if it exists
+ */
+ public static boolean fileExist(String file) {
+ File temp = new File(file);
+ return temp.exists();
+ }
+
+ /**
+ * this appender looks for a specific message in the log4j stream.
+ * It can be used to verify that a specific message was generated to the logging system.
+ */
+ public static class ValidationAppender extends AppenderSkeleton {
+
+ private boolean foundString = false;
+ private String targetString = "";
+
+ public ValidationAppender(String target) {
+ targetString = target;
+ }
+
+ @Override
+ protected void append(LoggingEvent loggingEvent) {
+ if (loggingEvent.getMessage().equals(targetString))
+ foundString = true;
+ }
+
+ public void close() {
+ // do nothing
+ }
+
+ public boolean requiresLayout() {
+ return false;
+ }
+
+ public boolean foundString() {
+ return foundString;
+ }
+ }
+
+ /**
+ * Creates a temp file that will be deleted on exit after tests are complete.
+ * @param name Prefix of the file.
+ * @param extension Extension to concat to the end of the file.
+ * @return A file in the temporary directory starting with name, ending with extension, which will be deleted after the program exits.
+ */
+ public static File createTempFile(final String name, final String extension) {
+ try {
+ final File file = File.createTempFile(name, extension);
+ file.deleteOnExit();
+
+ // Mark corresponding indices for deletion on exit as well just in case an index is created for the temp file:
+ new File(file.getAbsolutePath() + Tribble.STANDARD_INDEX_EXTENSION).deleteOnExit();
+ new File(file.getAbsolutePath() + TabixUtils.STANDARD_INDEX_EXTENSION).deleteOnExit();
+ new File(file.getAbsolutePath() + ".bai").deleteOnExit();
+ new File(file.getAbsolutePath().replaceAll(extension + "$", ".bai")).deleteOnExit();
+
+ return file;
+ } catch (IOException ex) {
+ throw new ReviewedGATKException("Cannot create temp file: " + ex.getMessage(), ex);
+ }
+ }
+
+ /**
+ * Creates a temp list file that will be deleted on exit after tests are complete.
+ * @param tempFilePrefix Prefix of the file.
+ * @param lines lines to write to the file.
+ * @return A list file in the temporary directory starting with tempFilePrefix, which will be deleted after the program exits.
+ */
+ public static File createTempListFile(final String tempFilePrefix, final String... lines) {
+ try {
+ final File tempListFile = createTempFile(tempFilePrefix, ".list");
+
+ final PrintWriter out = new PrintWriter(tempListFile);
+ for (final String line : lines) {
+ out.println(line);
+ }
+ out.close();
+
+ return tempListFile;
+ } catch (IOException ex) {
+ throw new ReviewedGATKException("Cannot create temp file: " + ex.getMessage(), ex);
+ }
+ }
+
+ /**
+ * Creates a temp file that will be deleted on exit after tests are complete.
+ * @param name Name of the file.
+ * @return A file in the network temporary directory with name, which will be deleted after the program exits.
+ * @throws SkipException when the network is not available.
+ */
+ public static File tryCreateNetworkTempFile(String name) {
+ if (!networkTempDirRootExists)
+ throw new SkipException("Network temporary directory does not exist: " + networkTempDirRoot);
+ File file = new File(networkTempDirFile, name);
+ file.deleteOnExit();
+ return file;
+ }
+
+ /**
+ * Log this message so that it shows up inline during output as well as in html reports
+ *
+ * @param message
+ */
+ public static void log(final String message) {
+ Reporter.log(message, true);
+ }
+
+ private static final double DEFAULT_FLOAT_TOLERANCE = 1e-1;
+
+ public static final void assertEqualsDoubleSmart(final Object actual, final Double expected) {
+ Assert.assertTrue(actual instanceof Double, "Not a double");
+ assertEqualsDoubleSmart((double)(Double)actual, (double)expected);
+ }
+
+ public static final void assertEqualsDoubleSmart(final Object actual, final Double expected, final double tolerance) {
+ Assert.assertTrue(actual instanceof Double, "Not a double");
+ assertEqualsDoubleSmart((double)(Double)actual, (double)expected, tolerance);
+ }
+
+ public static final void assertEqualsDoubleSmart(final double actual, final double expected) {
+ assertEqualsDoubleSmart(actual, expected, DEFAULT_FLOAT_TOLERANCE);
+ }
+
+ public static final <T> void assertEqualsSet(final Set<T> actual, final Set<T> expected, final String info) {
+ final Set<T> actualSet = new HashSet<T>(actual);
+ final Set<T> expectedSet = new HashSet<T>(expected);
+ Assert.assertTrue(actualSet.equals(expectedSet), info); // note this is necessary due to testng bug for set comps
+ }
+
+ public static void assertEqualsDoubleSmart(final double actual, final double expected, final double tolerance) {
+ assertEqualsDoubleSmart(actual, expected, tolerance, null);
+ }
+
+ public static void assertEqualsDoubleSmart(final double actual, final double expected, final double tolerance, final String message) {
+ if ( Double.isNaN(expected) ) // NaN == NaN => false unfortunately
+ Assert.assertTrue(Double.isNaN(actual), "expected is nan, actual is not");
+ else if ( Double.isInfinite(expected) ) // NaN == NaN => false unfortunately
+ Assert.assertTrue(Double.isInfinite(actual), "expected is infinite, actual is not");
+ else {
+ final double delta = Math.abs(actual - expected);
+ final double ratio = Math.abs(actual / expected - 1.0);
+ Assert.assertTrue(delta < tolerance || ratio < tolerance, "expected = " + expected + " actual = " + actual
+ + " not within tolerance " + tolerance
+ + (message == null ? "" : "message: " + message));
+ }
+ }
+
+ public static void assertVariantContextsAreEqual( final VariantContext actual, final VariantContext expected ) {
+ Assert.assertNotNull(actual, "VariantContext expected not null");
+ Assert.assertEquals(actual.getChr(), expected.getChr(), "chr");
+ Assert.assertEquals(actual.getStart(), expected.getStart(), "start");
+ Assert.assertEquals(actual.getEnd(), expected.getEnd(), "end");
+ Assert.assertEquals(actual.getID(), expected.getID(), "id");
+ Assert.assertEquals(actual.getAlleles(), expected.getAlleles(), "alleles for " + expected + " vs " + actual);
+
+ assertAttributesEquals(actual.getAttributes(), expected.getAttributes());
+ Assert.assertEquals(actual.filtersWereApplied(), expected.filtersWereApplied(), "filtersWereApplied");
+ Assert.assertEquals(actual.isFiltered(), expected.isFiltered(), "isFiltered");
+ assertEqualsSet(actual.getFilters(), expected.getFilters(), "filters");
+ assertEqualsDoubleSmart(actual.getPhredScaledQual(), expected.getPhredScaledQual());
+
+ Assert.assertEquals(actual.hasGenotypes(), expected.hasGenotypes(), "hasGenotypes");
+ if ( expected.hasGenotypes() ) {
+ assertEqualsSet(actual.getSampleNames(), expected.getSampleNames(), "sample names set");
+ Assert.assertEquals(actual.getSampleNamesOrderedByName(), expected.getSampleNamesOrderedByName(), "sample names");
+ final Set<String> samples = expected.getSampleNames();
+ for ( final String sample : samples ) {
+ assertGenotypesAreEqual(actual.getGenotype(sample), expected.getGenotype(sample));
+ }
+ }
+ }
+
+ public static void assertVariantContextStreamsAreEqual(final Iterable<VariantContext> actual, final Iterable<VariantContext> expected) {
+ final Iterator<VariantContext> actualIT = actual.iterator();
+ final Iterator<VariantContext> expectedIT = expected.iterator();
+
+ while ( expectedIT.hasNext() ) {
+ final VariantContext expectedVC = expectedIT.next();
+ if ( expectedVC == null )
+ continue;
+
+ VariantContext actualVC;
+ do {
+ Assert.assertTrue(actualIT.hasNext(), "Too few records found in actual");
+ actualVC = actualIT.next();
+ } while ( actualIT.hasNext() && actualVC == null );
+
+ if ( actualVC == null )
+ Assert.fail("Too few records in actual");
+
+ assertVariantContextsAreEqual(actualVC, expectedVC);
+ }
+ Assert.assertTrue(! actualIT.hasNext(), "Too many records found in actual");
+ }
+
+
+ public static void assertGenotypesAreEqual(final Genotype actual, final Genotype expected) {
+ Assert.assertEquals(actual.getSampleName(), expected.getSampleName(), "Genotype names");
+ Assert.assertEquals(actual.getAlleles(), expected.getAlleles(), "Genotype alleles");
+ Assert.assertEquals(actual.getGenotypeString(), expected.getGenotypeString(), "Genotype string");
+ Assert.assertEquals(actual.getType(), expected.getType(), "Genotype type");
+
+ // filters are the same
+ Assert.assertEquals(actual.getFilters(), expected.getFilters(), "Genotype fields");
+ Assert.assertEquals(actual.isFiltered(), expected.isFiltered(), "Genotype isFiltered");
+
+ // inline attributes
+ Assert.assertEquals(actual.getDP(), expected.getDP(), "Genotype dp");
+ Assert.assertTrue(Arrays.equals(actual.getAD(), expected.getAD()));
+ Assert.assertEquals(actual.getGQ(), expected.getGQ(), "Genotype gq");
+ Assert.assertEquals(actual.hasPL(), expected.hasPL(), "Genotype hasPL");
+ Assert.assertEquals(actual.hasAD(), expected.hasAD(), "Genotype hasAD");
+ Assert.assertEquals(actual.hasGQ(), expected.hasGQ(), "Genotype hasGQ");
+ Assert.assertEquals(actual.hasDP(), expected.hasDP(), "Genotype hasDP");
+
+ Assert.assertEquals(actual.hasLikelihoods(), expected.hasLikelihoods(), "Genotype haslikelihoods");
+ Assert.assertEquals(actual.getLikelihoodsString(), expected.getLikelihoodsString(), "Genotype getlikelihoodsString");
+ Assert.assertEquals(actual.getLikelihoods(), expected.getLikelihoods(), "Genotype getLikelihoods");
+ Assert.assertTrue(Arrays.equals(actual.getPL(), expected.getPL()));
+
+ Assert.assertEquals(actual.getPhredScaledQual(), expected.getPhredScaledQual(), "Genotype phredScaledQual");
+ assertAttributesEquals(actual.getExtendedAttributes(), expected.getExtendedAttributes());
+ Assert.assertEquals(actual.isPhased(), expected.isPhased(), "Genotype isPhased");
+ Assert.assertEquals(actual.getPloidy(), expected.getPloidy(), "Genotype getPloidy");
+ }
+
+ public static void assertVCFHeadersAreEqual(final VCFHeader actual, final VCFHeader expected) {
+ Assert.assertEquals(actual.getMetaDataInSortedOrder().size(), expected.getMetaDataInSortedOrder().size(), "No VCF header lines");
+
+ // for some reason set.equals() is returning false but all paired elements are .equals(). Perhaps compare to is busted?
+ //Assert.assertEquals(actual.getMetaDataInInputOrder(), expected.getMetaDataInInputOrder());
+ final List<VCFHeaderLine> actualLines = new ArrayList<VCFHeaderLine>(actual.getMetaDataInSortedOrder());
+ final List<VCFHeaderLine> expectedLines = new ArrayList<VCFHeaderLine>(expected.getMetaDataInSortedOrder());
+ for ( int i = 0; i < actualLines.size(); i++ ) {
+ Assert.assertEquals(actualLines.get(i), expectedLines.get(i), "VCF header lines");
+ }
+ }
+
+ public static void assertVCFandBCFFilesAreTheSame(final File vcfFile, final File bcfFile) throws IOException {
+ final Pair<VCFHeader, GATKVCFUtils.VCIterable<LineIterator>> vcfData = GATKVCFUtils.readAllVCs(vcfFile, new VCFCodec());
+ final Pair<VCFHeader, GATKVCFUtils.VCIterable<PositionalBufferedStream>> bcfData = GATKVCFUtils.readAllVCs(bcfFile, new BCF2Codec());
+ assertVCFHeadersAreEqual(bcfData.getFirst(), vcfData.getFirst());
+ assertVariantContextStreamsAreEqual(bcfData.getSecond(), vcfData.getSecond());
+ }
+
+ private static void assertAttributeEquals(final String key, final Object actual, final Object expected) {
+ if ( expected instanceof Double ) {
+ // must be very tolerant because doubles are being rounded to 2 sig figs
+ assertEqualsDoubleSmart(actual, (Double) expected, 1e-2);
+ } else
+ Assert.assertEquals(actual, expected, "Attribute " + key);
+ }
+
+ private static void assertAttributesEquals(final Map<String, Object> actual, Map<String, Object> expected) {
+ final Set<String> expectedKeys = new HashSet<String>(expected.keySet());
+
+ for ( final Map.Entry<String, Object> act : actual.entrySet() ) {
+ final Object actualValue = act.getValue();
+ if ( expected.containsKey(act.getKey()) && expected.get(act.getKey()) != null ) {
+ final Object expectedValue = expected.get(act.getKey());
+ if ( expectedValue instanceof List ) {
+ final List<Object> expectedList = (List<Object>)expectedValue;
+ Assert.assertTrue(actualValue instanceof List, act.getKey() + " should be a list but isn't");
+ final List<Object> actualList = (List<Object>)actualValue;
+ Assert.assertEquals(actualList.size(), expectedList.size(), act.getKey() + " size");
+ for ( int i = 0; i < expectedList.size(); i++ )
+ assertAttributeEquals(act.getKey(), actualList.get(i), expectedList.get(i));
+ } else
+ assertAttributeEquals(act.getKey(), actualValue, expectedValue);
+ } else {
+ // it's ok to have a binding in x -> null that's absent in y
+ Assert.assertNull(actualValue, act.getKey() + " present in one but not in the other");
+ }
+ expectedKeys.remove(act.getKey());
+ }
+
+ // now expectedKeys contains only the keys found in expected but not in actual,
+ // and they must all be null
+ for ( final String missingExpected : expectedKeys ) {
+ final Object value = expected.get(missingExpected);
+ Assert.assertTrue(isMissing(value), "Attribute " + missingExpected + " missing in one but not in other" );
+ }
+ }
+
+ private static final boolean isMissing(final Object value) {
+ if ( value == null ) return true;
+ else if ( value.equals(VCFConstants.MISSING_VALUE_v4) ) return true;
+ else if ( value instanceof List ) {
+ // handles the case where all elements are null or the list is empty
+ for ( final Object elt : (List)value)
+ if ( elt != null )
+ return false;
+ return true;
+ } else
+ return false;
+ }
+
+ /**
+ * Checks whether two double array contain the same values or not.
+ * @param actual actual produced array.
+ * @param expected expected array.
+ * @param tolerance maximum difference between double value to be consider equivalent.
+ */
+ protected static void assertEqualsDoubleArray(final double[] actual, final double[] expected, final double tolerance) {
+ if (expected == null)
+ Assert.assertNull(actual);
+ else {
+ Assert.assertNotNull(actual);
+ Assert.assertEquals(actual.length,expected.length,"array length");
+ }
+ for (int i = 0; i < actual.length; i++)
+ Assert.assertEquals(actual[i],expected[i],tolerance,"array position " + i);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/BaseUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/BaseUtilsUnitTest.java
new file mode 100644
index 0000000..b532baf
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/BaseUtilsUnitTest.java
@@ -0,0 +1,179 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Random;
+
+
+public class BaseUtilsUnitTest extends BaseTest {
+ @BeforeClass
+ public void init() { }
+
+ @Test
+ public void testMostFrequentBaseFraction() {
+ logger.warn("Executing testMostFrequentBaseFraction");
+
+ compareFrequentBaseFractionToExpected("AAAAA", 1.0);
+ compareFrequentBaseFractionToExpected("ACCG", 0.5);
+ compareFrequentBaseFractionToExpected("ACCCCTTTTG", 4.0/10.0);
+ }
+
+ private void compareFrequentBaseFractionToExpected(String sequence, double expected) {
+ double fraction = BaseUtils.mostFrequentBaseFraction(sequence.getBytes());
+ Assert.assertTrue(MathUtils.compareDoubles(fraction, expected) == 0);
+ }
+
+ @Test
+ public void testConvertIUPACtoN() {
+
+ checkBytesAreEqual(BaseUtils.convertIUPACtoN(new byte[]{'A', 'A', 'A'}, false, false), new byte[]{'A', 'A', 'A'});
+ checkBytesAreEqual(BaseUtils.convertIUPACtoN(new byte[]{'W', 'A', 'A'}, false, false), new byte[]{'N', 'A', 'A'});
+ checkBytesAreEqual(BaseUtils.convertIUPACtoN(new byte[]{'A', 'M', 'A'}, false, false), new byte[]{'A', 'N', 'A'});
+ checkBytesAreEqual(BaseUtils.convertIUPACtoN(new byte[]{'A', 'A', 'K'}, false, false), new byte[]{'A', 'A', 'N'});
+ checkBytesAreEqual(BaseUtils.convertIUPACtoN(new byte[]{'M', 'M', 'M'}, false, false), new byte[]{'N', 'N', 'N'});
+ }
+
+ private void checkBytesAreEqual(final byte[] b1, final byte[] b2) {
+ for ( int i = 0; i < b1.length; i++ )
+ Assert.assertEquals(b1[i], b2[i]);
+ }
+
+ @Test
+ public void testConvertBasesToIUPAC() {
+
+ for ( final BaseUtils.Base b : BaseUtils.Base.values() ) {
+ if ( BaseUtils.isRegularBase(b.base) )
+ Assert.assertEquals(BaseUtils.basesToIUPAC(b.base, b.base), b.base, "testing same base");
+ }
+
+ Assert.assertEquals(BaseUtils.basesToIUPAC((byte)'A', (byte)'X'), 'N', "testing non-standard base");
+ Assert.assertEquals(BaseUtils.basesToIUPAC((byte)'X', (byte)'A'), 'N', "testing non-standard base");
+ Assert.assertEquals(BaseUtils.basesToIUPAC((byte)'X', (byte)'X'), 'N', "testing non-standard base");
+
+ Assert.assertEquals(BaseUtils.basesToIUPAC((byte)'A', (byte)'T'), 'W', "testing A/T=W");
+ Assert.assertEquals(BaseUtils.basesToIUPAC((byte)'T', (byte)'A'), 'W', "testing T/A=W");
+ Assert.assertEquals(BaseUtils.basesToIUPAC((byte) 'G', (byte) 'T'), 'K', "testing G/T=K");
+ Assert.assertEquals(BaseUtils.basesToIUPAC((byte) 'T', (byte) 'G'), 'K', "testing T/G=K");
+ }
+
+ @Test
+ public void testTransitionTransversion() {
+ logger.warn("Executing testTransitionTransversion");
+
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'A', (byte)'T' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'A', (byte)'C' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'A', (byte)'G' ) == BaseUtils.BaseSubstitutionType.TRANSITION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'C', (byte)'A' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'C', (byte)'T' ) == BaseUtils.BaseSubstitutionType.TRANSITION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'C', (byte)'G' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'T', (byte)'A' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'T', (byte)'C' ) == BaseUtils.BaseSubstitutionType.TRANSITION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'T', (byte)'G' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'G', (byte)'A' ) == BaseUtils.BaseSubstitutionType.TRANSITION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'G', (byte)'T' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'G', (byte)'C' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'a', (byte)'T' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'a', (byte)'C' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'A', (byte)'T' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'A', (byte)'C' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'A', (byte)'t' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'A', (byte)'c' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'a', (byte)'t' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ Assert.assertTrue( BaseUtils.SNPSubstitutionType( (byte)'a', (byte)'c' ) == BaseUtils.BaseSubstitutionType.TRANSVERSION );
+ }
+
+ @Test
+ public void testReverseComplementString() {
+ logger.warn("Executing testReverseComplementString");
+
+ compareRCStringToExpected("ACGGT", "ACCGT");
+ compareRCStringToExpected("TCGTATATCTCGCTATATATATATAGCTCTAGTATA", "TATACTAGAGCTATATATATATAGCGAGATATACGA");
+ compareRCStringToExpected("AAAN", "NTTT");
+ }
+
+ private void compareRCStringToExpected(String fw, String rcExp) {
+ String rcObs = BaseUtils.simpleReverseComplement(fw);
+
+ Assert.assertTrue(rcObs.equals(rcExp));
+ }
+
+ @Test(dataProvider="baseComparatorData")
+ public void testBaseComparator(final Collection<byte[]> basesToSort) {
+ final ArrayList<byte[]> sorted = new ArrayList<>(basesToSort);
+ Collections.sort(sorted, BaseUtils.BASES_COMPARATOR);
+ for (int i = 0; i < sorted.size(); i++) {
+ Assert.assertEquals(BaseUtils.BASES_COMPARATOR.compare(sorted.get(i),sorted.get(i)),0);
+ final String iString = new String(sorted.get(i));
+ for (int j = i; j < sorted.size(); j++) {
+ final String jString = new String(sorted.get(j));
+ if (iString.compareTo(jString) == 0)
+ Assert.assertEquals(BaseUtils.BASES_COMPARATOR.compare(sorted.get(i),sorted.get(j)),0);
+ else
+ Assert.assertTrue(BaseUtils.BASES_COMPARATOR.compare(sorted.get(i),sorted.get(j)) * iString.compareTo(jString) > 0);
+ Assert.assertTrue(BaseUtils.BASES_COMPARATOR.compare(sorted.get(i),sorted.get(j)) <= 0);
+ }
+ }
+ }
+
+ @DataProvider(name="baseComparatorData")
+ public Object[][] baseComparatorData() {
+ final int testCount = 10;
+ final int testSizeAverage = 10;
+ final int testSizeDeviation = 10;
+ final int haplotypeSizeAverage = 100;
+ final int haplotypeSizeDeviation = 100;
+
+ final Object[][] result = new Object[testCount][];
+
+ GenomeAnalysisEngine.resetRandomGenerator();
+ final Random rnd = GenomeAnalysisEngine.getRandomGenerator();
+
+ for (int i = 0; i < testCount; i++) {
+ final int size = (int) Math.max(0,rnd.nextDouble() * testSizeDeviation + testSizeAverage);
+ final ArrayList<byte[]> bases = new ArrayList<>(size);
+ for (int j = 0; j < size; j++) {
+ final int jSize = (int) Math.max(0,rnd.nextDouble() * haplotypeSizeDeviation + haplotypeSizeAverage);
+ final byte[] b = new byte[jSize];
+ for (int k = 0; k < jSize; k++)
+ b[k] = BaseUtils.baseIndexToSimpleBase(rnd.nextInt(4));
+ bases.add(b);
+ }
+ result[i] = new Object[] { bases };
+ }
+ return result;
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/BitSetUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/BitSetUtilsUnitTest.java
new file mode 100644
index 0000000..87a5914
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/BitSetUtilsUnitTest.java
@@ -0,0 +1,85 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.Random;
+
+/**
+ * @author Mauricio Carneiro
+ * @since 3/5/12
+ */
+
+public class BitSetUtilsUnitTest {
+ private static int RANDOM_NUMBERS_TO_TRY = 87380;
+ private static Random random;
+
+ @BeforeClass
+ public void init() {
+ random = GenomeAnalysisEngine.getRandomGenerator();
+ }
+
+ @Test(enabled = true)
+ public void testLongBitSet() {
+ long[] numbers = {0L, 1L, 428L, 65536L, 239847L, 4611686018427387903L, Long.MAX_VALUE, Long.MIN_VALUE, -1L, -2L, -7L, -128L, -65536L, -100000L};
+ for (long n : numbers)
+ Assert.assertEquals(BitSetUtils.longFrom(BitSetUtils.bitSetFrom(n)), n);
+
+ for (int i = 0; i < RANDOM_NUMBERS_TO_TRY; i++) {
+ long n = random.nextLong();
+ Assert.assertEquals(BitSetUtils.longFrom(BitSetUtils.bitSetFrom(n)), n); // Because class Random uses a seed with only 48 bits, this algorithm will not return all possible long values.
+ }
+ }
+
+ @Test(enabled = true)
+ public void testShortBitSet() {
+ short[] numbers = {0, 1, 428, 25934, 23847, 16168, Short.MAX_VALUE, Short.MIN_VALUE, -1, -2, -7, -128, -12312, -31432};
+ for (long n : numbers)
+ Assert.assertEquals(BitSetUtils.shortFrom(BitSetUtils.bitSetFrom(n)), n);
+
+ for (int i = 0; i < RANDOM_NUMBERS_TO_TRY; i++) {
+ short n = (short) random.nextInt();
+ Assert.assertEquals(BitSetUtils.shortFrom(BitSetUtils.bitSetFrom(n)), n);
+ }
+ }
+
+ @Test(enabled = false)
+ public void testDNAAndBitSetConversion() {
+ String[] dna = {"AGGTGTTGT", "CCCCCCCCCCCCCC", "GGGGGGGGGGGGGG", "TTTTTTTTTTTTTT", "GTAGACCGATCTCAGCTAGT", "AACGTCAATGCAGTCAAGTCAGACGTGGGTT", "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT", "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT"};
+
+ // Test all contexts of size 1-8.
+ //for (long n = 0; n < RANDOM_NUMBERS_TO_TRY; n++)
+ // Assert.assertEquals(BitSetUtils.longFrom(BitSetUtils.bitSetFrom(ContextCovariate.contextFromKey(BitSetUtils.bitSetFrom(n)))), n);
+
+ // Test the special cases listed in the dna array
+ //for (String d : dna)
+ // Assert.assertEquals(BitSetUtils.dnaFrom(BitSetUtils.bitSetFrom(d)), d);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/ExampleToCopyUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/ExampleToCopyUnitTest.java
new file mode 100644
index 0000000..8c6e24c
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/ExampleToCopyUnitTest.java
@@ -0,0 +1,241 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+
+// the imports for unit testing.
+
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileupImpl;
+import org.broadinstitute.gatk.utils.sam.ArtificialBAMBuilder;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.broadinstitute.gatk.utils.sam.GATKSamRecordFactory;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.*;
+
+public class ExampleToCopyUnitTest extends BaseTest {
+ // example genome loc parser for this test, can be deleted if you don't use the reference
+ private GenomeLocParser genomeLocParser;
+
+ // example fasta index file, can be deleted if you don't use the reference
+ private IndexedFastaSequenceFile seq;
+
+ @BeforeClass
+ public void setup() throws FileNotFoundException {
+ // sequence
+ seq = new CachingIndexedFastaSequenceFile(new File(b37KGReference));
+ genomeLocParser = new GenomeLocParser(seq);
+ }
+
+ /**
+ * Combinatorial unit test data provider example.
+ *
+ * Creates data for testMyData test function, containing two arguments, start and size at each value
+ *
+ * @return Object[][] for testng DataProvider
+ */
+ @DataProvider(name = "MyDataProvider")
+ public Object[][] makeMyDataProvider() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ for ( final int start : Arrays.asList(1, 10, 100) ) {
+ for ( final int size : Arrays.asList(1, 10, 100, 1000) ) {
+ tests.add(new Object[]{start, size});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ /**
+ * Example testng test using MyDataProvider
+ */
+ @Test(dataProvider = "MyDataProvider")
+ public void testMyData(final int start, final int size) {
+ // adaptor this code to do whatever testing you want given the arguments start and size
+ Assert.assertTrue(start >= 0);
+ Assert.assertTrue(size >= 0);
+ }
+
+ /**
+ * DataProvider example using a class-based data structure
+ */
+ private class MyDataProviderClass extends TestDataProvider {
+ private int start;
+ private int size;
+
+ private MyDataProviderClass(int start, int size) {
+ super(MyDataProviderClass.class);
+ this.start = start;
+ this.size = size;
+ }
+ }
+
+ @DataProvider(name = "MyClassBasedDataProvider")
+ public Object[][] makeMyDataProviderClass() {
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ for ( final int start : Arrays.asList(1, 10, 100) ) {
+ for ( final int size : Arrays.asList(1, 10, 100, 1000) ) {
+ new MyDataProviderClass(start, size);
+ }
+ }
+
+ return TestDataProvider.getTests(MyDataProviderClass.class);
+ }
+
+ /**
+ * Example testng test using MyClassBasedDataProvider
+ */
+ @Test(dataProvider = "MyClassBasedDataProvider")
+ public void testMyDataProviderClass(MyDataProviderClass testSpec) {
+ // adaptor this code to do whatever testing you want given the arguments start and size
+ Assert.assertTrue(testSpec.start >= 0);
+ Assert.assertTrue(testSpec.size >= 0);
+ }
+
+ /**
+ * A unit test that creates an artificial read for testing some code that uses reads
+ */
+ @Test()
+ public void testWithARead() {
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(seq.getSequenceDictionary());
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, 10);
+ Assert.assertEquals(read.getReadLength(), 10);
+ // TODO -- add some tests here using read
+ }
+
+ /**
+ * A unit test that creates a GenomeLoc for testing
+ */
+ @Test()
+ public void testWithAGenomeLoc() {
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc("1", 1, 10);
+ Assert.assertEquals(loc.size(), 10);
+ // TODO -- add some tests here using the loc
+ }
+
+ /**
+ * A unit test that creates an artificial read for testing some code that uses reads
+ *
+ * Note that effective creation of RBPs isn't so good. If you need pileups of specific properties, you shoud
+ * look into building them yourself as in the example below
+ */
+ @Test()
+ public void testWithAPileup() {
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(seq.getSequenceDictionary());
+ final GenomeLoc myLocation = genomeLocParser.createGenomeLoc("1", 10);
+ final ReadBackedPileup pileup = ArtificialSAMUtils.createReadBackedPileup(header, myLocation, 10, 400, 10);
+ Assert.assertFalse(pileup.isEmpty());
+ // TODO -- add some tests here using pileup
+ }
+
+ /**
+ * A unit test that creates an artificial read for testing some code that uses reads
+ *
+ * Builds the pileup from scratch to have specific properties
+ */
+ @Test()
+ public void testBuildingAPileupWithSpecificProperties() {
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(seq.getSequenceDictionary());
+ final GenomeLoc myLocation = genomeLocParser.createGenomeLoc("1", 10);
+
+ final int pileupSize = 100;
+ final int readLength = 10;
+ final List<GATKSAMRecord> reads = new LinkedList<GATKSAMRecord>();
+ for ( int i = 0; i < pileupSize; i++ ) {
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead" + i, 0, 1, readLength);
+ final byte[] bases = Utils.dupBytes((byte)'A', readLength);
+ bases[0] = (byte)(i % 2 == 0 ? 'A' : 'C'); // every other base is a C
+
+ // set the read's bases and quals
+ read.setReadBases(bases);
+ read.setBaseQualities(Utils.dupBytes((byte)30, readLength));
+ reads.add(read);
+ }
+
+ // create a pileup with all reads having offset 0
+ final ReadBackedPileup pileup = new ReadBackedPileupImpl(myLocation, reads, 0);
+ // TODO -- add some tests here using pileup
+
+ // this code ensures that the pileup example is correct. Can be deleted
+ Assert.assertEquals(pileup.getNumberOfElements(), pileupSize);
+ int nA = 0, nC = 0;
+ for ( final PileupElement p : pileup ) {
+ if ( p.getBase() == 'A' ) nA++;
+ if ( p.getBase() == 'C' ) nC++;
+ }
+ Assert.assertEquals(nA, pileupSize / 2);
+ Assert.assertEquals(nC, pileupSize / 2);
+
+ }
+
+ /**
+ * A unit test that creates an artificial read for testing some code that uses reads
+ */
+ @Test()
+ public void testWithBAMFile() {
+ // create a fake BAM file, and iterate through it
+ final ArtificialBAMBuilder bamBuilder = new ArtificialBAMBuilder(seq, 20, 10);
+ final File bam = bamBuilder.makeTemporarilyBAMFile();
+ final SAMFileReader reader = new SAMFileReader(bam);
+ reader.setSAMRecordFactory(new GATKSamRecordFactory());
+
+ final Iterator<SAMRecord> bamIt = reader.iterator();
+ while ( bamIt.hasNext() ) {
+ final GATKSAMRecord read = (GATKSAMRecord)bamIt.next(); // all reads are actually GATKSAMRecords
+ // TODO -- add some tests that use reads from a BAM
+ }
+ }
+
+ /**
+ * Test code that creates VariantContexts
+ */
+ @Test()
+ public void testWithVariantContext() throws Exception {
+ final List<Allele> alleles = Arrays.asList(Allele.create("A", true), Allele.create("C"));
+ final VariantContext vc = new VariantContextBuilder("test", "1", 10, 10, alleles).make();
+ Assert.assertTrue(vc.getAlleles().size() >= 0);
+ // TODO -- add some tests that use VariantContext
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GATKTextReporter.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GATKTextReporter.java
new file mode 100644
index 0000000..957ccd2
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GATKTextReporter.java
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.testng.reporters.TextReporter;
+
+/**
+ * HACK: Create a variant of the TestNG TextReporter that can be run with no
+ * arguments, and can therefore be added to the TestNG listener list.
+ *
+ * @author hanna
+ * @version 0.1
+ */
+public class GATKTextReporter extends TextReporter {
+ public GATKTextReporter() {
+ super("GATK test suite",2);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocParserBenchmark.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocParserBenchmark.java
new file mode 100644
index 0000000..7f19879
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocParserBenchmark.java
@@ -0,0 +1,81 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+
+import java.io.File;
+
+/**
+ * Caliper microbenchmark of genome loc parser
+ */
+public class GenomeLocParserBenchmark extends SimpleBenchmark {
+ private IndexedFastaSequenceFile seq;
+ private final int ITERATIONS = 1000000;
+
+ @Param({"NEW", "NONE"})
+ GenomeLocParser.ValidationLevel validationLevel; // set automatically by framework
+
+ @Param({"true", "false"})
+ boolean useContigIndex; // set automatically by framework
+
+ @Override protected void setUp() throws Exception {
+ seq = new CachingIndexedFastaSequenceFile(new File("/Users/depristo/Desktop/broadLocal/localData/human_g1k_v37.fasta"));
+ }
+//
+// public void timeSequentialCreationFromGenomeLoc(int rep) {
+// final GenomeLocParser genomeLocParser = new GenomeLocParser(seq.getSequenceDictionary(), validationLevel);
+// GenomeLoc last = genomeLocParser.createGenomeLoc("1", 1, 1);
+// for ( int i = 0; i < rep; i++ ) {
+// for ( int j = 1; j < ITERATIONS; j++ ) {
+// if ( useContigIndex )
+// last = genomeLocParser.createGenomeLoc(last.getContig(), last.getContigIndex(), last.getStart() + 1);
+// else
+// last = genomeLocParser.createGenomeLoc(last.getContig(), last.getStart() + 1);
+// }
+// }
+// }
+//
+// public void timeSequentialCreationFromGenomeLocOriginal(int rep) {
+// final GenomeLocParserOriginal genomeLocParser = new GenomeLocParserOriginal(seq.getSequenceDictionary());
+// GenomeLoc last = genomeLocParser.createGenomeLoc("1", 1, 1);
+// for ( int i = 0; i < rep; i++ ) {
+// for ( int j = 1; j < ITERATIONS; j++ ) {
+// if ( useContigIndex )
+// last = genomeLocParser.createGenomeLoc(last.getContig(), last.getContigIndex(), last.getStart() + 1);
+// else
+// last = genomeLocParser.createGenomeLoc(last.getContig(), last.getStart() + 1);
+// }
+// }
+// }
+
+ public static void main(String[] args) {
+ com.google.caliper.Runner.main(GenomeLocParserBenchmark.class, args);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocParserUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocParserUnitTest.java
new file mode 100644
index 0000000..d413633
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocParserUnitTest.java
@@ -0,0 +1,509 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import htsjdk.tribble.BasicFeature;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * @author aaron
+ * <p/>
+ * Class GenomeLocParserUnitTest
+ * <p/>
+ * Test out the functionality of the new genome loc parser
+ */
+public class GenomeLocParserUnitTest extends BaseTest {
+ private GenomeLocParser genomeLocParser;
+ private SAMFileHeader header;
+
+ @BeforeClass
+ public void init() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 10);
+ genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ }
+
+ @Test(expectedExceptions=UserException.MalformedGenomeLoc.class)
+ public void testGetContigIndex() {
+ assertEquals(genomeLocParser.getContigIndex("blah"), -1); // should not be in the reference
+ }
+
+ @Test
+ public void testGetContigIndexValid() {
+ assertEquals(genomeLocParser.getContigIndex("chr1"), 0); // should be in the reference
+ }
+
+ @Test(expectedExceptions=UserException.class)
+ public void testGetContigInfoUnknownContig1() {
+ assertEquals(null, genomeLocParser.getContigInfo("blah")); // should *not* be in the reference
+ }
+
+ @Test(expectedExceptions=UserException.class)
+ public void testGetContigInfoUnknownContig2() {
+ assertEquals(null, genomeLocParser.getContigInfo(null)); // should *not* be in the reference
+ }
+
+ @Test()
+ public void testHasContigInfoUnknownContig1() {
+ assertEquals(false, genomeLocParser.contigIsInDictionary("blah")); // should *not* be in the reference
+ }
+
+ @Test()
+ public void testHasContigInfoUnknownContig2() {
+ assertEquals(false, genomeLocParser.contigIsInDictionary(null)); // should *not* be in the reference
+ }
+
+ @Test()
+ public void testHasContigInfoKnownContig() {
+ assertEquals(true, genomeLocParser.contigIsInDictionary("chr1")); // should be in the reference
+ }
+
+ @Test
+ public void testGetContigInfoKnownContig() {
+ assertEquals(0, "chr1".compareTo(genomeLocParser.getContigInfo("chr1").getSequenceName())); // should be in the reference
+ }
+
+ @Test(expectedExceptions=ReviewedGATKException.class)
+ public void testParseBadString() {
+ genomeLocParser.parseGenomeLoc("Bad:0-1");
+ }
+
+ @Test
+ public void testContigHasColon() {
+ SAMFileHeader header = new SAMFileHeader();
+ header.setSortOrder(htsjdk.samtools.SAMFileHeader.SortOrder.coordinate);
+ SAMSequenceDictionary dict = new SAMSequenceDictionary();
+ SAMSequenceRecord rec = new SAMSequenceRecord("c:h:r1", 10);
+ rec.setSequenceLength(10);
+ dict.addSequence(rec);
+ header.setSequenceDictionary(dict);
+
+ final GenomeLocParser myGenomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ GenomeLoc loc = myGenomeLocParser.parseGenomeLoc("c:h:r1:4-5");
+ assertEquals(0, loc.getContigIndex());
+ assertEquals(loc.getStart(), 4);
+ assertEquals(loc.getStop(), 5);
+ }
+
+ @Test
+ public void testParseGoodString() {
+ GenomeLoc loc = genomeLocParser.parseGenomeLoc("chr1:1-10");
+ assertEquals(0, loc.getContigIndex());
+ assertEquals(loc.getStop(), 10);
+ assertEquals(loc.getStart(), 1);
+ }
+
+ @Test
+ public void testCreateGenomeLoc1() {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc("chr1", 1, 100);
+ assertEquals(0, loc.getContigIndex());
+ assertEquals(loc.getStop(), 100);
+ assertEquals(loc.getStart(), 1);
+ }
+
+ @Test
+ public void testCreateGenomeLoc1point5() { // in honor of VAAL!
+ GenomeLoc loc = genomeLocParser.parseGenomeLoc("chr1:1");
+ assertEquals(0, loc.getContigIndex());
+ assertEquals(loc.getStop(), 1);
+ assertEquals(loc.getStart(), 1);
+ }
+
+ @Test
+ public void testCreateGenomeLoc2() {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc("chr1", 1, 100);
+ assertEquals("chr1", loc.getContig());
+ assertEquals(loc.getStop(), 100);
+ assertEquals(loc.getStart(), 1);
+ }
+
+ @Test
+ public void testCreateGenomeLoc3() {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc("chr1", 1);
+ assertEquals("chr1", loc.getContig());
+ assertEquals(loc.getStop(), 1);
+ assertEquals(loc.getStart(), 1);
+ }
+
+ @Test
+ public void testCreateGenomeLoc4() {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc("chr1", 1);
+ assertEquals(0, loc.getContigIndex());
+ assertEquals(loc.getStop(), 1);
+ assertEquals(loc.getStart(), 1);
+ }
+
+ @Test
+ public void testCreateGenomeLoc5() {
+ GenomeLoc loc = genomeLocParser.createGenomeLoc("chr1", 1, 100);
+ GenomeLoc copy = genomeLocParser.createGenomeLoc(loc.getContig(),loc.getStart(),loc.getStop());
+ assertEquals(0, copy.getContigIndex());
+ assertEquals(copy.getStop(), 100);
+ assertEquals(copy.getStart(), 1);
+ }
+
+ @Test
+ public void testGenomeLocPlusSign() {
+ GenomeLoc loc = genomeLocParser.parseGenomeLoc("chr1:1+");
+ assertEquals(loc.getContigIndex(), 0);
+ assertEquals(loc.getStop(), 10); // the size
+ assertEquals(loc.getStart(), 1);
+ }
+
+ @Test
+ public void testGenomeLocParseOnlyChrome() {
+ GenomeLoc loc = genomeLocParser.parseGenomeLoc("chr1");
+ assertEquals(loc.getContigIndex(), 0);
+ assertEquals(loc.getStop(), 10); // the size
+ assertEquals(loc.getStart(), 1);
+ }
+
+ @Test(expectedExceptions=ReviewedGATKException.class)
+ public void testGenomeLocParseOnlyBadChrome() {
+ GenomeLoc loc = genomeLocParser.parseGenomeLoc("chr12");
+ assertEquals(loc.getContigIndex(), 0);
+ assertEquals(loc.getStop(), 10); // the size
+ assertEquals(loc.getStart(), 1);
+ }
+
+ @Test(expectedExceptions=ReviewedGATKException.class)
+ public void testGenomeLocBad() {
+ GenomeLoc loc = genomeLocParser.parseGenomeLoc("chr1:1-");
+ assertEquals(loc.getContigIndex(), 0);
+ assertEquals(loc.getStop(), 10); // the size
+ assertEquals(loc.getStart(), 1);
+ }
+
+ @Test(expectedExceptions=UserException.class)
+ public void testGenomeLocBad2() {
+ GenomeLoc loc = genomeLocParser.parseGenomeLoc("chr1:1-500-0");
+ assertEquals(loc.getContigIndex(), 0);
+ assertEquals(loc.getStop(), 10); // the size
+ assertEquals(loc.getStart(), 1);
+ }
+
+ @Test(expectedExceptions=UserException.class)
+ public void testGenomeLocBad3() {
+ GenomeLoc loc = genomeLocParser.parseGenomeLoc("chr1:1--0");
+ assertEquals(loc.getContigIndex(), 0);
+ assertEquals(loc.getStop(), 10); // the size
+ assertEquals(loc.getStart(), 1);
+ }
+
+ // test out the validating methods
+ @Test
+ public void testValidationOfGenomeLocs() {
+ assertTrue(genomeLocParser.isValidGenomeLoc("chr1",1,1));
+ assertTrue(!genomeLocParser.isValidGenomeLoc("chr2",1,1)); // shouldn't have an entry
+ assertTrue(!genomeLocParser.isValidGenomeLoc("chr1",1,11)); // past the end of the contig
+ assertTrue(!genomeLocParser.isValidGenomeLoc("chr1",-1,10)); // bad start
+ assertTrue(!genomeLocParser.isValidGenomeLoc("chr1",1,-2)); // bad stop
+ assertTrue( genomeLocParser.isValidGenomeLoc("chr1",-1,2, false)); // bad stop
+ assertTrue(!genomeLocParser.isValidGenomeLoc("chr1",10,11)); // bad start, past end
+ assertTrue( genomeLocParser.isValidGenomeLoc("chr1",10,11, false)); // bad start, past end
+ assertTrue(!genomeLocParser.isValidGenomeLoc("chr1",2,1)); // stop < start
+ }
+
+ @Test(expectedExceptions = ReviewedGATKException.class)
+ public void testValidateGenomeLoc() {
+ // bad contig index
+ genomeLocParser.validateGenomeLoc("chr1", 1, 1, 2, false);
+ }
+
+ private static class FlankingGenomeLocTestData extends TestDataProvider {
+ final GenomeLocParser parser;
+ final int basePairs;
+ final GenomeLoc original, flankStart, flankStop;
+
+ private FlankingGenomeLocTestData(String name, GenomeLocParser parser, int basePairs, String original, String flankStart, String flankStop) {
+ super(FlankingGenomeLocTestData.class, name);
+ this.parser = parser;
+ this.basePairs = basePairs;
+ this.original = parse(parser, original);
+ this.flankStart = flankStart == null ? null : parse(parser, flankStart);
+ this.flankStop = flankStop == null ? null : parse(parser, flankStop);
+ }
+
+ private static GenomeLoc parse(GenomeLocParser parser, String str) {
+ return "unmapped".equals(str) ? GenomeLoc.UNMAPPED : parser.parseGenomeLoc(str);
+ }
+ }
+
+ @DataProvider(name = "flankingGenomeLocs")
+ public Object[][] getFlankingGenomeLocs() {
+ int contigLength = 10000;
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, contigLength);
+ GenomeLocParser parser = new GenomeLocParser(header.getSequenceDictionary());
+
+ new FlankingGenomeLocTestData("atStartBase1", parser, 1,
+ "chr1:1", null, "chr1:2");
+
+ new FlankingGenomeLocTestData("atStartBase50", parser, 50,
+ "chr1:1", null, "chr1:2-51");
+
+ new FlankingGenomeLocTestData("atStartRange50", parser, 50,
+ "chr1:1-10", null, "chr1:11-60");
+
+ new FlankingGenomeLocTestData("atEndBase1", parser, 1,
+ "chr1:" + contigLength, "chr1:" + (contigLength - 1), null);
+
+ new FlankingGenomeLocTestData("atEndBase50", parser, 50,
+ "chr1:" + contigLength, String.format("chr1:%d-%d", contigLength - 50, contigLength - 1), null);
+
+ new FlankingGenomeLocTestData("atEndRange50", parser, 50,
+ String.format("chr1:%d-%d", contigLength - 10, contigLength),
+ String.format("chr1:%d-%d", contigLength - 60, contigLength - 11),
+ null);
+
+ new FlankingGenomeLocTestData("nearStartBase1", parser, 1,
+ "chr1:2", "chr1:1", "chr1:3");
+
+ new FlankingGenomeLocTestData("nearStartRange50", parser, 50,
+ "chr1:21-30", "chr1:1-20", "chr1:31-80");
+
+ new FlankingGenomeLocTestData("nearEndBase1", parser, 1,
+ "chr1:" + (contigLength - 1), "chr1:" + (contigLength - 2), "chr1:" + contigLength);
+
+ new FlankingGenomeLocTestData("nearEndRange50", parser, 50,
+ String.format("chr1:%d-%d", contigLength - 30, contigLength - 21),
+ String.format("chr1:%d-%d", contigLength - 80, contigLength - 31),
+ String.format("chr1:%d-%d", contigLength - 20, contigLength));
+
+ new FlankingGenomeLocTestData("beyondStartBase1", parser, 1,
+ "chr1:3", "chr1:2", "chr1:4");
+
+ new FlankingGenomeLocTestData("beyondStartRange50", parser, 50,
+ "chr1:101-200", "chr1:51-100", "chr1:201-250");
+
+ new FlankingGenomeLocTestData("beyondEndBase1", parser, 1,
+ "chr1:" + (contigLength - 3),
+ "chr1:" + (contigLength - 4),
+ "chr1:" + (contigLength - 2));
+
+ new FlankingGenomeLocTestData("beyondEndRange50", parser, 50,
+ String.format("chr1:%d-%d", contigLength - 200, contigLength - 101),
+ String.format("chr1:%d-%d", contigLength - 250, contigLength - 201),
+ String.format("chr1:%d-%d", contigLength - 100, contigLength - 51));
+
+ new FlankingGenomeLocTestData("unmapped", parser, 50,
+ "unmapped", null, null);
+
+ new FlankingGenomeLocTestData("fullContig", parser, 50,
+ "chr1", null, null);
+
+ return FlankingGenomeLocTestData.getTests(FlankingGenomeLocTestData.class);
+ }
+
+ @Test(dataProvider = "flankingGenomeLocs")
+ public void testCreateGenomeLocAtStart(FlankingGenomeLocTestData data) {
+ GenomeLoc actual = data.parser.createGenomeLocAtStart(data.original, data.basePairs);
+ String description = String.format("%n name: %s%n original: %s%n actual: %s%n expected: %s%n",
+ data.toString(), data.original, actual, data.flankStart);
+ assertEquals(actual, data.flankStart, description);
+ }
+
+ @Test(dataProvider = "flankingGenomeLocs")
+ public void testCreateGenomeLocAtStop(FlankingGenomeLocTestData data) {
+ GenomeLoc actual = data.parser.createGenomeLocAtStop(data.original, data.basePairs);
+ String description = String.format("%n name: %s%n original: %s%n actual: %s%n expected: %s%n",
+ data.toString(), data.original, actual, data.flankStop);
+ assertEquals(actual, data.flankStop, description);
+ }
+
+ @DataProvider(name = "parseGenomeLoc")
+ public Object[][] makeParsingTest() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ tests.add(new Object[]{ "chr1:10", "chr1", 10 });
+ tests.add(new Object[]{ "chr1:100", "chr1", 100 });
+ tests.add(new Object[]{ "chr1:1000", "chr1", 1000 });
+ tests.add(new Object[]{ "chr1:1,000", "chr1", 1000 });
+ tests.add(new Object[]{ "chr1:10000", "chr1", 10000 });
+ tests.add(new Object[]{ "chr1:10,000", "chr1", 10000 });
+ tests.add(new Object[]{ "chr1:100000", "chr1", 100000 });
+ tests.add(new Object[]{ "chr1:100,000", "chr1", 100000 });
+ tests.add(new Object[]{ "chr1:1000000", "chr1", 1000000 });
+ tests.add(new Object[]{ "chr1:1,000,000", "chr1", 1000000 });
+ tests.add(new Object[]{ "chr1:1000,000", "chr1", 1000000 });
+ tests.add(new Object[]{ "chr1:1,000000", "chr1", 1000000 });
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test( dataProvider = "parseGenomeLoc")
+ public void testParsingPositions(final String string, final String contig, final int start) {
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 10000000);
+ GenomeLocParser genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ final GenomeLoc loc = genomeLocParser.parseGenomeLoc(string);
+ Assert.assertEquals(loc.getContig(), contig);
+ Assert.assertEquals(loc.getStart(), start);
+ Assert.assertEquals(loc.getStop(), start);
+ }
+
+ @Test( )
+ public void testCreationFromSAMRecord() {
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "foo", 0, 1, 5);
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(read);
+ Assert.assertEquals(loc.getContig(), read.getReferenceName());
+ Assert.assertEquals(loc.getContigIndex(), (int)read.getReferenceIndex());
+ Assert.assertEquals(loc.getStart(), read.getAlignmentStart());
+ Assert.assertEquals(loc.getStop(), read.getAlignmentEnd());
+ }
+
+ @Test( )
+ public void testCreationFromSAMRecordUnmapped() {
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "foo", 0, 1, 5);
+ read.setReadUnmappedFlag(true);
+ read.setReferenceIndex(-1);
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(read);
+ Assert.assertTrue(loc.isUnmapped());
+ }
+
+ @Test( )
+ public void testCreationFromSAMRecordUnmappedButOnGenome() {
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "foo", 0, 1, 5);
+ read.setReadUnmappedFlag(true);
+ read.setCigarString("*");
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(read);
+ Assert.assertEquals(loc.getContig(), read.getReferenceName());
+ Assert.assertEquals(loc.getContigIndex(), (int)read.getReferenceIndex());
+ Assert.assertEquals(loc.getStart(), read.getAlignmentStart());
+ Assert.assertEquals(loc.getStop(), read.getAlignmentStart());
+ }
+
+ @Test
+ public void testCreationFromFeature() {
+ final Feature feature = new BasicFeature("chr1", 1, 5);
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(feature);
+ Assert.assertEquals(loc.getContig(), feature.getChr());
+ Assert.assertEquals(loc.getStart(), feature.getStart());
+ Assert.assertEquals(loc.getStop(), feature.getEnd());
+ }
+
+ @Test
+ public void testCreationFromVariantContext() {
+ final VariantContext feature = new VariantContextBuilder("x", "chr1", 1, 5, Arrays.asList(Allele.create("AAAAA", true))).make();
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(feature);
+ Assert.assertEquals(loc.getContig(), feature.getChr());
+ Assert.assertEquals(loc.getStart(), feature.getStart());
+ Assert.assertEquals(loc.getStop(), feature.getEnd());
+ }
+
+ @Test
+ public void testcreateGenomeLocOnContig() throws FileNotFoundException {
+ final CachingIndexedFastaSequenceFile seq = new CachingIndexedFastaSequenceFile(new File(b37KGReference));
+ final SAMSequenceDictionary dict = seq.getSequenceDictionary();
+ final GenomeLocParser genomeLocParser = new GenomeLocParser(dict);
+
+ for ( final SAMSequenceRecord rec : dict.getSequences() ) {
+ final GenomeLoc loc = genomeLocParser.createOverEntireContig(rec.getSequenceName());
+ Assert.assertEquals(loc.getContig(), rec.getSequenceName());
+ Assert.assertEquals(loc.getStart(), 1);
+ Assert.assertEquals(loc.getStop(), rec.getSequenceLength());
+ }
+ }
+
+ @DataProvider(name = "GenomeLocOnContig")
+ public Object[][] makeGenomeLocOnContig() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ final int contigLength = header.getSequence(0).getSequenceLength();
+ for ( int start = -10; start < contigLength + 10; start++ ) {
+ for ( final int len : Arrays.asList(1, 10, 20) ) {
+ tests.add(new Object[]{ "chr1", start, start + len });
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test( dataProvider = "GenomeLocOnContig")
+ public void testGenomeLocOnContig(final String contig, final int start, final int stop) {
+ final int contigLength = header.getSequence(0).getSequenceLength();
+ final GenomeLoc loc = genomeLocParser.createGenomeLocOnContig(contig, start, stop);
+
+ if ( stop < 1 || start > contigLength )
+ Assert.assertNull(loc, "GenomeLoc should be null if the start/stops are not meaningful");
+ else {
+ Assert.assertNotNull(loc);
+ Assert.assertEquals(loc.getContig(), contig);
+ Assert.assertEquals(loc.getStart(), Math.max(start, 1));
+ Assert.assertEquals(loc.getStop(), Math.min(stop, contigLength));
+ }
+ }
+
+ @DataProvider(name = "GenomeLocPadding")
+ public Object[][] makeGenomeLocPadding() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ final int contigLength = header.getSequence(0).getSequenceLength();
+ for ( int pad = 0; pad < contigLength + 1; pad++) {
+ for ( int start = 1; start < contigLength; start++ ) {
+ for ( int stop = start; stop < contigLength; stop++ ) {
+ tests.add(new Object[]{ genomeLocParser.createGenomeLoc("chr1", start, stop), pad});
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test( dataProvider = "GenomeLocPadding")
+ public void testGenomeLocPadding(final GenomeLoc input, final int pad) {
+ final int contigLength = header.getSequence(0).getSequenceLength();
+ final GenomeLoc padded = genomeLocParser.createPaddedGenomeLoc(input, pad);
+
+ Assert.assertNotNull(padded);
+ Assert.assertEquals(padded.getContig(), input.getContig());
+ Assert.assertEquals(padded.getStart(), Math.max(input.getStart() - pad, 1));
+ Assert.assertEquals(padded.getStop(), Math.min(input.getStop() + pad, contigLength));
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocSortedSetUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocSortedSetUnitTest.java
new file mode 100644
index 0000000..6553120
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocSortedSetUnitTest.java
@@ -0,0 +1,405 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ *
+ * User: aaron
+ * Date: May 22, 2009
+ * Time: 2:14:07 PM
+ *
+ * The Broad Institute
+ * SOFTWARE COPYRIGHT NOTICE AGREEMENT
+ * This software and its documentation are copyright 2009 by the
+ * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
+ *
+ * This software is supplied without any warranty or guaranteed support whatsoever. Neither
+ * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
+ *
+ */
+
+
+/**
+ * @author aaron
+ * @version 1.0
+ * <p/>
+ * Class GenomeLocSetTest
+ * <p/>
+ * This tests the functions of the GenomeLocSet
+ */
+public class GenomeLocSortedSetUnitTest extends BaseTest {
+
+ private GenomeLocSortedSet mSortedSet = null;
+ private SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(NUMBER_OF_CHROMOSOMES, STARTING_CHROMOSOME, CHROMOSOME_SIZE);
+ private static final int NUMBER_OF_CHROMOSOMES = 5;
+ private static final int STARTING_CHROMOSOME = 1;
+ private static final int CHROMOSOME_SIZE = 1000;
+
+ private GenomeLocParser genomeLocParser;
+ private String contigOneName;
+
+ @BeforeClass
+ public void setup() {
+ genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ contigOneName = header.getSequenceDictionary().getSequence(1).getSequenceName();
+ }
+
+ @BeforeMethod
+ public void initializeSortedSet() {
+ mSortedSet = new GenomeLocSortedSet(genomeLocParser);
+ }
+
+ @Test
+ public void testAdd() {
+ GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 0, 0);
+ assertTrue(mSortedSet.size() == 0);
+ mSortedSet.add(g);
+ assertTrue(mSortedSet.size() == 1);
+ }
+
+ @Test
+ public void testRemove() {
+ assertTrue(mSortedSet.size() == 0);
+ GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 0, 0);
+ mSortedSet.add(g);
+ assertTrue(mSortedSet.size() == 1);
+ mSortedSet.remove(g);
+ assertTrue(mSortedSet.size() == 0);
+ }
+
+ @Test
+ public void addRegion() {
+ assertTrue(mSortedSet.size() == 0);
+ GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 1, 50);
+ mSortedSet.add(g);
+ GenomeLoc f = genomeLocParser.createGenomeLoc(contigOneName, 30, 80);
+ mSortedSet.addRegion(f);
+ assertTrue(mSortedSet.size() == 1);
+ }
+
+ @Test
+ public void addRegionsOutOfOrder() {
+ final String contigTwoName = header.getSequenceDictionary().getSequence(2).getSequenceName();
+ assertTrue(mSortedSet.size() == 0);
+ GenomeLoc g = genomeLocParser.createGenomeLoc(contigTwoName, 1, 50);
+ mSortedSet.add(g);
+ GenomeLoc f = genomeLocParser.createGenomeLoc(contigOneName, 30, 80);
+ mSortedSet.addRegion(f);
+ assertTrue(mSortedSet.size() == 2);
+ assertTrue(mSortedSet.toList().get(0).getContig().equals(contigOneName));
+ assertTrue(mSortedSet.toList().get(1).getContig().equals(contigTwoName));
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void addThrowsException() {
+ assertTrue(mSortedSet.size() == 0);
+ GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 1, 50);
+ mSortedSet.add(g);
+ GenomeLoc f = genomeLocParser.createGenomeLoc(contigOneName, 30, 80);
+ mSortedSet.add(f);
+ }
+
+ @Test(expectedExceptions=IllegalArgumentException.class)
+ public void testAddDuplicate() {
+ assertTrue(mSortedSet.size() == 0);
+ GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 0, 0);
+ mSortedSet.add(g);
+ assertTrue(mSortedSet.size() == 1);
+ mSortedSet.add(g);
+ }
+
+ @Test
+ public void mergingOverlappingBelow() {
+ GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 0, 50);
+ GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 49, 100);
+ assertTrue(mSortedSet.size() == 0);
+ mSortedSet.add(g);
+ assertTrue(mSortedSet.size() == 1);
+ mSortedSet.addRegion(e);
+ assertTrue(mSortedSet.size() == 1);
+ Iterator<GenomeLoc> iter = mSortedSet.iterator();
+ GenomeLoc loc = iter.next();
+ assertEquals(loc.getStart(), 0);
+ assertEquals(loc.getStop(), 100);
+ assertEquals(loc.getContigIndex(), 1);
+ }
+
+ @Test
+ public void overlap() {
+ for ( int i = 1; i < 6; i++ ) {
+ final int start = i * 10;
+ mSortedSet.add(genomeLocParser.createGenomeLoc(contigOneName, start, start + 1));
+ }
+
+ // test matches in and around interval
+ assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 9, 9)));
+ assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 10, 10)));
+ assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 11, 11)));
+ assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 12, 12)));
+
+ // test matches spanning intervals
+ assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 14, 20)));
+ assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 11, 15)));
+ assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 30, 40)));
+ assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 51, 53)));
+
+ // test miss
+ assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 12, 19)));
+
+ // test exact match after miss
+ assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 40, 41)));
+
+ // test matches at beginning of intervals
+ assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 5, 6)));
+ assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 0, 10)));
+
+ // test matches at end of intervals
+ assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 52, 53)));
+ assertTrue(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 51, 53)));
+ assertFalse(mSortedSet.overlaps(genomeLocParser.createGenomeLoc(contigOneName, 52, 53)));
+ }
+
+ @Test
+ public void mergingOverlappingAbove() {
+ GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 0, 50);
+ GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 49, 100);
+ assertTrue(mSortedSet.size() == 0);
+ mSortedSet.add(g);
+ assertTrue(mSortedSet.size() == 1);
+ mSortedSet.addRegion(e);
+ assertTrue(mSortedSet.size() == 1);
+ Iterator<GenomeLoc> iter = mSortedSet.iterator();
+ GenomeLoc loc = iter.next();
+ assertEquals(loc.getStart(), 0);
+ assertEquals(loc.getStop(), 100);
+ assertEquals(loc.getContigIndex(), 1);
+ }
+
+ @Test
+ public void deleteAllByRegion() {
+ GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 1, 100);
+ mSortedSet.add(e);
+ for (int x = 1; x < 101; x++) {
+ GenomeLoc del = genomeLocParser.createGenomeLoc(contigOneName,x,x);
+ mSortedSet = mSortedSet.subtractRegions(new GenomeLocSortedSet(genomeLocParser,del));
+ }
+ assertTrue(mSortedSet.isEmpty());
+ }
+
+ @Test
+ public void deleteSomeByRegion() {
+ GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 1, 100);
+ mSortedSet.add(e);
+ for (int x = 1; x < 50; x++) {
+ GenomeLoc del = genomeLocParser.createGenomeLoc(contigOneName,x,x);
+ mSortedSet = mSortedSet.subtractRegions(new GenomeLocSortedSet(genomeLocParser,del));
+ }
+ assertTrue(!mSortedSet.isEmpty());
+ assertTrue(mSortedSet.size() == 1);
+ GenomeLoc loc = mSortedSet.iterator().next();
+ assertTrue(loc.getStop() == 100);
+ assertTrue(loc.getStart() == 50);
+
+ }
+
+ @Test
+ public void deleteSuperRegion() {
+ GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 10, 20);
+ GenomeLoc g = genomeLocParser.createGenomeLoc(contigOneName, 70, 100);
+ mSortedSet.add(g);
+ mSortedSet.addRegion(e);
+ assertTrue(mSortedSet.size() == 2);
+ // now delete a region
+ GenomeLoc d = genomeLocParser.createGenomeLoc(contigOneName, 15, 75);
+ mSortedSet = mSortedSet.subtractRegions(new GenomeLocSortedSet(genomeLocParser,d));
+ Iterator<GenomeLoc> iter = mSortedSet.iterator();
+ GenomeLoc loc = iter.next();
+ assertTrue(loc.getStart() == 10);
+ assertTrue(loc.getStop() == 14);
+ assertTrue(loc.getContigIndex() == 1);
+
+ loc = iter.next();
+ assertTrue(loc.getStart() == 76);
+ assertTrue(loc.getStop() == 100);
+ assertTrue(loc.getContigIndex() == 1);
+ }
+
+ @Test
+ public void substractComplexExample() {
+ GenomeLoc e = genomeLocParser.createGenomeLoc(contigOneName, 1, 20);
+ mSortedSet.add(e);
+
+ GenomeLoc r1 = genomeLocParser.createGenomeLoc(contigOneName, 3, 5);
+ GenomeLoc r2 = genomeLocParser.createGenomeLoc(contigOneName, 10, 12);
+ GenomeLoc r3 = genomeLocParser.createGenomeLoc(contigOneName, 16, 18);
+ GenomeLocSortedSet toExclude = new GenomeLocSortedSet(genomeLocParser,Arrays.asList(r1, r2, r3));
+
+ GenomeLocSortedSet remaining = mSortedSet.subtractRegions(toExclude);
+// logger.debug("Initial " + mSortedSet);
+// logger.debug("Exclude " + toExclude);
+// logger.debug("Remaining " + remaining);
+
+ assertEquals(mSortedSet.coveredSize(), 20);
+ assertEquals(toExclude.coveredSize(), 9);
+ assertEquals(remaining.coveredSize(), 11);
+
+ Iterator<GenomeLoc> it = remaining.iterator();
+ GenomeLoc p1 = it.next();
+ GenomeLoc p2 = it.next();
+ GenomeLoc p3 = it.next();
+ GenomeLoc p4 = it.next();
+
+ assertEquals(genomeLocParser.createGenomeLoc(contigOneName, 1, 2), p1);
+ assertEquals(genomeLocParser.createGenomeLoc(contigOneName, 6, 9), p2);
+ assertEquals(genomeLocParser.createGenomeLoc(contigOneName, 13, 15), p3);
+ assertEquals(genomeLocParser.createGenomeLoc(contigOneName, 19, 20), p4);
+ }
+
+ private void testSizeBeforeLocX(int pos, int size) {
+ GenomeLoc test = genomeLocParser.createGenomeLoc(contigOneName, pos, pos);
+ assertEquals(mSortedSet.sizeBeforeLoc(test), size, String.format("X pos=%d size=%d", pos, size));
+ }
+
+ @Test
+ public void testSizeBeforeLoc() {
+ GenomeLoc r1 = genomeLocParser.createGenomeLoc(contigOneName, 3, 5);
+ GenomeLoc r2 = genomeLocParser.createGenomeLoc(contigOneName, 10, 12);
+ GenomeLoc r3 = genomeLocParser.createGenomeLoc(contigOneName, 16, 18);
+ mSortedSet.addAll(Arrays.asList(r1,r2,r3));
+
+ testSizeBeforeLocX(2, 0);
+ testSizeBeforeLocX(3, 0);
+ testSizeBeforeLocX(4, 1);
+ testSizeBeforeLocX(5, 2);
+ testSizeBeforeLocX(6, 3);
+
+ testSizeBeforeLocX(10, 3);
+ testSizeBeforeLocX(11, 4);
+ testSizeBeforeLocX(12, 5);
+ testSizeBeforeLocX(13, 6);
+ testSizeBeforeLocX(15, 6);
+
+ testSizeBeforeLocX(16, 6);
+ testSizeBeforeLocX(17, 7);
+ testSizeBeforeLocX(18, 8);
+ testSizeBeforeLocX(19, 9);
+ testSizeBeforeLocX(50, 9);
+ testSizeBeforeLocX(50, (int)mSortedSet.coveredSize());
+ }
+
+
+ @Test
+ public void fromSequenceDictionary() {
+ mSortedSet = GenomeLocSortedSet.createSetFromSequenceDictionary(this.header.getSequenceDictionary());
+ // we should have sequence
+ assertTrue(mSortedSet.size() == GenomeLocSortedSetUnitTest.NUMBER_OF_CHROMOSOMES);
+ int seqNumber = 0;
+ for (GenomeLoc loc : mSortedSet) {
+ assertTrue(loc.getStart() == 1);
+ assertTrue(loc.getStop() == GenomeLocSortedSetUnitTest.CHROMOSOME_SIZE);
+ assertTrue(loc.getContigIndex() == seqNumber);
+ ++seqNumber;
+ }
+ assertTrue(seqNumber == GenomeLocSortedSetUnitTest.NUMBER_OF_CHROMOSOMES);
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ //
+ // Test getOverlapping
+ //
+ // -----------------------------------------------------------------------------------------------
+
+ @DataProvider(name = "GetOverlapping")
+ public Object[][] makeGetOverlappingTest() throws Exception {
+ final GenomeLocParser genomeLocParser = new GenomeLocParser(new CachingIndexedFastaSequenceFile(new File(b37KGReference)));
+
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final GenomeLoc prev1 = genomeLocParser.createGenomeLoc("19", 1, 10);
+ final GenomeLoc prev2 = genomeLocParser.createGenomeLoc("19", 20, 50);
+ final GenomeLoc post1 = genomeLocParser.createGenomeLoc("21", 1, 10);
+ final GenomeLoc post2 = genomeLocParser.createGenomeLoc("21", 20, 50);
+
+ final int chr20Length = genomeLocParser.getContigs().getSequence("20").getSequenceLength();
+ for ( final int regionStart : Arrays.asList(1, 10, chr20Length - 10, chr20Length) ) {
+ for ( final int regionSize : Arrays.asList(1, 10, 100) ) {
+ final GenomeLoc region = genomeLocParser.createGenomeLocOnContig("20", regionStart, regionStart + regionSize);
+ final GenomeLoc spanning = genomeLocParser.createGenomeLocOnContig("20", regionStart - 10, region.getStop() + 10);
+ final GenomeLoc before_into = genomeLocParser.createGenomeLocOnContig("20", regionStart - 10, regionStart + 1);
+ final GenomeLoc middle = genomeLocParser.createGenomeLocOnContig("20", regionStart + 1, regionStart + 2);
+ final GenomeLoc middle_past = genomeLocParser.createGenomeLocOnContig("20", region.getStop()-1, region.getStop()+10);
+
+ final List<GenomeLoc> potentials = new LinkedList<GenomeLoc>();
+ potentials.add(region);
+ if ( spanning != null ) potentials.add(spanning);
+ if ( before_into != null ) potentials.add(before_into);
+ if ( middle != null ) potentials.add(middle);
+ if ( middle_past != null ) potentials.add(middle_past);
+
+ for ( final int n : Arrays.asList(1, 2, 3) ) {
+ for ( final List<GenomeLoc> regions : Utils.makePermutations(potentials, n, false) ) {
+ tests.add(new Object[]{new GenomeLocSortedSet(genomeLocParser, regions), region});
+ tests.add(new Object[]{new GenomeLocSortedSet(genomeLocParser, Utils.append(regions, prev1)), region});
+ tests.add(new Object[]{new GenomeLocSortedSet(genomeLocParser, Utils.append(regions, prev1, prev2)), region});
+ tests.add(new Object[]{new GenomeLocSortedSet(genomeLocParser, Utils.append(regions, post1)), region});
+ tests.add(new Object[]{new GenomeLocSortedSet(genomeLocParser, Utils.append(regions, post1, post2)), region});
+ tests.add(new Object[]{new GenomeLocSortedSet(genomeLocParser, Utils.append(regions, prev1, post1)), region});
+ tests.add(new Object[]{new GenomeLocSortedSet(genomeLocParser, Utils.append(regions, prev1, prev2, post1, post2)), region});
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "GetOverlapping")
+ public void testGetOverlapping(final GenomeLocSortedSet intervals, final GenomeLoc region) {
+ final List<GenomeLoc> expectedOverlapping = intervals.getOverlappingFullSearch(region);
+ final List<GenomeLoc> actualOverlapping = intervals.getOverlapping(region);
+ Assert.assertEquals(actualOverlapping, expectedOverlapping);
+ Assert.assertEquals(intervals.overlaps(region), ! expectedOverlapping.isEmpty(), "GenomeLocSortedSet.overlaps didn't return expected result");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocUnitTest.java
new file mode 100644
index 0000000..ae86ca5
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/GenomeLocUnitTest.java
@@ -0,0 +1,386 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+
+// the imports for unit testing.
+
+
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.interval.IntervalMergingRule;
+import org.broadinstitute.gatk.utils.interval.IntervalUtils;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.*;
+
+/**
+ * Basic unit test for GenomeLoc
+ */
+public class GenomeLocUnitTest extends BaseTest {
+ private static ReferenceSequenceFile seq;
+ private GenomeLocParser genomeLocParser;
+
+ @BeforeClass
+ public void init() throws FileNotFoundException {
+ // sequence
+ seq = new CachingIndexedFastaSequenceFile(new File(hg18Reference));
+ genomeLocParser = new GenomeLocParser(seq);
+ }
+
+ /**
+ * Tests that we got a string parameter in correctly
+ */
+ @Test
+ public void testIsBetween() {
+ logger.warn("Executing testIsBetween");
+
+ GenomeLoc locMiddle = genomeLocParser.createGenomeLoc("chr1", 3, 3);
+
+ GenomeLoc locLeft = genomeLocParser.createGenomeLoc("chr1", 1, 1);
+ GenomeLoc locRight = genomeLocParser.createGenomeLoc("chr1", 5, 5);
+
+ Assert.assertTrue(locMiddle.isBetween(locLeft, locRight));
+ Assert.assertFalse(locLeft.isBetween(locMiddle, locRight));
+ Assert.assertFalse(locRight.isBetween(locLeft, locMiddle));
+
+ }
+ @Test
+ public void testContigIndex() {
+ logger.warn("Executing testContigIndex");
+ GenomeLoc locOne = genomeLocParser.createGenomeLoc("chr1",1,1);
+ Assert.assertEquals(1, locOne.getContigIndex());
+ Assert.assertEquals("chr1", locOne.getContig());
+
+ GenomeLoc locX = genomeLocParser.createGenomeLoc("chrX",1,1);
+ Assert.assertEquals(23, locX.getContigIndex());
+ Assert.assertEquals("chrX", locX.getContig());
+
+ GenomeLoc locNumber = genomeLocParser.createGenomeLoc(seq.getSequenceDictionary().getSequence(1).getSequenceName(),1,1);
+ Assert.assertEquals(1, locNumber.getContigIndex());
+ Assert.assertEquals("chr1", locNumber.getContig());
+ Assert.assertEquals(0, locOne.compareTo(locNumber));
+
+ }
+
+ @Test
+ public void testCompareTo() {
+ logger.warn("Executing testCompareTo");
+ GenomeLoc twoOne = genomeLocParser.createGenomeLoc("chr2", 1);
+ GenomeLoc twoFive = genomeLocParser.createGenomeLoc("chr2", 5);
+ GenomeLoc twoOtherFive = genomeLocParser.createGenomeLoc("chr2", 5);
+ Assert.assertEquals(twoFive.compareTo(twoOtherFive), 0);
+
+ Assert.assertEquals(twoOne.compareTo(twoFive), -1);
+ Assert.assertEquals(twoFive.compareTo(twoOne), 1);
+
+ GenomeLoc oneOne = genomeLocParser.createGenomeLoc("chr1", 5);
+ Assert.assertEquals(oneOne.compareTo(twoOne), -1);
+ Assert.assertEquals(twoOne.compareTo(oneOne), 1);
+ }
+
+
+ @Test
+ public void testUnmappedSort() {
+ GenomeLoc chr1 = genomeLocParser.createGenomeLoc("chr1",1,10000000);
+ GenomeLoc chr2 = genomeLocParser.createGenomeLoc("chr2",1,10000000);
+ GenomeLoc unmapped = GenomeLoc.UNMAPPED;
+
+ List<GenomeLoc> unmappedOnly = Arrays.asList(unmapped);
+ Collections.sort(unmappedOnly);
+ Assert.assertEquals(unmappedOnly.size(),1,"Wrong number of elements in unmapped-only list.");
+ Assert.assertEquals(unmappedOnly.get(0),unmapped,"List sorted in wrong order");
+
+ List<GenomeLoc> chr1Presorted = Arrays.asList(chr1,unmapped);
+ Collections.sort(chr1Presorted);
+ Assert.assertEquals(chr1Presorted.size(),2,"Wrong number of elements in chr1,unmapped list.");
+ Assert.assertEquals(chr1Presorted,Arrays.asList(chr1,unmapped),"List sorted in wrong order");
+
+ List<GenomeLoc> chr1Inverted = Arrays.asList(unmapped,chr1);
+ Collections.sort(chr1Inverted);
+ Assert.assertEquals(chr1Inverted.size(),2,"Wrong number of elements in chr1,unmapped list.");
+ Assert.assertEquals(chr1Inverted,Arrays.asList(chr1,unmapped),"List sorted in wrong order");
+
+ List<GenomeLoc> chr1and2Presorted = Arrays.asList(chr1,chr2,unmapped);
+ Collections.sort(chr1and2Presorted);
+ Assert.assertEquals(chr1and2Presorted.size(),3,"Wrong number of elements in chr1,chr2,unmapped list.");
+ Assert.assertEquals(chr1and2Presorted,Arrays.asList(chr1,chr2,unmapped),"List sorted in wrong order");
+
+ List<GenomeLoc> chr1and2UnmappedInFront = Arrays.asList(unmapped,chr1,chr2);
+ Collections.sort(chr1and2UnmappedInFront);
+ Assert.assertEquals(chr1and2UnmappedInFront.size(),3,"Wrong number of elements in unmapped,chr1,chr2 list.");
+ Assert.assertEquals(chr1and2UnmappedInFront,Arrays.asList(chr1,chr2,unmapped),"List sorted in wrong order");
+
+ List<GenomeLoc> chr1and2UnmappedSandwiched = Arrays.asList(chr1,unmapped,chr2);
+ Collections.sort(chr1and2UnmappedSandwiched);
+ Assert.assertEquals(chr1and2UnmappedSandwiched.size(),3,"Wrong number of elements in chr1,unmapped,chr2 list.");
+ Assert.assertEquals(chr1and2UnmappedSandwiched,Arrays.asList(chr1,chr2,unmapped),"List sorted in wrong order");
+ }
+
+ @Test
+ public void testUnmappedMerge() {
+ GenomeLoc chr1 = genomeLocParser.createGenomeLoc("chr1",1,10000000);
+ GenomeLoc unmapped = GenomeLoc.UNMAPPED;
+
+ List<GenomeLoc> oneUnmappedOnly = Arrays.asList(unmapped);
+ oneUnmappedOnly = IntervalUtils.sortAndMergeIntervals(genomeLocParser,oneUnmappedOnly, IntervalMergingRule.OVERLAPPING_ONLY).toList();
+ Assert.assertEquals(oneUnmappedOnly.size(),1,"Wrong number of elements in list.");
+ Assert.assertEquals(oneUnmappedOnly.get(0),unmapped,"List sorted in wrong order");
+
+ List<GenomeLoc> twoUnmapped = Arrays.asList(unmapped,unmapped);
+ twoUnmapped = IntervalUtils.sortAndMergeIntervals(genomeLocParser,twoUnmapped,IntervalMergingRule.OVERLAPPING_ONLY).toList();
+ Assert.assertEquals(twoUnmapped.size(),1,"Wrong number of elements in list.");
+ Assert.assertEquals(twoUnmapped.get(0),unmapped,"List sorted in wrong order");
+
+ List<GenomeLoc> twoUnmappedAtEnd = Arrays.asList(chr1,unmapped,unmapped);
+ twoUnmappedAtEnd = IntervalUtils.sortAndMergeIntervals(genomeLocParser,twoUnmappedAtEnd,IntervalMergingRule.OVERLAPPING_ONLY).toList();
+ Assert.assertEquals(twoUnmappedAtEnd.size(),2,"Wrong number of elements in list.");
+ Assert.assertEquals(twoUnmappedAtEnd,Arrays.asList(chr1,unmapped),"List sorted in wrong order");
+
+ List<GenomeLoc> twoUnmappedMixed = Arrays.asList(unmapped,chr1,unmapped);
+ twoUnmappedMixed = IntervalUtils.sortAndMergeIntervals(genomeLocParser,twoUnmappedMixed,IntervalMergingRule.OVERLAPPING_ONLY).toList();
+ Assert.assertEquals(twoUnmappedMixed.size(),2,"Wrong number of elements in list.");
+ Assert.assertEquals(twoUnmappedMixed,Arrays.asList(chr1,unmapped),"List sorted in wrong order");
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // testing overlap detection
+ //
+ // -------------------------------------------------------------------------------------
+
+ private class ReciprocalOverlapProvider extends TestDataProvider {
+ GenomeLoc gl1, gl2;
+ int overlapSize;
+ double overlapFraction;
+
+ private ReciprocalOverlapProvider(int start1, int stop1, int start2, int stop2) {
+ super(ReciprocalOverlapProvider.class);
+ gl1 = genomeLocParser.createGenomeLoc("chr1", start1, stop1);
+ gl2 = genomeLocParser.createGenomeLoc("chr1", start2, stop2);
+
+ int shared = 0;
+ for ( int i = start1; i <= stop1; i++ ) {
+ if ( i >= start2 && i <= stop2 )
+ shared++;
+ }
+
+ this.overlapSize = shared;
+ this.overlapFraction = Math.min((1.0*shared)/gl1.size(), (1.0*shared)/gl2.size());
+ super.setName(String.format("%d-%d / %d-%d overlap=%d / %.2f", start1, stop1, start2, stop2, overlapSize, overlapFraction));
+ }
+ }
+
+ @DataProvider(name = "ReciprocalOverlapProvider")
+ public Object[][] makeReciprocalOverlapProvider() {
+ for ( int start1 = 1; start1 <= 10; start1++ ) {
+ for ( int stop1 = start1; stop1 <= 10; stop1++ ) {
+ new ReciprocalOverlapProvider(start1, stop1, 1, 10);
+ new ReciprocalOverlapProvider(start1, stop1, 5, 10);
+ new ReciprocalOverlapProvider(start1, stop1, 5, 7);
+ new ReciprocalOverlapProvider(start1, stop1, 5, 15);
+ new ReciprocalOverlapProvider(start1, stop1, 11, 20);
+
+ new ReciprocalOverlapProvider(1, 10, start1, stop1);
+ new ReciprocalOverlapProvider(5, 10, start1, stop1);
+ new ReciprocalOverlapProvider(5, 7, start1, stop1);
+ new ReciprocalOverlapProvider(5, 15, start1, stop1);
+ new ReciprocalOverlapProvider(11, 20, start1, stop1);
+ }
+ }
+
+ return ReciprocalOverlapProvider.getTests(ReciprocalOverlapProvider.class);
+ }
+
+ @Test(dataProvider = "ReciprocalOverlapProvider")
+ public void testReciprocalOverlapProvider(ReciprocalOverlapProvider cfg) {
+ if ( cfg.overlapSize == 0 ) {
+ Assert.assertFalse(cfg.gl1.overlapsP(cfg.gl2));
+ } else {
+ Assert.assertTrue(cfg.gl1.overlapsP(cfg.gl2));
+ Assert.assertEquals(cfg.gl1.intersect(cfg.gl2).size(), cfg.overlapSize);
+ Assert.assertEquals(cfg.gl1.reciprocialOverlapFraction(cfg.gl2), cfg.overlapFraction);
+ }
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // testing comparison, hashcode, and equals
+ //
+ // -------------------------------------------------------------------------------------
+
+ @DataProvider(name = "GenomeLocComparisons")
+ public Object[][] createGenomeLocComparisons() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final int start = 10;
+ for ( int stop = start; stop < start + 3; stop++ ) {
+ final GenomeLoc g1 = genomeLocParser.createGenomeLoc("chr2", start, stop);
+ for ( final String contig : Arrays.asList("chr1", "chr2", "chr3")) {
+ for ( int start2 = start - 1; start2 <= stop + 1; start2++ ) {
+ for ( int stop2 = start2; stop2 < stop + 2; stop2++ ) {
+ final GenomeLoc g2 = genomeLocParser.createGenomeLoc(contig, start2, stop2);
+
+ ComparisonResult cmp = ComparisonResult.EQUALS;
+ if ( contig.equals("chr3") ) cmp = ComparisonResult.LESS_THAN;
+ else if ( contig.equals("chr1") ) cmp = ComparisonResult.GREATER_THAN;
+ else if ( start < start2 ) cmp = ComparisonResult.LESS_THAN;
+ else if ( start > start2 ) cmp = ComparisonResult.GREATER_THAN;
+ else if ( stop < stop2 ) cmp = ComparisonResult.LESS_THAN;
+ else if ( stop > stop2 ) cmp = ComparisonResult.GREATER_THAN;
+
+ tests.add(new Object[]{g1, g2, cmp});
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ private enum ComparisonResult {
+ LESS_THAN(-1),
+ EQUALS(0),
+ GREATER_THAN(1);
+
+ final int cmp;
+
+ private ComparisonResult(int cmp) {
+ this.cmp = cmp;
+ }
+ }
+
+ @Test(dataProvider = "GenomeLocComparisons")
+ public void testGenomeLocComparisons(GenomeLoc g1, GenomeLoc g2, ComparisonResult expected) {
+ Assert.assertEquals(g1.compareTo(g2), expected.cmp, "Comparing genome locs failed");
+ Assert.assertEquals(g1.equals(g2), expected == ComparisonResult.EQUALS);
+ if ( expected == ComparisonResult.EQUALS )
+ Assert.assertEquals(g1.hashCode(), g2.hashCode(), "Equal genome locs don't have the same hash code");
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // testing merging functionality
+ //
+ // -------------------------------------------------------------------------------------
+
+ private static final GenomeLoc loc1 = new GenomeLoc("1", 0, 10, 20);
+ private static final GenomeLoc loc2 = new GenomeLoc("1", 0, 21, 30);
+ private static final GenomeLoc loc3 = new GenomeLoc("1", 0, 31, 40);
+
+ private class MergeTest {
+ public List<GenomeLoc> locs;
+
+ private MergeTest(final List<GenomeLoc> locs) {
+ this.locs = locs;
+ }
+ }
+
+ @DataProvider(name = "SGLtest")
+ public Object[][] createFindVariantRegionsData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ tests.add(new Object[]{new MergeTest(Arrays.<GenomeLoc>asList(loc1))});
+ tests.add(new Object[]{new MergeTest(Arrays.<GenomeLoc>asList(loc1, loc2))});
+ tests.add(new Object[]{new MergeTest(Arrays.<GenomeLoc>asList(loc1, loc2, loc3))});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "SGLtest", enabled = true)
+ public void testSimpleGenomeLoc(MergeTest test) {
+ testMerge(test.locs);
+ }
+
+ @Test(expectedExceptions = ReviewedGATKException.class)
+ public void testNotContiguousLocs() {
+ final List<GenomeLoc> locs = new ArrayList<GenomeLoc>(1);
+ locs.add(loc1);
+ locs.add(loc3);
+ testMerge(locs);
+ }
+
+ private void testMerge(final List<GenomeLoc> locs) {
+ GenomeLoc result1 = locs.get(0);
+ for ( int i = 1; i < locs.size(); i++ )
+ result1 = GenomeLoc.merge(result1, locs.get(i));
+
+ GenomeLoc result2 = GenomeLoc.merge(new TreeSet<GenomeLoc>(locs));
+ Assert.assertEquals(result1, result2);
+ Assert.assertEquals(result1.getStart(), locs.get(0).getStart());
+ Assert.assertEquals(result1.getStop(), locs.get(locs.size() - 1).getStop());
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // testing distance functionality
+ //
+ // -------------------------------------------------------------------------------------
+
+ @Test(enabled=true)
+ public void testDistanceAcrossContigs() {
+ final int chrSize = 1000;
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(10, 0, chrSize);
+ GenomeLocParser parser = new GenomeLocParser(header.getSequenceDictionary());
+ GenomeLoc loc1 = parser.createGenomeLoc("chr3", 500); // to check regular case
+ GenomeLoc loc2 = parser.createGenomeLoc("chr7", 200); // to check regular case
+ GenomeLoc loc3 = parser.createGenomeLoc("chr0", 1); // to check corner case
+ GenomeLoc loc4 = parser.createGenomeLoc("chr9", 1000);// to check corner case
+ GenomeLoc loc5 = parser.createGenomeLoc("chr7", 500); // to make sure it does the right thing when in the same chromosome
+
+ GenomeLoc loc6 = parser.createGenomeLoc("chr7", 200, 300);
+ GenomeLoc loc7 = parser.createGenomeLoc("chr7", 500, 600);
+ GenomeLoc loc8 = parser.createGenomeLoc("chr9", 500, 600);
+
+ // Locus comparisons
+ Assert.assertEquals(loc1.distanceAcrossContigs(loc2, header), 3*chrSize + chrSize-loc1.getStop() + loc2.getStart()); // simple case, smaller first
+ Assert.assertEquals(loc2.distanceAcrossContigs(loc1, header), 3*chrSize + chrSize-loc1.getStop() + loc2.getStart()); // simple case, bigger first
+
+ Assert.assertEquals(loc3.distanceAcrossContigs(loc4, header), 10*chrSize - 1); // corner case, smaller first
+ Assert.assertEquals(loc4.distanceAcrossContigs(loc3, header), 10*chrSize - 1); // corner case, bigger first
+
+ Assert.assertEquals(loc2.distanceAcrossContigs(loc5, header), 300); // same contig, smaller first
+ Assert.assertEquals(loc5.distanceAcrossContigs(loc2, header), 300); // same contig, bigger first
+
+ // Interval comparisons
+ Assert.assertEquals(loc6.distanceAcrossContigs(loc7, header), 200); // same contig, smaller first
+ Assert.assertEquals(loc7.distanceAcrossContigs(loc6, header), 200); // same contig, bigger first
+
+ Assert.assertEquals(loc7.distanceAcrossContigs(loc8, header), chrSize + chrSize-loc7.stop + loc8.getStart()); // across contigs, smaller first
+ Assert.assertEquals(loc8.distanceAcrossContigs(loc7, header), chrSize + chrSize-loc7.stop + loc8.getStart()); // across congits, bigger first
+
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MD5DB.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MD5DB.java
new file mode 100644
index 0000000..d7c9929
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MD5DB.java
@@ -0,0 +1,312 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.engine.walkers.diffengine.DiffEngine;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.*;
+import java.util.Arrays;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: depristo
+ * Date: 7/18/11
+ * Time: 9:10 AM
+ *
+ * Utilities for manipulating the MD5 database of previous results
+ */
+public class MD5DB {
+ public static final Logger logger = Logger.getLogger(MD5DB.class);
+
+ /**
+ * Subdirectory under the ant build directory where we store integration test md5 results
+ */
+ private static final int MAX_RECORDS_TO_READ = 1000000;
+ private static final int MAX_RAW_DIFFS_TO_SUMMARIZE = -1;
+ public static final String LOCAL_MD5_DB_DIR = "integrationtests";
+ public static final String GLOBAL_MD5_DB_DIR = "/humgen/gsa-hpprojects/GATK/data/integrationtests";
+
+ // tracking and emitting a data file of origina and new md5s
+ private final File MD5MismatchesFile;
+ private final PrintStream md5MismatchStream;
+
+ public MD5DB() {
+ this(new File(MD5DB.LOCAL_MD5_DB_DIR + "/md5mismatches.txt"));
+ }
+
+ public MD5DB(final File MD5MismatchesFile) {
+ this.MD5MismatchesFile = MD5MismatchesFile;
+
+ ensureMd5DbDirectory();
+
+ logger.debug("Creating md5 mismatch db at " + MD5MismatchesFile);
+ try {
+ md5MismatchStream = new PrintStream(new FileOutputStream(MD5MismatchesFile));
+ md5MismatchStream.printf("%s\t%s\t%s%n", "expected", "observed", "test");
+ } catch ( FileNotFoundException e ) {
+ throw new ReviewedGATKException("Failed to open md5 mismatch file", e);
+ }
+
+ }
+
+ public void close() {
+ if ( md5MismatchStream != null ) {
+ logger.debug("Closeing md5 mismatch db at " + MD5MismatchesFile);
+ md5MismatchStream.close();
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // MD5 DB stuff
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * Create the MD5 file directories if necessary
+ */
+ private void ensureMd5DbDirectory() {
+ File dir = new File(LOCAL_MD5_DB_DIR);
+ if ( ! dir.exists() ) {
+ System.out.printf("##### Creating MD5 db %s%n", LOCAL_MD5_DB_DIR);
+ if ( ! dir.mkdir() ) {
+ // Need to check AGAIN whether the dir exists, because we might be doing multi-process parallelism
+ // within the same working directory, and another GATK instance may have come along and created the
+ // directory between the calls to exists() and mkdir() above.
+ if ( ! dir.exists() ) {
+ throw new ReviewedGATKException("Infrastructure failure: failed to create md5 directory " + LOCAL_MD5_DB_DIR);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the path to an already existing file with the md5 contents, or valueIfNotFound
+ * if no such file exists in the db.
+ *
+ * @param md5
+ * @param valueIfNotFound
+ * @return
+ */
+ public String getMD5FilePath(final String md5, final String valueIfNotFound) {
+ // we prefer the global db to the local DB, so match it first
+ for ( String dir : Arrays.asList(GLOBAL_MD5_DB_DIR, LOCAL_MD5_DB_DIR)) {
+ File f = getFileForMD5(md5, dir);
+ if ( f.exists() && f.canRead() )
+ return f.getAbsolutePath();
+ }
+
+ return valueIfNotFound;
+ }
+
+ /**
+ * Utility function that given a file's md5 value and the path to the md5 db,
+ * returns the canonical name of the file. For example, if md5 is XXX and db is YYY,
+ * this will return YYY/XXX.integrationtest
+ *
+ * @param md5
+ * @param dbPath
+ * @return
+ */
+ private File getFileForMD5(final String md5, final String dbPath) {
+ final String basename = String.format("%s.integrationtest", md5);
+ return new File(dbPath + "/" + basename);
+ }
+
+ /**
+ * Copies the results file with md5 value to its canonical file name and db places
+ *
+ * @param md5
+ * @param resultsFile
+ */
+ private void updateMD5Db(final String md5, final File resultsFile) {
+ copyFileToDB(getFileForMD5(md5, LOCAL_MD5_DB_DIR), resultsFile);
+ copyFileToDB(getFileForMD5(md5, GLOBAL_MD5_DB_DIR), resultsFile);
+ }
+
+ /**
+ * Low-level utility routine that copies resultsFile to dbFile
+ * @param dbFile
+ * @param resultsFile
+ */
+ private void copyFileToDB(File dbFile, final File resultsFile) {
+ if ( ! dbFile.exists() ) {
+ // the file isn't already in the db, copy it over
+ System.out.printf("##### Updating MD5 file: %s%n", dbFile.getPath());
+ try {
+ FileUtils.copyFile(resultsFile, dbFile);
+ } catch ( IOException e ) {
+ System.out.printf("##### Skipping update, cannot write file %s%n", dbFile);
+ }
+ } else {
+ //System.out.printf("##### MD5 file is up to date: %s%n", dbFile.getPath());
+ }
+ }
+
+ /**
+ * Returns the byte[] of the entire contents of file, for md5 calculations
+ * @param file
+ * @return
+ * @throws IOException
+ */
+ private static byte[] getBytesFromFile(File file) throws IOException {
+ InputStream is = new FileInputStream(file);
+
+ // Get the size of the file
+ long length = file.length();
+
+ if (length > Integer.MAX_VALUE) {
+ // File is too large
+ }
+
+ // Create the byte array to hold the data
+ byte[] bytes = new byte[(int) length];
+
+ // Read in the bytes
+ int offset = 0;
+ int numRead = 0;
+ while (offset < bytes.length
+ && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
+ offset += numRead;
+ }
+
+ // Ensure all the bytes have been read in
+ if (offset < bytes.length) {
+ throw new IOException("Could not completely read file " + file.getName());
+ }
+
+ // Close the input stream and return bytes
+ is.close();
+ return bytes;
+ }
+
+ public static class MD5Match {
+ public final String actualMD5, expectedMD5;
+ public final String failMessage;
+ public final String diffEngineOutput;
+ public final boolean failed;
+
+ public MD5Match(final String actualMD5, final String expectedMD5, final String failMessage, final String diffEngineOutput, final boolean failed) {
+ this.actualMD5 = actualMD5;
+ this.expectedMD5 = expectedMD5;
+ this.failMessage = failMessage;
+ this.diffEngineOutput = diffEngineOutput;
+ this.failed = failed;
+ }
+ }
+
+ /**
+ * Tests a file MD5 against an expected value, returning an MD5Match object containing a description of the
+ * match or mismatch. In case of a mismatch, outputs a description of the mismatch to various log files/streams.
+ *
+ * NOTE: This function WILL NOT throw an exception if the MD5s are different.
+ *
+ * @param testName Name of the test.
+ * @param testClassName Name of the class that contains the test.
+ * @param resultsFile File to MD5.
+ * @param expectedMD5 Expected MD5 value.
+ * @param parameterize If true or if expectedMD5 is an empty string, will print out the calculated MD5 instead of error text.
+ * @return an MD5Match object containing a description of the match/mismatch. Will have its "failed" field set
+ * to true if there was a mismatch (unless we're using the "parameterize" argument)
+ */
+ public MD5Match testFileMD5(final String testName, final String testClassName, final File resultsFile, final String expectedMD5, final boolean parameterize) {
+ final String actualMD5 = calculateFileMD5(resultsFile);
+ String diffEngineOutput = "";
+ String failMessage = "";
+ boolean failed = false;
+
+ // copy md5 to integrationtests
+ updateMD5Db(actualMD5, resultsFile);
+
+ if (parameterize || expectedMD5.equals("")) {
+ BaseTest.log(String.format("PARAMETERIZATION: file %s has md5 = %s", resultsFile, actualMD5));
+ } else if ( ! expectedMD5.equals(actualMD5) ) {
+ failed = true;
+ failMessage = String.format("%s:%s has mismatching MD5s: expected=%s observed=%s", testClassName, testName, expectedMD5, actualMD5);
+ diffEngineOutput = logMD5MismatchAndGetDiffEngineOutput(testName, testClassName, expectedMD5, actualMD5);
+ }
+
+ return new MD5Match(actualMD5, expectedMD5, failMessage, diffEngineOutput, failed);
+ }
+
+ /**
+ * Calculates the MD5 for the specified file and returns it as a String
+ *
+ * @param file file whose MD5 to calculate
+ * @return file's MD5 in String form
+ * @throws RuntimeException if the file could not be read
+ */
+ public String calculateFileMD5( final File file ) {
+ try {
+ return Utils.calcMD5(getBytesFromFile(file));
+ }
+ catch ( Exception e ) {
+ throw new RuntimeException("Failed to read bytes from file: " + file + " for MD5 calculation", e);
+ }
+ }
+
+ /**
+ * Logs a description (including diff engine output) of the MD5 mismatch between the expectedMD5
+ * and actualMD5 to a combination of BaseTest.log(), the md5MismatchStream, and stdout, then returns
+ * the diff engine output.
+ *
+ * @param testName name of the test that generated the mismatch
+ * @param testClassName name of the class containing the test that generated the mismatch
+ * @param expectedMD5 the MD5 we were expecting from this test
+ * @param actualMD5 the MD5 we actually calculated from the test output
+ * @return the diff engine output produced while logging the description of the mismatch
+ */
+ private String logMD5MismatchAndGetDiffEngineOutput(final String testName, final String testClassName, final String expectedMD5, final String actualMD5) {
+ System.out.printf("##### Test %s:%s is going to fail #####%n", testClassName, testName);
+ String pathToExpectedMD5File = getMD5FilePath(expectedMD5, "[No DB file found]");
+ String pathToFileMD5File = getMD5FilePath(actualMD5, "[No DB file found]");
+ BaseTest.log(String.format("expected %s", expectedMD5));
+ BaseTest.log(String.format("calculated %s", actualMD5));
+ BaseTest.log(String.format("diff %s %s", pathToExpectedMD5File, pathToFileMD5File));
+
+ md5MismatchStream.printf("%s\t%s\t%s%n", expectedMD5, actualMD5, testName);
+ md5MismatchStream.flush();
+
+ // inline differences
+ String diffEngineOutput = "";
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final PrintStream ps = new PrintStream(baos);
+ DiffEngine.SummaryReportParams params = new DiffEngine.SummaryReportParams(ps, 20, 10, 0, MAX_RAW_DIFFS_TO_SUMMARIZE, false);
+ boolean success = DiffEngine.simpleDiffFiles(new File(pathToExpectedMD5File), new File(pathToFileMD5File), MAX_RECORDS_TO_READ, params);
+ if ( success ) {
+ diffEngineOutput = baos.toString();
+ BaseTest.log(diffEngineOutput);
+ System.out.printf("Note that the above list is not comprehensive. At most 20 lines of output, and 10 specific differences will be listed. Please use -T DiffObjects -R " + BaseTest.publicTestDir + "exampleFASTA.fasta -m %s -t %s to explore the differences more freely%n",
+ pathToExpectedMD5File, pathToFileMD5File);
+ }
+ ps.close();
+
+ return diffEngineOutput;
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MD5Mismatch.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MD5Mismatch.java
new file mode 100644
index 0000000..11064d1
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MD5Mismatch.java
@@ -0,0 +1,67 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Assertion failure representing an MD5 mismatch between expected and actual
+ *
+ * @author Your Name
+ * @since Date created
+ */
+public class MD5Mismatch extends Exception {
+ final List<String> actuals, expecteds, diffEngineOutputs;
+
+ public MD5Mismatch(final String actual, final String expected, final String diffEngineOutput) {
+ this(Collections.singletonList(actual), Collections.singletonList(expected), Collections.singletonList(diffEngineOutput));
+ }
+
+ public MD5Mismatch(final List<String> actuals, final List<String> expecteds, final List<String> diffEngineOutputs) {
+ super(formatMessage(actuals, expecteds, diffEngineOutputs));
+ this.actuals = actuals;
+ this.expecteds = expecteds;
+ this.diffEngineOutputs = diffEngineOutputs;
+ }
+
+ @Override
+ public String toString() {
+ return formatMessage(actuals, expecteds, diffEngineOutputs);
+ }
+
+ private static String formatMessage(final List<String> actuals, final List<String> expecteds, final List<String> diffEngineOutputs) {
+ final StringBuilder b = new StringBuilder("MD5 mismatch: ");
+ for ( int i = 0; i < actuals.size(); i++ ) {
+ if ( i >= 1 ) b.append("\t\t\n\n");
+ b.append("actual ").append(actuals.get(i));
+ b.append(" expected ").append(expecteds.get(i));
+ b.append("\nDiff Engine Output:\n");
+ b.append(diffEngineOutputs.get(i));
+ }
+ return b.toString();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MRUCachingSAMSequencingDictionaryUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MRUCachingSAMSequencingDictionaryUnitTest.java
new file mode 100644
index 0000000..978a9a7
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MRUCachingSAMSequencingDictionaryUnitTest.java
@@ -0,0 +1,97 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class MRUCachingSAMSequencingDictionaryUnitTest extends BaseTest {
+ private static ReferenceSequenceFile seq;
+ private static SAMSequenceDictionary dict;
+
+ @BeforeClass
+ public void init() throws FileNotFoundException {
+ // sequence
+ seq = new CachingIndexedFastaSequenceFile(new File(b37KGReference));
+ dict = seq.getSequenceDictionary();
+ }
+
+ @Test
+ public void testBasic() {
+ final MRUCachingSAMSequenceDictionary caching = new MRUCachingSAMSequenceDictionary(dict);
+
+ Assert.assertEquals(caching.getDictionary(), dict, "Dictionary not the one I expected");
+
+ for ( final SAMSequenceRecord rec : dict.getSequences() ) {
+ Assert.assertFalse(caching.isCached(rec.getSequenceIndex()), "Expected index to not be cached");
+ Assert.assertFalse(caching.isCached(rec.getSequenceName()), "Expected contig to not be cached");
+
+ Assert.assertEquals(caching.getSequence(rec.getSequenceName()), rec, "Couldn't query for sequence");
+ Assert.assertEquals(caching.getSequence(rec.getSequenceIndex()), rec, "Couldn't query for sequence index");
+ Assert.assertEquals(caching.hasContig(rec.getSequenceName()), true, "hasContig query for sequence");
+ Assert.assertEquals(caching.hasContigIndex(rec.getSequenceIndex()), true, "hasContigIndex query for sequence");
+ Assert.assertEquals(caching.getSequenceIndex(rec.getSequenceName()), rec.getSequenceIndex(), "Couldn't query for sequence");
+
+ Assert.assertEquals(caching.hasContig(rec.getSequenceName() + "asdfadsfa"), false, "hasContig query for unknown sequence");
+ Assert.assertEquals(caching.hasContigIndex(dict.getSequences().size()), false, "hasContigIndex query for unknown index");
+
+ Assert.assertTrue(caching.isCached(rec.getSequenceIndex()), "Expected index to be cached");
+ Assert.assertTrue(caching.isCached(rec.getSequenceName()), "Expected contig to be cached");
+ }
+ }
+
+ @Test(expectedExceptions = ReviewedGATKException.class)
+ public void testBadGetSequence() {
+ final MRUCachingSAMSequenceDictionary caching = new MRUCachingSAMSequenceDictionary(dict);
+ caching.getSequence("notInDictionary");
+ }
+
+ @Test(expectedExceptions = ReviewedGATKException.class)
+ public void testBadGetSequenceIndex() {
+ final MRUCachingSAMSequenceDictionary caching = new MRUCachingSAMSequenceDictionary(dict);
+ caching.getSequence(dict.getSequences().size());
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MWUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MWUnitTest.java
new file mode 100644
index 0000000..c148dc9
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MWUnitTest.java
@@ -0,0 +1,131 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.collections.Pair;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: Ghost
+ * Date: 3/5/11
+ * Time: 2:06 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class MWUnitTest extends BaseTest {
+ @BeforeClass
+ public void init() { }
+
+ @Test
+ private void testMWU() {
+ logger.warn("Testing MWU");
+ MannWhitneyU mwu = new MannWhitneyU();
+ mwu.add(0, MannWhitneyU.USet.SET1);
+ mwu.add(1,MannWhitneyU.USet.SET2);
+ mwu.add(2,MannWhitneyU.USet.SET2);
+ mwu.add(3,MannWhitneyU.USet.SET2);
+ mwu.add(4,MannWhitneyU.USet.SET2);
+ mwu.add(5,MannWhitneyU.USet.SET2);
+ mwu.add(6,MannWhitneyU.USet.SET1);
+ mwu.add(7,MannWhitneyU.USet.SET1);
+ mwu.add(8,MannWhitneyU.USet.SET1);
+ mwu.add(9,MannWhitneyU.USet.SET1);
+ mwu.add(10,MannWhitneyU.USet.SET1);
+ mwu.add(11,MannWhitneyU.USet.SET2);
+ Assert.assertEquals(MannWhitneyU.calculateOneSidedU(mwu.getObservations(), MannWhitneyU.USet.SET1),25L);
+ Assert.assertEquals(MannWhitneyU.calculateOneSidedU(mwu.getObservations(),MannWhitneyU.USet.SET2),11L);
+
+ MannWhitneyU mwu2 = new MannWhitneyU();
+ MannWhitneyU mwuNoDither = new MannWhitneyU(false);
+ for ( int dp : new int[]{2,4,5,6,8} ) {
+ mwu2.add(dp,MannWhitneyU.USet.SET1);
+ mwuNoDither.add(dp,MannWhitneyU.USet.SET1);
+ }
+
+ for ( int dp : new int[]{1,3,7,9,10,11,12,13} ) {
+ mwu2.add(dp,MannWhitneyU.USet.SET2);
+ mwuNoDither.add(dp,MannWhitneyU.USet.SET2);
+ }
+
+ MannWhitneyU.ExactMode pm = MannWhitneyU.ExactMode.POINT;
+ MannWhitneyU.ExactMode cm = MannWhitneyU.ExactMode.CUMULATIVE;
+
+ // tests using the hypothesis that set 2 dominates set 1 (U value = 10)
+ Assert.assertEquals(MannWhitneyU.calculateOneSidedU(mwu2.getObservations(),MannWhitneyU.USet.SET1),10L);
+ Assert.assertEquals(MannWhitneyU.calculateOneSidedU(mwu2.getObservations(),MannWhitneyU.USet.SET2),30L);
+ Assert.assertEquals(MannWhitneyU.calculateOneSidedU(mwuNoDither.getObservations(),MannWhitneyU.USet.SET1),10L);
+ Assert.assertEquals(MannWhitneyU.calculateOneSidedU(mwuNoDither.getObservations(),MannWhitneyU.USet.SET2),30L);
+
+ Pair<Integer,Integer> sizes = mwu2.getSetSizes();
+
+ Assert.assertEquals(MannWhitneyU.calculatePUniformApproximation(sizes.first,sizes.second,10L),0.4180519701814064,1e-14);
+ Assert.assertEquals(MannWhitneyU.calculatePRecursively(sizes.first,sizes.second,10L,false,pm).second,0.021756021756021756,1e-14);
+ Assert.assertEquals(MannWhitneyU.calculatePNormalApproximation(sizes.first,sizes.second,10L,false).second,0.06214143703127617,1e-14);
+ logger.warn("Testing two-sided");
+ Assert.assertEquals((double)mwu2.runTwoSidedTest().second,2*0.021756021756021756,1e-8);
+
+ // tests using the hypothesis that set 1 dominates set 2 (U value = 30) -- empirical should be identical, normall approx close, uniform way off
+ Assert.assertEquals(MannWhitneyU.calculatePNormalApproximation(sizes.second,sizes.first,30L,true).second,2.0*0.08216463976903321,1e-14);
+ Assert.assertEquals(MannWhitneyU.calculatePUniformApproximation(sizes.second,sizes.first,30L),0.0023473625009559074,1e-14);
+ Assert.assertEquals(MannWhitneyU.calculatePRecursively(sizes.second,sizes.first,30L,false,pm).second,0.021756021756021756,1e-14); // note -- exactly same value as above
+ Assert.assertEquals(MannWhitneyU.calculatePRecursively(sizes.second,sizes.first,29L,false,cm).second,1.0-0.08547008547008,1e-14); // r does a correction, subtracting 1 from U
+ Assert.assertEquals(MannWhitneyU.calculatePRecursively(sizes.second,sizes.first,11L,false,cm).second,0.08547008547008,1e-14); // r does a correction, subtracting 1 from U
+ Assert.assertEquals(MannWhitneyU.calculatePRecursively(sizes.second,sizes.first,11L,false,cm).first,-1.36918910442,1e-2); // apache inversion set to be good only to 1e-2
+ Assert.assertEquals(MannWhitneyU.calculatePRecursively(sizes.second,sizes.first,29L,false,cm).first,1.36918910442,1e-2); // apache inversion set to be good only to 1e-2
+ Assert.assertEquals(MannWhitneyU.calculatePRecursively(sizes.second,sizes.first,29L,false,pm).first,1.2558754796642067,1e-8); // PDF should be similar
+ Assert.assertEquals(MannWhitneyU.calculatePRecursively(sizes.second,sizes.first,11L,false,pm).first,-1.2558754796642067,1e-8); // PDF should be similar
+ Assert.assertEquals(MannWhitneyU.calculatePRecursively(4,5,10L,false,pm).second,0.0952381,1e-5);
+ Assert.assertEquals(MannWhitneyU.calculatePRecursively(4,5,10L,false,pm).first,0.0,1e-14);
+
+ logger.warn("Set 1");
+ Assert.assertEquals((double)mwu2.runOneSidedTest(MannWhitneyU.USet.SET1).second,0.021756021756021756,1e-8);
+ logger.warn("Set 2");
+ Assert.assertEquals((double)mwu2.runOneSidedTest(MannWhitneyU.USet.SET2).second,0.021756021756021756,1e-8);
+
+ MannWhitneyU mwu3 = new MannWhitneyU();
+ for ( int dp : new int[]{0,2,4} ) {
+ mwu3.add(dp,MannWhitneyU.USet.SET1);
+ }
+ for ( int dp : new int[]{1,5,6,7,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34} ) {
+ mwu3.add(dp,MannWhitneyU.USet.SET2);
+ }
+ long u = MannWhitneyU.calculateOneSidedU(mwu3.getObservations(),MannWhitneyU.USet.SET1);
+ //logger.warn(String.format("U is: %d",u));
+ Pair<Integer,Integer> nums = mwu3.getSetSizes();
+ //logger.warn(String.format("Corrected p is: %.4e",MannWhitneyU.calculatePRecursivelyDoNotCheckValuesEvenThoughItIsSlow(nums.first,nums.second,u)));
+ //logger.warn(String.format("Counted sequences: %d",MannWhitneyU.countSequences(nums.first, nums.second, u)));
+ //logger.warn(String.format("Possible sequences: %d", (long) Arithmetic.binomial(nums.first+nums.second,nums.first)));
+ //logger.warn(String.format("Ratio: %.4e",MannWhitneyU.countSequences(nums.first,nums.second,u)/Arithmetic.binomial(nums.first+nums.second,nums.first)));
+ Assert.assertEquals(MannWhitneyU.calculatePRecursivelyDoNotCheckValuesEvenThoughItIsSlow(nums.first, nums.second, u), 3.665689149560116E-4, 1e-14);
+ Assert.assertEquals(MannWhitneyU.calculatePNormalApproximation(nums.first,nums.second,u,false).second,0.0032240865760884696,1e-14);
+ Assert.assertEquals(MannWhitneyU.calculatePUniformApproximation(nums.first,nums.second,u),0.0026195003025784036,1e-14);
+
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MathUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MathUtilsUnitTest.java
new file mode 100644
index 0000000..4e2fd31
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MathUtilsUnitTest.java
@@ -0,0 +1,913 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import cern.jet.random.Normal;
+import org.apache.commons.lang.ArrayUtils;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+/**
+ * Basic unit test for MathUtils
+ */
+public class MathUtilsUnitTest extends BaseTest {
+
+ @BeforeClass
+ public void init() {
+ }
+
+ /**
+ * Tests that we get unique values for the valid (non-null-producing) input space for {@link MathUtils#fastGenerateUniqueHashFromThreeIntegers(int, int, int)}.
+ */
+ @Test
+ public void testGenerateUniqueHashFromThreePositiveIntegers() {
+ logger.warn("Executing testGenerateUniqueHashFromThreePositiveIntegers");
+
+ final Set<Long> observedLongs = new HashSet<>();
+ for (short i = 0; i < Byte.MAX_VALUE; i++) {
+ for (short j = 0; j < Byte.MAX_VALUE; j++) {
+ for (short k = 0; k < Byte.MAX_VALUE; k++) {
+ final Long aLong = MathUtils.fastGenerateUniqueHashFromThreeIntegers(i, j, k);
+ //System.out.println(String.format("%s, %s, %s: %s", i, j, k, aLong));
+ Assert.assertTrue(observedLongs.add(aLong));
+ }
+ }
+ }
+
+ for (short i = Byte.MAX_VALUE; i <= Short.MAX_VALUE && i > 0; i += 128) {
+ for (short j = Byte.MAX_VALUE; j <= Short.MAX_VALUE && j > 0; j += 128) {
+ for (short k = Byte.MAX_VALUE; k <= Short.MAX_VALUE && k > 0; k += 128) {
+ final Long aLong = MathUtils.fastGenerateUniqueHashFromThreeIntegers(i, j, k);
+ // System.out.println(String.format("%s, %s, %s: %s", i, j, k, aLong));
+ Assert.assertTrue(observedLongs.add(aLong));
+ }
+ }
+ }
+ }
+
+ @Test(dataProvider = "log10OneMinusPow10Data")
+ public void testLog10OneMinusPow10(final double x, final double expected) {
+ final double actual = MathUtils.log10OneMinusPow10(x);
+ if (Double.isNaN(expected))
+ Assert.assertTrue(Double.isNaN(actual));
+ else
+ Assert.assertEquals(actual,expected,1E-9);
+ }
+
+ @Test(dataProvider = "log1mexpData")
+ public void testLog1mexp(final double x, final double expected) {
+ final double actual = MathUtils.log1mexp(x);
+ if (Double.isNaN(expected))
+ Assert.assertTrue(Double.isNaN(actual));
+ else
+ Assert.assertEquals(actual,expected,1E-9);
+ }
+
+ @DataProvider(name = "log10OneMinusPow10Data")
+ public Iterator<Object[]> log10OneMinusPow10Data() {
+
+ final double[] inValues = new double[] { Double.NaN, 10, 1, 0, -1, -3, -10, -30, -100, -300, -1000, -3000 };
+ return new Iterator<Object[]>() {
+
+ private int i = 0;
+
+ @Override
+ public boolean hasNext() {
+ return i < inValues.length;
+
+ }
+
+ @Override
+ public Object[] next() {
+ final double input = inValues[i++];
+ final double output = Math.log10( 1 - Math.pow(10,input));
+ return new Object[] { input, output };
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @DataProvider(name = "log1mexpData")
+ public Iterator<Object[]> log1mexpData() {
+
+ final double[] inValues = new double[] { Double.NaN, 10, 1, 0, -1, -3, -10, -30, -100, -300, -1000, -3000 };
+ return new Iterator<Object[]>() {
+
+ private int i = 0;
+
+ @Override
+ public boolean hasNext() {
+ return i < inValues.length;
+
+ }
+
+ @Override
+ public Object[] next() {
+ final double input = inValues[i++];
+ final double output = Math.log( 1 - Math.exp(input));
+ return new Object[] { input, output };
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * Tests that we get the right values from the binomial distribution
+ */
+ @Test
+ public void testBinomialProbability() {
+ logger.warn("Executing testBinomialProbability");
+
+ Assert.assertEquals(MathUtils.binomialProbability(3, 2, 0.5), 0.375, 0.0001);
+ Assert.assertEquals(MathUtils.binomialProbability(100, 10, 0.5), 1.365543e-17, 1e-18);
+ Assert.assertEquals(MathUtils.binomialProbability(217, 73, 0.02), 4.521904e-67, 1e-68);
+ Assert.assertEquals(MathUtils.binomialProbability(300, 100, 0.02), 9.27097e-91, 1e-92);
+ Assert.assertEquals(MathUtils.binomialProbability(300, 150, 0.98), 6.462892e-168, 1e-169);
+ Assert.assertEquals(MathUtils.binomialProbability(300, 120, 0.98), 3.090054e-221, 1e-222);
+ Assert.assertEquals(MathUtils.binomialProbability(300, 112, 0.98), 2.34763e-236, 1e-237);
+ }
+
+ /**
+ * Tests that we get the right values from the binomial distribution
+ */
+ @Test
+ public void testCumulativeBinomialProbability() {
+ logger.warn("Executing testCumulativeBinomialProbability");
+
+ for (int j = 0; j < 2; j++) { // Test memoizing functionality, as well.
+ final int numTrials = 10;
+ for ( int i = 0; i < numTrials; i++ )
+ Assert.assertEquals(MathUtils.binomialCumulativeProbability(numTrials, i, i), MathUtils.binomialProbability(numTrials, i), 1e-10, String.format("k=%d, n=%d", i, numTrials));
+
+ Assert.assertEquals(MathUtils.binomialCumulativeProbability(10, 0, 2), 0.05468750, 1e-7);
+ Assert.assertEquals(MathUtils.binomialCumulativeProbability(10, 0, 5), 0.62304687, 1e-7);
+ Assert.assertEquals(MathUtils.binomialCumulativeProbability(10, 0, 10), 1.0, 1e-7);
+ }
+ }
+
+ /**
+ * Tests that we get the right values from the multinomial distribution
+ */
+ @Test
+ public void testMultinomialProbability() {
+ logger.warn("Executing testMultinomialProbability");
+
+ int[] counts0 = {2, 0, 1};
+ double[] probs0 = {0.33, 0.33, 0.34};
+ Assert.assertEquals(MathUtils.multinomialProbability(counts0, probs0), 0.111078, 1e-6);
+
+ int[] counts1 = {10, 20, 30};
+ double[] probs1 = {0.25, 0.25, 0.50};
+ Assert.assertEquals(MathUtils.multinomialProbability(counts1, probs1), 0.002870301, 1e-9);
+
+ int[] counts2 = {38, 82, 50, 36};
+ double[] probs2 = {0.25, 0.25, 0.25, 0.25};
+ Assert.assertEquals(MathUtils.multinomialProbability(counts2, probs2), 1.88221e-09, 1e-10);
+
+ int[] counts3 = {1, 600, 1};
+ double[] probs3 = {0.33, 0.33, 0.34};
+ Assert.assertEquals(MathUtils.multinomialProbability(counts3, probs3), 5.20988e-285, 1e-286);
+ }
+
+ /**
+ * Tests that the random index selection is working correctly
+ */
+ @Test
+ public void testRandomIndicesWithReplacement() {
+ logger.warn("Executing testRandomIndicesWithReplacement");
+
+ // Check that the size of the list returned is correct
+ Assert.assertTrue(MathUtils.sampleIndicesWithReplacement(5, 0).size() == 0);
+ Assert.assertTrue(MathUtils.sampleIndicesWithReplacement(5, 1).size() == 1);
+ Assert.assertTrue(MathUtils.sampleIndicesWithReplacement(5, 5).size() == 5);
+ Assert.assertTrue(MathUtils.sampleIndicesWithReplacement(5, 1000).size() == 1000);
+
+ // Check that the list contains only the k element range that as asked for - no more, no less
+ List<Integer> Five = new ArrayList<>();
+ Collections.addAll(Five, 0, 1, 2, 3, 4);
+ List<Integer> BigFive = MathUtils.sampleIndicesWithReplacement(5, 10000);
+ Assert.assertTrue(BigFive.containsAll(Five));
+ Assert.assertTrue(Five.containsAll(BigFive));
+ }
+
+ /**
+ * Tests that we get the right values from the multinomial distribution
+ */
+ @Test
+ public void testSliceListByIndices() {
+ logger.warn("Executing testSliceListByIndices");
+
+ // Check that the list contains only the k element range that as asked for - no more, no less but now
+ // use the index list to pull elements from another list using sliceListByIndices
+ List<Integer> Five = new ArrayList<>();
+ Collections.addAll(Five, 0, 1, 2, 3, 4);
+ List<Character> FiveAlpha = new ArrayList<>();
+ Collections.addAll(FiveAlpha, 'a', 'b', 'c', 'd', 'e');
+ List<Integer> BigFive = MathUtils.sampleIndicesWithReplacement(5, 10000);
+ List<Character> BigFiveAlpha = MathUtils.sliceListByIndices(BigFive, FiveAlpha);
+ Assert.assertTrue(BigFiveAlpha.containsAll(FiveAlpha));
+ Assert.assertTrue(FiveAlpha.containsAll(BigFiveAlpha));
+ }
+
+ /**
+ * Tests that we correctly compute mean and standard deviation from a stream of numbers
+ */
+ @Test
+ public void testRunningAverage() {
+ logger.warn("Executing testRunningAverage");
+
+ int[] numbers = {1, 2, 4, 5, 3, 128, 25678, -24};
+ MathUtils.RunningAverage r = new MathUtils.RunningAverage();
+
+ for (final double b : numbers)
+ r.add(b);
+
+ Assert.assertEquals((long) numbers.length, r.observationCount());
+ Assert.assertTrue(r.mean() - 3224.625 < 2e-10);
+ Assert.assertTrue(r.stddev() - 9072.6515881128 < 2e-10);
+ }
+
+ @Test
+ public void testLog10Gamma() {
+ logger.warn("Executing testLog10Gamma");
+
+ Assert.assertEquals(MathUtils.log10Gamma(4.0), 0.7781513, 1e-6);
+ Assert.assertEquals(MathUtils.log10Gamma(10), 5.559763, 1e-6);
+ Assert.assertEquals(MathUtils.log10Gamma(10654), 38280.53, 1e-2);
+ }
+
+ @Test
+ public void testLog10BinomialCoefficient() {
+ logger.warn("Executing testLog10BinomialCoefficient");
+ // note that we can test the binomial coefficient calculation indirectly via Newton's identity
+ // (1+z)^m = sum (m choose k)z^k
+ double[] z_vals = new double[]{0.999,0.9,0.8,0.5,0.2,0.01,0.0001};
+ int[] exponent = new int[]{5,15,25,50,100};
+ for ( double z : z_vals ) {
+ double logz = Math.log10(z);
+ for ( int exp : exponent ) {
+ double expected_log = exp*Math.log10(1+z);
+ double[] newtonArray_log = new double[1+exp];
+ for ( int k = 0 ; k <= exp; k++ ) {
+ newtonArray_log[k] = MathUtils.log10BinomialCoefficient(exp,k)+k*logz;
+ }
+ Assert.assertEquals(MathUtils.log10sumLog10(newtonArray_log),expected_log,1e-6);
+ }
+ }
+
+ Assert.assertEquals(MathUtils.log10BinomialCoefficient(4, 2), 0.7781513, 1e-6);
+ Assert.assertEquals(MathUtils.log10BinomialCoefficient(10, 3), 2.079181, 1e-6);
+ Assert.assertEquals(MathUtils.log10BinomialCoefficient(103928, 119), 400.2156, 1e-4);
+ }
+
+ @Test
+ public void testFactorial() {
+ logger.warn("Executing testFactorial");
+ Assert.assertEquals((int) MathUtils.factorial(4), 24);
+ Assert.assertEquals((int) MathUtils.factorial(10), 3628800);
+ Assert.assertEquals((int) MathUtils.factorial(12), 479001600);
+ }
+
+ @Test
+ public void testLog10Factorial() {
+ logger.warn("Executing testLog10Factorial");
+ Assert.assertEquals(MathUtils.log10Factorial(4), 1.380211, 1e-6);
+ Assert.assertEquals(MathUtils.log10Factorial(10), 6.559763, 1e-6);
+ Assert.assertEquals(MathUtils.log10Factorial(12), 8.680337, 1e-6);
+ Assert.assertEquals(MathUtils.log10Factorial(200), 374.8969, 1e-3);
+ Assert.assertEquals(MathUtils.log10Factorial(12342), 45138.26, 1e-1);
+ double log10factorial_small = 0;
+ double log10factorial_middle = 374.8969;
+ double log10factorial_large = 45138.26;
+ int small_start = 1;
+ int med_start = 200;
+ int large_start = 12342;
+ for ( int i = 1; i < 1000; i++ ) {
+ log10factorial_small += Math.log10(i+small_start);
+ log10factorial_middle += Math.log10(i+med_start);
+ log10factorial_large += Math.log10(i+large_start);
+ Assert.assertEquals(MathUtils.log10Factorial(small_start+i),log10factorial_small,1e-6);
+ Assert.assertEquals(MathUtils.log10Factorial(med_start+i),log10factorial_middle,1e-3);
+ Assert.assertEquals(MathUtils.log10Factorial(large_start+i),log10factorial_large,1e-1);
+ }
+ }
+
+ @Test
+ public void testApproximateLog10SumLog10() {
+
+ final double requiredPrecision = 1E-4;
+
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {0.0}), 0.0, requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-5.15}), -5.15, requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {130.0}), 130.0, requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-0.145}), -0.145, requiredPrecision);
+
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(0.0, 0.0), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-1.0, 0.0), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(0.0, -1.0), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, -1.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-2.2, -3.5), Math.log10(Math.pow(10.0, -2.2) + Math.pow(10.0, -3.5)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-1.0, -7.1), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, -7.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(5.0, 6.2), Math.log10(Math.pow(10.0, 5.0) + Math.pow(10.0, 6.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(38.1, 16.2), Math.log10(Math.pow(10.0, 38.1) + Math.pow(10.0, 16.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-38.1, 6.2), Math.log10(Math.pow(10.0, -38.1) + Math.pow(10.0, 6.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-19.1, -37.1), Math.log10(Math.pow(10.0, -19.1) + Math.pow(10.0, -37.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-29.1, -27.6), Math.log10(Math.pow(10.0, -29.1) + Math.pow(10.0, -27.6)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-0.12345, -0.23456), Math.log10(Math.pow(10.0, -0.12345) + Math.pow(10.0, -0.23456)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-15.7654, -17.0101), Math.log10(Math.pow(10.0, -15.7654) + Math.pow(10.0, -17.0101)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-0.12345, Double.NEGATIVE_INFINITY), -0.12345, requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-15.7654, Double.NEGATIVE_INFINITY), -15.7654, requiredPrecision);
+
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {0.0, 0.0}), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-1.0, 0.0}), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {0.0, -1.0}), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, -1.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-2.2, -3.5}), Math.log10(Math.pow(10.0, -2.2) + Math.pow(10.0, -3.5)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-1.0, -7.1}), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, -7.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {5.0, 6.2}), Math.log10(Math.pow(10.0, 5.0) + Math.pow(10.0, 6.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {38.1, 16.2}), Math.log10(Math.pow(10.0, 38.1) + Math.pow(10.0, 16.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-38.1, 6.2}), Math.log10(Math.pow(10.0, -38.1) + Math.pow(10.0, 6.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-19.1, -37.1}), Math.log10(Math.pow(10.0, -19.1) + Math.pow(10.0, -37.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-29.1, -27.6}), Math.log10(Math.pow(10.0, -29.1) + Math.pow(10.0, -27.6)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-0.12345, -0.23456}), Math.log10(Math.pow(10.0, -0.12345) + Math.pow(10.0, -0.23456)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-15.7654, -17.0101}), Math.log10(Math.pow(10.0, -15.7654) + Math.pow(10.0, -17.0101)), requiredPrecision);
+
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {0.0, 0.0, 0.0}), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-1.0, 0.0, 0.0}), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {0.0, -1.0, -2.5}), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, -1.0) + Math.pow(10.0, -2.5)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-2.2, -3.5, -1.1}), Math.log10(Math.pow(10.0, -2.2) + Math.pow(10.0, -3.5) + Math.pow(10.0, -1.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-1.0, -7.1, 0.5}), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, -7.1) + Math.pow(10.0, 0.5)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {5.0, 6.2, 1.3}), Math.log10(Math.pow(10.0, 5.0) + Math.pow(10.0, 6.2) + Math.pow(10.0, 1.3)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {38.1, 16.2, 18.1}), Math.log10(Math.pow(10.0, 38.1) + Math.pow(10.0, 16.2) + Math.pow(10.0, 18.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-38.1, 6.2, 26.6}), Math.log10(Math.pow(10.0, -38.1) + Math.pow(10.0, 6.2) + Math.pow(10.0, 26.6)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-19.1, -37.1, -45.1}), Math.log10(Math.pow(10.0, -19.1) + Math.pow(10.0, -37.1) + Math.pow(10.0, -45.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-29.1, -27.6, -26.2}), Math.log10(Math.pow(10.0, -29.1) + Math.pow(10.0, -27.6) + Math.pow(10.0, -26.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-0.12345, -0.23456, -0.34567}), Math.log10(Math.pow(10.0, -0.12345) + Math.pow(10.0, -0.23456) + Math.pow(10.0, -0.34567)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(new double[] {-15.7654, -17.0101, -17.9341}), Math.log10(Math.pow(10.0, -15.7654) + Math.pow(10.0, -17.0101) + Math.pow(10.0, -17.9341)), requiredPrecision);
+
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(0.0, 0.0, 0.0), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-1.0, 0.0, 0.0), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(0.0, -1.0, -2.5), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, -1.0) + Math.pow(10.0, -2.5)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-2.2, -3.5, -1.1), Math.log10(Math.pow(10.0, -2.2) + Math.pow(10.0, -3.5) + Math.pow(10.0, -1.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-1.0, -7.1, 0.5), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, -7.1) + Math.pow(10.0, 0.5)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(5.0, 6.2, 1.3), Math.log10(Math.pow(10.0, 5.0) + Math.pow(10.0, 6.2) + Math.pow(10.0, 1.3)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(38.1, 16.2, 18.1), Math.log10(Math.pow(10.0, 38.1) + Math.pow(10.0, 16.2) + Math.pow(10.0, 18.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-38.1, 6.2, 26.6), Math.log10(Math.pow(10.0, -38.1) + Math.pow(10.0, 6.2) + Math.pow(10.0, 26.6)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-19.1, -37.1, -45.1), Math.log10(Math.pow(10.0, -19.1) + Math.pow(10.0, -37.1) + Math.pow(10.0, -45.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-29.1, -27.6, -26.2), Math.log10(Math.pow(10.0, -29.1) + Math.pow(10.0, -27.6) + Math.pow(10.0, -26.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-0.12345, -0.23456, -0.34567), Math.log10(Math.pow(10.0, -0.12345) + Math.pow(10.0, -0.23456) + Math.pow(10.0, -0.34567)), requiredPrecision);
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(-15.7654, -17.0101, -17.9341), Math.log10(Math.pow(10.0, -15.7654) + Math.pow(10.0, -17.0101) + Math.pow(10.0, -17.9341)), requiredPrecision);
+
+ // magnitude of the sum doesn't matter, so we can combinatorially test this via partitions of unity
+ double[] mult_partitionFactor = new double[]{0.999,0.98,0.95,0.90,0.8,0.5,0.3,0.1,0.05,0.001};
+ int[] n_partitions = new int[] {2,4,8,16,32,64,128,256,512,1028};
+ for ( double alpha : mult_partitionFactor ) {
+ double log_alpha = Math.log10(alpha);
+ double log_oneMinusAlpha = Math.log10(1-alpha);
+ for ( int npart : n_partitions ) {
+ double[] multiplicative = new double[npart];
+ double[] equal = new double[npart];
+ double remaining_log = 0.0; // realspace = 1
+ for ( int i = 0 ; i < npart-1; i++ ) {
+ equal[i] = -Math.log10(npart);
+ double piece = remaining_log + log_alpha; // take a*remaining, leaving remaining-a*remaining = (1-a)*remaining
+ multiplicative[i] = piece;
+ remaining_log = remaining_log + log_oneMinusAlpha;
+ }
+ equal[npart-1] = -Math.log10(npart);
+ multiplicative[npart-1] = remaining_log;
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(equal),0.0,requiredPrecision,String.format("Did not sum to one: k=%d equal partitions.",npart));
+ Assert.assertEquals(MathUtils.approximateLog10SumLog10(multiplicative),0.0,requiredPrecision, String.format("Did not sum to one: k=%d multiplicative partitions with alpha=%f",npart,alpha));
+ }
+ }
+ }
+
+ @Test
+ public void testLog10sumLog10() {
+ final double requiredPrecision = 1E-14;
+
+ final double log3 = 0.477121254719662;
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[]{0.0, 0.0, 0.0}), log3, requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {0.0, 0.0, 0.0}, 0), log3, requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[]{0.0, 0.0, 0.0}, 0, 3), log3, requiredPrecision);
+
+ final double log2 = 0.301029995663981;
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {0.0, 0.0, 0.0}, 0, 2), log2, requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {0.0, 0.0, 0.0}, 0, 1), 0.0, requiredPrecision);
+
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {0.0}), 0.0, requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-5.15}), -5.15, requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {130.0}), 130.0, requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-0.145}), -0.145, requiredPrecision);
+
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {0.0, 0.0}), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-1.0, 0.0}), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {0.0, -1.0}), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, -1.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-2.2, -3.5}), Math.log10(Math.pow(10.0, -2.2) + Math.pow(10.0, -3.5)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-1.0, -7.1}), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, -7.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {5.0, 6.2}), Math.log10(Math.pow(10.0, 5.0) + Math.pow(10.0, 6.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {38.1, 16.2}), Math.log10(Math.pow(10.0, 38.1) + Math.pow(10.0, 16.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-38.1, 6.2}), Math.log10(Math.pow(10.0, -38.1) + Math.pow(10.0, 6.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-19.1, -37.1}), Math.log10(Math.pow(10.0, -19.1) + Math.pow(10.0, -37.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-29.1, -27.6}), Math.log10(Math.pow(10.0, -29.1) + Math.pow(10.0, -27.6)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-0.12345, -0.23456}), Math.log10(Math.pow(10.0, -0.12345) + Math.pow(10.0, -0.23456)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-15.7654, -17.0101}), Math.log10(Math.pow(10.0, -15.7654) + Math.pow(10.0, -17.0101)), requiredPrecision);
+
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {0.0, 0.0, 0.0}), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-1.0, 0.0, 0.0}), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, 0.0) + Math.pow(10.0, 0.0)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {0.0, -1.0, -2.5}), Math.log10(Math.pow(10.0, 0.0) + Math.pow(10.0, -1.0) + Math.pow(10.0, -2.5)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-2.2, -3.5, -1.1}), Math.log10(Math.pow(10.0, -2.2) + Math.pow(10.0, -3.5) + Math.pow(10.0, -1.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-1.0, -7.1, 0.5}), Math.log10(Math.pow(10.0, -1.0) + Math.pow(10.0, -7.1) + Math.pow(10.0, 0.5)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {5.0, 6.2, 1.3}), Math.log10(Math.pow(10.0, 5.0) + Math.pow(10.0, 6.2) + Math.pow(10.0, 1.3)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {38.1, 16.2, 18.1}), Math.log10(Math.pow(10.0, 38.1) + Math.pow(10.0, 16.2) + Math.pow(10.0, 18.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-38.1, 6.2, 26.6}), Math.log10(Math.pow(10.0, -38.1) + Math.pow(10.0, 6.2) + Math.pow(10.0, 26.6)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-19.1, -37.1, -45.1}), Math.log10(Math.pow(10.0, -19.1) + Math.pow(10.0, -37.1) + Math.pow(10.0, -45.1)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-29.1, -27.6, -26.2}), Math.log10(Math.pow(10.0, -29.1) + Math.pow(10.0, -27.6) + Math.pow(10.0, -26.2)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-0.12345, -0.23456, -0.34567}), Math.log10(Math.pow(10.0, -0.12345) + Math.pow(10.0, -0.23456) + Math.pow(10.0, -0.34567)), requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(new double[] {-15.7654, -17.0101, -17.9341}), Math.log10(Math.pow(10.0, -15.7654) + Math.pow(10.0, -17.0101) + Math.pow(10.0, -17.9341)), requiredPrecision);
+
+ // magnitude of the sum doesn't matter, so we can combinatorially test this via partitions of unity
+ double[] mult_partitionFactor = new double[]{0.999,0.98,0.95,0.90,0.8,0.5,0.3,0.1,0.05,0.001};
+ int[] n_partitions = new int[] {2,4,8,16,32,64,128,256,512,1028};
+ for ( double alpha : mult_partitionFactor ) {
+ double log_alpha = Math.log10(alpha);
+ double log_oneMinusAlpha = Math.log10(1-alpha);
+ for ( int npart : n_partitions ) {
+ double[] multiplicative = new double[npart];
+ double[] equal = new double[npart];
+ double remaining_log = 0.0; // realspace = 1
+ for ( int i = 0 ; i < npart-1; i++ ) {
+ equal[i] = -Math.log10(npart);
+ double piece = remaining_log + log_alpha; // take a*remaining, leaving remaining-a*remaining = (1-a)*remaining
+ multiplicative[i] = piece;
+ remaining_log = remaining_log + log_oneMinusAlpha;
+ }
+ equal[npart-1] = -Math.log10(npart);
+ multiplicative[npart-1] = remaining_log;
+ Assert.assertEquals(MathUtils.log10sumLog10(equal),0.0,requiredPrecision);
+ Assert.assertEquals(MathUtils.log10sumLog10(multiplicative),0.0,requiredPrecision,String.format("Did not sum to one: nPartitions=%d, alpha=%f",npart,alpha));
+ }
+ }
+ }
+
+ @Test
+ public void testLogDotProduct() {
+ Assert.assertEquals(MathUtils.logDotProduct(new double[]{-5.0,-3.0,2.0}, new double[]{6.0,7.0,8.0}),10.0,1e-3);
+ Assert.assertEquals(MathUtils.logDotProduct(new double[]{-5.0}, new double[]{6.0}),1.0,1e-3);
+ }
+
+ @Test
+ public void testNormalDistribution() {
+ final double requiredPrecision = 1E-10;
+
+ final Normal n = new Normal(0.0, 1.0, null);
+ for( final double mu : new double[]{-5.0, -3.2, -1.5, 0.0, 1.2, 3.0, 5.8977} ) {
+ for( final double sigma : new double[]{1.2, 3.0, 5.8977} ) {
+ for( final double x : new double[]{-5.0, -3.2, -1.5, 0.0, 1.2, 3.0, 5.8977} ) {
+ n.setState(mu, sigma);
+ Assert.assertEquals(n.pdf(x), MathUtils.normalDistribution(mu, sigma, x), requiredPrecision);
+ Assert.assertEquals(Math.log10(n.pdf(x)), MathUtils.normalDistributionLog10(mu, sigma, x), requiredPrecision);
+ }
+ }
+ }
+ }
+
+ @DataProvider(name = "ArrayMinData")
+ public Object[][] makeArrayMinData() {
+ List<Object[]> tests = new ArrayList<>();
+
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ tests.add(new Object[]{Arrays.asList(10), 10});
+ tests.add(new Object[]{Arrays.asList(-10), -10});
+
+ for ( final List<Integer> values : Utils.makePermutations(Arrays.asList(1,2,3), 3, false) ) {
+ tests.add(new Object[]{values, 1});
+ }
+
+ for ( final List<Integer> values : Utils.makePermutations(Arrays.asList(1,2,-3), 3, false) ) {
+ tests.add(new Object[]{values, -3});
+ }
+
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "ArrayMinData")
+ public void testArrayMinList(final List<Integer> values, final int expected) {
+ final int actual = MathUtils.arrayMin(values);
+ Assert.assertEquals(actual, expected, "Failed with " + values);
+ }
+
+ @Test(dataProvider = "ArrayMinData")
+ public void testArrayMinIntArray(final List<Integer> values, final int expected) {
+ final int[] asArray = ArrayUtils.toPrimitive(values.toArray(new Integer[values.size()]));
+ final int actual = MathUtils.arrayMin(asArray);
+ Assert.assertEquals(actual, expected, "Failed with " + values);
+ }
+
+ @Test(dataProvider = "ArrayMinData")
+ public void testArrayMinByteArray(final List<Integer> values, final int expected) {
+ final byte[] asArray = new byte[values.size()];
+ for ( int i = 0; i < values.size(); i++ ) asArray[i] = (byte)(values.get(i) & 0xFF);
+ final byte actual = MathUtils.arrayMin(asArray);
+ Assert.assertEquals(actual, (byte)(expected & 0xFF), "Failed with " + values);
+ }
+
+ @Test(dataProvider = "ArrayMinData")
+ public void testArrayMinDoubleArray(final List<Integer> values, final int expected) {
+ final double[] asArray = new double[values.size()];
+ for ( int i = 0; i < values.size(); i++ ) asArray[i] = (double)(values.get(i));
+ final double actual = MathUtils.arrayMin(asArray);
+ Assert.assertEquals(actual, (double)expected, "Failed with " + values);
+ }
+
+ @DataProvider(name = "MedianData")
+ public Object[][] makeMedianData() {
+ final List<Object[]> tests = new ArrayList<>();
+
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ tests.add(new Object[]{Arrays.asList(10), 10});
+ tests.add(new Object[]{Arrays.asList(1, 10), 10});
+
+ for ( final List<Integer> values : Utils.makePermutations(Arrays.asList(1,2,-3), 3, false) ) {
+ tests.add(new Object[]{values, 1});
+ }
+
+ for ( final List<Double> values : Utils.makePermutations(Arrays.asList(1.1,2.1,-3.1), 3, false) ) {
+ tests.add(new Object[]{values, 1.1});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "MedianData")
+ public void testMedian(final List<Comparable> values, final Comparable expected) {
+ final Comparable actual = MathUtils.median(values);
+ Assert.assertEquals(actual, expected, "Failed with " + values);
+ }
+
+
+
+ // man. All this to test dirichlet.
+
+ private double[] unwrap(List<Double> stuff) {
+ double[] unwrapped = new double[stuff.size()];
+ int idx = 0;
+ for ( Double d : stuff ) {
+ unwrapped[idx++] = d == null ? 0.0 : d;
+ }
+
+ return unwrapped;
+ }
+
+ /**
+ * The PartitionGenerator generates all of the partitions of a number n, e.g.
+ * 5 + 0
+ * 4 + 1
+ * 3 + 2
+ * 3 + 1 + 1
+ * 2 + 2 + 1
+ * 2 + 1 + 1 + 1
+ * 1 + 1 + 1 + 1 + 1
+ *
+ * This is used to help enumerate the state space over which the Dirichlet-Multinomial is defined,
+ * to ensure that the distribution function is properly implemented
+ */
+ class PartitionGenerator implements Iterator<List<Integer>> {
+ // generate the partitions of an integer, each partition sorted numerically
+ int n;
+ List<Integer> a;
+
+ int y;
+ int k;
+ int state;
+
+ int x;
+ int l;
+
+ public PartitionGenerator(int n) {
+ this.n = n;
+ this.y = n - 1;
+ this.k = 1;
+ this.a = new ArrayList<>();
+ for ( int i = 0; i < n; i++ ) {
+ this.a.add(i);
+ }
+ this.state = 0;
+ }
+
+ public void remove() { /* do nothing */ }
+
+ public boolean hasNext() { return ! ( this.k == 0 && state == 0 ); }
+
+ private String dataStr() {
+ return String.format("a = [%s] k = %d y = %d state = %d x = %d l = %d",
+ Utils.join(",",a), k, y, state, x, l);
+ }
+
+ public List<Integer> next() {
+ if ( this.state == 0 ) {
+ this.x = a.get(k-1)+1;
+ k -= 1;
+ this.state = 1;
+ }
+
+ if ( this.state == 1 ) {
+ while ( 2 * x <= y ) {
+ this.a.set(k,x);
+ this.y -= (int) x;
+ this.k++;
+ }
+ this.l = 1+this.k;
+ this.state = 2;
+ }
+
+ if ( this.state == 2 ) {
+ if ( x <= y ) {
+ this.a.set(k,x);
+ this.a.set(l,y);
+ x += 1;
+ y -= 1;
+ return this.a.subList(0, this.k + 2);
+ } else {
+ this.state =3;
+ }
+ }
+
+ if ( this.state == 3 ) {
+ this.a.set(k,x+y);
+ this.y = x + y - 1;
+ this.state = 0;
+ return a.subList(0, k + 1);
+ }
+
+ throw new IllegalStateException("Cannot get here");
+ }
+
+ public String toString() {
+ final StringBuilder buf = new StringBuilder();
+ buf.append("{ ");
+ while ( hasNext() ) {
+ buf.append("[");
+ buf.append(Utils.join(",",next()));
+ buf.append("],");
+ }
+ buf.deleteCharAt(buf.lastIndexOf(","));
+ buf.append(" }");
+ return buf.toString();
+ }
+
+ }
+
+ /**
+ * NextCounts is the enumerator over the state space of the multinomial dirichlet.
+ *
+ * It filters the partition of the total sum to only those with a number of terms
+ * equal to the number of categories.
+ *
+ * It then generates all permutations of that partition.
+ *
+ * In so doing it enumerates over the full state space.
+ */
+ class NextCounts implements Iterator<int[]> {
+
+ private PartitionGenerator partitioner;
+ private int numCategories;
+ private int[] next;
+
+ public NextCounts(int numCategories, int totalCounts) {
+ partitioner = new PartitionGenerator(totalCounts);
+ this.numCategories = numCategories;
+ next = nextFromPartitioner();
+ }
+
+ public void remove() { /* do nothing */ }
+
+ public boolean hasNext() { return next != null; }
+
+ public int[] next() {
+ int[] toReturn = clone(next);
+ next = nextPermutation();
+ if ( next == null ) {
+ next = nextFromPartitioner();
+ }
+
+ return toReturn;
+ }
+
+ private int[] clone(int[] arr) {
+ return Arrays.copyOf(arr, arr.length);
+ }
+
+ private int[] nextFromPartitioner() {
+ if ( partitioner.hasNext() ) {
+ List<Integer> nxt = partitioner.next();
+ while ( partitioner.hasNext() && nxt.size() > numCategories ) {
+ nxt = partitioner.next();
+ }
+
+ if ( nxt.size() > numCategories ) {
+ return null;
+ } else {
+ int[] buf = new int[numCategories];
+ for ( int idx = 0; idx < nxt.size(); idx++ ) {
+ buf[idx] = nxt.get(idx);
+ }
+ Arrays.sort(buf);
+ return buf;
+ }
+ }
+
+ return null;
+ }
+
+ public int[] nextPermutation() {
+ return MathUtilsUnitTest.nextPermutation(next);
+ }
+
+ }
+
+ public static int[] nextPermutation(int[] next) {
+ // the counts can swap among each other. The int[] is originally in ascending order
+ // this generates the next array in lexicographic order descending
+
+ // locate the last occurrence where next[k] < next[k+1]
+ int gt = -1;
+ for ( int idx = 0; idx < next.length-1; idx++) {
+ if ( next[idx] < next[idx+1] ) {
+ gt = idx;
+ }
+ }
+
+ if ( gt == -1 ) {
+ return null;
+ }
+
+ int largestLessThan = gt+1;
+ for ( int idx = 1 + largestLessThan; idx < next.length; idx++) {
+ if ( next[gt] < next[idx] ) {
+ largestLessThan = idx;
+ }
+ }
+
+ int val = next[gt];
+ next[gt] = next[largestLessThan];
+ next[largestLessThan] = val;
+
+ // reverse the tail of the array
+ int[] newTail = new int[next.length-gt-1];
+ int ctr = 0;
+ for ( int idx = next.length-1; idx > gt; idx-- ) {
+ newTail[ctr++] = next[idx];
+ }
+
+ for ( int idx = 0; idx < newTail.length; idx++) {
+ next[gt+idx+1] = newTail[idx];
+ }
+
+ return next;
+ }
+
+
+ // before testing the dirichlet multinomial, we need to test the
+ // classes used to test the dirichlet multinomial
+
+ @Test
+ public void testPartitioner() {
+ int[] numsToTest = new int[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
+ int[] expectedSizes = new int[]{1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56, 77, 101, 135, 176, 231, 297, 385, 490, 627};
+ for ( int testNum = 0; testNum < numsToTest.length; testNum++ ) {
+ PartitionGenerator gen = new PartitionGenerator(numsToTest[testNum]);
+ int size = 0;
+ while ( gen.hasNext() ) {
+ logger.debug(gen.dataStr());
+ size += 1;
+ gen.next();
+ }
+ Assert.assertEquals(size,expectedSizes[testNum],
+ String.format("Expected %d partitions, observed %s",expectedSizes[testNum],new PartitionGenerator(numsToTest[testNum]).toString()));
+ }
+ }
+
+ @Test
+ public void testNextPermutation() {
+ int[] arr = new int[]{1,2,3,4};
+ int[][] gens = new int[][] {
+ new int[]{1,2,3,4},
+ new int[]{1,2,4,3},
+ new int[]{1,3,2,4},
+ new int[]{1,3,4,2},
+ new int[]{1,4,2,3},
+ new int[]{1,4,3,2},
+ new int[]{2,1,3,4},
+ new int[]{2,1,4,3},
+ new int[]{2,3,1,4},
+ new int[]{2,3,4,1},
+ new int[]{2,4,1,3},
+ new int[]{2,4,3,1},
+ new int[]{3,1,2,4},
+ new int[]{3,1,4,2},
+ new int[]{3,2,1,4},
+ new int[]{3,2,4,1},
+ new int[]{3,4,1,2},
+ new int[]{3,4,2,1},
+ new int[]{4,1,2,3},
+ new int[]{4,1,3,2},
+ new int[]{4,2,1,3},
+ new int[]{4,2,3,1},
+ new int[]{4,3,1,2},
+ new int[]{4,3,2,1} };
+ for ( int gen = 0; gen < gens.length; gen ++ ) {
+ for ( int idx = 0; idx < 3; idx++ ) {
+ Assert.assertEquals(arr[idx],gens[gen][idx],
+ String.format("Error at generation %d, expected %s, observed %s",gen,Arrays.toString(gens[gen]),Arrays.toString(arr)));
+ }
+ arr = nextPermutation(arr);
+ }
+ }
+
+ private double[] addEpsilon(double[] counts) {
+ double[] d = new double[counts.length];
+ for ( int i = 0; i < counts.length; i ++ ) {
+ d[i] = counts[i] + 1e-3;
+ }
+ return d;
+ }
+
+ @Test
+ public void testDirichletMultinomial() {
+ List<double[]> testAlleles = Arrays.asList(
+ new double[]{80,240},
+ new double[]{1,10000},
+ new double[]{0,500},
+ new double[]{5140,20480},
+ new double[]{5000,800,200},
+ new double[]{6,3,1000},
+ new double[]{100,400,300,800},
+ new double[]{8000,100,20,80,2},
+ new double[]{90,20000,400,20,4,1280,720,1}
+ );
+
+ Assert.assertTrue(! Double.isInfinite(MathUtils.log10Gamma(1e-3)) && ! Double.isNaN(MathUtils.log10Gamma(1e-3)));
+
+ int[] numAlleleSampled = new int[]{2,5,10,20,25};
+ for ( double[] alleles : testAlleles ) {
+ for ( int count : numAlleleSampled ) {
+ // test that everything sums to one. Generate all multinomial draws
+ List<Double> likelihoods = new ArrayList<>(100000);
+ NextCounts generator = new NextCounts(alleles.length,count);
+ double maxLog = Double.MIN_VALUE;
+ //List<String> countLog = new ArrayList<String>(200);
+ while ( generator.hasNext() ) {
+ int[] thisCount = generator.next();
+ //countLog.add(Arrays.toString(thisCount));
+ Double likelihood = MathUtils.dirichletMultinomial(addEpsilon(alleles),thisCount);
+ Assert.assertTrue(! Double.isNaN(likelihood) && ! Double.isInfinite(likelihood),
+ String.format("Likelihood for counts %s and nAlleles %d was %s",
+ Arrays.toString(thisCount),alleles.length,Double.toString(likelihood)));
+ if ( likelihood > maxLog )
+ maxLog = likelihood;
+ likelihoods.add(likelihood);
+ }
+ //System.out.printf("%d likelihoods and max is (probability) %e\n",likelihoods.size(),Math.pow(10,maxLog));
+ Assert.assertEquals(MathUtils.sumLog10(unwrap(likelihoods)),1.0,1e-7,
+ String.format("Counts %d and alleles %d have nLikelihoods %d. \n Counts: %s",
+ count,alleles.length,likelihoods.size(), "NODEBUG"/*,countLog*/));
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MedianUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MedianUnitTest.java
new file mode 100644
index 0000000..21f3d89
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/MedianUnitTest.java
@@ -0,0 +1,115 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+
+// the imports for unit testing.
+
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+
+public class MedianUnitTest extends BaseTest {
+
+ // --------------------------------------------------------------------------------
+ //
+ // Provider
+ //
+ // --------------------------------------------------------------------------------
+
+ private class MedianTestProvider extends TestDataProvider {
+ final List<Integer> values = new ArrayList<Integer>();
+ final int cap;
+ final Integer expected;
+
+ public MedianTestProvider(int expected, int cap, Integer ... values) {
+ super(MedianTestProvider.class);
+ this.expected = expected;
+ this.cap = cap;
+ this.values.addAll(Arrays.asList(values));
+ this.name = String.format("values=%s expected=%d cap=%d", this.values, expected, cap);
+ }
+ }
+
+ @DataProvider(name = "MedianTestProvider")
+ public Object[][] makeMedianTestProvider() {
+ new MedianTestProvider(1, 1000, 0, 1, 2);
+ new MedianTestProvider(1, 1000, 1, 0, 1, 2);
+ new MedianTestProvider(1, 1000, 0, 1, 2, 3);
+ new MedianTestProvider(2, 1000, 0, 1, 2, 3, 4);
+ new MedianTestProvider(2, 1000, 4, 1, 2, 3, 0);
+ new MedianTestProvider(1, 1000, 1);
+ new MedianTestProvider(2, 1000, 2);
+ new MedianTestProvider(1, 1000, 1, 2);
+
+ new MedianTestProvider(1, 3, 1);
+ new MedianTestProvider(1, 3, 1, 2);
+ new MedianTestProvider(2, 3, 1, 2, 3);
+ new MedianTestProvider(2, 3, 1, 2, 3, 4);
+ new MedianTestProvider(2, 3, 1, 2, 3, 4, 5);
+
+ new MedianTestProvider(1, 3, 1);
+ new MedianTestProvider(1, 3, 1, 2);
+ new MedianTestProvider(2, 3, 3, 2, 1);
+ new MedianTestProvider(3, 3, 4, 3, 2, 1);
+ new MedianTestProvider(4, 3, 5, 4, 3, 2, 1);
+
+ return MedianTestProvider.getTests(MedianTestProvider.class);
+ }
+
+ @Test(dataProvider = "MedianTestProvider")
+ public void testBasicLikelihoods(MedianTestProvider cfg) {
+ final Median<Integer> median = new Median<Integer>(cfg.cap);
+
+ int nAdded = 0;
+ for ( final int value : cfg.values )
+ if ( median.add(value) )
+ nAdded++;
+
+ Assert.assertEquals(nAdded, median.size());
+
+ Assert.assertEquals(cfg.values.isEmpty(), median.isEmpty());
+ Assert.assertEquals(cfg.values.size() >= cfg.cap, median.isFull());
+ Assert.assertEquals(median.getMedian(), cfg.expected, cfg.toString());
+ }
+
+ @Test(expectedExceptions = IllegalStateException.class)
+ public void testEmptyMedian() {
+ final Median<Integer> median = new Median<Integer>();
+ Assert.assertTrue(median.isEmpty());
+ final Integer d = 100;
+ Assert.assertEquals(median.getMedian(d), d);
+ median.getMedian();
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/NGSPlatformUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/NGSPlatformUnitTest.java
new file mode 100644
index 0000000..b247f59
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/NGSPlatformUnitTest.java
@@ -0,0 +1,167 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+
+// the imports for unit testing.
+
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class NGSPlatformUnitTest extends BaseTest {
+ // example genome loc parser for this test, can be deleted if you don't use the reference
+ private GenomeLocParser genomeLocParser;
+
+ // example fasta index file, can be deleted if you don't use the reference
+ private IndexedFastaSequenceFile seq;
+
+ @BeforeClass
+ public void setup() throws FileNotFoundException {
+ // sequence
+ seq = new CachingIndexedFastaSequenceFile(new File(b37KGReference));
+ genomeLocParser = new GenomeLocParser(seq);
+ }
+
+ @DataProvider(name = "TestPrimary")
+ public Object[][] makeTestPrimary() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final NGSPlatform pl : NGSPlatform.values() ) {
+ tests.add(new Object[]{pl, pl.BAM_PL_NAMES[0]});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "TestPrimary")
+ public void testPrimary(final NGSPlatform pl, final String expectedPrimaryName) {
+ Assert.assertEquals(pl.getDefaultPlatform(), expectedPrimaryName, "Failed primary test for " + pl);
+ }
+
+ // make sure common names in BAMs are found
+ @DataProvider(name = "TestMappings")
+ public Object[][] makeTestMappings() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final Map<String, NGSPlatform> expected = new HashMap<String, NGSPlatform>();
+ // VALID VALUES ACCORDING TO SAM SPEC: https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CC8QFjAA&url=http%3A%2F%2Fsamtools.sourceforge.net%2FSAM1.pdf&ei=Dm8WUbXAEsi10QHYqoDwDQ&usg=AFQjCNFkMtvEi6LeiKgpxQGtHTlqWKw2yw&bvm=bv.42080656,d.dmQ
+ expected.put("CAPILLARY", NGSPlatform.CAPILLARY);
+ expected.put("LS454", NGSPlatform.LS454);
+ expected.put("ILLUMINA", NGSPlatform.ILLUMINA);
+ expected.put("SOLID", NGSPlatform.SOLID);
+ expected.put("HELICOS", NGSPlatform.HELICOS);
+ expected.put("IONTORRENT", NGSPlatform.ION_TORRENT);
+ expected.put("PACBIO", NGSPlatform.PACBIO);
+ // other commonly seen values out in the wild
+ expected.put("SLX", NGSPlatform.ILLUMINA);
+ expected.put("SOLEXA", NGSPlatform.ILLUMINA);
+ expected.put("454", NGSPlatform.LS454);
+ expected.put("COMPLETE", NGSPlatform.COMPLETE_GENOMICS);
+ // unknown platforms should map to unknown
+ expected.put("MARKS_GENOMICS_TECH", NGSPlatform.UNKNOWN);
+ expected.put("RANDOM_PL_VALUE", NGSPlatform.UNKNOWN);
+ // critical -- a null platform maps to unknown
+ expected.put(null, NGSPlatform.UNKNOWN);
+
+ for ( final Map.Entry<String,NGSPlatform> one : expected.entrySet() ) {
+ tests.add(new Object[]{one.getKey(), one.getValue()});
+
+ if ( one.getKey() != null ) {
+ // make sure we're case insensitive
+ tests.add(new Object[]{one.getKey().toLowerCase(), one.getValue()});
+ tests.add(new Object[]{one.getKey().toUpperCase(), one.getValue()});
+
+ // make sure appending GENOMICS works (required for COMPLETE mapping
+ tests.add(new Object[]{one.getKey() + " GENOMICS", one.getValue()});
+ // make sure that random junk works correctly
+ tests.add(new Object[]{one.getKey() + " asdfa", one.getValue()});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "TestMappings")
+ public void testMappings(final String plField, final NGSPlatform expected) {
+ Assert.assertEquals(NGSPlatform.fromReadGroupPL(plField), expected, "Failed primary test for " + plField + " mapping to " + expected);
+ }
+
+ @Test(dataProvider = "TestMappings")
+ public void testKnown(final String plField, final NGSPlatform expected) {
+ Assert.assertEquals(NGSPlatform.isKnown(plField), expected != NGSPlatform.UNKNOWN, "Failed isKnown test for " + plField + " mapping to " + expected);
+ }
+
+ /**
+ * A unit test that creates an artificial read for testing some code that uses reads
+ */
+ @Test(dataProvider = "TestMappings")
+ public void testPLFromReadWithRG(final String plField, final NGSPlatform expected) {
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(seq.getSequenceDictionary());
+ final String rgID = "ID";
+ final SAMReadGroupRecord rg = new SAMReadGroupRecord(rgID);
+ if ( plField != null )
+ rg.setPlatform(plField);
+ header.addReadGroup(rg);
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, 10);
+ read.setAttribute("RG", rgID);
+ Assert.assertEquals(NGSPlatform.fromRead(read), expected);
+ }
+
+ @Test()
+ public void testPLFromReadWithRGButNoPL() {
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(seq.getSequenceDictionary());
+ final String rgID = "ID";
+ final SAMReadGroupRecord rg = new SAMReadGroupRecord(rgID);
+ header.addReadGroup(rg);
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, 10);
+ read.setAttribute("RG", rgID);
+ Assert.assertEquals(NGSPlatform.fromRead(read), NGSPlatform.UNKNOWN);
+ }
+
+ @Test
+ public void testReadWithoutRG() {
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(seq.getSequenceDictionary());
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, 10);
+ Assert.assertEquals(NGSPlatform.fromRead(read), NGSPlatform.UNKNOWN);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/PathUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/PathUtilsUnitTest.java
new file mode 100644
index 0000000..00cc0dc
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/PathUtilsUnitTest.java
@@ -0,0 +1,65 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+import java.io.File;
+
+public class PathUtilsUnitTest extends BaseTest {
+ @BeforeClass
+ public void init() { }
+
+ /**
+ * Tests that we can successfully refresh a volume
+ */
+ @Test
+ public void testRefreshVolume() {
+ logger.warn("Executing testRefreshVolume");
+
+ Assert.assertTrue(successfullyRefreshedVolume(System.getProperty("java.io.tmpdir")));
+ Assert.assertFalse(successfullyRefreshedVolume("/a/made/up/file.txt"));
+ }
+
+ private boolean successfullyRefreshedVolume(String filename) {
+ boolean result = true;
+
+ try {
+ PathUtils.refreshVolume(new File(filename));
+ } catch (ReviewedGATKException e) {
+ result = false;
+ }
+
+ logger.warn(filename + " is accessible : " + result);
+
+ return result;
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/QualityUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/QualityUtilsUnitTest.java
new file mode 100644
index 0000000..86b436b
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/QualityUtilsUnitTest.java
@@ -0,0 +1,189 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: rpoplin
+ * Date: 3/21/12
+ */
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Basic unit test for QualityUtils class
+ */
+public class QualityUtilsUnitTest extends BaseTest {
+ final private static double TOLERANCE = 1e-9;
+
+ @BeforeClass
+ public void init() {
+ }
+
+ @DataProvider(name = "QualTest")
+ public Object[][] makeMyDataProvider() {
+ final List<Object[]> tests = new ArrayList<>();
+
+ for ( int qual = 0; qual < 255; qual++ ) {
+ tests.add(new Object[]{(byte)(qual & 0xFF), Math.pow(10.0, ((double)qual)/-10.0)});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ /**
+ * Example testng test using MyDataProvider
+ */
+ @Test(dataProvider = "QualTest")
+ public void testMyData(final byte qual, final double errorRate) {
+ final double trueRate = 1 - errorRate;
+
+ final double actualErrorRate = QualityUtils.qualToErrorProb(qual);
+ Assert.assertEquals(actualErrorRate, errorRate, TOLERANCE);
+ final double actualTrueRate = QualityUtils.qualToProb(qual);
+ Assert.assertEquals(actualTrueRate, trueRate, TOLERANCE);
+
+ // log10 tests
+ final double actualLog10ErrorRate = QualityUtils.qualToErrorProbLog10(qual);
+ Assert.assertEquals(actualLog10ErrorRate, Math.log10(errorRate), TOLERANCE);
+ final double actualLog10TrueRate = QualityUtils.qualToProbLog10(qual);
+ Assert.assertEquals(actualLog10TrueRate, Math.log10(trueRate), TOLERANCE);
+
+ // test that we can convert our error rates to quals, accounting for boundaries
+ final int expectedQual = Math.max(Math.min(qual & 0xFF, QualityUtils.MAX_SAM_QUAL_SCORE), 1);
+ final byte actualQual = QualityUtils.trueProbToQual(trueRate);
+ Assert.assertEquals(actualQual, expectedQual & 0xFF);
+ final byte actualQualFromErrorRate = QualityUtils.errorProbToQual(errorRate);
+ Assert.assertEquals(actualQualFromErrorRate, expectedQual & 0xFF);
+
+ for ( int maxQual = 10; maxQual < QualityUtils.MAX_SAM_QUAL_SCORE; maxQual++ ) {
+ final byte maxAsByte = (byte)(maxQual & 0xFF);
+ final byte expectedQual2 = (byte)(Math.max(Math.min(qual & 0xFF, maxQual), 1) & 0xFF);
+ final byte actualQual2 = QualityUtils.trueProbToQual(trueRate, maxAsByte);
+ Assert.assertEquals(actualQual2, expectedQual2, "Failed with max " + maxQual);
+ final byte actualQualFromErrorRate2 = QualityUtils.errorProbToQual(errorRate, maxAsByte);
+ Assert.assertEquals(actualQualFromErrorRate2, expectedQual2, "Failed with max " + maxQual);
+
+ // test the integer routines
+ final byte actualQualInt2 = QualityUtils.trueProbToQual(trueRate, maxQual);
+ Assert.assertEquals(actualQualInt2, expectedQual2, "Failed with max " + maxQual);
+ final byte actualQualFromErrorRateInt2 = QualityUtils.errorProbToQual(errorRate, maxQual);
+ Assert.assertEquals(actualQualFromErrorRateInt2, expectedQual2, "Failed with max " + maxQual);
+ }
+ }
+
+ @Test
+ public void testTrueProbWithMinDouble() {
+ final byte actual = QualityUtils.trueProbToQual(Double.MIN_VALUE);
+ Assert.assertEquals(actual, 1, "Failed to convert true prob of min double to 1 qual");
+ }
+
+ @Test
+ public void testTrueProbWithVerySmallValue() {
+ final byte actual = QualityUtils.trueProbToQual(1.7857786272673852E-19);
+ Assert.assertEquals(actual, 1, "Failed to convert true prob of very small value 1.7857786272673852E-19 to 1 qual");
+ }
+
+ @Test
+ public void testQualCaches() {
+ Assert.assertEquals(QualityUtils.qualToErrorProb((byte) 20), 0.01, 1e-6);
+ Assert.assertEquals(QualityUtils.qualToErrorProbLog10((byte) 20), -2.0, 1e-6);
+ Assert.assertEquals(QualityUtils.qualToProb((byte) 20), 0.99, 1e-6);
+ Assert.assertEquals(QualityUtils.qualToProbLog10((byte) 20), -0.0043648054, 1e-6);
+
+ Assert.assertEquals(QualityUtils.qualToErrorProb((byte) 30), 0.001, 1e-6);
+ Assert.assertEquals(QualityUtils.qualToErrorProbLog10((byte) 30), -3.0, 1e-6);
+ Assert.assertEquals(QualityUtils.qualToProb((byte) 30), 0.999, 1e-6);
+ Assert.assertEquals(QualityUtils.qualToProbLog10((byte) 30), -0.000434511774, 1e-6);
+
+ Assert.assertEquals(QualityUtils.qualToErrorProb((byte) 40), 0.0001, 1e-6);
+ Assert.assertEquals(QualityUtils.qualToErrorProbLog10((byte) 40), -4.0, 1e-6);
+ Assert.assertEquals(QualityUtils.qualToProb((byte) 40), 0.9999, 1e-6);
+ Assert.assertEquals(QualityUtils.qualToProbLog10((byte) 40), -4.34316198e-5, 1e-6);
+ }
+
+ @Test()
+ public void testBoundingDefault() {
+ for ( int qual = 0; qual < 1000; qual++ ) {
+ final byte expected = (byte)Math.max(Math.min(qual, QualityUtils.MAX_SAM_QUAL_SCORE), 1);
+ Assert.assertEquals(QualityUtils.boundQual(qual), expected);
+ }
+ }
+
+ @Test()
+ public void testBoundingWithMax() {
+ for ( int max = 10; max < 255; max += 50 ) {
+ for ( int qual = 0; qual < 1000; qual++ ) {
+ final int expected = Math.max(Math.min(qual, max), 1);
+ Assert.assertEquals(QualityUtils.boundQual(qual, (byte)(max & 0xFF)) & 0xFF, expected & 0xFF, "qual " + qual + " max " + max);
+ }
+ }
+ }
+
+ @DataProvider(name = "PhredScaleDoubleOps")
+ public Object[][] makePhredDoubleTest() {
+ final List<Object[]> tests = new ArrayList<>();
+
+ tests.add(new Object[]{0.0, -10 * Math.log10(Double.MIN_VALUE)});
+ tests.add(new Object[]{1.0, 0.0});
+ for ( int pow = 1; pow < 20; pow++ ) {
+ tests.add(new Object[]{Math.pow(10.0, -1.0 * pow), pow * 10});
+ tests.add(new Object[]{Math.pow(10.0, -1.5 * pow), pow * 15});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test()
+ public void testQualToErrorProbDouble() {
+ for ( double qual = 3.0; qual < 255.0; qual += 0.1 ) {
+ final double expected = Math.pow(10.0, qual / -10.0);
+ Assert.assertEquals(QualityUtils.qualToErrorProb(qual), expected, TOLERANCE, "failed qual->error prob for double qual " + qual);
+ }
+ }
+
+
+ @Test(dataProvider = "PhredScaleDoubleOps")
+ public void testPhredScaleDoubleOps(final double errorRate, final double expectedPhredScaled) {
+ final double actualError = QualityUtils.phredScaleErrorRate(errorRate);
+ Assert.assertEquals(actualError, expectedPhredScaled, TOLERANCE);
+ final double trueRate = 1 - errorRate;
+ final double actualTrue = QualityUtils.phredScaleCorrectRate(trueRate);
+ if ( trueRate == 1.0 ) {
+ Assert.assertEquals(actualTrue, QualityUtils.MIN_PHRED_SCALED_QUAL);
+ } else {
+ final double tol = errorRate < 1e-10 ? 10.0 : 1e-3;
+ Assert.assertEquals(actualTrue, expectedPhredScaled, tol);
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/R/RScriptExecutorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/R/RScriptExecutorUnitTest.java
new file mode 100644
index 0000000..7a56b99
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/R/RScriptExecutorUnitTest.java
@@ -0,0 +1,110 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.R;
+
+import org.apache.commons.io.FileUtils;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.io.IOUtils;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.File;
+
+/**
+ * Basic unit test for RScriptExecutor in reduced reads
+ */
+public class RScriptExecutorUnitTest extends BaseTest {
+
+ private static final String HELLO_WORLD_SCRIPT = "print('hello, world')";
+ private static final String GSALIB_LOADED_SCRIPT = "if (!'package:gsalib' %in% search()) stop('gsalib not loaded')";
+
+ @Test
+ public void testRscriptExists() {
+ Assert.assertTrue(RScriptExecutor.RSCRIPT_EXISTS, "Rscript not found in environment ${PATH}");
+ }
+
+ @Test(dependsOnMethods = "testRscriptExists")
+ public void testExistingScript() {
+ File script = writeScript(HELLO_WORLD_SCRIPT);
+ try {
+ RScriptExecutor executor = new RScriptExecutor();
+ executor.addScript(script);
+ executor.setExceptOnError(true);
+ Assert.assertTrue(executor.exec(), "Exec failed");
+ } finally {
+ FileUtils.deleteQuietly(script);
+ }
+ }
+
+ @Test(dependsOnMethods = "testRscriptExists", expectedExceptions = RScriptExecutorException.class)
+ public void testNonExistantScriptException() {
+ RScriptExecutor executor = new RScriptExecutor();
+ executor.setExceptOnError(true);
+ executor.addScript(new File("does_not_exists.R"));
+ executor.exec();
+ }
+
+ @Test(dependsOnMethods = "testRscriptExists")
+ public void testNonExistantScriptNoException() {
+ logger.warn("Testing that warning is printed an no exception thrown for missing script.");
+ RScriptExecutor executor = new RScriptExecutor();
+ executor.setExceptOnError(false);
+ executor.addScript(new File("does_not_exists.R"));
+ Assert.assertFalse(executor.exec(), "Exec should have returned false when the job failed");
+ }
+
+ @Test(dependsOnMethods = "testRscriptExists")
+ public void testLibrary() {
+ File script = writeScript(GSALIB_LOADED_SCRIPT);
+ try {
+ RScriptExecutor executor = new RScriptExecutor();
+ executor.addScript(script);
+ executor.addLibrary(RScriptLibrary.GSALIB);
+ executor.setExceptOnError(true);
+ Assert.assertTrue(executor.exec(), "Exec failed");
+ } finally {
+ FileUtils.deleteQuietly(script);
+ }
+ }
+
+ @Test(dependsOnMethods = "testRscriptExists", expectedExceptions = RScriptExecutorException.class)
+ public void testLibraryMissing() {
+ File script = writeScript(GSALIB_LOADED_SCRIPT);
+ try {
+ RScriptExecutor executor = new RScriptExecutor();
+ executor.addScript(script);
+ // GSALIB is not added nor imported in the script
+ executor.setExceptOnError(true);
+ executor.exec();
+ } finally {
+ FileUtils.deleteQuietly(script);
+ }
+ }
+
+ private File writeScript(String content) {
+ return IOUtils.writeTempFile(content, "myTestScript", ".R");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/R/RScriptLibraryUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/R/RScriptLibraryUnitTest.java
new file mode 100644
index 0000000..b89686c
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/R/RScriptLibraryUnitTest.java
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.R;
+
+import org.apache.commons.io.FileUtils;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.File;
+
+public class RScriptLibraryUnitTest {
+ @Test
+ public void testProperties() {
+ Assert.assertEquals(RScriptLibrary.GSALIB.getLibraryName(), "gsalib");
+ Assert.assertEquals(RScriptLibrary.GSALIB.getResourcePath(), "gsalib.tar.gz");
+ }
+
+ @Test
+ public void testWriteTemp() {
+ File file = RScriptLibrary.GSALIB.writeTemp();
+ Assert.assertTrue(file.exists(), "R library was not written to temp file: " + file);
+ FileUtils.deleteQuietly(file);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/R/RUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/R/RUtilsUnitTest.java
new file mode 100644
index 0000000..51ab6f7
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/R/RUtilsUnitTest.java
@@ -0,0 +1,65 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.R;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class RUtilsUnitTest {
+ @DataProvider(name = "stringLists")
+ public Object[][] getStringLists() {
+ return new Object[][] {
+ new Object[] { null, "NA" },
+ new Object[] { Collections.EMPTY_LIST, "c()" },
+ new Object[] { Arrays.asList("1", "2", "3"), "c('1','2','3')" }
+ };
+ }
+
+ @Test(dataProvider = "stringLists")
+ public void testToStringList(List<? extends CharSequence> actual, String expected) {
+ Assert.assertEquals(RUtils.toStringList(actual), expected);
+ }
+
+ @DataProvider(name = "numberLists")
+ public Object[][] getNumberLists() {
+ return new Object[][] {
+ new Object[] { null, "NA" },
+ new Object[] { Collections.EMPTY_LIST, "c()" },
+ new Object[] { Arrays.asList(1, 2, 3), "c(1,2,3)" },
+ new Object[] { Arrays.asList(1D, 2D, 3D), "c(1.0,2.0,3.0)" }
+ };
+ }
+
+ @Test(dataProvider = "numberLists")
+ public void testToNumberList(List<? extends Number> actual, String expected) {
+ Assert.assertEquals(RUtils.toNumberList(actual), expected);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/SampleUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/SampleUtilsUnitTest.java
new file mode 100644
index 0000000..d11c4bf
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/SampleUtilsUnitTest.java
@@ -0,0 +1,52 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.apache.commons.io.FileUtils;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.io.IOUtils;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * Testing framework for sample utilities class.
+ *
+ * @author gauthier
+ */
+
+public class SampleUtilsUnitTest extends BaseTest {
+ @Test(expectedExceptions=UserException.class)
+ public void testBadSampleFiles() throws Exception {
+ Set<File> sampleFiles = new HashSet<File>(0);
+ sampleFiles.add(new File("fileNotHere.samples"));
+ Collection<String> samplesFromFile = SampleUtils.getSamplesFromFiles(sampleFiles);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/SequenceDictionaryUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/SequenceDictionaryUtilsUnitTest.java
new file mode 100644
index 0000000..6ccb0c9
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/SequenceDictionaryUtilsUnitTest.java
@@ -0,0 +1,241 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import htsjdk.samtools.SAMSequenceDictionary;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.apache.log4j.Logger;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import static org.broadinstitute.gatk.utils.SequenceDictionaryUtils.*;
+import static org.broadinstitute.gatk.utils.SequenceDictionaryUtils.SequenceDictionaryCompatibility.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class SequenceDictionaryUtilsUnitTest extends BaseTest {
+
+ private static Logger logger = Logger.getLogger(SequenceDictionaryUtilsUnitTest.class);
+
+
+ @DataProvider( name = "SequenceDictionaryDataProvider" )
+ public Object[][] generateSequenceDictionaryTestData() {
+ final SAMSequenceRecord CHRM_HG19 = new SAMSequenceRecord("chrM", 16571);
+ final SAMSequenceRecord CHR_NONSTANDARD1 = new SAMSequenceRecord("NonStandard1", 8675309);
+ final SAMSequenceRecord CHR_NONSTANDARD2 = new SAMSequenceRecord("NonStandard2", 8675308);
+
+ final Class NO_COMMON_CONTIGS_EXCEPTION = UserException.IncompatibleSequenceDictionaries.class;
+ final Class UNEQUAL_COMMON_CONTIGS_EXCEPTION = UserException.IncompatibleSequenceDictionaries.class;
+ final Class NON_CANONICAL_HUMAN_ORDER_EXCEPTION = UserException.LexicographicallySortedSequenceDictionary.class;
+ final Class OUT_OF_ORDER_EXCEPTION = UserException.IncompatibleSequenceDictionaries.class;
+ final Class DIFFERENT_INDICES_EXCEPTION = UserException.IncompatibleSequenceDictionaries.class;
+
+ final List<SAMSequenceRecord> hg19Sequences = Arrays.asList(CHRM_HG19, CHR1_HG19, CHR2_HG19, CHR10_HG19);
+ final GenomeLocParser hg19GenomeLocParser = new GenomeLocParser(new SAMSequenceDictionary(hg19Sequences));
+ final List<GenomeLoc> hg19AllContigsIntervals = Arrays.asList(hg19GenomeLocParser.createGenomeLoc("chrM", 0, 1),
+ hg19GenomeLocParser.createGenomeLoc("chr1", 0, 1),
+ hg19GenomeLocParser.createGenomeLoc("chr2", 0, 1),
+ hg19GenomeLocParser.createGenomeLoc("chr10", 0, 1));
+ final List<GenomeLoc> hg19PartialContigsIntervals = Arrays.asList(hg19GenomeLocParser.createGenomeLoc("chrM", 0, 1),
+ hg19GenomeLocParser.createGenomeLoc("chr1", 0, 1));
+ final GenomeLocSortedSet hg19AllContigsIntervalSet = new GenomeLocSortedSet(hg19GenomeLocParser, hg19AllContigsIntervals);
+ final GenomeLocSortedSet hg19PartialContigsIntervalSet = new GenomeLocSortedSet(hg19GenomeLocParser, hg19PartialContigsIntervals);
+
+ return new Object[][] {
+ // Identical dictionaries:
+ { Arrays.asList(CHR1_HG19), Arrays.asList(CHR1_HG19), null, IDENTICAL, null, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19), Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19), null, IDENTICAL, null, false, null },
+ { Arrays.asList(CHR1_B37), Arrays.asList(CHR1_B37), null, IDENTICAL, null, false, null },
+ { Arrays.asList(CHR1_B37, CHR2_B37, CHR10_B37), Arrays.asList(CHR1_B37, CHR2_B37, CHR10_B37), null, IDENTICAL, null, false, null },
+
+ // Dictionaries with a common subset:
+ { Arrays.asList(CHR1_HG19), Arrays.asList(CHR1_HG19, CHR_NONSTANDARD1), null, COMMON_SUBSET, null, false, null },
+ { Arrays.asList(CHR1_HG19, CHR_NONSTANDARD1), Arrays.asList(CHR1_HG19, CHR_NONSTANDARD2), null, COMMON_SUBSET, null, false, null },
+ { Arrays.asList(CHR_NONSTANDARD1, CHR1_HG19), Arrays.asList(CHR_NONSTANDARD2, CHR1_HG19), null, COMMON_SUBSET, null, false, null },
+ { Arrays.asList(CHR_NONSTANDARD1, CHR1_HG19), Arrays.asList(CHR_NONSTANDARD2, CHR1_HG19, CHRM_HG19), null, COMMON_SUBSET, null, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19, CHR_NONSTANDARD1), Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19, CHR_NONSTANDARD2), null, COMMON_SUBSET, null, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19, CHR_NONSTANDARD1), Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19), null, COMMON_SUBSET, null, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19), Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19, CHR_NONSTANDARD1), null, COMMON_SUBSET, null, false, null },
+ { Arrays.asList(CHR_NONSTANDARD1, CHR1_HG19, CHR2_HG19, CHR10_HG19), Arrays.asList(CHR_NONSTANDARD2, CHR1_HG19, CHR2_HG19, CHR10_HG19), null, COMMON_SUBSET, null, false, null },
+ { Arrays.asList(CHR_NONSTANDARD1, CHR1_HG19, CHR2_HG19, CHR10_HG19), Arrays.asList(CHR_NONSTANDARD2, CHR1_HG19, CHR2_HG19, CHR10_HG19, CHRM_HG19), null, COMMON_SUBSET, null, false, null },
+ { Arrays.asList(CHR1_B37, CHR2_B37, CHR10_B37, CHR_NONSTANDARD1), Arrays.asList(CHR1_B37, CHR2_B37, CHR10_B37, CHR_NONSTANDARD2), null, COMMON_SUBSET, null, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19), Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19), null, COMMON_SUBSET, null, false, null },
+
+ // Dictionaries with no common contigs:
+ { Arrays.asList(CHR1_HG19), Arrays.asList(CHR2_HG19), null, NO_COMMON_CONTIGS, NO_COMMON_CONTIGS_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_HG19), Arrays.asList(CHR1_B37), null, NO_COMMON_CONTIGS, NO_COMMON_CONTIGS_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19), Arrays.asList(CHR1_B37, CHR2_B37, CHR10_B37), null, NO_COMMON_CONTIGS, NO_COMMON_CONTIGS_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19), Arrays.asList(CHR1_B37, CHR2_B37, CHR10_B37), null, NO_COMMON_CONTIGS, NO_COMMON_CONTIGS_EXCEPTION, false, null },
+
+ // Dictionaries with unequal common contigs:
+ { Arrays.asList(CHR1_HG19), Arrays.asList(CHR1_HG18), null, UNEQUAL_COMMON_CONTIGS, UNEQUAL_COMMON_CONTIGS_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_B36), Arrays.asList(CHR1_B37), null, UNEQUAL_COMMON_CONTIGS, UNEQUAL_COMMON_CONTIGS_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19), Arrays.asList(CHR1_HG18, CHR2_HG18, CHR10_HG18), null, UNEQUAL_COMMON_CONTIGS, UNEQUAL_COMMON_CONTIGS_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_B37, CHR2_B37, CHR10_B37), Arrays.asList(CHR1_B36, CHR2_B36, CHR10_B36), null, UNEQUAL_COMMON_CONTIGS, UNEQUAL_COMMON_CONTIGS_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19, CHR_NONSTANDARD1), Arrays.asList(CHR1_HG18, CHR2_HG18, CHR10_HG18, CHR_NONSTANDARD2), null, UNEQUAL_COMMON_CONTIGS, UNEQUAL_COMMON_CONTIGS_EXCEPTION, false, null },
+ { Arrays.asList(CHR_NONSTANDARD1, CHR1_HG19, CHR2_HG19, CHR10_HG19), Arrays.asList(CHR_NONSTANDARD2, CHR1_HG18, CHR2_HG18, CHR10_HG18), null, UNEQUAL_COMMON_CONTIGS, UNEQUAL_COMMON_CONTIGS_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19), Arrays.asList(CHR1_HG18, CHR2_HG18, CHR10_HG18), null, UNEQUAL_COMMON_CONTIGS, UNEQUAL_COMMON_CONTIGS_EXCEPTION, false, null },
+
+ // One or both dictionaries in non-canonical human order:
+ { Arrays.asList(CHR1_HG19, CHR10_HG19, CHR2_HG19), Arrays.asList(CHR1_HG19, CHR10_HG19, CHR2_HG19), null, NON_CANONICAL_HUMAN_ORDER, NON_CANONICAL_HUMAN_ORDER_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_HG18, CHR10_HG18, CHR2_HG18), Arrays.asList(CHR1_HG18, CHR10_HG18, CHR2_HG18), null, NON_CANONICAL_HUMAN_ORDER, NON_CANONICAL_HUMAN_ORDER_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_HG19, CHR10_HG19, CHR2_HG19), Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19), null, NON_CANONICAL_HUMAN_ORDER, NON_CANONICAL_HUMAN_ORDER_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19), Arrays.asList(CHR1_HG19, CHR10_HG19, CHR2_HG19), null, NON_CANONICAL_HUMAN_ORDER, NON_CANONICAL_HUMAN_ORDER_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_B37, CHR10_B37, CHR2_B37), Arrays.asList(CHR1_B37, CHR10_B37, CHR2_B37), null, NON_CANONICAL_HUMAN_ORDER, NON_CANONICAL_HUMAN_ORDER_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_B36, CHR10_B36, CHR2_B36), Arrays.asList(CHR1_B36, CHR10_B36, CHR2_B36), null, NON_CANONICAL_HUMAN_ORDER, NON_CANONICAL_HUMAN_ORDER_EXCEPTION, false, null },
+
+ // Dictionaries with a common subset, but different relative ordering within that subset:
+ { Arrays.asList(CHR1_HG19, CHR2_HG19), Arrays.asList(CHR2_HG19, CHR1_HG19), null, OUT_OF_ORDER, OUT_OF_ORDER_EXCEPTION, false, null },
+ { Arrays.asList(CHRM_HG19, CHR1_HG19, CHR2_HG19), Arrays.asList(CHR2_HG19, CHR1_HG19, CHRM_HG19), null, OUT_OF_ORDER, OUT_OF_ORDER_EXCEPTION, false, null },
+ { Arrays.asList(CHRM_HG19, CHR1_HG19, CHR2_HG19), Arrays.asList(CHRM_HG19, CHR2_HG19, CHR1_HG19), null, OUT_OF_ORDER, OUT_OF_ORDER_EXCEPTION, false, null },
+ { Arrays.asList(CHRM_HG19, CHR1_HG19, CHR2_HG19), Arrays.asList(CHR2_HG19, CHRM_HG19, CHR1_HG19), null, OUT_OF_ORDER, OUT_OF_ORDER_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_B37, CHR2_B37), Arrays.asList(CHR2_B37, CHR1_B37), null, OUT_OF_ORDER, OUT_OF_ORDER_EXCEPTION, false, null },
+
+
+ // Dictionaries with a common subset in the same relative order, but with different indices.
+ // This will only throw an exception during validation if isReadsToReferenceComparison is true,
+ // and there are intervals overlapping the misindexed contigs:
+
+ // These have isReadsToReferenceComparison == true and overlapping intervals, so we expect an exception:
+ { Arrays.asList(CHRM_HG19, CHR1_HG19), Arrays.asList(CHR1_HG19), null, DIFFERENT_INDICES, DIFFERENT_INDICES_EXCEPTION, true, hg19AllContigsIntervalSet },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19), Arrays.asList(CHRM_HG19, CHR1_HG19, CHR2_HG19), null, DIFFERENT_INDICES, DIFFERENT_INDICES_EXCEPTION, true, hg19AllContigsIntervalSet },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19), Arrays.asList(CHRM_HG19, CHR1_HG19, CHR2_HG19, CHR_NONSTANDARD1), null, DIFFERENT_INDICES, DIFFERENT_INDICES_EXCEPTION, true, hg19AllContigsIntervalSet },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19), Arrays.asList(CHRM_HG19, CHR_NONSTANDARD1, CHR1_HG19, CHR2_HG19), null, DIFFERENT_INDICES, DIFFERENT_INDICES_EXCEPTION, true, hg19AllContigsIntervalSet },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19, CHR_NONSTANDARD1, CHRM_HG19 ), Arrays.asList(CHR1_HG19, CHR2_HG19, CHRM_HG19), null, DIFFERENT_INDICES, DIFFERENT_INDICES_EXCEPTION, true, hg19AllContigsIntervalSet },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19, CHR_NONSTANDARD1, CHRM_HG19, CHR_NONSTANDARD2 ), Arrays.asList(CHR1_HG19, CHR2_HG19, CHRM_HG19, CHR_NONSTANDARD2 ), null, DIFFERENT_INDICES, DIFFERENT_INDICES_EXCEPTION, true, hg19AllContigsIntervalSet },
+ { Arrays.asList(CHR1_HG19, CHR_NONSTANDARD1, CHR2_HG19, CHRM_HG19, CHR_NONSTANDARD2 ), Arrays.asList(CHR1_HG19, CHR2_HG19, CHRM_HG19, CHR_NONSTANDARD2 ), null, DIFFERENT_INDICES, DIFFERENT_INDICES_EXCEPTION, true, hg19AllContigsIntervalSet },
+
+ // These have isReadsToReferenceComparison == true but no overlapping intervals, so we don't expect an exception:
+ { Arrays.asList(CHR2_HG19, CHR10_HG19), Arrays.asList(CHR10_HG19), null, DIFFERENT_INDICES, null, true, hg19PartialContigsIntervalSet },
+ { Arrays.asList(CHR1_HG19, CHR_NONSTANDARD1, CHR2_HG19), Arrays.asList(CHR1_HG19, CHR2_HG19), null, DIFFERENT_INDICES, null, true, hg19PartialContigsIntervalSet },
+ { Arrays.asList(CHR1_HG19, CHR_NONSTANDARD1, CHR2_HG19, CHR10_HG19), Arrays.asList(CHR1_HG19, CHR2_HG19, CHR10_HG19), null, DIFFERENT_INDICES, null, true, hg19PartialContigsIntervalSet },
+
+ // These have isReadsToReferenceComparison == false, so we don't expect an exception:
+ { Arrays.asList(CHRM_HG19, CHR1_HG19), Arrays.asList(CHR1_HG19), null, DIFFERENT_INDICES, null, false, hg19AllContigsIntervalSet },
+ { Arrays.asList(CHR1_HG19, CHR_NONSTANDARD1, CHR2_HG19, CHRM_HG19), Arrays.asList(CHR1_HG19, CHR2_HG19, CHRM_HG19), null, DIFFERENT_INDICES, null, false, hg19AllContigsIntervalSet },
+
+
+ // Tests for validation exclusions. Note that errors resulting from NO_COMMON_CONTIGs cannot be suppressed
+ { Arrays.asList(CHR1_HG19), Arrays.asList(CHR2_HG19), ValidationExclusion.TYPE.ALLOW_SEQ_DICT_INCOMPATIBILITY, NO_COMMON_CONTIGS, NO_COMMON_CONTIGS_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_HG19), Arrays.asList(CHR2_HG19), ValidationExclusion.TYPE.ALL, NO_COMMON_CONTIGS, NO_COMMON_CONTIGS_EXCEPTION, false, null },
+ { Arrays.asList(CHR1_HG19), Arrays.asList(CHR1_HG18), ValidationExclusion.TYPE.ALLOW_SEQ_DICT_INCOMPATIBILITY, UNEQUAL_COMMON_CONTIGS, null, false, null },
+ { Arrays.asList(CHR1_HG19), Arrays.asList(CHR1_HG18), ValidationExclusion.TYPE.ALL, UNEQUAL_COMMON_CONTIGS, null, false, null },
+ { Arrays.asList(CHR1_HG19, CHR10_HG19, CHR2_HG19), Arrays.asList(CHR1_HG19, CHR10_HG19, CHR2_HG19), ValidationExclusion.TYPE.ALLOW_SEQ_DICT_INCOMPATIBILITY, NON_CANONICAL_HUMAN_ORDER, null, false, null },
+ { Arrays.asList(CHR1_HG19, CHR10_HG19, CHR2_HG19), Arrays.asList(CHR1_HG19, CHR10_HG19, CHR2_HG19), ValidationExclusion.TYPE.ALL, NON_CANONICAL_HUMAN_ORDER, null, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19), Arrays.asList(CHR2_HG19, CHR1_HG19), ValidationExclusion.TYPE.ALLOW_SEQ_DICT_INCOMPATIBILITY, OUT_OF_ORDER, null, false, null },
+ { Arrays.asList(CHR1_HG19, CHR2_HG19), Arrays.asList(CHR2_HG19, CHR1_HG19), ValidationExclusion.TYPE.ALL, OUT_OF_ORDER, null, false, null },
+ { Arrays.asList(CHRM_HG19, CHR1_HG19), Arrays.asList(CHR1_HG19), ValidationExclusion.TYPE.ALLOW_SEQ_DICT_INCOMPATIBILITY, DIFFERENT_INDICES, null, true, hg19AllContigsIntervalSet },
+ { Arrays.asList(CHRM_HG19, CHR1_HG19), Arrays.asList(CHR1_HG19), ValidationExclusion.TYPE.ALL, DIFFERENT_INDICES, null, true, hg19AllContigsIntervalSet }
+ };
+ }
+
+ @Test( dataProvider = "SequenceDictionaryDataProvider" )
+ public void testSequenceDictionaryValidation( final List<SAMSequenceRecord> firstDictionaryContigs,
+ final List<SAMSequenceRecord> secondDictionaryContigs,
+ final ValidationExclusion.TYPE validationExclusions,
+ final SequenceDictionaryUtils.SequenceDictionaryCompatibility dictionaryCompatibility,
+ final Class expectedExceptionUponValidation,
+ final boolean isReadsToReferenceComparison,
+ final GenomeLocSortedSet intervals ) {
+
+ final SAMSequenceDictionary firstDictionary = createSequenceDictionary(firstDictionaryContigs);
+ final SAMSequenceDictionary secondDictionary = createSequenceDictionary(secondDictionaryContigs);
+ final String testDescription = String.format("First dictionary: %s Second dictionary: %s Validation exclusions: %s",
+ SequenceDictionaryUtils.getDictionaryAsString(firstDictionary),
+ SequenceDictionaryUtils.getDictionaryAsString(secondDictionary),
+ validationExclusions);
+
+ Exception exceptionThrown = null;
+ try {
+ SequenceDictionaryUtils.validateDictionaries(logger,
+ validationExclusions,
+ "firstDictionary",
+ firstDictionary,
+ "secondDictionary",
+ secondDictionary,
+ isReadsToReferenceComparison,
+ intervals);
+ }
+ catch ( Exception e ) {
+ exceptionThrown = e;
+ }
+
+ if ( expectedExceptionUponValidation != null ) {
+ Assert.assertTrue(exceptionThrown != null && expectedExceptionUponValidation.isInstance(exceptionThrown),
+ String.format("Expected exception %s but saw %s instead. %s",
+ expectedExceptionUponValidation.getSimpleName(),
+ exceptionThrown == null ? "no exception" : exceptionThrown.getClass().getSimpleName(),
+ testDescription));
+ }
+ else {
+ Assert.assertTrue(exceptionThrown == null,
+ String.format("Expected no exception but saw exception %s instead. %s",
+ exceptionThrown != null ? exceptionThrown.getClass().getSimpleName() : "none",
+ testDescription));
+ }
+ }
+
+ @Test( dataProvider = "SequenceDictionaryDataProvider" )
+ public void testSequenceDictionaryComparison( final List<SAMSequenceRecord> firstDictionaryContigs,
+ final List<SAMSequenceRecord> secondDictionaryContigs,
+ final ValidationExclusion.TYPE validationExclusions,
+ final SequenceDictionaryUtils.SequenceDictionaryCompatibility dictionaryCompatibility,
+ final Class expectedExceptionUponValidation,
+ final boolean isReadsToReferenceComparison,
+ final GenomeLocSortedSet intervals ) {
+
+ final SAMSequenceDictionary firstDictionary = createSequenceDictionary(firstDictionaryContigs);
+ final SAMSequenceDictionary secondDictionary = createSequenceDictionary(secondDictionaryContigs);
+ final String testDescription = String.format("First dictionary: %s Second dictionary: %s",
+ SequenceDictionaryUtils.getDictionaryAsString(firstDictionary),
+ SequenceDictionaryUtils.getDictionaryAsString(secondDictionary));
+
+ final SequenceDictionaryUtils.SequenceDictionaryCompatibility reportedCompatibility =
+ SequenceDictionaryUtils.compareDictionaries(firstDictionary, secondDictionary);
+
+ Assert.assertTrue(reportedCompatibility == dictionaryCompatibility,
+ String.format("Dictionary comparison should have returned %s but instead returned %s. %s",
+ dictionaryCompatibility, reportedCompatibility, testDescription));
+ }
+
+ private SAMSequenceDictionary createSequenceDictionary( final List<SAMSequenceRecord> contigs ) {
+ final List<SAMSequenceRecord> clonedContigs = new ArrayList<SAMSequenceRecord>(contigs.size());
+
+ // Clone the individual SAMSequenceRecords to avoid contig-index issues with shared objects
+ // across multiple dictionaries in tests
+ for ( SAMSequenceRecord contig : contigs ) {
+ clonedContigs.add(contig.clone());
+ }
+
+ return new SAMSequenceDictionary(clonedContigs);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/SimpleTimerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/SimpleTimerUnitTest.java
new file mode 100644
index 0000000..85aec81
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/SimpleTimerUnitTest.java
@@ -0,0 +1,179 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Field;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public class SimpleTimerUnitTest extends BaseTest {
+ private final static String NAME = "unit.test.timer";
+
+ @Test
+ public void testSimpleTimer() {
+ SimpleTimer t = new SimpleTimer(NAME);
+ Assert.assertEquals(t.getName(), NAME, "Name is not the provided one");
+ Assert.assertFalse(t.isRunning(), "Initial state of the timer is running");
+ Assert.assertEquals(t.getElapsedTime(), 0.0, "New timer elapsed time should be 0");
+ Assert.assertEquals(t.getElapsedTimeNano(), 0l, "New timer elapsed time nano should be 0");
+
+ t.start();
+ Assert.assertTrue(t.isRunning(), "Started timer isn't running");
+ Assert.assertTrue(t.getElapsedTime() >= 0.0, "Elapsed time should be >= 0");
+ Assert.assertTrue(t.getElapsedTimeNano() >= 0.0, "Elapsed time nano should be >= 0");
+ long n1 = t.getElapsedTimeNano();
+ double t1 = t.getElapsedTime();
+ idleLoop(); // idle loop to wait a tiny bit of time
+ long n2 = t.getElapsedTimeNano();
+ double t2 = t.getElapsedTime();
+ Assert.assertTrue(t2 >= t1, "T2 >= T1 for a running time");
+ Assert.assertTrue(n2 >= n1, "T2 >= T1 nano for a running time");
+
+ t.stop();
+ Assert.assertFalse(t.isRunning(), "Stopped timer still running");
+ long n3 = t.getElapsedTimeNano();
+ double t3 = t.getElapsedTime();
+ idleLoop(); // idle loop to wait a tiny bit of time
+ double t4 = t.getElapsedTime();
+ long n4 = t.getElapsedTimeNano();
+ Assert.assertTrue(t4 == t3, "Elapsed times for two calls of stop timer not the same");
+ Assert.assertTrue(n4 == n3, "Elapsed times for two calls of stop timer not the same");
+
+ t.restart();
+ idleLoop(); // idle loop to wait a tiny bit of time
+ double t5 = t.getElapsedTime();
+ long n5 = t.getElapsedTimeNano();
+ Assert.assertTrue(t.isRunning(), "Restarted timer should be running");
+ idleLoop(); // idle loop to wait a tiny bit of time
+ double t6 = t.getElapsedTime();
+ long n6 = t.getElapsedTimeNano();
+ Assert.assertTrue(t5 >= t4, "Restarted timer elapsed time should be after elapsed time preceding the restart");
+ Assert.assertTrue(t6 >= t5, "Second elapsed time not after the first in restarted timer");
+ Assert.assertTrue(n5 >= n4, "Restarted timer elapsed time nano should be after elapsed time preceding the restart");
+ Assert.assertTrue(n6 >= n5, "Second elapsed time nano not after the first in restarted timer");
+
+ final List<Double> secondTimes = Arrays.asList(t1, t2, t3, t4, t5, t6);
+ final List<Long> nanoTimes = Arrays.asList(n1, n2, n3, n4, n5, n6);
+ for ( int i = 0; i < nanoTimes.size(); i++ )
+ Assert.assertEquals(
+ SimpleTimer.nanoToSecondsAsDouble(nanoTimes.get(i)),
+ secondTimes.get(i), 1e-1, "Nanosecond and second timer disagree");
+ }
+
+ @Test
+ public void testNanoResolution() {
+ SimpleTimer t = new SimpleTimer(NAME);
+
+ // test the nanosecond resolution
+ long n7 = t.currentTimeNano();
+ int sum = 0;
+ for ( int i = 0; i < 100; i++) sum += i;
+ long n8 = t.currentTimeNano();
+ final long delta = n8 - n7;
+ final long oneMilliInNano = TimeUnit.MILLISECONDS.toNanos(1);
+ logger.warn("nanoTime before nano operation " + n7);
+ logger.warn("nanoTime after nano operation of summing 100 ints " + n8 + ", sum = " + sum + " time delta " + delta + " vs. 1 millsecond in nano " + oneMilliInNano);
+ Assert.assertTrue(n8 > n7, "SimpleTimer doesn't appear to have nanoSecond resolution: n8 " + n8 + " <= n7 " + n7);
+ Assert.assertTrue(delta < oneMilliInNano,
+ "SimpleTimer doesn't appear to have nanoSecond resolution: time delta is " + delta + " vs 1 millisecond in nano " + oneMilliInNano);
+ }
+
+ @Test
+ public void testMeaningfulTimes() {
+ SimpleTimer t = new SimpleTimer(NAME);
+
+ t.start();
+ for ( int i = 0; i < 100; i++ ) ;
+ long nano = t.getElapsedTimeNano();
+ double secs = t.getElapsedTime();
+
+ Assert.assertTrue(secs > 0, "Seconds timer doesn't appear to count properly: elapsed time is " + secs);
+ Assert.assertTrue(secs < 0.01, "Fast operation said to take longer than 10 milliseconds: elapsed time in seconds " + secs);
+
+ Assert.assertTrue(nano > 0, "Nanosecond timer doesn't appear to count properly: elapsed time is " + nano);
+ final long maxTimeInMicro = 10000;
+ final long maxTimeInNano = TimeUnit.MICROSECONDS.toNanos(maxTimeInMicro);
+ Assert.assertTrue(nano < maxTimeInNano, "Fast operation said to take longer than " + maxTimeInMicro + " microseconds: elapsed time in nano " + nano + " micro " + TimeUnit.NANOSECONDS.toMicros(nano));
+ }
+
+ @Test
+ public void testCheckpointRestart() throws Exception {
+ SimpleTimer t = new SimpleTimer(NAME);
+
+ final Field offsetField = t.getClass().getDeclaredField("nanoTimeOffset");
+ offsetField.setAccessible(true);
+ long offset = ((Long) offsetField.get(t)).longValue();
+
+ t.start();
+ idleLoop();
+ // Make it as if clock has jumped into the past
+ offsetField.set(t, offset + TimeUnit.SECONDS.toNanos(10));
+ t.stop();
+ offset = ((Long) offsetField.get(t)).longValue();
+ Assert.assertEquals(t.getElapsedTime(), 0.0, "Time over restart is not zero.");
+
+ t.start();
+ idleLoop();
+ t.stop();
+ offset = ((Long) offsetField.get(t)).longValue();
+ double elapsed = t.getElapsedTime();
+ Assert.assertTrue(elapsed >= 0.0, "Elapsed time is zero.");
+ t.restart();
+ // Make the clock jump again by just a little
+ offsetField.set(t, offset + TimeUnit.SECONDS.toNanos(1));
+ idleLoop();
+ t.stop();
+ offset = ((Long) offsetField.get(t)).longValue();
+ Assert.assertTrue(t.getElapsedTime() > elapsed, "Small clock drift causing reset.");
+ elapsed = t.getElapsedTime();
+ // Now a bigger jump, into the future this time.
+ t.restart();
+ // Make the clock jump again by a lot
+ offsetField.set(t, offset - TimeUnit.SECONDS.toNanos(10));
+ t.stop();
+ Assert.assertEquals(t.getElapsedTime(), elapsed, "Time added over checkpoint/restart.");
+
+ // Test without stopping
+ t.start();
+ offset = ((Long) offsetField.get(t)).longValue();
+ // Make it as if clock has jumped into the past
+ offsetField.set(t, offset + TimeUnit.SECONDS.toNanos(10));
+ Assert.assertEquals(t.getElapsedTime(), 0.0, "Elapsed time after C/R is not zero.");
+ idleLoop();
+ Assert.assertTrue(t.getElapsedTime() > 0.0, "Elapsed time zero after re-sync.");
+
+ }
+
+ private static void idleLoop() {
+ for ( int i = 0; i < 100000; i++ ) ; // idle loop to wait a tiny bit of time
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/TestNGTestTransformer.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/TestNGTestTransformer.java
new file mode 100644
index 0000000..e804e70
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/TestNGTestTransformer.java
@@ -0,0 +1,62 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.apache.log4j.Logger;
+import org.testng.IAnnotationTransformer;
+import org.testng.annotations.ITestAnnotation;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+/**
+ * Provide default @Test values for GATK testng tests.
+ *
+ * Currently only sets the maximum runtime to 40 minutes, if it's not been specified.
+ *
+ * See http://beust.com/weblog/2006/10/18/annotation-transformers-in-java/
+ *
+ * @author depristo
+ * @since 10/31/12
+ * @version 0.1
+ */
+public class TestNGTestTransformer implements IAnnotationTransformer {
+ public static final long DEFAULT_TIMEOUT = 1000 * 60 * 40; // 40 minutes max per test
+
+ final static Logger logger = Logger.getLogger(TestNGTestTransformer.class);
+
+ public void transform(ITestAnnotation annotation,
+ Class testClass,
+ Constructor testConstructor,
+ Method testMethod)
+ {
+ if ( annotation.getTimeOut() == 0 ) {
+ logger.warn("test " + (testMethod == null ? "<null>" : testMethod.toString()) + " has no specified timeout, adding default timeout " + DEFAULT_TIMEOUT / 1000 / 60 + " minutes");
+ annotation.setTimeOut(DEFAULT_TIMEOUT);
+ }
+ }
+}
+
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/UtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/UtilsUnitTest.java
new file mode 100644
index 0000000..a303f2c
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/UtilsUnitTest.java
@@ -0,0 +1,363 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import org.apache.commons.io.FileUtils;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.io.IOUtils;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.*;
+
+/**
+ * Testing framework for general purpose utilities class.
+ *
+ * @author hanna
+ * @version 0.1
+ */
+
+public class UtilsUnitTest extends BaseTest {
+ @Test
+ public void testAppend() {
+ for ( int leftSize : Arrays.asList(0, 1, 2, 3) ) {
+ for ( final int rightSize : Arrays.asList(0, 1, 2) ) {
+ final List<Integer> left = new LinkedList<Integer>();
+ for ( int i = 0; i < leftSize; i++ ) left.add(i);
+ final List<Integer> total = new LinkedList<Integer>();
+ for ( int i = 0; i < leftSize + rightSize; i++ ) total.add(i);
+
+ if ( rightSize == 0 )
+ Assert.assertEquals(Utils.append(left), total);
+ if ( rightSize == 1 )
+ Assert.assertEquals(Utils.append(left, leftSize), total);
+ if ( rightSize == 2 )
+ Assert.assertEquals(Utils.append(left, leftSize, leftSize + 1), total);
+ }
+ }
+
+ }
+
+ @Test
+ public void testDupStringNoChars() {
+ String duped = Utils.dupString('a',0);
+ Assert.assertEquals(duped.length(), 0, "dupString did not produce zero-length string");
+ }
+
+ @Test
+ public void testDupStringOneChar() {
+ String duped = Utils.dupString('b',1);
+ Assert.assertEquals(duped.length(), 1, "dupString did not produce single character string");
+ Assert.assertEquals(duped.charAt(0), 'b', "dupString character was incorrect");
+ }
+
+ @Test
+ public void testXor() {
+ Assert.assertEquals(Utils.xor(false, false), false, "xor F F failed");
+ Assert.assertEquals(Utils.xor(false, true), true, "xor F T failed");
+ Assert.assertEquals(Utils.xor(true, false), true, "xor T F failed");
+ Assert.assertEquals(Utils.xor(true, true), false, "xor T T failed");
+ }
+
+ @Test
+ public void testDupStringMultiChar() {
+ String duped = Utils.dupString('c',5);
+ Assert.assertEquals(duped.length(), 5, "dupString did not produce five character string");
+ Assert.assertEquals(duped,"ccccc","dupString string was incorrect");
+ }
+
+ @Test
+ public void testJoinMap() {
+ Map<String,Integer> map = new LinkedHashMap<String,Integer>();
+ map.put("one",1);
+ map.put("two",2);
+ String joined = Utils.joinMap("-",";",map);
+ Assert.assertTrue("one-1;two-2".equals(joined));
+ }
+
+ @Test
+ public void testJoinMapLargerSet() {
+ Map<String,Integer> map = new LinkedHashMap<String,Integer>();
+ map.put("one",1);
+ map.put("two",2);
+ map.put("three",1);
+ map.put("four",2);
+ map.put("five",1);
+ map.put("six",2);
+ String joined = Utils.joinMap("-",";",map);
+ Assert.assertTrue("one-1;two-2;three-1;four-2;five-1;six-2".equals(joined));
+ }
+
+ @Test
+ public void testConcat() {
+ final String s1 = "A";
+ final String s2 = "CC";
+ final String s3 = "TTT";
+ final String s4 = "GGGG";
+ Assert.assertEquals(new String(Utils.concat()), "");
+ Assert.assertEquals(new String(Utils.concat(s1.getBytes())), s1);
+ Assert.assertEquals(new String(Utils.concat(s1.getBytes(), s2.getBytes())), s1 + s2);
+ Assert.assertEquals(new String(Utils.concat(s1.getBytes(), s2.getBytes(), s3.getBytes())), s1 + s2 + s3);
+ Assert.assertEquals(new String(Utils.concat(s1.getBytes(), s2.getBytes(), s3.getBytes(), s4.getBytes())), s1 + s2 + s3 + s4);
+ }
+
+ @Test
+ public void testEscapeExpressions() {
+ String[] expected, actual;
+
+ expected = new String[] {"one", "two", "three"};
+ actual = Utils.escapeExpressions("one two three");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" one two three");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions("one two three ");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" one two three ");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" one two three ");
+ Assert.assertEquals(actual, expected);
+
+ expected = new String[] {"one", "two", "three four", "five", "six"};
+ actual = Utils.escapeExpressions("one two 'three four' five six");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" one two 'three four' five six");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions("one two 'three four' five six ");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" one two 'three four' five six ");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" one two 'three four' five six ");
+ Assert.assertEquals(actual, expected);
+
+ expected = new String[] {"one two", "three", "four"};
+ actual = Utils.escapeExpressions("'one two' three four");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" 'one two' three four");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions("'one two' three four ");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" 'one two' three four ");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" 'one two' three four ");
+ Assert.assertEquals(actual, expected);
+
+ expected = new String[] {"one", "two", "three four"};
+ actual = Utils.escapeExpressions("one two 'three four'");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" one two 'three four'");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions("one two 'three four' ");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" one two 'three four' ");
+ Assert.assertEquals(actual, expected);
+ actual = Utils.escapeExpressions(" one two 'three four' ");
+ Assert.assertEquals(actual, expected);
+ }
+
+ @Test(dataProvider = "asIntegerListData")
+ public void testAsIntegerList(final int[] values) {
+ if (values == null) {
+ try {
+ Utils.asList((int[]) null);
+ Assert.fail("Should have thrown an exception");
+ } catch (final IllegalArgumentException ex) {
+ // good.
+ }
+ } else {
+ final Random rdn = GenomeAnalysisEngine.getRandomGenerator();
+ final int[] valuesClone = values.clone();
+ final List<Integer> list = Utils.asList(valuesClone);
+ Assert.assertNotNull(list);
+ Assert.assertEquals(list.size(),values.length);
+ for (int i = 0; i < values.length; i++)
+ Assert.assertEquals((int) list.get(i),values[i]);
+ for (int i = 0; i < values.length; i++)
+ valuesClone[rdn.nextInt(values.length)] = rdn.nextInt(1000);
+ for (int i = 0; i < values.length; i++)
+ Assert.assertEquals((int) list.get(i),valuesClone[i]);
+ }
+ }
+
+ @Test(dataProvider = "asDoubleListData")
+ public void testAsDoubleList(final double[] values) {
+ if (values == null) {
+ try {
+ Utils.asList((int[]) null);
+ Assert.fail("Should have thrown an exception");
+ } catch (final IllegalArgumentException ex) {
+ // good.
+ }
+ } else {
+ final Random rdn = GenomeAnalysisEngine.getRandomGenerator();
+ final double[] valuesClone = values.clone();
+ final List<Double> list = Utils.asList(valuesClone);
+ Assert.assertNotNull(list);
+ Assert.assertEquals(list.size(),values.length);
+ for (int i = 0; i < values.length; i++)
+ Assert.assertEquals((double) list.get(i),values[i]);
+ for (int i = 0; i < values.length; i++)
+ valuesClone[rdn.nextInt(values.length)] = rdn.nextDouble() * 1000;
+ for (int i = 0; i < values.length; i++)
+ Assert.assertEquals((double) list.get(i),valuesClone[i]);
+ }
+ }
+
+ @Test
+ public void testCalcMD5() throws Exception {
+ final File source = new File(publicTestDir + "exampleFASTA.fasta");
+ final String sourceMD5 = "36880691cf9e4178216f7b52e8d85fbe";
+
+ final byte[] sourceBytes = IOUtils.readFileIntoByteArray(source);
+ Assert.assertEquals(Utils.calcMD5(sourceBytes), sourceMD5);
+
+ final String sourceString = FileUtils.readFileToString(source);
+ Assert.assertEquals(Utils.calcMD5(sourceString), sourceMD5);
+ }
+
+ @Test
+ public void testLongestCommonOps() {
+ for ( int prefixLen = 0; prefixLen < 20; prefixLen++ ) {
+ for ( int extraSeq1Len = 0; extraSeq1Len < 10; extraSeq1Len++ ) {
+ for ( int extraSeq2Len = 0; extraSeq2Len < 10; extraSeq2Len++ ) {
+ for ( int max = 0; max < 50; max++ ) {
+ final String prefix = Utils.dupString("A", prefixLen);
+ final int expected = Math.min(prefixLen, max);
+
+ {
+ final String seq1 = prefix + Utils.dupString("C", extraSeq1Len);
+ final String seq2 = prefix + Utils.dupString("G", extraSeq1Len);
+ Assert.assertEquals(Utils.longestCommonPrefix(seq1.getBytes(), seq2.getBytes(), max), expected, "LongestCommonPrefix failed: seq1 " + seq1 + " seq2 " + seq2 + " max " + max);
+ }
+
+ {
+ final String seq1 = Utils.dupString("C", extraSeq1Len) + prefix;
+ final String seq2 = Utils.dupString("G", extraSeq1Len) + prefix;
+ Assert.assertEquals(Utils.longestCommonSuffix(seq1.getBytes(), seq2.getBytes(), max), expected, "longestCommonSuffix failed: seq1 " + seq1 + " seq2 " + seq2 + " max " + max);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @DataProvider(name = "trim")
+ public Object[][] createTrimTestData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final String s = "AAAA";
+ for ( int front = 0; front < s.length(); front++ ) {
+ for ( int back = 0; back < s.length(); back++ ) {
+ if ( front + back <= s.length() )
+ tests.add(new Object[]{s, front, back});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "trim", enabled = true)
+ public void testTrim(final String s, final int frontTrim, final int backTrim) {
+ Assert.assertEquals(s.length() - frontTrim - backTrim, Utils.trimArray(s.getBytes(), frontTrim, backTrim).length);
+ }
+
+ @Test(dataProvider = "equalRangeData", enabled = true)
+ public void testEqualRange(final byte[] array1, final byte[] array2, final int offset1, final int offset2, final int length, final boolean expected) {
+ Assert.assertEquals(Utils.equalRange(array1,offset1,array2,offset2,length),expected);
+ Assert.assertTrue(Utils.equalRange(array1,offset1,array1,offset1,length));
+ Assert.assertTrue(Utils.equalRange(array2,offset2,array2,offset2,length));
+
+ }
+
+ @DataProvider(name = "equalRangeData")
+ public Object[][] equalRangeData() {
+ return new Object[][] {
+ new Object[] { new byte[0] , new byte[0], 0, 0, 0, true},
+ new Object[] { "ABCF".getBytes(), "BC".getBytes(), 1,0,2, true },
+ new Object[] { "ABCF".getBytes(), "".getBytes(), 1,0,0, true },
+ new Object[] { "ABCF".getBytes(), "ACBF".getBytes(), 0,0, 4, false}
+ };
+
+ }
+
+ @Test(dataProvider = "skimArrayData")
+ public void testSkimArray(final String original, final String remove) {
+ final StringBuilder resultBuilder = new StringBuilder();
+ final boolean[] removeBoolean = new boolean[remove.length()];
+ for (int i = 0; i < original.length(); i++)
+ if (remove.charAt(i) == '1') {
+ resultBuilder.append(original.charAt(i));
+ removeBoolean[i] = false;
+ } else
+ removeBoolean[i] = true;
+
+ final String expected = resultBuilder.toString();
+ final byte[] resultBytes = Utils.skimArray(original.getBytes(),removeBoolean);
+ final String resultString = new String(resultBytes);
+ Assert.assertEquals(resultString,expected);
+ }
+
+ @DataProvider(name = "skimArrayData")
+ public Object[][] skimArrayData() {
+ return new Object[][] {
+ {"romeo+juliette" , "11111111111111" },
+ {"romeo+juliette" , "11111011111111" },
+ {"romeo+juliette" , "00000011111111" },
+ {"romeo+juliette" , "11111100000000" },
+ {"romeo+juliette" , "11111011111111" },
+ {"romeo+juliette" , "01111010000001" },
+ {"romeo+juliette" , "01100110000110" },
+ {"romeo+juliette" , "10101010101010" },
+ {"romeo+juliette" , "01010101010101" },
+ {"romeo+juliette" , "01111010111001" },
+ };
+ }
+
+
+ @DataProvider(name = "asIntegerListData")
+ public Object[][] asIntegerListData() {
+ return new Object[][] {
+ { null },
+ {new int[0]},
+ {new int[]{1, 2, 3, 4, 5}},
+ {new int[]{2}},
+ {new int[]{3,4}}
+ };
+ }
+
+ @DataProvider(name = "asDoubleListData")
+ public Object[][] asDoubleListData() {
+ return new Object[][] {
+ { null },
+ {new double[0]},
+ {new double[]{1, 2, 3, 4, 5}},
+ {new double[]{2}},
+ {new double[]{3,4}},
+ {new double[]{Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY}}
+ };
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/ActiveRegionUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/ActiveRegionUnitTest.java
new file mode 100644
index 0000000..41f7a76
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/ActiveRegionUnitTest.java
@@ -0,0 +1,395 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.activeregion;
+
+
+// the imports for unit testing.
+
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.*;
+
+
+public class ActiveRegionUnitTest extends BaseTest {
+ private final static boolean DEBUG = false;
+ private GenomeLocParser genomeLocParser;
+ private IndexedFastaSequenceFile seq;
+ private String contig;
+ private int contigLength;
+
+ @BeforeClass
+ public void init() throws FileNotFoundException {
+ // sequence
+ seq = new CachingIndexedFastaSequenceFile(new File(b37KGReference));
+ genomeLocParser = new GenomeLocParser(seq);
+ contig = "1";
+ contigLength = genomeLocParser.getContigInfo(contig).getSequenceLength();
+ }
+
+ @DataProvider(name = "ActionRegionCreationTest")
+ public Object[][] makePollingData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+ for ( final int start : Arrays.asList(1, 10, 100, contigLength - 10, contigLength - 1) ) {
+ for ( final int size : Arrays.asList(1, 10, 100, 1000) ) {
+ for ( final int ext : Arrays.asList(0, 1, 10, 100) ) {
+ for ( final boolean isActive : Arrays.asList(true, false) ) {
+ for ( final boolean addStates : Arrays.asList(true, false) ) {
+ List<ActivityProfileState> states = null;
+ if ( addStates ) {
+ states = new LinkedList<ActivityProfileState>();
+ for ( int i = start; i < start + size; i++ ) {
+ states.add(new ActivityProfileState(genomeLocParser.createGenomeLoc(contig, i + start), isActive ? 1.0 : 0.0));
+ }
+ }
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(contig, start, start + size - 1);
+ tests.add(new Object[]{loc, states, isActive, ext});
+ }
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "ActionRegionCreationTest")
+ public void testCreatingActiveRegions(final GenomeLoc loc, final List<ActivityProfileState> supportingStates, final boolean isActive, final int extension) {
+ final ActiveRegion region = new ActiveRegion(loc, supportingStates, isActive, genomeLocParser, extension);
+ Assert.assertEquals(region.getLocation(), loc);
+ Assert.assertEquals(region.getExtendedLoc().getStart(), Math.max(loc.getStart() - extension, 1));
+ Assert.assertEquals(region.getExtendedLoc().getStop(), Math.min(loc.getStop() + extension, contigLength));
+ Assert.assertEquals(region.getReadSpanLoc().getStart(), Math.max(loc.getStart() - extension, 1));
+ Assert.assertEquals(region.getReadSpanLoc().getStop(), Math.min(loc.getStop() + extension, contigLength));
+ Assert.assertEquals(region.isActive(), isActive);
+ Assert.assertEquals(region.getExtension(), extension);
+ Assert.assertEquals(region.getReads(), Collections.emptyList());
+ Assert.assertEquals(region.size(), 0);
+ Assert.assertEquals(region.getSupportingStates(), supportingStates == null ? Collections.emptyList() : supportingStates);
+ Assert.assertNotNull(region.toString());
+
+ assertGoodReferenceGetter(region.getActiveRegionReference(seq), region.getExtendedLoc(), 0);
+ assertGoodReferenceGetter(region.getActiveRegionReference(seq, 10), region.getExtendedLoc(), 10);
+ assertGoodReferenceGetter(region.getFullReference(seq), region.getReadSpanLoc(), 0);
+ assertGoodReferenceGetter(region.getFullReference(seq, 10), region.getReadSpanLoc(), 10);
+ }
+
+ private void assertGoodReferenceGetter(final byte[] actualBytes, final GenomeLoc span, final int padding) {
+ final int expectedStart = Math.max(span.getStart() - padding, 1);
+ final int expectedStop = Math.min(span.getStop() + padding, contigLength);
+ final byte[] expectedBytes = seq.getSubsequenceAt(span.getContig(), expectedStart, expectedStop).getBases();
+ Assert.assertEquals(actualBytes, expectedBytes);
+ }
+
+ @DataProvider(name = "ActiveRegionReads")
+ public Object[][] makeActiveRegionReads() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(seq.getSequenceDictionary());
+ for ( final int start : Arrays.asList(1, 10, 100, contigLength - 10, contigLength - 1) ) {
+ for ( final int readStartOffset : Arrays.asList(-100, -10, 0, 10, 100) ) {
+ for ( final int readSize : Arrays.asList(10, 100, 1000) ) {
+ final GenomeLoc loc = genomeLocParser.createGenomeLocOnContig(contig, start, start + 10);
+
+ final int readStart = Math.max(start + readStartOffset, 1);
+ final int readStop = Math.min(readStart + readSize, contigLength);
+ final int readLength = readStop - readStart + 1;
+ if ( readLength > 0 ) {
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read", 0, readStart, readLength);
+ final GenomeLoc readLoc = genomeLocParser.createGenomeLoc(read);
+ if ( readLoc.overlapsP(loc) )
+ tests.add(new Object[]{loc, read});
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "ActiveRegionReads")
+ public void testActiveRegionReads(final GenomeLoc loc, final GATKSAMRecord read) throws Exception {
+ final GenomeLoc expectedSpan = loc.union(genomeLocParser.createGenomeLoc(read));
+
+ final ActiveRegion region = new ActiveRegion(loc, null, true, genomeLocParser, 0);
+ final ActiveRegion region2 = new ActiveRegion(loc, null, true, genomeLocParser, 0);
+ Assert.assertEquals(region.getReads(), Collections.emptyList());
+ Assert.assertEquals(region.size(), 0);
+ Assert.assertEquals(region.getExtendedLoc(), loc);
+ Assert.assertEquals(region.getReadSpanLoc(), loc);
+ Assert.assertTrue(region.equalExceptReads(region2));
+
+ region.add(read);
+ Assert.assertEquals(region.getReads(), Collections.singletonList(read));
+ Assert.assertEquals(region.size(), 1);
+ Assert.assertEquals(region.getExtendedLoc(), loc);
+ Assert.assertEquals(region.getReadSpanLoc(), expectedSpan);
+ Assert.assertTrue(region.equalExceptReads(region2));
+
+ region.clearReads();
+ Assert.assertEquals(region.getReads(), Collections.emptyList());
+ Assert.assertEquals(region.size(), 0);
+ Assert.assertEquals(region.getExtendedLoc(), loc);
+ Assert.assertEquals(region.getReadSpanLoc(), loc);
+ Assert.assertTrue(region.equalExceptReads(region2));
+
+ region.addAll(Collections.singleton(read));
+ Assert.assertEquals(region.getReads(), Collections.singletonList(read));
+ Assert.assertEquals(region.size(), 1);
+ Assert.assertEquals(region.getExtendedLoc(), loc);
+ Assert.assertEquals(region.getReadSpanLoc(), expectedSpan);
+ Assert.assertTrue(region.equalExceptReads(region2));
+
+ region.removeAll(Collections.<GATKSAMRecord>emptySet());
+ Assert.assertEquals(region.getReads(), Collections.singletonList(read));
+ Assert.assertEquals(region.size(), 1);
+ Assert.assertEquals(region.getExtendedLoc(), loc);
+ Assert.assertEquals(region.getReadSpanLoc(), expectedSpan);
+ Assert.assertTrue(region.equalExceptReads(region2));
+
+ region.removeAll(Collections.singleton(read));
+ Assert.assertEquals(region.getReads(), Collections.emptyList());
+ Assert.assertEquals(region.size(), 0);
+ Assert.assertEquals(region.getExtendedLoc(), loc);
+ Assert.assertEquals(region.getReadSpanLoc(), loc);
+ Assert.assertTrue(region.equalExceptReads(region2));
+
+ final GATKSAMRecord read2 = (GATKSAMRecord)read.clone();
+ read2.setReadName(read.getReadName() + ".clone");
+
+ for ( final GATKSAMRecord readToKeep : Arrays.asList(read, read2)) {
+ region.addAll(Arrays.asList(read, read2));
+ final GATKSAMRecord readToDiscard = readToKeep == read ? read2 : read;
+ region.removeAll(Collections.singleton(readToDiscard));
+ Assert.assertEquals(region.getReads(), Arrays.asList(readToKeep));
+ Assert.assertEquals(region.size(), 1);
+ Assert.assertEquals(region.getExtendedLoc(), loc);
+ }
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ //
+ // Make sure bad inputs are properly detected
+ //
+ // -----------------------------------------------------------------------------------------------
+
+ @DataProvider(name = "BadReadsTest")
+ public Object[][] makeBadReadsTest() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(seq.getSequenceDictionary());
+ tests.add(new Object[]{
+ ArtificialSAMUtils.createArtificialRead(header, "read1", 0, 10, 10),
+ ArtificialSAMUtils.createArtificialRead(header, "read2", 0, 9, 10)});
+ tests.add(new Object[]{
+ ArtificialSAMUtils.createArtificialRead(header, "read1", 0, 10, 10),
+ ArtificialSAMUtils.createArtificialRead(header, "read2", 1, 9, 10)});
+ tests.add(new Object[]{
+ ArtificialSAMUtils.createArtificialRead(header, "read1", 1, 10, 10),
+ ArtificialSAMUtils.createArtificialRead(header, "read2", 0, 9, 10)});
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "BadReadsTest", expectedExceptions = IllegalArgumentException.class)
+ public void testBadReads(final GATKSAMRecord read1, final GATKSAMRecord read2) {
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(read1);
+ final ActiveRegion region = new ActiveRegion(loc, null, true, genomeLocParser, 0);
+ region.add(read1);
+ region.add(read2);
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ //
+ // Make sure we can properly cut up an active region based on engine intervals
+ //
+ // -----------------------------------------------------------------------------------------------
+
+ @DataProvider(name = "SplitActiveRegion")
+ public Object[][] makeSplitActiveRegion() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final GenomeLoc whole_span = genomeLocParser.createGenomeLoc("20", 1, 500);
+ final GenomeLoc gl_before = genomeLocParser.createGenomeLoc("20", 1, 9);
+ final GenomeLoc gl_after = genomeLocParser.createGenomeLoc("20", 250, 500);
+ final GenomeLoc gl_diff_contig = genomeLocParser.createGenomeLoc("19", 40, 50);
+
+ final int regionStart = 10;
+ final int regionStop = 100;
+ final GenomeLoc region = genomeLocParser.createGenomeLoc("20", regionStart, regionStop);
+
+ for ( final GenomeLoc noEffect : Arrays.asList(whole_span) )
+ tests.add(new Object[]{
+ region,
+ Arrays.asList(noEffect),
+ Arrays.asList(region)});
+
+ for ( final GenomeLoc noOverlap : Arrays.asList(gl_before, gl_after, gl_diff_contig) )
+ tests.add(new Object[]{
+ region,
+ Arrays.asList(noOverlap),
+ Arrays.asList()});
+
+ tests.add(new Object[]{region,
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", 5, 50)),
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", regionStart, 50))});
+
+ tests.add(new Object[]{region,
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", 50, 200)),
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", 50, regionStop))});
+
+ tests.add(new Object[]{region,
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", 40, 50)),
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", 40, 50))});
+
+ tests.add(new Object[]{region,
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", 20, 30), genomeLocParser.createGenomeLoc("20", 40, 50)),
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", 20, 30), genomeLocParser.createGenomeLoc("20", 40, 50))});
+
+ tests.add(new Object[]{region,
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", 1, 30), genomeLocParser.createGenomeLoc("20", 40, 50)),
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", regionStart, 30), genomeLocParser.createGenomeLoc("20", 40, 50))});
+
+ tests.add(new Object[]{region,
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", 1, 30), genomeLocParser.createGenomeLoc("20", 70, 200)),
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", regionStart, 30), genomeLocParser.createGenomeLoc("20", 70, regionStop))});
+
+ tests.add(new Object[]{region,
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", 1, 30), genomeLocParser.createGenomeLoc("20", 40, 50), genomeLocParser.createGenomeLoc("20", 70, 200)),
+ Arrays.asList(genomeLocParser.createGenomeLoc("20", regionStart, 30), genomeLocParser.createGenomeLoc("20", 40, 50), genomeLocParser.createGenomeLoc("20", 70, regionStop))});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "SplitActiveRegion")
+ public void testSplitActiveRegion(final GenomeLoc regionLoc, final List<GenomeLoc> intervalLocs, final List<GenomeLoc> expectedRegionLocs) {
+ for ( final boolean addSubstates : Arrays.asList(true, false) ) {
+ final List<ActivityProfileState> states;
+ if ( addSubstates ) {
+ states = new LinkedList<ActivityProfileState>();
+ for ( int i = 0; i < regionLoc.size(); i++ )
+ states.add(new ActivityProfileState(genomeLocParser.createGenomeLoc(regionLoc.getContig(), regionLoc.getStart() + i), 1.0));
+ } else {
+ states = null;
+ }
+
+ final ActiveRegion region = new ActiveRegion(regionLoc, states, true, genomeLocParser, 0);
+ final GenomeLocSortedSet intervals = new GenomeLocSortedSet(genomeLocParser, intervalLocs);
+ final List<ActiveRegion> regions = region.splitAndTrimToIntervals(intervals);
+
+ Assert.assertEquals(regions.size(), expectedRegionLocs.size(), "Wrong number of split locations");
+ for ( int i = 0; i < expectedRegionLocs.size(); i++ ) {
+ final GenomeLoc expected = expectedRegionLocs.get(i);
+ final ActiveRegion actual = regions.get(i);
+ Assert.assertEquals(actual.getLocation(), expected, "Bad region after split");
+ Assert.assertEquals(actual.isActive(), region.isActive());
+ Assert.assertEquals(actual.getExtension(), region.getExtension());
+ }
+ }
+ }
+
+ // -----------------------------------------------------------------------------------------------
+ //
+ // Make sure we can properly cut up an active region based on engine intervals
+ //
+ // -----------------------------------------------------------------------------------------------
+
+ @DataProvider(name = "TrimActiveRegionData")
+ public Object[][] makeTrimActiveRegionData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ // fully enclosed within active region
+ tests.add(new Object[]{
+ genomeLocParser.createGenomeLoc("20", 10, 20), 10,
+ genomeLocParser.createGenomeLoc("20", 15, 16),
+ genomeLocParser.createGenomeLoc("20", 15, 16), 0});
+
+ tests.add(new Object[]{
+ genomeLocParser.createGenomeLoc("20", 10, 20), 10,
+ genomeLocParser.createGenomeLoc("20", 10, 15),
+ genomeLocParser.createGenomeLoc("20", 10, 15), 0});
+
+ tests.add(new Object[]{
+ genomeLocParser.createGenomeLoc("20", 10, 20), 10,
+ genomeLocParser.createGenomeLoc("20", 15, 20),
+ genomeLocParser.createGenomeLoc("20", 15, 20), 0});
+
+ // needs extra padding on the right
+ tests.add(new Object[]{
+ genomeLocParser.createGenomeLoc("20", 10, 20), 10,
+ genomeLocParser.createGenomeLoc("20", 15, 25),
+ genomeLocParser.createGenomeLoc("20", 15, 20), 5});
+
+ // needs extra padding on the left
+ tests.add(new Object[]{
+ genomeLocParser.createGenomeLoc("20", 10, 20), 10,
+ genomeLocParser.createGenomeLoc("20", 5, 15),
+ genomeLocParser.createGenomeLoc("20", 10, 15), 5});
+
+ // needs extra padding on both
+ tests.add(new Object[]{
+ genomeLocParser.createGenomeLoc("20", 10, 20), 10,
+ genomeLocParser.createGenomeLoc("20", 7, 21),
+ genomeLocParser.createGenomeLoc("20", 10, 20), 3});
+ tests.add(new Object[]{
+ genomeLocParser.createGenomeLoc("20", 10, 20), 10,
+ genomeLocParser.createGenomeLoc("20", 9, 23),
+ genomeLocParser.createGenomeLoc("20", 10, 20), 3});
+
+ // desired span captures everything, so we're returning everything. Tests that extension is set correctly
+ tests.add(new Object[]{
+ genomeLocParser.createGenomeLoc("20", 10, 20), 10,
+ genomeLocParser.createGenomeLoc("20", 1, 50),
+ genomeLocParser.createGenomeLoc("20", 10, 20), 10});
+
+ // At the start of the chromosome, potentially a bit weird
+ tests.add(new Object[]{
+ genomeLocParser.createGenomeLoc("20", 1, 10), 10,
+ genomeLocParser.createGenomeLoc("20", 1, 50),
+ genomeLocParser.createGenomeLoc("20", 1, 10), 10});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "TrimActiveRegionData")
+ public void testTrimActiveRegion(final GenomeLoc regionLoc, final int extension, final GenomeLoc desiredSpan, final GenomeLoc expectedActiveRegion, final int expectedExtension) {
+ final ActiveRegion region = new ActiveRegion(regionLoc, Collections.<ActivityProfileState>emptyList(), true, genomeLocParser, extension);
+ final ActiveRegion trimmed = region.trim(desiredSpan);
+ Assert.assertEquals(trimmed.getLocation(), expectedActiveRegion, "Incorrect region");
+ Assert.assertEquals(trimmed.getExtension(), expectedExtension, "Incorrect region");
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfileStateUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfileStateUnitTest.java
new file mode 100644
index 0000000..75e9d9a
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfileStateUnitTest.java
@@ -0,0 +1,92 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.activeregion;
+
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.FileNotFoundException;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: depristo
+ * Date: 1/17/13
+ * Time: 2:30 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ActivityProfileStateUnitTest {
+ private GenomeLocParser genomeLocParser;
+
+ @BeforeClass
+ public void init() throws FileNotFoundException {
+ // sequence
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 100);
+ genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ }
+
+ @DataProvider(name = "ActiveProfileResultProvider")
+ public Object[][] makeActiveProfileResultProvider() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ final String chr = genomeLocParser.getContigs().getSequence(0).getSequenceName();
+ for ( final GenomeLoc loc : Arrays.asList(
+ genomeLocParser.createGenomeLoc(chr, 10, 10),
+ genomeLocParser.createGenomeLoc(chr, 100, 100) )) {
+ for ( final double prob : Arrays.asList(0.0, 0.5, 1.0) ) {
+ for ( final ActivityProfileState.Type state : ActivityProfileState.Type.values() ) {
+ for ( final Number value : Arrays.asList(1, 2, 4) ) {
+ tests.add(new Object[]{ loc, prob, state, value});
+ }
+ }
+ tests.add(new Object[]{ loc, prob, null, null});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "ActiveProfileResultProvider")
+ public void testActiveProfileResultProvider(GenomeLoc loc, final double prob, ActivityProfileState.Type maybeState, final Number maybeNumber) {
+ final ActivityProfileState apr = maybeState == null
+ ? new ActivityProfileState(loc, prob)
+ : new ActivityProfileState(loc, prob, maybeState, maybeNumber);
+
+ Assert.assertEquals(apr.getLoc(), loc);
+ Assert.assertNotNull(apr.toString());
+ Assert.assertEquals(apr.isActiveProb, prob);
+ Assert.assertEquals(apr.resultState, maybeState == null ? ActivityProfileState.Type.NONE : maybeState);
+ Assert.assertEquals(apr.resultValue, maybeState == null ? null : maybeNumber);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfileUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfileUnitTest.java
new file mode 100644
index 0000000..b3442b3
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/ActivityProfileUnitTest.java
@@ -0,0 +1,491 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.activeregion;
+
+
+// the imports for unit testing.
+
+
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.*;
+
+
+public class ActivityProfileUnitTest extends BaseTest {
+ private final static boolean DEBUG = false;
+ private GenomeLocParser genomeLocParser;
+ private GenomeLoc startLoc;
+
+ private final static int MAX_PROB_PROPAGATION_DISTANCE = 50;
+ private final static double ACTIVE_PROB_THRESHOLD= 0.002;
+
+ @BeforeClass
+ public void init() throws FileNotFoundException {
+ // sequence
+ ReferenceSequenceFile seq = new CachingIndexedFastaSequenceFile(new File(hg18Reference));
+ genomeLocParser = new GenomeLocParser(seq);
+ startLoc = genomeLocParser.createGenomeLoc("chr1", 1, 1, 100);
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Basic tests Provider
+ //
+ // --------------------------------------------------------------------------------
+
+ private class BasicActivityProfileTestProvider extends TestDataProvider {
+ List<Double> probs;
+ List<ActiveRegion> expectedRegions;
+ int extension = 0;
+ GenomeLoc regionStart = startLoc;
+ final ProfileType type;
+
+ public BasicActivityProfileTestProvider(final ProfileType type, final List<Double> probs, boolean startActive, int ... startsAndStops) {
+ super(BasicActivityProfileTestProvider.class);
+ this.type = type;
+ this.probs = probs;
+ this.expectedRegions = toRegions(startActive, startsAndStops);
+ setName(getName());
+ }
+
+ private String getName() {
+ return String.format("type=%s probs=%s expectedRegions=%s", type, Utils.join(",", probs), Utils.join(",", expectedRegions));
+ }
+
+ public ActivityProfile makeProfile() {
+ switch ( type ) {
+ case Base: return new ActivityProfile(genomeLocParser, MAX_PROB_PROPAGATION_DISTANCE, ACTIVE_PROB_THRESHOLD);
+ case BandPass:
+ // zero size => equivalent to ActivityProfile
+ return new BandPassActivityProfile(genomeLocParser, null, MAX_PROB_PROPAGATION_DISTANCE, ACTIVE_PROB_THRESHOLD, 0, 0.01, false);
+ default: throw new IllegalStateException(type.toString());
+ }
+ }
+
+ private List<ActiveRegion> toRegions(boolean isActive, int[] startsAndStops) {
+ List<ActiveRegion> l = new ArrayList<ActiveRegion>();
+ for ( int i = 0; i < startsAndStops.length - 1; i++) {
+ int start = regionStart.getStart() + startsAndStops[i];
+ int end = regionStart.getStart() + startsAndStops[i+1] - 1;
+ GenomeLoc activeLoc = genomeLocParser.createGenomeLoc(regionStart.getContig(), start, end);
+ ActiveRegion r = new ActiveRegion(activeLoc, Collections.<ActivityProfileState>emptyList(), isActive, genomeLocParser, extension);
+ l.add(r);
+ isActive = ! isActive;
+ }
+ return l;
+ }
+ }
+
+ private enum ProfileType {
+ Base, BandPass
+ }
+
+ @DataProvider(name = "BasicActivityProfileTestProvider")
+ public Object[][] makeQualIntervalTestProvider() {
+ for ( final ProfileType type : ProfileType.values() ) {
+ new BasicActivityProfileTestProvider(type, Arrays.asList(1.0), true, 0, 1);
+ new BasicActivityProfileTestProvider(type, Arrays.asList(1.0, 0.0), true, 0, 1, 2);
+ new BasicActivityProfileTestProvider(type, Arrays.asList(0.0, 1.0), false, 0, 1, 2);
+ new BasicActivityProfileTestProvider(type, Arrays.asList(1.0, 0.0, 1.0), true, 0, 1, 2, 3);
+ new BasicActivityProfileTestProvider(type, Arrays.asList(1.0, 1.0, 1.0), true, 0, 3);
+ }
+
+ return BasicActivityProfileTestProvider.getTests(BasicActivityProfileTestProvider.class);
+ }
+
+ @Test(enabled = ! DEBUG, dataProvider = "BasicActivityProfileTestProvider")
+ public void testBasicActivityProfile(BasicActivityProfileTestProvider cfg) {
+ ActivityProfile profile = cfg.makeProfile();
+
+ Assert.assertTrue(profile.isEmpty());
+
+ Assert.assertEquals(profile.parser, genomeLocParser);
+
+ for ( int i = 0; i < cfg.probs.size(); i++ ) {
+ double p = cfg.probs.get(i);
+ GenomeLoc loc = genomeLocParser.createGenomeLoc(cfg.regionStart.getContig(), cfg.regionStart.getStart() + i, cfg.regionStart.getStart() + i);
+ profile.add(new ActivityProfileState(loc, p));
+ Assert.assertFalse(profile.isEmpty(), "Profile shouldn't be empty after adding a state");
+ }
+ Assert.assertEquals(profile.regionStartLoc, genomeLocParser.createGenomeLoc(cfg.regionStart.getContig(), cfg.regionStart.getStart(), cfg.regionStart.getStart() ), "Start loc should be the start of the region");
+
+ Assert.assertEquals(profile.size(), cfg.probs.size(), "Should have exactly the number of states we expected to add");
+ assertProbsAreEqual(profile.stateList, cfg.probs);
+
+ // TODO -- reanble tests
+ //assertRegionsAreEqual(profile.createActiveRegions(0, 100), cfg.expectedRegions);
+ }
+
+ private void assertRegionsAreEqual(List<ActiveRegion> actual, List<ActiveRegion> expected) {
+ Assert.assertEquals(actual.size(), expected.size());
+ for ( int i = 0; i < actual.size(); i++ ) {
+ Assert.assertTrue(actual.get(i).equalExceptReads(expected.get(i)));
+ }
+ }
+
+ private void assertProbsAreEqual(List<ActivityProfileState> actual, List<Double> expected) {
+ Assert.assertEquals(actual.size(), expected.size());
+ for ( int i = 0; i < actual.size(); i++ ) {
+ Assert.assertEquals(actual.get(i).isActiveProb, expected.get(i));
+ }
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // Hardcore tests for adding to the profile and constructing active regions
+ //
+ // -------------------------------------------------------------------------------------
+
+ private static class SizeToStringList<T> extends ArrayList<T> {
+ @Override public String toString() { return "List[" + size() + "]"; }
+ }
+
+ @DataProvider(name = "RegionCreationTests")
+ public Object[][] makeRegionCreationTests() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ final int contigLength = genomeLocParser.getContigs().getSequences().get(0).getSequenceLength();
+ for ( int start : Arrays.asList(1, 10, 100, contigLength - 100, contigLength - 10) ) {
+ for ( int regionSize : Arrays.asList(1, 10, 100, 1000, 10000) ) {
+ for ( int maxRegionSize : Arrays.asList(10, 50, 200) ) {
+ for ( final boolean waitUntilEnd : Arrays.asList(false, true) ) {
+ for ( final boolean forceConversion : Arrays.asList(false, true) ) {
+ // what do I really want to test here? I'd like to test a few cases:
+ // -- region is all active (1.0)
+ // -- region is all inactive (0.0)
+ // -- cut the interval into 1, 2, 3, 4, 5 ... 10 regions, each with alternating activity values
+ for ( final boolean startWithActive : Arrays.asList(true, false) ) {
+ for ( int nParts : Arrays.asList(1, 2, 3, 4, 5, 7, 10, 11, 13) ) {
+
+// for ( int start : Arrays.asList(1) ) {
+// for ( int regionSize : Arrays.asList(100) ) {
+// for ( int maxRegionSize : Arrays.asList(10) ) {
+// for ( final boolean waitUntilEnd : Arrays.asList(true) ) {
+// for ( final boolean forceConversion : Arrays.asList(false) ) {
+// for ( final boolean startWithActive : Arrays.asList(true) ) {
+// for ( int nParts : Arrays.asList(3) ) {
+ regionSize = Math.min(regionSize, contigLength - start);
+ final List<Boolean> regions = makeRegions(regionSize, startWithActive, nParts);
+ tests.add(new Object[]{ start, regions, maxRegionSize, nParts, forceConversion, waitUntilEnd });
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ private List<Boolean> makeRegions(final int totalRegionSize,
+ final boolean startWithActive,
+ final int nParts) {
+ final List<Boolean> regions = new SizeToStringList<Boolean>();
+
+ boolean isActive = startWithActive;
+ final int activeRegionSize = Math.max(totalRegionSize / nParts, 1);
+ for ( int i = 0; i < totalRegionSize; i += activeRegionSize ) {
+ for ( int j = 0; j < activeRegionSize && j + i < totalRegionSize; j++ ) {
+ regions.add(isActive);
+ }
+ isActive = ! isActive;
+ }
+
+ return regions;
+ }
+
+
+ @Test(enabled = !DEBUG, dataProvider = "RegionCreationTests")
+ public void testRegionCreation(final int start, final List<Boolean> probs, int maxRegionSize, final int nParts, final boolean forceConversion, final boolean waitUntilEnd) {
+ final ActivityProfile profile = new ActivityProfile(genomeLocParser, MAX_PROB_PROPAGATION_DISTANCE, ACTIVE_PROB_THRESHOLD);
+ Assert.assertNotNull(profile.toString());
+
+ final String contig = genomeLocParser.getContigs().getSequences().get(0).getSequenceName();
+ final List<Boolean> seenSites = new ArrayList<Boolean>(Collections.nCopies(probs.size(), false));
+ ActiveRegion lastRegion = null;
+ for ( int i = 0; i < probs.size(); i++ ) {
+ final boolean isActive = probs.get(i);
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(contig, i + start);
+ final ActivityProfileState state = new ActivityProfileState(loc, isActive ? 1.0 : 0.0);
+ profile.add(state);
+ Assert.assertNotNull(profile.toString());
+
+ if ( ! waitUntilEnd ) {
+ final List<ActiveRegion> regions = profile.popReadyActiveRegions(0, 1, maxRegionSize, false);
+ lastRegion = assertGoodRegions(start, regions, maxRegionSize, lastRegion, probs, seenSites);
+ }
+ }
+
+ if ( waitUntilEnd || forceConversion ) {
+ final List<ActiveRegion> regions = profile.popReadyActiveRegions(0, 1, maxRegionSize, forceConversion);
+ lastRegion = assertGoodRegions(start, regions, maxRegionSize, lastRegion, probs, seenSites);
+ }
+
+ for ( int i = 0; i < probs.size(); i++ ) {
+ if ( forceConversion || (i + maxRegionSize + profile.getMaxProbPropagationDistance() < probs.size()))
+ // only require a site to be seen if we are forcing conversion or the site is more than maxRegionSize from the end
+ Assert.assertTrue(seenSites.get(i), "Missed site " + i);
+ }
+
+ Assert.assertNotNull(profile.toString());
+ }
+
+ private ActiveRegion assertGoodRegions(final int start, final List<ActiveRegion> regions, final int maxRegionSize, ActiveRegion lastRegion, final List<Boolean> probs, final List<Boolean> seenSites) {
+ for ( final ActiveRegion region : regions ) {
+ Assert.assertTrue(region.getLocation().size() > 0, "Region " + region + " has a bad size");
+ Assert.assertTrue(region.getLocation().size() <= maxRegionSize, "Region " + region + " has a bad size: it's big than the max region size " + maxRegionSize);
+ if ( lastRegion != null ) {
+ Assert.assertTrue(region.getLocation().getStart() == lastRegion.getLocation().getStop() + 1, "Region " + region + " doesn't start immediately after previous region" + lastRegion);
+ }
+
+ // check that all active bases are actually active
+ final int regionOffset = region.getLocation().getStart() - start;
+ Assert.assertTrue(regionOffset >= 0 && regionOffset < probs.size(), "Region " + region + " has a bad offset w.r.t. start");
+ for ( int j = 0; j < region.getLocation().size(); j++ ) {
+ final int siteOffset = j + regionOffset;
+ Assert.assertEquals(region.isActive(), probs.get(siteOffset).booleanValue());
+ Assert.assertFalse(seenSites.get(siteOffset), "Site " + j + " in " + region + " was seen already");
+ seenSites.set(siteOffset, true);
+ }
+
+ lastRegion = region;
+ }
+
+ return lastRegion;
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // Hardcore tests for adding to the profile and constructing active regions
+ //
+ // -------------------------------------------------------------------------------------
+
+ @DataProvider(name = "SoftClipsTest")
+ public Object[][] makeSoftClipsTest() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ final int contigLength = genomeLocParser.getContigs().getSequences().get(0).getSequenceLength();
+ for ( int start : Arrays.asList(1, 10, 100, contigLength - 100, contigLength - 10, contigLength - 1) ) {
+ for ( int precedingSites: Arrays.asList(0, 1, 10) ) {
+ if ( precedingSites + start < contigLength ) {
+ for ( int softClipSize : Arrays.asList(1, 2, 10, 100) ) {
+// for ( int start : Arrays.asList(10) ) {
+// for ( int precedingSites: Arrays.asList(10) ) {
+// for ( int softClipSize : Arrays.asList(1) ) {
+ tests.add(new Object[]{ start, precedingSites, softClipSize });
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = ! DEBUG, dataProvider = "SoftClipsTest")
+ public void testSoftClips(final int start, int nPrecedingSites, final int softClipSize) {
+ final ActivityProfile profile = new ActivityProfile(genomeLocParser, MAX_PROB_PROPAGATION_DISTANCE, ACTIVE_PROB_THRESHOLD);
+
+ final int contigLength = genomeLocParser.getContigs().getSequences().get(0).getSequenceLength();
+ final String contig = genomeLocParser.getContigs().getSequences().get(0).getSequenceName();
+ for ( int i = 0; i < nPrecedingSites; i++ ) {
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(contig, i + start);
+ final ActivityProfileState state = new ActivityProfileState(loc, 0.0);
+ profile.add(state);
+ }
+
+ final GenomeLoc softClipLoc = genomeLocParser.createGenomeLoc(contig, nPrecedingSites + start);
+ profile.add(new ActivityProfileState(softClipLoc, 1.0, ActivityProfileState.Type.HIGH_QUALITY_SOFT_CLIPS, softClipSize));
+
+ final int actualNumOfSoftClips = Math.min(softClipSize, profile.getMaxProbPropagationDistance());
+ if ( nPrecedingSites == 0 ) {
+ final int profileSize = Math.min(start + actualNumOfSoftClips, contigLength) - start + 1;
+ Assert.assertEquals(profile.size(), profileSize, "Wrong number of states in the profile");
+ }
+
+ for ( int i = 0; i < profile.size(); i++ ) {
+ final ActivityProfileState state = profile.getStateList().get(i);
+ final boolean withinSCRange = state.getLoc().distance(softClipLoc) <= actualNumOfSoftClips;
+ if ( withinSCRange ) {
+ Assert.assertTrue(state.isActiveProb > 0.0, "active prob should be changed within soft clip size");
+ } else {
+ Assert.assertEquals(state.isActiveProb, 0.0, "active prob shouldn't be changed outside of clip size");
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // Tests to ensure we cut large active regions in the right place
+ //
+ // -------------------------------------------------------------------------------------
+
+ private void addProb(final List<Double> l, final double v) {
+ l.add(v);
+ }
+
+ @DataProvider(name = "ActiveRegionCutTests")
+ public Object[][] makeActiveRegionCutTests() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+// for ( final int activeRegionSize : Arrays.asList(30) ) {
+// for ( final int minRegionSize : Arrays.asList(5) ) {
+ for ( final int activeRegionSize : Arrays.asList(10, 12, 20, 30, 40) ) {
+ for ( final int minRegionSize : Arrays.asList(1, 5, 10) ) {
+ final int maxRegionSize = activeRegionSize * 2 / 3;
+ if ( minRegionSize >= maxRegionSize ) continue;
+ { // test flat activity profile
+ final List<Double> probs = Collections.nCopies(activeRegionSize, 1.0);
+ tests.add(new Object[]{minRegionSize, maxRegionSize, maxRegionSize, probs});
+ }
+
+ { // test point profile is properly handled
+ for ( int end = 1; end < activeRegionSize; end++ ) {
+ final List<Double> probs = Collections.nCopies(end, 1.0);
+ tests.add(new Object[]{minRegionSize, maxRegionSize, Math.min(end, maxRegionSize), probs});
+ }
+ }
+
+ { // test increasing activity profile
+ final List<Double> probs = new ArrayList<Double>(activeRegionSize);
+ for ( int i = 0; i < activeRegionSize; i++ ) {
+ addProb(probs, (1.0*(i+1))/ activeRegionSize);
+ }
+ tests.add(new Object[]{minRegionSize, maxRegionSize, maxRegionSize, probs});
+ }
+
+ { // test decreasing activity profile
+ final List<Double> probs = new ArrayList<Double>(activeRegionSize);
+ for ( int i = 0; i < activeRegionSize; i++ ) {
+ addProb(probs, 1 - (1.0*(i+1))/ activeRegionSize);
+ }
+ tests.add(new Object[]{minRegionSize, maxRegionSize, maxRegionSize, probs});
+ }
+
+ { // test two peaks
+// for ( final double rootSigma : Arrays.asList(2.0) ) {
+// int maxPeak1 = 9; {
+// int maxPeak2 = 16; {
+ for ( final double rootSigma : Arrays.asList(1.0, 2.0, 3.0) ) {
+ for ( int maxPeak1 = 0; maxPeak1 < activeRegionSize / 2; maxPeak1++ ) {
+ for ( int maxPeak2 = activeRegionSize / 2 + 1; maxPeak2 < activeRegionSize; maxPeak2++ ) {
+ final double[] gauss1 = makeGaussian(maxPeak1, activeRegionSize, rootSigma);
+ final double[] gauss2 = makeGaussian(maxPeak2, activeRegionSize, rootSigma+1);
+ final List<Double> probs = new ArrayList<Double>(activeRegionSize);
+ for ( int i = 0; i < activeRegionSize; i++ ) {
+ addProb(probs, gauss1[i] + gauss2[i]);
+ }
+ final int cutSite = findCutSiteForTwoMaxPeaks(probs, minRegionSize);
+ if ( cutSite != -1 && cutSite < maxRegionSize )
+ tests.add(new Object[]{minRegionSize, maxRegionSize, Math.max(cutSite, minRegionSize), probs});
+ }
+ }
+ }
+ }
+
+ { // test that the lowest of two minima is taken
+ // looks like a bunch of 1s, 0.5, some 1.0s, 0.75, some more 1s
+// int firstMin = 0; {
+// int secondMin = 4; {
+ for ( int firstMin = 1; firstMin < activeRegionSize; firstMin++ ) {
+ for ( int secondMin = firstMin + 1; secondMin < activeRegionSize; secondMin++ ) {
+ final List<Double> probs = new ArrayList<Double>(Collections.nCopies(activeRegionSize, 1.0));
+ probs.set(firstMin, 0.5);
+ probs.set(secondMin, 0.75);
+ final int expectedCut;
+ if ( firstMin + 1 < minRegionSize ) {
+ if ( firstMin == secondMin - 1 ) // edge case for non-min at minRegionSize
+ expectedCut = maxRegionSize;
+ else
+ expectedCut = secondMin + 1 > maxRegionSize ? maxRegionSize : ( secondMin + 1 < minRegionSize ? maxRegionSize : secondMin + 1);
+ } else if ( firstMin + 1 > maxRegionSize )
+ expectedCut = maxRegionSize;
+ else {
+ expectedCut = firstMin + 1;
+ }
+
+ Math.min(firstMin + 1, maxRegionSize);
+ tests.add(new Object[]{minRegionSize, maxRegionSize, expectedCut, probs});
+ }
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ private double[] makeGaussian(final int mean, final int range, final double sigma) {
+ final double[] gauss = new double[range];
+ for( int iii = 0; iii < range; iii++ ) {
+ gauss[iii] = MathUtils.normalDistribution(mean, sigma, iii) + ACTIVE_PROB_THRESHOLD;
+ }
+ return gauss;
+ }
+
+ private int findCutSiteForTwoMaxPeaks(final List<Double> probs, final int minRegionSize) {
+ for ( int i = probs.size() - 2; i > minRegionSize; i-- ) {
+ double prev = probs.get(i - 1);
+ double next = probs.get(i + 1);
+ double cur = probs.get(i);
+ if ( cur < next && cur < prev )
+ return i + 1;
+ }
+
+ return -1;
+ }
+
+ @Test(dataProvider = "ActiveRegionCutTests")
+ public void testActiveRegionCutTests(final int minRegionSize, final int maxRegionSize, final int expectedRegionSize, final List<Double> probs) {
+ final ActivityProfile profile = new ActivityProfile(genomeLocParser, MAX_PROB_PROPAGATION_DISTANCE, ACTIVE_PROB_THRESHOLD);
+
+ final String contig = genomeLocParser.getContigs().getSequences().get(0).getSequenceName();
+ for ( int i = 0; i <= maxRegionSize + profile.getMaxProbPropagationDistance(); i++ ) {
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(contig, i + 1);
+ final double prob = i < probs.size() ? probs.get(i) : 0.0;
+ final ActivityProfileState state = new ActivityProfileState(loc, prob);
+ profile.add(state);
+ }
+
+ final List<ActiveRegion> regions = profile.popReadyActiveRegions(0, minRegionSize, maxRegionSize, false);
+ Assert.assertTrue(regions.size() >= 1, "Should only be one regions for this test");
+ final ActiveRegion region = regions.get(0);
+ Assert.assertEquals(region.getLocation().getStart(), 1, "Region should start at 1");
+ Assert.assertEquals(region.getLocation().size(), expectedRegionSize, "Incorrect region size; cut must have been incorrect");
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/BandPassActivityProfileUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/BandPassActivityProfileUnitTest.java
new file mode 100644
index 0000000..2087d9a
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/activeregion/BandPassActivityProfileUnitTest.java
@@ -0,0 +1,339 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.activeregion;
+
+
+// the imports for unit testing.
+
+
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import org.apache.commons.lang.ArrayUtils;
+import htsjdk.tribble.readers.LineIterator;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.broadinstitute.gatk.utils.variant.GATKVCFUtils;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.vcf.VCFCodec;
+import htsjdk.variant.vcf.VCFHeader;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+
+public class BandPassActivityProfileUnitTest extends BaseTest {
+ private final static boolean DEBUG = false;
+ private GenomeLocParser genomeLocParser;
+
+ private final static int MAX_PROB_PROPAGATION_DISTANCE = 50;
+ private final static double ACTIVE_PROB_THRESHOLD= 0.002;
+
+ @BeforeClass
+ public void init() throws FileNotFoundException {
+ // sequence
+ ReferenceSequenceFile seq = new CachingIndexedFastaSequenceFile(new File(b37KGReference));
+ genomeLocParser = new GenomeLocParser(seq);
+ }
+
+ @DataProvider(name = "BandPassBasicTest")
+ public Object[][] makeBandPassTest() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ for ( int start : Arrays.asList(1, 10, 100, 1000) ) {
+ for ( boolean precedingIsActive : Arrays.asList(true, false) ) {
+ for ( int precedingSites: Arrays.asList(0, 1, 10, 100) ) {
+ for ( int bandPassSize : Arrays.asList(0, 1, 10, 100) ) {
+ for ( double sigma : Arrays.asList(1.0, 2.0, BandPassActivityProfile.DEFAULT_SIGMA) ) {
+// for ( int start : Arrays.asList(10) ) {
+// for ( boolean precedingIsActive : Arrays.asList(false) ) {
+// for ( int precedingSites: Arrays.asList(0) ) {
+// for ( int bandPassSize : Arrays.asList(1) ) {
+ tests.add(new Object[]{ start, precedingIsActive, precedingSites, bandPassSize, sigma });
+ }
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = ! DEBUG, dataProvider = "BandPassBasicTest")
+ public void testBandPass(final int start, final boolean precedingIsActive, final int nPrecedingSites, final int bandPassSize, final double sigma) {
+ final BandPassActivityProfile profile = new BandPassActivityProfile(genomeLocParser, null, MAX_PROB_PROPAGATION_DISTANCE, ACTIVE_PROB_THRESHOLD, bandPassSize, sigma, false);
+
+ final int expectedBandSize = bandPassSize * 2 + 1;
+ Assert.assertEquals(profile.getFilteredSize(), bandPassSize, "Wrong filter size");
+ Assert.assertEquals(profile.getSigma(), sigma, "Wrong sigma");
+ Assert.assertEquals(profile.getBandSize(), expectedBandSize, "Wrong expected band size");
+
+ final String contig = genomeLocParser.getContigs().getSequences().get(0).getSequenceName();
+ final double precedingProb = precedingIsActive ? 1.0 : 0.0;
+ for ( int i = 0; i < nPrecedingSites; i++ ) {
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(contig, i + start);
+ final ActivityProfileState state = new ActivityProfileState(loc, precedingProb);
+ profile.add(state);
+ }
+
+ final GenomeLoc nextLoc = genomeLocParser.createGenomeLoc(contig, nPrecedingSites + start);
+ profile.add(new ActivityProfileState(nextLoc, 1.0));
+
+ if ( precedingIsActive == false && nPrecedingSites >= bandPassSize && bandPassSize < start ) {
+ // we have enough space that all probs fall on the genome
+ final double[] probs = profile.getProbabilitiesAsArray();
+ Assert.assertEquals(MathUtils.sum(probs), 1.0 * (nPrecedingSites * precedingProb + 1), 1e-3, "Activity profile doesn't sum to number of non-zero prob states");
+ }
+ }
+
+ private double[] bandPassInOnePass(final BandPassActivityProfile profile, final double[] activeProbArray) {
+ final double[] bandPassProbArray = new double[activeProbArray.length];
+
+ // apply the band pass filter for activeProbArray into filteredProbArray
+ final double[] GaussianKernel = profile.getKernel();
+ for( int iii = 0; iii < activeProbArray.length; iii++ ) {
+ final double[] kernel = ArrayUtils.subarray(GaussianKernel, Math.max(profile.getFilteredSize() - iii, 0), Math.min(GaussianKernel.length, profile.getFilteredSize() + activeProbArray.length - iii));
+ final double[] activeProbSubArray = ArrayUtils.subarray(activeProbArray, Math.max(0,iii - profile.getFilteredSize()), Math.min(activeProbArray.length,iii + profile.getFilteredSize() + 1));
+ bandPassProbArray[iii] = dotProduct(activeProbSubArray, kernel);
+ }
+
+ return bandPassProbArray;
+ }
+
+ public static double dotProduct(double[] v1, double[] v2) {
+ Assert.assertEquals(v1.length,v2.length,"Array lengths do not mach in dotProduct");
+ double result = 0.0;
+ for (int k = 0; k < v1.length; k++)
+ result += v1[k] * v2[k];
+
+ return result;
+ }
+
+ @DataProvider(name = "BandPassComposition")
+ public Object[][] makeBandPassComposition() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ for ( int bandPassSize : Arrays.asList(0, 1, 10, 100, BandPassActivityProfile.MAX_FILTER_SIZE) ) {
+ for ( int integrationLength : Arrays.asList(1, 10, 100, 1000) ) {
+ tests.add(new Object[]{ bandPassSize, integrationLength });
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test( enabled = ! DEBUG, dataProvider = "BandPassComposition")
+ public void testBandPassComposition(final int bandPassSize, final int integrationLength) {
+ final int start = 1;
+ final BandPassActivityProfile profile = new BandPassActivityProfile(genomeLocParser, null, MAX_PROB_PROPAGATION_DISTANCE,
+ ACTIVE_PROB_THRESHOLD, bandPassSize, BandPassActivityProfile.DEFAULT_SIGMA);
+ final double[] rawActiveProbs = new double[integrationLength + bandPassSize * 2];
+
+ // add a buffer so that we can get all of the band pass values
+ final String contig = genomeLocParser.getContigs().getSequences().get(0).getSequenceName();
+ int pos = start;
+ int rawProbsOffset = 0;
+ for ( int i = 0; i < bandPassSize; i++ ) {
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(contig, pos++);
+ final ActivityProfileState state = new ActivityProfileState(loc, 0.0);
+ profile.add(state);
+ rawActiveProbs[rawProbsOffset++] = 0.0;
+ rawActiveProbs[rawActiveProbs.length - rawProbsOffset] = 0.0;
+ }
+
+ for ( int i = 0; i < integrationLength; i++ ) {
+ final GenomeLoc nextLoc = genomeLocParser.createGenomeLoc(contig, pos++);
+ profile.add(new ActivityProfileState(nextLoc, 1.0));
+ rawActiveProbs[rawProbsOffset++] = 1.0;
+
+ for ( int j = 0; j < profile.size(); j++ ) {
+ Assert.assertTrue(profile.getStateList().get(j).isActiveProb >= 0.0, "State probability < 0 at " + j);
+ Assert.assertTrue(profile.getStateList().get(j).isActiveProb <= 1.0 + 1e-3, "State probability > 1 at " + j);
+ }
+ }
+
+ final double[] expectedProbs = bandPassInOnePass(profile, rawActiveProbs);
+ for ( int j = 0; j < profile.size(); j++ ) {
+ Assert.assertEquals(profile.getStateList().get(j).isActiveProb, expectedProbs[j], "State probability not expected at " + j);
+ }
+ }
+
+ // ------------------------------------------------------------------------------------
+ //
+ // Code to test the creation of the kernels
+ //
+ // ------------------------------------------------------------------------------------
+
+ /**
+
+ kernel <- function(sd, pThres) {
+ raw = dnorm(-80:81, mean=0, sd=sd)
+ norm = raw / sum(raw)
+ bad = norm < pThres
+ paste(norm[! bad], collapse=", ")
+ }
+
+ print(kernel(0.01, 1e-5))
+ print(kernel(1, 1e-5))
+ print(kernel(5, 1e-5))
+ print(kernel(17, 1e-5))
+
+ * @return
+ */
+
+ @DataProvider(name = "KernelCreation")
+ public Object[][] makeKernelCreation() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ tests.add(new Object[]{ 0.01, 1000, new double[]{1.0}});
+ tests.add(new Object[]{ 1.0, 1000, new double[]{0.0001338302, 0.004431848, 0.053990966, 0.241970723, 0.398942278, 0.241970723, 0.053990966, 0.004431848, 0.0001338302}});
+ tests.add(new Object[]{ 1.0, 0, new double[]{1.0}});
+ tests.add(new Object[]{ 1.0, 1, new double[]{0.2740686, 0.4518628, 0.2740686}});
+ tests.add(new Object[]{ 1.0, 2, new double[]{0.05448868, 0.24420134, 0.40261995, 0.24420134, 0.05448868}});
+ tests.add(new Object[]{ 1.0, 1000, new double[]{0.0001338302, 0.004431848, 0.053990966, 0.241970723, 0.398942278, 0.241970723, 0.053990966, 0.004431848, 0.0001338302}});
+ tests.add(new Object[]{ 5.0, 1000, new double[]{1.1788613551308e-05, 2.67660451529771e-05, 5.83893851582921e-05, 0.000122380386022754, 0.000246443833694604, 0.000476817640292968, 0.000886369682387602, 0.00158309031659599, 0.00271659384673712, 0.00447890605896858, 0.00709491856924629, 0.0107981933026376, 0.0157900316601788, 0.0221841669358911, 0.029945493127149, 0.0388372109966426, 0.0483941449038287, 0.0579383105522965, 0.0666449205783599, 0.0736540280606647, 0.0782085387950912, [...]
+ tests.add(new Object[]{17.0, 1000, new double[]{1.25162575710745e-05, 1.57001772728555e-05, 1.96260034693739e-05, 2.44487374842009e-05, 3.03513668801384e-05, 3.75489089511911e-05, 4.62928204154855e-05, 5.68757597480354e-05, 6.96366758708924e-05, 8.49661819944029e-05, 0.000103312156275406, 0.000125185491708561, 0.000151165896477646, 0.000181907623161359, 0.000218144981137171, 0.000260697461819069, 0.000310474281706066, 0.000368478124457557, 0.000435807841336874, 0.0005136598504885 [...]
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test( enabled = ! DEBUG, dataProvider = "KernelCreation")
+ public void testKernelCreation(final double sigma, final int maxSize, final double[] expectedKernel) {
+ final BandPassActivityProfile profile = new BandPassActivityProfile(genomeLocParser, null, MAX_PROB_PROPAGATION_DISTANCE, ACTIVE_PROB_THRESHOLD,
+ maxSize, sigma, true);
+
+ final double[] kernel = profile.getKernel();
+ Assert.assertEquals(kernel.length, expectedKernel.length);
+ for ( int i = 0; i < kernel.length; i++ )
+ Assert.assertEquals(kernel[i], expectedKernel[i], 1e-3, "Kernels not equal at " + i);
+ }
+
+ // ------------------------------------------------------------------------------------
+ //
+ // Large-scale test, reading in 1000G Phase I chr20 calls and making sure that
+ // the regions returned are the same if you run on the entire profile vs. doing it
+ // incremental
+ //
+ // ------------------------------------------------------------------------------------
+
+ @DataProvider(name = "VCFProfile")
+ public Object[][] makeVCFProfile() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ //tests.add(new Object[]{ privateTestDir + "ALL.chr20.phase1_release_v3.20101123.snps_indels_svs.sites.vcf", "20", 60470, 61000});
+ //tests.add(new Object[]{ privateTestDir + "ALL.chr20.phase1_release_v3.20101123.snps_indels_svs.sites.vcf", "20", 60470, 100000});
+ //tests.add(new Object[]{ privateTestDir + "ALL.chr20.phase1_release_v3.20101123.snps_indels_svs.sites.vcf", "20", 60470, 1000000});
+ tests.add(new Object[]{ privateTestDir + "ALL.chr20.phase1_release_v3.20101123.snps_indels_svs.sites.vcf", "20", 60470, 1000000});
+ tests.add(new Object[]{ privateTestDir + "NA12878.WGS.b37.chr20.firstMB.vcf", "20", 1, 1000000});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test( dataProvider = "VCFProfile")
+ public void testVCFProfile(final String path, final String contig, final int start, final int end) throws Exception {
+ final int extension = 50;
+ final int minRegionSize = 50;
+ final int maxRegionSize = 300;
+
+ final File file = new File(path);
+ final VCFCodec codec = new VCFCodec();
+ final Pair<VCFHeader, GATKVCFUtils.VCIterable<LineIterator>> reader = GATKVCFUtils.readAllVCs(file, codec);
+
+ final List<ActiveRegion> incRegions = new ArrayList<ActiveRegion>();
+ final BandPassActivityProfile incProfile = new BandPassActivityProfile(genomeLocParser, null, MAX_PROB_PROPAGATION_DISTANCE, ACTIVE_PROB_THRESHOLD);
+ final BandPassActivityProfile fullProfile = new BandPassActivityProfile(genomeLocParser, null, MAX_PROB_PROPAGATION_DISTANCE, ACTIVE_PROB_THRESHOLD);
+ int pos = start;
+ for ( final VariantContext vc : reader.getSecond() ) {
+ if ( vc == null ) continue;
+ while ( pos < vc.getStart() ) {
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(contig, pos);
+ //logger.warn("Adding 0.0 at " + loc + " because vc.getStart is " + vc.getStart());
+ incProfile.add(new ActivityProfileState(loc, 0.0));
+ fullProfile.add(new ActivityProfileState(loc, 0.0));
+ pos++;
+ }
+ if ( vc.getStart() >= start && vc.getEnd() <= end ) {
+ final GenomeLoc loc = genomeLocParser.createGenomeLoc(contig, pos);
+ //logger.warn("Adding 1.0 at " + loc);
+ ActivityProfileState.Type type = ActivityProfileState.Type.NONE;
+ Number value = null;
+ if ( vc.isBiallelic() && vc.isIndel() ) {
+ type = ActivityProfileState.Type.HIGH_QUALITY_SOFT_CLIPS;
+ value = Math.abs(vc.getIndelLengths().get(0));
+ }
+ final ActivityProfileState state = new ActivityProfileState(loc, 1.0, type, value);
+ incProfile.add(state);
+ fullProfile.add(state);
+ pos++;
+ }
+
+ incRegions.addAll(incProfile.popReadyActiveRegions(extension, minRegionSize, maxRegionSize, false));
+
+ if ( vc.getStart() > end )
+ break;
+ }
+
+ incRegions.addAll(incProfile.popReadyActiveRegions(extension, minRegionSize, maxRegionSize, true));
+
+ final List<ActiveRegion> fullRegions = fullProfile.popReadyActiveRegions(extension, minRegionSize, maxRegionSize, true);
+ assertGoodRegions(fullRegions, start, end, maxRegionSize);
+ assertGoodRegions(incRegions, start, end, maxRegionSize);
+
+ Assert.assertEquals(incRegions.size(), fullRegions.size(), "incremental and full region sizes aren't the same");
+ for ( int i = 0; i < fullRegions.size(); i++ ) {
+ final ActiveRegion incRegion = incRegions.get(i);
+ final ActiveRegion fullRegion = fullRegions.get(i);
+ Assert.assertTrue(incRegion.equalExceptReads(fullRegion), "Full and incremental regions are not equal: full = " + fullRegion + " inc = " + incRegion);
+ }
+ }
+
+ private void assertGoodRegions(final List<ActiveRegion> regions, final int start, final int end, final int maxRegionSize) {
+ int lastPosSeen = start - 1;
+ for ( int regionI = 0; regionI < regions.size(); regionI++ ) {
+ final ActiveRegion region = regions.get(regionI);
+ Assert.assertEquals(region.getLocation().getStart(), lastPosSeen + 1, "discontinuous with previous region. lastPosSeen " + lastPosSeen + " but region is " + region);
+ Assert.assertTrue(region.getLocation().size() <= maxRegionSize, "Region is too big: " + region);
+ lastPosSeen = region.getLocation().getStop();
+
+ for ( final ActivityProfileState state : region.getSupportingStates() ) {
+ Assert.assertEquals(state.isActiveProb > ACTIVE_PROB_THRESHOLD, region.isActive(),
+ "Region is active=" + region.isActive() + " but contains a state " + state + " with prob "
+ + state.isActiveProb + " not within expected values given threshold for activity of "
+ + ACTIVE_PROB_THRESHOLD);
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/baq/BAQUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/baq/BAQUnitTest.java
new file mode 100644
index 0000000..7ea26ee
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/baq/BAQUnitTest.java
@@ -0,0 +1,257 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.baq;
+
+
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.BeforeMethod;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.Utils;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.util.List;
+import java.util.ArrayList;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.*;
+
+/**
+ * Basic unit test for BAQ calculation
+ */
+public class BAQUnitTest extends BaseTest {
+ private SAMFileHeader header;
+ private final int startChr = 1;
+ private final int numChr = 2;
+ private final int chrSize = 1000;
+ IndexedFastaSequenceFile fasta = null;
+
+ @BeforeMethod
+ public void before() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(numChr, startChr, chrSize);
+ File referenceFile = new File(hg18Reference);
+ try {
+ fasta = new IndexedFastaSequenceFile(referenceFile);
+ }
+ catch(FileNotFoundException ex) {
+ throw new UserException.CouldNotReadInputFile(referenceFile,ex);
+ }
+ }
+
+ private class BAQTest {
+ String readBases, refBases;
+ byte[] quals, expected;
+ String cigar;
+ int refOffset;
+ int pos;
+
+ public BAQTest(String _refBases, String _readBases, String _quals, String _expected) {
+ this(0, -1, null, _readBases, _refBases, _quals, _expected);
+ }
+
+ public BAQTest(int refOffset, String _refBases, String _readBases, String _quals, String _expected) {
+ this(refOffset, -1, null, _refBases, _readBases, _quals, _expected);
+ }
+
+ public BAQTest(long pos, String cigar, String _readBases, String _quals, String _expected) {
+ this(0, pos, cigar, null, _readBases, _quals, _expected);
+ }
+
+
+ public BAQTest(int _refOffset, long _pos, String _cigar, String _refBases, String _readBases, String _quals, String _expected) {
+ refOffset = _refOffset;
+ pos = (int)_pos;
+ cigar = _cigar;
+ readBases = _readBases;
+ refBases = _refBases;
+
+ quals = new byte[_quals.getBytes().length];
+ expected = new byte[_quals.getBytes().length];
+ for ( int i = 0; i < quals.length; i++) {
+ quals[i] = (byte)(_quals.getBytes()[i] - 33);
+ expected[i] = (byte)(_expected.getBytes()[i] - 33);
+ }
+ }
+
+ public String toString() { return readBases; }
+
+ public SAMRecord createRead() {
+ SAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "foo", 0, pos > 0 ? pos + (refOffset > 0 ? refOffset : 0): 1, readBases.getBytes(), quals);
+ //if ( cigar != null ) read.setAlignmentEnd(readBases.getBytes().length + pos);
+ read.setCigarString( cigar == null ? String.format("%dM", quals.length) : cigar);
+ return read;
+ }
+ }
+
+
+ @DataProvider(name = "data")
+ public Object[][] createData1() {
+ List<BAQTest> params = new ArrayList<BAQTest>();
+
+ params.add(new BAQTest("GCTGCTCCTGGTACTGCTGGATGAGGGCCTCGATGAAGCTAAGCTTTTTCTCCTGCTCCTGCGTGATCCGCTGCAG",
+ "GCTGCTCCTGGTACTGCTGGATGAGGGCCTCGATGAAGCTAAGCTTTTCCTCCTGCTCCTGCGTGATCCGCTGCAG",
+ "?BACCBDDDFFBCFFHHFIHFEIFHIGHHGHBFEIFGIIGEGIIHGGGIHHIIHIIHIIHGICCIGEII at IGIHCG",
+ "?BACCBDDDFFBCFFHHFIHFEIFHIGHHGHBFEIFGIIGEGII410..0HIIHIIHIIHGICCIGEII at IGIHCE"));
+
+ params.add(new BAQTest("GCTTTTTCTCCTCCTG",
+ "GCTTTTCCTCCTCCTG",
+ "IIHGGGIHHIIHHIIH",
+ "EI410..0HIIHHIIE"));
+
+ // big and complex, also does a cap from 3 to 4!
+ params.add(new BAQTest(-3, 9999810l, "49M1I126M1I20M1I25M",
+ "AAATTCAAGATTTCAAAGGCTCTTAACTGCTCAAGATAATTTTTTTTTTTTGAGACAGAGTCTTGCTGTGTTGCCCAGGCTGGAGTGCAGTGGCGTGATCTTGGCTCACTGCAAGCTCCGCCTCCCGGGTTCACGCCATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGACTACAGGCACCCACCACCACGCCTGGCCAATTTTTTTGTATTTTTAGTAGAGATAG",
+ "TTCAAGATTTCAAAGGCTCTTAACTGCTCAAGATAATTTTTTTTTTTTGTAGACAGAGTCTTGCTGTGTTGCCCAGGCTGGAGTGCAGTGGCGTGATCTTGGCTCACTGCAAGCTCCGCCTCCCGGGTTCACGCCATTCTCCTGCCTCAGCCTCCCGAGTAGCTGGGACTACAGGCCACCCACCACCACGCCTGGCCTAATTTTTTTGTATTTTTAGTAGAGA",
+ ">IHFECEBDBBCBCABABAADBD?AABBACEABABC?>?B>@A@@>A?B3BBC?CBDBAABBBBBAABAABBABDACCCBCDAACBCBABBB:ABDBACBBDCCCCABCDCCBCC@@;?<B at BC;CBBBAB=;A>ACBABBBABBCA@@<?>>AAA<CA at AABBABCC?BB8@<@C<>5;<A5=A;>=64>???B>=6497<<;;<;>2?>BA@??A6<<A59",
+ ">EHFECEBDBBCBCABABAADBD?AABBACEABABC?>?B>@A@@>A?838BC?CBDBAABBBBBAABAABBABDACCCBCDAACBCBABBB:ABDBACBBDCCCCABCDCCBCC@@;?<B at BC;CBBBAB=;A>ACBABBBABBCA@@<?>>AAA<CA at AABBABCC?BB8@<@%<>5;<A5=A;>=64>???B;86497<<;;<;>2?>BA@??A6<<A59"));
+
+ // now changes
+ params.add(new BAQTest(-3, 9999966l, "36M",
+ "CCGAGTAGCTGGGACTACAGGCACCCACCACCACGCCTGGCC",
+ "AGTAGCTGGGACTACAGGCACCCACCACCACGCCTG",
+ "A?>>@>AA?@@>A?>A@?>@>>?=>?'>?=>7=?A9",
+ "A?>>@>AA?@@>A?>A@?>@>>?=>?'>?=>7=?A9"));
+
+ // raw base qualities are low -- but they shouldn't be capped
+ params.add(new BAQTest(-3, 9999993l, "36M",
+ "CCACCACGCCTGGCCAATTTTTTTGTATTTTTAGTAGAGATA",
+ "CCACGCTTGGCAAAGTTTTCCGTACGTTTAGCCGAG",
+ "33'/(7+270&4),(&&-)$&,%7$',-/61(,6?8",
+ "33'/(7+270&4),(&&-)$&,%7$',-/61(,6?8"));
+
+ // soft clipping
+ // todo soft clip testing just doesn't work right now!
+
+// params.add(new BAQTest(29, 10000109l, "29S190M",
+// null, "GAAGGTTGAATCAAACCTTCGGTTCCAACGGATTACAGGTGTGAGCCACCGCGACCGGCCTGCTCAAGATAATTTTTAGGGCTAACTATGACATGAACCCCAAAATTCCTGTCCTCTAGATGGCAGAAACCAAGATAAAGTATCCCCACATGGCCACAAGGTTAAGCTCTTATGGACACAAAACAAGGCAGAGAAATGTCATTTGGCATTGGTTTCAGG",
+// "3737088:858278273772:3<=;:?;5=9@>@?>@=<>8?>@=>>?>4=5>?=5====A==@?A@=@6 at A><?B:A;:;>@A?>?AA>@?AA>A?>==?AAA@@A>=A<A>>A=?A>AA==@A?AA?>?AA?A@@C@:?A@<;::??AA==>@@?BB=<A?BA>>A>A?AB=???@?BBA@?BA==?A>A?BB=A:@?ABAB>>?ABB>8A at BAIGA",
+// "3737088:858278273772:3<=;:?;5=9@>@?>@=<>8?>@=>>?>4=5>?=5====A==@?A@=@6 at A><?B:A;:;>@A?>?AA>@?AA>A?>==?AAA@@A>=A<A>>A=?A>AA==@A?AA?>?AA?A@@C@:?A@<;::??AA==>@@?BB=<A?BA>>A>A?AB=???@?BBA@?BA==?A>A?BB=A:@?ABAB>>?ABB>8A at BAI>;"));
+
+// params.add(new BAQTest(30, 10000373l, "30S69M1D2M",
+// null, "TGAAATCCTGCCTTATAGTTCCCCTAAACCCACGTTCTATCCCCAGATACTCCCCTCTTCATTACAGAACAACAAAGAAAGACAAATTCTTAGCATCAATG",
+// "###############################=89>B;6<;96*>.1799>++66=:=:8=<-.9>><;9<':-+;*+::=;8=;;.::<:;=/2=70<=?-",
+// "###############################=89>B;6<;96*>.1799>++66=:=:8=<-.9>><;9<':-+;*+::=;8=;;.::<:;=/2=7000%%"));
+
+
+// params.add(new BAQTest(5, 10000109l, "5S5M",
+// "GAAGGTTGAA",
+// null,
+// "HHHHHHHHHH",
+// "HHHHHHHHHE"));
+
+// params.add(new BAQTest(10009480l, "102M1I18M1I16M1I43M1I10M1D9M1I7M1I7M1I16M1I9M1I8M1I14M2I18M",
+// "AGAGATGGGGTTTCGCCATGTTGTCCAGGCTGGTCTTGAACTCCTGACCTCAAGTGATCTGCCCACCTCGGCCTCCCAAAGTGCTGGGATTACACGTGTGAAACCACCATGCCTGGTCTCTTAATTTTTCNGATTCTAATAAAATTACATTCTATTTGCTGAAAGNGTACTTTAGAGTTGAAAGAAAAAGAAAGGNGTGGAACTTCCCCTAGTAAACAAGGAAAAACNTCCATGTTATTTATTGGACCTTAAAAATAGTGAAACATCTTAAGAAAAAAAATCAATCCTA",
+// "@HI at BA<?C@?CA>7>=AA>9@==??C???@?>:?BB at BA>B?=A@@<=B?AB???@@@@@?=?A==B at 7<<?@>==>=<=>???>=@@A?<=B:5?413577/675;><;==@=<>>968;6;>????:#;=?>:3072077726/6;3719;9A=9;774771#30532676??=8::97<7144448/4425#65688821515986255/5601548355551#218>96/5/8<4/.2344/914/55553)1047;:30312:4:63556565631=:62610",
+// "@HI at BA<?C@?CA>7>=AA>9@==??C???@?>:?BB at BA>B?=A@@<=B?AB???@@@@@?=?A==B at 7<<?@>==>=<=>???>=@@A?<=B:5?413&!7/675;><;==@=<>>96!;6;>????:#;=?>:3!72077726/6;3719;9A=9;774771#30532676??=8::&!<7144448'$!25#65687421515986255/560!548355551#218>96!5/8<4/.2344/614(%!!53)1047;:30312:4:63556565631=:62610"));
+
+ List<Object[]> params2 = new ArrayList<Object[]>();
+ for ( BAQTest x : params ) params2.add(new Object[]{x});
+ return params2.toArray(new Object[][]{});
+ }
+
+
+
+ @Test(dataProvider = "data", enabled = true)
+ public void testBAQWithProvidedReference(BAQTest test) {
+ if ( test.refBases != null ) {
+ testBAQ(test, false);
+ }
+ }
+
+ @Test(dataProvider = "data", enabled = true)
+ public void testBAQWithCigarAndRefLookup(BAQTest test) {
+ if ( test.cigar != null ) {
+ testBAQ(test, true);
+ }
+ }
+
+ @Test(enabled = true)
+ public void testBAQQualRange() {
+ BAQ baq = new BAQ(1e-3, 0.1, 7, (byte)4, false); // matches current samtools parameters
+ final byte ref = (byte)'A';
+ final byte alt = (byte)'A';
+
+ for ( int i = 0; i <= SAMUtils.MAX_PHRED_SCORE; i++ )
+ Assert.assertTrue(baq.calcEpsilon( ref, alt, (byte)i) >= 0.0, "Failed to get baq epsilon range");
+ }
+
+ @Test(enabled = true)
+ public void testBAQOverwritesExistingTagWithNull() {
+
+ // create a read with a single base off the end of the contig, which cannot be BAQed
+ final SAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "foo", 0, fasta.getSequenceDictionary().getSequence("chr1").getSequenceLength() + 1, 1);
+ read.setReadBases(new byte[] {(byte) 'A'});
+ read.setBaseQualities(new byte[] {(byte) 20});
+ read.setCigarString("1M");
+ read.setAttribute("BQ", "A");
+
+ // try to BAQ and tell it to RECALCULATE AND ADD_TAG
+ BAQ baq = new BAQ(1e-3, 0.1, 7, (byte)4, false);
+ baq.baqRead(read, fasta, BAQ.CalculationMode.RECALCULATE, BAQ.QualityMode.ADD_TAG);
+
+ // did we remove the existing tag?
+ Assert.assertTrue(read.getAttribute("BQ") == null);
+ }
+
+ public void testBAQ(BAQTest test, boolean lookupWithFasta) {
+ BAQ baqHMM = new BAQ(1e-3, 0.1, 7, (byte)4, false); // matches current samtools parameters
+
+ SAMRecord read = test.createRead();
+ BAQ.BAQCalculationResult result;
+ if ( lookupWithFasta && test.cigar != null )
+ result = baqHMM.calcBAQFromHMM(read, fasta);
+ else
+ result = baqHMM.calcBAQFromHMM(read, test.refBases.getBytes(), test.refOffset);
+
+ System.out.println(Utils.dupString('-', 40));
+ System.out.println("reads : " + new String(test.readBases));
+ printQuals(System.out, "in-quals:", test.quals, false);
+ printQuals(System.out, "bq-quals:", result.bq, false);
+ for (int i = 0; i < test.quals.length; i++) {
+ //result.bq[i] = baqHMM.capBaseByBAQ(result.rawQuals[i], result.bq[i], result.state[i], i);
+ Assert.assertTrue(result.bq[i] >= baqHMM.getMinBaseQual() || test.expected[i] < baqHMM.getMinBaseQual(), "BQ < min base quality");
+ Assert.assertEquals(result.bq[i], test.expected[i], "Did not see the expected BAQ value at " + i);
+ }
+
+ }
+
+ public final static void printQuals( PrintStream out, String prefix, byte[] quals, boolean asInt ) {
+ out.print(prefix);
+ for ( int i = 0; i < quals.length; i++) {
+ if ( asInt ) {
+ out.printf("%2d", (int)quals[i]);
+ if ( i+1 != quals.length ) out.print(",");
+ } else
+ out.print((char)(quals[i]+33));
+ }
+ out.println();
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/classloader/JVMUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/classloader/JVMUtilsUnitTest.java
new file mode 100644
index 0000000..c232e1c
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/classloader/JVMUtilsUnitTest.java
@@ -0,0 +1,75 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.classloader;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class JVMUtilsUnitTest {
+
+ // Test classes used by the tests for JVMUtils.getCallingClass():
+ private static class DummyTestClass1 {
+ public static Class getCaller( final Class callee ) {
+ return DummyTestClass2.getCaller(callee);
+ }
+ }
+
+ private static class DummyTestClass2 {
+ public static Class getCaller( final Class callee ) {
+ return DummyTestClass3.getCaller(callee);
+ }
+ }
+
+ private static class DummyTestClass3 {
+ public static Class getCaller( final Class callee ) {
+ return JVMUtils.getCallingClass(callee);
+ }
+ }
+
+ @DataProvider( name = "TestGetCallingClassDataProvider" )
+ public Object[][] getTestCallingClassTestData() {
+ return new Object[][] {
+ { DummyTestClass1.class, JVMUtilsUnitTest.class },
+ { DummyTestClass2.class, DummyTestClass1.class },
+ { DummyTestClass3.class, DummyTestClass2.class }
+ };
+ }
+
+ @Test( dataProvider = "TestGetCallingClassDataProvider" )
+ public void testGetCallingClass( final Class callee, final Class expectedCaller ) {
+ final Class reportedCaller = DummyTestClass1.getCaller(callee);
+
+ Assert.assertEquals(reportedCaller, expectedCaller,
+ String.format("Wrong calling class returned from DummyTestClass1.getCaller(%s)", callee.getSimpleName()));
+ }
+
+ @Test( expectedExceptions = IllegalArgumentException.class )
+ public void testGetCallingClassCalleeNotFound() {
+ // Trying to get the calling class of a class not on the runtime stack should produce an exception.
+ JVMUtils.getCallingClass(DummyTestClass1.class);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/clipping/ReadClipperTestUtils.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/clipping/ReadClipperTestUtils.java
new file mode 100644
index 0000000..8ce0a9e
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/clipping/ReadClipperTestUtils.java
@@ -0,0 +1,144 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.clipping;
+
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.TextCigarCodec;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.CigarUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Stack;
+
+public class ReadClipperTestUtils {
+ //Should contain all the utils needed for tests to mass produce
+ //reads, cigars, and other needed classes
+
+ final static byte [] BASES = {'A', 'C', 'T', 'G'};
+ final static byte [] QUALS = {2, 15, 25, 30};
+ final static String CIGAR = "4M";
+ final static CigarElement[] cigarElements = { new CigarElement(1, CigarOperator.HARD_CLIP),
+ new CigarElement(1, CigarOperator.SOFT_CLIP),
+ new CigarElement(1, CigarOperator.INSERTION),
+ new CigarElement(1, CigarOperator.DELETION),
+ new CigarElement(1, CigarOperator.MATCH_OR_MISMATCH)};
+
+
+ public static GATKSAMRecord makeReadFromCigar(Cigar cigar) {
+ return ArtificialSAMUtils.createArtificialRead(Utils.arrayFromArrayWithLength(BASES, cigar.getReadLength()), Utils.arrayFromArrayWithLength(QUALS, cigar.getReadLength()), cigar.toString());
+ }
+
+ public static GATKSAMRecord makeReadFromCigar(String cigarString) {
+ return makeReadFromCigar(CigarUtils.cigarFromString(cigarString));
+ }
+
+ public static List<Cigar> generateCigarList(int maximumLength) {
+ return generateCigarList(maximumLength, cigarElements);
+ }
+
+ /**
+ * This function generates every valid permutation of cigar strings (with a given set of cigarElement) with a given length.
+ *
+ * A valid cigar object obeys the following rules:
+ * - No Hard/Soft clips in the middle of the read
+ * - No deletions in the beginning / end of the read
+ * - No repeated adjacent element (e.g. 1M2M -> this should be 3M)
+ * - No consecutive I/D elements
+ *
+ * @param maximumLength the maximum number of elements in the cigar
+ * @return a list with all valid Cigar objects
+ */
+ public static List<Cigar> generateCigarList(int maximumLength, CigarElement[] cigarElements) {
+ int numCigarElements = cigarElements.length;
+ LinkedList<Cigar> cigarList = new LinkedList<Cigar>();
+ byte [] cigarCombination = new byte[maximumLength];
+
+ Utils.fillArrayWithByte(cigarCombination, (byte) 0); // we start off with all 0's in the combination array.
+ int currentIndex = 0;
+ while (true) {
+ Cigar cigar = createCigarFromCombination(cigarCombination, cigarElements); // create the cigar
+ cigar = CigarUtils.combineAdjacentCigarElements(cigar); // combine adjacent elements
+ if (CigarUtils.isCigarValid(cigar)) { // check if it's valid
+ cigarList.add(cigar); // add it
+ }
+
+ boolean currentIndexChanged = false;
+ while (currentIndex < maximumLength && cigarCombination[currentIndex] == numCigarElements - 1) {
+ currentIndex++; // find the next index to increment
+ currentIndexChanged = true; // keep track of the fact that we have changed indices!
+ }
+
+ if (currentIndex == maximumLength) // if we hit the end of the array, we're done.
+ break;
+
+ cigarCombination[currentIndex]++; // otherwise advance the current index
+
+ if (currentIndexChanged) { // if we have changed index, then...
+ for (int i = 0; i < currentIndex; i++)
+ cigarCombination[i] = 0; // reset everything from 0->currentIndex
+ currentIndex = 0; // go back to the first index
+ }
+ }
+
+ return cigarList;
+ }
+
+ private static Cigar createCigarFromCombination(byte[] cigarCombination, CigarElement[] cigarElements) {
+ Cigar cigar = new Cigar();
+ for (byte i : cigarCombination) {
+ cigar.add(cigarElements[i]);
+ }
+ return cigar;
+ }
+
+ public static GATKSAMRecord makeRead() {
+ return ArtificialSAMUtils.createArtificialRead(BASES, QUALS, CIGAR);
+ }
+
+ /**
+ * Asserts that the two reads have the same bases, qualities and cigar strings
+ *
+ * @param actual the calculated read
+ * @param expected the expected read
+ */
+ public static void assertEqualReads(GATKSAMRecord actual, GATKSAMRecord expected) {
+ // If they're both not empty, test their contents
+ if(!actual.isEmpty() && !expected.isEmpty()) {
+ Assert.assertEquals(actual.getReadBases(), expected.getReadBases());
+ Assert.assertEquals(actual.getBaseQualities(), expected.getBaseQualities());
+ Assert.assertEquals(actual.getCigarString(), expected.getCigarString());
+ }
+ // Otherwise test if they're both empty
+ else
+ Assert.assertEquals(actual.isEmpty(), expected.isEmpty());
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/clipping/ReadClipperUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/clipping/ReadClipperUnitTest.java
new file mode 100644
index 0000000..400e984
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/clipping/ReadClipperUnitTest.java
@@ -0,0 +1,421 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.clipping;
+
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.sam.CigarUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * User: roger
+ * Date: 9/28/11
+ */
+public class ReadClipperUnitTest extends BaseTest {
+ private final static boolean DEBUG = false;
+
+ List<Cigar> cigarList;
+ int maximumCigarSize = 10; // 6 is the minimum necessary number to try all combinations of cigar types with guarantee of clipping an element with length = 2
+
+ @BeforeClass
+ public void init() {
+ cigarList = ReadClipperTestUtils.generateCigarList(maximumCigarSize);
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testHardClipBothEndsByReferenceCoordinates() {
+ for (Cigar cigar : cigarList) {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ int alnStart = read.getAlignmentStart();
+ int alnEnd = read.getAlignmentEnd();
+ int readLength = alnStart - alnEnd;
+ for (int i = 0; i < readLength / 2; i++) {
+ GATKSAMRecord clippedRead = ReadClipper.hardClipBothEndsByReferenceCoordinates(read, alnStart + i, alnEnd - i);
+ Assert.assertTrue(clippedRead.getAlignmentStart() >= alnStart + i, String.format("Clipped alignment start is less than original read (minus %d): %s -> %s", i, read.getCigarString(), clippedRead.getCigarString()));
+ Assert.assertTrue(clippedRead.getAlignmentEnd() <= alnEnd + i, String.format("Clipped alignment end is greater than original read (minus %d): %s -> %s", i, read.getCigarString(), clippedRead.getCigarString()));
+ assertUnclippedLimits(read, clippedRead);
+ }
+ }
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testHardClipByReadCoordinates() {
+ for (Cigar cigar : cigarList) {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ int readLength = read.getReadLength();
+ for (int i = 0; i < readLength; i++) {
+ GATKSAMRecord clipLeft = ReadClipper.hardClipByReadCoordinates(read, 0, i);
+ Assert.assertTrue(clipLeft.getReadLength() <= readLength - i, String.format("Clipped read length is greater than original read length (minus %d): %s -> %s", i, read.getCigarString(), clipLeft.getCigarString()));
+ assertUnclippedLimits(read, clipLeft);
+
+ GATKSAMRecord clipRight = ReadClipper.hardClipByReadCoordinates(read, i, readLength - 1);
+ Assert.assertTrue(clipRight.getReadLength() <= i, String.format("Clipped read length is greater than original read length (minus %d): %s -> %s", i, read.getCigarString(), clipRight.getCigarString()));
+ assertUnclippedLimits(read, clipRight);
+ }
+ }
+ }
+
+ @DataProvider(name = "ClippedReadLengthData")
+ public Object[][] makeClippedReadLengthData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ final int originalReadLength = 50;
+ for ( int nToClip = 1; nToClip < originalReadLength - 1; nToClip++ ) {
+ tests.add(new Object[]{originalReadLength, nToClip});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "ClippedReadLengthData", enabled = !DEBUG)
+ public void testHardClipReadLengthIsRight(final int originalReadLength, final int nToClip) {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(originalReadLength + "M");
+ read.getReadLength(); // provoke the caching of the read length
+ final int expectedReadLength = originalReadLength - nToClip;
+ GATKSAMRecord clipped = ReadClipper.hardClipByReadCoordinates(read, 0, nToClip - 1);
+ Assert.assertEquals(clipped.getReadLength(), expectedReadLength,
+ String.format("Clipped read length %d with cigar %s not equal to the expected read length %d after clipping %d bases from the left from a %d bp read with cigar %s",
+ clipped.getReadLength(), clipped.getCigar(), expectedReadLength, nToClip, read.getReadLength(), read.getCigar()));
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testHardClipByReferenceCoordinates() {
+ for (Cigar cigar : cigarList) {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ int start = read.getSoftStart();
+ int stop = read.getSoftEnd();
+
+ for (int i = start; i <= stop; i++) {
+ GATKSAMRecord clipLeft = (new ReadClipper(read)).hardClipByReferenceCoordinates(-1, i);
+ if (!clipLeft.isEmpty()) {
+ Assert.assertTrue(clipLeft.getAlignmentStart() >= Math.min(read.getAlignmentEnd(), i + 1), String.format("Clipped alignment start (%d) is less the expected (%d): %s -> %s", clipLeft.getAlignmentStart(), i + 1, read.getCigarString(), clipLeft.getCigarString()));
+ assertUnclippedLimits(read, clipLeft);
+ }
+
+ GATKSAMRecord clipRight = (new ReadClipper(read)).hardClipByReferenceCoordinates(i, -1);
+ if (!clipRight.isEmpty() && clipRight.getAlignmentStart() <= clipRight.getAlignmentEnd()) { // alnStart > alnEnd if the entire read is a soft clip now. We can't test those.
+ Assert.assertTrue(clipRight.getAlignmentEnd() <= Math.max(read.getAlignmentStart(), i - 1), String.format("Clipped alignment end (%d) is greater than expected (%d): %s -> %s", clipRight.getAlignmentEnd(), i - 1, read.getCigarString(), clipRight.getCigarString()));
+ assertUnclippedLimits(read, clipRight);
+ }
+ }
+ }
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testHardClipByReferenceCoordinatesLeftTail() {
+ for (Cigar cigar : cigarList) {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ int alnStart = read.getAlignmentStart();
+ int alnEnd = read.getAlignmentEnd();
+ if (read.getSoftStart() == alnStart) { // we can't test left clipping if the read has hanging soft clips on the left side
+ for (int i = alnStart; i <= alnEnd; i++) {
+ GATKSAMRecord clipLeft = ReadClipper.hardClipByReferenceCoordinatesLeftTail(read, i);
+
+ if (!clipLeft.isEmpty()) {
+ Assert.assertTrue(clipLeft.getAlignmentStart() >= i + 1, String.format("Clipped alignment start (%d) is less the expected (%d): %s -> %s", clipLeft.getAlignmentStart(), i + 1, read.getCigarString(), clipLeft.getCigarString()));
+ assertUnclippedLimits(read, clipLeft);
+ }
+ }
+ }
+ }
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testHardClipByReferenceCoordinatesRightTail() {
+ for (Cigar cigar : cigarList) {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ int alnStart = read.getAlignmentStart();
+ int alnEnd = read.getAlignmentEnd();
+ if (read.getSoftEnd() == alnEnd) { // we can't test right clipping if the read has hanging soft clips on the right side
+ for (int i = alnStart; i <= alnEnd; i++) {
+ GATKSAMRecord clipRight = ReadClipper.hardClipByReferenceCoordinatesRightTail(read, i);
+ if (!clipRight.isEmpty() && clipRight.getAlignmentStart() <= clipRight.getAlignmentEnd()) { // alnStart > alnEnd if the entire read is a soft clip now. We can't test those.
+ Assert.assertTrue(clipRight.getAlignmentEnd() <= i - 1, String.format("Clipped alignment end (%d) is greater than expected (%d): %s -> %s", clipRight.getAlignmentEnd(), i - 1, read.getCigarString(), clipRight.getCigarString()));
+ assertUnclippedLimits(read, clipRight);
+ }
+ }
+ }
+ }
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testHardClipLowQualEnds() {
+ final byte LOW_QUAL = 2;
+ final byte HIGH_QUAL = 30;
+
+ /** create a read for every cigar permutation */
+ for (Cigar cigar : cigarList) {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ int readLength = read.getReadLength();
+ byte[] quals = new byte[readLength];
+
+ for (int nLowQualBases = 0; nLowQualBases < readLength; nLowQualBases++) {
+
+ /** create a read with nLowQualBases in the left tail */
+ Utils.fillArrayWithByte(quals, HIGH_QUAL);
+ for (int addLeft = 0; addLeft < nLowQualBases; addLeft++)
+ quals[addLeft] = LOW_QUAL;
+ read.setBaseQualities(quals);
+ GATKSAMRecord clipLeft = ReadClipper.hardClipLowQualEnds(read, LOW_QUAL);
+ checkClippedReadsForLowQualEnds(read, clipLeft, LOW_QUAL, nLowQualBases);
+
+ /** create a read with nLowQualBases in the right tail */
+ Utils.fillArrayWithByte(quals, HIGH_QUAL);
+ for (int addRight = 0; addRight < nLowQualBases; addRight++)
+ quals[readLength - addRight - 1] = LOW_QUAL;
+ read.setBaseQualities(quals);
+ GATKSAMRecord clipRight = ReadClipper.hardClipLowQualEnds(read, LOW_QUAL);
+ checkClippedReadsForLowQualEnds(read, clipRight, LOW_QUAL, nLowQualBases);
+
+ /** create a read with nLowQualBases on both tails */
+ if (nLowQualBases <= readLength / 2) {
+ Utils.fillArrayWithByte(quals, HIGH_QUAL);
+ for (int addBoth = 0; addBoth < nLowQualBases; addBoth++) {
+ quals[addBoth] = LOW_QUAL;
+ quals[readLength - addBoth - 1] = LOW_QUAL;
+ }
+ read.setBaseQualities(quals);
+ GATKSAMRecord clipBoth = ReadClipper.hardClipLowQualEnds(read, LOW_QUAL);
+ checkClippedReadsForLowQualEnds(read, clipBoth, LOW_QUAL, 2*nLowQualBases);
+ }
+ }
+ }
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testHardClipSoftClippedBases() {
+ for (Cigar cigar : cigarList) {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ GATKSAMRecord clippedRead = ReadClipper.hardClipSoftClippedBases(read);
+ CigarCounter original = new CigarCounter(read);
+ CigarCounter clipped = new CigarCounter(clippedRead);
+
+ assertUnclippedLimits(read, clippedRead); // Make sure limits haven't changed
+ original.assertHardClippingSoftClips(clipped); // Make sure we have only clipped SOFT_CLIPS
+ }
+ }
+
+ @Test(enabled = false)
+ public void testHardClipLeadingInsertions() {
+ for (Cigar cigar : cigarList) {
+ if (startsWithInsertion(cigar)) {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ GATKSAMRecord clippedRead = ReadClipper.hardClipLeadingInsertions(read);
+
+ assertUnclippedLimits(read, clippedRead); // Make sure limits haven't changed
+
+ int expectedLength = read.getReadLength() - leadingCigarElementLength(read.getCigar(), CigarOperator.INSERTION);
+ if (cigarHasElementsDifferentThanInsertionsAndHardClips(read.getCigar()))
+ expectedLength -= leadingCigarElementLength(CigarUtils.invertCigar(read.getCigar()), CigarOperator.INSERTION);
+
+ if (!clippedRead.isEmpty()) {
+ Assert.assertEquals(expectedLength, clippedRead.getReadLength(), String.format("%s -> %s", read.getCigarString(), clippedRead.getCigarString())); // check that everything else is still there
+ Assert.assertFalse(startsWithInsertion(clippedRead.getCigar())); // check that the insertions are gone
+ } else
+ Assert.assertTrue(expectedLength == 0, String.format("expected length: %d", expectedLength)); // check that the read was expected to be fully clipped
+ }
+ }
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testRevertSoftClippedBases() {
+ for (Cigar cigar : cigarList) {
+ final int leadingSoftClips = leadingCigarElementLength(cigar, CigarOperator.SOFT_CLIP);
+ final int tailSoftClips = leadingCigarElementLength(CigarUtils.invertCigar(cigar), CigarOperator.SOFT_CLIP);
+
+ final GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ final GATKSAMRecord unclipped = ReadClipper.revertSoftClippedBases(read);
+
+ assertUnclippedLimits(read, unclipped); // Make sure limits haven't changed
+
+ if (leadingSoftClips > 0 || tailSoftClips > 0) {
+ final int expectedStart = read.getAlignmentStart() - leadingSoftClips;
+ final int expectedEnd = read.getAlignmentEnd() + tailSoftClips;
+
+ Assert.assertEquals(unclipped.getAlignmentStart(), expectedStart);
+ Assert.assertEquals(unclipped.getAlignmentEnd(), expectedEnd);
+ } else
+ Assert.assertEquals(read.getCigarString(), unclipped.getCigarString());
+ }
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testRevertSoftClippedBasesWithThreshold() {
+ for (Cigar cigar : cigarList) {
+ final int leadingSoftClips = leadingCigarElementLength(cigar, CigarOperator.SOFT_CLIP);
+ final int tailSoftClips = leadingCigarElementLength(CigarUtils.invertCigar(cigar), CigarOperator.SOFT_CLIP);
+
+ final GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ final GATKSAMRecord unclipped = ReadClipper.revertSoftClippedBases(read);
+
+ assertUnclippedLimits(read, unclipped); // Make sure limits haven't changed
+ Assert.assertNull(read.getCigar().isValid(null, -1));
+ Assert.assertNull(unclipped.getCigar().isValid(null, -1));
+
+ if (!(leadingSoftClips > 0 || tailSoftClips > 0))
+ Assert.assertEquals(read.getCigarString(), unclipped.getCigarString());
+
+ }
+ }
+
+ @DataProvider(name = "RevertSoftClipsBeforeContig")
+ public Object[][] makeRevertSoftClipsBeforeContig() {
+ List<Object[]> tests = new ArrayList<>();
+
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ for ( int softStart : Arrays.asList(-10, -1, 0) ) {
+ for ( int alignmentStart : Arrays.asList(1, 10) ) {
+ tests.add(new Object[]{softStart, alignmentStart});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = true, dataProvider = "RevertSoftClipsBeforeContig")
+ public void testRevertSoftClippedBasesBeforeStartOfContig(final int softStart, final int alignmentStart) {
+ final int nMatches = 10;
+ final int nSoft = -1 * (softStart - alignmentStart);
+ final String cigar = nSoft + "S" + nMatches + "M";
+ final GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar(cigar);
+ read.setAlignmentStart(alignmentStart);
+
+ Assert.assertEquals(read.getSoftStart(), softStart);
+ Assert.assertEquals(read.getAlignmentStart(), alignmentStart);
+ Assert.assertEquals(read.getCigarString(), cigar);
+
+ final GATKSAMRecord reverted = ReadClipper.revertSoftClippedBases(read);
+
+ final int expectedAlignmentStart = 1;
+ final String expectedCigar = (1 - softStart) + "H" + read.getAlignmentEnd() + "M";
+ Assert.assertEquals(reverted.getSoftStart(), expectedAlignmentStart);
+ Assert.assertEquals(reverted.getAlignmentStart(), expectedAlignmentStart);
+ Assert.assertEquals(reverted.getCigarString(), expectedCigar);
+ }
+
+ private void assertNoLowQualBases(GATKSAMRecord read, byte low_qual) {
+ if (!read.isEmpty()) {
+ byte[] quals = read.getBaseQualities();
+ for (int i = 0; i < quals.length; i++)
+ Assert.assertFalse(quals[i] <= low_qual, String.format("Found low qual (%d) base after hard clipping. Position: %d -- %s", low_qual, i, read.getCigarString()));
+ }
+ }
+
+ private void checkClippedReadsForLowQualEnds(GATKSAMRecord read, GATKSAMRecord clippedRead, byte lowQual, int nLowQualBases) {
+ assertUnclippedLimits(read, clippedRead); // Make sure limits haven't changed
+ assertNoLowQualBases(clippedRead, lowQual); // Make sure the low qualities are gone
+ }
+
+ /**
+ * Asserts that clipping doesn't change the getUnclippedStart / getUnclippedEnd
+ *
+ * @param original original read
+ * @param clipped clipped read
+ */
+ private void assertUnclippedLimits(GATKSAMRecord original, GATKSAMRecord clipped) {
+ if (CigarUtils.readHasNonClippedBases(clipped)) {
+ Assert.assertEquals(original.getUnclippedStart(), clipped.getUnclippedStart());
+ Assert.assertEquals(original.getUnclippedEnd(), clipped.getUnclippedEnd());
+ }
+ }
+
+ private boolean startsWithInsertion(Cigar cigar) {
+ return leadingCigarElementLength(cigar, CigarOperator.INSERTION) > 0;
+ }
+
+ private int leadingCigarElementLength(Cigar cigar, CigarOperator operator) {
+ for (CigarElement cigarElement : cigar.getCigarElements()) {
+ if (cigarElement.getOperator() == operator)
+ return cigarElement.getLength();
+ if (cigarElement.getOperator() != CigarOperator.HARD_CLIP)
+ break;
+ }
+ return 0;
+ }
+
+ private boolean cigarHasElementsDifferentThanInsertionsAndHardClips(Cigar cigar) {
+ for (CigarElement cigarElement : cigar.getCigarElements())
+ if (cigarElement.getOperator() != CigarOperator.INSERTION && cigarElement.getOperator() != CigarOperator.HARD_CLIP)
+ return true;
+ return false;
+ }
+
+ private class CigarCounter {
+ private HashMap<CigarOperator, Integer> counter;
+
+ public Integer getCounterForOp(CigarOperator operator) {
+ return counter.get(operator);
+ }
+
+ public CigarCounter(GATKSAMRecord read) {
+ CigarOperator[] operators = CigarOperator.values();
+ counter = new HashMap<CigarOperator, Integer>(operators.length);
+
+ for (CigarOperator op : operators)
+ counter.put(op, 0);
+
+ for (CigarElement cigarElement : read.getCigar().getCigarElements())
+ counter.put(cigarElement.getOperator(), counter.get(cigarElement.getOperator()) + cigarElement.getLength());
+ }
+
+ public boolean assertHardClippingSoftClips(CigarCounter clipped) {
+ for (CigarOperator op : counter.keySet()) {
+ if (op == CigarOperator.HARD_CLIP || op == CigarOperator.SOFT_CLIP) {
+ int counterTotal = counter.get(CigarOperator.HARD_CLIP) + counter.get(CigarOperator.SOFT_CLIP);
+ int clippedHard = clipped.getCounterForOp(CigarOperator.HARD_CLIP);
+ int clippedSoft = clipped.getCounterForOp(CigarOperator.SOFT_CLIP);
+
+ Assert.assertEquals(counterTotal, clippedHard);
+ Assert.assertTrue(clippedSoft == 0);
+ } else
+ Assert.assertEquals(counter.get(op), clipped.getCounterForOp(op));
+ }
+ return true;
+ }
+
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testRevertEntirelySoftclippedReads() {
+ GATKSAMRecord read = ReadClipperTestUtils.makeReadFromCigar("2H1S3H");
+ GATKSAMRecord clippedRead = ReadClipper.revertSoftClippedBases(read);
+ Assert.assertEquals(clippedRead.getAlignmentStart(), read.getSoftStart());
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/codecs/hapmap/HapMapUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/codecs/hapmap/HapMapUnitTest.java
new file mode 100644
index 0000000..0ff50d7
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/codecs/hapmap/HapMapUnitTest.java
@@ -0,0 +1,164 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.codecs.hapmap;
+
+import htsjdk.tribble.annotation.Strand;
+import htsjdk.tribble.readers.LineIterator;
+import htsjdk.tribble.readers.LineIteratorImpl;
+import htsjdk.tribble.readers.LineReaderUtil;
+import htsjdk.tribble.readers.PositionalBufferedStream;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * Unit tests for the HapMap codec
+ */
+public class HapMapUnitTest extends BaseTest {
+ // our sample hapmap file
+ private final static File hapMapFile = new File(privateTestDir + "genotypes_chr1_ASW_phase3.3_first500.hapmap");
+ private final static String knownLine = "rs2185539 C/T chr1 556738 + ncbi_b36 bbs urn:lsid:bbs.hapmap.org:Protocol:Phase3.r3:1 urn:lsid:bbs.hapmap.org:Assay:Phase3.r3_r" +
+ "s2185539:1 urn:lsid:dcc.hapmap.org:Panel:US_African-30-trios:4 QC+ CC TC TT CT CC CC CC CC CC CC CC CC CC";
+ /**
+ * test reading the header off of the file. We take in the file, read off the first line,
+ * close the reader, and then ask the HapMap decoder for the header with a new reader. These should
+ * be equal (i.e. they return the same object).
+ */
+ @Test
+ public void testReadHeader() {
+ RawHapMapCodec codec = new RawHapMapCodec();
+ final LineIterator reader = getLineIterator();
+ try {
+ String header = reader.next();
+ Assert.assertTrue(header.equals(codec.readActualHeader(getLineIterator())));
+ } finally {
+ codec.close(reader);
+ }
+ }
+
+ @Test
+ public void testKnownRecordConversion() {
+ RawHapMapCodec codec = new RawHapMapCodec();
+ RawHapMapFeature feature = (RawHapMapFeature)codec.decode(knownLine);
+
+
+ // check that the alleles are right
+ Assert.assertEquals(feature.getAlleles().length,2);
+ Assert.assertTrue("C".equals(feature.getAlleles()[0]));
+ Assert.assertTrue("T".equals(feature.getAlleles()[1]));
+
+ // check the name
+ Assert.assertTrue("rs2185539".equals(feature.getName()));
+
+ // check the position
+ Assert.assertEquals(feature.getStart(),556738);
+ Assert.assertEquals(feature.getEnd(),556738);
+
+ // check the contig
+ Assert.assertTrue("chr1".equals(feature.getChr()));
+
+ // check the assembly, center, protLSID, assayLSID, panelLSID, and qccode
+ Assert.assertTrue("ncbi_b36".equals(feature.getAssembly()));
+ Assert.assertTrue("bbs".equals(feature.getCenter()));
+ Assert.assertTrue("urn:lsid:bbs.hapmap.org:Protocol:Phase3.r3:1".equals(feature.getProtLSID()));
+ Assert.assertTrue("urn:lsid:bbs.hapmap.org:Assay:Phase3.r3_rs2185539:1".equals(feature.getAssayLSID()));
+ Assert.assertTrue("urn:lsid:dcc.hapmap.org:Panel:US_African-30-trios:4".equals(feature.getPanelLSID()));
+ Assert.assertTrue("QC+".equals(feature.getQCCode()));
+
+ // check the strand
+ Assert.assertEquals(feature.getStrand(),Strand.POSITIVE);
+
+ // check the genotypes
+ int x = 0;
+ for (; x < feature.getGenotypes().length; x++) {
+ switch (x) {
+ case 1: Assert.assertTrue("TC".equals(feature.getGenotypes()[x])); break;
+ case 2: Assert.assertTrue("TT".equals(feature.getGenotypes()[x])); break;
+ case 3: Assert.assertTrue("CT".equals(feature.getGenotypes()[x])); break;
+ default: Assert.assertTrue("CC".equals(feature.getGenotypes()[x])); break;
+ }
+ }
+ // assert that we found the correct number of records
+ Assert.assertEquals(x,13);
+ }
+
+ @Test
+ public void testReadCorrectNumberOfRecords() {
+ // setup the record for reading our 500 line file (499 records, 1 header line)
+ RawHapMapCodec codec = new RawHapMapCodec();
+ final LineIterator reader = getLineIterator();
+
+ int count = 0;
+ try {
+ codec.readHeader(reader);
+ while (reader.hasNext()) {
+ codec.decode(reader.next());
+ ++count;
+ }
+ } catch (IOException e) {
+ Assert.fail("IOException " + e.getMessage());
+ } finally {
+ codec.close(reader);
+ }
+ Assert.assertEquals(count,499);
+ }
+
+ @Test
+ public void testGetSampleNames() {
+ // setup the record for reading our 500 line file (499 records, 1 header line)
+ RawHapMapCodec codec = new RawHapMapCodec();
+ final LineIterator reader = getLineIterator();
+
+ String line;
+ try {
+ codec.readHeader(reader);
+ line = reader.next();
+ RawHapMapFeature feature = (RawHapMapFeature) codec.decode(line);
+ Assert.assertEquals(feature.getSampleIDs().length,87);
+
+ } catch (IOException e) {
+ Assert.fail("IOException " + e.getMessage());
+ } finally {
+ codec.close(reader);
+ }
+ }
+
+
+ public LineIterator getLineIterator() {
+ try {
+ return new LineIteratorImpl(LineReaderUtil.fromBufferedStream(new PositionalBufferedStream(new FileInputStream(hapMapFile))));
+ } catch (FileNotFoundException e) {
+ Assert.fail("Unable to open hapmap file : " + hapMapFile);
+ }
+ return null; // for intellij, it doesn't know that assert.fail is fatal
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/collections/DefaultHashMapUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/collections/DefaultHashMapUnitTest.java
new file mode 100755
index 0000000..a87aeba
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/collections/DefaultHashMapUnitTest.java
@@ -0,0 +1,159 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.collections;
+
+
+// the imports for unit testing.
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+
+/**
+ * Basic unit test for DefaultHashMap
+ */
+public class DefaultHashMapUnitTest extends BaseTest {
+ DefaultHashMap<String, Double> empty, hasOne, hasTen;
+ Double initialDefault = 10.0;
+
+ @BeforeMethod
+ public void before() {
+ empty = new DefaultHashMap<String, Double>(initialDefault);
+
+ hasOne = new DefaultHashMap<String, Double>(initialDefault);
+ hasOne.put("1", .1);
+
+ hasTen = new DefaultHashMap<String, Double>(initialDefault);
+ for (Integer i = 1; i <= 10; i++) {
+ hasTen.put(i.toString(), i.doubleValue() / 10);
+ }
+ }
+
+ @Test
+ public void testBasicSizes() {
+ logger.warn("Executing testBasicSizes");
+
+ Assert.assertEquals(0, empty.size());
+ Assert.assertEquals(1, hasOne.size());
+ Assert.assertEquals(10, hasTen.size());
+ }
+
+ @Test
+ public void testTenElements() {
+ logger.warn("Executing testTenElements");
+
+ for (Integer i = 1; i <= 10; i++) {
+ Assert.assertEquals(i.doubleValue() / 10, hasTen.get(i.toString()));
+ }
+ Assert.assertEquals(initialDefault, hasTen.get("0"));
+ }
+
+ @Test
+ public void testClear() {
+ logger.warn("Executing testClear");
+
+ empty.clear();
+ hasOne.clear();
+ hasTen.clear();
+
+ Assert.assertEquals(0, empty.size());
+ Assert.assertEquals(0, hasOne.size());
+ Assert.assertEquals(0, hasTen.size());
+ }
+
+
+ @Test
+ public void testSettingTenElements() {
+ logger.warn("Executing testSettingTenElements");
+
+ Assert.assertEquals(10, hasTen.size());
+ for (Integer i = 1; i <= 10; i++) {
+ hasTen.put(i.toString(), i.doubleValue());
+ }
+
+ Assert.assertEquals(10, hasTen.size());
+ for (Integer i = 1; i <= 10; i++) {
+ Assert.assertEquals(i.doubleValue(), hasTen.get(i.toString()));
+ }
+ }
+
+ @Test
+ public void testSettingDefault() {
+ logger.warn("Executing testSettingDefault");
+
+ Assert.assertEquals(initialDefault, empty.get("0"));
+ Assert.assertEquals(initialDefault, hasOne.get("0"));
+ Assert.assertEquals(initialDefault, hasTen.get("0"));
+
+ empty.setDefaultValue(2 * initialDefault);
+ hasOne.setDefaultValue(2 * initialDefault);
+ hasTen.setDefaultValue(2 * initialDefault);
+
+ Assert.assertEquals(2 * initialDefault, empty.get("0"));
+ Assert.assertEquals(2 * initialDefault, hasOne.get("0"));
+ Assert.assertEquals(2 * initialDefault, hasTen.get("0"));
+
+ }
+
+ @Test
+ public void testAdd() {
+ logger.warn("Executing testAdd");
+
+ Assert.assertEquals(0, empty.size());
+
+ Double x = 1.0;
+ empty.put(x.toString(), x / 10);
+ Assert.assertEquals(1, empty.size());
+ Assert.assertEquals(.1, empty.get(x.toString()));
+
+ x = 2.0;
+ empty.put(x.toString(), x / 10);
+ Assert.assertEquals(2, empty.size());
+ Assert.assertEquals(.2, empty.get(x.toString()));
+
+ }
+
+ @Test
+ public void testUnset() {
+ logger.warn("Executing testUnset1");
+
+ Assert.assertEquals(10, hasTen.size());
+ Assert.assertEquals(.9, hasTen.get("9"));
+
+ hasTen.remove("9");
+
+ Assert.assertEquals(9, hasTen.size());
+ Assert.assertEquals(initialDefault, hasTen.get("9"));
+
+ hasTen.remove("1");
+
+ Assert.assertEquals(8, hasTen.size());
+ Assert.assertEquals(initialDefault, hasTen.get("1"));
+
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/collections/ExpandingArrayListUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/collections/ExpandingArrayListUnitTest.java
new file mode 100644
index 0000000..7f9d808
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/collections/ExpandingArrayListUnitTest.java
@@ -0,0 +1,177 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.collections;
+
+
+// the imports for unit testing.
+
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+
+import java.util.Arrays;
+
+/**
+ * Basic unit test for RecalData
+ */
+public class ExpandingArrayListUnitTest extends BaseTest {
+ ExpandingArrayList<Integer> empty, initCap10, hasOne, hasTen;
+
+ @BeforeMethod
+ public void before() {
+ empty = new ExpandingArrayList<Integer>();
+
+ initCap10 = new ExpandingArrayList<Integer>(10);
+
+ hasOne = new ExpandingArrayList<Integer>();
+ hasOne.add(1);
+
+ hasTen = new ExpandingArrayList<Integer>();
+ hasTen.addAll(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+ }
+
+ @Test
+ public void testBasicSizes() {
+ logger.warn("Executing testBasicSizes");
+
+ Assert.assertEquals(0, empty.size());
+ Assert.assertEquals(0, initCap10.size());
+ Assert.assertEquals(1, hasOne.size());
+ Assert.assertEquals(10, hasTen.size());
+ }
+
+ @Test
+ public void testTenElements() {
+ logger.warn("Executing testTenElements");
+
+ for ( int i = 0; i < 10; i++ ) {
+ Assert.assertEquals(i+1, (int)hasTen.get(i));
+ }
+ }
+
+ @Test
+ public void testSettingTenElements() {
+ logger.warn("Executing testSettingTenElements");
+
+ for ( int i = 0; i < 10; i++ ) {
+ Assert.assertEquals(i+1, (int)hasTen.set(i, 2*i));
+ }
+
+ Assert.assertEquals(10, hasTen.size());
+ for ( int i = 0; i < 10; i++ ) {
+ Assert.assertEquals(2*i, (int)hasTen.get(i));
+ }
+ }
+
+ @Test
+ public void testAdd() {
+ logger.warn("Executing testAdd");
+
+ Assert.assertEquals(0, empty.size());
+ empty.add(1);
+ Assert.assertEquals(1, empty.size());
+ Assert.assertEquals(1, (int)empty.get(0));
+ empty.add(2);
+ Assert.assertEquals(2, empty.size());
+ Assert.assertEquals(2, (int)empty.get(1));
+ }
+
+ @Test
+ public void testSet1() {
+ logger.warn("Executing testSet1");
+
+ Assert.assertEquals(0, empty.size());
+ empty.set(0, 1);
+ Assert.assertEquals(1, empty.size());
+ Assert.assertEquals(1, (int)empty.get(0));
+
+ empty.set(1, 2);
+ Assert.assertEquals(2, empty.size());
+ Assert.assertEquals(2, (int)empty.get(1));
+
+ // doesn't expand
+ empty.set(0, 3);
+ Assert.assertEquals(2, empty.size());
+ Assert.assertEquals(3, (int)empty.get(0));
+ }
+
+ @Test
+ public void testSetExpanding() {
+ logger.warn("Executing testSetExpanding");
+
+ Assert.assertEquals(0, empty.size());
+ empty.set(3, 1);
+ Assert.assertEquals(4, empty.size());
+ Assert.assertEquals(empty.get(0), null);
+ Assert.assertEquals(empty.get(1), null);
+ Assert.assertEquals(empty.get(2), null);
+ Assert.assertEquals(1, (int)empty.get(3));
+ }
+
+ @Test
+ public void testSetExpandingReset() {
+ logger.warn("Executing testSetExpandingReset");
+
+ Assert.assertEquals(0, empty.size());
+ empty.set(3, 3);
+ empty.set(2, 2);
+ empty.set(1, 1);
+ empty.set(0, 0);
+ Assert.assertEquals(4, empty.size());
+ for ( int i = 0; i < 4; i++ )
+ Assert.assertEquals(i, (int)empty.get(i));
+ }
+
+ @Test
+ public void testSetExpandingBig() {
+ logger.warn("Executing testSetExpandingBig");
+
+ Assert.assertEquals(0, empty.size());
+ empty.set(1000, 1000);
+ Assert.assertEquals(1001, empty.size());
+ for ( int i = 0; i < 1000; i++ )
+ Assert.assertEquals(empty.get(i), null);
+ Assert.assertEquals(1000, (int)empty.get(1000));
+ }
+
+ @Test (expectedExceptions=IndexOutOfBoundsException.class )
+ public void testSetBadGetNegative() {
+ logger.warn("Executing testSetBadGetNegative");
+ empty.get(-1);
+ }
+
+ @Test
+ public void testSetBadGetPost() {
+ logger.warn("Executing testSetBadGetPost");
+ empty.set(1, 1);
+ Assert.assertEquals(empty.get(0), null);
+ Assert.assertEquals(1, (int)empty.get(1));
+ Assert.assertEquals(empty.get(2), null);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSiteUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSiteUnitTest.java
new file mode 100644
index 0000000..b1ba784
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSiteUnitTest.java
@@ -0,0 +1,80 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.File;
+
+public class ArgumentMatchSiteUnitTest {
+ @Test
+ public void testCommandLine() {
+ ArgumentMatchSite site = new ArgumentMatchSite(ArgumentMatchSource.COMMAND_LINE, 1);
+ Assert.assertEquals(site.getSource(), ArgumentMatchSource.COMMAND_LINE);
+ Assert.assertEquals(site.getIndex(), 1);
+ }
+
+ @Test
+ public void testFile() {
+ ArgumentMatchSource source = new ArgumentMatchFileSource(new File("test"));
+ ArgumentMatchSite site = new ArgumentMatchSite(source, 1);
+ Assert.assertEquals(site.getSource(), source);
+ Assert.assertEquals(site.getIndex(), 1);
+ }
+
+ @Test
+ public void testEquals() {
+ ArgumentMatchSource cmdLine = ArgumentMatchSource.COMMAND_LINE;
+ ArgumentMatchSite site1 = new ArgumentMatchSite(cmdLine, 1);
+ ArgumentMatchSite site2 = new ArgumentMatchSite(cmdLine, 2);
+
+ Assert.assertFalse(site1.equals(null));
+
+ Assert.assertTrue(site1.equals(site1));
+ Assert.assertFalse(site1.equals(site2));
+
+ Assert.assertFalse(site2.equals(site1));
+ Assert.assertTrue(site2.equals(site2));
+ }
+
+ @Test
+ public void testCompareTo() {
+ ArgumentMatchSource cmdLine = ArgumentMatchSource.COMMAND_LINE;
+ ArgumentMatchSite site1 = new ArgumentMatchSite(cmdLine, 1);
+ ArgumentMatchSite site2 = new ArgumentMatchSite(cmdLine, 2);
+
+ Assert.assertTrue(site1.compareTo(site1) == 0);
+ Assert.assertTrue(site1.compareTo(site2) < 0);
+ Assert.assertTrue(site2.compareTo(site1) > 0);
+ Assert.assertTrue(site2.compareTo(site2) == 0);
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testCompareToNull() {
+ new ArgumentMatchSite(ArgumentMatchSource.COMMAND_LINE, 0).compareTo(null);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSourceUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSourceUnitTest.java
new file mode 100644
index 0000000..8837f4b
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ArgumentMatchSourceUnitTest.java
@@ -0,0 +1,99 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.io.File;
+
+public class ArgumentMatchSourceUnitTest extends BaseTest {
+ @Test
+ public void testCommandLine() {
+ ArgumentMatchSource source = ArgumentMatchSource.COMMAND_LINE;
+ Assert.assertEquals(source.getType(), ArgumentMatchSourceType.CommandLine);
+ Assert.assertNull(source.getDescription());
+ }
+
+ @Test
+ public void testFile() {
+ File f = new File("test");
+ ArgumentMatchSource source = new ArgumentMatchFileSource(f);
+ Assert.assertEquals(source.getType(), ArgumentMatchSourceType.Provider);
+ Assert.assertEquals(source.getDescription(), "file " + f.getAbsolutePath());
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testNullFile() {
+ new ArgumentMatchSource(null);
+ }
+
+ @Test
+ public void testEquals() {
+ ArgumentMatchSource cmdLine = ArgumentMatchSource.COMMAND_LINE;
+ ArgumentMatchSource fileA = new ArgumentMatchFileSource(new File("a"));
+ ArgumentMatchSource fileB = new ArgumentMatchFileSource(new File("b"));
+
+ Assert.assertFalse(cmdLine.equals(null));
+
+ Assert.assertTrue(cmdLine.equals(cmdLine));
+ Assert.assertFalse(cmdLine.equals(fileA));
+ Assert.assertFalse(cmdLine.equals(fileB));
+
+ Assert.assertFalse(fileA.equals(cmdLine));
+ Assert.assertTrue(fileA.equals(fileA));
+ Assert.assertFalse(fileA.equals(fileB));
+
+ Assert.assertFalse(fileB.equals(cmdLine));
+ Assert.assertFalse(fileB.equals(fileA));
+ Assert.assertTrue(fileB.equals(fileB));
+ }
+
+ @Test
+ public void testCompareTo() {
+ ArgumentMatchSource cmdLine = ArgumentMatchSource.COMMAND_LINE;
+ ArgumentMatchSource fileA = new ArgumentMatchFileSource(new File("a"));
+ ArgumentMatchSource fileB = new ArgumentMatchFileSource(new File("b"));
+
+ Assert.assertTrue(cmdLine.compareTo(cmdLine) == 0);
+ Assert.assertTrue(cmdLine.compareTo(fileA) < 0);
+ Assert.assertTrue(cmdLine.compareTo(fileB) < 0);
+
+ Assert.assertTrue(fileA.compareTo(cmdLine) > 0);
+ Assert.assertTrue(fileA.compareTo(fileA) == 0);
+ Assert.assertTrue(fileA.compareTo(fileB) < 0);
+
+ Assert.assertTrue(fileB.compareTo(cmdLine) > 0);
+ Assert.assertTrue(fileB.compareTo(fileA) > 0);
+ Assert.assertTrue(fileB.compareTo(fileB) == 0);
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testCompareToNull() {
+ ArgumentMatchSource.COMMAND_LINE.compareTo(null);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ArgumentTypeDescriptorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ArgumentTypeDescriptorUnitTest.java
new file mode 100644
index 0000000..1dfffa3
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ArgumentTypeDescriptorUnitTest.java
@@ -0,0 +1,233 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import htsjdk.variant.variantcontext.VariantContext;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import htsjdk.samtools.SAMFileWriter;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.io.stubs.*;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import htsjdk.variant.variantcontext.writer.VariantContextWriter;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Collection;
+
+
+public class ArgumentTypeDescriptorUnitTest extends BaseTest {
+
+ ////////////////////////////////////////////////////////////////////
+ // This section tests the functionality of the @Output annotation //
+ ////////////////////////////////////////////////////////////////////
+
+ private class ATDTestCommandLineProgram extends CommandLineProgram {
+ public int execute() { return 0; }
+
+ @Override
+ public Collection<ArgumentTypeDescriptor> getArgumentTypeDescriptors() {
+ final GenomeAnalysisEngine engine = new GenomeAnalysisEngine();
+ return Arrays.asList( new SAMFileWriterArgumentTypeDescriptor(engine, System.out),
+ new OutputStreamArgumentTypeDescriptor(engine, System.out),
+ new VCFWriterArgumentTypeDescriptor(engine, System.out, null));
+ }
+
+ protected abstract class ATDTestOutputArgumentSource {
+ public abstract Object getOut();
+ }
+
+ protected class OutputRequiredSamArgumentSource extends ATDTestOutputArgumentSource {
+ @Output(shortName="o", doc="output file", required = true)
+ public SAMFileWriter out;
+ public Object getOut() { return out; }
+ }
+
+ protected class OutputRequiredVcfArgumentSource extends ATDTestOutputArgumentSource {
+ @Output(shortName="o", doc="output file", required = true)
+ public VariantContextWriter out;
+ public Object getOut() { return out; }
+ }
+
+ protected class OutputRequiredStreamArgumentSource extends ATDTestOutputArgumentSource {
+ @Output(shortName="o", doc="output file", required = true)
+ public PrintStream out;
+ public Object getOut() { return out; }
+ }
+
+ protected class OutputNotRequiredNoDefaultSamArgumentSource extends ATDTestOutputArgumentSource {
+ @Output(shortName="o", doc="output file", required = false, defaultToStdout = false)
+ public SAMFileWriter out;
+ public Object getOut() { return out; }
+ }
+
+ protected class OutputNotRequiredNoDefaultVcfArgumentSource extends ATDTestOutputArgumentSource {
+ @Output(shortName="o", doc="output file", required = false, defaultToStdout = false)
+ public VariantContextWriter out;
+ public Object getOut() { return out; }
+ }
+
+ protected class OutputNotRequiredNoDefaultStreamArgumentSource extends ATDTestOutputArgumentSource {
+ @Output(shortName="o", doc="output file", required = false, defaultToStdout = false)
+ public PrintStream out;
+ public Object getOut() { return out; }
+ }
+
+ protected class OutputNotRequiredSamArgumentSource extends ATDTestOutputArgumentSource {
+ @Output(shortName="o", doc="output file", required = false)
+ public SAMFileWriter out;
+ public Object getOut() { return out; }
+ }
+
+ protected class OutputNotRequiredVcfArgumentSource extends ATDTestOutputArgumentSource {
+ @Output(shortName="o", doc="output file", required = false)
+ public VariantContextWriter out;
+ public Object getOut() { return out; }
+ }
+
+ protected class OutputNotRequiredStreamArgumentSource extends ATDTestOutputArgumentSource {
+ @Output(shortName="o", doc="output file", required = false)
+ public PrintStream out;
+ public Object getOut() { return out; }
+ }
+ }
+
+ @DataProvider(name = "OutputProvider")
+ public Object[][] OutputProvider() {
+
+ ObjectArrayList<Object[]> tests = new ObjectArrayList<Object[]>();
+
+ final ATDTestCommandLineProgram clp = new ATDTestCommandLineProgram();
+
+ for ( final Object obj : Arrays.asList(clp.new OutputRequiredSamArgumentSource(), clp.new OutputRequiredVcfArgumentSource(), clp.new OutputRequiredStreamArgumentSource()) ) {
+ for ( final boolean provided : Arrays.asList(true, false) ) {
+ tests.add(new Object[]{obj, true, true, provided});
+ }
+ }
+
+ for ( final Object obj : Arrays.asList(clp.new OutputNotRequiredSamArgumentSource(), clp.new OutputNotRequiredVcfArgumentSource(), clp.new OutputNotRequiredStreamArgumentSource()) ) {
+ for ( final boolean provided : Arrays.asList(true, false) ) {
+ tests.add(new Object[]{obj, false, true, provided});
+ }
+ }
+
+ for ( final Object obj : Arrays.asList(clp.new OutputNotRequiredNoDefaultSamArgumentSource(), clp.new OutputNotRequiredNoDefaultVcfArgumentSource(), clp.new OutputNotRequiredNoDefaultStreamArgumentSource()) ) {
+ for ( final boolean provided : Arrays.asList(true, false) ) {
+ tests.add(new Object[]{obj, false, false, provided});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "OutputProvider")
+ public void testOutput(final ATDTestCommandLineProgram.ATDTestOutputArgumentSource argumentSource, final boolean required, final boolean hasDefault, final boolean provided) {
+
+ final ParsingEngine parser = new ParsingEngine(new ATDTestCommandLineProgram());
+ parser.addArgumentSource(argumentSource.getClass());
+ parser.parse(provided ? new String[] {"out", "foo"} : new String[] {});
+
+ try {
+ parser.loadArgumentsIntoObject(argumentSource);
+
+ if ( !provided && (required || !hasDefault) )
+ Assert.assertEquals(argumentSource.getOut(), null);
+ else if ( !provided )
+ Assert.assertNotEquals(argumentSource.getOut(), null);
+ else if ( argumentSource.getOut() == null || !(argumentSource.getOut() instanceof SAMFileWriterStub) ) // can't test this one case
+ Assert.assertEquals(!provided, outputIsStdout(argumentSource.getOut()));
+
+ } catch (Exception e) {
+ throw new ReviewedGATKException(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testRodBindingsCollection() {
+
+ final ParsingEngine parser = new ParsingEngine(new ATDTestCommandLineProgram());
+
+ //A list file containing a single VCF
+ final File listFile = createTempListFile("oneVCF", privateTestDir + "empty.vcf");
+
+ try {
+ Object result = ArgumentTypeDescriptor.getRodBindingsCollection(listFile,
+ parser,
+ VariantContext.class,
+ "variant",
+ new Tags(),
+ "variantTest");
+ if (!(result instanceof RodBindingCollection))
+ throw new ReviewedGATKException("getRodBindingsCollection did not return a RodBindingCollection");
+ RodBindingCollection<?> rbc = (RodBindingCollection) result;
+
+ Assert.assertEquals(rbc.getType(), VariantContext.class);
+ Assert.assertEquals(rbc.getRodBindings().size(), 1);
+
+ } catch (IOException e) {
+ throw new ReviewedGATKException(e.getMessage(), e);
+ }
+
+ //The same file, now with an extra blank line
+ final File listFileWithBlank = createTempListFile("oneVCFwithBlankLine", privateTestDir + "empty.vcf", "");
+ try {
+ Object result = ArgumentTypeDescriptor.getRodBindingsCollection(listFileWithBlank,
+ parser,
+ VariantContext.class,
+ "variant",
+ new Tags(),
+ "variantTest");
+ if (!(result instanceof RodBindingCollection))
+ throw new ReviewedGATKException("getRodBindingsCollection did not return a RodBindingCollection");
+ RodBindingCollection<?> rbc = (RodBindingCollection) result;
+
+ Assert.assertEquals(rbc.getType(), VariantContext.class);
+ Assert.assertEquals(rbc.getRodBindings().size(), 1);
+
+ } catch (IOException e) {
+ throw new ReviewedGATKException(e.getMessage(), e);
+ }
+ }
+
+ private static boolean outputIsStdout(final Object out) {
+ if ( out == null ) {
+ return false;
+ } else if ( out instanceof SAMFileWriterStub ) {
+ return ((SAMFileWriterStub)out).getOutputStream() != System.out;
+ } else if ( out instanceof VariantContextWriterStub ) {
+ return ((VariantContextWriterStub)out).getOutputStream() == System.out;
+ } else if ( out instanceof OutputStreamStub ) {
+ return ((OutputStreamStub)out).getOutputStream() == System.out;
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/InvalidArgumentIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/InvalidArgumentIntegrationTest.java
new file mode 100644
index 0000000..8ab2159
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/InvalidArgumentIntegrationTest.java
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: chartl
+ * Date: 8/31/12
+ * Time: 11:03 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class InvalidArgumentIntegrationTest extends WalkerTest {
+ private static final String callsB36 = BaseTest.validationDataLocation + "lowpass.N3.chr1.raw.vcf";
+
+ private WalkerTest.WalkerTestSpec baseTest(String flag, String arg, Class exeption) {
+ return new WalkerTest.WalkerTestSpec("-T VariantsToTable -M 10 --variant:vcf "
+ + callsB36 + " -F POS,CHROM -R "
+ + b36KGReference + " -o %s " + flag + " " + arg,
+ 1, exeption);
+
+ }
+
+ @Test
+ public void testUnknownReadFilter() {
+ executeTest("UnknownReadFilter",baseTest("-rf","TestUnknownReadFilter", UserException.MalformedReadFilterException.class));
+ }
+
+ @Test
+ public void testMalformedWalkerArgs() {
+ executeTest("MalformedWalkerArgs",
+ new WalkerTest.WalkerTestSpec("-T UnknownWalkerName -M 10 --variant:vcf "
+ + callsB36 + " -F POS,CHROM -R "
+ + b36KGReference + " -o %s ",
+ 1, UserException.MalformedWalkerArgumentsException.class));
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/LoggingIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/LoggingIntegrationTest.java
new file mode 100644
index 0000000..d690f68
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/LoggingIntegrationTest.java
@@ -0,0 +1,117 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Level;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.MD5DB;
+import org.broadinstitute.gatk.utils.MD5Mismatch;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.utils.runtime.*;
+
+public class LoggingIntegrationTest {
+ private final MD5DB md5db = new MD5DB();
+
+ private class LoggingTestProvider extends BaseTest.TestDataProvider {
+
+ private final String baseCmdLine;
+
+ private final Level logLevel;
+ private final String logFileStr;
+ public final File argumentOutputFile;
+ public final File pipedOutputFile;
+
+ private LoggingTestProvider(final Level logLevel, final boolean explicitLogfile) throws IOException {
+ super(LoggingTestProvider.class);
+
+ // TODO: a better command line that exercises log levels besides INFO
+ this.baseCmdLine = String.format("java -cp %s %s -T SelectVariants -R %s -V %s -L 1:1000000-2000000 --no_cmdline_in_header",
+ StringUtils.join(RuntimeUtils.getAbsoluteClassPaths(), File.pathSeparatorChar),
+ CommandLineGATK.class.getCanonicalName(), BaseTest.b37KGReference, BaseTest.b37_NA12878_OMNI);
+
+ this.logLevel = logLevel;
+ this.logFileStr = explicitLogfile ? " -log " + BaseTest.createTempFile(logLevel.toString(), "log") : "";
+ this.argumentOutputFile = BaseTest.createTempFile(logLevel.toString(), "vcf");
+ this.pipedOutputFile = BaseTest.createTempFile(logLevel.toString(), "vcf");
+ }
+
+ public final String getCmdLine(boolean redirectStdout) {
+ String command = String.format("%s -l %s %s", baseCmdLine, logLevel, logFileStr);
+ return redirectStdout ? command : command + " -o " + argumentOutputFile;
+ }
+
+ public String toString() {
+ return String.format("LoggingTestProvider logLevel=%s", logLevel);
+ }
+ }
+
+ @DataProvider(name = "LoggingTest")
+ public Object[][] makeLoggingTestProvider() throws IOException {
+ for (Boolean explicitLogFile : Arrays.asList(true, false)) {
+ // TODO: enable other logging levels when tests for those exist
+ new LoggingTestProvider(Level.DEBUG, explicitLogFile);
+ }
+
+ return LoggingTestProvider.getTests(LoggingTestProvider.class);
+ }
+
+ /**
+ * test that using an output argument produces the same output as stdout
+ */
+ @Test(dataProvider = "LoggingTest")
+ public void testStdoutEquivalence(final LoggingTestProvider cfg) throws IOException {
+
+ ProcessController pc = ProcessController.getThreadLocal();
+
+ // output argument
+
+ ProcessSettings ps = new ProcessSettings(cfg.getCmdLine(false).split("\\s+"));
+ pc.execAndCheck(ps);
+ String output_argument_md5 = md5db.calculateFileMD5(cfg.argumentOutputFile);
+
+ // pipe to stdout
+
+ ps = new ProcessSettings(cfg.getCmdLine(true).split("\\s+"));
+ ps.setStdoutSettings(new OutputStreamSettings(cfg.pipedOutputFile));
+ pc.execAndCheck(ps);
+
+ MD5DB.MD5Match result = md5db.testFileMD5("LoggingIntegrationTest", "LoggingIntegrationTest", cfg.pipedOutputFile, output_argument_md5, false);
+ if(result.failed) {
+ final MD5Mismatch failure = new MD5Mismatch(result.actualMD5, result.expectedMD5, result.diffEngineOutput);
+ Assert.fail(failure.toString());
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ParsingEngineUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ParsingEngineUnitTest.java
new file mode 100644
index 0000000..d3c85b6
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/ParsingEngineUnitTest.java
@@ -0,0 +1,1140 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.apache.commons.io.FileUtils;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import htsjdk.variant.variantcontext.VariantContext;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * Test suite for the parsing engine.
+ */
+public class ParsingEngineUnitTest extends BaseTest {
+ /** we absolutely cannot have this file existing, or we'll fail the UnitTest */
+ private final static String NON_EXISTANT_FILENAME_VCF = "this_file_should_not_exist_on_disk_123456789.vcf";
+ private ParsingEngine parsingEngine;
+
+ @BeforeMethod
+ public void setUp() {
+ parsingEngine = new ParsingEngine(null);
+ RodBinding.resetNameCounter();
+ }
+
+ private class InputFileArgProvider {
+ @Argument(fullName="input_file",doc="input file",shortName="I")
+ public String inputFile;
+ }
+
+ @Test
+ public void shortNameArgumentTest() {
+ final String[] commandLine = new String[] {"-I","na12878.bam"};
+
+ parsingEngine.addArgumentSource( InputFileArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ InputFileArgProvider argProvider = new InputFileArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.inputFile,"na12878.bam","Argument is not correctly initialized");
+ }
+
+ @Test
+ public void multiCharShortNameArgumentTest() {
+ final String[] commandLine = new String[] {"-out","out.txt"};
+
+ parsingEngine.addArgumentSource( MultiCharShortNameArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ MultiCharShortNameArgProvider argProvider = new MultiCharShortNameArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.outputFile,"out.txt","Argument is not correctly initialized");
+ }
+
+
+ private class MultiCharShortNameArgProvider {
+ @Argument(shortName="out", doc="output file")
+ public String outputFile;
+ }
+
+ @Test
+ public void longNameArgumentTest() {
+ final String[] commandLine = new String[] {"--input_file", "na12878.bam"};
+
+ parsingEngine.addArgumentSource( InputFileArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ InputFileArgProvider argProvider = new InputFileArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.inputFile,"na12878.bam","Argument is not correctly initialized");
+ }
+
+ @Test
+ public void extraWhitespaceTest() {
+ final String[] commandLine = new String[] {" --input_file ", "na12878.bam"};
+
+ parsingEngine.addArgumentSource( InputFileArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ InputFileArgProvider argProvider = new InputFileArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.inputFile,"na12878.bam","Argument is not correctly initialized");
+ }
+
+ @Test
+ public void primitiveArgumentTest() {
+ final String[] commandLine = new String[] {"--foo", "5"};
+
+ parsingEngine.addArgumentSource( PrimitiveArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ PrimitiveArgProvider argProvider = new PrimitiveArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.foo, 5, "Argument is not correctly initialized");
+ }
+
+ @Test(expectedExceptions=InvalidArgumentValueException.class)
+ public void primitiveArgumentNoValueTest() {
+ final String[] commandLine = new String[] {"--foo"};
+
+ parsingEngine.addArgumentSource( PrimitiveArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ PrimitiveArgProvider argProvider = new PrimitiveArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.foo, 5, "Argument is not correctly initialized");
+ }
+
+ private class PrimitiveArgProvider {
+ @Argument(doc="simple integer")
+ int foo;
+ }
+
+ @Test
+ public void flagTest() {
+ final String[] commandLine = new String[] {"--all_loci"};
+
+ parsingEngine.addArgumentSource( AllLociArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ AllLociArgProvider argProvider = new AllLociArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertTrue(argProvider.allLoci,"Argument is not correctly initialized");
+ }
+
+ private class AllLociArgProvider {
+ @Argument(fullName="all_loci",shortName="A", doc="all loci")
+ public boolean allLoci = false;
+ }
+
+ @Test
+ public void arrayTest() {
+ final String[] commandLine = new String[] {"-I", "foo.txt", "--input_file", "bar.txt"};
+
+ parsingEngine.addArgumentSource( MultiValueArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ MultiValueArgProvider argProvider = new MultiValueArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.inputFile.length, 2, "Argument array is of incorrect length");
+ Assert.assertEquals(argProvider.inputFile[0],"foo.txt","1st filename is incorrect");
+ Assert.assertEquals(argProvider.inputFile[1],"bar.txt","2nd filename is incorrect");
+ }
+
+ private class MultiValueArgProvider {
+ @Argument(fullName="input_file",shortName="I", doc="input file")
+ public String[] inputFile;
+ }
+
+ @Test
+ public void enumTest() {
+ final String[] commandLine = new String[] { "--test_enum", "TWO" };
+
+ parsingEngine.addArgumentSource( EnumArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ EnumArgProvider argProvider = new EnumArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.testEnum, TestEnum.TWO, "Enum value is not correct");
+ }
+
+ @Test
+ public void enumMixedCaseTest() {
+ final String[] commandLine = new String[] { "--test_enum", "oNe" };
+
+ parsingEngine.addArgumentSource( EnumArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ EnumArgProvider argProvider = new EnumArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.testEnum, TestEnum.ONE, "Enum value is not correct");
+ }
+
+ @Test
+ public void enumDefaultTest() {
+ final String[] commandLine = new String[] {};
+
+ parsingEngine.addArgumentSource( EnumArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ EnumArgProvider argProvider = new EnumArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.testEnum, TestEnum.THREE, "Enum value is not correct");
+ }
+
+ public enum TestEnum { ONE, TWO, THREE }
+
+ private class EnumArgProvider {
+ @Argument(fullName="test_enum",shortName="ti",doc="test enum",required=false)
+ public TestEnum testEnum = TestEnum.THREE;
+ }
+
+ @Test
+ public void typedCollectionTest() {
+ final String[] commandLine = new String[] { "-N","2","-N","4","-N","6","-N","8","-N","10" };
+
+ parsingEngine.addArgumentSource( IntegerListArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ IntegerListArgProvider argProvider = new IntegerListArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertNotNull(argProvider.integers, "Argument array is null");
+ Assert.assertEquals(argProvider.integers.size(), 5, "Argument array is of incorrect length");
+ Assert.assertEquals(argProvider.integers.get(0).intValue(), 2, "1st integer is incorrect");
+ Assert.assertEquals(argProvider.integers.get(1).intValue(), 4, "2nd integer is incorrect");
+ Assert.assertEquals(argProvider.integers.get(2).intValue(), 6, "3rd integer is incorrect");
+ Assert.assertEquals(argProvider.integers.get(3).intValue(), 8, "4th integer is incorrect");
+ Assert.assertEquals(argProvider.integers.get(4).intValue(), 10, "5th integer is incorrect");
+ }
+
+ private class IntegerListArgProvider {
+ @Argument(fullName="integer_list",shortName="N",doc="integer list")
+ public List<Integer> integers;
+ }
+
+ @Test
+ public void untypedCollectionTest() {
+ final String[] commandLine = new String[] { "-N","2","-N","4","-N","6","-N","8","-N","10" };
+
+ parsingEngine.addArgumentSource( UntypedListArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ UntypedListArgProvider argProvider = new UntypedListArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertNotNull(argProvider.integers, "Argument array is null");
+ Assert.assertEquals(argProvider.integers.size(), 5, "Argument array is of incorrect length");
+ Assert.assertEquals(argProvider.integers.get(0), "2", "1st integer is incorrect");
+ Assert.assertEquals(argProvider.integers.get(1), "4", "2nd integer is incorrect");
+ Assert.assertEquals(argProvider.integers.get(2), "6", "3rd integer is incorrect");
+ Assert.assertEquals(argProvider.integers.get(3), "8", "4th integer is incorrect");
+ Assert.assertEquals(argProvider.integers.get(4), "10", "5th integer is incorrect");
+ }
+
+ private class UntypedListArgProvider {
+ @Argument(fullName="untyped_list",shortName="N", doc="untyped list")
+ public List integers;
+ }
+
+ @Test(expectedExceptions=MissingArgumentException.class)
+ public void requiredArgTest() {
+ final String[] commandLine = new String[0];
+
+ parsingEngine.addArgumentSource( RequiredArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+ }
+
+ private class RequiredArgProvider {
+ @Argument(required=true,doc="value")
+ public Integer value;
+ }
+
+ @Test
+ public void defaultValueTest() {
+ // First try getting the default.
+ String[] commandLine = new String[0];
+
+ parsingEngine.addArgumentSource( DefaultValueArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ DefaultValueArgProvider argProvider = new DefaultValueArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.value.intValue(), 42, "Default value is not correctly initialized");
+
+ // Then try to override it.
+ commandLine = new String[] { "--value", "27" };
+
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.value.intValue(), 27, "Default value is not correctly initialized");
+ }
+
+ private class DefaultValueArgProvider {
+ @Argument(doc="value",required=false)
+ public Integer value = 42;
+ }
+
+ @Test
+ public void disableValidationOfRequiredArgTest() {
+ final String[] commandLine = new String[0];
+
+ parsingEngine.addArgumentSource( RequiredArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate( EnumSet.of(ParsingEngine.ValidationType.MissingRequiredArgument) );
+
+ RequiredArgProvider argProvider = new RequiredArgProvider();
+ parsingEngine.loadArgumentsIntoObject(argProvider );
+
+ Assert.assertNull(argProvider.value, "Value should have remain unset");
+ }
+
+ @Test
+ public void unrequiredArgTest() {
+ final String[] commandLine = new String[0];
+
+ parsingEngine.addArgumentSource( UnrequiredArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ UnrequiredArgProvider argProvider = new UnrequiredArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertNull(argProvider.value, "Value was unrequired and unspecified; contents should be null");
+ }
+
+ private class UnrequiredArgProvider {
+ @Argument(required=false,doc="unrequired value")
+ public Integer value;
+ }
+
+ @Test(expectedExceptions=InvalidArgumentException.class)
+ public void invalidArgTest() {
+ final String[] commandLine = new String[] { "--foo" };
+
+ parsingEngine.addArgumentSource( UnrequiredArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+ }
+
+ @Test(expectedExceptions= ReviewedGATKException.class)
+ public void duplicateLongNameTest() {
+ parsingEngine.addArgumentSource( DuplicateLongNameProvider.class );
+ }
+
+ private class DuplicateLongNameProvider {
+ @Argument(fullName="myarg",doc="my arg")
+ public Integer foo;
+
+ @Argument(fullName="myarg", doc="my arg")
+ public Integer bar;
+ }
+
+ @Test(expectedExceptions= ReviewedGATKException.class)
+ public void duplicateShortNameTest() {
+ parsingEngine.addArgumentSource( DuplicateShortNameProvider.class );
+ }
+
+
+ private class DuplicateShortNameProvider {
+ @Argument(shortName="myarg", doc="my arg")
+ public Integer foo;
+
+ @Argument(shortName="myarg", doc="my arg")
+ public Integer bar;
+ }
+
+ @Test(expectedExceptions=UnmatchedArgumentException.class)
+ public void missingArgumentNameTest() {
+ final String[] commandLine = new String[] {"foo.txt"};
+
+ parsingEngine.addArgumentSource( NoArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+ }
+
+ private class NoArgProvider {
+
+ }
+
+ @Test(expectedExceptions=UnmatchedArgumentException.class)
+ public void extraValueTest() {
+ final String[] commandLine = new String[] {"-I", "foo.txt", "bar.txt"};
+
+ parsingEngine.addArgumentSource( InputFileArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+ }
+
+ @Test(expectedExceptions=MissingArgumentException.class)
+ public void multipleInvalidArgTest() {
+ final String[] commandLine = new String[] {"-N1", "-N2", "-N3"};
+
+ parsingEngine.addArgumentSource( RequiredArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+ }
+
+ @Test(expectedExceptions=TooManyValuesForArgumentException.class)
+ public void invalidArgCountTest() {
+ final String[] commandLine = new String[] {"--value","1","--value","2","--value","3"};
+
+ parsingEngine.addArgumentSource( RequiredArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+ }
+
+ @Test
+ public void packageProtectedArgTest() {
+ final String[] commandLine = new String[] {"--foo", "1"};
+
+ parsingEngine.addArgumentSource( PackageProtectedArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ PackageProtectedArgProvider argProvider = new PackageProtectedArgProvider();
+ parsingEngine.loadArgumentsIntoObject(argProvider);
+
+ Assert.assertEquals(argProvider.foo.intValue(), 1, "Argument is not correctly initialized");
+ }
+
+ private class PackageProtectedArgProvider {
+ @Argument(doc="foo")
+ Integer foo;
+ }
+
+ @Test
+ public void derivedArgTest() {
+ final String[] commandLine = new String[] {"--bar", "5"};
+
+ parsingEngine.addArgumentSource( DerivedArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ DerivedArgProvider argProvider = new DerivedArgProvider();
+ parsingEngine.loadArgumentsIntoObject(argProvider);
+
+ Assert.assertEquals(argProvider.bar.intValue(), 5, "Argument is not correctly initialized");
+ }
+
+ private class DerivedArgProvider extends BaseArgProvider {
+ }
+
+ private class BaseArgProvider {
+ @Argument(doc="bar")
+ public Integer bar;
+ }
+
+ @Test
+ public void correctDefaultArgNameTest() {
+ parsingEngine.addArgumentSource( CamelCaseArgProvider.class );
+
+ DefinitionMatcher matcher = ArgumentDefinitions.FullNameDefinitionMatcher;
+ ArgumentDefinition definition = parsingEngine.argumentDefinitions.findArgumentDefinition("myarg", matcher);
+
+ Assert.assertNotNull(definition, "Invalid default argument name assigned");
+ }
+
+ @SuppressWarnings("unused")
+ private class CamelCaseArgProvider {
+ @Argument(doc="my arg")
+ Integer myArg;
+ }
+
+ @Test(expectedExceptions=UnmatchedArgumentException.class)
+ public void booleanWithParameterTest() {
+ final String[] commandLine = new String[] {"--mybool", "true"};
+
+ parsingEngine.addArgumentSource( BooleanArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+ }
+
+ @SuppressWarnings("unused")
+ private class BooleanArgProvider {
+ @Argument(doc="my bool")
+ boolean myBool;
+ }
+
+ @Test
+ public void validParseForAnalysisTypeTest() {
+ final String[] commandLine = new String[] {"--analysis_type", "Pileup" };
+
+ parsingEngine.addArgumentSource( AnalysisTypeArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate( EnumSet.of(ParsingEngine.ValidationType.MissingRequiredArgument) );
+
+ AnalysisTypeArgProvider argProvider = new AnalysisTypeArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.Analysis_Name,"Pileup","Argument is not correctly initialized");
+ }
+
+ private class AnalysisTypeArgProvider {
+ @Argument(fullName="analysis_type", shortName="T", doc="Type of analysis to run")
+ public String Analysis_Name = null;
+ }
+
+ @Test(expectedExceptions=TooManyValuesForArgumentException.class)
+ public void invalidParseForAnalysisTypeTest() {
+ final String[] commandLine = new String[] {"--analysis_type", "Pileup", "-T", "CountReads" };
+
+ parsingEngine.addArgumentSource( AnalysisTypeArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate( EnumSet.of(ParsingEngine.ValidationType.MissingRequiredArgument) );
+ }
+
+ @Test(expectedExceptions=ArgumentsAreMutuallyExclusiveException.class)
+ public void mutuallyExclusiveArgumentsTest() {
+ // Passing only foo should work fine...
+ String[] commandLine = new String[] {"--foo","5"};
+
+ parsingEngine.addArgumentSource( MutuallyExclusiveArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ MutuallyExclusiveArgProvider argProvider = new MutuallyExclusiveArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.foo.intValue(), 5, "Argument is not correctly initialized");
+
+ // But when foo and bar come together, danger!
+ commandLine = new String[] {"--foo","5","--bar","6"};
+
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+ }
+
+ @SuppressWarnings("unused")
+ private class MutuallyExclusiveArgProvider {
+ @Argument(doc="foo",exclusiveOf="bar")
+ Integer foo;
+
+ @Argument(doc="bar",required=false)
+ Integer bar;
+ }
+
+ @Test(expectedExceptions=InvalidArgumentValueException.class)
+ public void argumentValidationTest() {
+ // Passing only foo should work fine...
+ String[] commandLine = new String[] {"--value","521"};
+
+ parsingEngine.addArgumentSource( ValidatingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ ValidatingArgProvider argProvider = new ValidatingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.value.intValue(), 521, "Argument is not correctly initialized");
+
+ // Try some invalid arguments
+ commandLine = new String[] {"--value","foo"};
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+ }
+
+ private class ValidatingArgProvider {
+ @Argument(doc="value",validation="\\d+")
+ Integer value;
+ }
+
+ @Test
+ public void argumentCollectionTest() {
+ String[] commandLine = new String[] { "--value", "5" };
+
+ parsingEngine.addArgumentSource( ArgumentCollectionProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ ArgumentCollectionProvider argProvider = new ArgumentCollectionProvider();
+ parsingEngine.loadArgumentsIntoObject(argProvider);
+
+ Assert.assertEquals(argProvider.rap.value.intValue(), 5, "Argument is not correctly initialized");
+ }
+
+ private class ArgumentCollectionProvider {
+ @ArgumentCollection
+ RequiredArgProvider rap = new RequiredArgProvider();
+ }
+
+ @Test(expectedExceptions= ReviewedGATKException.class)
+ public void multipleArgumentCollectionTest() {
+ parsingEngine.addArgumentSource( MultipleArgumentCollectionProvider.class );
+ }
+
+ @SuppressWarnings("unused")
+ private class MultipleArgumentCollectionProvider {
+ @ArgumentCollection
+ RequiredArgProvider rap1 = new RequiredArgProvider();
+ @ArgumentCollection
+ RequiredArgProvider rap2 = new RequiredArgProvider();
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Tests of the RodBinding<T> system
+ //
+ // --------------------------------------------------------------------------------
+
+ private class SingleRodBindingArgProvider {
+ @Input(fullName="binding", shortName="V", required=true)
+ public RodBinding<Feature> binding;
+ }
+
+ @Test
+ public void basicRodBindingArgumentTest() {
+ final String[] commandLine = new String[] {"-V:vcf",NON_EXISTANT_FILENAME_VCF};
+
+ parsingEngine.addArgumentSource( SingleRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ SingleRodBindingArgProvider argProvider = new SingleRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.binding.getName(), "binding", "Name isn't set properly");
+ Assert.assertEquals(argProvider.binding.getSource(), NON_EXISTANT_FILENAME_VCF, "Source isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getType(), Feature.class, "Type isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.isBound(), true, "Bound() isn't returning its expected value");
+ Assert.assertEquals(argProvider.binding.getTags().getPositionalTags().size(), 1, "Tags aren't correctly set");
+ }
+
+ private class ShortNameOnlyRodBindingArgProvider {
+ @Input(shortName="short", required=false)
+ public RodBinding<Feature> binding; // = RodBinding.makeUnbound(Feature.class);
+ }
+
+ @Test
+ public void shortNameOnlyRodBindingArgumentTest() {
+ final String[] commandLine = new String[] {"-short:vcf",NON_EXISTANT_FILENAME_VCF};
+
+ parsingEngine.addArgumentSource( ShortNameOnlyRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ ShortNameOnlyRodBindingArgProvider argProvider = new ShortNameOnlyRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.binding.getName(), "binding", "Name isn't set properly");
+ Assert.assertEquals(argProvider.binding.getSource(), NON_EXISTANT_FILENAME_VCF, "Source isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getType(), Feature.class, "Type isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.isBound(), true, "Bound() isn't returning its expected value");
+ Assert.assertEquals(argProvider.binding.getTags().getPositionalTags().size(), 1, "Tags aren't correctly set");
+ }
+
+ private class OptionalRodBindingArgProvider {
+ @Input(fullName="binding", shortName="V", required=false)
+ public RodBinding<Feature> binding;
+
+ @Input(fullName="bindingNull", shortName="VN", required=false)
+ public RodBinding<VariantContext> bindingNull = null;
+ }
+
+ @Test
+ public void optionalRodBindingArgumentTest() {
+ final String[] commandLine = new String[] {};
+
+ parsingEngine.addArgumentSource( OptionalRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ OptionalRodBindingArgProvider argProvider = new OptionalRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertNotNull(argProvider.binding, "Default value not applied corrected to RodBinding");
+ Assert.assertEquals(argProvider.binding.getName(), RodBinding.UNBOUND_VARIABLE_NAME, "Name isn't set properly");
+ Assert.assertEquals(argProvider.binding.getSource(), RodBinding.UNBOUND_SOURCE, "Source isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getType(), Feature.class, "Type isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.isBound(), false, "Bound() isn't returning its expected value");
+ Assert.assertEquals(argProvider.binding.getTags().getPositionalTags().size(), 0, "Tags aren't correctly set");
+
+ Assert.assertNotNull(argProvider.bindingNull, "Default value not applied corrected to RodBinding");
+ Assert.assertEquals(argProvider.bindingNull.getName(), RodBinding.UNBOUND_VARIABLE_NAME, "Name isn't set properly");
+ Assert.assertEquals(argProvider.bindingNull.getSource(), RodBinding.UNBOUND_SOURCE, "Source isn't set to its expected value");
+ Assert.assertEquals(argProvider.bindingNull.getType(), VariantContext.class, "Type isn't set to its expected value");
+ Assert.assertEquals(argProvider.bindingNull.isBound(), false, "Bound() isn't returning its expected value");
+ Assert.assertEquals(argProvider.bindingNull.getTags().getPositionalTags().size(), 0, "Tags aren't correctly set");
+ }
+
+ @Test(expectedExceptions = UserException.class)
+ public void rodBindingArgumentTestMissingType() {
+ final String[] commandLine = new String[] {"-V",NON_EXISTANT_FILENAME_VCF};
+
+ parsingEngine.addArgumentSource( SingleRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ SingleRodBindingArgProvider argProvider = new SingleRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject(argProvider);
+ }
+
+ @Test(expectedExceptions = UserException.class)
+ public void rodBindingArgumentTestTooManyTags() {
+ final String[] commandLine = new String[] {"-V:x,y,z",NON_EXISTANT_FILENAME_VCF};
+
+ parsingEngine.addArgumentSource( SingleRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ SingleRodBindingArgProvider argProvider = new SingleRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject(argProvider);
+ }
+
+ private class VariantContextRodBindingArgProvider {
+ @Input(fullName = "binding", shortName="V")
+ public RodBinding<VariantContext> binding;
+ }
+
+ @Test
+ public void variantContextBindingArgumentTest() {
+ final String[] commandLine = new String[] {"-V:vcf",NON_EXISTANT_FILENAME_VCF};
+
+ parsingEngine.addArgumentSource( VariantContextRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ VariantContextRodBindingArgProvider argProvider = new VariantContextRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.binding.getName(), "binding", "Name isn't set properly");
+ Assert.assertEquals(argProvider.binding.getSource(), NON_EXISTANT_FILENAME_VCF, "Source isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getType(), VariantContext.class, "Type isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getTags().getPositionalTags().size(), 1, "Tags aren't correctly set");
+ }
+
+ private class ListRodBindingArgProvider {
+ @Input(fullName = "binding", shortName="V", required=false)
+ public List<RodBinding<Feature>> bindings;
+ }
+
+ @Test
+ public void listRodBindingArgumentTest() {
+ final String[] commandLine = new String[] {"-V:vcf",NON_EXISTANT_FILENAME_VCF};
+
+ parsingEngine.addArgumentSource( ListRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ ListRodBindingArgProvider argProvider = new ListRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.bindings.size(), 1, "Unexpected number of bindings");
+ RodBinding<Feature> binding = argProvider.bindings.get(0);
+ Assert.assertEquals(binding.getName(), "binding", "Name isn't set properly");
+ Assert.assertEquals(binding.getSource(), NON_EXISTANT_FILENAME_VCF, "Source isn't set to its expected value");
+ Assert.assertEquals(binding.getType(), Feature.class, "Type isn't set to its expected value");
+ Assert.assertEquals(binding.getTags().getPositionalTags().size(), 1, "Tags aren't correctly set");
+ }
+
+ @Test
+ public void listRodBindingArgumentTest2Args() {
+ final String[] commandLine = new String[] {"-V:vcf",NON_EXISTANT_FILENAME_VCF, "-V:vcf", "bar.vcf"};
+
+ parsingEngine.addArgumentSource( ListRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ ListRodBindingArgProvider argProvider = new ListRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.bindings.size(), 2, "Unexpected number of bindings");
+
+ RodBinding<Feature> binding = argProvider.bindings.get(0);
+ Assert.assertEquals(binding.getName(), "binding", "Name isn't set properly");
+ Assert.assertEquals(binding.getSource(), NON_EXISTANT_FILENAME_VCF, "Source isn't set to its expected value");
+ Assert.assertEquals(binding.getType(), Feature.class, "Type isn't set to its expected value");
+ Assert.assertEquals(binding.getTags().getPositionalTags().size(), 1, "Tags aren't correctly set");
+
+ RodBinding<Feature> binding2 = argProvider.bindings.get(1);
+ Assert.assertEquals(binding2.getName(), "binding2", "Name isn't set properly");
+ Assert.assertEquals(binding2.getSource(), "bar.vcf", "Source isn't set to its expected value");
+ Assert.assertEquals(binding2.getType(), Feature.class, "Type isn't set to its expected value");
+ Assert.assertEquals(binding2.getTags().getPositionalTags().size(), 1, "Tags aren't correctly set");
+ }
+
+ @Test
+ public void listRodBindingArgumentTest0Args() {
+ final String[] commandLine = new String[] {};
+
+ parsingEngine.addArgumentSource( ListRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ ListRodBindingArgProvider argProvider = new ListRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertNull(argProvider.bindings, "Bindings were not null");
+ }
+
+ @Test
+ public void listRodBindingArgumentTestExplicitlyNamed() {
+ final String[] commandLine = new String[] {"-V:foo,vcf",NON_EXISTANT_FILENAME_VCF, "-V:foo,vcf", "bar.vcf"};
+
+ parsingEngine.addArgumentSource( ListRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ ListRodBindingArgProvider argProvider = new ListRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.bindings.size(), 2, "Unexpected number of bindings");
+ Assert.assertEquals(argProvider.bindings.get(0).getName(), "foo", "Name isn't set properly");
+ Assert.assertEquals(argProvider.bindings.get(1).getName(), "foo2", "Name isn't set properly");
+ }
+
+ private final static String HISEQ_VCF = privateTestDir + "HiSeq.10000.vcf";
+ private final static String TRANCHES_FILE = privateTestDir + "tranches.6.txt";
+
+ @Test
+ public void variantContextBindingTestDynamicTyping1() {
+ final String[] commandLine = new String[] {"-V", HISEQ_VCF};
+
+ parsingEngine.addArgumentSource( VariantContextRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ VariantContextRodBindingArgProvider argProvider = new VariantContextRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.binding.getName(), "binding", "Name isn't set properly");
+ Assert.assertEquals(argProvider.binding.getSource(), HISEQ_VCF, "Source isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getType(), VariantContext.class, "Type isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getTags().getPositionalTags().size(), 0, "Tags aren't correctly set");
+ }
+
+ @Test
+ public void variantContextBindingTestDynamicTypingNameAsSingleArgument() {
+ final String[] commandLine = new String[] {"-V:name", HISEQ_VCF};
+
+ parsingEngine.addArgumentSource( VariantContextRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ VariantContextRodBindingArgProvider argProvider = new VariantContextRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.binding.getName(), "name", "Name isn't set properly");
+ Assert.assertEquals(argProvider.binding.getSource(), HISEQ_VCF, "Source isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getType(), VariantContext.class, "Type isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getTags().getPositionalTags().size(), 1, "Tags aren't correctly set");
+ }
+
+ @Test()
+ public void variantContextBindingTestDynamicTypingTwoTagsPassing() {
+ final String[] commandLine = new String[] {"-V:name,vcf", HISEQ_VCF};
+
+ parsingEngine.addArgumentSource( VariantContextRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ VariantContextRodBindingArgProvider argProvider = new VariantContextRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.binding.getName(), "name", "Name isn't set properly");
+ Assert.assertEquals(argProvider.binding.getSource(), HISEQ_VCF, "Source isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getType(), VariantContext.class, "Type isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getTags().getPositionalTags().size(), 2, "Tags aren't correctly set");
+ }
+
+ @Test()
+ public void variantContextBindingTestDynamicTypingTwoTagsCausingTypeFailure() {
+ final String[] commandLine = new String[] {"-V:name,beagle", HISEQ_VCF};
+
+ parsingEngine.addArgumentSource( VariantContextRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ VariantContextRodBindingArgProvider argProvider = new VariantContextRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject(argProvider);
+
+ Assert.assertEquals(argProvider.binding.getName(), "name", "Name isn't set properly");
+ Assert.assertEquals(argProvider.binding.getSource(), HISEQ_VCF, "Source isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getType(), VariantContext.class, "Type isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getTribbleType(), "beagle", "Type isn't set to its expected value");
+ Assert.assertEquals(argProvider.binding.getTags().getPositionalTags().size(), 2, "Tags aren't correctly set");
+ }
+
+ @Test(expectedExceptions = UserException.class)
+ public void variantContextBindingTestDynamicTypingUnknownTribbleType() {
+ final String[] commandLine = new String[] {"-V", TRANCHES_FILE};
+
+ parsingEngine.addArgumentSource( VariantContextRodBindingArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ VariantContextRodBindingArgProvider argProvider = new VariantContextRodBindingArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+ }
+
+ @Test
+ public void argumentListTest() throws IOException {
+ File argsFile = BaseTest.createTempListFile("args.", "-I na12878.bam");
+ try {
+ final String[] commandLine = new String[] {"-args", argsFile.getPath()};
+ parsingEngine.addArgumentSource(InputFileArgProvider.class);
+ parsingEngine.parse(commandLine);
+ parsingEngine.validate();
+
+ InputFileArgProvider argProvider = new InputFileArgProvider();
+ parsingEngine.loadArgumentsIntoObject(argProvider);
+
+ Assert.assertEquals(argProvider.inputFile, "na12878.bam", "Argument is not correctly initialized");
+ } finally {
+ FileUtils.deleteQuietly(argsFile);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private class NumericRangeArgProvider {
+ @Argument(fullName = "intWithHardMinAndMax", minValue = 5, maxValue = 10)
+ public int intWithHardMinAndMax;
+
+ @Argument(fullName = "intWithHardMin", minValue = 5)
+ public int intWithHardMin;
+
+ @Argument(fullName = "intWithHardMax", maxValue = 10)
+ public int intWithHardMax;
+
+ @Argument(fullName = "intWithSoftMinAndMax", minRecommendedValue = 5, maxRecommendedValue = 10)
+ public int intWithSoftMinAndMax;
+
+ @Argument(fullName = "intWithSoftMin", minRecommendedValue = 5)
+ public int intWithSoftMin;
+
+ @Argument(fullName = "intWithSoftMax", maxRecommendedValue = 10)
+ public int intWithSoftMax;
+
+ @Argument(fullName = "intWithHardAndSoftMinAndMax", minValue = 5, minRecommendedValue = 7, maxValue = 10, maxRecommendedValue = 9)
+ public int intWithHardAndSoftMinAndMax;
+
+ @Argument(fullName = "intWithHardAndSoftMin", minValue = 5, minRecommendedValue = 7)
+ public int intWithHardAndSoftMin;
+
+ @Argument(fullName = "intWithHardAndSoftMax", maxValue = 10, maxRecommendedValue = 8)
+ public int intWithHardAndSoftMax;
+
+ @Argument(fullName = "intWithHardMinAndMaxDefaultOutsideRange", minValue = 5, maxValue = 10)
+ public int intWithHardMinAndMaxDefaultOutsideRange = -1;
+
+ @Argument(fullName = "integerWithHardMinAndMax", minValue = 5, maxValue = 10)
+ public Integer integerWithHardMinAndMax;
+
+ @Argument(fullName = "byteWithHardMinAndMax", minValue = 5, maxValue = 10)
+ public byte byteWithHardMinAndMax;
+
+ @Argument(fullName = "byteWithHardMin", minValue = 5)
+ public byte byteWithHardMin;
+
+ @Argument(fullName = "byteWithHardMax", maxValue = 10)
+ public byte byteWithHardMax;
+
+ @Argument(fullName = "doubleWithHardMinAndMax", minValue = 5.5, maxValue = 10.0)
+ public double doubleWithHardMinAndMax;
+
+ @Argument(fullName = "doubleWithHardMin", minValue = 5.5)
+ public double doubleWithHardMin;
+
+ @Argument(fullName = "doubleWithHardMax", maxValue = 10.0)
+ public double doubleWithHardMax;
+ }
+
+ @DataProvider(name = "NumericRangeConstraintViolationDataProvider")
+ public Object[][] numericRangeConstraintViolationDataProvider() {
+ return new Object[][] {
+ { new String[]{"--intWithHardMinAndMax", "11"} },
+ { new String[]{"--intWithHardMinAndMax", "4"} },
+ { new String[]{"--intWithHardMin", "4"} },
+ { new String[]{"--intWithHardMax", "11"} },
+ { new String[]{"--intWithHardAndSoftMinAndMax", "11"} },
+ { new String[]{"--intWithHardAndSoftMinAndMax", "4"} },
+ { new String[]{"--intWithHardAndSoftMin", "4"} },
+ { new String[]{"--intWithHardAndSoftMax", "11"} },
+ { new String[]{"--intWithHardMinAndMaxDefaultOutsideRange", "11"} },
+ { new String[]{"--intWithHardMinAndMaxDefaultOutsideRange", "4"} },
+ { new String[]{"--integerWithHardMinAndMax", "11"} },
+ { new String[]{"--integerWithHardMinAndMax", "4"} },
+ { new String[]{"--byteWithHardMinAndMax", "11"} },
+ { new String[]{"--byteWithHardMinAndMax", "4"} },
+ { new String[]{"--byteWithHardMin", "4"} },
+ { new String[]{"--byteWithHardMax", "11"} },
+ { new String[]{"--doubleWithHardMinAndMax", "5.4"} },
+ { new String[]{"--doubleWithHardMinAndMax", "10.1"} },
+ { new String[]{"--doubleWithHardMin", "5.4"} },
+ { new String[]{"--doubleWithHardMax", "10.1"} }
+ };
+ }
+
+ @Test(dataProvider = "NumericRangeConstraintViolationDataProvider",
+ expectedExceptions = ArgumentValueOutOfRangeException.class)
+ public void testNumericRangeWithConstraintViolation( final String[] commandLine ) {
+ runNumericArgumentRangeTest(commandLine);
+ }
+
+ @DataProvider(name = "NumericRangeWithoutConstraintViolationDataProvider")
+ public Object[][] numericRangeWithoutConstraintViolationDataProvider() {
+ return new Object[][] {
+ { new String[]{"--intWithHardMinAndMax", "10"} },
+ { new String[]{"--intWithHardMinAndMax", "5"} },
+ { new String[]{"--intWithHardMinAndMax", "7"} },
+ { new String[]{"--intWithHardMin", "11"} },
+ { new String[]{"--intWithHardMax", "4"} },
+ { new String[]{"--intWithSoftMinAndMax", "11"} },
+ { new String[]{"--intWithSoftMinAndMax", "4"} },
+ { new String[]{"--intWithSoftMin", "4"} },
+ { new String[]{"--intWithSoftMax", "11"} },
+ { new String[]{"--intWithHardAndSoftMinAndMax", "5"} },
+ { new String[]{"--intWithHardAndSoftMinAndMax", "7"} },
+ { new String[]{"--intWithHardAndSoftMinAndMax", "8"} },
+ { new String[]{"--intWithHardAndSoftMinAndMax", "9"} },
+ { new String[]{"--intWithHardAndSoftMinAndMax", "10"} },
+ { new String[]{"--intWithHardAndSoftMin", "5"} },
+ { new String[]{"--intWithHardAndSoftMin", "6"} },
+ { new String[]{"--intWithHardAndSoftMin", "7"} },
+ { new String[]{"--intWithHardAndSoftMax", "10"} },
+ { new String[]{"--intWithHardAndSoftMax", "9"} },
+ { new String[]{"--intWithHardAndSoftMax", "8"} },
+ { new String[]{"--intWithHardMinAndMaxDefaultOutsideRange", "10"} },
+ { new String[]{"--intWithHardMinAndMaxDefaultOutsideRange", "5"} },
+ { new String[]{"--intWithHardMinAndMaxDefaultOutsideRange", "7"} },
+ { new String[]{"--integerWithHardMinAndMax", "10"} },
+ { new String[]{"--integerWithHardMinAndMax", "5"} },
+ { new String[]{"--byteWithHardMinAndMax", "10"} },
+ { new String[]{"--byteWithHardMinAndMax", "5"} },
+ { new String[]{"--byteWithHardMinAndMax", "7"} },
+ { new String[]{"--byteWithHardMin", "5"} },
+ { new String[]{"--byteWithHardMax", "10"} },
+ { new String[]{"--doubleWithHardMinAndMax", "5.5"} },
+ { new String[]{"--doubleWithHardMinAndMax", "10.0"} },
+ { new String[]{"--doubleWithHardMinAndMax", "7.5"} },
+ { new String[]{"--doubleWithHardMin", "5.5"} },
+ { new String[]{"--doubleWithHardMin", "15.5"} },
+ { new String[]{"--doubleWithHardMax", "10.0"} },
+ { new String[]{"--doubleWithHardMax", "7.5"} }
+ };
+ }
+
+ @Test(dataProvider = "NumericRangeWithoutConstraintViolationDataProvider")
+ public void testNumericRangeWithoutConstraintViolation( final String[] commandLine ) {
+ // These tests succeed if no exception is thrown, since no constraints have been violated
+ runNumericArgumentRangeTest(commandLine);
+ }
+
+ private void runNumericArgumentRangeTest( final String[] commandLine ) {
+ parsingEngine.addArgumentSource(NumericRangeArgProvider.class);
+ parsingEngine.parse(commandLine);
+
+ NumericRangeArgProvider argProvider = new NumericRangeArgProvider();
+ parsingEngine.loadArgumentsIntoObject(argProvider);
+ }
+
+ @SuppressWarnings("unused")
+ private class VariedTypeArgProvider {
+ @Argument(fullName = "intVal", required=false)
+ private int anInt;
+
+ @Argument(fullName = "stringVal", required=false)
+ private String aString;
+
+ @Argument(fullName = "enumVal", required=false)
+ private TestEnum anEnum;
+
+ @Argument(fullName = "fileVal", required=false)
+ private File aFile;
+
+ @Argument(fullName = "stringSet", required=false)
+ private Set<String> someStrings;
+
+ @Argument(fullName = "intervalVal", required=false)
+ private IntervalBinding<Feature> anInterval;
+ }
+
+ @DataProvider(name = "MissingArgumentValueDataProvider")
+ public Object[][] missingArgumentDataProvider() {
+ return new Object[][]{
+ { new String[]{"--intVal"} },
+ { new String[]{"--stringVal"} },
+ { new String[]{"--enumVal"} },
+ { new String[]{"--fileVal"} },
+ { new String[]{"--stringSet"} },
+ { new String[]{"--stringSet", "aha", "--stringSet"} },
+ { new String[]{"--intervalVal"} }
+ };
+ }
+
+ @Test(dataProvider = "MissingArgumentValueDataProvider",
+ expectedExceptions = {InvalidArgumentValueException.class, MissingArgumentValueException.class})
+ public void testMissingArguments( final String[] commandLine ) {
+ parsingEngine.addArgumentSource( VariedTypeArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ VariedTypeArgProvider argProvider = new VariedTypeArgProvider();
+ parsingEngine.loadArgumentsIntoObject(argProvider);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/RodBindingCollectionUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/RodBindingCollectionUnitTest.java
new file mode 100644
index 0000000..a846384
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/RodBindingCollectionUnitTest.java
@@ -0,0 +1,133 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import htsjdk.variant.variantcontext.VariantContext;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Collection;
+
+public class RodBindingCollectionUnitTest extends BaseTest {
+
+ private ParsingEngine parsingEngine;
+ private Tags mytags;
+
+ private static final String defaultTagString = "VCF";
+ private static final String testVCFFileName = privateTestDir + "empty.vcf";
+ private static final String testListFileName = createTempListFile("oneVCF", testVCFFileName).getAbsolutePath();
+
+ @BeforeMethod
+ public void setUp() {
+ parsingEngine = new ParsingEngine(null);
+ RodBinding.resetNameCounter();
+ mytags = new Tags();
+ mytags.addPositionalTag(defaultTagString);
+ }
+
+ private class RodBindingCollectionArgProvider {
+ @Argument(fullName="input",doc="input",shortName="V")
+ public RodBindingCollection<VariantContext> input;
+ }
+
+ @Test
+ public void testStandardVCF() {
+ final String[] commandLine = new String[] {"-V", testVCFFileName};
+
+ parsingEngine.addArgumentSource( RodBindingCollectionArgProvider.class );
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ final RodBindingCollectionArgProvider argProvider = new RodBindingCollectionArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.input.getRodBindings().iterator().next().getSource(), testVCFFileName, "Argument is not correctly initialized");
+ }
+
+ @Test
+ public void testList() {
+ final String[] commandLine = new String[] {"-V", testListFileName};
+
+ parsingEngine.addArgumentSource(RodBindingCollectionArgProvider.class);
+ parsingEngine.parse( commandLine );
+ parsingEngine.validate();
+
+ final RodBindingCollectionArgProvider argProvider = new RodBindingCollectionArgProvider();
+ parsingEngine.loadArgumentsIntoObject( argProvider );
+
+ Assert.assertEquals(argProvider.input.getRodBindings().iterator().next().getSource(), testVCFFileName, "Argument is not correctly initialized");
+ }
+
+ @Test
+ public void testDefaultTagsInFile() throws IOException {
+
+ final File testFile = createTempListFile("RodBindingCollectionUnitTest.defaultTags", testVCFFileName);
+
+ ArgumentTypeDescriptor.getRodBindingsCollection(testFile, parsingEngine, VariantContext.class, "foo", mytags, "input");
+
+ final Collection<RodBinding> bindings = parsingEngine.getRodBindings();
+ Assert.assertNotNull(bindings);
+ Assert.assertEquals(bindings.size(), 1);
+
+ final RodBinding binding = bindings.iterator().next();
+ Assert.assertEquals(parsingEngine.getTags(binding), mytags);
+ }
+
+ @Test(expectedExceptions = UserException.BadArgumentValue.class)
+ public void testDuplicateEntriesInFile() throws IOException {
+
+ final File testFile = createTempListFile("RodBindingCollectionUnitTest.variantListWithDuplicates", testVCFFileName, testVCFFileName);
+
+ ArgumentTypeDescriptor.getRodBindingsCollection(testFile, parsingEngine, VariantContext.class, "foo", mytags, "input");
+ }
+
+ @Test(expectedExceptions = UserException.BadArgumentValue.class)
+ public void testValidateEmptyFile() throws IOException {
+ final File testFile = createTempListFile("RodBindingCollectionUnitTest.emptyVCFList");
+
+ ArgumentTypeDescriptor.getRodBindingsCollection(testFile, parsingEngine, VariantContext.class, "foo", mytags, "input");
+ }
+
+ @Test
+ public void testOverrideTagsInFile() throws IOException {
+ final File testFile = createTempListFile("RodBindingCollectionUnitTest.overrideTags", "foo " + testVCFFileName);
+
+ ArgumentTypeDescriptor.getRodBindingsCollection(testFile, parsingEngine, VariantContext.class, "foo", mytags, "input");
+
+ final Collection<RodBinding> bindings = parsingEngine.getRodBindings();
+ Assert.assertNotNull(bindings);
+ Assert.assertEquals(bindings.size(), 1);
+
+ final RodBinding binding = bindings.iterator().next();
+ Assert.assertNotEquals(parsingEngine.getTags(binding), mytags);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/RodBindingUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/RodBindingUnitTest.java
new file mode 100644
index 0000000..bffb1d2
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/commandline/RodBindingUnitTest.java
@@ -0,0 +1,82 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.commandline;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import htsjdk.variant.variantcontext.VariantContext;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+
+/**
+ * Test suite for the parsing engine.
+ */
+public class RodBindingUnitTest extends BaseTest {
+ Tags mytags = new Tags();
+
+ @BeforeMethod
+ public void setUp() {
+ RodBinding.resetNameCounter();
+ }
+
+ @Test
+ public void testStandardRodBinding() {
+ RodBinding<VariantContext> b = new RodBinding<VariantContext>(VariantContext.class, "b", "foo", "vcf", mytags);
+ Assert.assertEquals(b.getName(), "b");
+ Assert.assertEquals(b.getType(), VariantContext.class);
+ Assert.assertEquals(b.getSource(), "foo");
+ Assert.assertEquals(b.getTribbleType(), "vcf");
+ Assert.assertEquals(b.isBound(), true);
+ }
+
+ @Test
+ public void testUnboundRodBinding() {
+ RodBinding<VariantContext> u = RodBinding.makeUnbound(VariantContext.class);
+ Assert.assertEquals(u.getName(), RodBinding.UNBOUND_VARIABLE_NAME);
+ Assert.assertEquals(u.getSource(), RodBinding.UNBOUND_SOURCE);
+ Assert.assertEquals(u.getType(), VariantContext.class);
+ Assert.assertEquals(u.getTribbleType(), RodBinding.UNBOUND_TRIBBLE_TYPE);
+ Assert.assertEquals(u.isBound(), false);
+ }
+
+ @Test
+ public void testMultipleBindings() {
+ String name = "binding";
+ RodBinding<VariantContext> b1 = new RodBinding<VariantContext>(VariantContext.class, name, "foo", "vcf", mytags);
+ Assert.assertEquals(b1.getName(), name);
+ Assert.assertEquals(b1.getType(), VariantContext.class);
+ Assert.assertEquals(b1.getSource(), "foo");
+ Assert.assertEquals(b1.getTribbleType(), "vcf");
+ Assert.assertEquals(b1.isBound(), true);
+
+ RodBinding<VariantContext> b2 = new RodBinding<VariantContext>(VariantContext.class, name, "foo", "vcf", mytags);
+ Assert.assertEquals(b2.getName(), name + "2");
+ Assert.assertEquals(b2.getType(), VariantContext.class);
+ Assert.assertEquals(b2.getSource(), "foo");
+ Assert.assertEquals(b2.getTribbleType(), "vcf");
+ Assert.assertEquals(b2.isBound(), true);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/crypt/CryptUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/crypt/CryptUtilsUnitTest.java
new file mode 100644
index 0000000..c44bfdc
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/crypt/CryptUtilsUnitTest.java
@@ -0,0 +1,199 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.crypt;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.SkipException;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Arrays;
+
+public class CryptUtilsUnitTest extends BaseTest {
+
+ @Test
+ public void testGenerateValidKeyPairWithDefaultSettings() {
+ KeyPair keyPair = CryptUtils.generateKeyPair();
+ Assert.assertTrue(CryptUtils.keysDecryptEachOther(keyPair.getPrivate(), keyPair.getPublic()));
+ }
+
+ @DataProvider( name = "InvalidKeyPairSettings" )
+ public Object[][] invalidKeyPairSettingsDataProvider() {
+ return new Object[][] {
+ { -1, CryptUtils.DEFAULT_ENCRYPTION_ALGORITHM, CryptUtils.DEFAULT_RANDOM_NUMBER_GENERATION_ALGORITHM},
+ { CryptUtils.DEFAULT_KEY_LENGTH, "Made-up algorithm", CryptUtils.DEFAULT_RANDOM_NUMBER_GENERATION_ALGORITHM},
+ { CryptUtils.DEFAULT_KEY_LENGTH, CryptUtils.DEFAULT_ENCRYPTION_ALGORITHM, "Made-up algorithm"}
+ };
+ }
+
+ @Test( dataProvider = "InvalidKeyPairSettings", expectedExceptions = ReviewedGATKException.class )
+ public void testGenerateKeyPairWithInvalidSettings( int keyLength, String encryptionAlgorithm, String randomNumberGenerationAlgorithm ) {
+ KeyPair keyPair = CryptUtils.generateKeyPair(keyLength, encryptionAlgorithm, randomNumberGenerationAlgorithm);
+ }
+
+ @Test
+ public void testGATKMasterKeyPairMutualDecryption() {
+ if ( gatkPrivateKeyExistsButReadPermissionDenied() ) {
+ throw new SkipException(String.format("Skipping test %s because we do not have permission to read the GATK private key",
+ "testGATKMasterKeyPairMutualDecryption"));
+ }
+
+ Assert.assertTrue(CryptUtils.keysDecryptEachOther(CryptUtils.loadGATKMasterPrivateKey(), CryptUtils.loadGATKMasterPublicKey()));
+ }
+
+ @Test
+ public void testGATKMasterPrivateKeyWithDistributedPublicKeyMutualDecryption() {
+ if ( gatkPrivateKeyExistsButReadPermissionDenied() ) {
+ throw new SkipException(String.format("Skipping test %s because we do not have permission to read the GATK private key",
+ "testGATKMasterPrivateKeyWithDistributedPublicKeyMutualDecryption"));
+ }
+
+ Assert.assertTrue(CryptUtils.keysDecryptEachOther(CryptUtils.loadGATKMasterPrivateKey(), CryptUtils.loadGATKDistributedPublicKey()));
+ }
+
+ @Test
+ public void testKeyPairWriteThenRead() {
+ KeyPair keyPair = CryptUtils.generateKeyPair();
+ File privateKeyFile = createTempFile("testKeyPairWriteThenRead_private", "key");
+ File publicKeyFile = createTempFile("testKeyPairWriteThenRead_public", "key");
+
+ CryptUtils.writeKeyPair(keyPair, privateKeyFile, publicKeyFile);
+
+ assertKeysAreEqual(keyPair.getPrivate(), CryptUtils.readPrivateKey(privateKeyFile));
+ assertKeysAreEqual(keyPair.getPublic(), CryptUtils.readPublicKey(publicKeyFile));
+ }
+
+ @Test
+ public void testPublicKeyWriteThenReadFromFile() {
+ File keyFile = createTempFile("testPublicKeyWriteThenReadFromFile", "key");
+ PublicKey publicKey = CryptUtils.generateKeyPair().getPublic();
+
+ CryptUtils.writeKey(publicKey, keyFile);
+
+ assertKeysAreEqual(publicKey, CryptUtils.readPublicKey(keyFile));
+ }
+
+ @Test
+ public void testPublicKeyWriteThenReadFromStream() throws IOException {
+ File keyFile = createTempFile("testPublicKeyWriteThenReadFromStream", "key");
+ PublicKey publicKey = CryptUtils.generateKeyPair().getPublic();
+
+ CryptUtils.writeKey(publicKey, keyFile);
+
+ assertKeysAreEqual(publicKey, CryptUtils.readPublicKey(new FileInputStream(keyFile)));
+ }
+
+ @Test
+ public void testPrivateKeyWriteThenReadFromFile() {
+ File keyFile = createTempFile("testPrivateKeyWriteThenReadFromFile", "key");
+ PrivateKey privateKey = CryptUtils.generateKeyPair().getPrivate();
+
+ CryptUtils.writeKey(privateKey, keyFile);
+
+ assertKeysAreEqual(privateKey, CryptUtils.readPrivateKey(keyFile));
+ }
+
+ @Test
+ public void testPrivateKeyWriteThenReadFromStream() throws IOException {
+ File keyFile = createTempFile("testPrivateKeyWriteThenReadFromStream", "key");
+ PrivateKey privateKey = CryptUtils.generateKeyPair().getPrivate();
+
+ CryptUtils.writeKey(privateKey, keyFile);
+
+ assertKeysAreEqual(privateKey, CryptUtils.readPrivateKey(new FileInputStream(keyFile)));
+ }
+
+ @Test( expectedExceptions = UserException.CouldNotReadInputFile.class )
+ public void testReadNonExistentPublicKey() {
+ File nonExistentFile = new File("jdshgkdfhg.key");
+ Assert.assertFalse(nonExistentFile.exists());
+
+ CryptUtils.readPublicKey(nonExistentFile);
+ }
+
+ @Test( expectedExceptions = UserException.CouldNotReadInputFile.class )
+ public void testReadNonExistentPrivateKey() {
+ File nonExistentFile = new File("jdshgkdfhg.key");
+ Assert.assertFalse(nonExistentFile.exists());
+
+ CryptUtils.readPrivateKey(nonExistentFile);
+ }
+
+ @Test
+ public void testDecodePublicKey() {
+ PublicKey originalKey = CryptUtils.generateKeyPair().getPublic();
+ PublicKey decodedKey = CryptUtils.decodePublicKey(originalKey.getEncoded(), CryptUtils.DEFAULT_ENCRYPTION_ALGORITHM);
+ assertKeysAreEqual(originalKey, decodedKey);
+ }
+
+ @Test
+ public void testDecodePrivateKey() {
+ PrivateKey originalKey = CryptUtils.generateKeyPair().getPrivate();
+ PrivateKey decodedKey = CryptUtils.decodePrivateKey(originalKey.getEncoded(), CryptUtils.DEFAULT_ENCRYPTION_ALGORITHM);
+ assertKeysAreEqual(originalKey, decodedKey);
+ }
+
+ @Test
+ public void testLoadGATKMasterPrivateKey() {
+ if ( gatkPrivateKeyExistsButReadPermissionDenied() ) {
+ throw new SkipException(String.format("Skipping test %s because we do not have permission to read the GATK private key",
+ "testLoadGATKMasterPrivateKey"));
+ }
+
+ PrivateKey gatkMasterPrivateKey = CryptUtils.loadGATKMasterPrivateKey();
+ }
+
+ @Test
+ public void testLoadGATKMasterPublicKey() {
+ PublicKey gatkMasterPublicKey = CryptUtils.loadGATKMasterPublicKey();
+ }
+
+ @Test
+ public void testLoadGATKDistributedPublicKey() {
+ PublicKey gatkDistributedPublicKey = CryptUtils.loadGATKDistributedPublicKey();
+ }
+
+ private void assertKeysAreEqual( Key originalKey, Key keyFromDisk ) {
+ Assert.assertTrue(Arrays.equals(originalKey.getEncoded(), keyFromDisk.getEncoded()));
+ Assert.assertEquals(originalKey.getAlgorithm(), keyFromDisk.getAlgorithm());
+ Assert.assertEquals(originalKey.getFormat(), keyFromDisk.getFormat());
+ }
+
+ private boolean gatkPrivateKeyExistsButReadPermissionDenied() {
+ File gatkPrivateKey = new File(CryptUtils.GATK_MASTER_PRIVATE_KEY_FILE);
+ return gatkPrivateKey.exists() && ! gatkPrivateKey.canRead();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/crypt/GATKKeyIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/crypt/GATKKeyIntegrationTest.java
new file mode 100644
index 0000000..9cafd61
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/crypt/GATKKeyIntegrationTest.java
@@ -0,0 +1,157 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.crypt;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.broadinstitute.gatk.engine.phonehome.GATKRunReport;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+public class GATKKeyIntegrationTest extends WalkerTest {
+
+ public static final String BASE_COMMAND = String.format("-T PrintReads -R %s -I %s -o %%s",
+ publicTestDir + "exampleFASTA.fasta",
+ publicTestDir + "exampleBAM.bam");
+ public static final String MD5_UPON_SUCCESSFUL_RUN = "e7b4a5b62f9d4badef1cd07040011b2b";
+
+
+ private void runGATKKeyTest ( String testName, String etArg, String keyArg, Class expectedException, String md5 ) {
+ String command = BASE_COMMAND + String.format(" %s %s", etArg, keyArg);
+
+ WalkerTestSpec spec = expectedException != null ?
+ new WalkerTestSpec(command, 1, expectedException) :
+ new WalkerTestSpec(command, 1, Arrays.asList(md5));
+
+ spec.disableImplicitArgs(); // Turn off automatic inclusion of -et/-K args by WalkerTest
+ executeTest(testName, spec);
+ }
+
+ @Test
+ public void testValidKeyNoET() {
+ runGATKKeyTest("testValidKeyNoET",
+ "-et " + GATKRunReport.PhoneHomeOption.NO_ET,
+ "-K " + keysDataLocation + "valid.key",
+ null,
+ MD5_UPON_SUCCESSFUL_RUN);
+ }
+
+ @Test
+ public void testValidKeyETStdout() {
+ runGATKKeyTest("testValidKeyETStdout",
+ "-et " + GATKRunReport.PhoneHomeOption.STDOUT,
+ "-K " + keysDataLocation + "valid.key",
+ null,
+ MD5_UPON_SUCCESSFUL_RUN);
+ }
+
+ @Test
+ public void testValidKeyETStandard() {
+ runGATKKeyTest("testValidKeyETStandard",
+ "",
+ "-K " + keysDataLocation + "valid.key",
+ null,
+ MD5_UPON_SUCCESSFUL_RUN);
+ }
+
+ @Test
+ public void testNoKeyNoET() {
+ runGATKKeyTest("testNoKeyNoET",
+ "-et " + GATKRunReport.PhoneHomeOption.NO_ET,
+ "",
+ UserException.class,
+ null);
+ }
+
+ @Test
+ public void testNoKeyETStdout() {
+ runGATKKeyTest("testNoKeyETStdout",
+ "-et " + GATKRunReport.PhoneHomeOption.STDOUT,
+ "",
+ UserException.class,
+ null);
+ }
+
+ @Test
+ public void testNoKeyETStandard() {
+ runGATKKeyTest("testNoKeyETStandard",
+ "",
+ "",
+ null,
+ MD5_UPON_SUCCESSFUL_RUN);
+ }
+
+ @Test
+ public void testRevokedKey() {
+ runGATKKeyTest("testRevokedKey",
+ "-et " + GATKRunReport.PhoneHomeOption.NO_ET,
+ "-K " + keysDataLocation + "revoked.key",
+ UserException.KeySignatureVerificationException.class,
+ null);
+ }
+
+ @DataProvider(name = "CorruptKeyTestData")
+ public Object[][] corruptKeyDataProvider() {
+ return new Object[][] {
+ { "corrupt_empty.key", UserException.UnreadableKeyException.class },
+ { "corrupt_single_byte_file.key", UserException.UnreadableKeyException.class },
+ { "corrupt_random_contents.key", UserException.UnreadableKeyException.class },
+ { "corrupt_single_byte_deletion.key", UserException.UnreadableKeyException.class },
+ { "corrupt_single_byte_insertion.key", UserException.UnreadableKeyException.class },
+ { "corrupt_single_byte_change.key", UserException.UnreadableKeyException.class },
+ { "corrupt_multi_byte_deletion.key", UserException.UnreadableKeyException.class },
+ { "corrupt_multi_byte_insertion.key", UserException.UnreadableKeyException.class },
+ { "corrupt_multi_byte_change.key", UserException.UnreadableKeyException.class },
+ { "corrupt_bad_isize_field.key", UserException.UnreadableKeyException.class },
+ { "corrupt_bad_crc.key", UserException.UnreadableKeyException.class },
+ { "corrupt_no_email_address.key", UserException.UnreadableKeyException.class },
+ { "corrupt_no_sectional_delimiter.key", UserException.UnreadableKeyException.class },
+ { "corrupt_no_signature.key", UserException.UnreadableKeyException.class },
+ { "corrupt_bad_signature.key", UserException.KeySignatureVerificationException.class },
+ { "corrupt_non_gzipped_valid_key.key", UserException.UnreadableKeyException.class }
+ };
+ }
+
+ @Test(dataProvider = "CorruptKeyTestData")
+ public void testCorruptKey ( String corruptKeyName, Class expectedException ) {
+ runGATKKeyTest(String.format("testCorruptKey (%s)", corruptKeyName),
+ "-et " + GATKRunReport.PhoneHomeOption.NO_ET,
+ "-K " + keysDataLocation + corruptKeyName,
+ expectedException,
+ null);
+ }
+
+ @Test
+ public void testCorruptButNonRequiredKey() {
+ runGATKKeyTest("testCorruptButNonRequiredKey",
+ "",
+ "-K " + keysDataLocation + "corrupt_random_contents.key",
+ null,
+ MD5_UPON_SUCCESSFUL_RUN);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/crypt/GATKKeyUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/crypt/GATKKeyUnitTest.java
new file mode 100644
index 0000000..5fd6475
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/crypt/GATKKeyUnitTest.java
@@ -0,0 +1,129 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.crypt;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.SkipException;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.io.File;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+public class GATKKeyUnitTest extends BaseTest {
+
+ @Test
+ public void testCreateGATKKeyUsingMasterKeyPair() {
+ if ( gatkPrivateKeyExistsButReadPermissionDenied() ) {
+ throw new SkipException(String.format("Skipping test %s because we do not have permission to read the GATK private key",
+ "testCreateGATKKeyUsingMasterKeyPair"));
+ }
+
+ PrivateKey masterPrivateKey = CryptUtils.loadGATKMasterPrivateKey();
+ PublicKey masterPublicKey = CryptUtils.loadGATKMasterPublicKey();
+
+ // We should be able to create a valid GATKKey using our master key pair:
+ GATKKey key = new GATKKey(masterPrivateKey, masterPublicKey, "foo at bar.com");
+ Assert.assertTrue(key.isValid());
+ }
+
+ @Test
+ public void testCreateGATKKeyUsingMasterPrivateKeyAndDistributedPublicKey() {
+ if ( gatkPrivateKeyExistsButReadPermissionDenied() ) {
+ throw new SkipException(String.format("Skipping test %s because we do not have permission to read the GATK private key",
+ "testCreateGATKKeyUsingMasterPrivateKeyAndDistributedPublicKey"));
+ }
+
+ PrivateKey masterPrivateKey = CryptUtils.loadGATKMasterPrivateKey();
+ PublicKey distributedPublicKey = CryptUtils.loadGATKDistributedPublicKey();
+
+ // We should also be able to create a valid GATKKey using our master private
+ // key and the public key we distribute with the GATK:
+ GATKKey key = new GATKKey(masterPrivateKey, distributedPublicKey, "foo at bar.com");
+ Assert.assertTrue(key.isValid());
+ }
+
+ @Test( expectedExceptions = ReviewedGATKException.class )
+ public void testKeyPairMismatch() {
+ KeyPair firstKeyPair = CryptUtils.generateKeyPair();
+ KeyPair secondKeyPair = CryptUtils.generateKeyPair();
+
+ // Attempting to create a GATK Key with private and public keys that aren't part of the
+ // same key pair should immediately trigger a validation failure:
+ GATKKey key = new GATKKey(firstKeyPair.getPrivate(), secondKeyPair.getPublic(), "foo at bar.com");
+ }
+
+ @Test( expectedExceptions = ReviewedGATKException.class )
+ public void testEncryptionAlgorithmMismatch() {
+ KeyPair keyPair = CryptUtils.generateKeyPair(CryptUtils.DEFAULT_KEY_LENGTH, "DSA", CryptUtils.DEFAULT_RANDOM_NUMBER_GENERATION_ALGORITHM);
+
+ // Attempting to use a DSA private key to create an RSA signature should throw an error:
+ GATKKey key = new GATKKey(keyPair.getPrivate(), keyPair.getPublic(), "foo at bar.com", "SHA1withRSA");
+ }
+
+ @Test( expectedExceptions = UserException.class )
+ public void testInvalidEmailAddress() {
+ String emailAddressWithNulByte = new String(new byte[] { 0 });
+ KeyPair keyPair = CryptUtils.generateKeyPair();
+
+ // Email addresses cannot contain the NUL byte, since it's used as a sectional delimiter in the key file:
+ GATKKey key = new GATKKey(keyPair.getPrivate(), keyPair.getPublic(), emailAddressWithNulByte);
+ }
+
+ @Test
+ public void testCreateGATKKeyFromValidKeyFile() {
+ GATKKey key = new GATKKey(CryptUtils.loadGATKDistributedPublicKey(), new File(keysDataLocation + "valid.key"));
+ Assert.assertTrue(key.isValid());
+ }
+
+ @Test( expectedExceptions = UserException.UnreadableKeyException.class )
+ public void testCreateGATKKeyFromCorruptKeyFile() {
+ GATKKey key = new GATKKey(CryptUtils.loadGATKDistributedPublicKey(), new File(keysDataLocation + "corrupt_random_contents.key"));
+ }
+
+ @Test
+ public void testCreateGATKKeyFromRevokedKeyFile() {
+ GATKKey key = new GATKKey(CryptUtils.loadGATKDistributedPublicKey(), new File(keysDataLocation + "revoked.key"));
+ Assert.assertFalse(key.isValid());
+ }
+
+ @Test( expectedExceptions = UserException.CouldNotReadInputFile.class )
+ public void testCreateGATKKeyFromNonExistentFile() {
+ File nonExistentFile = new File("ghfdkgsdhg.key");
+ Assert.assertFalse(nonExistentFile.exists());
+
+ GATKKey key = new GATKKey(CryptUtils.loadGATKDistributedPublicKey(), nonExistentFile);
+ }
+
+ private boolean gatkPrivateKeyExistsButReadPermissionDenied() {
+ File gatkPrivateKey = new File(CryptUtils.GATK_MASTER_PRIVATE_KEY_FILE);
+ return gatkPrivateKey.exists() && ! gatkPrivateKey.canRead();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/fasta/CachingIndexedFastaSequenceFileUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/fasta/CachingIndexedFastaSequenceFileUnitTest.java
new file mode 100644
index 0000000..3e877b9
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/fasta/CachingIndexedFastaSequenceFileUnitTest.java
@@ -0,0 +1,264 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.fasta;
+
+
+// the imports for unit testing.
+
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequence;
+import htsjdk.samtools.SAMSequenceRecord;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Priority;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Basic unit test for CachingIndexedFastaSequenceFile
+ */
+public class CachingIndexedFastaSequenceFileUnitTest extends BaseTest {
+ private File simpleFasta = new File(publicTestDir + "/exampleFASTA.fasta");
+ private static final int STEP_SIZE = 1;
+ private final static boolean DEBUG = false;
+
+ //private static final List<Integer> QUERY_SIZES = Arrays.asList(1);
+ private static final List<Integer> QUERY_SIZES = Arrays.asList(1, 10, 100);
+ private static final List<Integer> CACHE_SIZES = Arrays.asList(-1, 100, 1000);
+
+ @DataProvider(name = "fastas")
+ public Object[][] createData1() {
+ List<Object[]> params = new ArrayList<Object[]>();
+ for ( File fasta : Arrays.asList(simpleFasta) ) {
+ for ( int cacheSize : CACHE_SIZES ) {
+ for ( int querySize : QUERY_SIZES ) {
+ params.add(new Object[]{fasta, cacheSize, querySize});
+ }
+ }
+ }
+
+ return params.toArray(new Object[][]{});
+ }
+
+ private static long getCacheSize(final long cacheSizeRequested) {
+ return cacheSizeRequested == -1 ? CachingIndexedFastaSequenceFile.DEFAULT_CACHE_SIZE : cacheSizeRequested;
+ }
+
+ @Test(dataProvider = "fastas", enabled = true && ! DEBUG)
+ public void testCachingIndexedFastaReaderSequential1(File fasta, int cacheSize, int querySize) throws FileNotFoundException {
+ final CachingIndexedFastaSequenceFile caching = new CachingIndexedFastaSequenceFile(fasta, getCacheSize(cacheSize), true, false);
+
+ SAMSequenceRecord contig = caching.getSequenceDictionary().getSequence(0);
+ logger.warn(String.format("Checking contig %s length %d with cache size %d and query size %d",
+ contig.getSequenceName(), contig.getSequenceLength(), cacheSize, querySize));
+ testSequential(caching, fasta, querySize);
+ }
+
+ private void testSequential(final CachingIndexedFastaSequenceFile caching, final File fasta, final int querySize) throws FileNotFoundException {
+ Assert.assertTrue(caching.isPreservingCase(), "testSequential only works for case preserving CachingIndexedFastaSequenceFile readers");
+
+ final IndexedFastaSequenceFile uncached = new IndexedFastaSequenceFile(fasta);
+
+ SAMSequenceRecord contig = uncached.getSequenceDictionary().getSequence(0);
+ for ( int i = 0; i < contig.getSequenceLength(); i += STEP_SIZE ) {
+ int start = i;
+ int stop = start + querySize;
+ if ( stop <= contig.getSequenceLength() ) {
+ ReferenceSequence cachedVal = caching.getSubsequenceAt(contig.getSequenceName(), start, stop);
+ ReferenceSequence uncachedVal = uncached.getSubsequenceAt(contig.getSequenceName(), start, stop);
+
+ Assert.assertEquals(cachedVal.getName(), uncachedVal.getName());
+ Assert.assertEquals(cachedVal.getContigIndex(), uncachedVal.getContigIndex());
+ Assert.assertEquals(cachedVal.getBases(), uncachedVal.getBases());
+ }
+ }
+
+ // asserts for efficiency. We are going to make contig.length / STEP_SIZE queries
+ // at each of range: start -> start + querySize against a cache with size of X.
+ // we expect to hit the cache each time range falls within X. We expect a hit
+ // on the cache if range is within X. Which should happen at least (X - query_size * 2) / STEP_SIZE
+ // times.
+ final int minExpectedHits = (int)Math.floor((Math.min(caching.getCacheSize(), contig.getSequenceLength()) - querySize * 2.0) / STEP_SIZE);
+ caching.printEfficiency(Priority.WARN);
+ Assert.assertTrue(caching.getCacheHits() >= minExpectedHits, "Expected at least " + minExpectedHits + " cache hits but only got " + caching.getCacheHits());
+
+ }
+
+ // Tests grabbing sequences around a middle cached value.
+ @Test(dataProvider = "fastas", enabled = true && ! DEBUG)
+ public void testCachingIndexedFastaReaderTwoStage(File fasta, int cacheSize, int querySize) throws FileNotFoundException {
+ final IndexedFastaSequenceFile uncached = new IndexedFastaSequenceFile(fasta);
+ final CachingIndexedFastaSequenceFile caching = new CachingIndexedFastaSequenceFile(fasta, getCacheSize(cacheSize), true, false);
+
+ SAMSequenceRecord contig = uncached.getSequenceDictionary().getSequence(0);
+
+ int middleStart = (contig.getSequenceLength() - querySize) / 2;
+ int middleStop = middleStart + querySize;
+
+ logger.warn(String.format("Checking contig %s length %d with cache size %d and query size %d with intermediate query",
+ contig.getSequenceName(), contig.getSequenceLength(), cacheSize, querySize));
+
+ for ( int i = 0; i < contig.getSequenceLength(); i += 10 ) {
+ int start = i;
+ int stop = start + querySize;
+ if ( stop <= contig.getSequenceLength() ) {
+ ReferenceSequence grabMiddle = caching.getSubsequenceAt(contig.getSequenceName(), middleStart, middleStop);
+ ReferenceSequence cachedVal = caching.getSubsequenceAt(contig.getSequenceName(), start, stop);
+ ReferenceSequence uncachedVal = uncached.getSubsequenceAt(contig.getSequenceName(), start, stop);
+
+ Assert.assertEquals(cachedVal.getName(), uncachedVal.getName());
+ Assert.assertEquals(cachedVal.getContigIndex(), uncachedVal.getContigIndex());
+ Assert.assertEquals(cachedVal.getBases(), uncachedVal.getBases());
+ }
+ }
+ }
+
+ @DataProvider(name = "ParallelFastaTest")
+ public Object[][] createParallelFastaTest() {
+ List<Object[]> params = new ArrayList<Object[]>();
+
+ for ( File fasta : Arrays.asList(simpleFasta) ) {
+ for ( int cacheSize : CACHE_SIZES ) {
+ for ( int querySize : QUERY_SIZES ) {
+ for ( int nt : Arrays.asList(1, 2, 3, 4) ) {
+ params.add(new Object[]{fasta, cacheSize, querySize, nt});
+ }
+ }
+ }
+ }
+
+ return params.toArray(new Object[][]{});
+ }
+
+
+ @Test(dataProvider = "ParallelFastaTest", enabled = true && ! DEBUG, timeOut = 60000)
+ public void testCachingIndexedFastaReaderParallel(final File fasta, final int cacheSize, final int querySize, final int nt) throws FileNotFoundException, InterruptedException {
+ final CachingIndexedFastaSequenceFile caching = new CachingIndexedFastaSequenceFile(fasta, getCacheSize(cacheSize), true, false);
+
+ logger.warn(String.format("Parallel caching index fasta reader test cacheSize %d querySize %d nt %d", caching.getCacheSize(), querySize, nt));
+ for ( int iterations = 0; iterations < 1; iterations++ ) {
+ final ExecutorService executor = Executors.newFixedThreadPool(nt);
+ final Collection<Callable<Object>> tasks = new ArrayList<Callable<Object>>(nt);
+ for ( int i = 0; i < nt; i++ )
+ tasks.add(new Callable<Object>() {
+ @Override
+ public Object call() throws Exception {
+ testSequential(caching, fasta, querySize);
+ return null;
+ }
+ });
+ executor.invokeAll(tasks);
+ executor.shutdownNow();
+ }
+ }
+
+ // make sure some bases are lower case and some are upper case
+ @Test(enabled = true)
+ public void testMixedCasesInExample() throws FileNotFoundException, InterruptedException {
+ final IndexedFastaSequenceFile original = new IndexedFastaSequenceFile(new File(exampleFASTA));
+ final CachingIndexedFastaSequenceFile casePreserving = new CachingIndexedFastaSequenceFile(new File(exampleFASTA), true);
+ final CachingIndexedFastaSequenceFile allUpper = new CachingIndexedFastaSequenceFile(new File(exampleFASTA));
+
+ int nMixedCase = 0;
+ for ( SAMSequenceRecord contig : original.getSequenceDictionary().getSequences() ) {
+ nMixedCase += testCases(original, casePreserving, allUpper, contig.getSequenceName(), -1, -1);
+
+ final int step = 100;
+ for ( int lastPos = step; lastPos < contig.getSequenceLength(); lastPos += step ) {
+ testCases(original, casePreserving, allUpper, contig.getSequenceName(), lastPos - step, lastPos);
+ }
+ }
+
+ Assert.assertTrue(nMixedCase > 0, "No mixed cases sequences found in file. Unexpected test state");
+ }
+
+ private int testCases(final IndexedFastaSequenceFile original,
+ final IndexedFastaSequenceFile casePreserving,
+ final IndexedFastaSequenceFile allUpper,
+ final String contig, final int start, final int stop ) {
+ final String orig = fetchBaseString(original, contig, start, stop);
+ final String keptCase = fetchBaseString(casePreserving, contig, start, stop);
+ final String upperCase = fetchBaseString(allUpper, contig, start, stop).toUpperCase();
+
+ final String origToUpper = orig.toUpperCase();
+ if ( ! orig.equals(origToUpper) ) {
+ Assert.assertEquals(keptCase, orig, "Case preserving operation not equal to the original case for contig " + contig);
+ Assert.assertEquals(upperCase, origToUpper, "All upper case reader not equal to the uppercase of original case for contig " + contig);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ private String fetchBaseString(final IndexedFastaSequenceFile reader, final String contig, final int start, final int stop) {
+ if ( start == -1 )
+ return new String(reader.getSequence(contig).getBases());
+ else
+ return new String(reader.getSubsequenceAt(contig, start, stop).getBases());
+ }
+
+ @Test(enabled = true)
+ public void testIupacChanges() throws FileNotFoundException, InterruptedException {
+ final String testFasta = privateTestDir + "iupacFASTA.fasta";
+ final CachingIndexedFastaSequenceFile iupacPreserving = new CachingIndexedFastaSequenceFile(new File(testFasta), CachingIndexedFastaSequenceFile.DEFAULT_CACHE_SIZE, false, true);
+ final CachingIndexedFastaSequenceFile makeNs = new CachingIndexedFastaSequenceFile(new File(testFasta));
+
+ int preservingNs = 0;
+ int changingNs = 0;
+ for ( SAMSequenceRecord contig : iupacPreserving.getSequenceDictionary().getSequences() ) {
+ final String sPreserving = fetchBaseString(iupacPreserving, contig.getSequenceName(), 0, 15000);
+ preservingNs += StringUtils.countMatches(sPreserving, "N");
+
+ final String sChanging = fetchBaseString(makeNs, contig.getSequenceName(), 0, 15000);
+ changingNs += StringUtils.countMatches(sChanging, "N");
+ }
+
+ Assert.assertEquals(changingNs, preservingNs + 4);
+ }
+
+ @Test(enabled = true, expectedExceptions = {UserException.class})
+ public void testFailOnBadBase() throws FileNotFoundException, InterruptedException {
+ final String testFasta = privateTestDir + "problematicFASTA.fasta";
+ final CachingIndexedFastaSequenceFile fasta = new CachingIndexedFastaSequenceFile(new File(testFasta));
+
+ for ( SAMSequenceRecord contig : fasta.getSequenceDictionary().getSequences() ) {
+ fetchBaseString(fasta, contig.getSequenceName(), -1, -1);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/file/FSLockWithSharedUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/file/FSLockWithSharedUnitTest.java
new file mode 100644
index 0000000..63d98a2
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/file/FSLockWithSharedUnitTest.java
@@ -0,0 +1,60 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.file;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.annotations.Test;
+
+import java.io.File;
+
+public class FSLockWithSharedUnitTest extends BaseTest {
+
+ private static final int MAX_EXPECTED_LOCK_ACQUISITION_TIME = FSLockWithShared.DEFAULT_LOCK_ACQUISITION_TIMEOUT_IN_MILLISECONDS +
+ FSLockWithShared.THREAD_TERMINATION_TIMEOUT_IN_MILLISECONDS;
+
+ /**
+ * Test to ensure that we're never spending more than the maximum configured amount of time in lock acquisition calls.
+ */
+ @Test( timeOut = MAX_EXPECTED_LOCK_ACQUISITION_TIME + 10 * 1000 )
+ public void testLockAcquisitionTimeout() {
+ final File lockFile = createTempFile("FSLockWithSharedUnitTest", ".lock");
+ final FSLockWithShared lock = new FSLockWithShared(lockFile);
+ boolean lockAcquisitionSucceeded = false;
+
+ try {
+ lockAcquisitionSucceeded = lock.sharedLock();
+ }
+ catch ( UserException e ) {
+ logger.info("Caught UserException from lock acquisition call: lock acquisition must have timed out. Message: " + e.getMessage());
+ }
+ finally {
+ if ( lockAcquisitionSucceeded ) {
+ lock.unlock();
+ }
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/fragments/FragmentUtilsBenchmark.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/fragments/FragmentUtilsBenchmark.java
new file mode 100644
index 0000000..f388d14
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/fragments/FragmentUtilsBenchmark.java
@@ -0,0 +1,81 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.fragments;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Caliper microbenchmark of fragment pileup
+ */
+public class FragmentUtilsBenchmark extends SimpleBenchmark {
+ List<ReadBackedPileup> pileups;
+
+ @Param({"0", "4", "30", "150", "1000"})
+ int pileupSize; // set automatically by framework
+
+ @Param({"200", "400"})
+ int insertSize; // set automatically by framework
+
+ @Override protected void setUp() {
+ final int nPileupsToGenerate = 100;
+ pileups = new ArrayList<ReadBackedPileup>(nPileupsToGenerate);
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000);
+ GenomeLocParser genomeLocParser;
+ genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ GenomeLoc loc = genomeLocParser.createGenomeLoc("chr1", 50);
+ final int readLen = 100;
+
+ for ( int pileupN = 0; pileupN < nPileupsToGenerate; pileupN++ ) {
+ ReadBackedPileup rbp = ArtificialSAMUtils.createReadBackedPileup(header, loc, readLen, insertSize, pileupSize);
+ pileups.add(rbp);
+ }
+ }
+
+// public void timeOriginal(int rep) {
+// run(rep, FragmentUtils.FragmentMatchingAlgorithm.ORIGINAL);
+// }
+
+ public void timeSkipNonOverlapping(int rep) {
+ int nFrags = 0;
+ for ( int i = 0; i < rep; i++ ) {
+ for ( ReadBackedPileup rbp : pileups )
+ nFrags += FragmentUtils.create(rbp).getOverlappingPairs().size();
+ }
+ }
+
+ public static void main(String[] args) {
+ com.google.caliper.Runner.main(FragmentUtilsBenchmark.class, args);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/fragments/FragmentUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/fragments/FragmentUtilsUnitTest.java
new file mode 100644
index 0000000..f9f9ba4
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/fragments/FragmentUtilsUnitTest.java
@@ -0,0 +1,390 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.fragments;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.TextCigarCodec;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileupImpl;
+import org.broadinstitute.gatk.utils.recalibration.EventType;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMReadGroupRecord;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test routines for read-backed pileup.
+ */
+public class FragmentUtilsUnitTest extends BaseTest {
+ private static SAMFileHeader header;
+ private static GATKSAMReadGroupRecord rgForMerged;
+ private final static boolean DEBUG = false;
+
+ private class FragmentUtilsTest extends TestDataProvider {
+ List<TestState> statesForPileup = new ArrayList<TestState>();
+ List<TestState> statesForReads = new ArrayList<TestState>();
+
+ private FragmentUtilsTest(String name, int readLen, int leftStart, int rightStart,
+ boolean leftIsFirst, boolean leftIsNegative) {
+ super(FragmentUtilsTest.class, String.format("%s-leftIsFirst:%b-leftIsNegative:%b", name, leftIsFirst, leftIsNegative));
+
+ List<GATKSAMRecord> pair = ArtificialSAMUtils.createPair(header, "readpair", readLen, leftStart, rightStart, leftIsFirst, leftIsNegative);
+ GATKSAMRecord left = pair.get(0);
+ GATKSAMRecord right = pair.get(1);
+
+ for ( int pos = leftStart; pos < rightStart + readLen; pos++) {
+ boolean posCoveredByLeft = pos >= left.getAlignmentStart() && pos <= left.getAlignmentEnd();
+ boolean posCoveredByRight = pos >= right.getAlignmentStart() && pos <= right.getAlignmentEnd();
+
+ if ( posCoveredByLeft || posCoveredByRight ) {
+ List<GATKSAMRecord> reads = new ArrayList<GATKSAMRecord>();
+ List<Integer> offsets = new ArrayList<Integer>();
+
+ if ( posCoveredByLeft ) {
+ reads.add(left);
+ offsets.add(pos - left.getAlignmentStart());
+ }
+
+ if ( posCoveredByRight ) {
+ reads.add(right);
+ offsets.add(pos - right.getAlignmentStart());
+ }
+
+ boolean shouldBeFragment = posCoveredByLeft && posCoveredByRight;
+ ReadBackedPileup pileup = new ReadBackedPileupImpl(null, reads, offsets);
+ TestState testState = new TestState(shouldBeFragment ? 0 : 1, shouldBeFragment ? 1 : 0, pileup, null);
+ statesForPileup.add(testState);
+ }
+
+ TestState testState = left.getAlignmentEnd() >= right.getAlignmentStart() ? new TestState(0, 1, null, pair) : new TestState(2, 0, null, pair);
+ statesForReads.add(testState);
+ }
+ }
+ }
+
+ private class TestState {
+ int expectedSingletons, expectedPairs;
+ ReadBackedPileup pileup;
+ List<GATKSAMRecord> rawReads;
+
+ private TestState(final int expectedSingletons, final int expectedPairs, final ReadBackedPileup pileup, final List<GATKSAMRecord> rawReads) {
+ this.expectedSingletons = expectedSingletons;
+ this.expectedPairs = expectedPairs;
+ this.pileup = pileup;
+ this.rawReads = rawReads;
+ }
+ }
+
+ @DataProvider(name = "fragmentUtilsTest")
+ public Object[][] createTests() {
+ for ( boolean leftIsFirst : Arrays.asList(true, false) ) {
+ for ( boolean leftIsNegative : Arrays.asList(true, false) ) {
+ // Overlapping pair
+ // ----> [first]
+ // <--- [second]
+ new FragmentUtilsTest("overlapping-pair", 10, 1, 5, leftIsFirst, leftIsNegative);
+
+ // Non-overlapping pair
+ // ---->
+ // <----
+ new FragmentUtilsTest("nonoverlapping-pair", 10, 1, 15, leftIsFirst, leftIsNegative);
+ }
+ }
+
+ return FragmentUtilsTest.getTests(FragmentUtilsTest.class);
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "fragmentUtilsTest")
+ public void testAsPileup(FragmentUtilsTest test) {
+ for ( TestState testState : test.statesForPileup ) {
+ ReadBackedPileup rbp = testState.pileup;
+ FragmentCollection<PileupElement> fp = FragmentUtils.create(rbp);
+ Assert.assertEquals(fp.getOverlappingPairs().size(), testState.expectedPairs);
+ Assert.assertEquals(fp.getSingletonReads().size(), testState.expectedSingletons);
+ }
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "fragmentUtilsTest")
+ public void testAsListOfReadsFromPileup(FragmentUtilsTest test) {
+ for ( TestState testState : test.statesForPileup ) {
+ FragmentCollection<GATKSAMRecord> fp = FragmentUtils.create(testState.pileup.getReads());
+ Assert.assertEquals(fp.getOverlappingPairs().size(), testState.expectedPairs);
+ Assert.assertEquals(fp.getSingletonReads().size(), testState.expectedSingletons);
+ }
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "fragmentUtilsTest")
+ public void testAsListOfReads(FragmentUtilsTest test) {
+ for ( TestState testState : test.statesForReads ) {
+ FragmentCollection<GATKSAMRecord> fp = FragmentUtils.create(testState.rawReads);
+ Assert.assertEquals(fp.getOverlappingPairs().size(), testState.expectedPairs);
+ Assert.assertEquals(fp.getSingletonReads().size(), testState.expectedSingletons);
+ }
+ }
+
+ @Test(enabled = !DEBUG, expectedExceptions = IllegalArgumentException.class)
+ public void testOutOfOrder() {
+ final List<GATKSAMRecord> pair = ArtificialSAMUtils.createPair(header, "readpair", 100, 1, 50, true, true);
+ final GATKSAMRecord left = pair.get(0);
+ final GATKSAMRecord right = pair.get(1);
+ final List<GATKSAMRecord> reads = Arrays.asList(right, left); // OUT OF ORDER!
+ final List<Integer> offsets = Arrays.asList(0, 50);
+ final ReadBackedPileup pileup = new ReadBackedPileupImpl(null, reads, offsets);
+ FragmentUtils.create(pileup); // should throw exception
+ }
+
+ @BeforeTest
+ public void setup() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(1,1,1000);
+ rgForMerged = new GATKSAMReadGroupRecord("RG1");
+ }
+
+ @DataProvider(name = "MergeFragmentsTest")
+ public Object[][] createMergeFragmentsTest() throws Exception {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final String leftFlank = "CCC";
+ final String rightFlank = "AAA";
+ final String allOverlappingBases = "ACGTACGTGGAACCTTAG";
+ for ( int overlapSize = 1; overlapSize < allOverlappingBases.length(); overlapSize++ ) {
+ final String overlappingBases = allOverlappingBases.substring(0, overlapSize);
+ final byte[] overlappingBaseQuals = new byte[overlapSize];
+ for ( int i = 0; i < overlapSize; i++ ) overlappingBaseQuals[i] = (byte)(i + 30);
+ final GATKSAMRecord read1 = makeOverlappingRead(leftFlank, 20, overlappingBases, overlappingBaseQuals, "", 30, 1);
+ final GATKSAMRecord read2 = makeOverlappingRead("", 20, overlappingBases, overlappingBaseQuals, rightFlank, 30, leftFlank.length() + 1);
+ final GATKSAMRecord merged = makeOverlappingRead(leftFlank, 20, overlappingBases, overlappingBaseQuals, rightFlank, 30, 1);
+ tests.add(new Object[]{"equalQuals", read1, read2, merged});
+
+ // test that the merged read base quality is the
+ tests.add(new Object[]{"lowQualLeft", modifyBaseQualities(read1, leftFlank.length(), overlapSize), read2, merged});
+ tests.add(new Object[]{"lowQualRight", read1, modifyBaseQualities(read2, 0, overlapSize), merged});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ private GATKSAMRecord modifyBaseQualities(final GATKSAMRecord read, final int startOffset, final int length) throws Exception {
+ final GATKSAMRecord readWithLowQuals = (GATKSAMRecord)read.clone();
+ final byte[] withLowQuals = Arrays.copyOf(read.getBaseQualities(), read.getBaseQualities().length);
+ for ( int i = startOffset; i < startOffset + length; i++ )
+ withLowQuals[i] = (byte)(read.getBaseQualities()[i] + (i % 2 == 0 ? -1 : 0));
+ readWithLowQuals.setBaseQualities(withLowQuals);
+ return readWithLowQuals;
+ }
+
+ private GATKSAMRecord makeOverlappingRead(final String leftFlank, final int leftQual, final String overlapBases,
+ final byte[] overlapQuals, final String rightFlank, final int rightQual,
+ final int alignmentStart) {
+ final String bases = leftFlank + overlapBases + rightFlank;
+ final int readLength = bases.length();
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, alignmentStart, readLength);
+ final byte[] leftQuals = Utils.dupBytes((byte) leftQual, leftFlank.length());
+ final byte[] rightQuals = Utils.dupBytes((byte) rightQual, rightFlank.length());
+ final byte[] quals = Utils.concat(leftQuals, overlapQuals, rightQuals);
+ read.setCigarString(readLength + "M");
+ read.setReadBases(bases.getBytes());
+ for ( final EventType type : EventType.values() )
+ read.setBaseQualities(quals, type);
+ read.setReadGroup(rgForMerged);
+ read.setMappingQuality(60);
+ return read;
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "MergeFragmentsTest")
+ public void testMergingTwoReads(final String name, final GATKSAMRecord read1, final GATKSAMRecord read2, final GATKSAMRecord expectedMerged) {
+ final GATKSAMRecord actual = FragmentUtils.mergeOverlappingPairedFragments(read1, read2);
+
+ if ( expectedMerged == null ) {
+ Assert.assertNull(actual, "Expected reads not to merge, but got non-null result from merging");
+ } else {
+ Assert.assertTrue(actual.isStrandless(), "Merged reads should be strandless");
+ Assert.assertNotNull(actual, "Expected reads to merge, but got null result from merging");
+ // I really care about the bases, the quals, the CIGAR, and the read group tag
+ Assert.assertEquals(actual.getCigarString(), expectedMerged.getCigarString());
+ Assert.assertEquals(actual.getReadBases(), expectedMerged.getReadBases());
+ Assert.assertEquals(actual.getReadGroup(), expectedMerged.getReadGroup());
+ Assert.assertEquals(actual.getMappingQuality(), expectedMerged.getMappingQuality());
+ for ( final EventType type : EventType.values() )
+ Assert.assertEquals(actual.getBaseQualities(type), expectedMerged.getBaseQualities(type), "Failed base qualities for event type " + type);
+ }
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testHardClippingBeforeMerge() {
+ final String common = Utils.dupString("A", 10);
+ final byte[] commonQuals = Utils.dupBytes((byte)30, common.length());
+ final String adapter = "NNNN";
+
+ final GATKSAMRecord read1 = makeOverlappingRead(adapter, 30, common, commonQuals, "", 30, 10);
+ final GATKSAMRecord read2 = makeOverlappingRead("", 30, common, commonQuals, adapter, 30, 10);
+ final GATKSAMRecord expectedMerged = makeOverlappingRead("", 30, common, commonQuals, "", 30, 10);
+ read1.setCigarString("4S" + common.length() + "M");
+ read1.setProperPairFlag(true);
+ read1.setReadPairedFlag(true);
+ read1.setFirstOfPairFlag(true);
+ read1.setReadNegativeStrandFlag(true);
+ read1.setMateNegativeStrandFlag(false);
+ read1.setMateAlignmentStart(read2.getAlignmentStart());
+ read2.setCigarString(common.length() + "M4S");
+ read2.setProperPairFlag(true);
+ read2.setReadPairedFlag(true);
+ read2.setFirstOfPairFlag(false);
+ read2.setReadNegativeStrandFlag(false);
+ read2.setMateNegativeStrandFlag(true);
+ read2.setMateAlignmentStart(read1.getAlignmentStart());
+
+ final int insertSize = common.length() - 1;
+ read1.setInferredInsertSize(-insertSize);
+ read2.setInferredInsertSize(insertSize);
+
+ final GATKSAMRecord actual = FragmentUtils.mergeOverlappingPairedFragments(read1, read2);
+ Assert.assertEquals(actual.getCigarString(), expectedMerged.getCigarString());
+ Assert.assertEquals(actual.getReadBases(), expectedMerged.getReadBases());
+ Assert.assertEquals(actual.getReadGroup(), expectedMerged.getReadGroup());
+ Assert.assertEquals(actual.getMappingQuality(), expectedMerged.getMappingQuality());
+ for ( final EventType type : EventType.values() )
+ Assert.assertEquals(actual.getBaseQualities(type), expectedMerged.getBaseQualities(type), "Failed base qualities for event type " + type);
+ }
+
+ @Test(enabled = true)
+ public void testHardClippingBeforeMergeResultingInCompletelyContainedSecondRead() {
+ final String adapter = "NNNN";
+
+ final GATKSAMRecord read1 = makeOverlappingRead(adapter, 30, Utils.dupString("A", 10), Utils.dupBytes((byte)30, 10), "", 30, 10);
+ final GATKSAMRecord read2 = makeOverlappingRead("", 30, Utils.dupString("A", 7), Utils.dupBytes((byte)30, 7), adapter, 30, 10);
+ read1.setCigarString("4S10M");
+ read1.setProperPairFlag(true);
+ read1.setFirstOfPairFlag(true);
+ read1.setReadNegativeStrandFlag(true);
+ read1.setMateAlignmentStart(10);
+ read2.setCigarString("7M4S");
+ read2.setProperPairFlag(true);
+ read2.setFirstOfPairFlag(false);
+ read2.setReadNegativeStrandFlag(false);
+
+ final int insertSize = 7 - 1;
+ read1.setInferredInsertSize(insertSize);
+ read2.setInferredInsertSize(-insertSize);
+
+ final GATKSAMRecord actual = FragmentUtils.mergeOverlappingPairedFragments(read1, read2);
+ Assert.assertNull(actual);
+ }
+
+ @DataProvider(name = "MergeFragmentsOffContig")
+ public Object[][] makeMergeFragmentsOffContig() throws Exception {
+ List<Object[]> tests = new ArrayList<>();
+
+ for ( final int pre1 : Arrays.asList(0, 50)) {
+ for ( final int post1 : Arrays.asList(0, 50)) {
+ for ( final int pre2 : Arrays.asList(0, 50)) {
+ for ( final int post2 : Arrays.asList(0, 50)) {
+ tests.add(new Object[]{pre1, post1, pre2, post2});
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "MergeFragmentsOffContig")
+ public void testMergeFragmentsOffContig(final int pre1, final int post1, final int pre2, final int post2) {
+ final int contigSize = 10;
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 0, contigSize);
+
+ final GATKSAMRecord read1 = createReadOffContig(header, false, pre1, post1);
+ final GATKSAMRecord read2 = createReadOffContig(header, true, pre2, post2);
+
+ final GATKSAMRecord merged = FragmentUtils.mergeOverlappingPairedFragments(read1, read2);
+ }
+
+ private GATKSAMRecord createReadOffContig(final SAMFileHeader header, final boolean negStrand, final int pre, final int post) {
+ final int contigLen = header.getSequence(0).getSequenceLength();
+ final int readLen = pre + contigLen + post;
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read1", 0, 1, readLen);
+ read.setAlignmentStart(1);
+ read.setCigar(TextCigarCodec.getSingleton().decode(pre + "S" + contigLen + "M" + post + "S"));
+ read.setBaseQualities(Utils.dupBytes((byte) 30, readLen));
+ read.setReadBases(Utils.dupBytes((byte)'A', readLen));
+ read.setMappingQuality(60);
+ read.setMateAlignmentStart(1);
+ read.setProperPairFlag(true);
+ read.setReadPairedFlag(true);
+ read.setInferredInsertSize(30);
+ read.setReadNegativeStrandFlag(negStrand);
+ read.setMateNegativeStrandFlag(! negStrand);
+ read.setReadGroup(new GATKSAMReadGroupRecord("foo"));
+ return read;
+ }
+
+
+ private static final byte highQuality = 30;
+ private static final byte overlappingQuality = 20;
+
+ @DataProvider(name = "AdjustFragmentsTest")
+ public Object[][] createAdjustFragmentsTest() throws Exception {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final String leftFlank = "CCC";
+ final String rightFlank = "AAA";
+ final String allOverlappingBases = "ACGTACGTGGAACCTTAG";
+ for ( int overlapSize = 1; overlapSize < allOverlappingBases.length(); overlapSize++ ) {
+ final String overlappingBases = allOverlappingBases.substring(0, overlapSize);
+ final byte[] overlappingBaseQuals = new byte[overlapSize];
+ for ( int i = 0; i < overlapSize; i++ ) overlappingBaseQuals[i] = highQuality;
+ final GATKSAMRecord read1 = makeOverlappingRead(leftFlank, highQuality, overlappingBases, overlappingBaseQuals, "", highQuality, 1);
+ final GATKSAMRecord read2 = makeOverlappingRead("", highQuality, overlappingBases, overlappingBaseQuals, rightFlank, highQuality, leftFlank.length() + 1);
+ tests.add(new Object[]{read1, read2, overlapSize});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "AdjustFragmentsTest")
+ public void testAdjustingTwoReads(final GATKSAMRecord read1, final GATKSAMRecord read2, final int overlapSize) {
+ FragmentUtils.adjustQualsOfOverlappingPairedFragments(read1, read2);
+
+ for ( int i = 0; i < read1.getReadLength() - overlapSize; i++ )
+ Assert.assertEquals(read1.getBaseQualities()[i], highQuality);
+ for ( int i = read1.getReadLength() - overlapSize; i < read1.getReadLength(); i++ )
+ Assert.assertEquals(read1.getBaseQualities()[i], overlappingQuality);
+
+ for ( int i = 0; i < overlapSize; i++ )
+ Assert.assertEquals(read2.getBaseQualities()[i], overlappingQuality);
+ for ( int i = overlapSize; i < read2.getReadLength(); i++ )
+ Assert.assertEquals(read2.getBaseQualities()[i], highQuality);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/haplotype/EventMapUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/haplotype/EventMapUnitTest.java
new file mode 100644
index 0000000..6baf6ef
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/haplotype/EventMapUnitTest.java
@@ -0,0 +1,203 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.haplotype;
+
+import htsjdk.samtools.TextCigarCodec;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.UnvalidatingGenomeLoc;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.variant.GATKVariantContextUtils;
+import htsjdk.variant.variantcontext.VariantContext;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+public class EventMapUnitTest extends BaseTest {
+ private final static String CHR = "20";
+ private final static String NAME = "foo";
+
+ @DataProvider(name = "MyDataProvider")
+ public Object[][] makeMyDataProvider() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final List<String> SNP_ALLELES = Arrays.asList("A", "C");
+ final List<String> INS_ALLELES = Arrays.asList("A", "ACGTGA");
+ final List<String> DEL_ALLELES = Arrays.asList("ACGTA", "C");
+ final List<List<String>> allAlleles = Arrays.asList(SNP_ALLELES, INS_ALLELES, DEL_ALLELES);
+ for ( final int leftNotClump : Arrays.asList(-1, 3) ) {
+ for ( final int middleNotClump : Arrays.asList(-1, 10, 500) ) {
+ for ( final int rightNotClump : Arrays.asList(-1, 1000) ) {
+ for ( final int nClumped : Arrays.asList(3, 4) ) {
+ for ( final List<List<String>> alleles : Utils.makePermutations(allAlleles, nClumped, true)) {
+ final List<VariantContext> allVCS = new LinkedList<VariantContext>();
+
+ if ( leftNotClump != -1 ) allVCS.add(GATKVariantContextUtils.makeFromAlleles(NAME, CHR, leftNotClump, SNP_ALLELES));
+ if ( middleNotClump != -1 ) allVCS.add(GATKVariantContextUtils.makeFromAlleles(NAME, CHR, middleNotClump, SNP_ALLELES));
+ if ( rightNotClump != -1 ) allVCS.add(GATKVariantContextUtils.makeFromAlleles(NAME, CHR, rightNotClump, SNP_ALLELES));
+
+ int clumpStart = 50;
+ final List<VariantContext> vcs = new LinkedList<VariantContext>();
+ for ( final List<String> myAlleles : alleles ) {
+ final VariantContext vc = GATKVariantContextUtils.makeFromAlleles(NAME, CHR, clumpStart, myAlleles);
+ clumpStart = vc.getEnd() + 3;
+ vcs.add(vc);
+ }
+
+ tests.add(new Object[]{new EventMap(new LinkedList<VariantContext>(allVCS)), Collections.emptyList()});
+ allVCS.addAll(vcs);
+ tests.add(new Object[]{new EventMap(allVCS), vcs});
+ }
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ /**
+ * Example testng test using MyDataProvider
+ */
+ @Test(dataProvider = "MyDataProvider", enabled = true)
+ public void testGetNeighborhood(final EventMap eventMap, final List<VariantContext> expectedNeighbors) {
+ final VariantContext leftOfNeighors = expectedNeighbors.isEmpty() ? null : expectedNeighbors.get(0);
+
+ for ( final VariantContext vc : eventMap.getVariantContexts() ) {
+ final List<VariantContext> n = eventMap.getNeighborhood(vc, 5);
+ if ( leftOfNeighors == vc )
+ Assert.assertEquals(n, expectedNeighbors);
+ else if ( ! expectedNeighbors.contains(vc) )
+ Assert.assertEquals(n, Collections.singletonList(vc), "Should only contain the original vc but " + n);
+ }
+ }
+
+ @DataProvider(name = "BlockSubstitutionsData")
+ public Object[][] makeBlockSubstitutionsData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( int size = EventMap.MIN_NUMBER_OF_EVENTS_TO_COMBINE_INTO_BLOCK_SUBSTITUTION; size < 10; size++ ) {
+ final String ref = Utils.dupString("A", size);
+ final String alt = Utils.dupString("C", size);
+ tests.add(new Object[]{ref, alt, size + "M", GATKVariantContextUtils.makeFromAlleles(NAME, CHR, 1, Arrays.asList(ref, alt))});
+ }
+
+ tests.add(new Object[]{"AAAAAA", "GAGAGA", "6M", GATKVariantContextUtils.makeFromAlleles(NAME, CHR, 1, Arrays.asList("AAAAA", "GAGAG"))});
+ tests.add(new Object[]{"AAAAAA", "GAGAGG", "6M", GATKVariantContextUtils.makeFromAlleles(NAME, CHR, 1, Arrays.asList("AAAAAA", "GAGAGG"))});
+
+ for ( int len = 0; len < 10; len++ ) {
+ final String s = len == 0 ? "" : Utils.dupString("A", len);
+ tests.add(new Object[]{s + "AACCCCAA", s + "GAAG", len + 2 + "M4D2M", GATKVariantContextUtils.makeFromAlleles(NAME, CHR, 1 + len, Arrays.asList("AACCCCAA", "GAAG"))});
+ tests.add(new Object[]{s + "AAAA", s + "GACCCCAG", len + 2 + "M4I2M", GATKVariantContextUtils.makeFromAlleles(NAME, CHR, 1 + len, Arrays.asList("AAAA", "GACCCCAG"))});
+
+ tests.add(new Object[]{"AACCCCAA" + s, "GAAG" + s, "2M4D" + (len + 2) + "M", GATKVariantContextUtils.makeFromAlleles(NAME, CHR, 1, Arrays.asList("AACCCCAA", "GAAG"))});
+ tests.add(new Object[]{"AAAA" + s, "GACCCCAG" + s, "2M4I" + (len + 2) + "M", GATKVariantContextUtils.makeFromAlleles(NAME, CHR, 1, Arrays.asList("AAAA", "GACCCCAG"))});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ /**
+ * Example testng test using MyDataProvider
+ */
+ @Test(dataProvider = "BlockSubstitutionsData")
+ public void testBlockSubstitutionsData(final String refBases, final String haplotypeBases, final String cigar, final VariantContext expectedBlock) {
+ final Haplotype hap = new Haplotype(haplotypeBases.getBytes(), false, 0, TextCigarCodec.getSingleton().decode(cigar));
+ final GenomeLoc loc = new UnvalidatingGenomeLoc(CHR, 0, 1, refBases.length());
+ final EventMap ee = new EventMap(hap, refBases.getBytes(), loc, NAME);
+ ee.replaceClumpedEventsWithBlockSubstitutions();
+ Assert.assertEquals(ee.getNumberOfEvents(), 1);
+ final VariantContext actual = ee.getVariantContexts().iterator().next();
+ Assert.assertTrue(GATKVariantContextUtils.equalSites(actual, expectedBlock), "Failed with " + actual);
+ }
+
+ @DataProvider(name = "AdjacentSNPIndelTest")
+ public Object[][] makeAdjacentSNPIndelTest() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ tests.add(new Object[]{"TT", "GCT", "1M1I1M", Arrays.asList(Arrays.asList("T", "GC"))});
+ tests.add(new Object[]{"GCT", "TT", "1M1D1M", Arrays.asList(Arrays.asList("GC", "T"))});
+ tests.add(new Object[]{"TT", "GCCT", "1M2I1M", Arrays.asList(Arrays.asList("T", "GCC"))});
+ tests.add(new Object[]{"GCCT", "TT", "1M2D1M", Arrays.asList(Arrays.asList("GCC", "T"))});
+ tests.add(new Object[]{"AAGCCT", "AATT", "3M2D1M", Arrays.asList(Arrays.asList("GCC", "T"))});
+ tests.add(new Object[]{"AAGCCT", "GATT", "3M2D1M", Arrays.asList(Arrays.asList("A", "G"), Arrays.asList("GCC", "T"))});
+ tests.add(new Object[]{"AAAAA", "AGACA", "5M", Arrays.asList(Arrays.asList("A", "G"), Arrays.asList("A", "C"))});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ /**
+ * Example testng test using MyDataProvider
+ */
+ @Test(dataProvider = "AdjacentSNPIndelTest")
+ public void testAdjacentSNPIndelTest(final String refBases, final String haplotypeBases, final String cigar, final List<List<String>> expectedAlleles) {
+ final Haplotype hap = new Haplotype(haplotypeBases.getBytes(), false, 0, TextCigarCodec.getSingleton().decode(cigar));
+ final GenomeLoc loc = new UnvalidatingGenomeLoc(CHR, 0, 1, refBases.length());
+ final EventMap ee = new EventMap(hap, refBases.getBytes(), loc, NAME);
+ ee.replaceClumpedEventsWithBlockSubstitutions();
+ Assert.assertEquals(ee.getNumberOfEvents(), expectedAlleles.size());
+ final List<VariantContext> actuals = new ArrayList<VariantContext>(ee.getVariantContexts());
+ for ( int i = 0; i < ee.getNumberOfEvents(); i++ ) {
+ final VariantContext actual = actuals.get(i);
+ Assert.assertEquals(actual.getReference().getDisplayString(), expectedAlleles.get(i).get(0));
+ Assert.assertEquals(actual.getAlternateAllele(0).getDisplayString(), expectedAlleles.get(i).get(1));
+ }
+ }
+
+ @DataProvider(name = "MakeBlockData")
+ public Object[][] makeMakeBlockData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ tests.add(new Object[]{Arrays.asList("A", "G"), Arrays.asList("AGT", "A"), Arrays.asList("AGT", "G")});
+ tests.add(new Object[]{Arrays.asList("A", "G"), Arrays.asList("A", "AGT"), Arrays.asList("A", "GGT")});
+
+ tests.add(new Object[]{Arrays.asList("AC", "A"), Arrays.asList("A", "AGT"), Arrays.asList("AC", "AGT")});
+ tests.add(new Object[]{Arrays.asList("ACGTA", "A"), Arrays.asList("A", "AG"), Arrays.asList("ACGTA", "AG")});
+ tests.add(new Object[]{Arrays.asList("AC", "A"), Arrays.asList("A", "AGCGT"), Arrays.asList("AC", "AGCGT")});
+ tests.add(new Object[]{Arrays.asList("A", "ACGTA"), Arrays.asList("AG", "A"), Arrays.asList("AG", "ACGTA")});
+ tests.add(new Object[]{Arrays.asList("A", "AC"), Arrays.asList("AGCGT", "A"), Arrays.asList("AGCGT", "AC")});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ /**
+ * Example testng test using MyDataProvider
+ */
+ @Test(dataProvider = "MakeBlockData", enabled = true)
+ public void testGetNeighborhood(final List<String> firstAlleles, final List<String> secondAlleles, final List<String> expectedAlleles) {
+ final VariantContext vc1 = GATKVariantContextUtils.makeFromAlleles("x", "20", 10, firstAlleles);
+ final VariantContext vc2 = GATKVariantContextUtils.makeFromAlleles("x", "20", 10, secondAlleles);
+ final VariantContext expected = GATKVariantContextUtils.makeFromAlleles("x", "20", 10, expectedAlleles);
+
+ final EventMap eventMap = new EventMap(Collections.<VariantContext>emptyList());
+ final VariantContext block = eventMap.makeBlock(vc1, vc2);
+
+ Assert.assertEquals(block.getStart(), expected.getStart());
+ Assert.assertEquals(block.getAlleles(), expected.getAlleles());
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeUnitTest.java
new file mode 100644
index 0000000..b0087dc
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/haplotype/HaplotypeUnitTest.java
@@ -0,0 +1,249 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.haplotype;
+
+
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.TextCigarCodec;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.UnvalidatingGenomeLoc;
+import org.broadinstitute.gatk.utils.haplotype.Haplotype;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.variantcontext.VariantContextBuilder;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+/**
+ * Basic unit test for Haplotype Class
+ */
+public class HaplotypeUnitTest extends BaseTest {
+ @Test
+ public void testSimpleInsertionAllele() {
+ final String bases = "ACTGGTCAACTGGTCAACTGGTCAACTGGTCA";
+
+ final ArrayList<CigarElement> h1CigarList = new ArrayList<CigarElement>();
+ h1CigarList.add(new CigarElement(bases.length(), CigarOperator.M));
+ final Cigar h1Cigar = new Cigar(h1CigarList);
+ String h1bases = "AACTTCTGGTCAACTGGTCAACTGGTCAACTGGTCA";
+ basicInsertTest("A", "AACTT", 0, h1Cigar, bases, h1bases);
+ h1bases = "ACTGGTCAACTTACTGGTCAACTGGTCAACTGGTCA";
+ basicInsertTest("A", "AACTT", 7, h1Cigar, bases, h1bases);
+ h1bases = "ACTGGTCAACTGGTCAAACTTCTGGTCAACTGGTCA";
+ basicInsertTest("A", "AACTT", 16, h1Cigar, bases, h1bases);
+ }
+
+ @Test
+ public void testSimpleDeletionAllele() {
+ final String bases = "ACTGGTCAACTGGTCAACTGGTCAACTGGTCA";
+
+ final ArrayList<CigarElement> h1CigarList = new ArrayList<CigarElement>();
+ h1CigarList.add(new CigarElement(bases.length(), CigarOperator.M));
+ final Cigar h1Cigar = new Cigar(h1CigarList);
+ String h1bases = "ATCAACTGGTCAACTGGTCAACTGGTCA";
+ basicInsertTest("ACTGG", "A", 0, h1Cigar, bases, h1bases);
+ h1bases = "ACTGGTCAGTCAACTGGTCAACTGGTCA";
+ basicInsertTest("AACTG", "A", 7, h1Cigar, bases, h1bases);
+ h1bases = "ACTGGTCAACTGGTCAATCAACTGGTCA";
+ basicInsertTest("ACTGG", "A", 16, h1Cigar, bases, h1bases);
+ }
+
+ @Test
+ public void testSimpleSNPAllele() {
+ final String bases = "ACTGGTCAACTGGTCAACTGGTCAACTGGTCA";
+
+ final ArrayList<CigarElement> h1CigarList = new ArrayList<CigarElement>();
+ h1CigarList.add(new CigarElement(bases.length(), CigarOperator.M));
+ final Cigar h1Cigar = new Cigar(h1CigarList);
+ String h1bases = "AGTGGTCAACTGGTCAACTGGTCAACTGGTCA";
+ basicInsertTest("C", "G", 1, h1Cigar, bases, h1bases);
+ h1bases = "ACTGGTCTACTGGTCAACTGGTCAACTGGTCA";
+ basicInsertTest("A", "T", 7, h1Cigar, bases, h1bases);
+ h1bases = "ACTGGTCAACTGGTCAAATGGTCAACTGGTCA";
+ basicInsertTest("C", "A", 17, h1Cigar, bases, h1bases);
+ }
+
+ @Test
+ public void testComplexInsertionAllele() {
+ final String bases = "ATCG" + "CCGGCCGGCC" + "ATCGATCG" + "AGGGGGA" + "AGGC";
+
+ final ArrayList<CigarElement> h1CigarList = new ArrayList<CigarElement>();
+ h1CigarList.add(new CigarElement(4, CigarOperator.M));
+ h1CigarList.add(new CigarElement(10, CigarOperator.I));
+ h1CigarList.add(new CigarElement(8, CigarOperator.M));
+ h1CigarList.add(new CigarElement(3, CigarOperator.D));
+ h1CigarList.add(new CigarElement(7 + 4, CigarOperator.M));
+ final Cigar h1Cigar = new Cigar(h1CigarList);
+ String h1bases = "AACTTTCG" + "CCGGCCGGCC" + "ATCGATCG" + "AGGGGGA" + "AGGC";
+ basicInsertTest("A", "AACTT", 0, h1Cigar, bases, h1bases);
+ h1bases = "ATCG" + "CCGGCCGGCC" + "ATCACTTGATCG" + "AGGGGGA" + "AGGC";
+ basicInsertTest("C", "CACTT", 6, h1Cigar, bases, h1bases);
+ h1bases = "ATCG" + "CCGGCCGGCC" + "ATCGATCG" + "AGACTTGGGGA" + "AGGC";
+ basicInsertTest("G", "GACTT", 16, h1Cigar, bases, h1bases);
+ }
+
+ @Test
+ public void testComplexDeletionAllele() {
+ final String bases = "ATCG" + "CCGGCCGGCC" + "ATCGATCG" + "AGGGGGA" + "AGGC";
+
+ final ArrayList<CigarElement> h1CigarList = new ArrayList<CigarElement>();
+ h1CigarList.add(new CigarElement(4, CigarOperator.M));
+ h1CigarList.add(new CigarElement(10, CigarOperator.I));
+ h1CigarList.add(new CigarElement(8, CigarOperator.M));
+ h1CigarList.add(new CigarElement(3, CigarOperator.D));
+ h1CigarList.add(new CigarElement(7 + 4, CigarOperator.M));
+ final Cigar h1Cigar = new Cigar(h1CigarList);
+ String h1bases = "A" + "CCGGCCGGCC" + "ATCGATCG" + "AGGGGGA" + "AGGC";
+ basicInsertTest("ATCG", "A", 0, h1Cigar, bases, h1bases);
+ h1bases = "ATCG" + "CCGGCCGGCC" + "ATAAAG" + "AGGGGGA" + "AGGC";
+ basicInsertTest("CGATC", "AAA", 6, h1Cigar, bases, h1bases);
+ h1bases = "ATCG" + "CCGGCCGGCC" + "ATCGATCG" + "AGA" + "AGGC";
+ basicInsertTest("GGGGG", "G", 16, h1Cigar, bases, h1bases);
+ }
+
+ @Test
+ public void testComplexSNPAllele() {
+ final String bases = "ATCG" + "CCGGCCGGCC" + "ATCGATCG" + "AGGGGGA" + "AGGC";
+
+ final ArrayList<CigarElement> h1CigarList = new ArrayList<CigarElement>();
+ h1CigarList.add(new CigarElement(4, CigarOperator.M));
+ h1CigarList.add(new CigarElement(10, CigarOperator.I));
+ h1CigarList.add(new CigarElement(8, CigarOperator.M));
+ h1CigarList.add(new CigarElement(3, CigarOperator.D));
+ h1CigarList.add(new CigarElement(7 + 4, CigarOperator.M));
+ final Cigar h1Cigar = new Cigar(h1CigarList);
+ String h1bases = "AGCG" + "CCGGCCGGCC" + "ATCGATCG" + "AGGGGGA" + "AGGC";
+ basicInsertTest("T", "G", 1, h1Cigar, bases, h1bases);
+ h1bases = "ATCG" + "CCGGCCGGCC" + "ATCTATCG" + "AGGGGGA" + "AGGC";
+ basicInsertTest("G", "T", 7, h1Cigar, bases, h1bases);
+ h1bases = "ATCG" + "CCGGCCGGCC" + "ATCGATCG" + "AGCGGGA" + "AGGC";
+ basicInsertTest("G", "C", 17, h1Cigar, bases, h1bases);
+ }
+
+ private void basicInsertTest(String ref, String alt, int loc, Cigar cigar, String hap, String newHap) {
+ final Haplotype h = new Haplotype(hap.getBytes());
+ final Allele h1refAllele = Allele.create(ref, true);
+ final Allele h1altAllele = Allele.create(alt, false);
+ final ArrayList<Allele> alleles = new ArrayList<Allele>();
+ alleles.add(h1refAllele);
+ alleles.add(h1altAllele);
+ final VariantContext vc = new VariantContextBuilder().alleles(alleles).loc("1", loc, loc + h1refAllele.getBases().length - 1).make();
+ h.setAlignmentStartHapwrtRef(0);
+ h.setCigar(cigar);
+ final Haplotype h1 = h.insertAllele(vc.getReference(), vc.getAlternateAllele(0), loc, vc.getStart());
+ final Haplotype h1expected = new Haplotype(newHap.getBytes());
+ Assert.assertEquals(h1, h1expected);
+ }
+
+ private Haplotype makeHCForCigar(final String bases, final String cigar) {
+ final Haplotype h = new Haplotype(bases.getBytes());
+ h.setCigar(TextCigarCodec.getSingleton().decode(cigar));
+ return h;
+ }
+
+ @Test
+ public void testConsolidateCigar() throws Exception {
+ Assert.assertEquals(makeHCForCigar("AGCT", "4M").getConsolidatedPaddedCigar(0).toString(), "4M");
+ Assert.assertEquals(makeHCForCigar("AGCT", "4M").getConsolidatedPaddedCigar(1).toString(), "5M");
+ Assert.assertEquals(makeHCForCigar("AGCT", "1M1I1I1M").getConsolidatedPaddedCigar(0).toString(), "1M2I1M");
+ Assert.assertEquals(makeHCForCigar("AGCT", "1M1I1I1M").getConsolidatedPaddedCigar(1).toString(), "1M2I2M");
+ Assert.assertEquals(makeHCForCigar("AGCT", "1M1I1I1M").getConsolidatedPaddedCigar(2).toString(), "1M2I3M");
+ Assert.assertEquals(makeHCForCigar("AGCT", "1M1I1I1I").getConsolidatedPaddedCigar(0).toString(), "1M3I");
+ Assert.assertEquals(makeHCForCigar("AGCT", "1M1I1I1I").getConsolidatedPaddedCigar(1).toString(), "1M3I1M");
+ Assert.assertEquals(makeHCForCigar("AGCT", "1M1I1I1I").getConsolidatedPaddedCigar(2).toString(), "1M3I2M");
+ }
+
+ @DataProvider(name = "TrimmingData")
+ public Object[][] makeTrimmingData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ final GenomeLoc loc = new UnvalidatingGenomeLoc("20", 0, 10, 20);
+ final String fullBases = "ACGTAACCGGT";
+ for ( int trimStart = loc.getStart(); trimStart < loc.getStop(); trimStart++ ) {
+ for ( int trimStop = trimStart; trimStop <= loc.getStop(); trimStop++ ) {
+ final int start = trimStart - loc.getStart();
+ final int stop = start + (trimStop - trimStart) + 1;
+ final GenomeLoc trimmedLoc = new UnvalidatingGenomeLoc("20", 0, start + loc.getStart(), stop + loc.getStart() - 1);
+ final String expectedBases = fullBases.substring(start, stop);
+ final Haplotype full = new Haplotype(fullBases.getBytes(), loc);
+ final Haplotype trimmed = new Haplotype(expectedBases.getBytes(), trimmedLoc);
+
+ final int hapStart = 10;
+ full.setAlignmentStartHapwrtRef(hapStart);
+ full.setCigar(TextCigarCodec.getSingleton().decode(full.length() + "M"));
+
+ trimmed.setAlignmentStartHapwrtRef(hapStart + start);
+ trimmed.setCigar(TextCigarCodec.getSingleton().decode(trimmed.length() + "M"));
+
+ tests.add(new Object[]{full, trimmedLoc, trimmed});
+ }
+ }
+
+ final Haplotype full = new Haplotype("ACT".getBytes(), new UnvalidatingGenomeLoc("20", 0, 10, 14));
+ full.setAlignmentStartHapwrtRef(10);
+ full.setCigar(TextCigarCodec.getSingleton().decode("1M2D2M"));
+ tests.add(new Object[]{full, new UnvalidatingGenomeLoc("20", 0, 11, 12), null});
+ tests.add(new Object[]{full, new UnvalidatingGenomeLoc("20", 0, 10, 12), null});
+ tests.add(new Object[]{full, new UnvalidatingGenomeLoc("20", 0, 11, 13), null});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "TrimmingData")
+ public void testTrim(final Haplotype full, final GenomeLoc trimTo, final Haplotype expected) {
+ final Haplotype actual = full.trim(trimTo);
+ if ( expected != null ) {
+ Assert.assertEquals(actual.getBases(), expected.getBases());
+ Assert.assertEquals(actual.getStartPosition(), trimTo.getStart());
+ Assert.assertEquals(actual.getStopPosition(), trimTo.getStop());
+ Assert.assertEquals(actual.getCigar(), expected.getCigar());
+ Assert.assertEquals(actual.getAlignmentStartHapwrtRef(), expected.getAlignmentStartHapwrtRef());
+ } else {
+ Assert.assertNull(actual);
+ }
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testBadTrimLoc() {
+ final GenomeLoc loc = new UnvalidatingGenomeLoc("20", 0, 10, 20);
+ final Haplotype hap = new Haplotype("ACGTAACCGGT".getBytes(), loc);
+ hap.trim(new UnvalidatingGenomeLoc("20", 0, 1, 20));
+ }
+
+ @Test(expectedExceptions = IllegalStateException.class)
+ public void testBadTrimNoLoc() {
+ final Haplotype hap = new Haplotype("ACGTAACCGGT".getBytes());
+ hap.trim(new UnvalidatingGenomeLoc("20", 0, 1, 20));
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/interval/IntervalIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/interval/IntervalIntegrationTest.java
new file mode 100644
index 0000000..8d8f7d2
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/interval/IntervalIntegrationTest.java
@@ -0,0 +1,304 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.interval;
+
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Test the GATK core interval parsing mechanism.
+ */
+public class IntervalIntegrationTest extends WalkerTest {
+ @Test(enabled = true)
+ public void testAllImplicitIntervalParsing() {
+ String md5 = "7821db9e14d4f8e07029ff1959cd5a99";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+ " -R " + hg18Reference +
+ " -o %s",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testAllIntervalsImplicit",spec);
+ }
+
+// '-L all' is no longer supported
+// @Test(enabled = true)
+// public void testAllExplicitIntervalParsing() {
+// String md5 = "7821db9e14d4f8e07029ff1959cd5a99";
+// WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+// "-T CountLoci" +
+// " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+// " -R " + hg18Reference +
+// " -L all" +
+// " -o %s",
+// 1, // just one output file
+// Arrays.asList(md5));
+// executeTest("testAllIntervalsExplicit",spec);
+// }
+
+ @Test
+ public void testUnmappedReadInclusion() {
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T PrintReads" +
+ " -I " + validationDataLocation + "MV1994.bam" +
+ " -R " + validationDataLocation + "Escherichia_coli_K12_MG1655.fasta" +
+ " -L unmapped" +
+ " -U",
+ 0, // two output files
+ Collections.<String>emptyList());
+
+ // our base file
+ File baseOutputFile = createTempFile("testUnmappedReadInclusion",".bam");
+ spec.setOutputFileLocation(baseOutputFile);
+ spec.addAuxFile("95e98192e5b90cf80eaa87a4ace263da",createTempFileFromBase(baseOutputFile.getAbsolutePath()));
+ spec.addAuxFile("fadcdf88597b9609c5f2a17f4c6eb455", createTempFileFromBase(baseOutputFile.getAbsolutePath().substring(0,baseOutputFile.getAbsolutePath().indexOf(".bam"))+".bai"));
+
+ executeTest("testUnmappedReadInclusion",spec);
+ }
+
+ @Test
+ public void testMixedMappedAndUnmapped() {
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T PrintReads" +
+ " -I " + validationDataLocation + "MV1994.bam" +
+ " -R " + validationDataLocation + "Escherichia_coli_K12_MG1655.fasta" +
+ " -L Escherichia_coli_K12:4630000-4639675" +
+ " -L unmapped" +
+ " -U",
+ 0, // two output files
+ Collections.<String>emptyList());
+
+ // our base file
+ File baseOutputFile = createTempFile("testUnmappedReadInclusion",".bam");
+ spec.setOutputFileLocation(baseOutputFile);
+ spec.addAuxFile("3944b5a6bfc06277ed3afb928a20d588",createTempFileFromBase(baseOutputFile.getAbsolutePath()));
+ spec.addAuxFile("fa90ff91ac0cc689c71a3460a3530b8b", createTempFileFromBase(baseOutputFile.getAbsolutePath().substring(0,baseOutputFile.getAbsolutePath().indexOf(".bam"))+".bai"));
+
+ executeTest("testUnmappedReadInclusion",spec);
+ }
+
+
+ @Test(enabled = false)
+ public void testUnmappedReadExclusion() {
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T PrintReads" +
+ " -I " + validationDataLocation + "MV1994.bam" +
+ " -R " + validationDataLocation + "Escherichia_coli_K12_MG1655.fasta" +
+ " -XL unmapped" +
+ " -U",
+ 0, // two output files
+ Collections.<String>emptyList());
+
+ // our base file
+ File baseOutputFile = createTempFile("testUnmappedReadExclusion",".bam");
+ spec.setOutputFileLocation(baseOutputFile);
+ spec.addAuxFile("80887ba488e53dabd9596ff93070ae75",createTempFileFromBase(baseOutputFile.getAbsolutePath()));
+ spec.addAuxFile("b341d808ecc33217f37c0c0cde2a3e2f", createTempFileFromBase(baseOutputFile.getAbsolutePath().substring(0,baseOutputFile.getAbsolutePath().indexOf(".bam"))+".bai"));
+
+ executeTest("testUnmappedReadExclusion",spec);
+ }
+
+ @Test(enabled = true)
+ public void testIntervalParsingFromFile() {
+ String md5 = "48a24b70a0b376535542b996af517398";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+ " -R " + hg18Reference +
+ " -o %s" +
+ " -L " + validationDataLocation + "intervalTest.1.vcf",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testIntervalParsingFromFile", spec);
+ }
+
+ @Test(enabled = true)
+ public void testIntervalMergingFromFiles() {
+ String md5 = "9ae0ea9e3c9c6e1b9b6252c8395efdc1";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+ " -R " + hg18Reference +
+ " -o %s" +
+ " -L " + validationDataLocation + "intervalTest.1.vcf" +
+ " -L " + validationDataLocation + "intervalTest.2.vcf",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testIntervalMergingFromFiles", spec);
+ }
+
+ @Test(enabled = true)
+ public void testIntervalExclusionsFromFiles() {
+ String md5 = "26ab0db90d72e28ad0ba1e22ee510510";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+ " -R " + hg18Reference +
+ " -o %s" +
+ " -L " + validationDataLocation + "intervalTest.1.vcf" +
+ " -XL " + validationDataLocation + "intervalTest.2.vcf",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testIntervalExclusionsFromFiles", spec);
+ }
+
+ @Test(enabled = true)
+ public void testMixedIntervalMerging() {
+ String md5 = "7c5aba41f53293b712fd86d08ed5b36e";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+ " -R " + hg18Reference +
+ " -o %s" +
+ " -L " + validationDataLocation + "intervalTest.1.vcf" +
+ " -L chr1:1677524-1677528",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testMixedIntervalMerging", spec);
+ }
+
+ @Test(enabled = true)
+ public void testBed() {
+ String md5 = "cf4278314ef8e4b996e1b798d8eb92cf";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+ " -R " + hg18Reference +
+ " -o %s" +
+ " -L " + validationDataLocation + "intervalTest.bed",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testBed", spec);
+ }
+
+ @Test(enabled = true)
+ public void testComplexVCF() {
+ String md5 = "166d77ac1b46a1ec38aa35ab7e628ab5";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+ " -R " + hg18Reference +
+ " -o %s" +
+ " -L " + validationDataLocation + "intervalTest.3.vcf",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testComplexVCF", spec);
+ }
+
+ @Test(enabled = true)
+ public void testComplexVCFWithPadding() {
+ String md5 = "649ee93d50739c656e94ec88a32c7ffe";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " --interval_padding 2" +
+ " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+ " -R " + hg18Reference +
+ " -o %s" +
+ " -L " + validationDataLocation + "intervalTest.3.vcf",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testComplexVCFWithPadding", spec);
+ }
+
+ @Test(enabled = true)
+ public void testMergingWithComplexVCF() {
+ String md5 = "6d7fce9fee471194aa8b5b6e47267f03";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+ " -R " + hg18Reference +
+ " -o %s" +
+ " -L " + validationDataLocation + "intervalTest.1.vcf" +
+ " -XL " + validationDataLocation + "intervalTest.3.vcf",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testMergingWithComplexVCF", spec);
+ }
+
+ @Test(enabled = true)
+ public void testEmptyVCF() {
+ String md5 = "897316929176464ebc9ad085f31e7284";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+ " -R " + hg18Reference +
+ " -o %s" +
+ " -L " + validationDataLocation + "intervalTest.empty.vcf",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testEmptyVCFWarning", spec);
+ }
+
+ @Test(enabled = true)
+ public void testIncludeExcludeIsTheSame() {
+ String md5 = "897316929176464ebc9ad085f31e7284";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " -I " + validationDataLocation + "OV-0930.normal.chunk.bam" +
+ " -R " + hg18Reference +
+ " -o %s" +
+ " -L " + validationDataLocation + "intervalTest.1.vcf" +
+ " -XL " + validationDataLocation + "intervalTest.1.vcf",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testIncludeExcludeIsTheSame", spec);
+ }
+
+ @Test(enabled = true)
+ public void testSymbolicAlleles() {
+ String md5 = "52745056d2fd5904857bbd4984c08098";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ "-T CountLoci" +
+ " -I " + validationDataLocation + "NA12878.chrom1.SLX.SRP000032.2009_06.bam" +
+ " -R " + b36KGReference +
+ " -o %s" +
+ " -L " + privateTestDir + "symbolic_alleles_1.vcf",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testSymbolicAlleles", spec);
+ }
+
+ @Test
+ public void testIntersectionOfLexicographicallySortedIntervals() {
+ final String md5 = "18be9375e5a753f766616a51eb6131f0";
+ WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec(
+ " -T CountLoci" +
+ " -I " + privateTestDir + "NA12878.4.snippet.bam" +
+ " -R " + b37KGReference +
+ " -L " + privateTestDir + "lexicographicallySortedIntervals.bed" +
+ " -L 4" +
+ " -isr INTERSECTION" +
+ " -o %s",
+ 1, // just one output file
+ Arrays.asList(md5));
+ executeTest("testIntersectionOfLexicographicallySortedIntervals", spec);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/interval/IntervalUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/interval/IntervalUtilsUnitTest.java
new file mode 100644
index 0000000..e9846da
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/interval/IntervalUtilsUnitTest.java
@@ -0,0 +1,1110 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.interval;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.reference.ReferenceSequenceFile;
+import htsjdk.samtools.util.Interval;
+import htsjdk.samtools.util.IntervalList;
+import htsjdk.samtools.SAMFileHeader;
+import org.apache.commons.io.FileUtils;
+import htsjdk.tribble.Feature;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.commandline.IntervalBinding;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.arguments.GATKArgumentCollection;
+import org.broadinstitute.gatk.engine.datasources.reference.ReferenceDataSource;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.*;
+
+/**
+ * test out the interval utility methods
+ */
+public class IntervalUtilsUnitTest extends BaseTest {
+ // used to seed the genome loc parser with a sequence dictionary
+ private SAMFileHeader hg18Header;
+ private GenomeLocParser hg18GenomeLocParser;
+ private List<GenomeLoc> hg18ReferenceLocs;
+ private SAMFileHeader hg19Header;
+ private GenomeLocParser hg19GenomeLocParser;
+ private List<GenomeLoc> hg19ReferenceLocs;
+ private List<GenomeLoc> hg19exomeIntervals;
+
+ private List<GenomeLoc> getLocs(String... intervals) {
+ return getLocs(Arrays.asList(intervals));
+ }
+
+ private List<GenomeLoc> getLocs(List<String> intervals) {
+ if (intervals.size() == 0)
+ return hg18ReferenceLocs;
+ List<GenomeLoc> locs = new ArrayList<GenomeLoc>();
+ for (String interval: intervals)
+ locs.add(hg18GenomeLocParser.parseGenomeLoc(interval));
+ return Collections.unmodifiableList(locs);
+ }
+
+ @BeforeClass
+ public void init() {
+ File hg18Ref = new File(BaseTest.hg18Reference);
+ try {
+ ReferenceDataSource referenceDataSource = new ReferenceDataSource(hg18Ref);
+ hg18Header = new SAMFileHeader();
+ hg18Header.setSequenceDictionary(referenceDataSource.getReference().getSequenceDictionary());
+ ReferenceSequenceFile seq = new CachingIndexedFastaSequenceFile(hg18Ref);
+ hg18GenomeLocParser = new GenomeLocParser(seq);
+ hg18ReferenceLocs = Collections.unmodifiableList(GenomeLocSortedSet.createSetFromSequenceDictionary(referenceDataSource.getReference().getSequenceDictionary()).toList()) ;
+ }
+ catch(FileNotFoundException ex) {
+ throw new UserException.CouldNotReadInputFile(hg18Ref,ex);
+ }
+
+ File hg19Ref = new File(BaseTest.hg19Reference);
+ try {
+ ReferenceDataSource referenceDataSource = new ReferenceDataSource(hg19Ref);
+ hg19Header = new SAMFileHeader();
+ hg19Header.setSequenceDictionary(referenceDataSource.getReference().getSequenceDictionary());
+ ReferenceSequenceFile seq = new CachingIndexedFastaSequenceFile(hg19Ref);
+ hg19GenomeLocParser = new GenomeLocParser(seq);
+ hg19ReferenceLocs = Collections.unmodifiableList(GenomeLocSortedSet.createSetFromSequenceDictionary(referenceDataSource.getReference().getSequenceDictionary()).toList()) ;
+
+ hg19exomeIntervals = Collections.unmodifiableList(IntervalUtils.parseIntervalArguments(hg19GenomeLocParser, Arrays.asList(hg19Intervals)));
+ }
+ catch(FileNotFoundException ex) {
+ throw new UserException.CouldNotReadInputFile(hg19Ref,ex);
+ }
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // tests to ensure the quality of the interval cuts of the interval cutting functions
+ //
+ // -------------------------------------------------------------------------------------
+
+ private class IntervalSlicingTest extends TestDataProvider {
+ public int parts;
+ public double maxAllowableVariance;
+
+ private IntervalSlicingTest(final int parts, final double maxAllowableVariance) {
+ super(IntervalSlicingTest.class);
+ this.parts = parts;
+ this.maxAllowableVariance = maxAllowableVariance;
+ }
+
+ public String toString() {
+ return String.format("IntervalSlicingTest parts=%d maxVar=%.2f", parts, maxAllowableVariance);
+ }
+ }
+
+ @DataProvider(name = "intervalslicingdata")
+ public Object[][] createTrees() {
+ new IntervalSlicingTest(1, 0);
+ new IntervalSlicingTest(2, 1);
+ new IntervalSlicingTest(5, 1);
+ new IntervalSlicingTest(10, 1);
+ new IntervalSlicingTest(67, 1);
+ new IntervalSlicingTest(100, 1);
+ new IntervalSlicingTest(500, 1);
+ new IntervalSlicingTest(1000, 1);
+ return IntervalSlicingTest.getTests(IntervalSlicingTest.class);
+ }
+
+ @Test(enabled = true, dataProvider = "intervalslicingdata")
+ public void testFixedScatterIntervalsAlgorithm(IntervalSlicingTest test) {
+ List<List<GenomeLoc>> splits = IntervalUtils.splitFixedIntervals(hg19exomeIntervals, test.parts);
+
+ long totalSize = IntervalUtils.intervalSize(hg19exomeIntervals);
+ long idealSplitSize = totalSize / test.parts;
+
+ long sumOfSplitSizes = 0;
+ int counter = 0;
+ for ( final List<GenomeLoc> split : splits ) {
+ long splitSize = IntervalUtils.intervalSize(split);
+ double sigma = (splitSize - idealSplitSize) / (1.0 * idealSplitSize);
+ //logger.warn(String.format("Split %d size %d ideal %d sigma %.2f", counter, splitSize, idealSplitSize, sigma));
+ counter++;
+ sumOfSplitSizes += splitSize;
+ Assert.assertTrue(Math.abs(sigma) <= test.maxAllowableVariance, String.format("Interval %d (size %d ideal %d) has a variance %.2f outside of the tolerated range %.2f", counter, splitSize, idealSplitSize, sigma, test.maxAllowableVariance));
+ }
+
+ Assert.assertEquals(totalSize, sumOfSplitSizes, "Split intervals don't contain the exact number of bases in the origianl intervals");
+ }
+
+ // -------------------------------------------------------------------------------------
+ //
+ // splitLocusIntervals tests
+ //
+ // -------------------------------------------------------------------------------------
+
+ /** large scale tests for many intervals */
+ private class SplitLocusIntervalsTest extends TestDataProvider {
+ final List<GenomeLoc> originalIntervals;
+ final public int parts;
+
+ private SplitLocusIntervalsTest(final String name, List<GenomeLoc> originalIntervals, final int parts) {
+ super(SplitLocusIntervalsTest.class, name);
+ this.parts = parts;
+ this.originalIntervals = originalIntervals;
+ }
+
+ public String toString() {
+ return String.format("%s parts=%d", super.toString(), parts);
+ }
+ }
+
+ @DataProvider(name = "IntervalRepartitionTest")
+ public Object[][] createIntervalRepartitionTest() {
+ for ( int parts : Arrays.asList(1, 2, 3, 10, 13, 100, 151, 1000, 10000) ) {
+ //for ( int parts : Arrays.asList(10) ) {
+ new SplitLocusIntervalsTest("hg19RefLocs", hg19ReferenceLocs, parts);
+ new SplitLocusIntervalsTest("hg19ExomeLocs", hg19exomeIntervals, parts);
+ }
+
+ return SplitLocusIntervalsTest.getTests(SplitLocusIntervalsTest.class);
+ }
+
+ @Test(enabled = true, dataProvider = "IntervalRepartitionTest")
+ public void testIntervalRepartition(SplitLocusIntervalsTest test) {
+ List<List<GenomeLoc>> splitByLocus = IntervalUtils.splitLocusIntervals(test.originalIntervals, test.parts);
+ Assert.assertEquals(splitByLocus.size(), test.parts, "SplitLocusIntervals failed to generate correct number of intervals");
+ List<GenomeLoc> flat = IntervalUtils.flattenSplitIntervals(splitByLocus);
+
+ // test overall size
+ final long originalSize = IntervalUtils.intervalSize(test.originalIntervals);
+ final long flatSize = IntervalUtils.intervalSize(flat);
+ Assert.assertEquals(flatSize, originalSize, "SplitLocusIntervals locs cover an incorrect number of bases");
+
+ // test size of each split
+ final long ideal = (long)Math.floor(originalSize / (1.0 * test.parts));
+ final long maxSize = ideal + (originalSize % test.parts) * test.parts; // no more than N * rounding error in size
+ for ( final List<GenomeLoc> split : splitByLocus ) {
+ final long splitSize = IntervalUtils.intervalSize(split);
+ Assert.assertTrue(splitSize >= ideal && splitSize <= maxSize,
+ String.format("SplitLocusIntervals interval (start=%s) has size %d outside of bounds ideal=%d, max=%d",
+ split.get(0), splitSize, ideal, maxSize));
+ }
+
+ // test that every base in original is covered once by a base in split by locus intervals
+ String diff = IntervalUtils.equateIntervals(test.originalIntervals, flat);
+ Assert.assertNull(diff, diff);
+ }
+
+ /** small scale tests where the expected cuts are enumerated upfront for testing */
+ private class SplitLocusIntervalsSmallTest extends TestDataProvider {
+ final List<GenomeLoc> original;
+ final public int parts;
+ final public int expectedParts;
+ final List<GenomeLoc> expected;
+
+ private SplitLocusIntervalsSmallTest(final String name, List<GenomeLoc> originalIntervals, final int parts, List<GenomeLoc> expected) {
+ this(name, originalIntervals, parts, expected, parts);
+ }
+
+ private SplitLocusIntervalsSmallTest(final String name, List<GenomeLoc> originalIntervals, final int parts, List<GenomeLoc> expected, int expectedParts) {
+ super(SplitLocusIntervalsSmallTest.class, name);
+ this.parts = parts;
+ this.expectedParts = expectedParts;
+ this.original = originalIntervals;
+ this.expected = expected;
+ }
+
+ public String toString() {
+ return String.format("%s parts=%d", super.toString(), parts);
+ }
+ }
+
+ @DataProvider(name = "SplitLocusIntervalsSmallTest")
+ public Object[][] createSplitLocusIntervalsSmallTest() {
+ GenomeLoc bp01_10 = hg19GenomeLocParser.createGenomeLoc("1", 1, 10);
+
+ GenomeLoc bp1_5 = hg19GenomeLocParser.createGenomeLoc("1", 1, 5);
+ GenomeLoc bp6_10 = hg19GenomeLocParser.createGenomeLoc("1", 6, 10);
+ new SplitLocusIntervalsSmallTest("cut into two", Arrays.asList(bp01_10), 2, Arrays.asList(bp1_5, bp6_10));
+
+ GenomeLoc bp20_30 = hg19GenomeLocParser.createGenomeLoc("1", 20, 30);
+ new SplitLocusIntervalsSmallTest("two in two", Arrays.asList(bp01_10, bp20_30), 2, Arrays.asList(bp01_10, bp20_30));
+
+ GenomeLoc bp1_7 = hg19GenomeLocParser.createGenomeLoc("1", 1, 7);
+ GenomeLoc bp8_10 = hg19GenomeLocParser.createGenomeLoc("1", 8, 10);
+ GenomeLoc bp20_23 = hg19GenomeLocParser.createGenomeLoc("1", 20, 23);
+ GenomeLoc bp24_30 = hg19GenomeLocParser.createGenomeLoc("1", 24, 30);
+ new SplitLocusIntervalsSmallTest("two in three", Arrays.asList(bp01_10, bp20_30), 3,
+ Arrays.asList(bp1_7, bp8_10, bp20_23, bp24_30));
+
+ GenomeLoc bp1_2 = hg19GenomeLocParser.createGenomeLoc("1", 1, 2);
+ GenomeLoc bp1_1 = hg19GenomeLocParser.createGenomeLoc("1", 1, 1);
+ GenomeLoc bp2_2 = hg19GenomeLocParser.createGenomeLoc("1", 2, 2);
+ new SplitLocusIntervalsSmallTest("too many pieces", Arrays.asList(bp1_2), 5, Arrays.asList(bp1_1, bp2_2), 2);
+
+ new SplitLocusIntervalsSmallTest("emptyList", Collections.<GenomeLoc>emptyList(), 5, Collections.<GenomeLoc>emptyList(), 0);
+
+ return SplitLocusIntervalsSmallTest.getTests(SplitLocusIntervalsSmallTest.class);
+ }
+
+ @Test(enabled = true, dataProvider = "SplitLocusIntervalsSmallTest")
+ public void splitLocusIntervalsSmallTest(SplitLocusIntervalsSmallTest test) {
+ List<List<GenomeLoc>> splitByLocus = IntervalUtils.splitLocusIntervals(test.original, test.parts);
+ Assert.assertEquals(splitByLocus.size(), test.expectedParts, "SplitLocusIntervals failed to generate correct number of intervals");
+ List<GenomeLoc> flat = IntervalUtils.flattenSplitIntervals(splitByLocus);
+
+ // test sizes
+ final long originalSize = IntervalUtils.intervalSize(test.original);
+ final long splitSize = IntervalUtils.intervalSize(flat);
+ Assert.assertEquals(splitSize, originalSize, "SplitLocusIntervals locs cover an incorrect number of bases");
+
+ Assert.assertEquals(flat, test.expected, "SplitLocusIntervals locs not expected intervals");
+ }
+
+ //
+ // Misc. tests
+ //
+
+ @Test(expectedExceptions=UserException.class)
+ public void testMergeListsBySetOperatorNoOverlap() {
+ // a couple of lists we'll use for the testing
+ List<GenomeLoc> listEveryTwoFromOne = new ArrayList<GenomeLoc>();
+ List<GenomeLoc> listEveryTwoFromTwo = new ArrayList<GenomeLoc>();
+
+ // create the two lists we'll use
+ for (int x = 1; x < 101; x++) {
+ if (x % 2 == 0)
+ listEveryTwoFromTwo.add(hg18GenomeLocParser.createGenomeLoc("chr1",x,x));
+ else
+ listEveryTwoFromOne.add(hg18GenomeLocParser.createGenomeLoc("chr1",x,x));
+ }
+
+ List<GenomeLoc> ret;
+ ret = IntervalUtils.mergeListsBySetOperator(listEveryTwoFromTwo, listEveryTwoFromOne, IntervalSetRule.UNION);
+ Assert.assertEquals(ret.size(), 100);
+ ret = IntervalUtils.mergeListsBySetOperator(listEveryTwoFromTwo, listEveryTwoFromOne, null);
+ Assert.assertEquals(ret.size(), 100);
+ ret = IntervalUtils.mergeListsBySetOperator(listEveryTwoFromTwo, listEveryTwoFromOne, IntervalSetRule.INTERSECTION);
+ Assert.assertEquals(ret.size(), 0);
+ }
+
+ @Test
+ public void testMergeListsBySetOperatorAllOverlap() {
+ // a couple of lists we'll use for the testing
+ List<GenomeLoc> allSites = new ArrayList<GenomeLoc>();
+ List<GenomeLoc> listEveryTwoFromTwo = new ArrayList<GenomeLoc>();
+
+ // create the two lists we'll use
+ for (int x = 1; x < 101; x++) {
+ if (x % 2 == 0)
+ listEveryTwoFromTwo.add(hg18GenomeLocParser.createGenomeLoc("chr1",x,x));
+ allSites.add(hg18GenomeLocParser.createGenomeLoc("chr1",x,x));
+ }
+
+ List<GenomeLoc> ret;
+ ret = IntervalUtils.mergeListsBySetOperator(listEveryTwoFromTwo, allSites, IntervalSetRule.UNION);
+ Assert.assertEquals(ret.size(), 150);
+ ret = IntervalUtils.mergeListsBySetOperator(listEveryTwoFromTwo, allSites, null);
+ Assert.assertEquals(ret.size(), 150);
+ ret = IntervalUtils.mergeListsBySetOperator(listEveryTwoFromTwo, allSites, IntervalSetRule.INTERSECTION);
+ Assert.assertEquals(ret.size(), 50);
+ }
+
+ @Test
+ public void testMergeListsBySetOperator() {
+ // a couple of lists we'll use for the testing
+ List<GenomeLoc> allSites = new ArrayList<GenomeLoc>();
+ List<GenomeLoc> listEveryTwoFromTwo = new ArrayList<GenomeLoc>();
+
+ // create the two lists we'll use
+ for (int x = 1; x < 101; x++) {
+ if (x % 5 == 0) {
+ listEveryTwoFromTwo.add(hg18GenomeLocParser.createGenomeLoc("chr1",x,x));
+ allSites.add(hg18GenomeLocParser.createGenomeLoc("chr1",x,x));
+ }
+ }
+
+ List<GenomeLoc> ret;
+ ret = IntervalUtils.mergeListsBySetOperator(listEveryTwoFromTwo, allSites, IntervalSetRule.UNION);
+ Assert.assertEquals(ret.size(), 40);
+ ret = IntervalUtils.mergeListsBySetOperator(listEveryTwoFromTwo, allSites, null);
+ Assert.assertEquals(ret.size(), 40);
+ ret = IntervalUtils.mergeListsBySetOperator(listEveryTwoFromTwo, allSites, IntervalSetRule.INTERSECTION);
+ Assert.assertEquals(ret.size(), 20);
+ }
+
+ @Test
+ public void testOverlappingIntervalsFromSameSourceWithIntersection() {
+ // a couple of lists we'll use for the testing
+ List<GenomeLoc> source1 = new ArrayList<GenomeLoc>();
+ List<GenomeLoc> source2 = new ArrayList<GenomeLoc>();
+
+ source1.add(hg18GenomeLocParser.createGenomeLoc("chr1", 10, 20));
+ source1.add(hg18GenomeLocParser.createGenomeLoc("chr1", 15, 25));
+
+ source2.add(hg18GenomeLocParser.createGenomeLoc("chr1", 16, 18));
+ source2.add(hg18GenomeLocParser.createGenomeLoc("chr1", 22, 24));
+
+ List<GenomeLoc> ret = IntervalUtils.mergeListsBySetOperator(source1, source2, IntervalSetRule.INTERSECTION);
+ Assert.assertEquals(ret.size(), 2);
+ }
+
+ @Test
+ public void testGetContigLengths() {
+ Map<String, Integer> lengths = IntervalUtils.getContigSizes(new File(BaseTest.hg18Reference));
+ Assert.assertEquals((long)lengths.get("chr1"), 247249719);
+ Assert.assertEquals((long)lengths.get("chr2"), 242951149);
+ Assert.assertEquals((long)lengths.get("chr3"), 199501827);
+ Assert.assertEquals((long)lengths.get("chr20"), 62435964);
+ Assert.assertEquals((long)lengths.get("chrX"), 154913754);
+ }
+
+ @Test
+ public void testParseIntervalArguments() {
+ Assert.assertEquals(getLocs().size(), 45);
+ Assert.assertEquals(getLocs("chr1", "chr2", "chr3").size(), 3);
+ Assert.assertEquals(getLocs("chr1:1-2", "chr1:4-5", "chr2:1-1", "chr3:2-2").size(), 4);
+ }
+
+ @Test
+ public void testIsIntervalFile() {
+ Assert.assertTrue(IntervalUtils.isIntervalFile(BaseTest.privateTestDir + "empty_intervals.list"));
+ Assert.assertTrue(IntervalUtils.isIntervalFile(BaseTest.privateTestDir + "empty_intervals.list", true));
+
+ List<String> extensions = Arrays.asList("bed", "interval_list", "intervals", "list", "picard");
+ for (String extension: extensions) {
+ Assert.assertTrue(IntervalUtils.isIntervalFile("test_intervals." + extension, false), "Tested interval file extension: " + extension);
+ }
+ }
+
+ @Test(expectedExceptions = UserException.CouldNotReadInputFile.class)
+ public void testMissingIntervalFile() {
+ IntervalUtils.isIntervalFile(BaseTest.privateTestDir + "no_such_intervals.list");
+ }
+
+ @Test
+ public void testFixedScatterIntervalsBasic() {
+ GenomeLoc chr1 = hg18GenomeLocParser.parseGenomeLoc("chr1");
+ GenomeLoc chr2 = hg18GenomeLocParser.parseGenomeLoc("chr2");
+ GenomeLoc chr3 = hg18GenomeLocParser.parseGenomeLoc("chr3");
+
+ List<File> files = testFiles("basic.", 3, ".intervals");
+
+ List<GenomeLoc> locs = getLocs("chr1", "chr2", "chr3");
+ List<List<GenomeLoc>> splits = IntervalUtils.splitFixedIntervals(locs, files.size());
+ IntervalUtils.scatterFixedIntervals(hg18Header, splits, files);
+
+ List<GenomeLoc> locs1 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(0).toString()));
+ List<GenomeLoc> locs2 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(1).toString()));
+ List<GenomeLoc> locs3 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(2).toString()));
+
+ Assert.assertEquals(locs1.size(), 1);
+ Assert.assertEquals(locs2.size(), 1);
+ Assert.assertEquals(locs3.size(), 1);
+
+ Assert.assertEquals(locs1.get(0), chr1);
+ Assert.assertEquals(locs2.get(0), chr2);
+ Assert.assertEquals(locs3.get(0), chr3);
+ }
+
+ @Test
+ public void testScatterFixedIntervalsLessFiles() {
+ GenomeLoc chr1 = hg18GenomeLocParser.parseGenomeLoc("chr1");
+ GenomeLoc chr2 = hg18GenomeLocParser.parseGenomeLoc("chr2");
+ GenomeLoc chr3 = hg18GenomeLocParser.parseGenomeLoc("chr3");
+ GenomeLoc chr4 = hg18GenomeLocParser.parseGenomeLoc("chr4");
+
+ List<File> files = testFiles("less.", 3, ".intervals");
+
+ List<GenomeLoc> locs = getLocs("chr1", "chr2", "chr3", "chr4");
+ List<List<GenomeLoc>> splits = IntervalUtils.splitFixedIntervals(locs, files.size());
+ IntervalUtils.scatterFixedIntervals(hg18Header, splits, files);
+
+ List<GenomeLoc> locs1 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(0).toString()));
+ List<GenomeLoc> locs2 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(1).toString()));
+ List<GenomeLoc> locs3 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(2).toString()));
+
+ Assert.assertEquals(locs1.size(), 1);
+ Assert.assertEquals(locs2.size(), 1);
+ Assert.assertEquals(locs3.size(), 2);
+
+ Assert.assertEquals(locs1.get(0), chr1);
+ Assert.assertEquals(locs2.get(0), chr2);
+ Assert.assertEquals(locs3.get(0), chr3);
+ Assert.assertEquals(locs3.get(1), chr4);
+ }
+
+ @Test(expectedExceptions=UserException.BadArgumentValue.class)
+ public void testSplitFixedIntervalsMoreFiles() {
+ List<File> files = testFiles("more.", 3, ".intervals");
+ List<GenomeLoc> locs = getLocs("chr1", "chr2");
+ IntervalUtils.splitFixedIntervals(locs, files.size());
+ }
+
+ @Test(expectedExceptions=UserException.BadArgumentValue.class)
+ public void testScatterFixedIntervalsMoreFiles() {
+ List<File> files = testFiles("more.", 3, ".intervals");
+ List<GenomeLoc> locs = getLocs("chr1", "chr2");
+ List<List<GenomeLoc>> splits = IntervalUtils.splitFixedIntervals(locs, locs.size()); // locs.size() instead of files.size()
+ IntervalUtils.scatterFixedIntervals(hg18Header, splits, files);
+ }
+ @Test
+ public void testScatterFixedIntervalsStart() {
+ List<String> intervals = Arrays.asList("chr1:1-2", "chr1:4-5", "chr2:1-1", "chr3:2-2");
+ GenomeLoc chr1a = hg18GenomeLocParser.parseGenomeLoc("chr1:1-2");
+ GenomeLoc chr1b = hg18GenomeLocParser.parseGenomeLoc("chr1:4-5");
+ GenomeLoc chr2 = hg18GenomeLocParser.parseGenomeLoc("chr2:1-1");
+ GenomeLoc chr3 = hg18GenomeLocParser.parseGenomeLoc("chr3:2-2");
+
+ List<File> files = testFiles("split.", 3, ".intervals");
+
+ List<GenomeLoc> locs = getLocs(intervals);
+ List<List<GenomeLoc>> splits = IntervalUtils.splitFixedIntervals(locs, files.size());
+ IntervalUtils.scatterFixedIntervals(hg18Header, splits, files);
+
+ List<GenomeLoc> locs1 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(0).toString()));
+ List<GenomeLoc> locs2 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(1).toString()));
+ List<GenomeLoc> locs3 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(2).toString()));
+
+ Assert.assertEquals(locs1.size(), 1);
+ Assert.assertEquals(locs2.size(), 1);
+ Assert.assertEquals(locs3.size(), 2);
+
+ Assert.assertEquals(locs1.get(0), chr1a);
+ Assert.assertEquals(locs2.get(0), chr1b);
+ Assert.assertEquals(locs3.get(0), chr2);
+ Assert.assertEquals(locs3.get(1), chr3);
+ }
+
+ @Test
+ public void testScatterFixedIntervalsMiddle() {
+ List<String> intervals = Arrays.asList("chr1:1-1", "chr2:1-2", "chr2:4-5", "chr3:2-2");
+ GenomeLoc chr1 = hg18GenomeLocParser.parseGenomeLoc("chr1:1-1");
+ GenomeLoc chr2a = hg18GenomeLocParser.parseGenomeLoc("chr2:1-2");
+ GenomeLoc chr2b = hg18GenomeLocParser.parseGenomeLoc("chr2:4-5");
+ GenomeLoc chr3 = hg18GenomeLocParser.parseGenomeLoc("chr3:2-2");
+
+ List<File> files = testFiles("split.", 3, ".intervals");
+
+ List<GenomeLoc> locs = getLocs(intervals);
+ List<List<GenomeLoc>> splits = IntervalUtils.splitFixedIntervals(locs, files.size());
+ IntervalUtils.scatterFixedIntervals(hg18Header, splits, files);
+
+ List<GenomeLoc> locs1 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(0).toString()));
+ List<GenomeLoc> locs2 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(1).toString()));
+ List<GenomeLoc> locs3 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(2).toString()));
+
+ Assert.assertEquals(locs1.size(), 1);
+ Assert.assertEquals(locs2.size(), 1);
+ Assert.assertEquals(locs3.size(), 2);
+
+ Assert.assertEquals(locs1.get(0), chr1);
+ Assert.assertEquals(locs2.get(0), chr2a);
+ Assert.assertEquals(locs3.get(0), chr2b);
+ Assert.assertEquals(locs3.get(1), chr3);
+ }
+
+ @Test
+ public void testScatterFixedIntervalsEnd() {
+ List<String> intervals = Arrays.asList("chr1:1-1", "chr2:2-2", "chr3:1-2", "chr3:4-5");
+ GenomeLoc chr1 = hg18GenomeLocParser.parseGenomeLoc("chr1:1-1");
+ GenomeLoc chr2 = hg18GenomeLocParser.parseGenomeLoc("chr2:2-2");
+ GenomeLoc chr3a = hg18GenomeLocParser.parseGenomeLoc("chr3:1-2");
+ GenomeLoc chr3b = hg18GenomeLocParser.parseGenomeLoc("chr3:4-5");
+
+ List<File> files = testFiles("split.", 3, ".intervals");
+
+ List<GenomeLoc> locs = getLocs(intervals);
+ List<List<GenomeLoc>> splits = IntervalUtils.splitFixedIntervals(locs, files.size());
+ IntervalUtils.scatterFixedIntervals(hg18Header, splits, files);
+
+ List<GenomeLoc> locs1 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(0).toString()));
+ List<GenomeLoc> locs2 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(1).toString()));
+ List<GenomeLoc> locs3 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(2).toString()));
+
+ Assert.assertEquals(locs1.size(), 2);
+ Assert.assertEquals(locs2.size(), 1);
+ Assert.assertEquals(locs3.size(), 1);
+
+ Assert.assertEquals(locs1.get(0), chr1);
+ Assert.assertEquals(locs1.get(1), chr2);
+ Assert.assertEquals(locs2.get(0), chr3a);
+ Assert.assertEquals(locs3.get(0), chr3b);
+ }
+
+ @Test
+ public void testScatterFixedIntervalsFile() {
+ List<File> files = testFiles("sg.", 20, ".intervals");
+ List<GenomeLoc> locs = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(BaseTest.GATKDataLocation + "whole_exome_agilent_designed_120.targets.hg18.chr20.interval_list"));
+ List<List<GenomeLoc>> splits = IntervalUtils.splitFixedIntervals(locs, files.size());
+
+ int[] counts = {
+ 125, 138, 287, 291, 312, 105, 155, 324,
+ 295, 298, 141, 121, 285, 302, 282, 88,
+ 116, 274, 282, 248
+// 5169, 5573, 10017, 10567, 10551,
+// 5087, 4908, 10120, 10435, 10399,
+// 5391, 4735, 10621, 10352, 10654,
+// 5227, 5256, 10151, 9649, 9825
+ };
+
+ //String splitCounts = "";
+ for (int i = 0; i < splits.size(); i++) {
+ int splitCount = splits.get(i).size();
+ Assert.assertEquals(splitCount, counts[i], "Num intervals in split " + i);
+ }
+ //System.out.println(splitCounts.substring(2));
+
+ IntervalUtils.scatterFixedIntervals(hg18Header, splits, files);
+
+ int locIndex = 0;
+ for (int i = 0; i < files.size(); i++) {
+ String file = files.get(i).toString();
+ List<GenomeLoc> parsedLocs = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(file));
+ Assert.assertEquals(parsedLocs.size(), counts[i], "Intervals in " + file);
+ for (GenomeLoc parsedLoc: parsedLocs)
+ Assert.assertEquals(parsedLoc, locs.get(locIndex), String.format("Genome loc %d from file %d", locIndex++, i));
+ }
+ Assert.assertEquals(locIndex, locs.size(), "Total number of GenomeLocs");
+ }
+
+ @Test
+ public void testScatterFixedIntervalsMax() {
+ List<File> files = testFiles("sg.", 85, ".intervals");
+ List<List<GenomeLoc>> splits = IntervalUtils.splitFixedIntervals(hg19ReferenceLocs, files.size());
+ IntervalUtils.scatterFixedIntervals(hg19Header, splits, files);
+
+ for (int i = 0; i < files.size(); i++) {
+ String file = files.get(i).toString();
+ List<GenomeLoc> parsedLocs = IntervalUtils.parseIntervalArguments(hg19GenomeLocParser, Arrays.asList(file));
+ Assert.assertEquals(parsedLocs.size(), 1, "parsedLocs[" + i + "].size()");
+ Assert.assertEquals(parsedLocs.get(0), hg19ReferenceLocs.get(i), "parsedLocs[" + i + "].get()");
+ }
+ }
+
+ @Test
+ public void testScatterContigIntervalsOrder() {
+ List<String> intervals = Arrays.asList("chr2:1-1", "chr1:1-1", "chr3:2-2");
+ GenomeLoc chr1 = hg18GenomeLocParser.parseGenomeLoc("chr1:1-1");
+ GenomeLoc chr2 = hg18GenomeLocParser.parseGenomeLoc("chr2:1-1");
+ GenomeLoc chr3 = hg18GenomeLocParser.parseGenomeLoc("chr3:2-2");
+
+ List<File> files = testFiles("split.", 3, ".intervals");
+
+ IntervalUtils.scatterContigIntervals(hg18Header, getLocs(intervals), files);
+
+ List<GenomeLoc> locs1 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(0).toString()));
+ List<GenomeLoc> locs2 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(1).toString()));
+ List<GenomeLoc> locs3 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(2).toString()));
+
+ Assert.assertEquals(locs1.size(), 1);
+ Assert.assertEquals(locs2.size(), 1);
+ Assert.assertEquals(locs3.size(), 1);
+
+ Assert.assertEquals(locs1.get(0), chr2);
+ Assert.assertEquals(locs2.get(0), chr1);
+ Assert.assertEquals(locs3.get(0), chr3);
+ }
+
+ @Test
+ public void testScatterContigIntervalsBasic() {
+ GenomeLoc chr1 = hg18GenomeLocParser.parseGenomeLoc("chr1");
+ GenomeLoc chr2 = hg18GenomeLocParser.parseGenomeLoc("chr2");
+ GenomeLoc chr3 = hg18GenomeLocParser.parseGenomeLoc("chr3");
+
+ List<File> files = testFiles("contig_basic.", 3, ".intervals");
+
+ IntervalUtils.scatterContigIntervals(hg18Header, getLocs("chr1", "chr2", "chr3"), files);
+
+ List<GenomeLoc> locs1 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(0).toString()));
+ List<GenomeLoc> locs2 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(1).toString()));
+ List<GenomeLoc> locs3 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(2).toString()));
+
+ Assert.assertEquals(locs1.size(), 1);
+ Assert.assertEquals(locs2.size(), 1);
+ Assert.assertEquals(locs3.size(), 1);
+
+ Assert.assertEquals(locs1.get(0), chr1);
+ Assert.assertEquals(locs2.get(0), chr2);
+ Assert.assertEquals(locs3.get(0), chr3);
+ }
+
+ @Test
+ public void testScatterContigIntervalsLessFiles() {
+ GenomeLoc chr1 = hg18GenomeLocParser.parseGenomeLoc("chr1");
+ GenomeLoc chr2 = hg18GenomeLocParser.parseGenomeLoc("chr2");
+ GenomeLoc chr3 = hg18GenomeLocParser.parseGenomeLoc("chr3");
+ GenomeLoc chr4 = hg18GenomeLocParser.parseGenomeLoc("chr4");
+
+ List<File> files = testFiles("contig_less.", 3, ".intervals");
+
+ IntervalUtils.scatterContigIntervals(hg18Header, getLocs("chr1", "chr2", "chr3", "chr4"), files);
+
+ List<GenomeLoc> locs1 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(0).toString()));
+ List<GenomeLoc> locs2 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(1).toString()));
+ List<GenomeLoc> locs3 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(2).toString()));
+
+ Assert.assertEquals(locs1.size(), 2);
+ Assert.assertEquals(locs2.size(), 1);
+ Assert.assertEquals(locs3.size(), 1);
+
+ Assert.assertEquals(locs1.get(0), chr1);
+ Assert.assertEquals(locs1.get(1), chr2);
+ Assert.assertEquals(locs2.get(0), chr3);
+ Assert.assertEquals(locs3.get(0), chr4);
+ }
+
+ @Test(expectedExceptions=UserException.BadInput.class)
+ public void testScatterContigIntervalsMoreFiles() {
+ List<File> files = testFiles("contig_more.", 3, ".intervals");
+ IntervalUtils.scatterContigIntervals(hg18Header, getLocs("chr1", "chr2"), files);
+ }
+
+ @Test
+ public void testScatterContigIntervalsStart() {
+ List<String> intervals = Arrays.asList("chr1:1-2", "chr1:4-5", "chr2:1-1", "chr3:2-2");
+ GenomeLoc chr1a = hg18GenomeLocParser.parseGenomeLoc("chr1:1-2");
+ GenomeLoc chr1b = hg18GenomeLocParser.parseGenomeLoc("chr1:4-5");
+ GenomeLoc chr2 = hg18GenomeLocParser.parseGenomeLoc("chr2:1-1");
+ GenomeLoc chr3 = hg18GenomeLocParser.parseGenomeLoc("chr3:2-2");
+
+ List<File> files = testFiles("contig_split_start.", 3, ".intervals");
+
+ IntervalUtils.scatterContigIntervals(hg18Header, getLocs(intervals), files);
+
+ List<GenomeLoc> locs1 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(0).toString()));
+ List<GenomeLoc> locs2 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(1).toString()));
+ List<GenomeLoc> locs3 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(2).toString()));
+
+ Assert.assertEquals(locs1.size(), 2);
+ Assert.assertEquals(locs2.size(), 1);
+ Assert.assertEquals(locs3.size(), 1);
+
+ Assert.assertEquals(locs1.get(0), chr1a);
+ Assert.assertEquals(locs1.get(1), chr1b);
+ Assert.assertEquals(locs2.get(0), chr2);
+ Assert.assertEquals(locs3.get(0), chr3);
+ }
+
+ @Test
+ public void testScatterContigIntervalsMiddle() {
+ List<String> intervals = Arrays.asList("chr1:1-1", "chr2:1-2", "chr2:4-5", "chr3:2-2");
+ GenomeLoc chr1 = hg18GenomeLocParser.parseGenomeLoc("chr1:1-1");
+ GenomeLoc chr2a = hg18GenomeLocParser.parseGenomeLoc("chr2:1-2");
+ GenomeLoc chr2b = hg18GenomeLocParser.parseGenomeLoc("chr2:4-5");
+ GenomeLoc chr3 = hg18GenomeLocParser.parseGenomeLoc("chr3:2-2");
+
+ List<File> files = testFiles("contig_split_middle.", 3, ".intervals");
+
+ IntervalUtils.scatterContigIntervals(hg18Header, getLocs(intervals), files);
+
+ List<GenomeLoc> locs1 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(0).toString()));
+ List<GenomeLoc> locs2 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(1).toString()));
+ List<GenomeLoc> locs3 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(2).toString()));
+
+ Assert.assertEquals(locs1.size(), 1);
+ Assert.assertEquals(locs2.size(), 2);
+ Assert.assertEquals(locs3.size(), 1);
+
+ Assert.assertEquals(locs1.get(0), chr1);
+ Assert.assertEquals(locs2.get(0), chr2a);
+ Assert.assertEquals(locs2.get(1), chr2b);
+ Assert.assertEquals(locs3.get(0), chr3);
+ }
+
+ @Test
+ public void testScatterContigIntervalsEnd() {
+ List<String> intervals = Arrays.asList("chr1:1-1", "chr2:2-2", "chr3:1-2", "chr3:4-5");
+ GenomeLoc chr1 = hg18GenomeLocParser.parseGenomeLoc("chr1:1-1");
+ GenomeLoc chr2 = hg18GenomeLocParser.parseGenomeLoc("chr2:2-2");
+ GenomeLoc chr3a = hg18GenomeLocParser.parseGenomeLoc("chr3:1-2");
+ GenomeLoc chr3b = hg18GenomeLocParser.parseGenomeLoc("chr3:4-5");
+
+ List<File> files = testFiles("contig_split_end.", 3 ,".intervals");
+
+ IntervalUtils.scatterContigIntervals(hg18Header, getLocs(intervals), files);
+
+ List<GenomeLoc> locs1 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(0).toString()));
+ List<GenomeLoc> locs2 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(1).toString()));
+ List<GenomeLoc> locs3 = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Arrays.asList(files.get(2).toString()));
+
+ Assert.assertEquals(locs1.size(), 1);
+ Assert.assertEquals(locs2.size(), 1);
+ Assert.assertEquals(locs3.size(), 2);
+
+ Assert.assertEquals(locs1.get(0), chr1);
+ Assert.assertEquals(locs2.get(0), chr2);
+ Assert.assertEquals(locs3.get(0), chr3a);
+ Assert.assertEquals(locs3.get(1), chr3b);
+ }
+
+ @Test
+ public void testScatterContigIntervalsMax() {
+ List<File> files = testFiles("sg.", 85, ".intervals");
+ IntervalUtils.scatterContigIntervals(hg19Header, hg19ReferenceLocs, files);
+
+ for (int i = 0; i < files.size(); i++) {
+ String file = files.get(i).toString();
+ List<GenomeLoc> parsedLocs = IntervalUtils.parseIntervalArguments(hg19GenomeLocParser, Arrays.asList(file));
+ Assert.assertEquals(parsedLocs.size(), 1, "parsedLocs[" + i + "].size()");
+ Assert.assertEquals(parsedLocs.get(0), hg19ReferenceLocs.get(i), "parsedLocs[" + i + "].get()");
+ }
+ }
+
+ private List<File> testFiles(String prefix, int count, String suffix) {
+ ArrayList<File> files = new ArrayList<File>();
+ for (int i = 1; i <= count; i++) {
+ files.add(createTempFile(prefix + i, suffix));
+ }
+ return files;
+ }
+
+ @DataProvider(name="unmergedIntervals")
+ public Object[][] getUnmergedIntervals() {
+ return new Object[][] {
+ new Object[] {"small_unmerged_picard_intervals.list"},
+ new Object[] {"small_unmerged_gatk_intervals.list"}
+ };
+ }
+
+ @Test(dataProvider="unmergedIntervals")
+ public void testUnmergedIntervals(String unmergedIntervals) {
+ List<GenomeLoc> locs = IntervalUtils.parseIntervalArguments(hg18GenomeLocParser, Collections.singletonList(privateTestDir + unmergedIntervals));
+ Assert.assertEquals(locs.size(), 2);
+
+ List<GenomeLoc> merged;
+
+ merged = IntervalUtils.mergeIntervalLocations(locs, IntervalMergingRule.ALL);
+ Assert.assertEquals(merged.size(), 1);
+
+ // Test that null means the same as ALL
+ merged = IntervalUtils.mergeIntervalLocations(locs, null);
+ Assert.assertEquals(merged.size(), 1);
+ }
+
+ /*
+ Split into tests that can be written to files and tested by writeFlankingIntervals,
+ and lists that cannot but are still handled by getFlankingIntervals.
+ */
+ private static abstract class FlankingIntervalsTestData extends TestDataProvider {
+ final public File referenceFile;
+ final public GenomeLocParser parser;
+ final int basePairs;
+ final List<GenomeLoc> original;
+ final List<GenomeLoc> expected;
+
+ protected FlankingIntervalsTestData(Class<?> clazz, String name, File referenceFile, GenomeLocParser parser,
+ int basePairs, List<String> original, List<String> expected) {
+ super(clazz, name);
+ this.referenceFile = referenceFile;
+ this.parser = parser;
+ this.basePairs = basePairs;
+ this.original = parse(parser, original);
+ this.expected = parse(parser, expected);
+ }
+
+ private static List<GenomeLoc> parse(GenomeLocParser parser, List<String> locs) {
+ List<GenomeLoc> parsed = new ArrayList<GenomeLoc>();
+ for (String loc: locs)
+ parsed.add("unmapped".equals(loc) ? GenomeLoc.UNMAPPED : parser.parseGenomeLoc(loc));
+ return parsed;
+ }
+ }
+
+ private static class FlankingIntervalsFile extends FlankingIntervalsTestData {
+ public FlankingIntervalsFile(String name, File referenceFile, GenomeLocParser parser,
+ int basePairs, List<String> original, List<String> expected) {
+ super(FlankingIntervalsFile.class, name, referenceFile, parser, basePairs, original, expected);
+ }
+ }
+
+ private static class FlankingIntervalsList extends FlankingIntervalsTestData {
+ public FlankingIntervalsList(String name, File referenceFile, GenomeLocParser parser,
+ int basePairs, List<String> original, List<String> expected) {
+ super(FlankingIntervalsList.class, name, referenceFile, parser, basePairs, original, expected);
+ }
+ }
+
+ /* Intervals where the original and the flanks can be written to files. */
+ @DataProvider(name = "flankingIntervalsFiles")
+ public Object[][] getFlankingIntervalsFiles() {
+ File hg19ReferenceFile = new File(BaseTest.hg19Reference);
+ int hg19Length1 = hg19GenomeLocParser.getContigInfo("1").getSequenceLength();
+
+ new FlankingIntervalsFile("atStartBase1", hg19ReferenceFile, hg19GenomeLocParser, 1,
+ Arrays.asList("1:1"),
+ Arrays.asList("1:2"));
+
+ new FlankingIntervalsFile("atStartBase50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:1"),
+ Arrays.asList("1:2-51"));
+
+ new FlankingIntervalsFile("atStartRange50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:1-10"),
+ Arrays.asList("1:11-60"));
+
+ new FlankingIntervalsFile("atEndBase1", hg19ReferenceFile, hg19GenomeLocParser, 1,
+ Arrays.asList("1:" + hg19Length1),
+ Arrays.asList("1:" + (hg19Length1 - 1)));
+
+ new FlankingIntervalsFile("atEndBase50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:" + hg19Length1),
+ Arrays.asList(String.format("1:%d-%d", hg19Length1 - 50, hg19Length1 - 1)));
+
+ new FlankingIntervalsFile("atEndRange50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList(String.format("1:%d-%d", hg19Length1 - 10, hg19Length1)),
+ Arrays.asList(String.format("1:%d-%d", hg19Length1 - 60, hg19Length1 - 11)));
+
+ new FlankingIntervalsFile("nearStartBase1", hg19ReferenceFile, hg19GenomeLocParser, 1,
+ Arrays.asList("1:2"),
+ Arrays.asList("1:1", "1:3"));
+
+ new FlankingIntervalsFile("nearStartRange50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:21-30"),
+ Arrays.asList("1:1-20", "1:31-80"));
+
+ new FlankingIntervalsFile("nearEndBase1", hg19ReferenceFile, hg19GenomeLocParser, 1,
+ Arrays.asList("1:" + (hg19Length1 - 1)),
+ Arrays.asList("1:" + (hg19Length1 - 2), "1:" + hg19Length1));
+
+ new FlankingIntervalsFile("nearEndRange50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList(String.format("1:%d-%d", hg19Length1 - 30, hg19Length1 - 21)),
+ Arrays.asList(
+ String.format("1:%d-%d", hg19Length1 - 80, hg19Length1 - 31),
+ String.format("1:%d-%d", hg19Length1 - 20, hg19Length1)));
+
+ new FlankingIntervalsFile("beyondStartBase1", hg19ReferenceFile, hg19GenomeLocParser, 1,
+ Arrays.asList("1:3"),
+ Arrays.asList("1:2", "1:4"));
+
+ new FlankingIntervalsFile("beyondStartRange50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:101-200"),
+ Arrays.asList("1:51-100", "1:201-250"));
+
+ new FlankingIntervalsFile("beyondEndBase1", hg19ReferenceFile, hg19GenomeLocParser, 1,
+ Arrays.asList("1:" + (hg19Length1 - 3)),
+ Arrays.asList("1:" + (hg19Length1 - 4), "1:" + (hg19Length1 - 2)));
+
+ new FlankingIntervalsFile("beyondEndRange50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList(String.format("1:%d-%d", hg19Length1 - 200, hg19Length1 - 101)),
+ Arrays.asList(
+ String.format("1:%d-%d", hg19Length1 - 250, hg19Length1 - 201),
+ String.format("1:%d-%d", hg19Length1 - 100, hg19Length1 - 51)));
+
+ new FlankingIntervalsFile("betweenFar50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:101-200", "1:401-500"),
+ Arrays.asList("1:51-100", "1:201-250", "1:351-400", "1:501-550"));
+
+ new FlankingIntervalsFile("betweenSpan50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:101-200", "1:301-400"),
+ Arrays.asList("1:51-100", "1:201-300", "1:401-450"));
+
+ new FlankingIntervalsFile("betweenOverlap50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:101-200", "1:271-400"),
+ Arrays.asList("1:51-100", "1:201-270", "1:401-450"));
+
+ new FlankingIntervalsFile("betweenShort50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:101-200", "1:221-400"),
+ Arrays.asList("1:51-100", "1:201-220", "1:401-450"));
+
+ new FlankingIntervalsFile("betweenNone50", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:101-200", "1:121-400"),
+ Arrays.asList("1:51-100", "1:401-450"));
+
+ new FlankingIntervalsFile("twoContigs", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:101-200", "2:301-400"),
+ Arrays.asList("1:51-100", "1:201-250", "2:251-300", "2:401-450"));
+
+ // Explicit testing a problematic agilent target pair
+ new FlankingIntervalsFile("badAgilent", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("2:74756257-74756411", "2:74756487-74756628"),
+ // wrong! ("2:74756206-74756256", "2:74756412-74756462", "2:74756436-74756486", "2:74756629-74756679")
+ Arrays.asList("2:74756207-74756256", "2:74756412-74756486", "2:74756629-74756678"));
+
+ return TestDataProvider.getTests(FlankingIntervalsFile.class);
+ }
+
+ /* Intervals where either the original and/or the flanks cannot be written to a file. */
+ @DataProvider(name = "flankingIntervalsLists")
+ public Object[][] getFlankingIntervalsLists() {
+ File hg19ReferenceFile = new File(BaseTest.hg19Reference);
+ List<String> empty = Collections.emptyList();
+
+ new FlankingIntervalsList("empty", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ empty,
+ empty);
+
+ new FlankingIntervalsList("unmapped", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("unmapped"),
+ empty);
+
+ new FlankingIntervalsList("fullContig", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1"),
+ empty);
+
+ new FlankingIntervalsList("fullContigs", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1", "2", "3"),
+ empty);
+
+ new FlankingIntervalsList("betweenWithUnmapped", hg19ReferenceFile, hg19GenomeLocParser, 50,
+ Arrays.asList("1:101-200", "1:301-400", "unmapped"),
+ Arrays.asList("1:51-100", "1:201-300", "1:401-450"));
+
+ return TestDataProvider.getTests(FlankingIntervalsList.class);
+ }
+
+ @Test(dataProvider = "flankingIntervalsFiles")
+ public void testWriteFlankingIntervals(FlankingIntervalsTestData data) throws Exception {
+ File originalFile = createTempFile("original.", ".intervals");
+ File flankingFile = createTempFile("flanking.", ".intervals");
+ try {
+ List<String> lines = new ArrayList<String>();
+ for (GenomeLoc loc: data.original)
+ lines.add(loc.toString());
+ FileUtils.writeLines(originalFile, lines);
+
+ IntervalUtils.writeFlankingIntervals(data.referenceFile, originalFile, flankingFile, data.basePairs);
+
+ List<GenomeLoc> actual = IntervalUtils.intervalFileToList(data.parser, flankingFile.getAbsolutePath());
+
+ String description = String.format("%n name: %s%n original: %s%n actual: %s%n expected: %s%n",
+ data.toString(), data.original, actual, data.expected);
+ Assert.assertEquals(actual, data.expected, description);
+ } finally {
+ FileUtils.deleteQuietly(originalFile);
+ FileUtils.deleteQuietly(flankingFile);
+ }
+ }
+
+ @Test(dataProvider = "flankingIntervalsLists", expectedExceptions = UserException.class)
+ public void testWritingBadFlankingIntervals(FlankingIntervalsTestData data) throws Exception {
+ File originalFile = createTempFile("original.", ".intervals");
+ File flankingFile = createTempFile("flanking.", ".intervals");
+ try {
+ List<String> lines = new ArrayList<String>();
+ for (GenomeLoc loc: data.original)
+ lines.add(loc.toString());
+ FileUtils.writeLines(originalFile, lines);
+
+ // Should throw a user exception on bad input if either the original
+ // intervals are empty or if the flanking intervals are empty
+ IntervalUtils.writeFlankingIntervals(data.referenceFile, originalFile, flankingFile, data.basePairs);
+ } finally {
+ FileUtils.deleteQuietly(originalFile);
+ FileUtils.deleteQuietly(flankingFile);
+ }
+ }
+
+ @Test(dataProvider = "flankingIntervalsLists")
+ public void testGetFlankingIntervals(FlankingIntervalsTestData data) {
+ List<GenomeLoc> actual = IntervalUtils.getFlankingIntervals(data.parser, data.original, data.basePairs);
+ String description = String.format("%n name: %s%n original: %s%n actual: %s%n expected: %s%n",
+ data.toString(), data.original, actual, data.expected);
+ Assert.assertEquals(actual, data.expected, description);
+ }
+
+ @Test(expectedExceptions=UserException.BadArgumentValue.class)
+ public void testExceptionUponLegacyIntervalSyntax() throws Exception {
+ GenomeAnalysisEngine toolkit = new GenomeAnalysisEngine();
+ toolkit.setGenomeLocParser(new GenomeLocParser(new CachingIndexedFastaSequenceFile(new File(BaseTest.hg19Reference))));
+
+ // Attempting to use the legacy -L "interval1;interval2" syntax should produce an exception:
+ IntervalBinding<Feature> binding = new IntervalBinding<Feature>("1;2");
+ binding.getIntervals(toolkit);
+ }
+
+ @DataProvider(name="invalidIntervalTestData")
+ public Object[][] invalidIntervalDataProvider() throws Exception {
+ GATKArgumentCollection argCollection = new GATKArgumentCollection();
+ File fastaFile = new File(publicTestDir + "exampleFASTA.fasta");
+ GenomeLocParser genomeLocParser = new GenomeLocParser(new IndexedFastaSequenceFile(fastaFile));
+
+ return new Object[][] {
+ new Object[] {argCollection, genomeLocParser, "chr1", 10000000, 20000000},
+ new Object[] {argCollection, genomeLocParser, "chr2", 1, 2},
+ new Object[] {argCollection, genomeLocParser, "chr1", -1, 50}
+ };
+ }
+
+ @Test(dataProvider="invalidIntervalTestData")
+ public void testInvalidPicardIntervalHandling(GATKArgumentCollection argCollection, GenomeLocParser genomeLocParser,
+ String contig, int intervalStart, int intervalEnd ) throws Exception {
+
+ SAMFileHeader picardFileHeader = new SAMFileHeader();
+ picardFileHeader.addSequence(genomeLocParser.getContigInfo("chr1"));
+ IntervalList picardIntervals = new IntervalList(picardFileHeader);
+ picardIntervals.add(new Interval(contig, intervalStart, intervalEnd, true, "dummyname"));
+
+ File picardIntervalFile = createTempFile("testInvalidPicardIntervalHandling", ".intervals");
+ picardIntervals.write(picardIntervalFile);
+
+ List<IntervalBinding<Feature>> intervalArgs = new ArrayList<IntervalBinding<Feature>>(1);
+ intervalArgs.add(new IntervalBinding<Feature>(picardIntervalFile.getAbsolutePath()));
+
+ IntervalUtils.loadIntervals(intervalArgs, argCollection.intervalArguments.intervalSetRule, argCollection.intervalArguments.intervalMerging, argCollection.intervalArguments.intervalPadding, genomeLocParser);
+ }
+
+ @Test(expectedExceptions=UserException.class, dataProvider="invalidIntervalTestData")
+ public void testInvalidGATKFileIntervalHandling(GATKArgumentCollection argCollection, GenomeLocParser genomeLocParser,
+ String contig, int intervalStart, int intervalEnd ) throws Exception {
+
+ File gatkIntervalFile = createTempFile("testInvalidGATKFileIntervalHandling", ".intervals",
+ String.format("%s:%d-%d", contig, intervalStart, intervalEnd));
+
+ List<IntervalBinding<Feature>> intervalArgs = new ArrayList<IntervalBinding<Feature>>(1);
+ intervalArgs.add(new IntervalBinding<Feature>(gatkIntervalFile.getAbsolutePath()));
+
+ IntervalUtils.loadIntervals(intervalArgs, argCollection.intervalArguments.intervalSetRule, argCollection.intervalArguments.intervalMerging, argCollection.intervalArguments.intervalPadding, genomeLocParser);
+ }
+
+ private File createTempFile( String tempFilePrefix, String tempFileExtension, String... lines ) throws Exception {
+ File tempFile = BaseTest.createTempFile(tempFilePrefix, tempFileExtension);
+ FileUtils.writeLines(tempFile, Arrays.asList(lines));
+ return tempFile;
+ }
+
+ @DataProvider(name = "sortAndMergeIntervals")
+ public Object[][] getSortAndMergeIntervals() {
+ return new Object[][] {
+ new Object[] { IntervalMergingRule.OVERLAPPING_ONLY, getLocs("chr1:1", "chr1:3", "chr1:2"), getLocs("chr1:1", "chr1:2", "chr1:3") },
+ new Object[] { IntervalMergingRule.ALL, getLocs("chr1:1", "chr1:3", "chr1:2"), getLocs("chr1:1-3") },
+ new Object[] { IntervalMergingRule.OVERLAPPING_ONLY, getLocs("chr1:1", "chr1:3", "chr2:2"), getLocs("chr1:1", "chr1:3", "chr2:2") },
+ new Object[] { IntervalMergingRule.ALL, getLocs("chr1:1", "chr1:3", "chr2:2"), getLocs("chr1:1", "chr1:3", "chr2:2") },
+ new Object[] { IntervalMergingRule.OVERLAPPING_ONLY, getLocs("chr1:1", "chr1"), getLocs("chr1") },
+ new Object[] { IntervalMergingRule.ALL, getLocs("chr1:1", "chr1"), getLocs("chr1") }
+ };
+ }
+
+ @Test(dataProvider = "sortAndMergeIntervals")
+ public void testSortAndMergeIntervals(IntervalMergingRule merge, List<GenomeLoc> unsorted, List<GenomeLoc> expected) {
+ List<GenomeLoc> sorted = IntervalUtils.sortAndMergeIntervals(hg18GenomeLocParser, unsorted, merge).toList();
+ Assert.assertEquals(sorted, expected);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/io/IOUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/io/IOUtilsUnitTest.java
new file mode 100644
index 0000000..13a2e8a
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/io/IOUtilsUnitTest.java
@@ -0,0 +1,326 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.io;
+
+import org.apache.commons.io.FileUtils;
+import org.broadinstitute.gatk.utils.BaseTest;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class IOUtilsUnitTest extends BaseTest {
+ @Test
+ public void testGoodTempDir() {
+ IOUtils.checkTempDir(new File("/tmp/queue"));
+ }
+
+ @Test(expectedExceptions=UserException.BadTmpDir.class)
+ public void testBadTempDir() {
+ IOUtils.checkTempDir(new File("/tmp"));
+ }
+
+ @Test
+ public void testAbsoluteSubDir() {
+ File subDir = IOUtils.absolute(new File("."), new File("/path/to/file"));
+ Assert.assertEquals(subDir, new File("/path/to/file"));
+
+ subDir = IOUtils.absolute(new File("/different/path"), new File("/path/to/file"));
+ Assert.assertEquals(subDir, new File("/path/to/file"));
+
+ subDir = IOUtils.absolute(new File("/different/path"), new File("."));
+ Assert.assertEquals(subDir, new File("/different/path"));
+ }
+
+ @Test
+ public void testRelativeSubDir() throws IOException {
+ File subDir = IOUtils.absolute(new File("."), new File("path/to/file"));
+ Assert.assertEquals(subDir.getCanonicalFile(), new File("path/to/file").getCanonicalFile());
+
+ subDir = IOUtils.absolute(new File("/different/path"), new File("path/to/file"));
+ Assert.assertEquals(subDir, new File("/different/path/path/to/file"));
+ }
+
+ @Test
+ public void testDottedSubDir() throws IOException {
+ File subDir = IOUtils.absolute(new File("."), new File("path/../to/file"));
+ Assert.assertEquals(subDir.getCanonicalFile(), new File("path/../to/./file").getCanonicalFile());
+
+ subDir = IOUtils.absolute(new File("."), new File("/path/../to/file"));
+ Assert.assertEquals(subDir, new File("/path/../to/file"));
+
+ subDir = IOUtils.absolute(new File("/different/../path"), new File("path/to/file"));
+ Assert.assertEquals(subDir, new File("/different/../path/path/to/file"));
+
+ subDir = IOUtils.absolute(new File("/different/./path"), new File("/path/../to/file"));
+ Assert.assertEquals(subDir, new File("/path/../to/file"));
+ }
+
+ @Test
+ public void testTempDir() {
+ File tempDir = IOUtils.tempDir("Q-Unit-Test", "", new File("queueTempDirToDelete"));
+ Assert.assertTrue(tempDir.exists());
+ Assert.assertFalse(tempDir.isFile());
+ Assert.assertTrue(tempDir.isDirectory());
+ boolean deleted = IOUtils.tryDelete(tempDir);
+ Assert.assertTrue(deleted);
+ Assert.assertFalse(tempDir.exists());
+ }
+
+ @Test
+ public void testDirLevel() {
+ File dir = IOUtils.dirLevel(new File("/path/to/directory"), 1);
+ Assert.assertEquals(dir, new File("/path"));
+
+ dir = IOUtils.dirLevel(new File("/path/to/directory"), 2);
+ Assert.assertEquals(dir, new File("/path/to"));
+
+ dir = IOUtils.dirLevel(new File("/path/to/directory"), 3);
+ Assert.assertEquals(dir, new File("/path/to/directory"));
+
+ dir = IOUtils.dirLevel(new File("/path/to/directory"), 4);
+ Assert.assertEquals(dir, new File("/path/to/directory"));
+ }
+
+ @Test
+ public void testAbsolute() {
+ File dir = IOUtils.absolute(new File("/path/./to/./directory/."));
+ Assert.assertEquals(dir, new File("/path/to/directory"));
+
+ dir = IOUtils.absolute(new File("/"));
+ Assert.assertEquals(dir, new File("/"));
+
+ dir = IOUtils.absolute(new File("/."));
+ Assert.assertEquals(dir, new File("/"));
+
+ dir = IOUtils.absolute(new File("/././."));
+ Assert.assertEquals(dir, new File("/"));
+
+ dir = IOUtils.absolute(new File("/./directory/."));
+ Assert.assertEquals(dir, new File("/directory"));
+
+ dir = IOUtils.absolute(new File("/./directory/./"));
+ Assert.assertEquals(dir, new File("/directory"));
+
+ dir = IOUtils.absolute(new File("/./directory./"));
+ Assert.assertEquals(dir, new File("/directory."));
+
+ dir = IOUtils.absolute(new File("/./.directory/"));
+ Assert.assertEquals(dir, new File("/.directory"));
+ }
+
+ @Test
+ public void testTail() throws IOException {
+ List<String> lines = Arrays.asList(
+ "chr18_random 4262 3154410390 50 51",
+ "chr19_random 301858 3154414752 50 51",
+ "chr21_random 1679693 3154722662 50 51",
+ "chr22_random 257318 3156435963 50 51",
+ "chrX_random 1719168 3156698441 50 51");
+ List<String> tail = IOUtils.tail(new File(BaseTest.hg18Reference + ".fai"), 5);
+ Assert.assertEquals(tail.size(), 5);
+ for (int i = 0; i < 5; i++)
+ Assert.assertEquals(tail.get(i), lines.get(i));
+ }
+
+ @Test
+ public void testWriteSystemFile() throws IOException {
+ File temp = createTempFile("temp.", ".properties");
+ try {
+ IOUtils.writeResource(new Resource("testProperties.properties", null), temp);
+ } finally {
+ FileUtils.deleteQuietly(temp);
+ }
+ }
+
+ @Test
+ public void testWriteSystemTempFile() throws IOException {
+ File temp = IOUtils.writeTempResource(new Resource("testProperties.properties", null));
+ try {
+ Assert.assertTrue(temp.getName().startsWith("testProperties"), "File does not start with 'testProperties.': " + temp);
+ Assert.assertTrue(temp.getName().endsWith(".properties"), "File does not end with '.properties': " + temp);
+ } finally {
+ FileUtils.deleteQuietly(temp);
+ }
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testMissingSystemFile() throws IOException {
+ File temp = createTempFile("temp.", ".properties");
+ try {
+ IOUtils.writeResource(new Resource("MissingStingText.properties", null), temp);
+ } finally {
+ FileUtils.deleteQuietly(temp);
+ }
+ }
+
+ @Test
+ public void testWriteRelativeFile() throws IOException {
+ File temp = createTempFile("temp.", ".properties");
+ try {
+ IOUtils.writeResource(new Resource("/testProperties.properties", IOUtils.class), temp);
+ } finally {
+ FileUtils.deleteQuietly(temp);
+ }
+ }
+
+ @Test
+ public void testWriteRelativeTempFile() throws IOException {
+ File temp = IOUtils.writeTempResource(new Resource("/testProperties.properties", IOUtils.class));
+ try {
+ Assert.assertTrue(temp.getName().startsWith("testProperties"), "File does not start with 'testProperties.': " + temp);
+ Assert.assertTrue(temp.getName().endsWith(".properties"), "File does not end with '.properties': " + temp);
+ } finally {
+ FileUtils.deleteQuietly(temp);
+ }
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testMissingRelativeFile() throws IOException {
+ File temp = createTempFile("temp.", ".properties");
+ try {
+ // Looking for /org/broadinstitute/gatk/utils/file/GATKText.properties
+ IOUtils.writeResource(new Resource("GATKText.properties", IOUtils.class), temp);
+ } finally {
+ FileUtils.deleteQuietly(temp);
+ }
+ }
+
+ @Test
+ public void testResourceProperties() {
+ Resource resource = new Resource("foo", Resource.class);
+ Assert.assertEquals(resource.getPath(), "foo");
+ Assert.assertEquals(resource.getRelativeClass(), Resource.class);
+ }
+
+ @Test
+ public void testIsSpecialFile() {
+ Assert.assertTrue(IOUtils.isSpecialFile(new File("/dev")));
+ Assert.assertTrue(IOUtils.isSpecialFile(new File("/dev/null")));
+ Assert.assertTrue(IOUtils.isSpecialFile(new File("/dev/full")));
+ Assert.assertTrue(IOUtils.isSpecialFile(new File("/dev/stdout")));
+ Assert.assertTrue(IOUtils.isSpecialFile(new File("/dev/stderr")));
+ Assert.assertFalse(IOUtils.isSpecialFile(null));
+ Assert.assertFalse(IOUtils.isSpecialFile(new File("/home/user/my.file")));
+ Assert.assertFalse(IOUtils.isSpecialFile(new File("/devfake/null")));
+ }
+
+ @DataProvider( name = "ByteArrayIOTestData")
+ public Object[][] byteArrayIOTestDataProvider() {
+ return new Object[][] {
+ // file size, read buffer size
+ { 0, 4096 },
+ { 1, 4096 },
+ { 2000, 4096 },
+ { 4095, 4096 },
+ { 4096, 4096 },
+ { 4097, 4096 },
+ { 6000, 4096 },
+ { 8191, 4096 },
+ { 8192, 4096 },
+ { 8193, 4096 },
+ { 10000, 4096 }
+ };
+ }
+
+ @Test( dataProvider = "ByteArrayIOTestData" )
+ public void testWriteThenReadFileIntoByteArray ( int fileSize, int readBufferSize ) throws Exception {
+ File tempFile = createTempFile(String.format("testWriteThenReadFileIntoByteArray_%d_%d", fileSize, readBufferSize), "tmp");
+
+ byte[] dataWritten = getDeterministicRandomData(fileSize);
+ IOUtils.writeByteArrayToFile(dataWritten, tempFile);
+ byte[] dataRead = IOUtils.readFileIntoByteArray(tempFile, readBufferSize);
+
+ Assert.assertEquals(dataRead.length, dataWritten.length);
+ Assert.assertTrue(Arrays.equals(dataRead, dataWritten));
+ }
+
+ @Test( dataProvider = "ByteArrayIOTestData" )
+ public void testWriteThenReadStreamIntoByteArray ( int fileSize, int readBufferSize ) throws Exception {
+ File tempFile = createTempFile(String.format("testWriteThenReadStreamIntoByteArray_%d_%d", fileSize, readBufferSize), "tmp");
+
+ byte[] dataWritten = getDeterministicRandomData(fileSize);
+ IOUtils.writeByteArrayToStream(dataWritten, new FileOutputStream(tempFile));
+ byte[] dataRead = IOUtils.readStreamIntoByteArray(new FileInputStream(tempFile), readBufferSize);
+
+ Assert.assertEquals(dataRead.length, dataWritten.length);
+ Assert.assertTrue(Arrays.equals(dataRead, dataWritten));
+ }
+
+ @Test( expectedExceptions = UserException.CouldNotReadInputFile.class )
+ public void testReadNonExistentFileIntoByteArray() {
+ File nonExistentFile = new File("djfhsdkjghdfk");
+ Assert.assertFalse(nonExistentFile.exists());
+
+ IOUtils.readFileIntoByteArray(nonExistentFile);
+ }
+
+ @Test( expectedExceptions = ReviewedGATKException.class )
+ public void testReadNullStreamIntoByteArray() {
+ IOUtils.readStreamIntoByteArray(null);
+ }
+
+ @Test( expectedExceptions = ReviewedGATKException.class )
+ public void testReadStreamIntoByteArrayInvalidBufferSize() throws Exception {
+ IOUtils.readStreamIntoByteArray(new FileInputStream(createTempFile("testReadStreamIntoByteArrayInvalidBufferSize", "tmp")),
+ -1);
+ }
+
+ @Test( expectedExceptions = UserException.CouldNotCreateOutputFile.class )
+ public void testWriteByteArrayToUncreatableFile() {
+ IOUtils.writeByteArrayToFile(new byte[]{0}, new File("/dev/foo/bar"));
+ }
+
+ @Test( expectedExceptions = ReviewedGATKException.class )
+ public void testWriteNullByteArrayToFile() {
+ IOUtils.writeByteArrayToFile(null, createTempFile("testWriteNullByteArrayToFile", "tmp"));
+ }
+
+ @Test( expectedExceptions = ReviewedGATKException.class )
+ public void testWriteByteArrayToNullStream() {
+ IOUtils.writeByteArrayToStream(new byte[]{0}, null);
+ }
+
+ private byte[] getDeterministicRandomData ( int size ) {
+ GenomeAnalysisEngine.resetRandomGenerator();
+ Random rand = GenomeAnalysisEngine.getRandomGenerator();
+
+ byte[] randomData = new byte[size];
+ rand.nextBytes(randomData);
+
+ return randomData;
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/clibrary/LibCUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/clibrary/LibCUnitTest.java
new file mode 100644
index 0000000..f695d89
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/clibrary/LibCUnitTest.java
@@ -0,0 +1,70 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.clibrary;
+
+import com.sun.jna.NativeLong;
+import com.sun.jna.ptr.NativeLongByReference;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class LibCUnitTest extends BaseTest {
+
+ @Test
+ public void testEnvironment() {
+ String testProperty = "test_property";
+ String testValue = "value";
+ Assert.assertEquals(LibC.getenv(testProperty), null);
+ Assert.assertEquals(LibC.setenv(testProperty, testValue, 1), 0);
+ Assert.assertEquals(LibC.getenv(testProperty), testValue);
+ Assert.assertEquals(LibC.unsetenv(testProperty), 0);
+ Assert.assertEquals(LibC.getenv(testProperty), null);
+ }
+
+ @Test
+ public void testDifftime() throws Exception {
+ // Pointer to hold the times
+ NativeLongByReference ref = new NativeLongByReference();
+
+ // time() returns -1 on error.
+ NativeLong err = new NativeLong(-1L);
+
+ LibC.time(ref);
+ NativeLong time0 = ref.getValue();
+ Assert.assertNotSame(time0, err, "Time 0 returned an error (-1).");
+
+ Thread.sleep(5000L);
+
+ LibC.time(ref);
+ NativeLong time1 = ref.getValue();
+ Assert.assertNotSame(time1, err, "Time 1 returned an error (-1).");
+
+ Assert.assertNotSame(time1, time0, "Time 1 returned same time as Time 0.");
+
+ double diff = LibC.difftime(time1, time0);
+ Assert.assertTrue(diff >= 5, "Time difference was not greater than 5 seconds: " + diff);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaSessionQueueTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaSessionQueueTest.java
new file mode 100644
index 0000000..e683f4b
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/JnaSessionQueueTest.java
@@ -0,0 +1,165 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.drmaa.v1_0;
+
+import org.apache.commons.io.FileUtils;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.ggf.drmaa.*;
+import org.testng.Assert;
+import org.testng.SkipException;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.*;
+
+public class JnaSessionQueueTest extends BaseTest {
+ private String implementation = null;
+ private static final SessionFactory factory = new JnaSessionFactory();
+
+ @Test
+ public void testDrmaa() throws Exception {
+ Session session = factory.getSession();
+ Version version = session.getVersion();
+ System.out.println(String.format("DRMAA version: %d.%d", version.getMajor(), version.getMinor()));
+ System.out.println(String.format("DRMAA contact(s): %s", session.getContact()));
+ System.out.println(String.format("DRM system(s): %s", session.getDrmSystem()));
+ System.out.println(String.format("DRMAA implementation(s): %s", session.getDrmaaImplementation()));
+ this.implementation = session.getDrmaaImplementation();
+ }
+
+ @Test(dependsOnMethods = { "testDrmaa" })
+ public void testSubmitEcho() throws Exception {
+ if ( ! queueTestRunModeIsSet ) {
+ throw new SkipException("Skipping testSubmitEcho because we are in queue test dry run mode");
+ }
+
+ if (implementation.contains("LSF")) {
+ System.err.println(" ***********************************************************");
+ System.err.println(" *************************************************************");
+ System.err.println(" **** ****");
+ System.err.println(" **** Skipping JnaSessionQueueTest.testSubmitEcho() ****");
+ System.err.println(" **** Are you using the dotkit .combined_LSF_SGE? ****");
+ System.err.println(" **** ****");
+ System.err.println(" *************************************************************");
+ System.err.println(" ***********************************************************");
+ throw new SkipException("Skipping testSubmitEcho because correct DRMAA implementation not found");
+ }
+
+ File outFile = tryCreateNetworkTempFile("JnaSessionQueueTest.out");
+ Session session = factory.getSession();
+ session.init(null);
+ try {
+ JobTemplate template = session.createJobTemplate();
+ template.setRemoteCommand("sh");
+ template.setOutputPath(":" + outFile.getAbsolutePath());
+ template.setJoinFiles(true);
+ template.setArgs(Arrays.asList("-c", "echo \"Hello world.\""));
+
+ String jobId = session.runJob(template);
+ System.out.println(String.format("Job id %s", jobId));
+ session.deleteJobTemplate(template);
+
+ System.out.println("Waiting for job to run: " + jobId);
+ int remotePs = Session.QUEUED_ACTIVE;
+
+ List<Integer> runningStatuses = Arrays.asList(Session.QUEUED_ACTIVE, Session.RUNNING);
+
+ while (runningStatuses.contains(remotePs)) {
+ Thread.sleep(30 * 1000L);
+ remotePs = session.getJobProgramStatus(jobId);
+ }
+
+ Assert.assertEquals(remotePs, Session.DONE, "Job status is not DONE.");
+
+ JobInfo jobInfo = session.wait(jobId, Session.TIMEOUT_NO_WAIT);
+
+ Assert.assertTrue(jobInfo.hasExited(), String.format("Job did not exit cleanly: %s", jobId));
+ Assert.assertEquals(jobInfo.getExitStatus(), 0, String.format("Exit status for jobId %s is non-zero", jobId));
+ if (jobInfo.hasSignaled())
+ Assert.fail(String.format("JobId %s exited with signal %s and core dump flag %s", jobId, jobInfo.getTerminatingSignal(), jobInfo.hasCoreDump()));
+ Assert.assertFalse(jobInfo.wasAborted(), String.format("Job was aborted: %s", jobId));
+ } finally {
+ session.exit();
+ }
+
+ Assert.assertTrue(FileUtils.waitFor(outFile, 120), "File not found: " + outFile.getAbsolutePath());
+ System.out.println("--- output ---");
+ System.out.println(FileUtils.readFileToString(outFile));
+ System.out.println("--- output ---");
+ Assert.assertTrue(outFile.delete(), "Unable to delete " + outFile.getAbsolutePath());
+ System.out.println("Validating that we reached the end of the test without exit.");
+ }
+
+ @Test
+ public void testCollectionConversions() {
+ Collection<String> list = Arrays.asList("a=1", "foo=bar", "empty=");
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ map.put("a", "1");
+ map.put("foo", "bar");
+ map.put("empty", "");
+
+ Assert.assertEquals(JnaSession.collectionToMap(list), map);
+ Assert.assertEquals(JnaSession.mapToCollection(map), list);
+ }
+
+ @Test
+ public void testLimitConversions() {
+ Assert.assertEquals(JnaSession.formatLimit(0), "0:00:00");
+ Assert.assertEquals(JnaSession.formatLimit(59), "0:00:59");
+ Assert.assertEquals(JnaSession.formatLimit(60), "0:01:00");
+ Assert.assertEquals(JnaSession.formatLimit(3540), "0:59:00");
+ Assert.assertEquals(JnaSession.formatLimit(3599), "0:59:59");
+ Assert.assertEquals(JnaSession.formatLimit(7200), "2:00:00");
+ Assert.assertEquals(JnaSession.formatLimit(7260), "2:01:00");
+ Assert.assertEquals(JnaSession.formatLimit(7261), "2:01:01");
+
+ Assert.assertEquals(JnaSession.parseLimit("0"), 0);
+ Assert.assertEquals(JnaSession.parseLimit("00"), 0);
+ Assert.assertEquals(JnaSession.parseLimit("0:00"), 0);
+ Assert.assertEquals(JnaSession.parseLimit("00:00"), 0);
+ Assert.assertEquals(JnaSession.parseLimit("0:00:00"), 0);
+
+ Assert.assertEquals(JnaSession.parseLimit("1"), 1);
+ Assert.assertEquals(JnaSession.parseLimit("01"), 1);
+ Assert.assertEquals(JnaSession.parseLimit("0:01"), 1);
+ Assert.assertEquals(JnaSession.parseLimit("00:01"), 1);
+ Assert.assertEquals(JnaSession.parseLimit("0:00:01"), 1);
+
+ Assert.assertEquals(JnaSession.parseLimit("10"), 10);
+ Assert.assertEquals(JnaSession.parseLimit("0:10"), 10);
+ Assert.assertEquals(JnaSession.parseLimit("00:10"), 10);
+ Assert.assertEquals(JnaSession.parseLimit("0:00:10"), 10);
+
+ Assert.assertEquals(JnaSession.parseLimit("1:0"), 60);
+ Assert.assertEquals(JnaSession.parseLimit("1:00"), 60);
+ Assert.assertEquals(JnaSession.parseLimit("01:00"), 60);
+ Assert.assertEquals(JnaSession.parseLimit("0:01:00"), 60);
+
+ Assert.assertEquals(JnaSession.parseLimit("1:00:00"), 3600);
+
+ Assert.assertEquals(JnaSession.parseLimit("1:02:03"), 3723);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/LibDrmaaQueueTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/LibDrmaaQueueTest.java
new file mode 100644
index 0000000..accc0fe
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/drmaa/v1_0/LibDrmaaQueueTest.java
@@ -0,0 +1,257 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.drmaa.v1_0;
+
+import com.sun.jna.Memory;
+import com.sun.jna.NativeLong;
+import com.sun.jna.Pointer;
+import com.sun.jna.StringArray;
+import com.sun.jna.ptr.IntByReference;
+import com.sun.jna.ptr.PointerByReference;
+import org.apache.commons.io.FileUtils;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.SkipException;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
+public class LibDrmaaQueueTest extends BaseTest {
+ private String implementation = null;
+
+ @Test
+ public void testDrmaa() throws Exception {
+ Memory error = new Memory(LibDrmaa.DRMAA_ERROR_STRING_BUFFER);
+ int errnum;
+
+ IntByReference major = new IntByReference();
+ IntByReference minor = new IntByReference();
+ Memory contact = new Memory(LibDrmaa.DRMAA_CONTACT_BUFFER);
+ Memory drmSystem = new Memory(LibDrmaa.DRMAA_DRM_SYSTEM_BUFFER);
+ Memory drmaaImplementation = new Memory(LibDrmaa.DRMAA_DRMAA_IMPLEMENTATION_BUFFER);
+
+ errnum = LibDrmaa.drmaa_version(major, minor, error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not get version from the DRMAA library: %s", error.getString(0)));
+
+ System.out.println(String.format("DRMAA version: %d.%d", major.getValue(), minor.getValue()));
+
+ errnum = LibDrmaa.drmaa_get_contact(contact, LibDrmaa.DRMAA_CONTACT_BUFFER_LEN, error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not get contacts from the DRMAA library: %s", error.getString(0)));
+
+ System.out.println(String.format("DRMAA contact(s): %s", contact.getString(0)));
+
+ errnum = LibDrmaa.drmaa_get_DRM_system(drmSystem, LibDrmaa.DRMAA_DRM_SYSTEM_BUFFER_LEN, error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not get DRM system from the DRMAA library: %s", error.getString(0)));
+
+ System.out.println(String.format("DRM system(s): %s", drmSystem.getString(0)));
+
+ errnum = LibDrmaa.drmaa_get_DRMAA_implementation(drmaaImplementation, LibDrmaa.DRMAA_DRMAA_IMPLEMENTATION_BUFFER_LEN, error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not get DRMAA implementation from the DRMAA library: %s", error.getString(0)));
+
+ System.out.println(String.format("DRMAA implementation(s): %s", drmaaImplementation.getString(0)));
+
+ this.implementation = drmaaImplementation.getString(0);
+ }
+
+ @Test(dependsOnMethods = { "testDrmaa" })
+ public void testSubmitEcho() throws Exception {
+ if ( ! queueTestRunModeIsSet ) {
+ throw new SkipException("Skipping testSubmitEcho because we are in pipeline test dry run mode");
+ }
+
+ if (implementation.contains("LSF")) {
+ System.err.println(" *********************************************************");
+ System.err.println(" ***********************************************************");
+ System.err.println(" **** ****");
+ System.err.println(" **** Skipping LibDrmaaQueueTest.testSubmitEcho() ****");
+ System.err.println(" **** Are you using the dotkit .combined_LSF_SGE? ****");
+ System.err.println(" **** ****");
+ System.err.println(" ***********************************************************");
+ System.err.println(" *********************************************************");
+ throw new SkipException("Skipping testSubmitEcho because correct DRMAA implementation not found");
+ }
+
+ Memory error = new Memory(LibDrmaa.DRMAA_ERROR_STRING_BUFFER);
+ int errnum;
+
+ File outFile = tryCreateNetworkTempFile("LibDrmaaQueueTest.out");
+
+ errnum = LibDrmaa.drmaa_init(null, error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not initialize the DRMAA library: %s", error.getString(0)));
+
+ try {
+ PointerByReference jtRef = new PointerByReference();
+ Pointer jt;
+ Memory jobIdMem = new Memory(LibDrmaa.DRMAA_JOBNAME_BUFFER);
+ String jobId;
+ IntByReference remotePs = new IntByReference();
+ IntByReference stat = new IntByReference();
+ PointerByReference rusage = new PointerByReference();
+
+ errnum = LibDrmaa.drmaa_allocate_job_template(jtRef, error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not create job template: %s", error.getString(0)));
+
+ jt = jtRef.getValue();
+
+ errnum = LibDrmaa.drmaa_set_attribute(jt, LibDrmaa.DRMAA_REMOTE_COMMAND, "sh", error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not set attribute \"%s\": %s", LibDrmaa.DRMAA_REMOTE_COMMAND, error.getString(0)));
+
+ errnum = LibDrmaa.drmaa_set_attribute(jt, LibDrmaa.DRMAA_OUTPUT_PATH, ":" + outFile.getAbsolutePath(), error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not set attribute \"%s\": %s", LibDrmaa.DRMAA_OUTPUT_PATH, error.getString(0)));
+
+ errnum = LibDrmaa.drmaa_set_attribute(jt, LibDrmaa.DRMAA_JOIN_FILES, "y", error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not set attribute \"%s\": %s", LibDrmaa.DRMAA_JOIN_FILES, error.getString(0)));
+
+ StringArray args = new StringArray(new String[] { "-c", "echo \"Hello world.\"" });
+
+ errnum = LibDrmaa.drmaa_set_vector_attribute(jt, LibDrmaa.DRMAA_V_ARGV, args, error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not set attribute \"%s\": %s", LibDrmaa.DRMAA_V_ARGV, error.getString(0)));
+
+ errnum = LibDrmaa.drmaa_run_job(jobIdMem, LibDrmaa.DRMAA_JOBNAME_BUFFER_LEN, jt, error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not submit job: %s", error.getString(0)));
+
+ jobId = jobIdMem.getString(0);
+
+ System.out.println(String.format("Job id %s", jobId));
+
+ errnum = LibDrmaa.drmaa_delete_job_template(jt, error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not delete job template: %s", error.getString(0)));
+
+ System.out.println("Waiting for job to run: " + jobId);
+ remotePs.setValue(LibDrmaa.DRMAA_PS.DRMAA_PS_QUEUED_ACTIVE);
+
+ List<Integer> runningStatuses = Arrays.asList(
+ LibDrmaa.DRMAA_PS.DRMAA_PS_QUEUED_ACTIVE, LibDrmaa.DRMAA_PS.DRMAA_PS_RUNNING);
+
+ while (runningStatuses.contains(remotePs.getValue())) {
+ Thread.sleep(30 * 1000L);
+
+ errnum = LibDrmaa.drmaa_job_ps(jobId, remotePs, error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not get status for jobId %s: %s", jobId, error.getString(0)));
+ }
+
+ Assert.assertEquals(remotePs.getValue(), LibDrmaa.DRMAA_PS.DRMAA_PS_DONE, "Job status is not DONE.");
+
+ errnum = LibDrmaa.drmaa_wait(jobId, Pointer.NULL, new NativeLong(0), stat, LibDrmaa.DRMAA_TIMEOUT_NO_WAIT,
+ rusage, error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Wait failed for jobId %s: %s", jobId, error.getString(0)));
+
+ IntByReference exited = new IntByReference();
+ IntByReference exitStatus = new IntByReference();
+ IntByReference signaled = new IntByReference();
+ Memory signal = new Memory(LibDrmaa.DRMAA_SIGNAL_BUFFER);
+ IntByReference coreDumped = new IntByReference();
+ IntByReference aborted = new IntByReference();
+
+ errnum = LibDrmaa.drmaa_wifexited(exited, stat.getValue(), error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Exit check failed for jobId %s: %s", jobId, error.getString(0)));
+
+ Assert.assertTrue(exited.getValue() != 0, String.format("Job did not exit cleanly: %s", jobId));
+
+ errnum = LibDrmaa.drmaa_wexitstatus(exitStatus, stat.getValue(), error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Exit status failed for jobId %s: %s", jobId, error.getString(0)));
+
+ Assert.assertEquals(exitStatus.getValue(), 0, String.format("Exit status for jobId %s is non-zero", jobId));
+
+ errnum = LibDrmaa.drmaa_wifsignaled(signaled, stat.getValue(), error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Signaled check failed for jobId %s: %s", jobId, error.getString(0)));
+
+ if (signaled.getValue() != 0) {
+ errnum = LibDrmaa.drmaa_wtermsig(signal, LibDrmaa.DRMAA_SIGNAL_BUFFER_LEN, stat.getValue(), error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Signal lookup failed for jobId %s: %s", jobId, error.getString(0)));
+
+ errnum = LibDrmaa.drmaa_wcoredump(coreDumped, stat.getValue(), error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Core dump check failed for jobId %s: %s", jobId, error.getString(0)));
+
+ Assert.fail(String.format("JobId %s exited with signal %s and core dump flag %d", jobId, signal.getString(0), coreDumped.getValue()));
+ }
+
+ errnum = LibDrmaa.drmaa_wifaborted(aborted, stat.getValue(), error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Aborted check failed for jobId %s: %s", jobId, error.getString(0)));
+
+ Assert.assertTrue(aborted.getValue() == 0, String.format("Job was aborted: %s", jobId));
+
+ } finally {
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS) {
+ LibDrmaa.drmaa_exit(error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+ } else {
+ errnum = LibDrmaa.drmaa_exit(error, LibDrmaa.DRMAA_ERROR_STRING_BUFFER_LEN);
+
+ if (errnum != LibDrmaa.DRMAA_ERRNO.DRMAA_ERRNO_SUCCESS)
+ Assert.fail(String.format("Could not shut down the DRMAA library: %s", error.getString(0)));
+ }
+ }
+
+ Assert.assertTrue(FileUtils.waitFor(outFile, 120), "File not found: " + outFile.getAbsolutePath());
+ System.out.println("--- output ---");
+ System.out.println(FileUtils.readFileToString(outFile));
+ System.out.println("--- output ---");
+ Assert.assertTrue(outFile.delete(), "Unable to delete " + outFile.getAbsolutePath());
+ System.out.println("Validating that we reached the end of the test without exit.");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/lsf/v7_0_6/LibBatQueueTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/lsf/v7_0_6/LibBatQueueTest.java
new file mode 100644
index 0000000..4af2bf7
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/jna/lsf/v7_0_6/LibBatQueueTest.java
@@ -0,0 +1,162 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.jna.lsf.v7_0_6;
+
+import com.sun.jna.*;
+import com.sun.jna.ptr.IntByReference;
+import org.apache.commons.io.FileUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.testng.Assert;
+import org.testng.SkipException;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.jna.lsf.v7_0_6.LibBat.*;
+
+import java.io.File;
+
+/**
+ * Really unit tests, but these tests will only run on systems with LSF set up.
+ */
+public class LibBatQueueTest extends BaseTest {
+ @BeforeClass
+ public void initLibBat() {
+ Assert.assertFalse(LibBat.lsb_init("LibBatQueueTest") < 0, LibBat.lsb_sperror("lsb_init() failed"));
+ }
+
+ @Test
+ public void testClusterName() {
+ String clusterName = LibLsf.ls_getclustername();
+ System.out.println("Cluster name: " + clusterName);
+ Assert.assertNotNull(clusterName);
+ }
+
+ @Test
+ public void testReadConfEnv() {
+ LibLsf.config_param[] configParams = (LibLsf.config_param[]) new LibLsf.config_param().toArray(4);
+
+ configParams[0].paramName = "LSF_UNIT_FOR_LIMITS";
+ configParams[1].paramName = "LSF_CONFDIR";
+ configParams[2].paramName = "MADE_UP_PARAMETER";
+
+ Structure.autoWrite(configParams);
+
+ if (LibLsf.ls_readconfenv(configParams[0], null) != 0) {
+ Assert.fail(LibLsf.ls_sysmsg());
+ }
+
+ Structure.autoRead(configParams);
+
+ System.out.println("LSF_UNIT_FOR_LIMITS: " + configParams[0].paramValue);
+ Assert.assertNotNull(configParams[1].paramValue);
+ Assert.assertNull(configParams[2].paramValue);
+ Assert.assertNull(configParams[3].paramName);
+ Assert.assertNull(configParams[3].paramValue);
+ }
+
+ @Test
+ public void testReadQueueLimits() {
+ String queue = "hour";
+ StringArray queues = new StringArray(new String[] {queue});
+ IntByReference numQueues = new IntByReference(1);
+ queueInfoEnt queueInfo = LibBat.lsb_queueinfo(queues, numQueues, null, null, 0);
+
+ Assert.assertEquals(numQueues.getValue(), 1);
+ Assert.assertNotNull(queueInfo);
+ Assert.assertEquals(queueInfo.queue, queue);
+
+ int runLimit = queueInfo.rLimits[LibLsf.LSF_RLIMIT_RUN];
+ Assert.assertTrue(runLimit > 0, "LSF run limit is not greater than zero: " + runLimit);
+ }
+
+ @Test
+ public void testSubmitEcho() throws Exception {
+ if ( ! queueTestRunModeIsSet ) {
+ throw new SkipException("Skipping testSubmitEcho because we are in queue test dry run mode");
+ }
+
+ String queue = "hour";
+ File outFile = tryCreateNetworkTempFile("LibBatQueueTest.out");
+
+ submit req = new submit();
+
+ for (int i = 0; i < LibLsf.LSF_RLIM_NLIMITS; i++)
+ req.rLimits[i] = LibLsf.DEFAULT_RLIMIT;
+
+ req.projectName = "LibBatQueueTest";
+ req.options |= LibBat.SUB_PROJECT_NAME;
+
+ req.queue = queue;
+ req.options |= LibBat.SUB_QUEUE;
+
+ req.outFile = outFile.getPath();
+ req.options |= LibBat.SUB_OUT_FILE;
+
+ req.userPriority = 100;
+ req.options2 |= LibBat.SUB2_JOB_PRIORITY;
+
+ req.command = "echo \"Hello world.\"";
+
+ String[] argv = {"", "-a", "tv"};
+ int setOptionResult = LibBat.setOption_(argv.length, new StringArray(argv), "a:", req, ~0, ~0, ~0, null);
+ Assert.assertTrue(setOptionResult != -1, "setOption_ returned -1");
+
+ submitReply reply = new submitReply();
+ long jobId = LibBat.lsb_submit(req, reply);
+
+ Assert.assertFalse(jobId < 0, LibBat.lsb_sperror("Error dispatching"));
+
+ System.out.println("Waiting for job to run: " + jobId);
+ int jobStatus = LibBat.JOB_STAT_PEND;
+ while (Utils.isFlagSet(jobStatus, LibBat.JOB_STAT_PEND) || Utils.isFlagSet(jobStatus, LibBat.JOB_STAT_RUN)) {
+ Thread.sleep(30 * 1000L);
+
+ int numJobs = LibBat.lsb_openjobinfo(jobId, null, null, null, null, LibBat.ALL_JOB);
+ try {
+ Assert.assertEquals(numJobs, 1);
+
+ IntByReference more = new IntByReference();
+
+ jobInfoEnt jobInfo = LibBat.lsb_readjobinfo(more);
+ Assert.assertNotNull(jobInfo, "Job info is null");
+ Assert.assertEquals(more.getValue(), 0, "More job info results than expected");
+
+ jobStatus = jobInfo.status;
+ } finally {
+ LibBat.lsb_closejobinfo();
+ }
+ }
+ Assert.assertTrue(Utils.isFlagSet(jobStatus, LibBat.JOB_STAT_DONE), String.format("Unexpected job status: 0x%02x", jobStatus));
+
+ Assert.assertTrue(FileUtils.waitFor(outFile, 120), "File not found: " + outFile.getAbsolutePath());
+ System.out.println("--- output ---");
+ System.out.println(FileUtils.readFileToString(outFile));
+ System.out.println("--- output ---");
+ Assert.assertTrue(outFile.delete(), "Unable to delete " + outFile.getAbsolutePath());
+ Assert.assertEquals(reply.queue, req.queue, "LSF reply queue does not match requested queue.");
+ System.out.println("Validating that we reached the end of the test without exit.");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/AlignmentStateMachineUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/AlignmentStateMachineUnitTest.java
new file mode 100644
index 0000000..d8c39d3
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/AlignmentStateMachineUnitTest.java
@@ -0,0 +1,110 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+/**
+ * testing of the new (non-legacy) version of LocusIteratorByState
+ */
+public class AlignmentStateMachineUnitTest extends LocusIteratorByStateBaseTest {
+ @DataProvider(name = "AlignmentStateMachineTest")
+ public Object[][] makeAlignmentStateMachineTest() {
+// return new Object[][]{{new LIBSTest("2M2D2X", 2)}};
+// return createLIBSTests(
+// Arrays.asList(2),
+// Arrays.asList(2));
+ return createLIBSTests(
+ Arrays.asList(1, 2),
+ Arrays.asList(1, 2, 3, 4));
+ }
+
+ @Test(dataProvider = "AlignmentStateMachineTest")
+ public void testAlignmentStateMachineTest(LIBSTest params) {
+ final GATKSAMRecord read = params.makeRead();
+ final AlignmentStateMachine state = new AlignmentStateMachine(read);
+ final LIBS_position tester = new LIBS_position(read);
+
+ // min is one because always visit something, even for 10I reads
+ final int expectedBpToVisit = read.getAlignmentEnd() - read.getAlignmentStart() + 1;
+
+ Assert.assertSame(state.getRead(), read);
+ Assert.assertNotNull(state.toString());
+
+ int bpVisited = 0;
+ int lastOffset = -1;
+
+ // TODO -- more tests about test state machine state before first step?
+ Assert.assertTrue(state.isLeftEdge());
+ Assert.assertNull(state.getCigarOperator());
+ Assert.assertNotNull(state.toString());
+ Assert.assertEquals(state.getReadOffset(), -1);
+ Assert.assertEquals(state.getGenomeOffset(), -1);
+ Assert.assertEquals(state.getCurrentCigarElementOffset(), -1);
+ Assert.assertEquals(state.getCurrentCigarElement(), null);
+
+ while ( state.stepForwardOnGenome() != null ) {
+ Assert.assertNotNull(state.toString());
+
+ tester.stepForwardOnGenome();
+
+ Assert.assertTrue(state.getReadOffset() >= lastOffset, "Somehow read offsets are decreasing: lastOffset " + lastOffset + " current " + state.getReadOffset());
+ Assert.assertEquals(state.getReadOffset(), tester.getCurrentReadOffset(), "Read offsets are wrong at " + bpVisited);
+
+ Assert.assertFalse(state.isLeftEdge());
+
+ Assert.assertEquals(state.getCurrentCigarElement(), read.getCigar().getCigarElement(tester.currentOperatorIndex), "CigarElement index failure");
+ Assert.assertEquals(state.getOffsetIntoCurrentCigarElement(), tester.getCurrentPositionOnOperatorBase0(), "CigarElement index failure");
+
+ Assert.assertEquals(read.getCigar().getCigarElement(state.getCurrentCigarElementOffset()), state.getCurrentCigarElement(), "Current cigar element isn't what we'd get from the read itself");
+
+ Assert.assertTrue(state.getOffsetIntoCurrentCigarElement() >= 0, "Offset into current cigar too small");
+ Assert.assertTrue(state.getOffsetIntoCurrentCigarElement() < state.getCurrentCigarElement().getLength(), "Offset into current cigar too big");
+
+ Assert.assertEquals(state.getGenomeOffset(), tester.getCurrentGenomeOffsetBase0(), "Offset from alignment start is bad");
+ Assert.assertEquals(state.getGenomePosition(), tester.getCurrentGenomeOffsetBase0() + read.getAlignmentStart(), "GenomePosition start is bad");
+ Assert.assertEquals(state.getLocation(genomeLocParser).size(), 1, "GenomeLoc position should have size == 1");
+ Assert.assertEquals(state.getLocation(genomeLocParser).getStart(), state.getGenomePosition(), "GenomeLoc position is bad");
+
+ // most tests of this functionality are in LIBS
+ Assert.assertNotNull(state.makePileupElement());
+
+ lastOffset = state.getReadOffset();
+ bpVisited++;
+ }
+
+ Assert.assertEquals(bpVisited, expectedBpToVisit, "Didn't visit the expected number of bp");
+ Assert.assertEquals(state.getReadOffset(), read.getReadLength());
+ Assert.assertEquals(state.getCurrentCigarElementOffset(), read.getCigarLength());
+ Assert.assertEquals(state.getCurrentCigarElement(), null);
+ Assert.assertNotNull(state.toString());
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LIBS_position.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LIBS_position.java
new file mode 100644
index 0000000..92680a7
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LIBS_position.java
@@ -0,0 +1,155 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import htsjdk.samtools.Cigar;
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.SAMRecord;
+
+/**
+* Created with IntelliJ IDEA.
+* User: depristo
+* Date: 1/5/13
+* Time: 8:42 PM
+* To change this template use File | Settings | File Templates.
+*/
+public final class LIBS_position {
+
+ SAMRecord read;
+
+ final int numOperators;
+ int currentOperatorIndex = 0;
+ int currentPositionOnOperator = 0;
+ int currentReadOffset = 0;
+ int currentGenomeOffset = 0;
+
+ public boolean isBeforeDeletionStart = false;
+ public boolean isBeforeDeletedBase = false;
+ public boolean isAfterDeletionEnd = false;
+ public boolean isAfterDeletedBase = false;
+ public boolean isBeforeInsertion = false;
+ public boolean isAfterInsertion = false;
+ public boolean isNextToSoftClip = false;
+
+ boolean sawMop = false;
+
+ public LIBS_position(final SAMRecord read) {
+ this.read = read;
+ numOperators = read.getCigar().numCigarElements();
+ }
+
+ public int getCurrentReadOffset() {
+ return Math.max(0, currentReadOffset - 1);
+ }
+
+ public int getCurrentPositionOnOperatorBase0() {
+ return currentPositionOnOperator - 1;
+ }
+
+ public int getCurrentGenomeOffsetBase0() {
+ return currentGenomeOffset - 1;
+ }
+
+ /**
+ * Steps forward on the genome. Returns false when done reading the read, true otherwise.
+ */
+ public boolean stepForwardOnGenome() {
+ if ( currentOperatorIndex == numOperators )
+ return false;
+
+ CigarElement curElement = read.getCigar().getCigarElement(currentOperatorIndex);
+ if ( currentPositionOnOperator >= curElement.getLength() ) {
+ if ( ++currentOperatorIndex == numOperators )
+ return false;
+
+ curElement = read.getCigar().getCigarElement(currentOperatorIndex);
+ currentPositionOnOperator = 0;
+ }
+
+ switch ( curElement.getOperator() ) {
+ case I: // insertion w.r.t. the reference
+// if ( !sawMop )
+// break;
+ case S: // soft clip
+ currentReadOffset += curElement.getLength();
+ case H: // hard clip
+ case P: // padding
+ currentOperatorIndex++;
+ return stepForwardOnGenome();
+
+ case D: // deletion w.r.t. the reference
+ case N: // reference skip (looks and gets processed just like a "deletion", just different logical meaning)
+ currentPositionOnOperator++;
+ currentGenomeOffset++;
+ break;
+
+ case M:
+ case EQ:
+ case X:
+ sawMop = true;
+ currentReadOffset++;
+ currentPositionOnOperator++;
+ currentGenomeOffset++;
+ break;
+ default:
+ throw new IllegalStateException("No support for cigar op: " + curElement.getOperator());
+ }
+
+ final boolean isFirstOp = currentOperatorIndex == 0;
+ final boolean isLastOp = currentOperatorIndex == numOperators - 1;
+ final boolean isFirstBaseOfOp = currentPositionOnOperator == 1;
+ final boolean isLastBaseOfOp = currentPositionOnOperator == curElement.getLength();
+
+ isBeforeDeletionStart = isBeforeOp(read.getCigar(), currentOperatorIndex, CigarOperator.D, isLastOp, isLastBaseOfOp);
+ isBeforeDeletedBase = isBeforeDeletionStart || (!isLastBaseOfOp && curElement.getOperator() == CigarOperator.D);
+ isAfterDeletionEnd = isAfterOp(read.getCigar(), currentOperatorIndex, CigarOperator.D, isFirstOp, isFirstBaseOfOp);
+ isAfterDeletedBase = isAfterDeletionEnd || (!isFirstBaseOfOp && curElement.getOperator() == CigarOperator.D);
+ isBeforeInsertion = isBeforeOp(read.getCigar(), currentOperatorIndex, CigarOperator.I, isLastOp, isLastBaseOfOp)
+ || (!sawMop && curElement.getOperator() == CigarOperator.I);
+ isAfterInsertion = isAfterOp(read.getCigar(), currentOperatorIndex, CigarOperator.I, isFirstOp, isFirstBaseOfOp);
+ isNextToSoftClip = isBeforeOp(read.getCigar(), currentOperatorIndex, CigarOperator.S, isLastOp, isLastBaseOfOp)
+ || isAfterOp(read.getCigar(), currentOperatorIndex, CigarOperator.S, isFirstOp, isFirstBaseOfOp);
+
+ return true;
+ }
+
+ private static boolean isBeforeOp(final Cigar cigar,
+ final int currentOperatorIndex,
+ final CigarOperator op,
+ final boolean isLastOp,
+ final boolean isLastBaseOfOp) {
+ return !isLastOp && isLastBaseOfOp && cigar.getCigarElement(currentOperatorIndex+1).getOperator() == op;
+ }
+
+ private static boolean isAfterOp(final Cigar cigar,
+ final int currentOperatorIndex,
+ final CigarOperator op,
+ final boolean isFirstOp,
+ final boolean isFirstBaseOfOp) {
+ return !isFirstOp && isFirstBaseOfOp && cigar.getCigarElement(currentOperatorIndex-1).getOperator() == op;
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorBenchmark.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorBenchmark.java
new file mode 100644
index 0000000..1f02a68
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorBenchmark.java
@@ -0,0 +1,142 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.QualityUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Caliper microbenchmark of fragment pileup
+ */
+public class LocusIteratorBenchmark extends SimpleBenchmark {
+ protected SAMFileHeader header;
+ protected GenomeLocParser genomeLocParser;
+
+ List<GATKSAMRecord> reads = new LinkedList<GATKSAMRecord>();
+ final int readLength = 101;
+ final int nReads = 10000;
+ final int locus = 1;
+
+ @Param({"101M", "50M10I40M", "50M10D40M"})
+ String cigar; // set automatically by framework
+
+ @Override protected void setUp() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000);
+ genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+
+ for ( int j = 0; j < nReads; j++ ) {
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read", 0, locus, readLength);
+ read.setReadBases(Utils.dupBytes((byte) 'A', readLength));
+ final byte[] quals = new byte[readLength];
+ for ( int i = 0; i < readLength; i++ )
+ quals[i] = (byte)(i % QualityUtils.MAX_SAM_QUAL_SCORE);
+ read.setBaseQualities(quals);
+ read.setCigarString(cigar);
+ reads.add(read);
+ }
+ }
+
+// public void timeOriginalLIBS(int rep) {
+// for ( int i = 0; i < rep; i++ ) {
+// final org.broadinstitute.gatk.utils.locusiterator.old.LocusIteratorByState libs =
+// new org.broadinstitute.gatk.utils.locusiterator.old.LocusIteratorByState(
+// new LocusIteratorByStateBaseTest.FakeCloseableIterator<SAMRecord>(reads.iterator()),
+// LocusIteratorByStateBaseTest.createTestReadProperties(),
+// genomeLocParser,
+// LocusIteratorByState.sampleListForSAMWithoutReadGroups());
+//
+// while ( libs.hasNext() ) {
+// AlignmentContext context = libs.next();
+// }
+// }
+// }
+//
+// public void timeLegacyLIBS(int rep) {
+// for ( int i = 0; i < rep; i++ ) {
+// final org.broadinstitute.gatk.utils.locusiterator.legacy.LegacyLocusIteratorByState libs =
+// new org.broadinstitute.gatk.utils.locusiterator.legacy.LegacyLocusIteratorByState(
+// new LocusIteratorByStateBaseTest.FakeCloseableIterator<SAMRecord>(reads.iterator()),
+// LocusIteratorByStateBaseTest.createTestReadProperties(),
+// genomeLocParser,
+// LocusIteratorByState.sampleListForSAMWithoutReadGroups());
+//
+// while ( libs.hasNext() ) {
+// AlignmentContext context = libs.next();
+// }
+// }
+// }
+
+ public void timeNewLIBS(int rep) {
+ for ( int i = 0; i < rep; i++ ) {
+ final org.broadinstitute.gatk.utils.locusiterator.LocusIteratorByState libs =
+ new org.broadinstitute.gatk.utils.locusiterator.LocusIteratorByState(
+ new LocusIteratorByStateBaseTest.FakeCloseableIterator<GATKSAMRecord>(reads.iterator()),
+ LocusIteratorByStateBaseTest.createTestReadProperties(),
+ genomeLocParser,
+ LocusIteratorByState.sampleListForSAMWithoutReadGroups());
+
+ while ( libs.hasNext() ) {
+ AlignmentContext context = libs.next();
+ }
+ }
+ }
+
+// public void timeOriginalLIBSStateMachine(int rep) {
+// for ( int i = 0; i < rep; i++ ) {
+// for ( final SAMRecord read : reads ) {
+// final SAMRecordAlignmentState alignmentStateMachine = new SAMRecordAlignmentState(read);
+// while ( alignmentStateMachine.stepForwardOnGenome() != null ) {
+// alignmentStateMachine.getGenomeOffset();
+// }
+// }
+// }
+// }
+
+ public void timeAlignmentStateMachine(int rep) {
+ for ( int i = 0; i < rep; i++ ) {
+ for ( final GATKSAMRecord read : reads ) {
+ final AlignmentStateMachine alignmentStateMachine = new AlignmentStateMachine(read);
+ while ( alignmentStateMachine.stepForwardOnGenome() != null ) {
+ ;
+ }
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ com.google.caliper.Runner.main(LocusIteratorBenchmark.class, args);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorByStateBaseTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorByStateBaseTest.java
new file mode 100644
index 0000000..286c712
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorByStateBaseTest.java
@@ -0,0 +1,252 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import htsjdk.samtools.*;
+import htsjdk.samtools.util.CloseableIterator;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.ReadProperties;
+import org.broadinstitute.gatk.engine.arguments.ValidationExclusion;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.broadinstitute.gatk.engine.downsampling.DownsamplingMethod;
+import org.broadinstitute.gatk.engine.filters.ReadFilter;
+import org.broadinstitute.gatk.engine.iterators.ReadTransformer;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.QualityUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+
+/**
+ * testing of the new (non-legacy) version of LocusIteratorByState
+ */
+public class LocusIteratorByStateBaseTest extends BaseTest {
+ protected static SAMFileHeader header;
+ protected GenomeLocParser genomeLocParser;
+
+ @BeforeClass
+ public void beforeClass() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000);
+ genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ }
+
+ protected LocusIteratorByState makeLTBS(List<GATKSAMRecord> reads,
+ ReadProperties readAttributes) {
+ return new LocusIteratorByState(new FakeCloseableIterator<GATKSAMRecord>(reads.iterator()),
+ readAttributes,
+ genomeLocParser,
+ LocusIteratorByState.sampleListForSAMWithoutReadGroups());
+ }
+
+ public static ReadProperties createTestReadProperties() {
+ return createTestReadProperties(null, false);
+ }
+
+ public static ReadProperties createTestReadProperties( DownsamplingMethod downsamplingMethod, final boolean keepReads ) {
+ return new ReadProperties(
+ Collections.<SAMReaderID>emptyList(),
+ new SAMFileHeader(),
+ SAMFileHeader.SortOrder.coordinate,
+ false,
+ ValidationStringency.STRICT,
+ downsamplingMethod,
+ new ValidationExclusion(),
+ Collections.<ReadFilter>emptyList(),
+ Collections.<ReadTransformer>emptyList(),
+ true,
+ (byte) -1,
+ keepReads);
+ }
+
+ public static class FakeCloseableIterator<T> implements CloseableIterator<T> {
+ Iterator<T> iterator;
+
+ public FakeCloseableIterator(Iterator<T> it) {
+ iterator = it;
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public T next() {
+ return iterator.next();
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("Don't remove!");
+ }
+ }
+
+ protected static class LIBSTest {
+ public static final int locus = 44367788;
+ final String cigarString;
+ final int readLength;
+ final private List<CigarElement> elements;
+
+ public LIBSTest(final String cigarString) {
+ final Cigar cigar = TextCigarCodec.getSingleton().decode(cigarString);
+ this.cigarString = cigarString;
+ this.elements = cigar.getCigarElements();
+ this.readLength = cigar.getReadLength();
+ }
+
+ @Override
+ public String toString() {
+ return "LIBSTest{" +
+ "cigar='" + cigarString + '\'' +
+ ", readLength=" + readLength +
+ '}';
+ }
+
+ public List<CigarElement> getElements() {
+ return elements;
+ }
+
+ public GATKSAMRecord makeRead() {
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read", 0, locus, readLength);
+ read.setReadBases(Utils.dupBytes((byte) 'A', readLength));
+ final byte[] quals = new byte[readLength];
+ for ( int i = 0; i < readLength; i++ )
+ quals[i] = (byte)(i % QualityUtils.MAX_SAM_QUAL_SCORE);
+ read.setBaseQualities(quals);
+ read.setCigarString(cigarString);
+ return read;
+ }
+ }
+
+ private boolean isIndel(final CigarElement ce) {
+ return ce.getOperator() == CigarOperator.D || ce.getOperator() == CigarOperator.I;
+ }
+
+ private boolean startsWithDeletion(final List<CigarElement> elements) {
+ for ( final CigarElement element : elements ) {
+ switch ( element.getOperator() ) {
+ case M:
+ case I:
+ case EQ:
+ case X:
+ return false;
+ case D:
+ return true;
+ default:
+ // keep looking
+ }
+ }
+
+ return false;
+ }
+
+ private LIBSTest makePermutationTest(final List<CigarElement> elements) {
+ CigarElement last = null;
+ boolean hasMatch = false;
+
+ // starts with D => bad
+ if ( startsWithDeletion(elements) )
+ return null;
+
+ // ends with D => bad
+ if ( elements.get(elements.size()-1).getOperator() == CigarOperator.D )
+ return null;
+
+ // make sure it's valid
+ String cigar = "";
+ int len = 0;
+ for ( final CigarElement ce : elements ) {
+ if ( ce.getOperator() == CigarOperator.N )
+ return null; // TODO -- don't support N
+
+ // abort on a bad cigar
+ if ( last != null ) {
+ if ( ce.getOperator() == last.getOperator() )
+ return null;
+ if ( isIndel(ce) && isIndel(last) )
+ return null;
+ }
+
+ cigar += ce.getLength() + ce.getOperator().toString();
+ len += ce.getLength();
+ last = ce;
+ hasMatch = hasMatch || ce.getOperator() == CigarOperator.M;
+ }
+
+ if ( ! hasMatch && elements.size() == 1 &&
+ ! (last.getOperator() == CigarOperator.I || last.getOperator() == CigarOperator.S))
+ return null;
+
+ return new LIBSTest(cigar);
+ }
+
+ @DataProvider(name = "LIBSTest")
+ public Object[][] createLIBSTests(final List<Integer> cigarLengths, final List<Integer> combinations) {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ final List<CigarOperator> allOps = Arrays.asList(CigarOperator.values());
+
+ final List<CigarElement> singleCigars = new LinkedList<CigarElement>();
+ for ( final int len : cigarLengths )
+ for ( final CigarOperator op : allOps )
+ singleCigars.add(new CigarElement(len, op));
+
+ for ( final int complexity : combinations ) {
+ for ( final List<CigarElement> elements : Utils.makePermutations(singleCigars, complexity, true) ) {
+ final LIBSTest test = makePermutationTest(elements);
+ if ( test != null ) tests.add(new Object[]{test});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ /**
+ * Work around inadequate tests that aren't worth fixing.
+ *
+ * Look at the CIGAR 2M2P2D2P2M. Both M states border a deletion, separated by P (padding elements). So
+ * the right answer for deletions here is true for isBeforeDeletion() and isAfterDeletion() for the first
+ * and second M. But the LIBS_position doesn't say so.
+ *
+ * @param elements
+ * @return
+ */
+ protected static boolean hasNeighboringPaddedOps(final List<CigarElement> elements, final int elementI) {
+ return (elementI - 1 >= 0 && isPadding(elements.get(elementI-1))) ||
+ (elementI + 1 < elements.size() && isPadding(elements.get(elementI+1)));
+ }
+
+ private static boolean isPadding(final CigarElement elt) {
+ return elt.getOperator() == CigarOperator.P || elt.getOperator() == CigarOperator.H || elt.getOperator() == CigarOperator.S;
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorByStateUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorByStateUnitTest.java
new file mode 100644
index 0000000..08cbeca
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/LocusIteratorByStateUnitTest.java
@@ -0,0 +1,753 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import htsjdk.samtools.CigarOperator;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.engine.ReadProperties;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.downsampling.DownsampleType;
+import org.broadinstitute.gatk.engine.downsampling.DownsamplingMethod;
+import org.broadinstitute.gatk.utils.NGSPlatform;
+import org.broadinstitute.gatk.utils.QualityUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.broadinstitute.gatk.utils.pileup.ReadBackedPileup;
+import org.broadinstitute.gatk.utils.sam.ArtificialBAMBuilder;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMReadGroupRecord;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+/**
+ * testing of the new (non-legacy) version of LocusIteratorByState
+ */
+public class LocusIteratorByStateUnitTest extends LocusIteratorByStateBaseTest {
+ private static final boolean DEBUG = false;
+ protected LocusIteratorByState li;
+
+ @Test(enabled = !DEBUG)
+ public void testUnmappedAndAllIReadsPassThrough() {
+ final int readLength = 10;
+ GATKSAMRecord mapped1 = ArtificialSAMUtils.createArtificialRead(header,"mapped1",0,1,readLength);
+ GATKSAMRecord mapped2 = ArtificialSAMUtils.createArtificialRead(header,"mapped2",0,1,readLength);
+ GATKSAMRecord unmapped = ArtificialSAMUtils.createArtificialRead(header,"unmapped",0,1,readLength);
+ GATKSAMRecord allI = ArtificialSAMUtils.createArtificialRead(header,"allI",0,1,readLength);
+
+ unmapped.setReadUnmappedFlag(true);
+ unmapped.setCigarString("*");
+ allI.setCigarString(readLength + "I");
+
+ List<GATKSAMRecord> reads = Arrays.asList(mapped1, unmapped, allI, mapped2);
+
+ // create the iterator by state with the fake reads and fake records
+ li = makeLTBS(reads,createTestReadProperties(DownsamplingMethod.NONE, true));
+
+ Assert.assertTrue(li.hasNext());
+ AlignmentContext context = li.next();
+ ReadBackedPileup pileup = context.getBasePileup();
+ Assert.assertEquals(pileup.depthOfCoverage(), 2, "Should see only 2 reads in pileup, even with unmapped and all I reads");
+
+ final List<GATKSAMRecord> rawReads = li.transferReadsFromAllPreviousPileups();
+ Assert.assertEquals(rawReads, reads, "Input and transferred read lists should be the same, and include the unmapped and all I reads");
+ }
+
+ @Test(enabled = true && ! DEBUG)
+ public void testXandEQOperators() {
+ final byte[] bases1 = new byte[] {'A','A','A','A','A','A','A','A','A','A'};
+ final byte[] bases2 = new byte[] {'A','A','A','C','A','A','A','A','A','C'};
+
+ // create a test version of the Reads object
+ ReadProperties readAttributes = createTestReadProperties();
+
+ GATKSAMRecord r1 = ArtificialSAMUtils.createArtificialRead(header,"r1",0,1,10);
+ r1.setReadBases(bases1);
+ r1.setBaseQualities(new byte[] {20,20,20,20,20,20,20,20,20,20});
+ r1.setCigarString("10M");
+
+ GATKSAMRecord r2 = ArtificialSAMUtils.createArtificialRead(header,"r2",0,1,10);
+ r2.setReadBases(bases2);
+ r2.setBaseQualities(new byte[] {20,20,20,20,20,20,20,20,20,20,20,20});
+ r2.setCigarString("3=1X5=1X");
+
+ GATKSAMRecord r3 = ArtificialSAMUtils.createArtificialRead(header,"r3",0,1,10);
+ r3.setReadBases(bases2);
+ r3.setBaseQualities(new byte[] {20,20,20,20,20,20,20,20,20,20,20,20});
+ r3.setCigarString("3=1X5M1X");
+
+ GATKSAMRecord r4 = ArtificialSAMUtils.createArtificialRead(header,"r4",0,1,10);
+ r4.setReadBases(bases2);
+ r4.setBaseQualities(new byte[] {20,20,20,20,20,20,20,20,20,20});
+ r4.setCigarString("10M");
+
+ List<GATKSAMRecord> reads = Arrays.asList(r1, r2, r3, r4);
+
+ // create the iterator by state with the fake reads and fake records
+ li = makeLTBS(reads,readAttributes);
+
+ while (li.hasNext()) {
+ AlignmentContext context = li.next();
+ ReadBackedPileup pileup = context.getBasePileup();
+ Assert.assertEquals(pileup.depthOfCoverage(), 4);
+ }
+ }
+
+ @Test(enabled = true && ! DEBUG)
+ public void testIndelsInRegularPileup() {
+ final byte[] bases = new byte[] {'A','A','A','A','A','A','A','A','A','A'};
+ final byte[] indelBases = new byte[] {'A','A','A','A','C','T','A','A','A','A','A','A'};
+
+ // create a test version of the Reads object
+ ReadProperties readAttributes = createTestReadProperties();
+
+ GATKSAMRecord before = ArtificialSAMUtils.createArtificialRead(header,"before",0,1,10);
+ before.setReadBases(bases);
+ before.setBaseQualities(new byte[] {20,20,20,20,20,20,20,20,20,20});
+ before.setCigarString("10M");
+
+ GATKSAMRecord during = ArtificialSAMUtils.createArtificialRead(header,"during",0,2,10);
+ during.setReadBases(indelBases);
+ during.setBaseQualities(new byte[] {20,20,20,20,20,20,20,20,20,20,20,20});
+ during.setCigarString("4M2I6M");
+
+ GATKSAMRecord after = ArtificialSAMUtils.createArtificialRead(header,"after",0,3,10);
+ after.setReadBases(bases);
+ after.setBaseQualities(new byte[] {20,20,20,20,20,20,20,20,20,20});
+ after.setCigarString("10M");
+
+ List<GATKSAMRecord> reads = Arrays.asList(before, during, after);
+
+ // create the iterator by state with the fake reads and fake records
+ li = makeLTBS(reads,readAttributes);
+
+ boolean foundIndel = false;
+ while (li.hasNext()) {
+ AlignmentContext context = li.next();
+ ReadBackedPileup pileup = context.getBasePileup().getBaseFilteredPileup(10);
+ for (PileupElement p : pileup) {
+ if (p.isBeforeInsertion()) {
+ foundIndel = true;
+ Assert.assertEquals(p.getLengthOfImmediatelyFollowingIndel(), 2, "Wrong event length");
+ Assert.assertEquals(p.getBasesOfImmediatelyFollowingInsertion(), "CT", "Inserted bases are incorrect");
+ break;
+ }
+ }
+
+ }
+
+ Assert.assertTrue(foundIndel,"Indel in pileup not found");
+ }
+
+ @Test(enabled = false && ! DEBUG)
+ public void testWholeIndelReadInIsolation() {
+ final int firstLocus = 44367789;
+
+ // create a test version of the Reads object
+ ReadProperties readAttributes = createTestReadProperties();
+
+ GATKSAMRecord indelOnlyRead = ArtificialSAMUtils.createArtificialRead(header, "indelOnly", 0, firstLocus, 76);
+ indelOnlyRead.setReadBases(Utils.dupBytes((byte)'A',76));
+ indelOnlyRead.setBaseQualities(Utils.dupBytes((byte) '@', 76));
+ indelOnlyRead.setCigarString("76I");
+
+ List<GATKSAMRecord> reads = Arrays.asList(indelOnlyRead);
+
+ // create the iterator by state with the fake reads and fake records
+ li = makeLTBS(reads, readAttributes);
+
+ // Traditionally, reads that end with indels bleed into the pileup at the following locus. Verify that the next pileup contains this read
+ // and considers it to be an indel-containing read.
+ Assert.assertTrue(li.hasNext(),"Should have found a whole-indel read in the normal base pileup without extended events enabled");
+ AlignmentContext alignmentContext = li.next();
+ Assert.assertEquals(alignmentContext.getLocation().getStart(), firstLocus, "Base pileup is at incorrect location.");
+ ReadBackedPileup basePileup = alignmentContext.getBasePileup();
+ Assert.assertEquals(basePileup.getReads().size(),1,"Pileup is of incorrect size");
+ Assert.assertSame(basePileup.getReads().get(0), indelOnlyRead, "Read in pileup is incorrect");
+ }
+
+ /**
+ * Test to make sure that reads supporting only an indel (example cigar string: 76I) do
+ * not negatively influence the ordering of the pileup.
+ */
+ @Test(enabled = true && ! DEBUG)
+ public void testWholeIndelRead() {
+ final int firstLocus = 44367788, secondLocus = firstLocus + 1;
+
+ GATKSAMRecord leadingRead = ArtificialSAMUtils.createArtificialRead(header,"leading",0,firstLocus,76);
+ leadingRead.setReadBases(Utils.dupBytes((byte)'A',76));
+ leadingRead.setBaseQualities(Utils.dupBytes((byte)'@',76));
+ leadingRead.setCigarString("1M75I");
+
+ GATKSAMRecord indelOnlyRead = ArtificialSAMUtils.createArtificialRead(header,"indelOnly",0,secondLocus,76);
+ indelOnlyRead.setReadBases(Utils.dupBytes((byte) 'A', 76));
+ indelOnlyRead.setBaseQualities(Utils.dupBytes((byte)'@',76));
+ indelOnlyRead.setCigarString("76I");
+
+ GATKSAMRecord fullMatchAfterIndel = ArtificialSAMUtils.createArtificialRead(header,"fullMatch",0,secondLocus,76);
+ fullMatchAfterIndel.setReadBases(Utils.dupBytes((byte)'A',76));
+ fullMatchAfterIndel.setBaseQualities(Utils.dupBytes((byte)'@',76));
+ fullMatchAfterIndel.setCigarString("75I1M");
+
+ List<GATKSAMRecord> reads = Arrays.asList(leadingRead, indelOnlyRead, fullMatchAfterIndel);
+
+ // create the iterator by state with the fake reads and fake records
+ li = makeLTBS(reads, createTestReadProperties());
+ int currentLocus = firstLocus;
+ int numAlignmentContextsFound = 0;
+
+ while(li.hasNext()) {
+ AlignmentContext alignmentContext = li.next();
+ Assert.assertEquals(alignmentContext.getLocation().getStart(),currentLocus,"Current locus returned by alignment context is incorrect");
+
+ if(currentLocus == firstLocus) {
+ List<GATKSAMRecord> readsAtLocus = alignmentContext.getBasePileup().getReads();
+ Assert.assertEquals(readsAtLocus.size(),1,"Wrong number of reads at locus " + currentLocus);
+ Assert.assertSame(readsAtLocus.get(0),leadingRead,"leadingRead absent from pileup at locus " + currentLocus);
+ }
+ else if(currentLocus == secondLocus) {
+ List<GATKSAMRecord> readsAtLocus = alignmentContext.getBasePileup().getReads();
+ Assert.assertEquals(readsAtLocus.size(),1,"Wrong number of reads at locus " + currentLocus);
+ Assert.assertSame(readsAtLocus.get(0),fullMatchAfterIndel,"fullMatchAfterIndel absent from pileup at locus " + currentLocus);
+ }
+
+ currentLocus++;
+ numAlignmentContextsFound++;
+ }
+
+ Assert.assertEquals(numAlignmentContextsFound, 2, "Found incorrect number of alignment contexts");
+ }
+
+ /**
+ * Test to make sure that reads supporting only an indel (example cigar string: 76I) are represented properly
+ */
+ @Test(enabled = false && ! DEBUG)
+ public void testWholeIndelReadRepresentedTest() {
+ final int firstLocus = 44367788, secondLocus = firstLocus + 1;
+
+ GATKSAMRecord read1 = ArtificialSAMUtils.createArtificialRead(header,"read1",0,secondLocus,1);
+ read1.setReadBases(Utils.dupBytes((byte) 'A', 1));
+ read1.setBaseQualities(Utils.dupBytes((byte) '@', 1));
+ read1.setCigarString("1I");
+
+ List<GATKSAMRecord> reads = Arrays.asList(read1);
+
+ // create the iterator by state with the fake reads and fake records
+ li = makeLTBS(reads, createTestReadProperties());
+
+ while(li.hasNext()) {
+ AlignmentContext alignmentContext = li.next();
+ ReadBackedPileup p = alignmentContext.getBasePileup();
+ Assert.assertTrue(p.getNumberOfElements() == 1);
+ // TODO -- fix tests
+// PileupElement pe = p.iterator().next();
+// Assert.assertTrue(pe.isBeforeInsertion());
+// Assert.assertFalse(pe.isAfterInsertion());
+// Assert.assertEquals(pe.getBasesOfImmediatelyFollowingInsertion(), "A");
+ }
+
+ GATKSAMRecord read2 = ArtificialSAMUtils.createArtificialRead(header,"read2",0,secondLocus,10);
+ read2.setReadBases(Utils.dupBytes((byte) 'A', 10));
+ read2.setBaseQualities(Utils.dupBytes((byte) '@', 10));
+ read2.setCigarString("10I");
+
+ reads = Arrays.asList(read2);
+
+ // create the iterator by state with the fake reads and fake records
+ li = makeLTBS(reads, createTestReadProperties());
+
+ while(li.hasNext()) {
+ AlignmentContext alignmentContext = li.next();
+ ReadBackedPileup p = alignmentContext.getBasePileup();
+ Assert.assertTrue(p.getNumberOfElements() == 1);
+ // TODO -- fix tests
+// PileupElement pe = p.iterator().next();
+// Assert.assertTrue(pe.isBeforeInsertion());
+// Assert.assertFalse(pe.isAfterInsertion());
+// Assert.assertEquals(pe.getBasesOfImmediatelyFollowingInsertion(), "AAAAAAAAAA");
+ }
+ }
+
+
+ /////////////////////////////////////////////
+ // get event length and bases calculations //
+ /////////////////////////////////////////////
+
+ @DataProvider(name = "IndelLengthAndBasesTest")
+ public Object[][] makeIndelLengthAndBasesTest() {
+ final String EVENT_BASES = "ACGTACGTACGT";
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ for ( int eventSize = 1; eventSize < 10; eventSize++ ) {
+ for ( final CigarOperator indel : Arrays.asList(CigarOperator.D, CigarOperator.I) ) {
+ final String cigar = String.format("2M%d%s1M", eventSize, indel.toString());
+ final String eventBases = indel == CigarOperator.D ? "" : EVENT_BASES.substring(0, eventSize);
+ final int readLength = 3 + eventBases.length();
+
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read", 0, 1, readLength);
+ read.setReadBases(("TT" + eventBases + "A").getBytes());
+ final byte[] quals = new byte[readLength];
+ for ( int i = 0; i < readLength; i++ )
+ quals[i] = (byte)(i % QualityUtils.MAX_SAM_QUAL_SCORE);
+ read.setBaseQualities(quals);
+ read.setCigarString(cigar);
+
+ tests.add(new Object[]{read, indel, eventSize, eventBases.equals("") ? null : eventBases});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "IndelLengthAndBasesTest")
+ public void testIndelLengthAndBasesTest(GATKSAMRecord read, final CigarOperator op, final int eventSize, final String eventBases) {
+ // create the iterator by state with the fake reads and fake records
+ li = makeLTBS(Arrays.asList((GATKSAMRecord)read), createTestReadProperties());
+
+ Assert.assertTrue(li.hasNext());
+
+ final PileupElement firstMatch = getFirstPileupElement(li.next());
+
+ Assert.assertEquals(firstMatch.getLengthOfImmediatelyFollowingIndel(), 0, "Length != 0 for site not adjacent to indel");
+ Assert.assertEquals(firstMatch.getBasesOfImmediatelyFollowingInsertion(), null, "Getbases of following event should be null at non-adajenct event");
+
+ Assert.assertTrue(li.hasNext());
+
+ final PileupElement pe = getFirstPileupElement(li.next());
+
+ if ( op == CigarOperator.D )
+ Assert.assertTrue(pe.isBeforeDeletionStart());
+ else
+ Assert.assertTrue(pe.isBeforeInsertion());
+
+ Assert.assertEquals(pe.getLengthOfImmediatelyFollowingIndel(), eventSize, "Length of event failed");
+ Assert.assertEquals(pe.getBasesOfImmediatelyFollowingInsertion(), eventBases, "Getbases of following event failed");
+ }
+
+ private PileupElement getFirstPileupElement(final AlignmentContext context) {
+ final ReadBackedPileup p = context.getBasePileup();
+ Assert.assertEquals(p.getNumberOfElements(), 1);
+ return p.iterator().next();
+ }
+
+ ////////////////////////////////////////////
+ // comprehensive LIBS/PileupElement tests //
+ ////////////////////////////////////////////
+
+ @DataProvider(name = "MyLIBSTest")
+ public Object[][] makeLIBSTest() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+// tests.add(new Object[]{new LIBSTest("2=2D2=2X", 1)});
+// return tests.toArray(new Object[][]{});
+
+ return createLIBSTests(
+ Arrays.asList(1, 2),
+ Arrays.asList(1, 2, 3, 4));
+
+// return createLIBSTests(
+// Arrays.asList(2),
+// Arrays.asList(3));
+ }
+
+ @Test(enabled = ! DEBUG, dataProvider = "MyLIBSTest")
+ public void testLIBS(LIBSTest params) {
+ // create the iterator by state with the fake reads and fake records
+ final GATKSAMRecord read = params.makeRead();
+ li = makeLTBS(Arrays.asList((GATKSAMRecord)read), createTestReadProperties());
+ final LIBS_position tester = new LIBS_position(read);
+
+ int bpVisited = 0;
+ int lastOffset = 0;
+ while ( li.hasNext() ) {
+ bpVisited++;
+
+ AlignmentContext alignmentContext = li.next();
+ ReadBackedPileup p = alignmentContext.getBasePileup();
+ Assert.assertEquals(p.getNumberOfElements(), 1);
+ PileupElement pe = p.iterator().next();
+
+ Assert.assertEquals(p.getNumberOfDeletions(), pe.isDeletion() ? 1 : 0, "wrong number of deletions in the pileup");
+ Assert.assertEquals(p.getNumberOfMappingQualityZeroReads(), pe.getRead().getMappingQuality() == 0 ? 1 : 0, "wront number of mapq reads in the pileup");
+
+ tester.stepForwardOnGenome();
+
+ if ( ! hasNeighboringPaddedOps(params.getElements(), pe.getCurrentCigarOffset()) ) {
+ Assert.assertEquals(pe.isBeforeDeletionStart(), tester.isBeforeDeletionStart, "before deletion start failure");
+ Assert.assertEquals(pe.isAfterDeletionEnd(), tester.isAfterDeletionEnd, "after deletion end failure");
+ }
+
+ Assert.assertEquals(pe.isBeforeInsertion(), tester.isBeforeInsertion, "before insertion failure");
+ Assert.assertEquals(pe.isAfterInsertion(), tester.isAfterInsertion, "after insertion failure");
+ Assert.assertEquals(pe.isNextToSoftClip(), tester.isNextToSoftClip, "next to soft clip failure");
+
+ Assert.assertTrue(pe.getOffset() >= lastOffset, "Somehow read offsets are decreasing: lastOffset " + lastOffset + " current " + pe.getOffset());
+ Assert.assertEquals(pe.getOffset(), tester.getCurrentReadOffset(), "Read offsets are wrong at " + bpVisited);
+
+ Assert.assertEquals(pe.getCurrentCigarElement(), read.getCigar().getCigarElement(tester.currentOperatorIndex), "CigarElement index failure");
+ Assert.assertEquals(pe.getOffsetInCurrentCigar(), tester.getCurrentPositionOnOperatorBase0(), "CigarElement index failure");
+
+ Assert.assertEquals(read.getCigar().getCigarElement(pe.getCurrentCigarOffset()), pe.getCurrentCigarElement(), "Current cigar element isn't what we'd get from the read itself");
+
+ Assert.assertTrue(pe.getOffsetInCurrentCigar() >= 0, "Offset into current cigar too small");
+ Assert.assertTrue(pe.getOffsetInCurrentCigar() < pe.getCurrentCigarElement().getLength(), "Offset into current cigar too big");
+
+ Assert.assertEquals(pe.getOffset(), tester.getCurrentReadOffset(), "Read offset failure");
+ lastOffset = pe.getOffset();
+ }
+
+ final int expectedBpToVisit = read.getAlignmentEnd() - read.getAlignmentStart() + 1;
+ Assert.assertEquals(bpVisited, expectedBpToVisit, "Didn't visit the expected number of bp");
+ }
+
+ // ------------------------------------------------------------
+ //
+ // Tests for keeping reads
+ //
+ // ------------------------------------------------------------
+
+ @DataProvider(name = "LIBS_ComplexPileupTests")
+ public Object[][] makeLIBS_ComplexPileupTests() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ for ( final int downsampleTo : Arrays.asList(-1, 1, 2, 5, 10, 30)) {
+ for ( final int nReadsPerLocus : Arrays.asList(1, 10, 60) ) {
+ for ( final int nLoci : Arrays.asList(1, 10, 25) ) {
+ for ( final int nSamples : Arrays.asList(1, 2, 10) ) {
+ for ( final boolean keepReads : Arrays.asList(true, false) ) {
+ for ( final boolean grabReadsAfterEachCycle : Arrays.asList(true, false) ) {
+// for ( final int downsampleTo : Arrays.asList(1)) {
+// for ( final int nReadsPerLocus : Arrays.asList(1) ) {
+// for ( final int nLoci : Arrays.asList(1) ) {
+// for ( final int nSamples : Arrays.asList(1) ) {
+// for ( final boolean keepReads : Arrays.asList(true) ) {
+// for ( final boolean grabReadsAfterEachCycle : Arrays.asList(true) ) {
+ tests.add(new Object[]{nReadsPerLocus, nLoci, nSamples,
+ keepReads, grabReadsAfterEachCycle,
+ downsampleTo});
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "LIBS_ComplexPileupTests")
+ public void testLIBS_ComplexPileupTests(final int nReadsPerLocus,
+ final int nLoci,
+ final int nSamples,
+ final boolean keepReads,
+ final boolean grabReadsAfterEachCycle,
+ final int downsampleTo) {
+ //logger.warn(String.format("testLIBSKeepSubmittedReads %d %d %d %b %b %b", nReadsPerLocus, nLoci, nSamples, keepReads, grabReadsAfterEachCycle, downsample));
+ final int readLength = 10;
+
+ final boolean downsample = downsampleTo != -1;
+ final DownsamplingMethod downsampler = downsample
+ ? new DownsamplingMethod(DownsampleType.BY_SAMPLE, downsampleTo, null)
+ : new DownsamplingMethod(DownsampleType.NONE, null, null);
+
+ final ArtificialBAMBuilder bamBuilder = new ArtificialBAMBuilder(header.getSequenceDictionary(), nReadsPerLocus, nLoci);
+ bamBuilder.createAndSetHeader(nSamples).setReadLength(readLength).setAlignmentStart(1);
+
+ final List<GATKSAMRecord> reads = bamBuilder.makeReads();
+ li = new LocusIteratorByState(new FakeCloseableIterator<GATKSAMRecord>(reads.iterator()),
+ createTestReadProperties(downsampler, keepReads),
+ genomeLocParser,
+ bamBuilder.getSamples());
+
+ final Set<GATKSAMRecord> seenSoFar = new HashSet<GATKSAMRecord>();
+ final Set<GATKSAMRecord> keptReads = new HashSet<GATKSAMRecord>();
+ int bpVisited = 0;
+ while ( li.hasNext() ) {
+ bpVisited++;
+ final AlignmentContext alignmentContext = li.next();
+ final ReadBackedPileup p = alignmentContext.getBasePileup();
+
+ AssertWellOrderedPileup(p);
+
+ if ( downsample ) {
+ // just not a safe test
+ //Assert.assertTrue(p.getNumberOfElements() <= maxDownsampledCoverage * nSamples, "Too many reads at locus after downsampling");
+ } else {
+ final int minPileupSize = nReadsPerLocus * nSamples;
+ Assert.assertTrue(p.getNumberOfElements() >= minPileupSize);
+ }
+
+ // the number of reads starting here
+ int nReadsStartingHere = 0;
+ for ( final GATKSAMRecord read : p.getReads() )
+ if ( read.getAlignmentStart() == alignmentContext.getPosition() )
+ nReadsStartingHere++;
+
+ // we can have no more than maxDownsampledCoverage per sample
+ final int maxCoveragePerLocus = downsample ? downsampleTo : nReadsPerLocus;
+ Assert.assertTrue(nReadsStartingHere <= maxCoveragePerLocus * nSamples);
+
+ seenSoFar.addAll(p.getReads());
+ if ( keepReads && grabReadsAfterEachCycle ) {
+ final List<GATKSAMRecord> locusReads = li.transferReadsFromAllPreviousPileups();
+
+
+ if ( downsample ) {
+ // with downsampling we might have some reads here that were downsampled away
+ // in the pileup. We want to ensure that no more than the max coverage per sample is added
+ Assert.assertTrue(locusReads.size() >= nReadsStartingHere);
+ Assert.assertTrue(locusReads.size() <= maxCoveragePerLocus * nSamples);
+ } else {
+ Assert.assertEquals(locusReads.size(), nReadsStartingHere);
+ }
+ keptReads.addAll(locusReads);
+
+ // check that all reads we've seen so far are in our keptReads
+ for ( final GATKSAMRecord read : seenSoFar ) {
+ Assert.assertTrue(keptReads.contains(read), "A read that appeared in a pileup wasn't found in the kept reads: " + read);
+ }
+ }
+
+ if ( ! keepReads )
+ Assert.assertTrue(li.getReadsFromAllPreviousPileups().isEmpty(), "Not keeping reads but the underlying list of reads isn't empty");
+ }
+
+ if ( keepReads && ! grabReadsAfterEachCycle )
+ keptReads.addAll(li.transferReadsFromAllPreviousPileups());
+
+ if ( ! downsample ) { // downsampling may drop loci
+ final int expectedBpToVisit = nLoci + readLength - 1;
+ Assert.assertEquals(bpVisited, expectedBpToVisit, "Didn't visit the expected number of bp");
+ }
+
+ if ( keepReads ) {
+ // check we have the right number of reads
+ final int totalReads = nLoci * nReadsPerLocus * nSamples;
+ if ( ! downsample ) { // downsampling may drop reads
+ Assert.assertEquals(keptReads.size(), totalReads, "LIBS didn't keep the right number of reads during the traversal");
+
+ // check that the order of reads is the same as in our read list
+ for ( int i = 0; i < reads.size(); i++ ) {
+ final GATKSAMRecord inputRead = reads.get(i);
+ final GATKSAMRecord keptRead = reads.get(i);
+ Assert.assertSame(keptRead, inputRead, "Input reads and kept reads differ at position " + i);
+ }
+ } else {
+ Assert.assertTrue(keptReads.size() <= totalReads, "LIBS didn't keep the right number of reads during the traversal");
+ }
+
+ // check uniqueness
+ final Set<String> readNames = new HashSet<String>();
+ for ( final GATKSAMRecord read : keptReads ) {
+ Assert.assertFalse(readNames.contains(read.getReadName()), "Found duplicate reads in the kept reads");
+ readNames.add(read.getReadName());
+ }
+
+ // check that all reads we've seen are in our keptReads
+ for ( final GATKSAMRecord read : seenSoFar ) {
+ Assert.assertTrue(keptReads.contains(read), "A read that appeared in a pileup wasn't found in the kept reads: " + read);
+ }
+
+ if ( ! downsample ) {
+ // check that every read in the list of keep reads occurred at least once in one of the pileups
+ for ( final GATKSAMRecord keptRead : keptReads ) {
+ Assert.assertTrue(seenSoFar.contains(keptRead), "There's a read " + keptRead + " in our keptReads list that never appeared in any pileup");
+ }
+ }
+ }
+ }
+
+ private void AssertWellOrderedPileup(final ReadBackedPileup pileup) {
+ if ( ! pileup.isEmpty() ) {
+ int leftMostPos = -1;
+
+ for ( final PileupElement pe : pileup ) {
+ Assert.assertTrue(pileup.getLocation().getContig().equals(pe.getRead().getReferenceName()), "ReadBackedPileup contains an element " + pe + " that's on a different contig than the pileup itself");
+ Assert.assertTrue(pe.getRead().getAlignmentStart() >= leftMostPos,
+ "ReadBackedPileup contains an element " + pe + " whose read's alignment start " + pe.getRead().getAlignmentStart()
+ + " occurs before the leftmost position we've seen previously " + leftMostPos);
+ }
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // make sure that downsampling isn't holding onto a bazillion reads
+ //
+ @DataProvider(name = "LIBS_NotHoldingTooManyReads")
+ public Object[][] makeLIBS_NotHoldingTooManyReads() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ for ( final int downsampleTo : Arrays.asList(1, 10)) {
+ for ( final int nReadsPerLocus : Arrays.asList(100, 1000, 10000, 100000) ) {
+ for ( final int payloadInBytes : Arrays.asList(0, 1024, 1024*1024) ) {
+ tests.add(new Object[]{nReadsPerLocus, downsampleTo, payloadInBytes});
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "LIBS_NotHoldingTooManyReads")
+// @Test(enabled = true, dataProvider = "LIBS_NotHoldingTooManyReads", timeOut = 100000)
+ public void testLIBS_NotHoldingTooManyReads(final int nReadsPerLocus, final int downsampleTo, final int payloadInBytes) {
+ logger.warn(String.format("testLIBS_NotHoldingTooManyReads %d %d %d", nReadsPerLocus, downsampleTo, payloadInBytes));
+ final int readLength = 10;
+
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 100000);
+ final int nSamples = 1;
+ final List<String> samples = new ArrayList<String>(nSamples);
+ for ( int i = 0; i < nSamples; i++ ) {
+ final GATKSAMReadGroupRecord rg = new GATKSAMReadGroupRecord("rg" + i);
+ final String sample = "sample" + i;
+ samples.add(sample);
+ rg.setSample(sample);
+ rg.setPlatform(NGSPlatform.ILLUMINA.getDefaultPlatform());
+ header.addReadGroup(rg);
+ }
+
+ final boolean downsample = downsampleTo != -1;
+ final DownsamplingMethod downsampler = downsample
+ ? new DownsamplingMethod(DownsampleType.BY_SAMPLE, downsampleTo, null)
+ : new DownsamplingMethod(DownsampleType.NONE, null, null);
+
+ // final List<GATKSAMRecord> reads = ArtificialSAMUtils.createReadStream(nReadsPerLocus, nLoci, header, 1, readLength);
+
+ final WeakReadTrackingIterator iterator = new WeakReadTrackingIterator(nReadsPerLocus, readLength, payloadInBytes, header);
+
+ li = new LocusIteratorByState(iterator,
+ createTestReadProperties(downsampler, false),
+ genomeLocParser,
+ samples);
+
+ while ( li.hasNext() ) {
+ final AlignmentContext next = li.next();
+ Assert.assertTrue(next.getBasePileup().getNumberOfElements() <= downsampleTo, "Too many elements in pileup " + next);
+ // TODO -- assert that there are <= X reads in memory after GC for some X
+ }
+ }
+
+ private static class WeakReadTrackingIterator implements Iterator<GATKSAMRecord> {
+ final int nReads, readLength, payloadInBytes;
+ int readI = 0;
+ final SAMFileHeader header;
+
+ private WeakReadTrackingIterator(int nReads, int readLength, final int payloadInBytes, final SAMFileHeader header) {
+ this.nReads = nReads;
+ this.readLength = readLength;
+ this.header = header;
+ this.payloadInBytes = payloadInBytes;
+ }
+
+ @Override public boolean hasNext() { return readI < nReads; }
+ @Override public void remove() { throw new UnsupportedOperationException("no remove"); }
+
+ @Override
+ public GATKSAMRecord next() {
+ readI++;
+ return makeRead();
+ }
+
+ private GATKSAMRecord makeRead() {
+ final SAMReadGroupRecord rg = header.getReadGroups().get(0);
+ final String readName = String.format("%s.%d.%s", "read", readI, rg.getId());
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, readName, 0, 1, readLength);
+ read.setReadGroup(new GATKSAMReadGroupRecord(rg));
+ if ( payloadInBytes > 0 )
+ // add a payload byte array to push memory use per read even higher
+ read.setAttribute("PL", new byte[payloadInBytes]);
+ return read;
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ //
+ // make sure that adapter clipping is working properly in LIBS
+ //
+ // ---------------------------------------------------------------------------
+ @DataProvider(name = "AdapterClippingTest")
+ public Object[][] makeAdapterClippingTest() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ final int start = 10;
+ for ( final int goodBases : Arrays.asList(10, 20, 30) ) {
+ for ( final int nClips : Arrays.asList(0, 1, 2, 10)) {
+ for ( final boolean onLeft : Arrays.asList(true, false) ) {
+ final int readLength = nClips + goodBases;
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read1" , 0, start, readLength);
+ read.setProperPairFlag(true);
+ read.setReadPairedFlag(true);
+ read.setReadUnmappedFlag(false);
+ read.setMateUnmappedFlag(false);
+ read.setReadBases(Utils.dupBytes((byte) 'A', readLength));
+ read.setBaseQualities(Utils.dupBytes((byte) '@', readLength));
+ read.setCigarString(readLength + "M");
+
+ if ( onLeft ) {
+ read.setReadNegativeStrandFlag(true);
+ read.setMateNegativeStrandFlag(false);
+ read.setMateAlignmentStart(start + nClips);
+ read.setInferredInsertSize(readLength);
+ tests.add(new Object[]{nClips, goodBases, 0, read});
+ } else {
+ read.setReadNegativeStrandFlag(false);
+ read.setMateNegativeStrandFlag(true);
+ read.setMateAlignmentStart(start - 1);
+ read.setInferredInsertSize(goodBases - 1);
+ tests.add(new Object[]{0, goodBases, nClips, read});
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = true, dataProvider = "AdapterClippingTest")
+ public void testAdapterClipping(final int nClipsOnLeft, final int nReadContainingPileups, final int nClipsOnRight, final GATKSAMRecord read) {
+
+ li = new LocusIteratorByState(new FakeCloseableIterator<>(Collections.singletonList(read).iterator()),
+ createTestReadProperties(DownsamplingMethod.NONE, false),
+ genomeLocParser,
+ LocusIteratorByState.sampleListForSAMWithoutReadGroups());
+
+ int expectedPos = read.getAlignmentStart() + nClipsOnLeft;
+ int nPileups = 0;
+ while ( li.hasNext() ) {
+ final AlignmentContext next = li.next();
+ Assert.assertEquals(next.getLocation().getStart(), expectedPos);
+ nPileups++;
+ expectedPos++;
+ }
+
+ final int nExpectedPileups = nReadContainingPileups;
+ Assert.assertEquals(nPileups, nExpectedPileups, "Wrong number of pileups seen");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/PerSampleReadStateManagerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/PerSampleReadStateManagerUnitTest.java
new file mode 100644
index 0000000..4a760b5
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/locusiterator/PerSampleReadStateManagerUnitTest.java
@@ -0,0 +1,188 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.locusiterator;
+
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.MathUtils;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+/**
+ * testing of the new (non-legacy) version of LocusIteratorByState
+ */
+public class PerSampleReadStateManagerUnitTest extends LocusIteratorByStateBaseTest {
+ private class PerSampleReadStateManagerTest extends TestDataProvider {
+ private List<Integer> readCountsPerAlignmentStart;
+ private List<SAMRecord> reads;
+ private List<ArrayList<AlignmentStateMachine>> recordStatesByAlignmentStart;
+ private int removalInterval;
+
+ public PerSampleReadStateManagerTest( List<Integer> readCountsPerAlignmentStart, int removalInterval ) {
+ super(PerSampleReadStateManagerTest.class);
+
+ this.readCountsPerAlignmentStart = readCountsPerAlignmentStart;
+ this.removalInterval = removalInterval;
+
+ reads = new ArrayList<SAMRecord>();
+ recordStatesByAlignmentStart = new ArrayList<ArrayList<AlignmentStateMachine>>();
+
+ setName(String.format("%s: readCountsPerAlignmentStart: %s removalInterval: %d",
+ getClass().getSimpleName(), readCountsPerAlignmentStart, removalInterval));
+ }
+
+ public void run() {
+ PerSampleReadStateManager perSampleReadStateManager = new PerSampleReadStateManager(LocusIteratorByState.NO_DOWNSAMPLING);
+
+ makeReads();
+
+ for ( ArrayList<AlignmentStateMachine> stackRecordStates : recordStatesByAlignmentStart ) {
+ perSampleReadStateManager.addStatesAtNextAlignmentStart(new LinkedList<AlignmentStateMachine>(stackRecordStates));
+ }
+
+ // read state manager should have the right number of reads
+ Assert.assertEquals(reads.size(), perSampleReadStateManager.size());
+
+ Iterator<SAMRecord> originalReadsIterator = reads.iterator();
+ Iterator<AlignmentStateMachine> recordStateIterator = perSampleReadStateManager.iterator();
+ int recordStateCount = 0;
+ int numReadStatesRemoved = 0;
+
+ // Do a first-pass validation of the record state iteration by making sure we get back everything we
+ // put in, in the same order, doing any requested removals of read states along the way
+ while ( recordStateIterator.hasNext() ) {
+ AlignmentStateMachine readState = recordStateIterator.next();
+ recordStateCount++;
+ SAMRecord readFromPerSampleReadStateManager = readState.getRead();
+
+ Assert.assertTrue(originalReadsIterator.hasNext());
+ SAMRecord originalRead = originalReadsIterator.next();
+
+ // The read we get back should be literally the same read in memory as we put in
+ Assert.assertTrue(originalRead == readFromPerSampleReadStateManager);
+
+ // If requested, remove a read state every removalInterval states
+ if ( removalInterval > 0 && recordStateCount % removalInterval == 0 ) {
+ recordStateIterator.remove();
+ numReadStatesRemoved++;
+ }
+ }
+
+ Assert.assertFalse(originalReadsIterator.hasNext());
+
+ // If we removed any read states, do a second pass through the read states to make sure the right
+ // states were removed
+ if ( numReadStatesRemoved > 0 ) {
+ Assert.assertEquals(perSampleReadStateManager.size(), reads.size() - numReadStatesRemoved);
+
+ originalReadsIterator = reads.iterator();
+ recordStateIterator = perSampleReadStateManager.iterator();
+ int readCount = 0;
+ int readStateCount = 0;
+
+ // Match record states with the reads that should remain after removal
+ while ( recordStateIterator.hasNext() ) {
+ AlignmentStateMachine readState = recordStateIterator.next();
+ readStateCount++;
+ SAMRecord readFromPerSampleReadStateManager = readState.getRead();
+
+ Assert.assertTrue(originalReadsIterator.hasNext());
+
+ SAMRecord originalRead = originalReadsIterator.next();
+ readCount++;
+
+ if ( readCount % removalInterval == 0 ) {
+ originalRead = originalReadsIterator.next(); // advance to next read, since the previous one should have been discarded
+ readCount++;
+ }
+
+ // The read we get back should be literally the same read in memory as we put in (after accounting for removals)
+ Assert.assertTrue(originalRead == readFromPerSampleReadStateManager);
+ }
+
+ Assert.assertEquals(readStateCount, reads.size() - numReadStatesRemoved);
+ }
+
+ // Allow memory used by this test to be reclaimed
+ readCountsPerAlignmentStart = null;
+ reads = null;
+ recordStatesByAlignmentStart = null;
+ }
+
+ private void makeReads() {
+ int alignmentStart = 1;
+
+ for ( int readsThisStack : readCountsPerAlignmentStart ) {
+ ArrayList<GATKSAMRecord> stackReads = new ArrayList<GATKSAMRecord>(ArtificialSAMUtils.createStackOfIdenticalArtificialReads(readsThisStack, header, "foo", 0, alignmentStart, MathUtils.randomIntegerInRange(50, 100)));
+ ArrayList<AlignmentStateMachine> stackRecordStates = new ArrayList<AlignmentStateMachine>();
+
+ for ( GATKSAMRecord read : stackReads ) {
+ stackRecordStates.add(new AlignmentStateMachine(read));
+ }
+
+ reads.addAll(stackReads);
+ recordStatesByAlignmentStart.add(stackRecordStates);
+ }
+ }
+ }
+
+ @DataProvider(name = "PerSampleReadStateManagerTestDataProvider")
+ public Object[][] createPerSampleReadStateManagerTests() {
+ for ( List<Integer> thisTestReadStateCounts : Arrays.asList( Arrays.asList(1),
+ Arrays.asList(2),
+ Arrays.asList(10),
+ Arrays.asList(1, 1),
+ Arrays.asList(2, 2),
+ Arrays.asList(10, 10),
+ Arrays.asList(1, 10),
+ Arrays.asList(10, 1),
+ Arrays.asList(1, 1, 1),
+ Arrays.asList(2, 2, 2),
+ Arrays.asList(10, 10, 10),
+ Arrays.asList(1, 1, 1, 1, 1, 1),
+ Arrays.asList(10, 10, 10, 10, 10, 10),
+ Arrays.asList(1, 2, 10, 1, 2, 10)
+ ) ) {
+
+ for ( int removalInterval : Arrays.asList(0, 2, 3) ) {
+ new PerSampleReadStateManagerTest(thisTestReadStateCounts, removalInterval);
+ }
+ }
+
+ return PerSampleReadStateManagerTest.getTests(PerSampleReadStateManagerTest.class);
+ }
+
+ @Test(dataProvider = "PerSampleReadStateManagerTestDataProvider")
+ public void runPerSampleReadStateManagerTest( PerSampleReadStateManagerTest test ) {
+ logger.warn("Running test: " + test);
+
+ test.run();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/InputProducerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/InputProducerUnitTest.java
new file mode 100644
index 0000000..d99a079
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/InputProducerUnitTest.java
@@ -0,0 +1,94 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+* UnitTests for the InputProducer
+*
+* User: depristo
+* Date: 8/24/12
+* Time: 11:25 AM
+* To change this template use File | Settings | File Templates.
+*/
+public class InputProducerUnitTest extends BaseTest {
+ @DataProvider(name = "InputProducerTest")
+ public Object[][] createInputProducerTest() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final int nElements : Arrays.asList(0, 1, 10, 100, 1000, 10000, 100000) ) {
+ for ( final int queueSize : Arrays.asList(1, 10, 100) ) {
+ tests.add(new Object[]{ nElements, queueSize });
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = true, dataProvider = "InputProducerTest", timeOut = NanoSchedulerUnitTest.NANO_SCHEDULE_MAX_RUNTIME)
+ public void testInputProducer(final int nElements, final int queueSize) throws InterruptedException {
+ final List<Integer> elements = new ArrayList<Integer>(nElements);
+ for ( int i = 0; i < nElements; i++ ) elements.add(i);
+
+ final InputProducer<Integer> ip = new InputProducer<Integer>(elements.iterator());
+
+ Assert.assertFalse(ip.allInputsHaveBeenRead(), "InputProvider said that all inputs have been read, but I haven't started reading yet");
+ Assert.assertEquals(ip.getNumInputValues(), -1, "InputProvider told me that the queue was done, but I haven't started reading yet");
+
+ int lastValue = -1;
+ int nRead = 0;
+ while ( ip.hasNext() ) {
+ final int nTotalElements = ip.getNumInputValues();
+
+ if ( nRead < nElements )
+ Assert.assertEquals(nTotalElements, -1, "getNumInputValues should have returned -1 with not all elements read");
+ // note, cannot test else case because elements input could have emptied between calls
+
+ final InputProducer<Integer>.InputValue value = ip.next();
+ if ( value.isEOFMarker() ) {
+ Assert.assertEquals(nRead, nElements, "Number of input values " + nRead + " not all that are expected " + nElements);
+ break;
+ } else {
+ Assert.assertTrue(lastValue < value.getValue(), "Read values coming out of order!");
+ final int expected = lastValue + 1;
+ Assert.assertEquals((int)value.getValue(), expected, "Value observed " + value.getValue() + " not equal to the expected value " + expected);
+ nRead++;
+ lastValue = value.getValue();
+ }
+ }
+
+ Assert.assertTrue(ip.allInputsHaveBeenRead(), "InputProvider said that all inputs haven't been read, but I read them all");
+ Assert.assertEquals(ip.getNumInputValues(), nElements, "Wrong number of total elements getNumInputValues");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/MapResultUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/MapResultUnitTest.java
new file mode 100644
index 0000000..93105cd
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/MapResultUnitTest.java
@@ -0,0 +1,65 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+* UnitTests for the InputProducer
+*
+* User: depristo
+* Date: 8/24/12
+* Time: 11:25 AM
+* To change this template use File | Settings | File Templates.
+*/
+public class MapResultUnitTest {
+ @DataProvider(name = "CompareTester")
+ public Object[][] createCompareTester() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( int id1 = 0; id1 < 10; id1++ ) {
+ for ( int id2 = 0; id2 < 10; id2++ ) {
+ tests.add(new Object[]{ id1, id2, Integer.valueOf(id1).compareTo(id2)});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = true, dataProvider = "CompareTester")
+ public void testInputProducer(final int id1, final int id2, final int comp ) throws InterruptedException {
+ final MapResult<Integer> mr1 = new MapResult<Integer>(id1, id1);
+ final MapResult<Integer> mr2 = new MapResult<Integer>(id2, id2);
+ Assert.assertEquals(mr1.compareTo(mr2), comp, "Compare MapResultsUnitTest failed");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/NanoSchedulerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/NanoSchedulerUnitTest.java
new file mode 100644
index 0000000..72636f0
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/NanoSchedulerUnitTest.java
@@ -0,0 +1,343 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+import org.apache.log4j.BasicConfigurator;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.SimpleTimer;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.testng.Assert;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * UnitTests for the NanoScheduler
+ *
+ * User: depristo
+ * Date: 8/24/12
+ * Time: 11:25 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class NanoSchedulerUnitTest extends BaseTest {
+ private final static boolean DEBUG = false;
+ private final static boolean debug = false;
+ public static final int NANO_SCHEDULE_MAX_RUNTIME = 30000;
+ public static final int EXCEPTION_THROWING_TEST_TIMEOUT = 10000;
+
+ private static class Map2x implements NSMapFunction<Integer, Integer> {
+ @Override public Integer apply(Integer input) { return input * 2; }
+ }
+
+ private static void maybeDelayMe(final int input) {
+ try {
+ if ( input % 7 == 0 ) {
+ final int milliToSleep = (input % 10);
+ //System.out.printf("Sleeping %d millseconds%n", milliToSleep);
+ Thread.sleep(milliToSleep);
+ }
+ } catch ( InterruptedException ex ) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private static class Map2xWithDelays extends Map2x {
+ @Override public Integer apply(Integer input) {
+ maybeDelayMe(input);
+ return input * 2;
+ }
+ }
+
+ private static class ReduceSum implements NSReduceFunction<Integer, Integer> {
+ int prevOne = Integer.MIN_VALUE;
+
+ @Override public Integer apply(Integer one, Integer sum) {
+ Assert.assertTrue(prevOne < one, "Reduce came in out of order. Prev " + prevOne + " cur " + one);
+ return one + sum;
+ }
+ }
+
+ private static class ProgressCallback implements NSProgressFunction<Integer> {
+ int callBacks = 0;
+
+ @Override
+ public void progress(Integer lastMapInput) {
+ callBacks++;
+ }
+ }
+
+
+ private static int sum2x(final int start, final int end) {
+ int sum = 0;
+ for ( int i = start; i < end; i++ )
+ sum += 2 * i;
+ return sum;
+ }
+
+ private static class NanoSchedulerBasicTest extends TestDataProvider {
+ final int bufferSize, nThreads, start, end, expectedResult;
+ final boolean addDelays;
+
+ public NanoSchedulerBasicTest(final int bufferSize, final int nThreads, final int start, final int end, final boolean addDelays) {
+ super(NanoSchedulerBasicTest.class);
+ this.bufferSize = bufferSize;
+ this.nThreads = nThreads;
+ this.start = start;
+ this.end = end;
+ this.expectedResult = sum2x(start, end);
+ this.addDelays = addDelays;
+ setName(String.format("%s nt=%d buf=%d start=%d end=%d sum=%d delays=%b",
+ getClass().getSimpleName(), nThreads, bufferSize, start, end, expectedResult, addDelays));
+ }
+
+ public Iterator<Integer> makeReader() {
+ final List<Integer> ints = new ArrayList<Integer>();
+ for ( int i = start; i < end; i++ )
+ ints.add(i);
+ return ints.iterator();
+ }
+
+ public int nExpectedCallbacks() {
+ int nElements = Math.max(end - start, 0);
+ return nElements / bufferSize / NanoScheduler.UPDATE_PROGRESS_FREQ;
+ }
+
+ public Map2x makeMap() { return addDelays ? new Map2xWithDelays() : new Map2x(); }
+ public Integer initReduce() { return 0; }
+ public ReduceSum makeReduce() { return new ReduceSum(); }
+
+ public NanoScheduler<Integer, Integer, Integer> makeScheduler() {
+ final NanoScheduler <Integer, Integer, Integer> nano;
+ if ( bufferSize == -1 )
+ nano = new NanoScheduler<Integer, Integer, Integer>(nThreads);
+ else
+ nano = new NanoScheduler<Integer, Integer, Integer>(bufferSize, nThreads);
+
+ nano.setDebug(debug);
+ return nano;
+ }
+ }
+
+ static NanoSchedulerBasicTest exampleTest = null;
+ static NanoSchedulerBasicTest exampleTestWithDelays = null;
+
+ @BeforeSuite
+ public void setUp() throws Exception {
+ exampleTest = new NanoSchedulerBasicTest(10, 2, 1, 10, false);
+ exampleTestWithDelays = new NanoSchedulerBasicTest(10, 2, 1, 10, true);
+ }
+
+ @DataProvider(name = "NanoSchedulerBasicTest")
+ public Object[][] createNanoSchedulerBasicTest() {
+// for ( final int bufferSize : Arrays.asList(1, 10) ) {
+// for ( final int nt : Arrays.asList(1, 2, 4) ) {
+// for ( final int start : Arrays.asList(0) ) {
+// for ( final int end : Arrays.asList(0, 1, 2) ) {
+// exampleTest = new NanoSchedulerBasicTest(bufferSize, nt, start, end, false);
+// }
+// }
+// }
+// }
+
+ for ( final int bufferSize : Arrays.asList(-1, 1, 10, 100) ) {
+ for ( final int nt : Arrays.asList(1, 2, 4) ) {
+ for ( final int start : Arrays.asList(0) ) {
+ for ( final int end : Arrays.asList(0, 1, 2, 11, 100, 10000, 100000) ) {
+ for ( final boolean addDelays : Arrays.asList(true, false) ) {
+ if ( end < 1000 )
+ new NanoSchedulerBasicTest(bufferSize, nt, start, end, addDelays);
+ }
+ }
+ }
+ }
+ }
+
+ return NanoSchedulerBasicTest.getTests(NanoSchedulerBasicTest.class);
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "NanoSchedulerBasicTest", timeOut = NANO_SCHEDULE_MAX_RUNTIME)
+ public void testSingleThreadedNanoScheduler(final NanoSchedulerBasicTest test) throws InterruptedException {
+ logger.warn("Running " + test);
+ if ( test.nThreads == 1 )
+ testNanoScheduler(test);
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "NanoSchedulerBasicTest", timeOut = NANO_SCHEDULE_MAX_RUNTIME, dependsOnMethods = "testSingleThreadedNanoScheduler")
+ public void testMultiThreadedNanoScheduler(final NanoSchedulerBasicTest test) throws InterruptedException {
+ logger.warn("Running " + test);
+ if ( test.nThreads >= 1 )
+ testNanoScheduler(test);
+ }
+
+ private void testNanoScheduler(final NanoSchedulerBasicTest test) throws InterruptedException {
+ final SimpleTimer timer = new SimpleTimer().start();
+ final NanoScheduler<Integer, Integer, Integer> nanoScheduler = test.makeScheduler();
+
+ final ProgressCallback callback = new ProgressCallback();
+ nanoScheduler.setProgressFunction(callback);
+
+ if ( test.bufferSize > -1 )
+ Assert.assertEquals(nanoScheduler.getBufferSize(), test.bufferSize, "bufferSize argument");
+ Assert.assertEquals(nanoScheduler.getnThreads(), test.nThreads, "nThreads argument");
+
+ final Integer sum = nanoScheduler.execute(test.makeReader(), test.makeMap(), test.initReduce(), test.makeReduce());
+ Assert.assertNotNull(sum);
+ Assert.assertEquals((int)sum, test.expectedResult, "NanoScheduler sum not the same as calculated directly");
+
+ Assert.assertTrue(callback.callBacks >= test.nExpectedCallbacks(), "Not enough callbacks detected. Expected at least " + test.nExpectedCallbacks() + " but saw only " + callback.callBacks);
+ nanoScheduler.shutdown();
+ }
+
+ @Test(enabled = true && ! DEBUG, dataProvider = "NanoSchedulerBasicTest", dependsOnMethods = "testMultiThreadedNanoScheduler", timeOut = 2 * NANO_SCHEDULE_MAX_RUNTIME)
+ public void testNanoSchedulerInLoop(final NanoSchedulerBasicTest test) throws InterruptedException {
+ if ( test.bufferSize > 1) {
+ logger.warn("Running " + test);
+
+ final NanoScheduler<Integer, Integer, Integer> nanoScheduler = test.makeScheduler();
+
+ // test reusing the scheduler
+ for ( int i = 0; i < 10; i++ ) {
+ final Integer sum = nanoScheduler.execute(test.makeReader(), test.makeMap(), test.initReduce(), test.makeReduce());
+ Assert.assertNotNull(sum);
+ Assert.assertEquals((int)sum, test.expectedResult, "NanoScheduler sum not the same as calculated directly");
+ }
+
+ nanoScheduler.shutdown();
+ }
+ }
+
+ @Test(enabled = true && ! DEBUG, timeOut = NANO_SCHEDULE_MAX_RUNTIME)
+ public void testShutdown() throws InterruptedException {
+ final NanoScheduler<Integer, Integer, Integer> nanoScheduler = new NanoScheduler<Integer, Integer, Integer>(1, 2);
+ Assert.assertFalse(nanoScheduler.isShutdown(), "scheduler should be alive");
+ nanoScheduler.shutdown();
+ Assert.assertTrue(nanoScheduler.isShutdown(), "scheduler should be dead");
+ }
+
+ @Test(enabled = true && ! DEBUG, expectedExceptions = IllegalStateException.class, timeOut = NANO_SCHEDULE_MAX_RUNTIME)
+ public void testShutdownExecuteFailure() throws InterruptedException {
+ final NanoScheduler<Integer, Integer, Integer> nanoScheduler = new NanoScheduler<Integer, Integer, Integer>(1, 2);
+ nanoScheduler.shutdown();
+ nanoScheduler.execute(exampleTest.makeReader(), exampleTest.makeMap(), exampleTest.initReduce(), exampleTest.makeReduce());
+ }
+
+ @DataProvider(name = "NanoSchedulerInputExceptionTest")
+ public Object[][] createNanoSchedulerInputExceptionTest() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+
+ for ( final int bufSize : Arrays.asList(100) ) {
+ for ( final int nThreads : Arrays.asList(8) ) {
+ for ( final boolean addDelays : Arrays.asList(true, false) ) {
+ final NanoSchedulerBasicTest test = new NanoSchedulerBasicTest(bufSize, nThreads, 1, 1000000, false);
+ final int maxN = addDelays ? 1000 : 10000;
+ for ( int nElementsBeforeError = 0; nElementsBeforeError < maxN; nElementsBeforeError += Math.max(nElementsBeforeError / 10, 1) ) {
+ tests.add(new Object[]{nElementsBeforeError, test, addDelays});
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = true, expectedExceptions = NullPointerException.class, timeOut = EXCEPTION_THROWING_TEST_TIMEOUT)
+ public void testInputErrorIsThrown_NPE() throws InterruptedException {
+ executeTestErrorThrowingInput(10, new NullPointerException(), exampleTest, false);
+ }
+
+ @Test(enabled = true, expectedExceptions = ReviewedGATKException.class, timeOut = EXCEPTION_THROWING_TEST_TIMEOUT)
+ public void testInputErrorIsThrown_RSE() throws InterruptedException {
+ executeTestErrorThrowingInput(10, new ReviewedGATKException("test"), exampleTest, false);
+ }
+
+ @Test(enabled = true, expectedExceptions = NullPointerException.class, dataProvider = "NanoSchedulerInputExceptionTest", timeOut = EXCEPTION_THROWING_TEST_TIMEOUT, invocationCount = 1)
+ public void testInputRuntimeExceptionDoesntDeadlock(final int nElementsBeforeError, final NanoSchedulerBasicTest test, final boolean addDelays ) throws InterruptedException {
+ executeTestErrorThrowingInput(nElementsBeforeError, new NullPointerException(), test, addDelays);
+ }
+
+ @Test(enabled = true, expectedExceptions = ReviewedGATKException.class, dataProvider = "NanoSchedulerInputExceptionTest", timeOut = EXCEPTION_THROWING_TEST_TIMEOUT, invocationCount = 1)
+ public void testInputErrorDoesntDeadlock(final int nElementsBeforeError, final NanoSchedulerBasicTest test, final boolean addDelays ) throws InterruptedException {
+ executeTestErrorThrowingInput(nElementsBeforeError, new Error(), test, addDelays);
+ }
+
+ private void executeTestErrorThrowingInput(final int nElementsBeforeError, final Throwable ex, final NanoSchedulerBasicTest test, final boolean addDelays) {
+ logger.warn("executeTestErrorThrowingInput " + nElementsBeforeError + " ex=" + ex + " test=" + test + " addInputDelays=" + addDelays);
+ final NanoScheduler<Integer, Integer, Integer> nanoScheduler = test.makeScheduler();
+ nanoScheduler.execute(new ErrorThrowingIterator(nElementsBeforeError, ex, addDelays), test.makeMap(), test.initReduce(), test.makeReduce());
+ }
+
+ private static class ErrorThrowingIterator implements Iterator<Integer> {
+ final int nElementsBeforeError;
+ final boolean addDelays;
+ int i = 0;
+ final Throwable ex;
+
+ private ErrorThrowingIterator(final int nElementsBeforeError, Throwable ex, boolean addDelays) {
+ this.nElementsBeforeError = nElementsBeforeError;
+ this.ex = ex;
+ this.addDelays = addDelays;
+ }
+
+ @Override public boolean hasNext() { return true; }
+ @Override public Integer next() {
+ if ( i++ > nElementsBeforeError ) {
+ if ( ex instanceof Error )
+ throw (Error)ex;
+ else if ( ex instanceof RuntimeException )
+ throw (RuntimeException)ex;
+ else
+ throw new RuntimeException("Bad exception " + ex);
+ } else if ( addDelays ) {
+ maybeDelayMe(i);
+ return i;
+ } else {
+ return i;
+ }
+ }
+ @Override public void remove() { throw new UnsupportedOperationException("x"); }
+ }
+
+ public static void main(String [ ] args) {
+ org.apache.log4j.Logger logger = org.apache.log4j.Logger.getRootLogger();
+ BasicConfigurator.configure();
+ logger.setLevel(org.apache.log4j.Level.DEBUG);
+
+ final NanoSchedulerBasicTest test = new NanoSchedulerBasicTest(1000, Integer.valueOf(args[0]), 0, Integer.valueOf(args[1]), false);
+ final NanoScheduler<Integer, Integer, Integer> nanoScheduler =
+ new NanoScheduler<Integer, Integer, Integer>(test.bufferSize, test.nThreads);
+ nanoScheduler.setDebug(true);
+
+ final Integer sum = nanoScheduler.execute(test.makeReader(), test.makeMap(), test.initReduce(), test.makeReduce());
+ System.out.printf("Sum = %d, expected =%d%n", sum, test.expectedResult);
+ nanoScheduler.shutdown();
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/ReducerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/ReducerUnitTest.java
new file mode 100644
index 0000000..987d13f
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/nanoScheduler/ReducerUnitTest.java
@@ -0,0 +1,236 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.nanoScheduler;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.MultiThreadedErrorTracker;
+import org.broadinstitute.gatk.utils.Utils;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * UnitTests for Reducer
+ *
+ * User: depristo
+ * Date: 8/24/12
+ * Time: 11:25 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ReducerUnitTest extends BaseTest {
+ @DataProvider(name = "ReducerThreadTest")
+ public Object[][] createReducerThreadTest() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final int groupSize : Arrays.asList(-1, 1, 5, 50, 500, 5000, 50000) ) {
+ for ( final int nElements : Arrays.asList(0, 1, 3, 5) ) {
+ if ( groupSize < nElements ) {
+ for ( final List<MapResult<Integer>> jobs : Utils.makePermutations(makeJobs(nElements), nElements, false) ) {
+ tests.add(new Object[]{ new ListOfJobs(jobs), groupSize });
+ }
+ }
+ }
+
+ for ( final int nElements : Arrays.asList(10, 100, 1000, 10000, 100000, 1000000) ) {
+ if ( groupSize < nElements ) {
+ tests.add(new Object[]{ new ListOfJobs(makeJobs(nElements)), groupSize });
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ private static class ListOfJobs extends ArrayList<MapResult<Integer>> {
+ private ListOfJobs(Collection<? extends MapResult<Integer>> c) {
+ super(c);
+ }
+
+ @Override
+ public String toString() {
+ if ( size() < 10 )
+ return super.toString();
+ else
+ return "JobList of " + size();
+ }
+ }
+
+ private static List<MapResult<Integer>> makeJobs(final int nElements) {
+ List<MapResult<Integer>> jobs = new ArrayList<MapResult<Integer>>(nElements);
+ for ( int i = 0; i < nElements; i++ ) {
+ jobs.add(new MapResult<Integer>(i, i));
+ }
+ return jobs;
+ }
+
+ private int expectedSum(final List<MapResult<Integer>> jobs) {
+ int sum = 0;
+ for ( final MapResult<Integer> job : jobs )
+ sum += job.getValue();
+ return sum;
+ }
+
+ @Test(enabled = true, dataProvider = "ReducerThreadTest", timeOut = NanoSchedulerUnitTest.NANO_SCHEDULE_MAX_RUNTIME)
+ public void testReducerThread(final List<MapResult<Integer>> allJobs, int groupSize) throws Exception {
+ if ( groupSize == -1 )
+ groupSize = allJobs.size();
+
+ final MapResultsQueue<Integer> mapResultsQueue = new MapResultsQueue<Integer>();
+
+ final List<List<MapResult<Integer>>> jobGroups = Utils.groupList(allJobs, groupSize);
+ final ReduceSumTest reduce = new ReduceSumTest();
+ final Reducer<Integer, Integer> reducer = new Reducer<Integer, Integer>(reduce, new MultiThreadedErrorTracker(), 0);
+
+ final TestWaitingForFinalReduce waitingThread = new TestWaitingForFinalReduce(reducer, expectedSum(allJobs));
+ final ExecutorService es = Executors.newSingleThreadExecutor();
+ es.submit(waitingThread);
+
+ int lastJobID = -1;
+ int nJobsSubmitted = 0;
+ int jobGroupCount = 0;
+ final int lastJobGroupCount = jobGroups.size() - 1;
+
+ for ( final List<MapResult<Integer>> jobs : jobGroups ) {
+ //logger.warn("Processing job group " + jobGroupCount + " with " + jobs.size() + " jobs");
+ for ( final MapResult<Integer> job : jobs ) {
+ lastJobID = Math.max(lastJobID, job.getJobID());
+ mapResultsQueue.put(job);
+ nJobsSubmitted++;
+ }
+
+ if ( jobGroupCount == lastJobGroupCount ) {
+ mapResultsQueue.put(new MapResult<Integer>(lastJobID+1));
+ nJobsSubmitted++;
+ }
+
+ final int nReduced = reducer.reduceAsMuchAsPossible(mapResultsQueue, true);
+ Assert.assertTrue(nReduced <= nJobsSubmitted, "Somehow reduced more jobs than submitted");
+
+ jobGroupCount++;
+ }
+
+ Assert.assertEquals(reduce.nRead, allJobs.size(), "number of read values not all of the values in the reducer queue");
+ es.shutdown();
+ es.awaitTermination(1, TimeUnit.HOURS);
+ }
+
+ @Test(timeOut = 1000, invocationCount = 100)
+ private void testNonBlockingReduce() throws Exception {
+ final Reducer<Integer, Integer> reducer = new Reducer<Integer, Integer>(new ReduceSumTest(), new MultiThreadedErrorTracker(), 0);
+ final MapResultsQueue<Integer> mapResultsQueue = new MapResultsQueue<Integer>();
+ mapResultsQueue.put(new MapResult<Integer>(0, 0));
+ mapResultsQueue.put(new MapResult<Integer>(1, 1));
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ExecutorService es = Executors.newSingleThreadExecutor();
+
+ es.submit(new Runnable() {
+ @Override
+ public void run() {
+ reducer.acquireReduceLock(true);
+ latch.countDown();
+ }
+ });
+
+ latch.await();
+ final int nReduced = reducer.reduceAsMuchAsPossible(mapResultsQueue, false);
+ Assert.assertEquals(nReduced, 0, "The reducer lock was already held but we did some work");
+ es.shutdown();
+ es.awaitTermination(1, TimeUnit.HOURS);
+ }
+
+ @Test(timeOut = 10000, invocationCount = 100)
+ private void testBlockingReduce() throws Exception {
+ final Reducer<Integer, Integer> reducer = new Reducer<Integer, Integer>(new ReduceSumTest(), new MultiThreadedErrorTracker(), 0);
+ final MapResultsQueue<Integer> mapResultsQueue = new MapResultsQueue<Integer>();
+ mapResultsQueue.put(new MapResult<Integer>(0, 0));
+ mapResultsQueue.put(new MapResult<Integer>(1, 1));
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ final ExecutorService es = Executors.newSingleThreadExecutor();
+
+ es.submit(new Runnable() {
+ @Override
+ public void run() {
+ reducer.acquireReduceLock(true);
+ latch.countDown();
+ try {
+ Thread.sleep(100);
+ } catch ( InterruptedException e ) {
+ ;
+ } finally {
+ reducer.releaseReduceLock();
+ }
+ }
+ });
+
+ latch.await();
+ final int nReduced = reducer.reduceAsMuchAsPossible(mapResultsQueue, true);
+ Assert.assertEquals(nReduced, 2, "The reducer should have blocked until the lock was freed and reduced 2 values");
+ es.shutdown();
+ es.awaitTermination(1, TimeUnit.HOURS);
+ }
+
+
+ public class ReduceSumTest implements NSReduceFunction<Integer, Integer> {
+ int nRead = 0;
+ int lastValue = -1;
+
+ @Override public Integer apply(Integer one, Integer sum) {
+ Assert.assertTrue(lastValue < one, "Reduce came in out of order. Prev " + lastValue + " cur " + one);
+
+ Assert.assertTrue(lastValue < one, "Read values coming out of order!");
+ final int expected = lastValue + 1;
+ Assert.assertEquals((int)one, expected, "Value observed " + one + " not equal to the expected value " + expected);
+ nRead++;
+ lastValue = expected;
+
+ return one + sum;
+ }
+ }
+
+ final static class TestWaitingForFinalReduce implements Runnable {
+ final Reducer<Integer, Integer> reducer;
+ final int expectedSum;
+
+ TestWaitingForFinalReduce(Reducer<Integer, Integer> reducer, final int expectedSum) {
+ this.reducer = reducer;
+ this.expectedSum = expectedSum;
+ }
+
+ @Override
+ public void run() {
+ final int observedSum = reducer.getReduceResult();
+ Assert.assertEquals(observedSum, expectedSum, "Reduce didn't sum to expected value");
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/pileup/PileupElementUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/pileup/PileupElementUnitTest.java
new file mode 100644
index 0000000..90d235f
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/pileup/PileupElementUnitTest.java
@@ -0,0 +1,189 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pileup;
+
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.CigarOperator;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.locusiterator.AlignmentStateMachine;
+import org.broadinstitute.gatk.utils.locusiterator.LIBS_position;
+import org.broadinstitute.gatk.utils.locusiterator.LocusIteratorByStateBaseTest;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * testing of the new (non-legacy) version of LocusIteratorByState
+ */
+public class PileupElementUnitTest extends LocusIteratorByStateBaseTest {
+ @DataProvider(name = "PileupElementTest")
+ public Object[][] makePileupElementTest() {
+// return new Object[][]{{new LIBSTest("2X2D2P2X")}};
+// return createLIBSTests(
+// Arrays.asList(2),
+// Arrays.asList(2));
+ return createLIBSTests(
+ Arrays.asList(1, 2),
+ Arrays.asList(1, 2, 3, 4));
+ }
+
+ @Test(dataProvider = "PileupElementTest")
+ public void testPileupElementTest(LIBSTest params) {
+ final GATKSAMRecord read = params.makeRead();
+ final AlignmentStateMachine state = new AlignmentStateMachine(read);
+ final LIBS_position tester = new LIBS_position(read);
+
+ while ( state.stepForwardOnGenome() != null ) {
+ tester.stepForwardOnGenome();
+ final PileupElement pe = state.makePileupElement();
+
+ Assert.assertEquals(pe.getRead(), read);
+ Assert.assertEquals(pe.getMappingQual(), read.getMappingQuality());
+ Assert.assertEquals(pe.getOffset(), state.getReadOffset());
+
+ Assert.assertEquals(pe.isDeletion(), state.getCigarOperator() == CigarOperator.D);
+ Assert.assertEquals(pe.isAfterInsertion(), tester.isAfterInsertion);
+ Assert.assertEquals(pe.isBeforeInsertion(), tester.isBeforeInsertion);
+ Assert.assertEquals(pe.isNextToSoftClip(), tester.isNextToSoftClip);
+
+ if ( ! hasNeighboringPaddedOps(params.getElements(), pe.getCurrentCigarOffset()) ) {
+ Assert.assertEquals(pe.isAfterDeletionEnd(), tester.isAfterDeletionEnd);
+ Assert.assertEquals(pe.isBeforeDeletionStart(), tester.isBeforeDeletionStart);
+ }
+
+
+
+ Assert.assertEquals(pe.atEndOfCurrentCigar(), state.getOffsetIntoCurrentCigarElement() == state.getCurrentCigarElement().getLength() - 1, "atEndOfCurrentCigar failed");
+ Assert.assertEquals(pe.atStartOfCurrentCigar(), state.getOffsetIntoCurrentCigarElement() == 0, "atStartOfCurrentCigar failed");
+
+ Assert.assertEquals(pe.getBase(), pe.isDeletion() ? PileupElement.DELETION_BASE : read.getReadBases()[state.getReadOffset()]);
+ Assert.assertEquals(pe.getQual(), pe.isDeletion() ? PileupElement.DELETION_QUAL : read.getBaseQualities()[state.getReadOffset()]);
+
+ Assert.assertEquals(pe.getCurrentCigarElement(), state.getCurrentCigarElement());
+ Assert.assertEquals(pe.getCurrentCigarOffset(), state.getCurrentCigarElementOffset());
+
+ // tested in libs
+ //pe.getLengthOfImmediatelyFollowingIndel();
+ //pe.getBasesOfImmediatelyFollowingInsertion();
+
+ // Don't test -- pe.getBaseIndex();
+ if ( pe.atEndOfCurrentCigar() && state.getCurrentCigarElementOffset() < read.getCigarLength() - 1 ) {
+ final CigarElement nextElement = read.getCigar().getCigarElement(state.getCurrentCigarElementOffset() + 1);
+ if ( nextElement.getOperator() == CigarOperator.I ) {
+ Assert.assertTrue(pe.getBetweenNextPosition().size() >= 1);
+ Assert.assertEquals(pe.getBetweenNextPosition().get(0), nextElement);
+ }
+ if ( nextElement.getOperator() == CigarOperator.M ) {
+ Assert.assertTrue(pe.getBetweenNextPosition().isEmpty());
+ }
+ } else {
+ Assert.assertTrue(pe.getBetweenNextPosition().isEmpty());
+ }
+
+ if ( pe.atStartOfCurrentCigar() && state.getCurrentCigarElementOffset() > 0 ) {
+ final CigarElement prevElement = read.getCigar().getCigarElement(state.getCurrentCigarElementOffset() - 1);
+ if ( prevElement.getOperator() == CigarOperator.I ) {
+ Assert.assertTrue(pe.getBetweenPrevPosition().size() >= 1);
+ Assert.assertEquals(pe.getBetweenPrevPosition().getLast(), prevElement);
+ }
+ if ( prevElement.getOperator() == CigarOperator.M ) {
+ Assert.assertTrue(pe.getBetweenPrevPosition().isEmpty());
+ }
+ } else {
+ Assert.assertTrue(pe.getBetweenPrevPosition().isEmpty());
+ }
+
+ // TODO -- add meaningful tests
+ pe.getBaseInsertionQual();
+ pe.getBaseDeletionQual();
+ }
+ }
+
+
+ @DataProvider(name = "PrevAndNextTest")
+ public Object[][] makePrevAndNextTest() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ final List<CigarOperator> operators = Arrays.asList(CigarOperator.I, CigarOperator.P, CigarOperator.S);
+
+ for ( final CigarOperator firstOp : Arrays.asList(CigarOperator.M) ) {
+ for ( final CigarOperator lastOp : Arrays.asList(CigarOperator.M, CigarOperator.D) ) {
+ for ( final int nIntermediate : Arrays.asList(1, 2, 3) ) {
+ for ( final List<CigarOperator> combination : Utils.makePermutations(operators, nIntermediate, false) ) {
+ final int readLength = 2 + combination.size();
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read", 0, 1, readLength);
+ read.setReadBases(Utils.dupBytes((byte) 'A', readLength));
+ read.setBaseQualities(Utils.dupBytes((byte) 30, readLength));
+
+ String cigar = "1" + firstOp;
+ for ( final CigarOperator op : combination ) cigar += "1" + op;
+ cigar += "1" + lastOp;
+ read.setCigarString(cigar);
+
+ tests.add(new Object[]{read, firstOp, lastOp, combination});
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "PrevAndNextTest")
+ public void testPrevAndNextTest(final GATKSAMRecord read, final CigarOperator firstOp, final CigarOperator lastOp, final List<CigarOperator> ops) {
+ final AlignmentStateMachine state = new AlignmentStateMachine(read);
+
+ state.stepForwardOnGenome();
+ final PileupElement pe = state.makePileupElement();
+ Assert.assertEquals(pe.getBetweenNextPosition().size(), ops.size());
+ Assert.assertEquals(pe.getBetweenPrevPosition().size(), 0);
+ assertEqualsOperators(pe.getBetweenNextPosition(), ops);
+ Assert.assertEquals(pe.getPreviousOnGenomeCigarElement(), null);
+ Assert.assertNotNull(pe.getNextOnGenomeCigarElement());
+ Assert.assertEquals(pe.getNextOnGenomeCigarElement().getOperator(), lastOp);
+
+ state.stepForwardOnGenome();
+ final PileupElement pe2 = state.makePileupElement();
+ Assert.assertEquals(pe2.getBetweenPrevPosition().size(), ops.size());
+ Assert.assertEquals(pe2.getBetweenNextPosition().size(), 0);
+ assertEqualsOperators(pe2.getBetweenPrevPosition(), ops);
+ Assert.assertNotNull(pe2.getPreviousOnGenomeCigarElement());
+ Assert.assertEquals(pe2.getPreviousOnGenomeCigarElement().getOperator(), firstOp);
+ Assert.assertEquals(pe2.getNextOnGenomeCigarElement(), null);
+ }
+
+ private void assertEqualsOperators(final List<CigarElement> elements, final List<CigarOperator> ops) {
+ for ( int i = 0; i < elements.size(); i++ ) {
+ Assert.assertEquals(elements.get(i).getOperator(), ops.get(i), "elements doesn't have expected operator at position " + i);
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/pileup/ReadBackedPileupUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/pileup/ReadBackedPileupUnitTest.java
new file mode 100644
index 0000000..9b3b3b8
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/pileup/ReadBackedPileupUnitTest.java
@@ -0,0 +1,328 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.pileup;
+
+import htsjdk.samtools.CigarElement;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.utils.GenomeLoc;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.sam.GATKSAMRecord;
+import org.testng.Assert;
+import org.broadinstitute.gatk.utils.sam.ArtificialSAMUtils;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+/**
+ * Test routines for read-backed pileup.
+ */
+public class ReadBackedPileupUnitTest {
+ protected static SAMFileHeader header;
+ protected GenomeLocParser genomeLocParser;
+ private GenomeLoc loc;
+
+ @BeforeClass
+ public void beforeClass() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000);
+ genomeLocParser = new GenomeLocParser(header.getSequenceDictionary());
+ loc = genomeLocParser.createGenomeLoc("chr1", 1);
+ }
+
+ /**
+ * Ensure that basic read group splitting works.
+ */
+ @Test
+ public void testSplitByReadGroup() {
+ SAMReadGroupRecord readGroupOne = new SAMReadGroupRecord("rg1");
+ SAMReadGroupRecord readGroupTwo = new SAMReadGroupRecord("rg2");
+
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1,1,1000);
+ header.addReadGroup(readGroupOne);
+ header.addReadGroup(readGroupTwo);
+
+ GATKSAMRecord read1 = ArtificialSAMUtils.createArtificialRead(header,"read1",0,1,10);
+ read1.setAttribute("RG",readGroupOne.getId());
+ GATKSAMRecord read2 = ArtificialSAMUtils.createArtificialRead(header,"read2",0,1,10);
+ read2.setAttribute("RG",readGroupTwo.getId());
+ GATKSAMRecord read3 = ArtificialSAMUtils.createArtificialRead(header,"read3",0,1,10);
+ read3.setAttribute("RG",readGroupOne.getId());
+ GATKSAMRecord read4 = ArtificialSAMUtils.createArtificialRead(header,"read4",0,1,10);
+ read4.setAttribute("RG",readGroupTwo.getId());
+ GATKSAMRecord read5 = ArtificialSAMUtils.createArtificialRead(header,"read5",0,1,10);
+ read5.setAttribute("RG",readGroupTwo.getId());
+ GATKSAMRecord read6 = ArtificialSAMUtils.createArtificialRead(header,"read6",0,1,10);
+ read6.setAttribute("RG",readGroupOne.getId());
+ GATKSAMRecord read7 = ArtificialSAMUtils.createArtificialRead(header,"read7",0,1,10);
+ read7.setAttribute("RG",readGroupOne.getId());
+
+ ReadBackedPileup pileup = new ReadBackedPileupImpl(null, Arrays.asList(read1,read2,read3,read4,read5,read6,read7), Arrays.asList(1,1,1,1,1,1,1));
+
+ ReadBackedPileup rg1Pileup = pileup.getPileupForReadGroup("rg1");
+ List<GATKSAMRecord> rg1Reads = rg1Pileup.getReads();
+ Assert.assertEquals(rg1Reads.size(), 4, "Wrong number of reads in read group rg1");
+ Assert.assertEquals(rg1Reads.get(0), read1, "Read " + read1.getReadName() + " should be in rg1 but isn't");
+ Assert.assertEquals(rg1Reads.get(1), read3, "Read " + read3.getReadName() + " should be in rg1 but isn't");
+ Assert.assertEquals(rg1Reads.get(2), read6, "Read " + read6.getReadName() + " should be in rg1 but isn't");
+ Assert.assertEquals(rg1Reads.get(3), read7, "Read " + read7.getReadName() + " should be in rg1 but isn't");
+
+ ReadBackedPileup rg2Pileup = pileup.getPileupForReadGroup("rg2");
+ List<GATKSAMRecord> rg2Reads = rg2Pileup.getReads();
+ Assert.assertEquals(rg2Reads.size(), 3, "Wrong number of reads in read group rg2");
+ Assert.assertEquals(rg2Reads.get(0), read2, "Read " + read2.getReadName() + " should be in rg2 but isn't");
+ Assert.assertEquals(rg2Reads.get(1), read4, "Read " + read4.getReadName() + " should be in rg2 but isn't");
+ Assert.assertEquals(rg2Reads.get(2), read5, "Read " + read5.getReadName() + " should be in rg2 but isn't");
+ }
+
+ /**
+ * Ensure that splitting read groups still works when dealing with null read groups.
+ */
+ @Test
+ public void testSplitByNullReadGroups() {
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1,1,1000);
+
+ GATKSAMRecord read1 = ArtificialSAMUtils.createArtificialRead(header,"read1",0,1,10);
+ GATKSAMRecord read2 = ArtificialSAMUtils.createArtificialRead(header,"read2",0,1,10);
+ GATKSAMRecord read3 = ArtificialSAMUtils.createArtificialRead(header,"read3",0,1,10);
+
+ ReadBackedPileup pileup = new ReadBackedPileupImpl(null,
+ Arrays.asList(read1,read2,read3),
+ Arrays.asList(1,1,1));
+
+ ReadBackedPileup nullRgPileup = pileup.getPileupForReadGroup(null);
+ List<GATKSAMRecord> nullRgReads = nullRgPileup.getReads();
+ Assert.assertEquals(nullRgPileup.getNumberOfElements(), 3, "Wrong number of reads in null read group");
+ Assert.assertEquals(nullRgReads.get(0), read1, "Read " + read1.getReadName() + " should be in null rg but isn't");
+ Assert.assertEquals(nullRgReads.get(1), read2, "Read " + read2.getReadName() + " should be in null rg but isn't");
+ Assert.assertEquals(nullRgReads.get(2), read3, "Read " + read3.getReadName() + " should be in null rg but isn't");
+
+ ReadBackedPileup rg1Pileup = pileup.getPileupForReadGroup("rg1");
+ Assert.assertNull(rg1Pileup, "Pileup for non-existent read group should return null");
+ }
+
+ /**
+ * Ensure that splitting read groups still works when dealing with a sample-split pileup.
+ */
+ @Test
+ public void testSplitBySample() {
+ SAMReadGroupRecord readGroupOne = new SAMReadGroupRecord("rg1");
+ readGroupOne.setSample("sample1");
+ SAMReadGroupRecord readGroupTwo = new SAMReadGroupRecord("rg2");
+ readGroupTwo.setSample("sample2");
+
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1,1,1000);
+ header.addReadGroup(readGroupOne);
+ header.addReadGroup(readGroupTwo);
+
+ GATKSAMRecord read1 = ArtificialSAMUtils.createArtificialRead(header,"read1",0,1,10);
+ read1.setAttribute("RG",readGroupOne.getId());
+ GATKSAMRecord read2 = ArtificialSAMUtils.createArtificialRead(header,"read2",0,1,10);
+ read2.setAttribute("RG",readGroupTwo.getId());
+ GATKSAMRecord read3 = ArtificialSAMUtils.createArtificialRead(header,"read3",0,1,10);
+ read3.setAttribute("RG",readGroupOne.getId());
+ GATKSAMRecord read4 = ArtificialSAMUtils.createArtificialRead(header,"read4",0,1,10);
+ read4.setAttribute("RG",readGroupTwo.getId());
+
+ ReadBackedPileupImpl sample1Pileup = new ReadBackedPileupImpl(null,
+ Arrays.asList(read1,read3),
+ Arrays.asList(1,1));
+ ReadBackedPileupImpl sample2Pileup = new ReadBackedPileupImpl(null,
+ Arrays.asList(read2,read4),
+ Arrays.asList(1,1));
+ Map<String,ReadBackedPileupImpl> sampleToPileupMap = new HashMap<String,ReadBackedPileupImpl>();
+ sampleToPileupMap.put(readGroupOne.getSample(),sample1Pileup);
+ sampleToPileupMap.put(readGroupTwo.getSample(),sample2Pileup);
+
+ ReadBackedPileup compositePileup = new ReadBackedPileupImpl(null,sampleToPileupMap);
+
+ ReadBackedPileup rg1Pileup = compositePileup.getPileupForReadGroup("rg1");
+ List<GATKSAMRecord> rg1Reads = rg1Pileup.getReads();
+
+ Assert.assertEquals(rg1Reads.size(), 2, "Wrong number of reads in read group rg1");
+ Assert.assertEquals(rg1Reads.get(0), read1, "Read " + read1.getReadName() + " should be in rg1 but isn't");
+ Assert.assertEquals(rg1Reads.get(1), read3, "Read " + read3.getReadName() + " should be in rg1 but isn't");
+
+ ReadBackedPileup rg2Pileup = compositePileup.getPileupForReadGroup("rg2");
+ List<GATKSAMRecord> rg2Reads = rg2Pileup.getReads();
+
+ Assert.assertEquals(rg1Reads.size(), 2, "Wrong number of reads in read group rg2");
+ Assert.assertEquals(rg2Reads.get(0), read2, "Read " + read2.getReadName() + " should be in rg2 but isn't");
+ Assert.assertEquals(rg2Reads.get(1), read4, "Read " + read4.getReadName() + " should be in rg2 but isn't");
+ }
+
+ @Test
+ public void testGetPileupForSample() {
+ String sample1 = "sample1";
+ String sample2 = "sample2";
+
+ SAMReadGroupRecord readGroupOne = new SAMReadGroupRecord("rg1");
+ readGroupOne.setSample(sample1);
+ SAMReadGroupRecord readGroupTwo = new SAMReadGroupRecord("rg2");
+ readGroupTwo.setSample(sample2);
+
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1,1,1000);
+ header.addReadGroup(readGroupOne);
+ header.addReadGroup(readGroupTwo);
+
+ GATKSAMRecord read1 = ArtificialSAMUtils.createArtificialRead(header,"read1",0,1,10);
+ read1.setAttribute("RG",readGroupOne.getId());
+ GATKSAMRecord read2 = ArtificialSAMUtils.createArtificialRead(header,"read2",0,1,10);
+ read2.setAttribute("RG",readGroupTwo.getId());
+
+ Map<String,ReadBackedPileupImpl> sampleToPileupMap = new HashMap<String,ReadBackedPileupImpl>();
+ sampleToPileupMap.put(sample1,new ReadBackedPileupImpl(null,Collections.singletonList(read1),0));
+ sampleToPileupMap.put(sample2,new ReadBackedPileupImpl(null,Collections.singletonList(read2),0));
+
+ ReadBackedPileup pileup = new ReadBackedPileupImpl(null,sampleToPileupMap);
+
+ ReadBackedPileup sample2Pileup = pileup.getPileupForSample(sample2);
+ Assert.assertEquals(sample2Pileup.getNumberOfElements(),1,"Sample 2 pileup has wrong number of elements");
+ Assert.assertEquals(sample2Pileup.getReads().get(0),read2,"Sample 2 pileup has incorrect read");
+
+ ReadBackedPileup missingSamplePileup = pileup.getPileupForSample("missing");
+ Assert.assertNull(missingSamplePileup,"Pileup for sample 'missing' should be null but isn't");
+
+ missingSamplePileup = pileup.getPileupForSample("not here");
+ Assert.assertNull(missingSamplePileup,"Pileup for sample 'not here' should be null but isn't");
+ }
+
+ private static int sampleI = 0;
+ private class RBPCountTest {
+ final String sample;
+ final int nReads, nMapq0, nDeletions;
+
+ private RBPCountTest(int nReads, int nMapq0, int nDeletions) {
+ this.sample = "sample" + sampleI++;
+ this.nReads = nReads;
+ this.nMapq0 = nMapq0;
+ this.nDeletions = nDeletions;
+ }
+
+ private List<PileupElement> makeReads( final int n, final int mapq, final String op ) {
+ final int readLength = 3;
+
+ final List<PileupElement> elts = new LinkedList<PileupElement>();
+ for ( int i = 0; i < n; i++ ) {
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read", 0, 1, readLength);
+ read.setReadBases(Utils.dupBytes((byte) 'A', readLength));
+ read.setBaseQualities(Utils.dupBytes((byte) 30, readLength));
+ read.setCigarString("1M1" + op + "1M");
+ read.setMappingQuality(mapq);
+ final int baseOffset = op.equals("M") ? 1 : 0;
+ final CigarElement cigarElement = read.getCigar().getCigarElement(1);
+ elts.add(new PileupElement(read, baseOffset, cigarElement, 1, 0));
+ }
+
+ return elts;
+ }
+
+ private ReadBackedPileupImpl makePileup() {
+ final List<PileupElement> elts = new LinkedList<PileupElement>();
+
+ elts.addAll(makeReads(nMapq0, 0, "M"));
+ elts.addAll(makeReads(nDeletions, 30, "D"));
+ elts.addAll(makeReads(nReads - nMapq0 - nDeletions, 30, "M"));
+
+ return new ReadBackedPileupImpl(loc, elts);
+ }
+
+ @Override
+ public String toString() {
+ return "RBPCountTest{" +
+ "sample='" + sample + '\'' +
+ ", nReads=" + nReads +
+ ", nMapq0=" + nMapq0 +
+ ", nDeletions=" + nDeletions +
+ '}';
+ }
+ }
+
+ @DataProvider(name = "RBPCountingTest")
+ public Object[][] makeRBPCountingTest() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ for ( final int nMapq : Arrays.asList(0, 10, 20) ) {
+ for ( final int nDeletions : Arrays.asList(0, 10, 20) ) {
+ for ( final int nReg : Arrays.asList(0, 10, 20) ) {
+ final int total = nMapq + nDeletions + nReg;
+ if ( total > 0 )
+ tests.add(new Object[]{new RBPCountTest(total, nMapq, nDeletions)});
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "RBPCountingTest")
+ public void testRBPCountingTestSinglePileup(RBPCountTest params) {
+ testRBPCounts(params.makePileup(), params);
+ }
+
+ @Test(dataProvider = "RBPCountingTest")
+ public void testRBPCountingTestMultiSample(RBPCountTest params) {
+ final RBPCountTest newSample = new RBPCountTest(2, 1, 1);
+ final Map<String, ReadBackedPileupImpl> pileupsBySample = new HashMap<String, ReadBackedPileupImpl>();
+ pileupsBySample.put(newSample.sample, newSample.makePileup());
+ pileupsBySample.put(params.sample, params.makePileup());
+ final ReadBackedPileup pileup = new ReadBackedPileupImpl(loc, pileupsBySample);
+ testRBPCounts(pileup, new RBPCountTest(params.nReads + 2, params.nMapq0 + 1, params.nDeletions + 1));
+ }
+
+ private void testRBPCounts(final ReadBackedPileup rbp, RBPCountTest expected) {
+ for ( int cycles = 0; cycles < 3; cycles++ ) {
+ // multiple cycles to make sure caching is working
+ Assert.assertEquals(rbp.getNumberOfElements(), expected.nReads);
+ Assert.assertEquals(rbp.depthOfCoverage(), expected.nReads);
+ Assert.assertEquals(rbp.getNumberOfDeletions(), expected.nDeletions);
+ Assert.assertEquals(rbp.getNumberOfMappingQualityZeroReads(), expected.nMapq0);
+ }
+ }
+
+ @Test
+ public void testRBPMappingQuals() {
+
+ // create a read with high MQ
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read", 0, 1, 10);
+ read.setReadBases(Utils.dupBytes((byte) 'A', 10));
+ read.setBaseQualities(Utils.dupBytes((byte) 30, 10));
+ read.setCigarString("10M");
+ read.setMappingQuality(200); // set a MQ higher than max signed byte
+
+ // now create the RBP
+ final List<PileupElement> elts = new LinkedList<>();
+ elts.add(new PileupElement(read, 0, read.getCigar().getCigarElement(0), 0, 0));
+ final Map<String, ReadBackedPileupImpl> pileupsBySample = new HashMap<>();
+ pileupsBySample.put("foo", new ReadBackedPileupImpl(loc, elts));
+ final ReadBackedPileup pileup = new ReadBackedPileupImpl(loc, pileupsBySample);
+
+ Assert.assertEquals(pileup.getMappingQuals()[0], 200);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterDaemonUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterDaemonUnitTest.java
new file mode 100644
index 0000000..9d549ea
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterDaemonUnitTest.java
@@ -0,0 +1,121 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.progressmeter;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.GenomeLocParser;
+import org.broadinstitute.gatk.utils.GenomeLocSortedSet;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * UnitTests for the ProgressMeterDaemon
+ *
+ * User: depristo
+ * Date: 8/24/12
+ * Time: 11:25 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ProgressMeterDaemonUnitTest extends BaseTest {
+ private GenomeLocParser genomeLocParser;
+
+ @BeforeClass
+ public void init() throws FileNotFoundException {
+ genomeLocParser = new GenomeLocParser(new CachingIndexedFastaSequenceFile(new File(b37KGReference)));
+ }
+
+ // capture and count calls to progress
+ private class TestingProgressMeter extends ProgressMeter {
+ final List<Long> progressCalls = new LinkedList<Long>();
+
+ private TestingProgressMeter(final long poll) {
+ super(null, "test", new GenomeLocSortedSet(genomeLocParser), poll);
+ super.start();
+ }
+
+ @Override
+ protected synchronized void printProgress(boolean mustPrint) {
+ progressCalls.add(System.currentTimeMillis());
+ }
+ }
+
+ @DataProvider(name = "PollingData")
+ public Object[][] makePollingData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+ for ( final int ticks : Arrays.asList(1, 5, 10) ) {
+ for ( final int poll : Arrays.asList(10, 100) ) {
+ tests.add(new Object[]{poll, ticks});
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test
+ public void testPeriodUpdateNano() {
+ final ProgressMeter meter = new TestingProgressMeter(10);
+ final long currentTime = meter.getRuntimeInNanoseconds();
+ meter.updateElapsedTimeInNanoseconds();
+ Assert.assertTrue( meter.getRuntimeInNanosecondsUpdatedPeriodically() > currentTime, "Updating the periodic runtime failed" );
+ }
+
+ @Test(dataProvider = "PollingData", invocationCount = 10, successPercentage = 90, enabled = false)
+ public void testProgressMeterDaemon(final long poll, final int ticks) throws InterruptedException {
+ final TestingProgressMeter meter = new TestingProgressMeter(poll);
+ final ProgressMeterDaemon daemon = meter.getProgressMeterDaemon();
+
+ Assert.assertTrue(daemon.isDaemon());
+
+ Assert.assertFalse(daemon.isDone());
+ Thread.sleep(ticks * poll);
+ Assert.assertFalse(daemon.isDone());
+
+ daemon.done();
+ Assert.assertTrue(daemon.isDone());
+
+ // wait for the thread to actually finish
+ daemon.join();
+
+ Assert.assertTrue(meter.progressCalls.size() >= 1,
+ "Expected at least one progress update call from daemon thread, but only got " + meter.progressCalls.size() + " with exact calls " + meter.progressCalls);
+
+ final int tolerance = (int)Math.ceil(0.8 * meter.progressCalls.size());
+ Assert.assertTrue(Math.abs(meter.progressCalls.size() - ticks) <= tolerance,
+ "Expected " + ticks + " progress calls from daemon thread, but got " + meter.progressCalls.size() + " and a tolerance of only " + tolerance);
+
+ Assert.assertTrue(meter.getRuntimeInNanosecondsUpdatedPeriodically() > 0, "Daemon should have updated our periodic runtime");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterDataUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterDataUnitTest.java
new file mode 100644
index 0000000..0c97377
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/progressmeter/ProgressMeterDataUnitTest.java
@@ -0,0 +1,86 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.progressmeter;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.AutoFormattingTime;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * UnitTests for the ProgressMeterData
+ *
+ * User: depristo
+ * Date: 8/24/12
+ * Time: 11:25 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ProgressMeterDataUnitTest extends BaseTest {
+ @Test
+ public void testBasic() {
+ Assert.assertEquals(new ProgressMeterData(1.0, 2, 3).getElapsedSeconds(), 1.0);
+ Assert.assertEquals(new ProgressMeterData(1.0, 2, 3).getUnitsProcessed(), 2);
+ Assert.assertEquals(new ProgressMeterData(1.0, 2, 3).getBpProcessed(), 3);
+ }
+
+ @Test
+ public void testFraction() {
+ final double TOL = 1e-3;
+ Assert.assertEquals(new ProgressMeterData(1.0, 1, 1).calculateFractionGenomeTargetCompleted(10), 0.1, TOL);
+ Assert.assertEquals(new ProgressMeterData(1.0, 1, 2).calculateFractionGenomeTargetCompleted(10), 0.2, TOL);
+ Assert.assertEquals(new ProgressMeterData(1.0, 1, 1).calculateFractionGenomeTargetCompleted(100), 0.01, TOL);
+ Assert.assertEquals(new ProgressMeterData(1.0, 1, 2).calculateFractionGenomeTargetCompleted(100), 0.02, TOL);
+ Assert.assertEquals(new ProgressMeterData(1.0, 1, 1).calculateFractionGenomeTargetCompleted(0), 1.0, TOL);
+ }
+
+ @Test
+ public void testSecondsPerBP() {
+ final double TOL = 1e-3;
+ final long M = 1000000;
+ Assert.assertEquals(new ProgressMeterData(1.0, 1, M).secondsPerMillionBP(), 1.0, TOL);
+ Assert.assertEquals(new ProgressMeterData(1.0, 1, M/10).secondsPerMillionBP(), 10.0, TOL);
+ Assert.assertEquals(new ProgressMeterData(2.0, 1, M).secondsPerMillionBP(), 2.0, TOL);
+ Assert.assertEquals(new ProgressMeterData(1.0, 1, 0).secondsPerMillionBP(), 1e6, TOL);
+ }
+
+ @Test
+ public void testSecondsPerElement() {
+ final double TOL = 1e-3;
+ final long M = 1000000;
+ Assert.assertEquals(new ProgressMeterData(1.0, M, 1).secondsPerMillionElements(), 1.0, TOL);
+ Assert.assertEquals(new ProgressMeterData(1.0, M/10, 1).secondsPerMillionElements(), 10.0, TOL);
+ Assert.assertEquals(new ProgressMeterData(2.00, M, 1).secondsPerMillionElements(), 2.0, TOL);
+ Assert.assertEquals(new ProgressMeterData(1.0, 0, 1).secondsPerMillionElements(), 1e6, TOL);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/recalibration/EventTypeUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/recalibration/EventTypeUnitTest.java
new file mode 100644
index 0000000..7749fb2
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/recalibration/EventTypeUnitTest.java
@@ -0,0 +1,61 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.recalibration;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+public final class EventTypeUnitTest extends BaseTest {
+ @Test
+ public void testEventTypes() {
+ for ( final EventType et : EventType.values() ) {
+ Assert.assertNotNull(et.toString());
+ Assert.assertNotNull(et.prettyPrint());
+ Assert.assertFalse("".equals(et.toString()));
+ Assert.assertFalse("".equals(et.prettyPrint()));
+ Assert.assertEquals(EventType.eventFrom(et.ordinal()), et);
+ Assert.assertEquals(EventType.eventFrom(et.toString()), et);
+ }
+ }
+
+ @Test
+ public void testEventTypesEnumItself() {
+ final Set<String> shortReps = new HashSet<String>();
+ for ( final EventType et : EventType.values() ) {
+ Assert.assertFalse(shortReps.contains(et.toString()), "Short representative for EventType has duplicates for " + et);
+ shortReps.add(et.toString());
+ }
+ Assert.assertEquals(shortReps.size(), EventType.values().length, "Short representatives for EventType aren't unique");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testBadString() {
+ EventType.eventFrom("asdfhalsdjfalkjsdf");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/report/ReportMarshallerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/report/ReportMarshallerUnitTest.java
new file mode 100644
index 0000000..ebeb158
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/report/ReportMarshallerUnitTest.java
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.report;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.annotations.Test;
+
+
+/**
+ * @author aaron
+ * <p/>
+ * Class ReportMarshallerUnitTest
+ * <p/>
+ * test out the marshaller
+ */
+public class ReportMarshallerUnitTest extends BaseTest {
+ @Test
+ public void testMarshalling() {
+ /*Configuration cfg = new Configuration();
+ try {
+ cfg.setDirectoryForTemplateLoading(new File("templates"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ cfg.setObjectWrapper(new DefaultObjectWrapper());
+ Template temp = null;
+ try {
+ temp = cfg.createMarhsaller("myTestTemp.ftl");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ FakeAnalysis fa = new FakeAnalysis();
+ File fl = new File("testFile.out");
+ fl.deleteOnExit();
+ ReportMarshaller marsh = new ReportMarshaller("report",fl,temp);
+ marsh.write(fa);
+ marsh.write(fa);
+ marsh.write(fa);
+ marsh.close();*/
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/runtime/ProcessControllerUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/runtime/ProcessControllerUnitTest.java
new file mode 100644
index 0000000..4fa7ef5
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/runtime/ProcessControllerUnitTest.java
@@ -0,0 +1,518 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.runtime;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.broadinstitute.gatk.utils.io.IOUtils;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public class ProcessControllerUnitTest extends BaseTest {
+ private static final String NL = String.format("%n");
+
+ @Test(timeOut = 60 * 1000)
+ public void testDestroyThreadLocal() throws InterruptedException {
+ for (int i = 0; i < 3; i++) {
+ final ProcessController controller = ProcessController.getThreadLocal();
+ final ProcessSettings job = new ProcessSettings(
+ new String[] {"sh", "-c", "echo Hello World && sleep 600 && echo Goodbye"});
+ job.getStdoutSettings().setBufferSize(-1);
+
+ Thread t = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("BACK: Starting on background thread");
+ ProcessOutput result = controller.exec(job);
+ // Assert in background thread doesn't make it to main thread but does print a trace.
+ Assert.assertTrue(result.getExitValue() != 0, "Destroy-attempted job returned zero exit status");
+ System.out.println("BACK: Background thread exiting");
+ }
+ });
+
+ System.out.println("MAIN: Starting background thread");
+ t.start();
+ System.out.println("MAIN: Sleeping main thread 3s");
+ Thread.sleep(3000);
+ System.out.println("MAIN: Destroying job");
+ controller.tryDestroy();
+ System.out.println("MAIN: Not waiting on background thread to exit");
+ // Using standard java.io this was blocking on linux.
+ // TODO: try again with NIO.
+ //t.join();
+ //System.out.println("MAIN: Background thread exited");
+ }
+ }
+
+ @Test
+ public void testReuseAfterError() {
+ ProcessController controller = new ProcessController();
+
+ ProcessSettings job;
+
+ for (int i = 0; i < 3; i++) {
+ // Test bad command
+ job = new ProcessSettings(new String[] {"no_such_command"});
+ try {
+ controller.exec(job);
+ } catch (ReviewedGATKException e) {
+ /* Was supposed to throw an exception */
+ }
+
+ // Test exit != 0
+ job = new ProcessSettings(new String[] {"cat", "non_existent_file"});
+ int exitValue = controller.exec(job).getExitValue();
+ Assert.assertTrue(exitValue != 0, "'cat' non existent file returned 0");
+
+ // Text success
+ job = new ProcessSettings(new String[] {"echo", "Hello World"});
+ exitValue = controller.exec(job).getExitValue();
+ Assert.assertEquals(exitValue, 0, "Echo failed");
+ }
+ }
+
+ @Test
+ public void testEnvironment() {
+ String key = "MY_NEW_VAR";
+ String value = "value is here";
+
+ ProcessSettings job = new ProcessSettings(new String[] {"sh", "-c", "echo $"+key});
+ job.getStdoutSettings().setBufferSize(-1);
+ job.setRedirectErrorStream(true);
+
+ Map<String, String> env = new HashMap<String, String>(System.getenv());
+ env.put(key, value);
+ job.setEnvironment(env);
+
+ ProcessController controller = new ProcessController();
+ ProcessOutput result = controller.exec(job);
+ int exitValue = result.getExitValue();
+
+ Assert.assertEquals(exitValue, 0, "Echo environment variable failed");
+ Assert.assertEquals(result.getStdout().getBufferString(), value + NL, "Echo environment returned unexpected output");
+ }
+
+ @Test
+ public void testDirectory() throws IOException {
+ File dir = null;
+ try {
+ dir = IOUtils.tempDir("temp.", "").getCanonicalFile();
+
+ ProcessSettings job = new ProcessSettings(new String[] {"pwd"});
+ job.getStdoutSettings().setBufferSize(-1);
+ job.setRedirectErrorStream(true);
+ job.setDirectory(dir);
+
+ ProcessController controller = new ProcessController();
+ ProcessOutput result = controller.exec(job);
+ int exitValue = result.getExitValue();
+
+ Assert.assertEquals(exitValue, 0, "Getting working directory failed");
+
+ Assert.assertEquals(result.getStdout().getBufferString(), dir.getAbsolutePath() + NL,
+ "Setting/getting working directory returned unexpected output");
+ } finally {
+ FileUtils.deleteQuietly(dir);
+ }
+ }
+
+ @Test
+ public void testReadStdInBuffer() {
+ String bufferText = "Hello from buffer";
+ ProcessSettings job = new ProcessSettings(new String[] {"cat"});
+ job.getStdoutSettings().setBufferSize(-1);
+ job.setRedirectErrorStream(true);
+ job.getStdinSettings().setInputBuffer(bufferText);
+
+ ProcessController controller = new ProcessController();
+ ProcessOutput output = controller.exec(job);
+
+ Assert.assertEquals(output.getStdout().getBufferString(), bufferText,
+ "Unexpected output from cat stdin buffer");
+ }
+
+ @Test
+ public void testReadStdInFile() {
+ File input = null;
+ try {
+ String fileText = "Hello from file";
+ input = IOUtils.writeTempFile(fileText, "stdin.", ".txt");
+
+ ProcessSettings job = new ProcessSettings(new String[] {"cat"});
+ job.getStdoutSettings().setBufferSize(-1);
+ job.setRedirectErrorStream(true);
+ job.getStdinSettings().setInputFile(input);
+
+ ProcessController controller = new ProcessController();
+ ProcessOutput output = controller.exec(job);
+
+ Assert.assertEquals(output.getStdout().getBufferString(), fileText,
+ "Unexpected output from cat stdin file");
+ } finally {
+ FileUtils.deleteQuietly(input);
+ }
+ }
+
+ @Test
+ public void testWriteStdOut() {
+ ProcessSettings job = new ProcessSettings(new String[] {"echo", "Testing to stdout"});
+ // Not going to call the System.setOut() for now. Just running a basic visual test.
+ job.getStdoutSettings().printStandard(true);
+ job.setRedirectErrorStream(true);
+
+ System.out.println("testWriteStdOut: Writing two lines to std out...");
+ ProcessController controller = new ProcessController();
+ controller.exec(job);
+ job.setCommand(new String[]{"cat", "non_existent_file"});
+ controller.exec(job);
+ System.out.println("testWriteStdOut: ...two lines should have been printed to std out");
+ }
+
+ @Test
+ public void testErrorToOut() throws IOException {
+ File outFile = null;
+ File errFile = null;
+ try {
+ outFile = BaseTest.createTempFile("temp", "");
+ errFile = BaseTest.createTempFile("temp", "");
+
+ ProcessSettings job = new ProcessSettings(new String[]{"cat", "non_existent_file"});
+ job.getStdoutSettings().setOutputFile(outFile);
+ job.getStdoutSettings().setBufferSize(-1);
+ job.getStderrSettings().setOutputFile(errFile);
+ job.getStderrSettings().setBufferSize(-1);
+ job.setRedirectErrorStream(true);
+
+ ProcessOutput result = new ProcessController().exec(job);
+ int exitValue = result.getExitValue();
+
+ Assert.assertTrue(exitValue != 0, "'cat' non existent file returned 0");
+
+ String fileString, bufferString;
+
+ fileString = FileUtils.readFileToString(outFile);
+ Assert.assertTrue(fileString.length() > 0, "Out file was length 0");
+
+ bufferString = result.getStdout().getBufferString();
+ Assert.assertTrue(bufferString.length() > 0, "Out buffer was length 0");
+
+ Assert.assertFalse(result.getStdout().isBufferTruncated(), "Out buffer was truncated");
+ Assert.assertEquals(bufferString.length(), fileString.length(), "Out buffer length did not match file length");
+
+ fileString = FileUtils.readFileToString(errFile);
+ Assert.assertEquals(fileString, "", "Unexpected output to err file");
+
+ bufferString = result.getStderr().getBufferString();
+ Assert.assertEquals(bufferString, "", "Unexepected output to err buffer");
+ } finally {
+ FileUtils.deleteQuietly(outFile);
+ FileUtils.deleteQuietly(errFile);
+ }
+ }
+
+ @Test
+ public void testErrorToErr() throws IOException {
+ File outFile = null;
+ File errFile = null;
+ try {
+ outFile = BaseTest.createTempFile("temp", "");
+ errFile = BaseTest.createTempFile("temp", "");
+
+ ProcessSettings job = new ProcessSettings(new String[]{"cat", "non_existent_file"});
+ job.getStdoutSettings().setOutputFile(outFile);
+ job.getStdoutSettings().setBufferSize(-1);
+ job.getStderrSettings().setOutputFile(errFile);
+ job.getStderrSettings().setBufferSize(-1);
+ job.setRedirectErrorStream(false);
+
+ ProcessOutput result = new ProcessController().exec(job);
+ int exitValue = result.getExitValue();
+
+ Assert.assertTrue(exitValue != 0, "'cat' non existent file returned 0");
+
+ String fileString, bufferString;
+
+ fileString = FileUtils.readFileToString(errFile);
+ Assert.assertTrue(fileString.length() > 0, "Err file was length 0");
+
+ bufferString = result.getStderr().getBufferString();
+ Assert.assertTrue(bufferString.length() > 0, "Err buffer was length 0");
+
+ Assert.assertFalse(result.getStderr().isBufferTruncated(), "Err buffer was truncated");
+ Assert.assertEquals(bufferString.length(), fileString.length(), "Err buffer length did not match file length");
+
+ fileString = FileUtils.readFileToString(outFile);
+ Assert.assertEquals(fileString, "", "Unexpected output to out file");
+
+ bufferString = result.getStdout().getBufferString();
+ Assert.assertEquals(bufferString, "", "Unexepected output to out buffer");
+ } finally {
+ FileUtils.deleteQuietly(outFile);
+ FileUtils.deleteQuietly(errFile);
+ }
+ }
+
+ private static final String TRUNCATE_TEXT = "Hello World";
+ private static final byte[] TRUNCATE_OUTPUT_BYTES = (TRUNCATE_TEXT + NL).getBytes();
+
+ /**
+ * @return Test truncating content vs. not truncating (run at -1/+1 size)
+ */
+ @DataProvider(name = "truncateSizes")
+ public Object[][] getTruncateBufferSizes() {
+ int l = TRUNCATE_OUTPUT_BYTES.length;
+ return new Object[][]{
+ new Object[]{0, 0},
+ new Object[]{l, l},
+ new Object[]{l + 1, l},
+ new Object[]{l - 1, l - 1}
+ };
+ }
+
+ @Test(dataProvider = "truncateSizes")
+ public void testTruncateBuffer(int truncateLen, int expectedLen) {
+ byte[] expected = Arrays.copyOf(TRUNCATE_OUTPUT_BYTES, expectedLen);
+
+ String[] command = {"echo", TRUNCATE_TEXT};
+ ProcessController controller = new ProcessController();
+
+ ProcessSettings job = new ProcessSettings(command);
+ job.getStdoutSettings().setBufferSize(truncateLen);
+ ProcessOutput result = controller.exec(job);
+
+ int exitValue = result.getExitValue();
+
+ Assert.assertEquals(exitValue, 0,
+ String.format("Echo returned %d: %s", exitValue, TRUNCATE_TEXT));
+
+ byte[] bufferBytes = result.getStdout().getBufferBytes();
+
+ Assert.assertEquals(bufferBytes, expected,
+ String.format("Output buffer didn't match (%d vs %d)", expected.length, bufferBytes.length));
+
+ boolean truncated = result.getStdout().isBufferTruncated();
+
+ Assert.assertEquals(truncated, TRUNCATE_OUTPUT_BYTES.length > truncateLen,
+ "Unexpected buffer truncation result");
+ }
+
+ private static final String[] LONG_COMMAND = getLongCommand();
+ private static final String LONG_COMMAND_STRING = StringUtils.join(LONG_COMMAND, " ");
+ private static final String LONG_COMMAND_DESCRIPTION = "<long command>";
+
+ @DataProvider(name = "echoCommands")
+ public Object[][] getEchoCommands() {
+
+ new EchoCommand(new String[]{"echo", "Hello", "World"}, "Hello World" + NL);
+ new EchoCommand(new String[]{"echo", "'Hello", "World"}, "'Hello World" + NL);
+ new EchoCommand(new String[]{"echo", "Hello", "World'"}, "Hello World'" + NL);
+ new EchoCommand(new String[]{"echo", "'Hello", "World'"}, "'Hello World'" + NL);
+
+ String[] longCommand = new String[LONG_COMMAND.length + 1];
+ longCommand[0] = "echo";
+ System.arraycopy(LONG_COMMAND, 0, longCommand, 1, LONG_COMMAND.length);
+ new EchoCommand(longCommand, LONG_COMMAND_STRING + NL) {
+ @Override
+ public String toString() {
+ return LONG_COMMAND_DESCRIPTION;
+ }
+ };
+
+ return TestDataProvider.getTests(EchoCommand.class);
+ }
+
+ @Test(dataProvider = "echoCommands")
+ public void testEcho(EchoCommand script) throws IOException {
+ File outputFile = null;
+ try {
+ outputFile = BaseTest.createTempFile("temp", "");
+
+ ProcessSettings job = new ProcessSettings(script.command);
+ if (script.output != null) {
+ job.getStdoutSettings().setOutputFile(outputFile);
+ job.getStdoutSettings().setBufferSize(script.output.getBytes().length);
+ }
+
+ ProcessOutput result = new ProcessController().exec(job);
+ int exitValue = result.getExitValue();
+
+ Assert.assertEquals(exitValue, 0,
+ String.format("Echo returned %d: %s", exitValue, script));
+
+ if (script.output != null) {
+
+ String fileString = FileUtils.readFileToString(outputFile);
+ Assert.assertEquals(fileString, script.output,
+ String.format("Output file didn't match (%d vs %d): %s",
+ fileString.length(), script.output.length(), script));
+
+ String bufferString = result.getStdout().getBufferString();
+ Assert.assertEquals(bufferString, script.output,
+ String.format("Output content didn't match (%d vs %d): %s",
+ bufferString.length(), script.output.length(), script));
+
+ Assert.assertFalse(result.getStdout().isBufferTruncated(),
+ "Output content was truncated: " + script);
+ }
+ } finally {
+ FileUtils.deleteQuietly(outputFile);
+ }
+ }
+
+ @Test(expectedExceptions = ReviewedGATKException.class)
+ public void testUnableToStart() {
+ ProcessSettings job = new ProcessSettings(new String[]{"no_such_command"});
+ new ProcessController().exec(job);
+ }
+
+ @DataProvider(name = "scriptCommands")
+ public Object[][] getScriptCommands() {
+ new ScriptCommand(true, "echo Hello World", "Hello World" + NL);
+ new ScriptCommand(false, "echo 'Hello World", null);
+ new ScriptCommand(false, "echo Hello World'", null);
+ new ScriptCommand(true, "echo 'Hello World'", "Hello World" + NL);
+ new ScriptCommand(true, "echo \"Hello World\"", "Hello World" + NL);
+ new ScriptCommand(false, "no_such_echo Hello World", null);
+ new ScriptCommand(true, "echo #", NL);
+ new ScriptCommand(true, "echo \\#", "#" + NL);
+ new ScriptCommand(true, "echo \\\\#", "\\#" + NL);
+
+ new ScriptCommand(true, "echo " + LONG_COMMAND_STRING, LONG_COMMAND_STRING + NL) {
+ @Override
+ public String toString() {
+ return LONG_COMMAND_DESCRIPTION;
+ }
+ };
+
+ return TestDataProvider.getTests(ScriptCommand.class);
+ }
+
+ @Test(dataProvider = "scriptCommands")
+ public void testScript(ScriptCommand script) throws IOException {
+ File scriptFile = null;
+ File outputFile = null;
+ try {
+ scriptFile = writeScript(script.content);
+ outputFile = BaseTest.createTempFile("temp", "");
+
+ ProcessSettings job = new ProcessSettings(new String[]{"sh", scriptFile.getAbsolutePath()});
+ if (script.output != null) {
+ job.getStdoutSettings().setOutputFile(outputFile);
+ job.getStdoutSettings().setBufferSize(script.output.getBytes().length);
+ }
+
+ ProcessOutput result = new ProcessController().exec(job);
+ int exitValue = result.getExitValue();
+
+ Assert.assertEquals(exitValue == 0, script.succeed,
+ String.format("Script returned %d: %s", exitValue, script));
+
+ if (script.output != null) {
+
+ String fileString = FileUtils.readFileToString(outputFile);
+ Assert.assertEquals(fileString, script.output,
+ String.format("Output file didn't match (%d vs %d): %s",
+ fileString.length(), script.output.length(), script));
+
+ String bufferString = result.getStdout().getBufferString();
+ Assert.assertEquals(bufferString, script.output,
+ String.format("Output content didn't match (%d vs %d): %s",
+ bufferString.length(), script.output.length(), script));
+
+ Assert.assertFalse(result.getStdout().isBufferTruncated(),
+ "Output content was truncated: " + script);
+ }
+ } finally {
+ FileUtils.deleteQuietly(scriptFile);
+ FileUtils.deleteQuietly(outputFile);
+ }
+ }
+
+ private static String[] getLongCommand() {
+ // This command fails on some systems with a 4096 character limit when run via the old sh -c "echo ...",
+ // but works on the same systems when run via sh <script>
+ int cnt = 500;
+ String[] command = new String[cnt];
+ for (int i = 1; i <= cnt; i++) {
+ command[i - 1] = String.format("%03d______", i);
+ }
+ return command;
+ }
+
+ private static File writeScript(String contents) {
+ try {
+ File file = BaseTest.createTempFile("temp", "");
+ FileUtils.writeStringToFile(file, contents);
+ return file;
+ } catch (IOException e) {
+ throw new UserException.BadTmpDir(e.getMessage());
+ }
+ }
+
+ private static class EchoCommand extends TestDataProvider {
+ public final String[] command;
+ public final String output;
+
+ public EchoCommand(String[] command, String output) {
+ super(EchoCommand.class);
+ this.command = command;
+ this.output = output;
+ }
+
+ @Override
+ public String toString() {
+ return StringUtils.join(command, " ");
+ }
+ }
+
+ public static class ScriptCommand extends TestDataProvider {
+ public final boolean succeed;
+ public final String content;
+ public final String output;
+
+ public ScriptCommand(boolean succeed, String content, String output) {
+ super(ScriptCommand.class);
+ this.succeed = succeed;
+ this.content = content;
+ this.output = output;
+ }
+
+ @Override
+ public String toString() {
+ return content;
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/runtime/RuntimeUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/runtime/RuntimeUtilsUnitTest.java
new file mode 100644
index 0000000..9573774
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/runtime/RuntimeUtilsUnitTest.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.runtime;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class RuntimeUtilsUnitTest extends BaseTest {
+ @Test
+ public void testWhichExists() {
+ Assert.assertNotNull(RuntimeUtils.which("ls"), "Unable to locate ls");
+ }
+
+ @Test
+ public void testWhichNotExists() {
+ Assert.assertNull(RuntimeUtils.which("does_not_exist"), "Found nonexistent binary: does_not_exist");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/AlignmentUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/AlignmentUtilsUnitTest.java
new file mode 100644
index 0000000..3281570
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/AlignmentUtilsUnitTest.java
@@ -0,0 +1,1044 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.*;
+import org.apache.commons.lang.ArrayUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.haplotype.Haplotype;
+import org.broadinstitute.gatk.utils.pileup.PileupElement;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+public class AlignmentUtilsUnitTest {
+ private final static boolean DEBUG = false;
+ private SAMFileHeader header;
+
+ /** Basic aligned and mapped read. */
+ private SAMRecord readMapped;
+
+ /** Read with no contig specified in the read, -L UNMAPPED */
+ private SAMRecord readNoReference;
+
+ /** This read has a start position, but is flagged that it's not mapped. */
+ private SAMRecord readUnmappedFlag;
+
+ /** This read says it's aligned, but to a contig not in the header. */
+ private SAMRecord readUnknownContig;
+
+ /** This read says it's aligned, but actually has an unknown start. */
+ private SAMRecord readUnknownStart;
+
+ @BeforeClass
+ public void init() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(3, 1, ArtificialSAMUtils.DEFAULT_READ_LENGTH * 2);
+
+ readMapped = createMappedRead("mapped", 1);
+
+ readNoReference = createUnmappedRead("unmappedNoReference");
+
+ readUnmappedFlag = createMappedRead("unmappedFlagged", 2);
+ readUnmappedFlag.setReadUnmappedFlag(true);
+
+ readUnknownContig = createMappedRead("unknownContig", 3);
+ readUnknownContig.setReferenceName("unknownContig");
+
+ readUnknownStart = createMappedRead("unknownStart", 1);
+ readUnknownStart.setAlignmentStart(SAMRecord.NO_ALIGNMENT_START);
+ }
+
+ /**
+ * Test for -L UNMAPPED
+ */
+ @DataProvider(name = "genomeLocUnmappedReadTests")
+ public Object[][] getGenomeLocUnmappedReadTests() {
+ return new Object[][] {
+ new Object[] {readNoReference, true},
+ new Object[] {readMapped, false},
+ new Object[] {readUnmappedFlag, false},
+ new Object[] {readUnknownContig, false},
+ new Object[] {readUnknownStart, false}
+ };
+ }
+ @Test(enabled = !DEBUG, dataProvider = "genomeLocUnmappedReadTests")
+ public void testIsReadGenomeLocUnmapped(SAMRecord read, boolean expected) {
+ Assert.assertEquals(AlignmentUtils.isReadGenomeLocUnmapped(read), expected);
+ }
+
+ /**
+ * Test for read being truly unmapped
+ */
+ @DataProvider(name = "unmappedReadTests")
+ public Object[][] getUnmappedReadTests() {
+ return new Object[][] {
+ new Object[] {readNoReference, true},
+ new Object[] {readMapped, false},
+ new Object[] {readUnmappedFlag, true},
+ new Object[] {readUnknownContig, false},
+ new Object[] {readUnknownStart, true}
+ };
+ }
+ @Test(enabled = !DEBUG, dataProvider = "unmappedReadTests")
+ public void testIsReadUnmapped(SAMRecord read, boolean expected) {
+ Assert.assertEquals(AlignmentUtils.isReadUnmapped(read), expected);
+ }
+
+ private SAMRecord createUnmappedRead(String name) {
+ return ArtificialSAMUtils.createArtificialRead(
+ header,
+ name,
+ SAMRecord.NO_ALIGNMENT_REFERENCE_INDEX,
+ SAMRecord.NO_ALIGNMENT_START,
+ ArtificialSAMUtils.DEFAULT_READ_LENGTH);
+ }
+
+ private SAMRecord createMappedRead(String name, int start) {
+ return ArtificialSAMUtils.createArtificialRead(
+ header,
+ name,
+ 0,
+ start,
+ ArtificialSAMUtils.DEFAULT_READ_LENGTH);
+ }
+
+ private final List<List<CigarElement>> makeCigarElementCombinations() {
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ final List<CigarElement> cigarElements = new LinkedList<CigarElement>();
+ for ( final int size : Arrays.asList(0, 10) ) {
+ for ( final CigarOperator op : CigarOperator.values() ) {
+ cigarElements.add(new CigarElement(size, op));
+ }
+ }
+
+ final List<List<CigarElement>> combinations = new LinkedList<List<CigarElement>>();
+ for ( final int nElements : Arrays.asList(1, 2, 3) ) {
+ combinations.addAll(Utils.makePermutations(cigarElements, nElements, true));
+ }
+
+ return combinations;
+ }
+
+
+ @DataProvider(name = "CalcNumDifferentBasesData")
+ public Object[][] makeCalcNumDifferentBasesData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ tests.add(new Object[]{"5M", "ACGTA", "ACGTA", 0});
+ tests.add(new Object[]{"5M", "ACGTA", "ACGTT", 1});
+ tests.add(new Object[]{"5M", "ACGTA", "TCGTT", 2});
+ tests.add(new Object[]{"5M", "ACGTA", "TTGTT", 3});
+ tests.add(new Object[]{"5M", "ACGTA", "TTTTT", 4});
+ tests.add(new Object[]{"5M", "ACGTA", "TTTCT", 5});
+ tests.add(new Object[]{"2M3I3M", "ACGTA", "ACNNNGTA", 3});
+ tests.add(new Object[]{"2M3I3M", "ACGTA", "ACNNNGTT", 4});
+ tests.add(new Object[]{"2M3I3M", "ACGTA", "TCNNNGTT", 5});
+ tests.add(new Object[]{"2M2D1M", "ACGTA", "ACA", 2});
+ tests.add(new Object[]{"2M2D1M", "ACGTA", "ACT", 3});
+ tests.add(new Object[]{"2M2D1M", "ACGTA", "TCT", 4});
+ tests.add(new Object[]{"2M2D1M", "ACGTA", "TGT", 5});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = true, dataProvider = "CalcNumDifferentBasesData")
+ public void testCalcNumDifferentBases(final String cigarString, final String ref, final String read, final int expectedDifferences) {
+ final Cigar cigar = TextCigarCodec.getSingleton().decode(cigarString);
+ Assert.assertEquals(AlignmentUtils.calcNumDifferentBases(cigar, ref.getBytes(), read.getBytes()), expectedDifferences);
+ }
+
+ @DataProvider(name = "NumAlignedBasesCountingSoftClips")
+ public Object[][] makeNumAlignedBasesCountingSoftClips() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final EnumSet<CigarOperator> alignedToGenome = EnumSet.of(CigarOperator.M, CigarOperator.EQ, CigarOperator.X, CigarOperator.S);
+ for ( final List<CigarElement> elements : makeCigarElementCombinations() ) {
+ int n = 0;
+ for ( final CigarElement elt : elements ) n += alignedToGenome.contains(elt.getOperator()) ? elt.getLength() : 0;
+ tests.add(new Object[]{new Cigar(elements), n});
+ }
+
+ tests.add(new Object[]{null, 0});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "NumAlignedBasesCountingSoftClips")
+ public void testNumAlignedBasesCountingSoftClips(final Cigar cigar, final int expected) {
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, cigar == null ? 10 : cigar.getReadLength());
+ read.setCigar(cigar);
+ Assert.assertEquals(AlignmentUtils.getNumAlignedBasesCountingSoftClips(read), expected, "Cigar " + cigar + " failed NumAlignedBasesCountingSoftClips");
+ }
+
+ @DataProvider(name = "CigarHasZeroElement")
+ public Object[][] makeCigarHasZeroElement() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final List<CigarElement> elements : makeCigarElementCombinations() ) {
+ boolean hasZero = false;
+ for ( final CigarElement elt : elements ) hasZero = hasZero || elt.getLength() == 0;
+ tests.add(new Object[]{new Cigar(elements), hasZero});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "CigarHasZeroElement")
+ public void testCigarHasZeroSize(final Cigar cigar, final boolean hasZero) {
+ Assert.assertEquals(AlignmentUtils.cigarHasZeroSizeElement(cigar), hasZero, "Cigar " + cigar.toString() + " failed cigarHasZeroSizeElement");
+ }
+
+ @DataProvider(name = "NumHardClipped")
+ public Object[][] makeNumHardClipped() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final List<CigarElement> elements : makeCigarElementCombinations() ) {
+ int n = 0;
+ for ( final CigarElement elt : elements ) n += elt.getOperator() == CigarOperator.H ? elt.getLength() : 0;
+ tests.add(new Object[]{new Cigar(elements), n});
+ }
+
+ tests.add(new Object[]{null, 0});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "NumHardClipped")
+ public void testNumHardClipped(final Cigar cigar, final int expected) {
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, cigar == null ? 10 : cigar.getReadLength());
+ read.setCigar(cigar);
+ Assert.assertEquals(AlignmentUtils.getNumHardClippedBases(read), expected, "Cigar " + cigar + " failed num hard clips");
+ }
+
+ @DataProvider(name = "NumAlignedBlocks")
+ public Object[][] makeNumAlignedBlocks() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final List<CigarElement> elements : makeCigarElementCombinations() ) {
+ int n = 0;
+ for ( final CigarElement elt : elements ) {
+ switch ( elt.getOperator() ) {
+ case M:case X:case EQ: n++; break;
+ default: break;
+ }
+ }
+ tests.add(new Object[]{new Cigar(elements), n});
+ }
+
+ tests.add(new Object[]{null, 0});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "NumAlignedBlocks")
+ public void testNumAlignedBlocks(final Cigar cigar, final int expected) {
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, cigar == null ? 10 : cigar.getReadLength());
+ read.setCigar(cigar);
+ Assert.assertEquals(AlignmentUtils.getNumAlignmentBlocks(read), expected, "Cigar " + cigar + " failed NumAlignedBlocks");
+ }
+
+ @DataProvider(name = "ConsolidateCigarData")
+ public Object[][] makeConsolidateCigarData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ tests.add(new Object[]{"1M1M", "2M"});
+ tests.add(new Object[]{"2M", "2M"});
+ tests.add(new Object[]{"2M0M", "2M"});
+ tests.add(new Object[]{"0M2M", "2M"});
+ tests.add(new Object[]{"0M2M0M0I0M1M", "3M"});
+ tests.add(new Object[]{"2M0M1M", "3M"});
+ tests.add(new Object[]{"1M1M1M1D2M1M", "3M1D3M"});
+ tests.add(new Object[]{"6M6M6M", "18M"});
+
+ final List<CigarElement> elements = new LinkedList<CigarElement>();
+ int i = 1;
+ for ( final CigarOperator op : CigarOperator.values() ) {
+ elements.add(new CigarElement(i++, op));
+ }
+ for ( final List<CigarElement> ops : Utils.makePermutations(elements, 3, false) ) {
+ final String expected = new Cigar(ops).toString();
+ final List<CigarElement> cutElements = new LinkedList<CigarElement>();
+ for ( final CigarElement elt : ops ) {
+ for ( int j = 0; j < elt.getLength(); j++ ) {
+ cutElements.add(new CigarElement(1, elt.getOperator()));
+ }
+ }
+
+ final String actual = new Cigar(cutElements).toString();
+ tests.add(new Object[]{actual, expected});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "ConsolidateCigarData")
+ public void testConsolidateCigarWithData(final String testCigarString, final String expectedCigarString) {
+ final Cigar testCigar = TextCigarCodec.getSingleton().decode(testCigarString);
+ final Cigar expectedCigar = TextCigarCodec.getSingleton().decode(expectedCigarString);
+ final Cigar actualCigar = AlignmentUtils.consolidateCigar(testCigar);
+ Assert.assertEquals(actualCigar, expectedCigar);
+ }
+
+ @DataProvider(name = "SoftClipsDataProvider")
+ public Object[][] makeSoftClipsDataProvider() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ for ( final int lengthOfLeftClip : Arrays.asList(0, 1, 10) ) {
+ for ( final int lengthOfRightClip : Arrays.asList(0, 1, 10) ) {
+ for ( final int qualThres : Arrays.asList(10, 20, 30) ) {
+ for ( final String middleOp : Arrays.asList("M", "D") ) {
+ for ( final int matchSize : Arrays.asList(0, 1, 10) ) {
+ final byte[] left = makeQualArray(lengthOfLeftClip, qualThres);
+ final byte[] right = makeQualArray(lengthOfRightClip, qualThres);
+ int n = 0;
+ for ( int i = 0; i < left.length; i++ ) n += left[i] > qualThres ? 1 : 0;
+ for ( int i = 0; i < right.length; i++ ) n += right[i] > qualThres ? 1 : 0;
+ tests.add(new Object[]{left, matchSize, middleOp, right, qualThres, n});
+ }
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ private byte[] makeQualArray(final int length, final int qualThreshold) {
+ final byte[] array = new byte[length];
+ for ( int i = 0; i < array.length; i++ )
+ array[i] = (byte)(qualThreshold + ( i % 2 == 0 ? 1 : - 1 ));
+ return array;
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "SoftClipsDataProvider")
+ public void testSoftClipsData(final byte[] qualsOfSoftClipsOnLeft, final int middleSize, final String middleOp, final byte[] qualOfSoftClipsOnRight, final int qualThreshold, final int numExpected) {
+ final int readLength = (middleOp.equals("D") ? 0 : middleSize) + qualOfSoftClipsOnRight.length + qualsOfSoftClipsOnLeft.length;
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, readLength);
+ final byte[] bases = Utils.dupBytes((byte) 'A', readLength);
+ final byte[] matchBytes = middleOp.equals("D") ? new byte[]{} : Utils.dupBytes((byte)30, middleSize);
+ final byte[] quals = ArrayUtils.addAll(ArrayUtils.addAll(qualsOfSoftClipsOnLeft, matchBytes), qualOfSoftClipsOnRight);
+
+ // set the read's bases and quals
+ read.setReadBases(bases);
+ read.setBaseQualities(quals);
+
+ final StringBuilder cigar = new StringBuilder();
+ if (qualsOfSoftClipsOnLeft.length > 0 ) cigar.append(qualsOfSoftClipsOnLeft.length + "S");
+ if (middleSize > 0 ) cigar.append(middleSize + middleOp);
+ if (qualOfSoftClipsOnRight.length > 0 ) cigar.append(qualOfSoftClipsOnRight.length + "S");
+
+ read.setCigarString(cigar.toString());
+
+ final int actual = AlignmentUtils.calcNumHighQualitySoftClips(read, (byte) qualThreshold);
+ Assert.assertEquals(actual, numExpected, "Wrong number of soft clips detected for read " + read.getSAMString());
+ }
+
+ ////////////////////////////////////////////
+ // Test AlignmentUtils.getMismatchCount() //
+ ////////////////////////////////////////////
+
+ @DataProvider(name = "MismatchCountDataProvider")
+ public Object[][] makeMismatchCountDataProvider() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final int readLength = 20;
+ final int lengthOfIndel = 2;
+ final int locationOnReference = 10;
+ final byte[] reference = Utils.dupBytes((byte)'A', readLength);
+ final byte[] quals = Utils.dupBytes((byte)'A', readLength);
+
+
+ for ( int startOnRead = 0; startOnRead <= readLength; startOnRead++ ) {
+ for ( int basesToRead = 0; basesToRead <= readLength; basesToRead++ ) {
+ for ( final int lengthOfSoftClip : Arrays.asList(0, 1, 10) ) {
+ for ( final int lengthOfFirstM : Arrays.asList(0, 3) ) {
+ for ( final char middleOp : Arrays.asList('M', 'D', 'I') ) {
+ for ( final int mismatchLocation : Arrays.asList(-1, 0, 5, 10, 15, 19) ) {
+
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, locationOnReference, readLength);
+
+ // set the read's bases and quals
+ final byte[] readBases = reference.clone();
+ // create the mismatch if requested
+ if ( mismatchLocation != -1 )
+ readBases[mismatchLocation] = (byte)'C';
+ read.setReadBases(readBases);
+ read.setBaseQualities(quals);
+
+ // create the CIGAR string
+ read.setCigarString(buildTestCigarString(middleOp, lengthOfSoftClip, lengthOfFirstM, lengthOfIndel, readLength));
+
+ // now, determine whether or not there's a mismatch
+ final boolean isMismatch;
+ if ( mismatchLocation < startOnRead || mismatchLocation >= startOnRead + basesToRead || mismatchLocation < lengthOfSoftClip ) {
+ isMismatch = false;
+ } else if ( middleOp == 'M' || middleOp == 'D' || mismatchLocation < lengthOfSoftClip + lengthOfFirstM || mismatchLocation >= lengthOfSoftClip + lengthOfFirstM + lengthOfIndel ) {
+ isMismatch = true;
+ } else {
+ isMismatch = false;
+ }
+
+ tests.add(new Object[]{read, locationOnReference, startOnRead, basesToRead, isMismatch});
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Adding test to make sure soft-clipped reads go through the exceptions thrown at the beginning of the getMismatchCount method
+ // todo: incorporate cigars with right-tail soft-clips in the systematic tests above.
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 10, 20);
+ read.setReadBases(reference);
+ read.setBaseQualities(quals);
+ read.setCigarString("10S5M5S");
+ tests.add(new Object[]{read, 10, read.getAlignmentStart(), read.getReadLength(), false});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "MismatchCountDataProvider")
+ public void testMismatchCountData(final GATKSAMRecord read, final int refIndex, final int startOnRead, final int basesToRead, final boolean isMismatch) {
+ final byte[] reference = Utils.dupBytes((byte)'A', 100);
+ final int actual = AlignmentUtils.getMismatchCount(read, reference, refIndex, startOnRead, basesToRead).numMismatches;
+ Assert.assertEquals(actual, isMismatch ? 1 : 0, "Wrong number of mismatches detected for read " + read.getSAMString());
+ }
+
+ private static String buildTestCigarString(final char middleOp, final int lengthOfSoftClip, final int lengthOfFirstM, final int lengthOfIndel, final int readLength) {
+ final StringBuilder cigar = new StringBuilder();
+ int remainingLength = readLength;
+
+ // add soft clips to the beginning of the read
+ if (lengthOfSoftClip > 0 ) {
+ cigar.append(lengthOfSoftClip).append("S");
+ remainingLength -= lengthOfSoftClip;
+ }
+
+ if ( middleOp == 'M' ) {
+ cigar.append(remainingLength).append("M");
+ } else {
+ if ( lengthOfFirstM > 0 ) {
+ cigar.append(lengthOfFirstM).append("M");
+ remainingLength -= lengthOfFirstM;
+ }
+
+ if ( middleOp == 'D' ) {
+ cigar.append(lengthOfIndel).append("D");
+ } else {
+ cigar.append(lengthOfIndel).append("I");
+ remainingLength -= lengthOfIndel;
+ }
+ cigar.append(remainingLength).append("M");
+ }
+
+ return cigar.toString();
+ }
+
+ ////////////////////////////////////////////////////////
+ // Test AlignmentUtils.calcAlignmentByteArrayOffset() //
+ ////////////////////////////////////////////////////////
+
+ @DataProvider(name = "AlignmentByteArrayOffsetDataProvider")
+ public Object[][] makeAlignmentByteArrayOffsetDataProvider() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final int readLength = 20;
+ final int lengthOfIndel = 2;
+ final int locationOnReference = 20;
+
+ for ( int offset = 0; offset < readLength; offset++ ) {
+ for ( final int lengthOfSoftClip : Arrays.asList(0, 1, 10) ) {
+ for ( final int lengthOfFirstM : Arrays.asList(0, 3) ) {
+ for ( final char middleOp : Arrays.asList('M', 'D', 'I') ) {
+
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, locationOnReference, readLength);
+ // create the CIGAR string
+ read.setCigarString(buildTestCigarString(middleOp, lengthOfSoftClip, lengthOfFirstM, lengthOfIndel, readLength));
+
+ // now, determine the expected alignment offset
+ final int expected;
+ boolean isDeletion = false;
+ if ( offset < lengthOfSoftClip ) {
+ expected = 0;
+ } else if ( middleOp == 'M' || offset < lengthOfSoftClip + lengthOfFirstM ) {
+ expected = offset - lengthOfSoftClip;
+ } else if ( offset < lengthOfSoftClip + lengthOfFirstM + lengthOfIndel ) {
+ if ( middleOp == 'D' ) {
+ isDeletion = true;
+ expected = offset - lengthOfSoftClip;
+ } else {
+ expected = lengthOfFirstM;
+ }
+ } else {
+ expected = offset - lengthOfSoftClip - (middleOp == 'I' ? lengthOfIndel : -lengthOfIndel);
+ }
+
+ tests.add(new Object[]{read.getCigar(), offset, expected, isDeletion, lengthOfSoftClip});
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "AlignmentByteArrayOffsetDataProvider")
+ public void testAlignmentByteArrayOffsetData(final Cigar cigar, final int offset, final int expectedResult, final boolean isDeletion, final int lengthOfSoftClip) {
+ final int actual = AlignmentUtils.calcAlignmentByteArrayOffset(cigar, isDeletion ? -1 : offset, isDeletion, 20, 20 + offset - lengthOfSoftClip);
+ Assert.assertEquals(actual, expectedResult, "Wrong alignment offset detected for cigar " + cigar.toString());
+ }
+
+ ////////////////////////////////////////////////////
+ // Test AlignmentUtils.readToAlignmentByteArray() //
+ ////////////////////////////////////////////////////
+
+ @DataProvider(name = "ReadToAlignmentByteArrayDataProvider")
+ public Object[][] makeReadToAlignmentByteArrayDataProvider() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final int readLength = 20;
+ final int lengthOfIndel = 2;
+ final int locationOnReference = 20;
+
+ for ( final int lengthOfSoftClip : Arrays.asList(0, 1, 10) ) {
+ for ( final int lengthOfFirstM : Arrays.asList(0, 3) ) {
+ for ( final char middleOp : Arrays.asList('M', 'D', 'I') ) {
+
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, locationOnReference, readLength);
+ // create the CIGAR string
+ read.setCigarString(buildTestCigarString(middleOp, lengthOfSoftClip, lengthOfFirstM, lengthOfIndel, readLength));
+
+ // now, determine the byte array size
+ final int expected = readLength - lengthOfSoftClip - (middleOp == 'I' ? lengthOfIndel : (middleOp == 'D' ? -lengthOfIndel : 0));
+ final int indelBasesStart = middleOp != 'M' ? lengthOfFirstM : -1;
+
+ tests.add(new Object[]{read.getCigar(), expected, middleOp, indelBasesStart, lengthOfIndel});
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "ReadToAlignmentByteArrayDataProvider")
+ public void testReadToAlignmentByteArrayData(final Cigar cigar, final int expectedLength, final char middleOp, final int startOfIndelBases, final int lengthOfDeletion) {
+ final byte[] read = Utils.dupBytes((byte)'A', cigar.getReadLength());
+ final byte[] alignment = AlignmentUtils.readToAlignmentByteArray(cigar, read);
+
+ Assert.assertEquals(alignment.length, expectedLength, "Wrong alignment length detected for cigar " + cigar.toString());
+
+ for ( int i = 0; i < alignment.length; i++ ) {
+ final byte expectedBase;
+ if ( middleOp == 'D' && i >= startOfIndelBases && i < startOfIndelBases + lengthOfDeletion )
+ expectedBase = PileupElement.DELETION_BASE;
+ else if ( middleOp == 'I' && i == startOfIndelBases - 1 )
+ expectedBase = PileupElement.A_FOLLOWED_BY_INSERTION_BASE;
+ else
+ expectedBase = (byte)'A';
+ Assert.assertEquals(alignment[i], expectedBase, "Wrong base detected at position " + i);
+ }
+ }
+
+ //////////////////////////////////////////
+ // Test AlignmentUtils.leftAlignIndel() //
+ //////////////////////////////////////////
+
+ @DataProvider(name = "LeftAlignIndelDataProvider")
+ public Object[][] makeLeftAlignIndelDataProvider() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final byte[] repeat1Reference = "ABCDEFGHIJKLMNOPXXXXXXXXXXABCDEFGHIJKLMNOP".getBytes();
+ final byte[] repeat2Reference = "ABCDEFGHIJKLMNOPXYXYXYXYXYABCDEFGHIJKLMNOP".getBytes();
+ final byte[] repeat3Reference = "ABCDEFGHIJKLMNOPXYZXYZXYZXYZABCDEFGHIJKLMN".getBytes();
+ final int referenceLength = repeat1Reference.length;
+
+ for ( int indelStart = 0; indelStart < repeat1Reference.length; indelStart++ ) {
+ for ( final int indelSize : Arrays.asList(0, 1, 2, 3, 4) ) {
+ for ( final char indelOp : Arrays.asList('D', 'I') ) {
+
+ if ( indelOp == 'D' && indelStart + indelSize >= repeat1Reference.length )
+ continue;
+
+ final int readLength = referenceLength - (indelOp == 'D' ? indelSize : -indelSize);
+
+ // create the original CIGAR string
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, readLength);
+ read.setCigarString(buildTestCigarString(indelSize == 0 ? 'M' : indelOp, 0, indelStart, indelSize, readLength));
+ final Cigar originalCigar = read.getCigar();
+
+ final Cigar expectedCigar1 = makeExpectedCigar1(originalCigar, indelOp, indelStart, indelSize, readLength);
+ final byte[] readString1 = makeReadString(repeat1Reference, indelOp, indelStart, indelSize, readLength, 1);
+ tests.add(new Object[]{originalCigar, expectedCigar1, repeat1Reference, readString1, 1});
+
+ final Cigar expectedCigar2 = makeExpectedCigar2(originalCigar, indelOp, indelStart, indelSize, readLength);
+ final byte[] readString2 = makeReadString(repeat2Reference, indelOp, indelStart, indelSize, readLength, 2);
+ tests.add(new Object[]{originalCigar, expectedCigar2, repeat2Reference, readString2, 2});
+
+ final Cigar expectedCigar3 = makeExpectedCigar3(originalCigar, indelOp, indelStart, indelSize, readLength);
+ final byte[] readString3 = makeReadString(repeat3Reference, indelOp, indelStart, indelSize, readLength, 3);
+ tests.add(new Object[]{originalCigar, expectedCigar3, repeat3Reference, readString3, 3});
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ private Cigar makeExpectedCigar1(final Cigar originalCigar, final char indelOp, final int indelStart, final int indelSize, final int readLength) {
+ if ( indelSize == 0 || indelStart < 17 || indelStart > (26 - (indelOp == 'D' ? indelSize : 0)) )
+ return originalCigar;
+
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, readLength);
+ read.setCigarString(buildTestCigarString(indelOp, 0, 16, indelSize, readLength));
+ return read.getCigar();
+ }
+
+ private Cigar makeExpectedCigar2(final Cigar originalCigar, final char indelOp, final int indelStart, final int indelSize, final int readLength) {
+ if ( indelStart < 17 || indelStart > (26 - (indelOp == 'D' ? indelSize : 0)) )
+ return originalCigar;
+
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, readLength);
+
+ if ( indelOp == 'I' && (indelSize == 1 || indelSize == 3) && indelStart % 2 == 1 )
+ read.setCigarString(buildTestCigarString(indelOp, 0, Math.max(indelStart - indelSize, 16), indelSize, readLength));
+ else if ( (indelSize == 2 || indelSize == 4) && (indelOp == 'D' || indelStart % 2 == 0) )
+ read.setCigarString(buildTestCigarString(indelOp, 0, 16, indelSize, readLength));
+ else
+ return originalCigar;
+
+ return read.getCigar();
+ }
+
+ private Cigar makeExpectedCigar3(final Cigar originalCigar, final char indelOp, final int indelStart, final int indelSize, final int readLength) {
+ if ( indelStart < 17 || indelStart > (28 - (indelOp == 'D' ? indelSize : 0)) )
+ return originalCigar;
+
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 1, readLength);
+
+ if ( indelSize == 3 && (indelOp == 'D' || indelStart % 3 == 1) )
+ read.setCigarString(buildTestCigarString(indelOp, 0, 16, indelSize, readLength));
+ else if ( (indelOp == 'I' && indelSize == 4 && indelStart % 3 == 2) ||
+ (indelOp == 'I' && indelSize == 2 && indelStart % 3 == 0) ||
+ (indelOp == 'I' && indelSize == 1 && indelStart < 28 && indelStart % 3 == 2) )
+ read.setCigarString(buildTestCigarString(indelOp, 0, Math.max(indelStart - indelSize, 16), indelSize, readLength));
+ else
+ return originalCigar;
+
+ return read.getCigar();
+ }
+
+ private static byte[] makeReadString(final byte[] reference, final char indelOp, final int indelStart, final int indelSize, final int readLength, final int repeatLength) {
+ final byte[] readString = new byte[readLength];
+
+ if ( indelOp == 'D' && indelSize > 0 ) {
+ System.arraycopy(reference, 0, readString, 0, indelStart);
+ System.arraycopy(reference, indelStart + indelSize, readString, indelStart, readLength - indelStart);
+ } else if ( indelOp == 'I' && indelSize > 0 ) {
+ System.arraycopy(reference, 0, readString, 0, indelStart);
+ for ( int i = 0; i < indelSize; i++ ) {
+ if ( i % repeatLength == 0 )
+ readString[indelStart + i] = 'X';
+ else if ( i % repeatLength == 1 )
+ readString[indelStart + i] = 'Y';
+ else
+ readString[indelStart + i] = 'Z';
+ }
+ System.arraycopy(reference, indelStart, readString, indelStart + indelSize, readLength - indelStart - indelSize);
+ } else {
+ System.arraycopy(reference, 0, readString, 0, readLength);
+ }
+
+ return readString;
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "LeftAlignIndelDataProvider")
+ public void testLeftAlignIndelData(final Cigar originalCigar, final Cigar expectedCigar, final byte[] reference, final byte[] read, final int repeatLength) {
+ final Cigar actualCigar = AlignmentUtils.leftAlignIndel(originalCigar, reference, read, 0, 0, true);
+ Assert.assertTrue(expectedCigar.equals(actualCigar), "Wrong left alignment detected for cigar " + originalCigar.toString() + " to " + actualCigar.toString() + " but expected " + expectedCigar.toString() + " with repeat length " + repeatLength);
+ }
+
+ //////////////////////////////////////////
+ // Test AlignmentUtils.trimCigarByReference() //
+ //////////////////////////////////////////
+
+ @DataProvider(name = "TrimCigarData")
+ public Object[][] makeTrimCigarData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( final CigarOperator op : Arrays.asList(CigarOperator.D, CigarOperator.EQ, CigarOperator.X, CigarOperator.M) ) {
+ for ( int myLength = 1; myLength < 6; myLength++ ) {
+ for ( int start = 0; start < myLength - 1; start++ ) {
+ for ( int end = start; end < myLength; end++ ) {
+ final int length = end - start + 1;
+
+ final List<CigarOperator> padOps = Arrays.asList(CigarOperator.D, CigarOperator.M);
+ for ( final CigarOperator padOp: padOps) {
+ for ( int leftPad = 0; leftPad < 2; leftPad++ ) {
+ for ( int rightPad = 0; rightPad < 2; rightPad++ ) {
+ tests.add(new Object[]{
+ (leftPad > 0 ? leftPad + padOp.toString() : "") + myLength + op.toString() + (rightPad > 0 ? rightPad + padOp.toString() : ""),
+ start + leftPad,
+ end + leftPad,
+ length + op.toString()});
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ for ( final int leftPad : Arrays.asList(0, 1, 2, 5) ) {
+ for ( final int rightPad : Arrays.asList(0, 1, 2, 5) ) {
+ final int length = leftPad + rightPad;
+ if ( length > 0 ) {
+ for ( final int insSize : Arrays.asList(1, 10) ) {
+ for ( int start = 0; start <= leftPad; start++ ) {
+ for ( int stop = leftPad; stop < length; stop++ ) {
+ final int leftPadRemaining = leftPad - start;
+ final int rightPadRemaining = stop - leftPad + 1;
+ final String insC = insSize + "I";
+ tests.add(new Object[]{
+ leftPad + "M" + insC + rightPad + "M",
+ start,
+ stop,
+ (leftPadRemaining > 0 ? leftPadRemaining + "M" : "") + insC + (rightPadRemaining > 0 ? rightPadRemaining + "M" : "")
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+
+ tests.add(new Object[]{"3M2D4M", 0, 8, "3M2D4M"});
+ tests.add(new Object[]{"3M2D4M", 2, 8, "1M2D4M"});
+ tests.add(new Object[]{"3M2D4M", 2, 6, "1M2D2M"});
+ tests.add(new Object[]{"3M2D4M", 3, 6, "2D2M"});
+ tests.add(new Object[]{"3M2D4M", 4, 6, "1D2M"});
+ tests.add(new Object[]{"3M2D4M", 5, 6, "2M"});
+ tests.add(new Object[]{"3M2D4M", 6, 6, "1M"});
+
+ tests.add(new Object[]{"2M3I4M", 0, 5, "2M3I4M"});
+ tests.add(new Object[]{"2M3I4M", 1, 5, "1M3I4M"});
+ tests.add(new Object[]{"2M3I4M", 1, 4, "1M3I3M"});
+ tests.add(new Object[]{"2M3I4M", 2, 4, "3I3M"});
+ tests.add(new Object[]{"2M3I4M", 2, 3, "3I2M"});
+ tests.add(new Object[]{"2M3I4M", 2, 2, "3I1M"});
+ tests.add(new Object[]{"2M3I4M", 3, 4, "2M"});
+ tests.add(new Object[]{"2M3I4M", 3, 3, "1M"});
+ tests.add(new Object[]{"2M3I4M", 4, 4, "1M"});
+
+ // this doesn't work -- but I'm not sure it should
+ // tests.add(new Object[]{"2M3I4M", 2, 1, "3I"});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "TrimCigarData", enabled = ! DEBUG)
+ public void testTrimCigar(final String cigarString, final int start, final int length, final String expectedCigarString) {
+ final Cigar cigar = TextCigarCodec.getSingleton().decode(cigarString);
+ final Cigar expectedCigar = TextCigarCodec.getSingleton().decode(expectedCigarString);
+ final Cigar actualCigar = AlignmentUtils.trimCigarByReference(cigar, start, length);
+ Assert.assertEquals(actualCigar, expectedCigar);
+ }
+
+ @DataProvider(name = "TrimCigarByBasesData")
+ public Object[][] makeTrimCigarByBasesData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ tests.add(new Object[]{"2M3I4M", 0, 8, "2M3I4M"});
+ tests.add(new Object[]{"2M3I4M", 1, 8, "1M3I4M"});
+ tests.add(new Object[]{"2M3I4M", 2, 8, "3I4M"});
+ tests.add(new Object[]{"2M3I4M", 3, 8, "2I4M"});
+ tests.add(new Object[]{"2M3I4M", 4, 8, "1I4M"});
+ tests.add(new Object[]{"2M3I4M", 4, 7, "1I3M"});
+ tests.add(new Object[]{"2M3I4M", 4, 6, "1I2M"});
+ tests.add(new Object[]{"2M3I4M", 4, 5, "1I1M"});
+ tests.add(new Object[]{"2M3I4M", 4, 4, "1I"});
+ tests.add(new Object[]{"2M3I4M", 5, 5, "1M"});
+
+ tests.add(new Object[]{"2M2D2I", 0, 3, "2M2D2I"});
+ tests.add(new Object[]{"2M2D2I", 1, 3, "1M2D2I"});
+ tests.add(new Object[]{"2M2D2I", 2, 3, "2D2I"});
+ tests.add(new Object[]{"2M2D2I", 3, 3, "1I"});
+ tests.add(new Object[]{"2M2D2I", 2, 2, "2D1I"});
+ tests.add(new Object[]{"2M2D2I", 1, 2, "1M2D1I"});
+ tests.add(new Object[]{"2M2D2I", 0, 1, "2M2D"});
+ tests.add(new Object[]{"2M2D2I", 1, 1, "1M2D"});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "TrimCigarByBasesData", enabled = !DEBUG)
+ public void testTrimCigarByBase(final String cigarString, final int start, final int length, final String expectedCigarString) {
+ final Cigar cigar = TextCigarCodec.getSingleton().decode(cigarString);
+ final Cigar expectedCigar = TextCigarCodec.getSingleton().decode(expectedCigarString);
+ final Cigar actualCigar = AlignmentUtils.trimCigarByBases(cigar, start, length);
+ Assert.assertEquals(actualCigar, expectedCigar);
+ }
+
+ //////////////////////////////////////////
+ // Test AlignmentUtils.applyCigarToCigar() //
+ //////////////////////////////////////////
+
+ @DataProvider(name = "ApplyCigarToCigarData")
+ public Object[][] makeApplyCigarToCigarData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ for ( int i = 1; i < 5; i++ )
+ tests.add(new Object[]{i + "M", i + "M", i + "M"});
+
+// * ref : ACGTAC
+// * hap : AC---C - 2M3D1M
+// * read : AC---C - 3M
+// * result: AG---C => 2M3D
+ tests.add(new Object[]{"3M", "2M3D1M", "2M3D1M"});
+
+// * ref : ACxG-TA
+// * hap : AC-G-TA - 2M1D3M
+// * read : AC-GxTA - 3M1I2M
+// * result: AC-GxTA => 2M1D1M1I2M
+ tests.add(new Object[]{"3M1I2M", "2M1D3M", "2M1D1M1I2M"});
+
+// * ref : A-CGTA
+// * hap : A-CGTA - 5M
+// * read : AxCGTA - 1M1I4M
+// * result: AxCGTA => 1M1I4M
+ tests.add(new Object[]{"1M1I4M", "5M", "1M1I4M"});
+
+// * ref : ACGTA
+// * hap : ACGTA - 5M
+// * read : A--TA - 1M2D2M
+// * result: A--TA => 1M2D2M
+ tests.add(new Object[]{"1M2D2M", "5M", "1M2D2M"});
+
+// * ref : AC-GTA
+// * hap : ACxGTA - 2M1I3M
+// * read : A--GTA - 1M2D3M
+// * result: A--GTA => 1M1D3M
+ tests.add(new Object[]{"108M14D24M2M18I29M92M1000M", "2M1I3M", "2M1I3M"});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "ApplyCigarToCigarData", enabled = !DEBUG)
+ public void testApplyCigarToCigar(final String firstToSecondString, final String secondToThirdString, final String expectedCigarString) {
+ final Cigar firstToSecond = TextCigarCodec.getSingleton().decode(firstToSecondString);
+ final Cigar secondToThird = TextCigarCodec.getSingleton().decode(secondToThirdString);
+ final Cigar expectedCigar = TextCigarCodec.getSingleton().decode(expectedCigarString);
+ final Cigar actualCigar = AlignmentUtils.applyCigarToCigar(firstToSecond, secondToThird);
+ Assert.assertEquals(actualCigar, expectedCigar);
+ }
+
+ //////////////////////////////////////////
+ // Test AlignmentUtils.applyCigarToCigar() //
+ //////////////////////////////////////////
+
+ @DataProvider(name = "ReadOffsetFromCigarData")
+ public Object[][] makeReadOffsetFromCigarData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final int SIZE = 10;
+ for ( int i = 0; i < SIZE; i++ ) {
+ tests.add(new Object[]{SIZE + "M", i, i});
+ }
+
+ // 0123ii45
+ // ref : ACGT--AC
+ // hap : AC--xxAC (2M2D2I2M)
+ // ref.pos: 01 45
+ tests.add(new Object[]{"2M2D2I2M", 0, 0});
+ tests.add(new Object[]{"2M2D2I2M", 1, 1});
+ tests.add(new Object[]{"2M2D2I2M", 2, 4});
+ tests.add(new Object[]{"2M2D2I2M", 3, 4});
+ tests.add(new Object[]{"2M2D2I2M", 4, 4});
+ tests.add(new Object[]{"2M2D2I2M", 5, 5});
+
+ // 10132723 - 10132075 - 500 = 148
+ // what's the offset of the first match after the I?
+ // 108M + 14D + 24M + 2M = 148
+ // What's the offset of the first base that is after the I?
+ // 108M + 24M + 2M + 18I = 134M + 18I = 152 - 1 = 151
+ tests.add(new Object[]{"108M14D24M2M18I29M92M", 0, 0});
+ tests.add(new Object[]{"108M14D24M2M18I29M92M", 107, 107});
+ tests.add(new Object[]{"108M14D24M2M18I29M92M", 108, 108 + 14}); // first base after the deletion
+
+ tests.add(new Object[]{"108M14D24M2M18I29M92M", 132, 132+14}); // 2 before insertion
+ tests.add(new Object[]{"108M14D24M2M18I29M92M", 133, 133+14}); // last base before insertion
+
+ // entering into the insertion
+ for ( int i = 0; i < 18; i++ ) {
+ tests.add(new Object[]{"108M14D24M2M18I29M92M", 134+i, 148}); // inside insertion
+ }
+ tests.add(new Object[]{"108M14D24M2M18I29M92M", 134+18, 148}); // first base after insertion matches at same as insertion
+ tests.add(new Object[]{"108M14D24M2M18I29M92M", 134+18+1, 149});
+ tests.add(new Object[]{"108M14D24M2M18I29M92M", 134+18+2, 150});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "ReadOffsetFromCigarData", enabled = !DEBUG)
+ public void testReadOffsetFromCigar(final String cigarString, final int startOnCigar, final int expectedOffset) {
+ final Cigar cigar = TextCigarCodec.getSingleton().decode(cigarString);
+ final int actualOffset = AlignmentUtils.calcFirstBaseMatchingReferenceInCigar(cigar, startOnCigar);
+ Assert.assertEquals(actualOffset, expectedOffset);
+ }
+
+ //////////////////////////////////////////
+ // Test AlignmentUtils.addCigarElements() //
+ //////////////////////////////////////////
+
+ @DataProvider(name = "AddCigarElementsData")
+ public Object[][] makeAddCigarElementsData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final int SIZE = 10;
+ for ( final CigarOperator op : Arrays.asList(CigarOperator.I, CigarOperator.M, CigarOperator.S, CigarOperator.EQ, CigarOperator.X)) {
+ for ( int start = 0; start < SIZE; start++ ) {
+ for ( int end = start; end < SIZE * 2; end ++ ) {
+ for ( int pos = 0; pos < SIZE * 3; pos++ ) {
+ int length = 0;
+ for ( int i = 0; i < SIZE; i++ ) length += (i+pos) >= start && (i+pos) <= end ? 1 : 0;
+ tests.add(new Object[]{SIZE + op.toString(), pos, start, end, length > 0 ? length + op.toString() : "*"});
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "AddCigarElementsData", enabled = !DEBUG)
+ public void testAddCigarElements(final String cigarString, final int pos, final int start, final int end, final String expectedCigarString) {
+ final Cigar cigar = TextCigarCodec.getSingleton().decode(cigarString);
+ final CigarElement elt = cigar.getCigarElement(0);
+ final Cigar expectedCigar = TextCigarCodec.getSingleton().decode(expectedCigarString);
+
+ final List<CigarElement> elts = new LinkedList<CigarElement>();
+ final int actualEndPos = AlignmentUtils.addCigarElements(elts, pos, start, end, elt);
+
+ Assert.assertEquals(actualEndPos, pos + elt.getLength());
+ Assert.assertEquals(AlignmentUtils.consolidateCigar(new Cigar(elts)), expectedCigar);
+ }
+
+ @DataProvider(name = "GetBasesCoveringRefIntervalData")
+ public Object[][] makeGetBasesCoveringRefIntervalData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ // matches
+ // 0123
+ // ACGT
+ tests.add(new Object[]{"ACGT", 0, 3, "4M", "ACGT"});
+ tests.add(new Object[]{"ACGT", 1, 3, "4M", "CGT"});
+ tests.add(new Object[]{"ACGT", 1, 2, "4M", "CG"});
+ tests.add(new Object[]{"ACGT", 1, 1, "4M", "C"});
+
+ // deletions
+ // 012345
+ // AC--GT
+ tests.add(new Object[]{"ACGT", 0, 5, "2M2D2M", "ACGT"});
+ tests.add(new Object[]{"ACGT", 1, 5, "2M2D2M", "CGT"});
+ tests.add(new Object[]{"ACGT", 2, 5, "2M2D2M", null});
+ tests.add(new Object[]{"ACGT", 3, 5, "2M2D2M", null});
+ tests.add(new Object[]{"ACGT", 4, 5, "2M2D2M", "GT"});
+ tests.add(new Object[]{"ACGT", 5, 5, "2M2D2M", "T"});
+ tests.add(new Object[]{"ACGT", 0, 4, "2M2D2M", "ACG"});
+ tests.add(new Object[]{"ACGT", 0, 3, "2M2D2M", null});
+ tests.add(new Object[]{"ACGT", 0, 2, "2M2D2M", null});
+ tests.add(new Object[]{"ACGT", 0, 1, "2M2D2M", "AC"});
+ tests.add(new Object[]{"ACGT", 0, 0, "2M2D2M", "A"});
+
+ // insertions
+ // 01--23
+ // ACTTGT
+ tests.add(new Object[]{"ACTTGT", 0, 3, "2M2I2M", "ACTTGT"});
+ tests.add(new Object[]{"ACTTGT", 1, 3, "2M2I2M", "CTTGT"});
+ tests.add(new Object[]{"ACTTGT", 2, 3, "2M2I2M", "GT"});
+ tests.add(new Object[]{"ACTTGT", 3, 3, "2M2I2M", "T"});
+ tests.add(new Object[]{"ACTTGT", 0, 2, "2M2I2M", "ACTTG"});
+ tests.add(new Object[]{"ACTTGT", 0, 1, "2M2I2M", "AC"});
+ tests.add(new Object[]{"ACTTGT", 1, 2, "2M2I2M", "CTTG"});
+ tests.add(new Object[]{"ACTTGT", 2, 2, "2M2I2M", "G"});
+ tests.add(new Object[]{"ACTTGT", 1, 1, "2M2I2M", "C"});
+
+ tests.add(new Object[]{"ACGT", 0, 1, "2M2I", "AC"});
+ tests.add(new Object[]{"ACGT", 1, 1, "2M2I", "C"});
+ tests.add(new Object[]{"ACGT", 0, 0, "2M2I", "A"});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "GetBasesCoveringRefIntervalData", enabled = true)
+ public void testGetBasesCoveringRefInterval(final String basesString, final int refStart, final int refEnd, final String cigarString, final String expected) {
+ final byte[] actualBytes = AlignmentUtils.getBasesCoveringRefInterval(refStart, refEnd, basesString.getBytes(), 0, TextCigarCodec.getSingleton().decode(cigarString));
+ if ( expected == null )
+ Assert.assertNull(actualBytes);
+ else
+ Assert.assertEquals(new String(actualBytes), expected);
+ }
+
+ @DataProvider(name = "StartsOrEndsWithInsertionOrDeletionData")
+ public Object[][] makeStartsOrEndsWithInsertionOrDeletionData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ tests.add(new Object[]{"2M", false});
+ tests.add(new Object[]{"1D2M", true});
+ tests.add(new Object[]{"2M1D", true});
+ tests.add(new Object[]{"2M1I", true});
+ tests.add(new Object[]{"1I2M", true});
+ tests.add(new Object[]{"1M1I2M", false});
+ tests.add(new Object[]{"1M1D2M", false});
+ tests.add(new Object[]{"1M1I2M1I", true});
+ tests.add(new Object[]{"1M1I2M1D", true});
+ tests.add(new Object[]{"1D1M1I2M", true});
+ tests.add(new Object[]{"1I1M1I2M", true});
+ tests.add(new Object[]{"1M1I2M1I1M", false});
+ tests.add(new Object[]{"1M1I2M1D1M", false});
+ tests.add(new Object[]{"1M1D2M1D1M", false});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "StartsOrEndsWithInsertionOrDeletionData", enabled = true)
+ public void testStartsOrEndsWithInsertionOrDeletion(final String cigar, final boolean expected) {
+ Assert.assertEquals(AlignmentUtils.startsOrEndsWithInsertionOrDeletion(TextCigarCodec.getSingleton().decode(cigar)), expected);
+ }
+
+ @Test(dataProvider = "StartsOrEndsWithInsertionOrDeletionData", enabled = true)
+ public void testRemoveTrailingDeletions(final String cigar, final boolean expected) {
+
+ final Cigar originalCigar = TextCigarCodec.getSingleton().decode(cigar);
+ final Cigar newCigar = AlignmentUtils.removeTrailingDeletions(originalCigar);
+
+ Assert.assertEquals(originalCigar.equals(newCigar), !cigar.endsWith("D"));
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialBAMBuilderUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialBAMBuilderUnitTest.java
new file mode 100644
index 0000000..b7042a6
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialBAMBuilderUnitTest.java
@@ -0,0 +1,121 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileReader;
+import htsjdk.samtools.SAMRecord;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: depristo
+ * Date: 1/15/13
+ * Time: 3:49 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ArtificialBAMBuilderUnitTest extends BaseTest {
+ @DataProvider(name = "ArtificialBAMBuilderUnitTestProvider")
+ public Object[][] makeArtificialBAMBuilderUnitTestProvider() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ final List<Integer> starts = Arrays.asList(
+ 1, // very start of the chromosome
+ ArtificialBAMBuilder.BAM_SHARD_SIZE - 100, // right before the shard boundary
+ ArtificialBAMBuilder.BAM_SHARD_SIZE + 100 // right after the shard boundary
+ );
+
+ for ( final int readLength : Arrays.asList(10, 20) ) {
+ for ( final int skips : Arrays.asList(0, 1, 10) ) {
+ for ( final int start : starts ) {
+ for ( final int nSamples : Arrays.asList(1, 2) ) {
+ for ( final int nReadsPerLocus : Arrays.asList(1, 10) ) {
+ for ( final int nLoci : Arrays.asList(10, 100, 1000) ) {
+ final ArtificialBAMBuilder bamBuilder = new ArtificialBAMBuilder(nReadsPerLocus, nLoci);
+ bamBuilder.setReadLength(readLength);
+ bamBuilder.setSkipNLoci(skips);
+ bamBuilder.setAlignmentStart(start);
+ bamBuilder.createAndSetHeader(nSamples);
+ tests.add(new Object[]{bamBuilder, readLength, skips, start, nSamples, nReadsPerLocus, nLoci});
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "ArtificialBAMBuilderUnitTestProvider")
+ public void testBamProvider(final ArtificialBAMBuilder bamBuilder, int readLength, int skips, int start, int nSamples, int nReadsPerLocus, int nLoci) {
+ Assert.assertEquals(bamBuilder.getReadLength(), readLength);
+ Assert.assertEquals(bamBuilder.getSkipNLoci(), skips);
+ Assert.assertEquals(bamBuilder.getAlignmentStart(), start);
+ Assert.assertEquals(bamBuilder.getNSamples(), nSamples);
+ Assert.assertEquals(bamBuilder.getnReadsPerLocus(), nReadsPerLocus);
+ Assert.assertEquals(bamBuilder.getnLoci(), nLoci);
+
+ final List<GATKSAMRecord> reads = bamBuilder.makeReads();
+ Assert.assertEquals(reads.size(), bamBuilder.expectedNumberOfReads());
+ for ( final GATKSAMRecord read : reads ) {
+ assertGoodRead(read, bamBuilder);
+ }
+
+ final File bam = bamBuilder.makeTemporarilyBAMFile();
+ final SAMFileReader reader = new SAMFileReader(bam);
+ Assert.assertTrue(reader.hasIndex());
+ final Iterator<SAMRecord> bamIt = reader.iterator();
+ int nReadsFromBam = 0;
+ int lastStart = -1;
+ while ( bamIt.hasNext() ) {
+ final SAMRecord read = bamIt.next();
+ assertGoodRead(read, bamBuilder);
+ nReadsFromBam++;
+ Assert.assertTrue(read.getAlignmentStart() >= lastStart);
+ lastStart = read.getAlignmentStart();
+ }
+ Assert.assertEquals(nReadsFromBam, bamBuilder.expectedNumberOfReads());
+ }
+
+ private void assertGoodRead(final SAMRecord read, final ArtificialBAMBuilder bamBuilder) {
+ Assert.assertEquals(read.getReadLength(), bamBuilder.getReadLength());
+ Assert.assertEquals(read.getReadBases().length, bamBuilder.getReadLength());
+ Assert.assertEquals(read.getBaseQualities().length, bamBuilder.getReadLength());
+ Assert.assertTrue(read.getAlignmentStart() >= bamBuilder.getAlignmentStart());
+ Assert.assertNotNull(read.getReadGroup());
+ }
+}
+
+
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialPatternedSAMIteratorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialPatternedSAMIteratorUnitTest.java
new file mode 100644
index 0000000..fe5fba7
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialPatternedSAMIteratorUnitTest.java
@@ -0,0 +1,122 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMRecord;
+
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ *
+ * @author aaron
+ *
+ * Class ArtificialPatternedSAMIteratorUnitTest
+ *
+ * tests ArtificialPatternedSAMIterator, making sure that if you specify in order
+ * you get reads in order, and if you specify out of order you get them out of order.
+ */
+public class ArtificialPatternedSAMIteratorUnitTest extends BaseTest {
+
+ // our artifical patterned iterator
+ ArtificialPatternedSAMIterator iter;
+
+ private int startingChr = 1;
+ private int endingChr = 2;
+ private int readCount = 100;
+ private int DEFAULT_READ_LENGTH = ArtificialSAMUtils.DEFAULT_READ_LENGTH;
+ SAMFileHeader header;
+
+ @BeforeMethod
+ public void before() {
+ header = ArtificialSAMUtils.createArtificialSamHeader(( endingChr - startingChr ) + 1, startingChr, readCount + DEFAULT_READ_LENGTH);
+
+ }
+ @Test
+ public void testInOrder() {
+ iter = new ArtificialPatternedSAMIterator(startingChr,endingChr,readCount,0,header, ArtificialPatternedSAMIterator.PATTERN.IN_ORDER_READS);
+ if (!iter.hasNext()) {
+ fail("no reads in the ArtificialPatternedSAMIterator");
+ }
+ SAMRecord last = iter.next();
+ while (iter.hasNext()) {
+ SAMRecord rec = iter.next();
+ if (!(rec.getReferenceIndex() > last.getReferenceIndex()) && (rec.getAlignmentStart() <= last.getAlignmentStart())) {
+ fail("read " + rec.getReadName() + " out of order compared to last read, " + last.getReadName());
+ }
+ last = rec;
+ }
+
+ }
+ @Test
+ public void testOutOfOrder() {
+ int outOfOrderCount = 0;
+ iter = new ArtificialPatternedSAMIterator(startingChr,endingChr,readCount,0,header, ArtificialPatternedSAMIterator.PATTERN.RANDOM_READS);
+ if (!iter.hasNext()) {
+ fail("no reads in the ArtificialPatternedSAMIterator");
+ }
+ SAMRecord last = iter.next();
+ while (iter.hasNext()) {
+ SAMRecord rec = iter.next();
+ if (!(rec.getReferenceIndex() > last.getReferenceIndex()) && (rec.getAlignmentStart() <= last.getAlignmentStart())) {
+ ++outOfOrderCount;
+ }
+ last = rec;
+ }
+ assertTrue(outOfOrderCount > 0);
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMFileWriterUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMFileWriterUnitTest.java
new file mode 100644
index 0000000..d527624
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMFileWriterUnitTest.java
@@ -0,0 +1,120 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.broadinstitute.gatk.utils.BaseTest;
+import htsjdk.samtools.SAMRecord;
+import htsjdk.samtools.SAMFileHeader;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author aaron
+ * <p/>
+ * Class ArtificialGATKSAMFileWriter
+ * <p/>
+ * Test out the ArtificialGATKSAMFileWriter class
+ */
+public class ArtificialSAMFileWriterUnitTest extends BaseTest {
+
+ /** the artificial sam writer */
+ private ArtificialGATKSAMFileWriter writer;
+ private SAMFileHeader header;
+ private final int startChr = 1;
+ private final int numChr = 2;
+ private final int chrSize = 100;
+
+ @BeforeMethod
+ public void before() {
+ writer = new ArtificialGATKSAMFileWriter();
+ header = ArtificialSAMUtils.createArtificialSamHeader(numChr, startChr, chrSize);
+ }
+
+ @Test
+ public void testBasicCount() {
+ for (int x = 1; x <= 100; x++) {
+ SAMRecord rec = ArtificialSAMUtils.createArtificialRead(header, String.valueOf(x), 1, x, ArtificialSAMUtils.DEFAULT_READ_LENGTH);
+ writer.addAlignment(rec);
+ }
+ assertEquals(writer.getRecords().size(), 100);
+
+ }
+
+ @Test
+ public void testReadName() {
+ List<String> names = new ArrayList<String>();
+
+ for (int x = 1; x <= 100; x++) {
+ names.add(String.valueOf(x));
+ SAMRecord rec = ArtificialSAMUtils.createArtificialRead(header, String.valueOf(x), 1, x, ArtificialSAMUtils.DEFAULT_READ_LENGTH);
+ writer.addAlignment(rec);
+ }
+ assertEquals(writer.getRecords().size(), 100);
+
+ // check the names
+ for (int x = 0; x < 100; x++) {
+ assertTrue(names.get(x).equals(writer.getRecords().get(x).getReadName()));
+ }
+
+ }
+
+ @Test
+ public void testClose() {
+ writer.close();
+ assertTrue(writer.isClosed());
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMQueryIteratorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMQueryIteratorUnitTest.java
new file mode 100644
index 0000000..32409c6
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMQueryIteratorUnitTest.java
@@ -0,0 +1,138 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Test;
+import htsjdk.samtools.SAMRecord;
+
+
+/*
+ * Copyright (c) 2009 The Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * @author aaron
+ * <p/>
+ * Class ArtificialSAMQueryIteratorUnitTest
+ * <p/>
+ * a test for the ArtificialSAMQueryIterator class.
+ */
+public class ArtificialSAMQueryIteratorUnitTest extends BaseTest {
+
+ @Test
+ public void testWholeChromosomeQuery() {
+ ArtificialSAMQueryIterator iter = ArtificialSAMUtils.queryReadIterator(1, 2, 100);
+ iter.queryContained("chr1", 1, -1);
+ int count = 0;
+ while (iter.hasNext()) {
+ SAMRecord rec = iter.next();
+ count++;
+ }
+ assertEquals(count, 100);
+
+ }
+
+ @Test
+ public void testContainedQueryStart() {
+ ArtificialSAMQueryIterator iter = ArtificialSAMUtils.queryReadIterator(1, 2, 100);
+ iter.queryContained("chr1", 1, 50);
+ int count = 0;
+ while (iter.hasNext()) {
+ SAMRecord rec = iter.next();
+ count++;
+ }
+ assertEquals(count, 1);
+
+ }
+
+ @Test
+ public void testOverlappingQueryStart() {
+ ArtificialSAMQueryIterator iter = ArtificialSAMUtils.queryReadIterator(1, 2, 100);
+ iter.queryOverlapping("chr1", 1, 50);
+ int count = 0;
+ while (iter.hasNext()) {
+ SAMRecord rec = iter.next();
+ count++;
+ }
+ assertEquals(count, 50);
+
+ }
+
+ @Test
+ public void testContainedQueryMiddle() {
+ ArtificialSAMQueryIterator iter = ArtificialSAMUtils.queryReadIterator(1, 2, 100);
+ iter.queryContained("chr1", 25, 74);
+ int count = 0;
+ while (iter.hasNext()) {
+ SAMRecord rec = iter.next();
+ count++;
+ }
+ assertEquals(count, 1);
+
+ }
+
+ @Test
+ public void testOverlappingQueryMiddle() {
+ ArtificialSAMQueryIterator iter = ArtificialSAMUtils.queryReadIterator(1, 2, 100);
+ iter.queryOverlapping("chr1", 25, 74);
+ int count = 0;
+ while (iter.hasNext()) {
+ SAMRecord rec = iter.next();
+ count++;
+ }
+ assertEquals(count, 50);
+
+ }
+
+ @Test(expectedExceptions=IllegalArgumentException.class)
+ public void testUnknownChromosome() {
+ ArtificialSAMQueryIterator iter = ArtificialSAMUtils.queryReadIterator(1, 2, 100);
+ iter.queryOverlapping("chr621", 25, 74);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMUtilsUnitTest.java
new file mode 100644
index 0000000..48ad212
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSAMUtilsUnitTest.java
@@ -0,0 +1,108 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.iterators.GATKSAMIterator;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+import org.testng.annotations.Test;
+import htsjdk.samtools.SAMRecord;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: aaronmckenna
+ * Date: Jun 3, 2009
+ * Time: 3:09:34 AM
+ * To change this template use File | Settings | File Templates.
+ */
+public class ArtificialSAMUtilsUnitTest extends BaseTest {
+
+
+ @Test
+ public void basicReadIteratorTest() {
+ GATKSAMIterator iter = ArtificialSAMUtils.mappedReadIterator(1, 100, 100);
+ int count = 0;
+ while (iter.hasNext()) {
+ SAMRecord rec = iter.next();
+ count++;
+ }
+ assertEquals(count, 100 * 100);
+ }
+
+ @Test
+ public void tenPerChromosome() {
+ GATKSAMIterator iter = ArtificialSAMUtils.mappedReadIterator(1, 100, 10);
+ int count = 0;
+ while (iter.hasNext()) {
+ SAMRecord rec = iter.next();
+
+ assertEquals(Integer.valueOf(Math.round(count / 10)), rec.getReferenceIndex());
+ count++;
+ }
+ assertEquals(count, 100 * 10);
+ }
+
+ @Test
+ public void onePerChromosome() {
+ GATKSAMIterator iter = ArtificialSAMUtils.mappedReadIterator(1, 100, 1);
+ int count = 0;
+ while (iter.hasNext()) {
+ SAMRecord rec = iter.next();
+
+ assertEquals(Integer.valueOf(count), rec.getReferenceIndex());
+ count++;
+ }
+ assertEquals(count, 100 * 1);
+ }
+
+ @Test
+ public void basicUnmappedIteratorTest() {
+ GATKSAMIterator iter = ArtificialSAMUtils.mappedAndUnmappedReadIterator(1, 100, 100, 1000);
+ int count = 0;
+ for (int x = 0; x < (100* 100); x++ ) {
+ if (!iter.hasNext()) {
+ fail ("we didn't get the expected number of reads");
+ }
+ SAMRecord rec = iter.next();
+ assertTrue(rec.getReferenceIndex() >= 0);
+ count++;
+ }
+ assertEquals(100 * 100, count);
+
+ // now we should have 1000 unmapped reads
+ count = 0;
+ while (iter.hasNext()) {
+ SAMRecord rec = iter.next();
+ assertTrue(rec.getReferenceIndex() < 0);
+ count++;
+ }
+ assertEquals(count, 1000);
+ }
+
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSingleSampleReadStreamUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSingleSampleReadStreamUnitTest.java
new file mode 100644
index 0000000..271a75a
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ArtificialSingleSampleReadStreamUnitTest.java
@@ -0,0 +1,186 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileHeader;
+import htsjdk.samtools.SAMReadGroupRecord;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+
+public class ArtificialSingleSampleReadStreamUnitTest extends BaseTest {
+
+ private static class ArtificialSingleSampleReadStreamTest extends TestDataProvider {
+ private ArtificialSingleSampleReadStream stream;
+ private ArtificialSingleSampleReadStreamAnalyzer streamAnalyzer;
+
+ public ArtificialSingleSampleReadStreamTest( ArtificialSingleSampleReadStream stream ) {
+ super(ArtificialSingleSampleReadStreamTest.class);
+
+ this.stream = stream;
+
+ setName(String.format("%s: numContigs=%d stacksPerContig=%d readsPerStack=%d-%d distanceBetweenStacks=%d-%d readLength=%d-%d unmappedReads=%d",
+ getClass().getSimpleName(),
+ stream.getNumContigs(),
+ stream.getNumStacksPerContig(),
+ stream.getMinReadsPerStack(),
+ stream.getMaxReadsPerStack(),
+ stream.getMinDistanceBetweenStacks(),
+ stream.getMaxDistanceBetweenStacks(),
+ stream.getMinReadLength(),
+ stream.getMaxReadLength(),
+ stream.getNumUnmappedReads()));
+ }
+
+ public void run() {
+ streamAnalyzer= new ArtificialSingleSampleReadStreamAnalyzer(stream);
+
+ streamAnalyzer.analyze(stream);
+
+ // Check whether the observed properties of the stream match its nominal properties
+ streamAnalyzer.validate();
+ }
+ }
+
+ @DataProvider(name = "ArtificialSingleSampleReadStreamTestDataProvider")
+ public Object[][] createArtificialSingleSampleReadStreamTests() {
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(3, 1, 10000);
+ String readGroupID = "testReadGroup";
+ SAMReadGroupRecord readGroup = new SAMReadGroupRecord(readGroupID);
+ readGroup.setSample("testSample");
+ header.addReadGroup(readGroup);
+
+ GenomeAnalysisEngine.resetRandomGenerator();
+
+ // brute force testing!
+ for ( int numContigs = 0; numContigs <= 2; numContigs++ ) {
+ for ( int stacksPerContig = 0; stacksPerContig <= 2; stacksPerContig++ ) {
+ for ( int minReadsPerStack = 1; minReadsPerStack <= 2; minReadsPerStack++ ) {
+ for ( int maxReadsPerStack = 1; maxReadsPerStack <= 3; maxReadsPerStack++ ) {
+ for ( int minDistanceBetweenStacks = 1; minDistanceBetweenStacks <= 2; minDistanceBetweenStacks++ ) {
+ for ( int maxDistanceBetweenStacks = 1; maxDistanceBetweenStacks <= 3; maxDistanceBetweenStacks++ ) {
+ for ( int minReadLength = 1; minReadLength <= 2; minReadLength++ ) {
+ for ( int maxReadLength = 1; maxReadLength <= 3; maxReadLength++ ) {
+ for ( int numUnmappedReads = 0; numUnmappedReads <= 2; numUnmappedReads++ ) {
+ // Only test sane combinations here
+ if ( minReadsPerStack <= maxReadsPerStack &&
+ minDistanceBetweenStacks <= maxDistanceBetweenStacks &&
+ minReadLength <= maxReadLength &&
+ ((numContigs > 0 && stacksPerContig > 0) || (numContigs == 0 && stacksPerContig == 0)) ) {
+
+ new ArtificialSingleSampleReadStreamTest(new ArtificialSingleSampleReadStream(header,
+ readGroupID,
+ numContigs,
+ stacksPerContig,
+ minReadsPerStack,
+ maxReadsPerStack,
+ minDistanceBetweenStacks,
+ maxDistanceBetweenStacks,
+ minReadLength,
+ maxReadLength,
+ numUnmappedReads));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return ArtificialSingleSampleReadStreamTest.getTests(ArtificialSingleSampleReadStreamTest.class);
+ }
+
+ @Test(dataProvider = "ArtificialSingleSampleReadStreamTestDataProvider")
+ public void testArtificialSingleSampleReadStream( ArtificialSingleSampleReadStreamTest test ) {
+ logger.warn("Running test: " + test);
+
+ GenomeAnalysisEngine.resetRandomGenerator();
+ test.run();
+ }
+
+ @DataProvider(name = "ArtificialSingleSampleReadStreamInvalidArgumentsTestDataProvider")
+ public Object[][] createInvalidArgumentsTests() {
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(3, 1, 10000);
+ String readGroupID = "testReadGroup";
+ header.addReadGroup(new SAMReadGroupRecord(readGroupID));
+
+ return new Object[][] {
+ {"testNullHeader", null, readGroupID, 1, 1, 1, 2, 1, 2, 1, 2, 0},
+ {"testNullReadGroup", header, null, 1, 1, 1, 2, 1, 2, 1, 2, 0},
+ {"testInvalidReadGroup", header, "foo", 1, 1, 1, 2, 1, 2, 1, 2, 0},
+ {"testInvalidNumContigs", header, readGroupID, -1, 1, 1, 2, 1, 2, 1, 2, 0},
+ {"testInvalidNumStacksPerContig", header, readGroupID, 1, -1, 1, 2, 1, 2, 1, 2, 0},
+ {"test0ContigsNon0StacksPerContig", header, readGroupID, 0, 1, 1, 2, 1, 2, 1, 2, 0},
+ {"testNon0Contigs0StacksPerContig", header, readGroupID, 1, 0, 1, 2, 1, 2, 1, 2, 0},
+ {"testInvalidMinReadsPerStack", header, readGroupID, 1, 1, -1, 2, 1, 2, 1, 2, 0},
+ {"testInvalidMaxReadsPerStack", header, readGroupID, 1, 1, 1, -2, 1, 2, 1, 2, 0},
+ {"testInvalidMinDistanceBetweenStacks", header, readGroupID, 1, 1, 1, 2, -1, 2, 1, 2, 0},
+ {"testInvalidMaxDistanceBetweenStacks", header, readGroupID, 1, 1, 1, 2, 1, -2, 1, 2, 0},
+ {"testInvalidMinReadLength", header, readGroupID, 1, 1, 1, 2, 1, 2, -1, 2, 0},
+ {"testInvalidMaxReadLength", header, readGroupID, 1, 1, 1, 2, 1, 2, 1, -2, 0},
+ {"testInvalidReadsPerStackRange", header, readGroupID, 1, 1, 2, 1, 1, 2, 1, 2, 0},
+ {"testInvalidDistanceBetweenStacksRange", header, readGroupID, 1, 1, 1, 2, 2, 1, 1, 2, 0},
+ {"testInvalidReadLengthRange", header, readGroupID, 1, 1, 1, 2, 1, 2, 2, 1, 0},
+ {"testInvalidNumUnmappedReads", header, readGroupID, 1, 1, 1, 2, 1, 2, 1, 2, -1},
+ };
+ }
+
+ @Test(dataProvider = "ArtificialSingleSampleReadStreamInvalidArgumentsTestDataProvider",
+ expectedExceptions = ReviewedGATKException.class)
+ public void testInvalidArguments( String testName,
+ SAMFileHeader header,
+ String readGroupID,
+ int numContigs,
+ int numStacksPerContig,
+ int minReadsPerStack,
+ int maxReadsPerStack,
+ int minDistanceBetweenStacks,
+ int maxDistanceBetweenStacks,
+ int minReadLength,
+ int maxReadLength,
+ int numUnmappedReads ) {
+
+ logger.warn("Running test: " + testName);
+
+ ArtificialSingleSampleReadStream stream = new ArtificialSingleSampleReadStream(header,
+ readGroupID,
+ numContigs,
+ numStacksPerContig,
+ minReadsPerStack,
+ maxReadsPerStack,
+ minDistanceBetweenStacks,
+ maxDistanceBetweenStacks,
+ minReadLength,
+ maxReadLength,
+ numUnmappedReads);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/GATKSAMRecordUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/GATKSAMRecordUnitTest.java
new file mode 100644
index 0000000..e703c52
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/GATKSAMRecordUnitTest.java
@@ -0,0 +1,78 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+public class GATKSAMRecordUnitTest extends BaseTest {
+ GATKSAMRecord read;
+ final static String BASES = "ACTG";
+ final static String QUALS = "!+5?";
+
+ @BeforeClass
+ public void init() {
+ SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000);
+ read = ArtificialSAMUtils.createArtificialRead(header, "read1", 0, 1, BASES.length());
+ read.setReadUnmappedFlag(true);
+ read.setReadBases(new String(BASES).getBytes());
+ read.setBaseQualityString(new String(QUALS));
+ }
+
+ @Test
+ public void testStrandlessReads() {
+ final byte [] bases = {'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'};
+ final byte [] quals = {20 , 20 , 20 , 20 , 20 , 20 , 20 , 20 };
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(bases, quals, "6M");
+ Assert.assertEquals(read.isStrandless(), false);
+
+ read.setReadNegativeStrandFlag(false);
+ Assert.assertEquals(read.isStrandless(), false);
+ Assert.assertEquals(read.getReadNegativeStrandFlag(), false);
+
+ read.setReadNegativeStrandFlag(true);
+ Assert.assertEquals(read.isStrandless(), false);
+ Assert.assertEquals(read.getReadNegativeStrandFlag(), true);
+
+ read.setReadNegativeStrandFlag(true);
+ read.setIsStrandless(true);
+ Assert.assertEquals(read.isStrandless(), true);
+ Assert.assertEquals(read.getReadNegativeStrandFlag(), false, "negative strand flag should return false even through its set for a strandless read");
+ }
+
+ @Test(expectedExceptions = IllegalStateException.class)
+ public void testStrandlessReadsFailSetStrand() {
+ final byte [] bases = {'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'};
+ final byte [] quals = {20 , 20 , 20 , 20 , 20 , 20 , 20 , 20 };
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(bases, quals, "6M");
+ read.setIsStrandless(true);
+ read.setReadNegativeStrandFlag(true);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/MisencodedBaseQualityUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/MisencodedBaseQualityUnitTest.java
new file mode 100644
index 0000000..207e01a
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/MisencodedBaseQualityUnitTest.java
@@ -0,0 +1,96 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.UserException;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Basic unit test for misencoded quals
+ */
+public class MisencodedBaseQualityUnitTest extends BaseTest {
+
+ private static final String readBases = "AAAAAAAAAA";
+ private static final byte[] badQuals = { 59, 60, 62, 63, 64, 61, 62, 58, 57, 56 };
+ private static final byte[] goodQuals = { 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 };
+ private static final byte[] fixedQuals = { 28, 29, 31, 32, 33, 30, 31, 27, 26, 25 };
+ private SAMFileHeader header;
+
+ @BeforeMethod
+ public void before() {
+ // reset the read counter so that we are deterministic
+ MisencodedBaseQualityReadTransformer.currentReadCounter = 0;
+ header = ArtificialSAMUtils.createArtificialSamHeader(1, 1, 1000);
+ }
+
+ private GATKSAMRecord createRead(final boolean useGoodBases) {
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "foo", 0, 10, readBases.getBytes(),
+ useGoodBases ? Arrays.copyOf(goodQuals, goodQuals.length) :
+ Arrays.copyOf(badQuals, badQuals.length));
+ read.setCigarString("10M");
+ return read;
+ }
+
+ @Test(enabled = true)
+ public void testGoodQuals() {
+ final List<GATKSAMRecord> reads = new ArrayList<GATKSAMRecord>(10000);
+ for ( int i = 0; i < 10000; i++ )
+ reads.add(createRead(true));
+
+ testEncoding(reads);
+ }
+
+ @Test(enabled = true, expectedExceptions = {UserException.class})
+ public void testBadQualsThrowsError() {
+ final List<GATKSAMRecord> reads = new ArrayList<GATKSAMRecord>(10000);
+ for ( int i = 0; i < 10000; i++ )
+ reads.add(createRead(false));
+
+ testEncoding(reads);
+ }
+
+ @Test(enabled = true)
+ public void testFixBadQuals() {
+ final GATKSAMRecord read = createRead(false);
+ final GATKSAMRecord fixedRead = MisencodedBaseQualityReadTransformer.fixMisencodedQuals(read);
+ for ( int i = 0; i < fixedQuals.length; i++ )
+ Assert.assertEquals(fixedQuals[i], fixedRead.getBaseQualities()[i]);
+ }
+
+ private void testEncoding(final List<GATKSAMRecord> reads) {
+ for ( final GATKSAMRecord read : reads )
+ MisencodedBaseQualityReadTransformer.checkForMisencodedQuals(read);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ReadUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ReadUtilsUnitTest.java
new file mode 100644
index 0000000..c7ceea1
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/sam/ReadUtilsUnitTest.java
@@ -0,0 +1,340 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.sam;
+
+import htsjdk.samtools.reference.IndexedFastaSequenceFile;
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.BaseUtils;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.*;
+
+
+public class ReadUtilsUnitTest extends BaseTest {
+ private interface GetAdaptorFunc {
+ public int getAdaptor(final GATKSAMRecord record);
+ }
+
+ @DataProvider(name = "AdaptorGetter")
+ public Object[][] makeActiveRegionCutTests() {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ tests.add( new Object[]{ new GetAdaptorFunc() {
+ @Override public int getAdaptor(final GATKSAMRecord record) { return ReadUtils.getAdaptorBoundary(record); }
+ }});
+
+ tests.add( new Object[]{ new GetAdaptorFunc() {
+ @Override public int getAdaptor(final GATKSAMRecord record) { return record.getAdaptorBoundary(); }
+ }});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ private GATKSAMRecord makeRead(final int fragmentSize, final int mateStart) {
+ final byte[] bases = {'A', 'C', 'G', 'T', 'A', 'C', 'G', 'T'};
+ final byte[] quals = {30, 30, 30, 30, 30, 30, 30, 30};
+ final String cigar = "8M";
+ GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(bases, quals, cigar);
+ read.setProperPairFlag(true);
+ read.setReadPairedFlag(true);
+ read.setMateAlignmentStart(mateStart);
+ read.setInferredInsertSize(fragmentSize);
+ return read;
+ }
+
+ @Test(dataProvider = "AdaptorGetter")
+ public void testGetAdaptorBoundary(final GetAdaptorFunc get) {
+ final int fragmentSize = 10;
+ final int mateStart = 1000;
+ final int BEFORE = mateStart - 2;
+ final int AFTER = mateStart + 2;
+ int myStart, boundary;
+ GATKSAMRecord read;
+
+ // Test case 1: positive strand, first read
+ read = makeRead(fragmentSize, mateStart);
+ myStart = BEFORE;
+ read.setAlignmentStart(myStart);
+ read.setReadNegativeStrandFlag(false);
+ read.setMateNegativeStrandFlag(true);
+ boundary = get.getAdaptor(read);
+ Assert.assertEquals(boundary, myStart + fragmentSize + 1);
+
+ // Test case 2: positive strand, second read
+ read = makeRead(fragmentSize, mateStart);
+ myStart = AFTER;
+ read.setAlignmentStart(myStart);
+ read.setReadNegativeStrandFlag(false);
+ read.setMateNegativeStrandFlag(true);
+ boundary = get.getAdaptor(read);
+ Assert.assertEquals(boundary, myStart + fragmentSize + 1);
+
+ // Test case 3: negative strand, second read
+ read = makeRead(fragmentSize, mateStart);
+ myStart = AFTER;
+ read.setAlignmentStart(myStart);
+ read.setReadNegativeStrandFlag(true);
+ read.setMateNegativeStrandFlag(false);
+ boundary = get.getAdaptor(read);
+ Assert.assertEquals(boundary, mateStart - 1);
+
+ // Test case 4: negative strand, first read
+ read = makeRead(fragmentSize, mateStart);
+ myStart = BEFORE;
+ read.setAlignmentStart(myStart);
+ read.setReadNegativeStrandFlag(true);
+ read.setMateNegativeStrandFlag(false);
+ boundary = get.getAdaptor(read);
+ Assert.assertEquals(boundary, mateStart - 1);
+
+ // Test case 5: mate is mapped to another chromosome (test both strands)
+ read = makeRead(fragmentSize, mateStart);
+ read.setInferredInsertSize(0);
+ read.setReadNegativeStrandFlag(true);
+ read.setMateNegativeStrandFlag(false);
+ boundary = get.getAdaptor(read);
+ Assert.assertEquals(boundary, ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);
+ read.setReadNegativeStrandFlag(false);
+ read.setMateNegativeStrandFlag(true);
+ boundary = get.getAdaptor(read);
+ Assert.assertEquals(boundary, ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);
+ read.setInferredInsertSize(10);
+
+ // Test case 6: read is unmapped
+ read = makeRead(fragmentSize, mateStart);
+ read.setReadUnmappedFlag(true);
+ boundary = get.getAdaptor(read);
+ Assert.assertEquals(boundary, ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);
+ read.setReadUnmappedFlag(false);
+
+ // Test case 7: reads don't overlap and look like this:
+ // <--------|
+ // |------>
+ // first read:
+ read = makeRead(fragmentSize, mateStart);
+ myStart = 980;
+ read.setAlignmentStart(myStart);
+ read.setInferredInsertSize(20);
+ read.setReadNegativeStrandFlag(true);
+ boundary = get.getAdaptor(read);
+ Assert.assertEquals(boundary, ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);
+
+ // second read:
+ read = makeRead(fragmentSize, mateStart);
+ myStart = 1000;
+ read.setAlignmentStart(myStart);
+ read.setInferredInsertSize(20);
+ read.setMateAlignmentStart(980);
+ read.setReadNegativeStrandFlag(false);
+ boundary = get.getAdaptor(read);
+ Assert.assertEquals(boundary, ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);
+
+ // Test case 8: read doesn't have proper pair flag set
+ read = makeRead(fragmentSize, mateStart);
+ read.setReadPairedFlag(true);
+ read.setProperPairFlag(false);
+ Assert.assertEquals(get.getAdaptor(read), ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY);
+
+ // Test case 9: read and mate have same negative flag setting
+ for ( final boolean negFlag: Arrays.asList(true, false) ) {
+ read = makeRead(fragmentSize, mateStart);
+ read.setAlignmentStart(BEFORE);
+ read.setReadPairedFlag(true);
+ read.setProperPairFlag(true);
+ read.setReadNegativeStrandFlag(negFlag);
+ read.setMateNegativeStrandFlag(!negFlag);
+ Assert.assertTrue(get.getAdaptor(read) != ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY, "Get adaptor should have succeeded");
+
+ read = makeRead(fragmentSize, mateStart);
+ read.setAlignmentStart(BEFORE);
+ read.setReadPairedFlag(true);
+ read.setProperPairFlag(true);
+ read.setReadNegativeStrandFlag(negFlag);
+ read.setMateNegativeStrandFlag(negFlag);
+ Assert.assertEquals(get.getAdaptor(read), ReadUtils.CANNOT_COMPUTE_ADAPTOR_BOUNDARY, "Get adaptor should have failed for reads with bad alignment orientation");
+ }
+ }
+
+ @Test (enabled = true)
+ public void testGetBasesReverseComplement() {
+ int iterations = 1000;
+ Random random = GenomeAnalysisEngine.getRandomGenerator();
+ while(iterations-- > 0) {
+ final int l = random.nextInt(1000);
+ GATKSAMRecord read = GATKSAMRecord.createRandomRead(l);
+ byte [] original = read.getReadBases();
+ byte [] reconverted = new byte[l];
+ String revComp = ReadUtils.getBasesReverseComplement(read);
+ for (int i=0; i<l; i++) {
+ reconverted[l-1-i] = BaseUtils.getComplement((byte) revComp.charAt(i));
+ }
+ Assert.assertEquals(reconverted, original);
+ }
+ }
+
+ @Test (enabled = true)
+ public void testGetMaxReadLength() {
+ for( final int minLength : Arrays.asList( 5, 30, 50 ) ) {
+ for( final int maxLength : Arrays.asList( 50, 75, 100 ) ) {
+ final List<GATKSAMRecord> reads = new ArrayList<GATKSAMRecord>();
+ for( int readLength = minLength; readLength <= maxLength; readLength++ ) {
+ reads.add( ReadUtils.createRandomRead( readLength ) );
+ }
+ Assert.assertEquals(ReadUtils.getMaxReadLength(reads), maxLength, "max length does not match");
+ }
+ }
+
+ final List<GATKSAMRecord> reads = new LinkedList<GATKSAMRecord>();
+ Assert.assertEquals(ReadUtils.getMaxReadLength(reads), 0, "Empty list should have max length of zero");
+ }
+
+ @Test (enabled = true)
+ public void testReadWithNsRefIndexInDeletion() throws FileNotFoundException {
+
+ final IndexedFastaSequenceFile seq = new CachingIndexedFastaSequenceFile(new File(b37KGReference));
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(seq.getSequenceDictionary());
+ final int readLength = 76;
+
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 8975, readLength);
+ read.setReadBases(Utils.dupBytes((byte) 'A', readLength));
+ read.setBaseQualities(Utils.dupBytes((byte)30, readLength));
+ read.setCigarString("3M414N1D73M");
+
+ final int result = ReadUtils.getReadCoordinateForReferenceCoordinateUpToEndOfRead(read, 9392, ReadUtils.ClippingTail.LEFT_TAIL);
+ Assert.assertEquals(result, 2);
+ }
+
+ @Test (enabled = true)
+ public void testReadWithNsRefAfterDeletion() throws FileNotFoundException {
+
+ final IndexedFastaSequenceFile seq = new CachingIndexedFastaSequenceFile(new File(b37KGReference));
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader(seq.getSequenceDictionary());
+ final int readLength = 76;
+
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "myRead", 0, 8975, readLength);
+ read.setReadBases(Utils.dupBytes((byte) 'A', readLength));
+ read.setBaseQualities(Utils.dupBytes((byte)30, readLength));
+ read.setCigarString("3M414N1D73M");
+
+ final int result = ReadUtils.getReadCoordinateForReferenceCoordinateUpToEndOfRead(read, 9393, ReadUtils.ClippingTail.LEFT_TAIL);
+ Assert.assertEquals(result, 3);
+ }
+
+ @DataProvider(name = "HasWellDefinedFragmentSizeData")
+ public Object[][] makeHasWellDefinedFragmentSizeData() throws Exception {
+ final List<Object[]> tests = new LinkedList<Object[]>();
+
+ // setup a basic read that will work
+ final SAMFileHeader header = ArtificialSAMUtils.createArtificialSamHeader();
+ final GATKSAMRecord read = ArtificialSAMUtils.createArtificialRead(header, "read1", 0, 10, 10);
+ read.setReadPairedFlag(true);
+ read.setProperPairFlag(true);
+ read.setReadUnmappedFlag(false);
+ read.setMateUnmappedFlag(false);
+ read.setAlignmentStart(100);
+ read.setCigarString("50M");
+ read.setMateAlignmentStart(130);
+ read.setInferredInsertSize(80);
+ read.setFirstOfPairFlag(true);
+ read.setReadNegativeStrandFlag(false);
+ read.setMateNegativeStrandFlag(true);
+
+ tests.add( new Object[]{ "basic case", read.clone(), true });
+
+ {
+ final GATKSAMRecord bad1 = (GATKSAMRecord)read.clone();
+ bad1.setReadPairedFlag(false);
+ tests.add( new Object[]{ "not paired", bad1, false });
+ }
+
+ {
+ final GATKSAMRecord bad = (GATKSAMRecord)read.clone();
+ bad.setProperPairFlag(false);
+ // we currently don't require the proper pair flag to be set
+ tests.add( new Object[]{ "not proper pair", bad, true });
+// tests.add( new Object[]{ "not proper pair", bad, false });
+ }
+
+ {
+ final GATKSAMRecord bad = (GATKSAMRecord)read.clone();
+ bad.setReadUnmappedFlag(true);
+ tests.add( new Object[]{ "read is unmapped", bad, false });
+ }
+
+ {
+ final GATKSAMRecord bad = (GATKSAMRecord)read.clone();
+ bad.setMateUnmappedFlag(true);
+ tests.add( new Object[]{ "mate is unmapped", bad, false });
+ }
+
+ {
+ final GATKSAMRecord bad = (GATKSAMRecord)read.clone();
+ bad.setMateNegativeStrandFlag(false);
+ tests.add( new Object[]{ "read and mate both on positive strand", bad, false });
+ }
+
+ {
+ final GATKSAMRecord bad = (GATKSAMRecord)read.clone();
+ bad.setReadNegativeStrandFlag(true);
+ tests.add( new Object[]{ "read and mate both on negative strand", bad, false });
+ }
+
+ {
+ final GATKSAMRecord bad = (GATKSAMRecord)read.clone();
+ bad.setInferredInsertSize(0);
+ tests.add( new Object[]{ "insert size is 0", bad, false });
+ }
+
+ {
+ final GATKSAMRecord bad = (GATKSAMRecord)read.clone();
+ bad.setAlignmentStart(1000);
+ tests.add( new Object[]{ "positve read starts after mate end", bad, false });
+ }
+
+ {
+ final GATKSAMRecord bad = (GATKSAMRecord)read.clone();
+ bad.setReadNegativeStrandFlag(true);
+ bad.setMateNegativeStrandFlag(false);
+ bad.setMateAlignmentStart(1000);
+ tests.add( new Object[]{ "negative strand read ends before mate starts", bad, false });
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "HasWellDefinedFragmentSizeData")
+ private void testHasWellDefinedFragmentSize(final String name, final GATKSAMRecord read, final boolean expected) {
+ Assert.assertEquals(ReadUtils.hasWellDefinedFragmentSize(read), expected);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/smithwaterman/SmithWatermanBenchmark.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/smithwaterman/SmithWatermanBenchmark.java
new file mode 100644
index 0000000..44ba64c
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/smithwaterman/SmithWatermanBenchmark.java
@@ -0,0 +1,87 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.smithwaterman;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import org.broadinstitute.gatk.utils.Utils;
+
+/**
+ * Caliper microbenchmark of parsing a VCF file
+ */
+public class SmithWatermanBenchmark extends SimpleBenchmark {
+
+ @Param({"Original"})
+ String version; // set automatically by framework
+
+ @Param({"10", "50", "100", "500"})
+ int sizeOfMiddleRegion; // set automatically by framework
+
+ @Param({"10", "50", "100", "500"})
+ int sizeOfEndRegions; // set automatically by framework
+
+ String refString;
+ String hapString;
+
+ @Override protected void setUp() {
+ final StringBuilder ref = new StringBuilder();
+ final StringBuilder hap = new StringBuilder();
+
+ ref.append(Utils.dupString('A', sizeOfEndRegions));
+ hap.append(Utils.dupString('A', sizeOfEndRegions));
+
+ // introduce a SNP
+ ref.append("X");
+ hap.append("Y");
+
+ ref.append(Utils.dupString('A', sizeOfMiddleRegion));
+ hap.append(Utils.dupString('A', sizeOfMiddleRegion));
+
+ // introduce a SNP
+ ref.append("X");
+ hap.append("Y");
+
+ ref.append(Utils.dupString('A', sizeOfEndRegions));
+ hap.append(Utils.dupString('A', sizeOfEndRegions));
+
+ refString = ref.toString();
+ hapString = hap.toString();
+ }
+
+ public void timeSW(int rep) {
+ for ( int i = 0; i < rep; i++ ) {
+ final SmithWaterman sw;
+ if ( version.equals("Greedy") )
+ throw new IllegalArgumentException("Unsupported implementation");
+ sw = new SWPairwiseAlignment(refString.getBytes(), hapString.getBytes());
+ sw.getCigar();
+ }
+ }
+
+ public static void main(String[] args) {
+ com.google.caliper.Runner.main(SmithWatermanBenchmark.class, args);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/text/ListFileUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/text/ListFileUtilsUnitTest.java
new file mode 100644
index 0000000..086cefe
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/text/ListFileUtilsUnitTest.java
@@ -0,0 +1,159 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.text;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.commandline.ParsingEngine;
+import org.broadinstitute.gatk.utils.commandline.Tags;
+import org.broadinstitute.gatk.engine.CommandLineGATK;
+import org.broadinstitute.gatk.engine.datasources.reads.SAMReaderID;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.PrintWriter;
+import java.util.*;
+
+/**
+ * Tests selected functionality in the CommandLineExecutable class
+ */
+public class ListFileUtilsUnitTest extends BaseTest {
+
+ @Test
+ public void testIgnoreBlankLinesInBAMListFiles() throws Exception {
+ File tempListFile = createTempListFile("testIgnoreBlankLines",
+ "",
+ publicTestDir + "exampleBAM.bam",
+ " "
+ );
+
+ List<SAMReaderID> expectedBAMFileListAfterUnpacking = new ArrayList<SAMReaderID>();
+ expectedBAMFileListAfterUnpacking.add(new SAMReaderID(new File(publicTestDir + "exampleBAM.bam"), new Tags()));
+
+ performBAMListFileUnpackingTest(tempListFile, expectedBAMFileListAfterUnpacking);
+ }
+
+ @Test
+ public void testCommentSupportInBAMListFiles() throws Exception {
+ File tempListFile = createTempListFile("testCommentSupport",
+ "#",
+ publicTestDir + "exampleBAM.bam",
+ "#" + publicTestDir + "foo.bam",
+ " # " + publicTestDir + "bar.bam"
+ );
+
+ List<SAMReaderID> expectedBAMFileListAfterUnpacking = new ArrayList<SAMReaderID>();
+ expectedBAMFileListAfterUnpacking.add(new SAMReaderID(new File(publicTestDir + "exampleBAM.bam"), new Tags()));
+
+ performBAMListFileUnpackingTest(tempListFile, expectedBAMFileListAfterUnpacking);
+ }
+
+ @Test
+ public void testUnpackSet() throws Exception {
+ Set<String> expected = new HashSet<String>(Arrays.asList(publicTestDir + "exampleBAM.bam"));
+ Set<String> actual;
+
+ actual = ListFileUtils.unpackSet(Arrays.asList(publicTestDir + "exampleBAM.bam"));
+ Assert.assertEquals(actual, expected);
+
+ File tempListFile = createTempListFile("testUnpackSet",
+ "#",
+ publicTestDir + "exampleBAM.bam",
+ "#" + publicTestDir + "foo.bam",
+ " # " + publicTestDir + "bar.bam"
+ );
+ actual = ListFileUtils.unpackSet(Arrays.asList(tempListFile.getAbsolutePath()));
+ Assert.assertEquals(actual, expected);
+ }
+
+ @DataProvider(name="includeMatchingTests")
+ public Object[][] getIncludeMatchingTests() {
+ return new Object[][] {
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a"), true, asSet("a") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a"), false, asSet("a", "ab", "abc") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("b"), true, Collections.EMPTY_SET },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("b"), false, asSet("ab", "abc") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a", "b"), true, asSet("a") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a", "b"), false, asSet("a", "ab", "abc") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a", "ab"), true, asSet("a", "ab") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a", "ab"), false, asSet("a", "ab", "abc") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList(".*b.*"), true, Collections.EMPTY_SET },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList(".*b.*"), false, asSet("ab", "abc") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList(".*"), true, Collections.EMPTY_SET },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList(".*"), false, asSet("a", "ab", "abc") }
+ };
+ }
+
+ @Test(dataProvider = "includeMatchingTests")
+ public void testIncludeMatching(Set<String> values, Collection<String> filters, boolean exactMatch, Set<String> expected) {
+ Set<String> actual = ListFileUtils.includeMatching(values, ListFileUtils.IDENTITY_STRING_CONVERTER, filters, exactMatch);
+ Assert.assertEquals(actual, expected);
+ }
+
+ @DataProvider(name="excludeMatchingTests")
+ public Object[][] getExcludeMatchingTests() {
+ return new Object[][] {
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a"), true, asSet("ab", "abc") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a"), false, Collections.EMPTY_SET },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("b"), true, asSet("a", "ab", "abc") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("b"), false, asSet("a") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a", "b"), true, asSet("ab", "abc") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a", "b"), false, Collections.EMPTY_SET },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a", "ab"), true, asSet("abc") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList("a", "ab"), false, Collections.EMPTY_SET },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList(".*b.*"), true, asSet("a", "ab", "abc") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList(".*b.*"), false, asSet("a") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList(".*"), true, asSet("a", "ab", "abc") },
+ new Object[] { asSet("a", "ab", "abc"), Arrays.asList(".*"), false, Collections.EMPTY_SET }
+ };
+ }
+
+ @Test(dataProvider = "excludeMatchingTests")
+ public void testExcludeMatching(Set<String> values, Collection<String> filters, boolean exactMatch, Set<String> expected) {
+ Set<String> actual = ListFileUtils.excludeMatching(values, ListFileUtils.IDENTITY_STRING_CONVERTER, filters, exactMatch);
+ Assert.assertEquals(actual, expected);
+ }
+
+ private static <T> Set<T> asSet(T... args){
+ return new HashSet<T>(Arrays.asList(args));
+ }
+
+ private void performBAMListFileUnpackingTest( File tempListFile, List<SAMReaderID> expectedUnpackedFileList ) throws Exception {
+ List<String> bamFiles = new ArrayList<String>();
+ bamFiles.add(tempListFile.getAbsolutePath());
+
+ CommandLineGATK testInstance = new CommandLineGATK();
+ testInstance.setParser(new ParsingEngine(testInstance));
+
+ List<SAMReaderID> unpackedBAMFileList = ListFileUtils.unpackBAMFileList(bamFiles,new ParsingEngine(testInstance));
+
+ Assert.assertEquals(unpackedBAMFileList.size(), expectedUnpackedFileList.size(),
+ "Unpacked BAM file list contains extraneous lines");
+ Assert.assertEquals(unpackedBAMFileList, expectedUnpackedFileList,
+ "Unpacked BAM file list does not contain correct BAM file names");
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/text/TextFormattingUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/text/TextFormattingUtilsUnitTest.java
new file mode 100644
index 0000000..5457310
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/text/TextFormattingUtilsUnitTest.java
@@ -0,0 +1,89 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.text;
+
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+public class TextFormattingUtilsUnitTest extends BaseTest {
+ @Test(expectedExceptions = ReviewedGATKException.class)
+ public void testSplitWhiteSpaceNullLine() {
+ TextFormattingUtils.splitWhiteSpace(null);
+ }
+
+ @Test
+ public void testSplitWhiteSpace() {
+ Assert.assertEquals(TextFormattingUtils.splitWhiteSpace("foo bar baz"), new String[] { "foo", "bar", "baz" });
+ Assert.assertEquals(TextFormattingUtils.splitWhiteSpace("foo bar baz"), new String[] { "foo", "bar", "baz" });
+ Assert.assertEquals(TextFormattingUtils.splitWhiteSpace(" foo bar baz"), new String[] { "foo", "bar", "baz" });
+ Assert.assertEquals(TextFormattingUtils.splitWhiteSpace(" foo bar baz "), new String[] { "foo", "bar", "baz" });
+ Assert.assertEquals(TextFormattingUtils.splitWhiteSpace("foo bar baz "), new String[] { "foo", "bar", "baz" });
+ Assert.assertEquals(TextFormattingUtils.splitWhiteSpace("\tfoo\tbar\tbaz\t"), new String[]{"foo", "bar", "baz"});
+ }
+
+ @Test(expectedExceptions = ReviewedGATKException.class)
+ public void testGetWordStartsNullLine() {
+ TextFormattingUtils.getWordStarts(null);
+ }
+
+ @Test
+ public void testGetWordStarts() {
+ Assert.assertEquals(TextFormattingUtils.getWordStarts("foo bar baz"), Arrays.asList(4, 8));
+ Assert.assertEquals(TextFormattingUtils.getWordStarts("foo bar baz"), Arrays.asList(5, 10));
+ Assert.assertEquals(TextFormattingUtils.getWordStarts(" foo bar baz"), Arrays.asList(1, 5, 9));
+ Assert.assertEquals(TextFormattingUtils.getWordStarts(" foo bar baz "), Arrays.asList(1, 5, 9));
+ Assert.assertEquals(TextFormattingUtils.getWordStarts("foo bar baz "), Arrays.asList(4, 8));
+ Assert.assertEquals(TextFormattingUtils.getWordStarts("\tfoo\tbar\tbaz\t"), Arrays.asList(1, 5, 9));
+ }
+
+ @Test(expectedExceptions = ReviewedGATKException.class)
+ public void testSplitFixedWidthNullLine() {
+ TextFormattingUtils.splitFixedWidth(null, Collections.<Integer>emptyList());
+ }
+
+ @Test(expectedExceptions = ReviewedGATKException.class)
+ public void testSplitFixedWidthNullColumnStarts() {
+ TextFormattingUtils.splitFixedWidth("foo bar baz", null);
+ }
+
+ @Test
+ public void testSplitFixedWidth() {
+ Assert.assertEquals(TextFormattingUtils.splitFixedWidth("foo bar baz", Arrays.asList(4, 8)), new String[] { "foo", "bar", "baz" });
+ Assert.assertEquals(TextFormattingUtils.splitFixedWidth("foo bar baz", Arrays.asList(5, 10)), new String[] { "foo", "bar", "baz" });
+ Assert.assertEquals(TextFormattingUtils.splitFixedWidth(" foo bar baz", Arrays.asList(5, 9)), new String[] { "foo", "bar", "baz" });
+ Assert.assertEquals(TextFormattingUtils.splitFixedWidth(" foo bar baz ", Arrays.asList(5, 9)), new String[] { "foo", "bar", "baz" });
+ Assert.assertEquals(TextFormattingUtils.splitFixedWidth("foo bar baz ", Arrays.asList(4, 8)), new String[] { "foo", "bar", "baz" });
+ Assert.assertEquals(TextFormattingUtils.splitFixedWidth("\tfoo\tbar\tbaz\t", Arrays.asList(5, 9)), new String[] { "foo", "bar", "baz" });
+ Assert.assertEquals(TextFormattingUtils.splitFixedWidth("f o b r b z", Arrays.asList(4, 8)), new String[] { "f o", "b r", "b z" });
+ Assert.assertEquals(TextFormattingUtils.splitFixedWidth(" f o b r b z", Arrays.asList(4, 8)), new String[] { "f o", "b r", "b z" });
+ Assert.assertEquals(TextFormattingUtils.splitFixedWidth(" f o b r b z", Arrays.asList(4, 8)), new String[] { "f", "o b", "r b z" });
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/threading/EfficiencyMonitoringThreadFactoryUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/threading/EfficiencyMonitoringThreadFactoryUnitTest.java
new file mode 100644
index 0000000..0c98813
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/threading/EfficiencyMonitoringThreadFactoryUnitTest.java
@@ -0,0 +1,189 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.threading;
+
+import org.apache.log4j.Priority;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.utils.Utils;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for the state monitoring thread factory.
+ */
+public class EfficiencyMonitoringThreadFactoryUnitTest extends BaseTest {
+ // the duration of the tests -- 100 ms is tolerable given the number of tests we are doing
+ private final static long THREAD_TARGET_DURATION_IN_MILLISECOND = 100000;
+ private final static int MAX_THREADS = 4;
+ final static Object GLOBAL_LOCK = new Object();
+
+ private class StateTest extends TestDataProvider {
+ private final double TOLERANCE = 0.1; // willing to tolerate a 10% error
+
+ final List<EfficiencyMonitoringThreadFactory.State> statesForThreads;
+
+ public StateTest(final List<EfficiencyMonitoringThreadFactory.State> statesForThreads) {
+ super(StateTest.class);
+ this.statesForThreads = statesForThreads;
+ setName("StateTest " + Utils.join(",", statesForThreads));
+ }
+
+ public List<EfficiencyMonitoringThreadFactory.State> getStatesForThreads() {
+ return statesForThreads;
+ }
+
+ public int getNStates() { return statesForThreads.size(); }
+
+ public double maxStatePercent(final EfficiencyMonitoringThreadFactory.State state) { return 100*(fraction(state) + TOLERANCE); }
+ public double minStatePercent(final EfficiencyMonitoringThreadFactory.State state) { return 100*(fraction(state) - TOLERANCE); }
+
+ private double fraction(final EfficiencyMonitoringThreadFactory.State state) {
+ return Collections.frequency(statesForThreads, state) / (1.0 * statesForThreads.size());
+ }
+ }
+
+ /**
+ * Test helper threading class that puts the thread into RUNNING, BLOCKED, or WAITING state as
+ * requested for input argument
+ */
+ private static class StateTestThread implements Callable<Double> {
+ private final EfficiencyMonitoringThreadFactory.State stateToImplement;
+
+ private StateTestThread(final EfficiencyMonitoringThreadFactory.State stateToImplement) {
+ this.stateToImplement = stateToImplement;
+ }
+
+ @Override
+ public Double call() throws Exception {
+ switch ( stateToImplement ) {
+ case USER_CPU:
+ // do some work until we get to THREAD_TARGET_DURATION_IN_MILLISECOND
+ double sum = 0.0;
+ final long startTime = System.currentTimeMillis();
+ for ( int i = 1; System.currentTimeMillis() - startTime < (THREAD_TARGET_DURATION_IN_MILLISECOND - 1); i++ ) {
+ sum += Math.log10(i);
+ }
+ return sum;
+ case WAITING:
+ Thread.currentThread().sleep(THREAD_TARGET_DURATION_IN_MILLISECOND);
+ return 0.0;
+ case BLOCKING:
+ if ( EfficiencyMonitoringThreadFactory.DEBUG ) logger.warn("Blocking...");
+ synchronized (GLOBAL_LOCK) {
+ // the GLOBAL_LOCK must be held by the unit test itself for this to properly block
+ if ( EfficiencyMonitoringThreadFactory.DEBUG ) logger.warn(" ... done blocking");
+ }
+ return 0.0;
+ case WAITING_FOR_IO:
+ // TODO -- implement me
+ // shouldn't ever get here, throw an exception
+ throw new ReviewedGATKException("WAITING_FOR_IO testing currently not implemented, until we figure out how to force a system call block");
+ default:
+ throw new ReviewedGATKException("Unexpected thread test state " + stateToImplement);
+ }
+ }
+ }
+
+ @DataProvider(name = "StateTest")
+ public Object[][] createStateTest() {
+ for ( final int nThreads : Arrays.asList(3) ) {
+ //final List<EfficiencyMonitoringThreadFactory.State> allStates = Arrays.asList(EfficiencyMonitoringThreadFactory.State.WAITING_FOR_IO);
+ final List<EfficiencyMonitoringThreadFactory.State> allStates = Arrays.asList(EfficiencyMonitoringThreadFactory.State.USER_CPU, EfficiencyMonitoringThreadFactory.State.WAITING, EfficiencyMonitoringThreadFactory.State.BLOCKING);
+ //final List<EfficiencyMonitoringThreadFactory.State> allStates = Arrays.asList(EfficiencyMonitoringThreadFactory.State.values());
+ for (final List<EfficiencyMonitoringThreadFactory.State> states : Utils.makePermutations(allStates, nThreads, true) ) {
+ //if ( Collections.frequency(states, Thread.State.BLOCKED) > 0)
+ new StateTest(states);
+ }
+ }
+
+ return StateTest.getTests(StateTest.class);
+ }
+
+ // NOTE this test takes an unreasonably long time to run, and so it's been disabled as these monitoring threads
+ // aren't a core GATK feature any longer. Should be reabled if we come to care about this capability again
+ // in the future, or we can run these in parallel
+ @Test(enabled = false, dataProvider = "StateTest", timeOut = MAX_THREADS * THREAD_TARGET_DURATION_IN_MILLISECOND)
+ public void testStateTest(final StateTest test) throws InterruptedException {
+ // allows us to test blocking
+ final EfficiencyMonitoringThreadFactory factory = new EfficiencyMonitoringThreadFactory(test.getNStates());
+ final ExecutorService threadPool = Executors.newFixedThreadPool(test.getNStates(), factory);
+
+ logger.warn("Running " + test);
+ synchronized (GLOBAL_LOCK) {
+ //logger.warn(" Have lock");
+ for ( final EfficiencyMonitoringThreadFactory.State threadToRunState : test.getStatesForThreads() )
+ threadPool.submit(new StateTestThread(threadToRunState));
+
+ // lock has to be here for the whole running of the activeThreads but end before the sleep so the blocked activeThreads
+ // can block for their allotted time
+ threadPool.shutdown();
+ Thread.sleep(THREAD_TARGET_DURATION_IN_MILLISECOND);
+ }
+ //logger.warn(" Releasing lock");
+ threadPool.awaitTermination(10, TimeUnit.SECONDS);
+ //logger.warn(" done awaiting termination");
+ //logger.warn(" waiting for all activeThreads to complete");
+ factory.waitForAllThreadsToComplete();
+ //logger.warn(" done waiting for activeThreads");
+
+ // make sure we counted everything properly
+ final long totalTime = factory.getTotalTime();
+ final long minTime = (long)(THREAD_TARGET_DURATION_IN_MILLISECOND * 0.5) * test.getNStates();
+ final long maxTime = (long)(THREAD_TARGET_DURATION_IN_MILLISECOND * 1.5) * test.getNStates();
+ //logger.warn("Testing total time");
+ Assert.assertTrue(totalTime >= minTime, "Factory results not properly accumulated: totalTime = " + totalTime + " < minTime = " + minTime);
+ Assert.assertTrue(totalTime <= maxTime, "Factory results not properly accumulated: totalTime = " + totalTime + " > maxTime = " + maxTime);
+
+ for (final EfficiencyMonitoringThreadFactory.State state : EfficiencyMonitoringThreadFactory.State.values() ) {
+ final double min = test.minStatePercent(state);
+ final double max = test.maxStatePercent(state);
+ final double obs = factory.getStatePercent(state);
+// logger.warn(" Checking " + state
+// + " min " + String.format("%.2f", min)
+// + " max " + String.format("%.2f", max)
+// + " obs " + String.format("%.2f", obs)
+// + " factor = " + factory);
+ Assert.assertTrue(obs >= min, "Too little time spent in state " + state + " obs " + obs + " min " + min);
+ Assert.assertTrue(obs <= max, "Too much time spent in state " + state + " obs " + obs + " max " + min);
+ }
+
+ // we actually ran the expected number of activeThreads
+ Assert.assertEquals(factory.getNThreadsCreated(), test.getNStates());
+
+ // should be called to ensure we don't format / NPE on output
+ factory.printUsageInformation(logger, Priority.WARN);
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/threading/ThreadPoolMonitorUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/threading/ThreadPoolMonitorUnitTest.java
new file mode 100644
index 0000000..a73cb26
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/threading/ThreadPoolMonitorUnitTest.java
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.threading;
+
+import org.testng.annotations.Test;
+import org.broadinstitute.gatk.utils.BaseTest;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+/**
+ * User: hanna
+ * Date: Apr 29, 2009
+ * Time: 4:30:55 PM
+ * BROAD INSTITUTE SOFTWARE COPYRIGHT NOTICE AND AGREEMENT
+ * Software and documentation are copyright 2005 by the Broad Institute.
+ * All rights are reserved.
+ *
+ * Users acknowledge that this software is supplied without any warranty or support.
+ * The Broad Institute is not responsible for its use, misuse, or
+ * functionality.
+ */
+
+/**
+ * Tests for the thread pool monitor class.
+ */
+
+public class ThreadPoolMonitorUnitTest extends BaseTest {
+ private ExecutorService threadPool = Executors.newFixedThreadPool(1);
+
+ /**
+ * Test to make sure the thread pool wait works properly.
+ */
+ @Test(timeOut=2000)
+ public void testThreadPoolMonitor() {
+ ThreadPoolMonitor monitor = new ThreadPoolMonitor();
+ synchronized(monitor) {
+ threadPool.submit(monitor);
+ monitor.watch();
+ }
+ }
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/GATKVCFUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/GATKVCFUtilsUnitTest.java
new file mode 100644
index 0000000..ab547b7
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/GATKVCFUtilsUnitTest.java
@@ -0,0 +1,138 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.variant;
+
+import htsjdk.tribble.index.DynamicIndexCreator;
+import htsjdk.tribble.index.IndexCreator;
+import htsjdk.tribble.index.interval.IntervalIndexCreator;
+import htsjdk.tribble.index.linear.LinearIndexCreator;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.engine.contexts.AlignmentContext;
+import org.broadinstitute.gatk.engine.contexts.ReferenceContext;
+import org.broadinstitute.gatk.engine.refdata.RefMetaDataTracker;
+import org.broadinstitute.gatk.engine.walkers.RodWalker;
+import org.broadinstitute.gatk.engine.walkers.Walker;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+
+public class GATKVCFUtilsUnitTest extends BaseTest {
+ public static class VCFHeaderTestWalker extends RodWalker<Integer, Integer> {
+ public Integer map(RefMetaDataTracker tracker, ReferenceContext ref, AlignmentContext context) { return null; }
+ public Integer reduceInit() { return 0; }
+ public Integer reduce(Integer value, Integer sum) { return value + sum; }
+ }
+
+ public static class VCFHeaderTest2Walker extends VCFHeaderTestWalker {}
+
+ @Test
+ public void testAddingVCFHeaderInfo() {
+ final VCFHeader header = new VCFHeader();
+
+ final Walker walker1 = new VCFHeaderTestWalker();
+ final Walker walker2 = new VCFHeaderTest2Walker();
+
+ final GenomeAnalysisEngine testEngine1 = new GenomeAnalysisEngine();
+ testEngine1.setWalker(walker1);
+
+ final GenomeAnalysisEngine testEngine2 = new GenomeAnalysisEngine();
+ testEngine2.setWalker(walker2);
+
+ final VCFHeaderLine line1 = GATKVCFUtils.getCommandLineArgumentHeaderLine(testEngine1, Collections.EMPTY_LIST);
+ logger.warn(line1);
+ Assert.assertNotNull(line1);
+ Assert.assertEquals(line1.getKey(), GATKVCFUtils.GATK_COMMAND_LINE_KEY);
+ for ( final String field : Arrays.asList("Version", "ID", "Date", "CommandLineOptions"))
+ Assert.assertTrue(line1.toString().contains(field), "Couldn't find field " + field + " in " + line1.getValue());
+ Assert.assertTrue(line1.toString().contains("ID=" + testEngine1.getWalkerName()));
+
+ final VCFHeaderLine line2 = GATKVCFUtils.getCommandLineArgumentHeaderLine(testEngine2, Collections.EMPTY_LIST);
+ logger.warn(line2);
+
+ header.addMetaDataLine(line1);
+ final Set<VCFHeaderLine> lines1 = header.getMetaDataInInputOrder();
+ Assert.assertTrue(lines1.contains(line1));
+
+ header.addMetaDataLine(line2);
+ final Set<VCFHeaderLine> lines2 = header.getMetaDataInInputOrder();
+ Assert.assertTrue(lines2.contains(line1));
+ Assert.assertTrue(lines2.contains(line2));
+ }
+
+ private class IndexCreatorTest extends TestDataProvider {
+ private final GATKVCFIndexType type;
+ private final int parameter;
+ private final Class expectedClass;
+ private final Integer expectedDimension;
+ private final Method dimensionGetter;
+
+ private IndexCreatorTest(GATKVCFIndexType type, int parameter, Class expectedClass, Integer expectedDimension,
+ String dimensionGetterName) {
+ super(IndexCreatorTest.class);
+
+ this.type = type;
+ this.parameter = parameter;
+ this.expectedClass = expectedClass;
+ this.expectedDimension = expectedDimension;
+ try {
+ // Conditional matches testGetIndexCreator's if-statement
+ this.dimensionGetter = this.expectedDimension == null ? null : expectedClass.getDeclaredMethod(dimensionGetterName);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @DataProvider(name = "indexCreator")
+ public Object[][] indexCreatorData() {
+ new IndexCreatorTest(GATKVCFIndexType.DYNAMIC_SEEK, 0, DynamicIndexCreator.class, null, null);
+ new IndexCreatorTest(GATKVCFIndexType.DYNAMIC_SIZE, 0, DynamicIndexCreator.class, null, null);
+ new IndexCreatorTest(GATKVCFIndexType.LINEAR, 100, LinearIndexCreator.class, 100, "getBinSize");
+ new IndexCreatorTest(GATKVCFIndexType.INTERVAL, 200, IntervalIndexCreator.class, 200, "getFeaturesPerInterval");
+
+ return IndexCreatorTest.getTests(IndexCreatorTest.class);
+ }
+
+ @Test(dataProvider = "indexCreator")
+ public void testGetIndexCreator(IndexCreatorTest spec) throws Exception{
+ File dummy = new File("");
+ IndexCreator ic = GATKVCFUtils.getIndexCreator(spec.type, spec.parameter, dummy);
+ Assert.assertEquals(ic.getClass(), spec.expectedClass, "Wrong IndexCreator type");
+ if (spec.expectedDimension != null) {
+ Integer dimension = (int)spec.dimensionGetter.invoke(ic);
+ Assert.assertEquals(dimension, spec.expectedDimension, "Wrong dimension");
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/GATKVariantContextUtilsUnitTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/GATKVariantContextUtilsUnitTest.java
new file mode 100644
index 0000000..feb10a7
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/GATKVariantContextUtilsUnitTest.java
@@ -0,0 +1,1612 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.variant;
+
+import htsjdk.variant.variantcontext.*;
+import org.broadinstitute.gatk.engine.GenomeAnalysisEngine;
+import org.broadinstitute.gatk.utils.*;
+import org.broadinstitute.gatk.utils.collections.Pair;
+import org.broadinstitute.gatk.utils.fasta.CachingIndexedFastaSequenceFile;
+import org.testng.Assert;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+public class GATKVariantContextUtilsUnitTest extends BaseTest {
+ private final static boolean DEBUG = false;
+
+ Allele Aref, T, C, G, Cref, ATC, ATCATC;
+ Allele ATCATCT;
+ Allele ATref;
+ Allele Anoref;
+ Allele GT;
+
+ private GenomeLocParser genomeLocParser;
+
+ @BeforeSuite
+ public void setup() throws IOException {
+ // alleles
+ Aref = Allele.create("A", true);
+ Cref = Allele.create("C", true);
+ T = Allele.create("T");
+ C = Allele.create("C");
+ G = Allele.create("G");
+ ATC = Allele.create("ATC");
+ ATCATC = Allele.create("ATCATC");
+ ATCATCT = Allele.create("ATCATCT");
+ ATref = Allele.create("AT",true);
+ Anoref = Allele.create("A",false);
+ GT = Allele.create("GT",false);
+ genomeLocParser = new GenomeLocParser(new CachingIndexedFastaSequenceFile(new File(hg18Reference)));
+ }
+
+ private Genotype makeG(String sample, Allele a1, Allele a2, double log10pError, int... pls) {
+ return new GenotypeBuilder(sample, Arrays.asList(a1, a2)).log10PError(log10pError).PL(pls).make();
+ }
+
+
+ private Genotype makeG(String sample, Allele a1, Allele a2, double log10pError) {
+ return new GenotypeBuilder(sample, Arrays.asList(a1, a2)).log10PError(log10pError).make();
+ }
+
+ private VariantContext makeVC(String source, List<Allele> alleles) {
+ return makeVC(source, alleles, null, null);
+ }
+
+ private VariantContext makeVC(String source, List<Allele> alleles, Genotype... g1) {
+ return makeVC(source, alleles, Arrays.asList(g1));
+ }
+
+ private VariantContext makeVC(String source, List<Allele> alleles, String filter) {
+ return makeVC(source, alleles, filter.equals(".") ? null : new HashSet<String>(Arrays.asList(filter)));
+ }
+
+ private VariantContext makeVC(String source, List<Allele> alleles, Set<String> filters) {
+ return makeVC(source, alleles, null, filters);
+ }
+
+ private VariantContext makeVC(String source, List<Allele> alleles, Collection<Genotype> genotypes) {
+ return makeVC(source, alleles, genotypes, null);
+ }
+
+ private VariantContext makeVC(String source, List<Allele> alleles, Collection<Genotype> genotypes, Set<String> filters) {
+ int start = 10;
+ int stop = start + alleles.get(0).length() - 1; // alleles.contains(ATC) ? start + 3 : start;
+ return new VariantContextBuilder(source, "1", start, stop, alleles).genotypes(genotypes).filters(filters).make();
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test allele merging
+ //
+ // --------------------------------------------------------------------------------
+
+ private class MergeAllelesTest extends TestDataProvider {
+ List<List<Allele>> inputs;
+ List<Allele> expected;
+
+ private MergeAllelesTest(List<Allele>... arg) {
+ super(MergeAllelesTest.class);
+ LinkedList<List<Allele>> all = new LinkedList<>(Arrays.asList(arg));
+ expected = all.pollLast();
+ inputs = all;
+ }
+
+ public String toString() {
+ return String.format("MergeAllelesTest input=%s expected=%s", inputs, expected);
+ }
+ }
+ @DataProvider(name = "mergeAlleles")
+ public Object[][] mergeAllelesData() {
+ // first, do no harm
+ new MergeAllelesTest(Arrays.asList(Aref),
+ Arrays.asList(Aref));
+
+ new MergeAllelesTest(Arrays.asList(Aref),
+ Arrays.asList(Aref),
+ Arrays.asList(Aref));
+
+ new MergeAllelesTest(Arrays.asList(Aref),
+ Arrays.asList(Aref, T),
+ Arrays.asList(Aref, T));
+
+ new MergeAllelesTest(Arrays.asList(Aref, C),
+ Arrays.asList(Aref, T),
+ Arrays.asList(Aref, C, T));
+
+ new MergeAllelesTest(Arrays.asList(Aref, T),
+ Arrays.asList(Aref, C),
+ Arrays.asList(Aref, T, C)); // in order of appearence
+
+ new MergeAllelesTest(Arrays.asList(Aref, C, T),
+ Arrays.asList(Aref, C),
+ Arrays.asList(Aref, C, T));
+
+ new MergeAllelesTest(Arrays.asList(Aref, C, T), Arrays.asList(Aref, C, T));
+
+ new MergeAllelesTest(Arrays.asList(Aref, T, C), Arrays.asList(Aref, T, C));
+
+ new MergeAllelesTest(Arrays.asList(Aref, T, C),
+ Arrays.asList(Aref, C),
+ Arrays.asList(Aref, T, C)); // in order of appearence
+
+ new MergeAllelesTest(Arrays.asList(Aref),
+ Arrays.asList(Aref, ATC),
+ Arrays.asList(Aref, ATC));
+
+ new MergeAllelesTest(Arrays.asList(Aref),
+ Arrays.asList(Aref, ATC, ATCATC),
+ Arrays.asList(Aref, ATC, ATCATC));
+
+ // alleles in the order we see them
+ new MergeAllelesTest(Arrays.asList(Aref, ATCATC),
+ Arrays.asList(Aref, ATC, ATCATC),
+ Arrays.asList(Aref, ATCATC, ATC));
+
+ // same
+ new MergeAllelesTest(Arrays.asList(Aref, ATC),
+ Arrays.asList(Aref, ATCATC),
+ Arrays.asList(Aref, ATC, ATCATC));
+
+ new MergeAllelesTest(Arrays.asList(ATref, ATC, Anoref, G),
+ Arrays.asList(Aref, ATCATC, G),
+ Arrays.asList(ATref, ATC, Anoref, G, ATCATCT, GT));
+
+ return MergeAllelesTest.getTests(MergeAllelesTest.class);
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "mergeAlleles")
+ public void testMergeAlleles(MergeAllelesTest cfg) {
+ final List<VariantContext> inputs = new ArrayList<VariantContext>();
+
+ int i = 0;
+ for ( final List<Allele> alleles : cfg.inputs ) {
+ final String name = "vcf" + ++i;
+ inputs.add(makeVC(name, alleles));
+ }
+
+ final List<String> priority = vcs2priority(inputs);
+
+ final VariantContext merged = GATKVariantContextUtils.simpleMerge(
+ inputs, priority,
+ GATKVariantContextUtils.FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED,
+ GATKVariantContextUtils.GenotypeMergeType.PRIORITIZE, false, false, "set", false, false);
+
+ Assert.assertEquals(merged.getAlleles().size(),cfg.expected.size());
+ Assert.assertEquals(merged.getAlleles(), cfg.expected);
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test rsID merging
+ //
+ // --------------------------------------------------------------------------------
+
+ private class SimpleMergeRSIDTest extends TestDataProvider {
+ List<String> inputs;
+ String expected;
+
+ private SimpleMergeRSIDTest(String... arg) {
+ super(SimpleMergeRSIDTest.class);
+ LinkedList<String> allStrings = new LinkedList<String>(Arrays.asList(arg));
+ expected = allStrings.pollLast();
+ inputs = allStrings;
+ }
+
+ public String toString() {
+ return String.format("SimpleMergeRSIDTest vc=%s expected=%s", inputs, expected);
+ }
+ }
+
+ @DataProvider(name = "simplemergersiddata")
+ public Object[][] createSimpleMergeRSIDData() {
+ new SimpleMergeRSIDTest(".", ".");
+ new SimpleMergeRSIDTest(".", ".", ".");
+ new SimpleMergeRSIDTest("rs1", "rs1");
+ new SimpleMergeRSIDTest("rs1", "rs1", "rs1");
+ new SimpleMergeRSIDTest(".", "rs1", "rs1");
+ new SimpleMergeRSIDTest("rs1", ".", "rs1");
+ new SimpleMergeRSIDTest("rs1", "rs2", "rs1,rs2");
+ new SimpleMergeRSIDTest("rs1", "rs2", "rs1", "rs1,rs2"); // duplicates
+ new SimpleMergeRSIDTest("rs2", "rs1", "rs2,rs1");
+ new SimpleMergeRSIDTest("rs2", "rs1", ".", "rs2,rs1");
+ new SimpleMergeRSIDTest("rs2", ".", "rs1", "rs2,rs1");
+ new SimpleMergeRSIDTest("rs1", ".", ".", "rs1");
+ new SimpleMergeRSIDTest("rs1", "rs2", "rs3", "rs1,rs2,rs3");
+
+ return SimpleMergeRSIDTest.getTests(SimpleMergeRSIDTest.class);
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "simplemergersiddata")
+ public void testRSIDMerge(SimpleMergeRSIDTest cfg) {
+ VariantContext snpVC1 = makeVC("snpvc1", Arrays.asList(Aref, T));
+ final List<VariantContext> inputs = new ArrayList<VariantContext>();
+
+ for ( final String id : cfg.inputs ) {
+ inputs.add(new VariantContextBuilder(snpVC1).id(id).make());
+ }
+
+ final VariantContext merged = GATKVariantContextUtils.simpleMerge(
+ inputs, null,
+ GATKVariantContextUtils.FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED,
+ GATKVariantContextUtils.GenotypeMergeType.UNSORTED, false, false, "set", false, false);
+ Assert.assertEquals(merged.getID(), cfg.expected);
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test filtered merging
+ //
+ // --------------------------------------------------------------------------------
+
+ private class MergeFilteredTest extends TestDataProvider {
+ List<VariantContext> inputs;
+ VariantContext expected;
+ String setExpected;
+ GATKVariantContextUtils.FilteredRecordMergeType type;
+
+
+ private MergeFilteredTest(String name, VariantContext input1, VariantContext input2, VariantContext expected, String setExpected) {
+ this(name, input1, input2, expected, GATKVariantContextUtils.FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED, setExpected);
+ }
+
+ private MergeFilteredTest(String name, VariantContext input1, VariantContext input2, VariantContext expected, GATKVariantContextUtils.FilteredRecordMergeType type, String setExpected) {
+ super(MergeFilteredTest.class, name);
+ LinkedList<VariantContext> all = new LinkedList<VariantContext>(Arrays.asList(input1, input2));
+ this.expected = expected;
+ this.type = type;
+ inputs = all;
+ this.setExpected = setExpected;
+ }
+
+ public String toString() {
+ return String.format("%s input=%s expected=%s", super.toString(), inputs, expected);
+ }
+ }
+
+ @DataProvider(name = "mergeFiltered")
+ public Object[][] mergeFilteredData() {
+ new MergeFilteredTest("AllPass",
+ makeVC("1", Arrays.asList(Aref, T), VariantContext.PASSES_FILTERS),
+ makeVC("2", Arrays.asList(Aref, T), VariantContext.PASSES_FILTERS),
+ makeVC("3", Arrays.asList(Aref, T), VariantContext.PASSES_FILTERS),
+ GATKVariantContextUtils.MERGE_INTERSECTION);
+
+ new MergeFilteredTest("noFilters",
+ makeVC("1", Arrays.asList(Aref, T), "."),
+ makeVC("2", Arrays.asList(Aref, T), "."),
+ makeVC("3", Arrays.asList(Aref, T), "."),
+ GATKVariantContextUtils.MERGE_INTERSECTION);
+
+ new MergeFilteredTest("oneFiltered",
+ makeVC("1", Arrays.asList(Aref, T), "."),
+ makeVC("2", Arrays.asList(Aref, T), "FAIL"),
+ makeVC("3", Arrays.asList(Aref, T), "."),
+ String.format("1-%s2", GATKVariantContextUtils.MERGE_FILTER_PREFIX));
+
+ new MergeFilteredTest("onePassOneFail",
+ makeVC("1", Arrays.asList(Aref, T), VariantContext.PASSES_FILTERS),
+ makeVC("2", Arrays.asList(Aref, T), "FAIL"),
+ makeVC("3", Arrays.asList(Aref, T), VariantContext.PASSES_FILTERS),
+ String.format("1-%s2", GATKVariantContextUtils.MERGE_FILTER_PREFIX));
+
+ new MergeFilteredTest("AllFiltered",
+ makeVC("1", Arrays.asList(Aref, T), "FAIL"),
+ makeVC("2", Arrays.asList(Aref, T), "FAIL"),
+ makeVC("3", Arrays.asList(Aref, T), "FAIL"),
+ GATKVariantContextUtils.MERGE_FILTER_IN_ALL);
+
+ // test ALL vs. ANY
+ new MergeFilteredTest("FailOneUnfiltered",
+ makeVC("1", Arrays.asList(Aref, T), "FAIL"),
+ makeVC("2", Arrays.asList(Aref, T), "."),
+ makeVC("3", Arrays.asList(Aref, T), "."),
+ GATKVariantContextUtils.FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED,
+ String.format("%s1-2", GATKVariantContextUtils.MERGE_FILTER_PREFIX));
+
+ new MergeFilteredTest("OneFailAllUnfilteredArg",
+ makeVC("1", Arrays.asList(Aref, T), "FAIL"),
+ makeVC("2", Arrays.asList(Aref, T), "."),
+ makeVC("3", Arrays.asList(Aref, T), "FAIL"),
+ GATKVariantContextUtils.FilteredRecordMergeType.KEEP_IF_ALL_UNFILTERED,
+ String.format("%s1-2", GATKVariantContextUtils.MERGE_FILTER_PREFIX));
+
+ // test excluding allele in filtered record
+ new MergeFilteredTest("DontIncludeAlleleOfFilteredRecords",
+ makeVC("1", Arrays.asList(Aref, T), "."),
+ makeVC("2", Arrays.asList(Aref, T), "FAIL"),
+ makeVC("3", Arrays.asList(Aref, T), "."),
+ String.format("1-%s2", GATKVariantContextUtils.MERGE_FILTER_PREFIX));
+
+ // promotion of site from unfiltered to PASSES
+ new MergeFilteredTest("UnfilteredPlusPassIsPass",
+ makeVC("1", Arrays.asList(Aref, T), "."),
+ makeVC("2", Arrays.asList(Aref, T), VariantContext.PASSES_FILTERS),
+ makeVC("3", Arrays.asList(Aref, T), VariantContext.PASSES_FILTERS),
+ GATKVariantContextUtils.MERGE_INTERSECTION);
+
+ new MergeFilteredTest("RefInAll",
+ makeVC("1", Arrays.asList(Aref), VariantContext.PASSES_FILTERS),
+ makeVC("2", Arrays.asList(Aref), VariantContext.PASSES_FILTERS),
+ makeVC("3", Arrays.asList(Aref), VariantContext.PASSES_FILTERS),
+ GATKVariantContextUtils.MERGE_REF_IN_ALL);
+
+ new MergeFilteredTest("RefInOne",
+ makeVC("1", Arrays.asList(Aref), VariantContext.PASSES_FILTERS),
+ makeVC("2", Arrays.asList(Aref, T), VariantContext.PASSES_FILTERS),
+ makeVC("3", Arrays.asList(Aref, T), VariantContext.PASSES_FILTERS),
+ "2");
+
+ return MergeFilteredTest.getTests(MergeFilteredTest.class);
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "mergeFiltered")
+ public void testMergeFiltered(MergeFilteredTest cfg) {
+ final List<String> priority = vcs2priority(cfg.inputs);
+ final VariantContext merged = GATKVariantContextUtils.simpleMerge(
+ cfg.inputs, priority, cfg.type, GATKVariantContextUtils.GenotypeMergeType.PRIORITIZE, true, false, "set", false, false);
+
+ // test alleles are equal
+ Assert.assertEquals(merged.getAlleles(), cfg.expected.getAlleles());
+
+ // test set field
+ Assert.assertEquals(merged.getAttribute("set"), cfg.setExpected);
+
+ // test filter field
+ Assert.assertEquals(merged.getFilters(), cfg.expected.getFilters());
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test genotype merging
+ //
+ // --------------------------------------------------------------------------------
+
+ private class MergeGenotypesTest extends TestDataProvider {
+ List<VariantContext> inputs;
+ VariantContext expected;
+ List<String> priority;
+
+ private MergeGenotypesTest(String name, String priority, VariantContext... arg) {
+ super(MergeGenotypesTest.class, name);
+ LinkedList<VariantContext> all = new LinkedList<VariantContext>(Arrays.asList(arg));
+ this.expected = all.pollLast();
+ inputs = all;
+ this.priority = Arrays.asList(priority.split(","));
+ }
+
+ public String toString() {
+ return String.format("%s input=%s expected=%s", super.toString(), inputs, expected);
+ }
+ }
+
+ @DataProvider(name = "mergeGenotypes")
+ public Object[][] mergeGenotypesData() {
+ new MergeGenotypesTest("TakeGenotypeByPriority-1,2", "1,2",
+ makeVC("1", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1)),
+ makeVC("2", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2)),
+ makeVC("3", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1)));
+
+ new MergeGenotypesTest("TakeGenotypeByPriority-1,2-nocall", "1,2",
+ makeVC("1", Arrays.asList(Aref, T), makeG("s1", Allele.NO_CALL, Allele.NO_CALL, -1)),
+ makeVC("2", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2)),
+ makeVC("3", Arrays.asList(Aref, T), makeG("s1", Allele.NO_CALL, Allele.NO_CALL, -1)));
+
+ new MergeGenotypesTest("TakeGenotypeByPriority-2,1", "2,1",
+ makeVC("1", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1)),
+ makeVC("2", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2)),
+ makeVC("3", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2)));
+
+ new MergeGenotypesTest("NonOverlappingGenotypes", "1,2",
+ makeVC("1", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1)),
+ makeVC("2", Arrays.asList(Aref, T), makeG("s2", Aref, T, -2)),
+ makeVC("3", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1), makeG("s2", Aref, T, -2)));
+
+ new MergeGenotypesTest("PreserveNoCall", "1,2",
+ makeVC("1", Arrays.asList(Aref, T), makeG("s1", Allele.NO_CALL, Allele.NO_CALL, -1)),
+ makeVC("2", Arrays.asList(Aref, T), makeG("s2", Aref, T, -2)),
+ makeVC("3", Arrays.asList(Aref, T), makeG("s1", Allele.NO_CALL, Allele.NO_CALL, -1), makeG("s2", Aref, T, -2)));
+
+ new MergeGenotypesTest("PerserveAlleles", "1,2",
+ makeVC("1", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1)),
+ makeVC("2", Arrays.asList(Aref, C), makeG("s2", Aref, C, -2)),
+ makeVC("3", Arrays.asList(Aref, T, C), makeG("s1", Aref, T, -1), makeG("s2", Aref, C, -2)));
+
+ new MergeGenotypesTest("TakeGenotypePartialOverlap-1,2", "1,2",
+ makeVC("1", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1)),
+ makeVC("2", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2), makeG("s3", Aref, T, -3)),
+ makeVC("3", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1), makeG("s3", Aref, T, -3)));
+
+ new MergeGenotypesTest("TakeGenotypePartialOverlap-2,1", "2,1",
+ makeVC("1", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1)),
+ makeVC("2", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2), makeG("s3", Aref, T, -3)),
+ makeVC("3", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2), makeG("s3", Aref, T, -3)));
+
+ //
+ // merging genothpes with PLs
+ //
+
+ // first, do no harm
+ new MergeGenotypesTest("OrderedPLs", "1",
+ makeVC("1", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1, 1, 2, 3)),
+ makeVC("1", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1, 1, 2, 3)));
+
+ // first, do no harm
+ new MergeGenotypesTest("OrderedPLs-3Alleles", "1",
+ makeVC("1", Arrays.asList(Aref, C, T), makeG("s1", Aref, T, -1, 1, 2, 3, 4, 5, 6)),
+ makeVC("1", Arrays.asList(Aref, C, T), makeG("s1", Aref, T, -1, 1, 2, 3, 4, 5, 6)));
+
+ // first, do no harm
+ new MergeGenotypesTest("OrderedPLs-3Alleles-2", "1",
+ makeVC("1", Arrays.asList(Aref, T, C), makeG("s1", Aref, T, -1, 1, 2, 3, 4, 5, 6)),
+ makeVC("1", Arrays.asList(Aref, T, C), makeG("s1", Aref, T, -1, 1, 2, 3, 4, 5, 6)));
+
+ // first, do no harm
+ new MergeGenotypesTest("OrderedPLs-3Alleles-2", "1",
+ makeVC("1", Arrays.asList(Aref, T, C), makeG("s1", Aref, T, -1, 1, 2, 3, 4, 5, 6)),
+ makeVC("1", Arrays.asList(Aref, T, C), makeG("s2", Aref, C, -1, 1, 2, 3, 4, 5, 6)),
+ makeVC("1", Arrays.asList(Aref, T, C), makeG("s1", Aref, T, -1, 1, 2, 3, 4, 5, 6), makeG("s2", Aref, C, -1, 1, 2, 3, 4, 5, 6)));
+
+ new MergeGenotypesTest("TakeGenotypePartialOverlapWithPLs-2,1", "2,1",
+ makeVC("1", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1,5,0,3)),
+ makeVC("2", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2,4,0,2), makeG("s3", Aref, T, -3,3,0,2)),
+ makeVC("3", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2,4,0,2), makeG("s3", Aref, T, -3,3,0,2)));
+
+ new MergeGenotypesTest("TakeGenotypePartialOverlapWithPLs-1,2", "1,2",
+ makeVC("1", Arrays.asList(Aref,ATC), makeG("s1", Aref, ATC, -1,5,0,3)),
+ makeVC("2", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2,4,0,2), makeG("s3", Aref, T, -3,3,0,2)),
+ // no likelihoods on result since type changes to mixed multiallelic
+ makeVC("3", Arrays.asList(Aref, ATC, T), makeG("s1", Aref, ATC, -1), makeG("s3", Aref, T, -3)));
+
+ new MergeGenotypesTest("MultipleSamplePLsDifferentOrder", "1,2",
+ makeVC("1", Arrays.asList(Aref, C, T), makeG("s1", Aref, C, -1, 1, 2, 3, 4, 5, 6)),
+ makeVC("2", Arrays.asList(Aref, T, C), makeG("s2", Aref, T, -2, 6, 5, 4, 3, 2, 1)),
+ // no likelihoods on result since type changes to mixed multiallelic
+ makeVC("3", Arrays.asList(Aref, C, T), makeG("s1", Aref, C, -1), makeG("s2", Aref, T, -2)));
+
+ return MergeGenotypesTest.getTests(MergeGenotypesTest.class);
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "mergeGenotypes")
+ public void testMergeGenotypes(MergeGenotypesTest cfg) {
+ final VariantContext merged = GATKVariantContextUtils.simpleMerge(
+ cfg.inputs, cfg.priority, GATKVariantContextUtils.FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED,
+ GATKVariantContextUtils.GenotypeMergeType.PRIORITIZE, true, false, "set", false, false);
+
+ // test alleles are equal
+ Assert.assertEquals(merged.getAlleles(), cfg.expected.getAlleles());
+
+ // test genotypes
+ assertGenotypesAreMostlyEqual(merged.getGenotypes(), cfg.expected.getGenotypes());
+ }
+
+ // necessary to not overload equals for genotypes
+ private void assertGenotypesAreMostlyEqual(GenotypesContext actual, GenotypesContext expected) {
+ if (actual == expected) {
+ return;
+ }
+
+ if (actual == null || expected == null) {
+ Assert.fail("Maps not equal: expected: " + expected + " and actual: " + actual);
+ }
+
+ if (actual.size() != expected.size()) {
+ Assert.fail("Maps do not have the same size:" + actual.size() + " != " + expected.size());
+ }
+
+ for (Genotype value : actual) {
+ Genotype expectedValue = expected.get(value.getSampleName());
+
+ Assert.assertEquals(value.getAlleles(), expectedValue.getAlleles(), "Alleles in Genotype aren't equal");
+ Assert.assertEquals(value.getGQ(), expectedValue.getGQ(), "GQ values aren't equal");
+ Assert.assertEquals(value.hasLikelihoods(), expectedValue.hasLikelihoods(), "Either both have likelihoods or both not");
+ if ( value.hasLikelihoods() )
+ Assert.assertEquals(value.getLikelihoods().getAsVector(), expectedValue.getLikelihoods().getAsVector(), "Genotype likelihoods aren't equal");
+ }
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testMergeGenotypesUniquify() {
+ final VariantContext vc1 = makeVC("1", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1));
+ final VariantContext vc2 = makeVC("2", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2));
+
+ final VariantContext merged = GATKVariantContextUtils.simpleMerge(
+ Arrays.asList(vc1, vc2), null, GATKVariantContextUtils.FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED,
+ GATKVariantContextUtils.GenotypeMergeType.UNIQUIFY, false, false, "set", false, false);
+
+ // test genotypes
+ Assert.assertEquals(merged.getSampleNames(), new HashSet<>(Arrays.asList("s1.1", "s1.2")));
+ }
+
+// TODO: remove after testing
+// @Test(expectedExceptions = IllegalStateException.class)
+// public void testMergeGenotypesRequireUnique() {
+// final VariantContext vc1 = makeVC("1", Arrays.asList(Aref, T), makeG("s1", Aref, T, -1));
+// final VariantContext vc2 = makeVC("2", Arrays.asList(Aref, T), makeG("s1", Aref, T, -2));
+//
+// final VariantContext merged = VariantContextUtils.simpleMerge(
+// Arrays.asList(vc1, vc2), null, VariantContextUtils.FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED,
+// VariantContextUtils.GenotypeMergeType.REQUIRE_UNIQUE, false, false, "set", false, false, false);
+// }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Misc. tests
+ //
+ // --------------------------------------------------------------------------------
+
+ @Test(enabled = !DEBUG)
+ public void testAnnotationSet() {
+ for ( final boolean annotate : Arrays.asList(true, false)) {
+ for ( final String set : Arrays.asList("set", "combine", "x")) {
+ final List<String> priority = Arrays.asList("1", "2");
+ VariantContext vc1 = makeVC("1", Arrays.asList(Aref, T), VariantContext.PASSES_FILTERS);
+ VariantContext vc2 = makeVC("2", Arrays.asList(Aref, T), VariantContext.PASSES_FILTERS);
+
+ final VariantContext merged = GATKVariantContextUtils.simpleMerge(
+ Arrays.asList(vc1, vc2), priority, GATKVariantContextUtils.FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED,
+ GATKVariantContextUtils.GenotypeMergeType.PRIORITIZE, annotate, false, set, false, false);
+
+ if ( annotate )
+ Assert.assertEquals(merged.getAttribute(set), GATKVariantContextUtils.MERGE_INTERSECTION);
+ else
+ Assert.assertFalse(merged.hasAttribute(set));
+ }
+ }
+ }
+
+ private static final List<String> vcs2priority(final Collection<VariantContext> vcs) {
+ final List<String> priority = new ArrayList<>();
+
+ for ( final VariantContext vc : vcs ) {
+ priority.add(vc.getSource());
+ }
+
+ return priority;
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // basic allele clipping test
+ //
+ // --------------------------------------------------------------------------------
+
+ private class ReverseClippingPositionTestProvider extends TestDataProvider {
+ final String ref;
+ final List<Allele> alleles = new ArrayList<Allele>();
+ final int expectedClip;
+
+ private ReverseClippingPositionTestProvider(final int expectedClip, final String ref, final String... alleles) {
+ super(ReverseClippingPositionTestProvider.class);
+ this.ref = ref;
+ for ( final String allele : alleles )
+ this.alleles.add(Allele.create(allele));
+ this.expectedClip = expectedClip;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("ref=%s allele=%s reverse clip %d", ref, alleles, expectedClip);
+ }
+ }
+
+ @DataProvider(name = "ReverseClippingPositionTestProvider")
+ public Object[][] makeReverseClippingPositionTestProvider() {
+ // pair clipping
+ new ReverseClippingPositionTestProvider(0, "ATT", "CCG");
+ new ReverseClippingPositionTestProvider(1, "ATT", "CCT");
+ new ReverseClippingPositionTestProvider(2, "ATT", "CTT");
+ new ReverseClippingPositionTestProvider(2, "ATT", "ATT"); // cannot completely clip allele
+
+ // triplets
+ new ReverseClippingPositionTestProvider(0, "ATT", "CTT", "CGG");
+ new ReverseClippingPositionTestProvider(1, "ATT", "CTT", "CGT"); // the T can go
+ new ReverseClippingPositionTestProvider(2, "ATT", "CTT", "CTT"); // both Ts can go
+
+ return ReverseClippingPositionTestProvider.getTests(ReverseClippingPositionTestProvider.class);
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "ReverseClippingPositionTestProvider")
+ public void testReverseClippingPositionTestProvider(ReverseClippingPositionTestProvider cfg) {
+ int result = GATKVariantContextUtils.computeReverseClipping(cfg.alleles, cfg.ref.getBytes());
+ Assert.assertEquals(result, cfg.expectedClip);
+ }
+
+
+ // --------------------------------------------------------------------------------
+ //
+ // test splitting into bi-allelics
+ //
+ // --------------------------------------------------------------------------------
+
+ @DataProvider(name = "SplitBiallelics")
+ public Object[][] makeSplitBiallelics() throws CloneNotSupportedException {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final VariantContextBuilder root = new VariantContextBuilder("x", "20", 10, 10, Arrays.asList(Aref, C));
+
+ // biallelic -> biallelic
+ tests.add(new Object[]{root.make(), Arrays.asList(root.make())});
+
+ // monos -> monos
+ root.alleles(Arrays.asList(Aref));
+ tests.add(new Object[]{root.make(), Arrays.asList(root.make())});
+
+ root.alleles(Arrays.asList(Aref, C, T));
+ tests.add(new Object[]{root.make(),
+ Arrays.asList(
+ root.alleles(Arrays.asList(Aref, C)).make(),
+ root.alleles(Arrays.asList(Aref, T)).make())});
+
+ root.alleles(Arrays.asList(Aref, C, T, G));
+ tests.add(new Object[]{root.make(),
+ Arrays.asList(
+ root.alleles(Arrays.asList(Aref, C)).make(),
+ root.alleles(Arrays.asList(Aref, T)).make(),
+ root.alleles(Arrays.asList(Aref, G)).make())});
+
+ final Allele C = Allele.create("C");
+ final Allele CA = Allele.create("CA");
+ final Allele CAA = Allele.create("CAA");
+ final Allele CAAAA = Allele.create("CAAAA");
+ final Allele CAAAAA = Allele.create("CAAAAA");
+ final Allele Cref = Allele.create("C", true);
+ final Allele CAref = Allele.create("CA", true);
+ final Allele CAAref = Allele.create("CAA", true);
+ final Allele CAAAref = Allele.create("CAAA", true);
+
+ root.alleles(Arrays.asList(Cref, CA, CAA));
+ tests.add(new Object[]{root.make(),
+ Arrays.asList(
+ root.alleles(Arrays.asList(Cref, CA)).make(),
+ root.alleles(Arrays.asList(Cref, CAA)).make())});
+
+ root.alleles(Arrays.asList(CAAref, C, CA)).stop(12);
+ tests.add(new Object[]{root.make(),
+ Arrays.asList(
+ root.alleles(Arrays.asList(CAAref, C)).make(),
+ root.alleles(Arrays.asList(CAref, C)).stop(11).make())});
+
+ root.alleles(Arrays.asList(CAAAref, C, CA, CAA)).stop(13);
+ tests.add(new Object[]{root.make(),
+ Arrays.asList(
+ root.alleles(Arrays.asList(CAAAref, C)).make(),
+ root.alleles(Arrays.asList(CAAref, C)).stop(12).make(),
+ root.alleles(Arrays.asList(CAref, C)).stop(11).make())});
+
+ root.alleles(Arrays.asList(CAAAref, CAAAAA, CAAAA, CAA, C)).stop(13);
+ tests.add(new Object[]{root.make(),
+ Arrays.asList(
+ root.alleles(Arrays.asList(Cref, CAA)).stop(10).make(),
+ root.alleles(Arrays.asList(Cref, CA)).stop(10).make(),
+ root.alleles(Arrays.asList(CAref, C)).stop(11).make(),
+ root.alleles(Arrays.asList(CAAAref, C)).stop(13).make())});
+
+ final Allele threeCopies = Allele.create("GTTTTATTTTATTTTA", true);
+ final Allele twoCopies = Allele.create("GTTTTATTTTA", true);
+ final Allele zeroCopies = Allele.create("G", false);
+ final Allele oneCopies = Allele.create("GTTTTA", false);
+ tests.add(new Object[]{root.alleles(Arrays.asList(threeCopies, zeroCopies, oneCopies)).stop(25).make(),
+ Arrays.asList(
+ root.alleles(Arrays.asList(threeCopies, zeroCopies)).stop(25).make(),
+ root.alleles(Arrays.asList(twoCopies, zeroCopies)).stop(20).make())});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "SplitBiallelics")
+ public void testSplitBiallelicsNoGenotypes(final VariantContext vc, final List<VariantContext> expectedBiallelics) {
+ final List<VariantContext> biallelics = GATKVariantContextUtils.splitVariantContextToBiallelics(vc);
+ Assert.assertEquals(biallelics.size(), expectedBiallelics.size());
+ for ( int i = 0; i < biallelics.size(); i++ ) {
+ final VariantContext actual = biallelics.get(i);
+ final VariantContext expected = expectedBiallelics.get(i);
+ assertVariantContextsAreEqual(actual, expected);
+ }
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "SplitBiallelics", dependsOnMethods = "testSplitBiallelicsNoGenotypes")
+ public void testSplitBiallelicsGenotypes(final VariantContext vc, final List<VariantContext> expectedBiallelics) {
+ final List<Genotype> genotypes = new ArrayList<Genotype>();
+
+ int sampleI = 0;
+ for ( final List<Allele> alleles : Utils.makePermutations(vc.getAlleles(), 2, true) ) {
+ genotypes.add(GenotypeBuilder.create("sample" + sampleI++, alleles));
+ }
+ genotypes.add(GenotypeBuilder.createMissing("missing", 2));
+
+ final VariantContext vcWithGenotypes = new VariantContextBuilder(vc).genotypes(genotypes).make();
+
+ final List<VariantContext> biallelics = GATKVariantContextUtils.splitVariantContextToBiallelics(vcWithGenotypes);
+ for ( int i = 0; i < biallelics.size(); i++ ) {
+ final VariantContext actual = biallelics.get(i);
+ Assert.assertEquals(actual.getNSamples(), vcWithGenotypes.getNSamples()); // not dropping any samples
+
+ for ( final Genotype inputGenotype : genotypes ) {
+ final Genotype actualGenotype = actual.getGenotype(inputGenotype.getSampleName());
+ Assert.assertNotNull(actualGenotype);
+ if ( ! vc.isVariant() || vc.isBiallelic() )
+ Assert.assertEquals(actualGenotype, vcWithGenotypes.getGenotype(inputGenotype.getSampleName()));
+ else
+ Assert.assertTrue(actualGenotype.isNoCall());
+ }
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test repeats
+ //
+ // --------------------------------------------------------------------------------
+
+ private class RepeatDetectorTest extends TestDataProvider {
+ String ref;
+ boolean isTrueRepeat;
+ VariantContext vc;
+
+ private RepeatDetectorTest(boolean isTrueRepeat, String ref, String refAlleleString, String ... altAlleleStrings) {
+ super(RepeatDetectorTest.class);
+ this.isTrueRepeat = isTrueRepeat;
+ this.ref = ref;
+
+ List<Allele> alleles = new LinkedList<Allele>();
+ final Allele refAllele = Allele.create(refAlleleString, true);
+ alleles.add(refAllele);
+ for ( final String altString: altAlleleStrings) {
+ final Allele alt = Allele.create(altString, false);
+ alleles.add(alt);
+ }
+
+ VariantContextBuilder builder = new VariantContextBuilder("test", "chr1", 1, refAllele.length(), alleles);
+ this.vc = builder.make();
+ }
+
+ public String toString() {
+ return String.format("%s refBases=%s trueRepeat=%b vc=%s", super.toString(), ref, isTrueRepeat, vc);
+ }
+ }
+
+ @DataProvider(name = "RepeatDetectorTest")
+ public Object[][] makeRepeatDetectorTest() {
+ new RepeatDetectorTest(true, "NAAC", "N", "NA");
+ new RepeatDetectorTest(true, "NAAC", "NA", "N");
+ new RepeatDetectorTest(false, "NAAC", "NAA", "N");
+ new RepeatDetectorTest(false, "NAAC", "N", "NC");
+ new RepeatDetectorTest(false, "AAC", "A", "C");
+
+ // running out of ref bases => false
+ new RepeatDetectorTest(false, "NAAC", "N", "NCAGTA");
+
+ // complex repeats
+ new RepeatDetectorTest(true, "NATATATC", "N", "NAT");
+ new RepeatDetectorTest(true, "NATATATC", "N", "NATA");
+ new RepeatDetectorTest(true, "NATATATC", "N", "NATAT");
+ new RepeatDetectorTest(true, "NATATATC", "NAT", "N");
+ new RepeatDetectorTest(false, "NATATATC", "NATA", "N");
+ new RepeatDetectorTest(false, "NATATATC", "NATAT", "N");
+
+ // multi-allelic
+ new RepeatDetectorTest(true, "NATATATC", "N", "NAT", "NATAT");
+ new RepeatDetectorTest(true, "NATATATC", "N", "NAT", "NATA");
+ new RepeatDetectorTest(true, "NATATATC", "NAT", "N", "NATAT");
+ new RepeatDetectorTest(true, "NATATATC", "NAT", "N", "NATA"); // two As
+ new RepeatDetectorTest(false, "NATATATC", "NAT", "N", "NATC"); // false
+ new RepeatDetectorTest(false, "NATATATC", "NAT", "N", "NCC"); // false
+ new RepeatDetectorTest(false, "NATATATC", "NAT", "NATAT", "NCC"); // false
+
+ return RepeatDetectorTest.getTests(RepeatDetectorTest.class);
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "RepeatDetectorTest")
+ public void testRepeatDetectorTest(RepeatDetectorTest cfg) {
+
+ // test alleles are equal
+ Assert.assertEquals(GATKVariantContextUtils.isTandemRepeat(cfg.vc, cfg.ref.getBytes()), cfg.isTrueRepeat);
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testRepeatAllele() {
+ Allele nullR = Allele.create("A", true);
+ Allele nullA = Allele.create("A", false);
+ Allele atc = Allele.create("AATC", false);
+ Allele atcatc = Allele.create("AATCATC", false);
+ Allele ccccR = Allele.create("ACCCC", true);
+ Allele cc = Allele.create("ACC", false);
+ Allele cccccc = Allele.create("ACCCCCC", false);
+ Allele gagaR = Allele.create("AGAGA", true);
+ Allele gagagaga = Allele.create("AGAGAGAGA", false);
+
+ // - / ATC [ref] from 20-22
+ String delLoc = "chr1";
+ int delLocStart = 20;
+ int delLocStop = 22;
+
+ // - [ref] / ATC from 20-20
+ String insLoc = "chr1";
+ int insLocStart = 20;
+ int insLocStop = 20;
+
+ Pair<List<Integer>,byte[]> result;
+ byte[] refBytes = "TATCATCATCGGA".getBytes();
+
+ Assert.assertEquals(GATKVariantContextUtils.findNumberOfRepetitions("ATG".getBytes(), "ATGATGATGATG".getBytes(), true),4);
+ Assert.assertEquals(GATKVariantContextUtils.findNumberOfRepetitions("G".getBytes(), "ATGATGATGATG".getBytes(), true),0);
+ Assert.assertEquals(GATKVariantContextUtils.findNumberOfRepetitions("T".getBytes(), "T".getBytes(), true),1);
+ Assert.assertEquals(GATKVariantContextUtils.findNumberOfRepetitions("AT".getBytes(), "ATGATGATCATG".getBytes(), true),1);
+ Assert.assertEquals(GATKVariantContextUtils.findNumberOfRepetitions("CCC".getBytes(), "CCCCCCCC".getBytes(), true),2);
+
+ Assert.assertEquals(GATKVariantContextUtils.findRepeatedSubstring("ATG".getBytes()),3);
+ Assert.assertEquals(GATKVariantContextUtils.findRepeatedSubstring("AAA".getBytes()),1);
+ Assert.assertEquals(GATKVariantContextUtils.findRepeatedSubstring("CACACAC".getBytes()),7);
+ Assert.assertEquals(GATKVariantContextUtils.findRepeatedSubstring("CACACA".getBytes()),2);
+ Assert.assertEquals(GATKVariantContextUtils.findRepeatedSubstring("CATGCATG".getBytes()),4);
+ Assert.assertEquals(GATKVariantContextUtils.findRepeatedSubstring("AATAATA".getBytes()),7);
+
+
+ // A*,ATC, context = ATC ATC ATC : (ATC)3 -> (ATC)4
+ VariantContext vc = new VariantContextBuilder("foo", insLoc, insLocStart, insLocStop, Arrays.asList(nullR,atc)).make();
+ result = GATKVariantContextUtils.getNumTandemRepeatUnits(vc, refBytes);
+ Assert.assertEquals(result.getFirst().toArray()[0],3);
+ Assert.assertEquals(result.getFirst().toArray()[1],4);
+ Assert.assertEquals(result.getSecond().length,3);
+
+ // ATC*,A,ATCATC
+ vc = new VariantContextBuilder("foo", insLoc, insLocStart, insLocStart+3, Arrays.asList(Allele.create("AATC", true),nullA,atcatc)).make();
+ result = GATKVariantContextUtils.getNumTandemRepeatUnits(vc, refBytes);
+ Assert.assertEquals(result.getFirst().toArray()[0],3);
+ Assert.assertEquals(result.getFirst().toArray()[1],2);
+ Assert.assertEquals(result.getFirst().toArray()[2],4);
+ Assert.assertEquals(result.getSecond().length,3);
+
+ // simple non-tandem deletion: CCCC*, -
+ refBytes = "TCCCCCCCCATG".getBytes();
+ vc = new VariantContextBuilder("foo", delLoc, 10, 14, Arrays.asList(ccccR,nullA)).make();
+ result = GATKVariantContextUtils.getNumTandemRepeatUnits(vc, refBytes);
+ Assert.assertEquals(result.getFirst().toArray()[0],8);
+ Assert.assertEquals(result.getFirst().toArray()[1],4);
+ Assert.assertEquals(result.getSecond().length,1);
+
+ // CCCC*,CC,-,CCCCCC, context = CCC: (C)7 -> (C)5,(C)3,(C)9
+ refBytes = "TCCCCCCCAGAGAGAG".getBytes();
+ vc = new VariantContextBuilder("foo", insLoc, insLocStart, insLocStart+4, Arrays.asList(ccccR,cc, nullA,cccccc)).make();
+ result = GATKVariantContextUtils.getNumTandemRepeatUnits(vc, refBytes);
+ Assert.assertEquals(result.getFirst().toArray()[0],7);
+ Assert.assertEquals(result.getFirst().toArray()[1],5);
+ Assert.assertEquals(result.getFirst().toArray()[2],3);
+ Assert.assertEquals(result.getFirst().toArray()[3],9);
+ Assert.assertEquals(result.getSecond().length,1);
+
+ // GAGA*,-,GAGAGAGA
+ refBytes = "TGAGAGAGAGATTT".getBytes();
+ vc = new VariantContextBuilder("foo", insLoc, insLocStart, insLocStart+4, Arrays.asList(gagaR, nullA,gagagaga)).make();
+ result = GATKVariantContextUtils.getNumTandemRepeatUnits(vc, refBytes);
+ Assert.assertEquals(result.getFirst().toArray()[0],5);
+ Assert.assertEquals(result.getFirst().toArray()[1],3);
+ Assert.assertEquals(result.getFirst().toArray()[2],7);
+ Assert.assertEquals(result.getSecond().length,2);
+
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // test forward clipping
+ //
+ // --------------------------------------------------------------------------------
+
+ @DataProvider(name = "ForwardClippingData")
+ public Object[][] makeForwardClippingData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ tests.add(new Object[]{Arrays.asList("A"), -1});
+ tests.add(new Object[]{Arrays.asList("<DEL>"), -1});
+ tests.add(new Object[]{Arrays.asList("A", "C"), -1});
+ tests.add(new Object[]{Arrays.asList("AC", "C"), -1});
+ tests.add(new Object[]{Arrays.asList("A", "G"), -1});
+ tests.add(new Object[]{Arrays.asList("A", "T"), -1});
+ tests.add(new Object[]{Arrays.asList("GT", "CA"), -1});
+ tests.add(new Object[]{Arrays.asList("GT", "CT"), -1});
+ tests.add(new Object[]{Arrays.asList("ACC", "AC"), 0});
+ tests.add(new Object[]{Arrays.asList("ACGC", "ACG"), 1});
+ tests.add(new Object[]{Arrays.asList("ACGC", "ACG"), 1});
+ tests.add(new Object[]{Arrays.asList("ACGC", "ACGA"), 2});
+ tests.add(new Object[]{Arrays.asList("ACGC", "AGC"), 0});
+ tests.add(new Object[]{Arrays.asList("A", "<DEL>"), -1});
+ for ( int len = 0; len < 50; len++ )
+ tests.add(new Object[]{Arrays.asList("A" + new String(Utils.dupBytes((byte)'C', len)), "C"), -1});
+
+ tests.add(new Object[]{Arrays.asList("A", "T", "C"), -1});
+ tests.add(new Object[]{Arrays.asList("AT", "AC", "AG"), 0});
+ tests.add(new Object[]{Arrays.asList("AT", "AC", "A"), -1});
+ tests.add(new Object[]{Arrays.asList("AT", "AC", "ACG"), 0});
+ tests.add(new Object[]{Arrays.asList("AC", "AC", "ACG"), 0});
+ tests.add(new Object[]{Arrays.asList("AC", "ACT", "ACG"), 0});
+ tests.add(new Object[]{Arrays.asList("ACG", "ACGT", "ACGTA"), 1});
+ tests.add(new Object[]{Arrays.asList("ACG", "ACGT", "ACGCA"), 1});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "ForwardClippingData")
+ public void testForwardClipping(final List<String> alleleStrings, final int expectedClip) {
+ final List<Allele> alleles = new LinkedList<Allele>();
+ for ( final String alleleString : alleleStrings )
+ alleles.add(Allele.create(alleleString));
+
+ for ( final List<Allele> myAlleles : Utils.makePermutations(alleles, alleles.size(), false)) {
+ final int actual = GATKVariantContextUtils.computeForwardClipping(myAlleles);
+ Assert.assertEquals(actual, expectedClip);
+ }
+ }
+
+ @DataProvider(name = "ClipAlleleTest")
+ public Object[][] makeClipAlleleTest() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ // this functionality can be adapted to provide input data for whatever you might want in your data
+ tests.add(new Object[]{Arrays.asList("ACC", "AC"), Arrays.asList("AC", "A"), 0});
+ tests.add(new Object[]{Arrays.asList("ACGC", "ACG"), Arrays.asList("GC", "G"), 2});
+ tests.add(new Object[]{Arrays.asList("ACGC", "ACGA"), Arrays.asList("C", "A"), 3});
+ tests.add(new Object[]{Arrays.asList("ACGC", "AGC"), Arrays.asList("AC", "A"), 0});
+ tests.add(new Object[]{Arrays.asList("AT", "AC", "AG"), Arrays.asList("T", "C", "G"), 1});
+ tests.add(new Object[]{Arrays.asList("AT", "AC", "ACG"), Arrays.asList("T", "C", "CG"), 1});
+ tests.add(new Object[]{Arrays.asList("AC", "ACT", "ACG"), Arrays.asList("C", "CT", "CG"), 1});
+ tests.add(new Object[]{Arrays.asList("ACG", "ACGT", "ACGTA"), Arrays.asList("G", "GT", "GTA"), 2});
+ tests.add(new Object[]{Arrays.asList("ACG", "ACGT", "ACGCA"), Arrays.asList("G", "GT", "GCA"), 2});
+
+ // trims from left and right
+ tests.add(new Object[]{Arrays.asList("ACGTT", "ACCTT"), Arrays.asList("G", "C"), 2});
+ tests.add(new Object[]{Arrays.asList("ACGTT", "ACCCTT"), Arrays.asList("G", "CC"), 2});
+ tests.add(new Object[]{Arrays.asList("ACGTT", "ACGCTT"), Arrays.asList("G", "GC"), 2});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "ClipAlleleTest")
+ public void testClipAlleles(final List<String> alleleStrings, final List<String> expected, final int numLeftClipped) {
+ final int start = 10;
+ final VariantContext unclipped = GATKVariantContextUtils.makeFromAlleles("test", "20", start, alleleStrings);
+ final VariantContext clipped = GATKVariantContextUtils.trimAlleles(unclipped, true, true);
+
+ Assert.assertEquals(clipped.getStart(), unclipped.getStart() + numLeftClipped);
+ for ( int i = 0; i < unclipped.getAlleles().size(); i++ ) {
+ final Allele trimmed = clipped.getAlleles().get(i);
+ Assert.assertEquals(trimmed.getBaseString(), expected.get(i));
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // test primitive allele splitting
+ //
+ // --------------------------------------------------------------------------------
+
+ @DataProvider(name = "PrimitiveAlleleSplittingData")
+ public Object[][] makePrimitiveAlleleSplittingData() {
+ List<Object[]> tests = new ArrayList<>();
+
+ // no split
+ tests.add(new Object[]{"A", "C", 0, null});
+ tests.add(new Object[]{"A", "AC", 0, null});
+ tests.add(new Object[]{"AC", "A", 0, null});
+
+ // one split
+ tests.add(new Object[]{"ACA", "GCA", 1, Arrays.asList(0)});
+ tests.add(new Object[]{"ACA", "AGA", 1, Arrays.asList(1)});
+ tests.add(new Object[]{"ACA", "ACG", 1, Arrays.asList(2)});
+
+ // two splits
+ tests.add(new Object[]{"ACA", "GGA", 2, Arrays.asList(0, 1)});
+ tests.add(new Object[]{"ACA", "GCG", 2, Arrays.asList(0, 2)});
+ tests.add(new Object[]{"ACA", "AGG", 2, Arrays.asList(1, 2)});
+
+ // three splits
+ tests.add(new Object[]{"ACA", "GGG", 3, Arrays.asList(0, 1, 2)});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "PrimitiveAlleleSplittingData")
+ public void testPrimitiveAlleleSplitting(final String ref, final String alt, final int expectedSplit, final List<Integer> variantPositions) {
+
+ final int start = 10;
+ final VariantContext vc = GATKVariantContextUtils.makeFromAlleles("test", "20", start, Arrays.asList(ref, alt));
+
+ final List<VariantContext> result = GATKVariantContextUtils.splitIntoPrimitiveAlleles(vc);
+
+ if ( expectedSplit > 0 ) {
+ Assert.assertEquals(result.size(), expectedSplit);
+ for ( int i = 0; i < variantPositions.size(); i++ ) {
+ Assert.assertEquals(result.get(i).getStart(), start + variantPositions.get(i));
+ }
+ } else {
+ Assert.assertEquals(result.size(), 1);
+ Assert.assertEquals(vc, result.get(0));
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // test allele remapping
+ //
+ // --------------------------------------------------------------------------------
+
+ @DataProvider(name = "AlleleRemappingData")
+ public Object[][] makeAlleleRemappingData() {
+ List<Object[]> tests = new ArrayList<>();
+
+ final Allele originalBase1 = Allele.create((byte)'A');
+ final Allele originalBase2 = Allele.create((byte)'T');
+
+ for ( final byte base1 : BaseUtils.BASES ) {
+ for ( final byte base2 : BaseUtils.BASES ) {
+ for ( final int numGenotypes : Arrays.asList(0, 1, 2, 5) ) {
+ Map<Allele, Allele> map = new HashMap<>(2);
+ map.put(originalBase1, Allele.create(base1));
+ map.put(originalBase2, Allele.create(base2));
+
+ tests.add(new Object[]{map, numGenotypes});
+ }
+ }
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "AlleleRemappingData")
+ public void testAlleleRemapping(final Map<Allele, Allele> alleleMap, final int numGenotypes) {
+
+ final GATKVariantContextUtils.AlleleMapper alleleMapper = new GATKVariantContextUtils.AlleleMapper(alleleMap);
+
+ final GenotypesContext originalGC = createGenotypesContext(numGenotypes, new ArrayList(alleleMap.keySet()));
+
+ final GenotypesContext remappedGC = GATKVariantContextUtils.updateGenotypesWithMappedAlleles(originalGC, alleleMapper);
+
+ for ( int i = 0; i < numGenotypes; i++ ) {
+ final Genotype originalG = originalGC.get(String.format("%d", i));
+ final Genotype remappedG = remappedGC.get(String.format("%d", i));
+
+ Assert.assertEquals(originalG.getAlleles().size(), remappedG.getAlleles().size());
+ for ( int j = 0; j < originalG.getAlleles().size(); j++ )
+ Assert.assertEquals(remappedG.getAllele(j), alleleMap.get(originalG.getAllele(j)));
+ }
+ }
+
+ private static GenotypesContext createGenotypesContext(final int numGenotypes, final List<Allele> alleles) {
+ GenomeAnalysisEngine.resetRandomGenerator();
+ final Random random = GenomeAnalysisEngine.getRandomGenerator();
+
+ final GenotypesContext gc = GenotypesContext.create();
+ for ( int i = 0; i < numGenotypes; i++ ) {
+ // choose alleles at random
+ final List<Allele> myAlleles = new ArrayList<Allele>();
+ myAlleles.add(alleles.get(random.nextInt(2)));
+ myAlleles.add(alleles.get(random.nextInt(2)));
+
+ final Genotype g = new GenotypeBuilder(String.format("%d", i)).alleles(myAlleles).make();
+ gc.add(g);
+ }
+
+ return gc;
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test subsetDiploidAlleles
+ //
+ // --------------------------------------------------------------------------------
+
+ @DataProvider(name = "subsetDiploidAllelesData")
+ public Object[][] makesubsetDiploidAllelesData() {
+ List<Object[]> tests = new ArrayList<>();
+
+ final Allele A = Allele.create("A", true);
+ final Allele C = Allele.create("C");
+ final Allele G = Allele.create("G");
+
+ final List<Allele> AA = Arrays.asList(A,A);
+ final List<Allele> AC = Arrays.asList(A,C);
+ final List<Allele> CC = Arrays.asList(C,C);
+ final List<Allele> AG = Arrays.asList(A,G);
+ final List<Allele> CG = Arrays.asList(C,G);
+ final List<Allele> GG = Arrays.asList(G,G);
+ final List<Allele> ACG = Arrays.asList(A,C,G);
+
+ final VariantContext vcBase = new VariantContextBuilder("test", "20", 10, 10, AC).make();
+
+ final double[] homRefPL = MathUtils.normalizeFromRealSpace(new double[]{0.9, 0.09, 0.01});
+ final double[] hetPL = MathUtils.normalizeFromRealSpace(new double[]{0.09, 0.9, 0.01});
+ final double[] homVarPL = MathUtils.normalizeFromRealSpace(new double[]{0.01, 0.09, 0.9});
+ final double[] uninformative = new double[]{0, 0, 0};
+
+ final Genotype base = new GenotypeBuilder("NA12878").DP(10).GQ(50).make();
+
+ // make sure we don't screw up the simple case
+ final Genotype aaGT = new GenotypeBuilder(base).alleles(AA).AD(new int[]{10,2}).PL(homRefPL).GQ(8).make();
+ final Genotype acGT = new GenotypeBuilder(base).alleles(AC).AD(new int[]{10,2}).PL(hetPL).GQ(8).make();
+ final Genotype ccGT = new GenotypeBuilder(base).alleles(CC).AD(new int[]{10,2}).PL(homVarPL).GQ(8).make();
+
+ tests.add(new Object[]{new VariantContextBuilder(vcBase).genotypes(aaGT).make(), AC, Arrays.asList(new GenotypeBuilder(aaGT).make())});
+ tests.add(new Object[]{new VariantContextBuilder(vcBase).genotypes(acGT).make(), AC, Arrays.asList(new GenotypeBuilder(acGT).make())});
+ tests.add(new Object[]{new VariantContextBuilder(vcBase).genotypes(ccGT).make(), AC, Arrays.asList(new GenotypeBuilder(ccGT).make())});
+
+ // uninformative test case
+ final Genotype uninformativeGT = new GenotypeBuilder(base).alleles(CC).PL(uninformative).GQ(0).make();
+ final Genotype emptyGT = new GenotypeBuilder(base).alleles(GATKVariantContextUtils.NO_CALL_ALLELES).noPL().noGQ().make();
+ tests.add(new Object[]{new VariantContextBuilder(vcBase).genotypes(uninformativeGT).make(), AC, Arrays.asList(emptyGT)});
+
+ // actually subsetting down from multiple alt values
+ final double[] homRef3AllelesPL = new double[]{0, -10, -20, -30, -40, -50};
+ final double[] hetRefC3AllelesPL = new double[]{-10, 0, -20, -30, -40, -50};
+ final double[] homC3AllelesPL = new double[]{-20, -10, 0, -30, -40, -50};
+ final double[] hetRefG3AllelesPL = new double[]{-20, -10, -30, 0, -40, -50};
+ final double[] hetCG3AllelesPL = new double[]{-20, -10, -30, -40, 0, -50}; // AA, AC, CC, AG, CG, GG
+ final double[] homG3AllelesPL = new double[]{-20, -10, -30, -40, -50, 0}; // AA, AC, CC, AG, CG, GG
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).PL(homRef3AllelesPL).make()).make(),
+ AC,
+ Arrays.asList(new GenotypeBuilder(base).alleles(AA).PL(new double[]{0, -10, -20}).GQ(100).make())});
+
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).PL(hetRefC3AllelesPL).make()).make(),
+ AC,
+ Arrays.asList(new GenotypeBuilder(base).alleles(AC).PL(new double[]{-10, 0, -20}).GQ(100).make())});
+
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).PL(homC3AllelesPL).make()).make(),
+ AC,
+ Arrays.asList(new GenotypeBuilder(base).alleles(CC).PL(new double[]{-20, -10, 0}).GQ(100).make())});
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).PL(hetRefG3AllelesPL).make()).make(),
+ AG,
+ Arrays.asList(new GenotypeBuilder(base).alleles(AG).PL(new double[]{-20, 0, -50}).GQ(200).make())});
+
+ // wow, scary -- bad output but discussed with Eric and we think this is the only thing that can be done
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).PL(hetCG3AllelesPL).make()).make(),
+ AG,
+ Arrays.asList(new GenotypeBuilder(base).alleles(AA).PL(new double[]{0, -20, -30}).GQ(200).make())});
+
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).PL(homG3AllelesPL).make()).make(),
+ AG,
+ Arrays.asList(new GenotypeBuilder(base).alleles(GG).PL(new double[]{-20, -40, 0}).GQ(200).make())});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "subsetDiploidAllelesData")
+ public void testsubsetDiploidAllelesData(final VariantContext inputVC,
+ final List<Allele> allelesToUse,
+ final List<Genotype> expectedGenotypes) {
+ final GenotypesContext actual = GATKVariantContextUtils.subsetDiploidAlleles(inputVC, allelesToUse, GATKVariantContextUtils.GenotypeAssignmentMethod.USE_PLS_TO_ASSIGN);
+
+ Assert.assertEquals(actual.size(), expectedGenotypes.size());
+ for ( final Genotype expected : expectedGenotypes ) {
+ final Genotype actualGT = actual.get(expected.getSampleName());
+ Assert.assertNotNull(actualGT);
+ assertGenotypesAreEqual(actualGT, expected);
+ }
+ }
+
+ @DataProvider(name = "UpdateGenotypeAfterSubsettingData")
+ public Object[][] makeUpdateGenotypeAfterSubsettingData() {
+ List<Object[]> tests = new ArrayList<Object[]>();
+
+ final Allele A = Allele.create("A", true);
+ final Allele C = Allele.create("C");
+ final Allele G = Allele.create("G");
+
+ final List<Allele> AA = Arrays.asList(A,A);
+ final List<Allele> AC = Arrays.asList(A,C);
+ final List<Allele> CC = Arrays.asList(C,C);
+ final List<Allele> AG = Arrays.asList(A,G);
+ final List<Allele> CG = Arrays.asList(C,G);
+ final List<Allele> GG = Arrays.asList(G,G);
+ final List<Allele> ACG = Arrays.asList(A,C,G);
+ final List<List<Allele>> allSubsetAlleles = Arrays.asList(AC,AG,ACG);
+
+ final double[] homRefPL = new double[]{0.9, 0.09, 0.01};
+ final double[] hetPL = new double[]{0.09, 0.9, 0.01};
+ final double[] homVarPL = new double[]{0.01, 0.09, 0.9};
+ final double[] uninformative = new double[]{0.33, 0.33, 0.33};
+ final List<double[]> allPLs = Arrays.asList(homRefPL, hetPL, homVarPL, uninformative);
+
+ for ( final List<Allele> alleles : allSubsetAlleles ) {
+ for ( final double[] pls : allPLs ) {
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.SET_TO_NO_CALL, pls, AA, alleles, GATKVariantContextUtils.NO_CALL_ALLELES});
+ }
+ }
+
+ for ( final List<Allele> originalGT : Arrays.asList(AA, AC, CC, AG, CG, GG) ) {
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.USE_PLS_TO_ASSIGN, homRefPL, originalGT, AC, AA});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.USE_PLS_TO_ASSIGN, hetPL, originalGT, AC, AC});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.USE_PLS_TO_ASSIGN, homVarPL, originalGT, AC, CC});
+// tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.USE_PLS_TO_ASSIGN, uninformative, AA, AC, GATKVariantContextUtils.NO_CALL_ALLELES});
+ }
+
+ for ( final double[] pls : allPLs ) {
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, AA, AC, AA});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, AC, AC, AC});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, CC, AC, CC});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, CG, AC, AC});
+
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, AA, AG, AA});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, AC, AG, AA});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, CC, AG, AA});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, CG, AG, AG});
+
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, AA, ACG, AA});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, AC, ACG, AC});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, CC, ACG, CC});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, AG, ACG, AG});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, CG, ACG, CG});
+ tests.add(new Object[]{GATKVariantContextUtils.GenotypeAssignmentMethod.BEST_MATCH_TO_ORIGINAL, pls, GG, ACG, GG});
+ }
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(enabled = !DEBUG, dataProvider = "UpdateGenotypeAfterSubsettingData")
+ public void testUpdateGenotypeAfterSubsetting(final GATKVariantContextUtils.GenotypeAssignmentMethod mode,
+ final double[] likelihoods,
+ final List<Allele> originalGT,
+ final List<Allele> allelesToUse,
+ final List<Allele> expectedAlleles) {
+ final GenotypeBuilder gb = new GenotypeBuilder("test");
+ final double[] log10Likelhoods = MathUtils.normalizeFromLog10(likelihoods, true, false);
+ GATKVariantContextUtils.updateGenotypeAfterSubsetting(originalGT, gb, mode, log10Likelhoods, allelesToUse);
+ final Genotype g = gb.make();
+ Assert.assertEquals(new HashSet<>(g.getAlleles()), new HashSet<>(expectedAlleles));
+ }
+
+ @Test(enabled = !DEBUG)
+ public void testSubsetToRef() {
+ final Map<Genotype, Genotype> tests = new LinkedHashMap<>();
+
+ for ( final List<Allele> alleles : Arrays.asList(Arrays.asList(Aref), Arrays.asList(C), Arrays.asList(Aref, C), Arrays.asList(Aref, C, C) ) ) {
+ for ( final String name : Arrays.asList("test1", "test2") ) {
+ final GenotypeBuilder builder = new GenotypeBuilder(name, alleles);
+ builder.DP(10);
+ builder.GQ(30);
+ builder.AD(alleles.size() == 1 ? new int[]{1} : (alleles.size() == 2 ? new int[]{1, 2} : new int[]{1, 2, 3}));
+ builder.PL(alleles.size() == 1 ? new int[]{1} : (alleles.size() == 2 ? new int[]{1,2} : new int[]{1,2,3}));
+ final List<Allele> refs = Collections.nCopies(alleles.size(), Aref);
+ tests.put(builder.make(), builder.alleles(refs).noAD().noPL().make());
+ }
+ }
+
+ for ( final int n : Arrays.asList(1, 2, 3) ) {
+ for ( final List<Genotype> genotypes : Utils.makePermutations(new ArrayList<>(tests.keySet()), n, false) ) {
+ final VariantContext vc = new VariantContextBuilder("test", "20", 1, 1, Arrays.asList(Aref, C)).genotypes(genotypes).make();
+ final GenotypesContext gc = GATKVariantContextUtils.subsetToRefOnly(vc, 2);
+
+ Assert.assertEquals(gc.size(), genotypes.size());
+ for ( int i = 0; i < genotypes.size(); i++ ) {
+// logger.warn("Testing " + genotypes.get(i) + " => " + gc.get(i) + " " + tests.get(genotypes.get(i)));
+ assertGenotypesAreEqual(gc.get(i), tests.get(genotypes.get(i)));
+ }
+ }
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test updatePLsAndAD
+ //
+ // --------------------------------------------------------------------------------
+
+ @DataProvider(name = "updatePLsAndADData")
+ public Object[][] makeUpdatePLsAndADData() {
+ List<Object[]> tests = new ArrayList<>();
+
+ final Allele A = Allele.create("A", true);
+ final Allele C = Allele.create("C");
+ final Allele G = Allele.create("G");
+
+ final List<Allele> AA = Arrays.asList(A,A);
+ final List<Allele> AC = Arrays.asList(A,C);
+ final List<Allele> CC = Arrays.asList(C,C);
+ final List<Allele> AG = Arrays.asList(A,G);
+ final List<Allele> CG = Arrays.asList(C,G);
+ final List<Allele> GG = Arrays.asList(G,G);
+ final List<Allele> ACG = Arrays.asList(A,C,G);
+
+ final VariantContext vcBase = new VariantContextBuilder("test", "20", 10, 10, AC).make();
+
+ final double[] homRefPL = MathUtils.normalizeFromRealSpace(new double[]{0.9, 0.09, 0.01});
+ final double[] hetPL = MathUtils.normalizeFromRealSpace(new double[]{0.09, 0.9, 0.01});
+ final double[] homVarPL = MathUtils.normalizeFromRealSpace(new double[]{0.01, 0.09, 0.9});
+ final double[] uninformative = new double[]{0, 0, 0};
+
+ final Genotype base = new GenotypeBuilder("NA12878").DP(10).GQ(100).make();
+
+ // make sure we don't screw up the simple case where no selection happens
+ final Genotype aaGT = new GenotypeBuilder(base).alleles(AA).AD(new int[]{10,2}).PL(homRefPL).GQ(8).make();
+ final Genotype acGT = new GenotypeBuilder(base).alleles(AC).AD(new int[]{10,2}).PL(hetPL).GQ(8).make();
+ final Genotype ccGT = new GenotypeBuilder(base).alleles(CC).AD(new int[]{10,2}).PL(homVarPL).GQ(8).make();
+
+ tests.add(new Object[]{new VariantContextBuilder(vcBase).genotypes(aaGT).make(), new VariantContextBuilder(vcBase).alleles(AC).make(), Arrays.asList(new GenotypeBuilder(aaGT).make())});
+ tests.add(new Object[]{new VariantContextBuilder(vcBase).genotypes(acGT).make(), new VariantContextBuilder(vcBase).alleles(AC).make(), Arrays.asList(new GenotypeBuilder(acGT).make())});
+ tests.add(new Object[]{new VariantContextBuilder(vcBase).genotypes(ccGT).make(), new VariantContextBuilder(vcBase).alleles(AC).make(), Arrays.asList(new GenotypeBuilder(ccGT).make())});
+
+ // uninformative test cases
+ final Genotype uninformativeGT = new GenotypeBuilder(base).alleles(CC).noAD().PL(uninformative).GQ(0).make();
+ tests.add(new Object[]{new VariantContextBuilder(vcBase).genotypes(uninformativeGT).make(), new VariantContextBuilder(vcBase).alleles(AC).make(), Arrays.asList(uninformativeGT)});
+ final Genotype emptyGT = new GenotypeBuilder(base).alleles(GATKVariantContextUtils.NO_CALL_ALLELES).noAD().noPL().noGQ().make();
+ tests.add(new Object[]{new VariantContextBuilder(vcBase).genotypes(emptyGT).make(), new VariantContextBuilder(vcBase).alleles(AC).make(), Arrays.asList(emptyGT)});
+
+ // actually subsetting down from multiple alt values
+ final double[] homRef3AllelesPL = new double[]{0, -10, -20, -30, -40, -50};
+ final double[] hetRefC3AllelesPL = new double[]{-10, 0, -20, -30, -40, -50};
+ final double[] homC3AllelesPL = new double[]{-20, -10, 0, -30, -40, -50};
+ final double[] hetRefG3AllelesPL = new double[]{-20, -10, -30, 0, -40, -50};
+ final double[] hetCG3AllelesPL = new double[]{-20, -10, -30, -40, 0, -50}; // AA, AC, CC, AG, CG, GG
+ final double[] homG3AllelesPL = new double[]{-20, -10, -30, -40, -50, 0}; // AA, AC, CC, AG, CG, GG
+
+ final int[] homRef3AllelesAD = new int[]{20, 0, 1};
+ final int[] hetRefC3AllelesAD = new int[]{10, 10, 1};
+ final int[] homC3AllelesAD = new int[]{0, 20, 1};
+ final int[] hetRefG3AllelesAD = new int[]{10, 0, 11};
+ final int[] hetCG3AllelesAD = new int[]{0, 12, 11}; // AA, AC, CC, AG, CG, GG
+ final int[] homG3AllelesAD = new int[]{0, 1, 21}; // AA, AC, CC, AG, CG, GG
+
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).AD(homRef3AllelesAD).PL(homRef3AllelesPL).make()).make(),
+ new VariantContextBuilder(vcBase).alleles(AC).make(),
+ Arrays.asList(new GenotypeBuilder(base).alleles(AA).PL(new double[]{0, -10, -20}).AD(new int[]{20, 0}).GQ(100).make())});
+
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).AD(hetRefC3AllelesAD).PL(hetRefC3AllelesPL).make()).make(),
+ new VariantContextBuilder(vcBase).alleles(AC).make(),
+ Arrays.asList(new GenotypeBuilder(base).alleles(AA).PL(new double[]{-10, 0, -20}).AD(new int[]{10, 10}).GQ(100).make())});
+
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).AD(homC3AllelesAD).PL(homC3AllelesPL).make()).make(),
+ new VariantContextBuilder(vcBase).alleles(AC).make(),
+ Arrays.asList(new GenotypeBuilder(base).alleles(AA).PL(new double[]{-20, -10, 0}).AD(new int[]{0, 20}).GQ(100).make())});
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).AD(hetRefG3AllelesAD).PL(hetRefG3AllelesPL).make()).make(),
+ new VariantContextBuilder(vcBase).alleles(AG).make(),
+ Arrays.asList(new GenotypeBuilder(base).alleles(AA).PL(new double[]{-20, 0, -50}).AD(new int[]{10, 11}).GQ(100).make())});
+
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).AD(hetCG3AllelesAD).PL(hetCG3AllelesPL).make()).make(),
+ new VariantContextBuilder(vcBase).alleles(AG).make(),
+ Arrays.asList(new GenotypeBuilder(base).alleles(AA).PL(new double[]{0, -20, -30}).AD(new int[]{0, 11}).GQ(100).make())});
+
+ tests.add(new Object[]{
+ new VariantContextBuilder(vcBase).alleles(ACG).genotypes(new GenotypeBuilder(base).alleles(AA).AD(homG3AllelesAD).PL(homG3AllelesPL).make()).make(),
+ new VariantContextBuilder(vcBase).alleles(AG).make(),
+ Arrays.asList(new GenotypeBuilder(base).alleles(AA).PL(new double[]{-20, -40, 0}).AD(new int[]{0, 21}).GQ(100).make())});
+
+ return tests.toArray(new Object[][]{});
+ }
+
+ @Test(dataProvider = "updatePLsAndADData")
+ public void testUpdatePLsAndADData(final VariantContext originalVC,
+ final VariantContext selectedVC,
+ final List<Genotype> expectedGenotypes) {
+ final VariantContext selectedVCwithGTs = new VariantContextBuilder(selectedVC).genotypes(originalVC.getGenotypes()).make();
+ final GenotypesContext actual = GATKVariantContextUtils.updatePLsAndAD(selectedVCwithGTs, originalVC);
+
+ Assert.assertEquals(actual.size(), expectedGenotypes.size());
+ for ( final Genotype expected : expectedGenotypes ) {
+ final Genotype actualGT = actual.get(expected.getSampleName());
+ Assert.assertNotNull(actualGT);
+ assertGenotypesAreEqual(actualGT, expected);
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // Test methods for merging reference confidence VCs
+ //
+ // --------------------------------------------------------------------------------
+
+
+ @Test(dataProvider = "indexOfAlleleData")
+ public void testIndexOfAllele(final Allele reference, final List<Allele> altAlleles, final List<Allele> otherAlleles) {
+ final List<Allele> alleles = new ArrayList<>(altAlleles.size() + 1);
+ alleles.add(reference);
+ alleles.addAll(altAlleles);
+ final VariantContext vc = makeVC("Source", alleles);
+
+ for (int i = 0; i < alleles.size(); i++) {
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,alleles.get(i),true,true,true),i);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,alleles.get(i),false,true,true),i);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,alleles.get(i),true,true,false),i);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,alleles.get(i),false,true,false),i);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,Allele.create(alleles.get(i),true),true,true,true),i);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,Allele.create(alleles.get(i),true),true,true,false),-1);
+ if (i == 0) {
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,alleles.get(i),true,false,true),-1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,alleles.get(i),false,false,true),-1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,alleles.get(i),true,false,false),-1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,alleles.get(i),false,false,false),-1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,Allele.create(alleles.get(i).getBases(),true),false,true,true),i);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,Allele.create(alleles.get(i).getBases(),false),false,true,true),-1);
+ } else {
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAltAllele(vc,alleles.get(i),true),i - 1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAltAllele(vc,alleles.get(i),false), i - 1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAltAllele(vc,Allele.create(alleles.get(i),true),true),i-1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAltAllele(vc,Allele.create(alleles.get(i),true),false),-1);
+ }
+ }
+
+ for (final Allele other : otherAlleles) {
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc, other, true, true, true), -1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,other,false,true,true),-1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,other,true,true,false),-1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,other,false,true,false),-1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,other,true,false,true),-1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,other,false,false,true),-1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc,other,true,false,false),-1);
+ Assert.assertEquals(GATKVariantContextUtils.indexOfAllele(vc, other, false, false, false),-1);
+ }
+ }
+
+ @DataProvider(name = "indexOfAlleleData")
+ public Iterator<Object[]> indexOfAlleleData() {
+
+ final Allele[] ALTERNATIVE_ALLELES = new Allele[] { T, C, G, ATC, ATCATC};
+
+ final int lastMask = 0x1F;
+
+ return new Iterator<Object[]>() {
+
+ int nextMask = 0;
+
+ @Override
+ public boolean hasNext() {
+ return nextMask <= lastMask;
+ }
+
+ @Override
+ public Object[] next() {
+
+ int mask = nextMask++;
+ final List<Allele> includedAlleles = new ArrayList<>(5);
+ final List<Allele> excludedAlleles = new ArrayList<>(5);
+ for (int i = 0; i < ALTERNATIVE_ALLELES.length; i++) {
+ ((mask & 1) == 1 ? includedAlleles : excludedAlleles).add(ALTERNATIVE_ALLELES[i]);
+ mask >>= 1;
+ }
+ return new Object[] { Aref , includedAlleles, excludedAlleles};
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Test(dataProvider="overlapWithData")
+ public void testOverlapsWith(final VariantContext vc, final GenomeLoc genomeLoc) {
+ final boolean expected;
+
+ if (genomeLoc.isUnmapped())
+ expected = false;
+ else if (vc.getStart() > genomeLoc.getStop())
+ expected = false;
+ else if (vc.getEnd() < genomeLoc.getStart())
+ expected = false;
+ else if (!vc.getChr().equals(genomeLoc.getContig()))
+ expected = false;
+ else
+ expected = true;
+
+ Assert.assertEquals(GATKVariantContextUtils.overlapsRegion(vc, genomeLoc), expected);
+ }
+
+
+ private final String[] OVERLAP_WITH_CHROMOSOMES = { "chr1", "chr20" };
+ private final int[] OVERLAP_WITH_EVENT_SIZES = { -10, -1, 0, 1, 10 }; // 0 == SNP , -X xbp deletion, +X xbp insertion.
+ private final int[] OVERLAP_WITH_EVENT_STARTS = { 10000000, 10000001,
+ 10000005, 10000010,
+ 10000009, 10000011,
+ 20000000 };
+
+ @DataProvider(name="overlapWithData")
+ public Object[][] overlapWithData() {
+
+ final int totalLocations = OVERLAP_WITH_CHROMOSOMES.length * OVERLAP_WITH_EVENT_SIZES.length * OVERLAP_WITH_EVENT_STARTS.length + 1;
+ final int totalEvents = OVERLAP_WITH_CHROMOSOMES.length * OVERLAP_WITH_EVENT_SIZES.length * OVERLAP_WITH_EVENT_STARTS.length;
+ final GenomeLoc[] locs = new GenomeLoc[totalLocations];
+ final VariantContext[] events = new VariantContext[totalEvents];
+
+ generateAllLocationsAndVariantContextCombinations(OVERLAP_WITH_CHROMOSOMES, OVERLAP_WITH_EVENT_SIZES,
+ OVERLAP_WITH_EVENT_STARTS, locs, events);
+
+ return generateAllParameterCombinationsForOverlapWithData(locs, events);
+ }
+
+ private Object[][] generateAllParameterCombinationsForOverlapWithData(GenomeLoc[] locs, VariantContext[] events) {
+ final List<Object[]> result = new LinkedList<>();
+ for (final GenomeLoc loc : locs)
+ for (final VariantContext event : events)
+ result.add(new Object[] { event , loc });
+
+ return result.toArray(new Object[result.size()][]);
+ }
+
+ private void generateAllLocationsAndVariantContextCombinations(final String[] chrs, final int[] eventSizes,
+ final int[] eventStarts, final GenomeLoc[] locs,
+ final VariantContext[] events) {
+ int nextIndex = 0;
+ for (final String chr : chrs )
+ for (final int size : eventSizes )
+ for (final int starts : eventStarts ) {
+ locs[nextIndex] = genomeLocParser.createGenomeLoc(chr,starts,starts + Math.max(0,size));
+ events[nextIndex++] = new VariantContextBuilder().source("test").loc(chr,starts,starts + Math.max(0,size)).alleles(Arrays.asList(
+ Allele.create(randomBases(size <= 0 ? 1 : size + 1, true), true), Allele.create(randomBases(size < 0 ? -size + 1 : 1, false), false))).make();
+ }
+
+ locs[nextIndex++] = GenomeLoc.UNMAPPED;
+ }
+
+ @Test(dataProvider = "totalPloidyData")
+ public void testTotalPloidy(final int[] ploidies, final int defaultPloidy, final int expected) {
+ final Genotype[] genotypes = new Genotype[ploidies.length];
+ final List<Allele> vcAlleles = Arrays.asList(Aref,C);
+ for (int i = 0; i < genotypes.length; i++)
+ genotypes[i] = new GenotypeBuilder().alleles(GATKVariantContextUtils.noCallAlleles(ploidies[i])).make();
+ final VariantContext vc = new VariantContextBuilder().chr("seq1").genotypes(genotypes).alleles(vcAlleles).make();
+ Assert.assertEquals(GATKVariantContextUtils.totalPloidy(vc,defaultPloidy),expected," " + defaultPloidy + " " + Arrays.toString(ploidies));
+ }
+
+ @DataProvider(name="totalPloidyData")
+ public Object[][] totalPloidyData() {
+ final Random rdn = GenomeAnalysisEngine.getRandomGenerator();
+ final List<Object[]> resultList = new ArrayList<>();
+ for (int i = 0; i < 100; i++) {
+ final int sampleCount = rdn.nextInt(10);
+
+ int expected = 0;
+ final int defaultPloidy = rdn.nextInt(10) + 1;
+ final int[] plodies = new int[sampleCount];
+ for (int j = 0; j < sampleCount; j++) {
+ plodies[j] = rdn.nextInt(10);
+ expected += plodies[j] == 0 ? defaultPloidy : plodies[j];
+ }
+ resultList.add(new Object[] { plodies, defaultPloidy, expected });
+ }
+ return resultList.toArray(new Object[100][]);
+ }
+
+ private byte[] randomBases(final int length, final boolean reference) {
+ final byte[] bases = new byte[length];
+ bases[0] = (byte) (reference ? 'A' : 'C');
+ BaseUtils.fillWithRandomBases(bases, 1, bases.length);
+ return bases;
+ }
+}
+
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/VCFIntegrationTest.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/VCFIntegrationTest.java
new file mode 100644
index 0000000..4a08702
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/VCFIntegrationTest.java
@@ -0,0 +1,377 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.variant;
+
+import htsjdk.tribble.AbstractFeatureReader;
+import htsjdk.tribble.Tribble;
+import htsjdk.tribble.index.AbstractIndex;
+import htsjdk.tribble.index.ChrIndex;
+import htsjdk.tribble.index.Index;
+import htsjdk.tribble.index.IndexFactory;
+import htsjdk.tribble.index.interval.IntervalTreeIndex;
+import htsjdk.tribble.index.linear.LinearIndex;
+import htsjdk.tribble.index.tabix.TabixIndex;
+import htsjdk.tribble.util.TabixUtils;
+import org.broadinstitute.gatk.utils.BaseTest;
+import org.broadinstitute.gatk.engine.walkers.WalkerTest;
+import htsjdk.variant.vcf.VCFCodec;
+import org.testng.Assert;
+import org.testng.TestException;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+public class VCFIntegrationTest extends WalkerTest {
+
+ @Test(enabled = true)
+ public void testReadingAndWritingWitHNoChanges() {
+
+ String md5ofInputVCF = "d991abe6c6a7a778a60a667717903be0";
+ String testVCF = privateTestDir + "vcf4.1.example.vcf";
+
+ String baseCommand = "-R " + b37KGReference + " --no_cmdline_in_header -o %s ";
+
+ String test1 = baseCommand + "-T VariantAnnotator --variant " + testVCF + " -L " + testVCF;
+ WalkerTestSpec spec1 = new WalkerTestSpec(test1, 1, Arrays.asList(md5ofInputVCF));
+ List<File> result = executeTest("Test Variant Annotator with no changes", spec1).getFirst();
+
+ String test2 = baseCommand + "-T VariantsToVCF --variant " + result.get(0).getAbsolutePath();
+ WalkerTestSpec spec2 = new WalkerTestSpec(test2, 1, Arrays.asList(md5ofInputVCF));
+ executeTest("Test Variants To VCF from new output", spec2);
+ }
+
+ @Test(enabled = true)
+ public void testReadingAndWritingBreakpointAlleles() {
+ String testVCF = privateTestDir + "breakpoint-example.vcf";
+
+ String baseCommand = "-R " + b37KGReference + " --no_cmdline_in_header -o %s ";
+
+ String test1 = baseCommand + "-T SelectVariants -V " + testVCF;
+ WalkerTestSpec spec1 = new WalkerTestSpec(test1, 1, Arrays.asList("13329ba7360a8beb3afc02569e5a20c4"));
+ executeTest("Test reading and writing breakpoint VCF", spec1);
+ }
+
+ @Test(enabled = true)
+ public void testReadingLowerCaseBases() {
+ String testVCF = privateTestDir + "lowercaseBases.vcf";
+
+ String baseCommand = "-R " + b37KGReference + " --no_cmdline_in_header -o %s ";
+
+ String test1 = baseCommand + "-T SelectVariants -V " + testVCF;
+ WalkerTestSpec spec1 = new WalkerTestSpec(test1, 1, Arrays.asList("e0e308a25e56bde1c664139bb44ed19d"));
+ executeTest("Test reading VCF with lower-case bases", spec1);
+ }
+
+ @Test(enabled = true)
+ public void testReadingAndWriting1000GSVs() {
+ String testVCF = privateTestDir + "1000G_SVs.chr1.vcf";
+
+ String baseCommand = "-R " + b37KGReference + " --no_cmdline_in_header -o %s ";
+
+ String test1 = baseCommand + "-T SelectVariants -V " + testVCF;
+ WalkerTestSpec spec1 = new WalkerTestSpec(test1, 1, Arrays.asList("bdab26dd7648a806dbab01f64db2bdab"));
+ executeTest("Test reading and writing 1000G Phase I SVs", spec1);
+ }
+
+ @Test
+ public void testReadingAndWritingSamtools() {
+ String testVCF = privateTestDir + "samtools.vcf";
+
+ String baseCommand = "-R " + b37KGReference + " --no_cmdline_in_header -o %s ";
+
+ String test1 = baseCommand + "-T SelectVariants -V " + testVCF;
+ WalkerTestSpec spec1 = new WalkerTestSpec(test1, 1, Arrays.asList("38697c195e7abf18d95dcc16c8e6d284"));
+ executeTest("Test reading and writing samtools vcf", spec1);
+ }
+
+ @Test
+ public void testWritingSamtoolsWExBCFExample() {
+ String testVCF = privateTestDir + "ex2.vcf";
+ String baseCommand = "-R " + b36KGReference + " --no_cmdline_in_header -o %s ";
+ String test1 = baseCommand + "-T SelectVariants -V " + testVCF;
+ WalkerTestSpec spec1 = new WalkerTestSpec(test1, 1, Arrays.asList("e8f721ce81e4fdadba13c5291027057f"));
+ executeTest("Test writing samtools WEx BCF example", spec1);
+ }
+
+ @Test(enabled = true)
+ public void testReadingSamtoolsWExBCFExample() {
+ String testVCF = privateTestDir + "ex2.bcf";
+ String baseCommand = "-R " + b36KGReference + " --no_cmdline_in_header -o %s ";
+ String test1 = baseCommand + "-T SelectVariants -V " + testVCF;
+ WalkerTestSpec spec1 = new WalkerTestSpec(test1, 1, Arrays.asList("0439e2b4ccc63bb4ba7c283cd9ab1b25"));
+ executeTest("Test reading samtools WEx BCF example", spec1);
+ }
+
+ //
+ //
+ // Tests to ensure that -U LENIENT_VCF_PROCESS
+ //
+ //
+
+ @Test
+ public void testFailingOnVCFWithoutHeaders() {
+ runVCFWithoutHeaders("", "", IllegalStateException.class, false);
+ }
+
+ @Test
+ public void testPassingOnVCFWithoutHeadersWithLenientProcessing() {
+ runVCFWithoutHeaders("-U LENIENT_VCF_PROCESSING", "6de8cb7457154dd355aa55befb943f88", null, true);
+ }
+
+ private void runVCFWithoutHeaders(final String moreArgs, final String expectedMD5, final Class expectedException, final boolean disableBCF) {
+ final String testVCF = privateTestDir + "vcfexample2.noHeader.vcf";
+ final String baseCommand = "-R " + b37KGReference
+ + " --no_cmdline_in_header -o %s "
+ + "-T VariantsToVCF -V " + testVCF + " " + moreArgs;
+ WalkerTestSpec spec1 = expectedException != null
+ ? new WalkerTestSpec(baseCommand, 1, expectedException)
+ : new WalkerTestSpec(baseCommand, 1, Arrays.asList(expectedMD5));
+ if ( disableBCF )
+ spec1.disableShadowBCF();
+ executeTest("Test reading VCF without header lines with additional args " + moreArgs, spec1);
+ }
+
+ //
+ //
+ // IndexCreator tests
+ //
+ //
+
+ private class VCFIndexCreatorTest extends TestDataProvider {
+ private final GATKVCFIndexType type;
+ private final int parameter;
+
+ private VCFIndexCreatorTest(GATKVCFIndexType type, int parameter) {
+ super(VCFIndexCreatorTest.class);
+
+ this.type = type;
+ this.parameter = parameter;
+ }
+
+ public String toString() {
+ return String.format("Index Type %s, Index Parameter %s", type, parameter);
+ }
+
+ public Index getIndex(final File vcfFile) {
+ switch (type) {
+ case DYNAMIC_SEEK : return IndexFactory.createDynamicIndex(vcfFile, new VCFCodec(), IndexFactory.IndexBalanceApproach.FOR_SEEK_TIME);
+ case DYNAMIC_SIZE : return IndexFactory.createDynamicIndex(vcfFile, new VCFCodec(), IndexFactory.IndexBalanceApproach.FOR_SIZE);
+ case LINEAR : return IndexFactory.createLinearIndex(vcfFile, new VCFCodec(), parameter);
+ case INTERVAL : return IndexFactory.createIntervalIndex(vcfFile, new VCFCodec(), parameter);
+ default : throw new TestException("Invalid index type");
+ }
+ }
+ }
+
+ @DataProvider(name = "IndexDataProvider")
+ public Object[][] indexCreatorData() {
+ new VCFIndexCreatorTest(GATKVCFIndexType.DYNAMIC_SEEK, 0);
+ new VCFIndexCreatorTest(GATKVCFIndexType.DYNAMIC_SIZE, 0);
+ new VCFIndexCreatorTest(GATKVCFIndexType.LINEAR, 100);
+ new VCFIndexCreatorTest(GATKVCFIndexType.LINEAR, 10000);
+ new VCFIndexCreatorTest(GATKVCFIndexType.INTERVAL, 20);
+ new VCFIndexCreatorTest(GATKVCFIndexType.INTERVAL, 2000);
+
+ return TestDataProvider.getTests(VCFIndexCreatorTest.class);
+ }
+
+ @Test(dataProvider = "IndexDataProvider")
+ public void testVCFIndexCreation(VCFIndexCreatorTest testSpec) throws NoSuchFieldException, IllegalAccessException {
+
+ final String commandLine = " -T SelectVariants" +
+ " -R " + b37KGReference +
+ " --no_cmdline_in_header" +
+ " -L 20" +
+ " -V " + b37_NA12878_OMNI +
+ " --variant_index_type " + testSpec.type +
+ " --variant_index_parameter " + testSpec.parameter +
+ " -o %s ";
+ final String name = "testVCFIndexCreation: " + testSpec.toString();
+
+ final WalkerTestSpec spec = new WalkerTestSpec(commandLine, 1, Arrays.asList(""));
+ spec.disableShadowBCF();
+
+ File outVCF = executeTest(name, spec).first.get(0);
+ File outIdx = new File(outVCF.getAbsolutePath() + Tribble.STANDARD_INDEX_EXTENSION);
+
+ final Index actualIndex = IndexFactory.loadIndex(outIdx.getAbsolutePath());
+ final Index expectedIndex = testSpec.getIndex(outVCF);
+
+ if (testSpec.type.equals("LINEAR"))
+ Assert.assertTrue(actualIndex instanceof LinearIndex, "Index is not a LinearIndex");
+ else if (testSpec.type.equals("INTERVAL"))
+ Assert.assertTrue(actualIndex instanceof IntervalTreeIndex, "Index is not a IntervalTreeIndex");
+ // dynamic indices ultimately resolve to one of LinearIndex or IntervalTreeIndex
+
+ Assert.assertTrue(equivalentAbstractIndices((AbstractIndex)actualIndex, (AbstractIndex)expectedIndex), "Indices are not equivalent");
+
+ if (actualIndex instanceof LinearIndex && expectedIndex instanceof LinearIndex) {
+ Assert.assertTrue(equivalentLinearIndices((LinearIndex)actualIndex, (LinearIndex)expectedIndex, "20"), "Linear indices are not equivalent");
+ }
+ else if (actualIndex instanceof IntervalTreeIndex && expectedIndex instanceof IntervalTreeIndex) {
+ Assert.assertTrue(equivalentIntervalIndices((IntervalTreeIndex)actualIndex, (IntervalTreeIndex)expectedIndex, "20"), "Interval indices are not equivalent");
+ }
+ else {
+ Assert.fail("Indices are not of the same type");
+ }
+ }
+
+ private static boolean equivalentAbstractIndices(AbstractIndex thisIndex, AbstractIndex otherIndex){
+ return thisIndex.getVersion() == otherIndex.getVersion() &&
+ thisIndex.getIndexedFile().equals(otherIndex.getIndexedFile()) &&
+ thisIndex.getIndexedFileSize() == otherIndex.getIndexedFileSize() &&
+ thisIndex.getIndexedFileMD5().equals(otherIndex.getIndexedFileMD5()) &&
+ thisIndex.getFlags() == otherIndex.getFlags();
+ }
+
+ private static boolean equivalentLinearIndices(LinearIndex thisIndex, LinearIndex otherIndex, String chr) throws NoSuchFieldException, IllegalAccessException {
+ htsjdk.tribble.index.linear.LinearIndex.ChrIndex thisChr = (htsjdk.tribble.index.linear.LinearIndex.ChrIndex)getChrIndex(thisIndex, chr);
+ htsjdk.tribble.index.linear.LinearIndex.ChrIndex otherChr = (htsjdk.tribble.index.linear.LinearIndex.ChrIndex)getChrIndex(otherIndex, chr);
+
+ return thisChr.getName().equals(otherChr.getName()) &&
+ //thisChr.getTotalSize() == otherChr.getTotalSize() && TODO: why does this differ?
+ thisChr.getNFeatures() == otherChr.getNFeatures() &&
+ thisChr.getNBlocks() == otherChr.getNBlocks();
+ }
+
+ private static boolean equivalentIntervalIndices(IntervalTreeIndex thisIndex, IntervalTreeIndex otherIndex, String chr) throws NoSuchFieldException, IllegalAccessException {
+ htsjdk.tribble.index.interval.IntervalTreeIndex.ChrIndex thisChr = (htsjdk.tribble.index.interval.IntervalTreeIndex.ChrIndex)getChrIndex(thisIndex, chr);
+ htsjdk.tribble.index.interval.IntervalTreeIndex.ChrIndex otherChr = (htsjdk.tribble.index.interval.IntervalTreeIndex.ChrIndex)getChrIndex(otherIndex, chr);
+
+ // TODO: compare trees?
+ return thisChr.getName().equals(otherChr.getName());
+ }
+
+ private static ChrIndex getChrIndex(AbstractIndex index, String chr) throws NoSuchFieldException, IllegalAccessException {
+ Field f = AbstractIndex.class.getDeclaredField("chrIndices");
+ f.setAccessible(true);
+ LinkedHashMap<String, ChrIndex> chrIndices = (LinkedHashMap<String, ChrIndex>) f.get(index);
+ return chrIndices.get(chr);
+ }
+
+ //
+ //
+ // Block-Compressed Tabix Index Tests
+ //
+ //
+
+ private class BlockCompressedIndexCreatorTest extends TestDataProvider {
+ private final String extension;
+
+ private BlockCompressedIndexCreatorTest(String extension) {
+ super(BlockCompressedIndexCreatorTest.class);
+
+ this.extension = extension;
+ }
+
+ public String toString() {
+ return String.format("File extension %s", extension);
+ }
+ }
+
+ @DataProvider(name = "BlockCompressedIndexDataProvider")
+ public Object[][] blockCompressedIndexCreatorData() {
+ for (final String extension : AbstractFeatureReader.BLOCK_COMPRESSED_EXTENSIONS)
+ new BlockCompressedIndexCreatorTest(".vcf" + extension);
+
+ return TestDataProvider.getTests(BlockCompressedIndexCreatorTest.class);
+ }
+
+ @Test(dataProvider = "BlockCompressedIndexDataProvider")
+ public void testBlockCompressedIndexCreation(BlockCompressedIndexCreatorTest testSpec) throws NoSuchFieldException, IllegalAccessException {
+
+ final String commandLine = " -T SelectVariants" +
+ " -R " + b37KGReference +
+ " --no_cmdline_in_header" +
+ " -L 20" +
+ " -V " + b37_NA12878_OMNI;
+ final String name = "testBlockCompressedIndexCreation: " + testSpec.toString();
+
+ File outVCF = createTempFile("testBlockCompressedIndexCreation", testSpec.extension);
+ final WalkerTestSpec spec = new WalkerTestSpec(commandLine, 1, Arrays.asList(""));
+ spec.disableShadowBCF();
+ spec.setOutputFileLocation(outVCF);
+
+ executeTest(name, spec);
+
+ File outTribbleIdx = new File(outVCF.getAbsolutePath() + Tribble.STANDARD_INDEX_EXTENSION);
+ Assert.assertFalse(outTribbleIdx.exists(), "testBlockCompressedIndexCreation: Want Tabix index but Tribble index exists: " + outTribbleIdx);
+
+ File outTabixIdx = new File(outVCF.getAbsolutePath() + TabixUtils.STANDARD_INDEX_EXTENSION);
+ final Index actualIndex = IndexFactory.loadIndex(outTabixIdx.toString());
+ Assert.assertTrue(actualIndex instanceof TabixIndex, "testBlockCompressedIndexCreation: Want Tabix index but index is not Tabix: " + outTabixIdx);
+ }
+
+ //
+ //
+ // Block-Compressed Input Tests
+ //
+ //
+
+ private class BlockCompressedInputTest extends TestDataProvider {
+ private final String extension;
+
+ private BlockCompressedInputTest(String extension) {
+ super(BlockCompressedInputTest.class);
+
+ this.extension = extension;
+ }
+
+ public String toString() {
+ return String.format("File extension %s", extension);
+ }
+ }
+
+ @DataProvider(name = "BlockCompressedInputDataProvider")
+ public Object[][] blockCompressedInputData() {
+ for (final String extension : AbstractFeatureReader.BLOCK_COMPRESSED_EXTENSIONS)
+ new BlockCompressedInputTest(".vcf" + extension);
+
+ return TestDataProvider.getTests(BlockCompressedInputTest.class);
+ }
+
+ @Test(dataProvider = "BlockCompressedInputDataProvider")
+ public void testBlockCompressedInput(BlockCompressedInputTest testSpec) {
+
+ File inputFile = new File(BaseTest.privateTestDir, "block_compressed_input_test" + testSpec.extension);
+ final String commandLine = " -T SelectVariants" +
+ " -R " + b37KGReference +
+ " --no_cmdline_in_header" +
+ " -V " + inputFile +
+ " -o %s ";
+ final String name = "testBlockCompressedInput: " + testSpec.toString();
+
+ final WalkerTestSpec spec = new WalkerTestSpec(commandLine, 1, Arrays.asList("3b60668bd973e43783d0406de80d2ed2"));
+
+ executeTest(name, spec);
+ }
+
+}
diff --git a/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/VariantContextBenchmark.java b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/VariantContextBenchmark.java
new file mode 100644
index 0000000..7c1b202
--- /dev/null
+++ b/public/gatk-tools-public/src/test/java/org/broadinstitute/gatk/utils/variant/VariantContextBenchmark.java
@@ -0,0 +1,377 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.variant;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import htsjdk.tribble.Feature;
+import htsjdk.tribble.FeatureCodec;
+import htsjdk.variant.variantcontext.*;
+import htsjdk.variant.vcf.VCFCodec;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Caliper microbenchmark of parsing a VCF file
+ */
+public class VariantContextBenchmark extends SimpleBenchmark {
+ @Param({"/Users/depristo/Desktop/broadLocal/localData/ALL.chr20.merged_beagle_mach.20101123.snps_indels_svs.genotypes.vcf"})
+ String vcfFile;
+
+ @Param({"1000"})
+ int linesToRead; // set automatically by framework
+
+ @Param({"100"})
+ int nSamplesToTake; // set automatically by framework
+
+ @Param({"10"})
+ int dupsToMerge; // set automatically by framework
+
+ @Param
+ Operation operation; // set automatically by framework
+
+ private String INPUT_STRING;
+
+ public enum Operation {
+ READ,
+ SUBSET_TO_SAMPLES,
+ GET_TYPE,
+ GET_ID,
+ GET_GENOTYPES,
+ GET_ATTRIBUTE_STRING,
+ GET_ATTRIBUTE_INT,
+ GET_N_SAMPLES,
+ GET_GENOTYPES_FOR_SAMPLES,
+ GET_GENOTYPES_IN_ORDER_OF_NAME,
+ CALC_GENOTYPE_COUNTS,
+ MERGE
+ }
+
+ @Override protected void setUp() {
+ // TODO -- update for new tribble interface
+// try {
+// ReferenceSequenceFile seq = new CachingIndexedFastaSequenceFile(new File(BaseTest.b37KGReference));
+// b37GenomeLocParser = new GenomeLocParser(seq);
+// } catch ( FileNotFoundException e) {
+// throw new RuntimeException(e);
+// }
+//
+// // read it into a String so that we don't try to benchmark IO issues
+// try {
+// FileInputStream s = new FileInputStream(new File(vcfFile));
+// AsciiLineReader lineReader = new AsciiLineReader(s);
+// int counter = 0;
+// StringBuffer sb = new StringBuffer();
+// while (counter++ < linesToRead ) {
+// String line = lineReader.readLine();
+// if ( line == null )
+// break;
+// sb.append(line + "\n");
+// }
+// s.close();
+// INPUT_STRING = sb.toString();
+// } catch (IOException e) {
+// throw new RuntimeException(e);
+// }
+ }
+
+ private interface FunctionToBenchmark<T extends Feature> {
+ public void run(T vc);
+ }
+
+ private <T extends Feature> void runBenchmark(FeatureCodec codec, FunctionToBenchmark<T> func) {
+ // TODO -- update for new Tribble interface
+// try {
+// InputStream is = new ByteArrayInputStream(INPUT_STRING.getBytes());
+// AsciiLineReader lineReader = new AsciiLineReader(is);
+// codec.readHeader(lineReader);
+//
+// int counter = 0;
+// while (counter++ < linesToRead ) {
+// String line = lineReader.readLine();
+// if ( line == null )
+// break;
+//
+// T vc = codec.decode(line);
+// func.run(vc);
+// }
+// } catch (Exception e) {
+// System.out.println("Benchmarking run failure because of " + e.getMessage());
+// }
+ }
+
+ public void timeV14(int rep) {
+ for ( int i = 0; i < rep; i++ ) {
+ FunctionToBenchmark<VariantContext> func = getV14FunctionToBenchmark();
+ final VCFCodec codec = new VCFCodec();
+ runBenchmark(codec, func);
+ }
+ }
+
+ public FunctionToBenchmark<VariantContext> getV14FunctionToBenchmark() {
+ switch ( operation ) {
+ case READ:
+ return new FunctionToBenchmark<VariantContext>() {
+ public void run(final VariantContext vc) {
+ ; // empty operation
+ }
+ };
+ case SUBSET_TO_SAMPLES:
+ return new FunctionToBenchmark<VariantContext>() {
+ Set<String> samples;
+ public void run(final VariantContext vc) {
+ if ( samples == null )
+ samples = new HashSet<>(new ArrayList<>(vc.getSampleNames()).subList(0, nSamplesToTake));
+ VariantContext sub = vc.subContextFromSamples(samples);
+ sub.getNSamples();
+ }
+ };
+ case GET_TYPE:
+ return new FunctionToBenchmark<VariantContext>() {
+ public void run(final VariantContext vc) {
+ vc.getType();
+ }
+ };
+ case GET_ID:
+ return new FunctionToBenchmark<VariantContext>() {
+ public void run(final VariantContext vc) {
+ vc.getID();
+ }
+ };
+ case GET_GENOTYPES:
+ return new FunctionToBenchmark<VariantContext>() {
+ public void run(final VariantContext vc) {
+ vc.getGenotypes().size();
+ }
+ };
+
+ case GET_GENOTYPES_FOR_SAMPLES:
+ return new FunctionToBenchmark<VariantContext>() {
+ Set<String> samples;
+ public void run(final VariantContext vc) {
+ if ( samples == null )
+ samples = new HashSet<>(new ArrayList<>(vc.getSampleNames()).subList(0, nSamplesToTake));
+ vc.getGenotypes(samples).size();
+ }
+ };
+
+ case GET_ATTRIBUTE_STRING:
+ return new FunctionToBenchmark<VariantContext>() {
+ public void run(final VariantContext vc) {
+ vc.getAttribute("AN", null);
+ }
+ };
+
+ case GET_ATTRIBUTE_INT:
+ return new FunctionToBenchmark<VariantContext>() {
+ public void run(final VariantContext vc) {
+ vc.getAttributeAsInt("AC", 0);
+ }
+ };
+
+ case GET_N_SAMPLES:
+ return new FunctionToBenchmark<VariantContext>() {
+ public void run(final VariantContext vc) {
+ vc.getNSamples();
+ }
+ };
+
+ case GET_GENOTYPES_IN_ORDER_OF_NAME:
+ return new FunctionToBenchmark<VariantContext>() {
+ public void run(final VariantContext vc) {
+ ; // TODO - TEST IS BROKEN
+// int n = 0;
+// for ( final Genotype g: vc.getGenotypesOrderedByName() ) n++;
+ }
+ };
+
+ case CALC_GENOTYPE_COUNTS:
+ return new FunctionToBenchmark<VariantContext>() {
+ public void run(final VariantContext vc) {
+ vc.getHetCount();
+ }
+ };
+
+ case MERGE:
+ return new FunctionToBenchmark<VariantContext>() {
+ public void run(final VariantContext vc) {
+ List<VariantContext> toMerge = new ArrayList<>();
+
+ for ( int i = 0; i < dupsToMerge; i++ ) {
+ GenotypesContext gc = GenotypesContext.create(vc.getNSamples());
+ for ( final Genotype g : vc.getGenotypes() ) {
+ gc.add(new GenotypeBuilder(g).name(g.getSampleName()+"_"+i).make());
+ }
+ toMerge.add(new VariantContextBuilder(vc).genotypes(gc).make());
+ }
+
+ GATKVariantContextUtils.simpleMerge(toMerge, null,
+ GATKVariantContextUtils.FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED,
+ GATKVariantContextUtils.GenotypeMergeType.UNSORTED,
+ true, false, "set", false, true);
+ }
+ };
+
+ default: throw new IllegalArgumentException("Unexpected operation " + operation);
+ }
+ }
+
+ // --------------------------------------------------------------------------------
+ //
+ // V13
+ //
+ // In order to use this, you must move the v13 version from archive and uncomment
+ //
+ // git mv private/archive/java/src/org/broadinstitute/sting/utils/variantcontext/v13 public/java/test/org/broadinstitute/sting/utils/variantcontext/v13
+ //
+ // --------------------------------------------------------------------------------
+
+// public void timeV13(int rep) {
+// for ( int i = 0; i < rep; i++ ) {
+// FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext> func = getV13FunctionToBenchmark();
+// FeatureCodec<htsjdk.variant.variantcontext.v13.VariantContext> codec = new htsjdk.variant.variantcontext.v13.VCFCodec();
+// runBenchmark(codec, func);
+// }
+// }
+//
+// public FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext> getV13FunctionToBenchmark() {
+// switch ( operation ) {
+// case READ:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// ; // empty operation
+// }
+// };
+// case SUBSET_TO_SAMPLES:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// List<String> samples;
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// if ( samples == null )
+// samples = new ArrayList<String>(vc.getSampleNames()).subList(0, nSamplesToTake);
+// htsjdk.variant.variantcontext.v13.VariantContext sub = vc.subContextFromGenotypes(vc.getGenotypes(samples).values());
+// sub.getNSamples();
+// }
+// };
+//
+// case GET_TYPE:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// vc.getType();
+// }
+// };
+// case GET_ID:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// vc.getID();
+// }
+// };
+// case GET_GENOTYPES:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// vc.getGenotypes().size();
+// }
+// };
+//
+// case GET_GENOTYPES_FOR_SAMPLES:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// Set<String> samples;
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// if ( samples == null )
+// samples = new HashSet<String>(new ArrayList<String>(vc.getSampleNames()).subList(0, nSamplesToTake));
+// vc.getGenotypes(samples).size();
+// }
+// };
+//
+// case GET_ATTRIBUTE_STRING:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// vc.getExtendedAttribute("AN", null);
+// }
+// };
+//
+// case GET_ATTRIBUTE_INT:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// vc.getAttributeAsInt("AC", 0);
+// }
+// };
+//
+// case GET_N_SAMPLES:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// vc.getNSamples();
+// }
+// };
+//
+// case GET_GENOTYPES_IN_ORDER_OF_NAME:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// ; // TODO - TEST IS BROKEN
+// //vc.getGenotypesOrderedByName();
+// }
+// };
+//
+// case CALC_GENOTYPE_COUNTS:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// vc.getHetCount();
+// }
+// };
+//
+// case MERGE:
+// return new FunctionToBenchmark<htsjdk.variant.variantcontext.v13.VariantContext>() {
+// public void run(final htsjdk.variant.variantcontext.v13.VariantContext vc) {
+// List<htsjdk.variant.variantcontext.v13.VariantContext> toMerge = new ArrayList<htsjdk.variant.variantcontext.v13.VariantContext>();
+//
+// for ( int i = 0; i < dupsToMerge; i++ ) {
+// Map<String, htsjdk.variant.variantcontext.v13.Genotype> gc = new HashMap<String, htsjdk.variant.variantcontext.v13.Genotype>();
+// for ( final htsjdk.variant.variantcontext.v13.Genotype g : vc.getGenotypes().values() ) {
+// String name = g.getSampleName()+"_"+i;
+// gc.put(name, new htsjdk.variant.variantcontext.v13.Genotype(name,
+// g.getAlleles(), g.getLog10PError(), g.getFilters(), g.getAttributes(), g.isPhased(), g.getLikelihoods().getAsVector()));
+// toMerge.add(htsjdk.variant.variantcontext.v13.VariantContext.modifyGenotypes(vc, gc));
+// }
+// }
+//
+// htsjdk.variant.variantcontext.v13.VariantContextUtils.simpleMerge(b37GenomeLocParser,
+// toMerge, null,
+// htsjdk.variant.variantcontext.v13.VariantContextUtils.FilteredRecordMergeType.KEEP_IF_ANY_UNFILTERED,
+// htsjdk.variant.variantcontext.v13.VariantContextUtils.GenotypeMergeType.UNSORTED,
+// true, false, "set", false, true, false);
+// }
+// };
+//
+// default: throw new IllegalArgumentException("Unexpected operation " + operation);
+// }
+// }
+
+ public static void main(String[] args) {
+ com.google.caliper.Runner.main(VariantContextBenchmark.class, args);
+ }
+}
diff --git a/public/gatk-tools-public/src/test/resources/testProperties.properties b/public/gatk-tools-public/src/test/resources/testProperties.properties
new file mode 100644
index 0000000..e422d6e
--- /dev/null
+++ b/public/gatk-tools-public/src/test/resources/testProperties.properties
@@ -0,0 +1,2 @@
+foo=bar
+version=1.0
diff --git a/public/gatk-utils/pom.xml b/public/gatk-utils/pom.xml
new file mode 100644
index 0000000..f656394
--- /dev/null
+++ b/public/gatk-utils/pom.xml
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-aggregator</artifactId>
+ <version>3.3</version>
+ <relativePath>../..</relativePath>
+ </parent>
+
+ <artifactId>gatk-utils</artifactId>
+ <packaging>jar</packaging>
+ <name>GATK Utils</name>
+
+ <properties>
+ <gatk.basedir>${project.basedir}/../..</gatk.basedir>
+ <gatk.packagetests.artifactId>gatk-package-distribution</gatk.packagetests.artifactId>
+ <gsalib.packagedir>org/broadinstitute/gatk/utils/R</gsalib.packagedir>
+ <gsalib.filename>gsalib.tar.gz</gsalib.filename>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>samtools</groupId>
+ <artifactId>htsjdk</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>picard</groupId>
+ <artifactId>picard</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>colt</groupId>
+ <artifactId>colt</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>it.unimi.dsi</groupId>
+ <artifactId>fastutil</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.simpleframework</groupId>
+ <artifactId>simple-xml</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.reflections</groupId>
+ <artifactId>reflections</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-jexl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-math</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>net.java.dev.jna</groupId>
+ <artifactId>jna</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>net.java.dev.jets3t</groupId>
+ <artifactId>jets3t</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>us.levk</groupId>
+ <artifactId>drmaa-gridengine</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.cofoja</groupId>
+ <artifactId>cofoja</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gsalib</artifactId>
+ <version>${project.version}</version>
+ <type>tar.gz</type>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.caliper</groupId>
+ <artifactId>caliper</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-gsalib</id>
+ <goals>
+ <goal>copy</goal>
+ </goals>
+ <phase>process-resources</phase>
+ <configuration>
+ <artifactItems>
+ <artifactItem>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gsalib</artifactId>
+ <version>${project.version}</version>
+ <type>tar.gz</type>
+ <outputDirectory>${project.build.outputDirectory}/${gsalib.packagedir}</outputDirectory>
+ <destFileName>${gsalib.filename}</destFileName>
+ </artifactItem>
+ </artifactItems>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>copy-resource-bundle-log4j</id>
+ <phase>prepare-package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <!--
+ TODO: Refactor ResourceBundleExtractorDoclet.isWalker() and move the RBED to utils.
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>extract-resource-bundle</id>
+ <phase>prepare-package</phase>
+ </execution>
+ </executions>
+ </plugin>
+ -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-invoker-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>package-unittests</id>
+ </execution>
+ <execution>
+ <id>package-integrationtests</id>
+ </execution>
+ <execution>
+ <id>package-largescaletests</id>
+ </execution>
+ <execution>
+ <id>package-knowledgebasetests</id>
+ </execution>
+ <execution>
+ <id>package-queuetests</id>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/public/gatk-utils/src/main/config/org/broadinstitute/gatk/utils/help/log4j.properties b/public/gatk-utils/src/main/config/org/broadinstitute/gatk/utils/help/log4j.properties
new file mode 100644
index 0000000..38c8335
--- /dev/null
+++ b/public/gatk-utils/src/main/config/org/broadinstitute/gatk/utils/help/log4j.properties
@@ -0,0 +1,7 @@
+# Root logger option
+log4j.rootLogger=INFO, stdout
+
+# Direct log messages to stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout
diff --git a/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/GenomeLoc.java b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/GenomeLoc.java
new file mode 100644
index 0000000..101796b
--- /dev/null
+++ b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/GenomeLoc.java
@@ -0,0 +1,657 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+import htsjdk.samtools.SAMFileHeader;
+import org.broadinstitute.gatk.utils.exceptions.ReviewedGATKException;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: mdepristo
+ * Date: Mar 2, 2009
+ * Time: 8:50:11 AM
+ *
+ * Genome location representation. It is *** 1 *** based closed. Note that GenomeLocs start and stop values
+ * can be any positive or negative number, by design. Bound validation is a feature of the GenomeLocParser,
+ * and not a fundamental constraint of the GenomeLoc
+ */
+public class GenomeLoc implements Comparable<GenomeLoc>, Serializable, HasGenomeLocation {
+ /**
+ * the basic components of a genome loc, its contig index,
+ * start and stop position, and (optionally) the contig name
+ */
+ protected final int contigIndex;
+ protected final int start;
+ protected final int stop;
+ protected final String contigName;
+
+ /**
+ * A static constant to use when referring to the unmapped section of a datafile
+ * file. The unmapped region cannot be subdivided. Only this instance of
+ * the object may be used to refer to the region, as '==' comparisons are used
+ * in comparators, etc.
+ */
+ // TODO - WARNING WARNING WARNING code somehow depends on the name of the contig being null!
+ public static final GenomeLoc UNMAPPED = new GenomeLoc((String)null);
+ public static final GenomeLoc WHOLE_GENOME = new GenomeLoc("all");
+
+ public static final boolean isUnmapped(GenomeLoc loc) {
+ return loc == UNMAPPED;
+ }
+
+ // --------------------------------------------------------------------------------------------------------------
+ //
+ // constructors
+ //
+ // --------------------------------------------------------------------------------------------------------------
+
+ @Requires({
+ "contig != null",
+ "contigIndex >= 0", // I believe we aren't allowed to create GenomeLocs without a valid contigIndex
+ "start <= stop"})
+ protected GenomeLoc( final String contig, final int contigIndex, final int start, final int stop ) {
+ this.contigName = contig;
+ this.contigIndex = contigIndex;
+ this.start = start;
+ this.stop = stop;
+ }
+
+ /** Unsafe constructor for special constant genome locs */
+ private GenomeLoc( final String contig ) {
+ this.contigName = contig;
+ this.contigIndex = -1;
+ this.start = 0;
+ this.stop = 0;
+ }
+
+ //
+ // Accessors
+ //
+ @Ensures("result != null")
+ public final GenomeLoc getLocation() { return this; }
+
+ public final GenomeLoc getStartLocation() { return new GenomeLoc(getContig(),getContigIndex(),getStart(),getStart()); }
+
+ public final GenomeLoc getStopLocation() { return new GenomeLoc(getContig(),getContigIndex(),getStop(),getStop()); }
+
+ /**
+ * @return the name of the contig of this GenomeLoc
+ */
+ public final String getContig() {
+ return this.contigName;
+ }
+
+ public final int getContigIndex() { return this.contigIndex; }
+ public final int getStart() { return this.start; }
+ public final int getStop() { return this.stop; }
+
+ @Ensures("result != null")
+ public final String toString() {
+ if(GenomeLoc.isUnmapped(this)) return "unmapped";
+ if ( throughEndOfContigP() && atBeginningOfContigP() )
+ return getContig();
+ else if ( throughEndOfContigP() || getStart() == getStop() )
+ return String.format("%s:%d", getContig(), getStart());
+ else
+ return String.format("%s:%d-%d", getContig(), getStart(), getStop());
+ }
+
+ private boolean throughEndOfContigP() { return this.stop == Integer.MAX_VALUE; }
+
+ private boolean atBeginningOfContigP() { return this.start == 1; }
+
+ @Requires("that != null")
+ public final boolean disjointP(GenomeLoc that) {
+ return this.contigIndex != that.contigIndex || this.start > that.stop || that.start > this.stop;
+ }
+
+ @Requires("that != null")
+ public final boolean discontinuousP(GenomeLoc that) {
+ return this.contigIndex != that.contigIndex || (this.start - 1) > that.stop || (that.start - 1) > this.stop;
+ }
+
+ @Requires("that != null")
+ public final boolean overlapsP(GenomeLoc that) {
+ return ! disjointP( that );
+ }
+
+ @Requires("that != null")
+ public final boolean contiguousP(GenomeLoc that) {
+ return ! discontinuousP( that );
+ }
+
+ /**
+ * Return true if this GenomeLoc represents the UNMAPPED location
+ * @return
+ */
+ public final boolean isUnmapped() {
+ return isUnmapped(this);
+ }
+
+
+ /**
+ * Returns a new GenomeLoc that represents the entire span of this and that. Requires that
+ * this and that GenomeLoc are contiguous and both mapped
+ */
+ @Requires({
+ "that != null",
+ "isUnmapped(this) == isUnmapped(that)"})
+ @Ensures("result != null")
+ public GenomeLoc merge( GenomeLoc that ) throws ReviewedGATKException {
+ if(GenomeLoc.isUnmapped(this) || GenomeLoc.isUnmapped(that)) {
+ if(! GenomeLoc.isUnmapped(this) || !GenomeLoc.isUnmapped(that))
+ throw new ReviewedGATKException("Tried to merge a mapped and an unmapped genome loc");
+ return UNMAPPED;
+ }
+
+ if (!(this.contiguousP(that))) {
+ throw new ReviewedGATKException("The two genome loc's need to be contiguous");
+ }
+
+ return new GenomeLoc(getContig(), this.contigIndex,
+ Math.min( getStart(), that.getStart() ),
+ Math.max( getStop(), that.getStop()) );
+ }
+
+ /**
+ * Returns a new GenomeLoc that represents the region between the endpoints of this and that. Requires that
+ * this and that GenomeLoc are both mapped.
+ */
+ @Requires({"that != null", "isUnmapped(this) == isUnmapped(that)"})
+ @Ensures("result != null")
+ public GenomeLoc endpointSpan(GenomeLoc that) throws ReviewedGATKException {
+ if(GenomeLoc.isUnmapped(this) || GenomeLoc.isUnmapped(that)) {
+ throw new ReviewedGATKException("Cannot get endpoint span for unmerged genome locs");
+ }
+
+ if ( ! this.getContig().equals(that.getContig()) ) {
+ throw new ReviewedGATKException("Cannot get endpoint span for genome locs on different contigs");
+ }
+
+ return new GenomeLoc(getContig(),this.contigIndex,Math.min(getStart(),that.getStart()),Math.max(getStop(),that.getStop()));
+ }
+
+ /**
+ * Splits the contig into to regions: [start,split point) and [split point, end].
+ * @param splitPoint The point at which to split the contig. Must be contained in the given interval.
+ * @return A two element array consisting of the genome loc before the split and the one after.
+ */
+ public GenomeLoc[] split(final int splitPoint) {
+ if(splitPoint < getStart() || splitPoint > getStop())
+ throw new ReviewedGATKException(String.format("Unable to split contig %s at split point %d; split point is not contained in region.",this,splitPoint));
+ return new GenomeLoc[] { new GenomeLoc(getContig(),contigIndex,getStart(),splitPoint-1), new GenomeLoc(getContig(),contigIndex,splitPoint,getStop()) };
+ }
+
+ public GenomeLoc union( GenomeLoc that ) { return merge(that); }
+
+ @Requires("that != null")
+ @Ensures("result != null")
+ public GenomeLoc intersect( GenomeLoc that ) throws ReviewedGATKException {
+ if(GenomeLoc.isUnmapped(this) || GenomeLoc.isUnmapped(that)) {
+ if(! GenomeLoc.isUnmapped(this) || !GenomeLoc.isUnmapped(that))
+ throw new ReviewedGATKException("Tried to intersect a mapped and an unmapped genome loc");
+ return UNMAPPED;
+ }
+
+ if (!(this.overlapsP(that))) {
+ throw new ReviewedGATKException("GenomeLoc::intersect(): The two genome loc's need to overlap");
+ }
+
+ return new GenomeLoc(getContig(), this.contigIndex,
+ Math.max(getStart(), that.getStart()),
+ Math.min( getStop(), that.getStop()) );
+ }
+
+ @Requires("that != null")
+ public final List<GenomeLoc> subtract( final GenomeLoc that ) {
+ if(GenomeLoc.isUnmapped(this) || GenomeLoc.isUnmapped(that)) {
+ if(! GenomeLoc.isUnmapped(this) || !GenomeLoc.isUnmapped(that))
+ throw new ReviewedGATKException("Tried to intersect a mapped and an unmapped genome loc");
+ return Arrays.asList(UNMAPPED);
+ }
+
+ if (!(this.overlapsP(that))) {
+ throw new ReviewedGATKException("GenomeLoc::minus(): The two genome loc's need to overlap");
+ }
+
+ if (equals(that)) {
+ return Collections.emptyList();
+ } else if (containsP(that)) {
+ List<GenomeLoc> l = new ArrayList<GenomeLoc>(2);
+
+ /**
+ * we have to create two new region, one for the before part, one for the after
+ * The old region:
+ * |----------------- old region (g) -------------|
+ * |----- to delete (e) ------|
+ *
+ * product (two new regions):
+ * |------| + |--------|
+ *
+ */
+ int afterStop = this.getStop(), afterStart = that.getStop() + 1;
+ int beforeStop = that.getStart() - 1, beforeStart = this.getStart();
+ if (afterStop - afterStart >= 0) {
+ GenomeLoc after = new GenomeLoc(this.getContig(), getContigIndex(), afterStart, afterStop);
+ l.add(after);
+ }
+ if (beforeStop - beforeStart >= 0) {
+ GenomeLoc before = new GenomeLoc(this.getContig(), getContigIndex(), beforeStart, beforeStop);
+ l.add(before);
+ }
+
+ return l;
+ } else if (that.containsP(this)) {
+ /**
+ * e completely contains g, delete g, but keep looking, there may be more regions
+ * i.e.:
+ * |--------------------- e --------------------|
+ * |--- g ---| |---- others ----|
+ */
+ return Collections.emptyList(); // don't need to do anything
+ } else {
+ /**
+ * otherwise e overlaps some part of g
+ *
+ * figure out which region occurs first on the genome. I.e., is it:
+ * |------------- g ----------|
+ * |------------- e ----------|
+ *
+ * or:
+ * |------------- g ----------|
+ * |------------ e -----------|
+ *
+ */
+
+ GenomeLoc n;
+ if (that.getStart() < this.getStart()) {
+ n = new GenomeLoc(this.getContig(), getContigIndex(), that.getStop() + 1, this.getStop());
+ } else {
+ n = new GenomeLoc(this.getContig(), getContigIndex(), this.getStart(), that.getStart() - 1);
+ }
+
+ // replace g with the new region
+ return Arrays.asList(n);
+ }
+ }
+
+ @Requires("that != null")
+ public final boolean containsP(GenomeLoc that) {
+ return onSameContig(that) && getStart() <= that.getStart() && getStop() >= that.getStop();
+ }
+
+ @Requires("that != null")
+ public final boolean onSameContig(GenomeLoc that) {
+ return (this.contigIndex == that.contigIndex);
+ }
+
+ @Requires("that != null")
+ @Ensures("result >= 0")
+ public final int distance( final GenomeLoc that ) {
+ if ( this.onSameContig(that) )
+ return Math.abs(this.getStart() - that.getStart());
+ else
+ return Integer.MAX_VALUE;
+ }
+
+ @Requires({"left != null", "right != null"})
+ public final boolean isBetween( final GenomeLoc left, final GenomeLoc right ) {
+ return this.compareTo(left) > -1 && this.compareTo(right) < 1;
+ }
+
+ /**
+ * Tests whether this contig is completely before contig 'that'.
+ * @param that Contig to test against.
+ * @return true if this contig ends before 'that' starts; false if this is completely after or overlaps 'that'.
+ */
+ @Requires("that != null")
+ public final boolean isBefore( GenomeLoc that ) {
+ int comparison = this.compareContigs(that);
+ return ( comparison == -1 || ( comparison == 0 && this.getStop() < that.getStart() ));
+ }
+
+ /**
+ * Tests whether this genome loc starts at the same position as that.
+ *
+ * i.e., do this and that have the same contig and the same start position
+ *
+ * @param that genome loc to compare to
+ * @return true if this and that have the same contig and the same start position
+ */
+ @Requires("that != null")
+ public final boolean startsAt( GenomeLoc that ) {
+ int comparison = this.compareContigs(that);
+ return comparison == 0 && this.getStart() == that.getStart();
+ }
+
+ /**
+ * Tests whether any portion of this contig is before that contig.
+ * @param that Other contig to test.
+ * @return True if the start of this contig is before the start of the that contig.
+ */
+ @Requires("that != null")
+ public final boolean startsBefore(final GenomeLoc that) {
+ int comparison = this.compareContigs(that);
+ return ( comparison == -1 || ( comparison == 0 && this.getStart() < that.getStart() ));
+ }
+
+ /**
+ * Tests whether this contig is completely after contig 'that'.
+ * @param that Contig to test against.
+ * @return true if this contig starts after 'that' ends; false if this is completely before or overlaps 'that'.
+ */
+ @Requires("that != null")
+ public final boolean isPast( GenomeLoc that ) {
+ int comparison = this.compareContigs(that);
+ return ( comparison == 1 || ( comparison == 0 && this.getStart() > that.getStop() ));
+ }
+
+ /**
+ * Return the minimum distance between any pair of bases in this and that GenomeLocs:
+ */
+ @Requires("that != null")
+ @Ensures("result >= 0")
+ public final int minDistance( final GenomeLoc that ) {
+ if (!this.onSameContig(that))
+ return Integer.MAX_VALUE;
+
+ int minDistance;
+ if (this.isBefore(that))
+ minDistance = distanceFirstStopToSecondStart(this, that);
+ else if (that.isBefore(this))
+ minDistance = distanceFirstStopToSecondStart(that, this);
+ else // this and that overlap [and possibly one contains the other]:
+ minDistance = 0;
+
+ return minDistance;
+ }
+
+ @Requires({
+ "locFirst != null",
+ "locSecond != null",
+ "locSecond.isPast(locFirst)"
+ })
+ @Ensures("result >= 0")
+ private static int distanceFirstStopToSecondStart(GenomeLoc locFirst, GenomeLoc locSecond) {
+ return locSecond.getStart() - locFirst.getStop();
+ }
+
+
+
+ /**
+ * Check to see whether two genomeLocs are equal.
+ * Note that this implementation ignores the contigInfo object.
+ * @param other Other contig to compare.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if(other == null)
+ return false;
+ if(other instanceof GenomeLoc) {
+ GenomeLoc otherGenomeLoc = (GenomeLoc)other;
+ return this.contigIndex == otherGenomeLoc.contigIndex &&
+ this.start == otherGenomeLoc.start &&
+ this.stop == otherGenomeLoc.stop;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return start << 16 | stop << 4 | contigIndex;
+ }
+
+
+ /**
+ * conpare this genomeLoc's contig to another genome loc
+ * @param that the genome loc to compare contigs with
+ * @return 0 if equal, -1 if that.contig is greater, 1 if this.contig is greater
+ */
+ @Requires("that != null")
+ @Ensures("result == 0 || result == 1 || result == -1")
+ public final int compareContigs( GenomeLoc that ) {
+ if (this.contigIndex == that.contigIndex)
+ return 0;
+ else if (this.contigIndex > that.contigIndex)
+ return 1;
+ return -1;
+ }
+
+ @Requires("that != null")
+ @Ensures("result == 0 || result == 1 || result == -1")
+ public int compareTo( GenomeLoc that ) {
+ int result = 0;
+
+ if ( this == that ) {
+ result = 0;
+ }
+ else if(GenomeLoc.isUnmapped(this))
+ result = 1;
+ else if(GenomeLoc.isUnmapped(that))
+ result = -1;
+ else {
+ final int cmpContig = compareContigs(that);
+
+ if ( cmpContig != 0 ) {
+ result = cmpContig;
+ } else {
+ if ( this.getStart() < that.getStart() ) result = -1;
+ else if ( this.getStart() > that.getStart() ) result = 1;
+ // these have the same start, so check the ends
+ else if ( this.getStop() < that.getStop() ) result = -1;
+ else if ( this.getStop() > that.getStop() ) result = 1;
+ }
+ }
+
+ return result;
+ }
+
+ @Requires("that != null")
+ public boolean endsAt(GenomeLoc that) {
+ return (this.compareContigs(that) == 0) && ( this.getStop() == that.getStop() );
+ }
+
+ /**
+ * How many BPs are covered by this locus?
+ * @return Number of BPs covered by this locus. According to the semantics of GenomeLoc, this should
+ * never be < 1.
+ */
+ @Ensures("result > 0")
+ public int size() {
+ return stop - start + 1;
+ }
+
+ /**
+ * reciprocialOverlap: what is the min. percent of gl1 and gl2 covered by both
+ *
+ * gl1.s ---------- gk1.e
+ * gl2.s ---------- gl2.e
+ * 100%
+ *
+ * gl1.s ---------- gk1.e
+ * gl2.s ---------- gl2.e
+ * 50%
+ *
+ * gl1.s ---------- gk1.e
+ * gl2.s -------------------- gl2.e
+ * 25% (50% for gl1 but only 25% for gl2)
+ */
+ public final double reciprocialOverlapFraction(final GenomeLoc o) {
+ if ( overlapsP(o) )
+ return Math.min(overlapPercent(this, o), overlapPercent(o, this));
+ else
+ return 0.0;
+ }
+
+ private final static double overlapPercent(final GenomeLoc gl1, final GenomeLoc gl2) {
+ return (1.0 * gl1.intersect(gl2).size()) / gl1.size();
+ }
+
+ public long sizeOfOverlap( final GenomeLoc that ) {
+ return ( this.overlapsP(that) ? Math.min( getStop(), that.getStop() ) - Math.max( getStart(), that.getStart() ) + 1L : 0L );
+ }
+
+ /**
+ * Returns the maximum GenomeLoc of this and other
+ * @param other another non-null genome loc
+ * @return the max of this and other
+ */
+ public GenomeLoc max(final GenomeLoc other) {
+ final int cmp = this.compareTo(other);
+ return cmp == -1 ? other : this;
+ }
+
+ /**
+ * create a new genome loc from an existing loc, with a new start position
+ * Note that this function will NOT explicitly check the ending offset, in case someone wants to
+ * set the start of a new GenomeLoc pertaining to a read that goes off the end of the contig.
+ *
+ * @param loc the old location
+ * @param start a new start position
+ *
+ * @return a newly allocated GenomeLoc as loc but with start == start
+ */
+ public GenomeLoc setStart(GenomeLoc loc, int start) {
+ return new GenomeLoc(loc.getContig(), loc.getContigIndex(), start, loc.getStop());
+ }
+
+ /**
+ * create a new genome loc from an existing loc, with a new stop position
+ * Note that this function will NOT explicitly check the ending offset, in case someone wants to
+ * set the stop of a new GenomeLoc pertaining to a read that goes off the end of the contig.
+ *
+ * @param loc the old location
+ * @param stop a new stop position
+ *
+ * @return a newly allocated GenomeLoc as loc but with stop == stop
+ */
+ public GenomeLoc setStop(GenomeLoc loc, int stop) {
+ return new GenomeLoc(loc.getContig(), loc.getContigIndex(), loc.start, stop);
+ }
+
+ /**
+ * return a new genome loc, with an incremented position
+ *
+ * @return a newly allocated GenomeLoc as loc but with start == loc.getStart() + 1
+ */
+ public GenomeLoc incPos() {
+ return incPos(1);
+ }
+
+ /**
+ * return a new genome loc, with an incremented position
+ *
+ * @param by how much to move the start and stop by
+ *
+ * @return a newly allocated GenomeLoc as loc but with start == loc.getStart() + by
+ */
+ public GenomeLoc incPos(int by) {
+ return new GenomeLoc(getContig(), getContigIndex(), start + by, stop + by);
+ }
+
+ /**
+ * Merges 2 *contiguous* locs into 1
+ *
+ * @param a GenomeLoc #1
+ * @param b GenomeLoc #2
+ * @return one merged loc
+ */
+ @Requires("a != null && b != null")
+ public static <T extends GenomeLoc> GenomeLoc merge(final T a, final T b) {
+ if ( isUnmapped(a) || isUnmapped(b) ) {
+ throw new ReviewedGATKException("Tried to merge unmapped genome locs");
+ }
+
+ if ( !(a.contiguousP(b)) ) {
+ throw new ReviewedGATKException("The two genome locs need to be contiguous");
+ }
+
+ return new GenomeLoc(a.getContig(), a.contigIndex, Math.min(a.getStart(), b.getStart()), Math.max(a.getStop(), b.getStop()));
+ }
+
+ /**
+ * Merges a list of *sorted* *contiguous* locs into 1
+ *
+ * @param sortedLocs a sorted list of contiguous locs
+ * @return one merged loc
+ */
+ @Requires("sortedLocs != null")
+ public static <T extends GenomeLoc> GenomeLoc merge(final SortedSet<T> sortedLocs) {
+ GenomeLoc result = null;
+
+ for ( GenomeLoc loc : sortedLocs ) {
+ if ( loc.isUnmapped() )
+ throw new ReviewedGATKException("Tried to merge unmapped genome locs");
+
+ if ( result == null )
+ result = loc;
+ else if ( !result.contiguousP(loc) )
+ throw new ReviewedGATKException("The genome locs need to be contiguous");
+ else
+ result = merge(result, loc);
+ }
+
+ return result;
+ }
+
+ /**
+ * Calculates the distance between two genomeLocs across contigs (if necessary).
+ *
+ * Returns minDistance(other) if in same contig.
+ * Works with intervals!
+ * Uses the SAMFileHeader to extract the size of the contigs and follows the order in the dictionary.
+ *
+ * @param other the genome loc to compare to
+ * @param samFileHeader the contig information
+ * @return the sum of all the bases in between the genomeLocs, including entire contigs
+ */
+ public long distanceAcrossContigs(GenomeLoc other, SAMFileHeader samFileHeader) {
+ if (onSameContig(other))
+ return minDistance(other);
+
+ // add the distance from the first genomeLoc to the end of it's contig and the distance from the
+ // second genomeLoc to the beginning of it's contig.
+ long distance = 0;
+ if (contigIndex < other.contigIndex) {
+ distance += samFileHeader.getSequence(contigIndex).getSequenceLength() - stop;
+ distance += other.start;
+ } else {
+ distance += samFileHeader.getSequence(other.contigIndex).getSequenceLength() - other.stop;
+ distance += start;
+ }
+
+ // add any contig (in its entirety) in between the two genomeLocs
+ for (int i=Math.min(this.contigIndex, other.contigIndex) + 1; i < Math.max(this.contigIndex, other.contigIndex); i++) {
+ distance += samFileHeader.getSequence(i).getSequenceLength();
+ }
+ return distance;
+ }
+}
diff --git a/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/HasGenomeLocation.java b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/HasGenomeLocation.java
new file mode 100644
index 0000000..d080d5b
--- /dev/null
+++ b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/HasGenomeLocation.java
@@ -0,0 +1,36 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+import com.google.java.contract.Ensures;
+
+/**
+ * Indicates that this object has a genomic location and provides a systematic interface to get it.
+ */
+public interface HasGenomeLocation {
+ @Ensures("result != null")
+ public GenomeLoc getLocation();
+}
diff --git a/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/SimpleTimer.java b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/SimpleTimer.java
new file mode 100644
index 0000000..39d6fa6
--- /dev/null
+++ b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/SimpleTimer.java
@@ -0,0 +1,261 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
+
+
+import com.google.java.contract.Ensures;
+import com.google.java.contract.Requires;
+
+import org.apache.log4j.Logger;
+
+import java.text.NumberFormat;
+import java.util.concurrent.TimeUnit;
+import static java.lang.Math.abs;
+
+/**
+ * A useful simple system for timing code with nano second resolution
+ *
+ * Note that this code is not thread-safe. If you have a single timer
+ * being started and stopped by multiple threads you will need to protect the
+ * calls to avoid meaningless results of having multiple starts and stops
+ * called sequentially.
+ *
+ * This timer has been modified to provide better semantics for dealing with
+ * system-level checkpoint and restarting. Such events can cause the internal JVM
+ * clock to be reset, breaking timings based upon it. Whilst this is difficult to
+ * counter without getting explicit notice of checkpoint events, we try to moderate
+ * the symptoms through tracking the offset between the system clock and the JVM clock.
+ * If this offset grows drastically (greater than CLOCK_DRIFT), we infer a JVM restart
+ * and reset the timer.
+ *
+ * User: depristo
+ * Date: Dec 10, 2010
+ * Time: 9:07:44 AM
+ */
+public class SimpleTimer {
+ private final static Logger logger = Logger.getLogger(SimpleTimer.class);
+ protected static final double NANO_TO_SECOND_DOUBLE = 1.0 / TimeUnit.SECONDS.toNanos(1);
+ private static final long MILLI_TO_NANO= TimeUnit.MILLISECONDS.toNanos(1);
+ private static final ThreadLocal<NumberFormat> NUMBER_FORMAT = new ThreadLocal<NumberFormat>() {
+ @Override
+ protected NumberFormat initialValue() {
+ return NumberFormat.getIntegerInstance();
+ }
+ };
+
+ /**
+ * Allowable clock drift in nanoseconds.
+ */
+ private static final long CLOCK_DRIFT = TimeUnit.SECONDS.toNanos(5);
+ private final String name;
+
+ /**
+ * The difference between system time and JVM time at last sync.
+ * This is used to detect JVM checkpoint/restart events, and should be
+ * reset when a JVM checkpoint/restart is detected.
+ */
+ private long nanoTimeOffset;
+
+ /**
+ * The elapsedTimeNano time in nanoSeconds of this timer. The elapsedTimeNano time is the
+ * sum of times between starts/restrats and stops.
+ */
+ private long elapsedTimeNano = 0l;
+
+ /**
+ * The start time of the last start/restart in nanoSeconds
+ */
+ private long startTimeNano = 0l;
+
+ /**
+ * Is this timer currently running (i.e., the last call was start/restart)
+ */
+ private boolean running = false;
+
+ /**
+ * Creates an anonymous simple timer
+ */
+ public SimpleTimer() {
+ this("Anonymous");
+ }
+
+ /**
+ * Creates a simple timer named name
+ * @param name of the timer, must not be null
+ */
+ public SimpleTimer(final String name) {
+ if ( name == null ) throw new IllegalArgumentException("SimpleTimer name cannot be null");
+ this.name = name;
+
+ this.nanoTimeOffset = getNanoOffset();
+ }
+
+ /**
+ * @return the name associated with this timer
+ */
+ public synchronized String getName() {
+ return name;
+ }
+
+ /**
+ * Starts the timer running, and sets the elapsedTimeNano time to 0. This is equivalent to
+ * resetting the time to have no history at all.
+ *
+ * @return this object, for programming convenience
+ */
+ @Ensures("elapsedTimeNano == 0l")
+ public synchronized SimpleTimer start() {
+ elapsedTimeNano = 0l;
+ return restart();
+ }
+
+ /**
+ * Starts the timer running, without resetting the elapsedTimeNano time. This function may be
+ * called without first calling start(). The only difference between start and restart
+ * is that start resets the elapsedTimeNano time, while restart does not.
+ *
+ * @return this object, for programming convenience
+ */
+ public synchronized SimpleTimer restart() {
+ running = true;
+ startTimeNano = currentTimeNano();
+ nanoTimeOffset = getNanoOffset();
+ return this;
+ }
+
+ /**
+ * @return is this timer running?
+ */
+ public synchronized boolean isRunning() {
+ return running;
+ }
+
+ /**
+ * @return A convenience function to obtain the current time in milliseconds from this timer
+ */
+ public long currentTime() {
+ return System.currentTimeMillis();
+ }
+
+ /**
+ * @return A convenience function to obtain the current time in nanoSeconds from this timer
+ */
+ public long currentTimeNano() {
+ return System.nanoTime();
+ }
+
+ /**
+ * Stops the timer. Increases the elapsedTimeNano time by difference between start and now.
+ * This method calls `ensureClockSync` to make sure that the JVM and system clocks
+ * are roughly in sync since the start of the timer. If they are not, then the time
+ * elapsed since the previous 'stop' will not be added to the timer.
+ *
+ * It's ok to call stop on a timer that's not running. It has no effect on the timer.
+ *
+ * @return this object, for programming convenience
+ */
+ @Requires("startTimeNano != 0l")
+ public synchronized SimpleTimer stop() {
+ if ( running ) {
+ running = false;
+ if (ensureClockSync()) {
+ elapsedTimeNano += currentTimeNano() - startTimeNano;
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Returns the total elapsedTimeNano time of all start/stops of this timer. If the timer is currently
+ * running, includes the difference from currentTime() and the start as well
+ *
+ * @return this time, in seconds
+ */
+ public synchronized double getElapsedTime() {
+ return nanoToSecondsAsDouble(getElapsedTimeNano());
+ }
+
+ protected static double nanoToSecondsAsDouble(final long nano) {
+ return nano * NANO_TO_SECOND_DOUBLE;
+ }
+
+ /**
+ * @see #getElapsedTime() but returns the result in nanoseconds
+ *
+ * @return the elapsed time in nanoseconds
+ */
+ public synchronized long getElapsedTimeNano() {
+ if (running && ensureClockSync()) {
+ return currentTimeNano() - startTimeNano + elapsedTimeNano;
+ } else {
+ return elapsedTimeNano;
+ }
+ }
+
+ /**
+ * Add the elapsed time from toAdd to this elapsed time
+ *
+ * @param toAdd the timer whose elapsed time we want to add to this timer
+ */
+ public synchronized void addElapsed(final SimpleTimer toAdd) {
+ elapsedTimeNano += toAdd.getElapsedTimeNano();
+ }
+
+ /**
+ * Get the current offset of nano time from system time.
+ */
+ private static long getNanoOffset() {
+ return System.nanoTime() - (System.currentTimeMillis() * MILLI_TO_NANO);
+ }
+
+ /**
+ * Ensure that the JVM time has remained in sync with system time.
+ * This will also reset the clocks to avoid gradual drift.
+ *
+ * @return true if the clocks are in sync, false otherwise
+ */
+ private boolean ensureClockSync() {
+ final long currentOffset = getNanoOffset();
+ final long diff = abs(currentOffset - nanoTimeOffset);
+ final boolean ret = (diff <= CLOCK_DRIFT);
+ if (!ret) {
+ final NumberFormat numberFormat = NUMBER_FORMAT.get();
+ final String msg = String.format(
+ "Clock drift of %s - %s = %s nanoseconds detected, vs. max allowable drift of %s. " +
+ "Assuming checkpoint/restart event.",
+ numberFormat.format(currentOffset),
+ numberFormat.format(nanoTimeOffset),
+ numberFormat.format(diff),
+ numberFormat.format(CLOCK_DRIFT));
+ // Log message
+ logger.warn(msg);
+ }
+ // Reset the drift meter to stay in sync.
+ this.nanoTimeOffset = currentOffset;
+ return ret;
+ }
+
+}
diff --git a/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/exceptions/GATKException.java b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/exceptions/GATKException.java
new file mode 100644
index 0000000..0eb0941
--- /dev/null
+++ b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/exceptions/GATKException.java
@@ -0,0 +1,64 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.exceptions;
+
+/**
+ *
+ * User: aaron
+ * Date: Apr 6, 2009
+ * Time: 8:11:12 PM
+ *
+ * The Broad Institute
+ * SOFTWARE COPYRIGHT NOTICE AGREEMENT
+ * This software and its documentation are copyright 2009 by the
+ * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
+ *
+ * This software is supplied without any warranty or guaranteed support whatsoever. Neither
+ * the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
+ *
+ */
+
+
+/**
+ * @author aaron
+ * @version 1.0
+ * @date Apr 6, 2009
+ * <p/>
+ * Class GATKException
+ * <p/>
+ * This exception allows us to filter out exceptions that come from core GATK code, and those that
+ * are not homegrown..
+ */
+public class GATKException extends RuntimeException {
+ public GATKException(String msg) {
+ super(msg);
+ }
+
+ public GATKException(String message, Throwable throwable) {
+ super(message, throwable);
+ }
+}
+
diff --git a/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/exceptions/ReviewedGATKException.java b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/exceptions/ReviewedGATKException.java
new file mode 100644
index 0000000..56dfc69
--- /dev/null
+++ b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/exceptions/ReviewedGATKException.java
@@ -0,0 +1,42 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils.exceptions;
+
+/**
+ * A trivial extension around GATKException to mark exceptions that have been reviewed for correctness,
+ * completeness, etc. By using this exception you are saying "this is the right error message". GATKException
+ * is now just a catch all for lazy users.
+ */
+public class ReviewedGATKException extends GATKException {
+ public ReviewedGATKException(String msg) {
+ super(msg);
+ }
+
+ public ReviewedGATKException(String message, Throwable throwable) {
+ super(message, throwable);
+ }
+}
+
diff --git a/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/package-info.java b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/package-info.java
new file mode 100644
index 0000000..8a42dff
--- /dev/null
+++ b/public/gatk-utils/src/main/java/org/broadinstitute/gatk/utils/package-info.java
@@ -0,0 +1,26 @@
+/*
+* Copyright (c) 2012 The Broad Institute
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+package org.broadinstitute.gatk.utils;
\ No newline at end of file
diff --git a/public/gatk-utils/src/main/resources/org/broadinstitute/gatk/utils/pairhmm/libVectorLoglessPairHMM.so b/public/gatk-utils/src/main/resources/org/broadinstitute/gatk/utils/pairhmm/libVectorLoglessPairHMM.so
new file mode 100644
index 0000000..a27f4e6
Binary files /dev/null and b/public/gatk-utils/src/main/resources/org/broadinstitute/gatk/utils/pairhmm/libVectorLoglessPairHMM.so differ
diff --git a/public/gsalib/pom.xml b/public/gsalib/pom.xml
new file mode 100644
index 0000000..1ce5b4d
--- /dev/null
+++ b/public/gsalib/pom.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-aggregator</artifactId>
+ <version>3.3</version>
+ <relativePath>../..</relativePath>
+ </parent>
+
+ <artifactId>gsalib</artifactId>
+ <packaging>pom</packaging>
+ <name>GATK GSALib</name>
+
+ <properties>
+ <gatk.basedir>${project.basedir}/../..</gatk.basedir>
+ <gsalib.packagedir>org/broadinstitute/gatk/utils/R</gsalib.packagedir>
+ <gsalib.filename>gsalib.tar.gz</gsalib.filename>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>gsalib-assembly</id>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <phase>${gatk.generate-resources.phase}</phase>
+ <configuration>
+ <appendAssemblyId>false</appendAssemblyId>
+ <descriptors>
+ <descriptor>src/assembly/gsalib.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/public/gsalib/src/R/DESCRIPTION b/public/gsalib/src/R/DESCRIPTION
new file mode 100644
index 0000000..229204f
--- /dev/null
+++ b/public/gsalib/src/R/DESCRIPTION
@@ -0,0 +1,13 @@
+Package: gsalib
+Type: Package
+Title: Utility functions
+Version: 1.0
+Date: 2010-10-02
+Imports: gplots, ggplot2, png
+Author: Kiran Garimella
+Maintainer: Mauricio Carneiro <carneiro at broadinstitute.org>
+BugReports: http://gatkforums.broadinstitute.org
+Description: Utility functions for GATK NGS analyses
+License: MIT + file LICENSE
+LazyLoad: yes
+NeedsCompilation: no
diff --git a/public/gsalib/src/R/LICENSE b/public/gsalib/src/R/LICENSE
new file mode 100644
index 0000000..59f3937
--- /dev/null
+++ b/public/gsalib/src/R/LICENSE
@@ -0,0 +1,2 @@
+YEAR: 2012
+COPYRIGHT HOLDER: The Broad Institute
\ No newline at end of file
diff --git a/public/gsalib/src/R/NAMESPACE b/public/gsalib/src/R/NAMESPACE
new file mode 100644
index 0000000..0bfe475
--- /dev/null
+++ b/public/gsalib/src/R/NAMESPACE
@@ -0,0 +1 @@
+exportPattern("^[^\\.]")
\ No newline at end of file
diff --git a/public/gsalib/src/R/R/gsa.error.R b/public/gsalib/src/R/R/gsa.error.R
new file mode 100644
index 0000000..1c6a560
--- /dev/null
+++ b/public/gsalib/src/R/R/gsa.error.R
@@ -0,0 +1,12 @@
+gsa.error <- function(message) {
+ message("");
+ gsa.message("Error: **********");
+ gsa.message(sprintf("Error: %s", message));
+ gsa.message("Error: **********");
+ message("");
+
+ traceback();
+
+ message("");
+ stop(message, call. = FALSE);
+}
diff --git a/public/gsalib/src/R/R/gsa.getargs.R b/public/gsalib/src/R/R/gsa.getargs.R
new file mode 100644
index 0000000..94613bf
--- /dev/null
+++ b/public/gsalib/src/R/R/gsa.getargs.R
@@ -0,0 +1,116 @@
+.gsa.getargs.usage <- function(argspec, doc) {
+ cargs = commandArgs();
+
+ usage = "Usage:";
+
+ fileIndex = grep("--file=", cargs);
+ if (length(fileIndex) > 0) {
+ progname = gsub("--file=", "", cargs[fileIndex[1]]);
+
+ usage = sprintf("Usage: Rscript %s [arguments]", progname);
+
+ if (!is.na(doc)) {
+ message(sprintf("%s: %s\n", progname, doc));
+ }
+ }
+
+ message(usage);
+
+ for (argname in names(argspec)) {
+ key = argname;
+ defaultValue = 0;
+ doc = "";
+
+ if (is.list(argspec[[argname]])) {
+ defaultValue = argspec[[argname]]$value;
+ doc = argspec[[argname]]$doc;
+ }
+
+ message(sprintf(" -%-10s\t[default: %s]\t%s", key, defaultValue, doc));
+ }
+
+ message("");
+
+ stop(call. = FALSE);
+}
+
+gsa.getargs <- function(argspec, doc = NA) {
+ argsenv = new.env();
+
+ for (argname in names(argspec)) {
+ value = 0;
+ if (is.list(argspec[[argname]])) {
+ value = argspec[[argname]]$value;
+ } else {
+ value = argspec[[argname]];
+ }
+
+ assign(argname, value, envir=argsenv);
+ }
+
+ if (interactive()) {
+ for (argname in names(argspec)) {
+ value = get(argname, envir=argsenv);
+
+ if (is.na(value) | is.null(value)) {
+ if (exists("cmdargs")) {
+ assign(argname, cmdargs[[argname]], envir=argsenv);
+ } else {
+ assign(argname, readline(sprintf("Please enter a value for '%s': ", argname)), envir=argsenv);
+ }
+ } else {
+ assign(argname, value, envir=argsenv);
+ }
+ }
+ } else {
+ cargs = commandArgs(TRUE);
+
+ if (length(cargs) == 0) {
+ .gsa.getargs.usage(argspec, doc);
+ }
+
+ for (i in 1:length(cargs)) {
+ if (length(grep("^-", cargs[i], ignore.case=TRUE)) > 0) {
+ key = gsub("-", "", cargs[i]);
+ value = cargs[i+1];
+
+ if (key == "h" | key == "help") {
+ .gsa.getargs.usage(argspec, doc);
+ }
+
+ if (length(grep("^[\\d\\.e\\+\\-]+$", value, perl=TRUE, ignore.case=TRUE)) > 0) {
+ value = as.numeric(value);
+ }
+
+ assign(key, value, envir=argsenv);
+ }
+ }
+ }
+
+ args = as.list(argsenv);
+
+ isMissingArgs = 0;
+ missingArgs = c();
+
+ for (arg in names(argspec)) {
+ if (is.na(args[[arg]]) | is.null(args[[arg]])) {
+ gsa.warn(sprintf("Value for required argument '-%s' was not specified", arg));
+
+ isMissingArgs = 1;
+ missingArgs = c(missingArgs, arg);
+ }
+ }
+
+ if (isMissingArgs) {
+ gsa.error(
+ paste(
+ "Missing required arguments: -",
+ paste(missingArgs, collapse=" -"),
+ ". Specify -h or -help to this script for a list of available arguments.",
+ sep=""
+ )
+ );
+ }
+
+ args;
+}
diff --git a/public/gsalib/src/R/R/gsa.message.R b/public/gsalib/src/R/R/gsa.message.R
new file mode 100644
index 0000000..a2b909d
--- /dev/null
+++ b/public/gsalib/src/R/R/gsa.message.R
@@ -0,0 +1,3 @@
+gsa.message <- function(message) {
+ message(sprintf("[gsalib] %s", message));
+}
diff --git a/public/gsalib/src/R/R/gsa.plot.venn.R b/public/gsalib/src/R/R/gsa.plot.venn.R
new file mode 100644
index 0000000..b1353cc
--- /dev/null
+++ b/public/gsalib/src/R/R/gsa.plot.venn.R
@@ -0,0 +1,50 @@
+gsa.plot.venn <-
+function(a, b, c=0, a_and_b, a_and_c=0, b_and_c=0,
+ col=c("#FF6342", "#63C6DE", "#ADDE63"),
+ pos=c(0.20, 0.20, 0.80, 0.82),
+ debug=0
+ ) {
+ library(png);
+ library(graphics);
+
+ # Set up properties
+ for (i in 1:length(col)) {
+ rgbcol = col2rgb(col[i]);
+ col[i] = sprintf("%02X%02X%02X", rgbcol[1], rgbcol[2], rgbcol[3]);
+ }
+
+ chco = paste(col[1], col[2], col[3], sep=",");
+ chd = paste(a, b, c, a_and_b, a_and_c, b_and_c, sep=",");
+
+ props = c(
+ 'cht=v',
+ 'chs=525x525',
+ 'chds=0,10000000000',
+ paste('chco=', chco, sep=""),
+ paste('chd=t:', chd, sep="")
+ );
+ proplist = paste(props[1], props[2], props[3], props[4], props[5], sep='&');
+
+ # Get the venn diagram (as a temporary file)
+ filename = tempfile("venn");
+ cmd = paste("wget -O ", filename, " 'http://chart.apis.google.com/chart?", proplist, "' > /dev/null 2>&1", sep="");
+
+ if (debug == 1) {
+ print(cmd);
+ }
+ system(cmd);
+
+ # Render the temp png file into a plotting frame
+ a = readPNG(filename);
+
+ plot(0, 0, type="n", xaxt="n", yaxt="n", bty="n", xlim=c(0, 1), ylim=c(0, 1), xlab="", ylab="");
+ if (c == 0 || a >= b) {
+ rasterImage(a, pos[1], pos[2], pos[3], pos[4]);
+ } else {
+ rasterImage(a, 0.37+pos[1], 0.37+pos[2], 0.37+pos[3], 0.37+pos[4], angle=180);
+ }
+
+ # Clean up!
+ unlink(filename);
+}
+
diff --git a/public/gsalib/src/R/R/gsa.read.eval.R b/public/gsalib/src/R/R/gsa.read.eval.R
new file mode 100644
index 0000000..f1d4909
--- /dev/null
+++ b/public/gsalib/src/R/R/gsa.read.eval.R
@@ -0,0 +1,83 @@
+.gsa.attemptToLoadFile <- function(filename) {
+ file = NA;
+
+ if (file.exists(filename) & file.info(filename)$size > 500) {
+ file = read.csv(filename, header=TRUE, comment.char="#");
+ }
+
+ file;
+}
+
+gsa.read.eval <-
+function(evalRoot) {
+ fileAlleleCountStats = paste(evalRoot, ".AlleleCountStats.csv", sep="");
+ fileCompOverlap = paste(evalRoot, ".Comp_Overlap.csv", sep="");
+ fileCountVariants = paste(evalRoot, ".Count_Variants.csv", sep="");
+ fileGenotypeConcordance = paste(evalRoot, ".Genotype_Concordance.csv", sep="");
+ fileMetricsByAc = paste(evalRoot, ".MetricsByAc.csv", sep="");
+ fileMetricsBySample = paste(evalRoot, ".MetricsBySample.csv", sep="");
+ fileQuality_Metrics_by_allele_count = paste(evalRoot, ".Quality_Metrics_by_allele_count.csv", sep="");
+ fileQualityScoreHistogram = paste(evalRoot, ".QualityScoreHistogram.csv", sep="");
+ fileSampleStatistics = paste(evalRoot, ".Sample_Statistics.csv", sep="");
+ fileSampleSummaryStatistics = paste(evalRoot, ".Sample_Summary_Statistics.csv", sep="");
+ fileSimpleMetricsBySample = paste(evalRoot, ".SimpleMetricsBySample.csv", sep="");
+ fileTi_slash_Tv_Variant_Evaluator = paste(evalRoot, ".Ti_slash_Tv_Variant_Evaluator.csv", sep="");
+ fileTiTvStats = paste(evalRoot, ".TiTvStats.csv", sep="");
+ fileVariant_Quality_Score = paste(evalRoot, ".Variant_Quality_Score.csv", sep="");
+
+ eval = list(
+ AlleleCountStats = NA,
+ CompOverlap = NA,
+ CountVariants = NA,
+ GenotypeConcordance = NA,
+ MetricsByAc = NA,
+ MetricsBySample = NA,
+ Quality_Metrics_by_allele_count = NA,
+ QualityScoreHistogram = NA,
+ SampleStatistics = NA,
+ SampleSummaryStatistics = NA,
+ SimpleMetricsBySample = NA,
+ TiTv = NA,
+ TiTvStats = NA,
+ Variant_Quality_Score = NA,
+
+ CallsetNames = c(),
+ CallsetOnlyNames = c(),
+ CallsetFilteredNames = c()
+ );
+
+ eval$AlleleCountStats = .gsa.attemptToLoadFile(fileAlleleCountStats);
+ eval$CompOverlap = .gsa.attemptToLoadFile(fileCompOverlap);
+ eval$CountVariants = .gsa.attemptToLoadFile(fileCountVariants);
+ eval$GenotypeConcordance = .gsa.attemptToLoadFile(fileGenotypeConcordance);
+ eval$MetricsByAc = .gsa.attemptToLoadFile(fileMetricsByAc);
+ eval$MetricsBySample = .gsa.attemptToLoadFile(fileMetricsBySample);
+ eval$Quality_Metrics_by_allele_count = .gsa.attemptToLoadFile(fileQuality_Metrics_by_allele_count);
+ eval$QualityScoreHistogram = .gsa.attemptToLoadFile(fileQualityScoreHistogram);
+ eval$SampleStatistics = .gsa.attemptToLoadFile(fileSampleStatistics);
+ eval$SampleSummaryStatistics = .gsa.attemptToLoadFile(fileSampleSummaryStatistics);
+ eval$SimpleMetricsBySample = .gsa.attemptToLoadFile(fileSimpleMetricsBySample);
+ eval$TiTv = .gsa.attemptToLoadFile(fileTi_slash_Tv_Variant_Evaluator);
+ eval$TiTvStats = .gsa.attemptToLoadFile(fileTiTvStats);
+ eval$Variant_Quality_Score = .gsa.attemptToLoadFile(fileVariant_Quality_Score);
+
+ uniqueJexlExpressions = unique(eval$TiTv$jexl_expression);
+ eval$CallsetOnlyNames = as.vector(uniqueJexlExpressions[grep("FilteredIn|Intersection|none", uniqueJexlExpressions, invert=TRUE, ignore.case=TRUE)]);
+ eval$CallsetNames = as.vector(gsub("-only", "", eval$CallsetOnlyNames));
+ eval$CallsetFilteredNames = as.vector(c(
+ paste(gsub("^(\\w)", "In\\U\\1", eval$CallsetNames[1], perl=TRUE), "-Filtered", gsub("^(\\w)", "In\\U\\1", eval$CallsetNames[2], perl=TRUE), sep=""),
+ paste(gsub("^(\\w)", "In\\U\\1", eval$CallsetNames[2], perl=TRUE), "-Filtered", gsub("^(\\w)", "In\\U\\1", eval$CallsetNames[1], perl=TRUE), sep=""))
+ );
+
+ if (!(eval$CallsetFilteredNames[1] %in% unique(eval$TiTv$jexl_expression))) {
+ eval$CallsetFilteredNames[1] = paste("In", eval$CallsetNames[1], "-FilteredIn", eval$CallsetNames[2], sep="");
+ }
+
+ if (!(eval$CallsetFilteredNames[2] %in% unique(eval$TiTv$jexl_expression))) {
+ eval$CallsetFilteredNames[2] = paste("In", eval$CallsetNames[2], "-FilteredIn", eval$CallsetNames[1], sep="");
+ #eval$CallsetFilteredNames[2] = paste(gsub("^(\\w)", "In", eval$CallsetNames[2], perl=TRUE), "-Filtered", gsub("^(\\w)", "In", eval$CallsetNames[1], perl=TRUE), sep="");
+ }
+
+ eval;
+}
+
diff --git a/public/gsalib/src/R/R/gsa.read.gatkreport.R b/public/gsalib/src/R/R/gsa.read.gatkreport.R
new file mode 100644
index 0000000..eba94c0
--- /dev/null
+++ b/public/gsalib/src/R/R/gsa.read.gatkreport.R
@@ -0,0 +1,196 @@
+# Load a table into the specified environment. Make sure that each new table gets a unique name (this allows one to cat a bunch of tables with the same name together and load them into R without each table overwriting the last.
+.gsa.assignGATKTableToEnvironment <- function(tableName, tableHeader, tableRows, tableEnv) {
+ d = data.frame(tableRows, row.names=NULL, stringsAsFactors=FALSE);
+ colnames(d) = tableHeader;
+
+ for (i in 1:ncol(d)) {
+ # use the general type.convert infrastructure of read.table to convert column data to R types
+ v = type.convert(d[,i])
+ d[,i] = v;
+ }
+
+ usedNames = ls(envir=tableEnv, pattern=tableName);
+
+ if (length(usedNames) > 0) {
+ tableName = paste(tableName, ".", length(usedNames), sep="");
+ }
+
+ assign(tableName, d, envir=tableEnv);
+}
+
+# Read a fixed width line of text into a list.
+.gsa.splitFixedWidth <- function(line, columnStarts) {
+ splitStartStop <- function(x) {
+ x = substring(x, starts, stops);
+ x = gsub("^[[:space:]]+|[[:space:]]+$", "", x);
+ x;
+ }
+
+ starts = c(1, columnStarts);
+ stops = c(columnStarts - 1, nchar(line));
+
+ sapply(line, splitStartStop)[,1];
+}
+
+# Old implementaton for v0.*
+gsa.read.gatkreportv0 <- function(lines) {
+
+ tableEnv = new.env();
+
+ tableName = NA;
+ tableHeader = c();
+ tableRows = c();
+ version = NA;
+
+ for (line in lines) {
+ if (length(grep("^##:GATKReport.v", line, ignore.case=TRUE)) > 0) {
+ headerFields = unlist(strsplit(line, "[[:space:]]+"));
+
+ if (!is.na(tableName)) {
+ .gsa.assignGATKTableToEnvironment(tableName, tableHeader, tableRows, tableEnv);
+ }
+
+ tableName = headerFields[2];
+ tableHeader = c();
+ tableRows = c();
+
+ # For differences in versions see
+ # $STING_HOME/public/java/src/org/broadinstitute/sting/gatk/report/GATKReportVersion.java
+ if (length(grep("^##:GATKReport.v0.1[[:space:]]+", line, ignore.case=TRUE)) > 0) {
+ version = "v0.1";
+
+ } else if (length(grep("^##:GATKReport.v0.2[[:space:]]+", line, ignore.case=TRUE)) > 0) {
+ version = "v0.2";
+ columnStarts = c();
+
+ }
+
+ } else if (length(grep("^[[:space:]]*$", line)) > 0 | length(grep("^[[:space:]]*#", line)) > 0) {
+ # do nothing
+ } else if (!is.na(tableName)) {
+
+ if (version == "v0.1") {
+ row = unlist(strsplit(line, "[[:space:]]+"));
+
+ } else if (version == "v0.2") {
+ if (length(tableHeader) == 0) {
+ headerChars = unlist(strsplit(line, ""));
+ # Find the first position of non space characters, excluding the first character
+ columnStarts = intersect(grep("[[:space:]]", headerChars, invert=TRUE), grep("[[:space:]]", headerChars) + 1);
+ }
+
+ row = .gsa.splitFixedWidth(line, columnStarts);
+ }
+
+ if (length(tableHeader) == 0) {
+ tableHeader = row;
+ } else {
+ tableRows = rbind(tableRows, row);
+ }
+ }
+ }
+
+ if (!is.na(tableName)) {
+ .gsa.assignGATKTableToEnvironment(tableName, tableHeader, tableRows, tableEnv);
+ }
+
+ gatkreport = as.list(tableEnv, all.names=TRUE);
+}
+
+# Load all GATKReport v1 tables from file
+gsa.read.gatkreportv1 <- function(lines) {
+ #print("loading with optimized v1 reader")
+ nLines = length(lines)
+ tableEnv = new.env();
+
+ tableName = NA;
+ tableHeader = c();
+ tableRows = NULL;
+ version = "";
+ rowCount = 0
+ headerRowCount = -1;
+
+ finishTable <- function() {
+ if ( rowCount == 1 )
+ # good I hate R. Work around to avoid collapsing into an unstructured vector when
+ # there's only 1 row
+ sub <- t(as.matrix(tableRows[1:rowCount,]))
+ else
+ sub <- tableRows[1:rowCount,]
+ .gsa.assignGATKTableToEnvironment(tableName, tableHeader, sub, tableEnv);
+ }
+
+ for (line in lines) {
+
+ if (length(grep("^#:GATKReport.v1", line, ignore.case=TRUE)) > 0) {
+ version = "v1.0";
+ headerRowCount = 0;
+ }
+
+ if ( (headerRowCount %% 2 == 1) && (version == "v1.0") ) {
+ #print("Trying to start a table with line:");
+ #print(line);
+
+ #Get table header
+ headerFields = unlist(strsplit(line, ":"));
+
+ if (!is.na(tableName)) {
+ finishTable()
+ }
+
+ tableName = headerFields[3];
+ tableHeader = c();
+ tableRows = NULL
+ rowCount = 0
+
+ columnStarts = c();
+ }
+
+ if (length(grep("^#:GATKTable", line, ignore.case=TRUE)) > 0) {
+ headerRowCount = headerRowCount+1;
+ #print("Header Row count is at:")
+ #print(headerRowCount);
+ } else if (!is.na(tableName)) {
+ if ( version == "v1.0") {
+ if (length(tableHeader) == 0) {
+ headerChars = unlist(strsplit(line, ""));
+ # Find the first position of non space characters, excluding the first character
+ columnStarts = intersect(grep("[[:space:]]", headerChars, invert=TRUE), grep("[[:space:]]", headerChars) + 1);
+ tableRows = matrix(nrow=nLines, ncol=length(columnStarts)+1);
+ }
+
+ row = .gsa.splitFixedWidth(line, columnStarts);
+ }
+
+ if (length(tableHeader) == 0) {
+ tableHeader = row;
+ } else if ( nchar(line) > 0 ) {
+ rowCount = rowCount + 1
+ tableRows[rowCount,] <- row
+ }
+ }
+ }
+
+ if (!is.na(tableName)) {
+ finishTable()
+ }
+
+ gatkreport = as.list(tableEnv, all.names=TRUE);
+}
+
+# Load all GATKReport tables from a file
+gsa.read.gatkreport <- function(filename) {
+ con = file(filename, "r", blocking = TRUE);
+ lines = readLines(con);
+ close(con);
+
+ # get first line
+ line = lines[1];
+
+ if (length(grep("^#:GATKReport.v1", line, ignore.case=TRUE)) > 0) {
+ gsa.read.gatkreportv1(lines)
+ }
+ else if (length(grep("^##:GATKReport.v0", line, ignore.case=TRUE)) > 0) {
+ gsa.read.gatkreportv0(lines)
+ }
+}
diff --git a/public/gsalib/src/R/R/gsa.read.squidmetrics.R b/public/gsalib/src/R/R/gsa.read.squidmetrics.R
new file mode 100644
index 0000000..39fa1ad
--- /dev/null
+++ b/public/gsalib/src/R/R/gsa.read.squidmetrics.R
@@ -0,0 +1,28 @@
+gsa.read.squidmetrics = function(project, bylane = FALSE) {
+ suppressMessages(library(ROracle));
+
+ drv = dbDriver("Oracle");
+ con = dbConnect(drv, "REPORTING/REPORTING at ora01:1521/SEQPROD");
+
+ if (bylane) {
+ statement = paste("SELECT * FROM ILLUMINA_PICARD_METRICS WHERE \"Project\" = '", project, "'", sep="");
+ print(statement);
+
+ rs = dbSendQuery(con, statement = statement);
+ d = fetch(rs, n=-1);
+ dbHasCompleted(rs);
+ dbClearResult(rs);
+ } else {
+ statement = paste("SELECT * FROM ILLUMINA_SAMPLE_STATUS_AGG WHERE \"Project\" = '", project, "'", sep="");
+ print(statement);
+
+ rs = dbSendQuery(con, statement = statement);
+ d = fetch(rs, n=-1);
+ dbHasCompleted(rs);
+ dbClearResult(rs);
+ }
+
+ oraCloseDriver(drv);
+
+ subset(d, Project == project);
+}
diff --git a/public/gsalib/src/R/R/gsa.read.vcf.R b/public/gsalib/src/R/R/gsa.read.vcf.R
new file mode 100644
index 0000000..5beb645
--- /dev/null
+++ b/public/gsalib/src/R/R/gsa.read.vcf.R
@@ -0,0 +1,23 @@
+gsa.read.vcf <- function(vcffile, skip=0, nrows=-1, expandGenotypeFields = FALSE) {
+ headers = readLines(vcffile, n=100);
+ headerline = headers[grep("#CHROM", headers)];
+ header = unlist(strsplit(gsub("#", "", headerline), "\t"))
+
+ d = read.table(vcffile, header=FALSE, skip=skip, nrows=nrows, stringsAsFactors=FALSE);
+ colnames(d) = header;
+
+ if (expandGenotypeFields) {
+ columns = ncol(d);
+
+ offset = columns + 1;
+ for (sampleIndex in 10:columns) {
+ gt = unlist(lapply(strsplit(d[,sampleIndex], ":"), function(x) x[1]));
+ d[,offset] = gt;
+ colnames(d)[offset] = sprintf("%s.GT", colnames(d)[sampleIndex]);
+
+ offset = offset + 1;
+ }
+ }
+
+ return(d);
+}
diff --git a/public/gsalib/src/R/R/gsa.variantqc.utils.R b/public/gsalib/src/R/R/gsa.variantqc.utils.R
new file mode 100644
index 0000000..507b336
--- /dev/null
+++ b/public/gsalib/src/R/R/gsa.variantqc.utils.R
@@ -0,0 +1,246 @@
+library(gplots)
+library(ggplot2)
+library(tools)
+
+# -------------------------------------------------------
+# Utilities for displaying multiple plots per page
+# -------------------------------------------------------
+
+distributeGraphRows <- function(graphs, heights = c()) {
+ # Viewport layout 2 graphs top to bottom with given relative heights
+ #
+ #
+ if (length(heights) == 0) {
+ heights <- rep.int(1, length(graphs))
+ }
+ heights <- heights[!is.na(graphs)]
+ graphs <- graphs[!is.na(graphs)]
+ numGraphs <- length(graphs)
+ Layout <- grid.layout(nrow = numGraphs, ncol = 1, heights=heights)
+ grid.newpage()
+ pushViewport(viewport(layout = Layout))
+ subplot <- function(x) viewport(layout.pos.row = x, layout.pos.col = 1)
+ for (i in 1:numGraphs) {
+ print(graphs[[i]], vp = subplot(i))
+ }
+}
+
+distributeLogGraph <- function(graph, xName) {
+ continuousGraph <- graph + scale_x_continuous(xName)
+ logGraph <- graph + scale_x_log10(xName) + ggtitle("")
+ distributeGraphRows(list(continuousGraph, logGraph))
+}
+
+distributePerSampleGraph <- function(perSampleGraph, distGraph, ratio=c(2,1)) {
+ distributeGraphRows(list(perSampleGraph, distGraph), ratio)
+}
+
+removeExtraStrats <- function(variantEvalDataFrame, moreToRemove=c()) {
+ # Remove the standard extra stratification columns FunctionalClass, Novelty, and others in moreToRemove from the variantEvalDataFrame
+ #
+ # Only keeps the column marked with "all" for each removed column
+ #
+ for ( toRemove in c("FunctionalClass", "Novelty", moreToRemove) ) {
+ if (toRemove %in% colnames(variantEvalDataFrame)) {
+ variantEvalDataFrame <- variantEvalDataFrame[variantEvalDataFrame[[toRemove]] == "all",]
+ }
+ }
+ variantEvalDataFrame
+}
+
+openPDF <- function(outputPDF) {
+ # Open the outputPDF file with standard dimensions, if outputPDF is not NA
+ if ( ! is.na(outputPDF) ) {
+ pdf(outputPDF, height=8.5, width=11)
+ }
+}
+
+closePDF <- function(outputPDF) {
+ # close the outputPDF file if not NA, and try to compact the PDF if possible
+ if ( ! is.na(outputPDF) ) {
+ dev.off()
+ if (exists("compactPDF")) {
+ print("compacting PDF")
+ compactPDF(outputPDF)
+ }
+ }
+}
+
+makeRatioDataFrame <- function(ACs, num, denom, widths = NULL) {
+ if ( is.null(widths) ) widths <- rep(1, length(ACs))
+
+ value = NULL
+ titv <- data.frame(AC=ACs, width = widths, num=num, denom = denom, ratio = num / denom)
+}
+
+.reduceACs <- function(binWidthForAC, ACs) {
+ # computes data structures necessary to reduce the full range of ACs
+ #
+ # binWidthForAC returns the number of upcoming bins that should be merged into
+ # that AC bin. ACs is a vector of all AC values from 0 to 2N that should be
+ # merged together
+ #
+ # Returns a list containing the reduced ACs starts, their corresponding widths,
+ # and a map from original ACs to their new ones (1 -> 1, 2 -> 2, 3 -> 2, etc)
+ maxAC <- max(ACs)
+ newACs <- c()
+ widths <- c()
+ newACMap <- c()
+ ac <- 0
+ while ( ac < maxAC ) {
+ newACs <- c(newACs, ac)
+ width <- binWidthForAC(ac)
+ widths <- c(widths, width)
+ newACMap <- c(newACMap, rep(ac, width))
+ ac <- ac + width
+ }
+ list(ACs = newACs, widths=widths, newACMap = newACMap)
+}
+
+# geometricACs <- function(k, ACs) {
+# nBins <- round(k * log10(max(ACs)))
+#
+# binWidthForAC <- function(ac) {
+# max(ceiling(ac / nBins), 1)
+# }
+#
+# return(reduceACs(binWidthForAC, ACs))
+# }
+
+reduce.AC.on.LogLinear.intervals <- function(scaleFactor, ACs) {
+ # map the full range of AC values onto a log linear scale
+ #
+ # Reduce the full AC range onto one where the width of each new AC increases at a rate of
+ # 10^scaleFactor in size with growing AC values. This is primarily useful for accurately
+ # computing ratios or other quantities by AC that aren't well determined when the AC
+ # values are very large
+ #
+ # Returns a list containing the reduced ACs starts, their corresponding widths,
+ # and a map from original ACs to their new ones (1 -> 1, 2 -> 2, 3 -> 2, etc)
+ maxAC <- max(ACs)
+ afs <- ACs / maxAC
+ breaks <- 10^(seq(-4, -1, scaleFactor))
+ widths <- c()
+ lastBreak <- 1
+ for ( i in length(breaks):1 ) {
+ b <- breaks[i]
+ width <- sum(afs < lastBreak & afs >= b)
+ widths <- c(widths, width)
+ lastBreak <- b
+ }
+ widths <- rev(widths)
+
+ binWidthForAC <- function(ac) {
+ af <- ac / maxAC
+ value = 1
+ for ( i in length(breaks):1 )
+ if ( af >= breaks[i] ) {
+ value = widths[i]
+ break
+ }
+
+ return(value)
+ }
+
+ return(.reduceACs(binWidthForAC, ACs))
+}
+
+.remapACs <- function(remapper, k, df) {
+ newACs <- remapper(k, df$AC)
+
+ n = length(newACs$ACs)
+ num = rep(0, n)
+ denom = rep(0, n)
+ for ( i in 1:dim(df)[1] ) {
+ rowI = df$AC == i
+ row = df[rowI,]
+ newAC = newACs$newACMap[row$AC]
+ newRowI = newACs$ACs == newAC
+ num[newRowI] = num[newRowI] + df$num[rowI]
+ denom[newRowI] = denom[newRowI] + df$denom[rowI]
+ }
+
+ newdf <- makeRatioDataFrame(newACs$ACs, num, denom, newACs$widths )
+ newdf
+}
+
+compute.ratio.on.LogLinear.AC.intervals <- function(ACs, num, denom, scaleFactor = 0.1) {
+ df = makeRatioDataFrame(ACs, num, denom, 1)
+ return(.remapACs(reduce.AC.on.LogLinear.intervals, scaleFactor, df))
+}
+
+plotVariantQC <- function(metrics, measures, requestedStrat = "Sample",
+ fixHistogramX=F, anotherStrat = NULL, nObsField = "n_indels",
+ onSamePage=F, facetVariableOnXPerSample = F, facetVariableOnXForDist = T,
+ moreTitle="", note = NULL) {
+ metrics$strat = metrics[[requestedStrat]]
+
+ otherFacet = "."
+ id.vars = c("strat", "nobs")
+ metrics$nobs <- metrics[[nObsField]]
+
+ # keep track of the other strat and it's implied facet value
+ if (! is.null(anotherStrat)) {
+ id.vars = c(id.vars, anotherStrat)
+ otherFacet = anotherStrat
+ }
+
+ molten <- melt(metrics, id.vars=id.vars, measure.vars=c(measures))
+ perSampleGraph <- ggplot(data=molten, aes(x=strat, y=value, group=variable, color=variable, fill=variable))
+
+ # create the title
+ titleText=paste(paste(paste(measures, collapse=", "), "by", requestedStrat), moreTitle)
+ if ( !is.null(note) ) {
+ titleText=paste(titleText, note, sep="\n")
+ }
+ paste(titleText)
+ title <- ggtitle(titleText)
+
+ determineFacet <- function(onX) {
+ if ( onX ) {
+ paste(otherFacet, "~ variable")
+ } else {
+ paste("variable ~", otherFacet)
+ }
+ }
+
+ sampleFacet = determineFacet(facetVariableOnXPerSample)
+ distFacet = determineFacet(facetVariableOnXForDist)
+
+ if ( requestedStrat == "Sample" ) {
+ perSampleGraph <- perSampleGraph + geom_text(aes(label=strat), size=1.5) + geom_blank() # don't display a scale
+ perSampleGraph <- perSampleGraph + scale_x_discrete("Sample (ordered by nSNPs)")
+ } else { # by AlleleCount
+ perSampleGraph <- perSampleGraph + geom_point(aes(size=log10(nobs))) #+ geom_smooth(aes(weight=log10(nobs)))
+ perSampleGraph <- perSampleGraph + scale_x_log10("AlleleCount")
+ }
+ perSampleGraph <- perSampleGraph + ylab("Variable value") + title
+ perSampleGraph <- perSampleGraph + facet_grid(sampleFacet, scales="free")
+
+ nValues = length(unique(molten$value))
+ if (nValues > 2) {
+ if ( requestedStrat == "Sample" ) {
+ distGraph <- ggplot(data=molten, aes(x=value, group=variable, fill=variable))
+ } else {
+ distGraph <- ggplot(data=molten, aes(x=value, group=variable, fill=variable, weight=nobs))
+ }
+ distGraph <- distGraph + geom_histogram(aes(y=..ndensity..))
+ distGraph <- distGraph + geom_density(alpha=0.5, aes(y=..scaled..))
+ distGraph <- distGraph + geom_rug(aes(y=NULL, color=variable, position="jitter"))
+ scale = "free"
+ if ( fixHistogramX ) scale = "fixed"
+ distGraph <- distGraph + facet_grid(distFacet, scales=scale)
+ distGraph <- distGraph + ylab("Relative frequency")
+ distGraph <- distGraph + xlab("Variable value (see facet for variable by color)")
+ distGraph <- distGraph + theme(axis.text.x=element_text(angle=-45)) # , legend.position="none")
+ } else {
+ distGraph <- NA
+ }
+
+ if ( onSamePage ) {
+ suppressMessages(distributePerSampleGraph(perSampleGraph, distGraph))
+ } else {
+ suppressMessages(print(perSampleGraph))
+ suppressMessages(print(distGraph + title))
+ }
+}
diff --git a/public/gsalib/src/R/R/gsa.warn.R b/public/gsalib/src/R/R/gsa.warn.R
new file mode 100644
index 0000000..7ee08ce
--- /dev/null
+++ b/public/gsalib/src/R/R/gsa.warn.R
@@ -0,0 +1,3 @@
+gsa.warn <- function(message) {
+ gsa.message(sprintf("Warning: %s", message));
+}
diff --git a/public/gsalib/src/R/Read-and-delete-me b/public/gsalib/src/R/Read-and-delete-me
new file mode 100644
index 0000000..d04323a
--- /dev/null
+++ b/public/gsalib/src/R/Read-and-delete-me
@@ -0,0 +1,9 @@
+* Edit the help file skeletons in 'man', possibly combining help files
+ for multiple functions.
+* Put any C/C++/Fortran code in 'src'.
+* If you have compiled code, add a .First.lib() function in 'R' to load
+ the shared library.
+* Run R CMD build to build the package tarball.
+* Run R CMD check to check the package tarball.
+
+Read "Writing R Extensions" for more information.
diff --git a/public/gsalib/src/R/man/gsa.error.Rd b/public/gsalib/src/R/man/gsa.error.Rd
new file mode 100644
index 0000000..df7c0cb
--- /dev/null
+++ b/public/gsalib/src/R/man/gsa.error.Rd
@@ -0,0 +1,49 @@
+\name{gsa.error}
+\alias{gsa.error}
+\title{
+GSA error
+}
+\description{
+Write an error message to standard out with the prefix '[gsalib] Error:', print a traceback, and exit.
+}
+\usage{
+gsa.error(message)
+}
+%- maybe also 'usage' for other objects documented here.
+\arguments{
+ \item{message}{
+The error message to write.
+}
+}
+\details{
+%% ~~ If necessary, more details than the description above ~~
+}
+\value{
+%% ~Describe the value returned
+%% If it is a LIST, use
+%% \item{comp1 }{Description of 'comp1'}
+%% \item{comp2 }{Description of 'comp2'}
+%% ...
+}
+\references{
+%% ~put references to the literature/web site here ~
+}
+\author{
+Kiran Garimella
+}
+\note{
+%% ~~further notes~~
+}
+
+%% ~Make other sections like Warning with \section{Warning }{....} ~
+
+\seealso{
+%% ~~objects to See Also as \code{\link{help}}, ~~~
+}
+\examples{
+gsa.error("This is a message");
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{ ~kwd1 }
+\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line
diff --git a/public/gsalib/src/R/man/gsa.getargs.Rd b/public/gsalib/src/R/man/gsa.getargs.Rd
new file mode 100644
index 0000000..27aa1b0
--- /dev/null
+++ b/public/gsalib/src/R/man/gsa.getargs.Rd
@@ -0,0 +1,57 @@
+\name{gsa.getargs}
+\alias{gsa.getargs}
+\title{
+Get script arguments
+}
+\description{
+Get script arguments given a list object specifying arguments and documentation. Can be used in command-line or interactive mode. This is helpful when developing scripts in interactive mode that will eventually become command-line programs. If no arguments are specified or help is requested in command-line mode, the script will print out a usage statement with available arguments and exit.
+}
+\usage{
+gsa.getargs(argspec, doc = NA)
+}
+\arguments{
+ \item{argspec}{
+A list object. Each key is an argument name. The value is another list object with a 'value' and 'doc' keys. For example:
+\preformatted{argspec = list(
+ arg1 = list(value=10, doc="Info for optional arg1"),
+ arg2 = list(value=NA, doc="Info for required arg2")
+);
+}
+
+If the value provided is NA, the argument is considered required and must be specified when the script is invoked. For command-line mode, this means the argument must be specified on the command-line. In interactive mode, there are two ways of specifying these arguments. First, if a properly formatted list argument called 'cmdargs' is present in the current environment (i.e. the object returned by gsa.getargs() from a previous invocation), the value is taken from this object. Otherwi [...]
+}
+
+ \item{doc}{
+An optional string succinctly documenting the purpose of the script.
+}
+}
+\details{
+Interactive scripts typically make use of hardcoded filepaths and parameter settings. This makes testing easy, but generalization to non-interactive mode more difficult. This utility provides a mechanism for writing scripts that work properly in both interactive and command-line modes.
+
+To use this method, specify a list with key-value pairs representing the arguments as specified above. In command-line mode, if no arguments are specified or the user specifies '-h' or '-help' anywhere on the command string, a help message indicating available arguments, their default values, and some documentation about the argument are provided.
+}
+\value{
+Returns a list with keys matching the argspec and values representing the specified arguments.
+
+\item{arg1 }{Value for argument 1}
+\item{arg2 }{Value for argument 2}
+...etc.
+}
+\references{
+%% ~put references to the literature/web site here ~
+}
+\author{
+Kiran Garimella
+}
+\examples{
+argspec = list(
+ file = list(value="/my/test.vcf", doc="VCF file"),
+ verbose = list(value=0, doc="If 1, set verbose mode"),
+ test2 = list(value=2.3e9, doc="Another argument that does stuff")
+);
+
+cmdargs = gsa.getargs(argspec, doc="My test program");
+
+print(cmdargs$file); # will print '[1] "/my/test.vcf"'
+}
+\keyword{ ~kwd1 }
diff --git a/public/gsalib/src/R/man/gsa.message.Rd b/public/gsalib/src/R/man/gsa.message.Rd
new file mode 100644
index 0000000..9752de8
--- /dev/null
+++ b/public/gsalib/src/R/man/gsa.message.Rd
@@ -0,0 +1,44 @@
+\name{gsa.message}
+\alias{gsa.message}
+\title{
+GSA message
+}
+\description{
+Write a message to standard out with the prefix '[gsalib]'.
+}
+\usage{
+gsa.message(message)
+}
+\arguments{
+ \item{message}{
+The message to write.
+}
+}
+\details{
+%% ~~ If necessary, more details than the description above ~~
+}
+\value{
+%% ~Describe the value returned
+%% If it is a LIST, use
+%% \item{comp1 }{Description of 'comp1'}
+%% \item{comp2 }{Description of 'comp2'}
+%% ...
+}
+\references{
+%% ~put references to the literature/web site here ~
+}
+\author{
+Kiran Garimella
+}
+\note{
+%% ~~further notes~~
+}
+
+\seealso{
+%% ~~objects to See Also as \code{\link{help}}, ~~~
+}
+\examples{
+## Write message to stdout
+gsa.message("This is a message");
+}
+\keyword{ ~kwd1 }
diff --git a/public/gsalib/src/R/man/gsa.plot.venn.Rd b/public/gsalib/src/R/man/gsa.plot.venn.Rd
new file mode 100644
index 0000000..bf4feb5
--- /dev/null
+++ b/public/gsalib/src/R/man/gsa.plot.venn.Rd
@@ -0,0 +1,75 @@
+\name{gsa.plot.venn}
+\alias{gsa.plot.venn}
+\title{
+Plot a proportional venn diagram
+}
+\description{
+Plot a proportional venn diagram (two or three-way venns allowed)
+}
+\usage{
+gsa.plot.venn(a, b, c = 0, a_and_b, a_and_c = 0, b_and_c = 0, col = c("#FF6342", "#63C6DE", "#ADDE63"), pos = c(0.2, 0.2, 0.8, 0.82), debug = 0)
+}
+\arguments{
+ \item{a}{
+size of 'a' circle
+}
+ \item{b}{
+size of 'b' circle
+}
+ \item{c}{
+size of 'c' circle
+}
+ \item{a_and_b}{
+size of a and b overlap
+}
+ \item{a_and_c}{
+size of a and c overlap
+}
+ \item{b_and_c}{
+size of b and c overlap
+}
+ \item{col}{
+vector of colors for each venn piece
+}
+ \item{pos}{
+vector of positional elements
+}
+ \item{debug}{
+if 1, set debug mode and print useful information
+}
+}
+\details{
+Plots a two-way or three-way proportional Venn diagram. Internally, this method uses the Google Chart API to generate the diagram, then renders it into the plot window where it can be annotated in interesting ways.
+}
+\value{
+%% ~Describe the value returned
+%% If it is a LIST, use
+%% \item{comp1 }{Description of 'comp1'}
+%% \item{comp2 }{Description of 'comp2'}
+%% ...
+}
+\references{
+}
+\author{
+Kiran Garimella
+}
+\note{
+%% ~~further notes~~
+}
+
+%% ~Make other sections like Warning with \section{Warning }{....} ~
+
+\seealso{
+%% ~~objects to See Also as \code{\link{help}}, ~~~
+}
+\examples{
+## Plot a two-way Venn diagram
+gsa.plot.venn(1000, 750, 0, 400);
+
+## Plot a three-way Venn diagram
+gsa.plot.venn(1000, 750, 900, 400, 650, 500);
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{ ~kwd1 }
+\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line
diff --git a/public/gsalib/src/R/man/gsa.read.eval.Rd b/public/gsalib/src/R/man/gsa.read.eval.Rd
new file mode 100644
index 0000000..0e2baba
--- /dev/null
+++ b/public/gsalib/src/R/man/gsa.read.eval.Rd
@@ -0,0 +1,111 @@
+\name{gsa.read.eval}
+\alias{gsa.read.eval}
+\title{
+Read a VariantEval file
+}
+\description{
+Read a VariantEval file that's output in R format.
+}
+\usage{
+gsa.read.eval(evalRoot)
+}
+%- maybe also 'usage' for other objects documented here.
+\arguments{
+ \item{evalRoot}{
+%% ~~Describe \code{evalRoot} here~~
+}
+}
+\details{
+%% ~~ If necessary, more details than the description above ~~
+}
+\value{
+%% ~Describe the value returned
+%% If it is a LIST, use
+%% \item{comp1 }{Description of 'comp1'}
+%% \item{comp2 }{Description of 'comp2'}
+%% ...
+}
+\references{
+%% ~put references to the literature/web site here ~
+}
+\author{
+%% ~~who you are~~
+}
+\note{
+%% ~~further notes~~
+}
+
+%% ~Make other sections like Warning with \section{Warning }{....} ~
+
+\seealso{
+%% ~~objects to See Also as \code{\link{help}}, ~~~
+}
+\examples{
+##---- Should be DIRECTLY executable !! ----
+##-- ==> Define data, use random,
+##-- or do help(data=index) for the standard data sets.
+
+## The function is currently defined as
+function(evalRoot) {
+ fileAlleleCountStats = paste(evalRoot, ".AlleleCountStats.csv", sep="");
+ fileCompOverlap = paste(evalRoot, ".Comp_Overlap.csv", sep="");
+ fileCountVariants = paste(evalRoot, ".Count_Variants.csv", sep="");
+ fileGenotypeConcordance = paste(evalRoot, ".Genotype_Concordance.csv", sep="");
+ fileMetricsByAc = paste(evalRoot, ".MetricsByAc.csv", sep="");
+ fileMetricsBySample = paste(evalRoot, ".MetricsBySample.csv", sep="");
+ fileQuality_Metrics_by_allele_count = paste(evalRoot, ".Quality_Metrics_by_allele_count.csv", sep="");
+ fileQualityScoreHistogram = paste(evalRoot, ".QualityScoreHistogram.csv", sep="");
+ fileSampleStatistics = paste(evalRoot, ".Sample_Statistics.csv", sep="");
+ fileSampleSummaryStatistics = paste(evalRoot, ".Sample_Summary_Statistics.csv", sep="");
+ fileSimpleMetricsBySample = paste(evalRoot, ".SimpleMetricsBySample.csv", sep="");
+ fileTi_slash_Tv_Variant_Evaluator = paste(evalRoot, ".Ti_slash_Tv_Variant_Evaluator.csv", sep="");
+ fileTiTvStats = paste(evalRoot, ".TiTvStats.csv", sep="");
+ fileVariant_Quality_Score = paste(evalRoot, ".Variant_Quality_Score.csv", sep="");
+
+ eval = list(
+ AlleleCountStats = NA,
+ CompOverlap = NA,
+ CountVariants = NA,
+ GenotypeConcordance = NA,
+ MetricsByAc = NA,
+ MetricsBySample = NA,
+ Quality_Metrics_by_allele_count = NA,
+ QualityScoreHistogram = NA,
+ SampleStatistics = NA,
+ SampleSummaryStatistics = NA,
+ SimpleMetricsBySample = NA,
+ TiTv = NA,
+ TiTvStats = NA,
+ Variant_Quality_Score = NA,
+
+ CallsetNames = c(),
+ CallsetOnlyNames = c(),
+ CallsetFilteredNames = c()
+ );
+
+ eval$AlleleCountStats = .attemptToLoadFile(fileAlleleCountStats);
+ eval$CompOverlap = .attemptToLoadFile(fileCompOverlap);
+ eval$CountVariants = .attemptToLoadFile(fileCountVariants);
+ eval$GenotypeConcordance = .attemptToLoadFile(fileGenotypeConcordance);
+ eval$MetricsByAc = .attemptToLoadFile(fileMetricsByAc);
+ eval$MetricsBySample = .attemptToLoadFile(fileMetricsBySample);
+ eval$Quality_Metrics_by_allele_count = .attemptToLoadFile(fileQuality_Metrics_by_allele_count);
+ eval$QualityScoreHistogram = .attemptToLoadFile(fileQualityScoreHistogram);
+ eval$SampleStatistics = .attemptToLoadFile(fileSampleStatistics);
+ eval$SampleSummaryStatistics = .attemptToLoadFile(fileSampleSummaryStatistics);
+ eval$SimpleMetricsBySample = .attemptToLoadFile(fileSimpleMetricsBySample);
+ eval$TiTv = .attemptToLoadFile(fileTi_slash_Tv_Variant_Evaluator);
+ eval$TiTvStats = .attemptToLoadFile(fileTiTvStats);
+ eval$Variant_Quality_Score = .attemptToLoadFile(fileVariant_Quality_Score);
+
+ uniqueJexlExpressions = unique(eval$TiTv$jexl_expression);
+ eval$CallsetOnlyNames = as.vector(uniqueJexlExpressions[grep("FilteredIn|Intersection|none", uniqueJexlExpressions, invert=TRUE, ignore.case=TRUE)]);
+ eval$CallsetNames = as.vector(gsub("-only", "", eval$CallsetOnlyNames));
+ eval$CallsetFilteredNames = as.vector(c());
+ eval;
+ }
+}
+% Add one or more standard keywords, see file 'KEYWORDS' in the
+% R documentation directory.
+\keyword{ ~kwd1 }
+\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line
diff --git a/public/gsalib/src/R/man/gsa.read.gatkreport.Rd b/public/gsalib/src/R/man/gsa.read.gatkreport.Rd
new file mode 100644
index 0000000..67c2c7b
--- /dev/null
+++ b/public/gsalib/src/R/man/gsa.read.gatkreport.Rd
@@ -0,0 +1,55 @@
+\name{gsa.read.gatkreport}
+\alias{gsa.read.gatkreport}
+\title{
+gsa.read.gatkreport
+}
+\description{
+Reads a GATKReport file - a multi-table document - and loads each table as a separate data.frame object in a list.
+}
+\usage{
+gsa.read.gatkreport(filename)
+}
+\arguments{
+ \item{filename}{
+The path to the GATKReport file.
+}
+}
+\details{
+The GATKReport format replaces the multi-file output format used by many GATK tools and provides a single, consolidated file format. This format accomodates multiple tables and is still R-loadable - through this function.
+
+The file format looks like this:
+\preformatted{##:GATKReport.v0.1 TableName : The description of the table
+col1 col2 col3
+0 0.007451835696110506 25.474613284804366
+1 0.002362777171937477 29.844949954504095
+2 9.087604507451836E-4 32.87590975254731
+3 5.452562704471102E-4 34.498999090081895
+4 9.087604507451836E-4 35.14831665150137
+}
+
+}
+\value{
+Returns a list object, where each key is the TableName and the value is the data.frame object with the contents of the table. If multiple tables with the same name exist, each one after the first will be given names of "TableName.v1", "TableName.v2", ..., "TableName.vN".
+%% ~Describe the value returned
+%% If it is a LIST, use
+%% \item{comp1 }{Description of 'comp1'}
+%% \item{comp2 }{Description of 'comp2'}
+%% ...
+}
+\references{
+%% ~put references to the literature/web site here ~
+}
+\author{
+Kiran Garimella
+}
+\note{
+%% ~~further notes~~
+}
+
+\seealso{
+%% ~~objects to See Also as \code{\link{help}}, ~~~
+}
+\examples{
+report = gsa.read.gatkreport("/path/to/my/output.gatkreport");
+}
+\keyword{ ~kwd1 }
diff --git a/public/gsalib/src/R/man/gsa.read.squidmetrics.Rd b/public/gsalib/src/R/man/gsa.read.squidmetrics.Rd
new file mode 100644
index 0000000..0a8b378
--- /dev/null
+++ b/public/gsalib/src/R/man/gsa.read.squidmetrics.Rd
@@ -0,0 +1,48 @@
+\name{gsa.read.squidmetrics}
+\alias{gsa.read.squidmetrics}
+\title{
+gsa.read.squidmetrics
+}
+\description{
+Reads metrics for a specified SQUID project into a dataframe.
+}
+\usage{
+gsa.read.squidmetrics("C315")
+}
+\arguments{
+ \item{project}{
+The project for which metrics should be obtained.
+}
+ \item{bylane}{
+If TRUE, obtains per-lane metrics rather than the default per-sample metrics.
+}
+}
+\details{
+%% ~~ If necessary, more details than the description above ~~
+}
+\value{
+%% ~Describe the value returned
+%% If it is a LIST, use
+%% \item{comp1 }{Description of 'comp1'}
+%% \item{comp2 }{Description of 'comp2'}
+%% ...
+Returns a data frame with samples (or lanes) as the row and the metric as the column.
+}
+\references{
+%% ~put references to the literature/web site here ~
+}
+\author{
+Kiran Garimella
+}
+\note{
+This method will only work within the Broad Institute internal network.
+}
+
+\seealso{
+%% ~~objects to See Also as \code{\link{help}}, ~~~
+}
+\examples{
+## Obtain metrics for project C315.
+d = gsa.read.squidmetrics("C315");
+}
+\keyword{ ~kwd1 }
diff --git a/public/gsalib/src/R/man/gsa.read.vcf.Rd b/public/gsalib/src/R/man/gsa.read.vcf.Rd
new file mode 100644
index 0000000..cffd35e
--- /dev/null
+++ b/public/gsalib/src/R/man/gsa.read.vcf.Rd
@@ -0,0 +1,53 @@
+\name{gsa.read.vcf}
+\alias{gsa.read.vcf}
+\title{
+gsa.read.vcf
+}
+\description{
+Reads a VCF file into a table. Optionally expands genotype columns into separate columns containing the genotype, separate from the other fields specified in the FORMAT field.
+}
+\usage{
+gsa.read.vcf(vcffile, skip=0, nrows=-1, expandGenotypeFields = FALSE)
+}
+\arguments{
+ \item{vcffile}{
+The path to the vcf file.
+}
+ \item{skip}{
+The number of lines of the data file to skip before beginning to read data.
+}
+ \item{nrows}{
+The maximum number of rows to read in. Negative and other invalid values are ignored.
+}
+ \item{expandGenotypeFields}{
+If TRUE, adds an additional column per sample containing just the genotype.
+}
+}
+\details{
+The VCF format is the standard variant call file format used in the GATK. This function reads that data in as a table for easy analysis.
+}
+\value{
+Returns a data.frame object, where each column corresponds to the columns in the VCF file.
+%% ~Describe the value returned
+%% If it is a LIST, use
+%% \item{comp1 }{Description of 'comp1'}
+%% \item{comp2 }{Description of 'comp2'}
+%% ...
+}
+\references{
+%% ~put references to the literature/web site here ~
+}
+\author{
+Kiran Garimella
+}
+\note{
+%% ~~further notes~~
+}
+
+\seealso{
+%% ~~objects to See Also as \code{\link{help}}, ~~~
+}
+\examples{
+vcf = gsa.read.vcf("/path/to/my/output.vcf");
+}
+\keyword{ ~kwd1 }
diff --git a/public/gsalib/src/R/man/gsa.warn.Rd b/public/gsalib/src/R/man/gsa.warn.Rd
new file mode 100644
index 0000000..0b9770b
--- /dev/null
+++ b/public/gsalib/src/R/man/gsa.warn.Rd
@@ -0,0 +1,46 @@
+\name{gsa.warn}
+\alias{gsa.warn}
+\title{
+GSA warn
+}
+\description{
+Write a warning message to standard out with the prefix '[gsalib] Warning:'.
+}
+\usage{
+gsa.warn(message)
+}
+%- maybe also 'usage' for other objects documented here.
+\arguments{
+ \item{message}{
+The warning message to write.
+}
+}
+\details{
+%% ~~ If necessary, more details than the description above ~~
+}
+\value{
+%% ~Describe the value returned
+%% If it is a LIST, use
+%% \item{comp1 }{Description of 'comp1'}
+%% \item{comp2 }{Description of 'comp2'}
+%% ...
+}
+\references{
+%% ~put references to the literature/web site here ~
+}
+\author{
+Kiran Garimella
+}
+\note{
+%% ~~further notes~~
+}
+
+\seealso{
+%% ~~objects to See Also as \code{\link{help}}, ~~~
+}
+\examples{
+## Write message to stdout
+gsa.warn("This is a warning message");
+}
+\keyword{ ~kwd1 }
+\keyword{ ~kwd2 }% __ONLY ONE__ keyword per line
diff --git a/public/gsalib/src/R/man/gsalib-package.Rd b/public/gsalib/src/R/man/gsalib-package.Rd
new file mode 100644
index 0000000..4a49cf9
--- /dev/null
+++ b/public/gsalib/src/R/man/gsalib-package.Rd
@@ -0,0 +1,70 @@
+\name{gsalib-package}
+\alias{gsalib-package}
+\alias{gsalib}
+\docType{package}
+\title{
+GATK utility analysis functions
+}
+\description{
+Utility functions for analyzing GATK-processed NGS data
+}
+\details{
+This package contains functions for working with GATK-processed NGS data. These functions include a command-line parser that also allows a script to be used in interactive mode (good for developing scripts that will eventually be automated), a proportional Venn diagram generator, convenience methods for parsing VariantEval output, and more.
+}
+\author{
+Genome Sequencing and Analysis Group
+
+Medical and Population Genetics Program
+
+Maintainer: Kiran Garimella
+}
+\references{
+GATK website: http://www.broadinstitute.org/gatk
+
+GATK documentation guide: http://www.broadinstitute.org/gatk/guide
+
+GATK help forum: http://gatkforums.broadinstitute.org
+}
+\examples{
+## get script arguments in interactive and non-interactive mode
+cmdargs = gsa.getargs( list(
+ requiredArg1 = list(
+ value = NA,
+ doc = "Documentation for requiredArg1"
+ ),
+
+ optionalArg1 = list(
+ value = 3e9,
+ doc = "Documentation for optionalArg1"
+ )
+) );
+
+## plot a proportional Venn diagram
+gsa.plot.venn(500, 250, 0, 100);
+
+## read a GATKReport file
+report = gsa.gatk.report("/path/to/my/output.gatkreport");
+
+## emit a message
+gsa.message("This is a message");
+
+## emit a warning message
+gsa.message("This is a warning message");
+
+## emit an error message
+gsa.message("This is an error message");
+
+## read the SQUID metrics for a given sequencing project (internal to the Broad only)
+s = gsa.read.squidmetrics("C427");
+
+## read command-line arguments
+cmdargs = gsa.getargs(
+ list(
+ file = list(value="/my/test.vcf", doc="VCF file"),
+ verbose = list(value=0, doc="If 1, set verbose mode"),
+ test2 = list(value=2.3e9, doc="Another argument that does stuff")
+ ),
+ doc="My test program"
+);
+}
+\keyword{ package }
diff --git a/public/gsalib/src/assembly/gsalib.xml b/public/gsalib/src/assembly/gsalib.xml
new file mode 100644
index 0000000..7650c71
--- /dev/null
+++ b/public/gsalib/src/assembly/gsalib.xml
@@ -0,0 +1,13 @@
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>gsalib</id>
+ <formats>
+ <format>tar.gz</format>
+ </formats>
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+ <outputDirectory>gsalib</outputDirectory>
+ <directory>src/R</directory>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git a/public/java/config/log4j.properties b/public/java/config/log4j.properties
new file mode 100644
index 0000000..480646f
--- /dev/null
+++ b/public/java/config/log4j.properties
@@ -0,0 +1,10 @@
+log4j.logger.org.broadinstitute.gatk.tools.walkers.Walker=INFO, walker
+
+# use this to append walker data to the console only
+log4j.appender.walker=org.apache.log4j.ConsoleAppender
+
+# uncomment the following instead for writing debug info to a file called walker.log
+#log4j.appender.walker=org.apache.log4j.FileAppender
+#log4j.appender.walker.File=walker.log
+#log4j.appender.walker.layout=org.apache.log4j.PatternLayout
+#log4j.appender.walker.layout.ConversionPattern=%r [%t] %-5p %c - %m%n
diff --git a/public/package-tests/pom.xml b/public/package-tests/pom.xml
new file mode 100644
index 0000000..ce3f5cf
--- /dev/null
+++ b/public/package-tests/pom.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!--
+ Run during package testing by the maven invoker plugin in the gatk-aggregator /pom.xml
+ -->
+
+ <parent>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-root</artifactId>
+ <version>3.3</version>
+ <relativePath>../gatk-root</relativePath>
+ </parent>
+
+ <artifactId>gatk-package-tests</artifactId>
+ <packaging>pom</packaging>
+ <name>GATK Package Tests</name>
+
+ <properties>
+ <gatk.basedir>${project.basedir}/../..</gatk.basedir>
+ <gatk.packageunittests.skipped>true</gatk.packageunittests.skipped>
+ <gatk.packageintegrationtests.skipped>true</gatk.packageintegrationtests.skipped>
+ <gatk.packagequeuetests.skipped>true</gatk.packagequeuetests.skipped>
+ <gatk.packagelargescaletests.skipped>true</gatk.packagelargescaletests.skipped>
+ <gatk.packageknowledgebasetests.skipped>true</gatk.packageknowledgebasetests.skipped>
+ </properties>
+
+ <!-- Dependency configuration (versions, etc.) -->
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${gatk.packagetests.artifactId}</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!--
+ gatk-framework test-jar added for BaseTest
+
+ TODO: Currently the <exclusion> isn't working 100%, so switched to using additionalClasspathElements
+
+ TODO: Uncomment below to use the explicitly bad "exclude *" to really test correct packaging,
+ TODO: until we can separate BaseTest and other utilities into their own gatk-test-utils artifact.
+ TODO: We only want the classes in the packaged jars tested, not the classes within the dependency jars too.
+ See also:
+ http://stackoverflow.com/questions/547805/how-to-exclude-all-transitive-dependencies-of-a-maven-dependency
+ http://maven.apache.org/plugins/maven-jar-plugin/usage.html#The_preferred_way
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>gatk-tools-public</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+
+ </dependency>
+ -->
+
+ <!--
+ NOTE: Any test dependencies used by a packaged artifact must be ALSO added here.
+ For example, gatk-tools-protected uses caliper, so caliper should also be added here.
+ TestNG and its reporters are inherited from the global gatk-root/pom.xml as dependencies.
+ -->
+ <dependency>
+ <groupId>com.google.caliper</groupId>
+ <artifactId>caliper</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <directory>${gatk.packagetests.basedir}/target</directory>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>unittests</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>unittests.profile.enabled</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <!-- Plugin configuration -->
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <basedir>${gatk.packagetests.basedir}</basedir>
+ <workingDirectory>${gatk.packagetests.basedir}</workingDirectory>
+ <classesDirectory>${project.build.outputDirectory}/ignored_by_package_test</classesDirectory>
+ <testClassesDirectory>${gatk.packagetests.testClasses}</testClassesDirectory>
+ <!-- TODO: Using additionalClasspathElement while debugging exclusion issue above -->
+ <additionalClasspathElements>
+ <additionalClasspathElement>${gatk.basedir}/public/gatk-tools-public/target/gatk-tools-public-${project.version}-tests.jar</additionalClasspathElement>
+ <additionalClasspathElement>${gatk.basedir}/public/gatk-queue/target/gatk-queue-${project.version}-tests.jar</additionalClasspathElement>
+ </additionalClasspathElements>
+ </configuration>
+ <executions>
+ <execution>
+ <id>unit-tests</id>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <skip>${gatk.packageunittests.skipped}</skip>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>integrationtests</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>integrationtests.profile.enabled</name>
+ <value>true</value>
+ </property>
+ </activation>
+ <build>
+ <!-- Plugin configuration -->
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <configuration>
+ <basedir>${gatk.packagetests.basedir}</basedir>
+ <workingDirectory>${gatk.packagetests.basedir}</workingDirectory>
+ <classesDirectory>${project.build.outputDirectory}/ignored_by_package_test</classesDirectory>
+ <testClassesDirectory>${gatk.packagetests.testClasses}</testClassesDirectory>
+ <!-- TODO: Using additionalClasspathElement while debugging exclusion issue above -->
+ <additionalClasspathElements>
+ <additionalClasspathElement>${gatk.basedir}/public/gatk-tools-public/target/gatk-tools-public-${project.version}-tests.jar</additionalClasspathElement>
+ <additionalClasspathElement>${gatk.basedir}/public/gatk-queue/target/gatk-queue-${project.version}-tests.jar</additionalClasspathElement>
+ </additionalClasspathElements>
+ </configuration>
+ <executions>
+ <execution>
+ <id>integration-tests</id>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ <!-- run integration tests -->
+ <configuration>
+ <skip>${gatk.packageintegrationtests.skipped}</skip>
+ </configuration>
+ </execution>
+ <execution>
+ <id>queue-tests</id>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ <!-- run queue dry run tests -->
+ <configuration>
+ <skip>${gatk.packagequeuetests.skipped}</skip>
+ </configuration>
+ </execution>
+ <execution>
+ <id>large-scale-tests</id>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ <!-- run large scale tests -->
+ <configuration>
+ <skip>${gatk.packagelargescaletests.skipped}</skip>
+ </configuration>
+ </execution>
+ <execution>
+ <id>knowledge-base-tests</id>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ <!-- run knowledge base tests -->
+ <configuration>
+ <skip>${gatk.packageknowledgebasetests.skipped}</skip>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ </profiles>
+
+</project>
diff --git a/public/perl/liftOverVCF.pl b/public/perl/liftOverVCF.pl
new file mode 100755
index 0000000..a942145
--- /dev/null
+++ b/public/perl/liftOverVCF.pl
@@ -0,0 +1,83 @@
+#!/usr/bin/perl -w
+
+# Runs the liftover tool on a VCF and properly handles the output
+
+use strict;
+use Getopt::Long;
+
+my $in = undef;
+my $gatk = undef;
+my $chain = undef;
+my $newRef = undef;
+my $oldRef = undef;
+my $out = undef;
+my $tmp = "/tmp";
+my $recordOriginalLocation = 0;
+GetOptions( "vcf=s" => \$in,
+ "gatk=s" => \$gatk,
+ "chain=s" => \$chain,
+ "newRef=s" => \$newRef,
+ "oldRef=s" => \$oldRef,
+ "out=s" => \$out,
+ "tmp=s" => \$tmp,
+ "recordOriginalLocation" => \$recordOriginalLocation);
+
+if ( !$in || !$gatk || !$chain || !$newRef || !$oldRef || !$out ) {
+ print "Usage: liftOverVCF.pl\n\t-vcf \t\t<input vcf>\n\t-gatk \t\t<path to gatk trunk>\n\t-chain \t\t<chain file>\n\t-newRef \t<path to new reference prefix; we will need newRef.dict, .fasta, and .fasta.fai>\n\t-oldRef \t<path to old reference prefix; we will need oldRef.fasta>\n\t-out \t\t<output vcf>\n\t-tmp \t\t<temp file location; defaults to /tmp>\n\t-recordOriginalLocation \t\t<Should we record what the original location was in the INFO field?; defaults to false>\n";
+ print "Example: ./liftOverVCF.pl\n\t-vcf /humgen/gsa-hpprojects/GATK/data/Comparisons/Validated/1kg_snp_validation/all_validation_batches.b36.vcf\n\t-chain b36ToHg19.broad.over.chain\n\t-out lifted.hg19.vcf\n\t-gatk /humgen/gsa-scr1/ebanks/Sting_dev\n\t-newRef /seq/references/Homo_sapiens_assembly19/v0/Homo_sapiens_assembly19\n\t-oldRef /humgen/1kg/reference/human_b36_both\n";
+ exit(1);
+}
+
+# generate a random number
+my $random_number = rand();
+my $tmp_prefix = "$tmp/$random_number";
+print "Writing temporary files to prefix: $tmp_prefix\n";
+my $unsorted_vcf = "$tmp_prefix.unsorted.vcf";
+
+# lift over the file
+print "Lifting over the vcf...";
+my $cmd = "java -jar $gatk/dist/GenomeAnalysisTK.jar -T LiftoverVariants -R $oldRef.fasta -V:variant $in -o $unsorted_vcf -chain $chain -dict $newRef.dict -U LENIENT_VCF_PROCESSING";
+if ($recordOriginalLocation) {
+ $cmd .= " -recordOriginalLocation";
+}
+system($cmd) == 0 or quit("The liftover step failed. Please correct the necessary errors before retrying.");
+
+# we need to sort the lifted over file now
+print "\nRe-sorting the vcf...\n";
+my $sorted_vcf = "$tmp_prefix.sorted.vcf";
+open(SORTED, ">$sorted_vcf") or die "can't open $sorted_vcf: $!";
+
+# write the header
+open(UNSORTED, "< $unsorted_vcf") or die "can't open $unsorted_vcf: $!";
+my $inHeader = 1;
+while ( $inHeader == 1 ) {
+ my $line = <UNSORTED>;
+ if ( $line !~ m/^#/ ) {
+ $inHeader = 0;
+ } else {
+ print SORTED "$line";
+ }
+}
+close(UNSORTED);
+close(SORTED);
+
+$cmd = "grep \"^#\" -v $unsorted_vcf | sort -n -k2 -T $tmp | $gatk/public/perl/sortByRef.pl --tmp $tmp - $newRef.fasta.fai >> $sorted_vcf";
+system($cmd) == 0 or quit("The sorting step failed. Please correct the necessary errors before retrying.");
+
+# Filter the VCF for bad records
+print "\nFixing/removing bad records...\n";
+$cmd = "java -jar $gatk/dist/GenomeAnalysisTK.jar -T FilterLiftedVariants -R $newRef.fasta -V:variant $sorted_vcf -o $out -U LENIENT_VCF_PROCESSING";
+system($cmd) == 0 or quit("The filtering step failed. Please correct the necessary errors before retrying.");
+
+# clean up
+unlink $unsorted_vcf;
+unlink $sorted_vcf;
+my $sorted_index = "$sorted_vcf.idx";
+unlink $sorted_index;
+
+print "\nDone!\n";
+
+sub quit {
+ print "\n$_[0]\n";
+ exit(1);
+}
diff --git a/public/perl/sortByRef.pl b/public/perl/sortByRef.pl
new file mode 100755
index 0000000..e177077
--- /dev/null
+++ b/public/perl/sortByRef.pl
@@ -0,0 +1,127 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Getopt::Long;
+
+sub usage {
+
+ print "\nUsage:\n";
+ print "sortByRef.pl [--k POS] [--tmp dir] INPUT REF_DICT\n\n";
+
+ print " Sorts lines of the input file INFILE according\n";
+ print " to the reference contig order specified by the\n";
+ print " reference dictionary REF_DICT (.fai file).\n";
+ print " The sort is stable. If -k option is not specified,\n";
+ print " it is assumed that the contig name is the first\n";
+ print " field in each line.\n\n";
+ print " INPUT input file to sort. If '-' is specified, \n";
+ print " then reads from STDIN.\n";
+ print " REF_DICT .fai file, or ANY file that has contigs, in the\n";
+ print " desired soting order, as its first column.\n";
+ print " --k POS : contig name is in the field POS (1-based)\n";
+ print " of input lines.\n\n";
+ print " --tmp DIR : temp directory [default=/tmp]\n\n";
+
+ exit(1);
+}
+
+my $pos = 1;
+my $tmp = "/tmp";
+GetOptions( "k:i" => \$pos,
+ "tmp=s" => \$tmp);
+
+$pos--;
+
+usage() if ( scalar(@ARGV) == 0 );
+
+if ( scalar(@ARGV) != 2 ) {
+ print "Wrong number of arguments\n";
+ usage();
+}
+
+my $input_file = $ARGV[0];
+my $dict_file = $ARGV[1];
+
+
+open(DICT, "< $dict_file") or die("Can not open $dict_file: $!");
+
+my %ref_order;
+
+my $n = 0;
+while ( <DICT> ) {
+ chomp;
+ my ($contig, $rest) = split '\s';
+ die("Dictionary file is probably corrupt: multiple instances of contig $contig") if ( defined $ref_order{$contig} );
+
+ $ref_order{$contig} = $n;
+ $n++;
+}
+
+close DICT;
+#we have loaded contig ordering now
+
+my $INPUT;
+if ($input_file eq "-" ) {
+ $INPUT = "STDIN";
+} else {
+ open($INPUT, "< $input_file") or die("Can not open $input_file: $!");
+}
+
+my %temp_outputs;
+
+while ( <$INPUT> ) {
+
+ my @fields = split '\s';
+ die("Specified field position exceeds the number of fields:\n$_")
+ if ( $pos >= scalar(@fields) );
+
+ my $contig = $fields[$pos];
+ if ( $contig =~ m/:/ ) {
+ my @loc = split(/:/, $contig);
+ # print $contig . " " . $loc[0] . "\n";
+ $contig = $loc[0]
+ }
+ chomp $contig if ( $pos == scalar(@fields) - 1 ); # if last field in line
+
+ my $order;
+ if ( defined $ref_order{$contig} ) { $order = $ref_order{$contig}; }
+ else {
+ $ref_order{$contig} = $n;
+ $order = $n; # input line has contig that was not in the dict;
+ $n++; # this contig will go at the end of the output,
+ # after all known contigs
+ }
+
+ my $fhandle;
+ if ( defined $temp_outputs{$order} ) { $fhandle = $temp_outputs{$order} }
+ else {
+ #print "opening $order $$ $_\n";
+ open( $fhandle, " > $tmp/sortByRef.$$.$order.tmp" ) or
+ die ( "Can not open temporary file $order: $!");
+ $temp_outputs{$order} = $fhandle;
+ }
+
+ # we got the handle to the temp file that keeps all
+ # lines with contig $contig
+
+ print $fhandle $_; # send current line to its corresponding temp file
+}
+
+close $INPUT;
+
+foreach my $f ( values %temp_outputs ) { close $f; }
+
+# now collect back into single output stream:
+
+for ( my $i = 0 ; $i < $n ; $i++ ) {
+ # if we did not have any lines on contig $i, then there's
+ # no temp file and nothing to do
+ next if ( ! defined $temp_outputs{$i} ) ;
+
+ my $f;
+ open ( $f, "< $tmp/sortByRef.$$.$i.tmp" );
+ while ( <$f> ) { print ; }
+ close $f;
+
+ unlink "$tmp/sortByRef.$$.$i.tmp";
+}
diff --git a/public/pom.xml b/public/pom.xml
new file mode 100644
index 0000000..7533fca
--- /dev/null
+++ b/public/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.broadinstitute.gatk</groupId>
+ <artifactId>gatk-root</artifactId>
+ <version>3.3</version>
+ <relativePath>gatk-root</relativePath>
+ </parent>
+
+ <artifactId>gatk-aggregator-public</artifactId>
+ <packaging>pom</packaging>
+ <name>GATK Aggregator Public</name>
+
+ <modules>
+ <module>gatk-root</module>
+ <module>gsalib</module>
+ <module>gatk-utils</module>
+ <module>gatk-engine</module>
+ <module>gatk-tools-public</module>
+ <module>external-example</module>
+ <!-- queue optionally enabled as profiles -->
+ </modules>
+
+ <properties>
+ <gatk.basedir>${project.basedir}/..</gatk.basedir>
+ </properties>
+
+ <profiles>
+ <!-- Allow queue to be disabled. -->
+ <profile>
+ <id>queue</id>
+ <activation>
+ <property>
+ <name>!disable.queue</name>
+ </property>
+ </activation>
+ <modules>
+ <module>gatk-queue</module>
+ <module>gatk-queue-extensions-generator</module>
+ <module>gatk-queue-extensions-public</module>
+ </modules>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/public/repo/com/google/code/cofoja/cofoja/1.0-r139/cofoja-1.0-r139.jar b/public/repo/com/google/code/cofoja/cofoja/1.0-r139/cofoja-1.0-r139.jar
new file mode 100644
index 0000000..2cbdd38
Binary files /dev/null and b/public/repo/com/google/code/cofoja/cofoja/1.0-r139/cofoja-1.0-r139.jar differ
diff --git a/public/repo/com/google/code/cofoja/cofoja/1.0-r139/cofoja-1.0-r139.pom b/public/repo/com/google/code/cofoja/cofoja/1.0-r139/cofoja-1.0-r139.pom
new file mode 100644
index 0000000..5a6fb69
--- /dev/null
+++ b/public/repo/com/google/code/cofoja/cofoja/1.0-r139/cofoja-1.0-r139.pom
@@ -0,0 +1,9 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.google.code.cofoja</groupId>
+ <artifactId>cofoja</artifactId>
+ <name>cofoja</name>
+ <version>1.0-r139</version>
+</project>
diff --git a/public/repo/net/sf/snpeff/snpeff/2.0.5/snpeff-2.0.5.jar b/public/repo/net/sf/snpeff/snpeff/2.0.5/snpeff-2.0.5.jar
new file mode 100644
index 0000000..6dc922a
Binary files /dev/null and b/public/repo/net/sf/snpeff/snpeff/2.0.5/snpeff-2.0.5.jar differ
diff --git a/public/repo/net/sf/snpeff/snpeff/2.0.5/snpeff-2.0.5.pom b/public/repo/net/sf/snpeff/snpeff/2.0.5/snpeff-2.0.5.pom
new file mode 100644
index 0000000..d316e20
--- /dev/null
+++ b/public/repo/net/sf/snpeff/snpeff/2.0.5/snpeff-2.0.5.pom
@@ -0,0 +1,9 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>net.sf</groupId>
+ <artifactId>snpeff</artifactId>
+ <name>snpeff</name>
+ <version>2.0.5</version>
+</project>
diff --git a/public/repo/picard/picard/1.120.1579/picard-1.120.1579.jar b/public/repo/picard/picard/1.120.1579/picard-1.120.1579.jar
new file mode 100644
index 0000000..fa3fa36
Binary files /dev/null and b/public/repo/picard/picard/1.120.1579/picard-1.120.1579.jar differ
diff --git a/public/repo/picard/picard/1.120.1579/picard-1.120.1579.pom b/public/repo/picard/picard/1.120.1579/picard-1.120.1579.pom
new file mode 100644
index 0000000..cca9972
--- /dev/null
+++ b/public/repo/picard/picard/1.120.1579/picard-1.120.1579.pom
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>picard</groupId>
+ <artifactId>picard</artifactId>
+ <version>1.120.1579</version>
+ <name>picard</name>
+ <dependencies>
+ <dependency>
+ <groupId>samtools</groupId>
+ <artifactId>htsjdk</artifactId>
+ <version>1.120.1620</version>
+ </dependency>
+ <!-- TODO: Picard is using a custom zip with just ant's BZip2 classes. See also: http://www.kohsuke.org/bzip2 -->
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant</artifactId>
+ <version>1.8.2</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant-launcher</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>com.sun</groupId>
+ <artifactId>tools.jar</artifactId>
+ <version>1.5</version>
+ <scope>system</scope>
+ <systemPath>${java.home}/../lib/tools.jar</systemPath>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/public/repo/samtools/htsjdk/1.120.1620/htsjdk-1.120.1620.jar b/public/repo/samtools/htsjdk/1.120.1620/htsjdk-1.120.1620.jar
new file mode 100644
index 0000000..8480ddc
Binary files /dev/null and b/public/repo/samtools/htsjdk/1.120.1620/htsjdk-1.120.1620.jar differ
diff --git a/public/repo/samtools/htsjdk/1.120.1620/htsjdk-1.120.1620.pom b/public/repo/samtools/htsjdk/1.120.1620/htsjdk-1.120.1620.pom
new file mode 100644
index 0000000..04ebef8
--- /dev/null
+++ b/public/repo/samtools/htsjdk/1.120.1620/htsjdk-1.120.1620.pom
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>samtools</groupId>
+ <artifactId>htsjdk</artifactId>
+ <version>1.120.1620</version>
+ <name>htsjdk</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>5.5</version>
+ <classifier>jdk15</classifier>
+ </dependency>
+ <dependency>
+ <groupId>org.xerial.snappy</groupId>
+ <artifactId>snappy-java</artifactId>
+ <version>1.0.3-rc3</version>
+ </dependency>
+ <!-- TODO: This artifact is only in the GATK local repo, not in central, yet. -->
+ <dependency>
+ <groupId>com.google.code.cofoja</groupId>
+ <artifactId>cofoja</artifactId>
+ <version>1.0-r139</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/public/repo/sysinternals/junction/1.04/junction-1.04.exe b/public/repo/sysinternals/junction/1.04/junction-1.04.exe
new file mode 100644
index 0000000..9ec3b1c
Binary files /dev/null and b/public/repo/sysinternals/junction/1.04/junction-1.04.exe differ
diff --git a/public/repo/sysinternals/junction/1.04/junction-1.04.exe.md5 b/public/repo/sysinternals/junction/1.04/junction-1.04.exe.md5
new file mode 100644
index 0000000..a7854ee
--- /dev/null
+++ b/public/repo/sysinternals/junction/1.04/junction-1.04.exe.md5
@@ -0,0 +1 @@
+b25b81716aaca69eecd0eedbf7891ad1
\ No newline at end of file
diff --git a/public/repo/sysinternals/junction/1.04/junction-1.04.pom b/public/repo/sysinternals/junction/1.04/junction-1.04.pom
new file mode 100644
index 0000000..bb2f9b1
--- /dev/null
+++ b/public/repo/sysinternals/junction/1.04/junction-1.04.pom
@@ -0,0 +1,15 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>sysinternals</groupId>
+ <artifactId>junction</artifactId>
+ <version>1.04</version>
+ <url>http://www.sysinternals.com/Utilities/Junction.html</url>
+ <name>Junction (symbolic links on windows)</name>
+ <description>Directory symbolic links are known as NTFS junctions in Windows.</description>
+ <licenses>
+ <license>
+ <name>SYSINTERNALS SOFTWARE LICENSE</name>
+ <url>http://www.sysinternals.com/Licensing.html</url>
+ </license>
+ </licenses>
+</project>
\ No newline at end of file
diff --git a/public/repo/sysinternals/junction/1.04/junction-1.04.pom.md5 b/public/repo/sysinternals/junction/1.04/junction-1.04.pom.md5
new file mode 100644
index 0000000..2062887
--- /dev/null
+++ b/public/repo/sysinternals/junction/1.04/junction-1.04.pom.md5
@@ -0,0 +1 @@
+253b197c9831aef9e275a751a464e332
\ No newline at end of file
diff --git a/public/src/main/scripts/shell/delete_maven_links.sh b/public/src/main/scripts/shell/delete_maven_links.sh
new file mode 100755
index 0000000..31fb06d
--- /dev/null
+++ b/public/src/main/scripts/shell/delete_maven_links.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+#
+# Delete symlinks to testdata/qscripts created by maven. This is necessary
+# in cases where "mvn clean" fails to delete these links itself and exits
+# with an error.
+#
+# Should be run from the root directory of your git clone.
+#
+
+find -L . -type l -name testdata -print0 | xargs -0 rm
+find -L . -type l -name qscript -print0 | xargs -0 rm
+
+exit 0
diff --git a/settings/helpTemplates/common.html b/settings/helpTemplates/common.html
new file mode 100644
index 0000000..5400162
--- /dev/null
+++ b/settings/helpTemplates/common.html
@@ -0,0 +1,88 @@
+<!--
+ ~ Copyright (c) 2012, The Broad Institute
+ ~
+ ~ Permission is hereby granted, free of charge, to any person
+ ~ obtaining a copy of this software and associated documentation
+ ~ files (the "Software"), to deal in the Software without
+ ~ restriction, including without limitation the rights to use,
+ ~ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ ~ copies of the Software, and to permit persons to whom the
+ ~ Software is furnished to do so, subject to the following
+ ~ conditions:
+ ~
+ ~ The above copyright notice and this permission notice shall be
+ ~ included in all copies or substantial portions of the Software.
+ ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ ~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ ~ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ ~ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ ~ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ ~ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ ~ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ ~ OTHER DEALINGS IN THE SOFTWARE.
+ -->
+
+<#--
+ This file contains all the theming neccesary to present GATKDocs on the GATK website
+ Included are the paths to our bootstrap assets as well as helper functions to generate relevant links
+
+ -->
+
+ <#global siteRoot = "http://www.broadinstitute.org/gatk/" />
+ <#global guideIndex = "http://www.broadinstitute.org/gatk/guide/" />
+ <#global forum = "http://gatkforums.broadinstitute.org/" />
+
+ <#macro footerInfo>
+ <hr>
+ <p><a href='#top'><i class='fa fa-chevron-up'></i> Return to top</a></p>
+ <hr>
+ <p class="see-also">See also
+ <a href="${guideIndex}">Guide Index</a> |
+ <a href="index">Tool Documentation Index</a> |
+ <a href="${forum}">Support Forum</a>
+ </p>
+
+ <p class="version">GATK version ${version} built at ${timestamp}.
+ <#-- closing P tag in next macro -->
+ </#macro>
+
+ <#macro footerClose>
+ <#-- ugly little hack to enable adding tool-specific info inline -->
+ </p>
+ </#macro>
+
+ <#macro getCategories groups>
+ <style>
+ #sidenav .accordion-body a {
+ color : gray;
+ }
+
+ .accordion-body li {
+ list-style : none;
+ }
+ </style>
+ <ul class="nav nav-pills nav-stacked" id="sidenav">
+ <#assign seq = ["engine", "tools", "utilities", "other"]>
+ <#list seq as supercat>
+ <hr>
+ <#list groups?sort_by("name") as group>
+ <#if group.supercat == supercat>
+ <li><a data-toggle="collapse" data-parent="#sidenav" href="#${group.id}">${group.name}</a>
+ <div id="${group.id}"
+ <?php echo ($group == '${group.name}')? 'class="accordion-body collapse in"'.chr(62) : 'class="accordion-body collapse"'.chr(62);?>
+ <ul>
+ <#list data as datum>
+ <#if datum.group == group.name>
+ <li>
+ <a href="${datum.filename}">${datum.name}</a>
+ </li>
+ </#if>
+ </#list>
+ </ul>
+ </div>
+ </li>
+ </#if>
+ </#list>
+ </#list>
+ </ul>
+ </#macro>
\ No newline at end of file
diff --git a/settings/helpTemplates/generic.index.template.html b/settings/helpTemplates/generic.index.template.html
new file mode 100644
index 0000000..bd5742f
--- /dev/null
+++ b/settings/helpTemplates/generic.index.template.html
@@ -0,0 +1,93 @@
+<!--
+ ~ Copyright (c) 2012, The Broad Institute
+ ~
+ ~ Permission is hereby granted, free of charge, to any person
+ ~ obtaining a copy of this software and associated documentation
+ ~ files (the "Software"), to deal in the Software without
+ ~ restriction, including without limitation the rights to use,
+ ~ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ ~ copies of the Software, and to permit persons to whom the
+ ~ Software is furnished to do so, subject to the following
+ ~ conditions:
+ ~
+ ~ The above copyright notice and this permission notice shall be
+ ~ included in all copies or substantial portions of the Software.
+ ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ ~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ ~ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ ~ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ ~ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ ~ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ ~ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ ~ OTHER DEALINGS IN THE SOFTWARE.
+ -->
+
+<?php
+
+ include '../../../include/common.php';
+ $module = modules::GATK;
+ printHeader($module, "GATK | Tool Documentation Index", "Guides");
+?>
+
+<div class='row-fluid'>
+
+<?php printGATKDocsNav($module); ?>
+
+<div class='span9'>
+
+<#include "common.html"/>
+
+<#macro emitGroup group>
+ <div class="accordion-group">
+ <div class="accordion-heading">
+ <a class="accordion-toggle" data-toggle="collapse" data-parent="#index" href="#${group.id}">
+ <h4>${group.name}</h4>
+ </a>
+ </div>
+ <div class="accordion-body collapse" id="${group.id}">
+ <div class="accordion-inner">
+ <p class="lead">${group.summary}</p>
+ <table class="table table-striped table-bordered table-condensed">
+ <tr>
+ <th>Name</th>
+ <th>Summary</th>
+ </tr>
+ <#list data as datum>
+ <#if datum.group == group.name>
+ <tr>
+ <td><a href="${datum.filename}">${datum.name}</a></td>
+ <td>${datum.summary}</td>
+ </tr>
+ </#if>
+ </#list>
+ </table>
+ </div>
+ </div>
+ </div>
+</#macro>
+
+<h1 id="top">Tool Documentation Index
+ <small>${version}</small>
+</h1>
+<div class="accordion" id="index">
+ <#assign seq = ["engine", "tools", "utilities", "other", "dev"]>
+ <#list seq as supercat>
+ <hr>
+ <#list groups?sort_by("name") as group>
+ <#if group.supercat == supercat>
+ <@emitGroup group=group/>
+ </#if>
+ </#list>
+ </#list>
+</div>
+
+<@footerInfo />
+<@footerClose />
+
+</div></div>
+
+<?php
+
+ printFooter($module);
+
+?>
\ No newline at end of file
diff --git a/settings/helpTemplates/generic.template.html b/settings/helpTemplates/generic.template.html
new file mode 100644
index 0000000..d163eff
--- /dev/null
+++ b/settings/helpTemplates/generic.template.html
@@ -0,0 +1,327 @@
+<!--
+ ~ Copyright (c) 2012, The Broad Institute
+ ~
+ ~ Permission is hereby granted, free of charge, to any person
+ ~ obtaining a copy of this software and associated documentation
+ ~ files (the "Software"), to deal in the Software without
+ ~ restriction, including without limitation the rights to use,
+ ~ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ ~ copies of the Software, and to permit persons to whom the
+ ~ Software is furnished to do so, subject to the following
+ ~ conditions:
+ ~
+ ~ The above copyright notice and this permission notice shall be
+ ~ included in all copies or substantial portions of the Software.
+ ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ ~ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ ~ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ ~ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ ~ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ ~ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ ~ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ ~ OTHER DEALINGS IN THE SOFTWARE.
+ -->
+
+<?php
+
+ include '../../../include/common.php';
+ $module = modules::GATK;
+ printHeader($module, "GATK | Tool Documentation Index", "Guides");
+?>
+
+<div class='row-fluid' id="top">
+
+<#include "common.html"/>
+
+<#macro argumentlist name myargs>
+ <#if myargs?size != 0>
+ <tr>
+ <th colspan="4" id="row-divider">${name}</th>
+ </tr>
+ <#list myargs as arg>
+ <tr>
+ <td><a href="#${arg.name}">${arg.name}</a><br />
+ <#if arg.synonyms != "NA">
+ <#if arg.name[2..] != arg.synonyms[1..]>
+ <em>${arg.synonyms}</em>
+ </#if>
+ </#if>
+ </td>
+ <!--<td>${arg.type}</td> -->
+ <td>${arg.defaultValue!"NA"}</td>
+ <td>${arg.summary}</td>
+ </tr>
+ </#list>
+ </#if>
+</#macro>
+
+<#macro argumentDetails arg>
+ <hr style="border-bottom: dotted 1px #C0C0C0;" />
+ <h3><a name="${arg.name}">${arg.name} </a>
+ <#if arg.synonyms??> / <small>${arg.synonyms}</small></#if>
+ </h3>
+ <p class="args">
+ <b>${arg.summary}</b><br />
+ ${arg.fulltext}
+ </p>
+ <!-- Not sure what this can contain apart from "required" and "deprecated" (which args are @hidden) so removing it provisionally -->
+ <!--<#if arg.attributes??>
+ <p>${arg.attributes}</p>
+ </#if>-->
+ <#if arg.rodTypes != "NA">
+ <p>${arg.name} binds reference ordered data. This argument supports ROD files of the following types: ${arg.rodTypes}</p>
+ </#if>
+ <#if arg.options?has_content>
+ <p>
+ The ${arg.name} argument is an enumerated type (${arg.type}), which can have one of the following values:
+ <dl class="enum">
+ <#list arg.options as option>
+ <dt class="enum">${option.name}</dt>
+ <dd class="enum">${option.summary}</dd>
+ </#list>
+ </dl>
+ </p>
+ </#if>
+ <p><#if arg.required != "NA">
+ <#if arg.required == "yes">
+ <span class="badge badge-important">R</span>
+ </#if>
+ </#if>
+ <span class="label label-info ">${arg.type}</span>
+ <#if arg.defaultValue?is_number>
+ <span class="label">${arg.defaultValue}</span>
+ </#if>
+ <#if arg.minValue?is_number>
+ <span class="label label-warning">[ [ ${arg.minValue}</span>
+ </#if>
+ <#if arg.minRecValue?is_number>
+ <span class="label label-success">[ ${arg.minRecValue}</span>
+ </#if>
+ <#if arg.maxRecValue?is_number>
+ <span class="label label-success">${arg.maxRecValue} ]</span>
+ </#if>
+ <#if arg.maxValue?is_number>
+ <span class="label label-warning">${arg.maxValue} ] ]</span>
+ </#if>
+ </p>
+</#macro>
+<#macro relatedByType name type>
+ <#list relatedDocs as relatedDoc>
+ <#if relatedDoc.relation == type>
+ <h3>${name}</h3>
+ <ul>
+ <#list relatedDocs as relatedDoc>
+ <#if relatedDoc.relation == type>
+ <li><a href="${relatedDoc.filename}">${relatedDoc.name}</a> is a ${relatedDoc.relation}</li>
+ </#if>
+ </#list>
+ </ul>
+ <#break>
+ </#if>
+ </#list>
+</#macro>
+
+<?php $group = '${group}'; ?>
+
+<section class="span4">
+ <aside class="well">
+ <a href="index"><h4><i class='fa fa-chevron-left'></i> Back to Tool Docs Index</h4></a>
+ </aside>
+ <aside class="well">
+ <h2>Categories</h2>
+ <@getCategories groups=groups />
+ </aside>
+ <?php getForumPosts( '${name}' ) ?>
+
+</section>
+
+<div class="span8">
+
+ <h1>${name}</h1>
+
+ <p class="lead">${summary}</p>
+ <#-- using goto dev annotation instead, see above footer
+ <#if author??>
+ <h3>Author
+ <small> ${author}</small>
+ </h3>
+ </#if> -->
+ <#if group?? >
+ <h3>Category
+ <small> ${group}</small>
+ </h3>
+ </#if>
+ <#if walkertype != "">
+ <h3>Traversal
+ <small>${walkertype}</small>
+ </h3>
+ </#if>
+ <#if walkertype != "">
+ <h3>PartitionBy
+ <small>${partitiontype}</small>
+ </h3>
+ </#if>
+ <#if annotfield != "" >
+ <h3>VCF Field
+ <small>${annotfield}</small>
+ </h3>
+ </#if>
+ <#if annotinfo != "" >
+ <h3>Type
+ <small>${annotinfo}</small>
+ </h3>
+ </#if>
+ <#if annotdescript?has_content >
+ <h3>Header info <br />
+ <small>
+ <#list annotdescript as line>
+ <li><pre>${line}</pre></li>
+ </#list>
+ </small>
+ </h3>
+ </#if>
+
+ <hr>
+ <h2>Overview</h2>
+ ${description}
+
+ <#-- Create references to additional capabilities if appropriate -->
+ <#if readfilters?size != 0 || parallel?size != 0>
+ <hr>
+ <h2>Additional Information</h2>
+ <p></p>
+ </#if>
+ <#if readfilters?size != 0>
+ <h3>Read filters</h3>
+ <#if readfilters?size = 1>
+ <p>This Read Filter is automatically applied to the data by the Engine before processing by ${name}.</p>
+ </#if>
+ <#if (readfilters?size > 1) >
+ <p>These Read Filters are automatically applied to the data by the Engine before processing by ${name}.</p>
+ </#if>
+ <ul>
+ <#list readfilters as filter>
+ <li><a href="${filter.filename}">${filter.name}</a></li>
+ </#list>
+ </ul>
+ </#if>
+ <#if parallel?size != 0>
+ <h3>Parallelism options</h3>
+ <#if parallel?size == 1>
+ <p>This tool can be run in multi-threaded mode using this option.</p>
+ </#if>
+ <#if (parallel?size > 1)>
+ <p>This tool can be run in multi-threaded mode using these options.</p>
+ </#if>
+ <ul>
+ <#list parallel as option>
+ <li><a href="${option.link}">${option.name} (${option.arg})</a></li>
+ </#list>
+ </ul>
+ </#if>
+ <#if downsampling?size != 0>
+ <h3>Downsampling settings</h3>
+ <#if downsampling.by == "NONE">
+ <p>This tool does not apply any downsampling by default.</p>
+ </#if>
+ <#if downsampling.by != "NONE">
+ <p>This tool applies the following downsampling settings by default.</p>
+ <ul>
+ <li>Mode: <b>${downsampling.by}</b></li>
+ <li>To coverage: <b>${downsampling.to_cov}</b></li>
+ </ul>
+ </#if>
+ </#if>
+ <#if refwindow?size != 0>
+ <h3>Window size</h3>
+ <p>This tool uses a sliding window on the reference.</p>
+ <ul>
+ <li>Window start: <b>${refwindow.start}</b> bp before the locus</li>
+ <li>Window stop: <b>${refwindow.stop}</b> bp after the locus</li>
+ </ul>
+ </#if>
+ <#if activeregion?size != 0>
+ <h3>ActiveRegion settings</h3>
+ <p>This tool uses ActiveRegions on the reference.</p>
+ <ul>
+ <li>Minimum region size: <b>${activeregion.min}</b> bp</li>
+ <li>Maximum region size: <b>${activeregion.max}</b> bp</li>
+ <li>Extension increments: <b>${activeregion.ext}</b> bp</li>
+ </ul>
+ </#if>
+ <#if extradocs?size != 0 || arguments.all?size != 0>
+ <hr>
+ <h2>Command-line Arguments</h2>
+ <p></p>
+ </#if>
+ <#if extradocs?size != 0>
+ <h3>Inherited arguments</h3>
+ <p>The arguments described in the entries below can be supplied to this tool to modify
+ its behavior. For example, the -L argument directs the GATK engine restricts processing
+ to specific genomic intervals (this is an Engine capability and is therefore available to all GATK walkers).</p>
+ <ul>
+ <#list extradocs as extradoc>
+ <li><a href="${extradoc.filename}">${extradoc.name}</a></li>
+ </#list>
+ </ul>
+ </#if>
+
+ <#-- This class is related to other documented classes via sub/super relationships -->
+ <#if relatedDocs?? && relatedDocs?size != 0>
+ <h3>Related capabilities</h3>
+ <@relatedByType name="Superclasses" type="superclass"/>
+ <@relatedByType name="Subclasses" type="subclass"/>
+ </#if>
+
+ <#-- Create the argument summary -->
+ <#if arguments.all?size != 0>
+ <h3>${name} specific arguments</h3>
+ <p>This table summarizes the command-line arguments that are specific to this tool. For more details on each argument, see the list further down below the table or click on an argument name to jump directly to that entry in the list.</p>
+ <table class="table table-striped table-bordered table-condensed">
+ <thead>
+ <tr>
+ <th>Argument name(s)</th>
+ <!--<th>Short name</th> -->
+ <th>Default value</th>
+ <th>Summary</th>
+ </tr>
+ </thead>
+ <tbody>
+ <@argumentlist name="Required Inputs" myargs=arguments.required_in/>
+ <@argumentlist name="Required Outputs" myargs=arguments.required_out/>
+ <@argumentlist name="Required Parameters" myargs=arguments.required_param/>
+ <@argumentlist name="Required Flags" myargs=arguments.required_flag/>
+ <@argumentlist name="Optional Inputs" myargs=arguments.optional_in/>
+ <@argumentlist name="Optional Outputs" myargs=arguments.optional_out/>
+ <@argumentlist name="Optional Parameters" myargs=arguments.optional_param/>
+ <@argumentlist name="Optional Flags" myargs=arguments.optional_flag/>
+ <@argumentlist name="Advanced Inputs" myargs=arguments.advanced_in/>
+ <@argumentlist name="Advanced Outputs" myargs=arguments.advanced_out/>
+ <@argumentlist name="Advanced Parameters" myargs=arguments.advanced_param/>
+ <@argumentlist name="Advanced Flags" myargs=arguments.advanced_flag/>
+ <@argumentlist name="Hidden" myargs=arguments.hidden/>
+ <@argumentlist name="Deprecated" myargs=arguments.deprecated/>
+ </tbody>
+ </table>
+ </#if>
+
+ <#-- List all of the -->
+ <#if arguments.all?size != 0>
+ <#-- Create the argument details -->
+ <h3>Argument details</h3>
+ <p>Arguments in this list are specific to this tool. Keep in mind that other arguments are available that are shared with other tools (e.g. command-line GATK arguments); see Inherited arguments above.</p>
+ <#list arguments.all as arg>
+ <@argumentDetails arg=arg/>
+ </#list>
+ </#if>
+
+ <@footerInfo />
+ <#-- Specify go-to developer (for internal use) -->
+ <#if gotoDev??>
+ <small>GTD: ${gotoDev}</small>
+ </#if>
+ <@footerClose />
+
+</div>
+
+<?php printFooter($module); ?>
\ No newline at end of file
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/gatk.git
More information about the debian-med-commit
mailing list